From 8ec2dd0d11e4b28a6046e31e5947f15f4582b6c7 Mon Sep 17 00:00:00 2001 From: Adam Talbot Date: Wed, 7 Jun 2023 12:03:03 +0100 Subject: [PATCH 01/34] fix: file collision when using cellranger --- CHANGELOG.md | 4 ++++ modules/local/mtx_to_seurat.nf | 6 +++--- subworkflows/local/mtx_conversion.nf | 8 ++++++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 113692a9..2da23fa2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## dev + +- Fixed issue with file collisions while using cellranger + ## v2.3.1 - 2023-06-02 Yellow Strontium Pinscher - Add `public_aws_ecr` config for using the AWS mirror of containers where possible ([#225](https://github.com/nf-core/scrnaseq/pull/225)) diff --git a/modules/local/mtx_to_seurat.nf b/modules/local/mtx_to_seurat.nf index b55008bb..6b8c293f 100644 --- a/modules/local/mtx_to_seurat.nf +++ b/modules/local/mtx_to_seurat.nf @@ -20,9 +20,9 @@ process MTX_TO_SEURAT { script: def aligner = params.aligner if (params.aligner == "cellranger") { - matrix = "filtered_feature_bc_matrix/matrix.mtx.gz" - barcodes = "filtered_feature_bc_matrix/barcodes.tsv.gz" - features = "filtered_feature_bc_matrix/features.tsv.gz" + matrix = "matrix.mtx.gz" + barcodes = "barcodes.tsv.gz" + features = "features.tsv.gz" } else if (params.aligner == "kallisto") { matrix = "*count/counts_unfiltered/*.mtx" barcodes = "*count/counts_unfiltered/*.barcodes.txt" diff --git a/subworkflows/local/mtx_conversion.nf b/subworkflows/local/mtx_conversion.nf index 10b29b07..5286a1b5 100644 --- a/subworkflows/local/mtx_conversion.nf +++ b/subworkflows/local/mtx_conversion.nf @@ -14,6 +14,14 @@ workflow MTX_CONVERSION { main: ch_versions = Channel.empty() + // Cellranger module output contains too many files which cause path collisions, we filter to the ones we need. + if ( params.aligner == "cellranger" ) { + mtx_matrices = mtx_matrices.map { meta, mtx_files -> + [ meta, mtx_files.findAll { it.toString().contains("filtered_feature_bc_matrix") } ] + } + .filter { meta, mtx_files -> mtx_files } // Remove any that are missing the relevant files + } + // // Convert matrix to h5ad // From 24c59a77078d3ad6e7e6ff332140f02f0e8eb71b Mon Sep 17 00:00:00 2001 From: Adam Talbot Date: Wed, 7 Jun 2023 12:05:38 +0100 Subject: [PATCH 02/34] Add cellranger to continuous tests --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ce37d142..218ed59a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,7 @@ jobs: "test,docker --aligner alevin", "test,docker --aligner kallisto", "test,docker --aligner star", - "test,docker --aligner cellranger -stub", + "test,docker --aligner cellranger", "test,docker --aligner universc -stub", ] steps: From d1614ffd5a62be5719f44ae1aa05ddafb79cdee4 Mon Sep 17 00:00:00 2001 From: Harshil Patel Date: Thu, 8 Jun 2023 12:22:37 +0100 Subject: [PATCH 03/34] Add singularity.registry = 'quay.io' and bump NF version to 23.04.0 --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- .github/workflows/ci.yml | 2 +- README.md | 2 +- nextflow.config | 9 +++++---- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 85665d42..bbbae0c1 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -42,7 +42,7 @@ body: attributes: label: System information description: | - * Nextflow version _(eg. 22.10.1)_ + * Nextflow version _(eg. 23.04.0)_ * Hardware _(eg. HPC, Desktop, Cloud)_ * Executor _(eg. slurm, local, awsbatch)_ * Container engine: _(e.g. Docker, Singularity, Conda, Podman, Shifter, Charliecloud, or Apptainer)_ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ce37d142..875d1b83 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: strategy: matrix: NXF_VER: - - "22.10.1" + - "23.04.0" - "latest-everything" profile: [ diff --git a/README.md b/README.md index f9f3eb20..306e43dd 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![GitHub Actions Linting Status](https://github.com/nf-core/scrnaseq/workflows/nf-core%20linting/badge.svg)](https://github.com/nf-core/scrnaseq/actions?query=workflow%3A%22nf-core+linting%22) [![AWS CI](https://img.shields.io/badge/CI%20tests-full%20size-FF9900?logo=Amazon%20AWS)](https://nf-co.re/scrnaseq/results) [![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.3568187-1073c8)](https://doi.org/10.5281/zenodo.3568187) -[![Nextflow](https://img.shields.io/badge/nextflow%20DSL2-%E2%89%A522.10.1-23aa62.svg)](https://www.nextflow.io/) +[![Nextflow](https://img.shields.io/badge/nextflow%20DSL2-%E2%89%A523.04.0-23aa62.svg)](https://www.nextflow.io/) [![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/) [![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/) [![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/) diff --git a/nextflow.config b/nextflow.config index 76a0d4a2..e731ad08 100644 --- a/nextflow.config +++ b/nextflow.config @@ -229,8 +229,9 @@ process.shell = ['/bin/bash', '-euo', 'pipefail'] // Set default registry for Docker and Podman independent of -profile // Will not be used unless Docker / Podman are enabled // Set to your registry if you have a mirror of containers -docker.registry = 'quay.io' -podman.registry = 'quay.io' +singularity.registry = 'quay.io' +docker.registry = 'quay.io' +podman.registry = 'quay.io' def trace_timestamp = new java.util.Date().format( 'yyyy-MM-dd_HH-mm-ss') timeline { @@ -256,8 +257,8 @@ manifest { homePage = 'https://github.com/nf-core/scrnaseq' description = """Pipeline for processing 10x Genomics single cell rnaseq data""" mainScript = 'main.nf' - nextflowVersion = '!>=22.10.1' - version = '2.3.2' + nextflowVersion = '!>=23.04.0' + version = '2.4.0dev' doi = '10.5281/zenodo.3568187' } From 00d4fd9a88c5e56ed8ca1b39125872b5d30582df Mon Sep 17 00:00:00 2001 From: Harshil Patel Date: Thu, 8 Jun 2023 12:24:14 +0100 Subject: [PATCH 04/34] Update CHANGELOG --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95cafcd5..73bc18e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unpublished Version / DEV] + +- [#237](https://github.com/nf-core/scrnaseq/pull/237) Add `singularity.registry = 'quay.io'` and bump NF version to 23.04.0 + ## v2.3.2 - 2023-06-07 Patched Yellow Strontium Pinscher - Move containers for pipeline to quay.io ([#233](https://github.com/nf-core/scrnaseq/pull/233)) From 8a22c13deca75e600c4b319115aa0aa3b8be2741 Mon Sep 17 00:00:00 2001 From: Harshil Patel Date: Thu, 8 Jun 2023 12:26:13 +0100 Subject: [PATCH 05/34] Fix nf-core lint --- .nf-core.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.nf-core.yml b/.nf-core.yml index a76e0ec8..738ad918 100644 --- a/.nf-core.yml +++ b/.nf-core.yml @@ -1,3 +1,5 @@ repository_type: pipeline lint: template_strings: False + files_unchanged: + - .github/ISSUE_TEMPLATE/bug_report.yml From dfa6e49d7e5f11ef0a3de507eb0756192909453b Mon Sep 17 00:00:00 2001 From: Adam Talbot Date: Fri, 9 Jun 2023 17:42:53 +0100 Subject: [PATCH 06/34] revert CI test --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 218ed59a..ce37d142 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,7 @@ jobs: "test,docker --aligner alevin", "test,docker --aligner kallisto", "test,docker --aligner star", - "test,docker --aligner cellranger", + "test,docker --aligner cellranger -stub", "test,docker --aligner universc -stub", ] steps: From 3fc366ea68d8777b0de9cb29b0e8303907f55344 Mon Sep 17 00:00:00 2001 From: Adam Talbot Date: Tue, 13 Jun 2023 10:12:25 +0100 Subject: [PATCH 07/34] CHANGELOG --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 08e2089d..91ff6718 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - ## dev - Fixed issue with file collisions while using cellranger From 21666d9421dc1273061fe03e7b798bc1024ffbeb Mon Sep 17 00:00:00 2001 From: Adam Talbot Date: Tue, 13 Jun 2023 10:13:52 +0100 Subject: [PATCH 08/34] set CELLRANGER maxForks = 1 when running on test See if this fixes the CI issue --- .github/workflows/ci.yml | 2 +- conf/test.config | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ce37d142..218ed59a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,7 @@ jobs: "test,docker --aligner alevin", "test,docker --aligner kallisto", "test,docker --aligner star", - "test,docker --aligner cellranger -stub", + "test,docker --aligner cellranger", "test,docker --aligner universc -stub", ] steps: diff --git a/conf/test.config b/conf/test.config index 34111c6c..ad5d5abe 100644 --- a/conf/test.config +++ b/conf/test.config @@ -31,3 +31,9 @@ params { // Ignore `--input` as otherwise the parameter validation will throw an error schema_ignore_params = 'genomes,input_paths,input' } + +process { + withName: '.*:CELLRANGER' { + maxForks = 1 + } +} From faa175121a899dd4acbaab672f21f249a2098cba Mon Sep 17 00:00:00 2001 From: Adam Talbot Date: Tue, 13 Jun 2023 10:15:49 +0100 Subject: [PATCH 09/34] fixup --- conf/test.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/test.config b/conf/test.config index ad5d5abe..322dd7ae 100644 --- a/conf/test.config +++ b/conf/test.config @@ -33,7 +33,7 @@ params { } process { - withName: '.*:CELLRANGER' { + withName: '.*:CELLRANGER_COUNT' { maxForks = 1 } } From a51e4b1ecc3b60d901dd72f0642a5b3c87a52df1 Mon Sep 17 00:00:00 2001 From: Adam Talbot Date: Tue, 13 Jun 2023 10:19:49 +0100 Subject: [PATCH 10/34] Fix issue with multiqc channel trying to access null objects fixes #231 --- CHANGELOG.md | 4 ++++ subworkflows/local/alevin.nf | 5 ++--- workflows/scrnaseq.nf | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95cafcd5..aa554a15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## dev + +- Fix issue where multiqc inputs tried to access objects that did not exist. + ## v2.3.2 - 2023-06-07 Patched Yellow Strontium Pinscher - Move containers for pipeline to quay.io ([#233](https://github.com/nf-core/scrnaseq/pull/233)) diff --git a/subworkflows/local/alevin.nf b/subworkflows/local/alevin.nf index a13e596d..8fc0a983 100644 --- a/subworkflows/local/alevin.nf +++ b/subworkflows/local/alevin.nf @@ -40,8 +40,8 @@ workflow SCRNASEQ_ALEVIN { transcript_tsv = SIMPLEAF_INDEX.out.transcript_tsv.collect() ch_versions = ch_versions.mix(SIMPLEAF_INDEX.out.versions) - if (!txp2gene) { - txp2gene = SIMPLEAF_INDEX.out.transcript_tsv + if (!txp2gene) { + txp2gene = SIMPLEAF_INDEX.out.transcript_tsv } } @@ -69,5 +69,4 @@ workflow SCRNASEQ_ALEVIN { ch_versions alevin_results = SIMPLEAF_QUANT.out.alevin_results alevinqc = ALEVINQC.out.report - for_multiqc = SIMPLEAF_QUANT.out.alevin_results.collect{it[1]}.ifEmpty([]) } diff --git a/workflows/scrnaseq.nf b/workflows/scrnaseq.nf index 30ca6359..93537d3e 100644 --- a/workflows/scrnaseq.nf +++ b/workflows/scrnaseq.nf @@ -158,7 +158,7 @@ workflow SCRNASEQ { ch_fastq ) ch_versions = ch_versions.mix(SCRNASEQ_ALEVIN.out.ch_versions) - ch_multiqc_alevin = SCRNASEQ_ALEVIN.out.for_multiqc + ch_multiqc_alevin = SCRNASEQ_ALEVIN.out.alevin_results ch_mtx_matrices = ch_mtx_matrices.mix(SCRNASEQ_ALEVIN.out.alevin_results) } From db99566cb33f380247e4f44f4b8b6acdd0487167 Mon Sep 17 00:00:00 2001 From: Adam Talbot Date: Tue, 13 Jun 2023 10:27:04 +0100 Subject: [PATCH 11/34] add explicit channel values to handle multiqc inputs --- workflows/scrnaseq.nf | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/workflows/scrnaseq.nf b/workflows/scrnaseq.nf index 93537d3e..70265642 100644 --- a/workflows/scrnaseq.nf +++ b/workflows/scrnaseq.nf @@ -231,13 +231,17 @@ workflow SCRNASEQ { methods_description = WorkflowScrnaseq.methodsDescriptionText(workflow, ch_multiqc_custom_methods_description) ch_methods_description = Channel.value(methods_description) + ch_multiqc_fastqc.dump(tag: 'fastqc', pretty: true) + ch_multiqc_alevin.dump(tag: 'alevin', pretty: true) + ch_multiqc_star.dump(tag: 'star', pretty: true) + ch_multiqc_files = Channel.empty() ch_multiqc_files = ch_multiqc_files.mix(ch_workflow_summary.collectFile(name: 'workflow_summary_mqc.yaml')) ch_multiqc_files = ch_multiqc_files.mix(ch_methods_description.collectFile(name: 'methods_description_mqc.yaml')) ch_multiqc_files = ch_multiqc_files.mix(CUSTOM_DUMPSOFTWAREVERSIONS.out.mqc_yml.collect()) - ch_multiqc_files = ch_multiqc_files.mix(ch_multiqc_fastqc.collect{it[1]}.ifEmpty([])) - ch_multiqc_files = ch_multiqc_files.mix(ch_multiqc_alevin.collect{it[1]}.ifEmpty([])) - ch_multiqc_files = ch_multiqc_files.mix(ch_multiqc_star.collect{it[1]}.ifEmpty([])) + ch_multiqc_files = ch_multiqc_files.mix(ch_multiqc_fastqc.collect{ meta, qcfile -> qcfile }.ifEmpty([])) + ch_multiqc_files = ch_multiqc_files.mix(ch_multiqc_alevin.collect{ meta, qcfile -> qcfile }.ifEmpty([])) + ch_multiqc_files = ch_multiqc_files.mix(ch_multiqc_star.collect{ meta, qcfile -> qcfile }.ifEmpty([])) MULTIQC ( ch_multiqc_files.collect(), From e6ca31c314e4c08210ff250c842eebbe38a2add6 Mon Sep 17 00:00:00 2001 From: Adam Talbot Date: Tue, 13 Jun 2023 10:29:01 +0100 Subject: [PATCH 12/34] CHANGELOG --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa554a15..307d4a8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## dev -- Fix issue where multiqc inputs tried to access objects that did not exist. +- Fix issue where multiqc inputs tried to access objects that did not exist ([#239](https://github.com/nf-core/scrnaseq/pull/239)) ## v2.3.2 - 2023-06-07 Patched Yellow Strontium Pinscher From 02d3c47292c41a015bffec36b1503b1734f81d46 Mon Sep 17 00:00:00 2001 From: Adam Talbot Date: Tue, 13 Jun 2023 14:28:02 +0100 Subject: [PATCH 13/34] Add stub back in because cellranger doesn't work in tests --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 218ed59a..ce37d142 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,7 @@ jobs: "test,docker --aligner alevin", "test,docker --aligner kallisto", "test,docker --aligner star", - "test,docker --aligner cellranger", + "test,docker --aligner cellranger -stub", "test,docker --aligner universc -stub", ] steps: From 6264efa88ed0da9d7628963e4e25f5b3fae9dcf9 Mon Sep 17 00:00:00 2001 From: Maxime U Garcia Date: Wed, 14 Jun 2023 13:25:59 +0200 Subject: [PATCH 14/34] Update public_aws_ecr.config --- conf/public_aws_ecr.config | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/conf/public_aws_ecr.config b/conf/public_aws_ecr.config index 0f4a7163..2f98603a 100644 --- a/conf/public_aws_ecr.config +++ b/conf/public_aws_ecr.config @@ -8,8 +8,9 @@ ---------------------------------------------------------------------------------------- */ -docker.registry = 'public.ecr.aws' -podman.registry = 'public.ecr.aws' +docker.registry = 'public.ecr.aws' +podman.registry = 'public.ecr.aws' +singularity.registry = 'public.ecr.aws' process { withName: 'CELLRANGER_COUNT' { From 0bb02d380db1d514add5d15867166358edb9d3cc Mon Sep 17 00:00:00 2001 From: Adam Talbot <12817534+adamrtalbot@users.noreply.github.com> Date: Mon, 19 Jun 2023 14:02:40 +0000 Subject: [PATCH 15/34] Remove public_aws_ecr profile --- .devcontainer/devcontainer.json | 7 ++++- .github/workflows/awsfulltest.yml | 2 +- .github/workflows/awstest.yml | 2 +- CHANGELOG.md | 1 + conf/public_aws_ecr.config | 52 ------------------------------- nextflow.config | 3 -- 6 files changed, 9 insertions(+), 58 deletions(-) delete mode 100644 conf/public_aws_ecr.config diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index ea27a584..69f83df5 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -21,7 +21,12 @@ }, // Add the IDs of extensions you want installed when the container is created. - "extensions": ["ms-python.python", "ms-python.vscode-pylance", "nf-core.nf-core-extensionpack"] + "extensions": [ + "ms-python.python", + "ms-python.vscode-pylance", + "nf-core.nf-core-extensionpack", + "github.vscode-github-actions" + ] } } } diff --git a/.github/workflows/awsfulltest.yml b/.github/workflows/awsfulltest.yml index a4c9a575..9cff9984 100644 --- a/.github/workflows/awsfulltest.yml +++ b/.github/workflows/awsfulltest.yml @@ -28,7 +28,7 @@ jobs: "outdir": "s3://${{ secrets.AWS_S3_BUCKET }}/scrnaseq/results-${{ github.sha }}/aligner_${{ matrix.aligner }}", "aligner": "${{ matrix.aligner }}" } - profiles: test_full,public_aws_ecr + profiles: test_full - uses: actions/upload-artifact@v3 with: name: Tower debug log file diff --git a/.github/workflows/awstest.yml b/.github/workflows/awstest.yml index e51330ee..f23fa0dd 100644 --- a/.github/workflows/awstest.yml +++ b/.github/workflows/awstest.yml @@ -26,7 +26,7 @@ jobs: "outdir": "s3://${{ secrets.AWS_S3_BUCKET }}/scrnaseq/results-test-${{ github.sha }}/aligner_${{ matrix.aligner }}", "aligner": "${{ matrix.aligner }}" } - profiles: test,public_aws_ecr + profiles: test - uses: actions/upload-artifact@v3 with: name: Tower debug log file diff --git a/CHANGELOG.md b/CHANGELOG.md index 389e513f..dd283ea2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [#237](https://github.com/nf-core/scrnaseq/pull/237) Add `singularity.registry = 'quay.io'` and bump NF version to 23.04.0 - Fixed issue with file collisions while using cellranger ([#232](https://github.com/nf-core/scrnaseq/pull/232)) - Fix issue where multiqc inputs tried to access objects that did not exist ([#239](https://github.com/nf-core/scrnaseq/pull/239)) +- Removed `public_aws_ecr` profile ## v2.3.2 - 2023-06-07 Patched Yellow Strontium Pinscher diff --git a/conf/public_aws_ecr.config b/conf/public_aws_ecr.config deleted file mode 100644 index 2f98603a..00000000 --- a/conf/public_aws_ecr.config +++ /dev/null @@ -1,52 +0,0 @@ -/* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - AWS ECR Config -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Config to set public AWS ECR images wherever possible - This improves speed when running on AWS infrastructure. - Use this as an example template when using your own private registry. ----------------------------------------------------------------------------------------- -*/ - -docker.registry = 'public.ecr.aws' -podman.registry = 'public.ecr.aws' -singularity.registry = 'public.ecr.aws' - -process { - withName: 'CELLRANGER_COUNT' { - container = 'quay.io/nf-core/cellranger:7.1.0' - } - withName: 'CELLRANGER_MKGTF' { - container = 'quay.io/nf-core/cellranger:7.1.0' - } - withName: 'CELLRANGER_MKREF' { - container = 'quay.io/nf-core/cellranger:7.1.0' - } - withName: 'CONCAT_H5AD' { - container = 'quay.io/biocontainers/scanpy:1.7.2--pyhdfd78af_0' - } - withName: 'GENE_MAP' { - container = 'quay.io/biocontainers/python:3.8.3' - } - withName: 'GTF_GENE_FILTER' { - container = 'quay.io/biocontainers/python:3.9--1' - } - withName: 'GUNZIP' { - container = 'quay.io/nf-core/ubuntu:20.04' - } - withName: 'MTX_TO_H5AD' { - container = 'quay.io/biocontainers/scanpy:1.7.2--pyhdfd78af_0' - } - withName: 'MTX_TO_SEURAT' { - container = 'quay.io/nf-core/seurat:4.3.0' - } - withName: 'SAMPLESHEET_CHECK' { - container = 'quay.io/biocontainers/python:3.8.3' - } - withName: 'STAR_GENOMEGENERATE' { - container = 'quay.io/biocontainers/mulled-v2-1fa26d1ce03c295fe2fdcf85831a92fbcbd7e8c2:1df389393721fc66f3fd8778ad938ac711951107-0' - } - withName: 'UNIVERSC' { - container = 'quay.io/nf-core/universc:1.2.5.1' - } -} diff --git a/nextflow.config b/nextflow.config index e731ad08..3367748d 100644 --- a/nextflow.config +++ b/nextflow.config @@ -198,9 +198,6 @@ profiles { executor.cpus = 16 executor.memory = 60.GB } - public_aws_ecr { - includeConfig 'conf/public_aws_ecr.config' - } test { includeConfig 'conf/test.config' } test_full { includeConfig 'conf/test_full.config' } } From a70d065c5376e1284ea9e9405b194b1347496580 Mon Sep 17 00:00:00 2001 From: nf-core-bot Date: Tue, 27 Jun 2023 08:12:15 +0000 Subject: [PATCH 16/34] [automated] Fix linting with Prettier --- .devcontainer/devcontainer.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 69f83df5..c91a6aaf 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -22,11 +22,11 @@ // Add the IDs of extensions you want installed when the container is created. "extensions": [ - "ms-python.python", - "ms-python.vscode-pylance", - "nf-core.nf-core-extensionpack", - "github.vscode-github-actions" - ] + "ms-python.python", + "ms-python.vscode-pylance", + "nf-core.nf-core-extensionpack", + "github.vscode-github-actions" + ] } } } From 58996c48fca4bc3d7e1fbe264994b5dfeba7cb2a Mon Sep 17 00:00:00 2001 From: Adam Talbot Date: Tue, 27 Jun 2023 09:27:28 +0100 Subject: [PATCH 17/34] Reset .devcontainer --- .devcontainer/devcontainer.json | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index c91a6aaf..ea27a584 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -21,12 +21,7 @@ }, // Add the IDs of extensions you want installed when the container is created. - "extensions": [ - "ms-python.python", - "ms-python.vscode-pylance", - "nf-core.nf-core-extensionpack", - "github.vscode-github-actions" - ] + "extensions": ["ms-python.python", "ms-python.vscode-pylance", "nf-core.nf-core-extensionpack"] } } } From 64cb15788040968c80c14041a3eda1f512ef0af6 Mon Sep 17 00:00:00 2001 From: Gregor Sturm Date: Thu, 29 Jun 2023 12:36:25 +0200 Subject: [PATCH 18/34] Add cellranger to multiqc report --- workflows/scrnaseq.nf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/workflows/scrnaseq.nf b/workflows/scrnaseq.nf index 70265642..d4780c32 100644 --- a/workflows/scrnaseq.nf +++ b/workflows/scrnaseq.nf @@ -191,6 +191,9 @@ workflow SCRNASEQ { ch_versions = ch_versions.mix(CELLRANGER_ALIGN.out.ch_versions) ch_mtx_matrices = ch_mtx_matrices.mix(CELLRANGER_ALIGN.out.cellranger_out) ch_star_index = CELLRANGER_ALIGN.out.star_index + ch_multiqc_cellranger = CELLRANGER_ALIGN.out.cellranger_out.map{ + meta, outs -> outs.findAll{ it -> it.name == "web_summary.html"} + } } // Run universc pipeline @@ -242,6 +245,7 @@ workflow SCRNASEQ { ch_multiqc_files = ch_multiqc_files.mix(ch_multiqc_fastqc.collect{ meta, qcfile -> qcfile }.ifEmpty([])) ch_multiqc_files = ch_multiqc_files.mix(ch_multiqc_alevin.collect{ meta, qcfile -> qcfile }.ifEmpty([])) ch_multiqc_files = ch_multiqc_files.mix(ch_multiqc_star.collect{ meta, qcfile -> qcfile }.ifEmpty([])) + ch_multiqc_files = ch_multiqc_files.mix(ch_multiqc_cellranger.collect().ifEmpty([])) MULTIQC ( ch_multiqc_files.collect(), From 97dc9651cc349e449bd9c9dd8279afeea584d924 Mon Sep 17 00:00:00 2001 From: Gregor Sturm Date: Thu, 29 Jun 2023 12:40:07 +0200 Subject: [PATCH 19/34] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd283ea2..8bcb281c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed issue with file collisions while using cellranger ([#232](https://github.com/nf-core/scrnaseq/pull/232)) - Fix issue where multiqc inputs tried to access objects that did not exist ([#239](https://github.com/nf-core/scrnaseq/pull/239)) - Removed `public_aws_ecr` profile +- Include cellranger in MultiQC report ([#244](https://github.com/nf-core/scrnaseq/pull/244)) ## v2.3.2 - 2023-06-07 Patched Yellow Strontium Pinscher From 3555ef8d6e4de0267fd647a8f8fd72984968b729 Mon Sep 17 00:00:00 2001 From: Gregor Sturm Date: Thu, 29 Jun 2023 12:41:57 +0200 Subject: [PATCH 20/34] Initialize with empty channel --- workflows/scrnaseq.nf | 1 + 1 file changed, 1 insertion(+) diff --git a/workflows/scrnaseq.nf b/workflows/scrnaseq.nf index d4780c32..18f6ed9e 100644 --- a/workflows/scrnaseq.nf +++ b/workflows/scrnaseq.nf @@ -79,6 +79,7 @@ ch_transcript_fasta = params.transcript_fasta ? file(params.transcript_fasta): [ ch_txp2gene = params.txp2gene ? file(params.txp2gene) : [] ch_multiqc_alevin = Channel.empty() ch_multiqc_star = Channel.empty() +ch_multiqc_cellranger = Channel.empty() if (params.barcode_whitelist) { ch_barcode_whitelist = file(params.barcode_whitelist) } else if (params.protocol.contains("10X")) { From bba52df611e958b39ba4abdfab70a3a6dfb3ed23 Mon Sep 17 00:00:00 2001 From: nf-core-bot Date: Fri, 30 Jun 2023 16:15:44 +0000 Subject: [PATCH 21/34] Template update for nf-core/tools version 2.9 --- .github/CONTRIBUTING.md | 1 - .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- .github/workflows/awsfulltest.yml | 11 +- .github/workflows/awstest.yml | 10 +- .github/workflows/ci.yml | 2 +- .gitpod.yml | 5 + CHANGELOG.md | 2 +- CITATIONS.md | 6 + README.md | 6 +- assets/methods_description_template.yml | 12 +- assets/multiqc_config.yml | 4 +- assets/nf-core-scrnaseq_logo_light.png | Bin 11729 -> 75757 bytes assets/slackreport.json | 2 +- conf/test_full.config | 2 - docs/usage.md | 6 +- lib/NfcoreSchema.groovy | 530 ------------------------ lib/NfcoreTemplate.groovy | 2 +- lib/WorkflowMain.groovy | 37 -- lib/WorkflowScrnaseq.groovy | 45 +- main.nf | 16 + nextflow.config | 54 ++- nextflow_schema.json | 36 +- workflows/scrnaseq.nf | 25 +- 23 files changed, 177 insertions(+), 639 deletions(-) delete mode 100755 lib/NfcoreSchema.groovy diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index a90769de..a7783031 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -116,4 +116,3 @@ To get started: Devcontainer specs: - [DevContainer config](.devcontainer/devcontainer.json) -- [Dockerfile](.devcontainer/Dockerfile) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 85665d42..bbbae0c1 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -42,7 +42,7 @@ body: attributes: label: System information description: | - * Nextflow version _(eg. 22.10.1)_ + * Nextflow version _(eg. 23.04.0)_ * Hardware _(eg. HPC, Desktop, Cloud)_ * Executor _(eg. slurm, local, awsbatch)_ * Container engine: _(e.g. Docker, Singularity, Conda, Podman, Shifter, Charliecloud, or Apptainer)_ diff --git a/.github/workflows/awsfulltest.yml b/.github/workflows/awsfulltest.yml index b845e0d2..65b078e4 100644 --- a/.github/workflows/awsfulltest.yml +++ b/.github/workflows/awsfulltest.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Launch workflow via tower - uses: seqeralabs/action-tower-launch@v1 + uses: seqeralabs/action-tower-launch@v2 # TODO nf-core: You can customise AWS full pipeline tests as required # Add full size test data (but still relatively small datasets for few samples) # on the `test_full.config` test runs with only one set of parameters @@ -22,13 +22,18 @@ jobs: workspace_id: ${{ secrets.TOWER_WORKSPACE_ID }} access_token: ${{ secrets.TOWER_ACCESS_TOKEN }} compute_env: ${{ secrets.TOWER_COMPUTE_ENV }} + revision: ${{ github.sha }} workdir: s3://${{ secrets.AWS_S3_BUCKET }}/work/scrnaseq/work-${{ github.sha }} parameters: | { + "hook_url": "${{ secrets.MEGATESTS_ALERTS_SLACK_HOOK_URL }}", "outdir": "s3://${{ secrets.AWS_S3_BUCKET }}/scrnaseq/results-${{ github.sha }}" } - profiles: test_full,aws_tower + profiles: test_full + - uses: actions/upload-artifact@v3 with: name: Tower debug log file - path: tower_action_*.log + path: | + tower_action_*.log + tower_action_*.json diff --git a/.github/workflows/awstest.yml b/.github/workflows/awstest.yml index f7d0fad7..060785d7 100644 --- a/.github/workflows/awstest.yml +++ b/.github/workflows/awstest.yml @@ -12,18 +12,22 @@ jobs: steps: # Launch workflow using Tower CLI tool action - name: Launch workflow via tower - uses: seqeralabs/action-tower-launch@v1 + uses: seqeralabs/action-tower-launch@v2 with: workspace_id: ${{ secrets.TOWER_WORKSPACE_ID }} access_token: ${{ secrets.TOWER_ACCESS_TOKEN }} compute_env: ${{ secrets.TOWER_COMPUTE_ENV }} + revision: ${{ github.sha }} workdir: s3://${{ secrets.AWS_S3_BUCKET }}/work/scrnaseq/work-${{ github.sha }} parameters: | { "outdir": "s3://${{ secrets.AWS_S3_BUCKET }}/scrnaseq/results-test-${{ github.sha }}" } - profiles: test,aws_tower + profiles: test + - uses: actions/upload-artifact@v3 with: name: Tower debug log file - path: tower_action_*.log + path: | + tower_action_*.log + tower_action_*.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aac0ff56..d466269a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: strategy: matrix: NXF_VER: - - "22.10.1" + - "23.04.0" - "latest-everything" steps: - name: Check out pipeline code diff --git a/.gitpod.yml b/.gitpod.yml index 85d95ecc..25488dcc 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -1,4 +1,9 @@ image: nfcore/gitpod:latest +tasks: + - name: Update Nextflow and setup pre-commit + command: | + pre-commit install --install-hooks + nextflow self-update vscode: extensions: # based on nf-core.nf-core-extensionpack diff --git a/CHANGELOG.md b/CHANGELOG.md index 75b89d16..49a9920c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## v2.3.0dev - [date] +## v2.4.0dev - [date] Initial release of nf-core/scrnaseq, created with the [nf-core](https://nf-co.re/) template. diff --git a/CITATIONS.md b/CITATIONS.md index 07609f49..298fec73 100644 --- a/CITATIONS.md +++ b/CITATIONS.md @@ -12,7 +12,10 @@ - [FastQC](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/) + > Andrews, S. (2010). FastQC: A Quality Control Tool for High Throughput Sequence Data [Online]. Available online https://www.bioinformatics.babraham.ac.uk/projects/fastqc/. + - [MultiQC](https://pubmed.ncbi.nlm.nih.gov/27312411/) + > Ewels P, Magnusson M, Lundin S, Käller M. MultiQC: summarize analysis results for multiple tools and samples in a single report. Bioinformatics. 2016 Oct 1;32(19):3047-8. doi: 10.1093/bioinformatics/btw354. Epub 2016 Jun 16. PubMed PMID: 27312411; PubMed Central PMCID: PMC5039924. ## Software packaging/containerisation tools @@ -31,5 +34,8 @@ - [Docker](https://dl.acm.org/doi/10.5555/2600239.2600241) + > Merkel, D. (2014). Docker: lightweight linux containers for consistent development and deployment. Linux Journal, 2014(239), 2. doi: 10.5555/2600239.2600241. + - [Singularity](https://pubmed.ncbi.nlm.nih.gov/28494014/) + > Kurtzer GM, Sochat V, Bauer MW. Singularity: Scientific containers for mobility of compute. PLoS One. 2017 May 11;12(5):e0177459. doi: 10.1371/journal.pone.0177459. eCollection 2017. PubMed PMID: 28494014; PubMed Central PMCID: PMC5426675. diff --git a/README.md b/README.md index 8bbb6fe5..5e620efc 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![AWS CI](https://img.shields.io/badge/CI%20tests-full%20size-FF9900?labelColor=000000&logo=Amazon%20AWS)](https://nf-co.re/scrnaseq/results)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX) -[![Nextflow](https://img.shields.io/badge/nextflow%20DSL2-%E2%89%A522.10.1-23aa62.svg)](https://www.nextflow.io/) +[![Nextflow](https://img.shields.io/badge/nextflow%20DSL2-%E2%89%A523.04.0-23aa62.svg)](https://www.nextflow.io/) [![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/) [![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/) [![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/) @@ -66,11 +66,11 @@ nextflow run nf-core/scrnaseq \ > provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_; > see [docs](https://nf-co.re/usage/configuration#custom-configuration-files). -For more details, please refer to the [usage documentation](https://nf-co.re/scrnaseq/usage) and the [parameter documentation](https://nf-co.re/scrnaseq/parameters). +For more details and further functionality, please refer to the [usage documentation](https://nf-co.re/scrnaseq/usage) and the [parameter documentation](https://nf-co.re/scrnaseq/parameters). ## Pipeline output -To see the the results of a test run with a full size dataset refer to the [results](https://nf-co.re/scrnaseq/results) tab on the nf-core website pipeline page. +To see the results of an example test run with a full size dataset refer to the [results](https://nf-co.re/scrnaseq/results) tab on the nf-core website pipeline page. For more details about the output files and reports, please refer to the [output documentation](https://nf-co.re/scrnaseq/output). diff --git a/assets/methods_description_template.yml b/assets/methods_description_template.yml index 1e84fd63..c79ee0c1 100644 --- a/assets/methods_description_template.yml +++ b/assets/methods_description_template.yml @@ -3,17 +3,21 @@ description: "Suggested text and references to use when describing pipeline usag section_name: "nf-core/scrnaseq Methods Description" section_href: "https://github.com/nf-core/scrnaseq" plot_type: "html" -## TODO nf-core: Update the HTML below to your prefered methods description, e.g. add publication citation for this pipeline +## TODO nf-core: Update the HTML below to your preferred methods description, e.g. add publication citation for this pipeline ## You inject any metadata in the Nextflow '${workflow}' object data: |

