From 6830a731b777fd1e864a741a8cbd3ad33370ed0b Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Fri, 25 Jul 2025 01:20:43 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9F=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA?= =?UTF-8?q?=D0=B0=20=D0=BD=D0=B0=20=D0=BF=D0=BB=D0=B0=D0=B3=D0=B8=D0=B0?= =?UTF-8?q?=D1=82=20=D1=81=20=D0=BF=D0=BE=D0=BC=D0=BE=D1=89=D1=8C=D1=8E=20?= =?UTF-8?q?Moss.=20(closes=20#10)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- courses/operating-systems-2024f.yaml | 243 ++ plagiarism.py | 399 ++++ requirements.txt | 11 +- .../moss_real_report_os-2024f.html | 768 +++++++ .../moss_real_results_os-2024f.json | 2002 +++++++++++++++++ test/test_plagiarism.py | 99 + 6 files changed, 3518 insertions(+), 4 deletions(-) create mode 100644 courses/operating-systems-2024f.yaml create mode 100644 plagiarism.py create mode 100644 test/mosschecker_reports/moss_real_report_os-2024f.html create mode 100644 test/mosschecker_reports/moss_real_results_os-2024f.json create mode 100644 test/test_plagiarism.py diff --git a/courses/operating-systems-2024f.yaml b/courses/operating-systems-2024f.yaml new file mode 100644 index 0000000..0cb937e --- /dev/null +++ b/courses/operating-systems-2024f.yaml @@ -0,0 +1,243 @@ +--- +# Configuration file for lab-grader + +course: + name: Operating systems + alt-names: + - OS + - Операционные системы + - ОС + semester: Fall 2024 + email: k43guap@ya.ru + timezone: UTC+3 + github: + organization: suai-os-2024f + teachers: + - "Mark Polyak" + - markpolyak + google: + spreadsheet: 1lgwe2QuLoNdGnq-c3lZvl2frUI0s_TPtSdS6kCwjPI0 + info-sheet: График + task-id-column: 0 + student-name-column: 1 + lab-column-offset: 1 + staff: + - name: Поляк Марк Дмитриевич + title: ст. преп. + status: лектор + - name: Поляк Марк Дмитриевич + title: ст. преп. + status: лабораторные работы + labs: + "0": + github-prefix: os-task0 + short-name: ЛР0 + penalty-max: 5 + ignore-task-id: True + ci: + - workflows + files: + - goals.md + - info.md + - report.pdf + moss: + language: c + report: + - Задание + - Результат + "01": + github-prefix: os-task-I-1 + short-name: ЛР0.1 + taskid-max: 20 + penalty-max: 6 + # ignore-task-id: True + ci: + - workflows + files: + - typescript + moss: + language: c + max-matches: 1000 + report: + - Цель работы + - Индивидуальное задание + - Результат выполнения работы + - Содержимое файла typescript c записанной последовательностью команд + - Выводы + "1": + github-prefix: os-task1 + short-name: ЛР1 + taskid-max: 25 + penalty-max: 6 + ci: + - workflows + files: + - lab1.sh + moss: + language: c + max-matches: 1000 + local-path: lab1 + additional: + - suai-os-2020 + - suai-os-2021 + - suai-os-2022 + - suai-os-2023 + - suai-os-2024 + basefiles: + - + repo: k43guap/os-course-task1 + filename: lab1.sh + report: + - Цель работы + - Индивидуальное задание + - Описание входных данных + - Результат выполнения работы + - Исходный код программы с комментариями + - Выводы + "2": + github-prefix: os-task2 + short-name: ЛР2 + taskid-max: 20 + taskid-shift: 4 + penalty-max: 9 + ci: + - workflows + files: + - lab2.cpp + moss: + language: cc + max-matches: 1000 + local-path: lab2 + additional: + - suai-os-2020 + - suai-os-2021 + - suai-os-2022 + - suai-os-2023 + - suai-os-2024 + basefiles: + - + repo: k43guap/os-course-task2 + filename: lab2.cpp + - + repo: k43guap/os-course-task2 + filename: examples/ex3.cpp + report: + - Цель работы + - Задание на лабораторную работу + - Граф запуска потоков + - Результат выполнения работы + - Исходный код программы с комментариями + - Выводы + "3": + github-prefix: os-task3 + short-name: ЛР3 + taskid-max: 20 + penalty-max: 7 + ci: + - workflows + files: + - lab3.cpp + moss: + language: cc + max-matches: 1000 + local-path: lab3 + additional: + - suai-os-2020 + - suai-os-2021 + - suai-os-2022 + - suai-os-2023 + - suai-os-2024 + basefiles: + - + repo: k43guap/os-course-task3 + filename: lab3.cpp + report: + - Цель работы + - Задание на лабораторную работу + - Граф запуска потоков + - Результат выполнения работы + - Исходный код программы с комментариями + - Выводы + "4": + github-prefix: os-task4 + short-name: ЛР4 + taskid-max: 30 + penalty-max: 8 + ci: + - workflows + files: + - lab4.cpp + moss: + language: cc + max-matches: 100 + local-path: lab4 + additional: + - suai-os-2021 + - suai-os-2022 + - suai-os-2023 + - suai-os-2024 + basefiles: + - + repo: k43guap/os-course-task4 + filename: lab4.cpp + report: + - Цель работы + - Задание на лабораторную работу + - Описание используемых алгоритмов замещения страниц + - Результат выполнения работы + - Исходный код программы с комментариями + - Выводы + "5": + github-prefix: os-task5 + short-name: ЛР5 + taskid-max: 30 + penalty-max: 10 + # ignore-completion-date: True + ci: + workflows: + - run-autograding-tests + - cpplint + files: + - client.cpp + - server.cpp + moss: + language: cc + max-matches: 1000 + local-path: lab5 + additional: + - suai-os-2021 + - suai-os-2022 + - suai-os-2023 + - suai-os-2024 + report: + - Цель работы + - Задание на лабораторную работу + - Схема взаимодействия между клиентом и сервером + - Результат выполнения работы + - Исходный код программы с комментариями + - Выводы + "6": + github-prefix: os-task5 + short-name: ЛР6 + taskid-max: 30 + penalty-max: 7 + moss: + language: cc + max-matches: 1000 + local-path: lab5 + additional: + - suai-os-2021 + - suai-os-2022 + - suai-os-2023 + - suai-os-2024 + report: + - Цель работы + - Задание на лабораторную работу + - Описание структуры конфигурационного файла + - Содержимое написанного конфигурационного файла + - Логи сборки проекта в облаке + - Исходный код тестов + - Выводы +misc: + requests-timeout: 5 + diff --git a/plagiarism.py b/plagiarism.py new file mode 100644 index 0000000..ce7c9cc --- /dev/null +++ b/plagiarism.py @@ -0,0 +1,399 @@ + +import json +import re +import mosspy +from pathlib import Path +from abc import ABC, abstractmethod +from html.parser import HTMLParser +from typing import List, Dict, Optional, Tuple, Any +from datetime import datetime + +class PlagiarismChecker(ABC): + """Абстрактный класс (интерфейс) для проверки работ на плагиат""" + def __init__(self, lab_id: str, language: str): + self.lab_id = lab_id + self.language = language + + @abstractmethod + def run_check( + self, + student_files: List[Path], + base_files: List[Path] = None, + report_path: Path = None, + **kwargs: Any + ) -> Path: + """ + Запускает проверку. Возвращает локальный путь до файла с отчетом. + + :param student_files: Список файлов студентов для проверки + :param base_files: Базовые файлы (шаблоны, исключения) + :param report_path: Путь к файлу сохранения отчета + :param kwargs: Специфичные параметры для реализации (Например: опции MOSS) + :return: Путь до файла с отчетом + """ + pass + + @abstractmethod + def parse_results( + self, + report_path: Path, + threshold: float = 0.0, + **kwargs: Any + ) -> List[Dict]: + """ + Парсит результаты проверки. + + :param report_path: Путь до файла с отчетом + :param threshold: Порог фильтрации совпадений + :param kwargs: Дополнительные параметры парсинга + :return: Извлеченные пары совпадений + """ + pass + +class MossChecker(PlagiarismChecker): + """ Реализация PlagiarismChecker с использованием сервиса Moss """ + + class HTMLParserTextExtractor(HTMLParser): + """ HTML-парсер, основанный на патерне visitor, для извлечения данных из html-тегов """ + def __init__(self): + super().__init__() + self.extracted_data = [] + + def handle_data(self, data: str) -> None: + stripped_data = data.strip() + if stripped_data: + self.extracted_data.append(stripped_data) + + def _read_html_doc(self, report_path: str) -> str: + """ Читает отчет Moss""" + try: + with open(report_path, 'r', encoding='utf-8') as f: + html_content = f.read() + except FileNotFoundError: + raise FileNotFoundError + except Exception as e: + raise e + + return html_content + + @staticmethod + def load_moss_report(report_url : str, report_save_path: Path) -> Path: + """ + Загружает файл отчета MOSS, по предоставленной ссылке + + :param report_url: URL отчета MOSS + :param report_save_path: Куда сохранить отчет + :return: Путь до сохраненного отчета + """ + + moss = mosspy.Moss(user_id=0) + moss.saveWebPage(report_url, report_save_path) + return report_save_path + + def _extract_data_from_student_string(self, line: str) -> Optional[Tuple[str, str, str]]: + """Извлекает данные из строки по двум шаблонам""" + # Проверяем первый формат + match1 = self.pattern1.fullmatch(line) + if match1: + return match1.group(1), match1.group(2), match1.group(3) + + # Проверяем второй формат + match2 = self.pattern2.fullmatch(line) + if match2: + return match2.group(1), match2.group(2), match2.group(3) + + return None + + def __init__( + self, + lab_id: str, + language: str, + moss_user_id: int + ): + super().__init__(lab_id, language) + self.moss_user_id = moss_user_id + # Формат 1: __ (%) + self.pattern1 = re.compile(r'^(\d+)_[^_]+_([a-zA-Z0-9]+)\s*\((\d+)%\)$') + # Формат 2: ___ (%) + self.pattern2 = re.compile(r'^(\d+)_([a-zA-Z0-9-]+)_[^_]+?_\d{4}-\d{2}-\d{2}\s*\((\d+)%\)$') + + def run_check( + self, + student_files: List[Path], + base_files: List[Path] = None, + report_path: Path = None, + **kwargs: Any + ) -> Path: + """ + Отправляет файлы в Moss, запускает проверку, сохраняет отчет + :param student_files: Список файлов студентов для проверки + :param base_files: Базовые файлы (шаблоны, исключения) + :param report_path: Путь к файлу сохранения отчета + :param kwargs: Специфичные параметры для реализации (Например: опции MOSS) + :return: Локальный Путь до файла с отчетом + + Доп. параметры: + - max_matches + """ + + if report_path is None: + report_path = f'MossChecker_report_{datetime.now().strftime("%Y-%m-%d_%H-%M-%S")}.html' + + # Реализация отправки файлов + + moss = mosspy.Moss(user_id=self.moss_user_id, language=self.language) + max_matches = kwargs.get('max_matches', 250) + ignore_comments = kwargs.get('ignore_comments', False) + moss.setIgnoreLimit(max_matches) + moss.setCommentString(ignore_comments) + + for student_file in student_files: + if student_file.exists(): + moss.addFile(str(student_file), str(student_file.stem)) + else: + raise FileNotFoundError(f"Student file {str(student_file)} not found") + + for base_file in base_files: + if base_file.exists(): + moss.addBaseFile(str(base_file)) + else: + raise FileNotFoundError(f"Student file {str(base_file)} not found") + + url = moss.send() + if (url is None) or (len(url) == 0): + raise Exception("Cant send files to MOSS service (recievied URL is empty)") + + moss.saveWebPage(url, report_path) + return Path(report_path) + + def parse_results( + self, + report_path: Path, + threshold: float = 0.0, + **kwargs: Any + ) -> List[Dict]: + """ + Парсит HTML-страницу с результатами Moss + + :param report_path: Путь до HTML отчета MOSS + :param threshold: Минимальный процент совпадения для учета + :param kwargs: Дополнительные параметры парсинга для отчетов *MOSS* + :return: Извлеченные пары совпадений + """ + + # Чтение файла отчета + if not report_path.exists(): + raise FileNotFoundError(f"Report file: {report_path} not found") + html_doc = self._read_html_doc(str(report_path)) + html_doc_lower = html_doc.lower() + + # Проверка что файл HTML документ + if html_doc_lower.find("") == -1: + raise ValueError("File is not valid HTML document") + + # Проверка наличия таблицы + if "" not in html_doc_lower: + raise ValueError("HTML document does not contain a table") + + # Находим все строки таблицы + tr_start = 0 + tr_positions = [] + while True: + tr_start = html_doc_lower.find("", tr_start) + if tr_start == -1: + break + tr_end = html_doc_lower.find("", tr_start) + + if tr_end == -1: + next_tr = html_doc_lower.find("", tr_start + 4) + tr_end = next_tr if next_tr != -1 else len(html_doc) + else: + tr_end += 5 + + tr_positions.append((tr_start, tr_end)) + tr_start = tr_end + + # Пропускаем заголовок таблицы + if tr_positions: + tr_positions = tr_positions[1:] + + pairs = [] + for start, end in tr_positions: + # Извлекаем содержимое строки таблицы + tr_content = html_doc[start:end] + parser = self.HTMLParserTextExtractor() + parser.feed(tr_content) + + # Ожидаем 3 элемента: два студента + количество строк + if len(parser.extracted_data) < 3: + continue + + student1_data = parser.extracted_data[0] + student2_data = parser.extracted_data[1] + lines_count = parser.extracted_data[2] + + # Извлекаем данные студентов + stud1 = self._extract_data_from_student_string(student1_data) + stud2 = self._extract_data_from_student_string(student2_data) + + # Проверяем что оба студента распознаны + if not stud1 or not stud2: + #print(f"Skipping invalid data: {student1_data} | {student2_data}") + continue + + lab_id1, github1, percent1 = stud1 + lab_id2, github2, percent2 = stud2 + + if self.lab_id != lab_id1 or self.lab_id != lab_id2: + raise ValueError("Different lab ids") + + # Проверяем что работы одного типа + if lab_id1 != lab_id2: + #print(f"Skipping mismatched labs: {lab_id1} vs {lab_id2}") + raise Exception(f"Lab IDs from student dont match: {student1_data} vs {student2_data}") + + # Формируем результат + pairs.append({ + "student1": github1, + "student2": github2, + "match1": percent1, + "match2": percent2, + "lines": lines_count, + "lab_id": lab_id1 + }) + + return pairs + + + +class PlagiarismDetectionService: + """ Сервис производящий проверку студентческих файлов на плагиат """ + + def __init__(self, checker: PlagiarismChecker, course_config: Dict, lab_id: str): + self.checker = checker + self.results: List[Dict] = [] + self.course_config = course_config + self.lab_id = lab_id + + # Setup Checker + self.checker.lab_id = self.lab_id + try: + lang_str = self.course_config['course']['labs'][self.lab_id]['moss']['language'] + except: + raise Exception("Course config parsing error: cant get lab language") + + self.checker.language = lang_str + + def save_results_to_json(self, json_path : str): + """ Сохраняет результаты проверки работ в формате JSON""" + try: + with open(json_path, 'w', encoding='utf-8') as file: + json.dump(self.results, file, ensure_ascii=False, indent=4) + print(f"Результаты успешно сохранены в {json_path}") + except Exception as e: + print(f"Ошибка при сохранении JSON: {e}") + raise + + def load_results_from_json(self, json_path: str): + """ Читает и устанавливает пары совпадений из формата jSON """ + with open(json_path, "r", encoding="utf-8") as file: + data: List[Dict] = json.load(file) + self.results = data + + @staticmethod + def save_results_to_json_ex(results : List[Dict], json_path : str): + """ + Сохраняет результаты проверки работ в формате JSON + :param results: Результаты с извлеченными совпадениями + :param json_path: Путь к новому JSON + :exception Exception: Ошибка при сохранении JSON + """ + try: + with open(json_path, 'w', encoding='utf-8') as file: + json.dump(results, file, ensure_ascii=False, indent=4) + print(f"Результаты успешно сохранены в {json_path}") + except Exception as e: + print(f"Ошибка при сохранении JSON: {e}") + raise + + def get_results(self) -> List[Dict]: + """ Получить результаты проверки на плагиат """ + return self.results + + def _filter_by_threshold(self, threshold: float) -> List[Dict]: + """ + Фильтрует результаты проверки, оставляя только те совпадения, + где максимальный процент совпадения (match1 или match2) >= threshold + + :param threshold: Пороговое значение (0-100) для фильтрации + :return: Отфильтрованный список результатов + """ + if not isinstance(threshold, (int, float)): + raise ValueError("Threshold must be a number") + + threshold *= 100 + if threshold < 0 or threshold > 100: + raise ValueError("Threshold must be between 0 and 100") + + filtered_results = [] + + for result in self.results: + try: + # Преобразуем проценты в числа и берем максимальное значение + match1 = float(result.get("match1", 0)) + match2 = float(result.get("match2", 0)) + max_match = max(match1, match2) + + if max_match >= threshold: + filtered_results.append(result) + except (ValueError, TypeError) as e: + # Пропускаем записи с некорректными данными + continue + + return filtered_results + + def run_check_manual( + self, + students_files: List[Path], + base_files: List[Path], + threshold: float, + **checker_kwargs + ) -> List[Dict]: + """ + Запускает цикл проверки + + :param students_files: Список файлов студентов для проверки + :param base_files: Базовые файлы (шаблоны, исключения) + :param threshold: Минимальный процент совпадения для учета + :param checker_kwargs: Специфичные параметры для реализации (Например: опции MOSS) + :return: Извлеченные пары совпадений + """ + + # Checker Strategy + if isinstance(self.checker, MossChecker): + # Получаем user_id из kwargs или из атрибута объекта + user_id = checker_kwargs.get("moss_user_id", self.checker.moss_user_id) + + if not user_id: + raise ValueError("Moss checker is disabled, moss_user_id not provided") + + + # Запускаем проверку с распаковкой kwargs + report_path = self.checker.run_check( + students_files, + base_files, + **checker_kwargs + ) + + # Парсим результаты + self.results = self.checker.parse_results( + report_path, + threshold=threshold, + **checker_kwargs + ) + else: + raise NotImplementedError("This checker type is not supported yet") + + self.results = self._filter_by_threshold(threshold) + return self.results + diff --git a/requirements.txt b/requirements.txt index e9d6b98..e19c529 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,9 +1,12 @@ -fastapi +fastapi~=0.115.8 uvicorn gspread oauth2client -pyyaml -requests +pyyaml~=6.0.1 +requests~=2.31.0 python-multipart python-dotenv -itsdangerous \ No newline at end of file +itsdangerous +typing~=3.7.4.3 +pydantic~=2.10.6 +mosspy~=1.0.9 \ No newline at end of file diff --git a/test/mosschecker_reports/moss_real_report_os-2024f.html b/test/mosschecker_reports/moss_real_report_os-2024f.html new file mode 100644 index 0000000..3edb31f --- /dev/null +++ b/test/mosschecker_reports/moss_real_report_os-2024f.html @@ -0,0 +1,768 @@ + + +Moss Results + + +Moss Results

+Thu Jul 17 21:27:46 PDT 2025 +

+Options -l cc -m 1000 +


+[ How to Read the Results | Tips | FAQ | Contact | Submission Scripts | Credits ] +
+
+
File 1File 2Lines Matched +
2_suai-os-2024_ech00wv (71%) + 2_suai-os-2024_KoWalevDV (71%) + 445 +
2_suai-os-2020_student (94%) + 2_suai-os-2021_student (94%) +360 +
2_suai-os-2020_Lazyrniy (99%) + 2_suai-os-2021_matanforever (99%) +355 +
2_suai-os-2020_iMark0 (92%) + 2_suai-os-2020_nastyakotova (94%) +377 +
2_suai-os-2024_Doshchechnikov (77%) + 2_suai-os-2024_caxap (78%) +327 +
2_suai-os-2020_SasukeBack (73%) + 2_suai-os-2021_berry (71%) +360 +
2_suai-os-2020_lexybelial (90%) + 2_suai-os-2020_Chuzhanova (90%) +681 +
2_suai-os-2020_SasukeBack (67%) + 2_suai-os-2020_nastyakotova (81%) +290 +
2_suai-os-2020_darkgreen1112 (55%) + 2_suai-os-2022_koptev (56%) +369 +
2_suai-os-2022_wogusfer (70%) + 2_suai-os-2022_maximborodai (70%) +443 +
2_suai-os-2023_romanenko (77%) + 2_suai-os-2024_OrlovGUAP (77%) +346 +
2_suai-os-2020_Anton22122 (81%) + 2_suai-os-2020_nastyakotova (80%) +277 +
2_Ilusha-iz_lab2.cpp_2024-11-25 (74%) + 2_Kotplankov_lab2.cpp_2025-02-18 (74%) +336 +
2_mjolnirswa_lab2.cpp_2024-10-20 (67%) + 2_suai-os-2024_densergeev2003 (67%) +349 +
2_mashka15_lab2.cpp_2024-11-09 (81%) + 2_suai-os-2024_Al1Bi2 (81%) +302 +
2_suai-os-2023_matveynis (56%) + 2_suai-os-2023_Xamrah (57%) +586 +
2_suai-os-2021_AleksDiaz (61%) + 2_suai-os-2022_dianchix (61%) +667 +
2_suai-os-2020_nidzhat666 (61%) + 2_suai-os-2022_dianchix (61%) +372 +
2_suai-os-2020_nidzhat666 (61%) + 2_suai-os-2021_AleksDiaz (61%) +667 +
2_suai-os-2020_Foureh (61%) + 2_suai-os-2022_dianchix (61%) +407 +
2_suai-os-2020_Foureh (61%) + 2_suai-os-2021_AleksDiaz (61%) +667 +
2_suai-os-2020_Foureh (61%) + 2_suai-os-2020_nidzhat666 (61%) +407 +
2_suai-os-2020_SasukeBack (64%) + 2_suai-os-2021_matanforever (73%) +294 +
2_suai-os-2020_Lazyrniy (73%) + 2_suai-os-2020_SasukeBack (64%) +294 +
2_suai-os-2020_Lazyrniy (72%) + 2_suai-os-2020_Anton22122 (79%) +251 +
2_suai-os-2020_Anton22122 (79%) + 2_suai-os-2021_matanforever (72%) +251 +
2_suai-os-2020_darkgreen1112 (52%) + 2_suai-os-2021_SemenikhinaVasilina (53%) +303 +
2_suai-os-2024_Emb9r (60%) + 2_suai-os-2024_AnastasiyaPospelova (60%) +311 +
2_suai-os-2020_iMark0 (75%) + 2_suai-os-2020_SasukeBack (63%) +281 +
2_suai-os-2021_SemenikhinaVasilina (53%) + 2_suai-os-2022_koptev (53%) +341 +
2_suai-os-2020_ku4er99 (77%) + 2_suai-os-2020_nastyakotova (76%) +284 +
2_suai-os-2020_Fedora30697432 (61%) + 2_suai-os-2024_NLawliet6 (76%) +296 +
2_suai-os-2020_ku4er99 (76%) + 2_suai-os-2021_matanforever (71%) +263 +
2_suai-os-2020_Lazyrniy (71%) + 2_suai-os-2020_ku4er99 (76%) +260 +
2_zaykaa0_lab2.cpp_2024-10-29 (86%) + 2_suai-os-2024_nikarpoff (76%) +360 +
2_suai-os-2020_iMark0 (73%) + 2_suai-os-2020_Anton22122 (76%) +302 +
2_suai-os-2024_kiriksik (75%) + 2_suai-os-2024_ITEXNIKJS (75%) +296 +
2_suai-os-2022_KozyrevBM911 (62%) + 2_suai-os-2022_TheNitroZyniak (45%) +269 +
2_suai-os-2020_Pokemon3000 (74%) + 2_suai-os-2020_SasukeBack (60%) +278 +
2_suai-os-2020_Pokemon3000 (74%) + 2_suai-os-2021_matanforever (68%) +269 +
2_suai-os-2020_Lazyrniy (68%) + 2_suai-os-2020_Pokemon3000 (74%) +269 +
2_suai-os-2020_SasukeBack (59%) + 2_suai-os-2020_ku4er99 (73%) +245 +
2_istoki0bespokoystva_lab2.cpp_2024-12-03 (64%) + 2_AlinaYuuu_lab2.cpp_2024-10-21 (63%) +334 +
2_suai-os-2020_Anton22122 (73%) + 2_suai-os-2020_ku4er99 (72%) +272 +
2_danlylacov_lab2.cpp_2024-10-30 (77%) + 2_suai-os-2024_kiriksik (72%) +288 +
2_danlylacov_lab2.cpp_2024-10-30 (77%) + 2_suai-os-2024_ITEXNIKJS (72%) +266 +
2_suai-os-2020_iMark0 (69%) + 2_suai-os-2020_ku4er99 (71%) +245 +
2_suai-os-2020_nastyakotova (69%) + 2_suai-os-2021_matanforever (65%) +228 +
2_suai-os-2020_Pokemon3000 (71%) + 2_suai-os-2020_Anton22122 (71%) +246 +
2_suai-os-2020_Lazyrniy (65%) + 2_suai-os-2020_nastyakotova (69%) +225 +
2_suai-os-2020_Pokemon3000 (71%) + 2_suai-os-2020_nastyakotova (69%) +254 +
2_suai-os-2020_Pokemon3000 (71%) + 2_suai-os-2020_iMark0 (68%) +255 +
2_suai-os-2024_bogtogus (63%) + 2_suai-os-2024_AshuraSaint (62%) +274 +
2_suai-os-2020_ku4er99 (69%) + 2_suai-os-2021_NoTimeToPeace (72%) +269 +
2_suai-os-2020_TrueGrigo (81%) + 2_suai-os-2021_CoderButerbroder (79%) +320 +
2_suai-os-2020_Pokemon3000 (70%) + 2_suai-os-2020_ku4er99 (69%) +242 +
2_suai-os-2020_iMark0 (67%) + 2_suai-os-2021_matanforever (64%) +264 +
2_suai-os-2020_Lazyrniy (64%) + 2_suai-os-2020_iMark0 (67%) +261 +
2_suai-os-2021_Vonisak (66%) + 2_suai-os-2022_ladadmitr (58%) +275 +
2_DaryaNazarova4236_lab2.cpp_2025-04-11 (97%) + 2_suai-os-2022_Zefiry (97%) +315 +
2_suai-os-2020_SasukeBack (56%) + 2_suai-os-2020_Anton22122 (69%) +231 +
2_kateutkate23_lab2.cpp_2024-10-21 (79%) + 2_suai-os-2024_shmkvdmd (80%) +279 +
2_l1eanny_lab2.cpp_2024-12-24 (74%) + 2_suai-os-2024_Sirius867 (74%) +271 +
2_SvyatoslavVS_lab2.cpp_2025-02-19 (74%) + 2_suai-os-2024_Sirius867 (74%) +271 +
2_SvyatoslavVS_lab2.cpp_2025-02-19 (74%) + 2_l1eanny_lab2.cpp_2024-12-24 (74%) +241 +
2_suai-os-2022_Pogold (75%) + 2_suai-os-2022_WhiteDimka (75%) +307 +
2_suai-os-2020_akkurshin (76%) + 2_suai-os-2020_AlekseiUKR (75%) +292 +
2_suai-os-2020_ParfenovID (75%) + 2_suai-os-2021_CoderButerbroder (77%) +294 +
2_suai-os-2020_SolikovDA (78%) + 2_suai-os-2020_TrueGrigo (80%) +318 +
2_gently-whitesnow_lab2.cpp_2025-01-26 (77%) + 2_rekko907_lab2.cpp_2025-05-17 (63%) +257 +
2_suai-os-2022_Thunder484 (59%) + 2_suai-os-2023_LazyPlatypua (59%) +270 +
2_suai-os-2020_lexybelial (68%) + 2_suai-os-2021_matanforever (62%) +262 +
2_suai-os-2020_lexybelial (68%) + 2_suai-os-2020_Lazyrniy (62%) +262 +
2_suai-os-2020_BogachevED (53%) + 2_suai-os-2020_ShadowStraif (63%) +246 +
2_suai-os-2020_CyberShrex (82%) + 2_suai-os-2021_ilkatel (79%) +252 +
2_barashik07_lab2.cpp_2024-10-25 (56%) + 2_suai-os-2021_Kiryakor (45%) +234 +
2_suai-os-2020_darkgreen1112 (44%) + 2_suai-os-2024_LizzieKostr (58%) +273 +
2_suai-os-2020_ShadowStraif (62%) + 2_suai-os-2020_TheGreatestJew (68%) +248 +
2_suai-os-2022_qveex (63%) + 2_suai-os-2022_xincas (78%) +203 +
2_suai-os-2022_limenitiz (72%) + 2_suai-os-2022_IaroslavKurgan (67%) +291 +
2_suai-os-2020_nastyakotova (65%) + 2_suai-os-2021_NoTimeToPeace (68%) +260 +
2_suai-os-2020_Anton22122 (66%) + 2_suai-os-2021_NoTimeToPeace (68%) +267 +
2_suai-os-2021_SemenikhinaVasilina (44%) + 2_suai-os-2024_BloodyChain (64%) +272 +
2_suai-os-2020_TrueGrigo (77%) + 2_suai-os-2021_PineappleOne (73%) +330 +
2_suai-os-2020_lexybelial (66%) + 2_suai-os-2021_berry (52%) +247 +
2_suai-os-2024_markpolyak (57%) + 2_suai-os-2024_KleinerKaktus455 (63%) +368 +
2_suai-os-2020_iMark0 (63%) + 2_suai-os-2021_berry (51%) +249 +
2_suai-os-2020_Anton22122 (65%) + 2_suai-os-2021_OlegZharenov (51%) +271 +
2_suai-os-2020_SasukeBack (53%) + 2_suai-os-2021_GachiPriest (48%) +275 +
2_suai-os-2020_TrueGrigo (76%) + 2_suai-os-2020_ParfenovID (72%) +289 +
2_suai-os-2021_PineappleOne (72%) + 2_suai-os-2021_CoderButerbroder (73%) +342 +
2_suai-os-2020_Blake (89%) + 2_suai-os-2020_CornSnak3 (92%) +247 +
2_suai-os-2020_Anton22122 (64%) + 2_suai-os-2020_Chuzhanova (65%) +445 +
2_suai-os-2021_GachiPriest (47%) + 2_suai-os-2021_bar (48%) +261 +
2_suai-os-2020_iMark0 (62%) + 2_suai-os-2021_NoTimeToPeace (66%) +237 +
2_suai-os-2020_Chuzhanova (65%) + 2_suai-os-2021_matanforever (59%) +491 +
2_suai-os-2020_SolikovDA (74%) + 2_suai-os-2021_CoderButerbroder (72%) +313 +
2_suai-os-2021_matanforever (59%) + 2_suai-os-2021_GachiPriest (47%) +280 +
2_suai-os-2020_Lazyrniy (59%) + 2_suai-os-2021_GachiPriest (47%) +280 +
2_ev-osi_lab2.cpp_2024-11-03 (72%) + 2_guap-studentx_lab2.cpp_2024-10-27 (80%) +327 +
2_suai-os-2020_nastyakotova (62%) + 2_suai-os-2021_berry (50%) +207 +
2_suai-os-2020_SolikovDA (73%) + 2_suai-os-2020_Shore13 (66%) +330 +
2_suai-os-2020_Chuzhanova (64%) + 2_suai-os-2021_berry (50%) +457 +
2_suai-os-2021_GachiPriest (46%) + 2_suai-os-2021_berry (50%) +289 +
2_suai-os-2020_nastyakotova (62%) + 2_suai-os-2021_bar (48%) +266 +
2_suai-os-2020_Anton22122 (63%) + 2_suai-os-2021_berry (50%) +223 +
2_DaniilUshakov4231_lab2.cpp_2024-10-23 (57%) + 2_Zein-Berg_lab2.cpp_2024-10-23 (43%) +282 +
2_suai-os-2020_SasukeBack (51%) + 2_suai-os-2021_bar (48%) +270 +
2_suai-os-2020_Baka9k (46%) + 2_suai-os-2020_v3g45 (53%) +269 +
2_suai-os-2021_dno (57%) + 2_suai-os-2021_SemenikhinaVasilina (43%) +253 +
2_suai-os-2024_lizabogdanova (55%) + 2_suai-os-2024_fawl7 (62%) +231 +
2_suai-os-2021_matanforever (58%) + 2_suai-os-2021_berry (49%) +214 +
2_suai-os-2020_Shore13 (65%) + 2_suai-os-2021_PineappleOne (70%) +353 +
2_suai-os-2020_Lazyrniy (58%) + 2_suai-os-2021_berry (49%) +213 +
2_suai-os-2022_luckyirchucky (62%) + 2_suai-os-2022_EvgeniyEkimenko (67%) +287 +
2_suai-os-2022_belkanel (90%) + 2_suai-os-2022_AnatoliyQ (91%) +285 +
2_suai-os-2021_GachiPriest (46%) + 2_suai-os-2021_OlegZharenov (49%) +262 +
2_suai-os-2021_OlegZharenov (49%) + 2_suai-os-2021_bar (47%) +240 +
2_ondavlad_lab2.cpp_2024-11-22 (56%) + 2_suai-os-2024_StanislavTsyganko (48%) +315 +
2_suai-os-2020_BogachevED (49%) + 2_suai-os-2020_TheGreatestJew (64%) +251 +
2_suai-os-2022_Krutov777 (65%) + 2_suai-os-2022_qveex (59%) +187 +
2_suai-os-2020_Shore13 (64%) + 2_suai-os-2020_ParfenovID (68%) +301 +
2_suai-os-2020_SolikovDA (71%) + 2_suai-os-2021_froglet (52%) +244 +
2_suai-os-2020_Lazyrniy (57%) + 2_suai-os-2020_Chuzhanova (62%) +469 +
2_suai-os-2020_iMark0 (59%) + 2_suai-os-2021_bar (46%) +278 +
2_suai-os-2021_matanforever (56%) + 2_suai-os-2021_OlegZharenov (48%) +243 +
2_suai-os-2020_lexybelial (62%) + 2_suai-os-2020_iMark0 (59%) +243 +
2_suai-os-2020_iMark0 (59%) + 2_suai-os-2020_Chuzhanova (62%) +454 +
2_suai-os-2020_Lazyrniy (56%) + 2_suai-os-2021_OlegZharenov (48%) +243 +
2_suai-os-2021_Kunerv (56%) + 2_suai-os-2024_Kukonen (60%) +243 +
2_suai-os-2023_alisasob (60%) + 2_suai-os-2024_NLawliet6 (60%) +261 +
2_Ddkaba_lab2.cpp_2024-10-23 (38%) + 2_suai-os-2021_ch (44%) +280 +
2_Bolotnik-ss_lab2.cpp_2024-10-30 (43%) + 2_suai-os-2020_Fedora30697432 (48%) +257 +
2_suai-os-2020_Pokemon3000 (61%) + 2_suai-os-2021_NoTimeToPeace (63%) +226 +
2_Vlad-ftec_lab2.cpp_2024-11-13 (48%) + 2_SkilletCountersAnotherAcc_lab2.cpp_2024-11-05 (46%) +223 +
2_Zein-Berg_lab2.cpp_2024-10-23 (41%) + 2_suai-os-2023_sofyanagovitsyna (45%) +263 +
2_Zein-Berg_lab2.cpp_2024-10-23 (41%) + 2_suai-os-2020_Baka9k (44%) +254 +
2_suai-os-2022_Akkey2k (55%) + 2_suai-os-2023_Xamrah (43%) +384 +
2_suai-os-2020_SasukeBack (49%) + 2_suai-os-2021_NoTimeToPeace (62%) +231 +
2_suai-os-2020_ku4er99 (59%) + 2_suai-os-2021_berry (47%) +212 +
2_suai-os-2023_ga11eon (55%) + 2_suai-os-2024_StanislavTsyganko (46%) +237 +
2_suai-os-2023_Likade (59%) + 2_suai-os-2023_serjobor (57%) +264 +
2_suai-os-2022_BarBariska619 (54%) + 2_suai-os-2022_TheNitroZyniak (37%) +229 +
2_Ddkaba_lab2.cpp_2024-10-23 (38%) + 2_Zein-Berg_lab2.cpp_2024-10-23 (41%) +258 +
2_Zein-Berg_lab2.cpp_2024-10-23 (41%) + 2_suai-os-2023_matveynis (42%) +274 +
2_suai-os-2022_PrincessKarolyn (56%) + 2_suai-os-2024_VanButrij (60%) +249 +
2_suai-os-2020_lexybelial (60%) + 2_suai-os-2020_SasukeBack (48%) +215 +
2_suai-os-2020_SasukeBack (48%) + 2_suai-os-2020_Chuzhanova (60%) +426 +
2_suai-os-2020_ParfenovID (66%) + 2_suai-os-2021_PineappleOne (66%) +284 +
2_suai-os-2020_AlekseiUKR (65%) + 2_suai-os-2021_berry (47%) +212 +
2_Zein-Berg_lab2.cpp_2024-10-23 (41%) + 2_suai-os-2024_StanislavTsyganko (45%) +248 +
2_suai-os-2020_AlekseiUKR (65%) + 2_suai-os-2021_ilkatel (70%) +214 +
2_suai-os-2022_koptev (40%) + 2_suai-os-2024_BloodyChain (58%) +272 +
2_suai-os-2020_Baka9k (44%) + 2_suai-os-2024_KoWalevDV (37%) +287 +
2_suai-os-2023_khozhbekyanyana (51%) + 2_suai-os-2024_scarypuppp (56%) +278 +
2_darkperson8_lab2.cpp_2024-10-22 (56%) + 2_suai-os-2023_Grig (60%) +218 +
2_suai-os-2024_SirPersimmon (72%) + 2_suai-os-2024_dev007 (76%) +341 +
2_suai-os-2020_SolikovDA (68%) + 2_suai-os-2021_PineappleOne (65%) +314 +
2_suai-os-2021_SemenikhinaVasilina (40%) + 2_suai-os-2024_LizzieKostr (52%) +236 +
2_suai-os-2021_matanforever (54%) + 2_suai-os-2021_NoTimeToPeace (61%) +227 +
2_suai-os-2020_nastyakotova (58%) + 2_suai-os-2020_Chuzhanova (60%) +447 +
2_suai-os-2020_lexybelial (60%) + 2_suai-os-2020_nastyakotova (58%) +224 +
2_suai-os-2020_Lazyrniy (54%) + 2_suai-os-2021_NoTimeToPeace (61%) +227 +
2_suai-os-2020_Baka9k (43%) + 2_suai-os-2024_ech00wv (37%) +279 +
2_Fedor204_lab2.cpp_2024-10-19 (54%) + 2_suai-os-2023_ga11eon (54%) +227 +
2_suai-os-2022_forGUAP (67%) + 2_suai-os-2024_PavKaa (64%) +222 +
2_ondavlad_lab2.cpp_2024-11-22 (53%) + 2_suai-os-2024_nebeyp (52%) +271 +
2_suai-os-2020_darkgreen1112 (39%) + 2_suai-os-2024_BloodyChain (57%) +238 +
2_suai-os-2021_SemenikhinaVasilina (40%) + 2_suai-os-2023_1Mercury1 (58%) +240 +
2_suai-os-2020_lexybelial (60%) + 2_suai-os-2020_Anton22122 (59%) +217 +
2_suai-os-2020_SolikovDA (68%) + 2_suai-os-2020_ParfenovID (65%) +287 +
2_darkperson8_lab2.cpp_2024-10-22 (56%) + 2_suai-os-2021_Kunerv (55%) +194 +
2_suai-os-2023_OzevaS (60%) + 2_suai-os-2023_ga11eon (54%) +238 +
2_suai-os-2020_grawford2525 (70%) + 2_suai-os-2021_ilkatel (69%) +235 +
2_suai-os-2022_anto1e (53%) + 2_suai-os-2023_ga11eon (54%) +244 +
2_suai-os-2021_DevVladikNT (47%) + 2_suai-os-2023_Durdma (51%) +290 +
2_suai-os-2022_koptev (40%) + 2_suai-os-2024_LizzieKostr (51%) +274 +
2_suai-os-2020_Pokemon3000 (59%) + 2_suai-os-2021_berry (46%) +226 +
2_Zein-Berg_lab2.cpp_2024-10-23 (40%) + 2_suai-os-2021_ivansoya (37%) +250 +
2_suai-os-2022_Krutov777 (61%) + 2_suai-os-2022_xincas (69%) +176 +
2_suai-os-2020_CyberShrex (72%) + 2_suai-os-2020_grawford2525 (69%) +223 +
2_suai-os-2020_Anton22122 (59%) + 2_suai-os-2021_GachiPriest (43%) +250 +
2_Zein-Berg_lab2.cpp_2024-10-23 (40%) + 2_suai-os-2021_SemenikhinaVasilina (39%) +258 +
2_suai-os-2020_tech (57%) + 2_suai-os-2020_hyroquin (55%) +222 +
2_suai-os-2021_Vonisak (55%) + 2_suai-os-2023_ga11eon (54%) +233 +
2_suai-os-2020_darkgreen1112 (39%) + 2_suai-os-2021_dno (52%) +226 +
2_suai-os-2021_SemenikhinaVasilina (39%) + 2_suai-os-2022_ladadmitr (49%) +246 +
2_suai-os-2022_argo2707 (45%) + 2_suai-os-2024_Doshchechnikov (48%) +253 +
2_suai-os-2023_ninadugina (48%) + 2_suai-os-2023_ga11eon (53%) +244 +
2_suai-os-2023_KazakovaPolya (52%) + 2_suai-os-2023_NikitaUlanskiy (52%) +246 +
2_suai-os-2022_forGUAP (66%) + 2_suai-os-2022_ladadmitr (48%) +228 +
2_Zein-Berg_lab2.cpp_2024-10-23 (39%) + 2_suai-os-2024_LizzieKostr (50%) +251 +
2_Zein-Berg_lab2.cpp_2024-10-23 (39%) + 2_suai-os-2022_Tirannozavr (46%) +244 +
2_suai-os-2021_ivansoya (37%) + 2_suai-os-2024_StanislavTsyganko (44%) +221 +
2_Zein-Berg_lab2.cpp_2024-10-23 (39%) + 2_suai-os-2020_darkgreen1112 (38%) +250 +
2_suai-os-2021_SemenikhinaVasilina (39%) + 2_suai-os-2021_Vonisak (54%) +232 +
2_suai-os-2023_matveynis (40%) + 2_suai-os-2023_ga11eon (53%) +238 +
2_suai-os-2020_Lazyrniy (53%) + 2_suai-os-2020_EldarGuseinov (82%) +201 +
2_suai-os-2020_EldarGuseinov (82%) + 2_suai-os-2021_matanforever (53%) +201 +
2_suai-os-2021_AndyTune (56%) + 2_suai-os-2024_StanislavTsyganko (43%) +229 +
2_suai-os-2020_lexybelial (58%) + 2_suai-os-2020_AlekseiUKR (62%) +210 +
2_suai-os-2020_Tit0v (53%) + 2_suai-os-2020_v3g45 (48%) +235 +
2_suai-os-2020_AlekseiUKR (62%) + 2_suai-os-2020_Chuzhanova (58%) +407 +
2_suai-os-2024_bogtogus (51%) + 2_suai-os-2024_lizabogdanova (49%) +201 +
2_suai-os-2023_matveynis (40%) + 2_suai-os-2024_nebeyp (50%) +249 +
2_ondavlad_lab2.cpp_2024-11-22 (51%) + 2_suai-os-2022_Thunder484 (49%) +233 +
2_suai-os-2021_matanforever (52%) + 2_suai-os-2021_bar (43%) +244 +
2_suai-os-2020_Shore13 (59%) + 2_suai-os-2020_TrueGrigo (67%) +265 +
2_suai-os-2020_Lazyrniy (52%) + 2_suai-os-2021_bar (43%) +244 +
2_suai-os-2020_KateGorbacheva (52%) + 2_suai-os-2020_liquidmann (45%) +286 +
2_suai-os-2023_A1phar1us (42%) + 2_suai-os-2024_densergeev2003 (47%) +219 +
2_suai-os-2020_Shore13 (59%) + 2_suai-os-2021_CoderButerbroder (64%) +294 +
2_suai-os-2024_BloodyChain (55%) + 2_suai-os-2024_LizzieKostr (50%) +234 +
2_suai-os-2022_forGUAP (65%) + 2_suai-os-2022_axelBaher (66%) +212 +
2_suai-os-2022_Tirannozavr (46%) + 2_suai-os-2024_bogtogus (51%) +229 +
2_suai-os-2022_Tirannozavr (46%) + 2_suai-os-2024_E (49%) +213 +
2_suai-os-2021_berry (44%) + 2_suai-os-2021_bar (43%) +251 +
2_suai-os-2023_Xamrah (40%) + 2_suai-os-2024_mistake (53%) +406 +
2_suai-os-2021_ivansoya (36%) + 2_suai-os-2021_BatMaxim (53%) +206 +
2_Ddkaba_lab2.cpp_2024-10-23 (36%) + 2_suai-os-2021_SemenikhinaVasilina (38%) +238 +
2_DaniilUshakov4231_lab2.cpp_2024-10-23 (51%) + 2_suai-os-2023_khozhbekyanyana (48%) +251 +
2_suai-os-2022_argo2707 (44%) + 2_suai-os-2024_caxap (48%) +245 +
2_suai-os-2020_AlekseiUKR (62%) + 2_suai-os-2020_iMark0 (54%) +226 +
2_Ddkaba_lab2.cpp_2024-10-23 (35%) + 2_suai-os-2024_Doshchechnikov (47%) +236 +
2_suai-os-2021_gwenbleyd (52%) + 2_suai-os-2021_OzoneTaTaY (56%) +211 +
2_suai-os-2020_Baka9k (41%) + 2_suai-os-2024_StanislavTsyganko (43%) +214 +
2_Zein-Berg_lab2.cpp_2024-10-23 (38%) + 2_suai-os-2022_ekaterina (47%) +258 +
2_Zein-Berg_lab2.cpp_2024-10-23 (38%) + 2_suai-os-2020_ilya (50%) +299 +
2_suai-os-2023_A1phar1us (41%) + 2_suai-os-2024_Doshchechnikov (47%) +223 +
2_suai-os-2022_ekaterina (47%) + 2_suai-os-2024_kiriksik (56%) +241 +
2_suai-os-2022_ekaterina (47%) + 2_suai-os-2024_ITEXNIKJS (56%) +241 +
2_suai-os-2020_zhukalin (52%) + 2_suai-os-2020_darkgreen1112 (38%) +242 +
2_ondavlad_lab2.cpp_2024-11-22 (50%) + 2_suai-os-2022_Tirannozavr (45%) +295 +
2_Zein-Berg_lab2.cpp_2024-10-23 (38%) + 2_suai-os-2022_argo2707 (44%) +253 +
2_suai-os-2020_VdovVal (54%) + 2_suai-os-2020_v3g45 (47%) +260 +
2_Zein-Berg_lab2.cpp_2024-10-23 (38%) + 2_suai-os-2024_fawl7 (55%) +237 +
2_Vindemitor_lab2.cpp_2025-02-13 (43%) + 2_Zein-Berg_lab2.cpp_2024-10-23 (38%) +257 +
2_Ddkaba_lab2.cpp_2024-10-23 (35%) + 2_suai-os-2022_argo2707 (44%) +245 +
2_suai-os-2022_wolk2608 (53%) + 2_suai-os-2022_Krutov777 (59%) +173 +
2_suai-os-2021_AndyTune (55%) + 2_suai-os-2022_Tirannozavr (45%) +243 +
2_suai-os-2020_ms1a (79%) + 2_suai-os-2020_ku4er99 (55%) +189 +
2_suai-os-2022_wolk2608 (53%) + 2_suai-os-2022_xincas (66%) +168 +
2_suai-os-2022_ladadmitr (47%) + 2_suai-os-2023_ga11eon (52%) +232 +
2_suai-os-2022_daryaaleshina (51%) + 2_suai-os-2022_ladadmitr (47%) +260 +
2_suai-os-2020_iMark0 (54%) + 2_suai-os-2021_GachiPriest (41%) +269 +
2_suai-os-2020_EldarGuseinov (80%) + 2_suai-os-2021_chempion (74%) +204 +
2_chekkip_lab2.cpp_2024-10-29 (55%) + 2_jirafa27_lab2.cpp_2024-12-22 (49%) +266 +
2_suai-os-2020_zhukalin (52%) + 2_suai-os-2024_LizzieKostr (49%) +244 +
2_suai-os-2022_wogusfer (47%) + 2_suai-os-2023_matveynis (39%) +275 +
2_suai-os-2022_maximborodai (47%) + 2_suai-os-2023_matveynis (39%) +314 +
+
+Any errors encountered during this query are listed below.

+ diff --git a/test/mosschecker_reports/moss_real_results_os-2024f.json b/test/mosschecker_reports/moss_real_results_os-2024f.json new file mode 100644 index 0000000..254bf50 --- /dev/null +++ b/test/mosschecker_reports/moss_real_results_os-2024f.json @@ -0,0 +1,2002 @@ +[ + { + "student1": "ech00wv", + "student2": "KoWalevDV", + "match1": "71", + "match2": "71", + "lines": "445", + "lab_id": "2" + }, + { + "student1": "student", + "student2": "student", + "match1": "94", + "match2": "94", + "lines": "360", + "lab_id": "2" + }, + { + "student1": "Lazyrniy", + "student2": "matanforever", + "match1": "99", + "match2": "99", + "lines": "355", + "lab_id": "2" + }, + { + "student1": "iMark0", + "student2": "nastyakotova", + "match1": "92", + "match2": "94", + "lines": "377", + "lab_id": "2" + }, + { + "student1": "Doshchechnikov", + "student2": "caxap", + "match1": "77", + "match2": "78", + "lines": "327", + "lab_id": "2" + }, + { + "student1": "SasukeBack", + "student2": "berry", + "match1": "73", + "match2": "71", + "lines": "360", + "lab_id": "2" + }, + { + "student1": "lexybelial", + "student2": "Chuzhanova", + "match1": "90", + "match2": "90", + "lines": "681", + "lab_id": "2" + }, + { + "student1": "SasukeBack", + "student2": "nastyakotova", + "match1": "67", + "match2": "81", + "lines": "290", + "lab_id": "2" + }, + { + "student1": "darkgreen1112", + "student2": "koptev", + "match1": "55", + "match2": "56", + "lines": "369", + "lab_id": "2" + }, + { + "student1": "wogusfer", + "student2": "maximborodai", + "match1": "70", + "match2": "70", + "lines": "443", + "lab_id": "2" + }, + { + "student1": "romanenko", + "student2": "OrlovGUAP", + "match1": "77", + "match2": "77", + "lines": "346", + "lab_id": "2" + }, + { + "student1": "Anton22122", + "student2": "nastyakotova", + "match1": "81", + "match2": "80", + "lines": "277", + "lab_id": "2" + }, + { + "student1": "Ilusha-iz", + "student2": "Kotplankov", + "match1": "74", + "match2": "74", + "lines": "336", + "lab_id": "2" + }, + { + "student1": "mjolnirswa", + "student2": "densergeev2003", + "match1": "67", + "match2": "67", + "lines": "349", + "lab_id": "2" + }, + { + "student1": "mashka15", + "student2": "Al1Bi2", + "match1": "81", + "match2": "81", + "lines": "302", + "lab_id": "2" + }, + { + "student1": "matveynis", + "student2": "Xamrah", + "match1": "56", + "match2": "57", + "lines": "586", + "lab_id": "2" + }, + { + "student1": "AleksDiaz", + "student2": "dianchix", + "match1": "61", + "match2": "61", + "lines": "667", + "lab_id": "2" + }, + { + "student1": "nidzhat666", + "student2": "dianchix", + "match1": "61", + "match2": "61", + "lines": "372", + "lab_id": "2" + }, + { + "student1": "nidzhat666", + "student2": "AleksDiaz", + "match1": "61", + "match2": "61", + "lines": "667", + "lab_id": "2" + }, + { + "student1": "Foureh", + "student2": "dianchix", + "match1": "61", + "match2": "61", + "lines": "407", + "lab_id": "2" + }, + { + "student1": "Foureh", + "student2": "AleksDiaz", + "match1": "61", + "match2": "61", + "lines": "667", + "lab_id": "2" + }, + { + "student1": "Foureh", + "student2": "nidzhat666", + "match1": "61", + "match2": "61", + "lines": "407", + "lab_id": "2" + }, + { + "student1": "SasukeBack", + "student2": "matanforever", + "match1": "64", + "match2": "73", + "lines": "294", + "lab_id": "2" + }, + { + "student1": "Lazyrniy", + "student2": "SasukeBack", + "match1": "73", + "match2": "64", + "lines": "294", + "lab_id": "2" + }, + { + "student1": "Lazyrniy", + "student2": "Anton22122", + "match1": "72", + "match2": "79", + "lines": "251", + "lab_id": "2" + }, + { + "student1": "Anton22122", + "student2": "matanforever", + "match1": "79", + "match2": "72", + "lines": "251", + "lab_id": "2" + }, + { + "student1": "darkgreen1112", + "student2": "SemenikhinaVasilina", + "match1": "52", + "match2": "53", + "lines": "303", + "lab_id": "2" + }, + { + "student1": "Emb9r", + "student2": "AnastasiyaPospelova", + "match1": "60", + "match2": "60", + "lines": "311", + "lab_id": "2" + }, + { + "student1": "iMark0", + "student2": "SasukeBack", + "match1": "75", + "match2": "63", + "lines": "281", + "lab_id": "2" + }, + { + "student1": "SemenikhinaVasilina", + "student2": "koptev", + "match1": "53", + "match2": "53", + "lines": "341", + "lab_id": "2" + }, + { + "student1": "ku4er99", + "student2": "nastyakotova", + "match1": "77", + "match2": "76", + "lines": "284", + "lab_id": "2" + }, + { + "student1": "Fedora30697432", + "student2": "NLawliet6", + "match1": "61", + "match2": "76", + "lines": "296", + "lab_id": "2" + }, + { + "student1": "ku4er99", + "student2": "matanforever", + "match1": "76", + "match2": "71", + "lines": "263", + "lab_id": "2" + }, + { + "student1": "Lazyrniy", + "student2": "ku4er99", + "match1": "71", + "match2": "76", + "lines": "260", + "lab_id": "2" + }, + { + "student1": "zaykaa0", + "student2": "nikarpoff", + "match1": "86", + "match2": "76", + "lines": "360", + "lab_id": "2" + }, + { + "student1": "iMark0", + "student2": "Anton22122", + "match1": "73", + "match2": "76", + "lines": "302", + "lab_id": "2" + }, + { + "student1": "kiriksik", + "student2": "ITEXNIKJS", + "match1": "75", + "match2": "75", + "lines": "296", + "lab_id": "2" + }, + { + "student1": "KozyrevBM911", + "student2": "TheNitroZyniak", + "match1": "62", + "match2": "45", + "lines": "269", + "lab_id": "2" + }, + { + "student1": "Pokemon3000", + "student2": "SasukeBack", + "match1": "74", + "match2": "60", + "lines": "278", + "lab_id": "2" + }, + { + "student1": "Pokemon3000", + "student2": "matanforever", + "match1": "74", + "match2": "68", + "lines": "269", + "lab_id": "2" + }, + { + "student1": "Lazyrniy", + "student2": "Pokemon3000", + "match1": "68", + "match2": "74", + "lines": "269", + "lab_id": "2" + }, + { + "student1": "SasukeBack", + "student2": "ku4er99", + "match1": "59", + "match2": "73", + "lines": "245", + "lab_id": "2" + }, + { + "student1": "istoki0bespokoystva", + "student2": "AlinaYuuu", + "match1": "64", + "match2": "63", + "lines": "334", + "lab_id": "2" + }, + { + "student1": "Anton22122", + "student2": "ku4er99", + "match1": "73", + "match2": "72", + "lines": "272", + "lab_id": "2" + }, + { + "student1": "danlylacov", + "student2": "kiriksik", + "match1": "77", + "match2": "72", + "lines": "288", + "lab_id": "2" + }, + { + "student1": "danlylacov", + "student2": "ITEXNIKJS", + "match1": "77", + "match2": "72", + "lines": "266", + "lab_id": "2" + }, + { + "student1": "iMark0", + "student2": "ku4er99", + "match1": "69", + "match2": "71", + "lines": "245", + "lab_id": "2" + }, + { + "student1": "nastyakotova", + "student2": "matanforever", + "match1": "69", + "match2": "65", + "lines": "228", + "lab_id": "2" + }, + { + "student1": "Pokemon3000", + "student2": "Anton22122", + "match1": "71", + "match2": "71", + "lines": "246", + "lab_id": "2" + }, + { + "student1": "Lazyrniy", + "student2": "nastyakotova", + "match1": "65", + "match2": "69", + "lines": "225", + "lab_id": "2" + }, + { + "student1": "Pokemon3000", + "student2": "nastyakotova", + "match1": "71", + "match2": "69", + "lines": "254", + "lab_id": "2" + }, + { + "student1": "Pokemon3000", + "student2": "iMark0", + "match1": "71", + "match2": "68", + "lines": "255", + "lab_id": "2" + }, + { + "student1": "bogtogus", + "student2": "AshuraSaint", + "match1": "63", + "match2": "62", + "lines": "274", + "lab_id": "2" + }, + { + "student1": "ku4er99", + "student2": "NoTimeToPeace", + "match1": "69", + "match2": "72", + "lines": "269", + "lab_id": "2" + }, + { + "student1": "TrueGrigo", + "student2": "CoderButerbroder", + "match1": "81", + "match2": "79", + "lines": "320", + "lab_id": "2" + }, + { + "student1": "Pokemon3000", + "student2": "ku4er99", + "match1": "70", + "match2": "69", + "lines": "242", + "lab_id": "2" + }, + { + "student1": "iMark0", + "student2": "matanforever", + "match1": "67", + "match2": "64", + "lines": "264", + "lab_id": "2" + }, + { + "student1": "Lazyrniy", + "student2": "iMark0", + "match1": "64", + "match2": "67", + "lines": "261", + "lab_id": "2" + }, + { + "student1": "Vonisak", + "student2": "ladadmitr", + "match1": "66", + "match2": "58", + "lines": "275", + "lab_id": "2" + }, + { + "student1": "DaryaNazarova4236", + "student2": "Zefiry", + "match1": "97", + "match2": "97", + "lines": "315", + "lab_id": "2" + }, + { + "student1": "SasukeBack", + "student2": "Anton22122", + "match1": "56", + "match2": "69", + "lines": "231", + "lab_id": "2" + }, + { + "student1": "kateutkate23", + "student2": "shmkvdmd", + "match1": "79", + "match2": "80", + "lines": "279", + "lab_id": "2" + }, + { + "student1": "l1eanny", + "student2": "Sirius867", + "match1": "74", + "match2": "74", + "lines": "271", + "lab_id": "2" + }, + { + "student1": "SvyatoslavVS", + "student2": "Sirius867", + "match1": "74", + "match2": "74", + "lines": "271", + "lab_id": "2" + }, + { + "student1": "SvyatoslavVS", + "student2": "l1eanny", + "match1": "74", + "match2": "74", + "lines": "241", + "lab_id": "2" + }, + { + "student1": "Pogold", + "student2": "WhiteDimka", + "match1": "75", + "match2": "75", + "lines": "307", + "lab_id": "2" + }, + { + "student1": "akkurshin", + "student2": "AlekseiUKR", + "match1": "76", + "match2": "75", + "lines": "292", + "lab_id": "2" + }, + { + "student1": "ParfenovID", + "student2": "CoderButerbroder", + "match1": "75", + "match2": "77", + "lines": "294", + "lab_id": "2" + }, + { + "student1": "SolikovDA", + "student2": "TrueGrigo", + "match1": "78", + "match2": "80", + "lines": "318", + "lab_id": "2" + }, + { + "student1": "gently-whitesnow", + "student2": "rekko907", + "match1": "77", + "match2": "63", + "lines": "257", + "lab_id": "2" + }, + { + "student1": "Thunder484", + "student2": "LazyPlatypua", + "match1": "59", + "match2": "59", + "lines": "270", + "lab_id": "2" + }, + { + "student1": "lexybelial", + "student2": "matanforever", + "match1": "68", + "match2": "62", + "lines": "262", + "lab_id": "2" + }, + { + "student1": "lexybelial", + "student2": "Lazyrniy", + "match1": "68", + "match2": "62", + "lines": "262", + "lab_id": "2" + }, + { + "student1": "BogachevED", + "student2": "ShadowStraif", + "match1": "53", + "match2": "63", + "lines": "246", + "lab_id": "2" + }, + { + "student1": "CyberShrex", + "student2": "ilkatel", + "match1": "82", + "match2": "79", + "lines": "252", + "lab_id": "2" + }, + { + "student1": "barashik07", + "student2": "Kiryakor", + "match1": "56", + "match2": "45", + "lines": "234", + "lab_id": "2" + }, + { + "student1": "darkgreen1112", + "student2": "LizzieKostr", + "match1": "44", + "match2": "58", + "lines": "273", + "lab_id": "2" + }, + { + "student1": "ShadowStraif", + "student2": "TheGreatestJew", + "match1": "62", + "match2": "68", + "lines": "248", + "lab_id": "2" + }, + { + "student1": "qveex", + "student2": "xincas", + "match1": "63", + "match2": "78", + "lines": "203", + "lab_id": "2" + }, + { + "student1": "limenitiz", + "student2": "IaroslavKurgan", + "match1": "72", + "match2": "67", + "lines": "291", + "lab_id": "2" + }, + { + "student1": "nastyakotova", + "student2": "NoTimeToPeace", + "match1": "65", + "match2": "68", + "lines": "260", + "lab_id": "2" + }, + { + "student1": "Anton22122", + "student2": "NoTimeToPeace", + "match1": "66", + "match2": "68", + "lines": "267", + "lab_id": "2" + }, + { + "student1": "SemenikhinaVasilina", + "student2": "BloodyChain", + "match1": "44", + "match2": "64", + "lines": "272", + "lab_id": "2" + }, + { + "student1": "TrueGrigo", + "student2": "PineappleOne", + "match1": "77", + "match2": "73", + "lines": "330", + "lab_id": "2" + }, + { + "student1": "lexybelial", + "student2": "berry", + "match1": "66", + "match2": "52", + "lines": "247", + "lab_id": "2" + }, + { + "student1": "markpolyak", + "student2": "KleinerKaktus455", + "match1": "57", + "match2": "63", + "lines": "368", + "lab_id": "2" + }, + { + "student1": "iMark0", + "student2": "berry", + "match1": "63", + "match2": "51", + "lines": "249", + "lab_id": "2" + }, + { + "student1": "Anton22122", + "student2": "OlegZharenov", + "match1": "65", + "match2": "51", + "lines": "271", + "lab_id": "2" + }, + { + "student1": "SasukeBack", + "student2": "GachiPriest", + "match1": "53", + "match2": "48", + "lines": "275", + "lab_id": "2" + }, + { + "student1": "TrueGrigo", + "student2": "ParfenovID", + "match1": "76", + "match2": "72", + "lines": "289", + "lab_id": "2" + }, + { + "student1": "PineappleOne", + "student2": "CoderButerbroder", + "match1": "72", + "match2": "73", + "lines": "342", + "lab_id": "2" + }, + { + "student1": "Blake", + "student2": "CornSnak3", + "match1": "89", + "match2": "92", + "lines": "247", + "lab_id": "2" + }, + { + "student1": "Anton22122", + "student2": "Chuzhanova", + "match1": "64", + "match2": "65", + "lines": "445", + "lab_id": "2" + }, + { + "student1": "GachiPriest", + "student2": "bar", + "match1": "47", + "match2": "48", + "lines": "261", + "lab_id": "2" + }, + { + "student1": "iMark0", + "student2": "NoTimeToPeace", + "match1": "62", + "match2": "66", + "lines": "237", + "lab_id": "2" + }, + { + "student1": "Chuzhanova", + "student2": "matanforever", + "match1": "65", + "match2": "59", + "lines": "491", + "lab_id": "2" + }, + { + "student1": "SolikovDA", + "student2": "CoderButerbroder", + "match1": "74", + "match2": "72", + "lines": "313", + "lab_id": "2" + }, + { + "student1": "matanforever", + "student2": "GachiPriest", + "match1": "59", + "match2": "47", + "lines": "280", + "lab_id": "2" + }, + { + "student1": "Lazyrniy", + "student2": "GachiPriest", + "match1": "59", + "match2": "47", + "lines": "280", + "lab_id": "2" + }, + { + "student1": "ev-osi", + "student2": "guap-studentx", + "match1": "72", + "match2": "80", + "lines": "327", + "lab_id": "2" + }, + { + "student1": "nastyakotova", + "student2": "berry", + "match1": "62", + "match2": "50", + "lines": "207", + "lab_id": "2" + }, + { + "student1": "SolikovDA", + "student2": "Shore13", + "match1": "73", + "match2": "66", + "lines": "330", + "lab_id": "2" + }, + { + "student1": "Chuzhanova", + "student2": "berry", + "match1": "64", + "match2": "50", + "lines": "457", + "lab_id": "2" + }, + { + "student1": "GachiPriest", + "student2": "berry", + "match1": "46", + "match2": "50", + "lines": "289", + "lab_id": "2" + }, + { + "student1": "nastyakotova", + "student2": "bar", + "match1": "62", + "match2": "48", + "lines": "266", + "lab_id": "2" + }, + { + "student1": "Anton22122", + "student2": "berry", + "match1": "63", + "match2": "50", + "lines": "223", + "lab_id": "2" + }, + { + "student1": "DaniilUshakov4231", + "student2": "Zein-Berg", + "match1": "57", + "match2": "43", + "lines": "282", + "lab_id": "2" + }, + { + "student1": "SasukeBack", + "student2": "bar", + "match1": "51", + "match2": "48", + "lines": "270", + "lab_id": "2" + }, + { + "student1": "Baka9k", + "student2": "v3g45", + "match1": "46", + "match2": "53", + "lines": "269", + "lab_id": "2" + }, + { + "student1": "dno", + "student2": "SemenikhinaVasilina", + "match1": "57", + "match2": "43", + "lines": "253", + "lab_id": "2" + }, + { + "student1": "lizabogdanova", + "student2": "fawl7", + "match1": "55", + "match2": "62", + "lines": "231", + "lab_id": "2" + }, + { + "student1": "matanforever", + "student2": "berry", + "match1": "58", + "match2": "49", + "lines": "214", + "lab_id": "2" + }, + { + "student1": "Shore13", + "student2": "PineappleOne", + "match1": "65", + "match2": "70", + "lines": "353", + "lab_id": "2" + }, + { + "student1": "Lazyrniy", + "student2": "berry", + "match1": "58", + "match2": "49", + "lines": "213", + "lab_id": "2" + }, + { + "student1": "luckyirchucky", + "student2": "EvgeniyEkimenko", + "match1": "62", + "match2": "67", + "lines": "287", + "lab_id": "2" + }, + { + "student1": "belkanel", + "student2": "AnatoliyQ", + "match1": "90", + "match2": "91", + "lines": "285", + "lab_id": "2" + }, + { + "student1": "GachiPriest", + "student2": "OlegZharenov", + "match1": "46", + "match2": "49", + "lines": "262", + "lab_id": "2" + }, + { + "student1": "OlegZharenov", + "student2": "bar", + "match1": "49", + "match2": "47", + "lines": "240", + "lab_id": "2" + }, + { + "student1": "ondavlad", + "student2": "StanislavTsyganko", + "match1": "56", + "match2": "48", + "lines": "315", + "lab_id": "2" + }, + { + "student1": "BogachevED", + "student2": "TheGreatestJew", + "match1": "49", + "match2": "64", + "lines": "251", + "lab_id": "2" + }, + { + "student1": "Krutov777", + "student2": "qveex", + "match1": "65", + "match2": "59", + "lines": "187", + "lab_id": "2" + }, + { + "student1": "Shore13", + "student2": "ParfenovID", + "match1": "64", + "match2": "68", + "lines": "301", + "lab_id": "2" + }, + { + "student1": "SolikovDA", + "student2": "froglet", + "match1": "71", + "match2": "52", + "lines": "244", + "lab_id": "2" + }, + { + "student1": "Lazyrniy", + "student2": "Chuzhanova", + "match1": "57", + "match2": "62", + "lines": "469", + "lab_id": "2" + }, + { + "student1": "iMark0", + "student2": "bar", + "match1": "59", + "match2": "46", + "lines": "278", + "lab_id": "2" + }, + { + "student1": "matanforever", + "student2": "OlegZharenov", + "match1": "56", + "match2": "48", + "lines": "243", + "lab_id": "2" + }, + { + "student1": "lexybelial", + "student2": "iMark0", + "match1": "62", + "match2": "59", + "lines": "243", + "lab_id": "2" + }, + { + "student1": "iMark0", + "student2": "Chuzhanova", + "match1": "59", + "match2": "62", + "lines": "454", + "lab_id": "2" + }, + { + "student1": "Lazyrniy", + "student2": "OlegZharenov", + "match1": "56", + "match2": "48", + "lines": "243", + "lab_id": "2" + }, + { + "student1": "Kunerv", + "student2": "Kukonen", + "match1": "56", + "match2": "60", + "lines": "243", + "lab_id": "2" + }, + { + "student1": "alisasob", + "student2": "NLawliet6", + "match1": "60", + "match2": "60", + "lines": "261", + "lab_id": "2" + }, + { + "student1": "Ddkaba", + "student2": "ch", + "match1": "38", + "match2": "44", + "lines": "280", + "lab_id": "2" + }, + { + "student1": "Bolotnik-ss", + "student2": "Fedora30697432", + "match1": "43", + "match2": "48", + "lines": "257", + "lab_id": "2" + }, + { + "student1": "Pokemon3000", + "student2": "NoTimeToPeace", + "match1": "61", + "match2": "63", + "lines": "226", + "lab_id": "2" + }, + { + "student1": "Vlad-ftec", + "student2": "SkilletCountersAnotherAcc", + "match1": "48", + "match2": "46", + "lines": "223", + "lab_id": "2" + }, + { + "student1": "Zein-Berg", + "student2": "sofyanagovitsyna", + "match1": "41", + "match2": "45", + "lines": "263", + "lab_id": "2" + }, + { + "student1": "Zein-Berg", + "student2": "Baka9k", + "match1": "41", + "match2": "44", + "lines": "254", + "lab_id": "2" + }, + { + "student1": "Akkey2k", + "student2": "Xamrah", + "match1": "55", + "match2": "43", + "lines": "384", + "lab_id": "2" + }, + { + "student1": "SasukeBack", + "student2": "NoTimeToPeace", + "match1": "49", + "match2": "62", + "lines": "231", + "lab_id": "2" + }, + { + "student1": "ku4er99", + "student2": "berry", + "match1": "59", + "match2": "47", + "lines": "212", + "lab_id": "2" + }, + { + "student1": "ga11eon", + "student2": "StanislavTsyganko", + "match1": "55", + "match2": "46", + "lines": "237", + "lab_id": "2" + }, + { + "student1": "Likade", + "student2": "serjobor", + "match1": "59", + "match2": "57", + "lines": "264", + "lab_id": "2" + }, + { + "student1": "BarBariska619", + "student2": "TheNitroZyniak", + "match1": "54", + "match2": "37", + "lines": "229", + "lab_id": "2" + }, + { + "student1": "Ddkaba", + "student2": "Zein-Berg", + "match1": "38", + "match2": "41", + "lines": "258", + "lab_id": "2" + }, + { + "student1": "Zein-Berg", + "student2": "matveynis", + "match1": "41", + "match2": "42", + "lines": "274", + "lab_id": "2" + }, + { + "student1": "PrincessKarolyn", + "student2": "VanButrij", + "match1": "56", + "match2": "60", + "lines": "249", + "lab_id": "2" + }, + { + "student1": "lexybelial", + "student2": "SasukeBack", + "match1": "60", + "match2": "48", + "lines": "215", + "lab_id": "2" + }, + { + "student1": "SasukeBack", + "student2": "Chuzhanova", + "match1": "48", + "match2": "60", + "lines": "426", + "lab_id": "2" + }, + { + "student1": "ParfenovID", + "student2": "PineappleOne", + "match1": "66", + "match2": "66", + "lines": "284", + "lab_id": "2" + }, + { + "student1": "AlekseiUKR", + "student2": "berry", + "match1": "65", + "match2": "47", + "lines": "212", + "lab_id": "2" + }, + { + "student1": "Zein-Berg", + "student2": "StanislavTsyganko", + "match1": "41", + "match2": "45", + "lines": "248", + "lab_id": "2" + }, + { + "student1": "AlekseiUKR", + "student2": "ilkatel", + "match1": "65", + "match2": "70", + "lines": "214", + "lab_id": "2" + }, + { + "student1": "koptev", + "student2": "BloodyChain", + "match1": "40", + "match2": "58", + "lines": "272", + "lab_id": "2" + }, + { + "student1": "Baka9k", + "student2": "KoWalevDV", + "match1": "44", + "match2": "37", + "lines": "287", + "lab_id": "2" + }, + { + "student1": "khozhbekyanyana", + "student2": "scarypuppp", + "match1": "51", + "match2": "56", + "lines": "278", + "lab_id": "2" + }, + { + "student1": "darkperson8", + "student2": "Grig", + "match1": "56", + "match2": "60", + "lines": "218", + "lab_id": "2" + }, + { + "student1": "SirPersimmon", + "student2": "dev007", + "match1": "72", + "match2": "76", + "lines": "341", + "lab_id": "2" + }, + { + "student1": "SolikovDA", + "student2": "PineappleOne", + "match1": "68", + "match2": "65", + "lines": "314", + "lab_id": "2" + }, + { + "student1": "SemenikhinaVasilina", + "student2": "LizzieKostr", + "match1": "40", + "match2": "52", + "lines": "236", + "lab_id": "2" + }, + { + "student1": "matanforever", + "student2": "NoTimeToPeace", + "match1": "54", + "match2": "61", + "lines": "227", + "lab_id": "2" + }, + { + "student1": "nastyakotova", + "student2": "Chuzhanova", + "match1": "58", + "match2": "60", + "lines": "447", + "lab_id": "2" + }, + { + "student1": "lexybelial", + "student2": "nastyakotova", + "match1": "60", + "match2": "58", + "lines": "224", + "lab_id": "2" + }, + { + "student1": "Lazyrniy", + "student2": "NoTimeToPeace", + "match1": "54", + "match2": "61", + "lines": "227", + "lab_id": "2" + }, + { + "student1": "Baka9k", + "student2": "ech00wv", + "match1": "43", + "match2": "37", + "lines": "279", + "lab_id": "2" + }, + { + "student1": "Fedor204", + "student2": "ga11eon", + "match1": "54", + "match2": "54", + "lines": "227", + "lab_id": "2" + }, + { + "student1": "forGUAP", + "student2": "PavKaa", + "match1": "67", + "match2": "64", + "lines": "222", + "lab_id": "2" + }, + { + "student1": "ondavlad", + "student2": "nebeyp", + "match1": "53", + "match2": "52", + "lines": "271", + "lab_id": "2" + }, + { + "student1": "darkgreen1112", + "student2": "BloodyChain", + "match1": "39", + "match2": "57", + "lines": "238", + "lab_id": "2" + }, + { + "student1": "SemenikhinaVasilina", + "student2": "1Mercury1", + "match1": "40", + "match2": "58", + "lines": "240", + "lab_id": "2" + }, + { + "student1": "lexybelial", + "student2": "Anton22122", + "match1": "60", + "match2": "59", + "lines": "217", + "lab_id": "2" + }, + { + "student1": "SolikovDA", + "student2": "ParfenovID", + "match1": "68", + "match2": "65", + "lines": "287", + "lab_id": "2" + }, + { + "student1": "darkperson8", + "student2": "Kunerv", + "match1": "56", + "match2": "55", + "lines": "194", + "lab_id": "2" + }, + { + "student1": "OzevaS", + "student2": "ga11eon", + "match1": "60", + "match2": "54", + "lines": "238", + "lab_id": "2" + }, + { + "student1": "grawford2525", + "student2": "ilkatel", + "match1": "70", + "match2": "69", + "lines": "235", + "lab_id": "2" + }, + { + "student1": "anto1e", + "student2": "ga11eon", + "match1": "53", + "match2": "54", + "lines": "244", + "lab_id": "2" + }, + { + "student1": "DevVladikNT", + "student2": "Durdma", + "match1": "47", + "match2": "51", + "lines": "290", + "lab_id": "2" + }, + { + "student1": "koptev", + "student2": "LizzieKostr", + "match1": "40", + "match2": "51", + "lines": "274", + "lab_id": "2" + }, + { + "student1": "Pokemon3000", + "student2": "berry", + "match1": "59", + "match2": "46", + "lines": "226", + "lab_id": "2" + }, + { + "student1": "Zein-Berg", + "student2": "ivansoya", + "match1": "40", + "match2": "37", + "lines": "250", + "lab_id": "2" + }, + { + "student1": "Krutov777", + "student2": "xincas", + "match1": "61", + "match2": "69", + "lines": "176", + "lab_id": "2" + }, + { + "student1": "CyberShrex", + "student2": "grawford2525", + "match1": "72", + "match2": "69", + "lines": "223", + "lab_id": "2" + }, + { + "student1": "Anton22122", + "student2": "GachiPriest", + "match1": "59", + "match2": "43", + "lines": "250", + "lab_id": "2" + }, + { + "student1": "Zein-Berg", + "student2": "SemenikhinaVasilina", + "match1": "40", + "match2": "39", + "lines": "258", + "lab_id": "2" + }, + { + "student1": "tech", + "student2": "hyroquin", + "match1": "57", + "match2": "55", + "lines": "222", + "lab_id": "2" + }, + { + "student1": "Vonisak", + "student2": "ga11eon", + "match1": "55", + "match2": "54", + "lines": "233", + "lab_id": "2" + }, + { + "student1": "darkgreen1112", + "student2": "dno", + "match1": "39", + "match2": "52", + "lines": "226", + "lab_id": "2" + }, + { + "student1": "SemenikhinaVasilina", + "student2": "ladadmitr", + "match1": "39", + "match2": "49", + "lines": "246", + "lab_id": "2" + }, + { + "student1": "argo2707", + "student2": "Doshchechnikov", + "match1": "45", + "match2": "48", + "lines": "253", + "lab_id": "2" + }, + { + "student1": "ninadugina", + "student2": "ga11eon", + "match1": "48", + "match2": "53", + "lines": "244", + "lab_id": "2" + }, + { + "student1": "KazakovaPolya", + "student2": "NikitaUlanskiy", + "match1": "52", + "match2": "52", + "lines": "246", + "lab_id": "2" + }, + { + "student1": "forGUAP", + "student2": "ladadmitr", + "match1": "66", + "match2": "48", + "lines": "228", + "lab_id": "2" + }, + { + "student1": "Zein-Berg", + "student2": "LizzieKostr", + "match1": "39", + "match2": "50", + "lines": "251", + "lab_id": "2" + }, + { + "student1": "Zein-Berg", + "student2": "Tirannozavr", + "match1": "39", + "match2": "46", + "lines": "244", + "lab_id": "2" + }, + { + "student1": "ivansoya", + "student2": "StanislavTsyganko", + "match1": "37", + "match2": "44", + "lines": "221", + "lab_id": "2" + }, + { + "student1": "Zein-Berg", + "student2": "darkgreen1112", + "match1": "39", + "match2": "38", + "lines": "250", + "lab_id": "2" + }, + { + "student1": "SemenikhinaVasilina", + "student2": "Vonisak", + "match1": "39", + "match2": "54", + "lines": "232", + "lab_id": "2" + }, + { + "student1": "matveynis", + "student2": "ga11eon", + "match1": "40", + "match2": "53", + "lines": "238", + "lab_id": "2" + }, + { + "student1": "Lazyrniy", + "student2": "EldarGuseinov", + "match1": "53", + "match2": "82", + "lines": "201", + "lab_id": "2" + }, + { + "student1": "EldarGuseinov", + "student2": "matanforever", + "match1": "82", + "match2": "53", + "lines": "201", + "lab_id": "2" + }, + { + "student1": "AndyTune", + "student2": "StanislavTsyganko", + "match1": "56", + "match2": "43", + "lines": "229", + "lab_id": "2" + }, + { + "student1": "lexybelial", + "student2": "AlekseiUKR", + "match1": "58", + "match2": "62", + "lines": "210", + "lab_id": "2" + }, + { + "student1": "Tit0v", + "student2": "v3g45", + "match1": "53", + "match2": "48", + "lines": "235", + "lab_id": "2" + }, + { + "student1": "AlekseiUKR", + "student2": "Chuzhanova", + "match1": "62", + "match2": "58", + "lines": "407", + "lab_id": "2" + }, + { + "student1": "bogtogus", + "student2": "lizabogdanova", + "match1": "51", + "match2": "49", + "lines": "201", + "lab_id": "2" + }, + { + "student1": "matveynis", + "student2": "nebeyp", + "match1": "40", + "match2": "50", + "lines": "249", + "lab_id": "2" + }, + { + "student1": "ondavlad", + "student2": "Thunder484", + "match1": "51", + "match2": "49", + "lines": "233", + "lab_id": "2" + }, + { + "student1": "matanforever", + "student2": "bar", + "match1": "52", + "match2": "43", + "lines": "244", + "lab_id": "2" + }, + { + "student1": "Shore13", + "student2": "TrueGrigo", + "match1": "59", + "match2": "67", + "lines": "265", + "lab_id": "2" + }, + { + "student1": "Lazyrniy", + "student2": "bar", + "match1": "52", + "match2": "43", + "lines": "244", + "lab_id": "2" + }, + { + "student1": "KateGorbacheva", + "student2": "liquidmann", + "match1": "52", + "match2": "45", + "lines": "286", + "lab_id": "2" + }, + { + "student1": "A1phar1us", + "student2": "densergeev2003", + "match1": "42", + "match2": "47", + "lines": "219", + "lab_id": "2" + }, + { + "student1": "Shore13", + "student2": "CoderButerbroder", + "match1": "59", + "match2": "64", + "lines": "294", + "lab_id": "2" + }, + { + "student1": "BloodyChain", + "student2": "LizzieKostr", + "match1": "55", + "match2": "50", + "lines": "234", + "lab_id": "2" + }, + { + "student1": "forGUAP", + "student2": "axelBaher", + "match1": "65", + "match2": "66", + "lines": "212", + "lab_id": "2" + }, + { + "student1": "Tirannozavr", + "student2": "bogtogus", + "match1": "46", + "match2": "51", + "lines": "229", + "lab_id": "2" + }, + { + "student1": "Tirannozavr", + "student2": "E", + "match1": "46", + "match2": "49", + "lines": "213", + "lab_id": "2" + }, + { + "student1": "berry", + "student2": "bar", + "match1": "44", + "match2": "43", + "lines": "251", + "lab_id": "2" + }, + { + "student1": "Xamrah", + "student2": "mistake", + "match1": "40", + "match2": "53", + "lines": "406", + "lab_id": "2" + }, + { + "student1": "ivansoya", + "student2": "BatMaxim", + "match1": "36", + "match2": "53", + "lines": "206", + "lab_id": "2" + }, + { + "student1": "Ddkaba", + "student2": "SemenikhinaVasilina", + "match1": "36", + "match2": "38", + "lines": "238", + "lab_id": "2" + }, + { + "student1": "DaniilUshakov4231", + "student2": "khozhbekyanyana", + "match1": "51", + "match2": "48", + "lines": "251", + "lab_id": "2" + }, + { + "student1": "argo2707", + "student2": "caxap", + "match1": "44", + "match2": "48", + "lines": "245", + "lab_id": "2" + }, + { + "student1": "AlekseiUKR", + "student2": "iMark0", + "match1": "62", + "match2": "54", + "lines": "226", + "lab_id": "2" + }, + { + "student1": "Ddkaba", + "student2": "Doshchechnikov", + "match1": "35", + "match2": "47", + "lines": "236", + "lab_id": "2" + }, + { + "student1": "gwenbleyd", + "student2": "OzoneTaTaY", + "match1": "52", + "match2": "56", + "lines": "211", + "lab_id": "2" + }, + { + "student1": "Baka9k", + "student2": "StanislavTsyganko", + "match1": "41", + "match2": "43", + "lines": "214", + "lab_id": "2" + }, + { + "student1": "Zein-Berg", + "student2": "ekaterina", + "match1": "38", + "match2": "47", + "lines": "258", + "lab_id": "2" + }, + { + "student1": "Zein-Berg", + "student2": "ilya", + "match1": "38", + "match2": "50", + "lines": "299", + "lab_id": "2" + }, + { + "student1": "A1phar1us", + "student2": "Doshchechnikov", + "match1": "41", + "match2": "47", + "lines": "223", + "lab_id": "2" + }, + { + "student1": "ekaterina", + "student2": "kiriksik", + "match1": "47", + "match2": "56", + "lines": "241", + "lab_id": "2" + }, + { + "student1": "ekaterina", + "student2": "ITEXNIKJS", + "match1": "47", + "match2": "56", + "lines": "241", + "lab_id": "2" + }, + { + "student1": "zhukalin", + "student2": "darkgreen1112", + "match1": "52", + "match2": "38", + "lines": "242", + "lab_id": "2" + }, + { + "student1": "ondavlad", + "student2": "Tirannozavr", + "match1": "50", + "match2": "45", + "lines": "295", + "lab_id": "2" + }, + { + "student1": "Zein-Berg", + "student2": "argo2707", + "match1": "38", + "match2": "44", + "lines": "253", + "lab_id": "2" + }, + { + "student1": "VdovVal", + "student2": "v3g45", + "match1": "54", + "match2": "47", + "lines": "260", + "lab_id": "2" + }, + { + "student1": "Zein-Berg", + "student2": "fawl7", + "match1": "38", + "match2": "55", + "lines": "237", + "lab_id": "2" + }, + { + "student1": "Vindemitor", + "student2": "Zein-Berg", + "match1": "43", + "match2": "38", + "lines": "257", + "lab_id": "2" + }, + { + "student1": "Ddkaba", + "student2": "argo2707", + "match1": "35", + "match2": "44", + "lines": "245", + "lab_id": "2" + }, + { + "student1": "wolk2608", + "student2": "Krutov777", + "match1": "53", + "match2": "59", + "lines": "173", + "lab_id": "2" + }, + { + "student1": "AndyTune", + "student2": "Tirannozavr", + "match1": "55", + "match2": "45", + "lines": "243", + "lab_id": "2" + }, + { + "student1": "ms1a", + "student2": "ku4er99", + "match1": "79", + "match2": "55", + "lines": "189", + "lab_id": "2" + }, + { + "student1": "wolk2608", + "student2": "xincas", + "match1": "53", + "match2": "66", + "lines": "168", + "lab_id": "2" + }, + { + "student1": "ladadmitr", + "student2": "ga11eon", + "match1": "47", + "match2": "52", + "lines": "232", + "lab_id": "2" + }, + { + "student1": "daryaaleshina", + "student2": "ladadmitr", + "match1": "51", + "match2": "47", + "lines": "260", + "lab_id": "2" + }, + { + "student1": "iMark0", + "student2": "GachiPriest", + "match1": "54", + "match2": "41", + "lines": "269", + "lab_id": "2" + }, + { + "student1": "EldarGuseinov", + "student2": "chempion", + "match1": "80", + "match2": "74", + "lines": "204", + "lab_id": "2" + }, + { + "student1": "chekkip", + "student2": "jirafa27", + "match1": "55", + "match2": "49", + "lines": "266", + "lab_id": "2" + }, + { + "student1": "zhukalin", + "student2": "LizzieKostr", + "match1": "52", + "match2": "49", + "lines": "244", + "lab_id": "2" + }, + { + "student1": "wogusfer", + "student2": "matveynis", + "match1": "47", + "match2": "39", + "lines": "275", + "lab_id": "2" + }, + { + "student1": "maximborodai", + "student2": "matveynis", + "match1": "47", + "match2": "39", + "lines": "314", + "lab_id": "2" + } +] \ No newline at end of file diff --git a/test/test_plagiarism.py b/test/test_plagiarism.py new file mode 100644 index 0000000..f75bf79 --- /dev/null +++ b/test/test_plagiarism.py @@ -0,0 +1,99 @@ +import re +import unittest +import json +import yaml +from plagiarism import MossChecker, PlagiarismDetectionService +from typing import List, Dict, Optional, Tuple +from pathlib import Path + + +def read_json(jsonpath: str) -> list[dict]: + with open(jsonpath, "r", encoding="utf-8") as file: + data: List[Dict] = json.load(file) + return data + + +class TestPlagiarism(unittest.TestCase): + + def test_mosschecker_load_moss_report_1(self): + report_url = "http://moss.stanford.edu/results/8/6516272398616/" + new_report_path = Path(".\\tmp\\test_mosschecker_load_moss_report_1.html") + MossChecker.load_moss_report(report_url, new_report_path) + + def test_mosschecker_method_parse_results_1(self): + """ Проверка метода parse_results() | Локальный отчет """ + results = (MossChecker(lab_id="2", language="cc", moss_user_id=1234) + .parse_results(Path(".\\mosschecker_reports\\moss_real_report_os-2024f.html"))) + + excepted_results = read_json(".\\mosschecker_reports\\moss_real_results_os-2024f.json") + self.assertEqual(results, excepted_results) + + def test_mosschecker_method_parse_results_2(self): + """ Проверка метода parse_results() | По URL """ + report_url = "http://moss.stanford.edu/results/8/6516272398616/" + new_report_path = Path(".\\tmp\\test_mosschecker_method_parse_results_2.html") + MossChecker.load_moss_report(report_url, new_report_path) + results = (MossChecker(lab_id="2", language="cc", moss_user_id=1234) + .parse_results(new_report_path)) + + excepted_results = read_json(".\\mosschecker_reports\\moss_real_results_os-2024f.json") + self.assertEqual(results, excepted_results) + + def test_mosschecker_method_run_check_1(self): + """ Проверка метода run_check() | 4 файлы с работами """ + MOSS_TEST_USER_ID = CHANGE_ME + folder = Path(".\\students-codes") + students_files = [file for file in folder.iterdir() if file.is_file()] + folder = Path(".\\base-files") + base_files = [file for file in folder.iterdir() if file.is_file()] + local_report_path = Path(".\\tmp\\test_mosschecker_run_check_1.html") + rec_report_path = MossChecker(lab_id="2", language="cc", moss_user_id=MOSS_TEST_USER_ID).run_check(students_files, base_files, local_report_path) + self.assertEqual(rec_report_path, local_report_path) + self.assertTrue(rec_report_path.stat().st_size > 0) + + def test_mosschecker_method_parse_results_3(self): + local_report_path = Path(".\\tmp\\test_mosschecker_run_check_1.html") + results = (MossChecker(lab_id="2", language="cc", moss_user_id=1234) + .parse_results(local_report_path)) + excepted_results = read_json(".\\mosschecker_reports\\custom_results.json") + self.assertEqual(results, excepted_results) + + def test_PlagiarismDetectionService_1(self): + + MOSS_TEST_USER_ID = 325834785 + + ## Open Course Config + with open("..\\courses\\operating-systems-2024f.yaml", "r") as f: + course_config = yaml.safe_load(f) + + ## Get Students and Base Files + folder = Path(".\\students-codes") + students_files = [file for file in folder.iterdir() if file.is_file()] + folder = Path(".\\base-files") + base_files = [file for file in folder.iterdir() if file.is_file()] + + ## Run Checks + + moss_checker = MossChecker( + language="cc", + moss_user_id=MOSS_TEST_USER_ID, + lab_id="2" + ) + + service = PlagiarismDetectionService( + checker=moss_checker, + course_config=course_config, + lab_id="2" + ) + + results = service.run_check_manual( + students_files, + base_files, + 0.7, + max_matches=1000, + ignore_comments=True + ) + + service.save_results_to_json(".\\tmp\\run_check_man_results.json") + +