diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index bb1c808..565d7df 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -13,7 +13,7 @@ jobs: strategy: matrix: - os: [macos-13, ubuntu-latest] + os: [macos-latest, ubuntu-latest] python-version: ["3.9"] steps: @@ -34,11 +34,10 @@ jobs: - name: Install project shell: bash -l {0} run: | - conda install python=${{ matrix.python-version }} + conda install python=${{ matrix.python-version }} pip python -m pip install --upgrade pip pip install -e . - pip install black - pip install isort + pip install ruff pip install pytest pip install pytest-cov - name: Check formatting diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 0618cf8..4754605 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: conda-incubator/setup-miniconda@v3 with: python-version: 3.9 @@ -26,10 +26,7 @@ jobs: run: | python -m pip install -U pip pip install -e . - pip install black - pip install isort - pip install pytest - pip install pytest-cov + pip install ruff - name: Build a binary wheel and a source tarball shell: bash -l {0} run: just build diff --git a/HISTORY.md b/HISTORY.md index a8874b9..99ae868 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,12 @@ # History +# 1.4.0 + +* Fixes [#102](https://github.com/gbouras13/dnaapler/issues/102). `dnaapler largest`, `mystery` and `nearest` could reorient to the wrong coordinate when the chosen CDS was on the negative strand, as the lowest coordinate of the CDS was used instead of its actual start codon. The reoriented sequence now correctly begins at the start codon. A related latent bug in the negative-strand fallback of the MMseqs2-based reorientation was also fixed. +* If you run `dnaapler` with GFA input, it now also writes a `{prefix}_reoriented.fasta` alongside the `{prefix}_reoriented.gfa`. This FASTA contains all contigs from the GFA (circular contigs reoriented with overlap trimmed, non-circular contigs passed through unchanged), so it can be fed directly to downstream tools such as polishers. +* If a GFA input contains no circular sequences, `dnaapler` no longer exits with an error. Instead it warns, copies the input GFA to the output, and writes all sequences out as a linear `{prefix}_reoriented.fasta`. For `dnaapler all` and `dnaapler bulk`, a reorientation summary is also written with every contig marked as not reoriented. +* Internal: migrated linting and formatting to [ruff](https://docs.astral.sh/ruff/), added golden-output regression tests, and fixed the CI workflows. + # 1.3.0 (2025-08-21) * Thanks @mbhall88 for extending the functionality of `--ignore` and generally cleaning up the codebase a bit diff --git a/docs/output.md b/docs/output.md index 5645422..99b4e36 100644 --- a/docs/output.md +++ b/docs/output.md @@ -4,7 +4,9 @@ dnaapler creates a number of output files. For all subcommands that are not `dnaapler bulk`, inside the output directory you will find: -* A `{prefix}_reoriented.fasta` containing the reoriented genome. If the input file was in GFA format, this will instead be `{prefix}_reoriented.gfa`. +* A `{prefix}_reoriented.fasta` containing the reoriented genome. If the input file was in GFA format, dnaapler will additionally write a `{prefix}_reoriented.gfa`. In this case the `{prefix}_reoriented.fasta` contains all contigs from the GFA — circular contigs reoriented (with overlap trimmed), and non-circular contigs passed through unchanged — so it can be fed directly to downstream tools such as polishers. Reoriented contigs are indicated in the FASTA header with `rotated=True`. + +* If the input GFA contains no circular sequences, there is nothing to reorient. Rather than exiting with an error, dnaapler will warn, copy the input GFA to `{prefix}_reoriented.gfa`, and write all sequences out as a linear `{prefix}_reoriented.fasta` unchanged. For `dnaapler all` and `dnaapler bulk`, a reorientation summary is also written (`{prefix}_all_reorientation_summary.tsv` / `{prefix}_bulk_reorientation_summary.tsv`) with every contig marked `No_reorientation`. * A `{prefix}_blast_output.txt` if a BLAST based method is used. This file will contain the raw blastx results in BLAST output format 6. diff --git a/justfile b/justfile index a4cf1a5..1cee4f6 100644 --- a/justfile +++ b/justfile @@ -2,19 +2,15 @@ PROJECT := "dnaapler" OPEN := if os() == "macos" { "open" } else { "xdg-open" } VERSION := `poetry version | rg -o '\d+\.\d+\.\d+'` -# format code with black and isort +# format code with ruff fmt: - poetry run black . - poetry run isort . + poetry run ruff format . + poetry run ruff check --fix . -# check format of code with black and isort +# check formatting and lint with ruff check-fmt: - poetry run black --check . - poetry run isort --check . - -# lint code with flake8 -lint: - poetry run flake8 . + poetry run ruff format --check . + poetry run ruff check . # install latest version with poetry install: diff --git a/pyproject.toml b/pyproject.toml index 26331b6..4bde039 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "dnaapler" -version = "1.3.0" # change VERSION too +version = "1.4.0" # change VERSION too description = "Reorients assembled microbial sequences" authors = ["George Bouras "] license = "MIT" @@ -26,11 +26,9 @@ pyrodigal = ">=3.0.0" [tool.poetry.dev-dependencies] -black = ">=22.3.0" -isort = ">=5.10.1" +ruff = ">=0.4.0" pytest = ">=6.2.5" pytest-cov = ">=3.0.0" -flake8 = ">=3.0.1" [[tool.poetry.source]] name = "pypi-test" @@ -41,5 +39,10 @@ priority = "primary" requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" -[tool.isort] -profile = "black" +[tool.ruff] +line-length = 88 +exclude = ["*.ipynb"] + +[tool.ruff.lint] +select = ["E", "F", "W", "I"] +ignore = ["E501"] diff --git a/src/dnaapler/__init__.py b/src/dnaapler/__init__.py index 9dfc329..d5e0a02 100755 --- a/src/dnaapler/__init__.py +++ b/src/dnaapler/__init__.py @@ -189,7 +189,10 @@ def chromosome( # validates fasta or gfa validate_input(input) - input_is_gfa, input, original_gfa = prep_gfa(input, output) + input_is_gfa, input, original_gfa, gfa_no_circular = prep_gfa(input, output, prefix) + if gfa_no_circular: + end_dnaapler(start_time) + return # validate E-value check_evalue(evalue) @@ -270,7 +273,10 @@ def archaea( # validates fasta or gfa validate_input(input) - input_is_gfa, input, original_gfa = prep_gfa(input, output) + input_is_gfa, input, original_gfa, gfa_no_circular = prep_gfa(input, output, prefix) + if gfa_no_circular: + end_dnaapler(start_time) + return # validate E-value check_evalue(evalue) @@ -351,7 +357,10 @@ def plasmid( # validates fasta or gfa validate_input(input) - input_is_gfa, input, original_gfa = prep_gfa(input, output) + input_is_gfa, input, original_gfa, gfa_no_circular = prep_gfa(input, output, prefix) + if gfa_no_circular: + end_dnaapler(start_time) + return # validate E-value check_evalue(evalue) @@ -432,7 +441,10 @@ def phage( # validates fasta or gfa validate_input(input) - input_is_gfa, input, original_gfa = prep_gfa(input, output) + input_is_gfa, input, original_gfa, gfa_no_circular = prep_gfa(input, output, prefix) + if gfa_no_circular: + end_dnaapler(start_time) + return # validate E-value check_evalue(evalue) @@ -520,7 +532,10 @@ def custom( # validates fasta or gfa validate_input(input) - input_is_gfa, input, original_gfa = prep_gfa(input, output) + input_is_gfa, input, original_gfa, gfa_no_circular = prep_gfa(input, output, prefix) + if gfa_no_circular: + end_dnaapler(start_time) + return # validate E-value check_evalue(evalue) @@ -645,7 +660,10 @@ def nearest(ctx, input, output, threads, prefix, force, **kwargs): # validates fasta or gfa validate_input(input) - input_is_gfa, input, original_gfa = prep_gfa(input, output) + input_is_gfa, input, original_gfa, gfa_no_circular = prep_gfa(input, output, prefix) + if gfa_no_circular: + end_dnaapler(start_time) + return # run the nearest workflow run_nearest(ctx, input, output, prefix) @@ -691,7 +709,10 @@ def largest(ctx, input, output, threads, prefix, force, **kwargs): # validates fasta or gfa validate_input(input) - input_is_gfa, input, original_gfa = prep_gfa(input, output) + input_is_gfa, input, original_gfa, gfa_no_circular = prep_gfa(input, output, prefix) + if gfa_no_circular: + end_dnaapler(start_time) + return # run the nearest workflow run_largest(ctx, input, output, prefix) @@ -781,7 +802,12 @@ def bulk( # validates fasta or gfa validate_input_bulk(input) check_duplicate_headers(input) - input_is_gfa, input, original_gfa = prep_gfa(input, output) + input_is_gfa, input, original_gfa, gfa_no_circular = prep_gfa( + input, output, prefix, summary_type="bulk" + ) + if gfa_no_circular: + end_dnaapler(start_time) + return # validate E-value check_evalue(evalue) @@ -954,7 +980,12 @@ def all( # validates fasta or gfa validate_input_all(input) check_duplicate_headers(input) - input_is_gfa, input, original_gfa = prep_gfa(input, output) + input_is_gfa, input, original_gfa, gfa_no_circular = prep_gfa( + input, output, prefix, summary_type="all" + ) + if gfa_no_circular: + end_dnaapler(start_time) + return # validate E-value check_evalue(evalue) diff --git a/src/dnaapler/utils/cds_methods.py b/src/dnaapler/utils/cds_methods.py index 5ed58c5..c0b9589 100644 --- a/src/dnaapler/utils/cds_methods.py +++ b/src/dnaapler/utils/cds_methods.py @@ -59,8 +59,11 @@ def run_mystery(ctx, input: Path, seed_value: int, output: Path, prefix: str) -> reorient_gene_number = random.randint(2, gene_count - 1) logger.info(f"Gene number {reorient_gene_number} was selected.") - start = genes[reorient_gene_number].begin strand = genes[reorient_gene_number].strand + if strand == 1: + start = genes[reorient_gene_number].begin + else: + start = genes[reorient_gene_number].end if strand == 1: strand_eng = "forward" @@ -112,8 +115,11 @@ def run_nearest(ctx, input: Path, output: Path, prefix: str) -> None: reorient_gene_number = 1 - start = genes[reorient_gene_number].begin strand = genes[reorient_gene_number].strand + if strand == 1: + start = genes[reorient_gene_number].begin + else: + start = genes[reorient_gene_number].end if strand == 1: strand_eng = "forward" @@ -176,8 +182,11 @@ def run_largest(ctx, input: Path, output: Path, prefix: str) -> None: # Find the gene with the max overlap largest_gene_index = max(size_dict, key=lambda key: size_dict[key]) - start = genes[largest_gene_index].begin strand = genes[largest_gene_index].strand + if strand == 1: + start = genes[largest_gene_index].begin + else: + start = genes[largest_gene_index].end max_size = size_dict[largest_gene_index] / 3 if strand == 1: diff --git a/src/dnaapler/utils/gfa.py b/src/dnaapler/utils/gfa.py index f14754f..78702b3 100644 --- a/src/dnaapler/utils/gfa.py +++ b/src/dnaapler/utils/gfa.py @@ -5,6 +5,7 @@ import os import re +import shutil from pathlib import Path from Bio import SeqIO @@ -22,35 +23,64 @@ def is_gfa(input_file): return gfa_sequence_count(input_file) > 0 -def prep_gfa(input_file, output_dir): +def prep_gfa(input_file, output_dir, prefix, summary_type=None): """ If the input file given to Dnaapler is a GFA file, this function is run early in Dnaapler's - pipeline. It will save a temporary FASTA file which contains the circular sequences from the - GFA. + pipeline. It saves a temporary FASTA file which contains the circular sequences from the GFA, + which is what Dnaapler reorients. + + If the GFA contains no circular sequences there is nothing to reorient, so the input GFA is + instead copied to the output and all sequences are written out as a linear FASTA, and the caller + is told to skip reorientation. + + Args: + * summary_type (str | None): for a GFA with no circular sequences, controls whether a + * reorientation summary is also written. "all" and "bulk" write the corresponding summary + * (with every contig marked as not reoriented); None (the single-gene commands) writes none. Returns: * bool: whether or not the input was GFA format * str: FASTA input file to reorient (if the input was GFA, this is the temp FASTA file, but if * the input was FASTA this is just the same FASTA) * str: GFA input file (if the input was FASTA this is None) + * bool: whether reorientation should be skipped (True only for a GFA with no circular sequences, + * in which case the output GFA and FASTA have already been written) """ - if is_gfa(input_file): - temp_input_fasta = os.path.join(output_dir, "input.fasta") - save_circular_sequences_as_fasta(input_file, temp_input_fasta) - return True, temp_input_fasta, input_file - else: - return False, input_file, None + if not is_gfa(input_file): + return False, input_file, None, False + + contigs, links = load_gfa(input_file) + circular_contigs = find_circular_contigs(contigs, links) + + if not circular_contigs: + logger.warning( + f"{input_file} contains no circular sequences. No contigs will be reoriented; the " + "input GFA will be copied to the output and all sequences written out as a linear FASTA." + ) + write_gfa_passthrough(input_file, output_dir, prefix, summary_type) + return True, input_file, input_file, True + + temp_input_fasta = os.path.join(output_dir, "input.fasta") + circular_contigs = trim_overlaps(circular_contigs) + write_fasta(circular_contigs, temp_input_fasta) + logger.info( + f"number of circular sequences in {input_file}: {len(circular_contigs)}" + ) + return True, temp_input_fasta, input_file, False def finalise_gfa(temp_input_fasta, gfa_input_file, output_fasta): """ If the input file given to Dnaapler is a GFA file, this function is run at the end of Dnaapler's - pipeline. It will create the output GFA and remove the output FASTA (because non-circular - sequences will be missing from the FASTA). + pipeline. It creates the output GFA and rewrites the output FASTA so that it contains all + contigs from the GFA (circular contigs reoriented, non-circular contigs passed through + unchanged), making it suitable for downstream tools such as polishers. """ remove_file(Path(temp_input_fasta)) - save_reoriented_gfa(gfa_input_file, output_fasta) - remove_file(Path(output_fasta)) + # save_reoriented_gfa reads the circular-only output_fasta to build the GFA, so it must run + # before we overwrite output_fasta with the complete (all-contigs) version below. + reoriented_gfa = save_reoriented_gfa(gfa_input_file, output_fasta) + gfa_to_fasta(reoriented_gfa, output_fasta) def remove_file(file_path: Path): @@ -58,17 +88,74 @@ def remove_file(file_path: Path): file_path.unlink() -def save_circular_sequences_as_fasta(gfa_file, fasta_file): +def write_gfa_passthrough(input_gfa, output_dir, prefix, summary_type=None): + """ + Handles a GFA input that contains no circular sequences: copies the input GFA to the output + {prefix}_reoriented.gfa and writes all of its sequences out, unchanged, as a linear + {prefix}_reoriented.fasta. Nothing is reoriented. + + For the `all` and `bulk` commands (summary_type "all"/"bulk"), a reorientation summary is also + written, with every contig marked as not reoriented. + """ + reoriented_gfa = os.path.join(output_dir, f"{prefix}_reoriented.gfa") + reoriented_fasta = os.path.join(output_dir, f"{prefix}_reoriented.fasta") + logger.info(f"copying input GFA to {reoriented_gfa}") + shutil.copyfile(input_gfa, reoriented_gfa) + gfa_to_fasta(input_gfa, reoriented_fasta) + if summary_type is not None: + write_no_reorientation_summary( + gfa_sequence_names(input_gfa), output_dir, prefix, summary_type + ) + + +def write_no_reorientation_summary(contig_names, output_dir, prefix, summary_type): """ - Identifies the circular sequences in the GFA file and saves them in FASTA format. + Writes a reorientation summary TSV marking every contig as not reoriented. Used for the `all` + and `bulk` commands when a GFA input has no circular sequences. The columns mirror the summaries + written by dnaapler.utils.all and dnaapler.utils.bulk respectively. """ - contigs, links = load_gfa(gfa_file) - contigs = find_circular_contigs(contigs, links) - if not contigs: - logger.error(f"Error: {gfa_file} file contains no circular sequences.") - contigs = trim_overlaps(contigs) - write_fasta(contigs, fasta_file) - logger.info(f"number of circular sequences in {gfa_file}: {len(contigs)}") + if summary_type == "all": + columns = [ + "Contig", + "Gene_Reoriented", + "Start", + "Strand", + "Top_Hit", + "Top_Hit_Length", + "Covered_Length", + "Coverage", + "Identical_AAs", + "Identity_Percentage", + "Overlapping_Contig_End", + ] + summary_file = os.path.join( + output_dir, f"{prefix}_all_reorientation_summary.tsv" + ) + elif summary_type == "bulk": + columns = [ + "Contig", + "Start", + "Strand", + "Top_Hit", + "Top_Hit_Length", + "Covered_Length", + "Coverage", + "Identical_AAs", + "Identity_Percentage", + ] + summary_file = os.path.join( + output_dir, f"{prefix}_bulk_reorientation_summary.tsv" + ) + else: + return + + logger.info(f"writing reorientation summary to {summary_file}") + with open(summary_file, "wt") as f: + f.write("\t".join(columns) + "\n") + for name in contig_names: + f.write( + "\t".join([name] + ["No_reorientation"] * (len(columns) - 1)) + "\n" + ) def load_gfa(filename): @@ -164,6 +251,33 @@ def save_reoriented_gfa(original_gfa, reoriented_fasta): parts[5] = "0M" line = "\t".join(parts) + "\n" out_gfa.write(line) + return reoriented_gfa + + +def gfa_to_fasta(gfa_file, fasta_file): + """ + Writes all sequences (the S lines) from a GFA file to a FASTA file. Contigs that were reoriented + carry an "RT:z:" tag in the GFA (added by save_reoriented_gfa); these are annotated in the + FASTA header with "rotated=True rotated_gene=" to match the `dnaapler all` convention. + Non-circular contigs are written out unchanged with a plain header. + """ + logger.info(f"saving reoriented sequences to FASTA format in {fasta_file}") + with open(gfa_file, "rt") as in_gfa, open(fasta_file, "wt") as out_fasta: + for line in in_gfa: + parts = line.rstrip("\n").split("\t") + if parts[0] != "S": + continue + name, seq = parts[1], parts[2] + gene = None + for field in parts[3:]: + if field.startswith("RT:z:"): + gene = field[len("RT:z:") :] + break + if gene is not None: + header = f">{name} rotated=True rotated_gene={gene}" + else: + header = f">{name}" + out_fasta.write(f"{header}\n{seq}\n") def load_reoriented_fasta(reoriented_fasta): diff --git a/src/dnaapler/utils/processing.py b/src/dnaapler/utils/processing.py index 7ac106b..f2e4dd4 100644 --- a/src/dnaapler/utils/processing.py +++ b/src/dnaapler/utils/processing.py @@ -30,7 +30,6 @@ def choose_highest_mmseqs2_bitscore(MMseqs2_df: pd.DataFrame, gene: str) -> List unique_qseqids = MMseqs2_df["qseqid"].unique() for qseqid in unique_qseqids: - if qseqid.startswith("rotated_"): # Check if there is no matching original seqid original_id = qseqid[len("rotated_") :] @@ -38,7 +37,6 @@ def choose_highest_mmseqs2_bitscore(MMseqs2_df: pd.DataFrame, gene: str) -> List chosen_contig_list.append(qseqid) else: for keyword in keywords: - rotated_id = f"rotated_{qseqid}" # Get rows for the original and rotated qseqid @@ -69,7 +67,6 @@ def choose_highest_mmseqs2_bitscore(MMseqs2_df: pd.DataFrame, gene: str) -> List rotated_max_bitscore = 0 if rotated_max_bitscore > 0 or original_max_bitscore > 0: - # Compare the max bitscore # if the rotated is higher if rotated_max_bitscore > original_max_bitscore: @@ -355,8 +352,6 @@ def reorient_sequence( elif strand == -1: start = genes[closest_gene_index].end - start = genes[closest_gene_index].begin - if strand == 1: strand_eng = "forward" else: diff --git a/tests/test_data/NC_007458_rc.fasta b/tests/test_data/NC_007458_rc.fasta new file mode 100644 index 0000000..a9275a8 --- /dev/null +++ b/tests/test_data/NC_007458_rc.fasta @@ -0,0 +1,622 @@ +>NC_007458_rc +GGGGCGGCGGTACGGACAGACCGCCCTGAATGTTTTTCGACCCGCCCCTACCCGTATTTC +TTTTTGTCTTCTGCTGTTTTTCTGTTGTGACATGGATTACAAAGTGATTGTAAATTTTCT +AATTTGAGTTTTAAACTTGGATCAACTTTGATTGGAATGATATGGTCAACCATATCTGCA +ACTTTAATCTTTCTATTGTTCTTACAATGTAGGCACAACCCTTTGTCTCTCATTAGTGCC +TGCTCTCTTAACCTTTCCCATGCCTTTGACCTATAGAAAGCCGTACTCTCTTTGTCCCGT +TTGAATCGGTCGTAGTATCTATTCTTATCCTGCTGCGTTTCCTTCTCTTTGTATCTATGT +TCCTCACAATATCTTTCACGTGTGAGATTATAACAATGAAATTCGCAGCATGGTCTAAGC +GGTTTCTTCATCAGCGTTCACTTCCTCCAAGCTCTTCTCCCTTGATTATGCGACATTGAA +TTGAATCAGCTGTATGATTAACTGTAGACTTCGATAACAATTTACCTTCACAATAGAGTT +CCACTGTATCACTTCGATTTGTAAACTTATCCATAATCTTTTCTAATTTGTCCAGCGCAT +CTGCACATTCATTAGCTGCTTCAGTTACTTCTTTAATTCCTTCTAATGCCTCAGTTGTAT +CCGCAGTTACTTCAATAATTAATTTGTTATTGGCCATTTTATTCTTCCTCCTTTTCAATC +AAGTGTTCTAGACCAATGACCGCCTTGTCGTCCAAACGAATATCCATCAATCCTAAAATC +TTAATTACATCTTTTAAGGATTTGATTTTACTTGCGTCAATCTTATGAGGGTATCTTGGT +CTAAGATAAATACTGTCTTTCTTTTCCAATGTTAACTCCTGTCCTTCCATCCTTCATCCT +CCTCCAAAATAAAAAGCACCATCACTTGGCGCTTTCTTTTTTCTTATTCACCTGTTGAAA +CGCCATTGGTCCATTACAATCAGGACATTTCCAACCATCACGTACCTTATGAGAAGTCTC +TTCAAATCCGCAGTTTCTATCTAAACACCAATGCTTTGTTAATAGCATTTTCAAACTCGC +TTCACCTCTCACTTTCTCCTGTCAAACCTCTTCCTTAATCGTTTCATTTCATCTTCGATA +GCAAGATTCTTTTTATTAATCCGCTCATGACACTTTGCTATATCTGCTTGATACTTACGA +ATCTTATCATTCACGTACGCAGCTATATGTTCATGATTACAATGAGGACAAATAAAGAAA +CACTTCTCAATACGATTAGGGAGTTGTGTTACTTGCGGCTGCATGTCATAACTTTTATCA +CACTCAGAGCAATATACTTGCATTCCCTTTCACCTCATTGATCTATTGATTCTTACTTAA +TGAATCAATTAATATCTCACGTGTTAATTCGAATGACTGCTCTTCGTTAAATCCAGCTTC +TTTAAACTGTGTAAAGGCAGCGAACATCATTTTAGCGGCCAAAGCAAAATCTAGCATAGC +ATTTCCTACTTGTTCATTTTGCATATCGTTTACAATTTTATTAAACCCGTTCATTCAGTG +ACTCTCCTTTTCATATTCCTTTTTTAATTTCTTTAATTCACGTTTGAACTTCCAGATAAA +ACACTTATCTTTTACCTATTAACAAATATGGACAACATCTAAACTTGTTCCTTATTTGCA +ATAGGATGATTATGCTGAATGGTCTCGGTATTTAAACGTTTGTTATCGGCTGGTACATGT +TCAATATGAATGTATGTCCGATTAATTTTATCAATCGATTGAGATTCCCAATCAAACGTA +ACACGTAACTTTCTATCTATCTGTTCACCTTTGTAATGAACTATCGGTTTAGCATCTATA +TCTGTTAATGTAATTGTTAATAAAGGTTCTTCATTAGACTGTGTATTACGTTTGTACTTT +CCTAGCTTCCACACATCTACAAAAGCACCGTTGCATTCCGGACAAACCGTTACTTCTTGA +TACTCTTTTTTAGATGGATGATTCACTCTATCTTGATGACCACACACTAAACATACAGCC +TTATTAAAATATCCCTTTCCCATATCCTCACTCCTTACTCTCTAAAAACTCATCAATCGC +TTTCCCTAGTAAACTGATCGTCGCTTCCCTACGTTCTTTAGGAGTGGTATTATCAAAGAG +ATCGTTATGGAGTGCACTTGCTTGCGCCAACTTCTGGGGATTAATATGCTCATTAACAAT +CTGCTCACCAAGCGTTGAAATACAATGTGTCATTACAGCTGCTAGCTCTTGTTTAGATAA +CTTCTTCAATCCTAATCACTCCTGTATTTTTTTCATTGTTTCTTCTGCTACCAATTCCAA +CACACCATTATCAATTTTCTCCACTAAATACTCGCCTTGTATCCCTAAATGCGGATACAC +CACTTTTATTTTATCGCCTTTTTGTATAGCTGTTCGGTTTAGCACATCTGCCTTCGTTTC +TACCTGAAGCACTTTATGTTCTAGATTTTCTAATCGTCTCGACAACTCTTGTACATCCAT +CGTCTAATAACCTCCAAAATCAAAAAGAGCAACCGTGCACCAGTTGCCCTTCTGCTAAAA +TTGTATGCTATCAATATAAATCATTTTTTCAACCGTTTCGATTCATTTTAGGAGTGAACC +TAAATGACACCTTCTCGCTCCACGAACTTAATTAATCTAACGAGTTCAGCATGTTTCTTT +TTGATATGACTAGAACTATAATTTACTGCCTCTGCTATTTCTTCTAACGTCATACCATCC +ACATATTTTAATTTGAGTATCTGATTTTCTAAACCTCTAAACTTACTAATTAACTTTTTT +AATTTATACATATCGTTCATCTTATGTGCTAATTCGTATTCAATCGCTTCAATGCGGTTT +TCAACTTTTGCACCTTCAGATTCTGCCGTTAAACGTACTTCTCTCAAATCACCACTCACC +CAGCGTCTTAATTCAGCTTTTGTCTTATCTAAGTTGTATTCCAGATAGGCTATGTCTTCT +TCTAACTTTTGGTAATCTCTCAGCCAGTTAAACAAATGATGATTCACCTACTTTCATATT +TCTAGATCAACAACCACATTTCTAATTGTCGATAGGTGTCAAAATATCTCGTTGTTTATT +GCTACAGCTTGTACATATGTTTTGCTATAATGGATTTACATTGCCATCTGGAAAAGTGAC +TTGTCCCCAACGAGTTGCTTTTCCTTTTTTATTTTATGATTCCTGATTTCACAAAAATAT +TTCTCCAAGCTGCAGCAGTCCGTTCTTTATCAATTTCCTTTTGACGATTCAAAAATGCTC +TTTTAACATGTTTTTTCTTCCAAGCCCTCATTTTTATACTTCCTTCCTTAACAAATTCAT +TCTAATTTCCGTGCAACGTGTATAACAGGCTTGTACGCTCGAATAAGAGTTTTTTCGCTA +ATAAGGTCTTATGATATTCAGAAAGTTGTTTCCGTCTCAAAATAAACAATCTGAGAAGTT +GATTTATTCGAACTTTTGTTCTTTACTAACATTTATCTCACTAACTTCGTTTATGATGAC +TCCTTTGTCTACTAAATCATCTTCAGTTCTTTTTAAGTGTTTAATCACATCAATAATCTT +TTCCGCTGACTCCGCTTCAATGACTGCTTCATATATTTTCAACTCTGTAAAAGTCACATT +AAAAGTTTTCATTCTTTCTACTCCCTTTCTCCAAAATAAAATTTTTAATAAGAAATTAGT +CATTCCACTTAAAACGGATGTAATGTTCGTAGTAAGATCCGCCTAAAATATTTTTCTTTT +CTTCTTCCTTAAATTCAACCTTCACACCGTCCAGTAATTCTTGTAACTTTTCTATAAATA +TTTTTGAACACATCATATGCCGATTTGGATTTTCATTATGAATCTTATATCTATGACCTG +AATATCCGCTTGCGGCACTTTTAGTTATTACGATTTCCATTTCTTCCGCAAATTCCAATA +CCTTTTCATCGATGGCTTTTTCTTGGAGTTCCTTTAAATTCCCTACTAGAGACATATCCA +TTCCCCCTTTTCAATAAAATGCAGTTTTTATTTAACTTTCTTGCATAACATTTTTACTTC +TGCTCATACTATGGTTGTAATTCGCAATTACAACAGCAACATTTGCTAAACACCGTTTTC +TTTTCTTAACAGGACAGCTAGCTAATCACGCTAGCTGTTTTATTTTATAAAATAGCGTTT +TGGTTTAAATTACTTATTTTTGTATTTCATCTCCACAAAATCAGCTAATTCAATTTTCTT +CTGCACTTCTTCTTCCAGATAATGAAATACCGCTTCTTCTCCACCTTGTTCTCTAACATA +AGAAACCCAATTTTTCTGCGAATCATCTAATTCAAGTTTTATTGTCGCTTTAACAATCAT +TTGAATTTCACTCCGATCTATAAAATAACGATTTTGTTTTAAATCCTCACATTCCTAAAA +AAACATACATACAGTATCATGAGGTATTCTTTTTTATTTTTCTTAAGGAGCGCTTTAAAA +AGCCCTCTTTAGTTTTTAAATAAGCATTTTGTTTAAAAATTAATAACATCCTCTTGCTTG +GTGCACTCTATACCTAAAAGGAGTAATCATGAAAATTTTAAAATACATAGCGCTGACAAT +TGGATGGCTTGCATTACTATCAATTTGGTATACAATATTCTTTCCTTAATCCCTGTTATA +GTTCTTGGTCTAAGAGCACCGCACTCTCCAACGGCGCTCTTTTTAATTCAAATAACTATT +TTGTAGTAATCCTTTATAAATCGCGCATAAACTTTTATAATCTTTATATAAAAATATTGA +AAATCATTTAATTATAGGGGGCGTTTTTTATGCTACAGGGCATTAACCATATTTGTTTTT +CTGTATCAAACTTGGAAAAATCTATTGAATTCTATCAAAAAAATACTTCAAGCAAAATTA +TTAGTAAAAGGTAGAAAATTAGCGTATTTTGATTTAAATGGATTATGGATTGCTTTAAAT +GTTGAAGAAGATATACCAAGAAATGAAATTAAGCAATCTTATACACATATGGCTTTCACT +GTAACTAATGAAGCATTAGACCATTTAAAAGAAGTATTAATTCAAAATGATGTTAATATT +TTACCTGGCCGAGAAAGAGATGAGAGAGACCAAAGATCTCTTTACTTTACAGATCCAGAT +GGCCATAAGTTTGAGTTCCACACTGGCACTTTGCAAAACCGGTTAGAGTACTATAAAGAA +GATAAAAAACATATGACTTTTTACATATAATAAGAAAGCTAGGGCTTTCTTATTTTTTAT +CAAATAACGCTTTTGTTTAGTTTTCTTTATATTCAATTTTGCTAGCATCTATCGTTTCAA +TATTTTCAATTGAACCAAAGCTAGGATGCTCATTTATTCCTTTTAGCCATTCTGTAACTA +CCTTATTAATTTGTTCTTGAAGCTTTTCCCCTTCGTCCATCGGCACACCTGAAAGCCAAT +ATTCCGCAACCTCTCCACATTCATCGGTTGCTCGTTCATACAATTCATCCAACAATACAT +CTGCATTGATCCATGGAGAATACTGTTTGAATTGTCCAATTTGGAATTCATTATCGACTG +CCGCTCTATCCGCTACCATTTTATCTGTCCAATCTTTTAAAGCTGCTTGAATAGCTTCTT +CTTTCATTTCAAATTTATCGCTTGTCCAAATCTCATTATTGCTATCAAGGTTGTACATCC +ATTTCATATCTTTCATTCCCCTTTTTTGCTTATTTATCTTTACATTTACAATCGTGCAAC +CACTCATCACACTTATTACAACAGCAATCGCAATTCTCTATTTTTCTATCACACTGACTG +CAATAATCTGTAACTTCATAAATCATTTATTCTCCCTCCCTGAAATAATACTTCTATTCA +GTTTTCTGCTTTCTTTTCCACTTATGAATCGCTTTAGATATCTCTTGTACAATGCTTCTT +ATCATTAATGGAAGCCATCCCAAAACAATGACTACCGCAAAAACAGGATATAAGAATAAC +GAACCCCAACTATCCGTTGCGATTATCCATATAAGTAATGCAACTCCAATCAATAGATAT +AAACCGATCGCTATTGCCCACCAACTTATTTCAATCACCCTCATTTCTTAACAAAATTCA +AATTGTATTAGTATCCATTACTTTGACGTTCATGATTGATTTTGTTTTTCTCAATGTACT +CATGTCCAATTTCTTCTAACGAAAAGCACAACAATTCCCCTAAACCAAGATAATGGGATA +AAAGAACATCTGCCCTAAATGCTGTCGGTTCTTCTTTTAATCGTATTGCTAGATGATACA +ATTCGAAAAATTGCTCTGTAACTGTCTCGCAACGCATAGAAGCAGGAAAGTTAATTTCTG +TTTTCAAATCTATGCAAAGTCCAATTGCAAAATGTAGTCCGTCCACATATTCCTCAAGTA +AAGGGTTTTTATAAACTTCTACTTCATAACCATCATCTAGTACTATGATTTCCCCTGTAG +GTATGCTAGTTCTCGGTTTACGATCGTCGCTCCAAAACTTAAATACTCGCCATTCCTTCA +TGCATTCGCCTAATTCATCTAAAAACGCTAGTATTCTAAATTCGAATACTTCTCCTCTAG +AAAGATTTTTTGACTCTAAAACTCTTTTATCCAAAATGTTCTGCATTGCAAATAACTTTT +TAATATCCATTACGAACACTCCTTTTTTTAAATCGATGACTGGGTAAAACGCCCATTCAC +TTTCTTTCGTTAAAAAAATGCAAGTTGTCCATCTGGCCGTTGTAATAACTTAACCTCTTC +TCTAGTTTTTTCTTCTATATGATGACTTTGAACTGGTACAAAATCGGTAAACCAATGTAG +CGGAAAACAGCCACAAAATTTCTTTCGCTCCCGATCATGCCAAAAGTAGCAATGTTTCCC +TCTCGGCTGTACGATGTAGTCTTTAAGTGGTTTATCTTTATACCCCTTTTTTCGCCAAAT +CAACTGAGCTCTATAGAATAAGCTTGTATTCAACTCAGGCAGATTCGGTTGAGGTTCTGG +TGTCCATACTTCCTTTTCCGTGATTTGAAACCTTTCAGCTTGATAACAACCAAAATGCGC +TCCTTTACGATTAAATCTGCTTACATAGTAATGACTTGGTTTAGCAGGGAATAAAAAGTA +CTCTACTTTCTCATGTAGCAAATCTGAGTGATCTACATCGATACAAACACCTTTTGTAAC +ACTCAATCTTGAAGCCCTCCTTCTTTACCAAATTGAGCAGCTCTTTGATTAATCTTTGCT +AATATACGGCTAATTTGTACCTGACTGTATCCCATTTGATTTGCAATGTTTTGTTGCGTC +ATATTTTGTAAACGCATATCTAAAACGATATATTCTTTAGGAGGCAATGCAGCTTTAAAT +TCTCTTATCACAGCTCGATTAATGGTTGTTTCTTCAATGTCTTCCGTTTTAGTATCCTCT +ATCATTCTTTCTAATGTCAGTTCTTCATTAGCTCCAGATGCATATACAACCTTATTGAGT +GAATCTGTGCTTGGTTGATACTCTAAAGCCGTCTTTACTAAAGATACTGACTCATCCAAA +ATGTCTGCTATTTCTTCTGGTTCTTTATCTGCTAACTGTTGATTTAAAATCTTTCCTTTT +ACGCCATATACGGTTCTTTGAACTTTTATTTTTTGGTTATCCCGAATTGCCCTTCCTATT +TCCCCAATAATTTTCGGAACAGCATACGTTGAAAACGCACATCCAAATTCAAGGTCAAAA +TTATCTCGCGCCTTTATCAAACCGATCATTCCGAATTGTGTTAAATCCTCAATATCTAAA +CCGGTATCACGCTCTATACTGGCCTTTTTTTTCGCATATCTTTTCCATACGCAATGATGT +ACAAGCCTTCCGTATTTCTCTATAAACTCATCATCTGACATTCCACGAACATTAACTACT +TCCTTAGCTTGTCCCTTTTCTTTAGTCATTTTTGCTCTCTCCTTTATCAAACTTAGGAAA +GTGCTTTTCTCTTAACTTATTTAATGCTGTTTTGAAATCAATATCAGACTGCAGCTTATT +ATCACTTAGCATTTCAAACAGATCATCCAAAAAGTTTTTTACCCTTTCATCTGTTTTAGA +TTTAATCAGCAGTTGTCTTAATAACACGTCAAATTCTTCCATTAATTTGGTGTTTTTCCC +CTTTACCTCTTTCATTTCTCCGCACCCCTTTTATTAGAATCCAATGTCTAAATTTACAAT +TCGTTTGTCAGTGGTTGTTTTAAAAACAATTGTTTCATCTTTCGATACACCGTTTAACAA +TCTACTTGCTAGTTTCGGATCGTATTTTTGAAATAATTGAGCGCTTGACAGATTTGAAGT +TGTAATTGTTGTTTTATTTGCTCCTTGCCGTCCATTTGTAACACCATAAAGTATTTTATG +AACAAAATCGCTTGCTTCTCCGTTTCGATTCATCGAACCACTTTCAGCTCCTAAATCATC +GATTACAAGGAAATCCACATCTACCATTAAACTGATACAATAATCCATTGTATATTTTGA +CTCTATATTTCTAAAAGAGTGCTGTATTAATCGAATTAGCTTTTCAATCTCTACAAATAA +GCAGCTTTTCATATTTTTAAAAGCATGTTCGTCATTTAATTTCTCACCGTCTGATATTAC +CCAATAGTGTTTAACTAATTCATACAGCATCGCATACGCTAAATGGCTTTTTCCTACTCC +TTGAATCCCTGCAATGTATACATTTAAAAACTCACCGTTTTTTATGCGTTCAAGAATTTT +TATAGCTTTTTCTTTGTTTTCTTTCGTTTCTTGACAATCCGTCTTGTATGTAGACAATCT +TGATTCTGTAATGGATTGATTTTCTATGATGCTGTGTTGAAAGAGTACATTTTTCTTCCG +TTCTCTATTAATCTTTTTATAATGATTATTTGCTTGTTGAAATAAAACTGAATTTTGCTC +TTCAACCATGCAGCGGGGACAATATACCGTTCCTGCATCATCAATCATTTTCCTAACTAA +TTTAATAACTTCTTTCCCATGTTTATTAAAGGTGTGCTTATCACATTGTTCATCTGCAAA +TTTTAACTTAGTAAGTTTTTCAAAAGAATCTTGTATCTTTTTCACATTTAGTACTCCTTT +CTAAAACGGCATTTCCCCCCTAAATCCAGGTATAACAATCTGATCTCCATGTTGTTGATT +GGATATGTTGACCGTTTCATTTAAGTAGTTGTCAAAATGTTTTTGTGCAAATAACGTGCT +CGGTCTTAAAAATTGATCTAGTGGTTTTCCATCAAAACTTTTCTTACCAAACCATTGCGT +AGTTTTGTTATCGATAACTTTTTTAAAGTCCTCTAGTTTATACCCCTCATTCCATCTAGC +GCGAATTAACTTTCTATGTCCTTCTGCTTTAGGATTGAAATTTTTATTTGCTTTTTCATT +CAAGTAATCCAATATATCTTTATACGGTATTGGATTGGACTTTGCGTCTGATTTTAAAGA +CGCTTTGGATTTTATTCTTGTTTTTTCTTCTTCTGGTTCTTTTTCTTCTTCTTTTTGTTT +TTCTTTTTCTTTTTCTTTTTCTTCTTGTTCTTCTTTTTGTTCTTTTTTTTGTTCTTTTTC +TTCTTCTTGGTCACGTATCGCTAACGTATCGTGGGACGTATCGTCAAAACCCGCATAAAG +ATTGATTTTTCTTTTTAAAGCTGCATGATCTGTATGTTCTAAAATGAATTTTATTAGAGA +TAAATCTTTCACTTTATCAATTTCTCTTTTAAGACAATCTTCAATTGGTTTCCCGCCTCT +ATTCAGGTTGTATTTGCCCCAATTTTTTATAGCAATTTCTCTTGTCAGTTTGTTATATTT +AATTAATTTATGATGGTTTTCAAAACGTTCCAATAGTGCTCTAGCCGACTCTATTGATAG +TCCGATTTCAAAAGCTATCATCTTAGGTGTGATTTCATATACTCCCAATTGAGTTGTATG +GGGATTAGTTAAAAGGTACACCATAAACAATTTGTCTTCTGGCGTCATATCTTCTGATAC +TTTTACGTCTGTCCAAAATTCTGTATGCACTTTTCTAAAAAGAGCCATAATAACACCCTT +TCCATACATCGAGTGTGTATGTTATATTTCTAATAAGTATATTTTTATAAGTATTTTTAT +TTAGTAACTTGTTGGCGCAAGTTACTTTCTTTGTTTATAAGCCTTAATAACATCAATCAT +TGAACTGGTTTTAAATATCTTGGTCTAGATTTTTTAACTTCTTGGATCTCACCAGTACGG +TCATTTGTAATATATTCTTTTCCACCCTTTTCTTTATGCTTCGTGTAAGTATCGATACCT +AATCGCTCGGCAAACTCTTCAGTTAACGTTTTTTTACCTTGCATTTTCTGCAATTTATTT +AAAATGCTTACAGAGGCTAAGTTAAATAGTGTTATATCTTTAAAGTTTTGGTAATCCCAT +AAAAACTCCATGATTTTCTCTCCAATAGGTGTATCCATTCCGATTTTTTTAATTTCATTC +ATGGTAAAAAAGTAATCTTTCATTTCATAACGAGCGCCATCATAATTTTTATCGATTGGG +AATATGGTCATAAAATCCCTAGGCGTCAACACCTTCATCAAATTTTCTAAATAGCTTATT +AAAAGAAATCTATTCATTAGGTAGTCATAATTCAAACTGTCATTTTTTGATATTGAAATG +TATCTAACTCCATAAAAAATTGCTTTTTTATACGTATCCTTGCTTAATGATCTCGTTTCC +TCATCCTGTTTCTTTAACTCATTAACTGCATTCATAAATGCTCCAAGGTATATCTCAACA +TAATCTGGCTTATCCACTTTTTCTCCCTCAATAACACGTAACTGGTCCATTGTCTTTTCC +ACCTTTTCTTTAAATTTTTAACTTAGAAAAAAACCGGTTGAGAATGTTTTAACTAACTAC +ATTTCTGTAAAATCCATTTGTGCATTTACAAAAGAAATCTCTTCGCTCAATACAATTGGA +AGTGTATATTCTTCAACTATTTTTACTGCTACATTTAAGTGACAACGTTTAATTGCTTTG +TGACTTTTCACTCCGAATTCACGGTATAGTTGGTTGTAGATATCACGATAAACTTTCCCT +CTTAATCCACGATTTCGATAGGCATTAGACTGTTTTCCACCTAACAATATGACTCCTTGA +CGTTTTACAGCTGTAGAGATTTCATCACATTCAATTGCAAATAATGGTGTATTTTCTCTC +AAGTCTTGTACATCCGACTTTATCTCTTCGATTGCTTGCTGCTGGCCTTCTAATGCTTCG +AATGTAAGTTTTAAAATACTCATTGGATCTGTAGCCACTTGATTCTTTTCTCTCATGTTG +AAGTACTCATCAACTAATATGTCGTATAATTCCCAAGCTTTATCATCTTCGAGAATTTTT +AATAGTTTTGCGTAACCTCGTTCTGATAGAAGGTAGATGTTATTTGATTTCGCTATCTGC +ATATTTGAGAAACCAAGGTTTAATAATTGTGGTGGGTTAAAGCCACCACTTTTCAAATCA +ACAATATCCACACCATCTTTAAATCGAATGCGATTATCATTAATGCGACGATTGATTTCT +TTTAATGGTTGGTTATGAATTGTAGCTATATCCAAAACCAACATTGCTTTTTTACCTTCA +CCAAATCCTCCCTCGATTCCAGTAAATTCATATCCAGCTACTTTTCTTCTCCCTAAAAGA +CGTAATTCACTTGCTACTGTTAACTGATCCATCTTATTCCCTCCTAAACTTATAAACTTG +GAATTACACGAGTTGTGCTAGTATAACGGTGTACTAAATGCATTTCTCCATCCGCTTTCT +TGAAAACCAACCAATTATCAGGATTTAAGCTATATGATTTAAGATGCATTTTTTCACGTT +TAGTCAACCTTTTCCCGTTTTTCATTCATTTCTCTCCTTTCAGGCTTGTCCATTTTATAA +TCGACTTCATTGAATGTTCTCACTGAAGTTTAAAGATTAGCTGGCTGCACTATTGCGTTT +AGTCCCTAATTCCTTTTTAACAACCTTAACTTCAACCCCATAAAATGACTCATATGCTTC +TTTAAACACTTCTTCGATATTTCTTTCGCCATAAGTTTCCTTGATGATAAACCCTTTGTA +ATAAATTTCTGACATGGCCCTCTCACCCCTATGTTCCCTCAGGGAATATTGGTATTAAAA +AAAATCGACTTGCTCTTCAAACAAATCAACTACACTTGCATTTAATACATGCGCCATTCT +GGATGCTAAGTTATACGATATTTTCTTTTTGTAATTATGATTGTTAATTAGCTTGTAACA +GTAGCTGCAGGATATTTCTAATTCGTCAGCTAACTCTTGATACTTATACCCAGATTTTTT +GAATGCAGCTTTTAATTTTGTCTCGTCTTTAATTACTTTCATGTGGTAACTCCTTTCTAT +ATCTTTGTAAATCACCTTAACATTCCCTTAGGGAAAATTCAAGATATATTTTTACACATA +TTTTATATTATTCTTAGAAATAACTCGGATTGATTTTCCCTTTAGGAAATATTATAATAA +TCCTAACAAACCACTTATGAGGTGATTATTGTGGAATTTAAAGATCGGTTACGTCAATTA +CGAAGAGAACGGAATTTAACACAACATGATCTTGGACAAGCTATCGGTGTTACTGCAGGT +AGTATCACAGTAACTAATAACCAACTTTAAAACTATAAAGAAAATGTATATTCGATGTCG +ATATACTTATCCTTACTAAGTGTGATTTTCTTTATTAAAGTTTTAAAAACCTCATGCATA +TCTTTTTCTTCATCGAGCATTGAAAAAGCTTCTTTAATTTTTTTCTCTTCTTTATTTCTC +TTATTCTGATCTGTTAATTTAAGTAATGCCAACTCTTGCTCTTTAATTTCATTCTCGAAA +TTAAGATCCCGCTTCGAAAACATTTCTTTATCGATTAATCCTTCTACGTATAAATCAATC +AACTTCTCTTTTTTCACTTTTAACAACTTAATTTGCTTCTTAATTTCTGTAGATTTATCA +TTTCTTTTTTGATGCATTTTTGGATTGAAATGTATCTCTAGTTCTTTTTCTTGCTGCTTC +AATCCATAGATAATCGCCTCTCTTATATCATCATAATGAGCCGGGTCAAAGTTAACGCAG +CGATTGAATCTAATATAATTACTGCATTTCATATATACCCACTCTTTTTTACTTCCTTTT +GCGTATCTACCTGAATACTTAGCTGTAATTGGCTCACCACAATGTTTACAAAACATCATT +CCTCTAAATTCATTTCTTGTATCTTGTTTTGTTTTCTTTTTACTTGCCCTATCGCTATTT +ACCGCATTCCATAATTCTTTTGATACAATTGTTGGATAATGGTCTTCTATAATTGTTAAT +CTCTCTTTCGGAGTGTAAACTCTTTTCTTCTTTCCATCTACTTTTACTGTTTTATAACTA +TTTAAGACCAAATTCCCTTTATACGTCTGGTTCTTTAAAATCTTCCCTACAGTTGTATGC +GACCATAACTGGCCAAACTTCGTATATGTGCCTTTATCGTTTAGGATATTCGCTATTTTC +TTAAATCCATAGCCTTTATAGGATAAATCAAAAATTTCCCTTACAATTTCAGCTTCCTTT +TCATTGATAACAAGTTTCTTGTCAATTACATCGTATCCTAATCCCGGTTTTCCAATAAAC +TCGCCTCTTCTTGCTTTAGCTTGCATTGCAGCAGAAACAGATACAGATATAGTTTTAGGT +AATTGTGCAGCAAACATGGCAAACATTTCGAATTTAATATCATTGCCACCTTCATATAAA +CTATCGTAATTTTCTTCAATTGTAACCAAGCGTATCCCATGACCTATTAGAATTTCTTTA +ATTTCTAAGGCATCCCTTAGATCCCTTGCTAAACGGTGTATAGATTTAAATACGACTGTA +TCCAATTCATTTCGTCTTGCTTTTTCTAATATTAGTTGCATCGCATGACGTTCTAACCAA +GCTGTACCAGAAATACCATCGTCAAAATATACTGCATTTGGATCCCACTCATATCCGTTT +TTTTCTAACCAATATCGACAAATATCAATCTGATTTTCAACAGATGAAACTTGCTCATCT +CTATCCGTTGAAACTCGTACATAAACAGCGTATTTCAAAATTTTCACCCACTTATTTACT +AAGAATATGATAATTAAATTATATATATATTTTTCCCTGTGGGCAATTTTATATTATTCA +TTTAACCAATCGAACAATAATCCTCGACATTCTTTCCTTCTCTCCATTACAAATTTACTT +TCAACAATTCTATAAAAATAACCTTCAAAAGTACTTCTAATTTTATTTGCTTTTTCTGCG +AAGACAGTTTCTTTGAATGCTTGAATGGCTTGATTTATCACTTGTTCAATAGGCTTGTCT +ATTTTTGAACGTTTATAAGCTATTAATACTCGATGATACAATTTATAAATTTTATCTGCT +GATTTGAAGAATGGAGCTACCACATCTCTGAATTGGCTTGGTACATTTTCTGGTGTAAAA +GTTTCATCTAGATCCTCTAATTCGATTTCTTTAGATTCCCTTGCTGACGTTTCTTTTACG +TTTAATTCGCTTTTCAATTCTTCTAGAGGGTGTGATTCAGAAAGTTTAGCTTCCTTGTCC +GTTTTTGTATCTGAAACCTTTGATTCTGTAAGGTTTTCTTCATCTTGTCGCTGTGACATT +TTCGGTAGGACATTCGGTGTGACACTATATTTTTTTAGAAGGACATAGACGTTATGTCCG +TTCCCTCCACGTAATTTTCCTTCCGTTCGAATTGTTTTATGTCTAGTTACTACTTCAAAA +TCCTCTAATACTTTTAGTACCCTGCGAACAGTTCGATCACTTATATTTAATGCCTCCGCA +ATTGTCCCTACCTTCAAGAAAGAGACACCTGGGATTTTACAAGAGTGCCTTGCTAGAAAT +TTCAATACTTTTATTGCTGATTCGGATAATTCATGTGTATGTTTGTATAAAAAAGAACAA +ATCGCTTCATTCATCTCTTCTACTGATCGGAATGATTGTAATTTTTTATATTGCGTATAG +TTTGCTGAGCTAAGCATTTTCTCCCCTCCTTATATAAGAGCAATAATCATATCGATTAAA +AATAAAATCGTAGATATACTGAAGAAACCATAAAACCAAATGCAATCTGATTTACTTTCT +AAACCAAAATAATCATTTACTCGATTCATAATTGTTCCTCCTTTTAAGTTGAATTATAAC +TCTCTAATTATTCAACGTCAATAGTTGAACGAAAAAAGTTTTACTAATTTCGATTGATGT +TGTAAAATGAGTACAAGATAACCAGTGCTGCGGAGGAGAATAAAATGAAATTCACACTCG +GAAATTCTTTAGATGAATTGGGGATCACTAAAAATAAATTATCTACAGAATCCCAAGTAA +GATACAACACGATTAGTGATTTAGTGAATGGTAATGCTAATGCTGTTCGTTTTGATTCGC +TTGAAGCTATCATTGATGCTTTAAATGCCATTGCTGCAGAAAAAGGAATTAATAAAATTT +ACAAAATAGACGACGTAATACAATACATAAAAAAGAGCTAATCATTCGAAAATGATCAGC +TCTTTTTTTCATCATTAAGTAGTAGCGATTACATATACTTTTACAAACACATTATATTTA +TTTGCCAGTTCTTCTAATTTCTTTTCTCTATATTTTGTGATTGTAAAGAAATGAATAACT +GGCACTTTCCCGTTATGCTTCTGTTTATAAATCTGCGTTAACTCCTCATATTTTTTTAAT +TTTTCATCGTTCACTATCATTTTCTGAGTACGATCTATTTCTACAGCATGAAGTATTCTG +TCCTCATCACGAAATTTCACATCTGGAATTATTTTTTTCTTTTTATTATCCTTTATATAT +TTAATTTCAGTTTCTACTTGCCAATCATCAGGACAATATAAATTTAACCAAGCTTCATTA +CGTAAAAGAGCGTGTGTAACTTTACCATGATGTACAACTTTCCCTTCGCCAAACAACTTA +TGTCCTGATTGGTTTAAATAATATACATGCTCTTTATTGTAAACTACCTTACTTGTATAA +ATAGATAAATCTTTCAGAATTCGATTTGCATTTCTTATTCCACCCATTTCATGAATACTC +ATTAAATGCCTTCTCGTTGCAAACTGTAGCTTTCTAATCGTCGCAAGTATCGCCATTTGA +CGGTTGATTTGCATATGCGTTTGCATCCTCATGTTTCTCCACCTCATATCCTTTTAAATG +CTCCCACATCATCTCATTACTAATGTAAGGCACTTGTATTTCTGTAAGTCTATCGGTTTT +GAAAATCGCGCGTCCGGGAATGCTTTTTATCGTTTCTAATCCCGCTTCATCTATAACAAC +ACTTGATGCTGTTTGAGTCGGTAATCTAAAGCCTAATTTCGCATCACTATTTTGTTTTAC +TTGGCGCGGTAATGTATCCCCTGTCGGGTACTGTGTACAAAAAATCAATCTAAAACCTAA +AGCACCACCTATGCGCGCTATATGAGAGAGCATTTGTTGACACGCTCCTAATAACCTTTG +CTGTTCTTTTTTCATACTTTTATCTGGGCAAAGTTCGGCTCCTTCGTCTACTATTATGAA +GTAACGCTCTTTGATATTTGTTTCTACAACATTCGTATAATGTCTACATTTCATATATTC +CATTTTCTCTTCCATCTTCTTGAGGATATTAGTTAATATCATAAAAGCTTCTGCGGGCTT +TTCAGCAATAGAAACTACCTGTTTTAAATTCTTATACGGCCCAAACTCCAAGCCCCCTTT +TAAATCAATAATGTATAAATTAATATGTTCTGGTTGTGCTAAAGTAAGAGAAGTAACTAC +ATTTTTTAAAAATACCGTTTTTCCCATCCGTGTCAGACCACCTAGTGTCATATGTGGTGT +TTTATCAAAATCATGATAGATAAGTTTTTCTAAACTTTGGCCCATTGGAACACACCAGCT +TCCTTCTGCAACCAAACCTTTAGACCATGACCATTTTTTCGGTATATCCCTATGAAACAC +ACGAATATTTAGCTTGTAATTATCATAATCAATTCGGACAGGTTTACTTAGCCCTTCAGA +GACAACATCCTCGACCTTCTGAATAATTTTACTCGGCATTCCTACAGGCAACCGATATAT +ATAAGTTGTACTTCGGTCATCCTCTTTTTGTTCAAGAAAAACTGGATACTGTAATTTGTC +CTCTCTACGTATCGCAATTCCGCTTACTTCAAAAAAAACTTGTATTTTCTTTCGATCACT +CTCTCTTCCTTTGAGCCTTTCGCCAACTATGGCGAAAATTAAACCTGCGAATGGTACTGA +TAACAACTCCAGCATAAAATCACTCCTTATATCCCTCTTATAGAGGGTATATATCCCTGT +TTCAAGGAATACGTGCATACAAGCTAAACTCCTTATGACATAAGGAATGAAAAGTTTCCA +CATCGTATTCCTTCATAGAAATAAAACGAGAACATAACGTAGAAGGTATAGAAACGAGCC +TGTAAGTGTTGTGTACAAAGTGACACGTGGAAGCCAATGTGGAACACTTTTCCCCATTTT +TTCTGCTGCCTTCATTGCAACTACTGACAACCCTGTTGCCGTCCAAATAATAATCGCTTC +TCCAGCAAGAGTCATGCTTGTTCCTCCTCTTCTTTTTCACGAAATGCAATACCTTTTCTT +GTAAGAACTACATCATAACAATCCATTAGAATTTCCCAGTTTAAAACATCTTCTTCCTCT +CCATATAGATCTTCTTCTAATACCTGTGACAAACTGAAATATCCTTTATATTCTTTTCGA +TCATAAACTTCATGATTTTTCATGTGATTTAAAATTGATTCCGTCTCTGCTCTTGATCTC +GATCCATTGTACATTGAACATAATTCTTTGGATGGATGAAGATATGGAGTTGTATTCAAG +TGATTATACTGCCAACGCATGTAATCCTCTCCCCTCTTGATGTCCTTAGTTCCACTTGGT +ATTCCTCGTGGTCTTGATATAGGTATATGACTTAGAAAGAGTTATATTGCCTGTCCATTT +AAACTTTTCTAAATGTTCGTTGATTAAATTAAAGGAGGACACATTTCCATATGCGAATTG +TATATAATTAAAGAGGTGATATTGTGCGATTAAAATGTAAACTTCGTGTTATTTTTGCTG +AAAGAGAAATACGTCAAAAGGAGTTTTCAAAACTTATTGGAATTAGTCAAACTACAATGA +GTTCACTCGTTAATAACACGACGCTACCTACCTTTCTTACAGCCTATAAAATTGCAAAGG +AATTAAAATTGCACATGGAAGAAATTTGGATAGAGGAGGAGAATGAAAATGTATAAAAAA +CTTATAAGTATTTGCATTGGAAGTACCTTATTGTTAGGTCTAACAGCTTGTGATTCTTCT +AAACAAAGTGAATCAAGTGAAAAAACGAACGTCAAATCTCAACCAGAAACTAAAAAAGAT +TTAACATCTCAGGATGAGTTAAATAAGAAGATAAAGCAAGATGCTGAAGAAGTTAGTTTT +GTTAAGGCAAATGGAGATCAATACGAAAAAGGAAAAAGGCTTAAAGCTACCGGAACGGTA +GATTTATTACTTAAGTCTTCAGCATTACCTTCATTTGTCATAAGCACAAACGAAAATGAC +GGCAAAGGCATGTACACTATTCAAATTGTCCAAAGTGGAGTGCAAACGAACGAAAATGAA +ATAACACTTAAAAACGGATTAAAAATATCTAAAGGATCAATAGTAACAATCTATGGCGCC +TACGACGAAAAAGATAAAACAGGAATGCCTAAAATTAGTGCAACAGTAATTGAGCAATAA +AAAAAAGCCGCCCAACAGGACGGCTCTTATTTTTGTTCATAAAACTATTCTTTTGTTTTA +TTTAACTTCATACCACCAACCTTTACGGTCAAGGTATTCTTTCATTGCTTTTAGTTGTGC +ATCTGAAGTCGGTTTGGAAATAAAATAAGTTAATCCATCCGATTGTAAGATAAAATCAGC +TGTCATTTTAAGTGACGTTAATGCTCCCATAACATCAGGGGTTTCATACGGTGAGAAAGC +CCCTGATTGGATGATGTTTTGTTTTGTTGGTGAAGTAGTCGCCACATTCCCATTCTTAAC +CTTCTGAATGAATGCTCCCCACCTTCCCTCAGCTAACATTCTATGCGGACAATATTTACC +TGACCAGGATTGATGAGTTCGAACATTTTCAATCGGAATATTGTACATAGACATAAGTTG +TCGTACAACATCAACAGCATTATCCTCAGCTTTATAGTATCTATCTCCTCCTGATTTTGA +ATAACAGATTTCTACAGAAATGGATTGACGATTCCCCGAACCATTGCCGTCTCCGCAAGC +CCATGCATTACGTTCCAACGGAATACCTTGAATCGCTTTCTTGTCATCTACTGCAATATG +AAACGACACCTCATTATTGTTACTAATCATGTAACTCACTTCATTTTCAGCTGGAGCATC +ATTATATGTGTTGTGAACAGTGATATATTTAGGCTTCATTGTATACGGACACTTTGTACC +ATACTTACTTGGATCAACTAATTTTTTTTGGATTTCCATTACTGAACATCTCCTTTTTTC +TCTTCTTGTTTTTGTTTACCACCTAAAATCTCAACTGCATTTGTTAATGCTTGTGGGAGT +GGAATACCCATTCGCCCGGCATTTTCTAAGAGTGAAAGTAATTCATTACCCATGAAGAAG +AAAATTGTTGCTTCACGGATTGCACTGTTGCTTCCAAGTGCCGAGTCTAGTTGAGCGGCC +GCTCCGACCAAAAGAAAAAGCACCACCTTTTTGGCGATGCCTTTGAAACCAACTTTGCTT +TTTAATTCTCCGTTATACCCTGCTGCAATCATGCCAGTTAAATAATCAATAACTACCATT +GTCACTAAGATTTTCAATGTTGCATCCCATCCTCCCAAGAAATACCCACAGAAGCCACCA +AACGCAGCTATAAATGCTTTTAGTAATACATCAATACGATCCATCTTTTCCTCTCCTTTT +TGGCCAAAATAAAAAGACCAGCCTATGGCTGCTCTGGTTTCTTATTTATTAATTGTTGTA +GTAATAATTCTTCTAATCGTGCTATCCGATCTTCTTGACTAGCTATTTGTGATTTTAGAT +TTGCTATTTCTACCTCCTGTTCCTGTACTGTTGCATCAACTTCTTGTAAACCTTTAATTC +CAATGGATGCGTATGAGTACAAATGAATTCCTTTCCCACTTTCATCCACAAACATTTCAT +CACATTCATCTACGATTAAACCGTAGTATGTTTTAATATCTTCTGTTGTCAATGGTGGAT +CATTGGGACTTTTCTCTTCTCTCATCCGGTATAGTTCGTTTACAGCATTCTTATAATTAA +ATTGTCTAATTTTAAGACTTCTAATTTTTTCTAAGGCGGAAAAAGAAATATCACGGATAT +TAGATTTATACTCCCGTAATGAAGGAGTCATAAAATTCCCTTGAACAGCACCCCATCCAT +TTTGAGTAACAGGGGATTTCAATTGAATAACTCCTGTATATCCTGCTGCACGGCTATTAC +GTATAGTTACATTAGGTAATCTTAAATCAGAATCTGTACTATTATCTTCAACGACTAACG +AAGTTTGATACAACCCTGGTTTCCCTCTTCTGAAATACCAATTTCCATTTCCAGCGTAAA +AAACATGGTAATCATTAGCGTTTAGAACACTTAGTCCGTTTCTTTGCAACTCCCAATACA +CAGACTTTTGGACTGCACCATCAACTATGCCATTGCTAATACCAATGCTCGCATAAGCCC +CTGACCATCCTGCACCTGCTTGAGACATAAACAAAGTACCTTCCGGAGCGTTAGTCTTTT +CATCTGAACCTAAGATGAAAGTCGGTTGTACTGCACCATCTGATCTTCTGTAATGCCCCA +GAAATGCTCTAGCAACTCCTCTTTCATAGAGACGTATAAATTGATCATCTAAACTAACAT +AGTTATCCGTATTTGATGTTCTAATTTGGCAACCGCTCAGCAATCCAGCTTTAATCCACT +CCGCATTAACTTTACCAACTAAATCTATTCGTGCAGCATTTAACTTAATGTTTTCTTTAC +TCATGTTAATGGCTGCTATTACATCATTTTCTTTTACAGATATACTAACGCCCTTTTCAG +TTAACTGAAGACGAGTTTCCATATCTCTTACATAAGAACCTGTAGCGAATTGTCCATCTG +CTTGCGTTTTCGTATATACTTCTGTCTTTTTTGCTGCTGCATTGATACCCTGTTCATTAA +TAGTAAAACGATTATCAATCAGAGTCATTTTCTGATTAAATTGCTCAGTTGCAAGCTTAT +TGGCTAATTCATCTAATAAATCTTGTTTATTCTGATTAACTGTTTGCTTCAACTCTGGAA +TCTTAAACCCCGCAACATAATCCTCTACTTGTTTAAGCTCAACTTTACCTTCAAGTGCTT +TTGCAGTATTTTCCCATCCAGCTTTTGCCTCTTGTAATTGCCTTCCTTGTTCTGTCTGCG +TATTTTGTATTAAAGAGACATTTTGTTTAATGGCAGTTGCATCTTTTTCTACAGTAGCAA +CACGCTTATCAAATCCACTTTGATTATTTTCTACTTTTGTTATCGTTTCTTTGATACCAT +CTACACTTTTTGTAATTTCAATGGTTTTCTTGGTGAATTCATCGGTTGTTACCTGTTCTT +CAGGCGCTGGCGTCCAATCCTGTGGCTTATTCCCTTTATACAAGGCAACCCATTCTACAA +TTGCCTTTGTAGTATTACTTGGATAGTTATATAAACTTAACTTTCTTTCATTTCCACTTG +TAGTTGCAACAGCTTTAAAGGTTACATACGTTATTCCATTAGCATAAACACTTGTTGCAT +ATCCAACATTGCTAGACCCGCCATTCTGCCAAATCCCAAATTTCTGACCTTGTGGGACGC +TTCCCTTAATTACAAAGGTATATTCCTCACCCGCAAAGAAGTTTTCAGTTAGAGAATATT +GATTGATTAGGTAATCTGTTTTTTCATATTTAACATTTGAACCTAATAAAAGGTTACGCC +CTCCAGCTTTATCACTATTAACCTTTGTTTCTACACTCATTAACTTCTCACTGATTTTCC +CAGCTTCTTCTTTAATTTCAGTTGTTGTTTTCTTAAGATCACTTGTTGTTTGCTGTACAT +CGGAAATTGTCTTTTTTGTGCCTTCTACAGTAGATTCAATAGTGTTAACTTTTTCAGTAA +TCTGACCGTCTTTTTTTGTTAACTCTTCAATGGACTGTTTAAATCCACTAGAATCCTGTT +CAAACTTAGTTACCTTCTTATCGATTTCACCTTGTTTGTTCTCAACGTTTGTAATCGTAC +GACTAACGCCTTGTAAACTCTCTTTCACTTCATTGAATTGACCAGTCGCTTGGTTCTGTG +CTTCTTGAACCTTTTGATTTAACTCTGTTTTTGTGGACTCAATATCTTTATTAACCTGAT +CTAATGTTTCTTTTTTTACAGATTCAACATCGGGTACAACTGATTCCCACGCTGTACCTG +TCCATATTTTTAAAATACCGGGCTTTCCGTTACTAATATCACGCCAAAGCGTTTTAAAAG +GTTTCAGTCCTGTTGTCGGTGGATTCTTGGATTCTATAATTTCAACGGTATTATTTTTAA +TATTCTCTTGTACTTTTTCAGCTAGTGCTTTTGCTGCTTCTGACTCCTTCTTTGCATTAC +TAGCGGTTTCGTTAGCTTCGTTCACTAGTTTATCTAGCTGGTCTATCATTTCTTGTTTAT +TGCCAAGCGAACTAAGAATACGATTGTAAATTTTTCTTAATTCCTCATTTTGATTAACAA +TCTCACGATAATCTCCGAATTCATATTTATCTTGCGTTGGGTCTGTAAAAGATTCATCTC +CAGCTATTACTCGCGCTTCAAGATATAATTCTGGTGTAAACCCTGTATCTTTAATTTTGA +TCGTGTCGCCTTCGTTAATTAATTCGTGTTCTAGGCCGAAAATACGACCAATTGATTGTG +CTTCCACTTCATAAGAGATTGAGGAATTGACACGCTTTTTCAATTCTATTTCCATAAGCG +TCAGTAAACGTTTTGGAGTCATGTCTAATTCTTCTGTTTCTGGTGTATAAAAACCGAATT +TATGTTGTCCGTGTTCATTCCATCTTTGAAATGCATCTGCATCTACGATATAGGGTAGAC +CTTTATTAATACTTTCAATAGTGATTACCTTGTCACCTTCACCTTTTACAAATCCAACTA +AAGCAGTGCAAATATTACGTGTATGTTCAATACGCGTAACACCGACTAAATCTTTTCCTA +ATTCTATTTCTTTGCCTGTATCATGCCCGCGTTTTTGAATCATATCTACATACCAACCGA +TGATTTTTGAACCTTTAATCTCAACACGATATCGAATTTCCAGTTTAAATAAAGATGCAA +TCTTCTTTAAAAAAGTGAGTGAGTCCATATATTCATCGATGGTCATTGTATGAAATCCAG +CATATTCAGTAACTCCACGCTGCCACTTCATACCTAAGAGTGCTAAATCCATAAATTCGT +TGACCGTCTTACTCTCTATCCGTTGTGGTTTTATGACCCCTGATTTAGCAATTTGAATCC +AAGCTCCTGAAGCGTATGTGGTAATGGATCGTTTATCGGAATTTTTTTCAGTCTCTGTAA +TAACATACGGTACGATTCTTCCATCGCGAACTTCTTTTAAAACAAGATTCTGTTGTTGTA +ACGTAACTGCATGGTCTGTTCCATCAAAAGCGGTGAAATCCAACATGTCAATGTTATTTT +TTAGTTCCCAATGCCGTTTGTCATCCCAATAGTCCTCTGGCTGGATAGCTGCGACGATTT +GATCCGTTTTAAAATCCACAACATGCAAAATCCCGCTTGGTGTTCTCATCTATATCTCTC +CCTATAACTGATTGTTGCATTTACATCAGGTGGCATTATATCGATACGATTTTCACCACG +TATTACGATAGGAAAATTACTAAAGATTTCTTTTATATTGATTGCTTTCTCCCCATTGAT +CGTGACAAGACTTTTCTCAGTATCGATAACAATTTTATCTCCAGTATCAAAGATATATGG +TTGTGCATTAGATGGAACTTTGTTTACCTTCCAAATTTTTAAATCATCAATTTGCATTTC +GTTAATAGGTTGATGATTATCCCACTTGCAAATCGCAATCATAACTTGTGCAATTTTACG +TTCTGTCATCGGATTTCCTGTTTCATCAATCCAACGTTCTACAAGTGAAGCTCCATCTTT +TTCTGTACCATCTATAAATTTAGCCACATATACAGACCACACCTTCCCCCGCCTAGCAAT +ACGTAAACGCCCTCGGAATTGGTTAAATGTTGTCGAATAAAATCCACTTGTATCAACTAA +TTTTCGAAAACTATTGGGTGTTCCGCTATTTCCAATTGTCATATGCGCCCTTGTAATTTC +AGCGGTCGCATATAGATCATTCATATTGATGCGGGATATCACGTTACTCGTCTCATCTAA +AAGAAGAACTTCAACACGTCCCATTTCGCTTATGTTTTTGGACTTTAAAGTCACCCATGC +CTCCATTTCGAAGTCTTGTAATGGGCCGCCCGGAATGTTTTTCTTGGCTATAGCACCGTA +GAATCCTGTCTCTTTTCCGTAATCTTCACAATATAGTGCATGACCACCTCTTGATTTAAA +ACTACCTGTCCCTTTCATCTCCTCGAATTGTCCAGTAACAGGTGTCCATCCTATAGGAGT +AGCCATTTCATCCCACATGACTCTTTCTCGTTCTTGTACCGTGGTTTCTTCCACAGTCAG +AGGGTAGCCTATTCTGAAATAATCACGATTATGCGGATACTCTCCAAACCATACATCTAA +AAAGGTACTTGGTTTTTTCACTGTCATTTCAATTAATGCTGGAGCTTCTACACTTCCTTT +ATTAGTAAAATAAGAAGTTGTTTCTGTAGACCACTCTTGCGTAAATTTGTGAGTATTGAT +TTTCCCTAATTTATACGGCATTGGACAAACAAAAGTAATAACACCTTTACCTCTATTGAC +TATTTCGTCCAAATCGACAGAACCATCAATTAATGATAAATAAGTCCTGTCTAACTCATC +ATCAAAAATAAGTTCAGCAGGTTGCTCTGTATATAACCAATCCGCTAAATCTTCTTTTAA +CTTTTGTAAATCTGCCATATCTTTTTTCGCTTTAATAACAAGAGGAACGTCAATACGACG +TTCCTCCGTTTCTGTATTAAGTAAAAGAGCCCCTGCGCGATGAGGGACTCTTACTAATCT +TCTTTTTACTGGAGCCCATGAAGGACGTTTTCTTCCAACTAGCATTTGAATATAATCTTT +TCTAATATTATTAAAAGTAAAACTAAGTTTCCCCAACGTGCTCACCACCCTTAAAATTCC +GCTCTTCTTTTTTGTTCACGATTTTGAAGTTTTGTAGTATAGGTGTAACTTCCGTTTGCA +AGCTCTTTTCCATCTAAAACATTAGTCATGTTTACGGTTAAATTCAGTTCTTGTTCTCCA +CCTGGTCTATTTGGGAATATTGTTTTTGCCATAGATGGATTGTTATAAGATAATTGCGGT +TGCATATATCCACTGAAATCGCTAAATGTATTTTGCGGGATACTATATTGATTTGTTTGG +AATCCAAAATCAAAAACAGATGGCATATTCCCCATTTGTTTCTTAACAGTTCCGACTACA +TTTTTTGCTGCATCCACAACAAATCGTTTTCCCTTATCCATACCAACCCCAACACCTTCT +GGAACTGCGCTACCGACTGGAATCATCACTTTAGACGGACTGTTAATTTCTAATGCTCCA +GAAATAGTCTTCTTAATATCACTTGCAATTTCCGCAGCCTTACTAAACAGACCTCCTGAA +GCGTCATCTATTCCCTTGCCAAGCCCTTCTATGATTGATTTACCGATGGAACGTAAATTT +ATAGAACTGAAAAACTTTTCAACTGTATTCCACTTATCTTCAATACTACTTTTTATTTCT +GACATCTTATCAGTAACAGCTTTTTTCTGCTCTTCAAATTTTCTTGAAACTGTATTTTTT +ATCTCCTCTACTTTGTTGCTTGCAGAGTTTTTCATATCTTCATATTTGTTGGTAACGTCC +GACCACATTTCTTTCATTTTTCGAATAACATCGTCTTTCATAGCTTGATATTTCGATTTT +ACTTGGCCAGTTTCCCAATCTACCTGATTTGCATGTTCACCAGCTTGCGCTTTTGCTTCA +CTCACAATTTCTTTATGTTTATCTCGAGCTGTAGAAACTGTACTATCATATTGACGTTTT +GCCTCTGCAATGATTGCGTTCGCTTCATCAGCAGTGATTGTTTTATTTTCATCACGTTGG +CGAATCGCCTCTGCAATTTTTTCATCACGGGTCTTTTTCGCATCTTCAATAACTTTATCT +CTTGCTTTGGCGCTATTCTCTACAACTTCCGCTGCCTGTCTAGCTGAAATTTCACTAGCC +TGCACACGCATATTTTCAAGAATAACCTTCTGCTCCATTTGATTTTTAGACATATGCTCA +ACAGCAACTCTGTCCATTTCATCCTGCAATGCTTGTAAAGAGATACGTTCGGATGTCGTT +AATTCTCTGTTTTCTCTAGCCGCTGTTTGTAAGATCTCTTTAATTTTATTTTCTTTTTCT +TGCGTTTTTAGCTTTTCTTGTTCATAGTGCTGATTTAACTGTTCGATTCGTTTGTTCTCT +TCTTCAGCGGTTAATACATACGAATCAGCAAAGAACTTTTTAAGCCCTTCAATTTCTTTT +TGCTGCCTTGCGTTGGTTTTTTCAATGATTGTATTAGCTAATTTGTCATATTGACCAATC +AACTTTTGCGACTGTTCTTCTGTTATTACTTCATGGTTCAATCTAATTTCAGTTAACTTT +TGTCTAATACCATCGGACAGCTTGAAATACTCGCCAAGAACCTTCTTTGTTGAGGAGCTT +ACTTTCCCTTCTGTATTTGTAGCAAAGCGGTCTACTGATGCGATACTGTCTTCAGTCGCT +TTTTGATATGCTTTATATGCAACAACACCAGTTCCGATAAGAGCCGCTGCTACTAGACCA +ATTGGCCCTGTTAAAACCGCAAGCGCGCTTCCTAAGAATCCAACTGCTCCAGCCGCAATT +CCAGCAATCCCACCGACTGATGCTAAAGCAAGAGATAAAGAACCAATTCCTGAAGCAATC +ATTCCAAACGCTGCTAAAACCACACCTATTGCTGTAGCCACAGCTGTTAAAGCAAGGACG +ATACCACCTGTAATTGCTATTGCCTTTTGTACTGGTCCAGGTAAAGAGTTGAATCCATCA +ACAAGTTTTTGTAAACCAGCAACAAAAACACTAACTACTGGAGCTAGTGCATCACCAATT +GTCTTTTTCATTGTGGAAAACGCTGAATCTAGTAATGTAAGTCGTCCCTTTAAAGTATCA +ATTTTGGTCGCTGCTACATCAGCTGCTGTAACCTTTGACATGGAATCCCACATTTCATTG +ACACCTTTGGCGCCTTCTTTAAACAAGATAGTCGCACCACGTACAGCATCGGAACCAAAT +AATGTTTCCAGAGCCATACTTCGTTGTTGGTCTGTTAAATCTTTCATCGATTCATGAAGT +GTACCTGAAATATTTTCTAGACTTTGAATATGCCCCTGTTGATCATAGAATTTTGATGAT +AAAAATGCCGAACTTGTTGCTAATTCGCGAAACGTTGTATCACATTTATCATTCCATTTC +GTTACACCTTCTGTTTTCATTACATATTGTTCTAAAGCTACTTCTATATCCCCTACATTT +CTGGAAGCTGGTTGAATACCGTTTTTAACTAAGAAATCAAAACCTGCCTGTGCATTATAA +GTAATAAGTCCTAAATCTCTCATTTTGTTATATGCTTCTTTTGTTGAAGGATTTAACCTC +ATTAACATTGTTTTTAAAGATGTACCTGCATCTGATCCCTTAAGACCATTTTGTGCAAAT +ACCGCTAAAGTTGTAGCTGTATCCTTAAACGTCATTCCGGCTCCCGCTGCTACTGCTGAT +GAAGCTGAAAGTCCATATTTTAACTCTCTTACATCAGTTGCGGAAGCATTGGCTGCACCA +GATAAAATATTGGCTGCATCCGCAACTGAAAGATGGTCTGCTTTAAATGCATTCAGAGCT +GTGGAAGCAATTTCGGCTGCTTCACCTAACTCTAATTCCCCTGCCGTCGCTAAGTTAAGG +GCACCTGCCAATCCGCCGTTAATAATATCTTGTAAGCTAACACCAGCCTTTATTAATTCC +TCGATACCTTGACCTGCTTGAACACTGGAGTATTTTGTTGTTTCTCCCATATTAACAGCC +AATTCACTTAACTTTTTCATTTCTGCTCCAGTAGATCCAGAAACAGCTTTTACATTGGCC +ATCTGTTGCTCAAAATTCATTGATTCAGTGATTGCTGATTTTAAGCCCCGACCTATTGCG +TAAGTCATACCACCAAATACCATGCCGATCTGCATTCCGGCATTTTGCAAATGATTACCT +AATGTCTCCATGCGATTTCCGAAGTTCAATAGGCGATTCCCTTGCTGTTCTAATTCACGA +TTTGACTGCTGTAATCCAGTTTCAAATCGATTCAGTTCAGCTGTTGCCCGATGAATTTGT +TCAGCGTATCTTTGTGCTGATTGACTCGCTTCGCCTTCTTCTGTTTTAGCACGATTATAG +GCTTGTTGAAGTTCCCTAATCTTCTCTTTTTGTTTATCTACCATACGGGATAAAACATCT +ACTTTAGCCCTTGTTTGTTCTGTCGCATTAGAAAAACCGCCCATACCTGTTGTAATAGAC +TGAAATTCAGCTTGTAGGGATTTTAAAGAGTTGTTTAACTTATCCATCCCTTTTTGTTCA +GCTTGACGGTTTACTTGCTTTAATTCATTTTCAAATCTATTTAAATCAGCAACTGCCTTA +TTAACTTGCGAAGCATATCGCTGGGTTGCTGCATCATTTTCACCTAATTTAGCCTTATTT +TGATCATAGGCTTGTCGTAACGCTTTAACTTTCTCTTTTTGCGCATCAATGAGCCTACTG +AGTGTATTCATTTTCGCTTGTGTTTGCTGACTAGCGTTAGCAAAACCGCCCATTCCTGTA +CTTACAGATTTCAATTCATTCTGTAACGTCCTGACTGCACGACCTGAATTCGAGATACCT +TGTCTGAAATTTACGTTATCAAGGGAAAGTCTAACGACTAGATTATTTATTTCATTCGCC +ATAGTCTCACCTCCCTCGTTAAATAATGTTTTCCGCTGGCACTTCTATTTCATTTGAATT +GGAGCCTTCGTAATTTTCATTTCCGTTTTCATGCATTTTTCGATTAAGTCTCAAATAATG +CCAAATATCCATCTCATTATCAATGTGATGGTGTTTGTACCCTTGTCGCAATAAAGAGAG +GTAGAGCTCGTCCATAAACTCACTGAACGTTAGCCCTCCTCCCTCTATGCGTTTGGGTTT +TCTTCTTCTCCTGATTCAGTACTACCCCCTGCTGCTTCCACTGTTTCATTTATAATTGCG +TTAATTACATCTGAAGTTGTCGATAAGAATTTACGGGCATCAACACCATCCCAATACTGA +TCTAATGTAAATTGACCATCATAAACTTTCACTACGAATTGAACCATTTTATCCATATCT +TCTGGACCAGGATTGTTTGGAATTTCAGCAAGTTCAGGAGCCTGACGAATAAGGCGGGCT +GGAATAAATTCTGGCATATTAAAAGTTTGTTTTTCTTTATTAATCATTAATGTTAATTTC +ATAGTTTTTCCCTCCTAAATTTAATAAAAAAGAGAGAGCTTTTGCTCCCTCTTACTTTCC +TGCTGGTGGTTGTGTCACTGGTTTTTCATATACTTTATTAAACCAATTATCTCCAACTAA +TTTTGTGAACGTTGGTTCATCTTCATCTGCTGTAAATTTCGTTCTATCATCAAAATCACG +TTCAATAAAGGAACCTTTCAATTTTGTTGTTTGGAAGTTCGGTTTGTCTTTTTTCGTTTC +AGCTTCTTCTTCCTCTTGTGAAAGTTTCCCTTTTAATAACCAAACATATCGATACTTATC +ATTAGCTTTTAAGAATCGGAAACCAATAGCTAAATATGGTTTCTCACCTTCACGTTTCTC +ATCTAAAACGCCATCTTTTACTTCTGGAAACCCTTCAATGTCAGCCTTTGTAGAAAGTGA +AAGTCCTCGAACCTCAATCTCCACTTCAGTTTCGCCATCAGATTCTGCAATCTCTGATTT +TCTGTTATCGCTCCACATAACCTCAGAAGCTACTTTTTTAGTTAATTTAACCTTTACAGC +ACCTTCCATTTTCTTTACATCTGTATATTTAATAGCAGACGAATCATCTTGTAAAACTTT +CGCATATACAAGGTTGTCTACACCAACCGTTGAACTAATTCTTACAACTTCTCCAGCCAT +TTATAATTCCACTCCTTTTGCGAATCTCATCGCATAATGAAATATTTGTGTATCCTCTTC +ATATAAATCAGCAACCGCATAGCGTGAGAAACCAATTCTTTTCATGATTTCATTCACTTT +TTGATGGATTGCTGTTGTACTACTCTTTGCCCAAACATCAACTTGAAACAAGATTTCACT +TTCAATCTCTTGATTATCTGCAAATCCATCTGGCCTATTGTCTAATTCAAAATACGTAAT +TCGCGGAAACTCTTCTGCCTTCTTTGCTTTACGGTAATAAATTCGTTTCCCACCCAACAA +TGAAACAAGCTCTTGATCATTCTCAAGAGCTTGTAAAATATCAGGTCTTAAATTTATCAC +AAATCCAACCTCATTTCGTTCTTTAAAATATCTGTCATAGCACGTACAGCTTCCGCTTTT +GAAGCATTAAAACCCGGCTCTATAAATGGATGTGCTGGCATTTTGGATGTACCCCATTCA +TGGAACTTTAAATAGAACCACGGGGAACGATCCGCTTTATTAAGACCTATTTTTACTGTT +TTTATTCCACCTTCAAGTTTAGCTTTTGTTACTTTTATCTGGTCTGCACCATGTTGCCCT +GTACGCCACGGTTCACTTTTAGATCGTTTTTTGGGGCTTGGGCTTCTTGGCGCTCGTTCT +GCAATGGCTTTACGAATAGGTTCACCACCAGCTGCAAGAGCTTTATCTTCAATTTTCTCT +CCCCGTAACCCCATTTGGTCTAATTCAGTAACTAAACGATCAAATCCTAATAAATCTAAA +TCTATACCATCAGCCATTCATTTCACCACGTTTCCACATGATTAATAAAGTATGATCTTG +AGTTGGAATAACGGAAACAATATCATAAATCACGTTTTTGTACTTAATTTTCATATCTGC +ACTTACATCATCCCGATTTCTGATTTCTGTTTCTCCTTGAACCTCACTATTAGCAGCTGC +TGCCTCAAAGTATTTCCTTCCCTTTAAATAAACAAAAGAGCCCCATACGGTAAAAGCATC +TTTATATCCATCTATCGGATCACCGTCAGGCCCTTTTGCATTTTCATCTTTTACTTGAAA +TGTAAGCCGTTTATCTAATTTTGCAGGATTCATTTTCTTTCCTCCTGAGGCTCTGAAGCA +TATTGGAGCTGTAATATCATACTCTGAACAATGGTTCTGATTTTTTCACTGGCTTTTTCA +CCTACAAGTAGTCGATTTCCGTACCAATCAGCCACCAGAAATAAACAAAGCAACTTAGCA +TCTTCATTTGTTTGAGTAAATGTTTTGCCAGTTGCTTTGTAAATATATAATTCAGCCGCT +TTAATTAACATAGTGATAGTTGGGTCATCGTCTCCGTCCACTCGAATCCATTCTTTAGCT +TCTTCTAAGGTAACAAGCATTCAAATGCCTCCTTAGTTTACCCTTGAGGTTGTTCAACAG +GAGCGCTTAAATCGATTTCTCCGTAAACTGCTGCTTCATTATCCCACATTTGCACATCAT +CACGTTGAATTGCGCGTAAATCTAATGTATTACGAGTGAATGCTTTACCACCTACATCTG +TAGAAGCCAGTTCCATATCTTCACGTTTAAATAAAACAATAGCTTCTTTTAAATCACCAA +TAATAAGTGGCGCTTTTTTAGCTGTAGTTCCCTTTGATTTTAAGAAACGATTCGAAACAA +CAACGACTGGATTAGTACCAGCAAATAGTTTTTTGTTTTTTTGCGTTGGATCTGACTGTA +AAATATATTTTCCGTCTTTATCTTTTAATTTGTCTAAATAATTAAATCCATCTTGGTTTG +TAAGTAAAATCGCATTCGGAGAAATCGCTGGGTCTAATTTAACATTTAATACATCTTTAA +TATCATCCAGAGATTTGATTGCTTGTTTTGTTAACTTTTCAATTACGCCCAAGATTAACA +CATTACGTGTAACTTTAGATTTCTTACCTAGCCATTTAGTCACATACTTTAGGATGTTTT +GATCACTATCTTGAAGTAATGAACGAGATAACGGTAAAATACCTGCTCTGTCCTTCACTG +CATATTGTACATTTGAAAATTTCGGATTATCAGTTTCTGGAATTTCACCCATTTCAGTGA +TTTCAGCAAACGGAATCATATCTGAATTTTTCTCTAATACTCGTGATCCTGAACGTGTAC +GCACTGGTTCAACAGTTACATATTGCTCAAGCGCATCAAATGAACGAGCTAATTCATTGA +TTTGCGTTTGAATATCTTGAGGGATGACAAGTCCTCCATCTTCCCCAGTTAATCCTGACA +TGGCACGTTGTTCTAAATCATCCTCAAGAAATTCACGTTCTTCAGCATTTAATGGTTTAT +TGCGTAATGCTTTCATAAACACATCGCGGTATTCCATTTCACCATCTACATTACGTGTTT +CAACTTCTCTTCCATTATTTCGTTCTTCCGTTTCTGCTTCATCTAATGAGCGTTGTAAAT +CAATTTTTTTCTGAAGTGATCGCACTTCTTCCATCATTTGTTCTGCTTCTGCCACTTTAT +CTTCTCCCATAAGAGAGCGTACTTCTTCCTTTTTCCCTTCTAACTTAGCTAATAATTCAC +GTAATTCTTTTGACATTCAAATCACTCCTTAAATTTATCAATAAAAAAAGAGCCTTATAT +AAGCTCTAGTTCGATTTGTAGTTTTCTTTTCCTAAACTCATCAGCTACTCGCTTTTCTCC +AGCTTTAAAATCATCCAATGAACGTACACTTACTTCATTCGTTGGATATGCAGGGAATGC +AACCGGTGATATTTCATATAGTTCAGCATTTAAAATCGAACGCTTATAAAGCTTTCCATT +TTCACGTTCTTCCGATGACCATTTGTCTTTTGTAACCTTCATCCCAAAAGAAACTCCATC +AACATCTCCACGCTTAATTAATTCCCATGCGTCATTCCCAACAGTTGTATTAGGAATATC +TAATTCAAATCGTAATTCTTTCTTGTCATTTTCGATTCGTAAAGTTTTACTTTTAGTATT +TCCTAATACTTGAGATGTGTCGTGAGACCATAAACCTACAACATCACGAACTTTTAAACT +TTCATCAAAAGCTCCCTCAGCAATCTCTTCTACGAAAGTATCGCCCCACCAGTCACGCAT +TTCGGCACTTTCATTGTTATATTTTATCGATCCCGAAATTGTTCGTTTTCCCTCGTCCTC +ATTAACTTCACGGACTTCAATAGTCATTGGCAAAGCTCTAATTTCCTTCATTTCCTTCTT +TGCTGACTTCTCCATTAGTATCACCTCCCTTCAAATATGCCTGTCCAGCCATATCAATCG +GCAACATATTTCCATTAACAAGTAAACGATCCCCACCAGCTTCTGGTGGTAAATCTTCTT +TACTTCTAGCTTCGTTAGGTTTAAGGAAACCGCCTTGAATACCCGTTCTGTAAGCTTCAT +ATCTCGTTTTGATATCCGCTCTTAAAATAGCGTCTACATTGAATTTTGAATAAAACCCCT +TATCCAACTCACTGTCTAAAAATAGCTTATACGTCATTTCTTGCTCATACATTGTTAAAG +TCGCTTGTAATGTATCGGTATAGAATTGTTGTTGCTGCTGCTCAATATTATTTAAAGTCG +CTTTACTCAAATCATTTAATTGATGCATTTTAATGCCGAATGCAGTAGCGATTTGCCTAA +TAGTAAGTTCGGTATTTTCGAGAAATTGAGCATCTGACATATTTAATGAAATAGGTTGAA +ATTGATATCCTACTGGCATTAATGCAATACGATGGCTATTTTGAAGACCGCTAGACATTG +ATTCGAAATTTTCTCGGAAAACCTTTTTCGCATCTTCATTTAAATCACCGACATATTGAA +CTAATCCCTTTACCTGTAACCCTTGTTTGTAAAAATTATTTATGAATTTATCAGCTGAAG +CTGAATTTTCTAATGTAGACTTTAAATATTCCATTGTAGGAACACCGACAAGACCATCAA +GAGTTATTCCGTTTTTAAAGTGCAGTATCTCTTCTGGCTTTAACACTCTTTGTTGTCCAC +CCGTATTTACTACATACCACATTTTAGTTTTGGAATTTAATAAACCAACGTCATCAATGT +ATACTGTCACTTTAGAAGCATCTATCGGCCATAACGCTTGGACTTTACCTTTTCTATCAA +ACTCTATGTTAGCGTAGCTATTGCCATATAAATTTTTTTGAGCTTCTAATGATCCGAAAA +AGTTCATACTGGACATATACGGGTTAGGCCTTAGTCTCAGTAAATTGTTGAGATAATGCT +TTGTACCGCGTTGGATTCCATATTCATCTTCCTGATAAATTTTCAACGGTAACTTTGATA +CGGATTCAGATAGTATTTTGATACAAGCAAAGACTGTAGCAACTTTTAAAGCATTTTTTC +CTTTAACGCTAATAGTACTTGGAGAAATCCCTAGCCATTCTAATAATTTTTCATCGTCTT +TATTCAACTCTATTACCTGCGACGTTTGGCGTTTTTCAAAATTAAAGAACTTTTTAACAG +AATCCACTATCTTCACATGTTCACCCCCTCCCTAGTTCCATAACTTGCCTAGAAAGTCTT +TATTTGCAAATTCAGATACATCAAACCTGACACTTGCTCCATACATAGCCCTAGAAAATG +CATTTAAGACCGCTGCTGCTGGATCAATACGATTTTTACTTATTTTTTTCGAAATCATAA +TGTTTTCCTGATCATCCATTTTAACAACAGCATTATTAAGCGCCCAAAAAAGGACTGGAT +CTCCATTATGTTTAACTTTCTTTTCGTATACTTTTTCTCGAAAATTTTTAGTCGGAATGG +ATAAATTAGCAATCCTTTGAGGGATTTCTACACAAACGAACCCTTTATTCTCTAAATTTT +GTGCTAGATGTAACGCATTCCATTTATCGTAATCAAACTCTTGAATTTCTTTGTCTTTTG +AAAAGTTTTCTATCCAAGACTCAACAATTGTATAATCAACCATTTCACCAGGCGTTAAAG +TTAAATACCCTTGTTCGGCCCATAAATCATAACGCACCTTATCTATGGCCATCTTTTCTT +TCAAACGTGCTTCAGGCATAAATGAATGTTGTCCAACAATAAAATCACCTTCATCGTCCA +TTCCAACCCAACCGACACTAGTTAAATCTGTTGTCATTGATAAGTCGCCACCTATCCAAA +GAGTCGCACCTGAAAAATCAAAGGTATCTACTTCGCATTTTTGCCATTTTGACATATCCA +TGTATCCGTTGTCCTTTTTATCGACCCAAATATTCATGTTTTTGGTTAAAAAAGCCCTCA +TCTTTTCAGGTCTATCAAGAGCAACCTTCAAATCTGAACGTATACCTTCCAAACCTTCTT +CATATGTAGCTACGATTGGGTTTGCTTTTATCCAATTCGACTCATCTTTGATATCATCGT +TCTTTTCCAATTCACAGATCATAACGAAATAATCATCGTTTTCTACATTTTTTGACGGGT +CTAAGATGTCACTGACATACTCATACTCTCTATAACAAGGTCTTGATAAGTCGAAACCAG +CTGTTGTTATGATAAACATTAACGGCTCTTTCCTTGCCACCATACCAGACGATAAAACGT +CATAAATTTCATCAGTTTCATGTGCATGATATTCATCGACAATTCCAAGAGACGGGTTTT +TACCATCACCAGTTTTTCTAGCTTCTTTTGAAAGTGGAACGACAACTGAACCATTCTTAA +ATATTTCAATGGTACTATAAGCCTCTTTCCATTTACCTTCTAACAATTCACTAGAACTAA +TCCCTGTTTTTACAGCTTCATAAACTTCAGATGATTGGTCTCTTGTCCATCCAGCAATAT +AAGCCCGTTGTTTTTCGTCTCCAAGAAATGTACAAAAAGCTGCTACAATAGCAAGAAACT +GAGATTTAGCATTTTTACGCGCTAACTGAATAAAAACCTTTCTAAATCGCCTTGCTCCAT +TTATTTTCTTTTTGAATCCGAAAATATTAGCCGCTAGAAACAATTGAAAATCAGTTAATT +CTACGGATTCACCTGCCAAAATCCCTTCAACGTGCTTAAATTCCTTTGCAAACCAGTAAA +AATCCTCCGCTATCTCTCCATCAAAATAAAAAGGACTGTCTTCACTTTGACACTCCTCAT +AATCCCTTATAAATCGTTCAATGGCCCAACGATGTTTTTTACAACTATTTATCTTGCCGT +TTAAAATGTCCTCGCAATATGCAAAAACCCGTTCCATTATCCAGTTCATATACGATCACC +AAAACGCTTTTGCGCTTCACTTTGCTTTTGTTGTGAAGTATCTACTTCTGGAATAACTAA +TTTTAAGCGGGATGTAATGGTCAAACCTAAATCACTAGCTGAAGAACGGCATTCATTGAA +TAAAAGATTTTTACTTCTTTGCATTTGAGAATACAATTTAAAGTCATCTGAAGGTTTTGT +TTTTCTTAGCAGACGAACCATTTTTATATATTGGTCTTTAGAATCAACGTACCTTGCTAA +ACTGTCAACATCTAAGTTACTGAAAATTTTCAATCTGACTAATTCAGCAGCTAAAGTATC +GAATTCCTTTTTTTGTGCTGCAGTCAAATAAGAAGGAGCTTCAATTTTATCAGTATGCCC +CCGCAATGCTTCTTCTTGTTTTTCTCGTCTGTTTTTCTCACTTTTTGTAATGTGATTTGA +TCTACCTTTTCCCTGTATAACAGAGAGTGGTTGTTTATTTCTTCCAGCCATGATTACACC +CCCTTAAAAAAATATGCAAAAACGGATTTTTCTGCGAAGTTGAGGGGGCGGCG diff --git a/tests/test_data/golden/all_gfa.json b/tests/test_data/golden/all_gfa.json new file mode 100644 index 0000000..d0178b7 --- /dev/null +++ b/tests/test_data/golden/all_gfa.json @@ -0,0 +1,102 @@ +{ + "dnaapler_reoriented.fasta": { + "records": [ + { + "description": "1 rotated=True rotated_gene=dnaA", + "head": "GTGTCACTTTCGCTTTGGCAGCAGTGTCTTGCCCGATTGCAGGATGAGTTACCAGCCACA", + "id": "1", + "length": 398227, + "sha256": "2c19aeb7b29f9ee032444d0aea4951c278044a5df3e77e8177b02ee6abcbd21c" + }, + { + "description": "2 rotated=True rotated_gene=repA", + "head": "GTGACTGATCTTCAACAAACTTATTACCGCCAGGTAAAGAACCCGAATCCGGTGTTCACA", + "id": "2", + "length": 186230, + "sha256": "e3818b01ab17fa9c0ad20280a6f8dd6c5c5501665d92e37eccc1d036bd483e59" + }, + { + "description": "3 rotated=True rotated_gene=repA", + "head": "ATGATCGTAGCTTCAGAACATCAAACAAAGCTAAGACAGAAAGAAATACAGGAAATCGAC", + "id": "3", + "length": 1240, + "sha256": "7bb39e24a82b9994e4aeeb2b9aef7b5a6dc736c6536de6a29912130140661057" + }, + { + "description": "4 rotated=True rotated_gene=repA", + "head": "ATGTCAGAAGATAAATTCCTTTCGGACTACAGCCCCCGTGATGCAGTTTGGGATACCCAG", + "id": "4", + "length": 2088, + "sha256": "b83be93e219c10186b740e9c512608318886a579621c296ebb3ac2fbc428bb6e" + }, + { + "description": "5", + "head": "GTTCTAGCATCGTTCGTCTGAGTTTGTTCTATATAAAACGGGCGCAATGTCTGCTTTGAT", + "id": "5", + "length": 1000, + "sha256": "3d73d8de6a50a1c879bde1c733f8876ab81471d5bf2c1b394da04967488dec79" + } + ], + "type": "fasta" + }, + "dnaapler_reoriented.gfa": { + "non_s_lines": [ + "H\tVN:Z:1.0", + "L\t1\t+\t1\t+\t0M", + "L\t1\t-\t1\t-\t0M", + "L\t2\t+\t2\t+\t0M", + "L\t2\t-\t2\t-\t0M", + "L\t3\t+\t3\t+\t0M", + "L\t3\t-\t3\t-\t0M", + "L\t4\t+\t4\t+\t0M", + "L\t4\t-\t4\t-\t0M" + ], + "s_lines": { + "1": { + "length": 398227, + "sha256": "2c19aeb7b29f9ee032444d0aea4951c278044a5df3e77e8177b02ee6abcbd21c", + "tags": [ + "DP:f:17.00", + "CL:z:steelblue", + "RT:z:dnaA" + ] + }, + "2": { + "length": 186230, + "sha256": "e3818b01ab17fa9c0ad20280a6f8dd6c5c5501665d92e37eccc1d036bd483e59", + "tags": [ + "DP:f:22.00", + "CL:z:steelblue", + "RT:z:repA" + ] + }, + "3": { + "length": 1240, + "sha256": "7bb39e24a82b9994e4aeeb2b9aef7b5a6dc736c6536de6a29912130140661057", + "tags": [ + "DP:f:4.00", + "CL:z:steelblue", + "RT:z:repA" + ] + }, + "4": { + "length": 2088, + "sha256": "b83be93e219c10186b740e9c512608318886a579621c296ebb3ac2fbc428bb6e", + "tags": [ + "DP:f:5.00", + "CL:z:steelblue", + "RT:z:repA" + ] + }, + "5": { + "length": 1000, + "sha256": "3d73d8de6a50a1c879bde1c733f8876ab81471d5bf2c1b394da04967488dec79", + "tags": [ + "DP:f:4.00", + "CL:z:steelblue" + ] + } + }, + "type": "gfa" + } +} diff --git a/tests/test_data/golden/all_gfa_no_circular.json b/tests/test_data/golden/all_gfa_no_circular.json new file mode 100644 index 0000000..5687433 --- /dev/null +++ b/tests/test_data/golden/all_gfa_no_circular.json @@ -0,0 +1,82 @@ +{ + "dnaapler_all_reorientation_summary.tsv": { + "content": "Contig\tGene_Reoriented\tStart\tStrand\tTop_Hit\tTop_Hit_Length\tCovered_Length\tCoverage\tIdentical_AAs\tIdentity_Percentage\tOverlapping_Contig_End\n1\tNo_reorientation\tNo_reorientation\tNo_reorientation\tNo_reorientation\tNo_reorientation\tNo_reorientation\tNo_reorientation\tNo_reorientation\tNo_reorientation\tNo_reorientation\n2\tNo_reorientation\tNo_reorientation\tNo_reorientation\tNo_reorientation\tNo_reorientation\tNo_reorientation\tNo_reorientation\tNo_reorientation\tNo_reorientation\tNo_reorientation\n3\tNo_reorientation\tNo_reorientation\tNo_reorientation\tNo_reorientation\tNo_reorientation\tNo_reorientation\tNo_reorientation\tNo_reorientation\tNo_reorientation\tNo_reorientation\n4\tNo_reorientation\tNo_reorientation\tNo_reorientation\tNo_reorientation\tNo_reorientation\tNo_reorientation\tNo_reorientation\tNo_reorientation\tNo_reorientation\tNo_reorientation\n", + "type": "text" + }, + "dnaapler_reoriented.fasta": { + "records": [ + { + "description": "1", + "head": "TCATTTCTTCAACAG", + "id": "1", + "length": 15, + "sha256": "cb0f4a4e1ac479386ffa36a01d479cf97281b4c5e3b54ed15bafd5580f08cd3e" + }, + { + "description": "2", + "head": "GCAGGTAAAT", + "id": "2", + "length": 10, + "sha256": "2e2c3b363689876e85145293430e839dd3de6b0d2449a63351518a2ae206505e" + }, + { + "description": "3", + "head": "TGTGA", + "id": "3", + "length": 5, + "sha256": "7d2c94ac87c0df08826fd63b12c96b7d6017123f2a279133b9a4a52ec2ac379d" + }, + { + "description": "4", + "head": "ACAT", + "id": "4", + "length": 4, + "sha256": "d2189a0465aec644e836092ea0ff9a50c28c42c10a2efd22b28e9f20926e4ede" + } + ], + "type": "fasta" + }, + "dnaapler_reoriented.gfa": { + "non_s_lines": [ + "H\tVN:Z:1.0", + "L\t1\t+\t3\t+\t0M", + "L\t2\t+\t2\t-\t0M", + "L\t3\t+\t3\t+\t0M" + ], + "s_lines": { + "1": { + "length": 15, + "sha256": "cb0f4a4e1ac479386ffa36a01d479cf97281b4c5e3b54ed15bafd5580f08cd3e", + "tags": [ + "LN:i:15", + "dp:f:1.0" + ] + }, + "2": { + "length": 10, + "sha256": "2e2c3b363689876e85145293430e839dd3de6b0d2449a63351518a2ae206505e", + "tags": [ + "LN:i:10", + "dp:f:2.0" + ] + }, + "3": { + "length": 5, + "sha256": "7d2c94ac87c0df08826fd63b12c96b7d6017123f2a279133b9a4a52ec2ac379d", + "tags": [ + "LN:i:5", + "dp:f:3.0" + ] + }, + "4": { + "length": 4, + "sha256": "d2189a0465aec644e836092ea0ff9a50c28c42c10a2efd22b28e9f20926e4ede", + "tags": [ + "LN:i:4", + "dp:f:3.0" + ] + } + }, + "type": "gfa" + } +} diff --git a/tests/test_data/golden/archaea_cog1474.json b/tests/test_data/golden/archaea_cog1474.json new file mode 100644 index 0000000..a0f93c2 --- /dev/null +++ b/tests/test_data/golden/archaea_cog1474.json @@ -0,0 +1,14 @@ +{ + "dnaapler_reoriented.fasta": { + "records": [ + { + "description": "CP001742.1 Acidilobus saccharovorans 345-15, complete genome", + "head": "ATGGGAGGAAGGATATTCACGGACAGGAGGGTGTTCGAGGAGACCTACGTGCCCGACATA", + "id": "CP001742.1", + "length": 1496453, + "sha256": "3111a671a268dc38a0b9c9ce4bed54c601228f753f75f63762642e6081b77979" + } + ], + "type": "fasta" + } +} diff --git a/tests/test_data/golden/chromosome_dnaa.json b/tests/test_data/golden/chromosome_dnaa.json new file mode 100644 index 0000000..e366ff1 --- /dev/null +++ b/tests/test_data/golden/chromosome_dnaa.json @@ -0,0 +1,14 @@ +{ + "dnaapler_reoriented.fasta": { + "records": [ + { + "description": "chromosome", + "head": "ATGTCGGAAAAAGAAATTTGGGAAAAAGTGCTTGAAATTGCTCAAGAAAAATTATCAGCT", + "id": "chromosome", + "length": 2836041, + "sha256": "8fef4ea14a3307bfc0c72dbf688a758c3e61d1b4080d53b2338f11f1f0530b81" + } + ], + "type": "fasta" + } +} diff --git a/tests/test_data/golden/largest_neg_strand.json b/tests/test_data/golden/largest_neg_strand.json new file mode 100644 index 0000000..ca4ca27 --- /dev/null +++ b/tests/test_data/golden/largest_neg_strand.json @@ -0,0 +1,14 @@ +{ + "dnaapler_reoriented.fasta": { + "records": [ + { + "description": "NC_007458_rc", + "head": "ATGAGAACACCAAGCGGGATTTTGCATGTTGTGGATTTTAAAACGGATCAAATCGTCGCA", + "id": "NC_007458_rc", + "length": 37253, + "sha256": "80e7e51c9826cd595a3b80ccde42deb83a97397f42dafc70db8cb18b4de7609b" + } + ], + "type": "fasta" + } +} diff --git a/tests/test_data/golden/mystery_seed13.json b/tests/test_data/golden/mystery_seed13.json new file mode 100644 index 0000000..e08fe5c --- /dev/null +++ b/tests/test_data/golden/mystery_seed13.json @@ -0,0 +1,14 @@ +{ + "dnaapler_reoriented.fasta": { + "records": [ + { + "description": "chromosome", + "head": "ATGAAGAAAACATTACTCGCATCATCATTAGCAGTAGGTTTAGGAATCGTAGCAGGAAAT", + "id": "chromosome", + "length": 2836041, + "sha256": "a01c1628c071eda928163ea9e3b7679563efd2294faca5f1c19f1e10ed3b0f75" + } + ], + "type": "fasta" + } +} diff --git a/tests/test_data/golden/nearest.json b/tests/test_data/golden/nearest.json new file mode 100644 index 0000000..d64981c --- /dev/null +++ b/tests/test_data/golden/nearest.json @@ -0,0 +1,14 @@ +{ + "dnaapler_reoriented.fasta": { + "records": [ + { + "description": "chromosome", + "head": "ATGCACAATGAGAAATTAATTAAAGGCTTATATGACTATCGTGAGGAACATGATGCGTGT", + "id": "chromosome", + "length": 2836041, + "sha256": "0f3f478fb547d73d596798de3ae1e31b662910f36f4a5b27b2df6c708bd6416d" + } + ], + "type": "fasta" + } +} diff --git a/tests/test_data/golden/phage_terl.json b/tests/test_data/golden/phage_terl.json new file mode 100644 index 0000000..d85d717 --- /dev/null +++ b/tests/test_data/golden/phage_terl.json @@ -0,0 +1,14 @@ +{ + "dnaapler_reoriented.fasta": { + "records": [ + { + "description": "NC_007458.1 Bacillus phage Gamma, complete genome", + "head": "ATGAACTGGATAATGGAACGGGTTTTTGCATATTGCGAGGACATTTTAAACGGCAAGATA", + "id": "NC_007458.1", + "length": 37253, + "sha256": "de214b734448de3e1def4d7e7f7d6e5e207f26fcbbe080bf313d12695f37c07e" + } + ], + "type": "fasta" + } +} diff --git a/tests/test_data/golden/phage_terl_no_start_codon.json b/tests/test_data/golden/phage_terl_no_start_codon.json new file mode 100644 index 0000000..19c9fea --- /dev/null +++ b/tests/test_data/golden/phage_terl_no_start_codon.json @@ -0,0 +1,14 @@ +{ + "dnaapler_reoriented.fasta": { + "records": [ + { + "description": "MW460250_1_subset", + "head": "ATGGGTGTAATGGAAATGGTTCATTTTGCAGATATGCATAGTTATGCTAACGCAAAGTGT", + "id": "MW460250_1_subset", + "length": 34300, + "sha256": "e42d6f826c0216f5fe105f063cbbf19a46601d8fed6fe1d62c3b8b13c6fc6cc0" + } + ], + "type": "fasta" + } +} diff --git a/tests/test_data/golden/plasmid_repa.json b/tests/test_data/golden/plasmid_repa.json new file mode 100644 index 0000000..ebdfd2e --- /dev/null +++ b/tests/test_data/golden/plasmid_repa.json @@ -0,0 +1,14 @@ +{ + "dnaapler_reoriented.fasta": { + "records": [ + { + "description": "1 length=181436 plasmid_copy_number_short=1.0x plasmid_copy_number_long=1.04x circular=true", + "head": "ATGACGAGCGAAAATAACAGCTTACTTCTGAACCTTCAGGAAGTTGATAAGACAACCGGC", + "id": "1", + "length": 181436, + "sha256": "544052fb253d2636ce5f25e2450c9bc5082eaca8065457d64b31fb266aaeee4b" + } + ], + "type": "fasta" + } +} diff --git a/tests/test_dnaapler.py b/tests/test_dnaapler.py index 01dadca..c90786c 100755 --- a/tests/test_dnaapler.py +++ b/tests/test_dnaapler.py @@ -17,6 +17,8 @@ import pytest from loguru import logger +from src.dnaapler.utils.cds_methods import run_largest +from src.dnaapler.utils.gfa import gfa_to_fasta from src.dnaapler.utils.processing import ( process_MMseqs2_output_and_reorient, reorient_sequence, @@ -178,6 +180,103 @@ def test_reorient_sequence_random_bad_strand(self): strand = 24 reorient_sequence_random(input, out_file, start, strand) + def test_reorient_sequence_random_negative_strand_start_codon(self, tmp_path=None): + # Regression test for issue #102: negative-strand gene reorientation must use + # gene.end (not gene.begin) so the output starts with a valid start codon. + # no_hit_plasmid.fasta has its only/largest CDS on strand=-1 with begin=450, end=1184. + import tempfile + + from Bio import SeqIO + + input_fasta = os.path.join(overall_inputs_test_data, "no_hit_plasmid.fasta") + with tempfile.NamedTemporaryFile(suffix=".fasta", delete=False) as fh: + out_file = fh.name + + # strand=-1, correct start = gene.end = 1184 + reorient_sequence_random(input_fasta, out_file, 1184, -1) + + record = SeqIO.read(out_file, "fasta") + first_codon = str(record.seq[:3]) + assert first_codon in ("ATG", "GTG", "TTG"), ( + f"Reoriented sequence should start with a valid start codon, got {first_codon}" + ) + + # Confirm the old buggy behaviour (using begin=450) would NOT produce a start codon + reorient_sequence_random(input_fasta, out_file, 450, -1) + record_wrong = SeqIO.read(out_file, "fasta") + first_codon_wrong = str(record_wrong.seq[:3]) + assert first_codon_wrong not in ("ATG", "GTG", "TTG"), ( + "Expected the buggy reorientation to fail to produce a start codon" + ) + os.unlink(out_file) + + +class TestRunLargestNegativeStrand(unittest.TestCase): + """Regression tests for issue #102 - run_largest must orient correctly when + the largest CDS is on the negative strand.""" + + def test_run_largest_negative_strand(self, tmp_path=None): + # NC_007458_rc.fasta is the reverse complement of NC_007458.fasta. + # Its largest CDS is on strand=-1 (begin=20063, end=23929). + # After correct reorientation the first gene should begin at position 1. + import tempfile + + import pyrodigal + from Bio import SeqIO + + input_fasta = os.path.join(test_data, "NC_007458_rc.fasta") + with tempfile.TemporaryDirectory() as tmp_dir: + ctx = click.Context(click.Command("test")) + run_largest(ctx, input_fasta, tmp_dir, "test") + + out_file = os.path.join(tmp_dir, "test_reoriented.fasta") + assert os.path.exists(out_file), "Reoriented output file was not created" + + record = SeqIO.read(out_file, "fasta") + orf_finder = pyrodigal.GeneFinder(meta=True) + genes = orf_finder.find_genes(str(record.seq)) + assert len(genes) > 0, "No genes found in reoriented sequence" + # The first gene should start at position 1 after correct reorientation + first_gene = genes[0] + assert first_gene.begin == 1, ( + f"Expected first gene to start at position 1 after reorientation, got {first_gene.begin}" + ) + + +class TestGfaToFasta(unittest.TestCase): + """Tests for gfa_to_fasta - GFA input should yield a complete FASTA of all contigs.""" + + def test_gfa_to_fasta_writes_all_contigs_with_annotations(self): + import tempfile + + from Bio import SeqIO + + # A minimal reoriented GFA: one rotated contig (with RT:z: tag) and one + # passed-through (non-circular) contig with no tag. + gfa_contents = ( + "H\tVN:Z:1.0\n" + "S\t1\tATGCATGCAT\tRT:z:dnaA\n" + "S\t2\tGGGGCCCCAA\n" + "L\t1\t+\t1\t+\t0M\n" + ) + with tempfile.TemporaryDirectory() as tmp_dir: + gfa_file = os.path.join(tmp_dir, "test_reoriented.gfa") + fasta_file = os.path.join(tmp_dir, "test_reoriented.fasta") + with open(gfa_file, "w") as fh: + fh.write(gfa_contents) + + gfa_to_fasta(gfa_file, fasta_file) + + records = {rec.id: rec for rec in SeqIO.parse(fasta_file, "fasta")} + # both contigs present (the L line is ignored) + assert set(records.keys()) == {"1", "2"} + assert str(records["1"].seq) == "ATGCATGCAT" + assert str(records["2"].seq) == "GGGGCCCCAA" + # rotated contig is annotated from the RT:z: tag, the other is not + assert "rotated=True" in records["1"].description + assert "rotated_gene=dnaA" in records["1"].description + assert "rotated=True" not in records["2"].description + class TestBlastOutput(unittest.TestCase): """Tests for process_MMseqs2_output_and_reorient""" diff --git a/tests/test_golden.py b/tests/test_golden.py new file mode 100644 index 0000000..c7f7896 --- /dev/null +++ b/tests/test_golden.py @@ -0,0 +1,202 @@ +""" +Golden-output regression tests. + +Each test runs a dnaapler command and compares its output files against a stored +snapshot in tests/test_data/golden/. The snapshot records, for each output file, a +compact but exact fingerprint - reoriented sequences are captured as lengths + sha256 +hashes (so large genomes don't bloat the repo), and small text files (e.g. the +no-reorientation summary) are stored verbatim. Any change to dnaapler's reoriented +output is therefore caught. + +Only the primary reoriented outputs (the FASTA / GFA, and the fully deterministic +no-circular summary) are goldened. Summary *statistics* for real reorientations +(coverage %, identity %, etc.) are intentionally not goldened, as those can shift with +MMseqs2 version changes without indicating a dnaapler regression. + +If an output change is intentional (a new feature, or a dependency bump that +legitimately changes reorientation), regenerate the snapshots with: + + DNAAPLER_UPDATE_GOLDEN=1 pytest tests/test_golden.py + +and commit the updated tests/test_data/golden/*.json files. +""" + +import hashlib +import json +import os +import subprocess +from pathlib import Path + +import pytest +from Bio import SeqIO + +test_data = Path("tests/test_data") +overall_test_data = test_data / "overall_inputs" +golden_dir = test_data / "golden" + +UPDATE = os.environ.get("DNAAPLER_UPDATE_GOLDEN") == "1" + + +def exec_command(cmnd): + """Executes a shell command, raising if it exits non-zero.""" + proc = subprocess.Popen( + cmnd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE + ) + out, err = proc.communicate() + if proc.returncode != 0: + raise RuntimeError(f"FAILED: {cmnd}\n{err.decode('utf8', 'replace')}") + return out.decode("utf8") if out is not None else None + + +def _sha256(text): + return hashlib.sha256(text.encode()).hexdigest() + + +def snapshot_fasta(path): + """Snapshot a FASTA as an ordered list of records (id, description, length, hash).""" + records = [] + for rec in SeqIO.parse(path, "fasta"): + seq = str(rec.seq) + records.append( + { + "id": rec.id, + "description": rec.description, + "length": len(seq), + "sha256": _sha256(seq), + "head": seq[:60], + } + ) + return {"type": "fasta", "records": records} + + +def snapshot_gfa(path): + """Snapshot a GFA: S-line sequences as hashes, all other lines verbatim.""" + non_s_lines = [] + s_lines = {} + with open(path) as fh: + for line in fh: + parts = line.rstrip("\n").split("\t") + if parts[0] == "S": + seq = parts[2] + s_lines[parts[1]] = { + "length": len(seq), + "sha256": _sha256(seq), + "tags": parts[3:], + } + else: + non_s_lines.append(line.rstrip("\n")) + return {"type": "gfa", "non_s_lines": non_s_lines, "s_lines": s_lines} + + +def snapshot_text(path): + """Snapshot a small text file verbatim.""" + with open(path) as fh: + return {"type": "text", "content": fh.read()} + + +def snapshot_file(path): + suffix = Path(path).suffix + if suffix == ".fasta": + return snapshot_fasta(path) + if suffix == ".gfa": + return snapshot_gfa(path) + return snapshot_text(path) + + +def snapshot_outputs(output_dir, filenames): + return {name: snapshot_file(os.path.join(output_dir, name)) for name in filenames} + + +def check_golden(name, snapshot): + """Compare snapshot to the stored golden, or (re)write it when updating.""" + golden_path = golden_dir / f"{name}.json" + if UPDATE: + golden_dir.mkdir(parents=True, exist_ok=True) + golden_path.write_text(json.dumps(snapshot, indent=2, sort_keys=True) + "\n") + return + assert golden_path.exists(), ( + f"Missing golden file {golden_path}. " + "Regenerate with: DNAAPLER_UPDATE_GOLDEN=1 pytest tests/test_golden.py" + ) + expected = json.loads(golden_path.read_text()) + assert snapshot == expected, ( + f"Output for '{name}' differs from golden {golden_path}. " + "If this change is intentional, regenerate with: " + "DNAAPLER_UPDATE_GOLDEN=1 pytest tests/test_golden.py" + ) + + +# (name, command template, [output files to snapshot]) +# {overall}, {test_data} and {out} are filled in below. +GOLDEN_CASES = [ + ( + "chromosome_dnaa", + "dnaapler chromosome -i {overall}/chromosome.fasta -o {out} -t 1 -f", + ["dnaapler_reoriented.fasta"], + ), + ( + "plasmid_repa", + "dnaapler plasmid -i {overall}/plasmid.fasta -o {out} -t 1 -f", + ["dnaapler_reoriented.fasta"], + ), + ( + "phage_terl", + "dnaapler phage -i {overall}/NC_007458.fasta -o {out} -t 1 -f", + ["dnaapler_reoriented.fasta"], + ), + ( + # tophit alignment has no valid start codon -> overlapping-ORF reorientation path + "phage_terl_no_start_codon", + "dnaapler phage -i {overall}/SAOMS1.fasta -o {out} -t 1 -f", + ["dnaapler_reoriented.fasta"], + ), + ( + "archaea_cog1474", + "dnaapler archaea -i {overall}/CP001742.1_archaea.fasta -o {out} -t 1 -f", + ["dnaapler_reoriented.fasta"], + ), + ( + # largest CDS is on the negative strand - guards issue #102 + "largest_neg_strand", + "dnaapler largest -i {test_data}/NC_007458_rc.fasta -o {out} -t 1 -f", + ["dnaapler_reoriented.fasta"], + ), + ( + "nearest", + "dnaapler nearest -i {overall}/chromosome.fasta -o {out} -t 1 -f", + ["dnaapler_reoriented.fasta"], + ), + ( + # mystery uses the default random seed (13) and is therefore deterministic + "mystery_seed13", + "dnaapler mystery -i {overall}/chromosome.fasta -o {out} -t 1 -f", + ["dnaapler_reoriented.fasta"], + ), + ( + # GFA input: reorients circular contigs and writes both GFA and complete FASTA + "all_gfa", + "dnaapler all -i {overall}/all_test.gfa -o {out} -t 1 -f", + ["dnaapler_reoriented.fasta", "dnaapler_reoriented.gfa"], + ), + ( + # GFA with no circular sequences: passthrough GFA + linear FASTA + summary + "all_gfa_no_circular", + "dnaapler all -i {overall}/no_circular.gfa -o {out} -t 1 -f", + [ + "dnaapler_reoriented.fasta", + "dnaapler_reoriented.gfa", + "dnaapler_all_reorientation_summary.tsv", + ], + ), +] + + +@pytest.mark.parametrize( + "name,cmd_tmpl,outputs", GOLDEN_CASES, ids=[c[0] for c in GOLDEN_CASES] +) +def test_golden(tmp_path, name, cmd_tmpl, outputs): + out = str(tmp_path / name) + cmd = cmd_tmpl.format(overall=overall_test_data, test_data=test_data, out=out) + exec_command(cmd) + snapshot = snapshot_outputs(out, outputs) + check_golden(name, snapshot) diff --git a/tests/test_overall.py b/tests/test_overall.py index 1f12400..c1cc81d 100755 --- a/tests/test_overall.py +++ b/tests/test_overall.py @@ -15,6 +15,7 @@ from pathlib import Path import pytest +from Bio import SeqIO test_data = Path("tests/test_data") overall_test_data = Path(f"{test_data}/overall_inputs") @@ -264,6 +265,69 @@ def test_gfa_all(tmp_dir): assert seq_4.startswith("ATGTCAGAAG") and len(seq_4) == 2088 assert seq_5.startswith("GTTCTAGCAT") and len(seq_5) == 1000 + # GFA input should also produce a complete FASTA containing all contigs + gfa_s_lines = { + parts[1]: parts + for parts in (line.split("\t") for line in output_gfa_lines) + if parts[0] == "S" + } + fasta_records = { + rec.id: rec + for rec in SeqIO.parse(f"{tmp_dir}/dnaapler_reoriented.fasta", "fasta") + } + # every contig from the GFA is present in the FASTA with an identical sequence + assert set(fasta_records) == set(gfa_s_lines) + for name, parts in gfa_s_lines.items(): + assert str(fasta_records[name].seq) == parts[2] + # a contig is annotated rotated=True in the FASTA iff it carries an RT:z: tag in the GFA + has_rt_tag = any(field.startswith("RT:z:") for field in parts[3:]) + assert ("rotated=True" in fasta_records[name].description) == has_rt_tag + # the non-circular contig (5) is passed through unannotated + assert "rotated=True" not in fasta_records["5"].description + + +def test_gfa_no_circular(tmp_dir): + """test all with a GFA input that has no circular sequences - instead of erroring, dnaapler + should warn, copy the input GFA to the output, and write all sequences out as a linear FASTA.""" + input_gfa: Path = f"{overall_test_data}/no_circular.gfa" + cmd = f"dnaapler all -i {input_gfa} -o {tmp_dir} -t 1 -f" + exec_command(cmd) + + # the input GFA is copied to the output unchanged + with open(input_gfa) as f: + original_gfa = f.read() + with open(f"{tmp_dir}/dnaapler_reoriented.gfa") as f: + assert f.read() == original_gfa + + # all sequences are written out as a linear FASTA, unchanged and unannotated + input_seqs = { + parts[1]: parts[2] + for parts in ( + line.rstrip("\n").split("\t") for line in original_gfa.splitlines() + ) + if parts and parts[0] == "S" + } + fasta_records = { + rec.id: rec + for rec in SeqIO.parse(f"{tmp_dir}/dnaapler_reoriented.fasta", "fasta") + } + assert set(fasta_records) == set(input_seqs) + for name, seq in input_seqs.items(): + assert str(fasta_records[name].seq) == seq + assert "rotated=True" not in fasta_records[name].description + + # a summary is written marking every contig as not reoriented + summary_lines = ( + open(f"{tmp_dir}/dnaapler_all_reorientation_summary.tsv").read().splitlines() + ) + header = summary_lines[0].split("\t") + assert header[0] == "Contig" and "Gene_Reoriented" in header + summary_rows = {line.split("\t")[0]: line.split("\t") for line in summary_lines[1:]} + assert set(summary_rows) == set(input_seqs) + for name, row in summary_rows.items(): + # every column other than the contig name marks no reorientation + assert row[1:] == ["No_reorientation"] * (len(header) - 1) + """ this one is for hybracter @@ -483,14 +547,6 @@ def test_bulk_dupe_header(self): cmd = f"dnaapler bulk -i {input_fasta} -o {outdir} -t 1 -f " exec_command(cmd) - def test_gfa_no_circular(self): - """test all with a GFA input that contains no circular sequences""" - with self.assertRaises(RuntimeError): - input_gfa: Path = f"{overall_test_data}/no_circular.gfa" - outdir: Path = f"{overall_test_data}/all_out" - cmd = f"dnaapler all -i {input_gfa} -o {outdir} -t 1 -f " - exec_command(cmd) - def test_gfa_inexact_overlap(self): """test all with a GFA input that contains an inexact overlap""" with self.assertRaises(RuntimeError): diff --git a/tests/test_process_ignore_input.py b/tests/test_process_ignore_input.py index a64276c..b795ad1 100644 --- a/tests/test_process_ignore_input.py +++ b/tests/test_process_ignore_input.py @@ -20,7 +20,6 @@ class TestProcessIgnoreInput(unittest.TestCase): - def test_empty_input(self): """Test empty string and None input""" self.assertEqual(process_ignore_input(""), [])