Methods

-

Data was processed using nf-core/scrnaseq v${workflow.manifest.version} ${doi_text} of the nf-core collection of workflows (Ewels et al., 2020).

+

Data was processed using nf-core/scrnaseq v${workflow.manifest.version} ${doi_text} of the nf-core collection of workflows (Ewels et al., 2020), utilising reproducible software environments from the Bioconda (Grüning et al., 2018) and Biocontainers (da Veiga Leprevost et al., 2017) projects.

The pipeline was executed with Nextflow v${workflow.nextflow.version} (Di Tommaso et al., 2017) with the following command:

${workflow.commandLine}
+

${tool_citations}

References

    -
  • Di Tommaso, P., Chatzou, M., Floden, E. W., Barja, P. P., Palumbo, E., & Notredame, C. (2017). Nextflow enables reproducible computational workflows. Nature Biotechnology, 35(4), 316-319. https://doi.org/10.1038/nbt.3820
  • -
  • Ewels, P. A., Peltzer, A., Fillinger, S., Patel, H., Alneberg, J., Wilm, A., Garcia, M. U., Di Tommaso, P., & Nahnsen, S. (2020). The nf-core framework for community-curated bioinformatics pipelines. Nature Biotechnology, 38(3), 276-278. https://doi.org/10.1038/s41587-020-0439-x
  • +
  • Di Tommaso, P., Chatzou, M., Floden, E. W., Barja, P. P., Palumbo, E., & Notredame, C. (2017). Nextflow enables reproducible computational workflows. Nature Biotechnology, 35(4), 316-319. doi: 10.1038/nbt.3820
  • +
  • Ewels, P. A., Peltzer, A., Fillinger, S., Patel, H., Alneberg, J., Wilm, A., Garcia, M. U., Di Tommaso, P., & Nahnsen, S. (2020). The nf-core framework for community-curated bioinformatics pipelines. Nature Biotechnology, 38(3), 276-278. doi: 10.1038/s41587-020-0439-x
  • +
  • Grüning, B., Dale, R., Sjödin, A., Chapman, B. A., Rowe, J., Tomkins-Tinch, C. H., Valieris, R., Köster, J., & Bioconda Team. (2018). Bioconda: sustainable and comprehensive software distribution for the life sciences. Nature Methods, 15(7), 475–476. doi: 10.1038/s41592-018-0046-7
  • +
  • da Veiga Leprevost, F., Grüning, B. A., Alves Aflitos, S., Röst, H. L., Uszkoreit, J., Barsnes, H., Vaudel, M., Moreno, P., Gatto, L., Weber, J., Bai, M., Jimenez, R. C., Sachsenberg, T., Pfeuffer, J., Vera Alvarez, R., Griss, J., Nesvizhskii, A. I., & Perez-Riverol, Y. (2017). BioContainers: an open-source and community-driven framework for software standardization. Bioinformatics (Oxford, England), 33(16), 2580–2582. doi: 10.1093/bioinformatics/btx192
  • + ${tool_bibliography}
