From c284a49e36271bae2113dd6362ff72536cb24f7b Mon Sep 17 00:00:00 2001 From: "Anastasiia.Birillo" Date: Mon, 23 Aug 2021 16:10:22 +0300 Subject: [PATCH 1/6] Delete evaluation --- setup.py | 11 +- src/python/evaluation/README.md | 36 -- src/python/evaluation/__init__.py | 0 src/python/evaluation/common/__init__.py | 0 src/python/evaluation/common/csv_util.py | 13 - src/python/evaluation/common/pandas_util.py | 107 ---- src/python/evaluation/common/util.py | 53 -- src/python/evaluation/common/xlsx_util.py | 40 -- src/python/evaluation/evaluation_config.py | 58 -- src/python/evaluation/evaluation_run_tool.py | 172 ----- src/python/evaluation/inspectors/README.md | 312 --------- src/python/evaluation/inspectors/__init__.py | 0 .../evaluation/inspectors/common/__init__.py | 0 .../inspectors/common/statistics.py | 108 ---- .../evaluation/inspectors/diffs_between_df.py | 109 ---- .../inspectors/distribute_grades.py | 66 -- .../evaluation/inspectors/filter_issues.py | 67 -- .../evaluation/inspectors/filter_solutions.py | 60 -- .../evaluation/inspectors/generate_history.py | 131 ---- .../inspectors/get_worse_public_examples.py | 68 -- .../inspectors/inspectors_stat/README.md | 45 -- .../inspectors/inspectors_stat/__init__.py | 0 .../inspectors_stat/issues/__init__.py | 0 .../issues/flake8_all_issues.py | 601 ------------------ .../inspectors_stat/issues/other_issues.py | 8 - .../issues/pylint_all_issues.py | 496 --------------- .../inspectors_stat/statistics_gathering.py | 129 ---- .../inspectors/print_inspectors_statistics.py | 95 --- .../evaluation/issues_statistics/README.md | 59 -- .../evaluation/issues_statistics/__init__.py | 0 .../issues_statistics/common/__init__.py | 0 .../common/raw_issue_encoder_decoder.py | 67 -- .../issues_statistics/get_raw_issues.py | 275 -------- .../get_raw_issues_statistics.py | 227 ------- .../evaluation/paper_evaluation/README.md | 7 - .../evaluation/paper_evaluation/__init__.py | 0 .../comparison_with_other_tools/README.md | 58 -- .../comparison_with_other_tools/__init__.py | 0 .../statistics_gathering.py | 58 -- .../tutor_statistics.py | 127 ---- .../comparison_with_other_tools/util.py | 27 - .../issues_statistics/README.md | 107 ---- .../issues_statistics/__init__.py | 0 .../issues_statistics/examples/countable.png | Bin 147959 -> 0 bytes .../examples/maintainability_and_cohesion.png | Bin 108669 -> 0 bytes .../issues_statistics/examples/measurable.png | Bin 135918 -> 0 bytes .../issues_statistics/examples/ratio.png | Bin 116254 -> 0 bytes .../raw_issues_statistics_visualization.py | 207 ------ .../paper_evaluation/survey_handler/README.md | 73 --- .../survey_handler/__init__.py | 0 .../survey_handler/survey_statistics.py | 61 -- .../survey_statistics_gathering.py | 46 -- .../paper_evaluation/user_dynamics/README.md | 31 - .../user_dynamics/__init__.py | 0 .../user_dynamics/dynamics_gathering.py | 91 --- .../user_dynamics/dynamics_visualization.py | 96 --- .../user_dynamics/unpack_solutions.py | 72 --- .../user_dynamics/user_statistics.py | 23 - src/python/evaluation/plots/README.md | 160 ----- src/python/evaluation/plots/__init__.py | 0 .../evaluation/plots/common/__init__.py | 0 .../evaluation/plots/common/plotly_consts.py | 57 -- src/python/evaluation/plots/common/utils.py | 188 ------ src/python/evaluation/plots/diffs_plotter.py | 172 ----- .../examples/BEST_PRACTICES_box_plot.png | Bin 19449 -> 0 bytes .../BEST_PRACTICES_box_plot_grouped.png | Bin 21325 -> 0 bytes .../examples/CODE_STYLE_ratio_histogram.png | Bin 24012 -> 0 bytes .../CYCLOMATIC_COMPLEXITY_line_chart.png | Bin 35501 -> 0 bytes ...CLOMATIC_COMPLEXITY_line_chart_grouped.png | Bin 43037 -> 0 bytes .../plots/examples/issues_by_category.png | Bin 27515 -> 0 bytes .../median_penalty_influence_by_category.png | Bin 29328 -> 0 bytes .../penalty_influence_distribution.png | Bin 31956 -> 0 bytes .../examples/penalty_issues_by_category.png | Bin 27515 -> 0 bytes .../examples/unique_issues_by_category.png | Bin 26022 -> 0 bytes .../unique_penalty_issues_by_category.png | Bin 26022 -> 0 bytes .../evaluation/plots/plotters/__init__.py | 0 .../plots/plotters/diffs_plotters.py | 161 ----- .../raw_issues_statistics_plotters.py | 234 ------- .../plots/raw_issues_statistics_plotter.py | 150 ----- src/python/evaluation/qodana/README.md | 311 --------- src/python/evaluation/qodana/__init__.py | 0 .../convert_to_hyperstyle_inspections.py | 123 ---- .../evaluation/qodana/dataset_labeling.py | 280 -------- .../evaluation/qodana/filter_inspections.py | 58 -- .../qodana/fragment_to_inspections_list.py | 33 - ...agment_to_inspections_list_line_by_line.py | 62 -- .../qodana/get_unique_inspectors.py | 94 --- .../qodana/imitation_model/README.md | 173 ----- .../qodana/imitation_model/__init__.py | 3 - .../qodana/imitation_model/common/__init__.py | 0 .../common/evaluation_config.py | 47 -- .../qodana/imitation_model/common/metric.py | 41 -- .../imitation_model/common/train_config.py | 118 ---- .../qodana/imitation_model/common/util.py | 46 -- .../imitation_model/dataset/__init__.py | 0 .../qodana/imitation_model/dataset/dataset.py | 34 - .../qodana/imitation_model/evaluation.py | 75 --- .../imitation_model/preprocessing/README.md | 57 -- .../imitation_model/preprocessing/__init__.py | 0 .../preprocessing/encode_data.py | 162 ----- .../preprocessing/split_dataset.py | 77 --- .../qodana/imitation_model/train.py | 46 -- src/python/evaluation/qodana/util/__init__.py | 0 .../evaluation/qodana/util/issue_types.py | 6 - src/python/evaluation/qodana/util/models.py | 66 -- src/python/evaluation/qodana/util/util.py | 51 -- test/python/evaluation/__init__.py | 17 - test/python/evaluation/common/__init__.py | 0 .../evaluation/common/pandas_util/__init__.py | 0 .../pandas_util/test_drop_duplicates.py | 18 - .../pandas_util/test_filter_by_language.py | 29 - test/python/evaluation/inspectors/__init__.py | 0 .../inspectors/diffs_between_df/__init__.py | 0 .../diffs_between_df/test_diifs_between_df.py | 98 --- .../evaluation/issues_statistics/__init__.py | 15 - .../issues_statistics/test_get_raw_issues.py | 343 ---------- .../test_get_raw_issues_statistics.py | 112 ---- .../test_raw_issue_encoding_decoding.py | 228 ------- test/python/evaluation/test_data_path.py | 15 - test/python/evaluation/test_output_results.py | 34 - test/python/evaluation/test_tool_path.py | 28 - .../evaluation/test_xlsx_file_structure.py | 23 - test/python/evaluation/testing_config.py | 25 - test/python/quality/__init__.py | 0 test/python/quality/test_penalty.py | 158 ----- 125 files changed, 8 insertions(+), 8717 deletions(-) delete mode 100644 src/python/evaluation/README.md delete mode 100644 src/python/evaluation/__init__.py delete mode 100644 src/python/evaluation/common/__init__.py delete mode 100644 src/python/evaluation/common/csv_util.py delete mode 100644 src/python/evaluation/common/pandas_util.py delete mode 100644 src/python/evaluation/common/util.py delete mode 100644 src/python/evaluation/common/xlsx_util.py delete mode 100644 src/python/evaluation/evaluation_config.py delete mode 100644 src/python/evaluation/evaluation_run_tool.py delete mode 100644 src/python/evaluation/inspectors/README.md delete mode 100644 src/python/evaluation/inspectors/__init__.py delete mode 100644 src/python/evaluation/inspectors/common/__init__.py delete mode 100644 src/python/evaluation/inspectors/common/statistics.py delete mode 100644 src/python/evaluation/inspectors/diffs_between_df.py delete mode 100644 src/python/evaluation/inspectors/distribute_grades.py delete mode 100644 src/python/evaluation/inspectors/filter_issues.py delete mode 100644 src/python/evaluation/inspectors/filter_solutions.py delete mode 100644 src/python/evaluation/inspectors/generate_history.py delete mode 100644 src/python/evaluation/inspectors/get_worse_public_examples.py delete mode 100644 src/python/evaluation/inspectors/inspectors_stat/README.md delete mode 100644 src/python/evaluation/inspectors/inspectors_stat/__init__.py delete mode 100644 src/python/evaluation/inspectors/inspectors_stat/issues/__init__.py delete mode 100644 src/python/evaluation/inspectors/inspectors_stat/issues/flake8_all_issues.py delete mode 100644 src/python/evaluation/inspectors/inspectors_stat/issues/other_issues.py delete mode 100644 src/python/evaluation/inspectors/inspectors_stat/issues/pylint_all_issues.py delete mode 100644 src/python/evaluation/inspectors/inspectors_stat/statistics_gathering.py delete mode 100644 src/python/evaluation/inspectors/print_inspectors_statistics.py delete mode 100644 src/python/evaluation/issues_statistics/README.md delete mode 100644 src/python/evaluation/issues_statistics/__init__.py delete mode 100644 src/python/evaluation/issues_statistics/common/__init__.py delete mode 100644 src/python/evaluation/issues_statistics/common/raw_issue_encoder_decoder.py delete mode 100644 src/python/evaluation/issues_statistics/get_raw_issues.py delete mode 100644 src/python/evaluation/issues_statistics/get_raw_issues_statistics.py delete mode 100644 src/python/evaluation/paper_evaluation/README.md delete mode 100644 src/python/evaluation/paper_evaluation/__init__.py delete mode 100644 src/python/evaluation/paper_evaluation/comparison_with_other_tools/README.md delete mode 100644 src/python/evaluation/paper_evaluation/comparison_with_other_tools/__init__.py delete mode 100644 src/python/evaluation/paper_evaluation/comparison_with_other_tools/statistics_gathering.py delete mode 100644 src/python/evaluation/paper_evaluation/comparison_with_other_tools/tutor_statistics.py delete mode 100644 src/python/evaluation/paper_evaluation/comparison_with_other_tools/util.py delete mode 100644 src/python/evaluation/paper_evaluation/issues_statistics/README.md delete mode 100644 src/python/evaluation/paper_evaluation/issues_statistics/__init__.py delete mode 100644 src/python/evaluation/paper_evaluation/issues_statistics/examples/countable.png delete mode 100644 src/python/evaluation/paper_evaluation/issues_statistics/examples/maintainability_and_cohesion.png delete mode 100644 src/python/evaluation/paper_evaluation/issues_statistics/examples/measurable.png delete mode 100644 src/python/evaluation/paper_evaluation/issues_statistics/examples/ratio.png delete mode 100644 src/python/evaluation/paper_evaluation/issues_statistics/raw_issues_statistics_visualization.py delete mode 100644 src/python/evaluation/paper_evaluation/survey_handler/README.md delete mode 100644 src/python/evaluation/paper_evaluation/survey_handler/__init__.py delete mode 100644 src/python/evaluation/paper_evaluation/survey_handler/survey_statistics.py delete mode 100644 src/python/evaluation/paper_evaluation/survey_handler/survey_statistics_gathering.py delete mode 100644 src/python/evaluation/paper_evaluation/user_dynamics/README.md delete mode 100644 src/python/evaluation/paper_evaluation/user_dynamics/__init__.py delete mode 100644 src/python/evaluation/paper_evaluation/user_dynamics/dynamics_gathering.py delete mode 100644 src/python/evaluation/paper_evaluation/user_dynamics/dynamics_visualization.py delete mode 100644 src/python/evaluation/paper_evaluation/user_dynamics/unpack_solutions.py delete mode 100644 src/python/evaluation/paper_evaluation/user_dynamics/user_statistics.py delete mode 100644 src/python/evaluation/plots/README.md delete mode 100644 src/python/evaluation/plots/__init__.py delete mode 100644 src/python/evaluation/plots/common/__init__.py delete mode 100644 src/python/evaluation/plots/common/plotly_consts.py delete mode 100644 src/python/evaluation/plots/common/utils.py delete mode 100644 src/python/evaluation/plots/diffs_plotter.py delete mode 100644 src/python/evaluation/plots/examples/BEST_PRACTICES_box_plot.png delete mode 100644 src/python/evaluation/plots/examples/BEST_PRACTICES_box_plot_grouped.png delete mode 100644 src/python/evaluation/plots/examples/CODE_STYLE_ratio_histogram.png delete mode 100644 src/python/evaluation/plots/examples/CYCLOMATIC_COMPLEXITY_line_chart.png delete mode 100644 src/python/evaluation/plots/examples/CYCLOMATIC_COMPLEXITY_line_chart_grouped.png delete mode 100644 src/python/evaluation/plots/examples/issues_by_category.png delete mode 100644 src/python/evaluation/plots/examples/median_penalty_influence_by_category.png delete mode 100644 src/python/evaluation/plots/examples/penalty_influence_distribution.png delete mode 100644 src/python/evaluation/plots/examples/penalty_issues_by_category.png delete mode 100644 src/python/evaluation/plots/examples/unique_issues_by_category.png delete mode 100644 src/python/evaluation/plots/examples/unique_penalty_issues_by_category.png delete mode 100644 src/python/evaluation/plots/plotters/__init__.py delete mode 100644 src/python/evaluation/plots/plotters/diffs_plotters.py delete mode 100644 src/python/evaluation/plots/plotters/raw_issues_statistics_plotters.py delete mode 100644 src/python/evaluation/plots/raw_issues_statistics_plotter.py delete mode 100644 src/python/evaluation/qodana/README.md delete mode 100644 src/python/evaluation/qodana/__init__.py delete mode 100644 src/python/evaluation/qodana/convert_to_hyperstyle_inspections.py delete mode 100644 src/python/evaluation/qodana/dataset_labeling.py delete mode 100644 src/python/evaluation/qodana/filter_inspections.py delete mode 100644 src/python/evaluation/qodana/fragment_to_inspections_list.py delete mode 100644 src/python/evaluation/qodana/fragment_to_inspections_list_line_by_line.py delete mode 100644 src/python/evaluation/qodana/get_unique_inspectors.py delete mode 100644 src/python/evaluation/qodana/imitation_model/README.md delete mode 100644 src/python/evaluation/qodana/imitation_model/__init__.py delete mode 100644 src/python/evaluation/qodana/imitation_model/common/__init__.py delete mode 100644 src/python/evaluation/qodana/imitation_model/common/evaluation_config.py delete mode 100644 src/python/evaluation/qodana/imitation_model/common/metric.py delete mode 100644 src/python/evaluation/qodana/imitation_model/common/train_config.py delete mode 100644 src/python/evaluation/qodana/imitation_model/common/util.py delete mode 100644 src/python/evaluation/qodana/imitation_model/dataset/__init__.py delete mode 100644 src/python/evaluation/qodana/imitation_model/dataset/dataset.py delete mode 100644 src/python/evaluation/qodana/imitation_model/evaluation.py delete mode 100644 src/python/evaluation/qodana/imitation_model/preprocessing/README.md delete mode 100644 src/python/evaluation/qodana/imitation_model/preprocessing/__init__.py delete mode 100644 src/python/evaluation/qodana/imitation_model/preprocessing/encode_data.py delete mode 100644 src/python/evaluation/qodana/imitation_model/preprocessing/split_dataset.py delete mode 100644 src/python/evaluation/qodana/imitation_model/train.py delete mode 100644 src/python/evaluation/qodana/util/__init__.py delete mode 100644 src/python/evaluation/qodana/util/issue_types.py delete mode 100644 src/python/evaluation/qodana/util/models.py delete mode 100644 src/python/evaluation/qodana/util/util.py delete mode 100644 test/python/evaluation/__init__.py delete mode 100644 test/python/evaluation/common/__init__.py delete mode 100644 test/python/evaluation/common/pandas_util/__init__.py delete mode 100644 test/python/evaluation/common/pandas_util/test_drop_duplicates.py delete mode 100644 test/python/evaluation/common/pandas_util/test_filter_by_language.py delete mode 100644 test/python/evaluation/inspectors/__init__.py delete mode 100644 test/python/evaluation/inspectors/diffs_between_df/__init__.py delete mode 100644 test/python/evaluation/inspectors/diffs_between_df/test_diifs_between_df.py delete mode 100644 test/python/evaluation/issues_statistics/__init__.py delete mode 100644 test/python/evaluation/issues_statistics/test_get_raw_issues.py delete mode 100644 test/python/evaluation/issues_statistics/test_get_raw_issues_statistics.py delete mode 100644 test/python/evaluation/issues_statistics/test_raw_issue_encoding_decoding.py delete mode 100644 test/python/evaluation/test_data_path.py delete mode 100644 test/python/evaluation/test_output_results.py delete mode 100644 test/python/evaluation/test_tool_path.py delete mode 100644 test/python/evaluation/test_xlsx_file_structure.py delete mode 100644 test/python/evaluation/testing_config.py delete mode 100644 test/python/quality/__init__.py delete mode 100644 test/python/quality/test_penalty.py diff --git a/setup.py b/setup.py index 8b23d17a..7a119b2e 100644 --- a/setup.py +++ b/setup.py @@ -28,10 +28,15 @@ def get_inspectors_additional_files() -> List[str]: return result +def get_requires() -> List[str]: + with open(current_dir / 'requirements.txt') as requirements_file: + return requirements_file.read().split('\n') + + setup( - name='review', + name='hyperstyle', version=get_version(), - description='review', + description='A tool for running a set of pre-configured linters and evaluating code quality.', long_description=get_long_description(), long_description_content_type='text/markdown', url='https://github.com/hyperskill/hyperstyle', @@ -47,7 +52,7 @@ def get_inspectors_additional_files() -> List[str]: ], keywords='code review', python_requires='>=3.8, <4', - install_requires=['upsourceapi'], + install_requires=get_requires(), packages=find_packages(exclude=[ '*.unit_tests', '*.unit_tests.*', diff --git a/src/python/evaluation/README.md b/src/python/evaluation/README.md deleted file mode 100644 index b98e2deb..00000000 --- a/src/python/evaluation/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# Hyperstyle evaluation - -This tool allows running the `Hyperstyle` tool on a `xlsx` or `csv` table to get code quality for all code fragments. -Please, note that your input file should consist of at least 2 obligatory columns to run the tool on its code fragments: - -- `code` -- `lang` - -Possible values for column `lang` are: `python3`, `kotlin`, `java8`, `java11`. - -Output file is a new `xlsx` or `csv` file with the all columns from the input file and two additional ones: -- `grade` -- `traceback` (optional) - -Grade assessment is conducted by [`run_tool.py`](https://github.com/hyperskill/hyperstyle/blob/main/README.md) with default arguments. - Avaliable values for column `grade` are: BAD, MODERATE, GOOD, EXCELLENT. - `traceback` column stores full inspectors feedback on each code fragment. - More details on enabling traceback column in **Optional Arguments** table. - -## Usage - -Run the [evaluation_run_tool.py](evaluation_run_tool.py) with the arguments from command line. - -Required arguments: - -`solutions_file_path` — path to xlsx-file or csv-file with code samples to inspect. - -Optional arguments: -Argument | Description ---- | --- -|**‑f**, **‑‑format**| The output format. Available values: `json`, `text`. The default value is `json` . Use this argument when `traceback` is enabled, otherwise it will not be used.| -|**‑tp**, **‑‑tool‑path**| Path to run-tool. Default is `src/python/review/run_tool.py` .| -|**‑‑traceback**| To include a column with errors traceback into an output file. Default is `False`.| -|**‑ofp**, **‑‑output‑folder‑path**| An explicit folder path to store file with results. Default is a parent directory of a folder with xlsx-file or csv-file sent for inspection. | -|**‑ofn**, **‑‑output‑file‑name**| A name of an output file where evaluation results will be stored. Default is `results.xlsx` or `results.csv`.| -|**‑‑to‑drop‑nan**| If True, empty code fragments will be deleted from df. Default is `False`.| diff --git a/src/python/evaluation/__init__.py b/src/python/evaluation/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/python/evaluation/common/__init__.py b/src/python/evaluation/common/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/python/evaluation/common/csv_util.py b/src/python/evaluation/common/csv_util.py deleted file mode 100644 index c2956e57..00000000 --- a/src/python/evaluation/common/csv_util.py +++ /dev/null @@ -1,13 +0,0 @@ -from pathlib import Path -from typing import Union - -import pandas as pd -from src.python.review.common.file_system import Encoding - - -def write_dataframe_to_csv(csv_file_path: Union[str, Path], df: pd.DataFrame) -> None: - # Get error with this encoding=ENCODING on several fragments. So change it then to 'utf8' - try: - df.to_csv(csv_file_path, encoding=Encoding.ISO_ENCODING.value, index=False) - except UnicodeEncodeError: - df.to_csv(csv_file_path, encoding=Encoding.UTF_ENCODING.value, index=False) diff --git a/src/python/evaluation/common/pandas_util.py b/src/python/evaluation/common/pandas_util.py deleted file mode 100644 index 5aadf8ab..00000000 --- a/src/python/evaluation/common/pandas_util.py +++ /dev/null @@ -1,107 +0,0 @@ -import json -import logging -from pathlib import Path -from typing import Any, Iterable, List, Set, Union - -import numpy as np -import pandas as pd -from src.python.evaluation.common.csv_util import write_dataframe_to_csv -from src.python.evaluation.common.util import ColumnName -from src.python.evaluation.common.xlsx_util import create_workbook, remove_sheet, write_dataframe_to_xlsx_sheet -from src.python.evaluation.inspectors.common.statistics import PenaltyIssue -from src.python.review.application_config import LanguageVersion -from src.python.review.common.file_system import Extension, get_restricted_extension -from src.python.review.reviewers.utils.print_review import convert_json_to_issues - -logger = logging.getLogger(__name__) - - -def filter_df_by_language(df: pd.DataFrame, languages: Set[LanguageVersion], - column: str = ColumnName.LANG.value) -> pd.DataFrame: - return filter_df_by_iterable_value(df, column, set(map(lambda l: l.value, languages))) - - -def filter_df_by_iterable_value(df: pd.DataFrame, column: str, value: Iterable) -> pd.DataFrame: - return df.loc[df[column].isin(value)] - - -def filter_df_by_single_value(df: pd.DataFrame, column: str, value: Any) -> pd.DataFrame: - return df.loc[df[column] == value] - - -def drop_duplicates(df: pd.DataFrame, column: str = ColumnName.CODE.value) -> pd.DataFrame: - return df.drop_duplicates(column, keep='last').reset_index(drop=True) - - -# Find all rows and columns where two dataframes are inconsistent. -# For example: -# row | column | -# ------------------------- -# 3 | column_1 | True -# | column_2 | True -# ------------------------- -# 4 | column_1 | True -# | column_2 | True -# means first and second dataframes have different values -# in column_1 and in column_2 in 3-th and 4-th rows -def get_inconsistent_positions(first: pd.DataFrame, second: pd.DataFrame) -> pd.DataFrame: - ne_stacked = (first != second).stack() - inconsistent_positions = ne_stacked[ne_stacked] - inconsistent_positions.index.names = [ColumnName.ROW.value, ColumnName.COLUMN.value] - return inconsistent_positions - - -# Create a new dataframe with all items that are different. -# For example: -# | old | new -# --------------------------------- -# row column | | -# 3 grade | EXCELLENT | MODERATE -# 4 grade | EXCELLENT | BAD -def get_diffs(first: pd.DataFrame, second: pd.DataFrame) -> pd.DataFrame: - changed = get_inconsistent_positions(first, second) - - difference_locations = np.where(first != second) - changed_from = first.values[difference_locations] - changed_to = second.values[difference_locations] - return pd.DataFrame({ - ColumnName.OLD.value: changed_from, - ColumnName.NEW.value: changed_to}, - index=changed.index) - - -def get_solutions_df(ext: Extension, file_path: Union[str, Path]) -> pd.DataFrame: - try: - if ext == Extension.XLSX: - lang_code_dataframe = pd.read_excel(file_path) - else: - lang_code_dataframe = pd.read_csv(file_path) - except FileNotFoundError as e: - logger.error('XLSX-file or CSV-file with the specified name does not exists.') - raise e - - return lang_code_dataframe - - -def get_solutions_df_by_file_path(path: Path) -> pd.DataFrame: - ext = get_restricted_extension(path, [Extension.XLSX, Extension.CSV]) - return get_solutions_df(ext, path) - - -def write_df_to_file(df: pd.DataFrame, output_file_path: Path, extension: Extension) -> None: - if extension == Extension.CSV: - write_dataframe_to_csv(output_file_path, df) - elif extension == Extension.XLSX: - create_workbook(output_file_path) - write_dataframe_to_xlsx_sheet(output_file_path, df, 'inspection_results') - # remove empty sheet that was initially created with the workbook - remove_sheet(output_file_path, 'Sheet') - - -def get_issues_from_json(str_json: str) -> List[PenaltyIssue]: - parsed_json = json.loads(str_json)['issues'] - return convert_json_to_issues(parsed_json) - - -def get_issues_by_row(df: pd.DataFrame, row: int) -> List[PenaltyIssue]: - return get_issues_from_json(df.iloc[row][ColumnName.TRACEBACK.value]) diff --git a/src/python/evaluation/common/util.py b/src/python/evaluation/common/util.py deleted file mode 100644 index cc7cb309..00000000 --- a/src/python/evaluation/common/util.py +++ /dev/null @@ -1,53 +0,0 @@ -from enum import Enum, unique -from typing import Set - -from src.python.review.application_config import LanguageVersion -from src.python.review.common.file_system import Extension - - -@unique -class ColumnName(Enum): - CODE = 'code' - LANG = 'lang' - LANGUAGE = 'language' - GRADE = 'grade' - ID = 'id' - COLUMN = 'column' - ROW = 'row' - OLD = 'old' - NEW = 'new' - IS_PUBLIC = 'is_public' - DECREASED_GRADE = 'decreased_grade' - PENALTY = 'penalty' - USER = 'user' - HISTORY = 'history' - TIME = 'time' - TRACEBACK = 'traceback' - - -@unique -class EvaluationArgument(Enum): - TRACEBACK = 'traceback' - RESULT_FILE_NAME = 'evaluation_results' - RESULT_FILE_NAME_XLSX = f'{RESULT_FILE_NAME}{Extension.XLSX.value}' - RESULT_FILE_NAME_CSV = f'{RESULT_FILE_NAME}{Extension.CSV.value}' - - -script_structure_rule = ('Please, make sure your XLSX-file matches following script standards: \n' - '1. Your XLSX-file or CSV-file should have 2 obligatory columns named:' - f'"{ColumnName.CODE.value}" & "{ColumnName.LANG.value}". \n' - f'"{ColumnName.CODE.value}" column -- relates to the code-sample. \n' - f'"{ColumnName.LANG.value}" column -- relates to the language of a ' - 'particular code-sample. \n' - '2. Your code samples should belong to the one of the supported languages. \n' - 'Supported languages are: Java, Kotlin, Python. \n' - f'3. Check that "{ColumnName.LANG.value}" column cells are filled with ' - 'acceptable language-names: \n' - f'Acceptable language-names are: {LanguageVersion.PYTHON_3.value}, ' - f'{LanguageVersion.JAVA_8.value} ,' - f'{LanguageVersion.JAVA_11.value} and {LanguageVersion.KOTLIN.value}.') - - -# Split string by separator -def parse_set_arg(str_arg: str, separator: str = ',') -> Set[str]: - return set(str_arg.split(separator)) diff --git a/src/python/evaluation/common/xlsx_util.py b/src/python/evaluation/common/xlsx_util.py deleted file mode 100644 index e4a3dcf4..00000000 --- a/src/python/evaluation/common/xlsx_util.py +++ /dev/null @@ -1,40 +0,0 @@ -import logging.config -from pathlib import Path -from typing import Union - -import pandas as pd -from openpyxl import load_workbook, Workbook - -logger = logging.getLogger(__name__) - - -def remove_sheet(workbook_path: Union[str, Path], sheet_name: str, to_raise_error: bool = False) -> None: - try: - workbook = load_workbook(workbook_path) - workbook.remove(workbook[sheet_name]) - workbook.save(workbook_path) - - except KeyError as e: - message = f'Sheet with specified name: {sheet_name} does not exist.' - if to_raise_error: - logger.exception(message) - raise e - else: - logger.info(message) - - -def create_workbook(output_file_path: Path) -> Workbook: - workbook = Workbook() - workbook.save(output_file_path) - return workbook - - -def write_dataframe_to_xlsx_sheet(xlsx_file_path: Union[str, Path], df: pd.DataFrame, sheet_name: str, - mode: str = 'a', to_write_row_names: bool = False) -> None: - """ - mode: str Available values are {'w', 'a'}. File mode to use (write or append). - to_write_row_names: bool Write row names. - """ - - with pd.ExcelWriter(xlsx_file_path, mode=mode) as writer: - df.to_excel(writer, sheet_name=sheet_name, index=to_write_row_names) diff --git a/src/python/evaluation/evaluation_config.py b/src/python/evaluation/evaluation_config.py deleted file mode 100644 index 06672696..00000000 --- a/src/python/evaluation/evaluation_config.py +++ /dev/null @@ -1,58 +0,0 @@ -import logging.config -import os -from argparse import Namespace -from pathlib import Path -from typing import List, Optional, Union - -from src.python.common.tool_arguments import RunToolArgument -from src.python.evaluation.common.util import EvaluationArgument -from src.python.review.application_config import LanguageVersion -from src.python.review.common.file_system import ( - Extension, - get_parent_folder, - get_restricted_extension, -) - -logger = logging.getLogger(__name__) - - -class EvaluationConfig: - def __init__(self, args: Namespace): - self.tool_path: Union[str, Path] = args.tool_path - self.format: str = args.format - self.solutions_file_path: Union[str, Path] = args.solutions_file_path - self.traceback: bool = args.traceback - self.with_history: bool = args.with_history - self.output_folder_path: Union[str, Path] = args.output_folder_path - self.extension: Extension = get_restricted_extension(self.solutions_file_path, [Extension.XLSX, Extension.CSV]) - self.__init_output_file_name(args.output_file_name) - self.to_drop_nan: bool = args.to_drop_nan - - def __init_output_file_name(self, output_file_name: Optional[str]): - if output_file_name is None: - self.output_file_name = f'{EvaluationArgument.RESULT_FILE_NAME.value}{self.extension.value}' - else: - self.output_file_name = output_file_name - - def build_command(self, inspected_file_path: Union[str, Path], lang: str, history: Optional[str]) -> List[str]: - command = [LanguageVersion.PYTHON_3.value, - self.tool_path, - inspected_file_path, - RunToolArgument.FORMAT.value.short_name, self.format] - - if self.with_history and history is not None: - command.extend([RunToolArgument.HISTORY.value.long_name, history]) - - if lang == LanguageVersion.JAVA_8.value or lang == LanguageVersion.JAVA_11.value: - command.extend([RunToolArgument.LANG_VERSION.value.long_name, lang]) - return command - - def get_output_file_path(self) -> Path: - if self.output_folder_path is None: - try: - self.output_folder_path = get_parent_folder(Path(self.solutions_file_path)) - os.makedirs(self.output_folder_path, exist_ok=True) - except FileNotFoundError as e: - logger.error('XLSX-file or CSV-file with the specified name does not exists.') - raise e - return Path(self.output_folder_path) / self.output_file_name diff --git a/src/python/evaluation/evaluation_run_tool.py b/src/python/evaluation/evaluation_run_tool.py deleted file mode 100644 index 6304bf4f..00000000 --- a/src/python/evaluation/evaluation_run_tool.py +++ /dev/null @@ -1,172 +0,0 @@ -import argparse -import logging.config -import os -import re -import sys -import time -import traceback -from pathlib import Path -from typing import Optional - -sys.path.append('') -sys.path.append('../../..') - -import pandas as pd -from pandarallel import pandarallel -from src.python.common.tool_arguments import RunToolArgument -from src.python.evaluation.common.pandas_util import get_solutions_df, write_df_to_file -from src.python.evaluation.common.util import ColumnName, EvaluationArgument, script_structure_rule -from src.python.evaluation.evaluation_config import EvaluationConfig -from src.python.review.application_config import LanguageVersion -from src.python.review.common.file_system import create_file -from src.python.review.common.subprocess_runner import run_in_subprocess -from src.python.review.reviewers.perform_review import OutputFormat - -logger = logging.getLogger(__name__) - - -def configure_arguments(parser: argparse.ArgumentParser) -> None: - parser.add_argument(RunToolArgument.SOLUTIONS_FILE_PATH.value.long_name, - type=lambda value: Path(value).absolute(), - help=RunToolArgument.SOLUTIONS_FILE_PATH.value.description) - - parser.add_argument('-tp', '--tool-path', - default=Path(f'{os.path.dirname(os.path.abspath(__file__))}/../review/run_tool.py'), - type=lambda value: Path(value).absolute(), - help='Path to script to run on files.') - - parser.add_argument('--traceback', - help='If True, column with the full inspector feedback will be added ' - 'to the output file with results.', - action='store_true') - - parser.add_argument('-ofp', '--output-folder-path', - help='An absolute path to the folder where file with evaluation results' - 'will be stored.' - 'Default is the path to a directory, where is the folder with xlsx or csv file.', - # if None default path will be specified based on solutions_file_path. - default=None, - type=str) - - parser.add_argument('-ofn', '--output-file-name', - help='Filename for that will be created to store inspection results.' - f'Default is "{EvaluationArgument.RESULT_FILE_NAME.value}" ' - f'with the same extension as the input file has', - default=None, - type=str) - - parser.add_argument(RunToolArgument.FORMAT.value.short_name, - RunToolArgument.FORMAT.value.long_name, - default=OutputFormat.JSON.value, - choices=OutputFormat.values(), - type=str, - help=f'{RunToolArgument.FORMAT.value.description}' - f'Use this argument when {EvaluationArgument.TRACEBACK.value} argument' - 'is enabled argument will not be used otherwise.') - - parser.add_argument('--with-history', - help=f'If True, then history will be taken into account when calculating the grade. ' - f'In that case, for each fragment, the "{ColumnName.HISTORY.value}" column ' - 'must contain the history of previous errors.', - action='store_true') - - parser.add_argument('--to-drop-nan', - help='If True, empty code fragments will be deleted from df', - action='store_true') - - -def get_language_version(lang_key: str) -> LanguageVersion: - try: - return LanguageVersion(lang_key) - except ValueError as e: - logger.error(script_structure_rule) - # We should raise KeyError since it is incorrect value for key in a column - raise KeyError(e) - - -def __inspect_row(lang: str, code: str, fragment_id: int, history: Optional[str], - config: EvaluationConfig) -> Optional[str]: - print(f'current id: {fragment_id}') - # Tool does not work correctly with tmp files from module on macOS - # thus we create a real file in the file system - extension = get_language_version(lang).extension_by_language().value - tmp_file_path = config.solutions_file_path.parent.absolute() / f'inspected_code_{fragment_id}{extension}' - temp_file = next(create_file(tmp_file_path, code)) - command = config.build_command(temp_file, lang, history) - results = run_in_subprocess(command) - os.remove(temp_file) - return results - - -def __get_grade_from_traceback(traceback: str) -> str: - # this regular expression matches final tool grade: EXCELLENT, GOOD, MODERATE or BAD - return re.match(r'^.*{"code":\s"([A-Z]+)"', traceback).group(1) - - -# TODO: calculate grade after it -def inspect_solutions_df(config: EvaluationConfig, lang_code_dataframe: pd.DataFrame) -> pd.DataFrame: - report = pd.DataFrame(columns=lang_code_dataframe.columns) - report[ColumnName.TRACEBACK.value] = [] - - pandarallel.initialize() - if config.traceback: - report[ColumnName.TRACEBACK.value] = [] - try: - if config.to_drop_nan: - lang_code_dataframe = lang_code_dataframe.dropna() - lang_code_dataframe[ColumnName.TRACEBACK.value] = lang_code_dataframe.parallel_apply( - lambda row: __inspect_row(row[ColumnName.LANG.value], - row[ColumnName.CODE.value], - row[ColumnName.ID.value], - row.get(ColumnName.HISTORY.value), - config), axis=1) - - lang_code_dataframe[ColumnName.GRADE.value] = lang_code_dataframe.parallel_apply( - lambda row: __get_grade_from_traceback(row[ColumnName.TRACEBACK.value]), axis=1) - - if not config.traceback: - del lang_code_dataframe[ColumnName.TRACEBACK.value] - return lang_code_dataframe - - except ValueError as e: - logger.error(script_structure_rule) - # parallel_apply can raise ValueError but it connected to KeyError: not all columns exist in df - raise KeyError(e) - - except Exception as e: - traceback.print_exc() - logger.exception('An unexpected error.') - raise e - - -def main() -> int: - parser = argparse.ArgumentParser() - configure_arguments(parser) - - try: - start = time.time() - args = parser.parse_args() - config = EvaluationConfig(args) - lang_code_dataframe = get_solutions_df(config.extension, config.solutions_file_path) - results = inspect_solutions_df(config, lang_code_dataframe) - write_df_to_file(results, config.get_output_file_path(), config.extension) - end = time.time() - print(f'All time: {end - start}') - return 0 - - except FileNotFoundError: - logger.error('XLSX-file or CSV-file with the specified name does not exists.') - return 2 - - except KeyError: - logger.error(script_structure_rule) - return 2 - - except Exception: - traceback.print_exc() - logger.exception('An unexpected error.') - return 2 - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/src/python/evaluation/inspectors/README.md b/src/python/evaluation/inspectors/README.md deleted file mode 100644 index 762602e9..00000000 --- a/src/python/evaluation/inspectors/README.md +++ /dev/null @@ -1,312 +0,0 @@ -# Hyperstyle evaluation: inspectors - -This module allows comparing two different versions of `Hyperstyle` tool. -This module contains _preprocessing_ stage and _analysing_ stage. -`Preprocessing` stage includes: -- [filter_solutions.py](filter_solutions.py) script, that allows keeping only necessary languages in - the `csv` or `xslx` file with student solutions and drop duplicates of code fragments (optional); -- [distribute_grades.py](distribute_grades.py) allows distributing calculated grades and traceback - for unique solutions into all solutions. -- [generate_history.py](generate_history.py) allows you to generate history based on issues from previous solutions. - -`Analysing` stage includes: -- [diffs_between_df.py](diffs_between_df.py) allows finding a difference between - old and new grades and collect issues that were found in new data -- [print_inspectors_statistics.py](print_inspectors_statistics.py) allows printing statistics - that were found by [diffs_between_df.py](diffs_between_df.py) -- [get_worse_public_examples.py](get_worse_public_examples.py) allows getting - top N worse public examples from a dataset. The measure is to count unique new inspections. - -___ - -## Preprocessing - -### Filter solutions - -[filter_solutions.py](filter_solutions.py) script allows keeping only necessary languages in - the `csv` or `xslx` file with student solutions and drop duplicates of code fragments (optional). - -Please, note that your input file must meet the requirements to [evaluation](./../evaluation_run_tool.py) tool. -You can find all requirements in the evaluation [README](./../README.md) file. - -Output file is a new `xlsx` or `csv` (the same format with the input file) file with the all columns -from the input file. - -#### Usage - -Run the [filter_solutions.py](filter_solutions.py) with the arguments from command line. - -Required arguments: - -`solutions_file_path` — path to xlsx-file or csv-file with code samples. - -Optional arguments: -Argument | Description ---- | --- -|**‑l**, **‑‑languages**| Set of languages to keep in the dataset. Available values: `java7`, `java8`, `java9` `java11`, `python3`, `kotlin`. The default value is set of all languages.| -|**‑‑duplicates**| If True, drop duplicates in the "code" column. By default is disabled.| - -The resulting file will be stored in the same folder as the input file. - -___ - -### Distribute grades - -[distribute_grades.py](distribute_grades.py) allows distributing calculated grades and traceback - for unique solutions into all solutions. - -Please, note that your input file with all code fragments should consist of at least 1 obligatory columns: - -- `code`. - -Please, note that your input file with unique code fragments should consist of at least 2 obligatory columns: - -- `code`, -- `grade`, -- `traceback` (optional), - -and must have all fragments from the input file with all code fragments. - -Output file is a new `xlsx` or `csv` (the same format with the input files) file with the all columns -from the input file with unique solutions. - -#### Usage - -Run the [distribute_grades.py](distribute_grades.py) with the arguments from command line. - -Required arguments: - -- `solutions_file_path_all` — path to xlsx-file or csv-file with all code samples, -- `solutions_file_path_uniq` — path to xlsx-file or csv-file with unique code samples, - -The resulting file will be stored in the same folder as the input file with all samples. - ----- - -### Generate history - -[generate_history.py](generate_history.py) allows you to generate history based on issues from previous solutions. - -Please, note that your solutions file should consist of at least 4 obligatory columns: - -- `user`, -- `lang`, -- `time`, -- `traceback`. - -You can get such a file with [evaluation_run_tool.py](../evaluation_run_tool.py). - -The output file is a new `xlsx` or `csv` (the same format with the input files) file with all columns from the input -except for `traceback` and `grade` (this behavior can be changed when you run the script). - -#### Usage - -Run the [generate_history.py](generate_history.py) with the arguments from command line. - -Required argument: - -- `solutions_file_path` — path to xlsx-file or csv-file with necessary columns, - -Optional arguments: -Argument | Description ---- | --- -|**‑o**, **‑‑output‑path**| The path where the dataset with history will be saved. If not specified, the dataset will be saved next to the original one. | -|**‑‑to‑drop‑traceback**| The `traceback` column will be removed from the final dataset. Default is false. | -|**‑‑to‑drop‑grades**| The `grade` column will be removed from the final dataset. Default is false.| - -___ - -## Analysing - -### Find diffs - -[diffs_between_df.py](diffs_between_df.py) allows finding a difference between - old and new grades and collect issues that were found in new data. - -Please, note that your input files should consist of at least 3 obligatory columns: - -- `id`, -- `grade`, -- `traceback`. - -Output file is a `pickle` file with serialized dictionary with the result. - - -#### Usage - -Run the [diffs_between_df.py](diffs_between_df.py) with the arguments from command line. - -Required arguments: - -- `solutions_file_path_old` — path to xlsx-file or csv-file with code samples that was graded by the old version of the tool, -- `solutions_file_path_new` — path to xlsx-file or csv-file with code samples that was graded by the new version of the tool. - -The resulting file will be stored in the same folder as the `solutions_file_path_old` input file. - -An example of the pickle` file is: - -```json -{ - grade: [2, 3], - decreased_grade: [1], - user: 2, - traceback: { - 1: { - PenaltyIssue( - origin_class='C0305', - description='Trailing newlines', - line_no=15, - column_no=1, - type=IssueType('CODE_STYLE'), - - file_path=Path(), - inspector_type=InspectorType.UNDEFINED, - influence_on_penalty=0, - ), PenaltyIssue( - origin_class='E211', - description='whitespace before \'(\'', - line_no=1, - column_no=6, - type=IssueType('CODE_STYLE'), - - file_path=Path(), - inspector_type=InspectorType.UNDEFINED, - influence_on_penalty=0.6, - ), - } - }, - penalty: { - 1: { - PenaltyIssue( - origin_class='E211', - description='whitespace before \'(\'', - line_no=1, - column_no=6, - type=IssueType('CODE_STYLE'), - - file_path=Path(), - inspector_type=InspectorType.UNDEFINED, - influence_on_penalty=0.6, - ), - } - } -} -``` -In the `grade` field are stored fragments ids for which grade was increased in the new data. -In the `decreased_grade` field are stored fragments ids for which grade was decreased in the new data. -In the `user` field are stored count unique users in the new dataset. -In the `traceback` field for fragments ids are stored set of issues. These issues were found in the new data and were not found in the old data. -In the `penalty` field for fragments ids are stored set of issues. These issues have not zero `influence_on_penalty` coefficient. - -___ - -### Print statistics - -[print_inspectors_statistics.py](print_inspectors_statistics.py) allows print statistics - that were calculated by [diffs_between_df.py](diffs_between_df.py) - -#### Usage - -Run the [print_inspectors_statistics.py](print_inspectors_statistics.py) with the arguments from command line. - -Required arguments: - -- `diffs_file_path` — path to a `pickle` file, that was calculated by [diffs_between_df.py](diffs_between_df.py). - -Optional arguments: -Argument | Description ---- | --- -|**‑‑categorize**| If True, statistics will be categorized by several categories. By default is disabled.| -|**‑n**, **‑‑top‑n**| The top N items will be printed. Default value is 10.| -|**‑‑full‑stat**| If True, full statistics (with all issues) will be printed. By default is disabled.| - -The statistics will be printed into console. - -The output contains: -- was found incorrect grades or not; -- how many grades have decreased value; -- how many unique users was found in the new dataset; -- for new issues and for penalty statistics: - - how many fragments has additional issues; - - how many unique issues was found; - - top N issues in the format: (issue_key, frequency); - - short categorized statistics: for each category how many issues were found and how many - fragments have these issues; - - \[Optional\] full categorized statistics: for each category for each issue how many - fragments have this issue -- for each category base influence on the penalty statistics: min, max and median values - -An example of the printed statistics (without full categorized statistics): - -```json -SUCCESS! Was not found incorrect grades. -All grades are equal. -______ -NEW INSPECTIONS STATISTICS: -39830 fragments has additional issues -139 unique issues was found -4671 unique users was found! -______ -Top 10 issues: -SC200: 64435 times -WPS432: 17477 times -WPS221: 10618 times -WPS336: 4965 times -H601: 3826 times -SC100: 2719 times -WPS319: 2655 times -WPS317: 2575 times -WPS515: 1783 times -WPS503: 1611 times -______ -CODE_STYLE: 28 issues, 26171 fragments -BEST_PRACTICES: 76 issues, 88040 fragments -ERROR_PRONE: 17 issues, 2363 fragments -COMPLEXITY: 17 issues, 13928 fragments -COHESION: 1 issues, 3826 fragments -______ -______ -PENALTY INSPECTIONS STATISTICS; -Statistics is empty! -______ -______ -INFLUENCE ON PENALTY STATISTICS; -CODE_STYLE issues: min=1, max=100, median=86 -BEST_PRACTICES issues: min=1, max=100, median=98.0 -COMPLEXITY issues: min=1, max=100, median=16.0 -MAINTAINABILITY issues: min=1, max=7, median=2.0 -CYCLOMATIC_COMPLEXITY issues: min=1, max=58, median=11.5 -COHESION issues: min=1, max=100, median=56 -BOOL_EXPR_LEN issues: min=6, max=6, median=6 -______ -``` - ---- - -### Get worse public examples - -[get_worse_public_examples.py](get_worse_public_examples.py) allows getting - top N worse public examples from a dataset. The measure is to count unique new inspections. - -#### Usage - -Run the [get_worse_public_examples.py](get_worse_public_examples.py) with the arguments from command line. - -Required arguments: - -- `solutions_file_path` — path to xlsx-file or csv-file with graded code samples; -- `diffs_file_path` — path to a `pickle` file, that was calculated by [diffs_between_df.py](diffs_between_df.py). - -Please, note that your `solutions_file_path` file with code fragments should consist of at least 2 obligatory columns: - -- `code`, -- `traceback`, -- `is_public`, -- `id`. - -Optional arguments: -Argument | Description ---- | --- -|**‑n**, **‑‑n**| The N worse fragments will be saved.| - -The resulting file will be stored in the same folder as the `solutions_file_path` input file. diff --git a/src/python/evaluation/inspectors/__init__.py b/src/python/evaluation/inspectors/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/python/evaluation/inspectors/common/__init__.py b/src/python/evaluation/inspectors/common/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/python/evaluation/inspectors/common/statistics.py b/src/python/evaluation/inspectors/common/statistics.py deleted file mode 100644 index 401a29a6..00000000 --- a/src/python/evaluation/inspectors/common/statistics.py +++ /dev/null @@ -1,108 +0,0 @@ -from collections import defaultdict -from dataclasses import dataclass -from statistics import median -from typing import Dict, List, Tuple - -from src.python.review.inspectors.issue import BaseIssue, IssueType, ShortIssue - - -@dataclass(frozen=True, eq=True) -class PenaltyIssue(BaseIssue): - influence_on_penalty: int - - -@dataclass(frozen=True) -class IssuesStatistics: - stat: Dict[ShortIssue, int] - fragments_in_stat: int - - def print_full_statistics(self, n: int, full_stat: bool, separator: str = '') -> None: - if self.fragments_in_stat == 0: - print('Statistics is empty!') - return - - print(f'{self.fragments_in_stat} fragments has additional issues') - print(f'{self.count_unique_issues()} unique issues was found') - - self.print_top_n(n, separator) - self.print_short_categorized_statistics() - print(separator) - - if full_stat: - self.print_full_inspectors_statistics() - - def print_top_n(self, n: int, separator: str) -> None: - top_n = self.get_top_n_issues(n) - print(separator) - print(f'Top {n} issues:') - for issue, freq in top_n: - IssuesStatistics.print_issue_with_freq(issue, freq) - print(separator) - - def print_full_inspectors_statistics(self, to_categorize: bool = True) -> None: - if to_categorize: - categorized_statistics: Dict[IssueType, Dict[ShortIssue, int]] = self.get_categorized_statistics() - for category, issues in categorized_statistics.items(): - print(f'{category.value} issues:') - self.__print_stat(issues) - else: - self.__print_stat(self.stat) - - @classmethod - def __print_stat(cls, stat: Dict[ShortIssue, int]) -> None: - for issue, freq in stat.items(): - cls.print_issue_with_freq(issue, freq, prefix='- ') - - @classmethod - def print_issue_with_freq(cls, issue: ShortIssue, freq: int, prefix: str = '', suffix: str = '') -> None: - print(f'{prefix}{issue.origin_class}: {freq} times{suffix}') - - def get_categorized_statistics(self) -> Dict[IssueType, Dict[ShortIssue, int]]: - categorized_stat: Dict[IssueType, Dict[ShortIssue, int]] = defaultdict(dict) - for issue, freq in self.stat.items(): - categorized_stat[issue.type][issue] = freq - return categorized_stat - - # Get statistics for each IssueType: count unique issues, count fragments with these issues - def get_short_categorized_statistics(self) -> Dict[IssueType, Tuple[int, int]]: - categorized_statistics: Dict[IssueType, Dict[ShortIssue, int]] = self.get_categorized_statistics() - short_categorized_statistics = defaultdict(tuple) - for issue_type, stat in categorized_statistics.items(): - unique_issues = len(stat) - fragments = sum(stat.values()) - short_categorized_statistics[issue_type] = (unique_issues, fragments) - return short_categorized_statistics - - def print_short_categorized_statistics(self) -> None: - short_categorized_statistics = self.get_short_categorized_statistics() - for category, stat in short_categorized_statistics.items(): - print(f'{category.value}: {stat[0]} issues, {stat[1]} fragments') - - def get_top_n_issues(self, n: int) -> List[ShortIssue]: - return sorted(self.stat.items(), key=lambda t: t[1], reverse=True)[:n] - - def count_unique_issues(self) -> int: - return len(self.stat) - - -# Store list of penalty influences for each category -@dataclass -class PenaltyInfluenceStatistics: - stat: Dict[IssueType, List[float]] - - def __init__(self, issues_stat_dict: Dict[int, List[PenaltyIssue]]): - self.stat = defaultdict(list) - for _, issues in issues_stat_dict.items(): - for issue in issues: - self.stat[issue.type].append(issue.influence_on_penalty) - - def print_stat(self): - for category, issues in self.stat.items(): - print(f'{category.value} issues: min={min(issues)}, max={max(issues)}, median={median(issues)}') - - -@dataclass(frozen=True) -class GeneralInspectorsStatistics: - new_issues_stat: IssuesStatistics - penalty_issues_stat: IssuesStatistics - penalty_influence_stat: PenaltyInfluenceStatistics diff --git a/src/python/evaluation/inspectors/diffs_between_df.py b/src/python/evaluation/inspectors/diffs_between_df.py deleted file mode 100644 index 5556484f..00000000 --- a/src/python/evaluation/inspectors/diffs_between_df.py +++ /dev/null @@ -1,109 +0,0 @@ -import argparse -from pathlib import Path - -import pandas as pd -from src.python.common.tool_arguments import RunToolArgument -from src.python.evaluation.common.pandas_util import ( - get_inconsistent_positions, get_issues_by_row, get_solutions_df, get_solutions_df_by_file_path, -) -from src.python.evaluation.common.util import ColumnName -from src.python.review.common.file_system import ( - Extension, get_parent_folder, get_restricted_extension, serialize_data_and_write_to_file, -) -from src.python.review.quality.model import QualityType - - -def configure_arguments(parser: argparse.ArgumentParser) -> None: - parser.add_argument(f'{RunToolArgument.SOLUTIONS_FILE_PATH.value.long_name}_old', - type=lambda value: Path(value).absolute(), - help=f'{RunToolArgument.SOLUTIONS_FILE_PATH.value.description}' - f'\nAll code fragments from this file must be graded ' - f'(file contains grade and traceback (optional) columns)') - - parser.add_argument(f'{RunToolArgument.SOLUTIONS_FILE_PATH.value.long_name}_new', - type=lambda value: Path(value).absolute(), - help=f'{RunToolArgument.SOLUTIONS_FILE_PATH.value.description}' - f'\nAll code fragments from this file must be graded ' - f'(file contains grade and traceback (optional) columns)') - - -# Find difference between two dataframes. Return dict: -# { -# grade: [list_of_fragment_ids], -# decreased_grade: [list_of_fragment_ids], -# user: count_unique_users, -# traceback: { -# fragment_id: [list of issues] -# }, -# penalty: { -# fragment_id: [list of issues] -# }, -# } -# The key contains only fragments that increase quality in new df -# The key contains only fragments that decrease quality in new df -# The key count number of unique users in the new dataset -# The key contains list of new issues for each fragment -# The key contains list of issues with not zero influence_on_penalty coefficient -def find_diffs(old_df: pd.DataFrame, new_df: pd.DataFrame) -> dict: - if ColumnName.HISTORY.value in new_df.columns: - del new_df[ColumnName.HISTORY.value] - new_df = new_df.reindex(columns=old_df.columns) - inconsistent_positions = get_inconsistent_positions(old_df, new_df) - diffs = { - ColumnName.GRADE.value: [], - ColumnName.DECREASED_GRADE.value: [], - ColumnName.TRACEBACK.value: {}, - ColumnName.PENALTY.value: {}, - } - if ColumnName.USER.value in new_df.columns: - diffs[ColumnName.USER.value] = len(new_df[ColumnName.USER.value].unique()) - else: - diffs[ColumnName.USER.value] = 0 - # Keep only diffs in the TRACEBACK column - for row, _ in filter(lambda t: t[1] == ColumnName.TRACEBACK.value, inconsistent_positions.index): - old_value = old_df.iloc[row][ColumnName.GRADE.value] - new_value = new_df.iloc[row][ColumnName.GRADE.value] - old_quality = QualityType(old_value).to_number() - new_quality = QualityType(new_value).to_number() - fragment_id = old_df.iloc[row][ColumnName.ID.value] - if new_quality > old_quality: - # It is an unexpected keys, we should check the algorithm - diffs[ColumnName.GRADE.value].append(fragment_id) - else: - if new_quality < old_quality: - diffs[ColumnName.DECREASED_GRADE.value].append(fragment_id) - old_issues = get_issues_by_row(old_df, row) - new_issues = get_issues_by_row(new_df, row) - # Find difference between issues - if len(old_issues) > len(new_issues): - raise ValueError(f'New dataframe contains less issues than old for fragment {id}') - difference = set(set(new_issues) - set(old_issues)) - if len(difference) > 0: - diffs[ColumnName.TRACEBACK.value][fragment_id] = difference - - # Find issues with influence_in_penalty > 0 - penalty = set(filter(lambda i: i.influence_on_penalty > 0, new_issues)) - if len(penalty) > 0: - diffs[ColumnName.PENALTY.value][fragment_id] = penalty - return diffs - - -def main() -> None: - parser = argparse.ArgumentParser() - configure_arguments(parser) - args = parser.parse_args() - - old_solutions_file_path = args.solutions_file_path_old - output_ext = get_restricted_extension(old_solutions_file_path, [Extension.XLSX, Extension.CSV]) - old_solutions_df = get_solutions_df(output_ext, old_solutions_file_path) - - new_solutions_file_path = args.solutions_file_path_new - new_solutions_df = get_solutions_df_by_file_path(new_solutions_file_path) - - diffs = find_diffs(old_solutions_df, new_solutions_df) - output_path = get_parent_folder(Path(old_solutions_file_path)) / f'diffs{Extension.PICKLE.value}' - serialize_data_and_write_to_file(output_path, diffs) - - -if __name__ == '__main__': - main() diff --git a/src/python/evaluation/inspectors/distribute_grades.py b/src/python/evaluation/inspectors/distribute_grades.py deleted file mode 100644 index 0518b9a1..00000000 --- a/src/python/evaluation/inspectors/distribute_grades.py +++ /dev/null @@ -1,66 +0,0 @@ -import argparse -from pathlib import Path -from typing import Dict, Optional, Tuple - -import pandas as pd -from src.python.common.tool_arguments import RunToolArgument -from src.python.evaluation.common.pandas_util import get_solutions_df, get_solutions_df_by_file_path, write_df_to_file -from src.python.evaluation.common.util import ColumnName -from src.python.review.common.file_system import Extension, get_parent_folder, get_restricted_extension - -CodeToGradesDict = Dict[str, Tuple[str, Optional[str]]] - - -def configure_arguments(parser: argparse.ArgumentParser) -> None: - parser.add_argument(f'{RunToolArgument.SOLUTIONS_FILE_PATH.value.long_name}_all', - type=lambda value: Path(value).absolute(), - help=f'{RunToolArgument.SOLUTIONS_FILE_PATH.value.description}' - f'\nAll code fragments from this file must be in the uniq file') - - parser.add_argument(f'{RunToolArgument.SOLUTIONS_FILE_PATH.value.long_name}_uniq', - type=lambda value: Path(value).absolute(), - help=f'{RunToolArgument.SOLUTIONS_FILE_PATH.value.description}' - f'\nAll code fragments from this file must be graded ' - f'(file contains grade and traceback (optional) columns)') - - -def __add_grade(code_to_grades_dict: CodeToGradesDict, code: str, grade: str, traceback: Optional[str]) -> None: - code_to_grades_dict[code] = (grade, traceback) - - -# Return a dictionary that contains code fragments -# with their grades and traceback (optional, can be None) -def get_code_to_grades_dict(df: pd.DataFrame) -> CodeToGradesDict: - code_to_grades_dict: CodeToGradesDict = {} - df.apply(lambda row: __add_grade(code_to_grades_dict, - row[ColumnName.CODE.value], - row[ColumnName.GRADE.value], - row[ColumnName.TRACEBACK.value]), axis=1) - return code_to_grades_dict - - -def fill_all_solutions_df(all_solutions_df: pd.DataFrame, code_to_grades_dict: CodeToGradesDict) -> pd.DataFrame: - all_solutions_df[ColumnName.GRADE.value], all_solutions_df[ColumnName.TRACEBACK.value] = zip( - *all_solutions_df[ColumnName.CODE.value].map(lambda code: code_to_grades_dict[code])) - return all_solutions_df - - -def main() -> None: - parser = argparse.ArgumentParser() - configure_arguments(parser) - args = parser.parse_args() - - all_solutions_file_path = args.solutions_file_path_all - output_ext = get_restricted_extension(all_solutions_file_path, [Extension.XLSX, Extension.CSV]) - all_solutions_df = get_solutions_df(output_ext, all_solutions_file_path) - uniq_solutions_df = get_solutions_df_by_file_path(args.solutions_file_path_uniq) - - code_to_grades_dict = get_code_to_grades_dict(uniq_solutions_df) - all_solutions_df = fill_all_solutions_df(all_solutions_df, code_to_grades_dict) - - output_path = get_parent_folder(Path(all_solutions_file_path)) - write_df_to_file(all_solutions_df, output_path / f'evaluation_result_all{output_ext.value}', output_ext) - - -if __name__ == '__main__': - main() diff --git a/src/python/evaluation/inspectors/filter_issues.py b/src/python/evaluation/inspectors/filter_issues.py deleted file mode 100644 index 60276f20..00000000 --- a/src/python/evaluation/inspectors/filter_issues.py +++ /dev/null @@ -1,67 +0,0 @@ -import argparse -from pathlib import Path -from typing import List, Set - -import pandas as pd -from src.python.common.tool_arguments import RunToolArgument -from src.python.evaluation.common.pandas_util import get_issues_from_json, get_solutions_df_by_file_path -from src.python.evaluation.common.util import ColumnName, parse_set_arg -from src.python.evaluation.inspectors.common.statistics import PenaltyIssue -from src.python.review.common.file_system import Extension, get_parent_folder, serialize_data_and_write_to_file -from src.python.review.inspectors.issue import BaseIssue - - -TRACEBACK = ColumnName.TRACEBACK.value -ID = ColumnName.ID.value -GRADE = ColumnName.GRADE.value - - -def configure_arguments(parser: argparse.ArgumentParser) -> None: - parser.add_argument(RunToolArgument.SOLUTIONS_FILE_PATH.value.long_name, - type=lambda value: Path(value).absolute(), - help=f'{RunToolArgument.SOLUTIONS_FILE_PATH.value.description}' - f'\nAll code fragments from this file must be graded ') - - parser.add_argument('-i', '--issues', - help='Set of issues', - default='') - - -def __get_new_issues(traceback: str, new_issues_classes: Set[str]) -> List[PenaltyIssue]: - all_issues = get_issues_from_json(traceback) - return list(filter(lambda i: i.origin_class in new_issues_classes, all_issues)) - - -def __add_issues_for_fragment(fragment_id: int, new_issues: List[BaseIssue], diffs: dict) -> None: - if len(new_issues) > 0: - diffs[TRACEBACK][fragment_id] = new_issues - - -# Make a dict with the same structure as in the find_diffs function from diffs_between_df.py -def get_statistics_dict(solutions_df: pd.DataFrame, new_issues_classes: Set[str]) -> dict: - diffs = { - GRADE: [], - TRACEBACK: {}, - } - solutions_df.apply(lambda row: __add_issues_for_fragment(row[ID], - __get_new_issues(row[TRACEBACK], new_issues_classes), - diffs), axis=1) - return diffs - - -def main() -> None: - parser = argparse.ArgumentParser() - configure_arguments(parser) - args = parser.parse_args() - - solutions_file_path = args.solutions_file_path - solutions_df = get_solutions_df_by_file_path(solutions_file_path) - issues = parse_set_arg(args.issues) - - diffs = get_statistics_dict(solutions_df, issues) - output_path = get_parent_folder(Path(solutions_file_path)) / f'diffs{Extension.PICKLE.value}' - serialize_data_and_write_to_file(output_path, diffs) - - -if __name__ == '__main__': - main() diff --git a/src/python/evaluation/inspectors/filter_solutions.py b/src/python/evaluation/inspectors/filter_solutions.py deleted file mode 100644 index 99d3ac89..00000000 --- a/src/python/evaluation/inspectors/filter_solutions.py +++ /dev/null @@ -1,60 +0,0 @@ -import argparse -import logging -from pathlib import Path -from typing import Set - -from src.python.common.tool_arguments import RunToolArgument -from src.python.evaluation.common.pandas_util import ( - drop_duplicates, - filter_df_by_language, - get_solutions_df, - write_df_to_file, -) -from src.python.review.application_config import LanguageVersion -from src.python.review.common.file_system import Extension, get_parent_folder, get_restricted_extension - -logger = logging.getLogger(__name__) - - -def parse_languages(value: str) -> Set[LanguageVersion]: - passed_names = value.lower().split(',') - allowed_names = {lang.value for lang in LanguageVersion} - if not all(name in allowed_names for name in passed_names): - raise argparse.ArgumentError('--languages', 'Incorrect --languages\' names') - - return {LanguageVersion(name) for name in passed_names} - - -def configure_arguments(parser: argparse.ArgumentParser) -> None: - parser.add_argument(RunToolArgument.SOLUTIONS_FILE_PATH.value.long_name, - type=lambda value: Path(value).absolute(), - help=RunToolArgument.SOLUTIONS_FILE_PATH.value.description) - - parser.add_argument('-l', '--languages', - help='Set of languages to keep in the dataset', - type=parse_languages, - default=set(LanguageVersion)) - - parser.add_argument('--duplicates', - help='If True, drop duplicates in the "code" column.', - action='store_true') - - -def main() -> None: - parser = argparse.ArgumentParser() - configure_arguments(parser) - args = parser.parse_args() - - solutions_file_path = args.solutions_file_path - ext = get_restricted_extension(solutions_file_path, [Extension.XLSX, Extension.CSV]) - solutions_df = get_solutions_df(ext, solutions_file_path) - - filtered_df = filter_df_by_language(solutions_df, args.languages) - if args.duplicates: - filtered_df = drop_duplicates(filtered_df) - output_path = get_parent_folder(Path(solutions_file_path)) - write_df_to_file(filtered_df, output_path / f'filtered_solutions{ext.value}', ext) - - -if __name__ == '__main__': - main() diff --git a/src/python/evaluation/inspectors/generate_history.py b/src/python/evaluation/inspectors/generate_history.py deleted file mode 100644 index 2ff95c34..00000000 --- a/src/python/evaluation/inspectors/generate_history.py +++ /dev/null @@ -1,131 +0,0 @@ -import argparse -import json -from collections import Counter -from pathlib import Path - -import pandas as pd -from pandarallel import pandarallel -from src.python.common.tool_arguments import RunToolArgument -from src.python.evaluation.common.pandas_util import ( - get_issues_from_json, - get_solutions_df_by_file_path, - write_df_to_file, -) -from src.python.evaluation.common.util import ColumnName, EvaluationArgument -from src.python.evaluation.evaluation_run_tool import get_language_version -from src.python.review.common.file_system import ( - Extension, - get_name_from_path, - get_parent_folder, - get_restricted_extension, -) -from src.python.review.common.language import Language - -TRACEBACK = EvaluationArgument.TRACEBACK.value -GRADE = ColumnName.GRADE.value -HISTORY = ColumnName.HISTORY.value -USER = ColumnName.USER.value -LANG = ColumnName.LANG.value -TIME = ColumnName.TIME.value -EXTRACTED_ISSUES = 'extracted_issues' - - -def configure_arguments(parser: argparse.ArgumentParser) -> None: - parser.add_argument( - RunToolArgument.SOLUTIONS_FILE_PATH.value.long_name, - type=lambda value: Path(value).absolute(), - help=f'Path to csv or xlsx file. Your dataset must include column-names: ' - f'"{USER}", "{LANG}", "{TIME}, "{TRACEBACK}".', - ) - - parser.add_argument( - '-o', '--output-path', - type=lambda value: Path(value).absolute(), - help='The path where the dataset with history will be saved. ' - 'If not specified, the dataset will be saved next to the original one.', - ) - - parser.add_argument( - '--to-drop-traceback', - help=f'The "{TRACEBACK}" column will be removed from the final dataset.', - action='store_true', - ) - - parser.add_argument( - '--to-drop-grade', - help=f'The "{GRADE}" column will be removed from the final dataset.', - action='store_true', - ) - - -def _update_counter(extracted_issues: str, counter: Counter) -> None: - issue_classes = [] - if extracted_issues: - issue_classes = extracted_issues.split(',') - - counter.update(issue_classes) - - -def _add_history(row, solutions_df: pd.DataFrame) -> str: - counter = Counter() - - filtered_df = solutions_df[ - (solutions_df[USER] == row[USER]) & (solutions_df[LANG] == row[LANG]) & (solutions_df[TIME] < row[TIME]) - ] - filtered_df.apply(lambda row: _update_counter(row[EXTRACTED_ISSUES], counter), axis=1) - - history = {} - - # If we were unable to identify the language version, we return an empty history - try: - lang_version = get_language_version(row[LANG]) - except KeyError: - return json.dumps(history) - - lang = Language.from_language_version(lang_version) - if len(counter) != 0: - history = {lang.value.lower(): [{'origin_class': key, 'number': value} for key, value in counter.items()]} - - return json.dumps(history) - - -def _extract_issues(traceback: str) -> str: - issues = get_issues_from_json(traceback) - issue_classes = [issue.origin_class for issue in issues] - return ','.join(issue_classes) - - -def main(): - parser = argparse.ArgumentParser() - configure_arguments(parser) - args = parser.parse_args() - - pandarallel.initialize() - - solutions_file_path = args.solutions_file_path - solutions_df = get_solutions_df_by_file_path(solutions_file_path) - solutions_df[EXTRACTED_ISSUES] = solutions_df.parallel_apply(lambda row: _extract_issues(row[TRACEBACK]), axis=1) - solutions_df[HISTORY] = solutions_df.parallel_apply(_add_history, axis=1, args=(solutions_df,)) - - columns_to_drop = [EXTRACTED_ISSUES] - - if args.to_drop_grade: - columns_to_drop.append(GRADE) - - if args.to_drop_traceback: - columns_to_drop.append(TRACEBACK) - - solutions_df.drop(columns=columns_to_drop, inplace=True, errors='ignore') - - output_path = args.output_path - if output_path is None: - output_dir = get_parent_folder(solutions_file_path) - dataset_name = get_name_from_path(solutions_file_path, with_extension=False) - output_path = output_dir / f'{dataset_name}_with_history{Extension.CSV.value}' - - output_ext = get_restricted_extension(solutions_file_path, [Extension.XLSX, Extension.CSV]) - write_df_to_file(solutions_df, output_path, output_ext) - - -if __name__ == '__main__': - main() diff --git a/src/python/evaluation/inspectors/get_worse_public_examples.py b/src/python/evaluation/inspectors/get_worse_public_examples.py deleted file mode 100644 index 980c8a9e..00000000 --- a/src/python/evaluation/inspectors/get_worse_public_examples.py +++ /dev/null @@ -1,68 +0,0 @@ -import argparse -from pathlib import Path -from typing import Dict, List - -import pandas as pd -from src.python.common.tool_arguments import RunToolArgument -from src.python.evaluation.common.csv_util import write_dataframe_to_csv -from src.python.evaluation.common.pandas_util import filter_df_by_single_value, get_solutions_df_by_file_path -from src.python.evaluation.common.util import ColumnName -from src.python.evaluation.inspectors.common.statistics import PenaltyIssue -from src.python.review.common.file_system import deserialize_data_from_file, Extension, get_parent_folder - - -def configure_arguments(parser: argparse.ArgumentParser) -> None: - parser.add_argument(RunToolArgument.SOLUTIONS_FILE_PATH.value.long_name, - type=lambda value: Path(value).absolute(), - help=RunToolArgument.SOLUTIONS_FILE_PATH.value.description) - - parser.add_argument(RunToolArgument.DIFFS_FILE_PATH.value.long_name, - type=lambda value: Path(value).absolute(), - help=RunToolArgument.DIFFS_FILE_PATH.value.description) - - parser.add_argument('-n', '--n', - help='The N worse fragments will be saved', - type=int, - default=10) - - -def __get_new_inspections(fragment_id_to_issues: Dict[int, List[PenaltyIssue]], fragment_id: int) -> str: - return ','.join(set(map(lambda i: i.origin_class, fragment_id_to_issues.get(fragment_id, [])))) - - -def __get_public_fragments(solutions_df: pd.DataFrame, diffs_dict: dict) -> pd.DataFrame: - # Keep only public solutions - public_fragments = filter_df_by_single_value(solutions_df, ColumnName.IS_PUBLIC.value, 'YES') - count_inspections_column = 'count_inspections' - new_inspections_column = 'new_inspections' - - # Get only new inspections and count them - fragment_id_to_issues = diffs_dict[ColumnName.TRACEBACK.value] - public_fragments[new_inspections_column] = public_fragments.apply( - lambda row: __get_new_inspections(fragment_id_to_issues, row[ColumnName.ID.value]), axis=1) - public_fragments[count_inspections_column] = public_fragments.apply( - lambda row: len(row[new_inspections_column].split(',')), axis=1) - - public_fragments = public_fragments.sort_values(count_inspections_column, ascending=False) - # Keep only public columns - return public_fragments[[ColumnName.CODE.value, ColumnName.TRACEBACK.value, new_inspections_column]] - - -# TODO: add readme -def main() -> None: - parser = argparse.ArgumentParser() - configure_arguments(parser) - args = parser.parse_args() - - solutions_file_path = args.solutions_file_path - solutions_df = get_solutions_df_by_file_path(solutions_file_path) - diffs = deserialize_data_from_file(args.diffs_file_path) - - public_fragments = __get_public_fragments(solutions_df, diffs) - - output_path = get_parent_folder(Path(solutions_file_path)) / f'worse_fragments{Extension.CSV.value}' - write_dataframe_to_csv(output_path, public_fragments.head(args.n)) - - -if __name__ == '__main__': - main() diff --git a/src/python/evaluation/inspectors/inspectors_stat/README.md b/src/python/evaluation/inspectors/inspectors_stat/README.md deleted file mode 100644 index f8a4ad94..00000000 --- a/src/python/evaluation/inspectors/inspectors_stat/README.md +++ /dev/null @@ -1,45 +0,0 @@ -# Hyperstyle evaluation: inspectors statistics gathering - -This module allows gathering statistics about inspections that are used -during analysis for a specific language. We collect all available issues' keys, -removed ignored ones and gather statistics for fours main categories: - -- code style issues; -- best practice issues; -- error-prone issues; -- code complexity issues. - -More information about these categories can be found on [this](https://support.hyperskill.org/hc/en-us/articles/360049582712-Code-style-Code-quality) page. - -## Current statistics - -The current statistics is: - -| | Error prone | Code style | Code complexity | Best practice | -|------------|:-----------:|:----------:|:---------------:|:-------------:| -| Python | 162 | 146 | 35 | 254 | -| Java | 51 | 50 | 8 | 110 | -| JavaScript | 15 | 17 | 1 | 34 | -| Kotlin | 21 | 70 | 12 | 75 | - - -## Usage - -Run the [statistics_gathering.py](statistics_gathering.py) with the arguments from command line. - -Required arguments: - -`language` — the language for which statistics will be gathering. -Available values are: `python`, `java`, `kotlin`, `javascript`. - -An example of the output is: - -```text -Collected statistics for python language: -best practices: 254 times; -code style: 146 times; -complexity: 35 times; -error prone: 162 times; -undefined: 3 times; -Note: undefined means a category that is not categorized among the four main categories. Most likely it is info category -``` diff --git a/src/python/evaluation/inspectors/inspectors_stat/__init__.py b/src/python/evaluation/inspectors/inspectors_stat/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/python/evaluation/inspectors/inspectors_stat/issues/__init__.py b/src/python/evaluation/inspectors/inspectors_stat/issues/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/python/evaluation/inspectors/inspectors_stat/issues/flake8_all_issues.py b/src/python/evaluation/inspectors/inspectors_stat/issues/flake8_all_issues.py deleted file mode 100644 index eecc92dc..00000000 --- a/src/python/evaluation/inspectors/inspectors_stat/issues/flake8_all_issues.py +++ /dev/null @@ -1,601 +0,0 @@ -# According to https://gist.github.com/sharkykh/c76c80feadc8f33b129d846999210ba3 -ALL_STANDARD_ISSUES = { - # Indentation - 'E101': 'indentation contains mixed spaces and tabs', - 'E111': 'indentation is not a multiple of four', - 'E112': 'expected an indented block', - 'E113': 'unexpected indentation', - 'E114': 'indentation is not a multiple of four (comment)', - 'E115': 'expected an indented block (comment)', - 'E116': 'unexpected indentation (comment)', - 'E121': 'continuation line under-indented for hanging indent', - 'E122': 'continuation line missing indentation or outdented', - 'E123': 'closing bracket does not match indentation of opening bracket\'s line', - 'E124': 'closing bracket does not match visual indentation', - 'E125': 'continuation line with same indent as next logical line', - 'E126': 'continuation line over-indented for hanging indent', - 'E127': 'continuation line over-indented for visual indent', - 'E128': 'continuation line under-indented for visual indent', - 'E129': 'visually indented line with same indent as next logical line', - 'E131': 'continuation line unaligned for hanging indent', - 'E133': 'closing bracket is missing indentation', - - # Whitespace - 'E201': 'whitespace after \'(\'', - 'E202': 'whitespace before \')\'', - 'E203': 'whitespace before \':\'', - 'E211': 'whitespace before \'(\'', - 'E221': 'multiple spaces before operator', - 'E222': 'multiple spaces after operator', - 'E223': 'tab before operator', - 'E224': 'tab after operator', - 'E225': 'missing whitespace around operator', - 'E226': 'missing whitespace around arithmetic operator', - 'E227': 'missing whitespace around bitwise or shift operator', - 'E228': 'missing whitespace around modulo operator', - 'E231': 'missing whitespace after \',\', \';\', or \':\'', - 'E241': 'multiple spaces after \',\'', - 'E242': 'tab after \',\'', - 'E251': 'unexpected spaces around keyword / parameter equals', - 'E261': 'at least two spaces before inline comment', - 'E262': 'inline comment should start with \'# \'', - 'E265': 'block comment should start with \'# \'', - 'E266': 'too many leading \'#\' for block comment', - 'E271': 'multiple spaces after keyword', - 'E272': 'multiple spaces before keyword', - 'E273': 'tab after keyword', - 'E274': 'tab before keyword', - 'E275': 'missing whitespace after keyword', - - # Blank line - 'E301': 'expected 1 blank line, found 0', - 'E302': 'expected 2 blank lines, found 0', - 'E303': 'too many blank lines (3)', - 'E304': 'blank lines found after function decorator', - 'E305': 'expected 2 blank lines after end of function or class', - 'E306': 'expected 1 blank line before a nested definition', - - # Import - 'E401': 'multiple imports on one line', - 'E402': 'module level import not at top of file', - - # Line length - 'E501': 'line too long (82 > 79 characters)', - 'E502': 'the backslash is redundant between brackets', - - # Statement - 'E701': 'multiple statements on one line (colon)', - 'E702': 'multiple statements on one line (semicolon)', - 'E703': 'statement ends with a semicolon', - 'E704': 'multiple statements on one line (def)', - 'E711': 'comparison to None should be \'if cond is None:\'', - 'E712': 'comparison to True should be \'if cond is True:\' or \'if cond:\'', - 'E713': 'test for membership should be \'not in\'', - 'E714': 'test for object identity should be \'is not\'', - 'E721': 'do not compare types, use \'isinstance()\'', - 'E722': 'do not use bare except, specify exception instead', - 'E731': 'do not use variables named \'l\', \'O\', or \'I\'', - 'E741': 'do not use variables named \'l\', \'O\', or \'I\'', - 'E742': 'do not define classes named \'l\', \'O\', or \'I\'', - 'E743': 'do not define functions named \'l\', \'O\', or \'I\'', - - # Runtime - 'E901': 'SyntaxError or IndentationError', - 'E902': 'IOError', - - # Indentation warning - 'W191': 'indentation contains tabs', - - # Whitespace warning - 'W291': 'trailing whitespace', - 'W292': 'no newline at end of file', - 'W293': 'blank line contains whitespace', - - # Blank line warning - 'W391': 'blank line at end of file', - - # Line break warning - 'W503': 'line break before binary operator', - 'W504': 'line break after binary operator', - 'W505': 'doc line too long (82 > 79 characters)', - - # Deprecation warning - 'W601': '.has_key() is deprecated, use \'in\'', - 'W602': 'deprecated form of raising exception', - 'W603': '\'<>\' is deprecated, use \'!=\'', - 'W604': 'backticks are deprecated, use \'repr()\'', - 'W605': 'invalid escape sequence \'x\'', - 'W606': '\'async\' and \'await\' are reserved keywords starting with Python 3.7', - - 'F401': 'module imported but unused', - 'F402': 'import module from line N shadowed by loop variable', - 'F403': '\'from module import *\' used; unable to detect undefined names', - 'F404': 'future import(s) name after other statements', - 'F405': 'name may be undefined, or defined from star imports: module', - 'F406': '\'from module import *\' only allowed at module level', - 'F407': 'an undefined __future__ feature name was imported', - - 'F601': 'dictionary key name repeated with different values', - 'F602': 'dictionary key variable name repeated with different values', - 'F621': 'too many expressions in an assignment with star-unpacking', - 'F622': 'two or more starred expressions in an assignment (a, *b, *c = d)', - 'F631': 'assertion test is a tuple, which are always True', - - 'F701': 'a break statement outside of a while or for loop', - 'F702': 'a continue statement outside of a while or for loop', - 'F703': 'a continue statement in a finally block in a loop', - 'F704': 'a yield or yield from statement outside of a function', - 'F705': 'a return statement with arguments inside a generator', - 'F706': 'a return statement outside of a function/method', - 'F707': 'an except: block as not the last exception handler', - 'F721': 'doctest syntax error', - 'F722': 'syntax error in forward type annotation', - - 'F811': 'redefinition of unused name from line N', - 'F812': 'list comprehension redefines name from line N', - 'F821': 'undefined name name', - 'F822': 'undefined name name in __all__', - 'F823': 'local variable name ... referenced before assignment', - 'F831': 'duplicate argument name in function definition', - 'F841': 'local variable name is assigned to but never used', - - 'F901': 'raise NotImplemented should be raise NotImplementedError', - - 'N801': 'class names should use CapWords convention', - 'N802': 'function name should be lowercase', - 'N803': 'argument name should be lowercase', - 'N804': 'first argument of a classmethod should be named \'cls\'', - 'N805': 'first argument of a method should be named \'self\'', - 'N806': 'variable in function should be lowercase', - 'N807': 'function name should not start or end with \'__\'', - 'N811': 'constant imported as non constant', - 'N812': 'lowercase imported as non lowercase', - 'N813': 'camelcase imported as lowercase', - 'N814': 'camelcase imported as constant', - 'N815': 'mixedCase variable in class scope', - 'N816': 'mixedCase variable in global scope', -} - -# According to https://pypi.org/project/flake8-bugbear/ -ALL_BUGBEAR_ISSUES = { - 'B001': 'Do not use bare except:, it also catches unexpected events like memory errors, interrupts, system exit, ' - 'and so on. Prefer except Exception:. If you’re sure what you’re doing, be explicit and write except ' - 'BaseException:. Disable E722 to avoid duplicate warnings.', - 'B002': 'Python does not support the unary prefix increment. Writing ++n is equivalent to +(+(n)), which equals ' - 'n. You meant n += 1.', - 'B003': 'Assigning to os.environ doesn’t clear the environment. Subprocesses are going to see outdated variables, ' - 'in disagreement with the current process. Use os.environ.clear() or the env= argument to Popen.', - 'B004': 'Using hasattr(x, \'__call__\') to test if x is callable is unreliable. If x implements custom ' - '__getattr__ or its __call__ is itself not callable, you might get misleading results. Use callable(x) ' - 'for consistent results.', - 'B005': 'Using .strip() with multi-character strings is misleading the reader. It looks like stripping a ' - 'substring. Move your character set to a constant if this is deliberate. Use .replace() or regular ' - 'expressions to remove string fragments.', - 'B006': 'Do not use mutable data structures for argument defaults. They are created during function definition ' - 'time. All calls to the function reuse this one instance of that data structure, persisting changes ' - 'between them.', - 'B007': 'Loop control variable not used within the loop body. If this is intended, start the name with an ' - 'underscore.', - 'B008': 'Do not perform function calls in argument defaults. The call is performed only once at function ' - 'definition time. All calls to your function will reuse the result of that definition-time function call. ' - 'If this is intended, assign the function call to a module-level variable and use that variable as a ' - 'default value.', - 'B009': 'Do not call getattr(x, \'attr\'), instead use normal property access: x.attr. Missing a default to ' - 'getattr will cause an AttributeError to be raised for non-existent properties. There is no additional ' - 'safety in using getattr if you know the attribute name ahead of time.', - 'B010': 'Do not call setattr(x, \'attr\', val), instead use normal property access: x.attr = val. There is no ' - 'additional safety in using setattr if you know the attribute name ahead of time.', - 'B011': 'Do not call assert False since python -O removes these calls. Instead callers should raise ' - 'AssertionError().', - 'B012': 'Use of break, continue or return inside finally blocks will silence exceptions or override return values ' - 'from the try or except blocks. To silence an exception, do it explicitly in the except block. To ' - 'properly use a break, continue or return refactor your code so these statements are not in the finally ' - 'block.', - 'B013': 'A length-one tuple literal is redundant. Write except SomeError: instead of except (SomeError,):.', - 'B014': 'Redundant exception types in except (Exception, TypeError):. Write except Exception:, which catches ' - 'exactly the same exceptions.', - 'B015': 'Pointless comparison. This comparison does nothing but waste CPU instructions. Either prepend assert or ' - 'remove it.', - 'B016': 'Cannot raise a literal. Did you intend to return it or raise an Exception?', - 'B017': 'self.assertRaises(Exception): should be considered evil. It can lead to your test passing even if the ' - 'code being tested is never executed due to a typo. Either assert for a more specific exception (builtin ' - 'or custom), use assertRaisesRegex, or use the context manager form of assertRaises (with ' - 'self.assertRaises(Exception) as ex:) with an assertion against the data available in ex.', - - # Python 3 compatibility warnings - 'B301': 'Python 3 does not include .iter* methods on dictionaries. The default behavior is to return iterables. ' - 'Simply remove the iter prefix from the method. For Python 2 compatibility, also prefer the Python 3 ' - 'equivalent if you expect that the size of the dict to be small and bounded. The performance regression ' - 'on Python 2 will be negligible and the code is going to be the clearest. Alternatively, use six.iter* or ' - 'future.utils.iter*.', - 'B302': 'Python 3 does not include .view* methods on dictionaries. The default behavior is to return viewables. ' - 'Simply remove the view prefix from the method. For Python 2 compatibility, also prefer the Python 3 ' - 'equivalent if you expect that the size of the dict to be small and bounded. The performance regression ' - 'on Python 2 will be negligible and the code is going to be the clearest. Alternatively, use six.view* or ' - 'future.utils.view*.', - 'B303': 'The __metaclass__ attribute on a class definition does nothing on Python 3. Use class MyClass(BaseClass, ' - 'metaclass=...). For Python 2 compatibility, use six.add_metaclass.', - 'B304': 'sys.maxint is not a thing on Python 3. Use sys.maxsize.', - 'B305': '.next() is not a thing on Python 3. Use the next() builtin. For Python 2 compatibility, use six.next().', - 'B306': 'BaseException.message has been deprecated as of Python 2.6 and is removed in Python 3. Use str(e) to ' - 'access the user-readable message. Use e.args to access arguments passed to the exception.', -} - -# According to https://github.com/gforcada/flake8-builtins/blob/master/flake8_builtins.py#L49 -ALL_BUILTINS_ISSUES = { - 'A001': 'variable is shadowing a python builtin', - 'A002': 'argument is shadowing a python builtin', - 'A003': 'class attribute is shadowing a python builtin', -} - -# According to https://github.com/afonasev/flake8-return -ALL_RETURN_ISSUES = { - 'R501': 'do not explicitly return None in function if it is the only possible return value.', - 'R502': 'do not implicitly return None in function able to return non-None value.', - 'R503': 'missing explicit return at the end of function able to return non-None value.', - 'R504': 'unecessary variable assignement before return statement.', -} - -# According to https://pypi.org/project/flake8-string-format/ -ALL_FORMAT_STRING_ISSUES = { - # Presence of implicit parameters - 'P101': 'format string does contain unindexed parameters', - 'P102': 'docstring does contain unindexed parameters', - 'P103': 'other string does contain unindexed parameters', - - # Missing values in the parameters - 'P201': 'format call uses too large index (INDEX)', - 'P202': 'format call uses missing keyword (KEYWORD)', - 'P203': 'format call uses keyword arguments but no named entries', - 'P204': 'format call uses variable arguments but no numbered entries', - 'P205': 'format call uses implicit and explicit indexes together', - - # Unused values in the parameters - 'P301': 'format call provides unused index (INDEX)', - 'P302': 'format call provides unused keyword (KEYWORD)', -} - -# According to https://pypi.org/project/flake8-import-order/ -ALL_IMPORT_ORDER_ISSUES = { - 'I100': 'Your import statements are in the wrong order.', - 'I101': 'The names in your from import are in the wrong order.', - 'I201': 'Missing newline between import groups.', - 'I202': 'Additional newline in a group of imports.', -} - -# According to https://pypi.org/project/flake8-comprehensions/ -ALL_COMPREHENSIONS_ISSUES = { - 'C400': 'Unnecessary generator - rewrite as a comprehension.', - 'C401': 'Unnecessary generator - rewrite as a comprehension.', - 'C402': 'Unnecessary generator - rewrite as a comprehension.', - - 'C403': 'Unnecessary list comprehension - rewrite as a comprehension.', - 'C404': 'Unnecessary list comprehension - rewrite as a comprehension.', - - 'C405': 'Unnecessary literal - rewrite as a literal.', - 'C406': 'Unnecessary literal - rewrite as a literal.', - - 'C408': 'Unnecessary call - rewrite as a literal.', - - 'C409': ' Unnecessary passed to () - (remove the outer call to ``' - '()/rewrite as a `` literal).', - 'C410': ' Unnecessary passed to () - (remove the outer call to ``' - '()/rewrite as a `` literal).', - - 'C411': 'Unnecessary list call - remove the outer call to list().', - - 'C413': 'Unnecessary call around sorted().', - - 'C414': 'Unnecessary call within ().', - - 'C415': 'Unnecessary subscript reversal of iterable within ().', - - 'C416': 'Unnecessary comprehension - rewrite using ().', -} - -# According to https://pypi.org/project/flake8-spellcheck/ -ALL_SPELLCHECK_ISSUES = { - 'SC100': 'Spelling error in comments', - 'SC200': 'Spelling error in name (e.g. variable, function, class)', -} - -# According to https://wemake-python-stylegui.de/en/latest/pages/usage/violations/index.html -ALL_WPS_ISSUES = { - # Naming - 'WPS100': 'Found wrong module name', - 'WPS101': 'Found wrong module magic name', - 'WPS102': 'Found incorrect module name pattern', - 'WPS110': 'Found wrong variable name', - 'WPS111': 'Found too short name', - 'WPS112': 'Found private name pattern', - 'WPS113': 'Found same alias import', - 'WPS114': 'Found underscored number name pattern', - 'WPS115': 'Found upper-case constant in a class', - 'WPS116': 'Found consecutive underscores name', - 'WPS117': 'Found name reserved for first argument', - 'WPS118': 'Found too long name', - 'WPS119': 'Found unicode name', - 'WPS120': 'Found regular name with trailing underscore', - 'WPS121': 'Found usage of a variable marked as unused', - 'WPS122': 'Found all unused variables definition', - 'WPS123': 'Found wrong unused variable name', - 'WPS124': 'Found unreadable characters combination', - 'WPS125': 'Found builtin shadowing', - - # Complexity - 'WPS200': 'Found module with high Jones Complexity score', - 'WPS201': 'Found module with too many imports', - 'WPS202': 'Found too many module members', - 'WPS203': 'Found module with too many imported names', - 'WPS204': 'Found overused expression', - 'WPS210': 'Found too many local variables', - 'WPS211': 'Found too many arguments', - 'WPS212': 'Found too many return statements', - 'WPS213': 'Found too many expressions', - 'WPS214': 'Found too many methods', - 'WPS215': 'Too many base classes', - 'WPS216': 'Too many decorators', - 'WPS217': 'Found too many await expressions', - 'WPS218': 'Found too many `assert` statements', - 'WPS219': 'Found too deep access level', - 'WPS220': 'Found too deep nesting', - 'WPS221': 'Found line with high Jones Complexity', - 'WPS222': 'Found a condition with too much logic', - 'WPS223': 'Found too many `elif` branches', - 'WPS224': 'Found a comprehension with too many `for` statements', - 'WPS225': 'Found too many `except` cases', - 'WPS226': 'Found string constant over-use', - 'WPS227': 'Found too long yield tuple', - 'WPS228': 'Found too long compare', - 'WPS229': 'Found too long ``try`` body length', - 'WPS230': 'Found too many public instance attributes', - 'WPS231': 'Found function with too much cognitive complexity', - 'WPS232': 'Found module cognitive complexity that is too high', - 'WPS233': 'Found call chain that is too long', - 'WPS234': 'Found overly complex annotation', - 'WPS235': 'Found too many imported names from a module', - 'WPS236': 'Found too many variables used to unpack a tuple', - 'WPS237': 'Found a too complex `f` string', - 'WPS238': 'Found too many raises in a function', - - # Consistency - 'WPS300': 'Found local folder import', - 'WPS301': 'Found dotted raw import', - 'WPS302': 'Found unicode string prefix', - 'WPS303': 'Found underscored number', - 'WPS304': 'Found partial float', - 'WPS305': 'Found `f` string', - 'WPS306': 'Found class without a base class', - 'WPS307': 'Found list comprehension with multiple `if`s', - 'WPS308': 'Found constant comparison', - 'WPS309': 'Found reversed compare order', - 'WPS310': 'Found bad number suffix', - 'WPS311': 'Found multiple `in` compares', - 'WPS312': 'Found comparison of a variable to itself', - 'WPS313': 'Found parenthesis immediately after a keyword', - 'WPS314': 'Found conditional that always evaluates the same', - 'WPS315': 'Found extra `object` in parent classes list', - 'WPS316': 'Found context manager with too many assignments', - 'WPS317': 'Found incorrect multi-line parameters', - 'WPS318': 'Found extra indentation', - 'WPS319': 'Found bracket in wrong position', - 'WPS320': 'Found multi-line function type annotation', - 'WPS321': 'Found uppercase string modifier', - 'WPS322': 'Found incorrect multi-line string', - 'WPS323': 'Found `%` string formatting', - 'WPS324': 'Found inconsistent `return` statement', - 'WPS325': 'Found inconsistent `yield` statement', - 'WPS326': 'Found implicit string concatenation', - 'WPS327': 'Found useless `continue` at the end of the loop', - 'WPS328': 'Found useless node', - 'WPS329': 'Found useless `except` case', - 'WPS330': 'Found unnecessary operator', - 'WPS332': 'Found walrus operator', - 'WPS333': 'Found implicit complex compare', - 'WPS334': 'Found reversed complex comparison', - 'WPS335': 'Found incorrect `for` loop iter type', - 'WPS336': 'Found explicit string concatenation', - 'WPS337': 'Found multiline conditions', - 'WPS338': 'Found incorrect order of methods in a class', - 'WPS339': 'Found number with meaningless zeros', - 'WPS340': 'Found exponent number with positive exponent', - 'WPS341': 'Found wrong hex number case', - 'WPS342': 'Found implicit raw string', - 'WPS343': 'Found wrong complex number suffix', - 'WPS344': 'Found explicit zero division', - 'WPS345': 'Found meaningless number operation', - 'WPS346': 'Found wrong operation sign', - 'WPS347': 'Found vague import that may cause confusion', - 'WPS348': 'Found a line that starts with a dot', - 'WPS349': 'Found redundant subscript slice', - 'WPS350': 'Found usable augmented assign pattern', - 'WPS351': 'Found unnecessary literals', - 'WPS352': 'Found multiline loop', - 'WPS353': 'Found incorrect `yield from` target', - 'WPS354': 'Found consecutive `yield` expressions', - 'WPS355': 'Found an unnecessary blank line before a bracket', - 'WPS356': 'Found an unnecessary iterable unpacking', - 'WPS357': 'Found a ``\\r`` (carriage return) line break', - 'WPS358': 'Found a float zero (0.0)', - 'WPS359': 'Found an iterable unpacking to list', - 'WPS360': 'Found an unnecessary use of a raw string', - 'WPS361': 'Found an inconsistently structured comprehension', - 'WPS362': 'Found assignment to a subscript slice', - - # Best practices - 'WPS400': 'Found wrong magic comment', - 'WPS401': 'Found wrong doc comment', - 'WPS402': 'Found `noqa` comments overuse', - 'WPS403': 'Found `noqa` comments overuse', - 'WPS404': 'Found complex default value', - 'WPS405': 'Found wrong `for` loop variable definition', - 'WPS406': 'Found wrong context manager variable definition', - 'WPS407': 'Found mutable module constant', - 'WPS408': 'Found duplicate logical condition', - 'WPS409': 'Found heterogeneous compare', - 'WPS410': 'Found wrong metadata variable', - 'WPS411': 'Found empty module', - 'WPS412': 'Found `__init__.py` module with logic', - 'WPS413': 'Found bad magic module function', - 'WPS414': 'Found incorrect unpacking target', - 'WPS415': 'Found duplicate exception', - 'WPS416': 'Found `yield` inside comprehension', - 'WPS417': 'Found non-unique item in hash', - 'WPS418': 'Found exception inherited from `BaseException`', - 'WPS419': 'Found `try`/`else`/`finally` with multiple return paths', - 'WPS420': 'Found wrong keyword', - 'WPS421': 'Found wrong function call', - 'WPS422': 'Found future import', - 'WPS423': 'Found raise NotImplemented', - 'WPS424': 'Found except `BaseException`', - 'WPS425': 'Found boolean non-keyword argument', - 'WPS426': 'Found `lambda` in loop\'s body', - 'WPS427': 'Found unreachable code', - 'WPS428': 'Found statement that has no effect', - 'WPS429': 'Found multiple assign targets', - 'WPS430': 'Found nested function', - 'WPS431': 'Found nested class', - 'WPS432': 'Found magic number', - 'WPS433': 'Found nested import', - 'WPS434': 'Found reassigning variable to itself', - 'WPS435': 'Found list multiply', - 'WPS436': 'Found protected module import', - 'WPS437': 'Found protected attribute usage', - 'WPS438': 'Found `StopIteration` raising inside generator', - 'WPS439': 'Found unicode escape in a binary string', - 'WPS440': 'Found block variables overlap', - 'WPS441': 'Found control variable used after block', - 'WPS442': 'Found outer scope names shadowing', - 'WPS443': 'Found unhashable item', - 'WPS444': 'Found incorrect keyword condition', - 'WPS445': 'Found incorrectly named keyword in the starred dict', - 'WPS446': 'Found approximate constant', - 'WPS447': 'Found alphabet as strings', - 'WPS448': 'Found incorrect exception order', - 'WPS449': 'Found float used as a key', - 'WPS450': 'Found protected object import', - 'WPS451': 'Found positional-only argument', - 'WPS452': 'Found `break` or `continue` in `finally` block', - 'WPS453': 'Found executable mismatch', - 'WPS454': 'Found wrong `raise` exception type', - 'WPS455': 'Found non-trivial expression as an argument for "except"', - 'WPS456': 'Found "NaN" as argument to float()', - 'WPS457': 'Found an infinite while loop', - 'WPS458': 'Found imports collision', - 'WPS459': 'Found comparison with float or complex number', - 'WPS460': 'Found single element destructuring', - 'WPS461': 'Forbidden inline ignore', - 'WPS462': 'Wrong multiline string usage', - 'WPS463': 'Found a getter without a return value', - 'WPS464': 'Found empty comment', - 'WPS465': 'Found likely bitwise and boolean operation mixup', - 'WPS466': 'Found new-styled decorator', - - # Refactoring - 'WPS500': 'Found `else` in a loop without `break`', - 'WPS501': 'Found `finally` in `try` block without `except`', - 'WPS502': 'Found simplifiable `if` condition', - 'WPS503': 'Found useless returning `else` statement', - 'WPS504': 'Found negated condition', - 'WPS505': 'Found nested `try` block', - 'WPS506': 'Found useless lambda declaration', - 'WPS507': 'Found useless `len()` compare', - 'WPS508': 'Found incorrect `not` with compare usage', - 'WPS509': 'Found incorrectly nested ternary', - 'WPS510': 'Found `in` used with a non-set container', - 'WPS511': 'Found separate `isinstance` calls that can be merged for', - 'WPS512': 'Found `isinstance` call with a single element tuple', - 'WPS513': 'Found implicit `elif` condition', - 'WPS514': 'Found implicit `in` condition', - 'WPS515': 'Found `open()` used without a context manager', - 'WPS516': 'Found `type()` used to compare types', - 'WPS517': 'Found pointless starred expression', - 'WPS518': 'Found implicit `enumerate()` call', - 'WPS519': 'Found implicit `sum()` call', - 'WPS520': 'Found compare with falsy constant', - 'WPS521': 'Found wrong `is` compare', - 'WPS522': 'Found implicit primitive in a form of `lambda`', - 'WPS523': 'Found incorrectly swapped variables', - 'WPS524': 'Found self assignment with refactored assignment', - 'WPS525': 'Found wrong `in` compare with single item container', - 'WPS526': 'Found implicit `yield from` usage', - 'WPS527': 'Found not a tuple used as an argument', - 'WPS528': 'Found implicit `.items()` usage', - 'WPS529': 'Found implicit `.get()` dict usage', - 'WPS530': 'Found implicit negative index', - 'WPS531': 'Found simplifiable returning `if` condition in a function', - - # OOP - 'WPS600': 'Found subclassing a builtin', - 'WPS601': 'Found shadowed class attribute', - 'WPS602': 'Found using `@staticmethod`', - 'WPS603': 'Found using restricted magic method', - 'WPS604': 'Found incorrect node inside `class` body', - 'WPS605': 'Found method without arguments', - 'WPS606': 'Found incorrect base class', - 'WPS607': 'Found incorrect `__slots__` syntax', - 'WPS608': 'Found incorrect `super()` call', - 'WPS609': 'Found direct magic attribute usage', - 'WPS610': 'Found forbidden `async` magic method usage', - 'WPS611': 'Found forbidden `yield` magic method usage', - 'WPS612': 'Found useless overwritten method', - 'WPS613': 'Found incorrect `super()` call context: incorrect name access', - 'WPS614': 'Found descriptor applied on a function', - 'WPS615': 'Found unpythonic getter or setter', -} - -# According to the flake8 inspector config -FLAKE8_DISABLED_ISSUES = { - 'W291', - 'W292', # no newline at end of file - 'W293', - 'W503', # line break before binary operator - 'C408', # unnecessary (dict/list/tuple) call - rewrite as a literal - 'E501', # line too long - 'E800', # commented out code - 'I101', # order of imports within a line - 'I202', # additional new line - 'Q000', - 'E301', 'E302', 'E303', 'E304', 'E305', - 'E402', # module level import not at top of file - 'I100', # Import statements are in the wrong order - # WPS: Naming - 'WPS110', # Forbid blacklisted variable names. - 'WPS111', # Forbid short variable or module names. - 'WPS112', # Forbid private name pattern. - 'WPS114', # Forbid names with underscored numbers pattern. - 'WPS125', # Forbid variable or module names which shadow builtin names. - # WPS: Consistency - 'WPS303', # Forbid underscores in numbers. - 'WPS305', # Forbid f strings. - 'WPS306', # Forbid writing classes without base classes. - 'WPS318', # Forbid extra indentation. - 'WPS323', # Forbid % formatting on strings. - 'WPS324', # Enforce consistent return statements. - 'WPS335', # Forbid wrong for loop iter targets. - 'WPS358', # Forbid using float zeros: 0.0. - 'WPS362', # Forbid assignment to a subscript slice. - # WPS: Best practices - 'WPS404', # Forbid complex defaults. - 'WPS420', # Forbid some python keywords. - 'WPS421', # Forbid calling some built-in functions.(e.g., print) - 'WPS429', # Forbid multiple assignments on the same line. - 'WPS430', # Forbid nested functions. - 'WPS431', # Forbid nested classes. - 'WPS435', # Forbid multiplying lists. - # WPS: Refactoring - 'WPS518', # Forbid implicit enumerate() calls. - 'WPS527', # Require tuples as arguments for frozenset. - # WPS: OOP - 'WPS602', # Forbid @staticmethod decorator. - # flake8-string-format - 'P101', - 'P102', - 'P103', - 'F522', # unused named arguments. - 'F523', # unused positional arguments. - 'F524', # missing argument. - 'F525', # mixing automatic and manual numbering. - # flake8-commas - 'C814', # missing trailing comma in Python 2 -} diff --git a/src/python/evaluation/inspectors/inspectors_stat/issues/other_issues.py b/src/python/evaluation/inspectors/inspectors_stat/issues/other_issues.py deleted file mode 100644 index 365e6d74..00000000 --- a/src/python/evaluation/inspectors/inspectors_stat/issues/other_issues.py +++ /dev/null @@ -1,8 +0,0 @@ -PYTHON_RADON_ISSUES = { - 'RAD100': 'MAINTAINABILITY index', -} - -PYTHON_AST_ISSUES = { - 'C001': 'Boolean expressions length', - 'C002': 'Functions length', -} diff --git a/src/python/evaluation/inspectors/inspectors_stat/issues/pylint_all_issues.py b/src/python/evaluation/inspectors/inspectors_stat/issues/pylint_all_issues.py deleted file mode 100644 index b73e9efd..00000000 --- a/src/python/evaluation/inspectors/inspectors_stat/issues/pylint_all_issues.py +++ /dev/null @@ -1,496 +0,0 @@ -# According to https://seanwasere.com/pylint--list-msgs/ -ALL_ISSUES = { - 'C0102': 'Used when the name is listed in the black list (unauthorized names).', - 'C0103': 'Used when the name doesn\'t conform to naming rules associated to its type (constant, variable, ' - 'class...).', - 'C0111': 'Used when a module, function, class or method has no docstring.Some special methods like __init__ ' - 'doesn\'t necessary require a docstring.', - 'C0112': 'Used when a module, function, class or method has an empty docstring (it would be too easy ;).', - 'C0113': 'Used when a boolean expression contains an unneeded negation.', - 'C0121': 'Used when an expression is compared to singleton values like True, False or None.', - 'C0122': 'Used when the constant is placed on the left side of a comparison. It is usually clearer in intent to ' - 'place it in the right hand side of the comparison.', - 'C0123': 'The idiomatic way to perform an explicit typecheck in Python is to use isinstance(x, Y) rather than ' - 'type(x) == Y, type(x) is Y. Though there are unusual situations where these give different results.', - 'C0200': 'Emitted when code that iterates with range and len is encountered. Such code can be simplified by using ' - 'the enumerate builtin.', - 'C0201': 'Emitted when the keys of a dictionary are iterated through the .keys() method. It is enough to just ' - 'iterate through the dictionary itself, as in "for key in dictionary".', - 'C0202': 'Used when a class method has a first argument named differently than the value specified in ' - 'valid-classmethod-first-arg option (default to "cls"), recommended to easily differentiate them from ' - 'regular instance methods.', - 'C0203': 'Used when a metaclass method has a first argument named differently than the value specified in ' - 'valid-classmethod-first-arg option (default to "cls"), recommended to easily differentiate them from ' - 'regular instance methods.', - 'C0204': 'Used when a metaclass class method has a first argument named differently than the value specified in ' - 'valid-metaclass-classmethod-first-arg option (default to "mcs"), recommended to easily differentiate ' - 'them from regular instance methods.', - 'C0205': 'Used when a class __slots__ is a simple string, rather than an iterable.', - 'C0301': 'Used when a line is longer than a given number of characters.', - 'C0302': 'Used when a module has too many lines, reducing its readability.', - 'C0303': 'Used when there is whitespace between the end of a line and the newline.', - 'C0304': 'Used when the last line in a file is missing a newline.', - 'C0305': 'Used when there are trailing blank lines in a file.', - 'C0321': 'Used when more than on statement are found on the same line.', - 'C0325': 'Used when a single item in parentheses follows an if, for, or other keyword.', - 'C0326': 'Used when a wrong number of spaces is used around an operator, bracket or block opener.', - 'C0327': 'Used when there are mixed (LF and CRLF) newline signs in a file.', - 'C0328': 'Used when there is different newline than expected.', - 'C0330': 'bad-continuation', - 'C0401': 'Used when a word in comment is not spelled correctly.', - 'C0402': 'Used when a word in docstring is not spelled correctly.', - 'C0403': 'Used when a word in docstring cannot be checked by enchant.', - 'C0410': 'Used when import statement importing multiple modules is detected.', - 'C0411': 'Used when PEP8 import order is not respected (standard imports first, then third-party libraries, ' - 'then local imports)', - 'C0412': 'Used when imports are not grouped by packages', - 'C0413': 'Used when code and imports are mixed', - 'C0414': 'Used when an import alias is same as original package.e.g using import numpy as numpy instead of import ' - 'numpy as np', - 'C1801': 'Used when Pylint detects that len(sequence) is being used inside a condition to determine if a sequence ' - 'is empty. Instead of comparing the length to 0, rely on the fact that empty sequences are false.', - - 'E0001': 'Used when a syntax error is raised for a module.', - 'E0011': 'Used when an unknown inline option is encountered.', - 'E0012': 'Used when a bad value for an inline option is encountered.', - 'E0100': 'Used when the special class method __init__ is turned into a generator by a yield in its body.', - 'E0101': 'Used when the special class method __init__ has an explicit return value.', - 'E0102': 'Used when a function / class / method is redefined.', - 'E0103': 'Used when break or continue keywords are used outside a loop.', - 'E0104': 'Used when a "return" statement is found outside a function or method.', - 'E0105': 'Used when a "yield" statement is found outside a function or method.', - 'E0107': 'Used when you attempt to use the C-style pre-increment or pre-decrement operator -- and ++, ' - 'which doesn\'t exist in Python.', - 'E0108': 'Duplicate argument names in function definitions are syntax errors.', - 'E0110': 'Used when an abstract class with `abc.ABCMeta` as metaclass has abstract methods and is instantiated.', - 'E0111': 'Used when the first argument to reversed() builtin isn\'t a sequence (does not implement __reversed__, ' - 'nor __getitem__ and __len__', - 'E0112': 'Emitted when there are more than one starred expressions (`*x`) in an assignment. This is a SyntaxError.', - 'E0113': 'Emitted when a star expression is used as a starred assignment target.', - 'E0114': 'Emitted when a star expression is not used in an assignment target.', - 'E0115': 'Emitted when a name is both nonlocal and global.', - 'E0116': 'Emitted when the `continue` keyword is found inside a finally clause, which is a SyntaxError.', - 'E0117': 'Emitted when a nonlocal variable does not have an attached name somewhere in the parent scopes', - 'E0118': 'Emitted when a name is used prior a global declaration, which results in an error since Python 3.6. ' - 'This message can\'t be emitted when using Python < 3.6.', - 'E0119': 'Emitted when format function is not called on str object. ' - 'This might not be what the user intended to do.', - 'E0202': 'Used when a class defines a method which is hidden by an instance attribute from an ancestor class or ' - 'set by some client code.', - 'E0203': 'Used when an instance member is accessed before it\'s actually assigned.', - 'E0211': 'Used when a method which should have the bound instance as first argument has no argument defined.', - 'E0213': 'Used when a method has an attribute different the "self" as first argument. This is considered as an ' - 'error since this is a so common convention that you shouldn\'t break it!', - 'E0236': 'Used when an invalid (non-string) object occurs in __slots__.', - 'E0237': 'Used when assigning to an attribute not defined in the class slots.', - 'E0238': 'Used when an invalid __slots__ is found in class. Only a string, an iterable or a sequence is permitted.', - 'E0239': 'Used when a class inherits from something which is not a class.', - 'E0240': 'Used when a class has an inconsistent method resolution order.', - 'E0241': 'Used when a class has duplicate bases.', - 'E0301': 'Used when an __iter__ method returns something which is not an iterable (i.e. has no `__next__` method)', - 'E0302': 'Emitted when a special method was defined with an invalid number of parameters. If it has too few or ' - 'too many, it might not work at all.', - 'E0303': 'Used when a __len__ method returns something which is not a non-negative integer', - 'E0401': 'Used when pylint has been unable to import a module.', - 'E0402': 'Used when a relative import tries to access too many levels in the current package.', - 'E0601': 'Used when a local variable is accessed before its assignment.', - 'E0602': 'Used when an undefined variable is accessed.', - 'E0603': 'Used when an undefined variable name is referenced in __all__.', - 'E0604': 'Used when an invalid (non-string) object occurs in __all__.', - 'E0611': 'Used when a name cannot be found in a module.', - 'E0633': 'Used when something which is not a sequence is used in an unpack assignment', - 'E0701': 'Used when except clauses are not in the correct order (from the more specific to the more generic). If ' - 'you don\'t fix the order, some exceptions may not be caught by the most specific handler.', - 'E0702': 'Used when something which is neither a class, an instance or a string is raised (i.e. a `TypeError` ' - 'will be raised).', - 'E0703': 'Used when using the syntax "raise ... from ...", where the exception context is not an exception, ' - 'nor None.', - 'E0704': 'Used when a bare raise is not used inside an except clause. This generates an error, since there are no ' - 'active exceptions to be reraised. An exception to this rule is represented by a bare raise inside a ' - 'finally clause, which might work, as long as an exception is raised inside the try block, ' - 'but it is nevertheless a code smell that must not be relied upon.', - 'E0710': 'Used when a new style class which doesn\'t inherit from BaseException is raised.', - 'E0711': 'Used when NotImplemented is raised instead of NotImplementedError', - 'E0712': 'Used when a class which doesn\'t inherit from Exception is used as an exception in an except clause.', - 'E1003': 'Used when another argument than the current class is given as first argument of the super builtin.', - 'E1101': 'Used when a variable is accessed for an unexistent member.', - 'E1102': 'Used when an object being called has been inferred to a non callable object.', - 'E1111': 'Used when an assignment is done on a function call but the inferred function doesn\'t return anything.', - 'E1120': 'Used when a function call passes too few arguments.', - 'E1121': 'Used when a function call passes too many positional arguments.', - 'E1123': 'Used when a function call passes a keyword argument that doesn\'t correspond to one of the function\'s ' - 'parameter names.', - 'E1124': 'Used when a function call would result in assigning multiple values to a function parameter, one value ' - 'from a positional argument and one from a keyword argument.', - 'E1125': 'Used when a function call does not pass a mandatory keyword-only argument.', - 'E1126': 'Used when a sequence type is indexed with an invalid type. Valid types are ints, slices, and objects ' - 'with an __index__ method.', - 'E1127': 'Used when a slice index is not an integer, None, or an object with an __index__ method.', - 'E1128': 'Used when an assignment is done on a function call but the inferred function returns nothing but None.', - 'E1129': 'Used when an instance in a with statement doesn\'t implement the context manager protocol(' - '__enter__/__exit__).', - 'E1130': 'Emitted when a unary operand is used on an object which does not support this type of operation.', - 'E1131': 'Emitted when a binary arithmetic operation between two operands is not supported.', - 'E1132': 'Emitted when a function call got multiple values for a keyword.', - 'E1133': 'Used when a non-iterable value is used in place where iterable is expected', - 'E1134': 'Used when a non-mapping value is used in place where mapping is expected', - 'E1135': 'Emitted when an instance in membership test expression doesn\'t implement membership protocol (' - '__contains__/__iter__/__getitem__).', - 'E1136': 'Emitted when a subscripted value doesn\'t support subscription (i.e. doesn\'t define __getitem__ method ' - 'or __class_getitem__ for a class).', - 'E1137': 'Emitted when an object does not support item assignment (i.e. doesn\'t define __setitem__ method).', - 'E1138': 'Emitted when an object does not support item deletion (i.e. doesn\'t define __delitem__ method).', - 'E1139': 'Emitted whenever we can detect that a class is using, as a metaclass, something which might be invalid ' - 'for using as a metaclass.', - 'E1140': 'Emitted when a dict key is not hashable (i.e. doesn\'t define __hash__ method).', - 'E1200': 'Used when an unsupported format character is used in a logging statement format string.', - 'E1201': 'Used when a logging statement format string terminates before the end of a conversion specifier.', - 'E1205': 'Used when a logging format string is given too many arguments.', - 'E1206': 'Used when a logging format string is given too few arguments.', - 'E1300': 'Used when an unsupported format character is used in a format string.', - 'E1301': 'Used when a format string terminates before the end of a conversion specifier.', - 'E1302': 'Used when a format string contains both named (e.g. \'%(foo)d\') and unnamed (e.g. \'%d\') conversion ' - 'specifiers. This is also used when a named conversion specifier contains * for the minimum field width ' - 'and/or precision.', - 'E1303': 'Used when a format string that uses named conversion specifiers is used with an argument that is not a ' - 'mapping.', - 'E1304': 'Used when a format string that uses named conversion specifiers is used with a dictionary that doesn\'t ' - 'contain all the keys required by the format string.', - 'E1305': 'Used when a format string that uses unnamed conversion specifiers is given too many arguments.', - 'E1306': 'Used when a format string that uses unnamed conversion specifiers is given too few arguments', - 'E1307': 'Used when a type required by format string is not suitable for actual argument type', - 'E1310': 'The argument to a str.{l,r,}strip call contains a duplicate character,', - 'E1507': 'Env manipulation functions support only string type arguments. See ' - 'https://docs.python.org/3/library/os.html#os.getenv.', - 'E1601': 'Used when a print statement is used (`print` is a function in Python 3)', - 'E1602': 'Used when parameter unpacking is specified for a function(Python 3 doesn\'t allow it)', - 'E1603': 'Python3 will not allow implicit unpacking of exceptions in except clauses. See ' - 'http://www.python.org/dev/peps/pep-3110/', - 'E1604': 'Used when the alternate raise syntax \'raise foo, bar\' is used instead of \'raise foo(bar)\'.', - 'E1605': 'Used when the deprecated "``" (backtick) operator is used instead of the str() function.', - 'E1700': 'Used when an `yield` or `yield from` statement is found inside an async function. This message can\'t ' - 'be emitted when using Python < 3.5.', - 'E1701': 'Used when an async context manager is used with an object that does not implement the async context ' - 'management protocol. This message can\'t be emitted when using Python < 3.5.', - - # refactoring related checks - 'R0123': 'Used when comparing an object to a literal, which is usually what you do not want to do, since you can ' - 'compare to a different literal than what was expected altogether.', - 'R0124': 'Used when something is compared against itself.', - 'R0201': 'Used when a method doesn\'t use its bound instance, and so could be written as a function.', - 'R0202': 'Used when a class method is defined without using the decorator syntax.', - 'R0203': 'Used when a static method is defined without using the decorator syntax.', - 'R0205': 'Used when a class inherit from object, which under python3 is implicit, hence can be safely removed ' - 'from bases.', - 'R0401': 'Used when a cyclic import between two or more modules is detected.', - 'R0801': 'Indicates that a set of similar lines has been detected among multiple file. This usually means that ' - 'the code should be refactored to avoid this duplication.', - 'R0901': 'Used when class has too many parent classes, try to reduce this to get a simpler (and so easier to use) ' - 'class.', - 'R0902': 'Used when class has too many instance attributes, try to reduce this to get a simpler (and so easier to ' - 'use) class.', - 'R0903': 'Used when class has too few public methods, so be sure it\'s really worth it.', - 'R0904': 'Used when class has too many public methods, try to reduce this to get a simpler (and so easier to use) ' - 'class.', - 'R0911': 'Used when a function or method has too many return statement, making it hard to follow.', - 'R0912': 'Used when a function or method has too many branches, making it hard to follow.', - 'R0913': 'Used when a function or method takes too many arguments.', - 'R0914': 'Used when a function or method has too many local variables.', - 'R0915': 'Used when a function or method has too many statements. You should then split it in smaller functions / ' - 'methods.', - 'R0916': 'Used when an if statement contains too many boolean expressions.', - 'R1701': 'Used when multiple consecutive isinstance calls can be merged into one.', - 'R1702': 'Used when a function or a method has too many nested blocks. This makes the code less understandable ' - 'and maintainable.', - 'R1703': 'Used when an if statement can be replaced with \'bool(test)\'.', - 'R1704': 'Used when a local name is redefining an argument, which might suggest a potential error. This is taken ' - 'in account only for a handful of name binding operations, such as for iteration, with statement ' - 'assignment and exception handler assignment.', - 'R1705': 'Used in order to highlight an unnecessary block of code following an if containing a return statement. ' - 'As such, it will warn when it encounters an else following a chain of ifs, all of them containing a ' - 'return statement.', - 'R1706': 'Used when one of known pre-python 2.5 ternary syntax is used.', - 'R1707': 'In Python, a tuple is actually created by the comma symbol, not by the parentheses. Unfortunately, ' - 'one can actually create a tuple by misplacing a trailing comma, which can lead to potential weird bugs ' - 'in your code. You should always use parentheses explicitly for creating a tuple.', - 'R1708': 'According to PEP479, the raise of StopIteration to end the loop of a generator may lead to hard to find ' - 'bugs. This PEP specify that raise StopIteration has to be replaced by a simple return statement', - 'R1709': 'Emitted when redundant pre-python 2.5 ternary syntax is used.', - 'R1710': 'According to PEP8, if any return statement returns an expression, any return statements where no value ' - 'is returned should explicitly state this as return None, and an explicit return statement should be ' - 'present at the end of the function (if reachable)', - 'R1711': 'Emitted when a single "return" or "return None" statement is found at the end of function or method ' - 'definition. This statement can safely be removed because Python will implicitly return None', - 'R1712': 'You do not have to use a temporary variable in order to swap variables. Using "tuple unpacking" to ' - 'directly swap variables makes the intention more clear.', - 'R1713': 'Using str.join(sequence) is faster, uses less memory and increases readability compared to for-loop ' - 'iteration.', - 'R1714': 'To check if a variable is equal to one of many values,combine the values into a tuple and check if the ' - 'variable is contained "in" it instead of checking for equality against each of the values.This is ' - 'faster and less verbose.', - 'R1715': 'Using the builtin dict.get for getting a value from a dictionary if a key is present or a default if ' - 'not, is simpler and considered more idiomatic, although sometimes a bit slower', - 'R1716': 'This message is emitted when pylint encounters boolean operation like"a < b and b < c", suggesting ' - 'instead to refactor it to "a < b < c"', - 'R1717': 'Although there is nothing syntactically wrong with this code, it is hard to read and can be simplified ' - 'to a dict comprehension.Also it is faster since you don\'t need to create another transient list', - 'R1718': 'Although there is nothing syntactically wrong with this code, it is hard to read and can be simplified ' - 'to a set comprehension.Also it is faster since you don\'t need to create another transient list', - 'R1719': 'Used when an if expression can be replaced with \'bool(test)\'.', - 'R1720': 'Used in order to highlight an unnecessary block of code following an if containing a raise statement. ' - 'As such, it will warn when it encounters an else following a chain of ifs, all of them containing a ' - 'raise statement.', - - # warnings for stylistic issues, or minor programming issues - 'W0101': 'Used when there is some code behind a "return" or "raise" statement, which will never be accessed.', - 'W0102': 'Used when a mutable value as list or dictionary is detected in a default value for an argument.', - 'W0104': 'Used when a statement doesn\'t have (or at least seems to) any effect.', - 'W0105': 'Used when a string is used as a statement (which of course has no effect). This is a particular case of ' - 'W0104 with its own message so you can easily disable it if you\'re using those strings as ' - 'documentation, instead of comments.', - 'W0106': 'Used when an expression that is not a function call is assigned to nothing. Probably something else was ' - 'intended.', - 'W0107': 'Used when a "pass" statement that can be avoided is encountered.', - 'W0108': 'Used when the body of a lambda expression is a function call on the same argument list as the lambda ' - 'itself; such lambda expressions are in all but a few cases replaceable with the function being called ' - 'in the body of the lambda.', - 'W0109': 'Used when a dictionary expression binds the same key multiple times.', - 'W0111': 'Used when assignment will become invalid in future Python release due to introducing new keyword.', - 'W0120': 'Loops should only have an else clause if they can exit early with a break statement, otherwise the ' - 'statements under else should be on the same scope as the loop itself.', - 'W0122': 'Used when you use the "exec" statement (function for Python 3), to discourage its usage. That doesn\'t ' - 'mean you cannot use it !', - 'W0123': 'Used when you use the "eval" function, to discourage its usage. Consider using `ast.literal_eval` for ' - 'safely evaluating strings containing Python expressions from untrusted sources.', - 'W0124': 'Emitted when a `with` statement component returns multiple values and uses name binding with `as` only ' - 'for a part of those values, as in with ctx() as a, b. This can be misleading, since it\'s not clear if ' - 'the context manager returns a tuple or if the node without a name binding is another context manager.', - 'W0125': 'Emitted when a conditional statement (If or ternary if) uses a constant value for its test. This might ' - 'not be what the user intended to do.', - 'W0143': 'This message is emitted when pylint detects that a comparison with a callable was made, which might ' - 'suggest that some parenthesis were omitted, resulting in potential unwanted behaviour.', - 'W0150': 'Used when a break or a return statement is found inside the finally clause of a try...finally block: ' - 'the exceptions raised in the try clause will be silently swallowed instead of being re-raised.', - 'W0199': 'A call of assert on a tuple will always evaluate to true if the tuple is not empty, and will always ' - 'evaluate to false if it is.', - 'W0201': 'Used when an instance attribute is defined outside the __init__ method.', - 'W0211': 'Used when a static method has "self" or a value specified in valid- classmethod-first-arg option or ' - 'valid-metaclass-classmethod-first-arg option as first argument.', - 'W0212': 'Used when a protected member (i.e. class member with a name beginning with an underscore) is access ' - 'outside the class or a descendant of the class where it\'s defined.', - 'W0221': 'Used when a method has a different number of arguments than in the implemented interface or in an ' - 'overridden method.', - 'W0222': 'Used when a method signature is different than in the implemented interface or in an overridden method.', - 'W0223': 'Used when an abstract method (i.e. raise NotImplementedError) is not overridden in concrete class.', - 'W0231': 'Used when an ancestor class method has an __init__ method which is not called by a derived class.', - 'W0232': 'Used when a class has no __init__ method, neither its parent classes.', - 'W0233': 'Used when an __init__ method is called on a class which is not in the direct ancestors for the analysed ' - 'class.', - 'W0235': 'Used whenever we can detect that an overridden method is useless, relying on super() delegation to do ' - 'the same thing as another method from the MRO.', - 'W0301': 'Used when a statement is ended by a semi-colon (";"), which isn\'t necessary (that\'s python, not C ;).', - 'W0311': 'Used when an unexpected number of indentation\'s tabulations or spaces has been found.', - 'W0312': 'Used when there are some mixed tabs and spaces in a module.', - 'W0401': 'Used when `from module import *` is detected.', - 'W0402': 'Used a module marked as deprecated is imported.', - 'W0404': 'Used when a module is reimported multiple times.', - 'W0406': 'Used when a module is importing itself.', - 'W0410': 'Python 2.5 and greater require __future__ import to be the first non docstring statement in the module.', - 'W0511': 'Used when a warning note as FIXME or XXX is detected.', - 'W0601': 'Used when a variable is defined through the "global" statement but the variable is not defined in the ' - 'module scope.', - 'W0602': 'Used when a variable is defined through the "global" statement but no assignment to this variable is ' - 'done.', - 'W0603': 'Used when you use the "global" statement to update a global variable. Pylint just try to discourage ' - 'this usage. That doesn\'t mean you cannot use it !', - 'W0604': 'Used when you use the "global" statement at the module level since it has no effect', - 'W0611': 'Used when an imported module or variable is not used.', - 'W0612': 'Used when a variable is defined but not used.', - 'W0613': 'Used when a function or method argument is not used.', - 'W0614': 'Used when an imported module or variable is not used from a `\'from X import *\'` style import.', - 'W0621': 'Used when a variable\'s name hides a name defined in the outer scope.', - 'W0622': 'Used when a variable or function override a built-in.', - 'W0623': 'Used when an exception handler assigns the exception to an existing name', - 'W0631': 'Used when a loop variable (i.e. defined by a for loop or a list comprehension or a generator ' - 'expression) is used outside the loop.', - 'W0632': 'Used when there is an unbalanced tuple unpacking in assignment', - 'W0640': 'A variable used in a closure is defined in a loop. This will result in all closures using the same ' - 'value for the closed-over variable.', - 'W0641': 'Used when a variable is defined but might not be used. The possibility comes from the fact that locals(' - ') might be used, which could consume or not the said variable', - 'W0642': 'Invalid assignment to self or cls in instance or class method respectively.', - 'W0702': 'Used when an except clause doesn\'t specify exceptions type to catch.', - 'W0703': 'Used when an except catches a too general exception, possibly burying unrelated errors.', - 'W0705': 'Used when an except catches a type that was already caught by a previous handler.', - 'W0706': 'Used when an except handler uses raise as its first or only operator. This is useless because it raises ' - 'back the exception immediately. Remove the raise operator or the entire try-except-raise block!', - 'W0711': 'Used when the exception to catch is of the form "except A or B:". If intending to catch multiple, ' - 'rewrite as "except (A, B):"', - 'W0715': 'Used when passing multiple arguments to an exception constructor, the first of them a string literal ' - 'containing what appears to be placeholders intended for formatting', - 'W0716': 'Used when an operation is done against an exception, but the operation is not valid for the exception ' - 'in question. Usually emitted when having binary operations between exceptions in except handlers.', - 'W1113': 'When defining a keyword argument before variable positional arguments, one can end up in having ' - 'multiple values passed for the aforementioned parameter in case the method is called with keyword ' - 'arguments.', - 'W1201': 'Used when a logging statement has a call form of "logging.(format_string % (' - 'format_args...))". Such calls should leave string interpolation to the logging method itself and be ' - 'written "logging.(format_string, format_args...)" so that the program may avoid ' - 'incurring the cost of the interpolation in those cases in which no message will be logged. For more, ' - 'see http://www.python.org/dev/peps/pep-0282/.', - 'W1202': 'Used when a logging statement has a call form of "logging.(format_string.format(' - 'format_args...))". Such calls should use % formatting instead, but leave interpolation to the logging ' - 'function by passing the parameters as arguments.', - 'W1203': 'Used when a logging statement has a call form of "logging.method(f"..."))". Such calls should use % ' - 'formatting instead, but leave interpolation to the logging function by passing the parameters as ' - 'arguments.', - 'W1300': 'Used when a format string that uses named conversion specifiers is used with a dictionary whose keys ' - 'are not all strings.', - 'W1301': 'Used when a format string that uses named conversion specifiers is used with a dictionary that contains ' - 'keys not required by the format string.', - 'W1302': 'Used when a PEP 3101 format string is invalid.', - 'W1303': 'Used when a PEP 3101 format string that uses named fields doesn\'t ' - 'receive one or more required keywords.', - 'W1304': 'Used when a PEP 3101 format string that uses named fields is used with an argument that is not required ' - 'by the format string.', - 'W1305': 'Used when a PEP 3101 format string contains both automatic field numbering and manual ' - 'field specification.', - 'W1306': 'Used when a PEP 3101 format string uses an attribute specifier ({0.length}), but the argument passed ' - 'for formatting doesn\'t have that attribute.', - 'W1307': 'Used when a PEP 3101 format string uses a lookup specifier ({a[1]}), but the argument passed for ' - 'formatting doesn\'t contain or doesn\'t have that key as an attribute.', - 'W1308': 'Used when we detect that a string formatting is repeating an argument instead of using named string ' - 'arguments', - 'W1401': 'Used when a backslash is in a literal string but not as an escape.', - 'W1402': 'Used when an escape like \\u is encountered in a byte string where it has no effect.', - 'W1403': 'String literals are implicitly concatenated in a ' - 'literal iterable definition : maybe a comma is missing ?', - 'W1501': 'Python supports: r, w, a[, x] modes with b, +, and U (only with r) options. ' - 'See http://docs.python.org/2/library/functions.html#open', - 'W1503': 'The first argument of assertTrue and assertFalse is a condition. If a constant is passed as parameter, ' - 'that condition will be always true. In this case a warning should be emitted.', - 'W1505': 'The method is marked as deprecated and will be removed in a future version of Python. Consider looking ' - 'for an alternative in the documentation.', - 'W1506': 'The warning is emitted when a threading.Thread class is instantiated without the target function being ' - 'passed. By default, the first parameter is the group param, not the target param.', - 'W1507': 'os.environ is not a dict object but proxy object, so shallow copy has still effects on original object. ' - 'See https://bugs.python.org/issue15373 for reference.', - 'W1508': 'Env manipulation functions return None or str values. Supplying anything different as a default may ' - 'cause bugs. See https://docs.python.org/3/library/os.html#os.getenv.', - 'W1509': 'The preexec_fn parameter is not safe to use in the presence of threads in your application. The child ' - 'process could deadlock before exec is called. If you must use it, keep it trivial! Minimize the number ' - 'of libraries you call into.https://docs.python.org/3/library/subprocess.html#popen-constructor', - # miss some inspections that were missed from Python 3 - - 'I0001': 'Used to inform that a built-in module has not been checked using the raw checkers.', - 'I0010': 'Used when an inline option is either badly formatted or can\'t be used inside modules.', - 'I0011': 'Used when an inline option disables a message or a messages category.', - 'I0013': 'Used to inform that the file will not be checked', - 'I0020': 'A message was triggered on a line, but suppressed explicitly by a disable= comment in the file. ' - 'This message is not generated for messages that are ignored due to configuration settings.', - 'I0021': 'Reported when a message is explicitly disabled for a line or a block of code, but never triggered.', - 'I0022': 'Some inline pylint options have been renamed or reworked, only the most recent form should be used. ' - 'NOTE:skip-all is only available with pylint >= 0.26', - 'I0023': 'Used when a message is enabled or disabled by id.', - 'I1101': 'Used when a variable is accessed for non-existent member of C extension. Due to unavailability of source ' - 'static analysis is impossible, but it may be performed by introspecting living objects in run-time.', -} - -# According to the pylint inspector config -PYLINT_DISABLED_ISSUES = { - 'C0103', # invalid-name - 'C0111', # missing-docstring - 'C0301', # line-too-long - 'C0304', # missing-final-newline - 'E1601', # print-statement - 'E1602', # parameter-unpacking - 'E1603', # unpacking-in-except - 'E1604', # old-raise-syntax - 'E1605', - 'I0001', # raw-checker-failed - 'I0010', # bad-inline-option - 'I0011', # locally-disabled - 'I0013', # file-ignored - 'I0020', # suppressed-message - 'I0021', # useless-suppression - 'I0022', # deprecated-pragma - 'I0023', # use-symbolic-message-instead - 'R0901', # too-many-ancestors - 'R0902', # too-many-instance-attributes - 'R0903', # too-few-public-methods - 'R0904', # too-many-public-methods, - 'R0911', # too-many-return-statements - 'R0912', # too-many-branches - 'R0913', # too-many-arguments - 'R0914', # too-many-locals - 'R0916', # too-many-boolean-expressions - 'W1601', # apply-builtin - 'W1602', # basestring-builtin - 'W1603', # buffer-builtin - 'W1604', # cmp-builtin - 'W1605', # coerce-builtin - 'W1606', - 'W1607', # file-builtin - 'W1608', # long-builtin - 'W1609', # raw_input-builtin - 'W1610', # reduce-builtin - 'W1611', - 'W1612', # unicode-builtin - 'W1613', - 'W1614', # coerce-method - 'W1615', - 'W1616', - 'W1617', - 'W1618', # no-absolute-import - 'W1619', # old-division - 'W1620', # dict-iter-method - 'W1621', # dict-view-method - 'W1622', # next-method-called - 'W1623', - 'W1624', # indexing-exception - 'W1625', # raising-string - 'W1626', # reload-builtin - 'W1627', # oct-method - 'W1628', # hex-method - 'W1629', # nonzero-method - 'W1630', # cmp-method - 'W1632', # input-builtin - 'W1633', # round-builtin - 'W1634', # intern-builtin - 'W1635', - 'W1636', # map-builtin-not-iterating - 'W1637', # zip-builtin-not-iterating - 'W1638', # range-builtin-not-iterating - 'W1639', # filter-builtin-not-iterating - 'W1640', # using-cmp-argument - 'W1641', # eq-without-hash - 'W1642', # div-method - 'W1643', - 'W1644', - 'W1645', # exception-message-attribute - 'W1646', - 'W1647', # sys-max-int - 'W1648', # bad-python3-import - 'W1649', # deprecated-string-function - 'W1650', # deprecated-str-translate-call - 'W1651', # deprecated-itertools-function - 'W1652', # deprecated-types-field - 'W1653', # next-method-defined - 'W1654', # dict-items-not-iterating - 'W1655', # dict-keys-not-iterating - 'W1656', # dict-values-not-iterating - 'W1657', # deprecated-operator-function - 'W1658', # deprecated-urllib-function - 'W1659', - 'W1660', # deprecated-sys-function - 'W1661', # exception-escape - 'W1662', # comprehension-escape, - 'W0603', # global-statement - 'C0413', # wrong-import-position - 'R0915', # too-many-statements - 'C0327', # mixed-line-endings - 'E0401', # import-error - 'C0303', # trailing-whitespace - 'R1705', # no-else-return - 'R1720', # no-else-raise -} diff --git a/src/python/evaluation/inspectors/inspectors_stat/statistics_gathering.py b/src/python/evaluation/inspectors/inspectors_stat/statistics_gathering.py deleted file mode 100644 index 0de99fc6..00000000 --- a/src/python/evaluation/inspectors/inspectors_stat/statistics_gathering.py +++ /dev/null @@ -1,129 +0,0 @@ -import argparse -from typing import Callable, Dict, List, Set, Tuple - -from src.python.evaluation.inspectors.inspectors_stat.issues.flake8_all_issues import ( - ALL_BUGBEAR_ISSUES, ALL_BUILTINS_ISSUES, ALL_COMPREHENSIONS_ISSUES, ALL_FORMAT_STRING_ISSUES, - ALL_IMPORT_ORDER_ISSUES, ALL_RETURN_ISSUES, ALL_SPELLCHECK_ISSUES, ALL_STANDARD_ISSUES, ALL_WPS_ISSUES, - FLAKE8_DISABLED_ISSUES, -) -from src.python.evaluation.inspectors.inspectors_stat.issues.other_issues import PYTHON_AST_ISSUES, PYTHON_RADON_ISSUES -from src.python.evaluation.inspectors.inspectors_stat.issues.pylint_all_issues import ALL_ISSUES, PYLINT_DISABLED_ISSUES -from src.python.review.common.language import Language -from src.python.review.inspectors.checkstyle.checkstyle import CheckstyleInspector -from src.python.review.inspectors.checkstyle.issue_types import CHECK_CLASS_NAME_TO_ISSUE_TYPE -from src.python.review.inspectors.detekt.detekt import DetektInspector -from src.python.review.inspectors.detekt.issue_types import DETECT_CLASS_NAME_TO_ISSUE_TYPE -from src.python.review.inspectors.eslint.eslint import ESLintInspector -from src.python.review.inspectors.eslint.issue_types import ESLINT_CLASS_NAME_TO_ISSUE_TYPE -from src.python.review.inspectors.flake8.flake8 import Flake8Inspector -from src.python.review.inspectors.issue import ( - get_default_issue_stat, get_main_category_by_issue_type, IssuesStat, IssueType, -) -from src.python.review.inspectors.pmd.issue_types import PMD_RULE_TO_ISSUE_TYPE -from src.python.review.inspectors.pmd.pmd import PMDInspector -from src.python.review.inspectors.pyast.python_ast import PythonAstInspector -from src.python.review.inspectors.pylint.pylint import PylintInspector -from src.python.review.inspectors.radon.radon import RadonInspector - - -def __get_flake8_issue_keys() -> Set[str]: - issues_dicts = [ALL_STANDARD_ISSUES, ALL_BUGBEAR_ISSUES, ALL_BUILTINS_ISSUES, ALL_RETURN_ISSUES, - ALL_FORMAT_STRING_ISSUES, ALL_IMPORT_ORDER_ISSUES, ALL_COMPREHENSIONS_ISSUES, - ALL_SPELLCHECK_ISSUES, ALL_WPS_ISSUES] - all_issues = set().union(*map(lambda d: d.keys(), issues_dicts)) - return set(all_issues - set(FLAKE8_DISABLED_ISSUES)) - - -def __match_issue_keys_to_issue_type(issue_keys: Set[str], matcher: Callable) -> Dict[str, IssueType]: - matched_issues = {} - for key in issue_keys: - matched_issues[key] = matcher(key) - return matched_issues - - -# Count for each main category the frequency of issues for this category -def __gather_issues_stat(issue_types: List[IssueType]) -> IssuesStat: - main_category_to_issue_type = get_default_issue_stat() - for issue_type in issue_types: - main_category_to_issue_type[get_main_category_by_issue_type(issue_type)] += 1 - return main_category_to_issue_type - - -def __merge_issues_stats(*args: IssuesStat) -> IssuesStat: - assert len(args) >= 1, 'Please, use at least one argument' - final_stat = {} - for key in args[0].keys(): - final_stat[key] = sum(d[key] for d in args) - return final_stat - - -def __collect_language_stat(*args: Set[Tuple[Set[str], Callable]]) -> IssuesStat: - all_issue_types = [] - for issues, matcher in args: - all_issue_types.append(__match_issue_keys_to_issue_type(issues, matcher).values()) - return __merge_issues_stats(*map(lambda stat: __gather_issues_stat(stat), all_issue_types)) - - -def collect_stat_by_language(language: Language) -> IssuesStat: - if language == Language.PYTHON: - python_inspection_to_matcher = [ - (set(ALL_ISSUES.keys()) - set(PYLINT_DISABLED_ISSUES), PylintInspector.choose_issue_type), - (__get_flake8_issue_keys(), Flake8Inspector.choose_issue_type), - (set(PYTHON_RADON_ISSUES.keys()), RadonInspector.choose_issue_type), - (set(PYTHON_AST_ISSUES.keys()), PythonAstInspector.choose_issue_type), - ] - return __collect_language_stat(*python_inspection_to_matcher) - elif language == Language.JAVA: - java_inspection_to_matcher = [ - (set(PMD_RULE_TO_ISSUE_TYPE.keys()), PMDInspector.choose_issue_type), - (set(CHECK_CLASS_NAME_TO_ISSUE_TYPE.keys()), CheckstyleInspector.choose_issue_type), - ] - return __collect_language_stat(*java_inspection_to_matcher) - elif language == Language.KOTLIN: - kotlin_inspection_to_matcher = [ - (set(DETECT_CLASS_NAME_TO_ISSUE_TYPE.keys()), DetektInspector.choose_issue_type), - ] - return __collect_language_stat(*kotlin_inspection_to_matcher) - elif language == Language.JS: - js_inspection_to_matcher = [ - (set(ESLINT_CLASS_NAME_TO_ISSUE_TYPE.keys()), ESLintInspector.choose_issue_type), - ] - return __collect_language_stat(*js_inspection_to_matcher) - - raise NotImplementedError(f'Language {language} is not supported yet!') - - -def print_stat(language: Language, stat: IssuesStat) -> None: - print(f'Collected statistics for {language.value.lower()} language:') - for issue_type, freq in stat.items(): - print(f'{issue_type}: {freq} times;') - print(f'Note: {IssueType.UNDEFINED} means a category that is not categorized among the four main categories.') - - -def __parse_language(language: str) -> Language: - try: - return Language(language.upper()) - except KeyError: - raise KeyError(f'Incorrect language key: {language}. Please, try again!') - - -def configure_arguments(parser: argparse.ArgumentParser) -> None: - languages = ', '.join(map(lambda l: l.lower(), Language.values())) - - parser.add_argument('language', - type=__parse_language, - help=f'The language for which statistics will be printed. Available values are: {languages}') - - -def main() -> None: - parser = argparse.ArgumentParser() - configure_arguments(parser) - args = parser.parse_args() - - language = args.language - stat = collect_stat_by_language(language) - print_stat(language, stat) - - -if __name__ == '__main__': - main() diff --git a/src/python/evaluation/inspectors/print_inspectors_statistics.py b/src/python/evaluation/inspectors/print_inspectors_statistics.py deleted file mode 100644 index e3146cd6..00000000 --- a/src/python/evaluation/inspectors/print_inspectors_statistics.py +++ /dev/null @@ -1,95 +0,0 @@ -import argparse -from collections import defaultdict -from pathlib import Path -from typing import Dict, List - -from src.python.common.tool_arguments import RunToolArgument -from src.python.evaluation.common.util import ColumnName -from src.python.evaluation.inspectors.common.statistics import ( - GeneralInspectorsStatistics, IssuesStatistics, PenaltyInfluenceStatistics, PenaltyIssue, -) -from src.python.review.common.file_system import deserialize_data_from_file -from src.python.review.inspectors.issue import ShortIssue - - -def configure_arguments(parser: argparse.ArgumentParser) -> None: - parser.add_argument(RunToolArgument.DIFFS_FILE_PATH.value.long_name, - type=lambda value: Path(value).absolute(), - help=RunToolArgument.DIFFS_FILE_PATH.value.description) - - parser.add_argument('--categorize', - help='If True, statistics will be categorized by several categories.', - action='store_true') - - parser.add_argument('-n', '--top-n', - help='The top N items will be printed', - type=int, - default=10) - - parser.add_argument('--full-stat', - help='If True, full statistics will be printed.', - action='store_true') - - -def has_incorrect_grades(diffs_dict: dict) -> bool: - return len(diffs_dict.get(ColumnName.GRADE.value, [])) > 0 - - -def has_decreased_grades(diffs_dict: dict) -> bool: - return len(diffs_dict.get(ColumnName.DECREASED_GRADE.value, [])) > 0 - - -def __gather_issues_stat(issues_stat_dict: Dict[int, List[PenaltyIssue]]) -> IssuesStatistics: - fragments_in_stat = len(issues_stat_dict) - issues_dict: Dict[ShortIssue, int] = defaultdict(int) - for _, issues in issues_stat_dict.items(): - for issue in issues: - short_issue = ShortIssue(origin_class=issue.origin_class, type=issue.type) - issues_dict[short_issue] += 1 - return IssuesStatistics(issues_dict, fragments_in_stat) - - -def gather_statistics(diffs_dict: dict) -> GeneralInspectorsStatistics: - new_issues_stat = __gather_issues_stat(diffs_dict.get(ColumnName.TRACEBACK.value, {})) - penalty_issues_stat = __gather_issues_stat(diffs_dict.get(ColumnName.PENALTY.value, {})) - return GeneralInspectorsStatistics(new_issues_stat, penalty_issues_stat, - PenaltyInfluenceStatistics(diffs_dict.get(ColumnName.PENALTY.value, {}))) - - -def main() -> None: - parser = argparse.ArgumentParser() - configure_arguments(parser) - args = parser.parse_args() - - separator = '______' - - diffs = deserialize_data_from_file(args.diffs_file_path) - if has_incorrect_grades(diffs): - print(f'WARNING! Was found incorrect grades in the following fragments: {diffs[ColumnName.GRADE.value]}.') - else: - print('SUCCESS! Was not found incorrect grades.') - - if not has_decreased_grades(diffs): - print('All grades are equal.') - else: - print(f'Decreased grades was found in {len(diffs[ColumnName.DECREASED_GRADE.value])} fragments') - print(f'{diffs.get(ColumnName.USER.value, 0)} unique users was found!') - print(separator) - - statistics = gather_statistics(diffs) - n = args.top_n - print('NEW INSPECTIONS STATISTICS:') - statistics.new_issues_stat.print_full_statistics(n, args.full_stat, separator) - print(separator) - - print('PENALTY INSPECTIONS STATISTICS;') - statistics.penalty_issues_stat.print_full_statistics(n, args.full_stat, separator) - print(separator) - - print('INFLUENCE ON PENALTY STATISTICS;') - statistics.penalty_influence_stat.print_stat() - print(separator) - - -if __name__ == '__main__': - main() diff --git a/src/python/evaluation/issues_statistics/README.md b/src/python/evaluation/issues_statistics/README.md deleted file mode 100644 index 0b7f83d7..00000000 --- a/src/python/evaluation/issues_statistics/README.md +++ /dev/null @@ -1,59 +0,0 @@ -# Hyperstyle evaluation: statistics - -This module allows you to collect and visualize the statistics of the tool. - -## Get raw issues -This script allows you to get raw issues (issues that have not yet been processed by the main algorithm) for each fragment from a dataset (`xlsx` or `csv` file). The dataset must have 3 obligatory columns: -- `id` -- `code` -- `lang` - -Possible values for column `lang` are: `python3`, `kotlin`, `javascript`, `java7`, `java8`, `java9`, `java11`, `java15`. - -The output file is a new `xlsx` or `csv` file with all columns from the input file and an additional column: `raw_issues`. - -### Usage -Run the [get_raw_issues.py](get_raw_issues.py) with the arguments from command line. - -**Required arguments:** -- `solutions_file_path` — path to xlsx-file or csv-file with code samples to inspect. - -**Optional arguments:** -| Argument | Description | -|----------|-------------| -| **‑‑allow‑duplicates** | Allow duplicate issues found by different linters. By default, duplicates are skipped. | -| **‑‑allow‑zero‑measure‑issues** | Allow issues with zero measure. By default, such issues are skipped. | -| **‑‑allow‑info‑issues** | Allow issues from the INFO category. By default, such issues are skipped. | -| **‑‑to‑save‑path** | Allows to save the path to the file where the issue was found. By default, the path is not saved. | -| **‑o**, **‑‑output** | Path where the dataset with raw issues will be saved. If not specified, the dataset will be saved next to the original one. | -| **‑l**, **‑‑log-output** | Path where logs will be stored. If not specified, then logs will be output to stderr. | - -## Get raw issues statistics -The script takes the dataframe obtained after executing [get_raw_issues.py](get_raw_issues.py) and outputs dataframes with statistics grouped by language. - -The input dataset must have 3 obligatory columns: -- `id` -- `code` -- `lang` -- `raw_issues` - -Possible values for column `lang` are: `python3`, `kotlin`, `javascript`, `java7`, `java8`, `java9`, `java11`, `java15`. - -The output files is a new `xlsx` or `csv` files which contains the `value` column and the columns responsible for its category statistics. - -The `value` column shows the metric value (for measurable issue categories), quantity (for quantitative issue categories) or `ratio * 100` (for `CODE_STYLE` and `LINE_LEN`), where `ratio` is calculated as in the corresponding rules (`CodeStyleRule` and `LineLengthRule`). - -The table cells indicate how often value occurs in one fragment (for quantitative categories) or in all fragments (for measurable categories). - -All output datasets are arranged in folders according to language. - -### Usage -Run the [get_raw_issues_statistics.py](get_raw_issues_statistics.py) with the arguments from command line. - -**Required arguments:** -- `solutions_with_raw_issues` — path to an xlsx- or csv-file with code samples and raw issues, which were received with [get_raw_issues.py](get_raw_issues.py). - -**Optional arguments:** -| Argument | Description | -|----------|-------------| -| **‑o**, **‑‑output** | Path to the folder where datasets with statistics will be saved. If not specified, the datasets will be saved in the folder next to the original dataset. | diff --git a/src/python/evaluation/issues_statistics/__init__.py b/src/python/evaluation/issues_statistics/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/python/evaluation/issues_statistics/common/__init__.py b/src/python/evaluation/issues_statistics/common/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/python/evaluation/issues_statistics/common/raw_issue_encoder_decoder.py b/src/python/evaluation/issues_statistics/common/raw_issue_encoder_decoder.py deleted file mode 100644 index 42206eb3..00000000 --- a/src/python/evaluation/issues_statistics/common/raw_issue_encoder_decoder.py +++ /dev/null @@ -1,67 +0,0 @@ -import json -from pathlib import Path - -from src.python.review.inspectors.inspector_type import InspectorType -from src.python.review.inspectors.issue import ( - BaseIssue, - CodeIssue, - get_issue_class_by_issue_type, - IssueData, - IssueDifficulty, - IssueType, - Measurable, - MEASURABLE_ISSUE_TYPE_TO_MEASURE_NAME, -) - -MEASURE = 'measure' - - -class RawIssueEncoder(json.JSONEncoder): - to_safe_path: bool - - def __init__(self, to_safe_path: bool = True, **kwargs): - super().__init__(**kwargs) - self.to_safe_path = to_safe_path - - def default(self, obj): - if isinstance(obj, BaseIssue): - issue_data = { - IssueData.ORIGIN_ClASS.value: obj.origin_class, - IssueData.ISSUE_TYPE.value: obj.type.value, - IssueData.DESCRIPTION.value: obj.description, - IssueData.FILE_PATH.value: str(obj.file_path) if self.to_safe_path else "", - IssueData.LINE_NUMBER.value: obj.line_no, - IssueData.COLUMN_NUMBER.value: obj.column_no, - IssueData.INSPECTOR_TYPE.value: obj.inspector_type.value, - IssueData.DIFFICULTY.value: obj.difficulty.value, - } - - if isinstance(obj, Measurable): - issue_data[MEASURE] = obj.measure() - - return issue_data - - return json.JSONEncoder.default(self, obj) - - -class RawIssueDecoder(json.JSONDecoder): - def __init__(self, *args, **kwargs): - super().__init__(object_hook=self.object_hook, *args, **kwargs) - - def object_hook(self, json_dict): - json_dict[IssueData.ISSUE_TYPE.value] = IssueType(json_dict[IssueData.ISSUE_TYPE.value]) - json_dict[IssueData.INSPECTOR_TYPE.value] = InspectorType(json_dict[IssueData.INSPECTOR_TYPE.value]) - json_dict[IssueData.FILE_PATH.value] = Path(json_dict[IssueData.FILE_PATH.value]) - # TODO: remove get after analyzing raw issue statistics - json_dict[IssueData.DIFFICULTY.value] = IssueDifficulty( - json_dict.get(IssueData.DIFFICULTY.value, IssueDifficulty.HARD.value), - ) - - issue_type = json_dict[IssueData.ISSUE_TYPE.value] - if issue_type in MEASURABLE_ISSUE_TYPE_TO_MEASURE_NAME.keys(): - measure_name = MEASURABLE_ISSUE_TYPE_TO_MEASURE_NAME[issue_type] - json_dict[measure_name] = json_dict.pop(MEASURE) - measurable_issue_class = get_issue_class_by_issue_type(issue_type) - return measurable_issue_class(**json_dict) - - return CodeIssue(**json_dict) diff --git a/src/python/evaluation/issues_statistics/get_raw_issues.py b/src/python/evaluation/issues_statistics/get_raw_issues.py deleted file mode 100644 index 9aaaac7d..00000000 --- a/src/python/evaluation/issues_statistics/get_raw_issues.py +++ /dev/null @@ -1,275 +0,0 @@ -import argparse -import json -import logging -import os -import sys -from pathlib import Path -from typing import List, Optional - -sys.path.append('') -sys.path.append('../../..') - -import numpy as np -import pandas as pd -from pandarallel import pandarallel -from src.python.common.tool_arguments import RunToolArgument -from src.python.evaluation.common.pandas_util import get_solutions_df_by_file_path, write_df_to_file -from src.python.evaluation.common.util import ColumnName -from src.python.evaluation.issues_statistics.common.raw_issue_encoder_decoder import RawIssueEncoder -from src.python.review.application_config import LanguageVersion -from src.python.review.common.file_system import ( - create_file, - Extension, - get_name_from_path, - get_parent_folder, -) -from src.python.review.common.language import Language -from src.python.review.inspectors.issue import ( - BaseIssue, - IssueType, - Measurable, -) -from src.python.review.reviewers.common import LANGUAGE_TO_INSPECTORS -from src.python.review.reviewers.utils.issues_filter import filter_duplicate_issues - -LANG = ColumnName.LANG.value -CODE = ColumnName.CODE.value -ID = ColumnName.ID.value -RAW_ISSUES = 'raw_issues' - -ALLOWED_EXTENSION = {Extension.XLSX, Extension.CSV} - -ERROR_CODES = [ - 'E999', # flake8 - 'WPS000', # flake8 (wps) - 'E0001', # pylint -] - -logger = logging.getLogger(__name__) - - -def configure_arguments(parser: argparse.ArgumentParser) -> None: - parser.add_argument( - RunToolArgument.SOLUTIONS_FILE_PATH.value.long_name, - type=lambda value: Path(value).absolute(), - help=RunToolArgument.SOLUTIONS_FILE_PATH.value.description, - ) - - parser.add_argument( - RunToolArgument.DUPLICATES.value.long_name, - action='store_true', - help=RunToolArgument.DUPLICATES.value.description, - ) - - parser.add_argument( - '--allow-zero-measure-issues', - action='store_true', - help='Allow issues with zero measure. By default, such issues are skipped.', - ) - - parser.add_argument( - '--allow-info-issues', - action='store_true', - help='Allow issues from the INFO category. By default, such issues are skipped.', - ) - - parser.add_argument( - '--to-save-path', - action='store_true', - help='Allows to save the path to the file where the issue was found. By default, the path is not saved.', - ) - - parser.add_argument( - '-o', '--output', - type=lambda value: Path(value).absolute(), - help='Path where the dataset with raw issues will be saved. ' - 'If not specified, the dataset will be saved next to the original one.', - ) - - parser.add_argument( - '-l', '--log-output', - type=lambda value: Path(value).absolute(), - help='Path where logs will be stored. If not specified, then logs will be output to stderr.', - ) - - -def _filter_issues( - issues: List[BaseIssue], - allow_duplicates: bool, - allow_zero_measure_issues: bool, - allow_info_issues: bool, -) -> List[BaseIssue]: - - filtered_issues = issues - - if not allow_duplicates: - filtered_issues = filter_duplicate_issues(filtered_issues) - - if not allow_zero_measure_issues: - filtered_issues = list( - filter(lambda issue: not isinstance(issue, Measurable) or issue.measure() != 0, filtered_issues), - ) - - if not allow_info_issues: - filtered_issues = list(filter(lambda issue: issue.type != IssueType.INFO, filtered_issues)) - - return filtered_issues - - -def _check_issues_for_errors(issues: List[BaseIssue]) -> bool: - origin_classes = {issue.origin_class for issue in issues} - return any(error_code in origin_classes for error_code in ERROR_CODES) - - -def _inspect_row( - row: pd.Series, - solutions_file_path: Path, - allow_duplicates: bool, - allow_zero_measure_issues: bool, - allow_info_issues: bool, - to_safe_path: bool, -) -> Optional[str]: - - print(f'{row[ID]}: processing started') - - if pd.isnull(row[LANG]): - logger.warning(f'{row[ID]}: no lang.') - return np.nan - - if pd.isnull(row[CODE]): - logger.warning(f'{row[ID]}: no code.') - return np.nan - - # If we were unable to identify the language version, we return None - language_version = LanguageVersion.from_value(row[LANG]) - if language_version is None: - logger.warning(f'{row[ID]}: it was not possible to determine the language version from "{row[LANG]}"') - return np.nan - - # If we were unable to identify the language, we return None - language = Language.from_language_version(language_version) - if language == Language.UNKNOWN: - logger.warning(f'{row[ID]}: it was not possible to determine the language from "{language_version}"') - return np.nan - - # If there are no inspectors for the language, then return None - inspectors = LANGUAGE_TO_INSPECTORS.get(language, []) - if not inspectors: - logger.warning(f'{row[ID]}: no inspectors were found for the {language}.') - return np.nan - - tmp_file_extension = language_version.extension_by_language().value - tmp_file_path = solutions_file_path.parent.absolute() / f'fragment_{row[ID]}{tmp_file_extension}' - temp_file = next(create_file(tmp_file_path, row[CODE])) - - inspectors_config = { - 'language_version': language_version, - 'n_cpu': 1, - } - - raw_issues = [] - - for inspector in inspectors: - try: - issues = inspector.inspect(temp_file, inspectors_config) - - if _check_issues_for_errors(issues): - logger.warning(f'{row[ID]}: inspector {inspector.inspector_type.value} failed.') - continue - - raw_issues.extend(issues) - - except Exception: - logger.warning(f'{row[ID]}: inspector {inspector.inspector_type.value} failed.') - - os.remove(temp_file) - - raw_issues = _filter_issues(raw_issues, allow_duplicates, allow_zero_measure_issues, allow_info_issues) - - json_issues = json.dumps(raw_issues, cls=RawIssueEncoder, to_safe_path=to_safe_path) - - print(f'{row[ID]}: processing finished.') - - return json_issues - - -def _is_correct_output_path(output_path: Path) -> bool: - try: - output_extension = Extension.get_extension_from_file(str(output_path)) - except ValueError: - return False - - return output_extension in ALLOWED_EXTENSION - - -def _get_output_path(solutions_file_path: Path, output_path: Optional[Path]) -> Path: - if output_path is not None: - if _is_correct_output_path(output_path): - return output_path - logger.warning('The output path is not correct. The resulting dataset will be saved next to the original one.') - - extension = Extension.get_extension_from_file(str(solutions_file_path)) - output_dir = get_parent_folder(solutions_file_path) - dataset_name = get_name_from_path(solutions_file_path, with_extension=False) - return output_dir / f'{dataset_name}_with_raw_issues{extension.value}' - - -def inspect_solutions( - solutions_df: pd.DataFrame, - solutions_file_path: Path, - allow_duplicates: bool, - allow_zero_measure_issues: bool, - allow_info_issues: bool, - to_save_path: bool, -) -> pd.DataFrame: - - pandarallel.initialize() - - solutions_df[RAW_ISSUES] = solutions_df.parallel_apply( - _inspect_row, - args=(solutions_file_path, allow_duplicates, allow_zero_measure_issues, allow_info_issues, to_save_path), - axis=1, - ) - - return solutions_df - - -def main() -> None: - parser = argparse.ArgumentParser() - configure_arguments(parser) - args = parser.parse_args() - - if args.log_output is not None: - args.log_output.parent.mkdir(parents=True, exist_ok=True) - - logging.basicConfig( - filename=args.log_output, filemode='w', level=logging.INFO, format='%(asctime)s | %(levelname)s | %(message)s', - ) - - solutions = get_solutions_df_by_file_path(args.solutions_file_path) - - logger.info('Dataset inspection started.') - - solutions_with_raw_issues = inspect_solutions( - solutions, - args.solutions_file_path, - args.allow_duplicates, - args.allow_zero_measure_issues, - args.allow_info_issues, - args.to_save_path, - ) - - logger.info('Dataset inspection finished.') - - output_path = _get_output_path(args.solutions_file_path, args.output) - output_extension = Extension.get_extension_from_file(str(output_path)) - - logger.info(f'Saving the dataframe to a file: {output_path}.') - - write_df_to_file(solutions_with_raw_issues, output_path, output_extension) - - logger.info('Saving complete.') - - -if __name__ == '__main__': - main() diff --git a/src/python/evaluation/issues_statistics/get_raw_issues_statistics.py b/src/python/evaluation/issues_statistics/get_raw_issues_statistics.py deleted file mode 100644 index b32fe4eb..00000000 --- a/src/python/evaluation/issues_statistics/get_raw_issues_statistics.py +++ /dev/null @@ -1,227 +0,0 @@ -import argparse -import json -import logging -import sys -from collections import Counter -from json import JSONDecodeError -from pathlib import Path -from typing import Dict, List, Optional - -sys.path.append('') -sys.path.append('../../..') - -import pandas as pd -from pandarallel import pandarallel -from src.python.evaluation.common.pandas_util import get_solutions_df_by_file_path, write_df_to_file -from src.python.evaluation.common.util import ColumnName -from src.python.evaluation.issues_statistics.common.raw_issue_encoder_decoder import RawIssueDecoder -from src.python.evaluation.issues_statistics.get_raw_issues import RAW_ISSUES -from src.python.review.application_config import LanguageVersion -from src.python.review.common.file_system import Extension, get_parent_folder, get_total_code_lines_from_code -from src.python.review.common.language import Language -from src.python.review.inspectors.issue import BaseIssue, ISSUE_TYPE_TO_CLASS, IssueType, Measurable -from src.python.review.quality.rules.code_style_scoring import CodeStyleRule -from src.python.review.quality.rules.line_len_scoring import LineLengthRule -from src.python.review.reviewers.utils.code_statistics import get_code_style_lines - -ID = ColumnName.ID.value -LANG = ColumnName.LANG.value -CODE = ColumnName.CODE.value - -CODE_STYLE_LINES = f'{IssueType.CODE_STYLE.value}_lines' -CODE_STYLE_RATIO = f'{IssueType.CODE_STYLE.value}_ratio' -LINE_LEN_NUMBER = f'{IssueType.LINE_LEN.value}_number' -LINE_LEN_RATIO = f'{IssueType.LINE_LEN.value}_ratio' -TOTAL_LINES = 'total_lines' -VALUE = 'value' - -OUTPUT_DF_NAME = 'stats' -DEFAULT_OUTPUT_FOLDER_NAME = 'raw_issues_statistics' - -logger = logging.getLogger(__name__) - - -def configure_arguments(parser: argparse.ArgumentParser) -> None: - parser.add_argument( - 'solutions_with_raw_issues', - type=lambda value: Path(value).absolute(), - help=f'Local XLSX-file or CSV-file path. Your file must include column-names: ' - f'"{ID}", "{CODE}", "{LANG}", and "{RAW_ISSUES}".', - ) - - parser.add_argument( - '-o', '--output', - type=lambda value: Path(value).absolute(), - help='Path to the folder where datasets with statistics will be saved. ' - 'If not specified, the datasets will be saved in the folder next to the original one.', - ) - - parser.add_argument( - '-l', '--log-output', - type=lambda value: Path(value).absolute(), - help='Path where logs will be stored. If not specified, then logs will be output to stderr.', - ) - - -def _convert_language_code_to_language(fragment_id: str, language_code: str) -> str: - language_version = LanguageVersion.from_value(language_code) - - if language_version is None: - logger.warning(f'{fragment_id}: it was not possible to determine the language version from "{language_code}".') - return language_code - - language = Language.from_language_version(language_version) - - if language == Language.UNKNOWN: - logger.warning(f'{fragment_id}: it was not possible to determine the language from "{language_version}".') - return language_code - - return language.value - - -def _extract_stats_from_issues(row: pd.Series) -> pd.Series: - print(f'{row[ID]}: extracting stats.') - - if pd.isnull(row[CODE]): - logger.warning(f'{row[ID]}: no code.') - row[CODE] = "" - - if pd.isnull(row[LANG]): - logger.warning(f'{row[ID]}: no lang.') - row[LANG] = "" - - try: - issues: List[BaseIssue] = json.loads(row[RAW_ISSUES], cls=RawIssueDecoder) - except (JSONDecodeError, TypeError): - logger.warning(f'{row[ID]}: failed to decode issues.') - issues: List[BaseIssue] = [] - - counter = Counter([issue.type for issue in issues]) - - for issue_type, issue_class in ISSUE_TYPE_TO_CLASS.items(): - if issubclass(issue_class, Measurable): - row[issue_type.value] = [issue.measure() for issue in issues if isinstance(issue, issue_class)] - else: - row[issue_type.value] = counter[issue_type] - - row[CODE_STYLE_LINES] = get_code_style_lines(issues) - row[LINE_LEN_NUMBER] = counter[IssueType.LINE_LEN] - row[TOTAL_LINES] = get_total_code_lines_from_code(row[CODE]) - - row[LANG] = _convert_language_code_to_language(row[ID], row[LANG]) - - print(f'{row[ID]}: extraction of statistics is complete.') - - return row - - -def _convert_ratio_to_int(ratio: float): - """ - Round the ratio to 2 decimal places, multiply by 100, and take the integer part. - """ - return int((round(ratio, 2) * 100)) - - -def _group_stats_by_lang(df_with_stats: pd.DataFrame) -> Dict[str, pd.DataFrame]: - logger.info('The grouping of statistics by language has started.') - - result = {} - - df_grouped_by_lang = df_with_stats.groupby(LANG) - for lang in df_grouped_by_lang.groups: - logger.info(f'"{lang}" statistics grouping started.') - - lang_group = df_grouped_by_lang.get_group(lang) - - columns_with_stats = [] - - for issue_type, issue_class in ISSUE_TYPE_TO_CLASS.items(): - column = lang_group[issue_type.value] - if issubclass(issue_class, Measurable): - column = column.explode() - columns_with_stats.append(column.value_counts()) - - columns_with_stats.append(lang_group[TOTAL_LINES].value_counts()) - - line_len_ratio_column = lang_group.apply( - lambda row: LineLengthRule.get_ratio(row[LINE_LEN_NUMBER], row[TOTAL_LINES]), - axis=1, - ) - line_len_ratio_column = line_len_ratio_column.apply(_convert_ratio_to_int) - line_len_ratio_column.name = LINE_LEN_RATIO - columns_with_stats.append(line_len_ratio_column.value_counts()) - - code_style_ratio_column = lang_group.apply( - lambda row: CodeStyleRule.get_ratio( - row[CODE_STYLE_LINES], row[TOTAL_LINES], Language.from_value(str(lang), default=Language.UNKNOWN), - ), - axis=1, - ) - code_style_ratio_column = code_style_ratio_column.apply(_convert_ratio_to_int) - code_style_ratio_column.name = CODE_STYLE_RATIO - columns_with_stats.append(code_style_ratio_column.value_counts()) - - stats = pd.concat(columns_with_stats, axis=1).fillna(0).astype(int) - - # Put values in a separate column - stats.index.name = VALUE - stats.reset_index(inplace=True) - - result[str(lang)] = stats - logger.info(f'"{lang}" statistics grouping finished.') - - logger.info('The grouping of statistics by language has finished.') - - return result - - -def inspect_raw_issues(solutions_with_raw_issues: pd.DataFrame) -> Dict[str, pd.DataFrame]: - pandarallel.initialize() - - solutions_with_raw_issues = solutions_with_raw_issues.parallel_apply(_extract_stats_from_issues, axis=1) - - return _group_stats_by_lang(solutions_with_raw_issues) - - -def _get_output_folder(solutions_file_path: Path, output_folder: Optional[Path]): - if output_folder is not None: - return output_folder - - return get_parent_folder(solutions_file_path) / DEFAULT_OUTPUT_FOLDER_NAME - - -def _save_stats(stats_by_lang: Dict[str, pd.DataFrame], solutions_file_path: Path, output_path: Optional[Path]) -> None: - output_folder = _get_output_folder(solutions_file_path, output_path) - output_extension = Extension.get_extension_from_file(str(solutions_file_path)) - - logger.info(f'Saving statistics to a folder: {output_folder}.') - - for lang, stats in stats_by_lang.items(): - lang_folder = output_folder / lang - lang_folder.mkdir(parents=True, exist_ok=True) - write_df_to_file(stats, lang_folder / f'{OUTPUT_DF_NAME}{output_extension.value}', output_extension) - - logger.info('Saving statistics is complete.') - - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - configure_arguments(parser) - args = parser.parse_args() - - if args.log_output is not None: - args.log_output.parent.mkdir(parents=True, exist_ok=True) - - logging.basicConfig( - filename=args.log_output, filemode="w", level=logging.INFO, format='%(asctime)s | %(levelname)s | %(message)s', - ) - - solutions_with_raw_issues = get_solutions_df_by_file_path(args.solutions_with_raw_issues) - - logger.info("Dataset inspection started.") - - stats_by_lang = inspect_raw_issues(solutions_with_raw_issues) - - logger.info("Dataset inspection finished.") - - _save_stats(stats_by_lang, args.solutions_with_raw_issues, args.output) diff --git a/src/python/evaluation/paper_evaluation/README.md b/src/python/evaluation/paper_evaluation/README.md deleted file mode 100644 index 5dac490b..00000000 --- a/src/python/evaluation/paper_evaluation/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Paper evaluation - -This module contains scripts for SIGCSE-2022 paper evaluation: - -- [Comparison with other tools](./comparison_with_other_tools/README.md) -- Formatting issues importance -- [Dynamics of student usage](./user_dynamics/README.md) \ No newline at end of file diff --git a/src/python/evaluation/paper_evaluation/__init__.py b/src/python/evaluation/paper_evaluation/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/python/evaluation/paper_evaluation/comparison_with_other_tools/README.md b/src/python/evaluation/paper_evaluation/comparison_with_other_tools/README.md deleted file mode 100644 index 618165f7..00000000 --- a/src/python/evaluation/paper_evaluation/comparison_with_other_tools/README.md +++ /dev/null @@ -1,58 +0,0 @@ -# Comparison with other tools evaluation - -This module allows getting statistic about using of several code quality tools. -In our work we compare the Hyperstyle tool with the [Tutor](https://www.hkeuning.nl/rpt/) tool. -Other tools (FrenchPress, WebTA, and AutoStyle) does not have open sources. - -To get statistics we use students solutions for six programming tasks, -but the main script can gather this statistics for any tasks. - -The tasks from the out dataset: -- **countEven**. The `countEven` method returns the number of even integers in the values-array. -- **sumValues**. The `sumValues` method adds up all numbers from the values-array, - or only the positive numbers if the `positivesOnly` boolean parameter is set - to `true`. -- **oddSum**. The method `oddSum` returns the sum of all numbers at an odd index - in the array parameter, until the number -1 is seen at an odd index. -- **calculateScore**. The `calculateScore` method calculates the score for a train trip. - The highest score is 10. The score is based on the number of changes and the day of - the week (Monday is 1, Sunday is 7). -- **hasDoubled**. Write a program that calculates in how many years your savings - have doubled with the given interest. -- **haveThree**. Given an array of ints, return true if the value 3 appears in the - array exactly 3 times, and no 3's are next to each other. - -The dataset has several columns: -- Student id (student_id); -- Task key (task_key); -- Code fragment (solution); -- Tutor error, if it is existed (tutor_error); -- Tutor issues keys (tutor_issues); -- Hyperstyle issues keys (hyperstyle_issues); -- Hyperstyle INFO issues keys (hyperstyle_info_issues); -- Code style issues count (code_style_issues_count). - -The dataset stores in the `csv` format. - -## Usage - -Run the [statistics_gathering.py](statistics_gathering.py) with the arguments from command line. - -Required arguments: - -`solutions_file_path` — path to csv-file with code samples. - -The statistics will be printed in the terminal. The statistics includes: -- Unique users count; -- Code snippets count; -- Tasks statistics: for each task count code snippets and count snippets with the Tutor errors; -- Count code fragments has Tutor errors; -- Count of unique errors was found in Tutor; -- Error statistics: for each error get the error text and frequency; -- Issues statistics: - - Count of unique issues in total; - - Common issues statistics: for all common issues for Hyperstyle and Tutor count frequency of this issue; - - Tutor unique issues statistics: for all Tutor issues (that were not found by Hyperstyle) count frequency of this issue; - - Hyperstyle unique issues statistics: for all Hyperstyle issues (that were not found by Tutor) count frequency of this issue; - - Count code style issues and count fragments with these issues. - diff --git a/src/python/evaluation/paper_evaluation/comparison_with_other_tools/__init__.py b/src/python/evaluation/paper_evaluation/comparison_with_other_tools/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/python/evaluation/paper_evaluation/comparison_with_other_tools/statistics_gathering.py b/src/python/evaluation/paper_evaluation/comparison_with_other_tools/statistics_gathering.py deleted file mode 100644 index 130092eb..00000000 --- a/src/python/evaluation/paper_evaluation/comparison_with_other_tools/statistics_gathering.py +++ /dev/null @@ -1,58 +0,0 @@ -import argparse -import logging -import sys -from pathlib import Path - -from src.python.common.tool_arguments import RunToolArgument -from src.python.evaluation.common.pandas_util import get_solutions_df -from src.python.evaluation.paper_evaluation.comparison_with_other_tools.tutor_statistics import ( - IssuesStatistics, TutorStatistics, -) -from src.python.evaluation.paper_evaluation.comparison_with_other_tools.util import ComparisonColumnName -from src.python.review.common.file_system import Extension, get_restricted_extension - -sys.path.append('') -sys.path.append('../../..') - -logger = logging.getLogger(__name__) - - -def configure_arguments(parser: argparse.ArgumentParser) -> None: - parser.add_argument(RunToolArgument.SOLUTIONS_FILE_PATH.value.long_name, - type=lambda value: Path(value).absolute(), - help='Local CSV-file path with feedback from different tools. ' - 'Your file must include column-names:' - f'"{ComparisonColumnName.STUDENT_ID.name}" and ' - f'"{ComparisonColumnName.TASK_KEY.name}" and ' - f'"{ComparisonColumnName.SOLUTION.name}" and ' - f'"{ComparisonColumnName.TUTOR_ERROR.name}" and ') - - -def main() -> int: - parser = argparse.ArgumentParser() - configure_arguments(parser) - - try: - args = parser.parse_args() - solutions_file_path = args.solutions_file_path - extension = get_restricted_extension(solutions_file_path, [Extension.CSV]) - solutions_df = get_solutions_df(extension, solutions_file_path) - tutor_stat = TutorStatistics(solutions_df, to_drop_duplicates=True) - tutor_stat.print_tasks_stat() - tutor_stat.print_error_stat() - print('ISSUES STAT:') - issue_stat = IssuesStatistics(solutions_df) - issue_stat.print_issues_stat() - return 0 - - except FileNotFoundError: - logger.error('CSV-file with the specified name does not exists.') - return 2 - - except Exception: - logger.exception('An unexpected error.') - return 2 - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/src/python/evaluation/paper_evaluation/comparison_with_other_tools/tutor_statistics.py b/src/python/evaluation/paper_evaluation/comparison_with_other_tools/tutor_statistics.py deleted file mode 100644 index 083d6311..00000000 --- a/src/python/evaluation/paper_evaluation/comparison_with_other_tools/tutor_statistics.py +++ /dev/null @@ -1,127 +0,0 @@ -from collections import Counter -from collections import defaultdict -from dataclasses import dataclass -from typing import Any, Dict, List - -import pandas as pd -from src.python.evaluation.common.pandas_util import filter_df_by_single_value -from src.python.evaluation.paper_evaluation.comparison_with_other_tools.util import ( - ComparisonColumnName, ERROR_CONST, TutorTask, -) - - -def sort_freq_dict(freq_dict: Dict[Any, int]) -> Dict[Any, int]: - return dict(sorted(freq_dict.items(), key=lambda item: item[1], reverse=True)) - - -@dataclass -class TutorStatistics: - unique_users: int - task_to_freq: Dict[TutorTask, int] - task_to_error_freq: Dict[TutorTask, int] - error_to_freq: Dict[str, int] - fragments_with_error: int = 0 - - __separator: str = '----------' - - def __init__(self, solutions_df: pd.DataFrame, to_drop_duplicates: bool = False): - if to_drop_duplicates: - solutions_df = solutions_df.drop_duplicates(ComparisonColumnName.SOLUTION.value) - self.unique_users = len(solutions_df[ComparisonColumnName.STUDENT_ID.value].unique()) - self.task_to_freq = defaultdict(int) - self.task_to_error_freq = defaultdict(int) - self.error_to_freq = defaultdict(int) - for task in TutorTask: - task_df = filter_df_by_single_value(solutions_df, ComparisonColumnName.TASK_KEY.value, task.value) - self.task_to_freq[task] = task_df.shape[0] - errors_list = list(map(lambda e_l: e_l.split(';'), - task_df[ComparisonColumnName.TUTOR_ERROR.value].dropna().values)) - for cell_errors in errors_list: - for error in cell_errors: - self.error_to_freq[error.strip()] += 1 - self.task_to_error_freq[task] += 1 - self.fragments_with_error += 1 - self.task_to_freq = sort_freq_dict(self.task_to_freq) - self.error_to_freq = sort_freq_dict(self.error_to_freq) - - def print_tasks_stat(self) -> None: - print(f'Unique users count: {self.unique_users}') - print(f'Code snippets count: {sum(self.task_to_freq.values())}') - print('Tasks statistics:') - for task, freq in self.task_to_freq.items(): - print(f'Task {task.value}: {freq} items; {self.task_to_error_freq[task]} with tutor errors') - print(self.__separator) - - def print_error_stat(self) -> None: - print(f'{self.fragments_with_error} code fragments has errors during running by Tutor') - print(f'{len(self.error_to_freq.keys())} unique errors was found in Tutor') - print('Error statistics:') - for error, freq in self.error_to_freq.items(): - print(f'{error}: {freq} items') - print(self.__separator) - - -@dataclass -class IssuesStatistics: - common_issue_to_freq: Dict[str, int] - tutor_uniq_issue_to_freq: Dict[str, int] - hyperstyle_uniq_issue_to_freq: Dict[str, int] - - code_style_issues_count: int - fragments_count_with_code_style_issues: int - - __separator: str = '----------' - - # TODO: info and code style issues - def __init__(self, solutions_df: pd.DataFrame, to_drop_duplicates: bool = False): - if to_drop_duplicates: - solutions_df = solutions_df.drop_duplicates(ComparisonColumnName.SOLUTION.value) - self.common_issue_to_freq = defaultdict(int) - self.tutor_uniq_issue_to_freq = defaultdict(int) - self.hyperstyle_uniq_issue_to_freq = defaultdict(int) - solutions_df.apply(lambda row: self.__init_solution_df_row(row), axis=1) - self.common_issue_to_freq = sort_freq_dict(self.common_issue_to_freq) - self.tutor_uniq_issue_to_freq = sort_freq_dict(self.tutor_uniq_issue_to_freq) - self.hyperstyle_uniq_issue_to_freq = sort_freq_dict(self.hyperstyle_uniq_issue_to_freq) - self.code_style_issues_count = sum(solutions_df[ComparisonColumnName.CODE_STYLE_ISSUES_COUNT.value]) - self.fragments_count_with_code_style_issues = len(list( - filter(lambda x: x != 0, solutions_df[ComparisonColumnName.CODE_STYLE_ISSUES_COUNT.value]))) - - @staticmethod - def __parse_issues(issues_str: str) -> List[str]: - if pd.isna(issues_str) or issues_str == ERROR_CONST: - return [] - return list(map(lambda i: i.strip(), issues_str.split(';'))) - - @staticmethod - def __add_issues(issues_dict: Dict[str, int], issues: List[str]) -> None: - for issue in issues: - issues_dict[issue] += 1 - - def __init_solution_df_row(self, row: pd.DataFrame) -> None: - tutor_issues = self.__parse_issues(row[ComparisonColumnName.TUTOR_ISSUES.value]) - hyperstyle_issues = self.__parse_issues(row[ComparisonColumnName.HYPERSTYLE_ISSUES.value]) - common_issues = list((Counter(tutor_issues) & Counter(hyperstyle_issues)).elements()) - self.__add_issues(self.common_issue_to_freq, common_issues) - self.__add_issues(self.tutor_uniq_issue_to_freq, list(set(tutor_issues) - set(common_issues))) - self.__add_issues(self.hyperstyle_uniq_issue_to_freq, list(set(hyperstyle_issues) - set(common_issues))) - - def __print_freq_issues_stat(self, freq_stat: Dict[str, int], prefix: str) -> None: - print(f'{prefix} issues statistics:') - for issue, freq in freq_stat.items(): - print(f'{issue} was found {freq} times') - print(self.__separator) - - def print_issues_stat(self) -> None: - uniq_issues = (len(self.common_issue_to_freq) - + len(self.tutor_uniq_issue_to_freq) - + len(self.hyperstyle_uniq_issue_to_freq) - ) - print(f'{uniq_issues} unique issues in total was found') - print(self.__separator) - self.__print_freq_issues_stat(self.common_issue_to_freq, 'Common') - self.__print_freq_issues_stat(self.tutor_uniq_issue_to_freq, 'Tutor unique') - self.__print_freq_issues_stat(self.hyperstyle_uniq_issue_to_freq, 'Hyperstyle unique') - print(f'{self.code_style_issues_count} code style issues (spaces, different brackets, indentations)' - f' was found in total by hyperstyle in {self.fragments_count_with_code_style_issues} fragments') - print(self.__separator) diff --git a/src/python/evaluation/paper_evaluation/comparison_with_other_tools/util.py b/src/python/evaluation/paper_evaluation/comparison_with_other_tools/util.py deleted file mode 100644 index eff1bc15..00000000 --- a/src/python/evaluation/paper_evaluation/comparison_with_other_tools/util.py +++ /dev/null @@ -1,27 +0,0 @@ -from enum import Enum, unique - - -@unique -class ComparisonColumnName(Enum): - STUDENT_ID = 'student_id' - TASK_KEY = 'task_key' - SOLUTION = 'solution' - TUTOR_ERROR = 'tutor_error' - - TUTOR_ISSUES = 'tutor_issues' - HYPERSTYLE_ISSUES = 'hyperstyle_issues' - HYPERSTYLE_INFO_ISSUES = 'hyperstyle_info_issues' - CODE_STYLE_ISSUES_COUNT = 'code_style_issues_count' - - -ERROR_CONST = 'ERROR' - - -@unique -class TutorTask(Enum): - EVEN = 'countEven' - SUM_VALUES = 'sumValues' - ODD_SUM = 'oddSum' - SCORE = 'calculateScore' - HAS_DOUBLED = 'hasDoubled' - HAVE_THREE = 'haveThree' diff --git a/src/python/evaluation/paper_evaluation/issues_statistics/README.md b/src/python/evaluation/paper_evaluation/issues_statistics/README.md deleted file mode 100644 index 0c185a79..00000000 --- a/src/python/evaluation/paper_evaluation/issues_statistics/README.md +++ /dev/null @@ -1,107 +0,0 @@ -# Raw issue statistics visualization - -This script allows you to visualize raw issue statistics for a paper. - -## Usage -Run the [raw_issues_statistics_visualization.py](./raw_issues_statistics_visualization.py) with the arguments from command line. - -**Required arguments**: - --`stats_path` — path to a file with stats that were founded by [get_raw_issues_statistics.py](../../issues_statistics/get_raw_issues_statistics.py). Must be an xlsx or csv file. --`config_path` — path to the yaml file containing information about the charts to be plotted. A description of the config and its example is provided in [this section](#config). --`save_dir` — directory where the plotted charts will be saved. - -**Optional arguments**: -Argument | Description ---- | --- -**‑‑file‑extension** | Allows you to select the extension of output files. Available extensions: `.png`, `.jpg`, `.jpeg`, `.webp`, `.svg`, `.pdf`, `.eps`, `.json`. Default is `.svg`. - -## Config -The configuration file is a yaml file where each group name has its config. The group config contains `plot_config` and configs for each column of statistics. - -The `plot_config` consists of the following parameters: -- `rows` — number of rows. Default: `1`. -- `cols` — number of cols. Default: `1`. -- `height` — graph height. Default: `800`. -- `width` — graph width. Default: `1600`. -- `x_axis_name` — name of the x-axis. Default: `Value`. -- `y_axis_name` — name of the y-axis. Default: `Quantity`. -- `specs` — сonfiguration of traces on the graph. See [documentation](https://plotly.com/python-api-reference/generated/plotly.subplots.make_subplots.html) for details. Default: `None`. - -The column config consists of the following arguments: -- `range_of_values` — allows you to filter the values. It is an array of two values: a and b. Only values that belong to the range [a, b) are taken into account when plotting. By default, all values are taken into account when plotting. -- `trace_name` — trace name. The default is the name of the column. - -## Examples -### config.yaml -```yaml -measurable: - plot_config: - rows: 2 - cols: 2 - specs: [[{}, {}], [{colspan: 2}, null]] - x_axis_name: Measure - y_axis_name: Number of issues - BOOL_EXPR_LEN: - range_of_values: [1, 11] - trace_name: Boolean Expresion Length - CYCLOMATIC_COMPLEXITY: - range_of_values: [1, 11] - trace_name: Cyclomatic Complexity - FUNC_LEN: - range_of_values: [0, 60] - trace_name: Function Length - -maintainability_and_cohesion: - plot_config: - rows: 2 - width: 1000 - x_axis_name: Lack of measure (%) - y_axis_name: Number of issues - MAINTAINABILITY: - trace_name: Maintainability - COHESION: - trace_name: Cohesion - -ratio: - plot_config: - rows: 2 - width: 1000 - x_axis_name: Ratio (%) - y_axis_name: Number of fragments - CODE_STYLE_ratio: - range_of_values: [ 1, 101 ] - trace_name: Code Style - LINE_LEN_ratio: - range_of_values: [ 1, 101 ] - trace_name: Line Length - -countable: - plot_config: - rows: 2 - cols: 2 - specs: [[{"rowspan": 2}, {}], [null, {}]] - x_axis_name: Number of issues in one fragment - y_axis_name: Number of fragments - ERROR_PRONE: - range_of_values: [ 0, 10 ] - trace_name: Error Prone - BEST_PRACTICES: - range_of_values: [ 0, 10 ] - trace_name: Best Practices - COMPLEXITY: - range_of_values: [ 0, 10 ] - trace_name: Complexity -``` - -### measurable.png - - -### maintainability_and_cohesion.png - - -### ratio.png - - -### countable.png - diff --git a/src/python/evaluation/paper_evaluation/issues_statistics/__init__.py b/src/python/evaluation/paper_evaluation/issues_statistics/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/python/evaluation/paper_evaluation/issues_statistics/examples/countable.png b/src/python/evaluation/paper_evaluation/issues_statistics/examples/countable.png deleted file mode 100644 index 28f86363e2184fb69b07487a34940b407c37153d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 147959 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 z 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 z z$1o|lGiyQA1SeuSG!#a)*JkWjKVGlLpYUq?Q8*|AN-EpifeOor`P!%))HLNSwLYk3 zB;)+c5$Pi#0y4PLbL!rly9mvF38Gr_oc5BNCog858Tj36?!R_@=Xn;R?oDDuZt^S} zL*X(RvmV2rd-zTL@sm0p!_nidAN{>IZ_gUz%-5?n>^F^x&jF0{aKN_PU6)`(&O9tW z#&~h#)dN7_&kq;8c15q?TwG{DP;WF;EI}XjrB21&HHQ`hAMuz?gWet&I1( zt7S8L#wmSj4ngiLYK$)3_vzj3Fsd4hCI>?mG+%*H3oW`H_eZg!pS-M0sDxKjP}t^M z}?K0m-q^y z>?Hke@*uwX zIOBe{1Y--gRzj20N%R1Zv2CHrbKTag7v824Cg=Knds4ZNUZ?aI4!^?|EWN@OSQ&o; z3~IO_T6P3;3IFIb-W_!G6zEM_CyQ z5YVW45=Okx*nUn)+}p1l_rTY5UA8SGcg3E8|Larem*%Igq?4-yeMQ9%k~D|MCl^v% zhd;_R7_Rji;i9E*`(AA!A3^Khr{AMH+?lIxh(Epn3FwwX-K-NUcjZgMFF$>{7y76# zE!gfLQ`6Eq95&7>unyE_N(rQvM6J!5srX1l@$*J{aUZCMDRb#NSyug2!-zs1%B zo5d+Vs7)+JKIPMhHif|xBy?`$A~Wp?D#iC?95Bh430QblQuWM%O9P4b-GP&+A|2+M zH9vg(*lxYN$sRido1}y?cu{We$VYc?)<<;Yl+$G6j2NB1ddjlSD16C{p=w;r1y!n- z326?@dpJp*2!;Ujk9@kXRe0)iU^L8=>fxI(RxMk}kyI4_`FIO|^ARO!q!o&I@tiTu z4IUrpoA=(#T4(7?Tf=VHw;*dyo9S^QjKVz;tti8~LecZ)qRwn=~)dhc-5CQv`dBt0PIt zb_=ZJ?VE%6o-&?ZOb1ow1AbD;SB=*z1;0`pF|Z8>HW@P(y)H zidX-$lvodIANTV7kn!#fRvEnobp?9N$5L*}Xl`1bAUt-yG-B03`-o%n8W&Mb6`?~u%3@M*X;9{T*J8Q+ zc33I-4$jLD*sIY?Xug|`+`*%oC1^u+BlFaRoP?>j(x&fyG;1E%q0{-WCLHMX2);N9 zcYENcmxF%Ag0nK)^Qqg$^d82D=#Rn=Rv^t1sUD8$n54Rqhtu^H*@WHI$>lD*b-F0I zil5F`Pam{jX-Wqy7f7sZ_`IQHQD0;le`>s zc-)suAyM|Xfj7zwUUv&xs@zx=?OBB#BO;}^$cz)m2K;$`nJXt?t`uC#Z`cGEQEEbM=h&3<25Bg>7!YKs4Wb%&I`7;fj+}09!={4DV#IJI&yO2*;SV1Yi$q?Ls3)WOY%d$Z5U!exzVHpIS3y8Y;6`5+;m8UQPMmKC~0o#&=Q z+N{F;T9R+C2Fx{ama?fWx&P=x^~0Qf6JJ->8@C5DTlh71^TOJH$on7YTSHBgq*dvU z6LFONmzt2axHU2LpUFIgCH3vHAObj6=nYwR-<)smHM_!p#hOBO|xhB_5L(LpbzxfOT*|y#plf%lR0~ElrtNoMb~_3t za@h3QdAXf7ix!*Gx2*l{23-|Be|s}BmWhRr)9bk!Il~F>cc0k-SQ*J*0U^B_Ie{hA@ zkPeao^oHQe^<}sQ6MzYHM_j^}$$PL9Ra@Mlb%2wrmPWUiE`8g;>zd#BW+QbI+)lsJ6Z7E zf`9vN)%)n&g0R-uMK&jG=!VJ-(@Pq$69n%WME0uxN?*6^+Dq&AZKWvYB%+eAOCM?8 zihhl}chIRX*>ou;%PKE;JBISh)aSaTw~j64*AaB&k!TvdjcSE`BR5=M7+t6y)x(aN zHF%V6m{J_Sm~9v*U_qRSSZdqE7Y$3^nTB%cIp~SPsBt2EppG1}{E88ejI)9;28yg} zb7@B3P@HB!woSpceE*rf@&}(2MdOT7rihH#e`rYZQyavoJeFAI!V1$MD{@>KxqN3O znqzj%uzHMd{F{|Rb|=*Y`a}4tFuH=J#Yk|MOZSM}B`uiyNh(Uzg0I@h9v_%AOW?n2 zEv$sV8r$tg6ZBWpAWv=h z4_4koN;|vz3Rw}~6Z^kaK0t=_<+O9LBJSb6$^I8}i&6=$>U$gU@z9lMOquKkpq`D& z@Ttr4pOWPMSOh4YSK06XHAe}i$%ufpZsik>VM_|>6IA1A8uEHITz8CSFH&KCZ#+=# zT?C0t#ujik-DHHV4PwsCEY7{Y;Okg0TR%JxQRFUFxjHoKCOLX;VYR-=UF#fRa8R%8$`6&NV%>N9tM~AUgWX zXoZ8@c9z}{!j=RwF)3~Q9^R03jp38VIYxS=ru! z-<1691EsFU`6_&*xa|9iX1@LV7}AMzt^qXYl{h-TO)nLE5QUt_A6H$fB2Dl~*BNp! zx0H6y@1}eNw1cpxw0baehggGr6(}#n>(dGRWwem@?za^Bvo4tdgP4iM&Z_SfLZ6?` zjVX`JZZ{o3pIk#0dwS6f>s_Ej2+)oSUO>J;ysjQ-FB^V@*pSFoXrCZBoV+YyZqfpb zZ;GF?z!?r?01Mc(vtxy;;D%}eqS97y58Qx!{TP084HVx`rz!Ryz5rkN?_W2D-;4rR&9RYcqhTmKJ^SP>2;w^I|H^6w$EHSM zE7n11#zrc_O!66{mTv$B31Ev40ju6ArBm;7qNu{98|`qKmXNBym_lYN_6@l$Lgcg` z*Re*{W4}f>3;23e5P{zzKyBi9UBRWXDc9GwQA%{cvhxlCj74$jd=w4rKib+qb_Os< z^X?$gVY@8W>u;11(nah6u7DO#Aj{?4+O^<6qx2i(tZYhlI0Z1iGo3H5S5TmrvF7Go zW>fi)lHw~E3R*}d2QR7!L&s@v~f%YKeL_YhkbFW;S|=I>!29u|4k&bxtD zaU}v1!_AQFG|+@6Cu>UN^s1NLai4=_cwfG^jLdz6>xSmiiiU)+-Q1&!fo>9*x`+f` zt0n187P9aQi#Wv)m^tLr+PHggzxF#vwS_h|L^affH4u`=u>;X4%7uGO~d=| zaeqcwTD0B_7mNB7cBBmDD{bZ8443KeuiJEUAhg~MPMiv7_|^f!!W6BC)WkZ<@!CfD zV+f>nNT%##4J0<$G!U5JfmZ>I_dgVn{{!pQ#2Czl5`ouxbqWz4Ol7%l z1z|&-On}6Rd^}(knsPw36Mn0mbO3a3tV!OG6P}@i(=}fK%_ns5*p?kHB#0Q~!BYRT zQ38b+?3WB9GA9kj-EKoJ^zJDQj#pD5-2mQ_x1Vckzq}gcqN%T~Xt&TV>BBgS7qM-& z+8)n_NKBPz@_urq>u85|vs@h+A~GAE_`h^Fh!SD>^Stc3VpA2ss#G5r6||J;GNJWU z948`iYjH^U;C9B1LyyO+Wf#8PfdZjEGnkzw@8} z`WMwEA2c1|pyK}GSH&GL zvm@z&cN4zzU)kaZ7+om-g6&D`3uG^?TUWUe9H;e-0jgjmE@yrt)h=THS#+V|RIymz zF+m)R3EX2PoP0Hs0~4EYX?WdGQ3Z?_bEXBn`Spf>G5G=HZ40PO{W}&8|5OoGXLMWK zh~E(66{kmf3;IbmER(A#C#}=6Okl>K1+Ckc1OMVpd!n%k!Tpf1N2U3BVb&LDS&;6B zRih)jO{Par7U3bm^%HgaO^MRuD`L;V-nye;IBA@S;4Z*i8KVSZzR))XB8b2JQdfQ} zXAK!*P;jq2sjyE)FQcFspA0@Sy86@KGWa?hf*usYFtuoh&p@dw3K)jI=}un3XQ6gp zxmA_UJm=;YkMmctP?Cu1i}=+E^S^fpnCK%xZG9MW0Z2*Gk(q)~knXNX)p^kz`?vSn ztNz^6fU&jv;mO?UUJh4x=v(vwA4h*Nys9n?koEu4qJ|>t|8M80!1_I(ogj<&vy2^1 zM1br*(wsp!cO~biG{C&C_x}7tTYKybM=p8pE{0co{CYm1_x{lW_pj&IXIA$?66az} zbud8!GEC$~-4dfIVtq9ZU7>{wo!e3Idch0yyr5rI#aH!mpOci@0nmve^^!3}M{O@v z4Wn1IfMx(Zs0e8Mcnuq~8;tGSE2z?Rl`w|S<=qScC&u?bPi#GAs$gtZ1m;%p9piqI znDdX>0D2#Uipqe0{YG8>+Wwn_0E*LTvvA2Qhw4ceeHP-NH~)vRw~mXlTib@O85%)a z8b**-DUpUzP>_~JDFH#G8>I$|4oT?{q(QnH0Z9P?X%G;kyW?BKeeZj_pZ&b=`~AcG zF7!97YppYm^EhKsE*I>@3XWM8Kfs}P{5I)zww=W25c)+FDzp7u@4vRxX>hhx=O>+N z)g3FqsJ;Whr|s_Uu9Kdgo{fvM^W{h0AMg4szkBi)qMLhnR~rLQofdWs=H6Eled`U# zI%bO&l(hDyF~`eA^4P;M17Nj+)FJfxRw|dMxUt$nx_^v{^1b0&v_Qg{?(vc+!*!I+ zARW4=CG)>E!CBr$6#9G?^`mecD=VADSRZHOov*gj<~%Pv`z0LJEN$Z5CTCU&sXLiL zLsK5r#J+-fnM<8R7*)NbsnmRy>gdJ9uP)YJ^`7i4{;kb3oCS@=fZTxK7({MHP)amQMtb z1PN~^mQ~Nriy@Rnv?@P8N*EfPWoubIls8K0lP@bMXz5_S^Uq8q$0V>eD^yVlNfWB@by{qb#gnS(6~# z25;+If;!MnMU7sYb^Rj;eZ`Lw$nsC>`e+a{_g^4}7na5MuUdeMBBM3`%N$5u5~-); zXcI;E&%pqj-_yDnYv$E+8FZ{55Ao)hkvzt&Pr_NPB~KSPh4fHQ1O>IGF*Itk*Mru! z(Jd5Ghdzsb___{cj_;wvsH^sap*#8JphIVn%r7cSwg=)MJ0Nue0}+`*pNbJ;$x_cm zCtKi$l7g|Rpb6}7GdlvPT4Y$-rB<+#SH%A8-taVB*PFr-@`jbyeBqtb1flRo3eOK< z!zd&$86LnVuK{oH^|GC5v)zFEBZm*!T~`dba241!b7bTC)Eo@9`j)4*Sc8i+R$~F) z$829QZ=>UQXQyS&l>JiKZNHy8@&*f$BM9QXL+^9^Z-A_lO9Zfd_Xr{%VxnubK-BN- ziBW%Sk9VD@4b8Q<=D*lmI6$|IM#LcRz|*<}w2b!iEAgsiQSNdCvsriGn4^=ErH)E0 z`cOIz8J298Y}A4nIbwcBze685(+2~G4xrDD~yvflF^XySa2~CMx_$Nd>)oaB-yxP@F`jjiU^DxDYFLi~evEy5wL_IW(17 zoeIE&R*MStJ#?h=pWR{~(Sj;!33~J9*+R>q&0%gaxfb2bPz-4m(M6cRjuSE}=DGfG z%rno=C(YXmSm=GYhtmGqon^K1R#ws4Kd0KHLr$e6$nhyKZNJ1NEmP1hYBL?uAOnlP z!4&es>(-zk94v!B12j$lZ+m~?t$|MQR{a`DDsBeOQ^ga$hb4OvnN(qgz9{R^L|3=w z5$5Cx3K@JP1FHN@5fr^!&Ek`cc!Zkpr{{YNhAHW*G?M|>u@{LJ`3ooYU+tQaHM01j zVa$1xWU62%-2TB<=)So>cLJ#F_qR<8RH2>Np6#b(ud2VaY@5G#`Jz6+W8%PWnmsMg z^n;E6)}UIr-w%O##!t&!f3HbtwZ;eW450UZp)?PtPKKDQPTS?S4z;??Qv8NGOztYDoO%1l|F0N0#-}w4L!)pL2h`o5mS(%C{ zjwC@qp7AkAfH=?{=asz1raC9dX$elHkX{k6C;6m^0opj2PAKiWtY3b;&Qo>mzfm>) z0Gn!s(bOsZW$OOv0xh@>vH}&;P;(|aJlpB=VXphOfny+o(ZCBz`dtloMUQd>$Kr-X zl+w3E)1a)AKzdrxz(NH(=8}O^ozi{_s^(P8(PNjE zFnQB%Fw$xKDTz`A)>7+GbK=)TN<3U&XjNA#2kK>mq%yHBWZi(%mh2aqm2n6_C1Y_0aln`1Xqfdr0PU&ks{8k0s?Sr66MF@E&suXM2xXI- zaDR9%t`Xgzq<98sx>XCGI|%YR848?Fq=nt9B?Viz(b^z~Qb^iYgn0@cjDE8itBOig zogeP>Z3cx9e@Nm5Tyj)L9lV|?@Ndt{KFarxA0-KyG$Irv#%IKC7spqWvLi&ClT4f7 zN?13ERWeVyClqUQ)`9MC|BxS*FyK_$UW&a0L=n~#7*iDkMYYGpxCYic?1F&vp*MXaZ*IJwJ>f0x@|!KOQ%0SdOn?TB zjLgm4QgTf`67d#0zQ~EISh7zSmKPU6rR%?B;QJ=fHlg5}Gvc7I?CLp zxvtlajDo3N+|jrVNX-FyHnkD@s=Fv%57Rasi6r-Cg=My*^{HnXg8@p_9aE1+4!A5F z(KZci`q&}i$y(<>o&M+-nMF4ltC*tm?iv}ARELDgY<|=34&v5pAR8-Eer9DVs5tS` zL73)MC;77nEJjnD+XprMwP-(2ir^PK-YWST&gMjf|8O^HNK}o`I?NPDtk6>znzdQ5=ly=?vkXLY%d~ymUmYUrQ8bEX^opA2X zJcah;TaC#qgMGSJNZ6~P%A>#@+Ix;OpXWJyB<4G+I#&tb=5;8d;A!J{f0uZWQZeP&szp4t%3LMHV^5>^}pKLJy)2SNgsOeaj39`nrCN&)b2M8;xw!u z@P?bH@7fkzQX81$>p(B=_x9W6+YXOoPFzD?KLLXc+^(vI(|%dH8B;_mKO{;S;sRuN zQ%SQ~IRAZwQV}WYQi?3 z=@%==^=IuX{RB|r7_+^G67k_ZZB~rtd2vp(vn%(n&4LeblN0I?Ga_=t?1SML2atYl zeo^xhFt^-A%!$K5%J5xqKhG|eJH?@mA{|@-nP2-n{&=jvOo&6g!c!M*Ynai(YyIAM`+F0U zk@Qke1A~ET2%}x(LFDv-7R!_Dh8?o{Hp%J)OwR^p9{8bg>?vm|1A}mDNmP_Pf;dy}pJ$nM6;$rxIV@n<%G_`fH)gKz_|`p&JH_N$mFl zGeg(g2D}j+qp;{TZ$2`1S=36^y4{#U;xkLasW*PcgGrWpErghDuUbGcEom%&?WQ{N zEOZQ+GF<9%L;Qth?%*(*CjeCw|H*I%Um_M|-VwY$UQkewvHTV^otk8bkIgA2*YG2i z*2VDOP4XHIW-lu+O4yCgpJ{C|P!rk41L2u%mmj@q2CTT5juP;eS5{b-Bj9N!?5l}j z7RpVIGG=d5^z1!Q#Cv!%*$ltssQJrKKwR=z(;QH+F;g%x;PyH$)q(uYdm1ODwbk=H zk4J+Au*LSWr6Pse4gfe zACey8N*{UAYZ;zqX?<5L6sNg;oeN}8i+*xfIpBw;l0=KDfO}y`JUldytx`eDSpWzn<>=2|iP=f$_1&aEBoN2M zxD}=i{BCf_S(n{}(VM=rj{kmj$Wmoa=F#D49$5Xu~Z-_u)S8uSHMv6pP+xCHQDDn`&6E z1N{38l`sa_MqLmqZlWjKu=4|I{~9sD6yAG}@J&4z=q8<*a!uFkOw^hl2+}`7G2$MR z7;rkVYYS3iRgd`O)i!poUJPXc7WN`CL*oC-G0xsZ7BRpuMf`b#Y?be5`FG1lu?Yn)0~g=GJw`i_(w7C&_&<*RAa>r2L2vte8bgCyMML zDgw*xf#^H~g5}HagRkt!c$vgrIk8}^Heg_1p?QWqY?DejWd>JwXuMgnX&k zf|k-x)4(1c!Yt)KH z`g)9QzAtLlg#&|4Bz<1I_9bJAzGk!X=R39h++&)L4ua^3Cky?ay+7{nl?Cm@OXzNMx zYY(x1tv=nfmmd{SL!2Kj0KV`+^^OPFfyArL_GOd||I_gKJk7E4QX%X0#-0`u^ zgxBfvV?u_yI;Rebv%G{mP5SsONSG?SunQe<|G{+rS+C$}R4?Zxqks?*{Bi2u?wGz{ z%mKJ09Pj;&)uDtyneE@rYvx>e31}=yj&S(YEsBMm&u|S%?q#`deRw}z5BE#34?Io# z)x0>U<*Yf8?-Rw6z@T!QwX4EsemyS z|B*LInuVKaddwk{rrl6$8KLG(JgqbWUeWXcDw9(#IgmM)?Md>Kpm&aPZR%P{jZ8ZR z9eTI~)so$BU$}|xXOWkx_{1`H(KY<&XrF%h4OpI_X3B{Ko;nRs9#Bu~;@_^oZq0YK z-nHIk72ldbr>L_Lz$YzqDx=sVwCrk0xRu_GBz7G*g*_8+$~YiI{BKU7;UP>_Yl@sy zih;QON3n$c1`vUhNA~GZ4sz%9|lK@b9GCli^9;;ml z>9i3+j=0>kw%+lFi~r1xy!(DPRXbW&)cmoSla)=(a(>C*ialbn&243_5PLF|{EcG0 z%&FW`-<FrvqC#VkAE%QN zzex|`yK#q?}ubB?Y6w$nM>F3o_krx;1dX*f!4Knt&AOE3Hl; zj?i@^(>ksr=aJ+7Tyu8;#bdD$?hhy~EMMOh+wK^8FF22+iwS<^)^{$`1f7j%FQzL< zlObxYnpsbKz(B}|tm;YochhEAqohp_s5QK(h z{6h1HVBF8>3wovxk@9ur$`bG0EglrjnY$i<>3u}G)uSz1Ts#&6a@`txUx?usU; zv5$^$LyxHwq!o<>N!Aqg{@ZBx-v4mZ#NafV%@o@if4QUaX6EHt_UYs0(Es!izN{E5CaP-d(5Mi|+*wWAE zf)L(|eT$FWCY`j;gN~6ybmt9pxI1#5C?-(rJn^mKRvu3Lk?8ryz&;Of*yGU;Bq)H3 zmFi5e0@gAnU?Lmj48u5eMA4vW#MhOHbORTiSq?D_ufHEOfjF}8{?6VN2b-l(bLxI( zyb9VTH*o{(qkjLjr}3k$v{#FG1g~jqFRxCN8yNIVj}HlA`Hqo(EnvV8J#nop6u|PO zRVy?g!}9geWO@EO6XbWBwAklN^a?~B#Yi6OrSfjvIwZ4QB_Ot7*Gd|(%YY21Z(Sek zRI2RvvObfVCz%D2tVs=C$oe4%vNgJZ%nb01ueJ_$@4)yxEoFp?|I^Zg2KD8j*nKYQ zkkK{f^>D2o7F3}QMef$kwQ7tTCA_V1FrX z_=~^HM6AqQVl}5E4{hiv5N?X1zf78W@~OAl7749@8P!Z5?)uyeGM{_s809}EF9~xZ z`HExixsVHZ=Dd1@jD_jJ23##l-e*MJpebQ{GaJEKAf*vOvFUZO#P4z%OneH|&_OWvy#c0NnBfxnqpcfk)0>;oGW6+T4X?}5kwF{tS zOW|qGlTY4FCpN+{_sgBi=^p*2l#u|90bhNhjz?8d72M(OT&d94=nvJSXchAL2!B%? zL*MI?c3JNRGB>qAqImWkQ^EHX7WB=dhiw4I3&mAt=E}YJyo}XeYUUW9_Nwu?%Z@r%RUd;zloCt!t4h?oGyvy~ z`u$467-?xj^pc=#c)K08A)Gt=1EdT#f)=7IfItRblc@ai@bO|xY&nkLfD@R?l2OGX zE%+U9)9=Xf3qTSC6haAuLZ}-L$Te}WWS@-t3v~c@BAp;sQi7?=jXZPRt1p+!7|v%9 zv6SLjpsmlN-SLj^Pn{Xr0(c>eo7bfj2)Y)-TXiXzDz3mjofMGBE5MZeD|Lag+NR31 z5fMmwG)OGvttj%d&|twqH?qtL98(@YGI!aiXQ#CkrSP@({^WAx4gHsHUt>9IttI%- z_0a!&C4*jH$}*Pkz2C9?s$Q?#uS)rz?nH1cowZSr>q!57NN55^aD!ovRQqrE{|ACW zCmG2LCo^BvhizuAN^D8In5UZth9VAae8KHF-wFL|mG>>(EPmH>E~v6wUn56++2q>q z1F03I|0hq;_QsbXi0s7Gt#%Fd^a}0Br5M&?Rd9pg;a#9*UQ<(+2c?Hwod))xJ zE`EnGkmUhWqy8c>G+qroB|-3C_Fa)k!OoD{c;Vdx2X!MDqJZ`0N!!hv+xpce&vQTV z=SNJjtDvhFyORe#RpD;x-+1P=H;E;dpFMtlUgs7TrHV{ZtT4#4GQF&*p;Gzu(=^r{ z_2jHqx5Di$vO}3%?}*D_?(X}%MvS6vN6Pch+kYm^lp(*z!k?}yefip8Ovx2?72?<{ z*CV1>V@}VK5?GyB=lG&)hxILfB`gT{I#>?9C)6+&x-f8)G7IN$az$}<6*KlYu}poN}{alB2e70lU>kQ?RIn9 zgrKAn_c)aXspJt``2DlC(UR&3L-AndIf%*(w@+}6Ew_A?^GO4L>S<} zkr8hBbl?KSK5nSuwJ+;a=Qu26Q;-+tj4^amzIE&hmsa`?84V0cNBbyFjUM4|@~A0r z{kmn=;ho=OCii{d$gU0Z5>71Cht;X++5$T7r=NqscgAIOPbO{ku%xh07sK=6p(*;W zoVI&mn|jGR8LFG2j9Zm5Wc?NnB;Tn~UAc)4L0BCkE+g1pHr=20)?*Ee{AsXInJOdI zbZ}(NfTo7Y3%GP-|KuDA^fM^mSXu)gImu{^tNAJs)`y9GPN7iGG_6Z~w;5_DB+y;^ zp1>+%t>-=x-Vw=rb!KIR;;KYVNaJHr!uefH?lv~+x=zG%R+TH5#`hPRqGE~W`U(hk zRbVg#gMSX91R};_a*My42yJQ`hBRLSAJZ;A!=~%XFBZa7$TxIg%8>7X8qfFvpKo}U z>-FV!rljLRf!f=Yck*EE--Rh3U%AoE_ufv%theKmqkyK99vrF8wPq~=L#!?RmbnE( zcxJBYD}g8T7~^Z{5V-RGEFMY8JKL7k^43$Xx=!t`$c7@51m-?C|%od zgK9dYiFWozv?Pxgw-l?}qF_+vd}lAC%EQ6|oeZ5MMxEF>Q_S zJry%Z^|8}XhA+IH_E*1DLY$^&zu>|x`RkB0ztq-s8AvwqmAQ~E*jXU~RXD%djRy+Bd#E z*dK}Bbo4>8Jbde9ZyFdO{ocTg`$d7cR-hJtzg9yrZH6DS%FA}88FREfFh*La^+lV3 z7kBXEeeIQb@1$rLWH+kYAOAAKH@NqE2=$ci57q6dwG$fI2qSW0NHy@~SuX|jvmWP* zCIU*+#yU;lhNLUcMpsTb)^$n!;SyZa)L?RTDy`qcNQD;Gqw$Y;ze_I^ZclvqSvEl~ z&4XV3f7JqfJ%e{l=!vi1Ayd$N_z@ze;B6|vzkQ?y~ACDIdBQoU#3#0fW-Con zS3M;5pWS_Fb@P=7M(D@AgyY0ou0w;7cUyZsimTy@JUaJ)9Z=6)(Yp*oOq%C#7D2=s za&F-=kgs4>Fp0(u2v4RQV`o@B^@f=GfHu&CUs&N8+whcvpq;z>ZN z#TOEcNBEcP@lJ{zRx(rA?={KSI$|S~rU2DfL-;K*hDOEaysr0TIl8&QH=6S|?PJKd zZgNgF1`5?x?{^D?h-*)&3q)XuS&q4*-a&Y%Y)Kr|pv~T@kn5~5m$T4BAT~1iWU=yC zIad3S3Ar5ZS9We&yA6lGyX(MqEnF6ZtG{Pw6KDlpZJ2L<@e}UFVD9rnSB}>+i&oN( z-c}#$+%z5^Z)`T&&gMy1gvRuOT-ZJkBGWgtk`}OivTs3k{#A3v<+T#mqaH#nSso7@ z_QR!xZs!oi(W*H6n^SUM6IjT}rDZ2a7($#n7e2MpkHXACAD_);C*&KBo^aNj~vt)1#Hq)@X%=4#^LDl3g(n z&5f3cyD}V~c~X9#)RY4OwX9%Wg<34nvDZD4aKK2$+T{nr+tpmBmoZW7``U4}lJg1j zcON#Gp```ffY>%W*nwmu*+p%-a`u%yAC^LFeZ2$wYddr_cI$DjE~hWtp4|};=klqi z6UP~mxA7H&8I@%K@4BZ9$v!w(u(Y*yI(t5OVjZ}Mpd9Y}2%)yw)j3Uhcze@>(p3y1#g~ajWtvZqVtP`8Jn4JWpR>4* zpSNGRl&!QAuYk+IEc~8{_+D0UzV7Da`Z`5+_7Jkh*#@0K;0{zMhQwNk4|*Aorx}}D zo}jqGa$7##G@NJ<_r%jom(hT@5w z7HaiOt={@JnMW#ti?adSub{AfBQ&3x<70pM4MV@90o3CpH}B5n*3?+ZNVsHp19iTgd#M(l^Ud*lu-_uKo|0Ez=asDcD?h;d1ZAS6wq@R)TpW?nw><8heaDmbifgn;tKyb1MU^k|G969hXdpT7KW8 zirL3Qe16qBb#g?R@xprP{f`Qn22L$2o*7rD<%JQ30?E5m+49|f!o|f!mro4#C*u#? zls`DqdiOltFi_k4;gjG+^!6h+YLRD0Q-ONs2j}-U9}P-;*Nj?0R$}a44D{wDSH||6 zIvG5n3dSLh<)592bW+h*A^UQJ(Wi4xlg#@p&{%wUerxtZPfnuMcwK2dr$bkt)B5QE z-tMtv-W^6MmV>Io+3?F(AsM)9L-WZ$JNMl?)PQb%zjxl~HpYh~`!4&-<+j8~5rmG! z8fUUm{hA}xGa&lFMIH>w!dH~BO7yK`g`~$yufC0}fY+UEMOTy^maswBWJ;gsEElj& zSC2HWuDe)Q^&T$Q7MRxQC#L4=_oIOJyL$m*G0{$YC8BM75vRZ*jmU#n8aWdlyae7>3Wn%7-Nr(hI8(=p zyA&ks=^tYs_3t^axOyzkFLp$-BcAX=Ee|ODrL|y=sv?RRc^)PsuN!TRo4l!Rt68}i zjZ{zOX_8qVe7ZMON>Im15#r&6iz0~VSu{2zB#~&jov)nt+#y(+de!(Eq|<*ALj3S( zy*UmalU2EL@srg2Vl;f{Gp!mXsv;%Tix(4hkWu?M1`Ab@o+fDrtjn+-*!`~nSAUlG zeh33b|CCWs8cfw%s36H`F@6RRH9e{;JJEp?No1OjgMD6Tp?1tB=N>foJrN3xH|ci{ zg@~>4zE<+U5W@25^GNWvR-5!F_VpiM-h6?F8dhv_;Ap2cX57UVVPTFKP7%2O<}(_MQ0A?Mv(M}1H2|5R&WkBP8=`33fpBrF6E z8LXp1J!)Yl%73|RzWdC=4pQC*yiU5_Bp37O4FJ^s#LBO;;K*A%Dea^ns^duR9RLdyME>C) zT3^EFs@$I&-;ebzBXi}(*1P+rHsKJCv{!w2@!BS%o*AqBl}1}bmKrbI7Ct#IutYsQ zCxMLiNQoh%GA}q%uBqMvX33ITv*z8kK3;w~0wXk5cE>f~Hz{%OlU8zK*1%y8&dI&W z&DMj>?af5==6VrM^FwR0{g*Di(|@%_cZ}uMpMW@`d%dpw#n?=A*9YJV+rdN&m_$U3 z(z;T~>66dg*?59yKbWq=9W3}r9Q0iS-b23Iy}+}HFja-cc*V)J^t8Kpos43l0t?=+G0))vR z9rJ&?6Lcwren0;>Z={&(uDdJa>vHg|S=Gz- zi4rk24g$E0rqllFHLIVVyrjK^jF$l6G%eE6)l`{4_p_~CH~nEQ7xi*55S#J7z5;eQ z@<)n(`?wL)~@AoV)q_ueMT7^6J zv>hNniV&hy!-3&isv19GS&U@ur;O8b)|j<>c_7YF(a=+XA(l$^IKv_0f(Q*VEy$N9 zfxjpd3o*0kOsrFDS$jUxLeI^yu1R{C!|)cQ^KxXAh=05KtUbqwXvJY>S3qa|5lLsQ z7H}i`G;T3>&|91BcLS0R>d}7+NQ=m#kFA6MCK0?}0YIzQoOMM<5^E;2k>QN;bT9qu zV5h-OB^%iQU`1|WqQ>QKw%!uC&)D^UVHqr z_B6ozomxc!;Ol)Tbm?fF)Yd8LK_H{!UhYZo^I6AEHb`1fW-A9o{hlv>3q68-gY)O~ z!=cdeQhW0>BZ$;#(&u5MT#2GfmM5Ot2Y4$+=+M0^MwsK_XSY6s+oj**H9lP9%Td9) zAi@~XMA(cJuLdB(?u(x<;6o4Byl=aCb%;j4Nk#SI&tV`lS^I6@V=cdg)}8e2m0HTv zj=9bpR+q-+?bd$=eh1nBhhj7Y7U0AaQ5?ej>{@u7i7e!V)H z47&wKsSkURB8OVBFuayVOSWdyixBv$Qjly)$8TP6R16a2YHy)Xqwm{ZK#S)Y*s%~w zE-A7l)PWWa6|bL6eG$#0tlD?CTmF#X;<&@5^{Ir6h6qXLc3%X$6T5CB{fj_7yVdc| zk`m;r?>YB42nuzl7_b2>&5jld9xne!dmAePhpegBm&9GioO6%sbuI}v9cIWfR= z$9N-$D(79yR(C%(dhxX~=O%i|Fch8me6AsaSk_dyp(ejL!{c2}J{6S$(EX#}wP zmgj%yZ59r~DTvYdCnISej>GD0YMajAMDOf_*k)Bop|n!rL3paX&tYY%xn1|d7h@;D zOgzjerHsKuxu#@~et;vtFReP?h9RuEM6AWYGF$W1v3=nzpBgd^7GJU5lT?D85G0#p zi1VL6XM=b5vaY#iwcPraLJuUB6$+K&ap{kEKAC7mXR|*3T|x(k|1=k9YSI#A(ql+= zljevXJWX9Dk2Zj0?T#pT9s^MT*g)~KCUIj&h9-J>O*tI_y9=(S6V27A4=XHz9?7zRfmn{r-nu6+-PV1)l@IH!l2l0k4X8W;l$Cu>Pa+Y? z@qDzb_h9VTF$4QTIxASrKH7;Ssnr55T$~&NLEsnYT2&-&FWYP(5&OD2sVS!lA7t|N z>9WKf%kw86YHb8=dPM0|k7u~v zh3$91f60?H!Wc!7>vlob@&K}y=!*t9Ftki5;&RMT3-c2hqMSd_0vzdn+mHuMQmaAj zxmgbRukH<-jJ9>17vyA|*6)1&p2P`Ilb53lR}SzB5j)($5b=453v)3C_w;idenb};BA8u1c6jnm%Xabl1M`ulDC&i3j@T9&9dxW+ zK=60K{m-lY0enGVV+p#mng~AVXn57#s}Mi#WHr(g=c2t7piNVZ3C;+(ICQpx^neQ0 z>9=UNUCmK{L9gg?Kz3DefRgyabj0x?5ph3PFoB-lA=deBTkJRb)58pCLSzIL?n(0Jhm zd~R{6Sb_wJIPQA-%SY60RJpHN)hnAA`Wdoj{S*+zQDJ9a-h+$r1}1~LfNxgeEuaEK z6+4{=;hV1nD|eES`H`%%R`&JrIog#$TpZBP60v?>Z9|FDEEb`YQ$!`lwU73iNJzFv z)m&Hw@{KB+(};jVYv%f`KZEr|fsD_;AP&ksWqSnGc!6VJ2>y(&tU`E1M^VTjV}khV zz%Kgyz;=GDeynp5CwhT65k!r&=%_KpNT2sRpcFqk)JN_Ek31O`B$zS>p<@KKGX8o>8aw~yT`|^8X-x8!LL{;29!IQ>uPe1^KAZ&y8FllK+m+Yroon$1Hjn7y`SNM_lG)KPfF)@?91C?|eWwo# zz<@`04KRRbxLN-P3;^Wy2n0jCrRB+a-b0IcX=C~(L9}13daBAxe&%6!B8Wm<&*@O* zLB6c96AunGxq(csUqp)>(8I}uYjlds+05wZl9(m?>3}8QB3MDsrdCo2Y(Vx z_=#F+NMC_c?>@D00Dnue>S&x}pkD00Y+@^tLFYgvtgrhh0c` z_y?LKJ`u6HX^MUH$y);Ka;myu>RAA)1jV;2Dr1<{Q!*690Q67BI`5820Y!{S%m zgctHnrd{zPu0e+*scXHD8){>^`L}Z}J${7~%;tMiV~akd{DjN=Sg6J6yLJNLkd!3r z0l<2=hWa0e^tTwp5g?c=fk*7xKfv~?1RO>0&Swn|3gF@`)=ck%4f*fw0e($=TK-#t z^@mM-?`Wg#V2kjt6t%)G>=-ht$=6`M4g^DUJ7Xj385o9RLciq&hjXLSr-Oh-*Ys&< zsKXH15qmd7Ama5B4H6y57eBJt{!bNyh?58b_g?`k{xsx;bEPht+M9Y9@C+x;|A-Hu zm`oqzqMh0WEA0=H-ML|^z?#~$?nUh-$6A(zpDW9ymE%YXs13UnbE~yF#y9*vR!%1s zS?RyF`U{l{lmM2Um#G^BOr;j@Y3n7ZuQ%MClN1UId6XXrOp1RXsWf@Jfp=3q^eai; zG%z0pY<74e6r&y}CGuYpi5=38LUt_>V z4!P{*x_kZm>~XIb--uvCcI~e}f*$)ViZnmwO?O8_Ex&wd*7&nCUDS$pq1E;Grtz+g zlivP20R-dW{^cGoo>{W@A8=Ad0&&Di8ysgLYRC;qwH)m#2Dk>7EDFM zNFc+=_RS~EuMDrUC6t$$Q)LO7bB9~^Vk1uOs>$2#i-bANBm!Ofn~gY8nV5**!u%`F zQATBI(*42UT@bF=7jY~eN@#RYbFg0NjR(Kgc%iY`U{(2#bFNWea(9{@|nZ!&3O~oDjxS89 zY7J?$pA>Hmxi(u^l`6u${uQj2&LaA{+^IJ*iOO{Q+~Se$w!yqr?eWAVP%xtwNdf@9 z`dFOqA2w?;LFT_v(@%mA8XD)c#1aYAZ>^3U^y1c!o$TIs#{&?lF!e6`3Yr;I+C?Xi z0I;w>2LQl!mJs1iFwloVbrGXsrn2Zn@fKJ-$LnFIr`=tYzKBa7fw=T; zX;M4AXWedOO-9&*luFlpy=y-gT3|Rl=1ny`>9SE}`&0?S< zsmeT*1Nfp3Kfkv-;R6<45{6)zNvgrr%L|f&wLf9=u$%ho?catQQHs~ypyXpf`uR9B z2S)ut(9Y{zMm1#e^zP^U87>nYL0$(VpQi~`DaIqB&(k@xELn(<_eHS-`n^9=j&GgS zM@Pg-2m&=R!|+$&hSFqV0v`YYjX~zmeh1LTKPhf&#MRa}bwul=qAD-6O%!O`Cm1?u zdHz6Jvc06ww9Z;l`M7-Nv!)f=UHvN}&6Y?6DW!j$dpOQy^}lKXfII`coW<^V^7i=2 z-KjytE{ummqAl+@O&h#v>rGN^oLsJtO`jYG%I?fT%wbAe;}y=kt2XoB69{MkEWtr2 z&E|DyT_(O)bT2t4?n-aP{it_tU~zWJ@{&w=(594=ivvEWNK+o{!vw0RtN$ur*A5^O z0#2ZbdFecE&i8zY){Qr!z@RCC-p_F47P;j!SF6GJ`%I6b#1qz6#=lRh7|MRkz=L>4 zB^D0Sq*%Kr2tsGZZJ=AEm8c4S)|^|GCfO3r*g?ZF4Xj{J=v0 z#q;0J^Uouco9tnT=vSF6otmw&pQ2({T!te<))O5879`V&!~)d6!t-8IuxN!xEZzWr zy%*;9`vW0FP(XNZX{WHC^ga|YJJaAJ5#`@r7+~I(q=UR@1Ih4C7@z{aK8#wAy}@3I zD))i4LSVXeI!e`gMBc)^C7+&Bz9m^-(h(kue&wzN{^tMjme%%m%Xcv_77iWabA1-fN5}Q$%FXnE6dfXQ)tud;32t zoI<|nGaOVx#0H)jri$VgBDoEtU2|P0mRickw+!&NgtO4Vgq^Pz3T49jZde5o6DqK$ z0!V((SL=s*0u1+UQ(qf(CP?Y`FgCQeiDPxZQ9|~mH<$DYr{Clrt8bK3-n=ZbP8$|- z2`w>qq#30Ee0}I1tqLs81KFe|G>`@a(7)oJrx?gdm%CECEpp2Ork+fZzVw2V@E`SM zPqrdF^2{24a1$P@S&(&}i`{BF3_ud=bq5-xky;s09k_t{g$GN0y$jf;8V+8Xw!hAL z5}g;=Q;Lq!DMTO?|3S0$QbMX^)+g7zm2no4aCmdI>0K0xM(DiFRXpZdT&iwNzmoQC z5QV3fY7x8cGink3=s59GywPYZH)iBCf%ku*g}^f8u3<>SY{=PZAyo%e$0`cM!UJ!d z@XfM;)^L7uYcZlXqOkGzf#rIk;-1zB@|Y6un9EDX%czTl&LvO@7ZgoAV~Wi%Rb}S>6x%s zWNoBxK7Tzevxo{IlAX$L@?NrogGQU_^);muy{KhZ>gaGd*l6q8xyt4N?@7XD4ZJiq zI=j9bGPR-MkNBP`066`j7KsjmK~3HIHUv6NUG$c_*7J8n0k|JG{-fLiyd|kf*33s- z?U2`pYoHKt(zObwxo^yO5k7X`V?VoWZ)O&d_mBN-ul}9NBSdxK3VIH~*VvM2Jt&;M zwpqJ*yctKwyqLf&{}RJU)rqMpvSJ)4J*+#Y?Ojkk2I5&vPw}sG6EMxst<>>B5z-$Wj^_J8*+QS@eoem)wMrbR%*G*+{vKM^+3mjix&D>Q3?3{2TXKv zPD%J@M@?TEX*-&%LgL7wpM?z!J^)-6HsCjPlA+7b{$e!fg-ial41`dOUH^$P7W_mM z2lXS6@Je3{fkYTm^uxi!u}{lG`Oh7Ce$yX-I>te1M|ik6|6t*XO|u97{Zs?CZ@Y$d zA~C*t{G^bbezJb!ILuJKV9=}SD7gA|@XvC9vH4-Lr{}M1?|&+DrZLMODcaJKIQQgG zMi+q1<+Fk{X2;iI0*vDRexfwZ9y7{9^%spSD8qR7(T)j!Eb!Bs^jN>%zFUwW*-V&8 zjn%ODCa62SbNpHU*>t9wzR-ru%`Lmf-u4&>Ez+yYS$w9R?oZ@5T+83yXmbT#+8N|@ z|HG&Z{K0M&!4QpAhYO)!_6g2pjueT-?*u9;hy@^J_=Oa2|6DGNx1T;P z$x3s<+=&~i*NSV1CCSa*F#^j0-fVvNv;Go_;0!?(tbe~@*E~R3cdYQFK>xd1D{m)0 zD$tog)9btigZuFJd$}P`jsgK-NvbbMMeKdeIo#{7tIIvcHx~ZQ%_w@ReWjkJDp*aL~Fw{%tN^YH9gbPsNvN$!T#YJ}5z8&1aInaQxP;N{5U2l5Tjy zRHFuG*yUdbIH-NDF0G}k`0jBtSdGR~(9yRff43-RXa|F8)lZRebnjL=x@x1LD0iQ~ z7-KEc5{|>%=Lu&3GX{DXUl6$8oq2Z2_okwCoDfX;h7)QdzxOZq-nt+_ zk_Yvk-g@{4M_)jR6wvh~q@zEf8!&^1y|3Rt6ZAF>JjTSW0N145I1+>!HF>Ihu@jSB zSu3r6$`sY9gp8K}wIT~?$j-|TA)St&NI0y_aTw@$A(F>SQQA(T&8fb3(}&J`KA|j| zsgpz-1m~i1b2_W;sHWRg0toj7_V`{y#N2}#WFXZ^lTh2i z1hsHIl?nP!f)tw&_Z@AWvdJmsUqzLsJmVj15%0Ry#}c&n^6Nhp;0d}9FfBjAHb4*H zkiZ;f2iIM`1MIdu3R(xV`!~_{gnKIB^AkSoZ!_y6zI( zGk!{aFiSO^2F9!L4!<)2ta}7Kba<#Wgk?3RbXiL#xUs{$Hc(jhB8fqLkPlly{yL&$`;{Q0%x7QeRk(yZ~B^Kb_7G|!6_^JGE zvV9Z7P6C>W6OjsXWYos$tYdCWxgJTnc=R+{?;3NFWNDDMcSHOg8iRT8W&|0#(uk zBX;6CNLaBadDTZ`Tu@?KWB`+DC>gv0VDFyua2R+}?9jyk{J(%x-?^F2julTLhVB1H z*dkVXM%*eD7jjY_AKbeEKZ5)xw2B`qo4 z@SU4;?m6E3IrqMQzkd!dISS8S&suYiIp!E^Y6^8f)H*jrfBFg&N;E))#eG@NVRL_? zWg6$PDBP>@_<^nB$Eh?_KayPGWzY0CU9n}l_PRR<4`3H}J;cs3+$=b zF*_AtVE@|i{Wj0)kS;po{2D2u(_`@TBZo7-SnZx3d=zgB3pdSrc!*wbBXqtk!a-qr zQnuF^BqIny{OH^lf0kF`?Qnh{6My&)0%oy;{Y2S$yh%+W>K#WQV?6D%RG9l(#OaI&H+8IpZ_cJZ@voG2CwG_BMKak5>-WJj<=uGy$f^YAa;issmEJnLtgF7>Lf6~wI`_DZ zNFUX?B|=p(L+KFGze1Q@TN}`k+i!Q!!}e{xDNz0MbFWgboxKDV zVmzV=X^lFZeJ^!9!-=aUJ;S;RiH?P5cpA_IG5g?6|j5lW6 zzWx&g%I7DqDI3W8otfW4Xd%`uunf&Vo|lUzgc}au9yQUiR_z7*u0XefsU%tGg4>K0 zxpaF24K#0*Ib8Fh2c(VA&^)?8z}oVyr~GH%#W*d=skP z1&C?N8e$)EGT#=!x#=I2Pg(L~oSe$}(XiAo$orv-7_DA8g>Wg?j(=-FR3 zWwYZMAB62XlrA&W=wVtff*{QOH^8m>8;Q_{hZYl;P|#8q%d(QD>cDr6b@Zd5s>S*x z>*cjRI?rnB@vxFrcrLXJnVJ(VHXek3@AZkg0w0Ury<=_1@Pq<3TPLxIMOPeNc_N-E z7J35i=>OWd3gWX1G|&s|*ttmIb^4~3M2AIQ|Cd9hB%kIN84we0+4V*eBJLY#Od+B2 ziyHdwhlSFADI8@y07~eaO}734T&x>~*m-jM>n7=-#(z01N{7TdtZR*&rW^_#?>eH#Wqf z$Sa`n*77Vva8eHAeV#O&lX1dGl3%*$SrIn7?z+X_{zQuwt3G3?au69n+VU+R<|JKt zd%(*9O7(7Fxc{ry;5P{hY!Yckpa+<-&6Q(>$&e3NMu!gW{E{+=8>pXE!4pn}s;x1z zJDd7Hs3d3*03G+a;q6$1Mdop$5xb+k7WO;+NTHJDLK8wNqr6nFONl9C*&QUqRI>zStqu` zNs12sGmqL=Z^G;G&R$lr160P$d=SVEA9D4#IQ|>MN{hagv{Q%R>#-PYWfT`JV}0ZQ z!3w&Rsqz*D#Zc;B*Kx+k1ilVDzX5wq&AB}qnv_}jcT#M-6KNgrP~5_W$gxbM%_({J z((7=k-j%7gpfCrz{lX(sV={JqylD_Nf9poH1ofY2#_MyBcqf?Vaeth=QVgRD*))5| z)|^Sd{Qv}p!ra4$WhWvt7p$d-KYCmCCF#a#AI_u*LGE?A>~vAsJN$a7*PXFZTr_pf z8F^{E=k=9^T&}9`E`M@Lg%lo)A?AN4ElYm~EdgD4z+QYh&ayRog7o;QLR&7IrCQZ5 z-}#AQp>8->u7hI?Q!Ym}G$Zs?Q4DX+EQ|HdNbq0yWJYPdoil8m;c_-P*T1V0cn#R(5L^RVst%IsDzUtfqdge#b3Mt ziS$xbHJ_u@#(607bXKgYa?eAMm%s=I{^%I=V)b2@>x~%=reFqP&^w1x?BoQwc=OW| zT2DY3Cj5YTeyUOp_+GOwZW?z#G<@ZoK!$;#M~6IQE^{OsqlINL)Z_UwD|u9b0aIIU>kwBaq3zZ+zj3j? zUEH`+)W(87V|%FJ$2%PUh8SC-93Q03;~BCpu2mt|&zAo?nJ^=jUC+%vL&i2aQHupz z+-)@5j2w6UxS8sWImir{jN%p;ApOG9a$uV5$kuVsXrr)y4^FacK~WR~e0h@}+XpLn z4DMCYuIUR|_g`X>PYt`p!;2NN9k8V0C(9lo9T&xT0K>0C)lNp<{j=P*Yss)o@;{s* zNmM~{^(x8p?>wD_DBhZLBF1Y_wU7Gy`$oT5ZzL7gP2>l2ObU1)#_xTp<|)HXJ`mbC zHNJ~0Ls&;F?N;+5h!i@@_x9pJt&dO6oyyU^l;)We#ZlP4X_yGz(4^lO4NS}Wk8Wr% z9^3Z~@GzG2zZ$Rr{k{F{-9-1w#XFE4{<|ly3lUJFLl(EEk@M=vmB$t=iP%`xP*5B3 zEPs3K2UaQL;Tr5#qMG+(a3NBzxf$Y1pS<7fXDZfr4o+t&l<~WLTSM+HySs}}TS~Gv zEE?BciV3(#hR-Ja{)7S^DpdI0^+?T%d{dn*9$VHMay~`2dj4AmH}J-4Cho>Ha!M9j zehaHV_^FiCSNU+SVZ~H7=^(W4^`2uC>miE5`Nf2bgoT&H^8TIyMRl-f8Iv=!YNUye zblOj8MEvVfJ3$d+mbHYN*x76Jg0juG8!idmPhZ2yBbchj!et(gv7pJkGnQ~qaq3dn zw;y~Lm^B&MceCT0Oy|CYS1W6w?55Wppp+t(ZqJT&6b=w*CHc@E1+qTDho@>NPGOp5 zU$d?rcM&q(;fVZUB4WV``{+WT$TeZh$~4DEZE0p+C;BoV;dRYTGRhEK6rM4TPS@SK z2~$_XcZyCR*?HP=qE)j<0;(foHgS?#nw#=sg{6g=6h}g=%HEPGdoY6M2zZ*$CMGhlM+?YD+y%v=MSD4*;%y(U8da? zsI&Yi`aEEM{-X+oGoA1TJ%SXcDkqw4qW!Fbfz%5}w)L=#&YNnTdk%Fo&hLY^?U8+Y zcj`1$ooUc<$Qt!O$by4vK`d?JF<#c)H4Y3_u=qS6-ho5QT-JN^c7gY_x?9V1$x*6;|fZHJtq~l>CZv;lMu)XXmwpZ z!ei?rlBc7XLr6vriL7wAT3L?L=UfYEI7yx9tX_d_SS(`F`f-MKNPo?Gsy_JX=@%S@ zBp2-pZ7yMb!l(to*-;_|-~0C-t*%Y=Ual`G22910pv+bBWV(vOHdY19_f@sJ+8mw1 zaCqW>7!JQHA%uQO6GH;u$C40~!9RTL!rXoSiwCd#Sz#J`3Ee88OPoyegyb_%e(GPe zlsIpze0m@wh}v$;Q%wvSe0=nFH^j&r&9fI(&gcnyswh|fh@;i%723|eCAoQU3L$hZ zq`SG{B)eyTtv>kvA5PJqB|tD7e_qFhP{&g3X$!ZnTuA33BOJJR*9n=&W$(TA=)dtIx+w8NDzXH67zP}phE~PMOMqS&R z&Ty?12PeXS*yx@3TkH>)!8NGpbjf%6{Pw~v$%jXFi1)KfR7odi^A;uvy$p<*aEeux zKP-FRqh7>ClMsC!s9E~TwkO)?B$$T zXh?G(f0tjpGMe@5X$r+ioG{VQg7xk@cacGqcZ%c9JqqvWIRy}}|7D&2sRg}qZ{B4U zLoia$Mk`Q5EWFtmL?tNJLX;-c*>v;lX<|QCafJ)MYaUuCU>Iasq<9&{S-|^{`W$Ix z9w(@h7dRZNqup^WxLF&y|1u^?k;|m{l1$DYUXZ2P$Qz}14=x^*T4pNeN>*BNoZobt zS!Dj+B~@lJ{|h{b_gFxF_Gp8gLS$p$_TsVKlq~=eMxu@ZHY!FAYb1h3b9pui?g@&B zfLPs?f zHOS&>G3p77xZF2}A7R6tN@zG8-uG|Hq^Vq{M69qM!!N!{pyEeHF$Q_^OA0!**AG0e zJlI&J1Dje$;#<1GNbhAPijN`*ak^y-K6r;-V|}?&y;z<+!U-b@_x2i-pWcGbOwmWyoAzpKlV zEWY$b=Mxmgxue*mVVN>izl4NCPQAZzF0;J9q{syv%nFiT5P`aB3(ZTF!MxotYa^ zX-I1anQAkgK;jB_RFrz_6Dol4=@`{P*Bd}Pe_H8&>t+15$yX3*)rV0yo_5iBj^d(u zHL7GewHQfA#jZOubVK0Cu)>k~%S;hM4}9i>)-pvN#N;qy(hy5J=>)3K?8kVlpyiL~ zk5{4W>x*Z)PKAhgtQbp1fk>^oJONZ0IDq~$oPw{;x&bVrXW6PR%oB62X;r%q_>9|~ zmU>Ny=>7_$$3Tshqp=$Tecb}ls#~WKoOCbsnIX_>UJ52WjWCPWl+pWk;6_|2x|cLX zpR0en^w`Gj0yb{1+SW3lbE^2#XT*S2@PfxUZVg+cu1x+*3-Fst@TV#m^|I?J{pLZ| zwf!_-dC{o1(aIh)g8!Yhg6ypS;4CE(g2B8oRKUmb3n<ne@ukH@N zyvx5<3zE{A**j$wpcDK{=6Gj$0@RLwT@rv1gnk!IL4;A%{Hby)S-w+*QMn0u<*nDl z8XS74-M|F{oVsdg)o<6D=)YTovW~wJJBEjdJ{y=@si3c*2N6fS$;&R_xUy-~cD`U~ z!BXbh|K1HyDCOtZ5#pkQ#yYxU-*%M{xR@UX#26X$QA(;A@gEcb!G6R-ebX0XmH283 zRtYIjo>C%^r0{9|!WajLmQbeyv7UlHLXK<#)&NWrBf?vXu`OM9z1(mN7l6rjkjmXG zhkx>4JnuOt(d{P|+A7&=CDwokosG7|)*8f!wPT>o&TvO+Xft@Jc5n1uT%(WK{ju%m zdLu`bXHvpJ1!J<=c1&aZrqB7$QkNv7_jpy1(|A@n3)1YnTLb18jaR|9|Ght;(mh8x zOfr@PH=s_dO{=Aa$Lx&UV!ut>Y{KUvyajZde0O%)r42@MFY)>2c2SWsocdR9Yo;!0 z0JY|gvBMn8Zbly(SDZ=?>A&j%oh5$W{3DDJtnpm4% z>toDsx5moid=9QB*3pXsO?Us*iNT36BE;acdyoEIMIz}z=*~mAi2e0B=;8J-W_jlt z%wwtFYfW8RBdql5>v%^DeSVIQRAu@;5an!Uj^+A@u!vtk-{~@9S{Z}oW>mQQTEHA1 zv5*XjB0j%=4z3JM$3)IlQ{lX+3#`3m=?8>T3!C|v_h*^IUJSh4|0~?xB1QWh+qTW? z5>P%W!pkJurC34VEvH#$zWyB0EPA;U6jd|yf^&n91oeHc6oP;t+Vc@bec-#509V*JEt^!!_q zvWmT>(q@n||8>!fG42mYh~)i^)R?l*W%6?()Nqw6r`bI}1cyYdh*TLplx^{8CPxT8 zO;n;yKSU*~nvwmOkEO-0pUOXxPN57hQTlJ~6oR}=#0oUz<+iP-iM9(c8uHP{zI%8; zDM@jd-~KLGPSBx)X!@0vqFHfEL zxJH8h^O_N-v%;N-dwdjn2xYuV)`rge{GaHxbHJs$^wVY+T#JAis7Tg$QuKs5mCwf74rX>`_g~mDB5ns7f{Xaoh_LhDm^SFoyw82^qw#er zgCd<=306noKWoB&NDlU>#c!8pBCfhvTs1$uYN5JEH`JA(C5L2l-wC(B2(+)}jrtV` zX=|KGfjH>N*RS|ZUt&1XYG3-JxEoEyiImRiRD=N*ku^%C#M2-^+SGGrO*$+`V>-w>{s*R7AJW@+wKAgGEPUxxw%9*TmS({P>BdQOhJlummYCVz=rV9|4fd}v9N?4BP>b!Uq`A%0yQK& zj=e0kMv$nsvR^0|EC}T_>$D-Q6vzKclM{>xH>2%+S^jY8Culb0@?CP_wRs$CW%0tb z(0TEt{spT{$}<>pb0XJYuWo-INkb!%FdCXmmhSfPk=~ zuYumN8hmAwiavrgu=20-X24;t+2MvOhi`sW`Rl0!z1uYlcBgAoVI@C>dgcIlE-={z z{xda+d*>Fo;#te|8FHx6Oy@lgSt4z`{Ro;Ds&~dO&I1D|!wG^Y0g#D?S zw!y=8?D_CYxksSwt!WEzQ*ip@-k;~{VooGoubWql`THs=Kc45O;7QB>J|4i=m#Jf< z!d!7Yg_zCZeg+TnPx^fvS~We*Q5C$TwaBj zprS_;4g|Q`C4PUnaf(FrG$Q_H}ee-_8^2!4|rR4Tbnlze-0KW9vPXKoR<#vIZ5-T&5o+;aHQZ4J0{rpsz$4Ct|Jts zt$vE$hI&F307w+(YOl8#&rI|6&(rMMe5z>A@BKJV2L^Uff!UJPvKw)O*j@b@*p_L ze4t1^qNAuwa#sDMU0awwohJGI#ey0j2)+L_O8)cvyM<7^H(KSdd3%+(--y=D6l9_) z?%GSrKo$QNo67+<+*egfD5um=(|UThO+s!9bJv=R`PIE%ksBjhQqfAZ!>D9l<2snw zGMtZ5ULHTF&*4kw%Y)^SjhX9Ps*=AVl2~@ESW>P($bu7K`?nU*jj;M3LD}r;1r?C4 z8rvn8w=Hp`4qL~^ROMt2e`$PRkFn4N=Vzxv&Py+Kaf8s4nHSh{Ox>{}-eDw6kuK6C z@1H#uHCjfmkfDuSmKq5z(2QBKophbSe|!`jxV%kW$e#D-qpJGo#oe^Nd_l_kq@&|a zrC-yMvM+}mFe?iB-#J$(8LPWsip=K^vQs8tE^Yg z?b7eB<=HQ!bVPQHo6qtd`P%q!3sWN2W$B#~N8e!_S+S#ZD%BCERSkye>ZYu(xyMa8&B3NveQX z>$N8ok*#0nlZ<){tcAt>Rf+$+e^Zf(x1{K#5qq^Qj3oeR|)}VOv z!}p_5OaJf|kz$9W@n0`f1CYR*Z55-R3$KAlt+4D;8B)&QLglW*R}h7!`gvg@A_7_}1FuW3n$Rvfjweo^NSZl$-l zS7|^2!?RNw4VUc^GZG10K`6faLL;t@ani>~K^{aNmI+)pApR`sj|}st6(IF4Mmul` zgIcQp_P;~ue?VqwAq}y*N1ED|r{yb}aTif%`PfQkt)!9b+(nOH%%A<2JlGt|yRTuXCn7 zrBP1H=McrkITlm;QZ_F2Q1L8TXA40`^`(_ZB!FJg>g+&1%#DN4Bj?Z4x&j^c-J-Nh z8>;N$Z1W?umBzrKNDz@&?n83=(|&{}A_P4YTlg9OEsLZf6rB$Uk;cxOQF7j?;NH9M z-nZlpF=(jw)?L8LeBU=uNBx#lpsvx z_=^59rnD%19u^&+J&<;}mz=u#VL|YjYgLKG)Tt$luN?5Of7SSzT_6YDbyZj7f?uef zmv!j@&TaKo1_>R6qHoVxgBRkymvwxGCj7Gdu=n&`y*l)8pI&s2MUcN$!{5;sHv?&iG}D+AhlzXEWS z(2^U((mY!E1U8M5KmzN9TS&H#x}s{87>vWX4h^>drzQO_ceK(HVc6WIPzs*;1Xjzj zrg~f5oh+7~w|amhTsCeoLnUhUVYrJM@w=oHWCuJ$+X~!2RkUYh;wmS&{;>UnakPl` zmBz|;jRpK84x$#)tWjcDz2Z*$6 zZ(NGG5*zcq_|C+=rSFaIE|^G}pO_8Yo_b#8-VTs|1#j8{AW~*8Vk4f(RUj`^MeULq zjNb2+hsS}#A&}<_myw)BEJiVO{&{1D1Midbci=#neh+x^@3GmE;H;TBPgt=9ejAC}; zkIS`^?2Cj(F5-fwh&|oLcF7Ry%1v{6Jntg7BZw}L#CFIDUX#u%O)!c74n?8dcZcw3 zTmeyaU7G~@C`yaa^1C^sk9=Nij4ynY23~)DckN|6%rX6b(;3ctHjRr+5`ui|q9z0E zwCiQ~4>0OX?yH%RPiW+Bby(UdN>MV3Q7TEdVcc73lS%@5TZATiWN^`L$Ra51+7{`- z!hBWWbW$eJgZ&7)FTy1?*iE?12SlfqfuqCR8S$@sS^z%%+3i*W143?gk~Kwf2)6O` zW`5%4f@#sZHvU!UM5f&%^g00*iPnz6HAs>)3|_<-?aMlBp8uj*S^7h>^5P-pq8q-|iy$Pk;q)FApia73Wc-`L5B(^)RYa znO|nk*4ziq)QW;jMKLH?m98C)!zWSo5ETOdjO>RRlPp{|xU@>iVkF6|MtLb}?Y3<@ zA-v|#B~UUhB09TBJ_Nmmyx;D4s^Iui8#3fM&#Ks~I;=VKLh*e4o<_Jq?`vNbyIis!G zWdDODO{n~&&K?ACBAUp)4|jm!-#|)J0Vp}$`(>)o7*T$ub$ zTU&1uVZlmCAPnPlB(g0!E*G-nwlop5(2jkpOQ)^0$Q||^m3{bPwEheaYTuNhNs*fE zvf7sDY21K%N##&^q)Du6A=aedPe-e4ju_nzas1Q07eb@!qeTs;ys%eE$ddvK7XmkC z8oKxPPKc%oJidw?|7t>X4~EpC8}{g7?2JM*k^}~4FjZgl@cC%biRL6f2jjBP#Gk1~ zVjmlG5rsus3v6G)5#D>HYoNd0)Z^i8uCR0P2_~P(yt*7Dhor=D_A%8!Z-4r_evg_h z;~72&YVKsLzyr9nJi13>qE1viR5{6+hAC6Gd_nhxV(xW@OpP5RFUm7_W$CT_=ZV5<&gl%p;Ip|^k~k*ZmcoF2J7Yjeqf`^FoW>HE z)#5YzbG6p$v0IJ?mCy(yPm?t%(Lr_Zqhgp<8+w8pu+r*MV15d>>_)zv$8#6AQ_Ef_Sq~{N|CsBQz-*-+I&@hoZA8T7 zzD<7Uom}QXtfql4lP~FU6%C_v?O;5ev)fbU5G*roId9QI^X0DPXZIy33lk8y0n9YT z(`?$$u*~L8(dl!M*7a6=%dXyjc6Mv21ZmRzfJd5`C~UmH|1-?Je9HIY6*jJ-<^H23 zWu!?Bmc0EVLywOOWb*90dQZ%eI%md5GV_Oc*fSTs@LCoe<%W__lWe^oaG9-RmoKWE zCP7-X2lULJw|r6;Yh!&W4gG=_MTEYn|MjkxQ@h{eq%A78f(`?wxO4iW*Ig5^IEOUT z5QHuVH4D6`_XaS#cw(ajo_xEVAq)rWGzv-SfOLPa=SZFlLvP_hNnF` zOJ46E-h~khte@EAQxSxZs_W15qV}gO-7gT4e{JeWL{eJct2RPACRcKHk9cN^4r}DL+go>QHCdnZdobcoC{R)b*i%L84HYX zb~Sla=w^KphPT5<)4nXdw_q`>a#PhKB4^FMwM#x)yPJOAv_!&XgSFLpqy3ZJv$9t# z@0KWFl1hG;L%%wjM4{!dmlw5A&>gmneM<{#yEb5mVkyS&w1@TP;T74SXAx*s7{=m> zr89o6hY5#Y1ARm6XqYlwVJka)&Zx(>YRiDDr=xm_nyu$$TCyJxis=2_yQW0s{GTFR zG^p9!Ua#h)bPJ3u5lR_>b=D|)IlA{elb z{2ZL^>Y3cfeov*eY`=V~too@AD~;l^a+wyfStMUZz!)`3^sa_$*HZ=E!*FX=q)BnS z>_^>dHn${H=kVL`L*u3KKAIj*oeVh`zk$>9xsaOeDJtqb31%4hN%~j|G(CD~nbiU@ zP<2UzI#_#~llC`wLr<3vheR8rrAF1XJvAcoQ8hdf za$H5@SuaAEiAntN3f_4>)ZBzJFO98Id09=pXe*4Http~mU%pm;F;u`zqr5aPRMd;< z(Ob=pk7gd9E;dd%&wkS}5n95^29IGbP-PgwcC4 zOpi}K!Q$juJ^YaVuk%lzX?F|VG#)&NbQA9%*$)|sA$7!SiA)t^?;d$jcwa~wC-=Fi z!5qP>H**(TH(xROGZssaIGwK+?T+Feh?OaG*^3F^eR{qtr|pNOGwEQZ`Od2p90(y! zRRnhGW8I4q^0iw&to3=zT(PcXVLt-Z$L1@1-k2V>+tqZ}$IXuieX@Jwk=5|y%J+CI z&RbIh+&V;I4!vEU65%9XOhcSEl!1L2)D@4s#%2uT-jH<3+%*^R-(9C+yJ;n`ErTSb z;$g$mZ1}!Fmo(sh)ba2P(gzdV{7uzftD$kOj?`B|a4RA);e?a?Etn{5*Yzumfa8k$ zLgg+vaUmMZ#H-6cb=1%=I?uJhseY8UtO_$ze8liB z65$5iUzNvIEFeeEvEDpc^;zQi9X2H8bI}i1*HusT zN6A*jSdil`I^unC%1mXj&wa))ifxf05-Sac9#?d#c0QEbbg!47#3WOVrytB56p6?m z7k;7+gxQ^hxhZ#IatuTNr3G-q3pn-ph{O~!*Gh~q8zBzNHRK$_TKB7f>|hD$$9%e! zue<()rn&R|4Jy559kXT)p0kh}zHH+T$6;~K61`wa!b)>`dN~AzG>NZ+AvQ9m(_+re zk^=0JDZAA~y11?uDozN|thp3&w+e*)h9ZyC!6x(T(UIj<<&URm7z?FGDyi8WJ*HR5 zP>1Y+xq)>GYznBASaCbqf`xz&jJ-2`0X1CR)#Fo#_vaa7YhcPU;Vt`Xr4{YVg7ET7 zPG4mU&2DH76!wyx4-C2dK<0|v;X?J&oXO0zY5jRbC-!H;F=^K3i_+in7yIWV>Wc20 zA2qPXdQ2{dX0z^PulTj&O42s`K(GjyDteo5vf2rLEkbl+{o+58B@rK2LWBs>7krWR zqDH%PWih{$?nX?{EKJ{?Ueu1QhV_e#dQJdNeXW1Jw0vA9d7 zS^gw)NR15f8+n&}!UOa#ksOrGmk+I#3#A)7X%msZuJj_4M~+KqOkiuE=@pi&VKSr9 z{b}K7b>uh~wZvj%v*Lwa$AB8^EF8^^^R08udx@vQyZmgdCK8H}FY%u2Ws=UM$8`_H zuB=L|ev2{PEMRebixSY7J>neH9r-C`#A@$}WLMyzNjTSVH%E=mem{-lK_;J_YPqOS zMgb!H)_1c!6`3;)6bxb(w)gZ_qE2Z~b|Tcj3+gmjOQKm3uFMTIw39bAh+GWz+M`@- zKHXT9Xi16uxIed$6LM&I4SR5S#|goWy?uw_D~VHMZqORhgIU9ji-}N*M#xmO%i~T)p}4#Ev2rvXo_YSh1T%p;&lKDU&T5R$%1)dy^bVqI1S&~SMP0G2(Ow$ zxTu+iPZoY8Y$C^7Z7Sv2QDvtnZRA_I;*i z^G(^}I)@t|NRQ3zhsCM3&xH@e5*hBKU~9ubqkH2vs#temu$zejE+&D;B4R`i<4w!> zs%al#Iut8?Jrp+4DASrfe02@V774KLB96r)@Hct_#tc^fLG?FDgij ziyTQA=iRD@*zps45Sz_}KZaPQ)K2XqZTX7Mzg%tg9kuoDoJv+7I#XX)Qzn1jP?PD0 zIfrnM%zC8g9;x&D^-C8uBfO9ev$>Ipl_?vUdh_EYosLaabb%67iycu5-w*xBg0sa_ z%_Dh8`)W%Z$4f#B21brf&l>IxZ0D9RiID{wJGMDz*y)#eenQ-Y-Bh0Mwysxhd@zL` zDb~9A{e)vwlhxWROZ91LwiJGy`t&!=h1y7Y&+e{20OC(;#$&G&fg~KP$}@RFa! z>bX?anA)9xgx$0!+PXJ>fS)DFMp2djMc@e}&5s|3ciFSJnnT>N2W{1PTlR&f ztt9cVz#ZQiq(uRGGW3tYDfuI;1+45c(6E)QWQ1PDsc-4fxR@T+jIcqEolvjjb7!ND zJhf_vlz)?5{dp_T-e^Z*!pxIE+h;fTHN{JR#3jmX!R)b9%Rywm@kC?iG$m`_@?Sit zYWCi}ZeI!I&B>3bAqV|{2?|5FXUtu~tSw9?so)ly;7&v&3Q+fhJ|Qcr!FI_LzH0wm5lSeVhjIo+4x z4Ucb1(c=azEBZ5j2HM~U<Zc?acv>I)-Y@;*s2cx#6yZL@*%)%@{{Tp~sGZ5zyRqdxB1d&v>H{OH| z^Q*2=@1KrOh#d0ETbv9Qr=@EF;-b%6&M`7qD{0a#wmlrFTqzq}D!ETS83DCxg!fMX zvDYo=*9m}6(Mm4ere;fD;ZLp5K~mZe2|Q91q4H8X@-SKNI_P64Q3$=ian)CzYVj;S z-FeZ63^1%69<~|i3o-(SO|?_h+aGE^IM2K|f5KGuCYoN>;1vop#n8$Ls;qyZkS{;* zO3jz;E9G{?F>`V;^o3Q&Wd}~;u#xn0>C-ips5%bzW%}L5*LB$fbuWkK_St+jc^O|( z;s%`1);g$vGDySIw-rV@50^;zxr69O-A4#xV| z7%57d7IhfH?r5uI117^&1%1k%C$E8VjkcFr`{RY66F@cm|FOL;6NUK*1n^#@Yj;W> zebn+yR*=dI`MIEA&~ua-duaCSEYWMk`M|*~V`{cKj*HT40M#e!@X`<~G#1j2V`$h` zGET6!oF0fZ-Qm<4{ah(eLj~nU*-oiNTn(hU$>8i?Pd`m_C;7WZNia^QXj3ykw)fo4 zs226NwpyEqEvsd*J;Z~0YGLL<3|p4}Lc7Y-x$B5}ItqKi$DylKz`Ydg-@J=MS@;~o zy=)Xtvne9K_*`xeNR+()-s0AjE(Mdww+HI8RM`(YBK4MbY}Gym9v6yDP$>GFhGA-{ zYxV1WunmOIIN-d-N|PROeT-%Fu*A;hK-MLfm9O{Oa^39b?$pTf6<2+_#t79i?qvu>xDLFGllyu7^KDm`UL_*>L|J z!K~N*>;Y%0kBjEC;X|ci*{irG3aM}v(Z9S1l#%1uO=$n)oW=DN;x>ixk74*6{F2U_ zY`zYV%!*!nAAgFchUCtBNfIgUPLtN;o+{|M6y2P07A>J($+8_^iyLQ!iO6rJeWHRX z+LHRpAyE8BlphrV&1oUt9&ne64a&5Ny=GdJ<_BNn5CW@P8-xTs$l~uFM;wn<)M{uR zxm+%y`uu^t_)>RIag$g~8!0eW)4Ku&pNkaH{P?88+s&l7-YnfMGcs={o0RXWbXWWU z+EEq)BVZQet&2Rk0R>{gP$QVITtX~0o@@s4v%yGGuLri!*_SQCp^>E0dpz7H4`^=* z(E1AB6a5}URBWJ_zbEN+D)Ci^;$9TZJlkqmR;ORGc_B6RtlykZ zh`ZzZ3CG(v25i~BM_j=GL&0C2@W4^YlW>}^%hS&y0M)Jh7XHTYtN)~H*}4$CHkWTm z%??G92M=*RB0KT@rf)*(_K2PGaH;pa;HQTr*NDR2&speM9|wL{OyCzTd4msl#Oj4I zh9((F&%f>-z?RBq8nM{1%wx&+a7h(P)`pAs_oBo%yB2!p5moLjTls-eOyPnC)s>qT z$P5XadqiP(D0GI=7`k@yCDSoIY76ve%>{t83`v);BTxW#HZja5#$M#8B~wOQ2DOsVb!?IlJ7=m3%iU&3^?Dto}P9GV*GnLR|}%B z1|_uza8$WCNSqKrlx+XUxr6UX5RGZka;w&iNowx<6Il75yy-jh?L%+Ukb9Sb$LN#d z(i^b)6Le1YL}AJNYVMv;qBG!K!h%4zi$U3X6k%9RfkIB)MNZzUudzJo*ttm}dqUN@ zjAHf@2J&drmxudiOc1P;;Yv1b&#NXCU{PgML@H7dMOEUBGxA6wNsc5v00bm28pBa_ zuvn{Hnj;V4907&E`XrGd=7Hko*ATJZD-PRX9DF@j)?=OHmJe!K!-0cMrXQlGW_wq( z#V>>#V8r>D!5^zh%mqGYOCEtD(&Q?`riw}bqYy#l_DS>szOrf&^XK^)foERLuXv%( z(0De!3VSysPPz8DF8YC~i#l_gSm52g6eD}c?fV%R@uJse$A@}f?~l-Az0QZMBYEd5 z8=M%_I&Y@8w*6z^*Ty3P_?3R2^e6OYY~y(}`x&n~ZHB39ie`yvb?NEv8BG^Mj}lk$ zGY!vKX$(_tGYjcUmL{+ZM*X@zyt)agwV-9cKN#nV670c{FFKCokb8VC-?;RP1HU!v z{1M(P4Hm;iZ5&Nalu0vyx5*9puea4{#i1d{P2itA;%dm%t-qYw$q_6dg23C&ZO`er~PJUqb z{hrSD&$zjf3kfhH+j9Ky<7>o9lm+?g<5o$1G=@!VcjN?8amBnIhe8EpFJPE(fzc%nh+2{PF@Uhz9R#$f z;qZntJL#8TagJ0Hv#VTBph~hdI*eH97cv%v+(VxC%c z5joY1Pjrv5(mZXHgKr>B0-fB(VFCQ-$zSXK6GqiQM;npfJRR>7BDPIN@$AHoFXiqT zeb2>bd0U4h=nC^qw_haWYa46A?6?6*7alV_$Ks@4^1cc<<+<6&1Uz6c8B!zC#y&CL z<*AJ}DLmj*vemuz!D*S{VEZeaoh1(Si%2K(>sKh(biQtL;-+M zxw2*gKy=hHN>2n)NoLI?fgOSHS+UW%W&dA_? zft%IZ0okTKH2k!Ye|8K|_$dfNYM<735N74IXA!{74zFjdG2?Gl=I^}=xybKhbg$TE znGw(~G#f-e17Ox7DkN{%epjrPe3MP|cD=gSL_AI8!zd2D-y-}}AkcaO#pWNOInY?8 zO8px@ej)Tve*7|Yn-(64(F)5i%dCXqhRkWP3C-eP7gW+Lz02h>H7Yt**@UV!W)a zGqU=Nz8b>;;xn_|-=2#i?KFRQh>zpwpBPb>mA{tmR`G3QaqAm|-qThOC5gyOYCcf} zW2G_O>IlAuGzlrQ{r6s~@!)014k5Vbry4?;I5l6_V<}7%pK~wFy`_n)8XSIE{jR@Y zu6+fc`Lk0~_r*xc`9wFioG<&|dOUO&qbW*S{Gs5Gez9ODi!^cZdin_(j$&8p>g^2C zH|*UD0uM6-YR-=Ka}LDrcwaKo-YJ8D@S!*F=?*{K`D*W+upmScFMaDv_Adchmz^4} zGLJ*o%x~8q@LWIFcL-Tyb&EqBH-MG;G2>&%8Xne%+x>qw0~^SkkaU=Miq#i;b@3Fd zglFk312RP_oN(XOb?N{YCGv1Dp9IaKS!iqO+s^Mt_m1G)`ku35NAZR|&VdpTqQ$U# z2~=-}G61Lrq~|4lORnRnoDxoliSV}#ZFy0v@2TtLD+Fe@E3pq$Q6Vh4ezT!z13Pm= z%irwII==!mPDxTOgR5A$e-NO89LN7K_Awc8zB3UX^Z|foJJ|dWb8#RxNn*qDcFR1E zJRQ&I$TTBQu`_E};5A19{9!)4l1U>O_drbXNi86E`U15wL+QP$?l;&Ejb4Wd5}q^v zJV`T{@?dyK&#GRl4IumV6gp2MqOdV*H7mS-J$JzU!~cSR9-aw!S1jiCzTL&L$>2y=_|JK9~Negfxf0+J+vf$)|cH=z1Znp7){CGG1o4i$^KOCS;YhQdF@!??Tmg=yF~g5?qS8 zDk~AWhn2bwFjOBRN?x$_2MmjHTxaZvTDviSJ~($ro{z2-t~ZlIPBvhyQ@HV zk5I?<4TeHYz^5o>v8zp;a8ht$kQ))7EYLv%^PySBfPjT4?8?3VUeG1f#Zt#Y z?n`M}umUEe1_MU^2}r_1dX_}%IvyIWRfSs{S_H1+X$~hh$g8_u_s!HCI>8sS0qh6Y zk*>(-d+PoWtTaUjTIbh@qAdEWX;+XMIHg~z>1o(DP6YehYDoh)lJ@0``7$N!krxE# zf`+3yR6C!vh$5MUf(Uk0oPzYXFqyO6A`u4Cs})zAzzwJ^YZVnH3iG_y4?n!g)gbrZ z3%X-qN#1iNL#4(z1<`x5)yO%HsHWtq2&%TA+E6%rqrbOE8VY@mOSfFfiNb!-MgP?n zgd=0On~SFqkFS}2zRLVVS5Vh0qz61%(C4zkg)bJQOwU}*;ETMuCO$m;6h>R||0opFFwajN z@!>`6nz_XI8P=@OYCDZv^%)_K)YN6{S=ec`j~a=ese9@T<34dYJF|hdLFddXRZ+a< z_AKtsHf4`luPz&8>AUS|_;3?`R*Aq9GvFo(&h8ChnjX)f)dn3N+($)3L9~jTqy4~M z{2pIFROnVGPuQq?;y;@3kIl_Kyzpo?N*YsX9t^IKggFRO{f|EHK8nr(3CtZ2s;@-s zXBe@$oE+Wd$;lyo>Oq?7_tz}wNI8jA-YIO&i>Fmfr)E9oC?ooIS&ev14k;fumeRnl zW-z)Xzkqt!Se@5xu{#>z)#kU>b)V^sf6KO16>raVamS?rTQW&|b|b3uJg6IL0`??C zVXLcWw}4WcI$hJXZH}ub8@ZKIG6q!AyOyW(5ILAqC^mPYG&OoXei#=J#OO4a{g%2j z`1MF`on>d>wYMIF5QIF6FoDy%Dl{Rx3n_L}?*C)&t)rrR*S29&N~A%N7y(HE1qCHX zI;6XimXvN7P^4Qxq(frp?owJpM7pG#p@-(Z@b~Wh?)|*``8{iW|9oqG>s!l(3OD!6 zeZ_el=W!m#Ijk$(S|O2jP~APpdq?RN)`O%!r^fI z59A8t~HG-IiA#i2Rj?*uTVh3>pKV=rYl9U)(V;;C9qy2xTF*XIdQ~ zCCW#(W1}Ff+-W8cy6U-3GGxd&MN12rP{}%M16<&l!%9w;7%A}bf^+k2C;GKMR=$Gr z$wV2e)p1_#l*mPmhF)&J3yJ=ew#79EXvC#Cfw$0RZ*p$+?C|F~W@}S)0KM+R6}|3& zSYN?bo(tBrNyOHQF!=U$qIzG@zoap8GJdNV9@vm`#G71ARqA`rGs)tytUFx!WGcUX zNC43DHFduwRci$>cB9X~1!FH(sNT22NZh5X)Oq#)Th#JI>iM7KL5MvF_JJiA<(`qu zfHcWqBF0#LDAaP~Wr}MH5%vZKR~ad3>h;~P-iP*>r#w{8@2ja1O%y?MnfXwi;OQ!j zB{RaF{@E(o=jJ7P^2N_RCs#3Kcigd3ijm&5^9%5bf?jcRzVHFwS?DTb;XcPqR0V(C zcTe$SD*j{X$D0d%GEtB^&ym(QXik(6E43dR*<5oaA3f_{2`>2;h`r^(;D$@8T^hjI zjy`3VYiRs@IJseECLdbsaa*ifZNb~E(et*R`{h}hR&mFl79GS^VAj5ry)(l34=sS$@e6eKPXzK-1u07A%KmrR z)TI3Yr|{KW+#JY@dKI0BNg?7{Y}HvHPwbF~T}nX;0Rr{Po6b-%4^Md;b#R*$%Y5GF zt@nAa@bMiTTDwMaIy|+#10bksP1swX#jeT(?7q;WAe2CCDcEhk#Ys`2YTq~&LGfQH zkKQukJr>Vk3JP-7Dtb+OdS$f4F7qMWqSmiqO6?GZ$b5IsS7Vsa&B2)hgN0d{FgxS3 zvb{?I-6F~xjS){F%>F9Go7L=jI!r7U`)K7ZIoaxS^L~k+#4mB*WHW?(bTR!Yuc{Jl zGx0Iay#3XE-vPIxkXb~qpZEI4!5im+DhuxFJj};cEB@+4ZsrEtmx?nh^`8!w3XnpI zzgpv+_Idh2L9o#m{~uUV`m=a$v`*Ft5#n~C;~Cj5samWPYs& z&To@@GAR!@a=*-&hre3ePC#%GYZ2*Fq{4=FLy=PxH4Kggtm)tGX5x@P;nBnG@$jH00Fwc3whQ zipQdY2BBw4+C9aNCk<`A`@T3S{Y%kUl8Qo8l^$Wmld(2`q^%bxq0GGQj(eZ)Ck5<2G{&`ow zj{)TR^Xgo}8m96+W$Idqz8VzN$r~W;fXAaQ&i}q`|wS9z%iu6vEig&XlQf`iK@ADJqD&sgYGNqW3I$9}9J z;lAxy&g@!2kEnt0nz=U2HVY0OMZZqH?Cm(zK0e&za|tc5?HQrwHXpjk=Yw)YXZol!X0!%67GEo^D0N)&ub*0i*Ae`)*cf@;RKLW}v3KXQMNsCBp-ohZ= znWX&?JRg0muW5T1invsl+KHQuM`O4k%lSujnX{61J3Q71O1zs0UEX_q4LXr=Ru}GaA3Ux^FHtt2)#W zZ#~9>b|fEPU&V4>uEZx82z!@uz4H40ew02U^;35?ch=8!CpEs5d$Bvc>gE*_N)xYK zR2ert44TpkW(p%*^juYUo@q$tBeh4_*F-DRzCTFo*WlD|-oEJTk1X4tIU(3=Xl-28 z*z;#vEArah>OzFg885}2=MAZG3Lk&fqd2AJPumk)%0+49w$>lW_0G51FzXX? z>3+h+_fkxrw5v(ikCJHhtJr2p)t64wYi|%I-YSvG8BSc7u!$WvZJE5L7rJd&C88eb zk#&~wf{oD~X|_m@0$5}(m7I$5p!KdKw z%_n;?OxyJw^)9)k4cu|(pU-E{eG`!08awBLgGj64k@cg^$zk(!dtl7y+}aZ1i(4Of zkv7vKG8y;k>m2I-gzkXcV0;pU4D^ovPNDoVY8B(aS{AptUSn>)#b5 zMwg^FcGTWPgsLp%U$!pC`?XCsuaSGAd0}1TtbDr^ETs?P?YG_$Y4WrzvSK&$l4gip z>nU3_w4P>#6s96Cd$zOfB0#S3V)Vc8IUh@X4xilt1JZg!t_cwWQE4+ubXIhTyp({$ zxz%ML&|~`iB&t&(t6`c-66S_VDZnbvqC#jz-F%gni$beYy`_aam+r1$yYbc@U45-u zxH57+vb*NGDto37G55*Kej2AN%hk*1xTR6x&3<&oWoQ$%-A>rnC4_SC)J!(N27e*$rGVJthxRdY{i2495(ZBs;OvCpvZZWa}Z!dvdts z`4(k(V(q!|3r)&rH?>M4V~@_hRLnk?XH1E<=0P@^G>ui*+EN+BTc`39p4$FAi%~&& zw-o#U)^~w(Z{>8k;`pneFeI(udy%)P8U*o@sw+4j?s`qOiP4S2k zk!iee3p>>pK>A=Ohzw!G8yroasJbAvgQ&PqAhVK*3s<$TP!Xwm1bC&|=>?p6R0jj( z^I5OJi~xP`Z=esp^*Z4JDJW5=-w^~0(S8YNOlEG7geDG<``q#Sb;t7-wv%*bk!c&s z1HeJ=Gp_vw8iwV5ptqaot>r%ho#&$2&Y8$}t4{47nT18r2;@vkOBR@ZROL^!AcJSu z^M!6Wwdcbfl<=`eepr)H<&Vy$>E-tdA~LnbOWuk#w(QdEX23x*quP%1rH^ulaZPb% zht(EoONq#H)v!lg&Ca$o&FU#M>Ig2`dhX09f884(vG+(js4i;Kk$qlwY1P%x_RdxI zaJmTMaP8vio93zi`%q}i`#fl;dS=n{Nz-v1qKV1#Y`N1l+tYKpAw_KP(@cr%&YiWo zReADsvpfSzHE)`jsn+8U6l%^M2UBcgx?4hZD?8h>k(drn$1B6%L?Ef3&dsj`9eX;& z6kZV+rPUn{$ToVmu1+p93e>v_x#L6;wrKS_`n0$KTfr)Zli^bjf+&$yOiz3ZAoPGcw_fi6s z`_E8CwExsNUcbb6j&W0%mA$P8G7D`rj8*-^d;*{CV%qEDv#?(DVDv=`hU9Nm-XzQ`IBmBrmlU_+2R;wUt2Z!g=5&nMJHT=tCY}2V_pI5P7e>TC z;#$~AAk&Zxwp7V&7^CcGX_CLA|=8%?@?&{hjHc zo7q&y_YrS;7O3vFisUS~HibyCt&ZCQHPR@ksS_(t>-1_G?x^clGaq}+Nk7ur?HdX? z^u&BF>&K1BENuZ_!1pWOdyhT6woxbie6J+K&+K(37<%$AtsepXfMKTP2^4g*+lPyyam2ZVeA^;rw%=pfP+|=F{d4lYy5!VcZoVB$_d} zGg)^&FOxVY9jN=5eqk--iddG+MxKw`bGsVrc+whIN6>MfXeVT+YGO5`UjFBVBdd|m zf>3GXdsS=KdHtiM_;Ym(O>V2d%5Hbs8xH%~f~!})p_!-#XRtt7%iyT}(rTQyb{`Pc zF{F{&HVC}XqE61IGk^I+6oceoomVW$X3~58_Xttj#-LBjPB3xTeWjTjde8Qs^d2)b zjNTkdyas$D3*Th&LI?Q)bLlxe!T zK`bIfz0<}GMSG7BU6Ub$2&Lon6T;81VFlt#Lq8Z&Br{XndnM?&8R+UN1a&Ej6l|K9 zqRu6jqHUGr1cnag59C{fQe<2OPd0^pD`Hj>VxxxEtb^p=1-X{wRmrnfd_}7>zLEXQ z8QizE4>A-E7!6*aC(KtLX#lztiaTSGB@|*Xv}}m3wE(G~2&U9^nXO*bb7_cqNUs*I z4Po>0?fRUG_9g% z=S5hD%xb4^B|Q&lJwC+MyA9JxmZHGF6K}I0+`<74FF=e2ViNr(1W@5C^1)N^n}p~z znaY?_t(xHh8YA~ntSO@H?&I;5qXVAz2wx6!hDObQXWDf6_cR~=m4FhCH4&wnn2 z8=m(yq97Zp4P)n6Qj%P%2FNKPTqXYkMhb~DFgE5s)PWr;Tu2_I`6#G!nTM>{!hI;k zj@jNggj}m3t{#Mp*#6SGtP_t-V}H{a*vr&1wWJ;pb41mE@LO?_?u)}ihGY@D38LZd7NS{K}?D5&sLLv3|k zJ51d<7o`kNCH_zpRhg8>icbl4mowl$iIpLMkj2X!fAr7tGyjI749Mia{J?AG1lbCu zB9O1!ibMa91oxyrkwd)my^$LUonhadQj33ZlNBQ=c5~xp)cnlF_uh+Ki{E-aB}P_s z5dSMh%aTgxOyy6B{{WQuQ&aE-Z)CJ>|GIFcS}|{``zUcSm_SC%CJoZqGxrIVf7C|+ zhNY?_LuG*$GK-or5M`sRE9_#Wd0Of+XfLNc;6nd_6j|C1P$6d~74??V7$JjIFmI^a ze9v*7nx2Z7(|4od_qZt_2Py;C3QK_guJ?^r6%>{JQvpZG8a(#@E=o{4Gd~1EVC6N; zxdcG0>WR zTQP}6S&xLc-earz-te^C^*V}se&)Wzcp!3b`rJZu*Ek7n3S&HH@_?*dE`178E|)Qd zF=Id-ZtXa4i>IAF?V+|m9xNH*J{KL^HQTt;W@D})p1Ha5=yPS!@5Bnxbg&)JIt(1% z;zq>~k@La8{01-%95WEQ0Bq}``UB9P|I_S#)Bq|zvZ~PWG?C1rL_`9XCZ#ieg%E4h zxu?E1dz2jf6P>>b%FIXUdBOWMZ%(^V^uP#S!_{n|NtjZ;8#TJA$%+ph$T7^}zaODm zB8y%%)8d7aKSbxe)!_oI$!C(oC}G+C0F*6h8T+51b8j8@+b42}-1~_dqs3jOEW&2h z!zwial`Vrxek5ylUpJ8(89#}|YTDru!xR%v6B}-#Uu&&YNM}bZf5UJ9nO39EDa}$i zQzwi;aUJ8tZy*8}_yzxBds!&4-n%dB3{lakWz(WNI?c&H89kC(EdnjdJVQ5B*5-qn%R$( zLsjoD~Il@41!A$2Kb))+rJ`X6D)CL|f_JxngT&q`7fr1!Q?^|=XqJZvDg+9RGb=lYI= z`HL$)E=@j}_poB@tIl88*SEO->Zv6vNkcZ7lou!2XUa2f8hxhsm@+)Ik`PvZCa+zS z+huk&hm6>GWRhB4sRyz}PeR=hVOq7yh>$S8nokw})`>|8T{nCwbuf0O%AM5I_a?0M2TF zxP?vsT_$7q8)uvg(doy{1^qay*>VW?}|Ma1LzDr?w7igS~f36tNQ1Hj0xA_r$`P zbV_R~*U9-(x7MTi{KJmBQw8@WJyX92Lrhek(RcTx2+~P?S*@c%#gH1k&&1^Sfe1>N zOwa~3M;?)ij@B1@R@ub$@X|_}Qqt`%b-@TQM@5p^=!;j#%Qxeu&o|%_$*HU5GlSyE z7D%fIIMM^@D7anGBwSEGG3z3DN!PS^Xfu4Es}Lqt4L7&8$gc6uX^^X4UA2%H30GZB zJ!l@3W6nG`XP9DbMMalWRHGpaUfD?M$x}y$#Rb>bU5%{o*f*we=RcVlR67zF8<{av zjkBz;KR-X**(u2?=vr>h@$jMH?j8A6yfaoW;p|Jz&zN*x?^6%(lZ*TaHPQhZ?3;HQ06C&;R}4wFGB*MIWW~I6voPAyY&$Qw*i(8v%{i(*AkyM zeVX2mjqlb@toit7iOd_>cH9s@1zA6zqE#&08m zhwmq2kdbV#lQQeKZ}m zuJ?P*bQTcnB<%_m1W& z+D))C7_F|e-aGr87B!R(aLn;(oLw|7zFEX)+Hu6G@jCtZQ(jE{Kpo=?p@{)8^NnG2 zZ|h>~O@GT1z|zN$TxgO)Rua$eMWeMVd~OR9MMk_g1{b} z=u<*F|9rrpd}2#S;<1Q)3Q(7|?oewvIoC@$n?-Lp4UHfQkX~aP6b-Z8zkSnYp8vNd#IvW98N1lGm5&DZ7on9AafOjk;Qm6vJw~ zhPiSkpclAEG|Wy7ccZLWvms0zV7o5L*FlIWE2|sL)ObZvGq1k|t4@VgCin zp|s}SQyqVP4gxk;c|v5#O)^ZDJJe>|#Ol74A-RRTqGyb(d$awnWH3KMy=Fk`>6@e> zhF((Zb^kkvD`kyiTA|O2C!YSr2opU^60>jJNdbykZ?BPKpK)erZG_hi;ds9ndP{l47^O0} zJ3XNtm*EMm|LhHJU2L6_I$k+$+{`>G*D)#*x=npTIFr=ZKnq(MxV3)Dq;Bw*tb*-z z#0)V8+i@ywqwja}0X^j!=3TUppIZM(U_P%yDB@liedM-ufjOkNCpx>*I{Ab+%eNdqcbn$l(;v#Qap8k!$js>|P~xBGq9 zq$e8MF8+l|`2_j_{J~lkGTHsw1D1~!nG58;Te$ig-Il; z2j`Kh|M5a0?ppni_UfchP0>2iK> z-~GMdjRzM&*EC$z?z5AQ1TMkbUNO6J;o(G=tg}@JNn$^76ajqQ?jw@g!{+)sX z1VPx~2h@YV2C({mJOEdvL4~%!dhG1JFB5^r!1-#FCljQil>b7t|Er?d=wF8ppiaJz zH^u<^K!4bK`nOWxb&>-fF}EqW@^~lrr}q{$473r{>S(Fry&P$W9UeLA?TA&8j^yzfr#BU z20=Er#ovDb7Tw=YA?i&zNgV^^`kA-mqCwrEcJoH|aHa%P6$2ao|L*f~!z|qb&6&ZK z-~U{B0`Te`;GINFhX969{bL3f@K52mQvaD%+^CQ|pi7P_n3IYO^JhXW0g7qeBHRxyO8diD}iVX^ji9JB`?Z22i@GAYip4w z=(tgeAA67tV4X|yIbhvfv;99kIH#ZKe^{QJerh+{3oMAmXFwVK_oI1ZM{t=0E2#~b z^l+MQ)gkd4G2*EMuss3oHeY;`Ja3L2Jct6_7XBYT`5};6aJ?pHfTGcdL)l>W=xu%` zbK*q7o?+ZU-wk;-@tBANLjbkBM-0*lI=4XlP_cKLI1?~&qM%V2wFLJWygO;i04(M; zk{t|=MZt;sn?KNHATZCLo^&t+ul9F;9vj_gX2*XzF8tk9;2w%~AQ-XMR43p2+ZRT` z3DX37hQ9hR`T75Fp(+QEJNFi`n@jxdI|QS36Rd*R1)1dkhYRCC)iB$^>U(1J-wX}- zQELzggIxcw4kKp&BOdSL0K!Wu43!LR{5Ed1Iy@a0Z>DI?I97|tJUsFc7m3C5-@h&W z8nH65Ku4Mofx^$1gAvF4G(4$<=<#Bp0(y}cuh<2o@_T*!;kZMmEgN)3h#O zzxz#d)I#%rd*FexsCjS$T#<&>hvy~S3+f40DCzb>+;9H89Zd`Vo?Uq22sU*LIH!PX^&-W}yw5{YETx6{ zFu)o&*Ul|_nRd1?BISwap${C1ev*!sCR_b%j`C_kefGAcLQD2&FrRNA-NOYh$WXPB z9O4n6G&n=MYt)YFK)W&fINtN#q@f!CQLde(!0MD$a|*a<-*CtKYsBu@t&?Hdvn@9* zJ(>zP6)q3kwBy`WVa642t?G!3&Dl2><$V2rJE5e>R6gTGB$*aw>}jB#YN&bLB>i&y z=BilDTQhH;%AGUvqS&~{M7=HhAWbbX)7T}}hH-`WDNcJ1 zua5-PX*6r<2ebPzRy!vxx|fX=9(PLW8g#-8-7||$Rh9=o5Xn4jMK*sSema+i@b2eE za?{P7pGn6WgWdZ+81NdO;A$UqL5mz=;%;-*p^w&fw(Ix5PU%L9(Nn|SxNb~nx94A& z1Y;Nto9kiPH>3Zq24YXs%MY<k!UwG4zL!haX56)2fv@EUaU%JyYD)x5@WxIKANpW{Xz1}K4Q~CZ|_3CYuj!3ON8OQbXj5> zc04rcsF#5ZgjN=f3XoO!MgVA{)^N^~I{o-OMQJS!)d~2LjK$svqBbL|n#Il;yOGTg z9%-k2Je}p8J~BQAd$I$ZMl7j%;)jKiyn^U$_UJZOZX|_v7L(Y&-E7mRbaw*ey)Wmo z&~3_rz>F7XDd^+ot7*`OjXcTx$xp`uJBxiD?Ph`zcNV7eB+Kw-U^_;_pa0ddX%^wE z1PNCoRK$jH0XehbnvYvy(V3tqkLnbJ_f@ri< zC2z~f0?Xs7oxwz~70Tnlygy(YM_J!*vOBTrz6XvnQsDW`er`)PRB%q&P2&3U@aU$A z3cBr`j{Cm!bhI=Uj(Kzt)m;W7ZnG4I4S{vN&rCz37uC3_mTS2@?wwopL7P`<7)5~H zAwW#P<^`dJ#WvPw5A7(J_MfXFl%L~?PusD)WrUoggJvAd!N+=`XLdg{1@npGb!YC$ z#IqYR8{>lsE z)xwYbica~vh(h%>e$xH6n+`N#us4B@A>3wS#vX_CD2#2+xo%_Spf)VYvYE@9iZ4mC zTTD;Tc299zvD=tV8@)qPYzZac>gmMje$U%J3llT);NeHo3t?q%|3N++;Vr6D-$cCXIoF#qY$L@(6*IGLtC+rfY2tG8Dg;fG&yM3tcL zbdlJwX}HINTuAZ_h+7n*QT!b61uGEi?T*a!Z@M@{Y-FL_QF9iKu{Jn0nEy1=-Min; zE#$7Nmc7BNNLA9hjdmGYFg|F%WYFl@khkF*JbW5_lUdV;-Zqy-i<3@o&Uka@%GVP~ zLo2DZgL;AN%ULJG%+SUAqByyQOQ$ZDo)`{;lGSyuN6S{+hboeaaY#O=5r9b&um({y z(j{!=Oh00!B1Ek-Vfvz(&dOXN&9Zz)r0%2aFi+2bqYz@twtmJorr)-v$JXbZ!pYTa z7I{AKD%CaBeU75mr}UXnALRqO@dC*+7rh~$McFDAC7mkVXA(jg{!^&dMX5)L106-% zRchZR;rPaL8#W4^%_CDT6EWP!MOQo~_{>nhpBSG|So(_?!Kd|BZDEgSgi@kr&hDki zPa&)_7oO<`M^R4@MDauFNdyF^wk^)p@HJ{S3RYal*&h+b>F6?5Lv$W6Lg86&-i5O> z1%2T~KS@aXREGC9KS5_dinY4h`FxL

gNz*1b?%2_l zdW?QqDb(~>Y&2lvvwRH7KZKTKvIQ z&%-wyMMPWyTJ! z`Ci_9g*_4kH;f09Xu79%-I?)rDHoPpl$x5l6=aa4ll7r)=!H5;WWmPIY?3((`|*tu z_w8ShyAf1aaZ?zYqc%PBgH<)f#VL~`wsL(7jz`YVE8gNeoB?q~PkWYI9^A z=wb(CNvox#>^EM+oSF*Cbg3Hn^rcE10Un!L4u6CD===@HIE9Dqcht)70pvpSM zD731a&zL64c1uQ73ZAGa<4i`Ii<#UKK=g%=y{i9(JHa*uaZp}CodVJrTs9d$N(u{X z-Za~`dI>UQ)7X^vmTcrBZ7VocrOvUxTOlulZKeF(fz|9VYk1WV66Qo+$l zUyWyxF~Dp~M{v6vJnAGIDt+%<-T9zwmoy#v0__#-W0nT})UECA0J?oa=p3&~6?3UP z#H{&@n#{wIi%2-pPCa~})3%geLz9jI#qCx|3xTT4U~HN*hb_Bh{g)xF;W9N=7qo)> zrd2He`QRG7CFTnC_s|`cj$;@N9UY0<-b^-0L+xkFr}4d(Ig5nR!lsiOLPU?=X$CKeuv15{6_+*8+I$H(hD?y=_E!mE1j%K zON!f)G$h?!WGA7_`ZReLf|e;gp5T)#I6!cH!v-s}dse0HqXiz(akFge|2(4T)UEqE z5dm(iXys{ICq(|s@LHbrzLSS@g_KSB)a6-t4<6&dUkazLru>{38s+;1JPvDwhD>jr zDn*CBSXjdGHV!K?CeaKziL%r8-;0#U^X=(`&Jy@Or$fVcq_1d?v4b8yR+`Yt@Ft8^ z9i8$V^VIkgxagH1(|iO`F&V0&qSu{te78KRkpjk_!U zhhg}~bAp%o{|D~BOp4$Crv|PS8~6QJrDuT(UrhAJ7DhcKN||+*ezd)l|ID$tQH+sI z^us2@p=Pr^;@;Npwz}wV3=m(QmUZ&P6J5{EdUoY;NiZJVR_QXgs(7@!om-YFE*pos<3)Y!Dg8MfGQNgqC5C zU=M9__~2_&d}XDlgMRQDPnGZQrQufnNN>8f}SXSD5Z61sgNH8(~eEve!nm0;Otn$*gx;PG>;2vUdTt1ft&L#$N$+ak87bnBJ|n(hkyEdHX;~O zs_pQrJGScBC2ygfF`<;y1&>E$O(c|Y8qcxY`*0nz>m`=it-DOe{CR|467V7d!nS(L zXmvP*E%a;a>pc-CRbba@eA{`GR=(-Br@uQzsLzmSaS*F5>MbI7kc$#){&}u$yGY@7 z`~{_@f$@nv@e`gOSeuiaj3^Qsgl!c-yh@)0 z5hA~u+}NGB0Lp`!+3JDXDSEVh11#49#R|5+(^kn}j-u zt_h)S_`<3*lgnrjsZkhBWyTYaM$>s7Mrh|6POGJg;cdLbNED^Zdl>An zS9`xxh7v8#nD^%RDLJ-gC zHwUvKOItr+1Tp@KJ$RTdi%G1QeMfstR#QK8haFbiHHo5)N@?zi*|ti(sKb5 zO-#+?L-rWGy)p~pYjGfj%Q6i&KSBAbyCfaq8u8$HJocSHBhR45qLBC5yEe%Aag~72 zZMS2KBsaW>UZ91{kh0Rb-D4#<)&hOTHq)e-sgC-ZmA&(C;b7$89pd_7ke#@I+$A?} zCDpOB_CwF6LYbI?;%|C1FGWAsbT=7{nxn?Xjn8CkSCz9{1sVCKuChlH{^#rq{X1>$0I6Z8RcdntH&$v?Bm>1jIgY(_lg{tIEt(yTzdLs^)Ya{3fYsXPXl_f+Ri zPv66>pGgK&Cmt4WFn;yu`)0h$q8){Ob|19yv&L#m%AppJ<=C;d^Dc(E%an7B=eT66 ziDd>f4}bLGt9yP0EgOq5h~#^=8l}}@q2c$7r4;u^OOU3p3rP`mK!ov*7Rd-WfxB2t zG*H!(JkcH@eEXUhNh2Cpg-H(@a|R-+-%m(>*-@L=$4t@|!Z~VYWOYQHX{%&`nTsvU zAC6qMdoR`3^x6z3$}uSvjMY=%O?o=$mS-Iu&!>i7fD8fZXGz>G4b#nm7j%^SJRQeg z^CN~Vw>LlF-$!}nwd`(w+<4ZBf7D>@8w^iHiB7?+2d)_H#Ur1CfDYa!!HT_)`HPPb zTuM}!hFyJgwNp*1Gvay#2G{!R?adkJ3g?6yX9G$@gQ(*wFdSTWQCOEstFxYbU)bFv z;V^F{WdWY)yWYP#n!l~l9(Ad?d-o9=?Zp(bQJ>%1UKxZgg`#cQomH_e;2b_wtDAd= ze8-VnWH?v)+SVlAw8xk2kTA##yR`u23L@w{w}gR3$`=h|_8wZDE~(DTc7a9$l#^2IN6hsZXDl`JR~EK{ z!vs}(SdO<*3Q#X|dwfwS{kuUY>Y*sJvEWOWtcYA{ErMtdg4v-=hk~G2Pv;62bUGNI zW;Ad2u{OHKX7JnE;Fb|5*{pp|>inoD7WKuNj7`pgNr4$Yxthuv=;h&Q(|cKJm*}K| zXioL=7eAHx9%poRGa1gKwp@kSV)BVs-e(&M}0*k$Mo7aUn$WPB&gApPb)^Ftxx0TrVCZ>Pr@9wvNYlXW#0J9@_d{P=!#S zdXv#LBnIA1yqsNRG&=a;D2fw6FO0dg^@?ABGb)>vQMADz5H-0xn(HDX(u#97{6FEE_L87h;DHuZ_i zZ1T`_J(k{qr20!`zI%7}qKEH;DDR6i(YeRLoQ}GKKiL{4r)X#g>bmEY0gBJ#@dKlV z)HUDkc~c^=o%vuVk+UN87c(^SQ)$n7v0t zB(~V|hXw`X^dnuFQclcyLqxwR9U)fLNY8I2eMWv@LY^KeZ!7(_Cwc<-ZpM2t`E&TT zbY|qm8lBC?oX6C**UX-BA4x(ZN5^?hBsl`R#eJyN3^Wch!@9*<5XNUH8!gzQOMH7R z%d_`?(&sE?IL!?px`c8RWnnK?z7&28yuPhjE~PdG*oJJ84_Ob6*}uq%%Jn;r#8yC_ z|MFdzoo79y&51x1Ccd>~;mlNC+s(_nzuR(<Xbg4PqkexnVZR zVohStPA}mpTOkIB181MkoI75vISB-=i8<8qlY1w0f;aD-%XfX4Ye`Ta%C0Lf(G;i7 zVBh_pjLegiaABP$v#$XYtrnAh2TVTcwhOL?J?@Oqt%I{;ACEmbw)1yl{6ACVJ=R1O zU&-euC*U3mmI$g3LO0<{XSXWsIt!X-nMReqlN4Q5s;_Wc?f83dqWO7VV6D0je~jb9 zZ-r%1Yz4WWScx9p(X^td-42}{jHf4!=u;7{dsieNM?Jm%NY|(tFTPr?haL)uC>cOR zNn;Y^law#73EQDL6bL(r*@thoH-8+K_*Oh+$Q$ejK2Eq~`JJNR$ac_N^hCn@t?q|} zbqvFPr9JlFBSkABJ!PJmP&_mn0uF6K~63xK+LMZ6ctfVl`;u4l5g`M^=N` z*K0G$?oS@AF`jZpihc)xeu+GrY82bduq}QkhfYYfpv{HM3{Gu^_~$EL7_gFQM#(vu z?x?h&ybX~KYfRgidd8bEoaV;e1JOJv&l2mq9K_8o4p>9Isxy{w46gCzVNuNYR67e7 zs~c93!f9S&G&0LhzJ7wtvZt(l2?x}gU9J^R>UilTU&FzX8mWQ6$qb70@1OXAsks993I zNRzLu%cG}uU(VB_s0FpejaN+bF5dLsJ&#BkulaSQ^rFly|1vCNCjp#rb(^!<2F07r z0{2O7-KW^XD7#{&J5RJ?S#Kv8V3%d4dWI7n`B}5PYlGiN{5+iVv@Cl@fF5O&gDfRE z!rM7KDJY2orDDub{A~S8XR~Q_zWeFAp}gO-Us}Bg7O0>0&H19P6Mw`i12M;sGL>dJ zwy#inO!Yz@(!xuy_-kJ%KGlQuGT#J^!7)h1k@o6zxs1MrBziFEnunf^kHp5+mh^{d z4v}IW?npU3*4fp2c#6N7H`Bz`CVH%55PTAJpv! zKe7KAoYFA=DH@5IXq{6iBR$wRU)T}t{^L!KC$3wobV~4e|7o}dpFiQFr{7{di<;Lj z+pL1EV7E_pg}5&jSRWqLlh=IC{w|Sri{ByUq1n@*i~PBw_ck)rs9Xi>?b~SD*D)xI z+$xMSEpP5+1?u>F_Up(CQhtg*Fl_Uz%khX2lL~fTqQ+_Wb9&)B4}J zs9o@^w>KL$b9Q;;o!uVAxgCJj63=z?G)JXFHf7OedToV<)76r=KV>pMKc8c1``E*b zVazlsEJmhAmI=f2(h-rkY%B`!pvoum#GLD;#6*GP2@-pf5?{ zjq6tp5^S11oKCP1$v8c#pJ^XSOn4{Xof6~p?Yr;@(K*liEGF$%IoNTA0@8`r)-wZY zy?@`&OGzyO1o*8jWD-AWOv;(V^S#$BQ;(0S^|y57ubIzFy=u!&EW*9-Qzk{0K02j? z_1GFkX2E1H^Ajr46pfeeYC1IBn`!LaoZ>m(kCfj3yk69YX#D5}ceJ{W7dr{Kf-aH1wJDh9NbU})kuR15>DuX++%05K#HW&RF!#6aUqE?#~D zi-#nT750_c1P!@?V!LQE0v?GLPV(m09}dBxFgj6why~d1F~VfjH9B6RYvh&h;45^L zwGmr7+nl4xwZ*ZHVb=$DbAOaDlGq<~*5X8@_6S@Ebjh_}@b2yls!TggOZjj*K=zX-y}aX`C8m}@A9oJn*6!m zZoGn()I?$-naVr-)Ra7zM}_^=j`YqkPF$&6eoCuhZJm~3M~2&XXQL@{j0tbu z#gtiW&H3OwW--tKnwTEWYJ+cO-h8*ArvbcV$;IjO(Txir9wa>s2<8(__zGxk$AURM zykw1tRRUeRU%WK|sOaZ-qO3QC=RVImv+gd@ldJUOR;2}(?`{~ zSIYXgzR4C70soYm(l~kRy{H+Y)p)3A*%!d5^5O+TTd;B6_h3F6N#Qj1+sY&}nY8X& zysz9XD@Y2J8OxIv^&6v*->$)4-m2kT4eyETuNiQ+>8`^@Bx;yFPbR%D`-2qqnC3ib zx?uf28!emonIn1(z%V1}fIz3pi!YNPzM>JxJln#w(Wwz4&RAmUgFdZ@fddv52xN;z z{25In5R@B7HLm9k1ps|KlH402I>NhttDF`lagGe&(K)J_bqbc4Mo2jqT%Dv%^QRCV z6$>EuPH4~0lV+jwpm+8S(hxsbO_v;>ReCuaYJ1EBzoL=(hc~x^oaj`||9|mdpE{N3BpIk3d>|w!6LCtn z^B7lR?9pdCKj*wl$H0T0M2LRe{je!9IR?{*bZRKZd)v$~OsfEmrn1sCULRhcoub&=_FUrgz7c9YHWbBX&Z zq06S%S-@4;9fObEYmQx?%-0t;Yz$6EOx@1nTX9Fa*(W@-d)mn(1?zPyq^NfTzwM}i zU`LlHAKmdSx5sz)Rp3VVz&S%9y-F?8mNHLNrj@x|3v8aD8`@Wlc6jJwako&&v4a6k zpPE#XbbR5o&AhApm6AeBo_1{;tXkacFk>{5B%Iz^;JB94A6D@OKODNA5Xul0cRVRM zI$FgkCr=k?!hZ@1bhY%pL#>1h*KI*oRZG3TCnU9eOd-)&XjhQO@*LW;7LHVR)4R0z z1XXpzKX!Z%w4gb}0CSoa2`f_$0)m#mim>R{kCsp~uC=;)d}#t13O7u5fo{}**kw0v zNXjV*Wq=sh+z{250Pk1|GvXh$9Fje8+p?KC@2_v=tB{|nWMmB)n~K~D;F$B#k^y2(Rw zKTj8oLRE)ifj8t8(r>1tS7lehA3uDRp8P9RBM{!45b<2`9r6!JFb%N%MH~VBl#Evoyb4=YVq@k(pFS^GxBMvE$7eKP<}O12bEw44vp=0ba6YESMlddm zPX6UZ%f>G2#jjMZXN3glL!BqhCL|Aiic1*++?PH9*cc1eV4$_+Qs6U(wu7=?YXNT4 zU&<}5G0yWUilZMZ3RG5g&?}DuPb=eY&DlY{m1)@`vj7t|A;zgzf2-!~DE#03?9EyG_wDu@>;`5!gn6@qLW(%fs%rU#JizyVMM0`~GIJrEB)DxdUG7^XK}x*vZ==TD7Sp8MvS`vS)a) zoRaDG6*AlT1kXJnLK$C@}3!;($>Y!yxSxeJP_>-@GmtgZORZrg+E``|L zS>iDE-k7AxtUGB&4g=g%Isajx6>9hfKs!6Z9ZJGjxnyk^v}8T;o$tFf z&1_jp_*+!(4UbDOf2#sYkg#zgX}iAo1D%rqS=q%)dwi=dx&zlVD9796XpZ(bfv!5x ze?3o254V(08Md0CdkYA-9Y%W%d*s4ZVJ+KPB~JO9oyW{tOji$QbT?L#?cJAz$-=XE zH|bMT%$xHwK*;QS19iD7Bv3?NMSEs(-;9TU?vTe*nWzi099`BVqfbqjW`Z`*9^m$` zy4c)Rmzg60MMx$FgH}(N=FtKzQI2(t~_0fMy`@59CsQx*tM15 zxz;<|GXt)O0qnD}O@ZKmdf?=+W#o^()LMB;!AS(E%HZ`MB?2OlybPe@k?5bDk%r{q zX0Dt7)S-SQ04N*GKELaSg(%*JfBUFF0G#tn2HUC~K7BXUHaWS*_6(pBs-;fqW{g+1 zX`e@O%Aix$dEF1m9D*xw*Oo%z4hL7?AN9?(Q*j9*fRbq?*>MHq`}Zay^Gr}_V{Bw3 z@z$P;D0)DUI@RFGpPBDE`_uvt+vh5#tNr?4yIGj{Xd>`?8jde=3O&+Z>*p7OZVYv6VA_(}Q}b92d=>bD5iHvt$%l8lDWon%Mr#c5tNY*Y1bFibk~$fmzV z)u%03OWYza{2QLl0109?4D{18Wrq4iwiOTe0o*#<>078Mz`%^#M}vB~gh>2c#1QN~ zF*IzN0$FrpD$%Apkod+}yuN#fHm2P`226vw<+iwvE01kxzpp03$_<2WQHi2jwNTjKe? ziaV|Th3- z1v&jjpqNW4nzder1tY^emrfwk?&@6duMvdIspl9AvK9m87X1w1sk+Y?g}XN`H6WdT z$g@he39buuY%Y*+_%->Sb4h{|$o89+J2m*Kdvm&)`{kX|dxQQObXeJ#&*6lB+hp6K z{+cDoi`ZMxw=8+Lxe#LRFaIf?m2?S~{d^Nyfmor4^6-wK2fsjzQN+SzW)k5qAjBpi8!#pfLvLMqqadXfbO1r1fqGl(HdDl=|Gq zU)quN<;H-a`TVOAuif+3Ifm4(a&>`KtNI9mR8Vh5)+JTXcaXa$ZKdY;0})C*QRZse zV-1T(u!%;g9ib2A8=v=e-$ymp(pQt7!8zfA)YTJ2%yM zc6h`vIqR$$RrvnH#@tl|_o9(o4Y1heLo?faiBR!N3&7nA6pwkK=R{{Hp#0bE&d>aPV z)!H%z2CMCCyBah6w*W;wpV)Ho&e(DdcI0HqKX_rSACi$BNk9ztwh+HH;HJ`hOD$duV99HhR1duD^qu8kenM=uj30m5d0 zS%u!|o}YLF7a^m9c{)eqOgj>k1CNVyCb(qwY1x3F{s4YIKeDikMz*F50;uSL5lY9`5{UVsN|a~yx`c5bA>hPB1&;$+oU8`Bms ziOGkZN0i9!xI`^X+1`%;z}!458hN%KJI1`2rc5vxT;Iz4>2kNZpuRmeh9`_I2=>6P zerx6=-!-wgLLm5cyGIvsIqmtvmA(}$IW`~U0!~dz2Z^-zwml#T;hW)Wj2e){#9(MB z>QjzfFlSWm9C*fR&EjR|t(^HqGAdd5kVJktgWVc{dl`4dI!K`9+%k+1%_b8MuLo$# zh#n7e;~!}TzHv6k#8hE`MlP#TA#0*GWd!>Kr}-44@#&a9oP{mYJ^ZD@)A7E&!RD>c zbZbnRVTwSPiuVRPyfY{jd=^u*^%L(+WNnwLl<~L?96?f2^eo5*$gek+9XU=*_`e?% zE@GI#HvW3fTc&%zED*0wGIGfujHEm5YkDUC<@n3&di#W_aNo!7X^?uJWi0lI$L@jc{HvT7u}onhI(Hd{ z6TbLWgpT0WLr_1A%Gvv26_adeJzKEP`yg80Ob1qwA4eGUN} zB9uVlA!RPRnr)`zemhVGn$esS%*mClq( zW&!aMJ>U6_%lTS+$a~N$3;y3C+_L7h?F%~g3x$5ZQYgy263@zCLy2l98;$;OYUfb% z)%no6{M>V^*bD$8+;CtNUx6V1zR}}6eeXJWohW4%SYGJd&^N&R69G$;8#3Kg6i-Rj zT2P!ZMvx8JZGoz<1+`u2DKB`MQXc!gb-XHeuw2|4@AlLOa#82*ikDF;e^e0?jL0^& zPHF&ohi#?r=^*LGrxoXpmGPsF`L0B8g@th2@7;TwSCA%jLZwy=ygpZ!yh-U#SqLD? zo~7MYQN5Ho@_5^O+c*exkXQIRKYKu$@EDI?>nUbmWl_kn{!V2Ek;Gh*R-j#Z*CB8I z;VL6Mxzxrb=%w7j@p$BS{dsC_p*AP`x*yA2@JF>Q8!v?lX{DM)_Nn_4@*TLs7~ki2 za6-_eAHgNhjdb^&YN@Cx=7lFpNp}w9%w~XE9SwV%vMLbLa}0b?_ulm~>L0nF@zS2k zDW@vHIy^3bdDf5NALu1e8ekmA7QBvQa zg{yiu9YcWG=!zVIY-rgUIkQEN=GKTa4_ljSChPB!p*EtCj;t+KKG_3JumdXuIzmV} zk13Keousb2ap;LiqW*UxSQ`i&rTKHektcLqzk6+=~v zD?Oy$(yH6^ng+>C3RTgm8g~yTyq3ZMjsyOl0szf61u$n<`Gw1%Jr8&^lmB|Aol1gp zD8!PXTvdi>T2-$?;n!N5%fnG)soF8%P9t6dlJ$OgNvgh|m5)NzgWR4vPQUx+*ewT|~tvV7e2Ip;KF zhB`njpxH|$@bp~N<8!``iyG`S8Oe4AHV_%{ywH4CspS}Fx?gxOJ&T6xMeEoe>RivT z{+>r-rvl#uwFq>;=&E?J_*0jsDxq(hVlD%%73T7F z8tndfdp|p1XtW^<_>PoapE>Z{San=N8A&tvEl@QK)&pEmM?xQ+)KL38NXR!57Fp1i zyk&e^0z1>tbqf?z_{s7Ez0EyMk3A_VNSf;!=~MEQ(udj6fXEx0CpOLnb&obT1qLmR zxDn(*k7i3HWP~oxj2(%li#TLchPBC&YIF$p{B{D)%6@XPT<0_to56`X0B;p_@DmGe zdfWJaNn<7G%4+#_Tp^vK0iQ{qSlT8MFp|z#mix1l^)zHC=U8OFexshxdrsbQ`krNMu`#QT&qw((N3I`nNsZJgAYm)31yO5LDzKTF?>uV?0UvNu2YyU_5s zbJS@b`!Tr@Ot6U{F^bqQzxqS!AR!lSsS%MmIrcpX$zEi5xm9UFps!y7Ir=%rKUIT6 zLMU08oC=k~=?yVJPDf@slJC7`m|RZVE96RjhzBokOt~h!YpsNKmd$`Pf1W@bLRO5vJH??3%gML zA~FUw((T7D8{fFtMAufoI{NpeYHw53aBg$Z7=zEI2<}TR~ELQ zS9CvIa(qDafG>{yrs3P)>p+-jb~jW3C>iu2Cs93GB|q6zAx-p=CLD_u{l$^H+~~bZgm3^Nz6WHbpZdT7;nL9}K~5wCSq%mkdGwDn{@7zMo1^b|L4FZtqER*ChxY?8 z#~2ZMLjqa)58Yn&72@C+3ZLK}Barl;Y$G7o{0{zbLE;umZd!^zV;(@4eQ#*L~lwSQGwKRf&w4kr)I5kv&wFe+~jc(ZCNo zAq@CUIlZzJ2*eJ0C@-t=(r{y%Pn`43Wqb; z@PxtNMLV#oPni6Qio64R)T9Dyf(x$T z0#qB{S3ge4RcU&+l(MozwtHTU-JF4l z{M)bp_z$5>H|l@?e-OSsdppuGNYdEkchc68Nu=3jAj~vQPZ)C;y)hmIs2MjbyMum46=CpMM61K>pt$ zTrT&2SK*)I^}m7i_h$U>cK(;F@!yQ}SAP9(QvH{b_}|j@SH1oJOLb0Sef|AABynrH z0Ob*9Z0wp>Waamd7UZv`k4=Giv!D#(Njx=$12|*VGha$G?*_PJnn?Fl%@Gn{d3mC* zpjSYrN($*)=zC?}b`K5oFbGm~!_i}tvVSf&z@B+iiy2Eq zbsSH!>`>tS!^`FK zBjE7K$}xVP-TUkD^vqqdI08)ZaXnGjH zy5cp>%iz3i--tlc_^70oY4ctJN@a^v_0B3of}^ye)+6#vpwEG>w4$6M$_yzxUp7u-ud z{5!&{4DRTQkf1<}?-f)9IN}PG2IwV!v&)Y-9e<}vxCK7;p)S!kMXN{b@zAhP@DSvs zh&q#nR4vuz!#EUs)I<}s6BLxj5-dMqy??;4d=qpIX^$r`bMm;2iSZ5*>*EF=c8y$+ zRS@eHckQsvn^01%A3btsHL=plIDvRya6V#0O}ECEUXPGvQxR~7)(we!x|~-5_hp;$`oB@$LyZ@bRgz>n|xJR^YB+7#NV ztyJhL;kK9v3xC4Lb`TI%-}*9}e$(0P)W;*Y3V69|LQVr_Y;S&aoOKA9lYH93%}lIM zdDdE4+5XYTi`U(Ni~a+%n^$9tXjl(j;c>SzkMnmBh2uhWl+1AMWsHXF09(V29Ur(k zZLH4g%hxQI+a#y6lGYfGq56Qpj!Q}~Pg7tKVXAmb^q*?Mzi3YkKc1wIEu%lu3A5gQ zV+H01E#ZS_)H~g&o&?#N=Zt$`*E%WAyvmW$t1EPkT>;0`cuG9ZHeBd7;m;p{!Djqp zumFsVeFcIdh?Q@BxqKZBiZL4;Fx4d%%ES>eYj}4pLHHTb)O-COp6uz(=QTE&89gc4 zP7s&(FV1FNf9nY!`G8VtlHP3H`kBa9ZD=vH$1q3QSkt2^egXQl<7JKYxULi|7ubel zy1F%XsII~b%KxF862)~`T7^toQu80i(8L@X(;{xovN_t6mpnVyp!o< zbYVX(k+G1@&slRe@eSE}wozr%>l@)C5;fxK#1~^$cS2bXZeWka;W8)fDI3hH#*t$c z;-qL#X1bG_aPYLhnQ7gX+nJLN@*Cr)*%iWuGM^b5>Ogz&Kq@f#knS&3Z4F9(qf z5%*zcB0(1xQW7b>I+uf0SFqAMZ0)B*IypExh|o626gpGO2k8`XO_I5G{h~~4`tJ%5 zN;&E7P(-%KNA=L&#gjVT^yt^8v&>QF*C$}m<}uq#bAfUG?WEfPa4Sn4BgLSL*Sq(tiXL{m>b_Xjz6dUXee_q+os zeQ2>u&?oKI_CRS~udqG_EcMeUfc$FzIEx;6jP8U1A724NncWIYgf1lG-z0m8DH=zV zW4Vw%@=FEPqJ4C`ia_ym3PJR+Sisrt7#NoH_@MS|>q95UQ>CKMHb^D>1zxf7V(a3J z=ceS11?n&qyke|{xX7O1GiYOx>kQr?vromfuFpjU?@J0)V_5O|O-81s)Og|0Fh;)Py1T6^>U_RROxcMKgbZk# zWX-D{7-`0*=*gYSbeE-|S%Ds8l7}NbTCGu9TVv_4Fv3?2`8+K7srUFj7ln1xi`_%S zuiI#;6EcI`G=s#)CZB&2Gedi#vtN>AdxZuCUPKMc4Edl89F3&#H2sQc1#hCPqZ$g1 zdq8x!*(56?ZO|G5ZvGBOQ<-HH*yTJ5K)DW=-5{wbq^?-*WE``xi|ulj|f2P z=eu5XW7>F{h0b9M)z0d36cy4p$kDA<3eL@R#$=zFgHI>!?HkAmF|~W)9a5$R6TD8G zsgr)8mJG|lcfW5leNh_W)w$MY%#mpXHE-rE1$KZ;T_Kw-+)L|F^$K+4TO~g6tsom| z4%kc(dNwOsG@Byro!3G6`S!p{44LEXDEmwKz*&V?=hEDBArhess8C+fJL?wa-6D5X z%u14|c?3)SuZ$RJo!r1)O_^khRbi}i&sZm&&crV*8M|_% zWAblZQ{@V{BgENL3>}bZq|-$DDn;dk5uLCqM~u@vYRtbNw~F zPN{w0(&9T1qH{E+Ytvg&Q&1{0F?x^86g=H{VZ`1>9D17Axt8%lcMrego*@i7I5xhX z1;c*w3a*B$CeCJD4nguFi-&mOHWz%%%C(j1+F!hYambDf2@^G(#`L8R!Ur$6*r z7{)6sO2vz9xbVJ56s6>@ltr|#1q;~O*nLR)en9{4)#W}TNW&YJrhZK`@C|eKgj8n0 z#K1oH`mF|D!|>M-rS8T0sn!4;E66E3{mJ+U8}BnX7)@;sl7I?yo$&5 zHf^D%0k_J(2V8Nj;bSJH&7(%qNKLm6Ew&6Hr%aQNBS-SuDM}E(gwbT^_I!>M?og(y z4jY3;F&G6f@9_IU4wagi82L*yW+k^It?74GF%CnWFbwE3^bb({jz$VMlAIJ`!yc>=Y_m0Y(8~wZvD9~s3E!GCC)KFje&5AKB zmIL@4^{R9-F|SXx^=8Q!QJRU^3#jb9H%)$+aO3aXOrjWO$rP!l@EE6Q?G+AwTHZ~#wUxC)X=W0J2U~hahU4Q_)Fno3Neu#aG zXd{3u^i=7ftYh_H#&Y@*Xs*y16>t`YhyCtNlPP&h5b<@ng2DpY zbs(xLm8oQe@A+LMaCp&xGj>`u()Zjbs)kKb?gXA#uPrd9sd7dn-)36!&bnEh3_Wei zT2WcCHGC+MN;l&aajosy@FZte`}GQoRr;^9L9FD*Z4+%#A6aK($mU)I&oC3g&aJp0 zh#}Nw2^|$%=4`ms`@ZEJUCg5kVtH}^>b+1q?C%K$OL4woDB|LjtbJ1xLKhVV_kK9s z2C7J(7(aP7>;-f?2aha*{*RPH@!@bet&4H-#L(u0rCiAKDdf?!-U+3P1ncQBxdrK_ zL_~VWDr?<~O#FEjGu&7Xx(#3QO4Ny{Mn~LJb_APGHge1TM1VSQAJj~tq8>ojGy4^N zPBJ7QG0($|B{9STK z86Pn6dC?%@H@U#bJ(!RS{*yYBQ(ChZO|O3%!`Z$Kd`oL&K)G4nQYz#oMRQ(H(c9l; z#ZEEyQ*EgL&7LC@3Y^%DBLT^vwNiOs?ZCEUlM#-&H@7DPp^Z2{s_~ygTRD1iBq#R? zF;$sKYXDM{3^H6hNV6i`3S6t2e>&GI)t?&aS9)82tF8{7%d-cTk_xIHE#@aDfYK2` zj!QV|HZ+uE&3c8O{6MBlx|wkKd_hXTZEScZ3Pm`+SyaZo0{i6# zyA_@TT@O%J`BvC6^D2njp_EBHC_xV|x{cc1k0&y!v?$yMai`Ff#2tA%|T_pQlr6qF*sAi_ySQ%I@Bx3Q0V|O~AQRBtglk>L>sJjK?r;R`ZE8?3xRgl%3E3qZ` zK4ZVAp+x%QEGHDP^&>cLg9v)8y!Kmh8X&fAM{`b-z_4*w`U;NS4#Y&B!7)VhGm3C> z+JQ8U0ZJnLD_B@J9!0ntqS+4r4w1p{nfb&ut?u|5fx+6D&#gtgTM@5Muj=)}0+jU` ztpF6RtsvA=)O3Q>(km<+|#+#nc5!`ZcemUUXlmf!J*vAiwX$#m*u^{S;+x;=g+17#B}=BeqIXg#5$`06nQ> zIoH~e(v087TgYJ84c4{+TPf(V^~05~o~{RCp6$r3Rd1tuVMO7!{DX6p@nuzS!4J_d zj1UDKYR*v(zms2bn<$yR5_;dNMOsBOU_AU40m&1ov3ZnC!5SwpI;^$w%rUF`a5bdS z2+t5yChJjQv!FZts*NFfOAEB9Fc->EoJ}CR;}NXyNLYN*qV_r)Y${DnKEltqadWEx zhIJ>4$gR?tJG@J)2FE&oI#mhO20ghFxK9w5rn&zX*pf}lcTjTRO z_gb90yWe>Y1zU`?gBz-C;gdAc94nPKudc2@zYze(PFYSgeEN{-g&O{eX7GN@j#?EC zz&Dal;dKJzwXEda?Gr#XfH!Mrhkn(acOg(Osano2@(6h`kk?L=@}rNf#PAdqkmiW- z<2aOHXG`JjE()K%O9c>qb_c@j6kiZO%N96;4Sz8b-(M=+W+j4(!d*T=$f>H`i>8|I zECraZvq6fr!#2Uz?9`;GiQ&lfQt%Tur}glor!DGDjs7=-@kRNZN!cYK#~}|e)?_1R zH!NjRk*sIXut^_$yhQLFFlvAvcE&CTnZS^p6 zo0BW>#L5H6Ih8|P@afu4-#zw`X7LA#e|rI-=d6STXI3%tKtHPVzys~!+AZSVRID?o ztM6eP7q$e#a~`cGofB29gQ&*f z?yaZ$f(=PSA>C0L6d|;z$J2%xVLGAr%Ljf&3P7G5KG2iNTZkTsy=dYb z4rDG$l&ocDLY+_FOcBHJ+!RWYBoazg7WPxV>=!wD!~+Mpr+ZDGPFv~0d4?XDi`ED; zWYGFbU>0grVHpZ?BqUZDykAjMAaE=o&QanuU-UMG z%&9W>=Z%eLls&nW)_zCxE5Ted9p9^!O5?+d^UJvp(cwQG$R1wAb|TXk-*L%J1AC6r zoLsvDncfkU^11YOrWNH~T+xDy{Z`CvA2DKx4S{=N_X$knMo5&Gr>vQowi6upa+J{A zi!O=5rr4l%-^Zn~1w(`a2~Y0R zB0-!Sr|gAJwET1M*4SHW3$MV+1>W@|vYK#2R$lseW$paDxs>@Ice^A{3IGSmC6NL! z-{P?$mt0-D=`&(du2_G#*NFt}u`L(vhhe5KQZpp@u89xWqVb?sT~0q%clhZ#vCch4 zUrm&G+gbFUXKx5R)q1|qA9yNZBB;@CoU6>*b7aY%gfct;>r<+JO9G?hn_sX{jX$l$+ z%s6XTvflYa5cubP`$uDs_mVjUb|vyTyBm0V(Ev}mrqJ-nWhFt`rYFFk6&>cHe<}vurdCPP()Vb&=4$b! zQRTGW+u_XPTW#+jojE@k7+BC>yrJ)U>uZYeMGa+5ApaFSs$j;4Q7KDi>UoGyw?^XC z6TNa7Xrxo~t+)BXfDvr-a8_Pa`2JAp7O){gI;}3^dmk6F;XA*`PT;LB{aErjrTFUq zod{`rUcv?U5Br3W7hq@W;$3Idtk1XRs_fs?^onuSPObdRhC^|pa+lfiSBoTFqX0GO z6VDtted(Ra70RE`i+z)`Fz-IsF?RWXw=28_PEB+jj&}dhB z?`u74L~qBnfM24g=GIk2MM)AqpTo&R&mU^C0mwZ+W~o-kE2cem3s4JNh}hie*iZ(n z7(3*9x&16>9wC`yo`&MHA8ulNUHw5Hu7X_I@o4Y?;;t>Jy`&bHWVXo@qu2pF z-Ybp;)q4KU!JnJ^`CN7cP{f^U0#=uZPyyf-|3-&^pb0saty)QxWRBibn16<5rMyYq zc|uwI%5>gRj`4h0=j0)y<0Ng3I$W^i(@xkm|7Z6vg*T~Gf0yYYJfL2*1SkZ0LR~|{ zjy@&3=7jxN^MUz&W~SQn5A&V5_iTD%$w|57VJ+Wv)tEY2_WXi18HJq>5vSUCC*WgY zcvsQFf^tuQb~P|cLG1S}HYPcwH+nKJm{&Z>%(S+_{$25SGs9Y5E4?w5k>(+R*#?sCYIndvW`p zzZCRL^-?YwpHRjCeD_7m+Yvbd{AO^rhR;2L$v_NVn6%)TAd#)rA4~kTDjol~H0COi zDLFmUB){|k#K!vrBfm5qx;U%hk=fLx%kCNqZzb$(T9>|;##TM#@TjA#jt6@DbjZ~z z4GV3YJZS}`%|A89(09PWQj9ZFGXc66Y(%hwZ;B!SnwOT}(&{t-a?--NpR>2`1-P7~ z@kdLC;BX1+txTm^Ho+$S3dE{C=H@~yCd^a<$#PAH0KMQiz@#lQ z(!y9L1=R0pkm0);z34BwE;6r;r89ka%%Sobo9H1-TTO0hR9oJ)sh};_6A6ub^hB`M z_s`*8K1|nKHMr1hDN%DDw~nevU7GRGk@LoLV~5fk>J7##F1EFDJ1%0?AL(_50EQ@I z?Z9ss#9HOAfxh*LP_V_x4?+RM+NW~aR5ujo9?O`X$#M@Ud1$)%bPSmf-~K1{I|-24 zfUP>)C@6l(S>FlepjGCGjawY6%9j#XCw2Q~ZCAAR>qPH2SM%F}<(+fZSns?wK|Q&^ zUIM$x*1LUU3XP4@-abd!WG%V{rss}A%#ZQLlmZp;4QYi*z(<8)?+a{&OpDJ=H{SSS z7~ItZ@a6inI{6?viG!FNRKv*igK3nRHVi7*Rr_qMKwMj6i>l`eA#328EqE{g5wBEQ^Bk9d-hqKP8FJ5X6-3`9AUeTiF;~apYYE z6P_R9aZjh&%r@N`S~4Ci83fmceOE0!mJ~LB_o?q{+`DX87JS({rirCa^!;5l6UdvB zdKWjNl(Iy6O#Ezvl^p-Z1QmO{NW)ZXa4fp1i0!FDiMv@ElXDa-{DA0%py+PHCy|436(Bw~mEQ^<}_;EnR!&h4A87q0CZ{^tWu}_ELw-;Ui zAjtkMJ1=3E4f7w|>TQ7goT-5%%>BzR(fhGxL6 zfW#F8Nq`pZLbq3%q-_G+DL$Xq{-r+ChfLl-I|9zNgi~0TX|xpN7t+$TS{}H5_lw|B zi5_oGMgiT7ZRoYg%tJe|C7C-fW)@qZu}*UPsX)gPP`m*q@b!K&|K5}j%QjUI4V|$^ zWJ(P%V1szCzLyyCHP8^T)?S&9yH3$E*dztW)#SI+wb4FQx-DuOG2}pJKm+dL*?!4Y z@1(gwDwUU^jZWTPwFNaLbDY$Qj3}11_N}N*fTx!aTC!i+OtT=`3qJcg$pTcRdX-s;-pCcOV_fnVB>bRnujw z{9iNN6kp8Glzga=KaUx@_)VJ~L$NvLaLW%ABD&jfUQRfhe< zbLs%g>EqI&P01O``y`!@=VJpr`@N*fbgTMm0a?*(p>8GF;4YNhEU8f7l1JC;O?8|d z1{mQiQKeVlb>T5TX#lg8L5?7e&S7*jX{=6gcHyVKQp~#-t!ih0B(YQ00}xSZjd6aQAhqu%D3O z0Bk+MVN;;ts}e&ljr)o5@_?Xt(4c^og&&l6NS=n=eF?CLp-4l5&oc6zWpE~W3gmZu zj>aG&sVZR|oVh!b3)nz{nBrHq>bh&fbdxc26R*z6DA#5=6sPAr4AyY5h*e2G&}!O^a5*hD$$}%Px^G0P|aXcGvlD| zyQa9)t7OSrF|Ci_`)$0|v~ywBlmw;P!v^ekor| zRcA9i;Ds5MU>$7;9>`Xc^teC=ks+WGBJcr@R}p9m>%|Y8>W7hfiUMTciO25SFJ(#g zkLyMfpG)eDrcAEAJHO!_?!&5@e$71zmq`KU@7J2YzU3`4C$}LW=)%UK?_Zh_x2V&E z@1AI97^gZjPqW^NiIEVAi44e5=k3s6D>#Y(FA{x{W+KN|eNr7gxVT9jW>(chKGLxO z^NDCGay?PfxX03s{8BiO(Z(@Pm{*qXlNrYVN5V-*X19)o-S>{MRfGs042-Czr4 zCI4o^xxDtKRzJuJl^8ka{1?>SWW#Hgq3%&z>@UZq%8r(fv0XccVbdqW|B`aJ*X2tE z)fi#as@b|$Tm1O=ZE7M^8v7QjBV`I1j_DuS^1E^6pnT}>(J!AR)?Ejr+43iGdQ_=7 zdFf0x#HS*FZz%ZEHx#C7Oe3n0d^(a8@mcy(3%lvjCpszaz2&G7vU6?>DB%4^HbS;6 z=5RLQwc=??C}Mec2lTRoOSscx^V}(HZ*-#z3XPYh?3)I1mp|+PqaC^MAxb5dDRt^dHmf zRIkK~Q@#)XE+3X$sKXs=8GIC~Y<*#cU<1V>QtUN<{Ygk`%!j`|%{q?)%HXKn(xXp? zz$%um{wIIa+mlPHgk_QJv}%-iu6f@%IW5+^Q{f`dcj~5O+u3Y?`f<{yg8M&dcjm$T#Qg9+(5DqI7+fg~`_nE)-7hbCDr;99gn zNg3Vgz4soyf63DD>%Y5QdMhE-9}cOubI5_h}BmTk3@xKF1tP-+UGM1dY=R3N!-D9CwL3h|#MKJbI5M zrKHz~t=%+segX~utO(d|-R>$Pqxr+!&8-o0QRDmEuWHE$d8)Q1+1fd+yZ|%Ld6GS@ zy1zfglGe7@*u(R~@Ao|uN+mdLibFsETl%!*XaLablC?=|3{XTKms=An;MruICB+F? z#h5*|I?0O!=v}%`zSn;(1xRE~WA}*D7G?Z?APkat{aJ~Q%4W=dH?w%&VyrXF#Aj-1 zdZZ=j|EYg7+9k2QjglNcn&~+lcUW9C)P`IGn(evCv&q`gjk_{!h#fh$gH&dMM=@B{ zw-sGql|PLjD10(v_BZ&cPH!bR!0HL4j=7E;G9JyU#}95s8ba6tI>G&!`R8^_T@2VE z(YHUZU$T7Hp4&}7Zc})Z13)Z0l`VAsP>XRgcux~9-y}itrqz^P7LG~!G{YpnM67vc z#ziZ3{Q$aZ^$y@v?bD%2wm##zg$xU^4qJoaWwWmvE+T4`W?Ai105zF0ZmJZ(;dR}j zG%Wzr_1bi6^fNO3#4PnQ>u;=!J?33+pc)-wnA`MpqS2^XO@MOm0L?c@%LgP#Nsa@d zdw^U7LgE)90E!0f$G$x>nv9>5n9m2$-u~+w9>-Rwx>ifFLd&b}h*Rins^08pa?R;- zn~iIdPDf6Os;qU2c$Qv?i`(&n)3YlFkMp}vKEYKZr9c8E@R%6_Cwb7gbp-R33)_2E zov*}A(Po8>ygz*%UWKw}`9RdlunDwR9g+ z(#2p|y~&TE_sX2meqI*Yl>o_eduFmJo)kUlgSXM<2XjA(iDP-ugLDji){`u>jdXb$OTa$Skif57gYl};-mG#e&frKI^BE#r%+eEP0L2KEf_Z9H&n4)SCKzV z0nChSKrN2eWv*$!tGI}6dmmbJ4l-G|3J}~y3s(1_h_yCMb%${y5Mvc}gd*ICT>rJ7 zKT_U$SD5vt3~Y=JR4z0Ob99L~LBa&{h`k>B_+g6psdaB>uB?+jDw`!muX-<=*}$;A z%=_3&y|Pu8we0ia*nL)CPboKmIR3+CLE3mEkjBM95Mg4N3$F-sLDW|q)cg<@&$nBM z<_`_6E6$zZL&`k7s%Gt2bg^d)IF;O9zBMnmBSkZO{V`AoymdFeJH-#fk_P?u^td1W zb92W6qxg`06Pd2sluFmiWHRUbi8&5^GjMe%p4$SDAm#%F1PdBLu@_9mk(Q#ri*>Xw z2mr10fJs&C<^P^Q(+T$Je`Aem4}o``lXj%~2X9ROz&I2loO(n;lHuedor z!=uQK?Ql1oyDf24jEX0DDy7HiCdycYSg7C7R|bB&^?+`qG^uqdBjBxGk^kFTP`CA1 z72i1_>_-+M{#$_UN>G0dVW6ZRKswg+UqXxat+?0#9BH-aXb~V5geuho98W06Zk24) zCxj}1f6qwK;`gZ(3xEm8!At8*0n+=zXQs})J%+Sfbl&u>tP*(8-Kkt-#gI7 zpMAO3w!h@+54(DKK`Uk5ovDmSdTp{11@-*}x=k`KV8OQK=|2K=SPZrM6{ireR3w2D zZAu?fI$~_R?Ivrt>B|WO@<+ftQ>iwX9dt!hL&Oc*yM@wvW6`u08g}M(e6aDG&_z0lha1{B6e;2r6IXU6d3MRP4WH=}6JuLOn_A95H5ht-dAi>KGG( zr&F+Lzlq(6QH~E17&veM!oPUe-L>kTCRyuVU0H0e>!R5bra|WK$y`@cJsJ>Wg{rc5 zb{Nx#xigVR{7n9ebgTkb*tpT793+Ge?61U_ZHf!nYbFo@d|Opx&(*I(97 zx-R={3fs$EMN@-QS^;1vg0cKo@>9UwOvCvX^-%{1b>b9%D`k%Y1A+IO!lLzNRiiJ> ztA#B(hod;QNm*N|tZmA00OR>yT96MYb-gBPMT4Yh8<%AV6BxFcuclIZjv~6C*09Ipt~hl z;Lp$=_Yi`(BzNz_u>E-7xwU6My<*t8QMmh#&h9FHmD80shLOO2>X*=~`-)62;S_D$ zw1l%6U~bJa#+X(4g2sJ)2mwAlv9U#(s)41w252cqbhPyyXK|WX#XvFB*`x@`7joyA ziJYcdCwwpaTDI&g(emP4+h903LpAJA>Q*ST8z1|&FaT1i#zv#wHrre~uPw(GHD&Y; zEQRZSSr4c_Y^BEj#r?>1w#C#e!(A~Ex!B?xZTOd3Ueix}>&gf9e;NM>(*R><`@LiZ zV;-!>vm+3a>D7b5dusL$g+3x}1?p>3UiLR{TUcdPzAdc7tDMc8XL_0SvE*C~hGh+` zG>B#sY#i)zxUYe+1#}=WNvkjD>SVB=duo+8A5cc`BXUMP0j;E}FOVP5N(f+a24m-! zT3Y_(%GJQD5xrloUGP^30BY+c>B*B$7?|aNwrHBn_;Q6G z&`hp$2;GSSxEcT_d#X^Q5^Jl6`%M9#yI8gP)&Q}YO8|xDX~D;q^V~Rwf~imOU@6fq z7cQUAe^^J<0qe-tn`IvC>+Xsiws%GeC`v4Ko1-O<~Bmfr6zX zqg|rInPI9U#s}gK5ST4)8E(L#g=mMd*9Rq;&GiTX6{+El%^81Hegc#$1_82W0QJfu?si`GwviTc2IK zbjtkD86|fg6(i{+l&j%qCf2bcEMc?8F1q_9$}XV*32Ur(@;wv5@#b1xPCAg z(@g$P95&k;e;wJ0dh&Qv-Ol^r{xqmhZ7BP9?Qu2E=wNlcr|vb_Zz-zEj|5l`=~p>} z{=j;;^u?6`3WO5u?ethH#D;CIajKO(xRsFzA0gP`foQ%;yd)4T4cM{z-eBGiF6!|{ ztj@=_S)X_c^VRmT=xLD-q8O8&!wIy23`l{fc_@vK1q|@lA=vZVLWYJ-Kcw_V0A9;F zC+@@!$hznB6m_Ab=nlFcG5ZXtJ+suiLyv)MOZawpsjmGga14VDrN@zzNLcE%N>nPQ+$i^`>iM*};9CZd=Vga3;H z&5GfG7i#W*kCCjKs!$&oQ`cCg3Uv2iU{Ti+mTnfwd+{&Qq3MhrHvv#;8lGt-IMek{ z);z_|?nG%1$0(S0OV5H+UQDcU3uQtFAN}64YJX|RPNHdm`ZY7x|DEVIaTJge@Rx4Q z;z1D!6mvYn8DPKnnQmrxfyjt*F&C_@0%Ehp{ovK3jx50gr#jxPOP6|tAEt1-Pa9fC zWd7DB*{Vilc-V2J)w1I^Q0zmVF+O0T304ViO+(k%ecLMOOT3F7yrKE?HuLTneCh@^ zpKpTE|IX|Ao=8o4)Sl^w(BX$LtjW&u&+kCmzdMwK<^j@vR*%H4A<$AdhW|rZd?wpT z!{*57)^*a0nP#T(K={TG2`OFLe^2~5J;i-zA}Po(l||Lq-Ed8U9JpZ&CjEiY)t+l- zO+Sz`oX@2j*1Cn3CIa(c3)nl_eflxv-cecJ9j#fljJ5{#10`((+ zl;&V=?x9-@k28H4R_~BlgW^?B-_C5npKw@#36|XhOom0L=03-BVP&|{uc;Ad_h{85 z6R$|H-`Hz$BcR;$QMf2d^dQrzx_k?O1aWld*Tza1F{yZFjCIj&9dH|0_lAiK_hd7!GS zFkt^q%jSb7a+4D*=fPcSZ{vHr0XgkRY;AQv39##x`SSlnrk8QbWEzOwc zl;ru>SU7aN`}Tc#5m50jd-h`>7o=;qCRoDzN8{L@w|O&5a*3462Lg%l-wM?lP!9|^ zT(kD&an9DWgT?u^Y9-rRlBBwL)_!92ACyjWAyXCCuYd1@K=Jx~G=_=MThcAh3#=WD zs>RBnh|6;=bCcf`^)%Zif6X{6Rk|M4r-G%}l%!gu?`Gz&#Fu>p(xb;x=#Ud@H+gsz z-!tP6|6HOLGWxc#|6@9dGDzlCt;0!yC4jR7GhfyIbY~3kJ1albOoINJ@+vx31vGT& z)#_Y(*Zu3JnK;kbbdP;4&3gHz*N2Ub1AeFL4lz=R{ot13dR{ILx*Zs?pDz2|W8Zv) z(qkW}Q`SQvU3%2uQSfgoUBIEnjC1z^f~Hi*Fmc7j-jG5@GUH}ob$@2l{h26YT`Hnu zt1d>DORbVek-pFY5Fz?|I)V`d~e?zSu(5Z9;hvKL{Rs(d)y9S#jxWumPp z05s7D5-R+BrLB+f1}0@q*);dAax6g1RZnq$;g-;5a`g3KCVcwYZumX{WkV~*>t$g> z%Q@fb8->>Q01ucL$BK{vtecLBYIb)rR|c&qn#%4+vxr>d%LM&j_LdF_sn(C#9{@XQ zBw@M+5ZJl$IeMA)uEPwbJ#uGt6H{6lBTo6v^~Vx~rCUs>eOp5ED?JQ;t)ec9y%Wc? z%XV-X^MwK*31VVx+(iyy;}5|{ffdzdk>@!LCG)WZX>{Wi0M^=|&)*z>1jB9?WJpZ{ zQI=j&Df`%)+3xb|Un-5*OJYqtMwbstVD3-Es%ITX{C-Q#dS}S?TQph$=!0NECp)oT z?}C*GKhIodGzC&IwsvyCacTZ0q~dq1X&KXUI(-vO}toK^6+(p2+IpoC*1tGvmpV zi_!cl<#7V(=pS`8KUL#9z5o>2V~-Py>zWtbu_VXuMP0!1`Lavd{#kq3fc|epq2X29 zX30OW33}R6)X*}&05l)`5Nv}%p1MVy^GWtauEdq2=h0v(BSi%I45;{x2GS+pkm+hU zQX8$iVxD8Ki;)ny`mg^evEAzbn`3997*({&}j}X3XfO#&Ub3zHj&sX3`W&Gl_(s2$wI=Pm(H1xF>ZuQ3jxkb%O z;~dE9lMg@%y!sIXpf{kC8ts_bi|WKqVexusTFeYGpf4TSy! zqV9IKQ z%nYkpxOZSbwC7Rv4Jbl7>Y)7OJ5t*IffhW_1P|N%xe8L(fFq!E_aCb8o)vz4)gc^n zaw)|xX9%h}U|Jp+$0Au(^}OZ@P)pvg zCNSi=v)R&jNu7oH>eB! zI*#-ETOXG#0?zPH*pYIj)k{qa>KaM3cmIP9KZgux$(c$RbUOWdW{9!4%Ft(c?;$0M zV)vFgYGmfkd}sAue#bl^uHsqq=#*hw=+C@9PbYHd zu_qg3QWOA$2Xf|-usfNPru3B`seraWAot`=%Hu^k?fDYYzYwJ+0!oL1QUcN~sgy{A3`ip| zba#U&Aqvt6(%m^UQqtWGLw61J9K622x6l0_oPEyTYkg|%gNGcl|Ez?m5xQv0W2gGN z+XoZF{p@KvyeC309A!C;_2hNEQav_Ds5Xzj<&l8go_UJ|HO>x?4{lsO0&1K$)b(n# z7_|!w(+Q2tnX<>3i4Uv|^(ia>?Rn+rb|uiBQ4q5VAD}(28Jk?*Usk}Hrs=xT7FCB7 z8VtBCuX=#|&$>f!5#!EIQVc#yo=a!q7sO4h%qhqG{G8}GP|kMAA;9XJ5HH0IF_6}5 zWT3Am9R01RmneF^juP|w{x$|17g@CI7DD>@450=))N%0eYL(y4@Htnhq<-sq5AAxY zxb;k@f9DAVOBP%uu85+F*Q_9QC+ z{!ynt$Tan_TYLwUUVhwbO5Yu-j^UY77q)r*3)u;b+HQ3MBilkh6jS)r@pq3G#nlU} zEQ&d(a^`ob21yX%v!5)pdm@(3q$y(D@GBY`e&-QHU3xj(Rhj+im0uq}@i`Jni{z{3 zN#Y%~-dMiBMuc!@EvFFMQ z!E;{vX9 z0@%bw%bwC7m3@X(cJE-aDO7F5GVMwQ^oTk|A1FIXPMOSht+Yvo5IFDWyyTIDHtbAq zG$k%HX~tjewXW+H)%d_Qna)*ada?>M9L_&%&expYTFt3tpYw>pIzhIQ6UfV6Gj`?C zO?8C`&^R)fE4{cX+>V+7+3|Di@1J&vyXhgThV_>;GD}lzM)osmA=(nI%*-m4%xlM^8@H?W^mD^C8oh%3 zX00sWSnsuG*Q#q^94W@~9s)>1NyiM$u`vA&9 zrPXfkgOI#Y*54spq5OaC9>4EkL|N8toPmnjRZ{2e@B@Xl)!+p>-+5jSRCy+r2I;a1 zVHK+{Ae1|7#p{ewIuUL~i`n zFKA6t)v7VQoTH?RJ$9JS%30nse}?JgkNpOpA%q&cws79j#M(? z4tGLo1`ut+mJZN7Iy@U1pFw#Dvq*5RCX) zo_IJp>0$MU&IDH;>Ng7ZvcJIvvu;-i=8L&+ce@Hbml?!9F>9r^!oan$T~qg*8())K z$V!10RBB4)B;z*o)OUH6!(V*!QeIuNfqvX>KU8Y9p8lJ)PYKqGTA9O`oe;Eao0J~f zXu_e^TX>o;JE88d_M2%$JeKE8B<~#u72epRVK95(?w&v{>TmeROZ(MkZS!a(v`=k7 zzSEhrm&+gacdAdp>Pwm#R;S@aE5yCjj6dVB^nCJ5YxnmbFVMZgb44F+jcAeJ-vcs!k7I9Dge&kQZCw_iTP6z9}*HZbf9A!M_3oI+vr|-)R+@j^zO!J~A*n0)xGx zOTG!yRx$tAZ1e+z_L6JW)x{R$D*u#TllhH6O>Q7G5 zsP8u`<$lVdQ$Q(5EsIWVeCeN(>ekIyOfE4{{bjXM40!V5k+vk3hhWb)#}^m_bFp|G z1WdnQ%66f(COdQ3(z?~V?o45YDPyi;`Y0iG+@r4$ zTh;ge1P2XpW+tpk?vJaZpIam)5jq)5!9~d%9I2PuTp~g(-{~>}ZHvqI5`JBXj`*WA zkoLeQaL2-)_W^b=^@?FhGjMo~IW0L$&L;~b`tTodqgyonE#pRFpd1Vct3U^z{jX(d zZHaWi4KVJ+dEA#GQF4KC9B6^RS!(9q`V+N6IP~yBeQb$O`W`Jx!xFxR_7@%nVl(|w z?UV1c4drkXPzDv&{R;I%-_DL=mLsG!IBInT%fC|HobzW3n}cv9 zs_lWc8Afw9-iGk_`xB(Gm^jc(d~2EIo}dfjJRf?RkULLd;7%J2;aEV2OkCj<>(!^| zH*5vLSenC*>0j^Kpw%q!J8IhokgCH=_oZDg)y4U_?1ZsO8OX@FVf&3_&`$&Ci%()M zNmeEO^jRhTNW;7zLnD-)CPr|i(+)_1IzJ0RZ(w}t`a9AR?qq1^E|>P-O__@^!!jpL zfUbXre=a5}Gk6vG@wvGH81b+ysg!&QC@pEmpWitGCvBbwp!Kf z&pwNx^Lv#qzF^C{?oQcw^PX*6N@V)lvl$|1qP)}R65%LG0E!2BJ!zLqFAuxBO#yaic@r5c+3+sp)OWh!$ z4Gs9v_h)+5tlMA4&5vWeQ5_|Y!uFHL(AL;&-wl+tcCj9T@ldk68e)3D`S}-ae;BUz zp8l6FY3GDZ@8kO*?zzT-40dHe5pC}J{#_8=iyrwShN556_X_Qo@FQQTis5I})@)yk zzY7kct(Xz=(xg3$5U{&?r+rC=Xosv@W|e7*CwX;9!BPSs*aC033&4SF#QWNu3DeWR z`V}%?w#rAMr+dBny;0UBm_25dQWa({iVoS}?_8SIP<5-g0-D+_ZfKL-r%r#NiX8i| zHU>9DlLTAA8jzEKVqE_Pi>&3@;eF0Gt83WMrR*?CaAN+<)l}~Kngf5JEafqdJF54p zkK@b^Ko25qH<6LhlUpM#+$X>;3}Q87l{uqMKwv|PYvc>fD7tsu^7VwTKTwKGr_JG~(@H~2T7M1ruTdNrFsDVrTV*}=3DS&K;H)Tdp)}3_8{BfIC41hiHOhT-?jLQuVMbPejuX{ ztNT!K;R&aGO`x2__Lv67>4O4Sh)oP*oo4;b9U5NLGt0TqFRCl0zt#Mta$2Mglv9 zU1zO70+EA61)~ZkYEhRkt`!+-8fq@b!9-9EE^Apm`rlvuPBxWAuA5hlTYtv@mf;ZO zxio14M%dc_kXL>zG4K?HX_koSB>m9yv+Xie90g#PwodTNGOxbH(wFCc{b~}{LYvng zGlGk+NYNVMiE~;%B0;P1$~!IVF+^;CFIWCA3!oC^9pNj&(i^s%9OzLQuXxNItvcYa z2cAIp5BNgToa!iP_sud6Bb~O%4-_JRQ{$9FY8?@ySNvk1w8ch8am{7Ufxh8Hly)!X zMOD9()=*WMh4!=M^I?_$A>cQEHcg~_UDT^CTOtYu)txSz~I$ zq8jDB$T}5g~#QNJB zb5^&frvB_cU`Tyt8A^G#{fpBq1P-#zqJRnSMPWyhwxBdEkJ5h#gf zH?)65VazUTcHjoW!G_*$2N$4c^7eLr)^gY;7$k8g(+mv0vXwYn^CXBJj>IUhd`a6- z5c^R4L(}kOkicS^u$@7pwdYhJg*Z)bOQ65 zA<>NvyGNRf14>jUW_|C9k&R@(-36g~S&3UBH(?@UABtZ)#Y$@ehBfWtQbcXhi<2;; zvDdrol(sbW)^=iPFKwJ+=3a9gJUto~gB~&u;DF0(DqYJ``;!fNqEtLPdVO8xxY{IG zMzEcQ@%#bkinfZ**8*|(V|ppS$L*i;G%dUh-y@POLb#0C{)_lD7?GFt5r^pO)WO%< zulh~LbIwBUwwGGBmf(xV!c4n!%1#}~I#8CFL;b=h0x!_kHgul5;d5q(xVhP_g)N0`li87_QiHvn@_8Mk_) z(<>mrIn-8{E0~vlP8QyN36)4dTigk-geH9v$EII42`eKVw9$QVD#LLVUE+voOTLfR zbeZn*N>b#do==DEoU8cuQ>oc8OLnNI8J!#+{#vqe9e@lF6WCaBCDI2I8mhIg^zQ7R z4?x`6hdA(O08k^7V!!*80a@EGE-_`cUyAvIeccMUn3-3ixFFYu2+ij$=)Agm=Q`Y2 zdKt9!`Uj8XzHD(vY(L3HwzO6}tJ_Q$JYzwns6WF6{dL9)DjNC~XI=-- zI~=!C*B$-(oaQxEV=2*%Cij?^*BXj>(TPA5%a&GWTq(SC0AKJ&y zMqd_n`qbe2;gD0wnzT_s7u$`G!xjb6x2?Qc&vt@ecI|tC@7~Cg_JRhET>grh;rS}|aK**a)6Z#*doHzU@AzWQi zgdZF|^8k2d&MRMqecXw@=VFFOK$)B#U39KX@XE1U)G6TZLo$R{mz!cR5T-V|i${l2UcOezkoBzaoZ5Ox|3#^x$leXgL!CHLu- zGN}jG@NQ7}1RRZ4D?R?LOhj|&^=K-stuoqjtk>5>)@`ZPnh=n$^61BXQn^a?#^N)q zPk>tV|0vR;P{)}eJJtRaBKlr-Lld%4do|lzjH@w<<(*A@qZFY2)cZq;LKySCw z#$+WFNbzuiG-XHU|3sYIRWbUmGq(dgVke?O>AGL@97jjhp(T|84|T_@c85$|#?Gms zV(&RL6ht0M{_+vnZE13p3?qYu$0*?oOa}wE3fiY!&YkB&4-GU6zL_%j-GnVz7P$=A zp)|P1Ey^kWsPA3``hte$7rzmi07sfvbYY&i$Fj4Oa2j*Pt#FN5dgb;%DfEFVT( z#+LJW)zy`=0mr%u$|39ld`eiq{Sqf|ti=%q)&QvVSEO)ET^qc@z>`up#w^7}T|fz|T1Bq#6> zum_KSdZ7rF&;j{I6wYv_b)id+iG=NH$P&m-8&(E*k`#<9ni!uWwm6-zZB15R7*^Gq zCurUsmI}dnuC@mnEiv1}sl2n8`(xP&!j6`IPT$O79)%(?=G0aYQw$9!HZG4&;D3ov zrN9;sKm-mKR!iT<%~j=nt{n#E?&0Xcc!n>z*fXM4`m!y@a_v$RX&8!!{_NyeAk_E-(Un5(dSYj@&-1wzZ{7J*8;Q)A~A4Ii`OM~W*{HU z%K5 zwx>ig%vG_L^;_^HW;@-@IA~%F#nt8RMZLMhdQS#y`7pR0(iDu~KjI%$0dUD6gzSem zfJ@Xijayc60nOJTsG(Z#e!Yan&c=xLFz?LxE$f>%`CYwu(2t(!5&i758P?jWiCw*l zp^F7dDd`(7Yq6C=1W(#)Bisfz5`OJf#MitfsUZ@?{XHf9*HN{w!bD1<5sC(Xdm@`u zaWyi16@KSW=Q$t|A0|4k=u~~%zR#n%n%PTq$f2Zrz&EG1%yN-Vs~-qDukCVC{#9Rt z&rwNdD4f+tCQ|fxOFRCI??rB-EVhjS-%MCKbQZK>Q#eJEN zxoJvp5Ul1(G8j;=)Zrti9TF+PN@aO@S5PZ9rQL@ZumY5&`q~SB4unsNaOr>Op+Z>rcN) zGa*$@gA`B+&-GxPk3k0F{TF6EW)u5=i^5CD=)L)fQ1Sh(vcL*k2R`!B18NWjGuhV% zz=wU6YwWj5eE(s?ylrOgYZXm8t%$F$*zudG?Sx;HQ>hhMFScUyTI=H!IX_%6tk%@B z8wzRi{Xo?3@A9NaR0l^dF(MPITV%nToFHLtyX!6zpX&`FnucZE=(t$g^bA5FCv9wG zZvqv|_DxG$3d_-vYN8I)vz)Rmo{Y=Vi;K`)bOJm!rV3}C}l`cLvz#CbX-n~)oUhvj0E`=SxPZO`Z;?X1fE@FRoDE@F%# zbZ<;yth9BmP@r{!YIP5)B<0|!nmo(4Qkk4UjN2X7a6(K^9fP#iYm06|-1Z;aoUodk zX_HmRB+?*Ruwchhu!P+r@_kVcpoqVavaP5sH&pAka|CYVQ{+HMi47}^xt)o|D4nau zbxov%klR#`JJdQ%D3f3aCPPoqf~uLn19bkO1?2%Pxde@EXm~duOR!~Gm1)`E`w{{H z^CK@kN;11by5t?8oG^a2v9*af;j!7RA*Znq0<|n<)fU0T#j`M~B9Y{k8YW7?(3ByC zQ#B3*Nl>nAAni$lDm83GVJ)ZKBUfYhKcPqYd(&bZlfKswhjOFp!_`EhMVUCUH)7;9 zUPYDPd$hWoq(qXDc;p!1ZYciu?; zmZ=%k1-}1Y=pBDI0m<&6mW=Brh4}0rLiko$)kGYR&l=MP54%QJ$VbS$Ep$seA(zr{ zAskYM@VZrJvdG|bloV-|Pc>V!pZsvs;Gwi-eL8F?J}aVf*XL7v(Hf&9wn_t)sA8$g zC-4b1-OkckA#0lBpu`?wg4do}8Z8Con>sSipC1+f)e`e$Z#a;AjgLTeG9A;6kJYyM zn+$kuZWtAHO2c$Ei%?4cleZ@tFQ?4@|4YX`g&X@`zPy_)7~9g2i86Z3CiTP56;}_? zjxxK_$lfse*M`3Ae)H~Q8T^F<>d1(w?I^daMU~xue&lX?TS0*6?}UO02ZzT$1nfC1 zjZ7VVaEgzOw!XIJ`|`!%d_oaVMl7p`NhY(L3b;Uy(&P8#IyVzlMJEZ+P2g*CGy zPv+iH>h>W#!w)L6LG}op;aa?Ex8!K-blC2Y6s&I4vU1is5ptWB*yH5Ytz5Mc>VG1L zPQBN9ZaDYuHr85yxUv)CUKjc!MVJAZ8F$<$^%vr<|Bhu!061vIssrc)jQ8-ir~8zY zp5DoMZ}hf5CZcB~-myT+sT5oHTf1hkW%c8ByM>z2B0a5LeTZvwcDgL?#t zHJoW(-Hz&?%pj!fzvmY5n0i>TLuE(lKhr^qigU8$6n*6~6GroFox@s?8meEhhWHau z@Gcxsb-^`daSNogzodVpaIe6;rg6;u;5lPq4*4vf2sd8OZj1g*H2H%{Cf1xE=~Lld zLxiIb8`b?9Hyep;oCE|xj+`IkfK4UOvf%YK7JAZ1ulem5uuR@$C1WOAfQO$U)nh0c zL4mt1ThkfV{Ui}*D)G)m;M29;fIgT2)~XI@(GrZpB5K6KTekod6RXwdQ$0L>r(EQZI;6G{B$ZIoSY0qCTCLCbc0ukTXEGtdZEnyM>Na>`jp-k6Os@efSr6D zmbIPb?yQe54X&LK_=H|32Ou8mdEi72=n3HlJ>3?8v2|%WfU1RXQtq8k{Y2M+{EaF- zG^*DXei(ZzQd77edueXRP>av!z;op{ltaa@R1s{CumJRk;oH_=Of1I#9|`^{k1m@T z0@x}QwB^_g)VinjOm2mB=TBv)lK#(KP^nfdc0f&?u!OS73=!oi*vpWkO4sN zyWc-&pD9K0RvUD2g2~a9z^D`1S4)dnIMGF*W^yzU1@LhWo?s7_L#Z*Sx-a2OkJC?I zp!U{6N*FT~W}P@!9kKrL68f zh{6Pjj-#rb8WZ7GYFF-3?qob_ze+lMy&R8SCmsH?`9c#EYe+|5YUWcO$A$wfpx8J# zAGPrTiVXwdU zySb^@#Fw?Vjs$i_`Gv%^$dtlXUcVH!bozU@hiJic-U~XkU+Y704U^!xD9Qsd!GSR3OEq1oiN0O5*TfGOJDv>^k#vVFtZcB?}D>HPmwuPoI4u9N1I7Dzm zBdBmfp7t@W9xDWhs zt$!VTHHUbwGH4`q@(-JwvdFk3*X<3oTG8`T$GVYkC;Q3ihggZf3<7 z+M|PGj)T6ZhYQwQ&9n%eT)eEWLiSiCNdk-U1~&}8aioJO3aN*eIo^>p>egFMZ|&Q<;A_Z_Q#0GxIVHz<7<+%twMfo!*Z22RqSo# zN{ObP|Nqds#CQP_<|RG2X5i5_0Q&fke(c#;rvb(?jd>uRz8C{CD7DQ>3Lrwf@7SME z{ByCiX=|kb8D4ZLtvp-2OJ_ivC_JbOck4P`JJO3tjW=?w1hDscJn)K5hDs?r``(76 zX)3{M$f0{rea|%ts68k79B7c6bcpBc4IU-d*iMq22jlNuIFNgkP`6a+en$dn32y>4 zC0k;xf9As%$gmj*sl~a!J?^0rB}8PPke*y=IdL4Wi5PSs5TNgh#PH2feA13&EtIU> z7b=2qoa(4l{pV7|GBe{IDS$&smZ`1S1kw0s=M@PEg`DpOZcn;?#5s~U>cUntIf(48 z+AqUqM(4cUcF}FSrFbNlc0K;-o_R@i&&!(MIaSYxwc_a7sX0^9YT`)!2z@6V$g!QZ zd?6RT2}~z!9lv-dCzbE0I%i0`d#1_9fV`0|x!3?e-L*i!RNy~=^KB^FWxw=kfG}P~ z4v}198kzcu1(vG%i0yOG>;ow>_@W`lgY+_v0OFIw7z(9DkST5RYb2{s&F)-?N1^Mw zk==uV#zlfzBvs!#LIskZiVlFca?tPX{v>a^sffrrmxg_kXzwPlrwFIYa`}7VQWxxB z@F%>%k&k}5DJUhJ^+HS}?>dtY8k_n$P?c&m7Wo}B3uU#80FK84XGM(cVO75xpqs2T zphiasZ;*e)?yhmkBs7Us?E6Ci^X7=6TKPXq_CQC>s;d>py}}}zxho&qtb$+SK&4Sp zXmx~oaFxr}Wmnwld)deW@D2a#T$3>inZa^gmzF0+V1$8c99}0N^J8xPH65Y@wp8=? zh(!Cdz$lX&La1qFHHTJz2!bw`uG2l7(2c&Sv9ax(8tesavMUZJXo;%iC4#vZ!&M&Qbgh z70Tj&N*1N{Y-oY5Q~Bit0#eu6Bc|=>PpwX6-Amta4WUhn;a`AR$S%@{+PW>@IIxSB z?v_#XH$00@^LRAGkWL7E;_NtOqfh6ZTzh(AR#x~EsuSgsH4-dyWw})YSDS3@b_21F z|3!Nm{{ZQdM$>0L*Y^d(K6)SpaNq}~x`h^w_C$F1i3|xi!RWMug#IwHJV95aU7#x% zU4izu$}Zbi5o3c^iPM$Po<_ZsGlqQhi|7S<)vWL8!vws)rXI8A*Ln4?EMPrFt}vxm zIzSFYUN0JUQ8l=ZR|Gxx@5{%YfiY~kT9QBZ?%rga&FZsyGWg;qSEEW=q7es;@=?bw zx_wDp5xS@|Z5NesUFJ${fLcbmpZJ1(R)VBiT^JCzufW z?jzuM^uD-!3v}W@FARcik(h8aEwS$Ige%v~m->rlISa9_G&*)}&!^Z#$_nQ-dMryF zk7zY_rwW&HoF-9k?GXpQXqX(9N$gT1SAtuKdhEB z{nv>4s~g-S`-B{SO5*$ZLQcZcG^r*_umcyh#W!k4+h5xzPDd%CHP=V~l2t2gtFO&GdI=r!t!Bl;J*x0X zomu9n7T)8J+~qlMWGdEmU;OBC36CfEG{I)(UCrt!wTj+(xuv2T5n9RW{z^$M@rgdo z;g!DVB2vHyS$b92xE-DEep;-w)~0LomjV^e4WH|gNIIu(f}`Y{96UW;-^7btPmta5 zc#GCw2_j2q3Tw~1_2c0;*)&dlyw=BJc8)@>IhX4;=b|N_ywZ0HCq!SNreyW0ez@+F zO{Ac1u=gt-c-vI%A=SMnGMYa4AUUs!Kp@!%0W0TC#yfGT-kK>nD}U;}sgvFR{K_ZU z*E<~%3tDhpLO{dL&x)ZwuEiY|W;+D0H+ZU3>UV~@Z5#~fm7Y`=9j+}9BC+EeZ#A$! z&9n5`Jh&Sh*mqv_%%1xL|9N?)-}sn0@$sPLUEk#GQ){1iG>V`sLu$~Dy15czS`!^; zk`(0bHA^9$sNl3jXK+Vje3!a()zWzI+KAeW7)@#x2ZU;8ACL8~x7lLWfpG_zw>7KWz{yl#I&i}Dr;q^B8}m&?N4%@eHg)?Z$vV)U%DK0D#A zzd2_@mY_qdk_fPTFRk;j_wj(=+SjxHV}144&8TQa;e4@WjplkIoN0Tw)NSjd zCQXxVOLm0!GJ`CEheiLl%_g}~ho$bOg?&Wqr83hz1()&Q)xOtl;4!`cXs7;Wlf!y) zaFe;@jAXOf2!1uQ7NNeGaVC8CIdj3==S_NlVQ27NMS;;89mTlyh05}cM`|5>Pa3nMUbo&q8U5`?W8_9i2v#@-MqK_@y;iqS|}Kobc)`A5-JARkzL<< zTDx)nBXwqT{#|;6;x^w*l0Vv<7bSh5VOlBD_~hK-Q15dPA1htWo-{JK?Fm<+S8796 z#q`tge!8f03vIU6B1^1T6;nP*>NsUU+Hr%E!GoV6V)S@>=0Ga+3C*$F@sU=?#P0eY z2Q^_B@}rbvlsIjjGPgQ*m?DO${?I3wV6dbkkt6*@HvEO1KfAm2{<8}i?nj;RPGXWN zx=kX6;a{T9e7Qa>4sT4k%;sCqV5QsbW}#G;J)`4%f*{q;=F6)$fg8Q(HJ;7ecy5l9 z+U?KX{jBMjqmG1>&7EzlhYDz&}BGgme49}e~VZpkY9FKs6^2Oqj_dj-bX zpn*GUozQFE@O@7tv7RYxfBmux(NV9-S$olm0Yec(s~w`&*)2W1w97NzrIE*S$P(P{ zfJ67to6AAXrIn~P!aWbKncX0dS+Iz05+y8Vuz zW&+wWX<)bfO(62wjC}$hA+Ji5sEl|guQ_cUV{obF>vvV{68vbfTfv4lKPaPEL+Oi2HS(&C*qJ~z`^u1k53 zslo&qK3<|PF7C4n-GO}ZW~(+htlgoY+ofknJCBBIT>9(wXqxnGC)G;LmEA)a%c=M) zMeZ>NAl{`0Dw+}t(}Qr=1SrH^;^ZkZC#LE z(^>4MZTW)*7j2zTfB$$_-biUPd{r|JcH>H&d zPc1tu?t>hDU8Ur)x51QxqTjWon#_5|uIhHf{I9XlDc6CYL}fTR{1FR4G5!mCD^Y1A z!+BZYRM7iCY(zR7M*h#E5&Yax_%dBmEI@mk*y*$Xhe*&K_aZM&%GL?ChNVmlBEKy$ z&7+{5q(!$bce0Ym%70!+CN11i5}{AYsownYS7xKD^_JK^i>5Jp_bt2dZRjqy>sK+y z!dlDjGEMi&oL*Aae~NHxB>=~k*4YzN00~mD0&iXe2D~5P&#b=RWNCrGjq2S~qW3d9 zn?e`RlY6)RAkF&H2Ir%RhkSHc?tZzx;O5-DnVres0r3Ny`OhiK5HsBWg5(1Tk zd+u(3!D$?f<=yOtxH|>C`lYG+3Zyj_rt5v=HG(_feMGujPMhal^1M16jnf3L(rG-n zG(3G^!{PKO?YXjUKTB%&cdb|_3CoI0zlyKM=I9K_$LM9DV=w(-?cIF_=D_CaC|;y~d1A$`&oW0|A3 zrJ9#5tvvwMsx60cVfYbOf4LZ zvZndn{H8_?)#!slqAn-)c<(`cCs&SEn%Kx={+T--T7JAaXkVfYvpy38lH!=b%P%yd z$`Q=y0zG#Y7_NrTB>XxN#s<7OH)!9eW8>$Tzy8s(x81Mfx&iHuSqx$vu1WCxtaYw*F? zQ2AU6$A9YjK|l!THk0iuS>y5SGJN1%SYG*nNc(`E>~po++lKiGe3Pa={vI)Df^XjD zbm_&8s!mZpVyWRy9}0fDGuzH?`ntYAKS3c4I}uryeK{Yj9n8Q8Eg!e|@Ni&=1r&1jcN|)Y0zQ#!TB|=-@cqC*U}bRkl7t{nj6k4aYVUA2jJd@p zY;pZeV1()>|1s)0v}-e<&qJQq_lnYa>}Orx5f^IkaTwp>j!k3dS7A|MN2Gzv*i{a| z$i|KCv-*3xGu;~b2+y}%3qz8^b}&ZP1p>+s$*u$FHCbct_KT4a^Q|atpLZR}7996Le@I9Pg%8rB!7gy`Gxugy z8P7lRB$QBg(0uK4tS@)W;BTe5mA+<~Ms?-0AI zt^gn(yPjx)@ck4aC-G@63^m)U4plT#v5+Jltgv!JQs=-P1Misvi#^dHd`BO!J<1@F zyhwz%-Od@WxR0!5BH=MpU_`HFWxVYg#B0;iGRauEv1^ZHcl6DGdDa$xTMB+cm_K7M zh$mZqFpuIhaw*1Zeg>wuS1X7kTNSUEf0I^Bt*6=dBSz1Yjq`$#M=}}7qxtZ+KD`0q z<7$(xdk=A1avC95J;w*6)!)FA)3M{v%jCg6gI}_?)WCBoOh?03QeQOT%1&;T=|I~P z0Q0xZh|U!zZmoH{%i9UlcgdnR=SS!hwS1aWlUYY61guj(_m5M+6i&&}4;CAs5kES@ zwBXAIa!_I94heLNe&S6yf|5KLkkylxbuZ_sS_DE!XTbjx&RBE(8omGZ6VOS;YWM<^ zPEmZ`N`VX4Lk54xhoCy$OhnP+&x*m6nn1W%{U)zHQG@Ao;R0VJ%B1@kpTC8*PmSO( zfnq7s0qyW(=VX@m^4$5^!%u{ai}Uu~4TbS}8SfiJU_5p3kRyB4?0|B~V&0|c$afI< zW+L>WUJb>J<5obrnlAtvFnSJltc2&dpitWB=s;&igXr>m2S{~RB>?}k3J!#xSTVp{ z&w#_*khIon^l!Z_(|%PY#dzve!sZRqzw~?q*mfQ{t`82Fpyil)~ z!Y#V(+-KD|-fLRsy+EqXQ)qf@B_<~CG@GC5C0I$s6$T7P#Y>g*I{}j~Np5|PYQVam z45g39l>_UR`GKiv5BZJo|KAARKJ9W1tvR&iu0YGYC%u~H@F|VN$)j3@erl_9+J!)n zQmewjH`5oLZp5P{o>-kND+FBl|HeU_7f3KSalpbNZ~7^B5#QFv!W}VMG81yI$3$cw zuI3Xpm);~WPsVTlHxg05Tzk)F5T5y~nRD25?9Rk6Amr7vCvxaf&_mKPQkToGp;f;Y z6Kxox436Q+=oa1BQy#>e>K}OAT~g_hu^pV}PU5&}4Z1G%_=|2ip^cRFBGsr`d|5>3v679VZ z11h5HIrQxyax=Ez$`bp*!3P=>s9zbjL|^cr)biqFbj$B(>k6%%jRtx?aiaZP(z2Hw zbhBWm7kqJ~`yVDlQ%3KU_dr{|O9KB89agB^X!|n}lVA4z7y6dHMb3cT2{H&ua z`EFE`OfhNU*DPshnx>rDYY5e&X_6nEb%HKhB|EhoB3_3%?`?W5g1?<{w{iS7q=-B? z!t-53l}Ni-1iPE?8kvAa63xl7051)X+h*!4;a{N`JhKO4C4)Jf8;{Z1!NcBDMFkcY z57C@IcN`$4Z4@2I_U&_u^8~I8=<_k5qHs%#9c^u6ZMo0lO4L@-pX*AAKA(3xf1qHs zoH;W;u7=G&(|x}4%+|1DRFd-{N;B_63}*JGN{0iU=ee*-)Pe*^c43#i*$)ptQ**#} zK*K~T!8FeUb+axk298qCPV9^D-VbxXMrCOp4|h;5BM4@S8dnIs8X72xWHOH`V{8)% zznanDzaH#>s$x=->TG33f&j)>=ES87n>j{H)ASG$`yg*OTkcCcXaf}CV@gy2UPu#2YYv!P zlOwt$j_d9YC=~qQA=+toC)b`5Dmtj>l&W?KFlQ35ZB)cw-X=ZA+}F^!EJh^wUx@o# z7-TqmZ+@=km*oa9+3LNXvQe3*2(omPe7tmCPweJKK+m5C`~|Y9-YL`{a3F))uXz37 z+=Mm9-}vK2j351ZY)n*Ya=B0z+Yt*Mlpft~*~!_GbhgRZp!lO(SQt zmeYQb(GR{r*9r>F&*??U=#O8g(8Oknio#b9mwriN&tQ^KY2q^jc8Ff#H5LKz>9GlB z42J;JQ)+B)umTJ^862{4?FzU>vT@;S^W*!Sgtx1YkIF_L!~k^t{DHqd;2g4mD_lI} z8EB*$+fBG`4f5A5nH+qXm{^=mSE!cO$k3Lwu+K>6a-_!=vU)-^#~f+5)%vWwpV7;u zqAf<`u3r@{|M4Pmx4F7cpn7AKkGp;Q0MiKzjc6RPoG98LD|V+#5F~Y@qyM7(J*>k} z9Z%4-f+>*<`Wq8eBfHG+^e69h-;6ah#wgO^25egnXXbO;JVB8!4I(y;B;CP!jgO%2 zG#sV>JpA{|J~kMn-hpuoU~oMZY(N_H#_|b%Aj6k5LU3M3W(?q-_iTtuw?Rp|BKeNCexi)I9~4=~*F9 zr*)xi{wbyF-40t_(++(X!_Q>eLWh^$16(&UI*-*QpwX*(3O(Oi*$YiZ%Fn5}$c3bJ ziVf0E3{&W%!c23D%bIHaB*gEh{f4GQe9Zx19U(}FVdRye0c-=}x#dA1=3}>NmzDu+ z10W9k;yw?4v4Vhe2RDkqYbEv2$QwFBQhs?cYoz&EzXTPg%n1H@_T@UK`>HpJ;c z!1%@q@y%Oq^?`+Ge)laYR>Dd_96`3h2bF^HHn5I)-*43<+v7$ynAq*5VY+{BaMQyY ze$%F}G7cpU6lxwHiBPsaEpp`;0wP-MUNOF1y)?9~zkk<|+$V5~9U*mvEc0+{Bf_Sy zx?_GC&V?%x*1A)xto9pmw!GBjetAPqLf_*?Hui8Rc(sHoIc)Zv#7dT5fgejKV-yfS z0#sEgl2p^lFKO90S{C8w+agsJzl?^s!MqGn-_rJ9t?j@z{`5BLybY*&q{Qg!fo4uX zD?I;bdpL(ABY)h!RHe;MzKHT%+&2cA6B}Bewv7%mJenS=M++&r<7~Sx*|OoLs8IJ<@3>7@8fKekto|6@4zA zsiVx*T)R|ijkY!&`DA0rdh-P8vq9em&<^)cZ~ga%g#JI~-ZHAnuWKLOG)RL;3P>s` z-6bjAh@^CPcL>rUAkrY+(jAHjNOx{Pa?{=6S@?V2|9PMDJYUX-GsYQ%FMHpNeXpGJ zn%BDKnoz1sh0@|5uHiwaH1PahnS~{~6u2g&CwUYU0okuPk`jo;E^bUWdKv*hYjXdH zGfDPvzW*ag4Wr6Ir5U6d*RCR=^o+*MI&QPK|cUJ?sH&=fkz#0TjQaL?9dIlgV!ZsF?R zKf?LR?^|!hmFpQQ5c5x3t4ymsE_BMOq%AU&7FE*25|{G))VSe;YKHg)1I$$Wfpe*w zPoZrC7@E&%nRi-A;sRFSH7gawGAt2*|Mc?hRJd2|l_zWd7fO*2kk^c*2qOroIr`w# zmcQe2p-<|s((flaGM)Yc_VWQ9=tSu+?*btJ3&z8qWPzm7NY+9GTwI_k4zwEGmIo`} zLd7tU4e>f$RCY`dC0>DGIkH;sFEsD3PQ2oxL@kqMfywo7jPF9(%bTy_qv zCZ!~jw+g(J7`!vNKcIhBJOlR5r?;>xMqd_kIevpc-1*QP0$3;p!tERd<{~jo>gY z#K*q_tTssp?ajYC1FdkNk>d`S=Ejq>Vizzdl==gPqi~+}(Bes?Xxa40a{lme znMOBua2VxNq=2FALy1T(wde-xlkIYH1YU>0oYqx^5w(Lb*!|bHVD9LC*Yq7^DFA+1xcZo4j_-;RyTB5UP7{)>?s z=9ki!btEGRZN~vu1@7P?UE-`4Cg8e=yr1EvhVAm;AOamE<#kDmzmE|q(e5{F7qb+5BDLQhK)D(*|8*QfPn zB`8w7ZaocJkFOmF)Ul~yV(|=md_d#LbFn1>7%F~?q*j|{upgx(;5u<+0{=zT5|Axt zjY%fqo{EMc`F-`QTa&FjCjGrG2YF`dSf^gvQrt?2)Pw-{^Yl{=g(lHc0=rktq1OKI z$#|xjm)uRqg2O_#8`u?hURM^QR z#l~=yPf6&%!~!X$W*XLKoKfTc>z~CB=_bYcR{x42$ZAkyEV+`jcD*yrcf;pg)yf~O zOl9h1*5YF_+)Oa1d0+tpje>J%9?p(QDB; zop!utXzryO@X7W>V%R}0eti-io_v&1@Q{Q6{Ra1_&bK=RzGoP@^J*$_nG&7jfY;RDHSCR<%FK3sn6;veMqp}^BO|yFQh_I;xi7QWed8D za6|q5QnXRn5fphJ$D9<~R=e8KAd3z2t4!NITPbSJaC~{jz@2OrB9K&WCDxvba468x zp~;c>uJ6>tu78O}{_7P21~tt0D(T4(*})Jz>0JY)!jdadAV>n7zTqUw>VVX$u_6Bv z7_k_3#N&h-5n2S%xrLx-JvfG_ytpzqu|;6c0&i2MZt(Pz-%rQO0Ba_FU!kIViKb}t4RHem zLsfW1(WlKh{6l&4+eI7e{8-;=yaaK5i_^BT>VYQSw@>-qVEFs>B?wB#**X6V3m}8h z88@2_fuLMBTi=5lT+IVG(~(utgDSq$*c3C=$B6L0&tTqg%Q}dMAI@jT{eigdNlXHm zH2v~6)a3`={S%rAS^YU*2lIjS4j(hc9e57{ExC0O+`sgmm{G0i#|-g?$We{MDNa#A zJ{3aT+qXPPI>FoS{Tly-GJPBLA8lAuWZnp4@p^o-9$=v>AhiN4Zo66G;fBUPJV=`$ z{Ttk_ir45-DHJ!iZ9eD_?`JFSA%sFFyrdwfH4`%teF^!m?vqIh2PVWFdH+%kBQWSe z@@Xfn?K+};BNmn>g(!kEhHvK=R0DjM&i+>28kmfDIflD@u&OaANh424>VCfn@ zKfq{>OsS!KbgY2tV5}UybxMCQMf?C@-|3*>#&%-`D;M?Yd1e~bb}Z)H(-(=@HHCkF z-4dE@^V%s0E7C%^M@|m3THQ;?q*P>G`~ERZ+61 zoQ6|o%s8s;*!BO2^$$rJ>f19ju+}CaXyF87enj6df=cLv`kIRe&=~CdB@wS2A-r8| zAC@IWd56U2;2tg-qk0O}ul|dc={>feeXdOTrQc_h$FL%eIM`e)1KQ3b9>Qa=ww{dp z8@5RE6kH$CZMVL8=S&S24(t5v*=O9--4(r}Dd3*u;PJfpa*#kcgDXh83tLv$00V z#QQG#;j9=f#f7nq%GX_Z8Z3pkAxY?4N&nE-nMH$PLX~4>3aXo5rFMpVg{Cd&G+3LR z)SVN7y(l9as8syK%3W-QQvz1k-xV=B0Z?RtfCLy?!7XhEkmTchBk=Cj1>_K z?QYX|CN{)Jgn_4MUf{X~n#&y9!R7LI`v@5!q+a@7`!|Mwi2f_s9@+AOs*f*D#wDX- z1gKH5`bVPb6sp>G7gg7Z>wQK$>6^=+{qdGZ<6!RqqTFP<7ZZ%^nB{pDH=_@DLV1(o zLlP$fs(K?XSro8yC)|ex-9Cl4Ss!_Q8f8{eNLNE0^O<4!YaFP1IxYF+Rz8*idlmr% zxkD2*ksmoiOYnW8d6-Ofo*%FFNdq`@LJYt%NSBiBN9J;4n>%TK9DHbLqE9 zCc0x7`6*yL&5B>Tf_#X_RHxS?#@%JqZv|4ln@ztm?}wx;*?0jK3YHzl1Zr^FS z>A>3t%g2b07#`^ZxK8A*r|gL{L>aoN(})q3Cv->x}{ln_5!`Vc2;Ci|-f%KeCqUv5Wv&+34< zW%s*&SJN{c>rvwS%_aOYDa6_P;qqzIc#UzO&;cy5@e77GlJjEFkw=+}aPNim#BRko z5;Ip>K{IV4YBoUpp&i_ujR{UxMz;FvPr#&*I+|5Je~?`q2w#=`VqbBC%WJ{;8rA8A z7jQFhycOJTp_r>$gsQ1v*NBI6FC%dtY>ox*gM{i0F?^58L{nm$Hh!rq*bYYn!}r`; z!};Qj^a-XgsE*C7Zd0?~@LWa?SNX7d`gNm1+U%)bz0Ye?dSbCyILRkOB>*f7o4mLX zRzGoi`r)vwAHS!EADsJT75ZENO}Edmvfm}h4D(yd5p4zWt|(sj!hrqXoGC8MOhzBS zcTcR+>W)w{`7#+-g%N`=!xmI*na91Z9kdiHI*@VgslO=AoAd0mk09!;S^LNK>TUi= z-5HP46T-KUq1P>o8j%F<9gL2GW@!wd_Ew${HYBk#?L8< zDR}V;Yj&2104HmDN^5rI`2N_)h#*2l)_^aR&woh<(mo}$6_Aj4jF{%~QdDJ1Y;5q` z3|WI429XZ9Y~ItaGJ%HC5Ua!<2O*Y64|)oFC|7mC4lH;-puQDQbTkHs-k zS&TT-s!dp0!y|CRK&gA@585GoalPNab+YszVCMPN|KevXseDh=0BNMhJ2ptq6W1j_ zpcDOR51neCP9-GwYG}X(m6F_xQTLUXudsPyg@2bP?_0`QRZf%YXgjX2QaQ<9@E5py z_J2&ZIqFOD>z6HI!Cjv2^U^p=RwzHynxTzJOzVg9sFeI!A-$(b;?iQmaKryAqSQ)K zd2%pY{J_epI2KyS8~Zo%f2z6lIGI$4jUbw4q_lWX}tv|5kNx z`wg-Oaj>TA=`WT+9SU@lw=I^5Wp=F{b@ai){d)p~5OUmX;-^RizfCXf&&it{-q1u zP?p(W6*0#vHAA69*!0D))D6YpOz7>}s{>A0Q(XS8b)ML;AC{909Hti*ZKUd+TmZ5! zYLnwosqmYLukuU%zq9|0yit2Gl|6jQbgLd{70iV*XXip*)BHQ|Ovq(^HM-oTfrCDp z#mNRX*ogTo5m%+ItnnAWxR;I5*ZI1;6Goof;=+t^j-mXrMs_BuA-kvaPZ6YpGmmO# zs=KORWD(Oh-)xvTs^IsuRp(R$B11n})+9YAanZ@|syDJ2u}vcpc$6#FV60j6ViR>F z8=Ku!?N>>ULaO1dc+LmLwVJ_ae-er@u9@7=Tu|0L35ZnK7&N(R65 zf8LEI+$?#V*|$6`=QKSKTDqI>cV80e#d$Lrim1rH_9f(?{cce|e2h*ZW#rmr-2On} zawv7`mOWsS8zb-|yUg-}l7X*g9w_$`u1CK9;?ISi|7E7D$h8P$>h7H!GVN>|qc!xN zrX_M9yB!Mgh&Q@YLgxC)c!ST2DoPySbt9Mm-3AXQ-WoEZW5R*9E5M41aT(jYbxx;L zyi4#N6+`sr`{4WW;~=7dE$K`F(*f9bX^Axpq>32CJ0AD$PcMU5_Ch#Z)q9-b<#*mY z-j*zX@jw68$qrjm)Y$M&UQ{{SY&L8-+pNJBfaRys+YQV@k51OTWX#D52b$KtG)y(@ zC(mruDkYYA-ez^Q)BhHr2p}|MPF^;bz;C>hj_g0^SRJ)v-T(PGdhYg?6ng=(+ye1K z%QoPUs5rep9Z%!2ecIwWUq3ouUmrVbdr?Kf?6unyyGFdMAR3`Sbi&jN_ukl6#`8r$ z8nW^SNojI8!hkL~L@9k(lm{iE#E<4=j2Rt_JnT=jf$^e-o&FNkwuBdJk)7-37<8`QH53>@Xqd%rCi;GUw)Dxw1;S_Nm&O z{rY%^oR~zSep!Yryxwr=>ZAyZeX$6~{nNt6*u>JD1733lVcQ0_pU?YU+-^P>3|L#; z1)s5>DdTRPpnj`fsVM>VnDyqi5{)%&%Jilh@ILiQ!l$ofMr!xBnkhOC3!aee$Ez(k z^Li%QQT(+y4elzH$F$tOhm?T>sxVm>(t^q{yEBO@Vrj+KAxSx@ zGmcWl7+$*qk{{q1B^*AdHu8;AQba8{9m#(}L>`5&iS0TLGhGZydEU$Q0S1lczjw37n*cEvTHUY+)5ClhMj5eKOy zPowEim?$GWj;n@ z@hc(35L$eg1GnGwdl~o!_sg*qYcDlrm8g{Ub+2AZlo5*QQE;7^E0At?NCpq}(-H(8 zzfMA5jos4r zcr#J+La{3H2JHVM_1cvYw=&##zk` zv_wL!MeO(xsF&v5`SH|s#UKJ-Q07(ZOjA#0LDQ0&KlCT{2KjAYdqHEeQpGJlMpJ$= z5ry`ms{5x5V&(be2RjrqFH z;-NFyQZ6?nSwGRr7S>N@SKZJ*x{;50qzv>urm)qEjR@WP#wRc|70o9y&W2p{2- z=AX9yPlA+Q9G=OH{E2*wnNKbT8m%Y6qQqqX%D?eT{(W;gg6ubOI?-TZllPv}qS}u6 zN)pX`*wvePLIdXCJJP1o#8_D?1RqoRDjI0Pf)$w0pxng+0%6oIDM?OoKc9-dmk$<3 zwV-Zzgn8XNC`7G9{V=91)3++m$!{u3Vq)II8;=(W7%Ma_w0Fntw-gp`FK`Z?q>)-b zIkOlsR=X!02q5_rX!JNB_j^vK|HrxQzHAi99~tWPPM&hmk5Pe!()G_ogYDAPXQX=J z@HY>tbaM8qPd7%W%`)m?!#sjh2_w}jzvd;@BKAA1NhwforL#6~_tNqUv*#;tYJp2IDYG7o4kdKVlMh$OubEf*m`&bm$GEgLW*d zDLJwhFMPc1ESp~sD8RN>vsa()Xn(^X4Yuv3#Y(8Qo3`Vmfy9Vy&l!|H>W}Sei6r6q zgsZ3H`VCG>++~YpssR^97r(TxQ-fE@1+#tmpRt!8zHM;G1Rx6qe|2tTBsnEh)ZfS- z&o>?{mtNHo!yv=HGFRW4??>ht zEf4xd&2iu>Db&)q?IZ4BV8n-O>3Id6dr`bSl&S98{JWC^-(StJzu*&Q!o_F7D^;SI zb&CPF@pO{euWNhlwTBlAl%m0zq@KU(Wl2tL%qa`63&n7gx`?AAAwdzXq7{;&e-_}}p|7Z7gKnb!ez%SW9q|7`? zPUBN9#H190g=HMdq~M{*Z;&Ipw5txI+IK8Ii0bgT+UZsKY41(7_t*STgl}1x0milh zfB9PCRl$lDJJdG4*SkTsXZ7e4D2h?^cbSnmlSO#VDRrv~e-BYj2%7qj_kjggK5C#+rp zGh`hv5H2=*Q`Ld5$Tbc^#a&iKeLL!3nd3=VMRJ5u+gXG)wG~2V?aa4*TnsIyI~k{iRUV)A7VEEt?`= z%K+ONk4zkZTN5O(#EJ4-GWaZA;*G_f#!If_i=E~eNw-PLmH_&_rw!tR?lVSMYt>HO z@gB9Pb9g{(=bP(%J2WVS>g7bbaPZQ|q`>0pLgk4~Ef5>dHNoRz8@2BsSmE|432uz;|K9qIYmVMmI*w^9i((Cv8!g`w4 z&%gIQ2i@loq(AuIE`JatK!^w>j|wDEV0Jb2918q>_9_55BU#!WQMdcV z{Bf9Yir@*IzI09{>e_PN&98CrZ!Z*lwU4xU!ibh$@7LguitF2Yn()=cw;+Nrg~vTb z9YE~Yb9_sLm|jDLad0z%qFKnkhAs6MWU9QdgBn%=NMCg*csVdM{gP|v`>8HR$DgjZ znRZMrv}wRDlDy;_J9}`K6dp6e_V*1}{vmfC$tJhg4<=a^HQYArva$rt24Gx$xiICs zVc@{Jt|x`jXFozfurzKYpaK?{TzCf3X!bmxz{DpG#A{Aas^o$mAzX?;1=kWE<`JUH z5Cko|=7imSnc4fPsjutFD#0RCR@}*x_IBHiFRRg@yhd67Vg4gIvAl6?(;C`W9reFf z`+7@PO0)kQ7WPNLocF@h&{y@urF5tJQxS2%T{pE?J$~~Qr3Y&ajGquQ(MdZl@a9U6 z{0MnsO7sf#Tt;Z8mLn))Qt9MNk`OyQLu`%Dko~Clw}Ju<_Mcxat9!s8bRMrX} zt1l^3NwnjE222kW@UUq3l6K~NkWaC18xg21oYFXIDVS=mJe~9gRg-g3H|Uagl=+@7 zylrW&yuO9{fmzr~#us4t@(?!Il!hZi>x*-~>QcpN2J3I@^XeEbGE+$(ygy`@zq4v& zJ2YYu>-#dbkKC4LRSGf2J0r4HJHv@V<6KR$ ztSj98JjOh0IB$6RsRjjX3GcOU`wU=QGN0*efpAKL|2dr&8pdpPvZi{LN!Sr7>I$}J zY|i*?$6*Z@G-jtyLzH+5>S~-O)U++wCEB2nrhX)$W(|EoJoRJWMk)XqYKB%-oNf|q z*O#uR>spQa>4*77(e_2^+Z}r%8B`&8*QL2dJAP^kCT)SZ`ZwGUJENvwM9T{}g(Uge zSM(2Iy(n&zqTvX#?{)m9A~8q7At5~9bWrvPkH*>YhVtM?-47on?JUW`ZRQ11Ic0PjVl*dum2}v2 zHWGItTI2KL-nrJ+EVnRbwH@T@qI@(3cY@Y~iZ=9cKKv?5>Sw!JZ+HI0nMUsl_dm2I zJ%DVhogNGcYnIQ3Ji)3CAPx-3<#~bWu6T^lAyZM>nGcLd$CiCs4gK&15uT8z=gvp# zYaRN6j=XIauCt>8%(Ga`Jo0`wdePt^#xEk^S8v3_P2Ipo*vuCNhsiG~gZE2#hml@1 zq68V2w`&~PkH73_uFlyoupIeLR~C*c%0v&!s7y&YB(#XJ<<@+%_b?$4i?(@i?*f1B zqT6|b7niub7`60Oub3!%Xtdk8HFU=&-X0v3+s&?B)fmE*ka&g8?a@vv3O-#&-sFP% zX~$S$x>irIr)OVCzvr0>y-|xbb)yCCEB!z1vl#Kjj1#>^1<}cYi2d)+RB9dcoeh-F z5nXCtwNs$g-+fH$%x5L8+Ef=c1A*B#k?}-YA9j1c&UR0J9S`@X1kg`sc3WaXp#@~9 zhM>PxAS_}nfzBw9K_7XodJX!!|7VsqmGM&%#KTFwfTFAMcB!%c2u6GSc*Yf1f;Zz$ z;Qk5w66j~gPS25Nm|o;GYzWW56hoZuUB2O--uBT__fZ83V>UZiTu3-BD~g)!dK`{P zH*`79TIbySNtT3O&AIOW!_x7^cCpydVEEt06B|=$+8akh? z69#yp3cO`=p%u-$HmS3cXws(#3aMpU-$txI##-)ZYB>%bPc>&1SXH*>9X}CmZ!fKq z?gHPeem)Mw2bht!CjLz@vM-I9?+Dv?Ha5vq#*dvnz&^uRVu!DdYeL-`&>c#Nljxs~ zj>6}PYTT4j9F%xkE)OFv(Fe{%mzOne3sAx8YpPSd%*R8o<*sc4k&ZJ#`xXm%nc>X7 zXZOf^Icfx>3buu78tVLtKUYtZ*RAytheE?e23aav`*5~wGp?av;8|qR8*wL4F|Sc& z&v9Pmi&4P0#%m=Z`>w60<6;A6iRreGja_%(FtTKBAihV9z1?GHv)-N5@u8OxZ3D2wa;n7 zXaU@JKi7!q@CRl!LrdHr*vN|yc>TNJCx+w#5ywQcmBx3EFEtBuC;%n$RBi2QE4p(C z_w?7-Fy0n|s9*8@OQpW?mjL!=OpE%Xnv7-Zcww>dt%@QbU7$Mn_@BbfA@?pp(o;%W zQ#ZEYbIFj)xOVQYB^1ameuXxN`Vp8tvnKw*31JQE75*UxFN6#BRUO*{4nYX${z5Z? z4?502YML0ZAADs@pY#U10xEJ)*E@4o1Wi@p+8y`=7OHK^llkypwPLXdpMm9Thctv4 z8VzILqPo1Qz-pLkA77n2)(B>#+GlO3s7LlX-z=K6{`g=Xi zynH-+Q~MRMq8peb^AFxiZQHwj=Dw3JqwGjg^Z>ni3`UA+4WQsp1qG|k?^9wQ(h z6q((qkk-hN$Z&L_6RL!;aEp>Q9yey|dka9V9`tmuGFD(jgb7Hdy$eZ&=i}AzFCnpv ztbbbPwThqS#M33Nr5G&i5=xze1mJtzdTqB%a3*)6jRg(ZJPlgsbv91x8AiR`;nnI# zPyhi)_h^%>swIJs)>(5dH4q?jiJXZNQd;!2dB-_-x}TtPP4z}o_o^{0{bRGPyR%(V zO4Ix%ee4U8yN{48Sn1x{Qn}?Za4JHlTq9FXHG-I4b{ov&C6*%`3W9|9fYx8JHulof11y0?5nlbX2)@~^J!q|kW`=sd3x*Uj5eEQZ7e~JYQxB8rvxssd; z%02Ju!vd7ZuERmG7Kk|Jn1YVNk?K?S#x?CO$94YgefBIQE|G^1AuL<_2nJdnli8Qa z)~aIHK6me21Ma3{UADDv-%MmQ2mvy?K~dwG-U0LLh0Kwgg)GF8ev(HB-uIfOtC!{B zeaA}sdi`=GA3Ns1w&qvN=(88or9HT`*COuMLmI($xWX>Cw?;L+x+Npc?E{{I)TRlH z_D{syoB9gc(THb{U0zZtntdz+$;&40ugt zfmrK!qlwAof73~Gys<7WJ^ra0fVxa1g5&#(&$?RrYrWpx1SRxv{~{`-11rX zRiHF@=TL736Sl$&%FaD03?h+@AFPZ&OJ@td>Ff}C% zZg0(x;j7k)sjdh`7TS5yiw4IDYbz|aIlk2fS9c#56H`o&dDq+7{@E{yC7+MON27Qz zLvku6N*btPF(Pd^hC;!PdA&SaMTh2sn|(zZ8u_lk{C6SQ$bqP1ndk-NFeXB9aq*r0 zpE+kP=C*^6Yq$TS1#p=i%r0HY2V1l2gBVrXz&kM8eCe$ivV~#?r02UUB?*|{47`|% zuLDbNvn|D;w!RIYylH{=XEmQymJiOv+~%972T@Z&%=bMBu&oDYpP#Aw>r=+=+MH9s zYgb0hQhi2%T@SgD)mdpT50W?U2?v4dWdI)|S$^u>a7qU&DTe-~__5{44N5bpKAmK= zOxTvBIcXMlD{M;K?Z$TI|1ye)pTCOb)^D%*{w)1YwaIWqMBB;CGmu0pwWMFu=8com zd2zHL5|}I2P4TeL;5_8;O%mb?nEG)KW^h#>IgjO+Ba+A7Qt$lSOp7*BJWf~|F8ITA zD{V2MHEb38x*KerTszxL*NYA?{o5C7fPG9N#NKBio+NvmU&srFxKxX1_0dEvH=M8!b0EbwgSy7iX7|CcG zJ-a1O942H3e_ogp$yMfogJ;B|a#HbAtKGWhqx-4HdhVoRJd>wo7J7KHxf0w-D4@e9 zl;Omvfylngae!-QebOC`lk)O#4x!{-xwXF@!A{OK38j7by9y0_>jv9{H#{@02Onax z3~XX1ABk?3e0e3|rcIS!@(20r0i98wGUCvXv8*L2sjS3bg!E z(llz2wNN|0cawqIo>#Id@hVV#oVJDdG?w4w`_93%-)E_C8wPA(zcnx;&S z7O6p${5eRqLaK{ST$DePCrXN_gEUh@a&thAGeBfI_YFwb4ezg?0e)P zY0_|CU*5@Gv}jv$Th-zE#%>w0{kX0s#&syu?|7QEaoroCa*%{NBtX=qJ9G{ia{7dt zb}Pzx2K6xZd9+1_-9ZhNQ&a?>z?kyMFK}G9dRHK77rK4+TX`AfMe{y8>`|GeRq>7^ z;h)m%+mmH7IYt8-gff_!TS|6uFo)nQQ@IU^(@1SsL7# zC4>XdgI@nV#^Oj7Kl=TxfuiY1)|=|bl`Q_49I_YPTbpFbQm!@;h%y1- zw;IuGtmk7~?OTICHSieS&AA`#>m2-6*y*s>`D6Pn^b>Zd&Z~xV`egY|KNQ98)Jc0I zV{5ze&;0j^)DDXwg+@c8EC8V(T`V0vx4Kg@OQaB>hQou2fOg&27`?`WMFT@YQi)yI zGtU&K?HiLV?oWV)%%WsEqLEY~7|qu=USNlKNEBe|NkY*jiw$Q@5mgD9SvP&>m1@oy zO#5{$utQ1j?AP3jo#{4#^|mPmHSV@QqlwHq^$N4~rZJRGk?!f zaJL@RKU{XR;B(Q^=gZ`~v4n5`=QqNMfkEBxQ~EXIhmw5C$L*y?Eu;)aEX>Rw}eN zwtwnjjaV(3V=fsKC=F~dsy`wZIC%;BDD++#oV-Bn->cW1@WH5Qkoa)vVzv9jIcFtl zVzq1J=!&Qd!PpeC`GO&+!C>3Y@t`C-W|gt=`WclVO{mDI&l&-3u$_H-d@c7PR%tbw zIr^%1x&T-`u9~grNMxZl!ILU3fYJu6u8qHlDT#~=+Qko7d8X@ze&TyDMJ9VrgB1DQ z##->rl_lw8WZQFtQnJwYd5mxCQz_+ObAKUkUjKjnt7dv{RrYYZE=jYI0tBf$(@H*5 z2hA!++i(lS>NT8xyRaM?$M8eslK%H003qD7aB`#1!1N>XR+o%t$CmkU%)JBXR2ak1 zT*ITEjA}_sC6+7yY1|o|%j?Z^SgdBpp{RY@(&0~TjH})TI?It0=G-oPY|QIJhrvQk z@bN`j7a=544v!)sHS6aZN=JvZ9UdP&pTj^D{~0j^O#a!&%_BNp0vd_Z=! zB+jVf{3Rl_RD5FUtj&rT3m*_Pqh4#(EF(p|x_Gc%f9;IoW6b6~RU-khzhouz16j$= z>_*VN`KHAzwAl&p-py@e-Tyy*$uINput#|lvt39z4uHVt<2Ru(lrITkR@JwgoI#0L8 z=@qhseGkmR*bVGT>MRbaN7z-!2wzf58Otd%%+8RM1HblO+G>i!2 z;p0psB+GO!3A?0E3@l2%&z!P!a1UgTpmYB*uMc-M{^bVm-u) z-||%0|NVRLZ=&}PUaupao$B8j{?Lg)vIkN;_;s$ye?Gbehbx)>e5Mlr&u)pr^F5r7 zp(IH4{pX`AfQX>Te6E^If+$~-MU{~!Rd8DA;!sBC+~jz5=j{-}6XTx2D_(pLmN*r7 zbXN;edt8kaL8sD2zd-aRoyqvYe#E9~-eMvR5hNj~kKi)0Zd88%mO6*gXU3yVx9s9g z@g%+`=eoh+`QfYy-%tdSw>a6-2Uy>i8J%YouUuZppY+84?EW)U?c*k*i?}h!=&()S zj@*gf9T;E}x@<~$T_fXgq}Hk!ite*tE3n#o;>Jq0*GLq{iu$z!J_P=D81bGZ<7tCb zrniHw6DNldy2yHfA4-HVQZq_`yZYMEIo8SbbY`h#Uk0qWmL9(1(E&WsF(U+@(oC{3 z$IMd66y+L2VB~lJ4=qXptPJg;=9=#pYHWwh8a{|HH5?n<5EQB`<>lhAG9e^P%na>M zefu1uom=NklBcWzQED(oh$iaSm~7=0~1H}rWc2cvU zL9wsAn)OJJ)V8PU$baHItHEL5jm8c|=P-lAYZ_PwMmhv`RzJGb6fXfnhT6evzn`rq=fwFjrX}nI zq1xn@MO6dBBAzma(iP~M&t2+7u>d~Fu*)(XQ`G3Li;w%$4H**oz51N-h_DST!4KiQnOd+^85o4#q0Lfk#g+Y-g`jZ$ z!Wh>_iy%;@_dt#Y=g$RFL?Ia6@G1L$WL6ff$laMLpR@FcOFRp9mR|htKu4N%jSbjtkGJUuT@`NCSsv92@vi~wu~y1a;zOnfvXzmAhYFM@22 ziI-SmY3CkostpIP#2t9DJ077RB+v7EM36GUIeN7!J#whE+%67%$4Ntanj-C8ND%e$ z45E*Ya)+XAyc?duC$xxyI;m?bKb+jZM$4ar9;!PVH21UC!s@FdT> zlOs;4mfm!U{Xv474!Ji9O4`3+4HcM}v36a(D<^&w49yDHR5}WkS@E>_<;V^8vWJQ|>T)U-7&QfX8J&_LS3WKj3eadR$ z#REg|4Si~Hb(=R(B$NH%b#8iI?B%wvpQLY!ODPo}$k+YRnl{hZ-s6L zW*!6Ip}DQ&NxYo8qd3jlAN}3HxmAH_2>JVM=mY+oK!&zV&Do4Blq94XV6-N`o87f* zMBSZ9nV&ng<(GGM%X2)M7b126isMuRr>YB;|J zS6=9EIbGp(7jLbIUiq-yr*>~n6`gchVh?;E7iXNtJws$gwp#FQ#HWG6U5~yDAEhK~ z5u=@Ef%X4KJHO6kI@pobdLV=RKnVWok$kzL>krMhNL6e%xSyTh7H_;pTxOvzCjidrA}_My_A&v>(sN81Qf({@&jxnCtIJUU;`cH_8GVruJA*#?gocy zT?<32bWz}@#QJZC-VVy4oK0Mp1HCEqOkwGfCSp^4Jyn*Aq1KD9xo$o^=a>CU7014V zwacy_wWh-}JL=vF@_nD)*IPp}uc6UqKemQ=}yOxzGD>XfcyMl#6$Yu7L zp=I!8pz6i zFg|?WACsZvp5wBc_b=P(+nfL53?i4#f_9ASp4>ezPhO%+jcT&Z))49NZT2Ezd@LkI z8DOxIB;mnAlY%U9E3{QLu^mG7j`u6>UoIkl)dJeTvy^33|NyMYl9$(+dygbZh3jJ9zE}E?sEZk}S zrq<3gaJbb{=203E8!%fnpSLgPVVQ20?w+lG)Vevho~Nf<@oPWHui1G=_0oAi=or51 z2m>*c>N?~B;Jq+d+)WQ09cS6&h&g)7TY^)nQTGDxQ6hGNE_a$3d_KWs=8THf-6c3& z|6%_2v{tSKa9tl!{mdEsX335XMq>-KX;4rb-S&ql1Q3K^4O2+&H!jiXCHfB@^Vbdy z%Ewf@@F~2KqxpFPl4wM1A_5U7)+*A%o(B1V+<_vp=~fq&t{x5!Vd4E6Z%_MZ(I?MO z%RnDxnrUm=2Jm3kgco3EV%7SX<(k^l7(NIIwFf@*uinv8CKneQgmWVMB|oQiW2r~@ zqdG}QmD8!Bo!Ix_l-MUjLatjUGb~r$Uk)`1xgNOOq)NQh(J=ctjry~{d7<52^bnNW zvZQ(3NGJa6YuY;+9PcgF0P>hu<40A+yPc$8inPS!0G{%c>b~j@kvg?iX(h(86{7T{ z3mISam8Z;#lv-a)k|VrxC0ei9!od5=?GVIU=1adgYtD(DVKDOiJi6HVsQv z6+^e%S*B*I{^J(=`Rcm0vt%ogT9u+ic2s!Zzvc?7_Lh>S<`LQ&CZH>r3XUn=>uN-Q zq|%+oxNNiiHn*PAcG5lBh}Eir*;lQ~d%eN`EIGUD<$)SDzFIS7@znB>;u~U&+uTY! zS)oY-Hp7M72zrri3jyQ1>bY{wr-k0X#c-U7DOWY}I2{QW+vnB}nqFrYa)Im7!{=`x z675AJ6o3vn=%HpRKh%h@C>N#rt*k?wEVgF0@2$Fb?C}TE>+{*mx{=L+01^$Q5S*NZ zr-n>^;_jMZwOjPeSkt<{!H@1=ZK3FVRU}M=WqU@qh@eX_N%-yMzWf5cdCypD6{B%~ zrMjXe)>YQRY;0n)Zv$~qzxO<0zDVkupTdYhnElshd)~xl9XYIGD;E-)nm- z;Rg>hgZOLgV5s(nPc^^X2}_rG>7al6jiFz4_U zxu(F?#)A2ke5Ma#HdEi=Vm<3HNl<=Ht$^qj^@Vh*X>uH{wJai8!sQ92bIx1^gSjNh z-P91YDz*Jg)V;r09F|)o0pr zwm)9pBU`{x4x=6xFl@Z3Y04&J=2>lcKC&L*s3dt2bl`c=3ocjLJ>D zGy(`8klXQCIsPKMVYc^)a`2W9!76uRuzfGkA!3AGafxEpai0YlCNcOCqA7H6Og4Z0 zcJU+Cjdr>0&`%rV%GTgoeUbtV>4{rX8c$`X>Arh@#5JTUrf-fV!at>R5G|L~m#crt zIbGBq8Tx3DpCG%FsTHf!GGG_8=nQh_9^&YGd>lq5Ep~;5C>wjI_>ryg2~}aFQEG%8 zeBS8elh7ngu0OJ&-8&|0dcr6JDIGm9N8=8((eZMBafwOg_=ao`lDMpbW|4uC!%ut? z?Ui51tz`u$cNAbBhxSG(Xzld*jx9FaegJHTg{wO!{rDg>_`VIVALEqREqmQLjbSpO z^B=J^sdfDSg9>;E`QJXUa|HCHfSUc^WX0c@{~MqKD9CuGsQ$~dTEHSGF)DIP{Rd+K zA`URd!n}56lKfLmXw3Xyp2;wRXSFLP#{bD&(7faYMmTu& z=iC4CEKU4=UUM;bCy$mXL~E@%|n6XLEL{`~E|0=RgzsFLbh>s?Yi5@uj&~ zG0R8_7JsatPrgzv{s*{_7x?{Olznwrl-;`b3=G{Mpmd5NDM-iAC=yDyf&$XrF@U5} zDj-sWywWM%sFYHJNGK^ebPZkK!q<22_nfo$Ip4l6|9A%HnP=s_?q96+jPm^Mi$@pj zueVj<2HIGX(plG=wl$tk%{aBIO_Yu%;DJiI=S}plEbtzAfI31@t5UA)j`|?;lcKub z*wwrz=wFlOX7uKJ?wphymoH!5Jv*aws;YeJn-#g`fo~;WPVhEpoV%mO_t==*gFnpy zZhjvr{{AtBq0wDar9*Zi_PQJd(-B@x{5s1UV-B z10Jjg&!iP}Bm!CM9;~VI?GeW(0lu*11oBmac4ca*8*gjE>1~s)4zD`i|;ayu`wHuq7bUx2}!a0(^EKZ)njndOS+@YzMm0U@ZIXHVB zz4MHSWC!o<0Ry7R^X6&x72aB_`HKC3S8thJ0H0~xW|9~G3HBQK78p2g>M}V_-aI;+ z^XS_W;ZYz+;3wL=e(jD<+aZO zH6|77#q@+lCKLM7n)Ajms*ZwY=HqhW#xGv^&N ze{Gto=qyWlDA;2_qcmwSHkqb_R;1j zOk(|WZ3s5G*m^)@_*NMVrRS8FqvbN^_tF;-!}5grzOdw!9! zGU()w9SbSUaj*F41{lM53BQ{oq%C$4rAqS9?#OnT3qWjlcI^`FDRum;&elfkT6$-3 z;Ll+7(_nOwfp=^qu0{4s!JTX8dcg$fhgd0ppz^Nq5l3L{uL;L9QPdeIT0zAWgUPb! z#(3_ssC@)vrSHnf{MH#x{7dR1-n=yYVESl%C3ixWue+{OBR*2apFhpx9~1Zz;G2*=5TZuCrzS$%GCsl-Y8 z?`73B7=&cLM^SXQ5wM$g9+cq*ocj=UUP`IgfVB@_nzH#;&f<7hG}TdXhTD3WGl%X_}!;nSE5-R@2g-xm+ISADdM@h+wA zBD19X6ErTvq-7(f>9tP!6)|ZGsF}t3z*OUaKP2Y%vA&Z<`+-rQ->|J!J}n@~z`us3 z8c~*a5QSC^T;8}42cCB-&1vZd@KF*n(3gsK&r0_}%audMhT8Hk=<XU;in}>0Cl7vUV<2yYoKAv zgg7gSq2uOrpA~od-DC;6*Io*?rk#6ieHRZQRSFQBD}CRbDY(%XK&akXh~-ZnL&Lyu zZd~pivm9^Z#GeRWkQF!P_SXLzc|^WgzW7|wd;W=k-&@dLBR$;pL@gypZ=sp#-CtWMT64a!@Aj0Go}>xB z3;eEr5p`2`{X>=RDRN-Hm_!{qbQE2^EDk2q{;<<;0%f>Uxj6f1NwI>V)OdL>po9FR z_vW{?Q=WAZ4zntMWG;y2~WjUxTXeKAXiM?ax zn9}ER-#ez&gbM6i9os%v5JbC7N*>o;XTSt;mG@@}px1m;0_WwC7bEoxMyi%@0t1ogt@tlRVovG{TB%_Iit^BGFGU* zxwOz8#jjt#JHORTtXe1E0w6`;x2cu1`QJ%gYadA5*3uYlK?dDL82kaa8zMb?{FCZZ z-nMckAkQ@lV^>C(HIc2OZNxUdB>nWhdQ>(A7KM0><<^V8iIN#_eKVPrh!Dsf=ez^&l+@01{3 z9VNKOYg(!9+bQ%hSD+^r)s{5hbXfW=8qH;Chs0Xl6( zngTbYGH2ykzU;kE*Fu(e5vr96>4ix+ljFNTHizW2@}uD#bNjnoK|Bh-(ZYrC-f^G! z9y35E9R$QfNX>M&pQ95U4zdHRz5+UXF!xINnSJAx=je&M+WdBo#N!k~+FJukkTH=O zb??)6Kgf=$+~3OSCk92g8f`SS3-`?Gi+npNlyzw9=6IttsHp27eOeOk-FanXct7>W zSVxD~IMX)1gu4sJ(5WQJ%uWs0B|@Yp9?OijnjY~>C{-Air=VbNDZjntOe?oAmh~Sm@DR( z=qg7u-5PnV+<30G=OT)9v@Pic=arY;hxR{ZwPt)?%MF#|?&Z_m^=~~0y_L;MiJ^VR zLp9Z^u`4rx=H-t44q2}ep(A!;T1ykGwv^AJAR*$2-or|Mylv{ZVb1FM;!69^UbWNm zw06<1l_wQ)xnq8*ktSKF7L|}-O|m&(Ys24pZyA6#?iUI_7{TwAA6&z2`nI+k)wMR< zW$y%a7eZ$&+XhpV<*2L3LsjfcO9TBWiG9i0R62%Z6+~aBU*8ii@mYEsu9K)HJ(MZ>;N<#VYS-k?aHaC4J_QlTyEOD~3h)hn2yep)c*1KOXSHxHyKNsSnZQZwSXo zQte}_K9k${IewTWh!(e9ITBH%FOb<6Silss)@w_(PE%2nCTW`Hnv z?6@p4Eq#+s6`Vw&g7CjYdSpp|ZkUN3m(O>_)TVK4a5efX;RZ=K>(srW#~?<%K3hor zxAWQ^q**ZPfGz`#4g4G_)}K-8Pe8AJ=VNziCuQ+ zj&-XTTP24VObLY*Lk2a`PLg^ac7#n?bdnN0gwlbJ1vcY!nmRo5X{BsWt38a5&Fsv) z(WWawV_%R#joscgG2=&WfJ(QdHygCR&od%*>$Gz2_$3 zrraM7yJd@e_v%YBpZ3la?QY{p6i^rNhbsiLQyqKNHI1>_5a3}SUtMwa@gF{1naYvd z=uhmu04v~M-Ngno{hLbZ;Q9)?fDK4w4B5LgYjSi|+G6#=yVLax$e>Qr#nXcxvF*kQm6+?1>ctxl z>U*7ovAU9zw!G0B+m1Iv*Z0m86-&ZrcAdL|9>{*2GJMqhX`at^!iQmU4Rqd@x%zkO zVHG3;Ij?_eyq=lVW-ia}+v7VcqH_&}WWwA}bM}gbir+y`1<_l*ix78Nye7NeATrzl z6tQpat-_DS^8$ZV*IZwhu6n?WeOcPk-T7_Jkl=^W<~?%flCadZoxq2mm$ z<%BYdN+fEJv|hQLUgeOMD8|pYv$f97_bh|T+g0{;dzn?_ zZ;j*>j8uKs|JqfYPF!C_UkjD8i3zFkS~iQ4Y}xOySQwamf|LCyV3kvetO9>#(Q|(U z*?H{NYh0WB<|qgMx%b%cy@xNa(gBvtSAx4|X>a0s$TM796ka#7)b8De`i!sR&)Itc z2S5WxKI zZ(_4lS9^~wk6sy#HU^2DuIW{~$c9?3%+ymsS||ILwHYFWYE`%s9+>34Z}-xjjO@1k z-rN=dVpt9xPI`admnjjiN>j@i8{?~V1?40YGb%xxFQQ{0am;qj-!Kotx3mKCtl(VX0-m()OW5@0C^pl@LrB2iWK)NXHpc4)m+l@muB%U4VN zRwepvuY|~5YA+@Evu6#@ZQ4J&wV@&`>@t-~i1Ee(9j-jGi+2Ao**-N@eud_)4MzLI z>$2X9G+rPMOXpW8w6qZDq9UXg>;kx4o5++Uyb^bJA}|D_V2zq#^(K1c&p(c!D{PPm0r*= z-*?Dl_?N)pa(iZauXBD`ky~2>^QJ1RfJ35x+rK&xD)q!EG6Y4m zR#mKX!;45T9r6N}Tn!pjGY+Ij%*(!p(|ZBR$ectL5A(u z+(zuILAOVqJ(U?ocA9Y$zmPK@Y3N>SpbsI^-SP$+xQY3Ey5khTqVqefWFX>8YA42> zufew{6gNUFE-4mCLndjSq%u0@#qi=p22qNn+8zG`sPZ%ZqaXe&P-PiF?ibFs&2}v4 zF%u{RB3lQ@ukg0|YH!urV7P{TM#~fKMGZslLqDh>d^^)Pi^@!yr@}A0VqNqTT@iOnKs->~ZL)}WdmniJ=Lp=iP9q~40 z@k7W@AD@h46a(KmPFWKV*zv@a+bM5d)j1!XWI7Gb?s~lhJWmA&*C@A*7t1?kn0GXq zZkxy-hgzV3k|H8M9_*ZK;Bq#HrxdFX;A%eNiVA zXV4o%%I}+7@j1w4dEvp5>~bwtJeH%f zzZ_H#4J13Ao)sh&6Au+#+0*zA{flXi2ebz6!-^Y!)q)o5or*Wt6(w&&>OnaXt?g1}u7otgf-=zmvQT1mlgH&Xr!(!UiK z+~p7tyYt_rmy31>XDDF*F5Tblq7N=Mvxul-asC%q=kMo{NR<9htp-Y21_i%H&k_8u z%5brd^Y5ko>v|LcEUzRl-~|7o3}CCM-9J=~zg^hFFFc*Mk+9!g@b_u~uJ_j8>+#pM z2p|p}Lpijt{)KphLhjK0{Wt!)rU%C&)W}g@3;q{E(XWlre^uh2ZG<4fpNo<6`lUaZ zLtjG#Z+s-VrFQ&j5PvcB<;(`u9S=y&Q z!BX#cZXQIyhYKyL@fRTV%@vF)#YQyVLV+p7mHvU|X3t~)N1c!@FxMZ*4S~glLP$sC zG+|x_Ny5t`J5)M#vvzxHCiM}2FhhntDi^Rsslo%^B+=5@0`Fn~S(0e*hd;UmPnk!ZJ$O%re%VHr6 z8UMktcp9W(Q~xqv#G21~!K=?_Vdp!Uh)@5qU*_T=r{q+c&?0OKYL4yeKJZoC)_Ccm zU+r4(Em5h9#2vbVm~k(-b`cr26Z$lSu1B&--j&lrCu_EvTF*y;Na zX-dsWp4MZPOI*SbL4&W-6e#wsN4b%eVHAFwGtVR& zjoZD_&u((O}jy>_v1K!&dk&P6Rbk_4DUNS-h z%Q@cL3~G<6xFv|{Fh1{wH7V1v@O7>xI%qOUr(hTO(j)8?=eXP>Nmu)zx)Zq5-V{E) z%(P2%jLr;NLnGL=DvFbE6?7|8U~(mv0Uz75B}&HEAEC{0^E6r5y3QjU1) znJfq4KYRnTWZfoS2Q^5CW~e$+b~Rq_M=F$lu@<6Lx>Ll3)PINZlCBH0vE>%NHAk3_Mep`m4!xOiur{=qAZ}mw=WD7w7!`NZ z7_)mAf>=UG`qh+w%UL*fc8g7Fs=sy0KU8#f1TiHh|P zGX^9Y$v)&ev)FMg#mf<`chY#ixW9A7!XvX4&PVN*v)u>Fx!CnSIJCu9&z)L+7)0oY(hxc6GYXvE9WL%nDjpRTuQuOvl8}DM0!h(I ziE~!tr*=eI#dxHf5nb5YH*9XhOaJ%g>|*?p>UXY<2;xBEi9fb2tipz2j3k>Eck$6y z^AG2QVeagff{xd)>Rl2pi;_bpYE_>zL?Rp?@pKRmQLG#?NBXBB9Pe^4a6mwJ^b#f@ z9QBx#H5A~YH)&?W*^uDJ29CJSR*Q zE_#EEJ(m?pf908r!mqE_g0FWdSp-ifHQEba_Tc`CVb;LduDkkb_DD0v)4OuBs zyUKdM-)ffG%L7|$>O@ZPe-A09m5Hk%pZ?RkC{_Y+L$C>cKMVc#;KvISLbVbs zXGojl=Y5aT6sb&VJ?)dM9oP@P5K#p|_25pN?e4X*=J%X6+vQQ6z3M!YS#Y&z`X?5l18*J8cg0K&j6WB+DH|T;kJISBmV3c&1 zs0Naeu9Ps9f|)1udr=o@Lx+f>_S-e$;PLl6Q(i=m3b_}aJ%A#OBfP*da3j`C{563e zJHU#u%T*4WfMF(X5`Vs$VMkG1k;n-8C*&Jn$%=)70R%) zl^Sukz7)3~W`l9B17-`SV-pYU>n9G6vdXIitQc(^f@hEvqq(FD^&519)G=KAVO@l} zCuQ+!LA7Z|x24#SBNnp<{v=rS{n$kV2QUoXm9^Q&_-Gl@((r65l$}jASuz{)SU@<| zz7d-fdUWqu5~G0jT3jJ7J>lunSm!q-qa-HM!k?0e3@A0UGU)PAIiBkT4nJcgpOJ)$ z!wqSBvKr~Kg>by=tvNO*pVlrx9)ip#gQE(b^E(}+o73oh6HWM z%CoG~^H{^LPr@+MR>ta&VHn%`D?Mf~%!36Z z2VL+L$Pv&%ylS0V2USt2BQG3!=1$rg~TW0^e zIJah|C@x8*KPIZTKB%8ArE)DtwrP(uF$av z1k<>EVg7T3nYw7`(2ehyS;N6S+XE`7v_ai{^;1S?5_E#%vJjTPcCc(@@!H|pbGPa% z>QU7@yaprkTf}Y6#gS=6 z7XADfkMpxzhzwOTp7=8{Q99oFA+>dQcd?2 z;QL<;&-c|uruL4Wl+{q8PBS^FU(ds@Bbu2CxS}8T_wJjv_}o?INT@ePC=s42vZfx! z?szO#{2Xi#G*J@0^ge~kmb1#);Ac$n|w%XaWOV*RlVYBGMd!sti)^eK!mo?Ot{@ASH*Du=N4AQwJ0Z?|*Zn4I2*td48JuMb++-1N#w#mmLJG>1 zCl7^nsE=Up!rUxJ>L6*U#oJ1Fo{NYb@9&|IRo{;!#c#1=vEv+l13OwWCTdpLOHPO- z_Hh{VVzD_PzOJg&D};4-EofV>zQ~1cYwI@U#&@UbNZsei_#%gylNT8@NWYi6exDmD z*{`9m){NI~u3PD$Em9Gf7Ov>}6274BgUjfvE0bDx?Y_mSBjofTKk+@=9O;QDWHAH3 zF8&yP=;t}D0kPgVu_SHs9fHy$l!QFRo$(Qlkd16E_XlL8JXq6G^H!MIApe12K|IHk z4(2z3KBq|=ai^(>z9u=mf?33`q_*#SeFRaRyS@FAD%-9)R3kgTa$+q;{FfPpA-6ODNRL$9j6El-iIT6^(?*_&h@O=sVZ-?ne`t9DC!K_ zhFuQo2@lt22&Q^o_y;EOX(j+%{h$mj3iPp)FN_ag?>yfOC5^{ZoZFWZaz57iB#iAXjEod#6HSyX%t}JZ3`G_7XJPmAi)OmL-eD# z$8O8)QIBfiN!*wsP)N0WfCG%yoZW<~5kPA^YDKA82I>9pl4+8AenojRS--+- zdw%on$z(p8&8ZnT0NOGuOs6RFz(;@hGI-+_%)K;?M8h1**ZDo>J^^$>&Fgf+&&RF* zn5T;o<{q@zwbbj@dJEYvzBPWDvo_?sfi~^!G>gvqYn3<#0}veDtf4<$m&M96+Q`?m zvL0*Jok@sVOn<-nEgbjsiq6KD#aJJ*vX6&SGmhqcZo?jXJ#z3koy0-W`L8XbhCJ$9 z-x8Ci+49U@_CIDoF$Y}rzrG8~<)tWaOoa+fv8&RhKozdpY#vddLX-1pqd^na(ml`U zUYz=2Yq&gaeKX-H|u`Uj}>R~ z3vs;pc_b4zR?KGKwW&%Cv9>;G7$#4{n%2TOQrxm$T;V>lXH6BKI-E*S+%^ktR1ZF< zZl7&Pb%-!x9vg4jezJJ1&g(!>UX+Rb1Ha1@OR6LqhwU}l&_|-Z&5tT0Rsj?tPS|4Td4V*0)%W{zTvO_0wp|19p zjMoTI6M15LbJYsfMUs1(+Ue<@gLVaPRHeXi!2TA|^|{;MF%LofE`*!O>Y5wRq16Kl znV1SwM_xR?6>0MJEy3aoPk8kY6f>CGAs$vV0w_J zJDL!BkwB%#4;yqf;a)2`2g^S!rEgQ*22eFwn%Zv#J_MZ@bHScUM=%{k-k?>5myUlD za0dVxU^n4ku$Jcn*1m9Gk{Dau&)}yi;RG0(F%F6C=ZYkTn|~#D_;K zB*;X?ZG#JHq68-k9M&-~#=C=sL4W+_V$({-8c7qE(x2nC8`btwmOMcT!SmT#e|JPL zc0->Xc`PHpfdc^Lz8L-ua#U#i+ZsB2^yCr!t93wBa2N(KGL~lqg?9y!qY5{8CBw&{ zBZzgWF%zpU1b!^yqmSc(FAiH@3m3#UGm-;&wCX7=EZKjTtfrkap9`7%NMGz30s3c8 zlglPpC3Iq+!j~Ta)uv84gJ1;H(@RZ5 z0O<}-A>F~);rzV3g0@+2VrWgqM-S~MF@9RRc*52DExO3hOpaon&JH6~u?`JTcg3jz z7xEku*&I}Fm`RTKI8E{&VB)_p{mBCmxDeR*LWNTE;PD5M>YvR&`+Cn{gPN`OHP}Ga znE&3B^c4jCxuxLC1J>lgu~F{^Y>fU->0NqgY~SM73R|wu{Tmdh0OqWHEYQ4u3{R=? z(Q>K-#w0Lzr&E$UURb_bFN&ID_YS3}DAiP&I!Fw1d?m{wiQC9!L=d^K4|217~#*GS+=h{M2PF_C%j`LaxVx#A8)*x&=nZuIRN10<_%i_eT;E7EOgLsvyMtH5{03|Iy6f z`n^Dv+I8u<<=8r(3!rMwIYTrR$|W+@_(}f%#zIbZ-69^s{~xUh@{k1a3A*h%9$SkFR} zs^4eAdx(SOOMV}thYg)D4hsDWCg>}U!qRN;C>l5o)jzASK6*+04;ixQsd0mxg3KFp zH_z8|l5RBsRO%*lcL@Rwxbw^a0thz;fkZG9^BHFL89`ha$7^syvJW2%;cIXr-QrNe z%Mx0YNJ%x(^cVgu2CgailM+kUqWyGT46|ed{5(`hlti(7uUVAb<@m+BxB}jV=XP=_ zctK>d*F%XH2&SA$wZR{g<9^AI4Gv`T0)639s}AWaVzebmTnxXgYyA&FgFU&oNzxYG zne=p94Hpb>uF-5OR zP(+`)JYK;H{5!&ILU7a}_u{^=zwQGS!sY{2ZV-s#gt@N=OGA7&0^0Szc{3Z%j5@2<`GprHNI@=`E$}-T27_}l+q#N1Y zdC=nA5eEUCP%Mf459J@hXXR_2XGlZYuD-in(O~n4-|cTzy-x zB8$_fH3P8qXz3j#R(r|zpr3Da>2LIN+n6;dIYR%_00H`z@R&7t0dD}!<<8w0>`ACEn@=f3{m|ZO0R?akcBhpSI+ zZkt}HXRP=+YXm5E-uxh1qVu=WEm%it_-2=su-Ke*rjv1e=G-y6ByqhzUfD=0u+*%c z>`!2QFNi*5Gk~Cne=>?Ko$aP{b{A((gPiP{I%Qb~41>T~PGG>QSLwjbVv#<6KNufbY)_57r}ozfe3qBGdlJ)2<@hRPn`92E3h&@QOgXH8C7N}SREIevzX zxWaaTmlt@MZDWiP*>C)9uNt>%T^G&HE?MSGToh+iY2R^I7w@B{?(}S!{gJKpf`X;P zagPM*2UfcrdzmIzyVW zDGxr_2(|%84#qlH4E`l80J7gzFj5~Z8uNMpB0&7gxXj;4f;6+mrn-GCht`)DqxlZ! zg4i@2ialzsq`TQmv>8qp-C{j8jXjmS6L^4oAl7r3BBh4m{D_T&D~J=BV5fD!GW?1jmIC0?@4|NXE-{ zijyR;e5=xk!JC78ohyoSZesb~njqFFjqO@<`iS`%L4f}7`PH2s7m%B)P~}rHCFk%L ze7V5)-BtcQKQbT_;tjHEkqTxZ=!!5fI)&(;WkFPyL(JOOh#^J~FW5e#$Wvyq%gfDXJ}(CkKu zT3KnyFU*`enXMC{!zDoHTy3j6S-r?bDtU~hs(S!YDEsZWKN2whXViwDmH%dpT zkSc)w;nVv>MaanWNJ#x5_`@f-o z!MCH&5L4Z_f^h;*{95dEh$CdP5V7({;}?cn+SVmVMoE!6GPW9O5PV-J<@F~B1|pXK zUPMY_nzRwGH3E{x?415eKLmT~c>LV1elfP#iyWmU5cAHx^&NHzbmDPKeG-_ci|u2v zj^ryJX8K=iGKjoTHMU7ZF zjrUi)u+eefh7|eM@$g8YX}RRcg&^2YsCb%7GPV<>jKo<6w{1iNFOX>3yS}^|x@h?% z0(y;?bQ;Yb+gi1*RXkc%)&?6>0Mt_r*f$J3g)d#56P zNX8kFTzkyIfvr5pxsLnv!2v!%%$o?}D{;xS^psB@TJk*GtrU)&!$*hXd~(713BN7i z{q5~zydIt7S=;V#`JkgcLAuo+a7x+!_#@ER0 zzW3*=_?S?=ld?z;xqD)=|8jJ|d;C#yxZmT?I$kc!lAokKllP+B6sbOU>TLO5dE;3o zpvzRWj@%?t&VdByq$~3LM@(;ggJlo)jTjIY8N6umdCHo zH%i9e%&>?r4V%k{NWW1HB#PI}FJ7cQ5*nfI|K@(jHh2gzmA5P%W@3d27gyh^uHY$m z47c!*Nj5Vwk@eL-80nwnjy^T>*_u~iYTU?KyaR~C|AU|l+INVXINE1BV#lg)ahtGkF`=@+Vwu(>XIkpP7LHv5)N1SEHDnO_X2HH#1vHPhcW zvOBbxvEeJM%8_wW6zR{1qJ@lSwcfz;5k-6gCvX5v>bO-gmTL5a(!x*{uaY9Z0p@K& zO{6HmTo6XP`ZFx9r0(bU@+)`13LLXjZ@?^3Lq9#V>>e)*I&%u)R$yjTQ%4v4+Y++lIB~OvL@etemnLTcQ-iG{jsxo zaa@4pEf?+k6y;K$=r-*snh#t#=yM&JRHpsQkptHC&rYwvV`-7lkYimJQ&um`P%Gi0 zc-^eo|035W4%0Gf{(mgPal3&%l+Vq?CHDYXFMK!FA?;#nQEG~_967Tl$F7BJDlVsD z`72YK^Ui%W=hmZ*%EeX0p#4R5BxZF|C4ovdZvQ;xIZ*H}DU->=MJ1Tn!`YGa6ro!R zX#k_)!tS}A)1))Zedng2BS@-&#`{~%qywU!4nqeiP%}l| z)RPVmjPIz!Wfb70cEl!9NYYm@w4>BNDW{hcBon<`tfj2T2!HI_1i%i>QrcbMC~a{# zJo5`{;FJqMjR68F*o@_q8}Lm*fM@U+^O~`Ta4;29RZsYCE!EYl1|J(9Y z-jR^>F5;8z0V&cNt^`?Q4i8)nHt`DHOP+&3n>ZRi8s3GIS+Bn<08Wl&gM(#2&~!I4 zw8Jn!=06hzbk7jEIM7v2it@|$E+8BFE$4B;dO!_)5_hP3yRHYFPX9Yq#)YU;bp%mL z(#3Uyl|EJrsne0A+*|_amGo5RVU?vR5CQ#(hO4xsu*>B;1Y8&t zv#TY2kH^okdE=hVB?B1#b^|;Qq zaTTdQW$gLKMKwSI>(=*T(QRqA!#=g9?9_uK=2QPQmiLxFSlg2;R46~kAQ%k0a>$Uq zB>=4d9}b6az~SIZ{sfFIcBg`(;=jup_H8z7K6EUyxXTBB4s3O@W*={DpdD-UK2bD)TczR zI$Hwtyaa8=ETHi|*HgZOVeX6*t(SulPeQ(Gfu#cU*;*fMLkC7@GIZ2j6C`#ji$ulg zbFu#_%3w?ekCBBevg;?ih{lyw%~D4CrlqydhQq|)bKZu6Ogzwm^U(JeIO%t`uy+%N z`EjtiuZxck)I=R068w`!D?g$G#sFMsit#uwas_057fk#2@&H3EjK)NO_kI7~iefwr zQ{XS+c2BIBSM3(GiD&Gi2RT&Q#3#8h31L>^_EQ`X92rG7?%jcxwlz&Nje%$&z~aP) z#1pmTF3bcy9?%!HxGw5Y8t$hQeP)z%nJzeB`9aBXi6B9O_qHd6xM}cWczD@^oq9~t z(dV6sFMym<(mMtl*sJ!(<8A;w@U@YH^;P7^uv1HkGJN08b+T{bFDt<0QP28McYs(V z_Zqiexsi_R=L8t>2Heoepcp&T2vpyfZXZ_qJ4H{WVce|;+%aSIn+&ROGELJfl%jum z0frN=0ZY(~nOH2KFxVIG=mK8aL*R914X`WRhY*tpIv-lzh}( zZ+Q+YDx3ILVU>146-E9<6{YnvieccV> zrN-1dPpo>iYe;zo3Cj&vft3 z9RL<>O8neyWaLg7XQn#6M^fNo@45_bR|HJ#PVf^fDJyKRFPkV)q7_H)M{nEeq8@Vz z!&@Nj^1SX0y^WHEV}F0W%Vw+U(lwuQ|b;-@ypu$rb5sr_x_KbFsQVBRB~=I z!Yso{PNpEhY-8mSZU+BwUh9r2z0tlKnzidkehlfikHK2dBlOPqeVWA_&rbRBVZC0X z5Z1^>UFsmNxBMSErWQcL%p}xueZVsu?)d$1qXFl=F7=L583a}QNz(c2>55QXvau}d zBP?HD&!+wn7UZ#1D_sl_ffEK~%)$}tvzxYJ640h_tK&!cL<^Iin_ZK8gH({yr4o|j z3IenYL4qaSTI*cUyisMIi~DkO^H0;kxPW3E@pkDu($!yf6TFviupPYRz8PjBp*t=^ zr+F#_JBPNHZr5QN(l;3C?8dBzgNJFZk-j+)tFw{vxvr>}HxmIs->3O+nrv|hv-zHX zQifojYK9IcAebr@n+AYR-k~q+CC$G#D4ItsEus;+Jlq%D?gXkJZrJA-jh$6b%n8;A zb3}!Ty(!3l4)3|(yV3I6+3N7-Eh~hXEL>jn1GY~S{1Uvfo0;l0abym+6@<(8KNYyP z#T!L9teYRY1EJAfJCOL~79MoM+-Jzn2+OxAZNI-B=6?Q2xBoT)de?obr%KzYd49A5 z*KX(Ol8Be1O*%*fgoHHa`SIj&&;yFwLQ=g%3YH^*Be>W$lV#`4$gO`^veq=pX`nLO756N39nms2Ogc zg2G}XRS^1$&W)T0ggRESdChKRvO;B4sFCQd&)j<_^5**+=GY+Kwqw;<5FY@S^KGDB zu$-y-l!C|1ll$eysSpNGx5ni}I*|87P2%}2;GPOhoW^D&Asw@N^$ z&VARmos+`ag1ez7cmih{4Xgvrk|}+b3g)z~WYP1Inw*C!kmRpa5@mRJ3)o^5tsd@C zq++CVff)3?l+qK&@#7(Evh*#KXy8^eNSDUh-I1;rU8KTO`(WYh*wLJ~)k1fiblMtX z2Hg}1u2$I0EAa4TtyzY4{;-ic#8;e*WQ?iUUXjd9vGMw!1jV_jPthv5GhSNU1AEw} zR;$N-v&W=qc+ig%Us~^B*_XS|9KGI*$!Q>uVGpKqr*(aAr zvMNh12zSVQ(e272e|sdyi&WT6r!PWiRN?mb9wlIy#zmjBcVv#_GfZ=?Ym2vSNRk4& zeLeIapEpiSzY;#Ei{!~+cW-q8@`NAvBMiq#Niuif@GX=t-BhP5P%6G$bSPlL93Z4) z4~-+lyi7A~%mJysuIj_{XwGRnV8ki5Ovt9ON3Lxc$d4k@E{_wvF*hD_!%yaS}UT(-<=ak!Tk^rDSDIO`i>w1$KZ9qA zU2F{i1+6H~(1+mL7fGl@=HQrKmsJ{l==0{cQLhS?W5P^24u9^<18P#5Xd1z&@Vdgs z)VCW(@qUN+I7`7+g}KXv_P_e5YXkez2KV0V9ep=eDxbQ+-|XKNx<7$2xd=bzj@k8O z>hS-^*joog)pmQsFd&R{NT(nrCEcNvij+!8N{MvGP=kolAxg)9N_RJilu|=?NRBkp z>35CybDwiR=RNWLxnUUgzG7W#{bKDBAM9poz*>eUu1f+gsQBpI${AAcn3X??*eXl^ z6!NKyH}}3LQDrt1B@!Npe{BMNcc3u7yE5p@=V#Z7;l~EI)NHz$;Ul5%8!TV>dF!6u z*yvv{;m3gYA$&>26)%V&uuu7^&0Gmr9qMwQxYFx~$PBSZZ9(V?UKs(8eG#{kDGaH9 zyNZ)5@&|>!1@Q6MGE7@gap@tnV=8>Fim3GBjfI*&7!TJy-%|mjdnb|i-cIW>ym^0n zC4Y)7ra}2>jhLPb`3+l@rzJccRbQ@pqaWrSmy6b0Pd+bo=f&>Ijhef5uA6`M&hnc9 zW-1;koVB{qu~e?f!w%@Is$c7k4Pe@1FY{qC>UKa#d*9mpxaQ;a zWRX$hG69~}ESIN^S+bt_0^(upIhwuCn1Pm^!Y5qE!KvB4}S zMtsGnPFTDvo8p{a@jXEbY>{nWJa-CAnUTE)N>EbTYg^-AM`cDf-}(Vm0GoJ9&RrLC z{9oEuI?O0)8*LRf62NaKAUA%NVHFQJ;QnBDX7tgIJOWriE%h!Vzyfd$*#I(dn}%jV z6kq{w4U}Gjt7MuO9Z>6)$S;R4VHmB18)3ch2l-h{4A;lvKSUkNX(^`zkn?5aZ?u0g zPW>ah%L1}H3OcNL;FADK2TGuHm}t`!21*B()pv>>?XW8>mfzAp2+rg@?X53yK(WcK z{|J}e9ptdXEy+MZTN2uLWek*OI~O)0XqZd=+>-%dSQP~;%RmHFzZG3IwRY^Q%0uJX zrfz>}G2YoR&yF}}RZxFfjb({>R<^gIqW-nJ0Xqch1izR1;*%U}sc4k2UCaJe^N!Sj z)>?rZ7`@Lvl=ZA2281{AfX!cShd+83#DET?YCQ;Sa_rhsE8y*`Si}QTeC8~y8-3c6g&cBFc7eR=(A%Qtje?7porZ5tduB&@=I&h>{;)&q>P zc@Wl6`X9Z@d!ScA&R|pl87yb-?FTQT53`kGcpP3}*>j6kdH|l;LU8)^6sWJzrMl2j zwR!3;KURmnBv`TI&Vb;ywlG(O+5 zuA|rtDC@EQ`B(>cxB8mI@OCquS?qmtUClR$ucHE^(id%(|57_APCY?4_B)D(h8 z@038vUd`i%OM+CO^45QK9c4L5i3$Rm8qbjK^G;03!ee)P@ufBF19=q81;)|Q)L1(W&c-u|wi>#QQi?kH2tk7kR%wOBSd@{4( zAE4o!Z8R;u&$X$IeNegs&pRYX<{X7kd<@uh<+C(K+mLX9K?$(b#cvlrIm3%#L*D~C zeyhr_F=k?YK%;r!_7!%m!C=hwm4hr=Hl#T(rjLFzI~@qhwlUF$j@i>2N4Fuc3D4G% zv+JlQKJ9n_Dr&W50Q!~7fPRW+9rH9a<q8{ek}gpMWBXjy!byCU5hjarEIcQbD(0AgWi%PLfUhe+bq#s zgPe_AmAxW*w1QqqopDUT-JY3eDhA8LB_T6{dlGAJJEx8$oC0`ARhw_d=xc6uuL&AG zA^ftl;{qzIzB`|RNP>&k3{x(sUuK~V*a-0B^x9Ns>Tr#hfD*wo92&)S^(L3zb+$E$ zm<(C>93{VkCeK0Y_RK9~%Tu8gsjm~Li}1ogzDQ+K4x}eQ(T7C%uNr20QkL^);LQj> zK26O03H(TEBP;lze%vuij9R7vD49{Z4g}`i9K6K|1j+`BPd4lww?UVpjc{%{4+17< z`yV?QKqIlm#Ek;NidtMZ3|Dn&&z6@yBEI-BqF}>|>Jo4r_zX0OFD-IxHynM=!&x}) z0#M%Co5UeZ$k}_!GB{dLVF*H*=W{Yuw9;Zhgb3h3SGQOyI{nP8OZ3xDpZtCV{s2Am zKn)Vj>uKkE8awR1>_^f_6N8mz5F)=!Q?(Tc#PtD3Xcce%ufcnhK)dvPLX{j8?|mhu zI{O4Ly*SU36!`XB!5!US1hB;63_~B4!nG2T$(oY}DYwq%S*#tOKzRS1)#2p;(o zUww~>NOX-J`FD-}|HweV;G-c#fA^UJSA~MFH+-3Tz@O&>i$W6~yH44)fHLjDUPLuO zH$*1a*TK?QKci`P07XOgGe0%yAW*Me&c(vFkFh0Mexf}u4}p2)fAzdPuE~sV{PEUj zN6faw`8e@$2RLMk`q_4TnG9+yYMo-}p=^i&ql4HWx~-Q9`3nT{MC7PpyqO}_lkeFg zN#`6m(r1RAC@O>=C-M?gI*+Ahhq_$XPJjHe>mfLY*Z8ZMFWtO9{WEJ}>;^cosSSn! z84`=y=Gwddq~CE^$JNTI9O9Srs)tFSrtDW+I+3l0IC^seJb>8^$e;%691|VHih~yJ zYd5JV;(d&M8qg>(hsoiR4Un1$js?1UF3I&jfw;%&=i<3yAy=`(-UwlT#_VF*1Har5|Re#0B zv+3q#Rm7-ftodG|fwBss%4&IMBy{r$uIsF4(8KKZ>?qzK%0_b|)A`vAVt1lSMj*Sr z*EVAM3M&(GaKC4$CT!G+=|;_}>(8-0%)-(rS!XAYJ=Vpnf4Xo@T0Y%Oo;ZK5En#-Q z=&R^)iEllc5WFr2xk?FyZ@2WW3kYB~F&3ZOssTprSN?b<_5n=7akU;;puAZogc*@l zNQqMMhkupUa(_ze_z}xer|UPEfLcy2^>*=n=}9h@t?Ec(hjop4=`z{>T1xxnW1n39 zdwd@!L4HkZF#u_Hje79M;>+6U>{>_XIeNB$FL|q)g|9)T0*zq;Q|j-<2nR_Sp6z_;(U(iUe@WSDfPe)-cHS=NV5SFue?XFofx@?$4!!sL@b|z^ zrce%CB?~@9qJiTgn9E}FzZc!WeJa8Aiy9mw@c&N4D!v}y0eeQP=+a@M9lJ$qZKNnq z+{K7^xbv51;#UI1yXM}&Z3`iDPmyE)w%f%dYPXo2`V$onwY1Mafg5PpzDEn^#+5c$6?0vskBe^x|lmmS;6e z?z7ZAVBWuR;&n5nx!&vOZ^Nq`UyQ!F?)8XKjlWg@xg%$@7-v$K%Umyt!m)niEQmJe z6^9@DKO3oY>^#LV-tSV93(fsi_!Wb;U}kt=i+Ffx>PAi>r0I0<;4o4?_Bp2{{hegpOZaP^I7IY?T|#G^^x)&4K4GktxXpT2p8HavKlD1p!KEG9%X zoDIO=Y_`Yq-tk>9S?kal;pbr~z&Pa}l2AJ?Mpw*8|7V4+NPlej56PXXwCQH?M)i8R zTHPbq;tzm!2PiEoMoe(5jJwT~M{=~_$3{oZe!dhr{G;`cGCDFrix}E5^kvsEFw^M1 zpbslCzTgJnUfsT!1umKf_uKUDTl+o(6t)MX?Z1y7Z*9}-rGowRuU-3Q4a5Z8ZVyrh zEsE(aYXB==I@mT9hquRp*M2c^9>fEZT4xWoPg&j4Z$mwY*WJu-Ah_|PSvvrTDbg%M z-Gy!x0BPUQ;#pck`~PckZc>*{yaZ~7-m0m5uwOldy)J=np=ShN3EPd|@X&GKXrhRL z1vZN<-%{*qTDBj1d(9%B4<2U*`FYpMIlrY=na+ zy*u(wn14d5&RW4B>fKLCpH*grO8)nsDK0-vHX{`NLjYj4DR_m3G3Fe$5gtInj6R52 z5W3?7%pR-=T!GPbTW~f1M9yK_K*UbB#BctG?T56Q5UqOM;J z-Yon=b5<2@!nwPQvfPr7yPe*;i~JVsE+#EV`S^eJN=q9!T)ysWZIMns7=Di8!FE#! z60qZe)ISfT7AL}-ZPg^84~09Ja=O#!nfnjCF#RSLuAN#e7)?aB|Ch?! z9-tEKKS}lhDkg4E)*v3fUD3J@di^vJWuH4efYcK!>^m(->FuoDr1qrp%=NDV zljNEZ&>Ve;^rZ~1h{*i3{X49IEGHh z=@?uAHwj|^j^CsiX#+kB?$lq6EL=@zei=hCXMLjmT7YBom~>1Lq2kJzT=2Z?_R)vN zysz-PN9zEY1DpE$nxG@Ckd-G~7H=nX`D=dw&@^a0zf=AY zv`x?!6zsM~1BW%RDX=y71#{EDm0ERuJ-9j?-kAkX?t1KU-&CTGa?smC7;|>#r;GoS zKXKK|=53f2_%0tqOc)3sv2l2l2Lw;r&rFHHlDU_E90D>Ej)myM>!_>ly!0nPs`s-w zU<`l`90kuFO)+jX-Nj}~!ay|y%ExW>{HM>90ui^otRAiQyA1FvU z36ymnuwphnRK}?Tj*&lk7eLUBajJkLG54E}E)`}|z5iL0flA@A6||o==WDervTiSe z5mG-tymFC^7EgkHCnef<0xaJ4*9G{kI;*sz1@)CYeg%4j$9d~#_xN1Pxy=0T{Qnws z!10D+1n4%#Pr1OxJB0$2S<%d zUwoomzuK7Vy@8B)Ajz2xr3`yl|b&e7b zCXzjFi>Q%xp0DChVj05)d&7_9ag)j|#JCh@Kp{{GfW8T-pl^c4@nwZ5=B%9lsM*kw zo?{DCoy)j~aWI%Wpv8;fA5+61#KMuW&;HWx;-=zUGl%QbLq?iG;+1g^Ia(a@f?Uw% zKuIWQDh$pzVo^{K4mUQE3z~@hmyjLJN?p#B0sO86>MZ;?E~E8r?y*-^94Ccc zKX2Uj@gL4<9B@tnD=UYU0PV#jO)_bWy5_xqESh?X3#5G86#;tmoLI=OW@<*DDaM9b zLklGv;+(q#rlu-ilCXcJp8(&^C|sA|!fZ<4PO0(maoxFuT=dm`d$TK+b~*-Z?)$$M z6|daTrhkY3!}K3tPYAjh_+h^iqal)Q<7!Nf6|Ms@c%+j)8tXT_)Nf>T zgNWnz$3#A1w@koM!s?`$s;U$6^9lWq(R@9|=}OfN zw2l%NA%`i0adS)_g4u+_e(rnypXTj2OAs#k!%da<@IXE-0vN0moVBC1za%O zl%}NcX^#n=F3^{#|1(dCci*4t)_rOe?yE`B0(4b7Ler3s*-QMQ06TUC&yiG@C`y4j zTdCNa@)qu3%+9V3x(Nt;IO`i3oY`p9WjF>Na(?1s`bX#tO!_nxN~`>aj+n`Cdd0A_ ze0m%>#``9w$5gIOB@S2;;bpt0=dvJt%xp`OfqnAdoCaxAqOpH#0shl5 z%5rlizm;>n-%8&@3Ef&{5FC&BvChsxM)iu00XR2_C?4D>|0&~dJgZhhGP+A;5Yon{ z3z~lzuC=+-{}D`l1cC`*=|VRnY3}vRIhm1=n|17zRT!WMFv$$~IaPYnnr5mMxtUP~^<`)4MV zjF?T0)C%r5FlC-PC-8!2uXfLrh(XI6xXHl&>28*1@HO7danz)N*+CF;QxeECb_fiS zm7OSwR;fknIeqEHI+~orHO(L$jV3sHfy18C^m4HLV|%qOmf%uS%fwy|PQ6KCMW+lO z(}P=}<^8Gppap#HUr2iWcHW`8Xs<2olhiRiWwu9w;lo|f-j0g=ZHGO;r^yY%b!W~GsBpG>ws8_R<$Ujo$AU=$i0GEm6?X4-~nFp}>@8`5lNt8ASq53~> zQZ%Kil;?e)1LcT4g~%_|!hLD)3XB~ltyCmNyXgb4zoOgY(pZKZrcV~KuMYaiRYL!? zG*HkU;9C|Hi+={rH_jP&4I2Vidg1mrR)p@iZj73n2wd@*+YiCj;G>M1XIHD~aYZ=# zQbb4!+j^X52B3umal#Va3Ox2jO_N71SNbD;mV(rjIg0Y1+*!QeJ~v<>ECoDUxmMf0g1=q_Oz?QGKOU4SG-PH1JsN)ioNrTX@#ASc9`Uj_OeC1RJh&0+nc z7eTTLg%Ww*O8@6Q%}apOp8_KXPae?N>yBde&fHG@&W!8eChLK@Kon%P$hj)9AZ^b| zw7|8mTrjP8;k)d$L5%B^uz$Q-&(;=vxd0ps@euJY;;$~sJM<@;KU-h}85v%C*^3l~ z${TCrSF4vFkIl$pTf~3wIY2zJv3@u)TgWML7v8`4(vT`u8lBsT<2p+$A+SRPQmbWF z5^vVOoe7Ka)?pk2Wr{ile{eQk8?@2C&dE+Dzpynh3Bv<}x)^~=OxTQdj(JkBfB#@X z)xBsp05f&DUh*V3e%~TK?flk>Otd$kjtqIviRprC8p7qlgh1;u35S6M-( zf7TeRx+WqlDlQf+Rd~ZMd!|FCJa?;4b3+W$B$CnRo2&QrzqC8cZTRnXEjcRwtHx{*LoA>?%cQJ+y6`Rw5=It%W>QPk@i2x zSEf(4!ahJM8pVRnTS`a4i>7~!pn8D(H^avoHU&Ot7S-jJ@N0RC--`ps21t-t=b!Y?V0_*n8ElmdG$*kHd2WoW({2qLNHwD;~p5FGAd1eOY zB46N5Hn2VlYw6y44>ykW%S0O$!xFhEftq`wtyLJ6IDgJxy1TQ4F&kgvX)nFMkA2YE z{^%yoUqy%oBg^#u43I0pl8MgYK*Y`*2D5gjrTS7qit+8)o$e{QAlewop5VxGA#(0au zyUS!0YT^l%SmmQ{uDra?yH`?n^e->kwN;DwB>}-`{5n$-WcB&AJ(Qpq+H^eywZFj73 z;yat4qat5Y|M`n8_?o}NqD?96ADPugOEW;U9YYo}I@KIDMpF09u z9(R@RtosY$QKd1dguZsh+XXExZwHNEKrY9%`d!RH5Uo2;ME4eJeDo+a1nyvV+o}(w zf84}RKu55Y%hH^*UAyDTTQ`aB7uYfjp~uNQ^x|@@R8P2&5Q4O-9m@UBk>pg z!DFjpbI=JOYW3XmC8XZuUH(ogaG{;;yd4EDwEKBiLZFn$2;?GnYlk)C#_qHC4iDC4 zR)qs+#=}%r=wAh)cf&rXAgA$T6ocj@kKmyza=)&3B9ishLc%y`3ScZn55EEeg4cRj z*Fi6%#Lay+^g&dryaaT{7L~;DfFHJC9ujqUYA~=hQ+t8~Ds0GdNV79KpL`bpacYGY zdd_4RxtBQJIJ4FK!wmEQW}tpzyFuwXsyV!H6$^ZmLmfXA@GuFAYP{J7Q7o#{-V(>UFKUPMtwIsWqkmadN(oZCV)3~588qa zP{MGe@f#Gi8Bnqga&Tnn67p64_!5ezUtGu`XenYk_oGmAv2e_dG%aQOFMgl7 z!g>&*rjJRqNX4ESPE4<+AG<0HKNzZfkUYK0E^(TJJeOXRSo2Ark!|tG2!26|lJu=R z{337qykJkEmy1{lvG%mSe5nw6u<0~Vr2{UXb)LQyzAf`2`slQc?%Lzg9oF3Zrh-Bq3s5V8(e1J&73Hmq2|{9(WBg zPkvDAV&3!GIBsTWQ7rtBg>}S89Ls#7rsFye6=nS6K;#HJF588Tt>b1hbAMdfL}6J$YtCceeW43VL^SyxO-63BPSd=Jq% zRZ96f$ULNylHnk3$4rU|KFt64Ciq5*hrwFe^@TskA<8N$sy8E&8;16R!PB6y$Si-8kOa=jr9QD& z!iMF4!mCY%9zfLnX*0o7V(A1@f-yvdY6#hpqFzFJmKH_E&Pwi9sr- zD~;9c5SfzU0u3h?WEyM6k~Xc*9dkpWCtVfH9vZ#Jyr&D8fby7 zh~QwoH7){H=4U2rY%6^#hTeADCG4~Fs;jUv@WW^*rr-60BzdvvG~RY$_Jw@{

    ? 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 Ur*$KB7~oG@LP5M#RNw#q04n|8^Z)<= diff --git a/src/python/evaluation/paper_evaluation/issues_statistics/examples/measurable.png b/src/python/evaluation/paper_evaluation/issues_statistics/examples/measurable.png deleted file mode 100644 index ae8927833c1be90e47a72be391d63bd3dc1fbbde..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 135918 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 diff --git a/src/python/evaluation/paper_evaluation/issues_statistics/examples/ratio.png b/src/python/evaluation/paper_evaluation/issues_statistics/examples/ratio.png deleted file mode 100644 index 52d9953ceb540cdf3b0f6bc3cb053dc09cac0b36..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 116254 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

    y=aTX^`8#*3U7ql+P8lUt;A&*F-ffjMU9 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 bMDatt$hX@oc&0gJF#v(5tDnm{r-UW|!2I%o diff --git a/src/python/evaluation/paper_evaluation/issues_statistics/raw_issues_statistics_visualization.py b/src/python/evaluation/paper_evaluation/issues_statistics/raw_issues_statistics_visualization.py deleted file mode 100644 index 10450119..00000000 --- a/src/python/evaluation/paper_evaluation/issues_statistics/raw_issues_statistics_visualization.py +++ /dev/null @@ -1,207 +0,0 @@ -import argparse -import logging -import sys -from dataclasses import dataclass -from enum import Enum -from pathlib import Path -from typing import Dict, List, Optional - -import pandas as pd -import plotly.graph_objects as go -from plotly.subplots import make_subplots -from src.python.evaluation.common.pandas_util import get_solutions_df_by_file_path -from src.python.evaluation.plots.common.utils import get_supported_extensions, save_plot -from src.python.evaluation.plots.plotters.raw_issues_statistics_plotters import prepare_stats -from src.python.review.common.file_system import Extension, parse_yaml - -logger = logging.getLogger(__name__) -COLORWAY = ['rgb(47,22,84)', 'rgb(99,47,177)', 'rgb(153,110,216)'] - - -class _ConfigFields(Enum): - PLOT_CONFIG = 'plot_config' - ROWS = 'rows' - COLS = 'cols' - SPECS = 'specs' - HEIGHT = 'height' - WIDTH = 'width' - X_AXIS_NAME = 'x_axis_name' - Y_AXIS_NAME = 'y_axis_name' - - RANGE_OF_VALUES = 'range_of_values' - TRACE_NAME = 'trace_name' - - -_PLOT_CONFIG = _ConfigFields.PLOT_CONFIG.value -_ROWS = _ConfigFields.ROWS.value -_COLS = _ConfigFields.COLS.value -_SPECS = _ConfigFields.SPECS.value -_HEIGHT = _ConfigFields.HEIGHT.value -_WIDTH = _ConfigFields.WIDTH.value -_X_AXIS_NAME = _ConfigFields.X_AXIS_NAME.value -_Y_AXIS_NAME = _ConfigFields.Y_AXIS_NAME.value -_RANGE_OF_VALUES = _ConfigFields.RANGE_OF_VALUES.value -_TRACE_NAME = _ConfigFields.TRACE_NAME.value - - -@dataclass -class PlotConfig: - name: str - rows: int = 1 - cols: int = 1 - height: int = 800 - width: int = 1600 - x_axis_name: str = 'Value' - y_axis_name: str = 'Quantity' - specs: Optional[List] = None - - @staticmethod - def get_from_dict(plot_name: str, config: Dict) -> 'PlotConfig': - params = {'name': plot_name} - params.update(config) - return PlotConfig(**params) - - -@dataclass -class TraceConfig: - column: str - range_of_values: Optional[range] = None - trace_name: Optional[str] = None - - @staticmethod - def get_from_dict(column_name: str, config: Dict) -> 'TraceConfig': - params = {'column': column_name} - params.update(config) - - if _RANGE_OF_VALUES in params: - params[_RANGE_OF_VALUES] = range(*params[_RANGE_OF_VALUES]) - - return TraceConfig(**params) - - -def configure_arguments(parser: argparse.ArgumentParser) -> None: - parser.add_argument( - 'stats_path', - type=lambda value: Path(value).absolute(), - help='Path to the statistics file. Must be an xlsx or csv file.', - ) - - parser.add_argument( - 'config_path', - type=lambda value: Path(value).absolute(), - help='Path to the yaml file containing information about the graphs to be plotted.', - ) - - parser.add_argument( - 'save_dir', - type=lambda value: Path(value).absolute(), - help='The directory where the plotted charts will be saved.', - ) - - parser.add_argument( - '--file-extension', - type=str, - default=Extension.SVG.value, - choices=get_supported_extensions(), - help='Allows you to select the extension of output files.', - ) - - -def _update_fig(fig: go.Figure, plot_config: PlotConfig) -> None: - fig.update_layout( - width=plot_config.width, - height=plot_config.height, - font_size=22, - paper_bgcolor='rgba(0,0,0,0)', - plot_bgcolor='rgba(0,0,0,0)', - colorway=COLORWAY, - ) - - axes_common_params = { - 'showline': True, - 'linewidth': 1, - 'linecolor': 'black', - 'mirror': True, - } - - fig.update_xaxes(title=plot_config.x_axis_name, **axes_common_params) - fig.update_yaxes(title=plot_config.y_axis_name, **axes_common_params) - - -def build_subplots(df: pd.DataFrame, plot_config: PlotConfig, trace_configs: List[TraceConfig]) -> go.Figure: - fig = make_subplots( - rows=plot_config.rows, - cols=plot_config.cols, - specs=plot_config.specs, - ) - - if plot_config.specs is None: - plot_config.specs = [[{} for _ in range(plot_config.cols)] for _ in range(plot_config.rows)] - - for row_index, row in enumerate(plot_config.specs, start=1): - for column_index, cell in enumerate(row, start=1): - if cell is None: - continue - - trace_config = trace_configs.pop(0) - - stats = prepare_stats( - df, - trace_config.column, - trace_config.range_of_values, - plot_config.x_axis_name, - plot_config.y_axis_name, - ) - - fig.add_scatter( - x=stats[plot_config.x_axis_name], - y=stats[plot_config.y_axis_name], - col=column_index, - row=row_index, - line={'width': 5}, - marker={'size': 10}, - name=trace_config.trace_name if trace_config.trace_name is not None else trace_config.column, - ) - - _update_fig(fig, plot_config) - - return fig - - -def plot_and_save(stats: pd.DataFrame, config: Dict, output_dir: Path, extension: Extension) -> None: - for group_name, group_config in config.items(): - plot_config = PlotConfig.get_from_dict(group_name, group_config.pop(_PLOT_CONFIG)) - trace_configs = [] - for column_name, column_config in group_config.items(): - trace_configs.append(TraceConfig.get_from_dict(column_name, column_config)) - subplots = build_subplots(stats, plot_config, trace_configs) - save_plot(subplots, output_dir, group_name, extension) - - -def main(): - parser = argparse.ArgumentParser() - configure_arguments(parser) - - try: - args = parser.parse_args() - - config = parse_yaml(args.config_path) - stats = get_solutions_df_by_file_path(args.stats_path) - - plot_and_save(stats, config, args.save_dir, Extension(args.file_extension)) - - return 0 - - except IndexError: - logger.error( - 'The number of traces must be consistent with the number of rows and columns, as well as the specs.', - ) - return 2 - - except Exception: - logger.exception('An unexpected error.') - return 2 - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/src/python/evaluation/paper_evaluation/survey_handler/README.md b/src/python/evaluation/paper_evaluation/survey_handler/README.md deleted file mode 100644 index 4afe932e..00000000 --- a/src/python/evaluation/paper_evaluation/survey_handler/README.md +++ /dev/null @@ -1,73 +0,0 @@ -# Surveys handlers - -These scripts allow handling surveys results for the SIGCSE paper. -We have two surveys (for Python and for Java) where participants should choose a fragments -that has better formatting. -Each question in the surveys have randomly orders for fragments. -The left fragment can have good formatting, but at the same time, it can have bad formatting. -To handle these cases we created JSON configs with this information and another one with the results. -These scripts allow processing these config files. - -## Usage - -Run the [survey_statistics_gathering.py](survey_statistics_gathering.py) with the arguments from command line. - -Required arguments: - -`questions_json_path` — path to the JSON with labelled questions; -`results_json_path` — path to the JSON with survey results. - -An example of `questions_json` file: -```json -{ - "questions": [ - { - "number": 1, - "left_fragment": "before_formatting", - "right_fragment": "after_formatting" - }, - { - "number": 2, - "left_fragment": "after_formatting", - "right_fragment": "before_formatting" - } - ] -} -``` - -An example of `results_json` file: - -```json -{ - "questions": [ - { - "number": 1, - "left_fragment": 0, - "right_fragment": 11, - "both": 0 - }, - { - "number": 2, - "left_fragment": 10, - "right_fragment": 0, - "both": 1 - } - ] -} -``` - -An example of the statistics: -```text -total participants=11 -------before----after----any---- -1. 0 11 0 -2. 1 10 0 -3. 0 11 0 -4. 0 11 0 -5. 0 11 0 -6. 1 10 0 -7. 0 11 0 -8. 1 8 2 -9. 0 11 0 -10. 0 8 3 -``` diff --git a/src/python/evaluation/paper_evaluation/survey_handler/__init__.py b/src/python/evaluation/paper_evaluation/survey_handler/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/python/evaluation/paper_evaluation/survey_handler/survey_statistics.py b/src/python/evaluation/paper_evaluation/survey_handler/survey_statistics.py deleted file mode 100644 index 8cfc898b..00000000 --- a/src/python/evaluation/paper_evaluation/survey_handler/survey_statistics.py +++ /dev/null @@ -1,61 +0,0 @@ -from dataclasses import dataclass -from enum import Enum, unique -from typing import Any, Dict, List - - -@dataclass -class Question: - with_formatting_count: int = 0 - without_formatting_count: int = 0 - any_formatting_count: int = 0 - - def get_total(self): - return self.with_formatting_count + self.without_formatting_count + self.any_formatting_count - - -@unique -class SurveyJsonField(Enum): - NUMBER = 'number' - LEFT_FRAGMENT = 'left_fragment' - RIGHT_FRAGMENT = 'right_fragment' - - BEFORE_FORMATTING = 'before_formatting' - BOTH = 'both' - - QUESTIONS = 'questions' - - -@dataclass -class SurveyStatistics: - questions: List[Question] - - def __init__(self, questions_json: List[Dict[str, Any]], results_json: List[Dict[str, int]]): - self.questions = [] - for result_json in results_json: - question_number = result_json[SurveyJsonField.NUMBER.value] - question = self.__find_json_question(questions_json, question_number) - if question[SurveyJsonField.LEFT_FRAGMENT.value] == SurveyJsonField.BEFORE_FORMATTING.value: - without_formatting_count = result_json[SurveyJsonField.LEFT_FRAGMENT.value] - with_formatting_count = result_json[SurveyJsonField.RIGHT_FRAGMENT.value] - else: - without_formatting_count = result_json[SurveyJsonField.RIGHT_FRAGMENT.value] - with_formatting_count = result_json[SurveyJsonField.LEFT_FRAGMENT.value] - any_formatting_count = result_json[SurveyJsonField.BOTH.value] - self.questions.append(Question(with_formatting_count, without_formatting_count, any_formatting_count)) - - @staticmethod - def __find_json_question(questions_json: List[Dict[str, Any]], question_number: int) -> Dict[str, Any]: - for question in questions_json: - if question[SurveyJsonField.NUMBER.value] == question_number: - return question - raise ValueError(f'Did not find question {question_number}') - - def print_stat(self): - if len(self.questions) == 0: - print('No questions found') - return - print(f'total participants={self.questions[0].get_total()}') - print('------before----after----any----') - for index, question in enumerate(self.questions): - print(f'{index + 1}.\t\t{question.without_formatting_count}\t\t{question.with_formatting_count}\t\t ' - f'{question.any_formatting_count}') diff --git a/src/python/evaluation/paper_evaluation/survey_handler/survey_statistics_gathering.py b/src/python/evaluation/paper_evaluation/survey_handler/survey_statistics_gathering.py deleted file mode 100644 index 82b8b7d3..00000000 --- a/src/python/evaluation/paper_evaluation/survey_handler/survey_statistics_gathering.py +++ /dev/null @@ -1,46 +0,0 @@ -import argparse -import json -import sys -from pathlib import Path - -from src.python.evaluation.evaluation_run_tool import logger -from src.python.evaluation.paper_evaluation.survey_handler.survey_statistics import SurveyJsonField, SurveyStatistics -from src.python.review.common.file_system import get_content_from_file - - -def configure_arguments(parser: argparse.ArgumentParser) -> None: - parser.add_argument('questions_json_path', - type=lambda value: Path(value).absolute(), - help='Path to the JSON with labelled questions') - - parser.add_argument('results_json_path', - type=lambda value: Path(value).absolute(), - help='Path to the JSON with survey results') - - -def main() -> int: - parser = argparse.ArgumentParser() - configure_arguments(parser) - - try: - args = parser.parse_args() - questions_json = json.loads(get_content_from_file(args.questions_json_path)) - results_json = json.loads(get_content_from_file(args.results_json_path)) - stat = SurveyStatistics( - questions_json[SurveyJsonField.QUESTIONS.value], - results_json[SurveyJsonField.QUESTIONS.value], - ) - stat.print_stat() - return 0 - - except FileNotFoundError: - logger.error('JSON file did not found') - return 2 - - except Exception: - logger.exception('An unexpected error.') - return 2 - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/src/python/evaluation/paper_evaluation/user_dynamics/README.md b/src/python/evaluation/paper_evaluation/user_dynamics/README.md deleted file mode 100644 index 7d004bb1..00000000 --- a/src/python/evaluation/paper_evaluation/user_dynamics/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# Dynamics of student usage - -This module allows getting statistics about students dynamics in code quality issues improvements. - -## Usage - -Run the [dynamics_gathering.py](dynamics_gathering.py) with the arguments from command line. - -Required arguments: - -`solutions_file_path` — path to csv-file with code samples. - -In the result a file with students issues dynamics will be created. -We have three categories of dynamics: -- all (count of all code quality issues expect INFO issues) -- formatting (count of formatting code quality issues from CODE_STYLE category) -- other (all issues minus formatting issues) - -Each type of dynamics will be saved into a separated folder with csv files for each student. -Each csv file has only two columns: fragment id and issues count. - -An example of the csv file: -```text -issue_count,time -2,0 -20,1 -16,2 -15,3 -5,4 -5,5 -``` \ No newline at end of file diff --git a/src/python/evaluation/paper_evaluation/user_dynamics/__init__.py b/src/python/evaluation/paper_evaluation/user_dynamics/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/python/evaluation/paper_evaluation/user_dynamics/dynamics_gathering.py b/src/python/evaluation/paper_evaluation/user_dynamics/dynamics_gathering.py deleted file mode 100644 index 6c4ab4ad..00000000 --- a/src/python/evaluation/paper_evaluation/user_dynamics/dynamics_gathering.py +++ /dev/null @@ -1,91 +0,0 @@ -import argparse -import sys -from pathlib import Path -from typing import List - -import numpy as np -import pandas as pd -from src.python.common.tool_arguments import RunToolArgument -from src.python.evaluation.common.csv_util import write_dataframe_to_csv -from src.python.evaluation.common.pandas_util import ( - filter_df_by_single_value, get_issues_from_json, get_solutions_df, logger, -) -from src.python.evaluation.common.util import ColumnName -from src.python.evaluation.inspectors.common.statistics import PenaltyIssue -from src.python.evaluation.paper_evaluation.user_dynamics.user_statistics import DynamicsColumn -from src.python.review.common.file_system import Extension, get_parent_folder, get_restricted_extension -from src.python.review.inspectors.issue import IssueType - - -def configure_arguments(parser: argparse.ArgumentParser) -> None: - parser.add_argument(RunToolArgument.SOLUTIONS_FILE_PATH.value.long_name, - type=lambda value: Path(value).absolute(), - help=RunToolArgument.SOLUTIONS_FILE_PATH.value) - - -ALL_ISSUES_COUNT = DynamicsColumn.ALL_ISSUES_COUNT.value -FORMATTING_ISSUES_COUNT = DynamicsColumn.FORMATTING_ISSUES_COUNT.value -OTHER_ISSUES_COUNT = DynamicsColumn.OTHER_ISSUES_COUNT.value - - -def __get_all_issues(traceback: str) -> List[PenaltyIssue]: - return list(filter(lambda i: i.type != IssueType.INFO, get_issues_from_json(traceback))) - - -def __get_formatting_issues(traceback: str) -> List[PenaltyIssue]: - return list(filter(lambda i: i.type == IssueType.CODE_STYLE, __get_all_issues(traceback))) - - -def __write_dynamics(output_path: Path, user_fragments: pd.DataFrame, index: int) -> None: - output_path.mkdir(parents=True, exist_ok=True) - user_fragments.columns = [DynamicsColumn.ISSUE_COUNT.value] - user_fragments[ColumnName.TIME.value] = np.arange(len(user_fragments)) - write_dataframe_to_csv(output_path / f'user_{index}{Extension.CSV.value}', user_fragments) - - -def __get_users_statistics(solutions_df: pd.DataFrame, output_path: Path) -> None: - users = solutions_df[ColumnName.USER.value].unique() - for index, user in enumerate(users): - user_df = filter_df_by_single_value(solutions_df, - ColumnName.USER.value, user).sort_values(ColumnName.TIME.value) - user_df[ALL_ISSUES_COUNT] = user_df.apply(lambda row: - len(__get_all_issues( - row[ColumnName.TRACEBACK.value])), - axis=1) - user_df[FORMATTING_ISSUES_COUNT] = user_df.apply(lambda row: - len(__get_formatting_issues( - row[ColumnName.TRACEBACK.value])), - axis=1) - user_df[OTHER_ISSUES_COUNT] = user_df[ALL_ISSUES_COUNT] - user_df[FORMATTING_ISSUES_COUNT] - - __write_dynamics(output_path / 'all', user_df[[ALL_ISSUES_COUNT]], index) - __write_dynamics(output_path / 'formatting', user_df[[FORMATTING_ISSUES_COUNT]], index) - __write_dynamics(output_path / 'other', user_df[[OTHER_ISSUES_COUNT]], index) - - -def main() -> int: - parser = argparse.ArgumentParser() - configure_arguments(parser) - - try: - args = parser.parse_args() - solutions_file_path = args.solutions_file_path - extension = get_restricted_extension(solutions_file_path, [Extension.CSV]) - solutions_df = get_solutions_df(extension, solutions_file_path) - - output_path = get_parent_folder(Path(solutions_file_path)) / 'dynamics' - output_path.mkdir(parents=True, exist_ok=True) - __get_users_statistics(solutions_df, output_path) - return 0 - - except FileNotFoundError: - logger.error('CSV-file with the specified name does not exists.') - return 2 - - except Exception: - logger.exception('An unexpected error.') - return 2 - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/src/python/evaluation/paper_evaluation/user_dynamics/dynamics_visualization.py b/src/python/evaluation/paper_evaluation/user_dynamics/dynamics_visualization.py deleted file mode 100644 index b38ec54e..00000000 --- a/src/python/evaluation/paper_evaluation/user_dynamics/dynamics_visualization.py +++ /dev/null @@ -1,96 +0,0 @@ -import argparse -import sys -from collections import Counter -from pathlib import Path -from statistics import median -from typing import List - -import pandas as pd -import plotly.express as px -from src.python.evaluation.common.pandas_util import logger -from src.python.evaluation.paper_evaluation.user_dynamics.user_statistics import DynamicsColumn -from src.python.review.common.file_system import ( - Extension, extension_file_condition, get_all_file_system_items, get_parent_folder, -) - -MEDIAN_COLUMN = 'Median number of code quality issues in submissions' -FREQ_COLUMN = 'Number of users' -TYPE = 'Submissions\' type' -PERCENTAGE = 'percentage' - - -def configure_arguments(parser: argparse.ArgumentParser) -> None: - parser.add_argument('dynamics_folder_path', - type=lambda value: Path(value).absolute(), - help='Folder with dynamics after embedding tool') - - parser.add_argument('old_dynamics_folder_path', - type=lambda value: Path(value).absolute(), - help='Folder with dynamics before embedding tool') - - -def __get_medians(dynamics_folder_path: Path) -> List[float]: - dynamics_paths = get_all_file_system_items(dynamics_folder_path, extension_file_condition(Extension.CSV)) - medians = [] - for dynamic in dynamics_paths: - dynamic_df = pd.read_csv(dynamic) - medians.append(int(median(dynamic_df[DynamicsColumn.ISSUE_COUNT.value]))) - return medians - - -def __group_medians(path_to_dynamics: Path, dynamics_type: str, threshold: int = 8) -> pd.DataFrame: - medians = __get_medians(path_to_dynamics) - grouped_medians = dict(Counter(medians)) - more_threshold = sum([freq for m, freq in grouped_medians.items() if m > threshold]) - others = {str(m): freq for m, freq in grouped_medians.items() if m <= threshold} - others[f'> {threshold}'] = more_threshold - new_df = pd.DataFrame(others.items(), columns=[MEDIAN_COLUMN, FREQ_COLUMN]) - new_df[TYPE] = dynamics_type - all_users = sum(new_df[FREQ_COLUMN]) - new_df[PERCENTAGE] = new_df.apply(lambda row: f'{round(row[FREQ_COLUMN] / all_users * 100)}%', axis=1) - return new_df - - -def main() -> int: - parser = argparse.ArgumentParser() - configure_arguments(parser) - - try: - args = parser.parse_args() - old_df = __group_medians(args.old_dynamics_folder_path, 'Before embedding tool') - new_df = __group_medians(args.dynamics_folder_path, 'After embedding tool') - union_df = old_df.append(new_df).sort_values([MEDIAN_COLUMN, TYPE], ascending=[True, False]) - - fig = px.bar(union_df, x=MEDIAN_COLUMN, y=FREQ_COLUMN, width=1000, height=800, color=TYPE, - color_discrete_sequence=['rgb(253,251,220)', 'rgb(47,22,84)']) - fig.update_layout(legend={ - 'yanchor': 'top', - 'y': 0.99, - 'xanchor': 'right', - 'x': 0.99, - }, - font_size=22, - barmode='group', - paper_bgcolor='rgba(0,0,0,0)', - plot_bgcolor='rgba(0,0,0,0)', - ) - # Add borders around plot - fig.update_xaxes(showline=True, linewidth=1, linecolor='black', mirror=True) - fig.update_yaxes(showline=True, linewidth=1, linecolor='black', mirror=True) - # Add borders around bars - fig.update_traces(marker_line_color='black', marker_line_width=1.5, opacity=0.9, - textposition='outside') - fig.update_layout(uniformtext_minsize=11, uniformtext_mode='hide') - - output_path = get_parent_folder(args.old_dynamics_folder_path) / f'evaluation_chart{Extension.PDF.value}' - fig.write_image(str(output_path)) - fig.show() - return 0 - - except Exception: - logger.exception('An unexpected error.') - return 2 - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/src/python/evaluation/paper_evaluation/user_dynamics/unpack_solutions.py b/src/python/evaluation/paper_evaluation/user_dynamics/unpack_solutions.py deleted file mode 100644 index 149016d7..00000000 --- a/src/python/evaluation/paper_evaluation/user_dynamics/unpack_solutions.py +++ /dev/null @@ -1,72 +0,0 @@ -import argparse -import sys -import uuid -from pathlib import Path -from typing import List - -import pandas as pd -from src.python.common.tool_arguments import RunToolArgument -from src.python.evaluation.common.csv_util import write_dataframe_to_csv -from src.python.evaluation.common.pandas_util import get_solutions_df, logger -from src.python.evaluation.common.util import ColumnName -from src.python.review.common.file_system import Extension, get_parent_folder, get_restricted_extension - - -''' -This scripts allows unpacking solutions to the solutions dataframe. -The initial dataframe has only several obligatory columns user_id,times,codes, -where is an array with times separated by ; symbol and - is an array with code fragments separated by ₣ symbol. -The and arrays have to has the same length. -The resulting dataset will have several: columns user_id,time,code, -where each row contains obly one time and one code fragment -''' - - -def configure_arguments(parser: argparse.ArgumentParser) -> None: - parser.add_argument(RunToolArgument.SOLUTIONS_FILE_PATH.value.long_name, - type=lambda value: Path(value).absolute(), - help='Path to the compressed solutions') - - -def __parse_time_and_solutions(times_str: str, solutions_str: str) -> pd.DataFrame: - times = times_str.split(',') - solutions = solutions_str.split('₣') - time_to_solution = dict(zip(times, solutions)) - user_df = pd.DataFrame(time_to_solution.items(), columns=[ColumnName.TIME.value, ColumnName.CODE.value]) - user_df[ColumnName.USER.value] = uuid.uuid4() - return user_df - - -def __add_user_df(user_df_list: List[pd.DataFrame], user_df: pd.DataFrame): - user_df_list.append(user_df) - - -def main() -> int: - parser = argparse.ArgumentParser() - configure_arguments(parser) - - try: - args = parser.parse_args() - solutions_file_path = args.solutions_file_path - extension = get_restricted_extension(solutions_file_path, [Extension.CSV]) - solutions_df = get_solutions_df(extension, solutions_file_path) - user_df_list = [] - solutions_df.apply(lambda row: __add_user_df(user_df_list, - __parse_time_and_solutions(row['times'], row['codes'])), axis=1) - unpacked_solutions = pd.concat(user_df_list) - output_path = get_parent_folder(Path(solutions_file_path)) / f'unpacked_solutions{Extension.CSV.value}' - write_dataframe_to_csv(output_path, unpacked_solutions) - return 0 - - except FileNotFoundError: - logger.error('CSV-file with the specified name does not exists.') - return 2 - - except Exception: - logger.exception('An unexpected error.') - return 2 - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/src/python/evaluation/paper_evaluation/user_dynamics/user_statistics.py b/src/python/evaluation/paper_evaluation/user_dynamics/user_statistics.py deleted file mode 100644 index 7b1d4091..00000000 --- a/src/python/evaluation/paper_evaluation/user_dynamics/user_statistics.py +++ /dev/null @@ -1,23 +0,0 @@ -from dataclasses import dataclass -from enum import Enum, unique -from typing import Dict, List - -from src.python.evaluation.inspectors.common.statistics import PenaltyIssue - - -@unique -class DynamicsColumn(Enum): - ALL_ISSUES_COUNT = 'all_issues_count' - FORMATTING_ISSUES_COUNT = 'formatting_issues_count' - OTHER_ISSUES_COUNT = 'other_issues_count' - - ISSUE_COUNT = 'issue_count' - - -@dataclass -class UserStatistics: - traceback: List[List[PenaltyIssue]] - top_issues: Dict[str, int] - - def get_traceback_dynamics(self) -> List[int]: - return list(map(lambda i_l: len(i_l), self.traceback)) diff --git a/src/python/evaluation/plots/README.md b/src/python/evaluation/plots/README.md deleted file mode 100644 index be7e8797..00000000 --- a/src/python/evaluation/plots/README.md +++ /dev/null @@ -1,160 +0,0 @@ -# Hyperstyle evaluation: plots -This module allows you to visualize the data. - -## Diffs plotter -This script allows you to visualize a dataset obtained with [diffs_between_df.py](../inspectors/diffs_between_df.py). - -The script can build the following charts: -* number of unique issues by category ([Example](#number-of-unique-issues-by-category)) -* number of issues by category ([Example](#number-of-issues-by-category)) -* number of unique penalty issues by category ([Example](#number-of-unique-penalty-issues-by-category)) -* number of penalty issues by category ([Example](#number-of-penalty-issues-by-category)) -* median penalty influence by category ([Example](#median-influence-on-penalty-by-category)) -* distribution of penalty influence by category ([Example](#distribution-of-influence-on-penalty-by-category)) - -### Usage -Run the [diffs_plotter.py](diffs_plotter.py) with the arguments from command line. - -**Required arguments**: -1. `diffs_file_path` — path to a file with serialized diffs that were founded by [diffs_between_df.py](../inspectors/diffs_between_df.py). -2. `save_dir` — directory where the plotted charts will be saved. -3. `config_path` — path to the yaml file containing information about the charts to be plotted. A description of the config and its example is provided in [this section](#config). - - -**Optional arguments**: - -Argument | Description ---- | --- -**‑‑file‑extension** | Allows you to select the extension of output files. Available extensions: `.png`, `.jpg`, `.jpeg`, `.webp`, `.svg`, `.pdf`, `.eps`, `.json`. Default is `.svg`. - -### Config -The configuration file is a dictionary in yaml format, where each chart you want to build has its parameters. - -**Possible values of the charts**: -* `unique_issues_by_category` to plot the number of unique issues by category -* `issues_by_category` to plot the number of issues by category -* `unique_penalty_issues_by_category` to plot the number of unique penalty issues by category -* `penalty_issues_by_category` to plot the number of penalty issues by category -* `median_penalty_influence_by_category` to plot the median penalty influence by category -* `penalty_influence_distribution` to plot the distribution of penalty influence by category - -**Possible parameters**: -Parametr | Description ----|--- -**x_axis_name** | Name of the x-axis. The default value depends on the type of chart. -**y_axis_name** | Name of the y-axis. The default value depends on the type of chart. -**limit** | A value that allows you to filter the data before displaying them.

    For charts `unique_issues_by_category`, `issues_by_category`, `unique_penalty_issues_by_category` and `penalty_issues_by_category` only those categories will be shown where the number of issues is greater than or equal to the limit.

    For chart `penalty_issues_by_category` only those categories will be shown where the number of median value is greater than or equal to the limit.

    For chart `penalty_influence_distribution` only those categories will be shown where the number of values is greater than or equal to the limit.

    The default value depends on the type of chart. -**margin** | Defines the outer margin on all four sides of the chart. The available values are specified in the Enum class `MARGIN` from [plots const file](./common/plotly_consts.py). If not specified, the default value provided by Plotly is used. -**sort_order** | Defines the sorting order of the chart. The available values are specified in the Enum class `SORT_ORDER` from [plots const file](./common/plotly_consts.py). If not specified, the default value provided by Plotly is used. -**color** | Defines the color of the chart. The available values are specified in the Enum class `COLOR` from [plots const file](./common/plotly_consts.py). If not specified, the default value provided by Plotly is used. - -#### Example of config -```yaml -unique_issues_by_category: - margin: "ZERO" - limit: 10 - sort_order: "total descending" - color: "RED" -unique_penalty_issues_by_category: - limit: 30 - sort_order: "category ascending" -median_penalty_influence_by_category: -penalty_influence_distribution: -``` - -The result will be four graphs (`unique_issues_by_category`, `unique_penalty_issues_by_category`, `median_penalty_influence_by_category`, `penalty_influence_distribution`) with the corresponding parameters. - -### Examples - -#### Number of unique issues by category - - -#### Number of issues by category - - -#### Number of unique penalty issues by category - - -#### Number of penalty issues by category - - -#### Median influence on penalty by category - - -#### Distribution of influence on penalty by category - - -## Raw issues statistics plotter -This script allows you to visualize a dataset obtained with [get_raw_issues_statistics.py](../issues_statistics/get_raw_issues_statistics.py). - -The script can build the following charts: -* Line chart ([Example](#line-chart)) -* Box plot ([Example](#box-plot)) -* Histogram ([Example](#histogram)) - -### Usage -Run the [raw_issues_statistics_plotter.py](raw_issues_statistics_plotter.py) with the arguments from command line. - -**Required arguments**: -1. `config_path` — path to the yaml file containing information about the charts to be plotted. A description of the config and its example is provided in [this section](#config-1). -2. `save_dir` — directory where the plotted charts will be saved. - -**Optional arguments**: - -Argument | Description ---- | --- -**‑‑file‑extension** | Allows you to select the extension of output files. Available extensions: `.png`, `.jpg`, `.jpeg`, `.webp`, `.svg`, `.pdf`, `.eps`, `.json`. Default is `.svg`. -**‑‑group‑stats** | If present, there will be several languages on the charts at once. - -### Config -The configuration file is a dictionary in yaml format, where -1) paths to datasets with statistics are specified -2) for each column of the original dataset, the types of graphs to be plotted are specified. You can also put the general parameters when plotting multiple graphs for one column in a separate `common` group. - -**Possible values of the charts**: -* `line_chart` -* `histogram` -* `box_plot` - -**Possible parameters**: -Parametr | Description ----|--- -**x_axis_name** | Name of the x-axis. The default value depends on the type of chart. -**y_axis_name** | Name of the y-axis. The default value depends on the type of chart. -**boundaries** | Dictionary consisting of pairs `boundary value`: `boundary name` (boundary name may not exist). Allows to draw vertical or horizontal lines on graphs (depending on the type of plot). By default, the boundaries are not drawn. -**range_of_values** | Allows you to filter the values. It is an array of two values: a and b. Only values that belong to the range [a, b) are taken into account when plotting. By default, all values are taken into account when plotting. -**margin** | Defines the outer margin on all four sides of the chart. The available values are specified in the Enum class `MARGIN` from [plots const file](./common/plotly_consts.py). If not specified, the default value provided by Plotly is used. -**sort_order** | Defines the sorting order of the chart. The available values are specified in the Enum class `SORT_ORDER` from [plots const file](./common/plotly_consts.py). If not specified, the default value provided by Plotly is used. -**color** | Defines the color of the chart. The available values are specified in the Enum class `COLOR` from [plots const file](./common/plotly_consts.py). If not specified, the default value provided by Plotly is used. -**n_bins** | Allows you to adjust the number of bins when plotting a box plot. By default, this value is set by Plotly. - -#### Example of config -```yaml -CYCLOMATIC_COMPLEXITY: - line_chart: - x_axis_name: Cyclomatic complexity value - histigram: - common: - range_of_values: [0, 20] -``` - -The result will be two graphs: line chart and histogram. The values in both charts will be between 0 and 19 inclusive. In the line chart the x-axis will be named "Cyclomatic complexity value". - -### Examples - -#### Line chart -

    - - -

    - -#### Box plot -

    - - -

    - -#### Histogram -

    - -

    diff --git a/src/python/evaluation/plots/__init__.py b/src/python/evaluation/plots/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/python/evaluation/plots/common/__init__.py b/src/python/evaluation/plots/common/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/python/evaluation/plots/common/plotly_consts.py b/src/python/evaluation/plots/common/plotly_consts.py deleted file mode 100644 index 5f0e6d85..00000000 --- a/src/python/evaluation/plots/common/plotly_consts.py +++ /dev/null @@ -1,57 +0,0 @@ -from enum import Enum - -import plotly.express as px - - -class MARGIN(Enum): - ZERO = {'l': 0, 'r': 0, 'b': 0, 't': 0} - - -class SORT_ORDER(Enum): # noqa: N801 - CATEGORY_ASCENDING = 'category ascending' - CATEGORY_DESCENDING = 'category descending' - TOTAL_ASCENDING = 'total ascending' - TOTAL_DESCENDING = 'total descending' - - -class COLOR(Enum): - """ - Colors from px.colors.DEFAULT_PLOTLY_COLORS - """ - - BLUE = "rgb(31, 119, 180)" - ORANGE = "rgb(255, 127, 14)" - GREEN = "rgb(44, 160, 44)" - RED = "rgb(214, 39, 40)" - PURPLE = "rgb(148, 103, 189)" - BROWN = "rgb(140, 86, 75)" - PINK = "rgb(227, 119, 194)" - GRAY = "rgb(127, 127, 127)" - YELLOW = "rgb(188, 189, 34)" - CYAN = "rgb(23, 190, 207)" - - -class COLORWAY(Enum): # noqa: N801 - """ - Colors from px.colors.qualitative - """ - - PLOTLY = px.colors.qualitative.Plotly - D3 = px.colors.qualitative.D3 - G10 = px.colors.qualitative.G10 - T10 = px.colors.qualitative.T10 - ALPHABET = px.colors.qualitative.Alphabet - DARK24 = px.colors.qualitative.Dark24 - LIGHT24 = px.colors.qualitative.Light24 - SET1 = px.colors.qualitative.Set1 - PASTEL1 = px.colors.qualitative.Pastel1 - DARK2 = px.colors.qualitative.Dark2 - SET2 = px.colors.qualitative.Set2 - PASTEL2 = px.colors.qualitative.Pastel2 - SET3 = px.colors.qualitative.Set3 - ANTIQUE = px.colors.qualitative.Antique - BOLD = px.colors.qualitative.Bold - PASTEL = px.colors.qualitative.Pastel - PRISM = px.colors.qualitative.Prism - SAFE = px.colors.qualitative.Safe - VIVID = px.colors.qualitative.Vivid diff --git a/src/python/evaluation/plots/common/utils.py b/src/python/evaluation/plots/common/utils.py deleted file mode 100644 index 4ee1fb5c..00000000 --- a/src/python/evaluation/plots/common/utils.py +++ /dev/null @@ -1,188 +0,0 @@ -import os -from pathlib import Path -from typing import Dict, List, Optional - -import pandas as pd -import plotly.express as px -import plotly.graph_objects as go -from src.python.evaluation.plots.common import plotly_consts -from src.python.review.common.file_system import Extension - -COLOR = Optional[plotly_consts.COLOR] -COLORWAY = Optional[plotly_consts.COLORWAY] -MARGIN = Optional[plotly_consts.MARGIN] -SORT_ORDER = Optional[plotly_consts.SORT_ORDER] -LINES = Optional[Dict[int, Optional[str]]] - - -def get_supported_extensions() -> List[str]: - extensions = Extension.get_image_extensions() - extensions.append(Extension.JSON) - extensions.append(Extension.HTML) - return [extension.value for extension in extensions] - - -def create_bar_plot( - df: pd.DataFrame, - *, - x_axis: str, - y_axis: str, - margin: MARGIN = None, - sort_order: SORT_ORDER = None, - color: COLOR = None, -) -> go.Figure: - fig = px.bar(df, x=x_axis, y=y_axis, text=y_axis) - update_figure(fig, margin=margin, sort_order=sort_order, color=color) - return fig - - -def create_box_trace( - df: pd.DataFrame, - *, - x_column: Optional[str] = None, - y_column: Optional[str] = None, - color: COLOR = None, -) -> go.Box: - return go.Box( - x=df[x_column] if x_column is not None else None, - y=df[y_column] if y_column is not None else None, - line={'color': color.value if color is not None else None}, - ) - - -def create_box_plot( - df: pd.DataFrame, - *, - x_axis: Optional[str], - y_axis: Optional[str], - margin: MARGIN = None, - sort_order: SORT_ORDER = None, - color: COLOR = None, - horizontal_lines: LINES = None, -) -> go.Figure: - fig = go.Figure(create_box_trace(df, x_column=x_axis, y_column=y_axis, color=color)) - update_figure( - fig, - margin=margin, - sort_order=sort_order, - horizontal_lines=horizontal_lines, - x_axis_name=x_axis, - y_axis_name=y_axis, - ) - return fig - - -def create_scatter_trace( - df: pd.DataFrame, - *, - x_column: str, - y_column: str, - color: COLOR = None, -) -> go.Scatter: - return go.Scatter( - x=df[x_column], - y=df[y_column], - line={'color': color.value if color is not None else None}, - ) - - -def create_line_chart( - df: pd.DataFrame, - *, - x_axis: str, - y_axis: str, - margin: MARGIN = None, - color: COLOR = None, - vertical_lines: LINES = None, -) -> go.Figure: - fig = go.Figure(create_scatter_trace(df, x_column=x_axis, y_column=y_axis, color=color)) - update_figure( - fig, - margin=margin, - vertical_lines=vertical_lines, - x_axis_name=x_axis, - y_axis_name=y_axis, - ) - return fig - - -def create_histogram( - df: pd.DataFrame, - x_axis: str, - y_axis: str, - n_bins: Optional[int] = None, - margin: MARGIN = None, - color: COLOR = None, - vertical_lines: LINES = None, -) -> go.Figure: - fig = px.histogram(df, x=x_axis, y=y_axis, nbins=n_bins) - update_figure( - fig, - margin=margin, - color=color, - vertical_lines=vertical_lines, - x_axis_name=x_axis, - y_axis_name=y_axis, - ) - return fig - - -def update_figure( - fig: go.Figure, - *, - margin: MARGIN = None, - sort_order: SORT_ORDER = None, - color: COLOR = None, - colorway: COLORWAY = None, - horizontal_lines: LINES = None, - vertical_lines: LINES = None, - x_axis_name: Optional[str] = None, - y_axis_name: Optional[str] = None, -) -> None: - new_layout = {} - - if margin is not None: - new_layout["margin"] = margin.value - - if sort_order is not None: - new_layout["xaxis"] = {"categoryorder": sort_order.value} - - if x_axis_name is not None: - new_layout['xaxis_title'] = x_axis_name - - if y_axis_name is not None: - new_layout['yaxis_title'] = y_axis_name - - if colorway is not None: - new_layout['colorway'] = colorway.value - - fig.update_layout(**new_layout) - - new_trace = {} - - if color is not None: - new_trace["marker"] = {"color": color.value} - - fig.update_traces(**new_trace) - - if horizontal_lines is not None: - for y, annotation in horizontal_lines.items(): - fig.add_hline(y=y, annotation_text=annotation) - - if vertical_lines is not None: - for x, annotation in vertical_lines.items(): - fig.add_vline(x=x, annotation_text=annotation, annotation_textangle=90) - - -def save_plot( - fig: go.Figure, - dir_path: Path, - plot_name: str = "result_plot", - extension: Extension = Extension.SVG, -) -> None: - os.makedirs(dir_path, exist_ok=True) - file = dir_path / f"{plot_name}{extension.value}" - if extension == Extension.HTML: - fig.write_html(str(file)) - else: - fig.write_image(str(file)) diff --git a/src/python/evaluation/plots/diffs_plotter.py b/src/python/evaluation/plots/diffs_plotter.py deleted file mode 100644 index 5ecce6f7..00000000 --- a/src/python/evaluation/plots/diffs_plotter.py +++ /dev/null @@ -1,172 +0,0 @@ -import argparse -import sys -from enum import Enum, unique -from pathlib import Path -from typing import Any, Callable, Dict, Union - -sys.path.append('../../../..') - -import plotly.graph_objects as go -from src.python.common.tool_arguments import RunToolArgument -from src.python.evaluation.inspectors.common.statistics import ( - GeneralInspectorsStatistics, - IssuesStatistics, - PenaltyInfluenceStatistics, -) -from src.python.evaluation.inspectors.print_inspectors_statistics import gather_statistics -from src.python.evaluation.plots.common import plotly_consts -from src.python.evaluation.plots.common.utils import get_supported_extensions, save_plot -from src.python.evaluation.plots.plotters.diffs_plotters import ( - get_issues_by_category, - get_median_penalty_influence_by_category, - get_penalty_influence_distribution, - get_unique_issues_by_category, -) -from src.python.review.common.file_system import deserialize_data_from_file, Extension, parse_yaml - - -@unique -class ConfigFields(Enum): - X_AXIS_NAME = 'x_axis_name' - Y_AXIS_NAME = 'y_axis_name' - LIMIT = 'limit' - MARGIN = 'margin' - SORT_ORDER = 'sort_order' - COLOR = 'color' - - -X_AXIS_NAME = ConfigFields.X_AXIS_NAME.value -Y_AXIS_NAME = ConfigFields.Y_AXIS_NAME.value -LIMIT = ConfigFields.LIMIT.value -MARGIN = ConfigFields.MARGIN.value -SORT_ORDER = ConfigFields.SORT_ORDER.value -COLOR = ConfigFields.COLOR.value - - -@unique -class PlotTypes(Enum): - UNIQUE_ISSUES_BY_CATEGORY = 'unique_issues_by_category' - ISSUES_BY_CATEGORY = 'issues_by_category' - UNIQUE_PENALTY_ISSUES_BY_CATEGORY = 'unique_penalty_issues_by_category' - PENALTY_ISSUES_BY_CATEGORY = 'penalty_issues_by_category' - MEDIAN_PENALTY_INFLUENCE_BY_CATEGORY = 'median_penalty_influence_by_category' - PENALTY_INFLUENCE_DISTRIBUTION = 'penalty_influence_distribution' - - def to_plotter_function(self) -> Callable[..., go.Figure]: - type_to_function = { - PlotTypes.UNIQUE_ISSUES_BY_CATEGORY: get_unique_issues_by_category, - PlotTypes.ISSUES_BY_CATEGORY: get_issues_by_category, - PlotTypes.UNIQUE_PENALTY_ISSUES_BY_CATEGORY: get_unique_issues_by_category, - PlotTypes.PENALTY_ISSUES_BY_CATEGORY: get_issues_by_category, - PlotTypes.MEDIAN_PENALTY_INFLUENCE_BY_CATEGORY: get_median_penalty_influence_by_category, - PlotTypes.PENALTY_INFLUENCE_DISTRIBUTION: get_penalty_influence_distribution, - } - - return type_to_function[self] - - def extract_statistics( - self, - statistics: GeneralInspectorsStatistics, - ) -> Union[IssuesStatistics, PenaltyInfluenceStatistics]: - type_to_statistics = { - PlotTypes.UNIQUE_ISSUES_BY_CATEGORY: statistics.new_issues_stat, - PlotTypes.ISSUES_BY_CATEGORY: statistics.new_issues_stat, - PlotTypes.UNIQUE_PENALTY_ISSUES_BY_CATEGORY: statistics.penalty_issues_stat, - PlotTypes.PENALTY_ISSUES_BY_CATEGORY: statistics.penalty_issues_stat, - PlotTypes.MEDIAN_PENALTY_INFLUENCE_BY_CATEGORY: statistics.penalty_influence_stat, - PlotTypes.PENALTY_INFLUENCE_DISTRIBUTION: statistics.penalty_influence_stat, - } - - return type_to_statistics[self] - - -def configure_arguments(parser: argparse.ArgumentParser) -> None: - parser.add_argument( - RunToolArgument.DIFFS_FILE_PATH.value.long_name, - type=lambda value: Path(value).absolute(), - help=RunToolArgument.DIFFS_FILE_PATH.value.description, - ) - - parser.add_argument( - 'save_dir', - type=lambda value: Path(value).absolute(), - help='The directory where the plotted charts will be saved', - ) - - parser.add_argument( - 'config_path', - type=lambda value: Path(value).absolute(), - help='Path to the yaml file containing information about the graphs to be plotted.', - ) - - parser.add_argument( - '--file-extension', - type=str, - default=Extension.SVG.value, - choices=get_supported_extensions(), - help='Allows you to select the extension of output files', - ) - - -def get_plot_params(config: Dict, plot_type: PlotTypes) -> Dict[str, Any]: - config_params = config.get(plot_type.value) - params = {} - - if config_params is None: - return params - - if config_params.get(MARGIN) is not None: - margin_value = config_params.get(MARGIN).upper() - params[MARGIN] = plotly_consts.MARGIN[margin_value] - - if config_params.get(SORT_ORDER) is not None: - sort_order_value = config_params.get(SORT_ORDER) - params[SORT_ORDER] = plotly_consts.SORT_ORDER(sort_order_value) - - if config_params.get(LIMIT) is not None: - params[LIMIT] = config_params.get(LIMIT) - - if config_params.get(X_AXIS_NAME) is not None: - params[X_AXIS_NAME] = config_params.get(X_AXIS_NAME) - - if config_params.get(Y_AXIS_NAME) is not None: - params[Y_AXIS_NAME] = config_params.get(Y_AXIS_NAME) - - if config_params.get(COLOR) is not None: - color_value = config_params.get(COLOR) - params[COLOR] = plotly_consts.COLOR[color_value] - - return params - - -def plot_and_save( - config: Dict, - general_statistics: GeneralInspectorsStatistics, - save_dir: Path, - extension: Extension, -) -> None: - for plot_type in PlotTypes: - if plot_type.value in config: - params = get_plot_params(config, plot_type) - plotter_function = plot_type.to_plotter_function() - statistics = plot_type.extract_statistics(general_statistics) - plot = plotter_function(statistics, **params) - save_plot(plot, save_dir, plot_name=plot_type.value, extension=extension) - - -def main() -> None: - parser = argparse.ArgumentParser() - configure_arguments(parser) - args = parser.parse_args() - - diffs = deserialize_data_from_file(args.diffs_file_path) - general_statistics = gather_statistics(diffs) - - extension = Extension(args.file_extension) - config = parse_yaml(args.config_path) - - plot_and_save(config, general_statistics, args.save_dir, extension) - - -if __name__ == '__main__': - main() diff --git a/src/python/evaluation/plots/examples/BEST_PRACTICES_box_plot.png b/src/python/evaluation/plots/examples/BEST_PRACTICES_box_plot.png deleted file mode 100644 index 94b59e74b997eaff86a58d744f535b1f27b43612..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19449 zcmeHvc{r49-#=1Fwl+nU657yW7o&tCl(h(z>>+B*SjSQ+g(8G3WjB~)XNDvc*_SCY zGqQxijAaalncq33?)!b7=l&hXd;H$_J)ZY>-1CP&%z2&Xb)DCFe!rjZ=kqz|;RQoo zp3Op=Sy)(j&YeAD%)-KkW?^An;M@fMgTGA2v#^M>oI7*M6mBy;$n_#}l-@K;`m`(a zf^+OMV^iafpYHMR z8~A$${+@xqXW;J{__v&a2*<1SW9p5&cSZh+**9cwjeT4eKhDXI-gMIAK%Fc54dwNG zq70IY^u;VeezYPa1UuezYdtC4;^s%Yr++FGhr0!`qdKF8*7FMiB$q)Qc2w(u?#`24 z{MuKtbk@_5Z4jYUgnfqGzgki6x?uNffC?}`xd06Art@_u;+2?*#Lq+%WEDh!3JahW zB|?N%n2-fWkx&JXI?!d}1h4q{K*+-r0iGA?&@ur@Cyp;!pf7$W$Kzv59 zoukw2fY@Qi>~c?TLvo%qMHOLQ6Zh#s%kKx>%#SvFbzY9(`f(pQY3aRx0JYnfhd9{G zs9n=lf5|vMiL{IQs87}*G)b-xe0AH8S@B>GR2uBnj*6Ood0o3*dBkOgti$pFG)mJ5 z&HOxa()ck$E;HjSZ8%zfl?QxxAH1cj3w1TIEgqBUJmxc> zXE(2!=O1txvA@n$E$Fe1_z|{%ZNuA#v)xxx-v^$%w)bi>r}$NVaX1e=n$so>zk;Xt z6!26dwTe|;I$z&64_FJego+i!J8tQA&VG?2;{J(ZesI=f{BA-&=DQfrc;6Y@!1)+U%C7W{ zMm*gI?-`22CAN<21HcDTQU)&K%Ti@4Slu&Zp|#&z;>S9B_GJfH$Wa7^ zm1BF>n}20vM-4n6lryy;C7Kh-xxQ$+WORSfJVxa!z`B_SZtR+cD@f z-0|pah@zW$FxxV;H8!(1|C&tlh1WrlvfHVhD-P2};SVD&-n^OLCS!T29GjD$bm+=7 zLxV!OZfD2)0iVArdwnW4n;}8-54ql&w)>ofxt|s zup)^|i3O?qV-tyoZA7zRFrI?R@YAg7^a}`)7$psv^Hz6+atxBnCmRxmR|&~WpKk`N zEMq4>ueiq^35-wnKY};o9@#x6t#H#w!B-}=#68&WyS7^zt#d>F~qdZLK1v_f`3CK|MG9nAH?*5tJH8<5+VNP*SNI1(!IDgv>ex(%D zu4C7#nr#CTw(1&C#GK(YjFEyLeV>6amdanhyI9a^a3x}Lpw#|;9g(L3d6`fBNyqtk z8~;;rq1ftrHTaa>p@7+qF1|1s1_eR44{cOm5sMJ(GC
    wjn&UR!St`Q6bw5$wErO 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 F{2v4#!+8Jz diff --git a/src/python/evaluation/plots/examples/BEST_PRACTICES_box_plot_grouped.png b/src/python/evaluation/plots/examples/BEST_PRACTICES_box_plot_grouped.png deleted file mode 100644 index 7965aa25c1e72f2c953416db54eef7c0dada9b07..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21325 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 diff --git a/src/python/evaluation/plots/examples/CODE_STYLE_ratio_histogram.png b/src/python/evaluation/plots/examples/CODE_STYLE_ratio_histogram.png deleted file mode 100644 index e3dde849fe3e6c0e5474efece305031927f83c00..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24012 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 diff --git a/src/python/evaluation/plots/examples/CYCLOMATIC_COMPLEXITY_line_chart.png b/src/python/evaluation/plots/examples/CYCLOMATIC_COMPLEXITY_line_chart.png deleted file mode 100644 index 17673eb6a06e330a94c1d032d90a573af5b8350b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 35501 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 diff --git a/src/python/evaluation/plots/examples/CYCLOMATIC_COMPLEXITY_line_chart_grouped.png b/src/python/evaluation/plots/examples/CYCLOMATIC_COMPLEXITY_line_chart_grouped.png deleted file mode 100644 index 044e92c8456bacfe639fe49226c81371a693a79a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43037 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 diff --git a/src/python/evaluation/plots/examples/issues_by_category.png b/src/python/evaluation/plots/examples/issues_by_category.png deleted file mode 100644 index 3e55aa124bfd56f920d9be50d38fcfb919791952..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27515 zcmeEuXH=72*QU}06i^Wr5Cjns5D^4}bVWhB^d>>2gAkAwy0L(TqS8A`uTgqQ07XIR zHKB$GN(&H_5+DTT1bm)(=lh=LeZQGCYt5{g_YZfLCii`xbN1Q$+Sk7Jd3IArjfI(u zdC#6bEb2F|>F?P?gW9ua?=m9;_?I!Wt+73O`1Yt@yJ853&W-MaA2Awk`swcz)phO2 zd+WU%G1=qJD#~-YPx+qaMn64;7P&6VaOGO!Q+<^~*Pb8QZ+vgyUHa{b(g$z(X!J85 zmyHq=ubh(Lw}DvLb#9Vs>InXV7wtQi{8<~@?@0cnqd`0vUo4$LmdPYb8>sHtOLtJ2 z`sZoIgU|+Um;1$`duSN>9#H=r)ZR-2lPa%1`o}*!Q0}8=MCl1lJ^cL*@U`wEe2c0E zNzVK`KcW7)X8E9j+w1=Mr~kgu?-}?n&XL+aT>luQusdqfd9o^WDgNGuXpw^sZ{!ii zBQ6IzE~zvKJj=SRDxOEPvu20@y0=H+V`O-FlNL06IqX1;Vt(d^kIS3cn9h=%vbBB= zuC$sPoSbGg#jBsWy3knxipW!(@OlcafTZ;9HS0;p{%A4L(SS!*S(;JsQ50(~5B0tc z_Yk>sxVFN3mZMckss1(fI!Y_o0!wD)Shyh;;vFZlt%8ONF$$^Lb^5B0930K65nxVsd)POddXI*9C`)G7&Jb%HPc`tPwXk|uSDXb* z{J1r7#C5FNLVM^y*|z`Ci0u&CKCPzQ@vdkw#qkk?d}=;@)V?WZ6uGA-X2hjxsN5ml z*{T1g-bqKk#U|ogmZ>%-)VDsHbGtU2EPODg!8vAY?Q!+c@|0CgZMRpVU`p(Pq!4bLixE1cLo5RqIIUZb;u8fZEf!Xwu=4fMN^t06n7j%JmdqQAL z&DV{|lo|6SifnjFiSkrhV8|xo!G>pz+*Ewwz2L?EEsqc-KJ?O^ilgV4eHnG6t~D^D zc!uGggfyEin2X?K@bo<@%e6+FLY(Jsf*AEi<|oy`2B{ChcD^u}g^-<_6&EIg#b z{1g*C?O7{ZUDr;WRKH{2^#WY{UE*Q|@uImR(!@s^Wz6%Md-BLTTYJAR^JR4kGfUzM z=BURo^ZlINFWHM4{9!L1w47*%6mjv&r_ zRONvh*T*+sj_-O484ErUIn>zJnE0%;=iAhz3(B?;=d)P2D|3yocl_L&E>OVYn|pC) zo9V7nro>p-y>veRavJ+pacius;_eTw@c0WR`*RNH{k*GA2US;prr&C(Xe8e&id5T} z<*uI;>!`32zlXM4>rhp+^nPz*HrOMIv?q+RvB@*sAODH*Ws?kcW7pcDFN->jpKLiiV-IpZ2v6yvpWO9u z$~N?G55tQNPoDGB>=ZY1tskp5)qhJd4jGCwsw}Xm2*^^^PR=P?_9SEV{VI(0_3x%) zUz^pUnV1w;2tyAWL}w-mXxZXIwa$*#*iIoY=eTr|VjE`4ir$cLAIamLmYke*S6x5N z^;x2%sAm1v(VL`IChrEz^(R)waGpL}-S zHjY?VN7L(KcFYoJ-k{7emf|(A&8`1AL*>+5NFWtxU z%6Jwz$7KfjEtx#$+H2@dzY2{bap&t68zNj)n-F+er>ogpL+-Z~jXFuwL$ZqDNzqv^ z^8F3B8PcF|VT)r%OGA;;ZGrs5ip7p9X=vxoRq|lXx?h^2={oVeYeI(YzL`V1c7u@$ zn^h4F+-O%1!QbJH(Fg>k{A87mQg7dFpEo9IJc8{3TVwW4Y4Gn2*37k}6Y&mNrSeYj z7rK#33AUjVtR%tdcu8JC!LPVcipvCI6vwXnvZhiqdQ6;BE|9K%v82qNh>(!2RPW*@ z+7Y&c4h%%f9)$ChFvc_dj+aNyD&xZ^=?m zCT;n}bHyvw>G^72Ncne-!?n&2aTI*RMU;K&g5L0Vy6}|vyg+hhXszIEo}<~&vYN8A z_)0!b8p^_%V5`IyFzLvvKQ@a>IPdHI-HE_S_b8?^hSafrJSOCD5i5| zdUi-rJ3i5t*i=W-tH1>K-=11+a%PopB+pt5&JHW+p+h&xw-)AC0yq49l!J+ii_-AGs)H^t6@6B$c_}mC?+iU60FG5jPRb0u(UBe=tr5Sg?YS#LNHYb-On$4 z=h9K*6T$V~+Ac`6=Dk44i?rs;_bckw6^Xk10*g&QKi-+$^;=b14;lz1AqK9ldx2NG zzKe}+*X==IH+c>2?4_ZD#_ro4`{e$E@OGjE$6>e`?eE{3gWt}s8pz9`3V*+G84W<&^YN`kMf`ZpsHe5rO%~}tz5faxFKLK4RT!}`>OZ9Z}soF`d>GO6FhK}U{a~7 zZXz;ag14hLQ#&||BhS6S*uUH+ukwbq+x^Y`?;5$c6*6gd9c9F6fT85bPax9XEe~&b z45p>#aaxn7gO4Q_d`1>`t@T}R`SPX5t6UuOU_tE1lJ9lAfEh|d zrojEezk`(k^QY5`I)Muu6tq9mugoRi(Id{0lo~jT$$q9VSgz#K^`P0H{Pr*WErgGi zdCluu7L(eeES}m$T;s1o1Xg2dnfaCRVswW?e`hjNG%E)0t8H8)j-1A@6NN^wyU}`sd zPK=3oMXj{U^_EYPy;e)>{}C4+C)BG@)@XZvv6YnJpWIZ#%Nx)YHVm)tMe3YuhFnPO zF__(T3;25KINFC;x*yFi^a&nIwePg;V(&GYM?H7a-xeX)ljgJyQdBL=X2XS7Sz%HM{D6!(}eZNtmu3SK(cMK$Xx4a_jUnsL`bOK^ZYvG~Nu z_Z)Q9^NCQyd)bfWaZy*V!4mj!pOqx1Z4gjw)&K3}{~db%9j3vy2-y1{SP9R&y;hFb zXFKxyp<-sUVm-%`PizCcxklvY*xfX4r>P!gP#l$4tr;t-AYiakTxZBuUfY{GHg00# z5HNen*2ZS0X6Tr+GAZ`gI_lISZ(d*kIv3pJE%SZF-HqBo-SR0C+tPs>KS+LMofO#$ zt(g-Ef6qNIqB^XU+?7;lU?Y_;X?7_snYYS@G%)W9D+q4XV80Msw}fp(i*(*Ugc1tD zId~|2Z)A?shwmS%X^3@Yo`OEy#ol6E(~0KNp9EOc=EU|Lx%!~Ng7Gx#m0cR3gPQ&Y zo04ib6fPOX^~+d^8W-!$=nM8|%=6^y6}@JN&??^!rUn%af_rFUrFY*kq;3Zjs<(Mr zZ)$78^Ydq;KGe?@;5czIR=%tWiU=%!_-(FTym;*usRtD95n5wT7n zhP^bSd2JlTF9scF@;#s<=ESW9w4&aAO?QNe*DbO_TgCwqbZ`YF_4!h_ym(kvAM>cX9eD$DK^y# zpQy2($}~~)e@mjC`6d5r5%49Q$b2j8r1|;}(ol^{j-R)KUGO}ioFMIBlYdlO^F1x` zrQSs;FGF$Zz}qjIvOSIaJwykZf8L;d0XabfoI30Err-E^kUE~DS6*~P=6?t`nT^=+ zTKNG{%Exx8``KdLTt@3O|0Wuhrc!t$?i3%@;e0#(`86;rsEPYUIbc?0&!3&z!RrT0 zl>2Cq<*mcS_rfJx+e|+q`WqI+jOI6=uYQUXv&z$BpAr^Ruq+oZD2`4oiiwVnpDMS( zxWcYJ)TPu^@GXXn+}Dvee9+M9_XpOe5=(9dziy~hT_3&7i@>G?<~Z$yJ|B=jkM_gz zDUo{+ae{~)I`P3eh*V4dT2JU155moOckL!#Tp2H2-)wjTZ_DyKuseYaqF`9}=iFim z!|r~#VD+HEIVdvkB@Yzyo0%*=%C}fkLpjpPD(<`sz4k5vC^t!pXCD0a?_2#pJy+=s z4P?x7al^d3z9~Vo&niCcOA9JWShB+A3B?$YDtvOaX7nZ4hn7vuUlpUB%1tz5{a#2h z2sPL5K|r?rZ_w{r-U)SZpW$>PE0&;XXn(GEM8#IQL1o!=2J2Ur^3@y`<~3Tb?)v#x zO_2jwCe)z}ul@!)s7ZO!-5sQOOXTKlJbF6h(#G^>CJ{Y(^@;4dbeCZt;Vcv9`609k z1VSugi&Nydc!>tqHXUAb0fEi+)<3WtB-WXa9ETI6X5RvEYFKj3eH4yW(ctN|m@+(z zq|9*U`#P%?`B`hUnKGdyG9a@b>7W@y>Jq!JO?MI=s&H8iu#tYYWQy#MPZLspZfgE7 zk#!Vxiken$YiUSxSWE-=MZb*mT6pRFlp~LJwv6&30wOAB@dD~Q#)_&OyQTK|_2Ky| zie#sv)rDbXjkI_erziqqx2$Rz-{5R0C(N*u8X)kr$f$Nkl+J?AW?Ogzw-Wkp_U?N; z7P*PPhzbf;-ftCTf;_i<&7xwyufRif0J}cD1OqfPfv_pwM>x7JPXl|!#HoB35oi0G zHCU&iXTaIpiS?IMDt23j7xzxEr}mn_v`eoW2T~q|063r3don!X;9tB>06p^o6c*R5 zVxYES_@q}C^8`DFMBizb#@W{GM!$Gs6$yk?RYvUwk+}Lu9=(z_n=s}dV8H* zj;1g+5`*s<#c0^iPFX=_M@n_DRnZ+HCKXz5W)=uPt0-I0$f*Wlz<%qnRX96s6aOZ0 z6_XO*7Xm0cmO~M}ziVIu2pU@A2U#$G89bhp!Jrhc$-Ip*`Y8s>yN&+jVWqsHIf*Qf z6mlypslTR~v7L8Jw>eJE7#*skztX}HGg8KjfH>IdFd750vG91az;3(?0!*`xlec@{}$R*{AOq}p*XQtEMrXxNoMJ^SrCWds5{UFGh&ULNZr|}2#r7NZ^bX>OcF*kmLq>Rzh?wx7WrS;?Y@#T+fe)d!JHa)I_ zq+uILnfmr?P3%d+?)*JyxI=fw4!ktg|xL)y7NsFTfF%FU!gBr+Xr$ z-kta(^73Ui)H;)((si&0xJ0Fzn^&p(Jht9@;Ewb`#(~;K03u(l+*@dBAMVRBiN7ox0r~#M-g5 z7ZxLuHm;^J_x4^~#t9X8`G&WwlJD88tb{dz@%E~ENwe64TDJ_5f`tTAewryx$`^I9P74|3{?qh>T+aZ7p)J~7@+0Dtv zp;Wi;vlcB+Z$1V$uI@>2a%+rPWea`UAF9T6R}hBrVnW%iL^e-}EFwjir8bQf(DE8qjX*8}#(ktMf-YknHfrycyhk zM%2Q*Ld=e7RH=cN@YijAQ$s9HnkRi<(CxhW$T)Bwc6NBJ`I4p8)Lk!BrCwVm=;EW&)RPaW%lMB%<<`C1q9@9{sMPY1EDU}K!O@{ z9+2t4zKFw(=n(5J=m^Ew8H)>cF3W4$PxW{ zLOkNa>78}v&f6ClBbzh4xVO3}Y>LH|$HFGQO9ua;1$g#%kz|EdfH&B$cr&P;%8dOI zviN4=H=m-rLLdg`yS%WlZqmSqbE5T*omu4S*LnUsZCPtb8so(1YJmEOHHCk%sfO0> zR$7Cz>d8OK$q(t6144X0E`QGVRX4IUTsh$%_N)}z_sQO>PgsaIr~8rIEUHvDGU5DR z#1p&^9Er{dJrfyl(>}#FAG1|WumUInyNkb?<_Xl!m1iLI|>P{6SG9_Rdq zKeD)X=}O?L2qMmlV~m=gE}SggEsvyMprKc6ti}KEk@g!80KwnMLpPATUD!E%vaqLb z3fk?V%XYR+`qcdca;QUhyhhVO94b$KxEqJg0;?&PFZ5Yp*bE|H#yv^{>C3?O(z1c> zQ%=smn3w?ih~w~-SyjB3ll{0e6uigmvC`l5p_@gj?3r?b*o^+z`rj2vU@IU2j58T4uSD>)Ds-uI>A+Rj>WUT3b;I z6?dxss6Ff$t|lPV&O1ukPJ&Fq*7l$BTi=;bN`+)g`xN)*Kr@h0FvST~s}yoQqlOPp zGM3QWbpTh7eqo1G-Egcc9X~oZ53Ym*FuNk0(peg_e`jT8R?jvtf|U` zPZy7V8?+BCIyVxUjK9G{gA^D(>=SirvB|PE{=zP@yRsj=Lu7=%ajTMP zmdKQG*K=Lt0@wBzta8%>YO?f!AKX$v+>XnvZRTIBsoge=q+&BXDGi=lPgrRZt7!LR>V|{?xPKTfcRxEk+)3#3?(knCl@Tz<<8rodfaGBOhU{Oz$&rn6 z8;k9sJY{9sHzN{PtWF;mItUkdGg~JChDW%}vFnL+fhQu6_JQKOq_#hmwzf|z@&FjA zhSZT{qtJ1%)g{#C7779?{$DO7b9 zeSLyCIP1bmbv(<(T+L8{#hS98(cwEYBtpeEPq3poY_W>AN=urKVaZwbrIOR&4tk;0TUgH2w=z{$U?Z9J86e8mL;JTJGVA z8?+yw4Inj&Qw0%#JT@@uEIRl%KZFv(0QPs>(j+>KB9o$HVv02EQ?k!g-r`uoMje8i zb$>eu(r1-d61zdgtwQg)n~rC z%id5E>FeMA$c=Ztdj1f|fit_K6F_1U7xQP54F`faF8AO#Uej$P?gx_Hw*)m#7OBh`u9Ks6QJUeB;oAmrcuBDkA+XI-Wj_a#RM zA~_}=?-6|zfz_LTI{ft@e4@fj>%?xNaCJYpp?&>gHiZ>OA@_Rem3tVLz~A4ZW%IjG z-F1wagrLK@y{Pe!r$Ne*b^3P(uyB|f_yac9X`}&Ta`d9uU#!YHv&@DVOF=!^4D3^E zn>*W7f;=LQgNGGBe3>Jhzfqt4{u2_5+4eS0E0s!w&Z1#20*my#lcc2NkDu`9`1pgK zUYJM`*RFizhL3Yz5)$2}82qz9R7%n7m84{er{(+$>2!b1^#JH0_@l`mkNE&%xbo0l zW_JeMslJo49vAL}wGUg(n#V3Ekjw0R^DW=5+#-g8)YDx!<?r+_-lEcM;2q+UH{B#OxA|8#cFC*o*SRzJZbn@ zyzb{4tA93<_0qFtGN**exd8CyC?lU)3RKV>+O~pjZx-j+L`If}) z#1$K>@C1}HC^(hS5*uFSt!}%TB4ZU|R~WDV&jWL;^!%Hg5U*Ze`?OTiMRU1w1H1ad zI6D^cvYX9y*8RUCxV;9iPdQHy*n7~x{<}Ddvp{3iCUB|4vuHgirAfyueW_DXWlLE( zP};T}`E$>NIAFIuRQ!1}V=qjP_pEG!v|;Vu9_ zG5%#|8Q0)!td#eg_1L6Fw_~^b(-ec&9mxu)(4fMTNAzm%Or_%*xm|;3VE>u#1kZp0 zX&}3ryn|Au|8(=lt47Oxidk`w;B2reGobc6>NN!i?80hF{w}*9_)=)mb-1qe=)1Zr zEG1JkQlL#jh*XCZ##*cJuF_fAHGNRtUh7fA#prsq?(z~JJ zyAZgCxzdlq3u(WEP9m{W5$D?89J(CRzTGloi%$4 ze-p{_*X~$m+#jCOa^yxv$C*|g-!L}ykY(6JAn=t|Bl;7j|S;3mc_RV@qRIa)d-DD z%P46+QH1dsE&N26ma)c&if~dJ(E+nlS!6xFJA+5e0sJ9PY>au?5A!qM09;I102Ee? zu&yR+;>A28|AJdE9#B|Xj`9pl+0HZ7*XIof>bVzx&sCX>;*3DXh1rs5)FA^k9_H0r zGO##Ba#P_h9AZ?Z=A(SoX-9Q<3o|oO$kY2LPrZ_f1v}A*6b{l(tIoXLH4LP>ERvF0 z5xqFN;JX~G=c`b3J9|LUl%Mqq$cr>^g@nWK_F19+-yks!;4D(`3h&LKt+2+HK=MLZ zeBNQWwJNOd2@^`SJnHW64A%s_0EidFNOncf=+}bJ|BgPyezl{63i${HO{(I<)1VRt zzwtE3S+~$iQkOb?#Ev;2Exs=SO~o0TJwWXkyLUH+PEyfM6^-+Qr zMSNxP+8(X^r1kXg5L{zI(Z+_Fb{Z+aiEaMyU!t#X`%#!15Gnr~F!}9ke@U4>7GGQd zlx#SWJH2u;GU9KtQ({$~`1i}g3JNO3z!LK~Y;NJ+QH!R($^0sbi^9G-B1R=uA||p1 zEUs1hifItLLST#C++KHRkb3i($9JdaAsb5PlE9*DwcO8(5E|I#^7Dk>)tG$c8!$)4 zmAl{MBOADNv`G=y@m?@u-VUB>P@q|7z;#fXI5ci=W?1g`x^y)th^Zfy}HjqvEhhxhlDC9U1^C5)9oU? zMrKg@I`K#GYB&2k4C-B)T-piiK!j(;x$BqyD2tgs0MP!&pU^&n74?ruc!qAQ%x-Hu zO!WyJ&f%;F%dW-U6{U)pKz@`cZn->j| zyGAQ~=Pg{1Q8n)sfpNI4MNR3dH`yTM_mu7*>v|sJEam%Mr6lOFJAqd~%0EDf$7;cJ zg;!R+U)03#ey<-Lv=Z5Iwhst-X(Z!zLpWa(wXnHe^fPCLyWgeDz|R-srkzx)RZE&P zsJx^-*GT1FXnA$}AAWu0L5~Y`oY7dgbZg#Rs!O`u=_z35Q1=g1%OkKaRrP<%ROuP7 zDJ(7wlv@Z}r}kHae5*ptwI2XfYAu@!Q(&um5x5#@*nF-yG%cAOo)bBf(LrgRdH$jx z*LQ+2Kf#D9B)EZ6WaB>yy`2!)4foGJ6+EXz7cn(ui6NvwW!p&MBB(I?JkPM7iB+P& zKVyi`44-5)!^p1813}bny)PmIx&5uh|yl}(XK(=7EnqzJPp7~)wnzR2SJd;0v z*D~@NpCb(EUwipVi^f&A+Jl4n7C&_8fpA0%@+I=(1W;*NtmJ2Ro6*$w@|4~?F z4x(@nZe0Qmt38XrR>kTc+zk}IbU>t_1iXyGYM;mIQtdM)AeEmuqR>~DAYyb5rt2{H zD~3zjJ+-H&*N9v)t1&ZZ4ixpiP))n})ibBpK=QSpM*PL)b2Jf5C|+ID**h;~jxjDe zXeax;oDq2NK!vJ-5YUqY)t;MPWAQqSDDtY`az6x`HSdw8#4&X=*R&hSY=6+t>=@Vr z%2gl{{C3n9Rdv|yDxTtBDdiENYf<^GmD}Wn5KWYer$xniRD*b=>Hb4_+Z%KT-QELj z?dSF!&u0y-B5r`>#;T9rKF`Q^oBA=+RbR6UqF_|w1> zMAdw_1>`H#kLshDvFX%QG|K%d9k?F)Wa|JPQVwp`Kc54q5qEA-2cB2R>rpj8-qep# zHR@tlfE#&qrjWJ*HLV!cCQ1l~Z3?7wdX$z~PazsR6`C_@T}d;!`n;44f92jO z8^=yuaAAVL-jmYF=TB06n4vV2E&b(U9pKg z)A7al>){?e?itsTR`%AKfs1brN z?jtpuJagMfC+K*8X2Rg==faaBkjd_A3dyhY%B1pU*LeeLFQp5G3gvsG1=GUT4dk8r z+j7*@rdUcpKUdF58P~h|&~x5Mkp^Zn^d%Pm#2&! zJ3gM9A6X%;bRxfZOM}9p+5)2*6}K%=bq%%K#mLkK?kzz#EzUgqoNM7hvIfEPFAKL9 zfZAQ4$<~RiGt;7pc5=_r71p(xA!&!Qp~7J+Gp}Eu{G4VH6UD{z{q#mCF1ep$JXSQY zHFEP)>HwaB0kGFkZIGUJ$bDw$VFU0}jEBoW@2({aC2knYFulLK>tTUt?4(QpJ zw&v9+t(X$%L71fP5Y|MmWw*8+uT%|?g2TK?n_)vIBF-2v8j zgay!7R@<6K;%a@tnn`%%~v?_7?6oo zP@rtz5X8Igp@G3Sta7qV#E8pZx6=yc0`A3Pwz+QB`m@iC4lOS~fLbhI)zT&vFM!*& zxA{F%DII1vM8z)?V0+sG6g7j1TRt6hxW(m2J?i*-fe~i=#BVTzzQPjao#69ZF|7{-2z+FrqTUIqB0KLqsbKrOFxm~T-wkGqY2FP#?nnAoT7 z!~~ddZYfToYd695%B>K9`b?D)Pis`M6k zQ7;fvSMcEQ1Fq5>Y>%@rp8k2+W#6 zyNT%#wXySH+?zwn4gJ94O)AsInLrbR5LktOFUUWOD-SYgiL=BY%(VKFw8u!JZ(hS6KunD{4yBGPU#^*kIP($yUKf3M_d4r_l|b!(Y_r=pj0?3~j9BV`)`J3B)pWhad;L`x_yEF)aAalkjmKVM~Qlmoh4%RYA zo6a-P5y|=Q;FQ+}qeo7l47@&)7de?@5mJ^$3XxA0UZ1SGZA9yh{-np}x~4%Um4YN6zw)dCk} z_o@XKYoOdEIc1o1G+Abb|&`up{vt0la>sF zjgSGcv41P1JpM-`B_aL#kxl~uojgcwNpc7*Dpmgw4Wo<-Fn-A4ETE?RGimp^|Cvg; zgjVxEP?iUdf1=vI4gCdx$5ZT*%Ev*#x%0{9EXexs2dN5}54-Me%>6SvoCkaO42X6i z0IRS#p0<5_285pW@X}M%t~0dmAHCtv@mLekdw%5 ze;p*S+?*z=)Y>n|nEr@A%^bRTuUne&0Ja}L1wv2etLQ^i^d$x9c>Yt+;?*Bo000Le zlEq=qLEr`1E$#1E6d{`0K&Xnnzz@O@pn08d2nY*E0oUT-n#{oot~R$gIY6ob0x84q zSj1xjazA&mJ68cRcnXjKNCQz67?5r7&%iJ0X#q?Rj&(}2R)$H%|~ z!1N&b!!yIWz!2V4yBphp>nnF#LojuKWajz}seNw!q=Pn>KW5^8@PHpoj|!JM=Nk|; zR6HgMzkt^lm}sE_L6DJ4|Bgk(DiB&CoSE1`k&fE<5hC?k@+zp?g-kY?y#f=d+7zQl zB}J%E{r{51`S*hS|F9tcF_c$9C^5#FM+?p8`(J0_PKAH?`V+`0!nb)74fpP(rT{|9 zsDs`o5<1ePz`o@owd|MTvpRE`^@Ww?oBx>z?u77ZLSdIX)T~5Yf@^qZ24#g7w|))V zl`lwKEo~nKou6ZU@mpX%ii8GSNXFC8`Sptap|wEswDZ zLcYjPE+X@u$P2Pe0s_E)Xn|lU1tMLpMR@*EE#73&#RW}Gllzt5oUm^Z#d$_5@;&%m zuOpRFz{|Q2!jfeW*e@0ON5CMJ`J51>+ePhi3i(^3=HKaX2mu4540A#0LX%d-)BlPw zVl`D@&_XmgE3>nRfXmH`!T_zG5InflFf3~O7Hw@ooYnNWo!_U8fe^K@iA1d9Tr|Dx z_T0tqY;=7&y`z_#?~SD#lC)9oX`xmG<@qB&JhKC>2BbRUy*w6YyjSjxaded>@VbnC z^b4~*mhApxn0wvJjOFXZ9Wj{s4o-h z`kn8$fPdtRRBodsf-0#ap(15=@J)h3H47QAu0B0<-!kF~S5l7| z5J}uV*(|_PIO)c?ctZtL=ml<38ywE7H&OLm_xFF2Uv%AVsVlWI^2Yy*(-MsDn*z6b z=Z?+G3&0UK(tW)E9B@N0-CbUI(fT=yI{kmuN@pt^dL0C?qpA!{Q4iQ@kShwTxB-Q4 z>}S+Nm_n5s%nt;B2*fvwfZTH3c}t&26}*?vc8YOeAuUXKZ_&2km3oR!kNeQj)71db z@t<$ZlxxF;xmq?~4gDQO`ecBoZ&J^=CE0Ge5BehEWbMN1&)$zEQ`}&g?2L~Mz~gna zo1V+<6&mT=#sPpgF(Jm{Ug`Hy=?=)vwK*lE!2fWoBwe=Wf4QUN04fjgRVGw1^kFqM z&pVoY3jf$Y!{A(eC?^O@7dLKj@H5MN%htiOy!T~DRmDrc%X2q>&At%suF+h^BLb2) z2kUraPr76`1EEFL9PCdw4jP!e=T{yN&yVPCo*qL^F%V?SGOHs5=y$#&d*AVsjXt%K z=FuGheg?~w_zy46gmSOEcj^*&V;hIRB9Ndn;PicIn(!z0L<8g!km^!dg7?Tmz12?1fMULVmCs#zXpDge)fT#7AW7Q#PH zl0{Uyq3<{9f&AL1+J?!|jd(5G_l!aCrm%F?*PLFR6^D;~=fEKv8Bscm(@~w2Rkq>j zzB5+}>VFba*fvFs^k+w^>WA^L} zB%Q9Z!NCm|>xE|ap)=&=e(c_&&5y{7I!n`UBAABOE59#kIM*#Xcef6&&){Kc`T)f`PhjT>T#8)g2HQluyMjASMn-e;tB^yp<>!?OerA3ub6 z2Y_dzPRoOzfMN*GaZOM%0Y=~#peG&aTK7SSAn}+@@h2g~IY5Im!7+FuapisLXEf6H zp{i0!9*^8oTH~{3P0L|$41#sSYAKpM$9@Jm4@z0twqehe2dI-JWZM7-d`FW(Wm_6( zLHMO`-o$wJm-0gfMQ{Az$gdpuva)DeYHDm&y9H}7B}zAX=#0<+%zYZC_-(8b0zd69 z1h1EJxRzZ(d>X*gUG)&`gYMiY=PETob)-TK92IGFs`8d%8Db}?42KQ&YC=ZVK6Alo zO62CMM-2v&U0w^hf*~{&LS#;CTt=hRYDsi+JY$)s^Hvm?hN`|ILCzWL&nXYsU1z~CEG`{N z0;h4@Ejw@`^8uK`D>?~{ht2}tsg=gPeCIn*6Y&qXKx$#OU+0h;@FT)U+Zqo5V9gnr z`TXFn9|;+dr_~i$#y|-{Gm2x+^J61JfF)cAzdFr04kmo;UuMs%AbEq;Sc#Mq%!y z;=D%)%+CszH9wZNGzMB(VnmI)zVMIETag2MkFo^JagN>(6qBx78M@WG@qGy?9dIvS zHD|fYj6-KXDLVXkWP|fHZsAjgyWaYZcP9!Iz9(0tprZGIOM}icCz4`ahBF?zRuEc7)&~u>zVhung+=cQec>$i;I-c(;-OqmjzzW;Jv z2L9k7fCA?hiXa%hqSo`L7en5M(%~-Ll{DOB+6k=T^EO#yl$ZL&gy#X7zjmv227|o!|vI8 zcWs`<^u`^4DY?(w2oWx!?!fEkAMQOUv!jA?`+sByO33wQ@YKrdHwcTg2^iBn`%EL^ z;n{tZ21u|*Cu$-Nx_#76X&^k!!ar39ClYltoZ+W>kx~ClL2=*mz}nE%s$2NP0!qI5 zpm^j}tNnD)IPp`JaYQOyz|I#ej%@&)uADe53@wnqw6v@DfZ&i@PaBVBWK9lr45U-<8qv$@m8;Cn8 zQ2VsKh znap<85)D6l`UGU7`c2fmrGqUfPzUxr)_wR>E~pTqhVzlAoSBz~vlL69Eh1cFWz-A|Kshp7-!8WZL|} z^bDMtj4^2J7*rsPY^zJxRY%NXP%j&tTSOwn zVWYC2S$mWTJD4$RS|V_%UiP&gRs~r0DS=wDQFV!}=a?m=*`FA%v|B?4DS~n|-3e|u zE#g7(y)JcRJ5OFlq==(O89~9^rw>`+?2LVSm@RI%!GtQWe(JNgnE|@r8+4xW_}t_4 zat#EDNyk#$YIp&LOWDvONIw1e%g&3NPvyHT!etclQM;DciY3}y%`MU*vlL(Q(RMSr2O{=M`t%=w+$vNW(S&ypv7^R z$esID;AC0wNuFE5;5dX=L@q_*TyI%Wqg{KFl&MhKO$@Jq+%S^iYv77$eMP=El>TTq zEgkcQM_VH9)j}Mmrj-bl3fMeBo?*lM==vEsKBv-5L@HL zvzX~x|3gF?U0%#{Rx~-N1n9A3v+QkJ{5}r@{kYRIKH~C(H_rteYaVGV@I|3=(4sY3 zVxpKeGS}q=gA>q^^GMch1*LQ-E*X+lT?6gJ;FjDFSZ`wr@$2Qzjdo9mokJQa+^|Iz z5@;6bEn6ZgY`F9uwY<4rcxy?ntgGFkvfwM_kyPM47@3W?;CyTEM*9~b&}0BQk|TBF z3;5Ya3q-d}J_oV4%))|uejGE2T|u4;UzkS@!-|XiUF)gZ_udxqdXw!#y~_@1WDm^O zH_n~RZ^hB;ubOl%GW#UZ^H7duf4+JVDz$HK1y|8!BW6oxMfQLm;y%4BjY+z_gydFN zMj#YAy?)zxXwa%e*1WFLJ-osQv3+q`QsV;6H}e-j z+`=-~-BMS1V$(GETUzaR7tqhn1b|-`&Vp1{fmU-|HK5EZ-@J)efQu`XRXifhKXDWm zF{p`FRa`=8#EIm2i*cXurfmDL==!Y+lEqgs^>*fIak#Y`Fcc}FNoh#>xN1ary7HCa z2#(1hvw;R~4Lcdn_TsGtdupF4rM9B4-voM^Adb+q+P-Npi7EtV8BMQEM1TV;o-%dj zf%cq4nei*2E{qM=Q`sg>t__0rcFXruLaZW-Y-BD-S@%B8<^r2%n`xS?(u?L*n2)$R zk4irul&Eg{ttHSK4R|Us9UdprovC64r$O6zYX1eOnq&wuRCLaCszl0XP>&-8?aqD! zsXW3vqN2nKp0_~Vd#jnp-!s*nmF0VAPAIDnUe_wvZPT}JXp%ng;I>1aUt&{uQ_E#p;9QJ4JKf;Fm|E-G>OC4r_VRQ1 z(wnH{_>O{f3bnA`wrs={yHR4 z#S?xfT|wJ9MZD>&HsQy^(yfuot*e*}7X!IP^WdhS3csSE5reUCDfxwX|~^0dbbpg=HPgU6(@t&h(gf~&hw~ZvR4!(BfhrW@oj-K zG@9Ci@fGv1!rQ*+!o9%4#S(v_V!3m-a%IJA!Bi^m%TfqsSxhsq<#V zk&4^K6QSN;D>-ljgwEht|udL)bko|MBvhv6c+^%+QJn1wV_!yYS8|UJ}S5t?$ zozJh+<6v7bG(%Xt9r0&J1YXZEwIL}c#YL&4m-s&Ka;?>eg++5bC{jCZH1G}AfzIGnC4P&vj|@68 zhDXx*+<*!kWv$>=5}P~Lu<=a5?s}AM=^MnWaj{l5THK^=9CK2$FZ;fkwqBi<{wI~7 z#gEEIcRb$m#!~`T%*owPifPk&dS)Vrwx6rvrSE+UsXgKR#$~v!H)yMS$f(H6(I}j& zuX}51doz`N4hZ{$jGO&bTQ_osr;ehtoTf|+N&6OVu17_7CP3dIu!$;nuRhdK{3%0K z{f&B0#H^Ycr2-k}jWe4qSlWe%GYXqn?v&s54=3Y_PLb+QqG$ zQVtGoo41^{ZjDwvH~b1DJSr;Zj)^vWC#@4b+>M|51^589)!Oz}#cNN)J{UVpm%HG0wOkn$3$RZ8=@R_^F zqS#Z>rumt%*POxypA94)tmS(}&y*+qkPqV^5S?z=Z~S-&%ePvDid_s!Wxq(YNodPu zf^2pKe;v8(u|P_$Ci$c-`KPLDE^1ia?>)q=gI(1&EQ2U~c!l#>(ze)-+z1e>K59>9 z`8e?4!hm!kBBWeNZE@2`sFet)cvS#fWeV^y) z`467g>-=(m_?*|h?{m)keeUPJUiW_7G2IL`UEF3ErDx`=D65oVu2Ft*>$MB;2c)2* z=#0}3ub9>#_R6O>#>0`MOwgaK&@;oe`RP>xmQjk^VUkN-9A)6|iHj&rW=vknmkwgeUl}78)6b;@~+kxE>L` zqxoesl$WrHt-GKkz~ER0vKf7u%M1av$}4=E!P`TM(`gQ@bfRv%tcC?LkRY z?=t~`)en7xq7d1vb$FO6H3~mBs}=alC$8SxhTG{&z}s=-Zl2|J)pLof5WUPQHv`go zyh^o}kC#)pzMujyaCr{jGxjdc(}ZT@1SbmlR74c-+X;I7*7&>HH4e=3;BjXhssAoY z!EP)5Op24zmGb8^2Xf8P-AVqW4Ks!d(@>stoQW7!$-3hr3}h#dt;|L?%0HcZf#OxF z%Xy9@t(9;^JM}Jre-sK^`a^U)NEwi(?(8AZIZrr*6p?FxwRS2R5c$HEL89=_mx1KXxg{c4v!#R zTJLa@cFd5G#UMcpHrVR3i>|N{X2)ytvi+aD+tgOYEW6X;R(&@L=I4&J)`q#8Qy*`A zR<-m`KPQB_KX7ohP5Oy@!sK@`t11@S8vo3^=G*sLhK2V9@2>$OBhePt9X)`S8_Rvo z@cm@4I+=-O@k4Sfo{Ndl5lVON%Ymx(SYx*%LAZg++o z8j#%QQCYMM#hV8;J>aS?OLM8u6&*B>geI}hNj`S2q0BYLHcLCLt{)8MDC=!fP%!bG zz7a6hk99C0>2uNt1+q9u;i&;Nld&(KOc%Vnp6$#K>na`EO_#9iYs#rnRfYCdJgM(D zA9Ln??P+oc^6P!-!d2pAfEGM1k&jp`X!YsrSf?elc>62n)d<7Om2$op<|E-m+-CYzz?+^JBoxp*qo7!_&PjegC z;V(?7PB<}yls}gl$wffH@kH9*w3)DhoYn8~47O%3E<2;5Z)zSxn$m(5#OM6x*|pHK z)kIaWYm)hFas~oA9BT{!KQs5dXI0MyldM^tI;V;e9QY=pR`rs)A9bZ<4|MUs$T>SO z(i+;-Qrv@XLZQU77A6<0%?}%M$iM6vZ6`Y1zB&lxsEj)dMHH3y&%g{?=;*U###!b{ z*`l2!jQb6EuLs|?;xBfw`{Bg=tuOc6s)7zlU-sqaO%%`Yn#ymnIpTOn`KD`sqPvwj z@i&~40*iS3uKkeNT!HZlUg!~00tI@tva8>&q4tzKAlC|l(Ze!Co z8^CYc#tDQo;kx^7T0!V-cx}t0ByLJu;leJhnN(OhDCp)w6~71A_rEW`IC#bS*XFrr zO>XFpFWyf7ukG9U({v7NZe~32P`CVq}wfW>hue0(zvF`#UxJo;hfI9nd zU+-Y>1NG;xYBdDakQ25PV7bT};VoU>rN(MV!x5e1kCx~Ci2TYaiHPL$?Y9f8byQH8 z%*-(C_(hjUXxnV^_PV32huIkT0jRpw6?sNHn=MYXKsU40OGZmg-{_8O%T!hh>QjgXFAn{c!+d@7o*8pC2ro20aqJChD;rdho#Qlk>@Zsy)R726D}xccNUumn9U0 z@sd7HDdSy_nztxIH3faQc5PrC!Dh!GPYWI|TfXqUnZBrY`ecXs?QW$|V!}Zie5>`x zD4x&4!s>I~T5AaIfx4(9tb=m(H4zaqv@2#R%`ZX=>Y1!%JlL|V7XcK^nY8$ADT-%G zFoMRU#N4fQ+dJgN0S#Qo3GrDqLO$yOBdu2OZNJ8`qa43*GJZbiDbLJYbFB_4ArH89 z-#S}TY%YCBWc9X5c-&vq8)y02UDU&(JUmBv1{;|lrP~rr-Ng>WhqQ(m+@8LOO4kl7 z9e^PhN*83lHZj#ZH*|@02G!Qp^$6G4w)ih760e`@lAOII_S?@7`0S|*NM~TauePq) zqUPG+W9hFUq46%~Di$=b3TOG)soJ6y2wz8xK!MukuiaqmhAYtSHlL+;>&H6jjJB+J zM`{3>L2lMwHKmA$!nNL27+R|OT$%^jL}_k}JmZlzpSbqXrX|5TV12Fu=`5R~*d{`* zt%xNd^{&HEOrZQ}wG`{+2Q3xom-)Nl-+F0;oWF$2m$^))%Ip#XX9R4znyU~il5ZSw zW98XG>HNs#1XJ5s)Vd?rb7>GQc}{jw(f?7xnVDcX9bplzqMj+t6WJ(wC(oW} z?+Qe8uaHKuO>X8(Orf(Sshg4wsbnS#&m8_wc?WKZWTUp%wRH^kq*qZ_xKe8g>H`4IgwelWv znIE?;Vs`h=n4Z|1A;#*$%;Y_d2g?X($601ax&Y1G6;wjr6n^zJOPz-hR&cDyI>zN! zS3yuoF8F*7jV@v5G|mTuSB7HA15OqOyAHmSg4AEYuk`zym@E&Pv|@|)AfN9wc=$26 z9y(n0J-BP?K`p-rq&(aR&QrMu=4h#~0U7X4*&VB)0nL(h5exZf%cvN*yaE~vcY=0{1M(WB$x=cv}27j;HDv{-ZL znnRBoKS{w_DzQmma@{PV6v3JHX-2%>)!RwAV}X2SO|- zu`>borhZ`y$=@~9mMpHV=tMkwNrkiKKmyuhfijdUUH2_{>6=GRW%ZKF>Rs9HB}i)E zDP4S{xe?}49_!ud4bSL>77m!c@G{bpFXS>3minWt5w2uGf5Y)dEYjIhJeW4OI@6w& zc{|{d?A_-_;0F+e9SM(l{(l&Q eO;?bl#pGYB`CeY{*X!)zHLa`ER4i0`_Uxfn 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 diff --git a/src/python/evaluation/plots/examples/penalty_issues_by_category.png b/src/python/evaluation/plots/examples/penalty_issues_by_category.png deleted file mode 100644 index 3e55aa124bfd56f920d9be50d38fcfb919791952..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27515 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 eO;?bl#0LU~1*AxC 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 diff --git a/src/python/evaluation/plots/examples/unique_penalty_issues_by_category.png b/src/python/evaluation/plots/examples/unique_penalty_issues_by_category.png deleted file mode 100644 index ab69b22fe1d2c1358bced1fe939d9eca309078b9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26022 zcmeFacT|(xwmuAq8hR83r6U3=C?dT#DN2(jO+ZAX2@xff(3PT6EeL`%>0LU~1*AxC ziFBe!3r$Lp{#$Rd_dWaEd(ZZaZ+zn`W1RmSA@9n1*DPz!XFhZK?1q*q4J8vL2?+_! zHMOg{BqU_jBqXHkup{7;3FG|<5)uxQYgZNY-OU%{J*u?^_gmyb(xTHyBEfI zz6_?S-MaSrO7xssYb2cVv=aCGD|geK(vDxCDVOLJ)4X8aaf<&|QkXmm8Qf34 zh$5Avx=lsP7w$*$=f`bl{Z@EhiFzwQ-ynW^HlCy*&SlC4_Q!MJ(?|_67~+auKjWW| zfz|pbII6FyY6buK82F95x0=Eny1XK zn(gdsyN8^76)q>L97v^ZxSw+45;kljf$zz4H7*$9Do^ZX;!!z~!2}wZ-Bww=tn9Oe zeTBdj?=cULUrHVK2fjT?&E>(;s$R z-W@#9$A(4HSoE&&gb;W4nDAqzC9418r^0Rz2lL$x5WBT@O_*>Tld^;z$mQ4y zW|70kQ@^DP5q5St5;|t4m@;Y!UebVQuRmNu6OZ4@nd*V3SnxZIypdQXNKgD`2*0{^ zHsufkh;)244M|)h5n3ZQ@$<0=5^R_|8C;g24pZvTo2_XczXTHnlKHyUI7@I%^+1;d z8gRZ0R~`qzII1bI-|rC*iG(0A`Pg8os{vx8Yw9jU6&Hs-)|3vh{bWc6D=7Fi$3i$b zY7S_NM^eu#g({O^x#j+Fdxem)35eVQPhnOl?*1aay#%zzhIHF(y(w6u+{=!YutovZb1h>?)55w>M_uC8vO2MNx}|S2rs&w7#PaI3G6}fSH)?f z4CSFW<%*of(jLRoZ0;UsB^Oq1^1ze@8q~v1fu}^g$W9Xv(Veh{jP@1Dl{a9GixwutHP#3=wPnom69ylD%1c6& zkbEuqOP=bg%>{$RqdX&rQ0}(n3;vEHg?gLRp0^TxYfOH$NA*UUI~t^*M0WO!mh(o6 zcqb+)QJ>Ix=VK+LlugUh8P;#+2m2v_q$hg%1qttQN|EDyLzPee&9n{Xj7Qy)263W@ zcJ6BLAg!BGUrt7$r;m7lv@b@tBX{SZ-2-pT6* zY(|WEZgkSs*-q^5#g^I{m#y5pdpG-D<0X_gRy^vQ`GCq$=>fS&mW64lfb7hN<-shE ze4v6t5!fmf5?}}1Gz4ptSED$q>|Xq}W~bLMc5h+zK6dQai0IfbGV@I*YkZj7!qnCU z!?Ke6s@0c`wU{yw?*Oq>ifcxPfxH>sopvK$k0r2Q7pmnBDtl$;R~kaGLj$~8JJGrE z6F3}Ndco7qk=bD;;ZT0}K#=C?Sjmg8gsSsjr6~wd7&VO48a%&Xc>QM)^Dx0uNnxkd z>kYAEB_36=NS3?ocCDx|cbD)BZv=911^FIdH;2b=SxC7pyRmKuX}*n>WW^#``Dsws zIZWLnR!f+fh$1B}(%I3WpBH3ja>eHLm)DooS^ltW=3z_|E_^EP zA@!&u8H?S6xO0od^Y{wA3qyy0N`ihMS9`X@NL@l-r0cSKjkH7R^(cO}HJREHhBE!L z3GP57KVN>AC7K*1=|te>rdib>;_HdL-Br`5^Jdo%RhH}LQFWDVwV>#*Vb`A@xA6fU zV;A<5sF7FW<#huwnqOfBal&@(cY!&z6}NmPx~0?Li!86V)E(N?B(@*K0fiOS8Gb@= zW*>m69~=Mh!)5B5f;*Sk4{~aPsT~I4$eHTH8mBMOF##uGE7aglFk}u}$k&M3O0>CC z0uOnSFzN%&dP?*vEd4}AE|iww4R#4mW#5LAOYJGR%Hgt3f4FmSw;mgZ zrFv8-U3G7isk?fVu=8io&c~aIpE7uH`>kw0PwXO`WjzVx4jklTuQVBfqgXveSepY5 z4mD&&mn#T7MUyBWM08jQ&>H65uR>|7!5XOcXf$yRFTxr=464#(0b<`My79WCU4|*|9CbkBvX*7U(7F+&99< zKl$Guwg3;-e#>}7v~xegl@ggwEyw__l->VaDZt(Q|M^P!kD3EJ|BssgKN>mJyJ7d{ zqG>7->w3c_9&x&QdV~9Ka03Znv2UbST;TcTIf>>TJ-P0PIcOk=g?SIlmBR_QaM&Ogo`HsNt%K-#aAll5DkNKh~@&5EFtZF|7Mvp;5R%1 z{O@tz<_AH6+f4pgrNboGaD_)4erZoHg1SmQBhkbFgiAVhd(Cr!ryGm0TJP`z)_3n- z$aA#XsdK9HF^*m zFTe3yZtyh4B-^8BDR-!s8FPFF#-8xn_dR91U{DnB*D%VvtbD9wQkBV~RDDx=P`B|qsKm1c_rsXWAp5R!fEefMC<_l+`o$(#fz*)O zx{hx9bRhEX&v43FZ;#VfVye z06>vuevYH>`A*bctwZ@XP2Bq^3!j`TY3g?Jn{Tp_pN8%#Ekf9&oVrbf@w z^ufe|xRP~vJ!x^%(7HkWpu{;yJ9_q+)QC_C&>mJ*~9+%j=)GeGP2||a6NZ{ zOpH$ZOoYx5*LAz`M+I|HC)wxQg12oKgF5YzGnX$W%Av(h!3q$wbKz1;r%wk0wh<#Ik(A_Q(O_B8IMjZ>2bGaN?m zAJgDzxfgCyXj{FV@65Ro+9mMxD$Yh zCzo74&>cu};=G9BG@CKdE{zZ|dKkAhSZ-?BY4UWXQem`2@)6g)VL$m8SksB|OMA^( z*MFp(wVrR(Hk^CQyHwu2m~UQezUUb~;6TN;`ahPxpmS?}H2=ewC{3N-_eE}Qbh0@i zE0vAI_MgGJ0uN0d%Zo$nYQ~j2Of^Y-X>Gj`K`S;_Va2}{^`?5?fA8HWZMoSp^WgxD z*t!eL`-ozTJA{ z8K%vzqksm0^3Z=Bw) zxKy)pzXp%z-Ch{vUC7MyO%(Ngc28q==6}4o3##;lh@Fwz=a95k)Y)y*<#b#WX1~13 zVdL@ta;`yn%LaA%7hQgC+02jTjM&IUeUcm*`GAzGDR+O5I6+8lo$FySWpJ))Qgx1? z?@#^gkkjYRU3x4Z0OVq>{&2$E^8KDs(YuB!Y(X77^VS|xEGtC_^ki6g7tDQM{z>!KQwtEgP0{p#1#*Tg zhd(RBpTdC_@ATSCWRBDaBbD=*P)kwegGF;9+rQQjrQ0*eSjqJA>_nfJh|Is=`_#_s zpu7<``%hGS>y6qDQ3)@S^|W%|Plx5-*m|h?>p2B>AK`Dipd+$kwdSdk%keh~NpE#WG*`tBE4&k3YqVLl>z88L@f1n5ce}^tLM-8huM4ek)Wsz%=mlAQI!0JNOW)uwpZ=!<}AC+%wyum^bsoT-! zK=@M_P`8mkU>2l(LQY4A269$LC8yRRrN(!uf3Id_E>@E9R}fH_zdJ$=Y~J8G&5(3j zogXP*96n1W+5=~Xntrykk%;g`PZsvCkLoFTD+T^eN6?v`RpY)t1y7#WHCkL|OG8Cl zr1D?}-yln{k5Q~859dz&PFcW7bV||QY){8zKfo$h9wg71h$2FtGxBAJ)j8^Ycir3Q zT8sEMglx9;xqRMdA_aKlo)4Z&J=Tl{<-Hxg`^cJ&{TYC!iT!RPlZAIBc;W)Z72mSI zzoBXRG^-fSZ4sa-nAdeiSR{awR24Xh

    8f?(3J62D!G!stPya%Itp@xh?qS_Bh4GZJLc>m&~|5tD0sZbMcBI_Iag-z%BT7su$LGG^`+Oh+x4r2Fj=12wG zZS5A;CM&voD`~foa@`(Q3|%?G?|&+s5Fe!^RlvxO5ia@M2^~I$FvDlxlm|04eK(dy zZ$+CMnV~Ii7qhA3=ZdoajWw#)nKLd#MZA2SMJH!web7sR8(o?g!41~VsMVBBa{lhb z!Fd2UvizVjcEhNMjn%2oxy5Le@1n=vp}k$43bJAm^}7{*FSFGXXbTwi?fS10FX(5+%`uueLiec2;H{b*+E_=7RVvdh?`QYqcI-9G zso2=3n6>}jU9i}-3J&o%9s9Bi540av)QAr}w{_+O2>BS2vpDr(;sBL7QyqRhFyt{Y zHK1|2Bv{l48Fq|1NMJs_I6}|iocbxi_)cgW2SI8)Tzs>Qj!;xP^0S|fT!XisRzRvc zedfVb3j&g=imY`QIdE8~Dc&k5)hj`G5zZ3T>vDy7JGQk_0vr#z9bI=zj*|9MOz~Au z?ET7llmF`mvlyZuV9AT_zP~);_a^kT#L?xyB>E=*5orBy*PMe)M0s~l3vw>d23J}x z*K1QCYnf8G?>)TB9V?ie_*=(#V*J0|?znzyJx5`5B8$`4%EWO~>E7R8(*@igmuoNU za6f14RNvPv&*W9 z-YHIp*ulg0vmXt|A%8Xdy}NF3J`rO#A2XiqvwiJ%1{1lg$5iGtk#$%gw}(zH&j6(o zq$N@KJXWky@kcu=mX9X@W4P@@V|lZK`4Y-DxJ(t1?}=az(`I6Cae~quf3Y{q77Y`KyiZ=hvi_zv*C```z8^ zOo2e5g62i*ObafZ!u{^s;HDmnsFfuDJnp@--j}m%H zKb>XB8$cbXQ?QZ0$x?gsL9-3PHwe)+vPA*kfZyVfg`IdU?;j!DG=F=mTJZ3q+!AgG z8^+8k7W7B_Q$!xBCJwUYtLcH4IVWS}HL!b=uMFnp?quiIWxB3Xv}8X>R@?@NOYG(@ z&c1)a#31is$rT}?VyUXBWgCel@m{K9<5wvj`Wg`(gJoN_?Pp7qcx4CIrwn9UP%Hv+ z(Im(LZymUqf9U==5<>R*CDk%xxhE7MmJ zJPo93)*4bS7{7PVuX0@;%88}vUx#jxpI3i(3*ky<^TIDOXZ4DdKIAm6UNDo{of1M> zcb)s4=LefspZKL#!yc0w;_xo3Upp`R_3IPf<=cjPJ1GJix9g-_G~=m$r^g%gl9CkVTHV@|#g@B;{2BDQq@sq(=KZTt0lEy=~H?+?SO{{~n? z%C_7({gAj;EB%#J?Ax0*obg8*9?OqHjw+#MM;Q0kdb_(^&JM%wNjo?7Q^&1k%o!c# zMjMlqPBTAS6tXX1XnOke+w7qaA?6n1TEOdpM7LXe&vFfr{Tt=VF+{nm%3oD{12&Rrd2#9zrMvm z34C!-G%h_T+TlB5#Ki%VY$EFB;!0)3+im!G}*v)7Sk$>B8_amaNt8SXMwC;x_(tc14oyhMrgp3KoI~EjKU+2r4 z5U;sx z`nK>lkWRc8xniI$*E}nGn`1j|^Aj7m0$U67#($ovTx6L9_&7)Wp7$mHv1HyFtzu#-v6-EkrK2 zox0*{7sle}hlP%Fm?n;nqCo%IH+2*}kn z4cf|wVNh&tGAT^%9|;$~>Ml^3|BB$`)KBy~ng!cWH*Oxeq8}g@+24@lMa&4cBhR|L zy$k{ieypDz2^lBXgQqLzzyMX~7E+l8we>oK%+^7+eB=tC5B=sb*_~BWrqv$mlYAyu zrQ8;84qZv3WiCp*61oz^Pfx+?M09qedYxgi$H8spbyXPyhn@A8t}DUs6pIUt7-o`o zeShQDxSZ?qV3MHrc`hzJt0mmRzY&fC>|^6w$5Dfr6wU5(LClc~V#R zJoSrhdw)Qk5Nz)&^}~Iqn>Hgo{nwY5LJ+fHjpPrQ@U=AcXF>4O9nQCJ!Tg`XAFQ*C za})vkg*abm8y(S(*o_qvpFs+DJS=*L6D|sDH~h3UC#@+;m5U7&0Ot9bJWiLL1Ag(t zPhK|ISpsd5zLRrl6IeF@MsbfCdc1D|9J9FM@e~g%fWSly60b=)7E8cQ!>XxGUxQfs z>o0mb^5fjVH#vx0?{7G-UTs#28 z-Zhn5V@y(+Apq0Wo$TSP_K!P$WQv~Xvoo$Hj|4#1GsWTdPB@GcV0BgB;?+ohj?rU-5g3>8}G4t54->& zozW#~fiABeG5+7gjbqrb&+oN5AN>xw^UDyPin-754QB20R8ho{GrddkwbwC9P~r&b z8Gv6PXE_FR3Itvz74CuNUK=uw!_{U2-AtBZ+g+*_^MD72L@w4z%{PUFe8p}&zTg=9 zhd&lbFa4+gG#=8am4uJq+g68t6De>LI z5mI$%=M-9jtM06izZLb+69O)!#Fxp`J^u)$BA2b&j@yp(n;tXQ{@GWdKy)EbUWO#! zBLInj>dGMoiiSt&818&&BtV-3Z~p>qp7UGTuiO_4iz~VT6%4?=CJ``(qiWe|e#QFt zW;lwi$-`aVX}3on{B#2`!#bRwF~P0!ckef~6U=LFc3Cu196m0uMfGIWpXjBPUiMfw zKwdiFP&z3rAQbpj$DUQTi?NbdKhthE(ktBdTRCFMa7qbIge(+VnVN6hfG7hB-@l_^ z0rB7gv-NLrsJ)5A%*Dla_gh6HaQd}`q4b*=q~o6pn2i%~f&$#4Bsqf1ieRdmF3le&z;!qHmOXTq zo=kx!vfHXH$iBndOdo^`^`Gl$5tHcwq+1}c0SuCj^E$JloY0#qetIZGuBZl;VAtn& zVpp2Zh*Xxn3D443P!2iK7MQdj#kdtj{=4AD5!I3ubB;lpZO2w zCnWv-6v)3x_I>zS?pTSdRTZ}RMlzvj9sIYh$C;ww^UVCTo5Rp(Z+0rYd68eQg} z8Ms(RC(ZW5LHmtU(mEkF)a3^qAZ}qoFygZx`yaJ)e9bdFm+mJ6aHQffKEpyZbGfI@ek?a(++vH} z)IE=NB9^AAb^FdOP}EuUsl+EH@oYHcfOz1TxnXO++NnSAzt+mx&miJZMg%=QMOH}B zG>Y}c|0t*ZSf$@~Tyk$9JKH4fCExvvg^vAu3LBbL$_{9!K2LUEYpMdI)-QCv(j(Tm zQ~#hSaaHH{WW2ZxCwQ#JNMvuwClE%AQy&u~KMvBzdQbbMc8Fb5Sz?!Kc+)H9BE;MN zFCtQ~p!0CuLi|KYSy(A@MivuXK3A?GBceB4Br>>BW(OxTKlXv)n`rs9s0*mUCsm8O zHcP9irBe{X_EIU(oZ~jFzqFfso=~NhIa&*GreM$kopbO+PsCeM?&SGf=b~4fKle78nLT2d9cLh=SwjF~U%h)#^r_%siXL#9dK?p4?<^@Ph;(d{D4<}j> zJ^BoOc@cEk+QQ`y1P}-bU8N+oA*bAZ9rU?I*Y3j^N(> zE4q02isaod)>vL5CML(*cq$nrw9OJ6Jg~Eh^@S_>0OnL;i%ph07|q!6Ebo8TVyKlm zA-ybPz z01D{Y^tN?gR<<{Z4}2z5C|^%QsOPD$^#=W`OabEdre?9me}E`h%SDVFTka;~Dxk>G`RJE0IPl(Jbs9T+RbGC=SxJ68ovsGF{^dem z23Umx)H*ZP$~C+~jKFYKMLoz-LQZz*hYBpUEZ20NXMAF05h@VzMOv@faB=pxB?O=G0uA4X`GZPr%Bq&2}x1++KCr^4GN0AK^FZq!5FLXA+#g zkC$0xES<(z$R40dzeMw;aMlcGt8CcgJ#l3V&feFJo|>s%e{v1N_ch|VInU2FAfeO{ zM`8;n3xfI&cst$AX>jO)!YDq7!kjfT`3&{_?N2~A(*ZcQLE1y*w9=0X7WpQ5Y=DFR zGZcHlJoj9KgZno@uT5gSztk!7&ow---J@2Ovz1yVl5Qp8=L~d3m|c4T43Ks8=X<<0 z1SP-PE;Y!Q{s=2Lz4iIrD|uqxs;Ju&hy&NS5QemegPfWdeh#~bok3p5iD?0BFbmN2 z`tv~D0_0OePg}GS3LaXk=Qyry!wRs^T2{u0Otea|&63yB&~3ij+Cxv?!2v&om5EHq z9|7D!Q$%JCpFmD>qVJe(`!bbKkj<-i;)@ngY6fbg*SlL?;#UN4eH<=l(f6&|0LN z`(@S9YC7MMqmg7L00k=MMIhsjQR9F&I9$6w0S*daTV)+41%S7mW89*Ee-V_6d8#^- zd1tH0-tCdM<7gQMIc{2})^C%>@n^Frm2(cm+w2?Td+cO2r^JxcfY-Mk3q^1ubi=`Z zcH~}+U~21^uJJ&(p@2*X zP$b^qaHmZ0o;Fdg38|!EC=Fcz=wDVMeD?)Mq^)evW@ z;p10loe?pAB#vKdXPfST#L?#7(-UM}AX<_TFN8~}Gv!k#qey9A| z0REH~iW9@M%7TS;331|oPxpb-E3d!SNb~6oAy_-Y=X)wl2vYyz%nC}fUQQ@j>utkF zssKVAC`<_-Q(}7qg0a;(4r$m40<_N{Zdbu+M1TawZ~vf6aRzi|$wv$)4HY;fp?FM8 za)_-@4X`9~dc|}>)fTR9ogw{$5hbQ9LX_HfmD#4>C;B^&urP!yObnPHi+;V}lkyC;`S7mpqcfzA^eqy2R!)kD^I8=$12zj2v z0cRzI=kfRH>{1Egxf;FTlqE!;NTh9eBJWR#B>i6nF+T;EEwa0nPo+uc`B%@A_??BX6m@;YS_g|!oY!D9Kfbbhs3F98?MWI$ zCUqbic#8?JV<%f!DQZ+dDbI0)l;KX_A+m93eH#tBKc9`J{PXuMgE3UuC37OA^BoQi zpB(G{sc%ST-Pssw+*vlfsx6>~3FZ@e%>0y;YmM*@7{BAUpBBR0w@9&vJp%r^%Kf^f zA6b$!3;HMdE@&pkC1k9)+F2NV4!MS?jq_jO5f3v*p9Z?k6O%ByBt|MA$5H*1<}b(e z;PS|UY3Yf*50ZK^l_${el!GakxfxUE2VUuw_|}2mgtsunSHV^Sy4ZM^Af2i~?yFW&2_RIV@6T@iNpWO2MBXOg@+R|v8hca?{#NrWR; zPJ$8W!$gTc8S^n$WqKGM!)op}-AzT{A}uFGxuwRb(%Zr-u&a|(!F6H8rx|F3`qP>ksCd|MhA1( z2F8#eDD&sD<`+8tFqRh|2n;U;*x<9Fu%toCic~Jw^r;PpW!hMI|+~fjJ$rzZ+J6)&CMYP*5JircrVL zrn3YI=^w4>Yft~Q8?iIiC&n+=0J%SAlKRV;{^KRV0&S$QUjQV4x@A-Y{GyS~&}NRE zPgx0?gM=|atXTe+OYmbgcXiJq1E-`;D_{S|m=ftTkjSCUgsGhl6w`o=B&nIm82|4^ z4i*56m|B1hcz@QOImS6@9bX7e9C7u_xoS%kWS%0fe^G7VWo`qBnP-y#FY)pa{LlF! z5in8#Tqv{|E?pHYO+RE4nZ#y-^;i-Rb65@s14%5b=pKd^0F;*kaKTyp?Dx0|b2qku zJPz}VE0l;B$nPnH{YRAlFN>1DN2>Z?6cG~e&=n)Qw;=tIVATY(4bqPH_%ELX%pZaV@Y#y$UN7Xsra7{Mh6Oyn%^gj9u$3M+9Zh+exox452ixp|^&4j}xc_m^hx z*Z!3PiNWQjcv}*+v_|M2v{PnE?0+bl3ooPM2HxV->@HIPr*>98J*1T$+^}R-ja7DQ zt|B<`R@uJD4W^&7EC&1*HvwyreJhoOFp7sb4#ZE0%>N`5hX18e*j4y1jl%DgTMP(; zgovZnUhu+=u%-9zO=j`}hE37@Fuou|ICV_Q975EfOq2pK#r>iYHP zU9x*;WdzgR5}vd&DFJ?`e(D2DGnetx^RHY(00mM7>I14-PE7sw`G9HSnn6VGSbS`j z%0_?D$Z)My^t|v~x=o^2y^q|C185LO{c5u*S?G+oySEJbcdRz8SkMT^d70|xC} zy}t_>H>7b;F~x#(@J%r@MDy7=vc9YGpjmk!GLgI)Bkhpo(b&GR@UmP4vC6@!msLG> z7xWV_l`Ul)U0zH=GK=DVV8$^OoOT~8`DQCt1KSS6#i{)vV#rTD#`%=)+Cp5aeN>9b z>=IgX2f;gpYY5$J`#%#As1~&f>kodrgM!ya=~}cb^lwP}T4?cgrDF+2oLJ zId!)&pOmq8rLNwqKitZM$H(6*xH8_%!?Q^1FpD~Z4klxVtc}b8r$aomLAd?oxcmZo zJ@>Wkb|^b6LaZOhTxOR*^*ZgO71cpoUvVr z^!GHqJoXg~gHNBHPx$XYGZ#JyX!xrUV+S;v5O;bCS8^tN%<9f^zP`22)K zS^lbc)kG9}KW{GdaKY61YIGo)F4MGpSwHcT7^9JU-p<9|GIU!8`y2wXAiY~3FNv*4 zVWmQ#C4H3khVft`$g)Jd&pbtC+Rv!1#_yEj!Z9(2Bmyzp$nR_F2ad}P(pxtY8yUhk zn(N+FJ2I~I)GjWv4pf`}gh5>)!ryv_vh}fQ8}p;mnD@4O`a2!!2x#QO(3Sf&wPt%c zD$-X*_S?#qKeP-^W~;l*1r9E5qNq{&Gx27c*T&q#kiFzqDl#ot#}+0Bua#Ts$C{rHnEC=cO5a3B#LT)iaU=n3w%=T$ssj`s-_D@I7~7+@m5*wSGR@UlM8`(z>eEBs5lyrt(n>_ zF6thw!7pnIdo-`P`WxB2xFo&2ehYgNXjk)%{Dotc^F>Va?xsq{HmJPM1)z@wuiYkAo!CgKp>o_?M^za5NL91@R9@eV zh|8MEpy@1rR^4S}yz1z^Vk{@$ajQhXIMFzN-satX_Hyy1n3TtF$U=E(Cm>{_Op`mIwFJfc;y>+Z;J|e-!z4+ng z1GPJYyVwA?<;0!)q#wfNW$?E*@9RVWCo+RCZhkRQK_(hV-9kcUGic{{aAc{qNR{P^ zi9;~j1hJhy_OR8{ZJjBvdE=5^4d10A<-u*)XUM5ph(j_Fe{uci%!K`PLt15l4WEd; zH{ud@tQuM69gYX=`>zgqDGv5Si;Pp$h%OU%++O#hYHnAew3^M{ViOtQggn`Z)4{n1 zBSnXX7k~T+1(V}K^^)?x7~7(qgCgV(RG=O$k5@;As$K?5^+gK7)G6~U=rr9YwRS=+ z(K#FqaTtH^ocMPk?>Cg=k2ZIgbh8*A-2+^f_P9}N-^>oEHmotp0b0xQSaqKLMD<%!5fUub5T(yrs_LS2q12AmXT*iko*v?dY zc(e1!VLNfu1;~ifeG%N{uj4%)J5L0JtrY7j0x*(_ws}!d*LAXDmd!$UCnUO*R|Ao|M8&n z)+XdV+Pe`sAydsRLxwImJpu;aq&-rd*$ULgwF@&2iucO~$E{h*ha-B{eldFSg?4B^&e{oZb6vi>p_5&>wE=}a!!qaU9d98RKk z61YU%`n>U^zZxkDN^?BX6Iw;=dSzhr$NX2%T$G!gQ=-Eclm}-uU)?XX5A|1d?T8O` zhduQg`CNvSedC8p&C&0-C%KA60B3CR>sByR`Cd7z8ik-i0Gc#pgR#VnIz*H?S6%*Knu=xAi_+GhqXT-!;scCQ;CUNNTAm9wAx zOhr}*Gop$??t9jomCvPSw|tRg_<-D5#=khl*HSeqq;<%%L^oc&tJi;>8r(?XY@lO{ zL0b0f{wJY~6_fWn?UfS?Eirp5{gRy?_miIQZC3PPT_aYROnpQmR$lh=9Qz>qD(^dm zo7??+?AqtdvIER`RoRiLX6$cPOj_u+T^%juuq`juafN1RMwL9d+txKj;lf4@4ta;s z(XI0q9);c|pRzwai4d+RZQL1ovuNM@gS2WqZ=*@_Wlw$!Y^V1fT8B3Pv!ijUDvmjz%`s`aQNnHyd=aDrZS%e#%{p(DaM8KRxIq4L^;HVo?5 zGn@5JI){as6%)Cq8}kFwI}!sDiH%jh2c%IK^@jI96{yEG4^=e>w~v{|-HM-CSSid!;h^OSDvj z4=v&*jY;=|a#0Pa-8;{zk_Yq1y%@AlwA@D5Cdchnd*GxU6#_Am_wh$&AH{MV z%y)ev>(zYJUk(1j^+_C(#Y-(0-MD2Xvv~IS1K4pelM(<39M!4B0nlL1Az*!Gf)A1t z%pVhHN)j?`0$M=$D`6Js4Nx~xlBppl4!|Vj$bJxv^~a=0@Wo_MAP7RCD2Nj^iKBfX z9Pl5zRfHzGd!EDn;Yh9@!~b;}y~E{zm)AFMsmk}J*b%5+t%#cqN)UnDzmx{Az0xrT3BUSE@PDv`PM6e^8Mjk z@(AN(`Z##qJ_j`Dq$s3h%ne0P=)O1;s9$1xOr#cn1w@dyb~f32GFztYz(|tR6Ior{ zGxG^xkkZw;m#*vx-<7~-jo1t*UjoVKqA#Cr>W6V~sX{YE61}$KRkYsa6x8hu?H`DV z{tB)vaRT}GiJjqeH)`F3DyRMhn>P+aaqL+(E%%@?dMYxahM*tivQ+pMm}T(VIHc5Z zXF1!axs9o(CQ2(G6}q?o_%q-7)Vt^sFnZYFoS}-?K%EAdy+FJBPEa0@)In`-e6~a6 z1(;#Zc3cf7X0B?$pRt1~k-RSe#^QkaP;xgqsk%Vs@Ogc*vAEQEO%wz>ZaWE5s4%qL zB?&PMEnz|v=nosLU&;fAU`caY$}EtIu`iP}z66Xas$43oMcvUr#BY?-J6ifcV28_+ z?a52}tv+@8dENuXjhflMKR$y%H)LD-@->VZ^4ajjL$k6K6J2lbvDixdDwRRH%Qf%a zt@4inn3wa(-xJYFPpUHQqpok~755^ZICkpJo zFBe82c0pIU>%wRr(_oH=T3k9bjP(QvjZ80_-=YCJ%Ark0V=`_PGT(Vn-6xnFW#N@E zPN&hg>S47CW>`fE)aJip==QqNqJIHlv9=fCfK=Kc-ToDI9)+vvUjLQ*dC11Gzh4OI zhbeLCvSoeba#%+6yM#A>a1#tZu))WSA51xniA-A7RJq>)FC|sVwe8kgdk+lynLa-5 zDx(T=*jx7M&gh(*DZ(pZZ0-u$?qM__R-8}UMN&7Qz}P}t+eCaBxv45^dY6xmA!fhI$?;*S z_r15!|9Rlg0jQNvgqcGRlR={jOQ}$xIVF1{zMM@oh-dNWaNYc}kE$M2v1j+jhk@07(P3{0NAiUw5QzC)@1biSc>zQR5H)WAto;5-h%a=W51lE_-E^g4-K3|*ltAFdu zUJpO@!xiE;w7a-B{PY-`WMf@VZWVWN0`0-}8FST)0#do>-(x6_3;@CmyT5 zU2f5_|2+}=tBL+YJ zx)nbxBZ2-)2mfgk-~*lx>Sj5mevk%qc-=d z`|UT{UsTKb(%Ln3E>y>s4ejfk2=Bi?{8HTpOwgd7ZFK2{)wOH)9=-eVS87zZmi?u> z)jzMdcbJP8E2@PrzM&ZlmfGUa3jz>;Ku`!Eyg``>#sL8c7*D`DA3JI0^IG=CN7}Gy ztNnPf6OXT~p?%xyw3CmM^<}W(56`kC@yu!`Xkd?4vUYW?^R(7$-G0^m#J&p8&s%Js$=1`E_{CJzcuCQ#agp=lS-8;uJfy( zrm=&%*pDLXJ9M(X`*E$^-Wk=Z+K)|h^4wwLC!7Ev00CnNAiTy*6$6C;1R#)`K>ra> z*gLv+wrgUa@wIlDtw)nRHE)TQ%pM6Y2tWV=5cn?vgqKu+00balC;{tf3)Y|iwZ52^ z_4;=8uWH|OWcD!$LqlWO5P$##TqS_;x{8y=AOHafB#*!?o$t55%+|4GBm0QL`i)yO zXv{QKIp!!0?A|hY1ED7fKmY;(CxGw<{6G3~X<#>;4SN6p002ovPDHLkV1l(4&i4QS diff --git a/src/python/evaluation/plots/plotters/__init__.py b/src/python/evaluation/plots/plotters/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/python/evaluation/plots/plotters/diffs_plotters.py b/src/python/evaluation/plots/plotters/diffs_plotters.py deleted file mode 100644 index 0ff94b64..00000000 --- a/src/python/evaluation/plots/plotters/diffs_plotters.py +++ /dev/null @@ -1,161 +0,0 @@ -from statistics import median -from typing import Any, Callable, Dict, Optional - -import pandas as pd -import plotly.graph_objects as go -from src.python.evaluation.inspectors.common.statistics import IssuesStatistics, PenaltyInfluenceStatistics -from src.python.evaluation.plots.common import plotly_consts -from src.python.evaluation.plots.common.utils import create_bar_plot, create_box_plot -from src.python.review.inspectors.issue import IssueType - - -def _get_dataframe_from_dict( - data_dict: Dict[Any, Any], - key_name: str, - value_name: str, - key_mapper: Callable = lambda x: x, - value_mapper: Callable = lambda y: y, -): - """ - Converts 'data_dict' to a dataframe consisting of two columns: 'key_name', 'value_name'. - 'key_name' contains all keys of 'data_dict', 'value_name' contains all corresponding - values of 'data_dict'. With the functions 'key_mapper' and 'value_mapper' you can - additionally convert keys and values respectively. - """ - converted_dict = { - key_name: list(map(key_mapper, data_dict.keys())), - value_name: list(map(value_mapper, data_dict.values())), - } - - return pd.DataFrame.from_dict(converted_dict) - - -def _extract_stats_from_issues_statistics( - statistics: IssuesStatistics, - limit: int, - only_unique: bool, -) -> Dict[IssueType, int]: - categorized_statistics = statistics.get_short_categorized_statistics() - - # If you want to get only unique issues, you should use position 0 of the tuple, otherwise 1. - position = int(not only_unique) - - return { - issue_type: stat[position] for issue_type, stat in categorized_statistics.items() if stat[position] >= limit - } - - -def get_unique_issues_by_category( - statistics: IssuesStatistics, - x_axis_name: str = 'Categories', - y_axis_name: str = 'Number of unique issues', - limit: int = 0, - margin: Optional[plotly_consts.MARGIN] = None, - sort_order: Optional[plotly_consts.SORT_ORDER] = None, - color: Optional[plotly_consts.COLOR] = None, -) -> go.Figure: - filtered_stats = _extract_stats_from_issues_statistics(statistics, limit, only_unique=True) - - df = _get_dataframe_from_dict( - filtered_stats, - key_name=x_axis_name, - value_name=y_axis_name, - key_mapper=lambda issue_type: issue_type.name, - ) - - return create_bar_plot( - df, - x_axis=x_axis_name, - y_axis=y_axis_name, - margin=margin, - sort_order=sort_order, - color=color, - ) - - -def get_issues_by_category( - statistics: IssuesStatistics, - x_axis_name: str = 'Categories', - y_axis_name: str = 'Number of issues', - limit: int = 0, - margin: Optional[plotly_consts.MARGIN] = None, - sort_order: Optional[plotly_consts.SORT_ORDER] = None, - color: Optional[plotly_consts.COLOR] = None, -) -> go.Figure: - filtered_stats = _extract_stats_from_issues_statistics(statistics, limit, only_unique=False) - - df = _get_dataframe_from_dict( - filtered_stats, - key_name=x_axis_name, - value_name=y_axis_name, - key_mapper=lambda issue_type: issue_type.name, - ) - - return create_bar_plot( - df, - x_axis=x_axis_name, - y_axis=y_axis_name, - margin=margin, - sort_order=sort_order, - color=color, - ) - - -def get_median_penalty_influence_by_category( - statistics: PenaltyInfluenceStatistics, - x_axis_name: str = 'Categories', - y_axis_name: str = 'Penalty influence (%)', - limit: int = 0, - margin: Optional[plotly_consts.MARGIN] = None, - sort_order: Optional[plotly_consts.SORT_ORDER] = None, - color: Optional[plotly_consts.COLOR] = None, -) -> go.Figure: - stat = statistics.stat - filtered_stats = {issue_type: influence for issue_type, influence in stat.items() if median(influence) >= limit} - - df = _get_dataframe_from_dict( - filtered_stats, - key_name=x_axis_name, - value_name=y_axis_name, - key_mapper=lambda issue_type: issue_type.name, - value_mapper=lambda influence: median(influence), - ) - - return create_bar_plot( - df, - x_axis=x_axis_name, - y_axis=y_axis_name, - margin=margin, - sort_order=sort_order, - color=color, - ) - - -def get_penalty_influence_distribution( - statistics: PenaltyInfluenceStatistics, - x_axis_name: str = 'Categories', - y_axis_name: str = 'Penalty influence (%)', - limit: int = 0, - margin: Optional[plotly_consts.MARGIN] = None, - sort_order: Optional[plotly_consts.SORT_ORDER] = None, - color: Optional[plotly_consts.COLOR] = None, -): - stat = statistics.stat - filtered_stats = {issue_type: influence for issue_type, influence in stat.items() if len(influence) >= limit} - - df = _get_dataframe_from_dict( - filtered_stats, - key_name=x_axis_name, - value_name=y_axis_name, - key_mapper=lambda issue_type: issue_type.name, - ) - df = df.explode(y_axis_name) - - return create_box_plot( - df, - x_axis=x_axis_name, - y_axis=y_axis_name, - margin=margin, - sort_order=sort_order, - color=color, - ) diff --git a/src/python/evaluation/plots/plotters/raw_issues_statistics_plotters.py b/src/python/evaluation/plots/plotters/raw_issues_statistics_plotters.py deleted file mode 100644 index 4e316e06..00000000 --- a/src/python/evaluation/plots/plotters/raw_issues_statistics_plotters.py +++ /dev/null @@ -1,234 +0,0 @@ -import logging -from dataclasses import dataclass -from enum import Enum, unique -from typing import Callable, Dict, Optional, Tuple - -import numpy as np -import pandas as pd -import plotly.graph_objects as go -from src.python.evaluation.issues_statistics.get_raw_issues_statistics import VALUE -from src.python.evaluation.plots.common.utils import ( - COLOR, - COLORWAY, - create_box_plot, - create_box_trace, - create_histogram, - create_line_chart, - create_scatter_trace, - LINES, - MARGIN, - update_figure, -) - -logger = logging.getLogger(__name__) - - -@unique -class PlotTypes(Enum): - LINE_CHART = 'line_chart' - HISTOGRAM = 'histogram' - BOX_PLOT = 'box_plot' - - def to_plotter_function(self) -> Callable[[Dict[str, pd.DataFrame], 'PlotConfig', bool], Dict[str, go.Figure]]: - type_to_function = { - PlotTypes.LINE_CHART: plot_line_chart, - PlotTypes.HISTOGRAM: plot_histogram, - PlotTypes.BOX_PLOT: plot_box_plot, - } - - return type_to_function[self] - - -@dataclass -class PlotConfig: - column: str - type: PlotTypes - x_axis_name: Optional[str] = None - y_axis_name: Optional[str] = None - margin: MARGIN = None - color: COLOR = None - colorway: COLORWAY = None - boundaries: LINES = None - range_of_values: Optional[range] = None - n_bins: Optional[int] = None - - -def prepare_stats( - stats: pd.DataFrame, - column: str, - range_of_values: Optional[range], - x_axis_name: str, - y_axis_name: str, -) -> pd.DataFrame: - result_df = stats[[VALUE, column]] - - if range_of_values is not None: - result_df = result_df[result_df[VALUE].isin(range_of_values)] - - result_df.set_index(VALUE, inplace=True) - - # Trim trailing zeros - result_df = result_df.apply(lambda column: np.trim_zeros(column, trim='b')).dropna() - - # Fill in the missing intermediate values with zeros - min_index, max_index = result_df.index.min(), result_df.index.max() - if pd.isna(min_index) or pd.isna(max_index): - logger.warning(f'{column}: no data') - else: - result_df = result_df.reindex(range(min_index, max_index + 1), fill_value=0) - - result_df.reset_index(inplace=True) - - return result_df.rename(columns={VALUE: x_axis_name, column: y_axis_name}) - - -def _get_axis_names( - *, - x_axis_name: Optional[str], - y_axis_name: Optional[str], - default_x_axis_name: str, - default_y_axis_name: str, -) -> Tuple[str, str]: - new_x_axis_name = default_x_axis_name - if x_axis_name is not None: - new_x_axis_name = x_axis_name - - new_y_axis_name = default_y_axis_name - if y_axis_name is not None: - new_y_axis_name = y_axis_name - - return new_x_axis_name, new_y_axis_name - - -def plot_line_chart( - stats_by_lang: Dict[str, pd.DataFrame], - config: PlotConfig, - group_stats: bool, -) -> Dict[str, go.Figure]: - x_axis_name, y_axis_name = _get_axis_names( - x_axis_name=config.x_axis_name, - y_axis_name=config.y_axis_name, - default_x_axis_name='Value', - default_y_axis_name='Quantity', - ) - - if not group_stats: - plots = {} - for lang, stats in stats_by_lang.items(): - stats = prepare_stats(stats, config.column, config.range_of_values, x_axis_name, y_axis_name) - plots[lang] = create_line_chart( - stats, - x_axis=x_axis_name, - y_axis=y_axis_name, - color=config.color, - margin=config.margin, - vertical_lines=config.boundaries, - ) - return plots - - plot = go.Figure() - for lang, stats in stats_by_lang.items(): - stats = prepare_stats(stats, config.column, config.range_of_values, x_axis_name, y_axis_name) - trace = create_scatter_trace(stats, x_column=x_axis_name, y_column=y_axis_name) - trace.name = lang - plot.add_trace(trace) - - update_figure( - plot, - margin=config.margin, - vertical_lines=config.boundaries, - x_axis_name=x_axis_name, - y_axis_name=y_axis_name, - colorway=config.colorway, - ) - - return {'grouped': plot} - - -def plot_histogram( - stats_by_lang: Dict[str, pd.DataFrame], - config: PlotConfig, - group_stats: bool, -) -> Dict[str, go.Figure]: - x_axis_name, y_axis_name = _get_axis_names( - x_axis_name=config.x_axis_name, - y_axis_name=config.y_axis_name, - default_x_axis_name='Value', - default_y_axis_name='Quantity', - ) - - if group_stats: - logger.info(f'{config.column}: the histogram cannot be grouped.') - - plots = {} - for lang, stats in stats_by_lang.items(): - stats = prepare_stats(stats, config.column, config.range_of_values, x_axis_name, y_axis_name) - plots[lang] = create_histogram( - stats, - x_axis_name, - y_axis_name, - margin=config.margin, - color=config.color, - n_bins=config.n_bins, - vertical_lines=config.boundaries, - ) - - return plots - - -def _get_values_df(stats: pd.DataFrame, config: PlotConfig, x_axis_name: str, y_axis_name: str): - values = [] - stats.apply(lambda row: values.extend([row[VALUE]] * row[config.column]), axis=1) - - if config.range_of_values is not None: - values = [elem for elem in values if elem in config.range_of_values] - - return pd.DataFrame.from_dict({x_axis_name: config.column, y_axis_name: values}) - - -def plot_box_plot( - stats_by_lang: Dict[str, pd.DataFrame], - config: PlotConfig, - group_stats: bool, -) -> Dict[str, go.Figure]: - x_axis_name, y_axis_name = _get_axis_names( - x_axis_name=config.x_axis_name, - y_axis_name=config.y_axis_name, - default_x_axis_name='Category', - default_y_axis_name='Values', - ) - - if not group_stats: - plots = {} - for lang, stats in stats_by_lang.items(): - values_df = _get_values_df(stats, config, x_axis_name, y_axis_name) - - plots[lang] = create_box_plot( - values_df, - x_axis=x_axis_name, - y_axis=y_axis_name, - color=config.color, - margin=config.margin, - horizontal_lines=config.boundaries, - ) - return plots - - plot = go.Figure() - for lang, stats in stats_by_lang.items(): - values_df = _get_values_df(stats, config, x_axis_name, y_axis_name) - - trace = create_box_trace(values_df, y_column=y_axis_name) - trace.name = lang - - plot.add_trace(trace) - - update_figure( - plot, - margin=config.margin, - horizontal_lines=config.boundaries, - x_axis_name=x_axis_name, - y_axis_name=y_axis_name, - colorway=config.colorway, - ) - - return {'grouped': plot} diff --git a/src/python/evaluation/plots/raw_issues_statistics_plotter.py b/src/python/evaluation/plots/raw_issues_statistics_plotter.py deleted file mode 100644 index 6d8295ff..00000000 --- a/src/python/evaluation/plots/raw_issues_statistics_plotter.py +++ /dev/null @@ -1,150 +0,0 @@ -import argparse -import logging -import sys -from enum import Enum, unique -from pathlib import Path -from typing import Dict, List, Optional - -sys.path.append('../../../..') - -import plotly.graph_objects as go -from src.python.evaluation.common.pandas_util import get_solutions_df_by_file_path -from src.python.evaluation.plots.common import plotly_consts -from src.python.evaluation.plots.common.utils import ( - get_supported_extensions, - save_plot, -) -from src.python.evaluation.plots.plotters.raw_issues_statistics_plotters import PlotConfig, PlotTypes -from src.python.review.common.file_system import Extension, parse_yaml - - -@unique -class ConfigFields(Enum): - X_AXIS_NAME = 'x_axis_name' - Y_AXIS_NAME = 'y_axis_name' - MARGIN = 'margin' - COLOR = 'color' - COLORWAY = 'colorway' - BOUNDARIES = 'boundaries' - COMMON = 'common' - STATS = 'stats' - RANGE_OF_VALUES = 'range_of_values' - N_BINS = 'n_bins' - - -X_AXIS_NAME = ConfigFields.X_AXIS_NAME.value -Y_AXIS_NAME = ConfigFields.Y_AXIS_NAME.value -MARGIN = ConfigFields.MARGIN.value -COLOR = ConfigFields.COLOR.value -COLORWAY = ConfigFields.COLORWAY.value -BOUNDARIES = ConfigFields.BOUNDARIES.value -COMMON = ConfigFields.COMMON.value -STATS = ConfigFields.STATS.value -RANGE_OF_VALUES = ConfigFields.RANGE_OF_VALUES.value -N_BINS = ConfigFields.N_BINS.value - - -def configure_arguments(parser: argparse.ArgumentParser) -> None: - parser.add_argument( - 'config_path', - type=lambda value: Path(value).absolute(), - help='Path to the yaml file containing information about the graphs to be plotted.', - ) - - parser.add_argument( - 'save_dir', - type=lambda value: Path(value).absolute(), - help='The directory where the plotted charts will be saved.', - ) - - parser.add_argument( - '--file-extension', - type=str, - default=Extension.SVG.value, - choices=get_supported_extensions(), - help='Allows you to select the extension of output files.', - ) - - parser.add_argument( - '--group-stats', - action='store_true', - help='If present, there will be several languages on the charts at once.', - ) - - -def _get_plot_config( - column_name: str, - plot_type: str, - plot_config: Optional[Dict], - common: Optional[Dict], -) -> PlotConfig: - params = {'column': column_name, 'type': PlotTypes(plot_type.lower())} - - if common is not None: - params.update(common) - - if plot_config is not None: - params.update(plot_config) - - if MARGIN in params: - margin_value = params.get(MARGIN).upper() - params[MARGIN] = plotly_consts.MARGIN[margin_value] - - if COLOR in params: - color_value = params.get(COLOR).upper() - params[COLOR] = plotly_consts.COLOR[color_value] - - if RANGE_OF_VALUES in params: - params[RANGE_OF_VALUES] = range(*params[RANGE_OF_VALUES]) - - if COLORWAY in params: - colorway_value = params.get(COLORWAY).upper() - params[COLORWAY] = plotly_consts.COLORWAY[colorway_value] - - return PlotConfig(**params) - - -def get_plot_configs(column_name: str, column_config: Dict) -> List[PlotConfig]: - common = column_config.pop(COMMON, None) - - plot_configs = [] - for plot_type, plot_config in column_config.items(): - plot_configs.append(_get_plot_config(column_name, plot_type, plot_config, common)) - - return plot_configs - - -def _save_plots(plots: Dict[str, go.Figure], save_dir: Path, extension: Extension, column: str, plot_type: str) -> None: - for output_name, plot in plots.items(): - subdir = save_dir / column - save_plot(plot, subdir, plot_name=f'{column}_{plot_type}_{output_name}', extension=extension) - - -def plot_and_save(config: Dict, save_dir: Path, extension: Extension, group_stats: bool) -> None: - stats_by_lang = { - lang: get_solutions_df_by_file_path(Path(lang_stats)) for lang, lang_stats in config.pop(STATS).items() - } - - for column_name, column_config in config.items(): - plot_configs = get_plot_configs(column_name, column_config) - for plot_config in plot_configs: - plotter_function = plot_config.type.to_plotter_function() - plots = plotter_function(stats_by_lang, plot_config, group_stats) - _save_plots(plots, save_dir, extension, plot_config.column, plot_config.type.value) - - -def main(): - parser = argparse.ArgumentParser() - configure_arguments(parser) - args = parser.parse_args() - - logging.basicConfig(level=logging.INFO) - - extension = Extension(args.file_extension) - config = parse_yaml(args.config_path) - - plot_and_save(config, args.save_dir, extension, args.group_stats) - - -if __name__ == "__main__": - main() diff --git a/src/python/evaluation/qodana/README.md b/src/python/evaluation/qodana/README.md deleted file mode 100644 index 0e81af0f..00000000 --- a/src/python/evaluation/qodana/README.md +++ /dev/null @@ -1,311 +0,0 @@ -# Dataset labelling -This script allows you to label a dataset using the found [Qodana](https://github.com/JetBrains/Qodana) inspections. - -The dataset must contain at least three columns: `id`, `code` and `lang`, where `id` is a unique solution number, `lang` is the language in which the code is written in the `code` column. The `lang` must belong to one of the following values: `java7`, `java8`, `java9`, `java11`, `python3`, `kotlin`. If `lang` is not equal to any of the values, the row will be skipped. - -The dataset must have the format `csv`. The labeled dataset is also in `csv` format, with a new column `inspections` added, which contains a list of all found inspections. - -# Usage -Run the [dataset_labeling.py](dataset_labeling.py) with the arguments from command line. - -### Required arguments - -`dataset_path` — path to dataset. - -### Optional arguments -| Argument | Description | -|-|-| -| **‑c**, **‑‑config** | Path to qodana.yaml. If the path is not specified, Qodana will start without a configuration file. | -| **‑l**, **‑‑limit** | Allows you to read only the specified number of first rows from the dataset. If no limit is specified, the whole dataset will be processed. | -| **‑s**, **‑‑chunk‑size** | The number of files that Qodana will process at a time. Default is `5000`. | -| **‑o**, **‑‑output‑path** | The path where the labeled dataset will be saved. If not specified, the original dataset will be overwritten. | - ---- - -# Preprocessing - -The model that imitates Qodana analysis gets input from a dataset in a special format. -This module allows preparing datasets that were graded by [dataset_labeling.py](dataset_labeling.py) script. - -Data processing consists of several stages: -- union several `csv` files that were graded by [dataset_labeling.py](dataset_labeling.py) script - and filter inspections list if it is necessary; -- get all unique inspections from the dataset; -- convert `csv` file into a special format. - -## Filter inspections - -This stage allow you to union several `csv` files that were graded by [dataset_labeling.py](dataset_labeling.py) script - and filter inspections list if it is necessary. - -Please, note that your all input files must be graded by [dataset_labeling.py](dataset_labeling.py) script -and have `inspections` column. - -Output file is a new `csv` file with the all columns from the input files. - -#### Usage - -Run the [filter_inspections.py](filter_inspections.py) with the arguments from command line. - -Required arguments: - -`dataset_folder` — path to a folder with csv files graded by Qodana. Each file must have `inspections` column. - -Optional arguments: -Argument | Description ---- | --- -|**‑i**, **‑‑inspections**| Set of inspections ids to exclude from the dataset separated by comma. By default all inspections remain. | - -The resulting file will be stored in the `dataset_folder`. - -___ - -## Get all unique inspections - -This stage allow you to get all unique inspections from a `csv` file graded by Qodana. -Please, note that your input file must be graded by [dataset_labeling.py](dataset_labeling.py) script -and has `inspections` column. - -Output file is a new `csv` file with four columns: `id`, `inspection_id`, `count_all`, `count_uniq`. -`id` is unique number for each inspection, minimal value is 1. -`inspection_id` is unique Qoadana id for each inspection. -`count_all` count all fragments where was this inspection (with duplicates). -`count_uniq` count all fragments where was this inspection (without duplicates). - -#### Usage - -Run the [get_unique_inspectors.py](get_unique_inspectors.py) with the arguments from command line. - -Required arguments: - -`solutions_file_path` — path to csv-file with code samples graded by [dataset_labeling.py](dataset_labeling.py) script. - -Optional arguments: -Argument | Description ---- | --- -|**‑‑uniq**| To count all fragments for each inspection where was this inspection (without duplicates). By default it disabled. | - -The resulting file will be stored in the same folder as the input file. - -An example of the output file: - -```json -id | inspection_id | count_all | count_unique ------|---------------------|--------------|-------------- -1 | SystemOutErr | 5 | 2 -2 | ConstantExpression | 1 | 1 -``` - -___ - -#### Convert `csv` file into a special format - -This block describes what format can be converted csv-file with code samples -graded by [dataset_labeling.py](dataset_labeling.py) script. - -We have two different formats: -- fragment to inspections list; -- fragment to inspections list with positions. - - -#### Fragment to inspections list - -This data representation match code fragments to a list with ids of inspections. - -Please, note that your input file must be graded by [dataset_labeling.py](dataset_labeling.py) script -and has `inspections` column. - -Output file is a new `csv` file with a new `inspections` column with list with ids of inspections. -If the list of inspections for the fragment is empty, then write 0. - -#### Usage - -Run the [fragment_to_inspections_list.py](fragment_to_inspections_list.py) with the arguments from command line. - -Required arguments: - -- `solutions_file_path` — path to csv-file with code samples graded by [dataset_labeling.py](dataset_labeling.py) script, -- `inspections_path` — path to csv-file with inspections list from the input file. You can get this file by [get_unique_inspectors.py](get_unique_inspectors.py) script. - -Optional arguments: -Argument | Description ---- | --- -|**‑‑remove‑duplicates**| Remove duplicates around inspections in each row. Default value is `False`. | - -The resulting file will be stored in the same folder as the input file. - -An example of the input file: - -```json -id | code | lang | inspections ------|-------------------|---------------|----------------- -2 | "// some code" | java11 | "{""issues"": []}" -3 | "// some code" | java11 | "{""issues"": [""{\"... \""problem_id\"": \""SystemOutErr\""}""]}" -0 | "// some code" | java11 | "{""issues"": [""{\"...\""problem_id\"": \""ConstantExpression\""}"",""{\"...\""problem_id\"": \""ConstantExpression\""}""]}" -1 | "// some code" | java11 | "{""issues"": []}" -``` - -with the inspections file: - -```json -id | inspection_id ------|------------------- -1 | SystemOutErr -2 | ConstantExpression -``` - -An example of the output file: - -```json -id | code | lang | inspections ------|-------------------|---------------|----------------- -2 | "// some code" | java11 | 0 -3 | "// some code" | java11 | 1 -0 | "// some code" | java11 | 2,2 -1 | "// some code" | java11 | 0 - -``` - ---- - -#### Fragment to inspections list with positions - -This data representation match each line in code fragments to a list with ids of inspections in this line. - -Please, note that your input file must be graded by [dataset_labeling.py](dataset_labeling.py) script -and has `inspections` column. - -Output file is a new `csv` file with a new `inspections` column with list with ids of inspections. -If the list of inspections for the fragment is empty, then write 0. -Note, that each line in code fragments in the new file is stored in a separate row. -All indents as well as blank lines are keeped. - -#### Usage - -Run the [fragment_to_inspections_list_line_by_line.py](fragment_to_inspections_list_line_by_line.py) with the arguments from command line. - -Required arguments: - -- `solutions_file_path` — path to csv-file with code samples graded by [dataset_labeling.py](dataset_labeling.py) script, -- `inspections_path` — path to csv-file with inspections list from the input file. You can get this file by [get_unique_inspectors.py](get_unique_inspectors.py) script. - -Optional arguments: -Argument | Description ---- | --- -|**‑‑remove‑duplicates**| Remove duplicates around inspections in each row. Default value is `False`. | - -The resulting file will be stored in the same folder as the input file. - -An example of the input file: - -```json -id | code | lang | inspections ------|-------------------|---------------|----------------- -2 | "// some code" | java11 | "{""issues"": []}" -3 | "// some code" | java11 | "{""issues"": [""{\"... \""problem_id\"": \""SystemOutErr\""}""]}" -0 | "// some code" | java11 | "{""issues"": [""{\"...\""problem_id\"": \""ConstantExpression\""}"",""{\"...\""problem_id\"": \""ConstantExpression\""}""]}" -1 | "// some code" | java11 | "{""issues"": []}" -``` - -with the inspections file: - -```json -id | inspection_id ------|------------------- -1 | SystemOutErr -2 | ConstantExpression -``` - -An example of the output file: - -```json -id | code | lang | inspections ------|----------------------------------------|---------------|----------------- -2 | "// first line from code with id 2" | java11 | 0 -2 | "// second line from code with id 2" | java11 | 0 -3 | "// first line from code with id 3" | java11 | 1 -3 | "// second line from code with id 3" | java11 | 0 -0 | "// first line from code with id 0" | java11 | 0 -0 | "// second line from code with id 0" | java11 | 2,2 -1 | "// first line from code with id 1" | java11 | 0 -1 | "// second line from code with id 1" | java11 | 0 - -``` - -# Postprocessing - -At this stage, you can convert the data received by the Qodana into the format of the Hyperstyle tool for -analysis and statistics gathering. - -## Convert Qodana inspections into Hyperstyle inspections - -This stage allows you to convert the `inspections` column from `csv` marked by Qodana into -`traceback` column with the Hyperstyle tool format. - -This stage includes: -- keep only unique code fragments in both datasets (Qodana and Hyperstyle); -- keep only fragments in both datasets that have same ids and same code fragments; -- add a `grade` column into Qodana dataset corresponding to the `grade` column from Hyperstyle dataset; -- add a `traceback` column in the Hyperstyle format into Qodana dataset with inspection from the `inspections` column. - -Please, note that your Qodana input file must be graded by [dataset_labeling.py](dataset_labeling.py) script -and have `inspections` column. Your Hyperstyle input file must be graded by [evaluation_run_tool.py](../evaluation_run_tool.py) script -and have `traceback` and `grade` columns. - -Output files is two new `csv` files. - -#### Usage - -Run the [convert_to_hyperstyle_inspections.py](convert_to_hyperstyle_inspections.py) with the arguments from command line. - -Required arguments: - -- `solutions_file_path_hyperstyle` — path to a `csv` file labelled by Hyperstyle; -- `solutions_file_path_qodana` — path to a `csv` file labelled by Qodana. - -Optional arguments: -Argument | Description ---- | --- -|**‑i**, **‑‑issues-to-keep**| Set of issues ids to keep in the dataset separated by comma. By default all issues are deleted. | - -The Hyperstyle resulting file will be stored in the same folder with `solutions_file_path_hyperstyle`. -The Qodana resulting file will be stored in the same folder with `solutions_file_path_qodana`. - -An example of the Qodana inspections before and after this processing: - -1. Before: - -```json -{ - "issues": [ - { - "fragment_id": 0, - "line": 8, - "offset": 8, - "length": 10, - "highlighted_element": "System.out", - "description": "Uses of System.out should probably be replaced with more robust logging #loc", - "problem_id": "SystemOutErr" - } - ] -} -``` - -2. After: - -```json -{ - "issues": [ - { - "code": "SystemOutErr", - "text": "Uses of System.out should probably be replaced with more robust logging #loc", - "line": "", - "line_number": 8, - "column_number": 8, - "category": "INFO", - "influence_on_penalty": 0 - } - ] -} -``` -___ diff --git a/src/python/evaluation/qodana/__init__.py b/src/python/evaluation/qodana/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/python/evaluation/qodana/convert_to_hyperstyle_inspections.py b/src/python/evaluation/qodana/convert_to_hyperstyle_inspections.py deleted file mode 100644 index 5d7530a3..00000000 --- a/src/python/evaluation/qodana/convert_to_hyperstyle_inspections.py +++ /dev/null @@ -1,123 +0,0 @@ -import argparse -import json -from pathlib import Path -from typing import Iterable, Set - -import pandas as pd -from src.python.common.tool_arguments import RunToolArgument -from src.python.evaluation.common.pandas_util import ( - drop_duplicates, filter_df_by_iterable_value, get_solutions_df_by_file_path, write_df_to_file, -) -from src.python.evaluation.common.util import ColumnName, parse_set_arg -from src.python.evaluation.qodana.util.issue_types import QODANA_CLASS_NAME_TO_ISSUE_TYPE -from src.python.evaluation.qodana.util.models import QodanaColumnName, QodanaIssue -from src.python.review.common.file_system import Extension, get_parent_folder -from src.python.review.inspectors.inspector_type import InspectorType -from src.python.review.inspectors.issue import BaseIssue, IssueType -from src.python.review.reviewers.utils.print_review import convert_issue_to_json - - -def configure_arguments(parser: argparse.ArgumentParser) -> None: - parser.add_argument(f'{RunToolArgument.SOLUTIONS_FILE_PATH.value.long_name}_hyperstyle', - type=lambda value: Path(value).absolute(), - help=f'{RunToolArgument.SOLUTIONS_FILE_PATH.value.description}' - f'\nAll code fragments from this file must be graded by hyperstyle tool' - f'(file contains traceback column)') - - parser.add_argument(f'{RunToolArgument.SOLUTIONS_FILE_PATH.value.long_name}_qodana', - type=lambda value: Path(value).absolute(), - help=f'{RunToolArgument.SOLUTIONS_FILE_PATH.value.description}' - f'\nAll code fragments from this file must be graded by qodana' - f'(file contains inspections column)') - - parser.add_argument('-i', '--issues-to-keep', - help='Set of issues to keep', - default='') - - -# Drop duplicates in the CODE column and delete rows that have ids from value_to_filter -# The new dataframe will be sorted by the ID column -def __preprocess_df(df: pd.DataFrame, ids_to_filter: Iterable) -> pd.DataFrame: - df = drop_duplicates(df) - df = filter_df_by_iterable_value(df, ColumnName.ID.value, ids_to_filter) - return df.sort_values(ColumnName.ID.value).set_index(ColumnName.ID.value, drop=False) - - -# Check if all code fragments with the same ids are equal -def __check_code_by_ids(qodana_df: pd.DataFrame, hyperstyle_df: pd.DataFrame) -> None: - assert qodana_df.shape[0] == hyperstyle_df.shape[0], ( - f'rows count {qodana_df.shape[0]} in the qodana df does not equal rows ' - f'count {hyperstyle_df.shape[0]} in the hyperstyle df' - ) - for i in range(0, qodana_df.shape[0]): - if qodana_df.iloc[i][ColumnName.CODE.value] != hyperstyle_df.iloc[i][ColumnName.CODE.value]: - raise ValueError(f'Code fragments in the {i}th row do not equal!') - - -# Convert qodana inspections output to hyperstyle output -# Note: keep only json field in the result -def __qodana_to_hyperstyle_output(qodana_output: str, issues_to_keep: Set[str]) -> str: - qodana_issues = QodanaIssue.parse_list_issues_from_json(qodana_output) - filtered_issues = filter(lambda issue: issue.problem_id in issues_to_keep, qodana_issues) - hyperstyle_issues = map(lambda issue: - BaseIssue(origin_class=issue.problem_id, - type=QODANA_CLASS_NAME_TO_ISSUE_TYPE.get(issue.problem_id, IssueType.INFO), - description=issue.description, - file_path=Path(), - line_no=issue.line, - column_no=issue.offset, - inspector_type=InspectorType.QODANA), - filtered_issues) - hyperstyle_json = {'issues': list(map(lambda issue: convert_issue_to_json(issue), hyperstyle_issues))} - - return json.dumps(hyperstyle_json) - - -# Resort all fields in the qodana dataframe according to the hyperstyle dataframe -# Add column with hyperstyle output (convert qodana output to hyperstyle output) -# Add grade column with grades from hyperstyle dataframe (to gather statistics by diffs_between_df.py script) -def __prepare_qodana_df(qodana_df: pd.DataFrame, hyperstyle_df: pd.DataFrame, - issues_to_keep: Set[str]) -> pd.DataFrame: - qodana_df = __preprocess_df(qodana_df, hyperstyle_df[ColumnName.ID.value]) - __check_code_by_ids(qodana_df, hyperstyle_df) - - qodana_df[ColumnName.TRACEBACK.value] = qodana_df.apply( - lambda row: __qodana_to_hyperstyle_output(row[QodanaColumnName.INSPECTIONS.value], issues_to_keep), axis=1) - - qodana_df[ColumnName.GRADE.value] = hyperstyle_df[ColumnName.GRADE.value] - return qodana_df - - -def __write_updated_df(old_df_path: Path, df: pd.DataFrame, name_prefix: str) -> None: - output_path = get_parent_folder(Path(old_df_path)) - write_df_to_file(df, output_path / f'{name_prefix}_updated{Extension.CSV.value}', Extension.CSV) - - -def __reassign_ids(df: pd.DataFrame) -> pd.DataFrame: - df = df.sort_values(ColumnName.CODE.value) - df[ColumnName.ID.value] = df.index - return df - - -def main() -> None: - parser = argparse.ArgumentParser() - configure_arguments(parser) - args = parser.parse_args() - - issues_to_keep = parse_set_arg(args.issues_to_keep) - - qodana_solutions_file_path = args.solutions_file_path_qodana - qodana_solutions_df = __reassign_ids(get_solutions_df_by_file_path(qodana_solutions_file_path)) - - hyperstyle_solutions_file_path = args.solutions_file_path_hyperstyle - hyperstyle_solutions_df = __reassign_ids(get_solutions_df_by_file_path(hyperstyle_solutions_file_path)) - hyperstyle_solutions_df = __preprocess_df(hyperstyle_solutions_df, qodana_solutions_df[ColumnName.ID.value]) - - qodana_solutions_df = __prepare_qodana_df(qodana_solutions_df, hyperstyle_solutions_df, issues_to_keep) - - __write_updated_df(qodana_solutions_file_path, qodana_solutions_df, 'qodana') - __write_updated_df(hyperstyle_solutions_file_path, hyperstyle_solutions_df, 'hyperstyle') - - -if __name__ == '__main__': - main() diff --git a/src/python/evaluation/qodana/dataset_labeling.py b/src/python/evaluation/qodana/dataset_labeling.py deleted file mode 100644 index f11de467..00000000 --- a/src/python/evaluation/qodana/dataset_labeling.py +++ /dev/null @@ -1,280 +0,0 @@ -import json -import logging -import os -import re -import sys -import traceback -from argparse import ArgumentParser, Namespace -from collections import defaultdict -from math import ceil -from pathlib import Path -from typing import Dict, List, Optional - -sys.path.append('../../../..') - -import numpy as np -import pandas as pd -from src.python.evaluation.common.csv_util import write_dataframe_to_csv -from src.python.evaluation.common.util import ColumnName -from src.python.evaluation.qodana.util.models import QodanaColumnName, QodanaIssue -from src.python.evaluation.qodana.util.util import to_json -from src.python.review.application_config import LanguageVersion -from src.python.review.common.file_system import ( - copy_directory, - copy_file, - create_file, - Extension, - get_all_file_system_items, - get_content_from_file, - get_name_from_path, - get_parent_folder, - match_condition, - remove_directory, -) -from src.python.review.common.subprocess_runner import run_and_wait -from src.python.review.run_tool import positive_int - -logger = logging.getLogger(__name__) -logging.basicConfig(level=logging.INFO) - -TEMPLATE_FOLDER = Path(__file__).parents[3] / 'resources' / 'evaluation' / 'qodana' / 'project_templates' - - -def configure_arguments(parser: ArgumentParser) -> None: - parser.add_argument( - 'dataset_path', - type=lambda value: Path(value).absolute(), - help=f"Dataset path. The dataset must contain at least three columns: '{ColumnName.ID.value}', " - f"'{ColumnName.CODE.value}' and '{ColumnName.LANG.value}', where '{ColumnName.ID.value}' is a unique " - f"solution number, '{ColumnName.LANG.value}' is the language in which the code is written in the " - f"'{ColumnName.CODE.value}' column. The '{ColumnName.LANG.value}' must belong to one of the following " - f"values: {', '.join(LanguageVersion.values())}. " - f"If '{ColumnName.LANG.value}' is not equal to any of the values, the row will be skipped.", - ) - - parser.add_argument('-c', '--config', type=lambda value: Path(value).absolute(), help='Path to qodana.yaml') - - parser.add_argument( - '-l', - '--limit', - type=positive_int, - help='Allows you to read only the specified number of first rows from the dataset.', - ) - - parser.add_argument( - '-s', - '--chunk-size', - type=positive_int, - help='The number of files that qodana will process at a time.', - default=5000, - ) - - parser.add_argument( - '-o', - '--output-path', - type=lambda value: Path(value).absolute(), - help='The path where the labeled dataset will be saved. ' - 'If not specified, the labeled dataset will be saved next to the original one.', - ) - - -class DatasetLabel: - """ - DatasetLabel allows you to label a dataset using the found Qodana inspections. - Accepts dataset_path, config, limit, chunk_size and output_path. - """ - - dataset_path: Path - config: Optional[Path] - limit: Optional[int] - chunk_size: Optional[int] - inspection_to_id: Dict[str, int] - output_path: Path - - def __init__(self, args: Namespace): - self.dataset_path = args.dataset_path - self.config = args.config - self.limit = args.limit - self.chunk_size = args.chunk_size - - self.output_path = args.output_path - if self.output_path is None: - output_dir = get_parent_folder(self.dataset_path) - dataset_name = get_name_from_path(self.dataset_path) - self.output_path = output_dir / f'labeled_{dataset_name}' - - def label(self) -> None: - """ - Runs Qodana on each row of the dataset and writes the found inspections in the 'inspections' column. - """ - dataset = pd.read_csv(self.dataset_path, nrows=self.limit) - - group_by_lang = dataset.groupby(ColumnName.LANG.value) - unique_languages = dataset[ColumnName.LANG.value].unique() - - logger.info(f'Unique languages: {unique_languages}') - - groups = [] - for language in unique_languages: - lang_group = group_by_lang.get_group(language) - - if language in LanguageVersion.values(): - # TODO: languages need implementation - try: - logger.info(f'Processing the language: {language}') - groups.append(self._label_language(lang_group, LanguageVersion(language))) - except NotImplementedError: - # If we find a language that is in the LanguageVersion, - # but is not supported in this script, we should skip this fragment. - logger.warning(f'{language} needs implementation') - groups.append(lang_group) - else: - logger.warning(f'Unknown language: {language}') - groups.append(lang_group) - - logger.info('Dataset processing finished') - - dataset = pd.concat(groups) - - logger.info('Writing the dataset to a file.') - write_dataframe_to_csv(self.output_path, dataset) - - def _label_language(self, df: pd.DataFrame, language: LanguageVersion) -> pd.DataFrame: - number_of_chunks = 1 - if self.chunk_size is not None: - number_of_chunks = ceil(df.shape[0] / self.chunk_size) - - chunks = np.array_split(df, number_of_chunks) - labeled_chunks = [] - # Todo: run this in parallel - for index, chunk in enumerate(chunks): - logger.info(f'Processing chunk: {index + 1} / {number_of_chunks}') - labeled_chunks.append(self._label_chunk(chunk, language, index)) - - logger.info(f'{language} processing finished.') - result = pd.concat(labeled_chunks) - return result - - @classmethod - def _extract_fragment_id(cls, folder_name: str) -> int: - numbers = re.findall(r'\d+', folder_name) - if len(numbers) != 1: - raise ValueError(f'Can not extract fragment id from {folder_name}') - return numbers[0] - - @classmethod - def _get_fragment_id_from_fragment_file_path(cls, fragment_file_path: str) -> int: - folder_name = get_name_from_path(get_parent_folder(fragment_file_path), with_extension=False) - return cls._extract_fragment_id(folder_name) - - @classmethod - def _parse_inspections_files(cls, inspections_files: List[Path]) -> Dict[int, List[QodanaIssue]]: - id_to_issues: Dict[int, List[QodanaIssue]] = defaultdict(list) - for file in inspections_files: - issues = json.loads(get_content_from_file(file))['problems'] - for issue in issues: - fragment_id = int(cls._get_fragment_id_from_fragment_file_path(issue['file'])) - qodana_issue = QodanaIssue( - line=issue['line'], - offset=issue['offset'], - length=issue['length'], - highlighted_element=issue['highlighted_element'], - description=issue['description'], - fragment_id=fragment_id, - problem_id=issue['problem_class']['id'], - ) - id_to_issues[fragment_id].append(qodana_issue) - return id_to_issues - - def _label_chunk(self, chunk: pd.DataFrame, language: LanguageVersion, chunk_id: int) -> pd.DataFrame: - tmp_dir_path = self.dataset_path.parent.absolute() / f'qodana_project_{chunk_id}' - os.makedirs(tmp_dir_path, exist_ok=True) - - project_dir = tmp_dir_path / 'project' - results_dir = tmp_dir_path / 'results' - - logger.info('Copying the template') - self._copy_template(project_dir, language) - - if self.config: - logger.info('Copying the config') - copy_file(self.config, project_dir) - - logger.info('Creating main files') - self._create_main_files(project_dir, chunk, language) - - logger.info('Running qodana') - self._run_qodana(project_dir, results_dir) - - logger.info('Getting inspections') - inspections_files = self._get_inspections_files(results_dir) - inspections = self._parse_inspections_files(inspections_files) - - logger.info('Write inspections') - chunk[QodanaColumnName.INSPECTIONS.value] = chunk.apply( - lambda row: to_json(inspections.get(row[ColumnName.ID.value], [])), axis=1, - ) - - remove_directory(tmp_dir_path) - return chunk - - @staticmethod - def _copy_template(project_dir: Path, language: LanguageVersion) -> None: - if language.is_java(): - java_template = TEMPLATE_FOLDER / "java" - copy_directory(java_template, project_dir) - else: - raise NotImplementedError(f'{language} needs implementation.') - - def _create_main_files(self, project_dir: Path, chunk: pd.DataFrame, language: LanguageVersion) -> None: - if language.is_java(): - working_dir = project_dir / 'src' / 'main' / 'java' - - chunk.apply( - lambda row: next( - create_file( - file_path=(working_dir / f'solution{row[ColumnName.ID.value]}' / f'Main{Extension.JAVA.value}'), - content=row[ColumnName.CODE.value], - ), - ), - axis=1, - ) - else: - raise NotImplementedError(f'{language} needs implementation.') - - @staticmethod - def _run_qodana(project_dir: Path, results_dir: Path) -> None: - results_dir.mkdir() - command = [ - 'docker', 'run', - '-u', str(os.getuid()), - '--rm', - '-v', f'{project_dir}/:/data/project/', - '-v', f'{results_dir}/:/data/results/', - 'jetbrains/qodana', - ] - run_and_wait(command) - - @staticmethod - def _get_inspections_files(results_dir: Path) -> List[Path]: - condition = match_condition(r'\w*.json') - return get_all_file_system_items(results_dir, condition, without_subdirs=True) - - -def main(): - parser = ArgumentParser() - configure_arguments(parser) - - try: - args = parser.parse_args() - dataset_label = DatasetLabel(args) - dataset_label.label() - - except Exception: - traceback.print_exc() - logger.exception('An unexpected error') - return 2 - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/src/python/evaluation/qodana/filter_inspections.py b/src/python/evaluation/qodana/filter_inspections.py deleted file mode 100644 index 9321a7eb..00000000 --- a/src/python/evaluation/qodana/filter_inspections.py +++ /dev/null @@ -1,58 +0,0 @@ -import argparse -from pathlib import Path -from typing import List - -import pandas as pd -from src.python.evaluation.common.csv_util import write_dataframe_to_csv -from src.python.evaluation.common.pandas_util import get_solutions_df_by_file_path -from src.python.evaluation.common.util import parse_set_arg -from src.python.evaluation.qodana.util.models import QodanaColumnName, QodanaIssue -from src.python.evaluation.qodana.util.util import to_json -from src.python.review.common.file_system import Extension, extension_file_condition, get_all_file_system_items - - -def configure_arguments(parser: argparse.ArgumentParser) -> None: - parser.add_argument('dataset_folder', - type=lambda value: Path(value).absolute(), - help='Path to a folder with csv files graded by Qodana. ' - 'Each file must have "inspections" column.') - - parser.add_argument('-i', '--inspections', - help='Set of inspections ids to exclude from the dataset', - type=str, - default='') - - -def __get_qodana_dataset(root: Path) -> pd.DataFrame: - if not root.is_dir(): - raise ValueError(f'The {root} is not a directory') - dataset_files = get_all_file_system_items(root, extension_file_condition(Extension.CSV)) - datasets = [] - for file_path in dataset_files: - datasets.append(get_solutions_df_by_file_path(file_path)) - return pd.concat(datasets) - - -def __filter_inspections(json_issues: str, inspections_to_keep: List[str]) -> str: - issues_list = QodanaIssue.parse_list_issues_from_json(json_issues) - filtered_issues = list(filter(lambda i: i.problem_id not in inspections_to_keep, issues_list)) - return to_json(filtered_issues) - - -def main() -> None: - parser = argparse.ArgumentParser() - configure_arguments(parser) - args = parser.parse_args() - - dataset_folder = args.dataset_folder - full_dataset = __get_qodana_dataset(dataset_folder) - inspections_to_keep = parse_set_arg(args.inspections) - - full_dataset[QodanaColumnName.INSPECTIONS.value] = full_dataset.apply( - lambda row: __filter_inspections(row[QodanaColumnName.INSPECTIONS.value], inspections_to_keep), axis=1) - - write_dataframe_to_csv(dataset_folder / f'filtered_issues{Extension.CSV.value}', full_dataset) - - -if __name__ == '__main__': - main() diff --git a/src/python/evaluation/qodana/fragment_to_inspections_list.py b/src/python/evaluation/qodana/fragment_to_inspections_list.py deleted file mode 100644 index 42fe3ec6..00000000 --- a/src/python/evaluation/qodana/fragment_to_inspections_list.py +++ /dev/null @@ -1,33 +0,0 @@ -import argparse -from pathlib import Path - -from src.python.evaluation.common.csv_util import write_dataframe_to_csv -from src.python.evaluation.common.pandas_util import get_solutions_df_by_file_path -from src.python.evaluation.qodana.util.models import QodanaColumnName, QodanaIssue -from src.python.evaluation.qodana.util.util import ( - configure_model_converter_arguments, get_inspections_dict, replace_inspections_on_its_ids, -) -from src.python.review.common.file_system import Extension, get_parent_folder - -INSPECTIONS = QodanaColumnName.INSPECTIONS.value - - -def main() -> None: - parser = argparse.ArgumentParser() - configure_model_converter_arguments(parser) - args = parser.parse_args() - - solutions_file_path = args.solutions_file_path - solutions_df = get_solutions_df_by_file_path(solutions_file_path) - inspections_dict = get_inspections_dict(args.inspections_path) - - solutions_df[INSPECTIONS] = solutions_df.apply( - lambda row: replace_inspections_on_its_ids(QodanaIssue.parse_list_issues_from_json(row[INSPECTIONS]), - inspections_dict, args.remove_duplicates), axis=1) - - output_path = get_parent_folder(Path(solutions_file_path)) - write_dataframe_to_csv(output_path / f'numbered_ids{Extension.CSV.value}', solutions_df) - - -if __name__ == '__main__': - main() diff --git a/src/python/evaluation/qodana/fragment_to_inspections_list_line_by_line.py b/src/python/evaluation/qodana/fragment_to_inspections_list_line_by_line.py deleted file mode 100644 index c70d9ba1..00000000 --- a/src/python/evaluation/qodana/fragment_to_inspections_list_line_by_line.py +++ /dev/null @@ -1,62 +0,0 @@ -import argparse -import os -from itertools import groupby -from pathlib import Path -from typing import Dict, List - -import pandas as pd -from src.python.evaluation.common.csv_util import write_dataframe_to_csv -from src.python.evaluation.common.pandas_util import get_solutions_df_by_file_path -from src.python.evaluation.common.util import ColumnName -from src.python.evaluation.qodana.util.models import QodanaColumnName, QodanaIssue -from src.python.evaluation.qodana.util.util import ( - configure_model_converter_arguments, get_inspections_dict, replace_inspections_on_its_ids, -) -from src.python.review.common.file_system import Extension, get_parent_folder - - -INSPECTIONS = QodanaColumnName.INSPECTIONS.value -CODE = ColumnName.CODE.value - - -# Make a new dataframe where code fragment is separated line by line and inspections are grouped line by line -def __replace_inspections_to_its_ids_in_row(row: pd.Series, inspections_dict: Dict[str, int], - to_remove_duplicates: bool) -> pd.DataFrame: - row_df = pd.DataFrame(row).transpose() - fragment_lines = row_df.iloc[0][CODE].split(os.linesep) - fragment_df = row_df.loc[row_df.index.repeat(len(fragment_lines))].reset_index(drop=True) - - issues_list = QodanaIssue.parse_list_issues_from_json(row_df.iloc[0][INSPECTIONS]) - line_number_to_issues = {k: list(v) for k, v in groupby(issues_list, key=lambda i: i.line)} - for index, fragment_line in enumerate(fragment_lines): - issues = line_number_to_issues.get(index + 1, []) - fragment_df.iloc[index][CODE] = fragment_line - fragment_df.iloc[index][INSPECTIONS] = replace_inspections_on_its_ids(issues, inspections_dict, - to_remove_duplicates) - return fragment_df - - -def __append_df(df: pd.DataFrame, df_list: List[pd.DataFrame]) -> None: - df_list.append(df) - - -def main() -> None: - parser = argparse.ArgumentParser() - configure_model_converter_arguments(parser) - args = parser.parse_args() - - solutions_file_path = args.solutions_file_path - solutions_df = get_solutions_df_by_file_path(solutions_file_path) - inspections_dict = get_inspections_dict(args.inspections_path) - - fragment_df_list = [] - solutions_df.apply( - lambda row: __append_df(__replace_inspections_to_its_ids_in_row(row, inspections_dict, args.remove_duplicates), - fragment_df_list), axis=1) - - output_path = get_parent_folder(Path(solutions_file_path)) - write_dataframe_to_csv(output_path / f'numbered_ids_line_by_line{Extension.CSV.value}', pd.concat(fragment_df_list)) - - -if __name__ == '__main__': - main() diff --git a/src/python/evaluation/qodana/get_unique_inspectors.py b/src/python/evaluation/qodana/get_unique_inspectors.py deleted file mode 100644 index 35c32bdb..00000000 --- a/src/python/evaluation/qodana/get_unique_inspectors.py +++ /dev/null @@ -1,94 +0,0 @@ -import argparse -import itertools -from collections import defaultdict -from pathlib import Path -from typing import Dict, List, Optional - -import pandas as pd -from src.python.common.tool_arguments import RunToolArgument -from src.python.evaluation.common.csv_util import write_dataframe_to_csv -from src.python.evaluation.common.pandas_util import get_solutions_df_by_file_path -from src.python.evaluation.qodana.util.models import QodanaColumnName, QodanaIssue -from src.python.review.common.file_system import Extension, get_parent_folder - - -INSPECTION_ID = QodanaColumnName.INSPECTION_ID.value -INSPECTIONS = QodanaColumnName.INSPECTIONS.value -COUNT_ALL = QodanaColumnName.COUNT_ALL.value -COUNT_UNIQUE = QodanaColumnName.COUNT_UNIQUE.value -ID = QodanaColumnName.ID.value - - -def configure_arguments(parser: argparse.ArgumentParser) -> None: - parser.add_argument(RunToolArgument.QODANA_SOLUTIONS_FILE_PATH.value.long_name, - type=lambda value: Path(value).absolute(), - help=RunToolArgument.QODANA_SOLUTIONS_FILE_PATH.value.description) - - parser.add_argument('--uniq', - help='If True, count fragments for eash inspection in which this inspection was.', - action='store_true') - - -def __get_inspections_ids(json_issues: str) -> List[str]: - issues_list = QodanaIssue.parse_list_issues_from_json(json_issues) - return list(map(lambda i: i.problem_id, issues_list)) - - -def __get_inspections_from_df(solutions_df: pd.DataFrame) -> List[str]: - inspections = solutions_df.apply(lambda row: __get_inspections_ids(row[INSPECTIONS]), axis=1) - return list(itertools.chain.from_iterable(inspections.values)) - - -def __count_uniq_inspections_in_fragment(json_issues: str, inspection_id_to_fragments: Dict[str, int]) -> None: - issues_list = set(__get_inspections_ids(json_issues)) - for issue in issues_list: - inspection_id_to_fragments[issue] += 1 - - -def __get_uniq_inspections_in_all_fragments(solutions_df: pd.DataFrame) -> Dict[str, int]: - inspection_id_to_fragments: Dict[str, int] = defaultdict(int) - solutions_df.apply(lambda row: __count_uniq_inspections_in_fragment(row[INSPECTIONS], inspection_id_to_fragments), - axis=1) - - return inspection_id_to_fragments - - -def __get_all_inspections_by_inspection_id(inspection_id: str, all_inspections: List[str]) -> List[str]: - return list(filter(lambda i: i == inspection_id, all_inspections)) - - -def __create_unique_inspections_df(inspections: List[str], - inspection_id_to_fragments: Optional[Dict[str, int]]) -> pd.DataFrame: - id_to_inspection = {} - for index, inspection in enumerate(set(inspections)): - id_to_inspection[index + 1] = inspection - inspections_df = pd.DataFrame(id_to_inspection.items(), columns=[ID, INSPECTION_ID]) - inspections_df[COUNT_ALL] = inspections_df.apply(lambda row: len(__get_all_inspections_by_inspection_id( - row[INSPECTION_ID], inspections)), axis=1) - if inspection_id_to_fragments is None: - inspections_df[COUNT_UNIQUE] = 0 - else: - inspections_df[COUNT_UNIQUE] = inspections_df.apply(lambda row: inspection_id_to_fragments.get( - row[INSPECTION_ID], 0), axis=1) - return inspections_df - - -def main() -> None: - parser = argparse.ArgumentParser() - configure_arguments(parser) - args = parser.parse_args() - - solutions_file_path = args.solutions_file_path - solutions_df = get_solutions_df_by_file_path(solutions_file_path) - if args.uniq: - inspection_id_to_fragments = __get_uniq_inspections_in_all_fragments(solutions_df) - else: - inspection_id_to_fragments = None - inspections_df = __create_unique_inspections_df(__get_inspections_from_df(solutions_df), inspection_id_to_fragments) - - output_path = get_parent_folder(Path(solutions_file_path)) - write_dataframe_to_csv(output_path / f'inspections{Extension.CSV.value}', inspections_df) - - -if __name__ == '__main__': - main() diff --git a/src/python/evaluation/qodana/imitation_model/README.md b/src/python/evaluation/qodana/imitation_model/README.md deleted file mode 100644 index acb635f5..00000000 --- a/src/python/evaluation/qodana/imitation_model/README.md +++ /dev/null @@ -1,173 +0,0 @@ -# Qodana imitation model -## Description -The general purpose of the model is to simulate the behavior of [`Qodana`](https://github.com/JetBrains/Qodana/tree/main) – -a code quality monitoring tool that identifies and suggests fixes for bugs, security vulnerabilities, duplications, and imperfections. - -Motivation for developing a model: -- acceleration of the code analysis process by training the model to recognize a certain class of errors; -- the ability to run the model on separate files without the need to create a project (for example, for the Java language) - - -## Architecture -[`RobertaForSequenceClassification`](https://huggingface.co/transformers/model_doc/roberta.html#robertaforsequenceclassification) model with [`BCEWithLogitsLoss`](https://pytorch.org/docs/stable/generated/torch.nn.BCEWithLogitsLoss.html) solve multilabel classification task. - -Model outputs is a tensor of size: `batch_size` x `num_classes`. Where `batch_size` is the number of training examples utilized in one iteration, -and `num_classes` is the number of error types met in the dataset. By model class here, we mean a unique error type. -Class probabilities are received by taking `sigmoid` and final predictions are computed by comparing the probability of each class with the `threshold`. - -As classes might be unbalanced the used metric is `f1-score`. -## What it does - -Model has two use cases: -- It can be trained to predict a unique number of errors in a **block** of code, unfixed length. - -**Example**: - -code | inspections ---- | --- -|`import java.util.Scanner; class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);// put your code here int num = scanner.nextInt(); System.out.println((num / 10 ) % 10);}}`| 1, 2| - - -- It can be trained to predict a unique number of errors in a **line** of code. - -**Example** - -code | inspections ---- | --- -|`import java.util.Scanner;`| 0| -|`\n`|0| -|`class Main {`|1| -|`public static void main(String[] args`) {|1| -|`Scanner scanner = new Scanner(System.in);`|0| -|`// put your code here`|0| -|`int num = scanner.nextInt();`|0| -|`System.out.println((num / 10 ) % 10);`|2| -|`}`|0| -|`}`|0| - - -## Data preprocessing - -Please address to the [`following documentation`](src/python/evaluation/qodana) for labeling dataset and to the [`following documentation`](preprocessing) to preprocess data for model training and evaluation afterwards. - -After completing the 3d preprocessing step you should have 3 folders: -`train`, `val`, `test` with `train.csv`, `val.csv` and `test.csv` respectively. - -Each file has the same structure, it should consist of 4+ columns: -- `id` – solutions id; -- `code` – line od code or block of code; -- `lang` - language version; -- `0`, `1`, `2` ... `n` – several columns, equal to the unique number of errors detected by Qodana in the dataset. -The values in the columns are binary numbers: `1` if inspection is detected and `0` otherwise. - - -## How to train the model - -Run [`train.py`](train.py) script from the command line with the following arguments: - -Required arguments: - -- `train_dataset_path` ‑ path to the `train.csv` – file that consists of samples -that model will use for training. - -- `val_dataset_path` ‑ path to the `val.csv` – file that consists of samples -that model will use for evaluation during training. - -Both files are received by running [`split_dataset.py`](preprocessing/split_dataset.py) script and has the structure as described above. - -Optional arguments: - -Argument | Description ---- | --- -|**‑o**, **‑‑output_directory_path**| Path to the directory where model weights will be saved. If not set, folder will be created in the `train` folder where `train.csv` dataset is stored.| -|**‑c**, **‑‑context_length**| Sequence length or embedding size of tokenized samples. Available values are any `positive integers`. **Default is 40**.| -|**‑e**, **‑‑epoch**| Number of epochs to train model. **Default is 2**.| -|**‑bs**, **‑‑batch_size**| Batch size for training and validation dataset. Available values are any `positive integers`. **Default is 16**.| -|**‑lr**, **‑‑learning_rate**| Optimizer learning rate. **Default is 2e-5**.| -|**‑w**, **‑‑weight_decay**| Weight decay parameter for an optimizer. **Default is 0.01**.| -|**‑th**, **‑‑threshold**| Is used to compute predictions. Available values: 0 < `threshold` < 1. If the probability of inspection is greater than `threshold`, sample will be classified with the inspection. **Default is 0.5**.| -|**‑ws**, **‑‑warm_up_steps**| A number of steps when optimizer uses constant learning rate before applying scheduler policy. **Default is 300**.| -|**‑sl**, **‑‑save_limit**| Total amount of checkpoints limit. Default is 1.| - -To inspect the rest of default training parameters please, address to the [`TrainingArguments`](common/train_config.py). - -## How to evaluate model - -Run [`evaluation.py`](evaluation.py) script from the command line with the following arguments: - -Required arguments: - -`test_dataset_path` ‑ path to the `test.csv` received by running [`split_dataset.py`](preprocessing/split_dataset.py) script. - -`model_weights_directory_path` ‑ path to the folder where trained model weights are saved. - -Optional arguments: - -Argument | Description ---- | --- -|**‑o**, **‑‑output_directory_path**| Path to the directory where labeled dataset will be saved. Default is the `test` folder.| -|**‑c**, **‑‑context_length**| Sequence length or embedding size of tokenized samples. Available values are any `positive integers`. **Default is 40**.| -|**‑sf**, **‑‑save_f1_score**| If enabled report with f1 scores by classes will be saved to the `csv` file in the parent directory of labeled dataset. **Disabled by default**.| -|**‑bs**, **‑‑batch_size**| The number of training examples utilized in one training and validation iteration. Available values are any `positive integers`. **Default is 16**.| -|**‑th**, **‑‑threshold**| Is used to compute predictions. Available values: 0 < `threshold` < 1. If the probability of inspection is greater than `threshold`, sample will be classified with the inspection. **Default is 0.5**.| - -Output is a `predictions.csv` file with the column names matches the number of classes. Each sample has a binary label: - -- `0` ‑ if the model didn't found an error in a sample. - -- `1` ‑ if the error was found in a sample. - - -## How to use model, pretrained on Java code snippets from Stepik - -There are 2 trained models available for the usage and 2 datasets on which models were trained and evaluated. -Access to the datasets is restricted. -### Model that uses program text as an input: -- [`train_dataset`](https://drive.google.com/drive/folders/1bdLExLIbY53SVobT0y4Lnz9oeZENqLmt?usp=sharing) – private access; -- [`evaluation_dataset`](https://drive.google.com/file/d/1hZlP7q3gVoIl8vmOur0UFpEyFDYyVZko/view?usp=sharing) – private access; -- [`test_dataset`](https://drive.google.com/file/d/1oappcDcH-p-2LwjdOfZHRSiRB9Vi39mc/view?usp=sharing) – private access; -- [`model_weights`](https://drive.google.com/file/d/1PFVHVd4JDjFUD3b5fDSGXoYBWEDlaEAg/view?usp=sharing) – public access. - -The model was trained to detect 110 Qodana inspections. The whole -list of inspections can be found via the link [here](https://drive.google.com/file/d/1PVqjx7QEot1dIXyiYP_-dJnWGup2Ef7v/view?usp=sharing). - -Evaluation results are: - -Inspection | Description | F1-Score ---- | --- | --- -|No Errors | No errors from the [list](https://docs.google.com/spreadsheets/d/14BTj_lTTRrGlx-GPTcbMlc8zdt--WXLZHRnegKRrZYM/edit?usp=sharing) were detected by Qodana.| 0.73 | -| Syntax Error |Reports any irrelevant usages of java syntax.| 0.99| -| System Out Error | Reports any usages of System.out or System.err. | 0.99 | -| IO Resources | Reports any I/O resource which is not safely closed. | 0.97 | - -The rests of the inspections were not learnt by the model due to the class disbalance. -### Model that uses a line of program text as an input: -- [`train_dataset`](https://drive.google.com/file/d/1c-kJUV4NKuehCoLiIC3JWrJh3_NgTmvi/view?usp=sharing) – private access; -- [`evaluation_dataset`](https://drive.google.com/file/d/1AVN4Uj4omPEquC3EAL6XviFATkYKcY_2/view?usp=sharing) – private access; -- [`test_dataset`](https://drive.google.com/file/d/1J3gz3wS_l63SI0_OMym8x5pCj7-PCIgG/view?usp=sharing) – private access; -- [`model_weights`](https://drive.google.com/file/d/1fc32-5XyUeOpZ5AkRotqv_3cWksHjat_/view?usp=sharing) – public access. - -One sample in the dataset consists of one line of program in the context. The context is 2 lines of the same -program before and after the target line. When there are not enough lines before or after target, special -token `NOC` is added. - -The model was also trained to detect 110 inspections. The whole -list of inspections can be found via the link [here](https://drive.google.com/file/d/1PVqjx7QEot1dIXyiYP_-dJnWGup2Ef7v/view?usp=sharing). - -Evaluation results are: - -Inspection | Description | F1-score ---- | --- | --- -|No Errors | No errors from the [list](https://docs.google.com/spreadsheets/d/14BTj_lTTRrGlx-GPTcbMlc8zdt--WXLZHRnegKRrZYM/edit?usp=sharing) were detected by Qodana.| 0.99 | -| Syntax Error |Reports any irrelevant usages of java syntax.| 0.23| -| System Out Error | Reports any usages of System.out or System.err.| 0.30 | -| IO Resources | Reports any I/O resource which is not safely closed | 0.23 | - -The rests of the inspections were not learnt by the model due to the class disbalance. - -To use any of the model follow [`fine-tuning`](https://huggingface.co/transformers/training.html) tutorial from HuggingFace. Unarchive `model weights` zip and use absolute path to the root folder instead of built-in name of pretrained model. - -For example: - - RobertaForSequenceClassification.from_pretrained(, - num_labels=) diff --git a/src/python/evaluation/qodana/imitation_model/__init__.py b/src/python/evaluation/qodana/imitation_model/__init__.py deleted file mode 100644 index 0c4d7f8e..00000000 --- a/src/python/evaluation/qodana/imitation_model/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from src.python import MAIN_FOLDER - -MODEL_FOLDER = MAIN_FOLDER.parent / 'python/imitation_model' diff --git a/src/python/evaluation/qodana/imitation_model/common/__init__.py b/src/python/evaluation/qodana/imitation_model/common/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/python/evaluation/qodana/imitation_model/common/evaluation_config.py b/src/python/evaluation/qodana/imitation_model/common/evaluation_config.py deleted file mode 100644 index e91bf687..00000000 --- a/src/python/evaluation/qodana/imitation_model/common/evaluation_config.py +++ /dev/null @@ -1,47 +0,0 @@ -import argparse - -from src.python.evaluation.qodana.imitation_model.common.util import ModelCommonArgument -from src.python.review.common.file_system import Extension - - -def configure_arguments(parser: argparse.ArgumentParser) -> None: - parser.add_argument('test_dataset_path', - type=str, - help='Path to the dataset received by either' - f' src.python.evaluation.qodana.fragment_to_inspections_list{Extension.PY.value}' - 'or src.python.evaluation.qodana.fragment_to_inspections_list_line_by_line' - f'{Extension.PY.value}script.') - - parser.add_argument('model_weights_directory_path', - type=str, - help='Path to the directory where trained imitation_model weights are stored.') - - parser.add_argument('-o', '--output_directory_path', - default=None, - type=str, - help='Path to the directory where labeled dataset will be saved. Default is the parent folder' - 'of test_dataset_path.') - - parser.add_argument('-sf', '--save_f1_score', - default=None, - action="store_true", - help=f'If enabled report with f1 scores by class will be saved to the {Extension.CSV.value}' - ' File will be saved to the labeled dataset parent directory. Default is False.') - - parser.add_argument(ModelCommonArgument.CONTEXT_LENGTH.value.short_name, - ModelCommonArgument.CONTEXT_LENGTH.value.long_name, - type=int, - default=40, - help=ModelCommonArgument.CONTEXT_LENGTH.value.description) - - parser.add_argument(ModelCommonArgument.BATCH_SIZE.value.short_name, - ModelCommonArgument.BATCH_SIZE.value.long_name, - type=int, - default=8, - help=ModelCommonArgument.BATCH_SIZE.value.description) - - parser.add_argument(ModelCommonArgument.THRESHOLD.value.short_name, - ModelCommonArgument.THRESHOLD.value.long_name, - type=float, - default=0.5, - help=ModelCommonArgument.THRESHOLD.value.description) diff --git a/src/python/evaluation/qodana/imitation_model/common/metric.py b/src/python/evaluation/qodana/imitation_model/common/metric.py deleted file mode 100644 index dce80a94..00000000 --- a/src/python/evaluation/qodana/imitation_model/common/metric.py +++ /dev/null @@ -1,41 +0,0 @@ -import logging.config -from typing import Optional - -import torch -from sklearn.metrics import multilabel_confusion_matrix -from src.python.evaluation.qodana.imitation_model.common.util import MeasurerArgument - -logger = logging.getLogger(__name__) - - -class Measurer: - def __init__(self, threshold: float): - self.threshold = threshold - - def get_f1_score(self, predictions: torch.tensor, targets: torch.tensor) -> Optional[float]: - confusion_matrix = multilabel_confusion_matrix(targets, predictions) - false_positives = sum(score[0][1] for score in confusion_matrix) - false_negatives = sum(score[1][0] for score in confusion_matrix) - true_positives = sum(score[1][1] for score in confusion_matrix) - try: - f1_score = true_positives / (true_positives + 1 / 2 * (false_positives + false_negatives)) - return f1_score - except ZeroDivisionError: - logger.error("No values of the class present in the dataset.") - # return None to make it clear after printing what classes are missing in the datasets - return None - - def compute_metric(self, evaluation_predictions: torch.tensor) -> dict: - logits, targets = evaluation_predictions - prediction_probabilities = torch.from_numpy(logits).sigmoid() - predictions = torch.where(prediction_probabilities > self.threshold, 1, 0) - return {MeasurerArgument.F1_SCORE.value: self.get_f1_score(predictions, torch.tensor(targets))} - - def f1_score_by_classes(self, predictions: torch.tensor, targets: torch.tensor) -> dict: - unique_classes = range(len(targets[0])) - f1_scores_by_classes = {} - for unique_class in unique_classes: - class_mask = torch.where(targets[:, unique_class] == 1) - f1_scores_by_classes[str(unique_class)] = self.get_f1_score(predictions[class_mask[0], unique_class], - targets[class_mask[0], unique_class]) - return f1_scores_by_classes diff --git a/src/python/evaluation/qodana/imitation_model/common/train_config.py b/src/python/evaluation/qodana/imitation_model/common/train_config.py deleted file mode 100644 index ba2d93fa..00000000 --- a/src/python/evaluation/qodana/imitation_model/common/train_config.py +++ /dev/null @@ -1,118 +0,0 @@ -import argparse - -import torch -from src.python.evaluation.qodana.imitation_model.common.util import ( - DatasetColumnArgument, - ModelCommonArgument, - SeedArgument, -) -from transformers import Trainer, TrainingArguments - - -class MultilabelTrainer(Trainer): - """ By default RobertaForSequence classification does not support - multi-label classification. - - Target and logits tensors should be represented as torch.FloatTensor of shape (1,). - https://huggingface.co/transformers/model_doc/roberta.html#transformers.RobertaForSequenceClassification - - To fine-tune the model for the multi-label classification task we can simply modify the trainer by - changing its loss function. https://huggingface.co/transformers/main_classes/trainer.html - """ - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - def compute_loss(self, model, inputs, return_outputs=False): - labels = inputs.pop(DatasetColumnArgument.LABELS.value) - outputs = model(**inputs) - logits = outputs.logits - loss_bce = torch.nn.BCEWithLogitsLoss() - loss = loss_bce(logits.view(-1, self.model.config.num_labels), - labels.float().view(-1, self.model.config.num_labels)) - - return (loss, outputs) if return_outputs else loss - - -def configure_arguments(parser: argparse.ArgumentParser) -> None: - parser.add_argument('train_dataset_path', - type=str, - help='Path to the train dataset.') - - parser.add_argument('val_dataset_path', - type=str, - help='Path to the dataset received by either') - - parser.add_argument('-wp', '--trained_weights_directory_path', - default=None, - type=str, - help='Path to the directory where to save imitation_model weights. Default is the directory' - 'where train dataset is.') - - parser.add_argument(ModelCommonArgument.CONTEXT_LENGTH.value.short_name, - ModelCommonArgument.CONTEXT_LENGTH.value.long_name, - type=int, - default=40, - help=ModelCommonArgument.CONTEXT_LENGTH.value.description) - - parser.add_argument(ModelCommonArgument.BATCH_SIZE.value.short_name, - ModelCommonArgument.BATCH_SIZE.value.long_name, - type=int, - default=16, - help=ModelCommonArgument.BATCH_SIZE.value.description) - - parser.add_argument(ModelCommonArgument.THRESHOLD.value.short_name, - ModelCommonArgument.THRESHOLD.value.long_name, - type=float, - default=0.5, - help=ModelCommonArgument.THRESHOLD.value.description) - - parser.add_argument('-lr', '--learning_rate', - type=int, - default=2e-5, - help='Learning rate.') - - parser.add_argument('-wd', '--weight_decay', - type=int, - default=0.01, - help='Wight decay parameter for optimizer.') - - parser.add_argument('-e', '--epoch', - type=int, - default=1, - help='Number of epochs to train imitation_model.') - - parser.add_argument('-ws', '--warm_up_steps', - type=int, - default=300, - help='Number of steps used for a linear warmup, default is 300.') - - parser.add_argument('-sl', '--save_limit', - type=int, - default=1, - help='Total amount of checkpoints limit. Default is 1.') - - -class TrainingArgs: - def __init__(self, args): - self.args = args - - def get_training_args(self, val_steps_to_be_made): - return TrainingArguments(num_train_epochs=self.args.epoch, - per_device_train_batch_size=self.args.batch_size, - per_device_eval_batch_size=self.args.batch_size, - learning_rate=self.args.learning_rate, - warmup_steps=self.args.warm_up_steps, - weight_decay=self.args.weight_decay, - save_total_limit=self.args.save_limit, - output_dir=self.args.trained_weights_directory_path, - overwrite_output_dir=True, - load_best_model_at_end=True, - greater_is_better=True, - save_steps=val_steps_to_be_made, - eval_steps=val_steps_to_be_made, - logging_steps=val_steps_to_be_made, - evaluation_strategy=DatasetColumnArgument.STEPS.value, - logging_strategy=DatasetColumnArgument.STEPS.value, - seed=SeedArgument.SEED.value, - report_to=[DatasetColumnArgument.WANDB.value]) diff --git a/src/python/evaluation/qodana/imitation_model/common/util.py b/src/python/evaluation/qodana/imitation_model/common/util.py deleted file mode 100644 index da0d29e5..00000000 --- a/src/python/evaluation/qodana/imitation_model/common/util.py +++ /dev/null @@ -1,46 +0,0 @@ -from enum import Enum, unique - -from src.python.common.tool_arguments import ArgumentsInfo - - -@unique -class DatasetColumnArgument(Enum): - ID = 'id' - IN_ID = 'inspection_id' - INSPECTIONS = 'inspections' - INPUT_IDS = 'input_ids' - LABELS = 'labels' - DATASET_PATH = 'dataset_path' - STEPS = 'steps' - WEIGHTS = 'weights' - WANDB = 'wandb' - - -@unique -class SeedArgument(Enum): - SEED = 42 - - -@unique -class CustomTokens(Enum): - NOC = '[NOC]' # no context token to add when there are no lines for the context - - -@unique -class ModelCommonArgument(Enum): - THRESHOLD = ArgumentsInfo('-th', '--threshold', - 'If the probability of inspection on code sample is greater than threshold,' - 'inspection id will be assigned to the sample. ' - 'Default is 0.5.') - - CONTEXT_LENGTH = ArgumentsInfo('-cl', '--context_length', - 'Sequence length of 1 sample after tokenization, default is 40.') - - BATCH_SIZE = ArgumentsInfo('-bs', '--batch_size', - 'Batch size – default values are 16 for training and 8 for evaluation mode.') - - -@unique -class MeasurerArgument(Enum): - F1_SCORE = 'f1_score' - F1_SCORES_BY_CLS = 'f1_scores_by_class' diff --git a/src/python/evaluation/qodana/imitation_model/dataset/__init__.py b/src/python/evaluation/qodana/imitation_model/dataset/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/python/evaluation/qodana/imitation_model/dataset/dataset.py b/src/python/evaluation/qodana/imitation_model/dataset/dataset.py deleted file mode 100644 index 088ce548..00000000 --- a/src/python/evaluation/qodana/imitation_model/dataset/dataset.py +++ /dev/null @@ -1,34 +0,0 @@ -import logging - -import pandas as pd -import torch -from src.python.evaluation.common.util import ColumnName -from src.python.evaluation.qodana.imitation_model.common.util import DatasetColumnArgument -from torch.utils.data import Dataset -from transformers import RobertaTokenizer - -logger = logging.getLogger(__name__) - - -class QodanaDataset(Dataset): - """ MarkingArgument.ID.value is a an id of the solution that corresponds to the line - MarkingArgument.INSPECTIONS.value is a is a target column name in dataset - ColumnName.CODE.value is an observation column name in dataset where lines of code are stored - """ - - def __init__(self, data_path: str, context_length: int): - super().__init__() - df = pd.read_csv(data_path) - tokenizer = RobertaTokenizer.from_pretrained('roberta-base') - code = list(map(str, df[ColumnName.CODE.value])) - self.target = torch.tensor(df.iloc[:, 1:].astype(float).values) - self.code_encoded = tokenizer( - code, padding=True, truncation=True, max_length=context_length, return_tensors="pt", - )[DatasetColumnArgument.INPUT_IDS.value] - - def __getitem__(self, idx): - return {DatasetColumnArgument.INPUT_IDS.value: self.code_encoded[idx], - DatasetColumnArgument.LABELS.value: self.target[idx]} - - def __len__(self): - return len(self.target) diff --git a/src/python/evaluation/qodana/imitation_model/evaluation.py b/src/python/evaluation/qodana/imitation_model/evaluation.py deleted file mode 100644 index 9eac3ec2..00000000 --- a/src/python/evaluation/qodana/imitation_model/evaluation.py +++ /dev/null @@ -1,75 +0,0 @@ -import argparse -import sys -from pathlib import Path - -import numpy as np -import pandas as pd -import torch -import transformers -from src.python.evaluation.common.csv_util import write_dataframe_to_csv -from src.python.evaluation.qodana.imitation_model.common.evaluation_config import configure_arguments -from src.python.evaluation.qodana.imitation_model.common.metric import Measurer -from src.python.evaluation.qodana.imitation_model.common.util import DatasetColumnArgument, MeasurerArgument -from src.python.evaluation.qodana.imitation_model.dataset.dataset import QodanaDataset -from src.python.review.common.file_system import Extension -from torch.utils.data import DataLoader -from transformers import RobertaForSequenceClassification - - -def get_predictions(eval_dataloader: torch.utils.data.DataLoader, - model: transformers.RobertaForSequenceClassification, - predictions: np.ndarray, - num_labels: int, - device: torch.device, - args: argparse.ArgumentParser) -> pd.DataFrame: - start_index = 0 - for batch in eval_dataloader: - with torch.no_grad(): - logits = model(input_ids=batch[DatasetColumnArgument.INPUT_IDS.value].to(device)).logits - logits = logits.sigmoid().detach().cpu().numpy() - predictions[start_index:start_index + args.batch_size, :num_labels] = (logits > args.threshold).astype(int) - start_index += args.batch_size - return pd.DataFrame(predictions, columns=range(num_labels), dtype=int) - - -def save_f1_scores(output_directory_path: Path, f1_score_by_class_dict: dict) -> None: - f1_score_report_file_name = f'{MeasurerArgument.F1_SCORES_BY_CLS.value}{Extension.CSV.value}' - f1_score_report_path = Path(output_directory_path).parent / f1_score_report_file_name - f1_score_report_df = pd.DataFrame({MeasurerArgument.F1_SCORE.value: f1_score_by_class_dict.values(), - 'inspection_id': range(len(f1_score_by_class_dict.values()))}) - write_dataframe_to_csv(f1_score_report_path, f1_score_report_df) - - -def main(): - parser = argparse.ArgumentParser() - configure_arguments(parser) - args = parser.parse_args() - if args.output_directory_path is None: - args.output_directory_path = Path(args.test_dataset_path).parent / f'predictions{Extension.CSV.value}' - - test_dataset = QodanaDataset(args.test_dataset_path, args.context_length) - num_labels = test_dataset[0][DatasetColumnArgument.LABELS.value].shape[0] - eval_dataloader = DataLoader(test_dataset, batch_size=args.batch_size) - predictions = np.zeros([len(test_dataset), num_labels], dtype=object) - - device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu") - model = RobertaForSequenceClassification.from_pretrained(args.model_weights_directory_path, - num_labels=num_labels).to(device) - model.eval() - - predictions = get_predictions(eval_dataloader, model, predictions, num_labels, device, args) - true_labels = torch.tensor(pd.read_csv(args.test_dataset_path).iloc[:, 1:].to_numpy()) - metric = Measurer(args.threshold) - f1_score_by_class_dict = metric.f1_score_by_classes(torch.tensor(predictions.to_numpy()), true_labels) - - print(f"{MeasurerArgument.F1_SCORE.value}:" - f"{metric.get_f1_score(torch.tensor(predictions.to_numpy()), true_labels)}", - f"\n{MeasurerArgument.F1_SCORES_BY_CLS.value}: {f1_score_by_class_dict}") - - write_dataframe_to_csv(args.output_directory_path, predictions) - if args.save_f1_score: - save_f1_scores(args.output_directory_path, f1_score_by_class_dict) - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/src/python/evaluation/qodana/imitation_model/preprocessing/README.md b/src/python/evaluation/qodana/imitation_model/preprocessing/README.md deleted file mode 100644 index 76e2b9d0..00000000 --- a/src/python/evaluation/qodana/imitation_model/preprocessing/README.md +++ /dev/null @@ -1,57 +0,0 @@ -# Data preprocessing - -This module transforms filtered and labeled dataset into the files that can be used as input -files for [train](src/python/evaluation/qodana/imitation_model/train.py) and -[evaluation](src/python/evaluation/qodana/imitation_model/evaluation.py) scripts. - -### Step 1 - -Run [fragment_to_inspections_list.py](https://github.com/hyperskill/hyperstyle/blob/roberta-model/src/python/evaluation/qodana/fragment_to_inspections_list.py) -script to get `numbered_ids.csv` file in case of working with code-blocks or alternatively run -[fragment_to_inspections_list_line_by_line.py](https://github.com/hyperskill/hyperstyle/blob/roberta-model/src/python/evaluation/qodana/fragment_to_inspections_list_line_by_line.py) -script to get `numbered_ids_line_by_line.csv` file. - -[Detailed instructions](https://github.com/hyperskill/hyperstyle/tree/roberta-model/src/python/evaluation/qodana) -on how to run following scripts. - -### Step 2 - -Run [encode_data.py](https://github.com/hyperskill/hyperstyle/blob/roberta-model/src/python/model/preprocessing/encode_data.py) with the -following arguments: - -Required arguments: - -`dataset_path` — path to `numbered_ids_line_by_line.csv` file or `numbered_ids.csv` file. - -Optional arguments: - -Argument | Description ---- | --- -|**‑o**, **‑‑output_file_path**| Path to the directory where output file will be created. If not set, output file will be saved in the parent directory of `dataset_path`.| -|**‑ohe**, **‑‑one_hot_encoding**| If `True` target column will be represented as one-hot-encoded vector. The length of each vector is equal to the unique number of classes in dataset. Default is `True`.| -|**‑c**, **‑‑add_context**| Should be used only when `dataset_path` is a path to `numbered_ids_line_by_line.csv`. If set to `True` each single line will be substituted by a piece of code – the context created from several lines. Default is `False`.| -|**‑n**, **‑‑n_lines_to_add**| A number of lines to append to the target line before and after it. A line is appended only if it matches the same solution. If there are not enough lines in the solution, special token will be appended instead. Default is 2.| - - -#### Script functionality overview: -- creates `one-hot-encoding` vectors matches each samples each sample in the dataset **(default)**. -- substitutes `NaN` values in the dataset by `\n` symbol **(default)**. -- transform lines of code into the `context` from several lines of code **(optional)**. - -### Step 3 - -Run [`split_dataset.py`](https://github.com/hyperskill/hyperstyle/blob/roberta-model/src/python/model/preprocessing/split_dataset.py) -with the following arguments: - -Required arguments: - -`dataset_path` — path to `encoded_dataset.csv` file obtained by running [encode_data.py](https://github.com/hyperskill/hyperstyle/blob/roberta-model/src/python/model/preprocessing/encode_data.py) script. - -Optional arguments: - -Argument | Description ---- | --- -|**‑o**, **‑‑output_directory_path**| Path to the directory where folders for train, test and validation datasets with the corresponding files will be created. If not set, folders will be created in the parent directory of `dataset_path`.| -|**‑ts**, **‑‑test_size**| Proportion of test dataset. Available values: 0 < n < 1. Default is 0.2.| -|**‑vs**, **‑‑val_size**| Proportion of validation dataset that will be taken from train dataset. Available values are: 0 < n < 1. Default is 0.3.| -|**‑sh**, **‑‑shuffle**| If `True` data will be shuffled before split. Default is `True`.| diff --git a/src/python/evaluation/qodana/imitation_model/preprocessing/__init__.py b/src/python/evaluation/qodana/imitation_model/preprocessing/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/python/evaluation/qodana/imitation_model/preprocessing/encode_data.py b/src/python/evaluation/qodana/imitation_model/preprocessing/encode_data.py deleted file mode 100644 index 8b57888a..00000000 --- a/src/python/evaluation/qodana/imitation_model/preprocessing/encode_data.py +++ /dev/null @@ -1,162 +0,0 @@ -import argparse -import logging -import sys -from itertools import chain -from pathlib import Path -from typing import List - -import numpy as np -import pandas as pd -from sklearn.preprocessing import MultiLabelBinarizer -from src.python.evaluation.common.csv_util import write_dataframe_to_csv -from src.python.evaluation.common.util import ColumnName -from src.python.evaluation.qodana.imitation_model.common.util import CustomTokens, DatasetColumnArgument -from src.python.review.common.file_system import Extension - - -logger = logging.getLogger(__name__) -sys.path.append('') -sys.path.append('../../../../..') - - -def configure_arguments(parser: argparse.ArgumentParser) -> None: - parser.add_argument('dataset_path', - type=lambda value: Path(value).absolute(), - help='Path to the dataset with the values to be encoded. ') - - parser.add_argument('-o', '--output_file_path', - help='Output file path. If not set, file will be saved to ' - 'the input file parent directory.', - type=str, - default='input_file_directory') - - parser.add_argument('-c', '--add_context', - help='Use for the datasets with code lines only, if set to True, ' - 'n lines before and n lines after target line will be added to each sample.' - ' Default is False.', - action='store_true') - - parser.add_argument('-n', '--n_lines_to_add', - help='Use only if add_context is enabled. Allows to add n-lines from the same piece of code, ' - 'before and after each line in the dataset. If there are no lines before or after a line' - 'from the same code-sample, special token will be added. Default is 2.', - default=2, - type=int) - - parser.add_argument('-ohe', '--one_hot_encoding', - help='If True, target column will be represented as one-hot-encoded vector. ' - 'The length of each vector is equal to the unique number of classes. ' - 'Default is True.', - action='store_false') - - -def __one_hot_encoding(df: pd.DataFrame) -> pd.DataFrame: - """ Transforms strings in 'inspections' column, - denoting inspection ids into n columns - with binary values: - - 1 x n_rows -> n_unique_classes x n_rows - - Where n_unique_classes is equal to the number - of unique inspections in the dataset. - - Example: - inspections -> 1, 2, 3 - '1, 2' 1 1 0 - '3' 0 0 1 - """ - target = df[DatasetColumnArgument.INSPECTIONS.value].to_numpy().astype(str) - target_list_int = [np.unique(tuple(map(int, label.split(',')))) for label in target] - try: - mlb = MultiLabelBinarizer() - encoded_target = mlb.fit_transform(target_list_int) - assert len(list(set(chain.from_iterable(target_list_int)))) == encoded_target.shape[1] - encoded_target = pd.DataFrame(data=encoded_target, columns=range(encoded_target.shape[1])) - return encoded_target - except AssertionError as e: - logger.error('encoded_target.shape[1] should be equal to number of classes') - raise e - - -class Context: - """ To each line of code add context from the same solution: - 'n_lines_before' line 'n_lines_after'. - If there are no lines before or / and after a piece of code, - special tokens are added. - """ - def __init__(self, df: pd.DataFrame, n_lines: int): - self.indices = df[DatasetColumnArgument.ID.value].to_numpy() - self.lines = df[ColumnName.CODE.value] - self.n_lines: int = n_lines - self.df = df - - def add_context_to_lines(self) -> pd.DataFrame: - lines_with_context = [] - for current_line_index, current_line in enumerate(self.lines): - context = self.add_context_before(current_line_index, current_line) - context = self.add_context_after(context, current_line_index) - lines_with_context.append(context[0]) - lines_with_context = pd.Series(lines_with_context) - self.df[ColumnName.CODE.value] = lines_with_context - return self.df - - def add_context_before(self, current_line_index: int, current_line: str) -> List[str]: - """ Add n_lines lines before the target line from the same piece of code, - If there are less than n lines above the target line will add - a special token. - """ - context = [''] - for n_line_index in range(current_line_index - self.n_lines, self.n_lines): - if n_line_index >= len(self.lines): - return context - if n_line_index == 0 or self.indices[n_line_index] != self.indices[current_line_index]: - context = [context[0] + CustomTokens.NOC.value] - else: - context = [context[0] + self.lines.iloc[n_line_index]] - if n_line_index != self.n_lines - 1: - context = [context[0] + '\n'] - context = [context[0] + current_line] - return context - - def add_context_after(self, context: List, current_line_index: int) -> List[str]: - """ Add n_lines lines after the target line from the same piece of code, - If there are less than n lines after the target line will add - a special token. - """ - for n_line_index in range(current_line_index + 1, self.n_lines + current_line_index + 1): - if n_line_index >= len(self.lines) or self.indices[n_line_index] != self.indices[current_line_index]: - context = [context[0] + CustomTokens.NOC.value] - else: - context = [context[0] + self.lines.iloc[n_line_index]] - if n_line_index != self.n_lines - 1: - context = [context[0] + '\n'] - return context - - -def main() -> None: - parser = argparse.ArgumentParser() - configure_arguments(parser) - args = parser.parse_args() - - dataset_path = args.dataset_path - output_file_path = args.output_file_path - - if output_file_path == 'input_file_directory': - output_file_path = Path(dataset_path).parent / f'encoded_dataset{Extension.CSV.value}' - - # nan -> \n (empty rows) - df = pd.read_csv(dataset_path) - df[ColumnName.CODE.value].fillna('\n', inplace=True) - - if args.one_hot_encoding: - target = __one_hot_encoding(df) - df = pd.concat([df[[ColumnName.ID.value, ColumnName.CODE.value]], target], axis=1) - - if args.add_context: - df = Context(df, args.n_lines_to_add).add_context_to_lines() - - write_dataframe_to_csv(output_file_path, df) - - -if __name__ == '__main__': - main() diff --git a/src/python/evaluation/qodana/imitation_model/preprocessing/split_dataset.py b/src/python/evaluation/qodana/imitation_model/preprocessing/split_dataset.py deleted file mode 100644 index 41a4319b..00000000 --- a/src/python/evaluation/qodana/imitation_model/preprocessing/split_dataset.py +++ /dev/null @@ -1,77 +0,0 @@ -import argparse -import os -from pathlib import Path - -import pandas as pd -from sklearn.model_selection import train_test_split -from src.python.evaluation.common.csv_util import write_dataframe_to_csv -from src.python.evaluation.common.util import ColumnName -from src.python.evaluation.qodana.imitation_model.common.util import SeedArgument -from src.python.review.common.file_system import Extension - - -def configure_parser() -> argparse.ArgumentParser: - parser = argparse.ArgumentParser() - parser.add_argument('dataset_path', - type=str, - help=f'Path to the dataset received by either' - f' src.python.evaluation.qodana.fragment_to_inspections_list{Extension.PY.value}' - f'or src.python.evaluation.qodana.fragment_to_inspections_list_line_by_line' - f'{Extension.PY.value}script.') - - parser.add_argument('-d', '--output_directory_path', - type=str, - default=None, - help='Path to the directory where folders for train, test and validation datasets will be ' - 'created. If not set directories will be created in the parent directory of dataset_path') - - parser.add_argument('-ts', '--test_size', - type=int, - default=0.2, - help='Rate of test size from the whole dataset. Default is 0.2') - - parser.add_argument('-vs', '--val_size', - type=int, - default=0.3, - help='Rate of validation dataset from the train dataset. Default is 0.3 ') - - parser.add_argument('-sh', '--shuffle', - type=bool, - default=True, - help='If true, data will be shuffled before splitting. Default is True.') - - return parser - - -def split_dataset(dataset_path: str, output_directory_path: str, val_size: float, test_size: float, shuffle: bool): - df = pd.read_csv(dataset_path) - target = df.iloc[:, 2:] - code_bank = df[ColumnName.CODE.value] - - code_train, code_test, target_train, target_test = train_test_split(code_bank, - target, - test_size=test_size, - random_state=SeedArgument.SEED.value, - shuffle=shuffle) - - code_train, code_val, target_train, target_val = train_test_split(code_train, - target_train, - test_size=val_size, - random_state=SeedArgument.SEED.value, - shuffle=shuffle) - if output_directory_path is None: - output_directory_path = Path(dataset_path).parent - - for holdout in [("train", code_train, target_train), - ("val", code_val, target_val), - ("test", code_test, target_test)]: - df = pd.concat([holdout[1], holdout[2]], axis=1) - os.makedirs(os.path.join(output_directory_path, holdout[0]), exist_ok=True) - write_dataframe_to_csv(Path(output_directory_path) / holdout[0] / f'{holdout[0]}{Extension.CSV.value}', df) - - -if __name__ == "__main__": - parser = configure_parser() - args = parser.parse_args() - - split_dataset(args.dataset_path, args.output_directory_path, args.val_size, args.test_size, args.shuffle) diff --git a/src/python/evaluation/qodana/imitation_model/train.py b/src/python/evaluation/qodana/imitation_model/train.py deleted file mode 100644 index fc458d95..00000000 --- a/src/python/evaluation/qodana/imitation_model/train.py +++ /dev/null @@ -1,46 +0,0 @@ -import argparse -import os -import sys -from pathlib import Path - -import torch -from src.python.evaluation.qodana.imitation_model.common.metric import Measurer -from src.python.evaluation.qodana.imitation_model.common.train_config import ( - configure_arguments, MultilabelTrainer, TrainingArgs, -) -from src.python.evaluation.qodana.imitation_model.common.util import DatasetColumnArgument -from src.python.evaluation.qodana.imitation_model.dataset.dataset import QodanaDataset -from transformers import RobertaForSequenceClassification - - -def main(): - parser = argparse.ArgumentParser() - configure_arguments(parser) - args = parser.parse_args() - device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu") - train_dataset = QodanaDataset(args.train_dataset_path, args.context_length) - val_dataset = QodanaDataset(args.val_dataset_path, args.context_length) - train_steps_to_be_made = len(train_dataset) // args.batch_size - val_steps_to_be_made = train_steps_to_be_made // 5 - print(f'Steps to be made: {train_steps_to_be_made}, validate each {val_steps_to_be_made}th step.') - - num_labels = train_dataset[0][DatasetColumnArgument.LABELS.value].shape[0] - model = RobertaForSequenceClassification.from_pretrained('roberta-base', num_labels=num_labels).to(device) - - metrics = Measurer(args.threshold) - if args.trained_weights_directory_path is None: - args.trained_weights_directory_path = Path(args.train_dataset_path).parent / DatasetColumnArgument.WEIGHTS.value - os.makedirs(args.trained_weights_directory_path, exist_ok=True) - - train_args = TrainingArgs(args) - - trainer = MultilabelTrainer(model=model, - args=train_args.get_training_args(val_steps_to_be_made), - train_dataset=train_dataset, - eval_dataset=val_dataset, - compute_metrics=metrics.compute_metric) - trainer.train() - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/src/python/evaluation/qodana/util/__init__.py b/src/python/evaluation/qodana/util/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/python/evaluation/qodana/util/issue_types.py b/src/python/evaluation/qodana/util/issue_types.py deleted file mode 100644 index aa495e43..00000000 --- a/src/python/evaluation/qodana/util/issue_types.py +++ /dev/null @@ -1,6 +0,0 @@ -from typing import Dict - -from src.python.review.inspectors.issue import IssueType - -QODANA_CLASS_NAME_TO_ISSUE_TYPE: Dict[str, IssueType] = { -} diff --git a/src/python/evaluation/qodana/util/models.py b/src/python/evaluation/qodana/util/models.py deleted file mode 100644 index 08ce4c9f..00000000 --- a/src/python/evaluation/qodana/util/models.py +++ /dev/null @@ -1,66 +0,0 @@ -import json -from dataclasses import dataclass -from enum import Enum, unique -from typing import List - - -@dataclass(frozen=True) -class QodanaIssue: - fragment_id: int - line: int - offset: int - length: int - highlighted_element: str - description: str - problem_id: str - - def to_json(self) -> str: - issue = { - QodanaJsonField.FRAGMENT_ID.value: self.fragment_id, - QodanaJsonField.LINE.value: self.line, - QodanaJsonField.OFFSET.value: self.offset, - QodanaJsonField.LENGTH.value: self.length, - QodanaJsonField.HIGHLIGHTED_ELEMENT.value: self.highlighted_element, - QodanaJsonField.DESCRIPTION.value: self.description, - QodanaJsonField.PROBLEM_ID.value: self.problem_id, - } - return json.dumps(issue) - - @classmethod - def from_json(cls, str_json: str) -> 'QodanaIssue': - issue = json.loads(str_json) - return QodanaIssue( - fragment_id=issue[QodanaJsonField.FRAGMENT_ID.value], - line=issue[QodanaJsonField.LINE.value], - offset=issue[QodanaJsonField.OFFSET.value], - length=issue[QodanaJsonField.LENGTH.value], - highlighted_element=issue[QodanaJsonField.HIGHLIGHTED_ELEMENT.value], - description=issue[QodanaJsonField.DESCRIPTION.value], - problem_id=issue[QodanaJsonField.PROBLEM_ID.value], - ) - - @classmethod - def parse_list_issues_from_json(cls, str_json: str) -> List['QodanaIssue']: - return list(map(lambda i: QodanaIssue.from_json(i), json.loads(str_json)[QodanaJsonField.ISSUES.value])) - - -@unique -class QodanaColumnName(Enum): - INSPECTIONS = 'inspections' - ID = 'id' - INSPECTION_ID = 'inspection_id' - COUNT_ALL = 'count_all' - COUNT_UNIQUE = 'count_unique' - - -@unique -class QodanaJsonField(Enum): - FRAGMENT_ID = 'fragment_id' - LINE = 'line' - OFFSET = 'offset' - LENGTH = 'length' - HIGHLIGHTED_ELEMENT = 'highlighted_element' - DESCRIPTION = 'description' - PROBLEM_ID = 'problem_id' - - ISSUES = 'issues' diff --git a/src/python/evaluation/qodana/util/util.py b/src/python/evaluation/qodana/util/util.py deleted file mode 100644 index 3766b09d..00000000 --- a/src/python/evaluation/qodana/util/util.py +++ /dev/null @@ -1,51 +0,0 @@ -import argparse -import json -from pathlib import Path -from typing import Dict, List - -import pandas as pd -from src.python.common.tool_arguments import RunToolArgument -from src.python.evaluation.qodana.util.models import QodanaColumnName, QodanaIssue, QodanaJsonField - - -def to_json(issues: List[QodanaIssue]) -> str: - issues_json = { - QodanaJsonField.ISSUES.value: list(map(lambda i: i.to_json(), issues)), - } - return json.dumps(issues_json) - - -# Get a dictionary: Qodana inspection_id -> inspection_id from csv file with two columns: id, inspection_id -def get_inspections_dict(inspections_path: str) -> Dict[str, int]: - inspections_df = pd.read_csv(inspections_path) - inspections_dict = inspections_df.set_index(QodanaColumnName.INSPECTION_ID.value).T.to_dict('list') - for qodana_id, id_list in inspections_dict.items(): - inspections_dict[qodana_id] = id_list[0] - return inspections_dict - - -def replace_inspections_on_its_ids(issues_list: List[QodanaIssue], inspections_dict: Dict[str, int], - to_remove_duplicates: bool) -> str: - if len(issues_list) == 0: - inspections = '0' - else: - problem_id_list = list(map(lambda i: inspections_dict[i.problem_id], issues_list)) - if to_remove_duplicates: - problem_id_list = list(set(problem_id_list)) - problem_id_list.sort() - inspections = ','.join(str(p) for p in problem_id_list) - return inspections - - -def configure_model_converter_arguments(parser: argparse.ArgumentParser) -> None: - parser.add_argument(RunToolArgument.QODANA_SOLUTIONS_FILE_PATH.value.long_name, - type=lambda value: Path(value).absolute(), - help=RunToolArgument.QODANA_SOLUTIONS_FILE_PATH.value.description) - - parser.add_argument(RunToolArgument.QODANA_INSPECTIONS_PATH.value.long_name, - type=lambda value: Path(value).absolute(), - help=RunToolArgument.QODANA_INSPECTIONS_PATH.value.description) - - parser.add_argument(RunToolArgument.QODANA_DUPLICATES.value.long_name, - help=RunToolArgument.QODANA_DUPLICATES.value.description, - action='store_true') diff --git a/test/python/evaluation/__init__.py b/test/python/evaluation/__init__.py deleted file mode 100644 index 293fdcae..00000000 --- a/test/python/evaluation/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -from test.python import TEST_DATA_FOLDER - -from src.python import MAIN_FOLDER - -CURRENT_TEST_DATA_FOLDER = TEST_DATA_FOLDER / 'evaluation' - -XLSX_DATA_FOLDER = CURRENT_TEST_DATA_FOLDER / 'xlsx_files' - -TARGET_XLSX_DATA_FOLDER = CURRENT_TEST_DATA_FOLDER / 'xlsx_target_files' - -RESULTS_DIR_PATH = MAIN_FOLDER.parent / 'evaluation/results' - -EVALUATION_COMMON_DIR_PATH = CURRENT_TEST_DATA_FOLDER / 'common' - -PANDAS_UTIL_DIR_PATH = EVALUATION_COMMON_DIR_PATH / 'pandas_util' - -INSPECTORS_DIR_PATH = EVALUATION_COMMON_DIR_PATH / 'inspectors' diff --git a/test/python/evaluation/common/__init__.py b/test/python/evaluation/common/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/test/python/evaluation/common/pandas_util/__init__.py b/test/python/evaluation/common/pandas_util/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/test/python/evaluation/common/pandas_util/test_drop_duplicates.py b/test/python/evaluation/common/pandas_util/test_drop_duplicates.py deleted file mode 100644 index acd47445..00000000 --- a/test/python/evaluation/common/pandas_util/test_drop_duplicates.py +++ /dev/null @@ -1,18 +0,0 @@ -from pathlib import Path -from test.python.common_util import equal_df, get_in_and_out_list -from test.python.evaluation import PANDAS_UTIL_DIR_PATH - -import pytest -from src.python.evaluation.common.pandas_util import drop_duplicates, get_solutions_df_by_file_path - -RESOURCES_PATH = PANDAS_UTIL_DIR_PATH / 'drop_duplicates' - -IN_AND_OUT_FILES = get_in_and_out_list(RESOURCES_PATH) - - -@pytest.mark.parametrize(('in_file', 'out_file'), IN_AND_OUT_FILES) -def test(in_file: Path, out_file: Path): - in_df = get_solutions_df_by_file_path(in_file) - out_df = get_solutions_df_by_file_path(out_file) - filtered_df = drop_duplicates(in_df) - assert equal_df(out_df, filtered_df) diff --git a/test/python/evaluation/common/pandas_util/test_filter_by_language.py b/test/python/evaluation/common/pandas_util/test_filter_by_language.py deleted file mode 100644 index 25af150d..00000000 --- a/test/python/evaluation/common/pandas_util/test_filter_by_language.py +++ /dev/null @@ -1,29 +0,0 @@ -from pathlib import Path -from test.python.common_util import equal_df, get_in_and_out_list -from test.python.evaluation import PANDAS_UTIL_DIR_PATH - -import pytest -from src.python.evaluation.common.pandas_util import filter_df_by_language, get_solutions_df_by_file_path -from src.python.review.application_config import LanguageVersion -from src.python.review.common.file_system import get_name_from_path - -RESOURCES_PATH = PANDAS_UTIL_DIR_PATH / 'filter_by_language' - - -IN_FILE_TO_LANGUAGES = { - 'in_1.csv': set(LanguageVersion), - 'in_2.csv': set(), - 'in_3.csv': [LanguageVersion.PYTHON_3], - 'in_4.csv': [LanguageVersion.PYTHON_3, LanguageVersion.PYTHON_3], - 'in_5.csv': [LanguageVersion.PYTHON_3, LanguageVersion.JAVA_11], -} - -IN_AND_OUT_FILES = get_in_and_out_list(RESOURCES_PATH) - - -@pytest.mark.parametrize(('in_file', 'out_file'), IN_AND_OUT_FILES) -def test(in_file: Path, out_file: Path): - in_df = get_solutions_df_by_file_path(in_file) - out_df = get_solutions_df_by_file_path(out_file) - filtered_df = filter_df_by_language(in_df, IN_FILE_TO_LANGUAGES[get_name_from_path(str(in_file))]) - assert equal_df(out_df, filtered_df) diff --git a/test/python/evaluation/inspectors/__init__.py b/test/python/evaluation/inspectors/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/test/python/evaluation/inspectors/diffs_between_df/__init__.py b/test/python/evaluation/inspectors/diffs_between_df/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/test/python/evaluation/inspectors/diffs_between_df/test_diifs_between_df.py b/test/python/evaluation/inspectors/diffs_between_df/test_diifs_between_df.py deleted file mode 100644 index 72571842..00000000 --- a/test/python/evaluation/inspectors/diffs_between_df/test_diifs_between_df.py +++ /dev/null @@ -1,98 +0,0 @@ -from pathlib import Path -from test.python.evaluation import INSPECTORS_DIR_PATH - -import pytest -from src.python.evaluation.common.pandas_util import get_solutions_df_by_file_path -from src.python.evaluation.common.util import ColumnName -from src.python.evaluation.inspectors.common.statistics import PenaltyIssue -from src.python.evaluation.inspectors.diffs_between_df import find_diffs -from src.python.review.inspectors.inspector_type import InspectorType -from src.python.review.inspectors.issue import IssueDifficulty, IssueType - -RESOURCES_PATH = INSPECTORS_DIR_PATH / 'diffs_between_df' - -EMPTY_DIFFS = { - ColumnName.GRADE.value: [], - ColumnName.DECREASED_GRADE.value: [], - ColumnName.USER.value: 0, - ColumnName.TRACEBACK.value: {}, - ColumnName.PENALTY.value: {}, -} - -INCORRECT_GRADE_DIFFS = { - ColumnName.GRADE.value: [1, 2], - ColumnName.DECREASED_GRADE.value: [], - ColumnName.USER.value: 0, - ColumnName.TRACEBACK.value: {}, - ColumnName.PENALTY.value: {}, -} - -ISSUES = { - PenaltyIssue( - origin_class='C0305', - description='Trailing newlines', - line_no=15, - column_no=1, - type=IssueType('CODE_STYLE'), - - file_path=Path(), - inspector_type=InspectorType.UNDEFINED, - influence_on_penalty=0, - difficulty=IssueDifficulty.EASY, - ), PenaltyIssue( - origin_class='E211', - description='whitespace before \'(\'', - line_no=1, - column_no=6, - type=IssueType('CODE_STYLE'), - - file_path=Path(), - inspector_type=InspectorType.UNDEFINED, - influence_on_penalty=0, - difficulty=IssueDifficulty.EASY, - ), -} - -ISSUES_DIFFS = { - ColumnName.GRADE.value: [], - ColumnName.DECREASED_GRADE.value: [], - ColumnName.USER.value: 0, - ColumnName.TRACEBACK.value: { - 1: ISSUES, - }, - ColumnName.PENALTY.value: {}, -} - -MIXED_DIFFS = { - ColumnName.GRADE.value: [2, 3], - ColumnName.DECREASED_GRADE.value: [], - ColumnName.USER.value: 0, - ColumnName.TRACEBACK.value: { - 1: ISSUES, - }, - ColumnName.PENALTY.value: {}, -} - -DECREASED_GRADE = { - ColumnName.GRADE.value: [], - ColumnName.DECREASED_GRADE.value: [2, 3], - ColumnName.USER.value: 0, - ColumnName.TRACEBACK.value: {}, - ColumnName.PENALTY.value: {}, -} - -TEST_DATA = [ - ('old_1.csv', 'new_1.csv', EMPTY_DIFFS), - ('old_2.csv', 'new_2.csv', INCORRECT_GRADE_DIFFS), - ('old_3.csv', 'new_3.csv', ISSUES_DIFFS), - ('old_4.csv', 'new_4.csv', MIXED_DIFFS), - ('old_5.csv', 'new_5.csv', DECREASED_GRADE), -] - - -@pytest.mark.parametrize(('old_file', 'new_file', 'diffs'), TEST_DATA) -def test(old_file: Path, new_file: Path, diffs: dict): - old_df = get_solutions_df_by_file_path(RESOURCES_PATH / old_file) - new_df = get_solutions_df_by_file_path(RESOURCES_PATH / new_file) - actual_diffs = find_diffs(old_df, new_df) - assert actual_diffs == diffs diff --git a/test/python/evaluation/issues_statistics/__init__.py b/test/python/evaluation/issues_statistics/__init__.py deleted file mode 100644 index 604e3d61..00000000 --- a/test/python/evaluation/issues_statistics/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -from test.python.evaluation import CURRENT_TEST_DATA_FOLDER - -ISSUES_STATISTICS_TEST_DATA_FOLDER = CURRENT_TEST_DATA_FOLDER / 'issues_statistics' - -GET_RAW_ISSUES_DATA_FOLDER = ISSUES_STATISTICS_TEST_DATA_FOLDER / 'get_raw_issues' - -GET_RAW_ISSUES_TEST_FILES_FOLDER = GET_RAW_ISSUES_DATA_FOLDER / 'test_files' - -GET_RAW_ISSUES_TARGET_FILES_FOLDER = GET_RAW_ISSUES_DATA_FOLDER / 'target_files' - -GET_RAW_ISSUES_STATISTICS_DATA_FOLDER = ISSUES_STATISTICS_TEST_DATA_FOLDER / 'get_raw_issues_statistics' - -GET_RAW_ISSUES_STATISTICS_TEST_FILES_FOLDER = GET_RAW_ISSUES_STATISTICS_DATA_FOLDER / 'test_files' - -GET_RAW_ISSUES_STATISTICS_TARGET_FILES_FOLDER = GET_RAW_ISSUES_STATISTICS_DATA_FOLDER / 'target_files' diff --git a/test/python/evaluation/issues_statistics/test_get_raw_issues.py b/test/python/evaluation/issues_statistics/test_get_raw_issues.py deleted file mode 100644 index 976701ba..00000000 --- a/test/python/evaluation/issues_statistics/test_get_raw_issues.py +++ /dev/null @@ -1,343 +0,0 @@ -from pathlib import Path -from test.python.common_util import equal_df -from test.python.evaluation.issues_statistics import ( - GET_RAW_ISSUES_TARGET_FILES_FOLDER, GET_RAW_ISSUES_TEST_FILES_FOLDER, -) -from typing import List, Optional - -import pandas as pd -import pytest -from src.python.evaluation.common.pandas_util import get_solutions_df_by_file_path -from src.python.evaluation.issues_statistics.get_raw_issues import _filter_issues, _get_output_path, inspect_solutions -from src.python.review.inspectors.inspector_type import InspectorType -from src.python.review.inspectors.issue import ( - BaseIssue, - CodeIssue, - IssueDifficulty, - IssueType, - LineLenIssue, - MaintainabilityLackIssue, -) - -ORIGINAL_DF_NAME = 'original_df' -ORIGINAL_DF_CSV = f'{ORIGINAL_DF_NAME}.csv' -ORIGINAL_DF_XLSX = f'{ORIGINAL_DF_NAME}.xlsx' - -ORIGINAL_DF_WITH_RAW_ISSUES_CSV = f'{ORIGINAL_DF_NAME}_with_raw_issues.csv' -ORIGINAL_DF_WITH_RAW_ISSUES_XLSX = f'{ORIGINAL_DF_NAME}_with_raw_issues.xlsx' - -NEW_DF_NAME = 'new_df' - -GET_OUTPUT_PATH_TEST_DATA = [ - (Path(ORIGINAL_DF_CSV), None, Path(ORIGINAL_DF_WITH_RAW_ISSUES_CSV)), - (Path(ORIGINAL_DF_XLSX), None, Path(ORIGINAL_DF_WITH_RAW_ISSUES_XLSX)), - (Path(ORIGINAL_DF_CSV), Path(f'{NEW_DF_NAME}.csv'), Path(f'{NEW_DF_NAME}.csv')), - (Path(ORIGINAL_DF_CSV), Path(f'{NEW_DF_NAME}.xlsx'), Path(f'{NEW_DF_NAME}.xlsx')), - (Path(ORIGINAL_DF_XLSX), Path(f'{NEW_DF_NAME}.csv'), Path(f'{NEW_DF_NAME}.csv')), - (Path(ORIGINAL_DF_XLSX), Path(f'{NEW_DF_NAME}.xlsx'), Path(f'{NEW_DF_NAME}.xlsx')), - (Path(ORIGINAL_DF_CSV), Path(NEW_DF_NAME), Path(ORIGINAL_DF_WITH_RAW_ISSUES_CSV)), - (Path(ORIGINAL_DF_XLSX), Path(NEW_DF_NAME), Path(ORIGINAL_DF_WITH_RAW_ISSUES_XLSX)), - (Path(ORIGINAL_DF_CSV), Path(f'{NEW_DF_NAME}/'), Path(ORIGINAL_DF_WITH_RAW_ISSUES_CSV)), - (Path(ORIGINAL_DF_XLSX), Path(f'{NEW_DF_NAME}/'), Path(ORIGINAL_DF_WITH_RAW_ISSUES_XLSX)), - (Path(ORIGINAL_DF_CSV), Path(f'{NEW_DF_NAME}.unknown'), Path(ORIGINAL_DF_WITH_RAW_ISSUES_CSV)), - (Path(ORIGINAL_DF_XLSX), Path(f'{NEW_DF_NAME}.unknown'), Path(ORIGINAL_DF_WITH_RAW_ISSUES_XLSX)), -] - - -@pytest.mark.parametrize(('solutions_file_path', 'output_path', 'expected_output_path'), GET_OUTPUT_PATH_TEST_DATA) -def test_get_output_path(solutions_file_path: Path, output_path: Optional[Path], expected_output_path: Path): - actual_output_path = _get_output_path(solutions_file_path, output_path) - assert actual_output_path == expected_output_path - - -ISSUES_FOR_FILTERING = [ - CodeIssue( - origin_class="MissingSwitchDefaultCheck", - type=IssueType.ERROR_PRONE, - description="Some description", - file_path=Path(""), - line_no=112, - column_no=13, - inspector_type=InspectorType.CHECKSTYLE, - difficulty=IssueDifficulty.HARD, - ), - CodeIssue( - origin_class="SwitchStmtsShouldHaveDefault", - type=IssueType.ERROR_PRONE, - description="Some description", - file_path=Path(""), - line_no=112, - column_no=1, - inspector_type=InspectorType.PMD, - difficulty=IssueDifficulty.HARD, - ), - CodeIssue( - origin_class="MagicNumberCheck", - type=IssueType.INFO, - description="Some description", - file_path=Path(""), - line_no=303, - column_no=25, - inspector_type=InspectorType.CHECKSTYLE, - difficulty=IssueDifficulty.EASY, - ), - MaintainabilityLackIssue( - origin_class="SomeMaintainabilityCheck", - type=IssueType.MAINTAINABILITY, - description="Some description", - file_path=Path(""), - line_no=574, - column_no=50, - inspector_type=InspectorType.CHECKSTYLE, - maintainability_lack=0, - difficulty=IssueDifficulty.HARD, - ), - LineLenIssue( - origin_class="SomeLineLenCheck", - type=IssueType.LINE_LEN, - description="Some description", - file_path=Path(""), - line_no=139, - column_no=24, - inspector_type=InspectorType.CHECKSTYLE, - line_len=10, - difficulty=IssueDifficulty.EASY, - ), -] - -ISSUES_WITHOUT_DUPLICATES = [ - CodeIssue( - origin_class="MissingSwitchDefaultCheck", - type=IssueType.ERROR_PRONE, - description="Some description", - file_path=Path(""), - line_no=112, - column_no=13, - inspector_type=InspectorType.CHECKSTYLE, - difficulty=IssueDifficulty.HARD, - ), - CodeIssue( - origin_class="MagicNumberCheck", - type=IssueType.INFO, - description="Some description", - file_path=Path(""), - line_no=303, - column_no=25, - inspector_type=InspectorType.CHECKSTYLE, - difficulty=IssueDifficulty.EASY, - ), - MaintainabilityLackIssue( - origin_class="SomeMaintainabilityCheck", - type=IssueType.MAINTAINABILITY, - description="Some description", - file_path=Path(""), - line_no=574, - column_no=50, - inspector_type=InspectorType.CHECKSTYLE, - maintainability_lack=0, - difficulty=IssueDifficulty.HARD, - ), - LineLenIssue( - origin_class="SomeLineLenCheck", - type=IssueType.LINE_LEN, - description="Some description", - file_path=Path(""), - line_no=139, - column_no=24, - inspector_type=InspectorType.CHECKSTYLE, - line_len=10, - difficulty=IssueDifficulty.EASY, - ), -] - -ISSUES_WITHOUT_ZERO_MEASURE_ISSUES = [ - CodeIssue( - origin_class="MissingSwitchDefaultCheck", - type=IssueType.ERROR_PRONE, - description="Some description", - file_path=Path(""), - line_no=112, - column_no=13, - inspector_type=InspectorType.CHECKSTYLE, - difficulty=IssueDifficulty.HARD, - ), - CodeIssue( - origin_class="SwitchStmtsShouldHaveDefault", - type=IssueType.ERROR_PRONE, - description="Some description", - file_path=Path(""), - line_no=112, - column_no=1, - inspector_type=InspectorType.PMD, - difficulty=IssueDifficulty.HARD, - ), - CodeIssue( - origin_class="MagicNumberCheck", - type=IssueType.INFO, - description="Some description", - file_path=Path(""), - line_no=303, - column_no=25, - inspector_type=InspectorType.CHECKSTYLE, - difficulty=IssueDifficulty.EASY, - ), - LineLenIssue( - origin_class="SomeLineLenCheck", - type=IssueType.LINE_LEN, - description="Some description", - file_path=Path(""), - line_no=139, - column_no=24, - inspector_type=InspectorType.CHECKSTYLE, - line_len=10, - difficulty=IssueDifficulty.EASY, - ), -] - -ISSUES_WITHOUT_INFO_CATEGORY = [ - CodeIssue( - origin_class="MissingSwitchDefaultCheck", - type=IssueType.ERROR_PRONE, - description="Some description", - file_path=Path(""), - line_no=112, - column_no=13, - inspector_type=InspectorType.CHECKSTYLE, - difficulty=IssueDifficulty.HARD, - ), - CodeIssue( - origin_class="SwitchStmtsShouldHaveDefault", - type=IssueType.ERROR_PRONE, - description="Some description", - file_path=Path(""), - line_no=112, - column_no=1, - inspector_type=InspectorType.PMD, - difficulty=IssueDifficulty.HARD, - ), - MaintainabilityLackIssue( - origin_class="SomeMaintainabilityCheck", - type=IssueType.MAINTAINABILITY, - description="Some description", - file_path=Path(""), - line_no=574, - column_no=50, - inspector_type=InspectorType.CHECKSTYLE, - maintainability_lack=0, - difficulty=IssueDifficulty.HARD, - ), - LineLenIssue( - origin_class="SomeLineLenCheck", - type=IssueType.LINE_LEN, - description="Some description", - file_path=Path(""), - line_no=139, - column_no=24, - inspector_type=InspectorType.CHECKSTYLE, - line_len=10, - difficulty=IssueDifficulty.EASY, - ), -] - -FILTERED_ISSUES = [ - CodeIssue( - origin_class="MissingSwitchDefaultCheck", - type=IssueType.ERROR_PRONE, - description="Some description", - file_path=Path(""), - line_no=112, - column_no=13, - inspector_type=InspectorType.CHECKSTYLE, - difficulty=IssueDifficulty.HARD, - ), - LineLenIssue( - origin_class="SomeLineLenCheck", - type=IssueType.LINE_LEN, - description="Some description", - file_path=Path(""), - line_no=139, - column_no=24, - inspector_type=InspectorType.CHECKSTYLE, - line_len=10, - difficulty=IssueDifficulty.EASY, - ), -] - -FILTER_ISSUES_TEST_DATA = [ - ( - ISSUES_FOR_FILTERING, - True, # allow_duplicates - True, # allow_zero_measure_issues - True, # allow_info_issues - ISSUES_FOR_FILTERING, - ), - ( - ISSUES_FOR_FILTERING, - False, # allow_duplicates - True, # allow_zero_measure_issues - True, # allow_info_issues - ISSUES_WITHOUT_DUPLICATES, - ), - ( - ISSUES_FOR_FILTERING, - True, # allow_duplicates - False, # allow_zero_measure_issues - True, # allow_info_issues - ISSUES_WITHOUT_ZERO_MEASURE_ISSUES, - ), - ( - ISSUES_FOR_FILTERING, - True, # allow_duplicates - True, # allow_zero_measure_issues - False, # allow_info_issues - ISSUES_WITHOUT_INFO_CATEGORY, - ), - ( - ISSUES_FOR_FILTERING, - False, # allow_duplicates - False, # allow_zero_measure_issues - False, # allow_info_issues - FILTERED_ISSUES, - ), -] - - -@pytest.mark.parametrize( - ('issues', 'allow_duplicates', 'allow_zero_measure_issues', 'allow_info_issues', 'expected_issues'), - FILTER_ISSUES_TEST_DATA, -) -def test_filter_issues( - issues: List[BaseIssue], - allow_duplicates: bool, - allow_zero_measure_issues: bool, - allow_info_issues: bool, - expected_issues: List[BaseIssue], -): - assert _filter_issues(issues, allow_duplicates, allow_zero_measure_issues, allow_info_issues) == expected_issues - - -TEST_CORRECT_OUTPUT_DATA = [ - ('test_fragment_per_language.csv', 'target_fragment_per_language.csv'), - ('test_incorrect_language.csv', 'target_incorrect_language.csv'), - ('test_incorrect_code.csv', 'target_incorrect_code.csv'), - ('test_rows_with_null.csv', 'target_rows_with_null.csv'), -] - - -@pytest.mark.parametrize(('test_file', 'target_file'), TEST_CORRECT_OUTPUT_DATA) -def test_correct_output(test_file: str, target_file: str): - solutions_file_path = Path(GET_RAW_ISSUES_TEST_FILES_FOLDER / test_file) - solutions = get_solutions_df_by_file_path(solutions_file_path) - - test_dataframe = inspect_solutions( - solutions, - solutions_file_path, - allow_duplicates=False, - allow_info_issues=False, - allow_zero_measure_issues=False, - to_save_path=False, - ) - - target_dataframe = pd.read_csv(GET_RAW_ISSUES_TARGET_FILES_FOLDER / target_file) - - assert equal_df(target_dataframe, test_dataframe) diff --git a/test/python/evaluation/issues_statistics/test_get_raw_issues_statistics.py b/test/python/evaluation/issues_statistics/test_get_raw_issues_statistics.py deleted file mode 100644 index 24c10a67..00000000 --- a/test/python/evaluation/issues_statistics/test_get_raw_issues_statistics.py +++ /dev/null @@ -1,112 +0,0 @@ -from pathlib import Path -from test.python.common_util import equal_df -from test.python.evaluation.issues_statistics import ( - GET_RAW_ISSUES_STATISTICS_TARGET_FILES_FOLDER, - GET_RAW_ISSUES_STATISTICS_TEST_FILES_FOLDER, -) -from typing import Optional - -import pandas as pd -import pytest -from src.python.evaluation.common.pandas_util import get_solutions_df_by_file_path -from src.python.evaluation.issues_statistics.get_raw_issues_statistics import ( - _convert_language_code_to_language, - _get_output_folder, - DEFAULT_OUTPUT_FOLDER_NAME, - inspect_raw_issues, -) -from src.python.review.common.language import Language - -DF_PARENT_FOLDER_NAME = 'parent_folder' -DF_NAME = 'input_df' -DF_PATH = Path(DF_PARENT_FOLDER_NAME) / DF_NAME -DEFAULT_OUTPUT_PATH = Path(DF_PARENT_FOLDER_NAME) / DEFAULT_OUTPUT_FOLDER_NAME - -NEW_FOLDER = 'new_folder' - -GET_OUTPUT_FOLDER_PATH_TEST_DATA = [ - (DF_PATH, None, DEFAULT_OUTPUT_PATH), - (DF_PATH, Path(NEW_FOLDER), Path(NEW_FOLDER)), -] - - -@pytest.mark.parametrize( - ('solutions_file_path', 'output_folder', 'expected_output_folder'), - GET_OUTPUT_FOLDER_PATH_TEST_DATA, -) -def test_get_output_folder(solutions_file_path: Path, output_folder: Optional[Path], expected_output_folder: Path): - actual_output_folder = _get_output_folder(solutions_file_path, output_folder) - assert actual_output_folder == expected_output_folder - - -CONVERT_LANGUAGE_CODE_TO_LANGUAGE_TEST_DATA = [ - ('java7', 'JAVA'), - ('java8', 'JAVA'), - ('java9', 'JAVA'), - ('java11', 'JAVA'), - ('java15', 'JAVA'), - ('python3', 'PYTHON'), - ('kotlin', 'KOTLIN'), - ('javascript', 'JAVASCRIPT'), - ('some_weird_lang', 'some_weird_lang'), -] - - -@pytest.mark.parametrize(('language_code', 'expected_language'), CONVERT_LANGUAGE_CODE_TO_LANGUAGE_TEST_DATA) -def test_convert_language_code_to_language(language_code: str, expected_language: str): - actual_language = _convert_language_code_to_language(fragment_id='0', language_code=language_code) - assert actual_language == expected_language - - -INSPECT_SOLUTIONS_TEST_DATA = [ - ( - 'test_df_with_null.csv', - 'target_df_with_null_python.csv', - Language.PYTHON.value, - ), - ( - 'test_df_with_null.csv', - 'target_df_with_null_unknown.csv', - '', - ), - ( - 'test_df_with_empty_raw_issues.csv', - 'target_df_with_empty_raw_issues.csv', - Language.KOTLIN.value, - ), - ( - 'test_df_with_incorrect_language.csv', - 'target_df_with_incorrect_language.csv', - 'some_weird_lang', - ), - ( - 'test_df_single_lang.csv', - 'target_df_single_lang.csv', - Language.JAVA.value, - ), - ( - 'test_df_multi_lang.csv', - 'target_df_multi_lang_java.csv', - Language.JAVA.value, - ), - ( - 'test_df_multi_lang.csv', - 'target_df_multi_lang_js.csv', - Language.JS.value, - ), - ( - 'test_df_multi_lang.csv', - 'target_df_multi_lang_python.csv', - Language.PYTHON.value, - ), -] - - -@pytest.mark.parametrize(('test_file', 'target_file', 'lang'), INSPECT_SOLUTIONS_TEST_DATA) -def test_inspect_solutions(test_file: str, target_file: str, lang: str): - test_df = get_solutions_df_by_file_path(GET_RAW_ISSUES_STATISTICS_TEST_FILES_FOLDER / test_file) - stats = inspect_raw_issues(test_df) - - freq_stats = pd.read_csv(GET_RAW_ISSUES_STATISTICS_TARGET_FILES_FOLDER / target_file) - - assert equal_df(stats[lang], freq_stats) diff --git a/test/python/evaluation/issues_statistics/test_raw_issue_encoding_decoding.py b/test/python/evaluation/issues_statistics/test_raw_issue_encoding_decoding.py deleted file mode 100644 index 79abcbba..00000000 --- a/test/python/evaluation/issues_statistics/test_raw_issue_encoding_decoding.py +++ /dev/null @@ -1,228 +0,0 @@ -import json -import textwrap -from pathlib import Path - -import pytest -from src.python.evaluation.issues_statistics.common.raw_issue_encoder_decoder import RawIssueDecoder, RawIssueEncoder -from src.python.review.inspectors.inspector_type import InspectorType -from src.python.review.inspectors.issue import ( - BaseIssue, - BoolExprLenIssue, - CodeIssue, - CohesionIssue, - CyclomaticComplexityIssue, - FuncLenIssue, - IssueDifficulty, - IssueType, - LineLenIssue, - MaintainabilityLackIssue, -) - -FILE_PATH = 'some_file.py' -DESCRIPTION = 'Some description' - -ISSUE_AND_JSON_ISSUE = [ - ( - CodeIssue( - origin_class='SomeCodeIssueClass', - type=IssueType.CODE_STYLE, - description=DESCRIPTION, - file_path=Path(FILE_PATH), - line_no=656, - column_no=42, - inspector_type=InspectorType.CHECKSTYLE, - difficulty=IssueDifficulty.EASY, - ), - f""" - {{ - "origin_class": "SomeCodeIssueClass", - "type": "CODE_STYLE", - "description": "{DESCRIPTION}", - "file_path": "{FILE_PATH}", - "line_no": 656, - "column_no": 42, - "inspector_type": "CHECKSTYLE", - "difficulty": "EASY" - }} - """, - ), - ( - BoolExprLenIssue( - origin_class='SomeBoolExprLenIssueClass', - type=IssueType.BOOL_EXPR_LEN, - description=DESCRIPTION, - file_path=Path(FILE_PATH), - line_no=983, - column_no=428, - inspector_type=InspectorType.DETEKT, - bool_expr_len=975, - difficulty=IssueDifficulty.EASY, - ), - f""" - {{ - "origin_class": "SomeBoolExprLenIssueClass", - "type": "BOOL_EXPR_LEN", - "description": "{DESCRIPTION}", - "file_path": "{FILE_PATH}", - "line_no": 983, - "column_no": 428, - "inspector_type": "DETEKT", - "difficulty": "EASY", - "measure": 975 - }} - """, - ), - ( - FuncLenIssue( - origin_class='SomeFuncLenIssueClass', - type=IssueType.FUNC_LEN, - description=DESCRIPTION, - file_path=Path(FILE_PATH), - line_no=790, - column_no=487, - inspector_type=InspectorType.ESLINT, - func_len=909, - difficulty=IssueDifficulty.EASY, - ), - f""" - {{ - "origin_class": "SomeFuncLenIssueClass", - "type": "FUNC_LEN", - "description": "{DESCRIPTION}", - "file_path": "{FILE_PATH}", - "line_no": 790, - "column_no": 487, - "inspector_type": "ESLINT", - "difficulty": "EASY", - "measure": 909 - }} - """, - ), - ( - LineLenIssue( - origin_class='SomeLineLenIssueClass', - type=IssueType.LINE_LEN, - description=DESCRIPTION, - file_path=Path(FILE_PATH), - line_no=154, - column_no=383, - inspector_type=InspectorType.PMD, - line_len=383, - difficulty=IssueDifficulty.EASY, - ), - f""" - {{ - "origin_class": "SomeLineLenIssueClass", - "type": "LINE_LEN", - "description": "{DESCRIPTION}", - "file_path": "{FILE_PATH}", - "line_no": 154, - "column_no": 383, - "inspector_type": "PMD", - "difficulty": "EASY", - "measure": 383 - }} - """, - ), - ( - CyclomaticComplexityIssue( - origin_class='SomeCyclomaticComplexityIssueClass', - type=IssueType.CYCLOMATIC_COMPLEXITY, - description=DESCRIPTION, - file_path=Path(FILE_PATH), - line_no=670, - column_no=78, - inspector_type=InspectorType.INTELLIJ, - cc_value=229, - difficulty=IssueDifficulty.HARD, - ), - f""" - {{ - "origin_class": "SomeCyclomaticComplexityIssueClass", - "type": "CYCLOMATIC_COMPLEXITY", - "description": "{DESCRIPTION}", - "file_path": "{FILE_PATH}", - "line_no": 670, - "column_no": 78, - "inspector_type": "INTELLIJ", - "difficulty": "HARD", - "measure": 229 - }} - """, - ), - ( - CohesionIssue( - origin_class='SomeCohesionIssueClass', - type=IssueType.COHESION, - description=DESCRIPTION, - file_path=Path(FILE_PATH), - line_no=997, - column_no=386, - inspector_type=InspectorType.PYLINT, - cohesion_lack=564, - difficulty=IssueDifficulty.HARD, - ), - f""" - {{ - "origin_class": "SomeCohesionIssueClass", - "type": "COHESION", - "description": "{DESCRIPTION}", - "file_path": "{FILE_PATH}", - "line_no": 997, - "column_no": 386, - "inspector_type": "PYLINT", - "difficulty": "HARD", - "measure": 564 - }} - """, - ), - ( - MaintainabilityLackIssue( - origin_class='SomeMaintainabilityLackIssueClass', - type=IssueType.MAINTAINABILITY, - description=DESCRIPTION, - file_path=Path(FILE_PATH), - line_no=830, - column_no=542, - inspector_type=InspectorType.RADON, - maintainability_lack=431, - difficulty=IssueDifficulty.HARD, - ), - f""" - {{ - "origin_class": "SomeMaintainabilityLackIssueClass", - "type": "MAINTAINABILITY", - "description": "{DESCRIPTION}", - "file_path": "{FILE_PATH}", - "line_no": 830, - "column_no": 542, - "inspector_type": "RADON", - "difficulty": "HARD", - "measure": 431 - }} - """, - ), -] - - -@pytest.mark.parametrize(('issue', 'expected_json'), ISSUE_AND_JSON_ISSUE) -def test_encode_issue(issue: BaseIssue, expected_json: str): - assert json.dumps(issue, cls=RawIssueEncoder, indent=4) == textwrap.dedent(expected_json).strip() - - -@pytest.mark.parametrize(('expected_issue', 'json_issue'), ISSUE_AND_JSON_ISSUE) -def test_decode_issue(json_issue: str, expected_issue: BaseIssue): - assert json.loads(json_issue, cls=RawIssueDecoder) == expected_issue - - -@pytest.mark.parametrize(('issue', 'json_issue'), ISSUE_AND_JSON_ISSUE) -def test_encode_decode(issue: BaseIssue, json_issue: str): - assert json.loads(json.dumps(issue, cls=RawIssueEncoder), cls=RawIssueDecoder) == issue - - -@pytest.mark.parametrize(('issue', 'json_issue'), ISSUE_AND_JSON_ISSUE) -def test_decode_encode(issue: BaseIssue, json_issue: str): - assert ( - json.dumps(json.loads(json_issue, cls=RawIssueDecoder), cls=RawIssueEncoder, indent=4) - == textwrap.dedent(json_issue).strip() - ) diff --git a/test/python/evaluation/test_data_path.py b/test/python/evaluation/test_data_path.py deleted file mode 100644 index bae12c11..00000000 --- a/test/python/evaluation/test_data_path.py +++ /dev/null @@ -1,15 +0,0 @@ -from test.python.evaluation import XLSX_DATA_FOLDER -from test.python.evaluation.testing_config import get_testing_arguments - -import pytest -from src.python.evaluation.evaluation_config import EvaluationConfig -from src.python.evaluation.evaluation_run_tool import get_solutions_df, inspect_solutions_df - - -def test_incorrect_data_path(): - with pytest.raises(FileNotFoundError): - testing_arguments_dict = get_testing_arguments(to_add_traceback=True, to_add_tool_path=True) - testing_arguments_dict.solutions_file_path = XLSX_DATA_FOLDER / 'do_not_exist.xlsx' - config = EvaluationConfig(testing_arguments_dict) - lang_code_dataframe = get_solutions_df(config.extension, config.solutions_file_path) - assert inspect_solutions_df(config, lang_code_dataframe) diff --git a/test/python/evaluation/test_output_results.py b/test/python/evaluation/test_output_results.py deleted file mode 100644 index 44508688..00000000 --- a/test/python/evaluation/test_output_results.py +++ /dev/null @@ -1,34 +0,0 @@ -from test.python.common_util import equal_df -from test.python.evaluation import TARGET_XLSX_DATA_FOLDER, XLSX_DATA_FOLDER -from test.python.evaluation.testing_config import get_testing_arguments - -import pandas as pd -import pytest -from src.python.evaluation.evaluation_config import EvaluationConfig -from src.python.evaluation.evaluation_run_tool import get_solutions_df, inspect_solutions_df - -FILE_NAMES = [ - ('test_sorted_order.xlsx', 'target_sorted_order.xlsx', False), - ('test_sorted_order.xlsx', 'target_sorted_order.xlsx', True), - ('test_unsorted_order.xlsx', 'target_unsorted_order.xlsx', False), - ('test_unsorted_order.xlsx', 'target_unsorted_order.xlsx', True), -] - - -@pytest.mark.parametrize(('test_file', 'target_file', 'output_type'), FILE_NAMES) -def test_correct_output(test_file: str, target_file: str, output_type: bool): - - testing_arguments_dict = get_testing_arguments(to_add_tool_path=True) - testing_arguments_dict.solutions_file_path = XLSX_DATA_FOLDER / test_file - testing_arguments_dict.traceback = output_type - - config = EvaluationConfig(testing_arguments_dict) - lang_code_dataframe = get_solutions_df(config.extension, config.solutions_file_path) - test_dataframe = inspect_solutions_df(config, lang_code_dataframe) - - sheet_name = 'grades' - if output_type: - sheet_name = 'traceback' - target_dataframe = pd.read_excel(TARGET_XLSX_DATA_FOLDER / target_file, sheet_name=sheet_name) - - assert equal_df(target_dataframe, test_dataframe) diff --git a/test/python/evaluation/test_tool_path.py b/test/python/evaluation/test_tool_path.py deleted file mode 100644 index 8ee4cd07..00000000 --- a/test/python/evaluation/test_tool_path.py +++ /dev/null @@ -1,28 +0,0 @@ -from test.python.evaluation import XLSX_DATA_FOLDER -from test.python.evaluation.testing_config import get_testing_arguments - -import pytest -from src.python import MAIN_FOLDER -from src.python.evaluation.evaluation_config import EvaluationConfig -from src.python.evaluation.evaluation_run_tool import get_solutions_df, inspect_solutions_df - - -def test_correct_tool_path(): - try: - testing_arguments_dict = get_testing_arguments(to_add_traceback=True, to_add_tool_path=True) - testing_arguments_dict.solutions_file_path = XLSX_DATA_FOLDER / 'test_unsorted_order.xlsx' - config = EvaluationConfig(testing_arguments_dict) - lang_code_dataframe = get_solutions_df(config.extension, config.solutions_file_path) - inspect_solutions_df(config, lang_code_dataframe) - except Exception: - pytest.fail("Unexpected error") - - -def test_incorrect_tool_path(): - with pytest.raises(Exception): - testing_arguments_dict = get_testing_arguments(to_add_traceback=True) - testing_arguments_dict.solutions_file_path = XLSX_DATA_FOLDER / 'test_unsorted_order.xlsx' - testing_arguments_dict.tool_path = MAIN_FOLDER.parent / 'review/incorrect_path.py' - config = EvaluationConfig(testing_arguments_dict) - lang_code_dataframe = get_solutions_df(config.extension, config.solutions_file_path) - assert inspect_solutions_df(config, lang_code_dataframe) diff --git a/test/python/evaluation/test_xlsx_file_structure.py b/test/python/evaluation/test_xlsx_file_structure.py deleted file mode 100644 index f043772d..00000000 --- a/test/python/evaluation/test_xlsx_file_structure.py +++ /dev/null @@ -1,23 +0,0 @@ -from test.python.evaluation import XLSX_DATA_FOLDER -from test.python.evaluation.testing_config import get_testing_arguments - -import pytest -from src.python.evaluation.evaluation_config import EvaluationConfig -from src.python.evaluation.evaluation_run_tool import get_solutions_df, inspect_solutions_df - -FILE_NAMES = [ - 'test_wrong_column_name.xlsx', - 'test_java_no_version.xlsx', - 'test_empty_lang_cell.xlsx', - 'test_empty_table.xlsx', -] - - -@pytest.mark.parametrize('file_name', FILE_NAMES) -def test_wrong_column(file_name: str): - with pytest.raises(KeyError): - testing_arguments_dict = get_testing_arguments(to_add_traceback=True, to_add_tool_path=True) - testing_arguments_dict.solutions_file_path = XLSX_DATA_FOLDER / file_name - config = EvaluationConfig(testing_arguments_dict) - lang_code_dataframe = get_solutions_df(config.extension, config.solutions_file_path) - assert inspect_solutions_df(config, lang_code_dataframe) diff --git a/test/python/evaluation/testing_config.py b/test/python/evaluation/testing_config.py deleted file mode 100644 index 4927e2ce..00000000 --- a/test/python/evaluation/testing_config.py +++ /dev/null @@ -1,25 +0,0 @@ -from argparse import Namespace - -from src.python import MAIN_FOLDER -from src.python.evaluation.common.util import EvaluationArgument -from src.python.review.reviewers.perform_review import OutputFormat - - -def get_testing_arguments(to_add_traceback=None, to_add_tool_path=None, to_add_history=None) -> Namespace: - testing_arguments = Namespace(format=OutputFormat.JSON.value, - output_file_name=EvaluationArgument.RESULT_FILE_NAME_XLSX.value, - output_folder_path=None, - with_history=False) - if to_add_traceback: - testing_arguments.traceback = True - - if to_add_tool_path: - testing_arguments.tool_path = MAIN_FOLDER.parent / 'review/run_tool.py' - - if to_add_history: - testing_arguments.with_history = True - - testing_arguments.solutions_file_path = None - testing_arguments.to_drop_nan = False - - return testing_arguments diff --git a/test/python/quality/__init__.py b/test/python/quality/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/test/python/quality/test_penalty.py b/test/python/quality/test_penalty.py deleted file mode 100644 index a596531b..00000000 --- a/test/python/quality/test_penalty.py +++ /dev/null @@ -1,158 +0,0 @@ -from pathlib import Path -from typing import List, Set - -import pytest -from src.python.review.inspectors.inspector_type import InspectorType -from src.python.review.inspectors.issue import BaseIssue, IssueDifficulty, IssueType -from src.python.review.quality.penalty import categorize, PreviousIssue, Punisher - -punisher = Punisher([], []) - -CURRENT_ISSUES = [ - BaseIssue( - file_path=Path("."), - line_no=1, - column_no=1, - description="Possibly misspelt word", - origin_class="SC200", - inspector_type=InspectorType.FLAKE8, - type=IssueType.BEST_PRACTICES, - difficulty=IssueDifficulty.MEDIUM, - ), - BaseIssue( - file_path=Path("."), - line_no=10, - column_no=5, - description="Lambda may not be necessary", - origin_class="W0108", - inspector_type=InspectorType.FLAKE8, - type=IssueType.CODE_STYLE, - difficulty=IssueDifficulty.EASY, - ), -] - -PREVIOUS_ISSUES_CURRENT_ISSUES_EXPECTED_CLASSES = [ - ([], [], set()), - ([], CURRENT_ISSUES, set()), - ([PreviousIssue("WPS301", 50), PreviousIssue("SC200", 10)], [], set()), - ([PreviousIssue("WPS301", 50), PreviousIssue("WPS412", 10)], CURRENT_ISSUES, set()), - ([PreviousIssue("SC200", 50), PreviousIssue("WPS412", 10)], CURRENT_ISSUES, {"SC200"}), - ([PreviousIssue("SC200", 50), PreviousIssue("W0108", 10)], CURRENT_ISSUES, {"SC200", "W0108"}), -] - - -@pytest.mark.parametrize(('previous_issues', 'current_issues', 'expected_penalizing_classes'), - PREVIOUS_ISSUES_CURRENT_ISSUES_EXPECTED_CLASSES) -def test_get_penalizing_classes(previous_issues: List[PreviousIssue], - current_issues: List[BaseIssue], - expected_penalizing_classes: Set[str]): - actual = punisher._get_penalizing_classes(current_issues, previous_issues) - - assert actual == expected_penalizing_classes - - -PREVIOUS_ISSUES_CURRENT_ISSUES_EXPECTED_CATEGORIES = [ - ([], [], []), - ([], CURRENT_ISSUES, []), - ([PreviousIssue("WPS301", 50), PreviousIssue("WPS412", 10)], [], [None, None]), - ([PreviousIssue("WPS301", 50), PreviousIssue("WPS412", 10)], CURRENT_ISSUES, [None, None]), - ([PreviousIssue("SC200", 50), PreviousIssue("WPS312", 10)], CURRENT_ISSUES, [IssueType.BEST_PRACTICES, None]), - ([PreviousIssue("SC200", 50), PreviousIssue("W0108", 10)], CURRENT_ISSUES, - [IssueType.BEST_PRACTICES, IssueType.CODE_STYLE]), -] - - -@pytest.mark.parametrize(('previous_issues', 'current_issues', 'expected_categories'), - PREVIOUS_ISSUES_CURRENT_ISSUES_EXPECTED_CATEGORIES) -def test_categorize(previous_issues: List[PreviousIssue], - current_issues: List[BaseIssue], - expected_categories: List[IssueType]): - categorize(previous_issues, current_issues) - - for issue, expected_category in zip(previous_issues, expected_categories): - assert issue.category == expected_category - - -ISSUE_CLASS_EXPECTED_INFLUENCE = [ - ("SC200", 63), - ("Q146", 0), -] - - -@pytest.mark.parametrize(('issue_class', 'expected_influence'), ISSUE_CLASS_EXPECTED_INFLUENCE) -def test_get_issue_influence_on_penalty(issue_class: str, expected_influence: int): - punisher._issue_class_to_influence = {"SC200": 0.636, "WPS312": 0.1225} - - actual = punisher.get_issue_influence_on_penalty(issue_class) - - assert actual == expected_influence - - -PENALTY_COEFFICIENT_CURRENT_ISSUES_NORMALIZED_PENALTY_COEFFICIENT = [ - (8, [], 0), - (8, CURRENT_ISSUES, 0.8), -] - - -@pytest.mark.parametrize(('penalty_coefficient', 'current_issues', 'normalized_penalty_coefficient'), - PENALTY_COEFFICIENT_CURRENT_ISSUES_NORMALIZED_PENALTY_COEFFICIENT) -def test_get_normalized_penalty_coefficient(penalty_coefficient: float, - current_issues: List[BaseIssue], - normalized_penalty_coefficient): - punisher._penalty_coefficient = penalty_coefficient - - actual = punisher._get_normalized_penalty_coefficient(current_issues) - - assert actual == normalized_penalty_coefficient - - -CURRENT_ISSUES_PREVIOUS_ISSUES_EXPECTED_COEFFICIENT = [ - ([], [], 0), - (CURRENT_ISSUES, [], 0), - ([], [PreviousIssue("WPS301", 50), PreviousIssue("WPS412", 10)], 0), - (CURRENT_ISSUES, [PreviousIssue("WPS301", 50), PreviousIssue("WPS123", 10)], 0), - (CURRENT_ISSUES, [PreviousIssue("SC200", 50), PreviousIssue("WPS123", 10)], 45), - (CURRENT_ISSUES, [PreviousIssue("SC200", 50), PreviousIssue("W0108", 10)], 45 + 10), -] - - -@pytest.mark.parametrize(('current_issues', 'previous_issues', 'expected_coefficient'), - CURRENT_ISSUES_PREVIOUS_ISSUES_EXPECTED_COEFFICIENT) -def test_get_penalty_coefficient(current_issues: List[BaseIssue], - previous_issues: List[PreviousIssue], - expected_coefficient: float): - categorize(previous_issues, current_issues) - actual = punisher._get_penalty_coefficient(current_issues, previous_issues) - - assert actual == expected_coefficient - - -CURRENT_ISSUES_PREVIOUS_ISSUES_ISSUE_CLASS_EXPECTED_INFLUENCE = [ - ([], [], 'WPS312', 0), - (CURRENT_ISSUES, [], 'WPS312', 0), - (CURRENT_ISSUES, [], 'SC200', 0), - ([], [PreviousIssue("WPS301", 50), PreviousIssue("WPS412", 10)], 'WPS312', 0), - ([], [PreviousIssue("WPS301", 50), PreviousIssue("WPS412", 10)], 'WPS301', 0), - (CURRENT_ISSUES, [PreviousIssue("WPS301", 50), PreviousIssue("WPS412", 10)], 'WPS312', 0), - (CURRENT_ISSUES, [PreviousIssue("WPS301", 50), PreviousIssue("WPS412", 10)], 'WPS301', 0), - (CURRENT_ISSUES, [PreviousIssue("WPS301", 50), PreviousIssue("WPS412", 10)], 'SC200', 0), - (CURRENT_ISSUES, [PreviousIssue("SC200", 50), PreviousIssue("WPS412", 10)], 'WPS301', 0), - (CURRENT_ISSUES, [PreviousIssue("SC200", 50), PreviousIssue("WPS412", 10)], 'SC200', 100), - (CURRENT_ISSUES, [PreviousIssue("SC200", 50), PreviousIssue("WPS412", 10)], 'WPS412', 0), - (CURRENT_ISSUES, [PreviousIssue("SC200", 50), PreviousIssue("W0108", 10)], 'WPS301', 0), - (CURRENT_ISSUES, [PreviousIssue("SC200", 50), PreviousIssue("W0108", 10)], 'SC200', 81), - (CURRENT_ISSUES, [PreviousIssue("SC200", 50), PreviousIssue("W0108", 10)], 'W0108', 18), -] - - -@pytest.mark.parametrize(('current_issues', 'previous_issues', 'issue_class', 'expected_influence'), - CURRENT_ISSUES_PREVIOUS_ISSUES_ISSUE_CLASS_EXPECTED_INFLUENCE) -def test_get_issue_class_to_influence(current_issues: List[BaseIssue], - previous_issues: List[PreviousIssue], - issue_class: str, - expected_influence: int): - categorize(previous_issues, current_issues) - punisher = Punisher(current_issues, previous_issues) - actual = punisher.get_issue_influence_on_penalty(issue_class) - - assert actual == expected_influence From a5448aeac15e25dc4ddd88d2b308aa8e9870a906 Mon Sep 17 00:00:00 2001 From: "Anastasiia.Birillo" Date: Mon, 23 Aug 2021 16:19:00 +0300 Subject: [PATCH 2/6] Update build --- .github/workflows/build.yml | 38 ++++++++---------------------------- docker/dev/Dockerfile | 39 ------------------------------------- 2 files changed, 8 insertions(+), 69 deletions(-) delete mode 100644 docker/dev/Dockerfile diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e971e1aa..54dd6ade 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,56 +10,34 @@ jobs: container: stepik/hyperstyle-base:py3.8.11-java11.0.11-node14.17.3 steps: - - name: Install git - run: | - apt-get update - apt-get -y install git - - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v1 - name: Install requirements run: | pip install --no-cache-dir -r requirements-test.txt -r requirements.txt - - name: Lint with flake8 run: | # stop the build if there are Python syntax errors or undefined names flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics --exclude=.git,__pycache__,docs/source/conf.py,old,build,dist,venv,test/resources,.eggs,review.egg-info,.pytest_cache,node_modules # TODO: change max-complexity into 10 after refactoring - # TODO: remove R504, A003, E800, E402, WPS1, WPS2, WPS3, WPS4, WPS5, WPS6, H601 - flake8 . --count --max-complexity=11 --max-line-length=120 --max-doc-length=120 --ignore=R504,A003,E800,E402,W503,WPS1,WPS2,WPS3,WPS4,WPS5,WPS6,H601 --statistics --exclude=.git,__pycache__,docs/source/conf.py,old,build,dist,venv,test/resources,.eggs,review.egg-info,.pytest_cache,node_modules - - - name: Sort whitelists - run: | - for file in "whitelist.txt" "src/python/review/inspectors/flake8/whitelist.txt" - do - LC_ALL=C sort $file -o $file - done - - - name: Commit sorted whitelists - uses: EndBug/add-and-commit@v7.2.1 - with: - add: "['whitelist.txt', 'src/python/review/inspectors/flake8/whitelist.txt']" - message: 'Sort whitelists (Github Actions)' - + flake8 . --count --max-complexity=11 --max-line-length=120 --max-doc-length=120 --ignore=R504,A003,E800,E402,W503,WPS,H601 --statistics --exclude=.git,__pycache__,docs/source/conf.py,old,build,dist,venv,test/resources,.eggs,review.egg-info,.pytest_cache,node_modules - name: Set up Eslint run: | # Consistent with eslint version in Dockerfile npm install eslint@7.5.0 -g && eslint --init - - name: Test with pytest run: | pytest - + - name: Install review module + run: | + pip install . - name: Check installed module can run python linters run: | - python src/python/review/run_tool.py setup.py - + review setup.py - name: Check installed module can run java linters run: | - python src/python/review/run_tool.py test/resources/inspectors/java/test_algorithm_with_scanner.java - + review test/resources/inspectors/java/test_algorithm_with_scanner.java - name: Check installed module can run js linters run: | - python src/python/review/run_tool.py test/resources/inspectors/js/case0_no_issues.js + review test/resources/inspectors/js/case0_no_issues.js \ No newline at end of file diff --git a/docker/dev/Dockerfile b/docker/dev/Dockerfile deleted file mode 100644 index 90433662..00000000 --- a/docker/dev/Dockerfile +++ /dev/null @@ -1,39 +0,0 @@ -FROM python:3.8.2-alpine3.11 - -RUN apk --no-cache add openjdk11 --repository=http://dl-cdn.alpinelinux.org/alpine/edge/community \ - && apk add --update nodejs npm - -RUN npm i -g eslint@7.5.0 - -RUN java -version -RUN ls /usr/lib/jvm - -# Install numpy and pandas for tests -RUN apk add --no-cache python3-dev libstdc++ && \ - apk add --no-cache g++ && \ - ln -s /usr/include/locale.h /usr/include/xlocale.h && \ - pip3 install numpy && \ - pip3 install pandas - -# Other dependencies -RUN apk add bash - -# Dependencies and package installation -WORKDIR / - -COPY requirements-test.txt review/requirements-test.txt -RUN pip3 install --no-cache-dir -r review/requirements-test.txt - -COPY requirements.txt review/requirements.txt -RUN pip3 install --no-cache-dir -r review/requirements.txt - -COPY requirements-evaluation.txt review/requirements-evaluation.txt -RUN pip3 install --no-cache-dir -r review/requirements-evaluation.txt - -COPY . review - -# Container's enviroment variables -ENV JAVA_HOME=/usr/lib/jvm/java-11-openjdk -ENV PATH="$JAVA_HOME/bin:${PATH}" - -CMD ["/bin/bash"] \ No newline at end of file From 2b3c7581b3bec61fa56b3e1cfff721ec5cee5d47 Mon Sep 17 00:00:00 2001 From: "Anastasiia.Birillo" Date: Mon, 23 Aug 2021 16:34:14 +0300 Subject: [PATCH 3/6] Fix tests --- setup.py | 2 +- src/python/common/tool_arguments.py | 20 ---------- src/python/review/quality/penalty.py | 6 +++ .../review/reviewers/utils/print_review.py | 2 +- test/python/common/__init__.py | 5 --- test/python/common/file_system/__init__.py | 0 .../common/file_system/test_subprocess.py | 39 ------------------- test/resources/common/file_system/in_1.java | 8 ---- test/resources/common/file_system/in_2.py | 13 ------- 9 files changed, 8 insertions(+), 87 deletions(-) delete mode 100644 test/python/common/__init__.py delete mode 100644 test/python/common/file_system/__init__.py delete mode 100644 test/python/common/file_system/test_subprocess.py delete mode 100644 test/resources/common/file_system/in_1.java delete mode 100644 test/resources/common/file_system/in_2.py diff --git a/setup.py b/setup.py index 7a119b2e..9fbcc330 100644 --- a/setup.py +++ b/setup.py @@ -34,7 +34,7 @@ def get_requires() -> List[str]: setup( - name='hyperstyle', + name='review', version=get_version(), description='A tool for running a set of pre-configured linters and evaluating code quality.', long_description=get_long_description(), diff --git a/src/python/common/tool_arguments.py b/src/python/common/tool_arguments.py index 0edb4689..025a1006 100644 --- a/src/python/common/tool_arguments.py +++ b/src/python/common/tool_arguments.py @@ -2,7 +2,6 @@ from enum import Enum, unique from typing import List, Optional -from src.python.evaluation.common.util import ColumnName from src.python.review.application_config import LanguageVersion from src.python.review.inspectors.inspector_type import InspectorType @@ -84,22 +83,3 @@ class RunToolArgument(Enum): GROUP_BY_DIFFICULTY = ArgumentsInfo(None, '--group-by-difficulty', 'With this flag, the final grade will be grouped by the issue difficulty.') - - SOLUTIONS_FILE_PATH = ArgumentsInfo(None, 'solutions_file_path', - 'Local XLSX-file or CSV-file path. ' - 'Your file must include column-names: ' - f'"{ColumnName.CODE.value}" and ' - f'"{ColumnName.LANG.value}". Acceptable values for ' - f'"{ColumnName.LANG.value}" column are: ' - f'{LanguageVersion.PYTHON_3.value}, {LanguageVersion.JAVA_8.value}, ' - f'{LanguageVersion.JAVA_11.value}, {LanguageVersion.KOTLIN.value}.') - - DIFFS_FILE_PATH = ArgumentsInfo(None, 'diffs_file_path', - 'Path to a file with serialized diffs that were founded by diffs_between_df.py') - - QODANA_SOLUTIONS_FILE_PATH = ArgumentsInfo(None, 'solutions_file_path', - 'Csv file with solutions. This file must be graded by Qodana.') - - QODANA_INSPECTIONS_PATH = ArgumentsInfo(None, 'inspections_path', 'Path to a CSV file with inspections list.') - - QODANA_DUPLICATES = ArgumentsInfo(None, '--remove-duplicates', 'Remove duplicates around inspections') diff --git a/src/python/review/quality/penalty.py b/src/python/review/quality/penalty.py index ff4a6e13..e8cfce2f 100644 --- a/src/python/review/quality/penalty.py +++ b/src/python/review/quality/penalty.py @@ -6,6 +6,12 @@ from src.python.review.inspectors.issue import BaseIssue, IssueType from src.python.review.quality.model import QualityType + +@dataclass(frozen=True, eq=True) +class PenaltyIssue(BaseIssue): + influence_on_penalty: int + + # TODO: need testing ISSUE_TYPE_TO_PENALTY_COEFFICIENT = { IssueType.COHESION: 0.6, diff --git a/src/python/review/reviewers/utils/print_review.py b/src/python/review/reviewers/utils/print_review.py index f7aa62eb..1467c45c 100644 --- a/src/python/review/reviewers/utils/print_review.py +++ b/src/python/review/reviewers/utils/print_review.py @@ -4,12 +4,12 @@ from pathlib import Path from typing import Any, Dict, List, Union -from src.python.evaluation.inspectors.common.statistics import PenaltyIssue from src.python.review.application_config import ApplicationConfig from src.python.review.common.file_system import get_file_line from src.python.review.inspectors.inspector_type import InspectorType from src.python.review.inspectors.issue import BaseIssue, IssueDifficulty, IssueType from src.python.review.quality.model import QualityType +from src.python.review.quality.penalty import PenaltyIssue from src.python.review.reviewers.review_result import FileReviewResult, GeneralReviewResult, ReviewResult diff --git a/test/python/common/__init__.py b/test/python/common/__init__.py deleted file mode 100644 index 689b1893..00000000 --- a/test/python/common/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from test.python import TEST_DATA_FOLDER - -CURRENT_TEST_DATA_FOLDER = TEST_DATA_FOLDER / 'common' - -FILE_SYSTEM_DATA_FOLDER = CURRENT_TEST_DATA_FOLDER / 'file_system' diff --git a/test/python/common/file_system/__init__.py b/test/python/common/file_system/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/test/python/common/file_system/test_subprocess.py b/test/python/common/file_system/test_subprocess.py deleted file mode 100644 index c3a60ffd..00000000 --- a/test/python/common/file_system/test_subprocess.py +++ /dev/null @@ -1,39 +0,0 @@ -import os -from pathlib import Path -from test.python.common import FILE_SYSTEM_DATA_FOLDER -from test.python.evaluation.testing_config import get_testing_arguments -from typing import Optional - -import pytest -from src.python.evaluation.evaluation_config import EvaluationConfig -from src.python.review.application_config import LanguageVersion -from src.python.review.common.file_system import create_file, get_content_from_file -from src.python.review.common.subprocess_runner import run_in_subprocess - -INPUT_DATA = [ - ('in_1.java', LanguageVersion.JAVA_11), - ('in_2.py', LanguageVersion.PYTHON_3), -] - - -def inspect_code(config: EvaluationConfig, file: str, language: LanguageVersion, history: Optional[str] = None) -> str: - command = config.build_command(file, language.value, history) - return run_in_subprocess(command) - - -@pytest.mark.parametrize(('test_file', 'language'), INPUT_DATA) -def test_synthetic_files(test_file: str, language: LanguageVersion): - input_file = FILE_SYSTEM_DATA_FOLDER / test_file - test_args = get_testing_arguments(to_add_traceback=True, to_add_tool_path=True) - config = EvaluationConfig(test_args) - - expected_output = inspect_code(config, input_file, language) - - input_code = get_content_from_file(Path(input_file)) - actual_file = next(create_file(FILE_SYSTEM_DATA_FOLDER / f'actual_file{language.extension_by_language().value}', - input_code)) - - actual_output = inspect_code(config, actual_file, language) - os.remove(actual_file) - - assert actual_output == expected_output diff --git a/test/resources/common/file_system/in_1.java b/test/resources/common/file_system/in_1.java deleted file mode 100644 index 1e4a378b..00000000 --- a/test/resources/common/file_system/in_1.java +++ /dev/null @@ -1,8 +0,0 @@ -public class Main { - public static void main(String[] args) { - - int variable = 123456; - - System.out.println(variable); - } -} \ No newline at end of file diff --git a/test/resources/common/file_system/in_2.py b/test/resources/common/file_system/in_2.py deleted file mode 100644 index aa1637a2..00000000 --- a/test/resources/common/file_system/in_2.py +++ /dev/null @@ -1,13 +0,0 @@ -a = int(input()) -b = int(input()) -c = int(input()) -d = int(input()) - -if a > b: - print('a > b') - -if a > b and a > b: - print('a > b again') - -if a > b and a < d: - print('b < a < d') \ No newline at end of file From 234e8235b0b56447acea4b153b28992eab87afd2 Mon Sep 17 00:00:00 2001 From: "Anastasiia.Birillo" Date: Mon, 23 Aug 2021 17:13:49 +0300 Subject: [PATCH 4/6] Rename: review -> hyperstyle --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 9fbcc330..7a119b2e 100644 --- a/setup.py +++ b/setup.py @@ -34,7 +34,7 @@ def get_requires() -> List[str]: setup( - name='review', + name='hyperstyle', version=get_version(), description='A tool for running a set of pre-configured linters and evaluating code quality.', long_description=get_long_description(), From 03007dc6840edbc3b9f07db6dfef8c349dbfce51 Mon Sep 17 00:00:00 2001 From: "Anastasiia.Birillo" Date: Tue, 24 Aug 2021 15:00:46 +0300 Subject: [PATCH 5/6] Add tests --- README.md | 1 - requirements-evaluation.txt | 1 - requirements-roberta.txt | 6 -- test/python/quality/__init__.py | 0 test/python/quality/test_penalty.py | 158 ++++++++++++++++++++++++++++ 5 files changed, 158 insertions(+), 8 deletions(-) delete mode 100644 requirements-evaluation.txt delete mode 100644 requirements-roberta.txt create mode 100644 test/python/quality/__init__.py create mode 100644 test/python/quality/test_penalty.py diff --git a/README.md b/README.md index 2310f493..a20f8978 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,6 @@ Simply clone the repository and run the following commands: 1. `pip install -r requirements.txt` 2. `pip install -r requirements-test.txt` for tests -3. `pip install -r requirements-evaluation.txt` for evaluation ## Usage diff --git a/requirements-evaluation.txt b/requirements-evaluation.txt deleted file mode 100644 index 046f8026..00000000 --- a/requirements-evaluation.txt +++ /dev/null @@ -1 +0,0 @@ -plotly==4.14.3 diff --git a/requirements-roberta.txt b/requirements-roberta.txt deleted file mode 100644 index 15421cf1..00000000 --- a/requirements-roberta.txt +++ /dev/null @@ -1,6 +0,0 @@ -tqdm==4.49.0 -scikit-learn==0.24.2 -transformers==4.6.1 -tokenizers==0.10.2 -torch==1.8.1 -wandb==0.10.31 \ No newline at end of file diff --git a/test/python/quality/__init__.py b/test/python/quality/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/test/python/quality/test_penalty.py b/test/python/quality/test_penalty.py new file mode 100644 index 00000000..70717302 --- /dev/null +++ b/test/python/quality/test_penalty.py @@ -0,0 +1,158 @@ +from pathlib import Path +from typing import List, Set + +import pytest +from src.python.review.inspectors.inspector_type import InspectorType +from src.python.review.inspectors.issue import BaseIssue, IssueDifficulty, IssueType +from src.python.review.quality.penalty import categorize, PreviousIssue, Punisher + +punisher = Punisher([], []) + +CURRENT_ISSUES = [ + BaseIssue( + file_path=Path(""), + line_no=1, + column_no=1, + description="Possibly misspelt word", + origin_class="SC200", + inspector_type=InspectorType.FLAKE8, + type=IssueType.BEST_PRACTICES, + difficulty=IssueDifficulty.MEDIUM, + ), + BaseIssue( + file_path=Path(""), + line_no=10, + column_no=5, + description="Lambda may not be necessary", + origin_class="W0108", + inspector_type=InspectorType.FLAKE8, + type=IssueType.CODE_STYLE, + difficulty=IssueDifficulty.EASY, + ), +] + +PREVIOUS_ISSUES_CURRENT_ISSUES_EXPECTED_CLASSES = [ + ([], [], set()), + ([], CURRENT_ISSUES, set()), + ([PreviousIssue("WPS301", 50), PreviousIssue("SC200", 10)], [], set()), + ([PreviousIssue("WPS301", 50), PreviousIssue("WPS412", 10)], CURRENT_ISSUES, set()), + ([PreviousIssue("SC200", 50), PreviousIssue("WPS412", 10)], CURRENT_ISSUES, {"SC200"}), + ([PreviousIssue("SC200", 50), PreviousIssue("W0108", 10)], CURRENT_ISSUES, {"SC200", "W0108"}), +] + + +@pytest.mark.parametrize(('previous_issues', 'current_issues', 'expected_penalizing_classes'), + PREVIOUS_ISSUES_CURRENT_ISSUES_EXPECTED_CLASSES) +def test_get_penalizing_classes(previous_issues: List[PreviousIssue], + current_issues: List[BaseIssue], + expected_penalizing_classes: Set[str]): + actual = punisher._get_penalizing_classes(current_issues, previous_issues) + + assert actual == expected_penalizing_classes + + +PREVIOUS_ISSUES_CURRENT_ISSUES_EXPECTED_CATEGORIES = [ + ([], [], []), + ([], CURRENT_ISSUES, []), + ([PreviousIssue("WPS301", 50), PreviousIssue("WPS412", 10)], [], [None, None]), + ([PreviousIssue("WPS301", 50), PreviousIssue("WPS412", 10)], CURRENT_ISSUES, [None, None]), + ([PreviousIssue("SC200", 50), PreviousIssue("WPS312", 10)], CURRENT_ISSUES, [IssueType.BEST_PRACTICES, None]), + ([PreviousIssue("SC200", 50), PreviousIssue("W0108", 10)], CURRENT_ISSUES, + [IssueType.BEST_PRACTICES, IssueType.CODE_STYLE]), +] + + +@pytest.mark.parametrize(('previous_issues', 'current_issues', 'expected_categories'), + PREVIOUS_ISSUES_CURRENT_ISSUES_EXPECTED_CATEGORIES) +def test_categorize(previous_issues: List[PreviousIssue], + current_issues: List[BaseIssue], + expected_categories: List[IssueType]): + categorize(previous_issues, current_issues) + + for issue, expected_category in zip(previous_issues, expected_categories): + assert issue.category == expected_category + + +ISSUE_CLASS_EXPECTED_INFLUENCE = [ + ("SC200", 63), + ("Q146", 0), +] + + +@pytest.mark.parametrize(('issue_class', 'expected_influence'), ISSUE_CLASS_EXPECTED_INFLUENCE) +def test_get_issue_influence_on_penalty(issue_class: str, expected_influence: int): + punisher._issue_class_to_influence = {"SC200": 0.636, "WPS312": 0.1225} + + actual = punisher.get_issue_influence_on_penalty(issue_class) + + assert actual == expected_influence + + +PENALTY_COEFFICIENT_CURRENT_ISSUES_NORMALIZED_PENALTY_COEFFICIENT = [ + (8, [], 0), + (8, CURRENT_ISSUES, 0.8), +] + + +@pytest.mark.parametrize(('penalty_coefficient', 'current_issues', 'normalized_penalty_coefficient'), + PENALTY_COEFFICIENT_CURRENT_ISSUES_NORMALIZED_PENALTY_COEFFICIENT) +def test_get_normalized_penalty_coefficient(penalty_coefficient: float, + current_issues: List[BaseIssue], + normalized_penalty_coefficient): + punisher._penalty_coefficient = penalty_coefficient + + actual = punisher._get_normalized_penalty_coefficient(current_issues) + + assert actual == normalized_penalty_coefficient + + +CURRENT_ISSUES_PREVIOUS_ISSUES_EXPECTED_COEFFICIENT = [ + ([], [], 0), + (CURRENT_ISSUES, [], 0), + ([], [PreviousIssue("WPS301", 50), PreviousIssue("WPS412", 10)], 0), + (CURRENT_ISSUES, [PreviousIssue("WPS301", 50), PreviousIssue("WPS123", 10)], 0), + (CURRENT_ISSUES, [PreviousIssue("SC200", 50), PreviousIssue("WPS123", 10)], 45), + (CURRENT_ISSUES, [PreviousIssue("SC200", 50), PreviousIssue("W0108", 10)], 45 + 10), +] + + +@pytest.mark.parametrize(('current_issues', 'previous_issues', 'expected_coefficient'), + CURRENT_ISSUES_PREVIOUS_ISSUES_EXPECTED_COEFFICIENT) +def test_get_penalty_coefficient(current_issues: List[BaseIssue], + previous_issues: List[PreviousIssue], + expected_coefficient: float): + categorize(previous_issues, current_issues) + actual = punisher._get_penalty_coefficient(current_issues, previous_issues) + + assert actual == expected_coefficient + + +CURRENT_ISSUES_PREVIOUS_ISSUES_ISSUE_CLASS_EXPECTED_INFLUENCE = [ + ([], [], 'WPS312', 0), + (CURRENT_ISSUES, [], 'WPS312', 0), + (CURRENT_ISSUES, [], 'SC200', 0), + ([], [PreviousIssue("WPS301", 50), PreviousIssue("WPS412", 10)], 'WPS312', 0), + ([], [PreviousIssue("WPS301", 50), PreviousIssue("WPS412", 10)], 'WPS301', 0), + (CURRENT_ISSUES, [PreviousIssue("WPS301", 50), PreviousIssue("WPS412", 10)], 'WPS312', 0), + (CURRENT_ISSUES, [PreviousIssue("WPS301", 50), PreviousIssue("WPS412", 10)], 'WPS301', 0), + (CURRENT_ISSUES, [PreviousIssue("WPS301", 50), PreviousIssue("WPS412", 10)], 'SC200', 0), + (CURRENT_ISSUES, [PreviousIssue("SC200", 50), PreviousIssue("WPS412", 10)], 'WPS301', 0), + (CURRENT_ISSUES, [PreviousIssue("SC200", 50), PreviousIssue("WPS412", 10)], 'SC200', 100), + (CURRENT_ISSUES, [PreviousIssue("SC200", 50), PreviousIssue("WPS412", 10)], 'WPS412', 0), + (CURRENT_ISSUES, [PreviousIssue("SC200", 50), PreviousIssue("W0108", 10)], 'WPS301', 0), + (CURRENT_ISSUES, [PreviousIssue("SC200", 50), PreviousIssue("W0108", 10)], 'SC200', 81), + (CURRENT_ISSUES, [PreviousIssue("SC200", 50), PreviousIssue("W0108", 10)], 'W0108', 18), +] + + +@pytest.mark.parametrize(('current_issues', 'previous_issues', 'issue_class', 'expected_influence'), + CURRENT_ISSUES_PREVIOUS_ISSUES_ISSUE_CLASS_EXPECTED_INFLUENCE) +def test_get_issue_class_to_influence(current_issues: List[BaseIssue], + previous_issues: List[PreviousIssue], + issue_class: str, + expected_influence: int): + categorize(previous_issues, current_issues) + punisher = Punisher(current_issues, previous_issues) + actual = punisher.get_issue_influence_on_penalty(issue_class) + + assert actual == expected_influence From be3d1201c3e2371c04a42427480a479fb6066aba Mon Sep 17 00:00:00 2001 From: "Anastasiia.Birillo" Date: Tue, 24 Aug 2021 19:03:49 +0300 Subject: [PATCH 6/6] Delete functions --- test/python/common_util.py | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 test/python/common_util.py diff --git a/test/python/common_util.py b/test/python/common_util.py deleted file mode 100644 index 4823bec8..00000000 --- a/test/python/common_util.py +++ /dev/null @@ -1,20 +0,0 @@ -from pathlib import Path -from typing import List, Tuple - -import pandas as pd -from src.python.review.common.file_system import ( - Extension, get_all_file_system_items, match_condition, pair_in_and_out_files, -) - - -def get_in_and_out_list(root: Path, - in_ext: Extension = Extension.CSV, - out_ext: Extension = Extension.CSV) -> List[Tuple[Path, Path]]: - in_files = get_all_file_system_items(root, match_condition(rf'in_\d+{in_ext.value}')) - out_files = get_all_file_system_items(root, match_condition(rf'out_\d+{out_ext.value}')) - return pair_in_and_out_files(in_files, out_files) - - -def equal_df(expected_df: pd.DataFrame, actual_df: pd.DataFrame) -> bool: - return expected_df.reset_index(drop=True).equals( - actual_df.reset_index(drop=True)) or (expected_df.empty and actual_df.empty)

    qX*v~Ya(#|C* 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