From 1f81e3ddbee10d457cbfe0badc4e0aa0a720da65 Mon Sep 17 00:00:00 2001 From: gskorokhod Date: Mon, 30 Oct 2023 14:00:39 +0000 Subject: [PATCH 01/55] Add essence-feature-usage-stats tool --- tools/essence-feature-usage-stats/.env | 9 + .../.idea/essence-feature-usage-stats.iml | 15 + .../inspectionProfiles/Project_Default.xml | 12 + .../inspectionProfiles/profiles_settings.xml | 6 + .../.idea/misc.xml | 9 + .../.idea/ruff.xml | 6 + .../essence-feature-usage-stats/.idea/vcs.xml | 6 + .../.idea/workspace.xml | 235 + tools/essence-feature-usage-stats/README.md | 45 + tools/essence-feature-usage-stats/main.py | 27 + .../pyproject.toml | 22 + .../requirements.txt | 16 + .../stats/__init__.py | 0 .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 178 bytes .../__pycache__/essence_file.cpython-311.pyc | Bin 0 -> 9076 bytes .../essence_keyword.cpython-311.pyc | Bin 0 -> 4626 bytes .../__pycache__/essence_stats.cpython-311.pyc | Bin 0 -> 7017 bytes .../stats/essence_file.py | 151 + .../stats/essence_keyword.py | 94 + .../stats/essence_stats.py | 146 + tools/essence-feature-usage-stats/table.html | 34639 ++++++++++++++++ .../test/__init__.py | 0 .../test_essence_file.cpython-311.pyc | Bin 0 -> 2650 bytes .../__pycache__/constants.cpython-311.pyc | Bin 0 -> 2481 bytes .../test/test_data/constants.py | 177 + .../test/test_data/knapsack.essence | 9 + .../test/test_data/mydir/not_essence.txt | 0 .../test/test_essence_file.py | 37 + .../utils/__init__.py | 0 .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 178 bytes .../utils/__pycache__/colour.cpython-311.pyc | Bin 0 -> 6748 bytes .../utils/__pycache__/conjure.cpython-311.pyc | Bin 0 -> 2501 bytes .../utils/__pycache__/files.cpython-311.pyc | Bin 0 -> 2086 bytes .../utils/__pycache__/git.cpython-311.pyc | Bin 0 -> 4518 bytes .../utils/__pycache__/maths.cpython-311.pyc | Bin 0 -> 976 bytes .../utils/__pycache__/misc.cpython-311.pyc | Bin 0 -> 2020 bytes .../utils/colour.py | 91 + .../utils/conjure.py | 48 + .../utils/files.py | 35 + .../essence-feature-usage-stats/utils/git.py | 82 + .../utils/maths.py | 17 + .../essence-feature-usage-stats/utils/misc.py | 42 + .../web/__pycache__/server.cpython-311.pyc | Bin 0 -> 1193 bytes .../essence-feature-usage-stats/web/server.py | 18 + .../web/static/script.js | 49 + .../web/static/styles.css | 15 + .../web/templates/base.html | 22 + .../web/templates/index.html | 30 + .../web/templates/keyword_list.html | 21 + .../web/templates/table.html | 33 + 50 files changed, 36164 insertions(+) create mode 100644 tools/essence-feature-usage-stats/.env create mode 100644 tools/essence-feature-usage-stats/.idea/essence-feature-usage-stats.iml create mode 100644 tools/essence-feature-usage-stats/.idea/inspectionProfiles/Project_Default.xml create mode 100644 tools/essence-feature-usage-stats/.idea/inspectionProfiles/profiles_settings.xml create mode 100644 tools/essence-feature-usage-stats/.idea/misc.xml create mode 100644 tools/essence-feature-usage-stats/.idea/ruff.xml create mode 100644 tools/essence-feature-usage-stats/.idea/vcs.xml create mode 100644 tools/essence-feature-usage-stats/.idea/workspace.xml create mode 100644 tools/essence-feature-usage-stats/README.md create mode 100644 tools/essence-feature-usage-stats/main.py create mode 100644 tools/essence-feature-usage-stats/pyproject.toml create mode 100644 tools/essence-feature-usage-stats/requirements.txt create mode 100644 tools/essence-feature-usage-stats/stats/__init__.py create mode 100644 tools/essence-feature-usage-stats/stats/__pycache__/__init__.cpython-311.pyc create mode 100644 tools/essence-feature-usage-stats/stats/__pycache__/essence_file.cpython-311.pyc create mode 100644 tools/essence-feature-usage-stats/stats/__pycache__/essence_keyword.cpython-311.pyc create mode 100644 tools/essence-feature-usage-stats/stats/__pycache__/essence_stats.cpython-311.pyc create mode 100644 tools/essence-feature-usage-stats/stats/essence_file.py create mode 100644 tools/essence-feature-usage-stats/stats/essence_keyword.py create mode 100644 tools/essence-feature-usage-stats/stats/essence_stats.py create mode 100644 tools/essence-feature-usage-stats/table.html create mode 100644 tools/essence-feature-usage-stats/test/__init__.py create mode 100644 tools/essence-feature-usage-stats/test/__pycache__/test_essence_file.cpython-311.pyc create mode 100644 tools/essence-feature-usage-stats/test/test_data/__pycache__/constants.cpython-311.pyc create mode 100644 tools/essence-feature-usage-stats/test/test_data/constants.py create mode 100644 tools/essence-feature-usage-stats/test/test_data/knapsack.essence create mode 100644 tools/essence-feature-usage-stats/test/test_data/mydir/not_essence.txt create mode 100644 tools/essence-feature-usage-stats/test/test_essence_file.py create mode 100644 tools/essence-feature-usage-stats/utils/__init__.py create mode 100644 tools/essence-feature-usage-stats/utils/__pycache__/__init__.cpython-311.pyc create mode 100644 tools/essence-feature-usage-stats/utils/__pycache__/colour.cpython-311.pyc create mode 100644 tools/essence-feature-usage-stats/utils/__pycache__/conjure.cpython-311.pyc create mode 100644 tools/essence-feature-usage-stats/utils/__pycache__/files.cpython-311.pyc create mode 100644 tools/essence-feature-usage-stats/utils/__pycache__/git.cpython-311.pyc create mode 100644 tools/essence-feature-usage-stats/utils/__pycache__/maths.cpython-311.pyc create mode 100644 tools/essence-feature-usage-stats/utils/__pycache__/misc.cpython-311.pyc create mode 100644 tools/essence-feature-usage-stats/utils/colour.py create mode 100644 tools/essence-feature-usage-stats/utils/conjure.py create mode 100644 tools/essence-feature-usage-stats/utils/files.py create mode 100644 tools/essence-feature-usage-stats/utils/git.py create mode 100644 tools/essence-feature-usage-stats/utils/maths.py create mode 100644 tools/essence-feature-usage-stats/utils/misc.py create mode 100644 tools/essence-feature-usage-stats/web/__pycache__/server.cpython-311.pyc create mode 100644 tools/essence-feature-usage-stats/web/server.py create mode 100644 tools/essence-feature-usage-stats/web/static/script.js create mode 100644 tools/essence-feature-usage-stats/web/static/styles.css create mode 100644 tools/essence-feature-usage-stats/web/templates/base.html create mode 100644 tools/essence-feature-usage-stats/web/templates/index.html create mode 100644 tools/essence-feature-usage-stats/web/templates/keyword_list.html create mode 100644 tools/essence-feature-usage-stats/web/templates/table.html diff --git a/tools/essence-feature-usage-stats/.env b/tools/essence-feature-usage-stats/.env new file mode 100644 index 000000000..cd8553056 --- /dev/null +++ b/tools/essence-feature-usage-stats/.env @@ -0,0 +1,9 @@ +ESSENCE_DIR=/home/mayday/Coding/VIP/EssenceCatalog +CONJURE_DIR=/home/mayday/Coding/VIP/conjure-v2.5.0-linux-with-solvers +ESSENCE_EXAMPLES_REPO=https://github.com/conjure-cp/EssenceCatalog.git +KEYWORD_BLOCKLIST="mInfo,finds,givens,enumGivens,enumLettings,lettings, + unnameds,strategyQ,Auto,Interactive,strategyA,trailCompact, + nameGenState,nbExtraGivens,representations,representationsTree, + originalDomains,trailGeneralised,trailVerbose,trailRewrites, + mLanguage,language,version,mStatements,Name,Declaration,FindOrGiven, + SuchThat,Op" \ No newline at end of file diff --git a/tools/essence-feature-usage-stats/.idea/essence-feature-usage-stats.iml b/tools/essence-feature-usage-stats/.idea/essence-feature-usage-stats.iml new file mode 100644 index 000000000..da8a8ad5c --- /dev/null +++ b/tools/essence-feature-usage-stats/.idea/essence-feature-usage-stats.iml @@ -0,0 +1,15 @@ + + + + + + + + \ No newline at end of file diff --git a/tools/essence-feature-usage-stats/.idea/inspectionProfiles/Project_Default.xml b/tools/essence-feature-usage-stats/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 000000000..19069e5c6 --- /dev/null +++ b/tools/essence-feature-usage-stats/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,12 @@ + + + + \ No newline at end of file diff --git a/tools/essence-feature-usage-stats/.idea/inspectionProfiles/profiles_settings.xml b/tools/essence-feature-usage-stats/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 000000000..105ce2da2 --- /dev/null +++ b/tools/essence-feature-usage-stats/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/tools/essence-feature-usage-stats/.idea/misc.xml b/tools/essence-feature-usage-stats/.idea/misc.xml new file mode 100644 index 000000000..77492c073 --- /dev/null +++ b/tools/essence-feature-usage-stats/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/tools/essence-feature-usage-stats/.idea/ruff.xml b/tools/essence-feature-usage-stats/.idea/ruff.xml new file mode 100644 index 000000000..a6efb6112 --- /dev/null +++ b/tools/essence-feature-usage-stats/.idea/ruff.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/tools/essence-feature-usage-stats/.idea/vcs.xml b/tools/essence-feature-usage-stats/.idea/vcs.xml new file mode 100644 index 000000000..35eb1ddfb --- /dev/null +++ b/tools/essence-feature-usage-stats/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/tools/essence-feature-usage-stats/.idea/workspace.xml b/tools/essence-feature-usage-stats/.idea/workspace.xml new file mode 100644 index 000000000..6ba431a5c --- /dev/null +++ b/tools/essence-feature-usage-stats/.idea/workspace.xml @@ -0,0 +1,235 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { + "associatedIndex": 5 +} + + + + { + "keyToString": { + "RunOnceActivity.OpenProjectViewOnStart": "true", + "RunOnceActivity.ShowReadmeOnStart": "true", + "WebServerToolWindowFactoryState": "false", + "git-widget-placeholder": "master", + "list.type.of.created.stylesheet": "CSS", + "node.js.detected.package.eslint": "true", + "node.js.detected.package.tslint": "true", + "node.js.selected.package.eslint": "(autodetect)", + "node.js.selected.package.tslint": "(autodetect)", + "nodejs_package_manager_path": "npm", + "settings.editor.selected.configurable": "preferences.pluginManager", + "ts.external.directory.path": "/home/mayday/.local/share/JetBrains/Toolbox/apps/pycharm-professional/plugins/javascript-impl/jsLanguageServicesImpl/external", + "vue.rearranger.settings.migration": "true" + }, + "keyToStringList": { + "stardust.markdown.MarkdownSplitEditorSuppressor:keyList": [ + ] + } +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1697476837664 + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/essence-feature-usage-stats/README.md b/tools/essence-feature-usage-stats/README.md new file mode 100644 index 000000000..f28f6d4ea --- /dev/null +++ b/tools/essence-feature-usage-stats/README.md @@ -0,0 +1,45 @@ +# essence-feature-usage-stats + +## About + +This is an internal tool for the [conjure-oxide](https://github.com/conjure-cp/conjure-oxide) project. + +It does the following: +- Given a directory containing Essence files, go through it and count how often every Essence language feature is used +- Display this data as a simple web page with a table + +The purpose of this is to make it easier to find Essence examples to test specific Essence language features, which should be useful over the course of rewriting the conjure tool stack in Rust + + +## Usage + +> This is heavily WIP and I am planning to make this more usable in the future. +> Eventually, this will be a Flask web server to host the web page, a better frontend (to make it searchable, sortable, etc), and the page will auto-update on changes to the relevant Essence example repos + +For now, though: + +- Put paths to conjure directory and Essence file directory in .env +- Run the main.py file +- See the generated HTML file + + +## ToDo + +- [x] Get basic stats in JSON format +- [x] Get basic stats as HTML table +- [ ] Table sorting +- [x] Code refactoring +- [ ] Documentation +- [ ] Show/Hide table rows/columns +- [ ] Web server for hosting the HTML page +- 🏗️ GitHub Actions integration +- [x] Extra stats, e.g. file line count +- [ ] Sorting using these stats + + +------------------------------------------ + +- Georgii Skorokhod and Hannah Zheng, 2023 +- University of St Andrews +- Developed as part of a Vertically Integrated Project by Ozgur Akgun et al +- (See [main repos](https://github.com/conjure-cp)) diff --git a/tools/essence-feature-usage-stats/main.py b/tools/essence-feature-usage-stats/main.py new file mode 100644 index 000000000..e0ebdcd26 --- /dev/null +++ b/tools/essence-feature-usage-stats/main.py @@ -0,0 +1,27 @@ +import os +from pathlib import Path + +from dotenv import load_dotenv + +from stats.essence_stats import EssenceStats +from web.server import create_server + +ENV_PATH = Path("./.env").resolve() +load_dotenv(dotenv_path=ENV_PATH) + +KEYWORD_BLOCKLIST = [x.strip() for x in os.getenv("KEYWORD_BLOCKLIST").split(",")] +ESSENCE_DIR = os.getenv("ESSENCE_DIR") +CONJURE_DIR = os.getenv("CONJURE_DIR") +ESSENCE_EXAMPLES_REPO = os.getenv("ESSENCE_EXAMPLES_REPO") +CONJURE_BIN = Path(CONJURE_DIR) / "conjure" + +if __name__ == "__main__": + stats = EssenceStats( + ESSENCE_DIR, + CONJURE_BIN, + ESSENCE_EXAMPLES_REPO, + blocklist=KEYWORD_BLOCKLIST, + ) + + app = create_server(stats) + app.run() diff --git a/tools/essence-feature-usage-stats/pyproject.toml b/tools/essence-feature-usage-stats/pyproject.toml new file mode 100644 index 000000000..8e329f4ba --- /dev/null +++ b/tools/essence-feature-usage-stats/pyproject.toml @@ -0,0 +1,22 @@ +[tool.ruff] +# 1. Enable flake8-bugbear (`B`) rules, in addition to the defaults. +select = ["E", "F", "B", "I", "N", "UP", + "A", "COM", "C4", "ISC001", "ISC002", + "ICN", "G", "INP", "PIE", "Q", "RSE", + "RET", "SIM", "ARG", + "FIX", "PL", "TRY", "FLY", "PERF", + "RUF", "ERA", "PTH", "SLF"] + +# 2. Avoid enforcing line-length violations (`E501`) +ignore = ["E501"] + +# 3. Unfixable rules +# ERA: Don't autoremove all commented code, I may actually need it +unfixable = ["ERA"] + +exclude = ["EssenceCatalog"] + +# 4. Ignore `E402` (import violations) in all `__init__.py` files, and in `path/to/file.py`. +[tool.ruff.per-file-ignores] +"web/colour.py" = ["PLR2004"] +#"**/{tests,docs,tools}/*" = ["E402"] diff --git a/tools/essence-feature-usage-stats/requirements.txt b/tools/essence-feature-usage-stats/requirements.txt new file mode 100644 index 000000000..cd2c8920d --- /dev/null +++ b/tools/essence-feature-usage-stats/requirements.txt @@ -0,0 +1,16 @@ +blinker==1.6.3 +click==8.1.7 +Flask==3.0.0 +gitdb==4.0.10 +GitPython==3.1.37 +itsdangerous==2.1.2 +Jinja2==3.1.2 +markdown-it-py==3.0.0 +MarkupSafe==2.1.3 +mdurl==0.1.2 +Pygments==2.16.1 +python-dotenv==1.0.0 +rich==13.6.0 +smmap==5.0.1 +tqdm==4.66.1 +Werkzeug==3.0.0 diff --git a/tools/essence-feature-usage-stats/stats/__init__.py b/tools/essence-feature-usage-stats/stats/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tools/essence-feature-usage-stats/stats/__pycache__/__init__.cpython-311.pyc b/tools/essence-feature-usage-stats/stats/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..67fe385cd4b77b1bee769d7b853d02d55ea5f3c6 GIT binary patch literal 178 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 literal 0 HcmV?d00001 diff --git a/tools/essence-feature-usage-stats/stats/__pycache__/essence_keyword.cpython-311.pyc b/tools/essence-feature-usage-stats/stats/__pycache__/essence_keyword.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..65791e8e5b57c143ada3e04e2d18ba394f7ae843 GIT binary patch literal 4626 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 F{tMwCIZglo literal 0 HcmV?d00001 diff --git a/tools/essence-feature-usage-stats/stats/essence_file.py b/tools/essence-feature-usage-stats/stats/essence_file.py new file mode 100644 index 000000000..1683a8810 --- /dev/null +++ b/tools/essence-feature-usage-stats/stats/essence_file.py @@ -0,0 +1,151 @@ +import os +from pathlib import Path +from typing import Generator + +from utils.conjure import get_essence_file_ast +from utils.files import count_lines, trim_path +from utils.misc import flat_keys_count + + +class EssenceFileError(ValueError): + pass + + +class EssenceFileInvalidPathError(EssenceFileError): + def __init__(self, fpath): + super().__init__(f"Not a valid Essence file: {fpath}") + + +class EssenceFileNotParsableError(EssenceFileError): + def __init__(self, fpath, msg=None): + message = f"Essence file could not be parsed: {fpath}" + if msg: + message += f", reason: {msg}" + + super().__init__(message) + + +class EssenceInvalidDirectoryError(ValueError): + def __init__(self, dir_path): + super().__init__(f"The provided path '{dir_path}' is not a valid directory") + + +def find_essence_files(dir_path: str | Path): + """ + Find all essence files in a given directory and return a list of full paths to them + :param dir_path: path to directory + :return: a generator of paths to essence files + """ + + dir_path = Path(dir_path) + + # Ensure the directory path is valid + if not dir_path.is_dir(): + raise EssenceInvalidDirectoryError + + # Walk through the directory and its subdirectories + for root, _, files in os.walk(dir_path): + for file in files: + fpath = Path(root) / file + if fpath.is_file() and fpath.suffix == ".essence": + yield fpath + + +class EssenceFile: + """ + EssenceFile stores keyword counts and number of lines for a given file "fpath". + """ + + def __init__(self, fpath: str | Path, conjure_bin_path, blocklist=None): + """ + Constructs a EssenceFile object from a given file path + """ + + fpath = Path(fpath).resolve() + + if not (fpath.is_file() and fpath.suffix == ".essence"): + raise EssenceFileInvalidPathError(fpath) + try: + self._fpath = Path.resolve(fpath) + self._ast = get_essence_file_ast( + self._fpath, + conjure_bin_path=conjure_bin_path, + ) + self._keyword_counts = flat_keys_count(self._ast, blocklist) + self._n_lines = count_lines(fpath) + except Exception as e: + raise EssenceFileNotParsableError(fpath, str(e)) from e + + @property + def path(self) -> Path: + return self._fpath + + @property + def ast(self) -> dict: + return self._ast + + @property + def keyword_counts(self) -> dict[str, int]: + return self._keyword_counts + + @property + def keywords(self) -> set: + return set(self._keyword_counts.keys()) + + @property + def n_lines(self) -> int: + return self._n_lines + + def get_str_path(self, depth=0) -> str: + """ + Get a formatted path to this essence file (and optionally trim it) + :param depth: (optional) trim path, leaving a suffix of this size + :return: formatted path to file + """ + return trim_path(self._fpath, depth) + + def get_uses(self, keyword: str) -> int: + """ + Get the number of times a given keyword is used in the file + :param keyword: (str) the Essence keyword to count + :return: how many times this keyword is used in the file + """ + return self._keyword_counts.get(keyword, 0) + + def __hash__(self): + return hash(self._fpath) + + def __eq__(self, other): + return self._fpath == other._fpath + + def __str__(self): + return f"EssenceFile({self._fpath}): {self.n_lines} lines" + + def as_json(self, path_depth=0) -> dict: + """ + Get file stats in json format + :param path_depth: (optional) trim path, leaving a suffix of this size + :return: (dict) file stats, including its path, number of lines, keywords and AST + """ + return { + "path": self.get_str_path(path_depth), + "ast": self._ast, + "keyword_counts": self._keyword_counts, + "n_lines": self.n_lines, + } + + @staticmethod + def get_essence_files_from_dir( + dir_path: str | Path, conjure_bin_path: str | Path, blocklist=None + ): + """ + :param dir_path: path to directory with essence files + :param conjure_bin_path: a path to conjure binary + :param blocklist: a list of Essence keywords to ignore + """ + for fpath in find_essence_files(dir_path): + try: + file = EssenceFile(fpath, conjure_bin_path, blocklist=blocklist) + yield file + except Exception as e: # noqa: PERF203 + print(f'Could not process file "{fpath}", throws exception: {e}') diff --git a/tools/essence-feature-usage-stats/stats/essence_keyword.py b/tools/essence-feature-usage-stats/stats/essence_keyword.py new file mode 100644 index 000000000..41ed6cb33 --- /dev/null +++ b/tools/essence-feature-usage-stats/stats/essence_keyword.py @@ -0,0 +1,94 @@ +from stats.essence_file import EssenceFile +from utils.colour import * # noqa: F403 + + +class EssenceKeyword: + """ + EssenceKeyword stores, for a particular keyword "name", the file uses of that keyword, and aggregate statistics. + """ + + # ToDo use python getters / setters instead of java style, + # search: "python function as attribute" or ask Nik + + # ToDo some attrs should be private? + + def __init__(self, name: str, files=None): + if files is None: + files = [] + + self.name = name + self.total_usages = 0 + self.min_usages = None + self.max_usages = None + + self.file_usages = {} + for file in files: + self.add_file(file) + + def add_file(self, file: EssenceFile): + if file not in self.file_usages and file.get_uses(self.name) > 0: + usages = file.get_uses(self.name) + self.file_usages[file] = usages + self.total_usages += usages + + if self.max_usages is None: + self.max_usages = usages + else: + self.max_usages = max(self.max_usages, usages) + + if self.min_usages is None: + self.min_usages = usages + else: + self.min_usages = min(self.min_usages, usages) + + @property + def files(self): + return set(self.file_usages.keys()) + + @property + def num_files_using_feature(self) -> int: + return len(self.files) + + @property + def avg_usages(self) -> float: + return float(self.total_usages) / float( + self.num_files_using_feature, + ) + + def get_file_paths(self, depth=0) -> list: + return [x.get_str_path(depth) for x in self.files] + + def get_usages_in_file(self, file) -> int: + return file.get_uses(self.name) + + def as_json(self, path_depth=0) -> dict: + return { + "name": self.name, + "used_in_files": self.get_file_paths(path_depth), + "max_usages_in_file": self.max_usages, + "min_usages_in_file": self.min_usages, + "avg_usages_per_file": self.avg_usages, + "total_usages": self.total_usages, + } + + def get_colour(self, n_uses: int) -> Colour: # noqa: F405 + avg = int(self.avg_usages) + + if n_uses == 0: + return RED # noqa: F405 + if n_uses < avg: + return get_linear_gradient_value( # noqa: F405 + n_uses, + self.min_usages, + avg, + HOT_ORANGE, # noqa: F405 + YELLOW, # noqa: F405 + ) + + return get_linear_gradient_value( # noqa: F405 + n_uses, + avg, + self.max_usages, + YELLOW, # noqa: F405 + GREEN, # noqa: F405 + ) diff --git a/tools/essence-feature-usage-stats/stats/essence_stats.py b/tools/essence-feature-usage-stats/stats/essence_stats.py new file mode 100644 index 000000000..2dbeb3a44 --- /dev/null +++ b/tools/essence-feature-usage-stats/stats/essence_stats.py @@ -0,0 +1,146 @@ +from pathlib import Path +from typing import Optional + +from stats.essence_keyword import EssenceKeyword +from stats.essence_file import EssenceFile +from utils.git import InvalidGitRemoteUrlError, sync_repo + +KeywordName: type = str +FilePath: type = str + +MOST_USED = "most-used" +AVG_USES = "avg-uses" +MOST_LINES = "most-lines" + + +class EssenceStats: + """ + Class that stores stats for a given directory with + """ + + # ToDo use python getters / setters instead of java style, + # search: "python function as attribute" or ask Nik + + # ToDo some attrs should be private? + + def __init__( # noqa: PLR0913 + self, + essence_dir: str, + conjure_bin: str, + remote_repo_url=None, + remote_branch="master", + remote_name="origin", + blocklist: Optional[list[KeywordName]] = None, + ): + if blocklist is None: + blocklist = [] + self.essence_dir = Path(essence_dir).resolve() + self.conjure_bin = Path(conjure_bin).resolve() + + self.blocklist = blocklist + + self.essence_keywords: dict[KeywordName, EssenceKeyword] = {} + self.essence_files: dict[FilePath, EssenceFile] = {} + + self._remote_repo_url = remote_repo_url + self._remote_branch = remote_branch + self._remote_name = remote_name + self._repo = None + + if remote_repo_url is not None: + self.sync_repo(remote_repo_url, remote_branch, remote_name) + + # just incase its a local file + # normally sync_repo calls this for us + self._update_stats() + + def _update_stats(self): + for file in EssenceFile.get_essence_files_from_dir( + self.essence_dir, + self.conjure_bin, + blocklist=self.blocklist, + ): + self.essence_files[file.get_str_path()] = file + + for keyword in file.keywords: + if keyword not in self.essence_keywords: + self.essence_keywords[keyword] = EssenceKeyword(keyword) + self.essence_keywords[keyword].add_file(file) + + def sync_repo( + self, + remote_repo_url: Optional[str] = None, + remote_branch: Optional[str] = None, + remote_name: Optional[str] = None, + ) -> None: + """ + Sync to an upstream git repository. + If an upstream repository is not given, the upstream repo specified at EssenceStats creation is used. + """ + if remote_repo_url is None: + remote_repo_url = self._remote_repo_url + if remote_branch is None: + remote_branch = self._remote_branch + if remote_name is None: + remote_name = self._remote_name + + try: + self._repo = sync_repo( + self.essence_dir, + remote_repo_url, + remote_name=remote_name, + branch=remote_branch, + ) + self._update_stats() + + self._remote_repo_url = remote_repo_url + self._remote_branch = remote_branch + self._remote_name = remote_name + except Exception as e: + raise InvalidGitRemoteUrlError(remote_repo_url) from e + + def get_essence_files( + self, + sort_mode: Optional[str] = None, + reverse: bool = True, + ) -> list[EssenceFile]: + ans = list(self.essence_files.values()) + + match sort_mode: + case "most-lines": + ans.sort(key=lambda x: x.n_lines, reverse=reverse) + case _: + pass + + return ans + + def get_essence_keywords( + self, + sort_mode: Optional[str] = None, + reverse: bool = True, + ) -> list[EssenceKeyword]: + ans = list(self.essence_keywords.values()) + + match sort_mode: + case "most-used": + ans.sort(key=lambda x: x.total_usages, reverse=reverse) + case "avg-uses": + ans.sort(key=lambda x: x.avg_usages, reverse=reverse) + case _: + pass + + return ans + + def get_stats_for_file(self, fpath: str) -> Optional[EssenceFile]: + return self.essence_files.get(fpath, None) + + def get_stats_for_keyword(self, keyword: str) -> Optional[EssenceKeyword]: + return self.essence_keywords.get(keyword, None) + + def as_json(self, path_depth=0) -> dict: + return { + "essence_files": [x.as_json(path_depth) for x in self.get_essence_files()], + "essence_keywords": [ + x.as_json(path_depth) for x in self.get_essence_keywords() + ], + } diff --git a/tools/essence-feature-usage-stats/table.html b/tools/essence-feature-usage-stats/table.html new file mode 100644 index 000000000..b444d5d49 --- /dev/null +++ b/tools/essence-feature-usage-stats/table.html @@ -0,0 +1,34639 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Essence FileReferenceTagIntConstantConstantIntDomainIntRangeBoundedSingleDomainReferenceAbstractLiteralGeneratorMkOpImageMkOpIndexingComprehensionAbsLitMatrixMkOpAndGenDomainNoReprMkOpSumMkOpEqLettingSizeAttr_NoneMkOpMinusRangeLowerBoundedDomainGenInExprDomainFunctionAbsLitTupleMkOpProductMkOpTwoBarsMkOpInAbsPatTupleMkOpImplyDomainSetDomainTupleMkOpLeqDomainMatrixDomainEnumMkOpOrAbsLitSetConditionMkOpNeqSizeAttr_SizeMkOpDivMkOpNotMkOpModObjectiveMkOpRangeMkOpToIntMkOpMaxMkOpDefinedRangeSingleMkOpGeqMkOpRelationProjMkOpLtMkOpPowMkOpActiveMkOpIntersectMkOpToSetWhereDomainSequenceMkOpGtMkOpPreImageDomainRelationLettingDomainDefnUnnamedMkOpAttributeAsConstraintMkOpRestrictMkOpNegateMkOpPowerSetAbsPatSetMkOpMinDomainBoolGivenDomainDefnEnumMkOpAllDiffMkOpSlicingMkOpPartsSizeAttr_MaxSizeSizeAttr_MinMaxSizepartsSizeisRegularpartsNumDomainPartitionLettingDomainDefnEnumMkOpLexLeqMkOpUnionMkOpIffConstantAbstractConstantBoolMkOpFreqSizeAttr_MinSizeSearchOrderBranchingOnDomainIntEDomainMSetMkOpSubsetEqMkOpTogetherMkOpPartyMkOpApartMkOpFlattenDomainVariantOccurAttr_NoneOccurAttr_MaxOccur
params/gen.essence32621215410010010100001000110000000010000000000000011300000000000000000000000000000000000000000000000000
csplib-prob133/knapsack.essence7300302002202000200300022000000101030000000010000000000000000000000000100000000000000000000000000000
csplib-prob005/LowAutocorrelationBinarySequences.essence9181111752022202202300111001010000000000000000010000200010000000000010000000000000000000000000000000000
csplib-prob022/BusDriverScheduling.essence4000001001001010000400010001100200020000000010000000000000000000000000100200111100000000000000000000
VanDerWaerdenNumbers/VanDerWaerden.essence133019191184044004443300143010010100000000000111000000000000000000000000000000100111100000000000000000000
csplib-prob003/QG3.essence13844424934303034011110301300000030000000000000000200000000000002200000000000000000000000000000000000
csplib-prob003/QG4.essence13844424934303034011110301300000030000000000000000200000000000002200000000000000000000000000000000000
csplib-prob003/QG5.essence13844424934303034011110301300000030000000000000000200000000000002200000000000000000000000000000000000
csplib-prob003/QG6.essence15844424944403034011110301400000030000000000000000200000000000002200000000000000000000000000000000000
csplib-prob003/QG7.essence15844424944403034011110301400000030000000000000000200000000000002200000000000000000000000000000000000
csplib-prob007/AllIntervalSeries.essence11201313761211301111112251202001000000000000000000000000000000000000000000000000000000000000000000000000
knapsack/knapsack.essence11511413003303001310300022000000101040000000010000000000000000000000000100000000000000000000000000000
csplib-prob015/SchursLemma.essence121388534224002221111102130000001100001001200000000000000000000000000000000000111100000000000000010000
csplib-prob025/Lam.essence15755217917086137330000000000000000201011003000300000000000000010000001000000000000000000000000000000
csplib-prob041/NFractionsPuzzle.essence125137371413341034031013722111201050000001000000020000100000000000000000000000000000000000000000000000000000
csplib-prob054/nqueens.essence9422212402201012001121101002000000000011000000000000100000000000000000000000000000000000000000000000
csplib-prob010/SocialGolfersProblem.essence111066413323002112100003010010000101000111300000100000000000000010000000000000111100000000000001000000
csplib-prob019/MagicSquares.essence24201313767927087227742021200000000000200000000000000000030000000000000000010000000000000000000000001000
tsp/tsp.essence21201111974042602201212110011210020010000000100010010000000000100000000000000000000000000000000000000000
csplib-prob034/WarehouseLocation.essence131799833823403112302405214101000011000000000011000000000000001000000000000000000000000000000000000000
csplib-prob036/FixedLengthErrorCorrectingCodes.essence151588743323302111102203222110000110030011100000000010000000000000000000100000000000000000000000000000
csplib-prob053-GracefulGears/GracefulGears.essence2050363614132692602922235241402072000000000010010200000000000000000000000000000000000000000000000000000000
csplib-prob053/GracefulGears.essence2050363614132692602922235241402072000000000010010200000000000000000000000000000000000000000000000000000000
csplib-prob001/CarSequencing.essence202916161374924504234313526304001000001000000000000100001000000001100000000000000000000000000000000000000
csplib-prob026/SportsTournamentScheduling.essence191412122110928007156120021020011220101001111220100100003000031000130000000000000000000000000000000000000
csplib-prob053-GracefulWheelGraphs/GracefulWheelGraphs.essence19271818982642602422225241402022000000000000000100000000000000000000000000000000000000000000000000000000
csplib-prob053/GracefulWheelGraphs.essence19271818982642602422225241402022000000000000000100000000000000000000000000000000000000000000000000000000
csplib-prob009/PerfectSquarePlacement.essence4340262614125714416031033712322212021010000001410000000020020200001110000000020000000000000000000000000000000
csplib-prob030/BalancedAcademicCurriculumProblem.essence252413131146926405254202307222002001002000000000000000021100000004100000000000000000000000000000000000000
csplib-prob038/steelMill.essence191055517307307020302504172001000101010010000010010020000010000000000010100300111100000000000000000000
csplib-prob053-GracefulHelms/GracefulHelms.essence2745313114133793903933435251402053000000000000000100000000000000000000000000000000000000000000000000000000
csplib-prob053/GracefulHelms.essence2745313114133793903933435251402053000000000000000100000000000000000000000000000000000000000000000000000000
csplib-prob006/GolombRuler.essence15644214022002020001021020000101100000202100010010000010000000000002200000000000000000000000000000000
csplib-prob013/PPP-function.essence261277519709508062231304173001001202000000100011100000100000001000000000000000000000000001000000000000
paramgen/TailAssignment-paramgen.essence27191212777925105272005400231000122107000000001000001000000000010200000000000000000000000000000000000000
csplib-prob006-decision/GolombRuler.essence14744314022002020001021020000101100000202100000000000010000000000002200000000000000000000000000000000
csplib-prob028/BIBD.essence151055504604003034030105000003000000000011000000000004000140000120000000000000000000000000000000000000
csplib-prob048/MinimumEnergyBroadcast.essence31201212869855505331132302243220042010000004000010120000000000010000000000000000000000000000000000000000
csplib-prob013-decision/ProgressivePartyProblem.essence271488629709508062231304173000001202000000100001100000100000001000000000000001000000000000000000000000
csplib-prob055/EFPA.essence191588736616305133234104331010001100000002100000200000000000000000000000000000000000000000000000000000
csplib-prob013/PPP-partition.essence221599629428206150121404182104000201000000100010000000000100000000001100010200111100000001000000100000
csplib-prob044/steiner.essence13282020872032022322121021000011000101101000110200000000000101000000000000000000000000000000000000000000
csplib-prob024/Langford-positional.essence173019201082472402422213132301420000010000000000000000000100000000000000000000000000000001000000000000000
csplib-prob053-GracefulDoubleWheelGraphs/GracefulDoubleWheelGraphs.essence3659414118174812412041244546271502074000000000000000200000000000000000000000000000000000000000000000000000000
csplib-prob053/GracefulDoubleWheelGraphs.essence3659414118174812412041244546271502074000000000000000200000000000000000000000000000000000000000000000000000000
csplib-prob002/TemplateDesign.essence131688843723403113201303103110000010000000000011010010000000000010000000000000000000000000000000000000
csplib-prob049/set_partition_full.essence161399423203003011241002120002000200000000220100000000020101000000000000000000000000100000000000000000
csplib-prob039/Rehearsal.essence3518101085716271107257403503304000000003000040000010000023000000000100000000000000000000000000000000000000
csplib-prob049/set_partition_simple.essence19151111434224004200451001140022000200000000220100000000000101000000000000000000000000100000000000000000
csplib-prob028/BIBD-sym.essence39402727131010106100096510234163200043000000000010020000400008100141010100000000000000000002000000000000000000
csplib-prob065/opd.essence3639252514112191001910308033110061000202000002230310200000000101000000001100000000000000000000000000000000
csplib-prob110/ArmiesOfQueens.essence151388544432002340112221220006020210000003000010000000000000000000000000000000000000000000000000000000
csplib-prob032/MaximumDensityStillLife.essence2756393917161251690069481112101210502530112000221002010300000000100000000060000000000000000000000000000000000
csplib-prob056/sonetAsMSet.essence131488633213003110111103130011000300001000200010000000000000000000000000000010000000000000000110000010
csplib-prob056/sonetAsSet.essence131599633213003110111103130011000400001000100010000000000000000000000000000011000000000000000010000000
csplib-prob016/TrafficLights.essence15866221491201111104100301400100010020400000100000200000000000000000000000000000010000000000000000000
csplib-prob033/WordDesign.essence241088227375405132311210131503100100010101001010200020000000002000002200000000000010000000000000000000
csplib-prob027/prob027-alientiles-singlepass.essence3118111175111631101873111702032200000000001402001000210000000000000000000000000000000000000000000000000000000
csplib-prob023/MagicHexagon.essence6676505026251111611010101061111440201100025001000201603010100060000010001000000000000000000000000000000000000000000
rcpsp/rcpsp.essence4518881049499190938841110001196000001420240010000010000020100000000000000001400000000000010000000000000000
SandwichSudoku/SandwichSudoku.essence6259394118161827101803213810186310401000404030001000400000000000000200000010000000000032000000000002000000000000000
csplib-prob132/layout.essence2624141410791267307475224603422202420410002000000000001000000000002000000020000000000000010000000000000000
csplib-prob017/RamseyNumbers.essence321266639787406275032010121610201211010000303000002000100001000000002200000000000010000000000000000000
csplib-prob115/TailAssignment.essence463220201291415614100133119222643253303600102003020000007002001000100000200000000000000000000000000000000000000
prob128-Cross/prob128-Cross.essence3729181811111310371206163063510345201161020001000000001002000000011000000000000000000000000000000000000000000
csplib-prob057/KillerSudoku.essence38644141231989981186958525134401040000000501000000000000000000000000000000000022000000000000000000000000000
Transshipment/Transshipment.essence353116161571913194091337756083660000100041000040000002020000000000000000000000000000000000000000000000000000
csplib-prob083/Transshipment.essence353116161571913194091337756083660000100041000040000002020000000000000000000000000000000000000000000000000000
csplib-prob018/water_buckets.essence664526261911296810240107936924201740041131012001101001010010000000000200000000000000020000000000000000000000000
prob037-peg-simple/prob037-peg-simple.essence631311021022929109271014209201610835180301603902112005111043000000020200100020000000000000001000000000000000000000000
prob037/prob037.essence6683595924221492371007171418846824626011971421002000043002002000000001000000000000000000000000100000000000000000
csplib-prob042/diagnosis-single.essence25352523121145531223552052601216001010000202000000010000000000000000000030005000000000000000200000000000000
csplib-prob050/DiamondFree.essence3519131365911109506269231210101701100001000110000200100010300110000100000000000000000000000000110000000000
CVRP/cvrpAsSet.essence4136242412812589908412925214272413030112000011010110100000000000100000000000010002000000000000000000000000
csplib-prob040/WW.essence625736362114101361036010668844767426020000100000000300010100000000000310000000000000000000000000000000000000000
csplib-prob051/TankAlloc-051.essence232213139551335095244223304310010200400500100102010200010000000000000000000000000000000000000000000000000
csplib-prob008/VesselLoading.essence86432626171272216738046670468856080000031000041005100000040040000000000000000040000000000000000000000000000000
prob123-Milk/prob123-Milk.essence3448353414125775505761531602144000700302001001102008000000000201000000000000000000000000110100000000000000
csplib-prob116/Vellino.essence8616101063133313250133143260402010400214080030600000080110113000000000000010000000000010000020010030000100000001
csplib-prob040/DistributionWagnerWhitin.essence534728281912101617995105579343474221210310120500030000010004000000000000000000000000000000000000000000000000000
prob037-peg/prob037-peg.essence841441071073737101335102213927221012651903027031500120102111145000000000000100000000000000000001000000000000000000000000
csplib-prob045/CoveringArray.essence3531171714107007467067010034000000001000201000200000000020110001200000000000004000000002000000000000000000
csplib-prob031/RackConfiguration.essence31321717157208384073304227072870320120013000010000012020000000000000010000000000000000000000000000000000000
csplib-prob012/nonogram.essence96107737334291217221205612221212121630853000000000008010000000000000000000000020000000000000000000000000000000000000000
csplib-prob021/Crossfigures.essence37023717317364402917491822441833231065954605801614206424926720420402000200200716000220000000002000020000010000000112000000100
\ No newline at end of file diff --git a/tools/essence-feature-usage-stats/test/__init__.py b/tools/essence-feature-usage-stats/test/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tools/essence-feature-usage-stats/test/__pycache__/test_essence_file.cpython-311.pyc b/tools/essence-feature-usage-stats/test/__pycache__/test_essence_file.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d6a70bb9c3dfd0eb5d1cb20848161b37b6e25a7d GIT binary patch literal 2650 zcmb_e%}*Og6rcUF7uNPdNK*_-W73G!wAdh8RZ*g*l+Zw;I5ea=__EqCLt^3&y1PV* zMI=|^K&2dV3x^!Igf>bJJ@nfDVT~+dtrQ8Vr`)LMiBsR3^*Ssjl_GU^_RYL~A2a^F z_h$TSJl;*9{qV;qo019n3z?uPt;zmp0wK=`B~&Pqygv$g0eG<}mZZES;5Vr#mz2E1 z=W;Ppisqwyt`yZ$SH4RiB4HAZY=N&=@cM0&uO4v0xCN6}0YmZ{SSn0=9Sz%Zk7Owp zC{i^n&&P2^77u@=T~&>cd_p8w3GH4ZRAa)D9{AXjU}bpymhWM`H1!U#qv zFH&KR6qCEWpmj!7anAok6Bu>Fe~4| z@!f3B>oGxSIkWa`*>+4o_NC~_HY+ZA@*-et<5p6sgB#iVl@iOA%tzFGl%1;3Lit|y z&g@*a<$H9InGT>jx?-F6*eJMi>@04D6QiYNpv%niBd>?=vcQ*g3Z}!VsUuisj%r}? z*cl)-@@oDeEMRUKhs~6|2c(p-0gvG`j|*6Z1EEpL=qw zu8%kL@g4obwtk_mUu@_XThZv>R{J+jK2L65sjKORns$S3q0dk}@R##KS%b-k#N+*i za(pzX_*x1_jmpPiomO&I0`~G2OBN0pg|cOUsi&i!|g02_4#~j0UEPm`*z3{13 zKR)KYZOjeFDwIl$R)^k;eV{UkUcLp=83Ug8KGHkMk?rKj@4aqvq@J8;Bq!XjuGZC= zhC1U0y%TxNMUMP3O#UC_m(U+?jvCC49&!F*nApZ&0^Zpl?jvNyloLoBUsfJNDOUy95Zo?>5=t>diF~h*h@+Hm;z@H0BN8~DlWUk`m8X1qZ%a8=@^ z;Mjgd`uSqhxjV+(&epYa4eeY_Z4#}fZKy68s*|Ax8G^}f;^XzZPYN6HdSbYd7_Mo}#EEtK z^kO}6rjacNuJ(soI3wE3jTQ~9VT*Yy}B(WT`Ad=duuamH-5gk QcC*HxJ&DKzAmAYV3;v%=MF0Q* literal 0 HcmV?d00001 diff --git a/tools/essence-feature-usage-stats/test/test_data/__pycache__/constants.cpython-311.pyc b/tools/essence-feature-usage-stats/test/test_data/__pycache__/constants.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e8c16a957fc3f8873e1a7324850ea8a1c4ac2198 GIT binary patch literal 2481 zcmcgsJ5w7;5Z={FLMtT1Ljoa$EQAaKAp{unI`a_khYcLUoXd%8VTNVTXoYuIwz(@; z-A|zEf+KL??6{2J0zyK<4Ywvz)kV&x%9*3<*#&dPsp|x^zUk@tzOQ?x_%j&vbMWc@ zJBNR54S0&8h+XcxB}^R(0aXYNfQ~-~hvqv0*5x ztP|hi7gSMIsf6K_s2iGOVEOn*;x1H-GO1lr4XjCf1~A<27Dxc9|Z_KF6dTL<%%T3_G_%^ z;DOZ6YO8s6%}R# zJi(&!3oaOj_F}!PViMkzG(!RJ#<88;E*sJzXFW&czdJ~ZxIL&G4T~Edk5PG zlHm|P#;(ZOX-hi9bc;mQp=yg-s6<@exS84`%} zA02=8Jt~z^oh%ZZVbU0TDi zj}u!?T~uV)&xuVZv$U4sfP;e!*KuO_WdHQt*{+!wG$TVa#Ip5wvkffU=dkiNXo(_gnjHi)yGTg-_ zyFMI)r;AsY9T)p%!vg$P#b&d$|GfF4#T+P@(OJ_sR}HjU_3c);&5E?0J~P8z)o8|w zC#oF-=P5J!&`OS2$zfXKZco4n61`_T=RcW!lNZM2wwYZu<7-xX=4|FBp(M<=Aznv?CecrOxnS&8YsUVPfD1*2Ad zyc&*L(GDw~t)??p=7E(PyI8zjG=EsT+BPS)%)X+NnY)<0N}CfKX5S|D2qV2z@MOEF zP}7kDTRp>8->5Y>4kw|`99XFiPg~>Dmr-+U)f#&Q2WI&ZI59XxJ-&&4D)<>e;64!4 z0YOu=KS7098hpmvnyHXzXr!Kw82Ic2pQ}6P}H1 z1Fvz5=Mp_Euv@Gnjw9m@a! literal 0 HcmV?d00001 diff --git a/tools/essence-feature-usage-stats/test/test_data/constants.py b/tools/essence-feature-usage-stats/test/test_data/constants.py new file mode 100644 index 000000000..9b5195ffd --- /dev/null +++ b/tools/essence-feature-usage-stats/test/test_data/constants.py @@ -0,0 +1,177 @@ +KNAPSACK_AST = { + "mInfo": { + "finds": [], + "givens": [], + "enumGivens": [], + "enumLettings": [], + "lettings": [], + "unnameds": [], + "strategyQ": {"Auto": {"Interactive": []}}, + "strategyA": {"Auto": {"Interactive": []}}, + "trailCompact": [], + "nameGenState": [], + "nbExtraGivens": 0, + "representations": [], + "representationsTree": [], + "originalDomains": [], + "trailGeneralised": [], + "trailVerbose": [], + "trailRewrites": [], + }, + "mLanguage": {"language": {"Name": "Essence"}, "version": [1, 3]}, + "mStatements": [ + {"Declaration": {"GivenDomainDefnEnum": {"Name": "items"}}}, + { + "Declaration": { + "FindOrGiven": [ + "Given", + {"Name": "weight"}, + { + "DomainFunction": [ + [], + [ + {"SizeAttr_None": []}, + "PartialityAttr_Total", + "JectivityAttr_None", + ], + {"DomainEnum": [{"Name": "items"}, None, None]}, + {"DomainInt": [{"TagInt": []}, []]}, + ] + }, + ] + } + }, + { + "Declaration": { + "FindOrGiven": [ + "Given", + {"Name": "gain"}, + { + "DomainFunction": [ + [], + [ + {"SizeAttr_None": []}, + "PartialityAttr_Total", + "JectivityAttr_None", + ], + {"DomainEnum": [{"Name": "items"}, None, None]}, + {"DomainInt": [{"TagInt": []}, []]}, + ] + }, + ] + } + }, + { + "Declaration": { + "FindOrGiven": [ + "Given", + {"Name": "capacity"}, + {"DomainInt": [{"TagInt": []}, []]}, + ] + } + }, + { + "Declaration": { + "FindOrGiven": [ + "Find", + {"Name": "picked"}, + { + "DomainSet": [ + [], + {"SizeAttr_None": []}, + {"DomainEnum": [{"Name": "items"}, None, None]}, + ] + }, + ] + } + }, + { + "Objective": [ + "Maximising", + { + "Op": { + "MkOpSum": { + "Comprehension": [ + { + "Op": { + "MkOpImage": [ + {"Reference": [{"Name": "gain"}, None]}, + {"Reference": [{"Name": "i"}, None]}, + ] + } + }, + [ + { + "Generator": { + "GenInExpr": [ + {"Single": {"Name": "i"}}, + { + "Reference": [ + {"Name": "picked"}, + None, + ] + }, + ] + } + } + ], + ] + } + } + }, + ] + }, + { + "SuchThat": [ + { + "Op": { + "MkOpLeq": [ + { + "Op": { + "MkOpSum": { + "Comprehension": [ + { + "Op": { + "MkOpImage": [ + { + "Reference": [ + {"Name": "weight"}, + None, + ] + }, + { + "Reference": [ + {"Name": "i"}, + None, + ] + }, + ] + } + }, + [ + { + "Generator": { + "GenInExpr": [ + {"Single": {"Name": "i"}}, + { + "Reference": [ + {"Name": "picked"}, + None, + ] + }, + ] + } + } + ], + ] + } + } + }, + {"Reference": [{"Name": "capacity"}, None]}, + ] + } + } + ] + }, + ], +} diff --git a/tools/essence-feature-usage-stats/test/test_data/knapsack.essence b/tools/essence-feature-usage-stats/test/test_data/knapsack.essence new file mode 100644 index 000000000..fa50e3f67 --- /dev/null +++ b/tools/essence-feature-usage-stats/test/test_data/knapsack.essence @@ -0,0 +1,9 @@ +language Essence 1.3 +$ knapsack.essence: Knapsack Problem + +given items new type enum +given weight, gain : function (total) items --> int +given capacity : int +find picked : set of items +maximising sum i in picked . gain(i) +such that (sum i in picked . weight(i)) <= capacity diff --git a/tools/essence-feature-usage-stats/test/test_data/mydir/not_essence.txt b/tools/essence-feature-usage-stats/test/test_data/mydir/not_essence.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tools/essence-feature-usage-stats/test/test_essence_file.py b/tools/essence-feature-usage-stats/test/test_essence_file.py new file mode 100644 index 000000000..016a0e7ab --- /dev/null +++ b/tools/essence-feature-usage-stats/test/test_essence_file.py @@ -0,0 +1,37 @@ +import os +import unittest +from pathlib import Path + +from dotenv import load_dotenv + +from stats.essence_file import EssenceFile +from test_data.constants import KNAPSACK_AST + +ENV_PATH = Path("../.env").resolve() +load_dotenv(dotenv_path=ENV_PATH) + +CONJURE_DIR = os.getenv("CONJURE_DIR") +CONJURE_BIN = Path(CONJURE_DIR) / "conjure" + + +class TestEssenceFile(unittest.TestCase): + def test_instantiate(self): + file = EssenceFile("test_data/knapsack.essence", CONJURE_BIN) + self.assertIsInstance(file, EssenceFile) + + def test_path(self): + file = EssenceFile("test_data/knapsack.essence", CONJURE_BIN) + path = Path("test_data/knapsack.essence").resolve() + self.assertEqual(file.path, path) + + def test_path_trimmed(self): + file = EssenceFile("test_data/knapsack.essence", CONJURE_BIN) + self.assertEqual(file.get_str_path(depth=1), "knapsack.essence") + + def test_ast(self): + file = EssenceFile("test_data/knapsack.essence", CONJURE_BIN) + self.assertEqual(file.ast, KNAPSACK_AST) + + +if __name__ == "__main__": + unittest.main() diff --git a/tools/essence-feature-usage-stats/utils/__init__.py b/tools/essence-feature-usage-stats/utils/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tools/essence-feature-usage-stats/utils/__pycache__/__init__.cpython-311.pyc b/tools/essence-feature-usage-stats/utils/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f520b66f879f313cc2672408e524f6d1bcfc6fb0 GIT binary patch literal 178 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 literal 0 HcmV?d00001 diff --git a/tools/essence-feature-usage-stats/utils/__pycache__/files.cpython-311.pyc b/tools/essence-feature-usage-stats/utils/__pycache__/files.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2448509d5a1d187f509ff8286000588ed9e7e5ff GIT binary patch literal 2086 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 M3zqo$KEOruPuTw)KmY&$ literal 0 HcmV?d00001 diff --git a/tools/essence-feature-usage-stats/utils/__pycache__/maths.cpython-311.pyc b/tools/essence-feature-usage-stats/utils/__pycache__/maths.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..42355b41a31875036779b780c1c351ffb5f8c03d GIT binary patch literal 976 zcmZ`&&1(}u6rb76m))cll@u%J7(od(Zajz(q@aRDTScfScqwCcng+8U?(FI&?4buQ z1%=$2V^4nIMQX+M-tWDA^X7f2G=pIMc53XJ zg3vE5OT8hX{|NUFP|&C18%jj3l+>`6Igh5mmD>4&q$$1IbQW~;6eh0)B8l6Ig*?#$Zetwvr-$^{)GmDW{`&|Bd@yoeLyZLQ7(pH9ZMT zv&{}Q9alVx)6ls+oT4k82xJ7V70@)TBzr&W?li-k@tAjF9F~%dMh*$9lP06zuUl^gILNfjZ$Ibac literal 0 HcmV?d00001 diff --git a/tools/essence-feature-usage-stats/utils/__pycache__/misc.cpython-311.pyc b/tools/essence-feature-usage-stats/utils/__pycache__/misc.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..27886947c4a229afe292d4c842be2f41b3f85411 GIT binary patch literal 2020 zcmaJ?TWcFf6h5;TS(0U2O?+u6sV7YuTiA{YH8dDw5}eRWOejeyC6Kz?-Bq%Uv}n#4-NRCO&juOB+!Gp5HKx$$lDe-5c1SBql;~&beZ`ymvfo(ojIdl z2L{rB-(M>;Hq`jGiPZCM<#ME1hHpd(X8UF4no8Fi03Hlf?0dTi_sBi{ zUSbOzxSz1JAQ6y)VksM``+A@kh^1~M*A$irLRH-ltyki~xch#OH?89tpvPNQdK*~Nq+RU|TZ5Ykq(v`(fJaDE z{I1w$nQ@zXw{1oZYB{D)Jw}TT_vz${=i9FD7{y|R-f{e!)U~;9TT+VCyp-ZOYPc3P zy|U|5l$4u}=Nha+Z`lLNLw#N+78_sk%yz$_bwwmQnp}I{a&jg-X`og{wlYD9ofYE z-c{}%xV%-eI)Ii`Q<+CS3$8+y2&v9YtUM)`pF&QHROB$yCA*PoxI9XA!{@?1rR(dj z&*yJ?B|Bd-Dwa{nFM1ZznE&$A&+|6tB9NJaZQzx+XUg2TVb5^i@Oi%MJ4K!^Iov$6 zQi=Ku%UVWXtF%xwd@Y;;BW%r~ zBcU0r2CL2N(Qq+LhRGk2+ZXHE6Jq!fdzjpPhlXmn*qX#CICU2F_Rt)d-Lk+*0=uL( z#K9x71wAFuEieH8KsgkYo`N{-citGZQ-#9?u|}!{i*s~M!Qxc05J~kwnhskc@L)tF zMs$`!W0;(@!yOmdM2aI#+(>+3uz;eW9u84db9}oLC0+ZDxi?r&{2*s zL32)JB4=zwz_3{8VJ>&44@3XJ`eLl<`iU6+7X}kL9`#LlnT6z$W-{|UnfY5+lZk%-A%>Jb87E=*?HCjh zB0{j(%p46q4i`6<9xMe*%?zz&=+5wt`SY=QW~z~ys>v4XD2ptohr) + - Colour(hex: str) + + Values of r,g,b must be in range[0, 255] + """ + + def __init__(self, item): + self.message = f"Not a valid colour: {item}\n" + self.default_message + super(self.message) + + +class Colour: + def __init__(self, *args, **kwargs): + # If we have 3 arguments, interpret them as rgb values + if len(args) >= 3: + self.r, self.g, self.b = (clamp(int(x), 0, 255) for x in args[:3]) + elif "hex" in kwargs: + self.r, self.g, self.b = Colour.hex_to_rgb(kwargs["hex"]) + elif "r" in kwargs and "g" in kwargs and "b" in kwargs: + self.r, self.g, self.b = ( + clamp(int(kwargs["r"]), 0, 255), + clamp(int(kwargs["g"]), 0, 255), + clamp(int(kwargs["b"]), 0, 255), + ) + elif isinstance(args[0], str): + self.r, self.g, self.b = Colour.hex_to_rgb(args[0]) + elif isinstance(args[0], Iterable): + self.r, self.g, self.b = (clamp(int(x), 0, 255) for x in args[0][:3]) + else: + raise ColourConstructorError(args) + + @staticmethod + def hex_to_rgb(hex_string): + # Remove any leading '#' if present + hex_string = hex_string.lstrip("#") + + # Check if the hex string is a valid length (it's always 6 characters long) + if len(hex_string) != 6: + raise ValueError("Invalid hex string length") # noqa: TRY003 + + # Convert the hex string to RGB values + r = int(hex_string[0:2], 16) + g = int(hex_string[2:4], 16) + b = int(hex_string[4:6], 16) + + return r, g, b + + @staticmethod + def rgb_to_hex(rgb_tuple): + # Ensure that the RGB values are in the valid range (0-255) + r, g, b = rgb_tuple + if not (0 <= r <= 255) or not (0 <= g <= 255) or not (0 <= b <= 255): + raise ValueError("RGB values must be in the range 0-255") # noqa: TRY003 + + # Convert the RGB values to a hex string + return f"#{r:02X}{g:02X}{b:02X}" + + def as_rgb(self) -> tuple[int, int, int]: + return self.r, self.g, self.b + + def as_hex(self) -> str: + return Colour.rgb_to_hex(self.as_rgb()) + + def __str__(self) -> str: + return self.as_hex() + + def __repr__(self) -> str: + return f"Colour({self.as_hex()})" + + +GREEN = Colour(0, 255, 0) +RED = Colour(255, 0, 0) +BLUE = Colour(0, 0, 255) +YELLOW = Colour(255, 255, 0) +HOT_ORANGE = Colour(255, 100, 0) + + +def get_linear_gradient_value(x, x_min, x_max, c_min: Colour, c_max: Colour) -> Colour: + r = int(map_range(x, x_min, x_max, float(c_min.r), float(c_max.r))) + g = int(map_range(x, x_min, x_max, float(c_min.g), float(c_max.g))) + b = int(map_range(x, x_min, x_max, float(c_min.b), float(c_max.b))) + return Colour(r, g, b) diff --git a/tools/essence-feature-usage-stats/utils/conjure.py b/tools/essence-feature-usage-stats/utils/conjure.py new file mode 100644 index 000000000..1f306537d --- /dev/null +++ b/tools/essence-feature-usage-stats/utils/conjure.py @@ -0,0 +1,48 @@ +import json +import subprocess +from os import PathLike +from pathlib import Path + + +def get_essence_file_ast( + fpath: Path | PathLike[str] | str, conjure_bin_path: Path | PathLike[str] | str +) -> dict: + """ + Run the `conjure pretty` command line tool and get the parsed AST as a dict + ToDo: Instead of relying on a conjure binary being provided, download one automatically if needed + :param conjure_bin_path: path to conjure binary + :param fpath: path to an essence file + :return: the Abstract Syntax Tree in json format (as a dict) + """ + + result = subprocess.run( + [str(conjure_bin_path), "pretty", "--output-format=astjson", str(fpath)], + capture_output=True, + text=True, + check=True, + ) + return json.loads(result.stdout) + + +def get_version(conjure_bin_path: Path | PathLike[str] | str) -> tuple[str, str]: + """ + Get version from conjure. Not useful now but maybe use this to auto-update conjure from git repo in the future? + :param conjure_bin_path: path to conjure binary + :return: tuple of (version, commit) - conjure version and git repo version (as given by conjure --version) + """ + result = subprocess.run( + [str(conjure_bin_path), "--version"], + capture_output=True, + text=True, + check=True, + ) + + version, commit = None, None + lines = result.stdout.split("\n") + for line in lines: + if "Release version" in line: + version = line.removeprefix("Release version ") + if "Repository version" in line: + commit, *ts_parts = line.removeprefix("Repository version ").split() + + return version, commit diff --git a/tools/essence-feature-usage-stats/utils/files.py b/tools/essence-feature-usage-stats/utils/files.py new file mode 100644 index 000000000..8ed5c7ef0 --- /dev/null +++ b/tools/essence-feature-usage-stats/utils/files.py @@ -0,0 +1,35 @@ +import os +from pathlib import Path + + +def count_lines(fpath: str | Path) -> int: + """ + Counts the number of lines in a file + :param fpath: path to the file + :return: int, the number of lines + """ + fpath = Path(fpath) + with fpath.open("r") as f: + return sum(1 for _ in f) + + +def trim_path(input_path: os.PathLike | Path | str, num_elements=0) -> str: + """ + Normalize path and get last N elements from the end of the path (returns whole path if num_elements is 0) + :param input_path: the path + :param num_elements: last N elements to return + :return: whole path or a part of it (str) + """ + input_path = os.path.normpath(str(input_path)) + + if num_elements == 0: + return input_path + + path_elements = input_path.split(os.path.sep) + num_elements = min( + num_elements, + len(path_elements), + ) # Ensure num_elements is not greater than the length of the path + return os.path.sep.join( + path_elements[-num_elements:], + ) # Join the last num_elements elements to form the trimmed path diff --git a/tools/essence-feature-usage-stats/utils/git.py b/tools/essence-feature-usage-stats/utils/git.py new file mode 100644 index 000000000..fa460ecce --- /dev/null +++ b/tools/essence-feature-usage-stats/utils/git.py @@ -0,0 +1,82 @@ +import os +import shutil +from pathlib import Path + +import git +from git import RemoteProgress, Repo +from tqdm import tqdm + + +class InvalidGitRemoteUrlError(ValueError): + """This exception is raised when a git remote url is invalid.""" + + def __init__(self, repo_url): + super().__init__(f"Not a valid git repository url: {repo_url}") + + +class CloneProgress(RemoteProgress): + def __init__(self): + super().__init__() + self.pbar = tqdm(desc="Cloning repo: ", unit="%", ncols=100) + + def update(self, op_code, cur_count, max_count=None, message=""): # noqa: ARG002 + self.pbar.total = 100 + self.pbar.n = int((cur_count / max_count) * 100) + self.pbar.refresh() + + +def sync_repo( + directory_path: str | Path, + repo_url, + branch="master", + remote_name="origin", +) -> Repo: + """ + Given a directory and a remote repo, synchronise directory with the repo. + That is: + - If directory does not exist, clone remote repo to directory + - If it exists, try to pull latest commit + - If it is not a valid repo, delete directory and clone repo again + :param directory_path: - path to directory + :param repo_url: - url of remote git repo + :param branch: - branch to use (master by default) + :param remote_name: - remote name to use (origin by default) + :return: - None + """ + + directory_path = Path(directory_path) + + if directory_path.exists() and len(os.listdir(directory_path)) == 0: + # If it's an empty directory, remove it (and clone repo) + directory_path.rmdir() + + if ( + not directory_path.exists() + ): # If the directory does not exist, clone the repository + repo = git.Repo.clone_from( + repo_url, + directory_path, + progress=CloneProgress(), + branch=branch, + ) + print(f"Cloned {repo_url} into {directory_path}") + return repo + + try: # If the directory exists, try to pull the latest changes + repo = git.Repo(directory_path) + origin = repo.remote(name=remote_name) + origin.pull(branch, progress=CloneProgress()) + print(f"Pulled the latest changes for {repo_url} in {directory_path}") + except git.exc.InvalidGitRepositoryError: + # If the directory exists but is not a valid Git repository, remove it and clone again + print(f"Removing invalid repository in {directory_path}") + shutil.rmtree(directory_path) + repo = git.Repo.clone_from( + repo_url, + directory_path, + progress=CloneProgress(), + branch=branch, + ) + print(f"Cloned {repo_url} into {directory_path}") + + return repo diff --git a/tools/essence-feature-usage-stats/utils/maths.py b/tools/essence-feature-usage-stats/utils/maths.py new file mode 100644 index 000000000..124086e97 --- /dev/null +++ b/tools/essence-feature-usage-stats/utils/maths.py @@ -0,0 +1,17 @@ +def map_range(x, in_min, in_max, out_min, out_max): + """ + Maps x between in_min, in_max to range between out_min and out_max + :param x: value to map + :param in_min: min value of x + :param in_max: max value of x + :param out_min: min value of output range + :param out_max: max value of output range + :return: mapped value + """ + if in_min == in_max: + return out_min + (out_max - out_min) / 2 + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min + + +def clamp(x, minn, maxn): + return min(max(x, minn), maxn) diff --git a/tools/essence-feature-usage-stats/utils/misc.py b/tools/essence-feature-usage-stats/utils/misc.py new file mode 100644 index 000000000..9873f8aae --- /dev/null +++ b/tools/essence-feature-usage-stats/utils/misc.py @@ -0,0 +1,42 @@ +from typing import Any + + +def flat_keys_count( + data: dict[Any, dict | list] | list, blocklist=None +) -> dict[Any, int]: + """ + Recurse over a dict or list (potentially with nested dicts / lists) and count all dictionary keys + :param data: a dictionary or list containing dictionaries / lists + :param blocklist: collection of keys to ignore + :return: dict in the format of :<№ of key's occurrences in data> + """ + + ans = {} + + def add_key(key, count=1): + if (blocklist is None) or (key not in blocklist): + if key in ans: + ans[key] += count + else: + ans[key] = count + + def recurse_and_add_keys( + item, + ): # Recurse over entry (list or dict) and add its keys to the count + if isinstance(item, (list, dict)): + new_keys = flat_keys_count(item) + for key in new_keys: + add_key(key, new_keys[key]) + + if isinstance( + data, + dict, + ): # If it's a dict, add its keys and recurse over the values + for key in data: + add_key(key) + recurse_and_add_keys(data[key]) + elif isinstance(data, list): # If it's a list, recurse over all its elements + for entry in data: + recurse_and_add_keys(entry) + + return ans diff --git a/tools/essence-feature-usage-stats/web/__pycache__/server.cpython-311.pyc b/tools/essence-feature-usage-stats/web/__pycache__/server.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9bb2ca3763312cebfcb4c786a06dca43a5137bb5 GIT binary patch literal 1193 zcmZ`&O=uHA6rS1LNzybiLYpGe)?SJPY!4Hq*OtA^367h%^{DOH*ene=FK-JF3CN|;%hR(Xx64IDX5!wEJ3B8(dPxqMGVW(Eax|fLc^S+m*JyD)$83H=;8;wPew(JPf+M6Mig{WJ z{(l63VS3T7q}M3cua018*p{$jgsBYDuvmsmJwt`mSF(bs2F5fml=;Etio#gseA-;j zxzu#6qHPt;nVh|n&6tnxKQvocOr)tL3XDz^xRs$3-i78meP(jXUQia#7bWqym4;Ic zLTR!EOgg!gq_^=MJKCTfw8q z=wayE=jhkf#*IfXn!0v1c#1&%R;r1#zTg=of-jq?a?3z6nYCP+OiIFX1wp~D9w>Dy zpJ!39xC(nZHpT{(JKRN+T?e1)BVPms%}epYN@((*xHo$ z$;bg2X=;Q3mo9axBi|@sY8|XDH4TMcL7_sYrMOw zij_z26Y`FG^v?s6Zq6<^bc&4vuD(*90M*nn#)s&3qxU#Qw;J7}=?me=`{5>nrKj@l F{s(}65*h#i literal 0 HcmV?d00001 diff --git a/tools/essence-feature-usage-stats/web/server.py b/tools/essence-feature-usage-stats/web/server.py new file mode 100644 index 000000000..b4ae194cc --- /dev/null +++ b/tools/essence-feature-usage-stats/web/server.py @@ -0,0 +1,18 @@ +from flask import Flask, render_template, request + +from stats.essence_stats import EssenceStats + + +def create_server(stats: EssenceStats): + app = Flask(__name__) + + @app.route("/") + @app.route("/index.html") + def index(): + # ToDo cache Essence ast generation etc + n_keywords = request.args.get("n_keywords", default=5, type=int) + return render_template( + "index.html", data={"essence_stats": stats, "n_keywords": n_keywords} + ) + + return app diff --git a/tools/essence-feature-usage-stats/web/static/script.js b/tools/essence-feature-usage-stats/web/static/script.js new file mode 100644 index 000000000..794450a08 --- /dev/null +++ b/tools/essence-feature-usage-stats/web/static/script.js @@ -0,0 +1,49 @@ +function IntValueComparator(header) { + const index = header.cellIndex; + const mult = (header.dataset.order === "desc") ? -1 : 1; + + return (a, b) => { + const aInt = parseInt(a.cells[index].textContent); + const bInt = parseInt(b.cells[index].textContent); + let ans = 0; + + if (aInt > bInt) ans = 1; + if (aInt < bInt) ans = -1; + ans *= mult; + + return ans; + } +} + +function toggleOrder(header) { + if (header.dataset.order === "desc") { + header.dataset.order = "asc"; + header.classList.remove("sort-desc"); + header.classList.add("sort-asc"); + } else { + header.dataset.order = "desc"; + header.classList.remove("sort-asc"); + header.classList.add("sort-desc"); + } +} + +function sortRows(table, header, comparator=IntValueComparator) { + const rows = Array.from(table.querySelectorAll("tbody tr")); + + rows.sort(comparator(header)); + rows.forEach(row => table.querySelector("tbody").appendChild(row)); +} + +document.addEventListener("DOMContentLoaded", function () { + console.log("DOM Loaded!"); + + const table = document.getElementById("sortable-table"); + const headers = table.querySelectorAll("th"); + + headers.forEach(header => { + header.addEventListener("click", (e) => { + toggleOrder(header); + sortRows(table, header); + }); + }); +}); \ No newline at end of file diff --git a/tools/essence-feature-usage-stats/web/static/styles.css b/tools/essence-feature-usage-stats/web/static/styles.css new file mode 100644 index 000000000..f4a39c9c1 --- /dev/null +++ b/tools/essence-feature-usage-stats/web/static/styles.css @@ -0,0 +1,15 @@ +th { + writing-mode: vertical-lr; +} + +th.sort-asc::after { + content: " ▲"; +} + +th.sort-desc::after { + content: " ▼"; +} + +th::after { + margin-left: 4px; +} diff --git a/tools/essence-feature-usage-stats/web/templates/base.html b/tools/essence-feature-usage-stats/web/templates/base.html new file mode 100644 index 000000000..f4c42252a --- /dev/null +++ b/tools/essence-feature-usage-stats/web/templates/base.html @@ -0,0 +1,22 @@ + + + + {% block title %}{% endblock %} + {% block stylesheets %} {% endblock %} + + + +
+ {% block content %}{% endblock %} +
+ + + {% block scripts %}{% endblock %} + + diff --git a/tools/essence-feature-usage-stats/web/templates/index.html b/tools/essence-feature-usage-stats/web/templates/index.html new file mode 100644 index 000000000..baa65e042 --- /dev/null +++ b/tools/essence-feature-usage-stats/web/templates/index.html @@ -0,0 +1,30 @@ +{% extends "base.html" %} + +{% block title %} Essence feature stats {% endblock title %} + +{% block nav %} +
  • Index
  • +{% endblock nav %} + +{% block content %} + {% include "keyword_list.html" %} + +
    +

    Essence feature table

    + {% if 'table' in data.keys() %} + {{ data['table'] }} + {% else %} + {# Include the table.html template here #} + {% include "table.html" %} + {% endif %} +
    +{% endblock content %} + +{% block stylesheets %} + +{% endblock stylesheets %} + +{% block scripts %} +

    Hello World!

    + +{% endblock scripts %} \ No newline at end of file diff --git a/tools/essence-feature-usage-stats/web/templates/keyword_list.html b/tools/essence-feature-usage-stats/web/templates/keyword_list.html new file mode 100644 index 000000000..e9f333613 --- /dev/null +++ b/tools/essence-feature-usage-stats/web/templates/keyword_list.html @@ -0,0 +1,21 @@ +
    + {% set stats = data['essence_stats'] %} + {% set keywords = stats.get_essence_keywords(sort_mode='most-used')[:data.get('n_keywords', -1)] %} + + {% if keywords|length == 0 %} + {% elif keywords|length == 1 %} +

    Most common keyword

    +
      + {% for keyword in keywords %} +
    1. {{ keyword.name }} ({{ keyword.total_usages }} usages in {{ keyword.num_files_using_feature }} files)
    2. + {% endfor %} +
    + {% else %} +

    {{ keywords|length }} most common keywords

    +
      + {% for keyword in keywords %} +
    1. {{ keyword.name }} ({{ keyword.total_usages }} usages in {{ keyword.num_files_using_feature }} files)
    2. + {% endfor %} +
    + {% endif %} +
    diff --git a/tools/essence-feature-usage-stats/web/templates/table.html b/tools/essence-feature-usage-stats/web/templates/table.html new file mode 100644 index 000000000..4e436ede4 --- /dev/null +++ b/tools/essence-feature-usage-stats/web/templates/table.html @@ -0,0 +1,33 @@ + + {% set stats = data['essence_stats'] %} + {% set keywords = stats.get_essence_keywords(sort_mode='most-used') %} + {% set files = stats.get_essence_files(sort_mode='most-lines', reverse=False) %} + + + + {% for essence_keyword in keywords %} + + {% endfor %} + + + + {% for file in files %} + + + {% for essence_keyword in keywords %} + {% set n_uses = file.get_uses(essence_keyword.name) %} + {% set colour = essence_keyword.get_colour(n_uses).as_hex() %} + + {% endfor %} + + {% endfor %} + +
    Essence File{{ essence_keyword.name }}
    {{ file.get_str_path(depth=2) }} + {{ n_uses }}
    \ No newline at end of file From 39fb6c70d21639a2697cee630dc578a110ddac24 Mon Sep 17 00:00:00 2001 From: gskorokhod Date: Mon, 30 Oct 2023 14:06:37 +0000 Subject: [PATCH 02/55] Modified gitignore --- .gitignore | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.gitignore b/.gitignore index f102fa849..cd695494c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,10 @@ target solvers/**/vendor/build +tools/essence-feature-usage-stats/.venv +tools/essence-feature-usage-stats/stats/__pycache__ +tools/essence-feature-usage-stats/utils/__pycache__ +tools/essence-feature-usage-stats/.idea +tools/essence-feature-usage-stats/test/__pycache__ +tools/essence-feature-usage-stats/web/__pycache__ + From 07bd9a4ec7510e6c4712ccb781601f1903b31f4d Mon Sep 17 00:00:00 2001 From: gskorokhod Date: Mon, 30 Oct 2023 14:09:12 +0000 Subject: [PATCH 03/55] Remove pycache files --- .gitignore | 2 +- .../.idea/essence-feature-usage-stats.iml | 15 -- .../inspectionProfiles/Project_Default.xml | 12 - .../inspectionProfiles/profiles_settings.xml | 6 - .../.idea/misc.xml | 9 - .../.idea/ruff.xml | 6 - .../essence-feature-usage-stats/.idea/vcs.xml | 6 - .../.idea/workspace.xml | 235 ------------------ .../__pycache__/__init__.cpython-311.pyc | Bin 178 -> 0 bytes .../__pycache__/essence_file.cpython-311.pyc | Bin 9076 -> 0 bytes .../essence_keyword.cpython-311.pyc | Bin 4626 -> 0 bytes .../__pycache__/essence_stats.cpython-311.pyc | Bin 7017 -> 0 bytes .../test_essence_file.cpython-311.pyc | Bin 2650 -> 0 bytes .../__pycache__/constants.cpython-311.pyc | Bin 2481 -> 0 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 178 -> 0 bytes .../utils/__pycache__/colour.cpython-311.pyc | Bin 6748 -> 0 bytes .../utils/__pycache__/conjure.cpython-311.pyc | Bin 2501 -> 0 bytes .../utils/__pycache__/files.cpython-311.pyc | Bin 2086 -> 0 bytes .../utils/__pycache__/git.cpython-311.pyc | Bin 4518 -> 0 bytes .../utils/__pycache__/maths.cpython-311.pyc | Bin 976 -> 0 bytes .../utils/__pycache__/misc.cpython-311.pyc | Bin 2020 -> 0 bytes .../web/__pycache__/server.cpython-311.pyc | Bin 1193 -> 0 bytes 22 files changed, 1 insertion(+), 290 deletions(-) delete mode 100644 tools/essence-feature-usage-stats/.idea/essence-feature-usage-stats.iml delete mode 100644 tools/essence-feature-usage-stats/.idea/inspectionProfiles/Project_Default.xml delete mode 100644 tools/essence-feature-usage-stats/.idea/inspectionProfiles/profiles_settings.xml delete mode 100644 tools/essence-feature-usage-stats/.idea/misc.xml delete mode 100644 tools/essence-feature-usage-stats/.idea/ruff.xml delete mode 100644 tools/essence-feature-usage-stats/.idea/vcs.xml delete mode 100644 tools/essence-feature-usage-stats/.idea/workspace.xml delete mode 100644 tools/essence-feature-usage-stats/stats/__pycache__/__init__.cpython-311.pyc delete mode 100644 tools/essence-feature-usage-stats/stats/__pycache__/essence_file.cpython-311.pyc delete mode 100644 tools/essence-feature-usage-stats/stats/__pycache__/essence_keyword.cpython-311.pyc delete mode 100644 tools/essence-feature-usage-stats/stats/__pycache__/essence_stats.cpython-311.pyc delete mode 100644 tools/essence-feature-usage-stats/test/__pycache__/test_essence_file.cpython-311.pyc delete mode 100644 tools/essence-feature-usage-stats/test/test_data/__pycache__/constants.cpython-311.pyc delete mode 100644 tools/essence-feature-usage-stats/utils/__pycache__/__init__.cpython-311.pyc delete mode 100644 tools/essence-feature-usage-stats/utils/__pycache__/colour.cpython-311.pyc delete mode 100644 tools/essence-feature-usage-stats/utils/__pycache__/conjure.cpython-311.pyc delete mode 100644 tools/essence-feature-usage-stats/utils/__pycache__/files.cpython-311.pyc delete mode 100644 tools/essence-feature-usage-stats/utils/__pycache__/git.cpython-311.pyc delete mode 100644 tools/essence-feature-usage-stats/utils/__pycache__/maths.cpython-311.pyc delete mode 100644 tools/essence-feature-usage-stats/utils/__pycache__/misc.cpython-311.pyc delete mode 100644 tools/essence-feature-usage-stats/web/__pycache__/server.cpython-311.pyc diff --git a/.gitignore b/.gitignore index cd695494c..7efe2d9dd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ target solvers/**/vendor/build -tools/essence-feature-usage-stats/.venv +tools/essence-feature-usage-stats/venv tools/essence-feature-usage-stats/stats/__pycache__ tools/essence-feature-usage-stats/utils/__pycache__ tools/essence-feature-usage-stats/.idea diff --git a/tools/essence-feature-usage-stats/.idea/essence-feature-usage-stats.iml b/tools/essence-feature-usage-stats/.idea/essence-feature-usage-stats.iml deleted file mode 100644 index da8a8ad5c..000000000 --- a/tools/essence-feature-usage-stats/.idea/essence-feature-usage-stats.iml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/tools/essence-feature-usage-stats/.idea/inspectionProfiles/Project_Default.xml b/tools/essence-feature-usage-stats/.idea/inspectionProfiles/Project_Default.xml deleted file mode 100644 index 19069e5c6..000000000 --- a/tools/essence-feature-usage-stats/.idea/inspectionProfiles/Project_Default.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - \ No newline at end of file diff --git a/tools/essence-feature-usage-stats/.idea/inspectionProfiles/profiles_settings.xml b/tools/essence-feature-usage-stats/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100644 index 105ce2da2..000000000 --- a/tools/essence-feature-usage-stats/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/tools/essence-feature-usage-stats/.idea/misc.xml b/tools/essence-feature-usage-stats/.idea/misc.xml deleted file mode 100644 index 77492c073..000000000 --- a/tools/essence-feature-usage-stats/.idea/misc.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/tools/essence-feature-usage-stats/.idea/ruff.xml b/tools/essence-feature-usage-stats/.idea/ruff.xml deleted file mode 100644 index a6efb6112..000000000 --- a/tools/essence-feature-usage-stats/.idea/ruff.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file diff --git a/tools/essence-feature-usage-stats/.idea/vcs.xml b/tools/essence-feature-usage-stats/.idea/vcs.xml deleted file mode 100644 index 35eb1ddfb..000000000 --- a/tools/essence-feature-usage-stats/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/tools/essence-feature-usage-stats/.idea/workspace.xml b/tools/essence-feature-usage-stats/.idea/workspace.xml deleted file mode 100644 index 6ba431a5c..000000000 --- a/tools/essence-feature-usage-stats/.idea/workspace.xml +++ /dev/null @@ -1,235 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { - "associatedIndex": 5 -} - - - - { - "keyToString": { - "RunOnceActivity.OpenProjectViewOnStart": "true", - "RunOnceActivity.ShowReadmeOnStart": "true", - "WebServerToolWindowFactoryState": "false", - "git-widget-placeholder": "master", - "list.type.of.created.stylesheet": "CSS", - "node.js.detected.package.eslint": "true", - "node.js.detected.package.tslint": "true", - "node.js.selected.package.eslint": "(autodetect)", - "node.js.selected.package.tslint": "(autodetect)", - "nodejs_package_manager_path": "npm", - "settings.editor.selected.configurable": "preferences.pluginManager", - "ts.external.directory.path": "/home/mayday/.local/share/JetBrains/Toolbox/apps/pycharm-professional/plugins/javascript-impl/jsLanguageServicesImpl/external", - "vue.rearranger.settings.migration": "true" - }, - "keyToStringList": { - "stardust.markdown.MarkdownSplitEditorSuppressor:keyList": [ - ] - } -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1697476837664 - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/tools/essence-feature-usage-stats/stats/__pycache__/__init__.cpython-311.pyc b/tools/essence-feature-usage-stats/stats/__pycache__/__init__.cpython-311.pyc deleted file mode 100644 index 67fe385cd4b77b1bee769d7b853d02d55ea5f3c6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 178 zcmZ3^%ge<81WyZeQ$h4&5CH>>P{wCAAY(d13PUi1CZpdaYszO^LBrX$IAY_}KHvCp>b*v?hwM2?%Vci7V0l|`8! zzTK5=u~be7bf|nV5T)?JF3thiLy&Wj{O}dI_I~EBKylY!q(Q*M0xAL&2ekcB(2xTd z`PKJkKe$WUIp@&f?%Ua!H#2YMy?OKATmGV_Crlu{_fO;Mg%~0Ki7!qP?99ghK;|}4 zh{EJZ3ZHC_$+Ibz!917a@_dS?c|IrP1E~Pb3%OukOo{nWDn#D{xp2NK)x{8&yh@bd z3Q5H6c|2Mu)CmEAJmp10$8G2PMs9M@6YVeY{q#ClS>uMpR z%Cp&=DyMZL$(mi6;zGfYbJ>Ebn;}EX=H)9^^T=#2ZOE6^MO~&i8GAhXVCiB}5zNC)pM%vK#TF^Vi zi7Sg53JL|7(IWts-Cu(jm!~u=qZqykI?KDU9jgD%GsRUh%P7o>nBrE+btc8b(zE7P z&xFquuBLNY1(`tSo^iT@jtCDoO3ubP06%4J6T?|ac>f6QPvEvv#Z%*y5s>CG^E2`R z`w`TB;$onzA|cbI!RewQr6o#&WK$&}zbB=SSyRv#uBaNaB3sBBvJ7nDbu~9@3bV*{ zGbGEITw2#griOJe83U}?8+wyxDJ>$BmiDPP(T1c6xfxJM-+IUC;%_cr8PZ$(b)zW zr#I{o^LTH}0YF)Bc)P@vSxqc+3R`B8*CkkwCGML_N|}4AjBwMXVXs_Bu(@-JQ~WxK@LWu3lhWXiuX%UhPj-P5^+b)}35^^$%Xby3=11chtol zRp+wgiJ8_0p;v7P`}YV8?q>}_94lS{;1d`@7;chp04%A&{xWd8$=UPIr#^;khS;iO zDyyj(P}_^0`U97l%FG*(`P21>!hY~f>4=}713A!&SF?($fIt{?(yr3rE-9;1A#rqz z;t*+x2S>%j6rq?NAeK}hseYN*`E^rug<>1D)5ie-Z`!oT%)RT?Ei=|t6VKPh^Ht}v zc=1%Ok3wG>0xAy2te(AU;!Oti#5aM~Xtd)Opudc(jNt{@Gy?aA2&JzP2F?%f_AL|t z)?6ZGQt`HjrdIMF33|}rof<;kWehM6oHXy&wD&$me(;^|11FZ4B^Fc*2k(Er#QW%B z{PdLh5-8&(p)6D!bIKWpKK)c_k+Lu!a1a#cG8KM}FAEpQZH6H?zkTzV!ou;ymHs7+ zI^tBeph)RlP67pj_6R+nbSYbq($b~uRka|w!X>2vRa4=x$I4t*H>BdMG`j$eQ8IPO zC`!hhny39vg7!-1u`w0FNlSPE!|l#Ov-+FF(Hsj2dv!bXkwu$)B~I9d)5)L)Ye~#N zR+ph)DpV$0)J^_cI(OL&LNOk9;TP9!jl4xS>^o@6JzO#I~86e$>_m2MLXsv6g z-Zg}>{Nj4=o~pR#%K+KB?e4D1?%Lps^}!dLgcqP1z>VHjel@+;*GOz>5-tRV09L2g z69ab=@1MPOwvwnNcCMamL=x{U{bcFJk8b`5dhHpi9QyF^{mBO-uT)1~X>8uQ)`h<( z%^>!`IepW;kpWWO9?+ zmREYgOy8tLR!AxaCOb*R6)@LR35t*O#sI%h-5eq?}r`^)3_g>DhT#r?z93iR@}N1IaK{jL_Ya^#p8o18X42bp)v z!R&(BwcImk<5Fz&dD^tm4tQt))1+`SaC{hOYuRa(Xd|Grw>s}QcLPsJJC%9A25+N* zf0tFbCH@`$8gq?Y=iVmQm?U31O<9hL=R~of8`?q!WybLuP|~F0#d$DAq*<+)_e%{b zOSieU8^{1BGny$D=D{zMFJ=o=1y3guNc{4f!cB=2MxU@s`h7yAG(+;W-jBYVKShHEa1a3C|{St&hI|MEySifRYW9O?_)`zTb7L>tS@{L3E@R-C2+BTot~E_TBFJ z`=0kBw<2hz9;%%D@VocVJ{Ubx9X+xh8^5R4Vh8K7gVpYXO*RyoV%7(@-yN$g)CR}v zgX61HH(y&H7;8imx4IfT_BRD?OYb8B;4uQIJ@chVMi1OS_}R<9&eldw*GEpTPSv}m z^`Tw&gxb(VeP{xZ{&E$5Pu3#?NWc`@FD|4M{A%Xcn|^uWvkSG@;d<=w=R2z1C!RoR za)<{R9TntnHXR#2eu(_`Q24|!_uHe}Pi*7V9ECo4W094@5h(^W&m*_b>~sCTTRXw$8id|SpT{cC8c ze+$4e`9mbOcCa4b^)Np6AU;-$Pt@ZRwaDIjWN%g6+c~%AVlD2-4w8blGAPBp>uVRv zNKlK#OI2}*j;-O*^YoAms-|ZzE}S4fy$<#)Q~Ebo1-`0c*aZ&PeA+M^zlj>B;5Vrr zJ6GC`CT)@GF0g?YC5*XAStIFo<(RRc-{vNz-41Hf!o)o@Cgs%hRS1f~kd~Q==escn zL+RO)+Um)%bUW$7qu<3#vKpRWbmu}IcdjWYIKGa{j7()a_OI3Smz`N?+nhZ42 zF?s{)vztV>+)3QsT2X6}v3g{zDvnV$m_b`|p3VwXA%68z@u~x;wNe>EaUE=7OTTw# zhHL@uu*{{c-Bxfdj(vx3;0bfFL(G! zhXHfNYf?U40B+OaDXX4mY$~q661p=vSY?|%8v6e}=7`7wm_yqJbxJQIJ{kI+4Uf@>t68wrds4cJ#wHb9_ZYj95lguV-J95?~bRd71reE()t{gtB&mpK}f8W zWxqyoN_7}dj{$%PKqS64b?dcSM5;%mswi1hqGUP=^OVYA$oK^ZtVjooSe~h^^t9tp z?n-+R*sl2&G$70B4}rRvSI(`ntI$$M`wv1^cxK&E@8%vv(A(-huiyO*nx<8a+mKFwJaxhVsXOPE5p-Exx z(kObV;qDvUw$wSHL4Dkn^AL)()vJqTZ%ovPGSyc9Pug;~lFb-N4*_F9K_<6=pCLd~ z>oig@=FutCvl?^MfaP}`n>p_in&h=9n5uRP!D$4@Iw*Y|^VDvkh6F9O^>4T}EuUBh z)4Gg{;peYiScd-eg8*Qc_maLX4--2dBz9KjYl;2!#QsLS|JKWm?Zfr$FE#qN-YPdk zLNpA~P6|R{%5)m7pw_c5R*gpa2;3W=0r=wqEeJ84T;jkPbD0bd3s+{qrDFVF$d>pr zZ-N&Ud_SWsb4#ty^XBd*Q>m=}l(%NEsOV=yGCQeMN?JS{@t?Z=& zxb<#xuyK#T;*I*Y+dYQ2-sGsX;tW>{X#*E(mskYlwlc(hK$s&~Kc0Hr@^F_d@`7 z6e~tH@4hG2`u5lR_Jb^j-T+4i;p)jI%lEv&toILB4psL|ex9xNpR4tstM{K<;~Sd? z*TUBC$$A{aU4ZF@>(RdI=5zNE!1cS=t!FLzdOiAjwd1ngBIpDCqfmM!AdbB%Nl-OpboJ0HA@6`!S^>~k*Wie zM?FK8g2@3lEX{Bhn|v1mRqs?oyos-GAwWA@`vHQ#0bq8ce#~a_sxenov<#N_BB0+i z>6bgoas=oQ>;DTU&9eJzvaBFB2?8-Dpa+TYPNp*T5A#<3DR4Il^x}85t!oM_xUjVa z9&u2$@)oUxc%+54W$ip-K#0)+9<(hk+GvHZ%-kEPy!9b|^btl|z=J;OqVKyif*AW+ zz=O8WMcZ~Kju_ioz=O7}83+jDO#+~z(?>gq284qZ4oeT-vmP|>0Z~TSft}kR08v+b zwE?`IK&foOK$idt7eK|Jk9IIf0MEFFt2m$4GgibVd?B4%u)g-wujw?tLxVFkL~d<`mKO4h=~v=m>mLC}v?36K z_K^N#fDo%-m<9 fG5&E7wkiXP&=2;c83qOE*^ft7-Q%x8p(6Bu`gI=Y diff --git a/tools/essence-feature-usage-stats/stats/__pycache__/essence_keyword.cpython-311.pyc b/tools/essence-feature-usage-stats/stats/__pycache__/essence_keyword.cpython-311.pyc deleted file mode 100644 index 65791e8e5b57c143ada3e04e2d18ba394f7ae843..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4626 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 F{tMwCIZglo diff --git a/tools/essence-feature-usage-stats/test/__pycache__/test_essence_file.cpython-311.pyc b/tools/essence-feature-usage-stats/test/__pycache__/test_essence_file.cpython-311.pyc deleted file mode 100644 index d6a70bb9c3dfd0eb5d1cb20848161b37b6e25a7d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2650 zcmb_e%}*Og6rcUF7uNPdNK*_-W73G!wAdh8RZ*g*l+Zw;I5ea=__EqCLt^3&y1PV* zMI=|^K&2dV3x^!Igf>bJJ@nfDVT~+dtrQ8Vr`)LMiBsR3^*Ssjl_GU^_RYL~A2a^F z_h$TSJl;*9{qV;qo019n3z?uPt;zmp0wK=`B~&Pqygv$g0eG<}mZZES;5Vr#mz2E1 z=W;Ppisqwyt`yZ$SH4RiB4HAZY=N&=@cM0&uO4v0xCN6}0YmZ{SSn0=9Sz%Zk7Owp zC{i^n&&P2^77u@=T~&>cd_p8w3GH4ZRAa)D9{AXjU}bpymhWM`H1!U#qv zFH&KR6qCEWpmj!7anAok6Bu>Fe~4| z@!f3B>oGxSIkWa`*>+4o_NC~_HY+ZA@*-et<5p6sgB#iVl@iOA%tzFGl%1;3Lit|y z&g@*a<$H9InGT>jx?-F6*eJMi>@04D6QiYNpv%niBd>?=vcQ*g3Z}!VsUuisj%r}? z*cl)-@@oDeEMRUKhs~6|2c(p-0gvG`j|*6Z1EEpL=qw zu8%kL@g4obwtk_mUu@_XThZv>R{J+jK2L65sjKORns$S3q0dk}@R##KS%b-k#N+*i za(pzX_*x1_jmpPiomO&I0`~G2OBN0pg|cOUsi&i!|g02_4#~j0UEPm`*z3{13 zKR)KYZOjeFDwIl$R)^k;eV{UkUcLp=83Ug8KGHkMk?rKj@4aqvq@J8;Bq!XjuGZC= zhC1U0y%TxNMUMP3O#UC_m(U+?jvCC49&!F*nApZ&0^Zpl?jvNyloLoBUsfJNDOUy95Zo?>5=t>diF~h*h@+Hm;z@H0BN8~DlWUk`m8X1qZ%a8=@^ z;Mjgd`uSqhxjV+(&epYa4eeY_Z4#}fZKy68s*|Ax8G^}f;^XzZPYN6HdSbYd7_Mo}#EEtK z^kO}6rjacNuJ(soI3wE3jTQ~9VT*Yy}B(WT`Ad=duuamH-5gk QcC*HxJ&DKzAmAYV3;v%=MF0Q* diff --git a/tools/essence-feature-usage-stats/test/test_data/__pycache__/constants.cpython-311.pyc b/tools/essence-feature-usage-stats/test/test_data/__pycache__/constants.cpython-311.pyc deleted file mode 100644 index e8c16a957fc3f8873e1a7324850ea8a1c4ac2198..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2481 zcmcgsJ5w7;5Z={FLMtT1Ljoa$EQAaKAp{unI`a_khYcLUoXd%8VTNVTXoYuIwz(@; z-A|zEf+KL??6{2J0zyK<4Ywvz)kV&x%9*3<*#&dPsp|x^zUk@tzOQ?x_%j&vbMWc@ zJBNR54S0&8h+XcxB}^R(0aXYNfQ~-~hvqv0*5x ztP|hi7gSMIsf6K_s2iGOVEOn*;x1H-GO1lr4XjCf1~A<27Dxc9|Z_KF6dTL<%%T3_G_%^ z;DOZ6YO8s6%}R# zJi(&!3oaOj_F}!PViMkzG(!RJ#<88;E*sJzXFW&czdJ~ZxIL&G4T~Edk5PG zlHm|P#;(ZOX-hi9bc;mQp=yg-s6<@exS84`%} zA02=8Jt~z^oh%ZZVbU0TDi zj}u!?T~uV)&xuVZv$U4sfP;e!*KuO_WdHQt*{+!wG$TVa#Ip5wvkffU=dkiNXo(_gnjHi)yGTg-_ zyFMI)r;AsY9T)p%!vg$P#b&d$|GfF4#T+P@(OJ_sR}HjU_3c);&5E?0J~P8z)o8|w zC#oF-=P5J!&`OS2$zfXKZco4n61`_T=RcW!lNZM2wwYZu<7-xX=4|FBp(M<=Aznv?CecrOxnS&8YsUVPfD1*2Ad zyc&*L(GDw~t)??p=7E(PyI8zjG=EsT+BPS)%)X+NnY)<0N}CfKX5S|D2qV2z@MOEF zP}7kDTRp>8->5Y>4kw|`99XFiPg~>Dmr-+U)f#&Q2WI&ZI59XxJ-&&4D)<>e;64!4 z0YOu=KS7098hpmvnyHXzXr!Kw82Ic2pQ}6P}H1 z1Fvz5=Mp_Euv@Gnjw9m@a! diff --git a/tools/essence-feature-usage-stats/utils/__pycache__/__init__.cpython-311.pyc b/tools/essence-feature-usage-stats/utils/__pycache__/__init__.cpython-311.pyc deleted file mode 100644 index f520b66f879f313cc2672408e524f6d1bcfc6fb0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 178 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 diff --git a/tools/essence-feature-usage-stats/utils/__pycache__/files.cpython-311.pyc b/tools/essence-feature-usage-stats/utils/__pycache__/files.cpython-311.pyc deleted file mode 100644 index 2448509d5a1d187f509ff8286000588ed9e7e5ff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2086 zcmZ`)|4ST46rb7MyIVbtJ-t}HK(aOoH$mQt`HSldEtBGQz!u@u?d&gq){a^2a( zc${!h3r!KaffW6rKUh$kl3)5KH2;Aog2#doD23)XMFZkbeKY6n-5EP``)20NdvD&n zd7pQ`x3{+ql(COsxYnZGc4QbdwQ*0CrYzk8XMw&=OA`~JBX%dmL zk``K$rb3#mg$bGq*9=u9hRY6Jexs5NNtL&ojvl`PgZS zBlGw@_zn|5#=*Z8h}O5^MXaHFXa&4pu0DDEm8-e;3(LMgE_q(4hkcs|mfr|Jypr>^SKbl%ksnr6P!RBqvG9l1Ow|e)y7| zBbG1HyqOdnNNeQd?5XPxGv-Gd4s^PJ!xDi00;Ggqx1si!ck%J~@_6Z!O3Q_x6F()q zvBy`Iuk0fn>RTP%>*(Yzs9x$x>S?Onq3m=h`y%XdfjT*0@<)u+dFRcJkB`q|*LgGs zo^AAwM#UFVX|yBqq7wu4TXid!cc)oqWP&UN$p9yx!utVEfK_XA0VdWOHEP?)1t{0r zSxhx!01$>X{E%C5gd*fVAdbcQjduR|a{=bg*cDv%M5nEY-HzHEp`y?%+l)WJaa|PE zZ(2WTO>PhfrbVHMqk#J#gx-MHd=8*jEF5txP1ug98hU|L0jXM=GDBR&P^qg-D8wKp zVd%~}w#o5GKmhQ~(9RKjql#Fn%+K1!DNoO`N-!NL>r}awY%BrwcOD8XHSRZR553_F z6piYkRh3%FXmG%Gpzc7maha>StK6WjQ+2>$?>muf@dcau60gj%1tH)w5ybou%^A82 zU?VwSG>Y~tin^;H;JE1?6 zjz-_k&dh%E{eR#5DUpa0XkU~j&6_a#JH7->ZV#UP4hDCLK@7nn8UHC{1b7cwp@NtZ z1%FP;NH8Z_QbEqh1tp{KdC3YF!kMr@LS&v8@@--$CfyPVxetH8Wg>hn3~SVs_pL=E zBtnd&5i?_^SP2ti#7$*UG7`7tOxzHzl62pfh-M)zc+wT!&80(L@?EoFyXF;UFEP_` zJn3DtWaGN~p;5@TPvwtL`{l_o82k*lGzoH+2^m60TqBEu5xPw?(i&M7GBTVcdc&8C zH*_m+%;#PIlpitc9mZ@{nRzdlcT{sZYnI%+T~y(P>3PRA)SEf8sOsuc-c=c=Of54D z*YiHEscb+8k|V(%W%J|;fZqyti7UXM-L~L)KX@UVT`QeQ&{I|TJ^4du3s&!UcAz$Z zgU~`nU9epshqKWps$@HP*Jdk7*o+Dyl$~A1SGUnS$IfSd$ubG{DX`6}6^iJynp!#i|%n-14TE`D|i z0Q5SYZ_xQ#(4W9=l2(wVqFyjH&5LSU!8Xbkj^mp4VOh7@D`8DD?5w77a=b*F(X44% zn)a!{l6X1__8jX2$Y=o2nVfk5KvwW;N^>=7t|bZbC80(BGsyY_%vl(8T3{_tUWch} ztK}9efW?Z2Y)H3-F3VNC#0ASPcAO&HF$}>2fiaNxGzYp6#A9cy|G_Br1Iu-}^MbhJT7YjkvXV7N9u_3-NF zVr^iqJ}}o9m|K(9BWv*EI$H2Zwu|LGAO0m^h1e-n$#od{P3wrhTTInZRjdG&hEM@a zy}sM?bw_O7vzr(-4z&GhX-5E-f}LrZ9f5}@ySA%ao|rGXo>26{%v^+^nS*5%q!+eJ zTGlp9FOn@Y7?ojLq@XXihv5RaHu$oG+^g8QxILv@GIZCh4D?FepB;j|&N%?9q&fOk z6y$o}?$F4_+0B)D>dl82>Z5Pfht4#H&hVvJlg8I0J9K25j?`(YK~uG$bJ;^kV=5p^ zE9?+F7;2LpMu0kJ7$w*s0)A|l+YaL-0{qPRA%HHoZG}SeJK(UdfK-&nTI62>-+}QA zPbuh*3n5jpS$-*B^pZxNnOO|FS_#sYr!W&jV=>#UNJw|SU!Di0_a=hsJ`=e`s;@`~ zy+**!b{n0GC$!u3&dK|6_Zp)i{FDbEHUKAf8-0L?^qwgEo0K^hU9`A%yWXK}6T|C) zRt1-GQOoVtduBECAhZSi-0$#oOLEZ&+RYF#MH*6-K%$g-`2%{Tt59^fm}J^*kDC3m zxg}MlO*FIvttvi{dokaVtMX1i#p9mj{{MRXfE1;hWLf-x+!Ro! z>8K86D2Za2n$O?hMOnuSRlR7adQhNY20EoWE5&S%K~8c^b#LR%yqigC0*?S^eSY7t5Ra&lfqGnUc=*!X70&EX}Bs zDu$lHHB`8q-0dxYr*c+A;|DYkqK4udS$txu};dH{Jc2 zUp4c(4Zm#{(O9f?5cpB`AOb(C;#UhGc8-*xD?yD*OTh&}@u{hVdA2gtiUOrMkcM{# zJS8o#H{qMg_!ZCq6!fV4Ko2>+2m7hq`&_xu?$>neHnIvE<>n5qw^8-wZ9g-7ARo$%Opc&r{CZ-mD&ogTUO&3o+Q z%EPJp$=Sxq+4{u!#>Dy0_3erI+Qj@LIFEYNU8ASrB2r8K;FDzl&_DZ$|E$x6 z23@G}{(Lu_w4egl@cIiwTp zG>*Ruzzbt^u=3ZqNwYIJk2#l{tzVZ%-`B0O$t}>oDe-bhbX>;Jcs?b5k%Tv?7xX*+ zjqGi930|>QbN&IKB?^MjB#~AAYm&q&|24^Qt+ziS(N+FylH;|P^(Gmt_4bw`33xMm zIozl`<||LT*OOF$;_o21v+x*apYAP<5wOkv;a23^LVt?@Xbya3D4Yl%1!B}%jv M3zqo$KEOruPuTw)KmY&$ diff --git a/tools/essence-feature-usage-stats/utils/__pycache__/maths.cpython-311.pyc b/tools/essence-feature-usage-stats/utils/__pycache__/maths.cpython-311.pyc deleted file mode 100644 index 42355b41a31875036779b780c1c351ffb5f8c03d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 976 zcmZ`&&1(}u6rb76m))cll@u%J7(od(Zajz(q@aRDTScfScqwCcng+8U?(FI&?4buQ z1%=$2V^4nIMQX+M-tWDA^X7f2G=pIMc53XJ zg3vE5OT8hX{|NUFP|&C18%jj3l+>`6Igh5mmD>4&q$$1IbQW~;6eh0)B8l6Ig*?#$Zetwvr-$^{)GmDW{`&|Bd@yoeLyZLQ7(pH9ZMT zv&{}Q9alVx)6ls+oT4k82xJ7V70@)TBzr&W?li-k@tAjF9F~%dMh*$9lP06zuUl^gILNfjZ$Ibac diff --git a/tools/essence-feature-usage-stats/utils/__pycache__/misc.cpython-311.pyc b/tools/essence-feature-usage-stats/utils/__pycache__/misc.cpython-311.pyc deleted file mode 100644 index 27886947c4a229afe292d4c842be2f41b3f85411..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2020 zcmaJ?TWcFf6h5;TS(0U2O?+u6sV7YuTiA{YH8dDw5}eRWOejeyC6Kz?-Bq%Uv}n#4-NRCO&juOB+!Gp5HKx$$lDe-5c1SBql;~&beZ`ymvfo(ojIdl z2L{rB-(M>;Hq`jGiPZCM<#ME1hHpd(X8UF4no8Fi03Hlf?0dTi_sBi{ zUSbOzxSz1JAQ6y)VksM``+A@kh^1~M*A$irLRH-ltyki~xch#OH?89tpvPNQdK*~Nq+RU|TZ5Ykq(v`(fJaDE z{I1w$nQ@zXw{1oZYB{D)Jw}TT_vz${=i9FD7{y|R-f{e!)U~;9TT+VCyp-ZOYPc3P zy|U|5l$4u}=Nha+Z`lLNLw#N+78_sk%yz$_bwwmQnp}I{a&jg-X`og{wlYD9ofYE z-c{}%xV%-eI)Ii`Q<+CS3$8+y2&v9YtUM)`pF&QHROB$yCA*PoxI9XA!{@?1rR(dj z&*yJ?B|Bd-Dwa{nFM1ZznE&$A&+|6tB9NJaZQzx+XUg2TVb5^i@Oi%MJ4K!^Iov$6 zQi=Ku%UVWXtF%xwd@Y;;BW%r~ zBcU0r2CL2N(Qq+LhRGk2+ZXHE6Jq!fdzjpPhlXmn*qX#CICU2F_Rt)d-Lk+*0=uL( z#K9x71wAFuEieH8KsgkYo`N{-citGZQ-#9?u|}!{i*s~M!Qxc05J~kwnhskc@L)tF zMs$`!W0;(@!yOmdM2aI#+(>+3uz;eW9u84db9}oLC0+ZDxi?r&{2*s zL32)JB4=zwz_3{8VJ>&44@3XJ`eLl<`iU6+7X}kL9`#LlnT6z$W-{|UnfY5+lZk%-A%>Jb87E=*?HCjh zB0{j(%p46q4i`6<9xMe*%?zz&=+5wt`SY=QW~z~ys>v4XD2ptohr4Hq*OtA^367h%^{DOH*ene=FK-JF3CN|;%hR(Xx64IDX5!wEJ3B8(dPxqMGVW(Eax|fLc^S+m*JyD)$83H=;8;wPew(JPf+M6Mig{WJ z{(l63VS3T7q}M3cua018*p{$jgsBYDuvmsmJwt`mSF(bs2F5fml=;Etio#gseA-;j zxzu#6qHPt;nVh|n&6tnxKQvocOr)tL3XDz^xRs$3-i78meP(jXUQia#7bWqym4;Ic zLTR!EOgg!gq_^=MJKCTfw8q z=wayE=jhkf#*IfXn!0v1c#1&%R;r1#zTg=of-jq?a?3z6nYCP+OiIFX1wp~D9w>Dy zpJ!39xC(nZHpT{(JKRN+T?e1)BVPms%}epYN@((*xHo$ z$;bg2X=;Q3mo9axBi|@sY8|XDH4TMcL7_sYrMOw zij_z26Y`FG^v?s6Zq6<^bc&4vuD(*90M*nn#)s&3qxU#Qw;J7}=?me=`{5>nrKj@l F{s(}65*h#i From 5ba0e0d377880655e4256a3f26a45a0adeca57a9 Mon Sep 17 00:00:00 2001 From: gskorokhod Date: Wed, 1 Nov 2023 13:29:24 +0000 Subject: [PATCH 04/55] Automatically download conjure from repo, lint essence-feature-usage-stats code, and reformat .gitignore --- .gitignore | 10 +- tools/essence-feature-usage-stats/.env | 4 +- tools/essence-feature-usage-stats/main.py | 38 +- .../pyproject.toml | 11 +- .../stats/essence_file.py | 62 +- .../stats/essence_keyword.py | 40 +- .../stats/essence_stats.py | 122 +- tools/essence-feature-usage-stats/table.html | 137127 +++++++++++---- .../test/test_data/__init__.py | 0 .../test/test_data/constants.py | 72 +- .../test/test_essence_file.py | 8 +- .../utils/colour.py | 34 +- .../utils/conjure.py | 103 +- .../utils/files.py | 47 +- .../essence-feature-usage-stats/utils/git.py | 82 - .../utils/git_utils.py | 91 + .../utils/maths.py | 10 +- .../essence-feature-usage-stats/utils/misc.py | 9 +- .../web/__init__.py | 0 .../essence-feature-usage-stats/web/server.py | 18 - .../web/templates/__init__.py | 0 .../web/templates/base.html | 4 +- .../web/templates/index.html | 19 +- 23 files changed, 103068 insertions(+), 34843 deletions(-) create mode 100644 tools/essence-feature-usage-stats/test/test_data/__init__.py delete mode 100644 tools/essence-feature-usage-stats/utils/git.py create mode 100644 tools/essence-feature-usage-stats/utils/git_utils.py create mode 100644 tools/essence-feature-usage-stats/web/__init__.py delete mode 100644 tools/essence-feature-usage-stats/web/server.py create mode 100644 tools/essence-feature-usage-stats/web/templates/__init__.py diff --git a/.gitignore b/.gitignore index 7efe2d9dd..0b4934d43 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,8 @@ target solvers/**/vendor/build -tools/essence-feature-usage-stats/venv -tools/essence-feature-usage-stats/stats/__pycache__ -tools/essence-feature-usage-stats/utils/__pycache__ -tools/essence-feature-usage-stats/.idea -tools/essence-feature-usage-stats/test/__pycache__ -tools/essence-feature-usage-stats/web/__pycache__ +venv +__pycache__ +.idea +.ruff_cache diff --git a/tools/essence-feature-usage-stats/.env b/tools/essence-feature-usage-stats/.env index cd8553056..8d8c94ed6 100644 --- a/tools/essence-feature-usage-stats/.env +++ b/tools/essence-feature-usage-stats/.env @@ -1,6 +1,8 @@ ESSENCE_DIR=/home/mayday/Coding/VIP/EssenceCatalog -CONJURE_DIR=/home/mayday/Coding/VIP/conjure-v2.5.0-linux-with-solvers +CONJURE_DIR=/home/mayday/Coding/VIP/conjure ESSENCE_EXAMPLES_REPO=https://github.com/conjure-cp/EssenceCatalog.git +CONJURE_REPO=https://github.com/conjure-cp/conjure +OUTPUT_PATH=./table.html KEYWORD_BLOCKLIST="mInfo,finds,givens,enumGivens,enumLettings,lettings, unnameds,strategyQ,Auto,Interactive,strategyA,trailCompact, nameGenState,nbExtraGivens,representations,representationsTree, diff --git a/tools/essence-feature-usage-stats/main.py b/tools/essence-feature-usage-stats/main.py index e0ebdcd26..e2278938c 100644 --- a/tools/essence-feature-usage-stats/main.py +++ b/tools/essence-feature-usage-stats/main.py @@ -1,27 +1,49 @@ +import datetime import os from pathlib import Path from dotenv import load_dotenv +from jinja2 import Environment, FileSystemLoader, select_autoescape from stats.essence_stats import EssenceStats -from web.server import create_server ENV_PATH = Path("./.env").resolve() load_dotenv(dotenv_path=ENV_PATH) KEYWORD_BLOCKLIST = [x.strip() for x in os.getenv("KEYWORD_BLOCKLIST").split(",")] -ESSENCE_DIR = os.getenv("ESSENCE_DIR") -CONJURE_DIR = os.getenv("CONJURE_DIR") +ESSENCE_DIR = Path(os.getenv("ESSENCE_DIR")) +CONJURE_DIR = Path(os.getenv("CONJURE_DIR")) +OUTPUT_PATH = Path(os.getenv("OUTPUT_PATH")) +CONJURE_REPO = os.getenv("CONJURE_REPO") ESSENCE_EXAMPLES_REPO = os.getenv("ESSENCE_EXAMPLES_REPO") -CONJURE_BIN = Path(CONJURE_DIR) / "conjure" + +jinja_env = Environment( + loader=FileSystemLoader(Path("web/templates")), + autoescape=select_autoescape(), +) if __name__ == "__main__": stats = EssenceStats( + CONJURE_DIR, + CONJURE_REPO, ESSENCE_DIR, - CONJURE_BIN, ESSENCE_EXAMPLES_REPO, - blocklist=KEYWORD_BLOCKLIST, + "master", + KEYWORD_BLOCKLIST, + ) + + timestamp = datetime.datetime.now().strftime("%d.%m.%Y - %H:%M") + template = jinja_env.get_template("index.html") + html = template.render( + data={ + "essence_stats": stats, + "n_keywords": 5, + "css_path": "web/static/styles.css", + "script_path": "web/static/script.js", + "timestamp": timestamp, + }, ) - app = create_server(stats) - app.run() + with OUTPUT_PATH.open("w") as f: + f.write(html) + f.close() diff --git a/tools/essence-feature-usage-stats/pyproject.toml b/tools/essence-feature-usage-stats/pyproject.toml index 8e329f4ba..0c1eac2ac 100644 --- a/tools/essence-feature-usage-stats/pyproject.toml +++ b/tools/essence-feature-usage-stats/pyproject.toml @@ -1,14 +1,15 @@ [tool.ruff] -# 1. Enable flake8-bugbear (`B`) rules, in addition to the defaults. select = ["E", "F", "B", "I", "N", "UP", "A", "COM", "C4", "ISC001", "ISC002", "ICN", "G", "INP", "PIE", "Q", "RSE", - "RET", "SIM", "ARG", + "RET", "SIM", "ARG", "D", "FIX", "PL", "TRY", "FLY", "PERF", "RUF", "ERA", "PTH", "SLF"] -# 2. Avoid enforcing line-length violations (`E501`) -ignore = ["E501"] +# 2. Avoid enforcing line-length violations (`E501`) and module docstrings (D100) (ToDo: add module doc strings). +# Use line breaks at the first line of doc string (D213), so ignore D212 +# Don't use blank lines before class docstring, so ignore D203 +ignore = ["E501", "D100", "D212", "D203"] # 3. Unfixable rules # ERA: Don't autoremove all commented code, I may actually need it @@ -19,4 +20,4 @@ exclude = ["EssenceCatalog"] # 4. Ignore `E402` (import violations) in all `__init__.py` files, and in `path/to/file.py`. [tool.ruff.per-file-ignores] "web/colour.py" = ["PLR2004"] -#"**/{tests,docs,tools}/*" = ["E402"] +"__init__.py" = ["D"] diff --git a/tools/essence-feature-usage-stats/stats/essence_file.py b/tools/essence-feature-usage-stats/stats/essence_file.py index 1683a8810..aca80aed0 100644 --- a/tools/essence-feature-usage-stats/stats/essence_file.py +++ b/tools/essence-feature-usage-stats/stats/essence_file.py @@ -1,6 +1,5 @@ import os from pathlib import Path -from typing import Generator from utils.conjure import get_essence_file_ast from utils.files import count_lines, trim_path @@ -8,16 +7,20 @@ class EssenceFileError(ValueError): - pass + """Parent class for all errors related to parsing Essence files.""" class EssenceFileInvalidPathError(EssenceFileError): - def __init__(self, fpath): + """Thrown when a path to an Essence file is invalid.""" + + def __init__(self, fpath): # noqa: D107 super().__init__(f"Not a valid Essence file: {fpath}") class EssenceFileNotParsableError(EssenceFileError): - def __init__(self, fpath, msg=None): + """Thrown when an Essence file cannot be parsed.""" + + def __init__(self, fpath, msg=None): # noqa: D107 message = f"Essence file could not be parsed: {fpath}" if msg: message += f", reason: {msg}" @@ -26,17 +29,19 @@ def __init__(self, fpath, msg=None): class EssenceInvalidDirectoryError(ValueError): - def __init__(self, dir_path): + """Thrown when a given directory with Essence files is not a valid directory.""" + + def __init__(self, dir_path): # noqa: D107 super().__init__(f"The provided path '{dir_path}' is not a valid directory") def find_essence_files(dir_path: str | Path): """ - Find all essence files in a given directory and return a list of full paths to them + Find all essence files in a given directory and return a list of full paths to them. + :param dir_path: path to directory - :return: a generator of paths to essence files + :return: a generator of paths to essence files. """ - dir_path = Path(dir_path) # Ensure the directory path is valid @@ -52,15 +57,10 @@ def find_essence_files(dir_path: str | Path): class EssenceFile: - """ - EssenceFile stores keyword counts and number of lines for a given file "fpath". - """ + """EssenceFile stores keyword counts and number of lines for a given file "fpath".""" def __init__(self, fpath: str | Path, conjure_bin_path, blocklist=None): - """ - Constructs a EssenceFile object from a given file path - """ - + """Construct an EssenceFile object from a given file path.""" fpath = Path(fpath).resolve() if not (fpath.is_file() and fpath.suffix == ".essence"): @@ -78,54 +78,64 @@ def __init__(self, fpath: str | Path, conjure_bin_path, blocklist=None): @property def path(self) -> Path: + """Get path to this file.""" return self._fpath @property def ast(self) -> dict: + """Get the AST of this file, as provided by the `conjure pretty` tool.""" return self._ast @property def keyword_counts(self) -> dict[str, int]: + """Get a dictionary of Essence keywords and how often they appear in this file.""" return self._keyword_counts @property - def keywords(self) -> set: + def keywords(self) -> set[str]: + """Get a set of Essence keywords used in the file.""" return set(self._keyword_counts.keys()) @property def n_lines(self) -> int: + """Get number of lines in the file.""" return self._n_lines def get_str_path(self, depth=0) -> str: """ - Get a formatted path to this essence file (and optionally trim it) + Get a formatted path to this essence file (and optionally trim it). + :param depth: (optional) trim path, leaving a suffix of this size - :return: formatted path to file + :return: formatted path to file. """ return trim_path(self._fpath, depth) def get_uses(self, keyword: str) -> int: """ - Get the number of times a given keyword is used in the file + Get the number of times a given keyword is used in the file. + :param keyword: (str) the Essence keyword to count - :return: how many times this keyword is used in the file + :return: how many times this keyword is used in the file. """ return self._keyword_counts.get(keyword, 0) def __hash__(self): + """Compute a hash of this EssenceFile object. The hash of the file's path is used.""" return hash(self._fpath) def __eq__(self, other): + """EssenceFile objects are considered equal if their paths are the same.""" return self._fpath == other._fpath - def __str__(self): + def __str__(self): # noqa: D105 return f"EssenceFile({self._fpath}): {self.n_lines} lines" def as_json(self, path_depth=0) -> dict: """ - Get file stats in json format + Get file stats in json format. + :param path_depth: (optional) trim path, leaving a suffix of this size - :return: (dict) file stats, including its path, number of lines, keywords and AST + :return: (dict) file stats, including its path, number of lines, keywords and AST. """ return { "path": self.get_str_path(path_depth), @@ -136,9 +146,13 @@ def as_json(self, path_depth=0) -> dict: @staticmethod def get_essence_files_from_dir( - dir_path: str | Path, conjure_bin_path: str | Path, blocklist=None + dir_path: str | Path, + conjure_bin_path: str | Path, + blocklist=None, ): """ + Get Essence files contained in a given directory. + :param dir_path: path to directory with essence files :param conjure_bin_path: a path to conjure binary :param blocklist: a list of Essence keywords to ignore diff --git a/tools/essence-feature-usage-stats/stats/essence_keyword.py b/tools/essence-feature-usage-stats/stats/essence_keyword.py index 41ed6cb33..9cd1d3878 100644 --- a/tools/essence-feature-usage-stats/stats/essence_keyword.py +++ b/tools/essence-feature-usage-stats/stats/essence_keyword.py @@ -1,18 +1,19 @@ +from typing import Dict + from stats.essence_file import EssenceFile from utils.colour import * # noqa: F403 class EssenceKeyword: - """ - EssenceKeyword stores, for a particular keyword "name", the file uses of that keyword, and aggregate statistics. - """ - - # ToDo use python getters / setters instead of java style, - # search: "python function as attribute" or ask Nik - - # ToDo some attrs should be private? + """EssenceKeyword stores, for a particular keyword "name", the file uses of that keyword, and aggregate statistics.""" def __init__(self, name: str, files=None): + """ + Create a new EssenceKeyword object. + + :param name: The Essence keyword + :param files: Collection of files that use it (more can be added after creation) + """ if files is None: files = [] @@ -21,11 +22,17 @@ def __init__(self, name: str, files=None): self.min_usages = None self.max_usages = None - self.file_usages = {} + self._file_usages = {} for file in files: self.add_file(file) + @property + def file_usages(self) -> Dict[EssenceFile, int]: + """Get a dictionary of EssenceFile objects and usages of this keyword in these files.""" + return self._file_usages + def add_file(self, file: EssenceFile): + """Add a file that uses this EssenceKeyword to the stats.""" if file not in self.file_usages and file.get_uses(self.name) > 0: usages = file.get_uses(self.name) self.file_usages[file] = usages @@ -43,25 +50,35 @@ def add_file(self, file: EssenceFile): @property def files(self): + """Get all files that use this keyword.""" return set(self.file_usages.keys()) @property - def num_files_using_feature(self) -> int: + def num_files_using_keyword(self) -> int: + """Get number of files that use this Essence keyword.""" return len(self.files) @property def avg_usages(self) -> float: + """Get the average number of usages of this keyword per file.""" return float(self.total_usages) / float( - self.num_files_using_feature, + self.num_files_using_keyword, ) def get_file_paths(self, depth=0) -> list: + """ + Get paths to files that use this essence keyword, trimmed to a given depth. + + :param depth: trim file paths, leaving a part of the path of this length (from the end). + """ return [x.get_str_path(depth) for x in self.files] def get_usages_in_file(self, file) -> int: + """Get how often this Essence keyword is used in the given file.""" return file.get_uses(self.name) def as_json(self, path_depth=0) -> dict: + """Get data for this Essence keyword as a JSON.""" return { "name": self.name, "used_in_files": self.get_file_paths(path_depth), @@ -72,6 +89,7 @@ def as_json(self, path_depth=0) -> dict: } def get_colour(self, n_uses: int) -> Colour: # noqa: F405 + """Get colour to use for this keyword's corresponding table cell.""" avg = int(self.avg_usages) if n_uses == 0: diff --git a/tools/essence-feature-usage-stats/stats/essence_stats.py b/tools/essence-feature-usage-stats/stats/essence_stats.py index 2dbeb3a44..8b069968a 100644 --- a/tools/essence-feature-usage-stats/stats/essence_stats.py +++ b/tools/essence-feature-usage-stats/stats/essence_stats.py @@ -1,9 +1,10 @@ from pathlib import Path from typing import Optional -from stats.essence_keyword import EssenceKeyword from stats.essence_file import EssenceFile -from utils.git import InvalidGitRemoteUrlError, sync_repo +from stats.essence_keyword import EssenceKeyword +from utils.conjure import download_conjure +from utils.git_utils import clone_or_pull KeywordName: type = str FilePath: type = str @@ -14,97 +15,72 @@ class EssenceStats: - """ - Class that stores stats for a given directory with - """ - - # ToDo use python getters / setters instead of java style, - # search: "python function as attribute" or ask Nik - - # ToDo some attrs should be private? + """Class that stores stats for a given directory with.""" def __init__( # noqa: PLR0913 self, - essence_dir: str, - conjure_bin: str, - remote_repo_url=None, - remote_branch="master", - remote_name="origin", + conjure_dir: Path, + conjure_repo_url: str, + essence_repo_dir: Path, + essence_repo_url: str, + essence_branch="master", blocklist: Optional[list[KeywordName]] = None, ): + """ + Create a new EssenceStats object. + + :param conjure_dir: Path to a directory containing conjure binary + :param conjure_repo_url: GitHub URL to download conjure release from + :param essence_repo_dir: Local repo with Essence example files + :param essence_repo_url: GitHub repo with Essence example files + :param essence_branch: Branch to download essence files from (master by default) + :param blocklist: Essence keywords to ignore + """ if blocklist is None: blocklist = [] - self.essence_dir = Path(essence_dir).resolve() - self.conjure_bin = Path(conjure_bin).resolve() - self.blocklist = blocklist + self._essence_repo = clone_or_pull( + essence_repo_dir, + essence_repo_url, + essence_branch, + ) + self._conjure_bin = download_conjure( + conjure_dir, + repository_url=conjure_repo_url, + ) - self.essence_keywords: dict[KeywordName, EssenceKeyword] = {} - self.essence_files: dict[FilePath, EssenceFile] = {} + self._blocklist = blocklist - self._remote_repo_url = remote_repo_url - self._remote_branch = remote_branch - self._remote_name = remote_name - self._repo = None + self._essence_keywords: dict[KeywordName, EssenceKeyword] = {} + self._essence_files: dict[FilePath, EssenceFile] = {} - if remote_repo_url is not None: - self.sync_repo(remote_repo_url, remote_branch, remote_name) - - # just incase its a local file - # normally sync_repo calls this for us self._update_stats() + @property + def essence_dir(self) -> Path: + """Get path to essence examples dir.""" + return Path(self._essence_repo.working_dir) + def _update_stats(self): for file in EssenceFile.get_essence_files_from_dir( self.essence_dir, - self.conjure_bin, - blocklist=self.blocklist, + self._conjure_bin, + blocklist=self._blocklist, ): - self.essence_files[file.get_str_path()] = file + self._essence_files[file.get_str_path()] = file for keyword in file.keywords: - if keyword not in self.essence_keywords: - self.essence_keywords[keyword] = EssenceKeyword(keyword) - self.essence_keywords[keyword].add_file(file) - - def sync_repo( - self, - remote_repo_url: Optional[str] = None, - remote_branch: Optional[str] = None, - remote_name: Optional[str] = None, - ) -> None: - """ - Sync to an upstream git repository. - If an upstream repository is not given, the upstream repo specified at EssenceStats creation is used. - """ - if remote_repo_url is None: - remote_repo_url = self._remote_repo_url - if remote_branch is None: - remote_branch = self._remote_branch - if remote_name is None: - remote_name = self._remote_name - - try: - self._repo = sync_repo( - self.essence_dir, - remote_repo_url, - remote_name=remote_name, - branch=remote_branch, - ) - self._update_stats() - - self._remote_repo_url = remote_repo_url - self._remote_branch = remote_branch - self._remote_name = remote_name - except Exception as e: - raise InvalidGitRemoteUrlError(remote_repo_url) from e + if keyword not in self._essence_keywords: + self._essence_keywords[keyword] = EssenceKeyword(keyword) + self._essence_keywords[keyword].add_file(file) def get_essence_files( self, sort_mode: Optional[str] = None, reverse: bool = True, ) -> list[EssenceFile]: - ans = list(self.essence_files.values()) + """Get a list of all essence example files.""" + ans = list(self._essence_files.values()) match sort_mode: case "most-lines": @@ -119,7 +95,8 @@ def get_essence_keywords( sort_mode: Optional[str] = None, reverse: bool = True, ) -> list[EssenceKeyword]: - ans = list(self.essence_keywords.values()) + """Get all essence keywords used across all files.""" + ans = list(self._essence_keywords.values()) match sort_mode: case "most-used": @@ -132,12 +109,15 @@ def get_essence_keywords( return ans def get_stats_for_file(self, fpath: str) -> Optional[EssenceFile]: - return self.essence_files.get(fpath, None) + """Get stats for a specific file.""" + return self._essence_files.get(fpath, None) def get_stats_for_keyword(self, keyword: str) -> Optional[EssenceKeyword]: - return self.essence_keywords.get(keyword, None) + """Get stats for a specific keyword.""" + return self._essence_keywords.get(keyword, None) def as_json(self, path_depth=0) -> dict: + """Get the essence stats as a JSON dictionary.""" return { "essence_files": [x.as_json(path_depth) for x in self.get_essence_files()], "essence_keywords": [ diff --git a/tools/essence-feature-usage-stats/table.html b/tools/essence-feature-usage-stats/table.html index b444d5d49..19b8e1d7c 100644 --- a/tools/essence-feature-usage-stats/table.html +++ b/tools/essence-feature-usage-stats/table.html @@ -1,34639 +1,102700 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + Essence feature usage stats + + + + + +

    Essence feature usage stats

    + + +
    + +
    + + + + +

    5 most common keywords

    +
      + +
    1. Reference (2789 usages in 85 files)
    2. + +
    3. TagInt (2738 usages in 84 files)
    4. + +
    5. Constant (1807 usages in 83 files)
    6. + +
    7. ConstantInt (1807 usages in 83 files)
    8. + +
    9. DomainInt (931 usages in 84 files)
    10. + +
    + +
    +
    +

    Essence feature table

    -
    - - + +
    Essence FileReferenceTagIntConstantConstantIntDomainIntRangeBoundedSingleDomainReferenceAbstractLiteralGeneratorMkOpImageMkOpIndexingComprehensionAbsLitMatrixMkOpAndGenDomainNoReprMkOpSumMkOpEqLettingSizeAttr_NoneMkOpMinusRangeLowerBoundedDomainGenInExprDomainFunctionAbsLitTupleMkOpProductMkOpTwoBarsMkOpInAbsPatTupleMkOpImplyDomainSetDomainTupleMkOpLeqDomainMatrixDomainEnumMkOpOrAbsLitSetConditionMkOpNeqSizeAttr_SizeMkOpDivMkOpNotMkOpModObjectiveMkOpRangeMkOpToIntMkOpMaxMkOpDefinedRangeSingleMkOpGeqMkOpRelationProjMkOpLtMkOpPowMkOpActiveMkOpIntersectMkOpToSetWhereDomainSequenceMkOpGtMkOpPreImageDomainRelationLettingDomainDefnUnnamedMkOpAttributeAsConstraintMkOpRestrictMkOpNegateMkOpPowerSetAbsPatSetMkOpMinDomainBoolGivenDomainDefnEnumMkOpAllDiffMkOpSlicingMkOpPartsSizeAttr_MaxSizeSizeAttr_MinMaxSizepartsSizeisRegularpartsNumDomainPartitionLettingDomainDefnEnumMkOpLexLeqMkOpUnionMkOpIffConstantAbstractConstantBoolMkOpFreqSizeAttr_MinSizeSearchOrderBranchingOnDomainIntEDomainMSetMkOpSubsetEqMkOpTogetherMkOpPartyMkOpApartMkOpFlattenDomainVariantOccurAttr_NoneOccurAttr_MaxOccur
    params/gen.essence32621215410010010100001000110000000010000000000000011300000000000000000000000000000000000000000000000000
    csplib-prob133/knapsack.essence7300302002202000200300022000000101030000000010000000000000000000000000100000000000000000000000000000
    csplib-prob005/LowAutocorrelationBinarySequences.essence9181111752022202202300111001010000000000000000010000200010000000000010000000000000000000000000000000000
    csplib-prob022/BusDriverScheduling.essence4000001001001010000400010001100200020000000010000000000000000000000000100200111100000000000000000000
    VanDerWaerdenNumbers/VanDerWaerden.essence133019191184044004443300143010010100000000000111000000000000000000000000000000100111100000000000000000000
    csplib-prob003/QG3.essence13844424934303034011110301300000030000000000000000200000000000002200000000000000000000000000000000000
    csplib-prob003/QG4.essence13844424934303034011110301300000030000000000000000200000000000002200000000000000000000000000000000000
    csplib-prob003/QG5.essence13844424934303034011110301300000030000000000000000200000000000002200000000000000000000000000000000000
    csplib-prob003/QG6.essence15844424944403034011110301400000030000000000000000200000000000002200000000000000000000000000000000000
    csplib-prob003/QG7.essence15844424944403034011110301400000030000000000000000200000000000002200000000000000000000000000000000000
    csplib-prob007/AllIntervalSeries.essence11201313761211301111112251202001000000000000000000000000000000000000000000000000000000000000000000000000
    knapsack/knapsack.essence11511413003303001310300022000000101040000000010000000000000000000000000100000000000000000000000000000
    csplib-prob015/SchursLemma.essence121388534224002221111102130000001100001001200000000000000000000000000000000000111100000000000000010000
    csplib-prob025/Lam.essence15755217917086137330000000000000000201011003000300000000000000010000001000000000000000000000000000000
    csplib-prob041/NFractionsPuzzle.essence125137371413341034031013722111201050000001000000020000100000000000000000000000000000000000000000000000000000
    csplib-prob054/nqueens.essence9422212402201012001121101002000000000011000000000000100000000000000000000000000000000000000000000000
    csplib-prob010/SocialGolfersProblem.essence111066413323002112100003010010000101000111300000100000000000000010000000000000111100000000000001000000
    csplib-prob019/MagicSquares.essence24201313767927087227742021200000000000200000000000000000030000000000000000010000000000000000000000001000
    tsp/tsp.essence21201111974042602201212110011210020010000000100010010000000000100000000000000000000000000000000000000000
    csplib-prob034/WarehouseLocation.essence131799833823403112302405214101000011000000000011000000000000001000000000000000000000000000000000000000
    csplib-prob036/FixedLengthErrorCorrectingCodes.essence151588743323302111102203222110000110030011100000000010000000000000000000100000000000000000000000000000
    csplib-prob053-GracefulGears/GracefulGears.essence2050363614132692602922235241402072000000000010010200000000000000000000000000000000000000000000000000000000
    csplib-prob053/GracefulGears.essence2050363614132692602922235241402072000000000010010200000000000000000000000000000000000000000000000000000000
    csplib-prob001/CarSequencing.essence202916161374924504234313526304001000001000000000000100001000000001100000000000000000000000000000000000000
    csplib-prob026/SportsTournamentScheduling.essence191412122110928007156120021020011220101001111220100100003000031000130000000000000000000000000000000000000
    csplib-prob053-GracefulWheelGraphs/GracefulWheelGraphs.essence19271818982642602422225241402022000000000000000100000000000000000000000000000000000000000000000000000000
    csplib-prob053/GracefulWheelGraphs.essence19271818982642602422225241402022000000000000000100000000000000000000000000000000000000000000000000000000
    csplib-prob009/PerfectSquarePlacement.essence4340262614125714416031033712322212021010000001410000000020020200001110000000020000000000000000000000000000000
    csplib-prob030/BalancedAcademicCurriculumProblem.essence252413131146926405254202307222002001002000000000000000021100000004100000000000000000000000000000000000000
    csplib-prob038/steelMill.essence191055517307307020302504172001000101010010000010010020000010000000000010100300111100000000000000000000
    csplib-prob053-GracefulHelms/GracefulHelms.essence2745313114133793903933435251402053000000000000000100000000000000000000000000000000000000000000000000000000
    csplib-prob053/GracefulHelms.essence2745313114133793903933435251402053000000000000000100000000000000000000000000000000000000000000000000000000
    csplib-prob006/GolombRuler.essence15644214022002020001021020000101100000202100010010000010000000000002200000000000000000000000000000000
    csplib-prob013/PPP-function.essence261277519709508062231304173001001202000000100011100000100000001000000000000000000000000001000000000000
    paramgen/TailAssignment-paramgen.essence27191212777925105272005400231000122107000000001000001000000000010200000000000000000000000000000000000000
    csplib-prob006-decision/GolombRuler.essence14744314022002020001021020000101100000202100000000000010000000000002200000000000000000000000000000000
    csplib-prob028/BIBD.essence151055504604003034030105000003000000000011000000000004000140000120000000000000000000000000000000000000
    csplib-prob048/MinimumEnergyBroadcast.essence31201212869855505331132302243220042010000004000010120000000000010000000000000000000000000000000000000000
    csplib-prob013-decision/ProgressivePartyProblem.essence271488629709508062231304173000001202000000100001100000100000001000000000000001000000000000000000000000
    csplib-prob055/EFPA.essence191588736616305133234104331010001100000002100000200000000000000000000000000000000000000000000000000000
    csplib-prob013/PPP-partition.essence221599629428206150121404182104000201000000100010000000000100000000001100010200111100000001000000100000
    csplib-prob044/steiner.essence13282020872032022322121021000011000101101000110200000000000101000000000000000000000000000000000000000000
    csplib-prob024/Langford-positional.essence173019201082472402422213132301420000010000000000000000000100000000000000000000000000000001000000000000000
    csplib-prob053-GracefulDoubleWheelGraphs/GracefulDoubleWheelGraphs.essence3659414118174812412041244546271502074000000000000000200000000000000000000000000000000000000000000000000000000
    csplib-prob053/GracefulDoubleWheelGraphs.essence3659414118174812412041244546271502074000000000000000200000000000000000000000000000000000000000000000000000000
    csplib-prob002/TemplateDesign.essence131688843723403113201303103110000010000000000011010010000000000010000000000000000000000000000000000000
    csplib-prob049/set_partition_full.essence161399423203003011241002120002000200000000220100000000020101000000000000000000000000100000000000000000
    csplib-prob039/Rehearsal.essence3518101085716271107257403503304000000003000040000010000023000000000100000000000000000000000000000000000000
    csplib-prob049/set_partition_simple.essence19151111434224004200451001140022000200000000220100000000000101000000000000000000000000100000000000000000
    csplib-prob028/BIBD-sym.essence39402727131010106100096510234163200043000000000010020000400008100141010100000000000000000002000000000000000000
    csplib-prob065/opd.essence3639252514112191001910308033110061000202000002230310200000000101000000001100000000000000000000000000000000
    csplib-prob110/ArmiesOfQueens.essence151388544432002340112221220006020210000003000010000000000000000000000000000000000000000000000000000000
    csplib-prob032/MaximumDensityStillLife.essence2756393917161251690069481112101210502530112000221002010300000000100000000060000000000000000000000000000000000
    csplib-prob056/sonetAsMSet.essence131488633213003110111103130011000300001000200010000000000000000000000000000010000000000000000110000010
    csplib-prob056/sonetAsSet.essence131599633213003110111103130011000400001000100010000000000000000000000000000011000000000000000010000000
    csplib-prob016/TrafficLights.essence15866221491201111104100301400100010020400000100000200000000000000000000000000000010000000000000000000
    csplib-prob033/WordDesign.essence241088227375405132311210131503100100010101001010200020000000002000002200000000000010000000000000000000
    csplib-prob027/prob027-alientiles-singlepass.essence3118111175111631101873111702032200000000001402001000210000000000000000000000000000000000000000000000000000000
    csplib-prob023/MagicHexagon.essence6676505026251111611010101061111440201100025001000201603010100060000010001000000000000000000000000000000000000000000
    rcpsp/rcpsp.essence4518881049499190938841110001196000001420240010000010000020100000000000000001400000000000010000000000000000
    SandwichSudoku/SandwichSudoku.essence6259394118161827101803213810186310401000404030001000400000000000000200000010000000000032000000000002000000000000000
    csplib-prob132/layout.essence2624141410791267307475224603422202420410002000000000001000000000002000000020000000000000010000000000000000
    csplib-prob017/RamseyNumbers.essence321266639787406275032010121610201211010000303000002000100001000000002200000000000010000000000000000000
    csplib-prob115/TailAssignment.essence463220201291415614100133119222643253303600102003020000007002001000100000200000000000000000000000000000000000000
    prob128-Cross/prob128-Cross.essence3729181811111310371206163063510345201161020001000000001002000000011000000000000000000000000000000000000000000
    csplib-prob057/KillerSudoku.essence38644141231989981186958525134401040000000501000000000000000000000000000000000022000000000000000000000000000
    Transshipment/Transshipment.essence353116161571913194091337756083660000100041000040000002020000000000000000000000000000000000000000000000000000
    csplib-prob083/Transshipment.essence353116161571913194091337756083660000100041000040000002020000000000000000000000000000000000000000000000000000
    csplib-prob018/water_buckets.essence664526261911296810240107936924201740041131012001101001010010000000000200000000000000020000000000000000000000000
    prob037-peg-simple/prob037-peg-simple.essence631311021022929109271014209201610835180301603902112005111043000000020200100020000000000000001000000000000000000000000
    prob037/prob037.essence6683595924221492371007171418846824626011971421002000043002002000000001000000000000000000000000100000000000000000
    csplib-prob042/diagnosis-single.essence25352523121145531223552052601216001010000202000000010000000000000000000030005000000000000000200000000000000
    csplib-prob050/DiamondFree.essence3519131365911109506269231210101701100001000110000200100010300110000100000000000000000000000000110000000000
    CVRP/cvrpAsSet.essence4136242412812589908412925214272413030112000011010110100000000000100000000000010002000000000000000000000000
    csplib-prob040/WW.essence625736362114101361036010668844767426020000100000000300010100000000000310000000000000000000000000000000000000000
    csplib-prob051/TankAlloc-051.essence232213139551335095244223304310010200400500100102010200010000000000000000000000000000000000000000000000000
    csplib-prob008/VesselLoading.essence86432626171272216738046670468856080000031000041005100000040040000000000000000040000000000000000000000000000000
    prob123-Milk/prob123-Milk.essence3448353414125775505761531602144000700302001001102008000000000201000000000000000000000000110100000000000000
    csplib-prob116/Vellino.essence8616101063133313250133143260402010400214080030600000080110113000000000000010000000000010000020010030000100000001
    csplib-prob040/DistributionWagnerWhitin.essence534728281912101617995105579343474221210310120500030000010004000000000000000000000000000000000000000000000000000
    prob037-peg/prob037-peg.essence841441071073737101335102213927221012651903027031500120102111145000000000000100000000000000000001000000000000000000000000
    csplib-prob045/CoveringArray.essence3531171714107007467067010034000000001000201000200000000020110001200000000000004000000002000000000000000000
    csplib-prob031/RackConfiguration.essence31321717157208384073304227072870320120013000010000012020000000000000010000000000000000000000000000000000000
    csplib-prob012/nonogram.essence96107737334291217221205612221212121630853000000000008010000000000000000000000020000000000000000000000000000000000000000
    + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    csplib-prob021/Crossfigures.essence370237173173644029174918224418332310659546058016142Essence File0ReferenceTagInt6ConstantConstantInt42DomainIntRangeBounded4SingleDomainReference9AbstractLiteralGenerator2MkOpImageMkOpIndexing6ComprehensionAbsLitMatrix7MkOpAndGenDomainNoRepr2MkOpSumMkOpEq0LettingSizeAttr_None4MkOpMinusRangeLowerBounded2DomainGenInExpr0DomainFunctionAbsLitTuple4MkOpProductMkOpTwoBars0MkOpInAbsPatTuple2MkOpImplyDomainSet0DomainTupleMkOpLeq0DomainMatrixDomainEnum0MkOpOrAbsLitSet2ConditionMkOpNeq0SizeAttr_SizeMkOpDiv0MkOpNotMkOpMod2ObjectiveMkOpRange0MkOpToIntMkOpMax0MkOpDefinedRangeSingle7MkOpGeqMkOpRelationProj16MkOpLtMkOpPow0MkOpActiveMkOpIntersect0MkOpToSetWhere0DomainSequenceMkOpGt2MkOpPreImageDomainRelation2LettingDomainDefnUnnamedMkOpRestrict0MkOpAttributeAsConstraintMkOpNegate0MkOpPowerSetAbsPatSet0MkOpMinDomainBool0GivenDomainDefnEnumMkOpAllDiff0MkOpSlicingMkOpParts0SizeAttr_MaxSizeSizeAttr_MinMaxSize0DomainPartitionpartsSize0partsNumisRegular0LettingDomainDefnEnumMkOpLexLeq2MkOpUnionMkOpIff0ConstantAbstractConstantBool0MkOpFreqSizeAttr_MinSize0SearchOrderDomainIntE0BranchingOnMkOpSubsetEq2DomainMSetMkOpTogether0MkOpPartyMkOpApart0MkOpFlattenDomainVariant0OccurAttr_NoneOccurAttr_MaxOccur0010000000112000000100
    params/gen.essence + 3 + 26 + 21 + 21 + 5 + 4 + 1 + 0 + 0 + 1 + 0 + 0 + 1 + 0 + 1 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 13 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob133/knapsack.essence + 7 + 3 + 0 + 0 + 3 + 0 + 2 + 0 + 0 + 2 + 2 + 0 + 2 + 0 + 0 + 0 + 2 + 0 + 0 + 3 + 0 + 0 + 0 + 2 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 1 + 0 + 3 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob005/LowAutocorrelationBinarySequences.essence + 9 + 18 + 11 + 11 + 7 + 5 + 2 + 0 + 2 + 2 + 2 + 0 + 2 + 2 + 0 + 2 + 3 + 0 + 0 + 1 + 1 + 1 + 0 + 0 + 1 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob022/BusDriverScheduling.essence + 4 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 1 + 0 + 0 + 1 + 0 + 1 + 0 + 0 + 0 + 0 + 4 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 2 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 2 + 0 + 0 + 1 + 1 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    VanDerWaerdenNumbers/VanDerWaerden.essence + 13 + 30 + 19 + 19 + 11 + 8 + 4 + 0 + 4 + 4 + 0 + 0 + 4 + 4 + 4 + 3 + 3 + 0 + 0 + 1 + 4 + 3 + 0 + 1 + 0 + 0 + 1 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 1 + 1 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob003/QG3.essence + 13 + 8 + 4 + 4 + 4 + 2 + 4 + 9 + 3 + 4 + 3 + 0 + 3 + 0 + 3 + 4 + 0 + 1 + 1 + 1 + 1 + 0 + 3 + 0 + 1 + 3 + 0 + 0 + 0 + 0 + 0 + 0 + 3 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob003/QG4.essence + 13 + 8 + 4 + 4 + 4 + 2 + 4 + 9 + 3 + 4 + 3 + 0 + 3 + 0 + 3 + 4 + 0 + 1 + 1 + 1 + 1 + 0 + 3 + 0 + 1 + 3 + 0 + 0 + 0 + 0 + 0 + 0 + 3 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob003/QG5.essence + 13 + 8 + 4 + 4 + 4 + 2 + 4 + 9 + 3 + 4 + 3 + 0 + 3 + 0 + 3 + 4 + 0 + 1 + 1 + 1 + 1 + 0 + 3 + 0 + 1 + 3 + 0 + 0 + 0 + 0 + 0 + 0 + 3 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob003/QG6.essence + 15 + 8 + 4 + 4 + 4 + 2 + 4 + 9 + 4 + 4 + 4 + 0 + 3 + 0 + 3 + 4 + 0 + 1 + 1 + 1 + 1 + 0 + 3 + 0 + 1 + 4 + 0 + 0 + 0 + 0 + 0 + 0 + 3 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob003/QG7.essence + 15 + 8 + 4 + 4 + 4 + 2 + 4 + 9 + 4 + 4 + 4 + 0 + 3 + 0 + 3 + 4 + 0 + 1 + 1 + 1 + 1 + 0 + 3 + 0 + 1 + 4 + 0 + 0 + 0 + 0 + 0 + 0 + 3 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob007/AllIntervalSeries.essence + 11 + 20 + 13 + 13 + 7 + 6 + 1 + 2 + 1 + 1 + 3 + 0 + 1 + 1 + 1 + 1 + 1 + 1 + 2 + 2 + 5 + 1 + 2 + 0 + 2 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    knapsack/knapsack.essence + 11 + 5 + 1 + 1 + 4 + 1 + 3 + 0 + 0 + 3 + 3 + 0 + 3 + 0 + 0 + 1 + 3 + 1 + 0 + 3 + 0 + 0 + 0 + 2 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 1 + 0 + 4 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob015/SchursLemma.essence + 12 + 13 + 8 + 8 + 5 + 3 + 4 + 2 + 2 + 4 + 0 + 0 + 2 + 2 + 2 + 1 + 1 + 1 + 1 + 1 + 0 + 2 + 1 + 3 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 1 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0
    csplib-prob025/Lam.essence + 15 + 7 + 5 + 5 + 2 + 1 + 7 + 9 + 1 + 7 + 0 + 8 + 6 + 1 + 3 + 7 + 3 + 3 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 1 + 0 + 1 + 1 + 0 + 0 + 3 + 0 + 0 + 0 + 3 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob041/NFractionsPuzzle.essence + 12 + 51 + 37 + 37 + 14 + 13 + 3 + 4 + 10 + 3 + 4 + 0 + 3 + 10 + 1 + 3 + 7 + 2 + 2 + 1 + 1 + 1 + 2 + 0 + 1 + 0 + 5 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob054/nqueens.essence + 9 + 4 + 2 + 2 + 2 + 1 + 2 + 4 + 0 + 2 + 2 + 0 + 1 + 0 + 1 + 2 + 0 + 0 + 1 + 1 + 2 + 1 + 1 + 0 + 1 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob010/SocialGolfersProblem.essence + 11 + 10 + 6 + 6 + 4 + 1 + 3 + 3 + 2 + 3 + 0 + 0 + 2 + 1 + 1 + 2 + 1 + 0 + 0 + 0 + 0 + 3 + 0 + 1 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 1 + 0 + 1 + 0 + 0 + 0 + 1 + 1 + 1 + 3 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob019/MagicSquares.essence + 24 + 20 + 13 + 13 + 7 + 6 + 7 + 9 + 2 + 7 + 0 + 8 + 7 + 2 + 2 + 7 + 7 + 4 + 2 + 0 + 2 + 1 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 3 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0
    tsp/tsp.essence + 21 + 20 + 11 + 11 + 9 + 7 + 4 + 0 + 4 + 2 + 6 + 0 + 2 + 2 + 0 + 1 + 2 + 1 + 2 + 1 + 1 + 0 + 0 + 1 + 1 + 2 + 1 + 0 + 0 + 2 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob034/WarehouseLocation.essence + 13 + 17 + 9 + 9 + 8 + 3 + 3 + 8 + 2 + 3 + 4 + 0 + 3 + 1 + 1 + 2 + 3 + 0 + 2 + 4 + 0 + 5 + 2 + 1 + 4 + 1 + 0 + 1 + 0 + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob036/FixedLengthErrorCorrectingCodes.essence + 15 + 15 + 8 + 8 + 7 + 4 + 3 + 3 + 2 + 3 + 3 + 0 + 2 + 1 + 1 + 1 + 1 + 0 + 2 + 2 + 0 + 3 + 2 + 2 + 2 + 1 + 1 + 0 + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 3 + 0 + 0 + 1 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob053-GracefulGears/GracefulGears.essence + 20 + 50 + 36 + 36 + 14 + 13 + 2 + 6 + 9 + 2 + 6 + 0 + 2 + 9 + 2 + 2 + 2 + 3 + 5 + 2 + 4 + 1 + 4 + 0 + 2 + 0 + 7 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 1 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob053/GracefulGears.essence + 20 + 50 + 36 + 36 + 14 + 13 + 2 + 6 + 9 + 2 + 6 + 0 + 2 + 9 + 2 + 2 + 2 + 3 + 5 + 2 + 4 + 1 + 4 + 0 + 2 + 0 + 7 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 1 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob001/CarSequencing.essence + 20 + 29 + 16 + 16 + 13 + 7 + 4 + 9 + 2 + 4 + 5 + 0 + 4 + 2 + 3 + 4 + 3 + 1 + 3 + 5 + 2 + 6 + 3 + 0 + 4 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob026/SportsTournamentScheduling.essence + 19 + 14 + 12 + 12 + 2 + 1 + 10 + 9 + 2 + 8 + 0 + 0 + 7 + 1 + 5 + 6 + 1 + 2 + 0 + 0 + 2 + 1 + 0 + 2 + 0 + 0 + 1 + 1 + 2 + 2 + 0 + 1 + 0 + 1 + 0 + 0 + 1 + 1 + 1 + 1 + 2 + 2 + 0 + 1 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 3 + 0 + 0 + 0 + 0 + 3 + 1 + 0 + 0 + 0 + 1 + 3 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob053-GracefulWheelGraphs/GracefulWheelGraphs.essence + 19 + 27 + 18 + 18 + 9 + 8 + 2 + 6 + 4 + 2 + 6 + 0 + 2 + 4 + 2 + 2 + 2 + 2 + 5 + 2 + 4 + 1 + 4 + 0 + 2 + 0 + 2 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob053/GracefulWheelGraphs.essence + 19 + 27 + 18 + 18 + 9 + 8 + 2 + 6 + 4 + 2 + 6 + 0 + 2 + 4 + 2 + 2 + 2 + 2 + 5 + 2 + 4 + 1 + 4 + 0 + 2 + 0 + 2 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob009/PerfectSquarePlacement.essence + 43 + 40 + 26 + 26 + 14 + 12 + 5 + 7 + 14 + 4 + 16 + 0 + 3 + 10 + 3 + 3 + 7 + 1 + 2 + 3 + 2 + 2 + 2 + 1 + 2 + 0 + 2 + 1 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 4 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 2 + 0 + 2 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob030/BalancedAcademicCurriculumProblem.essence + 25 + 24 + 13 + 13 + 11 + 4 + 6 + 9 + 2 + 6 + 4 + 0 + 5 + 2 + 5 + 4 + 2 + 0 + 2 + 3 + 0 + 7 + 2 + 2 + 2 + 0 + 0 + 2 + 0 + 0 + 1 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 4 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob038/steelMill.essence + 19 + 10 + 5 + 5 + 5 + 1 + 7 + 3 + 0 + 7 + 3 + 0 + 7 + 0 + 2 + 0 + 3 + 0 + 2 + 5 + 0 + 4 + 1 + 7 + 2 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 1 + 0 + 1 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 1 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 1 + 0 + 0 + 3 + 0 + 0 + 1 + 1 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob053-GracefulHelms/GracefulHelms.essence + 27 + 45 + 31 + 31 + 14 + 13 + 3 + 7 + 9 + 3 + 9 + 0 + 3 + 9 + 3 + 3 + 4 + 3 + 5 + 2 + 5 + 1 + 4 + 0 + 2 + 0 + 5 + 3 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob053/GracefulHelms.essence + 27 + 45 + 31 + 31 + 14 + 13 + 3 + 7 + 9 + 3 + 9 + 0 + 3 + 9 + 3 + 3 + 4 + 3 + 5 + 2 + 5 + 1 + 4 + 0 + 2 + 0 + 5 + 3 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob006/GolombRuler.essence + 15 + 6 + 4 + 4 + 2 + 1 + 4 + 0 + 2 + 2 + 0 + 0 + 2 + 0 + 2 + 0 + 0 + 0 + 1 + 0 + 2 + 1 + 0 + 2 + 0 + 0 + 0 + 0 + 1 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 2 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob013/PPP-function.essence + 26 + 12 + 7 + 7 + 5 + 1 + 9 + 7 + 0 + 9 + 5 + 0 + 8 + 0 + 6 + 2 + 2 + 3 + 1 + 3 + 0 + 4 + 1 + 7 + 3 + 0 + 0 + 1 + 0 + 0 + 1 + 2 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    paramgen/TailAssignment-paramgen.essence + 27 + 19 + 12 + 12 + 7 + 7 + 7 + 9 + 2 + 5 + 1 + 0 + 5 + 2 + 7 + 2 + 0 + 0 + 5 + 4 + 0 + 0 + 2 + 3 + 1 + 0 + 0 + 0 + 1 + 2 + 2 + 1 + 0 + 7 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob006-decision/GolombRuler.essence + 14 + 7 + 4 + 4 + 3 + 1 + 4 + 0 + 2 + 2 + 0 + 0 + 2 + 0 + 2 + 0 + 0 + 0 + 1 + 0 + 2 + 1 + 0 + 2 + 0 + 0 + 0 + 0 + 1 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 2 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob028/BIBD.essence + 15 + 10 + 5 + 5 + 5 + 0 + 4 + 6 + 0 + 4 + 0 + 0 + 3 + 0 + 3 + 4 + 0 + 3 + 0 + 1 + 0 + 5 + 0 + 0 + 0 + 0 + 0 + 3 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 4 + 0 + 0 + 0 + 1 + 4 + 0 + 0 + 0 + 0 + 1 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob048/MinimumEnergyBroadcast.essence + 31 + 20 + 12 + 12 + 8 + 6 + 9 + 8 + 5 + 5 + 5 + 0 + 5 + 3 + 3 + 1 + 1 + 3 + 2 + 3 + 0 + 2 + 2 + 4 + 3 + 2 + 2 + 0 + 0 + 4 + 2 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 4 + 0 + 0 + 0 + 0 + 1 + 0 + 1 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob013-decision/ProgressivePartyProblem.essence + 27 + 14 + 8 + 8 + 6 + 2 + 9 + 7 + 0 + 9 + 5 + 0 + 8 + 0 + 6 + 2 + 2 + 3 + 1 + 3 + 0 + 4 + 1 + 7 + 3 + 0 + 0 + 0 + 0 + 0 + 1 + 2 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob055/EFPA.essence + 19 + 15 + 8 + 8 + 7 + 3 + 6 + 6 + 1 + 6 + 3 + 0 + 5 + 1 + 3 + 3 + 2 + 3 + 4 + 1 + 0 + 4 + 3 + 3 + 1 + 0 + 1 + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 1 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob013/PPP-partition.essence + 22 + 15 + 9 + 9 + 6 + 2 + 9 + 4 + 2 + 8 + 2 + 0 + 6 + 1 + 5 + 0 + 1 + 2 + 1 + 4 + 0 + 4 + 1 + 8 + 2 + 1 + 0 + 4 + 0 + 0 + 0 + 2 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 1 + 0 + 2 + 0 + 0 + 1 + 1 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0
    csplib-prob044/steiner.essence + 13 + 28 + 20 + 20 + 8 + 7 + 2 + 0 + 3 + 2 + 0 + 2 + 2 + 3 + 2 + 2 + 1 + 2 + 1 + 0 + 2 + 1 + 0 + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 1 + 0 + 1 + 1 + 0 + 1 + 0 + 0 + 0 + 1 + 1 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob024/Langford-positional.essence + 17 + 30 + 19 + 20 + 10 + 8 + 2 + 4 + 7 + 2 + 4 + 0 + 2 + 4 + 2 + 2 + 2 + 1 + 3 + 1 + 3 + 2 + 3 + 0 + 1 + 4 + 2 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob053-GracefulDoubleWheelGraphs/GracefulDoubleWheelGraphs.essence + 36 + 59 + 41 + 41 + 18 + 17 + 4 + 8 + 12 + 4 + 12 + 0 + 4 + 12 + 4 + 4 + 5 + 4 + 6 + 2 + 7 + 1 + 5 + 0 + 2 + 0 + 7 + 4 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob053/GracefulDoubleWheelGraphs.essence + 36 + 59 + 41 + 41 + 18 + 17 + 4 + 8 + 12 + 4 + 12 + 0 + 4 + 12 + 4 + 4 + 5 + 4 + 6 + 2 + 7 + 1 + 5 + 0 + 2 + 0 + 7 + 4 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob002/TemplateDesign.essence + 13 + 16 + 8 + 8 + 8 + 4 + 3 + 7 + 2 + 3 + 4 + 0 + 3 + 1 + 1 + 3 + 2 + 0 + 1 + 3 + 0 + 3 + 1 + 0 + 3 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 0 + 1 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob049/set_partition_full.essence + 16 + 13 + 9 + 9 + 4 + 2 + 3 + 2 + 0 + 3 + 0 + 0 + 3 + 0 + 1 + 1 + 2 + 4 + 1 + 0 + 0 + 2 + 1 + 2 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 2 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 1 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob039/Rehearsal.essence + 35 + 18 + 10 + 10 + 8 + 5 + 7 + 16 + 2 + 7 + 11 + 0 + 7 + 2 + 5 + 7 + 4 + 0 + 3 + 5 + 0 + 3 + 3 + 0 + 4 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 3 + 0 + 0 + 0 + 0 + 4 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 2 + 3 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob049/set_partition_simple.essence + 19 + 15 + 11 + 11 + 4 + 3 + 4 + 2 + 2 + 4 + 0 + 0 + 4 + 2 + 0 + 0 + 4 + 5 + 1 + 0 + 0 + 1 + 1 + 4 + 0 + 0 + 2 + 2 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 2 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob028/BIBD-sym.essence + 39 + 40 + 27 + 27 + 13 + 10 + 10 + 10 + 6 + 10 + 0 + 0 + 9 + 6 + 5 + 10 + 2 + 3 + 4 + 1 + 6 + 3 + 2 + 0 + 0 + 0 + 4 + 3 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 4 + 0 + 0 + 0 + 0 + 8 + 1 + 0 + 0 + 1 + 4 + 1 + 0 + 1 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob065/opd.essence + 36 + 39 + 25 + 25 + 14 + 11 + 2 + 1 + 9 + 1 + 0 + 0 + 1 + 9 + 1 + 0 + 3 + 0 + 8 + 0 + 3 + 3 + 1 + 1 + 0 + 0 + 6 + 1 + 0 + 0 + 0 + 2 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 2 + 2 + 3 + 0 + 3 + 1 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob110/ArmiesOfQueens.essence + 15 + 13 + 8 + 8 + 5 + 4 + 4 + 4 + 3 + 2 + 0 + 0 + 2 + 3 + 4 + 0 + 1 + 1 + 2 + 2 + 2 + 1 + 2 + 2 + 0 + 0 + 0 + 6 + 0 + 2 + 0 + 2 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 3 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob032/MaximumDensityStillLife.essence + 27 + 56 + 39 + 39 + 17 + 16 + 12 + 5 + 16 + 9 + 0 + 0 + 6 + 9 + 4 + 8 + 11 + 1 + 2 + 1 + 0 + 1 + 2 + 1 + 0 + 5 + 0 + 2 + 5 + 3 + 0 + 1 + 1 + 2 + 0 + 0 + 0 + 2 + 2 + 1 + 0 + 0 + 2 + 0 + 1 + 0 + 3 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 6 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob056/sonetAsMSet.essence + 13 + 14 + 8 + 8 + 6 + 3 + 3 + 2 + 1 + 3 + 0 + 0 + 3 + 1 + 1 + 0 + 1 + 1 + 1 + 1 + 0 + 3 + 1 + 3 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 3 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 1 + 0
    csplib-prob056/sonetAsSet.essence + 13 + 15 + 9 + 9 + 6 + 3 + 3 + 2 + 1 + 3 + 0 + 0 + 3 + 1 + 1 + 0 + 1 + 1 + 1 + 1 + 0 + 3 + 1 + 3 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 4 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob016/TrafficLights.essence + 15 + 8 + 6 + 6 + 2 + 2 + 1 + 4 + 9 + 1 + 2 + 0 + 1 + 1 + 1 + 1 + 1 + 0 + 4 + 1 + 0 + 0 + 3 + 0 + 1 + 4 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 2 + 0 + 4 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob033/WordDesign.essence + 24 + 10 + 8 + 8 + 2 + 2 + 7 + 3 + 7 + 5 + 4 + 0 + 5 + 1 + 3 + 2 + 3 + 1 + 1 + 2 + 1 + 0 + 1 + 3 + 1 + 5 + 0 + 3 + 1 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 1 + 0 + 1 + 0 + 0 + 1 + 0 + 1 + 0 + 2 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 2 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob027/prob027-alientiles-singlepass.essence + 31 + 18 + 11 + 11 + 7 + 5 + 11 + 16 + 3 + 11 + 0 + 18 + 7 + 3 + 1 + 11 + 7 + 0 + 2 + 0 + 3 + 2 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 4 + 0 + 2 + 0 + 0 + 1 + 0 + 0 + 0 + 2 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob023/MagicHexagon.essence + 66 + 76 + 50 + 50 + 26 + 25 + 11 + 1 + 16 + 11 + 0 + 10 + 10 + 10 + 6 + 11 + 11 + 4 + 4 + 0 + 20 + 1 + 1 + 0 + 0 + 0 + 2 + 5 + 0 + 0 + 1 + 0 + 0 + 0 + 2 + 0 + 1 + 6 + 0 + 3 + 0 + 1 + 0 + 1 + 0 + 0 + 0 + 6 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    rcpsp/rcpsp.essence + 45 + 18 + 8 + 8 + 10 + 4 + 9 + 4 + 9 + 9 + 19 + 0 + 9 + 3 + 8 + 8 + 4 + 1 + 1 + 10 + 0 + 0 + 1 + 1 + 9 + 6 + 0 + 0 + 0 + 0 + 0 + 1 + 4 + 2 + 0 + 24 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 4 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    SandwichSudoku/SandwichSudoku.essence + 62 + 59 + 39 + 41 + 18 + 16 + 18 + 27 + 10 + 18 + 0 + 32 + 13 + 8 + 10 + 18 + 6 + 3 + 1 + 0 + 4 + 0 + 1 + 0 + 0 + 0 + 4 + 0 + 4 + 0 + 3 + 0 + 0 + 0 + 10 + 0 + 0 + 4 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 3 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob132/layout.essence + 26 + 24 + 14 + 14 + 10 + 7 + 9 + 12 + 6 + 7 + 3 + 0 + 7 + 4 + 7 + 5 + 2 + 2 + 4 + 6 + 0 + 3 + 4 + 2 + 2 + 2 + 0 + 2 + 4 + 2 + 0 + 4 + 1 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob017/RamseyNumbers.essence + 32 + 12 + 6 + 6 + 6 + 3 + 9 + 7 + 8 + 7 + 4 + 0 + 6 + 2 + 7 + 5 + 0 + 3 + 2 + 0 + 1 + 0 + 1 + 2 + 1 + 6 + 1 + 0 + 2 + 0 + 1 + 2 + 1 + 1 + 0 + 1 + 0 + 0 + 0 + 0 + 3 + 0 + 3 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob115/TailAssignment.essence + 46 + 32 + 20 + 20 + 12 + 9 + 14 + 15 + 6 + 14 + 10 + 0 + 13 + 3 + 11 + 9 + 2 + 2 + 2 + 6 + 4 + 3 + 2 + 5 + 3 + 3 + 0 + 3 + 6 + 0 + 0 + 1 + 0 + 2 + 0 + 0 + 3 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 7 + 0 + 0 + 2 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    prob128-Cross/prob128-Cross.essence + 37 + 29 + 18 + 18 + 11 + 11 + 13 + 10 + 3 + 7 + 12 + 0 + 6 + 1 + 6 + 3 + 0 + 6 + 3 + 5 + 1 + 0 + 3 + 4 + 5 + 2 + 0 + 1 + 1 + 6 + 1 + 0 + 2 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob057/KillerSudoku.essence + 38 + 64 + 41 + 41 + 23 + 19 + 8 + 9 + 9 + 8 + 1 + 18 + 6 + 9 + 5 + 8 + 5 + 2 + 5 + 1 + 3 + 4 + 4 + 0 + 1 + 0 + 4 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 5 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    Transshipment/Transshipment.essence + 35 + 31 + 16 + 16 + 15 + 7 + 19 + 13 + 1 + 9 + 4 + 0 + 9 + 1 + 3 + 3 + 7 + 7 + 5 + 6 + 0 + 8 + 3 + 6 + 6 + 0 + 0 + 0 + 0 + 10 + 0 + 0 + 4 + 1 + 0 + 0 + 0 + 0 + 4 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob083/Transshipment.essence + 35 + 31 + 16 + 16 + 15 + 7 + 19 + 13 + 1 + 9 + 4 + 0 + 9 + 1 + 3 + 3 + 7 + 7 + 5 + 6 + 0 + 8 + 3 + 6 + 6 + 0 + 0 + 0 + 0 + 10 + 0 + 0 + 4 + 1 + 0 + 0 + 0 + 0 + 4 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob018/water_buckets.essence + 66 + 45 + 26 + 26 + 19 + 11 + 29 + 6 + 8 + 10 + 24 + 0 + 10 + 7 + 9 + 3 + 6 + 9 + 2 + 4 + 2 + 0 + 1 + 7 + 4 + 0 + 0 + 4 + 1 + 13 + 1 + 0 + 1 + 2 + 0 + 0 + 1 + 1 + 0 + 1 + 0 + 0 + 1 + 0 + 1 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    prob037-peg-simple/prob037-peg-simple.essence + 63 + 131 + 102 + 102 + 29 + 29 + 10 + 9 + 27 + 10 + 14 + 20 + 9 + 20 + 16 + 10 + 8 + 3 + 5 + 1 + 8 + 0 + 3 + 0 + 1 + 6 + 0 + 3 + 9 + 0 + 2 + 1 + 1 + 2 + 0 + 0 + 5 + 1 + 1 + 1 + 0 + 4 + 3 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 2 + 0 + 0 + 1 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    prob037/prob037.essence + 66 + 83 + 59 + 59 + 24 + 22 + 14 + 9 + 23 + 7 + 10 + 0 + 7 + 17 + 14 + 1 + 8 + 8 + 4 + 6 + 8 + 2 + 4 + 6 + 2 + 6 + 0 + 11 + 9 + 7 + 1 + 4 + 2 + 1 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 4 + 3 + 0 + 0 + 2 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob042/diagnosis-single.essence + 25 + 35 + 25 + 23 + 12 + 11 + 4 + 5 + 5 + 3 + 12 + 2 + 3 + 5 + 5 + 2 + 0 + 5 + 2 + 6 + 0 + 1 + 2 + 1 + 6 + 0 + 0 + 1 + 0 + 1 + 0 + 0 + 0 + 0 + 2 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 3 + 0 + 0 + 0 + 5 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob050/DiamondFree.essence + 35 + 19 + 13 + 13 + 6 + 5 + 9 + 11 + 10 + 9 + 5 + 0 + 6 + 2 + 6 + 9 + 2 + 3 + 1 + 2 + 1 + 0 + 1 + 0 + 1 + 7 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 3 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    CVRP/cvrpAsSet.essence + 41 + 36 + 24 + 24 + 12 + 8 + 12 + 5 + 8 + 9 + 9 + 0 + 8 + 4 + 1 + 2 + 9 + 2 + 5 + 2 + 1 + 4 + 2 + 7 + 2 + 4 + 1 + 3 + 0 + 3 + 0 + 1 + 1 + 2 + 0 + 0 + 0 + 0 + 1 + 1 + 0 + 1 + 0 + 1 + 1 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob040/WW.essence + 62 + 57 + 36 + 36 + 21 + 14 + 10 + 13 + 6 + 10 + 36 + 0 + 10 + 6 + 6 + 8 + 8 + 4 + 4 + 7 + 6 + 7 + 4 + 2 + 6 + 0 + 2 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 3 + 0 + 0 + 0 + 1 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 3 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob051/TankAlloc-051.essence + 23 + 22 + 13 + 13 + 9 + 5 + 5 + 13 + 3 + 5 + 0 + 9 + 5 + 2 + 4 + 4 + 2 + 2 + 3 + 3 + 0 + 4 + 3 + 1 + 0 + 0 + 1 + 0 + 2 + 0 + 0 + 4 + 0 + 0 + 5 + 0 + 0 + 1 + 0 + 0 + 1 + 0 + 2 + 0 + 1 + 0 + 2 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob008/VesselLoading.essence + 86 + 43 + 26 + 26 + 17 + 12 + 7 + 22 + 16 + 7 + 38 + 0 + 4 + 6 + 6 + 7 + 0 + 4 + 6 + 8 + 8 + 5 + 6 + 0 + 8 + 0 + 0 + 0 + 0 + 0 + 3 + 1 + 0 + 0 + 0 + 0 + 4 + 10 + 0 + 5 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 4 + 0 + 0 + 4 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 4 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    prob123-Milk/prob123-Milk.essence + 34 + 48 + 35 + 34 + 14 + 12 + 5 + 7 + 7 + 5 + 5 + 0 + 5 + 7 + 6 + 1 + 5 + 3 + 1 + 6 + 0 + 2 + 1 + 4 + 4 + 0 + 0 + 0 + 7 + 0 + 0 + 3 + 0 + 2 + 0 + 0 + 1 + 0 + 0 + 1 + 1 + 0 + 2 + 0 + 0 + 8 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob116/Vellino.essence + 86 + 16 + 10 + 10 + 6 + 3 + 13 + 3 + 3 + 13 + 25 + 0 + 13 + 3 + 14 + 3 + 2 + 6 + 0 + 4 + 0 + 2 + 0 + 10 + 4 + 0 + 0 + 2 + 14 + 0 + 8 + 0 + 0 + 3 + 0 + 6 + 0 + 0 + 0 + 0 + 0 + 0 + 8 + 0 + 1 + 1 + 0 + 1 + 13 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 1 + 0 + 0 + 3 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 1
    csplib-prob040/DistributionWagnerWhitin.essence + 53 + 47 + 28 + 28 + 19 + 12 + 10 + 16 + 17 + 9 + 9 + 5 + 10 + 5 + 5 + 7 + 9 + 3 + 4 + 3 + 4 + 7 + 4 + 2 + 2 + 12 + 1 + 0 + 3 + 1 + 0 + 1 + 2 + 0 + 5 + 0 + 0 + 0 + 3 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 4 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    prob037-peg/prob037-peg.essence + 84 + 144 + 107 + 107 + 37 + 37 + 10 + 13 + 35 + 10 + 22 + 13 + 9 + 27 + 22 + 10 + 12 + 6 + 5 + 1 + 9 + 0 + 3 + 0 + 2 + 7 + 0 + 3 + 15 + 0 + 0 + 1 + 2 + 0 + 1 + 0 + 2 + 1 + 1 + 1 + 1 + 4 + 5 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob045/CoveringArray.essence + 35 + 31 + 17 + 17 + 14 + 10 + 7 + 0 + 0 + 7 + 4 + 6 + 7 + 0 + 6 + 7 + 0 + 1 + 0 + 0 + 3 + 4 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 2 + 0 + 1 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 1 + 1 + 0 + 0 + 0 + 1 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 4 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob031/RackConfiguration.essence + 31 + 32 + 17 + 17 + 15 + 7 + 20 + 8 + 3 + 8 + 4 + 0 + 7 + 3 + 3 + 0 + 4 + 2 + 2 + 7 + 0 + 7 + 2 + 8 + 7 + 0 + 3 + 2 + 0 + 12 + 0 + 0 + 1 + 3 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 1 + 2 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob012/nonogram.essence + 96 + 107 + 73 + 73 + 34 + 29 + 12 + 17 + 22 + 12 + 0 + 56 + 12 + 22 + 12 + 12 + 12 + 16 + 3 + 0 + 8 + 5 + 3 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 8 + 0 + 10 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
    csplib-prob021/Crossfigures.essence + 370 + 237 + 173 + 173 + 64 + 40 + 29 + 17 + 49 + 18 + 2 + 244 + 18 + 33 + 23 + 10 + 6 + 59 + 5 + 4 + 6 + 0 + 5 + 8 + 0 + 16 + 14 + 2 + 0 + 6 + 42 + 4 + 9 + 2 + 6 + 7 + 2 + 0 + 4 + 2 + 0 + 4 + 0 + 2 + 0 + 0 + 0 + 2 + 0 + 0 + 2 + 0 + 0 + 7 + 16 + 0 + 0 + 0 + 2 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 2 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0
    + + + + + + - - \ No newline at end of file + + + + \ No newline at end of file diff --git a/tools/essence-feature-usage-stats/test/test_data/__init__.py b/tools/essence-feature-usage-stats/test/test_data/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tools/essence-feature-usage-stats/test/test_data/constants.py b/tools/essence-feature-usage-stats/test/test_data/constants.py index 9b5195ffd..0bf83ebc1 100644 --- a/tools/essence-feature-usage-stats/test/test_data/constants.py +++ b/tools/essence-feature-usage-stats/test/test_data/constants.py @@ -36,10 +36,10 @@ ], {"DomainEnum": [{"Name": "items"}, None, None]}, {"DomainInt": [{"TagInt": []}, []]}, - ] + ], }, - ] - } + ], + }, }, { "Declaration": { @@ -56,10 +56,10 @@ ], {"DomainEnum": [{"Name": "items"}, None, None]}, {"DomainInt": [{"TagInt": []}, []]}, - ] + ], }, - ] - } + ], + }, }, { "Declaration": { @@ -67,8 +67,8 @@ "Given", {"Name": "capacity"}, {"DomainInt": [{"TagInt": []}, []]}, - ] - } + ], + }, }, { "Declaration": { @@ -80,10 +80,10 @@ [], {"SizeAttr_None": []}, {"DomainEnum": [{"Name": "items"}, None, None]}, - ] + ], }, - ] - } + ], + }, }, { "Objective": [ @@ -97,8 +97,8 @@ "MkOpImage": [ {"Reference": [{"Name": "gain"}, None]}, {"Reference": [{"Name": "i"}, None]}, - ] - } + ], + }, }, [ { @@ -109,17 +109,17 @@ "Reference": [ {"Name": "picked"}, None, - ] + ], }, - ] - } - } + ], + }, + }, ], - ] - } - } + ], + }, + }, }, - ] + ], }, { "SuchThat": [ @@ -137,16 +137,16 @@ "Reference": [ {"Name": "weight"}, None, - ] + ], }, { "Reference": [ {"Name": "i"}, None, - ] + ], }, - ] - } + ], + }, }, [ { @@ -157,21 +157,21 @@ "Reference": [ {"Name": "picked"}, None, - ] + ], }, - ] - } - } + ], + }, + }, ], - ] - } - } + ], + }, + }, }, {"Reference": [{"Name": "capacity"}, None]}, - ] - } - } - ] + ], + }, + }, + ], }, ], } diff --git a/tools/essence-feature-usage-stats/test/test_essence_file.py b/tools/essence-feature-usage-stats/test/test_essence_file.py index 016a0e7ab..9091b5b7e 100644 --- a/tools/essence-feature-usage-stats/test/test_essence_file.py +++ b/tools/essence-feature-usage-stats/test/test_essence_file.py @@ -3,9 +3,9 @@ from pathlib import Path from dotenv import load_dotenv +from test_data.constants import KNAPSACK_AST from stats.essence_file import EssenceFile -from test_data.constants import KNAPSACK_AST ENV_PATH = Path("../.env").resolve() load_dotenv(dotenv_path=ENV_PATH) @@ -15,20 +15,26 @@ class TestEssenceFile(unittest.TestCase): + """Tests for EssenceFile class.""" + def test_instantiate(self): + """Test that an EssenceFile can be instantiated.""" file = EssenceFile("test_data/knapsack.essence", CONJURE_BIN) self.assertIsInstance(file, EssenceFile) def test_path(self): + """Test that an EssenceFile object has the correct path.""" file = EssenceFile("test_data/knapsack.essence", CONJURE_BIN) path = Path("test_data/knapsack.essence").resolve() self.assertEqual(file.path, path) def test_path_trimmed(self): + """Test that an EssenceFile path is trimmed correctly.""" file = EssenceFile("test_data/knapsack.essence", CONJURE_BIN) self.assertEqual(file.get_str_path(depth=1), "knapsack.essence") def test_ast(self): + """Test that an AST is generated correctly.""" file = EssenceFile("test_data/knapsack.essence", CONJURE_BIN) self.assertEqual(file.ast, KNAPSACK_AST) diff --git a/tools/essence-feature-usage-stats/utils/colour.py b/tools/essence-feature-usage-stats/utils/colour.py index 8fd0056a4..cc91f6ee7 100644 --- a/tools/essence-feature-usage-stats/utils/colour.py +++ b/tools/essence-feature-usage-stats/utils/colour.py @@ -4,6 +4,8 @@ class ColourConstructorError(ValueError): + """Thrown when incorrect arguments are passed to a Colour constructor.""" + default_message = """ Supported inputs: - Colour(r: int, g: int, b: int) @@ -13,15 +15,26 @@ class ColourConstructorError(ValueError): Values of r,g,b must be in range[0, 255] """ - def __init__(self, item): + def __init__(self, item): # noqa: D107 self.message = f"Not a valid colour: {item}\n" + self.default_message super(self.message) class Colour: + """Represents an RGB colour value.""" + def __init__(self, *args, **kwargs): + """ + Create a Colour object. + + Valid formats: + - Colour(r: int, g: int, b: int) + - Colour((r, g, b): tuple) + - Colour(hex: str) + - Colour(r=r: int, g=g: int, b=b: int) + """ # If we have 3 arguments, interpret them as rgb values - if len(args) >= 3: + if len(args) >= 3: # noqa: PLR2004 self.r, self.g, self.b = (clamp(int(x), 0, 255) for x in args[:3]) elif "hex" in kwargs: self.r, self.g, self.b = Colour.hex_to_rgb(kwargs["hex"]) @@ -40,11 +53,12 @@ def __init__(self, *args, **kwargs): @staticmethod def hex_to_rgb(hex_string): + """Convert a HEX colour string to an RGB tuple.""" # Remove any leading '#' if present hex_string = hex_string.lstrip("#") # Check if the hex string is a valid length (it's always 6 characters long) - if len(hex_string) != 6: + if len(hex_string) != 6: # noqa: PLR2004 raise ValueError("Invalid hex string length") # noqa: TRY003 # Convert the hex string to RGB values @@ -56,24 +70,31 @@ def hex_to_rgb(hex_string): @staticmethod def rgb_to_hex(rgb_tuple): + """Convert an RGB tuple to a HEX string.""" # Ensure that the RGB values are in the valid range (0-255) r, g, b = rgb_tuple - if not (0 <= r <= 255) or not (0 <= g <= 255) or not (0 <= b <= 255): + if ( + not (0 <= r <= 255) # noqa: PLR2004 + or not (0 <= g <= 255) # noqa: PLR2004 + or not (0 <= b <= 255) # noqa: PLR2004 + ): raise ValueError("RGB values must be in the range 0-255") # noqa: TRY003 # Convert the RGB values to a hex string return f"#{r:02X}{g:02X}{b:02X}" def as_rgb(self) -> tuple[int, int, int]: + """Get the colour value as an RGB tuple.""" return self.r, self.g, self.b def as_hex(self) -> str: + """Get the colour value as a hex string.""" return Colour.rgb_to_hex(self.as_rgb()) - def __str__(self) -> str: + def __str__(self) -> str: # noqa: D105 return self.as_hex() - def __repr__(self) -> str: + def __repr__(self) -> str: # noqa: D105 return f"Colour({self.as_hex()})" @@ -85,6 +106,7 @@ def __repr__(self) -> str: def get_linear_gradient_value(x, x_min, x_max, c_min: Colour, c_max: Colour) -> Colour: + """Given an integer value x, minumum and maximum values of x, and two colours, generate x's corresponding gradient value.""" r = int(map_range(x, x_min, x_max, float(c_min.r), float(c_max.r))) g = int(map_range(x, x_min, x_max, float(c_min.g), float(c_max.g))) b = int(map_range(x, x_min, x_max, float(c_min.b), float(c_max.b))) diff --git a/tools/essence-feature-usage-stats/utils/conjure.py b/tools/essence-feature-usage-stats/utils/conjure.py index 1f306537d..415029772 100644 --- a/tools/essence-feature-usage-stats/utils/conjure.py +++ b/tools/essence-feature-usage-stats/utils/conjure.py @@ -3,18 +3,25 @@ from os import PathLike from pathlib import Path +import requests + +from utils.files import download_and_extract, make_executable_recursive +from utils.git_utils import parse_repo_url + +HTTP_OK = 200 + def get_essence_file_ast( - fpath: Path | PathLike[str] | str, conjure_bin_path: Path | PathLike[str] | str + fpath: Path | PathLike[str] | str, + conjure_bin_path: Path | PathLike[str] | str, ) -> dict: """ - Run the `conjure pretty` command line tool and get the parsed AST as a dict - ToDo: Instead of relying on a conjure binary being provided, download one automatically if needed + Run the `conjure pretty` command line tool and get the parsed AST as a dict. + :param conjure_bin_path: path to conjure binary :param fpath: path to an essence file - :return: the Abstract Syntax Tree in json format (as a dict) + :return: the Abstract Syntax Tree in json format (as a dict). """ - result = subprocess.run( [str(conjure_bin_path), "pretty", "--output-format=astjson", str(fpath)], capture_output=True, @@ -24,25 +31,77 @@ def get_essence_file_ast( return json.loads(result.stdout) -def get_version(conjure_bin_path: Path | PathLike[str] | str) -> tuple[str, str]: +def get_release_id_by_version(repository_url: str, version: str) -> str | None: + """Get release id for a specific release version of a repo from the GitHub API.""" + user, repo = parse_repo_url(repository_url) + api_url = f"https://api.github.com/repos/{user}/{repo}/releases" + response = requests.get(api_url) + + if response.status_code != HTTP_OK: + print(f"Failed to get the latest release information from {api_url}") + else: + release_data = response.json() + for release in release_data: + if version in (release["name"], release["tag_name"]): + return release[id] + + return None + + +def get_release_url(repository_url: str, version: str) -> str: + """Build the GitHub API url for a specific release version of a repo.""" + user, repo = parse_repo_url(repository_url) + + if version != "latest": + version = get_release_id_by_version(repository_url, version) + + return f"https://api.github.com/repos/{user}/{repo}/releases/{version}" + + +def get_conjure_zip_file_url(assets, version): + """Get github relese asset for a release of conjure.""" + for asset in assets: + if asset["name"] == f"conjure-{version}-linux.zip": + return asset["browser_download_url"] + return None + + +def download_conjure( + output_dir: Path | PathLike[str] | str, + version="latest", + repository_url="https://github.com/conjure-cp/conjure", +): """ - Get version from conjure. Not useful now but maybe use this to auto-update conjure from git repo in the future? - :param conjure_bin_path: path to conjure binary - :return: tuple of (version, commit) - conjure version and git repo version (as given by conjure --version) + Download conjure from GitHub and install the binary to a local directory. + + :param output_dir: local directory to download the conjure binary to + :param version: Conjure release version ("latest" or "vX.Y.Z") + :param repository_url: the GitHub repository URL """ - result = subprocess.run( - [str(conjure_bin_path), "--version"], - capture_output=True, - text=True, - check=True, + print( + f"Downloading Conjure release {version} from {repository_url} to {output_dir}", ) - version, commit = None, None - lines = result.stdout.split("\n") - for line in lines: - if "Release version" in line: - version = line.removeprefix("Release version ") - if "Repository version" in line: - commit, *ts_parts = line.removeprefix("Repository version ").split() + output_dir = Path(output_dir) + api_url = get_release_url(repository_url, version) + response = requests.get(api_url) + + if response.status_code != HTTP_OK: + print(f"Failed to get the latest release information from {api_url}") + else: + release_data = response.json() + version = release_data["tag_name"] + assets = release_data["assets"] + asset_file_url = get_conjure_zip_file_url(assets, version) + + download_and_extract(asset_file_url, output_dir) + make_executable_recursive(output_dir) + + conjure_path = output_dir / f"conjure-{version}-linux" / "conjure" + print(f"Conjure binary installed to {conjure_path.resolve()}") + return conjure_path + return None + - return version, commit +if __name__ == "__main__": + download_conjure("../conjure") diff --git a/tools/essence-feature-usage-stats/utils/files.py b/tools/essence-feature-usage-stats/utils/files.py index 8ed5c7ef0..9cb3a40e2 100644 --- a/tools/essence-feature-usage-stats/utils/files.py +++ b/tools/essence-feature-usage-stats/utils/files.py @@ -1,12 +1,16 @@ import os +import zipfile from pathlib import Path +import requests + def count_lines(fpath: str | Path) -> int: """ - Counts the number of lines in a file + Count the number of lines in a file. + :param fpath: path to the file - :return: int, the number of lines + :return: int, the number of lines. """ fpath = Path(fpath) with fpath.open("r") as f: @@ -15,10 +19,11 @@ def count_lines(fpath: str | Path) -> int: def trim_path(input_path: os.PathLike | Path | str, num_elements=0) -> str: """ - Normalize path and get last N elements from the end of the path (returns whole path if num_elements is 0) + Normalize path and get last N elements from the end of the path (returns whole path if num_elements is 0). + :param input_path: the path :param num_elements: last N elements to return - :return: whole path or a part of it (str) + :return: whole path or a part of it (str). """ input_path = os.path.normpath(str(input_path)) @@ -33,3 +38,37 @@ def trim_path(input_path: os.PathLike | Path | str, num_elements=0) -> str: return os.path.sep.join( path_elements[-num_elements:], ) # Join the last num_elements elements to form the trimmed path + + +def download_file(download_url: str, file_path: Path | str): + """Download a file from a URL to a local file.""" + file_path = Path(file_path) + + print(f"Downloading from {download_url} to {file_path.resolve()}...") + file_path.touch(exist_ok=True) + + response = requests.get(download_url, stream=True) + with file_path.open("wb") as file: + for chunk in response.iter_content(chunk_size=8192): + if chunk: + file.write(chunk) + + +def make_executable_recursive(directory_path): + """Recursively make files in a directory executable.""" + for item in directory_path.iterdir(): + if item.is_file(): + item.chmod(item.stat().st_mode | 0o111) # Add execute permission for files + elif item.is_dir(): + make_executable_recursive(item) # Recursively process subdirectories + + +def download_and_extract(download_url: str, dir_path: Path | str): + """Download and extract a file from a URL to a local directory.""" + temp_path = dir_path / "temp.zip" + download_file(download_url, temp_path) + + with zipfile.ZipFile(temp_path, "r") as zip_ref: + zip_ref.extractall(dir_path) + + temp_path.unlink() diff --git a/tools/essence-feature-usage-stats/utils/git.py b/tools/essence-feature-usage-stats/utils/git.py deleted file mode 100644 index fa460ecce..000000000 --- a/tools/essence-feature-usage-stats/utils/git.py +++ /dev/null @@ -1,82 +0,0 @@ -import os -import shutil -from pathlib import Path - -import git -from git import RemoteProgress, Repo -from tqdm import tqdm - - -class InvalidGitRemoteUrlError(ValueError): - """This exception is raised when a git remote url is invalid.""" - - def __init__(self, repo_url): - super().__init__(f"Not a valid git repository url: {repo_url}") - - -class CloneProgress(RemoteProgress): - def __init__(self): - super().__init__() - self.pbar = tqdm(desc="Cloning repo: ", unit="%", ncols=100) - - def update(self, op_code, cur_count, max_count=None, message=""): # noqa: ARG002 - self.pbar.total = 100 - self.pbar.n = int((cur_count / max_count) * 100) - self.pbar.refresh() - - -def sync_repo( - directory_path: str | Path, - repo_url, - branch="master", - remote_name="origin", -) -> Repo: - """ - Given a directory and a remote repo, synchronise directory with the repo. - That is: - - If directory does not exist, clone remote repo to directory - - If it exists, try to pull latest commit - - If it is not a valid repo, delete directory and clone repo again - :param directory_path: - path to directory - :param repo_url: - url of remote git repo - :param branch: - branch to use (master by default) - :param remote_name: - remote name to use (origin by default) - :return: - None - """ - - directory_path = Path(directory_path) - - if directory_path.exists() and len(os.listdir(directory_path)) == 0: - # If it's an empty directory, remove it (and clone repo) - directory_path.rmdir() - - if ( - not directory_path.exists() - ): # If the directory does not exist, clone the repository - repo = git.Repo.clone_from( - repo_url, - directory_path, - progress=CloneProgress(), - branch=branch, - ) - print(f"Cloned {repo_url} into {directory_path}") - return repo - - try: # If the directory exists, try to pull the latest changes - repo = git.Repo(directory_path) - origin = repo.remote(name=remote_name) - origin.pull(branch, progress=CloneProgress()) - print(f"Pulled the latest changes for {repo_url} in {directory_path}") - except git.exc.InvalidGitRepositoryError: - # If the directory exists but is not a valid Git repository, remove it and clone again - print(f"Removing invalid repository in {directory_path}") - shutil.rmtree(directory_path) - repo = git.Repo.clone_from( - repo_url, - directory_path, - progress=CloneProgress(), - branch=branch, - ) - print(f"Cloned {repo_url} into {directory_path}") - - return repo diff --git a/tools/essence-feature-usage-stats/utils/git_utils.py b/tools/essence-feature-usage-stats/utils/git_utils.py new file mode 100644 index 000000000..2461f4f40 --- /dev/null +++ b/tools/essence-feature-usage-stats/utils/git_utils.py @@ -0,0 +1,91 @@ +import shutil +from pathlib import Path +from typing import Tuple +from urllib.parse import urlsplit + +from git import InvalidGitRepositoryError, RemoteProgress, Repo +from tqdm import tqdm + + +class InvalidGitRemoteUrlError(ValueError): + """Raised when a git remote url is invalid.""" + + def __init__(self, repo_url): # noqa: D107 + super().__init__(f"Not a valid git repository url: {repo_url}") + + +class CloneProgress(RemoteProgress): + """Progress bar for cloning a repo.""" + + def __init__(self): # noqa: D107 + super().__init__() + self.pbar = tqdm(desc="Cloning repo: ", unit="%", ncols=100) + + def update( # noqa: D102 + self, + op_code, # noqa: ARG002 + cur_count, + max_count=None, + message="", # noqa: ARG002 + ): + self.pbar.total = 100 + self.pbar.n = int((cur_count / max_count) * 100) + self.pbar.refresh() + + +def is_git_repo(path: Path | str) -> bool: + """Check whether a given directory is a git repository.""" + try: + _ = Repo(path).git_dir + except InvalidGitRepositoryError: + return False + else: + return True + + +def clone_or_pull( + directory_path: Path | str, + remote_url: str, + branch="master", + remote_name="origin", +) -> Repo: + """ + Clone a given GitHub repository to a given local directory, or pull latest changes if local repo exists. + + :param directory_path: local directory to use + :param remote_url: remote repo url to pull from + :param remote_name: name of the remote (origin by default) + :param branch: branch of the remote repo to pull (master by default) + """ + directory_path = Path(directory_path) + + if directory_path.is_dir() and is_git_repo(directory_path): + repo = Repo(directory_path) + repo.remote(remote_name).pull() + else: + shutil.rmtree(directory_path) + repo = Repo.clone_from( + remote_url, + directory_path, + branch=branch, + progress=CloneProgress(), + ) + + return repo + + +def parse_repo_url(repo_url: str) -> Tuple[str, str]: + """ + Get the GitHub user and repo from a repo URL. + + :param repo_url: the GitHub repo URL + :return: (user, repo) + """ + if repo_url.startswith("http"): + parsed_url = urlsplit(repo_url) + path_components = parsed_url.path.strip("/").split("/") + user, repo = path_components[:2] + return user, repo + + elements = repo_url.split("/") + return tuple(elements[:2]) diff --git a/tools/essence-feature-usage-stats/utils/maths.py b/tools/essence-feature-usage-stats/utils/maths.py index 124086e97..8e9e8fc86 100644 --- a/tools/essence-feature-usage-stats/utils/maths.py +++ b/tools/essence-feature-usage-stats/utils/maths.py @@ -1,6 +1,7 @@ def map_range(x, in_min, in_max, out_min, out_max): """ - Maps x between in_min, in_max to range between out_min and out_max + Map x between in_min, in_max to range between out_min and out_max. + :param x: value to map :param in_min: min value of x :param in_max: max value of x @@ -14,4 +15,11 @@ def map_range(x, in_min, in_max, out_min, out_max): def clamp(x, minn, maxn): + """ + Clamp x between minn and maxn. + + :param x: the value to clamp + :param minn: the minimum value + :param maxn: the maximum value + """ return min(max(x, minn), maxn) diff --git a/tools/essence-feature-usage-stats/utils/misc.py b/tools/essence-feature-usage-stats/utils/misc.py index 9873f8aae..cdc801826 100644 --- a/tools/essence-feature-usage-stats/utils/misc.py +++ b/tools/essence-feature-usage-stats/utils/misc.py @@ -2,15 +2,16 @@ def flat_keys_count( - data: dict[Any, dict | list] | list, blocklist=None + data: dict[Any, dict | list] | list, + blocklist=None, ) -> dict[Any, int]: """ - Recurse over a dict or list (potentially with nested dicts / lists) and count all dictionary keys + Recurse over a dict or list (potentially with nested dicts / lists) and count all dictionary keys. + :param data: a dictionary or list containing dictionaries / lists :param blocklist: collection of keys to ignore - :return: dict in the format of :<№ of key's occurrences in data> + :return: dict in the format of :<№ of key's occurrences in data>. """ - ans = {} def add_key(key, count=1): diff --git a/tools/essence-feature-usage-stats/web/__init__.py b/tools/essence-feature-usage-stats/web/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tools/essence-feature-usage-stats/web/server.py b/tools/essence-feature-usage-stats/web/server.py deleted file mode 100644 index b4ae194cc..000000000 --- a/tools/essence-feature-usage-stats/web/server.py +++ /dev/null @@ -1,18 +0,0 @@ -from flask import Flask, render_template, request - -from stats.essence_stats import EssenceStats - - -def create_server(stats: EssenceStats): - app = Flask(__name__) - - @app.route("/") - @app.route("/index.html") - def index(): - # ToDo cache Essence ast generation etc - n_keywords = request.args.get("n_keywords", default=5, type=int) - return render_template( - "index.html", data={"essence_stats": stats, "n_keywords": n_keywords} - ) - - return app diff --git a/tools/essence-feature-usage-stats/web/templates/__init__.py b/tools/essence-feature-usage-stats/web/templates/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tools/essence-feature-usage-stats/web/templates/base.html b/tools/essence-feature-usage-stats/web/templates/base.html index f4c42252a..89f0b9697 100644 --- a/tools/essence-feature-usage-stats/web/templates/base.html +++ b/tools/essence-feature-usage-stats/web/templates/base.html @@ -1,10 +1,12 @@ - {% block title %}{% endblock %} + Essence feature usage stats {% block stylesheets %} {% endblock %} +

    Essence feature usage stats

    +