diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 56eb3e1..7d64246 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: coverage run -m pytest test/unit coverage xml -o coverage.xml env: - PHAGY_DIRECTORY: ${{ env.PHAGY_DIRECTORY }} + DATA_DIR: ${{ env.DATA_DIR }} FILE_SYSTEM: ${{ env.FILE_SYSTEM }} EMAIL: ${{ secrets.EMAIL }} API_KEY: ${{ secrets.API_KEY }} diff --git a/Makefile b/Makefile index 896a8a3..2bdeeb8 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,7 @@ clean: # Remove workspace files @rm -rf ./dist @rm -rf test/fixtures/assets_testing_folder/ncbi_download/fetch @rm -rf test/fixtures/assets_testing_folder/sequence_quality/genbank + @rm -rf test/fixtures/assets_testing_folder/sequence_quality_with_history/genbank @rm -rf test/fixtures/assets_testing_folder/blasting/gene_identity @rm -rf test/fixtures/assets_testing_folder/blasting_with_history/gene_identity @rm -rf test/fixtures/assets_testing_folder/synteny/synteny @@ -25,7 +26,7 @@ black: # Format code @black test flake: # Lint code - @flake8 --ignore=E501,W503,E731,E722 --max-cognitive-complexity=30 synphage + @flake8 --ignore=E501,W503,E731,E722 --max-complexity=30 synphage @python -c "print('Linting: 👌')" radon: diff --git a/README.md b/README.md index 7f9d6f5..6dd708c 100644 --- a/README.md +++ b/README.md @@ -40,9 +40,12 @@ docker pull vestalisvirginis/synphage:latest ### Additional dependencies -Synphage relies on two non-python dependencies that need to be manually installed when Synphage is installed with pip: +Synphage relies on one non-python dependency that need to be manually installed when Synphage is installed with pip: - [Blast+](https://ftp.ncbi.nlm.nih.gov/blast/executables/blast+/) >= 2.12.0 -- [OpenJDK](https://openjdk.org/projects/jdk/17/) == 17 +```bash +apt update +apt install -y ncbi-blast+ +``` ## Usage @@ -61,7 +64,7 @@ Synphage requires: #### Path setup ```bash -export PHAGY_DIRECTORY= +export DATA_DIR= ``` **Note:** For docker users, this path is defaulted to `/data`. diff --git a/conftest.py b/conftest.py index 5f7573b..2b90df3 100644 --- a/conftest.py +++ b/conftest.py @@ -1,10 +1,4 @@ -# import os -# import warnings import pytest -# from pyspark.sql import SparkSession -#import logging - -#logger = logging.getLogger(__name__) @pytest.fixture @@ -12,64 +6,54 @@ def mock_env_ncbi_connect(monkeypatch): monkeypatch.setenv("EMAIL", "name@domain.com") monkeypatch.setenv("API_KEY", "jhd6hdz778ahjeahj8889") - @pytest.fixture def mock_env_ncbi_download_pos(monkeypatch): - monkeypatch.setenv("PHAGY_DIRECTORY", "test/fixtures/ncbi_download/positive") - + monkeypatch.setenv("DATA_DIR", "test/fixtures/ncbi_download/positive") @pytest.fixture def mock_env_ncbi_download_neg(monkeypatch): - monkeypatch.setenv("PHAGY_DIRECTORY", "test/fixtures/ncbi_download/negative") - + monkeypatch.setenv("DATA_DIR", "test/fixtures/ncbi_download/negative") @pytest.fixture def mock_env_ncbi_count(monkeypatch): monkeypatch.setenv("DATABASE", "nuccore") monkeypatch.setenv("KEYWORD", "Bacillus subtilis strain P9_B1") - @pytest.fixture def mock_env_ncbi_fetch(monkeypatch): - monkeypatch.setenv("PHAGY_DIRECTORY", "test/fixtures/ncbi_download/fetch") - + monkeypatch.setenv("DATA_DIR", "test/fixtures/ncbi_download/fetch") @pytest.fixture def mock_env_sequence_check(monkeypatch): - monkeypatch.setenv("PHAGY_DIRECTORY", "test/fixtures/assets_testing_folder/sequence_quality") + monkeypatch.setenv("DATA_DIR", "test/fixtures/assets_testing_folder/sequence_quality") +@pytest.fixture +def mock_env_sequence_check_with_history(monkeypatch): + monkeypatch.setenv("DATA_DIR", "test/fixtures/assets_testing_folder/sequence_quality_with_history") @pytest.fixture def mock_env_phagy_dir_blasting(monkeypatch): - monkeypatch.setenv("PHAGY_DIRECTORY", "test/fixtures/assets_testing_folder/blasting") + monkeypatch.setenv("DATA_DIR", "test/fixtures/assets_testing_folder/blasting") @pytest.fixture def mock_env_phagy_dir_blasting_with_history(monkeypatch): - monkeypatch.setenv("PHAGY_DIRECTORY", "test/fixtures/assets_testing_folder/blasting_with_history") + monkeypatch.setenv("DATA_DIR", "test/fixtures/assets_testing_folder/blasting_with_history") @pytest.fixture def mock_env_phagy_dir_transform(monkeypatch): - monkeypatch.setenv("PHAGY_DIRECTORY", "test/fixtures/assets_testing_folder/transform") + monkeypatch.setenv("DATA_DIR", "test/fixtures/assets_testing_folder/transform") monkeypatch.setenv("FILE_SYSTEM", "fs") @pytest.fixture def mock_env_phagy_dir_transform_step3(monkeypatch): - monkeypatch.setenv("PHAGY_DIRECTORY", "test/fixtures/assets_testing_folder/transform_3") + monkeypatch.setenv("DATA_DIR", "test/fixtures/assets_testing_folder/transform_3") @pytest.fixture def mock_env_phagy_dir_synteny(monkeypatch): - monkeypatch.setenv("PHAGY_DIRECTORY", "test/fixtures/assets_testing_folder/synteny") + monkeypatch.setenv("DATA_DIR", "test/fixtures/assets_testing_folder/synteny") monkeypatch.setenv("SEQUENCE_FILE", "sequences.csv") -# @pytest.fixture(scope="session") -# def spark(): -# try: -# #logger = logging.getLogger("py4j") -# #ogger.setLevel(logging.ERROR) -# spark_session = SparkSession.builder.config( -# "spark.driver.memory", "2g" -# ).getOrCreate() -# yield spark_session -# except: -# pass -# finally: -# spark_session.stop() \ No newline at end of file + +@pytest.fixture +def mock_env_phagy_dir_none(monkeypatch): + monkeypatch.delenv("DATA_DIR", raising=False) + \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index cae97ef..5188298 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,7 +22,6 @@ dependencies = [ "biopython >= 1.81", "reportlab >= 3.6.12", "rlPyCairo >= 0.3.0", - "pyspark >= 2.15.1", "cuallee >= 0.6.0", "duckdb >= 0.9.1", "polars >= 0.19.11", diff --git a/synphage/assets/blaster/blaster.py b/synphage/assets/blaster/n_blaster.py similarity index 58% rename from synphage/assets/blaster/blaster.py rename to synphage/assets/blaster/n_blaster.py index 6a15eec..ba63bde 100644 --- a/synphage/assets/blaster/blaster.py +++ b/synphage/assets/blaster/n_blaster.py @@ -8,6 +8,7 @@ import os import pickle +import tempfile from Bio import SeqIO from pathlib import Path @@ -15,20 +16,15 @@ from typing import List -file_config = { +TEMP_DIR = tempfile.gettempdir() + + +folder_config = { "fs": Field( str, - description="Path to folder containing the genbank _files", + description="Path to folder containing the file system files", default_value="fs", ), -} - -sqc_folder_config = { - "sqc_download_dir": Field( - str, - description="Path to folder containing the downloaded genbank sequences", - default_value="download", - ), "genbank_dir": Field( str, description="Path to folder containing the genbank files", @@ -36,8 +32,18 @@ ), "fasta_dir": Field( str, - description="Path to folder containing the fasta sequence files", - default_value="gene_identity/fasta", + description="Path to folder containing the fasta files", + default_value=str(Path("gene_identity") / "fasta"), + ), + "blast_db_dir": Field( + str, + description="Path to folder containing the database for the blastn", + default_value=str(Path("gene_identity") / "blastn_database"), + ), + "blastn_dir": Field( + str, + description="Path to folder containing the blastn json files", + default_value=str(Path("gene_identity") / "blastn"), ), } @@ -58,11 +64,11 @@ def _assess_file_content(genome) -> bool: @multi_asset( - config_schema={**sqc_folder_config, **file_config}, + config_schema=folder_config, outs={ "new_fasta_files": AssetOut( is_required=True, - description="""Return the path for last created fasta _file. Parse genebank _file and create a _file containing every genes in the fasta format. + description="""Return the path for last created fasta files. Parse genebank file and create a file containing every genes in the fasta format. Note: The sequence start and stop indexes are `-1` on the fasta _file 1::10 --> [0:10] included/excluded.""", io_manager_key="io_manager", metadata={ @@ -79,33 +85,29 @@ def _assess_file_content(genome) -> bool: ), }, compute_kind="Biopython", - op_tags={"blaster": "compute_intense"}, ) -def genbank_to_fasta(context, standardised_ext_file): - # Paths to read and store the data - _path_out = "/".join( - [os.getenv(EnvVar("PHAGY_DIRECTORY")), context.op_config["fasta_dir"]] +def genbank_to_fasta(context, standardised_ext_file) -> tuple[List[str], List[str]]: + # Paths to read from and store the data + _path_fasta = str( + Path(os.getenv(EnvVar("DATA_DIR"), TEMP_DIR)) / context.op_config["fasta_dir"] ) - _path = "/".join( - [ - os.getenv(EnvVar("PHAGY_DIRECTORY")), - context.op_config["fs"], - "history_fasta_files", - ] + + _path_history = ( + Path(os.getenv(EnvVar("DATA_DIR"))) + / context.op_config["fs"] + / "history_fasta_files" ) # fasta_history - if os.path.exists(_path): - context.log.info("path exist") - _fasta_files = pickle.load(open(_path, "rb")) + if os.path.exists(_path_history): + _fasta_files = pickle.load(open(_path_history, "rb")) + context.log.info("Fasta history loaded") else: - context.log.info("path do not exist") _fasta_files = [] - context.log.info(_fasta_files) - - context.log.info(_path_out) + context.log.info("No fasta history") - os.makedirs(_path_out, exist_ok=True) + context.log.info(f"Path to fasta files: {_path_fasta}") + os.makedirs(_path_fasta, exist_ok=True) _new_fasta_files = [] _new_fasta_paths = [] @@ -114,12 +116,12 @@ def genbank_to_fasta(context, standardised_ext_file): context.log.info(f"The following file {_file} is being processed") # Genbank to fasta - _output_dir = f"{_path_out}/{Path(_file).stem}.fna" - context.log.info(_output_dir) + _output_dir = str(Path(_path_fasta) / f"{Path(_file).stem}.fna") + context.log.info(f"Output file being generated: {_output_dir}") _genome = SeqIO.read(_file, "genbank") _genome_records = list(SeqIO.parse(_file, "genbank")) - if _assess_file_content(_genome) == True: + if _assess_file_content(_genome): with open(_output_dir, "w") as _f: _gene_features = list( filter(lambda x: x.type == "gene", _genome.features) @@ -167,25 +169,24 @@ def genbank_to_fasta(context, standardised_ext_file): _new_fasta_files.append(Path(_file).stem) _new_fasta_paths.append(_output_dir) - context.log.info(_fasta_files) - _fasta_files = _fasta_files + _new_fasta_files + context.log.info("The fasta file history has been updated") _time = datetime.now() context.add_output_metadata( output_name="new_fasta_files", metadata={ - "text_metadata": f"The list of fasta files has been updated {_time.isoformat()} (UTC).", - "processed_file": _new_fasta_files, - "num_files": len(_new_fasta_files), - "path": _path_out, + "text_metadata": f"New genbank files have been processed to fasta {_time.isoformat()} (UTC).", + "file_location": _path_fasta, + "num_processed_files": len(_new_fasta_files), + "preview": _new_fasta_files, }, ) context.add_output_metadata( output_name="history_fasta_files", metadata={ "text_metadata": f"The list of fasta files has been updated {_time.isoformat()} (UTC).", - "path": _path_out, + "file_location": _path_history, "num_files": len(_fasta_files), "preview": _fasta_files, }, @@ -194,53 +195,43 @@ def genbank_to_fasta(context, standardised_ext_file): return _new_fasta_paths, _fasta_files -blastn_folder_config = { - "blast_db_dir": Field( - str, - description="Path to folder containing the database for the blastn", - default_value="gene_identity/blastn_database", - ), - "blastn_dir": Field( - str, - description="Path to folder containing the blastn output _files", - default_value="gene_identity/blastn", - ), -} - - @asset( - config_schema={**sqc_folder_config, **blastn_folder_config}, - description="Receive a fasta _file as input and create a database for blast in the output directory", + config_schema=folder_config, + description="Receive a fasta file as input and create a database for the blastn step", compute_kind="Blastn", - op_tags={"blaster": "compute_intense"}, metadata={"owner": "Virginie Grosboillot"}, ) -def create_blast_db(context, new_fasta_files): - _path = "/".join( - [os.getenv(EnvVar("PHAGY_DIRECTORY")), context.op_config["blast_db_dir"]] +def create_blast_db(context, new_fasta_files) -> List[str]: + # path to store db + _path_db = str( + Path(os.getenv(EnvVar("DATA_DIR"), TEMP_DIR)) + / context.op_config["blast_db_dir"] ) - context.log.info(_path) - os.makedirs(_path, exist_ok=True) + context.log.info(f"Path to database: {_path_db}") + os.makedirs(_path_db, exist_ok=True) _db = [] for _new_fasta_file in new_fasta_files: - _output_dir = f"{_path}/{Path(_new_fasta_file).stem}" - context.log.info(_output_dir) + _output_dir = str(Path(_path_db) / Path(_new_fasta_file).stem) + context.log.info(f"Database being generated: {_output_dir}") os.system( f"makeblastdb -in {_new_fasta_file} -input_type fasta -dbtype nucl -out {_output_dir}" ) - context.log.info("finished process") _db.append(_new_fasta_file) + context.log.info(f"File {_new_fasta_file} has been processed") - _all_db = list(set(map(lambda x: f"{_path}/{Path(x).stem}", os.listdir(_path)))) + _all_db = list( + set(map(lambda x: str(Path(_path_db) / Path(x).stem), os.listdir(_path_db))) + ) _time = datetime.now() context.add_output_metadata( metadata={ "text_metadata": f"The list of dbs has been updated {_time.isoformat()} (UTC).", + "file_location": _path_db, + "num_new_files": len(_db), "processed_files": _db, - "path": _path, - "preview": list(set([Path(_p).stem for _p in _all_db])), + "preview_all": list(set([Path(_p).stem for _p in _all_db])), } ) @@ -248,59 +239,65 @@ def create_blast_db(context, new_fasta_files): @asset( - config_schema={**sqc_folder_config, **blastn_folder_config}, - description="Perform blastn between sequence and database and return results as json", + config_schema=folder_config, + description="Perform blastn between available sequences and databases and return result in json format", compute_kind="Blastn", - op_tags={"blaster": "compute_intense"}, metadata={"owner": "Virginie Grosboillot"}, ) -def get_blastn(context, history_fasta_files, create_blast_db): - # Blastn json _file directory - create directory if not yet existing - _path = "/".join( - [os.getenv(EnvVar("PHAGY_DIRECTORY")), context.op_config["blastn_dir"]] +def get_blastn(context, history_fasta_files, create_blast_db) -> List[str]: + # Blastn json file directory - create directory if not yet existing + _path_blastn = str( + Path(os.getenv(EnvVar("DATA_DIR"), TEMP_DIR)) / context.op_config["blastn_dir"] ) - os.makedirs(_path, exist_ok=True) - context.log.info(_path) + os.makedirs(_path_blastn, exist_ok=True) + context.log.info(f"Path to blastn results: {_path_blastn}") # History - _history_path = "/".join( - [os.getenv("PHAGY_DIRECTORY"), os.getenv("FILE_SYSTEM"), "get_blastn"] + _history_path = str( + Path(os.getenv(EnvVar("DATA_DIR"), TEMP_DIR)) / "fs" / "get_blastn" ) - context.log.info(_history_path) if os.path.exists(_history_path): - context.log.info("path exist") - _blastn_history = pickle.load(open(_history_path, "rb")) + _blastn_history = [ + Path(file).name for file in pickle.load(open(_history_path, "rb")) + ] + context.log.info("Blastn history loaded") else: - context.log.info("path do not exist") _blastn_history = [] - context.log.info(_blastn_history) + context.log.info("No blastn history available") # Blast each query against every databases - _fasta_path = "/".join( - [os.getenv("PHAGY_DIRECTORY"), context.op_config["fasta_dir"]] + _fasta_path = str( + Path(os.getenv(EnvVar("DATA_DIR"), TEMP_DIR)) / context.op_config["fasta_dir"] + ) + context.log.info(f"Path to fasta files: {_fasta_path}") + _fasta_files = list( + map(lambda x: str(Path(_fasta_path) / f"{x}.fna"), history_fasta_files) ) - context.log.info(_fasta_path) - _fasta_files = list(map(lambda x: f"{_fasta_path}/{x}.fna", history_fasta_files)) + _new_blastn_files = [] for _query in _fasta_files: for _database in create_blast_db: - _output_dir = f"{_path}/{Path(_query).stem}_vs_{Path(_database).stem}" - if _output_dir not in _blastn_history: + _output_file = f"{Path(_query).stem}_vs_{Path(_database).stem}" + _output_dir = str(Path(_path_blastn) / _output_file) + if _output_file not in _blastn_history: os.system( f"blastn -query {_query} -db {_database} -evalue 1e-3 -dust no -out {_output_dir} -outfmt 15" ) + _new_blastn_files.append(_output_file) _blastn_history.append(_output_dir) - context.log.info(f"{Path(_output_dir)} processed successfully") + context.log.info(f"Query {_output_file} processed successfully") - _full_list = [Path(_x).stem for _x in _blastn_history] + _full_list = [Path(x).stem for x in _blastn_history] # Asset metadata _time = datetime.now() context.add_output_metadata( metadata={ - "text_metadata": f"The list of blasted sequneces has been updated {_time.isoformat()} (UTC).", - "processed__files": _full_list, - "path": _path, + "text_metadata": f"The list of blasted sequences has been updated {_time.isoformat()} (UTC).", + "file_location": _path_blastn, + "num_files": len(_new_blastn_files), + "processed_files": _new_blastn_files, + "preview_all": _full_list, } ) diff --git a/synphage/assets/ncbi_connect/accession.py b/synphage/assets/ncbi_connect/accession.py index e3e0d16..ed232f2 100644 --- a/synphage/assets/ncbi_connect/accession.py +++ b/synphage/assets/ncbi_connect/accession.py @@ -1,13 +1,17 @@ from dagster import asset, Field, AssetObservation, EnvVar import os +import tempfile from toolz import first from collections import namedtuple from typing import List from pathlib import Path +from datetime import datetime +TEMP_DIR = tempfile.gettempdir() + NucleotideRecord = namedtuple("NucleotideRecord", "dbname,menu,count,status") @@ -20,11 +24,11 @@ def _get_ncbi_count_result(result, dbname) -> NucleotideRecord: ncbi_query_config = { "database": Field(str, description="Database identifier", default_value="nuccore"), - # "keyword": Field( - # str, - # description="Search criteria for the ncbi query", - # default_value=os.getenv(EnvVar("KEYWORD"), "Listeria ivanovii"), - # ), + "use_history": Field( + str, description="Yes/No value for history", default_value="y" + ), + "idtype": Field(str, description="Options for acc", default_value="acc"), + "rettype": Field(str, description="File format", default_value="gb"), # gbwithparts } @@ -33,41 +37,51 @@ def _get_ncbi_count_result(result, dbname) -> NucleotideRecord: config_schema=ncbi_query_config, description="Getting the number of records matching the keyword(s) in the specified database", compute_kind="NCBI", + io_manager_key="io_manager", metadata={"owner": "Virginie Grosboillot"}, ) def accession_count(context) -> int: - keyword = os.getenv(EnvVar("KEYWORD"), "Listeria ivanovii") - context.log.info(keyword) + # Search key - default: Myoalterovirus (2 entries in NCBI database Jan 2024) + keyword = os.getenv(EnvVar("KEYWORD"), "Myoalterovirus") + context.log.info(f"Search key(s): {keyword}") + # Query _query = context.resources.ncbi_connection.conn.egquery(term=keyword) _result = context.resources.ncbi_connection.conn.read(_query) _query.close() + # Extract number of record for keyword _nucleotide = _get_ncbi_count_result(_result, context.op_config["database"]) _num_rows = int(_nucleotide.count) context.log_event( AssetObservation(asset_key="accession_count", metadata={"num_rows": _num_rows}) ) - return _num_rows + # Asset user metadata + _time = datetime.now() + context.add_output_metadata( + metadata={ + "text_metadata": f"End of query: {_time.isoformat()} (UTC).", + "search_word(s)": keyword, + "num_hits": _num_rows, + } + ) -ncbi_query_config_search = { - "use_history": Field( - str, description="Yes/No value for history", default_value="y" - ), - "idtype": Field(str, description="Options for acc", default_value="acc"), -} + return _num_rows @asset( required_resource_keys={"ncbi_connection"}, - config_schema={**ncbi_query_config, **ncbi_query_config_search}, + config_schema=ncbi_query_config, description="Getting all accession Ids corresponding to keyword(s)", compute_kind="NCBI", + io_manager_key="io_manager", metadata={"owner": "Virginie Grosboillot"}, ) -def accession_ids(context, accession_count): - context.log.info("Starting search") - keyword = os.getenv(EnvVar("KEYWORD"), "Listeria ivanovii") - context.log.info(keyword) +def accession_ids(context, accession_count) -> dict: + # Search key - default: Myoalterovirus (2 entries in NCBI database Jan 2024) + keyword = os.getenv(EnvVar("KEYWORD"), "Myoalterovirus") + context.log.info(f"Search key(s): {keyword}") + # Search + context.log.info("Start NCBI database search") _search = context.resources.ncbi_connection.conn.esearch( db=context.op_config["database"], term=keyword, @@ -83,6 +97,18 @@ def accession_ids(context, accession_count): ) ) _search.close() + + # Asset user metadata + _time = datetime.now() + context.add_output_metadata( + metadata={ + "text_metadata": f"End of search: {_time.isoformat()} (UTC).", + "search_word(s)": keyword, + "num_retrived_ids": len(_result["IdList"]), + "id_preview": _result["IdList"], + } + ) + return _result @@ -95,37 +121,57 @@ def accession_ids(context, accession_count): } -@asset(config_schema=download_folder_config, compute_kind="python") +@asset( + config_schema=download_folder_config, + description="In case of multiple search, checked what sequence have already been downloeded", + compute_kind="python", + io_manager_key="io_manager", + metadata={"owner": "Virginie Grosboillot"}, +) def downloaded_genomes(context) -> List[str]: - _download_path = "/".join( - [os.getenv(EnvVar("PHAGY_DIRECTORY")), context.op_config["output_directory"]] + # Download directory + _download_path = str( + Path(os.getenv(EnvVar("DATA_DIR"), TEMP_DIR)) + / context.op_config["output_directory"] + ) + os.makedirs(_download_path, exist_ok=True) + # List file in download directory + _downloaded_files = list(map(lambda x: Path(x).stem, os.listdir(_download_path))) + + # Asset user metadata + _time = datetime.now() + context.add_output_metadata( + metadata={ + "text_metadata": f"Downloaded files last update: {_time.isoformat()} (UTC).", + "num_files": len(_downloaded_files), + "preview": _downloaded_files, + } ) - return list(map(lambda x: Path(x).stem, os.listdir(_download_path))) - -ncbi_query_config_fetch = { - "database": Field(str, description="Database identifier", default_value="nuccore"), - "rettype": Field(str, description="File format", default_value="gb"), # gbwithparts - # "batch": Field(int, description="Options for acc", default_value=10) -} + return _downloaded_files @asset( required_resource_keys={"ncbi_connection"}, - config_schema={**download_folder_config, **ncbi_query_config_fetch}, + config_schema={**download_folder_config, **ncbi_query_config}, description="Download records one by one from the ncbi database", compute_kind="NCBI", + io_manager_key="io_manager", metadata={"owner": "Virginie Grosboillot"}, ) def fetch_genome(context, accession_ids, downloaded_genomes) -> List[str]: + # Exclude already downloaded files _A = set(accession_ids["IdList"]) _B = set(downloaded_genomes) _C = _A.difference(_B) - context.log.info(f"Number of NOT Downloaded: {len(_C)}") - _path = "/".join( - [os.getenv(EnvVar("PHAGY_DIRECTORY")), context.op_config["output_directory"]] + context.log.info(f"Number of files NOT downloaded: {len(_C)}") + # Path to download + _download_path = str( + Path(os.getenv(EnvVar("DATA_DIR"), TEMP_DIR)) + / context.op_config["output_directory"] ) - context.log.info(f"Output path: {_path}") + context.log.info(f"Path to download: {_download_path}") + # Fetch and write files for _entry in list(_C): _r = context.resources.ncbi_connection.conn.efetch( db=context.op_config["database"], @@ -136,8 +182,21 @@ def fetch_genome(context, accession_ids, downloaded_genomes) -> List[str]: query_key=accession_ids["QueryKey"], ) - _file_name = f"{_path}/{_entry}.gb" + _file_name = str(Path(_download_path) / f"{_entry}.gb") with open(_file_name, "w") as _writer: _writer.write(_r.read()) - return list(map(lambda x: f"{_path}/{x}.gb", accession_ids["IdList"])) + _all_ids = _B.union(_A) + _genomes = list(map(lambda x: str(Path(_download_path) / f"{x}.gb"), _all_ids)) + + # Asset user metadata + _time = datetime.now() + context.add_output_metadata( + metadata={ + "text_metadata": f"Dowloaded files latest status: {_time.isoformat()} (UTC).", + "num_files": len(_genomes), + "preview": _genomes, + } + ) + + return _genomes diff --git a/synphage/assets/ncbi_connect/sequence_quality_assessment.py b/synphage/assets/ncbi_connect/sequence_quality_assessment.py index 500933f..fb1f192 100644 --- a/synphage/assets/ncbi_connect/sequence_quality_assessment.py +++ b/synphage/assets/ncbi_connect/sequence_quality_assessment.py @@ -1,21 +1,32 @@ from dagster import ( - asset, EnvVar, Field, + multi_asset, + AssetOut, ) import os import shutil +import tempfile +import pickle from pathlib import Path from datetime import datetime from typing import List -sqc_folder_config = { - "sqc_download_dir": Field( +TEMP_DIR = tempfile.gettempdir() + + +folder_config = { + "fs": Field( + str, + description="Path to folder containing the file system files", + default_value="fs", + ), + "download_directory": Field( str, - description="Path to folder containing the downloaded genbank sequences", + description="Path to folder", default_value="download", ), "genbank_dir": Field( @@ -26,48 +37,87 @@ "fasta_dir": Field( str, description="Path to folder containing the fasta sequence files", - default_value="gene_identity/fasta", + default_value=str(Path("gene_identity") / "fasta"), ), } -@asset( - config_schema={**sqc_folder_config}, - description="Checks for sequence quality and accuracy", +@multi_asset( + config_schema=folder_config, + outs={ + "new_transferred_files": AssetOut( + is_required=True, + description="Checks for sequence quality and accuracy", + io_manager_key="io_manager", + metadata={ + "owner": "Virginie Grosboillot", + }, + ), + "history_transferred_files": AssetOut( + is_required=True, + description="Update the list of files already transferred from download to genbank folder", + io_manager_key="io_manager", + metadata={ + "owner": "Virginie Grosboillot", + }, + ), + }, compute_kind="Biopython", - metadata={"owner": "Virginie Grosboillot"}, ) -def sequence_check(context, fetch_genome) -> List[str]: - context.log.info(f"Number of genomes in download folder: {len(fetch_genome)}") +def sequence_check(context, fetch_genome) -> tuple[List[str], List[str]]: + # history check + _path_history = ( + Path(os.getenv(EnvVar("DATA_DIR"))) + / context.op_config["fs"] + / "history_transferred_files" + ) + + if os.path.exists(_path_history): + _transferred_files = pickle.load(open(_path_history, "rb")) + context.log.info("Transferred file history loaded") + else: + _transferred_files = [] + context.log.info("No transfer history") + + # genome to transfer + _T = list(set(fetch_genome).difference(set(_transferred_files))) + context.log.info(f"Number of genomes to transfer: {len(_T)}") - _gb_path = "/".join( - [os.getenv(EnvVar("PHAGY_DIRECTORY")), context.op_config["genbank_dir"]] + # path to genbank folder + _gb_path = str( + Path(os.getenv(EnvVar("DATA_DIR"), TEMP_DIR)) / context.op_config["genbank_dir"] ) os.makedirs(_gb_path, exist_ok=True) # add check to assess the quality of the query - for _file in fetch_genome: + _new_transfer = [] + for _file in _T: + _output_file = str(Path(_gb_path) / f"{Path(_file).stem.replace('.', '_')}.gb") shutil.copy2( _file, - f"{_gb_path}/{Path(_file).stem.replace('.', '_')}.gb", + _output_file, ) - - _downloaded_files = list( - map( - lambda x: Path(x).stem, - os.listdir(_gb_path), - ) - ) + _new_transfer.append(Path(_output_file).name) + _transferred_files.append(_file) _time = datetime.now() context.add_output_metadata( + output_name="new_transferred_files", metadata={ "text_metadata": f"List of downloaded sequences{_time.isoformat()} (UTC).", "path": _gb_path, - "num_files": len(_downloaded_files), - "preview": _downloaded_files, - } + "num_files": len(_new_transfer), + "preview": _new_transfer, + }, + ) + context.add_output_metadata( + output_name="history_transferred_files", + metadata={ + "text_metadata": f"List of downloaded sequences last update: {_time.isoformat()} (UTC).", + "num_files": len(_transferred_files), + "preview": _transferred_files, + }, ) - return _downloaded_files + return _new_transfer, _transferred_files diff --git a/synphage/assets/status/status.py b/synphage/assets/status/gb_file_status.py similarity index 67% rename from synphage/assets/status/status.py rename to synphage/assets/status/gb_file_status.py index d9a4a65..0b12528 100644 --- a/synphage/assets/status/status.py +++ b/synphage/assets/status/gb_file_status.py @@ -8,11 +8,17 @@ import os import pickle import glob -from pathlib import Path +import tempfile + +from pathlib import Path, PosixPath +from typing import List from datetime import datetime -def _standardise_file_extention(file) -> None: +TEMP_DIR = tempfile.gettempdir() + + +def _standardise_file_extention(file: str) -> PosixPath: """Change file extension when '.gbk' for '.gb'""" _path = Path(file) if _path.suffix == ".gbk": @@ -21,7 +27,7 @@ def _standardise_file_extention(file) -> None: return _path -sqc_folder_config = { +folder_config = { "fs": Field( str, description="Path to folder containing the genbank files", @@ -41,7 +47,7 @@ def _standardise_file_extention(file) -> None: @multi_asset( - config_schema={**sqc_folder_config}, + config_schema={**folder_config}, outs={ "standardised_ext_file": AssetOut( is_required=True, @@ -62,34 +68,31 @@ def _standardise_file_extention(file) -> None: }, compute_kind="Python", ) -def list_genbank_files(context): +def list_genbank_files(context) -> tuple[List[PosixPath], List[str]]: # List files in the genbank directory - _gb_path = "/".join( - [os.getenv("PHAGY_DIRECTORY"), context.op_config["genbank_dir"]] + _gb_path = str( + Path(os.getenv(EnvVar("DATA_DIR"), TEMP_DIR)) / context.op_config["genbank_dir"] ) context.log.info(f"Genbank path: {_gb_path}") # Load already processed files - _path = "/".join( - [ - os.getenv(EnvVar("PHAGY_DIRECTORY")), - context.op_config["fs"], - "list_genbank_files", - ] + _hist_gb_path = str( + Path(os.getenv(EnvVar("DATA_DIR"), TEMP_DIR)) + / context.op_config["fs"] + / "list_genbank_files" ) - - if os.path.exists(_path): - context.log.info("path exist") - _files = pickle.load(open(_path, "rb")) + if os.path.exists(_hist_gb_path): + _files = pickle.load(open(_hist_gb_path, "rb")) + context.log.info("History genbank files loaded") else: - context.log.info("path do not exist") _files = [] - context.log.info(_files) + context.log.info("No genbank history available") + # process new files _new_files = [] _new_paths = [] - for _file in glob.glob(f"{_gb_path}/*.gb*"): + for _file in glob.glob(str(Path(_gb_path) / "*.gb*")): if Path(_file).stem not in _files: - context.log.info(f"The following file {_file} is being processed") + context.log.info(f"The following file is being processed: {_file}") _new_path = _standardise_file_extention(_file) # Update lists @@ -104,17 +107,17 @@ def list_genbank_files(context): context.add_output_metadata( output_name="standardised_ext_file", metadata={ - "text_metadata": f"Last update of the genbank list {_time.isoformat()} (UTC).", - "processed_files": _new_files, - "num_files": len(_files), - "path": _path, + "text_metadata": f"New genbank files have been processed {_time.isoformat()} (UTC).", + "file_location": _gb_path, + "num_files": len(_new_files), + "file_preview": _new_files, }, ) context.add_output_metadata( output_name="list_genbank_files", metadata={ "text_metadata": f"Last update of the genbank list {_time.isoformat()} (UTC).", - "path": _path, + "file_location": _hist_gb_path, "num_files": len(_files), "updated_list": _files, }, diff --git a/synphage/assets/viewer/legend.svg b/synphage/assets/viewer/legend.svg index 32472aa..3733070 100644 --- a/synphage/assets/viewer/legend.svg +++ b/synphage/assets/viewer/legend.svg @@ -1,51 +1,66 @@ + + - - - - image/svg+xml - - ... - - - + xmlns:svg="http://www.w3.org/2000/svg"> + + + + id="defs1"> + + + + gradientTransform="matrix(1.0004631,0,0,1.0004631,-853.1451,-485.96135)" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + id="clipPath33"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + id="clipPath15634"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - ... - ... - - - + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(-3.7313103,-4.3002736)"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 20 + 40 + 60 + 80 + 100 + 0 + 100 + x="-788.80719" + y="-36.645962" + transform="matrix(-0.26470589,0,0,0.26470589,-177.31424,14.061549)" + clip-path="url(#clipPath26)" /> + x="687.79596" + y="-29.423595" + transform="matrix(0.19175111,0,0,0.26470592,-123.29193,14.061549)" + clip-path="url(#clipPath24)" /> + x="708.0517" + y="-29.423595" + transform="matrix(0.19175111,0,0,0.26470592,-123.29802,14.061549)" + clip-path="url(#clipPath22)" /> + x="728.30737" + y="-29.423595" + transform="matrix(0.19175111,0,0,0.26470592,-123.3041,14.061549)" + clip-path="url(#clipPath20)" /> + x="748.56305" + y="-29.423595" + transform="matrix(0.19175111,0,0,0.26470594,-123.31018,14.061549)" + clip-path="url(#clipPath18)" /> + x="768.81873" + y="-29.423595" + transform="matrix(0.19175111,0,0,0.26470592,-123.31627,14.061549)" + clip-path="url(#clipPath16)" /> 0 + id="tspan17">0 20 + id="tspan19">20 40 + id="tspan21">40 60 + id="tspan23">60 80 + id="tspan25">80 100 + id="tspan27">100 + transform="matrix(0.09620767,0,0,0.13410703,-50.090762,13.262359)" + clip-path="url(#clipPath14)" /> + transform="matrix(0.09714619,0,0,0.13410703,-50.567703,13.262359)" + clip-path="url(#clipPath12)" /> 0 + id="tspan29">0 100 + id="tspan31">100 diff --git a/synphage/assets/viewer/viewer.py b/synphage/assets/viewer/static_graph.py similarity index 84% rename from synphage/assets/viewer/viewer.py rename to synphage/assets/viewer/static_graph.py index 356940b..89017f2 100644 --- a/synphage/assets/viewer/viewer.py +++ b/synphage/assets/viewer/static_graph.py @@ -1,10 +1,14 @@ -from dagster import asset, Field, Config, EnvVar, MetadataValue +from dagster import asset, Config, EnvVar, MetadataValue import enum import os import base64 -from io import BytesIO +import math +import tempfile + +import polars as pl +from io import BytesIO from datetime import datetime from typing import Optional from Bio import SeqIO, SeqRecord @@ -12,27 +16,26 @@ from reportlab.lib import colors from Bio.SeqFeature import SeqFeature, SimpleLocation from Bio.Graphics.GenomeDiagram import CrossLink - -import polars as pl from pathlib import Path - from svgutils import compose as C from cairosvg import svg2png from lxml import etree -import math + + +TEMP_DIR = tempfile.gettempdir() def gene_uniqueness( - _path_to_dataset: str, - _record_name: list, -): + path_to_dataset: str, + record_name: list, +) -> pl.DataFrame: """Calculate percentage of the presence of a given gene over the displayed sequences""" _gene_uniqueness_df = ( - pl.read_parquet(_path_to_dataset) + pl.read_parquet(path_to_dataset) .filter( - (pl.col("name").is_in(_record_name)) - & (pl.col("source_genome_name").is_in(_record_name)) + (pl.col("name").is_in(record_name)) + & (pl.col("source_genome_name").is_in(record_name)) ) .with_columns(pl.col("name").n_unique().alias("total_seq")) .group_by("name", "gene", "locus_tag", "total_seq") @@ -47,12 +50,12 @@ def gene_uniqueness( return _gene_uniqueness_df -def _assess_file_content(_genome) -> bool: # Duplicated function +def _assess_file_content(genome: SeqRecord.SeqRecord) -> bool: # Duplicated function """Assess wether the genbank file contains gene or only CDS""" _gene_count = 0 _gene_value = False - for _feature in _genome.features: + for _feature in genome.features: if _feature.type == "gene": _gene_count = _gene_count + 1 if _gene_count > 1: @@ -62,8 +65,8 @@ def _assess_file_content(_genome) -> bool: # Duplicated function return _gene_value -def _get_sqc_identity_from_csv(_file_path): - _df = pl.read_csv(_file_path, has_header=False).select( +def _get_sqc_identity_from_csv(file_path: str) -> dict: + _df = pl.read_csv(file_path, has_header=False).select( "column_1", pl.col("column_2").cast(pl.Int16) ) return {x: y for x, y in zip(*_df.to_dict(as_series=False).values())} @@ -79,32 +82,32 @@ class CheckOrientation(enum.Enum): compute_kind="Python", metadata={"owner": "Virginie Grosboillot"}, ) -def create_genome(context): - context.log.info("get path") - context.log.info(os.getenv(EnvVar("PHAGY_DIRECTORY"))) - context.log.info(os.getenv(EnvVar("SEQUENCE_FILE"))) - _path = "/".join( - [os.getenv(EnvVar("PHAGY_DIRECTORY")), os.getenv(EnvVar("SEQUENCE_FILE"))] +def create_genome(context) -> dict: + # Path to sequence file + _path_seq = str( + Path(os.getenv(EnvVar("DATA_DIR"), TEMP_DIR)) + / os.getenv(EnvVar("SEQUENCE_FILE"), "sequences.csv") ) - context.log.info(_path) - - if os.path.exists(_path): - _sequences = _get_sqc_identity_from_csv(_path) + context.log.info(f"File containing the sequences to plot: {_path_seq}") + + if os.path.exists(_path_seq): + _sequences = _get_sqc_identity_from_csv(_path_seq) + for _k, _v in _sequences.items(): + # When the user is lazy and wants to do SEQUENCE=0, or REVERSE=1 + if isinstance(_v, int): + _sequences[_k] = CheckOrientation(_v).name else: - "The file format is not recognised" - - for _k, _v in _sequences.items(): - # When the user is lazy and wants to do SEQUENCE=0, or REVERSE=1 - if isinstance(_v, int): - _sequences[_k] = CheckOrientation(_v).name + _sequences = {} + context.log.info( + "sequences.csv file not present or the file format is not recognised" + ) # Asset metadata _time = datetime.now() context.add_output_metadata( metadata={ - "text_metadata": f"Dictionnary of sequences to plot {_time.isoformat()} (UTC).", + "text_metadata": f"Sequences to plot {_time.isoformat()} (UTC).", "num_sqcs": len(_sequences), - "path": _path, "sequences": MetadataValue.json(_sequences), } ) @@ -120,18 +123,18 @@ def _read_seq(_path: str, _orientation: str) -> SeqRecord.SeqRecord: def _get_feature( - _features, _id, _tags=("locus_tag", "gene", "old_locus_tag", "protein_id") -): + features, id, tags=("locus_tag", "gene", "old_locus_tag", "protein_id") +) -> SeqFeature: """Search list of SeqFeature objects for an identifier under the given tags.""" - for _f in _features: - for _key in _tags: + for _f in features: + for _key in tags: # tag may not be present in this feature for _x in _f.qualifiers.get(_key, []): - if _x == _id: # gene + if _x == id: # gene return _f - elif _x[:-2] == _id: # protein_id + elif _x[:-2] == id: # protein_id return _f - raise KeyError(_id) + raise KeyError(id) class Diagram(Config): @@ -147,18 +150,18 @@ class Diagram(Config): uniq_dir: str = "tables/uniqueness.parquet" -gene_uniqueness_folder_config = { - "output_folder": Field( - str, - description="Path to folder where the files will be saved", - default_value="table", - ), - "name": Field( - str, - description="Path to folder where the files will be saved", - default_value="gene_uniqueness", - ), -} +# gene_uniqueness_folder_config = { +# "output_folder": Field( +# str, +# description="Path to folder where the files will be saved", +# default_value="table", +# ), +# "name": Field( +# str, +# description="Path to folder where the files will be saved", +# default_value="gene_uniqueness", +# ), +# } @asset( @@ -172,18 +175,21 @@ class Diagram(Config): "owner": "Virginie Grosboillot", }, ) -def create_graph(context, create_genome, config: Diagram): +def create_graph( + context, create_genome: dict, config: Diagram +) -> GenomeDiagram.Diagram: # Define the paths - - _input_folder = "/".join([os.getenv(EnvVar("PHAGY_DIRECTORY")), "genbank"]) - _output_folder = "/".join([os.getenv(EnvVar("PHAGY_DIRECTORY")), "synteny"]) - _blastn_dir = "/".join( - [os.getenv(EnvVar("PHAGY_DIRECTORY")), "tables", "blastn_summary.parquet"] + _gb_folder = str(Path(os.getenv(EnvVar("DATA_DIR"), TEMP_DIR)) / "genbank") + _synteny_folder = str(Path(os.getenv(EnvVar("DATA_DIR"), TEMP_DIR)) / "synteny") + _blastn_dir = str( + Path(os.getenv(EnvVar("DATA_DIR"), TEMP_DIR)) + / "tables" + / "blastn_summary.parquet" ) - _uniq_dir = "/".join( - [os.getenv(EnvVar("PHAGY_DIRECTORY")), "tables", "uniqueness.parquet"] + _uniq_dir = str( + Path(os.getenv(EnvVar("DATA_DIR"), TEMP_DIR)) / "tables" / "uniqueness.parquet" ) - _colour_dir = "/".join([_output_folder, "colour_table"]) + _colour_dir = str(Path(_synteny_folder) / "colour_table") # Set name for the diagram if os.getenv(EnvVar("TITLE")): @@ -195,7 +201,7 @@ def create_graph(context, create_genome, config: Diagram): _records = {} for _k, _v in create_genome.items(): - _genbank_path = "/".join([_input_folder, _k]) + _genbank_path = str(Path(_gb_folder) / _k) _record = _read_seq(_genbank_path, _v) context.log.info(f"Orientation: {_record}") _records[_record.name] = _record @@ -300,7 +306,7 @@ def create_graph(context, create_genome, config: Diagram): _gd_feature_set = _feature_sets[_record_name] _gene_value = _assess_file_content(_record) - if _gene_value == True: + if _gene_value: for _feature in _record.features: if _feature.type != "gene": # Exclude this feature @@ -452,8 +458,8 @@ def create_graph(context, create_genome, config: Diagram): else: _fmt = "png" - _path_output = str(f"{_output_folder}/{_name_graph}.{_fmt}") - _png_output = str(f"{_output_folder}/{_name_graph}.png") + _path_output = str(Path(_synteny_folder) / f"{_name_graph}.{_fmt}") + _png_output = str(Path(_synteny_folder) / f"{_name_graph}.png") _gd_diagram.write(_path_output, config.output_format) context.log.info("Parsing SVG xml file") @@ -469,7 +475,7 @@ def create_graph(context, create_genome, config: Diagram): context.log.info(f"Coord of SVG: {str(xpos)} : {str(ypos)}") legend_path = "synphage/assets/viewer/legend.svg" - # (f"{_output_folder}/legend.svg") + # (f"{_synteny_folder}/legend.svg") C.Figure( f"{width}px", f"{height}px", diff --git a/synphage/jobs.py b/synphage/jobs.py index e13467d..93644fd 100644 --- a/synphage/jobs.py +++ b/synphage/jobs.py @@ -1,4 +1,5 @@ from dagster import ( + EnvVar, AssetSelection, define_asset_job, op, @@ -14,6 +15,7 @@ ) import os +import tempfile import duckdb import polars as pl from functools import partial @@ -28,6 +30,8 @@ warnings.filterwarnings("ignore", category=ExperimentalWarning) +TEMP_DIR = tempfile.gettempdir() + # Job 1 -> get the list of genbank to blastn blasting_job = define_asset_job( @@ -143,10 +147,7 @@ def gene_presence(context, blastn_all, locus_all): context.log.info(f"sql_file: {_path_gene_presence_sql}") query = open(_path_gene_presence_sql).read() conn.query(query.format(blastn_all, locus_all)).pl().write_parquet( - Path(os.getenv("PHAGY_DIRECTORY")) - / "tables" - / "uniqueness.parquet" - # "/data/tables/uniqueness.parquet" + str(Path(os.getenv("DATA_DIR")) / "tables" / "uniqueness.parquet") ) return "OK" @@ -154,27 +155,23 @@ def gene_presence(context, blastn_all, locus_all): default_config = RunConfig( ops={ "blastn": PipeConfig( - source="/".join([os.getenv("PHAGY_DIRECTORY"), "gene_identity/blastn"]), - target="/".join( - [ - os.getenv("PHAGY_DIRECTORY"), - os.getenv("FILE_SYSTEM"), - "blastn_parsing", - ] + source=str( + Path(os.getenv(EnvVar("DATA_DIR"), TEMP_DIR)) + / "gene_identity" + / "blastn" + ), + target=str( + Path(os.getenv(EnvVar("DATA_DIR"), TEMP_DIR)) / "fs" / "blastn_parsing" ), - table_dir="/".join([os.getenv("PHAGY_DIRECTORY"), "tables"]), + table_dir=str(Path(os.getenv(EnvVar("DATA_DIR"), TEMP_DIR)) / "tables"), file="blastn_summary.parquet", ), "locus": PipeConfig( - source="/".join([os.getenv("PHAGY_DIRECTORY"), "genbank"]), - target="/".join( - [ - os.getenv("PHAGY_DIRECTORY"), - os.getenv("FILE_SYSTEM"), - "locus_parsing", - ] + source=str(Path(os.getenv(EnvVar("DATA_DIR"), TEMP_DIR)) / "genbank"), + target=str( + Path(os.getenv(EnvVar("DATA_DIR"), TEMP_DIR)) / "fs" / "locus_parsing" ), - table_dir="/".join([os.getenv("PHAGY_DIRECTORY"), "tables"]), + table_dir=str(Path(os.getenv(EnvVar("DATA_DIR"), TEMP_DIR)) / "tables"), file="locus_and_gene.parquet", ), } diff --git a/synphage/resources/__init__.py b/synphage/resources/__init__.py index bba43f5..c7f35b2 100644 --- a/synphage/resources/__init__.py +++ b/synphage/resources/__init__.py @@ -1,15 +1,16 @@ import os +import tempfile + +from pathlib import Path from .ncbi_resource import ncbi_resource -from .parquet_io_manager import LocalParquetIOManager from dagster import EnvVar, FilesystemIOManager RESOURCES_LOCAL = { "ncbi_connection": ncbi_resource, - # "parquet_io_manager": LocalParquetIOManager(base_dir=EnvVar("PHAGY_DIRECTORY")), "io_manager": FilesystemIOManager( - base_dir="/".join([os.getenv("PHAGY_DIRECTORY"), "fs"]) + base_dir=str(Path(os.getenv(EnvVar("DATA_DIR"), tempfile.gettempdir())) / "fs") ), } diff --git a/synphage/resources/parquet_io_manager.py b/synphage/resources/parquet_io_manager.py index 5312731..9fcd98f 100644 --- a/synphage/resources/parquet_io_manager.py +++ b/synphage/resources/parquet_io_manager.py @@ -1,27 +1,25 @@ -from dagster import ConfigurableIOManager +# from dagster import ConfigurableIOManager -from pyspark.sql import SparkSession +# class LocalParquetIOManager(ConfigurableIOManager): +# base_dir: str -class LocalParquetIOManager(ConfigurableIOManager): - base_dir: str +# def _get_path(self, context): +# return "/".join( +# [ +# context.resource_config["base_dir"], +# context.metadata["tables"], +# context.metadata["name"], +# ] +# ) +# # return "/".join([context.resource_config["base_dir"], context.op_config["output_folder"], context.op_config["name"]]) AttributeError: 'OutputContext' object has no attribute 'op_config' - # def _get_path(self, context): - # return "/".join( - # [ - # context.resource_config["base_dir"], - # context.metadata["tables"], - # context.metadata["name"], - # ] - # ) - # # return "/".join([context.resource_config["base_dir"], context.op_config["output_folder"], context.op_config["name"]]) AttributeError: 'OutputContext' object has no attribute 'op_config' +# def handle_output(self, context, obj): +# if context.metadata["parquet_managment"] == "overwrite": +# obj.coalesce(1).write.mode("overwrite").parquet(self._get_path(context)) +# else: +# obj.coalesce(1).write.mode("append").parquet(self._get_path(context)) - # def handle_output(self, context, obj): - # if context.metadata["parquet_managment"] == "overwrite": - # obj.coalesce(1).write.mode("overwrite").parquet(self._get_path(context)) - # else: - # obj.coalesce(1).write.mode("append").parquet(self._get_path(context)) - - # def load_input(self, context): # context: InputContext - # spark = SparkSession.builder.getOrCreate() - # return spark.read.parquet(self._get_path(context.upstream_output)) +# def load_input(self, context): # context: InputContext +# spark = SparkSession.builder.getOrCreate() +# return spark.read.parquet(self._get_path(context.upstream_output)) diff --git a/test/fixtures/assets_testing_folder/sequence_quality/download/TT_000001.1.gb b/test/fixtures/assets_testing_folder/sequence_quality/download/TT_000001.1.gb new file mode 100644 index 0000000..5a2205e --- /dev/null +++ b/test/fixtures/assets_testing_folder/sequence_quality/download/TT_000001.1.gb @@ -0,0 +1,291 @@ +LOCUS TT_000001 10000 bp DNA linear CON 16-FEB-2023 +DEFINITION Synthetic Phage Genome 1. +ACCESSION TT_000001 REGION: 1..10000 +VERSION TT_000001.1 +DBLINK BioProject: SYNTH1 + BioSample: SYNTH000001 +KEYWORDS RefSeq; complete genome. +SOURCE Synthetic Phage Genome 1 + ORGANISM Synthetic Phage Genome 1 + Phage; Synthetic. +REFERENCE 1 + AUTHORS Grosboillot,V. + TITLE A synthetic phage genome for python testing. + JOURNAL XXX Xxxxx 11 (1), 3-17 (2023) + PUBMED 23021601 +COMMENT PROVISIONAL REFSEQ: This record has not yet been subject to final + NCBI review. + COMPLETENESS: full length. +FEATURES Location/Qualifiers + source 1..10000 + /organism="Synthetic Phage Genome 1" + /mol_type="genomic DNA" + /strain="1" + /sub_species="synthetic" + /type_material="type synthetic phage" + /db_xref="taxon:000001" + gene complement(1..1000) + /gene="geneA" + /locus_tag="GEN_10" + /old_locus_tag="GEN10" + /db_xref="GeneID:1" + CDS complement(1..1000) + /gene="geneA" + /locus_tag="GEN_10" + /old_locus_tag="GEN10" + /function="hypothetical" + /experiment="none" + /note="none" + /codon_start=1 + /transl_table=11 + /product="hypothetical protein; phage + SPbeta" + /protein_id="NP_000001.1" + /db_xref="EnsemblGenomes-Gn:GEN10" + /db_xref="GeneID:1" + /translation="MEPYQRYEELKKKTIKVVQKENYSIRYITQDEASNDLDEFYKQF + AQHLLEAALERKAE" + gene complement(1001..3000) + /gene="geneB" + /locus_tag="GEN_20" + /old_locus_tag="GEN20" + /db_xref="GeneID:2" + CDS complement(1001..3000) + /gene="geneB" + /locus_tag="GEN_20" + /old_locus_tag="GEN20" + /function="hypothetical" + /inference="none" + /note="none" + /codon_start=1 + /transl_table=11 + /product="hypothetical protein; phage SPbeta" + /protein_id="NP_000001.2" + /db_xref="EnsemblGenomes-Gn:GEN20" + /db_xref="GeneID:2" + /translation="MGANNQGKVFEANIEKSAADQKLFFYRIKDVNPMFLKRGAAVSK + NKYDCFLFFKGYLFPFELKSTKSKSISFSEKIIKPQQIKYLREATQYPNIIPGFLFQF + REPENKVYFVHINDFLTYKNIAEKQLKHTYKNKVNKASIPIAICEEIGTEVRSMKKKV + NYTYYLNKLCGELIKKEQSRDKPLHTYNTPVKTGV" + gene 3001..4000 + /gene="geneC" + /locus_tag="GEN_30" + /old_locus_tag="GEN30" + /db_xref="GeneID:3" + misc_feature 3001..4000 + /gene="geneC" + /locus_tag="GEN_30" + /old_locus_tag="GEN30" + /inference="none" + /note="none" + /pseudo + /db_xref="PSEUDO:3" + gene complement(4001..7000) + /gene="geneD" + /locus_tag="GEN_40" + /old_locus_tag="GEN_40" + /db_xref="GeneID:4" + CDS complement(4001..7000) + /gene="geneD" + /locus_tag="GEN_40" + /old_locus_tag="GEN40" + /inference="none" + /note="none" + /codon_start=1 + /transl_table=11 + /product="hypothetical protein; phage + SPbeta" + /protein_id="NP_000001.4" + /db_xref="EnsemblGenomes-Gn:GEN40" + /db_xref="GeneID:4" + /translation="MNEAYHSIQTLLNKMDRQMKTVKEAIEEKDLQRAHRNLINLADN + NEELMQEIRWVKKGTIL" + gene complement(7001..10000) + /gene="geneE" + /locus_tag="GEN_50" + /old_locus_tag="GEN50" + /db_xref="GeneID:5" + CDS complement(7001..10000) + /gene="geneE" + /locus_tag="GEN_50" + /old_locus_tag="GEN50" + /inference="none" + /note="none" + /codon_start=1 + /transl_table=11 + /product="hypothetical protein; phage SPbeta" + /protein_id="NP_000001.5" + /db_xref="EnsemblGenomes-Gn:GEN50" + /db_xref="GeneID:5" + /translation="MCNRNVITIPYEEDMSKYSILHQVGGRIEYFQKEYSQYPMFAFD + SEEDYNEYKCLIMQLKKNKKVSSFSF" +ORIGIN + 1 ttaagatact tactacatat ctaacgaaaa aaagaagctt actctgcctt cctttccaga + 61 gcagcttcta ataaatgttg agcaaattgt ttataaaact catctaagtc attacttgct + 121 tcatcctgag ttatatatcg aatactgtaa ttttctttct ggactacctt tattgttttt + 181 ttctttaatt cctcataacg ttggtaaggt tccaaggcta cacccccgtt ttcacaggag + 241 tattatatgt atgtaatggt ttgtctcttg actgttcttt cttaattagt tccccgcaaa + 301 gcttgtttaa ataatatgta taattcactt tctttttcat cgagcgcact tcagtaccga + 361 tttcttcaca aatcgcaatc gggatactgg ctttgtttac tttattctta tatgtatgtt + 421 tcaactgttt ttcagctatg ttcttatatg taaggaaatc attaatatgt acgaaataaa + 481 ctttgttttc cggctctcta aattgaaaca gaaaaccagg gattatgttt gggtattgtg + 541 ttgcttccct taaatattta atctgctgcg gctttatgat tttctcgctg aaggaaatgg + 601 acttgctttt tgtcgactta agctcaaagg ggaacaagta ccccttaaag aacagaaagc + 661 aatcatattt gttttttgat actgctgccc ctcttttcaa gaacattggg ttaacatctt + 721 taatccggta aaagaataac ttttgatctg ctgcagattt ttcaatgttc gcttcaaaaa + 781 ctttcccttg attgtttgct cccaatcaat cactctccta atctatattg aaggtaaatt + 841 atgtatgtgc taaaatcgtt gctgaaagag gtgtgcatag tgaaaaaaca atggaaacca + 901 gttgattcaa gactcaatga gctcatgcat gaatatagcg tttcaattga agatcttgtt + 961 gaatgtactg gattatcaaa acaacgtatt aatgattatg taggtggttt taaatcaaat + 1021 atgaatattg gaacagcaat gacatttgct gatgccatag gttgctctat agaagagctt + 1081 tatgtatgga actttaaaga gcgcagacaa ttaaccaaat aacttataat atggttccct + 1141 ttttgaccca ccttatttcc tgcattaatt cctcattatt gtcagccaag ttaattaagt + 1201 tacgatgtgc tctttgcaaa tctttttctt caatggcctc cttcactgtc ttcatttgtc + 1261 tatccatctt gtttaacagt gtttgaattg aatgataagc ctcgttaatt tttctcgcct + 1321 ctttcccata tgtgcaatat ttagttcatt actttttgca tattaaactg ttgtttgcaa + 1381 taccctactc ttttaaaaag agaaactaga gactttttta ttctttttaa gctgcattat + 1441 taagcattta tattcgttgt aatcctcttc actatcaaat gcgaacattg gatattgtga + 1501 atactctttt tgaaaatact caattcgccc ccctacctgg tgtagtattg aatactttga + 1561 catatcctct tcatatggaa ttgtaataac atttcgatta cacataatac ctccactaat + 1621 tttattttta ttctaaataa aagaccgatt ttatcctgtt cctatttaca ttaatctaga + 1681 taaacaactt cttttacaat tggaaatgga ctactgattc tctcacttaa atgcaaaact + 1741 atttcagtta cgtcttttga tgttgccacg tggactgcct ttgtaatttt aaaattgaat + 1801 tcattttcaa ttaagagacg tttaccttcg gaaaatatat ctattgaact aaccgcaaaa + 1861 tcacactttc catttattcg atacggatta aagcatttca caaaataaca tttatttaat + 1921 tccttactgt ctgataaaac aatgtcaaat tccacatccc aaacaaacgt gttaatctta + 1981 gaatgataaa ctaaatcatg ggtagctcct gtatctttaa aaatttcaat cattgaaata + 2041 atcctcccca aatcactcct gctgcaatag cagctataaa gacagaaaca aatttcatta + 2101 aaatgaaaaa cttaatatgc tttgtttcgt tctcagttaa gtcaaaatct gataaagcga + 2161 ataaaccaaa cacaattaac aatatccagg ctgtaacaat caggtatctt tcctccaatc + 2221 atgttttatt gtggcagata ttaatatatt ccttcaggct attaactgtt gaaataatac + 2281 accctcgaac ctcttcagga tcttcaaaat ccatttcatt ttgcagaaca aattcatcaa + 2341 actcaatcat ggcaagaaag cgatcgtcat tgggtagctt attaaaatca atattcttta + 2401 atcttggaat acctttttcc tttatccatt caaggaaggg ataatcaaca tcattctttg + 2461 ctactgcgat ttttaaaaac tcatgaatat cagaagagtt ttcaatattg aaataaatca + 2521 tgagactttc cttcataaga tcaaataatc acaataaagt tttatcaatg ttattgtctg + 2581 atttaatttc aaagtctata ttaaaccagg acattacgtt ctccattcaa tccctccttg + 2641 tacatctaaa ctattactca cttgactaac ccccttaagc gttcgacttc tgcaactaac + 2701 cattctgcat aactgatatg aatttttatc accttggttg atctaagtcg ccgagacatt + 2761 acttcaacaa attttttaac ttcttcaaat tcaatctctt tcattgagtt tatcccacta + 2821 aatgaaatca acgtcttaat caatcaagta tcttattttt tggctttata tcgatttcat + 2881 cacaagaagg acatgaaaaa tctgaattgt cacctatcca actaaaattg cattcattac + 2941 aagtccaatc aatttgttct ctactgtcca ttatagctac acctctttct taataaattc + 3001 aacattttat ctacttccaa ttgtagttct ccttttcttt ctctgaatca cctatatgcg + 3061 aaagaatcca attatgataa ccctcttctc cacaattagg gcaatccatt tcagatataa + 3121 cctttaatgt gtttatcata ggatttttag caaacaagtg atgattgcat tttctacaaa + 3181 aaaacacaac ttcattttcc atgtctcccc ttcccttctg tataaaatta gaattttaat + 3241 taaatctaaa tctcgaatgt tttaagctca aacgttttat atgaatctac ttcttcacca + 3301 ggtatcacat tgacactcgg ataattatca tagtcatacg ggtatccgat acaattcatg + 3361 tgaaagctcg ttccatcttt gtcaaactca gcttgtaaat gatcatgtcc acaaacccag + 3421 tgttttgcgt taatgaacgg gacatcaacc atgtagcatg tattaggctc aaatggagaa + 3481 taaggattgt gaacaggtgg aacatgtgag acaaatacat caacttgtgt attttcaagc + 3541 gtttcatacc aatccattga ttctttccac atcgctctta caccatctac tttgttataa + 3601 ccattaagcc aaatgtaatt agaatcgtta gatactcctt taaagaagtc ccatccttcg + 3661 attccttttg gaaggtacca cattacatct cctgcaaaga cttttccttt gtatgtttca + 3721 gttgtcttaa ttaatggtgt tacatttttc atgtcagcag ctttttgaat tagatcattc + 3781 aacctgccta acgagtctga gtatttcctt ttttggctct tgctaagtaa ataaagatca + 3841 tgattaccat atgtaaagta aaccttctcg tattgctttg ctgcctcatc taaaacccat + 3901 aaagtttgtt gattccattc agtaaaatcg ccggcaatga ccaatacctc cccattaccg + 3961 tttgagatta acctatttac aatttctctt gttcgcttct cccacttaat ctgatttaca + 4021 ttccaaggaa tccaatgatt tatatggaga tctgaaacat aatcaatttt cattttgtct + 4081 ccacctttct taatgaaaaa tttatttctt tggcgtgtat aaattaaaat aatctctcca + 4141 taatatgatt caaacaagct tgttttcatt acactttagg agatgaataa gatggctcaa + 4201 caaagtagat caagatcaaa caacaataat gatttactaa ttcctcaagc agcttcagct + 4261 attgaacaaa tgaaacttga aatagcttct gagtttggtg ttcaattagg cgctgagact + 4321 acatctcgtg caaacggttc agttggtgga gaaatcacta aacgtttagt tcgcttagct + 4381 caacaaaaca tgggcggtca atttcattaa tttatgaggg ggataattcc cctctctttt + 4441 ttaagtcttc tctaaatcca tacagaacta atggtattgt ttccacctct ttttatgtca + 4501 ctaactacta ttattaagct cctcgacttg cactgtgtaa tgtctgtacc attttattgc + 4561 ctcctttgat tagccactct ataaattgcg ttctcttcat ttagaatata tccagcgctc + 4621 cgtcacaata agaacatttg ccactaccct cttcacatgt acacatatat ttgtcacctc + 4681 caatttcgct accgtcaact gacaactcct cagatatcat ttaattgttg tttcagctca + 4741 aagaattcat catgaagaaa tttaaattta tccttattta cgtatgcttt gtcatcatta + 4801 agatcaaaga gatctaagta ctttctttta tttcttttaa taattcgtaa agcaatagtg + 4861 gcacttaccc actcttcacc ttccaattgg gttaagactt cacttagctc gaataacaat + 4921 tcaagcttag ctttgttttg ctgtgtttcg agttttaaca gatccctttg tttttcaagt + 4981 aaagttgttt caatttggta tttctttttc tctaaggctg ttatctgttc gttggtgtta + 5041 tgtattttgt ctcctacttc caatgaatca cctccttaaa gtttgaataa aatattagtt + 5101 ttaaaaaatg tatatttttt gtttttgtat attagataaa aaaactgtca tttcatcatc + 5161 ttctattatt atattataca tattatttgt atttgtctat agttatttta ttttcattct + 5221 taaatccatt tacttagccc tgacaaatgc taaaagggct tgagccgtat aatgagtgca + 5281 gctaaacaca atttcacatt atatgaaaaa taatactcaa agcaaagata aggttcccaa + 5341 agacataagc caaataaata tacctactat ggctcactgt ttcgccctcc aacacgtcta + 5401 aaaccttaaa catgcttagg actgtgtata taactgaaaa tgctgtccaa cagagtataa + 5461 ggatattttc atgcataatt aaaccgttat atgccaaggg gatgattaaa gaactcccct + 5521 taagcaaagt aaacaggtaa attaaattct tatttcgttt cgcatcttct ggagttgaat + 5581 tatcaagcac actctttact tttatatacg tattgctttc ccctcgcata atcaacctga + 5641 cctcattaat gtttaataca attagataag ctgatagaaa taaagttaca tatgttatag + 5701 taaacatctc ctaattttat atttgtgttg ggttggcttt tactcaccct caaactctat + 5761 accgttaata tttgctttta ttcaaatagc tcccccttta aaatcattca cttgatcagc + 5821 aatgttttct ttaattgtat gtggcaactg atcaatccct tttataatcc gtttctgacc + 5881 agttttccta atttttgtag tcatctcttt aaaacactct aaagcagtat ctgagatttc + 5941 atcatatagc ccctgaattt tcactaatac acttaaatat tcttcgtcac cttcttcaaa + 6001 tagcgacaac ccttcttcaa gtttgttgat cttttcaaca ctctttatta ttttattttt + 6061 atccttaaac aattaatccc ccacccagtt ttggtcatgc atcttcatga agttagctgc + 6121 tgccttcttg tatctcaggt ctttctcgta ctcagcaact tgtctcatat gttcaataaa + 6181 ttcatcttca agtccttgta actgaagaaa cccaaagcaa agaccgttcc tataaagcat + 6241 gtcgtcatat ttcgcttgta aatctctttc tttgctgtta ataatctctt cctccttaaa + 6301 tattagataa aagtattctt ttattcggaa atatttccaa caaaaatctt ttatggtaaa + 6361 ttaaaaacaa tgtatttaaa ggagtgttaa tttgcgaaaa atattaaaaa tcgttagctt + 6421 actgattcta ttgttattat tggtttattc tttcttcagt cctaattcac aattatttgt + 6481 gttcgttcag ctaatcataa ttgcattttt gattggtttt ggaattaact gttttgttaa + 6541 aaaagaacga taccaaggta ctctatactt cgtaattgca atatgcaaca ttaccattaa + 6601 tcttgataaa ataaacgagt taattcagag catttaactt atacatatat aggaggtggg + 6661 aaattaccca ccttctttat tggataggaa ctaatacttc acataagtga ttatcaatca + 6721 tttgtgaagt atatctctct ataattggtt ctcctctcat agttagacta tttttttcta + 6781 tttcagagaa aatattgccc caaaattcac ttactgcctc ttttgtatgg tcaagcaaga + 6841 aaacagcgta tttccctcca ggtaacttac caacttgagc tggttgcagc acattaaaat + 6901 cttcatttaa tacaacacca acatcataac ggcattcctc tttaggagta atacttggat + 6961 catcttgtgg aattcctaaa attacagagt tatgaaatac accattcaac tgtgcccact + 7021 ttttaaaaga ttccattagt tctttgtttt gcttaccacc atactctcca acgtttcgga + 7081 aataagcaat ccttaattca ggtaattctt caatagttat tttcatattt taatcccctt + 7141 tcctagaaaa aggtaatatg attaaaaatg tttttcaaga tgacttttaa aataatctat + 7201 atttcaaata caaaatccaa ttacttcgtt ccagttgatc cgtgcccacc tcggtcaccg + 7261 ttgcctagac ggtctacctc gatcaagtca actgccggca tcttcttcat aattctgaac + 7321 tggcagattc gatccccttt cttaatcttt gtgtcacgta acgcataagc aggaaagaac + 7381 caaaaatcgt tgtcaccctt ataagactca tcgataacac ccattgagtt tgtttgaatc + 7441 acaccaaagt tcttatacgt actcgaacga ggaacgacat gtgcttcgta accttcaggc + 7501 aattccatgg ccactcccaa tggaacaagt ttaaattcat cttttttgat cgctacatct + 7561 tcagctgcac gaagatcaat ccaatcacct tgctccattt tgttaattct tgtttgtgtt + 7621 tcatctaagt atttgatttt aatttgcatt atgtattagc tccttttaat tcaagtttgt + 7681 ttaaaattac ccttttatcg taattccttt agtaactcat caagttcatt aggcttaaaa + 7741 ccaacacttc ggtttacttc ttctccctga tcactcagca gaatggttac cggtactccc + 7801 atgacaccaa atcttgctgc tacttctggt tcctgtgtaa cgtcaacagt ctcaaattga + 7861 atatttactt gttctaagta attggacacc attttacatg gattgcaatt aggctgctct + 7921 aatttaatta atctcattga atacatcctt tctcggtaaa aatgaaatct gaatccttta + 7981 aaggctccac tgttgctttt ttgtatccat tccctttagt tgaaaagaag tcatgggatt + 8041 tagtcttagt gttcaaacca ttgataacaa ttggattaac atcctcttct tcaaaccaat + 8101 gatcaaagcc cagattgttt aaagctttat ttgcgttgta tctgatgaat ttctttacat + 8161 ctggagctaa tccaacctga tcatagacat cttctgtata ctccaattca ttttcgtaaa + 8221 gttcctgcag taagtttaaa gcccatgcgt acagttcttt ttgcttctgt ggcgtttgct + 8281 tcttataaat ctcttgagct aacaatccta catatacgcc atgtatcgct tcgtctctaa + 8341 tacccttagt tcaaccgagt tcgctacttt cggttcgttg ctctgtcgca accgccttac + 8401 gttaccgtaa ggagcagact atatcatcat ccctgtagga tgcctcccgt ttcgatttaa + 8461 ggggttctca cccacgccaa tagcttgcgc cctactcgtt ttgcggaatt tcgccgccta + 8521 tgcgatagtc gttgaacgtt ctatgcgatc ccataaagtc ttccatcttc ttttatgtcg + 8581 aattagacta acgtaacgag gatgaaggct gtatttttca ccagcttcaa cattgttcat + 8641 tccagcaatc aaatcataga ttaaatttgt tgcctccata ttagtgagct ttgacattga + 8701 attactttct ccaggttgtc ctgacattaa tccaattttc attgcatgta gagtattttc + 8761 tttaggtgta actatttcta agttccgaac gtggttgttt agtttatttc catctatgtg + 8821 gtttacaaac attccttttg gtatatcata aataaaatat tttgcgacta acctatgtac + 8881 taaatagttc tgtgttcctt ttttcggatg cgtgtatcct atcatttcat agccatgtgg + 8941 agtaataaat gtctttcttg gtttctttaa tttttttgat atgataactc ccgtttccgt + 9001 tatccaccaa ggtgcttctt cgacttcttt ccttatcatt ttcacctcct ttgggttcgc + 9061 atagcttcgc tgctgattgt cctaataagg attttccagc aattagagag gttcacattt + 9121 gccgttgccg acaaaaggga ctattaaata atcaggttaa tgatctctcc actttgcatt + 9181 aactttcctt gtccataaaa ataaagtggg taataaaacc ctgagtagaa aagaaaactc + 9241 tccaggaaca cagatgcaac cattccttta aataaagaaa tttcatcgtt tttcttgatt + 9301 gttttataga ctgaaacaat tgttctagct ttcttttgaa gaaacctatt gtttttcacc + 9361 cattcaaaga cttcattgat ctgctcggtt ggagccaatg ttagaaagat gttgctgtaa + 9421 gactttgcat gaacagcatt ttccatcatg gccatgaaat ttaaaactgc ctttctttga + 9481 tgtccatcta cgtgttcagc cacgatcggc atccccgtat tcccctgctc tgtatcaaga + 9541 agcgtaagtc cggccagtac cttcatataa gtgtcctgct cattttttcc gaggtacttc + 9601 catgtgagga gatcgccgtt taaagcaatc tcttccggaa gccagaactg tttcacgttt + 9661 tggttataga acatttgggt aaaatcgtct tcatgctttg accagtttgc tgcgtcataa + 9721 atttttgtca attaatcatg tcctttcaat tgaaatattt ttttccgaaa aaaatgcagt + 9781 gaatttaaaa gctgaattga cagactccta tattactgtc aaacattcga aaggaatgaa + 9841 agacagtgaa ttttttagat aaccttatat ctttgttaga gagtacagtc atttcaactg + 9901 gatggttgtg tgataggctt ttatcatgtt taatcgaata tattttgaag cttatatttg + 9961 gtttactttg taatgctctt atgagaaaat ttaacaaaat +// + diff --git a/test/fixtures/assets_testing_folder/sequence_quality_with_history/download/TT_000001.gb b/test/fixtures/assets_testing_folder/sequence_quality_with_history/download/TT_000001.gb new file mode 100644 index 0000000..5a2205e --- /dev/null +++ b/test/fixtures/assets_testing_folder/sequence_quality_with_history/download/TT_000001.gb @@ -0,0 +1,291 @@ +LOCUS TT_000001 10000 bp DNA linear CON 16-FEB-2023 +DEFINITION Synthetic Phage Genome 1. +ACCESSION TT_000001 REGION: 1..10000 +VERSION TT_000001.1 +DBLINK BioProject: SYNTH1 + BioSample: SYNTH000001 +KEYWORDS RefSeq; complete genome. +SOURCE Synthetic Phage Genome 1 + ORGANISM Synthetic Phage Genome 1 + Phage; Synthetic. +REFERENCE 1 + AUTHORS Grosboillot,V. + TITLE A synthetic phage genome for python testing. + JOURNAL XXX Xxxxx 11 (1), 3-17 (2023) + PUBMED 23021601 +COMMENT PROVISIONAL REFSEQ: This record has not yet been subject to final + NCBI review. + COMPLETENESS: full length. +FEATURES Location/Qualifiers + source 1..10000 + /organism="Synthetic Phage Genome 1" + /mol_type="genomic DNA" + /strain="1" + /sub_species="synthetic" + /type_material="type synthetic phage" + /db_xref="taxon:000001" + gene complement(1..1000) + /gene="geneA" + /locus_tag="GEN_10" + /old_locus_tag="GEN10" + /db_xref="GeneID:1" + CDS complement(1..1000) + /gene="geneA" + /locus_tag="GEN_10" + /old_locus_tag="GEN10" + /function="hypothetical" + /experiment="none" + /note="none" + /codon_start=1 + /transl_table=11 + /product="hypothetical protein; phage + SPbeta" + /protein_id="NP_000001.1" + /db_xref="EnsemblGenomes-Gn:GEN10" + /db_xref="GeneID:1" + /translation="MEPYQRYEELKKKTIKVVQKENYSIRYITQDEASNDLDEFYKQF + AQHLLEAALERKAE" + gene complement(1001..3000) + /gene="geneB" + /locus_tag="GEN_20" + /old_locus_tag="GEN20" + /db_xref="GeneID:2" + CDS complement(1001..3000) + /gene="geneB" + /locus_tag="GEN_20" + /old_locus_tag="GEN20" + /function="hypothetical" + /inference="none" + /note="none" + /codon_start=1 + /transl_table=11 + /product="hypothetical protein; phage SPbeta" + /protein_id="NP_000001.2" + /db_xref="EnsemblGenomes-Gn:GEN20" + /db_xref="GeneID:2" + /translation="MGANNQGKVFEANIEKSAADQKLFFYRIKDVNPMFLKRGAAVSK + NKYDCFLFFKGYLFPFELKSTKSKSISFSEKIIKPQQIKYLREATQYPNIIPGFLFQF + REPENKVYFVHINDFLTYKNIAEKQLKHTYKNKVNKASIPIAICEEIGTEVRSMKKKV + NYTYYLNKLCGELIKKEQSRDKPLHTYNTPVKTGV" + gene 3001..4000 + /gene="geneC" + /locus_tag="GEN_30" + /old_locus_tag="GEN30" + /db_xref="GeneID:3" + misc_feature 3001..4000 + /gene="geneC" + /locus_tag="GEN_30" + /old_locus_tag="GEN30" + /inference="none" + /note="none" + /pseudo + /db_xref="PSEUDO:3" + gene complement(4001..7000) + /gene="geneD" + /locus_tag="GEN_40" + /old_locus_tag="GEN_40" + /db_xref="GeneID:4" + CDS complement(4001..7000) + /gene="geneD" + /locus_tag="GEN_40" + /old_locus_tag="GEN40" + /inference="none" + /note="none" + /codon_start=1 + /transl_table=11 + /product="hypothetical protein; phage + SPbeta" + /protein_id="NP_000001.4" + /db_xref="EnsemblGenomes-Gn:GEN40" + /db_xref="GeneID:4" + /translation="MNEAYHSIQTLLNKMDRQMKTVKEAIEEKDLQRAHRNLINLADN + NEELMQEIRWVKKGTIL" + gene complement(7001..10000) + /gene="geneE" + /locus_tag="GEN_50" + /old_locus_tag="GEN50" + /db_xref="GeneID:5" + CDS complement(7001..10000) + /gene="geneE" + /locus_tag="GEN_50" + /old_locus_tag="GEN50" + /inference="none" + /note="none" + /codon_start=1 + /transl_table=11 + /product="hypothetical protein; phage SPbeta" + /protein_id="NP_000001.5" + /db_xref="EnsemblGenomes-Gn:GEN50" + /db_xref="GeneID:5" + /translation="MCNRNVITIPYEEDMSKYSILHQVGGRIEYFQKEYSQYPMFAFD + SEEDYNEYKCLIMQLKKNKKVSSFSF" +ORIGIN + 1 ttaagatact tactacatat ctaacgaaaa aaagaagctt actctgcctt cctttccaga + 61 gcagcttcta ataaatgttg agcaaattgt ttataaaact catctaagtc attacttgct + 121 tcatcctgag ttatatatcg aatactgtaa ttttctttct ggactacctt tattgttttt + 181 ttctttaatt cctcataacg ttggtaaggt tccaaggcta cacccccgtt ttcacaggag + 241 tattatatgt atgtaatggt ttgtctcttg actgttcttt cttaattagt tccccgcaaa + 301 gcttgtttaa ataatatgta taattcactt tctttttcat cgagcgcact tcagtaccga + 361 tttcttcaca aatcgcaatc gggatactgg ctttgtttac tttattctta tatgtatgtt + 421 tcaactgttt ttcagctatg ttcttatatg taaggaaatc attaatatgt acgaaataaa + 481 ctttgttttc cggctctcta aattgaaaca gaaaaccagg gattatgttt gggtattgtg + 541 ttgcttccct taaatattta atctgctgcg gctttatgat tttctcgctg aaggaaatgg + 601 acttgctttt tgtcgactta agctcaaagg ggaacaagta ccccttaaag aacagaaagc + 661 aatcatattt gttttttgat actgctgccc ctcttttcaa gaacattggg ttaacatctt + 721 taatccggta aaagaataac ttttgatctg ctgcagattt ttcaatgttc gcttcaaaaa + 781 ctttcccttg attgtttgct cccaatcaat cactctccta atctatattg aaggtaaatt + 841 atgtatgtgc taaaatcgtt gctgaaagag gtgtgcatag tgaaaaaaca atggaaacca + 901 gttgattcaa gactcaatga gctcatgcat gaatatagcg tttcaattga agatcttgtt + 961 gaatgtactg gattatcaaa acaacgtatt aatgattatg taggtggttt taaatcaaat + 1021 atgaatattg gaacagcaat gacatttgct gatgccatag gttgctctat agaagagctt + 1081 tatgtatgga actttaaaga gcgcagacaa ttaaccaaat aacttataat atggttccct + 1141 ttttgaccca ccttatttcc tgcattaatt cctcattatt gtcagccaag ttaattaagt + 1201 tacgatgtgc tctttgcaaa tctttttctt caatggcctc cttcactgtc ttcatttgtc + 1261 tatccatctt gtttaacagt gtttgaattg aatgataagc ctcgttaatt tttctcgcct + 1321 ctttcccata tgtgcaatat ttagttcatt actttttgca tattaaactg ttgtttgcaa + 1381 taccctactc ttttaaaaag agaaactaga gactttttta ttctttttaa gctgcattat + 1441 taagcattta tattcgttgt aatcctcttc actatcaaat gcgaacattg gatattgtga + 1501 atactctttt tgaaaatact caattcgccc ccctacctgg tgtagtattg aatactttga + 1561 catatcctct tcatatggaa ttgtaataac atttcgatta cacataatac ctccactaat + 1621 tttattttta ttctaaataa aagaccgatt ttatcctgtt cctatttaca ttaatctaga + 1681 taaacaactt cttttacaat tggaaatgga ctactgattc tctcacttaa atgcaaaact + 1741 atttcagtta cgtcttttga tgttgccacg tggactgcct ttgtaatttt aaaattgaat + 1801 tcattttcaa ttaagagacg tttaccttcg gaaaatatat ctattgaact aaccgcaaaa + 1861 tcacactttc catttattcg atacggatta aagcatttca caaaataaca tttatttaat + 1921 tccttactgt ctgataaaac aatgtcaaat tccacatccc aaacaaacgt gttaatctta + 1981 gaatgataaa ctaaatcatg ggtagctcct gtatctttaa aaatttcaat cattgaaata + 2041 atcctcccca aatcactcct gctgcaatag cagctataaa gacagaaaca aatttcatta + 2101 aaatgaaaaa cttaatatgc tttgtttcgt tctcagttaa gtcaaaatct gataaagcga + 2161 ataaaccaaa cacaattaac aatatccagg ctgtaacaat caggtatctt tcctccaatc + 2221 atgttttatt gtggcagata ttaatatatt ccttcaggct attaactgtt gaaataatac + 2281 accctcgaac ctcttcagga tcttcaaaat ccatttcatt ttgcagaaca aattcatcaa + 2341 actcaatcat ggcaagaaag cgatcgtcat tgggtagctt attaaaatca atattcttta + 2401 atcttggaat acctttttcc tttatccatt caaggaaggg ataatcaaca tcattctttg + 2461 ctactgcgat ttttaaaaac tcatgaatat cagaagagtt ttcaatattg aaataaatca + 2521 tgagactttc cttcataaga tcaaataatc acaataaagt tttatcaatg ttattgtctg + 2581 atttaatttc aaagtctata ttaaaccagg acattacgtt ctccattcaa tccctccttg + 2641 tacatctaaa ctattactca cttgactaac ccccttaagc gttcgacttc tgcaactaac + 2701 cattctgcat aactgatatg aatttttatc accttggttg atctaagtcg ccgagacatt + 2761 acttcaacaa attttttaac ttcttcaaat tcaatctctt tcattgagtt tatcccacta + 2821 aatgaaatca acgtcttaat caatcaagta tcttattttt tggctttata tcgatttcat + 2881 cacaagaagg acatgaaaaa tctgaattgt cacctatcca actaaaattg cattcattac + 2941 aagtccaatc aatttgttct ctactgtcca ttatagctac acctctttct taataaattc + 3001 aacattttat ctacttccaa ttgtagttct ccttttcttt ctctgaatca cctatatgcg + 3061 aaagaatcca attatgataa ccctcttctc cacaattagg gcaatccatt tcagatataa + 3121 cctttaatgt gtttatcata ggatttttag caaacaagtg atgattgcat tttctacaaa + 3181 aaaacacaac ttcattttcc atgtctcccc ttcccttctg tataaaatta gaattttaat + 3241 taaatctaaa tctcgaatgt tttaagctca aacgttttat atgaatctac ttcttcacca + 3301 ggtatcacat tgacactcgg ataattatca tagtcatacg ggtatccgat acaattcatg + 3361 tgaaagctcg ttccatcttt gtcaaactca gcttgtaaat gatcatgtcc acaaacccag + 3421 tgttttgcgt taatgaacgg gacatcaacc atgtagcatg tattaggctc aaatggagaa + 3481 taaggattgt gaacaggtgg aacatgtgag acaaatacat caacttgtgt attttcaagc + 3541 gtttcatacc aatccattga ttctttccac atcgctctta caccatctac tttgttataa + 3601 ccattaagcc aaatgtaatt agaatcgtta gatactcctt taaagaagtc ccatccttcg + 3661 attccttttg gaaggtacca cattacatct cctgcaaaga cttttccttt gtatgtttca + 3721 gttgtcttaa ttaatggtgt tacatttttc atgtcagcag ctttttgaat tagatcattc + 3781 aacctgccta acgagtctga gtatttcctt ttttggctct tgctaagtaa ataaagatca + 3841 tgattaccat atgtaaagta aaccttctcg tattgctttg ctgcctcatc taaaacccat + 3901 aaagtttgtt gattccattc agtaaaatcg ccggcaatga ccaatacctc cccattaccg + 3961 tttgagatta acctatttac aatttctctt gttcgcttct cccacttaat ctgatttaca + 4021 ttccaaggaa tccaatgatt tatatggaga tctgaaacat aatcaatttt cattttgtct + 4081 ccacctttct taatgaaaaa tttatttctt tggcgtgtat aaattaaaat aatctctcca + 4141 taatatgatt caaacaagct tgttttcatt acactttagg agatgaataa gatggctcaa + 4201 caaagtagat caagatcaaa caacaataat gatttactaa ttcctcaagc agcttcagct + 4261 attgaacaaa tgaaacttga aatagcttct gagtttggtg ttcaattagg cgctgagact + 4321 acatctcgtg caaacggttc agttggtgga gaaatcacta aacgtttagt tcgcttagct + 4381 caacaaaaca tgggcggtca atttcattaa tttatgaggg ggataattcc cctctctttt + 4441 ttaagtcttc tctaaatcca tacagaacta atggtattgt ttccacctct ttttatgtca + 4501 ctaactacta ttattaagct cctcgacttg cactgtgtaa tgtctgtacc attttattgc + 4561 ctcctttgat tagccactct ataaattgcg ttctcttcat ttagaatata tccagcgctc + 4621 cgtcacaata agaacatttg ccactaccct cttcacatgt acacatatat ttgtcacctc + 4681 caatttcgct accgtcaact gacaactcct cagatatcat ttaattgttg tttcagctca + 4741 aagaattcat catgaagaaa tttaaattta tccttattta cgtatgcttt gtcatcatta + 4801 agatcaaaga gatctaagta ctttctttta tttcttttaa taattcgtaa agcaatagtg + 4861 gcacttaccc actcttcacc ttccaattgg gttaagactt cacttagctc gaataacaat + 4921 tcaagcttag ctttgttttg ctgtgtttcg agttttaaca gatccctttg tttttcaagt + 4981 aaagttgttt caatttggta tttctttttc tctaaggctg ttatctgttc gttggtgtta + 5041 tgtattttgt ctcctacttc caatgaatca cctccttaaa gtttgaataa aatattagtt + 5101 ttaaaaaatg tatatttttt gtttttgtat attagataaa aaaactgtca tttcatcatc + 5161 ttctattatt atattataca tattatttgt atttgtctat agttatttta ttttcattct + 5221 taaatccatt tacttagccc tgacaaatgc taaaagggct tgagccgtat aatgagtgca + 5281 gctaaacaca atttcacatt atatgaaaaa taatactcaa agcaaagata aggttcccaa + 5341 agacataagc caaataaata tacctactat ggctcactgt ttcgccctcc aacacgtcta + 5401 aaaccttaaa catgcttagg actgtgtata taactgaaaa tgctgtccaa cagagtataa + 5461 ggatattttc atgcataatt aaaccgttat atgccaaggg gatgattaaa gaactcccct + 5521 taagcaaagt aaacaggtaa attaaattct tatttcgttt cgcatcttct ggagttgaat + 5581 tatcaagcac actctttact tttatatacg tattgctttc ccctcgcata atcaacctga + 5641 cctcattaat gtttaataca attagataag ctgatagaaa taaagttaca tatgttatag + 5701 taaacatctc ctaattttat atttgtgttg ggttggcttt tactcaccct caaactctat + 5761 accgttaata tttgctttta ttcaaatagc tcccccttta aaatcattca cttgatcagc + 5821 aatgttttct ttaattgtat gtggcaactg atcaatccct tttataatcc gtttctgacc + 5881 agttttccta atttttgtag tcatctcttt aaaacactct aaagcagtat ctgagatttc + 5941 atcatatagc ccctgaattt tcactaatac acttaaatat tcttcgtcac cttcttcaaa + 6001 tagcgacaac ccttcttcaa gtttgttgat cttttcaaca ctctttatta ttttattttt + 6061 atccttaaac aattaatccc ccacccagtt ttggtcatgc atcttcatga agttagctgc + 6121 tgccttcttg tatctcaggt ctttctcgta ctcagcaact tgtctcatat gttcaataaa + 6181 ttcatcttca agtccttgta actgaagaaa cccaaagcaa agaccgttcc tataaagcat + 6241 gtcgtcatat ttcgcttgta aatctctttc tttgctgtta ataatctctt cctccttaaa + 6301 tattagataa aagtattctt ttattcggaa atatttccaa caaaaatctt ttatggtaaa + 6361 ttaaaaacaa tgtatttaaa ggagtgttaa tttgcgaaaa atattaaaaa tcgttagctt + 6421 actgattcta ttgttattat tggtttattc tttcttcagt cctaattcac aattatttgt + 6481 gttcgttcag ctaatcataa ttgcattttt gattggtttt ggaattaact gttttgttaa + 6541 aaaagaacga taccaaggta ctctatactt cgtaattgca atatgcaaca ttaccattaa + 6601 tcttgataaa ataaacgagt taattcagag catttaactt atacatatat aggaggtggg + 6661 aaattaccca ccttctttat tggataggaa ctaatacttc acataagtga ttatcaatca + 6721 tttgtgaagt atatctctct ataattggtt ctcctctcat agttagacta tttttttcta + 6781 tttcagagaa aatattgccc caaaattcac ttactgcctc ttttgtatgg tcaagcaaga + 6841 aaacagcgta tttccctcca ggtaacttac caacttgagc tggttgcagc acattaaaat + 6901 cttcatttaa tacaacacca acatcataac ggcattcctc tttaggagta atacttggat + 6961 catcttgtgg aattcctaaa attacagagt tatgaaatac accattcaac tgtgcccact + 7021 ttttaaaaga ttccattagt tctttgtttt gcttaccacc atactctcca acgtttcgga + 7081 aataagcaat ccttaattca ggtaattctt caatagttat tttcatattt taatcccctt + 7141 tcctagaaaa aggtaatatg attaaaaatg tttttcaaga tgacttttaa aataatctat + 7201 atttcaaata caaaatccaa ttacttcgtt ccagttgatc cgtgcccacc tcggtcaccg + 7261 ttgcctagac ggtctacctc gatcaagtca actgccggca tcttcttcat aattctgaac + 7321 tggcagattc gatccccttt cttaatcttt gtgtcacgta acgcataagc aggaaagaac + 7381 caaaaatcgt tgtcaccctt ataagactca tcgataacac ccattgagtt tgtttgaatc + 7441 acaccaaagt tcttatacgt actcgaacga ggaacgacat gtgcttcgta accttcaggc + 7501 aattccatgg ccactcccaa tggaacaagt ttaaattcat cttttttgat cgctacatct + 7561 tcagctgcac gaagatcaat ccaatcacct tgctccattt tgttaattct tgtttgtgtt + 7621 tcatctaagt atttgatttt aatttgcatt atgtattagc tccttttaat tcaagtttgt + 7681 ttaaaattac ccttttatcg taattccttt agtaactcat caagttcatt aggcttaaaa + 7741 ccaacacttc ggtttacttc ttctccctga tcactcagca gaatggttac cggtactccc + 7801 atgacaccaa atcttgctgc tacttctggt tcctgtgtaa cgtcaacagt ctcaaattga + 7861 atatttactt gttctaagta attggacacc attttacatg gattgcaatt aggctgctct + 7921 aatttaatta atctcattga atacatcctt tctcggtaaa aatgaaatct gaatccttta + 7981 aaggctccac tgttgctttt ttgtatccat tccctttagt tgaaaagaag tcatgggatt + 8041 tagtcttagt gttcaaacca ttgataacaa ttggattaac atcctcttct tcaaaccaat + 8101 gatcaaagcc cagattgttt aaagctttat ttgcgttgta tctgatgaat ttctttacat + 8161 ctggagctaa tccaacctga tcatagacat cttctgtata ctccaattca ttttcgtaaa + 8221 gttcctgcag taagtttaaa gcccatgcgt acagttcttt ttgcttctgt ggcgtttgct + 8281 tcttataaat ctcttgagct aacaatccta catatacgcc atgtatcgct tcgtctctaa + 8341 tacccttagt tcaaccgagt tcgctacttt cggttcgttg ctctgtcgca accgccttac + 8401 gttaccgtaa ggagcagact atatcatcat ccctgtagga tgcctcccgt ttcgatttaa + 8461 ggggttctca cccacgccaa tagcttgcgc cctactcgtt ttgcggaatt tcgccgccta + 8521 tgcgatagtc gttgaacgtt ctatgcgatc ccataaagtc ttccatcttc ttttatgtcg + 8581 aattagacta acgtaacgag gatgaaggct gtatttttca ccagcttcaa cattgttcat + 8641 tccagcaatc aaatcataga ttaaatttgt tgcctccata ttagtgagct ttgacattga + 8701 attactttct ccaggttgtc ctgacattaa tccaattttc attgcatgta gagtattttc + 8761 tttaggtgta actatttcta agttccgaac gtggttgttt agtttatttc catctatgtg + 8821 gtttacaaac attccttttg gtatatcata aataaaatat tttgcgacta acctatgtac + 8881 taaatagttc tgtgttcctt ttttcggatg cgtgtatcct atcatttcat agccatgtgg + 8941 agtaataaat gtctttcttg gtttctttaa tttttttgat atgataactc ccgtttccgt + 9001 tatccaccaa ggtgcttctt cgacttcttt ccttatcatt ttcacctcct ttgggttcgc + 9061 atagcttcgc tgctgattgt cctaataagg attttccagc aattagagag gttcacattt + 9121 gccgttgccg acaaaaggga ctattaaata atcaggttaa tgatctctcc actttgcatt + 9181 aactttcctt gtccataaaa ataaagtggg taataaaacc ctgagtagaa aagaaaactc + 9241 tccaggaaca cagatgcaac cattccttta aataaagaaa tttcatcgtt tttcttgatt + 9301 gttttataga ctgaaacaat tgttctagct ttcttttgaa gaaacctatt gtttttcacc + 9361 cattcaaaga cttcattgat ctgctcggtt ggagccaatg ttagaaagat gttgctgtaa + 9421 gactttgcat gaacagcatt ttccatcatg gccatgaaat ttaaaactgc ctttctttga + 9481 tgtccatcta cgtgttcagc cacgatcggc atccccgtat tcccctgctc tgtatcaaga + 9541 agcgtaagtc cggccagtac cttcatataa gtgtcctgct cattttttcc gaggtacttc + 9601 catgtgagga gatcgccgtt taaagcaatc tcttccggaa gccagaactg tttcacgttt + 9661 tggttataga acatttgggt aaaatcgtct tcatgctttg accagtttgc tgcgtcataa + 9721 atttttgtca attaatcatg tcctttcaat tgaaatattt ttttccgaaa aaaatgcagt + 9781 gaatttaaaa gctgaattga cagactccta tattactgtc aaacattcga aaggaatgaa + 9841 agacagtgaa ttttttagat aaccttatat ctttgttaga gagtacagtc atttcaactg + 9901 gatggttgtg tgataggctt ttatcatgtt taatcgaata tattttgaag cttatatttg + 9961 gtttactttg taatgctctt atgagaaaat ttaacaaaat +// + diff --git a/test/fixtures/assets_testing_folder/sequence_quality_with_history/fs/history_transferred_files b/test/fixtures/assets_testing_folder/sequence_quality_with_history/fs/history_transferred_files new file mode 100644 index 0000000..937325c Binary files /dev/null and b/test/fixtures/assets_testing_folder/sequence_quality_with_history/fs/history_transferred_files differ diff --git a/test/unit/accession_asset/test_download_genomes.py b/test/unit/accession_asset/test_download_genomes.py index adea32b..99be474 100644 --- a/test/unit/accession_asset/test_download_genomes.py +++ b/test/unit/accession_asset/test_download_genomes.py @@ -14,7 +14,7 @@ def test_downloaded_genomes_pos(mock_env_ncbi_download_pos): def test_downloded_genomes_neg(mock_env_ncbi_download_neg): - _path = "/".join([os.getenv("PHAGY_DIRECTORY"), "download"]) + _path = "/".join([os.getenv("DATA_DIR"), "download"]) os.makedirs(_path, exist_ok=True) context = build_asset_context() result = downloaded_genomes(context) diff --git a/test/unit/accession_asset/test_fetch_genome.py b/test/unit/accession_asset/test_fetch_genome.py index 1d92178..6988e34 100644 --- a/test/unit/accession_asset/test_fetch_genome.py +++ b/test/unit/accession_asset/test_fetch_genome.py @@ -56,7 +56,7 @@ def test_fetch_genome(mock_env_ncbi_fetch): - _path = "/".join([os.getenv("PHAGY_DIRECTORY"), "download"]) + _path = "/".join([os.getenv("DATA_DIR"), "download"]) os.makedirs(_path, exist_ok=True) context = build_asset_context( resources={ @@ -81,7 +81,7 @@ def mock_upstream_ids(): def mock_upstream_download(): return ["NZ_CP045811.1"] - _path = "/".join([os.getenv("PHAGY_DIRECTORY"), "download"]) + _path = "/".join([os.getenv("DATA_DIR"), "download"]) os.makedirs(_path, exist_ok=True) assets = [fetch_genome, mock_upstream_ids, mock_upstream_download] diff --git a/test/unit/accession_asset/test_sequence_check.py b/test/unit/accession_asset/test_sequence_check.py index fd14b0e..f70b31c 100644 --- a/test/unit/accession_asset/test_sequence_check.py +++ b/test/unit/accession_asset/test_sequence_check.py @@ -9,8 +9,44 @@ def test_sequence_check(mock_env_sequence_check): "test/fixtures/assets_testing_folder/sequence_quality/download/TT_000001.gb" ] result = sequence_check(context, input_asset) - assert isinstance(result, list) - assert len(result) == 1 + assert isinstance(result, tuple) + assert len(result) == 2 + assert isinstance(result[0], list) + assert len(result[0]) == 1 + assert isinstance(result[1], list) + assert len(result[1]) == 1 + + +def test_sequence_check_with_history(mock_env_sequence_check_with_history): + context = build_asset_context() + input_asset = [ + "test/fixtures/assets_testing_folder/sequence_quality_with_history/download/TT_000001.gb" + ] + result = sequence_check(context, input_asset) + assert isinstance(result, tuple) + assert len(result) == 2 + assert isinstance(result[0], list) + assert len(result[0]) == 0 + assert isinstance(result[1], list) + assert len(result[1]) == 1 + + +def test_sequence_check_remove_dot(mock_env_sequence_check): + context = build_asset_context() + input_asset = [ + "test/fixtures/assets_testing_folder/sequence_quality/download/TT_000001.1.gb" + ] + result = sequence_check(context, input_asset) + assert isinstance(result, tuple) + assert len(result) == 2 + assert isinstance(result[0], list) + assert len(result[0]) == 1 + assert result[0] == ["TT_000001_1.gb"] + assert isinstance(result[1], list) + assert len(result[1]) == 1 + assert result[1] == [ + "test/fixtures/assets_testing_folder/sequence_quality/download/TT_000001.1.gb" + ] def test_sequence_check_asset(mock_env_sequence_check): @@ -23,5 +59,9 @@ def mock_upstream(): assets = [sequence_check, mock_upstream] result = materialize_to_memory(assets) assert result.success - seq = result.output_for_node("sequence_check") - assert seq == ["TT_000001"] + new_seq = result.output_for_node("sequence_check", "new_transferred_files") + hist_seq = result.output_for_node("sequence_check", "history_transferred_files") + assert new_seq == ["TT_000001.gb"] + assert hist_seq == [ + "test/fixtures/assets_testing_folder/sequence_quality/download/TT_000001.gb" + ] diff --git a/test/unit/all_jobs/test_blasting_job.py b/test/unit/all_jobs/test_blasting_job.py index a402c1d..574d116 100644 --- a/test/unit/all_jobs/test_blasting_job.py +++ b/test/unit/all_jobs/test_blasting_job.py @@ -2,12 +2,12 @@ from synphage.jobs import blasting_job -from synphage.assets.blaster import blaster -from synphage.assets.status import status +from synphage.assets.blaster import n_blaster +from synphage.assets.status import gb_file_status def test_blasting_job(): - all_assets = load_assets_from_modules([status, blaster]) + all_assets = load_assets_from_modules([gb_file_status, n_blaster]) defs = Definitions(assets=all_assets, jobs=[blasting_job]) result = defs.get_job_def("blasting_job").execute_in_process() assert isinstance(result, ExecuteInProcessResult) diff --git a/test/unit/all_jobs/transform_job/test_gene_presence.py b/test/unit/all_jobs/transform_job/test_gene_presence.py index 518fcb5..9b06ec4 100644 --- a/test/unit/all_jobs/transform_job/test_gene_presence.py +++ b/test/unit/all_jobs/transform_job/test_gene_presence.py @@ -33,7 +33,5 @@ def test_gene_presence_table_content(mock_env_phagy_dir_transform_step3): BLASTN_TABLE, LOCUS_TAG_TABLE, ) - df = pl.read_parquet( - Path(os.getenv("PHAGY_DIRECTORY")) / "tables" / "uniqueness.parquet" - ) + df = pl.read_parquet(Path(os.getenv("DATA_DIR")) / "tables" / "uniqueness.parquet") assert set(["name", "locus_tag", "gene"]).issubset(df.columns) diff --git a/test/unit/all_jobs/transform_job/test_transform.py b/test/unit/all_jobs/transform_job/test_transform.py index 0cd9214..08b5113 100644 --- a/test/unit/all_jobs/transform_job/test_transform.py +++ b/test/unit/all_jobs/transform_job/test_transform.py @@ -11,27 +11,27 @@ def test_transform(mock_env_phagy_dir_transform): config = RunConfig( ops={ "blastn": PipeConfig( - source="/".join([os.getenv("PHAGY_DIRECTORY"), "gene_identity/blastn"]), + source="/".join([os.getenv("DATA_DIR"), "gene_identity/blastn"]), target="/".join( [ - os.getenv("PHAGY_DIRECTORY"), + os.getenv("DATA_DIR"), os.getenv("FILE_SYSTEM"), "blastn_parsing", ] ), - table_dir="/".join([os.getenv("PHAGY_DIRECTORY"), "tables"]), + table_dir="/".join([os.getenv("DATA_DIR"), "tables"]), file="blastn_summary.parquet", ), "locus": PipeConfig( - source="/".join([os.getenv("PHAGY_DIRECTORY"), "genbank"]), + source="/".join([os.getenv("DATA_DIR"), "genbank"]), target="/".join( [ - os.getenv("PHAGY_DIRECTORY"), + os.getenv("DATA_DIR"), os.getenv("FILE_SYSTEM"), "locus_parsing", ] ), - table_dir="/".join([os.getenv("PHAGY_DIRECTORY"), "tables"]), + table_dir="/".join([os.getenv("DATA_DIR"), "tables"]), file="locus_and_gene.parquet", ), } diff --git a/test/unit/blaster_asset/test_blastn_computation.py b/test/unit/blaster_asset/test_blastn_computation.py index 1dea413..550fa48 100644 --- a/test/unit/blaster_asset/test_blastn_computation.py +++ b/test/unit/blaster_asset/test_blastn_computation.py @@ -2,7 +2,7 @@ from dagster import materialize_to_memory, build_asset_context, asset -from synphage.assets.blaster.blaster import get_blastn +from synphage.assets.blaster.n_blaster import get_blastn TEST_DATASET_BLAST_DB = "test/fixtures/synthetic_data/blast_db/" diff --git a/test/unit/blaster_asset/test_contains_genes.py b/test/unit/blaster_asset/test_contains_genes.py index 22a3337..1f25586 100644 --- a/test/unit/blaster_asset/test_contains_genes.py +++ b/test/unit/blaster_asset/test_contains_genes.py @@ -1,6 +1,6 @@ from Bio import SeqIO -from synphage.assets.blaster.blaster import _assess_file_content +from synphage.assets.blaster.n_blaster import _assess_file_content def test_contains_genes_pos(): diff --git a/test/unit/blaster_asset/test_db_creation.py b/test/unit/blaster_asset/test_db_creation.py index 60a63ba..74f0ef0 100644 --- a/test/unit/blaster_asset/test_db_creation.py +++ b/test/unit/blaster_asset/test_db_creation.py @@ -2,7 +2,7 @@ from dagster import materialize_to_memory, build_asset_context, asset -from synphage.assets.blaster.blaster import create_blast_db +from synphage.assets.blaster.n_blaster import create_blast_db TEST_DATA_FASTA_FILES = "test/fixtures/synthetic_data/fasta_files/" diff --git a/test/unit/blaster_asset/test_fasta_conversion.py b/test/unit/blaster_asset/test_fasta_conversion.py index 990a58d..dd61183 100644 --- a/test/unit/blaster_asset/test_fasta_conversion.py +++ b/test/unit/blaster_asset/test_fasta_conversion.py @@ -1,7 +1,7 @@ from pathlib import PosixPath from dagster import materialize_to_memory, build_asset_context, asset -from synphage.assets.blaster.blaster import genbank_to_fasta +from synphage.assets.blaster.n_blaster import genbank_to_fasta TEST_DATA_GB_DIR = "test/fixtures/assets_testing_folder/blasting/genbank/" diff --git a/test/unit/status_asset/test_list_gb_files.py b/test/unit/status_asset/test_list_gb_files.py index 057da71..e76533d 100644 --- a/test/unit/status_asset/test_list_gb_files.py +++ b/test/unit/status_asset/test_list_gb_files.py @@ -1,7 +1,7 @@ from dagster import materialize_to_memory, build_asset_context from pathlib import PosixPath -from synphage.assets.status.status import list_genbank_files +from synphage.assets.status.gb_file_status import list_genbank_files TEST_DATA_GB_DIR = "test/fixtures/assets_testing_folder/blasting/genbank/" diff --git a/test/unit/status_asset/test_std_file_name.py b/test/unit/status_asset/test_std_file_name.py index 0050c14..8b51c4c 100644 --- a/test/unit/status_asset/test_std_file_name.py +++ b/test/unit/status_asset/test_std_file_name.py @@ -1,7 +1,7 @@ import os from pathlib import Path -from synphage.assets.status.status import _standardise_file_extention +from synphage.assets.status.gb_file_status import _standardise_file_extention def test_standardise_file_extension_positive(): diff --git a/test/unit/test_no_data_dir_set.py b/test/unit/test_no_data_dir_set.py new file mode 100644 index 0000000..7a4d1a1 --- /dev/null +++ b/test/unit/test_no_data_dir_set.py @@ -0,0 +1,5 @@ +import os + + +def test_no_data_dir(mock_env_phagy_dir_none): + assert os.getenv("DATA_DIR") == None diff --git a/test/unit/viewer_asset/test_assess_file_content.py b/test/unit/viewer_asset/test_assess_file_content.py index 22a3337..1f25586 100644 --- a/test/unit/viewer_asset/test_assess_file_content.py +++ b/test/unit/viewer_asset/test_assess_file_content.py @@ -1,6 +1,6 @@ from Bio import SeqIO -from synphage.assets.blaster.blaster import _assess_file_content +from synphage.assets.blaster.n_blaster import _assess_file_content def test_contains_genes_pos(): diff --git a/test/unit/viewer_asset/test_checkOrientation_class.py b/test/unit/viewer_asset/test_checkOrientation_class.py index b0a38b8..864ab00 100644 --- a/test/unit/viewer_asset/test_checkOrientation_class.py +++ b/test/unit/viewer_asset/test_checkOrientation_class.py @@ -1,4 +1,4 @@ -from synphage.assets.viewer.viewer import CheckOrientation +from synphage.assets.viewer.static_graph import CheckOrientation def test_checkorientation(): diff --git a/test/unit/viewer_asset/test_create_genome.py b/test/unit/viewer_asset/test_create_genome.py index ab4bbe7..3b0c522 100644 --- a/test/unit/viewer_asset/test_create_genome.py +++ b/test/unit/viewer_asset/test_create_genome.py @@ -1,6 +1,6 @@ from dagster import materialize_to_memory, build_asset_context, asset -from synphage.assets.viewer.viewer import create_genome, CheckOrientation +from synphage.assets.viewer.static_graph import create_genome, CheckOrientation def test_create_genome(mock_env_phagy_dir_synteny): diff --git a/test/unit/viewer_asset/test_create_graph.py b/test/unit/viewer_asset/test_create_graph.py index 4b0e17d..313092b 100644 --- a/test/unit/viewer_asset/test_create_graph.py +++ b/test/unit/viewer_asset/test_create_graph.py @@ -2,7 +2,7 @@ from dagster import materialize_to_memory, build_asset_context, asset -from synphage.assets.viewer.viewer import create_graph, Diagram +from synphage.assets.viewer.static_graph import create_graph, Diagram def test_create_graph(mock_env_phagy_dir_synteny): diff --git a/test/unit/viewer_asset/test_diagram_class.py b/test/unit/viewer_asset/test_diagram_class.py index 0a71ffd..0c4d25b 100644 --- a/test/unit/viewer_asset/test_diagram_class.py +++ b/test/unit/viewer_asset/test_diagram_class.py @@ -1,6 +1,6 @@ import pytest -from synphage.assets.viewer.viewer import Diagram +from synphage.assets.viewer.static_graph import Diagram def test_Diagram(): diff --git a/test/unit/viewer_asset/test_gene_uniqueness.py b/test/unit/viewer_asset/test_gene_uniqueness.py index d0ee870..d9adb03 100644 --- a/test/unit/viewer_asset/test_gene_uniqueness.py +++ b/test/unit/viewer_asset/test_gene_uniqueness.py @@ -1,6 +1,6 @@ import polars as pl -from synphage.assets.viewer.viewer import gene_uniqueness +from synphage.assets.viewer.static_graph import gene_uniqueness def test_gene_uniqueness(): diff --git a/test/unit/viewer_asset/test_get_feature.py b/test/unit/viewer_asset/test_get_feature.py index 4c52a90..585a3be 100644 --- a/test/unit/viewer_asset/test_get_feature.py +++ b/test/unit/viewer_asset/test_get_feature.py @@ -3,7 +3,7 @@ from Bio import SeqIO from Bio.SeqFeature import SeqFeature -from synphage.assets.viewer.viewer import _get_feature +from synphage.assets.viewer.static_graph import _get_feature def test_get_feature_positive(): diff --git a/test/unit/viewer_asset/test_get_sqc_identity.py b/test/unit/viewer_asset/test_get_sqc_identity.py index b1866d2..3d973e1 100644 --- a/test/unit/viewer_asset/test_get_sqc_identity.py +++ b/test/unit/viewer_asset/test_get_sqc_identity.py @@ -1,4 +1,4 @@ -from synphage.assets.viewer.viewer import _get_sqc_identity_from_csv +from synphage.assets.viewer.static_graph import _get_sqc_identity_from_csv def test_get_sqc_identity_from_csv(): diff --git a/test/unit/viewer_asset/test_read_seq.py b/test/unit/viewer_asset/test_read_seq.py index 49219e6..a0dc31d 100644 --- a/test/unit/viewer_asset/test_read_seq.py +++ b/test/unit/viewer_asset/test_read_seq.py @@ -1,6 +1,6 @@ from Bio.SeqRecord import SeqRecord -from synphage.assets.viewer.viewer import _read_seq +from synphage.assets.viewer.static_graph import _read_seq def test_read_seq_sequence():