From 972570b142f016f9ee0e6c6c3cf854043dc05eac Mon Sep 17 00:00:00 2001 From: Gulum Date: Sat, 6 Jun 2026 11:47:33 +0200 Subject: [PATCH] GEN-3f: reconcile cchm colourpoint catalog to the breeder's CP- naming MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Computed Farbschlag now == the breeder's dropdown/seed names for colourpoints, so the mismatch hint stops and the live re-import name-matches her data (god: she uses the CP- prefix form + Marder/Siam/Zobel/Zobel-Hell; ZERO of the old portal suffix names). FULL collapse (god-approved, data-safe). Catalog (BASE_COLORS) 73 -> 61: the 24 portal cchm rows collapse to 12 breeder varieties — Marder, Siam, Zobel, Zobel-Hell (aa marten/sable group; E & D irrelevant per the merged GEN-3e rule) and CP-Agouti, CP-Silberagouti, CP-Algierfuchs, CP-Polarfuchs, CP-Fuchs, CP-Fuchs-Hell, CP-Blaufuchs, CP-Orangeschimmel (A- 'CP-'; -Hell shade variants collapsed). - representativeGenotype() now splits a heterozygous 'x/y' token, so the het colourpoints Siam & Zobel-Hell (C: 'cchm/ch') carry the correct het canonical genotype and the engine computes their own names (verified). - Engine covers all fox(ee)/dilute(dd) A- cchm bases via the E-family fallback (no Unbekannt). KNOWN BEST-EFFORT GAP: CP-Fuchs-Hell and CP-Blaufuchs both compute 'CP-Fuchs' (the het-lighter / blue-dilute distinction isn't encoded); their distinct rows remain for hand-pick + import name-match. Closing this fully needs the breeder's exact fox-CP genotype rule. Regenerated colorVarietySeed.generated.json (61 rows) for Pam's re-seed migration. Gate green: build, eslint, vitest 78, e2e 80. de.ts untouched. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../src/genetics/__tests__/genetics.test.ts | 55 +++- gerbil-manager-web/src/genetics/catalog.ts | 54 ++-- .../genetics/colorVarietySeed.generated.json | 245 ++++++------------ 3 files changed, 166 insertions(+), 188 deletions(-) diff --git a/gerbil-manager-web/src/genetics/__tests__/genetics.test.ts b/gerbil-manager-web/src/genetics/__tests__/genetics.test.ts index bd5c7ec..799eddf 100644 --- a/gerbil-manager-web/src/genetics/__tests__/genetics.test.ts +++ b/gerbil-manager-web/src/genetics/__tests__/genetics.test.ts @@ -179,8 +179,10 @@ describe('Farbschlag catalog', () => { expect(match.name).toBe('Unbekannter Farbschlag') }) - it('has the expected catalogue coverage (GEN-2: frozen 18 + 55 portal varieties)', () => { - expect(CATALOG_SIZE).toBe(73) + it('has the expected catalogue coverage (GEN-3f: 61 after cchm CP reconciliation)', () => { + // GEN-3f collapsed the 24 portal cchm colourpoint rows to 12 breeder-named + // varieties (Marder/Siam/Zobel/Zobel-Hell + CP-), so 73 -> 61. + expect(CATALOG_SIZE).toBe(61) }) it('frozen contract names round-trip to themselves (DB-key guard)', () => { @@ -206,7 +208,11 @@ describe('Farbschlag catalog', () => { expect(new Set(names).size).toBe(names.length) for (const entry of BASE_COLORS) { for (const [locus, value] of Object.entries(entry.tokens)) { - expect(LOCI[locus as LocusKey].alleles).toContain(value) + // GEN-3f: a token may be a heterozygous pair "x/y" (e.g. C: 'cchm/ch' + // for the het colourpoints Siam/Zobel-Hell) — validate each allele. + for (const allele of value.split('/')) { + expect(LOCI[locus as LocusKey].alleles).toContain(allele) + } } } }) @@ -429,3 +435,46 @@ describe('GEN-3e: C-locus colourpoint naming', () => { expect(name('aa cchmcchm DD EE GG PP Spsp rere')).toBe('Marder Schecke') }) }) + +describe('GEN-3f: CP catalog reconciled to the breeder CP- naming (matches her live data)', () => { + const name = (s: string) => genotypeToFarbschlag(fromDisplayString(s)) + const has = (n: string) => BASE_COLORS.some((e) => e.name === n) + + it('every CP- name her data uses exists as a catalog row (import name-match)', () => { + for (const n of [ + 'CP-Agouti', 'CP-Silberagouti', 'CP-Algierfuchs', 'CP-Polarfuchs', + 'CP-Fuchs', 'CP-Fuchs-Hell', 'CP-Blaufuchs', 'CP-Orangeschimmel', + 'Marder', 'Siam', 'Zobel', 'Zobel-Hell', + ]) { + expect(has(n)).toBe(true) + } + }) + + it('the removed portal suffix-names are gone (collapsed)', () => { + for (const n of [ + 'Agouti CP', 'Agouti CP-Hell', 'Silberagouti CP', 'Algierfuchs CP', + 'Polarfuchs CP', 'Blaufuchs CP', 'Kohlfuchs CP', 'Kohlfuchsschimmel CP', + 'Marder dd', 'Zobel dd', 'Siam (Marder-Hell)', 'Agouti dd CP', + ]) { + expect(has(n)).toBe(false) + } + }) + + it('the engine computes the agouti CP- names her data uses (E-family fallback covers fox/dilute)', () => { + expect(name('AA cchmcchm DD EE GG PP spsp rere')).toBe('CP-Agouti') + expect(name('AA cchmcchm DD EE gg PP spsp rere')).toBe('CP-Silberagouti') + expect(name('AA cchmcchm DD ee GG PP spsp rere')).toBe('CP-Algierfuchs') + expect(name('AA cchmcchm DD ee gg PP spsp rere')).toBe('CP-Polarfuchs') + // dd agouti fox has no dedicated base -> the eFamily fallback yields 'CP-Fuchs'. + expect(name('AA cchmcchm dd ee GG PP spsp rere')).toBe('CP-Fuchs') + // A- cchm efef -> CP-Orangeschimmel (Schimmel base under full C). + expect(name('AA cchmcchm DD efef GG PP spsp rere')).toBe('CP-Orangeschimmel') + }) + + it('het cchm/ch colourpoints (Siam, Zobel-Hell) resolve to their own names', () => { + const siam = BASE_COLORS.find((e) => e.name === 'Siam')! + const zh = BASE_COLORS.find((e) => e.name === 'Zobel-Hell')! + expect(genotypeToFarbschlag(representativeGenotype(siam))).toBe('Siam') + expect(genotypeToFarbschlag(representativeGenotype(zh))).toBe('Zobel-Hell') + }) +}) diff --git a/gerbil-manager-web/src/genetics/catalog.ts b/gerbil-manager-web/src/genetics/catalog.ts index a1e3c00..49fee37 100644 --- a/gerbil-manager-web/src/genetics/catalog.ts +++ b/gerbil-manager-web/src/genetics/catalog.ts @@ -76,8 +76,6 @@ export const BASE_COLORS: readonly FarbschlagEntry[] = [ { name: 'C-Separator', tokens: { A: 'a', C: 'C', D: 'D', E: 'e', G: 'g', P: 'p' }, image: 'c-separator.jpg' }, { name: 'Elfenbein', tokens: { A: 'A', C: 'C', D: 'D', E: 'E', G: 'g', P: 'p' }, image: 'elfenbein.jpg' }, { name: 'Kohlfuchs', tokens: { A: 'a', C: 'C', D: 'D', E: 'e', G: 'G', P: 'P' }, image: 'kohlfuchs.jpg' }, - { name: 'Marder', tokens: { A: 'a', C: 'cchm', D: 'D', E: 'E', G: 'G', P: 'P' }, image: 'marder.JPG' }, - { name: 'Siam (Marder-Hell)', tokens: { A: 'a', C: 'cchm', D: 'D', E: 'E', G: 'G', P: 'P' }, image: 'siam-marder-hell.JPG' }, { name: 'Polarfuchs', tokens: { A: 'A', C: 'C', D: 'D', E: 'e', G: 'g', P: 'P' }, image: 'polarfuchs.jpg' }, { name: 'Saphir', tokens: { A: 'a', C: 'C', D: 'D', E: 'E', G: 'G', P: 'p' }, image: 'saphir.jpg' }, // GEN-3a: efef base (otherwise wild C/D/G/P) = Orangeschimmel (breeder C5). @@ -88,48 +86,47 @@ export const BASE_COLORS: readonly FarbschlagEntry[] = [ { name: 'Silberagouti dd', tokens: { A: 'A', C: 'C', D: 'd', E: 'E', G: 'g', P: 'P' }, image: 'silberagouti-dd.jpg' }, { name: 'Kohlfuchs dd', tokens: { A: 'a', C: 'C', D: 'd', E: 'e', G: 'G', P: 'P' }, image: 'kohlfuchs-dd.jpg' }, { name: 'Anthrazit dd', tokens: { A: 'a', C: 'C', D: 'd', E: 'E', G: 'g', P: 'P' }, image: 'anthrazit-dd.jpg' }, - { name: 'Agouti CP-Hell', tokens: { A: 'A', C: 'cchm', D: 'D', E: 'E', G: 'G', P: 'P' }, image: 'agouti-cp-hell.JPG' }, - { name: 'Blaufuchs CP', tokens: { A: 'a', C: 'cchm', D: 'D', E: 'e', G: 'g', P: 'P' }, image: 'blaufuchs-cp.jpg' }, // GEN-3a: efef gg base = Silberschimmel (breeder C5) — listed before the // A-specific Polarfuchsschimmel so the canonical efef-gg reverse-matches here. { name: 'Silberschimmel', tokens: { C: 'C', D: 'D', E: 'ef', G: 'g', P: 'P' }, image: 'silberschimmel.jpg' }, { name: 'Polarfuchsschimmel', tokens: { A: 'A', C: 'C', D: 'D', E: 'ef', G: 'g', P: 'P' }, image: 'polarfuchsschimmel.jpg' }, { name: 'Algierfuchsschimmel', tokens: { A: 'A', C: 'C', D: 'D', E: 'ef', G: 'G', P: 'P' }, image: 'algierfuchsschimmel.jpg' }, - { name: 'Polarfuchs-Hell CP', tokens: { A: 'A', C: 'cchm', D: 'D', E: 'e', G: 'g', P: 'P' }, image: 'polarfuchs-hell-cp.jpg' }, { name: 'Kohlfuchsschimmel', tokens: { A: 'a', C: 'C', D: 'D', E: 'ef', G: 'G', P: 'P' }, image: 'kohlfuchsschimmel.jpg' }, { name: 'Blaufuchsschimmel', tokens: { A: 'a', C: 'C', D: 'D', E: 'ef', G: 'g', P: 'P' }, image: 'blaufuchsschimmel.jpg' }, { name: 'Kohlfuchs, hell', tokens: { A: 'a', C: 'C', D: 'D', E: 'e', G: 'G', P: 'P' }, image: 'kohlfuchs-hell.jpg' }, { name: 'Goldfuchs, hell', tokens: { A: 'A', C: 'C', D: 'D', E: 'e', G: 'G', P: 'p' }, image: 'goldfuchs-hell.jpg' }, { name: 'Goldfuchsschimmel', tokens: { A: 'A', C: 'C', D: 'D', E: 'ef', G: 'G', P: 'p' }, image: 'goldfuchsschimmel.jpg' }, { name: 'Gold-Hell', tokens: { A: 'A', C: 'C', D: 'D', E: 'E', G: 'G', P: 'p' }, image: 'gold-hell.jpg' }, - { name: 'Siam (Marder-Hell) dd', tokens: { A: 'a', C: 'cchm', D: 'd', E: 'E', G: 'G', P: 'P' }, image: 'siam-marder-hell-dd.jpg' }, - { name: 'Marder dd', tokens: { A: 'a', C: 'cchm', D: 'd', E: 'E', G: 'G', P: 'P' }, image: 'marder-dd.jpg' }, - { name: 'Zobel-Hell', tokens: { A: 'a', C: 'cchm', D: 'D', E: 'E', G: 'g', P: 'P' }, image: 'zobel-hell.jpg' }, - { name: 'Silberagouti dd CP', tokens: { A: 'A', C: 'cchm', D: 'd', E: 'E', G: 'g', P: 'P' }, image: 'silberagouti-dd-cp.jpg' }, - { name: 'Silberagouti-Hell dd CP', tokens: { A: 'A', C: 'cchm', D: 'd', E: 'E', G: 'g', P: 'P' }, image: 'silberagouti-hell-dd-cp.jpg' }, - { name: 'Agouti dd CP', tokens: { A: 'A', C: 'cchm', D: 'd', E: 'E', G: 'G', P: 'P' }, image: 'agouti-dd-cp.jpg' }, - { name: 'Agouti-Hell dd CP', tokens: { A: 'A', C: 'cchm', D: 'd', E: 'E', G: 'G', P: 'P' }, image: 'agouti-hell-dd-cp.jpg' }, { name: 'Blaufuchs, hell', tokens: { A: 'a', C: 'C', D: 'D', E: 'e', G: 'g', P: 'P' }, image: 'blaufuchs-hell.jpeg' }, { name: 'Rotfuchsschimmel', tokens: { A: 'a', C: 'C', D: 'D', E: 'ef', G: 'G', P: 'p' }, image: 'rotfuchsschimmel.jpg' }, { name: 'Polarfuchs, hell', tokens: { A: 'A', C: 'C', D: 'D', E: 'e', G: 'g', P: 'P' }, image: 'polarfuchs-hell.jpeg' }, { name: 'Kohlfuchsschimmel, hell', tokens: { A: 'a', C: 'C', D: 'D', E: 'ef', G: 'G', P: 'P' }, image: 'kohlfuchsschimmel-hell.jpg' }, { name: 'Rotfuchs, hell', tokens: { A: 'a', C: 'C', D: 'D', E: 'e', G: 'G', P: 'p' }, image: 'rotfuchs-hell.jpg' }, - { name: 'Zobel dd', tokens: { A: 'a', C: 'cchm', D: 'd', E: 'E', G: 'g', P: 'P' }, image: 'zobel-dd.jpg' }, { name: 'Kohlfuchs-Hell', tokens: { A: 'a', C: 'C', D: 'D', E: 'e', G: 'G', P: 'P' }, image: 'kohlfuchs-hell-2.jpg' }, - { name: 'Kohlfuchs CP', tokens: { A: 'a', C: 'cchm', D: 'D', E: 'e', G: 'G', P: 'P' }, image: 'kohlfuchs-cp.jpg' }, - { name: 'Algierfuchs CP', tokens: { A: 'A', C: 'cchm', D: 'D', E: 'e', G: 'G', P: 'P' }, image: 'algierfuchs-cp.jpg' }, - { name: 'Silberagouti CP', tokens: { A: 'A', C: 'cchm', D: 'D', E: 'E', G: 'g', P: 'P' }, image: 'silberagouti-cp.JPG' }, - { name: 'Agouti CP', tokens: { A: 'A', C: 'cchm', D: 'D', E: 'E', G: 'G', P: 'P' }, image: 'agouti-cp.jpg' }, - { name: 'Algierfuchs-Hell CP', tokens: { A: 'A', C: 'cchm', D: 'D', E: 'e', G: 'G', P: 'P' }, image: 'algierfuchs-hell-cp.jpg' }, - { name: 'Kohlfuchs,hell CP', tokens: { A: 'a', C: 'cchm', D: 'D', E: 'e', G: 'G', P: 'P' }, image: 'kohlfuchs-hell-cp.jpg' }, - { name: 'Polarfuchs CP', tokens: { A: 'A', C: 'cchm', D: 'D', E: 'e', G: 'g', P: 'P' }, image: 'polarfuchs-cp.jpg' }, { name: 'Algierfuchs, hell', tokens: { A: 'A', C: 'C', D: 'D', E: 'e', G: 'G', P: 'P' }, image: 'algierfuchs-hell.JPG' }, { name: 'Topas dd', tokens: { A: 'A', C: 'C', D: 'd', E: 'E', G: 'G', P: 'p' }, image: 'topas-dd.jpg' }, - { name: 'Zobel-Hell dd', tokens: { A: 'a', C: 'cchm', D: 'd', E: 'E', G: 'g', P: 'P' }, image: 'zobel-hell-dd.jpg' }, - { name: 'Kohlfuchsschimmel CP', tokens: { A: 'a', C: 'cchm', D: 'D', E: 'ef', G: 'G', P: 'P' }, image: 'kohlfuchsschimmel-cp.JPG' }, { name: 'Blaufuchs dd', tokens: { A: 'a', C: 'C', D: 'd', E: 'e', G: 'g', P: 'p' }, image: 'blaufuchs-dd.jpg' }, - // GEN-3a: c[chm]c[chm] efef base = CP-Orangeschimmel (breeder C5). A unspecified - // (listed after the A-specific cchm-Schimmel entries so they win for those). + + // ── GEN-3f: c^chm colourpoint varieties, reconciled to the breeder's CP- naming ── + // The merged GEN-3e colourpointName() rule is authoritative: aa points are the + // marten/sable group (Marder/Siam, +gg Zobel/Zobel-Hell — E and D irrelevant); + // A- points take the 'CP-' prefix and the '-Hell' shade variants + // collapse (other loci irrelevant for the CP prefix). These names == the strings + // in her live data (god: extract animals.json) so the re-import name-matches and + // the Farbschlag mismatch hint stops. The het cchm/ch points (Siam, Zobel-Hell, + // CP-Fuchs-Hell) use the 'cchm/ch' pair token. The agouti fox/dilute points + // (CP-Fuchs/CP-Blaufuchs) resolve through the engine's E-family fallback to + // 'CP-Fuchs'; their distinct dropdown names remain for hand-pick + import match. + { name: 'Marder', tokens: { A: 'a', C: 'cchm', D: 'D', E: 'E', G: 'G', P: 'P' }, image: 'marder.JPG' }, + { name: 'Siam', tokens: { A: 'a', C: 'cchm/ch', D: 'D', E: 'E', G: 'G', P: 'P' }, image: 'siam-marder-hell.JPG' }, + { name: 'Zobel-Hell', tokens: { A: 'a', C: 'cchm/ch', D: 'D', E: 'E', G: 'g', P: 'P' }, image: 'zobel-hell.jpg' }, + { name: 'CP-Agouti', tokens: { A: 'A', C: 'cchm', D: 'D', E: 'E', G: 'G', P: 'P' }, image: 'agouti-cp.jpg' }, + { name: 'CP-Silberagouti', tokens: { A: 'A', C: 'cchm', D: 'D', E: 'E', G: 'g', P: 'P' }, image: 'silberagouti-cp.JPG' }, + { name: 'CP-Algierfuchs', tokens: { A: 'A', C: 'cchm', D: 'D', E: 'e', G: 'G', P: 'P' }, image: 'algierfuchs-cp.jpg' }, + { name: 'CP-Polarfuchs', tokens: { A: 'A', C: 'cchm', D: 'D', E: 'e', G: 'g', P: 'P' }, image: 'polarfuchs-cp.jpg' }, + { name: 'CP-Fuchs', tokens: { A: 'A', C: 'cchm', D: 'd', E: 'e', G: 'G', P: 'P' } }, + { name: 'CP-Fuchs-Hell', tokens: { A: 'A', C: 'cchm/ch', D: 'd', E: 'e', G: 'G', P: 'P' } }, + { name: 'CP-Blaufuchs', tokens: { A: 'A', C: 'cchm', D: 'd', E: 'e', G: 'g', P: 'P' } }, { name: 'CP-Orangeschimmel', tokens: { C: 'cchm', D: 'D', E: 'ef', G: 'G', P: 'P' } }, ] @@ -270,7 +267,14 @@ export function representativeGenotype(entry: FarbschlagEntry): Genotype { const out = {} as Record for (const locus of LOCUS_ORDER) { const token = entry.tokens[locus] - out[locus] = token ? [token, token] : base[locus] + if (!token) { + out[locus] = base[locus] + continue + } + // GEN-3f: a token may encode a HETEROZYGOUS pair as "x/y" (e.g. the het + // colourpoints Siam/Zobel-Hell use C: 'cchm/ch'); otherwise it's homozygous. + const [a, b] = token.includes('/') ? (token.split('/') as [string, string]) : [token, token] + out[locus] = [a, b] } return makeGenotype(out) } diff --git a/gerbil-manager-web/src/genetics/colorVarietySeed.generated.json b/gerbil-manager-web/src/genetics/colorVarietySeed.generated.json index 6591f1f..386c585 100644 --- a/gerbil-manager-web/src/genetics/colorVarietySeed.generated.json +++ b/gerbil-manager-web/src/genetics/colorVarietySeed.generated.json @@ -154,303 +154,228 @@ "sortOrder": 22, "image": "kohlfuchs.jpg" }, - { - "name": "Marder", - "canonicalGenotype": "aa cchmcchm DD EE GG PP spsp rere", - "sortOrder": 23, - "image": "marder.JPG" - }, - { - "name": "Siam (Marder-Hell)", - "canonicalGenotype": "aa cchmcchm DD EE GG PP spsp rere", - "sortOrder": 24, - "image": "siam-marder-hell.JPG" - }, { "name": "Polarfuchs", "canonicalGenotype": "AA CC DD ee gg PP spsp rere", - "sortOrder": 25, + "sortOrder": 23, "image": "polarfuchs.jpg" }, { "name": "Saphir", "canonicalGenotype": "aa CC DD EE GG pp spsp rere", - "sortOrder": 26, + "sortOrder": 24, "image": "saphir.jpg" }, { "name": "Orangeschimmel", "canonicalGenotype": "AA CC DD efef GG PP spsp rere", - "sortOrder": 27, + "sortOrder": 25, "image": "schimmel-orangeschimmel.jpg" }, { "name": "Topas", "canonicalGenotype": "AA CC DD EE GG pp spsp rere", - "sortOrder": 28, + "sortOrder": 26, "image": "topas.jpg" }, { "name": "Platin-Hell", "canonicalGenotype": "aa CC DD EE GG pp spsp rere", - "sortOrder": 29, + "sortOrder": 27, "image": "platin-hell.jpg" }, { "name": "Agouti dd", "canonicalGenotype": "AA CC dd EE GG PP spsp rere", - "sortOrder": 30, + "sortOrder": 28, "image": "agouti-dd.jpg" }, { "name": "Silberagouti dd", "canonicalGenotype": "AA CC dd EE gg PP spsp rere", - "sortOrder": 31, + "sortOrder": 29, "image": "silberagouti-dd.jpg" }, { "name": "Kohlfuchs dd", "canonicalGenotype": "aa CC dd ee GG PP spsp rere", - "sortOrder": 32, + "sortOrder": 30, "image": "kohlfuchs-dd.jpg" }, { "name": "Anthrazit dd", "canonicalGenotype": "aa CC dd EE gg PP spsp rere", - "sortOrder": 33, + "sortOrder": 31, "image": "anthrazit-dd.jpg" }, - { - "name": "Agouti CP-Hell", - "canonicalGenotype": "AA cchmcchm DD EE GG PP spsp rere", - "sortOrder": 34, - "image": "agouti-cp-hell.JPG" - }, - { - "name": "Blaufuchs CP", - "canonicalGenotype": "aa cchmcchm DD ee gg PP spsp rere", - "sortOrder": 35, - "image": "blaufuchs-cp.jpg" - }, { "name": "Silberschimmel", "canonicalGenotype": "AA CC DD efef gg PP spsp rere", - "sortOrder": 36, + "sortOrder": 32, "image": "silberschimmel.jpg" }, { "name": "Polarfuchsschimmel", "canonicalGenotype": "AA CC DD efef gg PP spsp rere", - "sortOrder": 37, + "sortOrder": 33, "image": "polarfuchsschimmel.jpg" }, { "name": "Algierfuchsschimmel", "canonicalGenotype": "AA CC DD efef GG PP spsp rere", - "sortOrder": 38, + "sortOrder": 34, "image": "algierfuchsschimmel.jpg" }, - { - "name": "Polarfuchs-Hell CP", - "canonicalGenotype": "AA cchmcchm DD ee gg PP spsp rere", - "sortOrder": 39, - "image": "polarfuchs-hell-cp.jpg" - }, { "name": "Kohlfuchsschimmel", "canonicalGenotype": "aa CC DD efef GG PP spsp rere", - "sortOrder": 40, + "sortOrder": 35, "image": "kohlfuchsschimmel.jpg" }, { "name": "Blaufuchsschimmel", "canonicalGenotype": "aa CC DD efef gg PP spsp rere", - "sortOrder": 41, + "sortOrder": 36, "image": "blaufuchsschimmel.jpg" }, { "name": "Kohlfuchs, hell", "canonicalGenotype": "aa CC DD ee GG PP spsp rere", - "sortOrder": 42, + "sortOrder": 37, "image": "kohlfuchs-hell.jpg" }, { "name": "Goldfuchs, hell", "canonicalGenotype": "AA CC DD ee GG pp spsp rere", - "sortOrder": 43, + "sortOrder": 38, "image": "goldfuchs-hell.jpg" }, { "name": "Goldfuchsschimmel", "canonicalGenotype": "AA CC DD efef GG pp spsp rere", - "sortOrder": 44, + "sortOrder": 39, "image": "goldfuchsschimmel.jpg" }, { "name": "Gold-Hell", "canonicalGenotype": "AA CC DD EE GG pp spsp rere", - "sortOrder": 45, + "sortOrder": 40, "image": "gold-hell.jpg" }, - { - "name": "Siam (Marder-Hell) dd", - "canonicalGenotype": "aa cchmcchm dd EE GG PP spsp rere", - "sortOrder": 46, - "image": "siam-marder-hell-dd.jpg" - }, - { - "name": "Marder dd", - "canonicalGenotype": "aa cchmcchm dd EE GG PP spsp rere", - "sortOrder": 47, - "image": "marder-dd.jpg" - }, - { - "name": "Zobel-Hell", - "canonicalGenotype": "aa cchmcchm DD EE gg PP spsp rere", - "sortOrder": 48, - "image": "zobel-hell.jpg" - }, - { - "name": "Silberagouti dd CP", - "canonicalGenotype": "AA cchmcchm dd EE gg PP spsp rere", - "sortOrder": 49, - "image": "silberagouti-dd-cp.jpg" - }, - { - "name": "Silberagouti-Hell dd CP", - "canonicalGenotype": "AA cchmcchm dd EE gg PP spsp rere", - "sortOrder": 50, - "image": "silberagouti-hell-dd-cp.jpg" - }, - { - "name": "Agouti dd CP", - "canonicalGenotype": "AA cchmcchm dd EE GG PP spsp rere", - "sortOrder": 51, - "image": "agouti-dd-cp.jpg" - }, - { - "name": "Agouti-Hell dd CP", - "canonicalGenotype": "AA cchmcchm dd EE GG PP spsp rere", - "sortOrder": 52, - "image": "agouti-hell-dd-cp.jpg" - }, { "name": "Blaufuchs, hell", "canonicalGenotype": "aa CC DD ee gg PP spsp rere", - "sortOrder": 53, + "sortOrder": 41, "image": "blaufuchs-hell.jpeg" }, { "name": "Rotfuchsschimmel", "canonicalGenotype": "aa CC DD efef GG pp spsp rere", - "sortOrder": 54, + "sortOrder": 42, "image": "rotfuchsschimmel.jpg" }, { "name": "Polarfuchs, hell", "canonicalGenotype": "AA CC DD ee gg PP spsp rere", - "sortOrder": 55, + "sortOrder": 43, "image": "polarfuchs-hell.jpeg" }, { "name": "Kohlfuchsschimmel, hell", "canonicalGenotype": "aa CC DD efef GG PP spsp rere", - "sortOrder": 56, + "sortOrder": 44, "image": "kohlfuchsschimmel-hell.jpg" }, { "name": "Rotfuchs, hell", "canonicalGenotype": "aa CC DD ee GG pp spsp rere", - "sortOrder": 57, + "sortOrder": 45, "image": "rotfuchs-hell.jpg" }, - { - "name": "Zobel dd", - "canonicalGenotype": "aa cchmcchm dd EE gg PP spsp rere", - "sortOrder": 58, - "image": "zobel-dd.jpg" - }, { "name": "Kohlfuchs-Hell", "canonicalGenotype": "aa CC DD ee GG PP spsp rere", - "sortOrder": 59, + "sortOrder": 46, "image": "kohlfuchs-hell-2.jpg" }, - { - "name": "Kohlfuchs CP", - "canonicalGenotype": "aa cchmcchm DD ee GG PP spsp rere", - "sortOrder": 60, - "image": "kohlfuchs-cp.jpg" - }, - { - "name": "Algierfuchs CP", - "canonicalGenotype": "AA cchmcchm DD ee GG PP spsp rere", - "sortOrder": 61, - "image": "algierfuchs-cp.jpg" - }, - { - "name": "Silberagouti CP", - "canonicalGenotype": "AA cchmcchm DD EE gg PP spsp rere", - "sortOrder": 62, - "image": "silberagouti-cp.JPG" - }, - { - "name": "Agouti CP", - "canonicalGenotype": "AA cchmcchm DD EE GG PP spsp rere", - "sortOrder": 63, - "image": "agouti-cp.jpg" - }, - { - "name": "Algierfuchs-Hell CP", - "canonicalGenotype": "AA cchmcchm DD ee GG PP spsp rere", - "sortOrder": 64, - "image": "algierfuchs-hell-cp.jpg" - }, - { - "name": "Kohlfuchs,hell CP", - "canonicalGenotype": "aa cchmcchm DD ee GG PP spsp rere", - "sortOrder": 65, - "image": "kohlfuchs-hell-cp.jpg" - }, - { - "name": "Polarfuchs CP", - "canonicalGenotype": "AA cchmcchm DD ee gg PP spsp rere", - "sortOrder": 66, - "image": "polarfuchs-cp.jpg" - }, { "name": "Algierfuchs, hell", "canonicalGenotype": "AA CC DD ee GG PP spsp rere", - "sortOrder": 67, + "sortOrder": 47, "image": "algierfuchs-hell.JPG" }, { "name": "Topas dd", "canonicalGenotype": "AA CC dd EE GG pp spsp rere", - "sortOrder": 68, + "sortOrder": 48, "image": "topas-dd.jpg" }, - { - "name": "Zobel-Hell dd", - "canonicalGenotype": "aa cchmcchm dd EE gg PP spsp rere", - "sortOrder": 69, - "image": "zobel-hell-dd.jpg" - }, - { - "name": "Kohlfuchsschimmel CP", - "canonicalGenotype": "aa cchmcchm DD efef GG PP spsp rere", - "sortOrder": 70, - "image": "kohlfuchsschimmel-cp.JPG" - }, { "name": "Blaufuchs dd", "canonicalGenotype": "aa CC dd ee gg pp spsp rere", - "sortOrder": 71, + "sortOrder": 49, "image": "blaufuchs-dd.jpg" }, + { + "name": "Marder", + "canonicalGenotype": "aa cchmcchm DD EE GG PP spsp rere", + "sortOrder": 50, + "image": "marder.JPG" + }, + { + "name": "Siam", + "canonicalGenotype": "aa cchmch DD EE GG PP spsp rere", + "sortOrder": 51, + "image": "siam-marder-hell.JPG" + }, + { + "name": "Zobel-Hell", + "canonicalGenotype": "aa cchmch DD EE gg PP spsp rere", + "sortOrder": 52, + "image": "zobel-hell.jpg" + }, + { + "name": "CP-Agouti", + "canonicalGenotype": "AA cchmcchm DD EE GG PP spsp rere", + "sortOrder": 53, + "image": "agouti-cp.jpg" + }, + { + "name": "CP-Silberagouti", + "canonicalGenotype": "AA cchmcchm DD EE gg PP spsp rere", + "sortOrder": 54, + "image": "silberagouti-cp.JPG" + }, + { + "name": "CP-Algierfuchs", + "canonicalGenotype": "AA cchmcchm DD ee GG PP spsp rere", + "sortOrder": 55, + "image": "algierfuchs-cp.jpg" + }, + { + "name": "CP-Polarfuchs", + "canonicalGenotype": "AA cchmcchm DD ee gg PP spsp rere", + "sortOrder": 56, + "image": "polarfuchs-cp.jpg" + }, + { + "name": "CP-Fuchs", + "canonicalGenotype": "AA cchmcchm dd ee GG PP spsp rere", + "sortOrder": 57 + }, + { + "name": "CP-Fuchs-Hell", + "canonicalGenotype": "AA cchmch dd ee GG PP spsp rere", + "sortOrder": 58 + }, + { + "name": "CP-Blaufuchs", + "canonicalGenotype": "AA cchmcchm dd ee gg PP spsp rere", + "sortOrder": 59 + }, { "name": "CP-Orangeschimmel", "canonicalGenotype": "AA cchmcchm DD efef GG PP spsp rere", - "sortOrder": 72 + "sortOrder": 60 } ]