diff --git a/.gitattributes b/.gitattributes
index 7a2dabc..4457c76 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,4 +1,7 @@
*.config linguist-language=nextflow
*.nf.test linguist-language=nextflow
+*.bwt binary
+*.pac binary
+*.sa binary
modules/nf-core/** linguist-generated
subworkflows/nf-core/** linguist-generated
diff --git a/.github/workflows/nf-test.yml b/.github/workflows/nf-test.yml
index 0cecea5..d9e053f 100644
--- a/.github/workflows/nf-test.yml
+++ b/.github/workflows/nf-test.yml
@@ -119,7 +119,7 @@ jobs:
confirm-pass:
needs: [nf-test]
if: always()
- runs-on: # use self-hosted runners
+ runs-on: # use self-hosted runners
- runs-on=${{ github.run_id }}-confirm-pass
- runner=2cpu-linux-x64
steps:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index d06777a..646c359 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,3 +1,14 @@
+exclude: |
+ (?x)^(
+ \.nf-test/|
+ results/|
+ work/|
+ tmp/|
+ \.codex$|
+ \.codex/|
+ assets/testdata/.*\.(amb|ann|bwt|pac|sa)$
+ )
+
repos:
- repo: https://github.com/pre-commit/mirrors-prettier
rev: "v3.1.0"
diff --git a/README.md b/README.md
index 4c41aaa..602f26c 100644
--- a/README.md
+++ b/README.md
@@ -8,6 +8,7 @@ TrESFlow is a Nextflow DSL2 pipeline for the preprocessing of TrES-seq data from
## Install
Install your conda/mamba/micromamba env as follows (conda-forge & bioconda channels):
+
```bash
micromamba env create -n tres
micromamba activate tres
@@ -16,12 +17,14 @@ micromamba install screen samtools bwa-mem2 star fastqc multiqc trim-galore deep
```
Download the repo and cd in it:
+
```bash
git clone git@github.com:CSOgroup/TrESFlow.git
cd TrESFlow
```
Install codon in your env:
+
```bash
./scripts/install_codon_0.16.3.sh --prefix /path/to/env/prefix
```
@@ -110,6 +113,9 @@ RNA publishes:
- `rna_split_fastqs/`
- `rna_align/`
- `TrES_Stats/`
+- `qc/samtools/`
+- `multiqc/`
+- `tres_report/`
- `pipeline_info/`
DNA publishes:
@@ -117,9 +123,15 @@ DNA publishes:
- `dna_split_fastqs/`
- `dna_align/`
- `TrES_Stats/`
+- `qc/samtools/`
+- `multiqc/`
+- `tres_report/`
- `pipeline_info/`
-`TrES_Stats/` includes RNA and DNA sequencing-efficiency UpSet PDF plots. Sankey plots, HTML reports, count tables, combined RNA+DNA reports, and sequencing-efficiency warning TSVs are not produced. Optional unavailable BAM-derived categories are skipped with warnings in the process log.
+The pipeline also writes two end-of-run HTML reports:
+
+- `tres_report/tres_report.html`: compact TrESFlow-specific RNA/DNA mapping and barcode summary
+- `multiqc/multiqc_report.html`: nf-core MultiQC aggregation of supported logs and QC files
## Runtime Contract
@@ -162,7 +174,7 @@ Default local CPU budget:
Work-directory cleanup is intentionally aggressive: `--cleanup_work true` uses Nextflow's successful-run cleanup to remove task work directories after outputs have been published and downstream tasks have completed. This substantially reduces retained `work/` storage, but cleaned tasks are not expected to be usable with `--resume`. Set `--cleanup_work false` when you need the previous resume-friendly behavior for debugging or iterative development.
-DNA alignment no longer removes low-count cell barcodes during `ALIGN_DNA`. The aligned BAM still keeps proper-pair mapped, non-blacklisted reads; duplicate removal is represented later by `*_NoDup.bam`, and duplicate status appears in DNA sequencing-efficiency plots as `Unique +`.
+DNA alignment no longer removes low-count cell barcodes during `ALIGN_DNA`. The aligned BAM still keeps proper-pair mapped, non-blacklisted reads; duplicate removal is represented later by `*_NoDup.bam`.
Every run writes:
@@ -171,6 +183,21 @@ Every run writes:
- `${outdir}/pipeline_info/execution_trace.tsv`
- `${outdir}/pipeline_info/flowchart.html`
- `${outdir}/pipeline_info/runtime_contract.tsv`
+- `${outdir}/tres_report/tres_report.html` with per-library main statistics, detailed QC tables, and CSV/Excel export buttons
+- `${outdir}/tres_report/tres_report_metrics.json`
+- `${outdir}/multiqc/multiqc_report.html`
+
+Runs with real BAM outputs also write nf-core samtools sidecar QC under:
+
+- `${outdir}/qc/samtools/*.flagstat`
+- `${outdir}/qc/samtools/*.stats`
+- `${outdir}/qc/samtools/*.idxstats`
+- `${outdir}/qc/samtools/*.quickcheck.tsv`
+
+Raw FASTQ QC from nf-core FastQC is written under:
+
+- `${outdir}/qc/fastqc/*_fastqc.html`
+- `${outdir}/qc/fastqc/*_fastqc.zip`
The active runtime scripts live under [`scripts/core_runtime/`](scripts/core_runtime/). `upstream/source_scripts/` is kept only as provenance for the vendored core code.
diff --git a/assets/test_realdata/ligation_barcode_whitelist.txt b/assets/test_realdata/ligation_barcode_whitelist.txt
new file mode 100644
index 0000000..113a233
--- /dev/null
+++ b/assets/test_realdata/ligation_barcode_whitelist.txt
@@ -0,0 +1,48 @@
+ATCACGTT
+CGATGTTT
+TTAGGCAT
+TGACCACT
+ACAGTGGT
+GCCAATGT
+CAGATCTG
+ACTTGATG
+GATCAGCG
+TAGCTTGT
+GGCTACAG
+CTTGTACT
+TGGTTGTT
+TCTCGGTT
+TAAGCGTT
+TCCGTCTT
+TGTACCTT
+TTCTGTGT
+TCTGCTGT
+TTGGAGGT
+TCGAGCGT
+TGATACGT
+TGCATAGT
+TTGACTCT
+TGCGATCT
+TTCCTGCT
+TAGTGACT
+TACAGGAT
+TCCTCAAT
+TGTGGTTG
+TACTAGTC
+TTCCATTG
+TCGAAGTG
+TAACGCTG
+TTGGTATG
+TGAACTGG
+TACTTCGG
+TCTCACGG
+TCAGGAGG
+TAAGTTCG
+TCCAGTCG
+TGTATGCG
+TCATTGAG
+TGGCTCAG
+TATGCCAG
+TCAGATTC
+TAGTCTTG
+TTCAGCTC
diff --git a/bin/render_tres_report.py b/bin/render_tres_report.py
new file mode 100644
index 0000000..96c27b1
--- /dev/null
+++ b/bin/render_tres_report.py
@@ -0,0 +1,963 @@
+#!/usr/bin/env python3
+"""Render a compact TrESFlow HTML QC report from pipeline artifacts."""
+
+from __future__ import annotations
+
+import argparse
+import html
+import json
+import re
+from collections import defaultdict
+from datetime import datetime, timezone
+from pathlib import Path
+from statistics import mean
+
+
+def parse_number(value: str):
+ value = value.strip().replace(",", "")
+ if value in {"", "-nan", "nan", "NaN", "N/A"}:
+ return None
+ try:
+ if re.match(r"^-?\d+$", value):
+ return int(value)
+ return float(value)
+ except ValueError:
+ return None
+
+
+def parse_percent(value: str):
+ value = value.strip()
+ if not value:
+ return None
+ if value.endswith("%"):
+ value = value[:-1]
+ parsed = parse_number(value)
+ return float(parsed) if parsed is not None else None
+
+
+def pct_from_fraction(value):
+ if value is None:
+ return None
+ return float(value) * 100.0
+
+
+def fmt_int(value):
+ if value is None:
+ return "n/a"
+ try:
+ return f"{int(value):,}"
+ except (TypeError, ValueError):
+ return "n/a"
+
+
+def fmt_pct(value):
+ if value is None:
+ return "n/a"
+ return f"{float(value):.1f}%"
+
+
+def pct(numerator, denominator):
+ if numerator is None or denominator in {None, 0}:
+ return None
+ return float(numerator) / float(denominator) * 100.0
+
+
+def fmt_count_pct(count, denominator):
+ percent = pct(count, denominator)
+ if percent is None:
+ return "n/a"
+ return f"{fmt_pct(percent)} ({fmt_int(count)})"
+
+
+def css_width(value):
+ if value is None:
+ return "0"
+ return str(max(0.0, min(100.0, float(value))))
+
+
+def read_tsv_stats(path: Path):
+ stats = {}
+ for line in path.read_text(errors="replace").splitlines():
+ if not line.strip() or line.startswith("#"):
+ continue
+ parts = line.rstrip("\n").split("\t")
+ key = parts[0]
+ count = parse_number(parts[1]) if len(parts) > 1 else None
+ percent = parse_percent(parts[2]) if len(parts) > 2 else None
+ stats[key] = {"count": count, "percent": percent, "raw": parts}
+ return stats
+
+
+def read_counts(path: Path):
+ total = 0
+ observed = 0
+ top = []
+ for line in path.read_text(errors="replace").splitlines():
+ if not line.strip() or line.startswith("#"):
+ continue
+ parts = line.rstrip("\n").split("\t")
+ if not parts:
+ continue
+ count = parse_number(parts[0])
+ if count is not None:
+ total += int(count)
+ observed += 1
+ if len(top) < 5:
+ top.append({"count": int(count), "value": parts[1] if len(parts) > 1 else ""})
+ return {"total": total, "observed": observed, "top": top}
+
+
+def read_csv_key_values(path: Path):
+ values = {}
+ for line in path.read_text(errors="replace").splitlines():
+ if not line.strip() or "," not in line:
+ continue
+ key, value = line.split(",", 1)
+ values[key.strip()] = parse_number(value)
+ return values
+
+
+def read_flagstat(path: Path):
+ metrics = {"file": path.name}
+ for line in path.read_text(errors="replace").splitlines():
+ total = re.match(r"^(\d+) \+ \d+ in total", line)
+ primary = re.match(r"^(\d+) \+ \d+ primary$", line)
+ mapped = re.match(r"^(\d+) \+ \d+ mapped \(([^%]+)%", line)
+ primary_mapped = re.match(r"^(\d+) \+ \d+ primary mapped \(([^%]+)%", line)
+ paired = re.match(r"^(\d+) \+ \d+ paired in sequencing", line)
+ read1 = re.match(r"^(\d+) \+ \d+ read1", line)
+ read2 = re.match(r"^(\d+) \+ \d+ read2", line)
+ properly = re.match(r"^(\d+) \+ \d+ properly paired \(([^%]+)%", line)
+ duplicates = re.match(r"^(\d+) \+ \d+ duplicates", line)
+ if total:
+ metrics["total"] = int(total.group(1))
+ elif primary:
+ metrics["primary"] = int(primary.group(1))
+ elif mapped:
+ metrics["mapped"] = int(mapped.group(1))
+ metrics["mapped_percent"] = float(mapped.group(2))
+ elif primary_mapped:
+ metrics["primary_mapped"] = int(primary_mapped.group(1))
+ metrics["primary_mapped_percent"] = float(primary_mapped.group(2))
+ elif paired:
+ metrics["paired_in_sequencing"] = int(paired.group(1))
+ elif read1:
+ metrics["read1"] = int(read1.group(1))
+ elif read2:
+ metrics["read2"] = int(read2.group(1))
+ elif properly:
+ metrics["properly_paired"] = int(properly.group(1))
+ metrics["properly_paired_percent"] = float(properly.group(2))
+ elif duplicates:
+ metrics["duplicates"] = int(duplicates.group(1))
+ return metrics
+
+
+def read_duplicate_metrics(path: Path):
+ header = None
+ for line in path.read_text(errors="replace").splitlines():
+ if not line.strip() or line.startswith("#"):
+ continue
+ parts = line.rstrip("\n").split("\t")
+ if header is None:
+ if "PERCENT_DUPLICATION" not in parts:
+ continue
+ header = parts
+ continue
+ values = dict(zip(header, parts))
+ percent_dup = parse_number(values.get("PERCENT_DUPLICATION", ""))
+ read_pairs = parse_number(values.get("READ_PAIRS_EXAMINED", ""))
+ read_pair_duplicates = parse_number(values.get("READ_PAIR_DUPLICATES", ""))
+ unpaired_reads = parse_number(values.get("UNPAIRED_READS_EXAMINED", ""))
+ unpaired_duplicates = parse_number(values.get("UNPAIRED_READ_DUPLICATES", ""))
+ return {
+ "file": path.name,
+ "library": values.get("LIBRARY"),
+ "percent_duplication": float(percent_dup) * 100.0 if percent_dup is not None else None,
+ "unique_percent": (1.0 - float(percent_dup)) * 100.0 if percent_dup is not None else None,
+ "read_pairs_examined": int(read_pairs) if read_pairs is not None else None,
+ "read_pair_duplicates": int(read_pair_duplicates) if read_pair_duplicates is not None else None,
+ "unpaired_reads_examined": int(unpaired_reads) if unpaired_reads is not None else None,
+ "unpaired_read_duplicates": int(unpaired_duplicates) if unpaired_duplicates is not None else None,
+ }
+ return {"file": path.name}
+
+
+def strip_suffix(name: str, suffix: str) -> str:
+ return name[: -len(suffix)] if name.endswith(suffix) else name
+
+
+def collect_inputs(input_dir: Path):
+ files = [p for p in input_dir.rglob("*") if p.is_file()]
+ samples = defaultdict(lambda: {"rna": {}, "dna": {}})
+ rna_summaries = []
+ star_logs = []
+ flagstats = []
+ duplicate_metrics = []
+ samtools_stats = []
+
+ for path in files:
+ name = path.name
+
+ if name.endswith(".rna_sample_barcode.stats.tsv"):
+ sample = strip_suffix(name, ".rna_sample_barcode.stats.tsv")
+ samples[sample]["sample_id"] = sample
+ samples[sample]["rna"]["sample_barcode"] = read_tsv_stats(path)
+ elif name.endswith(".sample_barcode.stats.tsv") and not name.endswith(".dna_sample_barcode.stats.tsv"):
+ sample = strip_suffix(name, ".sample_barcode.stats.tsv")
+ samples[sample]["sample_id"] = sample
+ samples[sample]["rna"]["sample_barcode"] = read_tsv_stats(path)
+ elif name.endswith(".dna_sample_barcode.stats.tsv"):
+ sample = strip_suffix(name, ".dna_sample_barcode.stats.tsv")
+ samples[sample]["sample_id"] = sample
+ samples[sample]["dna"]["sample_barcode"] = read_tsv_stats(path)
+ elif name.endswith(".dna_modality.stats.tsv"):
+ sample = strip_suffix(name, ".dna_modality.stats.tsv")
+ samples[sample]["sample_id"] = sample
+ samples[sample]["dna"]["modality_barcode"] = read_tsv_stats(path)
+ elif name.endswith(".rna_umi.counts.tsv"):
+ sample = strip_suffix(name, ".rna_umi.counts.tsv")
+ samples[sample]["sample_id"] = sample
+ samples[sample]["rna"]["umi_counts"] = read_counts(path)
+ elif name.endswith(".umi.counts.tsv"):
+ sample = strip_suffix(name, ".umi.counts.tsv")
+ samples[sample]["sample_id"] = sample
+ samples[sample]["rna"]["umi_counts"] = read_counts(path)
+ elif name.endswith(".rna_cell.stats_L1.tsv") or name.endswith(".rna_cell.stats_L2.tsv") or name.endswith(".rna_cell.stats_L3.tsv"):
+ sample = re.sub(r"\.rna_cell\.stats_L[123]\.tsv$", "", name)
+ samples[sample]["sample_id"] = sample
+ samples[sample]["rna"].setdefault("cell_barcode", []).append(read_tsv_stats(path))
+ elif name.endswith(".cell.stats_L1.tsv") or name.endswith(".cell.stats_L2.tsv") or name.endswith(".cell.stats_L3.tsv"):
+ sample = re.sub(r"\.cell\.stats_L[123]\.tsv$", "", name)
+ samples[sample]["sample_id"] = sample
+ samples[sample]["rna"].setdefault("cell_barcode", []).append(read_tsv_stats(path))
+ elif name.endswith(".dna_cell.stats_L1.tsv") or name.endswith(".dna_cell.stats_L2.tsv") or name.endswith(".dna_cell.stats_L3.tsv"):
+ sample = re.sub(r"\.dna_cell\.stats_L[123]\.tsv$", "", name)
+ samples[sample]["sample_id"] = sample
+ samples[sample]["dna"].setdefault("cell_barcode", []).append(read_tsv_stats(path))
+ elif name == "Summary.csv":
+ split = path.parent.name.replace(".Solo.outGeneFull", "")
+ values = read_csv_key_values(path)
+ values["split_id"] = split
+ rna_summaries.append(values)
+ elif name.endswith(".Log.final.out"):
+ star_logs.append({"file": name})
+ elif name.endswith(".flagstat"):
+ metrics = read_flagstat(path)
+ metrics["id"] = strip_suffix(name, ".flagstat")
+ flagstats.append(metrics)
+ elif name.endswith(".DuplicateMetrics.txt"):
+ duplicate_metrics.append(read_duplicate_metrics(path))
+ elif name.endswith(".stats"):
+ samtools_stats.append({"file": name})
+
+ return {
+ "samples": dict(samples),
+ "rna_summaries": rna_summaries,
+ "star_logs": star_logs,
+ "flagstats": flagstats,
+ "duplicate_metrics": duplicate_metrics,
+ "samtools_stats": samtools_stats,
+ "input_file_count": len(files),
+ }
+
+
+def weighted_rna_percent(records, key):
+ numerator = 0.0
+ denominator = 0.0
+ for record in records:
+ reads = record.get("Number of Reads")
+ value = record.get(key)
+ if reads is None or value is None:
+ continue
+ numerator += float(reads) * float(value)
+ denominator += float(reads)
+ if denominator == 0:
+ return None
+ return pct_from_fraction(numerator / denominator)
+
+
+def average(values):
+ clean = [float(v) for v in values if v is not None]
+ return mean(clean) if clean else None
+
+
+def weighted_dna_unique_percent(records):
+ duplicate_total = 0
+ examined_total = 0
+ for record in records:
+ read_pairs = record.get("read_pairs_examined")
+ read_pair_duplicates = record.get("read_pair_duplicates")
+ unpaired_reads = record.get("unpaired_reads_examined") or 0
+ unpaired_duplicates = record.get("unpaired_read_duplicates") or 0
+ if read_pairs is None or read_pair_duplicates is None:
+ continue
+ duplicate_total += int(read_pair_duplicates) + int(unpaired_duplicates)
+ examined_total += int(read_pairs) + int(unpaired_reads)
+ if examined_total:
+ return (1.0 - (duplicate_total / examined_total)) * 100.0
+ return average([item.get("unique_percent") for item in records])
+
+
+def cell_barcode_percent(cell_stats):
+ if not cell_stats:
+ return None
+ candidates = []
+ for stats in cell_stats:
+ if "reads_with_all_ligations" in stats:
+ candidates.append(stats["reads_with_all_ligations"]["percent"])
+ elif "reads_with_ligation_all_segments" in stats:
+ candidates.append(stats["reads_with_ligation_all_segments"]["percent"])
+ elif "reads_with_ligation" in stats:
+ candidates.append(stats["reads_with_ligation"]["percent"])
+ elif "reads_with_L1" in stats:
+ candidates.append(stats["reads_with_L1"]["percent"])
+ return average(candidates)
+
+
+def sample_for_split(split_id: str, sample_ids):
+ matches = [sample_id for sample_id in sample_ids if split_id == sample_id or split_id.startswith(f"{sample_id}_")]
+ return max(matches, key=len) if matches else split_id.split("_", 1)[0]
+
+
+def flagstat_read_units(record):
+ if record.get("read1") is not None:
+ return record.get("read1")
+ if record.get("paired_in_sequencing") is not None:
+ return int(record["paired_in_sequencing"] / 2)
+ return record.get("primary_mapped") or record.get("mapped") or record.get("total")
+
+
+def split_from_flagstat_id(flagstat_id: str):
+ split_id = re.sub(r"^(rna|dna)\.", "", flagstat_id)
+ split_id = re.sub(r"\.(filtered_cells|aligned|markeddup|nodup)$", "", split_id)
+ return split_id
+
+
+def add_sample_value(sample_metrics, sample_id, key, value):
+ if value is None:
+ return
+ sample_metrics[sample_id][key] = sample_metrics[sample_id].get(key, 0) + int(round(float(value)))
+
+
+def rna_mapping_counts(records, sample_ids, key):
+ counts = defaultdict(int)
+ for record in records:
+ split_id = record.get("split_id")
+ reads = record.get("Number of Reads")
+ fraction = record.get(key)
+ if not split_id or reads is None or fraction is None:
+ continue
+ sample_id = sample_for_split(split_id, sample_ids)
+ counts[sample_id] += int(round(float(reads) * float(fraction)))
+ return counts
+
+
+def flagstat_counts_by_sample(flagstats, sample_ids, modality, stage):
+ counts = defaultdict(dict)
+ needle = f".{stage}"
+ for record in flagstats:
+ flagstat_id = record.get("id", "")
+ if not flagstat_id.startswith(f"{modality}.") or needle not in flagstat_id:
+ continue
+ sample_id = sample_for_split(split_from_flagstat_id(flagstat_id), sample_ids)
+ add_sample_value(counts, sample_id, "reads", flagstat_read_units(record))
+ return {sample_id: values.get("reads") for sample_id, values in counts.items()}
+
+
+def build_metrics(collected, library_name="unknown library"):
+ samples = collected["samples"]
+ library_name = library_name or "unknown library"
+ sample_ids = sorted(samples)
+ rna_transcriptome_counts = rna_mapping_counts(
+ collected["rna_summaries"],
+ sample_ids,
+ "Reads Mapped to GeneFull: Unique GeneFull",
+ )
+ rna_genome_counts = rna_mapping_counts(
+ collected["rna_summaries"],
+ sample_ids,
+ "Reads Mapped to Genome: Unique",
+ )
+ rna_usable_counts = flagstat_counts_by_sample(collected["flagstats"], sample_ids, "rna", "filtered_cells")
+ dna_mapped_counts = flagstat_counts_by_sample(collected["flagstats"], sample_ids, "dna", "aligned")
+ dna_usable_counts = flagstat_counts_by_sample(collected["flagstats"], sample_ids, "dna", "nodup")
+
+ sequencing_rows = []
+ for sample_id in sorted(samples):
+ sample = samples[sample_id]
+
+ rna = sample.get("rna", {})
+ rna_sb = rna.get("sample_barcode", {})
+ if rna_sb:
+ sequencing_rows.append(
+ {
+ "library_name": library_name,
+ "sample_id": sample_id,
+ "modality": "RNA",
+ "reads": rna_sb.get("reads", {}).get("count"),
+ "confidently_mapped": pct(rna_genome_counts.get(sample_id), rna_sb.get("reads", {}).get("count")),
+ "confidently_mapped_reads": rna_genome_counts.get(sample_id),
+ "valid_sample_barcodes": rna_sb.get("bc_reads", {}).get("percent"),
+ "valid_cell_barcodes": cell_barcode_percent(rna.get("cell_barcode", [])),
+ "valid_modality_barcodes": None,
+ "usable_reads": rna_usable_counts.get(sample_id),
+ }
+ )
+
+ dna = sample.get("dna", {})
+ dna_sb = dna.get("sample_barcode", {})
+ if dna_sb:
+ sequencing_rows.append(
+ {
+ "library_name": library_name,
+ "sample_id": sample_id,
+ "modality": "DNA",
+ "reads": dna_sb.get("reads", {}).get("count"),
+ "confidently_mapped": pct(dna_mapped_counts.get(sample_id), dna_sb.get("reads", {}).get("count")),
+ "confidently_mapped_reads": dna_mapped_counts.get(sample_id),
+ "valid_sample_barcodes": dna_sb.get("bc_reads", {}).get("percent"),
+ "valid_modality_barcodes": dna.get("modality_barcode", {}).get("bc_reads", {}).get("percent"),
+ "valid_cell_barcodes": cell_barcode_percent(dna.get("cell_barcode", [])),
+ "usable_reads": dna_usable_counts.get(sample_id),
+ }
+ )
+
+ rna_raw_reads = sum(row.get("reads") or 0 for row in sequencing_rows if row["modality"] == "RNA")
+ dna_raw_reads = sum(row.get("reads") or 0 for row in sequencing_rows if row["modality"] == "DNA")
+ rna_transcriptome_count = sum(rna_transcriptome_counts.values())
+ rna_genome_count = sum(rna_genome_counts.values())
+ dna_mapped_count = sum(dna_mapped_counts.values())
+ dna_usable_count = sum(dna_usable_counts.values())
+
+ mapping_quality = {
+ "rna_confidently_mapped_to_transcriptome_reads": rna_transcriptome_count,
+ "rna_confidently_mapped_to_transcriptome_percent": pct(rna_transcriptome_count, rna_raw_reads),
+ "rna_confidently_mapped_to_genome_reads": rna_genome_count,
+ "rna_confidently_mapped_to_genome_percent": pct(rna_genome_count, rna_raw_reads),
+ "dna_confidently_mapped_reads": dna_mapped_count,
+ "dna_confidently_mapped_percent": pct(dna_mapped_count, dna_raw_reads),
+ "dna_unique_reads": dna_usable_count,
+ "dna_unique_reads_percent": pct(dna_usable_count, dna_raw_reads),
+ }
+ main_statistics = [
+ {
+ "metric": "RNA confidently mapped to transcriptome",
+ "value": mapping_quality["rna_confidently_mapped_to_transcriptome_percent"],
+ "count": rna_transcriptome_count,
+ "denominator": rna_raw_reads,
+ "value_type": "percent",
+ "subtitle": "STARsolo GeneFull unique reads / raw RNA reads",
+ "modality": "RNA",
+ },
+ {
+ "metric": "DNA unique reads",
+ "value": mapping_quality["dna_unique_reads_percent"],
+ "count": dna_usable_count,
+ "denominator": dna_raw_reads,
+ "value_type": "percent",
+ "subtitle": "Final NoDup BAM read pairs / raw DNA reads",
+ "modality": "DNA",
+ },
+ ]
+ libraries = [
+ {
+ "library_name": library_name,
+ "mapping_quality": mapping_quality,
+ "main_statistics": main_statistics,
+ "sequencing_quality": sequencing_rows,
+ }
+ ]
+ export_rows = build_export_rows(libraries)
+
+ return {
+ "generated_at": datetime.now(timezone.utc).isoformat(),
+ "library_name": library_name,
+ "libraries": libraries,
+ "mapping_quality": mapping_quality,
+ "sequencing_quality": sequencing_rows,
+ "export_rows": export_rows,
+ "inputs": {
+ "file_count": collected["input_file_count"],
+ "rna_summary_count": len(collected["rna_summaries"]),
+ "flagstat_count": len(collected["flagstats"]),
+ "duplicate_metrics_count": len(collected["duplicate_metrics"]),
+ "samtools_stats_count": len(collected["samtools_stats"]),
+ },
+ "raw": collected,
+ }
+
+
+def export_value(value, value_type=None):
+ if value_type == "percent":
+ return fmt_pct(value)
+ if isinstance(value, int):
+ return str(value)
+ if isinstance(value, float):
+ return f"{value:.4g}"
+ if value is None:
+ return "n/a"
+ return str(value)
+
+
+def build_export_rows(libraries):
+ rows = []
+ for library in libraries:
+ library_name = library["library_name"]
+ for card in library["main_statistics"]:
+ rows.append(
+ {
+ "section": "Main statistics",
+ "library": library_name,
+ "modality": card["modality"],
+ "fastq_id": "",
+ "metric": card["metric"],
+ "value": export_value(card.get("value"), card.get("value_type")),
+ "absolute_reads": fmt_int(card.get("count")),
+ "raw_reads": fmt_int(card.get("denominator")),
+ "number_of_reads": "",
+ "confidently_mapped": "",
+ "valid_sample_barcodes": "",
+ "valid_cell_barcodes": "",
+ "valid_modality_barcodes": "",
+ "usable_reads": "",
+ "details": card["subtitle"],
+ }
+ )
+ for row in library["sequencing_quality"]:
+ rows.append(
+ {
+ "section": "Sequencing quality",
+ "library": library_name,
+ "modality": row["modality"],
+ "fastq_id": row["sample_id"],
+ "metric": "sample-level sequencing QC",
+ "value": "",
+ "number_of_reads": fmt_int(row.get("reads")),
+ "confidently_mapped": fmt_count_pct(row.get("confidently_mapped_reads"), row.get("reads")),
+ "valid_sample_barcodes": fmt_pct(row.get("valid_sample_barcodes")),
+ "valid_modality_barcodes": fmt_pct(row.get("valid_modality_barcodes"))
+ if row["modality"] == "DNA"
+ else "n/a",
+ "valid_cell_barcodes": fmt_pct(row.get("valid_cell_barcodes")),
+ "usable_reads": fmt_int(row.get("usable_reads")),
+ "details": "",
+ }
+ )
+ return rows
+
+
+def metric_card(title, value, subtitle, modality=None):
+ modality_class = (modality or "").lower()
+ absolute_line = ""
+ if isinstance(value, dict):
+ count = value.get("count")
+ denominator = value.get("denominator")
+ value = value.get("percent")
+ absolute_line = f"
{fmt_int(count)} / {fmt_int(denominator)} raw reads
"
+ return f"""
+
+
{html.escape(title)}
+
{fmt_pct(value)}
+ {absolute_line}
+
+
{html.escape(subtitle)}
+
+ """
+
+
+def sequencing_table(rows):
+ row_html = []
+ for row in rows:
+ modality_class = "rna" if row["modality"] == "RNA" else "dna"
+ row_html.append(
+ f"""
+
+ | {html.escape(row['modality'])} |
+ {html.escape(row['sample_id'])} |
+ {fmt_int(row.get('reads'))} |
+ {fmt_pct(row.get('valid_sample_barcodes'))} |
+ {fmt_pct(row.get('valid_modality_barcodes')) if row['modality'] == 'DNA' else 'n/a'} |
+ {fmt_pct(row.get('valid_cell_barcodes'))} |
+ {fmt_count_pct(row.get('confidently_mapped_reads'), row.get('reads'))} |
+ {fmt_int(row.get('usable_reads'))} |
+
+ """
+ )
+
+ return f"""
+
+
+
+ | Modality |
+ Fastq ID |
+ Number of reads |
+ Valid sample barcodes |
+ Valid modality barcodes |
+ Valid cell barcodes |
+ Confidently mapped to genome |
+ Usable reads |
+
+
+
+ {''.join(row_html) if row_html else '| No sequencing-quality inputs were detected. |
'}
+
+
+ """
+
+
+def render_library(library):
+ cards = []
+ for card in library["main_statistics"]:
+ cards.append(
+ metric_card(
+ card["metric"],
+ {
+ "percent": card.get("value"),
+ "count": card.get("count"),
+ "denominator": card.get("denominator"),
+ },
+ card["subtitle"],
+ card.get("modality"),
+ )
+ )
+
+ return f"""
+
+
+
+
+ {''.join(cards)}
+
+
+
+
+
+ {sequencing_table(library['sequencing_quality'])}
+
+
+ """
+
+
+def render_html(metrics):
+ libraries = metrics.get("libraries") or []
+ library_label = metrics.get("library_name") or "unknown library"
+ export_rows_json = json.dumps(metrics.get("export_rows", []), ensure_ascii=False).replace("", "<\\/")
+
+ return f"""
+
+
+
+
+ TrESFlow QC Report
+
+
+
+
+
+
+
TrESFlow QC Report {html.escape(library_label)}
+
Generated {html.escape(metrics['generated_at'])}
+
+
+
+
+
+
+
+ {''.join(render_library(library) for library in libraries) if libraries else 'No library metrics were detected.
'}
+
+
+
+
+
+"""
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--input-dir", required=True, type=Path)
+ parser.add_argument("--output-html", required=True, type=Path)
+ parser.add_argument("--output-json", required=True, type=Path)
+ parser.add_argument("--library-name", default="unknown library")
+ args = parser.parse_args()
+
+ collected = collect_inputs(args.input_dir)
+ metrics = build_metrics(collected, args.library_name)
+
+ args.output_json.write_text(json.dumps(metrics, indent=2, sort_keys=True), encoding="utf-8")
+ args.output_html.write_text(render_html(metrics), encoding="utf-8")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/conf/base.config b/conf/base.config
index b7ea605..098efc2 100644
--- a/conf/base.config
+++ b/conf/base.config
@@ -7,6 +7,11 @@ process {
// Scheduler reservations stay moderate by default so independent samples,
// groups, and marks can overlap under the local executor.
+ withLabel: process_single {
+ cpus = Math.max(1, Math.min((params.helper_cpus ?: 4) as int, params.max_cpus as int))
+ memory = '4 GB'
+ time = '2h'
+ }
withName: TAG_RNA_SAMPLE_BARCODE {
cpus = Math.max(1, Math.min((params.tagging_cpus ?: 4) as int, params.max_cpus as int))
@@ -83,30 +88,71 @@ process {
time = '12h'
}
+ withName: FASTQC {
+ cpus = Math.max(1, Math.min((params.helper_cpus ?: 4) as int, params.max_cpus as int))
+ memory = '4 GB'
+ time = '2h'
+ }
+
+ withName: SAMTOOLS_IDXSTATS {
+ cpus = Math.max(1, Math.min((params.helper_cpus ?: 4) as int, params.max_cpus as int))
+ memory = '2 GB'
+ time = '1h'
+ }
+
+ withName: SAMTOOLS_QUICKCHECK {
+ cpus = 1
+ memory = '1 GB'
+ time = '1h'
+ }
+
+ withName: SAMTOOLS_QUICKCHECK_REPORT {
+ cpus = 1
+ memory = '1 GB'
+ time = '30m'
+ }
+
// ALIGN_DNA passes this CPU value to bwa-mem2 and samtools inside the wrapper.
withName: ALIGN_DNA {
cpus = Math.max(1, Math.min((params.dna_align_cpus ?: 16) as int, params.max_cpus as int))
time = '12h'
}
- withName: MARK_DUPLICATES_DNA {
+ withName: GATK4_MARKDUPLICATES {
cpus = 1
memory = '8 GB'
time = '6h'
}
+ withName: NORMALIZE_DNA_MARKDUPLICATES {
+ cpus = 1
+ memory = '2 GB'
+ time = '1h'
+ }
+
withName: SPLIT_DUPLICATES_DNA {
cpus = Math.max(1, Math.min((params.helper_cpus ?: 4) as int, params.max_cpus as int))
memory = '4 GB'
time = '2h'
}
- withName: BAM_COVERAGE_DNA {
+ withName: CHECK_DNA_NODUP_BAM {
+ cpus = Math.max(1, Math.min((params.helper_cpus ?: 4) as int, params.max_cpus as int))
+ memory = '2 GB'
+ time = '1h'
+ }
+
+ withName: DEEPTOOLS_BAMCOVERAGE {
cpus = Math.max(1, Math.min((params.coverage_cpus ?: 8) as int, params.max_cpus as int))
memory = '4 GB'
time = '2h'
}
+ withName: NORMALIZE_DNA_BAMCOVERAGE {
+ cpus = 1
+ memory = '1 GB'
+ time = '30m'
+ }
}
timeline {
diff --git a/conf/modules.config b/conf/modules.config
index 20b79ff..ea01467 100644
--- a/conf/modules.config
+++ b/conf/modules.config
@@ -7,3 +7,59 @@
must not define a global `publishDir` without a target path.
----------------------------------------------------------------------------------------
*/
+
+process {
+ withName: FASTQC {
+ publishDir = [
+ path : "${params.outdir ?: "${projectDir}/results"}/qc/fastqc",
+ mode : params.publish_dir_mode,
+ overwrite: true
+ ]
+ }
+
+ withName: SAMTOOLS_FLAGSTAT {
+ publishDir = [
+ path : "${params.outdir ?: "${projectDir}/results"}/qc/samtools",
+ mode : params.publish_dir_mode,
+ overwrite: true,
+ pattern : "*.flagstat"
+ ]
+ }
+
+ withName: SAMTOOLS_STATS {
+ publishDir = [
+ path : "${params.outdir ?: "${projectDir}/results"}/qc/samtools",
+ mode : params.publish_dir_mode,
+ overwrite: true,
+ pattern : "*.stats"
+ ]
+ }
+
+ withName: SAMTOOLS_IDXSTATS {
+ publishDir = [
+ path : "${params.outdir ?: "${projectDir}/results"}/qc/samtools",
+ mode : params.publish_dir_mode,
+ overwrite: true,
+ pattern : "*.idxstats"
+ ]
+ }
+
+ withName: GATK4_MARKDUPLICATES {
+ ext.prefix = { "${meta.id}_MarkedDup.bam" }
+ ext.args = '--REMOVE_DUPLICATES false --BARCODE_TAG CB --CREATE_INDEX true --MAX_RECORDS_IN_RAM 10000000'
+ }
+
+ withName: DEEPTOOLS_BAMCOVERAGE {
+ ext.prefix = { "${meta.id}_NoDup" }
+ ext.args = { "-bs 100 --extendReads --centerReads --effectiveGenomeSize ${meta.dna_effective_genome_size}" }
+ }
+
+ withName: MULTIQC {
+ publishDir = [
+ path : "${params.outdir ?: "${projectDir}/results"}/multiqc",
+ mode : params.publish_dir_mode,
+ overwrite: true
+ ]
+ ext.prefix = 'multiqc_report'
+ }
+}
diff --git a/conf/test.config b/conf/test.config
index 0826d27..bb62fb6 100644
--- a/conf/test.config
+++ b/conf/test.config
@@ -81,18 +81,35 @@ process {
cpus = 1
}
- withName: MARK_DUPLICATES_DNA {
+ withName: SPLIT_DUPLICATES_DNA {
ext.mock = true
+ cpus = 1
}
- withName: SPLIT_DUPLICATES_DNA {
+ withName: CHECK_DNA_NODUP_BAM {
ext.mock = true
cpus = 1
+ memory = '1 GB'
}
- withName: BAM_COVERAGE_DNA {
- ext.mock = true
+ withName: DEEPTOOLS_BAMCOVERAGE {
cpus = 1
+ memory = '1 GB'
}
+ withName: SAMTOOLS_FLAGSTAT {
+ ext.when = false
+ }
+
+ withName: SAMTOOLS_STATS {
+ ext.when = false
+ }
+
+ withName: SAMTOOLS_IDXSTATS {
+ ext.when = false
+ }
+
+ withName: SAMTOOLS_QUICKCHECK {
+ ext.when = false
+ }
}
diff --git a/docs/architecture/implemented_pipeline.md b/docs/architecture/implemented_pipeline.md
index 50c4c06..2e28a04 100644
--- a/docs/architecture/implemented_pipeline.md
+++ b/docs/architecture/implemented_pipeline.md
@@ -3,8 +3,8 @@
Core workflow only:
- RNA through the repo-owned STARsolo, filtered-BAM, and coverage stages
-- DNA through `BAM_COVERAGE_DNA`
-- Shared sequencing-efficiency UpSet PDF reporting from tag-record and alignment channels
+- DNA through repo-owned tagging/splitting/alignment, nf-core `gatk4/markduplicates`, repo-owned NoDup extraction, and nf-core `deeptools/bamcoverage`
+- nf-core FastQC/samtools sidecar QC, nf-core MultiQC, and a TrESFlow-specific HTML report at the end of the run
```mermaid
flowchart TD
@@ -27,7 +27,6 @@ flowchart TD
REF --> DNA2
REF --> DNA5
REF --> DNA8
- DERIVE --> REPORT
DERIVE --> RNA0
DERIVE --> RNA4
DERIVE --> DNA0
@@ -54,12 +53,32 @@ flowchart TD
DNA3[TRIM_DNA_FASTQS]
DNA4[SPLIT_DNA_READS]
DNA5[ALIGN_DNA]
- DNA6[MARK_DUPLICATES_DNA]
+ DNA6[nf-core GATK4_MARKDUPLICATES\n+ TrESFlow filename normalization]
DNA7[SPLIT_DUPLICATES_DNA]
- DNA8[BAM_COVERAGE_DNA]
+ DNA8[CHECK_DNA_NODUP_BAM\n+ nf-core DEEPTOOLS_BAMCOVERAGE]
DNA0 --> DNA1 --> DNA2 --> DNA3 --> DNA4 --> DNA5 --> DNA6 --> DNA7 --> DNA8
end
+ subgraph Reporting[Shared Reporting]
+ FASTQC[nf-core FASTQC]
+ SAMTOOLS[nf-core SAMTOOLS_FLAGSTAT/STATS/IDXSTATS/QUICKCHECK]
+ MULTIQC[nf-core MULTIQC]
+ TRESHTML[TRES_REPORT_HTML]
+ end
+
+ RNA0 --> FASTQC
+ RNA7 --> SAMTOOLS
+ RNA6 --> MULTIQC
+ DNA0 --> FASTQC
+ DNA5 --> SAMTOOLS
+ DNA6 --> SAMTOOLS
+ DNA7 --> SAMTOOLS
+ FASTQC --> MULTIQC
+ SAMTOOLS --> MULTIQC
+ SAMTOOLS --> TRESHTML
+ RNA6 --> TRESHTML
+ RNA2 --> TRESHTML
+ DNA2 --> TRESHTML
```
Notes:
@@ -67,5 +86,8 @@ Notes:
- One hierarchical samplesheet can describe RNA-only, DNA-only, or combined runs.
- `sb_group_map.tsv`, `dna_mo_map.tsv`, and DNA modality whitelist files are internal artifacts, not user inputs.
- `TAG_DNA_CELL_BARCODE` uses DNA `i1` as the ligation source: single reads use starts `15,53,91`; dual reads use starts `41,79,117`.
-- DNA alignment does not enforce a low-count cell-barcode threshold; the BAM-derived `CB>100 +` category in sequencing-efficiency plots shows that status.
+- nf-core FastQC and samtools modules are sidecar QC readers only; they do not alter downstream TrESFlow outputs.
+- nf-core `gatk4/markduplicates` replaces the previous local GATK invocation but preserves `--BARCODE_TAG CB`, `--REMOVE_DUPLICATES false`, index creation, and the historical TrESFlow output names via a normalization adapter.
+- nf-core `deeptools/bamcoverage` replaces the previous direct `bamCoverage` call. A repo-owned precheck keeps the previous zero-mapped NoDup BAM behavior by publishing a warning artifact and skipping coverage when needed.
+- `TRES_REPORT_HTML` renders `tres_report/tres_report.html` and `tres_report_metrics.json` from existing TrES stats, STARsolo summaries, samtools outputs, and GATK duplicate metrics.
- The active core runtime lives under [`scripts/core_runtime/`](/mnt/dataFast/ahrmad/tresflowdir/TrESFlow/scripts/core_runtime).
diff --git a/docs/output.md b/docs/output.md
index ca85151..018907a 100644
--- a/docs/output.md
+++ b/docs/output.md
@@ -22,6 +22,10 @@ DNA-related outputs:
Shared reporting outputs:
- `pipeline_info/`
+- `qc/fastqc/`
+- `qc/samtools/`
+- `multiqc/`
+- `tres_report/`
## RNA outputs
@@ -39,6 +43,7 @@ SAM read-group header TSVs are internal work files and are not published.
STARsolo and filtered BAM outputs:
- `_.Solo.outGeneFull/`
+- `_.Log.final.out`
- `_.filtered_cells.bam`
- `_.stranded_*.bw`
- `_.unstranded_*.bw`
@@ -64,7 +69,7 @@ Duplicate-marked BAMs, final duplicate-filtered BAMs, and coverage tracks:
- `___NoDup.bam.bai`
- `___NoDup.bw`
-`*_MarkedDup.bam` is retained so sequencing-efficiency reporting can count aligned DNA reads before duplicate removal. `*_NoDup.bam` remains the duplicate-filtered output used for downstream DNA coverage.
+`*_MarkedDup.bam` is generated by nf-core `gatk4/markduplicates` with TrESFlow's barcode-aware duplicate settings and then normalized back to the historical TrESFlow filename contract. `*_NoDup.bam` remains the duplicate-filtered output used for downstream DNA coverage. `*_NoDup.bw` is generated via nf-core `deeptools/bamcoverage` after the pipeline confirms that the NoDup BAM has mapped reads.
## Tagging/count/stat outputs
@@ -92,6 +97,58 @@ Tagging summaries are published with modality-specific names:
Only published tag-record tables are gzipped. Uncompressed tag-record TSVs are internal work files.
+## QC and HTML reports
+
+### `qc/fastqc/`
+
+nf-core `fastqc` writes raw FASTQ QC files:
+
+- `*_fastqc.html`
+- `*_fastqc.zip`
+
+### `qc/samtools/`
+
+When real BAMs are produced, nf-core samtools sidecar modules write standardized BAM QC files:
+
+- `*.flagstat`
+- `*.stats`
+- `*.idxstats`
+- `*.quickcheck.tsv`
+
+These modules read existing RNA filtered BAMs and DNA aligned / marked-duplicate / NoDup BAMs. They do not modify any downstream TrESFlow outputs.
+
+In `-profile test`, the samtools sidecars are disabled because the smoke profile intentionally uses lightweight mock BAM text files.
+
+### `multiqc/`
+
+nf-core `multiqc` writes:
+
+- `multiqc_report.html`
+- `multiqc_report_data/`
+
+MultiQC aggregates supported logs and QC text files, including FastQC, STAR logs, samtools outputs, and GATK duplicate metrics when present.
+
+### `tres_report/`
+
+The TrESFlow-specific end-of-run report writes:
+
+- `tres_report.html`
+- `tres_report_metrics.json`
+
+This custom report is separate from MultiQC. It summarizes TrES-specific RNA/DNA mapping and barcode metrics in a compact HTML page:
+
+- the samplesheet `library_name` in the report title and per-library section header
+- per-library main-statistic cards for RNA mapping and DNA mapped/unique-read summaries
+- a detailed per-library sequencing QC table for barcode, read-count, and UMI/no-UMI fields
+- browser-side `Export CSV` and `Export Excel` buttons for the displayed report metrics
+- RNA mapping to transcriptome and genome from STARsolo `Summary.csv`
+- DNA mapped-read and unique-read metrics from samtools/GATK outputs when DNA BAM QC is present
+- RNA/DNA sample-barcode and cell-barcode rates from TrES tagging stats
+- RNA observed UMI count from UMI tagging counts
+- DNA modality barcode rate from DNA modality tagging stats
+
+DNA has no UMI metric by design.
+
## Pipeline information
`pipeline_info/` contains execution metadata and the derived helper contract written from the YAML samplesheet.
@@ -124,6 +181,6 @@ The pipeline does not keep intermediate tagging, uSAM, duplicate-split, or cover
- published RNA FASTQs are the grouped split FASTQs under `rna_split_fastqs/`
- published DNA FASTQs are the grouped and marked split FASTQs under `dna_split_fastqs/`
- earlier tag, trim, RNA uSAM, STAR aligned BAM, tag-record, and non-published coverage side products are transient task outputs
-- DNA duplicate-marked BAMs are published under `dna_align/` for sequencing-efficiency reporting
+- DNA duplicate-marked BAMs are published under `dna_align/` as duplicate-aware alignment outputs
By default, `--cleanup_work true` asks Nextflow to clean successful task work directories after the workflow finishes successfully. This preserves published outputs while reducing retained `work/` storage. Set `--cleanup_work false` to keep work directories for debugging or a more resume-friendly run.
diff --git a/docs/usage.md b/docs/usage.md
index 6a73b81..a1c1230 100644
--- a/docs/usage.md
+++ b/docs/usage.md
@@ -5,14 +5,22 @@
`TrESFlow` supports one public input contract: a single hierarchical YAML samplesheet passed with `--samplesheet`.
There is no CSV input mode in this repository.
-The pipeline runs two independent modality branches from that YAML, then builds sequencing-efficiency UpSet plots from the published tag-record and alignment channels:
+The pipeline runs two independent modality branches from that YAML, then builds nf-core QC sidecar outputs, MultiQC, and a compact TrESFlow-specific HTML report from the published tag-record, STAR, samtools, and alignment channels:
- `rna`: sample-barcode tagging, UMI tagging, cell-barcode tagging, trimming, split by SB groups, `FqToSAM`, STARsolo, filtered BAM, bigWigs
- `dna`: sample-barcode tagging, modality tagging, cell-barcode tagging, trimming, split by SB groups and DNA marks, alignment, duplicate marking, NoDup BAM, bigWig
-Sequencing-efficiency outputs are written to `TrES_Stats/` as UpSet PDFs only. Sankey plots, HTML reports, count tables, combined RNA+DNA reports, and sequencing-efficiency warning TSVs are not produced. Optional unavailable BAM-derived categories are skipped with warnings in the process log.
+End-of-run reporting is written separately:
-DNA alignment no longer filters out low-count cell barcodes during `ALIGN_DNA`. Low-count status is visualized in sequencing-efficiency plots as `CB>100 +`, using BAM-derived unique query-name read-pair support.
+- `tres_report/tres_report.html`: TrESFlow-specific per-library RNA/DNA mapping and barcode summary with CSV/Excel export buttons
+- `tres_report/tres_report_metrics.json`: machine-readable metrics used by the HTML report
+- `multiqc/multiqc_report.html`: nf-core MultiQC aggregation of supported logs and QC files
+- `qc/fastqc/*_fastqc.{html,zip}`: nf-core FastQC reports for raw FASTQs
+- `qc/samtools/*.flagstat`, `*.stats`, `*.idxstats`, and `*.quickcheck.tsv`: nf-core samtools sidecar QC for real BAM outputs
+
+The samtools sidecars are disabled in `-profile test` because the smoke profile uses mock BAM text files rather than valid BAMs.
+
+DNA alignment no longer filters out low-count cell barcodes during `ALIGN_DNA`. Duplicate-aware DNA outputs are represented by the published `*_MarkedDup.bam` and `*_NoDup.bam` files.
## Quick Start
@@ -90,7 +98,7 @@ samples:
### `runtime`
-- `env_prefix`: environment prefix containing `python3`, `codon`, `trim_galore`, `STAR`, `samtools`, `bedGraphToBigWig`, `bwa-mem2`, `bamCoverage`, and `gatk`
+- `env_prefix`: environment prefix containing `python3`, `codon`, `trim_galore`, `STAR`, `samtools`, `bedGraphToBigWig`, `bwa-mem2`, `bamCoverage`, `FastQC`, and `gatk`
- `tmpdir`: optional explicit task temporary directory. If omitted, the pipeline uses `--outdir`. The pipeline creates it if missing and fails if it is not writable.
### `references`
diff --git a/modules.json b/modules.json
index 7b81505..ea0a167 100644
--- a/modules.json
+++ b/modules.json
@@ -1,5 +1,52 @@
{
"name": "nf-core/tres",
"homePage": "",
- "repos": {}
-}
\ No newline at end of file
+ "repos": {
+ "https://github.com/nf-core/modules.git": {
+ "modules": {
+ "nf-core": {
+ "deeptools/bamcoverage": {
+ "branch": "master",
+ "git_sha": "6d46786420b4d7bc88eba026eb389c0c5535d120",
+ "installed_by": ["modules"]
+ },
+ "fastqc": {
+ "branch": "master",
+ "git_sha": "6d46786420b4d7bc88eba026eb389c0c5535d120",
+ "installed_by": ["modules"]
+ },
+ "gatk4/markduplicates": {
+ "branch": "master",
+ "git_sha": "6d46786420b4d7bc88eba026eb389c0c5535d120",
+ "installed_by": ["modules"]
+ },
+ "multiqc": {
+ "branch": "master",
+ "git_sha": "98403d15b0e50edae1f3fec5eae5e24982f1fade",
+ "installed_by": ["modules"]
+ },
+ "samtools/flagstat": {
+ "branch": "master",
+ "git_sha": "6d46786420b4d7bc88eba026eb389c0c5535d120",
+ "installed_by": ["modules"]
+ },
+ "samtools/idxstats": {
+ "branch": "master",
+ "git_sha": "6d46786420b4d7bc88eba026eb389c0c5535d120",
+ "installed_by": ["modules"]
+ },
+ "samtools/quickcheck": {
+ "branch": "master",
+ "git_sha": "6d46786420b4d7bc88eba026eb389c0c5535d120",
+ "installed_by": ["modules"]
+ },
+ "samtools/stats": {
+ "branch": "master",
+ "git_sha": "6d46786420b4d7bc88eba026eb389c0c5535d120",
+ "installed_by": ["modules"]
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/modules/local/check_dna_nodup_bam/main.nf b/modules/local/check_dna_nodup_bam/main.nf
new file mode 100644
index 0000000..0a73226
--- /dev/null
+++ b/modules/local/check_dna_nodup_bam/main.nf
@@ -0,0 +1,89 @@
+/*
+ * Guard nf-core/deeptools/bamcoverage from empty DNA NoDup BAMs.
+ *
+ * deepTools can be noisy or unhelpful on BAMs with zero mapped reads. The old
+ * local BAM_COVERAGE_DNA module skipped those BAMs and wrote a warning artifact;
+ * this module preserves that behavior before routing non-empty BAMs to nf-core.
+ */
+
+import RuntimeSupport
+
+process CHECK_DNA_NODUP_BAM {
+ tag "${splitName}"
+ label 'process_single'
+
+ publishDir "${params.outdir ?: "${projectDir}/results"}/pipeline_info/warnings", mode: params.publish_dir_mode, overwrite: true, pattern: "*.zero_mapped_nodup_bam.tsv"
+
+ input:
+ tuple val(splitName), val(meta), path(noDupBam, stageAs: "input_NoDup.bam"), path(noDupBai, stageAs: "input_NoDup.bam.bai"), val(effectiveGenomeSize)
+
+ output:
+ tuple val(splitName), val(meta), path("*_NoDup.bam"), path("*_NoDup.bam.bai"), val(effectiveGenomeSize), optional: true, emit: ready
+ tuple val(splitName), val(meta), path("${splitName}.zero_mapped_nodup_bam.tsv"), optional: true, emit: warnings
+ path("versions.yml"), emit: versions
+
+ script:
+ def mode = task.ext.mock ? 'mock' : 'real'
+ def runtimeExports = RuntimeSupport.shellExports(meta)
+ def sampleId = meta.id as String
+ def suffix = splitName.replaceFirst("^${sampleId}_", '')
+ def tokens = suffix.tokenize('_')
+ def groupName = tokens ? tokens[0] : ''
+ def markName = tokens.size() > 1 ? tokens[1..-1].join('_') : ''
+
+ if( mode == 'mock' ) {
+ """
+ ${runtimeExports}
+
+ touch "${splitName}_NoDup.bam" "${splitName}_NoDup.bam.bai"
+
+ cat <<-END_VERSIONS > versions.yml
+ "${task.process}":
+ component: "local"
+ END_VERSIONS
+ """
+ }
+ else {
+ """
+ ${runtimeExports}
+
+ if [[ ! -x "\$SAMTOOLS_BIN" ]]; then
+ echo "Missing configured DNA runtime executable: \$SAMTOOLS_BIN" >&2
+ exit 1
+ fi
+
+ mapped_reads="\$("\$SAMTOOLS_BIN" view --threads "${task.cpus}" -c -F 4 "${noDupBam}")"
+ if [[ "\${mapped_reads}" -eq 0 ]]; then
+ bam_path="\$(readlink -f "${noDupBam}")"
+ cat >&2 <<'EOF'
+================================================================================
+WARNING: ZERO MAPPED READS IN DNA NoDup BAM
+================================================================================
+EOF
+ echo "Sample: ${sampleId}" >&2
+ echo "Group: ${groupName}" >&2
+ echo "Mark: ${markName}" >&2
+ echo "BAM: \${bam_path}" >&2
+ echo "Mapped reads: \${mapped_reads}" >&2
+ echo "Skipped nf-core/deeptools/bamcoverage for ${splitName}" >&2
+ printf 'sample\tgroup\tmark\tbam\tmapped_reads\tskipped_output\n' > "${splitName}.zero_mapped_nodup_bam.tsv"
+ printf '%s\t%s\t%s\t%s\t%s\t%s\n' \\
+ "${sampleId}" \\
+ "${groupName}" \\
+ "${markName}" \\
+ "\${bam_path}" \\
+ "\${mapped_reads}" \\
+ "${splitName}_NoDup.bw" \\
+ >> "${splitName}.zero_mapped_nodup_bam.tsv"
+ else
+ cp -L "${noDupBam}" "${splitName}_NoDup.bam"
+ cp -L "${noDupBai}" "${splitName}_NoDup.bam.bai"
+ fi
+
+ cat <<-END_VERSIONS > versions.yml
+ "${task.process}":
+ component: "local"
+ END_VERSIONS
+ """
+ }
+}
diff --git a/modules/local/normalize_dna_bamcoverage/main.nf b/modules/local/normalize_dna_bamcoverage/main.nf
new file mode 100644
index 0000000..b9c5956
--- /dev/null
+++ b/modules/local/normalize_dna_bamcoverage/main.nf
@@ -0,0 +1,30 @@
+/*
+ * Normalize nf-core/deeptools/bamcoverage bigWig naming back to TrESFlow's
+ * historical _NoDup.bw output contract.
+ */
+
+process NORMALIZE_DNA_BAMCOVERAGE {
+ tag "${splitName}"
+ label 'process_single'
+
+ publishDir "${params.outdir ?: "${projectDir}/results"}/dna_align", mode: params.publish_dir_mode, overwrite: true, pattern: "${splitName}_NoDup.bw"
+
+ input:
+ tuple val(splitName), val(meta), path(bigwig)
+
+ output:
+ tuple val(splitName), val(meta), path("${splitName}_NoDup.bw"), emit: bw
+ path("versions.yml"), emit: versions
+
+ script:
+ """
+ if [[ "\$(readlink -f "${bigwig}")" != "\$(readlink -f "${splitName}_NoDup.bw" 2>/dev/null || true)" ]]; then
+ cp -L "${bigwig}" "${splitName}_NoDup.bw"
+ fi
+
+ cat <<-END_VERSIONS > versions.yml
+ "${task.process}":
+ component: "local"
+ END_VERSIONS
+ """
+}
diff --git a/modules/local/normalize_dna_markduplicates/main.nf b/modules/local/normalize_dna_markduplicates/main.nf
new file mode 100644
index 0000000..29ea524
--- /dev/null
+++ b/modules/local/normalize_dna_markduplicates/main.nf
@@ -0,0 +1,41 @@
+/*
+ * Normalize nf-core/gatk4/markduplicates outputs back to the TrESFlow DNA
+ * filename contract used by downstream NoDup extraction and reporting.
+ */
+
+process NORMALIZE_DNA_MARKDUPLICATES {
+ tag "${splitName}"
+ label 'process_single'
+
+ publishDir "${params.outdir ?: "${projectDir}/results"}/dna_align", mode: params.publish_dir_mode, overwrite: true, pattern: "${splitName}_MarkedDup.bam*"
+ publishDir "${params.outdir ?: "${projectDir}/results"}/dna_align", mode: params.publish_dir_mode, overwrite: true, pattern: "${splitName}.DuplicateMetrics.txt"
+
+ input:
+ tuple val(splitName), val(meta), path(markedDupBam), path(markedDupBai), path(markedDupMetrics)
+
+ output:
+ tuple val(splitName), val(meta), path("${splitName}_MarkedDup.bam"), emit: bam
+ tuple val(splitName), val(meta), path("${splitName}_MarkedDup.bam.bai"), emit: bai
+ tuple val(splitName), val(meta), path("${splitName}.DuplicateMetrics.txt"), emit: metrics
+ path("versions.yml"), emit: versions
+
+ script:
+ """
+ copy_if_needed() {
+ src="\$1"
+ dest="\$2"
+ if [[ "\$(readlink -f "\${src}")" != "\$(readlink -f "\${dest}" 2>/dev/null || true)" ]]; then
+ cp -L "\${src}" "\${dest}"
+ fi
+ }
+
+ copy_if_needed "${markedDupBam}" "${splitName}_MarkedDup.bam"
+ copy_if_needed "${markedDupBai}" "${splitName}_MarkedDup.bam.bai"
+ copy_if_needed "${markedDupMetrics}" "${splitName}.DuplicateMetrics.txt"
+
+ cat <<-END_VERSIONS > versions.yml
+ "${task.process}":
+ component: "local"
+ END_VERSIONS
+ """
+}
diff --git a/modules/local/rna_starsolo_align/main.nf b/modules/local/rna_starsolo_align/main.nf
index 7e3b337..eedb4ed 100644
--- a/modules/local/rna_starsolo_align/main.nf
+++ b/modules/local/rna_starsolo_align/main.nf
@@ -19,13 +19,16 @@ process RNA_STARSOLO_ALIGN {
label 'codon_wrapper'
publishDir "${params.outdir ?: "${projectDir}/results"}/rna_align", mode: 'copy', overwrite: true, pattern: "${splitName}.Solo.outGeneFull"
+ publishDir "${params.outdir ?: "${projectDir}/results"}/rna_align", mode: 'copy', overwrite: true, pattern: "${splitName}.Log.final.out"
input:
tuple val(splitName), val(meta), path(usam), val(starIndexDir)
output:
tuple val(splitName), val(meta), path("${splitName}.Solo.outGeneFull"), emit: solo_dir
+ tuple val(splitName), val(meta), path("${splitName}.Solo.outGeneFull/Summary.csv"), emit: solo_summary
tuple val(splitName), val(meta), path("${splitName}.Aligned.sortedByCoord.out.bam"), emit: aligned_bam
+ tuple val(splitName), val(meta), path("${splitName}.Log.final.out"), emit: star_log
path("versions.yml"), emit: versions
script:
@@ -54,6 +57,53 @@ EOF
EOF
printf 'mock aligned bam for %s\n' "${splitName}" > "${splitName}.Aligned.sortedByCoord.out.bam"
+ cat > "${splitName}.Log.final.out" <<'EOF'
+ Started job on | mock
+ Started mapping on | mock
+ Finished on | mock
+ Mapping speed, Million of reads per hour | 1.00
+ Number of input reads | 1000
+ Average input read length | 100
+ UNIQUE READS:
+ Uniquely mapped reads number | 900
+ Uniquely mapped reads % | 90.00%
+ Average mapped length | 100.00
+ Number of splices: Total | 0
+ Number of splices: Annotated (sjdb) | 0
+ Number of splices: GT/AG | 0
+ Number of splices: GC/AG | 0
+ Number of splices: AT/AC | 0
+ Number of splices: Non-canonical | 0
+ Mismatch rate per base, % | 0.10%
+ Deletion rate per base | 0.00%
+ Deletion average length | 0.00
+ Insertion rate per base | 0.00%
+ Insertion average length | 0.00
+ MULTI-MAPPING READS:
+ Number of reads mapped to multiple loci | 50
+ % of reads mapped to multiple loci | 5.00%
+ Number of reads mapped to too many loci | 0
+ % of reads mapped to too many loci | 0.00%
+ UNMAPPED READS:
+ Number of reads unmapped: too many mismatches | 0
+ % of reads unmapped: too many mismatches | 0.00%
+ Number of reads unmapped: too short | 50
+ % of reads unmapped: too short | 5.00%
+ Number of reads unmapped: other | 0
+ % of reads unmapped: other | 0.00%
+ CHIMERIC READS:
+ Number of chimeric reads | 0
+ % of chimeric reads | 0.00%
+EOF
+ cat > "${splitName}.Solo.outGeneFull/Summary.csv" <<'EOF'
+Number of Reads,1000
+Reads Mapped to Genome: Unique+Multiple,0.95
+Reads Mapped to Genome: Unique,0.90
+Reads Mapped to GeneFull: Unique+Multiple GeneFull,0.85
+Reads Mapped to GeneFull: Unique GeneFull,0.80
+Estimated Number of Cells,1
+UMIs in Cells,100
+EOF
cat <<-END_VERSIONS > versions.yml
"${task.process}":
@@ -76,7 +126,7 @@ EOF
"${starIndexDir}" \\
"." \\
"${task.cpus}"
-
+
cat <<-END_VERSIONS > versions.yml
"${task.process}":
component: "local"
diff --git a/modules/local/samtools_quickcheck_report/main.nf b/modules/local/samtools_quickcheck_report/main.nf
new file mode 100644
index 0000000..b2c2d33
--- /dev/null
+++ b/modules/local/samtools_quickcheck_report/main.nf
@@ -0,0 +1,34 @@
+/*
+ * Convert nf-core/samtools/quickcheck exit codes into a small report artifact.
+ */
+
+process SAMTOOLS_QUICKCHECK_REPORT {
+ tag "${meta.id}"
+ label 'process_single'
+
+ publishDir "${params.outdir ?: "${projectDir}/results"}/qc/samtools", mode: params.publish_dir_mode, overwrite: true, pattern: "*.quickcheck.tsv"
+
+ input:
+ tuple val(meta), path(bam), val(exitCode)
+
+ output:
+ tuple val(meta), path("*.quickcheck.tsv"), emit: report
+ path("versions.yml"), emit: versions
+
+ script:
+ def prefix = meta.id
+ """
+ printf 'id\tbam\texit_code\tstatus\n' > "${prefix}.quickcheck.tsv"
+ if [[ "${exitCode}" == "0" ]]; then
+ status="pass"
+ else
+ status="fail"
+ fi
+ printf '%s\t%s\t%s\t%s\n' "${prefix}" "${bam}" "${exitCode}" "\${status}" >> "${prefix}.quickcheck.tsv"
+
+ cat <<-END_VERSIONS > versions.yml
+ "${task.process}":
+ component: "local"
+ END_VERSIONS
+ """
+}
diff --git a/modules/local/tres_report_html/main.nf b/modules/local/tres_report_html/main.nf
new file mode 100644
index 0000000..0c3e7dd
--- /dev/null
+++ b/modules/local/tres_report_html/main.nf
@@ -0,0 +1,37 @@
+/*
+ * Module: TRES_REPORT_HTML
+ *
+ * Builds a compact TrESFlow-specific HTML report from existing pipeline QC
+ * artifacts. This is intentionally separate from MultiQC because TrESFlow has
+ * assay-specific RNA/DNA barcode and mapping semantics that should be explained
+ * in one stable end-of-run page.
+ */
+
+process TRES_REPORT_HTML {
+ tag "${meta.id}"
+ label 'process_single'
+
+ publishDir "${params.outdir ?: "${projectDir}/results"}/tres_report", mode: 'copy', overwrite: true, pattern: "tres_report*"
+
+ input:
+ tuple val(meta), path(reportInputs, stageAs: "inputs/?/*")
+
+ output:
+ tuple val(meta), path("tres_report.html"), emit: html
+ tuple val(meta), path("tres_report_metrics.json"), emit: metrics_json
+ path("versions.yml"), emit: versions
+
+ script:
+ """
+ python3 "${projectDir}/bin/render_tres_report.py" \\
+ --input-dir inputs \\
+ --output-html tres_report.html \\
+ --output-json tres_report_metrics.json \\
+ --library-name "${meta.library_name ?: 'unknown library'}"
+
+ cat <<-END_VERSIONS > versions.yml
+ "${task.process}":
+ component: "local"
+ END_VERSIONS
+ """
+}
diff --git a/modules/nf-core/deeptools/bamcoverage/environment.yml b/modules/nf-core/deeptools/bamcoverage/environment.yml
new file mode 100644
index 0000000..c2d2fb3
--- /dev/null
+++ b/modules/nf-core/deeptools/bamcoverage/environment.yml
@@ -0,0 +1,8 @@
+---
+# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json
+channels:
+ - conda-forge
+ - bioconda
+dependencies:
+ - bioconda::deeptools=3.5.6
+ - bioconda::samtools=1.20
diff --git a/modules/nf-core/deeptools/bamcoverage/main.nf b/modules/nf-core/deeptools/bamcoverage/main.nf
new file mode 100644
index 0000000..bae5860
--- /dev/null
+++ b/modules/nf-core/deeptools/bamcoverage/main.nf
@@ -0,0 +1,67 @@
+process DEEPTOOLS_BAMCOVERAGE {
+ tag "$meta.id"
+ label 'process_low'
+
+ conda "${moduleDir}/environment.yml"
+ container "${ workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container ?
+ 'https://depot.galaxyproject.org/singularity/mulled-v2-eb9e7907c7a753917c1e4d7a64384c047429618a:28424fe3aec58d2b3e4e4390025d886207657d25-0':
+ 'quay.io/biocontainers/mulled-v2-eb9e7907c7a753917c1e4d7a64384c047429618a:28424fe3aec58d2b3e4e4390025d886207657d25-0' }"
+
+ input:
+ tuple val(meta) , path(input) , path(input_index)
+ path(fasta)
+ path(fasta_fai)
+ tuple val(meta2), path(blacklist)
+
+ output:
+ tuple val(meta), path("*.bigWig") , emit: bigwig , optional: true
+ tuple val(meta), path("*.bedgraph"), emit: bedgraph, optional: true
+ tuple val("${task.process}"), val('deeptools'), eval('bamCoverage --version | sed "s/bamCoverage //g"') , emit: versions_deeptools, topic: versions
+ tuple val("${task.process}"), val('samtools'), eval("samtools version | sed '1!d;s/.* //'") , emit: versions_samtools, topic: versions
+
+ when:
+ task.ext.when == null || task.ext.when
+
+ script:
+ def args = task.ext.args ?: ''
+ def prefix = task.ext.prefix ?: "${meta.id}"
+ def blacklist_cmd = blacklist ? "--blackListFileName ${blacklist}" : ""
+ def extension = args.contains("--outFileFormat bedgraph") || args.contains("-of bedgraph") ? "bedgraph" : "bigWig"
+
+ // cram_input is currently not working with deeptools
+ // therefore it's required to convert cram to bam first
+ def is_cram = input.Extension == "cram" ? true : false
+ def input_out = is_cram ? input.BaseName + ".bam" : "${input}"
+ def fai_reference = fasta_fai ? "--fai-reference ${fasta_fai}" : ""
+
+ if (is_cram){
+ """
+ samtools view -T $fasta $input $fai_reference -@ $task.cpus -o $input_out
+ samtools index -b $input_out -@ $task.cpus
+
+ bamCoverage \\
+ --bam $input_out \\
+ $args \\
+ --numberOfProcessors ${task.cpus} \\
+ --outFileName ${prefix}.${extension} \\
+ $blacklist_cmd
+ """
+ }
+ else {
+ """
+ bamCoverage \\
+ --bam $input_out \\
+ $args \\
+ --numberOfProcessors ${task.cpus} \\
+ --outFileName ${prefix}.${extension} \\
+ $blacklist_cmd
+ """
+ }
+
+ stub:
+ def prefix = task.ext.prefix ?: "${meta.id}"
+ def extension = args.contains("--outFileFormat bedgraph") || args.contains("-of bedgraph") ? "bedgraph" : "bigWig"
+ """
+ touch ${prefix}.${extension}
+ """
+}
diff --git a/modules/nf-core/deeptools/bamcoverage/meta.yml b/modules/nf-core/deeptools/bamcoverage/meta.yml
new file mode 100644
index 0000000..e9039f1
--- /dev/null
+++ b/modules/nf-core/deeptools/bamcoverage/meta.yml
@@ -0,0 +1,129 @@
+name: deeptools_bamcoverage
+description: This tool takes an alignment of reads or fragments as input (BAM
+ file) and generates a coverage track (bigWig or bedGraph) as output.
+keywords:
+ - coverage
+ - depth
+ - track
+tools:
+ - deeptools:
+ description: A set of user-friendly tools for normalization and
+ visualization of deep-sequencing data
+ homepage: https://deeptools.readthedocs.io/en/develop/content/tools/bamCoverage.html
+ documentation: https://deeptools.readthedocs.io/en/develop/content/tools/bamCoverage.html
+ tool_dev_url: https://github.com/deeptools/deepTools/
+ doi: "10.1093/nar/gkw257"
+ licence:
+ - "GPL v3"
+ identifier: biotools:deeptools
+input:
+ - - meta:
+ type: map
+ description: |
+ Groovy Map containing sample information
+ e.g. [ id:'test', single_end:false ]
+ - input:
+ type: file
+ description: BAM/CRAM file
+ pattern: "*.{bam,cram}"
+ ontologies: []
+ - input_index:
+ type: file
+ description: BAM/CRAM index file
+ pattern: "*.{bai,crai}"
+ ontologies: []
+ - fasta:
+ type: file
+ description: Reference file the CRAM file was created with (required with
+ CRAM input)
+ pattern: "*.{fasta,fa}"
+ ontologies: []
+ - fasta_fai:
+ type: file
+ description: Index of the reference file (optional, but recommended)
+ pattern: "*.{fai}"
+ ontologies: []
+ - - meta2:
+ type: map
+ description: |
+ Groovy Map containing blacklist metadata
+ e.g. [ id:'blacklist' ]
+ - blacklist:
+ type: file
+ description: BED/GTF file containing regions to exclude from analysis
+ pattern: "*.{bed,gtf}"
+ ontologies:
+ - edam: "http://edamontology.org/data_3002"
+ - edam: "http://edamontology.org/format_3003"
+ optional: true
+output:
+ bigwig:
+ - - meta:
+ type: map
+ description: |
+ Groovy Map containing sample information
+ e.g. [ id:'test', single_end:false ]
+ - "*.bigWig":
+ type: file
+ description: BigWig file
+ pattern: "*.bigWig"
+ ontologies: []
+ bedgraph:
+ - - meta:
+ type: map
+ description: |
+ Groovy Map containing sample information
+ e.g. [ id:'test', single_end:false ]
+ - "*.bedgraph":
+ type: file
+ description: Bedgraph file
+ pattern: "*.bedgraph"
+ ontologies: []
+ versions_deeptools:
+ - - ${task.process}:
+ type: string
+ description: The name of the process
+ - deeptools:
+ type: string
+ description: The name of the tool
+ - bamCoverage --version | sed "s/bamCoverage //g":
+ type: eval
+ description: The expression to obtain the version of the tool
+ versions_samtools:
+ - - ${task.process}:
+ type: string
+ description: The name of the process
+ - samtools:
+ type: string
+ description: The name of the tool
+ - samtools version | sed '1!d;s/.* //':
+ type: eval
+ description: The expression to obtain the version of the tool
+topics:
+ versions:
+ - - ${task.process}:
+ type: string
+ description: The name of the process
+ - deeptools:
+ type: string
+ description: The name of the tool
+ - bamCoverage --version | sed "s/bamCoverage //g":
+ type: eval
+ description: The expression to obtain the version of the tool
+ - - ${task.process}:
+ type: string
+ description: The name of the process
+ - samtools:
+ type: string
+ description: The name of the tool
+ - samtools version | sed '1!d;s/.* //':
+ type: eval
+ description: The expression to obtain the version of the tool
+authors:
+ - "@FriederikeHanssen"
+ - "@SusiJo"
+ - "@JoseEspinosa"
+maintainers:
+ - "@FriederikeHanssen"
+ - "@SusiJo"
+ - "@JoseEspinosa"
diff --git a/modules/nf-core/deeptools/bamcoverage/tests/main.nf.test b/modules/nf-core/deeptools/bamcoverage/tests/main.nf.test
new file mode 100644
index 0000000..2857e33
--- /dev/null
+++ b/modules/nf-core/deeptools/bamcoverage/tests/main.nf.test
@@ -0,0 +1,134 @@
+nextflow_process {
+
+ name "Test Process DEEPTOOLS_BAMCOVERAGE"
+ script "../main.nf"
+ process "DEEPTOOLS_BAMCOVERAGE"
+
+ tag "modules"
+ tag "modules_nfcore"
+ tag "deeptools"
+ tag "deeptools/bamcoverage"
+
+ test("homo_sampiens - bam") {
+
+ when {
+ process {
+ """
+ input[0] = [
+ [ id:'test', single_end:false ], // meta map
+ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true),
+ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/bam/test.paired_end.sorted.bam.bai', checkIfExists: true)
+ ]
+ input[1] = []
+ input[2] = []
+ input[3] = [
+ [ id:'no_blacklist' ],
+ []
+ ]
+ """
+ }
+ }
+
+ then {
+ assertAll(
+ { assert process.success },
+ { assert snapshot(process.out.bigwig,
+ process.out.findAll { key, val -> key.startsWith('version') })
+ .match()
+ }
+ )
+ }
+ }
+
+ test("homo_sampiens - cram - fasta - fai ") {
+
+ when {
+ process {
+ """
+ input[0] = [
+ [ id:'test', single_end:false ], // meta map
+ file(params.modules_testdata_base_path + '/genomics/homo_sapiens/illumina/cram/test.paired_end.sorted.cram', checkIfExists: true),
+ file(params.modules_testdata_base_path + '/genomics/homo_sapiens/illumina/cram/test.paired_end.sorted.cram.crai', checkIfExists: true)
+ ]
+ input[1] = [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ]
+ input[2] = [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.fai', checkIfExists: true) ]
+ input[3] = [
+ [ id:'no_blacklist' ],
+ []
+ ]
+ """
+ }
+ }
+
+ then {
+ assertAll(
+ { assert process.success },
+ { assert snapshot(process.out.bigwig,
+ process.out.findAll { key, val -> key.startsWith('version') })
+ .match()
+ }
+ )
+ }
+ }
+
+ test("homo_sampiens - cram - fasta") {
+
+ when {
+ process {
+ """
+ input[0] = [
+ [ id:'test', single_end:false ], // meta map
+ file(params.modules_testdata_base_path + '/genomics/homo_sapiens/illumina/cram/test.paired_end.sorted.cram', checkIfExists: true),
+ file(params.modules_testdata_base_path + '/genomics/homo_sapiens/illumina/cram/test.paired_end.sorted.cram.crai', checkIfExists: true)
+ ]
+ input[1] = [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ]
+ input[2] = []
+ input[3] = [
+ [ id:'no_blacklist' ],
+ []
+ ]
+ """
+ }
+ }
+
+ then {
+ assertAll(
+ { assert process.success },
+ { assert snapshot(process.out.bigwig,
+ process.out.findAll { key, val -> key.startsWith('version') })
+ .match()
+ }
+ )
+ }
+ }
+
+ test("homo_sampiens - bam - stub") {
+
+ options "-stub"
+
+ when {
+ process {
+ """
+ input[0] = [
+ [ id:'test', single_end:false ], // meta map
+ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true),
+ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/bam/test.paired_end.sorted.bam.bai', checkIfExists: true)
+ ]
+ input[1] = []
+ input[2] = []
+ input[3] = [
+ [ id:'no_blacklist' ],
+ []
+ ]
+ """
+ }
+ }
+
+ then {
+ assertAll(
+ { assert process.success },
+ { assert snapshot(process.out).match() }
+ )
+ }
+ }
+}
diff --git a/modules/nf-core/deeptools/bamcoverage/tests/main.nf.test.snap b/modules/nf-core/deeptools/bamcoverage/tests/main.nf.test.snap
new file mode 100644
index 0000000..4644d85
--- /dev/null
+++ b/modules/nf-core/deeptools/bamcoverage/tests/main.nf.test.snap
@@ -0,0 +1,167 @@
+{
+ "homo_sampiens - bam": {
+ "content": [
+ [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.bigWig:md5,95fe9383a9e6c02aea6b785cf074274f"
+ ]
+ ],
+ {
+ "versions_deeptools": [
+ [
+ "DEEPTOOLS_BAMCOVERAGE",
+ "deeptools",
+ "3.5.6"
+ ]
+ ],
+ "versions_samtools": [
+ [
+ "DEEPTOOLS_BAMCOVERAGE",
+ "samtools",
+ "1.20"
+ ]
+ ]
+ }
+ ],
+ "timestamp": "2026-02-17T08:59:23.67581",
+ "meta": {
+ "nf-test": "0.9.4",
+ "nextflow": "25.10.4"
+ }
+ },
+ "homo_sampiens - cram - fasta - fai ": {
+ "content": [
+ [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.bigWig:md5,95fe9383a9e6c02aea6b785cf074274f"
+ ]
+ ],
+ {
+ "versions_deeptools": [
+ [
+ "DEEPTOOLS_BAMCOVERAGE",
+ "deeptools",
+ "3.5.6"
+ ]
+ ],
+ "versions_samtools": [
+ [
+ "DEEPTOOLS_BAMCOVERAGE",
+ "samtools",
+ "1.20"
+ ]
+ ]
+ }
+ ],
+ "timestamp": "2026-02-17T08:59:31.818598",
+ "meta": {
+ "nf-test": "0.9.4",
+ "nextflow": "25.10.4"
+ }
+ },
+ "homo_sampiens - bam - stub": {
+ "content": [
+ {
+ "0": [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.bigWig:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ],
+ "1": [
+
+ ],
+ "2": [
+ [
+ "DEEPTOOLS_BAMCOVERAGE",
+ "deeptools",
+ "3.5.6"
+ ]
+ ],
+ "3": [
+ [
+ "DEEPTOOLS_BAMCOVERAGE",
+ "samtools",
+ "1.20"
+ ]
+ ],
+ "bedgraph": [
+
+ ],
+ "bigwig": [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.bigWig:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ],
+ "versions_deeptools": [
+ [
+ "DEEPTOOLS_BAMCOVERAGE",
+ "deeptools",
+ "3.5.6"
+ ]
+ ],
+ "versions_samtools": [
+ [
+ "DEEPTOOLS_BAMCOVERAGE",
+ "samtools",
+ "1.20"
+ ]
+ ]
+ }
+ ],
+ "timestamp": "2026-02-17T08:59:45.595332",
+ "meta": {
+ "nf-test": "0.9.4",
+ "nextflow": "25.10.4"
+ }
+ },
+ "homo_sampiens - cram - fasta": {
+ "content": [
+ [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.bigWig:md5,95fe9383a9e6c02aea6b785cf074274f"
+ ]
+ ],
+ {
+ "versions_deeptools": [
+ [
+ "DEEPTOOLS_BAMCOVERAGE",
+ "deeptools",
+ "3.5.6"
+ ]
+ ],
+ "versions_samtools": [
+ [
+ "DEEPTOOLS_BAMCOVERAGE",
+ "samtools",
+ "1.20"
+ ]
+ ]
+ }
+ ],
+ "timestamp": "2026-02-17T08:59:38.037745",
+ "meta": {
+ "nf-test": "0.9.4",
+ "nextflow": "25.10.4"
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/nf-core/fastqc/.conda-lock/linux_amd64-bd-5cb1a2fa2f18c7c2_1.txt b/modules/nf-core/fastqc/.conda-lock/linux_amd64-bd-5cb1a2fa2f18c7c2_1.txt
new file mode 100644
index 0000000..7770ccd
--- /dev/null
+++ b/modules/nf-core/fastqc/.conda-lock/linux_amd64-bd-5cb1a2fa2f18c7c2_1.txt
@@ -0,0 +1,822 @@
+
+version: 6
+environments:
+default:
+channels:
+- url: https://conda.anaconda.org/conda-forge/
+- url: https://conda.anaconda.org/bioconda/
+- url: https://conda.anaconda.org/bioconda/
+options:
+pypi-prerelease-mode: if-necessary-or-explicit
+packages:
+linux-64:
+- conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.15.3-hb03c661_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.4-he90730b_1.conda
+- conda: https://conda.anaconda.org/bioconda/noarch/fastqc-0.12.1-hdfd78af_0.tar.bz2
+- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2
+- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2
+- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2
+- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.17.1-h27c8c51_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2
+- conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/giflib-5.2.2-hd590300_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.14-hecca717_2.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-13.2.1-h6083320_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/icu-78.3-h33c6efd_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.18-h0c24ade_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.1.0-hdb68285_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h7a8fb5f_6.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.25-h17f619e_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.7.4-hecca717_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype-2.14.3-ha770c72_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype6-2.14.3-h73754d4_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_18.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_18.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.86.4-h6548e54_1.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_18.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h3b78370_2.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.1.2-hb03c661_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.2-hb03c661_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.55-h421ea60_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_18.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.1-h9d88235_1.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.41.3-h5347b49_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/openjdk-25.0.2-ha668962_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.1-h35e630c_1.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.47-haa7fec5_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/perl-5.32.1-7_hd590300_perl5.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/pixman-0.46.4-h54a6638_1.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/procps-ng-4.0.6-h18c060e_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.1.2-hb9d3cd8_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.6-he73a12e_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.13-he1eb515_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.12-hb03c661_1.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb03c661_1.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.7-hb03c661_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxfixes-6.0.2-hb03c661_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxi-1.8.2-hb9d3cd8_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrandr-1.5.5-hb03c661_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.12-hb9d3cd8_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxt-1.3.1-hb9d3cd8_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxtst-1.2.5-hb9d3cd8_3.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda
+packages:
+- conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda
+build_number: 20
+sha256: 1dd3fffd892081df9726d7eb7e0dea6198962ba775bd88842135a4ddb4deb3c9
+md5: a9f577daf3de00bca7c3c76c0ecbd1de
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgomp >=7.5.0
+constrains:
+- openmp_impl <0.0a0
+license: BSD-3-Clause
+license_family: BSD
+size: 28948
+timestamp: 1770939786096
+- conda: https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.15.3-hb03c661_0.conda
+sha256: d88aa7ae766cf584e180996e92fef2aa7d8e0a0a5ab1d4d49c32390c1b5fff31
+md5: dcdc58c15961dbf17a0621312b01f5cb
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+license: LGPL-2.1-or-later
+license_family: GPL
+size: 584660
+timestamp: 1768327524772
+- conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda
+sha256: 0b75d45f0bba3e95dc693336fa51f40ea28c980131fec438afb7ce6118ed05f6
+md5: d2ffd7602c02f2b316fd921d39876885
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+license: bzip2-1.0.6
+license_family: BSD
+size: 260182
+timestamp: 1771350215188
+- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda
+sha256: 67cc7101b36421c5913a1687ef1b99f85b5d6868da3abbf6ec1a4181e79782fc
+md5: 4492fd26db29495f0ba23f146cd5638d
+depends:
+- __unix
+license: ISC
+size: 147413
+timestamp: 1772006283803
+- conda: https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.4-he90730b_1.conda
+sha256: 06525fa0c4e4f56e771a3b986d0fdf0f0fc5a3270830ee47e127a5105bde1b9a
+md5: bb6c4808bfa69d6f7f6b07e5846ced37
+depends:
+- __glibc >=2.17,<3.0.a0
+- fontconfig >=2.15.0,<3.0a0
+- fonts-conda-ecosystem
+- icu >=78.1,<79.0a0
+- libexpat >=2.7.3,<3.0a0
+- libfreetype >=2.14.1
+- libfreetype6 >=2.14.1
+- libgcc >=14
+- libglib >=2.86.3,<3.0a0
+- libpng >=1.6.53,<1.7.0a0
+- libstdcxx >=14
+- libxcb >=1.17.0,<2.0a0
+- libzlib >=1.3.1,<2.0a0
+- pixman >=0.46.4,<1.0a0
+- xorg-libice >=1.1.2,<2.0a0
+- xorg-libsm >=1.2.6,<2.0a0
+- xorg-libx11 >=1.8.12,<2.0a0
+- xorg-libxext >=1.3.6,<2.0a0
+- xorg-libxrender >=0.9.12,<0.10.0a0
+license: LGPL-2.1-only or MPL-1.1
+size: 989514
+timestamp: 1766415934926
+- conda: https://conda.anaconda.org/bioconda/noarch/fastqc-0.12.1-hdfd78af_0.tar.bz2
+sha256: 7cc26225d590540ae95cd24940ff42f2da7479dd4cd22ae9ab9298665d06790c
+md5: c9f6a4b12229f7331f79c9a00dd6e240
+depends:
+- font-ttf-dejavu-sans-mono
+- fontconfig
+- openjdk >=8.0.144
+- perl
+license: GPL >=3
+size: 11664291
+timestamp: 1677946722445
+- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2
+sha256: 58d7f40d2940dd0a8aa28651239adbf5613254df0f75789919c4e6762054403b
+md5: 0c96522c6bdaed4b1566d11387caaf45
+license: BSD-3-Clause
+license_family: BSD
+size: 397370
+timestamp: 1566932522327
+- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2
+sha256: c52a29fdac682c20d252facc50f01e7c2e7ceac52aa9817aaf0bb83f7559ec5c
+md5: 34893075a5c9e55cdafac56607368fc6
+license: OFL-1.1
+license_family: Other
+size: 96530
+timestamp: 1620479909603
+- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2
+sha256: 00925c8c055a2275614b4d983e1df637245e19058d79fc7dd1a93b8d9fb4b139
+md5: 4d59c254e01d9cde7957100457e2d5fb
+license: OFL-1.1
+license_family: Other
+size: 700814
+timestamp: 1620479612257
+- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda
+sha256: 2821ec1dc454bd8b9a31d0ed22a7ce22422c0aef163c59f49dfdf915d0f0ca14
+md5: 49023d73832ef61042f6a237cb2687e7
+license: LicenseRef-Ubuntu-Font-Licence-Version-1.0
+license_family: Other
+size: 1620504
+timestamp: 1727511233259
+- conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.17.1-h27c8c51_0.conda
+sha256: aa4a44dba97151221100a637c7f4bde619567afade9c0265f8e1c8eed8d7bd8c
+md5: 867127763fbe935bab59815b6e0b7b5c
+depends:
+- __glibc >=2.17,<3.0.a0
+- libexpat >=2.7.4,<3.0a0
+- libfreetype >=2.14.1
+- libfreetype6 >=2.14.1
+- libgcc >=14
+- libuuid >=2.41.3,<3.0a0
+- libzlib >=1.3.1,<2.0a0
+license: MIT
+license_family: MIT
+size: 270705
+timestamp: 1771382710863
+- conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2
+sha256: a997f2f1921bb9c9d76e6fa2f6b408b7fa549edd349a77639c9fe7a23ea93e61
+md5: fee5683a3f04bd15cbd8318b096a27ab
+depends:
+- fonts-conda-forge
+license: BSD-3-Clause
+license_family: BSD
+size: 3667
+timestamp: 1566974674465
+- conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda
+sha256: 54eea8469786bc2291cc40bca5f46438d3e062a399e8f53f013b6a9f50e98333
+md5: a7970cd949a077b7cb9696379d338681
+depends:
+- font-ttf-ubuntu
+- font-ttf-inconsolata
+- font-ttf-dejavu-sans-mono
+- font-ttf-source-code-pro
+license: BSD-3-Clause
+license_family: BSD
+size: 4059
+timestamp: 1762351264405
+- conda: https://conda.anaconda.org/conda-forge/linux-64/giflib-5.2.2-hd590300_0.conda
+sha256: aac402a8298f0c0cc528664249170372ef6b37ac39fdc92b40601a6aed1e32ff
+md5: 3bf7b9fd5a7136126e0234db4b87c8b6
+depends:
+- libgcc-ng >=12
+license: MIT
+license_family: MIT
+size: 77248
+timestamp: 1712692454246
+- conda: https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.14-hecca717_2.conda
+sha256: 25ba37da5c39697a77fce2c9a15e48cf0a84f1464ad2aafbe53d8357a9f6cc8c
+md5: 2cd94587f3a401ae05e03a6caf09539d
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+- libstdcxx >=14
+license: LGPL-2.0-or-later
+license_family: LGPL
+size: 99596
+timestamp: 1755102025473
+- conda: https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-13.2.1-h6083320_0.conda
+sha256: 477f2c553f72165020d3c56740ba354be916c2f0b76fd9f535e83d698277d5ec
+md5: 14470902326beee192e33719a2e8bb7f
+depends:
+- __glibc >=2.17,<3.0.a0
+- cairo >=1.18.4,<2.0a0
+- graphite2 >=1.3.14,<2.0a0
+- icu >=78.3,<79.0a0
+- libexpat >=2.7.4,<3.0a0
+- libfreetype >=2.14.2
+- libfreetype6 >=2.14.2
+- libgcc >=14
+- libglib >=2.86.4,<3.0a0
+- libstdcxx >=14
+- libzlib >=1.3.2,<2.0a0
+license: MIT
+license_family: MIT
+size: 2384060
+timestamp: 1774276284520
+- conda: https://conda.anaconda.org/conda-forge/linux-64/icu-78.3-h33c6efd_0.conda
+sha256: fbf86c4a59c2ed05bbffb2ba25c7ed94f6185ec30ecb691615d42342baa1a16a
+md5: c80d8a3b84358cb967fa81e7075fbc8a
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+- libstdcxx >=14
+license: MIT
+license_family: MIT
+size: 12723451
+timestamp: 1773822285671
+- conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda
+sha256: 0960d06048a7185d3542d850986d807c6e37ca2e644342dd0c72feefcf26c2a4
+md5: b38117a3c920364aff79f870c984b4a3
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=13
+license: LGPL-2.1-or-later
+size: 134088
+timestamp: 1754905959823
+- conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda
+sha256: 3e307628ca3527448dd1cb14ad7bb9d04d1d28c7d4c5f97ba196ae984571dd25
+md5: fb53fb07ce46a575c5d004bbc96032c2
+depends:
+- __glibc >=2.17,<3.0.a0
+- keyutils >=1.6.3,<2.0a0
+- libedit >=3.1.20250104,<3.2.0a0
+- libedit >=3.1.20250104,<4.0a0
+- libgcc >=14
+- libstdcxx >=14
+- openssl >=3.5.5,<4.0a0
+license: MIT
+license_family: MIT
+size: 1386730
+timestamp: 1769769569681
+- conda: https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.18-h0c24ade_0.conda
+sha256: 836ec4b895352110335b9fdcfa83a8dcdbe6c5fb7c06c4929130600caea91c0a
+md5: 6f2e2c8f58160147c4d1c6f4c14cbac4
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+- libjpeg-turbo >=3.1.2,<4.0a0
+- libtiff >=4.7.1,<4.8.0a0
+license: MIT
+license_family: MIT
+size: 249959
+timestamp: 1768184673131
+- conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.1.0-hdb68285_0.conda
+sha256: f84cb54782f7e9cea95e810ea8fef186e0652d0fa73d3009914fa2c1262594e1
+md5: a752488c68f2e7c456bcbd8f16eec275
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+- libstdcxx >=14
+license: Apache-2.0
+license_family: Apache
+size: 261513
+timestamp: 1773113328888
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h7a8fb5f_6.conda
+sha256: 205c4f19550f3647832ec44e35e6d93c8c206782bdd620c1d7cf66237580ff9c
+md5: 49c553b47ff679a6a1e9fc80b9c5a2d4
+depends:
+- __glibc >=2.17,<3.0.a0
+- krb5 >=1.22.2,<1.23.0a0
+- libgcc >=14
+- libstdcxx >=14
+- libzlib >=1.3.1,<2.0a0
+license: Apache-2.0
+license_family: Apache
+size: 4518030
+timestamp: 1770902209173
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.25-h17f619e_0.conda
+sha256: aa8e8c4be9a2e81610ddf574e05b64ee131fab5e0e3693210c9d6d2fba32c680
+md5: 6c77a605a7a689d17d4819c0f8ac9a00
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+license: MIT
+license_family: MIT
+size: 73490
+timestamp: 1761979956660
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda
+sha256: d789471216e7aba3c184cd054ed61ce3f6dac6f87a50ec69291b9297f8c18724
+md5: c277e0a4d549b03ac1e9d6cbbe3d017b
+depends:
+- ncurses
+- __glibc >=2.17,<3.0.a0
+- libgcc >=13
+- ncurses >=6.5,<7.0a0
+license: BSD-2-Clause
+license_family: BSD
+size: 134676
+timestamp: 1738479519902
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.7.4-hecca717_0.conda
+sha256: d78f1d3bea8c031d2f032b760f36676d87929b18146351c4464c66b0869df3f5
+md5: e7f7ce06ec24cfcfb9e36d28cf82ba57
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+constrains:
+- expat 2.7.4.*
+license: MIT
+license_family: MIT
+size: 76798
+timestamp: 1771259418166
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda
+sha256: 31f19b6a88ce40ebc0d5a992c131f57d919f73c0b92cd1617a5bec83f6e961e6
+md5: a360c33a5abe61c07959e449fa1453eb
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+license: MIT
+license_family: MIT
+size: 58592
+timestamp: 1769456073053
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype-2.14.3-ha770c72_0.conda
+sha256: 38f014a7129e644636e46064ecd6b1945e729c2140e21d75bb476af39e692db2
+md5: e289f3d17880e44b633ba911d57a321b
+depends:
+- libfreetype6 >=2.14.3
+license: GPL-2.0-only OR FTL
+size: 8049
+timestamp: 1774298163029
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype6-2.14.3-h73754d4_0.conda
+sha256: 16f020f96da79db1863fcdd8f2b8f4f7d52f177dd4c58601e38e9182e91adf1d
+md5: fb16b4b69e3f1dcfe79d80db8fd0c55d
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+- libpng >=1.6.55,<1.7.0a0
+- libzlib >=1.3.2,<2.0a0
+constrains:
+- freetype >=2.14.3
+license: GPL-2.0-only OR FTL
+size: 384575
+timestamp: 1774298162622
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_18.conda
+sha256: faf7d2017b4d718951e3a59d081eb09759152f93038479b768e3d612688f83f5
+md5: 0aa00f03f9e39fb9876085dee11a85d4
+depends:
+- __glibc >=2.17,<3.0.a0
+- _openmp_mutex >=4.5
+constrains:
+- libgcc-ng ==15.2.0=*_18
+- libgomp 15.2.0 he0feb66_18
+license: GPL-3.0-only WITH GCC-exception-3.1
+license_family: GPL
+size: 1041788
+timestamp: 1771378212382
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_18.conda
+sha256: e318a711400f536c81123e753d4c797a821021fb38970cebfb3f454126016893
+md5: d5e96b1ed75ca01906b3d2469b4ce493
+depends:
+- libgcc 15.2.0 he0feb66_18
+license: GPL-3.0-only WITH GCC-exception-3.1
+license_family: GPL
+size: 27526
+timestamp: 1771378224552
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.86.4-h6548e54_1.conda
+sha256: a27e44168a1240b15659888ce0d9b938ed4bdb49e9ea68a7c1ff27bcea8b55ce
+md5: bb26456332b07f68bf3b7622ed71c0da
+depends:
+- __glibc >=2.17,<3.0.a0
+- libffi >=3.5.2,<3.6.0a0
+- libgcc >=14
+- libiconv >=1.18,<2.0a0
+- libzlib >=1.3.1,<2.0a0
+- pcre2 >=10.47,<10.48.0a0
+constrains:
+- glib 2.86.4 *_1
+license: LGPL-2.1-or-later
+size: 4398701
+timestamp: 1771863239578
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_18.conda
+sha256: 21337ab58e5e0649d869ab168d4e609b033509de22521de1bfed0c031bfc5110
+md5: 239c5e9546c38a1e884d69effcf4c882
+depends:
+- __glibc >=2.17,<3.0.a0
+license: GPL-3.0-only WITH GCC-exception-3.1
+license_family: GPL
+size: 603262
+timestamp: 1771378117851
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h3b78370_2.conda
+sha256: c467851a7312765447155e071752d7bf9bf44d610a5687e32706f480aad2833f
+md5: 915f5995e94f60e9a4826e0b0920ee88
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+license: LGPL-2.1-only
+size: 790176
+timestamp: 1754908768807
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.1.2-hb03c661_0.conda
+sha256: cc9aba923eea0af8e30e0f94f2ad7156e2984d80d1e8e7fe6be5a1f257f0eb32
+md5: 8397539e3a0bbd1695584fb4f927485a
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+constrains:
+- jpeg <0.0.0a
+license: IJG AND BSD-3-Clause AND Zlib
+size: 633710
+timestamp: 1762094827865
+- conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.2-hb03c661_0.conda
+sha256: 755c55ebab181d678c12e49cced893598f2bab22d582fbbf4d8b83c18be207eb
+md5: c7c83eecbb72d88b940c249af56c8b17
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+constrains:
+- xz 5.8.2.*
+license: 0BSD
+size: 113207
+timestamp: 1768752626120
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.55-h421ea60_0.conda
+sha256: 36ade759122cdf0f16e2a2562a19746d96cf9c863ffaa812f2f5071ebbe9c03c
+md5: 5f13ffc7d30ffec87864e678df9957b4
+depends:
+- libgcc >=14
+- __glibc >=2.17,<3.0.a0
+- libzlib >=1.3.1,<2.0a0
+license: zlib-acknowledgement
+size: 317669
+timestamp: 1770691470744
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_18.conda
+sha256: 78668020064fdaa27e9ab65cd2997e2c837b564ab26ce3bf0e58a2ce1a525c6e
+md5: 1b08cd684f34175e4514474793d44bcb
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc 15.2.0 he0feb66_18
+constrains:
+- libstdcxx-ng ==15.2.0=*_18
+license: GPL-3.0-only WITH GCC-exception-3.1
+license_family: GPL
+size: 5852330
+timestamp: 1771378262446
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.1-h9d88235_1.conda
+sha256: e5f8c38625aa6d567809733ae04bb71c161a42e44a9fa8227abe61fa5c60ebe0
+md5: cd5a90476766d53e901500df9215e927
+depends:
+- __glibc >=2.17,<3.0.a0
+- lerc >=4.0.0,<5.0a0
+- libdeflate >=1.25,<1.26.0a0
+- libgcc >=14
+- libjpeg-turbo >=3.1.0,<4.0a0
+- liblzma >=5.8.1,<6.0a0
+- libstdcxx >=14
+- libwebp-base >=1.6.0,<2.0a0
+- libzlib >=1.3.1,<2.0a0
+- zstd >=1.5.7,<1.6.0a0
+license: HPND
+size: 435273
+timestamp: 1762022005702
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.41.3-h5347b49_0.conda
+sha256: 1a7539cfa7df00714e8943e18de0b06cceef6778e420a5ee3a2a145773758aee
+md5: db409b7c1720428638e7c0d509d3e1b5
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+license: BSD-3-Clause
+license_family: BSD
+size: 40311
+timestamp: 1766271528534
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_0.conda
+sha256: 3aed21ab28eddffdaf7f804f49be7a7d701e8f0e46c856d801270b470820a37b
+md5: aea31d2e5b1091feca96fcfe945c3cf9
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+constrains:
+- libwebp 1.6.0
+license: BSD-3-Clause
+license_family: BSD
+size: 429011
+timestamp: 1752159441324
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda
+sha256: 666c0c431b23c6cec6e492840b176dde533d48b7e6fb8883f5071223433776aa
+md5: 92ed62436b625154323d40d5f2f11dd7
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=13
+- pthread-stubs
+- xorg-libxau >=1.0.11,<2.0a0
+- xorg-libxdmcp
+license: MIT
+license_family: MIT
+size: 395888
+timestamp: 1727278577118
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda
+sha256: 6ae68e0b86423ef188196fff6207ed0c8195dd84273cb5623b85aa08033a410c
+md5: 5aa797f8787fe7a17d1b0821485b5adc
+depends:
+- libgcc-ng >=12
+license: LGPL-2.1-or-later
+size: 100393
+timestamp: 1702724383534
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda
+sha256: 55044c403570f0dc26e6364de4dc5368e5f3fc7ff103e867c487e2b5ab2bcda9
+md5: d87ff7921124eccd67248aa483c23fec
+depends:
+- __glibc >=2.17,<3.0.a0
+constrains:
+- zlib 1.3.2 *_2
+license: Zlib
+license_family: Other
+size: 63629
+timestamp: 1774072609062
+- conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda
+sha256: 3fde293232fa3fca98635e1167de6b7c7fda83caf24b9d6c91ec9eefb4f4d586
+md5: 47e340acb35de30501a76c7c799c41d7
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=13
+license: X11 AND BSD-3-Clause
+size: 891641
+timestamp: 1738195959188
+- conda: https://conda.anaconda.org/conda-forge/linux-64/openjdk-25.0.2-ha668962_0.conda
+sha256: 3825a4c84676a8a5cc23b397a2911e4efa4a805daf2af764153bd904e142ec41
+md5: a41092b0177362dbe5eb2a18501e86c0
+depends:
+- xorg-libx11
+- xorg-libxext
+- xorg-libxi
+- xorg-libxrender
+- xorg-libxtst
+- libstdcxx >=14
+- libgcc >=14
+- __glibc >=2.17,<3.0.a0
+- libfreetype >=2.14.1
+- libfreetype6 >=2.14.1
+- xorg-libxrender >=0.9.12,<0.10.0a0
+- libjpeg-turbo >=3.1.2,<4.0a0
+- giflib >=5.2.2,<5.3.0a0
+- xorg-libxrandr >=1.5.5,<2.0a0
+- harfbuzz >=12.3.2
+- fontconfig >=2.17.1,<3.0a0
+- fonts-conda-ecosystem
+- xorg-libxtst >=1.2.5,<2.0a0
+- xorg-libxi >=1.8.2,<2.0a0
+- lcms2 >=2.18,<3.0a0
+- alsa-lib >=1.2.15.3,<1.3.0a0
+- libpng >=1.6.55,<1.7.0a0
+- xorg-libxt >=1.3.1,<2.0a0
+- libzlib >=1.3.1,<2.0a0
+- xorg-libxext >=1.3.7,<2.0a0
+- xorg-libx11 >=1.8.13,<2.0a0
+- libcups >=2.3.3,<2.4.0a0
+license: GPL-2.0-or-later WITH Classpath-exception-2.0
+license_family: GPL
+size: 122465031
+timestamp: 1771443671180
+- conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.1-h35e630c_1.conda
+sha256: 44c877f8af015332a5d12f5ff0fb20ca32f896526a7d0cdb30c769df1144fb5c
+md5: f61eb8cd60ff9057122a3d338b99c00f
+depends:
+- __glibc >=2.17,<3.0.a0
+- ca-certificates
+- libgcc >=14
+license: Apache-2.0
+license_family: Apache
+size: 3164551
+timestamp: 1769555830639
+- conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.47-haa7fec5_0.conda
+sha256: 5e6f7d161356fefd981948bea5139c5aa0436767751a6930cb1ca801ebb113ff
+md5: 7a3bff861a6583f1889021facefc08b1
+depends:
+- __glibc >=2.17,<3.0.a0
+- bzip2 >=1.0.8,<2.0a0
+- libgcc >=14
+- libzlib >=1.3.1,<2.0a0
+license: BSD-3-Clause
+license_family: BSD
+size: 1222481
+timestamp: 1763655398280
+- conda: https://conda.anaconda.org/conda-forge/linux-64/perl-5.32.1-7_hd590300_perl5.conda
+build_number: 7
+sha256: 9ec32b6936b0e37bcb0ed34f22ec3116e75b3c0964f9f50ecea5f58734ed6ce9
+md5: f2cfec9406850991f4e3d960cc9e3321
+depends:
+- libgcc-ng >=12
+- libxcrypt >=4.4.36
+license: GPL-1.0-or-later OR Artistic-1.0-Perl
+size: 13344463
+timestamp: 1703310653947
+- conda: https://conda.anaconda.org/conda-forge/linux-64/pixman-0.46.4-h54a6638_1.conda
+sha256: 43d37bc9ca3b257c5dd7bf76a8426addbdec381f6786ff441dc90b1a49143b6a
+md5: c01af13bdc553d1a8fbfff6e8db075f0
+depends:
+- libgcc >=14
+- libstdcxx >=14
+- libgcc >=14
+- __glibc >=2.17,<3.0.a0
+license: MIT
+license_family: MIT
+size: 450960
+timestamp: 1754665235234
+- conda: https://conda.anaconda.org/conda-forge/linux-64/procps-ng-4.0.6-h18c060e_0.conda
+sha256: 4ce2e1ee31a6217998f78c31ce7dc0a3e0557d9238b51d49dd20c52d467a126d
+md5: f2c23a77b25efcad57d377b34bd84941
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+- ncurses >=6.5,<7.0a0
+license: GPL-2.0-or-later AND LGPL-2.0-or-later
+license_family: GPL
+size: 593603
+timestamp: 1769710381284
+- conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda
+sha256: 9c88f8c64590e9567c6c80823f0328e58d3b1efb0e1c539c0315ceca764e0973
+md5: b3c17d95b5a10c6e64a21fa17573e70e
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=13
+license: MIT
+license_family: MIT
+size: 8252
+timestamp: 1726802366959
+- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.1.2-hb9d3cd8_0.conda
+sha256: c12396aabb21244c212e488bbdc4abcdef0b7404b15761d9329f5a4a39113c4b
+md5: fb901ff28063514abb6046c9ec2c4a45
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=13
+license: MIT
+license_family: MIT
+size: 58628
+timestamp: 1734227592886
+- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.6-he73a12e_0.conda
+sha256: 277841c43a39f738927145930ff963c5ce4c4dacf66637a3d95d802a64173250
+md5: 1c74ff8c35dcadf952a16f752ca5aa49
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=13
+- libuuid >=2.38.1,<3.0a0
+- xorg-libice >=1.1.2,<2.0a0
+license: MIT
+license_family: MIT
+size: 27590
+timestamp: 1741896361728
+- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.13-he1eb515_0.conda
+sha256: 516d4060139dbb4de49a4dcdc6317a9353fb39ebd47789c14e6fe52de0deee42
+md5: 861fb6ccbc677bb9a9fb2468430b9c6a
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+- libxcb >=1.17.0,<2.0a0
+license: MIT
+license_family: MIT
+size: 839652
+timestamp: 1770819209719
+- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.12-hb03c661_1.conda
+sha256: 6bc6ab7a90a5d8ac94c7e300cc10beb0500eeba4b99822768ca2f2ef356f731b
+md5: b2895afaf55bf96a8c8282a2e47a5de0
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+license: MIT
+license_family: MIT
+size: 15321
+timestamp: 1762976464266
+- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb03c661_1.conda
+sha256: 25d255fb2eef929d21ff660a0c687d38a6d2ccfbcbf0cc6aa738b12af6e9d142
+md5: 1dafce8548e38671bea82e3f5c6ce22f
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+license: MIT
+license_family: MIT
+size: 20591
+timestamp: 1762976546182
+- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.7-hb03c661_0.conda
+sha256: 79c60fc6acfd3d713d6340d3b4e296836a0f8c51602327b32794625826bd052f
+md5: 34e54f03dfea3e7a2dcf1453a85f1085
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+- xorg-libx11 >=1.8.12,<2.0a0
+license: MIT
+license_family: MIT
+size: 50326
+timestamp: 1769445253162
+- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxfixes-6.0.2-hb03c661_0.conda
+sha256: 83c4c99d60b8784a611351220452a0a85b080668188dce5dfa394b723d7b64f4
+md5: ba231da7fccf9ea1e768caf5c7099b84
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+- xorg-libx11 >=1.8.12,<2.0a0
+license: MIT
+license_family: MIT
+size: 20071
+timestamp: 1759282564045
+- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxi-1.8.2-hb9d3cd8_0.conda
+sha256: 1a724b47d98d7880f26da40e45f01728e7638e6ec69f35a3e11f92acd05f9e7a
+md5: 17dcc85db3c7886650b8908b183d6876
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=13
+- xorg-libx11 >=1.8.10,<2.0a0
+- xorg-libxext >=1.3.6,<2.0a0
+- xorg-libxfixes >=6.0.1,<7.0a0
+license: MIT
+license_family: MIT
+size: 47179
+timestamp: 1727799254088
+- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrandr-1.5.5-hb03c661_0.conda
+sha256: 80ed047a5cb30632c3dc5804c7716131d767089f65877813d4ae855ee5c9d343
+md5: e192019153591938acf7322b6459d36e
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+- xorg-libx11 >=1.8.12,<2.0a0
+- xorg-libxext >=1.3.6,<2.0a0
+- xorg-libxrender >=0.9.12,<0.10.0a0
+license: MIT
+license_family: MIT
+size: 30456
+timestamp: 1769445263457
+- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.12-hb9d3cd8_0.conda
+sha256: 044c7b3153c224c6cedd4484dd91b389d2d7fd9c776ad0f4a34f099b3389f4a1
+md5: 96d57aba173e878a2089d5638016dc5e
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=13
+- xorg-libx11 >=1.8.10,<2.0a0
+license: MIT
+license_family: MIT
+size: 33005
+timestamp: 1734229037766
+- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxt-1.3.1-hb9d3cd8_0.conda
+sha256: a8afba4a55b7b530eb5c8ad89737d60d60bc151a03fbef7a2182461256953f0e
+md5: 279b0de5f6ba95457190a1c459a64e31
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=13
+- xorg-libice >=1.1.1,<2.0a0
+- xorg-libsm >=1.2.4,<2.0a0
+- xorg-libx11 >=1.8.10,<2.0a0
+license: MIT
+license_family: MIT
+size: 379686
+timestamp: 1731860547604
+- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxtst-1.2.5-hb9d3cd8_3.conda
+sha256: 752fdaac5d58ed863bbf685bb6f98092fe1a488ea8ebb7ed7b606ccfce08637a
+md5: 7bbe9a0cc0df0ac5f5a8ad6d6a11af2f
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=13
+- xorg-libx11 >=1.8.10,<2.0a0
+- xorg-libxext >=1.3.6,<2.0a0
+- xorg-libxi >=1.7.10,<2.0a0
+license: MIT
+license_family: MIT
+size: 32808
+timestamp: 1727964811275
+- conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda
+sha256: 68f0206ca6e98fea941e5717cec780ed2873ffabc0e1ed34428c061e2c6268c7
+md5: 4a13eeac0b5c8e5b8ab496e6c4ddd829
+depends:
+- __glibc >=2.17,<3.0.a0
+- libzlib >=1.3.1,<2.0a0
+license: BSD-3-Clause
+license_family: BSD
+size: 601375
+timestamp: 1764777111296
diff --git a/modules/nf-core/fastqc/.conda-lock/linux_arm64-bd-e455e32f745abe68_1.txt b/modules/nf-core/fastqc/.conda-lock/linux_arm64-bd-e455e32f745abe68_1.txt
new file mode 100644
index 0000000..cdc434c
--- /dev/null
+++ b/modules/nf-core/fastqc/.conda-lock/linux_arm64-bd-e455e32f745abe68_1.txt
@@ -0,0 +1,769 @@
+
+version: 6
+environments:
+default:
+channels:
+- url: https://conda.anaconda.org/conda-forge/
+- url: https://conda.anaconda.org/bioconda/
+- url: https://conda.anaconda.org/bioconda/
+options:
+pypi-prerelease-mode: if-necessary-or-explicit
+packages:
+linux-aarch64:
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/_openmp_mutex-4.5-20_gnu.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/alsa-lib-1.2.15.3-he30d5cf_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/bzip2-1.0.8-h4777abc_9.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cairo-1.18.4-h0b6afd8_1.conda
+- conda: https://conda.anaconda.org/bioconda/noarch/fastqc-0.12.1-hdfd78af_0.tar.bz2
+- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2
+- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2
+- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2
+- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/fontconfig-2.17.1-hba86a56_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2
+- conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/giflib-5.2.2-h31becfc_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/graphite2-1.3.14-hfae3067_2.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/harfbuzz-13.2.1-h1134a53_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/icu-78.3-hcab7f73_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/keyutils-1.6.3-h86ecc28_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/krb5-1.22.2-hfd895c2_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lcms2-2.18-h9d5b58d_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lerc-4.1.0-h52b7260_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libcups-2.3.3-h4f2b762_6.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libdeflate-1.25-h1af38f5_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libedit-3.1.20250104-pl5321h976ea20_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libexpat-2.7.4-hfae3067_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libffi-3.5.2-h376a255_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libfreetype-2.14.3-h8af1aa0_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libfreetype6-2.14.3-hdae7a39_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-15.2.0-h8acb6b2_18.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-ng-15.2.0-he9431aa_18.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libglib-2.86.4-hf53f6bf_1.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgomp-15.2.0-h8acb6b2_18.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libiconv-1.18-h90929bb_2.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libjpeg-turbo-3.1.2-he30d5cf_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblzma-5.8.2-he30d5cf_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libpng-1.6.55-h1abf092_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libstdcxx-15.2.0-hef695bb_18.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libtiff-4.7.1-hdb009f0_1.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libuuid-2.41.3-h1022ec0_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libwebp-base-1.6.0-ha2e29f5_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxcb-1.17.0-h262b8f6_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxcrypt-4.4.36-h31becfc_1.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libzlib-1.3.2-hdc9db2a_2.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ncurses-6.5-ha32ae93_3.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openjdk-25.0.2-h488f50d_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openssl-3.6.1-h546c87b_1.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pcre2-10.47-hf841c20_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/perl-5.32.1-7_h31becfc_perl5.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pixman-0.46.4-h7ac5ae9_1.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/procps-ng-4.0.6-h1779866_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pthread-stubs-0.4-h86ecc28_1002.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libice-1.1.2-h86ecc28_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libsm-1.2.6-h0808dbd_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libx11-1.8.13-h63a1b12_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxau-1.0.12-he30d5cf_1.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxdmcp-1.1.5-he30d5cf_1.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxext-1.3.7-he30d5cf_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxfixes-6.0.2-he30d5cf_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxi-1.8.2-h57736b2_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxrandr-1.5.5-he30d5cf_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxrender-0.9.12-h86ecc28_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxt-1.3.1-h57736b2_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxtst-1.2.5-h57736b2_3.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstd-1.5.7-h85ac4a6_6.conda
+packages:
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/_openmp_mutex-4.5-20_gnu.conda
+build_number: 20
+sha256: a2527b1d81792a0ccd2c05850960df119c2b6d8f5fdec97f2db7d25dc23b1068
+md5: 468fd3bb9e1f671d36c2cbc677e56f1d
+depends:
+- libgomp >=7.5.0
+constrains:
+- openmp_impl <0.0a0
+license: BSD-3-Clause
+license_family: BSD
+size: 28926
+timestamp: 1770939656741
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/alsa-lib-1.2.15.3-he30d5cf_0.conda
+sha256: ea2233e2db9908c2e5f29d3ca420a546b4583253f4f70abb5494cdd676866d42
+md5: 4a98cbc4ade694520227402ff8880630
+depends:
+- libgcc >=14
+license: LGPL-2.1-or-later
+license_family: GPL
+size: 615729
+timestamp: 1768327548407
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/bzip2-1.0.8-h4777abc_9.conda
+sha256: b3495077889dde6bb370938e7db82be545c73e8589696ad0843a32221520ad4c
+md5: 840d8fc0d7b3209be93080bc20e07f2d
+depends:
+- libgcc >=14
+license: bzip2-1.0.6
+license_family: BSD
+size: 192412
+timestamp: 1771350241232
+- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda
+sha256: 67cc7101b36421c5913a1687ef1b99f85b5d6868da3abbf6ec1a4181e79782fc
+md5: 4492fd26db29495f0ba23f146cd5638d
+depends:
+- __unix
+license: ISC
+size: 147413
+timestamp: 1772006283803
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cairo-1.18.4-h0b6afd8_1.conda
+sha256: 675db823f3d6fb6bf747fab3b0170ba99b269a07cf6df1e49fff2f9972be9cd1
+md5: 043c13ed3a18396994be9b4fab6572ad
+depends:
+- fontconfig >=2.15.0,<3.0a0
+- fonts-conda-ecosystem
+- icu >=78.1,<79.0a0
+- libexpat >=2.7.3,<3.0a0
+- libfreetype >=2.14.1
+- libfreetype6 >=2.14.1
+- libgcc >=14
+- libglib >=2.86.3,<3.0a0
+- libpng >=1.6.53,<1.7.0a0
+- libstdcxx >=14
+- libxcb >=1.17.0,<2.0a0
+- libzlib >=1.3.1,<2.0a0
+- pixman >=0.46.4,<1.0a0
+- xorg-libice >=1.1.2,<2.0a0
+- xorg-libsm >=1.2.6,<2.0a0
+- xorg-libx11 >=1.8.12,<2.0a0
+- xorg-libxext >=1.3.6,<2.0a0
+- xorg-libxrender >=0.9.12,<0.10.0a0
+license: LGPL-2.1-only or MPL-1.1
+size: 927045
+timestamp: 1766416003626
+- conda: https://conda.anaconda.org/bioconda/noarch/fastqc-0.12.1-hdfd78af_0.tar.bz2
+sha256: 7cc26225d590540ae95cd24940ff42f2da7479dd4cd22ae9ab9298665d06790c
+md5: c9f6a4b12229f7331f79c9a00dd6e240
+depends:
+- font-ttf-dejavu-sans-mono
+- fontconfig
+- openjdk >=8.0.144
+- perl
+license: GPL >=3
+size: 11664291
+timestamp: 1677946722445
+- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2
+sha256: 58d7f40d2940dd0a8aa28651239adbf5613254df0f75789919c4e6762054403b
+md5: 0c96522c6bdaed4b1566d11387caaf45
+license: BSD-3-Clause
+license_family: BSD
+size: 397370
+timestamp: 1566932522327
+- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2
+sha256: c52a29fdac682c20d252facc50f01e7c2e7ceac52aa9817aaf0bb83f7559ec5c
+md5: 34893075a5c9e55cdafac56607368fc6
+license: OFL-1.1
+license_family: Other
+size: 96530
+timestamp: 1620479909603
+- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2
+sha256: 00925c8c055a2275614b4d983e1df637245e19058d79fc7dd1a93b8d9fb4b139
+md5: 4d59c254e01d9cde7957100457e2d5fb
+license: OFL-1.1
+license_family: Other
+size: 700814
+timestamp: 1620479612257
+- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda
+sha256: 2821ec1dc454bd8b9a31d0ed22a7ce22422c0aef163c59f49dfdf915d0f0ca14
+md5: 49023d73832ef61042f6a237cb2687e7
+license: LicenseRef-Ubuntu-Font-Licence-Version-1.0
+license_family: Other
+size: 1620504
+timestamp: 1727511233259
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/fontconfig-2.17.1-hba86a56_0.conda
+sha256: 835aff8615dd8d8fff377679710ce81b8a2c47b6404e21a92fb349fda193a15c
+md5: 0fed1ff55f4938a65907f3ecf62609db
+depends:
+- libexpat >=2.7.4,<3.0a0
+- libfreetype >=2.14.1
+- libfreetype6 >=2.14.1
+- libgcc >=14
+- libuuid >=2.41.3,<3.0a0
+- libzlib >=1.3.1,<2.0a0
+license: MIT
+license_family: MIT
+size: 279044
+timestamp: 1771382728182
+- conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2
+sha256: a997f2f1921bb9c9d76e6fa2f6b408b7fa549edd349a77639c9fe7a23ea93e61
+md5: fee5683a3f04bd15cbd8318b096a27ab
+depends:
+- fonts-conda-forge
+license: BSD-3-Clause
+license_family: BSD
+size: 3667
+timestamp: 1566974674465
+- conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda
+sha256: 54eea8469786bc2291cc40bca5f46438d3e062a399e8f53f013b6a9f50e98333
+md5: a7970cd949a077b7cb9696379d338681
+depends:
+- font-ttf-ubuntu
+- font-ttf-inconsolata
+- font-ttf-dejavu-sans-mono
+- font-ttf-source-code-pro
+license: BSD-3-Clause
+license_family: BSD
+size: 4059
+timestamp: 1762351264405
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/giflib-5.2.2-h31becfc_0.conda
+sha256: a79dc3bd54c4fb1f249942ee2d5b601a76ecf9614774a4cff9af49adfa458db2
+md5: 2f809afaf0ba1ea4135dce158169efac
+depends:
+- libgcc-ng >=12
+license: MIT
+license_family: MIT
+size: 82124
+timestamp: 1712692444545
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/graphite2-1.3.14-hfae3067_2.conda
+sha256: c9b1781fe329e0b77c5addd741e58600f50bef39321cae75eba72f2f381374b7
+md5: 4aa540e9541cc9d6581ab23ff2043f13
+depends:
+- libgcc >=14
+- libstdcxx >=14
+license: LGPL-2.0-or-later
+license_family: LGPL
+size: 102400
+timestamp: 1755102000043
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/harfbuzz-13.2.1-h1134a53_0.conda
+sha256: e22f485fddaaea3ff4b6cae98e0197b9dccd2ed2770337ad6ff38a92afe04e59
+md5: 05d65a2cf410adc331c9ea61f59f1013
+depends:
+- cairo >=1.18.4,<2.0a0
+- graphite2 >=1.3.14,<2.0a0
+- icu >=78.3,<79.0a0
+- libexpat >=2.7.4,<3.0a0
+- libfreetype >=2.14.2
+- libfreetype6 >=2.14.2
+- libgcc >=14
+- libglib >=2.86.4,<3.0a0
+- libstdcxx >=14
+- libzlib >=1.3.2,<2.0a0
+license: MIT
+license_family: MIT
+size: 2345732
+timestamp: 1774281448329
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/icu-78.3-hcab7f73_0.conda
+sha256: 49ba6aed2c6b482bb0ba41078057555d29764299bc947b990708617712ef6406
+md5: 546da38c2fa9efacf203e2ad3f987c59
+depends:
+- libgcc >=14
+- libstdcxx >=14
+license: MIT
+license_family: MIT
+size: 12837286
+timestamp: 1773822650615
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/keyutils-1.6.3-h86ecc28_0.conda
+sha256: 5ce830ca274b67de11a7075430a72020c1fb7d486161a82839be15c2b84e9988
+md5: e7df0aab10b9cbb73ab2a467ebfaf8c7
+depends:
+- libgcc >=13
+license: LGPL-2.1-or-later
+size: 129048
+timestamp: 1754906002667
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/krb5-1.22.2-hfd895c2_0.conda
+sha256: b53999d888dda53c506b264e8c02b5f5c8e022c781eda0718f007339e6bc90ba
+md5: d9ca108bd680ea86a963104b6b3e95ca
+depends:
+- keyutils >=1.6.3,<2.0a0
+- libedit >=3.1.20250104,<3.2.0a0
+- libedit >=3.1.20250104,<4.0a0
+- libgcc >=14
+- libstdcxx >=14
+- openssl >=3.5.5,<4.0a0
+license: MIT
+license_family: MIT
+size: 1517436
+timestamp: 1769773395215
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lcms2-2.18-h9d5b58d_0.conda
+sha256: 379ef5e91a587137391a6149755d0e929f1a007d2dcb211318ac670a46c8596f
+md5: bb960f01525b5e001608afef9d47b79c
+depends:
+- libgcc >=14
+- libjpeg-turbo >=3.1.2,<4.0a0
+- libtiff >=4.7.1,<4.8.0a0
+license: MIT
+license_family: MIT
+size: 293039
+timestamp: 1768184778398
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lerc-4.1.0-h52b7260_0.conda
+sha256: 8957fd460c1c132c8031f65fd5f56ec3807fd71b7cab2c5e2b0937b13404ab36
+md5: d13423b06447113a90b5b1366d4da171
+depends:
+- libgcc >=14
+- libstdcxx >=14
+license: Apache-2.0
+license_family: Apache
+size: 240444
+timestamp: 1773114901155
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libcups-2.3.3-h4f2b762_6.conda
+sha256: 41b04f995c9f63af8c4065a35931e46cbc2fdd6b9bf7e4c19f90d53cbb2bc8e5
+md5: 67828c963b17db7dc989fe5d509ef04a
+depends:
+- krb5 >=1.22.2,<1.23.0a0
+- libgcc >=14
+- libstdcxx >=14
+- libzlib >=1.3.1,<2.0a0
+license: Apache-2.0
+license_family: Apache
+size: 4553739
+timestamp: 1770903929794
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libdeflate-1.25-h1af38f5_0.conda
+sha256: 48814b73bd462da6eed2e697e30c060ae16af21e9fbed30d64feaf0aad9da392
+md5: a9138815598fe6b91a1d6782ca657b0c
+depends:
+- libgcc >=14
+license: MIT
+license_family: MIT
+size: 71117
+timestamp: 1761979776756
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libedit-3.1.20250104-pl5321h976ea20_0.conda
+sha256: c0b27546aa3a23d47919226b3a1635fccdb4f24b94e72e206a751b33f46fd8d6
+md5: fb640d776fc92b682a14e001980825b1
+depends:
+- ncurses
+- libgcc >=13
+- ncurses >=6.5,<7.0a0
+license: BSD-2-Clause
+license_family: BSD
+size: 148125
+timestamp: 1738479808948
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libexpat-2.7.4-hfae3067_0.conda
+sha256: 995ce3ad96d0f4b5ed6296b051a0d7b6377718f325bc0e792fbb96b0e369dad7
+md5: 57f3b3da02a50a1be2a6fe847515417d
+depends:
+- libgcc >=14
+constrains:
+- expat 2.7.4.*
+license: MIT
+license_family: MIT
+size: 76564
+timestamp: 1771259530958
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libffi-3.5.2-h376a255_0.conda
+sha256: 3df4c539449aabc3443bbe8c492c01d401eea894603087fca2917aa4e1c2dea9
+md5: 2f364feefb6a7c00423e80dcb12db62a
+depends:
+- libgcc >=14
+license: MIT
+license_family: MIT
+size: 55952
+timestamp: 1769456078358
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libfreetype-2.14.3-h8af1aa0_0.conda
+sha256: 752e4f66283d7deb4c6fd47d88df644d8daa2aaa825a54f3bf350a625190192a
+md5: a229e22d4d8814a07702b0919d8e6701
+depends:
+- libfreetype6 >=2.14.3
+license: GPL-2.0-only OR FTL
+size: 8125
+timestamp: 1774301094057
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libfreetype6-2.14.3-hdae7a39_0.conda
+sha256: 8e6b27fe4eec4c2fa7b7769a21973734c8dba1de80086fb0213e58375ac09f4c
+md5: b99ed99e42dafb27889483b3098cace7
+depends:
+- libgcc >=14
+- libpng >=1.6.55,<1.7.0a0
+- libzlib >=1.3.2,<2.0a0
+constrains:
+- freetype >=2.14.3
+license: GPL-2.0-only OR FTL
+size: 422941
+timestamp: 1774301093473
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-15.2.0-h8acb6b2_18.conda
+sha256: 43df385bedc1cab11993c4369e1f3b04b4ca5d0ea16cba6a0e7f18dbc129fcc9
+md5: 552567ea2b61e3a3035759b2fdb3f9a6
+depends:
+- _openmp_mutex >=4.5
+constrains:
+- libgcc-ng ==15.2.0=*_18
+- libgomp 15.2.0 h8acb6b2_18
+license: GPL-3.0-only WITH GCC-exception-3.1
+license_family: GPL
+size: 622900
+timestamp: 1771378128706
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-ng-15.2.0-he9431aa_18.conda
+sha256: 83bb0415f59634dccfa8335d4163d1f6db00a27b36666736f9842b650b92cf2f
+md5: 4feebd0fbf61075a1a9c2e9b3936c257
+depends:
+- libgcc 15.2.0 h8acb6b2_18
+license: GPL-3.0-only WITH GCC-exception-3.1
+license_family: GPL
+size: 27568
+timestamp: 1771378136019
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libglib-2.86.4-hf53f6bf_1.conda
+sha256: afc503dbd04a5bf2709aa9d8318a03a8c4edb389f661ff280c3494bfef4341ec
+md5: 4ac4372fc4d7f20630a91314cdac8afd
+depends:
+- libffi >=3.5.2,<3.6.0a0
+- libgcc >=14
+- libiconv >=1.18,<2.0a0
+- libzlib >=1.3.1,<2.0a0
+- pcre2 >=10.47,<10.48.0a0
+constrains:
+- glib 2.86.4 *_1
+license: LGPL-2.1-or-later
+size: 4512186
+timestamp: 1771863220969
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgomp-15.2.0-h8acb6b2_18.conda
+sha256: fc716f11a6a8525e27a5d332ef6a689210b0d2a4dd1133edc0f530659aa9faa6
+md5: 4faa39bf919939602e594253bd673958
+license: GPL-3.0-only WITH GCC-exception-3.1
+license_family: GPL
+size: 588060
+timestamp: 1771378040807
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libiconv-1.18-h90929bb_2.conda
+sha256: 1473451cd282b48d24515795a595801c9b65b567fe399d7e12d50b2d6cdb04d9
+md5: 5a86bf847b9b926f3a4f203339748d78
+depends:
+- libgcc >=14
+license: LGPL-2.1-only
+size: 791226
+timestamp: 1754910975665
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libjpeg-turbo-3.1.2-he30d5cf_0.conda
+sha256: 84064c7c53a64291a585d7215fe95ec42df74203a5bf7615d33d49a3b0f08bb6
+md5: 5109d7f837a3dfdf5c60f60e311b041f
+depends:
+- libgcc >=14
+constrains:
+- jpeg <0.0.0a
+license: IJG AND BSD-3-Clause AND Zlib
+size: 691818
+timestamp: 1762094728337
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblzma-5.8.2-he30d5cf_0.conda
+sha256: 843c46e20519651a3e357a8928352b16c5b94f4cd3d5481acc48be2e93e8f6a3
+md5: 96944e3c92386a12755b94619bae0b35
+depends:
+- libgcc >=14
+constrains:
+- xz 5.8.2.*
+license: 0BSD
+size: 125916
+timestamp: 1768754941722
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libpng-1.6.55-h1abf092_0.conda
+sha256: c7378c6b79de4d571d00ad1caf0a4c19d43c9c94077a761abb6ead44d891f907
+md5: be4088903b94ea297975689b3c3aeb27
+depends:
+- libgcc >=14
+- libzlib >=1.3.1,<2.0a0
+license: zlib-acknowledgement
+size: 340156
+timestamp: 1770691477245
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libstdcxx-15.2.0-hef695bb_18.conda
+sha256: 31fdb9ffafad106a213192d8319b9f810e05abca9c5436b60e507afb35a6bc40
+md5: f56573d05e3b735cb03efeb64a15f388
+depends:
+- libgcc 15.2.0 h8acb6b2_18
+constrains:
+- libstdcxx-ng ==15.2.0=*_18
+license: GPL-3.0-only WITH GCC-exception-3.1
+license_family: GPL
+size: 5541411
+timestamp: 1771378162499
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libtiff-4.7.1-hdb009f0_1.conda
+sha256: 7ff79470db39e803e21b8185bc8f19c460666d5557b1378d1b1e857d929c6b39
+md5: 8c6fd84f9c87ac00636007c6131e457d
+depends:
+- lerc >=4.0.0,<5.0a0
+- libdeflate >=1.25,<1.26.0a0
+- libgcc >=14
+- libjpeg-turbo >=3.1.0,<4.0a0
+- liblzma >=5.8.1,<6.0a0
+- libstdcxx >=14
+- libwebp-base >=1.6.0,<2.0a0
+- libzlib >=1.3.1,<2.0a0
+- zstd >=1.5.7,<1.6.0a0
+license: HPND
+size: 488407
+timestamp: 1762022048105
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libuuid-2.41.3-h1022ec0_0.conda
+sha256: c37a8e89b700646f3252608f8368e7eb8e2a44886b92776e57ad7601fc402a11
+md5: cf2861212053d05f27ec49c3784ff8bb
+depends:
+- libgcc >=14
+license: BSD-3-Clause
+license_family: BSD
+size: 43453
+timestamp: 1766271546875
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libwebp-base-1.6.0-ha2e29f5_0.conda
+sha256: b03700a1f741554e8e5712f9b06dd67e76f5301292958cd3cb1ac8c6fdd9ed25
+md5: 24e92d0942c799db387f5c9d7b81f1af
+depends:
+- libgcc >=14
+constrains:
+- libwebp 1.6.0
+license: BSD-3-Clause
+license_family: BSD
+size: 359496
+timestamp: 1752160685488
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxcb-1.17.0-h262b8f6_0.conda
+sha256: 461cab3d5650ac6db73a367de5c8eca50363966e862dcf60181d693236b1ae7b
+md5: cd14ee5cca2464a425b1dbfc24d90db2
+depends:
+- libgcc >=13
+- pthread-stubs
+- xorg-libxau >=1.0.11,<2.0a0
+- xorg-libxdmcp
+license: MIT
+license_family: MIT
+size: 397493
+timestamp: 1727280745441
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxcrypt-4.4.36-h31becfc_1.conda
+sha256: 6b46c397644091b8a26a3048636d10b989b1bf266d4be5e9474bf763f828f41f
+md5: b4df5d7d4b63579d081fd3a4cf99740e
+depends:
+- libgcc-ng >=12
+license: LGPL-2.1-or-later
+size: 114269
+timestamp: 1702724369203
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libzlib-1.3.2-hdc9db2a_2.conda
+sha256: eb111e32e5a7313a5bf799c7fb2419051fa2fe7eff74769fac8d5a448b309f7f
+md5: 502006882cf5461adced436e410046d1
+constrains:
+- zlib 1.3.2 *_2
+license: Zlib
+license_family: Other
+size: 69833
+timestamp: 1774072605429
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ncurses-6.5-ha32ae93_3.conda
+sha256: 91cfb655a68b0353b2833521dc919188db3d8a7f4c64bea2c6a7557b24747468
+md5: 182afabe009dc78d8b73100255ee6868
+depends:
+- libgcc >=13
+license: X11 AND BSD-3-Clause
+size: 926034
+timestamp: 1738196018799
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openjdk-25.0.2-h488f50d_0.conda
+sha256: 6fd2c872b275fa5d42a61a4b6dc28a819cde29f9048adb547363597432e0720e
+md5: 27fdd5d67e235c20d23b2d66406497d3
+depends:
+- xorg-libx11
+- xorg-libxext
+- xorg-libxi
+- xorg-libxrender
+- xorg-libxtst
+- libstdcxx >=14
+- libgcc >=14
+- libzlib >=1.3.1,<2.0a0
+- xorg-libxtst >=1.2.5,<2.0a0
+- libpng >=1.6.55,<1.7.0a0
+- alsa-lib >=1.2.15.3,<1.3.0a0
+- xorg-libx11 >=1.8.13,<2.0a0
+- xorg-libxi >=1.8.2,<2.0a0
+- xorg-libxrandr >=1.5.5,<2.0a0
+- lcms2 >=2.18,<3.0a0
+- xorg-libxrender >=0.9.12,<0.10.0a0
+- libcups >=2.3.3,<2.4.0a0
+- libfreetype >=2.14.1
+- libfreetype6 >=2.14.1
+- harfbuzz >=12.3.2
+- xorg-libxext >=1.3.7,<2.0a0
+- giflib >=5.2.2,<5.3.0a0
+- xorg-libxt >=1.3.1,<2.0a0
+- libjpeg-turbo >=3.1.2,<4.0a0
+- fontconfig >=2.17.1,<3.0a0
+- fonts-conda-ecosystem
+license: GPL-2.0-or-later WITH Classpath-exception-2.0
+license_family: GPL
+size: 106988620
+timestamp: 1771443741031
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openssl-3.6.1-h546c87b_1.conda
+sha256: 7f8048c0e75b2620254218d72b4ae7f14136f1981c5eb555ef61645a9344505f
+md5: 25f5885f11e8b1f075bccf4a2da91c60
+depends:
+- ca-certificates
+- libgcc >=14
+license: Apache-2.0
+license_family: Apache
+size: 3692030
+timestamp: 1769557678657
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pcre2-10.47-hf841c20_0.conda
+sha256: 04df2cee95feba440387f33f878e9f655521e69f4be33a0cd637f07d3d81f0f9
+md5: 1a30c42e32ca0ea216bd0bfe6f842f0b
+depends:
+- bzip2 >=1.0.8,<2.0a0
+- libgcc >=14
+- libzlib >=1.3.1,<2.0a0
+license: BSD-3-Clause
+license_family: BSD
+size: 1166552
+timestamp: 1763655534263
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/perl-5.32.1-7_h31becfc_perl5.conda
+build_number: 7
+sha256: d78296134263b5bf476cad838ded65451e7162db756f9997c5d06b08122572ed
+md5: 17d019cb2a6c72073c344e98e40dfd61
+depends:
+- libgcc-ng >=12
+- libxcrypt >=4.4.36
+license: GPL-1.0-or-later OR Artistic-1.0-Perl
+size: 13338804
+timestamp: 1703310557094
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pixman-0.46.4-h7ac5ae9_1.conda
+sha256: e6b0846a998f2263629cfeac7bca73565c35af13251969f45d385db537a514e4
+md5: 1587081d537bd4ae77d1c0635d465ba5
+depends:
+- libgcc >=14
+- libstdcxx >=14
+- libgcc >=14
+license: MIT
+license_family: MIT
+size: 357913
+timestamp: 1754665583353
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/procps-ng-4.0.6-h1779866_0.conda
+sha256: e9cbcbc94e151ada3d6dc365380aaaf591f65012c16d9a2abaea4b9b90adc402
+md5: ab7288cc39545556d1bc5e71ab2df9a9
+depends:
+- libgcc >=14
+- ncurses >=6.5,<7.0a0
+license: GPL-2.0-or-later AND LGPL-2.0-or-later
+license_family: GPL
+size: 636733
+timestamp: 1769712412683
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pthread-stubs-0.4-h86ecc28_1002.conda
+sha256: 977dfb0cb3935d748521dd80262fe7169ab82920afd38ed14b7fee2ea5ec01ba
+md5: bb5a90c93e3bac3d5690acf76b4a6386
+depends:
+- libgcc >=13
+license: MIT
+license_family: MIT
+size: 8342
+timestamp: 1726803319942
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libice-1.1.2-h86ecc28_0.conda
+sha256: a2ba1864403c7eb4194dacbfe2777acf3d596feae43aada8d1b478617ce45031
+md5: c8d8ec3e00cd0fd8a231789b91a7c5b7
+depends:
+- libgcc >=13
+license: MIT
+license_family: MIT
+size: 60433
+timestamp: 1734229908988
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libsm-1.2.6-h0808dbd_0.conda
+sha256: b86a819cd16f90c01d9d81892155126d01555a20dabd5f3091da59d6309afd0a
+md5: 2d1409c50882819cb1af2de82e2b7208
+depends:
+- libgcc >=13
+- libuuid >=2.38.1,<3.0a0
+- xorg-libice >=1.1.2,<2.0a0
+license: MIT
+license_family: MIT
+size: 28701
+timestamp: 1741897678254
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libx11-1.8.13-h63a1b12_0.conda
+sha256: cf886160e2ff580d77f7eb8ec1a77c41c2c5b05343e329bc35f0ddf40b8d92ab
+md5: 22dd10425ef181e80e130db50675d615
+depends:
+- libgcc >=14
+- libxcb >=1.17.0,<2.0a0
+license: MIT
+license_family: MIT
+size: 869058
+timestamp: 1770819244991
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxau-1.0.12-he30d5cf_1.conda
+sha256: e9f6e931feeb2f40e1fdbafe41d3b665f1ab6cb39c5880a1fcf9f79a3f3c84a5
+md5: 1c246e1105000c3660558459e2fd6d43
+depends:
+- libgcc >=14
+license: MIT
+license_family: MIT
+size: 16317
+timestamp: 1762977521691
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxdmcp-1.1.5-he30d5cf_1.conda
+sha256: 128d72f36bcc8d2b4cdbec07507542e437c7d67f677b7d77b71ed9eeac7d6df1
+md5: bff06dcde4a707339d66d45d96ceb2e2
+depends:
+- libgcc >=14
+license: MIT
+license_family: MIT
+size: 21039
+timestamp: 1762979038025
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxext-1.3.7-he30d5cf_0.conda
+sha256: db2188bc0d844d4e9747bac7f6c1d067e390bd769c5ad897c93f1df759dc5dba
+md5: fb42b683034619915863d68dd9df03a3
+depends:
+- libgcc >=14
+- xorg-libx11 >=1.8.12,<2.0a0
+license: MIT
+license_family: MIT
+size: 52409
+timestamp: 1769446753771
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxfixes-6.0.2-he30d5cf_0.conda
+sha256: 8cb9c88e25c57e47419e98f04f9ef3154ad96b9f858c88c570c7b91216a64d0e
+md5: e8b4056544341daf1d415eaeae7a040c
+depends:
+- libgcc >=14
+- xorg-libx11 >=1.8.12,<2.0a0
+license: MIT
+license_family: MIT
+size: 20704
+timestamp: 1759284028146
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxi-1.8.2-h57736b2_0.conda
+sha256: 7b587407ecb9ccd2bbaf0fb94c5dbdde4d015346df063e9502dc0ce2b682fb5e
+md5: eeee3bdb31c6acde2b81ad1b8c287087
+depends:
+- libgcc >=13
+- xorg-libx11 >=1.8.9,<2.0a0
+- xorg-libxext >=1.3.6,<2.0a0
+- xorg-libxfixes >=6.0.1,<7.0a0
+license: MIT
+license_family: MIT
+size: 48197
+timestamp: 1727801059062
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxrandr-1.5.5-he30d5cf_0.conda
+sha256: 9f5196665a8d72f4f119c40dcc4bafeb0b540b102cc7b8b299c2abf599e7919f
+md5: 1f64c613f0b8d67e9fb0e165d898fb6b
+depends:
+- libgcc >=14
+- xorg-libx11 >=1.8.12,<2.0a0
+- xorg-libxext >=1.3.6,<2.0a0
+- xorg-libxrender >=0.9.12,<0.10.0a0
+license: MIT
+license_family: MIT
+size: 31122
+timestamp: 1769445286951
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxrender-0.9.12-h86ecc28_0.conda
+sha256: ffd77ee860c9635a28cfda46163dcfe9224dc6248c62404c544ae6b564a0be1f
+md5: ae2c2dd0e2d38d249887727db2af960e
+depends:
+- libgcc >=13
+- xorg-libx11 >=1.8.10,<2.0a0
+license: MIT
+license_family: MIT
+size: 33649
+timestamp: 1734229123157
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxt-1.3.1-h57736b2_0.conda
+sha256: 7c109792b60720809a580612aba7f8eb2a0bd425b9fc078748a9d6ffc97cbfa8
+md5: a9e4852c8e0b68ee783e7240030b696f
+depends:
+- libgcc >=13
+- xorg-libice >=1.1.1,<2.0a0
+- xorg-libsm >=1.2.4,<2.0a0
+- xorg-libx11 >=1.8.9,<2.0a0
+license: MIT
+license_family: MIT
+size: 384752
+timestamp: 1731860572314
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxtst-1.2.5-h57736b2_3.conda
+sha256: 6eaffce5a34fc0a16a21ddeaefb597e792a263b1b0c387c1ce46b0a967d558e1
+md5: c05698071b5c8e0da82a282085845860
+depends:
+- libgcc >=13
+- xorg-libx11 >=1.8.9,<2.0a0
+- xorg-libxext >=1.3.6,<2.0a0
+- xorg-libxi >=1.7.10,<2.0a0
+license: MIT
+license_family: MIT
+size: 33786
+timestamp: 1727964907993
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstd-1.5.7-h85ac4a6_6.conda
+sha256: 569990cf12e46f9df540275146da567d9c618c1e9c7a0bc9d9cfefadaed20b75
+md5: c3655f82dcea2aa179b291e7099c1fcc
+depends:
+- libzlib >=1.3.1,<2.0a0
+license: BSD-3-Clause
+license_family: BSD
+size: 614429
+timestamp: 1764777145593
diff --git a/modules/nf-core/fastqc/environment.yml b/modules/nf-core/fastqc/environment.yml
new file mode 100644
index 0000000..f9f54ee
--- /dev/null
+++ b/modules/nf-core/fastqc/environment.yml
@@ -0,0 +1,7 @@
+---
+# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json
+channels:
+ - conda-forge
+ - bioconda
+dependencies:
+ - bioconda::fastqc=0.12.1
diff --git a/modules/nf-core/fastqc/main.nf b/modules/nf-core/fastqc/main.nf
new file mode 100644
index 0000000..1085126
--- /dev/null
+++ b/modules/nf-core/fastqc/main.nf
@@ -0,0 +1,57 @@
+process FASTQC {
+ tag "${meta.id}"
+ label 'process_low'
+
+ conda "${moduleDir}/environment.yml"
+ container "${workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container
+ ? 'https://depot.galaxyproject.org/singularity/fastqc:0.12.1--hdfd78af_0'
+ : 'quay.io/biocontainers/fastqc:0.12.1--hdfd78af_0'}"
+
+ input:
+ tuple val(meta), path(reads, stageAs: '?/*')
+
+ output:
+ tuple val(meta), path("*.html"), emit: html
+ tuple val(meta), path("*.zip"), emit: zip
+ tuple val("${task.process}"), val('fastqc'), eval('fastqc --version | sed "/FastQC v/!d; s/.*v//"'), emit: versions_fastqc, topic: versions
+
+ when:
+ task.ext.when == null || task.ext.when
+
+ script:
+ def args = task.ext.args ?: ''
+ def prefix = task.ext.prefix ?: "${meta.id}"
+ // Make list of old name and new name pairs to use for renaming in the bash while loop
+ def old_new_pairs = reads instanceof Path || reads.size() == 1 ? [[reads, "${prefix}.${reads.extension}"]] : reads.withIndex().collect { entry, index -> [entry, "${prefix}_${index + 1}.${entry.extension}"] }
+ def rename_to = old_new_pairs*.join(' ').join(' ')
+ def renamed_files = old_new_pairs.collect { _old_name, new_name -> new_name }.join(' ')
+
+ // The total amount of allocated RAM by FastQC is equal to the number of threads defined (--threads) time the amount of RAM defined (--memory)
+ // https://github.com/s-andrews/FastQC/blob/1faeea0412093224d7f6a07f777fad60a5650795/fastqc#L211-L222
+ // Dividing the task.memory by task.cpus allows to stick to requested amount of RAM in the label
+ def memory_in_mb = task.memory
+ ? (task.memory.toUnit('MB') / task.cpus).intValue()
+ : null
+ // FastQC memory value allowed range (100 - 10000)
+ def fastqc_memory = memory_in_mb > 10000 ? 10000 : (memory_in_mb < 100 ? 100 : memory_in_mb)
+ def fastqc_memory_arg = fastqc_memory ? "--memory ${fastqc_memory}" : ''
+
+ """
+ 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} \\
+ ${fastqc_memory_arg} \\
+ ${renamed_files}
+ """
+
+ stub:
+ def prefix = task.ext.prefix ?: "${meta.id}"
+ """
+ touch ${prefix}.html
+ touch ${prefix}.zip
+ """
+}
diff --git a/modules/nf-core/fastqc/meta.yml b/modules/nf-core/fastqc/meta.yml
new file mode 100644
index 0000000..2f6cfef
--- /dev/null
+++ b/modules/nf-core/fastqc/meta.yml
@@ -0,0 +1,111 @@
+name: fastqc
+description: Run FastQC on sequenced reads
+keywords:
+ - quality control
+ - qc
+ - adapters
+ - fastq
+tools:
+ - fastqc:
+ description: |
+ FastQC gives general quality metrics about your reads.
+ It provides information about the quality score distribution
+ across your reads, the per base sequence content (%A/C/G/T).
+
+ You get information about adapter contamination and other
+ overrepresented sequences.
+ homepage: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/
+ documentation: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/Help/
+ licence: ["GPL-2.0-only"]
+ identifier: biotools:fastqc
+input:
+ - - meta:
+ type: map
+ description: |
+ Groovy Map containing sample information
+ e.g. [ id:'test', single_end:false ]
+ - reads:
+ type: file
+ description: |
+ List of input FastQ files of size 1 and 2 for single-end and paired-end data,
+ respectively.
+ ontologies: []
+output:
+ html:
+ - - meta:
+ type: map
+ description: |
+ Groovy Map containing sample information
+ e.g. [ id:'test', single_end:false ]
+ - "*.html":
+ type: file
+ description: FastQC report
+ pattern: "*_{fastqc.html}"
+ ontologies: []
+ zip:
+ - - meta:
+ type: map
+ description: |
+ Groovy Map containing sample information
+ e.g. [ id:'test', single_end:false ]
+ - "*.zip":
+ type: file
+ description: FastQC report archive
+ pattern: "*_{fastqc.zip}"
+ ontologies: []
+ versions_fastqc:
+ - - ${task.process}:
+ type: string
+ description: The process the versions were collected from
+ - fastqc:
+ type: string
+ description: The tool name
+ - fastqc --version | sed "/FastQC v/!d; s/.*v//":
+ type: eval
+ description: The expression to obtain the version of the tool
+
+topics:
+ versions:
+ - - ${task.process}:
+ type: string
+ description: The process the versions were collected from
+ - fastqc:
+ type: string
+ description: The tool name
+ - fastqc --version | sed "/FastQC v/!d; s/.*v//":
+ type: eval
+ description: The expression to obtain the version of the tool
+authors:
+ - "@drpatelh"
+ - "@grst"
+ - "@ewels"
+ - "@FelixKrueger"
+maintainers:
+ - "@drpatelh"
+ - "@grst"
+ - "@ewels"
+ - "@FelixKrueger"
+containers:
+ docker:
+ linux/arm64:
+ name: community.wave.seqera.io/library/fastqc:0.12.1--e455e32f745abe68
+ build_id: bd-e455e32f745abe68_1
+ scan_id: sc-f102f736465af88c_1
+ linux/amd64:
+ name: community.wave.seqera.io/library/fastqc:0.12.1--5cb1a2fa2f18c7c2
+ build_id: bd-5cb1a2fa2f18c7c2_1
+ scan_id: sc-0c0466326b6b77d2_1
+ singularity:
+ linux/amd64:
+ name: oras://community.wave.seqera.io/library/fastqc:0.12.1--5c4bd442468d75dd
+ build_id: bd-5c4bd442468d75dd_1
+ https: https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/f2/f20b021476d1d87658820f971ebecc1e8cdbde0f338eb0d9cea2b0a8fc54a54b/data
+ linux/arm64:
+ name: oras://community.wave.seqera.io/library/fastqc:0.12.1--127a87fc06499035
+ build_id: bd-127a87fc06499035_1
+ https: https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/46/46daf2dad0169afd2ae047c3e50ed3776259f664bf07e5e06b045dc23449e994/data
+ conda:
+ linux/amd64:
+ lock_file: modules/nf-core/fastqc/.conda-lock/linux_amd64-bd-5cb1a2fa2f18c7c2_1.txt
+ linux/arm64:
+ lock_file: modules/nf-core/fastqc/.conda-lock/linux_arm64-bd-e455e32f745abe68_1.txt
diff --git a/modules/nf-core/fastqc/tests/main.nf.test b/modules/nf-core/fastqc/tests/main.nf.test
new file mode 100644
index 0000000..66c44da
--- /dev/null
+++ b/modules/nf-core/fastqc/tests/main.nf.test
@@ -0,0 +1,309 @@
+nextflow_process {
+
+ name "Test Process FASTQC"
+ script "../main.nf"
+ process "FASTQC"
+
+ tag "modules"
+ tag "modules_nfcore"
+ tag "fastqc"
+
+ test("sarscov2 single-end [fastq]") {
+
+ when {
+ process {
+ """
+ input[0] = Channel.of([
+ [ id: 'test', single_end:true ],
+ [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) ]
+ ])
+ """
+ }
+ }
+
+ then {
+ assertAll (
+ { assert process.success },
+ // NOTE The report contains the date inside it, which means that the md5sum is stable per day, but not longer than that. So you can't md5sum it.
+ // looks like this:
+ // https://github.com/nf-core/modules/pull/3903#issuecomment-1743620039
+ { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" },
+ { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" },
+ { assert path(process.out.html[0][1]).text.contains("| File type | Conventional base calls |
") },
+ { assert snapshot(sanitizeOutput(process.out).findAll { key, val -> key != 'html' && key != 'zip' }).match() }
+ )
+ }
+ }
+
+ test("sarscov2 paired-end [fastq]") {
+
+ when {
+ process {
+ """
+ input[0] = Channel.of([
+ [id: 'test', single_end: false], // meta map
+ [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true),
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true) ]
+ ])
+ """
+ }
+ }
+
+ then {
+ assertAll (
+ { assert process.success },
+ { assert process.out.html[0][1][0] ==~ ".*/test_1_fastqc.html" },
+ { assert process.out.html[0][1][1] ==~ ".*/test_2_fastqc.html" },
+ { assert process.out.zip[0][1][0] ==~ ".*/test_1_fastqc.zip" },
+ { assert process.out.zip[0][1][1] ==~ ".*/test_2_fastqc.zip" },
+ { assert path(process.out.html[0][1][0]).text.contains("| File type | Conventional base calls |
") },
+ { assert path(process.out.html[0][1][1]).text.contains("| File type | Conventional base calls |
") },
+ { assert snapshot(sanitizeOutput(process.out).findAll { key, val -> key != 'html' && key != 'zip' }).match() }
+ )
+ }
+ }
+
+ test("sarscov2 interleaved [fastq]") {
+
+ when {
+ process {
+ """
+ input[0] = Channel.of([
+ [id: 'test', single_end: false], // meta map
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_interleaved.fastq.gz', checkIfExists: true)
+ ])
+ """
+ }
+ }
+
+ then {
+ assertAll (
+ { assert process.success },
+ { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" },
+ { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" },
+ { assert path(process.out.html[0][1]).text.contains("| File type | Conventional base calls |
") },
+ { assert snapshot(sanitizeOutput(process.out).findAll { key, val -> key != 'html' && key != 'zip' }).match() }
+ )
+ }
+ }
+
+ test("sarscov2 paired-end [bam]") {
+
+ when {
+ process {
+ """
+ input[0] = Channel.of([
+ [id: 'test', single_end: false], // meta map
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true)
+ ])
+ """
+ }
+ }
+
+ then {
+ assertAll (
+ { assert process.success },
+ { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" },
+ { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" },
+ { assert path(process.out.html[0][1]).text.contains("| File type | Conventional base calls |
") },
+ { assert snapshot(sanitizeOutput(process.out).findAll { key, val -> key != 'html' && key != 'zip' }).match() }
+ )
+ }
+ }
+
+ test("sarscov2 multiple [fastq]") {
+
+ when {
+ process {
+ """
+ input[0] = Channel.of([
+ [id: 'test', single_end: false], // meta map
+ [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true),
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true),
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_1.fastq.gz', checkIfExists: true),
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_2.fastq.gz', checkIfExists: true) ]
+ ])
+ """
+ }
+ }
+
+ then {
+ assertAll (
+ { assert process.success },
+ { assert process.out.html[0][1][0] ==~ ".*/test_1_fastqc.html" },
+ { assert process.out.html[0][1][1] ==~ ".*/test_2_fastqc.html" },
+ { assert process.out.html[0][1][2] ==~ ".*/test_3_fastqc.html" },
+ { assert process.out.html[0][1][3] ==~ ".*/test_4_fastqc.html" },
+ { assert process.out.zip[0][1][0] ==~ ".*/test_1_fastqc.zip" },
+ { assert process.out.zip[0][1][1] ==~ ".*/test_2_fastqc.zip" },
+ { assert process.out.zip[0][1][2] ==~ ".*/test_3_fastqc.zip" },
+ { assert process.out.zip[0][1][3] ==~ ".*/test_4_fastqc.zip" },
+ { assert path(process.out.html[0][1][0]).text.contains("| File type | Conventional base calls |
") },
+ { assert path(process.out.html[0][1][1]).text.contains("| File type | Conventional base calls |
") },
+ { assert path(process.out.html[0][1][2]).text.contains("| File type | Conventional base calls |
") },
+ { assert path(process.out.html[0][1][3]).text.contains("| File type | Conventional base calls |
") },
+ { assert snapshot(sanitizeOutput(process.out).findAll { key, val -> key != 'html' && key != 'zip' }).match() }
+ )
+ }
+ }
+
+ test("sarscov2 custom_prefix") {
+
+ when {
+ process {
+ """
+ input[0] = Channel.of([
+ [ id:'mysample', single_end:true ], // meta map
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true)
+ ])
+ """
+ }
+ }
+
+ then {
+ assertAll (
+ { assert process.success },
+ { assert process.out.html[0][1] ==~ ".*/mysample_fastqc.html" },
+ { assert process.out.zip[0][1] ==~ ".*/mysample_fastqc.zip" },
+ { assert path(process.out.html[0][1]).text.contains("| File type | Conventional base calls |
") },
+ { assert snapshot(sanitizeOutput(process.out).findAll { key, val -> key != 'html' && key != 'zip' }).match() }
+ )
+ }
+ }
+
+ test("sarscov2 single-end [fastq] - stub") {
+
+ options "-stub"
+ when {
+ process {
+ """
+ input[0] = Channel.of([
+ [ id: 'test', single_end:true ],
+ [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) ]
+ ])
+ """
+ }
+ }
+
+ then {
+ assertAll (
+ { assert process.success },
+ { assert snapshot(process.out).match() }
+ )
+ }
+ }
+
+ test("sarscov2 paired-end [fastq] - stub") {
+
+ options "-stub"
+ when {
+ process {
+ """
+ input[0] = Channel.of([
+ [id: 'test', single_end: false], // meta map
+ [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true),
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true) ]
+ ])
+ """
+ }
+ }
+
+ then {
+ assertAll (
+ { assert process.success },
+ { assert snapshot(process.out).match() }
+ )
+ }
+ }
+
+ test("sarscov2 interleaved [fastq] - stub") {
+
+ options "-stub"
+ when {
+ process {
+ """
+ input[0] = Channel.of([
+ [id: 'test', single_end: false], // meta map
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_interleaved.fastq.gz', checkIfExists: true)
+ ])
+ """
+ }
+ }
+
+ then {
+ assertAll (
+ { assert process.success },
+ { assert snapshot(process.out).match() }
+ )
+ }
+ }
+
+ test("sarscov2 paired-end [bam] - stub") {
+
+ options "-stub"
+ when {
+ process {
+ """
+ input[0] = Channel.of([
+ [id: 'test', single_end: false], // meta map
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true)
+ ])
+ """
+ }
+ }
+
+ then {
+ assertAll (
+ { assert process.success },
+ { assert snapshot(process.out).match() }
+ )
+ }
+ }
+
+ test("sarscov2 multiple [fastq] - stub") {
+
+ options "-stub"
+ when {
+ process {
+ """
+ input[0] = Channel.of([
+ [id: 'test', single_end: false], // meta map
+ [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true),
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true),
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_1.fastq.gz', checkIfExists: true),
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_2.fastq.gz', checkIfExists: true) ]
+ ])
+ """
+ }
+ }
+
+ then {
+ assertAll (
+ { assert process.success },
+ { assert snapshot(process.out).match() }
+ )
+ }
+ }
+
+ test("sarscov2 custom_prefix - stub") {
+
+ options "-stub"
+ when {
+ process {
+ """
+ input[0] = Channel.of([
+ [ id:'mysample', single_end:true ], // meta map
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true)
+ ])
+ """
+ }
+ }
+
+ then {
+ assertAll (
+ { assert process.success },
+ { assert snapshot(process.out).match() }
+ )
+ }
+ }
+}
diff --git a/modules/nf-core/fastqc/tests/main.nf.test.snap b/modules/nf-core/fastqc/tests/main.nf.test.snap
new file mode 100644
index 0000000..c8ee120
--- /dev/null
+++ b/modules/nf-core/fastqc/tests/main.nf.test.snap
@@ -0,0 +1,476 @@
+{
+ "sarscov2 custom_prefix": {
+ "content": [
+ {
+ "versions_fastqc": [
+ [
+ "FASTQC",
+ "fastqc",
+ "0.12.1"
+ ]
+ ]
+ }
+ ],
+ "meta": {
+ "nf-test": "0.9.2",
+ "nextflow": "25.10.0"
+ },
+ "timestamp": "2025-10-28T16:39:14.518503"
+ },
+ "sarscov2 single-end [fastq] - stub": {
+ "content": [
+ {
+ "0": [
+ [
+ {
+ "id": "test",
+ "single_end": true
+ },
+ "test.html:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ],
+ "1": [
+ [
+ {
+ "id": "test",
+ "single_end": true
+ },
+ "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ],
+ "2": [
+ [
+ "FASTQC",
+ "fastqc",
+ "0.12.1"
+ ]
+ ],
+ "html": [
+ [
+ {
+ "id": "test",
+ "single_end": true
+ },
+ "test.html:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ],
+ "versions_fastqc": [
+ [
+ "FASTQC",
+ "fastqc",
+ "0.12.1"
+ ]
+ ],
+ "zip": [
+ [
+ {
+ "id": "test",
+ "single_end": true
+ },
+ "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ]
+ }
+ ],
+ "meta": {
+ "nf-test": "0.9.2",
+ "nextflow": "25.10.0"
+ },
+ "timestamp": "2025-10-28T16:39:19.309008"
+ },
+ "sarscov2 custom_prefix - stub": {
+ "content": [
+ {
+ "0": [
+ [
+ {
+ "id": "mysample",
+ "single_end": true
+ },
+ "mysample.html:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ],
+ "1": [
+ [
+ {
+ "id": "mysample",
+ "single_end": true
+ },
+ "mysample.zip:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ],
+ "2": [
+ [
+ "FASTQC",
+ "fastqc",
+ "0.12.1"
+ ]
+ ],
+ "html": [
+ [
+ {
+ "id": "mysample",
+ "single_end": true
+ },
+ "mysample.html:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ],
+ "versions_fastqc": [
+ [
+ "FASTQC",
+ "fastqc",
+ "0.12.1"
+ ]
+ ],
+ "zip": [
+ [
+ {
+ "id": "mysample",
+ "single_end": true
+ },
+ "mysample.zip:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ]
+ }
+ ],
+ "meta": {
+ "nf-test": "0.9.2",
+ "nextflow": "25.10.0"
+ },
+ "timestamp": "2025-10-28T16:39:44.94888"
+ },
+ "sarscov2 interleaved [fastq]": {
+ "content": [
+ {
+ "versions_fastqc": [
+ [
+ "FASTQC",
+ "fastqc",
+ "0.12.1"
+ ]
+ ]
+ }
+ ],
+ "meta": {
+ "nf-test": "0.9.2",
+ "nextflow": "25.10.0"
+ },
+ "timestamp": "2025-10-28T16:38:45.168496"
+ },
+ "sarscov2 paired-end [bam]": {
+ "content": [
+ {
+ "versions_fastqc": [
+ [
+ "FASTQC",
+ "fastqc",
+ "0.12.1"
+ ]
+ ]
+ }
+ ],
+ "meta": {
+ "nf-test": "0.9.2",
+ "nextflow": "25.10.0"
+ },
+ "timestamp": "2025-10-28T16:38:53.268919"
+ },
+ "sarscov2 multiple [fastq]": {
+ "content": [
+ {
+ "versions_fastqc": [
+ [
+ "FASTQC",
+ "fastqc",
+ "0.12.1"
+ ]
+ ]
+ }
+ ],
+ "meta": {
+ "nf-test": "0.9.2",
+ "nextflow": "25.10.0"
+ },
+ "timestamp": "2025-10-28T16:39:05.050305"
+ },
+ "sarscov2 paired-end [fastq]": {
+ "content": [
+ {
+ "versions_fastqc": [
+ [
+ "FASTQC",
+ "fastqc",
+ "0.12.1"
+ ]
+ ]
+ }
+ ],
+ "meta": {
+ "nf-test": "0.9.2",
+ "nextflow": "25.10.0"
+ },
+ "timestamp": "2025-10-28T16:38:37.2373"
+ },
+ "sarscov2 paired-end [fastq] - stub": {
+ "content": [
+ {
+ "0": [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.html:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ],
+ "1": [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ],
+ "2": [
+ [
+ "FASTQC",
+ "fastqc",
+ "0.12.1"
+ ]
+ ],
+ "html": [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.html:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ],
+ "versions_fastqc": [
+ [
+ "FASTQC",
+ "fastqc",
+ "0.12.1"
+ ]
+ ],
+ "zip": [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ]
+ }
+ ],
+ "meta": {
+ "nf-test": "0.9.2",
+ "nextflow": "25.10.0"
+ },
+ "timestamp": "2025-10-28T16:39:24.450398"
+ },
+ "sarscov2 multiple [fastq] - stub": {
+ "content": [
+ {
+ "0": [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.html:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ],
+ "1": [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ],
+ "2": [
+ [
+ "FASTQC",
+ "fastqc",
+ "0.12.1"
+ ]
+ ],
+ "html": [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.html:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ],
+ "versions_fastqc": [
+ [
+ "FASTQC",
+ "fastqc",
+ "0.12.1"
+ ]
+ ],
+ "zip": [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ]
+ }
+ ],
+ "meta": {
+ "nf-test": "0.9.2",
+ "nextflow": "25.10.0"
+ },
+ "timestamp": "2025-10-28T16:39:39.758762"
+ },
+ "sarscov2 single-end [fastq]": {
+ "content": [
+ {
+ "versions_fastqc": [
+ [
+ "FASTQC",
+ "fastqc",
+ "0.12.1"
+ ]
+ ]
+ }
+ ],
+ "meta": {
+ "nf-test": "0.9.2",
+ "nextflow": "25.10.0"
+ },
+ "timestamp": "2025-10-28T16:38:29.555068"
+ },
+ "sarscov2 interleaved [fastq] - stub": {
+ "content": [
+ {
+ "0": [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.html:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ],
+ "1": [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ],
+ "2": [
+ [
+ "FASTQC",
+ "fastqc",
+ "0.12.1"
+ ]
+ ],
+ "html": [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.html:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ],
+ "versions_fastqc": [
+ [
+ "FASTQC",
+ "fastqc",
+ "0.12.1"
+ ]
+ ],
+ "zip": [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ]
+ }
+ ],
+ "meta": {
+ "nf-test": "0.9.2",
+ "nextflow": "25.10.0"
+ },
+ "timestamp": "2025-10-28T16:39:29.193136"
+ },
+ "sarscov2 paired-end [bam] - stub": {
+ "content": [
+ {
+ "0": [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.html:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ],
+ "1": [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ],
+ "2": [
+ [
+ "FASTQC",
+ "fastqc",
+ "0.12.1"
+ ]
+ ],
+ "html": [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.html:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ],
+ "versions_fastqc": [
+ [
+ "FASTQC",
+ "fastqc",
+ "0.12.1"
+ ]
+ ],
+ "zip": [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ]
+ }
+ ],
+ "meta": {
+ "nf-test": "0.9.2",
+ "nextflow": "25.10.0"
+ },
+ "timestamp": "2025-10-28T16:39:34.144919"
+ }
+}
\ No newline at end of file
diff --git a/modules/nf-core/gatk4/markduplicates/environment.yml b/modules/nf-core/gatk4/markduplicates/environment.yml
new file mode 100644
index 0000000..4a13c61
--- /dev/null
+++ b/modules/nf-core/gatk4/markduplicates/environment.yml
@@ -0,0 +1,15 @@
+---
+# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json
+channels:
+ - conda-forge
+ - bioconda
+
+dependencies:
+ # renovate: datasource=conda depName=bioconda/gatk4
+ - bioconda::gatk4=4.6.2.0
+ # renovate: datasource=conda depName=bioconda/gcnvkernel
+ - bioconda::gcnvkernel=0.9
+ # do not update - later htslib versions not compatible with gcnvkernel
+ - bioconda::htslib=1.21
+ # do not update - later samtools versions not compatible with gcnvkernel
+ - bioconda::samtools=1.21
diff --git a/modules/nf-core/gatk4/markduplicates/main.nf b/modules/nf-core/gatk4/markduplicates/main.nf
new file mode 100644
index 0000000..6fd44ea
--- /dev/null
+++ b/modules/nf-core/gatk4/markduplicates/main.nf
@@ -0,0 +1,75 @@
+process GATK4_MARKDUPLICATES {
+ tag "${meta.id}"
+ label 'process_low'
+
+ conda "${moduleDir}/environment.yml"
+ container "${workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container
+ ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/e3/e3d753d93f57969fe76b8628a8dfcd23ef44bccd08c4ced7089c1f94bf47c89f/data'
+ : 'community.wave.seqera.io/library/gatk4_gcnvkernel_htslib_samtools:d3becb6465454c35'}"
+
+ input:
+ tuple val(meta), path(bam)
+ path fasta
+ path fasta_fai
+
+ output:
+ tuple val(meta), path("*cram"), emit: cram, optional: true
+ tuple val(meta), path("*bam"), emit: bam, optional: true
+ tuple val(meta), path("*.crai"), emit: crai, optional: true
+ tuple val(meta), path("*.bai"), emit: bai, optional: true
+ tuple val(meta), path("*.metrics"), emit: metrics
+ tuple val("${task.process}"), val('gatk4'), eval("gatk --version | sed -n '/GATK.*v/s/.*v//p'"), topic: versions, emit: versions_gatk4
+ tuple val("${task.process}"), val('samtools'), eval("samtools version | sed '1!d;s/.* //'"), topic: versions, emit: versions_samtools
+
+ when:
+ task.ext.when == null || task.ext.when
+
+ script:
+ def args = task.ext.args ?: ''
+ prefix = task.ext.prefix ?: "${meta.id}.bam"
+
+ // If the extension is CRAM, then change it to BAM
+ prefix_bam = prefix.tokenize('.')[-1] == 'cram' ? "${prefix.substring(0, prefix.lastIndexOf('.'))}.bam" : prefix
+
+ def input_list = bam.collect { bam_ -> "--INPUT ${bam_}" }.join(' ')
+ def reference = fasta ? "--REFERENCE_SEQUENCE ${fasta}" : ""
+
+ def avail_mem = 3072
+ if (!task.memory) {
+ log.info('[GATK MarkDuplicates] Available memory not known - defaulting to 3GB. Specify process memory requirements to change this.')
+ }
+ else {
+ avail_mem = (task.memory.mega * 0.8).intValue()
+ }
+
+ // Using samtools and not Markduplicates to compress to CRAM speeds up computation:
+ // https://medium.com/@acarroll.dna/looking-at-trade-offs-in-compression-levels-for-genomics-tools-eec2834e8b94
+ """
+ gatk --java-options "-Xmx${avail_mem}M -XX:-UsePerfData" \\
+ MarkDuplicates \\
+ ${input_list} \\
+ --OUTPUT ${prefix_bam} \\
+ --METRICS_FILE ${prefix}.metrics \\
+ --TMP_DIR . \\
+ ${reference} \\
+ ${args}
+
+ # If cram files are wished as output, the run samtools for conversion
+ if [[ ${prefix} == *.cram ]]; then
+ samtools view -Ch -T ${fasta} -o ${prefix} ${prefix_bam}
+ rm ${prefix_bam}
+ samtools index ${prefix}
+ fi
+ """
+
+ stub:
+ prefix = task.ext.prefix ?: "${meta.id}.bam"
+ prefix_no_suffix = task.ext.prefix ? prefix.tokenize('.')[0] : "${meta.id}"
+ """
+ touch ${prefix_no_suffix}.bam
+ touch ${prefix_no_suffix}.cram
+ touch ${prefix_no_suffix}.cram.crai
+ touch ${prefix_no_suffix}.bai
+ touch ${prefix}.metrics
+ """
+}
diff --git a/modules/nf-core/gatk4/markduplicates/meta.yml b/modules/nf-core/gatk4/markduplicates/meta.yml
new file mode 100644
index 0000000..33dbc1a
--- /dev/null
+++ b/modules/nf-core/gatk4/markduplicates/meta.yml
@@ -0,0 +1,149 @@
+name: gatk4_markduplicates
+description: This tool locates and tags duplicate reads in a BAM or SAM file,
+ where duplicate reads are defined as originating from a single fragment of
+ DNA.
+keywords:
+ - bam
+ - gatk4
+ - markduplicates
+ - sort
+tools:
+ - gatk4:
+ description: Developed in the Data Sciences Platform at the Broad Institute,
+ the toolkit offers a wide variety of tools with a primary focus on variant
+ discovery and genotyping. Its powerful processing engine and
+ high-performance computing features make it capable of taking on projects
+ of any size.
+ homepage: https://gatk.broadinstitute.org/hc/en-us
+ documentation: https://gatk.broadinstitute.org/hc/en-us/articles/360037052812-MarkDuplicates-Picard-
+ tool_dev_url: https://github.com/broadinstitute/gatk
+ doi: 10.1158/1538-7445.AM2017-3590
+ licence: ["MIT"]
+ identifier: ""
+input:
+ - - meta:
+ type: map
+ description: |
+ Groovy Map containing sample information
+ e.g. [ id:'test', single_end:false ]
+ - bam:
+ type: file
+ description: Sorted BAM file
+ pattern: "*.{bam}"
+ ontologies: []
+ - fasta:
+ type: file
+ description: Fasta file
+ pattern: "*.{fasta}"
+ ontologies: []
+ - fasta_fai:
+ type: file
+ description: Fasta index file
+ pattern: "*.{fai}"
+ ontologies: []
+output:
+ cram:
+ - - meta:
+ type: map
+ description: |
+ Groovy Map containing sample information
+ e.g. [ id:'test', single_end:false ]
+ - "*cram":
+ type: file
+ description: Marked duplicates CRAM file
+ pattern: "*.{cram}"
+ ontologies: []
+ bam:
+ - - meta:
+ type: map
+ description: |
+ Groovy Map containing sample information
+ e.g. [ id:'test', single_end:false ]
+ - "*bam":
+ type: file
+ description: Marked duplicates BAM file
+ pattern: "*.{bam}"
+ ontologies: []
+ crai:
+ - - meta:
+ type: map
+ description: |
+ Groovy Map containing sample information
+ e.g. [ id:'test', single_end:false ]
+ - "*.crai":
+ type: file
+ description: CRAM index file
+ pattern: "*.{cram.crai}"
+ ontologies: []
+ bai:
+ - - meta:
+ type: map
+ description: |
+ Groovy Map containing sample information
+ e.g. [ id:'test', single_end:false ]
+ - "*.bai":
+ type: file
+ description: BAM index file
+ pattern: "*.{bam.bai}"
+ ontologies: []
+ metrics:
+ - - meta:
+ type: map
+ description: |
+ Groovy Map containing sample information
+ e.g. [ id:'test', single_end:false ]
+ - "*.metrics":
+ type: file
+ description: Duplicate metrics file generated by GATK
+ pattern: "*.{metrics.txt}"
+ ontologies: []
+ versions_gatk4:
+ - - ${task.process}:
+ type: string
+ description: The name of the process
+ - gatk4:
+ type: string
+ description: The name of the tool
+ - gatk --version | sed -n '/GATK.*v/s/.*v//p':
+ type: eval
+ description: The expression to obtain the version of the tool
+ versions_samtools:
+ - - ${task.process}:
+ type: string
+ description: The name of the process
+ - samtools:
+ type: string
+ description: The name of the tool
+ - samtools version | sed '1!d;s/.* //':
+ type: eval
+ description: The expression to obtain the version of the tool
+
+topics:
+ versions:
+ - - ${task.process}:
+ type: string
+ description: The name of the process
+ - gatk4:
+ type: string
+ description: The name of the tool
+ - gatk --version | sed -n '/GATK.*v/s/.*v//p':
+ type: eval
+ description: The expression to obtain the version of the tool
+ - - ${task.process}:
+ type: string
+ description: The name of the process
+ - samtools:
+ type: string
+ description: The name of the tool
+ - samtools version | sed '1!d;s/.* //':
+ type: eval
+ description: The expression to obtain the version of the tool
+
+authors:
+ - "@ajodeh-juma"
+ - "@FriederikeHanssen"
+ - "@maxulysse"
+maintainers:
+ - "@ajodeh-juma"
+ - "@FriederikeHanssen"
+ - "@maxulysse"
diff --git a/modules/nf-core/gatk4/markduplicates/tests/bam.config b/modules/nf-core/gatk4/markduplicates/tests/bam.config
new file mode 100644
index 0000000..0bbfbac
--- /dev/null
+++ b/modules/nf-core/gatk4/markduplicates/tests/bam.config
@@ -0,0 +1,8 @@
+process {
+
+ withName: GATK4_MARKDUPLICATES {
+ ext.args = '--CREATE_INDEX true'
+ ext.prefix = { "${meta.id}.bam" }
+ }
+
+}
diff --git a/modules/nf-core/gatk4/markduplicates/tests/cram.config b/modules/nf-core/gatk4/markduplicates/tests/cram.config
new file mode 100644
index 0000000..04a9b07
--- /dev/null
+++ b/modules/nf-core/gatk4/markduplicates/tests/cram.config
@@ -0,0 +1,8 @@
+process {
+
+ withName: GATK4_MARKDUPLICATES {
+ ext.args = '--CREATE_INDEX true'
+ ext.prefix = { "${meta.id}.cram" }
+ }
+
+}
diff --git a/modules/nf-core/gatk4/markduplicates/tests/main.nf.test b/modules/nf-core/gatk4/markduplicates/tests/main.nf.test
new file mode 100644
index 0000000..bbf6639
--- /dev/null
+++ b/modules/nf-core/gatk4/markduplicates/tests/main.nf.test
@@ -0,0 +1,128 @@
+nextflow_process {
+
+ name "Test Process GATK4_MARKDUPLICATES"
+ script "../main.nf"
+ process "GATK4_MARKDUPLICATES"
+
+ tag "modules"
+ tag "modules_nfcore"
+ tag "gatk4"
+ tag "gatk4/markduplicates"
+
+ test("sarscov2 - bam") {
+ config "./bam.config"
+
+ when {
+ process {
+ """
+ input[0] = [
+ [ id:'test', single_end:false ],
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true)
+ ]
+ input[1] = []
+ input[2] = []
+ """
+ }
+ }
+
+ then {
+ assert process.success
+ assertAll(
+ { assert snapshot(
+ process.out.bam,
+ process.out.bai,
+ file(process.out.metrics[0][1]).name,
+ process.out.findAll { key, val -> key.startsWith("versions") }
+ ).match() }
+ )
+ }
+ }
+
+ test("homo_sapiens - multiple bam") {
+ config "./bam.config"
+
+ when {
+ process {
+ """
+ input[0] = [
+ [ id:'test', single_end:false ],
+ [
+ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true),
+ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/bam/test2.paired_end.sorted.bam', checkIfExists: true)
+ ]
+ ]
+ input[1] = []
+ input[2] = []
+ """
+ }
+ }
+
+ then {
+ assert process.success
+ assertAll(
+ { assert snapshot(
+ process.out.bam,
+ process.out.bai,
+ file(process.out.metrics[0][1]).name,
+ process.out.findAll { key, val -> key.startsWith("versions") }
+ ).match() }
+ )
+ }
+ }
+
+ test("homo_sapiens - multiple cram") {
+ config "./cram.config"
+
+ when {
+ process {
+ """
+ input[0] = [
+ [ id:'test', single_end:false ], // meta map
+ [
+ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true),
+ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/bam/test2.paired_end.sorted.bam', checkIfExists: true)
+ ]
+ ]
+ input[1] = file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true)
+ input[2] = file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.fai', checkIfExists: true)
+ """
+ }
+ }
+
+ then {
+ assert process.success
+ assertAll(
+ { assert snapshot(
+ file(process.out.cram[0][1]).name,
+ file(process.out.crai[0][1]).name,
+ file(process.out.metrics[0][1]).name,
+ process.out.findAll { key, val -> key.startsWith("versions") }
+ ).match() }
+ )
+ }
+ }
+
+ test("stub") {
+ config "./bam.config"
+ options "-stub"
+
+ when {
+ process {
+ """
+ input[0] = [
+ [ id:'test', single_end:false ],
+ []
+ ]
+ input[1] = []
+ input[2] = []
+ """
+ }
+ }
+
+ then {
+ assertAll(
+ { assert process.success }
+ )
+ }
+ }
+}
diff --git a/modules/nf-core/gatk4/markduplicates/tests/main.nf.test.snap b/modules/nf-core/gatk4/markduplicates/tests/main.nf.test.snap
new file mode 100644
index 0000000..0a49132
--- /dev/null
+++ b/modules/nf-core/gatk4/markduplicates/tests/main.nf.test.snap
@@ -0,0 +1,118 @@
+{
+ "sarscov2 - bam": {
+ "content": [
+ [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.bam:md5,a9994ba43be93769a06d4814e95928cd"
+ ]
+ ],
+ [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.bai:md5,fd1c3cc02f4e223d32eedeed842b86c7"
+ ]
+ ],
+ "test.bam.metrics",
+ {
+ "versions_gatk4": [
+ [
+ "GATK4_MARKDUPLICATES",
+ "gatk4",
+ "4.6.2.0"
+ ]
+ ],
+ "versions_samtools": [
+ [
+ "GATK4_MARKDUPLICATES",
+ "samtools",
+ "1.21"
+ ]
+ ]
+ }
+ ],
+ "meta": {
+ "nf-test": "0.9.3",
+ "nextflow": "25.10.3"
+ },
+ "timestamp": "2026-02-05T16:39:06.851947547"
+ },
+ "homo_sapiens - multiple bam": {
+ "content": [
+ [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.bam:md5,6fee419d69f55f53b5a0d0334a5f9615"
+ ]
+ ],
+ [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.bai:md5,2b1603773979ad06f4dbcbaa90e93e8c"
+ ]
+ ],
+ "test.bam.metrics",
+ {
+ "versions_gatk4": [
+ [
+ "GATK4_MARKDUPLICATES",
+ "gatk4",
+ "4.6.2.0"
+ ]
+ ],
+ "versions_samtools": [
+ [
+ "GATK4_MARKDUPLICATES",
+ "samtools",
+ "1.21"
+ ]
+ ]
+ }
+ ],
+ "meta": {
+ "nf-test": "0.9.3",
+ "nextflow": "25.10.3"
+ },
+ "timestamp": "2026-02-05T16:39:14.928475242"
+ },
+ "homo_sapiens - multiple cram": {
+ "content": [
+ "test.cram",
+ "test.cram.crai",
+ "test.cram.metrics",
+ {
+ "versions_gatk4": [
+ [
+ "GATK4_MARKDUPLICATES",
+ "gatk4",
+ "4.6.2.0"
+ ]
+ ],
+ "versions_samtools": [
+ [
+ "GATK4_MARKDUPLICATES",
+ "samtools",
+ "1.21"
+ ]
+ ]
+ }
+ ],
+ "meta": {
+ "nf-test": "0.9.3",
+ "nextflow": "25.10.3"
+ },
+ "timestamp": "2026-02-05T16:39:23.543842929"
+ }
+}
\ No newline at end of file
diff --git a/modules/nf-core/multiqc/.conda-lock/linux_amd64-bd-c17fb751507e9dfc_1.txt b/modules/nf-core/multiqc/.conda-lock/linux_amd64-bd-c17fb751507e9dfc_1.txt
new file mode 100644
index 0000000..2a91c22
--- /dev/null
+++ b/modules/nf-core/multiqc/.conda-lock/linux_amd64-bd-c17fb751507e9dfc_1.txt
@@ -0,0 +1,1526 @@
+
+version: 6
+environments:
+default:
+channels:
+- url: https://conda.anaconda.org/conda-forge/
+- url: https://conda.anaconda.org/bioconda/
+- url: https://conda.anaconda.org/bioconda/
+options:
+pypi-prerelease-mode: if-necessary-or-explicit
+packages:
+linux-64:
+- conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.7.0-pyhd8ed1ab_1.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/attrs-26.1.0-pyhcf101f3_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/backports.zstd-1.5.0-py314h680f03e_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.2.0-py314h3de4e8d_1.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.5.20-pyhd8ed1ab_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.7-pyhd8ed1ab_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/click-8.4.0-pyhc90fa1f_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/coloredlogs-15.0.1-pyhd8ed1ab_4.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/colormath-3.0.0-pyhd8ed1ab_4.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.14.5-py314hd8ed1ab_100.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/expat-2.8.1-hecca717_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2
+- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2
+- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2
+- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.18.0-h27c8c51_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/humanfriendly-10.0-pyh707e725_8.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/humanize-4.15.0-pyhd8ed1ab_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.15-pyhcf101f3_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-9.0.0-pyhcf101f3_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.6-pyhcf101f3_1.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/jsonschema-4.26.0-pyhcf101f3_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/jsonschema-specifications-2025.9.1-pyhcf101f3_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/kaleido-core-0.2.1-h3644ca4_0.tar.bz2
+- conda: https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.19.1-h0c24ade_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.1.0-hdb68285_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-7_h4a7cf45_openblas.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-7_h0358290_openblas.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.25-h17f619e_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.1-hecca717_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype-2.14.3-ha770c72_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype6-2.14.3-h73754d4_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_19.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_19.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_19.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_19.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_19.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.1.4.1-hb03c661_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-7_h47877c9_openblas.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_1.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.33-pthreads_h94d23a6_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.58-h421ea60_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.1-h0c1763c_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_19.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.1-h9d88235_1.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.1-h5347b49_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-3.10.2-pyhcf101f3_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.2.0-pyhd8ed1ab_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.3-py314h67df5f8_1.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/mathjax-2.7.7-ha770c72_3.tar.bz2
+- conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda
+- conda: https://conda.anaconda.org/bioconda/noarch/multiqc-1.35-pyhdfd78af_1.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.21.2-pyhcf101f3_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/natsort-8.4.0-pyhcf101f3_2.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/nspr-4.38-h29cc59b_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/nss-3.118-h445c969_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py314h2b28147_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.4-h55fea9a_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.2-h35e630c_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.2.0-py314h8ec4b1a_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/plotly-6.6.0-pyhd8ed1ab_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.41.0-pyh58ad624_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/polars-runtime-32-1.41.0-py310h49dadd8_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/polars-runtime-compat-1.41.0-py310hcbd6021_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/procps-ng-4.0.6-h18c060e_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/pyaml-env-1.2.2-pyhd8ed1ab_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.13.4-pyhcf101f3_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.46.4-py314h2e6c369_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.14.5-habeac84_100_cp314.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/python-dotenv-1.2.2-pyhcf101f3_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.14.5-h4df99d1_100.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/python-kaleido-0.2.1-pyhd8ed1ab_0.tar.bz2
+- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py314h67df5f8_1.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/referencing-0.37.0-pyhcf101f3_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/regex-2026.5.9-py314h5bd0f2a_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.34.2-pyhcf101f3_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/rich-15.0.0-pyhcf101f3_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/rich-click-1.9.7-pyh8f84b5b_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/rpds-py-0.30.0-py314h2e6c369_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/spectra-0.0.11-pyhd8ed1ab_2.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.53.1-hbc0de68_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/tiktoken-0.12.0-py314h67fec18_3.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/typeguard-4.5.2-pyhcf101f3_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.2-pyhcf101f3_2.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.7.0-pyhd8ed1ab_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.12-hb03c661_1.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb03c661_1.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h280c20c_3.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/zipp-4.1.0-pyhcf101f3_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-ng-2.3.3-hceb46e0_1.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda
+packages:
+- conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda
+build_number: 20
+sha256: 1dd3fffd892081df9726d7eb7e0dea6198962ba775bd88842135a4ddb4deb3c9
+md5: a9f577daf3de00bca7c3c76c0ecbd1de
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgomp >=7.5.0
+constrains:
+- openmp_impl <0.0a0
+license: BSD-3-Clause
+license_family: BSD
+size: 28948
+timestamp: 1770939786096
+- conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda
+sha256: a3967b937b9abf0f2a99f3173fa4630293979bd1644709d89580e7c62a544661
+md5: aaa2a381ccc56eac91d63b6c1240312f
+depends:
+- cpython
+- python-gil
+license: MIT
+license_family: MIT
+size: 8191
+timestamp: 1744137672556
+- conda: https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.7.0-pyhd8ed1ab_1.conda
+sha256: e0ea1ba78fbb64f17062601edda82097fcf815012cf52bb704150a2668110d48
+md5: 2934f256a8acfe48f6ebb4fce6cde29c
+depends:
+- python >=3.9
+- typing-extensions >=4.0.0
+license: MIT
+license_family: MIT
+size: 18074
+timestamp: 1733247158254
+- conda: https://conda.anaconda.org/conda-forge/noarch/attrs-26.1.0-pyhcf101f3_0.conda
+sha256: 1b6124230bb4e571b1b9401537ecff575b7b109cc3a21ee019f65e083b8399ab
+md5: c6b0543676ecb1fb2d7643941fe375f2
+depends:
+- python >=3.10
+- python
+license: MIT
+license_family: MIT
+size: 64927
+timestamp: 1773935801332
+- conda: https://conda.anaconda.org/conda-forge/noarch/backports.zstd-1.5.0-py314h680f03e_0.conda
+noarch: generic
+sha256: a1c97297e867776760489537bc5ae36fa83a154be30e3b79385a39ca4cb058fe
+md5: 1133126d840e75287d83947be3fc3e71
+depends:
+- python >=3.14
+license: BSD-3-Clause AND MIT AND EPL-2.0
+size: 7533
+timestamp: 1778594057496
+- conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.2.0-py314h3de4e8d_1.conda
+sha256: 3ad3500bff54a781c29f16ce1b288b36606e2189d0b0ef2f67036554f47f12b0
+md5: 8910d2c46f7e7b519129f486e0fe927a
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+- libstdcxx >=14
+- python >=3.14,<3.15.0a0
+- python_abi 3.14.* *_cp314
+constrains:
+- libbrotlicommon 1.2.0 hb03c661_1
+license: MIT
+license_family: MIT
+size: 367376
+timestamp: 1764017265553
+- conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda
+sha256: 0b75d45f0bba3e95dc693336fa51f40ea28c980131fec438afb7ce6118ed05f6
+md5: d2ffd7602c02f2b316fd921d39876885
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+license: bzip2-1.0.6
+license_family: BSD
+size: 260182
+timestamp: 1771350215188
+- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda
+sha256: 9812a303a1395e1dafbd92e5bc8a1ff6013bcbba0a09c7f03a8d23e43560aa9b
+md5: 489b8e97e666c93f68fdb35c3c9b957f
+depends:
+- __unix
+license: ISC
+size: 129868
+timestamp: 1779289852439
+- conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.5.20-pyhd8ed1ab_0.conda
+sha256: 645655a3510e38e625da136595f3f16f2130c3263630cc3bc8f60f619ddbe490
+md5: 9fefff2f745ea1cc2ef15211a20c054a
+depends:
+- python >=3.10
+license: ISC
+size: 134201
+timestamp: 1779285131141
+- conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.7-pyhd8ed1ab_0.conda
+sha256: 3f9483d62ce24ecd063f8a5a714448445dc8d9e201147c46699fc0033e824457
+md5: a9167b9571f3baa9d448faa2139d1089
+depends:
+- python >=3.10
+license: MIT
+license_family: MIT
+size: 58872
+timestamp: 1775127203018
+- conda: https://conda.anaconda.org/conda-forge/noarch/click-8.4.0-pyhc90fa1f_0.conda
+sha256: 99ab8ef815c4520cce3a7482c2513f377c14348206857661d84c76a55e030f97
+md5: 003767c47f1f0a474c4de268b57839c3
+depends:
+- __unix
+- python
+- python >=3.10
+license: BSD-3-Clause
+license_family: BSD
+size: 104631
+timestamp: 1779108494556
+- conda: https://conda.anaconda.org/conda-forge/noarch/coloredlogs-15.0.1-pyhd8ed1ab_4.conda
+sha256: 8021c76eeadbdd5784b881b165242db9449783e12ce26d6234060026fd6a8680
+md5: b866ff7007b934d564961066c8195983
+depends:
+- humanfriendly >=9.1
+- python >=3.9
+license: MIT
+license_family: MIT
+size: 43758
+timestamp: 1733928076798
+- conda: https://conda.anaconda.org/conda-forge/noarch/colormath-3.0.0-pyhd8ed1ab_4.conda
+sha256: 59c9e29800b483b390467f90e82b0da3a4fbf0612efe1c90813fca232780e160
+md5: 071cf7b0ce333c81718b054066c15102
+depends:
+- networkx >=2.0
+- numpy
+- python >=3.9
+license: BSD-3-Clause
+license_family: BSD
+size: 39326
+timestamp: 1735759976140
+- conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.14.5-py314hd8ed1ab_100.conda
+noarch: generic
+sha256: 777882d2685f368417f31bbe1b28f73687fc6c8f6a5768bda20ffeefa6b07f5b
+md5: a749029ce5d0632a913db19d17f944ab
+depends:
+- python >=3.14,<3.15.0a0
+- python_abi * *_cp314
+license: Python-2.0
+size: 50212
+timestamp: 1779236682725
+- conda: https://conda.anaconda.org/conda-forge/linux-64/expat-2.8.1-hecca717_0.conda
+sha256: 29a10599d56d93bd750914888ebe6822d47722070762b4647b34d12df9f4476e
+md5: d0757fd84af06f065eba49d39af6c546
+depends:
+- __glibc >=2.17,<3.0.a0
+- libexpat 2.8.1 hecca717_0
+- libgcc >=14
+license: MIT
+license_family: MIT
+size: 148238
+timestamp: 1779278694477
+- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2
+sha256: 58d7f40d2940dd0a8aa28651239adbf5613254df0f75789919c4e6762054403b
+md5: 0c96522c6bdaed4b1566d11387caaf45
+license: BSD-3-Clause
+license_family: BSD
+size: 397370
+timestamp: 1566932522327
+- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2
+sha256: c52a29fdac682c20d252facc50f01e7c2e7ceac52aa9817aaf0bb83f7559ec5c
+md5: 34893075a5c9e55cdafac56607368fc6
+license: OFL-1.1
+license_family: Other
+size: 96530
+timestamp: 1620479909603
+- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2
+sha256: 00925c8c055a2275614b4d983e1df637245e19058d79fc7dd1a93b8d9fb4b139
+md5: 4d59c254e01d9cde7957100457e2d5fb
+license: OFL-1.1
+license_family: Other
+size: 700814
+timestamp: 1620479612257
+- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda
+sha256: 2821ec1dc454bd8b9a31d0ed22a7ce22422c0aef163c59f49dfdf915d0f0ca14
+md5: 49023d73832ef61042f6a237cb2687e7
+license: LicenseRef-Ubuntu-Font-Licence-Version-1.0
+license_family: Other
+size: 1620504
+timestamp: 1727511233259
+- conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.18.0-h27c8c51_0.conda
+sha256: e798086d8a65d55dc4c51f5746705639c9a5f2eeb0b8fc50e6152cfc0d69a4e8
+md5: 06965b2f9854d0b15e0443ee81fe83dc
+depends:
+- __glibc >=2.17,<3.0.a0
+- libexpat >=2.8.1,<3.0a0
+- libfreetype >=2.14.3
+- libfreetype6 >=2.14.3
+- libgcc >=14
+- libuuid >=2.42.1,<3.0a0
+- libzlib >=1.3.2,<2.0a0
+license: MIT
+license_family: MIT
+size: 280882
+timestamp: 1779421631622
+- conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda
+sha256: 54eea8469786bc2291cc40bca5f46438d3e062a399e8f53f013b6a9f50e98333
+md5: a7970cd949a077b7cb9696379d338681
+depends:
+- font-ttf-ubuntu
+- font-ttf-inconsolata
+- font-ttf-dejavu-sans-mono
+- font-ttf-source-code-pro
+license: BSD-3-Clause
+license_family: BSD
+size: 4059
+timestamp: 1762351264405
+- conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda
+sha256: 84c64443368f84b600bfecc529a1194a3b14c3656ee2e832d15a20e0329b6da3
+md5: 164fc43f0b53b6e3a7bc7dce5e4f1dc9
+depends:
+- python >=3.10
+- hyperframe >=6.1,<7
+- hpack >=4.1,<5
+- python
+license: MIT
+license_family: MIT
+size: 95967
+timestamp: 1756364871835
+- conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda
+sha256: 6ad78a180576c706aabeb5b4c8ceb97c0cb25f1e112d76495bff23e3779948ba
+md5: 0a802cb9888dd14eeefc611f05c40b6e
+depends:
+- python >=3.9
+license: MIT
+license_family: MIT
+size: 30731
+timestamp: 1737618390337
+- conda: https://conda.anaconda.org/conda-forge/noarch/humanfriendly-10.0-pyh707e725_8.conda
+sha256: fa2071da7fab758c669e78227e6094f6b3608228740808a6de5d6bce83d9e52d
+md5: 7fe569c10905402ed47024fc481bb371
+depends:
+- __unix
+- python >=3.9
+license: MIT
+license_family: MIT
+size: 73563
+timestamp: 1733928021866
+- conda: https://conda.anaconda.org/conda-forge/noarch/humanize-4.15.0-pyhd8ed1ab_0.conda
+sha256: 6c4343b376d0b12a4c75ab992640970d36c933cad1fd924f6a1181fa91710e80
+md5: daddf757c3ecd6067b9af1df1f25d89e
+depends:
+- python >=3.10
+license: MIT
+license_family: MIT
+size: 67994
+timestamp: 1766267728652
+- conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda
+sha256: 77af6f5fe8b62ca07d09ac60127a30d9069fdc3c68d6b256754d0ffb1f7779f8
+md5: 8e6923fc12f1fe8f8c4e5c9f343256ac
+depends:
+- python >=3.9
+license: MIT
+license_family: MIT
+size: 17397
+timestamp: 1737618427549
+- conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.15-pyhcf101f3_0.conda
+sha256: 3d25f9f6f7ab3e1ce6429fc8c8aae0335cf446692e715068488536d220cc43de
+md5: 1b9083b7f00609605d1483dbc6071a81
+depends:
+- python >=3.10
+- python
+license: BSD-3-Clause
+license_family: BSD
+size: 62642
+timestamp: 1779294335905
+- conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-9.0.0-pyhcf101f3_0.conda
+sha256: 43e2a5497cad1598ff88a3e69f69bc88b7b8f141fa63c60eab5db296317318b8
+md5: ffc17e785d64e12fc311af9184221839
+depends:
+- python >=3.10
+- zipp >=3.20
+- python
+license: Apache-2.0
+size: 34766
+timestamp: 1779714582554
+- conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.6-pyhcf101f3_1.conda
+sha256: fc9ca7348a4f25fed2079f2153ecdcf5f9cf2a0bc36c4172420ca09e1849df7b
+md5: 04558c96691bed63104678757beb4f8d
+depends:
+- markupsafe >=2.0
+- python >=3.10
+- python
+license: BSD-3-Clause
+license_family: BSD
+size: 120685
+timestamp: 1764517220861
+- conda: https://conda.anaconda.org/conda-forge/noarch/jsonschema-4.26.0-pyhcf101f3_0.conda
+sha256: db973a37d75db8e19b5f44bbbdaead0c68dde745407f281e2a7fe4db74ec51d7
+md5: ada41c863af263cc4c5fcbaff7c3e4dc
+depends:
+- attrs >=22.2.0
+- jsonschema-specifications >=2023.3.6
+- python >=3.10
+- referencing >=0.28.4
+- rpds-py >=0.25.0
+- python
+license: MIT
+license_family: MIT
+size: 82356
+timestamp: 1767839954256
+- conda: https://conda.anaconda.org/conda-forge/noarch/jsonschema-specifications-2025.9.1-pyhcf101f3_0.conda
+sha256: 0a4f3b132f0faca10c89fdf3b60e15abb62ded6fa80aebfc007d05965192aa04
+md5: 439cd0f567d697b20a8f45cb70a1005a
+depends:
+- python >=3.10
+- referencing >=0.31.0
+- python
+license: MIT
+license_family: MIT
+size: 19236
+timestamp: 1757335715225
+- conda: https://conda.anaconda.org/conda-forge/linux-64/kaleido-core-0.2.1-h3644ca4_0.tar.bz2
+sha256: 7f243680ca03eba7457b7a48f93a9440ba8181a8eac20a3eb5ef165ab6c96664
+md5: b3723b235b0758abaae8c82ce4d80146
+depends:
+- __glibc >=2.17,<3.0.a0
+- expat >=2.2.10,<3.0.0a0
+- fontconfig
+- fonts-conda-forge
+- libgcc-ng >=9.3.0
+- mathjax 2.7.*
+- nspr >=4.29,<5.0a0
+- nss >=3.62,<4.0a0
+- sqlite >=3.34.0,<4.0a0
+license: MIT
+license_family: MIT
+size: 62099926
+timestamp: 1615199463039
+- conda: https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.19.1-h0c24ade_0.conda
+sha256: eb89c6c39f2f6a93db55723dbb2f6bba8c8e63e6312bf1abf13e6e9ff45849c8
+md5: f92f984b558e6e6204014b16d212b271
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+- libjpeg-turbo >=3.1.4.1,<4.0a0
+- libtiff >=4.7.1,<4.8.0a0
+license: MIT
+license_family: MIT
+size: 251086
+timestamp: 1778079286384
+- conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda
+sha256: 3d584956604909ff5df353767f3a2a2f60e07d070b328d109f30ac40cd62df6c
+md5: 18335a698559cdbcd86150a48bf54ba6
+depends:
+- __glibc >=2.17,<3.0.a0
+- zstd >=1.5.7,<1.6.0a0
+constrains:
+- binutils_impl_linux-64 2.45.1
+license: GPL-3.0-only
+license_family: GPL
+size: 728002
+timestamp: 1774197446916
+- conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.1.0-hdb68285_0.conda
+sha256: f84cb54782f7e9cea95e810ea8fef186e0652d0fa73d3009914fa2c1262594e1
+md5: a752488c68f2e7c456bcbd8f16eec275
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+- libstdcxx >=14
+license: Apache-2.0
+license_family: Apache
+size: 261513
+timestamp: 1773113328888
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-7_h4a7cf45_openblas.conda
+build_number: 7
+sha256: 081c850f99bc355821fac9c6e3727d40b3f8ce3beb50a5437cf03726b611ff39
+md5: 955b44e8b00b7f7ef4ce0130cef12394
+depends:
+- libopenblas >=0.3.33,<0.3.34.0a0
+- libopenblas >=0.3.33,<1.0a0
+constrains:
+- libcblas 3.11.0 7*_openblas
+- blas 2.307 openblas
+- liblapack 3.11.0 7*_openblas
+- liblapacke 3.11.0 7*_openblas
+- mkl <2027
+license: BSD-3-Clause
+license_family: BSD
+size: 18716
+timestamp: 1778489854108
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-7_h0358290_openblas.conda
+build_number: 7
+sha256: 956ae0bb1ec8b0c3663d75b151aceb0521b54e513bf97f621a035f9c87037970
+md5: 0675639dc24cb0032f199e7ff68e4633
+depends:
+- libblas 3.11.0 7_h4a7cf45_openblas
+constrains:
+- liblapacke 3.11.0 7*_openblas
+- blas 2.307 openblas
+- liblapack 3.11.0 7*_openblas
+license: BSD-3-Clause
+license_family: BSD
+size: 18675
+timestamp: 1778489861559
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.25-h17f619e_0.conda
+sha256: aa8e8c4be9a2e81610ddf574e05b64ee131fab5e0e3693210c9d6d2fba32c680
+md5: 6c77a605a7a689d17d4819c0f8ac9a00
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+license: MIT
+license_family: MIT
+size: 73490
+timestamp: 1761979956660
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.1-hecca717_0.conda
+sha256: 363018b25fdb5534c79783d912bd4b685a3547f4fc5996357ad548899b0ee8e7
+md5: 93764a5ca80616e9c10106cdaec92f74
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+constrains:
+- expat 2.8.1.*
+license: MIT
+license_family: MIT
+size: 77294
+timestamp: 1779278686680
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda
+sha256: 31f19b6a88ce40ebc0d5a992c131f57d919f73c0b92cd1617a5bec83f6e961e6
+md5: a360c33a5abe61c07959e449fa1453eb
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+license: MIT
+license_family: MIT
+size: 58592
+timestamp: 1769456073053
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype-2.14.3-ha770c72_0.conda
+sha256: 38f014a7129e644636e46064ecd6b1945e729c2140e21d75bb476af39e692db2
+md5: e289f3d17880e44b633ba911d57a321b
+depends:
+- libfreetype6 >=2.14.3
+license: GPL-2.0-only OR FTL
+size: 8049
+timestamp: 1774298163029
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype6-2.14.3-h73754d4_0.conda
+sha256: 16f020f96da79db1863fcdd8f2b8f4f7d52f177dd4c58601e38e9182e91adf1d
+md5: fb16b4b69e3f1dcfe79d80db8fd0c55d
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+- libpng >=1.6.55,<1.7.0a0
+- libzlib >=1.3.2,<2.0a0
+constrains:
+- freetype >=2.14.3
+license: GPL-2.0-only OR FTL
+size: 384575
+timestamp: 1774298162622
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_19.conda
+sha256: 8e0a3b5e41272e5678499b5dfc4cddb673f9e935de01eb0767ce857001229f46
+md5: 57736f29cc2b0ec0b6c2952d3f101b6a
+depends:
+- __glibc >=2.17,<3.0.a0
+- _openmp_mutex >=4.5
+constrains:
+- libgcc-ng ==15.2.0=*_19
+- libgomp 15.2.0 he0feb66_19
+license: GPL-3.0-only WITH GCC-exception-3.1
+license_family: GPL
+size: 1041084
+timestamp: 1778269013026
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_19.conda
+sha256: 9dcf54adfaa5e861123c2da4f2f0451a685464ea7e5a41ad91cf67b31d658d98
+md5: 331ee9b72b9dff570d56b1302c5ab37d
+depends:
+- libgcc 15.2.0 he0feb66_19
+license: GPL-3.0-only WITH GCC-exception-3.1
+license_family: GPL
+size: 27694
+timestamp: 1778269016987
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_19.conda
+sha256: 561a42758ef25b9ce308c4e2cf56daee4f06138385a17e29a492cd928e00be6f
+md5: 42bf7eca1a951735fa06c0e3c0d5c8e6
+depends:
+- libgfortran5 15.2.0 h68bc16d_19
+constrains:
+- libgfortran-ng ==15.2.0=*_19
+license: GPL-3.0-only WITH GCC-exception-3.1
+license_family: GPL
+size: 27655
+timestamp: 1778269042954
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_19.conda
+sha256: 057978bb69fea29ed715a9b98adf71015c31baecc4aeb2bfc20d4fd5d83579d4
+md5: 85072b0ad177c966294f129b7c04a2d5
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=15.2.0
+constrains:
+- libgfortran 15.2.0
+license: GPL-3.0-only WITH GCC-exception-3.1
+license_family: GPL
+size: 2483673
+timestamp: 1778269025089
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_19.conda
+sha256: 5abe4ab9d93f6c9757d654f1969ae2267d4505315c1f2f8fe705fd60af084f1b
+md5: faac990cb7aedc7f3a2224f2c9b0c26c
+depends:
+- __glibc >=2.17,<3.0.a0
+license: GPL-3.0-only WITH GCC-exception-3.1
+license_family: GPL
+size: 603817
+timestamp: 1778268942614
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.1.4.1-hb03c661_0.conda
+sha256: 10056646c28115b174de81a44e23e3a0a3b95b5347d2e6c45cc6d49d35294256
+md5: 6178c6f2fb254558238ef4e6c56fb782
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+constrains:
+- jpeg <0.0.0a
+license: IJG AND BSD-3-Clause AND Zlib
+size: 633831
+timestamp: 1775962768273
+- conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-7_h47877c9_openblas.conda
+build_number: 7
+sha256: 96962084921f197c9ad13fb7f8b324f2351d50ff3d8d962148751ad532f54a01
+md5: 6569b4f273740e25dc0dc7e3232c2a6c
+depends:
+- libblas 3.11.0 7_h4a7cf45_openblas
+constrains:
+- liblapacke 3.11.0 7*_openblas
+- libcblas 3.11.0 7*_openblas
+- blas 2.307 openblas
+license: BSD-3-Clause
+license_family: BSD
+size: 18694
+timestamp: 1778489869038
+- conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_0.conda
+sha256: ec30e52a3c1bf7d0425380a189d209a52baa03f22fb66dd3eb587acaa765bd6d
+md5: b88d90cad08e6bc8ad540cb310a761fb
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+constrains:
+- xz 5.8.3.*
+license: 0BSD
+size: 113478
+timestamp: 1775825492909
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_1.conda
+sha256: fe171ed5cf5959993d43ff72de7596e8ac2853e9021dec0344e583734f1e0843
+md5: 2c21e66f50753a083cbe6b80f38268fa
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+license: BSD-2-Clause
+license_family: BSD
+size: 92400
+timestamp: 1769482286018
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.33-pthreads_h94d23a6_0.conda
+sha256: 3d9aa85648e5e18a6d66db98b8c4317cc426721ad7a220aa86330d1ccedc8903
+md5: 2d3278b721e40468295ca755c3b84070
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+- libgfortran
+- libgfortran5 >=14.3.0
+constrains:
+- openblas >=0.3.33,<0.3.34.0a0
+license: BSD-3-Clause
+license_family: BSD
+size: 5931919
+timestamp: 1776993658641
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.58-h421ea60_0.conda
+sha256: 377cfe037f3eeb3b1bf3ad333f724a64d32f315ee1958581fc671891d63d3f89
+md5: eba48a68a1a2b9d3c0d9511548db85db
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+- libzlib >=1.3.2,<2.0a0
+license: zlib-acknowledgement
+size: 317729
+timestamp: 1776315175087
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.1-h0c1763c_0.conda
+sha256: 54cdcd3214313b62c2a8ee277e6f42150d9b748264c1b70d958bf735e420ef8d
+md5: 7dc38adcbf71e6b38748e919e16e0dce
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+- libzlib >=1.3.2,<2.0a0
+license: blessing
+size: 954962
+timestamp: 1777986471789
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_19.conda
+sha256: dff1058c76ec6b8759e41cefa2508162d00e4a5e6721aa68ec3fd10094e702dc
+md5: 5794b3bdc38177caf969dabd3af08549
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc 15.2.0 he0feb66_19
+constrains:
+- libstdcxx-ng ==15.2.0=*_19
+license: GPL-3.0-only WITH GCC-exception-3.1
+license_family: GPL
+size: 5852044
+timestamp: 1778269036376
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.1-h9d88235_1.conda
+sha256: e5f8c38625aa6d567809733ae04bb71c161a42e44a9fa8227abe61fa5c60ebe0
+md5: cd5a90476766d53e901500df9215e927
+depends:
+- __glibc >=2.17,<3.0.a0
+- lerc >=4.0.0,<5.0a0
+- libdeflate >=1.25,<1.26.0a0
+- libgcc >=14
+- libjpeg-turbo >=3.1.0,<4.0a0
+- liblzma >=5.8.1,<6.0a0
+- libstdcxx >=14
+- libwebp-base >=1.6.0,<2.0a0
+- libzlib >=1.3.1,<2.0a0
+- zstd >=1.5.7,<1.6.0a0
+license: HPND
+size: 435273
+timestamp: 1762022005702
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.1-h5347b49_0.conda
+sha256: 3f0edf1280e2f6684a986f821eaa3e123d2694a00b31b96ca0d4a4c12c129231
+md5: 7d0a66598195ef00b6efc55aefc7453b
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+license: BSD-3-Clause
+license_family: BSD
+size: 40163
+timestamp: 1779118517630
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_0.conda
+sha256: 3aed21ab28eddffdaf7f804f49be7a7d701e8f0e46c856d801270b470820a37b
+md5: aea31d2e5b1091feca96fcfe945c3cf9
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+constrains:
+- libwebp 1.6.0
+license: BSD-3-Clause
+license_family: BSD
+size: 429011
+timestamp: 1752159441324
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda
+sha256: 666c0c431b23c6cec6e492840b176dde533d48b7e6fb8883f5071223433776aa
+md5: 92ed62436b625154323d40d5f2f11dd7
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=13
+- pthread-stubs
+- xorg-libxau >=1.0.11,<2.0a0
+- xorg-libxdmcp
+license: MIT
+license_family: MIT
+size: 395888
+timestamp: 1727278577118
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda
+sha256: 55044c403570f0dc26e6364de4dc5368e5f3fc7ff103e867c487e2b5ab2bcda9
+md5: d87ff7921124eccd67248aa483c23fec
+depends:
+- __glibc >=2.17,<3.0.a0
+constrains:
+- zlib 1.3.2 *_2
+license: Zlib
+license_family: Other
+size: 63629
+timestamp: 1774072609062
+- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-3.10.2-pyhcf101f3_0.conda
+sha256: 20e0892592a3e7c683e3d66df704a9425d731486a97c34fc56af4da1106b2b6b
+md5: ba0a9221ce1063f31692c07370d062f3
+depends:
+- importlib-metadata >=4.4
+- python >=3.10
+- python
+license: BSD-3-Clause
+license_family: BSD
+size: 85893
+timestamp: 1770694658918
+- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.2.0-pyhd8ed1ab_0.conda
+sha256: 0c4c35376fe920714390d46e4b8d31c876d65f18e1655899e0763ec25f2a902f
+md5: 6d03368f2b2b0a5fb6839df53b2eb5e0
+depends:
+- mdurl >=0.1,<1
+- python >=3.10
+license: MIT
+license_family: MIT
+size: 69017
+timestamp: 1778169663339
+- conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.3-py314h67df5f8_1.conda
+sha256: c279be85b59a62d5c52f5dd9a4cd43ebd08933809a8416c22c3131595607d4cf
+md5: 9a17c4307d23318476d7fbf0fedc0cde
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+- python >=3.14,<3.15.0a0
+- python_abi 3.14.* *_cp314
+constrains:
+- jinja2 >=3.0.0
+license: BSD-3-Clause
+license_family: BSD
+size: 27424
+timestamp: 1772445227915
+- conda: https://conda.anaconda.org/conda-forge/linux-64/mathjax-2.7.7-ha770c72_3.tar.bz2
+sha256: 02fef69bde69db264a12f21386612262f545b6e3e68d8f1ccec19f3eaae58edf
+md5: 86e69bd82c2a2c6fd29f5ab7e02b3691
+license: Apache-2.0
+license_family: Apache
+size: 22281629
+timestamp: 1662784498331
+- conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda
+sha256: 78c1bbe1723449c52b7a9df1af2ee5f005209f67e40b6e1d3c7619127c43b1c7
+md5: 592132998493b3ff25fd7479396e8351
+depends:
+- python >=3.9
+license: MIT
+license_family: MIT
+size: 14465
+timestamp: 1733255681319
+- conda: https://conda.anaconda.org/bioconda/noarch/multiqc-1.35-pyhdfd78af_1.conda
+sha256: e86033aa55a9e915e2d0957e770bdb81e3feb26a227d1adb17f9d6c528da6a71
+md5: cdb20309681ba3ce8f52c110e214d4f3
+depends:
+- click
+- coloredlogs
+- humanize
+- importlib-metadata
+- jinja2 >=3.0.0
+- jsonschema
+- markdown
+- natsort
+- numpy
+- packaging
+- pillow >=10.2.0
+- plotly >=5.18
+- polars >=1.34.0
+- polars-runtime-compat >=1.34.0
+- pyaml-env
+- pydantic >=2.7.1
+- python >=3.9,!=3.14.1
+- python-dotenv
+- python-kaleido 0.2.1
+- pyyaml >=4
+- requests
+- rich >=10
+- rich-click
+- spectra >=0.0.10
+- tiktoken
+- tqdm
+- typeguard >=4
+license: GPL-3.0-or-later
+license_family: GPL3
+size: 4282188
+timestamp: 1779465338806
+- conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.21.2-pyhcf101f3_0.conda
+sha256: 70f43d62450927d51673eecd8823e14f5b3cfebdb43cda1d502eba97162bab42
+md5: 6687827c332121727ce383919e1ec8c2
+depends:
+- python >=3.10
+- python
+license: MIT
+license_family: MIT
+size: 284323
+timestamp: 1778929680962
+- conda: https://conda.anaconda.org/conda-forge/noarch/natsort-8.4.0-pyhcf101f3_2.conda
+sha256: aeb1548eb72e4f198e72f19d242fb695b35add2ac7b2c00e0d83687052867680
+md5: e941e85e273121222580723010bd4fa2
+depends:
+- python >=3.9
+- python
+license: MIT
+license_family: MIT
+size: 39262
+timestamp: 1770905275632
+- conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda
+sha256: fc89f74bbe362fb29fa3c037697a89bec140b346a2469a90f7936d1d7ea4d8a3
+md5: fc21868a1a5aacc937e7a18747acb8a5
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+license: X11 AND BSD-3-Clause
+size: 918956
+timestamp: 1777422145199
+- conda: https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda
+sha256: f6a82172afc50e54741f6f84527ef10424326611503c64e359e25a19a8e4c1c6
+md5: a2c1eeadae7a309daed9d62c96012a2b
+depends:
+- python >=3.11
+- python
+constrains:
+- numpy >=1.25
+- scipy >=1.11.2
+- matplotlib-base >=3.8
+- pandas >=2.0
+license: BSD-3-Clause
+license_family: BSD
+size: 1587439
+timestamp: 1765215107045
+- conda: https://conda.anaconda.org/conda-forge/linux-64/nspr-4.38-h29cc59b_0.conda
+sha256: e3664264bd936c357523b55c71ed5a30263c6ba278d726a75b1eb112e6fb0b64
+md5: e235d5566c9cc8970eb2798dd4ecf62f
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+- libstdcxx >=14
+license: MPL-2.0
+license_family: MOZILLA
+size: 228588
+timestamp: 1762348634537
+- conda: https://conda.anaconda.org/conda-forge/linux-64/nss-3.118-h445c969_0.conda
+sha256: 44dd98ffeac859d84a6dcba79a2096193a42fc10b29b28a5115687a680dd6aea
+md5: 567fbeed956c200c1db5782a424e58ee
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+- libsqlite >=3.51.0,<4.0a0
+- libstdcxx >=14
+- libzlib >=1.3.1,<2.0a0
+- nspr >=4.38,<5.0a0
+license: MPL-2.0
+license_family: MOZILLA
+size: 2057773
+timestamp: 1763485556350
+- conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py314h2b28147_0.conda
+sha256: bc61ae892973751a6b0e6ecea57ed6d7053224bddcb007165d6ceb1d7344ad47
+md5: f49b5f950379e0b97c35ca97682f7c6a
+depends:
+- python
+- libstdcxx >=14
+- libgcc >=14
+- __glibc >=2.17,<3.0.a0
+- liblapack >=3.9.0,<4.0a0
+- python_abi 3.14.* *_cp314
+- libblas >=3.9.0,<4.0a0
+- libcblas >=3.9.0,<4.0a0
+constrains:
+- numpy-base <0a0
+license: BSD-3-Clause
+license_family: BSD
+size: 8928909
+timestamp: 1779169198391
+- conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.4-h55fea9a_0.conda
+sha256: 3900f9f2dbbf4129cf3ad6acf4e4b6f7101390b53843591c53b00f034343bc4d
+md5: 11b3379b191f63139e29c0d19dee24cd
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+- libpng >=1.6.50,<1.7.0a0
+- libstdcxx >=14
+- libtiff >=4.7.1,<4.8.0a0
+- libzlib >=1.3.1,<2.0a0
+license: BSD-2-Clause
+license_family: BSD
+size: 355400
+timestamp: 1758489294972
+- conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.2-h35e630c_0.conda
+sha256: c0ef482280e38c71a08ad6d71448194b719630345b0c9c60744a2010e8a8e0cb
+md5: da1b85b6a87e141f5140bb9924cecab0
+depends:
+- __glibc >=2.17,<3.0.a0
+- ca-certificates
+- libgcc >=14
+license: Apache-2.0
+license_family: Apache
+size: 3167099
+timestamp: 1775587756857
+- conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda
+sha256: 3906abfb6511a3bb309e39b9b1b7bc38f50a723971de2395489fd1f379255890
+md5: 4c06a92e74452cfa53623a81592e8934
+depends:
+- python >=3.8
+- python
+license: Apache-2.0
+license_family: APACHE
+size: 91574
+timestamp: 1777103621679
+- conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.2.0-py314h8ec4b1a_0.conda
+sha256: 123d8a7c16c88658b4f29e9f115a047598c941708dade74fbaff373a32dbec5e
+md5: 76c4757c0ec9d11f969e8eb44899307b
+depends:
+- python
+- libgcc >=14
+- __glibc >=2.17,<3.0.a0
+- libtiff >=4.7.1,<4.8.0a0
+- openjpeg >=2.5.4,<3.0a0
+- libxcb >=1.17.0,<2.0a0
+- libwebp-base >=1.6.0,<2.0a0
+- zlib-ng >=2.3.3,<2.4.0a0
+- libjpeg-turbo >=3.1.2,<4.0a0
+- python_abi 3.14.* *_cp314
+- libfreetype >=2.14.3
+- libfreetype6 >=2.14.3
+- lcms2 >=2.18,<3.0a0
+- tk >=8.6.13,<8.7.0a0
+license: HPND
+size: 1082797
+timestamp: 1775060059882
+- conda: https://conda.anaconda.org/conda-forge/noarch/plotly-6.6.0-pyhd8ed1ab_0.conda
+sha256: c418d325359fc7a0074cea7f081ef1bce26e114d2da8a0154c5d27ecc87a08e7
+md5: 3e9427ee186846052e81fadde8ebe96a
+depends:
+- narwhals >=1.15.1
+- packaging
+- python >=3.10
+constrains:
+- ipywidgets >=7.6
+license: MIT
+license_family: MIT
+size: 5251872
+timestamp: 1772628857717
+- conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.41.0-pyh58ad624_0.conda
+sha256: 70fc56877c4a095ee658d61924d8019768fbae4a48437058d181fc94b0a7c4d8
+md5: 25a883fed9f1f3f21ff317a3e7c92ac4
+depends:
+- polars-runtime-32 ==1.41.0
+- python >=3.10
+- python
+constrains:
+- numpy >=1.16.0
+- pyarrow >=7.0.0
+- fastexcel >=0.9
+- openpyxl >=3.0.0
+- xlsx2csv >=0.8.0
+- connectorx >=0.3.2
+- deltalake >=1.0.0
+- pyiceberg >=0.7.1
+- altair >=5.4.0
+- great_tables >=0.8.0
+- polars-runtime-32 ==1.41.0
+- polars-runtime-64 ==1.41.0
+- polars-runtime-compat ==1.41.0
+license: MIT
+size: 539656
+timestamp: 1779630790562
+- conda: https://conda.anaconda.org/conda-forge/linux-64/polars-runtime-32-1.41.0-py310h49dadd8_0.conda
+noarch: python
+sha256: e51ee3fe5259f2e115b2f78f8fbe3554e419c7c82b0c110878e12a5ff95ce3ab
+md5: 7682765a1588e5ac887c99736d297c93
+depends:
+- python
+- __glibc >=2.17,<3.0.a0
+- libstdcxx >=14
+- libgcc >=14
+- _python_abi3_support 1.*
+- cpython >=3.10
+constrains:
+- __glibc >=2.17
+license: MIT
+size: 42578921
+timestamp: 1779630790562
+- conda: https://conda.anaconda.org/conda-forge/linux-64/polars-runtime-compat-1.41.0-py310hcbd6021_0.conda
+noarch: python
+sha256: 29c3831c92394af11d9f7d04882dda9479ffbb76a3d36ba155d52159d67805fa
+md5: cb0b620c9914a07a9022cb8b183ea9ee
+depends:
+- python
+- libstdcxx >=14
+- libgcc >=14
+- __glibc >=2.17,<3.0.a0
+- _python_abi3_support 1.*
+- cpython >=3.10
+constrains:
+- __glibc >=2.17
+license: MIT
+size: 41864944
+timestamp: 1779630722548
+- conda: https://conda.anaconda.org/conda-forge/linux-64/procps-ng-4.0.6-h18c060e_0.conda
+sha256: 4ce2e1ee31a6217998f78c31ce7dc0a3e0557d9238b51d49dd20c52d467a126d
+md5: f2c23a77b25efcad57d377b34bd84941
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+- ncurses >=6.5,<7.0a0
+license: GPL-2.0-or-later AND LGPL-2.0-or-later
+license_family: GPL
+size: 593603
+timestamp: 1769710381284
+- conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda
+sha256: 9c88f8c64590e9567c6c80823f0328e58d3b1efb0e1c539c0315ceca764e0973
+md5: b3c17d95b5a10c6e64a21fa17573e70e
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=13
+license: MIT
+license_family: MIT
+size: 8252
+timestamp: 1726802366959
+- conda: https://conda.anaconda.org/conda-forge/noarch/pyaml-env-1.2.2-pyhd8ed1ab_0.conda
+sha256: 58994e0d2ea8584cb399546e6f6896d771995e6121d1a7b6a2c9948388358932
+md5: e17be1016bcc3516827b836cd3e4d9dc
+depends:
+- python >=3.9
+- pyyaml >=5.0,<=7.0
+license: MIT
+license_family: MIT
+size: 14645
+timestamp: 1736766960536
+- conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.13.4-pyhcf101f3_0.conda
+sha256: 69700e31165df070e9716315e042196aa92525dae5deb5107785847ab9f4189f
+md5: 729843edafc0899b3348bd3f19525b9d
+depends:
+- typing-inspection >=0.4.2
+- typing_extensions >=4.14.1
+- python >=3.10
+- annotated-types >=0.6.0
+- pydantic-core ==2.46.4
+- python
+license: MIT
+license_family: MIT
+size: 346511
+timestamp: 1778103405862
+- conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.46.4-py314h2e6c369_0.conda
+sha256: 802e216c39f1359aed60823b6e11d8ccd812b0ae1c81ae5ac1c81f99446409ab
+md5: 0c96993dbeadf3a277cf757b9f1c9412
+depends:
+- python
+- typing-extensions >=4.6.0,!=4.7.0
+- libgcc >=14
+- __glibc >=2.17,<3.0.a0
+- python_abi 3.14.* *_cp314
+constrains:
+- __glibc >=2.17
+license: MIT
+license_family: MIT
+size: 1895020
+timestamp: 1778084229247
+- conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda
+sha256: cf70b2f5ad9ae472b71235e5c8a736c9316df3705746de419b59d442e8348e86
+md5: 16c18772b340887160c79a6acc022db0
+depends:
+- python >=3.10
+license: BSD-2-Clause
+license_family: BSD
+size: 893031
+timestamp: 1774796815820
+- conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda
+sha256: ba3b032fa52709ce0d9fd388f63d330a026754587a2f461117cac9ab73d8d0d8
+md5: 461219d1a5bd61342293efa2c0c90eac
+depends:
+- __unix
+- python >=3.9
+license: BSD-3-Clause
+license_family: BSD
+size: 21085
+timestamp: 1733217331982
+- conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.14.5-habeac84_100_cp314.conda
+build_number: 100
+sha256: 55eed9bf2a3f6e90311276f0834737fe7c2d9ec3e5e2e557507858df4c7521e6
+md5: da92e59ff92f2d5ede4f612af20f583f
+depends:
+- __glibc >=2.17,<3.0.a0
+- bzip2 >=1.0.8,<2.0a0
+- ld_impl_linux-64 >=2.36.1
+- libexpat >=2.8.0,<3.0a0
+- libffi >=3.5.2,<3.6.0a0
+- libgcc >=14
+- liblzma >=5.8.3,<6.0a0
+- libmpdec >=4.0.0,<5.0a0
+- libsqlite >=3.53.1,<4.0a0
+- libuuid >=2.42.1,<3.0a0
+- libzlib >=1.3.2,<2.0a0
+- ncurses >=6.6,<7.0a0
+- openssl >=3.5.6,<4.0a0
+- python_abi 3.14.* *_cp314
+- readline >=8.3,<9.0a0
+- tk >=8.6.13,<8.7.0a0
+- tzdata
+- zstd >=1.5.7,<1.6.0a0
+license: Python-2.0
+size: 36745188
+timestamp: 1779236923603
+python_site_packages_path: lib/python3.14/site-packages
+- conda: https://conda.anaconda.org/conda-forge/noarch/python-dotenv-1.2.2-pyhcf101f3_0.conda
+sha256: 74e417a768f59f02a242c25e7db0aa796627b5bc8c818863b57786072aeb85e5
+md5: 130584ad9f3a513cdd71b1fdc1244e9c
+depends:
+- python >=3.10
+license: BSD-3-Clause
+license_family: BSD
+size: 27848
+timestamp: 1772388605021
+- conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.14.5-h4df99d1_100.conda
+sha256: 41dd7da285d71d519257fa7dacb1cae060d5ebfaa5f92cba5994899d2978e943
+md5: 41954747ba952ec4b01e16c2c9e8d8ff
+depends:
+- cpython 3.14.5.*
+- python_abi * *_cp314
+license: Python-2.0
+size: 50212
+timestamp: 1779236703009
+- conda: https://conda.anaconda.org/conda-forge/noarch/python-kaleido-0.2.1-pyhd8ed1ab_0.tar.bz2
+sha256: e17bf63a30aec33432f1ead86e15e9febde9fc40a7f869c0e766be8d2db44170
+md5: 310259a5b03ff02289d7705f39e2b1d2
+depends:
+- kaleido-core 0.2.1.*
+- python >=3.5
+license: MIT
+license_family: MIT
+size: 18320
+timestamp: 1615204747600
+- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda
+build_number: 8
+sha256: ad6d2e9ac39751cc0529dd1566a26751a0bf2542adb0c232533d32e176e21db5
+md5: 0539938c55b6b1a59b560e843ad864a4
+constrains:
+- python 3.14.* *_cp314
+license: BSD-3-Clause
+license_family: BSD
+size: 6989
+timestamp: 1752805904792
+- conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py314h67df5f8_1.conda
+sha256: b318fb070c7a1f89980ef124b80a0b5ccf3928143708a85e0053cde0169c699d
+md5: 2035f68f96be30dc60a5dfd7452c7941
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+- python >=3.14,<3.15.0a0
+- python_abi 3.14.* *_cp314
+- yaml >=0.2.5,<0.3.0a0
+license: MIT
+license_family: MIT
+size: 202391
+timestamp: 1770223462836
+- conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda
+sha256: 12ffde5a6f958e285aa22c191ca01bbd3d6e710aa852e00618fa6ddc59149002
+md5: d7d95fc8287ea7bf33e0e7116d2b95ec
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+- ncurses >=6.5,<7.0a0
+license: GPL-3.0-only
+license_family: GPL
+size: 345073
+timestamp: 1765813471974
+- conda: https://conda.anaconda.org/conda-forge/noarch/referencing-0.37.0-pyhcf101f3_0.conda
+sha256: 0577eedfb347ff94d0f2fa6c052c502989b028216996b45c7f21236f25864414
+md5: 870293df500ca7e18bedefa5838a22ab
+depends:
+- attrs >=22.2.0
+- python >=3.10
+- rpds-py >=0.7.0
+- typing_extensions >=4.4.0
+- python
+license: MIT
+license_family: MIT
+size: 51788
+timestamp: 1760379115194
+- conda: https://conda.anaconda.org/conda-forge/linux-64/regex-2026.5.9-py314h5bd0f2a_0.conda
+sha256: c7a4aca4977c15c82d053b06cbc676460974c1b25757cfeea8a9a2497ac911f8
+md5: 9dd235b6ac69a0198080dac39f9891aa
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+- python >=3.14,<3.15.0a0
+- python_abi 3.14.* *_cp314
+license: Apache-2.0 AND CNRI-Python
+license_family: PSF
+size: 413611
+timestamp: 1778374155646
+- conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.34.2-pyhcf101f3_0.conda
+sha256: 1715246b19c9f85ee022933b4845f2fc14ac9184981b7b7d9b728bec8e9588da
+md5: 4a85203c1d80c1059086ae860836ffb9
+depends:
+- python >=3.10
+- certifi >=2023.5.7
+- charset-normalizer >=2,<4
+- idna >=2.5,<4
+- urllib3 >=1.26,<3
+- python
+constrains:
+- chardet >=3.0.2,<8
+license: Apache-2.0
+license_family: APACHE
+size: 68709
+timestamp: 1778851103479
+- conda: https://conda.anaconda.org/conda-forge/noarch/rich-15.0.0-pyhcf101f3_0.conda
+sha256: 3d6ba2c0fcdac3196ba2f0615b4104e532525ffa1335b50a2878be5ff488814a
+md5: 0242025a3c804966bf71aa04eee82f66
+depends:
+- markdown-it-py >=2.2.0
+- pygments >=2.13.0,<3.0.0
+- python >=3.10
+- typing_extensions >=4.0.0,<5.0.0
+- python
+license: MIT
+license_family: MIT
+size: 208577
+timestamp: 1775991661559
+- conda: https://conda.anaconda.org/conda-forge/noarch/rich-click-1.9.7-pyh8f84b5b_0.conda
+sha256: aa3fcb167321bae51998de2e94d199109c9024f25a5a063cb1c28d8f1af33436
+md5: 0c20a8ebcddb24a45da89d5e917e6cb9
+depends:
+- python >=3.10
+- rich >=12
+- click >=8
+- typing-extensions >=4
+- __unix
+- python
+license: MIT
+license_family: MIT
+size: 64356
+timestamp: 1769850479089
+- conda: https://conda.anaconda.org/conda-forge/linux-64/rpds-py-0.30.0-py314h2e6c369_0.conda
+sha256: e53b0cbf3b324eaa03ca1fe1a688fdf4ab42cea9c25270b0a7307d8aaaa4f446
+md5: c1c368b5437b0d1a68f372ccf01cb133
+depends:
+- python
+- libgcc >=14
+- __glibc >=2.17,<3.0.a0
+- python_abi 3.14.* *_cp314
+constrains:
+- __glibc >=2.17
+license: MIT
+license_family: MIT
+size: 376121
+timestamp: 1764543122774
+- conda: https://conda.anaconda.org/conda-forge/noarch/spectra-0.0.11-pyhd8ed1ab_2.conda
+sha256: 7c65782d2511738e62c70462e89d65da4fa54d5a7e47c46667bcd27a59f81876
+md5: 472239e4eb7b5a84bb96b3ed7e3a596a
+depends:
+- colormath >=3.0.0
+- python >=3.9
+license: MIT
+license_family: MIT
+size: 22284
+timestamp: 1735770589188
+- conda: https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.53.1-hbc0de68_0.conda
+sha256: d167fa92781bcdcd3b9aaa6bb1cd50c5b108f6190c170098a118b5cf5df2f881
+md5: 8e0b8654ead18e50af552e54b5a08a61
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+- libsqlite 3.53.1 h0c1763c_0
+- libzlib >=1.3.2,<2.0a0
+- ncurses >=6.6,<7.0a0
+- readline >=8.3,<9.0a0
+license: blessing
+size: 205399
+timestamp: 1777986477546
+- conda: https://conda.anaconda.org/conda-forge/linux-64/tiktoken-0.12.0-py314h67fec18_3.conda
+sha256: 7e395d67fd249d901beb1ae269057763c0d8c3ee5f7a348694bdb16d158a37d9
+md5: d705f9d8a1185a2b01cced191177a028
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+- libstdcxx >=14
+- python >=3.14,<3.15.0a0
+- python_abi 3.14.* *_cp314
+- regex >=2022.1.18
+- requests >=2.26.0
+constrains:
+- __glibc >=2.17
+license: MIT
+license_family: MIT
+size: 939648
+timestamp: 1764028306357
+- conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda
+sha256: cafeec44494f842ffeca27e9c8b0c27ed714f93ac77ddadc6aaf726b5554ebac
+md5: cffd3bdd58090148f4cfcd831f4b26ab
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+- libzlib >=1.3.1,<2.0a0
+constrains:
+- xorg-libx11 >=1.8.12,<2.0a0
+license: TCL
+license_family: BSD
+size: 3301196
+timestamp: 1769460227866
+- conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda
+sha256: 9ef8e47cf00e4d6dcc114eb32a1504cc18206300572ef14d76634ba29dfe1eb6
+md5: e5ce43272193b38c2e9037446c1d9206
+depends:
+- python >=3.10
+- __unix
+- python
+license: MPL-2.0 and MIT
+size: 94132
+timestamp: 1770153424136
+- conda: https://conda.anaconda.org/conda-forge/noarch/typeguard-4.5.2-pyhcf101f3_0.conda
+sha256: 59d7851d32fddb5b510272e6557aa982edeb927d349648dac27f5bf01d18bb26
+md5: 4460f039b7dedf15f7df086446ca75ae
+depends:
+- typing_extensions >=4.14.0
+- python >=3.10
+- importlib-metadata >=3.6
+- python
+constrains:
+- pytest >=7
+license: MIT
+license_family: MIT
+size: 38297
+timestamp: 1778779291237
+- conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda
+sha256: 7c2df5721c742c2a47b2c8f960e718c930031663ac1174da67c1ed5999f7938c
+md5: edd329d7d3a4ab45dcf905899a7a6115
+depends:
+- typing_extensions ==4.15.0 pyhcf101f3_0
+license: PSF-2.0
+license_family: PSF
+size: 91383
+timestamp: 1756220668932
+- conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.2-pyhcf101f3_2.conda
+sha256: 8b90d2f19f9458b8c58a55e1fcdc1d90c1603a847a47654d8a454549413ba60a
+md5: 53f5409c5cfd6c5a66417d68e3f0a864
+depends:
+- python >=3.10
+- typing_extensions >=4.12.0
+- python
+license: MIT
+license_family: MIT
+size: 20935
+timestamp: 1777105465795
+- conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda
+sha256: 032271135bca55aeb156cee361c81350c6f3fb203f57d024d7e5a1fc9ef18731
+md5: 0caa1af407ecff61170c9437a808404d
+depends:
+- python >=3.10
+- python
+license: PSF-2.0
+license_family: PSF
+size: 51692
+timestamp: 1756220668932
+- conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda
+sha256: 1d30098909076af33a35017eed6f2953af1c769e273a0626a04722ac4acaba3c
+md5: ad659d0a2b3e47e38d829aa8cad2d610
+license: LicenseRef-Public-Domain
+size: 119135
+timestamp: 1767016325805
+- conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.7.0-pyhd8ed1ab_0.conda
+sha256: feff959a816f7988a0893201aa9727bbb7ee1e9cec2c4f0428269b489eb93fb4
+md5: cbb88288f74dbe6ada1c6c7d0a97223e
+depends:
+- backports.zstd >=1.0.0
+- brotli-python >=1.2.0
+- h2 >=4,<5
+- pysocks >=1.5.6,<2.0,!=1.5.7
+- python >=3.10
+license: MIT
+license_family: MIT
+size: 103560
+timestamp: 1778188657149
+- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.12-hb03c661_1.conda
+sha256: 6bc6ab7a90a5d8ac94c7e300cc10beb0500eeba4b99822768ca2f2ef356f731b
+md5: b2895afaf55bf96a8c8282a2e47a5de0
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+license: MIT
+license_family: MIT
+size: 15321
+timestamp: 1762976464266
+- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb03c661_1.conda
+sha256: 25d255fb2eef929d21ff660a0c687d38a6d2ccfbcbf0cc6aa738b12af6e9d142
+md5: 1dafce8548e38671bea82e3f5c6ce22f
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+license: MIT
+license_family: MIT
+size: 20591
+timestamp: 1762976546182
+- conda: https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h280c20c_3.conda
+sha256: 6d9ea2f731e284e9316d95fa61869fe7bbba33df7929f82693c121022810f4ad
+md5: a77f85f77be52ff59391544bfe73390a
+depends:
+- libgcc >=14
+- __glibc >=2.17,<3.0.a0
+license: MIT
+license_family: MIT
+size: 85189
+timestamp: 1753484064210
+- conda: https://conda.anaconda.org/conda-forge/noarch/zipp-4.1.0-pyhcf101f3_0.conda
+sha256: 210bd31c22bb88f5e2a167df24c95bb5f152b2ada7502f9b8c49d1f5366db423
+md5: ba3dcdc8584155c97c648ae9c044b7a3
+depends:
+- python >=3.10
+- python
+license: MIT
+license_family: MIT
+size: 24190
+timestamp: 1779159948016
+- conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-ng-2.3.3-hceb46e0_1.conda
+sha256: ea4e50c465d70236408cb0bfe0115609fd14db1adcd8bd30d8918e0291f8a75f
+md5: 2aadb0d17215603a82a2a6b0afd9a4cb
+depends:
+- __glibc >=2.17,<3.0.a0
+- libgcc >=14
+- libstdcxx >=14
+license: Zlib
+license_family: Other
+size: 122618
+timestamp: 1770167931827
+- conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda
+sha256: 68f0206ca6e98fea941e5717cec780ed2873ffabc0e1ed34428c061e2c6268c7
+md5: 4a13eeac0b5c8e5b8ab496e6c4ddd829
+depends:
+- __glibc >=2.17,<3.0.a0
+- libzlib >=1.3.1,<2.0a0
+license: BSD-3-Clause
+license_family: BSD
+size: 601375
+timestamp: 1764777111296
diff --git a/modules/nf-core/multiqc/.conda-lock/linux_arm64-bd-5c84a5000a226ab5_1.txt b/modules/nf-core/multiqc/.conda-lock/linux_arm64-bd-5c84a5000a226ab5_1.txt
new file mode 100644
index 0000000..3d5b93d
--- /dev/null
+++ b/modules/nf-core/multiqc/.conda-lock/linux_arm64-bd-5c84a5000a226ab5_1.txt
@@ -0,0 +1,1476 @@
+
+version: 6
+environments:
+default:
+channels:
+- url: https://conda.anaconda.org/conda-forge/
+- url: https://conda.anaconda.org/bioconda/
+- url: https://conda.anaconda.org/bioconda/
+options:
+pypi-prerelease-mode: if-necessary-or-explicit
+packages:
+linux-aarch64:
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/_openmp_mutex-4.5-20_gnu.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.7.0-pyhd8ed1ab_1.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/attrs-26.1.0-pyhcf101f3_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/backports.zstd-1.5.0-py314h680f03e_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/brotli-python-1.2.0-py314h352cb57_1.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/bzip2-1.0.8-h4777abc_9.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.5.20-pyhd8ed1ab_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.7-pyhd8ed1ab_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/click-8.4.0-pyhc90fa1f_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/coloredlogs-15.0.1-pyhd8ed1ab_4.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/colormath-3.0.0-pyhd8ed1ab_4.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.14.5-py314hd8ed1ab_100.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/expat-2.8.1-hfae3067_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2
+- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2
+- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2
+- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/fontconfig-2.18.0-hba86a56_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/humanfriendly-10.0-pyh707e725_8.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/humanize-4.15.0-pyhd8ed1ab_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.15-pyhcf101f3_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-9.0.0-pyhcf101f3_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.6-pyhcf101f3_1.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/jsonschema-4.26.0-pyhcf101f3_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/jsonschema-specifications-2025.9.1-pyhcf101f3_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/kaleido-core-0.2.1-he5a581e_0.tar.bz2
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lcms2-2.19.1-h9d5b58d_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ld_impl_linux-aarch64-2.45.1-default_h1979696_102.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lerc-4.1.0-h52b7260_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libblas-3.11.0-7_haddc8a3_openblas.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libcblas-3.11.0-7_hd72aa62_openblas.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libdeflate-1.25-h1af38f5_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libexpat-2.8.1-hfae3067_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libffi-3.5.2-h376a255_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libfreetype-2.14.3-h8af1aa0_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libfreetype6-2.14.3-hdae7a39_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-15.2.0-h8acb6b2_19.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-ng-15.2.0-he9431aa_19.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran-15.2.0-he9431aa_19.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran5-15.2.0-h1b7bec0_19.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgomp-15.2.0-h8acb6b2_19.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libjpeg-turbo-3.1.4.1-he30d5cf_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblapack-3.11.0-7_h88aeb00_openblas.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblzma-5.8.3-he30d5cf_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmpdec-4.0.0-he30d5cf_1.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libopenblas-0.3.33-pthreads_h9d3fd7e_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libpng-1.6.58-h1abf092_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libsqlite-3.53.1-h022381a_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libstdcxx-15.2.0-hef695bb_19.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libtiff-4.7.1-hdb009f0_1.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libuuid-2.42.1-h1022ec0_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libwebp-base-1.6.0-ha2e29f5_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxcb-1.17.0-h262b8f6_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libzlib-1.3.2-hdc9db2a_2.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-3.10.2-pyhcf101f3_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.2.0-pyhd8ed1ab_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/markupsafe-3.0.3-py314hb76de3f_1.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/mathjax-2.7.7-h8af1aa0_3.tar.bz2
+- conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda
+- conda: https://conda.anaconda.org/bioconda/noarch/multiqc-1.35-pyhdfd78af_1.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.21.2-pyhcf101f3_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/natsort-8.4.0-pyhcf101f3_2.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ncurses-6.6-hf8d1292_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/nspr-4.38-h3ad9384_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/nss-3.118-h544fa81_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/numpy-2.4.6-py314he1698a1_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openjpeg-2.5.4-h5da879a_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openssl-3.6.2-h546c87b_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pillow-12.2.0-py314hac3e5ec_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/plotly-6.6.0-pyhd8ed1ab_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.41.0-pyh58ad624_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/polars-runtime-32-1.41.0-py310h32c7c23_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/polars-runtime-compat-1.41.0-py310hc0e61be_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/procps-ng-4.0.6-h1779866_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pthread-stubs-0.4-h86ecc28_1002.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/pyaml-env-1.2.2-pyhd8ed1ab_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.13.4-pyhcf101f3_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pydantic-core-2.46.4-py314h451b6cc_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-3.14.5-hfd9ac0a_100_cp314.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/python-dotenv-1.2.2-pyhcf101f3_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.14.5-h4df99d1_100.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/python-kaleido-0.2.1-pyhd8ed1ab_0.tar.bz2
+- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pyyaml-6.0.3-py314h807365f_1.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/readline-8.3-hb682ff5_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/referencing-0.37.0-pyhcf101f3_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/regex-2026.5.9-py314h51f160d_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.34.2-pyhcf101f3_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/rich-15.0.0-pyhcf101f3_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/rich-click-1.9.7-pyh8f84b5b_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/rpds-py-0.30.0-py314h02b7a91_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/spectra-0.0.11-pyhd8ed1ab_2.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/sqlite-3.53.1-he8854b5_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/tiktoken-0.12.0-py314h6a36e60_3.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/tk-8.6.13-noxft_h0dc03b3_103.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/typeguard-4.5.2-pyhcf101f3_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.2-pyhcf101f3_2.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.7.0-pyhd8ed1ab_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxau-1.0.12-he30d5cf_1.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxdmcp-1.1.5-he30d5cf_1.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/yaml-0.2.5-h80f16a2_3.conda
+- conda: https://conda.anaconda.org/conda-forge/noarch/zipp-4.1.0-pyhcf101f3_0.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zlib-ng-2.3.3-ha7cb516_1.conda
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstd-1.5.7-h85ac4a6_6.conda
+packages:
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/_openmp_mutex-4.5-20_gnu.conda
+build_number: 20
+sha256: a2527b1d81792a0ccd2c05850960df119c2b6d8f5fdec97f2db7d25dc23b1068
+md5: 468fd3bb9e1f671d36c2cbc677e56f1d
+depends:
+- libgomp >=7.5.0
+constrains:
+- openmp_impl <0.0a0
+license: BSD-3-Clause
+license_family: BSD
+size: 28926
+timestamp: 1770939656741
+- conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda
+sha256: a3967b937b9abf0f2a99f3173fa4630293979bd1644709d89580e7c62a544661
+md5: aaa2a381ccc56eac91d63b6c1240312f
+depends:
+- cpython
+- python-gil
+license: MIT
+license_family: MIT
+size: 8191
+timestamp: 1744137672556
+- conda: https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.7.0-pyhd8ed1ab_1.conda
+sha256: e0ea1ba78fbb64f17062601edda82097fcf815012cf52bb704150a2668110d48
+md5: 2934f256a8acfe48f6ebb4fce6cde29c
+depends:
+- python >=3.9
+- typing-extensions >=4.0.0
+license: MIT
+license_family: MIT
+size: 18074
+timestamp: 1733247158254
+- conda: https://conda.anaconda.org/conda-forge/noarch/attrs-26.1.0-pyhcf101f3_0.conda
+sha256: 1b6124230bb4e571b1b9401537ecff575b7b109cc3a21ee019f65e083b8399ab
+md5: c6b0543676ecb1fb2d7643941fe375f2
+depends:
+- python >=3.10
+- python
+license: MIT
+license_family: MIT
+size: 64927
+timestamp: 1773935801332
+- conda: https://conda.anaconda.org/conda-forge/noarch/backports.zstd-1.5.0-py314h680f03e_0.conda
+noarch: generic
+sha256: a1c97297e867776760489537bc5ae36fa83a154be30e3b79385a39ca4cb058fe
+md5: 1133126d840e75287d83947be3fc3e71
+depends:
+- python >=3.14
+license: BSD-3-Clause AND MIT AND EPL-2.0
+size: 7533
+timestamp: 1778594057496
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/brotli-python-1.2.0-py314h352cb57_1.conda
+sha256: 5a5b0cdcd7ed89c6a8fb830924967f6314a2b71944bc1ebc2c105781ba97aa75
+md5: a1b5c571a0923a205d663d8678df4792
+depends:
+- libgcc >=14
+- libstdcxx >=14
+- python >=3.14,<3.15.0a0
+- python >=3.14,<3.15.0a0 *_cp314
+- python_abi 3.14.* *_cp314
+constrains:
+- libbrotlicommon 1.2.0 he30d5cf_1
+license: MIT
+license_family: MIT
+size: 373193
+timestamp: 1764017486851
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/bzip2-1.0.8-h4777abc_9.conda
+sha256: b3495077889dde6bb370938e7db82be545c73e8589696ad0843a32221520ad4c
+md5: 840d8fc0d7b3209be93080bc20e07f2d
+depends:
+- libgcc >=14
+license: bzip2-1.0.6
+license_family: BSD
+size: 192412
+timestamp: 1771350241232
+- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda
+sha256: 9812a303a1395e1dafbd92e5bc8a1ff6013bcbba0a09c7f03a8d23e43560aa9b
+md5: 489b8e97e666c93f68fdb35c3c9b957f
+depends:
+- __unix
+license: ISC
+size: 129868
+timestamp: 1779289852439
+- conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.5.20-pyhd8ed1ab_0.conda
+sha256: 645655a3510e38e625da136595f3f16f2130c3263630cc3bc8f60f619ddbe490
+md5: 9fefff2f745ea1cc2ef15211a20c054a
+depends:
+- python >=3.10
+license: ISC
+size: 134201
+timestamp: 1779285131141
+- conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.7-pyhd8ed1ab_0.conda
+sha256: 3f9483d62ce24ecd063f8a5a714448445dc8d9e201147c46699fc0033e824457
+md5: a9167b9571f3baa9d448faa2139d1089
+depends:
+- python >=3.10
+license: MIT
+license_family: MIT
+size: 58872
+timestamp: 1775127203018
+- conda: https://conda.anaconda.org/conda-forge/noarch/click-8.4.0-pyhc90fa1f_0.conda
+sha256: 99ab8ef815c4520cce3a7482c2513f377c14348206857661d84c76a55e030f97
+md5: 003767c47f1f0a474c4de268b57839c3
+depends:
+- __unix
+- python
+- python >=3.10
+license: BSD-3-Clause
+license_family: BSD
+size: 104631
+timestamp: 1779108494556
+- conda: https://conda.anaconda.org/conda-forge/noarch/coloredlogs-15.0.1-pyhd8ed1ab_4.conda
+sha256: 8021c76eeadbdd5784b881b165242db9449783e12ce26d6234060026fd6a8680
+md5: b866ff7007b934d564961066c8195983
+depends:
+- humanfriendly >=9.1
+- python >=3.9
+license: MIT
+license_family: MIT
+size: 43758
+timestamp: 1733928076798
+- conda: https://conda.anaconda.org/conda-forge/noarch/colormath-3.0.0-pyhd8ed1ab_4.conda
+sha256: 59c9e29800b483b390467f90e82b0da3a4fbf0612efe1c90813fca232780e160
+md5: 071cf7b0ce333c81718b054066c15102
+depends:
+- networkx >=2.0
+- numpy
+- python >=3.9
+license: BSD-3-Clause
+license_family: BSD
+size: 39326
+timestamp: 1735759976140
+- conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.14.5-py314hd8ed1ab_100.conda
+noarch: generic
+sha256: 777882d2685f368417f31bbe1b28f73687fc6c8f6a5768bda20ffeefa6b07f5b
+md5: a749029ce5d0632a913db19d17f944ab
+depends:
+- python >=3.14,<3.15.0a0
+- python_abi * *_cp314
+license: Python-2.0
+size: 50212
+timestamp: 1779236682725
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/expat-2.8.1-hfae3067_0.conda
+sha256: a9cd5eb1700e11cc39acc36630a2d72a4e317943bd7c5695cd8804419f04ff42
+md5: 89f0247b3cea528d8ad1a6664a313153
+depends:
+- libexpat 2.8.1 hfae3067_0
+- libgcc >=14
+license: MIT
+license_family: MIT
+size: 140114
+timestamp: 1779278679081
+- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2
+sha256: 58d7f40d2940dd0a8aa28651239adbf5613254df0f75789919c4e6762054403b
+md5: 0c96522c6bdaed4b1566d11387caaf45
+license: BSD-3-Clause
+license_family: BSD
+size: 397370
+timestamp: 1566932522327
+- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2
+sha256: c52a29fdac682c20d252facc50f01e7c2e7ceac52aa9817aaf0bb83f7559ec5c
+md5: 34893075a5c9e55cdafac56607368fc6
+license: OFL-1.1
+license_family: Other
+size: 96530
+timestamp: 1620479909603
+- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2
+sha256: 00925c8c055a2275614b4d983e1df637245e19058d79fc7dd1a93b8d9fb4b139
+md5: 4d59c254e01d9cde7957100457e2d5fb
+license: OFL-1.1
+license_family: Other
+size: 700814
+timestamp: 1620479612257
+- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda
+sha256: 2821ec1dc454bd8b9a31d0ed22a7ce22422c0aef163c59f49dfdf915d0f0ca14
+md5: 49023d73832ef61042f6a237cb2687e7
+license: LicenseRef-Ubuntu-Font-Licence-Version-1.0
+license_family: Other
+size: 1620504
+timestamp: 1727511233259
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/fontconfig-2.18.0-hba86a56_0.conda
+sha256: 1805f4ab3d9e1734a5a17abccc2cb0fdade51d4d5f29bdc410600ea0115ec050
+md5: b660d59a9d0fb3297327418624acaec3
+depends:
+- libexpat >=2.8.1,<3.0a0
+- libfreetype >=2.14.3
+- libfreetype6 >=2.14.3
+- libgcc >=14
+- libuuid >=2.42.1,<3.0a0
+- libzlib >=1.3.2,<2.0a0
+license: MIT
+license_family: MIT
+size: 293348
+timestamp: 1779421661332
+- conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda
+sha256: 54eea8469786bc2291cc40bca5f46438d3e062a399e8f53f013b6a9f50e98333
+md5: a7970cd949a077b7cb9696379d338681
+depends:
+- font-ttf-ubuntu
+- font-ttf-inconsolata
+- font-ttf-dejavu-sans-mono
+- font-ttf-source-code-pro
+license: BSD-3-Clause
+license_family: BSD
+size: 4059
+timestamp: 1762351264405
+- conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda
+sha256: 84c64443368f84b600bfecc529a1194a3b14c3656ee2e832d15a20e0329b6da3
+md5: 164fc43f0b53b6e3a7bc7dce5e4f1dc9
+depends:
+- python >=3.10
+- hyperframe >=6.1,<7
+- hpack >=4.1,<5
+- python
+license: MIT
+license_family: MIT
+size: 95967
+timestamp: 1756364871835
+- conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda
+sha256: 6ad78a180576c706aabeb5b4c8ceb97c0cb25f1e112d76495bff23e3779948ba
+md5: 0a802cb9888dd14eeefc611f05c40b6e
+depends:
+- python >=3.9
+license: MIT
+license_family: MIT
+size: 30731
+timestamp: 1737618390337
+- conda: https://conda.anaconda.org/conda-forge/noarch/humanfriendly-10.0-pyh707e725_8.conda
+sha256: fa2071da7fab758c669e78227e6094f6b3608228740808a6de5d6bce83d9e52d
+md5: 7fe569c10905402ed47024fc481bb371
+depends:
+- __unix
+- python >=3.9
+license: MIT
+license_family: MIT
+size: 73563
+timestamp: 1733928021866
+- conda: https://conda.anaconda.org/conda-forge/noarch/humanize-4.15.0-pyhd8ed1ab_0.conda
+sha256: 6c4343b376d0b12a4c75ab992640970d36c933cad1fd924f6a1181fa91710e80
+md5: daddf757c3ecd6067b9af1df1f25d89e
+depends:
+- python >=3.10
+license: MIT
+license_family: MIT
+size: 67994
+timestamp: 1766267728652
+- conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda
+sha256: 77af6f5fe8b62ca07d09ac60127a30d9069fdc3c68d6b256754d0ffb1f7779f8
+md5: 8e6923fc12f1fe8f8c4e5c9f343256ac
+depends:
+- python >=3.9
+license: MIT
+license_family: MIT
+size: 17397
+timestamp: 1737618427549
+- conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.15-pyhcf101f3_0.conda
+sha256: 3d25f9f6f7ab3e1ce6429fc8c8aae0335cf446692e715068488536d220cc43de
+md5: 1b9083b7f00609605d1483dbc6071a81
+depends:
+- python >=3.10
+- python
+license: BSD-3-Clause
+license_family: BSD
+size: 62642
+timestamp: 1779294335905
+- conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-9.0.0-pyhcf101f3_0.conda
+sha256: 43e2a5497cad1598ff88a3e69f69bc88b7b8f141fa63c60eab5db296317318b8
+md5: ffc17e785d64e12fc311af9184221839
+depends:
+- python >=3.10
+- zipp >=3.20
+- python
+license: Apache-2.0
+size: 34766
+timestamp: 1779714582554
+- conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.6-pyhcf101f3_1.conda
+sha256: fc9ca7348a4f25fed2079f2153ecdcf5f9cf2a0bc36c4172420ca09e1849df7b
+md5: 04558c96691bed63104678757beb4f8d
+depends:
+- markupsafe >=2.0
+- python >=3.10
+- python
+license: BSD-3-Clause
+license_family: BSD
+size: 120685
+timestamp: 1764517220861
+- conda: https://conda.anaconda.org/conda-forge/noarch/jsonschema-4.26.0-pyhcf101f3_0.conda
+sha256: db973a37d75db8e19b5f44bbbdaead0c68dde745407f281e2a7fe4db74ec51d7
+md5: ada41c863af263cc4c5fcbaff7c3e4dc
+depends:
+- attrs >=22.2.0
+- jsonschema-specifications >=2023.3.6
+- python >=3.10
+- referencing >=0.28.4
+- rpds-py >=0.25.0
+- python
+license: MIT
+license_family: MIT
+size: 82356
+timestamp: 1767839954256
+- conda: https://conda.anaconda.org/conda-forge/noarch/jsonschema-specifications-2025.9.1-pyhcf101f3_0.conda
+sha256: 0a4f3b132f0faca10c89fdf3b60e15abb62ded6fa80aebfc007d05965192aa04
+md5: 439cd0f567d697b20a8f45cb70a1005a
+depends:
+- python >=3.10
+- referencing >=0.31.0
+- python
+license: MIT
+license_family: MIT
+size: 19236
+timestamp: 1757335715225
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/kaleido-core-0.2.1-he5a581e_0.tar.bz2
+sha256: d3c7f4797566e6f983d16c2a87063a18e4b2d819a66230190a21584d70042755
+md5: 4f0d284f5d11e04277b552eb1c172c7f
+depends:
+- __glibc >=2.17,<3.0.a0
+- expat >=2.2.10,<3.0.0a0
+- fontconfig
+- fonts-conda-forge
+- libgcc-ng >=9.3.0
+- mathjax 2.7.*
+- nspr >=4.29,<5.0a0
+- nss >=3.62,<4.0a0
+- sqlite >=3.34.0,<4.0a0
+license: MIT
+license_family: MIT
+size: 65750397
+timestamp: 1615199465742
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lcms2-2.19.1-h9d5b58d_0.conda
+sha256: 1e5f68e4b36a0e1a278c6dc026bc3d7775518a15832cbc9d7fc1c0e4c47784b1
+md5: b1f8bee3c53a6d2c103fb4a1ae44f5c4
+depends:
+- libgcc >=14
+- libjpeg-turbo >=3.1.4.1,<4.0a0
+- libtiff >=4.7.1,<4.8.0a0
+license: MIT
+license_family: MIT
+size: 296899
+timestamp: 1778079402392
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ld_impl_linux-aarch64-2.45.1-default_h1979696_102.conda
+sha256: 7abd913d81a9bf00abb699e8987966baa2065f5132e37e815f92d90fc6bba530
+md5: a21644fc4a83da26452a718dc9468d5f
+depends:
+- zstd >=1.5.7,<1.6.0a0
+constrains:
+- binutils_impl_linux-aarch64 2.45.1
+license: GPL-3.0-only
+license_family: GPL
+size: 875596
+timestamp: 1774197520746
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lerc-4.1.0-h52b7260_0.conda
+sha256: 8957fd460c1c132c8031f65fd5f56ec3807fd71b7cab2c5e2b0937b13404ab36
+md5: d13423b06447113a90b5b1366d4da171
+depends:
+- libgcc >=14
+- libstdcxx >=14
+license: Apache-2.0
+license_family: Apache
+size: 240444
+timestamp: 1773114901155
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libblas-3.11.0-7_haddc8a3_openblas.conda
+build_number: 7
+sha256: f27ba323c2f1e1731b5e880fe520f178f55047f25be94f77e649605b2343c066
+md5: e8d07b777f6ff1fab69665336561910b
+depends:
+- libopenblas >=0.3.33,<0.3.34.0a0
+- libopenblas >=0.3.33,<1.0a0
+constrains:
+- liblapack 3.11.0 7*_openblas
+- libcblas 3.11.0 7*_openblas
+- mkl <2027
+- blas 2.307 openblas
+- liblapacke 3.11.0 7*_openblas
+license: BSD-3-Clause
+license_family: BSD
+size: 18696
+timestamp: 1778489796402
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libcblas-3.11.0-7_hd72aa62_openblas.conda
+build_number: 7
+sha256: c8f0192362966df0828419f042d6f94c079e5df00ad6bd05b5e84c12b42f8cc7
+md5: 90ac57b82c055faa9be25031864b7d8f
+depends:
+- libblas 3.11.0 7_haddc8a3_openblas
+constrains:
+- liblapack 3.11.0 7*_openblas
+- blas 2.307 openblas
+- liblapacke 3.11.0 7*_openblas
+license: BSD-3-Clause
+license_family: BSD
+size: 18664
+timestamp: 1778489802790
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libdeflate-1.25-h1af38f5_0.conda
+sha256: 48814b73bd462da6eed2e697e30c060ae16af21e9fbed30d64feaf0aad9da392
+md5: a9138815598fe6b91a1d6782ca657b0c
+depends:
+- libgcc >=14
+license: MIT
+license_family: MIT
+size: 71117
+timestamp: 1761979776756
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libexpat-2.8.1-hfae3067_0.conda
+sha256: 1fc392b997c6ee2bd3226a7cd870d0edbcbb367e25f9f18dd4a7025fced6efc0
+md5: 513dd884361dfb8a554298ed69b58823
+depends:
+- libgcc >=14
+constrains:
+- expat 2.8.1.*
+license: MIT
+license_family: MIT
+size: 77140
+timestamp: 1779278671302
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libffi-3.5.2-h376a255_0.conda
+sha256: 3df4c539449aabc3443bbe8c492c01d401eea894603087fca2917aa4e1c2dea9
+md5: 2f364feefb6a7c00423e80dcb12db62a
+depends:
+- libgcc >=14
+license: MIT
+license_family: MIT
+size: 55952
+timestamp: 1769456078358
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libfreetype-2.14.3-h8af1aa0_0.conda
+sha256: 752e4f66283d7deb4c6fd47d88df644d8daa2aaa825a54f3bf350a625190192a
+md5: a229e22d4d8814a07702b0919d8e6701
+depends:
+- libfreetype6 >=2.14.3
+license: GPL-2.0-only OR FTL
+size: 8125
+timestamp: 1774301094057
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libfreetype6-2.14.3-hdae7a39_0.conda
+sha256: 8e6b27fe4eec4c2fa7b7769a21973734c8dba1de80086fb0213e58375ac09f4c
+md5: b99ed99e42dafb27889483b3098cace7
+depends:
+- libgcc >=14
+- libpng >=1.6.55,<1.7.0a0
+- libzlib >=1.3.2,<2.0a0
+constrains:
+- freetype >=2.14.3
+license: GPL-2.0-only OR FTL
+size: 422941
+timestamp: 1774301093473
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-15.2.0-h8acb6b2_19.conda
+sha256: 4592b096e553f67799ae70d4b6167eeda3ec74587d68c7aecbf4e7b1df136681
+md5: f35b3f52d0a2ec4ffe3c89ba135cdb9a
+depends:
+- _openmp_mutex >=4.5
+constrains:
+- libgomp 15.2.0 h8acb6b2_19
+- libgcc-ng ==15.2.0=*_19
+license: GPL-3.0-only WITH GCC-exception-3.1
+license_family: GPL
+size: 622462
+timestamp: 1778268755949
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-ng-15.2.0-he9431aa_19.conda
+sha256: 1137f93f477f56199ded24117430045a0c02cbe8b10031beac3b9ad2138539d3
+md5: 770cf892e5530f43e63cadc673e85653
+depends:
+- libgcc 15.2.0 h8acb6b2_19
+license: GPL-3.0-only WITH GCC-exception-3.1
+license_family: GPL
+size: 27738
+timestamp: 1778268759211
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran-15.2.0-he9431aa_19.conda
+sha256: e5ad94be72634233510b33ba792a3339921bd468f0b8bc6961ea05eded251d9b
+md5: c7a5b5decf969ead5ecada83654164cf
+depends:
+- libgfortran5 15.2.0 h1b7bec0_19
+constrains:
+- libgfortran-ng ==15.2.0=*_19
+license: GPL-3.0-only WITH GCC-exception-3.1
+license_family: GPL
+size: 27728
+timestamp: 1778268784621
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran5-15.2.0-h1b7bec0_19.conda
+sha256: af8e9bdcaa77f133a8ee4c1ef57ef564d9c45aa262abf9f5ef9b50eb99d96407
+md5: 779dbb494de6d3d6477cab52eb34285a
+depends:
+- libgcc >=15.2.0
+constrains:
+- libgfortran 15.2.0
+license: GPL-3.0-only WITH GCC-exception-3.1
+license_family: GPL
+size: 1487244
+timestamp: 1778268767295
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgomp-15.2.0-h8acb6b2_19.conda
+sha256: 2370ef0ffcbae5bede3c4bf136add4abc257245eb91f724c99bb4a43116c5a83
+md5: c5e8a379c4a2ec2aea4ba22758c001d9
+license: GPL-3.0-only WITH GCC-exception-3.1
+license_family: GPL
+size: 587387
+timestamp: 1778268674393
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libjpeg-turbo-3.1.4.1-he30d5cf_0.conda
+sha256: e97ec2af5f09f8f6ea8ecd550055c95ae80fae22015fcfadaa94eafe025c9ccc
+md5: a85ba48648f6868016f2741fd9170250
+depends:
+- libgcc >=14
+constrains:
+- jpeg <0.0.0a
+license: IJG AND BSD-3-Clause AND Zlib
+size: 693143
+timestamp: 1775962625956
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblapack-3.11.0-7_h88aeb00_openblas.conda
+build_number: 7
+sha256: 20b38a0156200ac65f597bf0a93914c565435f2cc58b1042581854231a99ac35
+md5: 5899cbd743cc74fd655c1ed2af7120f3
+depends:
+- libblas 3.11.0 7_haddc8a3_openblas
+constrains:
+- libcblas 3.11.0 7*_openblas
+- blas 2.307 openblas
+- liblapacke 3.11.0 7*_openblas
+license: BSD-3-Clause
+license_family: BSD
+size: 18685
+timestamp: 1778489809140
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblzma-5.8.3-he30d5cf_0.conda
+sha256: d61962b9cd54c3554361550203c64d5b65b71e3058a285b66e4b04b9769f0a5c
+md5: 76298a9e6d71ee6e832a8d0d7373b261
+depends:
+- libgcc >=14
+constrains:
+- xz 5.8.3.*
+license: 0BSD
+size: 126102
+timestamp: 1775828008518
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmpdec-4.0.0-he30d5cf_1.conda
+sha256: 57c0dd12d506e84541c4e877898bd2a59cca141df493d34036f18b2751e0a453
+md5: 7b9813e885482e3ccb1fa212b86d7fd0
+depends:
+- libgcc >=14
+license: BSD-2-Clause
+license_family: BSD
+size: 114056
+timestamp: 1769482343003
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libopenblas-0.3.33-pthreads_h9d3fd7e_0.conda
+sha256: b018ecfb05e75a8eea3f21f6b5c5c2a54b5178bdcf19e2e2df2735740214a8c8
+md5: 58a66cd95e9692f08abe89f55a6f3f12
+depends:
+- libgcc >=14
+- libgfortran
+- libgfortran5 >=14.3.0
+constrains:
+- openblas >=0.3.33,<0.3.34.0a0
+license: BSD-3-Clause
+license_family: BSD
+size: 5121336
+timestamp: 1776993423004
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libpng-1.6.58-h1abf092_0.conda
+sha256: 483eaa53da40a6a3e558709d9f7b1ca388735364ae21a1ba58cf942514649c92
+md5: f51503ac45a4888bce71af9027a2ecc9
+depends:
+- libgcc >=14
+- libzlib >=1.3.2,<2.0a0
+license: zlib-acknowledgement
+size: 341202
+timestamp: 1776315188425
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libsqlite-3.53.1-h022381a_0.conda
+sha256: ad03b7d8e4d08001f0df88ee7a56108bb35bae4795a42b9a04cc1abfa822bd07
+md5: 2ec1119217d8f0d086e9a62f3cb0e5ea
+depends:
+- libgcc >=14
+- libzlib >=1.3.2,<2.0a0
+license: blessing
+size: 955361
+timestamp: 1777986487553
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libstdcxx-15.2.0-hef695bb_19.conda
+sha256: 1dadc45e599f510dd5f97141dddcdbb9844d9f1430c1f3a38075cf1c58f87b4e
+md5: 543fbc8d71f2a0baf04cf88ce96cb8bb
+depends:
+- libgcc 15.2.0 h8acb6b2_19
+constrains:
+- libstdcxx-ng ==15.2.0=*_19
+license: GPL-3.0-only WITH GCC-exception-3.1
+license_family: GPL
+size: 5546559
+timestamp: 1778268777463
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libtiff-4.7.1-hdb009f0_1.conda
+sha256: 7ff79470db39e803e21b8185bc8f19c460666d5557b1378d1b1e857d929c6b39
+md5: 8c6fd84f9c87ac00636007c6131e457d
+depends:
+- lerc >=4.0.0,<5.0a0
+- libdeflate >=1.25,<1.26.0a0
+- libgcc >=14
+- libjpeg-turbo >=3.1.0,<4.0a0
+- liblzma >=5.8.1,<6.0a0
+- libstdcxx >=14
+- libwebp-base >=1.6.0,<2.0a0
+- libzlib >=1.3.1,<2.0a0
+- zstd >=1.5.7,<1.6.0a0
+license: HPND
+size: 488407
+timestamp: 1762022048105
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libuuid-2.42.1-h1022ec0_0.conda
+sha256: 1628839b062e98b2192857d4da8496ac9ac6b0dbb77aa040c34efc9192c440ee
+md5: 0f42f9fedd2a32d798de95a7f65c456f
+depends:
+- libgcc >=14
+license: BSD-3-Clause
+license_family: BSD
+size: 43453
+timestamp: 1779118526838
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libwebp-base-1.6.0-ha2e29f5_0.conda
+sha256: b03700a1f741554e8e5712f9b06dd67e76f5301292958cd3cb1ac8c6fdd9ed25
+md5: 24e92d0942c799db387f5c9d7b81f1af
+depends:
+- libgcc >=14
+constrains:
+- libwebp 1.6.0
+license: BSD-3-Clause
+license_family: BSD
+size: 359496
+timestamp: 1752160685488
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxcb-1.17.0-h262b8f6_0.conda
+sha256: 461cab3d5650ac6db73a367de5c8eca50363966e862dcf60181d693236b1ae7b
+md5: cd14ee5cca2464a425b1dbfc24d90db2
+depends:
+- libgcc >=13
+- pthread-stubs
+- xorg-libxau >=1.0.11,<2.0a0
+- xorg-libxdmcp
+license: MIT
+license_family: MIT
+size: 397493
+timestamp: 1727280745441
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libzlib-1.3.2-hdc9db2a_2.conda
+sha256: eb111e32e5a7313a5bf799c7fb2419051fa2fe7eff74769fac8d5a448b309f7f
+md5: 502006882cf5461adced436e410046d1
+constrains:
+- zlib 1.3.2 *_2
+license: Zlib
+license_family: Other
+size: 69833
+timestamp: 1774072605429
+- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-3.10.2-pyhcf101f3_0.conda
+sha256: 20e0892592a3e7c683e3d66df704a9425d731486a97c34fc56af4da1106b2b6b
+md5: ba0a9221ce1063f31692c07370d062f3
+depends:
+- importlib-metadata >=4.4
+- python >=3.10
+- python
+license: BSD-3-Clause
+license_family: BSD
+size: 85893
+timestamp: 1770694658918
+- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.2.0-pyhd8ed1ab_0.conda
+sha256: 0c4c35376fe920714390d46e4b8d31c876d65f18e1655899e0763ec25f2a902f
+md5: 6d03368f2b2b0a5fb6839df53b2eb5e0
+depends:
+- mdurl >=0.1,<1
+- python >=3.10
+license: MIT
+license_family: MIT
+size: 69017
+timestamp: 1778169663339
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/markupsafe-3.0.3-py314hb76de3f_1.conda
+sha256: 383c188496d13a55658c06e61e7d4cdff2c9f9d5a0648769fca8250bece7e0ef
+md5: e5de3c36dd548b35ff2a8aa49208dcb3
+depends:
+- libgcc >=14
+- python >=3.14,<3.15.0a0
+- python_abi 3.14.* *_cp314
+constrains:
+- jinja2 >=3.0.0
+license: BSD-3-Clause
+license_family: BSD
+size: 27913
+timestamp: 1772446407659
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/mathjax-2.7.7-h8af1aa0_3.tar.bz2
+sha256: 8fd4c79d6eda3d4cba73783114305a53a154ada4d1e334d4e02cb3521429599b
+md5: 7b08314a6867a9d5648a1c3265e9eb8e
+license: Apache-2.0
+license_family: Apache
+size: 22257008
+timestamp: 1662784555011
+- conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda
+sha256: 78c1bbe1723449c52b7a9df1af2ee5f005209f67e40b6e1d3c7619127c43b1c7
+md5: 592132998493b3ff25fd7479396e8351
+depends:
+- python >=3.9
+license: MIT
+license_family: MIT
+size: 14465
+timestamp: 1733255681319
+- conda: https://conda.anaconda.org/bioconda/noarch/multiqc-1.35-pyhdfd78af_1.conda
+sha256: e86033aa55a9e915e2d0957e770bdb81e3feb26a227d1adb17f9d6c528da6a71
+md5: cdb20309681ba3ce8f52c110e214d4f3
+depends:
+- click
+- coloredlogs
+- humanize
+- importlib-metadata
+- jinja2 >=3.0.0
+- jsonschema
+- markdown
+- natsort
+- numpy
+- packaging
+- pillow >=10.2.0
+- plotly >=5.18
+- polars >=1.34.0
+- polars-runtime-compat >=1.34.0
+- pyaml-env
+- pydantic >=2.7.1
+- python >=3.9,!=3.14.1
+- python-dotenv
+- python-kaleido 0.2.1
+- pyyaml >=4
+- requests
+- rich >=10
+- rich-click
+- spectra >=0.0.10
+- tiktoken
+- tqdm
+- typeguard >=4
+license: GPL-3.0-or-later
+license_family: GPL3
+size: 4282188
+timestamp: 1779465338806
+- conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.21.2-pyhcf101f3_0.conda
+sha256: 70f43d62450927d51673eecd8823e14f5b3cfebdb43cda1d502eba97162bab42
+md5: 6687827c332121727ce383919e1ec8c2
+depends:
+- python >=3.10
+- python
+license: MIT
+license_family: MIT
+size: 284323
+timestamp: 1778929680962
+- conda: https://conda.anaconda.org/conda-forge/noarch/natsort-8.4.0-pyhcf101f3_2.conda
+sha256: aeb1548eb72e4f198e72f19d242fb695b35add2ac7b2c00e0d83687052867680
+md5: e941e85e273121222580723010bd4fa2
+depends:
+- python >=3.9
+- python
+license: MIT
+license_family: MIT
+size: 39262
+timestamp: 1770905275632
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ncurses-6.6-hf8d1292_0.conda
+sha256: 369db85c5cd8d99dde364ce70725d76511d9c8199e5b820c740414091bf5bcca
+md5: b2a43456aa56fe80c2477a5094899eff
+depends:
+- libgcc >=14
+license: X11 AND BSD-3-Clause
+size: 960036
+timestamp: 1777422174534
+- conda: https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda
+sha256: f6a82172afc50e54741f6f84527ef10424326611503c64e359e25a19a8e4c1c6
+md5: a2c1eeadae7a309daed9d62c96012a2b
+depends:
+- python >=3.11
+- python
+constrains:
+- numpy >=1.25
+- scipy >=1.11.2
+- matplotlib-base >=3.8
+- pandas >=2.0
+license: BSD-3-Clause
+license_family: BSD
+size: 1587439
+timestamp: 1765215107045
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/nspr-4.38-h3ad9384_0.conda
+sha256: 78a06e89285fef242e272998b292c1e621e3ee3dd4fba62ec014e503c7ec118f
+md5: 6dd4f07147774bf720075a210f8026b9
+depends:
+- libgcc >=14
+- libstdcxx >=14
+license: MPL-2.0
+license_family: MOZILLA
+size: 235140
+timestamp: 1762350120355
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/nss-3.118-h544fa81_0.conda
+sha256: 48942696889367ffd448f8dccfc080fb7e130b9938a4a3b6b20ef8e6af856463
+md5: 4540f9570d12db2150f42ba036154552
+depends:
+- libgcc >=14
+- libsqlite >=3.51.0,<4.0a0
+- libstdcxx >=14
+- libzlib >=1.3.1,<2.0a0
+- nspr >=4.38,<5.0a0
+license: MPL-2.0
+license_family: MOZILLA
+size: 2061869
+timestamp: 1763490303490
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/numpy-2.4.6-py314he1698a1_0.conda
+sha256: 04af718b911f8a3a0095481c7e283aa081a175fe626eccbc2c5644bcb2aba9a1
+md5: 8b173772deea177b45d2a133b509b3f7
+depends:
+- python
+- libstdcxx >=14
+- libgcc >=14
+- python_abi 3.14.* *_cp314
+- libblas >=3.9.0,<4.0a0
+- liblapack >=3.9.0,<4.0a0
+- libcblas >=3.9.0,<4.0a0
+constrains:
+- numpy-base <0a0
+license: BSD-3-Clause
+license_family: BSD
+size: 8002900
+timestamp: 1779169206742
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openjpeg-2.5.4-h5da879a_0.conda
+sha256: bd1bc8bdde5e6c5cbac42d462b939694e40b59be6d0698f668515908640c77b8
+md5: cea962410e327262346d48d01f05936c
+depends:
+- libgcc >=14
+- libpng >=1.6.50,<1.7.0a0
+- libstdcxx >=14
+- libtiff >=4.7.1,<4.8.0a0
+- libzlib >=1.3.1,<2.0a0
+license: BSD-2-Clause
+license_family: BSD
+size: 392636
+timestamp: 1758489353577
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openssl-3.6.2-h546c87b_0.conda
+sha256: 348cb74c1530ac241215d047ef65d134cf797af935c97a68655319362b7e6a01
+md5: 3b129669089e4d6a5c6871dbb4669b99
+depends:
+- ca-certificates
+- libgcc >=14
+license: Apache-2.0
+license_family: Apache
+size: 3706406
+timestamp: 1775589602258
+- conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda
+sha256: 3906abfb6511a3bb309e39b9b1b7bc38f50a723971de2395489fd1f379255890
+md5: 4c06a92e74452cfa53623a81592e8934
+depends:
+- python >=3.8
+- python
+license: Apache-2.0
+license_family: APACHE
+size: 91574
+timestamp: 1777103621679
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pillow-12.2.0-py314hac3e5ec_0.conda
+sha256: 96b26c2657275ffe84ab510edf0865e21999d791485d12794edd4a71b837beb6
+md5: 87d58d103b47c4a8567b3d7666647684
+depends:
+- python
+- libgcc >=14
+- python 3.14.* *_cp314
+- openjpeg >=2.5.4,<3.0a0
+- libxcb >=1.17.0,<2.0a0
+- libwebp-base >=1.6.0,<2.0a0
+- zlib-ng >=2.3.3,<2.4.0a0
+- python_abi 3.14.* *_cp314
+- lcms2 >=2.18,<3.0a0
+- tk >=8.6.13,<8.7.0a0
+- libtiff >=4.7.1,<4.8.0a0
+- libjpeg-turbo >=3.1.2,<4.0a0
+- libfreetype >=2.14.3
+- libfreetype6 >=2.14.3
+license: HPND
+size: 1062080
+timestamp: 1775060067775
+- conda: https://conda.anaconda.org/conda-forge/noarch/plotly-6.6.0-pyhd8ed1ab_0.conda
+sha256: c418d325359fc7a0074cea7f081ef1bce26e114d2da8a0154c5d27ecc87a08e7
+md5: 3e9427ee186846052e81fadde8ebe96a
+depends:
+- narwhals >=1.15.1
+- packaging
+- python >=3.10
+constrains:
+- ipywidgets >=7.6
+license: MIT
+license_family: MIT
+size: 5251872
+timestamp: 1772628857717
+- conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.41.0-pyh58ad624_0.conda
+sha256: 70fc56877c4a095ee658d61924d8019768fbae4a48437058d181fc94b0a7c4d8
+md5: 25a883fed9f1f3f21ff317a3e7c92ac4
+depends:
+- polars-runtime-32 ==1.41.0
+- python >=3.10
+- python
+constrains:
+- numpy >=1.16.0
+- pyarrow >=7.0.0
+- fastexcel >=0.9
+- openpyxl >=3.0.0
+- xlsx2csv >=0.8.0
+- connectorx >=0.3.2
+- deltalake >=1.0.0
+- pyiceberg >=0.7.1
+- altair >=5.4.0
+- great_tables >=0.8.0
+- polars-runtime-32 ==1.41.0
+- polars-runtime-64 ==1.41.0
+- polars-runtime-compat ==1.41.0
+license: MIT
+size: 539656
+timestamp: 1779630790562
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/polars-runtime-32-1.41.0-py310h32c7c23_0.conda
+noarch: python
+sha256: d903b774ec09189e164207328aac157eee82fed8cc5c9ace46aeb5d1c15cb5b3
+md5: 8c08c506ed1ea8ce0ca37af5e918c58d
+depends:
+- python
+- libgcc >=14
+- libstdcxx >=14
+- _python_abi3_support 1.*
+- cpython >=3.10
+constrains:
+- __glibc >=2.17
+license: MIT
+size: 38704429
+timestamp: 1779630794932
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/polars-runtime-compat-1.41.0-py310hc0e61be_0.conda
+noarch: python
+sha256: 101696adff43a654146376c62ef9611bf7946b95fa46f604fe247d77eefc6267
+md5: 65b73e4260677ee5162bdbb252e28e06
+depends:
+- python
+- libstdcxx >=14
+- libgcc >=14
+- _python_abi3_support 1.*
+- cpython >=3.10
+constrains:
+- __glibc >=2.17
+license: MIT
+size: 38651498
+timestamp: 1779630714016
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/procps-ng-4.0.6-h1779866_0.conda
+sha256: e9cbcbc94e151ada3d6dc365380aaaf591f65012c16d9a2abaea4b9b90adc402
+md5: ab7288cc39545556d1bc5e71ab2df9a9
+depends:
+- libgcc >=14
+- ncurses >=6.5,<7.0a0
+license: GPL-2.0-or-later AND LGPL-2.0-or-later
+license_family: GPL
+size: 636733
+timestamp: 1769712412683
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pthread-stubs-0.4-h86ecc28_1002.conda
+sha256: 977dfb0cb3935d748521dd80262fe7169ab82920afd38ed14b7fee2ea5ec01ba
+md5: bb5a90c93e3bac3d5690acf76b4a6386
+depends:
+- libgcc >=13
+license: MIT
+license_family: MIT
+size: 8342
+timestamp: 1726803319942
+- conda: https://conda.anaconda.org/conda-forge/noarch/pyaml-env-1.2.2-pyhd8ed1ab_0.conda
+sha256: 58994e0d2ea8584cb399546e6f6896d771995e6121d1a7b6a2c9948388358932
+md5: e17be1016bcc3516827b836cd3e4d9dc
+depends:
+- python >=3.9
+- pyyaml >=5.0,<=7.0
+license: MIT
+license_family: MIT
+size: 14645
+timestamp: 1736766960536
+- conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.13.4-pyhcf101f3_0.conda
+sha256: 69700e31165df070e9716315e042196aa92525dae5deb5107785847ab9f4189f
+md5: 729843edafc0899b3348bd3f19525b9d
+depends:
+- typing-inspection >=0.4.2
+- typing_extensions >=4.14.1
+- python >=3.10
+- annotated-types >=0.6.0
+- pydantic-core ==2.46.4
+- python
+license: MIT
+license_family: MIT
+size: 346511
+timestamp: 1778103405862
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pydantic-core-2.46.4-py314h451b6cc_0.conda
+sha256: 1a7c6b18e404c13c4d959888ecb48a9ed9de0e41be2872932b83a35278088df0
+md5: 9c3ace6aba6df14b943256095ac1281e
+depends:
+- python
+- typing-extensions >=4.6.0,!=4.7.0
+- libgcc >=14
+- python 3.14.* *_cp314
+- python_abi 3.14.* *_cp314
+constrains:
+- __glibc >=2.17
+license: MIT
+license_family: MIT
+size: 1780773
+timestamp: 1778084251775
+- conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda
+sha256: cf70b2f5ad9ae472b71235e5c8a736c9316df3705746de419b59d442e8348e86
+md5: 16c18772b340887160c79a6acc022db0
+depends:
+- python >=3.10
+license: BSD-2-Clause
+license_family: BSD
+size: 893031
+timestamp: 1774796815820
+- conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda
+sha256: ba3b032fa52709ce0d9fd388f63d330a026754587a2f461117cac9ab73d8d0d8
+md5: 461219d1a5bd61342293efa2c0c90eac
+depends:
+- __unix
+- python >=3.9
+license: BSD-3-Clause
+license_family: BSD
+size: 21085
+timestamp: 1733217331982
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-3.14.5-hfd9ac0a_100_cp314.conda
+build_number: 100
+sha256: d37bad5447365346166c72950ea8f49689aa49cecc1b0623d00458427627b8df
+md5: d956e09feb806f5974675ce92ad81d45
+depends:
+- bzip2 >=1.0.8,<2.0a0
+- ld_impl_linux-aarch64 >=2.36.1
+- libexpat >=2.8.0,<3.0a0
+- libffi >=3.5.2,<3.6.0a0
+- libgcc >=14
+- liblzma >=5.8.3,<6.0a0
+- libmpdec >=4.0.0,<5.0a0
+- libsqlite >=3.53.1,<4.0a0
+- libuuid >=2.42.1,<3.0a0
+- libzlib >=1.3.2,<2.0a0
+- ncurses >=6.6,<7.0a0
+- openssl >=3.5.6,<4.0a0
+- python_abi 3.14.* *_cp314
+- readline >=8.3,<9.0a0
+- tk >=8.6.13,<8.7.0a0
+- tzdata
+- zstd >=1.5.7,<1.6.0a0
+license: Python-2.0
+size: 37510439
+timestamp: 1779236267040
+python_site_packages_path: lib/python3.14/site-packages
+- conda: https://conda.anaconda.org/conda-forge/noarch/python-dotenv-1.2.2-pyhcf101f3_0.conda
+sha256: 74e417a768f59f02a242c25e7db0aa796627b5bc8c818863b57786072aeb85e5
+md5: 130584ad9f3a513cdd71b1fdc1244e9c
+depends:
+- python >=3.10
+license: BSD-3-Clause
+license_family: BSD
+size: 27848
+timestamp: 1772388605021
+- conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.14.5-h4df99d1_100.conda
+sha256: 41dd7da285d71d519257fa7dacb1cae060d5ebfaa5f92cba5994899d2978e943
+md5: 41954747ba952ec4b01e16c2c9e8d8ff
+depends:
+- cpython 3.14.5.*
+- python_abi * *_cp314
+license: Python-2.0
+size: 50212
+timestamp: 1779236703009
+- conda: https://conda.anaconda.org/conda-forge/noarch/python-kaleido-0.2.1-pyhd8ed1ab_0.tar.bz2
+sha256: e17bf63a30aec33432f1ead86e15e9febde9fc40a7f869c0e766be8d2db44170
+md5: 310259a5b03ff02289d7705f39e2b1d2
+depends:
+- kaleido-core 0.2.1.*
+- python >=3.5
+license: MIT
+license_family: MIT
+size: 18320
+timestamp: 1615204747600
+- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda
+build_number: 8
+sha256: ad6d2e9ac39751cc0529dd1566a26751a0bf2542adb0c232533d32e176e21db5
+md5: 0539938c55b6b1a59b560e843ad864a4
+constrains:
+- python 3.14.* *_cp314
+license: BSD-3-Clause
+license_family: BSD
+size: 6989
+timestamp: 1752805904792
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pyyaml-6.0.3-py314h807365f_1.conda
+sha256: 496b5e65dfdd0aaaaa5de0dcaaf3bceea00fcb4398acf152f89e567c82ec1046
+md5: 9ae2c92975118058bd720e9ba2bb7c58
+depends:
+- libgcc >=14
+- python >=3.14,<3.15.0a0
+- python >=3.14,<3.15.0a0 *_cp314
+- python_abi 3.14.* *_cp314
+- yaml >=0.2.5,<0.3.0a0
+license: MIT
+license_family: MIT
+size: 195678
+timestamp: 1770223441816
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/readline-8.3-hb682ff5_0.conda
+sha256: fe695f9d215e9a2e3dd0ca7f56435ab4df24f5504b83865e3d295df36e88d216
+md5: 3d49cad61f829f4f0e0611547a9cda12
+depends:
+- libgcc >=14
+- ncurses >=6.5,<7.0a0
+license: GPL-3.0-only
+license_family: GPL
+size: 357597
+timestamp: 1765815673644
+- conda: https://conda.anaconda.org/conda-forge/noarch/referencing-0.37.0-pyhcf101f3_0.conda
+sha256: 0577eedfb347ff94d0f2fa6c052c502989b028216996b45c7f21236f25864414
+md5: 870293df500ca7e18bedefa5838a22ab
+depends:
+- attrs >=22.2.0
+- python >=3.10
+- rpds-py >=0.7.0
+- typing_extensions >=4.4.0
+- python
+license: MIT
+license_family: MIT
+size: 51788
+timestamp: 1760379115194
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/regex-2026.5.9-py314h51f160d_0.conda
+sha256: 05ef55f09f31eabd0a205f6b065e13fc746675f41924620977692ef0ffe5aad8
+md5: 34ed7bc9febeca70f55b757ca09c354d
+depends:
+- libgcc >=14
+- python >=3.14,<3.15.0a0
+- python >=3.14,<3.15.0a0 *_cp314
+- python_abi 3.14.* *_cp314
+license: Apache-2.0 AND CNRI-Python
+license_family: PSF
+size: 409780
+timestamp: 1778374195988
+- conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.34.2-pyhcf101f3_0.conda
+sha256: 1715246b19c9f85ee022933b4845f2fc14ac9184981b7b7d9b728bec8e9588da
+md5: 4a85203c1d80c1059086ae860836ffb9
+depends:
+- python >=3.10
+- certifi >=2023.5.7
+- charset-normalizer >=2,<4
+- idna >=2.5,<4
+- urllib3 >=1.26,<3
+- python
+constrains:
+- chardet >=3.0.2,<8
+license: Apache-2.0
+license_family: APACHE
+size: 68709
+timestamp: 1778851103479
+- conda: https://conda.anaconda.org/conda-forge/noarch/rich-15.0.0-pyhcf101f3_0.conda
+sha256: 3d6ba2c0fcdac3196ba2f0615b4104e532525ffa1335b50a2878be5ff488814a
+md5: 0242025a3c804966bf71aa04eee82f66
+depends:
+- markdown-it-py >=2.2.0
+- pygments >=2.13.0,<3.0.0
+- python >=3.10
+- typing_extensions >=4.0.0,<5.0.0
+- python
+license: MIT
+license_family: MIT
+size: 208577
+timestamp: 1775991661559
+- conda: https://conda.anaconda.org/conda-forge/noarch/rich-click-1.9.7-pyh8f84b5b_0.conda
+sha256: aa3fcb167321bae51998de2e94d199109c9024f25a5a063cb1c28d8f1af33436
+md5: 0c20a8ebcddb24a45da89d5e917e6cb9
+depends:
+- python >=3.10
+- rich >=12
+- click >=8
+- typing-extensions >=4
+- __unix
+- python
+license: MIT
+license_family: MIT
+size: 64356
+timestamp: 1769850479089
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/rpds-py-0.30.0-py314h02b7a91_0.conda
+sha256: a587240f16eac7c6a80f9585cef679cd1cb9a287b8dfcdd36dcef1f7e7db15dc
+md5: e7f6ed9e60043bb5cbcc527764897f0d
+depends:
+- python
+- libgcc >=14
+- python_abi 3.14.* *_cp314
+constrains:
+- __glibc >=2.17
+license: MIT
+license_family: MIT
+size: 376332
+timestamp: 1764543345455
+- conda: https://conda.anaconda.org/conda-forge/noarch/spectra-0.0.11-pyhd8ed1ab_2.conda
+sha256: 7c65782d2511738e62c70462e89d65da4fa54d5a7e47c46667bcd27a59f81876
+md5: 472239e4eb7b5a84bb96b3ed7e3a596a
+depends:
+- colormath >=3.0.0
+- python >=3.9
+license: MIT
+license_family: MIT
+size: 22284
+timestamp: 1735770589188
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/sqlite-3.53.1-he8854b5_0.conda
+sha256: 27467e4bfb0681546f149718c33b806fec078185fbaa6a4d17d440bc8f56185c
+md5: 46009bdca2315a99e0a3a7d0ba1af3b9
+depends:
+- libgcc >=14
+- libsqlite 3.53.1 h022381a_0
+- libzlib >=1.3.2,<2.0a0
+- ncurses >=6.6,<7.0a0
+- readline >=8.3,<9.0a0
+license: blessing
+size: 209964
+timestamp: 1777986493350
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/tiktoken-0.12.0-py314h6a36e60_3.conda
+sha256: c1da41c79262b27efa168407cfecc47b20270e5fc071a8307f95a2c85fb94170
+md5: 55bf7b559202236157b14323b40f19e6
+depends:
+- libgcc >=14
+- libstdcxx >=14
+- python >=3.14,<3.15.0a0
+- python_abi 3.14.* *_cp314
+- regex >=2022.1.18
+- requests >=2.26.0
+constrains:
+- __glibc >=2.17
+license: MIT
+license_family: MIT
+size: 914402
+timestamp: 1764030357702
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/tk-8.6.13-noxft_h0dc03b3_103.conda
+sha256: e25c314b52764219f842b41aea2c98a059f06437392268f09b03561e4f6e5309
+md5: 7fc6affb9b01e567d2ef1d05b84aa6ed
+depends:
+- libgcc >=14
+- libzlib >=1.3.1,<2.0a0
+constrains:
+- xorg-libx11 >=1.8.12,<2.0a0
+license: TCL
+license_family: BSD
+size: 3368666
+timestamp: 1769464148928
+- conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda
+sha256: 9ef8e47cf00e4d6dcc114eb32a1504cc18206300572ef14d76634ba29dfe1eb6
+md5: e5ce43272193b38c2e9037446c1d9206
+depends:
+- python >=3.10
+- __unix
+- python
+license: MPL-2.0 and MIT
+size: 94132
+timestamp: 1770153424136
+- conda: https://conda.anaconda.org/conda-forge/noarch/typeguard-4.5.2-pyhcf101f3_0.conda
+sha256: 59d7851d32fddb5b510272e6557aa982edeb927d349648dac27f5bf01d18bb26
+md5: 4460f039b7dedf15f7df086446ca75ae
+depends:
+- typing_extensions >=4.14.0
+- python >=3.10
+- importlib-metadata >=3.6
+- python
+constrains:
+- pytest >=7
+license: MIT
+license_family: MIT
+size: 38297
+timestamp: 1778779291237
+- conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda
+sha256: 7c2df5721c742c2a47b2c8f960e718c930031663ac1174da67c1ed5999f7938c
+md5: edd329d7d3a4ab45dcf905899a7a6115
+depends:
+- typing_extensions ==4.15.0 pyhcf101f3_0
+license: PSF-2.0
+license_family: PSF
+size: 91383
+timestamp: 1756220668932
+- conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.2-pyhcf101f3_2.conda
+sha256: 8b90d2f19f9458b8c58a55e1fcdc1d90c1603a847a47654d8a454549413ba60a
+md5: 53f5409c5cfd6c5a66417d68e3f0a864
+depends:
+- python >=3.10
+- typing_extensions >=4.12.0
+- python
+license: MIT
+license_family: MIT
+size: 20935
+timestamp: 1777105465795
+- conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda
+sha256: 032271135bca55aeb156cee361c81350c6f3fb203f57d024d7e5a1fc9ef18731
+md5: 0caa1af407ecff61170c9437a808404d
+depends:
+- python >=3.10
+- python
+license: PSF-2.0
+license_family: PSF
+size: 51692
+timestamp: 1756220668932
+- conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda
+sha256: 1d30098909076af33a35017eed6f2953af1c769e273a0626a04722ac4acaba3c
+md5: ad659d0a2b3e47e38d829aa8cad2d610
+license: LicenseRef-Public-Domain
+size: 119135
+timestamp: 1767016325805
+- conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.7.0-pyhd8ed1ab_0.conda
+sha256: feff959a816f7988a0893201aa9727bbb7ee1e9cec2c4f0428269b489eb93fb4
+md5: cbb88288f74dbe6ada1c6c7d0a97223e
+depends:
+- backports.zstd >=1.0.0
+- brotli-python >=1.2.0
+- h2 >=4,<5
+- pysocks >=1.5.6,<2.0,!=1.5.7
+- python >=3.10
+license: MIT
+license_family: MIT
+size: 103560
+timestamp: 1778188657149
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxau-1.0.12-he30d5cf_1.conda
+sha256: e9f6e931feeb2f40e1fdbafe41d3b665f1ab6cb39c5880a1fcf9f79a3f3c84a5
+md5: 1c246e1105000c3660558459e2fd6d43
+depends:
+- libgcc >=14
+license: MIT
+license_family: MIT
+size: 16317
+timestamp: 1762977521691
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxdmcp-1.1.5-he30d5cf_1.conda
+sha256: 128d72f36bcc8d2b4cdbec07507542e437c7d67f677b7d77b71ed9eeac7d6df1
+md5: bff06dcde4a707339d66d45d96ceb2e2
+depends:
+- libgcc >=14
+license: MIT
+license_family: MIT
+size: 21039
+timestamp: 1762979038025
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/yaml-0.2.5-h80f16a2_3.conda
+sha256: 66265e943f32ce02396ad214e27cb35f5b0490b3bd4f064446390f9d67fa5d88
+md5: 032d8030e4a24fe1f72c74423a46fb88
+depends:
+- libgcc >=14
+license: MIT
+license_family: MIT
+size: 88088
+timestamp: 1753484092643
+- conda: https://conda.anaconda.org/conda-forge/noarch/zipp-4.1.0-pyhcf101f3_0.conda
+sha256: 210bd31c22bb88f5e2a167df24c95bb5f152b2ada7502f9b8c49d1f5366db423
+md5: ba3dcdc8584155c97c648ae9c044b7a3
+depends:
+- python >=3.10
+- python
+license: MIT
+license_family: MIT
+size: 24190
+timestamp: 1779159948016
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zlib-ng-2.3.3-ha7cb516_1.conda
+sha256: 638a3a41a4fbfed52d3c60c8ef5a3693b3f12a5b1a3f58fa29f5698d0a0702e2
+md5: f731af71c723065d91b4c01bb822641b
+depends:
+- libgcc >=14
+- libstdcxx >=14
+license: Zlib
+license_family: Other
+size: 121046
+timestamp: 1770167944449
+- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstd-1.5.7-h85ac4a6_6.conda
+sha256: 569990cf12e46f9df540275146da567d9c618c1e9c7a0bc9d9cfefadaed20b75
+md5: c3655f82dcea2aa179b291e7099c1fcc
+depends:
+- libzlib >=1.3.1,<2.0a0
+license: BSD-3-Clause
+license_family: BSD
+size: 614429
+timestamp: 1764777145593
diff --git a/modules/nf-core/multiqc/environment.yml b/modules/nf-core/multiqc/environment.yml
new file mode 100644
index 0000000..7a970e2
--- /dev/null
+++ b/modules/nf-core/multiqc/environment.yml
@@ -0,0 +1,7 @@
+---
+# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json
+channels:
+ - conda-forge
+ - bioconda
+dependencies:
+ - bioconda::multiqc=1.35
diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf
new file mode 100644
index 0000000..c4bc715
--- /dev/null
+++ b/modules/nf-core/multiqc/main.nf
@@ -0,0 +1,50 @@
+process MULTIQC {
+ tag "${meta.id}"
+ label 'process_single'
+
+ conda "${moduleDir}/environment.yml"
+ container "${workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container
+ ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/c8/c8e346f4f6080eadf1253505e6ff09ef004454fc18e8d672006fd7b222cc412e/data'
+ : 'community.wave.seqera.io/library/multiqc:1.35--c17fb751507e9dfc'}"
+
+ input:
+ tuple val(meta), path(multiqc_files, stageAs: "?/*"), path(multiqc_config, stageAs: "?/*"), path(multiqc_logo), path(replace_names), path(sample_names)
+
+ output:
+ tuple val(meta), path("*.html"), emit: report
+ tuple val(meta), path("*_data"), emit: data
+ tuple val(meta), path("*_plots"), emit: plots, optional: true
+ // MultiQC should not push its versions to the `versions` topic. Its input depends on the versions topic to be resolved thus outputting to the topic will let the pipeline hang forever
+ tuple val("${task.process}"), val('multiqc'), eval('multiqc --version | sed "s/.* //g"'), emit: versions
+
+ when:
+ task.ext.when == null || task.ext.when
+
+ script:
+ def args = task.ext.args ?: ''
+ def prefix = task.ext.prefix ? "--filename ${task.ext.prefix}.html" : ''
+ def config = multiqc_config ? multiqc_config instanceof List ? "--config ${multiqc_config.join(' --config ')}" : "--config ${multiqc_config}" : ""
+ def logo = multiqc_logo ? "--cl-config 'custom_logo: \"${multiqc_logo}\"'" : ''
+ def replace = replace_names ? "--replace-names ${replace_names}" : ''
+ def samples = sample_names ? "--sample-names ${sample_names}" : ''
+ """
+ multiqc \\
+ --force \\
+ ${args} \\
+ ${config} \\
+ ${prefix} \\
+ ${logo} \\
+ ${replace} \\
+ ${samples} \\
+ .
+ """
+
+ stub:
+ """
+ mkdir multiqc_data
+ touch multiqc_data/.stub
+ mkdir multiqc_plots
+ touch multiqc_plots/.stub
+ touch multiqc_report.html
+ """
+}
diff --git a/modules/nf-core/multiqc/meta.yml b/modules/nf-core/multiqc/meta.yml
new file mode 100644
index 0000000..27ce18d
--- /dev/null
+++ b/modules/nf-core/multiqc/meta.yml
@@ -0,0 +1,133 @@
+name: multiqc
+description: Aggregate results from bioinformatics analyses across many samples
+ into a single report
+keywords:
+ - QC
+ - bioinformatics tools
+ - Beautiful stand-alone HTML report
+tools:
+ - multiqc:
+ description: |
+ MultiQC searches a given directory for analysis logs and compiles a HTML report.
+ It's a general use tool, perfect for summarising the output from numerous bioinformatics tools.
+ homepage: https://multiqc.info/
+ documentation: https://multiqc.info/docs/
+ licence:
+ - "GPL-3.0-or-later"
+ identifier: biotools:multiqc
+input:
+ - - meta:
+ type: map
+ description: |
+ Groovy Map containing sample information
+ e.g. [ id:'sample1', single_end:false ]
+ - multiqc_files:
+ type: file
+ description: |
+ List of reports / files recognised by MultiQC, for example the html and zip output of FastQC
+ ontologies: []
+ - multiqc_config:
+ type: file
+ description: Optional config yml for MultiQC
+ pattern: "*.{yml,yaml}"
+ ontologies:
+ - edam: http://edamontology.org/format_3750
+ - multiqc_logo:
+ type: file
+ description: Optional logo file for MultiQC
+ pattern: "*.{png}"
+ ontologies: []
+ - replace_names:
+ type: file
+ description: |
+ Optional two-column sample renaming file. First column a set of
+ patterns, second column a set of corresponding replacements. Passed via
+ MultiQC's `--replace-names` option.
+ pattern: "*.{tsv}"
+ ontologies:
+ - edam: http://edamontology.org/format_3475
+ - sample_names:
+ type: file
+ description: |
+ Optional TSV file with headers, passed to the MultiQC --sample_names
+ argument.
+ pattern: "*.{tsv}"
+ ontologies:
+ - edam: http://edamontology.org/format_3475
+output:
+ report:
+ - - meta:
+ type: map
+ description: |
+ Groovy Map containing sample information
+ e.g. [ id:'sample1', single_end:false ]
+ - "*.html":
+ type: file
+ description: MultiQC report file
+ pattern: ".html"
+ ontologies: []
+ data:
+ - - meta:
+ type: map
+ description: |
+ Groovy Map containing sample information
+ e.g. [ id:'sample1', single_end:false ]
+ - "*_data":
+ type: directory
+ description: MultiQC data dir
+ pattern: "multiqc_data"
+ plots:
+ - - meta:
+ type: map
+ description: |
+ Groovy Map containing sample information
+ e.g. [ id:'sample1', single_end:false ]
+ - "*_plots":
+ type: file
+ description: Plots created by MultiQC
+ pattern: "*_plots"
+ ontologies: []
+ versions:
+ - - ${task.process}:
+ type: string
+ description: The process the versions were collected from
+ - multiqc:
+ type: string
+ description: The tool name
+ - multiqc --version | sed "s/.* //g":
+ type: eval
+ description: The expression to obtain the version of the tool
+authors:
+ - "@abhi18av"
+ - "@bunop"
+ - "@drpatelh"
+ - "@jfy133"
+maintainers:
+ - "@abhi18av"
+ - "@bunop"
+ - "@drpatelh"
+ - "@jfy133"
+containers:
+ conda:
+ linux/amd64:
+ lock_file: modules/nf-core/multiqc/.conda-lock/linux_amd64-bd-c17fb751507e9dfc_1.txt
+ linux/arm64:
+ lock_file: modules/nf-core/multiqc/.conda-lock/linux_arm64-bd-5c84a5000a226ab5_1.txt
+ docker:
+ linux/amd64:
+ name: community.wave.seqera.io/library/multiqc:1.35--c17fb751507e9dfc
+ build_id: bd-c17fb751507e9dfc_1
+ scan_id: sc-3b1b3932f9846892_1
+ linux/arm64:
+ name: community.wave.seqera.io/library/multiqc:1.35--5c84a5000a226ab5
+ build_id: bd-5c84a5000a226ab5_1
+ scan_id: sc-0d39df41e9737bbd_1
+ singularity:
+ linux/amd64:
+ name: oras://community.wave.seqera.io/library/multiqc:1.35--c680f2aea25ccec2
+ build_id: bd-c680f2aea25ccec2_1
+ https: https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/c8/c8e346f4f6080eadf1253505e6ff09ef004454fc18e8d672006fd7b222cc412e/data
+ linux/arm64:
+ name: oras://community.wave.seqera.io/library/multiqc:1.35--c0468833d65b2f81
+ build_id: bd-c0468833d65b2f81_1
+ https: https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/e4/e48aa28aebc881254a499b24c3e1ce77b8df1b85a5432699ed6f72eb17ac7fb5/data
diff --git a/modules/nf-core/multiqc/tests/custom_prefix.config b/modules/nf-core/multiqc/tests/custom_prefix.config
new file mode 100644
index 0000000..b30b135
--- /dev/null
+++ b/modules/nf-core/multiqc/tests/custom_prefix.config
@@ -0,0 +1,5 @@
+process {
+ withName: 'MULTIQC' {
+ ext.prefix = "custom_prefix"
+ }
+}
diff --git a/modules/nf-core/multiqc/tests/main.nf.test b/modules/nf-core/multiqc/tests/main.nf.test
new file mode 100644
index 0000000..4cbdb95
--- /dev/null
+++ b/modules/nf-core/multiqc/tests/main.nf.test
@@ -0,0 +1,211 @@
+nextflow_process {
+
+ name "Test Process MULTIQC"
+ script "../main.nf"
+ process "MULTIQC"
+
+ tag "modules"
+ tag "modules_nfcore"
+ tag "multiqc"
+
+ config "./nextflow.config"
+
+ test("sarscov2 single-end [fastqc]") {
+
+ when {
+ process {
+ """
+ input[0] = channel.of([
+ [ id: 'FASTQC' ],
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true),
+ [],
+ [],
+ [],
+ []
+ ])
+ """
+ }
+ }
+
+ then {
+ assert process.success
+ assert snapshot(
+ sanitizeOutput(process.out).collectEntries { key, val ->
+ if (key == "data") {
+ return [key, val.collect { [path(it[1]).list().collect { file(it.toString()).name }] }]
+ }
+ else if (key == "plots") {
+ return [key, val.collect { [
+ "pdf",
+ path("${it[1]}/pdf").list().collect { file(it.toString()).name },
+ "png",
+ path("${it[1]}/png").list().collect { file(it.toString()).name },
+ "svg",
+ path("${it[1]}/svg").list().collect { file(it.toString()).name }] }]
+ }
+ else if (key == "report") {
+ return [key, file(val[0][1].toString()).name]
+ }
+ return [key, val]
+ }
+ ).match()
+ }
+ }
+
+ test("sarscov2 single-end [fastqc] - custom prefix") {
+ config "./custom_prefix.config"
+
+ when {
+ process {
+ """
+ input[0] = channel.of([
+ [ id: 'FASTQC' ],
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true),
+ [],
+ [],
+ [],
+ []
+ ])
+ """
+ }
+ }
+
+ then {
+ assert process.success
+ assert snapshot(
+ sanitizeOutput(process.out).collectEntries { key, val ->
+ if (key == "data") {
+ return [key, val.collect { [path(it[1]).list().collect { file(it.toString()).name }] }]
+ }
+ else if (key == "plots") {
+ return [key, val.collect { [
+ "pdf",
+ path("${it[1]}/pdf").list().collect { file(it.toString()).name },
+ "png",
+ path("${it[1]}/png").list().collect { file(it.toString()).name },
+ "svg",
+ path("${it[1]}/svg").list().collect { file(it.toString()).name }] }]
+ }
+ else if (key == "report") {
+ return [key, file(val[0][1].toString()).name]
+ }
+ return [key, val]
+ }
+ ).match()
+ }
+ }
+
+ test("sarscov2 single-end [fastqc] [config]") {
+
+ when {
+ process {
+ """
+ input[0] = channel.of([
+ [ id: 'FASTQC' ],
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true),
+ file("https://raw.githubusercontent.com/nf-core/seqinspector/1.0.0/assets/multiqc_config.yml", checkIfExists: true),
+ [],
+ [],
+ []
+ ])
+ """
+ }
+ }
+
+ then {
+ assert process.success
+ assert snapshot(
+ sanitizeOutput(process.out).collectEntries { key, val ->
+ if (key == "data") {
+ return [key, val.collect { [path(it[1]).list().collect { file(it.toString()).name }] }]
+ }
+ else if (key == "plots") {
+ return [key, val.collect { [
+ "pdf",
+ path("${it[1]}/pdf").list().collect { file(it.toString()).name },
+ "png",
+ path("${it[1]}/png").list().collect { file(it.toString()).name },
+ "svg",
+ path("${it[1]}/svg").list().collect { file(it.toString()).name }] }]
+ }
+ else if (key == "report") {
+ return [key, file(val[0][1].toString()).name]
+ }
+ return [key, val]
+ }
+ ).match()
+ }
+ }
+
+ test("sarscov2 single-end [fastqc] [multiple configs]") {
+
+ when {
+ process {
+ """
+ input[0] = channel.of([
+ [ id: 'FASTQC' ],
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true),
+ [
+ file("https://raw.githubusercontent.com/nf-core/seqinspector/1.0.0/assets/multiqc_config.yml", checkIfExists: true),
+ file("https://raw.githubusercontent.com/nf-core/seqinspector/1.0.0/assets/multiqc_config.yml", checkIfExists: true)
+ ],
+ [],
+ [],
+ []
+ ])
+ """
+ }
+ }
+
+ then {
+ assert process.success
+ assert snapshot(
+ sanitizeOutput(process.out).collectEntries { key, val ->
+ if (key == "data") {
+ return [key, val.collect { [path(it[1]).list().collect { file(it.toString()).name }] }]
+ }
+ else if (key == "plots") {
+ return [key, val.collect { [
+ "pdf",
+ path("${it[1]}/pdf").list().collect { file(it.toString()).name },
+ "png",
+ path("${it[1]}/png").list().collect { file(it.toString()).name },
+ "svg",
+ path("${it[1]}/svg").list().collect { file(it.toString()).name }] }]
+ }
+ else if (key == "report") {
+ return [key, file(val[0][1].toString()).name]
+ }
+ return [key, val]
+ }
+ ).match()
+ }
+ }
+
+ test("sarscov2 single-end [fastqc] - stub") {
+
+ options "-stub"
+
+ when {
+ process {
+ """
+ input[0] = channel.of([
+ [ id: 'FASTQC' ],
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true),
+ [],
+ [],
+ [],
+ []
+ ])
+ """
+ }
+ }
+
+ then {
+ assert process.success
+ assertAll(
+ { assert snapshot(sanitizeOutput(process.out)).match() }
+ )
+ }
+ }
+}
diff --git a/modules/nf-core/multiqc/tests/main.nf.test.snap b/modules/nf-core/multiqc/tests/main.nf.test.snap
new file mode 100644
index 0000000..4489921
--- /dev/null
+++ b/modules/nf-core/multiqc/tests/main.nf.test.snap
@@ -0,0 +1,422 @@
+{
+ "sarscov2 single-end [fastqc] [multiple configs]": {
+ "content": [
+ {
+ "data": [
+ [
+ [
+ "fastqc-status-check-heatmap.txt",
+ "fastqc_overrepresented_sequences_plot.txt",
+ "fastqc_per_base_n_content_plot.txt",
+ "fastqc_per_base_sequence_quality_plot.txt",
+ "fastqc_per_sequence_gc_content_plot_Counts.txt",
+ "fastqc_per_sequence_gc_content_plot_Percentages.txt",
+ "fastqc_per_sequence_quality_scores_plot.txt",
+ "fastqc_sequence_counts_plot.txt",
+ "fastqc_sequence_duplication_levels_plot.txt",
+ "fastqc_sequence_length_distribution_plot.txt",
+ "fastqc_top_overrepresented_sequences_table.txt",
+ "llms-full.txt",
+ "multiqc.log",
+ "multiqc.parquet",
+ "multiqc_citations.txt",
+ "multiqc_data.json",
+ "multiqc_fastqc.txt",
+ "multiqc_general_stats.txt",
+ "multiqc_sources.txt"
+ ]
+ ]
+ ],
+ "plots": [
+ [
+ "pdf",
+ [
+ "fastqc-status-check-heatmap.pdf",
+ "fastqc_overrepresented_sequences_plot.pdf",
+ "fastqc_per_base_n_content_plot.pdf",
+ "fastqc_per_base_sequence_quality_plot.pdf",
+ "fastqc_per_sequence_gc_content_plot_Counts.pdf",
+ "fastqc_per_sequence_gc_content_plot_Percentages.pdf",
+ "fastqc_per_sequence_quality_scores_plot.pdf",
+ "fastqc_sequence_counts_plot-cnt.pdf",
+ "fastqc_sequence_counts_plot-pct.pdf",
+ "fastqc_sequence_duplication_levels_plot.pdf",
+ "fastqc_sequence_length_distribution_plot.pdf",
+ "fastqc_top_overrepresented_sequences_table.pdf"
+ ],
+ "png",
+ [
+ "fastqc-status-check-heatmap.png",
+ "fastqc_overrepresented_sequences_plot.png",
+ "fastqc_per_base_n_content_plot.png",
+ "fastqc_per_base_sequence_quality_plot.png",
+ "fastqc_per_sequence_gc_content_plot_Counts.png",
+ "fastqc_per_sequence_gc_content_plot_Percentages.png",
+ "fastqc_per_sequence_quality_scores_plot.png",
+ "fastqc_sequence_counts_plot-cnt.png",
+ "fastqc_sequence_counts_plot-pct.png",
+ "fastqc_sequence_duplication_levels_plot.png",
+ "fastqc_sequence_length_distribution_plot.png",
+ "fastqc_top_overrepresented_sequences_table.png"
+ ],
+ "svg",
+ [
+ "fastqc-status-check-heatmap.svg",
+ "fastqc_overrepresented_sequences_plot.svg",
+ "fastqc_per_base_n_content_plot.svg",
+ "fastqc_per_base_sequence_quality_plot.svg",
+ "fastqc_per_sequence_gc_content_plot_Counts.svg",
+ "fastqc_per_sequence_gc_content_plot_Percentages.svg",
+ "fastqc_per_sequence_quality_scores_plot.svg",
+ "fastqc_sequence_counts_plot-cnt.svg",
+ "fastqc_sequence_counts_plot-pct.svg",
+ "fastqc_sequence_duplication_levels_plot.svg",
+ "fastqc_sequence_length_distribution_plot.svg",
+ "fastqc_top_overrepresented_sequences_table.svg"
+ ]
+ ]
+ ],
+ "report": "multiqc_report.html",
+ "versions": [
+ [
+ "MULTIQC",
+ "multiqc",
+ "1.35"
+ ]
+ ]
+ }
+ ],
+ "timestamp": "2026-03-17T16:15:42.577775492",
+ "meta": {
+ "nf-test": "0.9.4",
+ "nextflow": "25.10.4"
+ }
+ },
+ "sarscov2 single-end [fastqc]": {
+ "content": [
+ {
+ "data": [
+ [
+ [
+ "fastqc-status-check-heatmap.txt",
+ "fastqc_overrepresented_sequences_plot.txt",
+ "fastqc_per_base_n_content_plot.txt",
+ "fastqc_per_base_sequence_quality_plot.txt",
+ "fastqc_per_sequence_gc_content_plot_Counts.txt",
+ "fastqc_per_sequence_gc_content_plot_Percentages.txt",
+ "fastqc_per_sequence_quality_scores_plot.txt",
+ "fastqc_sequence_counts_plot.txt",
+ "fastqc_sequence_duplication_levels_plot.txt",
+ "fastqc_sequence_length_distribution_plot.txt",
+ "fastqc_top_overrepresented_sequences_table.txt",
+ "llms-full.txt",
+ "multiqc.log",
+ "multiqc.parquet",
+ "multiqc_citations.txt",
+ "multiqc_data.json",
+ "multiqc_fastqc.txt",
+ "multiqc_general_stats.txt",
+ "multiqc_software_versions.txt",
+ "multiqc_sources.txt"
+ ]
+ ]
+ ],
+ "plots": [
+ [
+ "pdf",
+ [
+ "fastqc-status-check-heatmap.pdf",
+ "fastqc_overrepresented_sequences_plot.pdf",
+ "fastqc_per_base_n_content_plot.pdf",
+ "fastqc_per_base_sequence_quality_plot.pdf",
+ "fastqc_per_sequence_gc_content_plot_Counts.pdf",
+ "fastqc_per_sequence_gc_content_plot_Percentages.pdf",
+ "fastqc_per_sequence_quality_scores_plot.pdf",
+ "fastqc_sequence_counts_plot-cnt.pdf",
+ "fastqc_sequence_counts_plot-pct.pdf",
+ "fastqc_sequence_duplication_levels_plot.pdf",
+ "fastqc_sequence_length_distribution_plot.pdf",
+ "fastqc_top_overrepresented_sequences_table.pdf"
+ ],
+ "png",
+ [
+ "fastqc-status-check-heatmap.png",
+ "fastqc_overrepresented_sequences_plot.png",
+ "fastqc_per_base_n_content_plot.png",
+ "fastqc_per_base_sequence_quality_plot.png",
+ "fastqc_per_sequence_gc_content_plot_Counts.png",
+ "fastqc_per_sequence_gc_content_plot_Percentages.png",
+ "fastqc_per_sequence_quality_scores_plot.png",
+ "fastqc_sequence_counts_plot-cnt.png",
+ "fastqc_sequence_counts_plot-pct.png",
+ "fastqc_sequence_duplication_levels_plot.png",
+ "fastqc_sequence_length_distribution_plot.png",
+ "fastqc_top_overrepresented_sequences_table.png"
+ ],
+ "svg",
+ [
+ "fastqc-status-check-heatmap.svg",
+ "fastqc_overrepresented_sequences_plot.svg",
+ "fastqc_per_base_n_content_plot.svg",
+ "fastqc_per_base_sequence_quality_plot.svg",
+ "fastqc_per_sequence_gc_content_plot_Counts.svg",
+ "fastqc_per_sequence_gc_content_plot_Percentages.svg",
+ "fastqc_per_sequence_quality_scores_plot.svg",
+ "fastqc_sequence_counts_plot-cnt.svg",
+ "fastqc_sequence_counts_plot-pct.svg",
+ "fastqc_sequence_duplication_levels_plot.svg",
+ "fastqc_sequence_length_distribution_plot.svg",
+ "fastqc_top_overrepresented_sequences_table.svg"
+ ]
+ ]
+ ],
+ "report": "multiqc_report.html",
+ "versions": [
+ [
+ "MULTIQC",
+ "multiqc",
+ "1.35"
+ ]
+ ]
+ }
+ ],
+ "timestamp": "2026-03-17T16:21:17.072841555",
+ "meta": {
+ "nf-test": "0.9.4",
+ "nextflow": "25.10.4"
+ }
+ },
+ "sarscov2 single-end [fastqc] - stub": {
+ "content": [
+ {
+ "data": [
+ [
+ {
+ "id": "FASTQC"
+ },
+ [
+ ".stub:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ]
+ ],
+ "plots": [
+ [
+ {
+ "id": "FASTQC"
+ },
+ [
+ ".stub:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ]
+ ],
+ "report": [
+ [
+ {
+ "id": "FASTQC"
+ },
+ "multiqc_report.html:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ],
+ "versions": [
+ [
+ "MULTIQC",
+ "multiqc",
+ "1.35"
+ ]
+ ]
+ }
+ ],
+ "timestamp": "2026-02-26T15:14:39.789193051",
+ "meta": {
+ "nf-test": "0.9.4",
+ "nextflow": "25.10.4"
+ }
+ },
+ "sarscov2 single-end [fastqc] [config]": {
+ "content": [
+ {
+ "data": [
+ [
+ [
+ "fastqc-status-check-heatmap.txt",
+ "fastqc_overrepresented_sequences_plot.txt",
+ "fastqc_per_base_n_content_plot.txt",
+ "fastqc_per_base_sequence_quality_plot.txt",
+ "fastqc_per_sequence_gc_content_plot_Counts.txt",
+ "fastqc_per_sequence_gc_content_plot_Percentages.txt",
+ "fastqc_per_sequence_quality_scores_plot.txt",
+ "fastqc_sequence_counts_plot.txt",
+ "fastqc_sequence_duplication_levels_plot.txt",
+ "fastqc_sequence_length_distribution_plot.txt",
+ "fastqc_top_overrepresented_sequences_table.txt",
+ "llms-full.txt",
+ "multiqc.log",
+ "multiqc.parquet",
+ "multiqc_citations.txt",
+ "multiqc_data.json",
+ "multiqc_fastqc.txt",
+ "multiqc_general_stats.txt",
+ "multiqc_sources.txt"
+ ]
+ ]
+ ],
+ "plots": [
+ [
+ "pdf",
+ [
+ "fastqc-status-check-heatmap.pdf",
+ "fastqc_overrepresented_sequences_plot.pdf",
+ "fastqc_per_base_n_content_plot.pdf",
+ "fastqc_per_base_sequence_quality_plot.pdf",
+ "fastqc_per_sequence_gc_content_plot_Counts.pdf",
+ "fastqc_per_sequence_gc_content_plot_Percentages.pdf",
+ "fastqc_per_sequence_quality_scores_plot.pdf",
+ "fastqc_sequence_counts_plot-cnt.pdf",
+ "fastqc_sequence_counts_plot-pct.pdf",
+ "fastqc_sequence_duplication_levels_plot.pdf",
+ "fastqc_sequence_length_distribution_plot.pdf",
+ "fastqc_top_overrepresented_sequences_table.pdf"
+ ],
+ "png",
+ [
+ "fastqc-status-check-heatmap.png",
+ "fastqc_overrepresented_sequences_plot.png",
+ "fastqc_per_base_n_content_plot.png",
+ "fastqc_per_base_sequence_quality_plot.png",
+ "fastqc_per_sequence_gc_content_plot_Counts.png",
+ "fastqc_per_sequence_gc_content_plot_Percentages.png",
+ "fastqc_per_sequence_quality_scores_plot.png",
+ "fastqc_sequence_counts_plot-cnt.png",
+ "fastqc_sequence_counts_plot-pct.png",
+ "fastqc_sequence_duplication_levels_plot.png",
+ "fastqc_sequence_length_distribution_plot.png",
+ "fastqc_top_overrepresented_sequences_table.png"
+ ],
+ "svg",
+ [
+ "fastqc-status-check-heatmap.svg",
+ "fastqc_overrepresented_sequences_plot.svg",
+ "fastqc_per_base_n_content_plot.svg",
+ "fastqc_per_base_sequence_quality_plot.svg",
+ "fastqc_per_sequence_gc_content_plot_Counts.svg",
+ "fastqc_per_sequence_gc_content_plot_Percentages.svg",
+ "fastqc_per_sequence_quality_scores_plot.svg",
+ "fastqc_sequence_counts_plot-cnt.svg",
+ "fastqc_sequence_counts_plot-pct.svg",
+ "fastqc_sequence_duplication_levels_plot.svg",
+ "fastqc_sequence_length_distribution_plot.svg",
+ "fastqc_top_overrepresented_sequences_table.svg"
+ ]
+ ]
+ ],
+ "report": "multiqc_report.html",
+ "versions": [
+ [
+ "MULTIQC",
+ "multiqc",
+ "1.35"
+ ]
+ ]
+ }
+ ],
+ "timestamp": "2026-03-17T16:15:30.372239611",
+ "meta": {
+ "nf-test": "0.9.4",
+ "nextflow": "25.10.4"
+ }
+ },
+ "sarscov2 single-end [fastqc] - custom prefix": {
+ "content": [
+ {
+ "data": [
+ [
+ [
+ "fastqc-status-check-heatmap.txt",
+ "fastqc_overrepresented_sequences_plot.txt",
+ "fastqc_per_base_n_content_plot.txt",
+ "fastqc_per_base_sequence_quality_plot.txt",
+ "fastqc_per_sequence_gc_content_plot_Counts.txt",
+ "fastqc_per_sequence_gc_content_plot_Percentages.txt",
+ "fastqc_per_sequence_quality_scores_plot.txt",
+ "fastqc_sequence_counts_plot.txt",
+ "fastqc_sequence_duplication_levels_plot.txt",
+ "fastqc_sequence_length_distribution_plot.txt",
+ "fastqc_top_overrepresented_sequences_table.txt",
+ "llms-full.txt",
+ "multiqc.log",
+ "multiqc.parquet",
+ "multiqc_citations.txt",
+ "multiqc_data.json",
+ "multiqc_fastqc.txt",
+ "multiqc_general_stats.txt",
+ "multiqc_software_versions.txt",
+ "multiqc_sources.txt"
+ ]
+ ]
+ ],
+ "plots": [
+ [
+ "pdf",
+ [
+ "fastqc-status-check-heatmap.pdf",
+ "fastqc_overrepresented_sequences_plot.pdf",
+ "fastqc_per_base_n_content_plot.pdf",
+ "fastqc_per_base_sequence_quality_plot.pdf",
+ "fastqc_per_sequence_gc_content_plot_Counts.pdf",
+ "fastqc_per_sequence_gc_content_plot_Percentages.pdf",
+ "fastqc_per_sequence_quality_scores_plot.pdf",
+ "fastqc_sequence_counts_plot-cnt.pdf",
+ "fastqc_sequence_counts_plot-pct.pdf",
+ "fastqc_sequence_duplication_levels_plot.pdf",
+ "fastqc_sequence_length_distribution_plot.pdf",
+ "fastqc_top_overrepresented_sequences_table.pdf"
+ ],
+ "png",
+ [
+ "fastqc-status-check-heatmap.png",
+ "fastqc_overrepresented_sequences_plot.png",
+ "fastqc_per_base_n_content_plot.png",
+ "fastqc_per_base_sequence_quality_plot.png",
+ "fastqc_per_sequence_gc_content_plot_Counts.png",
+ "fastqc_per_sequence_gc_content_plot_Percentages.png",
+ "fastqc_per_sequence_quality_scores_plot.png",
+ "fastqc_sequence_counts_plot-cnt.png",
+ "fastqc_sequence_counts_plot-pct.png",
+ "fastqc_sequence_duplication_levels_plot.png",
+ "fastqc_sequence_length_distribution_plot.png",
+ "fastqc_top_overrepresented_sequences_table.png"
+ ],
+ "svg",
+ [
+ "fastqc-status-check-heatmap.svg",
+ "fastqc_overrepresented_sequences_plot.svg",
+ "fastqc_per_base_n_content_plot.svg",
+ "fastqc_per_base_sequence_quality_plot.svg",
+ "fastqc_per_sequence_gc_content_plot_Counts.svg",
+ "fastqc_per_sequence_gc_content_plot_Percentages.svg",
+ "fastqc_per_sequence_quality_scores_plot.svg",
+ "fastqc_sequence_counts_plot-cnt.svg",
+ "fastqc_sequence_counts_plot-pct.svg",
+ "fastqc_sequence_duplication_levels_plot.svg",
+ "fastqc_sequence_length_distribution_plot.svg",
+ "fastqc_top_overrepresented_sequences_table.svg"
+ ]
+ ]
+ ],
+ "report": "custom_prefix.html",
+ "versions": [
+ [
+ "MULTIQC",
+ "multiqc",
+ "1.35"
+ ]
+ ]
+ }
+ ],
+ "timestamp": "2026-03-17T16:15:18.189023981",
+ "meta": {
+ "nf-test": "0.9.4",
+ "nextflow": "25.10.4"
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/nf-core/multiqc/tests/nextflow.config b/modules/nf-core/multiqc/tests/nextflow.config
new file mode 100644
index 0000000..374dfef
--- /dev/null
+++ b/modules/nf-core/multiqc/tests/nextflow.config
@@ -0,0 +1,6 @@
+process {
+ withName: 'MULTIQC' {
+ ext.prefix = null
+ ext.args = '-p'
+ }
+}
diff --git a/modules/nf-core/samtools/flagstat/environment.yml b/modules/nf-core/samtools/flagstat/environment.yml
new file mode 100644
index 0000000..946bb36
--- /dev/null
+++ b/modules/nf-core/samtools/flagstat/environment.yml
@@ -0,0 +1,10 @@
+---
+# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json
+channels:
+ - conda-forge
+ - bioconda
+dependencies:
+ # renovate: datasource=conda depName=bioconda/htslib
+ - bioconda::htslib=1.23.1
+ # renovate: datasource=conda depName=bioconda/samtools
+ - bioconda::samtools=1.23.1
diff --git a/modules/nf-core/samtools/flagstat/main.nf b/modules/nf-core/samtools/flagstat/main.nf
new file mode 100644
index 0000000..2d9588b
--- /dev/null
+++ b/modules/nf-core/samtools/flagstat/main.nf
@@ -0,0 +1,47 @@
+process SAMTOOLS_FLAGSTAT {
+ tag "${meta.id}"
+ label 'process_single'
+
+ conda "${moduleDir}/environment.yml"
+ container "${workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container
+ ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/8c/8c5d2818c8b9f58e1fba77ce219fdaf32087ae53e857c4a496402978af26e78c/data'
+ : 'community.wave.seqera.io/library/htslib_samtools:1.23.1--5b6bb4ede7e612e5'}"
+
+ input:
+ tuple val(meta), path(bam), path(bai)
+
+ output:
+ tuple val(meta), path("*.flagstat"), emit: flagstat
+ tuple val("${task.process}"), val('samtools'), eval("samtools version | sed '1!d;s/.* //'"), emit: versions_samtools, topic: versions
+
+ when:
+ task.ext.when == null || task.ext.when
+
+ script:
+ def prefix = task.ext.prefix ?: "${meta.id}"
+ """
+ samtools \\
+ flagstat \\
+ --threads ${task.cpus} \\
+ ${bam} \\
+ > ${prefix}.flagstat
+ """
+
+ stub:
+ def prefix = task.ext.prefix ?: "${meta.id}"
+ """
+ cat <<-END_FLAGSTAT > ${prefix}.flagstat
+ 1000000 + 0 in total (QC-passed reads + QC-failed reads)
+ 0 + 0 secondary
+ 0 + 0 supplementary
+ 0 + 0 duplicates
+ 900000 + 0 mapped (90.00% : N/A)
+ 1000000 + 0 paired in sequencing
+ 500000 + 0 read1
+ 500000 + 0 read2
+ 800000 + 0 properly paired (80.00% : N/A)
+ 850000 + 0 with mate mapped to a different chr
+ 50000 + 0 with mate mapped to a different chr (mapQ>=5)
+ END_FLAGSTAT
+ """
+}
diff --git a/modules/nf-core/samtools/flagstat/meta.yml b/modules/nf-core/samtools/flagstat/meta.yml
new file mode 100644
index 0000000..f658acd
--- /dev/null
+++ b/modules/nf-core/samtools/flagstat/meta.yml
@@ -0,0 +1,76 @@
+name: samtools_flagstat
+description: Counts the number of alignments in a BAM/CRAM/SAM file for each
+ FLAG type
+keywords:
+ - stats
+ - mapping
+ - counts
+ - bam
+ - sam
+ - cram
+tools:
+ - samtools:
+ description: |
+ SAMtools is a set of utilities for interacting with and post-processing
+ short DNA sequence read alignments in the SAM, BAM and CRAM formats, written by Heng Li.
+ These files are generated as output by short read aligners like BWA.
+ homepage: http://www.htslib.org/
+ documentation: http://www.htslib.org/doc/samtools.html
+ doi: 10.1093/bioinformatics/btp352
+ licence:
+ - "MIT"
+ identifier: biotools:samtools
+input:
+ - - meta:
+ type: map
+ description: |
+ Groovy Map containing sample information
+ e.g. [ id:'test', single_end:false ]
+ - bam:
+ type: file
+ description: BAM/CRAM/SAM file
+ pattern: "*.{bam,cram,sam}"
+ ontologies: []
+ - bai:
+ type: file
+ description: Index for BAM/CRAM/SAM file
+ pattern: "*.{bai,crai,sai}"
+ ontologies: []
+output:
+ flagstat:
+ - - meta:
+ type: map
+ description: |
+ Groovy Map containing sample information
+ e.g. [ id:'test', single_end:false ]
+ - "*.flagstat":
+ type: file
+ description: File containing samtools flagstat output
+ pattern: "*.{flagstat}"
+ ontologies: []
+ versions_samtools:
+ - - ${task.process}:
+ type: string
+ description: The name of the process
+ - samtools:
+ type: string
+ description: The name of the tool
+ - samtools version | sed '1!d;s/.* //':
+ type: eval
+ description: The expression to obtain the version of the tool
+topics:
+ versions:
+ - - ${task.process}:
+ type: string
+ description: The name of the process
+ - samtools:
+ type: string
+ description: The name of the tool
+ - samtools version | sed '1!d;s/.* //':
+ type: eval
+ description: The expression to obtain the version of the tool
+authors:
+ - "@drpatelh"
+maintainers:
+ - "@drpatelh"
+ - "@matthdsm"
diff --git a/modules/nf-core/samtools/flagstat/tests/main.nf.test b/modules/nf-core/samtools/flagstat/tests/main.nf.test
new file mode 100644
index 0000000..3b648a3
--- /dev/null
+++ b/modules/nf-core/samtools/flagstat/tests/main.nf.test
@@ -0,0 +1,56 @@
+nextflow_process {
+
+ name "Test Process SAMTOOLS_FLAGSTAT"
+ script "../main.nf"
+ process "SAMTOOLS_FLAGSTAT"
+ tag "modules"
+ tag "modules_nfcore"
+ tag "samtools"
+ tag "samtools/flagstat"
+
+ test("BAM") {
+
+ when {
+ process {
+ """
+ input[0] = Channel.of([
+ [ id:'test', single_end:false ], // meta map
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true),
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam.bai', checkIfExists: true)
+ ])
+ """
+ }
+ }
+
+ then {
+ assertAll (
+ { assert process.success },
+ { assert snapshot(process.out).match() }
+ )
+ }
+ }
+
+ test("BAM - stub") {
+
+ options "-stub"
+
+ when {
+ process {
+ """
+ input[0] = Channel.of([
+ [ id:'test', single_end:false ], // meta map
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true),
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam.bai', checkIfExists: true)
+ ])
+ """
+ }
+ }
+
+ then {
+ assertAll (
+ { assert process.success },
+ { assert snapshot(process.out).match() }
+ )
+ }
+ }
+}
diff --git a/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap b/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap
new file mode 100644
index 0000000..b110c47
--- /dev/null
+++ b/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap
@@ -0,0 +1,88 @@
+{
+ "BAM - stub": {
+ "content": [
+ {
+ "0": [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.flagstat:md5,67394650dbae96d1a4fcc70484822159"
+ ]
+ ],
+ "1": [
+ [
+ "SAMTOOLS_FLAGSTAT",
+ "samtools",
+ "1.23.1"
+ ]
+ ],
+ "flagstat": [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.flagstat:md5,67394650dbae96d1a4fcc70484822159"
+ ]
+ ],
+ "versions_samtools": [
+ [
+ "SAMTOOLS_FLAGSTAT",
+ "samtools",
+ "1.23.1"
+ ]
+ ]
+ }
+ ],
+ "meta": {
+ "nf-test": "0.9.3",
+ "nextflow": "25.10.4"
+ },
+ "timestamp": "2026-03-19T08:59:26.188788"
+ },
+ "BAM": {
+ "content": [
+ {
+ "0": [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.flagstat:md5,4f7ffd1e6a5e85524d443209ac97d783"
+ ]
+ ],
+ "1": [
+ [
+ "SAMTOOLS_FLAGSTAT",
+ "samtools",
+ "1.23.1"
+ ]
+ ],
+ "flagstat": [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.flagstat:md5,4f7ffd1e6a5e85524d443209ac97d783"
+ ]
+ ],
+ "versions_samtools": [
+ [
+ "SAMTOOLS_FLAGSTAT",
+ "samtools",
+ "1.23.1"
+ ]
+ ]
+ }
+ ],
+ "meta": {
+ "nf-test": "0.9.3",
+ "nextflow": "25.10.4"
+ },
+ "timestamp": "2026-03-19T08:59:20.212002"
+ }
+}
\ No newline at end of file
diff --git a/modules/nf-core/samtools/idxstats/environment.yml b/modules/nf-core/samtools/idxstats/environment.yml
new file mode 100644
index 0000000..946bb36
--- /dev/null
+++ b/modules/nf-core/samtools/idxstats/environment.yml
@@ -0,0 +1,10 @@
+---
+# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json
+channels:
+ - conda-forge
+ - bioconda
+dependencies:
+ # renovate: datasource=conda depName=bioconda/htslib
+ - bioconda::htslib=1.23.1
+ # renovate: datasource=conda depName=bioconda/samtools
+ - bioconda::samtools=1.23.1
diff --git a/modules/nf-core/samtools/idxstats/main.nf b/modules/nf-core/samtools/idxstats/main.nf
new file mode 100644
index 0000000..4d74768
--- /dev/null
+++ b/modules/nf-core/samtools/idxstats/main.nf
@@ -0,0 +1,38 @@
+process SAMTOOLS_IDXSTATS {
+ tag "${meta.id}"
+ label 'process_single'
+
+ conda "${moduleDir}/environment.yml"
+ container "${workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container
+ ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/8c/8c5d2818c8b9f58e1fba77ce219fdaf32087ae53e857c4a496402978af26e78c/data'
+ : 'community.wave.seqera.io/library/htslib_samtools:1.23.1--5b6bb4ede7e612e5'}"
+
+ input:
+ tuple val(meta), path(bam), path(bai)
+
+ output:
+ tuple val(meta), path("*.idxstats"), emit: idxstats
+ tuple val("${task.process}"), val('samtools'), eval("samtools version | sed '1!d;s/.* //'"), emit: versions_samtools, topic: versions
+
+ when:
+ task.ext.when == null || task.ext.when
+
+ script:
+ def prefix = task.ext.prefix ?: "${meta.id}"
+
+ """
+ # Note: --threads value represents *additional* CPUs to allocate (total CPUs = 1 + --threads).
+ samtools \\
+ idxstats \\
+ --threads ${task.cpus - 1} \\
+ ${bam} \\
+ > ${prefix}.idxstats
+ """
+
+ stub:
+ def prefix = task.ext.prefix ?: "${meta.id}"
+
+ """
+ touch ${prefix}.idxstats
+ """
+}
diff --git a/modules/nf-core/samtools/idxstats/meta.yml b/modules/nf-core/samtools/idxstats/meta.yml
new file mode 100644
index 0000000..0f9fb3d
--- /dev/null
+++ b/modules/nf-core/samtools/idxstats/meta.yml
@@ -0,0 +1,76 @@
+name: samtools_idxstats
+description: Reports alignment summary statistics for a BAM/CRAM/SAM file
+keywords:
+ - stats
+ - mapping
+ - counts
+ - chromosome
+ - bam
+ - sam
+ - cram
+tools:
+ - samtools:
+ description: |
+ SAMtools is a set of utilities for interacting with and post-processing
+ short DNA sequence read alignments in the SAM, BAM and CRAM formats, written by Heng Li.
+ These files are generated as output by short read aligners like BWA.
+ homepage: http://www.htslib.org/
+ documentation: http://www.htslib.org/doc/samtools.html
+ doi: 10.1093/bioinformatics/btp352
+ licence:
+ - "MIT"
+ identifier: biotools:samtools
+input:
+ - - meta:
+ type: map
+ description: |
+ Groovy Map containing sample information
+ e.g. [ id:'test', single_end:false ]
+ - bam:
+ type: file
+ description: BAM/CRAM/SAM file
+ pattern: "*.{bam,cram,sam}"
+ ontologies: []
+ - bai:
+ type: file
+ description: Index for BAM/CRAM/SAM file
+ pattern: "*.{bai,crai,sai}"
+ ontologies: []
+output:
+ idxstats:
+ - - meta:
+ type: map
+ description: |
+ Groovy Map containing sample information
+ e.g. [ id:'test', single_end:false ]
+ - "*.idxstats":
+ type: file
+ description: File containing samtools idxstats output
+ pattern: "*.{idxstats}"
+ ontologies: []
+ versions_samtools:
+ - - ${task.process}:
+ type: string
+ description: The name of the process
+ - samtools:
+ type: string
+ description: The name of the tool
+ - samtools version | sed '1!d;s/.* //':
+ type: eval
+ description: The expression to obtain the version of the tool
+topics:
+ versions:
+ - - ${task.process}:
+ type: string
+ description: The name of the process
+ - samtools:
+ type: string
+ description: The name of the tool
+ - samtools version | sed '1!d;s/.* //':
+ type: eval
+ description: The expression to obtain the version of the tool
+authors:
+ - "@drpatelh"
+maintainers:
+ - "@drpatelh"
+ - "@matthdsm"
diff --git a/modules/nf-core/samtools/idxstats/tests/main.nf.test b/modules/nf-core/samtools/idxstats/tests/main.nf.test
new file mode 100644
index 0000000..c990cd5
--- /dev/null
+++ b/modules/nf-core/samtools/idxstats/tests/main.nf.test
@@ -0,0 +1,59 @@
+nextflow_process {
+
+ name "Test Process SAMTOOLS_IDXSTATS"
+ script "../main.nf"
+ process "SAMTOOLS_IDXSTATS"
+ tag "modules"
+ tag "modules_nfcore"
+ tag "samtools"
+ tag "samtools/idxstats"
+
+ test("bam") {
+
+ when {
+ process {
+ """
+ input[0] = Channel.of([
+ [ id:'test', single_end:false ], // meta map
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true),
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam.bai', checkIfExists: true)
+ ])
+ """
+ }
+ }
+
+ then {
+ assertAll (
+ { assert process.success },
+ { assert snapshot(
+ process.out.idxstats,
+ process.out.findAll { key, val -> key.startsWith('versions') }
+ ).match() }
+ )
+ }
+ }
+
+ test("bam - stub") {
+ options "-stub"
+ when {
+ process {
+ """
+ input[0] = Channel.of([
+ [ id:'test', single_end:false ], // meta map
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true),
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam.bai', checkIfExists: true)
+ ])
+ """
+ }
+ }
+
+ then {
+ assertAll (
+ { assert process.success },
+ { assert snapshot(
+ process.out.idxstats,
+ process.out.findAll { key, val -> key.startsWith('versions') }
+ ).match() }
+ )
+ }
+ }}
diff --git a/modules/nf-core/samtools/idxstats/tests/main.nf.test.snap b/modules/nf-core/samtools/idxstats/tests/main.nf.test.snap
new file mode 100644
index 0000000..7bcde2f
--- /dev/null
+++ b/modules/nf-core/samtools/idxstats/tests/main.nf.test.snap
@@ -0,0 +1,56 @@
+{
+ "bam - stub": {
+ "content": [
+ [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.idxstats:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ],
+ {
+ "versions_samtools": [
+ [
+ "SAMTOOLS_IDXSTATS",
+ "samtools",
+ "1.23.1"
+ ]
+ ]
+ }
+ ],
+ "meta": {
+ "nf-test": "0.9.3",
+ "nextflow": "25.10.4"
+ },
+ "timestamp": "2026-03-19T08:59:41.877526"
+ },
+ "bam": {
+ "content": [
+ [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.idxstats:md5,df60a8c8d6621100d05178c93fb053a2"
+ ]
+ ],
+ {
+ "versions_samtools": [
+ [
+ "SAMTOOLS_IDXSTATS",
+ "samtools",
+ "1.23.1"
+ ]
+ ]
+ }
+ ],
+ "meta": {
+ "nf-test": "0.9.3",
+ "nextflow": "25.10.4"
+ },
+ "timestamp": "2026-03-19T08:59:34.725514"
+ }
+}
\ No newline at end of file
diff --git a/modules/nf-core/samtools/quickcheck/environment.yml b/modules/nf-core/samtools/quickcheck/environment.yml
new file mode 100644
index 0000000..310db6d
--- /dev/null
+++ b/modules/nf-core/samtools/quickcheck/environment.yml
@@ -0,0 +1,8 @@
+---
+# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json
+channels:
+ - conda-forge
+ - bioconda
+dependencies:
+ - "bioconda::samtools=1.23"
+ - "bioconda::htslib=1.23.1"
diff --git a/modules/nf-core/samtools/quickcheck/main.nf b/modules/nf-core/samtools/quickcheck/main.nf
new file mode 100644
index 0000000..0b877d6
--- /dev/null
+++ b/modules/nf-core/samtools/quickcheck/main.nf
@@ -0,0 +1,36 @@
+process SAMTOOLS_QUICKCHECK {
+ tag "${meta.id}"
+ label 'process_single'
+
+ conda "${moduleDir}/environment.yml"
+ container "${workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container
+ ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/8c/8c5d2818c8b9f58e1fba77ce219fdaf32087ae53e857c4a496402978af26e78c/data'
+ : 'community.wave.seqera.io/library/htslib_samtools:1.23.1--5b6bb4ede7e612e5'}"
+
+ input:
+ tuple val(meta), path(bam)
+
+ output:
+ tuple val(meta), path(bam), env("EXIT_CODE"), emit: bam
+ tuple val("${task.process}"), val('samtools'), eval("samtools version | sed '1!d;s/.* //'"), topic: versions, emit: versions_samtools
+
+ when:
+ task.ext.when == null || task.ext.when
+
+ script:
+ def args = task.ext.args ?: ''
+ """
+ samtools quickcheck \\
+ ${args} \\
+ ${bam} || EXIT_CODE=\$?
+
+ EXIT_CODE=\${EXIT_CODE:-0}
+ """
+
+ stub:
+ def args = task.ext.args ?: ''
+ """
+ EXIT_CODE=0
+ echo ${args}
+ """
+}
diff --git a/modules/nf-core/samtools/quickcheck/meta.yml b/modules/nf-core/samtools/quickcheck/meta.yml
new file mode 100644
index 0000000..64e44b6
--- /dev/null
+++ b/modules/nf-core/samtools/quickcheck/meta.yml
@@ -0,0 +1,76 @@
+# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/meta-schema.json
+name: "samtools_quickcheck"
+description: Quickly check that input files appear to be intact. Checks that beginning of the file contains a valid header (all formats) containing at least one target sequence and then seeks to the end of the file and checks that an end-of-file (EOF) is present and intact (BAM and CRAM only). Alignment records are not checked. The quickcheck module returns a non-zero EXIT_CODE if any input files don't have a valid header or are missing an EOF block. Otherwise EXIT_CODE is zero.
+keywords:
+ - check
+ - quickcheck
+ - sam
+ - bam
+ - cram
+tools:
+ - "samtools":
+ description: "Tools for dealing with SAM, BAM and CRAM files"
+ homepage: "https://www.htslib.org/"
+ documentation: "https://www.htslib.org/doc/samtools-quickcheck.html"
+ tool_dev_url: "https://github.com/samtools/"
+ doi: "10.1093/bioinformatics/btp352"
+ licence: ["MIT"]
+ identifier: biotools:samtools
+
+input:
+ - - meta:
+ type: map
+ description: Groovy Map containing sample information. e.g. `[ id:'sample1' ]`
+ - bam:
+ type: file
+ description: sequence_trace file
+ pattern: "*.{cram,sam,bam}"
+ ontologies:
+ - edam: http://edamontology.org/data_0924 # Sequence trace
+ - edam: http://edamontology.org/format_3462 # CRAM
+ - edam: http://edamontology.org/format_2573 # SAM
+ - edam: http://edamontology.org/format_2572 # BAM
+output:
+ bam:
+ - - meta:
+ type: map
+ description: Groovy Map containing sample information. e.g. `[ id:'sample1' ]`
+ - bam:
+ type: file
+ description: sequence_trace file
+ pattern: "*.{cram,sam,bam}"
+ ontologies:
+ - edam: http://edamontology.org/data_0924 # Sequence trace
+ - edam: http://edamontology.org/format_3462 # CRAM
+ - edam: http://edamontology.org/format_2573 # SAM
+ - edam: http://edamontology.org/format_2572 # BAM
+ - EXIT_CODE:
+ type: string
+ description: Exit code (0 for success, non-zero otherwise) that is the result of the format check.
+ ontologies: []
+ versions_samtools:
+ - - ${task.process}:
+ type: string
+ description: The name of the process
+ - samtools:
+ type: string
+ description: The name of the tool
+ - "samtools version | sed '1!d;s/.* //'":
+ type: eval
+ description: The expression to obtain the version of the tool
+topics:
+ versions:
+ - - ${task.process}:
+ type: string
+ description: The name of the process
+ - samtools:
+ type: string
+ description: The name of the tool
+ - "samtools version | sed '1!d;s/.* //'":
+ type: eval
+ description: The expression to obtain the version of the tool
+authors:
+ - "@Krannich479"
+maintainers:
+ - "@Krannich479"
+ - "@matthdsm"
diff --git a/modules/nf-core/samtools/quickcheck/tests/main.nf.test b/modules/nf-core/samtools/quickcheck/tests/main.nf.test
new file mode 100644
index 0000000..a4a0748
--- /dev/null
+++ b/modules/nf-core/samtools/quickcheck/tests/main.nf.test
@@ -0,0 +1,207 @@
+// nf-core modules test samtools/quickcheck
+nextflow_process {
+
+ name "Test Process SAMTOOLS_QUICKCHECK"
+ script "../main.nf"
+ process "SAMTOOLS_QUICKCHECK"
+
+ tag "modules"
+ tag "modules_nfcore"
+ tag "samtools"
+ tag "samtools/quickcheck"
+
+ test(" bam - PE ") {
+ when {
+ process {
+ """
+ input[0] = Channel.of([
+ [ id:'test.paired_end.sorted' ],
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true)
+ ])
+ """
+ }
+ }
+
+ then {
+ assertAll (
+ { assert process.success },
+ { assert process.out.bam.collect{ it[2] } == ["0"] },
+ { assert snapshot(process.out).match() }
+ )
+ }
+ }
+
+ test(" bam - SE ") {
+ when {
+ process {
+ """
+ input[0] = [
+ [ id:'test.single_end.sorted' ],
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.single_end.sorted.bam', checkIfExists: true),
+ ]
+ """
+ }
+ }
+
+ then {
+ assertAll (
+ { assert process.success },
+ { assert process.out.bam.collect{ it[2] } == ["0"] },
+ { assert snapshot(process.out).match() }
+ )
+ }
+ }
+
+ test(" bam - PE - stub") {
+ options "-stub"
+
+ when {
+ process {
+ """
+ input[0] = [
+ [ id:'test.paired_end.sorted' ],
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true),
+ ]
+ """
+ }
+ }
+
+ then {
+ assertAll (
+ { assert process.success },
+ { assert process.out.bam.collect{ it[2] } == ["0"] },
+ { assert snapshot(process.out).match() }
+ )
+ }
+ }
+
+ test(" cram - PE ") {
+ when {
+ process {
+ """
+ input[0] = Channel.of([
+ [ id:'test.paired_end.sorted' ],
+ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.sorted.cram', checkIfExists: true)
+ ])
+ """
+ }
+ }
+
+ then {
+ assertAll (
+ { assert process.success },
+ { assert process.out.bam.collect{ it[2] } == ["0"] },
+ { assert snapshot(process.out).match() }
+ )
+ }
+ }
+
+ test(" sam - PE - No targets") {
+ /* SAM header misses targets of corresponding alignments */
+ when {
+ process {
+ """
+ input[0] = [
+ [ id:'test.paired_end.sorted' ],
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.invalid.sam', checkIfExists: true),
+ ]
+ """
+ }
+ }
+
+ then {
+ assertAll (
+ { assert process.success },
+ { assert process.out.bam.collect{ it[2] } == ["8"] },
+ { assert snapshot(process.out).match() }
+ )
+ }
+ }
+
+ test(" sam - PE - No targets - ignore targets / unaligned option") {
+ /* SAM header misses targets of corresponding alignments, but the '-u' parameter makes this tolerated as unaligned */
+ config "./nextflow.config"
+
+ when {
+ process {
+ """
+ input[0] = [
+ [ id:'test.paired_end.sorted' ],
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.invalid.sam', checkIfExists: true),
+ ]
+ """
+ }
+ }
+
+ then {
+ assertAll (
+ { assert process.success },
+ { assert process.out.bam.collect{ it[2] } == ["0"] },
+ { assert snapshot(process.out).match() }
+ )
+ }
+ }
+
+ test(" bam - ?E - Bad EOF") {
+ when {
+ process {
+ """
+ input[0] = [
+ [ id:'1.quickcheck.badeof' ],
+ file('https://github.com/samtools/samtools/raw/refs/heads/develop/test/quickcheck/1.quickcheck.badeof.bam', checkIfExists: true),
+ ]
+ """
+ }
+ }
+
+ then {
+ assertAll (
+ { assert process.success },
+ { assert process.out.bam.collect{ it[2] } == ["16"] },
+ { assert snapshot(process.out).match() }
+ )
+ }
+ }
+
+ test(" bam - ?E - No targets") {
+ when {
+ process {
+ """
+ input[0] = [
+ [ id:'10.quickcheck.notargets' ],
+ file('https://github.com/samtools/samtools/raw/refs/heads/develop/test/quickcheck/10.quickcheck.notargets.bam', checkIfExists: true),
+ ]
+ """
+ }
+ }
+
+ then {
+ assertAll (
+ { assert process.success },
+ { assert process.out.bam.collect{ it[2] } == ["8"] },
+ { assert snapshot(process.out).match() }
+ )
+ }
+ }
+
+ test(" bam - ?E - Bad header") {
+ when {
+ process {
+ """
+ input[0] = [
+ [ id:'2.quickcheck.badheader' ],
+ file('https://github.com/samtools/samtools/raw/refs/heads/develop/test/quickcheck/2.quickcheck.badheader.bam', checkIfExists: true),
+ ]
+ """
+ }
+ }
+
+ then {
+ assertAll (
+ { assert process.success },
+ { assert process.out.bam.collect{ it[2] } == ["4"] },
+ { assert snapshot(process.out).match() }
+ )
+ }
+ }
+}
diff --git a/modules/nf-core/samtools/quickcheck/tests/main.nf.test.snap b/modules/nf-core/samtools/quickcheck/tests/main.nf.test.snap
new file mode 100644
index 0000000..a048e5a
--- /dev/null
+++ b/modules/nf-core/samtools/quickcheck/tests/main.nf.test.snap
@@ -0,0 +1,389 @@
+{
+ " bam - PE - stub": {
+ "content": [
+ {
+ "0": [
+ [
+ {
+ "id": "test.paired_end.sorted"
+ },
+ "test.paired_end.sorted.bam:md5,fb76969225f658c10e4cdf496b703a61",
+ "0"
+ ]
+ ],
+ "1": [
+ [
+ "SAMTOOLS_QUICKCHECK",
+ "samtools",
+ "1.23.1"
+ ]
+ ],
+ "bam": [
+ [
+ {
+ "id": "test.paired_end.sorted"
+ },
+ "test.paired_end.sorted.bam:md5,fb76969225f658c10e4cdf496b703a61",
+ "0"
+ ]
+ ],
+ "versions_samtools": [
+ [
+ "SAMTOOLS_QUICKCHECK",
+ "samtools",
+ "1.23.1"
+ ]
+ ]
+ }
+ ],
+ "meta": {
+ "nf-test": "0.9.3",
+ "nextflow": "25.10.4"
+ },
+ "timestamp": "2026-03-19T09:02:12.590185"
+ },
+ " sam - PE - No targets": {
+ "content": [
+ {
+ "0": [
+ [
+ {
+ "id": "test.paired_end.sorted"
+ },
+ "test.paired_end.sorted.invalid.sam:md5,c9307be2f9d47f648c1bb864b3e12542",
+ "8"
+ ]
+ ],
+ "1": [
+ [
+ "SAMTOOLS_QUICKCHECK",
+ "samtools",
+ "1.23.1"
+ ]
+ ],
+ "bam": [
+ [
+ {
+ "id": "test.paired_end.sorted"
+ },
+ "test.paired_end.sorted.invalid.sam:md5,c9307be2f9d47f648c1bb864b3e12542",
+ "8"
+ ]
+ ],
+ "versions_samtools": [
+ [
+ "SAMTOOLS_QUICKCHECK",
+ "samtools",
+ "1.23.1"
+ ]
+ ]
+ }
+ ],
+ "meta": {
+ "nf-test": "0.9.3",
+ "nextflow": "25.10.4"
+ },
+ "timestamp": "2026-03-19T09:02:23.072247"
+ },
+ " bam - SE ": {
+ "content": [
+ {
+ "0": [
+ [
+ {
+ "id": "test.single_end.sorted"
+ },
+ "test.single_end.sorted.bam:md5,e29aca28f0d40c6637139fc008f3f2c9",
+ "0"
+ ]
+ ],
+ "1": [
+ [
+ "SAMTOOLS_QUICKCHECK",
+ "samtools",
+ "1.23.1"
+ ]
+ ],
+ "bam": [
+ [
+ {
+ "id": "test.single_end.sorted"
+ },
+ "test.single_end.sorted.bam:md5,e29aca28f0d40c6637139fc008f3f2c9",
+ "0"
+ ]
+ ],
+ "versions_samtools": [
+ [
+ "SAMTOOLS_QUICKCHECK",
+ "samtools",
+ "1.23.1"
+ ]
+ ]
+ }
+ ],
+ "meta": {
+ "nf-test": "0.9.3",
+ "nextflow": "25.10.4"
+ },
+ "timestamp": "2026-03-19T09:02:05.559532"
+ },
+ " cram - PE ": {
+ "content": [
+ {
+ "0": [
+ [
+ {
+ "id": "test.paired_end.sorted"
+ },
+ "test.paired_end.sorted.cram:md5,e0146aa3a5a196e4cb5593f545e95c31",
+ "0"
+ ]
+ ],
+ "1": [
+ [
+ "SAMTOOLS_QUICKCHECK",
+ "samtools",
+ "1.23.1"
+ ]
+ ],
+ "bam": [
+ [
+ {
+ "id": "test.paired_end.sorted"
+ },
+ "test.paired_end.sorted.cram:md5,e0146aa3a5a196e4cb5593f545e95c31",
+ "0"
+ ]
+ ],
+ "versions_samtools": [
+ [
+ "SAMTOOLS_QUICKCHECK",
+ "samtools",
+ "1.23.1"
+ ]
+ ]
+ }
+ ],
+ "meta": {
+ "nf-test": "0.9.3",
+ "nextflow": "25.10.4"
+ },
+ "timestamp": "2026-03-19T09:02:17.843915"
+ },
+ " bam - PE ": {
+ "content": [
+ {
+ "0": [
+ [
+ {
+ "id": "test.paired_end.sorted"
+ },
+ "test.paired_end.sorted.bam:md5,fb76969225f658c10e4cdf496b703a61",
+ "0"
+ ]
+ ],
+ "1": [
+ [
+ "SAMTOOLS_QUICKCHECK",
+ "samtools",
+ "1.23.1"
+ ]
+ ],
+ "bam": [
+ [
+ {
+ "id": "test.paired_end.sorted"
+ },
+ "test.paired_end.sorted.bam:md5,fb76969225f658c10e4cdf496b703a61",
+ "0"
+ ]
+ ],
+ "versions_samtools": [
+ [
+ "SAMTOOLS_QUICKCHECK",
+ "samtools",
+ "1.23.1"
+ ]
+ ]
+ }
+ ],
+ "meta": {
+ "nf-test": "0.9.3",
+ "nextflow": "25.10.4"
+ },
+ "timestamp": "2026-03-19T09:01:59.948119"
+ },
+ " bam - ?E - Bad EOF": {
+ "content": [
+ {
+ "0": [
+ [
+ {
+ "id": "1.quickcheck.badeof"
+ },
+ "1.quickcheck.badeof.bam:md5,e389fce53b839a9b65fd9b25bd448d8b",
+ "16"
+ ]
+ ],
+ "1": [
+ [
+ "SAMTOOLS_QUICKCHECK",
+ "samtools",
+ "1.23.1"
+ ]
+ ],
+ "bam": [
+ [
+ {
+ "id": "1.quickcheck.badeof"
+ },
+ "1.quickcheck.badeof.bam:md5,e389fce53b839a9b65fd9b25bd448d8b",
+ "16"
+ ]
+ ],
+ "versions_samtools": [
+ [
+ "SAMTOOLS_QUICKCHECK",
+ "samtools",
+ "1.23.1"
+ ]
+ ]
+ }
+ ],
+ "meta": {
+ "nf-test": "0.9.3",
+ "nextflow": "25.10.4"
+ },
+ "timestamp": "2026-03-19T09:02:33.740526"
+ },
+ " bam - ?E - No targets": {
+ "content": [
+ {
+ "0": [
+ [
+ {
+ "id": "10.quickcheck.notargets"
+ },
+ "10.quickcheck.notargets.bam:md5,89fc7ae65ec7e624d1ce1d4499d4b43a",
+ "8"
+ ]
+ ],
+ "1": [
+ [
+ "SAMTOOLS_QUICKCHECK",
+ "samtools",
+ "1.23.1"
+ ]
+ ],
+ "bam": [
+ [
+ {
+ "id": "10.quickcheck.notargets"
+ },
+ "10.quickcheck.notargets.bam:md5,89fc7ae65ec7e624d1ce1d4499d4b43a",
+ "8"
+ ]
+ ],
+ "versions_samtools": [
+ [
+ "SAMTOOLS_QUICKCHECK",
+ "samtools",
+ "1.23.1"
+ ]
+ ]
+ }
+ ],
+ "meta": {
+ "nf-test": "0.9.3",
+ "nextflow": "25.10.4"
+ },
+ "timestamp": "2026-03-19T09:02:40.774367"
+ },
+ " sam - PE - No targets - ignore targets / unaligned option": {
+ "content": [
+ {
+ "0": [
+ [
+ {
+ "id": "test.paired_end.sorted"
+ },
+ "test.paired_end.sorted.invalid.sam:md5,c9307be2f9d47f648c1bb864b3e12542",
+ "0"
+ ]
+ ],
+ "1": [
+ [
+ "SAMTOOLS_QUICKCHECK",
+ "samtools",
+ "1.23.1"
+ ]
+ ],
+ "bam": [
+ [
+ {
+ "id": "test.paired_end.sorted"
+ },
+ "test.paired_end.sorted.invalid.sam:md5,c9307be2f9d47f648c1bb864b3e12542",
+ "0"
+ ]
+ ],
+ "versions_samtools": [
+ [
+ "SAMTOOLS_QUICKCHECK",
+ "samtools",
+ "1.23.1"
+ ]
+ ]
+ }
+ ],
+ "meta": {
+ "nf-test": "0.9.3",
+ "nextflow": "25.10.4"
+ },
+ "timestamp": "2026-03-19T09:02:28.064753"
+ },
+ " bam - ?E - Bad header": {
+ "content": [
+ {
+ "0": [
+ [
+ {
+ "id": "2.quickcheck.badheader"
+ },
+ "2.quickcheck.badheader.bam:md5,7c9300a04c23ee607dcc95e26f318932",
+ "4"
+ ]
+ ],
+ "1": [
+ [
+ "SAMTOOLS_QUICKCHECK",
+ "samtools",
+ "1.23.1"
+ ]
+ ],
+ "bam": [
+ [
+ {
+ "id": "2.quickcheck.badheader"
+ },
+ "2.quickcheck.badheader.bam:md5,7c9300a04c23ee607dcc95e26f318932",
+ "4"
+ ]
+ ],
+ "versions_samtools": [
+ [
+ "SAMTOOLS_QUICKCHECK",
+ "samtools",
+ "1.23.1"
+ ]
+ ]
+ }
+ ],
+ "meta": {
+ "nf-test": "0.9.3",
+ "nextflow": "25.10.4"
+ },
+ "timestamp": "2026-03-19T09:02:46.357687"
+ }
+}
\ No newline at end of file
diff --git a/modules/nf-core/samtools/quickcheck/tests/nextflow.config b/modules/nf-core/samtools/quickcheck/tests/nextflow.config
new file mode 100644
index 0000000..b6d217a
--- /dev/null
+++ b/modules/nf-core/samtools/quickcheck/tests/nextflow.config
@@ -0,0 +1,5 @@
+process {
+ withName: SAMTOOLS_QUICKCHECK {
+ ext.args = '-u'
+ }
+}
diff --git a/modules/nf-core/samtools/stats/environment.yml b/modules/nf-core/samtools/stats/environment.yml
new file mode 100644
index 0000000..946bb36
--- /dev/null
+++ b/modules/nf-core/samtools/stats/environment.yml
@@ -0,0 +1,10 @@
+---
+# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json
+channels:
+ - conda-forge
+ - bioconda
+dependencies:
+ # renovate: datasource=conda depName=bioconda/htslib
+ - bioconda::htslib=1.23.1
+ # renovate: datasource=conda depName=bioconda/samtools
+ - bioconda::samtools=1.23.1
diff --git a/modules/nf-core/samtools/stats/main.nf b/modules/nf-core/samtools/stats/main.nf
new file mode 100644
index 0000000..28457e6
--- /dev/null
+++ b/modules/nf-core/samtools/stats/main.nf
@@ -0,0 +1,40 @@
+process SAMTOOLS_STATS {
+ tag "${meta.id}"
+ label 'process_single'
+
+ conda "${moduleDir}/environment.yml"
+ container "${workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container
+ ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/8c/8c5d2818c8b9f58e1fba77ce219fdaf32087ae53e857c4a496402978af26e78c/data'
+ : 'community.wave.seqera.io/library/htslib_samtools:1.23.1--5b6bb4ede7e612e5'}"
+
+ input:
+ tuple val(meta), path(input), path(input_index)
+ tuple val(meta2), path(fasta), path(fai)
+
+ output:
+ tuple val(meta), path("*.stats"), emit: stats
+ tuple val("${task.process}"), val('samtools'), eval('samtools version | sed "1!d;s/.* //"'), emit: versions_samtools, topic: versions
+
+ when:
+ task.ext.when == null || task.ext.when
+
+ script:
+ def args = task.ext.args ?: ''
+ def prefix = task.ext.prefix ?: "${meta.id}"
+ def reference = fasta ? "--reference ${fasta}" : ""
+ """
+ samtools \\
+ stats \\
+ ${args} \\
+ --threads ${task.cpus} \\
+ ${reference} \\
+ ${input} \\
+ > ${prefix}.stats
+ """
+
+ stub:
+ def prefix = task.ext.prefix ?: "${meta.id}"
+ """
+ touch ${prefix}.stats
+ """
+}
diff --git a/modules/nf-core/samtools/stats/meta.yml b/modules/nf-core/samtools/stats/meta.yml
new file mode 100644
index 0000000..5fd7e76
--- /dev/null
+++ b/modules/nf-core/samtools/stats/meta.yml
@@ -0,0 +1,94 @@
+name: samtools_stats
+description: Produces comprehensive statistics from SAM/BAM/CRAM file
+keywords:
+ - statistics
+ - counts
+ - bam
+ - sam
+ - cram
+tools:
+ - samtools:
+ description: |
+ SAMtools is a set of utilities for interacting with and post-processing
+ short DNA sequence read alignments in the SAM, BAM and CRAM formats, written by Heng Li.
+ These files are generated as output by short read aligners like BWA.
+ homepage: http://www.htslib.org/
+ documentation: http://www.htslib.org/doc/samtools.html
+ doi: 10.1093/bioinformatics/btp352
+ licence: ["MIT"]
+ identifier: biotools:samtools
+input:
+ - - meta:
+ type: map
+ description: |
+ Groovy Map containing sample information
+ e.g. [ id:'test', single_end:false ]
+ - input:
+ type: file
+ description: BAM/CRAM file from alignment
+ pattern: "*.{bam,cram}"
+ ontologies: []
+ - input_index:
+ type: file
+ description: BAI/CRAI file from alignment
+ pattern: "*.{bai,crai}"
+ ontologies: []
+ - - meta2:
+ type: map
+ description: |
+ Groovy Map containing reference information
+ e.g. [ id:'genome' ]
+ - fasta:
+ type: file
+ description: Reference file the CRAM was created with (optional)
+ pattern: "*.{fasta,fa,fna}"
+ ontologies: []
+ - fai:
+ type: file
+ description: FASTA ref index file
+ pattern: "*.{fasta,fa,fna}.fai"
+ ontologies: []
+output:
+ stats:
+ - - meta:
+ type: map
+ description: |
+ Groovy Map containing sample information
+ e.g. [ id:'test', single_end:false ]
+ - "*.stats":
+ type: file
+ description: File containing samtools stats output
+ pattern: "*.{stats}"
+ ontologies: []
+ versions_samtools:
+ - - ${task.process}:
+ type: string
+ description: Name of the process
+ - samtools:
+ type: string
+ description: Name of the tool
+ - samtools version | sed "1!d;s/.* //":
+ type: eval
+ description: The expression to obtain the version of the tool
+
+topics:
+ versions:
+ - - ${task.process}:
+ type: string
+ description: Name of the process
+ - samtools:
+ type: string
+ description: Name of the tool
+ - samtools version | sed "1!d;s/.* //":
+ type: eval
+ description: The expression to obtain the version of the tool
+
+authors:
+ - "@drpatelh"
+ - "@FriederikeHanssen"
+ - "@ramprasadn"
+maintainers:
+ - "@drpatelh"
+ - "@FriederikeHanssen"
+ - "@ramprasadn"
+ - "@matthdsm"
diff --git a/modules/nf-core/samtools/stats/tests/main.nf.test b/modules/nf-core/samtools/stats/tests/main.nf.test
new file mode 100644
index 0000000..140adf3
--- /dev/null
+++ b/modules/nf-core/samtools/stats/tests/main.nf.test
@@ -0,0 +1,115 @@
+nextflow_process {
+
+ name "Test Process SAMTOOLS_STATS"
+ script "../main.nf"
+ process "SAMTOOLS_STATS"
+
+ tag "modules"
+ tag "modules_nfcore"
+ tag "samtools"
+ tag "samtools/stats"
+
+ test("bam") {
+
+ when {
+ process {
+ """
+ input[0] = Channel.of([
+ [ id:'test', single_end:false ], // meta map
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true),
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam.bai', checkIfExists: true)
+ ])
+ input[1] = [[],[],[]]
+ """
+ }
+ }
+
+ then {
+ assertAll(
+ {assert process.success},
+ {assert snapshot(process.out).match()}
+ )
+ }
+ }
+
+ test("cram") {
+
+ when {
+ process {
+ """
+ input[0] = Channel.of([
+ [ id:'test', single_end:false ], // meta map
+ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.recalibrated.sorted.cram', checkIfExists: true),
+ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.recalibrated.sorted.cram.crai', checkIfExists: true)
+ ])
+ input[1] = Channel.of([
+ [ id:'genome' ], // meta map
+ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr21/sequence/genome.fasta', checkIfExists: true),
+ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr21/sequence/genome.fasta.fai', checkIfExists: true)
+ ])
+ """
+ }
+ }
+
+ then {
+ assertAll(
+ {assert process.success},
+ {assert snapshot(process.out).match()}
+ )
+ }
+ }
+
+ test("bam - stub") {
+
+ options "-stub"
+
+ when {
+ process {
+ """
+ input[0] = Channel.of([
+ [ id:'test', single_end:false ], // meta map
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true),
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam.bai', checkIfExists: true)
+ ])
+ input[1] = [[],[],[]]
+ """
+ }
+ }
+
+ then {
+ assertAll(
+ {assert process.success},
+ {assert snapshot(process.out).match()}
+ )
+ }
+ }
+
+ test("cram - stub") {
+
+ options "-stub"
+
+ when {
+ process {
+ """
+ input[0] = Channel.of([
+ [ id:'test', single_end:false ], // meta map
+ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.recalibrated.sorted.cram', checkIfExists: true),
+ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.recalibrated.sorted.cram.crai', checkIfExists: true)
+ ])
+ input[1] = Channel.of([
+ [ id:'genome' ], // meta map
+ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr21/sequence/genome.fasta', checkIfExists: true),
+ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr21/sequence/genome.fasta.fai', checkIfExists: true)
+ ])
+ """
+ }
+ }
+
+ then {
+ assertAll(
+ {assert process.success},
+ {assert snapshot(process.out).match()}
+ )
+ }
+ }
+}
diff --git a/modules/nf-core/samtools/stats/tests/main.nf.test.snap b/modules/nf-core/samtools/stats/tests/main.nf.test.snap
new file mode 100644
index 0000000..975d44a
--- /dev/null
+++ b/modules/nf-core/samtools/stats/tests/main.nf.test.snap
@@ -0,0 +1,174 @@
+{
+ "cram": {
+ "content": [
+ {
+ "0": [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.stats:md5,e4d6cf0e75cebd0bafa84141e0b6929b"
+ ]
+ ],
+ "1": [
+ [
+ "SAMTOOLS_STATS",
+ "samtools",
+ "1.23.1"
+ ]
+ ],
+ "stats": [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.stats:md5,e4d6cf0e75cebd0bafa84141e0b6929b"
+ ]
+ ],
+ "versions_samtools": [
+ [
+ "SAMTOOLS_STATS",
+ "samtools",
+ "1.23.1"
+ ]
+ ]
+ }
+ ],
+ "meta": {
+ "nf-test": "0.9.3",
+ "nextflow": "25.10.4"
+ },
+ "timestamp": "2026-03-19T09:05:39.987454"
+ },
+ "bam - stub": {
+ "content": [
+ {
+ "0": [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.stats:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ],
+ "1": [
+ [
+ "SAMTOOLS_STATS",
+ "samtools",
+ "1.23.1"
+ ]
+ ],
+ "stats": [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.stats:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ],
+ "versions_samtools": [
+ [
+ "SAMTOOLS_STATS",
+ "samtools",
+ "1.23.1"
+ ]
+ ]
+ }
+ ],
+ "meta": {
+ "nf-test": "0.9.3",
+ "nextflow": "25.10.4"
+ },
+ "timestamp": "2026-03-19T09:05:47.495502"
+ },
+ "cram - stub": {
+ "content": [
+ {
+ "0": [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.stats:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ],
+ "1": [
+ [
+ "SAMTOOLS_STATS",
+ "samtools",
+ "1.23.1"
+ ]
+ ],
+ "stats": [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.stats:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ],
+ "versions_samtools": [
+ [
+ "SAMTOOLS_STATS",
+ "samtools",
+ "1.23.1"
+ ]
+ ]
+ }
+ ],
+ "meta": {
+ "nf-test": "0.9.3",
+ "nextflow": "25.10.4"
+ },
+ "timestamp": "2026-03-19T09:05:56.38373"
+ },
+ "bam": {
+ "content": [
+ {
+ "0": [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.stats:md5,80f94eb0b68e213bdc8231109d3b43ad"
+ ]
+ ],
+ "1": [
+ [
+ "SAMTOOLS_STATS",
+ "samtools",
+ "1.23.1"
+ ]
+ ],
+ "stats": [
+ [
+ {
+ "id": "test",
+ "single_end": false
+ },
+ "test.stats:md5,80f94eb0b68e213bdc8231109d3b43ad"
+ ]
+ ],
+ "versions_samtools": [
+ [
+ "SAMTOOLS_STATS",
+ "samtools",
+ "1.23.1"
+ ]
+ ]
+ }
+ ],
+ "meta": {
+ "nf-test": "0.9.3",
+ "nextflow": "25.10.4"
+ },
+ "timestamp": "2026-03-19T09:05:24.59441"
+ }
+}
\ No newline at end of file
diff --git a/scripts/core_runtime/Split_ReadsV2.codon b/scripts/core_runtime/Split_ReadsV2.codon
index aceb5c8..c430d1b 100755
--- a/scripts/core_runtime/Split_ReadsV2.codon
+++ b/scripts/core_runtime/Split_ReadsV2.codon
@@ -354,7 +354,7 @@ def gid_from_sb_raw(sample: str, sb_raw: str, sb_to_gid: Dict[str, int]) -> int:
# defensive: if some inputs ever already have injected base removed
if sb_raw in sb_to_gid:
return sb_to_gid[sb_raw]
-
+
key1 = normalize_sb_drop_first(sb_raw)
if key1 in sb_to_gid:
return sb_to_gid[key1]
diff --git a/scripts/core_runtime/Tag.codon b/scripts/core_runtime/Tag.codon
index 182b6b4..9e9dce0 100755
--- a/scripts/core_runtime/Tag.codon
+++ b/scripts/core_runtime/Tag.codon
@@ -29,7 +29,7 @@ def read_barcode_whitelist_from_file(bc_whitelist_filename: str):
with open(bc_whitelist_filename, "r") as fh:
[bc_whitelist.add(Kmer[BC_LEN](seq(bc_line.strip()))) for bc_line in fh]
-
+
return bc_whitelist
# Function to get the filename and extension
@@ -42,7 +42,7 @@ def split_filename(filepath):
else:
name, ext1 = filename.rsplit('.', 1)
return name, ext1
-
+
def tag_fastq(
I2:str,
R1:str,
@@ -106,7 +106,7 @@ def tag_fastq(
R1_tagged_outpath_fh = open(R1_tagged_outpath, 'w')
R2_tagged_outpath = f"{out_folder}/{R2_fname}_{tag}.{R2_ext}"
R2_tagged_outpath_fh = open(R2_tagged_outpath, 'w')
-
+
# Initialize barcode and stats lists
corr_bcs = List[str](capacity=500000000)
# Store number of reads which have hamming distance of 0, 1, 2 or 3 from barcodes whitelist.
@@ -114,7 +114,7 @@ def tag_fastq(
n_reads = 0
sys.stdout.write(f"Tagging reads...\n")
-
+
for recordI2,recordR1,recordR2 in zip(I2_gen,R1_gen, R2_gen):
#assert recordI2.name == recordR1.name == recordR2.name, f"I2 ({I2}) & R1 ({R1}) & R2 ({R2}) read names don't match."
@@ -132,12 +132,12 @@ def tag_fastq(
bc_seq=bc_seq,
bc_qual=bc_qual,
max_hamming_dist=HD)
-
+
if first_pass:
R1comment = ''
else:
R1comment = '\t' + recordR1.comment
-
+
##Check if read comment is already a SAM tag
#if (len(recordR1.comment) >= 3 and recordR1.comment[2] == ':' and recordR1.comment[0].isalpha() and recordR1.comment[1].isalnum()):
# R1comment = '\t' + recordR1.comment
@@ -159,14 +159,14 @@ def tag_fastq(
if n_reads % 20000 == 0:
sys.stdout.write(f"\r{n_reads} reads processed ...")
sys.stdout.flush()
-
+
sys.stdout.write("\r")
sys.stdout.flush()
sys.stdout.write(f"Finished processing {n_reads} reads...\n")
-
+
BC_Counter = Counter(corr_bcs)
n_nomatch = BC_Counter.pop('NoMatch')
-
+
# Close the corrected read files
R1_tagged_outpath_fh.close()
R2_tagged_outpath_fh.close()
@@ -177,7 +177,7 @@ def tag_fastq(
reads_without_bc = n_reads - bc_reads
# Calculate fraction of barcodes found in all reads.
frac_bcs_found = bc_reads / n_reads
-
+
# Store the stats
stats_tsv = (
f"reads\t{n_reads}\t100.00%\n" +
@@ -189,24 +189,24 @@ def tag_fastq(
f"bc_reads_with_{i}_mismatches\t{bc_mismatches_stats[i]}\t" +
f"{(bc_mismatches_stats[i] / n_reads * 100.0)}%\n"
)
-
+
#Writing log files and sam header
# write the stats to corrected_bc_stats_tsv_filename
with open(out_folder + corrected_bc_stats_tsv_filename, 'w') as file:
file.write(stats_tsv)
-
+
# write the reads_per_barcode to reads_per_barcode_tsv_filename
with open(out_folder + reads_per_barcode_tsv_filename, "w") as file:
# Write item counts as tab-separated values
for bc, read_count in BC_Counter.items():
file.write(f"{read_count}\t{bc}\n")
file.write(f"{n_nomatch}\tNoMatch")
-
+
# print the stats to the console
sys.stdout.write(f'\n{stats_tsv}\n')
return frac_bcs_found
-
+
def main():
# Check that the correct number of arguments are passed
@@ -224,7 +224,7 @@ def main():
out = sys.argv[7]
first_pass_arg = sys.argv[8]
rev_comp_arg = sys.argv[9]
-
+
# Check that the max_mismatches is 0, 1, 2 or 3
if HD not in [0,1,2,3]:
sys.stderr.write(f"\nExiting...\nMaximum Hamming Distance (HD) must be 0, 1, 2 or 3\n")
@@ -233,7 +233,7 @@ def main():
# Ensure the path ends with a '/'
if not out.endswith('/'):
out = out + '/'
-
+
xtraBC = ''
if first_pass_arg=='first_pass':
IS_IT_YOUR_FIRST_PASS=True
@@ -258,7 +258,7 @@ def main():
bc_whitelist = read_barcode_whitelist_from_file(bc_whitelist_filename=bc_whitelist_filename)
# Read FASTQ with Forward barcodes and write R1 R2 FASTQs tagging them in the read comment
- # with a tag and a barcode that match the whitelist closely enough,
+ # with a tag and a barcode that match the whitelist closely enough,
# Output stats
frac_bcs_found = tag_fastq(
@@ -273,7 +273,7 @@ def main():
reads_per_barcode_tsv_filename=f'Reads_Per_Barcode_{sample_name}_{tag_name}.tsv',
out_folder=out,
rev_comp=REV_COMP)
-
+
sys.stdout.write(f"\n{frac_bcs_found * 100.00}% of the reads had a valid barcode.\n")
if __name__ == "__main__":
diff --git a/scripts/core_runtime/Tag_Lig3.codon b/scripts/core_runtime/Tag_Lig3.codon
index 912c0b6..c4fc28f 100755
--- a/scripts/core_runtime/Tag_Lig3.codon
+++ b/scripts/core_runtime/Tag_Lig3.codon
@@ -81,7 +81,7 @@ def tag_fastq(
corrected_bc_stats_tsv_filename = f'Barcode_Statistics_{sample}_{tag}.tsv'
reads_per_barcode_tsv_filename = f'Reads_Per_Barcode_{sample}_{tag}.tsv'
Tag_records_filename = f'Tag_Records_{sample}.tsv'
-
+
# Initialize file readers/writers
# Process barcode reader
if I2.endswith('.gz'):
@@ -112,7 +112,7 @@ def tag_fastq(
# Handle Tag records output paths
Tag_records_outpath = f"{out_folder}/{Tag_records_filename}"
Tag_records_outpath_fh = open(Tag_records_outpath, 'w')
-
+
# Initialize barcode and stats lists
corr_bcs = List[str](capacity=500000000)
# Store number of reads which have hamming distance of 0, 1, 2 or 3 from barcodes whitelist.
@@ -136,14 +136,14 @@ def tag_fastq(
else:
# Forward
bc_seq_l1, bc_qual_l1 = (recordI2.seq[l_bc_start_list[0]:l_bc_start_list[0]+BC_LEN], recordI2.qual[l_bc_start_list[0]:l_bc_start_list[0]+BC_LEN])
-
+
corrected_bc_l1 = correct_bc_by_qual_order_with_whitelist_or_correct_bc_with_Ns_with_whitelist(
bc_whitelist=bc_whitelist,
bc_length=BC_LEN,
bc_seq=bc_seq_l1,
bc_qual=bc_qual_l1,
max_hamming_dist=HD)
-
+
if corrected_bc_l1:
bc_mismatches_stats_l1[corrected_bc_l1.hamming_dist] += 1
else:
@@ -156,14 +156,14 @@ def tag_fastq(
else:
# Forward
bc_seq_l2, bc_qual_l2 = (recordI2.seq[l_bc_start_list[1]:l_bc_start_list[1]+BC_LEN], recordI2.qual[l_bc_start_list[1]:l_bc_start_list[1]+BC_LEN])
-
+
corrected_bc_l2 = correct_bc_by_qual_order_with_whitelist_or_correct_bc_with_Ns_with_whitelist(
bc_whitelist=bc_whitelist,
bc_length=BC_LEN,
bc_seq=bc_seq_l2,
bc_qual=bc_qual_l2,
max_hamming_dist=HD)
-
+
if corrected_bc_l2:
bc_mismatches_stats_l2[corrected_bc_l2.hamming_dist] += 1
else:
@@ -177,14 +177,14 @@ def tag_fastq(
else:
# Forward
bc_seq_l3, bc_qual_l3 = (recordI2.seq[l_bc_start_list[2]:l_bc_start_list[2]+BC_LEN], recordI2.qual[l_bc_start_list[2]:l_bc_start_list[2]+BC_LEN])
-
+
corrected_bc_l3 = correct_bc_by_qual_order_with_whitelist_or_correct_bc_with_Ns_with_whitelist(
bc_whitelist=bc_whitelist,
bc_length=BC_LEN,
bc_seq=bc_seq_l3,
bc_qual=bc_qual_l3,
max_hamming_dist=HD)
-
+
if n_reads == 1:
assert recordI2.name == recordR1.name == recordR2.name, f"I2 ({I2}) & R1 ({R1}) & R2 ({R2}) read names don't match."
@@ -192,16 +192,16 @@ def tag_fastq(
bc_mismatches_stats_l3[corrected_bc_l3.hamming_dist] += 1
else:
corrected_bc_l3 = (8,'NoMatch')
-
+
sb_start = recordR1.comment.find("SB:Z:")
sb_tag = recordR1.comment[sb_start+5:].split()[0]
corrs = [sb_tag,corrected_bc_l1.corrected_bc,corrected_bc_l2.corrected_bc,corrected_bc_l3.corrected_bc]
# Check for NoMatch and build the final_bc
final_bc = 'NoMatch' if 'NoMatch' in corrs else ''.join(corrs)
-
+
corr_bcs.append(final_bc)
-
+
record_name_tagged = recordR1.name + f' {tag}:Z:{final_bc}' + f'\tRG:Z:{final_bc}' + f'\t{recordR1.comment}'
R1_tagged_outpath_fh.write(f'@{record_name_tagged}\n{recordR1.read}\n+\n{recordR1.qual}\n')
R2_tagged_outpath_fh.write(f'@{record_name_tagged}\n{recordR2.read}\n+\n{recordR2.qual}\n')
@@ -220,7 +220,7 @@ def tag_fastq(
sys.stdout.flush()
sys.stdout.write(f"Preparing BCs lists...DONE\n")
sys.stdout.flush()
-
+
# Close the corrected read files
R1_tagged_outpath_fh.close()
R2_tagged_outpath_fh.close()
@@ -238,7 +238,7 @@ def tag_fastq(
frac_bcs_found = bc_reads / n_reads
# Reads in barcode with less than required amount of reads
reads_in_too_small_bc = bc_reads - n_passing_reads #in this case reads_in_too_small_bc are the reads with at least 1 valid ligation but not all 3 ligations
-
+
# stats
stats_tsv = (
f"reads\t{n_reads}\t100.00%\n" +
@@ -254,9 +254,9 @@ def tag_fastq(
f"reads_with_L{li}\t{bc_reads}\t" + f"{(bc_reads / n_reads * 100.0)}%\n" +
f"reads_with_L{li}_with_all_ligations\t{n_passing_reads}\t" + f"{(n_passing_reads / bc_reads * 100.0)}%\n" +
f"reads_with_L{li}_missing_other_ligation\t{reads_in_too_small_bc}\t" + f"{(reads_in_too_small_bc / bc_reads * 100.0)}%\n"
- f"reads_with_all_ligations\t{n_passing_reads}\t" + f"{(n_passing_reads / n_reads * 100.0)}%\n"
+ f"reads_with_all_ligations\t{n_passing_reads}\t" + f"{(n_passing_reads / n_reads * 100.0)}%\n"
)
-
+
#Writing log files and sam header
# write the stats to corrected_bc_stats_tsv_filename
with open(out_folder + f"{corrected_bc_stats_tsv_filename.rsplit('.', 1)[0]}_L{li}.{corrected_bc_stats_tsv_filename.rsplit('.', 1)[1]}", 'w') as file:
@@ -273,7 +273,7 @@ def tag_fastq(
sys.stdout.write(f'DONE\n')
return frac_bcs_found
-
+
def main():
START_LIST = [15,53,91]
@@ -297,7 +297,7 @@ def main():
sys.stderr.write(f"\nExiting...\nExpected exactly three comma-separated ligation start positions, got: {sys.argv[8]}\n")
sys.exit(1)
START_LIST = [int(start_tokens[0]), int(start_tokens[1]), int(start_tokens[2])]
-
+
# Check that the max_mismatches is 0, 1, 2 or 3
if HD not in [0,1,2,3]:
sys.stderr.write(f"\nExiting...\nMaximum Hamming Distance (HD) must be 0, 1, 2 or 3\n")
@@ -307,7 +307,7 @@ def main():
bc_whitelist = read_barcode_whitelist_from_file(bc_whitelist_filename=bc_whitelist_filename)
# Read FASTQ with Forward barcodes and write R1 R2 FASTQs tagging them in the read comment
- # with a tag and a barcode that match the whitelist closely enough,
+ # with a tag and a barcode that match the whitelist closely enough,
# Output stats
frac_bcs_found = tag_fastq(
I2 = I2,
@@ -319,7 +319,7 @@ def main():
sample=sample_name,
out_folder=out+'/',
rev_comp=False)
-
+
sys.stdout.write(f"{frac_bcs_found * 100.00}% of the reads had a valid barcode.\n")
if __name__ == "__main__":
diff --git a/scripts/core_runtime/Tag_UMI.codon b/scripts/core_runtime/Tag_UMI.codon
index 3b51bb3..362af24 100755
--- a/scripts/core_runtime/Tag_UMI.codon
+++ b/scripts/core_runtime/Tag_UMI.codon
@@ -80,13 +80,13 @@ def tag_fastq(
R1_tagged_outpath_fh = open(R1_tagged_outpath, 'w')
R2_tagged_outpath = f"{out_folder}/{R2_fname}_{tag}.{R2_ext}"
R2_tagged_outpath_fh = open(R2_tagged_outpath, 'w')
-
+
# Initialize barcode and stats lists
corr_bcs = List[str](capacity=500000000)
n_reads = 0
sys.stdout.write(f"Tagging reads with UMI...\n")
-
+
for recordI2,recordR1,recordR2 in zip(I2_gen,R1_gen, R2_gen):
#assert recordI2.name == recordR1.name == recordR2.name, f"I2 ({I2}) & R1 ({R1}) & R2 ({R2}) read names don't match."
@@ -97,7 +97,7 @@ def tag_fastq(
else:
# Forward
bc_seq, bc_qual = (recordI2.seq[BC_START:BC_START+BC_LEN], recordI2.qual[BC_START:BC_START+BC_LEN])
-
+
bc_seq = str(bc_seq)
record_name_tagged = recordR1.name + f' {tag}:Z:{bc_seq}' + f'\t{recordR1.comment}'
corr_bcs.append(bc_seq)
@@ -109,25 +109,25 @@ def tag_fastq(
if n_reads % 20000 == 0:
sys.stdout.write(f"\r{n_reads} reads processed ...")
sys.stdout.flush()
-
+
sys.stdout.write("\r")
sys.stdout.flush()
sys.stdout.write(f"Finished processing {n_reads} reads...\n")
-
+
BC_Counter = Counter(corr_bcs)
-
+
# write the reads_per_barcode to reads_per_barcode_tsv_filename
with open(out_folder + reads_per_barcode_tsv_filename, "w") as file:
# Write item counts as tab-separated values
for bc, read_count in BC_Counter.items():
file.write(f"{read_count}\t{bc}\n")
-
+
# Close the corrected read files
R1_tagged_outpath_fh.close()
R2_tagged_outpath_fh.close()
return 0
-
+
def main():
# Check that the correct number of arguments are passed
@@ -148,7 +148,7 @@ def main():
out = out + '/'
# Read FASTQ with Forward barcodes and write R1 R2 FASTQs tagging them in the read comment
- # with a tag and a barcode that match the whitelist closely enough,
+ # with a tag and a barcode that match the whitelist closely enough,
# Output stats
tag_fastq(
I2 = I2,
@@ -158,7 +158,7 @@ def main():
reads_per_barcode_tsv_filename=f'Reads_Per_Barcode_{sample_name}_{tag_name}.tsv',
out_folder=out,
rev_comp=True)
-
+
if __name__ == "__main__":
main()
diff --git a/scripts/core_runtime/utils.codon b/scripts/core_runtime/utils.codon
index 5268544..a60b9b6 100755
--- a/scripts/core_runtime/utils.codon
+++ b/scripts/core_runtime/utils.codon
@@ -15,7 +15,7 @@ def get_qual_sorted_idx(qual):
key=lambda x: x[1],
algorithm="insertion",
reverse=False
- )
+ )
)
)
@@ -201,7 +201,7 @@ def correct_bc_by_qual_order_with_whitelist_or_correct_bc_with_Ns_with_whitelist
"""
assert len(str(bc_seq)) == bc_length, "The barcodes are not the expected length..."
-
+
if "N" in str(bc_seq):
corrected_bc = correct_bc_with_Ns_with_whitelist(
bc_whitelist,
diff --git a/subworkflows/local/dna_core/main.nf b/subworkflows/local/dna_core/main.nf
index 5eaed8e..fd164dc 100644
--- a/subworkflows/local/dna_core/main.nf
+++ b/subworkflows/local/dna_core/main.nf
@@ -26,9 +26,12 @@ include { TAG_DNA_CELL_BARCODE } from '../../../modules/local/tag_dna_cell_b
include { TRIM_DNA_FASTQS } from '../../../modules/local/trim_dna_fastqs/main'
include { SPLIT_DNA_READS } from '../../../modules/local/split_dna_reads/main'
include { ALIGN_DNA } from '../../../modules/local/align_dna/main'
-include { MARK_DUPLICATES_DNA } from '../../../modules/local/mark_duplicates_dna/main'
+include { GATK4_MARKDUPLICATES } from '../../../modules/nf-core/gatk4/markduplicates/main'
+include { NORMALIZE_DNA_MARKDUPLICATES } from '../../../modules/local/normalize_dna_markduplicates/main'
include { SPLIT_DUPLICATES_DNA } from '../../../modules/local/split_duplicates_dna/main'
-include { BAM_COVERAGE_DNA } from '../../../modules/local/bam_coverage_dna/main'
+include { CHECK_DNA_NODUP_BAM } from '../../../modules/local/check_dna_nodup_bam/main'
+include { DEEPTOOLS_BAMCOVERAGE } from '../../../modules/nf-core/deeptools/bamcoverage/main'
+include { NORMALIZE_DNA_BAMCOVERAGE } from '../../../modules/local/normalize_dna_bamcoverage/main'
def selectDnaIndexRead(final Map meta, final Object i1, final Object i2, final String fieldName) {
return meta[fieldName] == 'i1' ? i1 : i2
@@ -42,6 +45,19 @@ def dnaLigationStartPositions(final Map meta) {
return meta.dna_tagmentation == 'dual' ? '41,79,117' : '15,53,91'
}
+def nfcoreDnaMeta(final String splitName, final Map meta, final String stage) {
+ return meta + [
+ id : splitName,
+ tres_sample_id : meta.id,
+ tres_split_name: splitName,
+ tres_stage : stage,
+ ]
+}
+
+def restoreDnaMeta(final Map meta) {
+ return meta + [id: meta.tres_sample_id ?: meta.id]
+}
+
workflow DNA_CORE {
take:
ch_dna_samples
@@ -145,9 +161,32 @@ workflow DNA_CORE {
// Finish the DNA core with alignment, duplicate marking, NoDup extraction, and coverage.
ALIGN_DNA(ch_align_input)
ch_versions = ch_versions.mix(ALIGN_DNA.out.versions)
- MARK_DUPLICATES_DNA(ALIGN_DNA.out.bam)
- ch_versions = ch_versions.mix(MARK_DUPLICATES_DNA.out.versions)
- SPLIT_DUPLICATES_DNA(MARK_DUPLICATES_DNA.out.bam)
+
+ ch_gatk_markduplicates_input = ALIGN_DNA.out.bam.map { splitName, meta, alignedBam ->
+ tuple(nfcoreDnaMeta(splitName, meta, 'markeddup'), alignedBam)
+ }
+
+ GATK4_MARKDUPLICATES(ch_gatk_markduplicates_input, [], [])
+ ch_versions = ch_versions.mix(GATK4_MARKDUPLICATES.out.versions_gatk4)
+ ch_versions = ch_versions.mix(GATK4_MARKDUPLICATES.out.versions_samtools)
+
+ ch_normalize_markduplicates_input = GATK4_MARKDUPLICATES.out.bam
+ .join(GATK4_MARKDUPLICATES.out.bai)
+ .join(GATK4_MARKDUPLICATES.out.metrics)
+ .map { nfMeta, markedDupBam, markedDupBai, markedDupMetrics ->
+ tuple(
+ nfMeta.tres_split_name as String,
+ restoreDnaMeta(nfMeta),
+ markedDupBam,
+ markedDupBai,
+ markedDupMetrics
+ )
+ }
+
+ NORMALIZE_DNA_MARKDUPLICATES(ch_normalize_markduplicates_input)
+ ch_versions = ch_versions.mix(NORMALIZE_DNA_MARKDUPLICATES.out.versions)
+
+ SPLIT_DUPLICATES_DNA(NORMALIZE_DNA_MARKDUPLICATES.out.bam)
ch_versions = ch_versions.mix(SPLIT_DUPLICATES_DNA.out.versions)
ch_nodup_for_coverage = SPLIT_DUPLICATES_DNA.out.bam
@@ -162,13 +201,44 @@ workflow DNA_CORE {
)
}
- BAM_COVERAGE_DNA(ch_nodup_for_coverage)
- ch_versions = ch_versions.mix(BAM_COVERAGE_DNA.out.versions)
+ CHECK_DNA_NODUP_BAM(ch_nodup_for_coverage)
+ ch_versions = ch_versions.mix(CHECK_DNA_NODUP_BAM.out.versions)
+
+ ch_deeptools_bamcoverage_input = CHECK_DNA_NODUP_BAM.out.ready.map { splitName, meta, noDupBam, noDupBai, effectiveGenomeSize ->
+ tuple(nfcoreDnaMeta(splitName, meta, 'nodup_coverage'), noDupBam, noDupBai)
+ }
+
+ DEEPTOOLS_BAMCOVERAGE(
+ ch_deeptools_bamcoverage_input,
+ [],
+ [],
+ tuple([id: 'no_blacklist'], [])
+ )
+ ch_versions = ch_versions.mix(DEEPTOOLS_BAMCOVERAGE.out.versions_deeptools)
+ ch_versions = ch_versions.mix(DEEPTOOLS_BAMCOVERAGE.out.versions_samtools)
+
+ ch_normalize_bamcoverage_input = DEEPTOOLS_BAMCOVERAGE.out.bigwig.map { nfMeta, bigwig ->
+ tuple(
+ nfMeta.tres_split_name as String,
+ restoreDnaMeta(nfMeta),
+ bigwig
+ )
+ }
+
+ NORMALIZE_DNA_BAMCOVERAGE(ch_normalize_bamcoverage_input)
+ ch_versions = ch_versions.mix(NORMALIZE_DNA_BAMCOVERAGE.out.versions)
ch_barcode_reports = TAG_DNA_SAMPLE_BARCODE.out.metrics
.mix(TAG_DNA_MODALITY_BARCODE.out.metrics)
.mix(TAG_DNA_CELL_BARCODE.out.metrics)
+ ch_barcode_report_files = TAG_DNA_SAMPLE_BARCODE.out.metrics
+ .flatMap { sampleId, counts, stats -> [counts, stats] }
+ .mix(TAG_DNA_MODALITY_BARCODE.out.metrics.flatMap { sampleId, counts, stats -> [counts, stats] })
+ .mix(TAG_DNA_CELL_BARCODE.out.metrics.flatMap { sampleId, counts, tagRecords, statsL1, statsL2, statsL3 ->
+ [counts, statsL1, statsL2, statsL3]
+ })
+
emit:
tagged_fastqs = TAG_DNA_CELL_BARCODE.out.tagged
trimmed_fastqs = TRIM_DNA_FASTQS.out.trimmed
@@ -176,14 +246,15 @@ workflow DNA_CORE {
rg_headers = SPLIT_DNA_READS.out.rg_headers
aligned_bams = ALIGN_DNA.out.bam
aligned_bais = ALIGN_DNA.out.bai
- markeddup_bams = MARK_DUPLICATES_DNA.out.bam
- markeddup_bais = MARK_DUPLICATES_DNA.out.bai
- duplicate_metrics = MARK_DUPLICATES_DNA.out.metrics
+ markeddup_bams = NORMALIZE_DNA_MARKDUPLICATES.out.bam
+ markeddup_bais = NORMALIZE_DNA_MARKDUPLICATES.out.bai
+ duplicate_metrics = NORMALIZE_DNA_MARKDUPLICATES.out.metrics
nodup_bams = SPLIT_DUPLICATES_DNA.out.bam
nodup_bais = SPLIT_DUPLICATES_DNA.out.bai
- coverage_bigwigs = BAM_COVERAGE_DNA.out.bw
- coverage_warnings = BAM_COVERAGE_DNA.out.warnings
+ coverage_bigwigs = NORMALIZE_DNA_BAMCOVERAGE.out.bw
+ coverage_warnings = CHECK_DNA_NODUP_BAM.out.warnings
barcode_reports = ch_barcode_reports
+ barcode_report_files = ch_barcode_report_files
tres_tag_records = TAG_DNA_CELL_BARCODE.out.tres_tag_records
versions = ch_versions
}
diff --git a/subworkflows/local/dna_core/meta.yml b/subworkflows/local/dna_core/meta.yml
index cbebad9..336de97 100644
--- a/subworkflows/local/dna_core/meta.yml
+++ b/subworkflows/local/dna_core/meta.yml
@@ -14,9 +14,12 @@ components:
- "trim/dna/fastqs"
- "split/dna/reads"
- "align/dna"
- - "mark/duplicates/dna"
+ - "gatk4/markduplicates"
+ - "normalize/dna/markduplicates"
- "split/duplicates/dna"
- - "bam/coverage/dna"
+ - "check/dna/nodup/bam"
+ - "deeptools/bamcoverage"
+ - "normalize/dna/bamcoverage"
input:
- ch_dna_samples:
type: tuple
diff --git a/subworkflows/local/rna_core/main.nf b/subworkflows/local/rna_core/main.nf
index 69b7d80..61dcd75 100644
--- a/subworkflows/local/rna_core/main.nf
+++ b/subworkflows/local/rna_core/main.nf
@@ -138,6 +138,13 @@ workflow RNA_CORE {
.mix(TAG_RNA_UMI.out.metrics)
.mix(TAG_RNA_CELL_BARCODE.out.metrics)
+ ch_barcode_report_files = TAG_RNA_SAMPLE_BARCODE.out.metrics
+ .flatMap { sampleId, counts, stats -> [counts, stats] }
+ .mix(TAG_RNA_UMI.out.metrics.flatMap { sampleId, counts -> [counts] })
+ .mix(TAG_RNA_CELL_BARCODE.out.metrics.flatMap { sampleId, counts, tagRecords, statsL1, statsL2, statsL3 ->
+ [counts, statsL1, statsL2, statsL3]
+ })
+
emit:
tagged_fastqs = TAG_RNA_CELL_BARCODE.out.tagged
trimmed_fastqs = TRIM_RNA_FASTQS.out.trimmed
@@ -145,10 +152,13 @@ workflow RNA_CORE {
rg_headers = SPLIT_RNA_READS.out.rg_headers
usam_files = FQ_TO_SAM.out.usam
aligned_solo_dirs = RNA_STARSOLO_ALIGN.out.solo_dir
+ aligned_solo_summaries = RNA_STARSOLO_ALIGN.out.solo_summary
+ aligned_star_logs = RNA_STARSOLO_ALIGN.out.star_log
aligned_filtered_bams = RNA_FILTERED_BAM.out.filtered_bam
aligned_stranded_bigwigs = RNA_COVERAGE.out.stranded_bw
aligned_unstranded_bigwigs = RNA_COVERAGE.out.unstranded_bw
barcode_reports = ch_barcode_reports
+ barcode_report_files = ch_barcode_report_files
tres_tag_records = TAG_RNA_CELL_BARCODE.out.tres_tag_records
versions = ch_versions
}
diff --git a/workflows/treseq.nf b/workflows/treseq.nf
index 2a096c3..85f4032 100644
--- a/workflows/treseq.nf
+++ b/workflows/treseq.nf
@@ -20,6 +20,14 @@ import WorkflowSupport
include { RNA_CORE } from '../subworkflows/local/rna_core'
include { DNA_CORE } from '../subworkflows/local/dna_core'
+include { TRES_REPORT_HTML } from '../modules/local/tres_report_html/main'
+include { FASTQC } from '../modules/nf-core/fastqc/main'
+include { SAMTOOLS_FLAGSTAT } from '../modules/nf-core/samtools/flagstat/main'
+include { SAMTOOLS_STATS } from '../modules/nf-core/samtools/stats/main'
+include { SAMTOOLS_IDXSTATS } from '../modules/nf-core/samtools/idxstats/main'
+include { SAMTOOLS_QUICKCHECK } from '../modules/nf-core/samtools/quickcheck/main'
+include { SAMTOOLS_QUICKCHECK_REPORT } from '../modules/local/samtools_quickcheck_report/main'
+include { MULTIQC } from '../modules/nf-core/multiqc/main'
def toRnaCoreInput(final Map row) {
tuple(
@@ -55,6 +63,26 @@ def samplesheetParseOptions() {
]
}
+def qcMeta(final Map meta, final String id, final String modality, final String stage, final String splitName) {
+ return meta + [
+ id : id,
+ tres_modality : modality,
+ tres_qc_stage : stage,
+ tres_split_name : splitName,
+ ]
+}
+
+def toFastqcInput(final Map row) {
+ final List reads = row.modality == 'dna'
+ ? [row.i1, row.i2, row.r1, row.r2]
+ : [row.i1, row.r1, row.r2]
+
+ return tuple(
+ qcMeta(row, "${row.modality}.${row.id}.raw", row.modality as String, 'raw_fastq', row.id as String),
+ reads.findAll { it }.collect { file(it) }
+ )
+}
+
def validateCoreResourceContract(final List