71 Commits
Author SHA1 Message Date
kemal f4bd9de93b Weekly literature reading list (Jev), tests for the Jev tools, maintenance tools documented
ci / test (3.13) (push) Successful in 4m22s
ci / test (3.12) (push) Successful in 4m31s
2026-10-01 13:37:52 +01:00
kemal 01e60ba817 Automatic issue triage on Gitea (Jev): kind and area labels, missing information, privacy and clinical-use flags
ci / test (3.13) (push) Failing after 12m32s
ci / test (3.12) (push) Failing after 14m59s
2026-10-01 13:23:38 +01:00
kemal 3ed0503bdf Jev maintenance tools: shared client, spec coverage audit, voice check, nightly triage
ci / test (3.13) (push) Successful in 4m32s
ci / test (3.12) (push) Successful in 4m36s
2026-10-01 13:21:36 +01:00
kemal 0ff888e41b Ignore the local claim checker report
ci / test (3.13) (push) Successful in 3m41s
ci / test (3.12) (push) Successful in 3m43s
2026-10-01 13:10:03 +01:00
kemal 783e2a0039 Claim checker for public texts (TypeSafe), measured manifest load times, corrected README timings
ci / test (3.13) (push) Successful in 3m59s
ci / test (3.12) (push) Successful in 4m1s
2026-10-01 13:05:37 +01:00
kemal cab702aa24 Contact address [email protected] for security reports, conduct reports and feedback
ci / test (3.13) (push) Successful in 4m42s
ci / test (3.12) (push) Successful in 4m43s
2026-09-30 16:58:26 +01:00
kemal dc8a5361fb Prepare for public release on Gitea: simurgarray package names, community files, Gitea templates, pseudonymised P6 probe names
ci / test (3.13) (push) Successful in 4m6s
ci / test (3.12) (push) Successful in 4m8s
2026-09-30 12:09:13 +01:00
kemal 7b13720a4f README: badges, full install options, input files, quick start, usage for every command, outputs, performance, development 2026-09-30 11:48:17 +01:00
kemal 21e63089b9 Guard against committed credentials: ignore secret files, secret scan in CI 2026-09-30 08:37:18 +01:00
kemal 6aa398c2e9 CI: fix the Install step (setup-uv already creates .venv) and make sure a C linker exists for the Rust build 2026-09-30 08:29:58 +01:00
kemal 0562a31562 Tidy the repository: remove docs/research and bench, fix references 2026-09-30 08:07:35 +01:00
kemal 8ee0c46bba Apply the brand across the repo: reports, README, guide
* simurg/core/brand.py: single source of the mark geometry, colours, favicon
  and the report header band (scripts/brand now load it from there).
* HTML reports (QC report, compare dashboard, methylation QC): offline SVG
  favicon, indigo header band with the mark, version and a sha256 of the data
  shown; Noto Sans font stack; methylation plots in Okabe-Ito colours.
* README banner, guide logo, brand/blog links; branding brief updated to the
  final identity; Noto (OFL) and Okabe-Ito entries in THIRD_PARTY_NOTICES;
  CHANGELOG (Unreleased).

