sequana-downsampling 0.10.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,187 @@
1
+ Metadata-Version: 2.4
2
+ Name: sequana-downsampling
3
+ Version: 0.10.0
4
+ Summary: Downsample NGS data sets (FastQ/FastA) using the Sequana framework
5
+ License: BSD-3
6
+ License-File: LICENSE
7
+ Keywords: sequana,snakemake,NGS,fastq,downsampling
8
+ Author: Sequana Team
9
+ Requires-Python: >=3.10,<4.0
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Intended Audience :: Education
13
+ Classifier: Intended Audience :: End Users/Desktop
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: License :: OSI Approved :: BSD License
16
+ Classifier: License :: Other/Proprietary License
17
+ Classifier: Operating System :: POSIX :: Linux
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: 3.14
24
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
25
+ Classifier: Topic :: Scientific/Engineering :: Information Analysis
26
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
27
+ Requires-Dist: click (>=8.1.7)
28
+ Requires-Dist: pulp (>=2.8)
29
+ Requires-Dist: rich-click (>=1.7.2)
30
+ Requires-Dist: sequana (>=0.17)
31
+ Requires-Dist: sequana-pipetools (>=1.5.0)
32
+ Requires-Dist: snakemake (>=7.32)
33
+ Project-URL: Repository, https://github.com/sequana/downsampling
34
+ Description-Content-Type: text/x-rst
35
+
36
+
37
+ .. image:: https://badge.fury.io/py/sequana-downsampling.svg
38
+ :target: https://pypi.python.org/pypi/sequana-downsampling
39
+
40
+ .. image:: https://github.com/sequana/downsampling/actions/workflows/main.yml/badge.svg
41
+ :target: https://github.com/sequana/downsampling/actions/workflows
42
+
43
+ .. image:: https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12-blue.svg
44
+ :target: https://pypi.python.org/pypi/sequana-downsampling
45
+ :alt: Python 3.10 | 3.11 | 3.12
46
+
47
+ .. image:: https://joss.theoj.org/papers/10.21105/joss.00352/status.svg
48
+ :target: https://joss.theoj.org/papers/10.21105/joss.00352
49
+ :alt: JOSS (journal of open source software) DOI
50
+
51
+
52
+ This is the **downsampling** pipeline from the `Sequana <https://sequana.readthedocs.org>`_ project.
53
+
54
+ :Overview: Downsample NGS data sets (FastQ or FastA).
55
+ :Input: A set of FastQ or FastA files (single or paired-end).
56
+ :Output: Downsampled FastQ or FastA files.
57
+ :Status: Production
58
+ :Citation: Cokelaer et al, (2017), 'Sequana': a Set of Snakemake NGS pipelines, Journal of Open Source Software, 2(16), 352, JOSS DOI https://doi.org/10.21105/joss.00352
59
+
60
+
61
+ Installation
62
+ ~~~~~~~~~~~~
63
+
64
+ ::
65
+
66
+ pip install sequana_downsampling --upgrade
67
+
68
+ You will also need ``pigz`` available on your PATH.
69
+
70
+
71
+ Quick Start
72
+ ~~~~~~~~~~~
73
+
74
+ **1. Set up the pipeline**::
75
+
76
+ sequana_downsampling --input-directory DATAPATH
77
+
78
+ **2. Run the pipeline**::
79
+
80
+ cd downsampling
81
+ bash downsampling.sh
82
+
83
+
84
+ Usage
85
+ ~~~~~
86
+
87
+ ::
88
+
89
+ sequana_downsampling --help
90
+
91
+ Key pipeline-specific options:
92
+
93
+ ``--downsampling-input-format``
94
+ Input format: ``fastq`` (default), ``fasta``, or ``sam``.
95
+
96
+ ``--downsampling-method``
97
+ ``random`` (default, keeps a fixed number of reads) or ``random_pct``
98
+ (keeps a percentage of reads).
99
+
100
+ ``--downsampling-max-entries``
101
+ Number of reads to keep when using ``random`` (default: 1000).
102
+
103
+ ``--downsampling-percent``
104
+ Percentage of reads to keep when using ``random_pct`` (default: 10).
105
+
106
+ ``--downsampling-threads``
107
+ Number of threads used by ``pigz`` to compress output (default: 4).
108
+
109
+ Examples::
110
+
111
+ sequana_downsampling --input-directory DATAPATH \
112
+ --downsampling-method random --downsampling-max-entries 100
113
+
114
+ sequana_downsampling --input-directory DATAPATH \
115
+ --downsampling-method random_pct --downsampling-percent 10 \
116
+ --downsampling-input-format fasta --input-pattern "*.fasta"
117
+
118
+ Run on a SLURM cluster::
119
+
120
+ cd downsampling
121
+ sbatch downsampling.sh
122
+
123
+ Or drive Snakemake directly::
124
+
125
+ snakemake -s downsampling.rules --cores 4 --stats stats.txt
126
+
127
+
128
+ Requirements
129
+ ~~~~~~~~~~~~
130
+
131
+ The following tools must be available (install via conda/bioconda)::
132
+
133
+ mamba env create -f environment.yml
134
+
135
+ - **sequana** — FastQ/FastA selection (Python API)
136
+ - **pigz** — parallel gzip compression of outputs
137
+
138
+
139
+ Pipeline overview
140
+ ~~~~~~~~~~~~~~~~~
141
+
142
+ The pipeline randomly selects reads from the input files (single or paired).
143
+ If the inputs are paired, the one-to-one mapping between R1 and R2 is
144
+ preserved. FastQ inputs can be gzipped; outputs are gzipped with ``pigz``.
145
+ FastA inputs and outputs are uncompressed.
146
+
147
+
148
+ Configuration
149
+ ~~~~~~~~~~~~~
150
+
151
+ Here is the `latest documented configuration file <https://raw.githubusercontent.com/sequana/downsampling/main/sequana_pipelines/downsampling/config.yaml>`_.
152
+ Key sections:
153
+
154
+ - ``downsampling`` — method (``random`` / ``random_pct``), ``max_entries``,
155
+ ``percent``, ``threads``, and ``input_format`` (``fastq`` / ``fasta``)
156
+
157
+
158
+ Changelog
159
+ ~~~~~~~~~
160
+
161
+ ========= ====================================================================
162
+ Version Description
163
+ ========= ====================================================================
164
+ 0.10.0 * Migrate to Poetry / pyproject.toml packaging
165
+ * Simplify __init__.py using importlib.metadata
166
+ * Rewrite CLI with rich_click (replaces argparse)
167
+ * Update CI to use setup-micromamba with generate-run-shell
168
+ * Add ``localrules: pipeline``
169
+ * Add ``tools.txt`` and ``environment.yml``
170
+ * Refresh README badges and usage examples
171
+ 0.9.0 * Maintenance release
172
+ 0.8.5 * Cope with R1/R2 paired data properly. Improved make file
173
+ 0.8.4 * Add missing MANIFEST to include missing requirements.txt
174
+ 0.8.3 * Comply with new API from sequana_pipetools 0.2.4
175
+ 0.8.2 * Add a --run option to execute the pipeline directly
176
+ 0.8.1 * Fix input and N in the random selection
177
+ 0.8.0 **First release.**
178
+ ========= ====================================================================
179
+
180
+
181
+ Contribute & Code of Conduct
182
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
183
+
184
+ To contribute to this project, please take a look at the
185
+ `Contributing Guidelines <https://github.com/sequana/sequana/blob/main/CONTRIBUTING.rst>`_ first. Please note that this project is released with a
186
+ `Code of Conduct <https://github.com/sequana/sequana/blob/main/CONDUCT.md>`_. By contributing to this project, you agree to abide by its terms.
187
+
@@ -0,0 +1,11 @@
1
+ sequana_pipelines/downsampling/__init__.py,sha256=a2JTYHRndqt6IeaZvkrwj60qrJfuaH-ruh0ajj-ftus,88
2
+ sequana_pipelines/downsampling/config.yaml,sha256=PATX4d6C_rM2yuVLit5UvFUIdh84ZLYyAaKkLWAxrR0,1252
3
+ sequana_pipelines/downsampling/downsampling.rules,sha256=RFqZRMRmxQIeJxCJljbN97I76iQmbdHAVQKKQ83KS4A,4041
4
+ sequana_pipelines/downsampling/main.py,sha256=gY2HTctxkzY6yCemKLVe2txO2gnbjvVvpC9E7wru75M,3782
5
+ sequana_pipelines/downsampling/schema.yaml,sha256=giBDsqnGUwIcmLZGPodLrGRVsOkI7lWQrCrQsseL__Q,935
6
+ sequana_pipelines/downsampling/tools.txt,sha256=HwamIWOd6wMdHlrYZtHhk-nleP91pi4w46yOtzN6KjY,13
7
+ sequana_downsampling-0.10.0.dist-info/METADATA,sha256=TFS3iAq2cR6Rxcpc7BLgmOLZIqac_QpSQvkeLq-BsqY,6390
8
+ sequana_downsampling-0.10.0.dist-info/WHEEL,sha256=Vz2fHgx6HFtSwhs8KvkHLqH5Ea4w1_rner5uNVGCeIE,88
9
+ sequana_downsampling-0.10.0.dist-info/entry_points.txt,sha256=cWoyjeUM8nwsBG5V30q087sQEGwGYh3XhOJhaVzMKI0,81
10
+ sequana_downsampling-0.10.0.dist-info/licenses/LICENSE,sha256=tifUGMwXA9uaq2g1wFz0ZgRRPOFCfqsOxRj8JneHZ3M,1530
11
+ sequana_downsampling-0.10.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: poetry-core 2.3.2
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ sequana_downsampling=sequana_pipelines.downsampling.main:main
3
+
@@ -0,0 +1,29 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2016-2019, Sequana Development Team
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ * Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ * Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ * Neither the name of the copyright holder nor the names of its
17
+ contributors may be used to endorse or promote products derived from
18
+ this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,3 @@
1
+ import importlib.metadata
2
+
3
+ version = importlib.metadata.version("sequana-downsampling")
@@ -0,0 +1,37 @@
1
+ # ============================================================================
2
+ # Config file for Quality Control
3
+ # ==========================================[ Sections for the users ]========
4
+ #
5
+ # One of input_directory, input_pattern and input_samples must be provided
6
+ # If input_directory provided, use it otherwise if input_pattern provided,
7
+ # use it, otherwise use input_samples.
8
+ # ============================================================================
9
+
10
+ input_directory: '.'
11
+ input_pattern: '*.fastq.gz'
12
+ #input_readtag: "_R[12]_"
13
+
14
+
15
+ apptainers:
16
+ pigz: https://zenodo.org/record/7346805/files/pigz_2.4.0.img
17
+
18
+
19
+ ##############################################################################
20
+ # Your section
21
+ #
22
+ # :Parameters:
23
+ #
24
+ # - options: string with any valid FastQC options
25
+ # - threads: for unpigz/pigz if data is zipped
26
+ # - method can be a {tail, tail_pct, head, , head_pct, random, random_pct}
27
+ # if _pcft is appended, the percent field is used, otherwise, the max_entries
28
+ # if max_entries is used, depending on input_format, we select 1, 2, 4 lines.
29
+ # - input_format in [fastq, fasta]. If provided, we will check the extension
30
+ downsampling:
31
+ threads: 4
32
+ method: random
33
+ percent: 10
34
+ max_entries: 100
35
+ input_format: fastq
36
+
37
+
@@ -0,0 +1,131 @@
1
+ """downsampling pipeline
2
+
3
+ Author: Thomas Cokelaer
4
+ Affiliation: Institut Pasteur @ 2020
5
+
6
+ This pipeline is part of Sequana software (sequana.readthedocs.io)
7
+
8
+ snakemake -s downsampling.rules --forceall --stats stats.txt --cores 4
9
+
10
+ """
11
+ from sequana_pipetools import PipelineManager
12
+
13
+ # This must be defined before the include
14
+ configfile: "config.yaml"
15
+
16
+ manager = PipelineManager("downsampling", config, fastq=True)
17
+
18
+
19
+ localrules: pipeline, touch_done
20
+
21
+
22
+ rule pipeline:
23
+ input: expand("output/{sample}.done", sample=manager.samples)
24
+
25
+
26
+ fmt = config["downsampling"]["input_format"]
27
+ paired = manager.paired
28
+
29
+ if fmt == "fastq":
30
+ _ext = "fastq"
31
+ elif fmt == "fasta":
32
+ _ext = "fasta"
33
+ else:
34
+ raise NotImplementedError(f"Unsupported input_format: {fmt}")
35
+
36
+
37
+ if fmt == "fastq":
38
+
39
+ if paired:
40
+ rule select_reads:
41
+ input: manager.getrawdata()
42
+ output:
43
+ r1 = temp("output/{sample}_R1.fastq"),
44
+ r2 = temp("output/{sample}_R2.fastq"),
45
+ run:
46
+ from sequana import FastQ
47
+ f1 = FastQ(input[0])
48
+ if config['downsampling']['method'] == "random":
49
+ N = config['downsampling']['max_entries']
50
+ else:
51
+ N = int(len(f1) * config["downsampling"]["percent"] / 100)
52
+ selection = f1.select_random_reads(N, output.r1)
53
+ f2 = FastQ(input[1])
54
+ f2.select_random_reads(selection, output.r2)
55
+ else:
56
+ rule select_reads:
57
+ input: manager.getrawdata()
58
+ output: temp("output/{sample}.fastq")
59
+ run:
60
+ from sequana import FastQ
61
+ f1 = FastQ(input[0])
62
+ if config['downsampling']['method'] == "random":
63
+ N = config['downsampling']['max_entries']
64
+ else:
65
+ N = int(len(f1) * config["downsampling"]["percent"] / 100)
66
+ f1.select_random_reads(N, output[0])
67
+
68
+ elif fmt == "fasta":
69
+
70
+ if paired:
71
+ rule select_reads:
72
+ input: manager.getrawdata()
73
+ output:
74
+ r1 = temp("output/{sample}_R1.fasta"),
75
+ r2 = temp("output/{sample}_R2.fasta"),
76
+ run:
77
+ from sequana import FastA
78
+ f1 = FastA(input[0])
79
+ if config['downsampling']['method'] == "random":
80
+ N = config['downsampling']['max_entries']
81
+ else:
82
+ N = int(len(f1) * config["downsampling"]["percent"] / 100)
83
+ selection = f1.select_random_reads(N, output.r1)
84
+ f2 = FastA(input[1])
85
+ f2.select_random_reads(selection, output.r2)
86
+ else:
87
+ rule select_reads:
88
+ input: manager.getrawdata()
89
+ output: temp("output/{sample}.fasta")
90
+ run:
91
+ from sequana import FastA
92
+ f1 = FastA(input[0])
93
+ if config['downsampling']['method'] == "random":
94
+ N = config['downsampling']['max_entries']
95
+ else:
96
+ N = int(len(f1) * config["downsampling"]["percent"] / 100)
97
+ f1.select_random_reads(N, output[0])
98
+
99
+
100
+ rule pigz_compress:
101
+ input: "output/{prefix}." + _ext
102
+ output: "output/{prefix}." + _ext + ".gz"
103
+ threads: config["downsampling"]["threads"]
104
+ log: "logs/{prefix}/pigz.log"
105
+ container: config["apptainers"]["pigz"]
106
+ shell:
107
+ """
108
+ pigz -f -p {threads} {input} > {log} 2>&1
109
+ """
110
+
111
+
112
+ if paired:
113
+ rule touch_done:
114
+ input:
115
+ r1 = "output/{sample}_R1." + _ext + ".gz",
116
+ r2 = "output/{sample}_R2." + _ext + ".gz",
117
+ output: "output/{sample}.done"
118
+ shell: "touch {output}"
119
+ else:
120
+ rule touch_done:
121
+ input: "output/{sample}." + _ext + ".gz"
122
+ output: "output/{sample}.done"
123
+ shell: "touch {output}"
124
+
125
+
126
+ onsuccess:
127
+ manager.teardown(extra_files_to_remove=["*.done"])
128
+ shell("mv output/* . && rm -rf output")
129
+
130
+ onerror:
131
+ manager.onerror()
@@ -0,0 +1,126 @@
1
+ #
2
+ # This file is part of Sequana software
3
+ #
4
+ # Copyright (c) 2016-2021 - Sequana Development Team
5
+ #
6
+ # File author(s):
7
+ # Thomas Cokelaer <thomas.cokelaer@pasteur.fr>
8
+ #
9
+ # Distributed under the terms of the 3-clause BSD license.
10
+ # The full license is in the LICENSE file, distributed with this software.
11
+ #
12
+ # website: https://github.com/sequana/sequana
13
+ # documentation: http://sequana.readthedocs.io
14
+ #
15
+ ##############################################################################
16
+ import os
17
+ import sys
18
+
19
+ import rich_click as click
20
+ from sequana_pipetools import SequanaManager
21
+ from sequana_pipetools.options import *
22
+
23
+ NAME = "downsampling"
24
+
25
+
26
+ help = init_click(
27
+ NAME,
28
+ groups={
29
+ "Pipeline Specific": [
30
+ "--downsampling-input-format",
31
+ "--downsampling-method",
32
+ "--downsampling-percent",
33
+ "--downsampling-max-entries",
34
+ "--downsampling-threads",
35
+ ],
36
+ },
37
+ )
38
+
39
+
40
+ @click.command(context_settings=help)
41
+ @include_options_from(ClickInputOptions)
42
+ @include_options_from(ClickSnakemakeOptions, working_directory=NAME)
43
+ @include_options_from(ClickSlurmOptions)
44
+ @include_options_from(ClickGeneralOptions)
45
+ @click.option(
46
+ "--downsampling-input-format",
47
+ "downsampling_input_format",
48
+ default="fastq",
49
+ show_default=True,
50
+ type=click.Choice(["fasta", "fastq", "sam"]),
51
+ help="set input format (only 'fastq', 'fasta', 'sam' supported for now)",
52
+ )
53
+ @click.option(
54
+ "--downsampling-method",
55
+ "downsampling_method",
56
+ default="random",
57
+ show_default=True,
58
+ type=click.Choice(["random", "random_pct"]),
59
+ help="downsampling method: random (based on read counts) or random_pct (based on a percentage of reads)",
60
+ )
61
+ @click.option(
62
+ "--downsampling-percent",
63
+ "downsampling_percent",
64
+ default=10.0,
65
+ show_default=True,
66
+ type=float,
67
+ help="percentage of reads to select. Use with method 'random_pct' only",
68
+ )
69
+ @click.option(
70
+ "--downsampling-max-entries",
71
+ "downsampling_max_entries",
72
+ default=1000,
73
+ show_default=True,
74
+ type=int,
75
+ help="max entries (reads, alignments) to select. Use with method 'random' only",
76
+ )
77
+ @click.option(
78
+ "--downsampling-threads",
79
+ "downsampling_threads",
80
+ default=4,
81
+ show_default=True,
82
+ type=int,
83
+ help="max threads to use with pigz",
84
+ )
85
+ def main(**options):
86
+
87
+ if options["from_project"]:
88
+ click.echo("--from-project Not yet implemented")
89
+ sys.exit(1)
90
+
91
+ # the real stuff is here
92
+ manager = SequanaManager(options, NAME)
93
+ manager.setup()
94
+
95
+ options = manager.options
96
+ cfg = manager.config.config
97
+
98
+ from sequana_pipetools import logger
99
+
100
+ logger.setLevel(options.level)
101
+ logger.name = "sequana_downsampling"
102
+
103
+ manager.fill_data_options()
104
+
105
+ # --------------------------------------------------- downsampling
106
+ cfg.downsampling.input_format = options.downsampling_input_format
107
+ cfg.downsampling.method = options.downsampling_method
108
+ cfg.downsampling.percent = options.downsampling_percent
109
+ cfg.downsampling.max_entries = options.downsampling_max_entries
110
+ cfg.downsampling.threads = options.downsampling_threads
111
+
112
+ # If input format is fasta, adjust input pattern default
113
+ if options.downsampling_input_format == "fasta" and options.input_pattern == "*fastq.gz":
114
+ cfg.input_pattern = "*fasta.gz"
115
+
116
+ logger.info(f"Input data should be {cfg.downsampling.input_format}")
117
+ if cfg.downsampling.method == "random":
118
+ logger.info(f"Your data will be downsampled randomly keeping {cfg.downsampling.max_entries} reads")
119
+ elif cfg.downsampling.method == "random_pct":
120
+ logger.info(f"Your data will be downsampled randomly keeping {cfg.downsampling.percent}% of the reads")
121
+
122
+ manager.teardown()
123
+
124
+
125
+ if __name__ == "__main__":
126
+ main()
@@ -0,0 +1,43 @@
1
+ # Schema validator for the quality_control
2
+ # author: Thomas Cokelaer
3
+
4
+ type: map
5
+ mapping:
6
+ "input_directory":
7
+ type: str
8
+ required: False
9
+ #"input_readtag":
10
+ # type: str
11
+ # required: False
12
+ "input_pattern":
13
+ type: str
14
+ required: False
15
+ "exclude_pattern":
16
+ type: str
17
+ required: False
18
+ nullable: True
19
+
20
+ "apptainers":
21
+ type: any
22
+ required: False
23
+
24
+ "downsampling":
25
+ type: map
26
+ mapping:
27
+ "input_format":
28
+ type: str
29
+ enum: [fastq, fasta]
30
+ "method":
31
+ type: str
32
+ enum: [random, random_pct]
33
+ "threads":
34
+ type: int
35
+ range: { min: 1}
36
+ "percent":
37
+ type: float
38
+ range : { min: 0, max: 100}
39
+ "max_entries":
40
+ type: int
41
+ range: { min: 1}
42
+
43
+
@@ -0,0 +1,2 @@
1
+ sequana
2
+ pigz