@xivdyetools/core 5.1.0 → 5.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/NOTICE +26 -0
  2. package/README.md +57 -10
  3. package/dist/data/locales/de.json +8 -1
  4. package/dist/data/locales/en.json +8 -1
  5. package/dist/data/locales/fr.json +8 -1
  6. package/dist/data/locales/ja.json +8 -1
  7. package/dist/data/locales/ko.json +8 -1
  8. package/dist/data/locales/zh.json +8 -1
  9. package/dist/data/munsell-hues.json +175 -0
  10. package/dist/data/oklch-hue-table.json +297 -0
  11. package/dist/index.d.ts +18 -1
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +9 -0
  14. package/dist/index.js.map +1 -1
  15. package/dist/services/CharacterColorService.d.ts +1 -1
  16. package/dist/services/CharacterColorService.d.ts.map +1 -1
  17. package/dist/services/DyeService.d.ts +35 -0
  18. package/dist/services/DyeService.d.ts.map +1 -1
  19. package/dist/services/DyeService.js +35 -0
  20. package/dist/services/DyeService.js.map +1 -1
  21. package/dist/services/LocalizationService.d.ts +5 -1
  22. package/dist/services/LocalizationService.d.ts.map +1 -1
  23. package/dist/services/LocalizationService.js +8 -0
  24. package/dist/services/LocalizationService.js.map +1 -1
  25. package/dist/services/color/ColorConverter.d.ts +39 -0
  26. package/dist/services/color/ColorConverter.d.ts.map +1 -1
  27. package/dist/services/color/ColorConverter.js +173 -22
  28. package/dist/services/color/ColorConverter.js.map +1 -1
  29. package/dist/services/dye/DyeDatabase.d.ts +10 -1
  30. package/dist/services/dye/DyeDatabase.d.ts.map +1 -1
  31. package/dist/services/dye/DyeDatabase.js +34 -2
  32. package/dist/services/dye/DyeDatabase.js.map +1 -1
  33. package/dist/services/dye/HarmonyGenerator.d.ts +20 -0
  34. package/dist/services/dye/HarmonyGenerator.d.ts.map +1 -1
  35. package/dist/services/dye/HarmonyGenerator.js +11 -1
  36. package/dist/services/dye/HarmonyGenerator.js.map +1 -1
  37. package/dist/services/dye/HarmonySelector.d.ts +15 -1
  38. package/dist/services/dye/HarmonySelector.d.ts.map +1 -1
  39. package/dist/services/dye/HarmonySelector.js +20 -8
  40. package/dist/services/dye/HarmonySelector.js.map +1 -1
  41. package/dist/services/dye/wheels/ColorWheel.d.ts +29 -0
  42. package/dist/services/dye/wheels/ColorWheel.d.ts.map +1 -0
  43. package/dist/services/dye/wheels/ColorWheel.js +63 -0
  44. package/dist/services/dye/wheels/ColorWheel.js.map +1 -0
  45. package/dist/services/dye/wheels/hue-warp.d.ts +40 -0
  46. package/dist/services/dye/wheels/hue-warp.d.ts.map +1 -0
  47. package/dist/services/dye/wheels/hue-warp.js +144 -0
  48. package/dist/services/dye/wheels/hue-warp.js.map +1 -0
  49. package/dist/services/dye/wheels/munsell.d.ts +17 -0
  50. package/dist/services/dye/wheels/munsell.d.ts.map +1 -0
  51. package/dist/services/dye/wheels/munsell.js +18 -0
  52. package/dist/services/dye/wheels/munsell.js.map +1 -0
  53. package/dist/services/dye/wheels/oklch-hue.d.ts +22 -0
  54. package/dist/services/dye/wheels/oklch-hue.d.ts.map +1 -0
  55. package/dist/services/dye/wheels/oklch-hue.js +23 -0
  56. package/dist/services/dye/wheels/oklch-hue.js.map +1 -0
  57. package/dist/services/dye/wheels/oklch-lightness.d.ts +24 -0
  58. package/dist/services/dye/wheels/oklch-lightness.d.ts.map +1 -0
  59. package/dist/services/dye/wheels/oklch-lightness.js +65 -0
  60. package/dist/services/dye/wheels/oklch-lightness.js.map +1 -0
  61. package/dist/services/dye/wheels/rgb-ryb.d.ts +18 -0
  62. package/dist/services/dye/wheels/rgb-ryb.d.ts.map +1 -0
  63. package/dist/services/dye/wheels/rgb-ryb.js +47 -0
  64. package/dist/services/dye/wheels/rgb-ryb.js.map +1 -0
  65. package/dist/services/dye/wheels/types.d.ts +40 -0
  66. package/dist/services/dye/wheels/types.d.ts.map +1 -0
  67. package/dist/services/dye/wheels/types.js +11 -0
  68. package/dist/services/dye/wheels/types.js.map +1 -0
  69. package/dist/services/localization/LocaleLoader.d.ts +8 -0
  70. package/dist/services/localization/LocaleLoader.d.ts.map +1 -1
  71. package/dist/services/localization/LocaleLoader.js +8 -0
  72. package/dist/services/localization/LocaleLoader.js.map +1 -1
  73. package/dist/services/localization/LocaleRegistry.d.ts +9 -0
  74. package/dist/services/localization/LocaleRegistry.d.ts.map +1 -1
  75. package/dist/services/localization/LocaleRegistry.js +9 -0
  76. package/dist/services/localization/LocaleRegistry.js.map +1 -1
  77. package/dist/services/localization/TranslationProvider.d.ts +6 -1
  78. package/dist/services/localization/TranslationProvider.d.ts.map +1 -1
  79. package/dist/services/localization/TranslationProvider.js +8 -0
  80. package/dist/services/localization/TranslationProvider.js.map +1 -1
  81. package/package.json +13 -8