Unit tests + P5 QC oracle: 285 passed; ruff and mypy clean.
2026-09-30 08:01:30 +01:00
kemal deb8e263b2 Ignore editor lock files (.~lock.*#) 2026-09-30 07:52:07 +01:00
kemal 558c198957 branding: SimurgArray brand kit (mark, wordmark, lockups, icons, templates, guide)
Frontal dotted simurg on a bead grid: gold body and wings, three-dot crown,
red / gold / green channel plumes with peacock eyes. Detailed (31x27), simple
(11x10) and micro (7x7) drawings; dark, light, gold, black, white versions;
outlined Noto Sans wordmark; favicon and app icons; README banner, social
preview, avatar, featured-image template, report corner mark, CLI banner.
Checks: WCAG contrast table, protan/deutan simulation, icon sizes, family
sheet. Blog featured images regenerated with the new mark for consistency.
Geometry shared in scripts/brand/simurg_mark.py.
2026-09-30 07:51:52 +01:00
kemal ba38be122e blog: featured images (1200x630, ~90 KB) and a branding brief
Dotted simurg on a bead grid in the channel colors (red/green, gold bird,
indigo), one motif per post; generated by scripts/blog/make_featured_images.py.
2026-09-30 07:22:20 +01:00
kemal 4ab227e909 blog: five posts on SimurgArray (why, alternatives, impact, public release plan, usage and branding) 2026-09-30 06:24:25 +01:00
kemal af39d0ee6a Release 2.0.0: v2 modules (ArrayTrain, CN/LOH, PGx, methylation QC)
ci / test (3.12) (push) Failing after 9s
ci / test (3.13) (push) Failing after 16s
User guide: ArrayTrain section, v2 commands in the table, v2 accuracy rows,
updated limitations. README status for v2.0.0. Version 2.0.0 (Python package);
the Rust kernels are unchanged and stay simurg_core 1.1.0. uv.lock committed
(uv lock --check clean).

Full suite on the Pi, file by file under the memory guard: 29 files exit 0
(unit: 282 passed), ruff and mypy clean.
2026-09-30 06:24:12 +01:00
kemal 077619a6f1 test_p6_vcf: stream the gtc2vcf oracle output (OUT-012)
The INFO/extra-FORMAT comparison held ~700 000 gtc2vcf records as text plus two
dicts each (> 4.8 GB, stopped by the Pi memory guard). Now written to a temp
file and kept as compact tuples: peak 3.0 GB; all 5 tests pass.
2026-09-30 01:25:32 +01:00
kemal 6d22b5e19b CN: final full-cohort cloud validation (GSE165845, CYTO-041/042 defaults)
360 arrays vs NYGC 30x SV: all samples OK (K-027 gate fix), PASS precision
DEL 44 % / DUP 57 % (first run 39 % / 34 % with filters ignored), 61 % without
the one excess_events array; rare DEL sensitivity 30 %; LOH replicated 85 %.
m7g.4xlarge spot, 17 min. docs/validation/V2_cn.md, K-027.
2026-09-29 23:04:16 +01:00
kemal 1eb7ea8154 ArrayTrain: BIC-selected unbounded θ mixtures + HWE-guided labelling
Fixed θ windows mislabelled compressed/asymmetric loci (2-cluster loci: 1418 vs
186 errors). Now 1/2/3-component mixtures chosen by BIC, labelled by HWE
goodness of fit plus weak position and gap priors, split clusters merged.
GSE165845 chr22 vs 1000G 30x (240 arrays): concordance 99.44 % (v1 99.27 %,
vendor EGT 99.46 %), NRD 1.30 % (1.89 %, 1.23 %), call rate 99.61 %.
docs/validation/V2_arraytrain.md, K-030; plan §12, CLI-038.
2026-09-29 22:40:19 +01:00
kemal adad0efb08 train: loop variable typing (mypy) 2026-09-29 19:54:24 +01:00
kemal 7cfb0fd962 ArrayTrain (plan §12): simurg train — EGT cluster files from a cohort's GTCs
- simurg/train/clusters.py: vectorised per-locus θ mixture (AA/AB/BB + outlier component, θ-ordered bounds),
  cluster selection and merging, lone clusters homozygous, missing clusters imputed by cross-locus regression
  per assay type, cluster_sep and train (GenTrain-field) scores.
- formats/egt.py: write_egt (EGT v3, data block 9, round-trips through the reader).
- pipeline/train.py: normalised θ/R from GTC raw X/Y + transforms, sex-aware (X females, Y males, MT haploid),
  intensity-only loci as one R cluster.
- scripts/train/concordance_chr.py: array vs 1000G 30x on one chromosome.
Demo (36 GSA v4 PGx arrays, chr22 vs 1000G): trained 99.29 % / NRD 2.6 % vs vendor EGT 99.57 % / 1.55 %.
2026-09-29 19:53:53 +01:00
kemal cfae926fbc PGx validation on GSE165845: WGS-derived star truth, 2-fold masks, array-resolvable concordance
- scripts/pgx/wgs_star_truth.py: star alleles from the 1000G 30x phased panel with the DB definitions
  (wildcard-aware haplotype assignment; checked against GeT-RM on the demo CEPH individuals).
- validate_star_getrm.py: --all-genes, --individuals, --coverage (projection onto what the array can see);
  replicate_concordance.py.
- 120 individuals x 3 GSA v1 arrays: array-resolvable 1637/1710 (95.7 %), top 1223/1800 (chip lacks many
  defining variants), GeT-RM subset 28/35, replicates 99.2 % without the failed array (V2_pgx_star.md, K-029).
2026-09-29 19:00:34 +01:00
kemal 3fa97df61e CHANGELOG: v2 CN/LOH/mosaicism and pharmacogenomics 2026-09-29 17:16:10 +01:00
kemal 151723d5e1 docs: user guide sections for CN/LOH/mosaicism and pharmacogenomics 2026-09-29 17:15:43 +01:00
kemal d60a1d5180 tests: PGx demo oracle tests — definition sanity (PGX-023), limitations (PGX-009), determinism (PGX-029), JSON/TSV (PGX-028) 2026-09-29 17:15:09 +01:00
kemal ba8454e2c8 pgx_cn: PFB as float64 for the BAF evidence (mypy) 2026-09-29 17:11:50 +01:00
kemal 1cb7b59559 PGx CN: scan-date batch warning (PCN-006), CN-consistent BAF evidence (PCN-010, --bafs-in-cn),
noise-outlier exclusion + robustness test (PCN-017/EDGE-026), platform from the CSV manifest (CLI-032)

Also: star-allele calls are checked for one manifest/build per run (PGX-011), duplications at the CN cap are
named xN (PGX-022), and tandem names attach supporting variants to their full copy.
2026-09-29 17:11:34 +01:00
kemal ed5e92b859 PGx: ClinPGx variant-based genes (PGX-008) and --guideline dpwg (PGX-025)
- fetch_sources.sh downloads ClinPGx clinicalVariants (CC BY-SA 4.0); pgx db build adds genotype-only
  variant-based genes (levels 1A-2B, level 3 for the parity list), rsIDs resolved from the manifest's probes:
  70 genes in the DB.
- pgx phenotype --guideline dpwg: CPIC mappings for CPIC genes (as ClinPGx curates DPWG), no phenotype for
  DPWG-only genes (flags dpwg_via_cpic_mapping / dpwg_mapping_not_available). K-029 updated.
2026-09-29 17:01:36 +01:00
kemal 9a39ae62fe PGx: PharmVar genes (CYP1A2, CYP2A6, CYP2A13, CYP2C8, CYP3A4), CYP2A6 *4 from CN (PGX-001/006)
fetch_sources.sh downloads PharmVar per-gene zips; pgx db build adds core alleles for genes CPIC does not
define (normalised against the FASTA, *1 = reference). Masks re-derived with the new variants. GeT-RM:
CYP3A4 15/15, CYP2A6 7/9; all comparable genes 154/168 (CYP1A2/CYP2C8 definitions differ from GeT-RM's).
2026-09-29 16:50:27 +01:00
kemal b96ae21c70 PGx: CYP2D6 structures from sub-region CN — *68+*4, *36+*10, *13 (PGX-013/018)
Sub-region CNs (p5, intron 2, exon 9) resolve full copies and *36/*68/*13 units; candidates carry the
tandem names, background alleles, and CPIC activity sums. GeT-RM: CYP2D6 13/15 top (NA12878 *3/*68+*4 and
NA11832 *1/*68+*4 exact), 15/15 within feasible; all genes 132/144.
2026-09-29 16:29:54 +01:00
kemal 9a02f39d01 PGx: all CPIC gene kinds — G6PD, variant-based, HLA tags, *0 CN genes (PGX-006/007/021)
- DB build resolves the PGX-007 tag variants from the manifest's probes; coverage over all gene kinds.
- Variant-based genes reported per variant (rs.. REF/ALT | Reference) with the CPIC lowest-activity diplotype;
  tagging genes as positive/negative with the population caveat; GSTM1/GSTT1/UGT2B17 *0 from targeted CN.
- Case-insensitive phenotype keys (MT-RNR1). GeT-RM check extended to VKORC1 and the CN genes:
  131/144 gene calls (docs/validation/V2_pgx_star.md).
2026-09-29 16:24:33 +01:00
kemal e3f784859b PGx: full call detail (PGX-016..020, 027/028, 031), pgx coverage (PGX-009/035), full HGVS
- supporting_variants.tsv, unresolved_variants.tsv, variants_not_covered.tsv with PGX-026 metadata; per-allele
  supporting/unresolved sites for both alleles of every candidate; variant_change vs top, distant_alternative,
  unexplained_variants, alleles_impacted_by_no_call, alleles_tested.
- simurg pgx coverage: callable / not_covered / masked / equivalent_to per allele and manifest.
- HGVS on GRCh38 RefSeq accessions (NC_...:g.).
2026-09-29 16:16:39 +01:00
kemal f885593e32 PGx phenotypes: pgx phenotype|annotate (PGX-024..028, CLI-034)
CPIC lookups by allele function counts or activity values (duplications N x activity, *5/*0 = 0, total-score
fallback), Indeterminate when feasible solutions disagree or an allele is not in the guideline; per-sample
simurg.pgx/1 JSON and diplotype_annotations.tsv with PGX-026 metadata lines.
2026-09-29 16:03:27 +01:00
kemal 08d7fe6840 derive_masks: keep pysam's downloaded tabix indexes in data/pgx/cache, not the working directory 2026-09-29 16:00:25 +01:00
kemal feb1d993b5 PGx star alleles: pgx star-allele call (PGX-011..021), probe masks vs 1000G, GeT-RM validation (K-029)
- simurg/pgx/star.py: solver-free diplotype enumeration incl. CN forms (deletion, xN), wildcards, array-equivalence
  classes, raw_score/score with CPIC frequency priors; calibrated error model (spec PGX-012 amended).
- pipeline/pgx_star.py: DB gene models, SNV + PGx CN VCF evidence, masks, diplotype_summary.tsv + pgx_calls.json.
- scripts/pgx: derive_masks.py (array vs 1000G 30x over HTTPS, GS calibration), getrm_truth.py,
  validate_star_getrm.py.
- GSA v4 PGx demo vs GeT-RM (16 CEPH): 100/109 gene calls; CYP2D6/2C19/2C9 41/45 (docs/validation/V2_pgx_star.md).
2026-09-29 14:08:03 +01:00
kemal 0c5dd03ca8 PGx DB: pgx db build from CPIC (PGX-001..005, IN-053, CLI-035)
- scripts/pgx/fetch_sources.sh: CPIC API tables (CC0) into a dated folder with version and hashes.
- simurg/pgx/db.py: CPIC HGVS locations and values -> left-normalised VCF variants (SNV, del, ins, dup,
  repeats, delins, chrM); IUPAC values are core-allele wildcards; alleles without definitions are flagged.
- pipeline/pgx_db.py: deterministic SQLite (content-hash name), probe_map via the SNV VCF site mapper;
  GSA v4 PGx: 22 genes, 1354 alleles, 5002 probe links; two builds byte-identical.
2026-09-29 13:24:54 +01:00
kemal c3e0681b6e PGx CN: pgx copy-number train|call (CLI-031/032, PCN-001..017, IN-050), region BED v1, demo identities (K-028)
- simurg/pgx/cn.py: per-region CN mixture, mu_c = delta + gamma*log2((c+1)/3), free lower CN-0 component,
  Hardy-Weinberg-constrained weights over haplotype copy numbers, EM from a grid of label starts.
- pipeline/pgx_cn.py: model file (.simurg-pgxcn), batch rules (PCN-004), per-sample CN VCF + tbi, batch and
  sample summaries.
- The GSA v4 PGx demo arrays are 30 CEPH/1000G individuals (scripts/pgx/demo36_identity.tsv); against NYGC 30x
  SV RD_CN 224/240 region calls agree (GSTM1, UGT2B17 30/30), in-sample (docs/validation/V2_pgx_cn.md).
2026-09-29 13:16:19 +01:00
kemal 518bfbe059 V2 CN: CYTO-042 results (precision up, mosaic calls halved); pi_run reports process memory without page cache 2026-09-29 12:20:40 +01:00
kemal 924b6bb4b7 cn build-model: compute the per-probe LRR spread in column chunks (peak memory hit the 5 GB cap on 120 GSA arrays) 2026-09-29 12:11:38 +01:00
kemal da876b628e CN: per-probe LRR noise from the batch reference (CYTO-042), --probe-lrr-sd/--no-probe-lrr-sd 2026-09-29 12:00:04 +01:00
kemal d5ab45886c cn_validate_truth: sensitivity by carrier frequency (rare < 5 % is the primary metric, K-027) 2026-09-29 11:57:58 +01:00
kemal fa36e550c9 V2 CN validation: Pi tuning rounds, CYTO-041 effect, common-CNV sensitivity limit (K-027) 2026-09-29 11:11:14 +01:00
kemal 803f4aaec3 CN: MF split normalised by per-probe reference BAF noise; genotype-based complete loss (CYTO-041)
The mosaic BAF split is now estimated over heterozygous calls against each probe's expected noise (the
reference heterozygous spread scaled to the sample), inverting the median of |N(+-d, sigma)|. A mosaic loss
lacking the heterozygous calls its PFB predicts gets MF 1 and is promoted (CYTO-020).
2026-09-29 10:56:21 +01:00
kemal 6bc42e53b7 CN: noise-corrected BAF split and complete-loss MF (CYTO-041); Pi tuning harness
Mosaic fraction from the BAF split now subtracts the heterozygous BAF noise (median |BAF-0.5| of unsplit
hets = 0.6745 sigma_b), and a mosaic loss lacking its expected heterozygotes gets MF 1 and is promoted to a
constitutional DEL (CYTO-020). Adds scripts/v2/cn_tune.sh + cn_tune_report.py (GSE165845 rounds on the Pi).
2026-09-29 10:30:12 +01:00
kemal 98e16cf501 pi_run: hard per-job memory cap via a systemd scope (MemoryMax) when the memory cgroup is enabled
The Pi now boots with cgroup_enable=memory cgroup_memory=1; the MemAvailable guard stays as a
second layer and as the fallback on systems without the memory controller.
2026-09-29 08:24:29 +01:00
kemal 98f981b59e CN: per-probe heterozygous BAF spread from the batch reference; --mosaic-prior/--switch-distance; Pi memory guard
scripts/pi_run.sh runs heavy jobs in their own process group and stops them when
MemAvailable drops below a floor (Raspberry Pi OS boots with cgroup_disable=memory, so a
systemd MemoryMax cap is not available); a 360-sample genotype run with cohort QC had
exhausted memory and the OOM killer took down the desktop session.
2026-09-29 07:56:12 +01:00
kemal 6ad0c53664 v2 CN: real-data validation vs NYGC 30x SVs (interim), noise gate on normalised LRR (K-027)
GSE165845 360 arrays: constitutional DEL/DUP calls 77/74 % in the NYGC SV truth, LOH
reproduced across replicates 74 %; mosaic calls are mostly false positives (12-23 %),
sensitivity for 25 kb-1 Mb events 7-13 % at QUAL >= 20. All samples had been flagged
SampleQuality by the summary logr_dev (cluster-file mismatch); the gate now uses the SD
of the LRR after the batch reference. Validation script: --ignore-filter.
2026-09-29 07:42:06 +01:00
kemal 1e41acef27 test: packaged CN data files 2026-09-29 07:07:03 +01:00
kemal b8e3cf233a Track the packaged CN data files (the data/ ignore rule matched src/simurg/cn/data)
Found by the CN cloud validation: mask_GRCh3{7,8}.bed and cytoBand_GRCh3{7,8}.txt.gz were
never committed nor shipped in the wheel. The ignore rule now covers only the top-level data/.
2026-09-29 07:06:47 +01:00
kemal b6e8177e5a v2 CN: truth validation script (NYGC 30x SV freeze V3) and cloud task cnv 2026-09-29 01:39:49 +01:00
kemal 0bf5576049 v2 CN: cn annotate (JSON report, ISCN 2020, cytobands, genes) and the annotation bundle builder
cn call now records per-chromosome and sample statistics (percent het, LRR stats, BAF
deviations, robust LogR dev, call rate) in the sidecar; cn annotate writes
<sample>.cyto.json (CYTO-033) with ISCN microarray/traditional strings (CYTO-034), bands
and RefSeq gene lists (CYTO-035), LOH summaries, weighted median CN (CYTO-026); annotation
bundle from UCSC cytoBand + ncbiRefSeq (CYTO-036, IN-054). Tests for ISCN strings, gene
overlap, sidecar-missing error and an end-to-end call+annotate.
2026-09-29 01:37:56 +01:00
kemal 615a6139bf v2 CN: unit tests (GC windows, PFB, GC-wave, smoothing, HMM DEL/LOH, effective size, thresholds, mask, CLI VCF rules) 2026-09-29 01:32:56 +01:00
kemal 70001a0d6c v2 CN: synthetic implant evaluation (CYTO-022); reference GTC discovery follows symlinks
216 implanted events in 22 synthetic GSA samples (4 replicates per kind x fraction x
size; reference model from 30 other samples): constitutional DEL/DUP 16/16 at 5-20 Mb,
mosaic loss/gain/CN-LOH at 15 % / 5 Mb 12/12.
2026-09-29 01:30:07 +01:00
kemal edb59e4ee2 v2 CN/LOH (WIP): cn build-model and cn call
Cyto model (.simurg-cyto: GC 1 kb/100 kb/1 Mb, PFB from the cluster file, optional
sex-aware batch reference from normal GTCs; IN-051, CYTO-038); GC-wave correction
(CYTO-003); smoothing (CYTO-004); HMM with constitutional, gain-LOH, mosaic and haploid
states, forward-backward QUAL and Viterbi segments (CYTO-005/012); event statistics,
effective size, post-filters, per-type thresholds, promotion/LowFraction, built-in
centromere mask from UCSC cytoBand (CYTO-006..021); sex resolution (CYTO-024), ploidy;
CNV VCF with bgzip+tabix (CYTO-028..031), segments parquet, cn_sample_summary.tsv and
the cn_call_manifest.json sidecar.
2026-09-29 01:13:51 +01:00
kemal 5164124438 v2 methylation QC validated on minfiDataEPIC and against sesame (K-026)
beta r 0.99998 vs sesame 1.28.1 (max |dbeta| 0.011), detection calls 99.1% identical,
noob within 0.5% median; replicate r 0.997; all 21 control metrics pass. Spec deviations
recorded (5-field control lines, pOOBAH formula, minfi sheet keys). User guide section.
2026-09-29 00:41:54 +01:00
kemal 6aebb31991 methylation: combine_neg option; oracle compares both background variants and logs sesame's negative controls 2026-09-29 00:36:44 +01:00
kemal 3a816a1c44 sesame oracle: compare without bead-count masking on both sides 2026-09-29 00:29:25 +01:00
kemal 1aa9459525 sesame oracle: cache EPIC annotation up front 2026-09-29 00:23:24 +01:00
kemal 03587b2b0a sesame oracle: explicit platform, cache fallback 2026-09-29 00:18:17 +01:00
kemal da4a67b59b v2 methylation: sesame oracle scripts and cloud task 2026-09-29 00:14:18 +01:00
kemal 3eb51639cc v2 methylation control QC (WIP): simurg methyl qc|convert-manifest (MET-001..018)
Methylation CSV manifest reader (MET-002/003), raw M/U assembly with bead masking
(MET-005), pOOBAH detection p-values, noob background correction, linear/nonlinear dye
bias, beta and M-values (MET-010..012), the 21 methylation control metrics (MET-006,
bs-conv red-bg set option), per-sample ctrl/cgs tables, summary tsv/xlsx/html with the
detection histogram and a beta PCA, pcs.tsv.gz, controls_raw/controls_qc.tsv; methylation
datasets load in qc report (MET-014); qc controls --array-type methylation; minfi-style
Sentrix_ID/Sentrix_Position sheet keys. Vendor EPIC manifests carry a 5th field on some
control lines: >= 4 fields accepted. Runs on the public minfiDataEPIC set (3 x NA12878).
2026-09-29 00:13:22 +01:00
kemal d235dc5419 Release 1.1.0: compiled kernels (P9) and packaging (P10)
ci / test (3.12) (push) Failing after 9s
ci / test (3.13) (push) Failing after 12s
2026-09-28 23:56:39 +01:00
kemal 0b05b0d346 P10 complete: packaging verified on fresh x86_64 and aarch64 VMs
Wheels (pure + manylinux_2_28 kernels), sdist, Docker image and conda packages built and
installed on fresh Ubuntu 24.04 machines; 225 unit tests pass against the installed
package; the tutorial runs with pip (with and without kernels); GTC/VCF content digests are
identical across pip, Docker and conda on both architectures and equal to the Pi's run.
docs/validation/P10.md; guide: install from wheels, Docker, conda; exit code 141.
2026-09-28 23:53:59 +01:00
kemal 522429b731 CLI: a closed stdout pipe exits 141 silently (was E_INTERNAL); example avoids head under pipefail
Found by the P10 fresh-VM run: `simurg inspect … | head` raised BrokenPipeError, reported as
an internal error, and stopped examples/gsa_demo.sh (set -o pipefail). run_guarded now flushes
stdout inside the guard and maps BrokenPipeError to ExitCode.SIGPIPE (141) without a message.
p10.sh: SKIP_DOCKER/SKIP_CONDA, clearer digest report; p10t.sh runs build+pip+tutorial only.
2026-09-28 23:14:47 +01:00
kemal 035e5ad66f P10 (WIP): release build script, Dockerfile, conda recipes, fresh-VM acceptance task
scripts/build_dist.sh: sdist + pure wheel + manylinux_2_28 kernel wheels (maturin --zig,
both architectures). Dockerfile (multi-stage, kernels included, non-root user).
packaging/conda/{simurg,simurg-core}. scripts/p10/digest.py: platform-independent content
digests of GTC/VCF/summary outputs. Cloud task p10 installs the artifacts on a fresh
Ubuntu VM and runs the tutorial with pip, Docker and conda installs. trial.sh picks the
arm64/amd64 image from the instance type and can run instances in parallel (PARALLEL=1).
Licence files ship in both wheels; Rust crate notices added.
2026-09-28 22:41:56 +01:00
kemal 4d5c9be4ae P9 complete: compiled kernels validated (byte-identical, 78-80 GSA samples/min/core), scaling report
Graviton3 c7g.8xlarge, 360 GSE165845 arrays: 360/360 GTCs identical between the Rust
kernels and the pure-Python paths; 1 worker 78-80 samples/min (pure Python 29.6).
Scaling 1->8 workers efficiency 0.87-0.90; above that the 125 MB/s gp3 disk caps the
run (~620 samples/min) and, on a RAM disk, a fixed per-worker start-up cost limits a
360-sample batch to efficiency 0.48 at 32 workers (K-025). Worker state is pickled once.
docs/validation/P9.md, result JSONs, guide/README/CHANGELOG updates.
2026-09-28 22:32:48 +01:00
kemal d40da1d670 P9: scaling on a RAM disk (bench --work/--clean, cloud task p9b) 2026-09-28 22:04:10 +01:00
kemal f0d3739493 P9 cloud task: install gcc (linker for the Rust build); guide: kernel installation 2026-09-28 21:35:42 +01:00
kemal 587fadbaef bench: format 2026-09-28 21:29:07 +01:00
kemal 95e2338897 P9 (WIP): compiled kernels (rust/simurg-core, PyO3) with bit-identical pure-Python fallback
Rust ports of the hot paths found by profiling: fused per-locus GenCall calling
and scoring, BAF/LRR, libm maps with CPython math semantics, both nearest-neighbour
searches of the normalization fit, and the BPM LocusEntry parser. Address
coverage is memoised per IDAT layout. SIMURG_PURE_PYTHON=1 forces the pure paths.
On the Pi: genotype_sample 3.4 s -> 1.1 s, 36-sample GSA run 131 s -> 46 s, BPM
read 4x faster; 36 GSA + 6 Omni2.5 GTCs and QC tables byte-identical to the pure
path; tests/unit/test_core_kernels.py checks every kernel on edge cases.
bench/profile_genotype.py, bench/scaling.py, cloud task p9 (thread scaling).
2026-09-28 21:28:55 +01:00
251 changed files with 22153 additions and 7872 deletions

No files matched your search

+14
View File
@@ -0,0 +1,14 @@
.git
.venv
data
refs
dist
results
_phase0_archive
**/__pycache__
**/target
*.idat
*.idat.gz
*.bpm
*.egt
*.gtc
+66
View File
@@ -0,0 +1,66 @@
name: Bug report
about: A crash, an error message, or a result that looks wrong
title: "[bug] "
labels: []
body:
- type: markdown
attributes:
value: |
Thank you for reporting. Please do **not** attach vendor files (IDAT, BPM, CSV, EGT, GTC) or any genetic data of real people. An automatic triage reads the text to suggest labels (see CONTRIBUTING.md).
- type: input
id: version
attributes:
label: SimurgArray version
description: Output of `simurg --version`
validations:
required: true
- type: dropdown
id: platform
attributes:
label: Platform
options:
- Linux x86_64
- Linux aarch64 (for example Raspberry Pi)
- Docker
- conda
- other
validations:
required: true
- type: input
id: backend
attributes:
label: Backend
description: Output of `python -c "from simurg._core import backend; print(backend())"`
- type: textarea
id: command
attributes:
label: Command
description: The exact command you ran
render: shell
validations:
required: true
- type: textarea
id: what
attributes:
label: What happened, and what you expected
validations:
required: true
- type: textarea
id: log
attributes:
label: Error message or log
description: Add `--debug` for a traceback. Error codes look like `E_...` or `W_...`.
render: text
- type: textarea
id: manifest
attributes:
label: run_manifest.json
description: Paste or attach the run manifest of the run; it lists versions, options and input checksums.
render: json
- type: checkboxes
id: privacy
attributes:
label: Privacy
options:
- label: I did not attach vendor files or genetic data of real people.
required: true
+1
View File
@@ -0,0 +1 @@
blank_issues_enabled: false
@@ -0,0 +1,24 @@
name: Feature request
about: Suggest a new capability or a change in behaviour
title: "[feature] "
labels: []
body:
- type: textarea
id: problem
attributes:
label: What are you trying to do?
description: The research task or workflow, and where SimurgArray gets in the way.
validations:
required: true
- type: textarea
id: proposal
attributes:
label: What would help?
description: Describe the behaviour you would like. Mention spec items (for example CLI-021) if you know them.
validations:
required: true
- type: textarea
id: validation
attributes:
label: How could it be validated?
description: A public dataset, a reference tool or a paper the result could be checked against.
+16
View File
@@ -0,0 +1,16 @@
## What changes
## Spec items touched
<!-- for example CLI-021, OUT-031; update the spec in the same pull request if behaviour changes -->
## How it was validated
<!-- unit tests, oracle tests you ran, datasets, numbers -->
## Checklist
* [ ] `ruff`, `mypy` and `pytest tests/unit` pass
* [ ] `CHANGELOG.md` updated (Unreleased) if users would notice
* [ ] differences from reference tools recorded in `docs/known_unknowns.md`
* [ ] no vendor data, no genetic data of real people, no credentials
+38
View File
@@ -0,0 +1,38 @@
# Gitea Actions workflow: lint, types, secret scan and unit tests with and without the compiled kernels.
name: ci
on:
push:
pull_request:
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python: ["3.12", "3.13"]
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v5
with:
python-version: ${{ matrix.python }}
- name: Secret scan (no cloud keys or private keys in the repository)
run: |
if git grep -nIE '(AKIA|ASIA)[A-Z0-9]{16}|aws_secret_access_key *=|BEGIN [A-Z ]*PRIVATE KEY|apikey_[0-9a-f]{20,}'; then
echo "::error::credential-like content found"; exit 1
fi
- name: Install
# setup-uv >= 5.x already creates and activates .venv when python-version is set; --clear works either way
run: uv venv --clear && uv pip install -e ".[dev]"
- name: Lint
run: uv run ruff check src tests && uv run ruff format --check src tests
- name: Type check
run: uv run mypy
- name: Unit tests (no downloaded data needed)
run: uv run pytest tests/unit -q
- name: Build the compiled kernels (rust/simurg-core)
run: |
command -v cc >/dev/null || { apt-get update -qq && apt-get install -y -qq gcc >/dev/null; } # Rust needs a C linker
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal
PATH="$HOME/.cargo/bin:$PATH" uv pip install ./rust/simurg-core
- name: Unit tests with the compiled kernels (must equal the pure-Python results)
run: uv run pytest tests/unit -q
+19
View File
@@ -0,0 +1,19 @@
# Gitea Actions workflow: automatic first triage of new issues (scripts/jev/issue_triage.py, TypeSafe Jev).
# Needs the repository secret TYPESAFE_API_KEY; the built-in token applies labels and posts one comment.
name: issue-triage
on:
issues:
types: [opened, edited]
jobs:
triage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Triage
env:
TYPESAFE_API_KEY: ${{ secrets.TYPESAFE_API_KEY }}
GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITEA_API: ${{ github.api_url }}
REPO: ${{ github.repository }}
run: python3 scripts/jev/issue_triage.py --event "$GITHUB_EVENT_PATH"
-25
View File
@@ -1,25 +0,0 @@
# Runs on Gitea Actions (reads .github/workflows) and GitHub Actions.
name: ci
on:
push:
pull_request:
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python: ["3.12", "3.13"]
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v5
with:
python-version: ${{ matrix.python }}
- name: Install
run: uv venv && uv pip install -e ".[dev]"
- name: Lint
run: uv run ruff check src tests && uv run ruff format --check src tests
- name: Type check
run: uv run mypy
- name: Unit tests (no downloaded data needed)
run: uv run pytest tests/unit -q
+19 -1
View File
@@ -1,5 +1,5 @@
# vendor / large data — never commit
data/
/data/
refs/
_phase0_archive/
*.idat
@@ -18,3 +18,21 @@ __pycache__/
target/
.trial-last
results/
# editor lock files
.~lock.*#
# credentials and secrets (never commit)
.aws/
.env
.env.*
*.pem
*.key
*.p12
credentials
.git-credentials
.netrc
# local caches (claim checker and others)
.cache/
# claim checker output (local)
claims_report.md
spec_coverage_report.md
voice_report.md
+73
View File
@@ -1,5 +1,78 @@
# Changelog
## Unreleased
**Maintenance tools (TypeSafe Jev).** Spec coverage audit (152 of 354 testable spec items cited by tests, 23 more
judged covered, 150 without a test), brand voice check, automatic triage of failed nightly runs and of new Gitea
issues (labels, missing information, privacy and clinical use flags), and a weekly literature reading list. See
`CONTRIBUTING.md`.
**Documentation checks.** `scripts/docs/check_claims.py` checks the numeric claims of public texts against the
validation reports (code retrieves evidence, a TypeSafe System One model judges support). Its first run corrected the
manifest loading times (Omni2.5 about 18 s on a Pi, now measured in `docs/validation/P9.md`) and a demo timing
sentence in the README.
**Packaging.** The distributions are now `simurgarray` and `simurgarray-core` (the name `simurg` is taken on
PyPI); the `simurg` command and the `simurg` / `simurg_core` import names are unchanged. The conda recipe no longer pins
the kernel package to the Python package's version (it required `simurg-core == 2.0.0` while the kernels are 1.1.0).
Project URLs in the package metadata.
**Community.** `CONTRIBUTING.md`, `SECURITY.md`, `CODE_OF_CONDUCT.md`, `CITATION.cff`, Gitea issue and pull request
templates; CI moved to `.gitea/workflows/`. Probe names in the P6 oracle examples are replaced by stable pseudonyms.
**Repository tidy-up.** Removed the Phase-0 research notes (`docs/research/`), the P9 benchmark scripts (`bench/`,
`scripts/cloud/tasks/p9*.sh`) and a vendor probe-name list that should never have been committed (also purged from
the git history).
**Branding.** A visual identity (`branding/`, guide in `branding/README.md`): a dotted simurg mark in detailed, simple
and micro drawings, wordmark and lockups, icons, README banner, social preview and featured-image templates, with
contrast and colour-vision checks. HTML reports (QC report, compare dashboard, methylation QC) get a favicon and a
header band with the mark, the software version and a checksum of the data they show. The mark geometry lives in
`simurg/core/brand.py`. Blog posts and featured images in `blog/`.
## 2.0.0 — 2026-09-30 (v2 modules)
The Python package is 2.0.0. The optional Rust kernels are unchanged and stay `simurg_core` 1.1.0.
**Methylation control QC** (`simurg methyl qc`, `simurg methyl convert-manifest`; MET-001 … MET-018): methylation
CSV manifests, the 21 control metrics, pOOBAH detection p-values, noob, linear/nonlinear dye bias, β and M-values,
summary tsv/xlsx/html with a β PCA, per-sample tables; methylation folders load in `simurg qc report`;
`qc controls --array-type methylation`. Checked against sesame (`docs/validation/V2_methylation.md`, K-026).
**Copy number, LOH and mosaicism** (`simurg cn build-model|call|annotate`; CYTO-001 … CYTO-042): GC-wave
correction, sex-aware batch reference, HMM with constitutional, LOH and mosaic states, event statistics and
filters, CNV VCF + segments + sidecar, ISCN 2020 annotation from UCSC tables; noise-normalised mosaic fractions and
complete-loss promotion (CYTO-041), per-probe LRR noise (CYTO-042). Validated on implanted events and on 360
GSE165845 arrays against the NYGC 30x SV callset (`docs/validation/V2_cn.md`, K-027).
**Pharmacogenomics** (`simurg pgx db build|coverage`, `pgx copy-number train|call`, `pgx star-allele call`,
`pgx phenotype`; PCN-001 … PCN-017, PGX-001 … PGX-035): targeted CN for CYP2D6 sub-regions, CYP2A6, GSTM1, GSTT1,
UGT2B17, SULT1A1, CYP2E1 (HWE-constrained compression mixture); a deterministic PGx DB from CPIC, PharmVar and
ClinPGx (70 genes); solver-free diplotype calling with array-equivalence classes, CYP2D6 structures (*5, xN,
*68+*4, *36+*10, *13), G6PD, HLA tags, variant-based and *0 genes; probe masks from 1000G 30x concordance; CPIC and
DPWG phenotypes; per-sample JSON and the TSV set. The GSA v4 PGx demo arrays are 30 CEPH/1000G individuals: region
CN 224/240 vs NYGC SV, gene calls 154/168 vs GeT-RM (`docs/validation/V2_pgx_cn.md`, `V2_pgx_star.md`, K-028, K-029).
**ArrayTrain** (`simurg train`; plan §12): trains EGT cluster files (v3, dbv9) from a cohort's GTCs with sex-aware
sample selection, BIC-selected 1/2/3-cluster θ mixtures, HWE-guided labelling, and missing clusters imputed from
cross-locus relations. On GSE165845 (chr22 vs 1000G 30x) it gives 99.44 % concordance at a 99.61 % call rate;
the vendor EGT gives 99.46 % at 99.15 % (`docs/validation/V2_arraytrain.md`, K-030).
## 1.1.0 — 2026-09-28 (P9, P10)
**Packaging (P10).** `scripts/build_dist.sh` (sdist, pure wheel, manylinux_2_28 kernel wheels for x86_64 and
aarch64), `Dockerfile`, conda recipes (`packaging/conda/`). Verified on fresh x86_64 and aarch64 VMs: pip, Docker
and conda installs give identical outputs (`docs/validation/P10.md`). A closed stdout pipe now exits 141 silently
instead of reporting an internal error.
**Performance (P9).**
Optional compiled kernels `rust/simurg-core` (PyO3): fused GenCall calling and BAF/LRR, libm maps with CPython
semantics, normalization nearest-neighbour searches, BPM parser. Byte-identical outputs to the pure-Python paths
(`SIMURG_PURE_PYTHON=1`); 78–80 GSA samples/min per Graviton3 core (pure Python 30), manifest loading 4× faster.
Address coverage memoised per IDAT layout; worker state pickled once. `bench/profile_genotype.py`,
`bench/scaling.py`. Details and scaling limits: `docs/validation/P9.md`.
## 1.0.0 — 2026-09-28
First release: the v1.0 goals of the master plan (§1.1), built and validated phase by phase (P0–P8).
+30
View File
@@ -0,0 +1,30 @@
cff-version: 1.2.0
message: "If you use SimurgArray in your research, please cite it as below."
title: "SimurgArray: open analysis of Illumina Infinium genotyping arrays"
type: software
authors:
- family-names: "Yaylali"
given-names: "Kemal"
contact:
- family-names: "Yaylali"
given-names: "Kemal"
email: "[email protected]"
version: "2.0.0"
date-released: "2026-09-30"
license: MIT
repository-code: "https://gitea.yaylali.uk/kemal/SimurgArray"
url: "https://gitea.yaylali.uk/kemal/SimurgArray"
abstract: >-
SimurgArray takes Illumina Infinium BeadChip scans (IDAT files) to genotype calls, quality control reports,
VCF and PLINK files, and on to copy number, loss of heterozygosity and mosaicism, pharmacogenomics, cluster file
training and methylation control QC. Its genotype calling reproduces the vendor's GTC files byte for byte on
public data, and every difference from reference tools is documented. Research use only.
keywords:
- genotyping
- microarray
- Infinium
- IDAT
- VCF
- copy number
- pharmacogenomics
- bioinformatics
+30
View File
@@ -0,0 +1,30 @@
# Code of conduct
SimurgArray is a small scientific project. People who use it or contribute to it come from many fields, countries
and levels of experience. This page says how we treat each other here.
## Expected
* Be kind and assume good faith. Most disagreements are about evidence, so bring evidence.
* Criticise code, results and ideas, never people.
* Be patient with newcomers; everyone met their first cluster file once.
* Credit other people's work, including open source projects and papers.
* Respect privacy. Never post genetic data, sample identifiers of real people, or anyone's personal information.
## Not accepted
* Harassment, insults, threats, or discriminatory jokes and language, in any form.
* Sexualised language or imagery.
* Publishing someone else's private information without permission.
* Repeatedly derailing discussions or ignoring a request to stop.
## Scope
This applies to issues, pull requests, commit messages, documentation and any other space of the project, and to
anyone representing the project elsewhere.
## Enforcement
Report problems privately to **[email protected]**. Reports are handled confidentially. The maintainer may edit
or remove contributions and may block people who do not follow this code, starting with a private warning where
that is reasonable.
+102
View File
@@ -0,0 +1,102 @@
# Contributing to SimurgArray
Thank you for looking. SimurgArray is a small research project with strict habits, because its main promise is that
every number can be checked. The rules below keep that promise.
## Before you start
* Read the item in `SIMURGARRAY_FUNCTIONAL_SPEC.md` that your change touches. Behaviour is defined there item by item
(IDs such as `CLI-021` or `OUT-031`); algorithms and their sources are in `SIMURGARRAY_MASTER_PLAN.md`.
* For anything larger than a small fix, open an issue first and describe the change and how you will validate it.
## Setting up
```bash
git clone https://gitea.yaylali.uk/kemal/SimurgArray.git && cd SimurgArray
uv venv && uv pip install -e ".[dev]"
uv pip install ./rust/simurg-core # optional compiled kernels (needs Rust and a C compiler)
uv run pytest tests/unit
```
## The checks every change must pass
```bash
uv run ruff check . && uv run ruff format --check .
uv run mypy
uv run pytest tests/unit
```
CI runs the same checks, a secret scan, and the unit tests with and without the compiled kernels on Python 3.12
and 3.13. If your change touches file formats, calling, QC or outputs, also run the oracle tests
(`uv run pytest tests/oracle`, see the README for the data they need) and say which ones you ran.
## Rules of the house
1. **Cite the spec.** Commit messages and tests name the spec items they implement or change. If behaviour changes,
change the spec item in the same commit.
2. **Science modules are pure.** Code under `signal/`, `genotype/`, `cn/`, `qc/`, `pgx/` and `train/` has no file or
network access; the `pipeline/` layer does the I/O.
3. **Every algorithm names its source** in its docstring: a paper, a public technical note, an expired patent, or an
open source project with a compatible licence.
4. **Licences.** Code from MIT, BSD, Apache 2.0 or Unlicense projects may be adapted with attribution in
`THIRD_PARTY_NOTICES.md`. GPL tools are used only as separate programs for comparison; their code is never copied.
5. **Exact by default.** Default mode stays bit exact with the reference outputs. A cleaner numerical choice goes
behind an explicit option.
6. **Never hide a difference.** When SimurgArray and a reference tool disagree, record it in `docs/known_unknowns.md`
with the date, the evidence and what was decided.
7. **No vendor data and no secrets in the repository.** No IDAT, BPM, CSV, EGT or GTC files from a vendor, no
probe name lists derived from them, no patient or participant data, and no credentials of any kind. Test fixtures
are synthetic or openly licensed. `.gitignore` and the CI secret scan help, but the responsibility is yours.
8. **Plain writing.** Documentation follows the voice in `branding/README.md`: short sentences, numbers instead of
adjectives, and every claim next to its limitation.
## Checking numbers before publishing
Text that quotes results (README, user guide, blog posts, announcements) is checked against the validation reports
before it goes out:
```bash
python scripts/docs/check_claims.py README.md blog/*.md docs/user_guide.md my_draft.txt
```
Code finds every sentence or table row with a number and the passages in `docs/validation/`,
`docs/known_unknowns.md` and the spec that share it; a TypeSafe System One model only judges whether each passage
supports, contradicts or says nothing about the claim. `claims_report.md` lists contradicted claims, claims without
a source, low confidence cases for a person to read, and verified claims. Only this repository's documentation text
is sent to the API, never data. The key comes from `TYPESAFE_API_KEY` or `~/.config/typesafe/credentials` and never
enters the repository; a full check costs well under one cent. `--dry-run` shows the claims and evidence without
calling the API.
## Maintenance tools (TypeSafe Jev)
Small tools in `scripts/jev/` use TypeSafe System One judgments (Jev) where plain code needs semantic understanding.
Code always collects the evidence and decides what to do; the model only answers typed questions. They are never
part of the `simurg` commands, which stay offline. The key comes from `TYPESAFE_API_KEY` or
`~/.config/typesafe/credentials` (a repository secret of the same name for the issue workflow).
* `scripts/docs/check_claims.py FILES`: numeric claims of public texts against the validation reports.
* `scripts/jev/spec_coverage.py`: which spec items have a test; writes `spec_coverage_report.md`.
* `scripts/jev/voice_check.py FILES`: brand voice rules (dashes, banned words, claims without limits, hype, tone).
* `scripts/jev/nightly_triage.py NIGHT`: which known finding explains a failed nightly step; `scripts/nightly.py`
runs it automatically when a night fails.
* `scripts/jev/issue_triage.py`: first triage of new issues (`.gitea/workflows/issue_triage.yml`).
* `scripts/jev/literature_watch.py`: weekly reading list from bioRxiv and PubMed into `data/literature/`.
Each run costs a fraction of a cent; answers are cached in `.cache/jev/`.
## Pull requests
* One topic per pull request, with tests.
* Describe what changed, which spec items it touches, how you validated it, and any new entry in
`docs/known_unknowns.md`.
* Add a line to the `Unreleased` section of `CHANGELOG.md` for anything a user would notice.
## Reporting problems
Use the issue templates. New issues get an automatic first triage (`.gitea/workflows/issue_triage.yml`): the title
and text are sent to the TypeSafe API, which suggests kind and area labels, notes missing information, and flags
personal data, vendor file contents or credentials so they can be removed. A maintainer checks every label. For a wrong or unexpected result, attach the `run_manifest.json` of the run and the exact
command; it records every version, option and input checksum. Please do not attach vendor files or any genetic data
of real people. For security issues see `SECURITY.md`.
Questions and feedback that do not fit an issue are welcome at **[email protected]**.
+28
View File
@@ -0,0 +1,28 @@
# SimurgArray container: the `simurg` CLI with the compiled kernels.
# docker build -t simurg:2.0.0 .
# docker run --rm -v "$PWD":/work simurg:2.0.0 genotype --bpm M.bpm --egt C.egt --idats idats --out run/gtc
# Inputs and outputs live in the mounted /work folder; the image holds no data.
ARG PYTHON=3.12
FROM python:${PYTHON}-slim-bookworm AS build
RUN apt-get update -q && apt-get install -y -q --no-install-recommends curl gcc libc6-dev \
&& rm -rf /var/lib/apt/lists/*
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal
ENV PATH=/root/.cargo/bin:$PATH
WORKDIR /src
COPY pyproject.toml README.md LICENSE THIRD_PARTY_NOTICES.md ./
COPY src ./src
COPY rust/simurg-core ./rust/simurg-core
RUN pip wheel --no-cache-dir --no-deps -w /wheels . ./rust/simurg-core
FROM python:${PYTHON}-slim-bookworm
LABEL org.opencontainers.image.title="SimurgArray" \
org.opencontainers.image.description="Research toolkit for Illumina Infinium genotyping BeadChip data" \
org.opencontainers.image.licenses="MIT"
COPY --from=build /wheels /wheels
RUN pip install --no-cache-dir /wheels/*.whl && rm -rf /wheels \
&& useradd --create-home --uid 1000 simurg
USER simurg
WORKDIR /work
ENTRYPOINT ["simurg"]
CMD ["--help"]
+369 -29
View File
@@ -1,44 +1,384 @@
# SimurgArray
<p align="center"><img src="branding/templates/readme_banner_1280x320.png" alt="SimurgArray: Thirty birds, one picture." width="100%"></p>
Personal research toolkit for Illumina Infinium genotyping BeadChip data
(IDAT → normalization → genotype calling → BAF/LRR → QC → VCF/PLINK; later CN/LOH, PGx, cluster training).
<p align="center">
<a href="https://gitea.yaylali.uk/kemal/SimurgArray/actions"><img src="https://gitea.yaylali.uk/kemal/SimurgArray/actions/workflows/ci.yml/badge.svg?branch=main" alt="CI"></a>
<img src="https://img.shields.io/badge/version-2.0.0-D4A017" alt="Version 2.0.0">
<img src="https://img.shields.io/badge/python-3.12%20%7C%203.13-3776AB?logo=python&logoColor=white" alt="Python 3.12 and 3.13">
<img src="https://img.shields.io/badge/license-MIT-1E2240" alt="MIT licence">
<img src="https://img.shields.io/badge/platform-Linux%20x86__64%20%7C%20aarch64-2F8F5B?logo=linux&logoColor=white" alt="Linux x86_64 and aarch64">
<img src="https://img.shields.io/badge/kernels-Rust%20(optional)-B7410E?logo=rust&logoColor=white" alt="Optional Rust kernels">
<img src="https://img.shields.io/badge/docker-ready-2496ED?logo=docker&logoColor=white" alt="Docker ready">
<img src="https://img.shields.io/badge/runs%20on-Raspberry%20Pi%205-C51A4A?logo=raspberrypi&logoColor=white" alt="Runs on a Raspberry Pi 5">
<img src="https://img.shields.io/badge/use-research%20only-C8453A" alt="Research use only">
</p>
- **SIMURGARRAY_MASTER_PLAN.md** — architecture, algorithms, roadmap
- **SIMURGARRAY_FUNCTIONAL_SPEC.md** — 416 itemised requirements (CLI, inputs, outputs, QC, CN, PGx, methylation, edge cases)
- `docs/validation/` — per-phase validation reports · `docs/known_unknowns.md` — findings log · `docs/research/` — background
<p align="center">
<b>Open analysis of Illumina Infinium genotyping arrays, from IDAT to genotypes, QC, VCF, copy number and pharmacogenomics.</b><br>
<a href="#install">Install</a> · <a href="#quick-start">Quick start</a> · <a href="#usage">Usage</a> ·
<a href="docs/user_guide.md">User guide</a> · <a href="docs/validation/">Validation</a> · <a href="CHANGELOG.md">Changelog</a>
</p>
## Status
SimurgArray reads the raw scanner files of Infinium BeadChips and takes them all the way to analysis ready outputs.
Its genotype calling reproduces the vendor's GTC files byte for byte on public data, every algorithm names its
source, and every place where it differs from a reference tool is written down in `docs/known_unknowns.md`.
It runs on anything from a Raspberry Pi to a cloud server.
**v1.0.0** (2026-09-28) — see `CHANGELOG.md`. IDAT → normalization → GenCall-equivalent genotype calling → GTC v5 →
sample/control QC with an HTML report → plus-strand VCF/BCF → PLINK 1/2, bedGraph, final report; plus a
differential-testing harness. Validation (`docs/validation/`):
> **Research use only.** SimurgArray is not a medical device and must not be used for diagnosis or treatment
> decisions, including its pharmacogenomics output.
## Contents
* [Features](#features)
* [Validation](#validation)
* [Requirements](#requirements)
* [Install](#install)
* [Input files](#input-files)
* [Quick start](#quick-start)
* [Usage](#usage)
* [Outputs at a glance](#outputs-at-a-glance)
* [Performance and memory](#performance-and-memory)
* [Development](#development)
* [Repository layout](#repository-layout)
* [Documentation](#documentation)
* [Feedback and support](#feedback-and-support)
* [Citing](#citing)
* [Licence, data and trademarks](#licence-data-and-trademarks)
## Features
| | Area | What you get |
|---|---|---|
| 🧬 | **Genotyping** | IDAT → normalization → GenCall equivalent calls, scores, BAF and LRR → GTC v3/v5, bit exact with the vendor software (`--preset current` or `autocall-1.6.2`) |
| 📊 | **Quality control** | 21 control probe metrics, sample QC, BAF regression contamination, KING kinship and Mendel errors, sex checks, per locus summaries, and a self contained interactive HTML report |
| 📄 | **Outputs** | Plus strand VCF/BCF with tabix/CSI indexes, PLINK 1 and 2, bedGraph tracks, final reports and genotype matrices, all written natively |
| 🪶 | **ArrayTrain** | Train your own EGT cluster file from a cohort's GTCs instead of borrowing one |
| 🧩 | **Copy number** | Genome wide CNV, LOH and mosaicism calling with an HMM, ISCN 2020 annotation, cytobands and genes |
| 💊 | **Pharmacogenomics** | Targeted copy number (CYP2D6 and others), star allele diplotypes for 70 genes, CPIC and DPWG phenotypes, from open databases |
| 🧪 | **Methylation QC** | EPIC and MSA control metrics, pOOBAH detection, noob, dye bias correction, β and M values |
| 🔍 | **Differential testing** | `simurg compare` checks two runs field by field (EXACT / NEAR / DISCREPANCY / UNKNOWN) with an HTML dashboard |
| ⚡ | **Speed** | Optional Rust kernels with identical outputs: about 80 GSA samples a minute per server core, about one sample a second on a Pi core |
## Validation
Each phase has its own report in `docs/validation/`.
| Check | Result |
|---|---|
| 2141 vendor GTCs, 1000 Genomes Omni2.5 (`--preset autocall-1.6.2`) | normalization bit-identical; GTCs byte-identical in 2138/2141 |
| GSA demo vs gtc2vcf, GTCtoVCF, plink2 | zero unexplained differences |
| 1000 Genomes pedigrees (Omni2.5) | 717/717 parent–offspring pairs; Mendel error median 0.031 % |
| 2141 vendor GTCs, 1000 Genomes Omni2.5 (`--preset autocall-1.6.2`) | normalization bit identical; GTCs byte identical in 2138/2141 |
| GSA demo vs gtc2vcf, GTCtoVCF and plink2 | zero unexplained differences |
| 1000 Genomes pedigrees (Omni2.5) | 717/717 parent and offspring pairs; median Mendel error 0.031 % |
| 360 GSA arrays (GSE165845) vs NYGC 30x WGS / GIAB HG001 | concordance 0.9934 / 0.9985; replicates 0.9966 |
| ArrayTrain cluster file, GSE165845 chr22 vs 1000G 30x | 99.44 % concordance (vendor file 99.46 %) at a 99.61 % call rate |
| Copy number, 360 GSE165845 arrays vs NYGC 30x SV | PASS precision DEL 44 % / DUP 57 %; rare deletions found 30 % |
| Pharmacogenomics, GSA v4 demo vs GeT RM | 154/168 gene calls |
| Methylation QC vs sesame | β r = 0.99998 |
Commands: `simurg inspect`, `ingest`, `normalize`, `genotype`, `qc controls|samples|contamination|relatedness|loci|report|suggest-thresholds`,
`gtc-to-vcf`, `export plink|bedgraph|finalreport|locus-summary`, `compare`. **User guide: `docs/user_guide.md`**;
worked example: `examples/gsa_demo.sh`. Next (plan §18): P9 performance (compiled core), P10 packaging, then v2
modules (cluster training, CN/LOH, PGx).
## Requirements
* **Python 3.12 or 3.13** on 64 bit Linux (x86_64 or aarch64). Tested on Ubuntu 24.04 and Raspberry Pi OS.
* **Memory:** about 2 to 3 GB per worker process for GSA or Omni sized arrays. 8 GB is enough for a Pi with two workers.
* **Optional:** Rust and a C compiler for the compiled kernels; Docker or conda for those installs.
* The Python package is called `simurgarray`; the command and the import name are `simurg`.
* Only pure Python dependencies are needed (numpy, pyarrow, typer, rich, pyyaml, openpyxl). bcftools and plink2
are **not** required; SimurgArray writes VCF, BCF, indexes and PLINK files itself. They are used only as test oracles.
## Install
### From source (recommended)
With [uv](https://docs.astral.sh/uv/):
```bash
git clone https://gitea.yaylali.uk/kemal/SimurgArray.git
cd SimurgArray
uv venv && uv pip install -e . # add ".[dev]" for tests, ruff and mypy
source .venv/bin/activate
simurg --version
```
With plain pip:
```bash
python3 -m venv .venv && .venv/bin/pip install -e .
```
### Optional compiled kernels
Three to four times faster genotyping and four times faster manifest loading. Results are byte identical.
```bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal # Rust (needs gcc or clang)
uv pip install ./rust/simurg-core
python -c "from simurg._core import backend; print(backend())" # prints: rust 1.1.0
```
Without the kernels the same code runs in pure Python and NumPy. `SIMURG_PURE_PYTHON=1` forces that path.
### From release files
`bash scripts/build_dist.sh` writes a pure wheel, an sdist and `manylinux_2_28` kernel wheels for x86_64 and
aarch64 (glibc 2.28 or newer) to `dist/`:
```bash
python3 -m venv simurg-env
simurg-env/bin/pip install simurgarray-2.0.0-py3-none-any.whl \
simurgarray_core-1.1.0-cp312-abi3-manylinux_2_28_$(uname -m).whl # the kernel wheel is optional
```
### Docker
The image is about 550 MB, includes the kernels and runs as a non root user. Your data stay in the mounted folder.
```bash
docker build -t simurg:2.0.0 .
docker run --rm --user "$(id -u):$(id -g)" -v "$PWD":/work simurg:2.0.0 \
genotype --bpm M.bpm --egt C.egt --idats idats --out run/gtc
```
### conda
```bash
conda build -c conda-forge --output-folder conda-bld packaging/conda/simurg-core packaging/conda/simurg
conda create -n simurgarray -c ./conda-bld -c conda-forge simurgarray simurgarray-core
```
All installs give identical results on x86_64 and aarch64 (`docs/validation/P10.md`).
## Input files
| File | Needed by | Notes |
|---|---|---|
| **IDAT pairs** (`<barcode>_<RxxCxx>_Grn.idat` and `_Red.idat`, optionally `.gz`) | `genotype`, `qc controls`, `methyl qc` | searched recursively; the sample ID is `<barcode>_<position>` |
| **BPM manifest** | almost every command | loci, bead addresses, normalization bins, positions; its genome build sets the VCF build |
| **EGT cluster file** | `genotype`, `qc loci` | from the vendor, or trained with `simurg train` |
| **CSV manifest** | `gtc-to-vcf` (indels), `export finalreport`, PGx | same product and version as the BPM |
| **Reference FASTA** | `gtc-to-vcf`, `cn`, `pgx` | GRCh38 or GRCh37, plain or bgzip; `bash scripts/fetch_data.sh p6` downloads GRCh38 |
| **Sample sheet** (optional) | most commands | `Sample_ID`, `Sample_Name`, `Sample_Group`, `Parent1`/`Parent2`, sex and custom columns |
Manifests and cluster files come from the array vendor's support pages for your product. They are licensed by
the vendor and are **never** committed to this repository; `.gitignore` blocks IDAT, BPM, EGT and GTC files.
## Quick start
A complete run on the public GSA v4 PGx demo (36 samples):
```bash
uv venv && uv pip install -e ".[dev]"
uv run pytest tests/unit # no downloads needed
bash scripts/bootstrap_refs.sh # reference open-source repos → refs/ (oracles)
bash scripts/fetch_data.sh p0 # ~1.4 GB of public test data → data/
bash scripts/make_oracle_gtcs.sh # builds gtc2vcf, writes oracle GTCs
bash scripts/make_oracle_qc.sh # locus-summary oracle (BeadArrayFiles, separate venv)
bash scripts/fetch_data.sh p6 # GRCh38 FASTA (~0.9 GB download, 3.1 GB unpacked)
bash scripts/make_oracle_vcf.sh # gtc2vcf oracle VCF for the P6 tests
uv run pytest tests/oracle # real-data acceptance tests (add -m "not slow" to skip the long ones)
uv run simurg inspect data/p0/gsa_v4_pgx/idats_Demo_36/idats_Demo_36/207895980019/207895980019_R03C01_Grn.idat
bash examples/gsa_demo.sh results/gsa_demo 6 # end-to-end run on 6 demo samples
bash scripts/fetch_data.sh p0 # demo IDATs, manifest and cluster file (~1.4 GB)
bash scripts/fetch_data.sh p6 # GRCh38 FASTA for VCF output (~0.9 GB download)
bash examples/gsa_demo.sh results/gsa_demo 6 # end to end on 6 samples; drop the 6 for all 36
```
Vendor data files are downloaded for personal research use only and are never committed. See `THIRD_PARTY_NOTICES.md`.
The demo writes GTCs, a sample summary, an HTML QC report, per sample VCFs and a cohort BCF, PLINK files, bedGraph
tracks and a final report to `results/gsa_demo/`. On a Raspberry Pi 5 the whole demo for all 36 samples (genotyping, QC report, VCFs and exports) takes about ten minutes with two workers.
## Usage
Every command prints its options with `simurg COMMAND --help`. Global options on every command: `--quiet`,
`--log-level`, `--log-json` (JSON Lines on stderr) and `--debug`.
### Look inside files
```bash
simurg inspect idats/204112350001_R01C01_Grn.idat GSA.bpm GSA.egt
simurg inspect run/gtc/samples/S1/S1.gtc --json
```
### Genotype: IDAT → GTC
```bash
simurg genotype --bpm GSA.bpm --egt GSA.egt --csv GSA.csv \
--idats idats/ --sheet SampleSheet.csv --out run/gtc --threads 0
```
* `--threads 0` uses every core. On an 8 GB machine keep it at 2 or 3.
* `--preset current` (default) behaves like the current vendor software; `--preset autocall-1.6.2` reproduces
the legacy AutoCall GTCs. `--cutoff` sets the GenCall no call threshold (0.15).
* Writes one GTC per sample, `sample_summary.tsv`, control probe QC (`controls_qc.tsv`), relatedness, and
`run_manifest.json` with every version, option and input checksum.
### Quality control
```bash
simurg qc report --data run/gtc --out run/qc_report --output-format both # HTML report + xlsx/csv table
simurg qc samples --bpm GSA.bpm --gtcs run/gtc --out run/qc
simurg qc contamination --bpm GSA.bpm --gtcs run/gtc --out run/qc
simurg qc relatedness --bpm GSA.bpm --gtcs run/gtc --sheet SampleSheet.csv --out run/qc
simurg qc loci --bpm GSA.bpm --egt GSA.egt --gtcs run/gtc --out run/qc
simurg qc controls --array-type genotyping --idats idats/ --out run/controls # no genotyping needed
simurg qc suggest-thresholds --data run/gtc --out thresholds.yaml
```
The HTML report is a single file you can share: linked views, a thresholds editor, chip and plate heatmaps, trend
plots and a PCA card. Use `--no-metadata` or `--drop-metadata COL` before sharing reports with sample sheet columns.
### VCF and exports
```bash
simurg gtc-to-vcf --bpm GSA.bpm --csv GSA.csv --fasta GRCh38.fa --gtcs run/gtc --out run/vcf # per sample
simurg gtc-to-vcf --bpm GSA.bpm --csv GSA.csv --fasta GRCh38.fa --gtcs run/gtc --out run/bcf --merge # one cohort BCF
simurg export plink --vcfs run/vcf --gtcs run/gtc --out run/plink --format both # .bed/.bim/.fam + .pgen/.pvar/.psam
simurg export bedgraph --bpm GSA.bpm --gtcs run/gtc --out run/tracks --chrom-style ucsc
simurg export finalreport --bpm GSA.bpm --csv GSA.csv --egt GSA.egt --gtcs run/gtc --out run/report # --matrix for loci × samples
```
Useful `gtc-to-vcf` options: `--info-fields`, `--extra-format`, `--merge-snv-indel`, `--auxiliary-loci`,
`--filter-gs`, `--drop-ambiguous`, `--ploidy-policy sex-aware|diploid`, `--include-loci` and `--exclude-loci`.
### Train your own cluster file (ArrayTrain)
```bash
simurg train --gtcs cohort_gtc --bpm GSA.bpm --out mycohort.egt # at least 100 GTCs
simurg genotype --bpm GSA.bpm --egt mycohort.egt --idats new_idats/ --out run2/gtc
```
Training reads raw intensities, not genotypes, so it does not matter which cluster file the cohort was first
called with. Samples are chosen by sex for X and Y loci. See `docs/validation/V2_arraytrain.md`.
### Copy number, LOH and mosaicism
```bash
simurg cn build-model --bpm GSA.bpm --fasta GRCh38.fa --egt GSA.egt --reference-gtcs normals/ --out gsa.simurg-cyto
simurg cn call --bpm GSA.bpm --model gsa.simurg-cyto --gtcs run/gtc --fasta GRCh38.fa --out run/cn
simurg cn annotate --vcfs run/cn
```
Build the model once per manifest and batch from at least 24 normal samples. Each sample gets a CNV VCF,
a segments file and, after `annotate`, ISCN strings with cytobands and genes.
### Pharmacogenomics (GRCh38)
```bash
bash scripts/pgx/fetch_sources.sh # CPIC, PharmVar, ClinPGx → data/pgx/sources
simurg pgx db build --sources data/pgx/sources --fasta GRCh38.fa --manifests GSA_PGx.bpm --csv GSA_PGx.csv --out pgxdb/
simurg pgx coverage --bpm GSA_PGx.bpm --db pgxdb/pgx_db.sqlite # which alleles this array can call
simurg pgx copy-number train --gtcs cohort/ --bpm GSA_PGx.bpm --csv GSA_PGx.csv --fasta GRCh38.fa --out cnmodel/
simurg pgx copy-number call --gtcs run/gtc --model cnmodel/GSA_PGx.simurg-pgxcn --fasta GRCh38.fa --out run/vcf
simurg gtc-to-vcf --gtcs run/gtc --bpm GSA_PGx.bpm --csv GSA_PGx.csv --fasta GRCh38.fa --out run/vcf
simurg pgx star-allele call --vcfs run/vcf --db pgxdb/pgx_db.sqlite --out run/pgx
simurg pgx phenotype --calls run/pgx --db pgxdb/pgx_db.sqlite --guideline cpic # or dpwg
```
`pgx db build` names the database after its content hash (`pgx_db-1-<sha12>.sqlite`); use that file name.
Copy number training needs at least 96 samples. Outputs per sample: diplotypes, supporting and missing variants,
alternative diplotypes the array cannot tell apart, and a JSON report with phenotype and evidence.
### Methylation arrays
```bash
simurg methyl qc --manifest EPIC_manifest.csv --idats idats/ --sheet SampleSheet.csv --out run/methyl --profile auto
simurg methyl convert-manifest --manifest EPIC_manifest.csv --out manifest_tables/
```
### Compare two runs
```bash
simurg compare runA/gtc runB/gtc --out compare_report --fail-on-discrepancy
```
Every field of every GTC or VCF pair is compared. `compare_report/dashboard.html` shows the result and
`discrepancies.tsv.gz` lists every difference.
### Exit codes
`0` success · `1` internal error · `2` usage or validation error (nothing processed) · `3` some samples failed, or
`compare --fail-on-discrepancy` found differences · `4` no sample succeeded · `130`/`143` interrupted.
Every error and warning has a stable code (`E_…`, `W_…`) listed in `docs/messages.md`.
## Outputs at a glance
| Step | Main files |
|---|---|
| `genotype` | `samples/<id>/<id>.gtc`, `sample_summary.tsv`, `controls_qc.tsv`, `relatedness.tsv`, `run_manifest.json` |
| `qc samples` | `sample_qc.tsv`, `contamination.tsv`, `relatedness.tsv` (+ `mendel.tsv` with parents in the sheet) |
| `qc report` | `qc_report_<date>.html`, `qc_table_<date>.xlsx` |
| `gtc-to-vcf` | `<id>.snv.vcf.gz` + `.tbi`, or `cohort.snv.bcf` + `.csi` |
| `export plink` | `.bed/.bim/.fam`, `.pgen/.pvar/.psam` |
| `cn call` | `<id>.cyto.cnv.vcf.gz`, `<id>.cn_segments.parquet`, `cn_sample_summary.tsv` |
| `pgx phenotype` | `<id>.pgx.json`, `diplotype_summary.tsv`, `diplotype_annotations.tsv` |
| `train` | `<name>.egt`, `<name>.egt.json` |
Every HTML report carries the software version and a checksum of the data it shows.
## Performance and memory
* With the kernels a GSA sample takes about 1.1 s on one Raspberry Pi 5 core (3.4 s pure Python) and a server core
handles about 80 samples a minute (`docs/validation/P9.md`).
* Loading a manifest is a fixed cost per command: about 4 s for GSA and 18 s for Omni2.5 on a Pi with the kernels.
* Cohort QC steps grow with samples × loci. On small machines use `--threads 2`, and `--no-cohort-qc` on very
large `genotype` runs, then run the `qc` commands separately.
* `simurg train` needs about 2 GB for 120 GSA samples and takes about 70 minutes on a Pi.
## Development
```bash
uv venv && uv pip install -e ".[dev]"
uv run ruff check . && uv run ruff format --check .
uv run mypy
uv run pytest tests/unit # no downloads needed
```
Oracle tests compare against reference tools on real public data:
```bash
bash scripts/bootstrap_refs.sh # reference open source repositories → refs/
bash scripts/fetch_data.sh p0 # public test data → data/
bash scripts/make_oracle_gtcs.sh # builds gtc2vcf and writes oracle GTCs
bash scripts/make_oracle_qc.sh # locus summary oracle (BeadArrayFiles)
bash scripts/fetch_data.sh p6 && bash scripts/make_oracle_vcf.sh
uv run pytest tests/oracle # add -m "not slow" to skip the long ones
```
Before publishing text with numbers, `python scripts/docs/check_claims.py FILES` checks every claim against the
validation reports (see `CONTRIBUTING.md`).
CI runs lint, type checks, a secret scan and the unit tests with and without the Rust kernels on Python 3.12 and
3.13 for every push. `scripts/nightly.py` reruns the differential tests against the oracles.
## Repository layout
```
src/simurg/ the package: formats, signal, genotype, qc, harmonize, cn, pgx, train, pipeline, cli
rust/simurg-core/ optional compiled kernels (PyO3)
tests/ unit and oracle tests
scripts/ data fetchers, oracle builders, validation and cloud helpers, brand and blog image scripts
docs/ user guide, messages, validation reports, known unknowns
examples/ end to end demo
branding/ logo, icons, templates and the brand guide
blog/ five posts about the project, with featured images
packaging/ conda recipes (plus Dockerfile at the root)
.gitea/ CI workflow, issue and pull request templates
```
## Documentation
* [`docs/user_guide.md`](docs/user_guide.md): every command in detail, presets, QC, outputs, accuracy, limits, troubleshooting
* [`SIMURGARRAY_FUNCTIONAL_SPEC.md`](SIMURGARRAY_FUNCTIONAL_SPEC.md): 416 numbered requirements (CLI, inputs, outputs, QC, CN, PGx, methylation, edge cases)
* [`SIMURGARRAY_MASTER_PLAN.md`](SIMURGARRAY_MASTER_PLAN.md): architecture, algorithms with their sources, roadmap
* [`docs/validation/`](docs/validation/): one report per phase and module
* [`docs/known_unknowns.md`](docs/known_unknowns.md): every difference from reference tools, with dates and explanations
* [`docs/messages.md`](docs/messages.md): all error and warning codes
* [`CONTRIBUTING.md`](CONTRIBUTING.md), [`SECURITY.md`](SECURITY.md), [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md)
* [`branding/README.md`](branding/README.md) and [`blog/`](blog/)
## Feedback and support
Bug reports and feature requests go to the [issue tracker](https://gitea.yaylali.uk/kemal/SimurgArray/issues), using
the templates. Questions, feedback and anything that should not be public, such as security reports, go to
**[email protected]**.
## Citing
If SimurgArray helps your research, please cite it using [`CITATION.cff`](CITATION.cff) (version 2.0.0, 2026).
## Licence, data and trademarks
SimurgArray is released under the [MIT licence](LICENSE). Code adapted from MIT, BSD and Apache licensed projects
is credited in [`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md); GPL tools are only run as separate programs for
comparison. Brand artwork is CC BY 4.0.
Vendor manifests, cluster files and scan data are downloaded by each user for their own research and are never
part of this repository. PGx sources keep their own terms (CPIC CC0, PharmVar terms of use, ClinPGx CC BY SA 4.0);
SimurgArray ships the database builder, not the database.
Illumina, Infinium, GenCall, GenTrain and GenomeStudio are trademarks of Illumina, Inc. SimurgArray is an
independent project, not affiliated with or endorsed by Illumina.
+32
View File
@@ -0,0 +1,32 @@
# Security policy
## Supported versions
Security fixes go into the latest release. Older releases are not patched; upgrade to the newest version.
## Reporting a vulnerability
Please do not open a public issue for a security problem. Write privately to **[email protected]** and include:
* the SimurgArray version (`simurg --version`),
* what an attacker could do and under which conditions,
* the smallest input or command that shows the problem, without real genetic data.
You will get an answer within a week. Once a fix is released, the report is credited in `CHANGELOG.md` unless you
prefer otherwise.
## What counts
SimurgArray reads files that users download from third parties. Problems worth reporting include:
* crafted IDAT, BPM, CSV, EGT, GTC, VCF or sample sheet files that crash the reader in an unsafe way, write outside
the output folder, or execute code;
* HTML reports that run script from their input data (reports are meant to be safe to open and share);
* anything that could leak sample sheet metadata or genetic data beyond what the user chose to include.
## Handling genetic data
Genotype data are personal data. SimurgArray never sends data anywhere: it has no network access at run time and
its reports embed everything they need. Users are responsible for storing and sharing outputs according to their
consent and data protection rules. The QC report offers `--no-metadata`, `--drop-metadata` and `--keep-metadata` to
control what it contains.
+23 -1
View File
@@ -2435,6 +2435,23 @@ about **algorithms or numerics**, the plan wins. Each such conflict found during
Each yields valid, possibly empty, VCF and JSON output (EDGE-024). (src: E-35)
- **CYTO-041** `§10.3 · v2` **MF refinements [OURS].** Two refinements of CYTO-018, from real-data validation
(docs/validation/V2_cn.md, K-027):
- *noise-corrected split:* per-probe expected noise σ_i = the reference's heterozygous BAF spread of the probe ×
the sample's scale (median |BAF − 0.5| / spread over autosomal heterozygous calls, ÷ 0.6745; the sample's
heterozygous BAF SD without a reference spread). Over the event's heterozygous calls, m = median(|BAF − 0.5| /
σ_i); the split in σ units δ solves Φ(m − δ) − Φ(−m − δ) = ½ (δ = 0 when m ≤ 0.6745) and d = median(σ_i)·δ.
Without this, noise alone gave MF ≈ 0.1–0.3 and genomic waves were called as mosaic losses.
- *complete loss:* a mosaic loss whose called genotypes hold fewer than a quarter of the heterozygotes the PFB
predicts (Σ 2p(1−p) ≥ 3) has MF = 1. With the default `--max-mosaic-fraction 1.0` it is therefore promoted
(CYTO-020) to a constitutional DEL with `HIGHFRACTION`. This catches constitutional deletions whose LRR is
compressed towards the mosaic states.
- **CYTO-042** `§10.2 · v2` **Per-probe LRR noise [OURS].** A model built with `--reference-gtcs` stores each
probe's robust LRR SD across the reference (1.4826·MAD after removing each sample's median and the probe's
reference median). `cn call` scales the sample's LRR emission SD per probe by that spread relative to the autosomal
median spread, clipped to [0.5, 3]. Without the column, or with `--no-probe-lrr-sd`, every probe uses the sample SD.
---
## 7. Targeted PGx copy number (v2)
@@ -2742,7 +2759,10 @@ about **algorithms or numerics**, the plan wins. Each such conflict found during
In a region whose CN is n ≠ 2, the variant copy number `k ∈ {0..n}` is the maximum-likelihood value under the
observed BAF ~ N(k/n, σ²), with σ estimated per batch from AB clusters. It is reported as `variant_copy_number`.
GS enters as a per-call error rate: ε(GS) = 0.5·(1 − GS)², clipped to [1e-4, 0.25] [OURS]. (src: B-30, E-41)
GS enters as a per-call error rate: ε = 1e-3 for GS ≥ 0.15 and 0.05 below [OURS, calibrated: after probe masking
(PGX-010), 0 of 9 740 GSA v4 PGx calls at DB variants disagreed with 1000G 30x in any GS bin, so errors are
probe-specific and belong in the mask; the earlier ε(GS) = 0.5·(1 − GS)² made correct low-GS calls such as
CYP2C9 rs1799853 at GS 0.16 lose to the prior; K-029]. (src: B-30, E-41)
- **PGX-013** `§11 · v2` **Candidate enumeration [DIFF: solver-free].**
- For each gene, SimurgArray enumerates diplotypes from the gene's haplotypes: star alleles, `*0`, duplications
@@ -3710,6 +3730,8 @@ Generated from the item tags (`build.py`). Phases: P0–P10 as in plan §18; `v2
| CYTO-038 | Model building | §10 | v2 | A-G52 |
| CYTO-039 | Batch scale | §10, §19 | v2 | D-9, E-35 |
| CYTO-040 | Degenerate samples | §10 | v2 | E-35 |
| CYTO-041 | MF refinements | §10.3 | v2 | K-027 |
| CYTO-042 | Per-probe LRR noise | §10.2 | v2 | K-027 |
| PCN-001 | Region catalogue | §11 | v2 | B-23, C-G25, D-10 |
| PCN-002 | Genotype every region [EMU] | §11 | v2 | B-23 |
| PCN-003 | Inputs | §11 | v2 | A-G37 |
+1 -4
View File
@@ -136,8 +136,6 @@ curl -LsSf https://astral.sh/uv/install.sh | sh
uv python install 3.12
# Rust (Phase 9)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
# GitHub CLI (authenticate to avoid API rate limits)
sudo apt install -y gh && gh auth login
# Reference/oracle tools (subprocess only)
# gtc2vcf plugins for bcftools: build from https://github.com/freeseek/gtc2vcf (instructions in its README)
# plink2: https://www.cog-genomics.org/plink/2.0/
@@ -162,7 +160,7 @@ sudo apt install -y gh && gh auth login
| maturin + PyO3 (Phase 9) | Rust extension |
### 3.5 Moving the project
The canonical repository is the private Gitea repo **https://gitea.yaylali.uk/kemal/SimurgArray**.
The canonical repository is the Gitea repo **https://gitea.yaylali.uk/kemal/SimurgArray**.
```bash
# on the new machine
git clone https://gitea.yaylali.uk/kemal/SimurgArray.git && cd SimurgArray
@@ -218,7 +216,6 @@ simurg/
├── tests/
│ ├── unit/ property/ integration/ regression/ oracle/ perf/
│ └── fixtures/ # ONLY redistributable data (Bioconductor Artistic-2.0 files, synthetic)
├── bench/
├── docs/ # user guide, algorithm notes, validation reports
├── refs/ # (git-ignored) cloned third-party repos
└── data/ # (git-ignored) downloaded datasets
+8
View File
@@ -12,7 +12,15 @@ used only as external subprocess oracles and are not copied or linked.
| [klib `ksort.h`](https://github.com/attractivechaos/klib) as shipped in htslib — Copyright (c) 2008, 2012-2013, 2017-2019 Genome Research Ltd | MIT | Quickselect `ks_ksmall` partition order, ported to `simurg/qc/contamination.py` (`ks_ksmall`) to reproduce BAFregress medians |
| [Illumina GTCtoVCF](https://github.com/Illumina/GTCtoVCF) — Copyright Illumina, Inc. | Apache-2.0 | Indel source-sequence handling ported to `simurg/harmonize/sites.py` (design-strand orientation, left shift, IUPAC flank matching, deletion/insertion context score); multi-probe consistency idea in `simurg/harmonize/combine.py`; test oracle (run under Python 3 with two local compatibility patches, never shipped) |
| [Picard `picard.arrays`](https://github.com/broadinstitute/picard) | MIT | Second format reference |
| [PyO3](https://github.com/PyO3/pyo3), [rust-numpy](https://github.com/PyO3/rust-numpy), [ndarray](https://github.com/rust-ndarray/ndarray) and their Rust dependencies | MIT / Apache-2.0 / BSD-2-Clause | Compiled into the optional `simurg_core` extension (`rust/simurg-core`); list with `cargo tree` |
| [UCSC Genome Browser](https://genome.ucsc.edu/) `cytoBand` tables (hg38, hg19) and `ncbiRefSeq` (RefSeq transcripts, NCBI) | Free for all uses (UCSC data terms; RefSeq is public domain) | `simurg/cn/data/cytoBand_GRCh3{7,8}.txt.gz` and the derived centromere/acrocentric mask BEDs are shipped; `scripts/build_annotation_bundle.sh` downloads cytoBand + ncbiRefSeq for gene lists; `simurg/pgx/data/pgx_cn_regions.GRCh38.v1.bed` is derived from ncbiRefSeq exon coordinates (`scripts/pgx/build_cn_regions.py`) |
| [illuminaio](https://github.com/HenrikBengtsson/illuminaio) | GPL-2 | Documentation of IDAT field codes only; oracle via subprocess |
| [CPIC](https://cpicpgx.org) database via the CPIC API (allele definitions, allele function, diplotype→phenotype tables) | CC0 1.0 | downloaded by `scripts/pgx/fetch_sources.sh` into `data/` (never committed); `simurg pgx db build` derives the local PGx DB from it; source version and file hashes are recorded in the DB `meta` table |
| [PharmVar](https://www.pharmvar.org) haplotype definitions (Gaedigk et al. 2018 CPT 103:399) | PharmVar terms of use (attribution) | per-gene zips downloaded by `scripts/pgx/fetch_sources.sh` into `data/` (never committed); `simurg pgx db build` derives core-allele definitions for genes CPIC does not define |
| [GeT-RM](https://www.cdc.gov/lab-quality/php/get-rm/reference-materials.html) consolidated PGx/HLA table (CDC) | US government work | validation truth only (`scripts/pgx/getrm_truth.py`), not redistributed |
| [ClinPGx](https://www.clinpgx.org) (formerly PharmGKB) clinical-annotation variants | CC BY-SA 4.0 (attribution: ClinPGx, https://www.clinpgx.org/page/citingClinpgx) | `clinicalVariants.zip` downloaded by `scripts/pgx/fetch_sources.sh` into `data/` (never committed); rsIDs become genotype-only variant-based genes in the local PGx DB |
| [Noto Sans, Noto Sans Mono](https://fonts.google.com/noto) — Copyright 2022 The Noto Project Authors | SIL Open Font License 1.1 | Glyph outlines of the wordmark in `branding/logo/` (converted to SVG paths by `scripts/brand/make_brand.py`); named in report CSS but never bundled |
| Okabe and Ito colour-universal-design palette (Okabe & Ito 2008, *Color Universal Design*) | free to use (cited) | Chart colours in `simurg/core/brand.py` and the HTML reports |
## BSD-2-Clause (BeadArrayFiles, verbatim from its README)
+80
View File
@@ -0,0 +1,80 @@
# Why SimurgArray should exist
*Part 1 of 5. Kemal Yaylali, September 2026*
Every genotyping array tells a small story before it tells you anything about DNA. A glass slide goes into a scanner, the scanner writes two IDAT files per sample (one red, one green), and a few hundred thousand bead intensities wait for someone to turn them into genotypes. That someone is almost always a piece of closed software. You click, it thinks, and out come the calls.
For most people this is perfectly fine. The calls are good. The labs are busy. Nobody has time to ask how a pair of numbers became "AB".
I had the time, and I had the question. SimurgArray is the answer I ended up writing.
## The black box in the middle
Illumina Infinium arrays are everywhere. Biobanks use them, consumer genetics companies use them, research groups use them because they are cheap per sample and wonderfully boring in the best sense: they work. Hundreds of millions of people have been genotyped this way.
The pipeline is conceptually simple:
1. Read the raw intensities from the IDAT files.
2. Normalize them, because the red and green channels never quite agree with each other.
3. Compare each sample to a cluster file (an EGT) that says where AA, AB and BB usually sit.
4. Call genotypes, give each call a score, and write everything to a GTC file.
5. Turn that into something the rest of the world reads, usually a VCF.
Steps 1 to 4 are where the interesting decisions live, and they have historically been done by software you can run but cannot read. Good open tools exist around the edges, and I will talk about them in the next post, but I could not find one place where the whole chain was open, tested against the vendor's own outputs, and documented well enough that a stranger could check every step.
So I built that place.
## What SimurgArray actually is
SimurgArray is a personal research toolkit that takes IDAT files all the way to QC reports, VCF and PLINK files, and then keeps going:
* Genotype calling that reproduces the vendor's GTC files byte for byte in 2138 of 2141 public 1000 Genomes Omni2.5 samples. The last three are documented, not hidden.
* Sample and control QC with an HTML report you can actually click around in.
* Copy number, loss of heterozygosity and mosaicism calling across the genome.
* Pharmacogenomics: targeted copy number for genes like CYP2D6, star allele diplotypes and CPIC phenotypes.
* Methylation array control QC.
* ArrayTrain, which builds your own cluster file from your own cohort, so you are not forever borrowing someone else's.
Everything is specified item by item in a functional spec with 416 numbered requirements, and every algorithm points to where it came from: a paper, a public technical note, an expired patent, or an open source project with a compatible license. When our numbers differ from a reference tool, the difference goes into a file called `known_unknowns.md` with a date and an explanation. Thirty entries so far. Some of them are my favorite reading.
## Reason one: you should be able to check
Science has a slightly awkward relationship with tools it cannot inspect. We publish methods sections that say "genotypes were called with the manufacturer's software, default settings", and everybody nods, because what else would you say?
The problem shows up later. A cluster file that does not match your chips. A normalization version that changed between releases. A sex check that disagrees with the pedigree in 12 samples out of two thousand. With a black box you can only shrug. With open code you can open the file, find the line, and write down what happened.
SimurgArray was built around that idea. It has a differential testing harness that compares our outputs with reference tools field by field and labels each difference as exact, near, discrepancy or unknown. A nightly job runs it again at 02:30, when the Raspberry Pi has nothing better to do and the rest of the house is asleep.
## Reason two: the cluster file problem
Here is something that surprised me more than it should have. Genotype calls depend heavily on the cluster file, and the cluster file was trained by someone else, on samples you have never seen, possibly for a slightly different version of your chip.
On a public dataset of 360 GSA arrays I worked with, the only public cluster file available was made for a sibling chip. It works, mostly. The quality metrics politely complain the whole time.
With ArrayTrain you can train a cluster file from your own cohort. On that dataset, a cluster file trained from 120 arrays gave 99.44 % concordance with 30x whole genome sequencing, against 99.46 % for the vendor's file, while calling more genotypes. That is not a victory lap. It is a proof that the dependency is optional, which is a different and, I think, more useful thing.
## Reason three: it should run on a small computer
A lot of genomics software quietly assumes a server room. SimurgArray was developed and mostly validated on a Raspberry Pi 5 with 8 GB of memory. Heavy jobs run inside a memory guard, because I learned the hard way what happens when the kernel has to choose between my test suite and my web browser. The browser lost. So did the test suite, actually.
With the optional Rust kernels a GSA sample takes about a second on a single Pi core. On a cloud server core it is roughly 80 samples a minute. The few cloud validation runs I needed cost a few dollars in total, and every one of them was set to switch itself off and was checked afterwards to make sure nothing kept billing quietly in the background.
I care about this because the people who would benefit most from open array analysis are often the ones with the least infrastructure. More on that in part 3.
## Reason four: understanding is a feature
There is a kind of knowledge you only get by rebuilding something. I now know why the normalization uses the exact float operations it uses, why a median of an even number of values is not always the median you expect, and why a NaN can have a sign depending on which processor produced it. None of this is glamorous. All of it matters if you want two programs to agree to the last bit.
That understanding is now written down, in code and in documents, where it can outlive my own memory of it. Given how my memory works, that is a real advantage.
## What it is not
SimurgArray is a research tool. It is not a medical device, it is not for diagnosis, and its pharmacogenomics output is not a prescription. I say this plainly because PGx reports look very official, and a well formatted table can be more convincing than it deserves to be.
It also does not use anything it should not. No decompiled binaries, no vendor data in the repository, no copied GPL code. Tools under the GPL are only ever called as separate programs to compare against. When I borrowed from MIT, BSD or Apache licensed projects, the credit is in `THIRD_PARTY_NOTICES.md`, word for word.
## The short version
SimurgArray exists because array genotyping is too widely used to be understood by only one company, because cluster files should be something you can make yourself, and because a curious person with a small computer should be able to follow every number from the scanner to the VCF.
In the next post I will look at what else is out there, which is quite a lot, and why I still decided to write my own. The honest answer involves both good reasons and a certain amount of stubbornness.
@@ -0,0 +1,73 @@
# Are there alternatives? Yes. Why build it anyway?
*Part 2 of 5. Kemal Yaylali, September 2026*
Whenever someone tells me they are writing their own genotype caller, my first instinct is to ask whether they have looked around. So it is only fair that I answer the same question about myself.
I did look around. There is a lot of good work out there. Some of it I admire, some of it I depend on, and some of it is the reason SimurgArray can check its own answers at all.
## What the vendor gives you
The array manufacturer offers its own software, and it is good at what it does.
**GenomeStudio** is the classic. A desktop application for Windows where you load a project, look at cluster plots, fix the loci that look strange and export reports. Generations of lab scientists learned arrays on it. It is free to use after registering, but it is closed, it wants a graphical desktop, and it does not scale nicely to tens of thousands of samples.
**The command line tools** (the array analysis platform and its predecessors) turn IDATs into GTC files without the graphical part. They are fast and they are the reference: when I say SimurgArray matches the vendor byte for byte, these are the outputs I mean. They are also closed, so when something looks odd you can only guess why.
**The vendor's newer analysis software** does genotyping, copy number and pharmacogenomics in one package, locally or in the cloud. I studied its public documentation closely, because it describes a sensible feature set and a clear list of outputs. It is still closed, and its licensing and platform assumptions are aimed at institutions, not at a person with a Raspberry Pi and a free evening.
None of this is a complaint. A company building good closed tools for paying customers is a normal thing. It just leaves a gap.
## What the open source world gives you
This is where it gets interesting, because several people have already done a lot of the hard work in the open.
**gtc2vcf** by Giulio Genovese is a bcftools plugin that converts GTC files (and IDATs, via an open reimplementation of the calling) into VCF. It is careful, fast and MIT licensed. SimurgArray uses it as an oracle all the time, and it helped me understand several details that the public documentation leaves out. If you only need GTC to VCF, you may not need anything else.
**MoChA**, from the same author, detects mosaic chromosomal alterations using phased BAF. It is the right tool for mosaicism in large cohorts, and it is the reason I know my own mosaic caller has a hard limit below about 20 % cell fraction without phasing.
**BeadArrayFiles** and **GTCtoVCF**, both from the vendor's own open source repositories, read the file formats and write VCF. Old, a bit dusty (GTCtoVCF needed two small patches to run on Python 3), and extremely useful as references.
**illuminaio** in Bioconductor reads IDAT files. It is GPL licensed, so SimurgArray only runs it as a separate program to compare results and never reuses its code.
**crlmm** and **Illuminus** are academic callers from the late 2000s with a real statistical model behind them. Their papers shaped how ArrayTrain thinks about clusters.
**PennCNV** and **QuantiSNP** are the long standing tools for copy number from LRR and BAF.
**PharmCAT**, **Stargazer**, **Aldy** and friends call star alleles, mostly from sequencing data or from VCFs you already have.
**sesame** and **minfi** handle methylation arrays in R, and SimurgArray's methylation QC is checked against sesame.
**PLINK 2** does everything downstream of a VCF, better than I ever would, and I would not dream of replacing it.
## So why build another one?
Because none of these, alone or together, gave me the thing I wanted: one open pipeline from raw IDAT to final report, bit exact with the vendor where that is possible, tested against every one of the tools above, and honest about where it differs.
Here are the specific reasons, in the order they occurred to me.
**The chain was broken in the middle.** You can read IDATs with one tool, convert GTCs with another, call CNVs with a third and PGx with a fourth. Each hands off to the next with its own conventions for strand, allele order, missing values and sample names. SimurgArray keeps one data model from start to finish, and every hand off is tested.
**Nobody promised to agree with the vendor to the last bit.** Close is usually fine. But close means you cannot tell a real difference from a rounding difference. Once normalization, calling and GTC writing are identical down to the byte, any remaining difference is information instead of noise. Getting there required reproducing float32 quirks, a particular median that is not quite a median, and the sign of a NaN. I am unreasonably proud of that last one.
**Cluster files were a dependency without an exit.** Every open caller I found needs a cluster file from the vendor. ArrayTrain removes that requirement. For a cohort whose ancestry is not well represented in the samples the vendor trained on, that might matter a lot. I will come back to this.
**I wanted it to run on small hardware.** Most pipelines assume a cluster or at least a workstation. SimurgArray was written on a Raspberry Pi and validated there as much as possible, with the cloud used only when a dataset simply did not fit, and even then for minutes at a time.
**I wanted a specification, not just code.** The functional spec lists 416 behaviours with IDs, from command line options to edge cases like an empty sample name column in the vendor's own template sheet. Tests cite those IDs. It sounds bureaucratic. It is actually liberating, because "is this a bug?" becomes a question with an answer.
**I wanted to learn it properly.** Reading code teaches you how something works. Reproducing it teaches you why. Several of the most interesting facts about arrays that I know now came from a test failing by one unit in the last place.
## And the stubbornness
I should be honest: there is also a bit of "how hard can it be". The answer, as usual, was "harder than that, but not impossible". The first estimate for normalization was a few weeks. The first version that matched the vendor bit for bit took longer, and taught me more about floating point contraction on ARM processors than I had planned to know.
It helped that the expired patents on the core normalization and clustering methods are public, that the technical notes are public, and that people like the authors above wrote their work down in the open. SimurgArray stands on all of that. It does not replace any of it.
## Where it fits
If you want a mature graphical tool with support, use the vendor's software. If you only need GTC to VCF, use gtc2vcf. If you want mosaicism in a biobank, use MoChA. If you want PGx from sequencing, use PharmCAT or Aldy.
If you want to go from a folder of IDAT files to genotypes, QC, CNVs, PGx and your own cluster file, on hardware you own, with every step open and every disagreement written down, SimurgArray is the tool I wish I had found when I started.
Next time: why I think this is useful beyond my own curiosity, and who might actually benefit.
+65
View File
@@ -0,0 +1,65 @@
# What good could it do?
*Part 3 of 5. Kemal Yaylali, September 2026*
"Benefit to humanity" is a big phrase for a tool that mostly reads binary files. I will try to keep this post the right size. SimurgArray will not cure anything. What it can do is lower a few barriers that currently decide who gets to do genetics research and how much of it they can trust.
Here is where I think it helps, roughly from the most certain to the most hopeful.
## 1. Reproducible science
Array genotypes feed genome wide association studies, polygenic scores, ancestry analyses and a great deal of population genetics. A lot of that work rests on a sentence like "calls were produced with the manufacturer's software". If someone wants to rerun the analysis five years later, with a different version of that software, the numbers may shift, and nobody can say exactly why.
With SimurgArray every run writes a manifest: software version, normalization version, cluster file checksum, command line, even which backend (Python or Rust) was used. The same inputs give the same bytes. And because the pipeline reproduces the vendor's GTC files exactly on public data, an old analysis can be rebuilt and compared field by field, instead of "roughly".
This is the least exciting benefit and probably the most important one.
## 2. Research where budgets are small
Genotyping arrays are the cheapest way to look at hundreds of thousands of variants in a person. That makes them the natural choice for biobanks and studies in countries where sequencing everyone is not realistic. Ironically, the analysis side is where those projects often struggle: licenses, servers, specialist staff, and software that assumes all three.
SimurgArray runs on a Raspberry Pi. I do not recommend running a national biobank on one (I did find its limits, usually around midnight), but a single ordinary server core handles about 80 GSA samples a minute. A modest machine can process a large study in an afternoon, and the software costs nothing.
The pipeline also produces the things a small team needs to trust its data without a bioinformatics department: control probe QC, sample QC, contamination estimates, relatedness, sex checks, and an HTML report that a lab person can open in a browser and actually understand.
## 3. Better calls for underrepresented populations
This is the part I find most hopeful.
A cluster file encodes where the genotype clouds sit for each SNP. It is trained on a set of samples, and those samples have ancestries. If your cohort comes from a population that was thin or absent in that training set, rare alleles that are common in your population may never have had a proper cluster. The caller then does its best with an imputed guess.
ArrayTrain lets a group train cluster files on their own samples. On public data, a cluster file trained from 120 arrays already matched the vendor's accuracy against whole genome sequencing within 0.02 percentage points, while calling more genotypes. I have only tested one cohort so far, so I will not claim more than that. But the direction is clear: the people who own the samples can own the clusters too.
## 4. Pharmacogenomics research that is open to inspection
A growing number of arrays include pharmacogenomic content, because a handful of genes (CYP2D6, CYP2C19, CYP2C9, SLCO1B1, DPYD and others) influence how people respond to common drugs. Calling star alleles from an array is tricky. CYP2D6 in particular has deletions, duplications and hybrid genes that a SNP array can only see indirectly.
SimurgArray builds its PGx database from open sources (CPIC, PharmVar, ClinPGx), calls targeted copy number, and reports diplotypes together with everything that went into them: which variants were seen, which were missing, which alternative diplotypes the array cannot tell apart. On public reference samples it agreed with the GeT RM consensus in 154 of 168 comparable gene calls, and the misses are listed and explained.
I want to be very clear here. This is research software. It is not for choosing a drug or a dose. But openness matters even for research: when an algorithm says someone is a poor metabolizer, a researcher should be able to see why, and disagree.
## 5. Copy number for rare disease research
Large deletions and duplications cause many rare diseases, and arrays are still a common first look. SimurgArray calls CNVs, loss of heterozygosity and mosaic events across the genome and writes them with ISCN style annotation.
Its honest numbers: on 360 public arrays compared with 30x sequencing, constitutional deletion calls were right far more often than mosaic ones, and rare deletions were found about 30 % of the time at the size and probe density we tested. Common CNVs are mostly invisible to the method by design, because the reference batch absorbs them. For rare disease research, rare events are the interesting ones, so that is the right trade, but it is a trade and it is written down.
## 6. Teaching
I learned more about arrays by rebuilding the pipeline than from any course. The code is written to be read. Every algorithm names its source. Every oddity the vendor has, and every place we deliberately behave differently, is documented with a date and a reason.
A student who wants to know how a genotype call happens can follow one sample through normalization, clustering and scoring, print intermediate values, and compare them with the reference tools. That used to require either a job at the company or a lot of guessing.
## 7. Keeping the ecosystem honest
Open alternatives are good for everyone, including the vendor. When a public tool can reproduce outputs exactly, differences become bug reports instead of mysteries. Several findings in `known_unknowns.md` are small documentation errors or version quirks that anyone using the official tools would benefit from knowing about.
## What it will not do
It will not replace clinical laboratories, their validated pipelines, or the people who sign reports. It will not make arrays as informative as sequencing. It will not replace the excellent open tools it builds on. And it will not make genetic data less sensitive: people who run it are responsible for handling their data properly, which the software supports with privacy options in its reports but cannot enforce.
## The small version of a big claim
If SimurgArray helps one underfunded study get cleaner genotypes, one student understand what a cluster file is, or one reviewer ask "which version of the normalization did you use?", it has done its job. The bird in its name is known for bringing many small travellers to one clear place. I will be happy if it brings a few people to a clearer view of their data.
Next time: what it would take to make SimurgArray public properly, and a realistic calendar for doing it.
+105
View File
@@ -0,0 +1,105 @@
# Going public: what it takes, and a calendar
*Part 4 of 5. Kemal Yaylali, September 2026*
Right now SimurgArray lives in a private repository on my own Git server. It has a license, a changelog, a user guide, wheels, a Docker image and a version number that just became 2.0.0. In other words, it looks public. It is not, yet.
Publishing code is easy. Publishing it responsibly is a checklist. This post is that checklist, followed by a calendar I intend to keep, give or take the usual week.
## What "public" means here
By public I mean four things:
1. The source code on my own Gitea server, open to everyone, with issues and pull requests open.
2. Installable packages: a Python wheel, the optional Rust kernel wheels, a container image and a conda recipe.
3. Documentation someone can follow without asking me anything.
4. A citable record: a DOI for each release and a short preprint describing the methods and the validation.
## The checklist
### Licensing
SimurgArray is MIT licensed. Code borrowed from other projects came only from MIT, BSD and Apache licensed sources, and their license texts sit in `THIRD_PARTY_NOTICES.md` exactly as the authors wrote them. GPL tools are only ever run as separate programs for comparison, never copied.
Before going public I will do one more pass over every file to confirm that each ported function names its origin, and that nothing slipped in during the late night sessions. Late night sessions are when things slip in.
### Data that must never be published
The repository must not contain vendor manifests, cluster files, IDATs or GTCs. The `.gitignore` has blocked them from the start, and the test fixtures are Bioconductor example files under the Artistic 2.0 license plus synthetic data. Still, "we never committed it" is a claim, and a claim deserves a check. I will scan the complete Git history, not just the current tree, for large binaries and for file types that should not be there.
The same goes for secrets. The cloud scripts use credentials from the local environment, never from files in the repository, but a full history scan for keys is cheap and embarrassment is expensive. The cloud account credentials used during development will be rotated before the switch, as a matter of principle.
### Names and trademarks
The software reads file formats defined by Illumina and reproduces the behaviour of Illumina's algorithms from public documents and expired patents. Illumina, Infinium, GenCall, GenTrain and GenomeStudio are their trademarks. The documentation will say clearly that SimurgArray is independent and not affiliated with or endorsed by the vendor, and it will use those names only to describe compatibility.
The name needed a check on the Python package index, conda channels and container registries before anything is uploaded. It turned out `simurg` on the Python package index already belongs to someone else, so the package is called `simurgarray` while the command stays `simurg`. I was sad for about an hour, which is less than I had budgeted.
### Third party data sources
The PGx database is built on the user's machine from public sources:
* CPIC (CC0),
* PharmVar (their own terms),
* ClinPGx (CC BY SA).
SimurgArray ships the builder, not the database, so each source keeps its own terms and attribution. The documentation will list those terms next to the download commands, so nobody has to find them in a footnote.
### Scope and safety language
Every README, report header and PGx output will state that the software is for research, not for diagnosis or treatment decisions. The PGx JSON already carries the database version and the evidence behind each call. That transparency is the main safety feature, but it is not a substitute for saying the obvious out loud.
### Engineering hygiene
* Continuous integration on my own Gitea runner: lint, type checks, a secret scan, and unit tests with and without the compiled kernels.
* Oracle tests that need large public datasets stay opt in, with a script that downloads everything with checksums.
* Issue templates that ask for the command, the software version and the run manifest, because "it gave a wrong genotype" is hard to debug without them.
* A contributing guide, a code of conduct and a security policy.
* A short description of the release process, so that it is not only in my head.
### Documentation
The user guide covers every command. What is missing is a gentle path for newcomers: a tutorial that starts from public IDATs (the Bioconductor fixtures and the GEO dataset used in validation), runs the whole pipeline on a laptop, and explains each output. I also want one page per validation report written for people who do not want to read a JSON file. Most people.
### Citation
Each tagged release will get a DOI through Zenodo, and the repository will carry a citation file. A preprint on bioRxiv will describe the design, the bit exact reproduction, ArrayTrain, the CN and PGx modules, and every known limitation. If it is going to be cited, it should be cited for what it actually does.
## The calendar
The weeks start on Mondays. Everything below costs nothing except time, apart from an optional domain for the documentation site.
**Week of October 5, 2026: audit**
Full history scan for vendor files and secrets. Credential rotation. Provenance pass over ported code. Trademark and disclaimer text in README, user guide and report templates.
**Week of October 12: public repository**
Open the repository to everyone on my own Gitea server, where it has lived since the first commit, with continuous integration, issue templates, a contributing guide, a code of conduct and a security policy. No mirror elsewhere: one home is easier to keep honest.
**Week of October 19: packages**
Check name availability. Upload version 2.0.0 wheels to the Python package index, the image to a public container registry, and submit the conda recipe for review.
**Weeks of October 26 and November 2: tutorial and docs site**
End to end tutorial on public data, validation summaries rewritten for humans, documentation site generated from the repository.
**Week of November 16: soft launch**
Announce to a few people who work with arrays and will not be polite about problems. Collect issues. Fix the embarrassing ones quietly and the interesting ones loudly.
**Weeks of November 30 and December 14: preprint**
Write the methods paper, rerun every validation from a clean checkout so the numbers in the paper come from the public code, deposit data summaries, submit to bioRxiv.
**Week of January 11, 2027: version 2.1**
First release shaped by other people's feedback. Likely candidates: a second cohort for ArrayTrain validation, iterative CN references for better rare event sensitivity, and anything the soft launch reveals.
After that, a steady rhythm: a minor release every two or three months, a DOI for each, and a public changelog that keeps the habit of writing down what changed and why.
## What could delay it
* **A name clash.** Solvable, mildly annoying.
* **An unexpected license question about a source.** Solvable, possibly slow.
* **Real life.** Unavoidable, frequently scheduled.
## Why announce a calendar at all
Because a public date is the best cure for "just one more feature". The software is already more complete than I planned when I started. What it needs now is other people using it, finding its mistakes and telling me which of its choices were wrong.
Next time, the last post: what using SimurgArray actually looks like, from a folder of IDATs to a report, and what the name and the bird are about.
@@ -0,0 +1,158 @@
# Using SimurgArray, and the bird behind the name
*Part 5 of 5. Kemal Yaylali, September 2026*
Four posts of reasons are enough. This one is about what it looks like when you actually use the thing, and about the name, which people ask about more often than they ask about normalization. Fair enough.
One small note first. The command examples below use the usual command line options, and those start with two little lines. The prose around them does not. That is a personal style choice and I am sticking to it.
## Installing
On any Linux or macOS machine with Python 3.12:
```bash
uv venv && uv pip install simurgarray-2.0.0-py3-none-any.whl
simurg --help
```
If you have a C compiler and Rust, you can add the optional kernels, which make the heavy steps about three times faster and produce exactly the same bytes:
```bash
uv pip install ./rust/simurg-core
python -c "from simurg._core import backend; print(backend())"
```
There is also a Docker image and a conda recipe. The user guide covers all of them.
## A first look at your files
Before running anything, it helps to know what you have. `simurg inspect` reads any IDAT, manifest, cluster file, GTC or sample sheet and prints what is inside:
```bash
simurg inspect idats/204112350001_R01C01_Grn.idat
simurg inspect GSA.bpm GSA.egt --json
```
This is surprisingly useful. It will tell you, for instance, that your cluster file was made for a different manifest version than your chips, which is the kind of thing you would rather know on day one.
## From IDAT to genotypes
The main event. One command reads the IDATs, normalizes them, calls genotypes against the cluster file, writes a GTC per sample, and runs the sample and control QC:
```bash
simurg genotype --bpm GSA.bpm --egt GSA.egt --csv GSA.csv \
--idats idats/ --sheet SampleSheet.csv --out run/gtc --threads 0
```
`threads 0` means "use every core". On a Raspberry Pi 5 that is four, which is plenty for a few dozen samples while you make tea.
What you get:
* one GTC file per sample, identical to what the vendor's command line tool would produce with the same inputs,
* `sample_summary.tsv` with call rates, LogR deviation, sex estimates and flags,
* control probe metrics, contamination estimates and a relatedness table for the batch,
* a `run_manifest.json` that records every version, checksum and option used.
## Looking at the QC
```bash
simurg qc report --data run/gtc --out run/qc_report --output-format both
```
This writes a single HTML file you can email to a colleague, plus a spreadsheet. The report has linked views: select an odd looking sample in the call rate plot and it lights up in the control metrics, the sex check and the chip layout. There is a thresholds editor, so you can move a cutoff and see which samples fail before you commit to it.
My favorite part is the chip heatmap. When a whole row of a BeadChip fails together, you stop blaming the DNA and start asking about the scanner.
## To VCF and beyond
```bash
simurg gtc-to-vcf --bpm GSA.bpm --csv GSA.csv --fasta GRCh38.fa --gtcs run/gtc --out run/vcf
simurg export plink --vcfs run/vcf --gtcs run/gtc --out run/plink --format both
```
The VCFs are on the plus strand, validated with bcftools, and agree with gtc2vcf and GTCtoVCF apart from a documented list of cases where one of them cannot resolve an insertion or deletion probe. PLINK 1 and PLINK 2 files come out identical to what plink2 itself produces from the same VCFs.
## Copy number, LOH and mosaicism
Build a model once per chip and batch, from at least 24 normal samples, then call:
```bash
simurg cn build-model --bpm GSA.bpm --fasta GRCh38.fa --egt GSA.egt \
--reference-gtcs normals/ --out gsa.simurg-cyto
simurg cn call --bpm GSA.bpm --model gsa.simurg-cyto --gtcs run/gtc --fasta GRCh38.fa --out run/cn
simurg cn annotate --vcfs run/cn
```
Each sample gets a CNV VCF with deletions, duplications, LOH and mosaic events, a segments file, and ISCN style descriptions with cytobands and genes. The sample summary flags arrays with far too many events. On the public validation set, exactly one array raised that flag, and it deserved it.
## Pharmacogenomics
Build the database from open sources, check what your array can actually see, then call:
```bash
bash scripts/pgx/fetch_sources.sh
simurg pgx db build --sources data/pgx/sources --fasta GRCh38.fa \
--manifests GSA_PGx.bpm --csv GSA_PGx.csv --out pgxdb/
simurg pgx coverage --bpm GSA_PGx.bpm --db pgxdb/pgx_db.sqlite
simurg pgx copy-number call --gtcs run/gtc --model cnmodel/GSA_PGx.simurg-pgxcn --fasta GRCh38.fa --out run/vcf
simurg pgx star-allele call --vcfs run/vcf --db pgxdb/pgx_db.sqlite --out run/pgx
simurg pgx phenotype --calls run/pgx --db pgxdb/pgx_db.sqlite
```
The coverage step is the one I would not skip. It tells you, before you look at a single sample, which alleles your array can distinguish and which it cannot. A lot of confusion about array PGx comes from asking a chip a question it was never able to answer.
For each sample you get a diplotype summary, the supporting variants, the variants that were not covered, alternative diplotypes the array cannot tell apart, and a JSON file with the phenotype and the evidence. For research, as always.
## Training your own cluster file
```bash
simurg train --gtcs cohort_gtc --bpm GSA.bpm --out mycohort.egt
simurg genotype --bpm GSA.bpm --egt mycohort.egt --idats new_idats/ --out run2/gtc
```
A hundred samples is the minimum. Training reads raw intensities, not genotypes, so it does not matter which cluster file your cohort was first called with. On the Pi, 120 GSA samples take a bit over an hour. I usually start it and go to bed, which is also how most of this project got done.
## Checking one run against another
```bash
simurg compare run/gtc other_run/gtc --out compare_report
```
Every field of every GTC or VCF is compared and labelled EXACT, NEAR, DISCREPANCY or UNKNOWN, with an HTML dashboard. This is the tool I used to build everything else, and it is the one I would miss most.
## About the name
In Persian and Turkic mythology the Simurg (Simurgh, Simorgh, depending on who is telling the story) is a great bird, old and wise, that lives on a mountain at the edge of the world. In Attar's twelfth century poem *The Conference of the Birds*, the birds of the world set out to find the Simurg and make it their king. Most give up along the way. When the survivors finally arrive, there are thirty of them, and they discover that "si murg" means "thirty birds". The Simurg they were looking for was themselves, together.
I liked the name because an array is exactly that: hundreds of thousands of tiny beads that only make sense once you look at them together. Then something happened that I did not plan. The public demo dataset I used for the pharmacogenomics validation was sold as 36 samples. When I checked identities against 1000 Genomes, it turned out to be 30 individuals.
Thirty birds. I took it as a sign that I had picked the right name, or at least a sign that I should stop looking for signs and get back to work.
## Branding
A tool for researchers does not need a marketing department, but it does need to be recognizable and consistent. Here is what I have settled on.
**Name.** SimurgArray in writing, `simurg` on the command line. Short to type, hard to mistype, and it does not collide with any genomics tool I know of.
**Tagline.** "Thirty birds, one picture." It is the whole idea in four words: many small signals, one honest result.
**Logo.** A bird in flight drawn only with dots on a square grid, the way beads sit on a BeadChip. The dots use the two scanner channels, red and green, and where they overlap the bird turns gold. It should work at 16 pixels as a favicon and at poster size, and it should look a little like a genotype cluster plot if you squint. People who work with arrays will squint.
**Colors.**
* Channel red #C8453A
* Channel green #2F8F5B
* Simurg gold #D4A017 for highlights and the bird
* Night indigo #1E2240 for backgrounds, because most of the work happened at night
* Paper #F7F5EF for documents
**Type.** A clean sans serif for text and a monospace font for anything you might paste into a terminal. Numbers in reports always use tabular figures, so columns of call rates line up.
**Voice.** Plain, exact and a little dry. Say what the software does, show the number, name the limitation in the same paragraph. No "revolutionary", no "AI powered", no promises about medicine. If a result has a caveat, the caveat goes next to the result, not in a footnote.
**Reports.** Every HTML report carries the small dotted bird in the corner, the software version and the run manifest checksum. The bird is there for recognition. The checksum is there because the bird cannot prove anything on its own.
## Thank you
If you have read all five posts, you now know more about SimurgArray than most of the machines it has run on. The code goes public on the calendar from the previous post. Until then, if you work with arrays and want to try it, or want to tell me which of my choices are wrong, I would be glad to hear from you at support@yaylali.uk.
The birds made it to the mountain. Now the interesting part starts.
+13
View File
@@ -0,0 +1,13 @@
# SimurgArray blog
Five posts about why SimurgArray exists and where it is going.
1. [Why SimurgArray should exist](01_why_simurgarray_should_exist.md)
2. [Are there alternatives? Yes. Why build it anyway?](02_alternatives_and_why_i_built_it_anyway.md)
3. [What good could it do?](03_what_good_it_could_do.md)
4. [Going public: what it takes, and a calendar](04_going_public_plan_and_calendar.md)
5. [Using SimurgArray, and the bird behind the name](05_using_simurgarray_and_the_bird_behind_the_name.md)
Featured images (1200 x 630 JPEG, about 90 KB each) are in `images/`, one per post with the same file name.
They are drawn by `scripts/blog/make_featured_images.py` (Pillow), so they can be regenerated or restyled.
`branding_prompt.md` is a brief for designing the full brand identity.
+82
View File
@@ -0,0 +1,82 @@
# Branding brief for SimurgArray
Copy everything below the line into a branding agent. The identity it asks for now exists in `branding/`; this brief is kept for future refinements.
________________________________________________________________________________
You are a senior brand and visual identity designer. Build a complete, small, practical brand identity for an open source scientific software project called **SimurgArray**. Work carefully, explain your choices briefly, and deliver production ready files.
## The project in one paragraph
SimurgArray is a personal, non commercial research toolkit for Illumina Infinium genotyping arrays. It turns raw scanner files (IDATs) into genotype calls, quality control reports, VCF and PLINK files, and goes on to copy number, loss of heterozygosity, mosaicism, pharmacogenomics and training its own cluster files. It reproduces the vendor's genotype files byte for byte on public data, runs on a Raspberry Pi, and documents every place where it differs from reference tools. It is MIT licensed and about to go public. It is a research tool, never a medical or diagnostic product.
## The name and the story
In Persian and Turkic mythology the Simurg is a great, wise bird. In Attar's twelfth century poem *The Conference of the Birds*, thirty birds travel to find the Simurg and discover that "si murg" means "thirty birds": the Simurg was all of them together. An array works the same way: hundreds of thousands of tiny beads only mean something when read together. By coincidence, the public demo dataset used in validation turned out to be exactly thirty people. The brand should carry this idea quietly, never explain it loudly.
Tagline: **"Thirty birds, one picture."**
## Audience
Bioinformaticians, genetic epidemiologists, lab scientists running arrays, students, biobanks with small budgets. They are skeptical, detail oriented and allergic to marketing. They trust numbers, clear limitations and good documentation.
## Personality
Precise, calm, honest, a little dry, quietly clever. Think of a well made scientific instrument with a small smile engraved somewhere nobody asked for one. Not corporate, not playful, not futuristic, not "AI".
## Existing visual direction (keep and refine it, do not replace it)
The identity already exists in `branding/` (guide: `branding/README.md`). Treat it as the starting point.
* **Core motif:** a simurg seen from the front, wings raised in a V with three feathers each, a three dot crown, drawn only with round dots on a square grid like beads on a BeadChip. Three drawings: detailed (31 x 27 dots), simple (11 x 10) and micro (7 x 7).
* **Channel colours:** the body, wings and crown are gold, "where the two channels meet". Three tail plumes: red on the left (red channel), gold in the middle, green on the right (green channel), each ending in a round peacock eye.
* **Palette:** night indigo #1E2240, paper #F7F5EF, simurg gold #D4A017, gold deep #A87A00 (the bird on light backgrounds), gold ink #8C6500 (accent text on light), channel red #C8453A, channel green #2F8F5B, muted #A3A7C9 on dark and #5A5E7E on light. Charts use the Okabe and Ito colours with shapes.
* **Type:** Noto Sans (wordmark in SemiBold, "Array" in the accent colour) and Noto Sans Mono.
* The five blog featured images, the README banner, the social preview, the avatar and the HTML report header band already use it.
## Deliverables
1. **Logo system**
* Primary mark: the dotted bird, redrawn so it reads clearly as a bird at every size. Provide a detailed version (roughly 30 to 40 dots across) and a simplified version (roughly 8 to 12 dots across).
* Wordmark "SimurgArray" and a lockup of mark plus wordmark, horizontal and stacked.
* Favicon and app icon: 16, 32, 48, 180 and 512 px. At 16 px the bird may become an abstract cluster of dots, but it must still feel like the same family.
* Versions for dark background, light background, single color gold, single color black and single color white.
* Formats: SVG (clean, no embedded bitmaps, dots as circles) and PNG exports.
2. **Color system:** final hex values, usage ratios, and a contrast table showing that text colors meet WCAG AA on indigo and on paper. Include a rule for charts: red and green are the channel colors, so every chart must also be readable for red green color blind viewers (use shape, position or a blue alternative, and say how).
3. **Typography:** confirm or replace Noto Sans and Noto Sans Mono with free, open licensed fonts. Give sizes and weights for headings, body text, code and report tables (tabular figures for numbers).
4. **Dot grid system:** the grid spacing, dot sizes and rules for building new illustrations from dots, so other people can draw consistent images later.
5. **Templates**
* WordPress featured image, 1200 x 630.
* Social avatar, square, readable when shown as a circle.
* GitHub README banner, around 1280 x 320.
* Social preview for the repository, 1280 x 640.
* A small corner mark for HTML QC reports, together with the rule that the software version and a run checksum always appear next to it.
* An optional ASCII or Unicode banner for the command line, at most 6 lines and 60 columns, that still looks good in a plain terminal.
6. **Short brand guide** (two to four pages, Markdown or PDF): the story in three sentences, voice rules, do and do not examples for the logo, color and type specs, and how to build a new featured image.
## Voice rules for any text you write
* Plain, exact English. Short sentences. Numbers instead of adjectives.
* Every claim sits next to its limitation.
* Humor is allowed only as a faint smile, never as a joke that needs explaining.
* **Do not use em dashes, en dashes or hyphens in prose.** Rephrase instead ("open source", "non commercial", "step by step"). Hyphens inside code, file names and command options are fine.
* Never use: "revolutionary", "cutting edge", "AI powered", "next generation", "seamless", "unlock".
## Hard constraints
* Do not use, imitate or reference the logos, colors or product names of Illumina or any other genomics company. Illumina and Infinium may appear only as plain words describing compatibility, never as visual elements.
* Do not name or allude to the vendor's commercial analysis software products.
* No medical imagery: no crosses, pills, stethoscopes or DNA helices used as clinical symbols. A double helix, if used at all, must be abstract and secondary. The bird is the hero.
* No stock photos, no gradients that mimic "tech startup" style, no 3D renders.
* Everything must be original and free to publish under the project's MIT license or CC BY 4.0 for artwork. List any fonts or assets you use with their licenses.
* Files must be small: SVGs clean and optimized, PNG and JPEG exports under 150 KB each where possible.
## Acceptance checks (report on each)
1. The mark is recognizable as a bird at 48 px and still distinctive at 16 px.
2. Dark and light versions both pass WCAG AA for any text.
3. A red green color blind simulation of the logo and one chart example still reads well.
4. The five existing featured images and your new templates look like one family when placed side by side.
5. No prose you wrote contains an em dash, en dash or hyphen.
Start by restating the brief in five bullet points, list any questions you would normally ask a client (and the assumption you will make for each), then produce the deliverables.
Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

+171
View File
@@ -0,0 +1,171 @@
# SimurgArray brand guide
Everything here is generated by `scripts/brand/make_brand.py` (logos, icons, templates, checks) and
`scripts/blog/make_featured_images.py` (blog images). The mark geometry lives in one place,
`scripts/brand/simurg_mark.py`, so every file shows exactly the same dots. Artwork is released under CC BY 4.0; the
fonts are Noto Sans and Noto Sans Mono (SIL Open Font License 1.1).
![Horizontal lockup](logo/png/lockup_horizontal_dark.png)
## The story in three sentences
In Attar's *Conference of the Birds*, thirty birds search for the Simurg and find that "si murg" means thirty birds:
the Simurg was all of them together. A genotyping array is the same idea, hundreds of thousands of small beads that
only mean something when read together. SimurgArray is the tool that reads them together, openly.
Tagline: **Thirty birds, one picture.**
## The mark
A simurg seen from the front, wings raised, drawn only with round dots on a square grid, the way beads sit on a
BeadChip.
* **Gold body, wings and crown.** Gold is what you get when the two scanner channels meet.
* **Three tail plumes:** red on the left (the red channel), gold in the middle, green on the right (the green
channel). Each ends in a round peacock eye.
* **Three dots on the head** form a small crown. Nobody has to notice it.
Three drawings of the same bird, chosen by size:
* `mark` (31 x 27 dots): 100 px and larger, banners, lockups, print.
* `mark_simple` (11 x 10 dots): 24 to 100 px, report corners, small UI.
* `mark_micro` (7 x 7 dots): 16 px favicon only.
Colour versions of each, in `logo/` as SVG and in `logo/png/` as PNG:
* `dark`: gold #D4A017 with red and green plumes, for indigo or other dark backgrounds.
* `light`: deep gold #A87A00 with red and green plumes, for paper or white.
* `gold`, `black`, `white`: single colour, for stamps, embossing, merchandise, fax machines that still exist.
The SVGs contain only circles, no embedded images and no fonts, so they render the same everywhere.
### Wordmark and lockups
"Simurg" in the text colour and "Array" in the accent colour, Noto Sans SemiBold, outlined to paths so no font is
needed. On dark backgrounds the accent is gold #D4A017, on light backgrounds gold ink #8C6500.
* `lockup_horizontal_*`: mark left, wordmark right. The default.
* `lockup_stacked_*`: mark above, wordmark centred below. For square spaces.
Clear space around any lockup: at least the height of the mark's head (about three dot rows) on every side.
### Do
* Keep the dots round and on their grid.
* Keep the red plume on the left and the green plume on the right.
* Use the light version on light backgrounds; plain gold on paper is too faint (contrast 2.18).
* Scale the whole mark; pick the simple or micro drawing when the dots would get smaller than about 2 px.
### Do not
* Recolour the plumes, add gradients, shadows, glows or outlines.
* Turn dots into squares or connect them with lines.
* Rotate, mirror or stretch the mark.
* Put the mark on busy photos.
* Combine it with DNA helices, crosses, pills or any clinical imagery. SimurgArray is a research tool.
* Use the logos, colours or product names of any genomics company as visual elements. Illumina and Infinium appear
only as plain words describing compatibility.
## Colour
Brand colours:
* **Night indigo** #1E2240: backgrounds (most of the work happened at night). Deep indigo #12142A for gradients.
* **Paper** #F7F5EF: light backgrounds and text on dark.
* **Simurg gold** #D4A017: the bird, accents on dark.
* **Gold deep** #A87A00: the bird on light backgrounds.
* **Gold ink** #8C6500: accent text on light backgrounds.
* **Channel red** #C8453A and **channel green** #2F8F5B: the plumes and the bead grid only. Never for text.
* **Muted on dark** #A3A7C9 and **muted on light** #5A5E7E: secondary text.
Rough proportions on a dark page: indigo 80, paper 10, gold 7, red and green 3 together.
Every text colour passes WCAG AA (4.5) and every graphic colour passes 3.0 on its background. The full table with
the computed ratios is in `checks/contrast.md`.
### Charts
Red against green is exactly the pair that red green colour blind readers cannot separate, and in genotyping it is
also the most tempting pair. So charts never use the channel colours to tell data apart. Use the Okabe and Ito
palette with a second cue:
* AA: vermillion #D55E00, circles.
* AB: bluish green #009E73, triangles.
* BB: blue #0072B2, squares.
Always add shape, position or a direct label as well as colour. `checks/colour_vision_check.png` shows the mark and
an example cluster plot under simulated protanopia and deuteranopia (Machado et al. 2009). The bird stays readable
because its shape carries it; the two coloured plumes become similar but keep their left and right positions; the
chart stays readable because of the shapes.
## Type
* **Noto Sans** for everything people read. Headings SemiBold or Bold, body Regular.
* **Noto Sans Mono** for anything a user might paste into a terminal, file names, and small labels such as
"PART 3".
* Numbers in tables use tabular figures (`font-variant-numeric: tabular-nums`), so columns of call rates line up.
Suggested sizes for the web: body 17 px with 1.6 line height, H1 40 px, H2 28 px, H3 21 px, code 15 px, table text
15 px. Reports: 13 px tables, 12 px captions.
## The dot grid
New illustrations are built from the same material as the logo.
* Background grid: dots every 18 px (at 1200 px width), radius 1.6 px, alternating red and green at 14 % opacity
over the indigo gradient.
* Foreground dots: radius 40 % of the cell, so neighbours never touch.
* Colour by meaning: gold for the subject, red and green only for things that come from the two channels, dimmed
gold or indigo mixes for "background" subjects.
* Motion is suggested with trails of shrinking, fading dots, never with lines.
* One subject per image. Empty space is part of the grid.
## Templates
In `templates/`:
* `featured_template_1200x630.jpg`: WordPress featured image and social preview for posts. Title on the left in Noto
Sans Bold (58 px, shrinks to fit a 540 px column), "PART N" above it in gold mono, footer with three dots, the name
and the tagline. The five blog images in `blog/images/` follow this layout, each with its own small motif.
* `social_preview_1280x640.png`: the repository preview image.
* `readme_banner_1280x320.png`: the top of the README.
* `avatar_512.png`: square avatar; the mark sits inside the central circle, so round crops are safe.
* `report_corner_mark.svg` and `report_corner_mark.html`: the small mark for HTML QC reports. It is always shown with
the software version and the first 12 characters of the run manifest checksum. The bird is for recognition; the
checksum is what actually proves anything.
* `cli_banner.txt`: six lines, 46 columns, plain ASCII, for `simurg --version` or a first run.
Icons in `icons/`: `favicon.ico` (16, 32, 48), PNGs at 16, 32, 48, 180 (Apple touch) and 512, all on a rounded
indigo tile. `checks/icon_sizes.png` shows them side by side.
## Making a new featured image
1. Add the post to `POSTS` in `scripts/blog/make_featured_images.py`: file stem, "Part N", the title with `\n`
where lines should break, and a motif.
2. Reuse a motif or write a new one: draw the mark with `draw_mark`, add at most one supporting element.
3. Run `python3 scripts/blog/make_featured_images.py`. Files come out at 1200 x 630 and about 100 KB.
## Voice
* Plain, exact English. Short sentences. Numbers instead of adjectives.
* Every claim sits next to its limitation, in the same paragraph.
* Humour only as a faint smile.
* No em dashes, en dashes or hyphens in prose; rephrase instead. Hyphens in code, file names and options are fine.
* Never: revolutionary, cutting edge, AI powered, next generation, seamless, unlock.
Examples:
* Yes: "Concordance with 30x sequencing was 99.44 %, against 99.46 % for the vendor's cluster file."
* No: "Best in class accuracy that rivals commercial solutions."
* Yes: "Research use only. The PGx report shows the evidence behind every call."
* No: "Personalised medicine, unlocked."
## Acceptance checks
1. **Recognisable at 48 px, distinctive at 16 px:** see `checks/icon_sizes.png`. The simple and micro drawings were
drawn by hand for these sizes instead of scaling the detailed one down.
2. **Contrast:** all text pairs pass AA, all graphic pairs pass 3.0 (`checks/contrast.md`); plain gold on paper is
the one pair that fails, and the guide forbids it.
3. **Colour vision:** `checks/colour_vision_check.png`.
4. **One family:** `checks/family.jpg` puts the five blog images and the templates side by side.
5. **No dashes in prose:** this guide and all generated text were checked for em dashes, en dashes and hyphens.
Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

+14
View File
@@ -0,0 +1,14 @@
| colour | on | use | contrast | AA text (4.5) | graphics (3.0) |
|---|---|---|---|---|---|
| paper #F7F5EF | indigo #1E2240 | text on dark | 14.18 | yes | yes |
| muted_dark #A3A7C9 | indigo #1E2240 | secondary text on dark | 6.57 | yes | yes |
| gold #D4A017 | indigo #1E2240 | accent text on dark | 6.51 | yes | yes |
| indigo #1E2240 | paper #F7F5EF | text on light | 14.18 | yes | yes |
| muted_light #5A5E7E | paper #F7F5EF | secondary text on light | 5.77 | yes | yes |
| gold_ink #8C6500 | paper #F7F5EF | accent text on light | 4.84 | yes | yes |
| red #C8453A | indigo #1E2240 | graphics on dark | 3.22 | no | yes |
| green #2F8F5B | indigo #1E2240 | graphics on dark | 3.83 | no | yes |
| gold_deep #A87A00 | paper #F7F5EF | graphics on light | 3.54 | no | yes |
| red #C8453A | paper #F7F5EF | graphics on light | 4.41 | no | yes |
| green #2F8F5B | paper #F7F5EF | graphics on light | 3.70 | no | yes |
| gold #D4A017 | paper #F7F5EF | never for text or small marks | 2.18 | no | no |
Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 8 8" width="8" height="8" role="img" aria-label="SimurgArray"><title>SimurgArray</title><rect width="8" height="8" rx="1.44" fill="#1E2240"/><g fill="#D4A017"><circle cx="1.000" cy="1.000" r="0.420"/><circle cx="7.000" cy="1.000" r="0.420"/><circle cx="1.000" cy="2.000" r="0.420"/><circle cx="2.000" cy="2.000" r="0.420"/><circle cx="4.000" cy="2.000" r="0.420"/><circle cx="6.000" cy="2.000" r="0.420"/><circle cx="7.000" cy="2.000" r="0.420"/><circle cx="2.000" cy="3.000" r="0.420"/><circle cx="3.000" cy="3.000" r="0.420"/><circle cx="4.000" cy="3.000" r="0.420"/><circle cx="5.000" cy="3.000" r="0.420"/><circle cx="6.000" cy="3.000" r="0.420"/><circle cx="3.000" cy="4.000" r="0.420"/><circle cx="4.000" cy="4.000" r="0.420"/><circle cx="5.000" cy="4.000" r="0.420"/><circle cx="4.000" cy="5.000" r="0.420"/><circle cx="4.000" cy="6.000" r="0.420"/><circle cx="4.000" cy="7.000" r="0.420"/></g><g fill="#C8453A"><circle cx="2.000" cy="6.000" r="0.420"/><circle cx="1.000" cy="7.000" r="0.420"/></g><g fill="#2F8F5B"><circle cx="6.000" cy="6.000" r="0.420"/><circle cx="7.000" cy="7.000" r="0.420"/></g></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 949 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 34 34" width="34" height="34" role="img" aria-label="SimurgArray"><title>SimurgArray</title><rect width="34" height="34" rx="6.12" fill="#1E2240"/><g fill="#D4A017"><circle cx="3.000" cy="4.000" r="0.400"/><circle cx="4.000" cy="4.000" r="0.400"/><circle cx="30.000" cy="4.000" r="0.400"/><circle cx="31.000" cy="4.000" r="0.400"/><circle cx="3.000" cy="5.000" r="0.400"/><circle cx="4.000" cy="5.000" r="0.400"/><circle cx="5.000" cy="5.000" r="0.400"/><circle cx="15.000" cy="5.000" r="0.400"/><circle cx="17.000" cy="5.000" r="0.400"/><circle cx="19.000" cy="5.000" r="0.400"/><circle cx="29.000" cy="5.000" r="0.400"/><circle cx="30.000" cy="5.000" r="0.400"/><circle cx="31.000" cy="5.000" r="0.400"/><circle cx="3.000" cy="6.000" r="0.400"/><circle cx="4.000" cy="6.000" r="0.400"/><circle cx="5.000" cy="6.000" r="0.400"/><circle cx="6.000" cy="6.000" r="0.400"/><circle cx="7.000" cy="6.000" r="0.400"/><circle cx="15.000" cy="6.000" r="0.400"/><circle cx="16.000" cy="6.000" r="0.400"/><circle cx="17.000" cy="6.000" r="0.400"/><circle cx="18.000" cy="6.000" r="0.400"/><circle cx="19.000" cy="6.000" r="0.400"/><circle cx="27.000" cy="6.000" r="0.400"/><circle cx="28.000" cy="6.000" r="0.400"/><circle cx="29.000" cy="6.000" r="0.400"/><circle cx="30.000" cy="6.000" r="0.400"/><circle cx="31.000" cy="6.000" r="0.400"/><circle cx="5.000" cy="7.000" r="0.400"/><circle cx="6.000" cy="7.000" r="0.400"/><circle cx="7.000" cy="7.000" r="0.400"/><circle cx="8.000" cy="7.000" r="0.400"/><circle cx="9.000" cy="7.000" r="0.400"/><circle cx="15.000" cy="7.000" r="0.400"/><circle cx="16.000" cy="7.000" r="0.400"/><circle cx="17.000" cy="7.000" r="0.400"/><circle cx="18.000" cy="7.000" r="0.400"/><circle cx="19.000" cy="7.000" r="0.400"/><circle cx="25.000" cy="7.000" r="0.400"/><circle cx="26.000" cy="7.000" r="0.400"/><circle cx="27.000" cy="7.000" r="0.400"/><circle cx="28.000" cy="7.000" r="0.400"/><circle cx="29.000" cy="7.000" r="0.400"/><circle cx="6.000" cy="8.000" r="0.400"/><circle cx="7.000" cy="8.000" r="0.400"/><circle cx="8.000" cy="8.000" r="0.400"/><circle cx="9.000" cy="8.000" r="0.400"/><circle cx="10.000" cy="8.000" r="0.400"/><circle cx="15.000" cy="8.000" r="0.400"/><circle cx="16.000" cy="8.000" r="0.400"/><circle cx="17.000" cy="8.000" r="0.400"/><circle cx="18.000" cy="8.000" r="0.400"/><circle cx="19.000" cy="8.000" r="0.400"/><circle cx="24.000" cy="8.000" r="0.400"/><circle cx="25.000" cy="8.000" r="0.400"/><circle cx="26.000" cy="8.000" r="0.400"/><circle cx="27.000" cy="8.000" r="0.400"/><circle cx="28.000" cy="8.000" r="0.400"/><circle cx="3.000" cy="9.000" r="0.400"/><circle cx="8.000" cy="9.000" r="0.400"/><circle cx="9.000" cy="9.000" r="0.400"/><circle cx="10.000" cy="9.000" r="0.400"/><circle cx="11.000" cy="9.000" r="0.400"/><circle cx="15.000" cy="9.000" r="0.400"/><circle cx="16.000" cy="9.000" r="0.400"/><circle cx="17.000" cy="9.000" r="0.400"/><circle cx="18.000" cy="9.000" r="0.400"/><circle cx="19.000" cy="9.000" r="0.400"/><circle cx="23.000" cy="9.000" r="0.400"/><circle cx="24.000" cy="9.000" r="0.400"/><circle cx="25.000" cy="9.000" r="0.400"/><circle cx="26.000" cy="9.000" r="0.400"/><circle cx="31.000" cy="9.000" r="0.400"/><circle cx="2.000" cy="10.000" r="0.400"/><circle cx="3.000" cy="10.000" r="0.400"/><circle cx="4.000" cy="10.000" r="0.400"/><circle cx="5.000" cy="10.000" r="0.400"/><circle cx="6.000" cy="10.000" r="0.400"/><circle cx="10.000" cy="10.000" r="0.400"/><circle cx="11.000" cy="10.000" r="0.400"/><circle cx="12.000" cy="10.000" r="0.400"/><circle cx="13.000" cy="10.000" r="0.400"/><circle cx="16.000" cy="10.000" r="0.400"/><circle cx="17.000" cy="10.000" r="0.400"/><circle cx="18.000" cy="10.000" r="0.400"/><circle cx="21.000" cy="10.000" r="0.400"/><circle cx="22.000" cy="10.000" r="0.400"/><circle cx="23.000" cy="10.000" r="0.400"/><circle cx="24.000" cy="10.000" r="0.400"/><circle cx="28.000" cy="10.000" r="0.400"/><circle cx="29.000" cy="10.000" r="0.400"/><circle cx="30.000" cy="10.000" r="0.400"/><circle cx="31.000" cy="10.000" r="0.400"/><circle cx="32.000" cy="10.000" r="0.400"/><circle cx="2.000" cy="11.000" r="0.400"/><circle cx="3.000" cy="11.000" r="0.400"/><circle cx="4.000" cy="11.000" r="0.400"/><circle cx="5.000" cy="11.000" r="0.400"/><circle cx="6.000" cy="11.000" r="0.400"/><circle cx="7.000" cy="11.000" r="0.400"/><circle cx="8.000" cy="11.000" r="0.400"/><circle cx="9.000" cy="11.000" r="0.400"/><circle cx="10.000" cy="11.000" r="0.400"/><circle cx="11.000" cy="11.000" r="0.400"/><circle cx="12.000" cy="11.000" r="0.400"/><circle cx="13.000" cy="11.000" r="0.400"/><circle cx="14.000" cy="11.000" r="0.400"/><circle cx="16.000" cy="11.000" r="0.400"/><circle cx="17.000" cy="11.000" r="0.400"/><circle cx="18.000" cy="11.000" r="0.400"/><circle cx="20.000" cy="11.000" r="0.400"/><circle cx="21.000" cy="11.000" r="0.400"/><circle cx="22.000" cy="11.000" r="0.400"/><circle cx="23.000" cy="11.000Line truncated

After

Width:  |  Height:  |  Size: 13 KiB

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 662.866 200" width="662.866" height="200" role="img" aria-label="SimurgArray"><title>SimurgArray</title><g fill="#111111"><circle cx="46.667" cy="42.222" r="1.778"/><circle cx="51.111" cy="42.222" r="1.778"/><circle cx="166.667" cy="42.222" r="1.778"/><circle cx="171.111" cy="42.222" r="1.778"/><circle cx="46.667" cy="46.667" r="1.778"/><circle cx="51.111" cy="46.667" r="1.778"/><circle cx="55.556" cy="46.667" r="1.778"/><circle cx="100.000" cy="46.667" r="1.778"/><circle cx="108.889" cy="46.667" r="1.778"/><circle cx="117.778" cy="46.667" r="1.778"/><circle cx="162.222" cy="46.667" r="1.778"/><circle cx="166.667" cy="46.667" r="1.778"/><circle cx="171.111" cy="46.667" r="1.778"/><circle cx="46.667" cy="51.111" r="1.778"/><circle cx="51.111" cy="51.111" r="1.778"/><circle cx="55.556" cy="51.111" r="1.778"/><circle cx="60.000" cy="51.111" r="1.778"/><circle cx="64.444" cy="51.111" r="1.778"/><circle cx="100.000" cy="51.111" r="1.778"/><circle cx="104.444" cy="51.111" r="1.778"/><circle cx="108.889" cy="51.111" r="1.778"/><circle cx="113.333" cy="51.111" r="1.778"/><circle cx="117.778" cy="51.111" r="1.778"/><circle cx="153.333" cy="51.111" r="1.778"/><circle cx="157.778" cy="51.111" r="1.778"/><circle cx="162.222" cy="51.111" r="1.778"/><circle cx="166.667" cy="51.111" r="1.778"/><circle cx="171.111" cy="51.111" r="1.778"/><circle cx="55.556" cy="55.556" r="1.778"/><circle cx="60.000" cy="55.556" r="1.778"/><circle cx="64.444" cy="55.556" r="1.778"/><circle cx="68.889" cy="55.556" r="1.778"/><circle cx="73.333" cy="55.556" r="1.778"/><circle cx="100.000" cy="55.556" r="1.778"/><circle cx="104.444" cy="55.556" r="1.778"/><circle cx="108.889" cy="55.556" r="1.778"/><circle cx="113.333" cy="55.556" r="1.778"/><circle cx="117.778" cy="55.556" r="1.778"/><circle cx="144.444" cy="55.556" r="1.778"/><circle cx="148.889" cy="55.556" r="1.778"/><circle cx="153.333" cy="55.556" r="1.778"/><circle cx="157.778" cy="55.556" r="1.778"/><circle cx="162.222" cy="55.556" r="1.778"/><circle cx="60.000" cy="60.000" r="1.778"/><circle cx="64.444" cy="60.000" r="1.778"/><circle cx="68.889" cy="60.000" r="1.778"/><circle cx="73.333" cy="60.000" r="1.778"/><circle cx="77.778" cy="60.000" r="1.778"/><circle cx="100.000" cy="60.000" r="1.778"/><circle cx="104.444" cy="60.000" r="1.778"/><circle cx="108.889" cy="60.000" r="1.778"/><circle cx="113.333" cy="60.000" r="1.778"/><circle cx="117.778" cy="60.000" r="1.778"/><circle cx="140.000" cy="60.000" r="1.778"/><circle cx="144.444" cy="60.000" r="1.778"/><circle cx="148.889" cy="60.000" r="1.778"/><circle cx="153.333" cy="60.000" r="1.778"/><circle cx="157.778" cy="60.000" r="1.778"/><circle cx="46.667" cy="64.444" r="1.778"/><circle cx="68.889" cy="64.444" r="1.778"/><circle cx="73.333" cy="64.444" r="1.778"/><circle cx="77.778" cy="64.444" r="1.778"/><circle cx="82.222" cy="64.444" r="1.778"/><circle cx="100.000" cy="64.444" r="1.778"/><circle cx="104.444" cy="64.444" r="1.778"/><circle cx="108.889" cy="64.444" r="1.778"/><circle cx="113.333" cy="64.444" r="1.778"/><circle cx="117.778" cy="64.444" r="1.778"/><circle cx="135.556" cy="64.444" r="1.778"/><circle cx="140.000" cy="64.444" r="1.778"/><circle cx="144.444" cy="64.444" r="1.778"/><circle cx="148.889" cy="64.444" r="1.778"/><circle cx="171.111" cy="64.444" r="1.778"/><circle cx="42.222" cy="68.889" r="1.778"/><circle cx="46.667" cy="68.889" r="1.778"/><circle cx="51.111" cy="68.889" r="1.778"/><circle cx="55.556" cy="68.889" r="1.778"/><circle cx="60.000" cy="68.889" r="1.778"/><circle cx="77.778" cy="68.889" r="1.778"/><circle cx="82.222" cy="68.889" r="1.778"/><circle cx="86.667" cy="68.889" r="1.778"/><circle cx="91.111" cy="68.889" r="1.778"/><circle cx="104.444" cy="68.889" r="1.778"/><circle cx="108.889" cy="68.889" r="1.778"/><circle cx="113.333" cy="68.889" r="1.778"/><circle cx="126.667" cy="68.889" r="1.778"/><circle cx="131.111" cy="68.889" r="1.778"/><circle cx="135.556" cy="68.889" r="1.778"/><circle cx="140.000" cy="68.889" r="1.778"/><circle cx="157.778" cy="68.889" r="1.778"/><circle cx="162.222" cy="68.889" r="1.778"/><circle cx="166.667" cy="68.889" r="1.778"/><circle cx="171.111" cy="68.889" r="1.778"/><circle cx="175.556" cy="68.889" r="1.778"/><circle cx="42.222" cy="73.333" r="1.778"/><circle cx="46.667" cy="73.333" r="1.778"/><circle cx="51.111" cy="73.333" r="1.778"/><circle cx="55.556" cy="73.333" r="1.778"/><circle cx="60.000" cy="73.333" r="1.778"/><circle cx="64.444" cy="73.333" r="1.778"/><circle cx="68.889" cy="73.333" r="1.778"/><circle cx="73.333" cy="73.333" r="1.778"/><circle cx="77.778" cy="73.333" r="1.778"/><circle cx="82.222" cy="73.333" r="1.778"/><circle cx="86.667" cy="73.333" r="1.778"/><circle cx="91.111" cy="73.333" r="1.778"/><circle cx="95.556" cy="73.333" r="1.778"/><circle cx="104.444" cy="73.333" r="1.778"/><circle cx="108.889" cy="73.333" r="1.778"/><circle cx="113.333" cy="73.333" r="1.778"/><circle cx="122.222" cy="73.333Line truncated

After

Width:  |  Height:  |  Size: 23 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 662.866 200" width="662.866" height="200" role="img" aria-label="SimurgArray"><title>SimurgArray</title><rect width="662.865777777778" height="200" fill="#1E2240"/><g fill="#D4A017"><circle cx="46.667" cy="42.222" r="1.778"/><circle cx="51.111" cy="42.222" r="1.778"/><circle cx="166.667" cy="42.222" r="1.778"/><circle cx="171.111" cy="42.222" r="1.778"/><circle cx="46.667" cy="46.667" r="1.778"/><circle cx="51.111" cy="46.667" r="1.778"/><circle cx="55.556" cy="46.667" r="1.778"/><circle cx="100.000" cy="46.667" r="1.778"/><circle cx="108.889" cy="46.667" r="1.778"/><circle cx="117.778" cy="46.667" r="1.778"/><circle cx="162.222" cy="46.667" r="1.778"/><circle cx="166.667" cy="46.667" r="1.778"/><circle cx="171.111" cy="46.667" r="1.778"/><circle cx="46.667" cy="51.111" r="1.778"/><circle cx="51.111" cy="51.111" r="1.778"/><circle cx="55.556" cy="51.111" r="1.778"/><circle cx="60.000" cy="51.111" r="1.778"/><circle cx="64.444" cy="51.111" r="1.778"/><circle cx="100.000" cy="51.111" r="1.778"/><circle cx="104.444" cy="51.111" r="1.778"/><circle cx="108.889" cy="51.111" r="1.778"/><circle cx="113.333" cy="51.111" r="1.778"/><circle cx="117.778" cy="51.111" r="1.778"/><circle cx="153.333" cy="51.111" r="1.778"/><circle cx="157.778" cy="51.111" r="1.778"/><circle cx="162.222" cy="51.111" r="1.778"/><circle cx="166.667" cy="51.111" r="1.778"/><circle cx="171.111" cy="51.111" r="1.778"/><circle cx="55.556" cy="55.556" r="1.778"/><circle cx="60.000" cy="55.556" r="1.778"/><circle cx="64.444" cy="55.556" r="1.778"/><circle cx="68.889" cy="55.556" r="1.778"/><circle cx="73.333" cy="55.556" r="1.778"/><circle cx="100.000" cy="55.556" r="1.778"/><circle cx="104.444" cy="55.556" r="1.778"/><circle cx="108.889" cy="55.556" r="1.778"/><circle cx="113.333" cy="55.556" r="1.778"/><circle cx="117.778" cy="55.556" r="1.778"/><circle cx="144.444" cy="55.556" r="1.778"/><circle cx="148.889" cy="55.556" r="1.778"/><circle cx="153.333" cy="55.556" r="1.778"/><circle cx="157.778" cy="55.556" r="1.778"/><circle cx="162.222" cy="55.556" r="1.778"/><circle cx="60.000" cy="60.000" r="1.778"/><circle cx="64.444" cy="60.000" r="1.778"/><circle cx="68.889" cy="60.000" r="1.778"/><circle cx="73.333" cy="60.000" r="1.778"/><circle cx="77.778" cy="60.000" r="1.778"/><circle cx="100.000" cy="60.000" r="1.778"/><circle cx="104.444" cy="60.000" r="1.778"/><circle cx="108.889" cy="60.000" r="1.778"/><circle cx="113.333" cy="60.000" r="1.778"/><circle cx="117.778" cy="60.000" r="1.778"/><circle cx="140.000" cy="60.000" r="1.778"/><circle cx="144.444" cy="60.000" r="1.778"/><circle cx="148.889" cy="60.000" r="1.778"/><circle cx="153.333" cy="60.000" r="1.778"/><circle cx="157.778" cy="60.000" r="1.778"/><circle cx="46.667" cy="64.444" r="1.778"/><circle cx="68.889" cy="64.444" r="1.778"/><circle cx="73.333" cy="64.444" r="1.778"/><circle cx="77.778" cy="64.444" r="1.778"/><circle cx="82.222" cy="64.444" r="1.778"/><circle cx="100.000" cy="64.444" r="1.778"/><circle cx="104.444" cy="64.444" r="1.778"/><circle cx="108.889" cy="64.444" r="1.778"/><circle cx="113.333" cy="64.444" r="1.778"/><circle cx="117.778" cy="64.444" r="1.778"/><circle cx="135.556" cy="64.444" r="1.778"/><circle cx="140.000" cy="64.444" r="1.778"/><circle cx="144.444" cy="64.444" r="1.778"/><circle cx="148.889" cy="64.444" r="1.778"/><circle cx="171.111" cy="64.444" r="1.778"/><circle cx="42.222" cy="68.889" r="1.778"/><circle cx="46.667" cy="68.889" r="1.778"/><circle cx="51.111" cy="68.889" r="1.778"/><circle cx="55.556" cy="68.889" r="1.778"/><circle cx="60.000" cy="68.889" r="1.778"/><circle cx="77.778" cy="68.889" r="1.778"/><circle cx="82.222" cy="68.889" r="1.778"/><circle cx="86.667" cy="68.889" r="1.778"/><circle cx="91.111" cy="68.889" r="1.778"/><circle cx="104.444" cy="68.889" r="1.778"/><circle cx="108.889" cy="68.889" r="1.778"/><circle cx="113.333" cy="68.889" r="1.778"/><circle cx="126.667" cy="68.889" r="1.778"/><circle cx="131.111" cy="68.889" r="1.778"/><circle cx="135.556" cy="68.889" r="1.778"/><circle cx="140.000" cy="68.889" r="1.778"/><circle cx="157.778" cy="68.889" r="1.778"/><circle cx="162.222" cy="68.889" r="1.778"/><circle cx="166.667" cy="68.889" r="1.778"/><circle cx="171.111" cy="68.889" r="1.778"/><circle cx="175.556" cy="68.889" r="1.778"/><circle cx="42.222" cy="73.333" r="1.778"/><circle cx="46.667" cy="73.333" r="1.778"/><circle cx="51.111" cy="73.333" r="1.778"/><circle cx="55.556" cy="73.333" r="1.778"/><circle cx="60.000" cy="73.333" r="1.778"/><circle cx="64.444" cy="73.333" r="1.778"/><circle cx="68.889" cy="73.333" r="1.778"/><circle cx="73.333" cy="73.333" r="1.778"/><circle cx="77.778" cy="73.333" r="1.778"/><circle cx="82.222" cy="73.333" r="1.778"/><circle cx="86.667" cy="73.333" r="1.778"/><circle cx="91.111" cy="73.333" r="1.778"/><circle cx="95.556" cy="73.333" r="1.778"/><circle cx="104.444" cy="73.333" r="1.778"/><circle cx="108.889" cy="73.333" r="1.778"/><circle cx="113Line truncated

After

Width:  |  Height:  |  Size: 23 KiB

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 662.866 200" width="662.866" height="200" role="img" aria-label="SimurgArray"><title>SimurgArray</title><rect width="662.865777777778" height="200" fill="#F7F5EF"/><g fill="#A87A00"><circle cx="46.667" cy="42.222" r="1.778"/><circle cx="51.111" cy="42.222" r="1.778"/><circle cx="166.667" cy="42.222" r="1.778"/><circle cx="171.111" cy="42.222" r="1.778"/><circle cx="46.667" cy="46.667" r="1.778"/><circle cx="51.111" cy="46.667" r="1.778"/><circle cx="55.556" cy="46.667" r="1.778"/><circle cx="100.000" cy="46.667" r="1.778"/><circle cx="108.889" cy="46.667" r="1.778"/><circle cx="117.778" cy="46.667" r="1.778"/><circle cx="162.222" cy="46.667" r="1.778"/><circle cx="166.667" cy="46.667" r="1.778"/><circle cx="171.111" cy="46.667" r="1.778"/><circle cx="46.667" cy="51.111" r="1.778"/><circle cx="51.111" cy="51.111" r="1.778"/><circle cx="55.556" cy="51.111" r="1.778"/><circle cx="60.000" cy="51.111" r="1.778"/><circle cx="64.444" cy="51.111" r="1.778"/><circle cx="100.000" cy="51.111" r="1.778"/><circle cx="104.444" cy="51.111" r="1.778"/><circle cx="108.889" cy="51.111" r="1.778"/><circle cx="113.333" cy="51.111" r="1.778"/><circle cx="117.778" cy="51.111" r="1.778"/><circle cx="153.333" cy="51.111" r="1.778"/><circle cx="157.778" cy="51.111" r="1.778"/><circle cx="162.222" cy="51.111" r="1.778"/><circle cx="166.667" cy="51.111" r="1.778"/><circle cx="171.111" cy="51.111" r="1.778"/><circle cx="55.556" cy="55.556" r="1.778"/><circle cx="60.000" cy="55.556" r="1.778"/><circle cx="64.444" cy="55.556" r="1.778"/><circle cx="68.889" cy="55.556" r="1.778"/><circle cx="73.333" cy="55.556" r="1.778"/><circle cx="100.000" cy="55.556" r="1.778"/><circle cx="104.444" cy="55.556" r="1.778"/><circle cx="108.889" cy="55.556" r="1.778"/><circle cx="113.333" cy="55.556" r="1.778"/><circle cx="117.778" cy="55.556" r="1.778"/><circle cx="144.444" cy="55.556" r="1.778"/><circle cx="148.889" cy="55.556" r="1.778"/><circle cx="153.333" cy="55.556" r="1.778"/><circle cx="157.778" cy="55.556" r="1.778"/><circle cx="162.222" cy="55.556" r="1.778"/><circle cx="60.000" cy="60.000" r="1.778"/><circle cx="64.444" cy="60.000" r="1.778"/><circle cx="68.889" cy="60.000" r="1.778"/><circle cx="73.333" cy="60.000" r="1.778"/><circle cx="77.778" cy="60.000" r="1.778"/><circle cx="100.000" cy="60.000" r="1.778"/><circle cx="104.444" cy="60.000" r="1.778"/><circle cx="108.889" cy="60.000" r="1.778"/><circle cx="113.333" cy="60.000" r="1.778"/><circle cx="117.778" cy="60.000" r="1.778"/><circle cx="140.000" cy="60.000" r="1.778"/><circle cx="144.444" cy="60.000" r="1.778"/><circle cx="148.889" cy="60.000" r="1.778"/><circle cx="153.333" cy="60.000" r="1.778"/><circle cx="157.778" cy="60.000" r="1.778"/><circle cx="46.667" cy="64.444" r="1.778"/><circle cx="68.889" cy="64.444" r="1.778"/><circle cx="73.333" cy="64.444" r="1.778"/><circle cx="77.778" cy="64.444" r="1.778"/><circle cx="82.222" cy="64.444" r="1.778"/><circle cx="100.000" cy="64.444" r="1.778"/><circle cx="104.444" cy="64.444" r="1.778"/><circle cx="108.889" cy="64.444" r="1.778"/><circle cx="113.333" cy="64.444" r="1.778"/><circle cx="117.778" cy="64.444" r="1.778"/><circle cx="135.556" cy="64.444" r="1.778"/><circle cx="140.000" cy="64.444" r="1.778"/><circle cx="144.444" cy="64.444" r="1.778"/><circle cx="148.889" cy="64.444" r="1.778"/><circle cx="171.111" cy="64.444" r="1.778"/><circle cx="42.222" cy="68.889" r="1.778"/><circle cx="46.667" cy="68.889" r="1.778"/><circle cx="51.111" cy="68.889" r="1.778"/><circle cx="55.556" cy="68.889" r="1.778"/><circle cx="60.000" cy="68.889" r="1.778"/><circle cx="77.778" cy="68.889" r="1.778"/><circle cx="82.222" cy="68.889" r="1.778"/><circle cx="86.667" cy="68.889" r="1.778"/><circle cx="91.111" cy="68.889" r="1.778"/><circle cx="104.444" cy="68.889" r="1.778"/><circle cx="108.889" cy="68.889" r="1.778"/><circle cx="113.333" cy="68.889" r="1.778"/><circle cx="126.667" cy="68.889" r="1.778"/><circle cx="131.111" cy="68.889" r="1.778"/><circle cx="135.556" cy="68.889" r="1.778"/><circle cx="140.000" cy="68.889" r="1.778"/><circle cx="157.778" cy="68.889" r="1.778"/><circle cx="162.222" cy="68.889" r="1.778"/><circle cx="166.667" cy="68.889" r="1.778"/><circle cx="171.111" cy="68.889" r="1.778"/><circle cx="175.556" cy="68.889" r="1.778"/><circle cx="42.222" cy="73.333" r="1.778"/><circle cx="46.667" cy="73.333" r="1.778"/><circle cx="51.111" cy="73.333" r="1.778"/><circle cx="55.556" cy="73.333" r="1.778"/><circle cx="60.000" cy="73.333" r="1.778"/><circle cx="64.444" cy="73.333" r="1.778"/><circle cx="68.889" cy="73.333" r="1.778"/><circle cx="73.333" cy="73.333" r="1.778"/><circle cx="77.778" cy="73.333" r="1.778"/><circle cx="82.222" cy="73.333" r="1.778"/><circle cx="86.667" cy="73.333" r="1.778"/><circle cx="91.111" cy="73.333" r="1.778"/><circle cx="95.556" cy="73.333" r="1.778"/><circle cx="104.444" cy="73.333" r="1.778"/><circle cx="108.889" cy="73.333" r="1.778"/><circle cx="113Line truncated

After

Width:  |  Height:  |  Size: 23 KiB

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 662.866 200" width="662.866" height="200" role="img" aria-label="SimurgArray"><title>SimurgArray</title><g fill="#FFFFFF"><circle cx="46.667" cy="42.222" r="1.778"/><circle cx="51.111" cy="42.222" r="1.778"/><circle cx="166.667" cy="42.222" r="1.778"/><circle cx="171.111" cy="42.222" r="1.778"/><circle cx="46.667" cy="46.667" r="1.778"/><circle cx="51.111" cy="46.667" r="1.778"/><circle cx="55.556" cy="46.667" r="1.778"/><circle cx="100.000" cy="46.667" r="1.778"/><circle cx="108.889" cy="46.667" r="1.778"/><circle cx="117.778" cy="46.667" r="1.778"/><circle cx="162.222" cy="46.667" r="1.778"/><circle cx="166.667" cy="46.667" r="1.778"/><circle cx="171.111" cy="46.667" r="1.778"/><circle cx="46.667" cy="51.111" r="1.778"/><circle cx="51.111" cy="51.111" r="1.778"/><circle cx="55.556" cy="51.111" r="1.778"/><circle cx="60.000" cy="51.111" r="1.778"/><circle cx="64.444" cy="51.111" r="1.778"/><circle cx="100.000" cy="51.111" r="1.778"/><circle cx="104.444" cy="51.111" r="1.778"/><circle cx="108.889" cy="51.111" r="1.778"/><circle cx="113.333" cy="51.111" r="1.778"/><circle cx="117.778" cy="51.111" r="1.778"/><circle cx="153.333" cy="51.111" r="1.778"/><circle cx="157.778" cy="51.111" r="1.778"/><circle cx="162.222" cy="51.111" r="1.778"/><circle cx="166.667" cy="51.111" r="1.778"/><circle cx="171.111" cy="51.111" r="1.778"/><circle cx="55.556" cy="55.556" r="1.778"/><circle cx="60.000" cy="55.556" r="1.778"/><circle cx="64.444" cy="55.556" r="1.778"/><circle cx="68.889" cy="55.556" r="1.778"/><circle cx="73.333" cy="55.556" r="1.778"/><circle cx="100.000" cy="55.556" r="1.778"/><circle cx="104.444" cy="55.556" r="1.778"/><circle cx="108.889" cy="55.556" r="1.778"/><circle cx="113.333" cy="55.556" r="1.778"/><circle cx="117.778" cy="55.556" r="1.778"/><circle cx="144.444" cy="55.556" r="1.778"/><circle cx="148.889" cy="55.556" r="1.778"/><circle cx="153.333" cy="55.556" r="1.778"/><circle cx="157.778" cy="55.556" r="1.778"/><circle cx="162.222" cy="55.556" r="1.778"/><circle cx="60.000" cy="60.000" r="1.778"/><circle cx="64.444" cy="60.000" r="1.778"/><circle cx="68.889" cy="60.000" r="1.778"/><circle cx="73.333" cy="60.000" r="1.778"/><circle cx="77.778" cy="60.000" r="1.778"/><circle cx="100.000" cy="60.000" r="1.778"/><circle cx="104.444" cy="60.000" r="1.778"/><circle cx="108.889" cy="60.000" r="1.778"/><circle cx="113.333" cy="60.000" r="1.778"/><circle cx="117.778" cy="60.000" r="1.778"/><circle cx="140.000" cy="60.000" r="1.778"/><circle cx="144.444" cy="60.000" r="1.778"/><circle cx="148.889" cy="60.000" r="1.778"/><circle cx="153.333" cy="60.000" r="1.778"/><circle cx="157.778" cy="60.000" r="1.778"/><circle cx="46.667" cy="64.444" r="1.778"/><circle cx="68.889" cy="64.444" r="1.778"/><circle cx="73.333" cy="64.444" r="1.778"/><circle cx="77.778" cy="64.444" r="1.778"/><circle cx="82.222" cy="64.444" r="1.778"/><circle cx="100.000" cy="64.444" r="1.778"/><circle cx="104.444" cy="64.444" r="1.778"/><circle cx="108.889" cy="64.444" r="1.778"/><circle cx="113.333" cy="64.444" r="1.778"/><circle cx="117.778" cy="64.444" r="1.778"/><circle cx="135.556" cy="64.444" r="1.778"/><circle cx="140.000" cy="64.444" r="1.778"/><circle cx="144.444" cy="64.444" r="1.778"/><circle cx="148.889" cy="64.444" r="1.778"/><circle cx="171.111" cy="64.444" r="1.778"/><circle cx="42.222" cy="68.889" r="1.778"/><circle cx="46.667" cy="68.889" r="1.778"/><circle cx="51.111" cy="68.889" r="1.778"/><circle cx="55.556" cy="68.889" r="1.778"/><circle cx="60.000" cy="68.889" r="1.778"/><circle cx="77.778" cy="68.889" r="1.778"/><circle cx="82.222" cy="68.889" r="1.778"/><circle cx="86.667" cy="68.889" r="1.778"/><circle cx="91.111" cy="68.889" r="1.778"/><circle cx="104.444" cy="68.889" r="1.778"/><circle cx="108.889" cy="68.889" r="1.778"/><circle cx="113.333" cy="68.889" r="1.778"/><circle cx="126.667" cy="68.889" r="1.778"/><circle cx="131.111" cy="68.889" r="1.778"/><circle cx="135.556" cy="68.889" r="1.778"/><circle cx="140.000" cy="68.889" r="1.778"/><circle cx="157.778" cy="68.889" r="1.778"/><circle cx="162.222" cy="68.889" r="1.778"/><circle cx="166.667" cy="68.889" r="1.778"/><circle cx="171.111" cy="68.889" r="1.778"/><circle cx="175.556" cy="68.889" r="1.778"/><circle cx="42.222" cy="73.333" r="1.778"/><circle cx="46.667" cy="73.333" r="1.778"/><circle cx="51.111" cy="73.333" r="1.778"/><circle cx="55.556" cy="73.333" r="1.778"/><circle cx="60.000" cy="73.333" r="1.778"/><circle cx="64.444" cy="73.333" r="1.778"/><circle cx="68.889" cy="73.333" r="1.778"/><circle cx="73.333" cy="73.333" r="1.778"/><circle cx="77.778" cy="73.333" r="1.778"/><circle cx="82.222" cy="73.333" r="1.778"/><circle cx="86.667" cy="73.333" r="1.778"/><circle cx="91.111" cy="73.333" r="1.778"/><circle cx="95.556" cy="73.333" r="1.778"/><circle cx="104.444" cy="73.333" r="1.778"/><circle cx="108.889" cy="73.333" r="1.778"/><circle cx="113.333" cy="73.333" r="1.778"/><circle cx="122.222" cy="73.333Line truncated

After

Width:  |  Height:  |  Size: 23 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 456.02 360" width="456.02" height="360" role="img" aria-label="SimurgArray"><title>SimurgArray</title><g fill="#111111"><circle cx="124.306" cy="43.704" r="2.963"/><circle cx="131.714" cy="43.704" r="2.963"/><circle cx="324.306" cy="43.704" r="2.963"/><circle cx="331.714" cy="43.704" r="2.963"/><circle cx="124.306" cy="51.111" r="2.963"/><circle cx="131.714" cy="51.111" r="2.963"/><circle cx="139.121" cy="51.111" r="2.963"/><circle cx="213.195" cy="51.111" r="2.963"/><circle cx="228.010" cy="51.111" r="2.963"/><circle cx="242.825" cy="51.111" r="2.963"/><circle cx="316.899" cy="51.111" r="2.963"/><circle cx="324.306" cy="51.111" r="2.963"/><circle cx="331.714" cy="51.111" r="2.963"/><circle cx="124.306" cy="58.519" r="2.963"/><circle cx="131.714" cy="58.519" r="2.963"/><circle cx="139.121" cy="58.519" r="2.963"/><circle cx="146.529" cy="58.519" r="2.963"/><circle cx="153.936" cy="58.519" r="2.963"/><circle cx="213.195" cy="58.519" r="2.963"/><circle cx="220.603" cy="58.519" r="2.963"/><circle cx="228.010" cy="58.519" r="2.963"/><circle cx="235.417" cy="58.519" r="2.963"/><circle cx="242.825" cy="58.519" r="2.963"/><circle cx="302.084" cy="58.519" r="2.963"/><circle cx="309.491" cy="58.519" r="2.963"/><circle cx="316.899" cy="58.519" r="2.963"/><circle cx="324.306" cy="58.519" r="2.963"/><circle cx="331.714" cy="58.519" r="2.963"/><circle cx="139.121" cy="65.926" r="2.963"/><circle cx="146.529" cy="65.926" r="2.963"/><circle cx="153.936" cy="65.926" r="2.963"/><circle cx="161.343" cy="65.926" r="2.963"/><circle cx="168.751" cy="65.926" r="2.963"/><circle cx="213.195" cy="65.926" r="2.963"/><circle cx="220.603" cy="65.926" r="2.963"/><circle cx="228.010" cy="65.926" r="2.963"/><circle cx="235.417" cy="65.926" r="2.963"/><circle cx="242.825" cy="65.926" r="2.963"/><circle cx="287.269" cy="65.926" r="2.963"/><circle cx="294.677" cy="65.926" r="2.963"/><circle cx="302.084" cy="65.926" r="2.963"/><circle cx="309.491" cy="65.926" r="2.963"/><circle cx="316.899" cy="65.926" r="2.963"/><circle cx="146.529" cy="73.333" r="2.963"/><circle cx="153.936" cy="73.333" r="2.963"/><circle cx="161.343" cy="73.333" r="2.963"/><circle cx="168.751" cy="73.333" r="2.963"/><circle cx="176.158" cy="73.333" r="2.963"/><circle cx="213.195" cy="73.333" r="2.963"/><circle cx="220.603" cy="73.333" r="2.963"/><circle cx="228.010" cy="73.333" r="2.963"/><circle cx="235.417" cy="73.333" r="2.963"/><circle cx="242.825" cy="73.333" r="2.963"/><circle cx="279.862" cy="73.333" r="2.963"/><circle cx="287.269" cy="73.333" r="2.963"/><circle cx="294.677" cy="73.333" r="2.963"/><circle cx="302.084" cy="73.333" r="2.963"/><circle cx="309.491" cy="73.333" r="2.963"/><circle cx="124.306" cy="80.741" r="2.963"/><circle cx="161.343" cy="80.741" r="2.963"/><circle cx="168.751" cy="80.741" r="2.963"/><circle cx="176.158" cy="80.741" r="2.963"/><circle cx="183.566" cy="80.741" r="2.963"/><circle cx="213.195" cy="80.741" r="2.963"/><circle cx="220.603" cy="80.741" r="2.963"/><circle cx="228.010" cy="80.741" r="2.963"/><circle cx="235.417" cy="80.741" r="2.963"/><circle cx="242.825" cy="80.741" r="2.963"/><circle cx="272.454" cy="80.741" r="2.963"/><circle cx="279.862" cy="80.741" r="2.963"/><circle cx="287.269" cy="80.741" r="2.963"/><circle cx="294.677" cy="80.741" r="2.963"/><circle cx="331.714" cy="80.741" r="2.963"/><circle cx="116.899" cy="88.148" r="2.963"/><circle cx="124.306" cy="88.148" r="2.963"/><circle cx="131.714" cy="88.148" r="2.963"/><circle cx="139.121" cy="88.148" r="2.963"/><circle cx="146.529" cy="88.148" r="2.963"/><circle cx="176.158" cy="88.148" r="2.963"/><circle cx="183.566" cy="88.148" r="2.963"/><circle cx="190.973" cy="88.148" r="2.963"/><circle cx="198.380" cy="88.148" r="2.963"/><circle cx="220.603" cy="88.148" r="2.963"/><circle cx="228.010" cy="88.148" r="2.963"/><circle cx="235.417" cy="88.148" r="2.963"/><circle cx="257.640" cy="88.148" r="2.963"/><circle cx="265.047" cy="88.148" r="2.963"/><circle cx="272.454" cy="88.148" r="2.963"/><circle cx="279.862" cy="88.148" r="2.963"/><circle cx="309.491" cy="88.148" r="2.963"/><circle cx="316.899" cy="88.148" r="2.963"/><circle cx="324.306" cy="88.148" r="2.963"/><circle cx="331.714" cy="88.148" r="2.963"/><circle cx="339.121" cy="88.148" r="2.963"/><circle cx="116.899" cy="95.556" r="2.963"/><circle cx="124.306" cy="95.556" r="2.963"/><circle cx="131.714" cy="95.556" r="2.963"/><circle cx="139.121" cy="95.556" r="2.963"/><circle cx="146.529" cy="95.556" r="2.963"/><circle cx="153.936" cy="95.556" r="2.963"/><circle cx="161.343" cy="95.556" r="2.963"/><circle cx="168.751" cy="95.556" r="2.963"/><circle cx="176.158" cy="95.556" r="2.963"/><circle cx="183.566" cy="95.556" r="2.963"/><circle cx="190.973" cy="95.556" r="2.963"/><circle cx="198.380" cy="95.556" r="2.963"/><circle cx="205.788" cy="95.556" r="2.963"/><circle cx="220.603" cy="95.556" r="2.963"/><circle cx="228.010" cy="95.556" r="2.963"/><circle cx="235.417" cy="95.55Line truncated

After

Width:  |  Height:  |  Size: 23 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 456.02 360" width="456.02" height="360" role="img" aria-label="SimurgArray"><title>SimurgArray</title><rect width="456.0199999999999" height="360.0" fill="#1E2240"/><g fill="#D4A017"><circle cx="124.306" cy="43.704" r="2.963"/><circle cx="131.714" cy="43.704" r="2.963"/><circle cx="324.306" cy="43.704" r="2.963"/><circle cx="331.714" cy="43.704" r="2.963"/><circle cx="124.306" cy="51.111" r="2.963"/><circle cx="131.714" cy="51.111" r="2.963"/><circle cx="139.121" cy="51.111" r="2.963"/><circle cx="213.195" cy="51.111" r="2.963"/><circle cx="228.010" cy="51.111" r="2.963"/><circle cx="242.825" cy="51.111" r="2.963"/><circle cx="316.899" cy="51.111" r="2.963"/><circle cx="324.306" cy="51.111" r="2.963"/><circle cx="331.714" cy="51.111" r="2.963"/><circle cx="124.306" cy="58.519" r="2.963"/><circle cx="131.714" cy="58.519" r="2.963"/><circle cx="139.121" cy="58.519" r="2.963"/><circle cx="146.529" cy="58.519" r="2.963"/><circle cx="153.936" cy="58.519" r="2.963"/><circle cx="213.195" cy="58.519" r="2.963"/><circle cx="220.603" cy="58.519" r="2.963"/><circle cx="228.010" cy="58.519" r="2.963"/><circle cx="235.417" cy="58.519" r="2.963"/><circle cx="242.825" cy="58.519" r="2.963"/><circle cx="302.084" cy="58.519" r="2.963"/><circle cx="309.491" cy="58.519" r="2.963"/><circle cx="316.899" cy="58.519" r="2.963"/><circle cx="324.306" cy="58.519" r="2.963"/><circle cx="331.714" cy="58.519" r="2.963"/><circle cx="139.121" cy="65.926" r="2.963"/><circle cx="146.529" cy="65.926" r="2.963"/><circle cx="153.936" cy="65.926" r="2.963"/><circle cx="161.343" cy="65.926" r="2.963"/><circle cx="168.751" cy="65.926" r="2.963"/><circle cx="213.195" cy="65.926" r="2.963"/><circle cx="220.603" cy="65.926" r="2.963"/><circle cx="228.010" cy="65.926" r="2.963"/><circle cx="235.417" cy="65.926" r="2.963"/><circle cx="242.825" cy="65.926" r="2.963"/><circle cx="287.269" cy="65.926" r="2.963"/><circle cx="294.677" cy="65.926" r="2.963"/><circle cx="302.084" cy="65.926" r="2.963"/><circle cx="309.491" cy="65.926" r="2.963"/><circle cx="316.899" cy="65.926" r="2.963"/><circle cx="146.529" cy="73.333" r="2.963"/><circle cx="153.936" cy="73.333" r="2.963"/><circle cx="161.343" cy="73.333" r="2.963"/><circle cx="168.751" cy="73.333" r="2.963"/><circle cx="176.158" cy="73.333" r="2.963"/><circle cx="213.195" cy="73.333" r="2.963"/><circle cx="220.603" cy="73.333" r="2.963"/><circle cx="228.010" cy="73.333" r="2.963"/><circle cx="235.417" cy="73.333" r="2.963"/><circle cx="242.825" cy="73.333" r="2.963"/><circle cx="279.862" cy="73.333" r="2.963"/><circle cx="287.269" cy="73.333" r="2.963"/><circle cx="294.677" cy="73.333" r="2.963"/><circle cx="302.084" cy="73.333" r="2.963"/><circle cx="309.491" cy="73.333" r="2.963"/><circle cx="124.306" cy="80.741" r="2.963"/><circle cx="161.343" cy="80.741" r="2.963"/><circle cx="168.751" cy="80.741" r="2.963"/><circle cx="176.158" cy="80.741" r="2.963"/><circle cx="183.566" cy="80.741" r="2.963"/><circle cx="213.195" cy="80.741" r="2.963"/><circle cx="220.603" cy="80.741" r="2.963"/><circle cx="228.010" cy="80.741" r="2.963"/><circle cx="235.417" cy="80.741" r="2.963"/><circle cx="242.825" cy="80.741" r="2.963"/><circle cx="272.454" cy="80.741" r="2.963"/><circle cx="279.862" cy="80.741" r="2.963"/><circle cx="287.269" cy="80.741" r="2.963"/><circle cx="294.677" cy="80.741" r="2.963"/><circle cx="331.714" cy="80.741" r="2.963"/><circle cx="116.899" cy="88.148" r="2.963"/><circle cx="124.306" cy="88.148" r="2.963"/><circle cx="131.714" cy="88.148" r="2.963"/><circle cx="139.121" cy="88.148" r="2.963"/><circle cx="146.529" cy="88.148" r="2.963"/><circle cx="176.158" cy="88.148" r="2.963"/><circle cx="183.566" cy="88.148" r="2.963"/><circle cx="190.973" cy="88.148" r="2.963"/><circle cx="198.380" cy="88.148" r="2.963"/><circle cx="220.603" cy="88.148" r="2.963"/><circle cx="228.010" cy="88.148" r="2.963"/><circle cx="235.417" cy="88.148" r="2.963"/><circle cx="257.640" cy="88.148" r="2.963"/><circle cx="265.047" cy="88.148" r="2.963"/><circle cx="272.454" cy="88.148" r="2.963"/><circle cx="279.862" cy="88.148" r="2.963"/><circle cx="309.491" cy="88.148" r="2.963"/><circle cx="316.899" cy="88.148" r="2.963"/><circle cx="324.306" cy="88.148" r="2.963"/><circle cx="331.714" cy="88.148" r="2.963"/><circle cx="339.121" cy="88.148" r="2.963"/><circle cx="116.899" cy="95.556" r="2.963"/><circle cx="124.306" cy="95.556" r="2.963"/><circle cx="131.714" cy="95.556" r="2.963"/><circle cx="139.121" cy="95.556" r="2.963"/><circle cx="146.529" cy="95.556" r="2.963"/><circle cx="153.936" cy="95.556" r="2.963"/><circle cx="161.343" cy="95.556" r="2.963"/><circle cx="168.751" cy="95.556" r="2.963"/><circle cx="176.158" cy="95.556" r="2.963"/><circle cx="183.566" cy="95.556" r="2.963"/><circle cx="190.973" cy="95.556" r="2.963"/><circle cx="198.380" cy="95.556" r="2.963"/><circle cx="205.788" cy="95.556" r="2.963"/><circle cx="220.603" cy="95.556" r="2.963"/><circle cx=Line truncated

After

Width:  |  Height:  |  Size: 23 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 456.02 360" width="456.02" height="360" role="img" aria-label="SimurgArray"><title>SimurgArray</title><rect width="456.0199999999999" height="360.0" fill="#F7F5EF"/><g fill="#A87A00"><circle cx="124.306" cy="43.704" r="2.963"/><circle cx="131.714" cy="43.704" r="2.963"/><circle cx="324.306" cy="43.704" r="2.963"/><circle cx="331.714" cy="43.704" r="2.963"/><circle cx="124.306" cy="51.111" r="2.963"/><circle cx="131.714" cy="51.111" r="2.963"/><circle cx="139.121" cy="51.111" r="2.963"/><circle cx="213.195" cy="51.111" r="2.963"/><circle cx="228.010" cy="51.111" r="2.963"/><circle cx="242.825" cy="51.111" r="2.963"/><circle cx="316.899" cy="51.111" r="2.963"/><circle cx="324.306" cy="51.111" r="2.963"/><circle cx="331.714" cy="51.111" r="2.963"/><circle cx="124.306" cy="58.519" r="2.963"/><circle cx="131.714" cy="58.519" r="2.963"/><circle cx="139.121" cy="58.519" r="2.963"/><circle cx="146.529" cy="58.519" r="2.963"/><circle cx="153.936" cy="58.519" r="2.963"/><circle cx="213.195" cy="58.519" r="2.963"/><circle cx="220.603" cy="58.519" r="2.963"/><circle cx="228.010" cy="58.519" r="2.963"/><circle cx="235.417" cy="58.519" r="2.963"/><circle cx="242.825" cy="58.519" r="2.963"/><circle cx="302.084" cy="58.519" r="2.963"/><circle cx="309.491" cy="58.519" r="2.963"/><circle cx="316.899" cy="58.519" r="2.963"/><circle cx="324.306" cy="58.519" r="2.963"/><circle cx="331.714" cy="58.519" r="2.963"/><circle cx="139.121" cy="65.926" r="2.963"/><circle cx="146.529" cy="65.926" r="2.963"/><circle cx="153.936" cy="65.926" r="2.963"/><circle cx="161.343" cy="65.926" r="2.963"/><circle cx="168.751" cy="65.926" r="2.963"/><circle cx="213.195" cy="65.926" r="2.963"/><circle cx="220.603" cy="65.926" r="2.963"/><circle cx="228.010" cy="65.926" r="2.963"/><circle cx="235.417" cy="65.926" r="2.963"/><circle cx="242.825" cy="65.926" r="2.963"/><circle cx="287.269" cy="65.926" r="2.963"/><circle cx="294.677" cy="65.926" r="2.963"/><circle cx="302.084" cy="65.926" r="2.963"/><circle cx="309.491" cy="65.926" r="2.963"/><circle cx="316.899" cy="65.926" r="2.963"/><circle cx="146.529" cy="73.333" r="2.963"/><circle cx="153.936" cy="73.333" r="2.963"/><circle cx="161.343" cy="73.333" r="2.963"/><circle cx="168.751" cy="73.333" r="2.963"/><circle cx="176.158" cy="73.333" r="2.963"/><circle cx="213.195" cy="73.333" r="2.963"/><circle cx="220.603" cy="73.333" r="2.963"/><circle cx="228.010" cy="73.333" r="2.963"/><circle cx="235.417" cy="73.333" r="2.963"/><circle cx="242.825" cy="73.333" r="2.963"/><circle cx="279.862" cy="73.333" r="2.963"/><circle cx="287.269" cy="73.333" r="2.963"/><circle cx="294.677" cy="73.333" r="2.963"/><circle cx="302.084" cy="73.333" r="2.963"/><circle cx="309.491" cy="73.333" r="2.963"/><circle cx="124.306" cy="80.741" r="2.963"/><circle cx="161.343" cy="80.741" r="2.963"/><circle cx="168.751" cy="80.741" r="2.963"/><circle cx="176.158" cy="80.741" r="2.963"/><circle cx="183.566" cy="80.741" r="2.963"/><circle cx="213.195" cy="80.741" r="2.963"/><circle cx="220.603" cy="80.741" r="2.963"/><circle cx="228.010" cy="80.741" r="2.963"/><circle cx="235.417" cy="80.741" r="2.963"/><circle cx="242.825" cy="80.741" r="2.963"/><circle cx="272.454" cy="80.741" r="2.963"/><circle cx="279.862" cy="80.741" r="2.963"/><circle cx="287.269" cy="80.741" r="2.963"/><circle cx="294.677" cy="80.741" r="2.963"/><circle cx="331.714" cy="80.741" r="2.963"/><circle cx="116.899" cy="88.148" r="2.963"/><circle cx="124.306" cy="88.148" r="2.963"/><circle cx="131.714" cy="88.148" r="2.963"/><circle cx="139.121" cy="88.148" r="2.963"/><circle cx="146.529" cy="88.148" r="2.963"/><circle cx="176.158" cy="88.148" r="2.963"/><circle cx="183.566" cy="88.148" r="2.963"/><circle cx="190.973" cy="88.148" r="2.963"/><circle cx="198.380" cy="88.148" r="2.963"/><circle cx="220.603" cy="88.148" r="2.963"/><circle cx="228.010" cy="88.148" r="2.963"/><circle cx="235.417" cy="88.148" r="2.963"/><circle cx="257.640" cy="88.148" r="2.963"/><circle cx="265.047" cy="88.148" r="2.963"/><circle cx="272.454" cy="88.148" r="2.963"/><circle cx="279.862" cy="88.148" r="2.963"/><circle cx="309.491" cy="88.148" r="2.963"/><circle cx="316.899" cy="88.148" r="2.963"/><circle cx="324.306" cy="88.148" r="2.963"/><circle cx="331.714" cy="88.148" r="2.963"/><circle cx="339.121" cy="88.148" r="2.963"/><circle cx="116.899" cy="95.556" r="2.963"/><circle cx="124.306" cy="95.556" r="2.963"/><circle cx="131.714" cy="95.556" r="2.963"/><circle cx="139.121" cy="95.556" r="2.963"/><circle cx="146.529" cy="95.556" r="2.963"/><circle cx="153.936" cy="95.556" r="2.963"/><circle cx="161.343" cy="95.556" r="2.963"/><circle cx="168.751" cy="95.556" r="2.963"/><circle cx="176.158" cy="95.556" r="2.963"/><circle cx="183.566" cy="95.556" r="2.963"/><circle cx="190.973" cy="95.556" r="2.963"/><circle cx="198.380" cy="95.556" r="2.963"/><circle cx="205.788" cy="95.556" r="2.963"/><circle cx="220.603" cy="95.556" r="2.963"/><circle cx=Line truncated

After

Width:  |  Height:  |  Size: 23 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 456.02 360" width="456.02" height="360" role="img" aria-label="SimurgArray"><title>SimurgArray</title><g fill="#FFFFFF"><circle cx="124.306" cy="43.704" r="2.963"/><circle cx="131.714" cy="43.704" r="2.963"/><circle cx="324.306" cy="43.704" r="2.963"/><circle cx="331.714" cy="43.704" r="2.963"/><circle cx="124.306" cy="51.111" r="2.963"/><circle cx="131.714" cy="51.111" r="2.963"/><circle cx="139.121" cy="51.111" r="2.963"/><circle cx="213.195" cy="51.111" r="2.963"/><circle cx="228.010" cy="51.111" r="2.963"/><circle cx="242.825" cy="51.111" r="2.963"/><circle cx="316.899" cy="51.111" r="2.963"/><circle cx="324.306" cy="51.111" r="2.963"/><circle cx="331.714" cy="51.111" r="2.963"/><circle cx="124.306" cy="58.519" r="2.963"/><circle cx="131.714" cy="58.519" r="2.963"/><circle cx="139.121" cy="58.519" r="2.963"/><circle cx="146.529" cy="58.519" r="2.963"/><circle cx="153.936" cy="58.519" r="2.963"/><circle cx="213.195" cy="58.519" r="2.963"/><circle cx="220.603" cy="58.519" r="2.963"/><circle cx="228.010" cy="58.519" r="2.963"/><circle cx="235.417" cy="58.519" r="2.963"/><circle cx="242.825" cy="58.519" r="2.963"/><circle cx="302.084" cy="58.519" r="2.963"/><circle cx="309.491" cy="58.519" r="2.963"/><circle cx="316.899" cy="58.519" r="2.963"/><circle cx="324.306" cy="58.519" r="2.963"/><circle cx="331.714" cy="58.519" r="2.963"/><circle cx="139.121" cy="65.926" r="2.963"/><circle cx="146.529" cy="65.926" r="2.963"/><circle cx="153.936" cy="65.926" r="2.963"/><circle cx="161.343" cy="65.926" r="2.963"/><circle cx="168.751" cy="65.926" r="2.963"/><circle cx="213.195" cy="65.926" r="2.963"/><circle cx="220.603" cy="65.926" r="2.963"/><circle cx="228.010" cy="65.926" r="2.963"/><circle cx="235.417" cy="65.926" r="2.963"/><circle cx="242.825" cy="65.926" r="2.963"/><circle cx="287.269" cy="65.926" r="2.963"/><circle cx="294.677" cy="65.926" r="2.963"/><circle cx="302.084" cy="65.926" r="2.963"/><circle cx="309.491" cy="65.926" r="2.963"/><circle cx="316.899" cy="65.926" r="2.963"/><circle cx="146.529" cy="73.333" r="2.963"/><circle cx="153.936" cy="73.333" r="2.963"/><circle cx="161.343" cy="73.333" r="2.963"/><circle cx="168.751" cy="73.333" r="2.963"/><circle cx="176.158" cy="73.333" r="2.963"/><circle cx="213.195" cy="73.333" r="2.963"/><circle cx="220.603" cy="73.333" r="2.963"/><circle cx="228.010" cy="73.333" r="2.963"/><circle cx="235.417" cy="73.333" r="2.963"/><circle cx="242.825" cy="73.333" r="2.963"/><circle cx="279.862" cy="73.333" r="2.963"/><circle cx="287.269" cy="73.333" r="2.963"/><circle cx="294.677" cy="73.333" r="2.963"/><circle cx="302.084" cy="73.333" r="2.963"/><circle cx="309.491" cy="73.333" r="2.963"/><circle cx="124.306" cy="80.741" r="2.963"/><circle cx="161.343" cy="80.741" r="2.963"/><circle cx="168.751" cy="80.741" r="2.963"/><circle cx="176.158" cy="80.741" r="2.963"/><circle cx="183.566" cy="80.741" r="2.963"/><circle cx="213.195" cy="80.741" r="2.963"/><circle cx="220.603" cy="80.741" r="2.963"/><circle cx="228.010" cy="80.741" r="2.963"/><circle cx="235.417" cy="80.741" r="2.963"/><circle cx="242.825" cy="80.741" r="2.963"/><circle cx="272.454" cy="80.741" r="2.963"/><circle cx="279.862" cy="80.741" r="2.963"/><circle cx="287.269" cy="80.741" r="2.963"/><circle cx="294.677" cy="80.741" r="2.963"/><circle cx="331.714" cy="80.741" r="2.963"/><circle cx="116.899" cy="88.148" r="2.963"/><circle cx="124.306" cy="88.148" r="2.963"/><circle cx="131.714" cy="88.148" r="2.963"/><circle cx="139.121" cy="88.148" r="2.963"/><circle cx="146.529" cy="88.148" r="2.963"/><circle cx="176.158" cy="88.148" r="2.963"/><circle cx="183.566" cy="88.148" r="2.963"/><circle cx="190.973" cy="88.148" r="2.963"/><circle cx="198.380" cy="88.148" r="2.963"/><circle cx="220.603" cy="88.148" r="2.963"/><circle cx="228.010" cy="88.148" r="2.963"/><circle cx="235.417" cy="88.148" r="2.963"/><circle cx="257.640" cy="88.148" r="2.963"/><circle cx="265.047" cy="88.148" r="2.963"/><circle cx="272.454" cy="88.148" r="2.963"/><circle cx="279.862" cy="88.148" r="2.963"/><circle cx="309.491" cy="88.148" r="2.963"/><circle cx="316.899" cy="88.148" r="2.963"/><circle cx="324.306" cy="88.148" r="2.963"/><circle cx="331.714" cy="88.148" r="2.963"/><circle cx="339.121" cy="88.148" r="2.963"/><circle cx="116.899" cy="95.556" r="2.963"/><circle cx="124.306" cy="95.556" r="2.963"/><circle cx="131.714" cy="95.556" r="2.963"/><circle cx="139.121" cy="95.556" r="2.963"/><circle cx="146.529" cy="95.556" r="2.963"/><circle cx="153.936" cy="95.556" r="2.963"/><circle cx="161.343" cy="95.556" r="2.963"/><circle cx="168.751" cy="95.556" r="2.963"/><circle cx="176.158" cy="95.556" r="2.963"/><circle cx="183.566" cy="95.556" r="2.963"/><circle cx="190.973" cy="95.556" r="2.963"/><circle cx="198.380" cy="95.556" r="2.963"/><circle cx="205.788" cy="95.556" r="2.963"/><circle cx="220.603" cy="95.556" r="2.963"/><circle cx="228.010" cy="95.556" r="2.963"/><circle cx="235.417" cy="95.55Line truncated

After

Width:  |  Height:  |  Size: 23 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 33 29" width="33" height="29" role="img" aria-label="SimurgArray"><title>SimurgArray</title><g fill="#111111"><circle cx="2.500" cy="1.500" r="0.400"/><circle cx="3.500" cy="1.500" r="0.400"/><circle cx="29.500" cy="1.500" r="0.400"/><circle cx="30.500" cy="1.500" r="0.400"/><circle cx="2.500" cy="2.500" r="0.400"/><circle cx="3.500" cy="2.500" r="0.400"/><circle cx="4.500" cy="2.500" r="0.400"/><circle cx="14.500" cy="2.500" r="0.400"/><circle cx="16.500" cy="2.500" r="0.400"/><circle cx="18.500" cy="2.500" r="0.400"/><circle cx="28.500" cy="2.500" r="0.400"/><circle cx="29.500" cy="2.500" r="0.400"/><circle cx="30.500" cy="2.500" r="0.400"/><circle cx="2.500" cy="3.500" r="0.400"/><circle cx="3.500" cy="3.500" r="0.400"/><circle cx="4.500" cy="3.500" r="0.400"/><circle cx="5.500" cy="3.500" r="0.400"/><circle cx="6.500" cy="3.500" r="0.400"/><circle cx="14.500" cy="3.500" r="0.400"/><circle cx="15.500" cy="3.500" r="0.400"/><circle cx="16.500" cy="3.500" r="0.400"/><circle cx="17.500" cy="3.500" r="0.400"/><circle cx="18.500" cy="3.500" r="0.400"/><circle cx="26.500" cy="3.500" r="0.400"/><circle cx="27.500" cy="3.500" r="0.400"/><circle cx="28.500" cy="3.500" r="0.400"/><circle cx="29.500" cy="3.500" r="0.400"/><circle cx="30.500" cy="3.500" r="0.400"/><circle cx="4.500" cy="4.500" r="0.400"/><circle cx="5.500" cy="4.500" r="0.400"/><circle cx="6.500" cy="4.500" r="0.400"/><circle cx="7.500" cy="4.500" r="0.400"/><circle cx="8.500" cy="4.500" r="0.400"/><circle cx="14.500" cy="4.500" r="0.400"/><circle cx="15.500" cy="4.500" r="0.400"/><circle cx="16.500" cy="4.500" r="0.400"/><circle cx="17.500" cy="4.500" r="0.400"/><circle cx="18.500" cy="4.500" r="0.400"/><circle cx="24.500" cy="4.500" r="0.400"/><circle cx="25.500" cy="4.500" r="0.400"/><circle cx="26.500" cy="4.500" r="0.400"/><circle cx="27.500" cy="4.500" r="0.400"/><circle cx="28.500" cy="4.500" r="0.400"/><circle cx="5.500" cy="5.500" r="0.400"/><circle cx="6.500" cy="5.500" r="0.400"/><circle cx="7.500" cy="5.500" r="0.400"/><circle cx="8.500" cy="5.500" r="0.400"/><circle cx="9.500" cy="5.500" r="0.400"/><circle cx="14.500" cy="5.500" r="0.400"/><circle cx="15.500" cy="5.500" r="0.400"/><circle cx="16.500" cy="5.500" r="0.400"/><circle cx="17.500" cy="5.500" r="0.400"/><circle cx="18.500" cy="5.500" r="0.400"/><circle cx="23.500" cy="5.500" r="0.400"/><circle cx="24.500" cy="5.500" r="0.400"/><circle cx="25.500" cy="5.500" r="0.400"/><circle cx="26.500" cy="5.500" r="0.400"/><circle cx="27.500" cy="5.500" r="0.400"/><circle cx="2.500" cy="6.500" r="0.400"/><circle cx="7.500" cy="6.500" r="0.400"/><circle cx="8.500" cy="6.500" r="0.400"/><circle cx="9.500" cy="6.500" r="0.400"/><circle cx="10.500" cy="6.500" r="0.400"/><circle cx="14.500" cy="6.500" r="0.400"/><circle cx="15.500" cy="6.500" r="0.400"/><circle cx="16.500" cy="6.500" r="0.400"/><circle cx="17.500" cy="6.500" r="0.400"/><circle cx="18.500" cy="6.500" r="0.400"/><circle cx="22.500" cy="6.500" r="0.400"/><circle cx="23.500" cy="6.500" r="0.400"/><circle cx="24.500" cy="6.500" r="0.400"/><circle cx="25.500" cy="6.500" r="0.400"/><circle cx="30.500" cy="6.500" r="0.400"/><circle cx="1.500" cy="7.500" r="0.400"/><circle cx="2.500" cy="7.500" r="0.400"/><circle cx="3.500" cy="7.500" r="0.400"/><circle cx="4.500" cy="7.500" r="0.400"/><circle cx="5.500" cy="7.500" r="0.400"/><circle cx="9.500" cy="7.500" r="0.400"/><circle cx="10.500" cy="7.500" r="0.400"/><circle cx="11.500" cy="7.500" r="0.400"/><circle cx="12.500" cy="7.500" r="0.400"/><circle cx="15.500" cy="7.500" r="0.400"/><circle cx="16.500" cy="7.500" r="0.400"/><circle cx="17.500" cy="7.500" r="0.400"/><circle cx="20.500" cy="7.500" r="0.400"/><circle cx="21.500" cy="7.500" r="0.400"/><circle cx="22.500" cy="7.500" r="0.400"/><circle cx="23.500" cy="7.500" r="0.400"/><circle cx="27.500" cy="7.500" r="0.400"/><circle cx="28.500" cy="7.500" r="0.400"/><circle cx="29.500" cy="7.500" r="0.400"/><circle cx="30.500" cy="7.500" r="0.400"/><circle cx="31.500" cy="7.500" r="0.400"/><circle cx="1.500" cy="8.500" r="0.400"/><circle cx="2.500" cy="8.500" r="0.400"/><circle cx="3.500" cy="8.500" r="0.400"/><circle cx="4.500" cy="8.500" r="0.400"/><circle cx="5.500" cy="8.500" r="0.400"/><circle cx="6.500" cy="8.500" r="0.400"/><circle cx="7.500" cy="8.500" r="0.400"/><circle cx="8.500" cy="8.500" r="0.400"/><circle cx="9.500" cy="8.500" r="0.400"/><circle cx="10.500" cy="8.500" r="0.400"/><circle cx="11.500" cy="8.500" r="0.400"/><circle cx="12.500" cy="8.500" r="0.400"/><circle cx="13.500" cy="8.500" r="0.400"/><circle cx="15.500" cy="8.500" r="0.400"/><circle cx="16.500" cy="8.500" r="0.400"/><circle cx="17.500" cy="8.500" r="0.400"/><circle cx="19.500" cy="8.500" r="0.400"/><circle cx="20.500" cy="8.500" r="0.400"/><circle cx="21.500" cy="8.500" r="0.400"/><circle cx="22.500" cy="8.500" r="0.400"/><circle cx="23.500" cy="8.500" r="0.400"/><circle cx="24.500" cy="8.500" r="0.400"/><ciLine truncated

After

Width:  |  Height:  |  Size: 13 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 33 29" width="33" height="29" role="img" aria-label="SimurgArray"><title>SimurgArray</title><g fill="#D4A017"><circle cx="2.500" cy="1.500" r="0.400"/><circle cx="3.500" cy="1.500" r="0.400"/><circle cx="29.500" cy="1.500" r="0.400"/><circle cx="30.500" cy="1.500" r="0.400"/><circle cx="2.500" cy="2.500" r="0.400"/><circle cx="3.500" cy="2.500" r="0.400"/><circle cx="4.500" cy="2.500" r="0.400"/><circle cx="14.500" cy="2.500" r="0.400"/><circle cx="16.500" cy="2.500" r="0.400"/><circle cx="18.500" cy="2.500" r="0.400"/><circle cx="28.500" cy="2.500" r="0.400"/><circle cx="29.500" cy="2.500" r="0.400"/><circle cx="30.500" cy="2.500" r="0.400"/><circle cx="2.500" cy="3.500" r="0.400"/><circle cx="3.500" cy="3.500" r="0.400"/><circle cx="4.500" cy="3.500" r="0.400"/><circle cx="5.500" cy="3.500" r="0.400"/><circle cx="6.500" cy="3.500" r="0.400"/><circle cx="14.500" cy="3.500" r="0.400"/><circle cx="15.500" cy="3.500" r="0.400"/><circle cx="16.500" cy="3.500" r="0.400"/><circle cx="17.500" cy="3.500" r="0.400"/><circle cx="18.500" cy="3.500" r="0.400"/><circle cx="26.500" cy="3.500" r="0.400"/><circle cx="27.500" cy="3.500" r="0.400"/><circle cx="28.500" cy="3.500" r="0.400"/><circle cx="29.500" cy="3.500" r="0.400"/><circle cx="30.500" cy="3.500" r="0.400"/><circle cx="4.500" cy="4.500" r="0.400"/><circle cx="5.500" cy="4.500" r="0.400"/><circle cx="6.500" cy="4.500" r="0.400"/><circle cx="7.500" cy="4.500" r="0.400"/><circle cx="8.500" cy="4.500" r="0.400"/><circle cx="14.500" cy="4.500" r="0.400"/><circle cx="15.500" cy="4.500" r="0.400"/><circle cx="16.500" cy="4.500" r="0.400"/><circle cx="17.500" cy="4.500" r="0.400"/><circle cx="18.500" cy="4.500" r="0.400"/><circle cx="24.500" cy="4.500" r="0.400"/><circle cx="25.500" cy="4.500" r="0.400"/><circle cx="26.500" cy="4.500" r="0.400"/><circle cx="27.500" cy="4.500" r="0.400"/><circle cx="28.500" cy="4.500" r="0.400"/><circle cx="5.500" cy="5.500" r="0.400"/><circle cx="6.500" cy="5.500" r="0.400"/><circle cx="7.500" cy="5.500" r="0.400"/><circle cx="8.500" cy="5.500" r="0.400"/><circle cx="9.500" cy="5.500" r="0.400"/><circle cx="14.500" cy="5.500" r="0.400"/><circle cx="15.500" cy="5.500" r="0.400"/><circle cx="16.500" cy="5.500" r="0.400"/><circle cx="17.500" cy="5.500" r="0.400"/><circle cx="18.500" cy="5.500" r="0.400"/><circle cx="23.500" cy="5.500" r="0.400"/><circle cx="24.500" cy="5.500" r="0.400"/><circle cx="25.500" cy="5.500" r="0.400"/><circle cx="26.500" cy="5.500" r="0.400"/><circle cx="27.500" cy="5.500" r="0.400"/><circle cx="2.500" cy="6.500" r="0.400"/><circle cx="7.500" cy="6.500" r="0.400"/><circle cx="8.500" cy="6.500" r="0.400"/><circle cx="9.500" cy="6.500" r="0.400"/><circle cx="10.500" cy="6.500" r="0.400"/><circle cx="14.500" cy="6.500" r="0.400"/><circle cx="15.500" cy="6.500" r="0.400"/><circle cx="16.500" cy="6.500" r="0.400"/><circle cx="17.500" cy="6.500" r="0.400"/><circle cx="18.500" cy="6.500" r="0.400"/><circle cx="22.500" cy="6.500" r="0.400"/><circle cx="23.500" cy="6.500" r="0.400"/><circle cx="24.500" cy="6.500" r="0.400"/><circle cx="25.500" cy="6.500" r="0.400"/><circle cx="30.500" cy="6.500" r="0.400"/><circle cx="1.500" cy="7.500" r="0.400"/><circle cx="2.500" cy="7.500" r="0.400"/><circle cx="3.500" cy="7.500" r="0.400"/><circle cx="4.500" cy="7.500" r="0.400"/><circle cx="5.500" cy="7.500" r="0.400"/><circle cx="9.500" cy="7.500" r="0.400"/><circle cx="10.500" cy="7.500" r="0.400"/><circle cx="11.500" cy="7.500" r="0.400"/><circle cx="12.500" cy="7.500" r="0.400"/><circle cx="15.500" cy="7.500" r="0.400"/><circle cx="16.500" cy="7.500" r="0.400"/><circle cx="17.500" cy="7.500" r="0.400"/><circle cx="20.500" cy="7.500" r="0.400"/><circle cx="21.500" cy="7.500" r="0.400"/><circle cx="22.500" cy="7.500" r="0.400"/><circle cx="23.500" cy="7.500" r="0.400"/><circle cx="27.500" cy="7.500" r="0.400"/><circle cx="28.500" cy="7.500" r="0.400"/><circle cx="29.500" cy="7.500" r="0.400"/><circle cx="30.500" cy="7.500" r="0.400"/><circle cx="31.500" cy="7.500" r="0.400"/><circle cx="1.500" cy="8.500" r="0.400"/><circle cx="2.500" cy="8.500" r="0.400"/><circle cx="3.500" cy="8.500" r="0.400"/><circle cx="4.500" cy="8.500" r="0.400"/><circle cx="5.500" cy="8.500" r="0.400"/><circle cx="6.500" cy="8.500" r="0.400"/><circle cx="7.500" cy="8.500" r="0.400"/><circle cx="8.500" cy="8.500" r="0.400"/><circle cx="9.500" cy="8.500" r="0.400"/><circle cx="10.500" cy="8.500" r="0.400"/><circle cx="11.500" cy="8.500" r="0.400"/><circle cx="12.500" cy="8.500" r="0.400"/><circle cx="13.500" cy="8.500" r="0.400"/><circle cx="15.500" cy="8.500" r="0.400"/><circle cx="16.500" cy="8.500" r="0.400"/><circle cx="17.500" cy="8.500" r="0.400"/><circle cx="19.500" cy="8.500" r="0.400"/><circle cx="20.500" cy="8.500" r="0.400"/><circle cx="21.500" cy="8.500" r="0.400"/><circle cx="22.500" cy="8.500" r="0.400"/><circle cx="23.500" cy="8.500" r="0.400"/><circle cx="24.500" cy="8.500" r="0.400"/><ciLine truncated

After

Width:  |  Height:  |  Size: 13 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 33 29" width="33" height="29" role="img" aria-label="SimurgArray"><title>SimurgArray</title><g fill="#D4A017"><circle cx="2.500" cy="1.500" r="0.400"/><circle cx="3.500" cy="1.500" r="0.400"/><circle cx="29.500" cy="1.500" r="0.400"/><circle cx="30.500" cy="1.500" r="0.400"/><circle cx="2.500" cy="2.500" r="0.400"/><circle cx="3.500" cy="2.500" r="0.400"/><circle cx="4.500" cy="2.500" r="0.400"/><circle cx="14.500" cy="2.500" r="0.400"/><circle cx="16.500" cy="2.500" r="0.400"/><circle cx="18.500" cy="2.500" r="0.400"/><circle cx="28.500" cy="2.500" r="0.400"/><circle cx="29.500" cy="2.500" r="0.400"/><circle cx="30.500" cy="2.500" r="0.400"/><circle cx="2.500" cy="3.500" r="0.400"/><circle cx="3.500" cy="3.500" r="0.400"/><circle cx="4.500" cy="3.500" r="0.400"/><circle cx="5.500" cy="3.500" r="0.400"/><circle cx="6.500" cy="3.500" r="0.400"/><circle cx="14.500" cy="3.500" r="0.400"/><circle cx="15.500" cy="3.500" r="0.400"/><circle cx="16.500" cy="3.500" r="0.400"/><circle cx="17.500" cy="3.500" r="0.400"/><circle cx="18.500" cy="3.500" r="0.400"/><circle cx="26.500" cy="3.500" r="0.400"/><circle cx="27.500" cy="3.500" r="0.400"/><circle cx="28.500" cy="3.500" r="0.400"/><circle cx="29.500" cy="3.500" r="0.400"/><circle cx="30.500" cy="3.500" r="0.400"/><circle cx="4.500" cy="4.500" r="0.400"/><circle cx="5.500" cy="4.500" r="0.400"/><circle cx="6.500" cy="4.500" r="0.400"/><circle cx="7.500" cy="4.500" r="0.400"/><circle cx="8.500" cy="4.500" r="0.400"/><circle cx="14.500" cy="4.500" r="0.400"/><circle cx="15.500" cy="4.500" r="0.400"/><circle cx="16.500" cy="4.500" r="0.400"/><circle cx="17.500" cy="4.500" r="0.400"/><circle cx="18.500" cy="4.500" r="0.400"/><circle cx="24.500" cy="4.500" r="0.400"/><circle cx="25.500" cy="4.500" r="0.400"/><circle cx="26.500" cy="4.500" r="0.400"/><circle cx="27.500" cy="4.500" r="0.400"/><circle cx="28.500" cy="4.500" r="0.400"/><circle cx="5.500" cy="5.500" r="0.400"/><circle cx="6.500" cy="5.500" r="0.400"/><circle cx="7.500" cy="5.500" r="0.400"/><circle cx="8.500" cy="5.500" r="0.400"/><circle cx="9.500" cy="5.500" r="0.400"/><circle cx="14.500" cy="5.500" r="0.400"/><circle cx="15.500" cy="5.500" r="0.400"/><circle cx="16.500" cy="5.500" r="0.400"/><circle cx="17.500" cy="5.500" r="0.400"/><circle cx="18.500" cy="5.500" r="0.400"/><circle cx="23.500" cy="5.500" r="0.400"/><circle cx="24.500" cy="5.500" r="0.400"/><circle cx="25.500" cy="5.500" r="0.400"/><circle cx="26.500" cy="5.500" r="0.400"/><circle cx="27.500" cy="5.500" r="0.400"/><circle cx="2.500" cy="6.500" r="0.400"/><circle cx="7.500" cy="6.500" r="0.400"/><circle cx="8.500" cy="6.500" r="0.400"/><circle cx="9.500" cy="6.500" r="0.400"/><circle cx="10.500" cy="6.500" r="0.400"/><circle cx="14.500" cy="6.500" r="0.400"/><circle cx="15.500" cy="6.500" r="0.400"/><circle cx="16.500" cy="6.500" r="0.400"/><circle cx="17.500" cy="6.500" r="0.400"/><circle cx="18.500" cy="6.500" r="0.400"/><circle cx="22.500" cy="6.500" r="0.400"/><circle cx="23.500" cy="6.500" r="0.400"/><circle cx="24.500" cy="6.500" r="0.400"/><circle cx="25.500" cy="6.500" r="0.400"/><circle cx="30.500" cy="6.500" r="0.400"/><circle cx="1.500" cy="7.500" r="0.400"/><circle cx="2.500" cy="7.500" r="0.400"/><circle cx="3.500" cy="7.500" r="0.400"/><circle cx="4.500" cy="7.500" r="0.400"/><circle cx="5.500" cy="7.500" r="0.400"/><circle cx="9.500" cy="7.500" r="0.400"/><circle cx="10.500" cy="7.500" r="0.400"/><circle cx="11.500" cy="7.500" r="0.400"/><circle cx="12.500" cy="7.500" r="0.400"/><circle cx="15.500" cy="7.500" r="0.400"/><circle cx="16.500" cy="7.500" r="0.400"/><circle cx="17.500" cy="7.500" r="0.400"/><circle cx="20.500" cy="7.500" r="0.400"/><circle cx="21.500" cy="7.500" r="0.400"/><circle cx="22.500" cy="7.500" r="0.400"/><circle cx="23.500" cy="7.500" r="0.400"/><circle cx="27.500" cy="7.500" r="0.400"/><circle cx="28.500" cy="7.500" r="0.400"/><circle cx="29.500" cy="7.500" r="0.400"/><circle cx="30.500" cy="7.500" r="0.400"/><circle cx="31.500" cy="7.500" r="0.400"/><circle cx="1.500" cy="8.500" r="0.400"/><circle cx="2.500" cy="8.500" r="0.400"/><circle cx="3.500" cy="8.500" r="0.400"/><circle cx="4.500" cy="8.500" r="0.400"/><circle cx="5.500" cy="8.500" r="0.400"/><circle cx="6.500" cy="8.500" r="0.400"/><circle cx="7.500" cy="8.500" r="0.400"/><circle cx="8.500" cy="8.500" r="0.400"/><circle cx="9.500" cy="8.500" r="0.400"/><circle cx="10.500" cy="8.500" r="0.400"/><circle cx="11.500" cy="8.500" r="0.400"/><circle cx="12.500" cy="8.500" r="0.400"/><circle cx="13.500" cy="8.500" r="0.400"/><circle cx="15.500" cy="8.500" r="0.400"/><circle cx="16.500" cy="8.500" r="0.400"/><circle cx="17.500" cy="8.500" r="0.400"/><circle cx="19.500" cy="8.500" r="0.400"/><circle cx="20.500" cy="8.500" r="0.400"/><circle cx="21.500" cy="8.500" r="0.400"/><circle cx="22.500" cy="8.500" r="0.400"/><circle cx="23.500" cy="8.500" r="0.400"/><circle cx="24.500" cy="8.500" r="0.400"/><ciLine truncated

After

Width:  |  Height:  |  Size: 13 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 33 29" width="33" height="29" role="img" aria-label="SimurgArray"><title>SimurgArray</title><g fill="#A87A00"><circle cx="2.500" cy="1.500" r="0.400"/><circle cx="3.500" cy="1.500" r="0.400"/><circle cx="29.500" cy="1.500" r="0.400"/><circle cx="30.500" cy="1.500" r="0.400"/><circle cx="2.500" cy="2.500" r="0.400"/><circle cx="3.500" cy="2.500" r="0.400"/><circle cx="4.500" cy="2.500" r="0.400"/><circle cx="14.500" cy="2.500" r="0.400"/><circle cx="16.500" cy="2.500" r="0.400"/><circle cx="18.500" cy="2.500" r="0.400"/><circle cx="28.500" cy="2.500" r="0.400"/><circle cx="29.500" cy="2.500" r="0.400"/><circle cx="30.500" cy="2.500" r="0.400"/><circle cx="2.500" cy="3.500" r="0.400"/><circle cx="3.500" cy="3.500" r="0.400"/><circle cx="4.500" cy="3.500" r="0.400"/><circle cx="5.500" cy="3.500" r="0.400"/><circle cx="6.500" cy="3.500" r="0.400"/><circle cx="14.500" cy="3.500" r="0.400"/><circle cx="15.500" cy="3.500" r="0.400"/><circle cx="16.500" cy="3.500" r="0.400"/><circle cx="17.500" cy="3.500" r="0.400"/><circle cx="18.500" cy="3.500" r="0.400"/><circle cx="26.500" cy="3.500" r="0.400"/><circle cx="27.500" cy="3.500" r="0.400"/><circle cx="28.500" cy="3.500" r="0.400"/><circle cx="29.500" cy="3.500" r="0.400"/><circle cx="30.500" cy="3.500" r="0.400"/><circle cx="4.500" cy="4.500" r="0.400"/><circle cx="5.500" cy="4.500" r="0.400"/><circle cx="6.500" cy="4.500" r="0.400"/><circle cx="7.500" cy="4.500" r="0.400"/><circle cx="8.500" cy="4.500" r="0.400"/><circle cx="14.500" cy="4.500" r="0.400"/><circle cx="15.500" cy="4.500" r="0.400"/><circle cx="16.500" cy="4.500" r="0.400"/><circle cx="17.500" cy="4.500" r="0.400"/><circle cx="18.500" cy="4.500" r="0.400"/><circle cx="24.500" cy="4.500" r="0.400"/><circle cx="25.500" cy="4.500" r="0.400"/><circle cx="26.500" cy="4.500" r="0.400"/><circle cx="27.500" cy="4.500" r="0.400"/><circle cx="28.500" cy="4.500" r="0.400"/><circle cx="5.500" cy="5.500" r="0.400"/><circle cx="6.500" cy="5.500" r="0.400"/><circle cx="7.500" cy="5.500" r="0.400"/><circle cx="8.500" cy="5.500" r="0.400"/><circle cx="9.500" cy="5.500" r="0.400"/><circle cx="14.500" cy="5.500" r="0.400"/><circle cx="15.500" cy="5.500" r="0.400"/><circle cx="16.500" cy="5.500" r="0.400"/><circle cx="17.500" cy="5.500" r="0.400"/><circle cx="18.500" cy="5.500" r="0.400"/><circle cx="23.500" cy="5.500" r="0.400"/><circle cx="24.500" cy="5.500" r="0.400"/><circle cx="25.500" cy="5.500" r="0.400"/><circle cx="26.500" cy="5.500" r="0.400"/><circle cx="27.500" cy="5.500" r="0.400"/><circle cx="2.500" cy="6.500" r="0.400"/><circle cx="7.500" cy="6.500" r="0.400"/><circle cx="8.500" cy="6.500" r="0.400"/><circle cx="9.500" cy="6.500" r="0.400"/><circle cx="10.500" cy="6.500" r="0.400"/><circle cx="14.500" cy="6.500" r="0.400"/><circle cx="15.500" cy="6.500" r="0.400"/><circle cx="16.500" cy="6.500" r="0.400"/><circle cx="17.500" cy="6.500" r="0.400"/><circle cx="18.500" cy="6.500" r="0.400"/><circle cx="22.500" cy="6.500" r="0.400"/><circle cx="23.500" cy="6.500" r="0.400"/><circle cx="24.500" cy="6.500" r="0.400"/><circle cx="25.500" cy="6.500" r="0.400"/><circle cx="30.500" cy="6.500" r="0.400"/><circle cx="1.500" cy="7.500" r="0.400"/><circle cx="2.500" cy="7.500" r="0.400"/><circle cx="3.500" cy="7.500" r="0.400"/><circle cx="4.500" cy="7.500" r="0.400"/><circle cx="5.500" cy="7.500" r="0.400"/><circle cx="9.500" cy="7.500" r="0.400"/><circle cx="10.500" cy="7.500" r="0.400"/><circle cx="11.500" cy="7.500" r="0.400"/><circle cx="12.500" cy="7.500" r="0.400"/><circle cx="15.500" cy="7.500" r="0.400"/><circle cx="16.500" cy="7.500" r="0.400"/><circle cx="17.500" cy="7.500" r="0.400"/><circle cx="20.500" cy="7.500" r="0.400"/><circle cx="21.500" cy="7.500" r="0.400"/><circle cx="22.500" cy="7.500" r="0.400"/><circle cx="23.500" cy="7.500" r="0.400"/><circle cx="27.500" cy="7.500" r="0.400"/><circle cx="28.500" cy="7.500" r="0.400"/><circle cx="29.500" cy="7.500" r="0.400"/><circle cx="30.500" cy="7.500" r="0.400"/><circle cx="31.500" cy="7.500" r="0.400"/><circle cx="1.500" cy="8.500" r="0.400"/><circle cx="2.500" cy="8.500" r="0.400"/><circle cx="3.500" cy="8.500" r="0.400"/><circle cx="4.500" cy="8.500" r="0.400"/><circle cx="5.500" cy="8.500" r="0.400"/><circle cx="6.500" cy="8.500" r="0.400"/><circle cx="7.500" cy="8.500" r="0.400"/><circle cx="8.500" cy="8.500" r="0.400"/><circle cx="9.500" cy="8.500" r="0.400"/><circle cx="10.500" cy="8.500" r="0.400"/><circle cx="11.500" cy="8.500" r="0.400"/><circle cx="12.500" cy="8.500" r="0.400"/><circle cx="13.500" cy="8.500" r="0.400"/><circle cx="15.500" cy="8.500" r="0.400"/><circle cx="16.500" cy="8.500" r="0.400"/><circle cx="17.500" cy="8.500" r="0.400"/><circle cx="19.500" cy="8.500" r="0.400"/><circle cx="20.500" cy="8.500" r="0.400"/><circle cx="21.500" cy="8.500" r="0.400"/><circle cx="22.500" cy="8.500" r="0.400"/><circle cx="23.500" cy="8.500" r="0.400"/><circle cx="24.500" cy="8.500" r="0.400"/><ciLine truncated

After

Width:  |  Height:  |  Size: 13 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 9 9" width="9" height="9" role="img" aria-label="SimurgArray"><title>SimurgArray</title><g fill="#111111"><circle cx="1.500" cy="1.500" r="0.400"/><circle cx="7.500" cy="1.500" r="0.400"/><circle cx="1.500" cy="2.500" r="0.400"/><circle cx="2.500" cy="2.500" r="0.400"/><circle cx="4.500" cy="2.500" r="0.400"/><circle cx="6.500" cy="2.500" r="0.400"/><circle cx="7.500" cy="2.500" r="0.400"/><circle cx="2.500" cy="3.500" r="0.400"/><circle cx="3.500" cy="3.500" r="0.400"/><circle cx="4.500" cy="3.500" r="0.400"/><circle cx="5.500" cy="3.500" r="0.400"/><circle cx="6.500" cy="3.500" r="0.400"/><circle cx="3.500" cy="4.500" r="0.400"/><circle cx="4.500" cy="4.500" r="0.400"/><circle cx="5.500" cy="4.500" r="0.400"/><circle cx="4.500" cy="5.500" r="0.400"/><circle cx="4.500" cy="6.500" r="0.400"/><circle cx="4.500" cy="7.500" r="0.400"/></g><g fill="#111111"><circle cx="2.500" cy="6.500" r="0.400"/><circle cx="1.500" cy="7.500" r="0.400"/></g><g fill="#111111"><circle cx="6.500" cy="6.500" r="0.400"/><circle cx="7.500" cy="7.500" r="0.400"/></g></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 9 9" width="9" height="9" role="img" aria-label="SimurgArray"><title>SimurgArray</title><g fill="#D4A017"><circle cx="1.500" cy="1.500" r="0.400"/><circle cx="7.500" cy="1.500" r="0.400"/><circle cx="1.500" cy="2.500" r="0.400"/><circle cx="2.500" cy="2.500" r="0.400"/><circle cx="4.500" cy="2.500" r="0.400"/><circle cx="6.500" cy="2.500" r="0.400"/><circle cx="7.500" cy="2.500" r="0.400"/><circle cx="2.500" cy="3.500" r="0.400"/><circle cx="3.500" cy="3.500" r="0.400"/><circle cx="4.500" cy="3.500" r="0.400"/><circle cx="5.500" cy="3.500" r="0.400"/><circle cx="6.500" cy="3.500" r="0.400"/><circle cx="3.500" cy="4.500" r="0.400"/><circle cx="4.500" cy="4.500" r="0.400"/><circle cx="5.500" cy="4.500" r="0.400"/><circle cx="4.500" cy="5.500" r="0.400"/><circle cx="4.500" cy="6.500" r="0.400"/><circle cx="4.500" cy="7.500" r="0.400"/></g><g fill="#C8453A"><circle cx="2.500" cy="6.500" r="0.400"/><circle cx="1.500" cy="7.500" r="0.400"/></g><g fill="#2F8F5B"><circle cx="6.500" cy="6.500" r="0.400"/><circle cx="7.500" cy="7.500" r="0.400"/></g></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 9 9" width="9" height="9" role="img" aria-label="SimurgArray"><title>SimurgArray</title><g fill="#D4A017"><circle cx="1.500" cy="1.500" r="0.400"/><circle cx="7.500" cy="1.500" r="0.400"/><circle cx="1.500" cy="2.500" r="0.400"/><circle cx="2.500" cy="2.500" r="0.400"/><circle cx="4.500" cy="2.500" r="0.400"/><circle cx="6.500" cy="2.500" r="0.400"/><circle cx="7.500" cy="2.500" r="0.400"/><circle cx="2.500" cy="3.500" r="0.400"/><circle cx="3.500" cy="3.500" r="0.400"/><circle cx="4.500" cy="3.500" r="0.400"/><circle cx="5.500" cy="3.500" r="0.400"/><circle cx="6.500" cy="3.500" r="0.400"/><circle cx="3.500" cy="4.500" r="0.400"/><circle cx="4.500" cy="4.500" r="0.400"/><circle cx="5.500" cy="4.500" r="0.400"/><circle cx="4.500" cy="5.500" r="0.400"/><circle cx="4.500" cy="6.500" r="0.400"/><circle cx="4.500" cy="7.500" r="0.400"/></g><g fill="#D4A017"><circle cx="2.500" cy="6.500" r="0.400"/><circle cx="1.500" cy="7.500" r="0.400"/></g><g fill="#D4A017"><circle cx="6.500" cy="6.500" r="0.400"/><circle cx="7.500" cy="7.500" r="0.400"/></g></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 9 9" width="9" height="9" role="img" aria-label="SimurgArray"><title>SimurgArray</title><g fill="#A87A00"><circle cx="1.500" cy="1.500" r="0.400"/><circle cx="7.500" cy="1.500" r="0.400"/><circle cx="1.500" cy="2.500" r="0.400"/><circle cx="2.500" cy="2.500" r="0.400"/><circle cx="4.500" cy="2.500" r="0.400"/><circle cx="6.500" cy="2.500" r="0.400"/><circle cx="7.500" cy="2.500" r="0.400"/><circle cx="2.500" cy="3.500" r="0.400"/><circle cx="3.500" cy="3.500" r="0.400"/><circle cx="4.500" cy="3.500" r="0.400"/><circle cx="5.500" cy="3.500" r="0.400"/><circle cx="6.500" cy="3.500" r="0.400"/><circle cx="3.500" cy="4.500" r="0.400"/><circle cx="4.500" cy="4.500" r="0.400"/><circle cx="5.500" cy="4.500" r="0.400"/><circle cx="4.500" cy="5.500" r="0.400"/><circle cx="4.500" cy="6.500" r="0.400"/><circle cx="4.500" cy="7.500" r="0.400"/></g><g fill="#C8453A"><circle cx="2.500" cy="6.500" r="0.400"/><circle cx="1.500" cy="7.500" r="0.400"/></g><g fill="#2F8F5B"><circle cx="6.500" cy="6.500" r="0.400"/><circle cx="7.500" cy="7.500" r="0.400"/></g></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 9 9" width="9" height="9" role="img" aria-label="SimurgArray"><title>SimurgArray</title><g fill="#FFFFFF"><circle cx="1.500" cy="1.500" r="0.400"/><circle cx="7.500" cy="1.500" r="0.400"/><circle cx="1.500" cy="2.500" r="0.400"/><circle cx="2.500" cy="2.500" r="0.400"/><circle cx="4.500" cy="2.500" r="0.400"/><circle cx="6.500" cy="2.500" r="0.400"/><circle cx="7.500" cy="2.500" r="0.400"/><circle cx="2.500" cy="3.500" r="0.400"/><circle cx="3.500" cy="3.500" r="0.400"/><circle cx="4.500" cy="3.500" r="0.400"/><circle cx="5.500" cy="3.500" r="0.400"/><circle cx="6.500" cy="3.500" r="0.400"/><circle cx="3.500" cy="4.500" r="0.400"/><circle cx="4.500" cy="4.500" r="0.400"/><circle cx="5.500" cy="4.500" r="0.400"/><circle cx="4.500" cy="5.500" r="0.400"/><circle cx="4.500" cy="6.500" r="0.400"/><circle cx="4.500" cy="7.500" r="0.400"/></g><g fill="#FFFFFF"><circle cx="2.500" cy="6.500" r="0.400"/><circle cx="1.500" cy="7.500" r="0.400"/></g><g fill="#FFFFFF"><circle cx="6.500" cy="6.500" r="0.400"/><circle cx="7.500" cy="7.500" r="0.400"/></g></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 13 12" width="13" height="12" role="img" aria-label="SimurgArray"><title>SimurgArray</title><g fill="#111111"><circle cx="1.500" cy="1.500" r="0.400"/><circle cx="11.500" cy="1.500" r="0.400"/><circle cx="1.500" cy="2.500" r="0.400"/><circle cx="2.500" cy="2.500" r="0.400"/><circle cx="10.500" cy="2.500" r="0.400"/><circle cx="11.500" cy="2.500" r="0.400"/><circle cx="2.500" cy="3.500" r="0.400"/><circle cx="3.500" cy="3.500" r="0.400"/><circle cx="6.500" cy="3.500" r="0.400"/><circle cx="9.500" cy="3.500" r="0.400"/><circle cx="10.500" cy="3.500" r="0.400"/><circle cx="3.500" cy="4.500" r="0.400"/><circle cx="4.500" cy="4.500" r="0.400"/><circle cx="5.500" cy="4.500" r="0.400"/><circle cx="6.500" cy="4.500" r="0.400"/><circle cx="7.500" cy="4.500" r="0.400"/><circle cx="8.500" cy="4.500" r="0.400"/><circle cx="9.500" cy="4.500" r="0.400"/><circle cx="1.500" cy="5.500" r="0.400"/><circle cx="2.500" cy="5.500" r="0.400"/><circle cx="3.500" cy="5.500" r="0.400"/><circle cx="4.500" cy="5.500" r="0.400"/><circle cx="5.500" cy="5.500" r="0.400"/><circle cx="6.500" cy="5.500" r="0.400"/><circle cx="7.500" cy="5.500" r="0.400"/><circle cx="8.500" cy="5.500" r="0.400"/><circle cx="9.500" cy="5.500" r="0.400"/><circle cx="10.500" cy="5.500" r="0.400"/><circle cx="11.500" cy="5.500" r="0.400"/><circle cx="4.500" cy="6.500" r="0.400"/><circle cx="5.500" cy="6.500" r="0.400"/><circle cx="6.500" cy="6.500" r="0.400"/><circle cx="7.500" cy="6.500" r="0.400"/><circle cx="8.500" cy="6.500" r="0.400"/><circle cx="5.500" cy="7.500" r="0.400"/><circle cx="6.500" cy="7.500" r="0.400"/><circle cx="7.500" cy="7.500" r="0.400"/><circle cx="6.500" cy="8.500" r="0.400"/><circle cx="6.500" cy="9.500" r="0.400"/><circle cx="5.500" cy="10.500" r="0.400"/><circle cx="6.500" cy="10.500" r="0.400"/><circle cx="7.500" cy="10.500" r="0.400"/></g><g fill="#111111"><circle cx="4.500" cy="8.500" r="0.400"/><circle cx="3.500" cy="9.500" r="0.400"/><circle cx="2.500" cy="10.500" r="0.400"/><circle cx="3.500" cy="10.500" r="0.400"/></g><g fill="#111111"><circle cx="8.500" cy="8.500" r="0.400"/><circle cx="9.500" cy="9.500" r="0.400"/><circle cx="9.500" cy="10.500" r="0.400"/><circle cx="10.500" cy="10.500" r="0.400"/></g></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 13 12" width="13" height="12" role="img" aria-label="SimurgArray"><title>SimurgArray</title><g fill="#D4A017"><circle cx="1.500" cy="1.500" r="0.400"/><circle cx="11.500" cy="1.500" r="0.400"/><circle cx="1.500" cy="2.500" r="0.400"/><circle cx="2.500" cy="2.500" r="0.400"/><circle cx="10.500" cy="2.500" r="0.400"/><circle cx="11.500" cy="2.500" r="0.400"/><circle cx="2.500" cy="3.500" r="0.400"/><circle cx="3.500" cy="3.500" r="0.400"/><circle cx="6.500" cy="3.500" r="0.400"/><circle cx="9.500" cy="3.500" r="0.400"/><circle cx="10.500" cy="3.500" r="0.400"/><circle cx="3.500" cy="4.500" r="0.400"/><circle cx="4.500" cy="4.500" r="0.400"/><circle cx="5.500" cy="4.500" r="0.400"/><circle cx="6.500" cy="4.500" r="0.400"/><circle cx="7.500" cy="4.500" r="0.400"/><circle cx="8.500" cy="4.500" r="0.400"/><circle cx="9.500" cy="4.500" r="0.400"/><circle cx="1.500" cy="5.500" r="0.400"/><circle cx="2.500" cy="5.500" r="0.400"/><circle cx="3.500" cy="5.500" r="0.400"/><circle cx="4.500" cy="5.500" r="0.400"/><circle cx="5.500" cy="5.500" r="0.400"/><circle cx="6.500" cy="5.500" r="0.400"/><circle cx="7.500" cy="5.500" r="0.400"/><circle cx="8.500" cy="5.500" r="0.400"/><circle cx="9.500" cy="5.500" r="0.400"/><circle cx="10.500" cy="5.500" r="0.400"/><circle cx="11.500" cy="5.500" r="0.400"/><circle cx="4.500" cy="6.500" r="0.400"/><circle cx="5.500" cy="6.500" r="0.400"/><circle cx="6.500" cy="6.500" r="0.400"/><circle cx="7.500" cy="6.500" r="0.400"/><circle cx="8.500" cy="6.500" r="0.400"/><circle cx="5.500" cy="7.500" r="0.400"/><circle cx="6.500" cy="7.500" r="0.400"/><circle cx="7.500" cy="7.500" r="0.400"/><circle cx="6.500" cy="8.500" r="0.400"/><circle cx="6.500" cy="9.500" r="0.400"/><circle cx="5.500" cy="10.500" r="0.400"/><circle cx="6.500" cy="10.500" r="0.400"/><circle cx="7.500" cy="10.500" r="0.400"/></g><g fill="#C8453A"><circle cx="4.500" cy="8.500" r="0.400"/><circle cx="3.500" cy="9.500" r="0.400"/><circle cx="2.500" cy="10.500" r="0.400"/><circle cx="3.500" cy="10.500" r="0.400"/></g><g fill="#2F8F5B"><circle cx="8.500" cy="8.500" r="0.400"/><circle cx="9.500" cy="9.500" r="0.400"/><circle cx="9.500" cy="10.500" r="0.400"/><circle cx="10.500" cy="10.500" r="0.400"/></g></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 13 12" width="13" height="12" role="img" aria-label="SimurgArray"><title>SimurgArray</title><g fill="#D4A017"><circle cx="1.500" cy="1.500" r="0.400"/><circle cx="11.500" cy="1.500" r="0.400"/><circle cx="1.500" cy="2.500" r="0.400"/><circle cx="2.500" cy="2.500" r="0.400"/><circle cx="10.500" cy="2.500" r="0.400"/><circle cx="11.500" cy="2.500" r="0.400"/><circle cx="2.500" cy="3.500" r="0.400"/><circle cx="3.500" cy="3.500" r="0.400"/><circle cx="6.500" cy="3.500" r="0.400"/><circle cx="9.500" cy="3.500" r="0.400"/><circle cx="10.500" cy="3.500" r="0.400"/><circle cx="3.500" cy="4.500" r="0.400"/><circle cx="4.500" cy="4.500" r="0.400"/><circle cx="5.500" cy="4.500" r="0.400"/><circle cx="6.500" cy="4.500" r="0.400"/><circle cx="7.500" cy="4.500" r="0.400"/><circle cx="8.500" cy="4.500" r="0.400"/><circle cx="9.500" cy="4.500" r="0.400"/><circle cx="1.500" cy="5.500" r="0.400"/><circle cx="2.500" cy="5.500" r="0.400"/><circle cx="3.500" cy="5.500" r="0.400"/><circle cx="4.500" cy="5.500" r="0.400"/><circle cx="5.500" cy="5.500" r="0.400"/><circle cx="6.500" cy="5.500" r="0.400"/><circle cx="7.500" cy="5.500" r="0.400"/><circle cx="8.500" cy="5.500" r="0.400"/><circle cx="9.500" cy="5.500" r="0.400"/><circle cx="10.500" cy="5.500" r="0.400"/><circle cx="11.500" cy="5.500" r="0.400"/><circle cx="4.500" cy="6.500" r="0.400"/><circle cx="5.500" cy="6.500" r="0.400"/><circle cx="6.500" cy="6.500" r="0.400"/><circle cx="7.500" cy="6.500" r="0.400"/><circle cx="8.500" cy="6.500" r="0.400"/><circle cx="5.500" cy="7.500" r="0.400"/><circle cx="6.500" cy="7.500" r="0.400"/><circle cx="7.500" cy="7.500" r="0.400"/><circle cx="6.500" cy="8.500" r="0.400"/><circle cx="6.500" cy="9.500" r="0.400"/><circle cx="5.500" cy="10.500" r="0.400"/><circle cx="6.500" cy="10.500" r="0.400"/><circle cx="7.500" cy="10.500" r="0.400"/></g><g fill="#D4A017"><circle cx="4.500" cy="8.500" r="0.400"/><circle cx="3.500" cy="9.500" r="0.400"/><circle cx="2.500" cy="10.500" r="0.400"/><circle cx="3.500" cy="10.500" r="0.400"/></g><g fill="#D4A017"><circle cx="8.500" cy="8.500" r="0.400"/><circle cx="9.500" cy="9.500" r="0.400"/><circle cx="9.500" cy="10.500" r="0.400"/><circle cx="10.500" cy="10.500" r="0.400"/></g></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 13 12" width="13" height="12" role="img" aria-label="SimurgArray"><title>SimurgArray</title><g fill="#A87A00"><circle cx="1.500" cy="1.500" r="0.400"/><circle cx="11.500" cy="1.500" r="0.400"/><circle cx="1.500" cy="2.500" r="0.400"/><circle cx="2.500" cy="2.500" r="0.400"/><circle cx="10.500" cy="2.500" r="0.400"/><circle cx="11.500" cy="2.500" r="0.400"/><circle cx="2.500" cy="3.500" r="0.400"/><circle cx="3.500" cy="3.500" r="0.400"/><circle cx="6.500" cy="3.500" r="0.400"/><circle cx="9.500" cy="3.500" r="0.400"/><circle cx="10.500" cy="3.500" r="0.400"/><circle cx="3.500" cy="4.500" r="0.400"/><circle cx="4.500" cy="4.500" r="0.400"/><circle cx="5.500" cy="4.500" r="0.400"/><circle cx="6.500" cy="4.500" r="0.400"/><circle cx="7.500" cy="4.500" r="0.400"/><circle cx="8.500" cy="4.500" r="0.400"/><circle cx="9.500" cy="4.500" r="0.400"/><circle cx="1.500" cy="5.500" r="0.400"/><circle cx="2.500" cy="5.500" r="0.400"/><circle cx="3.500" cy="5.500" r="0.400"/><circle cx="4.500" cy="5.500" r="0.400"/><circle cx="5.500" cy="5.500" r="0.400"/><circle cx="6.500" cy="5.500" r="0.400"/><circle cx="7.500" cy="5.500" r="0.400"/><circle cx="8.500" cy="5.500" r="0.400"/><circle cx="9.500" cy="5.500" r="0.400"/><circle cx="10.500" cy="5.500" r="0.400"/><circle cx="11.500" cy="5.500" r="0.400"/><circle cx="4.500" cy="6.500" r="0.400"/><circle cx="5.500" cy="6.500" r="0.400"/><circle cx="6.500" cy="6.500" r="0.400"/><circle cx="7.500" cy="6.500" r="0.400"/><circle cx="8.500" cy="6.500" r="0.400"/><circle cx="5.500" cy="7.500" r="0.400"/><circle cx="6.500" cy="7.500" r="0.400"/><circle cx="7.500" cy="7.500" r="0.400"/><circle cx="6.500" cy="8.500" r="0.400"/><circle cx="6.500" cy="9.500" r="0.400"/><circle cx="5.500" cy="10.500" r="0.400"/><circle cx="6.500" cy="10.500" r="0.400"/><circle cx="7.500" cy="10.500" r="0.400"/></g><g fill="#C8453A"><circle cx="4.500" cy="8.500" r="0.400"/><circle cx="3.500" cy="9.500" r="0.400"/><circle cx="2.500" cy="10.500" r="0.400"/><circle cx="3.500" cy="10.500" r="0.400"/></g><g fill="#2F8F5B"><circle cx="8.500" cy="8.500" r="0.400"/><circle cx="9.500" cy="9.500" r="0.400"/><circle cx="9.500" cy="10.500" r="0.400"/><circle cx="10.500" cy="10.500" r="0.400"/></g></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 13 12" width="13" height="12" role="img" aria-label="SimurgArray"><title>SimurgArray</title><g fill="#FFFFFF"><circle cx="1.500" cy="1.500" r="0.400"/><circle cx="11.500" cy="1.500" r="0.400"/><circle cx="1.500" cy="2.500" r="0.400"/><circle cx="2.500" cy="2.500" r="0.400"/><circle cx="10.500" cy="2.500" r="0.400"/><circle cx="11.500" cy="2.500" r="0.400"/><circle cx="2.500" cy="3.500" r="0.400"/><circle cx="3.500" cy="3.500" r="0.400"/><circle cx="6.500" cy="3.500" r="0.400"/><circle cx="9.500" cy="3.500" r="0.400"/><circle cx="10.500" cy="3.500" r="0.400"/><circle cx="3.500" cy="4.500" r="0.400"/><circle cx="4.500" cy="4.500" r="0.400"/><circle cx="5.500" cy="4.500" r="0.400"/><circle cx="6.500" cy="4.500" r="0.400"/><circle cx="7.500" cy="4.500" r="0.400"/><circle cx="8.500" cy="4.500" r="0.400"/><circle cx="9.500" cy="4.500" r="0.400"/><circle cx="1.500" cy="5.500" r="0.400"/><circle cx="2.500" cy="5.500" r="0.400"/><circle cx="3.500" cy="5.500" r="0.400"/><circle cx="4.500" cy="5.500" r="0.400"/><circle cx="5.500" cy="5.500" r="0.400"/><circle cx="6.500" cy="5.500" r="0.400"/><circle cx="7.500" cy="5.500" r="0.400"/><circle cx="8.500" cy="5.500" r="0.400"/><circle cx="9.500" cy="5.500" r="0.400"/><circle cx="10.500" cy="5.500" r="0.400"/><circle cx="11.500" cy="5.500" r="0.400"/><circle cx="4.500" cy="6.500" r="0.400"/><circle cx="5.500" cy="6.500" r="0.400"/><circle cx="6.500" cy="6.500" r="0.400"/><circle cx="7.500" cy="6.500" r="0.400"/><circle cx="8.500" cy="6.500" r="0.400"/><circle cx="5.500" cy="7.500" r="0.400"/><circle cx="6.500" cy="7.500" r="0.400"/><circle cx="7.500" cy="7.500" r="0.400"/><circle cx="6.500" cy="8.500" r="0.400"/><circle cx="6.500" cy="9.500" r="0.400"/><circle cx="5.500" cy="10.500" r="0.400"/><circle cx="6.500" cy="10.500" r="0.400"/><circle cx="7.500" cy="10.500" r="0.400"/></g><g fill="#FFFFFF"><circle cx="4.500" cy="8.500" r="0.400"/><circle cx="3.500" cy="9.500" r="0.400"/><circle cx="2.500" cy="10.500" r="0.400"/><circle cx="3.500" cy="10.500" r="0.400"/></g><g fill="#FFFFFF"><circle cx="8.500" cy="8.500" r="0.400"/><circle cx="9.500" cy="9.500" r="0.400"/><circle cx="9.500" cy="10.500" r="0.400"/><circle cx="10.500" cy="10.500" r="0.400"/></g></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 33 29" width="33" height="29" role="img" aria-label="SimurgArray"><title>SimurgArray</title><g fill="#FFFFFF"><circle cx="2.500" cy="1.500" r="0.400"/><circle cx="3.500" cy="1.500" r="0.400"/><circle cx="29.500" cy="1.500" r="0.400"/><circle cx="30.500" cy="1.500" r="0.400"/><circle cx="2.500" cy="2.500" r="0.400"/><circle cx="3.500" cy="2.500" r="0.400"/><circle cx="4.500" cy="2.500" r="0.400"/><circle cx="14.500" cy="2.500" r="0.400"/><circle cx="16.500" cy="2.500" r="0.400"/><circle cx="18.500" cy="2.500" r="0.400"/><circle cx="28.500" cy="2.500" r="0.400"/><circle cx="29.500" cy="2.500" r="0.400"/><circle cx="30.500" cy="2.500" r="0.400"/><circle cx="2.500" cy="3.500" r="0.400"/><circle cx="3.500" cy="3.500" r="0.400"/><circle cx="4.500" cy="3.500" r="0.400"/><circle cx="5.500" cy="3.500" r="0.400"/><circle cx="6.500" cy="3.500" r="0.400"/><circle cx="14.500" cy="3.500" r="0.400"/><circle cx="15.500" cy="3.500" r="0.400"/><circle cx="16.500" cy="3.500" r="0.400"/><circle cx="17.500" cy="3.500" r="0.400"/><circle cx="18.500" cy="3.500" r="0.400"/><circle cx="26.500" cy="3.500" r="0.400"/><circle cx="27.500" cy="3.500" r="0.400"/><circle cx="28.500" cy="3.500" r="0.400"/><circle cx="29.500" cy="3.500" r="0.400"/><circle cx="30.500" cy="3.500" r="0.400"/><circle cx="4.500" cy="4.500" r="0.400"/><circle cx="5.500" cy="4.500" r="0.400"/><circle cx="6.500" cy="4.500" r="0.400"/><circle cx="7.500" cy="4.500" r="0.400"/><circle cx="8.500" cy="4.500" r="0.400"/><circle cx="14.500" cy="4.500" r="0.400"/><circle cx="15.500" cy="4.500" r="0.400"/><circle cx="16.500" cy="4.500" r="0.400"/><circle cx="17.500" cy="4.500" r="0.400"/><circle cx="18.500" cy="4.500" r="0.400"/><circle cx="24.500" cy="4.500" r="0.400"/><circle cx="25.500" cy="4.500" r="0.400"/><circle cx="26.500" cy="4.500" r="0.400"/><circle cx="27.500" cy="4.500" r="0.400"/><circle cx="28.500" cy="4.500" r="0.400"/><circle cx="5.500" cy="5.500" r="0.400"/><circle cx="6.500" cy="5.500" r="0.400"/><circle cx="7.500" cy="5.500" r="0.400"/><circle cx="8.500" cy="5.500" r="0.400"/><circle cx="9.500" cy="5.500" r="0.400"/><circle cx="14.500" cy="5.500" r="0.400"/><circle cx="15.500" cy="5.500" r="0.400"/><circle cx="16.500" cy="5.500" r="0.400"/><circle cx="17.500" cy="5.500" r="0.400"/><circle cx="18.500" cy="5.500" r="0.400"/><circle cx="23.500" cy="5.500" r="0.400"/><circle cx="24.500" cy="5.500" r="0.400"/><circle cx="25.500" cy="5.500" r="0.400"/><circle cx="26.500" cy="5.500" r="0.400"/><circle cx="27.500" cy="5.500" r="0.400"/><circle cx="2.500" cy="6.500" r="0.400"/><circle cx="7.500" cy="6.500" r="0.400"/><circle cx="8.500" cy="6.500" r="0.400"/><circle cx="9.500" cy="6.500" r="0.400"/><circle cx="10.500" cy="6.500" r="0.400"/><circle cx="14.500" cy="6.500" r="0.400"/><circle cx="15.500" cy="6.500" r="0.400"/><circle cx="16.500" cy="6.500" r="0.400"/><circle cx="17.500" cy="6.500" r="0.400"/><circle cx="18.500" cy="6.500" r="0.400"/><circle cx="22.500" cy="6.500" r="0.400"/><circle cx="23.500" cy="6.500" r="0.400"/><circle cx="24.500" cy="6.500" r="0.400"/><circle cx="25.500" cy="6.500" r="0.400"/><circle cx="30.500" cy="6.500" r="0.400"/><circle cx="1.500" cy="7.500" r="0.400"/><circle cx="2.500" cy="7.500" r="0.400"/><circle cx="3.500" cy="7.500" r="0.400"/><circle cx="4.500" cy="7.500" r="0.400"/><circle cx="5.500" cy="7.500" r="0.400"/><circle cx="9.500" cy="7.500" r="0.400"/><circle cx="10.500" cy="7.500" r="0.400"/><circle cx="11.500" cy="7.500" r="0.400"/><circle cx="12.500" cy="7.500" r="0.400"/><circle cx="15.500" cy="7.500" r="0.400"/><circle cx="16.500" cy="7.500" r="0.400"/><circle cx="17.500" cy="7.500" r="0.400"/><circle cx="20.500" cy="7.500" r="0.400"/><circle cx="21.500" cy="7.500" r="0.400"/><circle cx="22.500" cy="7.500" r="0.400"/><circle cx="23.500" cy="7.500" r="0.400"/><circle cx="27.500" cy="7.500" r="0.400"/><circle cx="28.500" cy="7.500" r="0.400"/><circle cx="29.500" cy="7.500" r="0.400"/><circle cx="30.500" cy="7.500" r="0.400"/><circle cx="31.500" cy="7.500" r="0.400"/><circle cx="1.500" cy="8.500" r="0.400"/><circle cx="2.500" cy="8.500" r="0.400"/><circle cx="3.500" cy="8.500" r="0.400"/><circle cx="4.500" cy="8.500" r="0.400"/><circle cx="5.500" cy="8.500" r="0.400"/><circle cx="6.500" cy="8.500" r="0.400"/><circle cx="7.500" cy="8.500" r="0.400"/><circle cx="8.500" cy="8.500" r="0.400"/><circle cx="9.500" cy="8.500" r="0.400"/><circle cx="10.500" cy="8.500" r="0.400"/><circle cx="11.500" cy="8.500" r="0.400"/><circle cx="12.500" cy="8.500" r="0.400"/><circle cx="13.500" cy="8.500" r="0.400"/><circle cx="15.500" cy="8.500" r="0.400"/><circle cx="16.500" cy="8.500" r="0.400"/><circle cx="17.500" cy="8.500" r="0.400"/><circle cx="19.500" cy="8.500" r="0.400"/><circle cx="20.500" cy="8.500" r="0.400"/><circle cx="21.500" cy="8.500" r="0.400"/><circle cx="22.500" cy="8.500" r="0.400"/><circle cx="23.500" cy="8.500" r="0.400"/><circle cx="24.500" cy="8.500" r="0.400"/><ciLine truncated

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 630.7 100" width="630.7" height="100" role="img" aria-label="SimurgArray"><title>SimurgArray</title><path fill="#111111" d="M50.800000000000004 58.5Q50.800000000000004 68.0 43.900000000000006 73.5Q37.0 79.0 24.8 79.0Q13.0 79.0 4.800000000000001 75.0V63.0Q9.3 65.0 14.700000000000001 66.65Q20.1 68.3 25.700000000000003 68.3Q32.1 68.3 35.1 65.8Q38.1 63.3 38.1 59.2Q38.1 54.7 34.3 52.1Q30.5 49.5 23.200000000000003 46.4Q18.8 44.5 14.8 41.9Q10.8 39.3 8.200000000000001 35.3Q5.6000000000000005 31.299999999999997 5.6000000000000005 25.099999999999994Q5.6000000000000005 15.899999999999999 12.05 10.749999999999996Q18.5 5.599999999999994 29.3 5.599999999999994Q35.0 5.599999999999994 39.95 6.799999999999997Q44.900000000000006 8.0 49.900000000000006 10.200000000000003L45.800000000000004 20.5Q41.300000000000004 18.599999999999994 37.25 17.499999999999996Q33.2 16.4 28.900000000000002 16.4Q23.700000000000003 16.4 21.0 18.749999999999996Q18.3 21.099999999999994 18.3 24.799999999999997Q18.3 27.799999999999997 19.8 29.799999999999997Q21.3 31.799999999999997 24.450000000000003 33.5Q27.6 35.199999999999996 32.6 37.4Q38.300000000000004 39.9 42.400000000000006 42.599999999999994Q46.5 45.3 48.650000000000006 49.099999999999994Q50.800000000000004 52.9 50.800000000000004 58.5Z M69.9 2.8999999999999915Q72.8 2.8999999999999915 74.85 4.349999999999994Q76.9 5.799999999999997 76.9 9.5Q76.9 13.200000000000003 74.85 14.7Q72.8 16.199999999999996 69.9 16.199999999999996Q67.0 16.199999999999996 64.95 14.7Q62.9 13.200000000000003 62.9 9.5Q62.9 5.799999999999997 64.95 4.349999999999994Q67.0 2.8999999999999915 69.9 2.8999999999999915ZM76.2 23.799999999999997V78.0H63.6V23.799999999999997Z M154.9 22.799999999999997Q164.10000000000002 22.799999999999997 168.75 27.499999999999996Q173.4 32.199999999999996 173.4 42.699999999999996V78.0H160.8V45.1Q160.8 33.0 151.60000000000002 33.0Q145.0 33.0 142.2 37.3Q139.4 41.6 139.4 49.8V78.0H126.80000000000001V45.1Q126.80000000000001 33.0 117.5 33.0Q110.60000000000001 33.0 108.0 37.8Q105.4 42.6 105.4 51.5V78.0H92.8V23.799999999999997H102.5L104.30000000000001 30.9H105.0Q107.4 26.699999999999996 111.75 24.749999999999996Q116.10000000000001 22.799999999999997 120.80000000000001 22.799999999999997Q126.9 22.799999999999997 131.05 24.849999999999998Q135.2 26.9 137.4 31.199999999999996H138.4Q140.9 26.799999999999997 145.4 24.799999999999997Q149.9 22.799999999999997 154.9 22.799999999999997Z M237.8 23.799999999999997V78.0H227.90000000000003L226.20000000000002 71.0H225.60000000000002Q222.90000000000003 75.2 218.35000000000002 77.1Q213.8 79.0 208.70000000000002 79.0Q199.60000000000002 79.0 194.45000000000002 74.3Q189.3 69.6 189.3 59.2V23.799999999999997H201.90000000000003V56.7Q201.90000000000003 68.8 211.90000000000003 68.8Q219.50000000000003 68.8 222.35000000000002 64.05Q225.20000000000002 59.3 225.20000000000002 50.3V23.799999999999997Z M282.8 22.799999999999997Q284.1 22.799999999999997 285.65000000000003 22.9Q287.20000000000005 23.0 288.3 23.299999999999997L287.20000000000005 35.0Q286.20000000000005 34.8 284.80000000000007 34.65Q283.40000000000003 34.5 282.3 34.5Q278.3 34.5 274.8 36.15Q271.3 37.8 269.15 41.25Q267.0 44.699999999999996 267.0 49.9V78.0H254.4V23.799999999999997H264.1L265.90000000000003 33.199999999999996H266.5Q268.90000000000003 28.9 273.1 25.849999999999998Q277.3 22.799999999999997 282.8 22.799999999999997Z M317.00000000000006 22.799999999999997Q327.30000000000007 22.799999999999997 333.1 30.799999999999997H333.6L334.80000000000007 23.799999999999997H345.30000000000007V78.4Q345.30000000000007 90.0 338.75000000000006 96.0Q332.20000000000005 102.0 319.20000000000005 102.0Q313.40000000000003 102.0 308.5 101.25Q303.6 100.5 299.20000000000005 98.7V88.3Q308.50000000000006 92.5 320.00000000000006 92.5Q326.20000000000005 92.5 329.45000000000005 89.05Q332.70000000000005 85.6 332.70000000000005 79.0V77.6Q332.70000000000005 76.1 332.80000000000007 74.1Q332.90000000000003 72.1 333.1 70.9H332.70000000000005Q329.90000000000003 75.1 325.85 77.05Q321.80000000000007 79.0 316.70000000000005 79.0Q306.80000000000007 79.0 301.20000000000005 71.6Q295.6 64.2 295.6 51.0Q295.6 37.8 301.25 30.299999999999997Q306.90000000000003 22.799999999999997 317.00000000000006 22.799999999999997ZM320.30000000000007 33.099999999999994Q308.50000000000006 33.099999999999994 308.50000000000006 51.2Q308.50000000000006 69.0 320.50000000000006 69.0Q327.1 69.0 330.25 65.35Q333.40000000000003 61.7 333.40000000000003 53.0V51.099999999999994Q333.40000000000003 41.5 330.25 37.3Q327.1 33.099999999999994 320.30000000000007 33.099999999999994Z"/><path fill="#111111" d="M409.70000000000005 78.0 403.20000000000005 59.099999999999994H376.30000000000007L369.9000000000001 78.0H356.30000000000007L382.50000000000006 6.299999999999997H397.1000000000001L423.30000000000007 78.0ZM393.70000000000005 29.699999999999996Q393.30000000000007 28.299999999999997 392.50000000000006 25.9Q391.70000000000005 23.5 390.95000000000005 Line truncated

After

Width:  |  Height:  |  Size: 7.8 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 630.7 100" width="630.7" height="100" role="img" aria-label="SimurgArray"><title>SimurgArray</title><path fill="#F7F5EF" d="M50.800000000000004 58.5Q50.800000000000004 68.0 43.900000000000006 73.5Q37.0 79.0 24.8 79.0Q13.0 79.0 4.800000000000001 75.0V63.0Q9.3 65.0 14.700000000000001 66.65Q20.1 68.3 25.700000000000003 68.3Q32.1 68.3 35.1 65.8Q38.1 63.3 38.1 59.2Q38.1 54.7 34.3 52.1Q30.5 49.5 23.200000000000003 46.4Q18.8 44.5 14.8 41.9Q10.8 39.3 8.200000000000001 35.3Q5.6000000000000005 31.299999999999997 5.6000000000000005 25.099999999999994Q5.6000000000000005 15.899999999999999 12.05 10.749999999999996Q18.5 5.599999999999994 29.3 5.599999999999994Q35.0 5.599999999999994 39.95 6.799999999999997Q44.900000000000006 8.0 49.900000000000006 10.200000000000003L45.800000000000004 20.5Q41.300000000000004 18.599999999999994 37.25 17.499999999999996Q33.2 16.4 28.900000000000002 16.4Q23.700000000000003 16.4 21.0 18.749999999999996Q18.3 21.099999999999994 18.3 24.799999999999997Q18.3 27.799999999999997 19.8 29.799999999999997Q21.3 31.799999999999997 24.450000000000003 33.5Q27.6 35.199999999999996 32.6 37.4Q38.300000000000004 39.9 42.400000000000006 42.599999999999994Q46.5 45.3 48.650000000000006 49.099999999999994Q50.800000000000004 52.9 50.800000000000004 58.5Z M69.9 2.8999999999999915Q72.8 2.8999999999999915 74.85 4.349999999999994Q76.9 5.799999999999997 76.9 9.5Q76.9 13.200000000000003 74.85 14.7Q72.8 16.199999999999996 69.9 16.199999999999996Q67.0 16.199999999999996 64.95 14.7Q62.9 13.200000000000003 62.9 9.5Q62.9 5.799999999999997 64.95 4.349999999999994Q67.0 2.8999999999999915 69.9 2.8999999999999915ZM76.2 23.799999999999997V78.0H63.6V23.799999999999997Z M154.9 22.799999999999997Q164.10000000000002 22.799999999999997 168.75 27.499999999999996Q173.4 32.199999999999996 173.4 42.699999999999996V78.0H160.8V45.1Q160.8 33.0 151.60000000000002 33.0Q145.0 33.0 142.2 37.3Q139.4 41.6 139.4 49.8V78.0H126.80000000000001V45.1Q126.80000000000001 33.0 117.5 33.0Q110.60000000000001 33.0 108.0 37.8Q105.4 42.6 105.4 51.5V78.0H92.8V23.799999999999997H102.5L104.30000000000001 30.9H105.0Q107.4 26.699999999999996 111.75 24.749999999999996Q116.10000000000001 22.799999999999997 120.80000000000001 22.799999999999997Q126.9 22.799999999999997 131.05 24.849999999999998Q135.2 26.9 137.4 31.199999999999996H138.4Q140.9 26.799999999999997 145.4 24.799999999999997Q149.9 22.799999999999997 154.9 22.799999999999997Z M237.8 23.799999999999997V78.0H227.90000000000003L226.20000000000002 71.0H225.60000000000002Q222.90000000000003 75.2 218.35000000000002 77.1Q213.8 79.0 208.70000000000002 79.0Q199.60000000000002 79.0 194.45000000000002 74.3Q189.3 69.6 189.3 59.2V23.799999999999997H201.90000000000003V56.7Q201.90000000000003 68.8 211.90000000000003 68.8Q219.50000000000003 68.8 222.35000000000002 64.05Q225.20000000000002 59.3 225.20000000000002 50.3V23.799999999999997Z M282.8 22.799999999999997Q284.1 22.799999999999997 285.65000000000003 22.9Q287.20000000000005 23.0 288.3 23.299999999999997L287.20000000000005 35.0Q286.20000000000005 34.8 284.80000000000007 34.65Q283.40000000000003 34.5 282.3 34.5Q278.3 34.5 274.8 36.15Q271.3 37.8 269.15 41.25Q267.0 44.699999999999996 267.0 49.9V78.0H254.4V23.799999999999997H264.1L265.90000000000003 33.199999999999996H266.5Q268.90000000000003 28.9 273.1 25.849999999999998Q277.3 22.799999999999997 282.8 22.799999999999997Z M317.00000000000006 22.799999999999997Q327.30000000000007 22.799999999999997 333.1 30.799999999999997H333.6L334.80000000000007 23.799999999999997H345.30000000000007V78.4Q345.30000000000007 90.0 338.75000000000006 96.0Q332.20000000000005 102.0 319.20000000000005 102.0Q313.40000000000003 102.0 308.5 101.25Q303.6 100.5 299.20000000000005 98.7V88.3Q308.50000000000006 92.5 320.00000000000006 92.5Q326.20000000000005 92.5 329.45000000000005 89.05Q332.70000000000005 85.6 332.70000000000005 79.0V77.6Q332.70000000000005 76.1 332.80000000000007 74.1Q332.90000000000003 72.1 333.1 70.9H332.70000000000005Q329.90000000000003 75.1 325.85 77.05Q321.80000000000007 79.0 316.70000000000005 79.0Q306.80000000000007 79.0 301.20000000000005 71.6Q295.6 64.2 295.6 51.0Q295.6 37.8 301.25 30.299999999999997Q306.90000000000003 22.799999999999997 317.00000000000006 22.799999999999997ZM320.30000000000007 33.099999999999994Q308.50000000000006 33.099999999999994 308.50000000000006 51.2Q308.50000000000006 69.0 320.50000000000006 69.0Q327.1 69.0 330.25 65.35Q333.40000000000003 61.7 333.40000000000003 53.0V51.099999999999994Q333.40000000000003 41.5 330.25 37.3Q327.1 33.099999999999994 320.30000000000007 33.099999999999994Z"/><path fill="#D4A017" d="M409.70000000000005 78.0 403.20000000000005 59.099999999999994H376.30000000000007L369.9000000000001 78.0H356.30000000000007L382.50000000000006 6.299999999999997H397.1000000000001L423.30000000000007 78.0ZM393.70000000000005 29.699999999999996Q393.30000000000007 28.299999999999997 392.50000000000006 25.9Q391.70000000000005 23.5 390.95000000000005 Line truncated

After

Width:  |  Height:  |  Size: 7.8 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 630.7 100" width="630.7" height="100" role="img" aria-label="SimurgArray"><title>SimurgArray</title><path fill="#D4A017" d="M50.800000000000004 58.5Q50.800000000000004 68.0 43.900000000000006 73.5Q37.0 79.0 24.8 79.0Q13.0 79.0 4.800000000000001 75.0V63.0Q9.3 65.0 14.700000000000001 66.65Q20.1 68.3 25.700000000000003 68.3Q32.1 68.3 35.1 65.8Q38.1 63.3 38.1 59.2Q38.1 54.7 34.3 52.1Q30.5 49.5 23.200000000000003 46.4Q18.8 44.5 14.8 41.9Q10.8 39.3 8.200000000000001 35.3Q5.6000000000000005 31.299999999999997 5.6000000000000005 25.099999999999994Q5.6000000000000005 15.899999999999999 12.05 10.749999999999996Q18.5 5.599999999999994 29.3 5.599999999999994Q35.0 5.599999999999994 39.95 6.799999999999997Q44.900000000000006 8.0 49.900000000000006 10.200000000000003L45.800000000000004 20.5Q41.300000000000004 18.599999999999994 37.25 17.499999999999996Q33.2 16.4 28.900000000000002 16.4Q23.700000000000003 16.4 21.0 18.749999999999996Q18.3 21.099999999999994 18.3 24.799999999999997Q18.3 27.799999999999997 19.8 29.799999999999997Q21.3 31.799999999999997 24.450000000000003 33.5Q27.6 35.199999999999996 32.6 37.4Q38.300000000000004 39.9 42.400000000000006 42.599999999999994Q46.5 45.3 48.650000000000006 49.099999999999994Q50.800000000000004 52.9 50.800000000000004 58.5Z M69.9 2.8999999999999915Q72.8 2.8999999999999915 74.85 4.349999999999994Q76.9 5.799999999999997 76.9 9.5Q76.9 13.200000000000003 74.85 14.7Q72.8 16.199999999999996 69.9 16.199999999999996Q67.0 16.199999999999996 64.95 14.7Q62.9 13.200000000000003 62.9 9.5Q62.9 5.799999999999997 64.95 4.349999999999994Q67.0 2.8999999999999915 69.9 2.8999999999999915ZM76.2 23.799999999999997V78.0H63.6V23.799999999999997Z M154.9 22.799999999999997Q164.10000000000002 22.799999999999997 168.75 27.499999999999996Q173.4 32.199999999999996 173.4 42.699999999999996V78.0H160.8V45.1Q160.8 33.0 151.60000000000002 33.0Q145.0 33.0 142.2 37.3Q139.4 41.6 139.4 49.8V78.0H126.80000000000001V45.1Q126.80000000000001 33.0 117.5 33.0Q110.60000000000001 33.0 108.0 37.8Q105.4 42.6 105.4 51.5V78.0H92.8V23.799999999999997H102.5L104.30000000000001 30.9H105.0Q107.4 26.699999999999996 111.75 24.749999999999996Q116.10000000000001 22.799999999999997 120.80000000000001 22.799999999999997Q126.9 22.799999999999997 131.05 24.849999999999998Q135.2 26.9 137.4 31.199999999999996H138.4Q140.9 26.799999999999997 145.4 24.799999999999997Q149.9 22.799999999999997 154.9 22.799999999999997Z M237.8 23.799999999999997V78.0H227.90000000000003L226.20000000000002 71.0H225.60000000000002Q222.90000000000003 75.2 218.35000000000002 77.1Q213.8 79.0 208.70000000000002 79.0Q199.60000000000002 79.0 194.45000000000002 74.3Q189.3 69.6 189.3 59.2V23.799999999999997H201.90000000000003V56.7Q201.90000000000003 68.8 211.90000000000003 68.8Q219.50000000000003 68.8 222.35000000000002 64.05Q225.20000000000002 59.3 225.20000000000002 50.3V23.799999999999997Z M282.8 22.799999999999997Q284.1 22.799999999999997 285.65000000000003 22.9Q287.20000000000005 23.0 288.3 23.299999999999997L287.20000000000005 35.0Q286.20000000000005 34.8 284.80000000000007 34.65Q283.40000000000003 34.5 282.3 34.5Q278.3 34.5 274.8 36.15Q271.3 37.8 269.15 41.25Q267.0 44.699999999999996 267.0 49.9V78.0H254.4V23.799999999999997H264.1L265.90000000000003 33.199999999999996H266.5Q268.90000000000003 28.9 273.1 25.849999999999998Q277.3 22.799999999999997 282.8 22.799999999999997Z M317.00000000000006 22.799999999999997Q327.30000000000007 22.799999999999997 333.1 30.799999999999997H333.6L334.80000000000007 23.799999999999997H345.30000000000007V78.4Q345.30000000000007 90.0 338.75000000000006 96.0Q332.20000000000005 102.0 319.20000000000005 102.0Q313.40000000000003 102.0 308.5 101.25Q303.6 100.5 299.20000000000005 98.7V88.3Q308.50000000000006 92.5 320.00000000000006 92.5Q326.20000000000005 92.5 329.45000000000005 89.05Q332.70000000000005 85.6 332.70000000000005 79.0V77.6Q332.70000000000005 76.1 332.80000000000007 74.1Q332.90000000000003 72.1 333.1 70.9H332.70000000000005Q329.90000000000003 75.1 325.85 77.05Q321.80000000000007 79.0 316.70000000000005 79.0Q306.80000000000007 79.0 301.20000000000005 71.6Q295.6 64.2 295.6 51.0Q295.6 37.8 301.25 30.299999999999997Q306.90000000000003 22.799999999999997 317.00000000000006 22.799999999999997ZM320.30000000000007 33.099999999999994Q308.50000000000006 33.099999999999994 308.50000000000006 51.2Q308.50000000000006 69.0 320.50000000000006 69.0Q327.1 69.0 330.25 65.35Q333.40000000000003 61.7 333.40000000000003 53.0V51.099999999999994Q333.40000000000003 41.5 330.25 37.3Q327.1 33.099999999999994 320.30000000000007 33.099999999999994Z"/><path fill="#D4A017" d="M409.70000000000005 78.0 403.20000000000005 59.099999999999994H376.30000000000007L369.9000000000001 78.0H356.30000000000007L382.50000000000006 6.299999999999997H397.1000000000001L423.30000000000007 78.0ZM393.70000000000005 29.699999999999996Q393.30000000000007 28.299999999999997 392.50000000000006 25.9Q391.70000000000005 23.5 390.95000000000005 Line truncated

After

Width:  |  Height:  |  Size: 7.8 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 630.7 100" width="630.7" height="100" role="img" aria-label="SimurgArray"><title>SimurgArray</title><path fill="#1E2240" d="M50.800000000000004 58.5Q50.800000000000004 68.0 43.900000000000006 73.5Q37.0 79.0 24.8 79.0Q13.0 79.0 4.800000000000001 75.0V63.0Q9.3 65.0 14.700000000000001 66.65Q20.1 68.3 25.700000000000003 68.3Q32.1 68.3 35.1 65.8Q38.1 63.3 38.1 59.2Q38.1 54.7 34.3 52.1Q30.5 49.5 23.200000000000003 46.4Q18.8 44.5 14.8 41.9Q10.8 39.3 8.200000000000001 35.3Q5.6000000000000005 31.299999999999997 5.6000000000000005 25.099999999999994Q5.6000000000000005 15.899999999999999 12.05 10.749999999999996Q18.5 5.599999999999994 29.3 5.599999999999994Q35.0 5.599999999999994 39.95 6.799999999999997Q44.900000000000006 8.0 49.900000000000006 10.200000000000003L45.800000000000004 20.5Q41.300000000000004 18.599999999999994 37.25 17.499999999999996Q33.2 16.4 28.900000000000002 16.4Q23.700000000000003 16.4 21.0 18.749999999999996Q18.3 21.099999999999994 18.3 24.799999999999997Q18.3 27.799999999999997 19.8 29.799999999999997Q21.3 31.799999999999997 24.450000000000003 33.5Q27.6 35.199999999999996 32.6 37.4Q38.300000000000004 39.9 42.400000000000006 42.599999999999994Q46.5 45.3 48.650000000000006 49.099999999999994Q50.800000000000004 52.9 50.800000000000004 58.5Z M69.9 2.8999999999999915Q72.8 2.8999999999999915 74.85 4.349999999999994Q76.9 5.799999999999997 76.9 9.5Q76.9 13.200000000000003 74.85 14.7Q72.8 16.199999999999996 69.9 16.199999999999996Q67.0 16.199999999999996 64.95 14.7Q62.9 13.200000000000003 62.9 9.5Q62.9 5.799999999999997 64.95 4.349999999999994Q67.0 2.8999999999999915 69.9 2.8999999999999915ZM76.2 23.799999999999997V78.0H63.6V23.799999999999997Z M154.9 22.799999999999997Q164.10000000000002 22.799999999999997 168.75 27.499999999999996Q173.4 32.199999999999996 173.4 42.699999999999996V78.0H160.8V45.1Q160.8 33.0 151.60000000000002 33.0Q145.0 33.0 142.2 37.3Q139.4 41.6 139.4 49.8V78.0H126.80000000000001V45.1Q126.80000000000001 33.0 117.5 33.0Q110.60000000000001 33.0 108.0 37.8Q105.4 42.6 105.4 51.5V78.0H92.8V23.799999999999997H102.5L104.30000000000001 30.9H105.0Q107.4 26.699999999999996 111.75 24.749999999999996Q116.10000000000001 22.799999999999997 120.80000000000001 22.799999999999997Q126.9 22.799999999999997 131.05 24.849999999999998Q135.2 26.9 137.4 31.199999999999996H138.4Q140.9 26.799999999999997 145.4 24.799999999999997Q149.9 22.799999999999997 154.9 22.799999999999997Z M237.8 23.799999999999997V78.0H227.90000000000003L226.20000000000002 71.0H225.60000000000002Q222.90000000000003 75.2 218.35000000000002 77.1Q213.8 79.0 208.70000000000002 79.0Q199.60000000000002 79.0 194.45000000000002 74.3Q189.3 69.6 189.3 59.2V23.799999999999997H201.90000000000003V56.7Q201.90000000000003 68.8 211.90000000000003 68.8Q219.50000000000003 68.8 222.35000000000002 64.05Q225.20000000000002 59.3 225.20000000000002 50.3V23.799999999999997Z M282.8 22.799999999999997Q284.1 22.799999999999997 285.65000000000003 22.9Q287.20000000000005 23.0 288.3 23.299999999999997L287.20000000000005 35.0Q286.20000000000005 34.8 284.80000000000007 34.65Q283.40000000000003 34.5 282.3 34.5Q278.3 34.5 274.8 36.15Q271.3 37.8 269.15 41.25Q267.0 44.699999999999996 267.0 49.9V78.0H254.4V23.799999999999997H264.1L265.90000000000003 33.199999999999996H266.5Q268.90000000000003 28.9 273.1 25.849999999999998Q277.3 22.799999999999997 282.8 22.799999999999997Z M317.00000000000006 22.799999999999997Q327.30000000000007 22.799999999999997 333.1 30.799999999999997H333.6L334.80000000000007 23.799999999999997H345.30000000000007V78.4Q345.30000000000007 90.0 338.75000000000006 96.0Q332.20000000000005 102.0 319.20000000000005 102.0Q313.40000000000003 102.0 308.5 101.25Q303.6 100.5 299.20000000000005 98.7V88.3Q308.50000000000006 92.5 320.00000000000006 92.5Q326.20000000000005 92.5 329.45000000000005 89.05Q332.70000000000005 85.6 332.70000000000005 79.0V77.6Q332.70000000000005 76.1 332.80000000000007 74.1Q332.90000000000003 72.1 333.1 70.9H332.70000000000005Q329.90000000000003 75.1 325.85 77.05Q321.80000000000007 79.0 316.70000000000005 79.0Q306.80000000000007 79.0 301.20000000000005 71.6Q295.6 64.2 295.6 51.0Q295.6 37.8 301.25 30.299999999999997Q306.90000000000003 22.799999999999997 317.00000000000006 22.799999999999997ZM320.30000000000007 33.099999999999994Q308.50000000000006 33.099999999999994 308.50000000000006 51.2Q308.50000000000006 69.0 320.50000000000006 69.0Q327.1 69.0 330.25 65.35Q333.40000000000003 61.7 333.40000000000003 53.0V51.099999999999994Q333.40000000000003 41.5 330.25 37.3Q327.1 33.099999999999994 320.30000000000007 33.099999999999994Z"/><path fill="#8C6500" d="M409.70000000000005 78.0 403.20000000000005 59.099999999999994H376.30000000000007L369.9000000000001 78.0H356.30000000000007L382.50000000000006 6.299999999999997H397.1000000000001L423.30000000000007 78.0ZM393.70000000000005 29.699999999999996Q393.30000000000007 28.299999999999997 392.50000000000006 25.9Q391.70000000000005 23.5 390.95000000000005 Line truncated

After

Width:  |  Height:  |  Size: 7.8 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 630.7 100" width="630.7" height="100" role="img" aria-label="SimurgArray"><title>SimurgArray</title><path fill="#FFFFFF" d="M50.800000000000004 58.5Q50.800000000000004 68.0 43.900000000000006 73.5Q37.0 79.0 24.8 79.0Q13.0 79.0 4.800000000000001 75.0V63.0Q9.3 65.0 14.700000000000001 66.65Q20.1 68.3 25.700000000000003 68.3Q32.1 68.3 35.1 65.8Q38.1 63.3 38.1 59.2Q38.1 54.7 34.3 52.1Q30.5 49.5 23.200000000000003 46.4Q18.8 44.5 14.8 41.9Q10.8 39.3 8.200000000000001 35.3Q5.6000000000000005 31.299999999999997 5.6000000000000005 25.099999999999994Q5.6000000000000005 15.899999999999999 12.05 10.749999999999996Q18.5 5.599999999999994 29.3 5.599999999999994Q35.0 5.599999999999994 39.95 6.799999999999997Q44.900000000000006 8.0 49.900000000000006 10.200000000000003L45.800000000000004 20.5Q41.300000000000004 18.599999999999994 37.25 17.499999999999996Q33.2 16.4 28.900000000000002 16.4Q23.700000000000003 16.4 21.0 18.749999999999996Q18.3 21.099999999999994 18.3 24.799999999999997Q18.3 27.799999999999997 19.8 29.799999999999997Q21.3 31.799999999999997 24.450000000000003 33.5Q27.6 35.199999999999996 32.6 37.4Q38.300000000000004 39.9 42.400000000000006 42.599999999999994Q46.5 45.3 48.650000000000006 49.099999999999994Q50.800000000000004 52.9 50.800000000000004 58.5Z M69.9 2.8999999999999915Q72.8 2.8999999999999915 74.85 4.349999999999994Q76.9 5.799999999999997 76.9 9.5Q76.9 13.200000000000003 74.85 14.7Q72.8 16.199999999999996 69.9 16.199999999999996Q67.0 16.199999999999996 64.95 14.7Q62.9 13.200000000000003 62.9 9.5Q62.9 5.799999999999997 64.95 4.349999999999994Q67.0 2.8999999999999915 69.9 2.8999999999999915ZM76.2 23.799999999999997V78.0H63.6V23.799999999999997Z M154.9 22.799999999999997Q164.10000000000002 22.799999999999997 168.75 27.499999999999996Q173.4 32.199999999999996 173.4 42.699999999999996V78.0H160.8V45.1Q160.8 33.0 151.60000000000002 33.0Q145.0 33.0 142.2 37.3Q139.4 41.6 139.4 49.8V78.0H126.80000000000001V45.1Q126.80000000000001 33.0 117.5 33.0Q110.60000000000001 33.0 108.0 37.8Q105.4 42.6 105.4 51.5V78.0H92.8V23.799999999999997H102.5L104.30000000000001 30.9H105.0Q107.4 26.699999999999996 111.75 24.749999999999996Q116.10000000000001 22.799999999999997 120.80000000000001 22.799999999999997Q126.9 22.799999999999997 131.05 24.849999999999998Q135.2 26.9 137.4 31.199999999999996H138.4Q140.9 26.799999999999997 145.4 24.799999999999997Q149.9 22.799999999999997 154.9 22.799999999999997Z M237.8 23.799999999999997V78.0H227.90000000000003L226.20000000000002 71.0H225.60000000000002Q222.90000000000003 75.2 218.35000000000002 77.1Q213.8 79.0 208.70000000000002 79.0Q199.60000000000002 79.0 194.45000000000002 74.3Q189.3 69.6 189.3 59.2V23.799999999999997H201.90000000000003V56.7Q201.90000000000003 68.8 211.90000000000003 68.8Q219.50000000000003 68.8 222.35000000000002 64.05Q225.20000000000002 59.3 225.20000000000002 50.3V23.799999999999997Z M282.8 22.799999999999997Q284.1 22.799999999999997 285.65000000000003 22.9Q287.20000000000005 23.0 288.3 23.299999999999997L287.20000000000005 35.0Q286.20000000000005 34.8 284.80000000000007 34.65Q283.40000000000003 34.5 282.3 34.5Q278.3 34.5 274.8 36.15Q271.3 37.8 269.15 41.25Q267.0 44.699999999999996 267.0 49.9V78.0H254.4V23.799999999999997H264.1L265.90000000000003 33.199999999999996H266.5Q268.90000000000003 28.9 273.1 25.849999999999998Q277.3 22.799999999999997 282.8 22.799999999999997Z M317.00000000000006 22.799999999999997Q327.30000000000007 22.799999999999997 333.1 30.799999999999997H333.6L334.80000000000007 23.799999999999997H345.30000000000007V78.4Q345.30000000000007 90.0 338.75000000000006 96.0Q332.20000000000005 102.0 319.20000000000005 102.0Q313.40000000000003 102.0 308.5 101.25Q303.6 100.5 299.20000000000005 98.7V88.3Q308.50000000000006 92.5 320.00000000000006 92.5Q326.20000000000005 92.5 329.45000000000005 89.05Q332.70000000000005 85.6 332.70000000000005 79.0V77.6Q332.70000000000005 76.1 332.80000000000007 74.1Q332.90000000000003 72.1 333.1 70.9H332.70000000000005Q329.90000000000003 75.1 325.85 77.05Q321.80000000000007 79.0 316.70000000000005 79.0Q306.80000000000007 79.0 301.20000000000005 71.6Q295.6 64.2 295.6 51.0Q295.6 37.8 301.25 30.299999999999997Q306.90000000000003 22.799999999999997 317.00000000000006 22.799999999999997ZM320.30000000000007 33.099999999999994Q308.50000000000006 33.099999999999994 308.50000000000006 51.2Q308.50000000000006 69.0 320.50000000000006 69.0Q327.1 69.0 330.25 65.35Q333.40000000000003 61.7 333.40000000000003 53.0V51.099999999999994Q333.40000000000003 41.5 330.25 37.3Q327.1 33.099999999999994 320.30000000000007 33.099999999999994Z"/><path fill="#FFFFFF" d="M409.70000000000005 78.0 403.20000000000005 59.099999999999994H376.30000000000007L369.9000000000001 78.0H356.30000000000007L382.50000000000006 6.299999999999997H397.1000000000001L423.30000000000007 78.0ZM393.70000000000005 29.699999999999996Q393.30000000000007 28.299999999999997 392.50000000000006 25.9Q391.70000000000005 23.5 390.95000000000005 Line truncated

After

Width:  |  Height:  |  Size: 7.8 KiB

Loaded 100 of 251 files, more files were not shown because too many files have changed in this diff. Show more