Repository: HobnobMancer/cazy_webscraper (language: python)

Issue:
Fix parsing config and selecting candidates of interest
- Near syntax
- Correct typos
- Add more logging messages
- Fix selecting candidates when multiple criteria are given
- Reduce computational burden and increase speed of getting proteins matching user criteria


Discussion / hints:

Fix patch:
diff --git a/README.md b/README.md
index 18369109..ef114417 100644
--- a/README.md
+++ b/README.md
@@ -15,10 +15,21 @@
 
 > `cazy_webscraper` version 1 is depracted. Please ensure you are using `cazy_webscraper` version 2 or newer.
 
-# Beta Version 2
-This release of `cazy_webscraper` is a beta release. The main component of `cazy_webscraper` (for the downloading of data from CAZy) is stable. Expanding the data set to incorproate data from UniProt, GenBank and PDB still require some work to workout all the remaining bugs.
+## cazy_webscraper
+
+`cazy_webscraper` is an application and Python3 package for the automated retrieval of protein data from the [CAZy](http://wwww.cazy.org/) database. The code is distributed under the MIT license.
+
+`cazy_webscraper` retrieves protein data from the [CAZy database](https://www.cazy.org) and stored the data in a local SQLite3 database. This enables users to integrate the dataset into analytical pipelines, and interrogate the data in a manner unachievable through the CAZy website.
+
+Using the `expand` subcommand, a user can retrieve:
+- Protein name, UniProt accession, EC numbers, PDB accessions and protein sequences from [UniProt](https://www.uniprot.org/)
+- CAZyme protein sequence data from [GenBank](https://www.ncbi.nlm.nih.gov/genbank/)
+- Protein structure files from the Research Collaboratory for Structural Bioinformatics (RCSB) Protein Data Bank [(PDB)](https://www.rcsb.org/)
+- Extract GenBank and UniProt protein sequences stored in the local CAZyme database and write them to FASTA file and/or BLAST database
+
+`cazy_webscraper` can recover specified CAZy Classes and/or CAZy families. These queries can be filtered by taxonomy at Kingdoms, genus, species or strain level. Successive CAZy queries can be collated into a single local database. A log of each query is recorded in the database for transparency, reproducibility and shareablity.
 
-The documentation is being actively updated to match the new `cazy_webscraper` version 2.
+Please see the [full documentation at ReadTheDocs](https://cazy-webscraper.readthedocs.io/en/latest/?badge=latest).
 
 **The `bioconda` installation method is not currently supported, but we are working on getting this fixed soon**. For now please install via pypi or from source.
 
@@ -29,8 +40,11 @@ The documentation is being actively updated to match the new `cazy_webscraper` v
 - **Caching:** Data downloaded from CAZy is not only parsed and written to a local CAZyme database. The raw data files are written to cache. Data can be scraped directly from a cache (ideal if CAZy updates during the retrieval of multiple datasets from the CAZy database).
 - **Handling multiple taxa:** It is possible for a single protein (identified by its unique GenBank accession) to be associated with multiple taxa in the CAZy data. For these instances, `cazy_webscraper` queries NCBI to retrieve the latest taxonomic source of the protein.
 
-## Recent updates in v2.0.5
+## Recent updates in v2
 
+- Fixed failure to retrieve all proteins matching the specified criteria from the local CAZyme database
+- Faster retrieval of proteins matching the specified criteria from the local CAZyme database
+- New tutorials and comprehensive documentation added to [Read the Docs](https://cazy-webscraper.readthedocs.io/en/latest/?badge=latest)
 - **UniProt:** `cazy_webscraper` can now be used successfully for retrieving data from UniProt and adding the data to the local CAZyme database. This includes retrieving:
 	- UniProt accessions
 	- Protein names
@@ -38,12 +52,13 @@ The documentation is being actively updated to match the new `cazy_webscraper` v
 	- EC number annotations
 	- PDB accessions
 - **GenBank:** `cazy_webscraper` can now be used to automate the retreival of protein sequences from GenBank for proteins in a local CAZyme database mathcing the users specified critieria. These protein sequences are stored in the local CAZyme database, and can be extracted to a FASTA file using `cazy_webscraper`
+- **Extract sequences from the db:** `cazy_webscraper` can be used to retrieve the GenBank and/or UniProt protein sequences stored in the database for user specified sets of CAZymes
+- **Accession lists:** As well as defining sets of CAZymes of interest for data retrieval by their class, family, EC number and/or taxonomy, `cazy_webscraper` can now accept lists of GenBank and/or UniProt accessions to define specific sets of CAZymes to additional protein data for
 - **Caching:** 
 	- More data is cached
 	- Cached data can be used to continue data retrievals from UniProt and GenBank, when a previous retrieval and/or addition of the data to the database fails
 	- Improved default name of cache dirs and subdirs
 - **Unit tests:** Started rewrite of unit tests to match the new program architecture
-- **Documentation:** Updating the documentation to include the new flags/options, and adding new tutorials for rautomating the retrieval if data from UniProt, GenBank and PDB
 
 ## Future work for version 2:
 - Calculate the coverage of the NCBI GenBank assembly database by CAZy (i.e. how many genomic assemblies from the Assembly database are included in the CAZy dataset)
@@ -51,19 +66,7 @@ The documentation is being actively updated to match the new `cazy_webscraper` v
 - Update the unit tests to work with the new `cazy_webscraper` architecture
 - Update the documentation
 - Create video tutorials
-
-## cazy_webscraper
-
-`cazy_webscraper` is an application and Python3 package for the automated retrieval of protein data from the [CAZy](http://wwww.cazy.org/) database. The code is distributed under the MIT license.
-
-`cazy_webscraper` retrieves protein data from the [CAZy database](https://www.cazy.org) into a local SQLite3 database. This enables users to integrate the dataset into analytical pipelines, and interrogate the data in a manner unachievable through the CAZy website.
-
-Using the `expand` subcommand, a user can retrieve:
-- CAZyme protein sequence data from [GenBank](https://www.ncbi.nlm.nih.gov/genbank/)
-- Protein structure files from the Research Collaboratory for Structural Bioinformatics (RCSB) Protein Data Bank [(PDB)](https://www.rcsb.org/)
-- EC number, PDB accessions and Uniprot protein IDs from the [UniProtKB database](https://www.uniprot.org/)
-
-`cazy_webscraper` can recover specified CAZy Classes and/or CAZy families. These queries can be filtered by taxonomy at Kingdoms, genus, species or strain level. Successive CAZy queries can be collated into a single local database. A log of each query is recorded in the database for transparency, reproducibility and shareablity.
+- Add a GUI for use, packaging and distribution
 
 ## Citation
 
@@ -149,12 +152,13 @@ Options are written in alphabetical order.
 
 `--citation`, `-C` - Print the `cazy_webscraper` citation. When called, the program terminates after printng the citation and CAZy is **not** scraped.
 
-`--database`, `-d` - Path to an **existings** local CAZyme database to add newly scraped too. Default: None.
+`--db_output`, `-o` - Path to write out a **new** local CAZyme database.
 
+`--database`, `-d` - Path to an **existings** local CAZyme database to add newly scraped too. Default: None.
 
 _Do not use `--db_output` **and** `--database` at the same time._
 
-_If `--db_output` **and** `--database` are **not** called, `cazy_webscraper` write out a local CAZyme database to the cwd with the standardised name `cazy_webscraper_<date>_<time>.db`_
+_If `--db_output` **and** `--database` are **not** called, `cazy_webscraper` writes out a local CAZyme database to the cwd with the standardised name `cazy_webscraper_<date>_<time>.db`_
 
 `--delete_old_relationships` - Detele old CAZy family annotations of GenBank accessions. These are CAZy family annotations of a given GenBank accession are in the local database but the accession is not longer associated with those CAZy families, so delete old accession-family relationships.
 
@@ -164,8 +168,14 @@ _If `--db_output` **and** `--database` are **not** called, `cazy_webscraper` wri
 
 `--genera` - List of genera to restrict the scrape to. Default: None, filter not applied to scrape.
 
+`--kingdoms` - List of taxonomic kingdoms to restrict the scrape to. Default: None, filter is not applied.
+
 `--log`, `-l` - Target path to write out a log file. If not called, no log file is written. Default: None (no log file is written out).
 
+`--nodelete`, `-n` - When called content in an existing output directory is not deleted.
+
+__When the `--db_output` flag is used, `cazy_webscraper` will create any necessary parent directories. If the direct/immediate parent directory of the database exists, by default `cazy_webscraper` will delete the content in this parent directory._
+
 `--nodelete_cache` - When called, content in the existing cache dir will **not** be deleted. Default: False (existing content is deleted).
 
 `--nodelete_log` - When called, content in the existing log dir will **not** be deleted. Default: False (existing content is deleted).
@@ -210,17 +220,18 @@ Class names can be written in all upper case, all lower case, or mixed case, suc
 
 ## Retrieve data from UniProt
 
-[UniProtKB] is one of the largest protein database, incorporating data from the [PDB] structure database and other protein annotation databases.
+[UniProtKB] is one of the largest protein database, incorporating data from the [PDB] structure database, NCBI and other protein annotation databases.
 
 `cazy_webscraper` can retrieve protein data from UniProt for proteins catalogued in a local CAZyme database created using `cazy_webscraper`. Specifically, for each protein, `cazy_webscraper` can retrieve:
 - The UniProt accession
+- Protein name
 - PDB accessions of associated structure files from the PDB database
 - EC number annnotations
 - Protein sequence from the UniProt
 
-`cazy_webscraper` always retrieves the UniProt accession, but the retrieval of PDB accession, EC numbers and protein sequences is optional.
+`cazy_webscraper` always retrieves the UniProt accession and protein name, but the retrieval of PDB accession, EC numbers and protein sequences is optional.
 
-Data can be retrieived for all proteins in the local CAZyme database, or a specific subset. CAZy class, CAZy family, genus, species, strains, kingdom and EC number filters can be defined in order to define a dataset to retrieve protein data from UniProt for.
+Data can be retrieived for all proteins in the local CAZyme database, or a specific subset. CAZy class, CAZy family, genus, species, strains, kingdom and EC number filters can be defined in order to define a dataset to retrieve protein data for.
 
 To retrieve all UniProt data for all proteins in a local CAZyme datbase, using the following command:
 ```bash
@@ -243,7 +254,9 @@ Below are listed the command-line flags for configuring the retrieval of UniProt
 
 `--config`, `-c` - Path to a configuration YAML file. Default: None.
 
-``--delete_old_ec`` - Boolean, delete EC number - Protein relationships that are no longer listed in UniProt, i.e. an EC number annotation is no longer included in UniProt but is in the local database. If set to TRUE these relationships will be DELETED from the database.
+`--delete_old_ec` - Boolean, delete EC number - Protein relationships that are no longer listed in UniProt, i.e. an EC number annotation is no longer included in UniProt but is in the local database. If set to TRUE these relationships will be DELETED from the database.
+
+`--delete_old_pdbs` - Boolean, delete PDB accessions - Protein relationships that are no longer listed in UniProt, i.e. an PDB accessions that are no longer included in UniProt but is in the local database. If set to TRUE these relationships will be DELETED from the database.
 
 `--ec`, `-e` - Enable retrieval of EC number annotations from UniProt
 
@@ -256,10 +269,12 @@ cw_get_uniprot_data my_cazyme_db/cazyme_db.db --ec_filter 'EC1.2.3.4,EC2.3.1.-'
 
 `--force` - Force writing in existing cache directory.
 
-``--genbank_accessions`` - Path to text file containing a list of GenBank accessions to retrieve protein data for. A unique accession per line.
+`--genbank_accessions` - Path to text file containing a list of GenBank accessions to retrieve protein data for. A unique accession per line.
 
 `--genera` - List of genera to restrict the scrape to. Default: None, filter not applied to scrape.
 
+`--kingdoms` - List of taxonomic kingdoms to restrict the scrape to. Default: None, filter is not applied.
+
 `--log`, `-l` - Target path to write out a log file. If not called, no log file is written. Default: None (no log file is written out).
 
 `--name_update` - Boolean, whether to overwrite the existing protein name (previously retrieved from UniProt). Default: do not update.
@@ -268,11 +283,15 @@ cw_get_uniprot_data my_cazyme_db/cazyme_db.db --ec_filter 'EC1.2.3.4,EC2.3.1.-'
 
 `--nodelete_log` - When called, content in the existing log dir will **not** be deleted. Default: False (existing content is deleted).
 
+`--pdb`, `-p` - Enable retrieval of PDB accessions. Default, PDB accessions not retrieved.
+
 `--retries`, `-r` - Define the number of times to retry making a connection to CAZy if the connection should fail. Default: 10.
 
+`--skip_uniprot_accessions` - Path to a JSON file, keyed by UniProt accessions/IDs and valued by dicts containing `{'gbk_acc': str, 'db_id': int}`. This file part of the cache created by `cw_get_uniprot_data`. This is option to skip retrieving the UniProt IDs for a set of GenBank accessions, if retrieving data for the same dataset (this save a lot of time!)
+
 `--sequence`, `-s` - Retrieve protein amino acid sequences from UniProt
 
-`--skip_uniprot_accessions` - Path to a JSON file, keyed by UniProt accessions/IDs and valued by dicts containing `{'gbk_acc': str, 'db_id': int}`. This file part of the cache created by `cw_get_uniprot_data`. This is option to skip retrieving the UniProt IDs for a set of GenBank accessions, if retrieving data for the same dataset (this save a lot of time!)
+`--seq_update` - If a newer version of the protein sequence is available, overwrite the existing sequence for the protein in the database. Default is false, the protein sequence is **not** overwritten and updated.
 
 `--sql_echo` - Set SQLite engine echo parameter to True, causing SQLite to print log messages. Default: False.
 
@@ -286,10 +305,13 @@ cw_get_uniprot_data my_cazyme_db/cazyme_db.db --ec_filter 'EC1.2.3.4,EC2.3.1.-'
 
 `--uniprot_batch_size` - Size of an individual batch query submitted to the [UniProt REST API](https://www.uniprot.org/help/programmatic_access) to retrieve the UniProt accessions of proteins identified by the GenBank accession. Default is 150. The UniProt API documentation recommands batch sizes of less than 20,000 but batch sizes of 1,000 often result in HTTP 400 errors. It is recommend to keep batch sizes less than 1,000, and ideally less than 200.
 
-`--seq_update` - If a newer version of the protein sequence is available, overwrite the existing sequence for the protein in the database. Default is false, the protein sequence is **not** overwritten and updated.
-
 `--verbose`, `-v` - Enable verbose logging. This does not set the SQLite engine `echo` parameter to True. Default: False.
 
+### UniProt data retrieval cache
+
+- The tables retrieved from UniProt are converted to dataframes, and written out as CSV files in the cache directory
+- The parsed UniProt data as a single JSON file
+
 ## Retrieveing protein seqences from GenBank
 
 Protein amino acid sequences can be retrieved for proteins in a local CAZyme database using `cazy_webscraper`. Protein sequences can be retrieved for a specific subset of proteins, identified through the use of CAZy class, CAZy family, taxonomy (kingdom, genus, species and strain) filters, and EC number filters. The retrieved protein sequences are written to the local CAZyme database.
@@ -301,10 +323,6 @@ To retrieve all GenBank protein seuqneces for all proteins in a local CAZyme dat
 cw_get_genbank_seqs <path_to_local_CAZyme_db>
 ```
 
-`cazy_webscraper` produces to cache files, which are written to the cache dir:
-1. `no_seq_retrieved.txt` which lists the GenBank accessions for which no sequence could be retrieved from GenBank
-2. `seq_retrieved.txt` which list GenBank accessiosn for which a sequence was retrieved from GenBank
-
 ### Configuring GenBank protein sequence retrieval
 
 Below are listed the command-line flags for configuring the retrieval of protein sequences from GenBank.
@@ -328,7 +346,7 @@ Below are listed the command-line flags for configuring the retrieval of protein
 cw_get_uniprot_data my_cazyme_db/cazyme_db.db --ec_filter 'EC1.2.3.4,EC2.3.1.-'
 ```
 
-`--entrez_batch_size` - Change the query batch size submitted via [`Entrez`]() to retrieve protein sequences from GenBank data. Default is 150. `Entrez` recommands queries not larger than XXX objects in length.
+`--force`, `-f` - Force writing cachce to exiting cache directory.
 
 `--families` - List of CAZy (sub)families to scrape.#
 
@@ -356,6 +374,13 @@ cw_get_uniprot_data my_cazyme_db/cazyme_db.db --ec_filter 'EC1.2.3.4,EC2.3.1.-'
 
 `--verbose`, `-v` - Enable verbose logging. This does not set the SQLite engine `echo` parameter to True. Default: False.
 
+### GenBank sequence retrieval cache
+
+`cazy_webscraper` produces three cache files, which are written to the cache dir:
+1. `no_seq_retrieved.txt` which lists the GenBank accessions for which no sequence could be retrieved from GenBank
+2. `seq_retrieved.txt` which list GenBank accessiosn for which a sequence was retrieved from GenBank
+3. JSON file keyed by GenBank accessions and valued by the retrieved protein sequence
+
 ## Extracting protein sequences from the local CAZyme database and building a BLAST database
 
 Protein sequences from GenBank and UniProt that are stored in the local CAZyme database can be extracted using `cazy_webscraper`, and written to any combination of:
@@ -367,16 +392,23 @@ Protein sequences from GenBank and UniProt that are stored in the local CAZyme d
 
 To extract all protein seqeunces from the local CAZyme database using the following command structure:
 ```bash
-cw_extract_sequences <path_to_local_CAZyme_db> --genbank --uniprot
+cw_extract_db_sequences <path_to_local_CAZyme_db> genbank uniprot
 ```
 
+To retrieve protein sequences from GenBank or UniProt, name only the respective database. For example, to retrieve only 
+GenBank proteins:
+```bash
+cw_extract_db_sequences <path_to_local_CAZyme_db> genbank
+```
+
+
 ### Configuring extracting sequences from a local CAZyme db
 
 Below are listed the command-line flags for configuring the extraction of protein sequences from the local CAZyme db.
 
 `database` - \[REQUIRED\] Path to a local CAZyme database to add UniProt data to.
 
-`source` - \[REQUIRED\] Define source databases of protein sequences. Accepts 'genbank' and 'uniprot'. To list both, separate with a single space, e.g.   
+`source` - \[REQUIRED\] Define source databases of protein sequences. Accepts 'genbank' and 'uniprot'. To list both, separate with a single space (' ')
 ```bash
 cw_extract_sequence cazy_database.db genbank uniprot
 ```
@@ -443,6 +475,14 @@ To retrieve structure files for all proteins in a local CAZyme database in `mmCi
 cw_get_pdb_structures <path_to_local_CAZyme_db> mmcif,pdb
 ```
 
+Protein structure files can be retrieved in a variety of formats, including:
+
+- mmCif (default, PDBx/mmCif file),
+- pdb (format PDB),
+- xml (PDBML/XML format),
+- mmtf (highly compressed),
+- bundle (PDB formatted archive for large structure}
+
 ### Configuring PDB protein structure file retrieval
 
 Below are listed the command-line flags for configuring the retrieval of protein structure files from PDB.
@@ -455,11 +495,13 @@ Below are listed the command-line flags for configuring the retrieval of protein
 - `xml`
 - `mmft`
 - `bundle`
-To chose multiple file types, list all desired file types, separting the files using a single comma. For example:
+To chose multiple file types, list all desired file types, separting the files using a single space (' '). For example:
 ```bash
-cw_get_genbank_seq my_cazyme_db/cazyme_db.db mmcif,pdb,xml
+cw_get_genbank_seq my_cazyme_db/cazyme_db.db mmcif pdb xml
 ```
-Providing the file types is **not** case sensitive, and the order the file types are listed does **not** matter.
+Providing the file types **is** case sensitive, but the order the file types are listed does **not** matter.
+
+`--batch_size` - Size of an individual batch query of PDB accessions submitted to PDB. Default is 150.
 
 `--cache_dir` - Path to cache dir to be used instead of default cache dir path.
 
@@ -480,6 +522,8 @@ cw_get_uniprot_data my_cazyme_db/cazyme_db.db --ec_filter 'EC1.2.3.4,EC2.3.1.-'
 
 `--genera` - List of genera to restrict the scrape to. Default: None, filter not applied to scrape.
 
+`--kingdoms` - List of taxonomy kingdoms to retrieve UniProt data for.
+
 `--log`, `-l` - Target path to write out a log file. If not called, no log file is written. Default: None (no log file is written out).
 
 `--nodelete` - When called, content in the existing output dir will **not** be deleted. Default: False (existing content is deleted).
@@ -488,6 +532,8 @@ cw_get_uniprot_data my_cazyme_db/cazyme_db.db --ec_filter 'EC1.2.3.4,EC2.3.1.-'
 
 `--outdir`, `-o` - Output directory to write out downloaded protein structure files to. Default is to write out the downloaded structure files to the current working directory.
 
+`--overwrite` - Overwrite existing structure files with the same PDB accession as files being downloaded. Default false, do not overwrite existing files.
+
 `--retries`, `-r` - Define the number of times to retry making a connection to CAZy if the connection should fail. Default: 10.
 
 `--sql_echo` - Set SQLite engine echo parameter to True, causing SQLite to print log messages. Default: False.
@@ -527,6 +573,25 @@ write them to a `json` file, the following command could be used for a database
 cw_query_database cazy.db json
 ```
 
+By default the output is written to the current working directory. A specific output directory (which can be built by `cazy_webscraper`) can be defined using the `-o`/`--output_dir` flag, followed by the path of the desired output directory.
+
+The file names of all output files are composed of the name of the local CAZyme database, followed by the names of the data retrieved from the local CAZyme database. For example, retrieving the following data from the local CAZyme database called `cazy_database.db`:
+- CAZy family annotation
+- CAZy subfamily annotations
+- EC numbers
+- PDB accessions
+Will produce the following file name: `cazy_database_gbkAcc_fams_subfams_ec_pdb`.  
+
+An optional prefix can be applied to all output file names using the `-p`/`--prefix` flag, followed by the desired prefix. For example, using the same example as above, the prefix 'engineering_candidates_` can be applied to every output file by adding the following to command:
+```bash
+--prefix engineering_candidates_
+```
+This will produce output files with the file name `engineering_candidates_cazy_database_gbkAcc_fams_subfams_ec_pdb`.
+
+`_gbkAcc` is always included in the file name because GenBank accessions are always retrieved and written to the output by cthe api.
+
+The data retrieved from the local CAZyme database and included in the final output is defined using the `--include` flag, followed by a list of all data to *include* in the output, with each data separated with a single space.
+
 ### Configuring interrogating the local CAZyme database
 
 Below are listed the command-line flags for configuring the interrogation of the local CAZyme database.
@@ -544,32 +609,41 @@ Below are listed the command-line flags for configuring the interrogation of the
 
 `--classes` - List of classes from which all families are to be retrieval.
 
-`--ec` - Included EC number annotations in the output
-
 `--ec_filter` - Limist retrieval of protein data to proteins annotated with a provided list of EC numbers. Separate the EC numbers bu single commas without spaces. Recommend to wrap the entire str in quotation marks, for example:
 ```bash
 cw_get_uniprot_data my_cazyme_db/cazyme_db.db --ec_filter 'EC1.2.3.4,EC2.3.1.-'
 ```
 
-`--family` - Include CAZy family annotations in the output.
-
 `--families` - List of CAZy (sub)families to retrieve CAZymes from. This includes families and SUBfamilies.
 
-`--genus` - Include a 'Genus' column in the output `csv` file, listing the genus for each retrieved CAZymes
+`--force`, `-f` - force writing to existing output dir.
 
 `--genera` - List of genera to restrict the retrieval to. Default: None, filter not applied to scrape.
 
+`--include` - List additional data to include in the output. Multiple fields can be named, separating each with a single space (' '). The accepted fields are:
+- 'class' - Include the CAZy class annotations
+- 'family' - Include the CAZy family annotations
+- 'subfamily' - Include the subfamily class annotations
+- 'uniprot_acc' - Include the UniProt accession
+- 'uniprot_name' - Include the protein name retrieved from UniProt
+- 'ec' - Include the EC number annotations
+- 'pdb' - Include the PDB accessions
+- 'genbank_seq' - Include the GenBank protein sequence
+- 'uniprot_seq' - Include the Uniprot protein sequence
+
+`--kingdoms` - List of taxonomy kingdoms to retrieve UniProt data for.
+
 `--log`, `-l` - Target path to write out a log file. If not called, no log file is written. Default: None (no log file is written out).
 
 `--nodelete` - When called, content in the existing output dir will **not** be deleted. Default: False (existing content is deleted).
 
-`--organism` - Include the scientific (organism) name of the source organis
+`--nodelete_cache` - When called, content in the existing cache dir will **not** be deleted. Default: False (existing content is deleted).
 
-`--output`, `-o` - Output path to write the compiled `csv` file. Default is to write out the `csv` file to the current working directory.
+`--output_dir`, `-o` - Output path to write the compiled `csv` file. Default is to write out the `csv` file to the current working directory.
 
-`--seq_genbank` - Add the protein sequences retrieved from GenBank to the query output
+`--overwrite` - Overwrite existing output files. Default: False, program closes if output already exists"
 
-`--seq_uniprot` - Add the protein sequences retrieved from GenBank to the query output
+`--prefix`, `-p` - Prefix of output files, default none.
 
 `--sql_echo` - Set SQLite engine echo parameter to True, causing SQLite to print log messages. Default: False.
 
@@ -577,10 +651,6 @@ cw_get_uniprot_data my_cazyme_db/cazyme_db.db --ec_filter 'EC1.2.3.4,EC2.3.1.-'
 
 `--strains` - List of specific species strains to restrict the retrieval of CAZymes to.
 
-`--subfamily` - Include the CAZy subfamily annotations for proteins matching the criteria of interest.
-
-`--uniprot` - Include the UniProt protein accession and protein name in the output.
-
 `--verbose`, `-v` - Enable verbose logging. This does not set the SQLite engine `echo` parameter to True. Default: False.
 
 
diff --git a/cazy_webscraper/__init__.py b/cazy_webscraper/__init__.py
index 5a9b5f77..c1133e8a 100644
--- a/cazy_webscraper/__init__.py
+++ b/cazy_webscraper/__init__.py
@@ -53,7 +53,7 @@
 from cazy_webscraper.sql import sql_orm
 
 
-__version__ = "2.0.0-beta"
+__version__ = "2.0.6-beta"
 
 VERSION_INFO = f"cazy_webscraper version: {__version__}"
 
diff --git a/cazy_webscraper/api/cw_query_database.py b/cazy_webscraper/api/cw_query_database.py
index 4ba6ce31..44660023 100644
--- a/cazy_webscraper/api/cw_query_database.py
+++ b/cazy_webscraper/api/cw_query_database.py
@@ -5,10 +5,10 @@
 # (c) James Hutton Institute 20201
 # Author:
 # Emma E. M. Hobbs
-
+#
 # Contact
 # eemh1@st-andrews.ac.uk
-
+#
 # Emma E. M. Hobbs,
 # Biomolecular Sciences Building,
 # University of St Andrews,
@@ -17,7 +17,7 @@
 # KY16 9ST
 # Scotland,
 # UK
-
+#
 # The MIT License
 #
 # Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -26,10 +26,10 @@
 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 # copies of the Software, and to permit persons to whom the Software is
 # furnished to do so, subject to the following conditions:
-
+#
 # The above copyright notice and this permission notice shall be included in all
 # copies or substantial portions of the Software.
-
+#
 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -42,19 +42,22 @@
 
 import logging
 import json
+import re
+import sys
 
 import pandas as pd
 
 from datetime import datetime
+from pathlib import Path
 from typing import List, Optional
 
 from saintBioutils.utilities.logger import config_logger
 from saintBioutils.utilities import file_io
 from tqdm import tqdm
 
-from cazy_webscraper import cazy_scraper
+from cazy_webscraper import cazy_scraper, closing_message
 from cazy_webscraper.sql.sql_interface import get_selected_gbks, get_api_data
-from cazy_webscraper.utilities.parsers import query_db_parser
+from cazy_webscraper.utilities.parsers import api_parser
 from cazy_webscraper.utilities.parse_configuration import get_expansion_configuration
 
 
@@ -66,17 +69,20 @@ def main(argv: Optional[List[str]] = None, logger: Optional[logging.Logger] = No
 
     # Program preparation
     if argv is None:
-        parser = query_db_parser.build_parser()
+        parser = api_parser.build_parser()
         args = parser.parse_args()
     else:
-        parser = query_db_parser.build_parser(argv)
+        parser = api_parser.build_parser(argv)
         args = parser.parse_args()
 
     if logger is None:
         logger = logging.getLogger(__name__)
         config_logger(args)
 
-    connection, logger_name, cache_dir = cazy_scraper.connect_existing_db(args, time_stamp)
+    connection, logger_name, cache_dir = cazy_scraper.connect_existing_db(args, time_stamp, start_time)
+
+    if args.output_dir is not None:
+        file_io.make_output_directory(args.output_dir, args.force, args.nodelete)
 
     if args.cache_dir is not None:  # use user defined cache dir
         cache_dir = args.cache_dir
@@ -94,6 +100,41 @@ def main(argv: Optional[List[str]] = None, logger: Optional[logging.Logger] = No
         ec_filters,
     ) = get_expansion_configuration(args)
 
+    output_path = compile_output_name(args)
+
+    existing_files = ""
+    if 'json' in args.file_types:
+        json_output_path = output_path + ".json"
+        logger.warning(f"JSON output path: {json_output_path}")
+        if Path(json_output_path).exists():
+            existing_files = existing_files + " " + f"{json_output_path}\n"
+    
+    if 'csv' in args.file_types:
+        csv_output_path = output_path + ".csv"
+        logger.warning(f"CSV output path: {csv_output_path}")
+        if Path(csv_output_path).exists():
+            existing_files = existing_files + " " + f"{csv_output_path}\n"
+    
+    existing_files = existing_files.strip()
+    if len(existing_files) != 0:
+        if args.overwrite:
+            logger.warning(
+                "The output files\n"
+                f"{existing_files}"
+                "Exist already. Overwrite is True. Overwriting output files"
+            )
+        else:
+            logger.warning(
+                "The output files\n"
+                f"{existing_files}"
+                "Exist already. Overwrite is False\n"
+                "To overwrite the files use the --overwrite flag, or "
+                "change the output file prefix using the --prefix flag\n"
+                "Terminating program"
+            )
+            closing_message("cw_query_database", start_time, args)
+            sys.exit(1)
+
     # get the records of GenBank accessions matching the criteria of interest
     # {gbk_acc: gbk_id}
     gbk_dict = get_selected_gbks.get_genbank_accessions(
@@ -105,9 +146,68 @@ def main(argv: Optional[List[str]] = None, logger: Optional[logging.Logger] = No
         connection,
     )
 
-    query_data = get_query_data(gbk_dict)
+    query_data = get_query_data(gbk_dict, connection, args)
+    logger.warning(f"Retrieved {len(list(query_data.keys()))} proteins from the local db")
+    
+    if 'json' in args.file_types:
+        write_json_output(json_output_path, query_data, args)
+
+    if 'csv' in args.file_types:
+        write_csv_output(query_data, args, csv_output_path)
+    
+    closing_message("cw_query_database", start_time, args)
+
+
+def compile_output_name(args):
+    """Compile the file name for output files.
+    
+    :param args: cmd-line args parser
+    
+    Return str"""
+    file_prefix = f"{args.database.name.replace('.db', '')}"
+    if args.prefix is not None:
+        file_prefix = f"{args.prefix}_{file_prefix}"
 
-    write_output(query_data, args)
+    file_prefix += "_gbkAcc"
+    
+    # CAZy classification info
+    if 'class' in args.include:
+        file_prefix += "_classes"
+    if 'family' in args.include:
+        file_prefix += "_fams"
+    if 'subfamily' in args.include:
+        file_prefix += "_subfams"
+    
+    # tax infor
+    if 'kingdom' in args.include:
+        file_prefix += "_kngdm"
+    if 'genus' in args.include:
+        file_prefix += "_genus"
+    if 'organism' in args.include:
+        file_prefix += "_orgnsm"
+
+    # data from genbank
+    if "genbank_seq" in args.include:
+        file_prefix += "_gbkSeq"
+
+    # data from uniprot
+    if 'uniprot_acc' in args.include:
+        file_prefix += "_uni_acc"
+    if 'uniprot_name' in args.include:
+        file_prefix += "_uni_name"
+    if "ec" in args.include:
+        file_prefix += "_ec"
+    if "pdb" in args.include:
+        file_prefix += "_pdb"
+    if "uniprot_seq" in args.include:
+        file_prefix += "_uniprotSeq"
+
+    if args.output_dir is not None:
+        output_path = args.output_dir / file_prefix
+    else:
+        output_path = file_prefix
+    
+    return output_path
 
 
 def get_query_data(gbk_dict, connection, args):
@@ -146,125 +246,187 @@ def get_query_data(gbk_dict, connection, args):
     for gbk_acc in gbk_dict:
         query_data[gbk_acc] = {}
 
-    if args.cazy_class or args.cazy_family or args.cazy_subfamily:
+    if ('class' in args.include) or ('family' in args.include) or ('subfamily' in args.include):
         # retrieve the CAZy family annotations from the local CAZyme database
         query_data = get_api_data.get_class_fam_annotations(gbk_dict, query_data, connection, args)
 
-    if args.kingdom or args.genus or args.organism:
+    if ('kingdom' in args.include) or ('genus' in args.include) or ('organism' in args.include):
         # retrieve the taxonomy data from the local CAZyme database
         query_data = get_api_data.get_tax_annotations(gbk_dict, query_data, connection, args)
 
-    if args.ec:
+    if 'ec' in args.include:
        # retrieve the ec numbers from the local CAZyme database
        query_data = get_api_data.get_ec_annotations(gbk_dict, query_data, connection)
 
-    if args.pdb:
+    if 'pdb' in args.include:
         # retrieve the PDB accessions from the local CAZyme database
         query_data = get_api_data.get_pdb_accessions(gbk_dict, query_data, connection)
 
-    if args.uniprot or args.seq_uniprot:
+    if ('uniprot_acc' in args.include) or ('uniprot_name' in args.include) or ('uniprot_seq' in args.include):
         # retrieve the UniProt data from the local CAZyme database
         query_data = get_api_data.get_uniprot_data(gbk_dict, query_data, connection, args)
 
-    if args.seq_genbank:
+    if 'genbank_seq' in args.include:
         # retrieve GenBank protein sequences from the local CAZyme database
         query_data = get_api_data.get_gbk_seq(gbk_dict, query_data, connection)
 
+    return query_data
+
+
+def write_json_output(json_output_path, query_data, args):
+    """Parse dict to be suitable for JSON serialisation and write out output.
+    
+    query_data = {
+        genbank_accession: 
+            'class': {CAZy classes},
+            'family': {CAZy families},
+            'subfamily': {CAZy subfamilies},
+            'kingdom': kingdom,
+            'genus': genus,
+            'organism': genus species strain,
+            'ec_numbers': {EC number annotations},
+            'pdb_accessions': {PDB accessions},
+            'uniprot_accession': UniProt protein accession,
+            'uniprot_name': Name of the protein from UniProt,
+            'uniprot_sequence': Protein Aa seq from UniProt,
+            'uniprot_sequence_date': Date the seq was last modified in UniProt,
+            'gbk_sequence': Protein Aa seq from GenBank
+            'gbk_sequence_date': Date the seq was last modified in Gbk,
+    }
 
-def write_output(query_data, args, time_stamp):
-    """Write out query data to disk.
+    Return nothing
+    """
+    set_keys = [
+        'class',
+        'family',
+        'subfamily',
+        'ec_numbers',
+        'pdb_accessions',
+    ]
+    for genbank_accession in query_data:
+        for key in set_keys:
+            try:
+                query_data[genbank_accession][key] = list(query_data[genbank_accession][key])
+            
+            except KeyError:  # raised when data was not retrieved from the db
+                pass
+
+    with open(json_output_path, 'w') as fh:
+        json.dump(query_data, fh)
+
+
+def write_csv_output(query_data, args, output_path):
+    """Parse the output into a df structure and write out to a csv file.
     
     :param query_data: dict containing db query data.
     :param args: cmd-line args parser
+    :param output_path: Path to write out output
     
-    Return nothing"""
-    output_path = compile_output_name(args, time_stamp)
+    Return nothing.
+    """
+    column_names = get_column_names(args)
 
-    if 'json' in args.file_types:
-        output_path += ".json"
-        with open(output_path, 'w') as fh:
-            json.dump(query_data, fh)
+    df_data = []  # list of nested lists, one nested list per df row
 
-    if 'csv' in args.file_types:
-        output_path += ".csv"
+    for gbk_acc in tqdm(query_data, desc="Compiling output dataframe"):
+        new_rows = []
 
-        # compile pandas df of the data
-        column_names = get_column_names(args)
+        if (('class' not in args.include) and ('family' not in args.include) and ('subfamily' not in args.include)):
+            new_rows.append([gbk_acc])  # don't need to create multiple rows to separate the class/fam/subfam annotations
         
-        df_data = []  # list of nested lists, one nested list per df row
-
-        for gbk_acc in tqdm(query_data, desc="Compiling output dataframe"):
-            new_rows = []
-
+        else:
             # create one row for each CAZy class, CAZy family and CAZy subfamily annotation
             # link the parent-child relationships between CAZy class, family and subfamily
-            if args.cazy_class is False and args.cazy_family is False and args.cazy_subfamily is False:
-                new_rows.append([gbk_acc])  # don't need to create multiple rows to separate the class/fam/subfam annotations
-
-            if args.kingdom:
-                for row in new_rows:
-                    row.append(query_data[gbk_acc]["kingdom"])
-            if args.genus:
-                for row in new_rows:
-                    row.append(query_data[gbk_acc]["genus"])
-            if args.organism:
-                for row in new_rows:
-                    row.append(query_data[gbk_acc]["organism"])
-            if args.ec:
-                for row in new_rows:
-                    row.append(" ".join(list(query_data[gbk_acc]["ec_numbers"])))
-            if args.pdb:
-                for row in new_rows:
-                    row.append(" ".join(list(query_data[gbk_acc]["pdb_accessions"])))
-            if args.uniprot:
-                for row in new_rows:
-                    row.append(query_data[gbk_acc]["uniprot_accession"])
-                    row.append(query_data[gbk_acc]["uniprot_name"])
-            if args.seq_uniprot:
-                for row in new_rows:
-                    row.append(query_data[gbk_acc]["uniprot_sequence"])
-                    row.append(query_data[gbk_acc]["uniprot_sequence_date"])
-            if args.seq_genbank:
-                for row in new_rows:
-                    row.append(query_data[gbk_acc]["gbk_sequence"])
-                    row.append(query_data[gbk_acc]["gbk_sequence_date"])
-
+            new_rows = get_class_fam_relationships(gbk_acc, query_data, args)
+
+        # data from CAZy
+        if 'kingdom' in args.include:
+            new_rows = add_single_value_to_rows(query_data, gbk_acc, 'kingdom', new_rows)
+        if 'genus' in args.include:
+            new_rows = add_single_value_to_rows(query_data, gbk_acc, 'genus', new_rows)
+        if 'organism' in args.include:
+            new_rows = add_single_value_to_rows(query_data, gbk_acc, 'organism', new_rows)
+        
+        # data from GenBank
+        if "genbank_seq" in args.include:
+            try:
+                seq = query_data[gbk_acc]["gbk_sequence"]
+            except KeyError:
+                seq = None
+            
+            try:
+                date = query_data[gbk_acc]["gbk_sequence_date"]
+            except KeyError:
+                date = None
+    
+            for row in new_rows:
+                row.append(seq)
+                row.append(date)
+        
+        # data from UniProt
+        if 'uniprot_acc' in args.include:
+            new_rows = add_single_value_to_rows(query_data, gbk_acc, 'uniprot_accession', new_rows)
+
+        if 'uniprot_name' in args.include:
+            new_rows = add_single_value_to_rows(query_data, gbk_acc, 'uniprot_name', new_rows)
+
+        if "ec" in args.include:
+            try:
+                ec_numbers = " ".join(list(query_data[gbk_acc]["ec_numbers"]))
+            except KeyError:
+                ec_numbers = None
+            for row in new_rows:
+                row.append(ec_numbers)
+            
+        if "pdb" in args.include:
+            try:
+                pdb_accessions = " ".join(list(query_data[gbk_acc]["pdb_accessions"]))
+            except KeyError:
+                pdb_accessions = None
+            for row in new_rows:
+                row.append(pdb_accessions)
+            
+        if "uniprot_seq" in args.include:
+            try:
+                seq = query_data[gbk_acc]["uniprot_sequence"]
+            except KeyError:
+                seq = None
+            
+            try:
+                date = query_data[gbk_acc]["uniprot_sequence_date"]
+            except KeyError:
+                date = None
+    
             for row in new_rows:
-                df_data.append(row)
-
-        query_df = pd.DataFrame(df_data, columns=column_names)
-
-        query_df.to_csv(output_path)
-
-
-def compile_output_name(args, time_stamp):
-    db_name = args.database.name.replace(".db","")
-    output_path = args.output_dir / f"{db_name}_{time_stamp}"
-
-    if args.cazy_class:
-        output_path += "_classes"
-    if args.cazy_family:
-        output_path += "_fams"
-    if args.cazy_subfamily:
-        output_path += "_subfams"
-    if args.kingdom:
-        output_path += "_kngdm"
-    if args.genus:
-        output_path += "_genus"
-    if args.organism:
-        output_path += "_orgnsm"
-    if args.ec:
-        output_path += "_ec"
-    if args.pdb:
-        output_path += "_pdb"
-    if args.uniprot:
-        output_path += "_uniprot"
-    if args.seq_uniprot:
-        output_path += "_uniprotSeq"
-    if args.seq_genbank:
-        output_path += "_gbkSeq"
+                row.append(seq)
+                row.append(date)
 
-    return output_path
+        for row in new_rows:
+            df_data.append(row)
+
+    query_df = pd.DataFrame(df_data, columns=column_names)
+
+    query_df.to_csv(output_path)
+
+
+def add_single_value_to_rows(query_data, gbk_acc, key, new_rows):
+    """Retrieve value for key from query data for the given protein, add value to all new_rows.
+    
+    :param query_data: dict
+    :param gbk_acc: str
+    :param key: str
+    :param new_rows: list of lists
+    
+    Return new_rows
+    """
+    try:
+        value = query_data[gbk_acc][key]
+    except KeyError:
+        value = None
+    for row in new_rows:
+        row.append(value)
+    
+    return new_rows
 
 
 def get_column_names(args):
@@ -275,34 +437,155 @@ def get_column_names(args):
     Return list of column names"""
     column_names = ["genbank_accession"]
 
-    if args.cazy_class:
+    # data from CAZy
+    if 'class' in args.include:
         column_names.append("class")
-    if args.cazy_family:
+    if 'family' in args.include:
         column_names.append("family")
-    if args.cazy_subfamily:
+    if 'subfamily' in args.include:
         column_names.append("subfamily")
-    if args.kingdom:
+    if 'kingdom' in args.include:
         column_names.append("kingdom")
-    if args.genus:
+    if 'genus' in args.include:
         column_names.append("genus")
-    if args.organism:
+    if 'organism' in args.include:
         column_names.append("source_organism")
-    if args.ec:
-        column_names.append("ec_number")
-    if args.pdb:
-        column_names.append("pdb_accession")
-    if args.uniprot:
+
+    # data from GenBank
+    if 'genbank_seq' in args.include:
+        column_names.append("genbank_sequence")
+        column_names.append("genbank_sequence_date")
+
+    # data from UniProt
+    if 'uniprot_acc' in args.include:
         column_names.append("uniprot_accession")
+    if 'uniprot_name' in args.include:
         column_names.append("uniprot_name")
-    if args.seq_uniprot:
+    if 'ec' in args.include:
+        column_names.append("ec_number")
+    if 'pdb' in args.include:
+        column_names.append("pdb_accession")
+    if 'uniprot_seq' in args.include:
         column_names.append("uniprot_sequence")
         column_names.append("uniprot_sequence_date")
-    if args.seq_genbank:
-        column_names.append("genbank_sequence")
-        column_names.append("genbank_sequence_date")
 
     return column_names
 
 
+def get_class_fam_relationships(gbk_acc, protein_query_data, args):
+    """Define CAZy class-family-subfamily relationships in the query data.
+    
+    :param gbk_acc: str, GenBank protein accession
+    :param query_data: dict, data retrieved from the local CAZyme database for the specific protein
+        {
+            'class': {CAZy classes},
+            'family': {CAZy families},
+            'subfamily': {CAZy subfamilies},
+        }
+    :param args: cmd-line args parser
+    
+    Return list of nested lists, one nested list per relationship.
+    """
+    logger =logging.getLogger(__name__)
+
+    new_rows = []
+
+    # class only
+    if ('class' in args.include) and ('family' not in args.include) and ('subfamily' not in args.include):
+        classes = protein_query_data[gbk_acc]['class']
+        for cazy_class in classes:
+            new_rows.append([gbk_acc, cazy_class])
+
+    # family only
+    elif ('class' not in args.include) and ('family' in args.include) and ('subfamily' not in args.include):
+        families = protein_query_data[gbk_acc]['family']
+        for family in families:
+            new_rows.append([gbk_acc, family])
+
+    # subfamily only
+    elif ('class' not in args.include) and ('family' not in args.include) and ('subfamily' in args.include):
+        subfamilies = protein_query_data[gbk_acc]['subfamily']
+        for subfamily in subfamilies:
+            new_rows.append([gbk_acc, subfamily])
+
+    # class and family, NO subfamily
+    elif ('class' in args.include) and ('family' in args.include) and ('subfamily' not in args.include):
+        families = protein_query_data[gbk_acc]['family']
+        for family in families:
+            try:
+                parent_class = re.match(r'\D{2,3}', family).group()
+            except AttributeError:
+                logger.warning(f"Could not retrieve CAZy class from {family}, setting CAZy class as 'NA'")
+                parent_class = 'NA'
+            new_rows.append([gbk_acc, parent_class, family])
+
+    # class and subfamily, NO family
+    elif  ('class' in args.include) and ('family' not in args.include) and ('subfamily' in args.include):
+        subfamilies = protein_query_data[gbk_acc]['subfamily']
+        for subfamily in subfamilies:
+            try:
+                parent_class = re.match(r'\D{2,3}', subfamily).group()
+            except AttributeError:
+                logger.warning(f"Could not retrieve CAZy class from {subfamily}, setting CAZy class as 'NA'")
+                parent_class = 'NA'
+            new_rows.append([gbk_acc, parent_class, subfamily])
+
+    # family and subfamily, NO class
+    elif  ('class' not in args.include) and ('family' in args.include) and ('subfamily' in args.include):
+        subfamilies = protein_query_data[gbk_acc]['subfamily']
+        added_families = set()
+        for subfamily in subfamilies:
+            try:
+                parent_fam = subfamily.split("_")[0]
+                added_families.add(parent_fam)
+            except AttributeError:
+                logger.warning(f"Could not retrieve CAZy family from {subfamily}, setting CAZy family as 'NA'")
+                parent_fam = 'NA'
+            new_rows.append([gbk_acc, parent_fam, subfamily])
+
+        # add remaining families for which there is no subfamily annotation
+        families = protein_query_data[gbk_acc]['family']
+        for family in families:
+            if family not in added_families:
+                new_rows.append([gbk_acc, family, None])
+
+    # class, family and subfamily
+    else:
+        subfamilies = protein_query_data[gbk_acc]['subfamily']
+        added_families = set()
+        for subfamily in subfamilies:
+
+            # get the parent family
+            try:
+                parent_fam = subfamily.split("_")[0]
+                added_families.add(parent_fam)
+            except AttributeError:
+                logger.warning(f"Could not retrieve CAZy family from {subfamily}, setting CAZy family as 'NA'")
+                parent_fam = 'NA'
+
+            # get the parent class
+            try:
+                parent_class = re.match(r'\D{2,3}', subfamily).group()
+            except AttributeError:
+                logger.warning(f"Could not retrieve CAZy class from {subfamily}, setting CAZy class as 'NA'")
+                parent_class = 'NA'
+
+            new_rows.append([gbk_acc, parent_class, parent_fam, subfamily])
+        
+        # add remaining families for which there is no subfamily annotation
+        families = protein_query_data[gbk_acc]['family']
+
+        for family in families:
+            if family not in added_families:
+                try:
+                    parent_class = re.match(r'\D{2,3}', family).group()
+                except AttributeError:
+                    logger.warning(f"Could not retrieve CAZy class from {family}, setting CAZy class as 'NA'")
+                    parent_class = 'NA'
+                new_rows.append([gbk_acc, parent_class, family, 'NA'])
+
+    return new_rows
+
+
 if __name__ == "__main__":
     main()
diff --git a/cazy_webscraper/cazy_scraper.py b/cazy_webscraper/cazy_scraper.py
index 9bdb931e..8eb3ccf8 100644
--- a/cazy_webscraper/cazy_scraper.py
+++ b/cazy_webscraper/cazy_scraper.py
@@ -77,6 +77,7 @@
 from pathlib import Path
 from typing import List, Optional
 from saintBioutils.utilities.file_io import make_output_directory
+from saintBioutils.utilities.logger import config_logger, build_logger
 
 from Bio import Entrez
 from cazy_webscraper import (
@@ -100,8 +101,6 @@
 from cazy_webscraper.sql import sql_orm, sql_interface
 from cazy_webscraper.sql.sql_interface import add_cazyme_data
 from cazy_webscraper.utilities import (
-    build_logger,
-    config_logger,
     parse_configuration,
     termcolour,
 )
@@ -152,14 +151,14 @@ def main(argv: Optional[List[str]] = None, logger: Optional[logging.Logger] = No
     if args.db_output is not None and args.db_output.exists():
         if args.force:
             logger.warning(
-                f"Local db {args.database} already exists\n"
+                f"Local db {args.db_output} already exists\n"
                 "Force is True\n"
                 "Ovewriting existing database."
             )
             os.remove(args.db_output)
         else:
             logger.warning(
-                f"Local db {args.database} already exists\n"
+                f"Local db {args.db_output} already exists\n"
                 "Force is False\n"
                 "Not ovewriting existing database\n"
                 "Termianting program"
@@ -201,9 +200,8 @@ def main(argv: Optional[List[str]] = None, logger: Optional[logging.Logger] = No
 
     logger.info(termcolour(scrape_config_message, "cyan"))
 
-    if args.database:  # adding data to an EXISTING database
+    if args.database is not None:  # adding data to an EXISTING database
         connection, logger_name, cache_dir = connect_existing_db(args, time_stamp, start_time)
-    
     else:  # build a new database
         connection, logger_name, cache_dir = connect_to_new_db(args, time_stamp, start_time)
 
@@ -227,16 +225,16 @@ def main(argv: Optional[List[str]] = None, logger: Optional[logging.Logger] = No
     else:
         make_output_directory(cache_dir, args.force, args.nodelete_cache)
 
-    logger.info(f"Created cache dir: {cache_dir}")
+    logger.warning(f"Created cache dir: {cache_dir}")
 
     if args.log is not None:  # write additional log files to user specified dir
-        logger_name = args.log.split(".")[0]
+        logger_name = args.log.name
+        if logger_name.endswith(".log"):
+            logger_name = logger_name[:-4]
+        make_output_directory(args.log, args.force, args.nodelete_log)
     else:
-        # write the additional log files to the .cazy_webscraper/log dir
-        logger_dir = Path(f"{str(cache_dir.parent)}/logs")
-        make_output_directory(logger_dir, args.force, args.nodelete_log)
-        # add logger dir path to the logger name
-        logger_name = f"{logger_dir}/{str(Path(logger_name).name)}"
+        # write the additional log files to the .cazy_webscraper cache dire
+        logger_name = "log"
 
     logger.info("Starting retrieval of data from CAZy")
 
@@ -301,9 +299,9 @@ def get_cazy_data(
 
     # define paths for additional logs files
     # unless specifed they are added to the logs dir in the cache dir
-    connection_failures_logger = build_logger(Path(f"{logger_name}_{time_stamp}_connection_failures.log"))
-    multiple_taxa_logger = build_logger(Path(f"{logger_name}_{time_stamp}_multiple_taxa.log"))
-    replaced_taxa_logger = build_logger(Path(f"{logger_name}_{time_stamp}_replaced_taxa.log"))
+    connection_failures_logger = build_logger(cache_dir, f"{logger_name}_{time_stamp}_connection_failures.log")
+    multiple_taxa_logger = build_logger(cache_dir, f"{logger_name}_{time_stamp}_multiple_taxa.log")
+    replaced_taxa_logger = build_logger(cache_dir, f"{logger_name}_{time_stamp}_replaced_taxa.log")
 
     if args.validate:  # retrieve CAZy family population sizes for validating all data was retrieved
         # {fam (str): pop size (int)}
diff --git a/cazy_webscraper/expand/extract_seqs/extract_db_seqs.py b/cazy_webscraper/expand/extract_seqs/extract_db_seqs.py
index 17361465..b1e0c201 100644
--- a/cazy_webscraper/expand/extract_seqs/extract_db_seqs.py
+++ b/cazy_webscraper/expand/extract_seqs/extract_db_seqs.py
@@ -56,16 +56,17 @@
 from Bio.Blast.Applications import NcbimakeblastdbCommandline
 from Bio.Seq import Seq
 from Bio.SeqRecord import SeqRecord
-
+from saintBioutils.utilities.file_io import make_output_directory
+from saintBioutils.utilities.file_io import make_output_directory
+from saintBioutils.utilities.logger import config_logger
 
 from cazy_webscraper import closing_message, connect_existing_db
-from cazy_webscraper.expand import get_chunks_gen
 from cazy_webscraper.sql.sql_interface import get_selected_gbks, get_table_dicts
 from cazy_webscraper.sql.sql_interface.get_records import (
     get_user_genbank_sequences,
     get_user_uniprot_sequences
 )
-from cazy_webscraper.utilities import config_logger, file_io, parse_configuration
+from cazy_webscraper.utilities import parse_configuration
 from cazy_webscraper.utilities.parsers.extract_seq_parser import build_parser
 
 
@@ -90,18 +91,18 @@ def main(argv: Optional[List[str]] = None, logger: Optional[logging.Logger] = No
     # make output directories
     if args.fasta_file:
         target_dir = args.fasta_file.parent
-        file_io.make_output_directory(target_dir, args.force, args.nodelete)
+        make_output_directory(target_dir, args.force, args.nodelete)
     if args.fasta_dir:
-        file_io.make_output_directory(args.fasta_dir, args.force, args.nodelete)
+        make_output_directory(args.fasta_dir, args.force, args.nodelete)
 
     connection, logger_name, cache_dir = connect_existing_db(args, time_stamp, start_time)
 
     if args.cache_dir is not None:  # use user defined cache dir
         cache_dir = args.cache_dir
-        file_io.make_output_directory(cache_dir, args.force, args.nodelete_cache)
+        make_output_directory(cache_dir, args.force, args.nodelete_cache)
     else:
         cache_dir = cache_dir / "sequence_extraction"
-        file_io.make_output_directory(cache_dir, args.force, args.nodelete_cache)
+        make_output_directory(cache_dir, args.force, args.nodelete_cache)
 
     (
         config_dict,
@@ -162,15 +163,25 @@ def main(argv: Optional[List[str]] = None, logger: Optional[logging.Logger] = No
     protein_records = []
     
     for protein_accession in tqdm(extracted_sequences, "Compiling SeqRecords"):
-        new_record = SeqRecord(
-            Seq(extracted_sequences[protein_accession]['seq']),
-            id=protein_accession,
-            description=extracted_sequences[protein_accession]['db']
-        )
-        protein_records.append(new_record)
+        try:
+            new_record = SeqRecord(
+                Seq(extracted_sequences[protein_accession]['seq']),
+                id=protein_accession,
+                description=extracted_sequences[protein_accession]['db']
+            )
+            protein_records.append(new_record)
+        except TypeError:
+            if extracted_sequences[protein_accession]['seq'] is not None:
+                logger.warning(
+                    f"Seq for {protein_accession} retrieved as type {type(extracted_sequences[protein_accession]['seq'])}\n"
+                    "Not adding to FASTA file"
+                )
+            pass  # passed when sequence is None
 
     # write out the sequences to the specified outputs
 
+    logger.warning(f"Extracted {len(protein_records)}")
+
     write_output(protein_records, cache_dir, args)
 
     closing_message("extract_sequences", start_time, args)
diff --git a/cazy_webscraper/expand/genbank/get_genbank_sequences.py b/cazy_webscraper/expand/genbank/get_genbank_sequences.py
index 1954f1cb..647dae19 100644
--- a/cazy_webscraper/expand/genbank/get_genbank_sequences.py
+++ b/cazy_webscraper/expand/genbank/get_genbank_sequences.py
@@ -42,8 +42,6 @@
 from http.client import IncompleteRead
 import json
 import logging
-import re
-
 import pandas as pd
 
 from datetime import datetime
@@ -51,10 +49,9 @@
 
 from Bio import Entrez, SeqIO
 from Bio.Seq import Seq
-from Bio.SeqRecord import SeqRecord
 from saintBioutils.genbank import entrez_retry
 from saintBioutils.misc import get_chunks_list
-from saintBioutils.utilities import file_io
+from saintBioutils.utilities.file_io import make_output_directory
 from saintBioutils.utilities.logger import config_logger
 from tqdm import tqdm
 
@@ -93,10 +90,10 @@ def main(argv: Optional[List[str]] = None, logger: Optional[logging.Logger] = No
 
     if args.cache_dir is not None:  # use user defined cache dir
         cache_dir = args.cache_dir
-        file_io.make_output_directory(cache_dir, args.force, args.nodelete_cache)
+        make_output_directory(cache_dir, args.force, args.nodelete_cache)
     else:
         cache_dir = cache_dir / "genbank_data_retrieval"
-        file_io.make_output_directory(cache_dir, args.force, args.nodelete_cache)
+        make_output_directory(cache_dir, args.force, args.nodelete_cache)
 
     (
         config_dict,
@@ -208,6 +205,8 @@ def get_sequences(genbank_accessions, args, retry=False):
 
     irregular_accessions = []
 
+    success_accessions = set()  # accessions for which seqs were retrieved
+
     for query_list in tqdm(all_queries, desc="Batch querying NCBI.Entrez"):
 
         try:
@@ -225,8 +224,6 @@ def get_sequences(genbank_accessions, args, retry=False):
             failed_queries.append(query_list)
             continue
 
-        success_accessions = set()  # accessions for which seqs were retrieved
-
         try:
             # retrieve the protein sequences
             with entrez_retry(
@@ -243,49 +240,24 @@ def get_sequences(genbank_accessions, args, retry=False):
 
                     # check if multiple items returned in ID
                     temp_accession = temp_accession.split("|")
-                    index, success = 0, False
-                    
-                    while (index < len(temp_accession)) and (success is False):
-                        acc = temp_accession[index]
-                        try:
-                            re.match(
-                                (
-                                    r"(\D{2}_\d{8}\.\d)|"
-                                    r"(\D{3}\d{5,7}\.\d+)|"
-                                    r"(\D\d(\D|\d){3}\d)|"
-                                    r"((\D\d(\D|\d){3}\d)\.\d)|"
-                                    r"(\D\d(\D|\d){3}\d\D(\D|\d){2}\d)|"
-                                    r"((\D\d(\D|\d){3}\d\D(\D|\d){2}\d)\.\d)|"
-                                    r"(\D\D_\d{9}\.\d)"
-                                ),
-                                acc,
-                            ).group()
-                            seq_accession = acc
-                            success = True
-                        except AttributeError:
-                            index += 1
-                            pass
-
-                    if success is False:  # if could not retrieve GenBank accession from the record
+                    retrieved_accession = None
+
+                    for acc in temp_accession:
+                        if acc.strip() in genbank_accessions:
+                            retrieved_accession = acc
+
+                    if retrieved_accession is None:  # if could not retrieve GenBank accession from the record
                         logger.error(
-                            "Could not retrieve a GenBank protein accession from the record with the id:\n"
+                            "Could not retrieve a GenBank protein accession matching an accession from the local database from:\n"
                             f"{record.id}\n"
                             "The sequence from this record will not be added to the db"    
                         )
-                        continue
-
-                    if seq_accession not in genbank_accessions:  # if the retrieved Gbk acc does not match an acc in the db
-                        logger.warning(
-                            f"Retrieved the accession {temp_accession} from the record with the id:\n"
-                            f"{record.id},\n"
-                            "Not adding the protein seq from this record to the db"
-                        )
-                        irregular_accessions.append(f"Could not retrieve recognisable accession from '{acc}'")
+                        irregular_accessions.append(temp_accession)
                         continue
                         
-                    seq_dict[seq_accession] = record.seq
+                    seq_dict[retrieved_accession] = record.seq
 
-                    success_accessions.add(seq_accession)
+                    success_accessions.add(retrieved_accession)
         
         except IncompleteRead as err:
             logger.warning(
@@ -301,6 +273,7 @@ def get_sequences(genbank_accessions, args, retry=False):
             continue
 
     # list of GenBank accessions for which no protein sequence was retrieved
+
     no_seq = [acc for acc in genbank_accessions if acc not in success_accessions]
     no_seq += irregular_accessions
 
@@ -331,6 +304,8 @@ def get_sequences(genbank_accessions, args, retry=False):
 
             no_seq += failed_accessions
 
+    logger.warning(f"Retrieved sequences for {len(success_accessions)} proteins")
+
     return seq_dict, no_seq
 
 
@@ -343,7 +318,10 @@ def bulk_query_ncbi(accessions, args):
     Return webenv and query key
     """
     # perform batch query of Entrez
-    accessions_string = ",".join(accessions)
+    try:
+        accessions_string = ",".join(accessions)
+    except TypeError:
+        accessions_string = accessions
 
     # Runtime error captured by try/except function call
     epost_result = Entrez.read(
@@ -390,7 +368,7 @@ def retry_failed_queries(query, seq_dict, success_accessions, args):
     else:  # successful retrieval of data from NCBI
         for acc in new_seq_dict:
             seq_dict[acc] = new_seq_dict[acc]
-            success_accessions.append(success_accessions)
+            success_accessions.add(acc)
 
         failed_accessions += no_seq
 
diff --git a/cazy_webscraper/expand/pdb/get_pdb_structures.py b/cazy_webscraper/expand/pdb/get_pdb_structures.py
index cc41e8cc..a82f6e4d 100644
--- a/cazy_webscraper/expand/pdb/get_pdb_structures.py
+++ b/cazy_webscraper/expand/pdb/get_pdb_structures.py
@@ -44,8 +44,6 @@
 
 
 import logging
-import os
-import sys
 
 import pandas as pd
 
@@ -53,6 +51,9 @@
 from typing import List, Optional
 
 import Bio.PDB
+from saintBioutils.utilities.file_io import make_output_directory
+from saintBioutils.utilities.file_io import make_output_directory
+from saintBioutils.utilities.logger import config_logger
 
 from tqdm import tqdm
 
@@ -63,7 +64,7 @@
     get_user_genbank_sequences,
     get_user_uniprot_sequences
 )
-from cazy_webscraper.utilities import config_logger, file_io, parse_configuration
+from cazy_webscraper.utilities import parse_configuration
 from cazy_webscraper.utilities.parsers import pdb_strctre_parser
 
 
@@ -129,10 +130,10 @@ def main(argv: Optional[List[str]] = None, logger: Optional[logging.Logger] = No
     # make output and cache dirs
     if args.cache_dir is not None:  # use user defined cache dir
         cache_dir = args.cache_dir
-        file_io.make_output_directory(cache_dir, args.force, args.nodelete_cache)
+        make_output_directory(cache_dir, args.force, args.nodelete_cache)
     else:
-        cache_dir = cache_dir / "uniprot_data_retrieval"
-        file_io.make_output_directory(cache_dir, args.force, args.nodelete_cache)
+        cache_dir = cache_dir / "pdb_retrieval"
+        make_output_directory(cache_dir, args.force, args.nodelete_cache)
 
     download_pdb_structures(pdb_accessions, args)
 
diff --git a/cazy_webscraper/expand/uniprot/get_uniprot_data.py b/cazy_webscraper/expand/uniprot/get_uniprot_data.py
index 50bcfedf..fbf02a8e 100644
--- a/cazy_webscraper/expand/uniprot/get_uniprot_data.py
+++ b/cazy_webscraper/expand/uniprot/get_uniprot_data.py
@@ -43,14 +43,11 @@
 
 import json
 import logging
-import urllib.parse
-import urllib.request
 
 import pandas as pd
 
 from datetime import datetime
 from typing import List, Optional
-from urllib.error import HTTPError
 
 from bioservices import UniProt
 from saintBioutils.misc import get_chunks_list
@@ -71,6 +68,8 @@
 from cazy_webscraper.utilities.parsers.uniprot_parser import build_parser
 from cazy_webscraper.utilities.parse_configuration import get_expansion_configuration
 
+import sys
+
 
 def main(argv: Optional[List[str]] = None, logger: Optional[logging.Logger] = None):
     time_stamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")  # used in naming files
@@ -112,22 +111,22 @@ def main(argv: Optional[List[str]] = None, logger: Optional[logging.Logger] = No
     # add log to the local CAZyme database
     logger.info("Adding log of scrape to the local CAZyme database")
 
-    retrieved_annotations = "UniProt accessions"
+    retrieved_annotations = "UniProt accessions, Protein names"
     if args.ec:
         retrieved_annotations += ", EC numbers"
     if args.pdb:
-        retrieved_annotations = ", PDB accessions"
+        retrieved_annotations += ", PDB accessions"
     if args.sequence:
-        retrieved_annotations = ", Protein sequence"
+        retrieved_annotations += ", Protein sequence"
     if args.seq_update:
-        retrieved_annotations = ", Updated UniProt protein sequences"
+        retrieved_annotations += ", Updated UniProt protein sequences"
 
     with sql_orm.Session(bind=connection) as session:
         sql_interface.log_scrape_in_db(
             time_stamp,
             config_dict,
-            kingdom_filters,
             taxonomy_filter_dict,
+            kingdom_filters,
             ec_filters,
             'UniProt',
             retrieved_annotations,
@@ -158,23 +157,10 @@ def main(argv: Optional[List[str]] = None, logger: Optional[logging.Logger] = No
 
     logger.warning(f"Retrieving UniProt data for {len(gbk_dict.keys())}")
 
-    # Get the UniProt accessions/IDs for the corresponding GenBank accessions
-    if args.uniprot_accessions is not None:
-        logger.warning(f"Using UniProt accessions from cache: {args.uniprot_accessions}")
-        with open(args.uniprot_accessions, "r") as fh:
-            uniprot_gkb_dict = json.load(fh)
-
-    else:
-        uniprot_gkb_dict = get_uniprot_accessions(gbk_dict, args)  # {uniprot_acc: {'gbk_acc': str, 'db_id': int}}
-
-        uniprot_acc_cache = cache_dir / f"uniprot_accessions_{time_stamp}.json"
-        with open(uniprot_acc_cache, "w") as fh:
-            json.dump(uniprot_gkb_dict, fh)
-
-    # Get protein data from UniProt
-    if args.uniprot_data is not None:
-        logger.warning(f"Using UniProt data from cache: {args.uniprot_data}")
-        with open(args.uniprot_data, "r") as fh:
+    # if using cachce skip accession retrieval
+    if args.use_uniprot_cache is not None:
+        logger.warning(f"Using UniProt data from cache: {args.use_uniprot_cache}")
+        with open(args.use_uniprot_cache, "r") as fh:
             uniprot_dict = json.load(fh)
 
         if args.ec:
@@ -183,6 +169,21 @@ def main(argv: Optional[List[str]] = None, logger: Optional[logging.Logger] = No
             all_ecs = set()
 
     else:
+
+        # Get the UniProt accessions/IDs for the corresponding GenBank accessions
+        if args.skip_uniprot_accessions is not None:
+            logger.warning(f"Using UniProt accessions from cache: {args.skip_uniprot_accessions}")
+            with open(args.skip_uniprot_accessions, "r") as fh:
+                uniprot_gkb_dict = json.load(fh)
+
+        else:
+            uniprot_gkb_dict = get_uniprot_accessions(gbk_dict, args)  # {uniprot_acc: {'gbk_acc': str, 'db_id': int}}
+
+            uniprot_acc_cache = cache_dir / f"uniprot_accessions_{time_stamp}.json"
+            with open(uniprot_acc_cache, "w") as fh:
+                json.dump(uniprot_gkb_dict, fh)
+
+        # get data from UniProt
         uniprot_dict, all_ecs = get_uniprot_data(uniprot_gkb_dict, cache_dir, args)
 
         # converts sets to lists for json serialisation
@@ -201,6 +202,7 @@ def main(argv: Optional[List[str]] = None, logger: Optional[logging.Logger] = No
             json.dump(uniprot_dict, fh)   
 
     # add uniprot accessions (and sequences if seq retrieval is enabled)
+    logger.warning("Adding data to the local CAZyme database")
     add_uniprot_accessions(uniprot_dict, gbk_dict, connection, args)
 
     # add ec numbers
@@ -261,11 +263,17 @@ def get_uniprot_data(uniprot_gbk_dict, cache_dir, args):
         ]]
 
 
-
         for index in tqdm(range(len(uniprot_df['Entry'])), desc="Parsing UniProt response"):
             row = uniprot_df.iloc[index]
             uniprot_acc = row['Entry'].strip()
-            uniprot_name = row['Protein names'].strip()
+            try:
+                uniprot_name = row['Protein names'].strip()
+
+            except AttributeError:
+                logger.warning(
+                    f"Protein name {row['Protein names']} was returned as float not string. Converting to string"
+                )
+                uniprot_name = str(row['Protein names'])
 
             # remove quotation marks from the protein name, else an SQL error will be raised on insert
             uniprot_name = uniprot_name.replace("'", "")
@@ -281,6 +289,7 @@ def get_uniprot_data(uniprot_gbk_dict, cache_dir, args):
                     "But no corresponding record was found in the local CAZyme database\n"
                     "Skipping this UniProt ID"
                 )
+                continue  # uniprot ID does not match any retrieved previously
 
             try:
                 uniprot_dict[uniprot_acc]
@@ -326,7 +335,7 @@ def get_uniprot_data(uniprot_gbk_dict, cache_dir, args):
                 pdb_accessions = row['Cross-reference (PDB)']
                 try:
                     pdb_accessions = pdb_accessions.split(';')
-                    pdb_accessions = [pdb.strip() for pdb in pdb_accessions]
+                    pdb_accessions = [pdb.strip() for pdb in pdb_accessions if len(pdb.strip()) > 0]
                 except AttributeError:
                     pdb_accessions = set()
 
@@ -382,7 +391,7 @@ def get_ecs_from_cache(uniprot_dict):
         try:
             ecs = uniprot_dict[uniprot_acc]["ec"]
             for ec in ecs:
-                all_ecs.add(ec)
+                all_ecs.add( (ec,) )
         except (ValueError, TypeError, KeyError):
             pass
 
diff --git a/cazy_webscraper/genomes/cazy_genbank_coverage.py b/cazy_webscraper/genomes/cazy_genbank_coverage.py
index aee457e3..baae09d2 100644
--- a/cazy_webscraper/genomes/cazy_genbank_coverage.py
+++ b/cazy_webscraper/genomes/cazy_genbank_coverage.py
@@ -42,7 +42,8 @@
 import json
 import logging
 import os
-import time
+import sys
+from tracemalloc import get_object_traceback
 
 import pandas as pd
 
@@ -52,6 +53,7 @@
 
 from Bio import Entrez
 from saintBioutils.genbank import entrez_retry
+from saintBioutils.misc import get_chunks_list
 from saintBioutils.utilities.file_io import make_output_directory
 from saintBioutils.utilities.logger import config_logger
 from tqdm import tqdm
@@ -94,15 +96,14 @@ def main(argv: Optional[List[str]] = None, logger: Optional[logging.Logger] = No
     # make cache_dir
     make_output_directory(cache_dir, args.force_cache, args.nodelete_cache)
 
-    no_accession_logger = cache_dir / "logs"
-    # make logs dir
-    make_output_directory(no_accession_logger, args.force_cache, args.nodelete_cache)
-    no_accession_logger = no_accession_logger / f"no_genomic_accession_retrieved_{time_stamp}.log"
+    no_accession_logger = cache_dir / f"no_genomic_accession_retrieved_{time_stamp}.log"
 
     # load Genbank and Kingdom records from the db
     logger.warning("Retrieving Genbanks, Taxs and Kingdoms records from the local CAZyme db")
     genbank_kingdom_dict = get_table_dicts.get_gbk_kingdom_dict(connection)
-    logger.warning("Retrieved Genbanks, Taxs and Kingdoms records from the local CAZyme db")
+    # {kingdom: {genus: {species: {protein_accessions}}}
+
+    logger.warning(f"Retrieved Genbanks, Taxs and Kingdoms records from the local CAZyme db")
 
     nucleotide_accessions_dict = get_nucleotide_accessions(
         genbank_kingdom_dict,
@@ -150,224 +151,302 @@ def main(argv: Optional[List[str]] = None, logger: Optional[logging.Logger] = No
         )
 
 
-def get_nucleotide_accessions(genbank_kingdom_dict, no_accession_logger, args):
+def get_nucleotide_accessions(genbank_kingdom_dict, no_accession_logger, cache_dir, args):
     """Retrieve the NCBI Nucleotide db records ID's containing the GenBank protein accessions.
     
     :param genbank_kingdom_dict: dict of Genbank and Kingdom records from db
         {kingdom: {genus: {species: {protein_accessions}}}
     :param no_accession_logger: Path, path to log file to save protein accessions for which no 
         genomic accession was retrieved
+    :param cache_dir: Path to cache directory
     :param args: cmd-line args parser
     
     Return dict {kingdom: {genus: {species: {nucleotide_accession: {protein_accessions},},},},}
     """
     logger = logging.getLogger(__name__)
 
+    # convert the structure of genbank_kingdom_dict
+    # { protein_accession: {species: str, genus: str, kingdom} }
+    if args.gbk_organisms_relationships is not None:
+        logger.warning(f"Retriving protein-organisms relationships from file: {args.gbk_organisms_relationships}")
+        try:
+            with open(args.gbk_organisms_relationships, "r") as fh:
+                gbk_organism_dict = json.load(fh)
+        except FileNotFoundError:
+            logger.warning(
+                f"Could not find JSON file containing protein-organisms relationships at: {args.gbk_organisms_relationships}\n"
+                "Check the correct path was given.\n"
+                "Terminating program"
+            )
+            sys.exit(1)
+    else:
+        logger.warning("Retrieving protein-organism relationships from the local database")
+        gbk_organism_dict = get_gbk_organism_relationships(genbank_kingdom_dict)
+
+    # create dict to store the nucleotide records accessions
     nucleotide_accessions_dict = {}
     # {kingdom: {genus: {species: {nucleotide record accessio: {protein_accessions},},},},}
 
+    # create a dict to keep track of protein accessions for which a nucleotide record was retrieved
+    # store all retrieved ncucleotide accessions to prevent retrieval of the
+    # same assembly record multiple times
     retrieved_proteins = {}  # {protein_accession: nucleotide record accession}
 
-    # store all retrieved ncucleotide accessions to prevent retrieval of the same assembly record multiple times
-    
-    for kingdom in tqdm(genbank_kingdom_dict, desc="Retrieving nucleotide record accessions per kingdom"):
-        genera = genbank_kingdom_dict[kingdom]
+    # create set of protein accessions for which no nucleotide ID was retrievied
+    no_retrieved_nucleotide_ids = set()
 
-        gbk_organism_dict = {}  # protein_accession: {species: str, genus: str}
+    # gbk accessions waiting for a nucleotide id to be retrieved
+    remaining_accessions = list(gbk_organism_dict.keys())
 
-        for genus in genera:
-            organisms = genera[genus]
+    # break up the list into batches
+    gbk_accessions = list(gbk_organism_dict.keys())
+    gbk_batches = get_chunks_list(gbk_accessions, args.batch_size)
 
-            for species in organisms:
-                for gbk_acc in organisms[species]:
-                    gbk_organism_dict[gbk_acc] = {'species': species, 'genus': genus}
-        
-        # retrieve all Gbk protein accessions for the given genera
-        gbk_accessions = list(gbk_organism_dict.keys())
+    failed_batches = set()
 
-        # gbk accessions waiting for a nucleotide id to be retrieved
-        remaining_accessions = list(gbk_organism_dict.keys())
+    for batch in tqdm(gbk_batches, desc="Batching quering NCBI for nucleotide IDs"):
+        # eLink Protein to Nuccore db and retrieve IDs of linked nucleotide records
+        batch_query_ids = ",".join(batch)
 
-        while len(remaining_accessions) != 0:
-            starting_loop_length = len(remaining_accessions)
-            logger.warning(f"{len(remaining_accessions)} Gbk accessions remaining to be parsed for {kingdom}")
-            
-            accessions_to_parse = remaining_accessions[:args.batch_size]
+        try:
+            with entrez_retry(
+                args.retries,
+                Entrez.epost,
+                "Protein",
+                id=batch_query_ids,
+            ) as handle:
+                epost_result = Entrez.read(handle)
+        except RuntimeError:
+            logger.warning(
+                "Runtime error raised when batch quering\n"
+                "Possible result of a accessions not being in NCBI\n"
+                "Attempt identification of the causal accession later\n"
+            )
+            failed_batches.add(batch)
+            continue
+
+        epost_webenv = epost_result["WebEnv"]
+        epost_query_key = epost_result["QueryKey"]
 
-            # eLink Protein to Nuccore db and retrieve IDs of linked nucleotide records
-            batch_query_ids = ",".join(accessions_to_parse)
+        try:
             with entrez_retry(
-                args.retries, Entrez.epost, "Protein", id=batch_query_ids,
+                args.retries,
+                Entrez.elink,
+                dbfrom="Protein",
+                db="nuccore",
+                query_key=epost_webenv,
+                WebEnv=epost_query_key,
+                linkname='protein_nuccore',
             ) as handle:
-                batch_post = Entrez.read(handle)
+                batch_nuccore = Entrez.read(handle)
+        except Exception as err:
+            logger.warning(
+                f"Failed Entrez connection: {err}\n"
+                "No nucletoide IDs retrieved for batch query\n"
+                "Will try again later"
+            )
+            failed_batches.add(batch)
+            continue
 
-            # {protein record ID: {nucleotide records IDs}}
-            nucleotide_ids = entrez.get_linked_nucleotide_record_ids(batch_post, args)
+        # parse the query result from nuccore
 
-            if nucleotide_ids is None: 
-                # issue with at least one accession in the batch
-                # e.g. it is not longer stored in NCBI
-                # pass individually to find/parse the bad accession(s)
-                nucleotide_ids, no_nucleotides = entrez.link_nucleotide_ids_individually(
-                    accessions_to_parse,
-                    no_accession_logger,
-                    args,
-                )
+        # {protein record ID: {nucleotide records IDs}}
+        nucleotide_ids = entrez.get_linked_nucleotide_record_ids(batch_nuccore)
 
-                if len(no_nucleotides) != 0:
-                    logger.warning(f"{len(no_nucleotides)} proteins found with no linked Nucleotide records")
-                    for protein_accession in no_nucleotides:
-                        # already logged in link_nucleotide_ids_individually()
-                        try:
-                            remaining_accessions.remove(protein_accession)
-                        except ValueError:
-                            pass
-            
-            if len(list(nucleotide_ids.values())) == 0:
-                # no linked Nucleotide records retrieved for the current batch of protein accessions
-                for protein_accession in accessions_to_parse:
-                    logger.warning(
-                        f"Could not reitreve linked Nucleotide record for {protein_accession}"
-                    )
-                    # do not try to retrieve record again
+        if nucleotide_ids is None: 
+            # issue with at least one accession in the batch
+            # e.g. it is not longer stored in NCBI
+            # pass individually to find/parse the bad accession(s)
+            nucleotide_ids, no_nucleotides = entrez.link_nucleotide_ids_individually(
+                accessions_to_parse,
+                no_accession_logger,
+                args,
+            )
+
+            # no nucleotide IDs retrieved for at least one protein
+            if len(no_nucleotides) != 0:
+                logger.warning(f"{len(no_nucleotides)} proteins found with no linked Nucleotide records")
+                for protein_accession in no_nucleotides:
+                    # already logged in link_nucleotide_ids_individually()
                     try:
                         remaining_accessions.remove(protein_accession)
+                        no_retrieved_nucleotide_ids.add(protein_accession)
                     except ValueError:
                         pass
-                continue
-
-            # retrieves the nucleotide records IDs for protein records for whcih only one
-            # nuclotide ID was retrieved
-            single_nucleotide_ids = set()
-
-            # retrieve the protein_record_ids of protein records from which multiple nucletoide 
-            # record IDs were retrieved
-            protein_records_multi_nuc = set()
-
-            for protein_record_id in tqdm(nucleotide_ids, desc="Idenitfying proteins with multiple linked nucleotide records"):
-                if len(nucleotide_ids[protein_record_id]) == 1:
-                    single_nucleotide_ids.add(list(nucleotide_ids[protein_record_id])[0])
-                else:
-                    logger.warning(
-                        f"Found {len(nucleotide_ids[protein_record_id])} linked nucletoide records "
-                        f"for protein record {protein_record_id}"
-                        )
-                    protein_records_multi_nuc.add(protein_record_id)
+        
+        if len(list(nucleotide_ids.values())) == 0:
+            # no linked Nucleotide records retrieved for the current batch of protein accessions
+            for protein_accession in accessions_to_parse:
+                logger.warning(
+                    f"Could not reitreve linked Nucleotide record for {protein_accession}"
+                )
+                no_retrieved_nucleotide_ids.add(protein_accession)
+                # do not try to retrieve record again
+                try:
+                    remaining_accessions.remove(protein_accession)
+                except ValueError:
+                    pass
+            continue
 
-            # batch query to fetch nucletoide records for protein records
-            # from which only a sinlge nucleotide ID was retrieved
-            if len(single_nucleotide_ids) != 0:
-                retrieved_proteins, newly_retrieved_proteins, succcess = entrez.extract_protein_accessions(
+        # retrieves the nucleotide records IDs for protein records for whcih only one
+        # nuclotide ID was retrieved
+        single_nucleotide_ids = set()
+
+        # retrieve the protein_record_ids of protein records from which multiple nucletoide 
+        # record IDs were retrieved
+        protein_records_multi_nuc = set()
+
+        for protein_record_id in tqdm(nucleotide_ids, desc="Idenitfying proteins with multiple linked nucleotide records"):
+            if len(nucleotide_ids[protein_record_id]) == 1:
+                single_nucleotide_ids.add(list(nucleotide_ids[protein_record_id])[0])
+            else:
+                logger.warning(
+                    f"Found {len(nucleotide_ids[protein_record_id])} linked nucletoide records "
+                    f"for protein record {protein_record_id}"
+                    )
+                protein_records_multi_nuc.add(protein_record_id)
+
+        # batch query to fetch nucletoide records for protein records
+        # from which only a sinlge nucleotide ID was retrieved
+        if len(single_nucleotide_ids) != 0:
+            retrieved_proteins, newly_retrieved_proteins, succcess = entrez.extract_protein_accessions(
+                single_nucleotide_ids,
+                retrieved_proteins,
+                gbk_accessions,
+                args,
+            )
+            if succcess is False:
+                # issue with at least one accession in the batch
+                # e.g. it is not longer stored in NCBI
+                # pass individually to find/parse the bad accession(s)
+                retrieved_proteins, newly_retrieved_proteins = entrez.extract_protein_accessions_individually(
                     single_nucleotide_ids,
                     retrieved_proteins,
                     gbk_accessions,
                     args,
                 )
-                if succcess is False:
-                    # issue with at least one accession in the batch
-                    # e.g. it is not longer stored in NCBI
-                    # pass individually to find/parse the bad accession(s)
-                    retrieved_proteins, newly_retrieved_proteins = entrez.extract_protein_accessions_individually(
-                        single_nucleotide_ids,
-                        retrieved_proteins,
-                        gbk_accessions,
-                        args,
-                    )
 
-                # add the nucleotide accessions to the nucleotide_accessions_dict
-                # {kingdom: {genus: {species: {nucleotide record accessio: {protein_accessions},},},},}
-                nucleotide_accessions_dict = add_nucleotide_accessions(
-                    nucleotide_accessions_dict,
-                    gbk_organism_dict,
-                    retrieved_proteins,
-                    newly_retrieved_proteins,
-                    kingdom,
-                    no_accession_logger,
-                )
+            # add the nucleotide accessions to the nucleotide_accessions_dict
+            # {kingdom: {genus: {species: {nucleotide record accessio: {protein_accessions},},},},}
+            nucleotide_accessions_dict = add_nucleotide_accessions(
+                nucleotide_accessions_dict,
+                gbk_organism_dict,
+                retrieved_proteins,
+                newly_retrieved_proteins,
+                kingdom,
+                no_accession_logger,
+            )
 
-            # for Protein records for which multiple Nucleotide record IDs were retrieved
-            # Identify the longest Nucleotide record and retrieve protein accessions from it
-            # The longest record is most likely to be the most complete record
-            for protein_record_id in tqdm(protein_records_multi_nuc, "Parsing protein records with multiple linked Nucletide records"):
-                nucleotide_record_ids = nucleotide_ids[protein_record_id]
+        # for Protein records for which multiple Nucleotide record IDs were retrieved
+        # Identify the longest Nucleotide record and retrieve protein accessions from it
+        # The longest record is most likely to be the most complete record
+        for protein_record_id in tqdm(protein_records_multi_nuc, "Parsing protein records with multiple linked Nucletide records"):
+            nucleotide_record_ids = nucleotide_ids[protein_record_id]
+
+            retrieved_proteins, newly_retrieved_proteins, success = entrez.parse_longest_record(
+                nucleotide_record_ids,
+                retrieved_proteins,
+                gbk_accessions,
+                args,
+            )
 
-                retrieved_proteins, newly_retrieved_proteins, success = entrez.parse_longest_record(
+            if success is False:
+                # issue with at least one accession in the batch
+                # e.g. it is not longer stored in NCBI
+                # pass individually to find/parse the bad accession(s)
+                retrieved_proteins, newly_retrieved_proteins, success = entrez.parse_longest_record_individually(
                     nucleotide_record_ids,
                     retrieved_proteins,
                     gbk_accessions,
                     args,
                 )
 
-                if success is False:
-                    # issue with at least one accession in the batch
-                    # e.g. it is not longer stored in NCBI
-                    # pass individually to find/parse the bad accession(s)
-                    retrieved_proteins, newly_retrieved_proteins, success = entrez.parse_longest_record_individually(
-                        nucleotide_record_ids,
-                        retrieved_proteins,
-                        gbk_accessions,
-                        args,
-                    )
-
-                nucleotide_accessions_dict = add_nucleotide_accessions(
-                    nucleotide_accessions_dict,
-                    gbk_organism_dict,
-                    retrieved_proteins,
-                    newly_retrieved_proteins,
-                    kingdom,
-                    no_accession_logger,
-                )
-
-            # remove protein accessions from remaining_accessions because the linked Nucleotide 
-            # record ID has already been retrieved
-            for protein_accession in retrieved_proteins:
-                try:
-                    remaining_accessions.remove(protein_accession)
-                except ValueError:
-                    pass
+            nucleotide_accessions_dict = add_nucleotide_accessions(
+                nucleotide_accessions_dict,
+                gbk_organism_dict,
+                retrieved_proteins,
+                newly_retrieved_proteins,
+                kingdom,
+                no_accession_logger,
+            )
 
-            if starting_loop_length == len(remaining_accessions) and len(remaining_accessions) != 0:
-                # failing to retrieve data for protein accessions
-                nucleotide_ids, no_nucleotides = entrez.link_nucleotide_ids_individually(
-                    accessions_to_parse,
-                    no_accession_logger, 
-                    args,
-                )
+        # remove protein accessions from remaining_accessions because the linked Nucleotide 
+        # record ID has already been retrieved
+        for protein_accession in retrieved_proteins:
+            try:
+                remaining_accessions.remove(protein_accession)
+            except ValueError:
+                pass
+
+        if starting_loop_length == len(remaining_accessions) and len(remaining_accessions) != 0:
+            # failing to retrieve data for protein accessions
+            nucleotide_ids, no_nucleotides = entrez.link_nucleotide_ids_individually(
+                accessions_to_parse,
+                no_accession_logger, 
+                args,
+            )
 
-                if nucleotide_ids is None:
-                    for protein_accession in remaining_accessions:
-                        logger.warning(
-                                f"Could not retrieve  Nucletoide record for {protein_accession}"
-                            )
-                        try:
-                            remaining_accessions.remove(protein_accession)
-                        except ValueError:
-                            pass
-                    continue
-                
-            if len(list(nucleotide_ids.values())) == 0:
-                # no linked Nucleotide records retrieved for the current batch of protein accessions
-                for protein_accession in accessions_to_parse:
+            if nucleotide_ids is None:
+                for protein_accession in remaining_accessions:
                     logger.warning(
-                        f"Could not reitreve linked Nucleotide record for {protein_accession}"
-                    )
-                    # do not try to retrieve record again
-                    try:
-                        remaining_accessions.remove(protein_accession)
-                    except ValueError:
-                        pass
-        
-            if len(no_nucleotides) != 0:
-                for protein_accession in no_nucleotides:
-                    # already logged in link_nucleotide_ids_individually()
+                            f"Could not retrieve  Nucletoide record for {protein_accession}"
+                        )
                     try:
                         remaining_accessions.remove(protein_accession)
                     except ValueError:
                         pass
+                continue
             
+        if len(list(nucleotide_ids.values())) == 0:
+            # no linked Nucleotide records retrieved for the current batch of protein accessions
+            for protein_accession in accessions_to_parse:
+                logger.warning(
+                    f"Could not reitreve linked Nucleotide record for {protein_accession}"
+                )
+                # do not try to retrieve record again
+                try:
+                    remaining_accessions.remove(protein_accession)
+                except ValueError:
+                    pass
+    
+        if len(no_nucleotides) != 0:
+            for protein_accession in no_nucleotides:
+                # already logged in link_nucleotide_ids_individually()
+                try:
+                    remaining_accessions.remove(protein_accession)
+                except ValueError:
+                    pass
+        
     return nucleotide_accessions_dict
 
 
+def get_gbk_organism_relationships(genbank_kingdom_dict, cache_dir):
+    """Restructure the gbk_kingomds_dict to be keyed by genbank accessions.
+    
+    :param genbank_kingdom_dict: dict, {kingdom: {genus: {species: {protein_accessions}}}}
+    :param cache_dir: path to cache directory
+
+    Return gbk_organism_dict dict { protein_accession: {species: str, genus: str, kingdom} }
+    """
+    gbk_organism_dict = {}  # { protein_accession: {species: str, genus: str, kingdom} }
+
+    for kingdom in tqdm(genbank_kingdom_dict, desc="Retrieving protein-organisms relationships per kingdom"):
+        genera = genbank_kingdom_dict[kingdom]
+
+        for genus in tqdm(genera, desc=f"Parsing genera of {kingdom}"):
+            organisms = genera[genus]
+
+            for species in organisms:
+                for gbk_acc in organisms[species]:
+                    gbk_organism_dict[gbk_acc] = {'species': species, 'genus': genus, 'kingdom': kingdom}
+
+    gbk_organism_dict_path = cache_dir / "gbk_organisms_relationships.json"
+    with open(gbk_organism_dict_path, "w") as fh:
+        json.dump(gbk_organism_dict, fh)
+
+    return gbk_organism_dict
+
+
 def add_nucleotide_accessions(
     nucleotide_accessions_dict,
     gbk_organism_dict,
diff --git a/cazy_webscraper/genomes/entrez.py b/cazy_webscraper/genomes/entrez.py
index 651a362c..f871cd0b 100644
--- a/cazy_webscraper/genomes/entrez.py
+++ b/cazy_webscraper/genomes/entrez.py
@@ -46,17 +46,15 @@
 from tqdm import tqdm
 
 
-def get_linked_nucleotide_record_ids(batch_post, args):
-    """Use Entrez.elink to get the ID of the NCBI.Nucleotide db record linked to the NCBI.Protein
-    db record.
+def get_linked_nucleotide_record_ids(batch_nuccore):
+    """Parse the Entrez efetch XML result.
     
     In the resulting dict, the protein record ID is used to group nucleotide records that are 
     linked to the same protein record, and from which it will need to be determined which is
     the longest record, so that only one (and the longest) Nucleotide record is parsed for this protein
     not all retrieved Nucleotide records.
 
-    :param batch_post: Entrez dict containing WebEnv and query_key from batch posting protein accessions
-    :param args: cmd-line args parser
+    :param batch_nuccore: Entrez efetch xml query result
 
     Return dict {protein_accession: {nucleotide records IDs}}
     Return None if cannot retrieve data from NCBI
@@ -64,21 +62,6 @@ def get_linked_nucleotide_record_ids(batch_post, args):
     logger = logging.getLogger(__name__)
 
     nucleotide_ids = {}  # {protein_record_id: {nucleotide_ids}}
-    # used for identifying which nucleotide record to retrieve protein accessions from
-    with entrez_retry(
-        args.retries,
-        Entrez.elink,
-        dbfrom="Protein",
-        db="nuccore",
-        query_key=batch_post['QueryKey'],
-        WebEnv=batch_post['WebEnv'],
-        linkname='protein_nuccore',
-    ) as handle:
-        try:
-            batch_nuccore = Entrez.read(handle)
-        except Exception as err:
-            logger.warning(f"Failed Entrez connection: {err}\nNo nucletoide IDs retrieved for batch query")
-            return
 
     for record in tqdm(batch_nuccore, desc="Retrieving Nucleotide db records IDs from nuccore"):
         protein_record_id = record['IdList'][0]
@@ -92,7 +75,7 @@ def get_linked_nucleotide_record_ids(batch_post, args):
             # link_list = {'Link': [{'Id': '1127815138'}], 'DbTo': 'nuccore', 'LinkName': 'protein_nuccore'}
             links = link_dict['Link']
             for link in links:
-                # links = [{'Id': '1127815138'}]
+                # links = [{'Id': '1127815138'}, {'Id': '1127825138'}]
                 # link = {'Id': '1127815138'}
                 nucleotide_id = link['Id']
 
diff --git a/cazy_webscraper/sql/sql_interface/__init__.py b/cazy_webscraper/sql/sql_interface/__init__.py
index e32bd1ee..e36b1d1a 100644
--- a/cazy_webscraper/sql/sql_interface/__init__.py
+++ b/cazy_webscraper/sql/sql_interface/__init__.py
@@ -81,8 +81,8 @@ def log_scrape_in_db(
     Return nothing."""
     logger = logging.getLogger(__name__)
 
-    date = time_stamp[:time_stamp.find("--")]
-    time = time_stamp[((time_stamp.find("--")) + 2):].replace("-", ":")
+    date = time_stamp.split("_")[0]
+    time = time_stamp.split("_")[1]
 
     new_log = sql_orm.Log(
         date=date,
@@ -95,70 +95,110 @@ def log_scrape_in_db(
         # get classes that user named to be scraped
         try:
             classes = config_dict["classes"]
+            # E.G. {'classes': ['Polysaccharide Lyases (PLs)', 'Carbohydrate Esterases (CEs)']}
             if classes is not None:
-                classes = str(classes).replace("[", "").replace("]", "").replace("'", "")
+                classes = ""
+                for cazy_class in config_dict['classes']:
+                    if len(classes) == 0:
+                        classes = cazy_class
+                    else:
+                        classes += f", {cazy_class}"
+
                 new_log.classes = classes
         except KeyError:
             pass
+            
+        if len(classes) != 0:
+            new_log.classes = classes
 
         # create a list of families instructed to be scraped
-        families = []
+        families = ""
         for key in config_dict:
             if (key != "classes") and (config_dict[key] is not None):
-                families.append(config_dict[key])
+                for fam in config_dict[key]:
+                    if len(families) == 0:
+                        families = fam
+                    else:
+                        families += f", {fam}"
 
         if len(families) != 0:
-            families = str(families).replace("[", "").replace("]", "").replace("'", "")
             new_log.families = families
 
     # get taxonomy filters defined by user, and separate into genera, species and strains
     try:
+        genera = ""
         if len(taxonomy_filters["genera"]) != 0:
-            genera = str(taxonomy_filters["genera"]).replace("[", "").\
-                replace("]", "").replace("'", "")
+            for genus in taxonomy_filters["genera"]:
+                if len(genera) == 0:
+                    genera = genus
+                else:
+                    genera += f", {genus}"
+        if len(genera) != 0:
             new_log.genera = genera
     except TypeError:
         pass
 
     try:
+        species = ""
         if len(taxonomy_filters["species"]) != 0:
-            species = str(taxonomy_filters["species"])
-            species = species.replace("[", "").replace("]", "").replace("'", "")
+            for organism in taxonomy_filters["species"]:
+                if len(species) == 0:
+                    species = organism
+                else:
+                    species += f", {organism}"
+
+        if len(species) != 0:
             new_log.species = species
     except TypeError:
         pass
 
     try:
+        strains = ""
         if len(taxonomy_filters["strains"]) != 0:
-            strains = str(taxonomy_filters["strains"])
-            strains = strains.replace("[", "").replace("]", "").replace("'", "")
+            for organism in taxonomy_filters["strains"]:
+                if len(strains) == 0:
+                    strains = organism
+                else:
+                    strains += f", {organism}"
+        
+        if len(strains) != 0:
             new_log.strains = strains
     except TypeError:
         pass
 
     # get Taxonomy Kingdoms defined by user to be scraped
     if kingdoms is not None:
-        new_log.kingdoms = str(kingdoms).replace("[", "").replace("]", "").replace("'", "")
+        kingdoms_str = ""
+        for kingdom in kingdoms:
+            if len(kingdoms_str) == 0:
+                kingdoms_str = kingdom
+            else:
+                kingdoms_str += f", {kingdom}"
+        
+        if len(kingdoms_str) != 0:
+            new_log.kingdoms = kingdoms_str
+        else:
+            new_log.kingdoms = "ALL (Archaea, Bacteria, Eukaryota, Viruses, Unclassified)"
     else:
-        new_log.kingdoms = "ALL (Archaea, Bacteria, Eukaryota, Viruses, Unclassified"
+        new_log.kingdoms = "ALL (Archaea, Bacteria, Eukaryota, Viruses, Unclassified)"
     
     # retrieve commands from the command line
     cmd_line = ""
     for cmd in [
         [args.classes, " --classes '"],
         [args.families, " --families '"],
-        [args.kingdoms, " --kingdoms"],
+        [args.kingdoms, " --kingdoms '"],
         [args.genera, " --genera '"],
         [args.species, " --species '"],
         [args.strains, " --strains '"],
     ]:
         try:
-            cmd_line = cmd_line + cmd[1] + cmd[0] + "'"
+            cmd_line = cmd_line + cmd[1] + cmd[0] + "' "
         except TypeError:
             pass
 
     if len(ec_filter) != 0:
-        cmd_line = cmd_line + "--ec_filter" + (args.ec) + "'"
+        cmd_line = cmd_line + "--ec_filter '" + (args.ec_filter) + "'"
         new_log.ec_filter = ','.join(list(ec_filter))
 
     if len(cmd_line) != 0:
diff --git a/cazy_webscraper/sql/sql_interface/add_genbank_data.py b/cazy_webscraper/sql/sql_interface/add_genbank_data.py
index 07a4c843..05e39841 100644
--- a/cazy_webscraper/sql/sql_interface/add_genbank_data.py
+++ b/cazy_webscraper/sql/sql_interface/add_genbank_data.py
@@ -41,6 +41,7 @@
 """Add protein sequences retrieved from GenBank to a local SQLite database"""
 
 
+import logging
 from sqlalchemy import text
 from tqdm import tqdm
 
@@ -58,6 +59,8 @@ def add_gbk_seqs_to_db(seq_dict, retrieval_date, gbk_dict, connection, args):
     
     Return nothing
     """
+    logger = logging.getLogger(__name__)
+    
     # load the current Genbanks table into a dict
     gbk_table_dict = get_table_dicts.get_gbk_table_seq_dict(connection)
 
@@ -71,25 +74,28 @@ def add_gbk_seqs_to_db(seq_dict, retrieval_date, gbk_dict, connection, args):
         if existing_record['sequence'] is None:
             records.add( (db_id, seq) )
         else:
-            if (args.sequence_update) and (retrieval_date < existing_record['seq_date']):
+            if (args.seq_update) and (retrieval_date < existing_record['seq_date']):
                 records.add( (db_id, seq) )
 
-    with connection.begin():
-        for record in tqdm(records, desc="Adding seqs to db"): 
-                connection.execute(
-                    text(
-                        "UPDATE Genbanks "
-                        f"SET sequence = '{record[1]}'"
-                        f"WHERE genbank_id = '{record[0]}'"
+    if len(records) != 0:
+        with connection.begin():
+            for record in tqdm(records, desc="Adding seqs to db"): 
+                    connection.execute(
+                        text(
+                            "UPDATE Genbanks "
+                            f"SET sequence = '{record[1]}'"
+                            f"WHERE genbank_id = '{record[0]}'"
+                        )
                     )
-                )
-                #, seq_update_date = {retrieval_date} 
-                connection.execute(
-                    text(
-                        "UPDATE Genbanks "
-                        f"SET seq_update_date = '{retrieval_date}'"
-                        f"WHERE genbank_id = '{record[0]}'"
+                    #, seq_update_date = {retrieval_date} 
+                    connection.execute(
+                        text(
+                            "UPDATE Genbanks "
+                            f"SET seq_update_date = '{retrieval_date}'"
+                            f"WHERE genbank_id = '{record[0]}'"
+                        )
                     )
-                )
+    else:
+        logger.warning("No records to update")
 
     return
diff --git a/cazy_webscraper/sql/sql_interface/add_uniprot_data.py b/cazy_webscraper/sql/sql_interface/add_uniprot_data.py
index 88344bc5..eb9c6062 100644
--- a/cazy_webscraper/sql/sql_interface/add_uniprot_data.py
+++ b/cazy_webscraper/sql/sql_interface/add_uniprot_data.py
@@ -41,6 +41,7 @@
 """Add data retrieved from UniProt to a local SQLite database"""
 
 
+import logging
 from sqlalchemy import delete, text
 from tqdm import tqdm
 
@@ -134,7 +135,7 @@ def add_uniprot_accessions(uniprot_dict, gbk_dict, connection, args):
         if args.sequence or args.seq_update:
             columns = ['genbank_id', 'uniprot_accession', 'uniprot_name', 'sequence', 'seq_update_date']
         else:
-            columns = ['genbakn_id', 'uniprot_accession', 'uniprot_name']
+            columns = ['genbank_id', 'uniprot_accession', 'uniprot_name']
     
         insert_data(connection, "Uniprots", columns, list(uniprot_insert_values))
 
@@ -193,8 +194,8 @@ def add_ec_numbers(uniprot_dict, all_ecs, gbk_dict, connection, args):
     ec_insert_values = set()
 
     for ec in all_ecs:
-        if ec not in existing_ecs:
-            ec_insert_values.add( (ec,) )
+        if ec[0] not in existing_ecs:
+            ec_insert_values.add( ec )
 
     if len(ec_insert_values) != 0:
         insert_data(connection, "Ecs", ["ec_number"], list(ec_insert_values))
@@ -262,56 +263,97 @@ def add_pdb_accessions(uniprot_dict, gbk_dict, connection, args):
 
     Return nothing.
     """
+    logger = logging.getLogger(__name__)
+
+    pdbs_to_delete = set()  # only used if args.delete_old_pdbs is true
+    relationships_to_delete = set()  # only used if args.delete_old_pdbs is true
+
     # load in PDB objects in the local CAZyme db
     pdb_table_dict = get_table_dicts.get_pdb_table_dict(connection)
+    # {pdb_accession: pdb_db_id}
 
-    pdb_insert_values = set()  # new records to add to db
-    update_pdbs = set()  # records to update
-    existing_pdbs = set(pdb_table_dict.values())  # records already in the db
-    if args.delete_old_pdbs:
-        delete_pdbs = set()  # records to delete, PDB acc no longer listed in UniProt for the given protein
-
-    for uniprot_acc in tqdm(uniprot_dict, desc="Identifying new and updated PDB records"):
+    # First, identify new PDB accessions to add to the database
+    pdb_insert_values = set()
+    for uniprot_acc in tqdm(uniprot_dict, desc="Identifying new PDBs to add to db"):
+        for pdb in uniprot_dict[uniprot_acc]["pdb"]:
+            try:
+                pdb_table_dict[pdb]
+            except KeyError:
+                pdb_insert_values.add( (pdb,) )
+    
+    if len(pdb_insert_values) != 0:
+        logger.warning(f"Adding {len(pdb_insert_values)} PDB accessions to the database")
+        insert_data(connection, "Pdbs", ["pdb_accession"], list(pdb_insert_values))
+        # reload the updated pdb table
+        pdb_table_dict = get_table_dicts.get_pdb_table_dict(connection)
+    
+    # load in Genbanks_Pdbs relationship table
+    gbk_pdb_rel_table_dict = get_table_dicts.get_gbk_pdb_table_dict(connection)
+    # {gbk_db_id: {pdb_db_id} }
+
+    # convert the data from UniProt into a dict of {gbk_db_id: pdb_db_id} 
+    # to identify pdb-protein relationships retrieved from UniProt
+    gbk_pdb_insert_values = set()
+    for uniprot_acc in tqdm(uniprot_dict, desc="Identifying new protein-PDB relationships to add to db"):
         genbank_acc = uniprot_dict[uniprot_acc]["genbank_accession"]['gbk_acc']
-        gbk_id = gbk_dict[genbank_acc]
+        gbk_db_id = gbk_dict[genbank_acc]
 
+        # set of pdb_accessions retrieved from UniProt
         retrieved_pdbs = uniprot_dict[uniprot_acc]["pdb"]
         if len(retrieved_pdbs) == 0:
             continue
 
+        # set of pdb_db_ids the protein (gbk_db_id) is already related to in the db
+        try:
+            existing_pdb_relationships = gbk_pdb_rel_table_dict[gbk_db_id]  
+        except KeyError:
+            existing_pdb_relationships = set()
+
         for pdb_acc in retrieved_pdbs:
-            if pdb_acc in existing_pdbs:
-                # check if the gbk_id is the same
-                current_pdbs = pdb_table_dict[gbk_id]
-                if pdb_acc not in current_pdbs:
-                    update_pdbs.add( (pdb_acc, gbk_id) )
-            
-            else:
-                pdb_insert_values.add( (pdb_acc, gbk_id) )
-        
+            pdb_db_id = pdb_table_dict[pdb_acc]
+
+            try:
+                if pdb_db_id not in existing_pdb_relationships:
+                    # genbank and pdb records not yet stored together in the relationship table
+                    gbk_pdb_insert_values.add( (gbk_db_id, pdb_db_id) )
+            except KeyError:
+                # genbank not listed in the Genbanks_Pdbs relationship table
+                gbk_pdb_insert_values.add( (gbk_db_id, pdb_db_id) )
+
         if args.delete_old_pdbs:
-            existing_pdb_records = pdb_table_dict[gbk_id]
-            for pdb_acc in existing_pdb_records:
+            # convert gbk_pdb_rel_table_dict to be keyed by pdb_db_ids and valued by set of gbk_db_ids
+            pdb_gbk_relationships = {}
+            for existing_gbk_id in gbk_pdb_rel_table_dict:
+                existing_pdbs = gbk_pdb_rel_table_dict[existing_gbk_id]
+                for pdb in existing_pdbs:
+                    try:
+                        pdb_gbk_relationships[pdb].add(existing_gbk_id)
+                    except KeyError:
+                        pdb_gbk_relationships[pdb] = {existing_gbk_id}
+
+            # for each pdb_db_id related to the current protein in the db
+            # get the corresponding pdb_accession
+            all_existing_pdb_ids = list(set(pdb_table_dict.values()))
+            all_existing_pdb_accs = list(pdb_table_dict.keys())
+
+            for pdb_db_id in existing_pdb_relationships:
+                position = all_existing_pdb_ids.index(pdb_db_id)
+                pdb_acc = all_existing_pdb_accs[position]
+
                 if pdb_acc not in retrieved_pdbs:
-                    delete_pdbs.add( (pdb_acc,) )
+                    # delete genbank-pdb relationship
+                    relationships_to_delete.add( (gbk_db_id, pdb_db_id) )
 
-    if len(pdb_insert_values) != 0:
-        insert_data(connection, "Pdbs", ["pdb_accession", "genbank_id"], list(pdb_insert_values))
+                    # check if can delete pdb accession because it is not linked to any other proteins
+                    if len(pdb_gbk_relationships[pdb_db_id]) != 1:  # deleting one pdb accession will not leave not related to any genbanks
+                        pdbs_to_delete.add( (pdb_acc) )
 
-    if len(update_pdbs) != 0:
-        with connection.begin():
-            for record in tqdm(update_pdbs, desc="Updating PDB records"):
-                    connection.execute(
-                        text(
-                            "UPDATE Pdbs "
-                            f"SET genbank_id = {record[1]} "
-                            f"WHERE pdb_accession = '{record[0]}'"
-                        )
-                    )
+    if len(gbk_pdb_insert_values) != 0:
+        insert_data(connection, "Genbanks_Pdbs", ["genbank_id", "pdb_id"], list(gbk_pdb_insert_values))
 
-    if args.delete_old_pdbs and len(delete_pdbs) != 0:
+    if args.delete_old_pdbs and len(pdbs_to_delete) != 0:
         with connection.begin():
-            for record in tqdm(delete_pdbs, desc="Deleteing old PDB accessions"):
+            for record in tqdm(pdbs_to_delete, desc="Deleteing old PDB accessions"):
             # record = (pdb_acc,)
                 connection.execute(
                     text(
@@ -319,5 +361,16 @@ def add_pdb_accessions(uniprot_dict, gbk_dict, connection, args):
                         f"WHERE pdb_accession = '{record[0]}'"
                     )
                 )
+
+    if args.delete_old_pdbs and len(relationships_to_delete) != 0:
+        with connection.begin():
+            for record in tqdm(relationships_to_delete, desc="Deleteing old Genbank-PDB relationships"):
+            # record = (pdb_acc,)
+                connection.execute(
+                    text(
+                        "DELETE Genbanks_Pdbs "
+                        f"WHERE genbank_id = '{record[0]}' AND pdb_id = '{record[1]}'"
+                    )
+                )
                 
     return
diff --git a/cazy_webscraper/sql/sql_interface/get_api_data.py b/cazy_webscraper/sql/sql_interface/get_api_data.py
index 490ec331..86d4f843 100644
--- a/cazy_webscraper/sql/sql_interface/get_api_data.py
+++ b/cazy_webscraper/sql/sql_interface/get_api_data.py
@@ -73,7 +73,7 @@ def get_class_fam_annotations(gbk_dict, query_data, connection, args):
 
     # retrieve the data from the CAZy Family table
     with Session(bind=connection) as session:
-        fam_table_query = session.query(Genbank.genbank_id).\
+        fam_table_query = session.query(Genbank, CazyFamily).\
             join(CazyFamily, Genbank.families).\
             filter(Genbank.genbank_accession.in_(gbk_accessions)).\
             all()
@@ -88,7 +88,7 @@ def get_class_fam_annotations(gbk_dict, query_data, connection, args):
     for record in tqdm(fam_table_query, desc="Getting CAZy class/family annotations"):
         gbk_acc = record[0].genbank_accession
 
-        if args.cazy_class:
+        if 'class' in args.include:
             fam = record[1].family
             cazy_class = re.match(r"\D{2,3}\d", fam).group()[:-1]
 
@@ -103,7 +103,7 @@ def get_class_fam_annotations(gbk_dict, query_data, connection, args):
             except KeyError:
                 query_data[gbk_acc] = {'class': {cazy_class}}
         
-        if args.cazy_family:
+        if 'family' in args.include:
             fam = record[1].family
 
             try:
@@ -117,7 +117,7 @@ def get_class_fam_annotations(gbk_dict, query_data, connection, args):
             except KeyError:
                 query_data[gbk_acc] = {'family': {fam}}
 
-        if args.cazy_subfamily:
+        if 'subfamily' in args.include:
             subfam = record[1].subfamily
 
             try:
@@ -163,7 +163,7 @@ def get_tax_annotations(gbk_dict, query_data, connection, args):
     for record in tqdm(tax_query, desc="Getting taxonomy data"):
         gbk_acc = record[0].genbank_accession
 
-        if args.kingdom:
+        if 'kingdom' in args.include:
             kingdom = record[2].kingdom
 
             try:
@@ -182,7 +182,7 @@ def get_tax_annotations(gbk_dict, query_data, connection, args):
             except KeyError:
                 query_data[gbk_acc] = {'kingdom': kingdom}
         
-        if args.genus:
+        if 'genus' in args.include:
             genus = record[1].genus
 
             try:
@@ -201,7 +201,7 @@ def get_tax_annotations(gbk_dict, query_data, connection, args):
             except KeyError:
                 query_data[gbk_acc] = {'genus': genus}
 
-        if args.organism:
+        if 'organism' in args.include:
             genus = record[1].genus
             species = record[1].species
             organism = f"{genus} {species}"
@@ -241,7 +241,6 @@ def get_ec_annotations(gbk_dict, query_data, connection):
     # retrieve the data from the Taxonomy and Kingdom tables
     with Session(bind=connection) as session:
         ec_query = session.query(Genbank, Ec).\
-            join(Taxonomy, (Taxonomy.kingdom_id == Kingdom.kingdom_id)).\
             join(Ec, Genbank.ecs).\
             filter(Genbank.genbank_accession.in_(gbk_accessions)).\
             all()
@@ -285,7 +284,7 @@ def get_pdb_accessions(gbk_dict, query_data, connection):
     # retrieve the data from the Taxonomy and Kingdom tables
     with Session(bind=connection) as session:
         pdb_query = session.query(Genbank, Pdb).\
-            join(Pdb, (Pdb.genbank_id == Genbank.genbank_id)).\
+            join(Pdb, Genbank.pdbs).\
             filter(Genbank.genbank_accession.in_(gbk_accessions)).\
             all()
 
@@ -340,34 +339,51 @@ def get_uniprot_data(gbk_dict, query_data, connection, args):
     for record in tqdm(uniprot_query, desc="Getting UniProt data"):
         gbk_acc = record[0].genbank_accession
 
-        if args.uniprot:
+        if 'uniprot_acc' in args.include:
             uniprot_accession = record[1].uniprot_accession
+
+            try:
+                query_data[gbk_acc]
+    
+                try:
+                    query_data[gbk_acc]['uniprot_accession']
+                    logger.warning(
+                        f"Multiple UniProt records found for GBK acc {gbk_acc}\n"
+                        "Retreiving only one."
+                    )
+                    query_data[gbk_acc]['uniprot_accession'] = uniprot_accession
+
+                except KeyError:
+                    query_data[gbk_acc]['uniprot_accession'] = uniprot_accession
+
+            except KeyError:
+                query_data[gbk_acc] = {
+                    'uniprot_accession': uniprot_accession,
+                }
+
+        if 'uniprot_name' in args.include:
             uniprot_name = record[1].uniprot_name
 
             try:
                 query_data[gbk_acc]
                 
                 try:
-                    query_data[gbk_acc]['uniprot_accession']
                     query_data[gbk_acc]['uniprot_name']
                     logger.warning(
                         f"Multiple UniProt records found for GBK acc {gbk_acc}\n"
                         "Retreiving only one."
                     )
-                    query_data[gbk_acc]['uniprot_accession'] = uniprot_accession
                     query_data[gbk_acc]['uniprot_name'] = uniprot_name
+                    
                 except KeyError:
-
-                    query_data[gbk_acc]['uniprot_accession'] = uniprot_accession
                     query_data[gbk_acc]['uniprot_name'] = uniprot_name
 
             except KeyError:
                 query_data[gbk_acc] = {
-                    'uniprot_accession': uniprot_accession,
                     'uniprot_name': uniprot_name,
                 }
-        
-        if args.seq_uniprot:
+
+        if 'uniprot_seq' in args.include:
             seq = record[1].sequence
             seq_date = record[1].seq_update_date
 
diff --git a/cazy_webscraper/sql/sql_interface/get_records.py b/cazy_webscraper/sql/sql_interface/get_records.py
index fb495f16..499871ba 100644
--- a/cazy_webscraper/sql/sql_interface/get_records.py
+++ b/cazy_webscraper/sql/sql_interface/get_records.py
@@ -76,7 +76,7 @@ def get_user_genbank_sequences(gbk_table_dict, args):
 
     for gbk_accession in tqdm(gbk_accessions, desc="Getting database IDs for provided GenBank IDs"):
         try:
-            gbk_dict[gbk_accession] = gbk_table_dict[gbk_accessions]
+            gbk_dict[gbk_accession] = gbk_table_dict[gbk_accession]
         except KeyError:
             logging.warning(
                 f"Genbank accession {gbk_accession} retrieved from list in file\n"
diff --git a/cazy_webscraper/sql/sql_interface/get_selected_gbks.py b/cazy_webscraper/sql/sql_interface/get_selected_gbks.py
index 37668baf..4c9975b6 100644
--- a/cazy_webscraper/sql/sql_interface/get_selected_gbks.py
+++ b/cazy_webscraper/sql/sql_interface/get_selected_gbks.py
@@ -44,6 +44,8 @@
 import logging
 import sys
 
+from sqlalchemy import select
+from sqlalchemy.orm import aliased
 from tqdm import tqdm
 
 from cazy_webscraper.sql.sql_orm import (
@@ -56,6 +58,16 @@
 )
 
 
+CLASS_ABBREVIATIONS = {
+    'Glycoside Hydrolases (GHs)': 'GH',
+    'GlycosylTransferases (GTs)': 'GT',
+    'Polysaccharide Lyases (PLs)': 'PL',
+    'Carbohydrate Esterases (CEs)': 'CE',
+    'Auxiliary Activities (AAs)': 'AA',
+    'Carbohydrate-Binding Modules (CBMs)': 'CBM',
+}
+
+
 def get_ids(genbank_accessions, connection):
     """Get the local CAZyme database IDs for the list of provided GenBank accessions.
     
@@ -122,7 +134,6 @@ def get_genbank_accessions(
         initially_selected_gbk,
         taxonomy_filters,
         kingdom_filters,
-        connection
     )
     
     if len(filtered_gbk_accessions) == 0:
@@ -136,6 +147,7 @@ def get_genbank_accessions(
     # Apply EC number filter if provided
     if len(ec_filters) != 0:
         filtered_gbk_accessions = apply_ec_filters(
+            filtered_gbk_accessions,
             ec_filters,
             connection,
         )
@@ -171,15 +183,6 @@ def get_class_fam_genbank_accessions(
     """
     logger = logging.getLogger(__name__)
 
-    class_abbrevs = {
-        'Glycoside Hydrolases (GHs)': 'GH',
-        'GlycosylTransferases (GTs)': 'GT',
-        'Polysaccharide Lyases (PLs)': 'PL',
-        'Carbohydrate Esterases (CEs)': 'CE',
-        'Auxiliary Activities (AAs)': 'AA',
-        'Carbohydrate-Binding Modules (CBMs)': 'CBM',
-    }
-
     initially_selected_gbk = []
 
     if len(class_filters) == 0 and len(family_filters) == 0:
@@ -193,68 +196,71 @@ def get_class_fam_genbank_accessions(
                 all()
 
             initially_selected_gbk = gbk_query
+        
+        return initially_selected_gbk
 
-    else:
-        if len(class_filters) != 0:
-            logger.warning("Applying CAZy class filter(s)")
-        for cazy_class in tqdm(class_filters, desc="Retrieving GenBank accessions for selected CAZy classes"):
-            class_abbrev = class_abbrevs[cazy_class]
+    if len(class_filters) != 0:
+        logger.warning("Applying CAZy class filter(s)")
+    for cazy_class in tqdm(class_filters, desc="Retrieving GenBank accessions for selected CAZy classes"):
+        class_abbrev = CLASS_ABBREVIATIONS[cazy_class]
 
-            with Session(bind=connection) as session:
-                class_subquery = session.query(Genbank.genbank_id).\
+        # perform a subquery to retrieve all CAZy families in the CAZy class
+        inner_stmt = select(CazyFamily.family).where(CazyFamily.family.like(f'{class_abbrev}%'))
+        subq = inner_stmt.subquery()
+        aliased_families = aliased(CazyFamily, subq)
+        stmt = select(aliased_families)
+
+        # perform query to retrieve proteins in the CAZy families
+        with Session(bind=connection) as session:
+            gbk_query = session.query(Genbank, Taxonomy, Kingdom).\
+                join(Taxonomy, (Taxonomy.kingdom_id == Kingdom.kingdom_id)).\
+                join(Genbank, (Genbank.taxonomy_id == Taxonomy.taxonomy_id)).\
                 join(CazyFamily, Genbank.families).\
-                filter(CazyFamily.family.like(f'{class_abbrev}%')).\
-                subquery()
+                filter(CazyFamily.family.in_(stmt)).\
+                all()
 
+        initially_selected_gbk += gbk_query
+
+    if len(family_filters) != 0:
+        logger.warning("Applying CAZy family filter(s)")
+    for cazy_family in tqdm(family_filters, desc="Retrieving GenBank accessions for selected CAZy families"):
+        inner_stmt = select(CazyFamily.family).where(CazyFamily.family == cazy_family)
+        subq = inner_stmt.subquery()
+        aliased_families = aliased(CazyFamily, subq)
+        stmt = select(aliased_families)
+
+        if cazy_family.find('_') != -1:  # subfamily
             with Session(bind=connection) as session:
                 gbk_query = session.query(Genbank, Taxonomy, Kingdom).\
                     join(Taxonomy, (Taxonomy.kingdom_id == Kingdom.kingdom_id)).\
                     join(Genbank, (Genbank.taxonomy_id == Taxonomy.taxonomy_id)).\
                     join(CazyFamily, Genbank.families).\
-                    filter(Genbank.genbank_id.in_(class_subquery)).\
+                    filter(CazyFamily.subfamily.in_(stmt)).\
                     all()
-
-            initially_selected_gbk += gbk_query
-
-        if len(family_filters) != 0:
-            logger.warning("Applying CAZy family filter(s)")
-        for cazy_fam in tqdm(family_filters, desc="Retrieving GenBank accessions for selected CAZy families"):
-            if cazy_fam.find('_') != -1:  # subfamily
-                with Session(bind=connection) as session:
-                    fam_subquery = session.query(Genbank.genbank_id).\
-                    join(CazyFamily, Genbank.families).\
-                    filter(CazyFamily.subfamily == cazy_fam).\
-                    subquery()
-
-            else:  # family
-                with Session(bind=connection) as session:
-                    fam_subquery = session.query(Genbank.genbank_id).\
-                    join(CazyFamily, Genbank.families).\
-                    filter(CazyFamily.family == cazy_fam).\
-                    subquery()
-
+        
+        else:
             with Session(bind=connection) as session:
                 gbk_query = session.query(Genbank, Taxonomy, Kingdom).\
                     join(Taxonomy, (Taxonomy.kingdom_id == Kingdom.kingdom_id)).\
                     join(Genbank, (Genbank.taxonomy_id == Taxonomy.taxonomy_id)).\
                     join(CazyFamily, Genbank.families).\
-                    filter(Genbank.genbank_id.in_(fam_subquery)).\
+                    filter(CazyFamily.family.in_(stmt)).\
                     all()
 
-            initially_selected_gbk += gbk_query
+        initially_selected_gbk += gbk_query
         
-    return initially_selected_gbk
+    return list(set(initially_selected_gbk))
 
 
 def apply_tax_filters(
-    initially_selected_gbk,
+    initally_selected_records,
     taxonomy_filters,
     kingdom_filters,
-    connection,
 ):
     """Filter retrieved GenBank accessions by taxonomy filters.
     
-    :param initally_selected_gbk: list of db Genbank objs retrieved from the db
+    :param initally_selected_records: list of db objs retrieved from the db
+        including a Genbank, Taxonomy and Kingdom record
     :param taxonomy_filters: dict of taxonom filters to limit the retrieval of data to
     :param kingdom_filters: set of tax kingdoms to limit the retrieval of data to
     :param connection: open sqlaclchemy connection for an SQLite db
@@ -263,95 +269,45 @@ def apply_tax_filters(
     """
     logger = logging.getLogger(__name__)
     
-    if len(taxonomy_filters['genera']) == 0 and len(taxonomy_filters['species']) == 0 and len(taxonomy_filters['strains']) == 0 and len(kingdom_filters) == 0:
+    if len(taxonomy_filters['genera']) == 0 and \
+        len(taxonomy_filters['species']) == 0 and \
+        len(taxonomy_filters['strains']) == 0 and \
+        len(kingdom_filters) == 0:
         logger.warning("Applying no taxonomic filters")
-        gbks = [obj[0] for obj in initially_selected_gbk]
+        gbks = [obj[0] for obj in initally_selected_records]
         return set(gbks)
-    
-    tax_ids = set()
-    kingdom_applied = False
-    genus_applied = False
-    species_applied = False
-    strains_applied = False
-    
-    for kingdom in tqdm(kingdom_filters, desc="Retrieving IDs of species from selected kingdoms"):
-        with Session(bind=connection) as session:
-            kingdom_query = session.query(Taxonomy.taxonomy_id).\
-                join(Kingdom, (Kingdom.kingdom_id == Taxonomy.kingdom_id)).\
-                filter(Kingdom.kingdom == kingdom).\
-                all()
-            for taxa in kingdom_query:
-                tax_ids.add(taxa[0])
-        
-        kingdom_applied = True
-
-    try:
-        genera = taxonomy_filters['genus']
-
-        for genus in tqdm(genera, desc="Retrieving IDs of species from selected genera"):
-            with Session(bind=connection) as session:
-                tax_query = session.query(Taxonomy.taxonomy_id).\
-                    filter(Taxonomy.genus == genus).\
-                    all()
-                for taxa in tax_query:
-                    tax_ids.add(taxa[0])
-
-        genus_applied = True
-    
-    except KeyError:
-        pass
-
-    try:
-        species = taxonomy_filters['species']
-
-        for sp in tqdm(species, desc="Retrieving IDs of species from selected species"):
-            with Session(bind=connection) as session:
-                tax_query = session.query(Taxonomy.taxonomy_id).\
-                    filter(Taxonomy.species.like(f'{sp}%')).\
-                    all()
-                for taxa in tax_query:
-                    tax_ids.add(taxa[0])
-        
-        species_applied = True
-
-    except KeyError:
-        pass
-
-    try:
-        strains = taxonomy_filters['strains']
+ 
+    tax_filtered_gbks = set()  # Set of Genbank records from the local database
+
+    if len(kingdom_filters) == 0:
+        logger.warning("Not applying kingdom filter(s)")
+    for kingdom in tqdm(kingdom_filters, desc="Applying kingdom filter(s)"):
+        for obj in initally_selected_records:
+            if kingdom == obj[2].kingdom:
+                tax_filtered_gbks.add(obj[0])
+
+    if len(taxonomy_filters['genera']) == 0:
+        logger.warning("Npt applying genera filters")
+    for genus in taxonomy_filters['genera']:
+        for obj in initally_selected_records:
+            if genus == obj[1].genus:
+                tax_filtered_gbks.add(obj[0])
+                
+    if len(taxonomy_filters['species']) == 0:
+        logger.warning("Not applying species filters")
+    for species in taxonomy_filters['species']:
+        for obj in initally_selected_records:
+            if species == obj[1].species.split(" "):
+                tax_filtered_gbks.add(obj[0])
 
-        for strain in tqdm(strains, desc="Retrieving IDs of species from selected strains"):
-            with Session(bind=connection) as session:
-                tax_query = session.query(Taxonomy.taxonomy_id).\
-                    filter(Taxonomy.species == strain).\
-                    all()
-                for taxa in tax_query:
-                    tax_ids.add(taxa[0])
+    if len(taxonomy_filters['strains']) == 0:
+        logger.warning("Not applying strains filters")
+    for strain in taxonomy_filters['strains']:
+        for obj in initally_selected_records:
+            if strain == obj[1].species:
+                tax_filtered_gbks.add(obj[0])
 
-        strains_applied = True
-    
-    except KeyError:
-        pass
-                
-    if len(tax_ids) == 0 and True in [kingdom_applied, genus_applied, species_applied, strains_applied]:
-        logger.error(
-            "Retrieve NO taxonomy objects matching the provided kingdom and tax filters\n"
-            "Therefore, retrieved NO proteins matching the provided criteria.\n"
-            "Check the database contains the selected kingdoms, genera, species and strains\n"
-            "Terminating program"
-        )
-        sys.exit(1)
-    
-    if True in [kingdom_applied, genus_applied, species_applied, strains_applied]:
-        filtered_gbk = set()
-        for gbk in initially_selected_gbk:
-            if gbk[1].taxonomy_id in tax_ids:
-                filtered_gbk.add(gbk[0])
-                
-        return filtered_gbk
-    
-    else:
-        return initially_selected_gbk
+    return tax_filtered_gbks
 
 
 def apply_ec_filters(
@@ -369,31 +325,32 @@ def apply_ec_filters(
     """
     logger = logging.getLogger(__name__)
     
-    # retrieve the Genbank db IDs for all GenBank accessions associated with each user selected EC num in the db
-    gbk_ids = set()
+    ec_gbk_ids = set()
 
-    for ec in tqdm(ec_filters, desc="Retrieving selected EC numbers from db"):
+    # Retrieve all Genbank.genbank_ids for each EC number
+    for ec in tqdm(ec_filters, desc="Retrieving gbks for EC# filters"):
         with Session(bind=connection) as session:
             gbk_query = session.query(Genbank.genbank_id).\
                 join(Ec, Genbank.ecs).\
                 filter(Ec.ec_number == ec).\
                 all()
+
         for gbk_id in gbk_query:
-            gbk_ids.add(gbk_id)
+            ec_gbk_ids.add(gbk_id)
 
-    if len(gbk_ids) == 0:
+    if len(ec_gbk_ids) == 0:
         logger.error(
         "Retrieved NO proteins matching the provided EC numbers\n"
-        "Therefore, not retrievign UniProt data for any proteins.\n"
         "Check the local CAZyme db contains the EC numbers provided\n"
         "Terminating program"
     )
         sys.exit(1)
     
-    filtered_gbks = set()
-    for gbk in current_gbk_objs:
-        if gbk.genbank_id in gbk_ids:
-            filtered_gbks.add(gbk)
-    
-    return filtered_gbks
+    ec_filtered_gbks = set()
+
+    for gbk_record in tqdm(current_gbk_objs, desc="Checking gbk records against EC filters"):
+        if (gbk_record.genbank_id,) in ec_gbk_ids:
+            ec_filtered_gbks.add(gbk_record)
+        
+    return ec_filtered_gbks
 
diff --git a/cazy_webscraper/sql/sql_interface/get_selected_pdbs.py b/cazy_webscraper/sql/sql_interface/get_selected_pdbs.py
index 658e0461..c7a060fc 100644
--- a/cazy_webscraper/sql/sql_interface/get_selected_pdbs.py
+++ b/cazy_webscraper/sql/sql_interface/get_selected_pdbs.py
@@ -81,6 +81,14 @@ def get_pdb_accessions(
     # retrieve all PDB accessions for each GenBank accession retrieved for the local CAZyme db
 
     pdb_table_dict = get_table_dicts.get_pdb_table_dict(connection)  # used to retrieve PDB accs
+    # {pdb_accession: pdb_db_id}
+    # convert to be keyed by pdb_db_id and valued by pdb_accession
+    pdb_id_acc_dict = {}
+    for pdb_acc in pdb_table_dict:
+        pdb_id_acc_dict[pdb_table_dict[pdb_acc]] = pdb_acc
+
+    gbk_pdb_table_dict = get_table_dicts.get_gbk_pdb_table_dict(connection)
+    # {gbk_db_id: {pdb_db_id}}
 
     pdb_accessions = set()
 
@@ -88,11 +96,13 @@ def get_pdb_accessions(
         gbk_id = gbk_table_dict[gbk_accession]['gbk_id']
 
         try:
-            pdbs = pdb_table_dict[gbk_id]
+            pdb_ids = gbk_pdb_table_dict[gbk_id]
 
-            for pdb in pdbs:
+            for pdb_id in pdb_ids:
+                # convert pdb_db_id to pdb_accession
+                pdb_acc = pdb_id_acc_dict[pdb_id]
                 # remove chain annotation if present
-                parent_pdb = pdb.split("[")[0]
+                parent_pdb = pdb_acc.split("[")[0]
                 pdb_accessions.add(parent_pdb)
         
         except KeyError:
diff --git a/cazy_webscraper/sql/sql_interface/get_table_dicts.py b/cazy_webscraper/sql/sql_interface/get_table_dicts.py
index 74006ec6..e7739be4 100644
--- a/cazy_webscraper/sql/sql_interface/get_table_dicts.py
+++ b/cazy_webscraper/sql/sql_interface/get_table_dicts.py
@@ -275,22 +275,43 @@ def get_pdb_table_dict(connection):
     
     :param connection: open sqlalchemy db engine connection
     
-    Return dict {gbk_id: {pdb accessions}}
+    Return dict {pdb_accession: pdb_db_id}
     """
     with Session(bind=connection) as session:
         db_pdb_records = session.query(Pdb).all()
 
-    pdb_table_dict = {}  # {gbk_id: {pdb accessions}}
+    pdb_table_dict = {}  # {pdb_accession: pdb_db_id}
 
     for record in tqdm(db_pdb_records, desc="Loading existing PDB db records"):
-        gbk_id = record.genbank_id
+        pdb_table_dict[record.pdb_accession] = record.pdb_id
+
+    return pdb_table_dict 
+
+
+def get_gbk_pdb_table_dict(connection):
+    """Create dict of objects present in the Genbanks_Pdbs table.
+    
+    :param connection: open sqlalchemy db engine connection
+    
+    Return dict {gbk_db_id: {pdb_db_id} }
+    """
+    with Session(bind=connection) as session:
+        all_gbk_pdb_records = session.query(Genbank, Pdb).\
+            join(Pdb, Genbank.pdbs).\
+            all()
+
+    gbk_pdb_table_dict = {}  # {pdb_accession: pdb_db_id}
+
+    for record in tqdm(all_gbk_pdb_records, desc="Loading existing Genbank_Pdbs db records"):
+        genbank_id = record[0].genbank_id
+        pdb_id = record[1].pdb_id
+
         try:
-            pdb_table_dict[gbk_id].add(record.pdb_accession)
-            
+            gbk_pdb_table_dict[genbank_id].add(pdb_id)
         except KeyError:
-            pdb_table_dict[gbk_id] = {record.pdb_accession}
+            gbk_pdb_table_dict[genbank_id] = {pdb_id}
 
-    return pdb_table_dict 
+    return gbk_pdb_table_dict 
 
 
 def get_taxs_table_dict(connection):
diff --git a/cazy_webscraper/sql/sql_orm.py b/cazy_webscraper/sql/sql_orm.py
index baefbbc8..f2d52c6b 100644
--- a/cazy_webscraper/sql/sql_orm.py
+++ b/cazy_webscraper/sql/sql_orm.py
@@ -40,6 +40,7 @@
 # SOFTWARE.
 """Submodule to build a local SQL database"""
 
+from distutils.command.config import LANG_EXT
 import logging
 import re
 
@@ -166,6 +167,14 @@ def sqlite_engine_connect(dbapi_connection, connection_record):
 )
 
 
+genbanks_pdbs = Table(
+    "Genbanks_Pdbs",
+    Base.metadata,
+    Column("genbank_id", Integer, ForeignKey("Genbanks.genbank_id")),
+    Column("pdb_id", Integer, ForeignKey("Pdbs.pdb_id")),
+    PrimaryKeyConstraint("genbank_id", "pdb_id"),
+)
+
 
 # Define class tables
 class Genbank(Base):
@@ -206,7 +215,9 @@ class Genbank(Base):
     
     pdbs = relationship(
         "Pdb",
+        secondary=genbanks_pdbs,
         back_populates="genbank",
+        lazy="dynamic",
     )
     
     uniprot = relationship(
@@ -364,13 +375,14 @@ class Pdb(Base):
 
     pdb_id = Column(Integer, primary_key=True)
     pdb_accession = Column(String)
-    genbank_id = Column(Integer, ForeignKey('Genbanks.genbank_id'))
     
     Index('pdb_idx', pdb_accession)
 
     genbank = relationship(
         "Genbank",
+        secondary=genbanks_pdbs,
         back_populates="pdbs",
+        lazy="dynamic",
     )
     
     def __str__(self):
diff --git a/cazy_webscraper/utilities/__init__.py b/cazy_webscraper/utilities/__init__.py
index 5ab7bf98..863d31ae 100644
--- a/cazy_webscraper/utilities/__init__.py
+++ b/cazy_webscraper/utilities/__init__.py
@@ -41,82 +41,13 @@
 """Module containing functions for building parsers, loggers and parsing configuration."""
 
 
-import logging
-import os
-
-from pathlib import Path
 from typing import Optional
 
 
-def config_logger(args) -> logging.Logger:
-    """Configure package wide logger.
-
-    Configure a logger at the package level, from which the module will inherit.
-    If CMD-line args are provided, these are used to define output streams, and
-    logging level.
-
-    :param args: cmd-line args parser
-
-    Return nothing
-    """
-    logger = logging.getLogger(__package__)
-    logger.setLevel(logging.INFO)
-
-    # define logging level
-    if args.verbose:
-        logger.setLevel(logging.INFO)
-    else:
-        logger.setLevel(logging.WARNING)
-
-    # Set format of loglines
-    log_formatter = logging.Formatter("[%(levelname)s] [%(name)s]: %(message)s")
-
-    # Setup console handler to log to terminal
-    console_log_handler = logging.StreamHandler()
-    console_log_handler.setFormatter(log_formatter)
-    if args.verbose:
-        console_log_handler.setLevel(logging.INFO)
-    else:
-        console_log_handler.setLevel(logging.WARNING)
-    logger.addHandler(console_log_handler)
-
-    # Setup file handler to log to a file
-    if args.log is not None:
-        file_log_handler = logging.FileHandler(args.log)
-        file_log_handler.setFormatter(log_formatter)
-        if args.verbose:
-            file_log_handler.setLevel(logging.INFO)
-        else:
-            file_log_handler.setLevel(logging.WARNING)
-        logger.addHandler(file_log_handler)
-
-    return
-
-
-def build_logger(output):
-    """Build loggers with pre-defined parameters for writing out errors and failed scrapes.
-
-    :param output: Path to output dir or None
-
-    Return logger object.
-    """
-    file_name = output.name.split('.')[0]
-    logger = logging.getLogger(file_name)
-
-    # Set format of loglines
-    log_formatter = logging.Formatter(file_name + ": {} - {}".format("%(asctime)s", "%(message)s"))
-
-    # Setup file handler to log to a file
-    file_log_handler = logging.FileHandler(output)
-    file_log_handler.setLevel(logging.WARNING)
-    file_log_handler.setFormatter(log_formatter)
-    logger.addHandler(file_log_handler)
-
-    return logger
-
-
 def termcolour(
-    logstr: str, color: Optional[str] = None, bold: Optional[bool] = False
+    logstr: str,
+    color: Optional[str] = None,
+    bold: Optional[bool] = False
 ) -> str:
     """Return the passed logstr, wrapped in terminal colouring."""
     # For terminal colouring
diff --git a/cazy_webscraper/utilities/file_io/__init__.py b/cazy_webscraper/utilities/file_io/__init__.py
deleted file mode 100644
index d8ff3976..00000000
--- a/cazy_webscraper/utilities/file_io/__init__.py
+++ /dev/null
@@ -1,196 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-# (c) University of St Andrews 2020-2021
-# (c) University of Strathclyde 2020-2021
-# (c) James Hutton Institute 2020-2021
-#
-# Author:
-# Emma E. M. Hobbs
-
-# Contact
-# eemh1@st-andrews.ac.uk
-
-# Emma E. M. Hobbs,
-# Biomolecular Sciences Building,
-# University of St Andrews,
-# North Haugh Campus,
-# St Andrews,
-# KY16 9ST
-# Scotland,
-# UK
-
-# The MIT License
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
-
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-"""Submodule for handling inputs and outputs"""
-
-
-import logging
-import shutil
-import sys
-
-from Bio import SeqIO
-from Bio.Blast.Applications import NcbimakeblastdbCommandline
-
-
-
-def make_target_directory(output_path, force):
-    """Create target output directory for SQL database file and/or JSON file.
-
-    :param output_path: Path to target output file
-    :param force: bool, whether to overwrite an existing output file
-
-    Raises FileExistsError if target database file output path exists and 
-    force (force overwrite) is False.
-
-    Return Nothing
-    """
-    logger = logging.getLogger(__name__)
-
-    if output_path.exists():
-        if force is True:
-
-            logger.warning(
-                "Target output path exists.\n"
-                "Forced overwritting enabled. Overwritting existing file."
-            )
-            return
-        
-        else:
-            logger.warning(
-                "Target output path exists.\n"
-                "Forced overwritting NOT enabled\n."
-                "To overwrite the existing file\n,"
-                "rerun with the -f flag.\n"
-                "Terminating program."
-            )
-            sys.exit(1)
-
-    # make output directory
-    output_path.parent.mkdir(parents=True, exist_ok=force)
-    logger.warning(f"Built output directory: {output_path.parent}")
-
-    return
-
-
-def make_output_directory(output_path, force, nodelete):
-    """Create output directory to which multiple output files will be written
-
-    :param output_path: Path to target output dir
-    :param force: bool, whether to overwrite an existing output file
-    :param nodelete: bool, whether to delete contents in an existing target output dir
-
-    Raises FileExistsError if target database file output path exists and 
-    force (force overwrite) is False.
-
-    Return Nothing
-    """
-    logger = logging.getLogger(__name__)
-
-    if output_path.exists():
-
-        if nodelete is True:
-            logger.warning(
-                "Target output path for database exists.\n"
-                "Forced writing in existing output directory.\n"
-                "NOT deleting existing content in the output directory."
-            )
-            return
-
-        else:
-            logger.warning(
-                "Target output path for database exists.\n"
-                "Forced writing in existing output directory.\n"
-                "DELETING existing content in the output directory."
-            )
-
-    # make output directory
-    try:
-        output_path.mkdir(parents=True, exist_ok=force)
-    except FileExistsError:
-        pass
-    logger.warning(f"Built directory to store family files: {output_path}")
-
-    return
-
-
-def write_out_fasta(record, genbank_accession, args):
-    """Write out GenBank protein record to a FASTA file.
-
-    :param record: SeqIO parsed record
-    :param genbank_accession: str, accession number of the protein sequence in NCBI.GenBank
-    :param args: cmd-line arguments parser
-
-    Return nothing.
-    """
-    if args.fasta == 'separate':
-        fasta_name = f"{genbank_accession}.fasta"
-        fasta_name = args.write / fasta_name
-
-        with open(fasta_name, "w") as fh:
-            SeqIO.write(record, fh, "fasta")
-
-    else:  # add sequences to FASTA file
-        with open(args.fasta, "a") as fh:
-            SeqIO.write(record, fh, "fasta")
-
-    return
-
-
-def write_fasta_for_db(record, genbank_accession, args):
-    """Write out protein sequences to FASTA file for building a BLAST db of all retrieved sequences.
-
-    :param record: SeqIO parsed record
-    :param genbank_accession: str, accession number of the protein sequence in NCBI.GenBank
-    :param args: cmd-line arguments parser
-
-    Return nothing.
-    """
-    fasta_name = args.blastdb
-    fasta_name = fasta_name / "blast_db.fasta"
-
-    with open(args.fasta, "a") as fh:
-        SeqIO.write(record, fh, "fasta")
-
-    return
-
-
-def build_blast_db(args):
-    """Build BLAST database of sequences retrieved from GenBank.
-
-    :param args: cmd-line arguments parser
-
-    Return nothing.
-    """
-    logger = logging.getLogger(__name__)
-
-    fasta_name = args.blastdb
-    fasta_name = fasta_name / "blast_db.fasta"
-
-    # build the command
-    cmd_makedb = NcbimakeblastdbCommandline(cmd='makeblastdb', dbtype='prot', input_file=fasta_name)
-    # invoke the command
-    stdout, stderr = cmd_makedb()
-
-    # check the command was successfully exectured
-    if len(stderr) != 0:
-        logger.warning()
-        print(f"Could not build non-CAZyme db.\nstdout={stdout}\nstderr={stderr}")
-
-    return
diff --git a/cazy_webscraper/utilities/parse_configuration/__init__.py b/cazy_webscraper/utilities/parse_configuration/__init__.py
index 2e2d997d..10e1840c 100644
--- a/cazy_webscraper/utilities/parse_configuration/__init__.py
+++ b/cazy_webscraper/utilities/parse_configuration/__init__.py
@@ -230,10 +230,13 @@ def get_yaml_configuration(
             if yaml_config_dict["kingdoms"] is not None:
                 for kingdom in yaml_config_dict["kingdoms"]:
                     if kingdom.lower() == 'unclassified':
-                        kingdom_filters["kingdoms"].add(kingdom.lower())
+                        kingdom_filters.add(kingdom.lower())
                     else:
                         new_kingdom = kingdom[0].upper() + kingdom[1:].lower()
-                        kingdom_filters["kingdoms"].add(new_kingdom)
+                        kingdom_filters.add(new_kingdom)
+
+        elif key == 'ec':
+            continue
 
         else:  # key is a CAZy class and underneath are CAZy families to scrape
             if yaml_config_dict[key] is not None:  # CAZy families were listed
@@ -290,28 +293,35 @@ def parse_user_cazy_classes(cazy_classes, cazy_class_synonym_dict):
     logger = logging.getLogger(__name__)
     logger.info("Standardising names of class listed in configuration file")
 
+    accepted_class_names = list(cazy_class_synonym_dict.keys()) + list(cazy_class_synonym_dict.values())
     standardised_class_names = list(cazy_class_synonym_dict.keys())
 
-    index = 0
-    for index in range(len(cazy_classes)):
+    selected_classes = []
+
+    for cazy_class in cazy_classes:
         # identify user defined CAZy classes not written in standardised format
-        if cazy_classes[index] not in standardised_class_names:
-            for key in cazy_class_synonym_dict:
-                if cazy_classes[index] in cazy_class_synonym_dict[key]:  # if in synonyms in cazy_class_synonym_dict
-                    cazy_classes[index] = key  # standardise the class name
+        if cazy_class not in standardised_class_names:
 
-        # check all names are standardised, remove names that could not be standardised
-        if cazy_classes[index] not in standardised_class_names:
-            logger.warning(
-                (
-                    f"'{cazy_classes[index]}' could not be standardised.\n"
-                    "Please use a synonym in the file_io/cazy_class_synonym_dictionary.json.\n"
-                    f"'{cazy_classes[index]}' will NOT be scraped."
+            # not written in standardised format
+            # check if accepted class name
+            if cazy_class not in accepted_class_names:
+                logger.warning(
+                    (
+                        f"'{cazy_class}' could not be standardised.\n"
+                        "Please use a synonym in the file_io/cazy_class_synonym_dictionary.json.\n"
+                        f"'{cazy_class}' will NOT be scraped."
+                    )
                 )
-            )
-            del cazy_classes[index]
 
-    return cazy_classes
+            else:  # written in accepted alternative format
+                for standardised_class_name in cazy_class_synonym_dict:
+                    if cazy_class in cazy_class_synonym_dict[standardised_class_name]:
+                        selected_classes.append(standardised_class_name)
+
+        else:  # written in standardised format
+            selected_classes.appent(cazy_class)
+
+    return list(set(cazy_classes))
 
 
 def get_cmd_scrape_config(
@@ -347,13 +357,13 @@ def get_cmd_scrape_config(
 
     if args.species is not None:
         cmd_species = (args.species).split(",")
-        for cmd_species in cmd_species:
-            taxonomy_filter["species"].add(cmd_species)
+        for species in cmd_species:
+            taxonomy_filter["species"].add(species)
     
     if args.strains is not None:
         cmd_strains = (args.strains).split(",")
-        for cmd_genus in cmd_strains:
-            taxonomy_filter["strains"].add(cmd_strains)
+        for strain in cmd_strains:
+            taxonomy_filter["strains"].add(strain)
     
     if args.kingdoms is not None:
         cmd_kingdoms = (args.kingdoms).split(",")
@@ -381,33 +391,33 @@ def get_cmd_defined_families(config_dict, args):
 
     for fam in cmd_families:
         try:
-            if fam.find("GH") != -1:
+            if fam.startswith("GH"):
                 re.match(r"GH\d+", fam, re.IGNORECASE).group()
                 config_dict['Glycoside Hydrolases (GHs)'].add(fam)
 
-            elif fam.find("GT") != -1:
+            elif fam.startswith("GT"):
                 re.match(r"GT\d+", fam, re.IGNORECASE).group()
                 config_dict['GlycosylTransferases (GTs)'].add(fam)
 
-            elif fam.find("PL") != -1:
+            elif fam.startswith("PL"):
                 re.match(r"PL\d+", fam, re.IGNORECASE).group()
                 config_dict['Polysaccharide Lyases (PLs)'].add(fam)
 
-            elif fam.find("CE") != -1:
+            elif fam.startswith("CE"):
                 re.match(r"CE\d+", fam, re.IGNORECASE).group()
                 config_dict['Carbohydrate Esterases (CEs)'].add(fam)
 
-            elif fam.find("AA") != -1:
+            elif fam.startswith("AA"):
                 re.match(r"AA\d+", fam, re.IGNORECASE).group()
                 config_dict['Auxiliary Activities (AAs)'].add(fam)
 
-            elif fam.find("CBM") != -1:
+            elif fam.startswith("CBM"):
                 re.match(r"CBM\d+", fam, re.IGNORECASE).group()
-                config_dict['Carbohydrate-Binding Modules (CBMs)'].ad(fam)
+                config_dict['Carbohydrate-Binding Modules (CBMs)'].add(fam)
 
             else:
                 logger.warning(
-                    f"Invalid family specified at cmd line: {fam}\n"
+                    f"Do recognise class prefix for family specified at cmd line: {fam}\n"
                     "This family will not be scraped."
                 )
 
@@ -430,7 +440,6 @@ def get_excluded_classes(config_dict, cazy_class_synonym_dict):
 
     Return list of CAZy classes not to be scraped.
     """
-
     cazy_classes_to_scrape = set()
     
     # retrieve the names of classes for which specific families to be scraped HAVE BEEN named
@@ -554,6 +563,15 @@ def get_expansion_configuration(args):
 
 
 def get_ec_config(ec_filters, args):
+    """Parse EC number configuration.
+    
+    Standardise the EC numbers missing digits and remove 'EC' prefix.
+    
+    :param ec_filters: set of EC numbers
+    :param args: cmd line args parser
+    
+    Return set of EC numbers.
+    """
     logger = logging.getLogger(__name__)
 
     if args.config is not None:
diff --git a/cazy_webscraper/utilities/parsers/api_parser.py b/cazy_webscraper/utilities/parsers/api_parser.py
index 25e259e8..efb88b52 100644
--- a/cazy_webscraper/utilities/parsers/api_parser.py
+++ b/cazy_webscraper/utilities/parsers/api_parser.py
@@ -85,14 +85,6 @@ def build_parser(argv: Optional[List] = None):
         help="Path to JSON file containing CAZy class synoymn names",
     )
 
-    parser.add_argument(
-        "--cazy_class",
-        dest="class",
-        action="store_true",
-        default=False,
-        help="Include CAZy class annotations in the query output"
-    )
-
     # Add option to define complete classes to scrape
     parser.add_argument(
         "--classes",
@@ -111,25 +103,6 @@ def build_parser(argv: Optional[List] = None):
         help="Path to configuration file. Default: None, scrapes entire database",
     )
 
-    parser.add_argument(
-        "--delete_old_ec",
-        dest="delete_old_ec",
-        action="store_true",
-        default=False,
-        help=(
-            "Delete EC number-GenBank relationships/annotations\n"
-            "that are not longer listed in UniProt for a given protein"
-        ),
-    )
-
-    parser.add_argument(
-        "--ec",
-        dest="ec",
-        action="store_true",
-        default=False,
-        help="Include EC number annotations in the query output",
-    )
-
     parser.add_argument(
         "--ec_filter",
         type=str,
@@ -137,22 +110,6 @@ def build_parser(argv: Optional[List] = None):
         help="Limit retrieval to proteins annotated with the provided EC numbers. Separate EC numbers with single commas"
     )
 
-    parser.add_argument(
-        "--cazy_family",
-        dest="cazy_family",
-        action="store_true",
-        default=False,
-        help="Include CAZy family annotations in the query output. This is only CAZy families NOT subfamilies"
-    )
-
-    parser.add_argument(
-        "--cazy_subfamily",
-        dest="cazy_subfamily",
-        action="store_true",
-        default=False,
-        help="Include CAZy subfamily annotations in the query output."
-    )
-
     # Add option to specify families to scrape
     parser.add_argument(
         "--families",
@@ -162,11 +119,12 @@ def build_parser(argv: Optional[List] = None):
     )
 
     parser.add_argument(
-        "--genus",
-        dest="genus",
+        "-f",
+        "--force",
+        dest="force",
         action="store_true",
         default=False,
-        help="Include Genus annotations in the query output"
+        help="Force writing to existing output dir",
     )
 
     # Add option to restrict scrape to specific genera
@@ -178,11 +136,11 @@ def build_parser(argv: Optional[List] = None):
     )
 
     parser.add_argument(
-        "--kingdom",
-        dest="kingdom",
-        action="store_true",
-        default=False,
-        help="Include taxonomy Kingdom annotations in the query output"
+        "--include",
+        action="store",
+        nargs="+",
+        choices=["class", "family", "subfamily", "organism", "uniprot_acc", "uniprot_name", "ec", "pdb", "genbank_seq", "uniprot_seq"],
+        help="Additional data to include in the output file. Separate with a single space (' ')"
     )
 
     parser.add_argument(
@@ -203,46 +161,46 @@ def build_parser(argv: Optional[List] = None):
         help="Defines log file name and/or path",
     )
 
-    # Add option to not delete content in the existing cache dir
     parser.add_argument(
-        "--nodelete_cache",
-        dest="nodelete_cache",
+        "-n",
+        "--nodelete",
+        dest="nodelete",
         action="store_true",
         default=False,
-        help="When called, content in the existing cache dir is NOT deleted",
+        help="When called, content in the existing output dir is NOT deleted",
     )
 
+    # Add option to not delete content in the existing cache dir
     parser.add_argument(
-        "--organism",
-        dest="organism",
+        "--nodelete_cache",
+        dest="nodelete_cache",
         action="store_true",
         default=False,
-        help="Include scientific name of the source organism in the query output"
+        help="When called, content in the existing cache dir is NOT deleted",
     )
 
     parser.add_argument(
-        "-p",
-        "--pdb",
-        dest="pdb",
-        action="store_true",
-        default=False,
-        help="Include PDB accessions in the query output",
+        "-o",
+        "--output_dir",
+        type=Path,
+        default=None,
+        help="Path to output dir, default: None (writes to cwd)",
     )
 
     parser.add_argument(
-        "--seq_gebank",
-        dest="seq_genbank",
+        "--overwrite",
+        dest="overwrite",
         action="store_true",
         default=False,
-        help="Include the protein sequences retrieve from GenBank in the query output"
+        help="When called, overwrites existing output files",
     )
 
     parser.add_argument(
-        "--seq_uniprot",
-        dest="seq_uniprot",
-        action="store_true",
-        default=False,
-        help="Include the protein sequences retrieved from UniProt in the query output"
+        "-p",
+        "--prefix",
+        type=str,
+        default=None,
+        help="Str to prefix all output files with, default: None",
     )
 
     # Add option to force file over writting
@@ -274,14 +232,6 @@ def build_parser(argv: Optional[List] = None):
         ),
     )
 
-    parser.add_argument(
-        "--uniprot",
-        dest="uniprot",
-        action="store_true",
-        default=False,
-        help="Include UniProt ID and protein name in the query output"
-    )
-
     # Add option for more detail (verbose) logging
     parser.add_argument(
         "-v",
diff --git a/cazy_webscraper/utilities/parsers/extract_seq_parser.py b/cazy_webscraper/utilities/parsers/extract_seq_parser.py
index 0c729721..b97dd57b 100644
--- a/cazy_webscraper/utilities/parsers/extract_seq_parser.py
+++ b/cazy_webscraper/utilities/parsers/extract_seq_parser.py
@@ -228,6 +228,7 @@ def build_parser(argv: Optional[List] = None):
     )
 
     parser.add_argument(
+        "-n",
         "--nodelete",
         dest="nodelete",
         action="store_true",
diff --git a/cazy_webscraper/utilities/parsers/gbk_seq_parser.py b/cazy_webscraper/utilities/parsers/gbk_seq_parser.py
index e9bba6b7..75e38956 100644
--- a/cazy_webscraper/utilities/parsers/gbk_seq_parser.py
+++ b/cazy_webscraper/utilities/parsers/gbk_seq_parser.py
@@ -120,14 +120,6 @@ def build_parser(argv: Optional[List] = None):
         help="Limit retrieval to proteins annotated with the provided EC numbers. Separate EC numbers with single commas"
     )
 
-    # specify the number of accessions posted in single ePost to NCBI
-    parser.add_argument(
-        "--entrez_batch_size",
-        type=int,
-        default=150,
-        help="Number of accessions posted to NCBI per epost, advice to be max 200. Default=150"
-    )
-
     # Add option to force file over writting
     parser.add_argument(
         "-f",
@@ -135,7 +127,7 @@ def build_parser(argv: Optional[List] = None):
         dest="force",
         action="store_true",
         default=False,
-        help="Force file over writting",
+        help="Force file in existing cache directory",
     )
 
     # Add option to specify families to retrieve protein sequences for
diff --git a/docs/api.rst b/docs/api.rst
new file mode 100644
index 00000000..23a51284
--- /dev/null
+++ b/docs/api.rst
@@ -0,0 +1,135 @@
+====================================
+Interrogating the data using the API
+====================================
+
+The data stored in the local CAZyme database can be interrogated using SQL. ``cazy_webscraper`` also 
+includes an API, which can be used to interrogate the data in the local CAZyme database and write out the retrieved data 
+in ``JSON`` and/or ``CSV`` format.
+
+By default ``cazy_webscraper`` only includes the GenBank accessions of proteins matching the provided 
+criteria, but the inclusion of additional data (such as protein squences, UniProt accessions, EC numbers, etc) 
+is fully customisable.
+
+-----------
+Quick Start
+-----------
+
+To retrieve the GenBank accession of all CAZymes stored in the local CAZyme database, use the following command 
+structure:
+
+.. code-block:: bash
+
+   cw_query_database <path to local CAZyme db> <desired file formats>
+
+.. NOTE::
+   The ``cw`` prefix on command is an abbreviation of ``cazy_webscraper``.
+   
+---------------------
+Accepted file formats
+---------------------
+
+``cw_query_database`` can write the output to a csv or json file.
+
+These are provided as the second arguments to ``cw_query_database``. To write out both a csv and json 
+file use both ``csv`` and ``json`` after the path to the local CAZyme database, separted with a single space.
+
+.. code-block:: bash
+
+    cw_query_database <path to local CAZyme db> csv json
+
+.. NOTE::
+    The order ``csv`` and ``json`` are written does not matter.
+
+.. WARNING::
+    Both ``csv`` and ``json`` are case sensitive.
+
+--------------------
+Command line options
+--------------------
+
+``database`` - **REQUIRED** Path to a local CAZyme database to add UniProt data to.
+
+``file_types`` - **REQUIRED** List of file formats to export the data in. Currently supported: ``csv`` and ``json``.
+
+``--cache_dir`` - Path to cache dir to be used instead of default cache dir path.
+
+``--cazy_synonyms`` - Path to a JSON file containing accepted CAZy class synonsyms if the default are not sufficient.
+
+``--config``, ``-c`` - Path to a configuration YAML file. Default: None.
+
+``--classes`` - list of classes to retrieve data from.
+
+``--ec_filter`` - List of EC numbers to limit the retrieval of protein data with at least one of the given EC numbers *in the local CAZyme database*.
+
+``--force``, ``-f`` - Force writing to existing output dir. Default: False, do not write to existing target output dir. Not applied when ``--output_dir`` is not called.
+
+``--families`` - List of CAZy (sub)families to retrieve UniProt protein data for.
+
+``--genbank_accessions`` - Path to text file containing a list of GenBank accessions to retrieve protein data for. A unique accession per line.
+
+``--genera`` - List of genera to restrict the retrieval of protein to data from UniProt to proteins belonging to one of the given genera.
+
+``--include`` - List additional data to include in the output. Multiple fields can be named, separating each with a single space (' '). The accepted fields are:
+* 'class' - Include the CAZy class annotations
+* 'family' - Include the CAZy family annotations
+* 'subfamily' - Include the subfamily class annotations
+* 'kingdom' - Include the taxonomic kingdom of the source organism
+* 'genus' - Include the genus of the source organism
+* 'organism' - Include the scientific name of the source organism
+* 'uniprot_acc' - Include the UniProt accession
+* 'uniprot_name' - Include the protein name retrieved from UniProt
+* 'ec' - Include the EC number annotations
+* 'pdb' - Include the PDB accessions
+* 'genbank_seq' - Include the GenBank protein sequence
+* 'uniprot_seq' - Include the Uniprot protein sequence
+
+``--kingdoms`` - List of taxonomy kingdoms to retrieve UniProt data for.
+
+``--log``, ``-l`` - Target path to write out a log file. If not called, no log file is written. Default: None (no log file is written out).
+
+``--nodelete``, ``-n`` - When called, content in the existing output  will **not** be deleted. Default: False (existing content is deleted).
+
+``--nodelete_cache`` - When called, content in the existing cache dir will **not** be deleted. Default: False (existing content is deleted).
+
+``--output_dir``, ``-o`` - Define output directory to write out structure files. Default, write structure files to current working directory.
+
+``--overwrite`` - Overwrite existing structure files with the same PDB accession as files being downloaded. Default false, do not overwrite existing files.
+
+``--prefix``, ``-p`` - Had prefix to all output files.
+
+``--retries``, ``-r`` - Define the number of times to retry making a connection to CAZy if the connection should fail. Default: 10.
+
+``--sql_echo`` - Set SQLite engine echo parameter to True, causing SQLite to print log messages. Default: False.
+
+``--species`` - List of species (organsim scientific names) to restrict the retrieval of protein to data from UniProt to proteins belonging to one of the given species.
+
+``--strains`` - List of species strains to restrict the retrieval of protein to data from UniProt to proteins belonging to one of the given strains.
+
+``--timeout``, ``-t`` - Connection timout limit (seconds). Default: 45.
+
+``--uniprot_accessions`` - Path to text file containing a list of UniProt accessions to retrieve protein data for. A unique accession per line.
+
+``--verbose``, ``-v`` - Enable verbose logging. This does **not** set the SQLite engine ``echo`` parameter to True. Default: False.
+
+
+
+-----------
+Basic Usage
+-----------
+
+The command-line options listed above can be used in combination to customise the retrieval of data for proteins of interest. Some options (e.g. ``--families`` and ``--classes``) define the broad group of proteins for which structure files are retrieved, others (e.g. ``--species``) are used to filter and fine-tune the protein dataset for which structure files are retrieved.
+
+The ``--classes``, ``--families``, ``--kingdoms``, ``--genera``, ``--species``, and ``--strains`` filteres are applied 
+in the exactly same for retrieving data from CAZy, UniProt, GenBank, and PDB as for the extraction of data via the API. Examples of using these flags 
+can be found in the ``cazy_webscraper`` and ``cw_query_database`` tutorial in this documentation.
+
+.. NOTE::
+    To retrieve fata for members of specific CAZy subfamilies, list the subfamilies after the ``--families`` 
+    flag.
+
+
+--------------------------------------------
+Retrieving data from a local CAZyme database
+--------------------------------------------
+
+The command for using ``cazy_webscraper`` for interrogating the local CAZyme database and extract data is ``cw_query_databsae``.
diff --git a/docs/apitutorial.rst b/docs/apitutorial.rst
new file mode 100644
index 00000000..f954afb7
--- /dev/null
+++ b/docs/apitutorial.rst
@@ -0,0 +1,434 @@
+================================================
+Tutorial on interrogating the data using the API
+================================================
+
+``cazy_webscraper`` includes an API that can be used to interrogate the data in the local CAZyme database and write out the retrieved data 
+in ``JSON`` and/or ``CSV`` format.
+
+By default ``cazy_webscraper`` only includes the GenBank accessions of proteins matching the provided 
+criteria, but the inclusion of additional data (such as protein squences, UniProt accessions, EC numbers, etc) 
+is fully customisable. 
+
+For interrogating the data and retrieving proteins matching the provided criteria, many of the same configuration options 
+apply to the retrieval of protein data from CAZy, UniProt, GenBank and PDB.
+
+``cazy_webscraper`` can be configured via the **command line** and/or via a **YAML configuration file**.
+
+This page runs through examples of how to combine the various 'filters' that can be applied, to fully customised 
+the retrieval of protein data from the local CAZyme database. These tutorials are designed for those with less experience using command-line tools.
+
+.. NOTE::
+  If you installed ``cazy_webscraper`` using ``bioconda`` or ``pip`` to invoke ``cazy_webscraper`` to retrieve UniProt data call it using ``cw_query_database`` - this is the method used in this tutorial.  
+  If you installed ``cazy_webscraper`` from source then you will need to invoke ``cazy_webscraper`` from the root of the repo using the command ``python3 cazy_webscraper/api/cw_query_database.py``.
+
+From this point on, we will be discusseing the ``cw_query_database`` command, which is used by ``cazy_webscraper`` for 
+retrieving protein data from the local CAZyme database. We also presume you are comfortable configuring ``cazy_webscraper`` for the 
+scraping of data from CAZy.
+
+
+----------------------------------
+Configuration via the command line
+----------------------------------
+
+``cw_query_database`` requires two arguments:
+* The path to the local CAZyme database created using ``cazy_webscraper``
+* The file formats to write out the output
+
+Therefore, ``cw_query_database`` can be enabled using a simple command structure:
+
+.. code-block:: bash
+
+  cazy_webscraper <path to the local CAZyme db> <file formats>
+
+
+For example, if our database was stored in ``cazy/cazyme.db`` and we want to write the output to a csv file, we would used:
+
+.. code-block:: bash
+   
+  cazy_webscraper cazy/cazyme.db csv
+
+.. NOTE::
+   Make sure ``cw_query_database`` is pointed directly at the database file.
+
+When no optional arguments are provided, the default behaviour is invoked. The default behaviour is to: 
+retrieve only the GenBank accessions of **all** CAZymes in the local CAZyme CAZyme db
+
+
+---------------------
+Accepted file formats
+---------------------
+
+``cw_query_database`` can write the output to a csv or json file.
+
+These are provided as the second arguments to ``cw_query_database``. To write out both a csv and json 
+file use both ``csv`` and ``json`` after the path to the local CAZyme database, separted with a single space.
+
+.. code-block:: bash
+
+    cw_query_database <path to local CAZyme db> csv json
+
+.. NOTE::
+    The order ``csv`` and ``json`` are written does not matter.
+
+.. WARNING::
+    Both ``csv`` and ``json`` are case sensitive.
+
+
+-----------------------------------------
+Options configurable at the command line 
+-----------------------------------------
+
+The following behaviours of the ``cw_query_database`` can be configured at the command-line in the terminal:  
+
+* Limit the retrieval of protein data to CAZymes in the local databaes from specific CAZy classes, CAZy families, kingdoms, genuera, species, strains and/or EC numbers
+* Including any combination of the following in the output, along side the GenBank accessions:
+    * CAZy class
+    * CAZy family
+    * CAZy subfamily
+    * Kingdom
+    * Genus
+    * Scientific name of the source organsim
+    * Protein sequence retrieved from GenBank
+    * UniProt accession
+    * Protein name retrieved from UniProt
+    * EC numbers
+    * PDB accessions
+    * Protein sequence retrieved from UniProt
+* Write the output in JSON and/or CSV format
+* Choose an output directory
+* Force overwriting existing files
+* Enable verbose logging during the operation of the webscraper
+
+`Here <https://cazy-webscraper.readthedocs.io/en/latest/api.html>`_ you can find a full list of the command-line flags and options.
+
+----------------------------
+Choosing an output directory
+----------------------------
+
+By default, ``cw_query_database`` writes all output files to the current working directory.
+
+To specify an alternative output directory, using the ``--output_dir``/``-o`` flag, followed by the path to the target output directory. ``cw_query_database`` will build all necessary parent and child output directories.
+
+For example, to write the output to the directory ``my_cazy_data`` use the following command:
+
+.. code-block:: bash
+  cw_query_database cazy/cazyme.db json csv --output_dir my_cazy_data
+  
+If the output directory already exists, ``cw_query_database`` will raise an error warning the output directory already exists and close. This is to prevent accidently writing data to the wrong location.
+
+To force ``cw_query_database`` to write the data to an existing output directory, add the ``--force``/``-f`` flag.
+
+.. code-block:: bash
+  cw_query_database cazy/cazyme.db json csv --output_dir my_cazy_data --force
+
+By default ``cw_query_database`` will delete all content already present in the existing output directory. To retain the data in the existing output directory, add the ``--nodelete``/``-n`` flag.
+
+.. code-block:: bash
+  cw_query_database cazy/cazyme.db json csv --output_dir my_cazy_data -- force --nodelete
+  
+.. note::
+  The ``--force`` and ``--nodelete`` flags are only applied when the ``--output_dir`` flag is used. ``cw_query_database`` will **not** delete content in the current working directory when writing to the current working directory when the ``--output_dir`` flag is **not** used.
+  
+------------------------
+Overwrite existing files
+------------------------
+
+``cw_query_database`` automatically compiles the names of the output files. 
+
+The file names of all output files are composed of the name of the local CAZyme database, followed by the names of the data retrieved from the local CAZyme database. For example, retrieving the following data from the local CAZyme database called ``cazy_database.db``:
+* CAZy family annotation
+* CAZy subfamily annotations
+* EC numbers
+* PDB accessions
+Will produce the following file name: ``cazy_database_gbkAcc_fams_subfams_ec_pdb``.  
+
+.. note::
+  ``_gbkAcc`` is always included in the file name because GenBank accessions are always retrieved and written to the output by ``cw_query_database``.
+
+Both the `json` and `csv` files are given the same name, the files only differ in their file extension.
+
+An optional prefix can be applied to all output file names using the ``-p``/``--prefix`` flag, followed by the desired prefix. For example, using the same example as above, the prefix 'engineering_candidates_` can be applied to every output file by adding the following to command:
+
+.. code-block:: bash
+  --prefix engineering_candidates_
+
+This will produce output files with the file name ``engineering_candidates_cazy_database_fams_subfams_ec_pdb``.
+
+If files matching the file names compiled by ``cw_query_database`` already existing at the target output location, ``cw_query_database`` will raise a warning that output files already existing and terminate. This is to prevent accidently overwriting data files.
+
+To overwrite existing datafiles add the ``--overwrite`` flag to the command. For example, the following command will retrieve all GenBank accessions stored in the local CAZyme database located at ``cazy/cazyme.db`` and write out the GenBank accessions to a file called ``all_gbk_acc_cazyme_gbkAcc.csv`` to ``my_cazy_data``, and will not delete content in the existing output directory and will overwrite the existing output file ``my_cazy_data/all_gbk_acc_cazyme_gbkAcc.csv``.
+
+.. code-block:: bash
+  cw_query_database cazy/cazyme.db csv \
+  --output_dir my_cazy_data \
+  --prefix all_gbk_accs_
+  -- force \
+  --nodelete \
+  --overwrite
+ 
+--------------------------------------------------------------------
+Retrieving protein data for CAZy classes and families to scrape
+--------------------------------------------------------------------
+
+The ``--classes`` and ``--families`` flags from scraping data from CAZy are applied in the extact same way 
+for retrieving protein data from the local CAZyme databases.
+
+For instance, if instead of retrieving protein data for all CAZymes in your local CAZyme database, you want to 
+retrieve protein data for CAZymes in specific CAZy classes then add the 
+``--classes`` flag followed by the classes you want to retrieve protein data for.
+
+.. TIP::
+   To list multiple classes, separate the classes with a single comma. 
+
+For example, if you want to retrieve protein data for all CAZymes from Glycoside Hydrolase and Carbohydrate Esterases, and write the data to a csv file, then use the command:
+
+.. code-block:: bash
+
+   cw_query_database cazy/cazyme.db csv --classes GH,CE
+
+OR
+
+.. code-block:: bash
+
+   cw_query_database cazy/cazyme.db csv --classes Glycoside Hydrolases,Carbohydrate Esterases
+
+Retrieving protein data for proteins from specific specific CAZy families is achieved using the ``--families`` flag. For 
+example, to retrieve protein data for all proteins in PL1, PL2 and PL3 in the local CAZyme database, and write the 
+data to csv and json files, use the following command:
+
+.. code-block:: bash
+
+   cw_query_database cazy/cazyme.db json csv --families PL1,PL2,PL3
+
+.. WARNING::
+   ``cw_query_database`` only accpets families written in the proper CAZy family syntax.
+   GH1 is accepted.
+   gh1 and GlycosideHydrolases1 are not accepted.
+
+As with scraping data from CAZy, the ``--classes`` and ``--families`` flags can be combined. To retrieve 
+protein data for all CAZymes in PL1, PL2, PL3 and *all* of GH and CE both, and write the data to a json file:
+
+.. code-block:: bash
+
+   cw_query_database cazy/cazyme.db json --families PL1,PL2,PL3 --classes GH,CE
+
+**AND**
+
+.. code-block:: bash
+
+   cw_query_database cazy/cazyme.db json --classes GH,CE --families PL1,PL2,PL3
+
+are accepted.
+
+
+------------------
+Applying taxonomic
+------------------
+
+The ``--kingdoms``, ``--genera``, ``--species`` and ``--strains`` flags can be used to refine the dataset 
+of proteins to retrieve protein data by taxonomy. These flags are applied in the exact same way as they 
+are used for the scraping of data from CAZy. Only proteins in the local CAZyme database and matching at least on of the provided taxonomy 
+criteria will have protein data retrieved from GenBank and added to the local CAZyme datbase.
+
+For example, if you want to retrieve protein data for all CAZymes in a local CAZyme database from bacterial and eukaryotic species then use the command 
+
+.. code-block:: bash
+
+   cw_query_database cazy/cazyme.db csv --kingdoms bacteria,eukaryota
+
+.. warning::
+   The kingdoms must be spelt the same way CAZy spells them, for example use 'eukaryot**a**' instead of 'eukaryot**e**'.
+   
+.. NOTE:: 
+   The kingdoms are **not** case sensitive, therefore, both ``bacteria`` *and* ``Bacteria`` are accepted. 
+
+.. NOTE::
+   You can list the kingdoms in *any* order. Thus, both ``bacteria,eukaryota`` *and* ``eukaryota,bacteria`` are accepted.
+
+You can combine any combination of the optional flags, including combining the taxonomic filters. For example,
+you may wish to retrieve protein data for all CAZymes in a local CAZyme database that are derived from all viral species, Aspergillus species, Layia carnosa, Layia chrysanthemoides, Trichoderma reesei QM6a and 
+Trichoderma reesei QM9414. To do this we would combine the respective flags for a single ``cw_query_database`` command. The command 
+we would use would be:
+
+.. code-block:: bash
+
+   cw_query_database cazy/cazyme.db csv --kingdoms viruses --genera Aspergillus --species Layia carnosa,Layia chrysanthemoides --strains Trichoderma reesei QM6a,Trichoderma reesei QM9414
+
+.. note::
+   The order that the flags are used and the order taxa  are listed does **not** matter, and separate multiple taxa names with a single comma 
+   with **no** spaces.
+
+.. warning::
+   Use the standard scientific name formating. Captialise the first letter of *genus* and write a lower 
+   case letter for the first letter of the species.
+
+   Aspergillus niger is **correct**
+
+   asepergillus niger is **incorrect**
+
+   ASPERGILLUS NIGER is **incorrect**
+
+.. warning::
+   When you specify a species ``cw_query_database`` will retrieval CAZymes from *all* strains of the species.
+
+
+-------------------------
+Applying EC number filter
+-------------------------
+
+The retrieval of protein data from the local CAZyme database can also be limited to proteins in a local CAZyme database that are
+annotated with specific EC numbers.
+
+Having previously retrieved EC number annotations and added them to the local CAZyme database, you  may 
+wish to retrieve protein data for CAZymes annotated with specific EC numbers. To do this add the 
+``--ec_filter`` flag to the command, follwed by a list of EC numbers.
+
+.. code-block:: bash
+   
+   cw_query_database cazy/cazyme.db csv --ec_filter "EC1.2.3.4,EC2.3.4.5"
+
+
+.. NOTE::
+    Provide complete EC numbers. 
+    Both dashes ('-') and asterixes ('*') are accepted for missing digits in EC numbers.
+
+    EC1.2.3.- and EC1.2.3.* are accepted.
+    EC1.2.3. and EC 1.2.3 are **not** accepted.
+
+.. NOTE::
+   The 'EC' prefix is not necessary.
+   EC1.2.3.4 and 1.2.3.4 are accepted.
+
+.. WARNING::
+    If using dashes to represent missing digits in EC numbers, it is recommended to bookend the entire 
+    EC number list in single or double quotation marks. Some terminals may misinterpret EC1.2.-.- as trying to invoke the options '.'
+
+.. NOTE::
+    ``cazy_webscraper`` will retrieve the specified UniProt data for all proteins in the local CAZyme 
+    database that are annotated with **at least one** of the given EC numbers. Therefore, if multiple 
+    EC numbers are given this **does not mean** only CAZymes will all provided EC numbers will have data retrieved
+    from UniProt for them.
+
+``--ec_filter`` is based upon EC number annotations stored within the local CAZyme database. For 
+example, if protein A is annotated with the EC1.2.3.4, but this annotation is not stored in the 
+local CAZyme database, using ``--ec_filter EC1.2.3.4`` will **not** cause ``cazy_webscraper`` to retrieve
+data for protein A. This is because ``cazy_webscraper`` does not know protein A is annotated with 
+EC1.2.3.4, because this annotation is not within its database.
+
+.. WARNING::
+    If ``--ec_filter`` is used along side ``--ec``, ``cazy_webscraper`` will retrieve **all** EC number 
+    annotations from UniProt for all proteins in the local CAZyme database that are associated with 
+    at least one of the EC numbers provided via ``--ec_filter`` within the CAZyme database.
+
+
+---------------------
+Combining all filters
+---------------------
+
+The ``--classes``, ``--families``, ``--ec_filter``, ``--kingdoms``, ``--genera``, ``--species`` and ``--strains`` flags can 
+be used in any combination to define a specific subset of proteins in the local CAZyme database for whom
+protein data from GenBank will be retrieved.
+
+Below we run through 3 example commands of combining these flags, writing the output to a csv file, and the resulting behaviour.
+
+**Example 1:**
+To retrieve protein data for all CAZymes in GH, GT, CE1, CE5 and CE8, and which are derived from baceterial species we use the command:
+
+.. code-block:: bash
+
+   cw_query_database cazy/cazyme.db csv --classes GH,CE --families CE1,CE5,CE8 --kingdoms bacteria
+
+
+**Example 2:**
+To protein data for all CAZymes in GH and which are derived from *Aspegillus* and *Trichoderma* species we use the command:
+
+.. code-block:: bash
+
+   cw_query_database cazy/cazyme.db csv -classes GH --genera Aspegillus,Trichoderma
+
+
+**Example 3:**
+To retrieve protein data for all CAZymes in GH,CE and CBM which are derived from baceterial species and are annotated with at least one of 
+EC3.2.1.23, EC3.2.1.37 and EC3.2.1.85, we use the command:
+
+.. code-block:: bash
+
+   cw_query_database cazy/cazyme.db csv --ec --sequences --classes GH,CE,CBM --kingdoms bacteria --ec_filter "3.2.1.23,3.2.1.37,3.2.1.85"
+
+
+----------------------
+Customising the output
+----------------------
+
+By defauly ``cw_query_database`` only includes the GenBank accessions of the CAZymes matching the provided 
+criteria in the final output. Any combination of the following can also be included in the output:
+* CAZy class
+* CAZy family
+* CAZy subfamily
+* Kingdom
+* Genus
+* Scientific name of the source organsim
+* Protein sequence retrieved from GenBank
+* UniProt accession
+* Protein name retrieved from UniProt
+* EC numbers
+* PDB accessions
+* Protein sequence retrieved from UniProt
+
+To include additional data in the output use the ``--include`` flag followed by any combination (and any order) of the following options:
+``--include`` - List additional data to include in the output. Multiple fields can be named, separating each with a single space (' '). The accepted fields are:
+* 'class' - Include the CAZy class annotations
+* 'family' - Include the CAZy family annotations
+* 'subfamily' - Include the subfamily class annotations
+* 'kingdom' - Include the taxonomic kingdom of the source organism
+* 'genus' - Include the genus of the source organism
+* 'organism' - Include the scientific name of the source organism
+* 'uniprot_acc' - Include the UniProt accession
+* 'uniprot_name' - Include the protein name retrieved from UniProt
+* 'ec' - Include the EC number annotations
+* 'pdb' - Include the PDB accessions
+* 'genbank_seq' - Include the GenBank protein sequence
+* 'uniprot_seq' - Include the Uniprot protein sequence
+
+.. NOTE::
+   The quotation marks around the terms do not need to be included.
+
+.. NOTE::
+   No matter what additional data is included in the output, the data will be presented in the same 
+   order as presented above. For example, 'Kingdom' will always come before all fields listed below it. 
+   Changing the order the fields are listed in the command will not change the order data is presented in the 
+   output. For example, using ``--include kingdom genus organism`` and ``--include organism genus kingdom`` will 
+   both result in the respective columns being placed in the order of: 'Kingdom', 'Genus', 'Organism'
+
+To list multiple fields to include in the final output, separate each field with a singel space (' ').
+
+**Example 1:**
+To retrieve protein data for all CAZymes in GH, GT, CE1, CE5 and CE8, and which are derived from baceterial species, and include the CAZy family annotations and 
+scientific names of the source organisms we use the command:
+
+.. code-block:: bash
+
+   cw_query_database cazy/cazyme.db csv --classes GH,CE --families CE1,CE5,CE8 --kingdoms bacteria --include family organism
+
+
+**Example 2:**
+To protein data for all CAZymes in GH and which are derived from *Aspegillus* and *Trichoderma* species, and include the CAZy class, EC number and PDB accessions 
+in the output we use the command:
+
+.. code-block:: bash
+
+   cw_query_database cazy/cazyme.db csv --include class ec pdb --classes GH --genera Aspegillus,Trichoderma
+
+
+**Example 3:**
+To retrieve protein data for all CAZymes in GH,CE and CBM which are derived from baceterial species and are annotated with at least one of 
+EC3.2.1.23, EC3.2.1.37 and EC3.2.1.85, and include the EC number annotations, CAZy family and CAZy subfamily annotations we use the command:
+
+.. code-block:: bash
+
+   cw_query_database cazy/cazyme.db csv \
+      --ec --sequences \
+      --classes GH,CE,CBM \
+      --kingdoms bacteria \
+      --ec_filter "3.2.1.23,3.2.1.37,3.2.1.85" \
+      --include family subfamily ec
diff --git a/docs/cache.rst b/docs/cache.rst
index 62448df8..a131a66a 100644
--- a/docs/cache.rst
+++ b/docs/cache.rst
@@ -52,20 +52,59 @@ Cache files when retrieving data from UniProt
 
 The dataframes retrieved with each query to UniProt are cached.
 
+In addition two JSON files are created:
+* ``uniprot_accessions_YYYY-MM-DD_HH-MM-SS.json``
+* ``uniprot_data_YYYY-MM-DD_HH-MM-SS.json``
+
+**UniProt accessions:**
+
+The first file (``uniprot_accessions``) contains the UniProt accessions/IDs for each GenBank accession retrieved 
+from the local CAZyme database that matches the provided criteria. These UniProt IDs are used to query 
+UniProt and retrieve protein data. UniProt cannot be batch queried by GenBank accessions to retrieve protein 
+data using ``bioservices``.
+
+The JSON file is keyed by the UniProt accession and is valued by a Python dictionary like structure, 
+containing the GenBank accession the corresponding ID of its record in the local CAZyme database. For example: 
+
+.. code-block:: python
+    {"A0A1S6JHP8": {"gbk_acc": "AQS71285.1", "db_id": 1225219}
+
+This file can be used to skip the retrieval of UniProt IDs from UniProt (which is the first step performed by ``cw_get_uniprot_data``). To 
+do this use the ``--skip_uniprot_accessions`` flag followed by the path to the corresponding ``uniprot_accessions_YYYY-MM-DD_HH-MM-SS.json`` file.
+
+**UniProt data:**
+
+The second json file (``uniprot_data``) contains all data retrieved from UniProt for all proteins in the local 
+CAZyme database that match the specified criteria. The data retrieved from UniProt was parsed into a Python dictionary 
+which is then dumped into the JSON file.
+
+This file is used for mannually checking the parsing method employed by ``cw_get_uniprot_data`` is working, as well as skipping the 
+retrieval of the same dataset from UniProt (for example, if you wanted to recreate a specific CAZyme proteome dataset).
+
+To use the data cached in the ``uniprot_data`` file, using the ``--use_uniprot_cache`` flag, followed by the 
+path pointing to the corresponding file. Using this flag, skips the retrieval of protein data from UniProt, and only adds 
+data from the cache file into the local CAZyme database.
+
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 Cache files when retrieving data from GenBank
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-When retrieving protein sequences from GenBank two cache file are produced:
+When retrieving protein sequences from GenBank three cache file are produced:
+
+* ``genbank_sequence_retrieved_YYYY-MM-DD_HH-MM-SS.txt`` contains the GenBank protein accessions for which a protein sequence **was** successfully retrieved
+* ``genbank_no_sequence_YYYY-MM-DD_HH-MM-SS.txt`` contains the GenBank protein accessions for which a protein sequence was not retrieved, as well as the possible reason
+* ``gennbank_seqs_YYYY-MM-DD_HH-MM-SS.json``, which contains the GenBank accessions of proteins matching the provided criteria and the retrieved protein sequences.
 
-* ``genbank_sequence_retrieved.txt`` contains the GenBank protein accessions for which a protein sequence **was** successfully retrieved
-* ``genbank_no_sequence.txt`` contains the GenBank protein accessions for which a protein sequence was not retrieved, as well as the possible reason
+.. NOTE::
+    Future features for ``cazy_webscraper`` will include the ability to use this cached protein sequences, to (i) skip the 
+    retrieval of data from GenBank and (ii) facilitate the reproduction of local CAZyme databases.
 
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 Cache files when retrieving data from PDB
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-Too be added...
+One cache file is created when using ``cazy_webscraper`` to retrieval protein structure files from PDB: ``pdb_retrieval_YYYY-MM-DD_HH-MM-SS.txt``, which 
+lists the PDB accessions of all files that were successfully downloaded from PDB using ``cazy_webscraper`` and ``BioPython``.
 
 ---------------
 Cache directory
diff --git a/docs/cazy_webscraper_version2.svg b/docs/cazy_webscraper_version2.svg
new file mode 100644
index 00000000..69973b2c
--- /dev/null
+++ b/docs/cazy_webscraper_version2.svg
@@ -0,0 +1,1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:lucid="lucid" width="1611" height="800"><g transform="translate(-77 -88)" lucid:page-tab-id="0_0"><path d="M1141 484h4.95c6.63 0 12 5.37 12 12v35.98c0 6.63 5.37 12 12 12h4.35" stroke="#333" fill="none"/><path d="M1121.82 474l20 10-20 10" stroke="#333" fill="#fff" fill-opacity="0"/><path d="M1121.82 484h20M1174.3 533.98v20M1194.3 543.98h-20" stroke="#333" fill="#fff"/><path d="M620.6 356h-5.93c-6.63 0-12 5.37-12 12v199.98c0 6.62-5.37 12-12 12h-6.52" stroke="#333" fill="none"/><path d="M620.6 346v20M640.6 356h-20" stroke="#333" fill="#fff"/><path d="M564.96 569.98l20 10-20 10" stroke="#333" fill="#fff" fill-opacity="0"/><path d="M564.96 579.98h20" stroke="#333" fill="#fff"/><path d="M641.1 340v155c0 2.76 2.23 5 5 5h470c2.76 0 5-2.24 5-5V340" fill="#fff"/><path d="M641.1 340v-35c0-2.76 2.23-5 5-5h470c2.76 0 5 2.24 5 5v35" fill="#5abaa7"/><path d="M641.1 305c0-2.76 2.23-5 5-5h470c2.76 0 5 2.24 5 5v190c0 2.76-2.24 5-5 5h-470c-2.77 0-5-2.24-5-5zM641.1 340h480M811.96 340v160" stroke="#19967d" fill="none"/><use xlink:href="#a" transform="matrix(1,0,0,1,651.0945834120721,300) translate(0 23.6)"/><use xlink:href="#b" transform="matrix(1,0,0,1,646.0945834120721,342.5) translate(0 17.1)"/><use xlink:href="#c" transform="matrix(1,0,0,1,816.9573742408597,342.5) translate(0 17.1)"/><use xlink:href="#d" transform="matrix(1,0,0,1,816.9573742408597,342.5) translate(23.95 17.1)"/><use xlink:href="#e" transform="matrix(1,0,0,1,816.9573742408597,342.5) translate(96.7 17.1)"/><use xlink:href="#f" transform="matrix(1,0,0,1,816.9573742408597,342.5) translate(133.35 17.1)"/><use xlink:href="#g" transform="matrix(1,0,0,1,646.0945834120721,374.5) translate(0 17.1)"/><use xlink:href="#h" transform="matrix(1,0,0,1,816.9573742408597,374.5) translate(0 17.1)"/><use xlink:href="#i" transform="matrix(1,0,0,1,646.0945834120721,406.5) translate(0 17.1)"/><use xlink:href="#j" transform="matrix(1,0,0,1,816.9573742408597,406.5) translate(0 17.1)"/><use xlink:href="#k" transform="matrix(1,0,0,1,646.0945834120721,438.5) translate(0 17.1)"/><use xlink:href="#j" transform="matrix(1,0,0,1,816.9573742408597,438.5) translate(0 17.1)"/><use xlink:href="#l" transform="matrix(1,0,0,1,646.0945834120721,470.5) translate(0 17.1)"/><use xlink:href="#m" transform="matrix(1,0,0,1,816.9573742408597,470.5) translate(0 17.1)"/><use xlink:href="#n" transform="matrix(1,0,0,1,816.9573742408597,470.5) translate(23.95 17.1)"/><use xlink:href="#o" transform="matrix(1,0,0,1,816.9573742408597,470.5) translate(95.75000000000001 17.1)"/><use xlink:href="#p" transform="matrix(1,0,0,1,816.9573742408597,470.5) translate(128.75 17.1)"/><path d="M1194.8 563.98v123c0 2.77 2.24 5 5 5h456.3c2.76 0 5-2.23 5-5v-123" fill="#fff"/><path d="M1194.8 563.98v-35c0-2.76 2.24-5 5-5h456.3c2.76 0 5 2.24 5 5v35" fill="#5abaa7"/><path d="M1194.8 528.98c0-2.76 2.24-5 5-5h456.3c2.76 0 5 2.24 5 5v158c0 2.77-2.24 5-5 5h-456.3c-2.76 0-5-2.23-5-5zM1194.8 563.98h466.3M1326.68 563.98v128" stroke="#19967d" fill="none"/><use xlink:href="#q" transform="matrix(1,0,0,1,1204.8014778413853,523.9846122069607) translate(0 23.6)"/><use xlink:href="#r" transform="matrix(1,0,0,1,1199.8014778413853,566.4846122069607) translate(0 17.1)"/><use xlink:href="#c" transform="matrix(1,0,0,1,1331.6751354867317,566.4846122069607) translate(0 17.1)"/><use xlink:href="#d" transform="matrix(1,0,0,1,1331.6751354867317,566.4846122069607) translate(23.95 17.1)"/><use xlink:href="#e" transform="matrix(1,0,0,1,1331.6751354867317,566.4846122069607) translate(96.7 17.1)"/><use xlink:href="#f" transform="matrix(1,0,0,1,1331.6751354867317,566.4846122069607) translate(133.35 17.1)"/><use xlink:href="#s" transform="matrix(1,0,0,1,1199.8014778413853,598.4846122069607) translate(0 17.1)"/><use xlink:href="#t" transform="matrix(1,0,0,1,1331.6751354867317,598.4846122069607) translate(0 17.1)"/><use xlink:href="#u" transform="matrix(1,0,0,1,1199.8014778413853,630.4846122069607) translate(0 17.1)"/><use xlink:href="#v" transform="matrix(1,0,0,1,1331.6751354867317,630.4846122069607) translate(0 17.1)"/><use xlink:href="#w" transform="matrix(1,0,0,1,1199.8014778413853,662.4846122069607) translate(0 17.1)"/><use xlink:href="#m" transform="matrix(1,0,0,1,1331.6751354867317,662.4846122069607) translate(0 17.1)"/><use xlink:href="#x" transform="matrix(1,0,0,1,1331.6751354867317,662.4846122069607) translate(23.95 17.1)"/><use xlink:href="#o" transform="matrix(1,0,0,1,1331.6751354867317,662.4846122069607) translate(95.75000000000001 17.1)"/><use xlink:href="#y" transform="matrix(1,0,0,1,1331.6751354867317,662.4846122069607) translate(128.75 17.1)"/><path d="M97.95 563.98v59c0 2.76 2.24 5 5 5h456.3c2.75 0 5-2.24 5-5v-59" fill="#fff"/><path d="M97.95 563.98v-35c0-2.76 2.24-5 5-5h456.3c2.75 0 5 2.24 5 5v35" fill="#5abaa7"/><path d="M97.95 528.98c0-2.76 2.24-5 5-5h456.3c2.75 0 5 2.24 5 5v94c0 2.76-2.25 5-5 5h-456.3c-2.76 0-5-2.24-5-5zM97.95 563.98h466.3M236.23 563.98v64" stroke="#19967d" fill="none"/><use xlink:href="#z" transform="matrix(1,0,0,1,107.94803062672872,523.9767983436004) translate(0 23.6)"/><use xlink:href="#b" transform="matrix(1,0,0,1,102.94803062672872,566.4767983436004) translate(0 17.1)"/><use xlink:href="#m" transform="matrix(1,0,0,1,241.22786520259018,566.4767983436004) translate(0 17.1)"/><use xlink:href="#n" transform="matrix(1,0,0,1,241.22786520259018,566.4767983436004) translate(23.95 17.1)"/><use xlink:href="#o" transform="matrix(1,0,0,1,241.22786520259018,566.4767983436004) translate(95.75000000000001 17.1)"/><use xlink:href="#A" transform="matrix(1,0,0,1,241.22786520259018,566.4767983436004) translate(128.75 17.1)"/><use xlink:href="#B" transform="matrix(1,0,0,1,102.94803062672872,598.4767983436004) translate(0 17.1)"/><use xlink:href="#m" transform="matrix(1,0,0,1,241.22786520259018,598.4767983436004) translate(0 17.1)"/><use xlink:href="#n" transform="matrix(1,0,0,1,241.22786520259018,598.4767983436004) translate(23.95 17.1)"/><use xlink:href="#o" transform="matrix(1,0,0,1,241.22786520259018,598.4767983436004) translate(95.75000000000001 17.1)"/><use xlink:href="#C" transform="matrix(1,0,0,1,241.22786520259018,598.4767983436004) translate(128.75 17.1)"/><path d="M1212 792v59c0 2.76 2.23 5 5 5h420c2.75 0 5-2.24 5-5v-59" fill="#fff"/><path d="M1212 792v-35c0-2.76 2.23-5 5-5h420c2.75 0 5 2.24 5 5v35" fill="#5abaa7"/><path d="M1212 757c0-2.76 2.23-5 5-5h420c2.75 0 5 2.24 5 5v94c0 2.76-2.25 5-5 5h-420c-2.77 0-5-2.24-5-5zM1212 792h430M1368.63 792v64" stroke="#19967d" fill="none"/><use xlink:href="#D" transform="matrix(1,0,0,1,1221.99064466553,752) translate(0 23.6)"/><use xlink:href="#E" transform="matrix(1,0,0,1,1216.99064466553,794.5) translate(0 17.1)"/><use xlink:href="#c" transform="matrix(1,0,0,1,1373.6340685397536,794.5) translate(0 17.1)"/><use xlink:href="#d" transform="matrix(1,0,0,1,1373.6340685397536,794.5) translate(23.95 17.1)"/><use xlink:href="#e" transform="matrix(1,0,0,1,1373.6340685397536,794.5) translate(96.7 17.1)"/><use xlink:href="#f" transform="matrix(1,0,0,1,1373.6340685397536,794.5) translate(133.35 17.1)"/><use xlink:href="#F" transform="matrix(1,0,0,1,1216.99064466553,826.5) translate(0 17.1)"/><use xlink:href="#t" transform="matrix(1,0,0,1,1373.6340685397536,826.5) translate(0 17.1)"/><path d="M1427.95 711.9v9.6c0 .28-.22.5-.48.5-.27 0-.48.2-.48.47v9.03" stroke="#333" fill="none"/><path d="M1437.95 692.7l-10 20-10-20" stroke="#333" fill="#fff" fill-opacity="0"/><path d="M1427.95 692.7v20M1437 731.5h-20M1427 751.5v-20" stroke="#333" fill="#fff"/><path d="M116.1 760v91c0 2.76 2.23 5 5 5h420c2.76 0 5-2.24 5-5v-91" fill="#fff"/><path d="M116.1 760v-35c0-2.76 2.23-5 5-5h420c2.76 0 5 2.24 5 5v35" fill="#5abaa7"/><path d="M116.1 725c0-2.76 2.23-5 5-5h420c2.76 0 5 2.24 5 5v126c0 2.76-2.24 5-5 5h-420c-2.77 0-5-2.24-5-5zM116.1 760h430M226.5 760v96" stroke="#19967d" fill="none"/><use xlink:href="#G" transform="matrix(1,0,0,1,126.0945834120721,720) translate(0 23.6)"/><use xlink:href="#B" transform="matrix(1,0,0,1,121.0945834120721,762.5) translate(0 17.1)"/><use xlink:href="#c" transform="matrix(1,0,0,1,231.50177449530656,762.5) translate(0 17.1)"/><use xlink:href="#d" transform="matrix(1,0,0,1,231.50177449530656,762.5) translate(23.95 17.1)"/><use xlink:href="#e" transform="matrix(1,0,0,1,231.50177449530656,762.5) translate(96.7 17.1)"/><use xlink:href="#f" transform="matrix(1,0,0,1,231.50177449530656,762.5) translate(133.35 17.1)"/><use xlink:href="#H" transform="matrix(1,0,0,1,121.0945834120721,794.5) translate(0 17.1)"/><use xlink:href="#I" transform="matrix(1,0,0,1,231.50177449530656,794.5) translate(0 17.1)"/><use xlink:href="#J" transform="matrix(1,0,0,1,121.0945834120721,826.5) translate(0 17.1)"/><use xlink:href="#v" transform="matrix(1,0,0,1,231.50177449530656,826.5) translate(0 17.1)"/><path d="M331.1 700.1v-51.62" stroke="#333" fill="none"/><path d="M321.1 719.28l10-20 10 20" stroke="#333" fill="#fff" fill-opacity="0"/><path d="M331.1 719.28v-20M321.1 648.48h20M331.1 628.48v20" stroke="#333" fill="#fff"/><path d="M631.1 664v187c0 2.76 2.23 5 5 5h490c2.76 0 5-2.24 5-5V664" fill="#fff"/><path d="M631.1 664v-35c0-2.76 2.23-5 5-5h490c2.76 0 5 2.24 5 5v35" fill="#ffc374"/><path d="M631.1 629c0-2.76 2.23-5 5-5h490c2.76 0 5 2.24 5 5v222c0 2.76-2.24 5-5 5h-490c-2.77 0-5-2.24-5-5zM631.1 664h500M792.65 664v192" stroke="#ef8d22" fill="none"/><use xlink:href="#K" transform="matrix(1,0,0,1,641.0945834120721,624) translate(0 23.6)"/><use xlink:href="#b" transform="matrix(1,0,0,1,636.0945834120721,666.5) translate(0 17.1)"/><use xlink:href="#c" transform="matrix(1,0,0,1,797.6518855659983,666.5) translate(0 17.1)"/><use xlink:href="#L" transform="matrix(1,0,0,1,797.6518855659983,666.5) translate(23.95 17.1)"/><use xlink:href="#M" transform="matrix(1,0,0,1,797.6518855659983,666.5) translate(95.75000000000001 17.1)"/><use xlink:href="#N" transform="matrix(1,0,0,1,797.6518855659983,666.5) translate(128.75 17.1)"/><use xlink:href="#O" transform="matrix(1,0,0,1,636.0945834120721,698.5) translate(0 17.1)"/><use xlink:href="#c" transform="matrix(1,0,0,1,797.6518855659983,698.5) translate(0 17.1)"/><use xlink:href="#d" transform="matrix(1,0,0,1,797.6518855659983,698.5) translate(23.95 17.1)"/><use xlink:href="#e" transform="matrix(1,0,0,1,797.6518855659983,698.5) translate(96.7 17.1)"/><use xlink:href="#f" transform="matrix(1,0,0,1,797.6518855659983,698.5) translate(133.35 17.1)"/><use xlink:href="#P" transform="matrix(1,0,0,1,636.0945834120721,730.5) translate(0 17.1)"/><use xlink:href="#Q" transform="matrix(1,0,0,1,797.6518855659983,730.5) translate(0 17.1)"/><use xlink:href="#R" transform="matrix(1,0,0,1,797.6518855659983,730.5) translate(24.95 17.1)"/><use xlink:href="#S" transform="matrix(1,0,0,1,797.6518855659983,730.5) translate(100.75000000000001 17.1)"/><use xlink:href="#T" transform="matrix(1,0,0,1,797.6518855659983,730.5) translate(145.70000000000002 17.1)"/><use xlink:href="#U" transform="matrix(1,0,0,1,636.0945834120721,762.5) translate(0 17.1)"/><use xlink:href="#V" transform="matrix(1,0,0,1,797.6518855659983,762.5) translate(0 17.1)"/><use xlink:href="#W" transform="matrix(1,0,0,1,797.6518855659983,762.5) translate(40.9 17.1)"/><use xlink:href="#X" transform="matrix(1,0,0,1,797.6518855659983,762.5) translate(116.70000000000002 17.1)"/><use xlink:href="#Y" transform="matrix(1,0,0,1,797.6518855659983,762.5) translate(161.65000000000003 17.1)"/><use xlink:href="#i" transform="matrix(1,0,0,1,636.0945834120721,794.5) translate(0 17.1)"/><use xlink:href="#j" transform="matrix(1,0,0,1,797.6518855659983,794.5) translate(0 17.1)"/><use xlink:href="#k" transform="matrix(1,0,0,1,636.0945834120721,826.5) translate(0 17.1)"/><use xlink:href="#j" transform="matrix(1,0,0,1,797.6518855659983,826.5) translate(0 17.1)"/><path d="M1194.8 160v59c0 2.76 2.24 5 5 5h456.3c2.76 0 5-2.24 5-5v-59" fill="#fff"/><path d="M1194.8 160v-35c0-2.76 2.24-5 5-5h456.3c2.76 0 5 2.24 5 5v35" fill="#a3d977"/><path d="M1194.8 125c0-2.76 2.24-5 5-5h456.3c2.76 0 5 2.24 5 5v94c0 2.76-2.24 5-5 5h-456.3c-2.76 0-5-2.24-5-5zM1194.8 160h466.3M1314.27 160v64" stroke="#7ab648" fill="none"/><use xlink:href="#Z" transform="matrix(1,0,0,1,1204.8014778413853,120) translate(0 23.6)"/><use xlink:href="#b" transform="matrix(1,0,0,1,1199.8014778413853,162.5) translate(0 17.1)"/><use xlink:href="#m" transform="matrix(1,0,0,1,1319.2711528302957,162.5) translate(0 17.1)"/><use xlink:href="#n" transform="matrix(1,0,0,1,1319.2711528302957,162.5) translate(23.95 17.1)"/><use xlink:href="#o" transform="matrix(1,0,0,1,1319.2711528302957,162.5) translate(95.75000000000001 17.1)"/><use xlink:href="#A" transform="matrix(1,0,0,1,1319.2711528302957,162.5) translate(128.75 17.1)"/><use xlink:href="#aa" transform="matrix(1,0,0,1,1199.8014778413853,194.5) translate(0 17.1)"/><use xlink:href="#m" transform="matrix(1,0,0,1,1319.2711528302957,194.5) translate(0 17.1)"/><use xlink:href="#n" transform="matrix(1,0,0,1,1319.2711528302957,194.5) translate(23.95 17.1)"/><use xlink:href="#o" transform="matrix(1,0,0,1,1319.2711528302957,194.5) translate(95.75000000000001 17.1)"/><use xlink:href="#ab" transform="matrix(1,0,0,1,1319.2711528302957,194.5) translate(128.75 17.1)"/><path d="M1212.95 340v59c0 2.76 2.24 5 5 5h420c2.76 0 5-2.24 5-5v-59" fill="#fff"/><path d="M1212.95 340v-35c0-2.76 2.24-5 5-5h420c2.76 0 5 2.24 5 5v35" fill="#a3d977"/><path d="M1212.95 305c0-2.76 2.24-5 5-5h420c2.76 0 5 2.24 5 5v94c0 2.76-2.24 5-5 5h-420c-2.76 0-5-2.24-5-5zM1212.95 340h430M1360 340v64" stroke="#7ab648" fill="none"/><use xlink:href="#ac" transform="matrix(1,0,0,1,1222.9480306267287,300) translate(0 23.6)"/><use xlink:href="#aa" transform="matrix(1,0,0,1,1217.9480306267287,342.5) translate(0 17.1)"/><use xlink:href="#c" transform="matrix(1,0,0,1,1365.0071670472737,342.5) translate(0 17.1)"/><use xlink:href="#d" transform="matrix(1,0,0,1,1365.0071670472737,342.5) translate(23.95 17.1)"/><use xlink:href="#e" transform="matrix(1,0,0,1,1365.0071670472737,342.5) translate(96.7 17.1)"/><use xlink:href="#f" transform="matrix(1,0,0,1,1365.0071670472737,342.5) translate(133.35 17.1)"/><use xlink:href="#ad" transform="matrix(1,0,0,1,1217.9480306267287,374.5) translate(0 17.1)"/><use xlink:href="#v" transform="matrix(1,0,0,1,1365.0071670472737,374.5) translate(0 17.1)"/><path d="M1427.95 243.9v35.6" stroke="#333" fill="none"/><path d="M1437.95 224.72l-10 20-10-20" stroke="#333" fill="#fff" fill-opacity="0"/><path d="M1427.95 224.72v20M1437.95 279.5h-20M1427.95 299.5v-20" stroke="#333" fill="#fff"/><path d="M97.95 160v59c0 2.76 2.24 5 5 5h456.3c2.75 0 5-2.24 5-5v-59" fill="#fff"/><path d="M97.95 160v-35c0-2.76 2.24-5 5-5h456.3c2.75 0 5 2.24 5 5v35" fill="#b391b5"/><path d="M97.95 125c0-2.76 2.24-5 5-5h456.3c2.75 0 5 2.24 5 5v94c0 2.76-2.25 5-5 5h-456.3c-2.76 0-5-2.24-5-5zM97.95 160h466.3M231.93 160v64" stroke="#834187" fill="none"/><g><use xlink:href="#ae" transform="matrix(1,0,0,1,107.94803062672872,120) translate(0 23.6)"/></g><g><use xlink:href="#b" transform="matrix(1,0,0,1,102.94803062672872,162.5) translate(0 17.1)"/></g><g><use xlink:href="#m" transform="matrix(1,0,0,1,236.933256133045,162.5) translate(0 17.1)"/><use xlink:href="#n" transform="matrix(1,0,0,1,236.933256133045,162.5) translate(23.95 17.1)"/><use xlink:href="#o" transform="matrix(1,0,0,1,236.933256133045,162.5) translate(95.75000000000001 17.1)"/><use xlink:href="#A" transform="matrix(1,0,0,1,236.933256133045,162.5) translate(128.75 17.1)"/></g><g><use xlink:href="#af" transform="matrix(1,0,0,1,102.94803062672872,194.5) translate(0 17.1)"/></g><g><use xlink:href="#m" transform="matrix(1,0,0,1,236.933256133045,194.5) translate(0 17.1)"/><use xlink:href="#n" transform="matrix(1,0,0,1,236.933256133045,194.5) translate(23.95 17.1)"/><use xlink:href="#o" transform="matrix(1,0,0,1,236.933256133045,194.5) translate(95.75000000000001 17.1)"/><use xlink:href="#ag" transform="matrix(1,0,0,1,236.933256133045,194.5) translate(128.75 17.1)"/></g><path d="M620.6 320h-5.93c-6.63 0-12-5.37-12-12V188c0-6.63-5.37-12-12-12h-6.52" stroke="#333" fill="none"/><path d="M620.6 310v20M640.6 320h-20" stroke="#333" fill="#fff"/><path d="M564.96 166l20 10-20 10" stroke="#333" fill="#fff" fill-opacity="0"/><path d="M564.96 176h20" stroke="#333" fill="#fff"/><path d="M116.1 340v59c0 2.76 2.23 5 5 5h420c2.76 0 5-2.24 5-5v-59" fill="#fff"/><path d="M116.1 340v-35c0-2.76 2.23-5 5-5h420c2.76 0 5 2.24 5 5v35" fill="#b391b5"/><path d="M116.1 305c0-2.76 2.23-5 5-5h420c2.76 0 5 2.24 5 5v94c0 2.76-2.24 5-5 5h-420c-2.77 0-5-2.24-5-5zM116.1 340h430M239.37 340v64" stroke="#834187" fill="none"/><g><use xlink:href="#ah" transform="matrix(1,0,0,1,126.0945834120721,300) translate(0 23.6)"/></g><g><use xlink:href="#af" transform="matrix(1,0,0,1,121.0945834120721,342.5) translate(0 17.1)"/></g><g><use xlink:href="#c" transform="matrix(1,0,0,1,244.37243072121657,342.5) translate(0 17.1)"/><use xlink:href="#d" transform="matrix(1,0,0,1,244.37243072121657,342.5) translate(23.95 17.1)"/><use xlink:href="#e" transform="matrix(1,0,0,1,244.37243072121657,342.5) translate(96.7 17.1)"/><use xlink:href="#f" transform="matrix(1,0,0,1,244.37243072121657,342.5) translate(133.35 17.1)"/></g><g><use xlink:href="#ai" transform="matrix(1,0,0,1,121.0945834120721,374.5) translate(0 17.1)"/></g><g><use xlink:href="#v" transform="matrix(1,0,0,1,244.37243072121657,374.5) translate(0 17.1)"/></g><path d="M331.1 244.5v35.6" stroke="#333" fill="none"/><path d="M321.1 244.5h20M331.1 224.5v20" stroke="#333" fill="#fff"/><path d="M321.1 299.28l10-20 10 20" stroke="#333" fill="#fff" fill-opacity="0"/><path d="M331.1 299.28v-20" stroke="#333" fill="#fff"/><path d="M881.1 520.5v83" stroke="#333" fill="none"/><path d="M871.1 520.5h20M881.1 500.5v20M891.1 603.5h-20M881.1 623.5v-20" stroke="#333" fill="#fff"/><path d="M1141.6 320h4.35c6.63 0 12-5.37 12-12V188c0-6.63 5.37-12 12-12h4.94" stroke="#333" fill="none"/><path d="M1141.6 330v-20M1121.6 320h20" stroke="#333" fill="#fff"/><path d="M1194.08 186l-20-10 20-10" stroke="#333" fill="#fff" fill-opacity="0"/><path d="M1194.08 176h-20" stroke="#333" fill="#fff"/><defs><path fill="#333" d="M143 4C61 4 22-44 18-125c-5-107 100-154 193-111 17 8 29 25 37 43l-32 9c-13-25-37-40-76-40-61 0-88 39-88 99 0 61 29 100 91 101 35 0 62-11 79-27v-45h-74v-28h105v86C228-13 192 4 143 4" id="aj"/><path fill="#333" d="M100-194c63 0 86 42 84 106H49c0 40 14 67 53 68 26 1 43-12 49-29l28 8c-11 28-37 45-77 45C44 4 14-33 15-96c1-61 26-98 85-98zm52 81c6-60-76-77-97-28-3 7-6 17-6 28h103" id="ak"/><path fill="#333" d="M117-194c89-4 53 116 60 194h-32v-121c0-31-8-49-39-48C34-167 62-67 57 0H25l-1-190h30c1 10-1 24 2 32 11-22 29-35 61-36" id="al"/><path fill="#333" d="M115-194c53 0 69 39 70 98 0 66-23 100-70 100C84 3 66-7 56-30L54 0H23l1-261h32v101c10-23 28-34 59-34zm-8 174c40 0 45-34 45-75 0-40-5-75-45-74-42 0-51 32-51 76 0 43 10 73 51 73" id="am"/><path fill="#333" d="M141-36C126-15 110 5 73 4 37 3 15-17 15-53c-1-64 63-63 125-63 3-35-9-54-41-54-24 1-41 7-42 31l-33-3c5-37 33-52 76-52 45 0 72 20 72 64v82c-1 20 7 32 28 27v20c-31 9-61-2-59-35zM48-53c0 20 12 33 32 33 41-3 63-29 60-74-43 2-92-5-92 41" id="an"/><path fill="#333" d="M143 0L79-87 56-68V0H24v-261h32v163l83-92h37l-77 82L181 0h-38" id="ao"/><path fill="#333" d="M135-143c-3-34-86-38-87 0 15 53 115 12 119 90S17 21 10-45l28-5c4 36 97 45 98 0-10-56-113-15-118-90-4-57 82-63 122-42 12 7 21 19 24 35" id="ap"/><g id="a"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#aj"/><use transform="matrix(0.05,0,0,0.05,14,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,24,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,34,0)" xlink:href="#am"/><use transform="matrix(0.05,0,0,0.05,44,0)" xlink:href="#an"/><use transform="matrix(0.05,0,0,0.05,54,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,64,0)" xlink:href="#ao"/><use transform="matrix(0.05,0,0,0.05,73,0)" xlink:href="#ap"/></g><path fill="#333" d="M177-190C167-65 218 103 67 71c-23-6-38-20-44-43l32-5c15 47 100 32 89-28v-30C133-14 115 1 83 1 29 1 15-40 15-95c0-56 16-97 71-98 29-1 48 16 59 35 1-10 0-23 2-32h30zM94-22c36 0 50-32 50-73 0-42-14-75-50-75-39 0-46 34-46 75s6 73 46 73" id="aq"/><path fill="#333" d="M-5 72V49h209v23H-5" id="ar"/><path fill="#333" d="M24-231v-30h32v30H24zM24 0v-190h32V0H24" id="as"/><path fill="#333" d="M85-194c31 0 48 13 60 33l-1-100h32l1 261h-30c-2-10 0-23-3-31C134-8 116 4 85 4 32 4 16-35 15-94c0-66 23-100 70-100zm9 24c-40 0-46 34-46 75 0 40 6 74 45 74 42 0 51-32 51-76 0-42-9-74-50-73" id="at"/><g id="b"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#aq"/><use transform="matrix(0.05,0,0,0.05,10,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,20,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,30,0)" xlink:href="#am"/><use transform="matrix(0.05,0,0,0.05,40,0)" xlink:href="#an"/><use transform="matrix(0.05,0,0,0.05,50,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,60,0)" xlink:href="#ao"/><use transform="matrix(0.05,0,0,0.05,69,0)" xlink:href="#ar"/><use transform="matrix(0.05,0,0,0.05,79,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,82.95,0)" xlink:href="#at"/></g><path fill="#333" d="M59-47c-2 24 18 29 38 22v24C64 9 27 4 27-40v-127H5v-23h24l9-43h21v43h35v23H59v120" id="au"/><g id="c"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,3.95,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,13.949999999999998,0)" xlink:href="#au"/></g><path fill="#333" d="M87 75C49 33 22-17 22-94c0-76 28-126 65-167h31c-38 41-64 92-64 168S80 34 118 75H87" id="av"/><path fill="#333" d="M30-248c87 1 191-15 191 75 0 78-77 80-158 76V0H30v-248zm33 125c57 0 124 11 124-50 0-59-68-47-124-48v98" id="aw"/><path fill="#333" d="M114-163C36-179 61-72 57 0H25l-1-190h30c1 12-1 29 2 39 6-27 23-49 58-41v29" id="ax"/><path fill="#333" d="M210-169c-67 3-38 105-44 169h-31v-121c0-29-5-50-35-48C34-165 62-65 56 0H25l-1-190h30c1 10-1 24 2 32 10-44 99-50 107 0 11-21 27-35 58-36 85-2 47 119 55 194h-31v-121c0-29-5-49-35-48" id="ay"/><path fill="#333" d="M179-190L93 31C79 59 56 82 12 73V49c39 6 53-20 64-50L1-190h34L92-34l54-156h33" id="az"/><g id="d"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#av"/><use transform="matrix(0.05,0,0,0.05,5.95,0)" xlink:href="#aw"/><use transform="matrix(0.05,0,0,0.05,17.95,0)" xlink:href="#ax"/><use transform="matrix(0.05,0,0,0.05,23.9,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,27.849999999999994,0)" xlink:href="#ay"/><use transform="matrix(0.05,0,0,0.05,42.8,0)" xlink:href="#an"/><use transform="matrix(0.05,0,0,0.05,52.79999999999999,0)" xlink:href="#ax"/><use transform="matrix(0.05,0,0,0.05,58.75,0)" xlink:href="#az"/></g><path fill="#333" d="M68-38c1 34 0 65-14 84H32c9-13 17-26 17-46H33v-38h35" id="aA"/><g id="e"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#ao"/><use transform="matrix(0.05,0,0,0.05,9,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,19,0)" xlink:href="#az"/><use transform="matrix(0.05,0,0,0.05,26.649999999999995,0)" xlink:href="#aA"/></g><path fill="#333" d="M84 4C-5 8 30-112 23-190h32v120c0 31 7 50 39 49 72-2 45-101 50-169h31l1 190h-30c-1-10 1-25-2-33-11 22-28 36-60 37" id="aB"/><path fill="#333" d="M100-194c62-1 85 37 85 99 1 63-27 99-86 99S16-35 15-95c0-66 28-99 85-99zM99-20c44 1 53-31 53-75 0-43-8-75-51-75s-53 32-53 75 10 74 51 75" id="aC"/><path fill="#333" d="M96-169c-40 0-48 33-48 73s9 75 48 75c24 0 41-14 43-38l32 2c-6 37-31 61-74 61-59 0-76-41-82-99-10-93 101-131 147-64 4 7 5 14 7 22l-32 3c-4-21-16-35-41-35" id="aD"/><path fill="#333" d="M33-261c38 41 65 92 65 168S71 34 33 75H2C39 34 66-17 66-93S39-220 2-261h31" id="aE"/><g id="f"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#an"/><use transform="matrix(0.05,0,0,0.05,10,0)" xlink:href="#aB"/><use transform="matrix(0.05,0,0,0.05,20,0)" xlink:href="#au"/><use transform="matrix(0.05,0,0,0.05,25,0)" xlink:href="#aC"/><use transform="matrix(0.05,0,0,0.05,35,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,38.95,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,48.95,0)" xlink:href="#aD"/><use transform="matrix(0.05,0,0,0.05,57.95,0)" xlink:href="#ax"/><use transform="matrix(0.05,0,0,0.05,63.900000000000006,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,73.9,0)" xlink:href="#ay"/><use transform="matrix(0.05,0,0,0.05,88.85000000000001,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,98.85000000000001,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,108.85000000000001,0)" xlink:href="#au"/><use transform="matrix(0.05,0,0,0.05,113.85000000000001,0)" xlink:href="#aE"/></g><g id="g"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#aq"/><use transform="matrix(0.05,0,0,0.05,10,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,20,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,30,0)" xlink:href="#am"/><use transform="matrix(0.05,0,0,0.05,40,0)" xlink:href="#an"/><use transform="matrix(0.05,0,0,0.05,50,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,60,0)" xlink:href="#ao"/><use transform="matrix(0.05,0,0,0.05,69,0)" xlink:href="#ar"/><use transform="matrix(0.05,0,0,0.05,79,0)" xlink:href="#an"/><use transform="matrix(0.05,0,0,0.05,89,0)" xlink:href="#aD"/><use transform="matrix(0.05,0,0,0.05,98,0)" xlink:href="#aD"/><use transform="matrix(0.05,0,0,0.05,107,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,117,0)" xlink:href="#ap"/><use transform="matrix(0.05,0,0,0.05,126,0)" xlink:href="#ap"/><use transform="matrix(0.05,0,0,0.05,135,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,138.95,0)" xlink:href="#aC"/><use transform="matrix(0.05,0,0,0.05,148.95,0)" xlink:href="#al"/></g><path fill="#333" d="M185-189c-5-48-123-54-124 2 14 75 158 14 163 119 3 78-121 87-175 55-17-10-28-26-33-46l33-7c5 56 141 63 141-1 0-78-155-14-162-118-5-82 145-84 179-34 5 7 8 16 11 25" id="aF"/><g id="h"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#aF"/><use transform="matrix(0.05,0,0,0.05,12,0)" xlink:href="#au"/><use transform="matrix(0.05,0,0,0.05,17,0)" xlink:href="#ax"/></g><path fill="#333" d="M145-31C134-9 116 4 85 4 32 4 16-35 15-94c0-59 17-99 70-100 32-1 48 14 60 33 0-11-1-24 2-32h30l-1 268h-32zM93-21c41 0 51-33 51-76s-8-73-50-73c-40 0-46 35-46 75s5 74 45 74" id="aG"/><g id="i"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#ap"/><use transform="matrix(0.05,0,0,0.05,9,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,19,0)" xlink:href="#aG"/><use transform="matrix(0.05,0,0,0.05,29,0)" xlink:href="#aB"/><use transform="matrix(0.05,0,0,0.05,39,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,49,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,59,0)" xlink:href="#aD"/><use transform="matrix(0.05,0,0,0.05,68,0)" xlink:href="#ak"/></g><g id="j"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#ax"/><use transform="matrix(0.05,0,0,0.05,5.95,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,15.949999999999998,0)" xlink:href="#ap"/><use transform="matrix(0.05,0,0,0.05,24.95,0)" xlink:href="#au"/><use transform="matrix(0.05,0,0,0.05,29.950000000000003,0)" xlink:href="#ax"/></g><path fill="#333" d="M115-194c55 1 70 41 70 98S169 2 115 4C84 4 66-9 55-30l1 105H24l-1-265h31l2 30c10-21 28-34 59-34zm-8 174c40 0 45-34 45-75s-6-73-45-74c-42 0-51 32-51 76 0 43 10 73 51 73" id="aH"/><g id="k"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#ap"/><use transform="matrix(0.05,0,0,0.05,9,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,19,0)" xlink:href="#aG"/><use transform="matrix(0.05,0,0,0.05,29,0)" xlink:href="#ar"/><use transform="matrix(0.05,0,0,0.05,39,0)" xlink:href="#aB"/><use transform="matrix(0.05,0,0,0.05,49,0)" xlink:href="#aH"/><use transform="matrix(0.05,0,0,0.05,59,0)" xlink:href="#at"/><use transform="matrix(0.05,0,0,0.05,69,0)" xlink:href="#an"/><use transform="matrix(0.05,0,0,0.05,79,0)" xlink:href="#au"/><use transform="matrix(0.05,0,0,0.05,84,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,94,0)" xlink:href="#ar"/><use transform="matrix(0.05,0,0,0.05,104,0)" xlink:href="#at"/><use transform="matrix(0.05,0,0,0.05,114,0)" xlink:href="#an"/><use transform="matrix(0.05,0,0,0.05,124,0)" xlink:href="#au"/><use transform="matrix(0.05,0,0,0.05,129,0)" xlink:href="#ak"/></g><path fill="#333" d="M141 0L90-78 38 0H4l68-98-65-92h35l48 74 47-74h35l-64 92 68 98h-35" id="aI"/><g id="l"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#au"/><use transform="matrix(0.05,0,0,0.05,5,0)" xlink:href="#an"/><use transform="matrix(0.05,0,0,0.05,15,0)" xlink:href="#aI"/><use transform="matrix(0.05,0,0,0.05,24,0)" xlink:href="#aC"/><use transform="matrix(0.05,0,0,0.05,34,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,44,0)" xlink:href="#aC"/><use transform="matrix(0.05,0,0,0.05,54,0)" xlink:href="#ay"/><use transform="matrix(0.05,0,0,0.05,68.95,0)" xlink:href="#az"/><use transform="matrix(0.05,0,0,0.05,77.95,0)" xlink:href="#ar"/><use transform="matrix(0.05,0,0,0.05,87.95,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,91.9,0)" xlink:href="#at"/></g><g id="m"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,3.95,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,13.949999999999998,0)" xlink:href="#au"/></g><path fill="#333" d="M63-220v92h138v28H63V0H30v-248h175v28H63" id="aJ"/><g id="n"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#av"/><use transform="matrix(0.05,0,0,0.05,5.95,0)" xlink:href="#aJ"/><use transform="matrix(0.05,0,0,0.05,16.900000000000002,0)" xlink:href="#aC"/><use transform="matrix(0.05,0,0,0.05,26.900000000000002,0)" xlink:href="#ax"/><use transform="matrix(0.05,0,0,0.05,32.85,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,36.800000000000004,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,46.800000000000004,0)" xlink:href="#aq"/><use transform="matrix(0.05,0,0,0.05,56.800000000000004,0)" xlink:href="#al"/></g><g id="o"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#ao"/><use transform="matrix(0.05,0,0,0.05,9,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,19,0)" xlink:href="#az"/></g><path fill="#333" d="M127-220V0H93v-220H8v-28h204v28h-85" id="aK"/><path fill="#333" d="M33 0v-38h34V0H33" id="aL"/><g id="p"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#aK"/><use transform="matrix(0.05,0,0,0.05,8.950000000000001,0)" xlink:href="#an"/><use transform="matrix(0.05,0,0,0.05,18.950000000000003,0)" xlink:href="#aI"/><use transform="matrix(0.05,0,0,0.05,27.950000000000003,0)" xlink:href="#ap"/><use transform="matrix(0.05,0,0,0.05,36.95,0)" xlink:href="#aL"/><use transform="matrix(0.05,0,0,0.05,41.95,0)" xlink:href="#au"/><use transform="matrix(0.05,0,0,0.05,46.95,0)" xlink:href="#an"/><use transform="matrix(0.05,0,0,0.05,56.95,0)" xlink:href="#aI"/><use transform="matrix(0.05,0,0,0.05,65.95,0)" xlink:href="#aC"/><use transform="matrix(0.05,0,0,0.05,75.95,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,85.95,0)" xlink:href="#aC"/><use transform="matrix(0.05,0,0,0.05,95.95,0)" xlink:href="#ay"/><use transform="matrix(0.05,0,0,0.05,110.9,0)" xlink:href="#az"/><use transform="matrix(0.05,0,0,0.05,119.9,0)" xlink:href="#ar"/><use transform="matrix(0.05,0,0,0.05,129.9,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,133.85,0)" xlink:href="#at"/><use transform="matrix(0.05,0,0,0.05,143.85,0)" xlink:href="#aE"/></g><g id="q"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#aK"/><use transform="matrix(0.05,0,0,0.05,8.950000000000001,0)" xlink:href="#an"/><use transform="matrix(0.05,0,0,0.05,18.950000000000003,0)" xlink:href="#aI"/><use transform="matrix(0.05,0,0,0.05,27.950000000000003,0)" xlink:href="#ap"/></g><g id="r"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#au"/><use transform="matrix(0.05,0,0,0.05,5,0)" xlink:href="#an"/><use transform="matrix(0.05,0,0,0.05,15,0)" xlink:href="#aI"/><use transform="matrix(0.05,0,0,0.05,24,0)" xlink:href="#aC"/><use transform="matrix(0.05,0,0,0.05,34,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,44,0)" xlink:href="#aC"/><use transform="matrix(0.05,0,0,0.05,54,0)" xlink:href="#ay"/><use transform="matrix(0.05,0,0,0.05,68.95,0)" xlink:href="#az"/><use transform="matrix(0.05,0,0,0.05,77.95,0)" xlink:href="#ar"/><use transform="matrix(0.05,0,0,0.05,87.95,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,91.9,0)" xlink:href="#at"/></g><g id="s"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#aq"/><use transform="matrix(0.05,0,0,0.05,10,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,20,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,30,0)" xlink:href="#aB"/><use transform="matrix(0.05,0,0,0.05,40,0)" xlink:href="#ap"/></g><g id="t"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#ap"/><use transform="matrix(0.05,0,0,0.05,9,0)" xlink:href="#au"/><use transform="matrix(0.05,0,0,0.05,14,0)" xlink:href="#ax"/></g><g id="u"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#ap"/><use transform="matrix(0.05,0,0,0.05,9,0)" xlink:href="#aH"/><use transform="matrix(0.05,0,0,0.05,19,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,29,0)" xlink:href="#aD"/><use transform="matrix(0.05,0,0,0.05,38,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,41.95,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,51.95,0)" xlink:href="#ap"/></g><g id="v"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#ap"/><use transform="matrix(0.05,0,0,0.05,9,0)" xlink:href="#au"/><use transform="matrix(0.05,0,0,0.05,14,0)" xlink:href="#ax"/></g><g id="w"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#ao"/><use transform="matrix(0.05,0,0,0.05,9,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,12.949999999999998,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,22.95,0)" xlink:href="#aq"/><use transform="matrix(0.05,0,0,0.05,32.95,0)" xlink:href="#at"/><use transform="matrix(0.05,0,0,0.05,42.95,0)" xlink:href="#aC"/><use transform="matrix(0.05,0,0,0.05,52.95,0)" xlink:href="#ay"/><use transform="matrix(0.05,0,0,0.05,67.9,0)" xlink:href="#ar"/><use transform="matrix(0.05,0,0,0.05,77.9,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,81.85000000000001,0)" xlink:href="#at"/></g><g id="x"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#av"/><use transform="matrix(0.05,0,0,0.05,5.95,0)" xlink:href="#aJ"/><use transform="matrix(0.05,0,0,0.05,16.900000000000002,0)" xlink:href="#aC"/><use transform="matrix(0.05,0,0,0.05,26.900000000000002,0)" xlink:href="#ax"/><use transform="matrix(0.05,0,0,0.05,32.85,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,42.85,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,46.800000000000004,0)" xlink:href="#aq"/><use transform="matrix(0.05,0,0,0.05,56.800000000000004,0)" xlink:href="#al"/></g><path fill="#333" d="M194 0L95-120 63-95V0H30v-248h33v124l119-124h40L117-140 236 0h-42" id="aM"/><g id="y"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#aM"/><use transform="matrix(0.05,0,0,0.05,12,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,15.949999999999998,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,25.950000000000003,0)" xlink:href="#aq"/><use transform="matrix(0.05,0,0,0.05,35.95,0)" xlink:href="#at"/><use transform="matrix(0.05,0,0,0.05,45.95,0)" xlink:href="#aC"/><use transform="matrix(0.05,0,0,0.05,55.95,0)" xlink:href="#ay"/><use transform="matrix(0.05,0,0,0.05,70.9,0)" xlink:href="#ap"/><use transform="matrix(0.05,0,0,0.05,79.9,0)" xlink:href="#aL"/><use transform="matrix(0.05,0,0,0.05,84.9,0)" xlink:href="#ao"/><use transform="matrix(0.05,0,0,0.05,93.9,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,97.85000000000001,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,107.85000000000001,0)" xlink:href="#aq"/><use transform="matrix(0.05,0,0,0.05,117.85000000000001,0)" xlink:href="#at"/><use transform="matrix(0.05,0,0,0.05,127.85000000000001,0)" xlink:href="#aC"/><use transform="matrix(0.05,0,0,0.05,137.85000000000002,0)" xlink:href="#ay"/><use transform="matrix(0.05,0,0,0.05,152.8,0)" xlink:href="#ar"/><use transform="matrix(0.05,0,0,0.05,162.8,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,166.75,0)" xlink:href="#at"/><use transform="matrix(0.05,0,0,0.05,176.75,0)" xlink:href="#aE"/></g><path fill="#333" d="M212-179c-10-28-35-45-73-45-59 0-87 40-87 99 0 60 29 101 89 101 43 0 62-24 78-52l27 14C228-24 195 4 139 4 59 4 22-46 18-125c-6-104 99-153 187-111 19 9 31 26 39 46" id="aN"/><path fill="#333" d="M9 0v-24l116-142H16v-24h144v24L44-24h123V0H9" id="aO"/><path fill="#333" d="M24 0v-261h32V0H24" id="aP"/><g id="z"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#aj"/><use transform="matrix(0.05,0,0,0.05,14,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,24,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,34,0)" xlink:href="#am"/><use transform="matrix(0.05,0,0,0.05,44,0)" xlink:href="#an"/><use transform="matrix(0.05,0,0,0.05,54,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,64,0)" xlink:href="#ao"/><use transform="matrix(0.05,0,0,0.05,73,0)" xlink:href="#ap"/><use transform="matrix(0.05,0,0,0.05,82,0)" xlink:href="#ar"/><use transform="matrix(0.05,0,0,0.05,92,0)" xlink:href="#aN"/><use transform="matrix(0.05,0,0,0.05,104.95,0)" xlink:href="#an"/><use transform="matrix(0.05,0,0,0.05,114.95,0)" xlink:href="#aO"/><use transform="matrix(0.05,0,0,0.05,123.95,0)" xlink:href="#az"/><use transform="matrix(0.05,0,0,0.05,132.95,0)" xlink:href="#aJ"/><use transform="matrix(0.05,0,0,0.05,143.89999999999998,0)" xlink:href="#an"/><use transform="matrix(0.05,0,0,0.05,153.89999999999998,0)" xlink:href="#ay"/><use transform="matrix(0.05,0,0,0.05,168.84999999999997,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,172.79999999999995,0)" xlink:href="#aP"/><use transform="matrix(0.05,0,0,0.05,176.74999999999994,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,180.69999999999993,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,190.69999999999993,0)" xlink:href="#ap"/></g><g id="A"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#aj"/><use transform="matrix(0.05,0,0,0.05,14,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,24,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,34,0)" xlink:href="#am"/><use transform="matrix(0.05,0,0,0.05,44,0)" xlink:href="#an"/><use transform="matrix(0.05,0,0,0.05,54,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,64,0)" xlink:href="#ao"/><use transform="matrix(0.05,0,0,0.05,73,0)" xlink:href="#ap"/><use transform="matrix(0.05,0,0,0.05,82,0)" xlink:href="#aL"/><use transform="matrix(0.05,0,0,0.05,87,0)" xlink:href="#aq"/><use transform="matrix(0.05,0,0,0.05,97,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,107,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,117,0)" xlink:href="#am"/><use transform="matrix(0.05,0,0,0.05,127,0)" xlink:href="#an"/><use transform="matrix(0.05,0,0,0.05,137,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,147,0)" xlink:href="#ao"/><use transform="matrix(0.05,0,0,0.05,156,0)" xlink:href="#ar"/><use transform="matrix(0.05,0,0,0.05,166,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,169.95,0)" xlink:href="#at"/><use transform="matrix(0.05,0,0,0.05,179.95,0)" xlink:href="#aE"/></g><path fill="#333" d="M101-234c-31-9-42 10-38 44h38v23H63V0H32v-167H5v-23h27c-7-52 17-82 69-68v24" id="aQ"/><g id="B"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#aQ"/><use transform="matrix(0.05,0,0,0.05,5,0)" xlink:href="#an"/><use transform="matrix(0.05,0,0,0.05,15,0)" xlink:href="#ay"/><use transform="matrix(0.05,0,0,0.05,29.950000000000003,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,33.900000000000006,0)" xlink:href="#aP"/><use transform="matrix(0.05,0,0,0.05,37.85000000000001,0)" xlink:href="#az"/><use transform="matrix(0.05,0,0,0.05,46.85000000000001,0)" xlink:href="#ar"/><use transform="matrix(0.05,0,0,0.05,56.85,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,60.80000000000001,0)" xlink:href="#at"/></g><g id="C"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#aN"/><use transform="matrix(0.05,0,0,0.05,12.950000000000001,0)" xlink:href="#an"/><use transform="matrix(0.05,0,0,0.05,22.950000000000003,0)" xlink:href="#aO"/><use transform="matrix(0.05,0,0,0.05,31.950000000000003,0)" xlink:href="#az"/><use transform="matrix(0.05,0,0,0.05,40.95,0)" xlink:href="#aJ"/><use transform="matrix(0.05,0,0,0.05,51.900000000000006,0)" xlink:href="#an"/><use transform="matrix(0.05,0,0,0.05,61.900000000000006,0)" xlink:href="#ay"/><use transform="matrix(0.05,0,0,0.05,76.85000000000001,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,80.80000000000001,0)" xlink:href="#aP"/><use transform="matrix(0.05,0,0,0.05,84.75000000000001,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,88.70000000000002,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,98.70000000000002,0)" xlink:href="#ap"/><use transform="matrix(0.05,0,0,0.05,107.7,0)" xlink:href="#aL"/><use transform="matrix(0.05,0,0,0.05,112.7,0)" xlink:href="#aQ"/><use transform="matrix(0.05,0,0,0.05,117.7,0)" xlink:href="#an"/><use transform="matrix(0.05,0,0,0.05,127.7,0)" xlink:href="#ay"/><use transform="matrix(0.05,0,0,0.05,142.65,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,146.6,0)" xlink:href="#aP"/><use transform="matrix(0.05,0,0,0.05,150.54999999999998,0)" xlink:href="#az"/><use transform="matrix(0.05,0,0,0.05,159.54999999999998,0)" xlink:href="#aE"/></g><g id="D"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#aM"/><use transform="matrix(0.05,0,0,0.05,12,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,15.949999999999998,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,25.950000000000003,0)" xlink:href="#aq"/><use transform="matrix(0.05,0,0,0.05,35.95,0)" xlink:href="#at"/><use transform="matrix(0.05,0,0,0.05,45.95,0)" xlink:href="#aC"/><use transform="matrix(0.05,0,0,0.05,55.95,0)" xlink:href="#ay"/><use transform="matrix(0.05,0,0,0.05,70.9,0)" xlink:href="#ap"/></g><g id="E"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#ao"/><use transform="matrix(0.05,0,0,0.05,9,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,12.949999999999998,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,22.95,0)" xlink:href="#aq"/><use transform="matrix(0.05,0,0,0.05,32.95,0)" xlink:href="#at"/><use transform="matrix(0.05,0,0,0.05,42.95,0)" xlink:href="#aC"/><use transform="matrix(0.05,0,0,0.05,52.95,0)" xlink:href="#ay"/><use transform="matrix(0.05,0,0,0.05,67.9,0)" xlink:href="#ar"/><use transform="matrix(0.05,0,0,0.05,77.9,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,81.85000000000001,0)" xlink:href="#at"/></g><g id="F"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#ao"/><use transform="matrix(0.05,0,0,0.05,9,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,12.949999999999998,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,22.95,0)" xlink:href="#aq"/><use transform="matrix(0.05,0,0,0.05,32.95,0)" xlink:href="#at"/><use transform="matrix(0.05,0,0,0.05,42.95,0)" xlink:href="#aC"/><use transform="matrix(0.05,0,0,0.05,52.95,0)" xlink:href="#ay"/></g><g id="G"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#aN"/><use transform="matrix(0.05,0,0,0.05,12.950000000000001,0)" xlink:href="#an"/><use transform="matrix(0.05,0,0,0.05,22.950000000000003,0)" xlink:href="#aO"/><use transform="matrix(0.05,0,0,0.05,31.950000000000003,0)" xlink:href="#az"/><use transform="matrix(0.05,0,0,0.05,40.95,0)" xlink:href="#aJ"/><use transform="matrix(0.05,0,0,0.05,51.900000000000006,0)" xlink:href="#an"/><use transform="matrix(0.05,0,0,0.05,61.900000000000006,0)" xlink:href="#ay"/><use transform="matrix(0.05,0,0,0.05,76.85000000000001,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,80.80000000000001,0)" xlink:href="#aP"/><use transform="matrix(0.05,0,0,0.05,84.75000000000001,0)" xlink:href="#aP"/><use transform="matrix(0.05,0,0,0.05,88.70000000000002,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,92.65000000000002,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,102.65000000000003,0)" xlink:href="#ap"/></g><g id="H"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#aQ"/><use transform="matrix(0.05,0,0,0.05,5,0)" xlink:href="#an"/><use transform="matrix(0.05,0,0,0.05,15,0)" xlink:href="#ay"/><use transform="matrix(0.05,0,0,0.05,29.950000000000003,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,33.900000000000006,0)" xlink:href="#aP"/><use transform="matrix(0.05,0,0,0.05,37.85000000000001,0)" xlink:href="#az"/></g><g id="I"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#ax"/><use transform="matrix(0.05,0,0,0.05,5.95,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,15.949999999999998,0)" xlink:href="#ap"/><use transform="matrix(0.05,0,0,0.05,24.95,0)" xlink:href="#au"/><use transform="matrix(0.05,0,0,0.05,29.950000000000003,0)" xlink:href="#ax"/></g><g id="J"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#ap"/><use transform="matrix(0.05,0,0,0.05,9,0)" xlink:href="#aB"/><use transform="matrix(0.05,0,0,0.05,19,0)" xlink:href="#am"/><use transform="matrix(0.05,0,0,0.05,29,0)" xlink:href="#aQ"/><use transform="matrix(0.05,0,0,0.05,34,0)" xlink:href="#an"/><use transform="matrix(0.05,0,0,0.05,44,0)" xlink:href="#ay"/><use transform="matrix(0.05,0,0,0.05,58.95,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,62.900000000000006,0)" xlink:href="#aP"/><use transform="matrix(0.05,0,0,0.05,66.85000000000001,0)" xlink:href="#az"/></g><path fill="#333" d="M232-93c-1 65-40 97-104 97C67 4 28-28 28-90v-158h33c8 89-33 224 67 224 102 0 64-133 71-224h33v155" id="aR"/><g id="K"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#aR"/><use transform="matrix(0.05,0,0,0.05,12.950000000000001,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,22.950000000000003,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,26.900000000000002,0)" xlink:href="#aH"/><use transform="matrix(0.05,0,0,0.05,36.900000000000006,0)" xlink:href="#ax"/><use transform="matrix(0.05,0,0,0.05,42.85000000000001,0)" xlink:href="#aC"/><use transform="matrix(0.05,0,0,0.05,52.85,0)" xlink:href="#au"/><use transform="matrix(0.05,0,0,0.05,57.85,0)" xlink:href="#ap"/></g><g id="L"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#av"/><use transform="matrix(0.05,0,0,0.05,5.95,0)" xlink:href="#aJ"/><use transform="matrix(0.05,0,0,0.05,16.900000000000002,0)" xlink:href="#aC"/><use transform="matrix(0.05,0,0,0.05,26.900000000000002,0)" xlink:href="#ax"/><use transform="matrix(0.05,0,0,0.05,32.85,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,36.800000000000004,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,46.800000000000004,0)" xlink:href="#aq"/><use transform="matrix(0.05,0,0,0.05,56.800000000000004,0)" xlink:href="#al"/></g><g id="M"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#ao"/><use transform="matrix(0.05,0,0,0.05,9,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,19,0)" xlink:href="#az"/></g><g id="N"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#aj"/><use transform="matrix(0.05,0,0,0.05,14,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,24,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,34,0)" xlink:href="#am"/><use transform="matrix(0.05,0,0,0.05,44,0)" xlink:href="#an"/><use transform="matrix(0.05,0,0,0.05,54,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,64,0)" xlink:href="#ao"/><use transform="matrix(0.05,0,0,0.05,73,0)" xlink:href="#ap"/><use transform="matrix(0.05,0,0,0.05,82,0)" xlink:href="#aL"/><use transform="matrix(0.05,0,0,0.05,87,0)" xlink:href="#aq"/><use transform="matrix(0.05,0,0,0.05,97,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,107,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,117,0)" xlink:href="#am"/><use transform="matrix(0.05,0,0,0.05,127,0)" xlink:href="#an"/><use transform="matrix(0.05,0,0,0.05,137,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,147,0)" xlink:href="#ao"/><use transform="matrix(0.05,0,0,0.05,156,0)" xlink:href="#ar"/><use transform="matrix(0.05,0,0,0.05,166,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,169.95,0)" xlink:href="#at"/><use transform="matrix(0.05,0,0,0.05,179.95,0)" xlink:href="#aE"/></g><g id="O"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#aB"/><use transform="matrix(0.05,0,0,0.05,10,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,20,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,23.95,0)" xlink:href="#aH"/><use transform="matrix(0.05,0,0,0.05,33.95,0)" xlink:href="#ax"/><use transform="matrix(0.05,0,0,0.05,39.900000000000006,0)" xlink:href="#aC"/><use transform="matrix(0.05,0,0,0.05,49.900000000000006,0)" xlink:href="#au"/><use transform="matrix(0.05,0,0,0.05,54.900000000000006,0)" xlink:href="#ar"/><use transform="matrix(0.05,0,0,0.05,64.9,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,68.85000000000001,0)" xlink:href="#at"/></g><g id="P"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#aB"/><use transform="matrix(0.05,0,0,0.05,10,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,20,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,23.95,0)" xlink:href="#aH"/><use transform="matrix(0.05,0,0,0.05,33.95,0)" xlink:href="#ax"/><use transform="matrix(0.05,0,0,0.05,39.900000000000006,0)" xlink:href="#aC"/><use transform="matrix(0.05,0,0,0.05,49.900000000000006,0)" xlink:href="#au"/><use transform="matrix(0.05,0,0,0.05,54.900000000000006,0)" xlink:href="#ar"/><use transform="matrix(0.05,0,0,0.05,64.9,0)" xlink:href="#an"/><use transform="matrix(0.05,0,0,0.05,74.9,0)" xlink:href="#aD"/><use transform="matrix(0.05,0,0,0.05,83.9,0)" xlink:href="#aD"/><use transform="matrix(0.05,0,0,0.05,92.9,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,102.9,0)" xlink:href="#ap"/><use transform="matrix(0.05,0,0,0.05,111.9,0)" xlink:href="#ap"/><use transform="matrix(0.05,0,0,0.05,120.9,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,124.85000000000001,0)" xlink:href="#aC"/><use transform="matrix(0.05,0,0,0.05,134.85000000000002,0)" xlink:href="#al"/></g><g id="Q"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#ap"/><use transform="matrix(0.05,0,0,0.05,9,0)" xlink:href="#au"/><use transform="matrix(0.05,0,0,0.05,14,0)" xlink:href="#ax"/></g><path fill="#333" d="M33-154v-36h34v36H33zM33 0v-36h34V0H33" id="aS"/><g id="R"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#av"/><use transform="matrix(0.05,0,0,0.05,5.95,0)" xlink:href="#aR"/><use transform="matrix(0.05,0,0,0.05,18.900000000000002,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,28.900000000000002,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,32.85,0)" xlink:href="#aw"/><use transform="matrix(0.05,0,0,0.05,44.85,0)" xlink:href="#ax"/><use transform="matrix(0.05,0,0,0.05,50.800000000000004,0)" xlink:href="#aC"/><use transform="matrix(0.05,0,0,0.05,60.800000000000004,0)" xlink:href="#au"/><use transform="matrix(0.05,0,0,0.05,65.80000000000001,0)" xlink:href="#aS"/></g><g id="S"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,10,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,20,0)" xlink:href="#au"/><use transform="matrix(0.05,0,0,0.05,25,0)" xlink:href="#ax"/><use transform="matrix(0.05,0,0,0.05,30.950000000000003,0)" xlink:href="#az"/></g><g id="T"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,3.95,0)" xlink:href="#at"/><use transform="matrix(0.05,0,0,0.05,13.949999999999998,0)" xlink:href="#aE"/></g><g id="U"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#aB"/><use transform="matrix(0.05,0,0,0.05,10,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,20,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,23.95,0)" xlink:href="#aH"/><use transform="matrix(0.05,0,0,0.05,33.95,0)" xlink:href="#ax"/><use transform="matrix(0.05,0,0,0.05,39.900000000000006,0)" xlink:href="#aC"/><use transform="matrix(0.05,0,0,0.05,49.900000000000006,0)" xlink:href="#au"/><use transform="matrix(0.05,0,0,0.05,54.900000000000006,0)" xlink:href="#ar"/><use transform="matrix(0.05,0,0,0.05,64.9,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,74.9,0)" xlink:href="#an"/><use transform="matrix(0.05,0,0,0.05,84.9,0)" xlink:href="#ay"/><use transform="matrix(0.05,0,0,0.05,99.85000000000001,0)" xlink:href="#ak"/></g><g id="V"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#ax"/><use transform="matrix(0.05,0,0,0.05,5.95,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,15.949999999999998,0)" xlink:href="#ap"/><use transform="matrix(0.05,0,0,0.05,24.95,0)" xlink:href="#au"/><use transform="matrix(0.05,0,0,0.05,29.950000000000003,0)" xlink:href="#ax"/></g><g id="W"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#av"/><use transform="matrix(0.05,0,0,0.05,5.95,0)" xlink:href="#aR"/><use transform="matrix(0.05,0,0,0.05,18.900000000000002,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,28.900000000000002,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,32.85,0)" xlink:href="#aw"/><use transform="matrix(0.05,0,0,0.05,44.85,0)" xlink:href="#ax"/><use transform="matrix(0.05,0,0,0.05,50.800000000000004,0)" xlink:href="#aC"/><use transform="matrix(0.05,0,0,0.05,60.800000000000004,0)" xlink:href="#au"/><use transform="matrix(0.05,0,0,0.05,65.80000000000001,0)" xlink:href="#aS"/></g><g id="X"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,10,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,20,0)" xlink:href="#au"/><use transform="matrix(0.05,0,0,0.05,25,0)" xlink:href="#ax"/><use transform="matrix(0.05,0,0,0.05,30.950000000000003,0)" xlink:href="#az"/></g><g id="Y"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,10,0)" xlink:href="#an"/><use transform="matrix(0.05,0,0,0.05,20,0)" xlink:href="#ay"/><use transform="matrix(0.05,0,0,0.05,34.95,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,44.95,0)" xlink:href="#aE"/></g><g id="Z"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#aj"/><use transform="matrix(0.05,0,0,0.05,14,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,24,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,34,0)" xlink:href="#am"/><use transform="matrix(0.05,0,0,0.05,44,0)" xlink:href="#an"/><use transform="matrix(0.05,0,0,0.05,54,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,64,0)" xlink:href="#ao"/><use transform="matrix(0.05,0,0,0.05,73,0)" xlink:href="#ap"/><use transform="matrix(0.05,0,0,0.05,82,0)" xlink:href="#ar"/><use transform="matrix(0.05,0,0,0.05,92,0)" xlink:href="#aw"/><use transform="matrix(0.05,0,0,0.05,104,0)" xlink:href="#at"/><use transform="matrix(0.05,0,0,0.05,114,0)" xlink:href="#am"/><use transform="matrix(0.05,0,0,0.05,124,0)" xlink:href="#ap"/></g><g id="aa"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#aH"/><use transform="matrix(0.05,0,0,0.05,10,0)" xlink:href="#at"/><use transform="matrix(0.05,0,0,0.05,20,0)" xlink:href="#am"/><use transform="matrix(0.05,0,0,0.05,30,0)" xlink:href="#ar"/><use transform="matrix(0.05,0,0,0.05,40,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,43.95,0)" xlink:href="#at"/></g><g id="ab"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#aw"/><use transform="matrix(0.05,0,0,0.05,12,0)" xlink:href="#at"/><use transform="matrix(0.05,0,0,0.05,22,0)" xlink:href="#am"/><use transform="matrix(0.05,0,0,0.05,32,0)" xlink:href="#ap"/><use transform="matrix(0.05,0,0,0.05,41,0)" xlink:href="#aL"/><use transform="matrix(0.05,0,0,0.05,46,0)" xlink:href="#aH"/><use transform="matrix(0.05,0,0,0.05,56,0)" xlink:href="#at"/><use transform="matrix(0.05,0,0,0.05,66,0)" xlink:href="#am"/><use transform="matrix(0.05,0,0,0.05,76,0)" xlink:href="#ar"/><use transform="matrix(0.05,0,0,0.05,86,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,89.95,0)" xlink:href="#at"/><use transform="matrix(0.05,0,0,0.05,99.95,0)" xlink:href="#aE"/></g><g id="ac"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#aw"/><use transform="matrix(0.05,0,0,0.05,12,0)" xlink:href="#at"/><use transform="matrix(0.05,0,0,0.05,22,0)" xlink:href="#am"/><use transform="matrix(0.05,0,0,0.05,32,0)" xlink:href="#ap"/></g><g id="ad"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#aH"/><use transform="matrix(0.05,0,0,0.05,10,0)" xlink:href="#at"/><use transform="matrix(0.05,0,0,0.05,20,0)" xlink:href="#am"/><use transform="matrix(0.05,0,0,0.05,30,0)" xlink:href="#ar"/><use transform="matrix(0.05,0,0,0.05,40,0)" xlink:href="#an"/><use transform="matrix(0.05,0,0,0.05,50,0)" xlink:href="#aD"/><use transform="matrix(0.05,0,0,0.05,59,0)" xlink:href="#aD"/><use transform="matrix(0.05,0,0,0.05,68,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,78,0)" xlink:href="#ap"/><use transform="matrix(0.05,0,0,0.05,87,0)" xlink:href="#ap"/><use transform="matrix(0.05,0,0,0.05,96,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,99.95,0)" xlink:href="#aC"/><use transform="matrix(0.05,0,0,0.05,109.95,0)" xlink:href="#al"/></g><path fill="#333" d="M30 0v-248h187v28H63v79h144v27H63v87h162V0H30" id="aT"/><g id="ae"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#aj"/><use transform="matrix(0.05,0,0,0.05,14,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,24,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,34,0)" xlink:href="#am"/><use transform="matrix(0.05,0,0,0.05,44,0)" xlink:href="#an"/><use transform="matrix(0.05,0,0,0.05,54,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,64,0)" xlink:href="#ao"/><use transform="matrix(0.05,0,0,0.05,73,0)" xlink:href="#ap"/><use transform="matrix(0.05,0,0,0.05,82,0)" xlink:href="#ar"/><use transform="matrix(0.05,0,0,0.05,92,0)" xlink:href="#aT"/><use transform="matrix(0.05,0,0,0.05,104,0)" xlink:href="#aD"/><use transform="matrix(0.05,0,0,0.05,113,0)" xlink:href="#ap"/></g><g id="af"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,10,0)" xlink:href="#aD"/><use transform="matrix(0.05,0,0,0.05,19,0)" xlink:href="#ar"/><use transform="matrix(0.05,0,0,0.05,29,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,32.95,0)" xlink:href="#at"/></g><g id="ag"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#aT"/><use transform="matrix(0.05,0,0,0.05,12,0)" xlink:href="#aD"/><use transform="matrix(0.05,0,0,0.05,21,0)" xlink:href="#ap"/><use transform="matrix(0.05,0,0,0.05,30,0)" xlink:href="#aL"/><use transform="matrix(0.05,0,0,0.05,35,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,45,0)" xlink:href="#aD"/><use transform="matrix(0.05,0,0,0.05,54,0)" xlink:href="#ar"/><use transform="matrix(0.05,0,0,0.05,64,0)" xlink:href="#as"/><use transform="matrix(0.05,0,0,0.05,67.95,0)" xlink:href="#at"/><use transform="matrix(0.05,0,0,0.05,77.95,0)" xlink:href="#aE"/></g><g id="ah"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#aT"/><use transform="matrix(0.05,0,0,0.05,12,0)" xlink:href="#aD"/><use transform="matrix(0.05,0,0,0.05,21,0)" xlink:href="#ap"/></g><g id="ai"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,10,0)" xlink:href="#aD"/><use transform="matrix(0.05,0,0,0.05,19,0)" xlink:href="#ar"/><use transform="matrix(0.05,0,0,0.05,29,0)" xlink:href="#al"/><use transform="matrix(0.05,0,0,0.05,39,0)" xlink:href="#aB"/><use transform="matrix(0.05,0,0,0.05,49,0)" xlink:href="#ay"/><use transform="matrix(0.05,0,0,0.05,63.95,0)" xlink:href="#am"/><use transform="matrix(0.05,0,0,0.05,73.95,0)" xlink:href="#ak"/><use transform="matrix(0.05,0,0,0.05,83.95,0)" xlink:href="#ax"/></g></defs></g></svg>
\ No newline at end of file
diff --git a/docs/database.rst b/docs/database.rst
index 4c61bbc2..29d0e968 100644
--- a/docs/database.rst
+++ b/docs/database.rst
@@ -23,7 +23,14 @@ Each CAZyme may or may not have the following data, depending on the entry:
 Database Schema
 ---------------
 
-The database ORM (schema) can be viewed `Here <https://hobnobmancer.github.io/cazy_webscraper/database_schema.pdf>`_
+Below is the database ORM. It plots the relationships between elements in each table.
+
+.. image:: cazy_webscraper_version2.svg
+   :scale: 100 %
+   :alt: cazy_webscraper database schema
+   :align: center
+
+The database ORM (schema) can also be viewed `Here <https://hobnobmancer.github.io/cazy_webscraper/database_schema.pdf>`_
 
 --------------
 The Logs table
diff --git a/docs/genbank.rst b/docs/genbank.rst
index cc8adce1..c1a6758a 100644
--- a/docs/genbank.rst
+++ b/docs/genbank.rst
@@ -58,7 +58,7 @@ Command line options
 
 ``--ec_filter`` - List of EC numbers to limit the retrieval of protein data for proteins annotated with at least one of the given EC numbers **in the local CAZyme database**.
 
-``--entrez_batch_size`` - Change the query batch size submitted via [`Entrez`]() to retrieve protein sequences from GenBank data. Default is 150. `Entrez <https://www.ncbi.nlm.nih.gov/books/NBK179288/>_` recommands queries not larger than XXX objects in length.
+``--force``, ``-f`` - Force writing cachce to exiting cache directory.
 
 ``--families`` - List of CAZy (sub)families to retrieve UniProt protein data for.
 
@@ -66,6 +66,8 @@ Command line options
 
 ``--genera`` - List of genera to restrict the retrieval of protein to data from UniProt to proteins belonging to one of the given genera.
 
+``--kingdoms`` - List of taxonomy kingdoms to retrieve UniProt data for.
+
 ``--log``, ``-l`` - Target path to write out a log file. If not called, no log file is written. Default: None (no log file is written out).
 
 ``--nodelete_cache`` - When called, content in the existing cache dir will **not** be deleted. Default: False (existing content is deleted).
@@ -84,19 +86,18 @@ Command line options
 
 ``--strains`` - List of species strains to restrict the retrieval of protein to data from UniProt to proteins belonging to one of the given strains.
 
-``--timeout``, ``-t`` - Connection timout limit (seconds). Default: 45.
-
 ``--verbose``, ``-v`` - Enable verbose logging. This does **not** set the SQLite engine ``echo`` parameter to True. Default: False.
 
 -----------
 Basic Usage
 -----------
 
-The command-line options listed above can be used in combination to customise the scraping of CAZy. Some options (e.g. ``--families`` and ``--classes``) define the broad group of data that will be scraped, others (e.g. ``--species``) are used to filter and fine-tune the data that is scraped.
+The command-line options listed above can be used in combination to customise the scraping of CAZy. Some options (e.g. ``--families`` and ``--classes``) 
+define the broad group of data that will be scraped, others (e.g. ``--species``) are used to filter and fine-tune the data that is scraped.
 
 The ``--classes``, ``--families``, ``--kingdoms``, ``--genera``, ``--species``, and ``--strains`` filteres are applied 
-in the exactly same for retrieving data from CAZy as retrieving data from UniProt. Examples of using these flags 
-can be found in the ``cazy_webscraper`` tutorial in this documentation.
+in the exactly same for retrieving data from CAZy as retrieving protein sequences from GenBank and protein data from UniProt. Examples of using these flags 
+can be found in the `tutorial <https://cazy-webscraper.readthedocs.io/en/latest/genbanktutorial.html>`_.
 
 The ``--seq_update`` flag is used in the same way for retrieving protein sequences from UniProt and GenBank.
 
diff --git a/docs/genbanktutorial.rst b/docs/genbanktutorial.rst
index 94a6ec0a..cf78584f 100644
--- a/docs/genbanktutorial.rst
+++ b/docs/genbanktutorial.rst
@@ -2,7 +2,259 @@
 Retrieving Sequences from GenBank Tutorial
 ==========================================
 
-Tutorial coming soon!
+``cazy_webscraper`` can be configured to retrieve protein sequences for for specific date 
+sets of CAZymes in a local CAZyme database. Many of the same configuration options 
+apply to the retrieval of protein sequences from CAZy, UniProt, GenBank and PDB.
+
+.. NOTE::
+   ``cazy_webscraper`` retrieves protein sequences from GenBank for CAZymes in a local CAZyme database.
+
+``cazy_webscraper`` can be configured via the **command line** and/or via a **YAML configuration file**.
+
+This page runs through examples of how to combine the various 'filters' that can be applied, to fully customised 
+the retrieval of protein sequences from GenBank. These tutorials are designed for those with less experience using command-line tools.
+
+.. NOTE::
+  If you installed ``cazy_webscraper`` using ``bioconda`` or ``pip`` to invoke ``cazy_webscraper`` to retrieve UniProt data call it using ``cw_get_genbank_seqs`` - this is the method used in this tutorial.  
+  If you installed ``cazy_webscraper`` from source then you will need to invoke ``cazy_webscraper`` from the root of the repo using the command ``python3 cazy_webscraper/expand/uniprot/get_uniprot_data.py``.
+
+From this point on, we will be discusseing the ``cw_get_genbank_seqs`` command, which is used by ``cazy_webscraper`` for 
+retrieving protein sequences from GenBank. We also presume you are comfortable configuring ``cazy_webscraper`` for the 
+scraping of data from CAZy.
+
+All protein sequences from GenBank by ``cw_get_genbank_seqs`` are added to the local CAZyme database.
+
+----------------------------------
+Configuration via the command line
+----------------------------------
+
+``cw_get_genbank_seqs`` requires two arguments:
+* The path to the local CAZyme database created using ``cazy_webscraper``
+* The user's email address
+
+Therefore, ``cw_get_genbank_seqs`` can be enabled using a simple command structure:
+
+.. code-block:: bash
+
+  cazy_webscraper <path to the local CAZyme db> <email address>
+
+.. note::
+    NCBI Entrez is used to retrieve the data from GenBank and requires the user's email address.
+
+For example, if our database was stored in ``cazy/cazyme.db``, we would used:
+
+.. code-block:: bash
+   
+  cazy_webscraper cazy/cazyme.db my_email@domain.com
+
+.. NOTE::
+   Make sure ``cw_get_genbank_seqs`` is pointed directly at the database file.
+
+When no optional arguments are provided, the default behaviour is invoked. The default behaviour is to: 
+retrieve protein sequences for **all** CAZymes in the local CAZyme db
+
+-----------------------------------------
+Options configurable at the command line 
+-----------------------------------------
+
+The following behaviours of the ``cw_get_genbank_seqs`` can be configured at the command-line in the terminal:  
+
+* Limit the retrieval of protein sequences to CAZymes in the local databaes from specific CAZy classes, CAZy families, kingdoms, genuera, species, strains and/or EC numbers
+* Enable updating protein sequences in the local CAZyme database if newer versions are retrieved from UniProt
+* Enable verbose logging during the operation of the webscraper
+
+`Here <https://cazy-webscraper.readthedocs.io/en/latest/genbank.html>`_ you can find a full list of the command-line flags and options.
+
+
+--------------------------------------------------------------------
+Retrieving protein sequences for CAZy classes and families to scrape
+--------------------------------------------------------------------
+
+The ``--classes`` and ``--families`` flags from scraping data from CAZy are applied in the extact same way 
+for retrieving protein sequences from GenBanks.
+
+For instance, if instead of retrieving protein sequences for all CAZymes in your local CAZyme database, you want to 
+retrieve protein sequences for CAZymes in specific CAZy classes then add the 
+``--classes`` flag followed by the classes you want to retrieve protein sequences for.
+
+.. TIP::
+   To list multiple classes, separate the classes with a single comma. 
+
+For example, if you want to retrieve protein sequences for all CAZymes from Glycoside Hydrolase and Carbohydrate Esterases then use the command:
+
+.. code-block:: bash
+
+   cw_get_genbank_seqs cazy/cazyme.db dummy.email@domain.co.uk --classes GH,CE
+
+OR
+
+.. code-block:: bash
+
+   cw_get_genbank_seqs cazy/cazyme.db dummy.email@domain.co.uk --classes Glycoside Hydrolases,Carbohydrate Esterases
+
+Retrieving protein sequences for proteins from specific specific CAZy families is achieved using the ``--families`` flag. For 
+example, to retrieve protein sequences for all proteins in PL1, PL2 and PL3 in the local CAZyme database use the 
+following command:
+
+.. code-block:: bash
+
+   cw_get_genbank_seqs cazy/cazyme.db dummy.email@domain.co.uk --families PL1,PL2,PL3
+
+.. WARNING::
+   ``cw_get_genbank_seqs`` only accpets families written in the proper CAZy family syntax.
+   GH1 is accepted.
+   gh1 and GlycosideHydrolases1 are not accepted.
+
+As with scraping data from CAZy, the ``--classes`` and ``--families`` flags can be combined. To retrieve 
+protein sequences for all CAZymes in PL1, PL2, PL3 and *all* of GH and CE both:
+
+.. code-block:: bash
+
+   cw_get_genbank_seqs cazy/cazyme.db dummy.email@domain.co.uk --families PL1,PL2,PL3 --classes GH,CE
+
+**AND**
+
+.. code-block:: bash
+
+   cw_get_genbank_seqs cazy/cazyme.db dummy.email@domain.co.uk --classes GH,CE --families PL1,PL2,PL3
+
+are accepted.
+
+
+------------------
+Applying taxonomic
+------------------
+
+The ``--kingdoms``, ``--genera``, ``--species`` and ``--strains`` flags can be used to refine the dataset 
+of proteins to retrieve protein sequences by taxonomy. These flags are applied in the exact same way as they 
+are used for the scraping of data from CAZy. Only proteins in the local CAZyme database and matching at least on of the provided taxonomy 
+criteria will have protein sequences retrieved from GenBank and added to the local CAZyme datbase.
+
+For example, if you want to retrieve protein sequences for all CAZymes in a local CAZyme database from bacterial and eukaryotic species then use the command 
+
+.. code-block:: bash
+
+   cw_get_genbank_seqs cazy/cazyme.db dummy.email@domain.co.uk --kingdoms bacteria,eukaryota
+
+.. warning::
+   The kingdoms must be spelt the same way CAZy spells them, for example use 'eukaryot**a**' instead of 'eukaryot**e**'.
+   
+.. NOTE:: 
+   The kingdoms are **not** case sensitive, therefore, both ``bacteria`` *and* ``Bacteria`` are accepted. 
+
+.. NOTE::
+   You can list the kingdoms in *any* order. Thus, both ``bacteria,eukaryota`` *and* ``eukaryota,bacteria`` are accepted.
+
+You can combine any combination of the optional flags, including combining the taxonomic filters. For example,
+you may wish to retrieve protein sequences for all CAZymes in a local CAZyme database that are derived from all viral species, Aspergillus species, Layia carnosa, Layia chrysanthemoides, Trichoderma reesei QM6a and 
+Trichoderma reesei QM9414. To do this we would combine the respective flags for a single ``cw_get_genbank_seqs`` command. The command 
+we would use would be:
+
+.. code-block:: bash
+
+   cw_get_genbank_seqs cazy/cazyme.db dummy.email@domain.co.uk --kingdoms viruses --genera Aspergillus --species Layia carnosa,Layia chrysanthemoides --strains Trichoderma reesei QM6a,Trichoderma reesei QM9414
+
+.. note::
+   The order that the flags are used and the order taxa  are listed does **not** matter, and separate multiple taxa names with a single comma 
+   with **no** spaces.
+
+.. warning::
+   Use the standard scientific name formating. Captialise the first letter of *genus* and write a lower 
+   case letter for the first letter of the species.
+
+   Aspergillus niger is **correct**
+
+   asepergillus niger is **incorrect**
+
+   ASPERGILLUS NIGER is **incorrect**
+
+.. warning::
+   When you specify a species ``cw_get_genbank_seqs`` will retrieval CAZymes from *all* strains of the species.
+
+
+-------------------------
+Applying EC number filter
+-------------------------
+
+The retrieval of protein sequences from GenBank can also be limited to proteins in a local CAZyme database that are
+annotated with specific EC numbers.
+
+Having previously retrieved EC number annotations and added them to the local CAZyme database, you  may 
+wish to retrieve protein sequences for CAZymes annotated with specific EC numbers. To do this add the 
+``--ec_filter`` flag to the command, follwed by a list of EC numbers.
+
+.. code-block:: bash
+   
+   cw_get_genbank_seqs cazy/cazyme.db dummy.email@domain.co.uk --ec_filter "EC1.2.3.4,EC2.3.4.5"
+
+
+.. NOTE::
+    Provide complete EC numbers. 
+    Both dashes ('-') and asterixes ('*') are accepted for missing digits in EC numbers.
+
+    EC1.2.3.- and EC1.2.3.* are accepted.
+    EC1.2.3. and EC 1.2.3 are **not** accepted.
+
+.. NOTE::
+   The 'EC' prefix is not necessary.
+   EC1.2.3.4 and 1.2.3.4 are accepted.
+
+.. WARNING::
+    If using dashes to represent missing digits in EC numbers, it is recommended to bookend the entire 
+    EC number list in single or double quotation marks. Some terminals may misinterpret EC1.2.-.- as trying to invoke the options '.'
+
+.. NOTE::
+    ``cazy_webscraper`` will retrieve the specified UniProt data for all proteins in the local CAZyme 
+    database that are annotated with **at least one** of the given EC numbers. Therefore, if multiple 
+    EC numbers are given this **does not mean** only CAZymes will all provided EC numbers will have data retrieved
+    from UniProt for them.
+
+``--ec_filter`` is based upon EC number annotations stored within the local CAZyme database. For 
+example, if protein A is annotated with the EC1.2.3.4, but this annotation is not stored in the 
+local CAZyme database, using ``--ec_filter EC1.2.3.4`` will **not** cause ``cazy_webscraper`` to retrieve
+data for protein A. This is because ``cazy_webscraper`` does not know protein A is annotated with 
+EC1.2.3.4, because this annotation is not within its database.
+
+.. WARNING::
+    If ``--ec_filter`` is used along side ``--ec``, ``cazy_webscraper`` will retrieve **all** EC number 
+    annotations from UniProt for all proteins in the local CAZyme database that are associated with 
+    at least one of the EC numbers provided via ``--ec_filter`` within the CAZyme database.
+
+
+---------------------
+Combining all filters
+---------------------
+
+The ``--classes``, ``--families``, ``--ec_filter``, ``--kingdoms``, ``--genera``, ``--species`` and ``--strains`` flags can 
+be used in any combination to define a specific subset of proteins in the local CAZyme database for whom
+protein sequences from GenBank will be retrieved.
+
+Below we run through 3 example commands of combining these flags, and the resulting behaviour.
+
+**Example 1:**
+To retrieve protein sequences for all CAZymes in GH, GT, CE1, CE5 and CE8, and which are derived from baceterial species we use the command:
+
+.. code-block:: bash
+
+   cw_get_genbank_seqs cazy/cazyme.db dummy.email@domain.co.uk --classes GH,CE --families CE1,CE5,CE8 --kingdoms bacteria
+
+
+**Example 2:**
+To protein sequences for all CAZymes in GH and which are derived from *Aspegillus* and *Trichoderma* species we use the command:
+
+.. code-block:: bash
+
+   cw_get_genbank_seqs cazy/cazyme.db dummy.email@domain.co.uk -classes GH --genera Aspegillus,Trichoderma
+
+
+**Example 3:**
+To retrieve protein sequences for all CAZymes in GH,CE and CBM which are derived from baceterial species and are annotated with at least one of 
+EC3.2.1.23, EC3.2.1.37 and EC3.2.1.85, we use the command:
+
+.. code-block:: bash
+
+   cw_get_genbank_seqs cazy/cazyme.db dummy.email@domain.co.uk --ec --sequences --classes GH,CE,CBM --kingdoms bacteria --ec_filter "3.2.1.23,3.2.1.37,3.2.1.85"
+
 
 ------------------------------
 Providing a list of accessions
diff --git a/docs/index.rst b/docs/index.rst
index a5d1fbbd..b3654741 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -130,6 +130,8 @@ For details and updates on development, please consult the `GitHub repository <h
    sequencetutorial
    pdb
    pdbtutorial
+   api
+   apitutorial
    cache
    license
 
diff --git a/docs/pdb.rst b/docs/pdb.rst
index ba4f27fe..cb4066c2 100644
--- a/docs/pdb.rst
+++ b/docs/pdb.rst
@@ -74,6 +74,8 @@ Command line options
 
 ``--genera`` - List of genera to restrict the retrieval of protein to data from UniProt to proteins belonging to one of the given genera.
 
+``--kingdoms`` - List of taxonomy kingdoms to retrieve UniProt data for.
+
 ``--log``, ``-l`` - Target path to write out a log file. If not called, no log file is written. Default: None (no log file is written out).
 
 ``--nodelete``, ``-n`` - When called, content in the existing output  will **not** be deleted. Default: False (existing content is deleted).
@@ -96,8 +98,6 @@ Command line options
 
 ``--uniprot_accessions`` - Path to text file containing a list of UniProt accessions to retrieve protein data for. A unique accession per line.
 
-``--update_seq`` - If a newer version of the protein sequence is available, overwrite the existing sequence for the protein in the database. Default is false, the protein sequence is **not** overwritten and updated.
-
 ``--verbose``, ``-v`` - Enable verbose logging. This does **not** set the SQLite engine ``echo`` parameter to True. Default: False.
 
 
diff --git a/docs/sequence.rst b/docs/sequence.rst
index f6364fb1..f197d641 100644
--- a/docs/sequence.rst
+++ b/docs/sequence.rst
@@ -9,7 +9,7 @@ The extracted protein sequences can be written to any combination of:
 * One FASTA file per extracted sequence
 * A BLASTp database
 
-Protein sequences retrieved from GenBank and/or UniProt can be extracted.
+GenBank and/or UniProt protein sequences retrieved can be extracted.
 
 -----------
 Quick Start
@@ -44,7 +44,7 @@ Command line options
 
 *The database names are not case sensitive, therefore, both GenBank and genbank are accepted.* 
 
-``-b``, ``--blastdb`` - Create BLAST database of extracted protein sequences. Provide the path to the directory to store the BLAST database in.
+``--blastdb``, ``-b`` - Create BLAST database of extracted protein sequences. Provide the path to the directory to store the BLAST database in.
 
 ``--fasta_dir`` - Write out each extracted sequence to a separate FASTA file in the provided dir. Provide a path to a directory to write out the FASTA files.
 
diff --git a/docs/sequencetutorial.rst b/docs/sequencetutorial.rst
index bac58ac6..dd694a8b 100644
--- a/docs/sequencetutorial.rst
+++ b/docs/sequencetutorial.rst
@@ -1,15 +1,15 @@
-==========================================================================
-Tutorials on configuring ``cazy_webscraper`` to extract protein sequences
-==========================================================================
+============================================================
+Tutorials on configuring the extraction of protein sequences
+============================================================
 
-``cazy_webscraper`` can be configured to extract GenBank and/or UniProt protein sequences for user specified data sets of proteins from 
+``cazy_webscraper`` can be configured to extract GenBank and/or UniProt protein sequences for user specified sets of proteins from 
 a local CAZyme database. Many of the configuration options 
 apply to the retrieval of protein data from CAZy, UniProt, GenBank and PDB.
 
 ``cazy_webscraper`` can be configured via the **command line** and/or via a **YAML configuration file**.
 
 This page runs through examples of how to combine the various 'filters' that can be applied, to fully customised 
-the extract of protein sequences. These tutorials are designed for those with less experience using command-line tools.
+the extraction of protein sequences. These tutorials are designed for those with less experience using command-line tools.
 
 .. NOTE::
   If you installed ``cazy_webscraper`` using ``bioconda`` or ``pip`` to invoke ``cazy_webscraper`` to retrieve UniProt data call it using ``cw_extract_db_sequences`` - this is the method used in this tutorial.  
@@ -24,14 +24,13 @@ scraping of data from CAZy.
 Configuration via the command line
 ----------------------------------
 
-``cw_extract_db_sequences`` has at 3 required arguments:
+``cw_extract_db_sequences`` has at 2 required arguments:
 
 1. The path to the local CAZyme databases created using ``cazy_webscraper``
 2. The names of the database from which the proteins were sourced
-3. Target to write out output
 
 When no optional arguments are provided, the default behaviour is invoked. The default behaviour is to: 
-Extract protein sequences (previously retrieved from GenBank and/for UniProt) for **all** CAZymes in the local CAZyme db
+Extract (GenBank and/ot UniProt) protein sequences for **all** CAZymes in the local CAZyme db
 
 
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -147,7 +146,7 @@ limit the extraction of protein sequences to CAZymes in the local databaes from
 * Species strains
 * Annotated with at least one of a set of specified EC numbers
 
-`Here <https://cazy-webscraper.readthedocs.io/en/latest/configuration_scraper.html>`_ you can find a full list of the command-line flags and options.
+`Here <https://cazy-webscraper.readthedocs.io/en/latest/sequence.html>`_ you can find a full list of the command-line flags and options.
 
 
 ----------------------------------------------------------------
diff --git a/docs/tutorial.rst b/docs/tutorial.rst
index 800f6d14..897d3716 100644
--- a/docs/tutorial.rst
+++ b/docs/tutorial.rst
@@ -2,8 +2,8 @@
 Tutorials on configuring ``cazy_webscraper`` to scrape CAZy
 ================================================================
 
-``cazy_webscraper`` can be configured to retrieve user specified data sets from CAZy. The configuration 
-applies to the retrieval of protein data from UniProt, protein sequences from GenBank and protein structure files from PDB.
+``cazy_webscraper`` can be configured to retrieve user specified data sets from CAZy. The same configuration 
+applies to the retrieval of protein data from UniProt, GenBank and PDB.
 
 ``cazy_webscraper`` can be configured via the **command line** and/or via a **YAML configuration file**.
 
@@ -21,7 +21,7 @@ Configuration via the command line
 ----------------------------------
 
 ``cazy_webscraper`` has only one required argument, the user email address. Therefore, 
- the scraper can be enabled by simply calling the scraper at the command line. For example, using: 
+ the scraper can be enabled to scrape all of CAZy using the following command:
 
 .. code-block:: bash
 
@@ -30,14 +30,14 @@ Configuration via the command line
 When no optional arguments are provided the default behaviour of the scraper will be performed. 
 The default behaviour is to:
 
-* Scrape the entire CAZy databases
+* Scrape the entirety of CAZy databases
 * Write the resulting database to the current working directory
-* Not to retrieve subfamilies (members of subfamilies will be retrieved but only their parent family will be listed)
+* Not retrieve subfamilies (members of subfamilies will be retrieved but only their parent family will be listed)
 
-.. note::
+.. NOTE::
    **For those new to using command-line tools:**  
    Arguments are additional pieces of information we add onto the end of the command. They are used to configure the specific behaviour 
-   performed by computer when we tell it to perform a specific command. In the examples above the command is ``cazy_webscraper myemail@domain.com``, 
+   performed by yjr computer when we tell it to perform a specific command. In the examples above the command is ``cazy_webscraper myemail@domain.com``, 
    where we have told to computer to run the Python program ``cazy_webscraper`` and submit the user email 
    address to NCBI for the retrieval of source orgnaism data. No additional information was provided, the computer 
    will invoke ``cazy_webscraper`` using its default behaviour. If you do not want the default behaviour of ``cazy_webscraper`` then we need to 
@@ -57,7 +57,7 @@ The following behaviours of the ``cazy_webscraper`` can be configured at the com
 * Enable retrieving subfamilies
 * Enable verbose logging during the operation of the webscraper
 
-`Here <https://cazy-webscraper.readthedocs.io/en/latest/configuration_scraper.html>`_ you can find a full list of the command-line flags and options.
+`Here <https://cazy-webscraper.readthedocs.io/en/latest/usage.html>`_ you can find a full list of the command-line flags and options.
 
 
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -68,16 +68,21 @@ The command-line options listed above can be used in any combination to customis
 to restrict which CAZymes are scraped from CAZy are applied in combination. For example, if the ``--families`` option and ``--genera`` option are called then 
 only CAZymes from the specified families **and** belonging to source organisms within the defined genera will be retrieved.
 
-We will now walk through some examples of how to use ``cazy_webscraper``. All example code provided in this section will presume that the terminal is pointed at the ``cazy_webscraper`` directory, which contains the ``cazy_webscraper.py`` file.
+We will now walk through some examples of how to use ``cazy_webscraper``. All example code presumes ``cazy_webscraper`` was installled using 
+``Bioconda`` or ``pip`` and therefore, be simply called using the command ``cazy_webscraper``.
 
 .. NOTE::
-   
    **For those new to using command-line tools: flags**
-   Command-line flags are used to tell the computer specifically which option(s) to change. Flags **always** come after the command. The abbreivated 
-   version of a flag with with prefixed with a single dash, followed by a single letter. For example, ``-s``,``-o`` and ``-l`` are all examples of short 
-   hand flags. The long version of a flag is prefixed by two dashes, followed by complete words. For example, ``--output`` is the long version of the ``-o``. 
+   Command-line flags are used to tell the computer specifically which option(s) to change. Flags **always** come after the command.
+   
+   The abbreivated 
+   version of a flag is given the prefixed of a single dash, followed by a single letter. For example, ``-s``, ``-o`` and ``-l`` are all examples of short 
+   hand flags.
+   
+   The long version of a flag is prefixed by two dashes, followed by complete words. For example, ``--output`` is the long version of the ``-o``. 
+
    The flags used by a program are defined within the program. This means the flag ``-o`` may represent different options for different programs. Always make 
-   sure to check the documentation to see what flags are provided with the program, and what they do.
+   sure to check the documentation to see what flags are provided with the program, and what they do!
    
    You can use the command-line to list all flags for a program/tool by typing in the command to invoke that tool, followed by the flag ``--help`` or ``-h``. For example: 
    ``cazy_webscraper --help``.
@@ -87,9 +92,13 @@ We will now walk through some examples of how to use ``cazy_webscraper``. All ex
 Configuring were the output is saved
 -------------------------------------
 
-Instead of writing out database to the current working directory using the default database name 
+^^^^^^^^^^^^^^^^^^^^^^^
+Creating a new database
+^^^^^^^^^^^^^^^^^^^^^^^
+
+Instead of writing out the database to the current working directory using the default database name 
 (``cazy_webscraper_<date>_<time>.db``), we can name the database and directory that the database 
-created by ``cazy_webscraper`` is written by calling the ``--output`` flag. 
+created by ``cazy_webscraper`` is written to by calling the ``--output`` flag. 
 
 We add the flag to the command that invokes ``cazy_webscraper``. For example, to write the output to the directory 'cazyme_database' with the file 
 name 'cazyme_database.db' we can use:
@@ -105,7 +114,7 @@ OR we can use the short hand version of the ``--output`` flag, ``-o``:
    cazy_webscraper -o cazyme_database/cazyme_database.db
 
 .. NOTE::
-   The final element of the path provided after the ``--output``/``-o`` flag is the name of database compiled by 
+   The final element of the path provided after the ``--output`` / ``-o`` flag is the name of database compiled by 
    ``cazy_webscraper``.
 
 The output directory does not have to exist when ``cazy_webscraper`` is invoked. ``cazy_webscraper`` can make 
@@ -117,11 +126,14 @@ The ``--output`` flag can take an infinetly long path. For example, we could use
 
    cazy_webscraper -o data/cazyme_research/cazyme_database/cazyme_database.db
 
-If the directories ``cazymes_research`` and ``cazyme_database`` did not exist then ``cazy_webscraper`` will build 
+If the directories ``cazymes_research`` and ``cazyme_database`` did not exist, then ``cazy_webscraper`` will build 
 these for you.
 
-**Writing the output to an existing database**
-If you want to write the output CAZyme database to a directory that already exists, you will need to add the force (``--force`` *or* ``-f``) flag 
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Overwriting an existing database or directory
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If you want to write the output CAZyme database to a directory and/or file that already exists, you will need to add the force (``--force`` *or* ``-f``) flag 
 anywhere to the ``cazy_webscraper`` command. For example:
 
 .. code-block:: bash
@@ -160,6 +172,38 @@ The above examples also highlight that it does not matter if you use the long or
    about ``cazy_webscraper`` deleting content in the current working directory. This only applies if you chose to
    write the database to a directory over than the current working directory.
 
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Add the scraped data to an existing CAZyme database
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+You may wish to scrape CAZy in multiple stages; maybe your internet dropped out while scraping CAZy 
+and you don't want to start again, or maybe you scraped CAZy but missed out a species of interest. No matter 
+the reason ``cazy_webscraper`` allows you to add more CAZyme data to an existing database previously created by 
+``cazy_webscraper``.
+
+To do this add the database (``--database`` or ``-d``) flag to the ``cazy_webscraper`` command, followed by the path 
+to the CAZyme database you want to add your scraped CAZy data to. For example, to add data to an existing 
+database in ``cazy/cazyme_db.db`` use the command:
+
+.. code-block:: bash
+
+   cazy_webscraper -- database cazy/cazyme_db.db
+
+.. note::
+   Don't forget the .db file extension at the end of the path!
+
+All the paths we pass to ``cazy_webscraper`` are a *relative* path. This means ``cazy_webscraper`` will start in the directory 
+the terminal is currently pointed out, and follow the path from there. For example, if we used the command:
+
+.. code-block:: bash
+
+   cazy_webscraper -d my_cazyme_databases/my_cazyme_database.db
+
+Then the computer will look for a directory called ``my_cazyme_databases`` in the directory the terminal is looking at, then within the 
+``my_cazyme_databases`` directory the computer will look for the file ``my_cazyme_database.db``.
+
+
 ----------------------------------------------
 Specifying CAZy classes and families to scrape
 ----------------------------------------------
@@ -196,6 +240,8 @@ For example, if you want to scrape all CAZymes from Glycoside Hydrolase and Carb
    These synonyms are stored in a JSON found at ``scraper/utilities/parse_configuration/cazy_dictionary.json``. 
    Storing these synonyms allows you to modify this file if you wish to add your own synonoms for each CAZy class.
 
+If you have your own synonyms these can be used by using the ``--cazy_synonyms`` flag, followed by the path to your JSON file. This JSON file **must** have the same 
+architecture as the JSON filed used by ``cazy_webscraper``.
 
 ^^^^^^^^^^^^^^^^^^^^^^^^^^
 Scraping specific families
@@ -333,7 +379,7 @@ For example, if we wanted to retrieve all CAZymes from *Aspergillus niger* and *
 
 .. code-block:: bash
 
-   cazy_webscraper --species Aspergillus niger,Asepergillus fumigatus
+   cazy_webscraper --species "Aspergillus niger,Asepergillus fumigatus"
 
 
 .. note::
@@ -350,6 +396,16 @@ For example, if we wanted to retrieve all CAZymes from *Aspergillus niger* and *
 
    ASPERGILLUS NIGER is **incorrect**
 
+.. warning::
+  When providing any parameter that contains a space within it, enclose the entire parameter is single or double quotation marks
+  
+   "Aspergillus niger,Trichoderma reesie" is **correct**
+   
+   'Aspergillus niger,Trichoderma reesie' is **correct**
+
+   asepergillus niger,Trichoderma reesie is **incorrect**
+   
+   Therefore, when using the ``-species`` and ``--strains`` flag,s **always** enclode the provided argument (or parameter) in single or double quotation marks.
 
 .. warning::
    When you specify a species ``cazy_webscraper`` will retrieval CAZymes from *all* strains of the species.
@@ -370,7 +426,7 @@ For example, if we wanted to retrieve all CAZymes from Aspergillus niger ATCC 10
 
 .. code-block:: bash
 
-   cazy_webscraper --strains Aspergillus niger ATCC 1015,Aspergillus uvarum CBS 121591
+   cazy_webscraper --strains "Aspergillus niger ATCC 1015,Aspergillus uvarum CBS 121591"
 
 he order that the strains are listed does **not** matter.
 
@@ -378,11 +434,21 @@ he order that the strains are listed does **not** matter.
    If you use the ``--species``, ``--genera`` and ``--strains`` flags in any combination and a source organism matches 
    multiple of the taxonomy critera, the CAZymes derived from that species will only be retrieved **once**.
    
-   For example, using the command ``cazy_webscraper --genera Aspergillus --species Aspergillus niger --strains Aspergillus niger ATCC 1015`` 
+   For example, using the command ``cazy_webscraper --genera Aspergillus --species "Aspergillus niger" --strains "Aspergillus niger ATCC 1015"`` 
    will retrieve all CAZymes from *all* Aspergillus species *once*.
    
 The higher taxonomy levels take president, and the command will not retrieve all CAZymes from all Aspergillus species once AND all CAZymes from Aspergillus niger strains as well, and then retrieve another copy of all CAZymes from Aspergillus niger ATCC 1015.
 
+.. warning::
+  When providing any parameter that contains a space within it, enclose the entire parameter is single or double quotation marks
+  
+   "Aspergillus niger,Trichoderma reesie" is **correct**
+   
+   'Aspergillus niger,Trichoderma reesie' is **correct**
+
+   asepergillus niger,Trichoderma reesie is **incorrect**
+   
+   Therefore, when using the ``-species`` and ``--strains`` flag,s **always** enclode the provided argument (or parameter) in single or double quotation marks.
 
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 Combining taxonomic filters
@@ -395,7 +461,7 @@ we would use would be:
 
 .. code-block:: bash
 
-   cazy_webscraper --kingdoms viruses --genera Aspergillus --species Layia carnosa,Layia chrysanthemoides --strains Trichoderma reesei QM6a,Trichoderma reesei QM9414
+   cazy_webscraper --kingdoms viruses --genera Aspergillus --species "Layia carnosa,Layia chrysanthemoides" --strains "Trichoderma reesei QM6a,Trichoderma reesei QM9414"
 
 .. note::
    This is a single command written on a single line. When typing the command into the terminal do not fit enter until you have finished the command. 
@@ -410,7 +476,7 @@ When combining taxonomy filters, the higher taxonomy levels take president. For
    
 .. code-block:: bash
 
-   cazy_webscraper --genera Aspergillus --species Aspergillus niger --strains Aspergillus niger ATCC 1015
+   cazy_webscraper --genera Aspergillus --species "Aspergillus niger" --strains "Aspergillus niger ATCC 1015"
 
 will not retrieve all CAZymes from all Aspergillus species once AND all CAZymes from Aspergillus niger strains as well. 
 ``cazy_webscraper`` will retrieval all CAZymes for all strains of *Aspergillus niger*.
@@ -423,7 +489,7 @@ By default ``cazy_webscraper`` only retrieves the CAZy family annotation for eac
 retrieve the CAZy subfamily annotation. For example, a CAZyme within the CAZy subfamily GH3_1, will be 
 stored in the local CAZyme database as only a GH3 CAZyme.
 
-To retrieve the CAZy family **and** CAZy subfamily annotations, add the ``-subfamilies``/``-s`` flag, anywhere in the 
+To retrieve the CAZy family **and** CAZy subfamily annotations, add the ``-subfamilies`` / ``-s`` flag, anywhere in the 
 ``cazy_webscraper`` command. For example:
 
 .. code-block:: bash
@@ -462,7 +528,7 @@ To retrieve CAZymes from all viral species, and all Aspergillus niger strains wh
 
 .. code-block:: bash
 
-   cazy_webscraper --families GH3_1,GH3_2 --subfamilies --species Aspergillus niger --kingdoms Bacteria
+   cazy_webscraper --families GH3_1,GH3_2 --subfamilies --species "Aspergillus niger" --kingdoms Bacteria
 
 ------------------
 Configuration file
@@ -608,13 +674,16 @@ allow you to add notes to your configuration file. For example:
    ECs:  # only CAZymes with at least one of these EC numbers will be scrapped
 
 
+Example configuration files and tempate files can be found `hre <https://github.com/HobnobMancer/cazy_webscraper/tree/master/configuration_files>`_.
+
+
 ^^^^^^^^^^^^^^^^^^^^^^^^^^
 Using a configuration file
 ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Once you have created a configuration file (we recommend modifying the template one provided with ``cazy_webscraper`` 
 you then need to invoke ``cazy_webscraper`` and tell it you are using a configuration file. To do this we add the 
-``--config``/``-c`` flag to the ``cazy_webscraper`` command, followed by the path to the configuration file.
+``--config`` / ``-c`` flag to the ``cazy_webscraper`` command, followed by the path to the configuration file.
 
 The path we pass to ``cazy_webscraper`` is a *relative* path. This means ``cazy_webscraper`` will start in the directory 
 the terminal is currently pointed out, and follow the path from there. For example, if we used the command:
@@ -654,36 +723,6 @@ To use a configuration file and a the command-line to configure ``cazy_webscrape
 Additional operations to fine tune how ``cazy_webscraper`` operates
 -------------------------------------------------------------------
 
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Add the scraped data to an existing CAZyme database
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-You may wish to scrape CAZy in multiple stages; maybe your internet dropped out while scraping CAZy 
-and you don't want to start again, or maybe you scraped CAZy but missed out a species of interest. No matter 
-the reason ``cazy_webscraper`` allows you to add more CAZyme data to an existing database previously created by 
-``cazy_webscraper``.
-
-To do this add the database (``--database`` or ``-d``) flag to the ``cazy_webscraper`` command, followed by the path 
-to the CAZyme database you want to add your scraped CAZy data to. For example, to add data to an existing 
-database in ``cazy/cazyme_db.db`` use the command:
-
-.. code-block:: bash
-
-   cazy_webscraper -- database cazy/cazyme_db.db
-
-.. note::
-   Don't forget the .db file extension at the end of the path!
-
-All the paths we pass to ``cazy_webscraper`` are a *relative* path. This means ``cazy_webscraper`` will start in the directory 
-the terminal is currently pointed out, and follow the path from there. For example, if we used the command:
-
-.. code-block:: bash
-
-   cazy_webscraper -d my_cazyme_databases/my_cazyme_database.db
-
-Then the computer will look for a directory called ``my_cazyme_databases`` in the directory the terminal is looking at, then within the 
-``my_cazyme_databases`` directory the computer will look for the file ``my_cazyme_database.db``.
-
 
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 Scraping data from a previously downloaded CAZy txt file
@@ -713,7 +752,7 @@ Writing out a log file
 ^^^^^^^^^^^^^^^^^^^^^^
 
 If you want to have a log file of all terminal output produced by ``cazy_webscraper`` then add the log 
-``--log``/``-l`` anywhere to the ``cazy_webscraper`` command, followed by a 
+``--log`` / ``-l`` anywhere to the ``cazy_webscraper`` command, followed by a 
 path to write the log file to. This path is a *relative* path and must include target a log file specifically. 
 For example:
 
diff --git a/docs/uniprot.rst b/docs/uniprot.rst
index 8ee70837..9acff15e 100644
--- a/docs/uniprot.rst
+++ b/docs/uniprot.rst
@@ -53,6 +53,8 @@ to retrieve protein data. Default 150. ``bioservices`` recommends submitting
 
 ``--delete_old_ec`` - Boolean, delete EC number - Protein relationships that are no longer listed in UniProt, i.e. an EC number annotation is no longer included in UniProt but is in the local database. If set to TRUE these relationships will be DELETED from the database.
 
+``--delete_old_pdbs`` - Boolean, delete PDB accessions - Protein relationships that are no longer listed in UniProt, i.e. an PDB accessions that are no longer included in UniProt but is in the local database. If set to TRUE these relationships will be DELETED from the database.
+
 ``--ec``, ``-e`` - Enable retrieval of EC number annotations from UniProt. Default, EC number annotations are **not** retrieved.
 
 ``--ec_filter`` - List of EC numbers to limit the retrieval of protein data for proteins annotated with at least one of the given EC numbers **in the local CAZyme database**.
@@ -65,6 +67,8 @@ to retrieve protein data. Default 150. ``bioservices`` recommends submitting
 
 ``--genera`` - List of genera to restrict the retrieval of protein to data from UniProt to proteins belonging to one of the given genera.
 
+``--kingdoms`` - List of taxonomic kingdoms to restrict the scrape to. Default: None, filter is not applied.
+
 ``--log``, ``-l`` - Target path to write out a log file. If not called, no log file is written. Default: None (no log file is written out).
 
 ``--name_update`` - Boolean, whether to overwrite the existing protein name (previously retrieved from UniProt). Default: do not update.
@@ -127,12 +131,23 @@ local CAZyme database. ``cw_get_uniprot_data`` can also retrieve from UniProt:
 * PDB accessions
 * Protein amino acid sequences
 
+.. WARNING:: 
+    When performing retrievals of large datasets from UniProt, please perform these retrievals during quiet periods (e.g. at the weekend). 
+
+.. WARNING::
+    It is strongly advised to only download data from UniProt for the necessary protein datasets. Retrieval of very large 
+    datasets from UniProt (e.g. for +1,000,000 proteins or all proteins in the GH class) can result in UniProt 
+    terminating the connection early due to a high bandwidth command over an extended period of time.
+
+    To retrieve data from large datasets, it is recommend to break down the dataset into subgroups, and periodically 
+    retrieve the data for one subgroup. This reduces the burdeon on the UniProt server and will not break 
+    the expected use and practises of the UniProt database.
 
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 Retrieving EC number annotations
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-To retrieve EC number annotations from UniProt add the ``--ec``/``-e`` flag to the command:
+To retrieve EC number annotations from UniProt add the ``--ec`` /  ``-e`` flag to the command:
 
 .. code-block:: bash
 
@@ -155,7 +170,7 @@ Retrieving PDB accessions
 ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 To retrieve all PDB accessions for all CAZymes in the local CAZyme database matching the given filter criteria,
-add the ``--pdb``/``-p`` flag to the command:
+add the ``--pdb`` /  ``-p`` flag to the command:
 
 .. code-block:: bash
 
@@ -173,7 +188,7 @@ Retrieving protein sequences
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 To retrieve all protein amino acid sequences for all CAZymes in the local CAZyme database matching the given filter criteria,
-add the ``--sequence``/``-s`` flag to the command:
+add the ``--sequence`` /  ``-s`` flag to the command:
 
 .. code-block:: bash
 
@@ -197,7 +212,7 @@ When using ``--sequence`` flag, ``cw_get_uniprot_data`` will only add *new* prot
 it will only add protein sequences to records that do not have a sequence. Therefore, if a protein
 already has a sequence in the local database, this sequence is **not** overwritten.
 
-You may wish to update the protein sequences in your local CAZyme database. To do this use the ``--sequence``/``-s`` 
+You may wish to update the protein sequences in your local CAZyme database. To do this use the ``--sequence`` /  ``-s`` 
 flag to tell ``cw_get_uniprot_data`` to retrieve protein sequences, **and** use the ``--seq_update`` flag.
 
 .. code-block:: bash
diff --git a/docs/uniprottutorial.rst b/docs/uniprottutorial.rst
index a6d138a7..9d9bebbb 100644
--- a/docs/uniprottutorial.rst
+++ b/docs/uniprottutorial.rst
@@ -3,12 +3,12 @@ Tutorials on configuring ``cazy_webscraper`` to retrieve data from UniProt
 ==========================================================================
 
 ``cazy_webscraper`` can be configured to retrieve user specified data sets from UniProt for specific date 
-sets of CAZymes in a local CAZyme database. Many of the configuration options 
+sets of CAZymes in a local CAZyme database. Many of the same configuration options 
 apply to the retrieval of protein data from CAZy, UniProt, GenBank and PDB.
 
 .. NOTE::
    ``cazy_webscraper`` retrieves protein data from UniProt for CAZymes in a local CAZyme database. It 
-   will not add new proteins to the database.
+   will **not** add new proteins to the database.
 
 ``cazy_webscraper`` can be configured via the **command line** and/or via a **YAML configuration file**.
 
@@ -19,7 +19,7 @@ the retrieval of data from UniProt. These tutorials are designed for those with
   If you installed ``cazy_webscraper`` using ``bioconda`` or ``pip`` to invoke ``cazy_webscraper`` to retrieve UniProt data call it using ``cw_get_uniprot_data`` - this is the method used in this tutorial.  
   If you installed ``cazy_webscraper`` from source then you will need to invoke ``cazy_webscraper`` from the root of the repo using the command ``python3 cazy_webscraper/expand/uniprot/get_uniprot_data.py``.
 
-From this point on, we will be discussed the ``cw_get_uniprot_data``, which is the entry point for 
+From this point on, we will be discusseing the ``cw_get_uniprot_data`` command, which is used by ``cazy_webscraper`` for 
 retrieving data from UniProt. We also presume you are comfortable configuring ``cazy_webscraper`` for the 
 scraping of data from CAZy.
 
@@ -29,8 +29,10 @@ All data retrieved from UniProt by ``cw_get_uniprot_data`` is added to the local
 Configuration via the command line
 ----------------------------------
 
-``cw_get_uniprot_data`` has only one required argument: the path to the local CAZyme database created 
-using ``cazy_webscraper``. Therefore, ``cw_get_uniprot_data`` can be enabled using a simple command structure:
+``cw_get_uniprot_data`` only requires one argument: the path to the local CAZyme database created 
+using ``cazy_webscraper``.
+
+Therefore, ``cw_get_uniprot_data`` can be enabled using a simple command structure:
 
 .. code-block:: bash
 
@@ -42,10 +44,14 @@ For example, if our database was stored in ``cazy/cazyme.db``, we would used:
    
   cazy_webscraper cazy/cazyme.db
 
+.. NOTE::
+   Make sure ``cw_get_uniprot_data`` is pointed directly at the database file.
+
 When no optional arguments are provided, the default behaviour is invoked. The default behaviour is to:
 
 * Retrieve protein data for **all** CAZymes in the local CAZyme db
 * Retrieve UniProt protein accessions and protein names
+* Not retrieve EC number, PDB accessions and protein sequences
 
 -----------------------------------------
 Options configurable at the command line 
@@ -60,7 +66,7 @@ The following behaviours of the ``cw_get_uniprot_data`` can be configured at the
 * Enable updating protein sequences in the local CAZyme database if newer versions are retrieved from UniProt
 * Enable verbose logging during the operation of the webscraper
 
-`Here <https://cazy-webscraper.readthedocs.io/en/latest/configuration_scraper.html>`_ you can find a full list of the command-line flags and options.
+`Here <https://cazy-webscraper.readthedocs.io/en/latest/uniprot.html>`_ you can find a full list of the command-line flags and options.
 
 
 ---------------------------------------------------------------
@@ -243,7 +249,7 @@ To retrieve EC numbers and PDB accessions for all CAZymes in GH and which are de
 
 .. code-block:: bash
 
-   cw_get_uniprot_data cazy/cazyme.db --pdb --classes GH --genera Aspegillus,Trichoderma
+   cw_get_uniprot_data cazy/cazyme.db --pdb --ec --classes GH --genera Aspegillus,Trichoderma
 
 
 **Example 3:**
@@ -252,7 +258,7 @@ EC3.2.1.23, EC3.2.1.37 and EC3.2.1.85, we use the command:
 
 .. code-block:: bash
 
-   cw_get_uniprot_data cazy/cazyme.db --pdb --sequences --classes GH,CE,CBM --kingdoms bacteria --ec_filter "3.2.1.23,3.2.1.37,3.2.1.85"
+   cw_get_uniprot_data cazy/cazyme.db --ec --sequences --classes GH,CE,CBM --kingdoms bacteria --ec_filter "3.2.1.23,3.2.1.37,3.2.1.85"
 
 ------------------------------
 Providing a list of accessions
diff --git a/docs/usage.rst b/docs/usage.rst
index b50c2b0c..cf7bc63e 100644
--- a/docs/usage.rst
+++ b/docs/usage.rst
@@ -53,7 +53,7 @@ to download data from CAZy.
 
 .. NOTE::
   If ``--db_output`` **and** ``--database`` are **not** called,
-  ``cazy_webscraper`` will write out a local CAZyme database to the cwd with the standardised name ``cazy_webscraper_<date>_<time>.db``
+  ``cazy_webscraper`` will writes out a local CAZyme database to the cwd with the standardised name ``cazy_webscraper_<date>_<time>.db``
 
 ``--delete_old_relationships`` - Detele old CAZy family annotations of GenBank accessions. These are CAZy family annotations of a given GenBank accession are in the local database but the accession is not longer associated with those CAZy families, so delete old accession-family relationships.
 
@@ -67,10 +67,15 @@ to download data from CAZy.
 
 ``--genera`` - List of genera to restrict the scrape to. Default: None, filter not applied to scrape.
 
+``--kingdoms`` - List of taxonomic kingdoms to restrict the scrape to. Default: None, filter is not applied.
+
 ``--log``, ``-l`` - Target path to write out a log file. If not called, no log file is written. Default: None (no log file is written out).
 
 ``--nodelete``, ``-n`` - When called, content in the existing output dir will **not** be deleted. Default: False (existing content is deleted).
 
+.. NOTE::
+    When the ``--db_output`` flag is used, ``cazy_webscraper`` will create any necessary parent directories. If the direct/immediate parent directory of the database exists, by default ``cazy_webscraper`` will delete the content in this parent directory.
+
 ``--nodelete_cache`` - When called, content in the existing cache dir will **not** be deleted. Default: False (existing content is deleted).
 
 ``--nodelete_log`` - When called, content in the existing log dir will **not** be deleted. Default: False (existing content is deleted).
@@ -136,7 +141,7 @@ By default ``cazy_webscraper`` writes out a SQL database file to the current wor
 filename with the following structure ``cazy_webscraper_<date>_<time>.db``, where the date and time mark 
 the time ``cazy_webscraper`` was called.
 
-To specify the location of the output database the ``--db_output``/``-o`` option can be used:
+To specify the location of the output database the ``--db_output`` / ``-o`` option can be used:
 
 .. code-block:: bash
 
@@ -145,7 +150,7 @@ To specify the location of the output database the ``--db_output``/``-o`` option
 will write an SQL database file to ``GH169_output.db``.
 
 If the target output file already exists, ``cazy_webscraper`` by default will not overwrite the existing file and will terminate. To 
-overwrite an existing file use the ``--force``/``-f`` options:
+overwrite an existing file use the ``--force`` / ``-f`` options:
 
 .. code-block:: bash
 
@@ -160,20 +165,20 @@ the ``cazy`` and ``families`` directories do not exist, ``cazy_webscraper`` will
   cazy_webscraper --families GH169 -o cazy/families/GH169_output.db 
 
 If any of the output directories exist, by default, ``cazy_webscraper`` will terminate. To write to an existing output 
-directory use the ``--force``/``-f`` options:
+directory use the ``--force`` / ``-f`` options:
 
 .. code-block:: bash
 
   cazy_webscraper --families GH169 -o GH169_output.db -f
 
 By default ``cazy_webscraper`` will delete the existing content in the existing output files. To not delete the content 
-in the existing output directories use the ``--nodelete``/``-n``:
+in the existing output directories use the ``--nodelete`` / ``-n``:
 
 .. code-block:: bash
 
   cazy_webscraper --families GH169 -o GH169_output.db -f -n
 
-If you already have an existing CAZy database, then specifying this database with the ``-d``/``--database`` option will cause the scraper to use the existing database rather than creating a new one:
+If you already have an existing CAZy database, then specifying this database with the ``-d`` / ``--database`` option will cause the scraper to use the existing database rather than creating a new one:
 
 .. code-block:: bash
 
diff --git a/setup.py b/setup.py
index 6ac9cefc..b0be02f5 100644
--- a/setup.py
+++ b/setup.py
@@ -52,7 +52,7 @@
 
 setuptools.setup(
     name="cazy_webscraper",
-    version="2.0.5",
+    version="2.0.6",
     # Metadata
     author="Emma E. M. Hobbs",
     author_email="eemh1@st-andrews.ac.uk",
@@ -88,7 +88,7 @@
         "pandas>=1.0.3",
         "pyyaml",
         "requests",
-        "saintBioutils>=0.0.19",
+        "saintBioutils>=0.0.22",
         "sqlalchemy>=1.4.20",
         "tqdm",
     ],


Test patch:
diff --git a/tests/test_inputs/test_inputs_parse_configuration/config_file.yaml b/tests/test_inputs/test_inputs_parse_configuration/config_file.yaml
index 6964c7ea..8fed23bf 100644
--- a/tests/test_inputs/test_inputs_parse_configuration/config_file.yaml
+++ b/tests/test_inputs/test_inputs_parse_configuration/config_file.yaml
@@ -16,4 +16,9 @@ species:
   - 'Aspergillus niger'
 strains:
   - 'Clostridium botulinum IBCA10-7060'
-  - 'Bacillus endophyticus Hbe603'
\ No newline at end of file
+  - 'Bacillus endophyticus Hbe603'
+kingdoms:
+  - 'Bacteria'
+  - 'unclassified'
+ec:
+  - '5.5.6.4'
\ No newline at end of file
diff --git a/tests/test_parse_config.py b/tests/test_parse_config.py
new file mode 100644
index 00000000..b32da312
--- /dev/null
+++ b/tests/test_parse_config.py
@@ -0,0 +1,253 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+# (c) University of St Andrews 2020-2021
+# (c) University of Strathclyde 2020-2021
+# (c) James Hutton Institute 2020-2021
+#
+# Author:
+# Emma E. M. Hobbs
+#
+# Contact
+# eemh1@st-andrews.ac.uk
+#
+# Emma E. M. Hobbs,
+# Biomolecular Sciences Building,
+# University of St Andrews,
+# North Haugh Campus,
+# St Andrews,
+# KY16 9ST
+# Scotland,
+# UK
+#
+# The MIT License
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+"""Tests the module utilities.parse_configuration which parses the users configuration.
+
+These test are intened to be run from the root of the repository using:
+pytest -v
+"""
+
+from distutils.command.config import config
+from cazy_webscraper.utilities import parse_configuration
+
+
+import pytest
+
+from argparse import Namespace
+
+
+@pytest.fixture
+def config_dict_blank():
+    config_dict = {
+        "classes": set(),
+        "Glycoside Hydrolases (GHs)": set(),
+        "GlycosylTransferases (GTs)": set(),
+        "Polysaccharide Lyases (PLs)": set(),
+        "Carbohydrate Esterases (CEs)": set(),
+        "Auxiliary Activities (AAs)": set(),
+        "Carbohydrate-Binding Modules (CBMs)": set(),
+    }
+    return config_dict
+
+
+@pytest.fixture
+def yaml_path():
+    path_ = "tests/test_inputs/test_inputs_parse_configuration/config_file.yaml"
+    return path_
+
+
+@pytest.fixture
+def tax_dict():
+    tax_dict = {'genera': set(), 'species': set(), 'strains': set()}
+    return tax_dict
+
+
+def test_class_synomymns_error():
+    args_dict = {
+        "args": Namespace(
+            cazy_synonyms ="testtesttest",
+        )
+    }
+
+    with pytest.raises(SystemExit) as pytest_wrapped_e:
+        parse_configuration.get_cazy_class_synonym_dict(args_dict['args'])
+    assert pytest_wrapped_e.type == SystemExit
+
+
+def test_class_synonyms():
+    args_dict = {
+        "args": Namespace(
+            cazy_synonyms="tests/test_inputs/cazy_dictionary.json",
+        )
+    }
+    parse_configuration.get_cazy_class_synonym_dict(args_dict['args'])
+
+
+def test_yaml_config_no_yaml(config_dict_blank, cazy_dictionary, tax_dict):
+    args_dict = {
+        "args": Namespace(
+            config="path",
+        )
+    }
+    
+    with pytest.raises(SystemExit) as pytest_wrapped_e:
+        parse_configuration.get_yaml_configuration(
+            config_dict_blank,
+            cazy_dictionary,
+            tax_dict,
+            set(),
+            args_dict['args'],
+        )
+    assert pytest_wrapped_e.type == SystemExit
+
+
+def test_yaml_config(config_dict_blank, cazy_dictionary, tax_dict, monkeypatch, yaml_path):
+    def mock_get_yaml_classes(*args, **kwards):
+        return ['GH', 'PL']
+    
+    args_dict = {
+        "args": Namespace(
+            config=yaml_path,
+        )
+    }
+    
+    monkeypatch.setattr(parse_configuration, "get_yaml_cazy_classes", mock_get_yaml_classes)
+    
+    parse_configuration.get_yaml_configuration(
+        config_dict_blank,
+        cazy_dictionary,
+        tax_dict,
+        set(),
+        args_dict['args'],
+    )
+
+
+def test_yaml_classes_keyerror(cazy_dictionary):
+    config_dict = {}
+    parse_configuration.get_yaml_cazy_classes(config_dict, cazy_dictionary)
+
+
+def test_yaml_classes_none(cazy_dictionary):
+    config_dict = {'classes': None}
+    parse_configuration.get_yaml_cazy_classes(config_dict, cazy_dictionary)
+
+
+def test_yaml_classes(cazy_dictionary, monkeypatch):
+    def mock_get_classes(*args, **kwards):
+        return ["GH", "PL"]
+
+    config_dict = {'classes': ['PL']}
+
+    monkeypatch.setattr(parse_configuration, "parse_user_cazy_classes", mock_get_classes)
+
+    parse_configuration.get_yaml_cazy_classes(config_dict, cazy_dictionary)
+
+
+def test_parse_classes(cazy_dictionary):
+    parse_configuration.parse_user_cazy_classes(["GH", "Cat", "gh"], cazy_dictionary)
+
+
+def test_parse_cmd_tax(monkeypatch, cazy_dictionary, config_dict_blank):
+
+    def mock_get_classes(*args, **kwards):
+        return ["GH", "PL"]
+
+    def mock_get_fams(*args, **kwards):
+        return config_dict_blank
+
+    args_dict = {
+        "args": Namespace(
+            classes="GH,PL",
+            families="GH1,GT2,PL3,CE19,AA10,CBM4,QQQ444,CBMQQQ",
+            genera="Aspergillus,Trichoderma",
+            species="Aspergillus niger,Genus species",
+            strains="Genus species strain,genus species strain",
+            kingdoms="bacteria,unclassified",
+        )
+    }
+
+    tax_dict = {'genera': set(), 'species': set(), 'strains': set()}
+
+    monkeypatch.setattr(parse_configuration, "parse_user_cazy_classes", mock_get_classes)
+    monkeypatch.setattr(parse_configuration, "get_cmd_defined_families", mock_get_fams)
+
+    parse_configuration.get_cmd_scrape_config(config_dict_blank, cazy_dictionary, tax_dict, set(), args_dict["args"])
+
+
+def test_parse_cmd_fams(config_dict_blank):
+    args_dict = {
+        "args": Namespace(
+            families="GH1,GT2,PL3,CE19,AA10,CBM4,QQQ444,CBMQQQ"
+        )
+    }
+
+    parse_configuration.get_cmd_defined_families(config_dict_blank, args_dict["args"])
+
+
+def test_excluded_classes(cazy_dictionary):
+    config_dict = {
+        "classes": set(),
+        "Glycoside Hydrolases (GHs)": ["GH1", "GH2"],
+    }
+
+    parse_configuration.get_excluded_classes(config_dict, cazy_dictionary)
+
+
+def test_excluded_classes_none(cazy_dictionary):
+    config_dict = cazy_dictionary
+    config_dict["classes"] = set()
+
+    parse_configuration.get_excluded_classes(config_dict, cazy_dictionary)
+
+
+def test_convert_empty():
+    tax_dict = {'genera': {'Aspergillus', 'Trichoderma'}, 'species': set()}
+
+    parse_configuration.convert_empty_sets_to_none(tax_dict)
+
+
+def test_get_filter_set():
+    tax_dict = {'genera': {'Aspergillus', 'Trichoderma'}, 'species': None}
+
+    parse_configuration.get_filter_set(tax_dict)
+
+
+def test_ec_filters(yaml_path):
+    args_dict = {
+        "args": Namespace(
+            config=yaml_path,
+        )
+    }
+    ec_filters = "EC3.2.1.3,1.-.-.-,ec10.0.1.*"
+    parse_configuration.get_ec_config(ec_filters, args_dict['args'])
+
+
+def test_ec_err():
+    args_dict = {
+        "args": Namespace(
+            config="path",
+        )
+    }
+    ec_filters = "EC3.2.1.3,1.-.-.-,ec10.0.1.*"
+
+    with pytest.raises(SystemExit) as pytest_wrapped_e:
+        parse_configuration.get_ec_config(ec_filters, args_dict['args'])
+    assert pytest_wrapped_e.type == SystemExit
+    
\ No newline at end of file
diff --git a/tests/test_parsers.py b/tests/test_parsers.py
new file mode 100644
index 00000000..c3c47235
--- /dev/null
+++ b/tests/test_parsers.py
@@ -0,0 +1,157 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+# (c) University of St Andrews 2020-2021
+# (c) University of Strathclyde 2020-2021
+# (c) James Hutton Institute 2020-2021
+#
+# Author:
+# Emma E. M. Hobbs
+#
+# Contact
+# eemh1@st-andrews.ac.uk
+#
+# Emma E. M. Hobbs,
+# Biomolecular Sciences Building,
+# University of St Andrews,
+# North Haugh Campus,
+# St Andrews,
+# KY16 9ST
+# Scotland,
+# UK
+#
+# The MIT License
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+"""Tests the module utilities which builds the args parser.
+
+These test are intened to be run from the root of the repository using:
+pytest -v
+"""
+
+
+import pytest
+
+from argparse import Namespace
+
+from cazy_webscraper.utilities.parsers import (
+    api_parser,
+    cazy_webscraper_parser,
+    extract_seq_parser,
+    gbk_seq_parser,
+    genbank_cov_parser,
+    pdb_strctre_parser,
+    uniprot_parser,
+)
+
+
+@pytest.fixture
+def args_v_false():
+    args_dict = {
+        "args": Namespace(
+            verbose=False,
+            log=None,
+        )
+    }
+    return args_dict
+
+
+@pytest.fixture
+def args_v_true():
+    args_dict = {
+        "args": Namespace(
+            verbose=True,
+            log="tests/test_outputs/test_log",
+        )
+    }
+    return args_dict
+
+
+# test building the parser
+
+
+# test cazy_webscraper parser
+
+def test_parser_cw():
+    """Test building the parser when argsv is None"""
+    cazy_webscraper_parser.build_parser()
+
+
+def test_parser_cw_arsv():
+    """Test building the parser when argsv is not None"""
+    cazy_webscraper_parser.build_parser(["dummy_email"])
+
+
+def test_parser_extract():
+    """Test building the parser when argsv is None"""
+    extract_seq_parser.build_parser()
+
+
+def test_parser_arsv_extract():
+    """Test building the parser when argsv is not None"""
+    extract_seq_parser.build_parser(["dummy_email", "genbank", "uniprot"])
+
+
+def test_parser_api():
+    """Test building the parser when argsv is None"""
+    api_parser.build_parser()
+
+
+def test_parser_arsv_api():
+    """Test building the parser when argsv is not None"""
+    api_parser.build_parser(["db", "csv"])
+
+
+def test_parser_gbk():
+    """Test building the parser when argsv is None"""
+    gbk_seq_parser.build_parser()
+
+
+def test_parser_arsv_gbk():
+    """Test building the parser when argsv is not None"""
+    gbk_seq_parser.build_parser(["db", "dummy_email"])
+
+
+def test_parser_pdb():
+    """Test building the parser when argsv is None"""
+    pdb_strctre_parser.build_parser()
+
+
+def test_parser_arsv_pdb():
+    """Test building the parser when argsv is not None"""
+    pdb_strctre_parser.build_parser(["dummy_email", "pdb"])
+
+
+def test_parser_uniprot():
+    """Test building the parser when argsv is None"""
+    uniprot_parser.build_parser()
+
+
+def test_parser_arsv_uniprot():
+    """Test building the parser when argsv is not None"""
+    uniprot_parser.build_parser(["dummy_email"])
+
+
+def test_parser_cov():
+    """Test building the parser when argsv is None"""
+    genbank_cov_parser.build_parser()
+
+
+def test_parser_arsv_cov():
+    """Test building the parser when argsv is not None"""
+    genbank_cov_parser.build_parser(["db", "dummy_email"])
diff --git a/tests/test_uniprot.py b/tests/test_uniprot.py
index 6aa905e6..ec4c248f 100644
--- a/tests/test_uniprot.py
+++ b/tests/test_uniprot.py
@@ -52,6 +52,7 @@
 
 from saintBioutils import uniprot
 from saintBioutils.utilities import file_io
+from saintBioutils.utilities import logger as saint_logger
 
 import cazy_webscraper
 
@@ -116,6 +117,8 @@ def mock_parser(*args, **kwargs):
             uniprot_data=None,
             verbose=False,
             pdb=True,
+            skip_uniprot_accessions=None,
+            use_uniprot_cache=None,
         )
         return parser
 
@@ -136,7 +139,7 @@ def mock_get_uniprot_data(*args, **kwards):
 
     monkeypatch.setattr(uniprot_parser, "build_parser", mock_building_parser)
     monkeypatch.setattr(ArgumentParser, "parse_args", mock_parser)
-    monkeypatch.setattr(utilities, "config_logger", mock_return_logger)
+    monkeypatch.setattr(saint_logger, "config_logger", mock_return_logger)
     monkeypatch.setattr(get_uniprot_data, "connect_existing_db", mock_connect_existing_db)
     monkeypatch.setattr("cazy_webscraper.expand.uniprot.get_uniprot_data.make_output_directory", mock_return_none)
     monkeypatch.setattr(get_uniprot_data, "get_expansion_configuration", mock_get_expansion_configuration)
diff --git a/tests/test_utilities.py b/tests/test_utilities.py
index 0c7fd4eb..1bc8c75c 100644
--- a/tests/test_utilities.py
+++ b/tests/test_utilities.py
@@ -1,171 +1,55 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-# (c) University of St Andrews 2020-2021
-# (c) University of Strathclyde 2020-2021
-# (c) James Hutton Institute 2020-2021
-#
-# Author:
-# Emma E. M. Hobbs
-#
-# Contact
-# eemh1@st-andrews.ac.uk
-#
-# Emma E. M. Hobbs,
-# Biomolecular Sciences Building,
-# University of St Andrews,
-# North Haugh Campus,
-# St Andrews,
-# KY16 9ST
-# Scotland,
-# UK
-#
-# The MIT License
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-"""Tests the module utilities which builds the logger and args parser.
-
-These test are intened to be run from the root of the repository using:
-pytest -v
-"""
-
-
-import pytest
-
-from argparse import Namespace
-
-from cazy_webscraper.utilities import config_logger, parsers
-from cazy_webscraper.utilities.parsers import (
-    api_parser,
-    cazy_webscraper_parser,
-    extract_seq_parser,
-    gbk_seq_parser,
-    genbank_cov_parser,
-    pdb_strctre_parser,
-    uniprot_parser,
-)
-
-
-@pytest.fixture
-def args_v_false():
-    args_dict = {
-        "args": Namespace(
-            verbose=False,
-            log=None,
-        )
-    }
-    return args_dict
-
-
-@pytest.fixture
-def args_v_true():
-    args_dict = {
-        "args": Namespace(
-            verbose=True,
-            log="tests/test_outputs/test_log",
-        )
-    }
-    return args_dict
-
-
-# test building the parser
-
-
-# test building the logger
-
-
-def test_verbose_false(args_v_false):
-    """Test build_logger when args.verbose and args.log are false"""
-    config_logger(args_v_false["args"])
-
-
-def test_verbose_true(args_v_true):
-    """Test build_logger when args.verbose and args.log are true"""
-    config_logger(args_v_true["args"])
-
-
-# test cazy_webscraper parser
-
-def test_parser_cw():
-    """Test building the parser when argsv is None"""
-    cazy_webscraper_parser.build_parser()
-
-
-def test_parser_cw_arsv():
-    """Test building the parser when argsv is not None"""
-    cazy_webscraper_parser.build_parser(["dummy_email"])
-
-
-def test_parser_extract():
-    """Test building the parser when argsv is None"""
-    extract_seq_parser.build_parser()
-
-
-def test_parser_arsv_extract():
-    """Test building the parser when argsv is not None"""
-    extract_seq_parser.build_parser(["dummy_email", "genbank", "uniprot"])
-
-
-def test_parser_api():
-    """Test building the parser when argsv is None"""
-    api_parser.build_parser()
-
-
-def test_parser_arsv_api():
-    """Test building the parser when argsv is not None"""
-    api_parser.build_parser(["db", "csv"])
-
-
-def test_parser_gbk():
-    """Test building the parser when argsv is None"""
-    gbk_seq_parser.build_parser()
-
-
-def test_parser_arsv_gbk():
-    """Test building the parser when argsv is not None"""
-    gbk_seq_parser.build_parser(["db", "dummy_email"])
-
-
-def test_parser_pdb():
-    """Test building the parser when argsv is None"""
-    pdb_strctre_parser.build_parser()
-
-
-def test_parser_arsv_pdb():
-    """Test building the parser when argsv is not None"""
-    pdb_strctre_parser.build_parser(["dummy_email", "pdb"])
-
-
-def test_parser_uniprot():
-    """Test building the parser when argsv is None"""
-    uniprot_parser.build_parser()
-
-
-def test_parser_arsv_uniprot():
-    """Test building the parser when argsv is not None"""
-    uniprot_parser.build_parser(["dummy_email"])
-
-
-def test_parser_cov():
-    """Test building the parser when argsv is None"""
-    genbank_cov_parser.build_parser()
-
-
-def test_parser_arsv_cov():
-    """Test building the parser when argsv is not None"""
-    genbank_cov_parser.build_parser(["db", "dummy_email"])
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+# (c) University of St Andrews 2020-2021
+# (c) University of Strathclyde 2020-2021
+# (c) James Hutton Institute 2020-2021
+#
+# Author:
+# Emma E. M. Hobbs
+#
+# Contact
+# eemh1@st-andrews.ac.uk
+#
+# Emma E. M. Hobbs,
+# Biomolecular Sciences Building,
+# University of St Andrews,
+# North Haugh Campus,
+# St Andrews,
+# KY16 9ST
+# Scotland,
+# UK
+#
+# The MIT License
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+"""Tests the module utilities which creates terminal colours.
+
+These test are intened to be run from the root of the repository using:
+pytest -v
+"""
+
+
+import pytest
+
+from cazy_webscraper.utilities import termcolour
+
+
+def test_termcolour():
+    """Test the terminal coloput func"""
+    termcolour("message", "red", bold=True)
diff --git a/tests/test_webscraper.py b/tests/test_webscraper.py
index 5f1e1e21..e6854bb0 100644
--- a/tests/test_webscraper.py
+++ b/tests/test_webscraper.py
@@ -50,6 +50,7 @@
 
 from cazy_webscraper import cazy
 from cazy_webscraper.utilities.parse_configuration.cazy_class_synonym_dict import cazy_synonym_dict
+from saintBioutils.utilities import logger as saint_logger
 import pytest
 import sys
 
@@ -81,7 +82,7 @@ def mock_building_parser(*args, **kwargs):
 
 @pytest.fixture
 def mock_parser(*args, **kwargs):
-    parser = Namespace(
+    parser = {"args": Namespace(
         config=None,
         classes=None,
         database="fake_database_path",
@@ -102,7 +103,7 @@ def mock_parser(*args, **kwargs):
         streamline=None,
         timeout=45,
         verbose=False,
-    )
+    )}
     return parser
 
 
@@ -236,7 +237,7 @@ def mock_parser(*args, **kwargs):
 
     monkeypatch.setattr(cazy_webscraper_parser, "build_parser", mock_building_parser)
     monkeypatch.setattr(ArgumentParser, "parse_args", mock_parser)
-    monkeypatch.setattr(utilities, "config_logger", mock_config_logger)
+    monkeypatch.setattr(saint_logger, "config_logger", mock_config_logger)
 
     cazy_scraper.main()
 
@@ -278,7 +279,7 @@ def mock_parser(*args, **kwargs):
 
     monkeypatch.setattr(cazy_webscraper_parser, "build_parser", mock_building_parser)
     monkeypatch.setattr(ArgumentParser, "parse_args", mock_parser)
-    monkeypatch.setattr(utilities, "config_logger", mock_config_logger)
+    monkeypatch.setattr(saint_logger,  "config_logger", mock_config_logger)
 
     cazy_scraper.main()
 
@@ -320,7 +321,7 @@ def mock_parser(*args, **kwargs):
 
     monkeypatch.setattr(cazy_webscraper_parser, "build_parser", mock_building_parser)
     monkeypatch.setattr(ArgumentParser, "parse_args", mock_parser)
-    monkeypatch.setattr(utilities, "config_logger", mock_config_logger)
+    monkeypatch.setattr(saint_logger,  "config_logger", mock_config_logger)
 
     cazy_scraper.main()
 
@@ -362,7 +363,7 @@ def mock_parser(*args, **kwargs):
 
     monkeypatch.setattr(cazy_webscraper_parser, "build_parser", mock_building_parser)
     monkeypatch.setattr(ArgumentParser, "parse_args", mock_parser)
-    monkeypatch.setattr(utilities, "config_logger", mock_config_logger)
+    monkeypatch.setattr(saint_logger,  "config_logger", mock_config_logger)
 
     cazy_scraper.main()
 
@@ -414,7 +415,7 @@ def mock_connect_db(*args, **kwargs):
     
     monkeypatch.setattr(cazy_webscraper_parser, "build_parser", mock_building_parser)
     monkeypatch.setattr(ArgumentParser, "parse_args", mock_parser)
-    monkeypatch.setattr(utilities, "config_logger", mock_config_logger)
+    monkeypatch.setattr(saint_logger,  "config_logger", mock_config_logger)
     monkeypatch.setattr(cazy_scraper, "connect_to_new_db", mock_connect_db)
     monkeypatch.setattr(cazy_scraper, "connect_existing_db", mock_connect_db)
     monkeypatch.setattr(cazy_scraper, "make_output_directory", mock_return_none)
@@ -472,7 +473,7 @@ def mock_connect_db(*args, **kwargs):
 
     monkeypatch.setattr(cazy_webscraper_parser, "build_parser", mock_building_parser)
     monkeypatch.setattr(ArgumentParser, "parse_args", mock_parser)
-    monkeypatch.setattr(utilities, "config_logger", mock_config_logger)
+    monkeypatch.setattr(saint_logger,  "config_logger", mock_config_logger)
     monkeypatch.setattr(cazy_scraper, "connect_to_new_db", mock_connect_db)
     monkeypatch.setattr(cazy_scraper, "connect_existing_db", mock_connect_db)
     monkeypatch.setattr(cazy_scraper, "make_output_directory", mock_return_none)
@@ -508,7 +509,7 @@ def mock_parser(*args, **kwargs):
             families=None,
             genera=None,
             kingdoms=None,
-            log='log_dir',
+            log=Path('log_dir'),
             nodelete=False,
             nodelete_cache=False,
             nodelete_log=False,
@@ -548,7 +549,7 @@ def mock_return_none(*args, **kwargs):
 
     monkeypatch.setattr(cazy_webscraper_parser, "build_parser", mock_building_parser)
     monkeypatch.setattr(ArgumentParser, "parse_args", mock_parser)
-    monkeypatch.setattr(utilities, "config_logger", mock_config_logger)
+    monkeypatch.setattr(saint_logger,  "config_logger", mock_config_logger)
     monkeypatch.setattr(parse_configuration, "parse_configuration", mock_parse_config)
     monkeypatch.setattr(cazy_scraper, "connect_existing_db", mock_connect_existing_db)
     monkeypatch.setattr(sql.sql_interface, "log_scrape_in_db", mock_return_none)
@@ -623,7 +624,7 @@ def mock_connect_db(*args, **kwargs):
 
     monkeypatch.setattr(cazy_webscraper_parser, "build_parser", mock_building_parser)
     monkeypatch.setattr(ArgumentParser, "parse_args", mock_parser)
-    monkeypatch.setattr(utilities, "config_logger", mock_config_logger)
+    monkeypatch.setattr(saint_logger,  "config_logger", mock_config_logger)
     monkeypatch.setattr(parse_configuration, "parse_configuration", mock_parse_config)
     monkeypatch.setattr(cazy_scraper, "connect_to_new_db", mock_connect_db)
     monkeypatch.setattr(cazy_scraper, "connect_existing_db", mock_connect_db)