package/NOTICE ADDED
@@ -0,0 +1,26 @@
1
+ Third-party data notices for @xivdyetools/core
2
+ ==============================================
3
+
4
+ Munsell hue-wheel data
5
+ ----------------------
6
+ The Munsell hue-angle table in src/data/munsell-hues.json is derived from
7
+ the Munsell renotation data (real.dat) published by the Munsell Color
8
+ Science Laboratory / Program of Color Science, Rochester Institute of
9
+ Technology:
10
+ https://www.rit.edu/science/munsell-color-science-lab-educational-resources
11
+ which in turn reproduces the tables of Newhall, S. M., Nickerson, D., &
12
+ Judd, D. B. (1943). "Final Report of the O.S.A. Subcommittee on the
13
+ Spacing of the Munsell Colors." JOSA 33(7), 385-418.
14
+ doi:10.1364/JOSA.33.000385
15
+
16
+ Only 40 derived hue-angle pairs (Value 6 / Chroma 8) are shipped; the
17
+ renotation dataset itself is not redistributed. sRGB values were
18
+ cross-checked against the R package `munsell`
19
+ (https://github.com/cwickham/munsell), Copyright (c) 2016 Charlotte
20
+ Wickham, MIT licence, and against munsell.js (MPL-2.0) as a development-time
21
+ oracle.
22
+
23
+ These values are computed colorimetric renotations, not measurements of
24
+ any physical Munsell Book of Color, and are not endorsed by or affiliated
25
+ with X-Rite, Pantone or Amazys Holding GmbH. MUNSELL is a registered
26
+ trademark (USPTO Reg. No. 1570854) of Amazys Holding GmbH.
package/README.md CHANGED
@@ -86,7 +86,7 @@ const harmonyDyes = dyeService.findComplementaryPair(baseDye.hex);
86
86
 
87
87
  Pure color conversion and manipulation algorithms.
88
88
 
89
- > **Memory Note**: ColorService uses LRU caches (5 caches × 1000 entries each = up to 5000 cached entries) for performance optimization. For long-running applications or memory-constrained environments, call `ColorService.clearCaches()` periodically to free memory. Each cache entry is approximately 50-100 bytes, so maximum memory usage is ~500KB.
89
+ > **Memory Note**: ColorService uses LRU caches (7 caches × 1000 entries each = up to 7000 cached entries — `hexToRgb`, `rgbToHex`, `rgbToHsv`, `hsvToRgb`, `hexToHsv`, `rgbToLab`, `rgbToOklab`) for performance optimization. For long-running applications or memory-constrained environments, call `ColorService.clearCaches()` periodically to free memory. Each cache entry is approximately 50-100 bytes, so maximum memory usage is ~700KB.
90
90
 
91
91
  ```typescript
92
92
  import { ColorService } from '@xivdyetools/core';
@@ -145,7 +145,8 @@ const dyeService = new DyeService(dyeDatabase);
145
145
  const allDyes = dyeService.getAllDyes(); // 125 dyes
146
146
  const dyeById = dyeService.getDyeById(13115); // By itemID (= Dye.id) - Jet Black; prefer getByStainId(102)
147
147
  const dyeByStain = dyeService.getByStainId(1); // By stainID (canonical key) - Snow White
148
- const categories = dyeService.getCategories(); // ['Neutral', 'Red', 'Blue', ...]
148
+ const categories = dyeService.getCategories();
149
+ // ['Neutral', 'Reds', 'Browns', 'Yellows', 'Greens', 'Blues', 'Purples', 'Special']
149
150
 
150
151
  // Color matching — matchingMethod is one of the 5.0 suite:
151
152
  // 'ciede2000' (default) | 'oklab' | 'cie76' | 'redmean' | 'rgb' | 'distinguish'
@@ -166,14 +167,13 @@ const triadicDeltaE = dyeService.findTriadicDyes('#FF6B6B', {
166
167
  deltaEFormula: 'ciede2000', // the default since 5.1.0; 'cie76' is faster, 'cie2000' a legacy alias
167
168
  });
168
169
 
169
- // Color space selection for hue rotation
170
- // OKLCH produces more perceptually balanced harmonies
171
- const triadicOklch = dyeService.findTriadicDyes('#FF6B6B', { colorSpace: 'oklch' });
172
- const compLch = dyeService.findComplementaryPair('#FF6B6B', { colorSpace: 'lch' });
173
- // Available spaces: 'hsv' (default), 'oklch', 'lch', 'hsl'
170
+ // DEPRECATED since 5.2.0: HarmonyOptions.colorSpace ('hsv' | 'oklch' | 'lch' | 'hsl').
171
+ // It rotates hue WITHOUT carrying the base's saturation and value, which is a
172
+ // different answer from the one every surface shows. Use `generateHarmonySlots`
173
+ // with a `wheel` instead (see "Colour wheels" below).
174
174
 
175
175
  // Filtering
176
- const redDyes = dyeService.searchByCategory('Red');
176
+ const redDyes = dyeService.searchByCategory('Reds'); // exact match against DYE_CATEGORIES
177
177
  const searchResults = dyeService.searchByName('black');
178
178
  const filtered = dyeService.filterDyes({
179
179
  category: 'Special',
@@ -183,6 +183,50 @@ const filtered = dyeService.filterDyes({
183
183
  });
184
184
  ```
185
185
 
186
+ #### Colour wheels
187
+
188
+ Harmony slot selection goes through `generateHarmonySlots(baseHex, harmonyType, candidates, config, options?)` — the one implementation the web app, the Discord bot and the OG card share. `config.wheel` chooses which wheel the offsets are measured on; `'rgb'` is the default and is today's behaviour bit for bit.
189
+
190
+ ```typescript
191
+ import {
192
+ generateHarmonySlots,
193
+ COLOR_WHEEL_IDS, // ['rgb', 'ryb', 'munsell', 'oklch-hue', 'oklch-lightness']
194
+ DEFAULT_COLOR_WHEEL, // 'rgb'
195
+ getColorWheel,
196
+ normalizeColorWheelId,
197
+ HARMONY_OFFSETS,
198
+ isKnownHarmonyType,
199
+ DyeService,
200
+ dyeDatabase,
201
+ } from '@xivdyetools/core';
202
+
203
+ const dyeService = new DyeService(dyeDatabase);
204
+
205
+ const slots = generateHarmonySlots(
206
+ '#FF6B6B',
207
+ 'triadic', // any key of HARMONY_OFFSETS (10 of them)
208
+ dyeService.getAllDyes(), // callers pre-filter the candidate pool
209
+ {
210
+ usePerceptualMatching: true,
211
+ matchingMethod: 'ciede2000',
212
+ wheel: 'ryb',
213
+ companionCount: 2,
214
+ preventDuplicates: true,
215
+ },
216
+ );
217
+ // HarmonySlot[]: { index, offset, targetHue, wheelHue, targetHex, dye, deviance, companions }
218
+ ```
219
+
220
+ Read the wheel list from `COLOR_WHEEL_IDS` and normalise anything arriving off
221
+ the wire with `normalizeColorWheelId(value)` (or `parseColorWheelId` when
222
+ "unknown" must stay distinguishable from `'rgb'`) — never hand-roll a
223
+ `toLowerCase()` + membership test. `getColorWheel(id)` returns the `ColorWheel`
224
+ itself (`hueOf`, `target`, `ringStops`, `carriesBaseHsv`).
225
+
226
+ `oklch-lightness` keeps the base's OKLab L and C rather than its HSV S/V
227
+ (`carriesBaseHsv === false`), so the selector forces ΔE ranking for it whatever
228
+ `usePerceptualMatching` says.
229
+
186
230
  ### PaletteService
187
231
 
188
232
  Multi-color palette extraction from images using K-means++ clustering.
@@ -390,7 +434,7 @@ Since **Patch 7.5**, 105 of the 125 dyes share three consolidated market itemIDs
390
434
 
391
435
  ## Requirements
392
436
 
393
- - **Node.js** 22.0.0 or higher
437
+ - **Node.js** 18.0.0 or higher (`engines.node: ">=18.0.0"`)
394
438
  - **TypeScript** 5.9 or higher (for development)
395
439
 
396
440
  ## Browser Compatibility
@@ -408,9 +452,10 @@ This package lives in the [xivdyetools monorepo](https://github.com/FlashGalatin
408
452
  - [`apps/discord-worker`](../../apps/discord-worker/) — Cloudflare Worker Discord bot
409
453
  - [`apps/api-worker`](../../apps/api-worker/) — public REST API
410
454
  - [`apps/og-worker`](../../apps/og-worker/) — OpenGraph cards (stateless localization trio)
411
- - [`apps/stoat-worker`](../../apps/stoat-worker/) — Revolt bot (parked)
412
455
  - [`@xivdyetools/svg`](../svg/), [`@xivdyetools/bot-logic`](../bot-logic/)
413
456
 
457
+ (`apps/stoat-worker` reaches core only indirectly, through `@xivdyetools/bot-logic`.)
458
+
414
459
  ## Support
415
460
 
416
461
  - **Issues**: [GitHub Issues](https://github.com/FlashGalatine/xivdyetools/issues)
@@ -442,6 +487,8 @@ This package lives in the [xivdyetools monorepo](https://github.com/FlashGalatin
442
487
 
443
488
  MIT © 2025-2026 Flash Galatine — see [LICENSE](./LICENSE).
444
489
 
490
+ Third-party data attributions (the Munsell hue wheel) are in [NOTICE](./NOTICE).
491
+
445
492
  ## Legal Notice
446
493
 
447
494
  **FINAL FANTASY is a registered trademark of Square Enix Holdings Co., Ltd.**
@@ -2,7 +2,7 @@
2
2
  "locale": "de",
3
3
  "meta": {
4
4
  "version": "1.0.0",
5
- "generated": "2026-09-03T12:01:42.834Z",
5
+ "generated": "2026-09-05T13:38:20.760Z",
6
6
  "dyeCount": 125
7
7
  },
8
8
  "labels": {
@@ -186,6 +186,13 @@
186
186
  "compound": "Zusammengesetzt",
187
187
  "shades": "Schattierungen"
188
188
  },
189
+ "colorWheels": {
190
+ "rgb": "RGB (Bildschirm)",
191
+ "ryb": "RYB (Malerfarbkreis)",
192
+ "munsell": "Munsell (JIS)",
193
+ "oklch-hue": "OKLCH-Farbton (wahrnehmungsgleiche Abstände)",
194
+ "oklch-lightness": "OKLCH-Helligkeit (behält die Helligkeit)"
195
+ },
189
196
  "visionTypes": {
190
197
  "normal": "Normales Sehen",
191
198
  "deuteranopia": "Deuteranopie (Rot-Grün-Farbenblindheit)",
@@ -2,7 +2,7 @@
2
2
  "locale": "en",
3
3
  "meta": {
4
4
  "version": "1.0.0",
5
- "generated": "2026-09-03T12:01:42.830Z",
5
+ "generated": "2026-09-05T13:38:20.756Z",
6
6
  "dyeCount": 125
7
7
  },
8
8
  "labels": {
@@ -186,6 +186,13 @@
186
186
  "compound": "Compound",
187
187
  "shades": "Shades"
188
188
  },
189
+ "colorWheels": {
190
+ "rgb": "RGB (screen)",
191
+ "ryb": "RYB (artist's)",
192
+ "munsell": "Munsell (JIS)",
193
+ "oklch-hue": "OKLCH hue (perceptual spacing)",
194
+ "oklch-lightness": "OKLCH lightness (keeps brightness)"
195
+ },
189
196
  "visionTypes": {
190
197
  "normal": "Normal Vision",
191
198
  "deuteranopia": "Deuteranopia (Red-Green Colorblindness)",
@@ -2,7 +2,7 @@
2
2
  "locale": "fr",
3
3
  "meta": {
4
4
  "version": "1.0.0",
5
- "generated": "2026-09-03T12:01:42.835Z",
5
+ "generated": "2026-09-05T13:38:20.761Z",
6
6
  "dyeCount": 125
7
7
  },
8
8
  "labels": {
@@ -186,6 +186,13 @@
186
186
  "compound": "Composé",
187
187
  "shades": "Nuances"
188
188
  },
189
+ "colorWheels": {
190
+ "rgb": "RVB (écran)",
191
+ "ryb": "RJB (roue des peintres)",
192
+ "munsell": "Munsell (JIS)",
193
+ "oklch-hue": "Teinte OKLCH (espacement perceptuel)",
194
+ "oklch-lightness": "Luminosité OKLCH (conserve la luminosité)"
195
+ },
189
196
  "visionTypes": {
190
197
  "normal": "Vision normale",
191
198
  "deuteranopia": "Deutéranopie (Daltonisme rouge-vert)",
@@ -2,7 +2,7 @@
2
2
  "locale": "ja",
3
3
  "meta": {
4
4
  "version": "1.0.0",
5
- "generated": "2026-09-03T12:01:42.833Z",
5
+ "generated": "2026-09-05T13:38:20.759Z",
6
6
  "dyeCount": 125
7
7
  },
8
8
  "labels": {
@@ -186,6 +186,13 @@
186
186
  "compound": "複合",
187
187
  "shades": "シェード"
188
188
  },
189
+ "colorWheels": {
190
+ "rgb": "RGB(画面)",
191
+ "ryb": "RYB(画家の色相環)",
192
+ "munsell": "マンセル(JIS)",
193
+ "oklch-hue": "OKLCH 色相(知覚的な間隔)",
194
+ "oklch-lightness": "OKLCH 明度(明るさを保持)"
195
+ },
189
196
  "visionTypes": {
190
197
  "normal": "正常視覚",
191
198
  "deuteranopia": "2型色覚(赤緑色盲)",
@@ -2,7 +2,7 @@
2
2
  "locale": "ko",
3
3
  "meta": {
4
4
  "version": "1.0.0",
5
- "generated": "2026-09-03T12:01:42.836Z",
5
+ "generated": "2026-09-05T13:38:20.762Z",
6
6
  "dyeCount": 125
7
7
  },
8
8
  "labels": {
@@ -186,6 +186,13 @@
186
186
  "compound": "복합",
187
187
  "shades": "명암"
188
188
  },
189
+ "colorWheels": {
190
+ "rgb": "RGB (화면)",
191
+ "ryb": "RYB (화가의 색상환)",
192
+ "munsell": "먼셀 (JIS)",
193
+ "oklch-hue": "OKLCH 색상 (지각적 간격)",
194
+ "oklch-lightness": "OKLCH 명도 (밝기 유지)"
195
+ },
189
196
  "visionTypes": {
190
197
  "normal": "정상 시력",
191
198
  "deuteranopia": "제2색맹 (적록색맹)",
@@ -2,7 +2,7 @@
2
2
  "locale": "zh",
3
3
  "meta": {
4
4
  "version": "1.0.0",
5
- "generated": "2026-09-03T12:01:42.837Z",
5
+ "generated": "2026-09-05T13:38:20.763Z",
6
6
  "dyeCount": 125
7
7
  },
8
8
  "labels": {
@@ -186,6 +186,13 @@
186
186
  "compound": "复合",
187
187
  "shades": "明暗"
188
188
  },
189
+ "colorWheels": {
190
+ "rgb": "RGB(屏幕)",
191
+ "ryb": "RYB(画家色环)",
192
+ "munsell": "孟塞尔(JIS)",
193
+ "oklch-hue": "OKLCH 色相(感知均匀间距)",
194
+ "oklch-lightness": "OKLCH 明度(保持亮度)"
195
+ },
189
196
  "visionTypes": {
190
197
  "normal": "正常视觉",
191
198
  "deuteranopia": "绿色盲(红绿色盲)",
@@ -0,0 +1,175 @@
1
+ {
2
+ "$comment": "Generated by scripts/build-munsell-hues.ts from the Munsell renotation data (RIT MCSL real.dat, Newhall, Nickerson & Judd 1943) at Value 6 / Chroma 8. Attribution: packages/core/NOTICE. Do not edit by hand.",
3
+ "value": 6,
4
+ "chroma": 8,
5
+ "table": [
6
+ [
7
+ 0,
8
+ 0
9
+ ],
10
+ [
11
+ 3.989034915710647,
12
+ 2.5139081249797073
13
+ ],
14
+ [
15
+ 12.989034915710647,
16
+ 8.447104607433062
17
+ ],
18
+ [
19
+ 21.989034915710647,
20
+ 14.803285189702649
21
+ ],
22
+ [
23
+ 30.989034915710647,
24
+ 20.191397337216358
25
+ ],
26
+ [
27
+ 39.98903491571065,
28
+ 26.275952042041865
29
+ ],
30
+ [
31
+ 48.98903491571065,
32
+ 31.383193267820104
33
+ ],
34
+ [
35
+ 57.98903491571065,
36
+ 37.05876235203499
37
+ ],
38
+ [
39
+ 66.98903491571065,
40
+ 42.398535896728106
41
+ ],
42
+ [
43
+ 75.98903491571065,
44
+ 47.9926554960407
45
+ ],
46
+ [
47
+ 84.98903491571065,
48
+ 53.017624252769565
49
+ ],
50
+ [
51
+ 93.98903491571065,
52
+ 57.90986372546996
53
+ ],
54
+ [
55
+ 102.98903491571065,
56
+ 65.62918717399259
57
+ ],
58
+ [
59
+ 111.98903491571065,
60
+ 75.0580027667944
61
+ ],
62
+ [
63
+ 120.98903491571065,
64
+ 93.22570091949439
65
+ ],
66
+ [
67
+ 129.98903491571065,
68
+ 116.51033176907356
69
+ ],
70
+ [
71
+ 138.98903491571065,
72
+ 144.6266917947504
73
+ ],
74
+ [
75
+ 147.98903491571065,
76
+ 157.24722825147705
77
+ ],
78
+ [
79
+ 156.98903491571065,
80
+ 163.457850437341
81
+ ],
82
+ [
83
+ 165.98903491571065,
84
+ 168.78816045754945
85
+ ],
86
+ [
87
+ 174.98903491571065,
88
+ 173.49142938669547
89
+ ],
90
+ [
91
+ 183.98903491571065,
92
+ 177.19320475875236
93
+ ],
94
+ [
95
+ 192.98903491571065,
96
+ 179.92793432347787
97
+ ],
98
+ [
99
+ 201.98903491571065,
100
+ 182.82865339190766
101
+ ],
102
+ [
103
+ 210.98903491571065,
104
+ 185.32791575269118
105
+ ],
106
+ [
107
+ 219.98903491571065,
108
+ 188.87511992237626
109
+ ],
110
+ [
111
+ 228.98903491571065,
112
+ 194.98672174211083
113
+ ],
114
+ [
115
+ 237.98903491571065,
116
+ 200.12467673015738
117
+ ],
118
+ [
119
+ 246.98903491571065,
120
+ 207.13552720434132
121
+ ],
122
+ [
123
+ 255.98903491571065,
124
+ 214.70895708520516
125
+ ],
126
+ [
127
+ 264.98903491571065,
128
+ 228.6615786246757
129
+ ],
130
+ [
131
+ 273.98903491571065,
132
+ 245.80502994636265
133
+ ],
134
+ [
135
+ 282.98903491571065,
136
+ 262.31165473110855
137
+ ],
138
+ [
139
+ 291.98903491571065,
140
+ 276.7201487217782
141
+ ],
142
+ [
143
+ 300.98903491571065,
144
+ 297.98603038444935
145
+ ],
146
+ [
147
+ 309.98903491571065,
148
+ 313.76831747322956
149
+ ],
150
+ [
151
+ 318.98903491571065,
152
+ 326.1458328240501
153
+ ],
154
+ [
155
+ 327.98903491571065,
156
+ 337.3234172322137
157
+ ],
158
+ [
159
+ 336.98903491571065,
160
+ 344.4367466165168
161
+ ],
162
+ [
163
+ 345.98903491571065,
164
+ 350.917143032286
165
+ ],
166
+ [
167
+ 354.98903491571065,
168
+ 356.8420667891947
169
+ ],
170
+ [
171
+ 360,
172
+ 360
173
+ ]
174
+ ]
175
+ }