Notes:
diff --git a/assets/multiqc_config.yml b/assets/multiqc_config.yml index 3679a380..bd63c010 100644 --- a/assets/multiqc_config.yml +++ b/assets/multiqc_config.yml @@ -1,7 +1,7 @@ report_comment: > - This report has been generated by the nf-core/scrnaseq + This report has been generated by the nf-core/scrnaseq analysis pipeline. For information about how to interpret these results, please see the - documentation. + documentation. report_section_order: "nf-core-scrnaseq-methods-description": order: -1000 diff --git a/assets/nf-core-scrnaseq_logo_light.png b/assets/nf-core-scrnaseq_logo_light.png index 325ed32b1b62a2b2a47e323101d694af2f817c3f..5e5ec430880def739192d05acf90d01c4bd6c8ee 100644 GIT binary patch literal 75757 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�ev`Q}H7y#R1zKkC5n?0_OP7^FqWWeXhX0t0pNK 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

)bNtXB<>| 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 NGp46=PC5She*mtGOvC^H literal 11729 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 diff --git a/assets/slackreport.json b/assets/slackreport.json index 043d02f2..f6ba6baf 100644 --- a/assets/slackreport.json +++ b/assets/slackreport.json @@ -3,7 +3,7 @@ { "fallback": "Plain-text summary of the attachment.", "color": "<% if (success) { %>good<% } else { %>danger<%} %>", - "author_name": "sanger-tol/readmapping v${version} - ${runName}", + "author_name": "nf-core/scrnaseq v${version} - ${runName}", "author_icon": "https://www.nextflow.io/docs/latest/_static/favicon.ico", "text": "<% if (success) { %>Pipeline completed successfully!<% } else { %>Pipeline completed with errors<% } %>", "fields": [ diff --git a/conf/test_full.config b/conf/test_full.config index 8ac7f6b3..e50f487c 100644 --- a/conf/test_full.config +++ b/conf/test_full.config @@ -10,8 +10,6 @@ ---------------------------------------------------------------------------------------- */ -cleanup = true - params { config_profile_name = 'Full test profile' config_profile_description = 'Full test dataset to check pipeline function' diff --git a/docs/usage.md b/docs/usage.md index 6d7d8cfd..88b70ade 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -57,7 +57,7 @@ An [example samplesheet](../assets/samplesheet.csv) has been provided with the p The typical command for running the pipeline is as follows: ```bash -nextflow run nf-core/scrnaseq --input samplesheet.csv --outdir --genome GRCh37 -profile docker +nextflow run nf-core/scrnaseq --input ./samplesheet.csv --outdir ./results --genome GRCh37 -profile docker ``` This will launch the pipeline with the `docker` configuration profile. See below for more information about profiles. @@ -76,7 +76,8 @@ If you wish to repeatedly use the same parameters for multiple runs, rather than Pipeline settings can be provided in a `yaml` or `json` file via `-params-file `. > ⚠️ Do not use `-c ` to specify parameters as this will result in errors. Custom config files specified with `-c` must only be used for [tuning process resource specifications](https://nf-co.re/docs/usage/configuration#tuning-workflow-resources), other infrastructural tweaks (such as output directories), or module arguments (args). -> The above pipeline run specified with a params file in yaml format: + +The above pipeline run specified with a params file in yaml format: ```bash nextflow run nf-core/scrnaseq -profile docker -params-file params.yaml @@ -88,7 +89,6 @@ with `params.yaml` containing: input: './samplesheet.csv' outdir: './results/' genome: 'GRCh37' -input: 'data' <...> ``` diff --git a/lib/NfcoreSchema.groovy b/lib/NfcoreSchema.groovy deleted file mode 100755 index 9b34804d..00000000 --- a/lib/NfcoreSchema.groovy +++ /dev/null @@ -1,530 +0,0 @@ -// -// This file holds several functions used to perform JSON parameter validation, help and summary rendering for the nf-core pipeline template. -// - -import nextflow.Nextflow -import org.everit.json.schema.Schema -import org.everit.json.schema.loader.SchemaLoader -import org.everit.json.schema.ValidationException -import org.json.JSONObject -import org.json.JSONTokener -import org.json.JSONArray -import groovy.json.JsonSlurper -import groovy.json.JsonBuilder - -class NfcoreSchema { - - // - // Resolve Schema path relative to main workflow directory - // - public static String getSchemaPath(workflow, schema_filename='nextflow_schema.json') { - return "${workflow.projectDir}/${schema_filename}" - } - - // - // Function to loop over all parameters defined in schema and check - // whether the given parameters adhere to the specifications - // - /* groovylint-disable-next-line UnusedPrivateMethodParameter */ - public static void validateParameters(workflow, params, log, schema_filename='nextflow_schema.json') { - def has_error = false - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Check for nextflow core params and unexpected params - def json = new File(getSchemaPath(workflow, schema_filename=schema_filename)).text - def Map schemaParams = (Map) new JsonSlurper().parseText(json).get('definitions') - def nf_params = [ - // Options for base `nextflow` command - 'bg', - 'c', - 'C', - 'config', - 'd', - 'D', - 'dockerize', - 'h', - 'log', - 'q', - 'quiet', - 'syslog', - 'v', - - // Options for `nextflow run` command - 'ansi', - 'ansi-log', - 'bg', - 'bucket-dir', - 'c', - 'cache', - 'config', - 'dsl2', - 'dump-channels', - 'dump-hashes', - 'E', - 'entry', - 'latest', - 'lib', - 'main-script', - 'N', - 'name', - 'offline', - 'params-file', - 'pi', - 'plugins', - 'poll-interval', - 'pool-size', - 'profile', - 'ps', - 'qs', - 'queue-size', - 'r', - 'resume', - 'revision', - 'stdin', - 'stub', - 'stub-run', - 'test', - 'w', - 'with-apptainer', - 'with-charliecloud', - 'with-conda', - 'with-dag', - 'with-docker', - 'with-mpi', - 'with-notification', - 'with-podman', - 'with-report', - 'with-singularity', - 'with-timeline', - 'with-tower', - 'with-trace', - 'with-weblog', - 'without-docker', - 'without-podman', - 'work-dir' - ] - def unexpectedParams = [] - - // Collect expected parameters from the schema - def expectedParams = [] - def enums = [:] - for (group in schemaParams) { - for (p in group.value['properties']) { - expectedParams.push(p.key) - if (group.value['properties'][p.key].containsKey('enum')) { - enums[p.key] = group.value['properties'][p.key]['enum'] - } - } - } - - for (specifiedParam in params.keySet()) { - // nextflow params - if (nf_params.contains(specifiedParam)) { - log.error "ERROR: You used a core Nextflow option with two hyphens: '--${specifiedParam}'. Please resubmit with '-${specifiedParam}'" - has_error = true - } - // unexpected params - def params_ignore = params.schema_ignore_params.split(',') + 'schema_ignore_params' - def expectedParamsLowerCase = expectedParams.collect{ it.replace("-", "").toLowerCase() } - def specifiedParamLowerCase = specifiedParam.replace("-", "").toLowerCase() - def isCamelCaseBug = (specifiedParam.contains("-") && !expectedParams.contains(specifiedParam) && expectedParamsLowerCase.contains(specifiedParamLowerCase)) - if (!expectedParams.contains(specifiedParam) && !params_ignore.contains(specifiedParam) && !isCamelCaseBug) { - // Temporarily remove camelCase/camel-case params #1035 - def unexpectedParamsLowerCase = unexpectedParams.collect{ it.replace("-", "").toLowerCase()} - if (!unexpectedParamsLowerCase.contains(specifiedParamLowerCase)){ - unexpectedParams.push(specifiedParam) - } - } - } - - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Validate parameters against the schema - InputStream input_stream = new File(getSchemaPath(workflow, schema_filename=schema_filename)).newInputStream() - JSONObject raw_schema = new JSONObject(new JSONTokener(input_stream)) - - // Remove anything that's in params.schema_ignore_params - raw_schema = removeIgnoredParams(raw_schema, params) - - Schema schema = SchemaLoader.load(raw_schema) - - // Clean the parameters - def cleanedParams = cleanParameters(params) - - // Convert to JSONObject - def jsonParams = new JsonBuilder(cleanedParams) - JSONObject params_json = new JSONObject(jsonParams.toString()) - - // Validate - try { - schema.validate(params_json) - } catch (ValidationException e) { - println '' - log.error 'ERROR: Validation of pipeline parameters failed!' - JSONObject exceptionJSON = e.toJSON() - printExceptions(exceptionJSON, params_json, log, enums) - println '' - has_error = true - } - - // Check for unexpected parameters - if (unexpectedParams.size() > 0) { - Map colors = NfcoreTemplate.logColours(params.monochrome_logs) - println '' - def warn_msg = 'Found unexpected parameters:' - for (unexpectedParam in unexpectedParams) { - warn_msg = warn_msg + "\n* --${unexpectedParam}: ${params[unexpectedParam].toString()}" - } - log.warn warn_msg - log.info "- ${colors.dim}Ignore this warning: params.schema_ignore_params = \"${unexpectedParams.join(',')}\" ${colors.reset}" - println '' - } - - if (has_error) { - Nextflow.error('Exiting!') - } - } - - // - // Beautify parameters for --help - // - public static String paramsHelp(workflow, params, command, schema_filename='nextflow_schema.json') { - Map colors = NfcoreTemplate.logColours(params.monochrome_logs) - Integer num_hidden = 0 - String output = '' - output += 'Typical pipeline command:\n\n' - output += " ${colors.cyan}${command}${colors.reset}\n\n" - Map params_map = paramsLoad(getSchemaPath(workflow, schema_filename=schema_filename)) - Integer max_chars = paramsMaxChars(params_map) + 1 - Integer desc_indent = max_chars + 14 - Integer dec_linewidth = 160 - desc_indent - for (group in params_map.keySet()) { - Integer num_params = 0 - String group_output = colors.underlined + colors.bold + group + colors.reset + '\n' - def group_params = params_map.get(group) // This gets the parameters of that particular group - for (param in group_params.keySet()) { - if (group_params.get(param).hidden && !params.show_hidden_params) { - num_hidden += 1 - continue; - } - def type = '[' + group_params.get(param).type + ']' - def description = group_params.get(param).description - def defaultValue = group_params.get(param).default != null ? " [default: " + group_params.get(param).default.toString() + "]" : '' - def description_default = description + colors.dim + defaultValue + colors.reset - // Wrap long description texts - // Loosely based on https://dzone.com/articles/groovy-plain-text-word-wrap - if (description_default.length() > dec_linewidth){ - List olines = [] - String oline = "" // " " * indent - description_default.split(" ").each() { wrd -> - if ((oline.size() + wrd.size()) <= dec_linewidth) { - oline += wrd + " " - } else { - olines += oline - oline = wrd + " " - } - } - olines += oline - description_default = olines.join("\n" + " " * desc_indent) - } - group_output += " --" + param.padRight(max_chars) + colors.dim + type.padRight(10) + colors.reset + description_default + '\n' - num_params += 1 - } - group_output += '\n' - if (num_params > 0){ - output += group_output - } - } - if (num_hidden > 0){ - output += colors.dim + "!! Hiding $num_hidden params, use --show_hidden_params to show them !!\n" + colors.reset - } - output += NfcoreTemplate.dashedLine(params.monochrome_logs) - return output - } - - // - // Groovy Map summarising parameters/workflow options used by the pipeline - // - public static LinkedHashMap paramsSummaryMap(workflow, params, schema_filename='nextflow_schema.json') { - // Get a selection of core Nextflow workflow options - def Map workflow_summary = [:] - if (workflow.revision) { - workflow_summary['revision'] = workflow.revision - } - workflow_summary['runName'] = workflow.runName - if (workflow.containerEngine) { - workflow_summary['containerEngine'] = workflow.containerEngine - } - if (workflow.container) { - workflow_summary['container'] = workflow.container - } - workflow_summary['launchDir'] = workflow.launchDir - workflow_summary['workDir'] = workflow.workDir - workflow_summary['projectDir'] = workflow.projectDir - workflow_summary['userName'] = workflow.userName - workflow_summary['profile'] = workflow.profile - workflow_summary['configFiles'] = workflow.configFiles.join(', ') - - // Get pipeline parameters defined in JSON Schema - def Map params_summary = [:] - def params_map = paramsLoad(getSchemaPath(workflow, schema_filename=schema_filename)) - for (group in params_map.keySet()) { - def sub_params = new LinkedHashMap() - def group_params = params_map.get(group) // This gets the parameters of that particular group - for (param in group_params.keySet()) { - if (params.containsKey(param)) { - def params_value = params.get(param) - def schema_value = group_params.get(param).default - def param_type = group_params.get(param).type - if (schema_value != null) { - if (param_type == 'string') { - if (schema_value.contains('$projectDir') || schema_value.contains('${projectDir}')) { - def sub_string = schema_value.replace('\$projectDir', '') - sub_string = sub_string.replace('\${projectDir}', '') - if (params_value.contains(sub_string)) { - schema_value = params_value - } - } - if (schema_value.contains('$params.outdir') || schema_value.contains('${params.outdir}')) { - def sub_string = schema_value.replace('\$params.outdir', '') - sub_string = sub_string.replace('\${params.outdir}', '') - if ("${params.outdir}${sub_string}" == params_value) { - schema_value = params_value - } - } - } - } - - // We have a default in the schema, and this isn't it - if (schema_value != null && params_value != schema_value) { - sub_params.put(param, params_value) - } - // No default in the schema, and this isn't empty - else if (schema_value == null && params_value != "" && params_value != null && params_value != false) { - sub_params.put(param, params_value) - } - } - } - params_summary.put(group, sub_params) - } - return [ 'Core Nextflow options' : workflow_summary ] << params_summary - } - - // - // Beautify parameters for summary and return as string - // - public static String paramsSummaryLog(workflow, params) { - Map colors = NfcoreTemplate.logColours(params.monochrome_logs) - String output = '' - def params_map = paramsSummaryMap(workflow, params) - def max_chars = paramsMaxChars(params_map) - for (group in params_map.keySet()) { - def group_params = params_map.get(group) // This gets the parameters of that particular group - if (group_params) { - output += colors.bold + group + colors.reset + '\n' - for (param in group_params.keySet()) { - output += " " + colors.blue + param.padRight(max_chars) + ": " + colors.green + group_params.get(param) + colors.reset + '\n' - } - output += '\n' - } - } - output += "!! Only displaying parameters that differ from the pipeline defaults !!\n" - output += NfcoreTemplate.dashedLine(params.monochrome_logs) - return output - } - - // - // Loop over nested exceptions and print the causingException - // - private static void printExceptions(ex_json, params_json, log, enums, limit=5) { - def causingExceptions = ex_json['causingExceptions'] - if (causingExceptions.length() == 0) { - def m = ex_json['message'] =~ /required key \[([^\]]+)\] not found/ - // Missing required param - if (m.matches()) { - log.error "* Missing required parameter: --${m[0][1]}" - } - // Other base-level error - else if (ex_json['pointerToViolation'] == '#') { - log.error "* ${ex_json['message']}" - } - // Error with specific param - else { - def param = ex_json['pointerToViolation'] - ~/^#\// - def param_val = params_json[param].toString() - if (enums.containsKey(param)) { - def error_msg = "* --${param}: '${param_val}' is not a valid choice (Available choices" - if (enums[param].size() > limit) { - log.error "${error_msg} (${limit} of ${enums[param].size()}): ${enums[param][0..limit-1].join(', ')}, ... )" - } else { - log.error "${error_msg}: ${enums[param].join(', ')})" - } - } else { - log.error "* --${param}: ${ex_json['message']} (${param_val})" - } - } - } - for (ex in causingExceptions) { - printExceptions(ex, params_json, log, enums) - } - } - - // - // Remove an element from a JSONArray - // - private static JSONArray removeElement(json_array, element) { - def list = [] - int len = json_array.length() - for (int i=0;i - if(raw_schema.keySet().contains('definitions')){ - raw_schema.definitions.each { definition -> - for (key in definition.keySet()){ - if (definition[key].get("properties").keySet().contains(ignore_param)){ - // Remove the param to ignore - definition[key].get("properties").remove(ignore_param) - // If the param was required, change this - if (definition[key].has("required")) { - def cleaned_required = removeElement(definition[key].required, ignore_param) - definition[key].put("required", cleaned_required) - } - } - } - } - } - if(raw_schema.keySet().contains('properties') && raw_schema.get('properties').keySet().contains(ignore_param)) { - raw_schema.get("properties").remove(ignore_param) - } - if(raw_schema.keySet().contains('required') && raw_schema.required.contains(ignore_param)) { - def cleaned_required = removeElement(raw_schema.required, ignore_param) - raw_schema.put("required", cleaned_required) - } - } - return raw_schema - } - - // - // Clean and check parameters relative to Nextflow native classes - // - private static Map cleanParameters(params) { - def new_params = params.getClass().newInstance(params) - for (p in params) { - // remove anything evaluating to false - if (!p['value']) { - new_params.remove(p.key) - } - // Cast MemoryUnit to String - if (p['value'].getClass() == nextflow.util.MemoryUnit) { - new_params.replace(p.key, p['value'].toString()) - } - // Cast Duration to String - if (p['value'].getClass() == nextflow.util.Duration) { - new_params.replace(p.key, p['value'].toString().replaceFirst(/d(?!\S)/, "day")) - } - // Cast LinkedHashMap to String - if (p['value'].getClass() == LinkedHashMap) { - new_params.replace(p.key, p['value'].toString()) - } - } - return new_params - } - - // - // This function tries to read a JSON params file - // - private static LinkedHashMap paramsLoad(String json_schema) { - def params_map = new LinkedHashMap() - try { - params_map = paramsRead(json_schema) - } catch (Exception e) { - println "Could not read parameters settings from JSON. $e" - params_map = new LinkedHashMap() - } - return params_map - } - - // - // Method to actually read in JSON file using Groovy. - // Group (as Key), values are all parameters - // - Parameter1 as Key, Description as Value - // - Parameter2 as Key, Description as Value - // .... - // Group - // - - private static LinkedHashMap paramsRead(String json_schema) throws Exception { - def json = new File(json_schema).text - def Map schema_definitions = (Map) new JsonSlurper().parseText(json).get('definitions') - def Map schema_properties = (Map) new JsonSlurper().parseText(json).get('properties') - /* Tree looks like this in nf-core schema - * definitions <- this is what the first get('definitions') gets us - group 1 - title - description - properties - parameter 1 - type - description - parameter 2 - type - description - group 2 - title - description - properties - parameter 1 - type - description - * properties <- parameters can also be ungrouped, outside of definitions - parameter 1 - type - description - */ - - // Grouped params - def params_map = new LinkedHashMap() - schema_definitions.each { key, val -> - def Map group = schema_definitions."$key".properties // Gets the property object of the group - def title = schema_definitions."$key".title - def sub_params = new LinkedHashMap() - group.each { innerkey, value -> - sub_params.put(innerkey, value) - } - params_map.put(title, sub_params) - } - - // Ungrouped params - def ungrouped_params = new LinkedHashMap() - schema_properties.each { innerkey, value -> - ungrouped_params.put(innerkey, value) - } - params_map.put("Other parameters", ungrouped_params) - - return params_map - } - - // - // Get maximum number of characters across all parameter names - // - private static Integer paramsMaxChars(params_map) { - Integer max_chars = 0 - for (group in params_map.keySet()) { - def group_params = params_map.get(group) // This gets the parameters of that particular group - for (param in group_params.keySet()) { - if (param.size() > max_chars) { - max_chars = param.size() - } - } - } - return max_chars - } -} diff --git a/lib/NfcoreTemplate.groovy b/lib/NfcoreTemplate.groovy index 25a0a74a..408951ae 100755 --- a/lib/NfcoreTemplate.groovy +++ b/lib/NfcoreTemplate.groovy @@ -128,7 +128,7 @@ class NfcoreTemplate { def email_html = html_template.toString() // Render the sendmail template - def max_multiqc_email_size = params.max_multiqc_email_size as nextflow.util.MemoryUnit + def max_multiqc_email_size = (params.containsKey('max_multiqc_email_size') ? params.max_multiqc_email_size : 0) as nextflow.util.MemoryUnit def smail_fields = [ email: email_address, subject: subject, email_txt: email_txt, email_html: email_html, projectDir: "$projectDir", mqcFile: mqc_report, mqcMaxSize: max_multiqc_email_size.toBytes() ] def sf = new File("$projectDir/assets/sendmail_template.txt") def sendmail_template = engine.createTemplate(sf).make(smail_fields) diff --git a/lib/WorkflowMain.groovy b/lib/WorkflowMain.groovy index 4a9153ef..bb00019b 100755 --- a/lib/WorkflowMain.groovy +++ b/lib/WorkflowMain.groovy @@ -20,40 +20,11 @@ class WorkflowMain { " https://github.com/${workflow.manifest.name}/blob/master/CITATIONS.md" } - // - // Generate help string - // - public static String help(workflow, params) { - def command = "nextflow run ${workflow.manifest.name} --input samplesheet.csv --genome GRCh37 -profile docker" - def help_string = '' - help_string += NfcoreTemplate.logo(workflow, params.monochrome_logs) - help_string += NfcoreSchema.paramsHelp(workflow, params, command) - help_string += '\n' + citation(workflow) + '\n' - help_string += NfcoreTemplate.dashedLine(params.monochrome_logs) - return help_string - } - - // - // Generate parameter summary log string - // - public static String paramsSummaryLog(workflow, params) { - def summary_log = '' - summary_log += NfcoreTemplate.logo(workflow, params.monochrome_logs) - summary_log += NfcoreSchema.paramsSummaryLog(workflow, params) - summary_log += '\n' + citation(workflow) + '\n' - summary_log += NfcoreTemplate.dashedLine(params.monochrome_logs) - return summary_log - } // // Validate parameters and print summary to screen // public static void initialise(workflow, params, log) { - // Print help to screen if required - if (params.help) { - log.info help(workflow, params) - System.exit(0) - } // Print workflow version and exit on --version if (params.version) { @@ -62,14 +33,6 @@ class WorkflowMain { System.exit(0) } - // Print parameter summary log to screen - log.info paramsSummaryLog(workflow, params) - - // Validate workflow parameters via the JSON schema - if (params.validate_params) { - NfcoreSchema.validateParameters(workflow, params, log) - } - // Check that a -profile or Nextflow config has been provided to run the pipeline NfcoreTemplate.checkConfigProvided(workflow, log) diff --git a/lib/WorkflowScrnaseq.groovy b/lib/WorkflowScrnaseq.groovy index 217f910b..6bae45d4 100755 --- a/lib/WorkflowScrnaseq.groovy +++ b/lib/WorkflowScrnaseq.groovy @@ -11,6 +11,7 @@ class WorkflowScrnaseq { // Check and validate parameters // public static void initialise(params, log) { + genomeExistsError(params, log) @@ -46,15 +47,57 @@ class WorkflowScrnaseq { return yaml_file_text } - public static String methodsDescriptionText(run_workflow, mqc_methods_yaml) { + // + // Generate methods description for MultiQC + // + + public static String toolCitationText(params) { + + // TODO Optionally add in-text citation tools to this list. + // Can use ternary operators to dynamically construct based conditions, e.g. params["run_xyz"] ? "Tool (Foo et al. 2023)" : "", + // Uncomment function in methodsDescriptionText to render in MultiQC report + def citation_text = [ + "Tools used in the workflow included:", + "FastQC (Andrews 2010),", + "MultiQC (Ewels et al. 2016)", + "." + ].join(' ').trim() + + return citation_text + } + + public static String toolBibliographyText(params) { + + // TODO Optionally add bibliographic entries to this list. + // Can use ternary operators to dynamically construct based conditions, e.g. params["run_xyz"] ? "

  • Author (2023) Pub name, Journal, DOI
  • " : "", + // Uncomment function in methodsDescriptionText to render in MultiQC report + def reference_text = [ + "
  • Andrews S, (2010) FastQC, URL: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/).
  • ", + "
  • Ewels, P., Magnusson, M., Lundin, S., & Käller, M. (2016). MultiQC: summarize analysis results for multiple tools and samples in a single report. Bioinformatics , 32(19), 3047–3048. doi: /10.1093/bioinformatics/btw354
  • " + ].join(' ').trim() + + return reference_text + } + + public static String methodsDescriptionText(run_workflow, mqc_methods_yaml, params) { // Convert to a named map so can be used as with familar NXF ${workflow} variable syntax in the MultiQC YML file def meta = [:] meta.workflow = run_workflow.toMap() meta["manifest_map"] = run_workflow.manifest.toMap() + // Pipeline DOI meta["doi_text"] = meta.manifest_map.doi ? "(doi: ${meta.manifest_map.doi})" : "" meta["nodoi_text"] = meta.manifest_map.doi ? "": "
  • If available, make sure to update the text to include the Zenodo DOI of version of the pipeline used.
  • " + // Tool references + meta["tool_citations"] = "" + meta["tool_bibliography"] = "" + + // TODO Only uncomment below if logic in toolCitationText/toolBibliographyText has been filled! + //meta["tool_citations"] = toolCitationText(params).replaceAll(", \\.", ".").replaceAll("\\. \\.", ".").replaceAll(", \\.", ".") + //meta["tool_bibliography"] = toolBibliographyText(params) + + def methods_text = mqc_methods_yaml.text def engine = new SimpleTemplateEngine() diff --git a/main.nf b/main.nf index 4d1eb0ea..e7cbaa2e 100644 --- a/main.nf +++ b/main.nf @@ -25,6 +25,22 @@ params.fasta = WorkflowMain.getGenomeAttribute(params, 'fasta') ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +include { validateParameters; paramsHelp } from 'plugin/nf-validation' + +// Print help message if needed +if (params.help) { + def logo = NfcoreTemplate.logo(workflow, params.monochrome_logs) + def citation = '\n' + WorkflowMain.citation(workflow) + '\n' + def String command = "nextflow run ${workflow.manifest.name} --input samplesheet.csv --genome GRCh37 -profile docker" + log.info logo + paramsHelp(command) + citation + NfcoreTemplate.dashedLine(params.monochrome_logs) + System.exit(0) +} + +// Validate input parameters +if (params.validate_params) { + validateParameters() +} + WorkflowMain.initialise(workflow, params, log) /* diff --git a/nextflow.config b/nextflow.config index 3f7e0878..6141a554 100644 --- a/nextflow.config +++ b/nextflow.config @@ -12,12 +12,12 @@ params { // TODO nf-core: Specify your pipeline's command line flags // Input options input = null - - // References genome = null igenomes_base = 's3://ngi-igenomes/igenomes' igenomes_ignore = false + + // MultiQC options multiqc_config = null multiqc_title = null @@ -27,7 +27,6 @@ params { // Boilerplate options outdir = null - tracedir = "${params.outdir}/pipeline_info" publish_dir_mode = 'copy' email = null email_on_fail = null @@ -36,19 +35,15 @@ params { hook_url = null help = false version = false - validate_params = true - show_hidden_params = false - schema_ignore_params = 'genomes' - // Config options + config_profile_name = null + config_profile_description = null custom_config_version = 'master' custom_config_base = "https://raw.githubusercontent.com/nf-core/configs/${params.custom_config_version}" - config_profile_description = null config_profile_contact = null config_profile_url = null - config_profile_name = null - + // Max resource options // Defaults only, expecting to be overwritten @@ -56,6 +51,13 @@ params { max_cpus = 16 max_time = '240.h' + // Schema validation default options + validationFailUnrecognisedParams = false + validationLenientMode = false + validationSchemaIgnoreParams = 'genomes' + validationShowHiddenParams = false + validate_params = true + } // Load base.config by default for all pipelines @@ -75,13 +77,11 @@ try { // } catch (Exception e) { // System.err.println("WARNING: Could not load nf-core/config/scrnaseq profiles: ${params.custom_config_base}/pipeline/scrnaseq.config") // } - - profiles { debug { dumpHashes = true process.beforeScript = 'echo $HOSTNAME' - cleanup = false + cleanup = false } conda { conda.enabled = true @@ -104,7 +104,6 @@ profiles { } docker { docker.enabled = true - docker.registry = 'quay.io' docker.userEmulation = true conda.enabled = false singularity.enabled = false @@ -128,7 +127,6 @@ profiles { } podman { podman.enabled = true - podman.registry = 'quay.io' conda.enabled = false docker.enabled = false singularity.enabled = false @@ -172,6 +170,18 @@ profiles { test_full { includeConfig 'conf/test_full.config' } } +// Set default registry for Apptainer, Docker, Podman and Singularity independent of -profile +// Will not be used unless Apptainer / Docker / Podman / Singularity are enabled +// Set to your registry if you have a mirror of containers +apptainer.registry = 'quay.io' +docker.registry = 'quay.io' +podman.registry = 'quay.io' +singularity.registry = 'quay.io' + +// Nextflow plugins +plugins { + id 'nf-validation' // Validation of pipeline parameters and creation of an input channel from a sample sheet +} // Load igenomes.config if required if (!params.igenomes_ignore) { @@ -179,8 +189,6 @@ if (!params.igenomes_ignore) { } else { params.genomes = [:] } - - // Export these variables to prevent local Python/R libraries from conflicting with those in the container // The JULIA depot path has been adjusted to a fixed path `/usr/local/share/julia` that needs to be used for packages in the container. // See https://apeltzer.github.io/post/03-julia-lang-nextflow/ for details on that. Once we have a common agreement on where to keep Julia packages, this is adjustable. @@ -198,19 +206,19 @@ process.shell = ['/bin/bash', '-euo', 'pipefail'] def trace_timestamp = new java.util.Date().format( 'yyyy-MM-dd_HH-mm-ss') timeline { enabled = true - file = "${params.tracedir}/execution_timeline_${trace_timestamp}.html" + file = "${params.outdir}/pipeline_info/execution_timeline_${trace_timestamp}.html" } report { enabled = true - file = "${params.tracedir}/execution_report_${trace_timestamp}.html" + file = "${params.outdir}/pipeline_info/execution_report_${trace_timestamp}.html" } trace { enabled = true - file = "${params.tracedir}/execution_trace_${trace_timestamp}.txt" + file = "${params.outdir}/pipeline_info/execution_trace_${trace_timestamp}.txt" } dag { enabled = true - file = "${params.tracedir}/pipeline_dag_${trace_timestamp}.html" + file = "${params.outdir}/pipeline_info/pipeline_dag_${trace_timestamp}.html" } manifest { @@ -219,8 +227,8 @@ manifest { homePage = 'https://github.com/nf-core/scrnaseq' description = """Pipeline for processing 10x Genomics single cell rnaseq data""" mainScript = 'main.nf' - nextflowVersion = '!>=22.10.1' - version = '2.3.0dev' + nextflowVersion = '!>=23.04.0' + version = '2.4.0dev' doi = '' } diff --git a/nextflow_schema.json b/nextflow_schema.json index 832f8e96..7212aa9b 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -15,9 +15,9 @@ "input": { "type": "string", "format": "file-path", + "exists": true, "mimetype": "text/csv", "pattern": "^\\S+\\.csv$", - "schema": "assets/schema_input.json", "description": "Path to comma-separated file containing information about the samples in the experiment.", "help_text": "You will need to create a design file with information about the samples in your experiment before running the pipeline. Use this parameter to specify its location. It has to be a comma-separated file with 3 columns, and a header row. See [usage docs](https://nf-co.re/scrnaseq/usage#samplesheet-input).", "fa_icon": "fas fa-file-csv" @@ -57,6 +57,7 @@ "fasta": { "type": "string", "format": "file-path", + "exists": true, "mimetype": "text/plain", "pattern": "^\\S+\\.fn?a(sta)?(\\.gz)?$", "description": "Path to FASTA genome file.", @@ -157,7 +158,7 @@ "description": "Maximum amount of time that can be requested for any single job.", "default": "240.h", "fa_icon": "far fa-clock", - "pattern": "^(\\d+\\.?\\s*(s|m|h|day)\\s*)+$", + "pattern": "^(\\d+\\.?\\s*(s|m|h|d|day)\\s*)+$", "hidden": true, "help_text": "Use to set an upper-limit for the time requirement for each process. Should be a string in the format integer-unit e.g. `--max_time '2.h'`" } @@ -174,12 +175,14 @@ "type": "boolean", "description": "Display help text.", "fa_icon": "fas fa-question-circle", + "default": false, "hidden": true }, "version": { "type": "boolean", "description": "Display version and exit.", "fa_icon": "fas fa-question-circle", + "default": false, "hidden": true }, "publish_dir_mode": { @@ -203,6 +206,7 @@ "type": "boolean", "description": "Send plain-text email instead of HTML.", "fa_icon": "fas fa-remove-format", + "default": false, "hidden": true }, "max_multiqc_email_size": { @@ -217,6 +221,7 @@ "type": "boolean", "description": "Do not use coloured log outputs.", "fa_icon": "fas fa-palette", + "default": false, "hidden": true }, "hook_url": { @@ -228,6 +233,7 @@ }, "multiqc_config": { "type": "string", + "format": "file-path", "description": "Custom config file to supply to MultiQC.", "fa_icon": "fas fa-cog", "hidden": true @@ -243,13 +249,6 @@ "description": "Custom MultiQC yaml file containing HTML including a methods description.", "fa_icon": "fas fa-cog" }, - "tracedir": { - "type": "string", - "description": "Directory to keep pipeline Nextflow logs and reports.", - "default": "${params.outdir}/pipeline_info", - "fa_icon": "fas fa-cogs", - "hidden": true - }, "validate_params": { "type": "boolean", "description": "Boolean whether to validate parameters against the schema at runtime", @@ -257,12 +256,29 @@ "fa_icon": "fas fa-check-square", "hidden": true }, - "show_hidden_params": { + "validationShowHiddenParams": { "type": "boolean", "fa_icon": "far fa-eye-slash", "description": "Show all params when using `--help`", + "default": false, "hidden": true, "help_text": "By default, parameters set as _hidden_ in the schema are not shown on the command line when a user runs with `--help`. Specifying this option will tell the pipeline to show all parameters." + }, + "validationFailUnrecognisedParams": { + "type": "boolean", + "fa_icon": "far fa-check-circle", + "description": "Validation of parameters fails when an unrecognised parameter is found.", + "default": false, + "hidden": true, + "help_text": "By default, when an unrecognised parameter is found, it returns a warinig." + }, + "validationLenientMode": { + "type": "boolean", + "fa_icon": "far fa-check-circle", + "description": "Validation of parameters in lenient more.", + "default": false, + "hidden": true, + "help_text": "Allows string values that are parseable as numbers or booleans. For further information see [JSONSchema docs](https://github.com/everit-org/json-schema#lenient-mode)." } } } diff --git a/workflows/scrnaseq.nf b/workflows/scrnaseq.nf index d61cf64f..c84f5858 100644 --- a/workflows/scrnaseq.nf +++ b/workflows/scrnaseq.nf @@ -1,21 +1,19 @@ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - VALIDATE INPUTS + PRINT PARAMS SUMMARY ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -def summary_params = NfcoreSchema.paramsSummaryMap(workflow, params) +include { paramsSummaryLog; paramsSummaryMap } from 'plugin/nf-validation' -// Validate input parameters -WorkflowScrnaseq.initialise(params, log) +def logo = NfcoreTemplate.logo(workflow, params.monochrome_logs) +def citation = '\n' + WorkflowMain.citation(workflow) + '\n' +def summary_params = paramsSummaryMap(workflow) -// TODO nf-core: Add all file path parameters for the pipeline to the list below -// Check input path parameters to see if they exist -def checkPathParamList = [ params.input, params.multiqc_config, params.fasta ] -for (param in checkPathParamList) { if (param) { file(param, checkIfExists: true) } } +// Print parameter summary log to screen +log.info logo + paramsSummaryLog(workflow) + citation -// Check mandatory parameters -if (params.input) { ch_input = file(params.input) } else { exit 1, 'Input samplesheet not specified!' } +WorkflowScrnaseq.initialise(params, log) /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -69,9 +67,12 @@ workflow SCRNASEQ { // SUBWORKFLOW: Read in samplesheet, validate and stage input files // INPUT_CHECK ( - ch_input + file(params.input) ) ch_versions = ch_versions.mix(INPUT_CHECK.out.versions) + // TODO: OPTIONAL, you can use nf-validation plugin to create an input channel from the samplesheet with Channel.fromSamplesheet("input") + // See the documentation https://nextflow-io.github.io/nf-validation/samplesheets/fromSamplesheet/ + // ! There is currently no tooling to help you write a sample sheet schema // // MODULE: Run FastQC @@ -91,7 +92,7 @@ workflow SCRNASEQ { workflow_summary = WorkflowScrnaseq.paramsSummaryMultiqc(workflow, summary_params) ch_workflow_summary = Channel.value(workflow_summary) - methods_description = WorkflowScrnaseq.methodsDescriptionText(workflow, ch_multiqc_custom_methods_description) + methods_description = WorkflowScrnaseq.methodsDescriptionText(workflow, ch_multiqc_custom_methods_description, params) ch_methods_description = Channel.value(methods_description) ch_multiqc_files = Channel.empty() From 9f1fb7540e8c0f63f818526e40689dd25040622a Mon Sep 17 00:00:00 2001 From: Gregor Sturm Date: Sat, 1 Jul 2023 15:09:20 +0200 Subject: [PATCH 22/34] Remove obsolete multiqc config file --- conf/multiqc_config.yaml | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 conf/multiqc_config.yaml diff --git a/conf/multiqc_config.yaml b/conf/multiqc_config.yaml deleted file mode 100644 index 7bcca017..00000000 --- a/conf/multiqc_config.yaml +++ /dev/null @@ -1,7 +0,0 @@ -report_comment: > - This report has been generated by the nf-core/scrnaseq - analysis pipeline. For information about how to interpret these results, please see the - documentation. -report_section_order: - nf-core/scrnaseq-software-versions: - order: -1000 From 0c13d6ea41fbd579820ca24f279810efdf93c599 Mon Sep 17 00:00:00 2001 From: Gregor Sturm Date: Sat, 1 Jul 2023 15:16:40 +0200 Subject: [PATCH 23/34] Fix linting --- lib/WorkflowScrnaseq.groovy | 3 +-- nextflow.config | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/WorkflowScrnaseq.groovy b/lib/WorkflowScrnaseq.groovy index ede40e18..5767add6 100755 --- a/lib/WorkflowScrnaseq.groovy +++ b/lib/WorkflowScrnaseq.groovy @@ -14,8 +14,7 @@ class WorkflowScrnaseq { genomeExists(params, log) if (!params.input) { - log.error "Please provide an input samplesheet with --input" - System.exit(1) + Nextflow.error "Please provide an input samplesheet with --input" } if (!params.fasta) { diff --git a/nextflow.config b/nextflow.config index a60dc295..bdfb7672 100644 --- a/nextflow.config +++ b/nextflow.config @@ -61,7 +61,6 @@ params { multiqc_methods_description = null // Boilerplate options - tracedir = "${params.outdir}/pipeline_info" publish_dir_mode = 'copy' email = null email_on_fail = null From d528174376e3d934ff8c6a55feb94dcf666d1d72 Mon Sep 17 00:00:00 2001 From: Gregor Sturm Date: Sat, 1 Jul 2023 15:21:16 +0200 Subject: [PATCH 24/34] Update modules --- modules.json | 4 +- modules/nf-core/cellranger/count/README.md | 99 +++++++++++++++++++ modules/nf-core/cellranger/count/main.nf | 23 +---- modules/nf-core/cellranger/count/meta.yml | 14 ++- .../count/templates/cellranger_count.py | 70 +++++++++++++ modules/nf-core/fastqc/main.nf | 6 +- 6 files changed, 191 insertions(+), 25 deletions(-) create mode 100644 modules/nf-core/cellranger/count/README.md create mode 100644 modules/nf-core/cellranger/count/templates/cellranger_count.py diff --git a/modules.json b/modules.json index 76e69565..372c71fc 100644 --- a/modules.json +++ b/modules.json @@ -7,7 +7,7 @@ "nf-core": { "cellranger/count": { "branch": "master", - "git_sha": "4b7d4863a5883b76e6bff13b6e52468fab090c5b", + "git_sha": "2d67954880926029c0e8dddf37b340bf7127a878", "installed_by": ["modules"] }, "cellranger/mkgtf": { @@ -27,7 +27,7 @@ }, "fastqc": { "branch": "master", - "git_sha": "911696ea0b62df80e900ef244d7867d177971f73", + "git_sha": "bd8092b67b5103bdd52e300f75889442275c3117", "installed_by": ["modules"] }, "gffread": { diff --git a/modules/nf-core/cellranger/count/README.md b/modules/nf-core/cellranger/count/README.md new file mode 100644 index 00000000..feafbfa9 --- /dev/null +++ b/modules/nf-core/cellranger/count/README.md @@ -0,0 +1,99 @@ +# Automatically renaming files for Cellranger + +See also https://github.com/nf-core/scrnaseq/issues/241 and the [Cellranger documentation](https://support.10xgenomics.com/single-cell-gene-expression/software/pipelines/latest/using/fastq-input). + +## Motivation + +Cellranger (and also Spaceranger, and probably other 10x pipelines) rely on the following input + +- `--fastqs`, to point to a directory with fastq files that are named according to `{sample_name}_S{i}_L00{j}_{R1,R2}_001.fastq.gz`. +- `--sample`, with a sample name (that is the prefix of all associated fastq files) + +In the easiest case, `--fastqs` points to a directory that contains all fastqs of a single sample that already follow the naming conventions. However, it's not always easy: + +1. the directory may contain fastqs for multiple samples + - this is not a problem for cellranger, it will automatically choose the correct fastq files via the `--sample` flag as long as they follow the naming convention, **but** + - if we stage the whole folder (or all files in that folder) using nextflow, it breaks caching in that if an additional sample (or any other file) gets added to the folder, the cache gets invalidated for _all_ samples. +2. the sample has been sequenced across multiple flow cells + - In this case, we need to specify multiple input folders. Cellranger allows passing a _list of directories_ e.g. `--fastqs=/path/dir1,path/dir2` + - Staging all _files_ in these folders into a single directory using nextflow doesn't do the job, as there may be duplicate file names across the different folders. +3. the raw sequencing data may have been downloaded from a sequence database and doesn't follow the naming convention anymore. + - In that case we need to rename the files to follow the bcl2fastq naming convention. + +## Solution + +Rename files automatically to match the `{sample_name}_S{i}_L00{j}_{R1,R2}_001.fastq.gz` pattern. We assume that +files in the input channel are ordered according to `file1 R1, file1 R2, file2 R1, file2 R2, ...`. +If the files are explicitly listed in a samplesheet, we have this order anyway. If the files follow any sensible naming +convention, this order can be achieved by sorting by filename. + +## Does renaming the files change the result? + +No. Here's how the same dataset was tested in four different scenarios. The result is the same down +to identical md5sums of the output files. + +### Prepare datasets + +1. Download dataset: + +``` +curl https://s3-us-west-2.amazonaws.com/10x.files/samples/cell-exp/6.1.2/10k_PBMC_3p_nextgem_Chromium_X_intron/10k_PBMC_3p_nextgem_Chromium_X_intron_fastqs.tar | tar -xv +INPUT_DIR=10k_PBMC_3p_nextgem_Chromium_X_fastqs +# remove index files +rm $INPUT_DIR/*_I{1,2}_*.fastq.gz +``` + +2. Simulate scenario where files were generated using multiple flow cells: + +``` +MFC=fastq_multiflowcell +mkdir -p $MFC/fc{1,2,3,4} +for f in $INPUT_DIR/*.fastq.gz; do ; ln $f $MFC; done +for i in $(seq 4) ; do ; mv $MFC/*L00$i* $MFC/fc$i ; done +for i in $(seq 4) ; do ; rename L00$i L001 $MFC/fc$i/*; done +``` + +3. Simulate scenario where sample was multiplexed: + +``` +MPX=fastq_multiplexed +mkdir $MPX +for f in $INPUT_DIR/*.fastq.gz; do ; ln $f $MPX; done +for i in $(seq 4) ; do ; rename S1_L00$i S${i}_L001 $MPX/* ; done +``` + +4. Concatenate files + +``` +mkdir fastq_cat +cat $INPUT_DIR/*_R1_*.fastq.gz > fastq_cat/10k_PBMC_3p_nextgem_Chromium_X_S1_L001_R1_001.fastq.gz +cat $INPUT_DIR/*_R2_*.fastq.gz > fastq_cat/10k_PBMC_3p_nextgem_Chromium_X_S1_L001_R2_001.fastq.gz +``` + +### Run cellranger + +``` +singularity pull docker://docker.io/nfcore/cellranger:7.1.0 +cd $INPUT_DIR && singularity exec -B $(pwd):$(pwd) -B /cfs:/cfs docker://docker.io/nfcore/cellranger:7.1.0 cellranger count --localcores=8 --id=10k_PBMC_3p_nextgem_Chromium_X --fastqs=. --transcriptome=/cfs/sturmgre/tmp/cellranger-ref/refdata-gex-GRCh38-2020-A --localmem=64 +cd $MFC && singularity exec -B $(pwd):$(pwd) -B /cfs:/cfs docker://docker.io/nfcore/cellranger:7.1.0 cellranger count --localcores=8 --id=10k_PBMC_3p_nextgem_Chromium_X --fastqs=fc1,fc2,fc3,fc4 --transcriptome=/cfs/sturmgre/tmp/cellranger-ref/refdata-gex-GRCh38-2020-A --localmem=64 +cd $MPX && singularity exec -B $(pwd):$(pwd) -B /cfs:/cfs docker://docker.io/nfcore/cellranger:7.1.0 cellranger count --localcores=8 --id=10k_PBMC_3p_nextgem_Chromium_X --fastqs=. --transcriptome=/cfs/sturmgre/tmp/cellranger-ref/refdata-gex-GRCh38-2020-A --localmem=64 +cd fastq_cat && singularity exec -B $(pwd):$(pwd) -B /cfs:/cfs docker://docker.io/nfcore/cellranger:7.1.0 cellranger count --localcores=8 --id=10k_PBMC_3p_nextgem_Chromium_X --fastqs=. --transcriptome=/cfs/sturmgre/tmp/cellranger-ref/refdata-gex-GRCh38-2020-A --localmem=64 +``` + +### Check results + +``` +> md5sum **/outs/*.h5 | sort +2a7a5a022f01cb8d95965980f0d95ca5 10k_PBMC_3p_nextgem_Chromium_X_fastqs/10k_PBMC_3p_nextgem_Chromium_X/outs/raw_feature_bc_matrix.h5 +2a7a5a022f01cb8d95965980f0d95ca5 fastq_cat/10k_PBMC_3p_nextgem_Chromium_X/outs/raw_feature_bc_matrix.h5 +2a7a5a022f01cb8d95965980f0d95ca5 fastq_multiflowcell/10k_PBMC_3p_nextgem_Chromium_X/outs/raw_feature_bc_matrix.h5 +2a7a5a022f01cb8d95965980f0d95ca5 fastq_multiplexed/10k_PBMC_3p_nextgem_Chromium_X/outs/raw_feature_bc_matrix.h5 +533f4156f2d90152594ebc587b7fde0a 10k_PBMC_3p_nextgem_Chromium_X_fastqs/10k_PBMC_3p_nextgem_Chromium_X/outs/filtered_feature_bc_matrix.h5 +533f4156f2d90152594ebc587b7fde0a fastq_cat/10k_PBMC_3p_nextgem_Chromium_X/outs/filtered_feature_bc_matrix.h5 +533f4156f2d90152594ebc587b7fde0a fastq_multiflowcell/10k_PBMC_3p_nextgem_Chromium_X/outs/filtered_feature_bc_matrix.h5 +533f4156f2d90152594ebc587b7fde0a fastq_multiplexed/10k_PBMC_3p_nextgem_Chromium_X/outs/filtered_feature_bc_matrix.h5 +cd33d3aa95c0d5cda7cf50908c5399c1 10k_PBMC_3p_nextgem_Chromium_X_fastqs/10k_PBMC_3p_nextgem_Chromium_X/outs/molecule_info.h5 +cd33d3aa95c0d5cda7cf50908c5399c1 fastq_cat/10k_PBMC_3p_nextgem_Chromium_X/outs/molecule_info.h5 +cd33d3aa95c0d5cda7cf50908c5399c1 fastq_multiflowcell/10k_PBMC_3p_nextgem_Chromium_X/outs/molecule_info.h5 +cd33d3aa95c0d5cda7cf50908c5399c1 fastq_multiplexed/10k_PBMC_3p_nextgem_Chromium_X/outs/molecule_info.h5 +``` diff --git a/modules/nf-core/cellranger/count/main.nf b/modules/nf-core/cellranger/count/main.nf index 6aacdbc3..0a76cbd4 100644 --- a/modules/nf-core/cellranger/count/main.nf +++ b/modules/nf-core/cellranger/count/main.nf @@ -10,7 +10,7 @@ process CELLRANGER_COUNT { } input: - tuple val(meta), path(reads) + tuple val(meta), path(reads, stageAs: "fastq_???/*") path reference output: @@ -21,24 +21,9 @@ process CELLRANGER_COUNT { task.ext.when == null || task.ext.when script: - def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" - def reference_name = reference.name - """ - cellranger \\ - count \\ - --id='$prefix' \\ - --fastqs=. \\ - --transcriptome=$reference_name \\ - --localcores=$task.cpus \\ - --localmem=${task.memory.toGiga()} \\ - $args - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - cellranger: \$(echo \$( cellranger --version 2>&1) | sed 's/^.*[^0-9]\\([0-9]*\\.[0-9]*\\.[0-9]*\\).*\$/\\1/' ) - END_VERSIONS - """ + args = task.ext.args ?: '' + prefix = task.ext.prefix ?: "${meta.id}" + template "cellranger_count.py" stub: def prefix = task.ext.prefix ?: "${meta.id}" diff --git a/modules/nf-core/cellranger/count/meta.yml b/modules/nf-core/cellranger/count/meta.yml index 51d82dd5..c7d82bbc 100644 --- a/modules/nf-core/cellranger/count/meta.yml +++ b/modules/nf-core/cellranger/count/meta.yml @@ -21,9 +21,17 @@ input: - reads: type: file description: | - List of input FastQ files of size 1 and 2 for single-end and paired-end data, - respectively. - pattern: "${Sample_Name}_S1_L00${Lane_Number}_${I1,I2,R1,R2}_001.fastq.gz" + List of input FastQ files. The order of the input files MUST be ["sample1 R1", "sample1 R2", "sample2, R1", + "sample2, R2", ...]. This can usually be achieved by sorting the input files by file name. + + Background: 10x data is always paired-end with R1 containing cell barcode and UMI + and R2 containing the actual read sequence. Cell Ranger requires files to adhere to the following file-name + convention: `${Sample_Name}_S1_L00${Lane_Number}_${R1,R2}_001.fastq.gz`. This module automatically + renames files to match this convention based on the order of input files to avoid various + issues (see https://github.com/nf-core/scrnaseq/issues/241). To avoid mistakes, the module + throws an error if a pair of R1 and R2 fastq files does not have the same filename except for the "_R1"/"_R2" part. + Renaming the files does not affect the results (see README.md for detailed tests). + pattern: "*{R1,R2}*.fastq.gz" - reference: type: directory description: Folder containing all the reference indices needed by Cell Ranger diff --git a/modules/nf-core/cellranger/count/templates/cellranger_count.py b/modules/nf-core/cellranger/count/templates/cellranger_count.py new file mode 100644 index 00000000..b121a538 --- /dev/null +++ b/modules/nf-core/cellranger/count/templates/cellranger_count.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +from subprocess import run +from pathlib import Path +from textwrap import dedent +import shlex + + +def chunk_iter(seq, size): + """iterate over `seq` in chunks of `size`""" + return (seq[pos : pos + size] for pos in range(0, len(seq), size)) + + +sample_id = "${meta.id}" + +# get fastqs, ordered by path. Files are staged into +# - "fastq_001/{original_name.fastq.gz}" +# - "fastq_002/{oritinal_name.fastq.gz}" +# - ... +# Since we require fastq files in the input channel to be ordered such that a R1/R2 pair +# of files follows each other, ordering will get us a sequence of [R1, R2, R1, R2, ...] +fastqs = sorted(Path(".").glob("fastq_*/*")) +assert len(fastqs) % 2 == 0 + +# target directory in which the renamed fastqs will be placed +fastq_all = Path("./fastq_all") +fastq_all.mkdir(exist_ok=True) + + +for i, (r1, r2) in enumerate(chunk_iter(fastqs, 2)): + if r1.name.replace("R1", "R2") != r2.name: + raise AssertionError( + dedent( + f"""\ + We expect R1 and R2 of the same sample to have the same filename except for R1/R2. + Files involved: + - {r1} + - {r2} + """ + ) + ) + r1.rename(fastq_all / f"{sample_id}_S1_L{i:03d}_R1_001.fastq.gz") + r2.rename(fastq_all / f"{sample_id}_S1_L{i:03d}_R2_001.fastq.gz") + +run( + # fmt: off + [ + "cellranger", "count", + "--id", "${prefix}", + "--fastqs", str(fastq_all), + "--transcriptome", "${reference.name}", + "--localcores", "${task.cpus}", + "--localmem", "${task.memory.toGiga()}", + *shlex.split("""${args}""") + ], + # fmt: on + check=True, +) + +# Output version information +version = run( + ["cellranger", "-V"], + text=True, + check=True, + capture_output=True, +).stdout.replace("cellranger cellranger-", "") + +# alas, no `pyyaml` pre-installed in the cellranger container +with open("versions.yml", "w") as f: + f.write('"${task.process}":\\n') + f.write(f' cellranger: "{version}"\\n') diff --git a/modules/nf-core/fastqc/main.nf b/modules/nf-core/fastqc/main.nf index 07d5e433..249f9064 100644 --- a/modules/nf-core/fastqc/main.nf +++ b/modules/nf-core/fastqc/main.nf @@ -29,7 +29,11 @@ process FASTQC { printf "%s %s\\n" $rename_to | while read old_name new_name; do [ -f "\${new_name}" ] || ln -s \$old_name \$new_name done - fastqc $args --threads $task.cpus $renamed_files + + fastqc \\ + $args \\ + --threads $task.cpus \\ + $renamed_files cat <<-END_VERSIONS > versions.yml "${task.process}": From 3b44e569f63292c0f11085e65691780ba6bb4261 Mon Sep 17 00:00:00 2001 From: Gregor Sturm Date: Fri, 7 Jul 2023 08:27:49 +0200 Subject: [PATCH 25/34] Update usage docs about FASTQ filenames --- CHANGELOG.md | 3 +++ docs/usage.md | 21 ++++++++++++--------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 12181516..9753978f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix issue where multiqc inputs tried to access objects that did not exist ([#239](https://github.com/nf-core/scrnaseq/pull/239)) - Removed `public_aws_ecr` profile - Nf-core template update to v2.9 ([#245](https://github.com/nf-core/scrnaseq/pull/245)) +- Update cellranger and fastqc module ([#246](https://github.com/nf-core/scrnaseq/pull/246)). + The [updated cellranger module](https://github.com/nf-core/modules/pull/3537) now automatically renames input FASTQ + files to match the expected naming conventions. ## v2.3.2 - 2023-06-07 Patched Yellow Strontium Pinscher diff --git a/docs/usage.md b/docs/usage.md index 5260f60a..089cd517 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -75,16 +75,21 @@ Other aligner options for running the pipeline are: ### If using cellranger or universc -In order to use cellranger aligner, reads must be named as [required by the tool](https://support.10xgenomics.com/single-cell-gene-expression/software/pipelines/latest/using/fastq-input): +This pipeline automatically renames input FASTQ files to follow the +[naming convention by 10x](https://support.10xgenomics.com/single-cell-gene-expression/software/pipelines/latest/using/fastq-input): -`[Sample Name]_S1_L00[Lane Number]_[Read Type]_001.fastq.gz` +``` +[Sample Name]_S1_L00[Lane Number]_[Read Type]_001.fastq.gz +``` -Besides that, the sample name given in the samplesheet must be the same that is present in the reads name. E.g. +For more details, see -```console -sample,fastq_1,fastq_2, -TEST1,TEST1_S1_L001_R1_001.fastq.gz,TEST1_S1_L001_R2_001.fastq.gz -``` +- [this issue](https://github.com/nf-core/scrnaseq/issues/241), discussing various mechanisms to deal with non-conformant filenames +- [the README of the cellranger/count module](https://github.com/nf-core/modules/blob/master/modules/nf-core/cellranger/count/README.md) which demonstrates that renaming files does not affect the results. +- [the code for renaming files in the cellranger/count module](https://github.com/nf-core/modules/blob/master/modules/nf-core/cellranger/count/templates/cellranger_count.py) +- [the code for renaming files in UniverSC](https://github.com/minoda-lab/universc/blob/99a20652430c1dc9f962536a2793536f643810b7/launch_universc.sh#L1411-L1609) + +As a sanity check, we verify that filenames of a pair of FASTQ files only differ by `R1`/`R2`. #### UniverSC technology configuration @@ -92,8 +97,6 @@ UniverSC automatically updates the barcode whitelist and chemistry parameters. U Currently only 3\' scRNA-Seq parameters are supported in nextflow, although chemistry parameters for 5\' scRNA-Seq and full-length scRNA-Seq libraries are supported by teh container. -Filenames are recommended to be the same format as for Cell Ranger but automated correction is attempted before calling Cell Ranger. - ## Running the pipeline The minimum typical command for running the pipeline is as follows: From 1b010843723a3d61f25f427332ca4e6c536141ce Mon Sep 17 00:00:00 2001 From: Adam Talbot Date: Tue, 18 Jul 2023 10:41:59 +0100 Subject: [PATCH 26/34] Remove duplicate registry setting from nextflow.config --- nextflow.config | 7 ------- 1 file changed, 7 deletions(-) diff --git a/nextflow.config b/nextflow.config index bdfb7672..a86e4add 100644 --- a/nextflow.config +++ b/nextflow.config @@ -237,13 +237,6 @@ env { // Capture exit codes from upstream processes when piping process.shell = ['/bin/bash', '-euo', 'pipefail'] -// Set default registry for Docker and Podman independent of -profile -// Will not be used unless Docker / Podman are enabled -// Set to your registry if you have a mirror of containers -singularity.registry = 'quay.io' -docker.registry = 'quay.io' -podman.registry = 'quay.io' - def trace_timestamp = new java.util.Date().format( 'yyyy-MM-dd_HH-mm-ss') timeline { enabled = true From 2771a59e38f2daad42301c830f5b6048d8a9618e Mon Sep 17 00:00:00 2001 From: Gregor Sturm Date: Mon, 7 Aug 2023 09:35:01 +0200 Subject: [PATCH 27/34] Update modules --- modules.json | 60 +++++++++++++++++------- modules/nf-core/cellranger/count/main.nf | 13 +++-- modules/nf-core/cellranger/mkgtf/main.nf | 9 ++-- modules/nf-core/cellranger/mkref/main.nf | 9 ++-- modules/nf-core/gunzip/main.nf | 10 ++-- modules/nf-core/multiqc/main.nf | 6 +-- 6 files changed, 68 insertions(+), 39 deletions(-) diff --git a/modules.json b/modules.json index 372c71fc..dadc4ad7 100644 --- a/modules.json +++ b/modules.json @@ -7,66 +7,90 @@ "nf-core": { "cellranger/count": { "branch": "master", - "git_sha": "2d67954880926029c0e8dddf37b340bf7127a878", - "installed_by": ["modules"] + "git_sha": "716ef3019b66772a817b417078edce2f7b337858", + "installed_by": [ + "modules" + ] }, "cellranger/mkgtf": { "branch": "master", - "git_sha": "4b7d4863a5883b76e6bff13b6e52468fab090c5b", - "installed_by": ["modules"] + "git_sha": "716ef3019b66772a817b417078edce2f7b337858", + "installed_by": [ + "modules" + ] }, "cellranger/mkref": { "branch": "master", - "git_sha": "4b7d4863a5883b76e6bff13b6e52468fab090c5b", - "installed_by": ["modules"] + "git_sha": "716ef3019b66772a817b417078edce2f7b337858", + "installed_by": [ + "modules" + ] }, "custom/dumpsoftwareversions": { "branch": "master", "git_sha": "911696ea0b62df80e900ef244d7867d177971f73", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "fastqc": { "branch": "master", "git_sha": "bd8092b67b5103bdd52e300f75889442275c3117", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "gffread": { "branch": "master", "git_sha": "911696ea0b62df80e900ef244d7867d177971f73", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "gunzip": { "branch": "master", - "git_sha": "5c460c5a4736974abde2843294f35307ee2b0e5e", - "installed_by": ["modules"] + "git_sha": "e06548bfa36ee31869b81041879dd6b3a83b1d57", + "installed_by": [ + "modules" + ] }, "kallistobustools/count": { "branch": "master", "git_sha": "de204d3c950f091336539ad74f0e47ddffe69ed4", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "kallistobustools/ref": { "branch": "master", "git_sha": "911696ea0b62df80e900ef244d7867d177971f73", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "multiqc": { "branch": "master", - "git_sha": "911696ea0b62df80e900ef244d7867d177971f73", - "installed_by": ["modules"] + "git_sha": "a6e11ac655e744f7ebc724be669dd568ffdc0e80", + "installed_by": [ + "modules" + ] }, "star/genomegenerate": { "branch": "master", "git_sha": "603ecbd9f45300c9788f197d2a15a005685b4220", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "universc": { "branch": "master", "git_sha": "4b7d4863a5883b76e6bff13b6e52468fab090c5b", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] } } } } } -} +} \ No newline at end of file diff --git a/modules/nf-core/cellranger/count/main.nf b/modules/nf-core/cellranger/count/main.nf index 0a76cbd4..d7a191fc 100644 --- a/modules/nf-core/cellranger/count/main.nf +++ b/modules/nf-core/cellranger/count/main.nf @@ -4,11 +4,6 @@ process CELLRANGER_COUNT { container "nf-core/cellranger:7.1.0" - // Exit if running this module with -profile conda / -profile mamba - if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { - exit 1, "CELLRANGER_COUNT module does not support Conda. Please use Docker / Singularity / Podman instead." - } - input: tuple val(meta), path(reads, stageAs: "fastq_???/*") path reference @@ -21,11 +16,19 @@ process CELLRANGER_COUNT { task.ext.when == null || task.ext.when script: + // Exit if running this module with -profile conda / -profile mamba + if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { + error "CELLRANGER_COUNT module does not support Conda. Please use Docker / Singularity / Podman instead." + } args = task.ext.args ?: '' prefix = task.ext.prefix ?: "${meta.id}" template "cellranger_count.py" stub: + // Exit if running this module with -profile conda / -profile mamba + if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { + error "CELLRANGER_COUNT module does not support Conda. Please use Docker / Singularity / Podman instead." + } def prefix = task.ext.prefix ?: "${meta.id}" """ mkdir -p "${prefix}/outs/" diff --git a/modules/nf-core/cellranger/mkgtf/main.nf b/modules/nf-core/cellranger/mkgtf/main.nf index 5411b0fd..e0b0dd67 100644 --- a/modules/nf-core/cellranger/mkgtf/main.nf +++ b/modules/nf-core/cellranger/mkgtf/main.nf @@ -4,11 +4,6 @@ process CELLRANGER_MKGTF { container "nf-core/cellranger:7.1.0" - // Exit if running this module with -profile conda / -profile mamba - if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { - exit 1, "CELLRANGER_MKGTF module does not support Conda. Please use Docker / Singularity / Podman instead." - } - input: path gtf @@ -20,6 +15,10 @@ process CELLRANGER_MKGTF { task.ext.when == null || task.ext.when script: + // Exit if running this module with -profile conda / -profile mamba + if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { + error "CELLRANGER_MKGTF module does not support Conda. Please use Docker / Singularity / Podman instead." + } def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${gtf.baseName}.filtered" """ diff --git a/modules/nf-core/cellranger/mkref/main.nf b/modules/nf-core/cellranger/mkref/main.nf index b4b9c547..986891b8 100644 --- a/modules/nf-core/cellranger/mkref/main.nf +++ b/modules/nf-core/cellranger/mkref/main.nf @@ -4,11 +4,6 @@ process CELLRANGER_MKREF { container "nf-core/cellranger:7.1.0" - // Exit if running this module with -profile conda / -profile mamba - if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { - exit 1, "CELLRANGER_MKREF module does not support Conda. Please use Docker / Singularity / Podman instead." - } - input: path fasta path gtf @@ -22,6 +17,10 @@ process CELLRANGER_MKREF { task.ext.when == null || task.ext.when script: + // Exit if running this module with -profile conda / -profile mamba + if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { + error "CELLRANGER_MKREF module does not support Conda. Please use Docker / Singularity / Podman instead." + } def args = task.ext.args ?: '' """ cellranger \\ diff --git a/modules/nf-core/gunzip/main.nf b/modules/nf-core/gunzip/main.nf index e7189d2f..73bf08cd 100644 --- a/modules/nf-core/gunzip/main.nf +++ b/modules/nf-core/gunzip/main.nf @@ -21,10 +21,14 @@ process GUNZIP { def args = task.ext.args ?: '' gunzip = archive.toString() - '.gz' """ - gunzip \\ - -f \\ + # Not calling gunzip itself because it creates files + # with the original group ownership rather than the + # default one for that user / the work directory + gzip \\ + -cd \\ $args \\ - $archive + $archive \\ + > $gunzip cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf index 1fc387be..65d7dd0d 100644 --- a/modules/nf-core/multiqc/main.nf +++ b/modules/nf-core/multiqc/main.nf @@ -1,10 +1,10 @@ process MULTIQC { label 'process_single' - conda "bioconda::multiqc=1.14" + conda "bioconda::multiqc=1.15" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/multiqc:1.14--pyhdfd78af_0' : - 'biocontainers/multiqc:1.14--pyhdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/multiqc:1.15--pyhdfd78af_0' : + 'biocontainers/multiqc:1.15--pyhdfd78af_0' }" input: path multiqc_files, stageAs: "?/*" From 8b5707b7f11dd74c839ca3e267141372f98b34ff Mon Sep 17 00:00:00 2001 From: Gregor Sturm Date: Mon, 7 Aug 2023 14:08:41 +0200 Subject: [PATCH 28/34] Fix prettier --- modules.json | 50 +++++++++++++------------------------------------- 1 file changed, 13 insertions(+), 37 deletions(-) diff --git a/modules.json b/modules.json index dadc4ad7..95175143 100644 --- a/modules.json +++ b/modules.json @@ -8,89 +8,65 @@ "cellranger/count": { "branch": "master", "git_sha": "716ef3019b66772a817b417078edce2f7b337858", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "cellranger/mkgtf": { "branch": "master", "git_sha": "716ef3019b66772a817b417078edce2f7b337858", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "cellranger/mkref": { "branch": "master", "git_sha": "716ef3019b66772a817b417078edce2f7b337858", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "custom/dumpsoftwareversions": { "branch": "master", "git_sha": "911696ea0b62df80e900ef244d7867d177971f73", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "fastqc": { "branch": "master", "git_sha": "bd8092b67b5103bdd52e300f75889442275c3117", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "gffread": { "branch": "master", "git_sha": "911696ea0b62df80e900ef244d7867d177971f73", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "gunzip": { "branch": "master", "git_sha": "e06548bfa36ee31869b81041879dd6b3a83b1d57", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "kallistobustools/count": { "branch": "master", "git_sha": "de204d3c950f091336539ad74f0e47ddffe69ed4", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "kallistobustools/ref": { "branch": "master", "git_sha": "911696ea0b62df80e900ef244d7867d177971f73", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "multiqc": { "branch": "master", "git_sha": "a6e11ac655e744f7ebc724be669dd568ffdc0e80", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "star/genomegenerate": { "branch": "master", "git_sha": "603ecbd9f45300c9788f197d2a15a005685b4220", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "universc": { "branch": "master", "git_sha": "4b7d4863a5883b76e6bff13b6e52468fab090c5b", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] } } } } } -} \ No newline at end of file +} From b39bc2d8b5ffae48656d573c3bc25adbd67810df Mon Sep 17 00:00:00 2001 From: shinthor <44301097+shinthor@users.noreply.github.com> Date: Tue, 15 Aug 2023 19:04:19 -0700 Subject: [PATCH 29/34] fix typo causing empty version imformation for mtx_conversion subworkflow --- subworkflows/local/mtx_conversion.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subworkflows/local/mtx_conversion.nf b/subworkflows/local/mtx_conversion.nf index 10b29b07..9bc9cff2 100644 --- a/subworkflows/local/mtx_conversion.nf +++ b/subworkflows/local/mtx_conversion.nf @@ -39,7 +39,7 @@ workflow MTX_CONVERSION { ) //TODO CONCAT h5ad and MTX to h5ad should also have versions.yaml output - ch_version = ch_versions.mix(MTX_TO_H5AD.out.versions, MTX_TO_SEURAT.out.versions) + ch_versions = ch_versions.mix(MTX_TO_H5AD.out.versions, MTX_TO_SEURAT.out.versions) emit: ch_versions From bfec9cefe31c6c1fa11d1e634c10691dc70a260a Mon Sep 17 00:00:00 2001 From: Gregor Sturm Date: Wed, 16 Aug 2023 13:36:21 +0200 Subject: [PATCH 30/34] Fix linting part 1 --- .github/CONTRIBUTING.md | 1 - .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- assets/multiqc_config.yml | 4 ++-- assets/nf-core-scrnaseq_logo_light.png | Bin 11729 -> 75757 bytes lib/WorkflowScrnaseq.groovy | 3 +-- nextflow.config | 2 +- 6 files changed, 5 insertions(+), 7 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index a90769de..a7783031 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -116,4 +116,3 @@ To get started: Devcontainer specs: - [DevContainer config](.devcontainer/devcontainer.json) -- [Dockerfile](.devcontainer/Dockerfile) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 85665d42..bbbae0c1 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -42,7 +42,7 @@ body: attributes: label: System information description: | - * Nextflow version _(eg. 22.10.1)_ + * Nextflow version _(eg. 23.04.0)_ * Hardware _(eg. HPC, Desktop, Cloud)_ * Executor _(eg. slurm, local, awsbatch)_ * Container engine: _(e.g. Docker, Singularity, Conda, Podman, Shifter, Charliecloud, or Apptainer)_ diff --git a/assets/multiqc_config.yml b/assets/multiqc_config.yml index 3679a380..bd63c010 100644 --- a/assets/multiqc_config.yml +++ b/assets/multiqc_config.yml @@ -1,7 +1,7 @@ report_comment: > - This report has been generated by the nf-core/scrnaseq + This report has been generated by the nf-core/scrnaseq analysis pipeline. For information about how to interpret these results, please see the - documentation. + documentation. report_section_order: "nf-core-scrnaseq-methods-description": order: -1000 diff --git a/assets/nf-core-scrnaseq_logo_light.png b/assets/nf-core-scrnaseq_logo_light.png index 325ed32b1b62a2b2a47e323101d694af2f817c3f..5e5ec430880def739192d05acf90d01c4bd6c8ee 100644 GIT binary patch literal 75757 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�ev`Q}H7y#R1zKkC5n?0_OP7^FqWWeXhX0t0pNK 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

    )bNtXB<>| z?zw$VG?;}cA_WMLuWxkpU`bqq^-gI`l!vzyJIgmqm5DEFjm;@^zl*oW_s|8wm8e*b zz0XFbT9w}8+|d^`xK_6-vkAYgt=Keh)4pg{f8qatTnp1$c}kL8Q8Mn_uNQo(tIlKi zpX6ZQc^`-|an(4vp*vd)^SNh=Ro#iKRpvBh@*kGgjw6S?q%KHqoeH6(_1wIA`lV^z zAiRs`A3r0$<3C?@`aE7#*py0h!ZV&RT$9)V_a4o83@+F_%Eo_IXpu`p#0RmnkYKV6>PRTk%i$*vH0e2KA$-EIE^&JXaojXAE*53ZKr9x)`Qum z7UB9BUT@5(waVq@friz=*QwcTSIWnOG4BIs|6G-zA;m{oOAc}4!>le3X(;(rUNgef z(7*5!tt5aZn8P0!173!kFHC$!crh8;jTxMQSIE;}csC5F6Vx;H$&(nH3E%(&HAh^MAf}e0nfSMQPOniL_ z7j57+Bi!(wmiNfn2t9a|2C1x>?Ls7;Mf~#%uyxQ4XbR0iiZG~93)7HJPQ|COV0;>D z#;*;}%i>vM=bScHgBHF=!NCGns4A2;tr8_sKh_4a@ zt{B5ZWXgYDXOdJtuC%DBe?Lald9&;{9%iclNek+#CCvfe_-`5NJW@!FZA`&&O&=p9 zUwlVLYHm&ldOFGYwv^64tn!6!H32EqrT>2?b9bz=kKq{R5PdaZBW0#`LK1sQ18{uJjq4Q*}wb*uTa%(>{4%;VK01*KSq zh^qcE(^@tu>pk>REghc5E4ZPCWk%EaO%C z&%%0tbPv5YmqdT&R)}mL3i4XV6jvmR@TXK!7qX{ZJj;Gln!(~06Vc5%7Z>XGw*|CW z{3(&T7JDu_+<_&!Qbi0h)Zwm?Xj;_}Cbifn__LJbIWH-7#rR}P@spEbTfxO^XYW%M zhJEnJEAHE}H`p5>4E?|@|MY1)YOBU;fR@a2X-nTo)!{n3Xe8yyJAvAW=7UAr+^*hFU0;)||N9fTIy zB@~>=9fZueR+b%uo2$%=%7YAE@|9h4K3Gnr3xsLX&S#8Hmt95P4}F2SFI?k!cZE44 z^2&Ay?B%9a<(R{>NER!X`!cultn!S|gQPK!EeGM-a%y_zD!WSZ*gKbs4pw(8pY<-^ zZBJZw0{4iaQ9^ zT8kD}ql$!cJZi)g!$|5ll7vYeP!8VLd+Mk=2qkg8GX(MjA-$f&*W^R5TcrikeH_3g z2RzjTDrfB$SYPI)M3L--)_uH^7i!obxP{DPi zM5t48>!<|&hzBc#kyj=3dbup07F$XBsm!&;-|?ih7;FeG61KWhHgd-0#CxaI2<~64 zohOXU9U8pb+TZb2+zY+0l&eo_^T46u{q~Ue|CxIAMORWHakreaG}#%Q%Wu`*Og7GV zU(<`Cn@pWKnelXBd)xB7O*ED&nM^4DsVG+&`L>C}E7;)|eoNuO5us;xlLaK?UPnWL z9oIsOax`n6NWdBgeD0uZkVvFNYZ%?+(*c2XdpL?3?WayfRx`iGtCGnq$3sx;Vx(au zeMO66%Z|@fLcKSiZ}rdp!ka9fSR9_AmJ&!TPG)LeAcVXh*qv(ZH>Fx_p?Z7S7nWz) z)ey*k3!|#s(e?>@K9M-NqOo)0su5>}F+r^NmaMFtnvw_?(x_3SS5a+IXoVT<|7f5n z-$buLmMlGF3C@o%cq8VqPK?AJsprrN^WyKE4no3s8pPF}Mx72q;$0I|xYfakYG_Gc z357U>Rwm+~cQ?0o5ZVLAvyHORs^qFRX=&JXjNyp<-C>)ib3q~29*v;gHnL2YMhrPvbt=vSuYW4(cr@f z8=UnNlqNf&edfv)#HSxS=HRS5$s<37`H)w=WnJZkdw)=f6Q~4HzGpHu=cCi6ALdP1 zOCr9WAv56gk*@9&ED&R5pq8^O508?s7~M)Fejy@&lnCqs11Ju?5*TNoMVw8rVifFj zD0Up1el31t94lNCfFJZE_M$Bg$??f}Y%#sOy>j30VgauF7cy3Jc`~NLc@mm zb8?LBF*sBh>XCT{wRV0tuIBgEOClz^!hqnpS-}56WzSQ*Z%VqH3wb{?>5ydo4tnPU zxyUu-egF3R#hbM+cj|mFzLvWi^Qho&TOYdh=><&`I1208d#|_`Ht* zfRdAjL*2={gxY5jye5M9Fzx%{!{{ykj`IBreyhrM>4S#a(B$UT4niMF_`CmYdt<}! zv8TF&?0Y&h^K-)qPt6Bqvdv`30^U!{lAW*_lN~5#lp;HEsikw`{me=8=mP$JDi?Wt zpa#P;VlYn}B(4JBW&+~lL7B{A@a#9uw?wkCvgxV=oB4M7kt}3Vvit@|LV5W!K?I|L z;3>H|#C-&2vSf0SPNeU_A;)l4Y=bTzbFMEopMuqayJ>Lz%MeuS)id4_(^6#Vsx^#o zqJb}O-d?j;t$TRbuU`6g@^K<|lER|I)?xgC5t-FXN4tI4sFc_8?ck z_s6pNjh^u1IPD}Zwz6z0QHJgOnmH*Tb6H$7o)*DF6c6r@K!6SodT)WI{mhGGYJ}Iv z!G7g_coQcvliHBmNaKOzCs7eL*ZUIhBH6^Vh1?Ut9Hgq~`^Uy{HQT9hx&FUXSiT-x%ApC;r_aezH z5*`hvJZYm4$ztvx)wS-`9#1_?{hdO*b6x)e;_Sl70nEZD-K&s5e7azHJS6&nIr0Jy z?hX=4@T`nG|L}!jp#>f|MKlg4`HoU`vDo%oI}t>JFDa7b*?2-Xjg7j)tL_sR)!fA4 z23JD&1o4a40%LCb>_Aj+KL-dDo6-q&IyRM3Vtl zU6Y4%0zY5B3a3h_CFR^*rw14cAhz554#zc6UOiEcHj1tR-a)J!uynF>Gtjm(L5vac zkXVJ}Py~5D=3bgQMWH~wV;yehqYQ&q*5boqKlP*5;s z`X$CJ`Am|30f|^+vYK=ms{$_?=mVJC$3(L1Ny~P_IR~dzTaL2&%qKA?v&>rSREbn1 zkzOFc&M>~dF3>-o5p){uFYMDUgU?T*?8t2ujbV>sTsYHiSGuKX-cIu3QDPS6oVyA4EfZW2Xu4$^yXXbD|MOyt_HljBV9W z6`249m?4$_7Z3xlgJsFO8%4&}bYl3;ZyYtwQ0-PxX`kA^+oQ_p*x74by-6~1385-` za4&r=N%(~UHR7s(Dk}VPdPzeDZiiDz89;xt4p`a7Tg6>H)D3wmCj|!yibe7T{AVh; z*4=`{Lh%R{UP?R~u#_Hh;B9SUj(aupz6921>-B58q3%Q7{#bHcIb^a=%!{q|0`7%`CQcJU~7Riz({dUF&@K;~-%)}AK|MpP z6Vq)quNDoPAyEd~Zbr-yWc;Z)i+Ff@&0EFP-0rD^+#qCOLB+7J0{)#VaJAHF?AKT} z(v`Yr>SbyflDqkG5@ggM7A>wpIw7u#q*V7aSJ^-QJIP#+3%@TSRBw}~2Sq{JXiSHN zCvYnL$RPDV$sdq;5H!BCyKVExK{i3sTToWE`yQkVVmeuft0<@iSmwbkZ&W0`8Hq}1 z8pY?Q4kVmBAl-6C3703W%N+{L$2-ptYO!Xr_!s~_mYIKk#TD0f#l(r)50*1O zT~}6fshz-2@bN`%=&ax6Q3Rtco!>Xw+yDk&7V_`#v@)#s*R1XPkO;Kw|0ka~6a zdfJPaG8moV6TDf9k{=LetjpsNUZc}^*~h?omwZo}fmCQuOonx^b(n-}IZ3?t4W_#PZ236ID--qTq5GeclbvmU%r!C#T|19f7bM={LI z<$K@Ay!9H!DU!u7g?@d<%}CWobKJz-j;*zV=OZy49x4J6K894zlL`2^25M^|_z#AL zXRIxR;0&gwh`h+Me|Am;a4OM@*YSZ%LB0eoh2dUNAF~gb%BmMX2lz)ubQF>z&k;|v zXuXMHT#4$qC6F(|-5iTQ5?njvOXssIn6VZBhjT-nLXa_9J10)*#OMc(E~FW4_y!tr zpyow~JQ9{b<=G(42t7}_U*5Jis{Ng*(?eYKObubVVF;gk1;H1)`_hAs*i5FhyV1qL zn_mH!s86VWez=1m?V;$Vt0F!bK8UlrJ+X$$yoR+V$RpVdzGVrSVUrMb0r)I=BJkO% z_;ZL~1d55oZ&JGEJ7*n_=(lfD$}1Lk%(0H%06I0>{Em<8P@p2|9wmtwi94%en3joo zs5BV`Jf6IO|8BL{_3tX)rCp({-nhh}lkUihBo@j<`rW%CNRvD3+-zQN=HxCtvKuP| zNIYrR(!Tx^zCmRB+hK=BhiGvJBknGgf?KLqy8EO(XPvTw#;&~3B2aSu>7@gR1*ApI z0LrjP!rn1=%VhYywzo8Vfkez_K2wE(bANl+7!(j-Sw4~|2#VgPke%2TlsM#>2O zLM}42U(mDn^%}D32eRO)0Fs^#4_|RAO#u$wk7Qv?pvUbXdt{J;J3n6>YPP3zAc%2| zPvr-S$1_O%i!FnFDWk38P|nv@7)5NtM)P?EpeFjkip85!G?Z>Kt`3TKiU>k@Ntcr2 z#P?Bns)Ks){v6ddC*TseBo`@*_fg`m*AQz7*N~vkU=p*%bz-r|l&0E^;EHG2hogJ7 zCu*dN>lLXcfPHZSc%61JbC4yDBXEzmnAxoc&$#U`**7>xwezv8^?kb+LEiUk*vCQ< z7L||Hhfe6z;xo~-EvoBw=Vec1^%8ZRv&%|J+Be~9bP{&_y^J(7RzC_{lIY+z4=tj@ z<}I-`VGYH;h+>$^M(_cWr_3@9AZT<{dA$!Xh+&&#MKY6opZk-mKsA(SpLEx<$y^Cn z4gkx||C00p3n8eH*|2aioZK-IBa-L-fWcVn}SELDwx)Jllb2CHe3m@i&x>cGr9Ixs~!M zOG^|wxxkH`PTJTw$Vx6q7Ax79yy+6I=BgXb-)k6Y82cgezic&j=wqQLOON1tK{+=X zpWj+L2-Kss&cf)H4VjJEQG?~4_z1!Cfu8!z!_~*+8S%dTn}^P&d(*_}T)uaQKEDMB z0M~w`LHBpvNQK~#Louu+Jzk=+1pSQ(JmX9iy~{1i%Eh*0F-nab-tJ2*b{NC1GBZkm z<5WTuPy?R>lK%5c)Rw5S8C1f%69VqqvsTC+|9xOtHLX(Gm(+n1R|+kgDIR!cZe^SRw}7d z;1&em1-gDV6g*@e4JNquZCras|!I3mmu2_8wnNe^b(RX!YgJmR@kpN_+ke zN`AvRg&|j zlt6_`N3vKGh+P?G>H$^=Hk26yRz|@`CzS8?a?UqmvhMU)n#Q*q&hVAJM7=7`g@9pe z89^<=G(sm_Xlz7mRswoTyYz60oQcfIC5`WJn*c#XDC%LR1XncX@lk5zthKr8aWR6g z*hz(MArpKerN|aCl=H|}N;ULiw!VkJdB6UT&f3!vDrVG_N30uZJ*3FGavst7@RE(% zQ3-P_&_?8bq2tAqnG~n{@01>-qa3GMUVkVib@76t>i+aY#M?422j6bHc9ILyvS*B> zQQ;hTorEx+5%Ejntqj?MpK@L-A>*grn3}Xmf~eL9A<3fu@V^M${v%Mb`npo{-kWab zY$g4;waJ-CY5_)}&t6?C)$H8ON*&Z{gA*WkD2AnI$WqGr+dDx4Jha4IECI7ORlX%xLkM2S>PMcfQAoTHXiHgre$Ng``C+UO#Tf z%h)nwFM(vfd1`y)$+e<9#vF(0WB#2seWeOrC8+#Sznrt;aTFq+VHge(W zrLULV-9kwxSkZvb=A>{4q$?@Los{c>y!(<4Z}}x7H_1eA)Vm2%hAVvAq&Gr=X3qss z%ZI$*`HOR832P|h_`UCt@YeCB?vDk`1ijIFpj0~S;5t0+y?on^xUzWvD01NIzw-6X zg!GOMi0ue9#H92NEiey6Cu+B^icR#ZYNp@eiUFO?Nfr7Ruph>k>z8L==o+C44y|SzJlM0I*>xbKB8ipr}PC$Vq1>q1lcQUVmYSy6QkL>A*e-!H* zE^(h_rDTROBbAFN7eq_a_1wd0CwYNzI#a@`n-!AuwhhFxQXr+>8N&+;k^;lb@8IM0MP++-^ot&?qrdT% z@mt^g{?3Z;HrZm^T9}sx)ecIrLxK@CD-D*|m9|IDBSIvWPqVHyJ{kM@xVB3677f>}YM!uoen+4Oz@ixxU4lLhmdnA5_Cq zn!eQCP6VBdu#5-q++!n15F&4}luzs{UuR55zOLgFrsna*>NC!J?Cp@C$r2nxuAoQ6_@4>i!6BY@q3nq~DerN>eBtm6*u#Q`uY>m(|fJDWc zpd*|pqn5K+7*%^nTL*KYS_V1t6%vq`ecJ&{84B}oF zCzG?le%RKJAo5Za*j|fNy}S>y9=!0XA^r$uwZD_MT)i18>}k80A($6~-0{+6T>DhH z))3w`G*u{EYE@%Bnl`c);H`-I_l(mxT>~H9CT$R>H^+UeV*&En!Rqu z{b+UcK~w&8PUYTj?1*4Qo4e_xVehcV!aJ`ri#6`$VfW$Z)xp#{#z~hsQAf`=ZCNL{JQMT4Pss0(=nZcMfFg6F79R(b&tT1 zA~R(|O243sb%AyG9^}`bKkgKq*>=nPf)x~SUzz6ij(RZ7+V`Tx0@d|mcE1L^^tM(30<+-Ybq|(J5AS4>HfrK@Y`q@59{K__?e~yDbZ00uR4!EC zK}u!5t72Q@REmf9ef}1&kj+`|1rPau?7jIrl>PfZK4UONMpDRHL#i98?0em|B$Q+) zQT8>BeVJ)N36)ZVC`5K5`!Yqe3_^pfgDhD`_Wg5C-LLokdjA36U%totI669tYpyw; z=kr`2=i_=_5Za}Sex-;&qkqB5Q9-pt%Q;$H4}%6UnTI4on}gW?(%!DFWoZ=EGCpt* zA_EhZlVk#AvmD#tCc7&rE;W-^$Ocl&jp6i51J>JOdEE~rYkbYC&s?n2ZSU8aT$fV3m1vghu|HooU*9d$mj=qkNt`t zt09T4l}15z5`_?{5KgWRKY{8msqooJsdc2QUEvPgDtH2qvQ17uH-kH%~UDuNJB*J>r zWdD@;EMV@Vpl$=1F3*4)F-F|}7eb0dU;eBb=ZdQOLfCGJLKrGRod*-BMr1NtP^eFs z(zTy-69%$DfYw6hdGvnd+py_NCX&}?kFhVf03X1YG3(0~9=>|_qYTzRpf~N3mtHDj zov&+iU%NwX)?`whbV>vuDa`MloDICHzmAVfm(JJG5$)4xbJ?-JE$igIW&Tx&N{w1_O$@d9aW_|(P6L3-5(lM!ysrRXefvNgJ@v9& z+9lgOcQeTO%f|A?^|}+Yt0T-IzB7qYEd$Fh#gZ0!)?HO?-fevF4qsbzYhI&_|_ zuIz9_P-*_`X3O>A>7|>ksJtzA=`eW?xc z4D>)9o}w;7fdRJA=eDadG=(g?lW86FIp(QY+1)wFV^Pr$jQBv(r|$hh10izTzmn`$ zMpO{u&!ikCIOYYfcb=Xf%MD!FSmoo|Y}n94Z!}b8-kBe3(j9Gn?mG}C(Tl#g?DqX6 zZh$LY*5mv8(M*YpE}_AaY8#h`edpbkscV69lJVW|2j6YG;HY6j|A`GvV0%0LaB-po zDFGi=t*g7w@G?Q7-t>%L`wtgjmc1^R&6Ecg@|{r`2szd_BGT4=vd3+mpdE_GJ$@+N z{+|-~$N{HpEO1NSczua0AE@-5-}?R6hO^xb{q|f)3f-SCz5TtZU|$@xS_0+WQ9}vP z7K+wL%59Z!eoP^83M@S=7W2Q*ze5>QcCbQ|P7*+penPd-wWI8WufG6l<0k=FPYJE=0XC( znF_yB$b^iG!I-)EaB~3lS4l*AIim*U%=Ak2%e@Yl{*{jnGRA1tk!=n?MoI%q<|4E= zBD8SQy>TweXPl8m@G-!>D>MyJ;9QH26m3NEuI7hfgEwrp>7(Z#!QsmolFf(a|DH9Hcmj>#6@|ph73*Q9&v+($HT%af29Pe(xh$l zZp29Qy^%)BE5QuSefeRr@UjN_j0A41zN?Jy)2jo2Dh)QMG~@_sDT?kx%~XE2PCX;O zbKg1#@VH~Ns~dif*-C`NW16dLkl8dF&+r1%#~Q=WT%}Z@8P61hj=l%gQZC5^5+dah zUq~7cU9+;@zbF09uOSPqHR^33DL$N%*JDb=K+W1CnmnhHej5i^o7K~iJc(Kz_A^Vcz;E37$N>!^d0 zS*WcfKF==mCk=vE9=`fy`j} zJB53Ncb&g(DHx$_^l)5F6BlOKS?8n zGQ3~Ssr=L{{ugSRuY^?tBTR-Qgp_35*mNzi$W+Z&IRPBLGLbtFDUGvEPpTo0u{O6( zC8Q|YE{>39L9#@szM9|xXTFd((mDisfB1)}kXZx8)nNh-5REUc!9gPb1c|mC0Nnfq zod_(EmljA;L&m-{>n`Uba9?y=@Q0AbmvT!>XM1>Xm?VT4GZa9-9EBrRnf2%LBT~CXJdqJCi9zQFjGi0c`?!PNJ->UR5Z^iFj#s;>)axt z*5+xYbV62@B_=Yh;ZHTd>$RC$W6iF7-}%d@UsPZ*u~0veghn;}0gAUikO;SOCrAEr zGZJFWf1f%#G2@(-YN+UcVao+LCAR`aoSs6%cS!QH8cLDWgOCi7?#w0e5!4`Nc!4UF z07OnrwFhR0cV^hL_#bq%CdyM69QovBVDfY~|Hfc44?*7zKGHa!vSCNPKw2j#%V$UB zq5Bd15QpgY_Os#9AhFzpDA6ZY20#^;n}G40nei}50VT}KA4tweF5MdrPzY>*J=Op(7KJ5 zgUW+i@IRXPu*RLzpZx06Iw6&i!C-)lei!v3F!e>illEHFQ*hg3W!jan8Y_|o41o`4 z#oRKvSiROao8Vxezv%S~NzyZUq-7j>@p~iuTAtDw2TwKTn(^><=w}n)Ox5v$fwq)` zLI{}r?Ug?S{6XIfZg!8;e$viJI{D=#^6+_3hL2=M2MxXH>*o+SepL?G4ZQ)~%f7Z( zo2`>i&oXlXMAXVgC;4%2vQBp{dThghqsE9kO+UTj0JR~u&jKApaQ--U4`LbfvLpL~ zOg1C#hsKD3iEY2A zI@W1mWD$%kLX-60zIw$9jsT^8ZEZvvK zh+)y+UvD>`Ql+Z+w_(w5Xm|VG%mc07Ptebp021&g*tCiNWIxUSakEY>rgyXvUH=40 zDM_k)ee6IV^M=9pmaGj>UHFFEq=Dk7fL{*}71Vue9CD(m`b;HP*~9hlz&un(#mL!5 zVcBY~!AB^x7UA_}?elCla&s={^cQ(t*Iy>}5Ga^MGK^vyUPr%lyXOI_It;NdKBIlI znJEM_#odREdToKPgP@$MB=Tnhk%lmfziMPqbB(0Bx$YKP#ZLPQtpO8B%ck9@bb7l_ zk?KJDAzNCBhdGuz@B8iag#()=okFK%c9kwJ(WbXnPucW8Xcx_twaEQBuzj^M)OwQ1 zL?^3st1w&lwJcKQ-g-EGX>hCYLLKjpZVj1_7hSz;3C>*sJp>R}CtTa%GL(uh6yr*d zCIR8~6si5hwv6v1#OE&h4Z><#l z)8q0ve=6duYER!uYU!GqHEHv*(##;CPH9zk+igAcY2YsBYWj%1iFe72EeOVVhN;0j zp|ty6fT8mP+cy6sZs5YMaqG-Z42bB&b8Jc|T7=)2xu4tmKq3mm^Oeb+>v8eZnmqys zqF&1x+>hdhwas+aOFf5)I(;QNZSF8G-0gSzMk9iSs!m_Io2_fmqvx(hPl_AeQCl+b zMW{cX_4{&1Mb2kJ0w?g1Fx&u&l#@u%QN>fdCmi739)RL6`~x!6Z!T>MO&@!eC{$)Z zMLom2|0(<}{Npd`8*m-=(ci%MZy8d@%1KB%3Ggh`7=SJC?(amo(1{`i`%M*3$O`ry zbVC2LR*=Ez_EjeaPaitL4~lPTMKGicJiDgv8DZ)o*t#4HeY#KlaYDMpyb_IcGV3lX z7xf-|ukaX(WCWuno6E?480I^T{nw3)=`7n-{|j1jXLwJ*ty~DYsY+>K6`X!fp%!sz z@qb*1zO*zBsHX@d@84w26-Tg*hl~A?!(Lj;!ywEA{%`fCK>U4i>l|n`|tvzTiGJ`6LysjF+$0|^ z*ofgX0BPWc>zV%$X@BozlP`TN_=gv3Seb}A2b&?|jq>~jD-9dpt#j+Yw89J&UK{E+ zVEFa!3{nK^t~_@?>N0zkFkr0@M@X@U8yY&b!_Ra}{i)&U;(T-c4M9PHK;LEOS8@!c z^e>==Q160du^`M+Z=!@niH01#kf8rbQ-MxPl_YSAtM8;<0zQ09)87O-Js+6z#h|yO zD%4rt?DSg%>F&@!oCFlc-yajvan5_%ns`MBAEPuSe6$TNkRvQ>_?|&_FoX^j#7Hat zmr8-sM`WdA8^0;;JN;BV)o&+h-^+dngKq z8sQT=B*TN#IAj5?{?7;4rl#oA3+U~@MMS1aN_cIAgGTrnDe85q4172ny8R|q07L)L zQYOGU-`UGhrn^DA3bX>)7r44D8q!ZWy!18_npc%#E_v3n8@8^>6`E}ifPVbXXVdKc z4>j#yLY95JBBXmIR(q z+i_L`IQsul3@=tU)}ItZK&4tR)6h_Vasfl9l1_9&CZmAH+;%*H5Q&dLcIrcb>i%vp zwNSB+(ndBSB$+V#wWvGH**2s+2kX21I0S@`hW+bTG8(|wL?#0toiqY1sRU3q(z79j zq5IKQ*os#Nk1_O1pOCF_{(8CVCk`pdUd1mjaK_=Jt480hDuI<1FqqMC9-YGfGLwUV zR!UOKz}}UCAtDBT?6iCH^yAu>yg6T^-4MSc$MpyP@pnrVY>g2f$YTjS ze98Bs9~!a$mn%TZe!o$W;=WKP2*?fW zwPvQJgrB7Yr%VuE@YsTLv>;LH7IFJ(>vJqz`l=3xSZ-**rzyZHbXb)-s>PQN>f z^HQOuL4;T=TGjtOpq|9nGQ9a7bXlgDc}0X)2*2V>wG*K{{r8R(`lAB~HRPx!RBnp& z%8d)0thjWo?(i5gKf-;dj{xn*cfqCa#xQg`^LBddEotLQ^#EcLZ*bA=vH47))uZ%3 zGveQy?F`%lIe0NGxIig1Sngn4_0a)db@5y3B>P zoIgzOfA)9jJdB~Z{ZLS|slHQ?x~4#}PX>;m;#w$kC^C_4O6iBM+D=P#8LIao&mORw z2b>~rAO5?Sz}0vP<8PKk479-KJe&Jh7-$=?=UBz7=V2U)^u*H6QH`kh{UO{ggvs^N z*@f9od8+WyKYZ|iWRSiE;o>CHSRNm78Ia-molNosXPU#VXWYCCrv?}+K#)?1UH>cl zLGkbi;AwWy*(cIbqaJ&#E20^xD$Szpr(@XjZ%l`~BG(c^F-U!eq`zf$JZ}C~X~krT zu!LHmCM0g)sfbhD|GHQPhB9L)U3@BDdwDj7VX5znT(w{sZyC?ZO}=1}%+-H`1|+cf z2@jR;1<}q04t=tvvkWFkIfWm>I;kK2TRo3NGEa|c{qCgySuLnc z^%5GW#p4@moprmf z?r>7Nec)h31mjNZ9+BGzh7R=~vOZIFzy9^>6AgtM`_&(xaDMQ5E+l4oJ?eOv-)T(^ zqmQqgiqNB87rmib$DM=w>jz}dGQMM<;s zPk!$;%C?UFG|d0}kv<^%`@!D-`N{uX@JAK@r-%R3!~Zx1{Nw-Z;s5O6{|ELUmWBFH zr`#Zc#V{B%oX)n83}N~>(^WA(rbjHlw&X+yCNle5HWo6}a+~290cmp%uj2*0@;vg6 zt%c`%t>qCVxW*xd<+zzH#@=dLJTbw3IpcxI;sp)H>5Vs!eB8~-$K@Xgj6Fm7toe&g z_r6(CE?UW#WAMFZ-%N`U*5Q3NqYOo zxx5^QQjE1MRcULdDZ2NpnBV&T)<>H4&fV)PUuR5LR@J`7vvSo;vYRhdlzp<9Ti!-a zIXd=$vYIO8xdeZ>GH&@U&%a;a(5E(&dlj41Dvb_eF;^S?uMU>6D>aK{J9V0|=8I+U zI|)xq`F5sshQ3rWs@_?qAT^tGomt1QFv6565y8*Cf%UxM%m1k@!7u#^-?Zv@WAXgA z0hAnr+CujQyLJgx#ruK%jRGti+TFMxLxE*??B=R_hXNJL#u#4RN%nOY9QeC3*}}A- z*mEOv>h-Kd-eez<*poi*0j<81Y8MHzCqGSWYQ-|= z8c$C~zrL8?HqQ#uQ-B80`Mn7Bu0rhk8R{63JTKb!U*gv7 zE{c%9DKPeEy)9mwJ6b*axt>sXTbc;!RHiFG@@bx^bnEp-woeyV^uJf>&n1?> z6n_q|3wswW^}?j+L;erZe96hFed~>1MgPMEpouGgG;dnqAa-}7UCk=vydZCo!{afcEt=hMhu(V5`p^EK~=7*(H9pF!~3 zW>s8>Ou62BF5nXJkp_^Lixk{dHS1qaRrt>z>2_}Re@p22;Ui2_F;DG@%A4vC*Q|%( z3&o4H>6rW>mAGY;RAZ_gSgj|CX2F*!e_u8Vdaj1%ukDttx3McRR`o zJmIRGA4*)1Md%pyOzMxx;1GmonQyn3c3UMT0+CNR2*?l0|lZQ6@fHs>Bx0Zr;%<^;n@9#qQx~ zEVSG6ey;CCiylt5@VM0=FIBhL{$hT$^u-RgG*N5^VhkCRCbN1!SG1rgm(&T^jL=E=4;?UF7;~ zpYJlG5VwT?MJOIk8s=&7IaO4`RK~l)=+;IF>z1F0bXOeOPg1Y!v?JDr5md_rSFp4~ z^2QY$4_hqm)^rZvj;@;ONltu5Tl|jV&=Q0YQ-2(>(v@y~al~qmB?)hbNBDXC?gYd6Jf0ESk*e z<$UHzZt-Yx%vVt>|6my`2gj8B(?mU&;&#`~-F|8`C$1gW^=&ua85}0N^SxWly&Gdu-gxacrR~(36b-!59jcSN8)ZNP=b#gW89LG8E^?=)?>fr$0M``_U2DNW-a5$h0GWK=5nVYH#={FU+C#0}CMX7TAnm9zeX5P9{ zqt4Au1y0SK@WVDN}`c+FQ%OO1&`iD_%gOL%# zPGUJinh85HLV7fMj7Qjr{&qMXN`d=vuMW1+QyMu8)`$(&f-L#wXT5Ay`~7mG)XZ}d zxK`x>takd~RqSiw#2GaZM>H`G2b=CDvZ+nHjgaT@<8@nXZGG!B+O0_KBPpGnj~)^? z4|BivHPSJekF|HRm?$7-UptN({B$=$*hy?y&>-P{N?v#fens7>m}g zpWZwAi5W;UlTzO5IG$;Ug1mkwX(H6uL-OVo*^bGzk|yZZ1v9y4M4YJ{&tvz4UnB8j zNHllj{vtL~wj*a~?^0lW#U$CGwb@KxP%z!X$zpl)Nzdi8kJ4%&C{}+{DGomB_V=gL zAG{i_iqV{?zsMWrf4+#x?}XdFis6ZHJ7Jn2Rf6d6?G<+#5*og-O|UuX-t2Zw`7tRW zBY_n53W*ARq@cbFO@WCosKJKQ?b`A+*{uZ=xmD`l-5qL&_cgX&?W1cqSk|mXXp;F_ z4&Q=hr)kK}TrH|Ys+v2}I-Z!EgGu>*FQVOPEZaM~$kBF&dF!66S(~USoCozeOla|} zNkO23+pAkW`QO$K(#)y(Qr;FIr@2NVJdY?}sTdgtu5_vUua_-r#2!eg5goltSE=Hz z@#94o;+Rq&NPmRK3yIYMZDQ-1CCw}NGfOZ#ug zERoFQ#`jG!t8j8~x8*5d@|#oo)=tuL$W^(D5$R&sV+d=lo;Olq4ehNOWp|@7MUTfrmtk>^jGm9KK!maJTkP zHhVl}XsP3Ux7&(U`Gk~5E+%CpGD6B}fZ)!dWbKQPY$mf`LW83WU#W}vtWp2HxNt(- z#Gy5$Jl6PJK(>V;Szk_O=uUC#qUt%paM-u9rq8|4zJw*`t^R5y+2Py0EEFV~M5)(^ ztD_SK=5t*3u0Rbzy7Iy6n;N`slT2neLbv9b$?=F!GE42|82g%DCusIu^UHNP8b2Rn zm>4!1)z6p+KdGLRq5hPehtj|dyg;fm_jc_~*_Rr1Z=+>Hx^C7#)~qiteowHdyZ>dJ zHv~I$ih7hZPZ+*8?09lCeef_A^HS!8il983$$6LSd5lT%MBhtjqFkR3%TuIFcG2tQ zJap0%V&^6F1-m{Q_nf+lclEesy{9PdOAf6X)vRS*)A%r9EG9*7SCHT_hSqAgbP1a0 zq$+IICD{$f^a_gqEHmBe?v@MsU9h*d61dubLv!Yf6WeayJrhI3h(-(&OA$MntHTP{&fkDk`Zc_qV=c=5UBtv76bV$<))eUvK=gf?_Hz+5x_ui?C+#D`=k1MV2{VH55IvN{ZxCaL#BW?)~)sZp^ zzH58`h1HLUFaX#)iO{4vL6})z_UD)r?#6x5?3zmbt_W{d)u@udCW^jQR^36l&X3$E zjVSxpGBgFjlWme&cXt!oseMwpv8h%aUmLX}LuL8g^1zST!tdJav!30HBT`wn&OAz6 z9lkB3cS-KvdL3y3RQQ~{L7dp7zL(>0tCn|uZgYzDv&x-n99~%3U(_o2J+a?ld9sEZ8+U7J(>IEVZRB{Ac^@)-elpuR;Fb{MJyCZKV*Cp4t)R>Ia&udQEBl(4_ zmW?^#!%-MtLiw>uF_Y%DeoBzF7#jK53Qgt~B-zY{%U(bLutRjZ9Z;{0&ncHS?kvD6? zn^f(5oHVM^73-hjdQ`R%a4!YPyAi%7;qb)Ad|jB3o~DK+riyF8u1!$0{&XK|taG?T zD_)Aj%TWWSeH^s$3FSS-M;SQgaMW2xHb?91*ZIw9GMi<%aHGjH)C7(z?Z0lD$vyCq z#5TXQ$``bLt~s)G1lxaJ!1jK{2mi|%Zp%mY+S;*0bsU2-@RjDWl1HR3a1>&(s=Ji) z6(hg-aujl{VDyz+6Mr@{JwQC?n*Dxd+KiBTo&OmY9d=-F(p=Cs) zF`9^ma$6-b;_%m!x$AAoTpOn~EH4PyieqiBX$0LXk#7kIOCQ-u3d~lAeH|?F%(?rs zgnwnvwC$xfL5+GM$(LZ4U34ZE_7*jOK8C^^ix!qxI_J93dfW;D>EO1A@mF42)qoW< zXfa8%zKFm+#Awsk!H_~ESiGi{0GN3bEa^xGqZZnU+unaVv_%IQ%ZmoUwz%xpgF zyxq>pakx#?EBX9$&D85U8p@?`tq$)oj{|RAISLt8_IldmxH4z4LorU-3j#ZH%3IwG zmaV9Js!ATDIr#@`$iF(9<%^(gMaaKZ{P^Ja-4mwf*CzORZ_8=a$7ZRM6C&iui3$ET5zYGjq-9U0L=n9n7OEYX1Gp>y zjv!HNbQb0$ z?OsF%La1J+H_KO^wgjINaq_Doego7(h`}Jc`QV~iY5Zaxi8HGRcDmg2^s>$0hShcj zJ3V5cg{kb+bM#k}<#lwzr0OL^P8?9*$H9%9{m}AaZFs|dA^{{+EgIC;-NOMhCy;!g6zb%<(OhL$DBJ=hoS&q(`&|5Rib!1ZTeVDgmAX{!d)E7 zX&Gy~kH*y9fp5ERHNMce2^D{v=(=CDp-}GoFeeyF3RS(PgxrmILTbc60kcw#j1cp@ zQ4P^MiB)(g4RnF`37zV&7WnPza5Cu4l0z?~kD7G(Rd`^B{HPc47B4efj!nd80Lrxl z)z);r7(O*i{Y)?y$5TX0ZZkdFbR$V4l!GE}zWN&SeMN<^&VCoXRJOX~4F9g60+%E0 z?i%$Rq^FMCHEF6!2tOQd2ZZch{fv&#oez83-YwSVm~-s4RevPX)Nqu;OCNsUQ~ff* zUCJB`q%ShUoAA_V>}#(g+e+QU?%;hKVvg-&kOZ;Qsq=}y;9$e0J8Wv*hx=G|Xg}5s z+ztLX+c;|sU!jzrg*o6f*q;dKTVfd!eY#!JlBcnT^MBS)Yiu`_LOB>f-IJL2YEbDU zRzHt!nrmNR|BX$a`CY?dGV?1`9>cSCujtt4MeKX@J;PAT-oA@1GGIx9n+H8@aXX?q zW^p}cQHFAxZ9mQ9xnusQ`Ahh>?pRhr9mG|YB_Epw;YWvb3?=z@C0-WzyUiyY#cdS+ z3<)lJB#5vjl+*DSW`(8yW4KxAB;DABqH$;bQ8;Mf_|{}7xoxqGq^EW z`^Ssfs52Ge1DTlPDEdBC@+Ytv&EBNPvicm&dMQNdsWxS^9+^jH;WW%hxWlUmc_I09 z#qe+19A5IY^a+0Gf|V4YjDrO`ReEEGzE13Jx9vOC4XqnD_l``pW7(MFx_xhHuV71# z%4aL$MRX<(^Mw>ENxsG$SnRUEUjk2nBf0jF%IPjq%HU^+i#SU6eG%+U**@)w$cw^5 z_a}BsEu6J+PjHiQX3za?d`_A;#G-))|IS3~=XMx)IXJ=s&sgHq$kJW+3}M{HtIa>J zyqm)d;~9d(KyBLR$4Kj>f59>jHHvajv2#J?IYQZ za#{rGc~&FmGZ_jyQ7Bt#pq9gOcAr=&h>tngCTAV=vciZ-hJmx{xyu<-b4b5Fe^N7@P#4!d>on-QVr9PzxVR3E}pm zsFU+n!MyL1h&?CgyU81|Q}uJiA)4xCZG_zdUsw1Jbiy$&p3w+mZR~SL9BU?@&LiEA zkiw6Bb-$sT?ssjp#b~472@np#cJw;F<-I*MTC?#vNv&1T-tGH`horOJXRDt?MxzMp z2<@pGIf;Ej*S-rrBQEn&2IM&AxTxPL3e2{A1$UQ1`p*Tjd(1@l{_N`B+~#I!vv7*) zu2eGqT9b;IvgQ_IO^&=(VHY4!hl5-LDrodn`!q zuu^|4>+F|XggVE8mT+9-iN0)67d!hcHOj#(je6zYAMPnKQ@y)-^(zG{s+BrWd~t22 zyE(EQdz$#Ws|9y%>~VWbYwf$Nw9`*a6IC{o3{H%%A&Ui9csCl?N)yZt9u ziK`C{d|&bGdrGm} zA@&c`hYtT#vEodH-Sgr4Ros`d+21(DOPwS72jU*Q`b^FyWD5`N=ODXZJ>%EYms?{UhyZENk=wkU&Qv`E_hP| zv3t4bnHk*+GFan+)K!O`J0V^k_vCjA ze0CYtjOaKw>>KqlOJU&6l_b|!D*V-gE61k0$J5DGcD%JYE_=E^x{C(g7>nS9hriJ6 z@rsr@%KI}~^SGItDv&mPrfg&!@>wQc~ zWW+qa<&Rg7OSLhGsCG%vQmLk zXDiodgBWPXyW?0JJ46{0Y3(MVEE~6%JeT6gz2_4h?6E`V%^$k!EeBlg)`+mHsO_g1 z7wWI<4^zT>AVNE<;p`sW(ygB?%MJ`N=;nrbnjwH4+ZBo$cajWNzMol746Y8Wu9;mH z>MQ;-Ptaz_utSX-ZeFri%~q_xZYBrd;?a3SxpCe@+lQgRj{7?S@4)6ZbZI$wi6cyA zr{5m;&*b$>;m;mNlZTJEU=%uQL#msZo>3@%~49ks9@tgp5mLJg=ij+JqK_ ziNomVkn(zti>o}RpWkvt`hhSuH5F-t0T1YR&~3b-(MZ8F7OSBQxkt0OKfEriHd(f1 z^^}<=Oh1*H@935f?9g)v6sL)I|KONT=)5+no2_m%ZdTXAMRg%P#b=+KZx~Yk(w6%* zMBGj6MWKQJ_siaMcqn9Ww{(b4CnqBOcxf{e{C8$jf{(es#=P0f;q})vze>qYJ$A?t zM&YJ;5j(nl0>X_P_CJ70Nf6`8)ytwBD2@6;QmoV1OX0}j1xf|E%7dN*zDWX1Q5msv zY*@UzpSib|&qIxcV@{qrQaqQ*DW`o0%EQq2m&ogOVs1BE0tp7o{*RZpBA_Q1P7$h` z5|r(swX4tn+LRUJ@G`aUH+zn1ShnuFBT<~mD3m56uq%D1cVUEle->-W*~lj1>TH&}_){Eek~#LIWG97VF4#PE zou?185n$hMDR5N*JH$x!*xy;=Gk+2{<8;4r&^@%5*^)WPX2;l@2zfp~4!7=XAJb&w zb|F2SPjEx^VWqLbH_T_pN=u-}m)-lYLk!d>=gQ<|V0|X2P|N3b2V@Z*i2iuuWOm)T z_LR**A$2~Ls%*FWqVK|z1>>L2mY(443B*0*!BPUbNp@ zr#EPsm&F@);v?kay||`p6gyG`PT7YjN(mv9_wZ0|-L3vvlCgjI*5D@YFwK@ac5>ce zwE8>xfRqQoogc~J3~H>FyDTmEbszaGv31vdLSG%V7|Z;Qe$jK2x>bBBxq83)fK<44 zJx~6u!%rVzhvr`$-8?xzV&}4i{7ANtn!igz;a#%k7kXbL?9Ju74`Uz|-i_Oj4|VTS zwzZBAMx2~KYwl(zZj2l=2{(;)Uq74>>@%z1y<}SZm^jO8Tf~0KzW*69hCz^dSAa|J zPOq$VIK!R3Pd0xE$D^rlCJ@07h{;W4G(!wSi0Si;!^i4XNXu7+X+hK);_Bt_3K{bC zYolxAAaDDvzi5%9ZCwkMLprZc&L5oL@;oV3dTlfr#h#*P(psIHi#Z++hczGtc)~4s~UW+968VaOKo}7;(2Z1MGY1yO%rva%)X-7Yk6C6Jb#F#kze3_bs zB7>ccA(lUpGknp z0`(~&12yT~PPW!atS2>28+?)=)xjpy;rVB(U&t;}^R`sgVvf(3#iF5WmynWk81+ES zzHV-l(qA!4VpL^RcC;>SOo(%zXuU=7fHe?>v*}7jxydb6AZgzw5KMU}>q`Q*@h9i? zsZ10F`>RZz*0_jQ5fM@Z;Vkb3awmS>x2L`7?aapf4%am(Xc?eC#Mo8otXadm$R~}* zYQjtOT0az5CpQiep~@Y%B1t-o0$3ZCW)Zybk{onox@bX>WPemA{tl-t*#nIxas)AI0Hbz>5SdR4LIo=X`V5##fUq}w$xL||1TttKn=_rWgDnWOl_Q`N@4bcDHU8q87%ZkazoF{S2uOE;qP2Bb4 z=6|>V_M-_-!(*2l5@TeeBM?dFpQmb_WN>K>-VNl7uSnko#V`g8&>Ua6Kyv`8f-(3OI zBnKj$Q%-v8+HdX8#V;$G3x8A&kUsuHg?#v@EcGDq=h6|*Z~N-hh(vbu40_{GL8g41 zNK?YVOE*mgAG@lC%lDMCiqJz>s_*UpGtqc!9c^<^cz2r=PE1b@Oxoldd|eY|1oi!STgeYL)lH!N1|A% z*>t^q`_~uyd4!s0V=A4*RzeR-ZKot?r5+tujjh$`Ip#LSy!xQ6g0R%6+{uO=;-Rig z@JlTXJ=EU_#^Lb$_ji|A$K+tXa?XAxt7T#?NJz~xY-K5iLo;%SFNATJ{|lSjzR0*E zQnMe)156=IE3UXCors8A`};qqJC$+xncC;&V@`4r%a2M8Bob>GH<)SuHWpsuI=sc? zje~9#q-Shz3T>E67(!1cjL&Dtu93Cu`}JKs1uI{M9Lwc%tZlOELzKNxB;B`qN)*b) zTsSC|Z_6Kfy*U$8klfqM3R99x0x8=4#&oPA^AVdGgM69dsfUGI<%hEp&i^_??WD(I z@pk|F-joSj+4a3&$YN6S97KP09G6Z!>L~*h+k1ZnEce$SmBHSUiTVjdnBVWFeVX9^ z5LOXPGp#jfSQ|@vt&q*9oI)4FT;N65J_^#FN^`${X%?ptlhu4-s*z+@A#suE>Zk-M zmkzf*$^sS;9+i#SYj#noKq7;5sxicXcVntd)@2?>!RE)K5F9$UR zP=69vACRjG70Dk}&|Q`SDPPai{m}7ym^Jtz<+mS>$C3F1V@Csd8WjK;%WKKSoOczY zeIxf838aOG^`H9-V2rC=p-jU97dFKx$kEpGk*7Hd_rM%e`=uU9*lp<{SS)!%ez+_8 zif^KRYstga5ps|LZue>Xex{9Uxahyt-4YAkU)8txo<-GuVfNqTF;m6E^$8)<)W0YM?z<*FVr_egeUFi zC`?hTPr7kY%pkw{!Z`D9Kxrxz02_Ft5VZ3)Rd*_fv9@}+9g7X;jivPJ5~Su+>DWnp z$})m4TYc|-XYY5{`w+0F1116*%N=@8g0!K4tqyrnK}YTfT?3_e3bl|=xL$iJS@Utj zV-mO96R?(Q`G<4*d6r$DU0iSv1QV89UPII5{+%YwGpmlkXBeT+d)&t<|_~EL!e;cGXY`JnoM2p}0ONUMe{uU)wU=9&^uZK5;Evvp#-e zcV(O2sI}GeR8k-5)o(=Xn+M&ftuxVXl=(5N?YY3h$)vR!gH`D&QK{J+5TNb8!gu|N zr+ki4<90*0ldr%q(w4((ucs-f{rirx=bd?0mjrB>*Az9!(m;p(4~cvLXo5NhKpka< z?9?ML!8*}E!KQZPTJ!1-y1!$lLt`R3f6<`8dE^7&6iJ4nP;8LH2P3_r6Eb{347)aDgvD1`zdZNSe>>m`9bZ8 zWDj}u)F*n;^%1SkG=R{M17bFN_5T>Meafvc|2IBBZ3cJg8t(?|KG!f9cC|9ym4GPR2 zx`vEC&cFC330D18wGfIxxaX_0BQ*hXr9$@bQKGHV zcU^~`ciRfQ$~d8J3kg*)_x<1*=e?_#c^xbT-nraCDLH3 zU7Ev3E{Do}PMXgWA}6A^!)2+V?9Nbzl=p*9R=8)p3e;$%C(V_%TqS5?r}@u6zwNkCeUvt+inWAe&oc_6TEOfHwo$A{&cpn34KCSb)i)nkoa zw0ZC;x~!N#_YL&rhm&KIg@@j_KY1E9T?QUCDsQ9n$i@!v?&UX`;8bk>A8K&7s*Bu@ zhclQ9(wMfU zeU&7^5~gEd>%Q@An+n*x(4USL!wyA~&`xsp(P=_qC-hdnGg@8(_&-gspzu^ROgjiq zNT-X}7e6%0+I&f|lPWkQRoapE{K(;rUAJ(zUV-Vk+BwN~Js|oThmTj1d-*wh5!yx$ z#1tsBr>=@8zhgSq0Y^=@g%m8M=;{Xgw>ASvwN9RD1Z@O_}ttwpRD=+?Y?P_0_e{vltb+ z7GLGS3scT7u=&p#-bf@Q&j$N)&iB#0Z8Z3a#L`RXyAhX)C(}-pSI{%fqp%NQLK0

    X+DRpdS5v2ulfJCD2akW}ZNO)h{`k2vWatkK&Xlz%?c^MI$j?`{q` z#AU`BM$6$O@~e(FxA%QR*?Ym0!%lx=hY(ahI6LKF@pQmih$QZS67M6fo;@6$$WFvS zT3^OWfzC3RfiqBAeUDf`;B>}eAc#I4MnTD-35_lm6F<>BvK3zx~guRap=7uV)J|c%fuunjv zUa@Nw#B4gcv5<;5em~y64yuPN|W5tWg?cP0>Vz#y+;j&d`V^lPTrXTO`>}Y;#L3L{s>GSjl zk4-<;^eR^rL`L1)D+S(PmQ>Lh8UFB2L%VYL|&N*?}E5NLNAeso0 za`MU+JrY4nSg&t|IT7+^l{V(4-V}aMKOja&?`Y>}w|;$)dDYhz#4j+M2PV_@^!r5Q ziVyV*fB3Dr&Toj048MD)c5i=Tzj4^{pTFT9IgV?yWR0s6MYR1A+x5hsEJ1R?TmD!K8rHO*-r6woJutxzEh}Tv}JiIKTLwtbRG!${0bYyVT&E#R3n!Aa%;=7=AP81?3l)P z)qXe*c!2&P==4`DM$A6y^z7edv?@VtxxiC(N67bvuOKwb0Eo)R*gW#3UFOmTi{&L7 zTOf0hNv*J7;uRdW;_+jWkUKO9zL#WAH<;IMH9V+AdtP~cCEo%z;NG2^ho?-yjFj%G zj(fse5>eY@@)(X&n<-e3qQLxWh)BU5acPH_gw9W<3Z$$7v-zJJ@RZcG#3wWBpJjqc zP|c~RJ9BO#d##?+Q>DF6StAbe`8m!u4F^g4KLurBr2SLDy$X?UKH3zffvgIs)h~%p z0Iivslk#vx{hgxv&`U*Yu(G;lwQS%-vI;7Gb<}i?{)R<^(^s}^x`?@Y+frm;Usg8m zc6d)cR3`KElH8dPvWUF?u;ELyxZaq=bVG6EaeKBDUUDmtM)3-#iQE=(y_ej&H(Vj6 z7^vUaG8G7>yYksiZZ5`Wq7MJN;DJ4^3`cW&- zNqVq=QKy!m*a)|4Qd9YN=D?KdTWsCm!XD6mefkYNTkmmvPd~8&7kSL&*`tGCJTF1x zL5BC#Byfq3Pp8yz|GSE}>!4PInbpwOx)f58JxlO_kzIlGkoPCoiC?Omx#?B z1-xu&V)BX)e5k&lwZpt1vQUM+nNnS7?Gq+)AXuukr2B7AKl=?X0c*cpff82r+`Xgm z(T3(^EQR+T0do$6_NT9iEuIXJ_IQycLjS})%D^L}rp9vS%_(niV1>hAn71Rnu4K(k z&j9H-ox5+ZO?Hj$-mFP`9%&m4T$BNZBUXv#0VdKJPo@A9?ZP?n#F@S>Tp$w67eGF* z2&U}j)|hRW0%FAwkO5#zuet&^<%fVI^CkPvyVY~c?M%Txwe_!!=UPcGd7ocgIa^r_hT$j_QPwMR7p?+u6 zF~beVHm{Jh zZbSI46meB8>vtwkW##m+P*&t)oZVrMK*91uX$Yza4cb^YG0GdGE=~>0ZFr-?Qb9*k zhymY*Rc#$NFJYwP6_ud8$LMH2!5)W|lzaZLvrqY$*6zCuF|X&3Z>1@fN={6PLlsWu zbAA7i1V%_n07?3Gh#L}X$?mdhKjd-sAMn4uo}yTF)kwwBurF_ne~;Ocd^(o&wS zT&gZNaG_*B>tnisYS&)%f( zZ%hwE5LB1&UPdyT>0`=&0W*!{ zcuYk#{+qg%BVHzkAy(J^DX9tRj@mXR2KlyuMO-+-e7NEBDv7wRoM`2sq2Z0uP6Pw- zTMCflUJLeJ0>zai-8-8ko2TF}o|yai%-=w2Uw9Ct?X?as7tf>kAlo0*S6;q(jaV8; zx?}JyU3~l>XCp}nYTM&O@LL?-==;|;^N3^M_Jb0tW_$1NKOgMv6s-V3(w#_|cEQKu zg)anqeXOKsAKsGPY!t1%`uwi06m2X}?_(5=-Z#J0sN=Z)5N(Q@C_A;aPRfz8mK{?2Nn`R+5qT8P69xHw0k+(d?QIc~*B*eWJiA-dXKP*?#C)$Jm z6WRTX6>WPyr$*uhrv5LsLr}CyU-aGTp-*R)R(N@Tk4 z)A1**ZQFDIP-&uU-XGr3w3=UZn$lLv_>0vm*5h=ZBv62ZtdTLG#8)__poQU$l1_vu z=65T4zZm3}fyRKI#c?mVS}lPQ>9^|vC&-O(E6v#u$jPxxcePtBNia{~C2^?f08A|PXSQ&$-kGL8u*LCzMC%rWWGKfQijS+LBp@_q8hgY_+8)#Efa4Nf1H}H9{I<>fdiP%SC}U-$`jbkj|^B-vQLst6Jhnf*eDVWDj*?8>Dg+ zFwiz0tx+uSQ3^wB#h$$Ays|>(B-O*Z{DrIrlK#4kKC>hkhH&GyB8$@ALJY`&WfW4x z-$r66-XFUh8(V_Br@{>-BQ#V+g3yFz$!$}Y@p9VaYJ(NE+{T{@XXvgd;YEwgHH+mcN-j5LU)v>D~XgYnWY9psq znUzc*wIkR+<<1|2yDf~Ag94G(htjXpUT&ozTV$fjUjdbz4Pj8asrG-Jred?7a zj+Fur?-h{tR@r>#euDI9UkDMC!2JfhyJ3-$I@tXTA!@Iqci#RnZ7u6R`iA^DVN1gs z^In^-sYvl{Z4`r`L}jBARSR;@H_lNrz7Kd6e)BpD%?5u%$#-!|(mZ)pk@KJYRn{oh z($;OfCT%-BAJ1F*#iN`emuE8Z0kCV@-bRjApx_oqn8Tx7B;%hm%a5?^5Z%KpTlK9- zUR8slx|a0@|EM24kTk~KJtiyF|JBD9iuHQBShp-S)Ese#8CQMbw=J2(fTBjlS)1%F zb{*%QMaKYF@(r=Xee7~3#b}VuAZY}?6h|1rTVnIdynJb$Y)%4M5W-vt;)Dr|jUx39 zvqB0=Ccn!m`bRx1^7fD7*mOTWCD@69R+KxEE)GGeX6x`-alGzk&LofLbKb832LGw* zwf1@#fP2z+5BNY^647-b1ajo)sq)MPO`0L6R{3V2SU1vI2pX)}9ruRK*-jGpQ$xcL z1!MkQSWk1SQSXm*@vhGuxp%t%U?RFV!JkHS{&)mr{ULxrfmuZX0tJ$wI_`9Fhz~if zm4i>^HZ=w%DucrnfWy@qNwzsDTd`T`1{I&10_WPdGC^eV-2ns}qBnnnjK?+~{Hm;^ zqii|#ZCNQi@!+4Th0-X z8W6`=cm;Y<2q^|L7@`WIvvFUv%?MAHx$u-nxrBtLWL8WS!)XtRq5i(hjbgLY9~;Fa zZVs=k{SpmS((xq4RNA+4WX5=&hLVvCHLb+bfG4t{9;67dG9MDu)<6`wr{qfguqda2 zh2(PB*INCptkBV6Sa6PC0n42A>w#;e*MExaI?9qXjJCGvm&UtWuy=C8Si`#^NYXbL z0YPTRa2!WikZzDS0ZtKBC*|gmGAMDrt8eHTF@Qww(Z#NX8EPz#bc6AKBtXWDljjNE1k}N?6QlNbHCP5atGIgV6O%ov_kBu4z}WikHu`{ zguA!u`my6$*8QiRrBij)SVrJr#-My*I1^J^IOkJrRsjXbjeM*g<&|>6PKvCiyok9> zM10Qk-^1a5bF1@z+dh)TzW2GWc;Oe^8e4y?f+`BA@1)LOt}HE|Mi%RaH;(VXEoN=< zk9t$6=^tfW^V{JY8OaJD!dWg24MXB>1CmgL!SkuA=On=yj*!M%>V}sOvh>s^0{!d} z`K0TLG3WfMfwCDSAZeZjQJ{cX1@%H@uHaYibNs*A`38rgmRmgQyBy!WNs`T4@+!MZ ziV-U-N5@GYvDO{Zcmh9fB{*!qrLfJjJTA1njU&T4{wainXt^?K^d|laxXchTfVzV| zi_|UY3tmVqUP5E$%41e(tNKSdwRm{@f-ln)mrLPhrW>3oVwyrp=UOyGYf=s$M#?kln5VX+mIrE8>!lc`sTH4mjhZKR?c3ldk33IA84 zV%v?txuj$MQJ4Z#|EO|MTs#^AhH5id-&LbDpW3JhBAU!Cg?Cb%upn|dgQ<|h9aBqj zT3Uj&9++r`j1^w;$;2(nC2;3OI~g|z70FX=Y>o877ha(5#=1mCSjnTDqbYWim4nELY|Xypmv44<1qcQRIkG9v zkG5N~kBRP(^)!+Ds!=hpE%%{x#YW(x7X~G4uU#LMARMXpBl`r;4?~Y!dHm@e>Nrq_ z#lM%4doBu13S&HXmtFmOiYy~!d}p$krs*zBuVs93ZNqPbrK;hL5TpX?jJ&ENJf4bC zH1sx_QMt)BnQ@Xl$+Gxm^Ss7_t!EhR_#@tWPG=wM`$`s;2OD4elWV{ch7rmXS@)4E z`r0kUwnfo8;TpiYkD}=%+yOEX9@<9YaN6T^qd2^R&-mbCXWUQxWI(`5X9RuytZ z8{4o83*PiD48^j(q#JDb$w!N)ffy?KF*t06v~B;7Eym+h2EY49Mdbmz@Glq_@NCh~ z8`ZvzdK88C@woobIocHzXZ-;oi<1xGT+PHY!@v*b9^Q8g(RsjEO17MEQHn1cC%HgoL^ybR%~gaidtUY}yWtqtv1w5meP{ zA;)}BC^0-p&}~qFYbMEt-U5;h^&>@8#t`^1V7po6I{~B&(nP6f7mi^E7AvGjc`Ar5 z_V%J@fQtdyA)dxSvrzI{W-ibO0NW^ zc$3y{8(9Rp>WJgEqM!ZcfZ2XJ+gpF&e`W!;gYh!rn-^Q(7z7B;5bS|-IgY)(bd;d4 ziLKc6&MK=-9IE#Hu=V`0PQPSEW&JU&v#;I!qj+UH<|FPS_Lqr0peDLM-F}GaOSVM7 zQCC3`GcTs9^xZAlpclXxO4|I%TY6}$ML++>TV)2}rl*T%-OaFKo5f1!lZXMiXz<{$ z9F!Lo|8wKeyGF5I)g;;R-5``cm0jcwL!ORSh=9n>OpnTwqrc~@N%!9{i=tSM6{CxN zFS8JG1vzTL78*&~+-Z#gHjmA@CbR%LjkeyLn~j2alz$r3DCjR=r2HH|C4CyIkiOg` zjbDeaeH$Y<75%=;(H%t81Q}PGG^?V4cW`)CD6r38(zZ29L9ywjAkb?#Y-GHlQWtHA zrJtofyj?g8R2#j63#xDLY^DI#aR;SNz6xv7f(?2%n|mnsCE88pP9k#wl8$#7`PxNuzDEUP!Pk6my-rz7!;TB6nAiy-(>`!jcx||DMpLUiKSQ;-tCv( zFHF?l>(LD`BZzcIV~Ps;U{Q#+R**l$f77MH>ak>-ffBcJ2^j3j7C&F`w!M7}7a)L3 zgl;S1Q4GeV*@B%yA8kbzV_|&!Nb4>re*CtmM&p1^H@7YcolU$Q;zfh8n)`Ro}%;}%0stFw|OBNkHijEdGI%$55 zOBdhpx?YAf&Yx!6+Y!sHM43m8OboCj3Il1FFv{`fw0x){I2_+49lHaBMom!j36o^K zj`~MwG;vy$b;w}T{=rB&=#yilU#}(xTq2ehqDw|d?7sQbL+;hfjiR!yk+Ad*t>1-N z4MqHj_fxNU%=8hN8y)>@y2W2T|-^G zjwpO4tp+v5{V_vO{KaM+6nyvEE#73tUz_Z#B8?w-HQ@%SvUIV)s%A)glhv+~3LlL7G>B^1C6q&2uc{7?q zL0x3lOxNz_eEYF0XLk*}f_*a4o?P^y-sNk`M0PuICXKq73zt(pa`M`ODCBS*mTS6y z*5mK$aTJ~g76kwAhh`-r_loR^jsjn0rB~H;jfqygWW|I(<_()Jx$1P=VH z@#Nqu)HDZ8%R$S}^R)=6X_;-6TmvAbBpf{NLe%pnfjnD%VXp72u1>STvXuq95p3n# z?~-Yr%eym}4d?y(hUGkYTo^Qg<(cT@PK;Y2d$z+Y2gRH51q8~T=C5lY?VFyJEt2du2RF|x| zY*nrY!Y1~J2nX?$+qoXf(=CJiUVzw+woQEZ4I2X~G&G155#^GQ7Uds^;DLthw%UVU z_iBa(`yz4X6&mc0ET?e82t2&@HmI(Bt0=wO5xP~et8v~3aEs#&UA> z42KdU0aUht1{)Dmj$`YvpoyoCW)f$97~@tiUq&RWOO`xGdH4IRb36HI$l?v+;TuM; zeB=S9;J8I=qgNcxwPWJ@`oINkSVj)x7;!X4+V_$EqX9h<_IG#JgC&d3#L{4Mt0^Ko z2MxYSEZu9)8v0I1-N~GXDlF%GfR?BB3(N?=EnTWR|hClXDP9wuX#(&$zepmp8>`$&Ez32vC6t|CTi;j+? zzpCJ64VIqakQlUs&=)=7HwlLq@9MQ-kR2Q9)q0}*cik2S186HcF+aowOY1*RoatF{ z(R|{Y78w%go6unHwSm4K*MsvV%B*JUQ&mk2X4Z9XLH_fhAKkk_OGI-JkFV(x zL5W%ARu83B4VXx%84_#7PC!RN9nvy}onOxKXMa#|jFO6%ed$ejp@jeV**&&v@ z$VQCz&A-2<%zJ2EXi1DkQM?IXD``ni46@eky!D#HOYs=!2FahwjRNJ4FRc$9O@#6K z*cu3Q%r{AQqSzcJeRN0!1|E{_{mGu85@s#gN`xb4`K^Q_#(o5H&%5SlmNJR;p9`WSfmg^5=EPRlq&1z z{YxzL*9`14%%e-VV`1Qqh_Z5!Da~$`7-&|J+t(fhxFJ2J{M#sa$B4ruZ%o2{*GQbr z;K7!L+?dZ#s9FI0q$zH(b+)3({$wfz4VIPL5L;capTFOOm-mW5BvU^-#FKiZm7}Hb z*{tyLf$&fSr=;T=Anat1WfDy9H=Kg3mD6fTbsv8hE}$J8&iRmv<+(;NYuP~w2UeG( zKIKUBq+LwifuxwlUzxBSal1>$$AP2B({kx>`K)_4-CYjSyVaZPtI6jt?e#zWO%ho= z7awqF__6lB<~=0}bkrXyDPT6p%8tAxvhxY@aonABs{$N=9eVHoj+=M^=bG~Q>@Od2 z#S4p-Nr9k-&}M;}{@ABA>Ed!IuiKn>l)z`E7aXd<_~XPU&<-k>#(slir3!QGk|cI4 zp059r{aVgUtlr{}(WT z7iyTufS&Lr+2$h=2{}1ObL?}^`I*qxoHANuFfJb_ouc8RO>OLY{`ScKx|3iU?W9oNxE}`a#vm^>V4}n(dGm4WQeO zQo4Gq1H_p*UKxdyczsr(pblfKtvx7Fd%Tu$60!Pt1m8LFm$6cWIOcm{5$gTv8oAea z{a@JTO*ar(Su?<-^NiGr`xr z+XF(#2#3yzKUlP7Ro-Une$u9@F8TEld+ApELv(W666`hfCET7#}6Us zw{WavOalKxNAD(C?v=-3Yfo$^3*Mv~$mQ^syoh1DS(}aAfs0vi!pw{rW7G(>scH=b-^0FVGN08@2l4M`9vy3OECk$>;ZyWM zJ0J{#c6$fBnsx(8V}1f(3H9kG;#@*Ic-2T&qA1sxTrW$Rzze?3CbbaLg#D!0Gd z`T_#AlewrwvP+6V=O&3W5S-)A+r7m?}6LNSk=}z`n&SVan;quEz3aZ#XY7~3h=8r6fc@;@Rd3O4Li{P59d@53MoOPZ)`X{VVTd3YN zBt5X?Mz>%S2&N8pWHXQ}$@i10vL~)G{>lYy$&#jr_tY;K|8ztE<*D1pbE%@9y24aF z)R~H*a7VJXQq*kjmFL2x78u!aepPq#@3`4e=%-k$=yK+$N@F572 z9VMqv`RDQSi|rqCX=w5OW}cG6CyUGP4ze_oViFk)CXRq!v!aEh+9mOV4mJzx%UYcg zxr7n>;djPoZf!rf<;-7NO)P?e507wW& zQT-HdWO{*Ux0mLeMu0T!6|}IQB$zLl4GNe)=m7#-`sfdWygqh4R6!fznOU(1@^SB< zVKrG{R;^;hk--f=Up9(q9~zYC^!Yw0!3nb`0?GnZ^{dwN`{8gM5o|FI(~To0W@mw{ z8>wp71=3JOOGwQyl=tz-E)3N2jaDxOxQM1kMaKih3k8I3K--Egx~1TVn=s|`8WrE3 zCp#o?CDpGFh%ODb3T^nKAe2IatPNywz&ettx`*{^9hHT~w7omTAjeHxC=nAsWjSF0 zzv=|s0hJ5tehBh9YyTqD z`I5Q_U~JqoCb)B~;SiuUPvl|%_4A35E?%+g^5?EzB0(SENryfqBUf}+jtPRlBeR6b z%-x0gLlPkO10plD|h}pw>G2341%B3H={sA3A&?&^z&^=Pgx^yUYQw_)+dC)q1 zMPOSBHx8i3FWB3-v8H~)6?>@8-%!Wl!6JyFrS7>%$N{t_kStf7{|dU;APztwpgfM~ z&{NfHRnLncy23pP+(D6-Xr3X5V@1_=#NMfVUN=CJw}^`GoUd$YT@ zg1`w?!MW*rJ|lE1=0a4G{5f!zHN^}4aQQL7zu#6t78?N*kXomcJay;a5p_0={x`&GQ_#U0jJIerOpt5OH7LwZe9EZqWkZhFar@mEf(Ed4Ex9esoh~zo+I}payJo< zD5R{})~`c20{$6--adIRlecwtU(jW;?Ts)MdQ-!gkx136Ibo(qELcHuM1vF747R_o zPRiSL#`8xWYy||L>^&2-SW3tNi-AQD(IS+5CjJ=qL-8mNP)GMy?Cp;G$Eu4hJzELg zz&=DMyZA7G!$PePSqY=ahpn6hC13>dD@)vaFXQ_HWLtitVv8NQ9A+H_H-}WooUkw? z!?ok^sus3Cvs3&`Vxnv)K%8&TQYZlZU88A7PD|i2M0cyO1iW3$2PJ}h4@ds3++RG3 z4YIwu>Hx^-O&odog8FVB<;`>MgA$U@m`9EI5wH~yWpWNPT%FYr3+@Hk0*qDr3NQh{ zV`yVPJtYZ}kx&OD*$^bm!~)*ZEm&bkin#Z{y*3>P(9zmJMjpt5(mbfF^G1pn1_%@| zNCEiTOF*Z6?~bs@0fM;nsJe^f<%?Ne;!xYVhO>T^K$1-a$_a)Tk|-+|&(3WXA^`DR z?^VpBoJ4v=Sqh5z3&`SC&Ut!R$+4kn6&^00c5j2Yp)vS zB$EV8^{_HK z4IrM^JPH9&lCMQB329q{qfG>PBGFkf=Nx4N1PN4t+G>6D6@z*oWyctYT|lP6NW%9C z6F#`Ead>y0M4c3f_8`!K8ifVa#VTHyA;>E*eZ?Ww&0w+Xi~}rcG2k|VnC2O`tQGqA1qu35`yB|CtEpz2|K-J{uzx+x`!W< ziUDW9afH>zMxi#(zF2B2vx>-qAtTAiNPyQ>jGmoZfP;dz*gDyg1OXyq|LA?ePEdiJ z1MzOinNXI^bm-xP7)AGOEzMi+}h*s)<7{A$Z2UF%74i`tbgxi zN9F#;5x(G+d60JO_|)b2kR<5lEzQF{soduD=?dCqOkd^+kfSbxWSVwfJ=^kKC~0G0 zmlC0j&Mfa7EdhP|q^Vzmv61-|Ep2Jr$!fU#5w|B$aG%*3?hJ-!K;RpdsUlLFP|AM?tbNQnWU$T>SGq29z90<668dV;sST=b12ru-j` zikcTilzxK={}JpUp8^v1@3$1B|6$_U9DE{IR(%5Y8v(-)*`|CNOdjDCb=(d~wKTYG z<#uqX9HD=+x4_TG+LiARdpQ< zixn?CM#@ zNA`&H@Qq^?EB&EmOvHT8Bn2*lhZxsO8uhDi61mv~UI#}843*d@t%t^*F?-UupzKk( zhd*C{WBI`IE$kTmp&04oAix&@=X_SYaOq>(Lw^sNbLC`{h!_`;i}rR&jPU5i3kQ+{ zV|0CdpT3+AMHaFt!sQ#J9V^I{HcV%)A0i3T)hG7z|AZ}LvodNCUFD*2@K&uD@|#!PGGBs`EV zBmlL6$sI*+;^O>F;^w+9L)4N(&3m3Rb7Iz%|KYoDwwaSQ#*21&@-gfhDOHLL5_+Hj z`0;#t6$Cw)J-RfKw&X#Q&^$p*iT6-l`T%E0#T2+Osi80ncio^tpBUgp6ATt0UE#h@ zmEIj<29_5eP|$@>I4`VMX|=6Asvu_jew<0kxexIBSt@L6x# zoG7R-^zRUScs`cxM?^pt>C7g-x!k0e8WINewuok|0BVd(n(@U6JWcKT-@(O6aCsb8 z9Ml!Px>@-sRs+PG#S4hJWKBD4<=P=HEJ~QYK)m}WV=5#rEdKZg`-^irrvQqGWVjzR zOFO159X;4&{PA|rgg35ER8?Tyy(_K*Ho&c8#<(&dYmE9dnM)<;1F~R4ebu&CD9$xF zTo1?k5%s-}oj@(oWHE~uB8+Yw8If-&)rWjN*WtbBM22I}#>w%@8=7Cr>`r%Ie<>5~ ztl<*wC7MVv%F@Pe387y3o4c8?YpDLf0zgL4boJ75 zkT9Pei(=}9sD0^LI!|7%oDilZkYb1I6#$QQOChlC+L@|!B$P~(O?Ix?_aucwsINU< zvXt1TVVjBa5;GU4OOqr*Y95*t#)Hy9nXshIQU(dCG6;%@L`UTbsgJnF2=#Ju?wNtg zjNQ#)O=!@tO&Vk)sgJbpKW?!GXozf0*Tz|sSK^7w>5`w&IQC;CHxF?QVN#JQ8|LWF}JaRUA zJ$2EQX17T{x3_>%Cnf!aA=Y_~xD<2~G0L(xlTW_7ZPo>A>DOc2=TA5SY7GPP{6KW{ z@6dr&CA)TAebAshZ;kZeyV{fA%RqT9U;ybBiq&ZzEtPcL^{6N4>OaT4>wwsXoKBD( zG&FxVMn~&lfhqrb(&rQIZUvT|_Gumgb88p_Lh_fkvrxqqfMKZX6$YK4OJ@E?h%Y{IHJquwb@B*-UzF6H1}2es z&oUEJP^@Nih-c4GS5kZ3WULklnC2H}oH=1LkC()^f@w!3^Es!(*_NNW_pQn4N@K;X7uo z+|CV9n-?*_m^NwR?*5BMGNk?f6=OKKYkUy4a`{CGv_X!#{qhdXTqQ19)djUwU5iG- zCO;NfwHAXfxcV@YbWSe;a1!jXmz=PVpDuXipv4BXOPnyjTEQpA#2$uL^Mac#nR)3y zns0xFen+|vH~TKys%>3wYEzo?{h!6#U6&5MJLF(<?Pb90CN}7H7Nzp}gDgqfg z&F*X>eGDY{ydDRKMv&p}OHzsLGvmfR3gt@8t4f;H%BDJ!?sX*$#GeV=?j9X@)#5+L zdYIS2|H(C`%b8v-T^chU`18BE)NIUozq;(4bj#M9E;Zja>WE>vRcjM5YKn$X9p;bk9M$a7h%+*bF1aBk%OvCmylwQbnj z6lA3I<{yOh&9A{kkUHV?NegeAjXwhxgfl-Fu7_ zU*WS0KgyOTcCEn;dTTh~bee}c%f@7<U7x`i^p)xkzY) NGp46=PC5She*mtGOvC^H literal 11729 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 diff --git a/lib/WorkflowScrnaseq.groovy b/lib/WorkflowScrnaseq.groovy index e4089a57..15584b23 100755 --- a/lib/WorkflowScrnaseq.groovy +++ b/lib/WorkflowScrnaseq.groovy @@ -14,8 +14,7 @@ class WorkflowScrnaseq { genomeExists(params, log) if (!params.input) { - log.error "Please provide an input samplesheet with --input" - System.exit(1) + Nextflow.error "Please provide an input samplesheet with --input" } if (!params.fasta) { diff --git a/nextflow.config b/nextflow.config index 76a0d4a2..6c0cc5f4 100644 --- a/nextflow.config +++ b/nextflow.config @@ -257,7 +257,7 @@ manifest { description = """Pipeline for processing 10x Genomics single cell rnaseq data""" mainScript = 'main.nf' nextflowVersion = '!>=22.10.1' - version = '2.3.2' + version = '2.4.0dev' doi = '10.5281/zenodo.3568187' } From d6f2da1ba2651bdceb78081cb212dad98f2b1c1b Mon Sep 17 00:00:00 2001 From: Gregor Sturm Date: Wed, 16 Aug 2023 13:54:04 +0200 Subject: [PATCH 31/34] Bump version to v2.4.0 for release --- assets/multiqc_config.yml | 4 ++-- nextflow.config | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/assets/multiqc_config.yml b/assets/multiqc_config.yml index bd63c010..3b0c72ff 100644 --- a/assets/multiqc_config.yml +++ b/assets/multiqc_config.yml @@ -1,7 +1,7 @@ report_comment: > - This report has been generated by the nf-core/scrnaseq + This report has been generated by the nf-core/scrnaseq analysis pipeline. For information about how to interpret these results, please see the - documentation. + documentation. report_section_order: "nf-core-scrnaseq-methods-description": order: -1000 diff --git a/nextflow.config b/nextflow.config index a86e4add..39d968b2 100644 --- a/nextflow.config +++ b/nextflow.config @@ -262,7 +262,7 @@ manifest { description = """Pipeline for processing 10x Genomics single cell rnaseq data""" mainScript = 'main.nf' nextflowVersion = '!>=23.04.0' - version = '2.4.0dev' + version = '2.4.0' doi = '10.5281/zenodo.3568187' } From b30255297d900a299f2ed2ec58441bf8a819cc35 Mon Sep 17 00:00:00 2001 From: Gregor Sturm Date: Wed, 16 Aug 2023 14:01:29 +0200 Subject: [PATCH 32/34] Update changelog --- CHANGELOG.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a6383a5b..f1866715 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,17 +5,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unpublished Version / DEV] -- [#237](https://github.com/nf-core/scrnaseq/pull/237) Add `singularity.registry = 'quay.io'` and bump NF version to 23.04.0 +## v2.4.0 - 2023-08-16 Lime Platinum Crab + +- Fix typo causing empty version imformation for mtx_conversion subworkflow ([#254](https://github.com/nf-core/scrnaseq/pull/254)) +- Add `singularity.registry = 'quay.io'` and bump NF version to 23.04.0 ([#237](https://github.com/nf-core/scrnaseq/pull/237)) - Fixed issue with file collisions while using cellranger ([#232](https://github.com/nf-core/scrnaseq/pull/232)) - Fix issue where multiqc inputs tried to access objects that did not exist ([#239](https://github.com/nf-core/scrnaseq/pull/239)) -- Removed `public_aws_ecr` profile +- Removed `public_aws_ecr` profile ([#242](https://github.com/nf-core/scrnaseq/pull/242)) - Include cellranger in MultiQC report ([#244](https://github.com/nf-core/scrnaseq/pull/244)) - Nf-core template update to v2.9 ([#245](https://github.com/nf-core/scrnaseq/pull/245)) - Update cellranger and fastqc module ([#246](https://github.com/nf-core/scrnaseq/pull/246)). The [updated cellranger module](https://github.com/nf-core/modules/pull/3537) now automatically renames input FASTQ files to match the expected naming conventions. -## v2.3.2 - 2023-06-07 Patched Yellow Strontium Pinscher +## v2.3.2 - 2023-06-07 Sepia Samarium Salmon - Move containers for pipeline to quay.io ([#233](https://github.com/nf-core/scrnaseq/pull/233)) From 3fdd6f536c2f3b4e86e56cceceaf3c3c72fd8be4 Mon Sep 17 00:00:00 2001 From: maxulysse Date: Wed, 23 Aug 2023 14:58:23 +0200 Subject: [PATCH 33/34] update schema_ignore_params to validationSchemaIgnoreParams --- conf/test.config | 2 +- conf/test_full.config | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/conf/test.config b/conf/test.config index 322dd7ae..961ab069 100644 --- a/conf/test.config +++ b/conf/test.config @@ -29,7 +29,7 @@ params { protocol = '10XV2' // Ignore `--input` as otherwise the parameter validation will throw an error - schema_ignore_params = 'genomes,input_paths,input' + validationSchemaIgnoreParams = 'genomes' } process { diff --git a/conf/test_full.config b/conf/test_full.config index 13c716d8..dd838978 100644 --- a/conf/test_full.config +++ b/conf/test_full.config @@ -21,5 +21,6 @@ params { genome = 'GRCh38' aligner = 'star' protocol = '10XV2' - schema_ignore_params = 'genomes' + + validationSchemaIgnoreParams = 'genomes' } From 18b26f2b80c3c863616c1a7865609e7a6dfa3ee5 Mon Sep 17 00:00:00 2001 From: Maxime U Garcia Date: Wed, 23 Aug 2023 16:29:05 +0200 Subject: [PATCH 34/34] Update conf/test.config --- conf/test.config | 1 - 1 file changed, 1 deletion(-) diff --git a/conf/test.config b/conf/test.config index 961ab069..45ee54c8 100644 --- a/conf/test.config +++ b/conf/test.config @@ -28,7 +28,6 @@ params { aligner = 'star' protocol = '10XV2' - // Ignore `--input` as otherwise the parameter validation will throw an error validationSchemaIgnoreParams = 'genomes' }