Merge remote-tracking branch 'upstream/master' into dev-submaps

This commit is contained in:
Mészáros Gergely 2021-12-08 13:17:39 +01:00
commit 19f5598187
73 changed files with 7693 additions and 3705 deletions

135
charges/agnusDei.svg Normal file
View file

@ -0,0 +1,135 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="#d7374a" stroke="#000" viewBox="50 50 200 200">
<metadata source="http://wappenwiki.org/images/2/26/Brixen.svg" license="https://creativecommons.org/licenses/by-nc-sa/3.0"/>
<g id="agnusDei" stroke-width="3" transform="matrix(.116 0 0 .116 74 60)">
<path d="M3.5 539s17.7 4.4 21.7 8.7c8.3 9.8 7.9 27.9 4.2 36.3-1.1 2.6-6.8.6-13.2-5.7 0 0 3 8.1.1 13.4-6.6-5.7-14.5-21.1-27.4-30-2.6-3.6-3.9-7.5-2.8-12.5s-4.5-5.5 3.7-7.1c6.1-1 13.7-3.1 13.7-3.1z"/>
<path d="M57.5 421.6c-10.1 9.4-30.8 14.9-41.2 15.2-18.2.6-43.3.4-49.2 6.8-1.8 1.9-3 10.9-8.1 14.6-1.6 3.8 3.6 13 6.1 24.3 2.6 9.7 5.7 26.1 7.3 28.1 3.6 7.8 11.3 2.1 15.4 4.4 2 1.5 2.1 1.9 2.8 5 1.1 5.2-5.7 5-5.5 10.6.2 3.8 2.1 3.5 5.1 5.3 3.2 1.6 3.1-5.3 8.4-5.6 5.1-.3 5.4 7.4 5.4 7.4s-15 7.4-14.3 24.4c-9.9-2.2-13.7-12.4-25-17.1-11.3-4.7-12.4-15.7-12.9-22.5-.5-6.8-5.9-29.6-8-36.5-3.4-10.7-12.2-33.4-13-43.6-.3-3.8 3.8-10 4.6-15.1 1.3-8.4 0-13 2.3-15.3 7-7.1 21-7.4 36.6-15.5 12.5-5.1 41-25.5 45.9-32.1"/>
<g fill="#f2bc51">
<polygon points="-24.2 591.3 -32.1 584.6 452.4 6.3 460.4 13"/>
<path d="M97.5 68.4c-65.6 0-118.7 53.2-118.7 118.7S31.9 305.9 97.5 305.9s118.7-53.2 118.7-118.7c0-65.7-53.1-118.8-118.7-118.8z"/>
<path d="M97.6 277.7c-50 0-90.6-40.6-90.6-90.6s40.6-90.6 90.6-90.6 90.6 40.6 90.6 90.6c0 50.1-40.6 90.6-90.6 90.6z"/>
<path d="M114.6 203.8h.4c31 .3 52.5 9.3 66.2 17.9 4.4-10.7 6.9-22.4 6.9-34.6 0-12-2.3-23.5-6.6-33.9-13.6 8.6-35.1 17.7-65.9 18.1h-1.1v-.5c.4-31.6 9.7-53.5 18.5-67.1a91.14 91.14 0 00-69.8-.5c8.8 13.5 18.4 35.4 18.8 67v1c-31.7-.8-54.1-10.6-68-19.5A90.45 90.45 0 006.9 187c0 12.8 2.7 25 7.4 36 13.9-8.8 36.1-18.4 67.6-19.2-.8 31-10.2 53.1-18.9 67 10.6 4.4 22.3 6.8 34.5 6.8 12.7 0 24.7-2.6 35.6-7.3-8.6-13.8-17.7-35.7-18.5-66.5z"/>
<path d="M494.3 60.2L334.7 75.6v7.7l159.5-15.4v-7.7z"/>
<path stroke-width="2" d="M455.9 11.8c0 .2 2.6 16.6 9.1 28.5 6.9 12.3 24.8 22.2 24.9 22.3l-1.7 3.2c-.8-.4-19-10.4-26.4-23.6-4.8-8.7-8.7-19.4-9.3-25.4"/>
<path stroke-width="2" d="M450.6 13.6c-6.3 7.5-25.7 26.9-50.5 38.8C360.5 71.9 328.4 78 328 78.1l-.7-3.5c.4-.1 32-6.2 71.3-25.5 31-14.9 51.9-41.1 52.1-41.4l3.2-4.4.1 5.4"/>
<path d="M488.3 54.8c5.1 0 9.3 4.2 9.3 9.3s-4.2 9.3-9.3 9.3c-5.1 0-9.3-4.2-9.3-9.3.1-5.2 4.2-9.3 9.3-9.3z"/>
<path d="M331.7 69.3c5.1 0 9.3 4.2 9.3 9.3 0 5.1-4.2 9.3-9.3 9.3-5.1 0-9.3-4.2-9.3-9.3-.1-5.2 4.1-9.3 9.3-9.3z"/>
<path d="M456.7-1.6c5.1 0 9.3 4.2 9.3 9.3s-4.2 9.3-9.3 9.3c-5.1 0-9.3-4.2-9.3-9.3.1-5 4.2-9.3 9.3-9.3z"/>
</g>
<path fill="#f6f6f6" d="M343.4 82l133-12.8s-11.3 29.2-3.7 63.7c9.1 44 43.1 51.1 53.5 109.9 7.6 43.9-7.3 70.9-7.3 70.9s-1.9-28.2-13.4-45.5c-14.4-21.6-36.4-33.5-36.4-33.5s7.2 18.7 5.2 41.6c-1.9 27.7-16.8 49.7-16.8 49.7s-4.6-40.3-24.8-68.5c-17.4-24.2-71.4-66.7-83.1-108.6-11.8-42.4-6.2-66.9-6.2-66.9z"/>
<path fill="#bc2e2e" d="M351.3 154c.2.5.3.9.5 1.4.3.9.7 1.7 1 2.7.1.2.2.4.2.6.4 1 .9 2.1 1.3 3.1 17.7-5.6 35-7.7 52.8-9.2 7.6 19.9 19.3 36 30.8 51.8 11.7 16.1 28.1 44.8 36.2 71.7v-.1c.3-3.8.4-7.5.3-11l-.5-8a99.42 99.42 0 00-4.8-22.3h0c0-.1-.1-.2-.1-.3h0v-.1l.1.1h0c1.2.7 11.6 6.6 22.5 16.9h0c-7.9-24.7-22.5-43.2-35.4-61.1-9.5-13.2-17.4-25.6-23.9-39.9 14.2-1.3 28.5-3.4 43.1-7.6h0c-.5-1.5-.9-3.1-1.4-4.6 0-.2-.1-.3-.1-.5-.2-.6-.3-1.2-.5-1.8 0-.2-.1-.4-.1-.6-.2-.8-.4-1.6-.5-2.5-.3-1.3-.5-2.8-.8-4.1 0-.2-.1-.4-.1-.7l-.6-3.9h0l-1.3-4.5c-14.9 4.4-29.6 6.2-45 7.5-3-14.7-3.2-31.8.7-53l-.4-.1-24.3 2.2c-3.2 20.4-2.8 37.6-.1 52.7-17.3 1.6-35.2 4-53.8 9.8v.1c.3 1.4.6 2.8 1 4.2 0 .2.1.3.1.5l1.2 4.6c.3 1.2.7 2.4 1.1 3.6.4 1.1.6 1.8.8 2.4z"/>
<path d="M96 650.6s0 18.2-3.3 23.1c-7.5 10.4-25.2 14.4-34.3 12.8-2.8-.5-2.2-6.4 2.3-14.2 0 0-7.2 4.9-13 3.3 3.9-7.8 16.9-19.2 22.5-33.8 2.9-3.4 6.4-5.6 11.5-5.7 5.1-.1 4.3-5.6 7.7 1.9 2.8 5.7 6.6 12.6 6.6 12.6z"/>
<path d="M445.1 650.6s0 18.2-3.3 23.1c-7.5 10.4-25.2 14.4-34.3 12.8-2.8-.5-2.2-6.4 2.3-14.2 0 0-7.2 4.9-13 3.3 3.9-7.8 16.9-19.2 22.5-33.8 2.9-3.4 6.4-5.6 11.5-5.7 5.1-.1 4.3-5.6 7.7 1.9 2.8 5.7 6.6 12.6 6.6 12.6z"/>
<path d="M295.1 650.6s0 18.2-3.3 23.1c-7.5 10.4-25.2 14.4-34.3 12.8-2.8-.5-2.2-6.4 2.3-14.2 0 0-7.2 4.9-13 3.3 3.9-7.8 16.9-19.2 22.5-33.8 2.9-3.4 6.4-5.6 11.5-5.7 5.1-.1 4.3-5.6 7.7 1.9 2.8 5.7 6.6 12.6 6.6 12.6z"/>
<path d="M384 474.7c-4.9 11.4-10.4 15-14.7 30.3-.5 1.8-1.5 3.5-1.6 5.4-.1 2.1.6 4.1 1 6.1.8 4.3 2.2 10.3-.9 13.5-7.7 7.8-15.2 10.9-22.4 19.3-11.9 13.9-25.6 32.7-29.6 50.6-3.3 14.8 4.5 21.5 2.6 26.3-1.3 2.4-2.5 4.3-5.7 5.4-5.5 1.9-7.2-3.6-13.4-2.6-4.1.8-7.1 4.5-7.2 6.4 0 4.1 6.1 3.1 6.8 8.9.3 2.3-4.3 4.8-4.3 4.8s-11.8-11.8-27.6-5.7c-1.1-10 11.8-28.6 19.5-38.1 10.5-13.1 22-38.9 24.6-44.1 7.3-14.7 14.7-29.5 18.7-45.4 4.2-16.8-3.3-24.7-9.1-51.1 5.9-1.7 9.4-2.5 14.8-5.5 5.3-3 11.5-5.3 17.5-4 3.8.8 7.1 3 10.2 5.1 6.7 4.5 14.1 9.9 20.8 14.4z"/>
<path d="M475.5 401.6c.1-1.3-2.9-3-5.2-7.9-1.9-3.9-4.7-20.6-22-35.3-23.7-20.1-27.3-28.1-43.9-44.4-16.8-13.6-21.8-18.1-45.6-25-9.9-2.9-20.9-4.4-30.9-5-12.2-.7-38.2.1-50.6 1.7-10.3 1.3-44.6 3.6-55.1 3.6-61.5 0-74.7-21.9-92.7-25.2-5-6.4-4.4-15.9-4.4-15.9s10.2 3 23.2-2.4c5.9-2.5 13.7-2.9 21-1.1 2.4.6 4.2 1.2 6.7 2.5 5.9 3.1 10 2.9 15.8 1.7 4.3-.9 7.2-7.6 7.2-7.6 3.3-.9 6.1-1.7 8.6-4.9 1.6-2.1 3.4-6.4 3.2-9.9 0-.7-1.1-3.3-1-4 0-.4.9-2 .8-4.2-.3-4.1-1.5-8.8-5.3-15.8-2.6-4.7-13.3-17.4-16.8-22.6-3.6-5.3-7.3-8.8-10.3-11.8-1.1-1.1-9.5-9.3-10.3-10-1.7-1.3-2.6-3.2-3-5.3-.8-4.9-6-10.2-10.8-13.2-2.2-1.4-2.5-2-2.6-2.7-.4-3.1-5.5-8-9.6-9-6.2-1.4-10.2-6.2-16.9-6.5-6.9-.2-9.9-1.3-13.6-1.9-3.7-.6-7.9.2-13.4-.8-15.2-2.8-29.1 4.4-36.5 9.2s-23 11.5-31.4 29.8c-3.3 7.2-5.5 14.7-8.9 21.8-3.2 6.9-3.4 14.1-5.6 21.4-1.9 6.1-6.2 11.7-2.3 16.5 0 0-1 8.6-5.5 15.6-3.6 5.6-1.1 12 3.2 15.1 0 0-1.8 6.8-8 13.2-4.7 4.9-4.2 12.6.2 16.4-3.5 10.6-24.2 21-13.6 38.2-14.7 10.8-6.4 30-8 38.2-10.1 20.8 11.4 40 11.4 40-8.8 19.5 17.8 34.5 17.8 34.5s1.6 15.2 24.1 14.4c4.9 15.3 20.2 19.2 26.1 20.4 1.2 9.3 3.2 16.6 13.6 37.7.7 1.4 2.2 2.6 2.2 4 0 6.7.4 13.7 1.6 20.3 1.1 5.9 1.9 7.9 2.8 13.9.7 4.6 3.6 7.8 2.9 12.7-1.5 10.2-.9 20.6-1.8 30.9-.9 10.4-3 20.8-4.3 31.1-1.5 12.1-9.6 19.5-9 29.5 16.1-5.3 27.3 7.2 27.3 7.2s4.7-2.3 4.6-4.6c-.4-5.9-6.6-5.1-6.4-9.2.2-1.9-1-3.6 2.7-5.6 5.6-2.8 8.8 2 13.6-1.4 2.8-2.1 3.3-4.2 3.9-6.9.4-5.2-12.1-6-9.6-17.8.7-4.1 3.7-17.8 4-28.5.3-10.8-1.6-26 1-29.8 3.7-5.2 5-10.2 7.4-15.9 2.4-8.9 2.9-12.7.1-21.7-.7-2.2-1-1.5-1-3.5s-2.1-9.4-1.8-11.7c.9-8 8.2-6 11.3-16.3l.2.4c2 .9 13.6 3.4 15.8 3.2 9.9-1.2 20.1-2.1 26.5-1.5 9.6.8 20.2-1.1 29.6.5 11.4 1.9 20.7-.9 32-2.3 4.1-.5 8.3-.9 12.3-2 3.6-1 7.3-1.1 11-1.8 4.9-.9 18.4.2 23.2 1.3 10 2.3 17.6-.4 27.9-.3 7.3.1 14.4-1.8 21.4-3.8 9-2.5 16.5-3.5 24-8.1 6.1 8.1 11.4 21.8 28 29.5l-.1.2c.5 3.9 3.2 7.2 6.4 9.5 3.1 2.4 6.7 4 9.9 6.3 9.1 6.6 11.5 12.3 16 21.8 2.1 4.6 5.3 8.7 7.1 13.4 2.7 7 9.2 25.9 9.6 43.8 0 8.5-1.4 11.6-2.3 23.8-.9 12.2-8.5 21.5-7.4 31.6 15.8-6.1 27.6 5.7 27.6 5.7s4.6-2.5 4.3-4.8c-.8-5.8-6.9-4.8-6.8-8.9.1-1.9-1.1-3.5 2.4-5.7 5.5-3.1 8.9 1.5 13.5-2.2 2.7-2.2 3.1-4.4 3.5-7.1.2-5.2-9.5-8.8-11.5-23.8-1.9-14.3-.7-34.6-2.6-48.9-1.9-14.6-3.8-19.3-2.3-34 .9-9.1 5-19 .3-26.8-3.6-5.9-15.6-9.5-17.7-16.1-.8-2.6-.7-5.4-.6-8.1.7-20 4.7-17.1 4.7-37.1 0-12.9-3.2-25.8-3.2-25.8s3.4 8.9 5.9 12.2c6 8 14.1 9.6 14.1 9.6s5.1 15.3 23 18.8c.2-2.5-4.1-7.5-4.9-12.9-.7-4.9 1.2-12.3.7-16.6-1.1-8.3-4.7-11.5-4.4-12.1 3.8 2.8 8.9 5.2 12.3 2.9z"/>
<path fill="none" d="M61 463.4c-1.1-6.5-2.4-13.4-4.4-22.5-4.4-12.5 1.8-23.5 1.8-23.5"/>
<path fill="none" d="M316.5 419.6c1 8.1 3.1 17.4 10.2 21.4 0 6.1 5.2 11.4 11.2 12.2 3 5.1 8.8 5.1 11.6 10.3"/>
<path d="M65.2 183.8c-2.9 1.6-10.4 4.8-19.6 4.9-8-.1-18.6-.1-28-3.3-10.4 1.8-19.4-4.1-19.5-7.7.7-4.9 12-8.3 15.8-10 15-7 19.8-12.1 28.1-15.4 10.8-4.3 24.8-5.1 31.3-3.7"/>
<path fill="#f6f6f6" stroke-width="2.5" d="M150.4 165.1c-2.6-.4-5.4-.2-7.3 1.7-.5.5-1.8 3.2-.1 7.4.7 1.7 1.8 3.1 3.4 4 2.1 1.2 6.2 1.8 8.7 1.1 2.6-.8 4.3-1.9 4.3-4.3.1-4.1-7-9.6-9-9.9z"/>
<g fill="#000" stroke="none">
<path d="m -8.3,426 c 3.6,-1 10.85,-2 14.55,-2 l 0.1,2 c -3.96,0 -11.46,0 -14.65,0 z"/>
<path d="M-38.4 434.8l-.3 2.8c-.1.9-.1 1.8-.1 2.7 0 1.8-.3 4-1.1 5.8-.4.9-.8 1.8-1.4 2.7-.6.9-1.3 1.7-2.2 2.3-1.7 1.3-3.8 2-5.9 1.6v-.5c1.7-.6 3.2-1.6 4.2-2.8.5-.6 1-1.3 1.4-2 .4-.7.7-1.5 1-2.4.6-1.6 1-3.2 1.5-5.1.5-1.8 1.4-3.7 2.9-5.1z"/>
<path d="M-48.7 463.4c1.1 4.6 2.2 9 3.4 13.5l1.7 6.7c.6 2.2 1.1 4.5 1.7 6.7.6 2.2 1.1 4.5 1.7 6.7l1.8 6.7c1.2 4.5 2.5 8.9 4.2 13.3-2.8-3.8-4.7-8.2-6.4-12.5l-1.2-3.3c-.4-1.1-.7-2.2-1.1-3.3-.7-2.2-1.3-4.5-1.9-6.7-1.1-4.5-2.1-9.1-2.8-13.7-.7-4.7-1.2-9.4-1.1-14.1z"/>
<path d="M-25.2 541.4a8 8 0 014.3.5c1.4.5 2.6 1.4 3.7 2.2 1.1.9 2.1 1.9 3 2.9.9 1 1.7 2.1 2.6 3.1l-.2.3c-1.4-.5-2.5-1.4-3.6-2.2-1.1-.9-2.1-1.8-3.1-2.6-1-.9-2-1.7-3.1-2.4-1.1-.6-2.2-1.2-3.6-1.8z"/>
<path d="M14.9 579.3c-2.3-3.6-5-7.1-7.8-10.5-2.8-3.4-5.7-6.7-8.7-9.9l.2-.2c3.3 2.9 6.5 5.9 9.7 9 3.1 3.1 6.2 6.3 9 9.8l-2.4 1.8z"/>
<path d="M59.7 671.4c2.9-3.1 5.7-6.6 8.3-10.1 2.6-3.5 5.1-7.1 7.6-10.8l.3.2c-2 3.9-4.2 7.8-6.5 11.6s-4.6 7.5-7.4 11.1l-2.3-2z"/>
<path d="M408.8 671.4c2.9-3.1 5.7-6.6 8.3-10.1 2.6-3.5 5.1-7.1 7.6-10.8l.3.2c-2 3.9-4.2 7.8-6.5 11.6s-4.6 7.5-7.4 11.1l-2.3-2z"/>
<path d="M258.8 671.4c3-3.1 5.7-6.6 8.3-10.1 2.6-3.5 5.2-7.1 7.6-10.8-2 3.9-4.1 7.8-6.4 11.6-2.3 3.8-4.6 7.6-7.3 11.2l-2.2-1.9z"/>
<path d="M145.4 426.3c.6 4.6.3 9.3-.6 13.9-.9 4.6-2.5 9-4.4 13.3-1.9 4.3-4.2 8.3-6.5 12.3s-4.7 7.9-6.4 12l-2.8-1.1c2-4.4 4.5-8.3 6.9-12.2 2.5-3.9 4.8-7.8 6.9-11.9a62.04 62.04 0 006.9-26.3z"/>
<path d="M111.2 547.6c-2.1 3.6-3.6 7.7-4.7 11.9-1.2 4.2-2 8.5-2.8 12.8-.8 4.3-1.5 8.6-2.4 13-.4 2.2-.9 4.3-1.6 6.4-.7 2.1-1.4 4.3-2.8 6l-.2-.2c1.3-1.7 1.9-3.9 2.4-6s.9-4.3 1.2-6.4c.7-4.3 1.1-8.7 1.7-13.1.6-4.4 1.2-8.7 2.2-13.1 1-4.3 2.2-8.7 4.4-12.8l2.6 1.5z"/>
<path d="M102.7 500.7c1.1 2.5 2.3 4.9 3.6 7.3 1.3 2.4 2.6 4.9 3.5 7.6.9 2.7 1.4 5.6 1.2 8.5-.2 2.9-.9 5.8-2.7 8.1l-.4-.2c.7-2.6.8-5.2.6-7.8-.2-2.6-.8-5.1-1.6-7.6s-1.8-4.9-2.7-7.6c-.9-2.6-1.6-5.4-1.6-8.2l.1-.1z"/>
<path d="M443.7 401.6c2 2.9 2.9 6.5 3.7 9.9.4 1.7.7 3.4 1.1 5.1.4 1.7.9 3.3 1.6 4.6l-2.8 1.2c-.7-1.9-.9-3.7-1.1-5.4-.2-1.8-.3-3.5-.5-5.2-.3-3.4-.8-6.9-2.4-10l.4-.2z"/>
<path d="M462.3 400.2c-1.5-1.4-2.8-2.9-3.9-4.5s-2.1-3.3-2.8-5l.3-.1c1.1 1.5 2.4 2.9 3.8 4.1 1.4 1.2 2.9 2.3 4.4 3.2l-1.8 2.3z"/>
<path d="M452 401.5c1.8 2.4 3.6 4.9 4.9 7.7 1.4 2.7 2.4 5.7 3 8.6.6 3 .9 6 1.8 8.7.9 2.7 2.6 5.2 4.3 7.6l-.2.2c-2.3-2-4.4-4.3-5.6-7.2-.7-1.4-1-3-1.4-4.5-.3-1.5-.5-3-.9-4.4-.6-2.9-1.4-5.7-2.5-8.4-.9-2.8-2.3-5.4-3.4-8.3z"/>
<path d="M427.3 400.1c-.7-4.6-1.6-9.2-2.7-13.8-1.1-4.6-2.3-9.1-3.7-13.6-2.8-9-6.2-17.8-9.7-26.7 2.4 4.1 4.5 8.4 6.4 12.7 1.9 4.4 3.6 8.8 5.3 13.3 1.6 4.5 3 9 4.3 13.6 1.3 4.6 2.2 9.3 3.1 14l-3 .5z"/>
<path d="M351.5 329.8c3.6.8 7.1 1.9 10.4 3.5 1.7.7 3.3 1.7 4.9 2.5 1.6.9 3.2 1.9 4.7 3 3 2.1 5.9 4.4 8.5 7 2.6 2.6 5 5.4 7 8.5l-.4.3c-2.7-2.4-5.5-4.7-8.3-6.9-2.8-2.2-5.6-4.4-8.5-6.4-1.4-1.1-2.9-2-4.4-3-1.5-1-3-1.9-4.5-2.8-3-1.9-6.2-3.5-9.4-5.4v-.3z"/>
<path d="M403.1 377.7c1.2.1 2.2.5 3.2.9 1 .5 1.9 1 2.7 1.6.4.3.8.6 1.2 1 .4.4.8.7 1.1 1.2.4.5.7 1 .9 1.7.1.3.1.7.1 1 0 .4-.2.7-.5.8-.1-.6-.5-.8-.8-1.1-.4-.2-.8-.5-1.2-.7-.4-.2-.9-.4-1.3-.7-.4-.3-.9-.6-1.3-.9-.8-.6-1.6-1.3-2.3-2.1-.7-.7-1.4-1.6-1.8-2.7z"/>
<path d="M406.6 389.5c1-.1 1.9.1 2.7.5a6.11 6.11 0 013.4 3.7c.3.8.4 1.7.2 2.7-.9-.4-1.6-.9-2.2-1.4-.6-.5-1.1-1-1.6-1.5s-.9-1.1-1.4-1.7c-.4-.6-.8-1.3-1.1-2.3z"/>
<path d="M409.2 399.9c1.2.5 2.2 1.3 3.1 2.2.9.9 1.6 1.9 2.3 2.9.6 1.1 1.1 2.2 1.4 3.4.3 1.2.5 2.5.3 3.8-1-.9-1.8-1.8-2.5-2.8-.7-.9-1.3-1.9-1.9-2.9-.6-1-1.1-2-1.6-3.1-.3-1.1-.8-2.2-1.1-3.5z"/>
<path d="M411.6 412.8c1 1 1.7 2.2 2.3 3.4.5 1.2.9 2.6 1.1 3.9.2 1.3.2 2.7 0 4.1-.2 1.3-.6 2.7-1.3 3.9-.5-1.4-.8-2.6-1-3.9l-.6-3.7c-.2-1.2-.3-2.5-.4-3.7-.1-1.3-.2-2.6-.1-4z"/>
<path d="M158.8 427.6c-.7-1.3-1.2-2.4-1.7-3.6-.5-1.1-1.1-2.3-1.6-3.4-.5-1.2-1-2.4-1.3-3.7-.4-1.3-.6-2.6-.6-4.1 1.1 1 1.9 2 2.7 3.1.8 1.1 1.4 2.3 2 3.5.5 1.3.9 2.6 1.1 4 0 1.4 0 2.9-.6 4.2z"/>
<path d="M209 307.4c1.1-.4 2.1-.6 3.1-.8 1-.2 1.9-.4 2.8-.5.9-.1 1.9-.3 2.9-.4 1-.1 2-.2 3.2-.1a6.4 6.4 0 01-2.5 2.4c-1 .6-2 .9-3.2 1.1-1.1.2-2.2.1-3.3-.1-1-.3-2.1-.8-3-1.6z"/>
<path d="M174.2 457.6c-.2.2-.2.4-.1.5.1.1.3.3.5.3.2.1.4.1.5.2h.6c1-.1 1.9-.1 2.9-.2 1.9-.1 3.8-.1 5.6-.2 1.9 0 3.7-.1 5.6-.1 1.9 0 3.8 0 5.8.2-1.7 1-3.6 1.6-5.5 2.1a28.72 28.72 0 01-14.6-.5l-.4-.1c-.2-.1-.3-.1-.5-.2-.3-.2-.5-.4-.7-.6-.2-.2-.3-.5-.4-.8 0-.1 0-.3.1-.5.4-.1.5-.1.6-.1z"/>
<path d="M183.2 411c1.2-.9 2.4-1.5 3.6-2 1.2-.5 2.5-1 3.7-1.4 1.3-.4 2.5-.7 3.9-.9 1.3-.2 2.7-.4 4.1-.3-1 1.1-2.2 1.9-3.4 2.5-1.2.7-2.5 1.2-3.8 1.6-1.3.4-2.6.6-4 .8-1.3.1-2.7.1-4.1-.3z"/>
<path d="M222.4 439.4c1.2-.4 2.4-.4 3.5-.2 1.2.2 2.3.7 3.3 1.3 1 .6 1.9 1.5 2.5 2.4.7 1 1.2 2.1 1.2 3.3-1.1-.5-2-1.1-2.9-1.6l-2.5-1.6-2.5-1.6c-.8-.6-1.7-1.2-2.6-2z"/>
<path d="M256 435.8a29.46 29.46 0 008.7.9c1.4-.1 2.7-.3 4.1-.7 1.4-.3 2.8-.8 4.3-1.4a7.9 7.9 0 01-3.4 3.6c-1.5.9-3.1 1.4-4.8 1.5-1.7.1-3.4-.1-5-.8-1.6-.7-3-1.7-3.9-3.1z"/>
<path d="M355.3 511.1c-1.9.2-2.9 1.5-3.7 2.9-.4.7-.8 1.4-1.1 2.1-.3.8-.7 1.5-.9 2.3-.6 1.6-1.1 3.2-1.6 4.8-.5 1.7-.8 3.4-1.3 5.2-.8-1.7-1-3.6-1-5.5s.4-3.8 1.1-5.6a13.68 13.68 0 013-5c.7-.7 1.6-1.3 2.6-1.6.5-.1 1-.2 1.5-.2.6.2 1 .4 1.4.6z"/>
<path d="M332.7 551.3c-2.1 4.4-4.4 8.6-6.8 12.8-1.2 2.1-2.4 4.1-3.7 6.2l-3.7 6.1c-1.3 2-2.5 4.1-3.7 6.1-1.3 2-2.4 4.1-3.6 6.2-2.4 4.1-4.6 8.4-6.8 12.7 1-4.7 2.7-9.3 4.7-13.8 1-2.2 2.1-4.4 3.3-6.5l3.6-6.3c2.6-4.1 5.2-8.1 8-12 2.7-3.9 5.6-7.8 8.7-11.5z"/>
<path d="M319.1 410.1c-.7-.6-1-1.6-1.2-2.5-.1-1 0-2 .4-2.9.7-1.8 1.9-3.4 3.5-4.5 1.5-1.1 3.2-1.7 4.8-2.3 1.6-.5 3.2-1 4.9-1.5-1 1.6-2.5 2.7-3.9 3.6-1.4.9-2.9 1.7-4.1 2.6-1.2.8-2.3 1.9-3.1 3.1-.9 1.2-1.5 2.5-1.3 4.4z"/>
<path d="M357.6 452c-.9 1-2.2 1.5-3.5 1.7-1.3.2-2.7 0-3.9-.5-1.2-.5-2.4-1.3-3.2-2.3-.8-1-1.4-2.3-1.4-3.6 1.1.8 2 1.3 2.9 1.9.9.5 1.8.9 2.8 1.3.9.4 1.9.7 2.9 1 1 .1 2.1.3 3.4.5z"/>
<path d="M46.2 335.6c0 2.5-.1 4.9-.1 7.3v7.1l.3 7.1c.1 2.4.3 4.8.4 7.2-1.3-2.1-2.1-4.5-2.8-6.9-.6-2.4-.9-4.9-1-7.4-.1-2.5.2-5 .7-7.4.5-2.4 1.3-4.8 2.5-7z"/>
<path d="M71.9 436.2c.4 2.1.8 4.1 1.3 6.1.5 1.9 1.2 3.8 1.9 5.6.7 1.8 1.6 3.6 2.6 5.3 1 1.7 2.1 3.4 3.3 5.2-2-.9-3.7-2.2-5.2-3.9-1.5-1.6-2.6-3.5-3.5-5.6-.8-2-1.3-4.2-1.4-6.4-.1-2.1.2-4.3 1-6.3z"/>
<path d="M81 471.1c1.3.7 2.4 1.3 3.6 2l3.3 1.9 3.3 1.8c1.1.6 2.3 1.2 3.5 2-1.4.5-2.9.5-4.3.2-1.4-.2-2.8-.7-4-1.4-1.3-.7-2.4-1.6-3.3-2.7-1-1.1-1.8-2.3-2.1-3.8z"/>
<path d="M150.8 399.4c1-.1 1.7-.8 2.2-1.6.5-.8.7-1.7.9-2.6a35.52 35.52 0 00-1-17.1v-.1c-.1-.4-.1-.8.2-1.1 1.2-1.9 1.8-4.2 1.9-6.6.1-1.2 0-2.5-.1-3.7-.1-1.3-.3-2.5-.5-3.8.6 1.1 1.2 2.3 1.6 3.6.5 1.2.8 2.5 1 3.9.2 1.3.2 2.7 0 4.1-.2 1.4-.7 2.8-1.4 4.1l.1-1.2c.7 2 1.3 4.1 1.5 6.2.3 2.1.3 4.2 0 6.3-.3 2.1-.8 4.1-1.6 6.1-.4 1-1 2-1.7 2.8-.4.4-.9.7-1.4.9-.6-.1-1.2 0-1.7-.2z"/>
<path d="M57.1 416.6c1-1.7 1.9-3.4 2.3-5.1.5-1.7.4-3.5 0-5.4-.4-1.9-.9-3.9-1.2-6-.3-2.1-.3-4.4.4-6.5v.6c-.6-2-.7-4-.6-6 .2-2 .6-4 1.3-5.8.7-1.8 1.6-3.6 2.7-5.2s2.4-3.1 3.9-4.3c-1.2 1.5-2.3 3.1-3.1 4.8a25.75 25.75 0 00-3 10.7c0 1.8.2 3.6.8 5.3.1.2.1.4 0 .6v.1c-.5 1.7-.4 3.6-.1 5.5.4 1.9 1 3.8 1.5 5.8.3 1 .5 2.1.5 3.3 0 1.1-.1 2.3-.3 3.4-.5 2.2-1.5 4.1-2.5 5.9l-2.6-1.7z"/>
<path d="M409.2 483.8c-.1 2 .7 3.7 1.8 4.9 1.1 1.3 2.6 2.3 4.2 3.5 1.6 1.2 3 2.5 4.5 3.9 1.4 1.4 2.8 2.8 3.9 4.5-1.9-.7-3.7-1.7-5.4-2.7-1.7-1-3.3-2.1-4.9-3.3-1.5-1.2-3.2-2.6-4.3-4.6-.5-1-.8-2.1-.8-3.2s.3-2.3 1-3z"/>
<path d="M439 583.8c-.4-5.5-.4-11.1-.3-16.6.1-5.5.4-11.1.7-16.6.3-5.5.8-11.1 1.5-16.6.6-5.5 1.4-11 2.5-16.5l2.9.6c-1.2 5.3-2 10.8-2.8 16.2-.8 5.5-1.4 10.9-2 16.4-1.1 11-1.7 22-2.5 33.1z"/>
<path d="M301 384.3c0 3.5 0 7 .3 10.5s.7 7 1.7 10.2c.5 1.6 1.2 3.1 2.1 4.4.9 1.3 2.1 2.5 3.4 3.6 2.6 2.1 5.6 3.7 8.7 5.3l-1.4 2.7c-3.1-1.7-6.3-3.5-9.1-5.9-1.4-1.2-2.6-2.7-3.6-4.3-1-1.6-1.7-3.4-2.1-5.2-.4-1.8-.7-3.6-.8-5.4-.1-1.8-.2-3.6-.2-5.3-.1-3.6.2-7.2 1-10.6z"/>
<path d="M76.3 306c1.1.1 2.1.8 2.7 1.9.6 1 .9 2.2.9 3.3.1 1.1 0 2.2-.3 3.3-.2 1.1-.5 2-.9 3-.7 2-1.5 3.9-2.4 5.7-1 1.8-2.1 3.6-3.5 5.1.3-2.1.8-4.1 1.3-6 .5-1.9 1.1-3.9 1.8-5.8s1.3-3.6 1.6-5.5c.4-1.7.5-3.5-1.2-5z"/>
<path d="M53.1 306c1.1-.2 2.2.5 3 1.3.8.8 1.4 1.7 1.9 2.7.9 2 1.5 4.1 1.7 6.3 0 1.2-.1 2.2-.2 3.3-.2 1.1-.5 2.1-.8 3.1-.7 2-1.6 3.8-2.5 5.7-.3-2.1-.1-4.3.2-6.2l.3-2.9c0-.5.1-1 .1-1.4v-1.4c-.1-1.8-.4-3.8-.9-5.6-.2-.9-.5-1.8-.9-2.7-.4-.9-.9-1.7-1.9-2.2z"/>
<path d="M118.8 306.1c1.6 2.2 2.8 4.6 3.7 7.1.9 2.5 1.6 5.1 1.9 7.8.4 2.6.5 5.3.3 8s-.7 5.3-1.6 7.8c-.3-2.7-.5-5.2-.8-7.8-.2-2.6-.5-5.1-.9-7.6s-.8-5-1.2-7.6c-.4-2.5-1-5-1.4-7.7z"/>
<path d="M140.5 316.3c1.1.3 2 .9 2.7 1.6.7.7 1.4 1.5 1.9 2.4.5.9.8 1.8 1 2.8.2 1 .2 2-.1 3.1-.9-.7-1.5-1.5-2-2.2-.6-.8-1-1.5-1.5-2.3-.4-.8-.8-1.6-1.2-2.5-.3-.9-.6-1.8-.8-2.9z"/>
<path d="M102 349.8c2.6.2 5 1.7 6.9 3.5 1.9 1.9 3.3 4.2 4.2 6.7.9 2.4 1.5 5 1.9 7.4.4 2.5.6 5 .8 7.5-1.4-2.2-2.2-4.6-3-7-.8-2.4-1.5-4.7-2.4-6.9a33 33 0 00-3.2-6.2c-1.4-1.8-3.1-3.6-5.2-5z"/>
<path d="M126.3 288.4c2 .8 3.8 1.8 5.5 2.9 1.7 1.1 3.4 2.3 5 3.6 1.6 1.3 3.1 2.6 4.6 3.8 1.5 1.2 3.1 2.2 5.2 2.7-2 .8-4.5.3-6.4-.6-2-.9-3.7-2.2-5.3-3.5-1.6-1.3-3.1-2.6-4.6-4.1-1.4-1.5-2.8-3-4-4.8z"/>
<path d="M96.4 312.8c1.4.9 2.5 2.2 3.3 3.6.8 1.4 1.3 3 1.4 4.7.2 1.6 0 3.3-.4 4.9-.5 1.6-1.2 3.1-2.4 4.2 0-1.6.1-3.1.1-4.5s-.1-2.8-.2-4.2c-.1-1.4-.4-2.8-.7-4.2-.3-1.5-.7-2.9-1.1-4.5z"/>
<path d="M92.9 298.7c-.2-1.8-.1-3.6-.1-5.3 0-1.7.1-3.4.2-5.1l.3-5.1c.2-1.7.3-3.4.7-5.2.9 1.6 1.4 3.4 1.7 5.1.3 1.8.4 3.6.3 5.3-.1 1.8-.4 3.6-.9 5.3-.5 1.8-1.2 3.5-2.2 5z"/>
<path d="M110.7 253.2c1.3.3 2.5 1 3.5 1.9 1 .9 1.8 2 2.3 3.2.6 1.2.9 2.5 1 3.8.1 1.3-.1 2.7-.8 3.9-.6-1.2-1.1-2.3-1.5-3.3-.5-1-.9-2-1.4-3-.5-1-.9-2-1.5-3-.5-1.2-1-2.3-1.6-3.5z"/>
<path d="M131 263.4c1 2.2 2.4 4.3 3.9 6.1 1.6 1.9 3.5 3.6 5.4 5.2 3.9 3.2 8.4 5.9 12.5 9.1-2.4-1-4.7-2.1-7-3.4-2.3-1.3-4.5-2.6-6.7-4.1a42.3 42.3 0 01-6.1-5.1 25.6 25.6 0 01-4.7-6.6l2.7-1.2z"/>
<path d="M30.1 309.6c-.6-1.8-1-3.6-1.1-5.5-.1-1.9 0-3.8.4-5.7.4-1.9 1.1-3.7 2.2-5.4 1.1-1.6 2.6-3 4.4-3.7-.9 1.7-1.7 3.2-2.3 4.8-.6 1.6-1 3.2-1.4 4.9-.4 1.7-.6 3.4-1 5.2-.2 1.7-.6 3.5-1.2 5.4z"/>
<path d="M52.9 274.1c-.4 1.6-.6 3.1-.7 4.6-.1 1.5-.1 2.9 0 4.4.1 1.4.4 2.9.8 4.3s1 2.8 1.6 4.4c-1.5-.8-2.6-2.1-3.4-3.6-.8-1.5-1.3-3.1-1.5-4.8-.2-1.7 0-3.4.5-5 .6-1.7 1.5-3.2 2.7-4.3z"/>
<path d="M14.1 216c.5.3.9.4 1.2.3.3-.1.8-.5 1.2-1.1.8-1.2 1.5-2.7 2.2-4.2.7-1.5 1.4-3 2.3-4.4.9-1.4 2-2.7 3.4-3.5-1.3 1-2.1 2.4-2.8 3.9-.7 1.4-1.1 3-1.6 4.5-.5 1.6-.8 3.1-1.6 4.8-.4.8-.9 1.7-2.1 2.3-.6.3-1.3.4-1.9.4-.6 0-1.1-.2-1.7-.4l1.4-2.6z"/>
<path d="M11.3 246.7c.5.1.8.1 1.1-.1.3-.2.7-.7 1-1.3.6-1.2 1-2.7 1.4-4.1.4-1.4.8-2.9 1.5-4.3s1.6-2.7 2.9-3.4c-1.2.9-1.8 2.3-2.2 3.7-.4 1.4-.6 2.9-.7 4.3-.2 1.5-.3 3-.7 4.6-.2.8-.6 1.7-1.4 2.5-.8.8-2 1.2-3 1.2l.1-3.1z"/>
<path d="M3.6 276.1c.4.1.6.1.9.1.3-.1.6-.3.9-.7.6-.8 1.1-1.9 1.5-3.1.4-1.1.8-2.3 1.4-3.5.5-1.1 1.2-2.3 2.2-3-.9.9-1.2 2.1-1.5 3.2-.3 1.2-.4 2.4-.6 3.6-.2 1.2-.4 2.5-1 3.8-.3.7-.8 1.4-1.6 1.9-.8.6-1.9.7-2.7.6l.5-2.9z"/>
<path d="M69.1 209.7c.1 1.7.1 3.3.3 4.8.2 1.5.3 3 .6 4.6.2 1.5.5 3 .8 4.6.3 1.5.6 3.1.8 4.8l-.4.2a13.9 13.9 0 01-2.8-4.3c-.7-1.5-1.1-3.2-1.3-4.9-.3-1.7-.2-3.4.1-5.1.3-1.7.9-3.3 1.9-4.7z"/>
<path d="M42.5 233.8c-.4-1.2-.5-2.5-.4-3.7.1-1.2.3-2.3.6-3.4s.6-2.1.9-3.1c.3-1 .6-2 .9-3.3.9.9 1.3 2.2 1.4 3.5.1 1.3 0 2.5-.3 3.6-.3 1.2-.7 2.2-1.2 3.2-.6 1.2-1.2 2.2-1.9 3.2z"/>
<path d="m 32.8,189 c -0.1,1 -0.3,2 -0.6,3 -0.3,1 -0.6,2 -0.9,3 -0.3,1 -0.6,2 -0.9,4 -0.9,-1 -1.3,-3 -1.4,-4 -0.1,-1 0,-2 0.3,-3 0.3,-2 0.7,-3 1.2,-4 z"/>
<path d="M57.5 194.5c.7 1 .9 2.1 1 3.2 0 1.1-.2 2.2-.6 3.3-.4 1-1 2-1.8 2.8-.8.8-1.7 1.4-2.9 1.7.3-1.2.6-2.1.9-3 .3-.9.6-1.8 1-2.6.3-.9.7-1.7 1.1-2.6.3-.9.7-1.8 1.3-2.8z"/>
<path d="M191.5 212.5c1.7.5 3.3 1.4 4.6 2.7 1.3 1.3 2.2 2.9 3 4.4.4.7.8 1.4 1.3 1.9.4.5 1 .8 1.6 1.1.6.3 1.2.4 1.8.4.6 0 1.2-.3 1.8-1l.4.1c.1.5 0 1-.3 1.5s-.7.9-1.3 1.2c-1.1.5-2.3.5-3.3.1s-1.9-1-2.5-1.9c-.7-.8-1-1.7-1.4-2.5-.4-.8-.7-1.6-1-2.3-.4-.7-.7-1.5-1.2-2.1-.9-1.3-2.1-2.5-3.5-3.6z"/>
<path d="M195.4 198.5c-2.1-.7-4-1.8-5.8-3.1a34.2 34.2 0 01-4.9-4.4c-1.5-1.6-2.8-3.3-4.1-5-1.3-1.7-2.6-3.3-4-4.9l.2-.2c2 1 3.6 2.5 5.1 4.1 1.5 1.5 2.9 3.2 4.3 4.7 1.4 1.6 2.9 3.1 4.4 4.5 1.6 1.5 3.2 2.9 4.8 4.3z"/>
<path d="M138.7 141.1c.8-1 2-1.7 3.3-1.9 1.3-.2 2.6-.1 3.8-.1 1.2 0 2.3-.1 3-.5.7-.4 1-1.2 1.3-2.2l2.8 1c-.4.7-.6 1.3-1.2 1.9-.2.3-.6.6-.9.8-.3.3-.7.4-1.1.6-1.6.6-3 .3-4.2 0-1.2-.2-2.4-.5-3.5-.6-1.1 0-2.3.3-3.1 1.1l-.2-.1z"/>
<path d="M197.6 213.9c1-.2 1.8-.2 2.7 0 .9.2 1.7.5 2.5 1s1.5 1.1 2 2c.5.9.6 2.1 0 2.9-.4-.9-1-1.3-1.5-1.7-.5-.4-1.2-.7-1.8-1.1-.6-.4-1.3-.8-1.9-1.3-.7-.5-1.3-1-2-1.8z"/>
<path d="M111.2 126.1c-1.9 0-3.6.2-5.2.7-.8.3-1.5.6-2.3 1-.7.4-1.5.9-2.4 1.3-.9.4-1.9.8-3 .9-1.1.1-2.1 0-3-.2-1.9-.4-3.5-1-5.4-1.2 1.8-.9 3.8-.7 5.6-.8.9 0 1.7-.1 2.5-.2s1.5-.4 2.2-.8c.8-.4 1.6-.8 2.5-1.2.9-.4 1.9-.7 2.9-.8 1.9-.1 4 .2 5.6 1.3z"/>
<path d="M114.9 144.9c-1.1.4-2.1.7-3.1 1.1-.9.4-1.8.8-2.7 1.3-.8.5-1.7 1-2.6 1.6-1 .5-2.1 1.1-3.3 1.1.8-.9 1.4-1.8 2.1-2.6.7-.8 1.6-1.7 2.7-2.3 1.1-.6 2.3-.9 3.5-1 1.1-.1 2.3.2 3.4.8z"/>
<path d="M96.6 139.9c.9-1.2 1.9-2.2 3.2-3 1.2-.8 2.6-1.4 4.1-1.8 1.4-.4 3-.5 4.5-.3s3 .6 4.1 1.7c-1.5-.1-2.8.1-4.1.3-1.3.2-2.6.5-3.9.8-1.3.3-2.5.7-3.8 1.1-1.4.3-2.7.8-4.1 1.2z"/>
<path d="M126.1 134.1c.3-.9 1-1.6 1.8-2 .8-.5 1.7-.7 2.5-.8.9-.1 1.7 0 2.5.2s1.6.6 2.3 1.2c-.9.4-1.6.6-2.4.7l-2.2.3-2.1.1-2.4.3z"/>
<path d="M155.9 183.7c-.4.4-.9.7-1.4 1-.5.2-1 .5-1.5.6-1.1.3-2.2.4-3.3.3a7.2 7.2 0 01-3.2-1.1c-1-.6-1.8-1.4-2.2-2.6l.3-.2c2 .8 3.7 1.2 5.5 1.4l2.8.3c.5 0 1 .1 1.5.1.4 0 .9 0 1.5.2z"/>
<path d="M131.7 166.2c1-1.2 2.1-2.2 3.4-3.1 1.3-.8 2.8-1.5 4.4-1.8 1.6-.3 3.2-.3 4.7-.2 1.5.2 3 .4 4.5.8 1.5.3 2.9.7 4.3 1.1 1.4.4 2.8.7 4.2 1 2.8.5 5.7 1 8.3-.4l.2.3a8.23 8.23 0 01-4.2 2c-1.6.3-3.1.2-4.6.1-3.1-.3-5.9-1.1-8.8-1.7-1.4-.3-2.8-.7-4.2-.9-1.4-.2-2.8-.3-4.2-.2-2.8.3-5.4 1.5-8 3z"/>
<path d="M134.5 170.9c1.5-.6 2.9-1.4 4.2-2.3 1.3-.9 2.6-1.8 3.6-2.9l1.5 2a24.72 24.72 0 01-9.3 3.2z"/>
<path d="M148.5 164.2c.7.2 1.4.3 2 .3.3 0 .6-.1.8-.1.3.2.7.3 1 .5.1.1.3.1.4.2.2.2.4.3.7.5.8.7 2.2 1.9 2.8 3-.1 2.6-1.7 4.9-4.2 6-.8.3-1.6-.3-1.5-1.1.3-2.9-.6-7.1-2-9.3z"/>
<path d="M170.1 177.5c-1.2.1-2.4.1-3.5-.2-1.2-.3-2.3-.6-3.4-1.1-1.1-.5-2.2-1-3.2-1.7s-2-1.4-2.9-2.3l1.9-1.7c.6.7 1.5 1.5 2.3 2.2.8.7 1.8 1.3 2.7 1.9.9.6 1.9 1.1 3 1.5 1 .5 2 .9 3.1 1.4z"/>
<path d="M73.5 147c1.9.5 3.7 1.2 5.3 2.1 1.6.9 3.1 2 4.4 3.3l-.2.2c-1.5-.9-3.2-1.6-4.8-2-1.7-.5-3.3-.7-5-.7l.3-2.9z"/>
<path d="M78.3 176.2c-2.4.8-4.4 2.4-6.4 4-1 .8-1.9 1.7-2.9 2.5s-2 1.7-3.2 2.5l-1.4-2.7c1-.4 2.1-1.1 3.2-1.7 1.1-.6 2.2-1.3 3.3-2 2.3-1.3 4.6-2.5 7.2-2.9l.2.3z"/>
<path d="M6.2 177c2.5-1.9 5.3-3.2 8.3-4.4a40 40 0 019.2-2.3c3.1-.4 6.4-.3 9.5.2 3.1.4 6.2 1.4 9.1 2.3 1.5.5 2.9.9 4.3 1.1 1.4.2 2.9.3 4.4.3.7 0 1.5 0 2.3-.1l2.3-.2c1.5-.1 2.9-.5 4.3-.9 2.8-.9 5.6-2.2 8.3-3.7 2.7-1.5 5.2-3.2 7.7-5.1l.3.3c-2.2 2.2-4.6 4.2-7.2 6-2.6 1.8-5.3 3.4-8.4 4.5-1.5.6-3.1 1-4.7 1.2l-2.3.3c-.8.1-1.6.1-2.4.2-1.6.1-3.2 0-4.9-.3-1.6-.3-3.2-.7-4.7-1.2-5.8-2-11.7-3.5-17.7-3.1-3 .2-6 .7-9 1.6-3 .9-5.9 1.9-8.7 3.3z"/>
<path d="M136.5 144.2c-.5 1.1-1.1 2.1-1.9 2.9-.8.8-1.8 1.5-3 1.9-1.2.4-2.5.5-3.7.2-1.2-.3-2.4-1.1-2.8-2.3 1.2.2 2.1.1 3 0 .9-.2 1.7-.4 2.6-.7.9-.3 1.7-.6 2.7-1 .9-.5 1.9-.9 3.1-1z"/>
<path d="M122.1 152.3c-.7 1.6-1.5 3.1-2.7 4.4-1.1 1.3-2.6 2.5-4.3 3.3-1.7.8-3.8.9-5.6.5-1.8-.4-3.4-1.3-4.6-2.6 1.8.1 3.4.3 4.9.2 1.5-.1 2.9-.4 4.2-.9 1.3-.6 2.6-1.4 3.9-2.3 1.3-.8 2.7-1.8 4.2-2.6z"/>
<path d="M104.9 166.5c.8 1 1.1 2.3 1 3.6-.1 1.3-.5 2.5-1.2 3.5s-1.6 1.9-2.7 2.5c-1.1.6-2.4.9-3.6.7.8-.9 1.5-1.7 2.1-2.5.6-.8 1.2-1.5 1.7-2.3.5-.8 1-1.6 1.5-2.5.4-.9.8-1.8 1.2-3z"/>
<path d="M97.9 184c1.3.7 2.3 2.1 2.8 3.6s.5 3.2.1 4.7-1.2 3-2.4 4c-1.2 1.1-2.4 1.5-3.6 2.4 0-.8.4-1.5.8-2.1.4-.6.7-1.2 1-1.7a15.07 15.07 0 001.3-10.9z"/>
<path d="M81.2 234.7c2 1.1 3.7 2.4 5.4 3.9 1.6 1.5 3 3.3 4.1 5.4 1 2.1 1.6 4.5 1.4 6.8-.1 2.3-1 4.7-2.7 6.2.6-2.2.7-4.2.4-6.1-.3-1.9-.9-3.8-1.8-5.6-.9-1.8-2-3.5-3.2-5.2-1.2-1.7-2.5-3.4-3.6-5.4z"/>
<path d="M101.4 260.4c1.8 1.5 3.2 3.3 4.5 5.2 1.3 1.9 2.3 4 3.1 6.2.8 2.1 1.4 4.5 1.3 7 0 1.2-.3 2.5-.8 3.6a6.3 6.3 0 01-2.4 2.7c1.2-2 1.2-4.1.9-6.1-.3-2.1-1-4-1.7-6.1-.7-2-1.5-4.1-2.3-6.1-1-2.2-1.8-4.2-2.6-6.4z"/>
<path d="M72.8 262.5c-.2.4-.1.8.1 1.2.2.4.4.7.7 1l1.7 2.2c1.1 1.5 2.2 3 3 4.8a13 13 0 011.2 5.9c-.1 2-.9 4.2-2.5 5.3.5-1.9.5-3.6.2-5.2-.3-1.7-.9-3.2-1.6-4.8-.7-1.6-1.6-3.2-2.3-4.9-.4-.9-.7-1.8-1-2.7-.1-.4-.3-1-.2-1.5 0-.3.1-.6.2-.8.1-.2.3-.4.5-.5z"/>
<path d="M58.1 234.8c.8 1.7 1.2 3.3 1.8 4.8.6 1.5 1.3 2.8 2.2 3.9.9 1.1 2.3 2.1 3.6 3.4.6.6 1.3 1.4 1.7 2.2.4.9.7 1.9.5 2.8-.9-1.6-2.2-2.3-3.7-3.2-1.4-.8-3-1.7-4.4-3.2-1.3-1.5-2-3.5-2.2-5.3-.2-1.8 0-3.6.5-5.4z"/>
<path d="M88.4 137.3c-1.3.1-2.5.1-3.6.1l-3.4-.1-3.4-.1c-1.2-.1-2.3-.1-3.6-.3 1-.8 2.2-1.3 3.4-1.6 1.2-.3 2.5-.5 3.7-.4 1.3 0 2.5.3 3.7.7 1.1.2 2.3.8 3.2 1.7z"/>
<path d="M79.3 128.3c-1.5.4-2.9.9-4.2 1.5-1.3.6-2.4 1.3-3.4 2.2-.5.4-1 .9-1.5 1.4-.5.5-1 1.1-1.6 1.6-.6.5-1.3 1.1-2 1.4-.8.4-1.7.5-2.5.3 1.5-.7 2.2-1.8 3-3 .4-.6.8-1.2 1.3-1.9.5-.6 1.1-1.3 1.7-1.8 1.3-1.1 2.8-1.8 4.4-2.2 1.6-.2 3.3-.1 4.8.5z"/>
<path d="M37.1 208.5c-.8 1.4-1.5 2.7-2 4-.5 1.3-.9 2.6-1.2 3.9-.3 1.3-.5 2.7-.5 4.1-.1 1.4 0 2.8.2 4.5-1.3-1-2.1-2.6-2.5-4.2-.4-1.6-.4-3.4-.1-5 .4-1.6 1.1-3.2 2.1-4.5 1-1.3 2.4-2.4 4-2.8z"/>
<path d="M29.7 243.9c.1 1.1 0 2.1-.1 3.1-.1.9-.3 1.8-.5 2.7-.2.9-.5 1.7-.8 2.6-.3.9-.7 1.8-1.4 2.7-.6-1-.9-2-1-3-.1-1 0-2.1.3-3.1s.7-1.9 1.2-2.8c.5-.9 1.3-1.7 2.3-2.2z"/>
<path d="M30.9 263.2c-.7 1.8-1.4 3.5-2 5.3-.6 1.7-1.1 3.4-1.5 5.1-.4 1.7-.8 3.5-1 5.3-.3 1.8-.4 3.6-.6 5.6-1-1.7-1.5-3.7-1.7-5.6-.2-2 0-4 .4-5.9.5-1.9 1.3-3.8 2.3-5.5 1.1-1.7 2.4-3.2 4.1-4.3z"/>
<path d="M49 244c-.6.6-.8 1.4-1.1 2.1-.2.8-.5 1.5-.6 2.3-.4 1.6-.7 3-.8 4.6-.2 1.6-.5 3.3-1 4.8-.5 1.6-1.2 3.1-2.2 4.5-.2-1.7-.1-3.3.1-5 .2-1.6.4-3.2.7-4.8.3-1.7.9-3.3 1.6-4.8.4-.7.8-1.5 1.4-2.2.5-.6 1.1-1.3 1.9-1.5z"/>
<path d="M100 224.4c-.1 3.2.6 6.3 2.1 8.9 1.5 2.6 3.7 4.8 6.3 6.6 2.5 1.7 5.3 3.1 8.2 4.2 2.9 1.1 5.9 2 8.9 2.6l-.7 2.9c-3.1-.8-6.3-1.8-9.3-3.1-3-1.3-5.9-2.9-8.4-5-2.6-2-4.9-4.6-6.3-7.6-1.3-2.9-1.7-6.4-.8-9.5z"/>
<path d="M199.2 242.7c-2.1.2-4.3.2-6.4-.5-2.1-.7-3.8-1.8-5.5-2.8-1.6-1.1-3.3-2.1-4.9-3.1-1.7-1-3.4-1.9-5.1-2.9 2 .3 3.9.9 5.7 1.6 1.8.8 3.6 1.7 5.4 2.5a22 22 0 005.1 2.1c.9.2 1.7.3 2.6.3l1.3-.1 1.3-.1.5 3z"/>
<path d="M90 198.9c-.1 1.2-.6 2.3-1.4 3.1-.7.9-1.7 1.6-2.6 2.1-1 .5-2 .8-3.1 1-1.1.1-2.2.2-3.3-.1.8-.9 1.7-1.5 2.5-2.1.9-.6 1.7-1 2.5-1.4.8-.4 1.7-.8 2.5-1.2l2.9-1.4z"/>
<path d="M136.7 206.1c1.2-.2 2.3-.1 3.4.3s2.1.9 3 1.6c.9.7 1.6 1.6 2.2 2.6.6 1 .9 2.1.9 3.3-1.1-.6-1.9-1.2-2.7-1.8-.8-.6-1.6-1.2-2.3-1.8-.7-.6-1.5-1.2-2.2-1.9-.7-.7-1.5-1.4-2.3-2.3z"/>
<path d="M145.8 217.9c.8.5 1.4 1.2 1.9 1.9a7.71 7.71 0 011.1 5.2c-.1.9-.4 1.8-.9 2.5-.3-.9-.5-1.7-.6-2.5l-.5-2.3-.5-2.3c-.2-.8-.4-1.6-.5-2.5z"/>
<path d="M-8.4 393.2c1-1.4 1.6-3.3 2-5.2.4-1.9.6-3.9.8-6 .5-4.1 1-8.2 2.7-12l.3.1C-3.9 374-4 378-4 382.1c0 2 0 4.1-.2 6.2-.2 2.1-.6 4.3-1.7 6.4l-2.5-1.5z"/>
<path d="M9.5 429.2c-.4-2-.4-4-.2-5.9.2-1.9.7-3.7 1.2-5.5.5-1.8 1-3.5 1.4-5.3.4-1.7.5-3.6.2-5.3l.3-.1c.6 1.8.7 3.7.5 5.5-.2 1.9-.5 3.7-.8 5.5-.3 1.8-.5 3.6-.5 5.3 0 1.7.2 3.4.7 5l-2.8.8z"/>
<path d="M-19.1 353c1.4-1 2.7-2.1 3.8-3.4 1.1-1.3 1.9-2.9 2.4-4.5.5-1.7.8-3.5 1.1-5.3.3-1.8.7-3.7 1.5-5.4l.3.1c-.6 1.7-.7 3.6-.8 5.4-.1 1.8-.1 3.7-.5 5.6-.3 1.9-1 3.8-2.1 5.5a23.8 23.8 0 01-3.9 4.5l-1.8-2.5z"/>
<path d="M-11.1 314.8c1.1-.8 2.2-1.8 3.1-3 1-1.1 1.8-2.4 2.8-3.7 1-1.3 2-2.5 3.3-3.5 1.2-1 2.6-1.8 4.1-2.4l.1.3c-1.3.8-2.5 1.8-3.5 2.9-1 1.1-1.8 2.4-2.6 3.7-.8 1.3-1.4 2.7-2.3 4.1-.8 1.4-1.9 2.7-3.1 3.9l-1.9-2.3z"/>
<path d="M12.1 380.3c1.6-1.5 3-3 4.2-4.6 1.3-1.6 2.4-3.2 3.3-4.9 1-1.7 1.8-3.5 2.5-5.4.7-1.9 1.3-3.9 1.8-6 .7 2.1.8 4.4.5 6.6-.3 2.2-1.1 4.4-2.2 6.3-1.1 1.9-2.6 3.7-4.3 5.1-1.7 1.4-3.7 2.5-5.8 2.9z"/>
<path d="M19.2 303.7c-1.6 1.5-3.1 2.9-4.5 4.4a42.9 42.9 0 00-3.6 4.8c-1.1 1.7-2 3.4-2.8 5.3-.8 1.8-1.5 3.8-2.1 5.9-.6-2.1-.6-4.4-.2-6.6.4-2.2 1.3-4.3 2.5-6.2 1.2-1.9 2.8-3.6 4.5-4.9 2-1.4 4-2.4 6.2-2.7z"/>
<path d="M18.1 332c-1.1 1.9-2.2 3.6-3 5.5-.8 1.8-1.5 3.7-2.1 5.6-.5 1.9-.9 3.8-1.1 5.8-.2 2-.3 4-.3 6.2-1.2-1.9-1.8-4-2-6.3a18.56 18.56 0 013.5-12.6c1.3-1.7 3-3.3 5-4.2z"/>
<path d="M35.2 387.7c-.5 2.1-1 4.1-1.3 6.1-.3 2-.6 3.9-.7 5.9-.1 2-.1 3.9 0 5.9.1 2 .3 4 .5 6.2-1.4-1.7-2.3-3.7-2.9-5.8-.6-2.1-.8-4.3-.6-6.5.1-2.2.6-4.3 1.4-6.4.9-2.1 2-3.9 3.6-5.4z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 28 KiB

13
charges/anvil.svg Normal file
View file

@ -0,0 +1,13 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="#d7374a" stroke="#000" viewBox="50 50 200 200">
<metadata source="http://wappenwiki.org/images/e/e1/Dwight_D._Eisenhower.svg" license="https://creativecommons.org/licenses/by-nc-sa/3.0"/>
<g id="anvil" stroke-width=".5">
<path d="m 111,116 6,5 v 9 c 0,0 0,1 -1,1 h -11 v -1 c -1,-1 -5.1,-4 -10,-4 -5,0 -10,3 -11,4 0,1 -0.5,1 -0.5,1 h -10 c -0.5,0 -1,-1 -1,-1 v -9 l 5.1,-5 7.9,-3 c 1.2,-2 1,-3 1,-6 0,-11 -12,-15 -22,-16 C 63,91 62,89.4 62,87.9 v -6.2 c 0,-0.9 0.5,-1.5 1.6,-1.5 H 108 c 1,0 2,0.6 2,1.5 v 0.6 c 0,1 0,1.5 1,1.5 h 2 c 1,0 1,0 1,0.5 v 1 c 4,0 26,0 26,0.6 0,5.6 -7,13 -18,14 -10,2.1 -19,3.1 -19,10.1 0,4 4,4 8,6 z"/>
<g fill="#000" stroke="none">
<path d="m 107,87 c 0,-2.2 -1,-3.6 -3,-3.6 H 86 v 16.5 c -0.6,-1.6 -0.6,-3 -0.6,-4 v -13 H 104 c 3,0.1 3,2 3,4.1 z"/>
<path d="m113 96c0-3-1-8.3 3-8.7l20-.5-20 1c-3 .2-3 5.2-3 8.2z"/>
<path d="m105 127c-8-5-14-4-22 0 7-5 16-5 22 0z"/>
<path d="m 79,118 c 2.8,-2 6.5,-4 7.2,-7 h 0.4 c -0.3,3 -5,6 -7.6,7 z"/>
<path d="m 110,118 c -4,-2 -6,-4 -7,-7 h 0 c 0,3 3,6 7,7 z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

8
charges/apple.svg Normal file
View file

@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="#d7374a" stroke="#000" viewBox="50 50 200 200">
<metadata source="http://wappenwiki.org/images/f/f1/Abildgaard.svg" license="https://creativecommons.org/licenses/by-nc-sa/3.0"/>
<g id="apple" stroke-width="1">
<path d="M80.96 73.92c-1.92 0-5.44.64-8.32 2.56-5.12 3.2-9.6 11.84-9.6 22.08 0 11.52 4.8 23.04 10.88 30.4 5.44 6.08 12.16 8.32 14.4 8.32 5.12 0 6.4-1.6 11.2-1.6s6.08 1.6 11.2 1.6c2.24 0 8.96-2.24 14.4-8.32 6.08-7.36 10.88-18.88 10.88-30.4 0-10.24-4.48-18.88-9.6-22.08a16.3 16.3 0 00-8.32-2.56c-5.44 0-12.8 3.52-18.56 3.52s-13.12-3.52-18.56-3.52z"/>
<path fill="none" stroke-width=".5" d="M90.56 135.36c10.56-3.84 11.2-1.6 17.92-.32"/>
<path fill="#328A35" d="M100.48 79.68s.32-3.52-.64-8.64c-1.28-5.44-2.88-8-2.88-8s-.32-.64-1.92-.32c-1.28.32-1.28 1.28-1.28 1.28s2.24 1.92 3.84 7.36c1.28 4.48 1.28 8.32 1.28 8.32s.32.32.96.32.64-.32.64-.32z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 927 B

220
charges/basilisk.svg Normal file
View file

@ -0,0 +1,220 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="#d7374a" stroke="#000" viewBox="50 50 200 200">
<metadata source="http://wappenwiki.org/images/d/d7/Kazan.svg" license="https://creativecommons.org/licenses/by-nc-sa/3.0" />
<g id="basilisk" stroke-width=".33">
<path d="M85.99 134.15c.15.02.7.06.82.14.38.29.74 1.14.6 2.04-.17 1.04-.85 2.05-1.06 2.03-.28-.04-.28-.44-.28-.65.02-.56.26-.92-.34-1.68-.22-.28-.59-.44-.72-.77-.02-.05.04-.19.05-.24 0-.1.06-.2.11-.29.19-.28.47-.61.82-.58z"/>
<path d="M76.82 127.7a1.38 1.38 0 00-.8-.47 2.95 2.95 0 00-1.56.27c-.57.24-1.5.94-1.5 1.54-.02.55.27.31.59.15.41-.22.88-.4 1.67-.19.53.14.7.5.89.62h.22"/>
<path d="M77.12 123.67c.02-.16.14-.69.09-.84-.18-.44-.88-1.02-1.8-1.13-1.05-.13-2.2.25-2.24.46-.03.28.34.39.55.44.55.14.96.01 1.53.78.21.29.25.7.54.91.04.04.19 0 .24.03.1.02.21 0 .31-.04.32-.1.73-.26.78-.61z"/>
<path d="M76.48 125.88c-.16-.05-.25.04-.4 0-.34-.09-.56-.36-.75-.68-.11-.2-.28-.87.15-1 .23-.07 1 .04 1.52-.83.13-.23.17-.64.17-.64s.27-.36.74.13c.53.56.38 1.25.38 1.25.35.28.41.9.62 1.07.1.08.2.13.31.2.54.31.78.74 1.17 1.2.14.14.88.85 1.08.93.16.05.57.34.74.35.3.03.17-.12.49-.06-.05.5-.82.39-1.21.7-.25.2-.54.37-.86.4-.4.05-.8-.16-1.15-.38a8.98 8.98 0 01-1.87-1.6c-.11-.14-.24-.26-.21-.44-.32-.23-.49-.67-1.16-.78"/>
<path d="M74.81 124.55c-.01-.16-.02-.7-.12-.83-.27-.38-1.1-.78-2.01-.67-1.06.12-2.1.77-2.07.98.03.27.43.3.64.3.56 0 .93-.22 1.67.4.27.22.42.6.74.75.04.02.18-.04.24-.04.1 0 .2-.06.28-.1.31-.18.65-.44.63-.8z"/>
<path d="M85.32 131.47c-.14-1.3-.25-1.2.5-1.96 4.97-5.02 8.8-7.36 8.37-6.91l-4.07-2.25c-.75 1.36-1.47 3.79-5.57 6.7-.54.39-.84.3-1.23.57-.97.35-1.66-.29-2.47-.6-.48-.2-1.16-.1-1.33-.13-.21-.02-.42-.1-.58-.22-.49-.35-.82-.73-1.41-.9l-.34-.11c-.26-.12-.73-.73-1.17-.95 0 0-.02-.7-.66-1.1-.57-.38-.75.05-.75.05s.08.4 0 .66c-.3.96-1.06 1.04-1.27 1.16-.39.23-.07.86.08 1.01.27.27.54.48.9.49.16 0 .32-.18.48-.18.68-.03.86.31 1.22.46.4.18.84.37.78.94-.06.67-.6 1.09-.75 1.3-.2.32-.2.79.53 1.04.54.19 1-.02 1.22-.27.07-.07.18-.08.27-.1.12-.02.24 0 .37 0 .73.12 1.45-.27 2.12.1.16.1.29.2.44.28.18.1.39.15.57.22l.25.13c.3.25.37.7.55 1.04.13.23.36.38.56.57.43.4.77 1.08.75 1.68 0 .17-.11.23-.11.4-.01.35.18.64.45.91.15.17.76.5 1 .13.13-.2.23-.96 1.2-1.23.26-.06.67.02.67.02s.43-.16.08-.74c-.4-.66-1.1-.7-1.1-.7a5.34 5.34 0 01-.55-1.51z"/>
<path fill="none" d="M76.01 127.24c1.09-.93 1.93.16 1.97.55.01.09.22.09.3.08.18-.05.36-.02.54-.01"/>
<path d="M101.3 118.29a5.39 5.39 0 01-1.34 2.04c-.27.24-.8.83-1.07 1.05a6.02 6.02 0 00-1.4 2.09c-.22.46-.52.9-.85 1.3-.37.43-.8.79-1.1 1.27-.21.38-.33.82-.33 1.25-.63-.15-1.3-.8-1.38-1.36-.78.6-1.29 1.66-2.11 2.04-.06.02-.13-.05-.08-.08a5.23 5.23 0 01.35-2.54c.21-.42.54-.77.73-1.2s.2-.98-.13-1.3a4.31 4.31 0 01-3.21 1.85c.44-.96.73-2.09.68-3.14 0-.1-.04-.21-.12-.22-.05-.02-.08 0-.12.02-.36.15-.74.24-1.08.42-.7.37-1.8.68-2.5.41.46-.27.86-.57 1.18-1.1.2-.35.26-1 .55-1.3s.55-.68.61-1.08a2.21 2.21 0 01-1.88.08c.5-.45.93-1 1.22-1.62.1-.22.64-2.45 1.18-3.16.5-1.43 2.01-2.49 3.43-3.47"/>
<path d="M106.41 64.41c.21-1.04-.9-.92-.41-2.77-.11-.04-1.85.43-1.46 2.76"/>
<path d="M111.81 75c1-.41.28-1.27 2.08-1.89-.03-.1-1.37-1.3-3.1.3"/>
<path d="M114.03 84.2c1.04-.25.47-1.21 2.34-1.54-.02-.12-1.16-1.5-3.11-.18"/>
<path d="M96.25 98.4c.66-.44 1.32-.99 1.43-1.76 0-.55-.11-1.1-.44-1.54-.11-.33-.44-.55-.55-.88-.33-.77.22-1.54 0-2.2-.88-1.32-1.76-1.1-1.87-1.98s-.33-.99-.66-1.76c-.11-.44-.33-.66-.44-1.21 0-.55.11-1.54.66-2.09 1.1-1.32 2.31-1.21 3.96-3.19 1.98-2.37 2.97-5.46 3.85-8.42.66-1.9.99-3.83 1.1-5.8.11-1.07.55-2.95 1.1-3.6.66.1 1.32.14 2.09-.28.33.65.33 1.46.33 2.2 5.5 15.3 10.56 24.48-.55 40.43-18.26-3.63-19.91-.88-10.01-7.92z"/>
<path d="M87.09 75.93c-1.21-.27-2.41.2-3.58-.2-1.18-.43-1.88-1.53-3.09-1.85-.85-.23-1.77-.08-2.73-.46-1.06-.44-1.6-.8-2.63-1.45-.79-.64-1.89-.77-2.9-.7-.34.02-.67.05-1.01.02-.59-.07-1.14-.35-1.7-.49-.76-.2-1.54-.16-2.3-.2s-1.58-.2-2.18-.67c-.63-.5-.82-1.35-2-1.53.94 1.02.82 2.25 1.61 3.08.8.85 1.87 1.06 3.01 1.2 1.73.2 3.47-.1 3.73 1.23-.59 1.56-3.07.93-3.5.88-1.31-.14-2 .04-2.5.46-.5.4-.75 1.15-.75 1.77.6-.56 1.22-.78 2.13-.6.66.11 1.28.39 1.94.53.57.12 1.03.25 1.62.25.79 0 1.5-.33 2.19-.7.58-.32.81-.58 1.35-1 .83-.63 1.64-.43 2.14 0 .36.33.49.8.25 1.23-.24.43-.68.7-1.12.9-.45.18-1.82.56-2.36 1.63-.96 1.91.04 3.1-1.29 4.53 3.86-.89 3.16-3.86 4.97-4.4 1.45-.5 1.89-1.89 2.86-1.82.6.04 1.21-.3 1.79-.14.2.06.4.16.6.22 1.05.35 3.36-.05 4.35.44l1.34.55-.24-2.71z"/>
<path d="M82.34 71.53c-1.15-.38-2.55.46-3.68.15-.66-.18-1.03-1.35-1.8-1.56-1.03-.29-1.7.33-1.9.8-.1.2-.34.17-.38-.08-.01-.03-.28-1 .9-2.42 1.6-1.93 4.51-1.8 5.67-1.4.77-.63 1.95-.16 2.08.05-.1.2-.77 2.38-.11 2.82 1.69 1.14 1.3 2.07 3.71 3.39.9.48 1 1.36 1.2 2.37.15 1.12-.27 1.58.01 2.77.12.6-.25.83-.82.97-.66.16-1.22-.12-1.92.05-2.1.4-2.13 1.56-4.38 2.02-.8.11-1.63-.14-2.02-.68-.37-.57-.4-1-.4-1 .03-.12 0-.26.18-.01.73.94 2.62.41 3.3-.05.9-.45 1.7-1.43 2.9-1.7 1.02-.3 2.03-.02 2.03-.21 0-.12.04-.53-.1-.94-.05-.15-.1-.3-.13-.46-.02-.2.02-.99-.01-1.19-.19-1.14-1.05-.87-2.26-2-.66-.55-1.18-1.4-2.08-1.7z"/>
<path d="M124.32 96.3c.33-2.06 1.66-3.8 2.92-5.46s2.1-3.37 2.66-5.55c1.73 2.18 1.23 5.28 1.23 5.28 2.29-1.35 3.03-3.68 2.9-6.61-.05-1.3-.57-3.41-.26-5.68a15.9 15.9 0 013.1-7.84 15.1 15.1 0 00-8.5 6.6c-.58 1-1.04 2.04-1.64 3.02-1.25 2.03-3.05 3.63-4.83 5.2 1.78.66 4.26.56 6.04-.1-.71 1.8-2.5 2.66-4.13 4.13s-3.25 3.16-3.73 5.3"/>
<path d="M132.77 99.72a3.35 3.35 0 00-.88-1.76v-.11c-.11-1.1-.99-2.53-2.2-3.52-.66-.44-2.31-1.54-3.08-1.32-1.32-.77-5.61-1.1-7.15.11-2.2-.11-4.07 1.1-5.94 2.2-4.51 1.76-10.23 2.97-15.18 4.29-.33-1.43-4.18-2.64-5.28-2.42-.77-1.1-1.87-1.21-3.08-1.87.88-1.32-.22-3.19-.44-5.06-.22-1.21-.44-2.53.33-3.63.55-.77 1.54-2.31 1.54-3.41.55.44 1.65.55 2.09 0-.66-.25-1.21-1.25-.77-2.06.99-1.76.77-2.54.66-3.62a3 3 0 01.77.8c.44-.56.77-1.68.66-2.56.88.69 1.98.54 2.31.37-1.65-1.25-.33-2.79-.22-3.95.22-1.35 0-2.1-.22-2.42a2.05 2.05 0 001.54-1.34c.22-.7 0-1.46-.11-1.62-.66.6-1.87.8-2.64.5-.88-.32-1.54-1.12-2.53-1.31l-8.14-.26c-.33.02-.66.3-.88.59-.22.28-.55.48-.66.74-.11.2-.77 2.38-.11 2.82 1.65 1.13 1.21 2.06 3.63 3.38.99.48 1.1 1.36 1.21 2.37.22 1.12-.22 1.58 0 2.77.22.6-.22.83-.77.97-.66.16-1.21-.12-1.87.05-.22.78-.66 1.1-1.32 1.57-1.32.99-2.53 3.09-4.62 2.32-.11.44.11 1.21.77 1.54-.55.22-1.32.44-1.76.88a6.3 6.3 0 00-1.21 1.21c-.33.55-.55 1.1-.44 1.65-.77.44-1.65.99-2.2 1.76-.66.77-1.32 1.65-1.21 2.75-.22.22-.66.55-.77.88a6.11 6.11 0 00-.99 1.87c-.22.77-.33 3.19.11 3.96.33.55-.33 3.19.77 4.51 0 .44.55 3.63 1.98 4.62a5.2 5.2 0 003.85 3.52 5.1 5.1 0 001.76 1.98c.66.44 1.65.88 2.42 1.21 1.32 1.43 3.08 1.98 5.06 2.2 2.2.88 4.73.88 6.93.11 1.98.55 4.07.33 6.05-.22 2.09 0 4.18-.99 5.72-2.09 1.43-.88 2.97-1.54 4.07-2.75 1.21-1.32 3.08-1.76 4.07-3.19a5.9 5.9 0 001.65-1.65 5.15 5.15 0 001.98 2.42c.77.22 2.31.77 2.86.66.22.33.77.55 1.1.66s1.1 0 1.43 0c.44.11.99.11 1.54.11.33 0 .66 0 .99-.11.22-.11.33-.22.55-.33s.44-.22.77-.33c.55-.33 1.21-.33 1.76-.77s1.1-1.32 1.54-1.65c.33-.33.66-.66.88-.99.33-.44.55-1.32.77-1.87a8.02 8.02 0 00.55-6.16zM124.3 105c-.55-.33-1.76-.44-2.31-.33a2.68 2.68 0 00-1.43-1.87c.11-.22.22-.44.33-.77a4.51 4.51 0 001.76-1.76c.55 0 1.1-.22 1.65-.44 0 .77.55 1.54 1.32 1.65-.11.44 0 .99.33 1.32a4.07 4.07 0 00-1.65 2.2z"/>
<g stroke-width=".24">
<path d="M91 62.3c0 .03 0 .04-.03.04-.28.46-.85 1.21-1.74 1.08-1.1-.14-1.78-1.3-1.78-1.3s-.39 1.14-1.66.96c-.72-.11-1.52-1.42-1.52-1.42s.44 2.55.45 3.77c1.05.42-.17-.36 5.74.47 5.92.83 4.61 1.32 5.64 1.13.44-1.17 1.82-3.44 1.82-3.44s-1.2 1-1.93.9c-1.28-.19-1.26-1.5-1.26-1.5s-1.04 1.05-2.14.88c-.94-.14-1.21-1.09-1.29-1.6l-.3.04z"/>
<path d="M97.06 65.6l-.2-.02c-.07-.04-.16-.05-.28-.07-.9-.25-2.98-.83-5.79-1.2-2.79-.38-4.98-.42-5.9-.44l-.31-.01c-.3-.01-.4-.18-.4-.3.01-.15.13-.26.34-.27l.1-.01h.06c.64-.01 2.57-.07 6.23.45s5.5 1.1 6.09 1.28l.09.04a.4.4 0 01.28.19c.05.06.05.13.01.2a.49.49 0 01-.32.16z"/>
<path d="M96.27 67.4h-.12c-.19 0-.7-.16-.89-.22a58.4 58.4 0 00-9.99-1.4H84.37c-.15-.05-.29-.1-.28-.3.02-.13.1-.28.31-.29l.1-.01a51.14 51.14 0 0111.67 1.65c.15.02.21.09.27.18.04.06.04.15 0 .22 0 .07-.04.16-.17.17z"/>
<path d="M87.3 64.98h-.1c-.22-.04-.39-.2-.34-.4.02-.15.18-.27.36-.28a.3.3 0 01.1.01c.23.03.4.2.35.39-.01.14-.15.26-.36.28z"/>
<path d="M84.77 64.84c-.25 0-.44-.14-.48-.33a.24.24 0 01.08-.21.4.4 0 01.26-.12h.04c.06 0 .16.14.2.33 0 .13-.03.26-.07.3.02.02 0 .02-.03.03z"/>
<path d="M93.88 65.9h-.1c-.23-.04-.39-.2-.35-.39.03-.15.2-.28.37-.29a.3.3 0 01.1.02c.23.03.4.2.35.38-.02.17-.18.28-.37.29z"/>
<path d="M90.88 65.4c-.12.01-.25 0-.37-.01a1.46 1.46 0 01-.64-.23c-.14-.1-.22-.21-.2-.31.01-.15.27-.27.6-.3l.37.01c.26.04.47.13.64.24.14.1.22.2.2.3-.03.16-.28.28-.6.3z"/>
<path d="M96.46 66.51a.87.87 0 01-.19-.02c-.03-.01-.03-.03-.03-.03-.04-.07-.01-.18.04-.31.08-.17.21-.28.28-.28h.03c.12.02.21.11.25.19.05.09.05.15 0 .22a.48.48 0 01-.38.23z"/>
<path d="M96.2 64.56c-.13.02-.25 0-.37 0-.93-.15-1.24-.8-1.32-1.17-.26.2-.82.55-1.5.6-.16 0-.31 0-.47-.03-.96-.12-1.4-.9-1.55-1.34-.25.3-.76.82-1.5.87l-.33-.01a2.63 2.63 0 01-1.69-1.1c-.16.3-.57.73-1.27.78l-.4-.01c-1.17-.17-1.7-1.46-1.73-1.51-.02-.03-.02-.06 0-.07l.06-.42c0-.05.04-.08.1-.1h.03c.06 0 .11.03.12.07 0 .02.63 1.23 1.55 1.37l.19.02c.52-.04.8-.54.99-.84l.01-.03c.08-.12.14-.23.28-.24s.23.08.34.25l.13.16c.28.38.65.9 1.34 1l.22.03c.87-.06 1.33-1.21 1.35-1.22.04-.06.07-.1.11-.1h.04l.48.07c.07.02.11.07.11.14 0 .02.04 1.43 1.07 1.56.1.03.2.02.33 0 .55-.02.99-.34 1.3-.57l.17-.14c.15-.1.23-.13.32-.14.22-.01.28.22.3.33v.03c.07.38.2 1.03.81 1.1.09.02.16.03.27.03.85-.06 1.79-.92 1.81-.92.03-.02.04-.03.09-.04l.06.01c.06.03.1.08.08.13l-.03.49c0 .03-.04.06-.04.08-.02.02-.86.82-1.85.88z"/>
<path d="M86.34 61.19c-.03-.17.03-.86-.8-.85-.4.01-.68.37-1.07.58.2-.43.76-.73.71-1.1-.1-.68-1-.51-1.25-.51.1.71.16 1.45.19 1.76-.1.02.05.34.05.34.83-.03 1.02.67 1.63.65.81-.02.56-.69.54-.87z"/>
<path d="M91.25 61.75c.53.27.8.8 1.3.89.8.13.76-.6.79-.77.02-.18.31-.85-.5-.97-.42-.05-.8.24-1.24.4.34-.39.98-.56 1.03-.95.11-.68-.86-.7-1.1-.74s-1.15-.3-1.26.38c-.07.38.48.75.68 1.2-.4-.28-.65-.67-1.05-.73-.81-.13-.79.58-.81.77-.02.18-.29.85.53.98.48.07.92-.37 1.54-.44l.09-.01v-.01z"/>
<path d="M98.93 61.36c-.23-.06-1.06-.51-1.36.12-.19.36.26.85.3 1.32-.29-.36-.42-.79-.83-.92-.77-.28-.96.44-1.02.6-.08.17-.54.78.22 1.07.56.21 1.26-.4 1.81-.15 0 0 .2-.29.14-.33l.74-1.7z"/>
<path d="M98.26 62.84c-.14-.06-.37.1-.5.36-.14.25-.14.47.03.53.32.1.67-.01.8-.25.12-.27-.02-.54-.33-.64z"/>
<path d="M84.15 60.93c.15 0 .3.21.36.48.04.27-.03.5-.2.5-.34 0-.63-.2-.68-.48-.05-.25.19-.5.52-.5z"/>
<path d="M91.26 61.24c-.37-.06-.7.13-.75.43-.05.3.18.57.56.62.36.06.7-.13.75-.43.06-.28-.2-.55-.56-.62z"/>
</g>
<path fill="none" d="M116.04 108.1c.56-.67 1.08-1.37 1.52-2.11a7.64 7.64 0 002.94-3.19"/>
<path fill="#F6F6F6" d="M86.17 69.95c-1.98.22-1.92-1.6-1.89-1.78.22.02 1.84-.5 2.4-.24.32.22.71 1.85-.5 2.02z"/>
<path d="M112.09 65.96c.32-1.02-.8-1.01-.13-2.8-.11-.05-1.88.23-1.73 2.6"/>
<path d="M116.37 77.05c1.02-.3.4-1.23 2.26-1.65-.02-.11-1.23-1.44-3.1-.01"/>
<path d="M117.62 86.44c1.07-.14.6-1.15 2.5-1.28-.01-.13-.99-1.62-3.08-.5"/>
<path d="M115.9 97.06c.92.53 1.16-.56 2.76.5.06-.1.18-1.89-2.15-2.26"/>
<path d="M111.8 102.75c.53.93 1.3.12 2.12 1.83.1-.05 1.13-1.52-.69-3.03"/>
<path d="M106.97 106.7c.18 1.05 1.17.55 1.37 2.45.12-.01 1.58-1.05.4-3.1"/>
<path d="M100.78 107.64c-.2 1.06.91.92.45 2.77.11.04 1.84-.44 1.42-2.77"/>
<path d="M96.54 107.21c-.44.86.56 1.04-.32 2.52.08.06 1.71.09 1.93-2.05"/>
<path d="M92.23 105.56c-.56.8.41 1.1-.68 2.44.1.07 1.69.33 2.21-1.73"/>
<path d="M91.87 106.43c.18-.71-.36-1.26-.98-1.72-.4-.04-.77.25-1.14.41a.19.19 0 01-.13.02c-.07-.02-.1-.1-.11-.16-.23-1.1.07-2.31.82-3.15-.23-.2-.38-.7-.42-1-.17-1.4.7-2.67 2.67-2.67.1-.06.4.15.5.1.52-.19 1.1-.04 1.6.2s.96.53 1.5.68c.75.2 1.59.03 2.27-.37s1.42-.9 1.6-1.67a2.3 2.3 0 00-.21-1.57c-.17-.32-.41-.6-.52-.94-.23-.75.44-1.44.23-2.2-.67-1.34-1.66-1.2-1.67-2.13 0-.86-.15-1.02-.4-1.84-.14-.47-.33-.69-.33-1.2 0-.6.27-1.55.82-2.03 1.3-1.14 2.46-.98 4.3-2.76 2.24-2.15 3.56-5.12 4.77-7.98a24.71 24.71 0 001.68-5.65c.18-1.07.84-2.88 1.38-3.48.7.17 1.4.29 2.13-.05.3.7.18 1.48.15 2.23-.52 4.62.26 8 3.37 7.51a2.9 2.9 0 001.11 2.03 8.32 8.32 0 00-1.71 2.94c-.31.9-.4 2.45.2 3.3a2.59 2.59 0 002.05 1.13c-.06.63.33 1.54.93 1.77-2.68 1.46-3.16 7.26-1.43 9-.38.53-.5 1.47-.32 2.09-2.88.12-3.47 3.15-2.66 4.83-.63 0-1.18.88-1.31 1.34-3.46-.03-3.67 3.19-3.53 3.74-.5-.11-1.17.1-1.49.5-.56-.97-1.7-1.28-2.8-1-.94.22-1.86.95-2.06 2.53-.35-.25-1.21-.26-1.64-.25-.09-.45-.46-.91-.9-1.07s-1.48-.18-2.18.67c-.44-.33-.92-.35-1.45-.28a1.59 1.59 0 00-1.25-1.29c-1.02-.2-1.85.27-1.85.27a1.84 1.84 0 00-1.59-.83z"/>
<path d="M113.32 136.72c.12-.1.52-.46.68-.5.48-.06 1.34.26 1.89.99.64.84.9 2.03.72 2.18-.22.16-.5-.1-.66-.26-.4-.4-.5-.82-1.44-.92-.35-.03-.73.13-1.06-.01-.05-.02-.1-.17-.13-.2-.07-.08-.1-.18-.12-.28-.09-.35-.15-.78.12-1z"/>
<path d="M102.32 138.85a1.4 1.4 0 00-.9.25c-.44.35-.68.78-.9 1.3-.22.6-.35 1.74.08 2.16.4.4.42.03.51-.31.13-.47.32-.92 1.02-1.33.48-.3.85-.15 1.07-.21"/>
<path d="M99.62 135.82c-.1-.13-.4-.58-.54-.64-.44-.17-1.36-.06-2.06.51-.82.67-1.35 1.77-1.23 1.94.17.22.51.02.7-.1.49-.29.67-.67 1.63-.54.35.04.68.3 1.03.24.06-.01.14-.13.18-.17a.58.58 0 00.19-.24c.16-.3.32-.71.1-1z"/>
<path d="M100.77 137.82c-.14.1-.14.21-.28.3-.3.18-.65.16-1.02.07-.2-.06-.82-.41-.61-.8.1-.23.72-.69.45-1.67-.07-.25-.34-.56-.34-.56s-.08-.45.6-.45c.77.01 1.16.6 1.16.6.44-.06.93.33 1.22.3.12-.02.23-.06.35-.1.6-.17 1.08-.04 1.67 0 .21 0 1.23-.04 1.42-.14.16-.08.65-.17.78-.3.23-.18.04-.2.3-.38.32.37-.29.86-.34 1.35-.03.32-.1.65-.3.9-.25.33-.67.47-1.08.57a9.2 9.2 0 01-2.45.23c-.18-.01-.34-.01-.45-.15-.39.07-.81-.12-1.36.29"/>
<path d="M98.66 138.1c-.12-.1-.52-.46-.68-.5-.48-.06-1.33.26-1.88.98-.65.85-.9 2.04-.73 2.18.22.17.5-.1.66-.25.4-.4.5-.83 1.44-.93.35-.03.73.14 1.06 0 .05-.03.1-.17.13-.2.08-.08.1-.18.12-.28.09-.34.15-.77-.12-1z"/>
<path d="M110.92 135.34c-1.03-.8-1-1.36-1.2-2.4-1.4-6.92-1.2-11.4-1.06-10.8l-4.15 2.11c.72 1.38 2.32 3.34 2.44 8.37.01.66-.1 1.01-.18 1.48-.43.94-1.37 1-2.16 1.35-.47.2-.88.76-1.01.87-.17.13-.36.23-.57.26-.6.1-1.08.09-1.63.39-.11.05-.21.12-.32.16-.26.1-1.02.02-1.49.19 0 0-.51-.47-1.26-.3-.66.16-.48.58-.48.58s.34.24.47.47c.5.89 0 1.48-.05 1.72-.1.44.58.64.8.64.37 0 .71-.06.96-.3.13-.13.1-.36.21-.48.44-.52.82-.4 1.18-.55.4-.17.84-.35 1.21.09.44.51.36 1.19.42 1.45.08.35.42.68 1.1.33.52-.26.68-.74.66-1.07-.01-.1.06-.17.12-.25.07-.1.16-.18.26-.25.59-.45.82-1.25 1.55-1.47.17-.05.35-.07.51-.12.19-.05.36-.17.55-.25a.8.8 0 01.28-.09c.38-.05.75.22 1.12.32.26.07.53 0 .8-.01.6-.02 1.3.2 1.74.63.1.12.09.24.2.35.25.24.6.3.98.3.22 0 .89-.2.79-.63-.06-.23-.54-.84-.05-1.73.14-.23.48-.46.48-.46s.17-.43-.49-.58c-.75-.18-1.26.3-1.26.3a4.8 4.8 0 01-1.47-.62z"/>
<path fill="none" d="M101.42 139.1c.08-1.43 1.44-1.28 1.76-1.04.08.05.22-.1.26-.17.1-.15.22-.26.37-.38"/>
<path d="M109.04 113.83c.41.44.88 1.66.96 2.26.04.34.23 1.12.28 1.47.08.84.52 1.6.95 2.33.27.44.45.94.6 1.43.15.54.2 1.12.45 1.62.18.4.48.74.84.98-.46.44-1.38.63-1.89.39.07.99.66 2 .5 2.89 0 .06-.1.09-.1.02a5.28 5.28 0 01-1.9-1.7c-.24-.41-.35-.88-.59-1.28s-.7-.72-1.15-.62a4.32 4.32 0 01-.26 3.7 6.94 6.94 0 00-2.23-2.32c-.08-.05-.19-.09-.25-.02-.04.03-.04.07-.05.1-.06.38-.2.75-.25 1.13-.08.78-.44 1.87-1.04 2.3.03-.52 0-1.03-.26-1.58-.17-.37-.68-.78-.77-1.17-.09-.41-.26-.84-.56-1.13a2.18 2.18 0 01-.98 1.61 5.1 5.1 0 00-.67-1.92c-.12-.21-1.67-1.9-1.96-2.74-.9-1.22-.93-3.06-.95-4.79"/>
<g fill="#000" stroke="none">
<path d="M78.42 124.15c-.09.17-.19.32-.33.44a.82.82 0 01-.23.14 2.2 2.2 0 00-.23.11l.17-.17.16-.19c.07-.13.12-.28.14-.44l.32.11z"/>
<path d="M76.19 124.71c-.05.18-.11.35-.22.5-.06.08-.12.15-.2.2s-.13.1-.19.17c.03-.08.09-.15.13-.22s.08-.14.1-.22c.05-.14.05-.3.04-.46l.34.03z"/>
<path d="M78.14 127.72a2.13 2.13 0 01.04 1.03.99.99 0 01-.15.3c.05-.1.06-.2.06-.31s-.01-.21-.03-.32c-.05-.21-.12-.4-.22-.58l.3-.12z"/>
<path d="M78.83 127.68c.24.03.48.11.69.21l.32.14.32.16.3.16.3.15c.1.04.21.03.32.04.12.01.23.03.34.07-.1-.03-.23-.03-.34-.03-.1.01-.23.03-.35 0l-.34-.1-.32-.14c-.21-.09-.43-.14-.65-.2s-.42-.12-.64-.12l.05-.34z"/>
<path d="M83.27 131.44c0 .3.01.6.06.9s.13.56.26.8l-.3.13c-.1-.3-.14-.62-.14-.92.02-.31.08-.6.12-.9z"/>
<path d="M85.89 133.1a1.1 1.1 0 00-.46.03l-.22.08-.22.13.17-.2a.76.76 0 01.2-.17c.15-.1.33-.15.52-.2v.33z"/>
<path d="M87.56 125.91c-.13.38-.32.74-.57 1.06-.24.32-.55.6-.87.83s-.66.44-1 .64c-.32.21-.63.42-.88.73.06-.19.16-.38.3-.52.14-.15.3-.29.45-.42.3-.25.63-.46.94-.7s.6-.46.88-.73c.27-.28.5-.58.75-.89z"/>
<path d="M89.88 121.18a3.35 3.35 0 001.52-1l.6-.74c.2-.24.43-.47.7-.66-.25.21-.44.45-.63.7s-.35.54-.54.8a3.6 3.6 0 01-1.53 1.2l-.12-.3z"/>
<path d="M88.44 118.64c0-.11.11-.33.22-.44l.22.11c0 .11-.11.33-.11.44z"/>
<path d="M92.44 122.77a13.04 13.04 0 011.58-1.74c.2-.16.41-.32.51-.58-.07.26-.26.46-.45.63s-.34.38-.5.58-.29.42-.44.63a8 8 0 00-.41.65l-.29-.18z"/>
<path d="M93.66 125.94a1.8 1.8 0 01.2-.89c.13-.26.3-.51.48-.73.17-.24.36-.44.55-.66l.55-.66-.49.7c-.16.24-.33.47-.47.71a3.4 3.4 0 00-.38.75c-.1.26-.12.52-.08.78h-.36z"/>
<path d="M94.93 118.09c-.11.33-.33.55-.44.77-.22.22-.33.55-.55.66-.22.22-.44.44-.77.66.22-.33.33-.55.55-.77.11-.22.33-.44.44-.66l.55-.77z"/>
<path d="M96.2 120.17l-.36.55c-.1.18-.18.35-.26.55-.07.2-.14.4-.24.61-.1.2-.28.41-.49.49.14-.19.2-.38.25-.58.05-.2.1-.41.17-.63.05-.11.09-.22.16-.32s.13-.2.21-.28c.17-.16.35-.28.55-.4z"/>
<path d="M98.1 120.27c-.06.23-.14.44-.22.65a34.55 34.55 0 01-.86 1.84 2.4 2.4 0 01.08-.69 4.22 4.22 0 01.55-1.26c.13-.21.27-.39.46-.54z"/>
<path d="M91.41 118.64c-.11.22-.66.77-.88.88-.22.22-.44.33-.66.22a.86.86 0 00.44-.44c.22-.11.44-.55.55-.77z"/>
<path d="M105.93 70.04c-.66 4.2-3.3 9.56-4.29 13.18l-.33-.11c1.32-4.07 3.63-9.12 4.62-13.07z"/>
<path d="M131.02 80.26c-.17.4-.32.8-.42 1.22s-.16.84-.22 1.27l-.13 1.28a13 13 0 01-.2 1.3l-.32-.09c.11-.4.2-.82.28-1.24s.13-.85.2-1.27.18-.85.3-1.27c.15-.42.31-.81.51-1.2z"/>
<path d="M130.44 78.63a7.54 7.54 0 00-1.54 3.14c-.31 1.13-.44 2.3-.82 3.45l-.3-.1c.4-1.1.6-2.26.96-3.4.18-.56.4-1.12.69-1.64.27-.53.61-1 1-1.45z"/>
<path d="M89.02 67.9c-.27-.2-.56-.34-.87-.47a9.46 9.46 0 00-1.9-.51c-.33-.06-.65-.11-.99-.14.33-.1.68-.13 1.02-.11s.69.06 1.03.15c.33.09.66.2.95.4.3.16.59.4.76.69z"/>
<path d="M85.2 68.18c.22-.06.36.01.42.17.11.3-.33.24-.27.55.07.3.45.4.14.5 0 0-.48 0-.6-.5-.05-.2-.01-.6.32-.72z"/>
<path d="M84.24 68.33c-.11-.03-.23-.06-.33-.14s-.16-.17-.19-.27a1.02 1.02 0 01-.01-.57c.01.08.02.18.06.26.02.09.06.17.1.23s.12.11.17.13a.4.4 0 00.2.01v.35z"/>
<path d="M87.8 68.27c-.1-.09-.23-.14-.35-.19s-.25-.06-.39-.07c-.26-.03-.52 0-.79.02v-.33c.28.02.56.07.84.14.13.05.26.09.4.17.1.06.2.15.3.26z"/>
<path d="M94.7 75.9c-.18-.24-.3-.51-.38-.79s-.1-.56-.12-.83c.07.27.16.54.28.78s.29.46.47.64l-.25.2z"/>
<path d="M96.69 69.95a4.6 4.6 0 01-2.27-.32 4 4 0 002.2 0l.07.32z"/>
<path d="M93.28 77.67a1.9 1.9 0 01-.25-.43c-.07-.16-.11-.31-.16-.45s-.1-.3-.17-.41-.21-.22-.36-.28c.16.04.3.11.42.23.11.13.2.27.27.4.07.14.14.28.22.4s.17.23.27.32l-.24.22z"/>
<path d="M91.3 83.4a2.05 2.05 0 01-.97-1.41c.11.26.27.5.45.7s.42.32.66.4l-.14.3z"/>
<path d="M80.18 84.68c.19.08.4.12.63.13s.44 0 .67-.04c.22-.03.45-.09.67-.14s.45-.12.67-.16c-.22.06-.44.16-.65.24-.22.07-.44.16-.66.22-.23.06-.46.1-.7.13s-.5 0-.74-.07l.1-.3z"/>
<path d="M82.07 67.24c.05 0 .09.04.12.07l.08.12c.03.1.04.2.04.3l-.03.14-.07.14a.7.7 0 01-.22.22c-.04.03-.1.05-.16.06s-.13.01-.19 0c-.06 0-.12-.04-.16-.07s-.1-.08-.12-.15a.32.32 0 010-.33l.1-.1.07-.04c.02-.01.06 0 .07.01-.02 0-.04.01-.05.03a.08.08 0 00-.02.05l-.02.1c0 .06.02.12.05.14s.1.04.13.04.07 0 .12-.04a.69.69 0 00.3-.48v-.11a.19.19 0 00-.04-.1z"/>
<path d="M81.27 67.15a1.95 1.95 0 00-.63 1.1c-.02.14-.03.3.06.43-.1-.11-.14-.29-.14-.44s.03-.31.06-.46c.08-.31.2-.6.42-.86l.23.23z"/>
<path d="M79.31 69.35v.15c-.11.21-.22.19-.33.06 0-.14.11-.17.33-.21z"/>
<path d="M78.65 69.3c.11.26-.11.39-.33.27.11-.19.22-.24.33-.28z"/>
<path d="M78.1 69.3c-.11.2-.22.21-.44.21 0-.28.22-.35.44-.22z"/>
<path d="M77.44 69.3v.16c-.11.14-.22.08-.33-.01 0-.19.11-.18.33-.14z"/>
<path d="M70 75.92c.59.06 1.17 0 1.7-.18a3.75 3.75 0 001.43-.91c.22-.2.43-.41.67-.6s.52-.34.8-.45a3.1 3.1 0 011.77-.18 3.92 3.92 0 00-2.04.63l-.34.26c-.22.17-.43.38-.64.59a3.36 3.36 0 01-1.57.91 3.17 3.17 0 01-1.79-.07z"/>
<path d="M73.66 81.03c-.01-.26.02-.53.06-.8.06-.25.11-.52.26-.77s.37-.45.61-.58c.24-.15.5-.22.75-.32s.48-.17.7-.29c.22-.11.43-.26.62-.43s.35-.36.46-.58c.12-.22.18-.48.16-.74.04.12.06.27.06.4s-.03.27-.06.4c-.05.14-.11.26-.18.38a2.6 2.6 0 01-.9.84c-.25.15-.5.25-.75.33s-.5.17-.72.28-.4.25-.55.45c-.13.2-.23.44-.32.68-.07.23-.15.49-.2.75z"/>
<path d="M78.7 75.8a3.2 3.2 0 001.36.38c.15 0 .3 0 .46-.02.32-.03.64-.09.99-.1.18 0 .34.01.52.05.16.05.33.13.46.24-.33-.1-.64-.08-.95-.03-.32.06-.63.14-.96.17-.17 0-.35.02-.52 0s-.35-.06-.5-.12a1.8 1.8 0 01-.87-.58z"/>
<path d="M65.93 71.42c.64.27 1.3.43 1.97.5.34.03.67.04 1.01.04l1.03-.01c.68-.02 1.37-.05 2.08.06l.51.11c.17.06.34.11.5.2.32.16.6.38.8.67a2.78 2.78 0 00-1.85-.73c-.33-.02-.67-.03-1-.02-.35 0-.69.02-1.03.04-.68 0-1.39 0-2.08-.11a4.63 4.63 0 01-1.94-.75z"/>
<path d="M75.63 74.33c.17-.06.37-.08.57-.05.18.02.37.07.56.14.35.12.68.3 1.01.38a1.92 1.92 0 00.52.1c.18.01.37.04.56.08s.37.1.54.2.32.22.43.37a2.1 2.1 0 00-1.02-.32l-.53-.03-.3-.02-.29-.06c-.38-.1-.7-.3-1.02-.47-.33-.16-.65-.3-1.03-.32z"/>
<path d="M88.6 71.7a3.42 3.42 0 01.98.94 3.28 3.28 0 01.6 1.23c-.17-.17-.31-.33-.45-.5l-.41-.53c-.13-.17-.25-.37-.37-.55s-.25-.39-.35-.6z"/>
<path d="M90.7 71.1c.2-.02.37-.07.56-.1s.37-.06.58-.03a.81.81 0 01.56.31c.13.18.18.37.2.57-.14-.14-.27-.29-.39-.39s-.26-.14-.41-.16-.35-.03-.53-.04a1.32 1.32 0 01-.56-.16z"/>
<path d="M93.83 71.4c.2-.03.4.02.58.1s.37.18.5.32.27.31.35.5.11.38.09.58c-.11-.16-.21-.32-.32-.46a4.4 4.4 0 00-.74-.74l-.46-.3z"/>
<path d="M92.04 73.58l.12.3.06.28.05.27v.32a.61.61 0 01-.24-.23c-.06-.1-.1-.2-.13-.3s-.02-.23 0-.34c.02-.1.06-.2.14-.3z"/>
<path d="M90.53 76.64c-.01.34.04.67.17.96.06.14.14.27.24.4l.3.41.13.25a2.24 2.24 0 01.1.81c-.04.35-.11.67-.14 1.01-.1-.33-.1-.68-.12-1.01a1.5 1.5 0 00-.25-.87c-.09-.13-.19-.26-.28-.42-.1-.14-.18-.32-.23-.5-.1-.36-.07-.73.08-1.04z"/>
<path d="M89.27 79.35c.04.2.03.4-.02.6-.04.19-.1.37-.15.54l-.15.52c-.04.18-.07.35-.07.55a.97.97 0 01-.2-.57c0-.21.04-.41.1-.6s.14-.36.22-.53l.27-.51z"/>
<path d="M86.99 81.77c.02.13 0 .25-.03.37a1.1 1.1 0 01-.2.31c-.08.09-.18.17-.29.22s-.23.08-.36.07l.2-.28.22-.23.2-.22c.07-.09.15-.17.26-.24z"/>
<path d="M87.92 84.32a.8.8 0 01.12.39c0 .14-.02.27-.05.4-.08.27-.2.49-.29.7s-.16.46-.22.7-.1.48-.14.75a2.17 2.17 0 01.06-1.56c.1-.26.24-.47.35-.69s.2-.43.17-.69z"/>
<path d="M84.59 85.14c.01.21-.03.43-.12.63a1.79 1.79 0 01-.91.9c-.2.08-.42.12-.63.1.18-.1.34-.22.5-.33s.3-.24.42-.37.27-.28.38-.43c.13-.15.24-.3.36-.5z"/>
<path d="M80.62 87.59c-.18.16-.35.3-.54.43l-.54.38-.5.4c-.19.14-.31.32-.47.5.03-.24.14-.47.27-.67.14-.2.3-.36.5-.5.19-.15.4-.26.6-.36.22-.06.44-.14.68-.18z"/>
<path d="M85.2 89.8c.02.15 0 .3-.06.44l-.19.38a4.56 4.56 0 00-.56 1.44c-.05.26-.08.53-.09.8a2.26 2.26 0 010-1.67c.1-.26.27-.51.45-.72.17-.21.36-.4.44-.66z"/>
<path d="M86.99 91.66a3.97 3.97 0 01.03 1.6c-.05.27-.13.5-.18.75s-.05.48.07.73a.59.59 0 01-.25-.33 1.1 1.1 0 01-.07-.42c0-.29.07-.55.11-.8.06-.25.1-.5.14-.75l.15-.78z"/>
<path d="M88.4 96.21c.03.18.06.33.13.47s.13.26.24.37c.1.1.23.22.34.36.06.08.11.15.14.24s.06.19.04.28a1.1 1.1 0 00-.36-.33c-.13-.1-.27-.19-.4-.33s-.23-.33-.24-.53a.64.64 0 01.12-.53z"/>
<path d="M85.1 94.55c0 .3-.05.58-.1.86-.04.28-.1.56-.15.83l-.08.42a.65.65 0 00-.01.35c.02.11.1.22.18.35s.18.26.17.41c-.13-.26-.43-.33-.6-.66a.88.88 0 01-.06-.5l.07-.42a5.54 5.54 0 01.59-1.64z"/>
<path d="M87.45 89.28c.17.22.3.44.43.67s.23.49.3.74.13.52.16.78c.02.26.03.53.01.8-.1-.25-.18-.5-.26-.76l-.21-.73c-.07-.24-.14-.49-.23-.74a3.5 3.5 0 01-.2-.76z"/>
<path d="M82.62 88.97c.07.17.04.38-.02.54-.07.18-.19.33-.3.46s-.26.26-.38.38a5.52 5.52 0 00-.93 1.2c-.17.3-.33.6-.47.92.01-.35.11-.71.24-1.04a3.77 3.77 0 011.34-1.64c.14-.11.26-.22.35-.36.1-.12.16-.28.17-.46z"/>
<path d="M82.37 94.77c-.02.39-.22.75-.35 1.08a5.9 5.9 0 00-.42 2.13c0 .36.02.73.22 1.07-.16-.12-.27-.3-.34-.47a2.08 2.08 0 01-.15-.58 3.78 3.78 0 01.44-2.26c.21-.34.44-.62.6-.97z"/>
<path d="M86.28 100.33c.06.28.08.58.1.86s0 .58-.02.87l-.03.43-.05.42c0 .13 0 .26.05.39s.1.24.23.33c-.16-.02-.29-.13-.38-.26s-.13-.3-.15-.45-.01-.3-.01-.45l.01-.43a6.96 6.96 0 01.25-1.72z"/>
<path d="M79.36 95.48c0 .3-.16.59-.34.82-.18.23-.4.43-.62.62s-.44.35-.64.53-.38.4-.5.66c-.02-.3.12-.59.3-.83.19-.24.4-.44.63-.62.22-.18.45-.35.65-.54s.38-.38.52-.63z"/>
<path d="M78.45 91.48c.03.14 0 .3-.06.45s-.16.28-.25.39l-.3.33a10.8 10.8 0 00-.82.96l-.52.7a3.8 3.8 0 011.12-1.9c.12-.08.23-.17.34-.27.2-.19.4-.37.5-.66z"/>
<path d="M75.3 93.16a8.1 8.1 0 00-.82 1.39 8.37 8.37 0 00-.45 1.53c-.09-.28-.1-.56-.08-.84a2.76 2.76 0 01.67-1.55c.2-.2.42-.4.68-.53z"/>
<path d="M74.65 97.58l-.39.86c-.12.28-.23.59-.33.87-.04.15-.1.3-.13.44-.05.16-.08.3-.1.44s-.02.29.02.43.12.28.25.36c-.16-.02-.3-.14-.4-.3-.09-.15-.13-.32-.13-.5s.02-.34.05-.5c.03-.16.08-.31.12-.47a3.77 3.77 0 011.03-1.64z"/>
<path d="M76.65 100.22a2.3 2.3 0 01-.1 1.73l-.36.75c-.11.24-.2.5-.2.8-.13-.27-.12-.6-.05-.89s.2-.55.31-.8.21-.5.27-.76c.06-.27.1-.55.13-.83z"/>
<path d="M79.76 99.49c.09.15.13.32.15.5s0 .36-.06.53c-.08.19-.2.31-.3.42-.1.12-.22.21-.2.39-.07-.06-.1-.17-.1-.27s.05-.18.08-.26c.08-.16.18-.29.22-.4.06-.13.09-.27.11-.43s.05-.3.1-.48z"/>
<path d="M83.27 101.07c-.09.27-.19.5-.26.76s-.16.5-.21.75-.08.5-.05.75.1.5.25.74a1.2 1.2 0 01-.5-.69 1.75 1.75 0 01-.02-.85c.05-.3.16-.54.3-.79.12-.25.28-.48.49-.67z"/>
<path d="M80.52 103.33c.04.23.01.46-.06.68s-.15.42-.25.62l-.3.57c-.1.19-.18.37-.27.58-.04-.22-.02-.46.03-.68s.16-.43.24-.62l.31-.57.3-.58z"/>
<path d="M77.84 104.78c.04.3.02.62-.03.92s-.14.6-.22.9c-.07.27-.13.55-.06.8.03.13.09.25.17.36s.2.2.36.23c-.16.04-.33 0-.47-.1a.93.93 0 01-.37-.66l-.01-.25c.01-.17.04-.33.08-.47.08-.31.2-.58.28-.86l.27-.87z"/>
<path d="M75.54 105.95c.03.22.03.41.04.62.01.2.02.4.05.59s.07.36.14.53c.08.18.16.35.32.51-.22-.04-.41-.19-.54-.37s-.22-.4-.24-.63a2.19 2.19 0 01.23-1.25z"/>
<path d="M87.93 102.5c.05.32.06.64.08.96l.03.95c.01.31.04.62.07.93s.09.63.14.95a3.59 3.59 0 01-.54-1.87c0-.33 0-.65.04-.98.03-.31.08-.63.18-.95z"/>
<path d="M84.77 104.44c.12.32.13.68.13 1.01s0 .66.08.95.26.54.47.8l.3.43c.1.16.15.32.16.5-.16-.31-.4-.51-.65-.75a3.95 3.95 0 01-.35-.39l-.14-.23a1.29 1.29 0 01-.1-.26c-.1-.37-.07-.73-.03-1.06.05-.34.11-.66.13-1z"/>
<path d="M82.11 106.39c.05.2.07.4.1.59l.16 1.14c.02.2.05.39.06.6-.14-.16-.23-.34-.3-.53a2.6 2.6 0 01-.17-1.21c.01-.2.07-.4.16-.6z"/>
<path d="M111.58 106.66l.83-.14a8.1 8.1 0 001.54-.53c.25-.11.5-.25.75-.39-.17.25-.38.44-.62.62-.24.17-.5.3-.78.4s-.57.15-.86.16c-.3 0-.58-.03-.86-.12z"/>
<path d="M111.4 109.83c.18-.1.36-.18.54-.25l.51-.22c.18-.07.35-.15.53-.21s.36-.14.56-.18c-.12.17-.27.3-.44.4s-.34.22-.53.3-.37.13-.57.15c-.19.03-.38.04-.6 0z"/>
<path d="M115.83 103.35c.11-.88.88-1.65 1.76-1.65-.66.44-1.21 1.1-1.76 1.65z"/>
<path d="M118.36 102.69c.77-.66.99-1.87 1.87-1.98-.77.55-.99 1.98-1.87 1.98z"/>
<path d="M116.73 100.38c0-.06.01-.12.05-.18s.07-.1.12-.13c.07-.08.16-.15.25-.22.18-.14.37-.26.57-.36.21-.1.43-.18.66-.21s.47-.02.7.07c-.24.05-.43.1-.63.18l-.59.26-.58.28c-.1.05-.2.1-.3.13-.1.05-.2.08-.25.18z"/>
<path d="M120.3 97.49c.28-.07.56-.1.83-.12l.82-.04c.27 0 .5-.04.74-.13l.76-.3c-.18.2-.4.39-.65.53a1.56 1.56 0 01-.84.22c-.28.01-.54 0-.82-.03a5.3 5.3 0 01-.83-.13z"/>
<path d="M122.2 95.03c.34-.03.67-.08 1.01-.13s.7-.06 1.06.02c.36.08.68.28.94.5.28.22.5.45.77.68-.33-.1-.62-.3-.91-.47a3.19 3.19 0 00-.87-.39c-.3-.06-.64-.07-.97-.08-.34 0-.7-.02-1.03-.13z"/>
<path d="M126.75 98.72a4.03 4.03 0 011.44.75c.21.17.41.38.55.62s.26.51.28.78a5.83 5.83 0 00-.47-.62c-.18-.19-.37-.37-.57-.53l-.6-.48a7.11 7.11 0 01-.63-.52z"/>
<path d="M127.4 101.14c.2.16.34.38.46.61.11.24.2.49.24.74.03.25.03.52 0 .78-.05.26-.13.5-.27.73l.01-.74a7.85 7.85 0 00-.2-1.4l-.24-.72z"/>
<path d="M129.72 103.71c.1.23.11.48.1.72a2.48 2.48 0 01-.5 1.34c-.15.19-.32.36-.53.47l.32-.61a6.1 6.1 0 00.46-1.26l.15-.66z"/>
<path d="M126.36 105.54c.04.24-.05.5-.18.71-.13.22-.32.4-.53.53a6.4 6.4 0 01-1.32.56c.17-.18.37-.33.55-.46l.59-.37c.19-.12.35-.27.5-.42.16-.14.29-.32.39-.55z"/>
<path d="M123.14 106.14c-.16.1-.33.15-.48.2-.16.06-.32.1-.48.13a3.94 3.94 0 01-1.03.15c.14-.12.29-.22.45-.3a2.65 2.65 0 011.02-.24c.17 0 .35 0 .52.06z"/>
<path d="M125.21 108.97c-.2.17-.41.29-.66.39a3.33 3.33 0 01-1.5.24c-.26-.02-.51-.07-.75-.18.25-.03.5-.05.73-.09s.49-.05.72-.1c.24-.03.47-.07.71-.12.27-.04.5-.1.75-.14z"/>
<path d="M127 109.31c.2-.16.46-.27.72-.34s.54-.08.77-.09c.24-.02.45-.06.65-.18s.36-.3.5-.53a1 1 0 01-.33.74 1.35 1.35 0 01-.8.32c-.27.02-.51 0-.76.02a3.6 3.6 0 00-.75.06z"/>
<path d="M131.05 102.61c-.03-.24-.03-.47-.04-.7l-.01-.68c-.01-.22-.02-.44-.06-.66s-.08-.44-.16-.67c.19.15.32.37.42.59a2.59 2.59 0 01.07 1.43c-.04.25-.1.47-.22.7z"/>
<path d="M129.67 98.3a.5.5 0 01-.32-.12.93.93 0 01-.23-.28c-.12-.2-.16-.44-.19-.63-.03-.21-.06-.39-.14-.55-.09-.17-.21-.32-.42-.38.1-.04.23-.03.34.01s.21.13.29.21.14.21.17.32c.05.11.07.22.08.33.03.21.04.4.1.6s.13.36.32.5z"/>
<path d="M120.36 94.64c-.15.09-.3.14-.46.19a3.8 3.8 0 01-.94.11 1.85 1.85 0 01-.48-.08c.16-.09.3-.14.46-.19l.47-.09c.16-.03.31-.02.47-.02.15.01.32.02.48.08z"/>
<path d="M123.87 98.03a3.44 3.44 0 011.04-.55c.2-.06.4-.1.6-.08s.42.08.57.2c-.2 0-.38.03-.56.06s-.35.08-.53.14l-.54.16c-.17.03-.37.08-.58.07z"/>
<path d="M121.08 108.08a1.5 1.5 0 01-.97.35c-.18 0-.35-.02-.52-.06a1.43 1.43 0 01-.46-.25h.97l.47-.02c.17-.02.33-.02.5-.02z"/>
<path d="M117.25 108.64c.16.1.3.22.43.35l.35.38c.06.05.11.1.18.14.05.04.12.08.2.11l.26.12c.09.05.16.11.2.2-.18-.06-.33-.03-.52-.07a.94.94 0 01-.55-.27c-.14-.14-.24-.3-.33-.46-.09-.15-.17-.31-.22-.5z"/>
<path d="M120.38 109.63c.21.02.41.13.58.24.16.12.3.26.45.37s.28.2.45.28.34.13.54.19a1 1 0 01-.63.05c-.2-.03-.42-.14-.58-.27s-.3-.29-.42-.43-.23-.29-.39-.43z"/>
<path d="M117.15 104.56c-.33.33-.55.88-.77 1.32a2.3 2.3 0 01-.44.66c.22-.55.22-1.21.66-1.65.11-.11.33-.33.55-.33z"/>
<path d="M110.02 110.03c-.12.12-.24.2-.36.3l-.35.28-.36.26c-.12.1-.24.2-.4.27.04-.17.12-.32.22-.45s.2-.26.34-.35.27-.18.43-.24c.15-.04.32-.08.48-.07z"/>
<path d="M106.62 109.33a.12.12 0 00-.1.06l-.06.1c-.03.08-.1.15-.16.23a1.38 1.38 0 01-1 .45c-.18 0-.37-.03-.54-.13l.51-.13a3.15 3.15 0 00.87-.4l.2-.14.14-.07c.06-.01.11-.01.14.03z"/>
<path d="M105.72 107.78a2.28 2.28 0 01-.86.2c-.14.02-.28.03-.43.02s-.3-.02-.45-.06c.14-.1.28-.16.42-.2a2.16 2.16 0 01.88-.09c.14.03.3.07.44.13z"/>
<path d="M97.79 110.94a7.88 7.88 0 01-1.7.15 3.86 3.86 0 01-.86-.13c-.28-.07-.55-.2-.78-.38.28.05.55.1.82.12.28.03.55.04.83.05.56.06 1.13.07 1.69.19z"/>
<path d="M91.38 109.1c.2-.08.43-.13.64-.15a4.27 4.27 0 011.3.05c.2.05.41.1.62.2a3.3 3.3 0 01-.65.06h-.64l-.63-.05c-.21-.03-.43-.05-.64-.12z"/>
<path d="M88.37 108.78a5.48 5.48 0 001.39 1.55c.18.16.37.3.55.48a2.65 2.65 0 01-1.3-.7 2.02 2.02 0 01-.45-.61c-.1-.21-.19-.46-.19-.72z"/>
<path d="M92.08 113.4c.23-.12.47-.2.73-.26l.36-.09c.12-.02.24-.05.37-.06s.28-.03.42 0c.16.04.29.12.39.2.2.16.34.36.58.47a.93.93 0 01-.39-.08l-.33-.18a.89.89 0 00-.63-.09l-.35.05-.38.03c-.25.01-.5.02-.77 0z"/>
<path d="M86.46 111.61c.01.25.14.45.29.6.15.16.35.27.56.38l.64.33.64.35a2.86 2.86 0 01-1.44-.4 1.74 1.74 0 01-.6-.49.93.93 0 01-.16-.37.61.61 0 01.07-.4z"/>
<path d="M82.72 110.58c.24.13.43.36.56.6.07.12.12.24.17.38.04.12.08.26.13.37s.09.2.16.26.18.12.29.17l.36.14c.12.05.26.12.34.23-.26-.09-.5-.06-.78-.12a.98.98 0 01-.42-.17.9.9 0 01-.26-.4l-.11-.39a3 3 0 00-.11-.36 3 3 0 00-.33-.71z"/>
<path d="M79.1 109.92c.11 0 .2-.03.3-.06.05 0 .1-.03.17-.03s.15.02.2.04c.12.06.21.13.29.19a5.65 5.65 0 01.7.64c.13.15.27.32.38.5a4.58 4.58 0 01-1.06-.69l-.23-.2c-.08-.09-.14-.16-.21-.2-.03-.03-.07-.05-.1-.06l-.13-.02-.17-.03c-.05-.02-.1-.04-.14-.08z"/>
<path d="M80.74 112.65c.3-.1.6-.17.94-.2.31-.01.65.03.96.16.16.07.31.17.43.28s.23.23.33.35c.2.23.38.47.67.6a.92.92 0 01-.47-.13 2.7 2.7 0 01-.38-.28l-.35-.3a1.89 1.89 0 00-.36-.22c-.25-.11-.55-.17-.85-.2s-.6-.03-.92-.06z"/>
<path d="M85.69 115.63a1 1 0 00.4.13l.2.04.21.04.83.1c.28.04.56.07.85.13s.57.13.83.26h-.86c-.28-.01-.57-.02-.85-.06a4.57 4.57 0 01-1.27-.36c-.13-.06-.27-.15-.34-.28z"/>
<path d="M89.67 114.92c.29-.09.57-.14.88-.12a1.74 1.74 0 01.87.3c.25.16.46.33.72.4.25.07.53.1.83.15-.28.09-.57.14-.89.1-.15-.01-.3-.07-.45-.13s-.26-.15-.39-.22-.23-.15-.35-.2-.24-.1-.37-.13c-.27-.08-.56-.1-.85-.15z"/>
<path d="M93.9 116.96c.23-.07.4-.19.6-.3a2.25 2.25 0 011.39-.29c.24.04.47.1.67.24-.24 0-.46 0-.68.03s-.44.04-.65.09-.42.1-.64.17a3.3 3.3 0 01-.35.09.74.74 0 01-.34-.03z"/>
<path d="M84.55 109.1c.23.15.46.25.7.34.24.1.5.17.75.27s.5.22.74.38c.22.17.42.4.5.66-.2-.2-.4-.33-.64-.44s-.47-.2-.71-.3c-.26-.1-.5-.2-.74-.33a1.55 1.55 0 01-.6-.59z"/>
<path d="M87.06 97.38a2.75 2.75 0 00.6 1.5l.27.32c.1.12.18.26.23.4.13.29.17.6.11.88a3 3 0 00-.34-.76c-.07-.11-.15-.22-.24-.32l-.28-.32a1.8 1.8 0 01-.4-.82c-.08-.3-.06-.6.05-.88z"/>
<path d="M74 102.94c.13.18.16.4.17.6s0 .41-.04.61c-.02.19-.04.38-.04.56s0 .37.07.58c-.17-.13-.28-.33-.33-.54s-.04-.43-.02-.63.07-.4.11-.58c.04-.21.08-.39.09-.6z"/>
<path d="M71.59 100.12a5.15 5.15 0 01.23-.91c.1-.3.24-.58.35-.86-.07.3-.14.59-.19.9l-.06.45c-.01.14-.02.3 0 .43h-.33z"/>
<path d="M73.2 92.92c.2-.15.39-.27.59-.38l.6-.31-.5.44c-.16.14-.31.3-.44.47l-.25-.22z"/>
<path d="M76.66 88.44l.48-.18a4.75 4.75 0 001.31-.73 4.65 4.65 0 01-1.21.95c-.14.09-.3.16-.43.25l-.15-.29z"/>
<path d="M72.36 104.36c0-.37.03-.74.1-1.09s.14-.7.17-1.05c.03.36 0 .71 0 1.07-.02.36 0 .7.06 1.05l-.33.02z"/>
<path d="M74.34 108.96a3.9 3.9 0 01.12-1.4c-.02.22-.01.45.03.67.04.22.1.44.17.66l-.32.07z"/>
<path d="M78.12 112.55c-.14-.31-.23-.63-.3-.95s-.1-.64-.15-.96c.09.31.19.62.3.9.13.3.26.58.44.83l-.29.18z"/>
<path d="M82.38 115.72l-.35-.62c-.11-.21-.21-.43-.3-.65.13.2.28.38.43.56s.3.35.47.52l-.25.2z"/>
<path d="M87.48 117.97l-.5-.45c-.16-.15-.32-.31-.47-.49.18.14.37.25.57.36l.58.3-.18.28z"/>
<path d="M94.48 118.13c-.78-.1-1.53-.3-2.25-.6.75.2 1.51.28 2.26.27l-.01.33z"/>
<path d="M103.1 102.67c.1.32.16.64.2.96s.07.64.08.97 0 .65-.03.98-.08.65-.18.97c-.03-.33-.07-.65-.08-.97l-.04-.96a14.88 14.88 0 01.04-1.95z"/>
<path d="M106.7 106c-.3-.37-.56-.76-.82-1.15s-.52-.8-.79-1.17a27 27 0 00-1.26-1.66c-.08-.08-.17-.15-.27-.21s-.2-.1-.31-.06c.04-.03.1-.05.17-.05l.19.02c.12.03.23.1.33.17s.2.15.28.24a7.96 7.96 0 011.16 1.36l.38.6a15.07 15.07 0 01.93 1.9z"/>
<path d="M99.11 103.06a13.13 13.13 0 01-.27 2.9l-.3.92c-.09-.33-.05-.67 0-.99l.15-.94c.06-.32.11-.64.18-.95s.14-.62.24-.94z"/>
<path d="M101.02 107.08c-.04-.44-.08-.88-.16-1.31l-.13-.64c-.05-.2-.1-.42-.17-.62-.12-.41-.26-.83-.44-1.21a2.11 2.11 0 00-.32-.53c-.06-.07-.14-.12-.24-.11-.09 0-.18.09-.25.17.04-.1.1-.2.23-.26a.25.25 0 01.2-.01c.06 0 .12.04.17.09.2.15.33.34.44.54.23.4.4.8.53 1.24l.15.66c.04.22.07.44.08.67.03.43.01.88-.09 1.32z"/>
<path d="M96 102.93a14.38 14.38 0 01-.64 1.6 10.1 10.1 0 01-.43.75c-.17.24-.33.48-.56.67.1-.28.2-.54.33-.8a9.83 9.83 0 011.3-2.22z"/>
<path d="M96.47 106.52c-.01-.29.01-.57.01-.85l.07-1.67c0-.28.02-.56.05-.85.11.27.17.55.2.84s.04.57.03.86-.04.57-.1.84c-.05.29-.13.58-.26.83z"/>
<path d="M93.27 101.96c.14.26.2.55.2.84 0 .3-.05.58-.14.86s-.22.55-.36.78c-.14.24-.3.46-.44.71.01-.28.11-.57.21-.82a8.12 8.12 0 00.47-1.54c.05-.28.07-.54.06-.83z"/>
<path d="M91.12 104.1c.08-.22.2-.4.31-.6s.25-.35.4-.51l.45-.48a6 6 0 01.5-.41 4.23 4.23 0 01-.7 1.11l-.45.47a6.83 6.83 0 01-.5.42z"/>
<path d="M107.54 83.67c.51-.64 1.04-1.25 1.6-1.86.25-.3.54-.6.82-.91l.83-.9.85-.88c.28-.29.56-.59.86-.88l.85-.87c.3-.29.59-.57.86-.87-.22.35-.48.66-.73.98l-.8.93c-.27.31-.53.62-.81.92l-.84.9-.84.88-.86.87a43.08 43.08 0 01-1.8 1.7z"/>
<path d="M110.97 71.52a18.23 18.23 0 01-1.42 3.9c-.6 1.26-1.24 2.48-1.9 3.7a73.3 73.3 0 00-1.86 3.7c-.29.63-.56 1.27-.8 1.92-.24.65-.41 1.3-.52 2 .03-.7.18-1.38.37-2.05.2-.67.44-1.32.7-1.97a47.1 47.1 0 011.82-3.75l.98-1.83c.33-.6.65-1.22.97-1.84s.62-1.23.9-1.86c.3-.62.55-1.26.76-1.92z"/>
<path d="M107.68 89.93c.65-.32 1.29-.66 1.92-.99l.96-.5c.32-.16.64-.32.95-.5l.47-.25.47-.27.94-.53c.62-.35 1.24-.72 1.83-1.12-.51.5-1.1.94-1.7 1.34a24.25 24.25 0 01-2.83 1.61l-.5.23c-.16.08-.32.16-.49.22-.33.14-.66.29-1 .4-.34.14-.68.26-1.02.36z"/>
<path d="M114.34 79.13a72.38 72.38 0 01-4.73 5.52c-.42.43-.84.87-1.28 1.29s-.86.83-1.28 1.27c-.4.44-.81.9-1.18 1.37-.17.24-.36.48-.5.73-.16.26-.3.53-.39.82.06-.3.17-.58.3-.86s.3-.54.46-.8a15.84 15.84 0 012.37-2.77 70.38 70.38 0 002.52-2.6l1.23-1.33a69.96 69.96 0 012.48-2.64z"/>
<path d="M107.72 94.39c.64.03 1.27.04 1.9.08l.94.06.95.06.94.08.95.1c.63.07 1.25.15 1.88.26-.64.03-1.27.02-1.9 0l-.95-.05-.95-.07c-.62-.05-1.25-.1-1.89-.2-.32-.04-.62-.08-.93-.14-.32-.04-.64-.09-.94-.18z"/>
<path d="M115.8 86.88c-.7.75-1.55 1.36-2.42 1.9s-1.77 1.05-2.69 1.51c-.46.23-.91.47-1.37.69l-1.39.66c-.46.22-.92.44-1.36.68a9.4 9.4 0 00-.66.37c-.22.13-.43.28-.6.46.15-.2.34-.37.55-.54a13.09 13.09 0 011.97-1.2c.45-.25.9-.48 1.37-.72l1.36-.7c.45-.22.91-.46 1.35-.7.46-.23.9-.48 1.35-.73.87-.5 1.73-1.04 2.54-1.68z"/>
<path d="M106.94 97.22c.5.23.98.49 1.45.76.25.13.48.28.7.4l.7.44.68.45c.22.15.45.3.67.47.44.32.88.65 1.27 1.05-.47-.28-.95-.55-1.4-.83-.24-.13-.47-.28-.7-.42l-.7-.43c-.46-.3-.9-.58-1.36-.9-.44-.33-.88-.64-1.3-.99z"/>
<path d="M113.69 96.68c-.65.01-1.3 0-1.94-.05-.65-.05-1.29-.11-1.93-.19l-.95-.13c-.32-.06-.64-.1-.95-.14a14.1 14.1 0 00-.96-.1c-.31-.01-.63-.02-.94.06.28-.15.63-.2.94-.23.33-.02.65 0 .98.01.65.05 1.29.15 1.93.21l.96.12.95.14c.63.08 1.27.18 1.9.3z"/>
<path d="M105.57 100.06a11.04 11.04 0 011.2 1.63l.35.57c.23.39.44.78.63 1.19s.35.82.45 1.27c-.22-.4-.46-.77-.68-1.15l-.68-1.14-.33-.58c-.1-.2-.22-.38-.33-.58-.23-.4-.44-.8-.61-1.2z"/>
<path d="M110.97 101.78c-.46-.31-.94-.6-1.42-.85l-.74-.39-.72-.4-1.43-.82-.73-.38c-.24-.12-.5-.22-.77-.28.28-.02.56.05.84.12l.78.3c.26.1.5.24.75.36l.72.4c.49.28.97.54 1.43.85.47.32.91.68 1.29 1.09z"/>
<path d="M100.87 135.23c.06.17.1.36.09.54a.7.7 0 01-.06.26c-.02.09-.06.16-.07.24-.02-.09 0-.17-.02-.25a.73.73 0 00-.03-.23 1.13 1.13 0 00-.22-.4l.31-.16z"/>
<path d="M99.73 137.22c.1.15.17.32.2.5.03.1.03.2.02.27-.02.09-.03.16-.02.25l-.06-.24a.69.69 0 00-.09-.22 1.3 1.3 0 00-.3-.34l.25-.22z"/>
<path d="M103.25 137.9c.2.11.4.25.56.42.07.09.15.18.2.27s.12.21.13.32c-.05-.1-.11-.18-.19-.26s-.16-.13-.25-.2c-.18-.1-.38-.2-.57-.24l.12-.3z"/>
<path d="M103.7 137.38c.18-.14.41-.26.62-.35l.32-.13.33-.12.33-.1c.11-.03.21-.07.31-.12s.18-.13.27-.21.17-.14.27-.2c-.09.07-.18.14-.25.23s-.15.18-.25.26c-.1.06-.2.12-.3.16l-.32.14-.6.32c-.2.11-.36.23-.52.39l-.21-.27z"/>
<path d="M109.5 136.79c.21.2.43.4.68.57s.5.29.77.38l-.13.3c-.28-.14-.53-.33-.75-.55s-.4-.46-.58-.7z"/>
<path d="M112.5 136.05c-.12.1-.23.21-.31.34l-.09.22c-.02.07-.03.17-.06.25l-.02-.26c0-.08 0-.17.02-.26.03-.19.12-.35.2-.5l.26.21z"/>
<path d="M107.69 129.47c.24.32.43.69.55 1.07.13.39.19.8.2 1.19s0 .8-.01 1.19c-.01.38-.01.77.1 1.14-.11-.16-.2-.35-.26-.54a2.8 2.8 0 01-.1-.6c-.03-.39-.03-.78-.04-1.17-.02-.38-.06-.76-.12-1.14-.09-.39-.2-.75-.32-1.14z"/>
<path d="M97.56 116.77c.02-.65.04-1.3.01-1.96-.02-.32-.06-.65-.12-.97s-.18-.62-.36-.9c.2.26.34.56.44.88s.16.64.2.97c.1.65.13 1.3.16 1.97l-.33.01z"/>
<path d="M108.16 111.22c.12.2.21.41.28.63l.19.67c.07.22.13.44.22.65s.2.4.33.56l-.28.2c-.13-.22-.23-.45-.3-.68s-.1-.46-.15-.7l-.1-.67a2.27 2.27 0 00-.19-.66z"/>
<path d="M106.73 112.95a3.5 3.5 0 00-.33-.18l-.3-.15-.3-.12c-.1-.04-.22-.07-.36-.1a.72.72 0 01.38-.15c.14-.01.29.02.4.08.14.05.25.14.34.25.1.1.16.23.17.37z"/>
<path d="M100.67 112.3c-.14.05-.25.11-.35.2s-.19.14-.26.23l-.26.29c-.09.1-.18.2-.3.3 0-.16.03-.3.07-.43.06-.14.13-.27.24-.39.11-.1.25-.2.4-.24.17-.06.33-.06.46.03z"/>
<path d="M102.73 111.47c.05-.11.15-.18.26-.21s.23-.03.34.01c.11.03.21.1.29.2.08.09.12.2.1.33-.1-.06-.19-.1-.27-.12-.07-.04-.15-.06-.22-.08l-.23-.07a.77.77 0 00-.27-.06z"/>
<path d="M105.06 124.91c.18-.58.18-1.22.02-1.81-.08-.31-.18-.61-.27-.92s-.16-.63-.16-.94c.04.32.13.61.25.9.1.3.24.6.35.9.22.6.27 1.29.14 1.95l-.33-.08z"/>
<path d="M102.18 124.72c-.14-.14-.24-.32-.3-.5s-.1-.38-.12-.55l-.03-.53c-.01-.18-.04-.34-.06-.52a5.7 5.7 0 00-.7-1.97 5.7 5.7 0 01.97 2.47l.07.51c.03.16.07.33.14.48s.15.26.27.37l-.24.24z"/>
<path d="M107.81 123.67l-.23-.75-.2-.76c-.05-.25-.1-.52-.13-.77s-.04-.52-.19-.74c.17.2.22.48.28.73a9.33 9.33 0 00.48 1.45l.31.7-.32.14z"/>
<path d="M111.13 124.44a1.8 1.8 0 01-.63-.65c-.16-.26-.27-.53-.36-.8l-.25-.83-.24-.82.32.79.32.79c.1.25.24.5.4.72.16.22.36.39.6.51l-.16.29z"/>
<path d="M105.24 114.83c.08.15.2.25.33.31s.27.12.41.17c.15.05.3.1.46.17s.3.18.41.3c.26.23.43.52.57.81s.21.6.27.93c-.19-.27-.34-.54-.5-.8-.17-.26-.36-.5-.57-.7-.1-.1-.22-.18-.34-.26s-.26-.14-.4-.22-.3-.16-.42-.28a.72.72 0 01-.17-.2c-.02-.06-.05-.14-.05-.23z"/>
<path d="M101.07 114.9c.03.29.04.57.05.85s.03.55.07.81c.03.27.1.53.19.78s.2.5.38.73a1.51 1.51 0 01-.61-.62 2.32 2.32 0 01-.28-.84c-.04-.3-.03-.59.01-.87.02-.29.09-.56.19-.84z"/>
<path d="M99.73 117.29c.14.22.18.5.2.76s-.03.51-.06.76-.06.48-.06.71c0 .24.04.47.14.72-.21-.17-.33-.43-.39-.69a2.4 2.4 0 01-.01-.79c.03-.25.09-.5.12-.74s.06-.47.06-.73z"/>
<path d="M104.58 117.27c0 .15.1.25.18.37s.17.24.23.37a5.33 5.33 0 01.63 1.65c.06.29.1.59.1.88-.13-.26-.24-.54-.35-.8l-.3-.8-.32-.8-.14-.41c-.02-.07-.06-.15-.07-.22 0-.1 0-.18.04-.25z"/>
<path d="M107.76 119.11c.1.2.17.41.26.6s.19.35.3.51.27.34.38.55c.11.2.19.45.13.67-.08-.2-.2-.37-.34-.52a4.67 4.67 0 01-.6-.8 1.78 1.78 0 01-.14-1.01z"/>
<path d="M103.41 113.93c-.09.19-.02.34.03.5.07.17.16.33.22.52s.1.4.1.6c-.02.2-.05.4-.14.58l-.12-.56-.14-.52c-.05-.17-.14-.35-.16-.56a.8.8 0 01.02-.32c.03-.1.1-.2.2-.24z"/>
<path d="M108.9 117.58c.15.2.29.38.4.57s.26.37.37.56c.12.18.24.37.35.57s.23.4.33.6a3 3 0 01-.97-1 4.67 4.67 0 01-.31-.61c-.07-.22-.15-.45-.17-.69z"/>
<path d="M102.93 120.3c.1.23.2.43.33.64.12.2.25.4.36.63s.2.47.22.72-.02.54-.18.74c.03-.25 0-.47-.07-.7s-.17-.41-.27-.62-.22-.43-.3-.66c-.08-.24-.14-.5-.1-.75z"/>
<path d="M101.53 88.39c.33.66.55.99.55 1.65 0 .77.33.99.66 1.54l.33.66v.66c0 .55-.33 1.43.11 1.98.11.44.33.88.44 1.43.22.44-.22.66-.22.99-.11.11-.11.22-.11.33a.7.7 0 010 .66v.22c-.22.44-.66.55-.99.77-.55.55-1.1.88-1.87 1.21l-.66.22c-.44.22-.88.22-1.32.33s-.88.44-1.32.55c-.22.11-.44.11-.66.11-.99.22-2.2-.55-2.64-.55-.11 0-.22 0-.44-.11-.11 0-.22 0-.33-.11s-.22-.33-.22-.55c0 .22.11.44.33.55s.44.11.66.11c1.43.44 1.32.44 2.64.44.22 0 .44 0 .66-.11.44-.11.77-.55 1.21-.66.77 0 1.43-.22 2.09-.55.66-.11 1.1-.66 1.65-1.1.22-.33.88-.33.88-.77.11-.22.11-.44.11-.66 0-.11-.11-.22 0-.33.22-.44.22-.44.22-.99 0-.44-.22-.77-.44-1.21a2.57 2.57 0 010-2.2v-.66c0-.22-.11-.33-.22-.55-.22-.33-.55-.66-.55-.99-.11-.22-.11-.44-.11-.66.11-.33-.11-.66-.11-.99z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 43 KiB

68
charges/cannon.svg Normal file
View file

@ -0,0 +1,68 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="#d7374a" stroke="#000" viewBox="50 50 200 200">
<metadata source="http://wappenwiki.org/images/0/0d/Smolensk_1857.svg" license="https://creativecommons.org/licenses/by-nc-sa/3.0"/>
<g id="cannon" stroke-width="3">
<path stroke-width=".4" d="M98.15 99.13l10.87 20.33 3.8 3.44-.94-26.38-13.73 2.61z"/>
<g transform="matrix(.13 0 0 .13 56.46 96.74)">
<g transform="translate(263 154)">
<path d="M-11.4-23.6c3.5 3.5 5.2 15 5.2 21.9v20.2h17.4V-1.7c0-6.8 1.6-18.4 5.2-21.9"/>
<path d="M16.1-25.5c-3.5-3.5-5.2-15-5.2-21.9v-20.2H-6.5v20.2c0 6.8-1.6 18.4-5.2 21.9"/>
<path d="M2.3-18.3c-8.8 0-14.6-2.6-14.8-2.8-1.6-.8-2.2-3-1.9-4.7.3-1.9 1.5-3.1 2.9-3.1.4 0 .7.1 1 .2 0 0 5.1 2.3 12.7 2.3s12.7-2.3 12.8-2.3c.3-.2.7-.2 1-.2 1.4 0 2.6 1.2 2.9 3.1.3 1.8-.3 4-1.9 4.7-.4.3-6 2.8-14.7 2.8z"/>
<path d="M-70.1-109.8c-3.5 3.5-15 5.2-21.9 5.2h-20.2v17.4H-92c6.8 0 18.4 1.6 21.9 5.2"/>
<path d="M-68.9-79.3c-1.7 0-3.2-.8-3.8-2-.3-.6-2.8-6.2-2.8-14.8s2.5-14.2 2.8-14.8c.6-1.2 2-2 3.8-2 .3 0 .6 0 .9.1 1.3.2 2.3.9 2.8 1.8.4.7.4 1.5 0 2.2 0 0-2.3 5.1-2.3 12.7s2.3 12.7 2.3 12.8c.1.3.2.7.2 1 0 1.4-1.2 2.6-3.1 2.9-.2.1-.5.1-.8.1h0z"/>
<path d="M-58.7-54.6c0 5-7 14.3-11.8 19.1l-14.3 14.3 12.3 12.3 14.3-14.3C-53.4-28-44.1-35-39.1-35"/>
<path d="M-37.8-36.5c0-5 7-14.3 11.8-19.1l14.3-14.3L-24-82.2l-14.3 14.3c-4.8 4.8-14.1 11.8-19.1 11.8"/>
<path d="M43.9-35.1c5 0 14.3 7 19.1 11.8L77.3-9l12.3-12.3-14.3-14.3c-4.8-4.8-11.8-14.1-11.8-19.1"/>
<path d="M62-55.9c-5 0-14.3-7-19.1-11.8L28.6-82 16.3-69.8l14.3 14.3c4.8 4.8 11.8 14.1 11.8 19.1"/>
<path d="M43.9-32.4c-1.3 0-2.8-.8-3.7-2.2-.8-1.1-1-2.3-.7-3.3.2-.7.8-1.3 1.5-1.6 0 0 5.2-2 10.6-7.4C57-52.3 59-57.5 59-57.5a2.49 2.49 0 012.5-1.6c.8 0 1.6.3 2.4.9 1.5 1 2.6 3 2 4.7-.2.6-2.5 6.4-8.5 12.4-6.1 6.1-11.8 8.3-12.4 8.5-.4.2-.7.2-1.1.2h0z"/>
<path d="M-112.9-162.5C-76.1-226.2 5.3-248 68.9-211.2S154.4-93 117.6-29.4C80.8 34.3-.6 56.1-64.2 19.3c-63.7-36.7-85.5-118.1-48.7-181.8zM-48.4-8C.2 20.1 62.4 3.4 90.5-45.2S101.9-156 53.3-184.1s-110.8-11.4-138.9 37.2S-97.1-36.1-48.4-8z"/>
<path d="M2.3-136.2c-22.1 0-40.1 18-40.1 40.1S-19.8-56 2.3-56s40.1-18 40.1-40.1-17.9-40.1-40.1-40.1zm0 60.2a20 20 0 1120-20c.1 11-8.9 20-20 20z"/>
<circle cx="2.3" cy="-96.1" r="20"/>
</g>
<g>
<path d="M304.9-106.1c6.3-.9 14-11.3 19.8-15.6 9.6-7 21.4-4.9 30 4 2.6 2.7 2.9 3.8 5.7 6.2 2.9 2.4 7.2 3.2 10.9 3l17.5-.8s-2.8-.7-7.9-5.8c-4.2-4.2-8.3-8.6-12.4-12.9-13.8-14.4-35.6-16.9-52.7-6.5-8.6 5.2-15.4 17.6-25.6 19-1.6.2-3.2.2-4.7.6-4.1 1-6.8 5.2-6.7 9.4 0 .1 25.1-.5 26.1-.6z"/>
<ellipse cx="51.7" cy="-68.6" rx="19.6" ry="48.4"/>
<ellipse cx="51.7" cy="-68.6" rx="5.9" ry="24.2"/>
<circle cx="628.3" cy="-68.6" r="15.8"/>
<path d="M614.6-77c-14.7-11.9-25.2-29.8-40.5-46.3 5.4 7.4 15.4 22.4 15.4 54.7s-10 47.3-15.4 54.7c15.4-16.5 25.8-34.4 40.5-46.3 0 0-1-3.4-1-8.4s1-8.4 1-8.4z"/>
<path d="M51.7-20.2c10.8 0 19.6-21.7 19.6-48.4S62.5-117 51.7-117c59 15 194.5 7 272.7 5.1 113-2.7 249.6-11.4 249.6-11.4 5.4 7.4 15.4 22.4 15.4 54.7s-10 47.3-15.4 54.7c0 0-136.5-8.8-249.6-11.4-78.2-1.8-212.8-10.1-272.7 5.1z"/>
<path d="M395.9-18c-.6 0-1.3-.1-1.9-.3-3.3-1.1-5.1-2.5-4.1-5.8.1-.3 3.8-12.9 3.8-44.5 0-31.8-3.8-44.4-3.8-44.5-1-3.3.8-4.7 4.1-5.8 3.3-1 6.8.8 7.9 4 .2.6 4.4 12 4.4 46.3s-4.2 45.7-4.4 46.3c-.8 2.6-3.3 4.3-6 4.3z"/>
<path d="M502.8-12.2c-.6 0-1.3-.1-1.9-.3-3.3-1.1-5.1-2.5-4.1-5.8.1-.3 4.3-14.5 4.3-50.2 0-35.9-4.3-50.1-4.3-50.3-1-3.3.8-4.7 4.1-5.8 3.3-1 6.8.8 7.9 4.1.2.6 4.9 13.6 4.9 52s-4.7 51.4-4.9 52c-.9 2.6-3.4 4.3-6 4.3z"/>
<path d="M249.1-21.4c-.6 0-1.3-.1-1.9-.3-3.3-1.1-5.1-2.5-4.1-5.8.1-.3 3.5-11.9 3.5-41 0-29.3-3.5-40.9-3.5-41-1-3.3.8-4.7 4.1-5.8 3.3-1 6.8.8 7.9 4 .2.5 4.1 11 4.1 42.8s-4 42.3-4.1 42.8c-.9 2.6-3.3 4.3-6 4.3z"/>
<path d="M131.6-22.7c-.6 0-1.3-.1-1.9-.3-3.3-1.1-5.1-2.5-4.1-5.8.1-.3 3.4-11.6 3.4-39.8 0-28.5-3.4-39.7-3.4-39.8-1-3.3.8-4.7 4.1-5.8 3.3-1 6.8.8 7.9 4 .2.5 4 10.7 4 41.6s-3.8 41.1-4 41.6a6.3 6.3 0 01-6 4.3z"/>
<path d="M344.8-112.4c6.3-.9 14-11.3 19.8-15.6 9.6-7 21.4-4.9 30 4 2.6 2.7 2.9 3.8 5.7 6.2 2.9 2.4 7.2 3.2 10.9 3l17.5-.8s-2.8-.7-7.9-5.8c-4.2-4.2-8.3-8.6-12.4-12.9-13.8-14.4-35.6-16.9-52.7-6.5-8.6 5.2-15.4 17.6-25.6 19-1.6.2-3.2.2-4.7.6-4.1 1-6.8 5.2-6.7 9.4-.1.1 25.1-.5 26.1-.6z"/>
</g>
<path d="M620.4 166.3c-11.2 0-19.7-5.9-25.2-14.2-5-7.6-7.5-16.8-13.8-23.5-7.8-8.4-21.2-10.9-31.5-6 1.7-30.3-25.1-46.4-50.3-37.3L435.8-43.6H193v88.4h157l83.6 156.4h186.7l.1-34.9h0z"/>
<path d="M182.7-13.9l-9.8-8.9-1-6.4h-8.2v47.6L193 44.8v-88.4h-6l-4.3 29.7z"/>
<circle cx="513.4" cy="123.1" r="17.6"/>
<g transform="translate(163 82)">
<path d="M179-86.6c-3.5-3.5-5.2-15-5.2-21.9v-20.2h-17.4v20.2c0 6.8-1.6 18.4-5.2 21.9"/>
<path d="M151.5-84.6c3.5 3.5 5.2 15 5.2 21.9v20.2h17.4v-20.2c0-6.8 1.6-18.4 5.2-21.9"/>
<path d="M179-81.3c-.4 0-.7-.1-1-.2 0 0-5.1-2.3-12.7-2.3s-12.7 2.3-12.8 2.3c-.3.1-.7.2-1 .2-1.4 0-2.6-1.2-2.9-3.1-.3-1.8.3-4 1.9-4.7.6-.3 6.2-2.8 14.8-2.8s14.2 2.5 14.8 2.8c1.6.8 2.2 3 1.9 4.7-.3 1.9-1.5 3.1-3 3.1z"/>
<path d="M151.5 58.4c3.5 3.5 5.2 15 5.2 21.9v20.2h17.4V80.3c0-6.8 1.6-18.4 5.2-21.9"/>
<path d="M179 56.5c-3.5-3.5-5.2-15-5.2-21.9V14.4h-17.4v20.2c0 6.8-1.6 18.4-5.2 21.9"/>
<path d="M165.2 63.7c-8.8 0-14.6-2.6-14.8-2.8-1.6-.8-2.2-3-1.9-4.7.3-1.9 1.5-3.1 2.9-3.1.4 0 .7.1 1 .2 0 0 5.1 2.3 12.7 2.3s12.7-2.3 12.8-2.3c.3-.2.7-.2 1-.2 1.4 0 2.6 1.2 2.9 3.1.3 1.8-.3 4-1.9 4.7-.4.3-6 2.8-14.7 2.8z"/>
<path d="M237.7-.3c3.5-3.5 15-5.2 21.9-5.2h20.2v-17.4h-20.2c-6.8 0-18.4-1.6-21.9-5.2"/>
<path d="M235.8-27.9c-3.5 3.5-15 5.2-21.9 5.2h-20.2v17.4h20.2c6.8 0 18.4 1.6 21.9 5.2"/>
<path d="M236.5 2.7c-.3 0-.6 0-.9-.1a3.8 3.8 0 01-2.8-1.8c-.4-.7-.4-1.5-.1-2.2 0 0 2.3-5.1 2.3-12.7s-2.3-12.7-2.3-12.8c-.2-.3-.2-.7-.2-1 0-1.4 1.2-2.6 3.1-2.9.3-.1.6-.1.9-.1 1.7 0 3.2.8 3.8 2 .1.2 2.8 6 2.8 14.8 0 8.6-2.5 14.2-2.8 14.8-.6 1.3-2.1 2-3.8 2h0z"/>
<path d="M92.8-27.8c-3.5 3.5-15 5.2-21.9 5.2H50.7v17.4h20.2c6.8 0 18.4 1.6 21.9 5.2"/>
<path d="M94.7-.3c3.5-3.5 15-5.2 21.9-5.2h20.2v-17.4h-20.2c-6.8 0-18.4-1.6-21.9-5.2"/>
<path d="M94 2.7c-1.7 0-3.2-.8-3.8-2-.3-.6-2.8-6.2-2.8-14.8s2.5-14.2 2.8-14.8c.6-1.2 2-2 3.8-2 .3 0 .6 0 .9.1 1.3.2 2.3.9 2.8 1.8.4.7.4 1.5 0 2.2 0 0-2.3 5.1-2.3 12.7s2.3 12.7 2.3 12.8c.1.3.2.7.2 1 0 1.4-1.2 2.6-3.1 2.9-.2.1-.5.1-.8.1h0z"/>
<path d="M226.3-55.6c0-5 7-14.3 11.8-19.1L252.4-89l-12.3-12.3L225.8-87c-4.8 4.8-14.1 11.8-19.1 11.8"/>
<path d="M205.4-73.7c0 5-7 14.3-11.8 19.1l-14.3 14.3L191.6-28l14.3-14.3c4.8-4.8 14.1-11.8 19.1-11.8"/>
<path d="M224.4-51.1c-1.1 0-2.1-.6-2.4-1.6 0 0-2-5.2-7.4-10.6-5.4-5.4-10.6-7.4-10.6-7.4-.3-.1-.6-.3-.9-.6-1-1-1-2.7.1-4.3.9-1.3 2.4-2.2 3.7-2.2.3 0 .7.1 1 .2.6.2 6.4 2.5 12.4 8.5 6.1 6.1 8.3 11.8 8.5 12.4.6 1.7-.5 3.6-2 4.7-.8.6-1.6.9-2.4.9h0z"/>
<path d="M104.2 27.4c0 5-7 14.3-11.8 19.1L78.1 60.8l12.3 12.3 14.3-14.3C109.5 54 118.8 47 123.8 47"/>
<path d="M125.1 45.5c0-5 7-14.3 11.8-19.1l14.3-14.3L138.9-.2l-14.3 14.3c-4.8 4.8-14.1 11.8-19.1 11.8"/>
<path d="M123.6 49.6c-.3 0-.7-.1-1-.2-.6-.2-6.4-2.5-12.4-8.5-6.1-6.1-8.3-11.8-8.5-12.4-.6-1.7.5-3.6 2-4.7.8-.6 1.6-.9 2.4-.9 1.1 0 2.1.6 2.4 1.6 0 0 2 5.3 7.4 10.6 5.4 5.4 10.6 7.4 10.6 7.4.3.1.6.3.9.6 1 1 1 2.7-.1 4.3a4.5 4.5 0 01-3.7 2.2h0z"/>
<path d="M206.8 46.9c5 0 14.3 7 19.1 11.8L240.2 73l12.3-12.3-14.3-14.3c-4.8-4.8-11.8-14.1-11.8-19.1"/>
<path d="M224.9 26.1c-5 0-14.3-7-19.1-11.8L191.5 0l-12.3 12.2 14.3 14.3c4.8 4.8 11.8 14.1 11.8 19.1"/>
<path d="M206.8 49.6c-1.3 0-2.8-.8-3.7-2.2-.8-1.1-1-2.3-.7-3.3.2-.7.8-1.3 1.5-1.6 0 0 5.2-2 10.6-7.4 5.4-5.4 7.4-10.6 7.4-10.6a2.49 2.49 0 012.5-1.6c.8 0 1.6.3 2.4.9 1.5 1 2.6 3 2 4.7-.2.6-2.5 6.4-8.5 12.4-6.1 6.1-11.8 8.3-12.4 8.5-.4.2-.7.2-1.1.2h0z"/>
<path d="M123.7-75.1c-5 0-14.3-7-19.1-11.8l-14.3-14.3L78-88.9l14.3 14.3c4.8 4.8 11.8 14.1 11.8 19.1"/>
<path d="M105.6-54.2c5 0 14.3 7 19.1 11.8L139-28.1l12.3-12.3L137-54.7c-4.8-4.8-11.8-14.1-11.8-19.1"/>
<path d="M106.1-51.1c-.8 0-1.6-.3-2.4-.9-1.5-1-2.6-3-2-4.7.2-.6 2.5-6.4 8.5-12.4 6.1-6.1 11.8-8.3 12.4-8.5.3-.1.6-.2 1-.2 1.3 0 2.8.8 3.7 2.2.8 1.1 1 2.3.7 3.3-.2.7-.8 1.3-1.5 1.6 0 0-5.3 2-10.6 7.4-5.4 5.4-7.4 10.6-7.4 10.6-.1.3-.3.6-.6.9-.4.4-1.1.7-1.8.7h0z"/>
<path d="M50-80.5c36.8-63.7 118.2-85.5 181.8-48.7S317.3-11 280.5 52.6c-36.8 63.7-118.2 85.5-181.8 48.7C35 64.6 13.2-16.8 50-80.5zM114.5 74c48.6 28.1 110.8 11.4 138.9-37.2S264.8-74 216.2-102.1 105.4-113.5 77.3-64.9 65.8 45.9 114.5 74z"/>
<path d="M165.2-54.2c-22.1 0-40.1 18-40.1 40.1s18 40.1 40.1 40.1 40.1-18 40.1-40.1-17.9-40.1-40.1-40.1zm0 60.2a20 20 0 1120-20c.1 11-8.9 20-20 20z"/>
<circle cx="165.2" cy="-14.1" r="20"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.7 KiB

10
charges/chain.svg Normal file
View file

@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="#d7374a" stroke="#000" viewBox="50 50 200 200">
<metadata source="http://wappenwiki.org/images/5/50/Neuhoff.svg" license="https://creativecommons.org/licenses/by-nc-sa/3.0"/>
<g id="chain" stroke-width="3" transform="translate(50 50) scale(0.12)">
<path d="M410.6 553.4c-23.7 0-46.8-11.8-64.8-33.3-20.9-24.8-32.5-58.6-32.5-95s11.5-70.2 32.5-95c18.1-21.5 41.1-33.3 64.8-33.3s46.8 11.8 64.8 33.3c20.9 24.8 32.5 58.6 32.5 95s-11.5 70.2-32.5 95c-18.1 21.5-41.1 33.3-64.8 33.3m0 68.6c91.6 0 165.9-88.2 165.9-197s-74.3-197-165.9-197-165.9 88.2-165.9 197 74.2 197 165.9 197h0z"/>
<path d="M335.3 249.5c-14.3-22.8-22.1-50.9-22.1-80.8 0-20.7 3.7-40.5 10.7-58.3-23.1-5.6-44.9-13.2-64.9-22.2-9.3 24.6-14.5 51.8-14.5 80.5 0 49 15.1 93.7 40 128.2 14.2-19.5 31.4-35.7 50.8-47.4z"/>
<path d="M562 88.2c-20.1 9-41.8 16.6-64.9 22.2 7 17.8 10.7 37.6 10.7 58.3 0 36.5-11.5 70.2-32.5 95-18.1 21.5-41.1 33.3-64.8 33.3-1.5 0-3 0-4.4-.1-22.2 1.4-43.4 13-60.4 33.1-3.8 4.5-7.2 9.3-10.4 14.3 22.6 13.6 48.1 21.4 75.2 21.4 91.6 0 165.9-88.2 165.9-197 .1-28.7-5.1-55.9-14.4-80.5z"/>
<path d="M335.4 600.6c-19.4-11.8-36.7-27.9-50.8-47.4-24.9 34.5-40 79.2-40 128.2 0 28.7 5.2 55.9 14.5 80.5 20.1-9 41.8-16.6 64.9-22.2-7-17.8-10.7-37.6-10.7-58.3 0-29.9 7.7-57.9 22.1-80.8z"/>
<path d="M410.6 484.4c-27.1 0-52.6 7.7-75.2 21.4 3.1 5 6.6 9.8 10.4 14.3 16.9 20.1 38.2 31.8 60.4 33.1 1.5-.1 2.9-.1 4.4-.1 23.7 0 46.8 11.8 64.8 33.3 20.9 24.8 32.5 58.6 32.5 95 0 20.7-3.7 40.5-10.7 58.3 23.1 5.6 44.9 13.2 64.9 22.2 9.3-24.6 14.5-51.8 14.5-80.5-.1-108.8-74.4-197-166-197z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

73
charges/crown2.svg Normal file
View file

@ -0,0 +1,73 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="#d7374a" stroke="#000" viewBox="50 50 200 200">
<metadata source="http://wappenwiki.org/images/1/1c/Astrakhan.svg" license="https://creativecommons.org/licenses/by-nc-sa/3.0"/>
<g id="crown2" stroke-width="0.57">
<path d="M130.07 93.52c-3.3-3-6.9-3.5-11.07-3.55-3.77-.06-7.19 2.56-10.95 1.67-3.11-.72-5.53-3.61-8.68-4.1-3.69-.6-7.03 2.22-10.66 3.1-3.8.9-7.22-1.19-10.87-.73-3.23.4-6.55 1.77-8.99 4.05-3.68 3.44-3.53 9.65-1.8 14.51 1.75 4.87 4.73 9.2 5.95 14.25l26.63-.19 26.64-.19c1.16-5.05 4.1-9.44 5.78-14.32 1.69-4.89 1.76-11.12-1.98-14.5z"/>
<path d="M75.18 135.43c2.07-.45 13.47-1.21 24.95-1.21 11.4 0 22.82.74 24.95 1.21-1.32 0-8.2 1.37-24.95 1.37-16.76 0-23.7-1.37-24.95-1.37z"/>
<g fill="#f2bc51" stroke-width="3" transform="matrix(.19 0 0 .19 22 46)">
<path d="M254.4 356.9c-8.8-11-15.9-23.2-20.9-36.3-5.1-13.1-7.8-27.3-7.8-41.6-.1-14.3 3.5-28.9 10-41.9 1.5-3.3 3.7-6.3 5.5-9.4 2-2.9 4.1-5.7 6.3-8.4 4.4-5.4 9.4-10.5 14.7-15 10.6-9.1 22.8-16.2 35.6-21.4 6.4-2.6 12.9-4.6 19.5-6.3 6.6-1.6 12.9-2.9 19.4-4.1 25.8-4.7 52.1-6.8 78.4-6.1l-.3 16.6c-25-.1-50.1 2.5-74.6 7.5-6.1 1.2-12.3 2.7-18.1 4.3-5.8 1.6-11.5 3.5-16.9 5.9-10.9 4.7-21 11-29.7 18.8-4.3 3.9-8.3 8.2-11.9 12.8-1.8 2.3-3.4 4.7-5.1 7.1-1.3 2.5-2.9 4.7-4 7.3-4.7 10-7.3 21.1-6.9 32.4.3 22.7 10.3 45.3 25.1 63l-18.3 14.8z"/>
<path d="M415.3 347s4.7 40 38 40c28 0 50.5-29.7 50.5-29.7s4.7 37.5 37.2 37.5c18.6 0 44.7-36.6 44.7-36.6s-19.7 61.1-25.5 99.3l-149.9-6.7-149.9 6.7c-5.8-38.3-25.5-99.3-25.5-99.3s26.1 36.6 44.7 36.6c32.7 0 37.2-37.5 37.2-37.5s22.5 33.3 50.5 33.3c33.6 0 38-40 38-40l6.9 3.3h0l3.1-6.9z"/>
<path d="M410.6 406.1c-81.9 0-142.1 11.1-158.2 13.3-4.4.8-7.2-1.4-7.8-4.4-.6-3.1 2.2-8.9 6.1-9.4 13-2.5 61.6-13.3 160.1-13.3s146.8 10.8 159.8 13.3c3.9.6 6.7 6.1 6.1 9.4-.6 3.1-3.3 5-7.8 4.4-16.5-2.2-76.4-13.3-158.3-13.3z"/>
<path d="M309.6 373.2c6-5.7 13.3-8.8 21.2-10.3a229.9 229.9 0 01-7.8-38.8c-2.4-20.5-2.3-41.5 1.4-61.3 2-9.9 4.9-19.2 9.6-27.2 4.9-8.2 11.5-15.6 19-22.1 15.2-12.8 34.1-21.4 53.8-24.2l-2.1-16.7c-23.1 2.6-45.3 12-63.5 26.6-9.1 7.4-17.3 16-23.7 26.2-3.2 5.1-5.9 10.8-8 16.3-2.1 5.6-3.7 11.2-5 16.8-2.5 11.3-3.8 22.6-4.3 33.9-.6 11.3-.2 22.6.8 33.8 1.5 15.9 4.3 31.6 8.6 47z"/>
<path d="M566.5 356.9c8.8-11 15.9-23.2 20.9-36.3 5.1-13.1 7.8-27.3 7.8-41.6.1-14.3-3.5-28.9-10-41.9-1.5-3.3-3.7-6.3-5.5-9.4-2-2.9-4.1-5.7-6.3-8.4-4.4-5.4-9.4-10.5-14.7-15-10.6-9.1-22.8-16.2-35.6-21.4-6.4-2.6-12.9-4.6-19.5-6.3-6.6-1.6-12.9-2.9-19.4-4.1-25.8-4.7-52.1-6.8-78.4-6.1l.3 16.6c25-.1 50.1 2.5 74.6 7.5 6.1 1.2 12.3 2.7 18.1 4.3 5.8 1.6 11.5 3.5 16.9 5.9 10.9 4.7 21 11 29.7 18.8 4.3 3.9 8.3 8.2 11.9 12.8 1.8 2.3 3.4 4.7 5.1 7.1 1.3 2.5 2.9 4.7 4 7.3 4.7 10 7.3 21.1 6.9 32.4-.3 22.7-10.3 45.3-25.1 63l18.3 14.8z"/>
<path d="M511.3 373.2c-6-5.7-13.3-8.8-21.2-10.3 3.7-12.6 6.3-25.6 7.8-38.8 2.4-20.5 2.3-41.5-1.4-61.3-2-9.9-4.9-19.2-9.6-27.2-4.9-8.2-11.5-15.6-19-22.1a107.84 107.84 0 00-53.8-24.2l2.1-16.7c23.1 2.6 45.3 12 63.5 26.6 9.1 7.4 17.3 16 23.7 26.2 3.2 5.1 5.9 10.8 8 16.3 2.1 5.6 3.7 11.2 5 16.8 2.5 11.3 3.8 22.6 4.3 33.9.6 11.3.2 22.6-.8 33.8-1.4 15.9-4.2 31.6-8.6 47z"/>
<polygon points="372.5 104.6 403.7 109.2 399.4 77.2 423.7 77.2 419.7 109.2 451 104.6 451 128.9 419.1 122.8 415.7 159.7 407.4 159.7 404 122.8 372.5 128.9"/>
<polygon points="391.8 309.1 429.5 309.1 426.7 175.2 394.5 175.2"/>
<path d="M390.7 167.6c0 10.8 8.9 13.5 20 13.5 10.8 0 20-2.6 20-13.5 0-10.8-8.9-19.7-20-19.7-11.1-.3-20 8.9-20 19.7z"/>
<path d="M454.2 393.9c-12.2 0-22.8-5.8-30-15.3-8.9-10.3-13.6-23.6-13.6-23.6s-6.4 15.3-13.3 23.6c-7.2 9.4-17.8 15.3-29.7 15.3-29.7 0-48.3-30.2-48.3-30.2s-5.5 34.7-37.2 34.7c-28 0-42.7-33.9-42.7-33.9l3.9-17.2s14.4 35.8 40 35.8c18.9 0 25.3-22.5 29.1-34.1 2.2-7.5 3.9-8.9 10.5-1.7 8.6 10.3 22.2 31.1 44.4 31.1 29.4 0 33.6-48 33.6-48H420s4.2 48 33.6 48c22.2 0 35.8-20.8 44.4-31.1 6.4-7.5 8-6.1 10.8 1.7 3.6 11.7 10 34.1 29.1 34.1 25.5 0 40-35.8 40-35.8l3.9 17.2s-14.7 33.9-42.7 33.9c-31.1 0-37.2-34.7-37.2-34.7s-18 30.2-47.7 30.2z"/>
<path d="M402 336.7c21.1 0 31.6 22.2 46.6 22.2 21.1 0 16.7-20.8 16.7-26.4 0-5.3 4.7-26.4-16.7-26.4-15.3 0-25.5 22.2-46.6 22.2"/>
<path d="M420.1 336.7c-21.1 0-31.4 22.2-46.6 22.2-21.1 0-17.5-20.8-17.5-26.4 0-5.3-3.9-26.4 17.5-26.4 15.3 0 25.5 22.2 46.6 22.2"/>
<path d="M591 350s5.8-29.4 13-56.9c-5.8-1.7-28.3-10-33.9 10-3.6 14.4 18.6 29.4 13.3 49.1"/>
<path d="M596.6 356.1c-20.8-4.4-36.4 14.7-51.1 11.7-20.5-4.4-11.4-23.9-10-29.4 1.4-5.3 2.8-26.4 23.6-22.2 15 3.3 19.4 26.9 40 31.4"/>
<path d="M415.6 335.6c0-20.5 25.3-30.2 25.3-45.2 0-20.3-24.1-16.6-30.2-16.6-6.1 0-30.2-3.6-30.2 16.6 0 14.7 25.3 24.7 25.3 45.2"/>
<path d="M230.8 350s-5.8-29.4-13-56.9c5.8-1.7 28.3-10 33.9 10 3.6 14.4-18.6 29.4-13.3 49.1"/>
<path d="M225.3 356.1c20.8-4.4 36.4 14.7 51.1 11.7 20.5-4.4 11.4-23.9 10-29.4-1.4-5.3-2.8-26.4-23.6-22.2-15 3.3-19.4 26.9-40.2 31.4"/>
<path d="M252.1 469.5c.6 5.3 3.7 8.1 7.5 9.3 28.2 11 94.5 14.5 151.4 14.5 56.9 0 122.9-3.1 151.4-14.5 3.7-1.6 6.9-4.5 7.5-9.3.3-4.9-1.4-8.5-5.7-9.3-3.7-1.2-74.7-11.6-153.1-11.6-78.7 0-149.1 10.4-153.1 11.6-4.2.4-6.2 4-5.9 9.3zm27.8 1.2c10.9-2.4 70.9-6.4 131.3-6.4 60 0 120.1 3.9 131.3 6.4-6.9 0-43.1 7.2-131.3 7.2-88.2 0-124.7-7.2-131.3-7.2z"/>
</g>
<g fill="#000" stroke="none">
<path d="M74.95 95.44c-.07.6-.13 1.21-.11 1.8a10.9 10.9 0 00.59 3.5c.19.57.43 1.1.72 1.65a5.28 5.28 0 01-1.05-1.52 6.8 6.8 0 01-.63-3.65c.06-.6.22-1.23.48-1.78z"/>
<path d="M91.54 94.22c-.23.74-.74 1.39-1.33 1.9s-1.27.93-1.94 1.31c-.66.38-1.33.76-1.94 1.18-.6.44-1.17.95-1.61 1.6.27-.74.78-1.37 1.39-1.86.6-.52 1.27-.92 1.93-1.3.67-.38 1.33-.76 1.94-1.2.61-.43 1.16-.96 1.56-1.63z"/>
<path d="M109.13 95.08c-.01.8.38 1.5.88 2.07.51.57 1.14 1.02 1.7 1.63a5.4 5.4 0 011.2 2.11c.27.74.5 1.5.82 2.22-.5-.62-.82-1.36-1.16-2.09a7.2 7.2 0 00-1.2-1.93c-.5-.57-1.13-1.07-1.63-1.73-.25-.33-.44-.7-.57-1.09-.11-.4-.15-.81-.04-1.2z"/>
<path d="M124.98 96.14c-.25.8-.68 1.52-1.16 2.2-.47.69-1 1.32-1.52 1.96-.51.63-1.02 1.27-1.46 1.96a7.17 7.17 0 00-.97 2.24 5.4 5.4 0 01.66-2.41c.38-.76.9-1.43 1.41-2.07.53-.65 1.08-1.26 1.6-1.88.53-.63 1.02-1.28 1.44-2z"/>
</g>
<g fill="#f6f6f6">
<path d="M118.48 127.89a2.38 2.38 0 01-2.43 2.38 2.38 2.38 0 010-4.76 2.43 2.43 0 012.43 2.38z"/>
<path d="M131.23 129.85a2.49 2.49 0 01-2.85 1.9c-.68-.15-.83-1.28-.53-2.53.32-1.31 1-2.26 1.58-2.1a2.21 2.21 0 011.8 2.73z"/>
<path d="M81.62 127.89a2.38 2.38 0 002.43 2.38c1.32 0 2.44-1.07 2.44-2.38s-1.07-2.38-2.44-2.38-2.43 1.07-2.43 2.38z"/>
<path d="M95.23 127.11c0 1.58 2.16 2.9 4.8 2.9 2.7 0 4.81-1.3 4.81-2.9s-2.17-2.9-4.8-2.9c-2.65.1-4.81 1.36-4.81 2.9z"/>
<path d="M68.85 129.85a2.49 2.49 0 002.85 1.9c.69-.15.84-1.28.54-2.53-.33-1.31-1.01-2.26-1.58-2.1a2.19 2.19 0 00-1.8 2.73z"/>
<path d="M70.75 86.47c.69.59 1.32.19 1.92-.47.6-.69.93-1.35.3-1.98a1.71 1.71 0 00-2.33.13c-.59.67-.5 1.73.11 2.32z"/>
<path d="M75.92 81.9c.32.83 1.08.77 1.94.48.84-.32 1.48-.77 1.16-1.61s-1.24-1.31-2.13-.95a1.67 1.67 0 00-.97 2.07z"/>
<path d="M82.74 79.48c.14.9.88 1 1.77.93.9-.13 1.63-.42 1.5-1.31a1.64 1.64 0 00-1.84-1.43c-.88.14-1.54.97-1.43 1.8z"/>
<path d="M89.92 78.28c.14.9.88 1 1.77.93.9-.13 1.64-.42 1.5-1.3a1.64 1.64 0 00-1.84-1.43c-.9.13-1.54.96-1.43 1.8z"/>
<path d="M66.63 91.73c.78.48 1.37-.07 1.8-.83.48-.78.69-1.5-.1-1.98a1.65 1.65 0 00-2.27.59c-.47.72-.23 1.73.57 2.22z"/>
<path d="M65.5 98.46c.88 0 1.13-.72 1.13-1.62s-.2-1.65-1.1-1.67-1.64.7-1.67 1.66c-.02.85.76 1.63 1.63 1.63z"/>
<path d="M85.95 85.71c.6.68 1.28.38 1.96-.2.69-.6 1.12-1.2.57-1.93a1.69 1.69 0 00-2.32-.2c-.68.6-.72 1.67-.2 2.33z"/>
<path d="M91.9 81.23c.32.83 1.08.77 1.94.49.83-.32 1.48-.78 1.16-1.61a1.64 1.64 0 00-2.13-.95c-.84.32-1.27 1.29-.97 2.07z"/>
<path d="M82.13 91.18c.82.44 1.35-.17 1.73-.95.44-.82.57-1.54-.24-1.97-.82-.44-1.79-.06-2.23.76-.4.74-.07 1.74.74 2.16z"/>
<path d="M80.39 97.66c.87.12 1.21-.57 1.33-1.46.11-.88 0-1.67-.88-1.79-.87-.11-1.7.5-1.86 1.43-.13.83.53 1.7 1.4 1.82z"/>
<path d="M80.18 105.09c.87-.06 1.08-.8 1.02-1.7-.05-.86-.32-1.62-1.21-1.57a1.7 1.7 0 00-1.56 1.77c.04.83.87 1.56 1.75 1.5z"/>
<path d="M129.22 86.47c-.69.59-1.31.19-1.92-.47-.6-.69-.93-1.35-.3-1.98a1.71 1.71 0 012.33.13c.6.67.5 1.73-.11 2.32z"/>
<path d="M124.05 81.9c-.32.83-1.08.77-1.94.48-.83-.32-1.48-.77-1.16-1.61s1.24-1.31 2.13-.95c.82.3 1.27 1.27.97 2.07z"/>
<path d="M117.23 79.48c-.14.9-.88 1-1.77.93-.9-.13-1.63-.42-1.5-1.31.13-.9.91-1.56 1.84-1.43.88.14 1.54.97 1.43 1.8z"/>
<path d="M110.06 78.28c-.13.9-.87 1-1.76.93-.9-.13-1.64-.42-1.5-1.3.13-.9.9-1.57 1.84-1.43.87.13 1.54.96 1.43 1.8z"/>
<path d="M133.36 91.73c-.78.48-1.37-.07-1.8-.83-.48-.78-.69-1.5.1-1.98a1.65 1.65 0 012.27.59c.45.72.2 1.73-.57 2.22z"/>
<path d="M134.48 98.46c-.9 0-1.14-.72-1.14-1.62s.2-1.65 1.1-1.67 1.64.7 1.67 1.66c.02.85-.74 1.63-1.63 1.63z"/>
<path d="M114.02 85.71c-.6.68-1.28.38-1.96-.2-.68-.6-1.12-1.2-.57-1.93a1.69 1.69 0 012.32-.2c.68.6.74 1.67.2 2.33z"/>
<path d="M108.07 81.23c-.32.83-1.08.77-1.94.49-.83-.32-1.48-.78-1.16-1.61a1.64 1.64 0 012.13-.95c.84.32 1.3 1.29.97 2.07z"/>
<path d="M117.84 91.18c-.82.44-1.35-.17-1.73-.95-.44-.82-.57-1.54.24-1.97.82-.44 1.79-.06 2.23.76.4.74.07 1.74-.74 2.16z"/>
<path d="M119.58 97.66c-.87.12-1.21-.57-1.33-1.46-.11-.88 0-1.67.88-1.79.87-.11 1.7.5 1.86 1.43.13.83-.53 1.7-1.4 1.82z"/>
<path d="M119.8 105.09c-.88-.06-1.09-.8-1.03-1.7.05-.86.32-1.62 1.21-1.57.88.06 1.6.82 1.56 1.77-.04.83-.85 1.56-1.75 1.5z"/>
<path d="M101.69 94.83c0 .9-.75 1.14-1.64 1.14-.9 0-1.63-.15-1.69-1.08s.68-1.64 1.63-1.7c.9 0 1.7.75 1.7 1.64z"/>
<path d="M101.69 89.76c0 .89-.75 1.14-1.64 1.14-.9 0-1.63-.16-1.69-1.09-.06-.93.68-1.63 1.63-1.69.9 0 1.7.74 1.7 1.64z"/>
<path d="M101.69 84.68c0 .9-.75 1.14-1.64 1.14-.9 0-1.63-.15-1.69-1.08-.06-.93.68-1.63 1.63-1.69.9 0 1.7.74 1.7 1.63z"/>
<path d="M135.92 113.3a2.95 2.95 0 01-3.47 2.16c-.84-.15-.95-1.52-.53-3.05.36-1.52 1.3-2.7 2.05-2.53a2.78 2.78 0 011.95 3.42z"/>
<path d="M96.86 109.02a3.21 3.21 0 006.42 0 3.19 3.19 0 00-3.2-3.17 3.22 3.22 0 00-3.22 3.17z"/>
<path d="M64.16 113.3a2.95 2.95 0 003.48 2.16c.83-.15.95-1.52.53-3.05-.36-1.52-1.31-2.7-2.05-2.53a2.74 2.74 0 00-1.96 3.42z"/>
<path d="M81.89 108.19c1.82 0 3.3 1.42 3.3 3.19s-1.48 3.2-3.3 3.2a3.25 3.25 0 01-3.3-3.2c0-1.71 1.47-3.2 3.3-3.2z"/>
<path d="M118.25 108.19c-1.82 0-3.3 1.42-3.3 3.19s1.48 3.2 3.3 3.2c1.83 0 3.31-1.43 3.31-3.2 0-1.71-1.48-3.2-3.3-3.2z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB

10
charges/falchion.svg Normal file
View file

@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="#d7374a" stroke="#000" viewBox="50 50 200 200">
<metadata source="http://wappenwiki.org/images/8/81/Essex.svg" license="https://creativecommons.org/licenses/by-nc-sa/3.0"/>
<g id="falchion" stroke-width="3" transform="matrix(0,-0.11,0.11,0,79.1,145)">
<path d="M205 161.1l-5.6 56.6s97.3 1 229.3 12.8c1.1-21.6 17.7-38.8 39.6-38.8 22.6 0 39.6 18.4 39.6 41 0 2.5-.2 4.9-.6 7.2 54.2 7.9 87 18 131.4 34.1 20.9-34.6 80.4-76.3 124.2-84.8C506.5 121.6 205 161.1 205 161.1z"/>
<path d="M103 168l-10.9 19 10.9 16 87 1c7 0 11-9 11-19 0-8-5-16-11-18z"/>
<path d="M71 229.4c-9.6-4.2-17.4-14.6-17.7-26.2-.3-10.7 1.9-23.4 10.5-29.2 9.9-6.7 28.3-5.7 43.4-6v.7c-3.5 3.1-5.3 9.9-5.3 16.9.1 6.4 1.7 13 5 16.4v1.1c-8.2 0-14.9-.2-18.7 8.4-3.8 8.6 3.1 9.9.2 14.9-2.5 4.4-9.9 6.3-17.4 3zM219.8 92.3c-17.6 0-26.2 15.5-28.9 33.7-1.2 9.7-3.4 48.8-3.4 61.6v0h0c0 .1 6 23.9 5.7 40-.1 7.1-.7 17.6-1.9 21.9-1.1 3.7-3.3 9.6-8.5 9.6-3.4 0-3.8-1.4-6.1-3.1-2.1-1.5-2.8-2.7-6.7-2.7-7 0-10 5.9-10 12.5 0 9.7 7.1 17.1 19 17.1 17.6 0 26.2-15.5 28.9-33.7 1.2-9.7 3.4-48.8 3.4-61.6 0 0-6-23.9-5.7-40 .1-7.1.7-17.6 1.9-21.9 1.1-3.7 3.3-9.6 8.5-9.6 3.4 0 3.8 1.4 6.1 3.1 2.1 1.5 2.8 2.7 6.7 2.7 7 0 10-5.9 10-12.5 0-9.7-7.1-17.1-19-17.1z"/>
<path fill="#000" stroke="none" d="M211.6 187.5s3.2-.1 8.8-.2h10.1c3.9 0 8.3 0 13 .1 4.8.1 10 .2 15.4.3 5.5.1 11.2.3 17.2.5s12.1.5 18.4.8c6.3.3 12.6.6 19 1s12.7.7 19 1.1c6.3.4 12.4.8 18.4 1.2 6 .4 11.7.9 17.2 1.3 5.5.5 10.6.9 15.4 1.3 4.8.4 9.1.8 13 1.1 3.9.4 7.2.7 10 .9 5.5.5 8.7.8 8.7.8s-3.2-.2-8.7-.7c-2.8-.2-6.1-.5-10-.8-3.9-.3-8.2-.6-13-.9-4.8-.3-9.9-.7-15.4-1.1-5.5-.3-11.2-.7-17.2-1-6-.4-12.1-.6-18.4-1-6.3-.3-12.6-.6-19-.9-6.4-.3-12.7-.5-19-.7-6.3-.2-12.4-.3-18.4-.5-6-.1-11.7-.2-17.2-.3-5.5-.1-10.6-.1-15.4-.1-4.8 0-9.1 0-13 .1-3.9 0-7.2.1-10 .2-5.6.1-8.7.3-8.7.3l-.2-2.8z"/>
<path fill="none" stroke="#000" stroke-width="3" stroke-miterlimit="10" d="M175.8 167.2c-5.2 1.7-7.8 9.9-7.7 18.4.1 8 2.6 16.4 7.7 18.3M153.7 167.2c-5.2 1.7-7.8 9.9-7.7 18.4.1 8 2.6 16.4 7.7 18.3M131.9 167.2c-5.2 1.7-7.8 9.9-7.7 18.4.1 8 2.6 16.4 7.7 18.3"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

14
charges/foot.svg Normal file
View file

@ -0,0 +1,14 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="#d7374a" stroke="#000" viewBox="50 50 200 200">
<metadata source="http://wappenwiki.org/images/e/e9/Barfod.svg" license="https://creativecommons.org/licenses/by-nc-sa/3.0"/>
<g id="foot" stroke-width="3" transform="translate(43 44) scale(0.14)">
<path d="M439.2 152.4c0 102.7 32.2 189.6 31.5 228.6-.4 22.6-4.6 43.2-14.1 62-12.3 24.3-45.1 41.2-71.9 50.5-10.3 3.6-25.4 13.8-33.8 20.7-19.7 16.2-36.5 31.8-54.4 39.1-18.3 5.9-33.4 8-51.8 16.6-8.6 4-28.5 14.1-38.6 17.5-14 4.6-36.2.4-49.5.4-5.1.2-8.8 7.2-9.5 8.1-.2.2-.2.4-.3.6-2.4 0-4.2 0-5 .1-1.3-.1-6.5 4.4-5.1 5.6-4.1 22.8-.2 53.1 27 53.1 19.2 0 32.5-1.4 45.6-5.8 11.8-4.4 23.4-9.1 35.3-3.7 11 5.3 37.3 16.1 64.3 15.7 41.5-.4 56.1-6.7 74.1-16.4 15.9-7.4 43.9-16 85.8-16 42.8 0 76.7 19.1 114.4 29 22.5 6 45.6 2.8 60.9-4.8 15.7-7.8 31.1-23.9 35.4-42.2 5.7-23.6-.6-50.9-13.4-71.5-22.4-36.3-36.3-82.5-36.3-136.9 0-52.7 45.8-134.9 45.8-250.4"/>
<path d="M439.2 152.4c0-9.4 49-17.1 112.8-17.1s123.7 7.7 123.7 17.1-59.9 17.1-123.7 17.1c-63.8 0-112.8-7.7-112.8-17.1z"/>
<path fill="none" d="M220.5 593.3c-12.9 4.4-29.5 4.8-32.6 4.3-3.7-.6-41.4-1.2-46.1-.9"/>
<path fill="none" d="M188.4 597.5c0 14.5-29.9 13-38.3 11.8-5.9-.9-4.9-5.7-7.9-12.8"/>
<g fill="#000" stroke="none">
<path d="M282.3 575.5s-.3 0-.7-.1c-.5-.1-1.2-.1-2.1-.1-.9-.1-2 0-3.2.1-.6.1-1.3.1-1.9.2l-2.1.3c-1.5.2-3.1.5-4.8.9-1.7.4-3.5.8-5.3 1.4-3.6 1-7.4 2.4-11.2 3.9-7.5 2.9-14.9 6.4-20.5 8.8-2.8 1.2-5.2 2.2-6.8 2.9-.8.3-1.5.6-2 .7-.5.2-.7.3-.7.3l-1-2.8s.2-.1.7-.2c.4-.1 1.1-.4 1.9-.7 1.6-.6 4-1.5 6.8-2.6 5.6-2.3 13.1-5.5 20.8-8.3 3.8-1.4 7.7-2.6 11.5-3.6 3.7-1 7.3-1.6 10.4-1.9 1.5-.1 3-.1 4.2 0 .6 0 1.2.1 1.7.2.5 0 1 .1 1.5.2.9.1 1.6.3 2 .4.5-.1.8 0 .8 0z"/>
<path d="M595 437.1s-.1.1-.2.4c-.1.3-.3.7-.5 1.2-.4 1.1-.9 2.7-1.3 4.7-.4 2.1-.5 4.7-.3 7.6.1 1.5.3 3 .7 4.6.3 1.6.7 3.3 1.3 5 1.2 3.5 2.5 7.2 3.6 11.4 1.1 4.1 2 8.5 2.4 13.2.4 4.7.2 9.6-.9 14.5a33.8 33.8 0 01-6.4 13.7 40 40 0 01-11.5 9.8c-2.2 1.3-4.5 2.2-6.8 3-2.3.8-4.7 1.4-7 1.7a47.22 47.22 0 01-19.6-1c-2-.5-3.8-1.1-5.5-1.8a39.1 39.1 0 01-8.9-4.9c-2.5-1.8-4.4-3.6-5.8-5.2-1.4-1.6-2.3-3.1-2.9-4.1l-.8-1.6.9 1.5c.7.9 1.7 2.3 3.2 3.8 1.5 1.5 3.5 3.2 6 4.7 2.5 1.6 5.5 3 8.9 4.2a48.06 48.06 0 0024.1 1.8c2.2-.4 4.4-1 6.5-1.8 2.1-.8 4.3-1.7 6.2-2.9 4.1-2.3 7.7-5.4 10.6-9.1 2.9-3.7 4.9-8 5.9-12.6 1.1-4.5 1.3-9.2 1.1-13.6-.3-4.5-1-8.8-1.9-12.9-.9-4.1-2.1-7.8-3-11.4-1-3.7-1.3-7-1.4-10.1 0-3 .3-5.7.8-7.8.5-2.1 1.2-3.7 1.7-4.7.2-.5.5-.9.6-1.2.1.1.2-.1.2-.1z"/>
<path d="M621.8 473.6s.2 1.1.5 2.9c.3 1.9.8 4.5 1.3 7.7.3 1.6.6 3.3.9 5.1.4 1.8.7 3.7 1.1 5.6.2 1 .4 2 .7 2.9.3 1 .5 2 .8 3 .5 2 1.1 4.1 1.7 6.1l1.8 6.1c.7 1.9 1.4 3.9 2.1 5.7.7 1.8 1.5 3.6 2.2 5.3.8 1.7 1.5 3.2 2.2 4.6a43.24 43.24 0 003.1 5.3c.3.5.6.9.9 1.2.6.7 1 1.3 1.4 1.6.4.3.6.5.6.5s-.2-.1-.7-.4c-.5-.2-1-.7-1.8-1.3l-1.1-1.1c-.4-.4-.8-.9-1.2-1.4-.8-1-1.7-2.2-2.6-3.6-.9-1.4-1.8-2.9-2.7-4.5a63 63 0 01-2.6-5.2c-.8-1.9-1.7-3.8-2.4-5.8s-1.3-4.1-2-6.1c-.6-2.1-1.2-4.2-1.6-6.2-.5-2.1-.9-4.1-1.2-6.2-.4-2-.5-4-.7-5.8-.2-1.8-.3-3.6-.4-5.2-.1-3.2-.2-5.9-.2-7.8-.2-1.9-.1-3-.1-3z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3 KiB

108
charges/greyhoundSejant.svg Normal file
View file

@ -0,0 +1,108 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="#d7374a" stroke="#000" viewBox="50 50 200 200">
<metadata source="http://wappenwiki.org/images/2/26/Brixen.svg" license="https://creativecommons.org/licenses/by-nc-sa/3.0"/>
<g id="greyhoundSejant" stroke-width=".36">
<path d="M80.18 136.12c.15 0 .15-.64 1.12-1.11.62-.33 1.53-.15 1.53-.15l.29-1.63-2.86-.67-2.12-.6-1.17.34s-.26.02-.44.87c-.13.6.08 1.59.35 1.59.15 0 .37-.84 1.45-1.36-.03.06-.05.2-.05.2-.18.84-.06 1.8.2 1.8.16 0 .5-.85 1.58-1.36.02-.02-.1.16-.14.4-.18.84-.02 1.68.26 1.68"/>
<path d="M100.4 136.12c.15 0 .15-.64 1.12-1.11.62-.33 1.53-.15 1.53-.15l.29-1.63-2.86-.67-2.12-.6-1.17.34s-.26.02-.44.87c-.13.6.08 1.59.35 1.59.15 0 .37-.84 1.45-1.36-.03.06-.05.2-.05.2-.18.84-.06 1.8.2 1.8.16 0 .5-.85 1.58-1.36.02-.02-.1.16-.14.4-.18.84 0 1.68.26 1.68"/>
<path d="M98.79 132.79c-.04 0-.53-.3-.91-.45-.82-.14-.88.15-.9.15-.09 0-.33-.36-.2-.7s.33-.61.76-.61c.6-.1.89-.36 1.33-.48.65-.17 1.4.26 1.89.23.49-.04-.69.8-.77 1-.07.2-1.2.86-1.2.86z"/>
<path d="M113.4 122.95c.54-1.62.58-3.36.62-5.07.03-1.62.03-3.34-.82-4.72-1.1-1.78-3.26-2.49-5.27-3.08-1.76-.51-3.57-1.03-5.4-.87-2.27.2-2.06 1.08-2.99 2.82-.7 1.32-3.3 2.24-3.6 4.03a8.64 8.64 0 00.12 4.03 18.36 18.36 0 002.37 5.47c.63.93 1.4 1.76 2.17 2.58.37.4 1.24.93 1.76 1.12.45.17.9.23 1.35.42.26.12.55.24.81.14.05 0 .1-.03.15-.02.07.02.1.1.13.16.1.16.34.21.54.21.2-.01.4-.05.6 0 .16.05.29.15.43.24a2 2 0 001.93.05.47.47 0 01.22-.05c.23.03.44.03.67 0a.4.4 0 01.41.25c.1.26.13.6-.28.71-1.2.4-4.17.2-5.26.07-.6-.06-2.22-.57-2.85-.56-.62.01-.96.26-1.49.5-.03 0-.45-.1-.81.42a.85.85 0 00-.16.32.4.4 0 00.42.51c.33-.03.85.07 1.63.69l.08.07.04.03s.38-.25.9-.03l.05.02c.75.45.95 1.03 1.01 1.29.04.15.16.27.31.3.12.03.28.04.5 0 .23-.03.68-.17.87-.4a.4.4 0 01.36-.16c.3.03.54.2.88.28.42.1.97-.25 1.3-.02.15.1.78.2 1.2.15.9-.1 1.65-.48 2.58-.44.6.02 1.2.18 1.8.19.17 0 .34-.04.5-.12.21-.1.34-.22.6-.24.4-.05.76-.17 1.15-.25.48-.1 1.04-.03 1.53-.03.15 0 .3 0 .45-.02.42-.05.9-.32 1-.77.09-.43-.26-.87-.41-1.26-.17-.4-.1-1.02 0-1.51a.4.4 0 01.75-.1"/>
<path d="M81.32 75.79s-2.86-1.42-5.33-1.3c-2.6.13-4.08 1.38-5.51 1.45-2.68.16-2.84-.98-3.12-.97-.2.06-.1.8.23 1.07.32.28 1.19 1.07 3.05.98 2.26-.12 3.3-1.18 5.48-1.3a9.18 9.18 0 015.06 1.3"/>
<path fill="#F6F6F6" stroke-width=".26" d="M72.24 76.03c-.08-.03-.56.79-.6 1.44l.06-.03c.24-.1.45-.12.65-.1-.08-.48-.03-1.29-.1-1.31z"/>
<path fill="#F6F6F6" stroke-width=".26" d="M71.56 74.83c.12-.1-.42-.67-.68-1.37a.95.95 0 01-.08-.35c-.28.03-.56.1-.87.07-.06 0-.27.02-.31 0 .26.5 1.14 1.65 1.94 1.65z"/>
<path d="M90.96 66.5c-.62-.9-.96-3.91-2.65-3.68-1.32.19-2.11.2-2.94.8a5.45 5.45 0 00-1.35 1.45"/>
<path d="M89.57 109.56a3.3 3.3 0 01.69-3.33c.26-.27.57-.51.75-.85.31-.56.17-1.26.01-1.88-.22-.9-.5-1.78-.8-2.64-.17-.48-.37-1-.8-1.29a1.93 1.93 0 00-1.29-.23c-.87.08-1.71.35-2.55.62-1.84.58-2.63 1.3-3.68 2.92-1.09 1.7-1.82 3.47-1.8 5.32 0 1.78.06 3.52.2 5.3v.02c0 1.57 1 4.46 1 5.64-.04 4.47-.25 5.94-.25 6.8 0 .55-.12 1.63-.12 2.02l-.01.08c-.05.2-.25 1-.56 1.7l-.04.05c-.8 1.25-1.94.2-2.92 1.13a.46.46 0 01-.2.1c-.36.07-.52.44-.65.74-.13.34.11.7.2.7.02 0 .17-.28.83-.16l.11.04.66.32c.11.05.23.05.34.01.25-.1.85-.19 1.88.63l.07.07.05.03s.37-.25.89-.03l.06.02c.72.43.94.99 1 1.25.03.14.15.26.3.3.12.02.27.05.5.05.52 0 .72.08 1.13-.22.61-.45.47-.32.9-1.14 0 0 .49-1.07.49-1.98s-.38-2.39-.47-2.96c0 0-.12-.95-.18-2.25s.83-6.28 1.32-7.72c.41-1.2.99-3.4 2.19-4.3.3-.23.66-1 .85-1.43l.01-.03c.18-.53.4-1.9-.62-2.49l-.04-.02s0 0 0 0c-.36-.3 0-.87.43-.67"/>
<path d="M102.11 115.78a4.84 4.84 0 00-1.05-.72c-1.35-.62-3.14-.85-3.14-.85s-.72-.05-.7-.48a.6.6 0 01.33-.53c.78-.37 2.82-.48 2.82-.48"/>
<path d="M82.12 137.34c.16 0 .16-.65 1.13-1.12.61-.32 1.52-.14 1.52-.14l.29-1.64-2.86-.67-2.12-.6-1.16.34s-.27.02-.45.87c-.13.6.09 1.59.35 1.59.16 0 .37-.84 1.45-1.36l-.05.2c-.18.85-.06 1.8.2 1.8.16 0 .5-.85 1.58-1.36.02-.01-.1.17-.13.4-.18.85-.01 1.69.25 1.69"/>
<path d="M102.82 137.34c.16 0 .16-.65 1.13-1.12.61-.32 1.52-.14 1.52-.14l.29-1.64-2.86-.67-2.12-.6-1.16.34s-.27.02-.45.87c-.13.6.09 1.59.35 1.59.16 0 .37-.84 1.45-1.36l-.05.2c-.18.85-.06 1.8.2 1.8.16 0 .5-.85 1.58-1.36.02-.01-.1.17-.13.4-.18.85-.01 1.69.25 1.69"/>
<path d="M101.21 133.99c-.03 0-.53-.3-.91-.45-.82-.14-.88.15-.9.15-.08 0-.32-.36-.2-.7s.33-.61.76-.61c.6-.1.9-.36 1.34-.48.64-.17 1.39.26 1.88.23.5-.04-.68.8-.77 1-.07.21-1.2.86-1.2.86z"/>
<path d="M127.14 102.3c-.1-3.58 1.17-6.18.78-6.65-.58-.09-3.18 2.8-3.18 7.9 0 11.33 7.74 15.1 7.74 21.37 0 3.51-1.92 5.8-5.17 5.8-.67 0-1.34-.1-1.97-.32a4.97 4.97 0 01-2.9-3.14 7.83 7.83 0 01-.38-1.97c-.04-.6.02-1.21 0-1.81-.04-.63-.11-1.26-.2-1.88-.45-3.2-1.96-7.34-4.06-9.8-3.56-4.18-8.44-7.21-10.97-9.64-4.67-4.48-6.78-7.02-8.77-12.06-1.25-3.14-1.74-5.73-2.32-7.66-.84-3.46-.12-6.64-.37-8.84s-.43-3.14-1.54-4.8c-1.1-1.65-1.68-1.86-2.36-2.31-1.29-.87-2.76-1.73-4.78-1.72-.73.03-1.27-.18-1.74-.19-.59-.01-1.03-.16-1.94-.02-.63.12-1.4.32-2.15.52a4.8 4.8 0 00-2.2.58c-.56.47-.6.53-.84.77-.27.19-1.17.79-2.83 1.19-1.65.4-2.16.24-3.83.57-1 .2-2.32.66-2.64.7-.32.02-1.41.15-1.76.43-.23.14-.26.5-.31.7-.05.24.1.82.37 1.1.18.26.04.5.34.82.15.18.24.24.75.57.54.35.8.93 1.49.97.25.02.8-.14 1.07-.14.65 0 2.3.4 2.69.5.6.06 1.24-.55 2.12-.56.68-.01 1.25.3 1.52.34.26.02 1.04.27 1.29.33.51.12 1.6.64 2.05.89.23.12 1.4 1.64 1.18 2.06-.22.42-2.67-.33-3.83-.2-1.18.14-1.21 0-1.7.08s-.76.32-1.2.38c-.3.03-.5.07-.8.06-.3-.02-.59.19-.89.18-.28 0-.68-.05-.98-.04-.26.01-.5.06-.74.18-.15.06-.28.2-.2.4.04.12.3.25.41.28.35.11.77.34 1.13.32.31-.05.68-.17 1.08-.18.46-.02.73 0 1.21-.05.3-.03.7.1 1.01.07.65-.06 1.46-.29 1.9-.23.43.06 1 .25 1.42.34.62.12 1.04.1 1.56.19.57.1 1.01-.01 1.5.24.96.5.32.32 1.76.47 0 0 .26 1.6-.39 3.19-1.03 2-2.04 2.2-3.01 3.5-.97 1.52-2.86 3.12-2.93 5.76a7.97 7.97 0 00-.23 6.96c.3 1.13-.08 2.37.5 3.36.49.84.9 1.74 1.45 2.56.55.82 1.04 1.42 1.7 2.14.46.5 1.2.74 1.2.74-.36 2.8-.03 5.87.06 7.12 0 1.57 1.01 4.47 1 5.65-.04 4.47-.24 5.94-.24 6.8 0 .58-.13 1.73-.12 2.05 0 0-.23.99-.59 1.78-.82 1.33-2.02.17-3.01 1.25-.45 0-.63.42-.76.75-.13.34.11.7.2.7.02 0 .19-.29.9-.14l.9.44s.6-.6 2.07.58c.01.03.07.07.07.07s.4-.27.91-.03c1.02.6 1.06 1.44 1.06 1.44s.1.18.78.18c.52 0 .72.09 1.13-.21.61-.46.47-.33.9-1.14 0 0 .49-1.07.49-1.98s-.38-2.39-.47-2.97c0 0-.12-.94-.18-2.24-.06-1.3.83-6.29 1.32-7.73.41-1.2.99-3.4 2.19-4.3.3-.22.67-1.01.85-1.45.18-.51.4-1.93-.64-2.5 0 0-.62-.45-.17-.99 3.27 1.93 7.3.28 10.23 3.18-1.87.93-2.79 1.7-3.03 3.13a9.8 9.8 0 00.48 4.28 18.36 18.36 0 002.37 5.47c.63.92 1.4 1.75 2.17 2.58.37.4 1.24.92 1.76 1.11.45.17.9.23 1.35.42.26.12.55.24.81.15.05-.01.1-.04.15-.03.07.03.1.1.13.16.1.17.34.22.54.22.2-.02.4-.05.6 0 .16.04.29.14.43.24a2 2 0 002.04-.02c.35.06.7.04 1.05-.02 0 0 .54.83-.14 1-1.2.4-4.17.19-5.26.07-.6-.06-2.22-.58-2.85-.57-.62.02-.96.27-1.49.5-.03 0-.45-.1-.81.43-.24.3-.28.95-.13.97 0 0 .6-.6 2.07.58.01.03.07.07.07.07s.4-.27.92-.03c1.02.6 1.05 1.44 1.05 1.44s.11.28.78.18c.29-.04.85-.22.95-.55.44-.1.72.17 1.15.27.42.1.97-.26 1.31-.03.14.1.78.2 1.2.16.89-.1 1.64-.48 2.58-.45.58.03 1.14.17 1.72.18.15 0 .3 0 .45-.06.28-.1.42-.26.72-.3.41-.04.77-.16 1.15-.25.48-.1 1.05-.02 1.54-.02.14 0 .3 0 .44-.03.42-.04.9-.32 1-.76.1-.44-.25-.88-.4-1.26-.3-.72.18-2.25.18-2.25.42.27.41.34.64.78.35.67 1 1.19 1.73 1.33.59.84 1.43.69 1.73.87.1.05.16.12.25.18.9.65 2.07.21 3.08.19a7.82 7.82 0 006.36-3.64 10.15 10.15 0 001.56-5.68c-.1-9.03-8.39-10.73-8.39-22.62z"/>
<path d="M92.22 67.68c.6-.17 1.54-.2 1.9-.39.82-.44 1.75-.32 2.34-.65s3.1-.48 3.22-1.22c.13-.73-2.75-1.06-2.75-1.06s-1.67-.37-3.31-.54c-1.34-.14-2.25-.48-3.2-.1-.81.33-1.77.26-2.3 1.23-.17.31-.38.7-.58 1.01"/>
<path fill="#F6F6F6" d="M80.85 67.94c-.13.22-.67.4-1.1.44-.44.05-.8-.06-.88-.32-.22-.46.24-1.06.51-1.04.28-.03 1.04.51 1.47.92z"/>
<g fill="none">
<path d="M80.06 131.38c-.03.03-.88-.1-1.24.44-.24.3-.4.94-.25.97"/>
<path d="M98.55 133.4c0-.08.13-.64.36-.76"/>
<path d="M101.04 113.9c1.13-.34 1.98-.74 3.8-.8 1.1-.02 2.65.36 4 1"/>
<path d="M82 132.6c-.02.02-.88-.1-1.24.43-.24.3-.4.95-.25.97"/>
<path d="M82.88 129.22c-.06 1.37-.39 2.81-.88 3.38"/>
<path d="M102.71 135.25s.22-.36.65-.61"/>
<path d="M100.97 134.61c0-.08.13-.63.36-.75"/>
<path d="M82.02 102.7c-.08.68-.18 1.86-.07 2.87.09.8.36 1.25.23 2.03"/>
<path d="M90.82 110.72c.76-1.73 1.84-3.61 2.02-6.65v-.27"/>
<path d="M82.01 135.25s.22-.36.65-.61"/>
<path d="M80.27 134.61c0-.08.13-.63.36-.75"/>
</g>
<g fill="#000" stroke="none">
<path d="M88.7 68.6c0-.4-.1-.8.2-1.1.7-.8.9-1.9 1.7-2.7.7-.5 1.6-.2 2.4-.2.8.1 1.5.3 2.3.3.8-.1 1.5.2 2.3.3-.8 0-1.6-.1-2.3-.1h-1.9c-.8-.1-1.6-.4-2.4-.1-.8.5-.9 1.4-1.5 2-.4.5-.9 1-.8 1.6z"/>
<path d="M99.75 131.2l.06.02h.07l.1.03.25.06.27.1c.18.07.35.17.47.25.12.08.18.16.18.16l-.02.02-.2-.1a3 3 0 00-.49-.15l-.26-.04h-.44v-.35z"/>
<path d="M97.56 130.99l.05.01.13.02c.11.03.26.05.4.1s.28.1.37.17c.05.02.09.06.11.08l.04.04-.03.02-.03-.02c-.03-.01-.06-.04-.11-.05-.1-.04-.23-.05-.37-.05l-.38.01-.13.02h-.05V131z"/>
<path d="M100.18 133.54l-.07.06-.09.06a.6.6 0 00-.1.09l-.11.1-.13.1-.14.12c-.04.04-.08.09-.13.12-.05.04-.08.09-.13.12l-.12.12-.2.23-.2.24-.04-.01s0-.13.1-.31c.04-.09.09-.2.16-.3l.12-.14.13-.13.15-.12.15-.1a.65.65 0 01.16-.09l.14-.06c.09-.04.17-.06.22-.07.1-.04.12-.04.13-.03z"/>
<path d="M98.3 133.08l-.05.06-.15.13-.19.18-.21.21-.41.41-.2.2-.03-.02s.02-.12.1-.26a2.05 2.05 0 01.62-.68l.13-.08c.04-.02.09-.03.12-.06a.99.99 0 01.2-.07c.03-.02.07-.02.07-.02z"/>
<path d="M80.08 131.2l.06.02c.04.02.1 0 .17.03.07.01.15.04.24.07s.17.08.25.12a1.65 1.65 0 01.42.32c.1.1.14.19.14.19l-.03.02-.04-.05-.12-.1-.19-.1c-.07-.04-.16-.06-.24-.08-.08-.03-.17-.04-.24-.05l-.22-.01h-.21l.01-.38z"/>
<path d="M77.34 130.84l.05.02c.04 0 .07 0 .13.02.06.01.14.02.2.05l.22.08c.15.06.28.16.36.24l.09.11c.02.02.02.05.02.05l-.03.01-.04-.04a.42.42 0 00-.1-.07.85.85 0 00-.37-.12l-.2-.01h-.18l-.13.01h-.05l.03-.35z"/>
<path d="M78.08 133.08l-.05.06-.15.13-.19.18-.21.21-.41.41-.2.2-.03-.02s.02-.12.1-.26a2.05 2.05 0 01.62-.68l.13-.08c.04-.02.09-.03.12-.06a.99.99 0 01.2-.07c.03-.02.05-.02.07-.02z"/>
<path d="M81.62 130.34v-.1a4.1 4.1 0 00.07-.46l.03-.2c.03-.14.05-.3.06-.44.03-.14.04-.29.06-.43a.7.7 0 00.03-.2l.02-.19a5.5 5.5 0 01.06-.38l.03.1.04.28c.02.12.03.26.03.4l-.01.23-.03.23c-.01.07-.02.15-.05.22 0 .08-.03.15-.06.22a2.28 2.28 0 01-.26.62c0 .06-.02.1-.02.1z"/>
<path d="M119.98 131.04l-.02-.03-.03-.02-.01-.01-.02-.03-.09-.13-.07-.16c-.05-.1-.08-.24-.13-.37a4.3 4.3 0 01-.13-.42l-.15-.4c-.05-.14-.1-.26-.15-.35l-.08-.14-.07-.1-.07-.06.08.06.09.08.1.12c.07.1.14.2.2.32l.2.4.2.4c.05.12.11.24.17.32a1.06 1.06 0 00.12.18l.02.01v.01l.03.03.03.01-.22.28z"/>
<path d="M88.28 86.94s.02.1 0 .24c0 .07-.03.14-.05.22l-.06.12c-.03.04-.05.08-.09.11l-.1.1-.1.08-.1.06-.13.04c-.08.01-.15 0-.19-.03-.02 0-.04-.02-.04-.03v-.01l.05-.03c.04-.01.06-.05.1-.1l.05-.07a.36.36 0 01.06-.08c.04-.06.1-.1.14-.17l.3-.3.12-.1c.01-.04.04-.05.04-.05z"/>
<path d="M89.63 87.78v.1l-.02.14-.04.16a.57.57 0 01-.07.18l-.1.2-.15.19-.17.18c-.06.06-.12.1-.2.15a.78.78 0 01-.2.14l-.2.1-.2.05-.16.04-.13.01h-.11l.08-.07.23-.17.15-.1c.04-.04.1-.1.15-.13l.16-.13.15-.14.16-.16.14-.16.14-.14.12-.14.18-.22.1-.08z"/>
<path d="M77.4 91.76l.09-.16.1-.18.16-.22c.06-.08.13-.17.22-.24.08-.09.17-.16.26-.24l.28-.23.25-.27a5.62 5.62 0 01.98-.98l.5-.4-.46.44c-.13.13-.29.28-.44.46a5.24 5.24 0 00-.45.58c-.07.1-.15.22-.24.31l-.25.27-.23.24c-.07.07-.12.15-.17.22l-.12.22a.64.64 0 00-.07.17l-.06.15-.35-.14z"/>
<path d="M108.92 113.94l.15.08.18.1.23.13.26.17.3.2.3.23.28.25.14.13.14.15.24.28.1.15.1.14.16.27c.03.08.08.16.1.24l.06.19.05.17-.06-.17c-.01-.05-.05-.11-.08-.18-.03-.07-.09-.15-.12-.23a1.95 1.95 0 00-.18-.25l-.11-.13-.12-.14-.26-.25-.15-.12-.14-.12-.3-.21-.3-.2-.29-.16-.26-.15-.23-.1-.18-.09-.16-.07.15-.31z"/>
<path d="M111.87 131.42l.6-.08.14-.03h.11c.04 0 .07.01.1.03.15.04.24.15.32.22.16.17.32.33.5.47.2.15.4.25.6.31a41.4 41.4 0 001.2.22l-.6-.05c-.18-.01-.4-.02-.62-.07a2.22 2.22 0 01-.68-.28 3.27 3.27 0 01-.58-.44.6.6 0 00-.22-.14h-.1l-.12.03-.6.15-.05-.34z"/>
<path d="M110.66 126.22l.07.15.08.17.11.2c.04.07.1.14.14.23l.18.24c.08.07.14.15.22.24l.24.23.26.2.27.18.26.14c.09.04.17.09.25.11l.22.09.18.06.16.04-.17.03-.2.01h-.11l-.14-.01c-.04-.01-.1-.01-.14-.03l-.16-.03-.3-.11c-.12-.05-.22-.1-.32-.17l-.3-.21a2.74 2.74 0 01-.48-.56c-.06-.1-.12-.19-.16-.3-.02-.04-.03-.1-.06-.14 0-.05-.02-.1-.04-.13l-.04-.13-.02-.12-.03-.2.03-.18z"/>
<path d="M112.98 127.2l.05.15.11.37c.1.3.22.69.42 1.02.05.09.1.16.17.24l.18.22a1.8 1.8 0 00.4.31l.17.1.16.06.1.03.04.02h-.03l-.11.02h-.18l-.1-.01c-.04-.01-.08-.03-.13-.03a2.16 2.16 0 01-.25-.1c-.08-.04-.18-.09-.26-.16a1.43 1.43 0 01-.24-.23 2.06 2.06 0 01-.46-.89 1.3 1.3 0 01-.05-.3l-.01-.26.02-.4v-.15z"/>
<path d="M114.28 128.97c.08.17.18.33.28.47a5.62 5.62 0 00.7.82c.06.06.12.12.2.16l.21.16.22.14a1 1 0 00.23.12c.08.04.15.08.24.11l.24.09c.16.04.33.08.5.1.17.03.35.03.53.04h.01c.06 0 .12.05.13.1l.05.18.07.15a1 1 0 00.1.15c.03.04.07.1.12.13l.07.06.07.06.07.05.09.04.18.08.1.02.09.02c-.06.02-.13.02-.2.02l-.2-.03a.53.53 0 01-.19-.07l-.1-.05-.08-.06c-.06-.03-.1-.08-.15-.13l-.15-.16-.1-.18a.72.72 0 01-.09-.2l.16.1a3.08 3.08 0 01-1.16-.08c-.1-.02-.19-.06-.27-.1l-.27-.11-.25-.15c-.08-.04-.17-.1-.24-.16l-.21-.2c-.08-.07-.15-.13-.2-.2-.14-.14-.25-.3-.36-.46-.22-.3-.37-.66-.44-1.03z"/>
<path d="M113.67 117.52l.05.1c0 .04.03.07.03.12l.04.17v.1l-.01.1c0 .07-.03.15-.05.23-.03.07-.05.16-.1.22-.03.07-.08.14-.12.2-.18.26-.4.47-.59.61l-.21.17-.09.06.04-.1a2.1 2.1 0 01.31-.6l.25-.36.12-.16.05-.09.05-.08.08-.17c.03-.06.05-.1.06-.16.03-.04.03-.1.04-.14l.02-.12.03-.1z"/>
<path d="M114.71 119.06l.03.08.02.23a1.47 1.47 0 01-.16.65l-.08.16-.1.14c-.07.08-.14.17-.21.23a.7.7 0 01-.2.12l-.08.03.03-.08c0-.05.04-.12.07-.2.06-.16.15-.36.25-.56l.28-.54.1-.18.05-.08z"/>
<path d="M93.93 104.25v.12l.01.12c.01.07.02.16.05.23l.08.2.11.2.06.08.07.08.07.08.09.07.18.12.19.08c.06.03.13.04.22.05a.7.7 0 01.28.13.7.7 0 01.18.25l.05.12.04.11.14.46.13.45-.2-.1a.6.6 0 01.29 0 .8.8 0 01.42.27c.05.06.1.12.13.2.04.05.07.13.1.19l.08.19a1.31 1.31 0 00.23.35.83.83 0 01-.33-.3l-.13-.16-.12-.17a1.2 1.2 0 00-.27-.24.4.4 0 00-.16-.05h-.07l-.06.02c-.09.02-.17-.02-.2-.1v-.01l-.16-.45-.16-.44-.03-.1-.04-.1a.37.37 0 00-.08-.14.27.27 0 00-.15-.06l-.24-.08a1.5 1.5 0 01-.24-.12 1.38 1.38 0 01-.29-.26l-.08-.11-.07-.11a1.44 1.44 0 01-.2-.59c0-.08 0-.17.02-.25l.02-.12.04-.1z"/>
<path d="M97.58 109.2v.06c0 .03 0 .07.02.12l.08.16.16.18c.13.11.31.22.52.27l.08.02.08.01.17.04.37.06c.14.02.27.05.39.1l.19.07a.2.2 0 01.08.05c.03 0 .06.03.09.04.21.14.38.3.51.44.14.13.24.25.33.32l.13.12s-.06-.01-.17-.06c-.1-.05-.25-.12-.4-.23-.17-.1-.35-.21-.55-.31l-.07-.04-.08-.03-.16-.05-.35-.07-.37-.07-.19-.05c-.04-.01-.06-.03-.1-.03-.03 0-.04-.02-.08-.03-.25-.1-.44-.27-.56-.43a.95.95 0 01-.12-.26c-.03-.08-.03-.15-.03-.21s.01-.11.03-.13v-.05z"/>
<path d="M81 104.84v.13l.03.15.03.19.06.21.09.24a4.99 4.99 0 00.98 1.6l.09.1-.28.22-.08-.1-.2-.3a5.37 5.37 0 01-.46-.94l-.17-.54c-.03-.08-.04-.17-.05-.25l-.04-.23v-.34c-.02-.1 0-.14 0-.14z"/>
<path d="M119.54 120.43l.03.24a5.52 5.52 0 01.09 1.02l.02.45.01.5v.5l-.01.5-.01.5-.03.45v.4c.02.24.06.44.12.57.03.08.06.12.09.16l.03.05-.04-.04c-.02-.01-.04-.02-.06-.05l-.08-.07a1.5 1.5 0 01-.26-.59 4.42 4.42 0 01-.06-.42l-.02-.46-.02-.5v-.5c0-.17 0-.34.02-.5v-.5l.03-.45.04-.41.07-.61.04-.24z"/>
<path d="M118.31 121.3l-.03-.14c-.03-.08-.05-.2-.08-.35l-.22-1-.27-1.01a2.08 2.08 0 00-.1-.34l-.03-.13.1.1.1.11.11.17c.09.12.17.28.24.45l.11.26a2.6 2.6 0 01.14.58l.04.28.01.27-.01.24-.02.2-.04.16-.05.14z"/>
<path d="M102.17 132.4l.06.02h.07l.1.03.25.06.28.1c.18.07.35.17.47.25.12.08.18.16.18.16l-.03.02-.2-.1a3 3 0 00-.48-.15l-.27-.04h-.44l.01-.35z"/>
<path d="M99.99 132.2l.05.01.13.03c.1.02.25.04.4.1.14.04.27.1.37.16l.1.08.04.04-.02.02-.04-.02-.1-.05a1.4 1.4 0 00-.38-.05c-.13 0-.28 0-.37.02h-.13c-.04 0-.05.02-.05.02v-.36z"/>
<path d="M103.1 134.61a.45.45 0 010-.18.7.7 0 01.02-.17 1.06 1.06 0 01.22-.46l.12-.14.13-.1.13-.09a2.2 2.2 0 01.6-.26c.06-.01.1-.03.17-.03h.17a.7.7 0 01.16.03c.06.01.11.02.17.05h-.01l.22.07.2.08.2.1c.08.03.14.07.2.12l.18.14.15.16c.05.06.1.12.13.18.04.06.08.13.1.2l-.04.01-.3-.27-.18-.12a.36.36 0 01-.08-.06l-.08-.05a1.31 1.31 0 00-.18-.1c-.06-.02-.12-.06-.2-.08a1.18 1.18 0 00-.19-.06l-.2-.05h-.01a.43.43 0 00-.12-.02l-.12-.01h-.12l-.12.03c-.17.05-.34.13-.48.23l-.12.08a.6.6 0 00-.1.09l-.08.08c-.03.04-.05.06-.06.1a.74.74 0 00-.09.23l-.01.12v.12l-.38.03z"/>
<path d="M104.81 133.2l.16-.05.19-.06.26-.05.32-.04h.34l.36.03c.12 0 .26.03.38.05l.36.07c.12.02.24.06.34.1l.33.1.27.11c.17.07.32.14.4.2l.14.1v.04l-.6-.15a12.66 12.66 0 00-.6-.14l-.34-.07c-.12-.03-.24-.04-.35-.05l-.35-.04-.34-.01-.3.01-.28.04-.23.05c-.07 0-.13.03-.18.04l-.16.05-.12-.33z"/>
<path d="M104.81 135.62l-.36.08c-.05.02-.1.04-.17.05l-.18.06a.9.9 0 00-.18.09c-.06.02-.12.06-.18.1l-.16.11-.16.13-.28.24-.27.26-.04-.03s.05-.14.18-.33a2.15 2.15 0 01.42-.46c.06-.05.11-.1.2-.14a.9.9 0 01.21-.11c.07-.04.14-.05.22-.07.07-.03.14-.03.2-.04l.18-.01c.23.02.38.06.37.07z"/>
<path d="M102.6 134.76l-.07.06c-.02 0-.05.03-.08.06a.6.6 0 00-.1.08c-.03.04-.07.06-.12.1l-.13.1-.13.12-.13.12-.14.12a.46.46 0 01-.12.12l-.2.23-.2.24-.04-.01s.01-.13.1-.31l.16-.29.12-.14.14-.14.14-.12.16-.1c.04-.04.1-.06.15-.09l.15-.06.21-.07c.1-.04.12-.04.13-.02z"/>
<path d="M100.72 134.29l-.05.06-.14.13-.2.18-.21.22c-.14.14-.3.28-.4.4l-.2.2-.04-.02s.03-.12.1-.26c.04-.07.08-.16.16-.24a2.05 2.05 0 01.46-.44l.14-.08.12-.06a.99.99 0 01.19-.07c.03-.02.07-.02.07-.02z"/>
<path d="M122.32 133.12l-.04-.06-.08-.16a4.8 4.8 0 01-.2-.52 1.2 1.2 0 01-.04-.29v-.13l.01-.12c0-.04.03-.07.03-.1l.03-.07.04-.06-.01.06c-.02.03-.02.05-.02.07v.1c0 .04 0 .07.02.1 0 .04 0 .1.03.13.03.08.06.17.11.25.08.17.2.32.28.43l.1.13a.2.2 0 01.04.05l-.3.2z"/>
<path d="M107 129c1 0 1 1 1 1l-1-1z"/>
<path d="M110.32 130.54l.25.16c.16.1.36.22.55.36a1.9 1.9 0 00.56.29c.08.02.15.05.2.05h.07l-.1.36-.09-.04a2.67 2.67 0 01-.48-.28c-.1-.07-.18-.15-.28-.24l-.48-.45-.2-.2z"/>
<path d="M112.95 135.45l.08-.01.1-.01c.03-.01.07-.01.1-.03.04 0 .09-.02.14-.04.05-.03.1-.04.14-.08a1 1 0 00.15-.1c.04-.03.1-.06.14-.11l.26-.25.14-.12.12-.11.1-.07.09-.05.08-.04-.07.05a.32.32 0 00-.07.06l-.1.1-.1.12-.09.14-.23.31-.13.16-.14.13c-.05.05-.11.07-.16.1a.9.9 0 01-.14.1.73.73 0 01-.15.05l-.1.04-.08.02-.08-.36z"/>
<path d="M115.85 135.38l.05-.04.12-.1a11.47 11.47 0 01.74-.64l.15-.08.06-.03s-.03.01-.05.04l-.1.1c-.1.1-.2.25-.3.4l-.26.42-.1.15-.03.04-.28-.26z"/>
<path d="M109.17 135.81v-.02l.01-.03.02-.06c.02 0 .02-.02.03-.03l.02-.03c.01 0 .04-.03.05-.06l.12-.1c.18-.11.42-.18.66-.26l.35-.1c.1-.03.21-.05.29-.09.08-.03.14-.08.19-.12.02-.01.03-.03.05-.03v-.02.03s-.03.02-.04.05l-.17.15c-.07.06-.18.11-.27.16l-.33.15c-.21.11-.43.23-.54.34a.32.32 0 00-.06.07l-.01.03v.06l-.37-.09z"/>
<path d="M82.74 99.1l-.02-.08c-.01-.05-.04-.1-.05-.2l-.06-.3c-.01-.12-.03-.26-.03-.41-.02-.15 0-.31 0-.48s.04-.35.08-.53a5.57 5.57 0 01.37-1.12l.15-.26.15-.25a8.38 8.38 0 011.58-1.64l.22-.16-.17.2-.45.54c-.1.11-.2.23-.29.36l-.31.41c-.11.14-.2.3-.3.46l-.15.24-.12.25c-.08.17-.15.33-.21.51l-.17.52c-.05.17-.08.34-.1.5l-.08.45-.04.38v.6z"/>
<path d="M89.43 106.77l.1-.1c.08-.05.16-.14.28-.23.23-.2.5-.47.77-.76l.37-.43c.06-.07.11-.15.17-.2l.13-.19c.06-.12.09-.24.11-.32l.02-.14s.03.04.05.14c.01.05.03.1.03.17 0 .06 0 .14-.02.23s-.06.18-.1.25l-.12.25-.17.25a1.6 1.6 0 01-.2.24c-.08.07-.15.16-.23.22l-.24.19-.24.16-.23.12c-.15.07-.27.1-.35.13l-.13.02z"/>
<path d="M88.31 107.28l-.08-.03a.94.94 0 01-.42-.31.98.98 0 01-.2-.4c0-.02 0-.06-.02-.08l-.02-.17.01-.3c.01-.09.04-.15.05-.2.01-.05.03-.07.03-.07l.04.07.08.19.09.26c.01.05.02.1.05.15l.02.07.02.07c.06.18.15.36.22.5.04.08.07.14.08.19.04.03.05.06.05.06z"/>
<path d="M86.86 106.6h-.07a.27.27 0 01-.18-.1 1.06 1.06 0 01-.28-.44c-.06-.16-.1-.34-.1-.48 0-.07 0-.13.02-.16l.01-.08.06.05.12.13c.08.11.18.27.24.44l.07.25a6.85 6.85 0 00.09.35l.02.03z"/>
<path d="M85.62 106.16l-.06-.06c-.03-.04-.1-.1-.14-.17a1.1 1.1 0 01-.16-.26l-.12-.33c0-.06-.02-.12-.03-.16l-.01-.17v-.3c0-.08.04-.17.06-.22l.03-.08.04.07.08.2c.06.15.12.36.18.58.05.22.1.43.12.6.01.08.01.16.03.22l-.02.08z"/>
<path d="M84.28 104.82a.93.93 0 01-.2-.3l-.04-.16-.02-.17a1.14 1.14 0 01.07-.51l.07-.16v.08a.36.36 0 01.02-.25c.04-.07.09-.14.16-.17v.11l.01.09c.01.06.04.1.06.13l.01.01v.07l-.06.59c0 .1 0 .2-.02.3a.7.7 0 01-.02.16c-.03.06-.03.12-.04.18z"/>
<path d="M82.97 99.8l-.06.12-.14.31a8.05 8.05 0 00-.54 2l-.04.34a.6.6 0 01-.01.13l-.36-.03.02-.13.08-.35a8.13 8.13 0 01.78-1.98l.18-.3c.07-.06.1-.11.1-.11z"/>
<path d="M92.67 103.8l.01-.17.02-.43a12.4 12.4 0 00-.16-2.62l-.11-.59s.07.23.15.58a16.86 16.86 0 01.4 2.62l.04.44v.17h-.35z"/>
<path d="M90.23 114.13v-.1l-.01-.1-.02-.14-.1-.3-.13-.36a1.68 1.68 0 00-.15-.3l-.08-.1h-.04c.02 0 0 0 0 0l-.02-.02a.1.1 0 00-.06-.02.74.74 0 01-.24-.13c-.05-.05-.05-.1-.05-.1l.03.01.06.03c.06 0 .13 0 .24-.02h.13l.06.02a.7.7 0 01.2.12c.12.1.2.25.25.4l.04.1.02.1c.02.07.04.13.04.2.02.13.02.26 0 .38a.4.4 0 01-.05.15c-.01.05-.03.07-.06.1-.03.07-.06.08-.06.08z"/>
<path d="M87.04 122.88l-.02-.06-.06-.2c-.05-.16-.1-.4-.1-.7 0-.15 0-.32.02-.48.02-.17.04-.35.08-.53a9.87 9.87 0 01.28-1.12l.16-.55.16-.53c.04-.17.1-.33.13-.5l.1-.46.08-.68v-.27l.07.27a3.61 3.61 0 01.02 1.19c-.02.16-.04.34-.08.52s-.07.36-.13.56l-.16.56c-.06.18-.1.37-.17.55l-.14.53-.12.5c-.04.16-.06.32-.08.46a3.65 3.65 0 00-.03.88l-.01.06z"/>
<path d="M82.02 132.42h.06l.17.04c.07.02.16.04.24.08l.25.12a1.65 1.65 0 01.42.3l.15.2-.04.02-.03-.04-.12-.1-.2-.1-.24-.1-.24-.04-.21-.01H82l.01-.37z"/>
<path d="M79.29 132.06h.05c.03.02.07.02.13.03l.2.05.22.08c.14.06.27.16.36.24l.08.11c.03.03.03.05.03.05l-.04.01-.04-.03a.42.42 0 00-.1-.08.85.85 0 00-.36-.12h-.57l.04-.34z"/>
<path d="M82.4 134.61a.45.45 0 010-.18.7.7 0 01.02-.17 1.06 1.06 0 01.22-.46l.12-.14.13-.1.13-.09a2.2 2.2 0 01.6-.26c.06-.01.1-.03.17-.03h.17a.7.7 0 01.16.03c.06.01.11.02.17.05h-.01l.2.06a.6.6 0 01.2.08l.1.05.1.05.1.06.08.06.08.07.09.07c.05.05.1.1.14.17a.6.6 0 01.11.19c.02.06.06.13.06.2l-.04.02c-.08-.11-.16-.2-.26-.3l-.07-.05-.07-.06-.16-.11-.08-.05a.2.2 0 01-.09-.05l-.08-.03-.09-.04-.18-.06-.19-.05h-.01a.43.43 0 00-.12-.02l-.12-.01-.12.01-.12.02c-.17.05-.34.14-.48.23l-.12.09a.6.6 0 00-.1.08l-.08.08c-.02.04-.05.06-.06.1a.74.74 0 00-.08.23c-.02.03-.02.08-.02.12v.12l-.4.02z"/>
<path d="M84 133.3l.04-.07c.01-.02.02-.05.05-.07l.06-.08.31-.41.13-.23a.85.85 0 00.09-.22c0-.03 0-.06.02-.1l.01-.06V132l.01.06.02.07v.1c0 .07-.02.15-.04.25l-.08.27c-.08.18-.16.35-.2.48a.59.59 0 01-.04.09l-.03.06-.02.06-.33-.15z"/>
<path d="M84.11 135.62l-.36.08c-.05.02-.1.04-.17.05l-.18.06a.9.9 0 00-.18.09c-.06.02-.12.06-.18.1l-.16.11-.16.13-.28.24-.27.26-.04-.03s.05-.14.18-.33a2.15 2.15 0 01.42-.46c.06-.05.11-.1.2-.14a.9.9 0 01.21-.11c.07-.04.14-.05.22-.07.07-.03.14-.03.2-.04l.18-.01c.23.02.37.06.37.07z"/>
<path d="M81.9 134.88l-.06.06-.16.13-.11.08c-.04.04-.09.06-.12.1l-.13.1-.14.11-.13.11-.12.11a.4.4 0 01-.12.1l-.1.1-.15.16-.06.06-.04-.01.03-.09.1-.2c.04-.08.1-.17.17-.26l.27-.26.14-.1.16-.1c.1-.06.2-.1.29-.13.08-.04.15-.05.21-.06l.07-.01z"/>
<path d="M80.02 134.29l-.05.06-.14.13-.2.18-.21.22c-.14.14-.3.28-.4.4l-.2.2-.04-.02s.03-.12.1-.26c.04-.07.08-.16.16-.24a2.05 2.05 0 01.46-.44l.14-.08.12-.06a.99.99 0 01.19-.07c.03-.02.07-.02.07-.02z"/>
<path d="M79.94 93.4l-.08.04a.79.79 0 00-.19.14 1.5 1.5 0 00-.23.3c-.07.11-.14.26-.2.41-.07.17-.12.34-.18.54-.04.1-.06.2-.08.3l-.09.31a17.3 17.3 0 00-.23 1.01l-.06.35-.06.35c0 .12-.02.23-.04.35-.03.22-.05.45-.06.68-.02.1-.02.22-.03.32l-.01.32-.01.57.01.5.01.37.01.32-.08-.32a9.12 9.12 0 01-.22-1.46v-.66c0-.22 0-.46.03-.7l.03-.35.05-.36.07-.36c.03-.12.05-.24.09-.35.06-.23.12-.46.19-.67l.1-.31.13-.3a3.72 3.72 0 01.54-.96c.1-.12.2-.2.3-.26.1-.06.17-.08.23-.1l.06-.02z"/>
<path d="M83.57 131.55l.01-.1a4.1 4.1 0 00.06-.46l.04-.2.06-.44.06-.43.02-.2.03-.18a5.5 5.5 0 01.06-.39l.02.11c.01.06.04.16.05.28l.02.4v.22l-.03.23-.05.23-.06.21a2.28 2.28 0 01-.26.63.88.88 0 01-.03.1z"/>
<path d="M79.43 67.15c.12 0 .13.29.15.61 0 .32.02.55-.1.55s-.31-.23-.32-.55c-.03-.31.14-.61.27-.61z"/>
<path d="M71.8 70.9c.7 0 1.3.2 1.8.7a4 4 0 01-1.8-.7z"/>
<path d="M78.71 71.89l.03.02.04.06.09.09.1.08c.17.12.43.24.7.37l.2.11.2.12c.12.08.23.18.3.26l.18.22.06.1-.11-.04-.26-.1-.35-.16-.2-.1-.2-.1c-.13-.07-.27-.14-.4-.24a1.06 1.06 0 01-.35-.46c-.03-.05-.03-.1-.04-.14v-.08l.01-.01z"/>
<path d="M85.2 75.1c.9.1 1.4.6 1.8 1.4-.6-.5-1.2-.9-1.8-1.4z"/>
<path d="M81.7 67.8c.6-.1.9.3 1.2.6-.5 0-1-.3-1.2-.6z"/>
<path d="M81.3 69c-.2.3-.3.5-.5 1.2-.2-.8 0-1 .5-1.2z"/>
<path d="M80.94 67.78l.04.04a5.04 5.04 0 00.42.29l.34.2c.1.06.14.11.14.11l-.17-.06a8.95 8.95 0 01-.78-.22l-.13-.04-.05-.03.2-.29z"/>
<path d="M78.7 66.2c-.1.3.5.6.9.4.6-.2 1.3-.3 1.8.2-.4-.1-1-.2-1.5.1-.4.1-1.1.4-1.3-.2-.1-.2.2-.7.1-.5z"/>
<path d="M78.3 68c.3.9-.2 1.2-.7 1.4.3-.4.6-.8.7-1.4z"/>
<path d="M66.8 71.1c.2 0 .4-.2.5-.4.1-.2.1-.4.2-.5.2-.2.3-.2.6-.1-.2.1-.4-.1-.5.1-.1.1-.1.4-.1.6 0 .3-.2.5-.4.6-.2.1-.3-.1-.3-.3z"/>
<path d="M67.9 71.2c0-.3.2-.5.4-.5.2.3-.4.6-.4.5z"/>
<path d="M87.71 66.06l-.03.04-.1.15a1.8 1.8 0 01-.14.24c-.04.05-.06.1-.11.14l-.12.12a1.3 1.3 0 01-.55.28l-.2.03h-.07l.07-.02.18-.07c.15-.06.32-.2.45-.35l.08-.12.06-.12c.04-.08.06-.18.09-.25.02-.09.06-.15.08-.2l.05-.08.26.2z"/>
<path d="M89.7 68.9c.2-.4.4-.9.6-1.4.2.9.1 1.2-.6 1.4z"/>
<path d="M92.3 67.84l-.11.04-.1.04c-.03.02-.08.03-.13.07a.9.9 0 00-.28.24c-.1.1-.16.23-.24.37a2.8 2.8 0 00-.23.83l-.03.4-.02-.41V69a2.21 2.21 0 01.3-.94c.1-.13.2-.25.3-.34l.15-.1.13-.08.1-.04.16.34z"/>
<path d="M83.93 79.18l.07.02.17.03a4.7 4.7 0 001.35.1l-.24.07a5.08 5.08 0 01-1.12.14h-.26l.03-.36z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 25 KiB

119
charges/horsePassant.svg Normal file
View file

@ -0,0 +1,119 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="#d7374a" stroke="#000" viewBox="50 50 200 200">
<metadata source="http://wappenwiki.org/images/5/5a/Albrecht_II_of_Braunschweig-Grubenhagen.svg" license="https://creativecommons.org/licenses/by-nc-sa/3.0"/>
<g id="horsePassant" stroke-width="3" transform="translate(51 51) scale(0.12)">
<path d="M457.3 678c.6 3.2 2.5 9.9-2.2 15.3-6.2 7.4-37.8 28.9-55 18.7-4.8-2.7 10.4-18.2 10.5-36.9.5-7 23.2-3 23.2-3s23.1 3.3 23.5 5.9z"/>
<path d="M551.2 469.4c-3.9 17.9-23.1 26-23.7 33.7-2 12.7 4.6 10.6 11.1 19.5 10.3 13.2 18.7 12 18.9 21.3-.4 10.1-7.2 15.7-16.3 15.4-3.6 1.9-6.7 7.7-19.2 16.3-5.3 3-9.2 4.5-15.2 6.3-4.3 1.3-18.8 29.3-26.8 36.3-8.3 7.2-14 9.1-14.1 12-2.7 11.6 11.2 14 11.1 19.2-.4 2.7-.8 4.8-3.4 7-4.5 3.7-7.9-.8-13.3 2.3-3.5 2.2-1.2 4.1-3.4 7.5-2 3.7 6 3.8 6.2 10 .1 2.4-5 4.5-5 4.5s-30.4-8.7-47.8-5.5c.5-6.2 4.6-8.3 10.8-12.8 6.1-4.6 9.6-10.9 9.6-16.2 0-13 9.9-20.9 20.7-32.2 5.2-11.9 13.8-18.2 26.7-34.2 7.8-9.6 18.5-32.4 19.8-38.1 2.2-11.3-62.9-27.6-70.3-54-8.9-6.4-2.3-23.7-3.5-27.4-2.4-7.5-4.6-17.7 1.5-22.7s13.7-7.8 21.3-9.9c26.7-7.2 55.6-6.4 80.8-17.7 5.2-2.3 11-5.2 16.3-3.1 2.4 1 4.3 2.9 6 4.8a59.33 59.33 0 0113.6 45.9"/>
<path d="M167.4 142c-7.2-8.6-13.7-20.3-13.5-34.1 12.8 14.4 26.4 16 38.1 23.5"/>
<path d="M129.9 538.7c3.2.5 10.1 1.2 13.5 7.5 4.7 8.4 13.6 45.6-2.2 58.1-4.2 3.6-13.3-16.2-30.7-23-6.4-2.9 5.4-22.8 5.4-22.8s11.4-20.4 14-19.8z"/>
<path d="M186.2 380.9c-5.4 2.4-7.6 3.4-12.8 6.2-7.9 4.6-30.9 20.9-45.6 22.7-18.9 4-30.8-1.7-38.7 5.9-2.5 2.4-1.3 7.5-3 16.7-1 5.5-5.8 12.2-5.6 16.4.5 11.3 6.6 17.9 8.2 30.1.9 7.8-.3 18.9-2.7 26-2.4 7.1-3.2 19.6 6.6 33.5 4.3 6.8 6.2 11.6 8.3 18.9 2.1 7.3 3.9 21.9 9.5 24.6 3.2-17.5 22.2-42.7 22.2-42.7s-.2-5.5-2.5-6.3c-5.8-2-8.8 5.4-11.5 2.2-2.4-3.3-3.8-3.7-2.4-7.6 2.2-5.8 9-2.7 10.1-8.4.6-3.4.7-3.9-.7-6.2-3.2-4.1-13.3-1.6-13.7-11.1-.8-2.7 1.4-11.7.5-22.6-.6-12.6-4-19.6-2.9-24 5-4.9 4.7-9.7 7.2-11.2 8.2-5 31.1 2.4 50.5 7.1 11.1 2.7 31.6-1.4 44.8-4.5 11.1-2.6 7.7.6 18.8-2 2.8-.6 2.9-2.6 6.3-4.5s1.1-3.6 1.9-4.7c.8-1.1 13.7-2.7 20-9.9 5.9-2.1 18.9-13.9 20.2-22.2"/>
<path d="M640.3 688c.3 3.2 1.5 10.1-3.6 15-6.9 6.8-40.3 25.2-56.6 13.4-4.5-3.1 12.1-17.1 14-35.7 1.1-6.9 23.4-.8 23.4-.8s22.7 5.5 22.8 8.1z"/>
<path d="M659.1 317.1c17.1 0 30.9 9.8 30.9 9.8s16.6 4.1 23.8 9.9c16.9 13.4 26.8 30.4 26.8 55.4 0 47.8-24.5 59.9-24.5 79.6 0 12.6 9.3 16.3 9.3 31.9 0 24.7-22.5 35.3-22.5 47.4 0 14.9 10 14.5 10 32.1 0 8.3-9.1 14-13.3 15.5-2.2-2.1 5.2-4.9 5.2-14.8 0-14.9-21.5-15.3-21.5-33.1 0-17 10.6-21.6 10.6-33.1 0-16.9-24.3-24.9-24.3-55.2 0-33.1 16.3-35.7 16.3-65.4 0-18.2-7.7-40.6-27.2-46.7-19.3-5.3-35.3 2.4-35.3 2.4 10.8 15.2 22.5 41.1 18.1 75.5-2.5 19.5-13.9 43-13.9 59.3 0 7.6-1.1 21.2 10.6 26.3 11.7 5.1 25.6 2.8 29.7 8.7 5.3 8.6 2.8 17-4.9 21.9-1.9 3.6 3.4 11-1.4 25.4-2.4 5.6-6 10.6-9.6 15.8-2.6 3.7-.8 15-2.9 25.4-2.2 10.8 2.1 20.8 2 23.6-2.4 11.6 4.7 13.8 4.7 18.9-.3 2.7-.7 4.8-3.3 7.1-4.4 3.8-7.9-.6-13.2 2.6-3.5 2.2-.9 4.1-1.1 7.9-.2 3.8 8 9.7 7.6 15.8-.2 2.4-5.4 4-5.4 4s-29.4-11.6-47.1-10c1.1-6.1 5.2-8.3 11.8-12.3 6.5-4 8.4-6 8.5-10 .7-17 7.5-22.3 11.8-28.4 4.3-6.1-1.8-18.8 1.2-38 2.7-12.3-2.9-33.7-7.9-42.9-5.8-10.2-14.4-12.6-46.3-18.9-16-3.2-23-5.6-36.7-17.9-9.9-5-22.3-22.1-26.1-32.5-3.8-10.5-11.4-21.6-14.4-32.2-58.4-8-92.5 41.4-175.6 48.5-34.3 2.9-39-1.7-39-1.7s-14.6.6-32.7-4.4c-32.1-8.8-51.8-24.8-63.3-45.5-18.5-33.5-6.6-53.6-9.7-63.4 0 0-6.9-18.3.1-38.6 3.2-9.3 8.2-17.8 18.6-29.6 9.1-10.4 13.5-13.5 23-32.6 5.6-10.9 8.6-20.7 7.7-33.2-1-9.1-5.7-13.2-5.7-13.2s-10.4 6.5-18.4 8.7c-12.7 3.5-23.1 1-23.1 1s-7.3 1.3-23.9 8.6c-5.3 2.5-11 5.1-14.4 8.7-3.7 4.2-2.7 6.9-6.1 9.7-2.5 2.1-7.2 2.1-9.1 1.6-2.8-.7-4.6.5-4.6.5s-2.6 2.6-4.6 1.6c-1.8-.9-1.7-2.6-1.5-3.9.5-2 3.6-5.5 8.7-9.4 4.8-3.7 7.1-4.8 8.6-7.1s1.3-3.7.3-4.4c-.9-.7-2.2-.5-3.7-.1-8.4 3-13.5 14.3-20.8 16.6a9.1 9.1 0 01-9.7-2.8c-2-2.4-2.4-4.9-2.9-7.5-1-5.3 0-8.4-.2-13.6-.2-5.1-3.5-11.8-1-16.3 2.5-4.9 7.1-5.2 12.3-9.6 2-1.7 1.2-.5 10.4-9.5 9.2-9 16.4-15.5 24.5-23.4 7.9-7.7 4.4-14.8 8.5-20.3 4.4-6.2 10-6.7 14-16.9.2.1-3.4-2.9-8.8-3.3-6.9.1-6.6 6.7-15.5 6.8-5.7.1-8.7-8.5-13.2-13.5-3.4-3.8-8.2-4.4-7.5-4.8 12.7-5 15 7.5 21.4 7.4s1.4-5.8 7.3-10.2c5.9-4.4 9.7-.6 14.6-.6.7-1.5 13.2-16.2 20-10.8-2.3-3.5-7.7-16.8-6.1-28.2 8.2 12.3 31.3 23.7 31.3 23.7s3.6-7.6 12.2-7.6c8.5-.1 11.4 8.8 15.7 8.7.2.1 1.5-5.2 5.4-9.2 4-4 10.3.9 13.3-5.1s-6.8-10.9-6.3-11.4c.7-2 15.3 2 15.4 10.7.1 7.1-2.1 9.8-3 10.3h-.3c0 .1.1.1.3 0 2.5-.3 11-3.3 19 .3 8.4 3.7 10.8 12.8 16 12.8 7.8-.4 4.6-11 5.4-11.3.8-.2 5.1 3.4 5.1 8.3 0 5.3-4.2 12.2-11 12.3-7 .1-12.1-2.4-12.7-2.6.4 1 5.2 3.3 9 3.9 4.4.8 10.6 2.1 14.9 4.8 6.8 4.3 10 16.1 14.7 16.1 3.3 0 4.6-2.2 4.6-5.4-.2-5-5-6.1-4.6-7.5.3-1.5 14.8 3 14.9 14.1-.2 9.6-4.8 14-10.6 17.1 1.5.3 2.9.8 4.2 1.2 21.2 7.7 12.7 26.7 14.3 31.6.2.7 1.5 2.3 5.5 2.3 5.9-.1 2.5-9.1 3.3-10 .8-.9 6.8 2.7 6.9 8.7.1 10.1-9.7 12-10.5 12.1 0 1.6 4.4 8.8 9.9 8.8 1.5 0 4.2-3.2 8.4-3.3 4.2 0 6.8 4.9 6.4 5.7-.4.7-3.4-1-5.8-.3-3.3 1-3.3 5.8-8.7 8-5.4 2.2-11.3.7-11.3.7s5.7 4.5 7.1 10.1c1.5 6.1-.3 7.9 1.2 12.4 1.8 5.7 9 9.4 9.1 19.8.1 10.4-4.9 14.8-5.4 14.3s-1.1-10.7-10.7-16.6c1.5 8.9-.5 15.2-1.2 17.9-4.2 14.9 41.7 24.1 66.8 24.1 68.4 0 75.7-11.1 131.3-8.5 33.8 2 54.1 16 68.1 16 22.2-.7 21.7-10.1 47.4-10.1z"/>
<path d="M268.9 688c.3 3.2 1.5 10.1-3.6 15-6.9 6.8-40.3 25.2-56.6 13.4-4.5-3.1 12.1-17.1 14-35.7 1.1-6.9 23.4-.8 23.4-.8s22.7 5.5 22.8 8.1z"/>
<path d="M218.3 454c-3.8 23.7 13.7 30.2 12.2 59.3 0 3.1-7.1 23.3 6 40.1 4.7 8.9 9.4 14.4 10.6 16.8 1.2 2.4 5.5 9.5 3.6 21.7-3 19.2 7.8 31.9 3.5 38-4.3 6.1-11.1 11.4-11.8 28.4-.2 4-2 6-8.5 10s-10.7 6.2-11.8 12.3c17.7-1.5 47.1 10 47.1 10s5.3-1.6 5.4-4c.4-6.2-7.8-12.1-7.6-15.8.2-3.8-2.3-5.6 1.1-7.9 5.3-3.2 8.8 1.2 13.2-2.6 2.6-2.3 2.9-4.4 3.3-7.1 0-5.2-11.2-7.3-8.7-18.9.1-2.8-.3-12.8 2-23.6 2.2-10.4-1.8-26.4-1.8-30.7 7.1-6.1 4.4-11.8 5.5-16.6 1.7-7.6 3.9-8.8 4-15.3.1-5.5-1.2-11.1-5.6-17.7-12.9-21.3 6.4-61.5 6.4-61.5"/>
<path fill="none" d="M345.5 295.4c-2.5 8.4-11.5 17.8-23.8 16.4-5.7-1.4 3.2-5.5 6.6-11.2"/>
<path fill="none" d="M220.8 127.6c25.3 2.6 58.4 16.3 83.7 57.1"/>
<path fill="none" stroke-width="1.72" d="M218.9 233.7c3.1-2 4.5-5.5 7.1-13.4 1.6-5.4 2.1-15.2 1.6-20.1"/>
<path fill="#f6f6f6" stroke-width="2.5" d="M164.5 173.6c6.6 1.8 13.5 6.5 13.5 6.5s-6.8 6.5-12.1 6.1c-6.4-.9-8.2-3.6-8.2-3.6s.7-3.1 2.3-5.5c1.4-2.1 3.6-3.6 4.5-3.5z"/>
<g fill="#000" stroke="none">
<path d="M496.9 583.7c-1.1.4-1.9 1.1-2.7 1.8-.8.7-1.6 1.5-2.3 2.4a66.8 66.8 0 00-4.1 5.2l-4 5.4-4.1 5.3c-2.8 3.5-5.7 7-9 10.1-1.6 1.6-3.4 3.1-5.4 4.3-1 .6-2 1.2-3.1 1.6-1.1.4-2.3.6-3.4.5 2.2-.4 4-1.7 5.6-3.2 1.6-1.4 3.1-3.1 4.6-4.7 2.9-3.3 5.6-6.9 8.3-10.4 2.8-3.5 5.6-7 8.7-10.3 1.5-1.7 3.1-3.3 4.9-4.7.9-.7 1.8-1.4 2.8-2 .9-.7 2-1.2 3.2-1.3z"/>
<path d="M451.9 655.6c-.3 1.6-1.5 2.8-2.6 3.8s-2.4 1.8-3.7 2.5c-1.3.7-2.6 1.3-3.8 1.8-1.3.6-2.6 1-3.9 1.8.1-.8.6-1.5 1-2.1.5-.6 1-1.2 1.6-1.7 1.2-1 2.4-1.8 3.7-2.4 1.3-.7 2.5-1.3 3.8-1.8 1.3-.7 2.5-1.1 3.9-1.9z"/>
<path d="M532.4 546.9c-1-.9-1.7-2.1-2-3.4a9 9 0 010-4c.3-1.3.8-2.5 1.5-3.6s1.6-2 2.9-2.6c-.2 1.3-.5 2.5-.7 3.6l-.8 3.2c-.2 1-.4 2.1-.6 3.2-.2 1.1-.2 2.2-.3 3.6z"/>
<path d="M497.4 501.3c.1-1.1.4-1.9.7-2.8.4-.8.8-1.5 1.4-2.2.5-.7 1.2-1.3 1.9-1.8s1.5-1 2.6-1.3c-.1 1.1-.4 1.9-.7 2.8a10.7 10.7 0 01-3.3 4c-.7.6-1.5 1-2.6 1.3z"/>
<path d="M498 490.9c-.1-.9-.1-1.6 0-2.2.1-.6.1-1.2.3-1.7.1-.5.3-1.1.6-1.6.3-.6.6-1.1 1.1-1.9a4.08 4.08 0 011.3 4.2c-.2.7-.6 1.4-1.1 2-.6.6-1.3 1.1-2.2 1.2z"/>
<path d="M144.2 430c6.7-.1 13.4.3 20 .7 3.3.2 6.6.4 9.9.5 3.3.1 6.6.3 9.9.3h4.9c1.6 0 3.2-.2 4.8-.4 3.2-.4 6.4-1.2 9.6-2 3.2-.8 6.4-1.7 9.5-2.7 1.6-.5 3.2-1 4.7-1.5.8-.3 1.6-.5 2.2-.9.7-.4 1.3-.9 1.8-1.7-.3.8-.9 1.5-1.5 2-.7.6-1.5 1-2.2 1.3-1.5.8-3 1.5-4.5 2.2-3.1 1.3-6.2 2.6-9.4 3.6-3.2 1.1-6.5 1.9-9.8 2.5-1.7.3-3.4.5-5.2.5-1.7 0-3.4.1-5 0-6.7-.1-13.4-.6-20-1.4-6.5-.9-13.1-1.9-19.7-3z"/>
<path d="M708.8 370.6c2 3.6 3.6 7.4 4.8 11.4 1.2 3.9 2.1 8 2.5 12.2.4 4.1.4 8.4-.3 12.5s-2 8.2-4 12c-1.9 3.8-4.2 7.3-6.6 10.6-2.4 3.4-4.9 6.6-7.1 10-2.2 3.4-4.2 6.9-5.8 10.5-1.6 3.7-2.6 7.5-3.1 11.5-.2 1-.3 2-.3 3-.1 1-.1 2-.2 3-.1 2 .1 3.9.5 5.8.8 3.8 2.7 7.3 4.9 10.8 2.1 3.4 4.5 6.9 6.5 10.5 2 3.6 3.7 7.6 4.5 11.7.4 2.1.7 4.1.8 6.2.1 2.1.1 4.2-.3 6.3-.3 2.1-1 4.1-1.8 6-.8 1.9-1.9 3.7-3 5.5-2.2 3.5-4.9 6.6-6.6 10.3-.8 1.8-1.4 3.8-1.5 5.9-.1 2 .1 4.1.7 6.1-.6-1.9-1-4-1-6.1 0-2.1.5-4.1 1.3-6.1 1.6-3.9 4.1-7.2 6.2-10.7 2.1-3.5 3.8-7.2 4.2-11.2.3-2 .2-4 .1-6s-.5-4-1-5.9c-1-3.9-2.6-7.6-4.6-11.1-2-3.5-4.4-6.8-6.7-10.3-2.3-3.5-4.4-7.2-5.4-11.5-.5-2.1-.7-4.3-.6-6.4 0-1.1 0-2.1.1-3.2s.1-2.1.3-3.1a51.02 51.02 0 015.9-17.9c1-1.8 2.1-3.6 3.3-5.3 2.3-3.5 4.8-6.7 7.2-10a92 92 0 006.6-10.1c1.9-3.5 3.3-7.3 4.1-11.2.8-3.9 1-8 .8-12-.1-8.1-2.1-16.2-5.4-23.7z"/>
<path d="M712.5 491.7c-2.3-2.2-4.3-4.6-6.1-7.3-1.7-2.7-3.1-5.7-3.8-8.9-.7-3.2-.6-6.7.1-9.9s2-6.2 3.3-9.1c2.7-5.7 5.6-11.2 7.3-17.1.8-2.9 1.3-6 1.4-9.1.2-3.1-.1-6.2-.4-9.3 1 3 1.7 6.1 1.9 9.3.2 3.2 0 6.5-.6 9.6-.6 3.2-1.7 6.2-2.9 9.2-1.2 2.9-2.6 5.8-3.9 8.6-2.7 5.6-4.7 11.4-3.9 17.3.4 2.9 1.4 5.8 2.8 8.6s3.1 5.4 4.8 8.1z"/>
<path d="M685.4 361.9a50.67 50.67 0 0112.1 19c2.6 7.2 3.3 15.2 1.9 22.8-.8 3.8-1.9 7.5-3.4 11s-3.2 6.9-4.9 10.2c-1.7 3.3-3.3 6.6-4.8 10a77 77 0 00-3.4 10.6c.2-3.7.9-7.5 2-11.1 1.1-3.6 2.5-7.1 4.1-10.6 1.5-3.4 3.1-6.8 4.4-10.2 1.4-3.4 2.4-6.9 3.1-10.4.8-3.5.9-7.2.7-10.8-.2-1.8-.3-3.6-.6-5.4-.1-.9-.4-1.8-.6-2.7-.2-.9-.4-1.8-.7-2.6-1-3.5-2.4-6.9-4.1-10.2-1.6-3.3-3.6-6.5-5.8-9.6z"/>
<path d="M108.2 440.2c.7.8 1.1 1.7 1.3 2.7.2 1 .1 2-.2 3-.3 1-.8 1.9-1.6 2.6-.7.7-1.7 1.2-2.7 1.3l1.4-4.7c.2-.7.5-1.4.7-2.2.2-.4.2-.8.4-1.2.3-.6.4-1 .7-1.5z"/>
<path d="M201.4 401.7c-1.2-1.6-1.8-3.7-1.9-5.8-.1-2.1.3-4.2.9-6.1.6-1.9 1.5-3.7 2.5-5.3 1-1.7 2-3.3 3-5 .2 2-.3 4-.8 5.9-.6 1.9-1.2 3.7-1.8 5.4-.6 1.7-1.1 3.5-1.4 5.2-.4 1.9-.5 3.7-.5 5.7z"/>
<path d="M215.4 414.1c-.5-.6-.9-1.2-1.3-1.8-.4-.6-.8-1.2-1.1-1.8-.7-1.2-1.4-2.3-2.1-3.4l-2.1-3.3c-.8-1.1-1.5-2.2-2.5-3.3 1.6.1 3 .8 4.2 1.7 1.2.9 2.2 2.1 3 3.4.8 1.3 1.3 2.7 1.7 4.1.2.7.3 1.5.3 2.2.1.7.1 1.4-.1 2.2z"/>
<path d="M99.5 458.1c2.2 3.7 3.6 7.8 4.4 12 .3 1.1.4 2.1.5 3.2.2 1.1.3 2.1.4 3.2.1 1.1.2 2.1.2 3.2.1 1.1.1 2.1.1 3.2 0 4.3-.2 8.5-.6 12.7-.3 4.2-.8 8.4-.9 12.6-1.1-4.1-1.3-8.5-1.5-12.7-.1-4.2-.1-8.5-.1-12.6v-4.7l-.1-1.6c0-1-.1-2.1-.2-3.1s-.1-2.1-.2-3.1c-.3-4-.9-8.1-2-12.3z"/>
<path d="M107.1 543c1.3.9 2.1 2.4 2.7 3.8.5 1.4.8 2.9 1 4.3.2 1.4.3 2.8.3 4.2.1 1.4 0 2.7.3 4.3-.7-.4-1.2-1.1-1.6-1.7-.4-.7-.7-1.4-1-2.1-.5-1.4-.8-2.9-1-4.3-.2-1.4-.3-2.8-.4-4.2-.1-1.5-.1-2.8-.3-4.3z"/>
<path d="M267.6 569.2c-.8 1.3-2.1 2.3-3.5 3-1.4.7-3 1-4.6 1a8.74 8.74 0 01-7.6-4.6c.8.2 1.4.5 2.1.6.7.2 1.3.4 1.9.5 1.2.3 2.5.5 3.7.5 1.2 0 2.5 0 3.8-.2 1.3-.3 2.7-.5 4.2-.8z"/>
<path d="M653.5 586c-2.2 3.8-3.7 8.1-5 12.5-1.3 4.4-2.3 8.9-3.2 13.4-1 4.5-1.8 9-2.9 13.6-.5 2.3-1.1 4.5-1.8 6.7-.4 1.1-.7 2.2-1.2 3.3-.5 1.1-1 2.1-1.7 3 .7-.9 1.2-2 1.6-3.1.4-1.1.7-2.2 1-3.3.6-2.2 1-4.5 1.4-6.8.8-4.5 1.4-9.1 2.1-13.7.7-4.6 1.5-9.1 2.5-13.7 1.1-4.5 2.3-9.1 4.6-13.4l2.6 1.5z"/>
<path d="M630.8 665.6c-.5 1.5-1.7 2.7-2.9 3.6-1.2.9-2.5 1.6-3.9 2.1-1.3.6-2.7 1-4 1.4-1.3.4-2.6.7-4 1.4.2-.8.7-1.4 1.2-2 .5-.6 1.1-1.1 1.8-1.5 1.2-.9 2.6-1.5 3.9-2.1 1.3-.6 2.6-1 4-1.5 1.3-.3 2.5-.7 3.9-1.4z"/>
<path d="M640.6 526.6c1.1-.7 2.5-1 3.8-1 1.3.1 2.7.5 3.8 1.1 1.2.6 2.2 1.5 3 2.5.8 1 1.4 2.2 1.7 3.5-1.2-.6-2.2-1.1-3.2-1.7l-2.9-1.6c-.9-.5-1.9-1-2.9-1.4-1-.5-2-.8-3.3-1.4z"/>
<path d="M176.6 380.7c.7 4.2 2.1 8.3 3.7 12.4s3.4 8.1 5.3 12.1c1.8 4 3.7 8 5.4 12.1 1.6 4.1 3.1 8.3 3.6 12.7-.7-4.4-2.5-8.4-4.3-12.4-1.9-4-4-7.8-6-11.7-2.1-3.9-4.1-7.8-6-11.8-1.9-4-3.5-8.2-4.6-12.7l2.9-.7z"/>
<path d="M277.4 581c-2.3 4-3.5 8.8-4.4 13.6-.9 4.8-1.4 9.7-1.8 14.7-.5 4.9-.8 9.9-1.3 14.8-.3 2.5-.6 4.9-1 7.4-.2 1.2-.5 2.4-.9 3.6-.4 1.2-.8 2.4-1.6 3.3.8-1 1.1-2.2 1.5-3.4.3-1.2.5-2.4.7-3.6.3-2.4.5-4.9.6-7.4.3-4.9.4-9.9.6-14.8.2-5 .5-9.9 1.1-14.9.3-2.5.7-5 1.3-7.4.6-2.5 1.4-4.9 2.6-7.3l2.6 1.4z"/>
<path d="M259 663.9c-.1 1.6-1 3-1.9 4.2-1 1.2-2.1 2.2-3.2 3.1-1.1.9-2.3 1.7-3.5 2.4-1.2.8-2.4 1.4-3.6 2.4 0-.8.3-1.6.7-2.3.4-.7.8-1.3 1.3-1.9 1-1.2 2.1-2.1 3.2-3 1.1-.9 2.3-1.7 3.5-2.4 1.2-.8 2.3-1.5 3.5-2.5z"/>
<path d="M216.8 454a51 51 0 00-.7-10.3c-.6-3.4-1.7-6.7-3-9.9s-2.9-6.5-4-9.8c-1.2-3.4-1.9-6.9-2.2-10.4.5 3.5 1.5 6.9 2.9 10.1 1.4 3.2 3.1 6.3 4.7 9.5s3 6.5 3.8 10.1c.9 3.5 1.3 7.1 1.5 10.7h-3z"/>
<path d="M285.2 468.1c4.1-6.6 7.3-13.8 9.6-21.4 2.3-7.5 3.6-15.4 3.7-23.3.4 7.9-.5 15.9-2.3 23.7a87.6 87.6 0 01-8.5 22.5l-2.5-1.5z"/>
<path d="M245.2 533.1c0-1.6.8-3.1 1.9-4.2 1.1-1.1 2.6-1.9 4.1-2.3 1.5-.4 3-.5 4.5-.3s2.9.6 4.2 1.2c-1.4.6-2.8.8-4.2 1.1-1.3.3-2.6.5-3.8.8-1.2.3-2.3.7-3.5 1.3-1 .6-2.1 1.3-3.2 2.4z"/>
<path d="M260.4 364.7c.5-1 1.3-1.7 2.2-2.3a7.61 7.61 0 016.1-.7c1 .3 2 .8 2.7 1.7-1.1.3-2 .5-2.9.7-.9.1-1.7.3-2.6.4-.8.1-1.7.2-2.6.2-.9 0-1.8.1-2.9 0z"/>
<path d="M277.2 367.5c.8-.6 1.8-.8 2.9-.7 1 .1 2 .4 2.9.9 1.8 1 3.1 2.4 4.3 3.5 1.2 1.1 2.5 2.1 3.9 3.1 1.4.9 2.9 1.8 4.6 2.6-1.9.4-3.8.1-5.7-.5-1.8-.6-3.5-1.7-5-3-1.4-1.3-2.4-2.7-3.6-3.8-1.1-1-2.5-2-4.3-2.1z"/>
<path d="M282.9 416.4c1.4.7 2.6 1.7 3.6 2.8 1 1.1 1.9 2.4 2.7 3.7.7 1.3 1.3 2.8 1.7 4.2.4 1.5.6 3 .5 4.6-.9-1.3-1.6-2.6-2.3-3.8l-2.1-3.8-2.1-3.8c-.6-1.2-1.3-2.4-2-3.9z"/>
<path d="M285.2 435.8c.9 2.4 1.2 5 1 7.5-.2 2.6-1 5.1-1.9 7.4-.9 2.3-1.8 4.4-2.6 6.7s-1.3 4.6-2 7c-.6-2.5-.6-5-.3-7.6.3-2.5 1.2-5 2.1-7.3.9-2.3 1.8-4.4 2.4-6.7.6-2.2 1-4.5 1.3-7z"/>
<path d="M479.8 406.4c.8-.3 1.5-.3 2.2-.3.7.1 1.3.2 1.8.5.6.3 1.1.6 1.6 1.1.5.5.9 1 1.2 1.9-.8.3-1.5.3-2.2.3-.7-.1-1.3-.2-1.8-.5-.6-.3-1.1-.6-1.6-1.1-.5-.5-.9-1-1.2-1.9z"/>
<path d="M485.5 395.7c1.3 0 2.6.4 3.7 1s2.2 1.3 3.1 2.2c.9.9 1.6 1.9 2.2 3.1.6 1.1 1 2.4 1 3.7-1.1-.8-2-1.5-2.9-2.3-.9-.8-1.7-1.6-2.5-2.4-.8-.8-1.6-1.6-2.3-2.5-.8-.8-1.6-1.7-2.3-2.8z"/>
<path d="M493.9 447.9c-1.3-5.3-2.9-10.6-5.3-15.5a42.1 42.1 0 00-9.8-13.2c4.5 3.3 8.2 7.7 11.1 12.5 2.9 4.8 5.1 10.1 6.9 15.4l-2.9.8z"/>
<path d="M387.9 467.1c1.5-2.8 2.9-5.4 4.2-8.1a85.05 85.05 0 005.9-16.9c.7-2.9 1.2-5.9 1.8-9 .7 3.1.8 6.2.5 9.4-.3 3.1-1 6.3-2 9.2-1 3-2.4 5.8-4.2 8.5-1.7 2.6-3.7 5-6.2 6.9z"/>
<path d="M365.2 470c1.4-2 2.6-3.9 3.7-5.8 1.1-2 2-4 2.9-6 .9-2.1 1.7-4.2 2.6-6.3.9-2.1 1.8-4.3 3-6.4 0 2.4-.3 4.7-.7 7-.5 2.3-1.2 4.6-2.1 6.8-.9 2.2-2.2 4.3-3.7 6.2a16.5 16.5 0 01-5.7 4.5z"/>
<path d="M348.2 474.9c.7-2.2 1.6-4.2 2.4-6.2.8-2 1.6-4 2.3-6 .7-2 1.5-4 2.2-6.1.7-2.1 1.4-4.1 2.2-6.3.4 2.3.3 4.6.1 6.8-.3 2.3-.9 4.5-1.7 6.6-.8 2.1-1.8 4.2-3 6.1a27 27 0 01-4.5 5.1z"/>
<path d="M331.8 471.3c.4-1.5 1-2.8 1.6-4.1.6-1.3 1.2-2.5 1.9-3.7l2.1-3.6c.8-1.2 1.6-2.4 2.6-3.5a16.18 16.18 0 01-2.2 8.6c-.7 1.3-1.6 2.5-2.6 3.6-.9 1-2.1 2-3.4 2.7z"/>
<path d="M317.8 470.8c.3-1 .7-1.7 1.1-2.4a12.74 12.74 0 012.9-3.5c.6-.5 1.3-1 2.2-1.4.2 1 .1 1.9-.2 2.7-.3.8-.7 1.6-1.3 2.3-.6.7-1.2 1.2-2 1.6-.8.5-1.7.8-2.7.7z"/>
<path d="M701 381.9c-.6-8-3.1-15.7-7.2-22.4-2.1-3.3-4.5-6.4-7.4-9-2.8-2.7-6-4.9-9.4-6.7-6.9-3.5-14.7-5.2-22.6-5.5-7.9-.2-15.8.9-23.3 3.9 7-4.1 15.2-6 23.3-6.2 8.2-.2 16.5 1.4 23.9 5.2 3.7 1.9 7.1 4.4 10.1 7.3 2.9 2.9 5.5 6.3 7.4 9.9 4 7.1 5.8 15.4 5.2 23.5z"/>
<path d="M641.5 331.2c2.7-1.8 5.8-3.1 9.1-3.8 3.2-.8 6.6-1 9.9-.8 3.3.2 6.6.9 9.7 2 3.1 1.1 6.1 2.7 8.6 4.9-3.1-1-6.1-2-9.2-2.6-3.1-.6-6.2-1.1-9.3-1.3-3.1-.2-6.2-.1-9.3.1-3.2.3-6.3.8-9.5 1.5z"/>
<path d="M134.9 247.4c.8.2 1.5.6 2 1.3.5.7.8 1.5.8 2.4 0 .9-.3 1.7-.7 2.4-.4.7-1 1.2-1.8 1.5.3-1.6.5-2.8.5-3.9 0-.6 0-1.1-.2-1.7-.1-.6-.3-1.2-.6-2z"/>
<path d="M98 241.3c.2-1.2.7-2.3 1.4-3.4.7-1 1.6-2 2.6-2.7l1.3-1.1c.4-.3.7-.7.8-1 .1-.2.2-.4.2-.6 0-.2.1-.4.1-.7.1-.5.1-.9 0-1.3-.2-.9-.6-1.9-1.1-2.9-.5-.9-1.1-1.9-1.8-2.5-.1-.1-.2-.1-.2-.2l-.1-.1h-.6c-.4 0-.9.2-1.3.5-.9.6-1.7 1.5-2.4 2.4.2-1.2.7-2.3 1.6-3.3.4-.5 1-.9 1.7-1.2.4-.1.7-.2 1.2-.2.3 0 .5.1.7.2.2.1.4.2.5.3 1.3.8 2 1.8 2.7 2.9.7 1.1 1.2 2.2 1.5 3.6.1.4.1.7.1 1.1 0 .4-.1.7-.1 1.1 0 .3-.2.7-.3 1.1-.1.3-.3.7-.5 1-.4.7-1 1.1-1.5 1.5-.5.4-1.1.7-1.6.9-1 .6-1.9 1.1-2.7 1.9-.7.9-1.4 1.8-2.2 2.7z"/>
<path d="M101.9 228.2c.1.6-.2 1.1-.4 1.6s-.5.9-.7 1.3c-.5.8-1 1.5-1.4 2.2l-1.4 2.2c-.5.7-1 1.5-1.7 2.3-.3-1-.3-2.1-.1-3.1.2-1 .6-2 1.2-2.8.6-.9 1.3-1.6 2.1-2.2.4-.3.8-.5 1.2-.8.4-.2.8-.3 1.2-.7z"/>
<path d="M144.5 197.2c-1.1 2.5-2.7 4.8-4.4 6.8-1.7 2.1-3.6 4-5.6 5.9-1.9 1.9-4 3.6-5.9 5.4-2 1.8-3.9 3.5-5.9 5.4 1.1-2.5 2.8-4.7 4.5-6.8 1.8-2.1 3.7-4 5.6-5.8 1.9-1.8 3.9-3.6 5.9-5.4l5.8-5.5z"/>
<path d="M146.2 175.4c.6-1.3 1.2-2.5 1.7-3.7.5-1.2.9-2.4 1.6-3.7.3-.7.8-1.3 1.3-1.9.5-.6 1.1-1 1.8-1.4 1.3-.8 2.6-1.3 4.1-1.5-.9 1.1-1.9 2-2.8 3-.9 1-1.5 1.9-2.1 3-.6 1.1-1.2 2.4-2.1 3.6-1.1 1.1-2.2 2-3.5 2.6z"/>
<path d="M226.7 200.2c0-1.4-.1-2.9-.3-4.4-.2-1.5-.5-3-.8-4.5-.3-1.5-.7-2.9-1.1-4.4-.5-1.4-1-2.9-2-4 .6.5 1 1.1 1.4 1.8.4.7.7 1.4 1 2.1.6 1.4 1.1 2.9 1.6 4.3.5 1.5.9 2.9 1.2 4.4.3 1.5.6 3 .8 4.6l-1.8.1z"/>
<path d="M183.3 180.7c-.2.5-.7.8-1.3.9-.5.1-1.1.1-1.6.1s-1.1-.1-1.6-.2-1-.2-1.6-.4l1.1-2.2c.3.3.7.6 1.1.8.4.3.8.5 1.2.7.4.2.8.4 1.3.5.5.2 1 .2 1.4-.2z"/>
<path d="M169.2 238.9c1.2 1.1 2.6 1.9 4 2.4a17.42 17.42 0 004.4.7l-.5 3c-.9-.3-1.7-.6-2.5-1s-1.5-.8-2.2-1.3c-1.3-1.1-2.5-2.4-3.2-3.8z"/>
<path d="M132 244.4c-.9.2-1.6.2-2.4.2h-2.2c-.7 0-1.4 0-2.2-.1-.7 0-1.5-.1-2.4-.2a6.9 6.9 0 017.1-1.2c.7.3 1.5.7 2.1 1.3z"/>
<path d="M138 229.4c.3-.4.6-.7 1-.8.4-.1.7-.2 1.1-.2.4 0 .7.1 1.1.4.3.2.6.5.8 1-.4.3-.8.4-1.1.5-.3.1-.6.1-.9.1-.3 0-.6-.1-.9-.3-.4-.1-.7-.3-1.1-.7z"/>
<path d="M142.5 226.6c.2-.5.6-.7.9-.9.3-.1.7-.2 1-.1.3 0 .6.2.9.4.3.2.5.5.7 1-.4.3-.7.5-1 .6-.3.1-.6.1-.9.1-.3 0-.5-.1-.8-.3-.2-.3-.4-.5-.8-.8z"/>
<path d="M147.2 224.8c.2-.4.4-.6.7-.8.2-.1.5-.2.7-.1.2 0 .4.1.6.3.2.2.4.4.5.9-.3.4-.5.5-.8.7-.2.1-.4.1-.6.1-.2 0-.4-.1-.5-.3-.2-.2-.4-.4-.6-.8z"/>
<path d="M151.6 223.5c0-.5.3-.7.5-.9.2-.1.5-.2.7-.1.2 0 .4.1.5.3.1.2.3.5.3.9-.3.3-.5.5-.7.6-.2.1-.3.1-.5.1-.1 0-.2-.1-.3-.3-.1 0-.2-.2-.5-.6z"/>
<path d="M105.5 252.5c-.1-.5.2-.9.4-1.2.3-.3.5-.4.9-.5.3-.1.6-.1 1-.1.3.1.7.2 1.1.6-.2.5-.4.7-.7 1-.2.2-.5.4-.8.4-.3.1-.5.1-.8.1-.3-.1-.6-.2-1.1-.3z"/>
<path d="M108.9 248.8c-.1-.5.1-.8.3-1 .2-.2.4-.4.6-.4.2-.1.4-.1.7 0 .3.1.5.2.8.6-.1.5-.2.7-.4.9-.2.2-.3.3-.5.4-.2.1-.4.1-.6 0-.3-.1-.5-.2-.9-.5z"/>
<path d="M112.4 246.6c-.2-.4-.1-.8.1-1 .2-.2.3-.4.5-.4.2-.1.4 0 .6.1.2.1.4.3.7.7-.1.4-.2.7-.4.9-.1.2-.2.3-.4.3-.1 0-.3 0-.4-.1-.2-.2-.3-.4-.7-.5z"/>
<path d="M162.6 208.2c-.3-.4-.2-.8-.2-1 .1-.3.2-.5.3-.7.2-.2.4-.3.6-.3.3 0 .6 0 1 .2.1.5.1.8 0 1l-.3.6c-.1.1-.3.2-.6.3-.1-.1-.4-.1-.8-.1z"/>
<path d="M164.3 203.8c-.4-.3-.4-.7-.4-1 0-.3.2-.5.3-.6.2-.1.4-.2.6-.2.3 0 .5.1.9.3.1.4.1.7 0 .9 0 .2-.1.4-.2.4-.1.1-.2.1-.4.1-.2.1-.4 0-.8.1z"/>
<path d="M165.7 224.4c-.5.1-.8-.3-.9-.5-.2-.2-.2-.5-.2-.7 0-.2.1-.4.3-.6.2-.2.5-.3.9-.3.3.3.5.5.6.7.1.2.1.3.1.5 0 .1-.1.2-.2.4-.1.1-.3.1-.6.5z"/>
<path d="M161.9 212.7c-.3-.3-.4-.7-.4-1 0-.3.1-.5.2-.7.1-.2.3-.3.6-.4.3-.1.6-.1 1-.1.2.4.2.7.3 1 0 .3-.1.5-.2.6-.1.2-.3.3-.5.4-.3.1-.6.1-1 .2z"/>
<path d="M162 216.9c-.4-.3-.5-.6-.5-.9 0-.3 0-.5.1-.7.1-.2.3-.4.5-.5.2-.1.5-.2 1-.2.2.4.3.7.4.9 0 .3 0 .5-.1.6-.1.2-.2.3-.4.4-.3.2-.5.3-1 .4z"/>
<path d="M163.5 220.9c-.4-.3-.5-.5-.7-.8-.1-.2-.1-.5-.1-.7 0-.2.1-.4.3-.6.2-.2.4-.4.9-.5.4.3.5.5.7.8.1.2.1.5.1.7 0 .2-.1.4-.3.6-.2.2-.5.4-.9.5z"/>
<path d="M118.5 271.3c.7-.3 1.5-.7 2.1-1.1.7-.4 1.3-.9 1.9-1.5.6-.6 1.2-1.2 1.9-1.8.7-.6 1.4-1.1 2.3-1.4-.7.5-1.3 1.2-1.7 1.9-.4.7-.8 1.5-1.3 2.3-.5.8-1 1.5-1.6 2.2-.6.7-1.3 1.3-2 1.9l-1.6-2.5z"/>
<path d="M108.8 230.6c-.5-.8-.8-1.5-1.2-2.1l-1-1.8c-.3-.6-.6-1.2-1-1.7-.4-.6-.7-1.2-1.4-1.8.4-.3.9-.2 1.4-.2.5.1.9.3 1.3.5.8.5 1.4 1.2 1.8 2 1 1.5 1.1 3.5.1 5.1z"/>
<path d="M171.6 173.3c.6-.4 1.4-.4 2-.3.7.1 1.3.4 1.8.7.5.3 1 .7 1.4 1.2.4.5.8 1 .9 1.8-.7-.1-1.3-.3-1.9-.5-.6-.2-1.1-.5-1.5-.8-.5-.3-.9-.6-1.4-1-.4-.3-.7-.7-1.3-1.1z"/>
<path d="M176.5 157.8l-3.6.3c-1.2.1-2.3.1-3.4.1h-3.4c-1.2 0-2.4 0-3.6-.3 2.1-1.6 4.6-2.2 7.1-2.3 1.2 0 2.5.1 3.7.5 1 .4 2.2.9 3.2 1.7z"/>
<path d="M177.5 172.9l-2.3-.6c-.8-.1-1.5-.4-2.2-.4-1.5-.2-2.9-.2-4.2.2-1.3.4-2.5 1.1-3.9 1.9-.7.4-1.4.8-2.3 1.1-.9.3-1.9.3-2.9.2h.2c-.8-.1-1.5-.3-2.2-.7-.7-.4-1.2-1-1.6-1.6-.8-1.3-.8-3 0-4-.2 1.3.3 2.5 1.1 3.2.4.4.8.6 1.3.8.5.2 1 .2 1.5.2h.2c1.2.1 2.2-.5 3.6-1.3 1.3-.8 2.8-1.7 4.6-2 1.8-.4 3.6-.1 5.1.5 1.4.5 2.8 1.5 4 2.5z"/>
<path d="M166.3 174.3s-.6.9-.2 3.2c.4 2.3 2 5.8-.3 5.9-2.3.1-4.5-1.8-4.9-5.5-.2-1.2.3-2.3.3-2.3"/>
<path d="M169.7 188.5c-.7.6-1.5 1-2.3 1.2-.8.2-1.7.2-2.6.1a5.81 5.81 0 01-4.3-2.8c.9.2 1.6.3 2.4.5.7.1 1.4.3 2.2.4l2.2.3c.7.1 1.5.1 2.4.3z"/>
<path d="M152 247.1c-1.2 1-2.4 1.9-3.6 2.8l-3.6 2.7-7.3 5.4c.7-1.4 1.7-2.6 2.8-3.7 1.1-1.1 2.3-2.1 3.5-3.1 1.2-.9 2.5-1.8 3.9-2.5 1.3-.6 2.7-1.2 4.3-1.6z"/>
<path d="M244.5 162.4c9.2 5.2 17.6 11.7 24.9 19.4l2.7 3 1.3 1.5 1.2 1.6 2.5 3.1 2.3 3.3c2.9 4.4 5.6 9 7.9 13.9 2.2 4.8 4.1 9.8 5.6 14.9a103 103 0 013.3 15.6c.7 5.3 1.1 10.6 1.1 15.8-.1 5.3-.4 10.6-1.4 15.8.5-5.2.5-10.5.2-15.7-.3-5.2-.9-10.4-1.8-15.6-1.8-10.3-4.9-20.3-9.3-29.7-4.4-9.4-10.2-18.2-17-26-6.9-7.9-14.8-14.8-23.5-20.9z"/>
<path d="M203.9 151.8c.7.7 1.4 1.1 2.2 1.6.8.4 1.5.8 2.3 1.2l2.4 1.2c.8.4 1.6.9 2.4 1.5-1 .1-1.9 0-2.8-.2-.9-.2-1.8-.5-2.7-.9-.9-.4-1.7-1-2.4-1.7-.8-.7-1.4-1.6-1.4-2.7z"/>
<path d="M167.6 140.1c1.3-1.6 3-2.7 4.7-3.8 1.7-1 3.5-2 5.3-2.9 1.8-.9 3.7-1.7 5.5-2.5 1.9-.8 3.8-1.4 5.7-2l.8 2.9c-1.9.5-3.8 1.1-5.7 1.6-1.9.6-3.7 1.2-5.6 1.9a90 90 0 00-5.5 2.2c-1.6.8-3.4 1.6-5.2 2.6z"/>
<path d="M305.8 183.9c4.4 7.7 8.4 15.7 11.5 24.1 3.1 8.4 5.2 17 6.5 25.8 1.3 8.8 1.7 17.7 1.4 26.5-.3 8.8-1.2 17.6-2 26.4.5-8.8 1.3-17.6 1.3-26.4 0-8.8-.6-17.6-2.1-26.3-1.5-8.6-3.9-17.1-7.2-25.2-3.3-8.1-7.4-15.9-11.9-23.3l2.5-1.6z"/>
<path d="M234.7 231.1c1 .9 2 1.8 2.9 2.9.8 1.1 1.7 2.1 2.4 3.3 1.5 2.3 2.5 4.9 3.3 7.6.7 2.7 1 5.5.9 8.2-.1 2.7-.5 5.5-1.6 8 .1-2.7 0-5.3-.3-7.9a48.45 48.45 0 00-4-14.9c-.5-1.2-1.1-2.4-1.7-3.6-.5-1.3-1.3-2.4-1.9-3.6z"/>
<path d="M345.5 238.5c-.9-.2-1.6-.4-2.3-.6-.7-.3-1.5-.6-2.1-1-.7-.4-1.3-.9-1.8-1.4-.5-.6-.9-1.2-1.2-1.9a5.8 5.8 0 003.6 1.9c.7.1 1.3.2 2 .2s1.4 0 1.9-.1l-.1 2.9z"/>
<path d="M346 278.3c-1.2-.9-2.3-1.8-3.3-2.9-1-1-1.9-2.2-2.8-3.3-.8-1.2-1.6-2.4-2.2-3.7-.6-1.3-1.1-2.6-1.5-4 .6 1.3 1.3 2.5 2.1 3.6s1.7 2.2 2.7 3.1a23.3 23.3 0 006.5 4.6l-1.5 2.6z"/>
<path d="M323.8 172.8c-.5.2-.9.3-1.3.4-.4.1-.8.1-1.3.2-.8.1-1.6 0-2.4-.1-.8-.1-1.6-.3-2.3-.6-.7-.3-1.4-.6-2-1l2.2.3c.7 0 1.4-.1 2.1-.2.7-.1 1.3-.3 1.9-.6.3-.1.6-.3.9-.4.2-.2.6-.4.7-.5l1.5 2.5z"/>
<path d="M347 218.8c-.7.1-1.3.1-1.9.1-.6 0-1.2-.1-1.8-.2-1.2-.2-2.4-.6-3.4-1.1-1.1-.5-2-1.2-2.8-2.1-.8-.8-1.4-1.8-2-2.7.8.8 1.5 1.6 2.5 2.1.9.6 1.9 1 2.9 1.2 1 .2 2 .3 3 .2.5 0 1-.1 1.5-.2s1-.3 1.3-.4l.7 3.1z"/>
<path d="M258.3 110.3c.1-.1-.1 0-.1 0h-.3c-.2 0-.4.1-.6.1-.4.1-.8.3-1.3.6-.4.2-.8.5-1.2.8-.4.3-.8.7-1.1 1a10.76 10.76 0 012.4-4.3c.2-.2.4-.4.7-.6.1-.1.3-.2.4-.3.2-.1.3-.2.6-.3l.5 3z"/>
<path d="M264 128.5c1.1-.9 2.3-1.7 3.7-2.2 1.4-.5 2.9-.8 4.3-.9 1.5-.1 3 .1 4.5.4 1.5.3 2.9.7 4.4 1.4l-1.6 2.6c-1-.7-2.2-1.3-3.5-1.8-1.3-.5-2.6-.9-3.9-1-1.3-.2-2.7-.1-4.1.1-1.3.1-2.5.7-3.8 1.4z"/>
<path d="M232 118.8c-.2-.9-.3-1.9-.3-2.9s.1-2.1.5-3.1l2.6 1.6c-1.2.9-2.1 2.6-2.8 4.4z"/>
<path d="M169.5 131.5c-1.4-.9-3-1.4-4.6-1.8-1.6-.4-3.2-.5-4.7-.5l.4-3a19.58 19.58 0 018.9 5.3z"/>
<path d="M331.6 221.6c-1.2-1.6-2.1-3.4-2.9-5.3-.7-1.9-1.3-3.9-1.7-5.8-.9-3.9-1.3-7.9-2.4-11.6-1-3.7-2.9-7.2-5.6-10-2.7-2.8-6.1-4.9-9.7-6.7 1.9.6 3.8 1.4 5.6 2.3 1.8 1 3.5 2.1 5 3.5s2.8 3 3.9 4.8c1.1 1.8 1.8 3.7 2.4 5.7 1.1 4 1.5 8 2.1 11.9.6 3.7 1.4 7.6 3.3 11.2z"/>
<path d="M305.2 158.8c-.8.2-1.6.1-2.4-.2-.8-.3-1.5-.7-2.1-1.2-1.3-1-2.5-2.1-3.6-3.2-2.3-2.2-4.5-4.5-7-6.1a15 15 0 00-4-2c-1.4-.5-3-.8-4.5-1.1-3.1-.5-6.2-.8-9.4-1.1 3.2-.4 6.4-.6 9.6-.3 1.6.1 3.2.4 4.8.9 1.6.4 3.2 1.2 4.5 2.1 2.7 1.9 4.9 4.3 7 6.6 1.1 1.2 2.1 2.4 3.2 3.4 1 1.2 2.2 2.3 3.9 2.2z"/>
<path d="M264.5 121.3a35.93 35.93 0 00-9.1 3c-1.4.7-2.8 1.4-4.3 2.2-.7.4-1.5.8-2.2 1.1-.4.2-.8.3-1.2.5-.4.1-.9.3-1.3.1.2 0 .4-.1.6-.2.2-.1.3-.2.5-.3.3-.2.6-.5.9-.8.6-.5 1.3-1 1.9-1.5 1.3-1 2.8-1.9 4.3-2.6 1.5-.7 3.1-1.3 4.8-1.6 1.8-.3 3.5-.4 5.1.1z"/>
<path d="M244.8 112.6c.7 1.1 1 2.6.5 3.9-.4 1.4-1.4 2.5-2.3 3.4-.9.9-1.9 1.6-2.7 2.5-.8.8-1.4 1.8-1.8 3.1-.3-1.3 0-2.7.8-3.9.7-1.2 1.7-2 2.6-2.9.9-.8 1.7-1.6 2.2-2.6.5-1 .7-2.2.7-3.5z"/>
<path d="M346.3 263.9c-1.8-1.5-3.3-3.3-4.4-5.4-.6-1-1-2.1-1.4-3.2-.4-1.1-.7-2.2-1.1-3.2-.7-2.1-1.7-4-3-5.9-1.3-1.8-2.9-3.5-4.3-5.3 2 1.2 3.8 2.7 5.4 4.4.4.4.8.9 1.1 1.4.4.5.7 1 1 1.5.6 1 1.1 2.1 1.5 3.3.8 2.2 1.3 4.4 2.1 6.5.7 2 1.9 3.9 3.1 5.9z"/>
<path d="M162.9 136.9c-2.2-.3-4.4-.7-6.6-.8-1.1 0-2.2-.1-3.2 0s-2 .3-2.9.7c-1.8.8-2.8 2.6-3.9 4.6-.3.5-.6 1-1 1.4-.4.4-.9.8-1.5 1.1-1.1.5-2.4.5-3.4.2 1.1-.1 2.2-.3 3-.9.8-.6 1.3-1.5 1.8-2.5.4-1 .9-2 1.6-3 .7-1 1.7-1.9 2.8-2.4 2.3-1 4.8-.9 7-.5s4.3 1.2 6.3 2.1z"/>
<path d="M175.8 93c.7 2.5 1.8 4.8 3.3 6.8 1.5 2 3.3 3.7 5.2 5.4 2 1.6 4 3.1 6.1 4.7 2 1.6 4 3.3 6 5.1 1.9 1.8 3.7 3.8 5.2 5.9 1.5 2.2 2.9 4.4 4 6.8 2.2 4.8 3.4 9.9 3.9 15.1-1.5-4.9-3.2-9.8-5.6-14.2a45.8 45.8 0 00-9.2-11.8c-3.6-3.5-7.8-6.5-11.6-10.1a26.7 26.7 0 01-5-6.1c-1.4-2.4-2.2-5-2.3-7.6z"/>
<path d="M203.2 139.9c-1.5-.6-2.8-1.7-3.9-2.9s-2-2.6-2.7-4c-.7-1.5-1.2-3.1-1.3-4.7-.2-1.6-.1-3.3.4-4.8.6 1.5 1 3 1.5 4.4.5 1.4 1.1 2.7 1.7 4.1.6 1.3 1.3 2.6 2 3.9.7 1.3 1.5 2.6 2.3 4z"/>
<path d="M201.1 141.9c-2.5-1.3-4.6-3-6.6-4.9-2-1.9-3.9-3.8-5.8-5.9-1.8-2-3.5-4.2-5.2-6.4-.4-.6-.8-1.1-1.2-1.7l-1.1-1.7c-.8-1.2-1.4-2.4-2.1-3.6l2.6-1.4c1.3 2.3 2.7 4.6 4.2 6.7a69.76 69.76 0 004.8 6.5c1.7 2.1 3.4 4.1 5.2 6.1 1.8 2 3.6 3.9 5.3 6.1l-.1.2z"/>
<path d="M206.5 111c2.5 1.4 4.8 3 6.9 5 2.1 1.9 4 4.1 5.6 6.4 1.6 2.3 3 4.8 4.1 7.3 1.1 2.5 2 5.2 2.3 8l-.3.1c-1.5-2.4-2.7-4.8-4-7.2-1.3-2.4-2.7-4.6-4.4-6.7-1.6-2.1-3.4-4-5.4-5.7-2-1.7-4.1-3.2-6.4-4.6l1.6-2.6z"/>
<path d="M231.7 263.3c.4 7-.8 14.1-3.5 20.6-1.3 3.3-3.1 6.4-4.9 9.4-1.9 3-3.9 5.8-5.9 8.7-4.1 5.6-8.3 11.1-11.6 17.1-3.3 6-5.7 12.5-6.9 19.4.2-7 2-14 5.1-20.3 1.5-3.2 3.4-6.2 5.3-9.1 1.9-2.9 4-5.7 6.1-8.6 4.1-5.6 8.1-11.2 11.1-17.4 2.8-6.1 4.6-12.8 5.2-19.8z"/>
<path d="M336.8 290.7c-.5-1.7-1.2-3.3-1.9-4.8-.8-1.5-1.6-3.1-2.3-4.7a19.1 19.1 0 01-1.3-10.5l1.2 5.1c.5 1.6 1 3.2 1.7 4.8.6 1.6 1.4 3.2 1.9 4.9.5 1.6.9 3.4.7 5.2z"/>
<path d="M594.5 504.8c3.9.1 7.9 1 11.4 2.9.4.3.9.5 1.3.7l1.2.9c.8.6 1.6 1.3 2.3 1.9 1.5 1.4 2.8 2.9 4 4.4 2.4 3.1 4.5 6.3 6.8 9.3 2.3 3 4.9 5.7 7.9 8.2-3.6-1.5-6.9-3.9-9.6-6.7-2.8-2.8-5.1-6-7.4-9-2.3-3-4.8-5.7-7.8-7.8-2.9-2-6.4-3.5-10.1-4.8z"/>
<path d="M629.4 392.3c.6 1.1.7 2.4.6 3.7-.1 1.3-.5 2.5-1 3.7-1 2.3-2.2 4.3-3.6 6.3s-2.9 3.8-4.6 5.6a31.2 31.2 0 01-5.6 4.6c1.2-2.1 2.5-4.1 3.8-6.1 1.3-1.9 2.6-3.9 3.9-5.8 1.3-1.9 2.7-3.8 3.9-5.7 1.5-2 2.5-3.9 2.6-6.3z"/>
<path d="M625.6 418.4c1 .8 1.3 2.1 1.3 3.4-.1 1.3-.5 2.5-1.3 3.5a8.5 8.5 0 01-6 3.3c.5-1.1 1.2-2 1.8-2.8.6-.8 1.2-1.5 1.7-2.2.5-.7 1-1.4 1.4-2.2.5-1 .9-1.8 1.1-3z"/>
<path d="M622.7 436.1c.7.4 1.1 1 1.3 1.5.2.6.3 1.2.3 1.8-.1.6-.3 1.2-.6 1.7-.4.5-.9 1-1.6 1.3-.4-.7-.6-1.3-.7-1.8-.1-.5-.1-1-.1-1.5s.2-.9.4-1.4c.2-.4.5-.9 1-1.6z"/>
<path d="M327 299.8c1.1-1.3 1.8-3.1 2.3-4.9.5-1.8.7-3.8.6-5.8.7 1.9.9 3.9.9 6 0 2-.3 4.2-1.2 6.3l-2.6-1.6z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 26 KiB

View file

@ -0,0 +1,119 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="#d7374a" stroke="#000" viewBox="50 50 200 200">
<metadata source="http://wappenwiki.org/images/2/26/Brixen.svg" license="https://creativecommons.org/licenses/by-nc-sa/3.0"/>
<g id="lambPassantReguardant" stroke-width="3" transform="matrix(.135 0 0 .135 73 46)">
<path d="M3.5 539s17.7 4.4 21.7 8.7c8.3 9.8 7.9 27.9 4.2 36.3-1.1 2.6-6.8.6-13.2-5.7 0 0 3 8.1.1 13.4-6.6-5.7-14.5-21.1-27.4-30-2.6-3.6-3.9-7.5-2.8-12.5s-4.5-5.5 3.7-7.1c6.1-1 13.7-3.1 13.7-3.1z"/>
<path d="M57.5 421.6c-10.1 9.4-30.8 14.9-41.2 15.2-18.2.6-43.3.4-49.2 6.8-1.8 1.9-3 10.9-8.1 14.6-1.6 3.8 3.6 13 6.1 24.3 2.6 9.7 5.7 26.1 7.3 28.1 3.6 7.8 11.3 2.1 15.4 4.4 2 1.5 2.1 1.9 2.8 5 1.1 5.2-5.7 5-5.5 10.6.2 3.8 2.1 3.5 5.1 5.3 3.2 1.6 3.1-5.3 8.4-5.6 5.1-.3 5.4 7.4 5.4 7.4s-15 7.4-14.3 24.4c-9.9-2.2-13.7-12.4-25-17.1-11.3-4.7-12.4-15.7-12.9-22.5-.5-6.8-5.9-29.6-8-36.5-3.4-10.7-12.2-33.4-13-43.6-.3-3.8 3.8-10 4.6-15.1 1.3-8.4 0-13 2.3-15.3 7-7.1 21-7.4 36.6-15.5 12.5-5.1 41-25.5 45.9-32.1"/>
<path d="M96 650.6s0 18.2-3.3 23.1c-7.5 10.4-25.2 14.4-34.3 12.8-2.8-.5-2.2-6.4 2.3-14.2 0 0-7.2 4.9-13 3.3 3.9-7.8 16.9-19.2 22.5-33.8 2.9-3.4 6.4-5.6 11.5-5.7 5.1-.1 4.3-5.6 7.7 1.9 2.8 5.7 6.6 12.6 6.6 12.6z"/>
<path d="M445.1 650.6s0 18.2-3.3 23.1c-7.5 10.4-25.2 14.4-34.3 12.8-2.8-.5-2.2-6.4 2.3-14.2 0 0-7.2 4.9-13 3.3 3.9-7.8 16.9-19.2 22.5-33.8 2.9-3.4 6.4-5.6 11.5-5.7 5.1-.1 4.3-5.6 7.7 1.9 2.8 5.7 6.6 12.6 6.6 12.6z"/>
<path d="M295.1 650.6s0 18.2-3.3 23.1c-7.5 10.4-25.2 14.4-34.3 12.8-2.8-.5-2.2-6.4 2.3-14.2 0 0-7.2 4.9-13 3.3 3.9-7.8 16.9-19.2 22.5-33.8 2.9-3.4 6.4-5.6 11.5-5.7 5.1-.1 4.3-5.6 7.7 1.9 2.8 5.7 6.6 12.6 6.6 12.6z"/>
<path d="M384 474.7c-4.9 11.4-10.4 15-14.7 30.3-.5 1.8-1.5 3.5-1.6 5.4-.1 2.1.6 4.1 1 6.1.8 4.3 2.2 10.3-.9 13.5-7.7 7.8-15.2 10.9-22.4 19.3-11.9 13.9-25.6 32.7-29.6 50.6-3.3 14.8 4.5 21.5 2.6 26.3-1.3 2.4-2.5 4.3-5.7 5.4-5.5 1.9-7.2-3.6-13.4-2.6-4.1.8-7.1 4.5-7.2 6.4 0 4.1 6.1 3.1 6.8 8.9.3 2.3-4.3 4.8-4.3 4.8s-11.8-11.8-27.6-5.7c-1.1-10 11.8-28.6 19.5-38.1 10.5-13.1 22-38.9 24.6-44.1 7.3-14.7 14.7-29.5 18.7-45.4 4.2-16.8-3.3-24.7-9.1-51.1 5.9-1.7 9.4-2.5 14.8-5.5 5.3-3 11.5-5.3 17.5-4 3.8.8 7.1 3 10.2 5.1 6.7 4.5 14.1 9.9 20.8 14.4z"/>
<path d="M475.5 401.6c.1-1.3-2.9-3-5.2-7.9-1.9-3.9-4.7-20.6-22-35.3-23.7-20.1-27.3-28.1-43.9-44.4-16.8-13.6-21.8-18.1-45.6-25-9.9-2.9-20.9-4.4-30.9-5-12.2-.7-38.2.1-50.6 1.7-10.3 1.3-44.6 3.6-55.1 3.6-61.5 0-74.7-21.9-92.7-25.2-5-6.4-4.4-15.9-4.4-15.9s10.2 3 23.2-2.4c5.9-2.5 13.7-2.9 21-1.1 2.4.6 4.2 1.2 6.7 2.5 5.9 3.1 10 2.9 15.8 1.7 4.3-.9 7.2-7.6 7.2-7.6 3.3-.9 6.1-1.7 8.6-4.9 1.6-2.1 3.4-6.4 3.2-9.9 0-.7-1.1-3.3-1-4 0-.4.9-2 .8-4.2-.3-4.1-1.5-8.8-5.3-15.8-2.6-4.7-13.3-17.4-16.8-22.6-3.6-5.3-7.3-8.8-10.3-11.8-1.1-1.1-9.5-9.3-10.3-10-1.7-1.3-2.6-3.2-3-5.3-.8-4.9-6-10.2-10.8-13.2-2.2-1.4-2.5-2-2.6-2.7-.4-3.1-5.5-8-9.6-9-6.2-1.4-10.2-6.2-16.9-6.5-6.9-.2-9.9-1.3-13.6-1.9-3.7-.6-7.9.2-13.4-.8-15.2-2.8-29.1 4.4-36.5 9.2s-23 11.5-31.4 29.8c-3.3 7.2-5.5 14.7-8.9 21.8-3.2 6.9-3.4 14.1-5.6 21.4-1.9 6.1-6.2 11.7-2.3 16.5 0 0-1 8.6-5.5 15.6-3.6 5.6-1.1 12 3.2 15.1 0 0-1.8 6.8-8 13.2-4.7 4.9-4.2 12.6.2 16.4-3.5 10.6-24.2 21-13.6 38.2-14.7 10.8-6.4 30-8 38.2-10.1 20.8 11.4 40 11.4 40-8.8 19.5 17.8 34.5 17.8 34.5s1.6 15.2 24.1 14.4c4.9 15.3 20.2 19.2 26.1 20.4 1.2 9.3 3.2 16.6 13.6 37.7.7 1.4 2.2 2.6 2.2 4 0 6.7.4 13.7 1.6 20.3 1.1 5.9 1.9 7.9 2.8 13.9.7 4.6 3.6 7.8 2.9 12.7-1.5 10.2-.9 20.6-1.8 30.9-.9 10.4-3 20.8-4.3 31.1-1.5 12.1-9.6 19.5-9 29.5 16.1-5.3 27.3 7.2 27.3 7.2s4.7-2.3 4.6-4.6c-.4-5.9-6.6-5.1-6.4-9.2.2-1.9-1-3.6 2.7-5.6 5.6-2.8 8.8 2 13.6-1.4 2.8-2.1 3.3-4.2 3.9-6.9.4-5.2-12.1-6-9.6-17.8.7-4.1 3.7-17.8 4-28.5.3-10.8-1.6-26 1-29.8 3.7-5.2 5-10.2 7.4-15.9 2.4-8.9 2.9-12.7.1-21.7-.7-2.2-1-1.5-1-3.5s-2.1-9.4-1.8-11.7c.9-8 8.2-6 11.3-16.3l.2.4c2 .9 13.6 3.4 15.8 3.2 9.9-1.2 20.1-2.1 26.5-1.5 9.6.8 20.2-1.1 29.6.5 11.4 1.9 20.7-.9 32-2.3 4.1-.5 8.3-.9 12.3-2 3.6-1 7.3-1.1 11-1.8 4.9-.9 18.4.2 23.2 1.3 10 2.3 17.6-.4 27.9-.3 7.3.1 14.4-1.8 21.4-3.8 9-2.5 16.5-3.5 24-8.1 6.1 8.1 11.4 21.8 28 29.5l-.1.2c.5 3.9 3.2 7.2 6.4 9.5 3.1 2.4 6.7 4 9.9 6.3 9.1 6.6 11.5 12.3 16 21.8 2.1 4.6 5.3 8.7 7.1 13.4 2.7 7 9.2 25.9 9.6 43.8 0 8.5-1.4 11.6-2.3 23.8-.9 12.2-8.5 21.5-7.4 31.6 15.8-6.1 27.6 5.7 27.6 5.7s4.6-2.5 4.3-4.8c-.8-5.8-6.9-4.8-6.8-8.9.1-1.9-1.1-3.5 2.4-5.7 5.5-3.1 8.9 1.5 13.5-2.2 2.7-2.2 3.1-4.4 3.5-7.1.2-5.2-9.5-8.8-11.5-23.8-1.9-14.3-.7-34.6-2.6-48.9-1.9-14.6-3.8-19.3-2.3-34 .9-9.1 5-19 .3-26.8-3.6-5.9-15.6-9.5-17.7-16.1-.8-2.6-.7-5.4-.6-8.1.7-20 4.7-17.1 4.7-37.1 0-12.9-3.2-25.8-3.2-25.8s3.4 8.9 5.9 12.2c6 8 14.1 9.6 14.1 9.6s5.1 15.3 23 18.8c.2-2.5-4.1-7.5-4.9-12.9-.7-4.9 1.2-12.3.7-16.6-1.1-8.3-4.7-11.5-4.4-12.1 3.8 2.8 8.9 5.2 12.3 2.9z"/>
<path fill="none" d="M61 463.4c-1.1-6.5-2.4-13.4-4.4-22.5-4.4-12.5 1.8-23.5 1.8-23.5"/>
<path fill="none" d="M316.5 419.6c1 8.1 3.1 17.4 10.2 21.4 0 6.1 5.2 11.4 11.2 12.2 3 5.1 8.8 5.1 11.6 10.3"/>
<path d="M65.2 183.8c-2.9 1.6-10.4 4.8-19.6 4.9-8-.1-18.6-.1-28-3.3-10.4 1.8-19.4-4.1-19.5-7.7.7-4.9 12-8.3 15.8-10 15-7 19.8-12.1 28.1-15.4 10.8-4.3 24.8-5.1 31.3-3.7"/>
<path fill="#f6f6f6" stroke-width="2.5" d="M150.4 165.1c-2.6-.4-5.4-.2-7.3 1.7-.5.5-1.8 3.2-.1 7.4.7 1.7 1.8 3.1 3.4 4 2.1 1.2 6.2 1.8 8.7 1.1 2.6-.8 4.3-1.9 4.3-4.3.1-4.1-7-9.6-9-9.9z"/>
<g fill="#000" stroke="none">
<path d="m -8.3,426 c 3.6,-1 10.85,-2 14.55,-2 l 0.1,2 c -3.96,0 -11.46,0 -14.65,0 z"/>
<path d="M-38.4 434.8l-.3 2.8c-.1.9-.1 1.8-.1 2.7 0 1.8-.3 4-1.1 5.8-.4.9-.8 1.8-1.4 2.7-.6.9-1.3 1.7-2.2 2.3-1.7 1.3-3.8 2-5.9 1.6v-.5c1.7-.6 3.2-1.6 4.2-2.8.5-.6 1-1.3 1.4-2 .4-.7.7-1.5 1-2.4.6-1.6 1-3.2 1.5-5.1.5-1.8 1.4-3.7 2.9-5.1z"/>
<path d="M-48.7 463.4c1.1 4.6 2.2 9 3.4 13.5l1.7 6.7c.6 2.2 1.1 4.5 1.7 6.7.6 2.2 1.1 4.5 1.7 6.7l1.8 6.7c1.2 4.5 2.5 8.9 4.2 13.3-2.8-3.8-4.7-8.2-6.4-12.5l-1.2-3.3c-.4-1.1-.7-2.2-1.1-3.3-.7-2.2-1.3-4.5-1.9-6.7-1.1-4.5-2.1-9.1-2.8-13.7-.7-4.7-1.2-9.4-1.1-14.1z"/>
<path d="M-25.2 541.4a8 8 0 014.3.5c1.4.5 2.6 1.4 3.7 2.2 1.1.9 2.1 1.9 3 2.9.9 1 1.7 2.1 2.6 3.1l-.2.3c-1.4-.5-2.5-1.4-3.6-2.2-1.1-.9-2.1-1.8-3.1-2.6-1-.9-2-1.7-3.1-2.4-1.1-.6-2.2-1.2-3.6-1.8z"/>
<path d="M14.9 579.3c-2.3-3.6-5-7.1-7.8-10.5-2.8-3.4-5.7-6.7-8.7-9.9l.2-.2c3.3 2.9 6.5 5.9 9.7 9 3.1 3.1 6.2 6.3 9 9.8l-2.4 1.8z"/>
<path d="M59.7 671.4c2.9-3.1 5.7-6.6 8.3-10.1 2.6-3.5 5.1-7.1 7.6-10.8l.3.2c-2 3.9-4.2 7.8-6.5 11.6s-4.6 7.5-7.4 11.1l-2.3-2z"/>
<path d="M408.8 671.4c2.9-3.1 5.7-6.6 8.3-10.1 2.6-3.5 5.1-7.1 7.6-10.8l.3.2c-2 3.9-4.2 7.8-6.5 11.6s-4.6 7.5-7.4 11.1l-2.3-2z"/>
<path d="M258.8 671.4c3-3.1 5.7-6.6 8.3-10.1 2.6-3.5 5.2-7.1 7.6-10.8-2 3.9-4.1 7.8-6.4 11.6-2.3 3.8-4.6 7.6-7.3 11.2l-2.2-1.9z"/>
<path d="M145.4 426.3c.6 4.6.3 9.3-.6 13.9-.9 4.6-2.5 9-4.4 13.3-1.9 4.3-4.2 8.3-6.5 12.3s-4.7 7.9-6.4 12l-2.8-1.1c2-4.4 4.5-8.3 6.9-12.2 2.5-3.9 4.8-7.8 6.9-11.9a62.04 62.04 0 006.9-26.3z"/>
<path d="M111.2 547.6c-2.1 3.6-3.6 7.7-4.7 11.9-1.2 4.2-2 8.5-2.8 12.8-.8 4.3-1.5 8.6-2.4 13-.4 2.2-.9 4.3-1.6 6.4-.7 2.1-1.4 4.3-2.8 6l-.2-.2c1.3-1.7 1.9-3.9 2.4-6s.9-4.3 1.2-6.4c.7-4.3 1.1-8.7 1.7-13.1.6-4.4 1.2-8.7 2.2-13.1 1-4.3 2.2-8.7 4.4-12.8l2.6 1.5z"/>
<path d="M102.7 500.7c1.1 2.5 2.3 4.9 3.6 7.3 1.3 2.4 2.6 4.9 3.5 7.6.9 2.7 1.4 5.6 1.2 8.5-.2 2.9-.9 5.8-2.7 8.1l-.4-.2c.7-2.6.8-5.2.6-7.8-.2-2.6-.8-5.1-1.6-7.6s-1.8-4.9-2.7-7.6c-.9-2.6-1.6-5.4-1.6-8.2l.1-.1z"/>
<path d="M443.7 401.6c2 2.9 2.9 6.5 3.7 9.9.4 1.7.7 3.4 1.1 5.1.4 1.7.9 3.3 1.6 4.6l-2.8 1.2c-.7-1.9-.9-3.7-1.1-5.4-.2-1.8-.3-3.5-.5-5.2-.3-3.4-.8-6.9-2.4-10l.4-.2z"/>
<path d="M462.3 400.2c-1.5-1.4-2.8-2.9-3.9-4.5s-2.1-3.3-2.8-5l.3-.1c1.1 1.5 2.4 2.9 3.8 4.1 1.4 1.2 2.9 2.3 4.4 3.2l-1.8 2.3z"/>
<path d="M452 401.5c1.8 2.4 3.6 4.9 4.9 7.7 1.4 2.7 2.4 5.7 3 8.6.6 3 .9 6 1.8 8.7.9 2.7 2.6 5.2 4.3 7.6l-.2.2c-2.3-2-4.4-4.3-5.6-7.2-.7-1.4-1-3-1.4-4.5-.3-1.5-.5-3-.9-4.4-.6-2.9-1.4-5.7-2.5-8.4-.9-2.8-2.3-5.4-3.4-8.3z"/>
<path d="M427.3 400.1c-.7-4.6-1.6-9.2-2.7-13.8-1.1-4.6-2.3-9.1-3.7-13.6-2.8-9-6.2-17.8-9.7-26.7 2.4 4.1 4.5 8.4 6.4 12.7 1.9 4.4 3.6 8.8 5.3 13.3 1.6 4.5 3 9 4.3 13.6 1.3 4.6 2.2 9.3 3.1 14l-3 .5z"/>
<path d="M351.5 329.8c3.6.8 7.1 1.9 10.4 3.5 1.7.7 3.3 1.7 4.9 2.5 1.6.9 3.2 1.9 4.7 3 3 2.1 5.9 4.4 8.5 7 2.6 2.6 5 5.4 7 8.5l-.4.3c-2.7-2.4-5.5-4.7-8.3-6.9-2.8-2.2-5.6-4.4-8.5-6.4-1.4-1.1-2.9-2-4.4-3-1.5-1-3-1.9-4.5-2.8-3-1.9-6.2-3.5-9.4-5.4v-.3z"/>
<path d="M403.1 377.7c1.2.1 2.2.5 3.2.9 1 .5 1.9 1 2.7 1.6.4.3.8.6 1.2 1 .4.4.8.7 1.1 1.2.4.5.7 1 .9 1.7.1.3.1.7.1 1 0 .4-.2.7-.5.8-.1-.6-.5-.8-.8-1.1-.4-.2-.8-.5-1.2-.7-.4-.2-.9-.4-1.3-.7-.4-.3-.9-.6-1.3-.9-.8-.6-1.6-1.3-2.3-2.1-.7-.7-1.4-1.6-1.8-2.7z"/>
<path d="M406.6 389.5c1-.1 1.9.1 2.7.5a6.11 6.11 0 013.4 3.7c.3.8.4 1.7.2 2.7-.9-.4-1.6-.9-2.2-1.4-.6-.5-1.1-1-1.6-1.5s-.9-1.1-1.4-1.7c-.4-.6-.8-1.3-1.1-2.3z"/>
<path d="M409.2 399.9c1.2.5 2.2 1.3 3.1 2.2.9.9 1.6 1.9 2.3 2.9.6 1.1 1.1 2.2 1.4 3.4.3 1.2.5 2.5.3 3.8-1-.9-1.8-1.8-2.5-2.8-.7-.9-1.3-1.9-1.9-2.9-.6-1-1.1-2-1.6-3.1-.3-1.1-.8-2.2-1.1-3.5z"/>
<path d="M411.6 412.8c1 1 1.7 2.2 2.3 3.4.5 1.2.9 2.6 1.1 3.9.2 1.3.2 2.7 0 4.1-.2 1.3-.6 2.7-1.3 3.9-.5-1.4-.8-2.6-1-3.9l-.6-3.7c-.2-1.2-.3-2.5-.4-3.7-.1-1.3-.2-2.6-.1-4z"/>
<path d="M158.8 427.6c-.7-1.3-1.2-2.4-1.7-3.6-.5-1.1-1.1-2.3-1.6-3.4-.5-1.2-1-2.4-1.3-3.7-.4-1.3-.6-2.6-.6-4.1 1.1 1 1.9 2 2.7 3.1.8 1.1 1.4 2.3 2 3.5.5 1.3.9 2.6 1.1 4 0 1.4 0 2.9-.6 4.2z"/>
<path d="M209 307.4c1.1-.4 2.1-.6 3.1-.8 1-.2 1.9-.4 2.8-.5.9-.1 1.9-.3 2.9-.4 1-.1 2-.2 3.2-.1a6.4 6.4 0 01-2.5 2.4c-1 .6-2 .9-3.2 1.1-1.1.2-2.2.1-3.3-.1-1-.3-2.1-.8-3-1.6z"/>
<path d="M174.2 457.6c-.2.2-.2.4-.1.5.1.1.3.3.5.3.2.1.4.1.5.2h.6c1-.1 1.9-.1 2.9-.2 1.9-.1 3.8-.1 5.6-.2 1.9 0 3.7-.1 5.6-.1 1.9 0 3.8 0 5.8.2-1.7 1-3.6 1.6-5.5 2.1a28.72 28.72 0 01-14.6-.5l-.4-.1c-.2-.1-.3-.1-.5-.2-.3-.2-.5-.4-.7-.6-.2-.2-.3-.5-.4-.8 0-.1 0-.3.1-.5.4-.1.5-.1.6-.1z"/>
<path d="M183.2 411c1.2-.9 2.4-1.5 3.6-2 1.2-.5 2.5-1 3.7-1.4 1.3-.4 2.5-.7 3.9-.9 1.3-.2 2.7-.4 4.1-.3-1 1.1-2.2 1.9-3.4 2.5-1.2.7-2.5 1.2-3.8 1.6-1.3.4-2.6.6-4 .8-1.3.1-2.7.1-4.1-.3z"/>
<path d="M222.4 439.4c1.2-.4 2.4-.4 3.5-.2 1.2.2 2.3.7 3.3 1.3 1 .6 1.9 1.5 2.5 2.4.7 1 1.2 2.1 1.2 3.3-1.1-.5-2-1.1-2.9-1.6l-2.5-1.6-2.5-1.6c-.8-.6-1.7-1.2-2.6-2z"/>
<path d="M256 435.8a29.46 29.46 0 008.7.9c1.4-.1 2.7-.3 4.1-.7 1.4-.3 2.8-.8 4.3-1.4a7.9 7.9 0 01-3.4 3.6c-1.5.9-3.1 1.4-4.8 1.5-1.7.1-3.4-.1-5-.8-1.6-.7-3-1.7-3.9-3.1z"/>
<path d="M355.3 511.1c-1.9.2-2.9 1.5-3.7 2.9-.4.7-.8 1.4-1.1 2.1-.3.8-.7 1.5-.9 2.3-.6 1.6-1.1 3.2-1.6 4.8-.5 1.7-.8 3.4-1.3 5.2-.8-1.7-1-3.6-1-5.5s.4-3.8 1.1-5.6a13.68 13.68 0 013-5c.7-.7 1.6-1.3 2.6-1.6.5-.1 1-.2 1.5-.2.6.2 1 .4 1.4.6z"/>
<path d="M332.7 551.3c-2.1 4.4-4.4 8.6-6.8 12.8-1.2 2.1-2.4 4.1-3.7 6.2l-3.7 6.1c-1.3 2-2.5 4.1-3.7 6.1-1.3 2-2.4 4.1-3.6 6.2-2.4 4.1-4.6 8.4-6.8 12.7 1-4.7 2.7-9.3 4.7-13.8 1-2.2 2.1-4.4 3.3-6.5l3.6-6.3c2.6-4.1 5.2-8.1 8-12 2.7-3.9 5.6-7.8 8.7-11.5z"/>
<path d="M319.1 410.1c-.7-.6-1-1.6-1.2-2.5-.1-1 0-2 .4-2.9.7-1.8 1.9-3.4 3.5-4.5 1.5-1.1 3.2-1.7 4.8-2.3 1.6-.5 3.2-1 4.9-1.5-1 1.6-2.5 2.7-3.9 3.6-1.4.9-2.9 1.7-4.1 2.6-1.2.8-2.3 1.9-3.1 3.1-.9 1.2-1.5 2.5-1.3 4.4z"/>
<path d="M357.6 452c-.9 1-2.2 1.5-3.5 1.7-1.3.2-2.7 0-3.9-.5-1.2-.5-2.4-1.3-3.2-2.3-.8-1-1.4-2.3-1.4-3.6 1.1.8 2 1.3 2.9 1.9.9.5 1.8.9 2.8 1.3.9.4 1.9.7 2.9 1 1 .1 2.1.3 3.4.5z"/>
<path d="M46.2 335.6c0 2.5-.1 4.9-.1 7.3v7.1l.3 7.1c.1 2.4.3 4.8.4 7.2-1.3-2.1-2.1-4.5-2.8-6.9-.6-2.4-.9-4.9-1-7.4-.1-2.5.2-5 .7-7.4.5-2.4 1.3-4.8 2.5-7z"/>
<path d="M71.9 436.2c.4 2.1.8 4.1 1.3 6.1.5 1.9 1.2 3.8 1.9 5.6.7 1.8 1.6 3.6 2.6 5.3 1 1.7 2.1 3.4 3.3 5.2-2-.9-3.7-2.2-5.2-3.9-1.5-1.6-2.6-3.5-3.5-5.6-.8-2-1.3-4.2-1.4-6.4-.1-2.1.2-4.3 1-6.3z"/>
<path d="M81 471.1c1.3.7 2.4 1.3 3.6 2l3.3 1.9 3.3 1.8c1.1.6 2.3 1.2 3.5 2-1.4.5-2.9.5-4.3.2-1.4-.2-2.8-.7-4-1.4-1.3-.7-2.4-1.6-3.3-2.7-1-1.1-1.8-2.3-2.1-3.8z"/>
<path d="M150.8 399.4c1-.1 1.7-.8 2.2-1.6.5-.8.7-1.7.9-2.6a35.52 35.52 0 00-1-17.1v-.1c-.1-.4-.1-.8.2-1.1 1.2-1.9 1.8-4.2 1.9-6.6.1-1.2 0-2.5-.1-3.7-.1-1.3-.3-2.5-.5-3.8.6 1.1 1.2 2.3 1.6 3.6.5 1.2.8 2.5 1 3.9.2 1.3.2 2.7 0 4.1-.2 1.4-.7 2.8-1.4 4.1l.1-1.2c.7 2 1.3 4.1 1.5 6.2.3 2.1.3 4.2 0 6.3-.3 2.1-.8 4.1-1.6 6.1-.4 1-1 2-1.7 2.8-.4.4-.9.7-1.4.9-.6-.1-1.2 0-1.7-.2z"/>
<path d="M57.1 416.6c1-1.7 1.9-3.4 2.3-5.1.5-1.7.4-3.5 0-5.4-.4-1.9-.9-3.9-1.2-6-.3-2.1-.3-4.4.4-6.5v.6c-.6-2-.7-4-.6-6 .2-2 .6-4 1.3-5.8.7-1.8 1.6-3.6 2.7-5.2s2.4-3.1 3.9-4.3c-1.2 1.5-2.3 3.1-3.1 4.8a25.75 25.75 0 00-3 10.7c0 1.8.2 3.6.8 5.3.1.2.1.4 0 .6v.1c-.5 1.7-.4 3.6-.1 5.5.4 1.9 1 3.8 1.5 5.8.3 1 .5 2.1.5 3.3 0 1.1-.1 2.3-.3 3.4-.5 2.2-1.5 4.1-2.5 5.9l-2.6-1.7z"/>
<path d="M409.2 483.8c-.1 2 .7 3.7 1.8 4.9 1.1 1.3 2.6 2.3 4.2 3.5 1.6 1.2 3 2.5 4.5 3.9 1.4 1.4 2.8 2.8 3.9 4.5-1.9-.7-3.7-1.7-5.4-2.7-1.7-1-3.3-2.1-4.9-3.3-1.5-1.2-3.2-2.6-4.3-4.6-.5-1-.8-2.1-.8-3.2s.3-2.3 1-3z"/>
<path d="M439 583.8c-.4-5.5-.4-11.1-.3-16.6.1-5.5.4-11.1.7-16.6.3-5.5.8-11.1 1.5-16.6.6-5.5 1.4-11 2.5-16.5l2.9.6c-1.2 5.3-2 10.8-2.8 16.2-.8 5.5-1.4 10.9-2 16.4-1.1 11-1.7 22-2.5 33.1z"/>
<path d="M301 384.3c0 3.5 0 7 .3 10.5s.7 7 1.7 10.2c.5 1.6 1.2 3.1 2.1 4.4.9 1.3 2.1 2.5 3.4 3.6 2.6 2.1 5.6 3.7 8.7 5.3l-1.4 2.7c-3.1-1.7-6.3-3.5-9.1-5.9-1.4-1.2-2.6-2.7-3.6-4.3-1-1.6-1.7-3.4-2.1-5.2-.4-1.8-.7-3.6-.8-5.4-.1-1.8-.2-3.6-.2-5.3-.1-3.6.2-7.2 1-10.6z"/>
<path d="M76.3 306c1.1.1 2.1.8 2.7 1.9.6 1 .9 2.2.9 3.3.1 1.1 0 2.2-.3 3.3-.2 1.1-.5 2-.9 3-.7 2-1.5 3.9-2.4 5.7-1 1.8-2.1 3.6-3.5 5.1.3-2.1.8-4.1 1.3-6 .5-1.9 1.1-3.9 1.8-5.8s1.3-3.6 1.6-5.5c.4-1.7.5-3.5-1.2-5z"/>
<path d="M53.1 306c1.1-.2 2.2.5 3 1.3.8.8 1.4 1.7 1.9 2.7.9 2 1.5 4.1 1.7 6.3 0 1.2-.1 2.2-.2 3.3-.2 1.1-.5 2.1-.8 3.1-.7 2-1.6 3.8-2.5 5.7-.3-2.1-.1-4.3.2-6.2l.3-2.9c0-.5.1-1 .1-1.4v-1.4c-.1-1.8-.4-3.8-.9-5.6-.2-.9-.5-1.8-.9-2.7-.4-.9-.9-1.7-1.9-2.2z"/>
<path d="M118.8 306.1c1.6 2.2 2.8 4.6 3.7 7.1.9 2.5 1.6 5.1 1.9 7.8.4 2.6.5 5.3.3 8s-.7 5.3-1.6 7.8c-.3-2.7-.5-5.2-.8-7.8-.2-2.6-.5-5.1-.9-7.6s-.8-5-1.2-7.6c-.4-2.5-1-5-1.4-7.7z"/>
<path d="M140.5 316.3c1.1.3 2 .9 2.7 1.6.7.7 1.4 1.5 1.9 2.4.5.9.8 1.8 1 2.8.2 1 .2 2-.1 3.1-.9-.7-1.5-1.5-2-2.2-.6-.8-1-1.5-1.5-2.3-.4-.8-.8-1.6-1.2-2.5-.3-.9-.6-1.8-.8-2.9z"/>
<path d="M102 349.8c2.6.2 5 1.7 6.9 3.5 1.9 1.9 3.3 4.2 4.2 6.7.9 2.4 1.5 5 1.9 7.4.4 2.5.6 5 .8 7.5-1.4-2.2-2.2-4.6-3-7-.8-2.4-1.5-4.7-2.4-6.9a33 33 0 00-3.2-6.2c-1.4-1.8-3.1-3.6-5.2-5z"/>
<path d="M126.3 288.4c2 .8 3.8 1.8 5.5 2.9 1.7 1.1 3.4 2.3 5 3.6 1.6 1.3 3.1 2.6 4.6 3.8 1.5 1.2 3.1 2.2 5.2 2.7-2 .8-4.5.3-6.4-.6-2-.9-3.7-2.2-5.3-3.5-1.6-1.3-3.1-2.6-4.6-4.1-1.4-1.5-2.8-3-4-4.8z"/>
<path d="M96.4 312.8c1.4.9 2.5 2.2 3.3 3.6.8 1.4 1.3 3 1.4 4.7.2 1.6 0 3.3-.4 4.9-.5 1.6-1.2 3.1-2.4 4.2 0-1.6.1-3.1.1-4.5s-.1-2.8-.2-4.2c-.1-1.4-.4-2.8-.7-4.2-.3-1.5-.7-2.9-1.1-4.5z"/>
<path d="M92.9 298.7c-.2-1.8-.1-3.6-.1-5.3 0-1.7.1-3.4.2-5.1l.3-5.1c.2-1.7.3-3.4.7-5.2.9 1.6 1.4 3.4 1.7 5.1.3 1.8.4 3.6.3 5.3-.1 1.8-.4 3.6-.9 5.3-.5 1.8-1.2 3.5-2.2 5z"/>
<path d="M110.7 253.2c1.3.3 2.5 1 3.5 1.9 1 .9 1.8 2 2.3 3.2.6 1.2.9 2.5 1 3.8.1 1.3-.1 2.7-.8 3.9-.6-1.2-1.1-2.3-1.5-3.3-.5-1-.9-2-1.4-3-.5-1-.9-2-1.5-3-.5-1.2-1-2.3-1.6-3.5z"/>
<path d="M131 263.4c1 2.2 2.4 4.3 3.9 6.1 1.6 1.9 3.5 3.6 5.4 5.2 3.9 3.2 8.4 5.9 12.5 9.1-2.4-1-4.7-2.1-7-3.4-2.3-1.3-4.5-2.6-6.7-4.1a42.3 42.3 0 01-6.1-5.1 25.6 25.6 0 01-4.7-6.6l2.7-1.2z"/>
<path d="M30.1 309.6c-.6-1.8-1-3.6-1.1-5.5-.1-1.9 0-3.8.4-5.7.4-1.9 1.1-3.7 2.2-5.4 1.1-1.6 2.6-3 4.4-3.7-.9 1.7-1.7 3.2-2.3 4.8-.6 1.6-1 3.2-1.4 4.9-.4 1.7-.6 3.4-1 5.2-.2 1.7-.6 3.5-1.2 5.4z"/>
<path d="M52.9 274.1c-.4 1.6-.6 3.1-.7 4.6-.1 1.5-.1 2.9 0 4.4.1 1.4.4 2.9.8 4.3s1 2.8 1.6 4.4c-1.5-.8-2.6-2.1-3.4-3.6-.8-1.5-1.3-3.1-1.5-4.8-.2-1.7 0-3.4.5-5 .6-1.7 1.5-3.2 2.7-4.3z"/>
<path d="M14.1 216c.5.3.9.4 1.2.3.3-.1.8-.5 1.2-1.1.8-1.2 1.5-2.7 2.2-4.2.7-1.5 1.4-3 2.3-4.4.9-1.4 2-2.7 3.4-3.5-1.3 1-2.1 2.4-2.8 3.9-.7 1.4-1.1 3-1.6 4.5-.5 1.6-.8 3.1-1.6 4.8-.4.8-.9 1.7-2.1 2.3-.6.3-1.3.4-1.9.4-.6 0-1.1-.2-1.7-.4l1.4-2.6z"/>
<path d="M11.3 246.7c.5.1.8.1 1.1-.1.3-.2.7-.7 1-1.3.6-1.2 1-2.7 1.4-4.1.4-1.4.8-2.9 1.5-4.3s1.6-2.7 2.9-3.4c-1.2.9-1.8 2.3-2.2 3.7-.4 1.4-.6 2.9-.7 4.3-.2 1.5-.3 3-.7 4.6-.2.8-.6 1.7-1.4 2.5-.8.8-2 1.2-3 1.2l.1-3.1z"/>
<path d="M3.6 276.1c.4.1.6.1.9.1.3-.1.6-.3.9-.7.6-.8 1.1-1.9 1.5-3.1.4-1.1.8-2.3 1.4-3.5.5-1.1 1.2-2.3 2.2-3-.9.9-1.2 2.1-1.5 3.2-.3 1.2-.4 2.4-.6 3.6-.2 1.2-.4 2.5-1 3.8-.3.7-.8 1.4-1.6 1.9-.8.6-1.9.7-2.7.6l.5-2.9z"/>
<path d="M69.1 209.7c.1 1.7.1 3.3.3 4.8.2 1.5.3 3 .6 4.6.2 1.5.5 3 .8 4.6.3 1.5.6 3.1.8 4.8l-.4.2a13.9 13.9 0 01-2.8-4.3c-.7-1.5-1.1-3.2-1.3-4.9-.3-1.7-.2-3.4.1-5.1.3-1.7.9-3.3 1.9-4.7z"/>
<path d="M42.5 233.8c-.4-1.2-.5-2.5-.4-3.7.1-1.2.3-2.3.6-3.4s.6-2.1.9-3.1c.3-1 .6-2 .9-3.3.9.9 1.3 2.2 1.4 3.5.1 1.3 0 2.5-.3 3.6-.3 1.2-.7 2.2-1.2 3.2-.6 1.2-1.2 2.2-1.9 3.2z"/>
<path d="m 32.8,189 c -0.1,1 -0.3,2 -0.6,3 -0.3,1 -0.6,2 -0.9,3 -0.3,1 -0.6,2 -0.9,4 -0.9,-1 -1.3,-3 -1.4,-4 -0.1,-1 0,-2 0.3,-3 0.3,-2 0.7,-3 1.2,-4 z"/>
<path d="M57.5 194.5c.7 1 .9 2.1 1 3.2 0 1.1-.2 2.2-.6 3.3-.4 1-1 2-1.8 2.8-.8.8-1.7 1.4-2.9 1.7.3-1.2.6-2.1.9-3 .3-.9.6-1.8 1-2.6.3-.9.7-1.7 1.1-2.6.3-.9.7-1.8 1.3-2.8z"/>
<path d="M191.5 212.5c1.7.5 3.3 1.4 4.6 2.7 1.3 1.3 2.2 2.9 3 4.4.4.7.8 1.4 1.3 1.9.4.5 1 .8 1.6 1.1.6.3 1.2.4 1.8.4.6 0 1.2-.3 1.8-1l.4.1c.1.5 0 1-.3 1.5s-.7.9-1.3 1.2c-1.1.5-2.3.5-3.3.1s-1.9-1-2.5-1.9c-.7-.8-1-1.7-1.4-2.5-.4-.8-.7-1.6-1-2.3-.4-.7-.7-1.5-1.2-2.1-.9-1.3-2.1-2.5-3.5-3.6z"/>
<path d="M195.4 198.5c-2.1-.7-4-1.8-5.8-3.1a34.2 34.2 0 01-4.9-4.4c-1.5-1.6-2.8-3.3-4.1-5-1.3-1.7-2.6-3.3-4-4.9l.2-.2c2 1 3.6 2.5 5.1 4.1 1.5 1.5 2.9 3.2 4.3 4.7 1.4 1.6 2.9 3.1 4.4 4.5 1.6 1.5 3.2 2.9 4.8 4.3z"/>
<path d="M138.7 141.1c.8-1 2-1.7 3.3-1.9 1.3-.2 2.6-.1 3.8-.1 1.2 0 2.3-.1 3-.5.7-.4 1-1.2 1.3-2.2l2.8 1c-.4.7-.6 1.3-1.2 1.9-.2.3-.6.6-.9.8-.3.3-.7.4-1.1.6-1.6.6-3 .3-4.2 0-1.2-.2-2.4-.5-3.5-.6-1.1 0-2.3.3-3.1 1.1l-.2-.1z"/>
<path d="M197.6 213.9c1-.2 1.8-.2 2.7 0 .9.2 1.7.5 2.5 1s1.5 1.1 2 2c.5.9.6 2.1 0 2.9-.4-.9-1-1.3-1.5-1.7-.5-.4-1.2-.7-1.8-1.1-.6-.4-1.3-.8-1.9-1.3-.7-.5-1.3-1-2-1.8z"/>
<path d="M111.2 126.1c-1.9 0-3.6.2-5.2.7-.8.3-1.5.6-2.3 1-.7.4-1.5.9-2.4 1.3-.9.4-1.9.8-3 .9-1.1.1-2.1 0-3-.2-1.9-.4-3.5-1-5.4-1.2 1.8-.9 3.8-.7 5.6-.8.9 0 1.7-.1 2.5-.2s1.5-.4 2.2-.8c.8-.4 1.6-.8 2.5-1.2.9-.4 1.9-.7 2.9-.8 1.9-.1 4 .2 5.6 1.3z"/>
<path d="M114.9 144.9c-1.1.4-2.1.7-3.1 1.1-.9.4-1.8.8-2.7 1.3-.8.5-1.7 1-2.6 1.6-1 .5-2.1 1.1-3.3 1.1.8-.9 1.4-1.8 2.1-2.6.7-.8 1.6-1.7 2.7-2.3 1.1-.6 2.3-.9 3.5-1 1.1-.1 2.3.2 3.4.8z"/>
<path d="M96.6 139.9c.9-1.2 1.9-2.2 3.2-3 1.2-.8 2.6-1.4 4.1-1.8 1.4-.4 3-.5 4.5-.3s3 .6 4.1 1.7c-1.5-.1-2.8.1-4.1.3-1.3.2-2.6.5-3.9.8-1.3.3-2.5.7-3.8 1.1-1.4.3-2.7.8-4.1 1.2z"/>
<path d="M126.1 134.1c.3-.9 1-1.6 1.8-2 .8-.5 1.7-.7 2.5-.8.9-.1 1.7 0 2.5.2s1.6.6 2.3 1.2c-.9.4-1.6.6-2.4.7l-2.2.3-2.1.1-2.4.3z"/>
<path d="M155.9 183.7c-.4.4-.9.7-1.4 1-.5.2-1 .5-1.5.6-1.1.3-2.2.4-3.3.3a7.2 7.2 0 01-3.2-1.1c-1-.6-1.8-1.4-2.2-2.6l.3-.2c2 .8 3.7 1.2 5.5 1.4l2.8.3c.5 0 1 .1 1.5.1.4 0 .9 0 1.5.2z"/>
<path d="M131.7 166.2c1-1.2 2.1-2.2 3.4-3.1 1.3-.8 2.8-1.5 4.4-1.8 1.6-.3 3.2-.3 4.7-.2 1.5.2 3 .4 4.5.8 1.5.3 2.9.7 4.3 1.1 1.4.4 2.8.7 4.2 1 2.8.5 5.7 1 8.3-.4l.2.3a8.23 8.23 0 01-4.2 2c-1.6.3-3.1.2-4.6.1-3.1-.3-5.9-1.1-8.8-1.7-1.4-.3-2.8-.7-4.2-.9-1.4-.2-2.8-.3-4.2-.2-2.8.3-5.4 1.5-8 3z"/>
<path d="M134.5 170.9c1.5-.6 2.9-1.4 4.2-2.3 1.3-.9 2.6-1.8 3.6-2.9l1.5 2a24.72 24.72 0 01-9.3 3.2z"/>
<path d="M148.5 164.2c.7.2 1.4.3 2 .3.3 0 .6-.1.8-.1.3.2.7.3 1 .5.1.1.3.1.4.2.2.2.4.3.7.5.8.7 2.2 1.9 2.8 3-.1 2.6-1.7 4.9-4.2 6-.8.3-1.6-.3-1.5-1.1.3-2.9-.6-7.1-2-9.3z"/>
<path d="M170.1 177.5c-1.2.1-2.4.1-3.5-.2-1.2-.3-2.3-.6-3.4-1.1-1.1-.5-2.2-1-3.2-1.7s-2-1.4-2.9-2.3l1.9-1.7c.6.7 1.5 1.5 2.3 2.2.8.7 1.8 1.3 2.7 1.9.9.6 1.9 1.1 3 1.5 1 .5 2 .9 3.1 1.4z"/>
<path d="M73.5 147c1.9.5 3.7 1.2 5.3 2.1 1.6.9 3.1 2 4.4 3.3l-.2.2c-1.5-.9-3.2-1.6-4.8-2-1.7-.5-3.3-.7-5-.7l.3-2.9z"/>
<path d="M78.3 176.2c-2.4.8-4.4 2.4-6.4 4-1 .8-1.9 1.7-2.9 2.5s-2 1.7-3.2 2.5l-1.4-2.7c1-.4 2.1-1.1 3.2-1.7 1.1-.6 2.2-1.3 3.3-2 2.3-1.3 4.6-2.5 7.2-2.9l.2.3z"/>
<path d="M6.2 177c2.5-1.9 5.3-3.2 8.3-4.4a40 40 0 019.2-2.3c3.1-.4 6.4-.3 9.5.2 3.1.4 6.2 1.4 9.1 2.3 1.5.5 2.9.9 4.3 1.1 1.4.2 2.9.3 4.4.3.7 0 1.5 0 2.3-.1l2.3-.2c1.5-.1 2.9-.5 4.3-.9 2.8-.9 5.6-2.2 8.3-3.7 2.7-1.5 5.2-3.2 7.7-5.1l.3.3c-2.2 2.2-4.6 4.2-7.2 6-2.6 1.8-5.3 3.4-8.4 4.5-1.5.6-3.1 1-4.7 1.2l-2.3.3c-.8.1-1.6.1-2.4.2-1.6.1-3.2 0-4.9-.3-1.6-.3-3.2-.7-4.7-1.2-5.8-2-11.7-3.5-17.7-3.1-3 .2-6 .7-9 1.6-3 .9-5.9 1.9-8.7 3.3z"/>
<path d="M136.5 144.2c-.5 1.1-1.1 2.1-1.9 2.9-.8.8-1.8 1.5-3 1.9-1.2.4-2.5.5-3.7.2-1.2-.3-2.4-1.1-2.8-2.3 1.2.2 2.1.1 3 0 .9-.2 1.7-.4 2.6-.7.9-.3 1.7-.6 2.7-1 .9-.5 1.9-.9 3.1-1z"/>
<path d="M122.1 152.3c-.7 1.6-1.5 3.1-2.7 4.4-1.1 1.3-2.6 2.5-4.3 3.3-1.7.8-3.8.9-5.6.5-1.8-.4-3.4-1.3-4.6-2.6 1.8.1 3.4.3 4.9.2 1.5-.1 2.9-.4 4.2-.9 1.3-.6 2.6-1.4 3.9-2.3 1.3-.8 2.7-1.8 4.2-2.6z"/>
<path d="M104.9 166.5c.8 1 1.1 2.3 1 3.6-.1 1.3-.5 2.5-1.2 3.5s-1.6 1.9-2.7 2.5c-1.1.6-2.4.9-3.6.7.8-.9 1.5-1.7 2.1-2.5.6-.8 1.2-1.5 1.7-2.3.5-.8 1-1.6 1.5-2.5.4-.9.8-1.8 1.2-3z"/>
<path d="M97.9 184c1.3.7 2.3 2.1 2.8 3.6s.5 3.2.1 4.7-1.2 3-2.4 4c-1.2 1.1-2.4 1.5-3.6 2.4 0-.8.4-1.5.8-2.1.4-.6.7-1.2 1-1.7a15.07 15.07 0 001.3-10.9z"/>
<path d="M81.2 234.7c2 1.1 3.7 2.4 5.4 3.9 1.6 1.5 3 3.3 4.1 5.4 1 2.1 1.6 4.5 1.4 6.8-.1 2.3-1 4.7-2.7 6.2.6-2.2.7-4.2.4-6.1-.3-1.9-.9-3.8-1.8-5.6-.9-1.8-2-3.5-3.2-5.2-1.2-1.7-2.5-3.4-3.6-5.4z"/>
<path d="M101.4 260.4c1.8 1.5 3.2 3.3 4.5 5.2 1.3 1.9 2.3 4 3.1 6.2.8 2.1 1.4 4.5 1.3 7 0 1.2-.3 2.5-.8 3.6a6.3 6.3 0 01-2.4 2.7c1.2-2 1.2-4.1.9-6.1-.3-2.1-1-4-1.7-6.1-.7-2-1.5-4.1-2.3-6.1-1-2.2-1.8-4.2-2.6-6.4z"/>
<path d="M72.8 262.5c-.2.4-.1.8.1 1.2.2.4.4.7.7 1l1.7 2.2c1.1 1.5 2.2 3 3 4.8a13 13 0 011.2 5.9c-.1 2-.9 4.2-2.5 5.3.5-1.9.5-3.6.2-5.2-.3-1.7-.9-3.2-1.6-4.8-.7-1.6-1.6-3.2-2.3-4.9-.4-.9-.7-1.8-1-2.7-.1-.4-.3-1-.2-1.5 0-.3.1-.6.2-.8.1-.2.3-.4.5-.5z"/>
<path d="M58.1 234.8c.8 1.7 1.2 3.3 1.8 4.8.6 1.5 1.3 2.8 2.2 3.9.9 1.1 2.3 2.1 3.6 3.4.6.6 1.3 1.4 1.7 2.2.4.9.7 1.9.5 2.8-.9-1.6-2.2-2.3-3.7-3.2-1.4-.8-3-1.7-4.4-3.2-1.3-1.5-2-3.5-2.2-5.3-.2-1.8 0-3.6.5-5.4z"/>
<path d="M88.4 137.3c-1.3.1-2.5.1-3.6.1l-3.4-.1-3.4-.1c-1.2-.1-2.3-.1-3.6-.3 1-.8 2.2-1.3 3.4-1.6 1.2-.3 2.5-.5 3.7-.4 1.3 0 2.5.3 3.7.7 1.1.2 2.3.8 3.2 1.7z"/>
<path d="M79.3 128.3c-1.5.4-2.9.9-4.2 1.5-1.3.6-2.4 1.3-3.4 2.2-.5.4-1 .9-1.5 1.4-.5.5-1 1.1-1.6 1.6-.6.5-1.3 1.1-2 1.4-.8.4-1.7.5-2.5.3 1.5-.7 2.2-1.8 3-3 .4-.6.8-1.2 1.3-1.9.5-.6 1.1-1.3 1.7-1.8 1.3-1.1 2.8-1.8 4.4-2.2 1.6-.2 3.3-.1 4.8.5z"/>
<path d="M37.1 208.5c-.8 1.4-1.5 2.7-2 4-.5 1.3-.9 2.6-1.2 3.9-.3 1.3-.5 2.7-.5 4.1-.1 1.4 0 2.8.2 4.5-1.3-1-2.1-2.6-2.5-4.2-.4-1.6-.4-3.4-.1-5 .4-1.6 1.1-3.2 2.1-4.5 1-1.3 2.4-2.4 4-2.8z"/>
<path d="M29.7 243.9c.1 1.1 0 2.1-.1 3.1-.1.9-.3 1.8-.5 2.7-.2.9-.5 1.7-.8 2.6-.3.9-.7 1.8-1.4 2.7-.6-1-.9-2-1-3-.1-1 0-2.1.3-3.1s.7-1.9 1.2-2.8c.5-.9 1.3-1.7 2.3-2.2z"/>
<path d="M30.9 263.2c-.7 1.8-1.4 3.5-2 5.3-.6 1.7-1.1 3.4-1.5 5.1-.4 1.7-.8 3.5-1 5.3-.3 1.8-.4 3.6-.6 5.6-1-1.7-1.5-3.7-1.7-5.6-.2-2 0-4 .4-5.9.5-1.9 1.3-3.8 2.3-5.5 1.1-1.7 2.4-3.2 4.1-4.3z"/>
<path d="M49 244c-.6.6-.8 1.4-1.1 2.1-.2.8-.5 1.5-.6 2.3-.4 1.6-.7 3-.8 4.6-.2 1.6-.5 3.3-1 4.8-.5 1.6-1.2 3.1-2.2 4.5-.2-1.7-.1-3.3.1-5 .2-1.6.4-3.2.7-4.8.3-1.7.9-3.3 1.6-4.8.4-.7.8-1.5 1.4-2.2.5-.6 1.1-1.3 1.9-1.5z"/>
<path d="M100 224.4c-.1 3.2.6 6.3 2.1 8.9 1.5 2.6 3.7 4.8 6.3 6.6 2.5 1.7 5.3 3.1 8.2 4.2 2.9 1.1 5.9 2 8.9 2.6l-.7 2.9c-3.1-.8-6.3-1.8-9.3-3.1-3-1.3-5.9-2.9-8.4-5-2.6-2-4.9-4.6-6.3-7.6-1.3-2.9-1.7-6.4-.8-9.5z"/>
<path d="M199.2 242.7c-2.1.2-4.3.2-6.4-.5-2.1-.7-3.8-1.8-5.5-2.8-1.6-1.1-3.3-2.1-4.9-3.1-1.7-1-3.4-1.9-5.1-2.9 2 .3 3.9.9 5.7 1.6 1.8.8 3.6 1.7 5.4 2.5a22 22 0 005.1 2.1c.9.2 1.7.3 2.6.3l1.3-.1 1.3-.1.5 3z"/>
<path d="M90 198.9c-.1 1.2-.6 2.3-1.4 3.1-.7.9-1.7 1.6-2.6 2.1-1 .5-2 .8-3.1 1-1.1.1-2.2.2-3.3-.1.8-.9 1.7-1.5 2.5-2.1.9-.6 1.7-1 2.5-1.4.8-.4 1.7-.8 2.5-1.2l2.9-1.4z"/>
<path d="M136.7 206.1c1.2-.2 2.3-.1 3.4.3s2.1.9 3 1.6c.9.7 1.6 1.6 2.2 2.6.6 1 .9 2.1.9 3.3-1.1-.6-1.9-1.2-2.7-1.8-.8-.6-1.6-1.2-2.3-1.8-.7-.6-1.5-1.2-2.2-1.9-.7-.7-1.5-1.4-2.3-2.3z"/>
<path d="M145.8 217.9c.8.5 1.4 1.2 1.9 1.9a7.71 7.71 0 011.1 5.2c-.1.9-.4 1.8-.9 2.5-.3-.9-.5-1.7-.6-2.5l-.5-2.3-.5-2.3c-.2-.8-.4-1.6-.5-2.5z"/>
<path d="M-8.4 393.2c1-1.4 1.6-3.3 2-5.2.4-1.9.6-3.9.8-6 .5-4.1 1-8.2 2.7-12l.3.1C-3.9 374-4 378-4 382.1c0 2 0 4.1-.2 6.2-.2 2.1-.6 4.3-1.7 6.4l-2.5-1.5z"/>
<path d="M9.5 429.2c-.4-2-.4-4-.2-5.9.2-1.9.7-3.7 1.2-5.5.5-1.8 1-3.5 1.4-5.3.4-1.7.5-3.6.2-5.3l.3-.1c.6 1.8.7 3.7.5 5.5-.2 1.9-.5 3.7-.8 5.5-.3 1.8-.5 3.6-.5 5.3 0 1.7.2 3.4.7 5l-2.8.8z"/>
<path d="M-19.1 353c1.4-1 2.7-2.1 3.8-3.4 1.1-1.3 1.9-2.9 2.4-4.5.5-1.7.8-3.5 1.1-5.3.3-1.8.7-3.7 1.5-5.4l.3.1c-.6 1.7-.7 3.6-.8 5.4-.1 1.8-.1 3.7-.5 5.6-.3 1.9-1 3.8-2.1 5.5a23.8 23.8 0 01-3.9 4.5l-1.8-2.5z"/>
<path d="M-11.1 314.8c1.1-.8 2.2-1.8 3.1-3 1-1.1 1.8-2.4 2.8-3.7 1-1.3 2-2.5 3.3-3.5 1.2-1 2.6-1.8 4.1-2.4l.1.3c-1.3.8-2.5 1.8-3.5 2.9-1 1.1-1.8 2.4-2.6 3.7-.8 1.3-1.4 2.7-2.3 4.1-.8 1.4-1.9 2.7-3.1 3.9l-1.9-2.3z"/>
<path d="M12.1 380.3c1.6-1.5 3-3 4.2-4.6 1.3-1.6 2.4-3.2 3.3-4.9 1-1.7 1.8-3.5 2.5-5.4.7-1.9 1.3-3.9 1.8-6 .7 2.1.8 4.4.5 6.6-.3 2.2-1.1 4.4-2.2 6.3-1.1 1.9-2.6 3.7-4.3 5.1-1.7 1.4-3.7 2.5-5.8 2.9z"/>
<path d="M19.2 303.7c-1.6 1.5-3.1 2.9-4.5 4.4a42.9 42.9 0 00-3.6 4.8c-1.1 1.7-2 3.4-2.8 5.3-.8 1.8-1.5 3.8-2.1 5.9-.6-2.1-.6-4.4-.2-6.6.4-2.2 1.3-4.3 2.5-6.2 1.2-1.9 2.8-3.6 4.5-4.9 2-1.4 4-2.4 6.2-2.7z"/>
<path d="M18.1 332c-1.1 1.9-2.2 3.6-3 5.5-.8 1.8-1.5 3.7-2.1 5.6-.5 1.9-.9 3.8-1.1 5.8-.2 2-.3 4-.3 6.2-1.2-1.9-1.8-4-2-6.3a18.56 18.56 0 013.5-12.6c1.3-1.7 3-3.3 5-4.2z"/>
<path d="M35.2 387.7c-.5 2.1-1 4.1-1.3 6.1-.3 2-.6 3.9-.7 5.9-.1 2-.1 3.9 0 5.9.1 2 .3 4 .5 6.2-1.4-1.7-2.3-3.7-2.9-5.8-.6-2.1-.8-4.3-.6-6.5.1-2.2.6-4.3 1.4-6.4.9-2.1 2-3.9 3.6-5.4z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 25 KiB

157
charges/mastiffStatant.svg Normal file
View file

@ -0,0 +1,157 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="#d7374a" stroke="#000" viewBox="50 50 200 200">
<metadata source="http://wappenwiki.org/images/d/d2/Toggenburger.svg" license="https://creativecommons.org/licenses/by-nc-sa/3.0"/>
<g id="mastiffStatant" stroke-width="3" transform="translate(49 68) scale(0.13)">
<path d="M256.5 505.7c.1.1-11.4 6.4-12.7 17.7-.2 1.7-.3 5.4.6 5.5.6.1 1-1.8 4.4-4.1 5.1-2.5 12.1-3.1 16.9-7"/>
<path d="M290.5 537.4c-4.7 4-11.6 4.8-16.6 7.6-3.2 2.4-3.6 4.3-4.2 4.3-.9-.1-.9-3.8-.8-5.5.8-11.3 12.1-18 12-18.1"/>
<path d="M324.2 496.9c1.2 2.5 3.1 1.4 5.8 4.5 1.5 1.9 2.9 4.9 3.3 5.1.6.2 1.5-1.8 1.8-2.9 1.7-6.5-.4-12.5-.3-12.5-5.2-5.5-11.3-11.3-17.5-15.7"/>
<path d="M576.1 505.7c.1.1-11.4 6.4-12.7 17.7-.2 1.7-.3 5.4.6 5.5.6.1 1-1.8 4.4-4.1 5.1-2.5 12.1-3.1 16.9-7"/>
<path d="M610.1 537.4c-4.7 4-11.6 4.8-16.6 7.6-3.2 2.4-3.6 4.3-4.2 4.3-.9-.1-.9-3.8-.8-5.5.8-11.3 12.1-18 12-18.1"/>
<path d="M598.1 527c-4.7 4-11.6 4.8-16.6 7.6-3.2 2.4-3.6 4.3-4.2 4.3-.9-.1-.9-3.8-.8-5.5.8-11.3 12.1-18 12-18.1"/>
<path d="M643.8 496.9c1.2 2.5 3.1 1.4 5.8 4.5 1.5 1.9 2.9 4.9 3.3 5.1.6.2 1.5-1.8 1.8-2.9 1.7-6.5-.4-12.5-.3-12.5-3.6-5.1-8.3-9.6-13.7-12.7"/>
<path d="M277.4 528c-4.7 4-11.6 4.8-16.6 7.6-3.2 2.4-3.6 4.3-4.2 4.3-.9-.1-.9-3.8-.8-5.5.8-11.3 12.1-18 12-18.1"/>
<path d="M409.6 471.6c.1.1-11.4 6.4-12.7 17.7-.2 1.7-.3 5.4.6 5.5.6.1 1-1.8 4.4-4.1 5.1-2.5 12.1-3.1 16.9-7"/>
<path d="M443.6 503.3c-4.7 4-11.6 4.8-16.6 7.6-3.2 2.4-3.6 4.3-4.2 4.3-.9-.1-.9-3.8-.8-5.5.8-11.3 12.1-18 12-18.1"/>
<path d="M431.6 492.8c-4.7 4-11.6 4.8-16.6 7.6-3.2 2.4-3.6 4.3-4.2 4.3-.9-.1-.9-3.8-.8-5.5.8-11.3 12.1-18 12-18.1"/>
<path d="M481.1 472.2c.6 2.7 2.7 2.1 4.6 5.8 1.1 2.2 1.6 5.5 2 5.7.5.3 1.9-1.4 2.5-2.4 3.2-5.9 2.5-12.2 2.6-12.2.6-6.8-.8-14.1-3.5-20.3"/>
<path d="M147.1 469.3c.1.1-12 5.1-14.4 16.3-.4 1.7-.8 5.3 0 5.5.6.1 1.2-1.7 4.8-3.6 5.3-2 12.3-1.8 17.5-5.2"/>
<path d="M177.7 504.3c-5.1 3.5-12.1 3.6-17.3 5.8-3.5 2-4 3.9-4.6 3.8-.8-.2-.5-3.8-.2-5.5 2-11.2 13.9-16.6 13.8-16.8"/>
<path d="M166.8 492.7c-5.1 3.5-12.1 3.6-17.3 5.8-3.5 2-4 3.9-4.6 3.8-.8-.2-.5-3.8-.2-5.5 2-11.2 13.9-16.6 13.8-16.8"/>
<path d="M215.4 467.5c1 2.6 3 1.7 5.3 5.1 1.3 2 2.3 5.2 2.7 5.4.5.2 1.7-1.6 2.1-2.7 2.4-6.3.9-12.4 1-12.5-4.6-3.5-9.4-7.3-14.2-10.5"/>
<path d="M193 285c-7.7 15.5-3.6 32.8-2.3 48.4.9 11.3 7.1 33.4 7.3 44.7 0 3.1-.3 6.3-.6 9.4-.4 3.4-.7 5.6-1 9-.4 3.7.8 7.2 1.5 10.8.7 4 0 6.9-.6 10.9-1.4 9.4-5 18.9-4.6 28.3-.6 2.9-5.5 7.8-7.5 10-2.2 2.5-6.9 6.4-9.3 7-9.9 4.3-14.3-3.4-20.9-.8-3.4.9-2.9.6-4.7.8-1.9.2-2.4-.2-4.6 1.5-3.1 3.1-1.8 6-1.8 6s2.4-1.6 7.1 3.6c3.4 3.9 3.2 8 3.2 8s2-1.1 5.7 2c4.7 4.2 4.2 9.6 4.2 9.6s2.9-2.6 8.4 2.2c2.6 2.9 4.5 5.8 3.7 8.3 1.6 1.5 8.9-.7 16.7-2.8 7.8-2.1 11.4-8 15.6-11.8 4.3-3.8 7.4-17 6.8-22.6.3-3 1.5-4.4 5.1-5 1.6-.3 4.4 0 6 .3.2.4 1.4-1.2 1.5-5.2 1-10-4.9-24.8-1.5-34 5.2-14.2 7.4-28.1 9.1-43.2.7-6.4 4-12.6 6.6-18.5 3.3-7.5 14.5-31.5 9.4-44"/>
<path d="M533.6 290c.2 7.1-2.8 24.6-6.7 30.6-4.1 6.2-4.4 8.9-6.8 15.6-3.2 8.7-12.2 23.9-11.1 31.8 2.1 15.1 9.2 11.5 13.5 13.6 5.3 2.7 6.8.3 12 7.1 2.8 3.6 3 6.9 2.1 11.5-.6 3.2-2.8 8.1-7.7 11-6.2 3.6-16 32.4-20.8 37.4-1.9 2-3.9 4-5.8 6.1-2.4 2.5-3.4 4.4-4.8 7.6-1.5 3.4-4.6 6.8-4.6 6.8-1.6-.5-3.2-1.2-4.9-1.1-3.7.2-6.1 1.4-6.8 4.3-5.8 4.5-4.5 9.5-8.3 14.9-3.1 4.5-6.8 9.3-14.3 12.2-7.5 2.9-14.6 5.9-16.4 4.5.5-2.5-1.7-5.3-4.6-7.9-6-4.2-8.6-1.3-8.6-1.3s0-5.4-5.2-9.1c-4-2.7-5.9-1.4-5.9-1.4s-.2-4-4-7.6c-5.2-4.7-7.5-2.8-7.5-2.8s-1.6-2.8 1.2-6.2c2-1.9 2.5-1.6 4.4-2 1.8-.4 1.3 0 4.6-1.3 6.4-3.3 13.7 4 23.1-1.3 2.3-.9 11.6-5.5 14.2-7.9 6.5-5 11.5-4 15-11.5 7.2-15.2 23-26.9 22.2-37.4-1-12.8-17.9-18.8-26.2-32.8-7-11.9-9.6-18.2-18-29-1.1-1.4-4-13.1-4.9-14.6-5.8-9.1-4.7-23.2 2.2-44.1 1.9-5.7 5.9-10.4 8.8-15.6 2.4-4.4 3.1-9.3 5.3-13.6 5.3-10 18.5-15.5 27.9-21.2 21-12.9 46.2 7.9 70.8 10.1"/>
<path d="M494.7 268.7c-24.3 2.6-45.1 18.6-45.1 18.6s-4.7 4.3-7.2 1.6c-1-1-2.2-2.8-1.5-5.3 2.7-9.2 22.1-22.8 22.1-22.8"/>
<path d="M207.7-7c1.3-6.6 5.1-11.5 9-16.6 5.5-7.1 9.6-15.3 12-24 1-3.8 2.1-8.1 5.7-9.8 11.4 19.8 14.9 43.6 12.6 66.6"/>
<path d="M218.2 85.7s-23.1-15-43.7-14.9c-21.5.1-34.4 9.9-46.2 9.9-20.1.3-19.6-9.2-21.2-9.2-1.6.4-2.1 4.2.4 8.9 2.4 4.4 8.4 9.7 21.7 9.3 18.9-.1 27.9-8.6 45.9-8.7 24.2-.1 41.5 12.6 41.5 12.6"/>
<g fill="#f6f6f6" stroke-width="2.5">
<path d="M139.5 80.1c-.9-.1-3.9 8.3-3.1 14.3.2-.1.3-.2.5-.3 2.1-1.4 4-1.9 5.8-2.1-1.6-4.3-2.5-11.8-3.2-11.9z"/>
<path d="M138.7 71.3c1-.8-1.6-4.4-3-12-.3-1.3-.3-2.6-.2-3.8-2.4-.1-4.7.2-7.3-.4-.4-.1-2.1-.2-2.6-.4 1.7 5.4 6.5 15.5 13.1 16.6z"/>
</g>
<path d="M330.1 149.9c-4.5-31.5-13.9-61.5-30.4-88.4a27.3 27.3 0 01-4.2-14.7 81.6 81.6 0 00-10.9-41.6c-3-6.9-9-18.5-19.8-22.9-9-3.9-13.8-6.3-31.9-5.1-7.6.5-13-1.2-19.7-.2-14.4.4-17.7 5.2-24.3 6.9-11.1 4.1-17.1 3.6-15.9 8.7 0 2.4 1.1 4 2.4 5.7-8.7-1.5-9.9-1-22.7 4.8-13.3 4.1-11.7.7-26.2 4.9-3.7.3-11.5-.1-12.5 3.5-3.3 9.3 3.1 12.9 3.1 15.6 0 0-.9 5.5.2 13.8.7 4.7 2.2 11.7 4.7 13 1.8 1.2 3.5 1.8 5.1 2.1 4.5.9 8.3 1.4 12.9 3.8s11.2 2.6 16 1c2.4-.8 4.8-2.3 6.9-3.8 1.5-1.1 3.3-3.1 5.2-3.5 2.2-.4 5.6 1.3 7.8 1.4 15.9 1.3 19.2-3 28.7 7.9 2 3.2 1.7 6.9 7.7 13 5.2 5.6 2.9 8.6 2.3 12.1-.6 3.5-3.8 6.4-11.4 4.7-7.6-1.7-13.2 3.8-21.5 4.5-6.2.5-15.2-5.3-20.9-3.7-12.9 3.5-14.9-3.1-22.7-1-2.5 1-7.1-.1-6.6 1.6-.8.5-.8 4.1 1.7 5.6 3.9 2.9 6.6 4.7 11.3 3.9 5.5-.9 3.3-.3 12.3-.2 15.1 1.1 11.7 4 23.5 4.4 14.6.2 22.2-5.2 36.4-3.5l-.4.2c-7.9 17-18.9 28.5-18.6 47.2.1 8.1-5.1 13.5-12.3 20.4-14.5 14.5-16.9 35.7-9.8 57.2-2 8.9-.1 31.7 7.4 42.2 0 0 4.1 20.8 27.5 29.5 9.5 24.8 35.2 27 35.2 27s5.9 3.3 16.9 27.6c-2.6 25.7 15.9 32.3 22.3 68.3.2 4.6 1.5 8.6 3.4 12.8 1.9 4 3.2 8.2 4.6 12.4.9 2.8 1.8 5.5 2.7 8.3 2.4 7.4 0 15.5-.8 23.2-.3 3-.4 6.1-2.2 8.6-1.9 2.7-6.2 7-8.5 7.9-9.3 5.3-14.5-1.9-20.9 1.3-3.3 1.3-2.8.9-4.6 1.3-1.9.4-2.4.1-4.4 2-2.8 3.4-1.2 6.2-1.2 6.2s2.3-1.8 7.5 2.8c3.8 3.6 4 7.6 4 7.6s1.9-1.3 5.9 1.4c5.1 3.7 5.2 9.1 5.2 9.1s2.6-2.9 8.6 1.3c2.9 2.6 5.1 5.4 4.6 7.9 1.7 1.4 8.8-1.6 16.4-4.5 7.5-2.9 10.5-9.1 14.3-13.3 3.9-4.2 5.6-17.7 4.5-23.2 0-3 1-4.5 4.5-5.5 1.6-.5 4.4-.4 6-.3-.9-6.6.4-12.8-1.2-19.3-1.7-6.9-4.8-14-7-20.7-2.8-8.3-3.7-18.5-3.9-27.2 0-15.1-3.9-40.4-2-52.8 2-13.4-2-9.2 0-21.4s.3-11 .3-21.8c22.8 0 33.2-19.1 67.5-32.3 41.6-12.9 44.7-27.5 87.8-27.5 14.3-.6 24 11.5 31.3 22.2 10.1 14.7 21.7 36.7 36.1 48.1 9.7 7.7 22.3 21.3 38.5 29.8 13.2 6.9 32.2 6.9 43 19.6 3.6 7.2 1.6 20.8 1.6 23.1 0 10.2.5 11.1.7 21.3.2 12 5.6 31-4.2 40.2-4.8 3.8-10.1 14.4-11.8 16.9-1.9 2.7-6.2 6-8.5 6.9-9.3 5.3-13.5-.9-19.8 2.4-3.3 1.3-2.8.9-4.6 1.3-1.9.4-2.4.1-4.4 2-2.8 3.4-1.2 6.2-1.2 6.2s2.3-1.8 7.5 2.8c3.8 3.6 4 7.6 4 7.6s1.9-1.3 5.9 1.4c5.1 3.7 5.2 9.1 5.2 9.1s2.6-2.9 8.6 1.3c2.9 2.6 5.1 5.4 4.6 7.9 1.7 1.4 8.8-1.6 16.4-4.5 7.5-2.9 9.4-8 13.3-12.2 3.9-4.2 3.1-17.8 5.5-24.3.7-2.5 2.1-4.5 5.6-5.5 1.6-.5 3.3-.4 5-.3 4.5-6.7 1-23.1 2.8-30 3.9-29.7 12.5-49.3 14.2-57.2 1.4-6.4 2.6-10.9 1.2-17.7-.6-2.8-1.7-4.7-1.1-7.7.9-3.9 4.1-6.7 5.5-10.3 1.2-3 .9-6.5.2-9.6-1-4.2-3.1-8.5-7.2-10-3-1-6.2-.2-9.3 0-6.5.5-16.2-3.5-20.4-7.8-8.6-10.9-11.8-21.6-15.2-34.3-4-15.3-4.8-17.1-7.2-32.4-2-12.6-4.1-17.9-8.2-29.9-4.2-12.1-11.6-32.2-21.1-40.8 44.7-7.2 65.9-26.8 79.3-50.5 9.7-17.1 14-37.3 12.1-56.9C674 32.8 624.9.6 579.9.6c-40 0-73 24.8-73 55.6 0 36.3 28.8 50.9 47.6 50.9 15.9 0 35.6-12.7 35.6-29.7s-13.4-20.2-13.4-20.2 11.4 33.7-22.2 33.7c-14.4 0-29-14.2-29-34.6 0-22.7 23.7-35.5 54.6-35.5 41.6 0 75 35.6 75 78.8 0 13-2.9 26.5-8.6 36.6-14.2 25.2-48.7 42.4-78.4 30.1-25.1-10.8-55.2-18.3-81.6-18.3-65.8-15.2-123.7-8.8-156.4 1.9z"/>
<path d="M246-13.5c2.8-6.1 7.6-10 12.7-14.1 7-5.6 12.9-12.7 17.2-20.6 1.9-3.4 4-7.4 7.8-8.2 6.5 21.9 4.4 45.9-3.1 67.7"/>
<g fill="none">
<path d="M164 494.3c.3-.6.3-2.5 2.6-4.9 1.7-1.8 4.3-2.8 6.6-1.9"/>
<path d="M154.1 482.7c.3-.6 0-3.1 2.6-5.2 1.9-1.6 4.7-2.2 6.8-1"/>
<path d="M428.9 494.7c.2-.6 0-2.5 2.1-5.2 1.5-2 4-3.2 6.4-2.6"/>
<path d="M417.9 484.2c.3-.6-.3-3.1 2.1-5.5 1.7-1.7 4.4-2.6 6.7-1.7"/>
<path d="M264.8 518.3c.3-.6-.3-3.1 2.1-5.5 1.7-1.7 4.4-2.6 6.7-1.7"/>
<path d="M595.5 528.8c.2-.6 0-2.5 2.1-5.2 1.5-2 4-3.2 6.4-2.6"/>
<path d="M584.4 518.3c.3-.6-.3-3.1 2.1-5.5 1.7-1.7 4.4-2.6 6.7-1.7"/>
<path d="M275.8 528.8c.2-.6 0-2.5 2.1-5.2 1.5-2 4-3.2 6.4-2.6"/>
</g>
<path fill="#f6f6f6" d="M205.6 8.8s-5.5 1.4-9.3 3.1c-3.8 1.7-12.8.4-14.2-2.1-.7-1.7.2-8 3.1-8.8 3.6-1.6 10.7-1.2 13.8 1.7 4 3.8 6.5 6 6.6 6.1z"/>
<g fill="#000" stroke="none">
<path d="m218 370c4 0 16-8 9 0-3 2-7 2-9 0z"/>
<path d="m225 357c2-3 14-9 8-2-2 2-5 3-8 2z"/>
<path d="m505 310c2 11-3 22-10 30 3-10 8-20 10-30z"/>
<path d="m173.8 486c.7.3 1.7.7 2.5 1.2s1.6 1.1 2.3 1.7c.7.7 1.3 1.4 1.8 2.2s.8 1.7 1 2.6c-.8-.6-1.4-1.2-2-1.7s-1.3-1-2-1.4-1.4-.7-2.2-1-1.5-.5-2.4-.8l1-2.8z"/>
<path d="m201 454c1 5-2 10-7 10 3-3 5-6 7-10z"/>
<path d="m150.1 462.1c1.3.1 2.5.3 3.7.8s2.3 1.1 3.2 1.8c1 .8 1.8 1.7 2.4 2.7s1.1 2.2 1 3.4c-.7-1-1.4-1.8-2.1-2.5-.8-.7-1.6-1.3-2.5-1.8s-1.9-.8-2.8-1.1c-1-.2-2-.3-2.9-.3v-3z"/>
<path d="m164.3 475.1c.6.4 1.4.8 2.1 1.3s1.4 1 2.1 1.6 1.2 1.3 1.7 2.1.8 1.7.8 2.6c-.7-.6-1.2-1.2-1.8-1.7s-1.2-.9-1.9-1.3-1.4-.7-2.1-1-1.5-.6-2.3-1l1.4-2.6z"/>
<path d="m175.8 502.4c-1.3.5-2.4.7-3.6.9-1.1.2-2.3.3-3.4.6-2.2.5-4.4 1.1-6.2 2.5 1.6-1.7 3.8-2.7 5.9-3.5 1.1-.4 2.2-.7 3.3-1.1 1.1-.3 2.2-.7 3-1.1l1 1.7z"/>
<path d="m164.2 490.5c-1.3.5-2.4.7-3.6.9-1.1.2-2.3.3-3.4.6-2.2.5-4.4 1.1-6.2 2.5 1.6-1.7 3.8-2.7 5.9-3.5 1.1-.4 2.2-.7 3.3-1.1 1.1-.3 2.2-.7 3-1.1l1 1.7z"/>
<path d="m153.4 479.7c-1.3.5-2.4.7-3.6.9-1.1.2-2.3.3-3.4.6-2.2.5-4.4 1.1-6.2 2.5 1.6-1.7 3.8-2.7 5.9-3.5 1.1-.4 2.2-.7 3.3-1.1 1.1-.3 2.2-.7 3-1.1l1 1.7z"/>
<path d="m172.7 486 3.8-1c1.3-.4 2.6-.6 3.7-1.1 1.1-.4 2.2-1.2 3.3-2 1.1-.7 2-1.7 2.9-2.6-.7 1.1-1.5 2.2-2.4 3.2s-1.9 2-3.1 2.7c-1.2.8-2.4 1.2-3.6 1.9l-3.6 1.7-1-2.8z"/>
<path d="m163.3 475 3.9-.6c1.3-.2 2.6-.3 3.8-.6s2.4-.8 3.5-1.4c1.2-.6 2.2-1.4 3.2-2.2-.8 1-1.7 2-2.8 2.8-1 .8-2.2 1.6-3.5 2.2s-2.6.9-3.8 1.4l-3.8 1.3-.5-2.9z"/>
<path d="m437.8 485.5c.8.2 1.7.5 2.6.9s1.7.9 2.5 1.5 1.4 1.3 2 2 1 1.6 1.2 2.5c-.8-.5-1.5-1-2.2-1.5s-1.4-.9-2.1-1.2-1.5-.6-2.3-.8-1.5-.3-2.5-.5l.8-2.9z"/>
<path d="m471 452c0 8-15 14-5 5 2-1 3-3 5-5z"/>
<path d="m411.8 464.1c1.3-.1 2.5 0 3.8.4 1.2.3 2.4.8 3.4 1.5s2 1.5 2.7 2.4 1.3 2.1 1.4 3.3c-.8-.9-1.5-1.6-2.4-2.3-.8-.7-1.7-1.2-2.7-1.6s-1.9-.7-2.9-.8-2-.1-3 0l-.3-2.9z"/>
<path d="m427.3 475.6 2.2 1.1c.8.4 1.5.9 2.2 1.4s1.4 1.2 1.9 1.9.9 1.6 1 2.5c-.7-.5-1.4-1-2-1.5-.6-.4-1.3-.8-2-1.1s-1.4-.6-2.2-.8-1.5-.4-2.4-.8l1.3-2.7z"/>
<path d="m441.6 501.6c-1.2.7-2.4.9-3.5 1.2l-3.3.9c-2.1.7-4.3 1.6-5.9 3.2 1.4-1.8 3.5-3.1 5.5-4.1 1-.5 2.1-1 3.2-1.4 1-.4 2.1-.9 2.8-1.4l1.2 1.6z"/>
<path d="m428.7 490.9c-1.2.7-2.4.9-3.5 1.2l-3.3.9c-2.1.7-4.3 1.6-5.9 3.2 1.4-1.8 3.5-3.1 5.5-4.1 1-.5 2.1-1 3.2-1.4 1-.4 2.1-.9 2.8-1.4l1.2 1.6z"/>
<path d="m416.9 481.3c-1.2.7-2.4.9-3.5 1.2l-3.3.9c-2.1.7-4.3 1.6-5.9 3.2 1.4-1.8 3.5-3.1 5.5-4.1 1-.5 2.1-1 3.2-1.4 1-.4 2.1-.9 2.8-1.4l1.2 1.6z"/>
<path d="m436.8 485.6 7.8-3c1.2-.5 2.5-1.2 3.5-2 1.1-.8 1.9-1.9 2.8-3-.6 1.2-1.3 2.5-2.2 3.6-1 1.1-2.1 2-3.3 2.8s-2.4 1.5-3.6 2.2l-3.6 2.2-1.4-2.8z"/>
<path d="m426.2 475.6 4.3-.9c1.4-.3 2.9-.6 4.3-1s2.8-.8 4-1.5c1.3-.7 2.3-1.7 3.4-2.8-.8 1.2-1.7 2.4-2.9 3.4s-2.6 1.7-3.9 2.3c-1.4.7-2.8 1.1-4.1 1.7l-4.2 1.7-.9-2.9z"/>
<path d="m222 403c3 5-2 18-2 19-3-7 3-13 2-19z"/>
<path d="m516 395c0 7 9 20 0 8-1-3-1-6 0-8z"/>
<path d="m306 426c5 6 8 23 5 24 0-8-4-16-5-24z"/>
<path d="m244.6 328.9c-2.4-3.2-4.3-6.8-5.5-10.6-.6-1.9-1.2-3.7-1.7-5.6l-.7-2.8c-.2-.9-.5-1.9-.6-2.9a39 39 0 01-.4-5.9c0-2 .1-3.9.3-5.8.3-3.9 1.2-7.6 1.8-11.5.1 1.9-.1 3.9-.2 5.8l-.3 5.8c-.1 1.9-.1 3.8 0 5.7s.3 3.8.7 5.6c.1.5.2.9.3 1.3s.2.9.4 1.3l.9 2.7c.6 1.8 1.2 3.6 1.9 5.4 1.4 3.5 3.2 6.7 5.5 9.6l-2.4 1.9z"/>
<path d="m319.3 327.7c.2-2.2.4-4.4.9-6.6s1.2-4.5 2.7-6.5c.7-1 1.5-1.8 2.2-2.5.7-.8 1.3-1.6 1.8-2.4 1.1-1.7 1.8-3.7 2.4-5.8.3-.7-.1-1.6-.6-2.5s-1.2-1.7-1.9-2.5c-1.4-1.6-2.9-3.3-4.2-5-1.3-1.8-2.5-3.6-3.4-5.7-.8-2-1.2-4.3-1-6.4 0 2.2.6 4.3 1.5 6.2s2.2 3.7 3.6 5.3 2.9 3.2 4.4 4.8c.7.8 1.5 1.6 2.1 2.6.3.5.6 1 .8 1.6s.3 1.4.1 2a27 27 0 01-2.2 6.4c-.5 1-1.2 2-1.9 2.9s-1.4 1.7-1.9 2.5c-1.1 1.6-1.6 3.6-1.9 5.6s-.5 4.2-.6 6.3l-2.9-.3z"/>
<path d="m307 335c3 16-8 31-5 46-7-16 4-30 5-46z"/>
<path d="m277 324c6 2 19 4 6 5-3-1-6-3-6-5z"/>
<path d="m288 319c10-3 18 4 3 2l-1-1z"/>
<path d="m296 312c4-1 7-4 11-3-2 2-8 7-11 3z"/>
<path d="m293 301c11-6 12 2 0 1z"/>
<path d="m226 227c-10 14 3 44 3 47-9-14-14-33-3-47z"/>
<path d="m310.1 219.8c2 .8 3.8 2 5.3 3.7 1.5 1.6 2.6 3.5 3.5 5.5s1.5 4.1 2.1 6.1c.2.5.3 1 .5 1.3 0 .1.1.2.1.2.2.2.5.3.7.5.9.7 1.8 1.6 2.4 2.6 1.3 2 2 4.4 2.2 6.6.2 2.3 0 4.5-.4 6.6s-.9 4.2-1.5 6.2c-.3 1-.6 2-.8 3l-.3 1.5c0 .5-.1 1 .2 1.5-.4-.4-.6-.9-.7-1.5-.1-.5-.2-1.1-.2-1.6 0-1.1 0-2.2.1-3.2.2-2.1.5-4.2.6-6.3.3-4.1.3-8.2-1.6-11.3-.5-.8-1-1.5-1.7-2.1-.2-.2-.4-.3-.5-.5l-.2-.1-.2-.2c-.1-.1-.2-.2-.2-.3-.1-.2-.2-.4-.3-.5-.3-.6-.4-1.2-.5-1.7-.5-2.1-.9-4.1-1.5-6.1-.6-1.9-1.5-3.8-2.6-5.5a18.8 18.8 0 00-4.5-4.4z"/>
<path d="m307 486c5 5-9 15-1 5v-3z"/>
<path d="m653 365c4 4 5 12 0 6-1-2-1-4 0-6z"/>
<path d="m521 196c13-6 23 6 0 0z"/>
<path d="m542 204c11-6 17 6 0 0z"/>
<path d="m563 212c13 9 3 10 0 0z"/>
<path d="m258.7 498.3c1.3-.1 2.5 0 3.8.4 1.2.3 2.4.8 3.4 1.5s2 1.5 2.7 2.4 1.3 2.1 1.4 3.3c-.8-.9-1.5-1.6-2.4-2.3-.8-.7-1.7-1.2-2.7-1.6s-1.9-.7-2.9-.8-2-.1-3 0l-.3-2.9z"/>
<path d="m274.1 509.8 2.2 1.1c.8.4 1.5.9 2.2 1.4s1.4 1.2 1.9 1.9.9 1.6 1 2.5c-.7-.5-1.4-1-2-1.5-.6-.4-1.3-.8-2-1.1s-1.4-.6-2.2-.8-1.5-.4-2.4-.8l1.3-2.7z"/>
<path d="m288.4 535.7c-1.2.7-2.4.9-3.5 1.2l-3.3.9c-2.1.7-4.3 1.6-5.9 3.2 1.4-1.8 3.5-3.1 5.5-4.1 1-.5 2.1-1 3.2-1.4 1-.4 2.1-.9 2.8-1.4l1.2 1.6z"/>
<path d="m274.5 526.1c-1.2.7-2.4.9-3.5 1.2l-3.3.9c-2.1.7-4.3 1.6-5.9 3.2 1.4-1.8 3.5-3.1 5.5-4.1 1-.5 2.1-1 3.2-1.4 1-.4 2.1-.9 2.8-1.4l1.2 1.6z"/>
<path d="m263.8 515.4c-1.2.7-2.4.9-3.5 1.2l-3.3.9c-2.1.7-4.3 1.6-5.9 3.2 1.4-1.8 3.5-3.1 5.5-4.1 1-.5 2.1-1 3.2-1.4 1-.4 2.1-.9 2.8-1.4l1.2 1.6z"/>
<path d="m604.3 519.6c.8.2 1.7.5 2.6.9s1.7.9 2.5 1.5 1.4 1.3 2 2 1 1.6 1.2 2.5c-.8-.5-1.5-1-2.2-1.5s-1.4-.9-2.1-1.2-1.5-.6-2.3-.8-1.5-.3-2.5-.5l.8-2.9z"/>
<path d="m631 482c-2 13-17 24 0 0z"/>
<path d="m578.3 498.3c1.3-.1 2.5 0 3.8.4 1.2.3 2.4.8 3.4 1.5s2 1.5 2.7 2.4 1.3 2.1 1.4 3.3c-.8-.9-1.5-1.6-2.4-2.3-.8-.7-1.7-1.2-2.7-1.6s-1.9-.7-2.9-.8-2-.1-3 0l-.3-2.9z"/>
<path d="m603.3 519.7 3.7-1.4c1.2-.5 2.5-.9 3.6-1.4 1.1-.6 2.1-1.4 3.1-2.3 1-.8 1.8-1.9 2.6-2.9-.6 1.2-1.2 2.4-2.1 3.4-.8 1-1.7 2.1-2.8 3s-2.3 1.5-3.4 2.2l-3.4 2.1-1.3-2.7z"/>
<path d="m592.7 509.7 3.8-1c1.3-.3 2.6-.6 3.7-1 1.2-.4 2.3-1 3.4-1.8 1.1-.7 2-1.6 3-2.5-.7 1.1-1.5 2.2-2.5 3.1-.9.9-2 1.9-3.2 2.5-1.2.7-2.4 1.2-3.7 1.8l-3.6 1.7-.9-2.8z"/>
<path d="m593.8 509.8 2.2 1.1c.8.4 1.5.9 2.2 1.4s1.4 1.2 1.9 1.9.9 1.6 1 2.5c-.7-.5-1.4-1-2-1.5-.6-.4-1.3-.8-2-1.1s-1.4-.6-2.2-.8-1.5-.4-2.4-.8l1.3-2.7z"/>
<path d="m608.1 535.7c-1.2.7-2.4.9-3.5 1.2l-3.3.9c-2.1.7-4.3 1.6-5.9 3.2 1.4-1.8 3.5-3.1 5.5-4.1 1-.5 2.1-1 3.2-1.4 1-.4 2.1-.9 2.8-1.4l1.2 1.6z"/>
<path d="m595.2 525c-1.2.7-2.4.9-3.5 1.2l-3.3.9c-2.1.7-4.3 1.6-5.9 3.2 1.4-1.8 3.5-3.1 5.5-4.1 1-.5 2.1-1 3.2-1.4 1-.4 2.1-.9 2.8-1.4l1.2 1.6z"/>
<path d="m583.5 515.4c-1.2.7-2.4.9-3.5 1.2l-3.3.9c-2.1.7-4.3 1.6-5.9 3.2 1.4-1.8 3.5-3.1 5.5-4.1 1-.5 2.1-1 3.2-1.4 1-.4 2.1-.9 2.8-1.4l1.2 1.6z"/>
<path d="m588.1 204.9c-4.9-5.4-11.1-9.7-18.1-12.5a49.8 49.8 0 0120.2 10.3l-2.1 2.2z"/>
<path d="m273.1 509.7 3.8-1c1.3-.3 2.6-.6 3.7-1 1.2-.4 2.3-1 3.4-1.8 1.1-.7 2-1.6 3-2.5-.7 1.1-1.5 2.2-2.5 3.1-.9.9-2 1.9-3.2 2.5-1.2.7-2.4 1.2-3.7 1.8l-3.6 1.7-.9-2.8z"/>
<path d="m283.7 519.7 3.7-1.4c1.2-.5 2.5-.9 3.6-1.4 1.1-.6 2.1-1.4 3.1-2.3 1-.8 1.8-1.9 2.6-2.9-.6 1.2-1.2 2.4-2.1 3.4-.8 1-1.7 2.1-2.8 3s-2.3 1.5-3.4 2.2l-3.4 2.1-1.3-2.7z"/>
<path d="m284.7 519.6c.8.2 1.7.5 2.6.9s1.7.9 2.5 1.5 1.4 1.3 2 2 1 1.6 1.2 2.5c-.8-.5-1.5-1-2.2-1.5s-1.4-.9-2.1-1.2-1.5-.6-2.3-.8-1.5-.3-2.5-.5l.8-2.9z"/>
<path d="m283-27.1c2 9.5 0 20.03-5 28.34-2 2.87-7 7.42-8 7.39 8-9.91 11-23.23 13-35.73z"/>
<path d="m127.1 14.4c.4.1.8.4 1 .7.2.4.3.8.3 1.3s-.1.9-.3 1.3-.6.8-.9 1.1c-1.4 1.2-3.2 1.4-3.7 2.2-.8.9-1.4 2.3-2.1 3.7-.4.7-.7 1.4-1.3 2.2a4.26 4.26 0 01-3.1 1.7v-3c.1 0 .2 0 .3-.1s.3-.2.5-.4c.4-.4.8-1 1.2-1.6.8-1.2 1.5-2.7 2.9-3.9.4-.3.8-.6 1.2-.8.3-.1.4-.2.6-.2l.6-.2c.7-.2 1.4-.4 1.9-.7.3-.2.5-.3.7-.5s.3-.5.5-.8c.3-.7.4-1.5-.3-2z"/>
<path d="m205.6 281.5c.2 1.7.6 3.3 1.1 4.9a121.2 121.2 0 005.4 14.1l-2.8 1a178 178 0 01-2.4-9.9l-.9-5c-.3-1.7-.4-3.4-.4-5.1z"/>
<path d="m203 180c-4 7-11 28-12 26 0-10 4-20 12-26z"/>
<path d="m277.5-40.9c.2 2.6-.6 5.4-2 7.7-.7 1.2-1.5 2.2-2.3 3.3l-.9 1.2-.4.4c-.5.5-1 1-1.5 1.4-2 1.7-3.9 3.4-5.8 5.1s-3.7 3.5-5.4 5.3c-1.7 1.9-3.2 3.8-4.3 6-.5 1.1-.9 2.1-1 3.2-.2 1.2-.3 2.4-.3 3.6-.1 2.4.3 4.7 1.5 6.9 1.1 2.1 2.9 4 4.8 5.8-2.4-1-4.8-2.4-6.5-4.7-.8-1.1-1.5-2.4-2-3.7-.4-1.4-.6-2.8-.7-4.1-.1-1.4.1-2.8.2-4.1.2-1.4.7-2.9 1.3-4.1 1.3-2.5 3-4.6 4.8-6.6 3.6-3.9 7.8-7.1 11.7-10.4.5-.4 1-.8 1.4-1.2l1.3-1.3c.9-.9 1.8-1.8 2.6-2.8 1.7-2.1 2.9-4.3 3.5-6.9z"/>
<path d="m272-16.5c0 6.77-5 13.67-12 14.1 4-4.15 8-8.8 12-14.1z"/>
<path d="m127 21.8c1 7.1-7 6 0 0z"/>
<path d="m176.2-3.1c.7.4 2.1.7 3.3.7 1.3.1 2.6.1 3.9 0 2.7-.1 5.4-.4 8-1 .6-.1 1.3-.3 2.1-.4.7-.1 1.4-.2 2.2-.2 1.4-.1 2.9 0 4.3.2 2.8.4 5.6 1.5 7.7 3.4-2.6-1-5.2-1.6-7.9-1.7-1.3-.1-2.6 0-3.9.2-.6.1-1.3.2-1.9.4s-1.2.4-1.9.6c-2.8.7-5.5 1.2-8.3 1.4-1.4.1-2.8.2-4.3.1s-3-.2-4.7-1.1l1.4-2.6z"/>
<path d="m247.4-12.9c-.5 1.1-.9 2.2-1.2 3.4s-.5 2.4-.6 3.6-.2 2.5-.1 3.7c0 1.2.1 2.5.2 3.8-.8-1.1-1.3-2.3-1.6-3.6s-.5-2.6-.6-4c-.1-1.3 0-2.7.1-4 .2-1.4.5-2.7 1-4l2.8 1.1z"/>
<path d="m281.9 11.8c-.5 1.3-1.2 2.4-1.9 3.4-.8 1-1.6 2-2.5 2.8s-1.9 1.6-2.9 2.3-2.1 1.3-3.3 1.7c.8-1 1.6-1.9 2.4-2.7.8-.9 1.6-1.8 2.3-2.7s1.4-1.9 1.9-2.8c.5-1 1-2 1.3-3l2.7 1z"/>
<path d="m188.5 1.7c1.3 0 1.4 1.1 1.4 3.8 0 .7 0 1.4-.1 2-.3 1.7-.1 2.8-1 2.8-1 0-2.8-1.2-3.2-3-.1-.6-.2-1.2-.2-1.8-.1-2.6 1.8-3.8 3.1-3.8z"/>
<path d="m169 4.8c-3 4.81-5 10.6-6 16.3-1 1.8-1-2.9-1-3.6 0-5 2-10.75 7-12.7z"/>
<path d="m193 36.4c2.6-2.6 3.4-6.1 4.4-9.6.9-3.5 1.9-7.2 4.2-10.5 1.1-1.6 2.6-3 4.3-4.1s3.5-1.9 5.4-2.3c3.7-1 7.5-.9 11.2-.3v.5c-3.6.5-7.2 1.1-10.4 2.3s-6 3.1-7.9 5.8c-2 2.7-3.1 6-4.5 9.4-.7 1.7-1.4 3.4-2.4 5-1.2 1.6-2.6 3-4.3 3.8z"/>
<path d="m179 6.8c-4 2.6-7 5.5-11 8.3 0-2.1 2-4.7 4-6.1 2-1.61 5-2.42 7-2.2z"/>
<path d="m203-2.7c3 4.3 7 6.86 11 9.9-2 1.04-5-.95-7-2.4-3-1.78-5-4.477-4-7.5z"/>
<path d="m154 14c0-3.2 3-6.43 7-6.1-1 2.5-4 4.5-6 5.9l-1 .1z"/>
<path d="m190-10.6c3-4.3 10-4 14-1.3 1 1.1 4 2.64 3 4.3-5-2.01-10-4.6-16-3.1z"/>
<path d="m216 60.5c2 1.6 2 6.3-1 6.8-1-2.2 0-4.9 1-6.8z"/>
<path d="m222 67.8c2 1.2 1 5.9-1 6.1-1-1.9-1-4.5 1-6.1z"/>
<path d="m225 75.5c2 .8 1 4.6-1 4.3-1-1.2-1-3.8 1-4.3z"/>
<path d="m227 82.9c3 .1 1 5-1 3-1-1.3 0-2.3 1-3z"/>
<path d="m174 38.1c1-.1 2 1.5 2 2.9 0 .7-1 1.7-1 1.7-2-.5-3-2.2-2-3.5 0-.4 0-.7 1-1.1z"/>
<path d="m178 42.4c2-.3 3 1.8 2 2.9-1 .7-2-.1-3-1 0-.8 1-1.4 1-1.9z"/>
<path d="m182 46.8c1-.8 3 1.6 1 2.3 0 .5-2 0-2-.8 0-.7 1-.8 1-1.5z"/>
<path d="m182.3 10.3c-1.3.2-2.5.5-3.8.7-1.3.3-2.5.5-3.7.9l-.2-.3c1-.8 2.2-1.5 3.3-2.2s2.2-1.3 3.4-2l1 2.9z"/>
<path d="m480 241c7 6 14 13 20 20-9-4-17-11-20-20z"/>
<path d="m462 240c-2 11-18 13-5 4 2-1 3-2 5-4z"/>
<path d="m216.8 102.8c3.7.1 7.4.3 11.1.3 3.6.1 7.3-.1 10.7-.9 1.7-.4 3.4-1 5-1.8.8-.4 1.6-.8 2.3-1.4.7-.5 1.4-1.1 2.1-1.7 2.7-2.4 4.9-5.4 7.3-8.3a41.2 41.2 0 01-6.3 9.3c-.6.7-1.3 1.3-2.1 1.9-.7.6-1.6 1.1-2.4 1.7a25 25 0 01-5.3 2.3c-3.7 1.1-7.5 1.4-11.2 1.5s-7.4 0-11.1 0l-.1-2.9z"/>
<path d="m265 63.7c1-6.2 7-19.7 5-6-1 2.4-2 4.7-5 6z"/>
<path d="m263.1 94.7c.8 1.5 1.2 3 1.4 4.6a18.48 18.48 0 01-1.2 9.3c-.6 1.5-1.4 2.9-2.5 4.1 0-1.6.1-3.2.2-4.6.1-1.5.3-2.9.5-4.4s.4-2.9.7-4.4c.2-1.6.4-3.1.9-4.6z"/>
<path d="m267.6 111.6c.4 1.5.3 3 .1 4.5a16.2 16.2 0 01-3.5 8.1c-.9 1.2-2 2.2-3.4 3 .4-1.5.9-2.9 1.4-4.2s1-2.6 1.6-3.9c.5-1.3 1.1-2.5 1.7-3.8.6-1.1 1.3-2.4 2.1-3.7z"/>
<path d="m269.5 120.4c.9 1.5 1.2 3.4 1 5.2s-.8 3.6-1.6 5.1c-.8 1.6-1.9 3-3 4.3-1.2 1.3-2.5 2.4-4 3.3.6-1.7 1.4-3.2 2.1-4.7l2.3-4.3c.7-1.4 1.4-2.8 1.9-4.3.6-1.3 1-2.8 1.3-4.6z"/>
<path d="m351 295c6-2 22-4 8 2-3 0-6 0-8-2z"/>
<path d="m364 284c3-1 20-3 12 1-4 1-8 1-12-1z"/>
<path d="m380 277c2-2 20-3 13 0-5 2-9 2-13 0z"/>
<path d="m394 267c6-5 25-6 9 0-3 0-6 1-9 0z"/>
</g>
<g stroke-width="2">
<path stroke-width="4" d="M194.4 158.3s3.1-6.1 5.6-15.9c2.5-9.8 4.7-27.5 4.7-27.5s27.3 2.4 59.2-1.3c31.9-3.8 60.7-9.6 60.7-9.6s3.9 21.1 5.6 26.4c2.8 8.9 6.5 14.4 6.5 14.4s-41.4 9.7-72.1 12.1c-30.6 2.4-70.2 1.4-70.2 1.4z"/>
<path d="M192 158.1l2.2-5.7s43.4 1.3 70.2-.7c26.8-2 73.4-12.4 73.4-12.4l2.1 6s-45.1 10.4-74.3 12.9c-29.4 2.4-73.6-.1-73.6-.1z"/>
<path d="M352.5 123.7l-23.8 4.4s-.9 1.8.8 5.8c1.6 4 3.4 4.3 3.4 4.3l19.6-14.5z"/>
<path d="M348.9 109.4l-23.8 4.4s-.9 1.8.8 5.8c1.6 4 3.4 4.3 3.4 4.3l19.6-14.5z"/>
<path d="M179.4 139.9l21.9 10.7s1.7-.9 2.6-5.1c.9-4.2-.3-5.5-.3-5.5l-24.2-.1z"/>
<path d="M181.7 124.7l21.9 10.7s1.7-.9 2.6-5.1c.9-4.2-.3-5.5-.3-5.5l-24.2-.1z"/>
<path d="M315.3 156.4l2.4-23.8s-1.4-1.4-5.5-.8c-4.1.5-4.9 2.2-4.9 2.2l8 22.4z"/>
<path d="M292 160.8l2.4-23.8s-1.4-1.4-5.5-.8c-4.1.5-4.9 2.2-4.9 2.2l8 22.4z"/>
<path d="M217.5 166.2l6.5-23s-1.2-1.6-5.3-1.8-5.2 1.3-5.2 1.3l4 23.5z"/>
<path d="M265.7 164l4.9-23.4s-1.3-1.5-5.4-1.4c-4.2.1-5.1 1.6-5.1 1.6l5.6 23.2z"/>
<path d="M240.8 165.7l6.5-23s-1.2-1.6-5.3-1.8c-4.2-.2-5.2 1.3-5.2 1.3l4 23.5z"/>
<path d="M202 120.2l1.5-5.8s36-.9 62.7-2.9c26.8-2 60.7-9 60.7-9l1.9 6.2s-32.1 6.8-61.4 9.3c-29.3 2.5-65.4 2.2-65.4 2.2z"/>
<path d="M219.9 108.2l-6.5 23s1.2 1.6 5.3 1.8 5.2-1.3 5.2-1.3l-4-23.5z"/>
<path d="M266 105.9l-4.9 23.4s1.3 1.5 5.4 1.4c4.2-.1 5.1-1.6 5.1-1.6l-5.6-23.2z"/>
<path d="M285.7 101.8l-2.8 23.9s1.4 1.3 5.6.8c4.1-.6 4.8-2.2 4.8-2.2l-7.6-22.5z"/>
<path d="M241.2 106.5l-5.1 23.5s1.3 1.5 5.4 1.4 5.1-1.7 5.1-1.7l-5.4-23.2z"/>
<path d="M306.9 98.2l7.5 22.3s-1 1.7-5.1 2.4-5.3-.6-5.3-.6l2.9-24.1z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 22 KiB

16
charges/plough.svg Normal file
View file

@ -0,0 +1,16 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="#d7374a" stroke="#000" viewBox="50 50 200 200">
<metadata source="http://wappenwiki.org/images/a/a7/New_Jersey.svg" license="https://creativecommons.org/licenses/by-nc-sa/3.0"/>
<g id="plough" stroke-width="3" transform="translate(30 25) scale(0.17)">
<rect width="11.1" height="41" x="189" y="424" ry="5.55"/>
<path d="M540 322c-40 15-50 65-70 87-10 22-20 45-10 46 10 2 20-16 30-37s20-57 40-77c20-18 54-11 60-15s7-10 0-11-30 2-50 7z"/>
<path d="M560 364c0 3-10 7-10 11h-40c-10 0-10-2-10-5 0-4 0-6 10-6zm-30 35v11h-40c-10 0-10-2-10-5s0-6 10-6z"/>
<path d="M590 336c-40 10-60 58-70 78-20 20-40 41-20 44 10 3 20-14 30-33 10-20 30-54 60-70 20-16 56-8 60-9s6-7 0-10-40-3-60 0z"/>
<path d="M420 438c-10 96-30 118-60 127 20-21 30-46 30-80l10 2v-48z"/>
<path d="M500 425l-10-6c10 70-30 112-80 148 70-2 120-34 140-85-20 12-30 11-50 9 10-26 10-47 0-66z"/>
<path d="M570 438c-30-8-60-9-90-10-30-2-60 7-100 7-100 1-190 0-190 0-10 0-10 14 0 14h210c30 0 60-2 90 0 20 2 50 8 70 13 10 1 20-20 10-24z"/>
<path fill="#000" stroke="none" d="M524 500c-5 16-32 40-45 46 19-5 45-35 45-46z"/>
<path fill="#000" stroke="none" d="M401 491c-2 28-20 61-31 68 16-10 33-50 31-68z"/>
<path fill="none" d="M450 532l20 23"/>
<path fill="none" d="M460 540c20-12 30-27 40-49"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

137
charges/porcupine.svg Normal file
View file

@ -0,0 +1,137 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="#d7374a" stroke="#000" viewBox="50 50 200 200">
<metadata source="http://wappenwiki.org/images/f/ff/Maupeou.svg" license="https://creativecommons.org/licenses/by-nc-sa/3.0"/>
<g id="porcupine" stroke-width=".3">
<path d="M93.88 122.72s-.1-.04-.62-.03c-.52.02-.93.32-1.06.44-.12.12-.45.64-.35.72.09.1.97-.25 1.38-.26.4-.02.6.03.73.07.13.04-.08-.94-.08-.94z"/>
<path d="M94.1 124.25s-.12-.04-.66.05a2 2 0 00-1.03.6c-.12.15-.38.63-.28.71.12.08 1-.29 1.4-.36.4-.07.63-.04.77-.03.14.01-.2-.97-.2-.97z"/>
<path d="M97 125.67c-.12.07-.31.18-.61.48s-.8 1.1-.92 1.1c-.14 0-.2-.54-.19-.72 0-.18.1-.71.48-1.1.38-.4.48-.31.48-.31s.88.48.76.55z"/>
<path d="M78.8 120.85s-.12.03-.49.39c-.38.36-.48.85-.5 1.04 0 .17.1.78.22.78.13 0 .57-.84.86-1.12.28-.27.47-.38.6-.44.1-.06-.7-.65-.7-.65z"/>
<path d="M79.97 121.84s-.12.04-.46.47a1.8 1.8 0 00-.37 1.14c.01.18.13.71.25.7.14-.01.55-.86.8-1.2.27-.32.44-.46.56-.54.13-.07-.78-.57-.78-.57z"/>
<path d="M83.08 120.98c-.04.12-.11.34-.12.75-.03.42.15 1.35.04 1.44-.1.1-.5-.27-.62-.41a1.9 1.9 0 01-.38-1.14c.03-.54.15-.55.15-.55s.98-.22.93-.1z"/>
<path d="M125.33 122.72s-.1-.04-.62-.03c-.51.02-.93.32-1.05.44-.13.12-.45.64-.36.72.1.1.98-.25 1.38-.26.4-.02.6.03.73.07.13.04-.08-.94-.08-.94z"/>
<path d="M125.55 124.25s-.11-.04-.65.05c-.53.1-.92.47-1.04.6-.11.15-.38.63-.27.71.11.08.99-.29 1.39-.36.41-.07.63-.04.77-.03.15.01-.2-.97-.2-.97z"/>
<path d="M128.45 125.67c-.11.07-.31.18-.6.48s-.8 1.1-.93 1.1c-.14 0-.2-.54-.18-.72 0-.18.09-.71.47-1.1.38-.4.48-.31.48-.31s.89.48.76.55z"/>
<path d="M110.76 121.2s-.1-.05-.62-.04c-.52.02-.93.32-1.06.44-.12.12-.44.64-.35.72.09.1.98-.25 1.38-.26.4-.01.6.03.73.07.13.03-.08-.94-.08-.94z"/>
<path d="M110.97 122.71s-.11-.04-.65.05c-.53.09-.92.47-1.04.6-.12.15-.38.63-.28.7.12.09 1-.28 1.4-.35.4-.07.63-.04.77-.03.16.01-.2-.97-.2-.97z"/>
<path d="M113.88 124.14c-.12.07-.31.18-.61.48s-.8 1.1-.92 1.1c-.14 0-.2-.54-.18-.72 0-.18.09-.71.47-1.1.38-.4.48-.31.48-.31s.88.48.76.55z"/>
<path d="M121.56 108.52c-.69 2.35-.8 4.57 1.31 5.02.3.05.38.48.46.77.12.42-.05.88-.32 1.23-.26.34-.62.62-.95.9a8.52 8.52 0 00-2.83 5.56c0 .69-.5 1.77-.86 1.93-.44.2-.17.15-.63.13-.49-.03-.81.23-1.32.34-.35.1-.77.2-1.04-.04-.37-.34-.6-.67-1.09-.25-.16.14-.28.34-.63.15-.03-.02-.3-.27-.52-.36-.21-.08-.41-.06-.44-.06-.21-.02-.25-.4-.25-.4s-.24.26-.49.33c-.25.08-.69.1-.78-.05-.37-.95-.78-1-.78-1 .11-.05-.07-.54.39-.71-.03-.24-.01-.41-.31-.87.02-.15.35-.65.88-.48.38.13 1-.27 1.4-.28.73 0 .87.33 1.3.39v-.01c.35-.08.74-.07 1.09.04.13.05.3.1.39 0l.04-.1c.15-.33.42-.61.47-.97.06-.38.26-.7.36-1.08.13-.43.12-.9.15-1.34.08-1.03.4-2.03.9-2.91-.38-.37-.88-.8-1.36-1.05-.55-.27-1.18-.34-1.8-.45-1.24-.22-2.47-.05-3.64-.54a6.86 6.86 0 01-2.8-2.02 2.52 2.52 0 01-.51-1.29c1-1.02 2.5-1.6 3.89-1.95 4-1.04 8.13-2 12.24-1.6"/>
<path d="M96.18 108.95c-.29.9-1.15 1.45-1.94 1.95-1.2.77-2.28 1.47-3.37 2.38-1.46 1.21-2.6 2.88-4.34 3.61-.5.21-.93.3-1.16.79-.24.26-.2.67-.13 1.02s.19.73.03 1.06c-.2.3-.55.38-.91.38-.5 0-.89-.12-.97.54-.02.2.02.43-.38.53-.03 0-.4-.02-.63.06-.22.09-.34.23-.37.26-.17.12-.44-.14-.44-.14s0 .36-.15.59c-.14.23-.46.52-.63.48-.9-.46-1.25-.23-1.25-.23.06-.12-.4-.35-.17-.78-.17-.18-.28-.3-.82-.45-.08-.13-.16-.71.35-.94.37-.17 1.2-.97 1.4-1.51a2 2 0 01.28-.89c.28-.41.55-.54 1-.77.27-.13.57-.24.82-.42.84-.55 1.3-1.42 1.79-2.27.43-.77.87-1.53 1.37-2.29a6.6 6.6 0 011.17-1.47c.65-.56 1.53-.86 2.1-1.52"/>
<path stroke-width=".2" d="M83.78 108.9c-.05-.11-.05-.46-.27-.72l-.25-.3-.04-.07c-.01-.08.1-.13.17-.14.18-.03.34-.08.5-.14.03-.01.07-.02.09-.06.05-.05.02-.12 0-.2a2.84 2.84 0 00-.25-.53c-.06 0-.1-.05-.13-.1l-.06-.17c-.08-.15-.26-.2-.42-.25l-.27-.11a.22.22 0 01-.11-.12c-.02-.06.02-.13.08-.16s.13-.03.2-.05c.16 0 .3-.03.47-.05.03 0 .06-.02.06-.05v-.06a1.81 1.81 0 00-.28-.45c-.13-.13-.24-.2-.27-.38a.34.34 0 00-.11-.02c-.07-.11.09-.24.11-.38.01-.09-.04-.17-.1-.25a7.68 7.68 0 00-.5-.63c-.2-.22-.4-.5-.28-.79.08-.2.3-.32.28-.52-.02-.25-.4-.34-.42-.6-.02-.15.14-.29.15-.46.01-.19-.24-.49-.43-.53-.12-.04-.2.07-.33.08-.13.01-.25-.06-.37-.12.2.04.37-.17.57-.24.09-.03.2-.03.27-.09l.08-.07.36-.2c.52-.4.2-.84.52-1.42.3-.57-.21-1.32-.58-1.86-.1-.16-.24-.29-.38-.42-.75-.62-1.03-.56-1.36-.47l.08-.02c-.25-.01-.46.18-.7.22-.09 0-.17 0-.25.02-.23.04-.4.23-.54.41.13-.16.16-.48-.06-.56a.7.7 0 00-.3-.01c-.15.02-.27.05-.41.06h-.04a.02.02 0 01-.02-.03c-.08-.11-.08-.3-.2-.34-.09-.04-.2.02-.27-.04-.07-.04-.18-.36-.17-.44a1.8 1.8 0 00-.74.09c.06-.24.35-.35.57-.45.26-.13.5-.33.66-.58a.46.46 0 01-.34-.08l-.14-.12c-.07-.05-.16-.04-.25-.04a3.1 3.1 0 00-.7.14c.08-.22.26-.37.4-.55.16-.17.25-.41.16-.62a6.16 6.16 0 00-.46-.02c-.06-.2 0-.42.1-.6s.25-.34.4-.47c.18-.18.48-.35.4-.58.34-.36 2.04-1.1 3.58-1.33.91-.14 3.06-1.4 3.97-1.53.89-.12 2.65-1.06 3.57-1.43 1.2-.48 5.44-2.37 10.28-3 8.98-1.18 16 .17 22.66 4.65a16.38 16.38 0 016.22 7.84c1.33 3.35 1.51 4.16 2.74 7.49.52 1.39.74 3.15.66 4.63-.03.46.43.52.88.67.44.15 1.19-.08 1.59.13.7.38.98 1.27.95 2.06 0 .8-.52 2.35-.52 3.14 0 2.37-.27 3.45.12 5.13.32 1.59.65 2.52.5 3.53a2.4 2.4 0 01-.97 1.6c-.31.24-.6.48-.97.64-.43.2-.16.15-.62.13-.5-.02-.81.23-1.32.35-.36.1-.77.2-1.05-.05-.36-.33-.58-.67-1.08-.24-.16.14-.28.33-.63.15-.03-.02-.3-.28-.52-.37-.22-.08-.41-.06-.45-.06-.2-.02-.24-.4-.24-.4s-.24.26-.5.33c-.24.08-.68.1-.77-.04-.37-.96-.79-1.01-.79-1.01.12-.05-.06-.53.4-.7-.03-.25-.02-.42-.31-.88.02-.15.35-.64.88-.47.38.13 1-.28 1.4-.29.73 0 1.12.33 1.56.4.2.1.81.1 1 .16.22.06.47.05.6-.12.1-.15.08-.35.05-.53a5.2 5.2 0 01.05-2.12c.18-.68-.13-1.54-.19-2.23-.06-.81 0-1.63-.46-2.3-.48-.76-.1-.81-.54-1.3-.87-.96-3.04-1.68-4.3-2.02-1.4-.4-2.95-.33-4.24-1-1.19-.62-1.8-1.52-2.55-2.61-1.75-.27-3.28.02-5 .38-3.38.71-8.01 2.04-11.4 1.4.45.5.85 1.02 1.04 1.62.4 1.27-.23 2.37-.48 3.68s.1 2.8.45 4.37c.26 1.06.38 2.52.24 3.53a2.4 2.4 0 01-.97 1.6c-.3.24-.87.48-1.23.64-.43.2-.93.36-1.42.48-.36.1-.77.2-1.05-.05-.37-.33-.58-.67-1.08-.24-.16.14-.29.33-.63.15-.04-.02-.3-.28-.52-.37-.22-.08-.41-.06-.45-.06-.2-.02-.24-.4-.24-.4s-.24.26-.5.33c-.25.08-.68.1-.78-.04-.36-.96-.78-1.01-.78-1.01.12-.05-.07-.53.4-.7-.03-.25-.02-.42-.32-.88.03-.15.36-.64.89-.47.38.13 1-.28 1.39-.29.74 0 .87.33 1.31.4.27.03.99.26 1.1.14.05-.06.06-.15.07-.23.06-.25.2-.48.28-.73.1-.3.1-.6.08-.89-.02-.43-.29-.9-.41-1.3-.1-.32-.22-.63-.31-.95-.18-.6-.12-1.26-.1-1.88 0-.45.07-.9-.03-1.33a6.75 6.75 0 00-.59-1.64c-1.35-1.95-2.86-1.4-3.78-3.84-1.86-.11-6.33.54-9.7-.7z"/>
<path stroke-width=".2" d="M83.78 108.9s-.57-.25-1.12-.38c-.47-.1-.88.04-1.18-.34-.09-.12-.18-.25-.32-.3-.14-.06-.33 0-.34.16a1.85 1.85 0 01-.67-.35c-.01.18-.06.36-.14.5a2.02 2.02 0 01-1.41-.91c-.06.11-.1.46-.12.59-.2-.03-.4-.12-.56-.26-.14-.11-.25-.27-.41-.35s-.42-.04-.46.13c-.3-.1-.35-.32-.66-.32-.46 0-.46.16-.76.2-.83.1-1-.3-2.17.07-.38.11-1.35-.19-1.91.03-.5.22-1 .16-1.23.22-.24.06-.5.03-.76.01a3.54 3.54 0 01-.8-.15c-.28-.13-.45-.34-.21-.62.07-.08.2-.11.3-.11 1 0 1.92-.26 2.57-.34.5-.06.8-.23 1.31-.22.26.02.54 0 .7-.2.15-.16.37-.43.35-.67-.01-.36-.45-.67-.8-.66-.19.02-.35.1-.52.15-.45.15-.95-.07-1.4.06-.33.1-.94.04-1.49.2 0 0-.37.12-.72.16-.44.04-.87.11-1.3.2-.4.1-.9.07-1.31.02-1.33-.18-2.07-.42-2.66-1.38a4.7 4.7 0 01-.5-1.13c-.06-.2-.09-.41-.15-.61-.05-.2-.1-.58 0-.78.07-.13.18-.24.28-.34.33-.28.85-.05 1.24.08.06.03.1.05.16.04.1-.01.15-.1.21-.17.38-.45.94-.45 1.22-.52 1.15-.27 1.67-1.52 2.6-2.1.9-.57 1.22-.6 1.48-1.55.13-.43.44-.67.66-1.08.32-.6 1.06-.84 1.62-1.23.45-.3.8-.96 1.23-1.3a7.1 7.1 0 011.55-.8c.95-.3 1.52-1.18 2.5-1.31.08.23-.23.4-.4.57-.15.15-.3.3-.4.47s-.17.4-.11.6l.46.02c.1.21 0 .45-.15.62-.15.18-.33.34-.41.56.23-.07.46-.12.7-.14a.4.4 0 01.25.03c.06.04.1.08.14.13.09.08.22.1.34.08-.17.24-.4.45-.66.58-.23.11-.51.2-.57.44.23-.09.49-.12.74-.09-.01.08.1.4.17.45.08.05.19 0 .27.03.12.05.12.25.2.35.01.01.01.02.03.02h.03l.4-.05c.1-.02.21-.04.31 0 .22.1.19.42.06.57.14-.18.31-.38.54-.41l.24-.03c.26-.03.46-.23.72-.22l-.08.03a2.65 2.65 0 013 .88c.35.54.07 1.3-.23 1.87s-.46 1.02-.98 1.41l-.36.2-.08.08c-.08.05-.18.05-.27.09-.2.07-.36.26-.57.24.1.06.24.13.37.12.13-.02.2-.1.33-.09.18.05.44.34.43.53-.01.16-.17.31-.15.48.02.24.4.33.43.58.02.2-.21.35-.3.53-.1.28.11.56.3.78.17.21.34.42.49.64.06.06.12.16.1.25 0 .14-.17.25-.11.38l.11.02c.03.18.14.24.27.38.11.14.2.29.27.45.02.01.02.03.02.06l-.07.04c-.15.03-.31.05-.47.06a.38.38 0 00-.2.05c-.06.03-.1.1-.08.16.01.04.07.08.11.11.08.05.18.08.27.12.16.05.36.09.42.25.03.05.04.1.06.16.02.05.07.1.13.1.1.19.18.34.25.54.02.07.04.14 0 .2a.25.25 0 01-.1.06c-.15.06-.31.1-.49.14-.08 0-.18.05-.17.13 0 .03.03.05.04.07l.25.3c.22.2.2.55.26.68z"/>
<path fill="#f6f6f6" stroke-width=".25" d="M72.86 99.39s.46.08 1.6-.7c-.73-.17-1.05-.65-1.55-.62-.1 0-.3.24-.33.65-.03.42.28.67.28.67z"/>
<g fill="#000" stroke="none">
<path d="M64.6 101.85c.22.2.49.24.77.38s.53.32.73.56c.2.25.34.54.37.87 0 .08 0 .16-.02.24a.84.84 0 01-.06.24.5.5 0 01-.17.18c-.03.03-.08.04-.11.05-.05 0-.08 0-.12-.02.08 0 .13-.05.18-.1a.5.5 0 00.07-.35l-.02-.1-.02-.09a1.7 1.7 0 00-.37-.67c-.17-.21-.38-.38-.6-.56l-.35-.25c-.12-.13-.23-.24-.28-.38z"/>
<path d="M64.45 103.75c.12.01.2.02.28.06.08.02.15.05.22.09a1.14 1.14 0 01.39.33c-.1.06-.2.07-.3.06a.84.84 0 01-.28-.08.67.67 0 01-.21-.19.61.61 0 01-.1-.27z"/>
<path d="M67.28 104.05a.67.67 0 01.57-.31c.06 0 .14 0 .25.04a.51.51 0 01-.34.34.48.48 0 01-.21.02c-.1-.02-.19-.03-.27-.1z"/>
<path d="M66.05 101.97c.1-.06.2-.1.28-.12l.24-.07.25-.03h.3a.56.56 0 01-.2.26.81.81 0 01-.28.13.7.7 0 01-.31 0c-.1-.05-.2-.1-.28-.17z"/>
<path d="M69.38 103.15a1.02 1.02 0 00.44-.37l.03-.04h.07a2.81 2.81 0 001.13-.14l.38-.14c-.08.12-.18.2-.3.29a1.64 1.64 0 01-1.24.2l.1-.03a.8.8 0 01-.3.2c-.1.03-.21.05-.32.03z"/>
<path d="M70.95 101.13l.23-.01h.18l.04-.05a.3.3 0 01.1-.1c.1-.07.22-.06.3-.06.17.02.3.09.43.09a.7.7 0 00.4-.1.51.51 0 01-.4.3.68.68 0 01-.26 0l-.2-.04c-.06-.01-.12-.01-.14.01-.02.01-.04.01-.06.05a.42.42 0 01-.15.1.23.23 0 01-.16-.03l-.1-.05-.2-.11z"/>
<path d="M74.4 104.2c.1.2.23.32.38.48.07.08.14.16.2.26.05.1.08.23.08.36a.95.95 0 01-.1.33c-.04.1-.11.19-.17.27-.13.16-.25.3-.37.48 0-.22.1-.41.2-.6.1-.18.17-.35.18-.51.01-.16-.07-.31-.17-.49-.06-.08-.1-.17-.15-.27a.45.45 0 01-.08-.3z"/>
<path d="M75.47 101.38c.13-.08.25-.14.38-.18l.37-.14.37-.14.37-.16a.79.79 0 01-.27.33 1 1 0 01-.38.2 1.74 1.74 0 01-.84.09z"/>
<path d="M70.78 98.5a2.25 2.25 0 01.2-1.2 1.73 1.73 0 01.21-.37c.17-.23.4-.43.66-.55a1.75 1.75 0 01.84-.22l-.1.03c.1-.07.18-.1.28-.15l.29-.09c.2-.06.4-.07.6-.08l.3.01.15.01.14.03c.1 0 .2.04.3.07l.27.1-.29-.02-.29-.02c-.18 0-.38.02-.55.04a2.73 2.73 0 00-1 .36.13.13 0 01-.1.03h0c-.1 0-.23.02-.35.06s-.23.07-.34.12c-.22.1-.42.26-.58.44a3.46 3.46 0 00-.64 1.4z"/>
<path d="M72.11 97.17a.69.69 0 00-.09.36c.01.11.07.23.14.26.07.04.18.01.3-.02.11-.04.23-.1.37-.14l.39-.08c.12-.02.26-.03.4-.03.27 0 .55.05.78.2a2.87 2.87 0 00-.77.01l-.38.07-.37.08-.38.12c-.07.01-.13.03-.22.03s-.17-.02-.24-.07a.35.35 0 01-.13-.2.51.51 0 01-.02-.23.72.72 0 01.22-.36z"/>
<path d="M72.87 99.52h-.32c-.1.02-.22.04-.32.09.08-.08.17-.15.27-.2a.5.5 0 01.16-.09l.17-.07.04.27z"/>
<path d="M71.17 99.47a1 1 0 01-.15-.37 1.46 1.46 0 01-.04-.39c.02-.12.03-.26.07-.39a.65.65 0 01.23-.32l-.03.37-.01.35c0 .26-.01.49-.07.75z"/>
<path d="M73.12 98.22c.13-.01.02.25.03.5 0 .21.13.43.04.44-.09 0-.3-.07-.34-.24-.01-.06-.02-.2-.04-.25 0-.26.19-.44.31-.45z"/>
<path d="M75.55 98.45a.66.66 0 01-.5-.03c-.07-.03-.14-.08-.2-.13s-.12-.13-.14-.23c.1 0 .17.03.24.04l.2.08.2.1c.07.05.14.1.2.17z"/>
<path d="M80.8 96.46l-.19.18-.18.14a1 1 0 01-.2.11c-.07.04-.15.09-.24.1.01-.1.05-.18.1-.24.06-.07.12-.14.2-.19.08-.04.16-.08.24-.1.1-.03.18-.03.28 0z"/>
<path d="M80.27 97.5l.36-.1.37-.06.4.01c.12.03.26.06.36.15l-.38.06-.37.05a2.1 2.1 0 01-.38 0 .97.97 0 01-.36-.12z"/>
<path d="M82.48 99.01c.04.12 0 .24-.05.33a.64.64 0 01-.26.25c-.1.05-.2.09-.3.1a1 1 0 01-.33.01c.07-.1.16-.15.25-.2.1-.06.18-.11.26-.14l.23-.15a.8.8 0 00.2-.2z"/>
<path d="M80.92 99.05a.57.57 0 01.29-.28l.33-.15c.1-.05.2-.1.32-.14a3 3 0 00.33-.17.78.78 0 01-.21.33c-.1.1-.2.16-.33.2a1.3 1.3 0 01-.37.11c-.12.04-.23.05-.36.1z"/>
<path d="M102.28 105.24a4 4 0 01.43 1.21 4 4 0 01-.03 1.29l-.06.32-.08.32c-.07.22-.2.42-.31.59-.11.18-.23.36-.29.53-.05.17 0 .3.12.44l-.27.23a.74.74 0 01-.17-.36.8.8 0 01.05-.4c.09-.23.23-.4.35-.58s.25-.33.33-.52l.09-.3.08-.3c.09-.42.16-.83.11-1.26-.04-.41-.2-.82-.35-1.2z"/>
<path d="M118.17 108.35a13.8 13.8 0 00-2.13-2.76c-.2-.2-.42-.4-.65-.58a4.45 4.45 0 00-.74-.47c-.26-.12-.54-.24-.76-.46a.93.93 0 01-.24-.38.64.64 0 01.01-.43.6.6 0 000 .42c.05.14.14.25.24.36.22.2.5.29.77.41.28.12.53.28.77.45a10.55 10.55 0 011.95 1.83c.38.45.74.93 1.07 1.42l-.3.19z"/>
<path d="M92.87 105.98c.03.63.1 1.26.2 1.89a7.43 7.43 0 00.57 1.74l-.3.16a4.72 4.72 0 01-.3-.94c-.07-.32-.1-.63-.14-.95-.05-.62-.07-1.27-.03-1.9z"/>
<path d="M130.6 110.73a2.4 2.4 0 001.01.7c.19.08.4.14.59.2.2.08.41.13.62.24a2.67 2.67 0 01-1.35-.12 1.8 1.8 0 01-.58-.39c-.15-.18-.27-.4-.29-.63z"/>
<path d="M116.9 110.98a.35.35 0 01.27-.07c.1.01.18.06.25.13s.13.15.15.24c.02.1.02.2-.04.29l-.2-.15-.14-.13-.14-.14-.16-.17z"/>
<path d="M115.5 109.58c.1-.02.2 0 .29.03.1.04.16.1.23.16.07.07.11.15.15.23.03.1.04.19.02.3-.1-.04-.17-.09-.24-.13a.77.77 0 01-.17-.17c-.06-.05-.1-.11-.15-.18a.95.95 0 01-.13-.24z"/>
<path d="M100.43 112.06a2.86 2.86 0 00.33.77l.2.37c.07.13.14.27.19.43a1.27 1.27 0 01-.4-.26c-.1-.1-.21-.23-.28-.36-.08-.14-.14-.3-.15-.46a.77.77 0 01.1-.49z"/>
<path d="M100.78 117.07c.02-.02.05 0 .07 0l.06.06a1.12 1.12 0 01.11.37c.04.16.05.31.05.47 0 .17 0 .33-.02.48-.03.16-.06.32-.13.48a1.87 1.87 0 01-.15-.47 2.19 2.19 0 01-.05-.47c0-.17 0-.33.03-.48a1.79 1.79 0 01.07-.34c0-.04 0-.07-.04-.1z"/>
<path d="M90.22 111.5c.03.1.04.18 0 .29a.7.7 0 01-.14.25c-.14.14-.3.24-.44.35l-.1.08-.09.09-.17.2-.33.4c-.22.28-.46.58-.71.84-.26.26-.55.51-.89.66.25-.27.46-.55.68-.85l.32-.44c.1-.15.22-.28.33-.43.12-.14.23-.29.37-.43l.2-.2c.04-.03.08-.05.11-.09a.77.77 0 01.13-.08c.17-.1.33-.16.47-.25.07-.05.13-.1.17-.17.06-.04.08-.13.1-.22z"/>
<path d="M117.39 114.28a.8.8 0 01.35-.08c.12-.01.23 0 .34.01.22.03.41.08.62.14-.2 0-.42 0-.62.04-.2.03-.4.09-.5.2l-.2-.3z"/>
<path d="M80.64 98.37a3.5 3.5 0 01.9-.34l.45-.12c.14-.05.28-.1.4-.22a.64.64 0 01-.3.4c-.16.1-.32.15-.48.18-.16.04-.31.07-.47.09-.17 0-.33.02-.5 0z"/>
<path d="M80.25 98.13l-.3.1a1.01 1.01 0 01-.64.02.67.67 0 01-.3-.15l.32-.06.3-.02h.3c.1.02.23.04.32.1z"/>
<path d="M79.9 104.32c.11.07.2.13.3.16.09.04.17.05.3.08.05.03.13.05.2.1s.08.12.1.18c.05.12.06.2.16.3-.07.01-.13-.02-.19-.06s-.1-.08-.13-.12a.74.74 0 00-.1-.1.28.28 0 00-.1-.04.58.58 0 01-.16-.05.53.53 0 01-.18-.1c-.11-.1-.2-.22-.2-.35z"/>
<path d="M77.69 104.05c.11.04.22.1.31.15.1.04.18.09.28.12l.13.04c.05 0 .12.02.18.04s.13.07.17.14c.03.06.05.15 0 .2-.01-.06-.06-.1-.1-.12-.04-.02-.07-.02-.12-.02h-.16a.64.64 0 01-.2-.03.87.87 0 01-.3-.21c-.09-.1-.14-.2-.19-.31z"/>
<path d="M76.32 104.75c.08.08.15.11.24.14l.26.07c.08.02.2.05.3.15s.12.2.12.3l-.25-.14c-.07-.03-.15-.04-.25-.06a.81.81 0 01-.3-.15c-.07-.07-.14-.2-.12-.31z"/>
<path d="M79.72 102.35a3.39 3.39 0 01.61-.05 1 1 0 01.32.08c.1.05.2.12.24.23-.12-.02-.21-.02-.3-.02l-.29-.01-.3-.05c-.1-.06-.2-.1-.27-.18z"/>
<path d="M77.62 102.75a.98.98 0 01.33-.05 1.53 1.53 0 01.9.3c-.11.02-.22.02-.33.02-.1 0-.2-.02-.31-.04-.1-.03-.2-.05-.3-.1a.66.66 0 01-.29-.13z"/>
<path d="M92.17 123.67a2 2 0 01.38-.21 1.73 1.73 0 01.63-.15l.22.01c.14.01.29.04.42.1v.03c-.15 0-.28 0-.42.02-.14.01-.27.02-.4.05-.28.04-.54.11-.83.15z"/>
<path d="M92.46 125.4a2.37 2.37 0 01.74-.42.54.54 0 01.22-.05l.22-.01c.15 0 .29.01.43.06v.02l-.42.06a1.7 1.7 0 00-.39.09c-.26.07-.52.17-.8.24z"/>
<path d="M95.6 127.06c.02-.14.08-.28.13-.41.06-.13.13-.26.21-.38l.14-.18.16-.15c.11-.09.24-.17.38-.21l.01.02-.29.3-.26.3c-.16.25-.3.48-.48.7z"/>
<path d="M95.41 124.99c0-.1.01-.2.04-.29a.67.67 0 01.36-.46c.1-.04.2-.06.3-.07l-.08.03c.17-.1.37-.14.55-.15.19-.02.36 0 .52 0s.32-.02.48-.04c.17-.02.33-.06.5-.07l.01.04c-.14.11-.3.2-.47.25-.17.06-.35.08-.53.1-.17 0-.35 0-.5.03-.14.02-.3.05-.42.12l-.02.01-.05.02a.66.66 0 00-.16.04c-.05.02-.08.06-.12.1a.36.36 0 00-.06.14l-.03.18-.32.02z"/>
<path d="M96.18 123.47c-.14.1-.29.15-.45.19l-.48.06c-.16.02-.32.03-.48.02-.16 0-.33-.02-.5-.05h0l-.03-.01-.06-.01h-.07a.3.3 0 00-.14.03l-.15-.31a.7.7 0 01.27-.07h.14c.04.01.08.01.15.04l-.04-.02a5.86 5.86 0 00.91.08h.46c.15 0 .31-.02.47 0v.05z"/>
<path d="M94.58 122.08c.07.07.13.14.16.22a1.05 1.05 0 01.08.68h-.03a1.38 1.38 0 00-.15-.38c-.03-.06-.08-.1-.11-.14a.41.41 0 00-.14-.08l.2-.3z"/>
<path d="M96.37 124.48c.09-.05.2-.09.3-.09.1 0 .21.04.3.08.1.06.19.14.24.23.05.1.08.2.05.32l-.04.02-.23-.15-.2-.12-.2-.11a1.01 1.01 0 00-.1-.07c-.04-.03-.09-.05-.14-.1h.02z"/>
<path d="M94.33 123.37c.03 0 .05 0 .06.02l.04.02.07.05a.77.77 0 01.27.34c.03.09.07.18.08.26l.04.25-.03.01a2.88 2.88 0 00-.25-.41.5.5 0 00-.18-.14c-.03-.01-.05-.03-.09-.03l-.04-.02h-.03s0 0 0 0l.06-.35z"/>
<path d="M78.14 122.69a2.39 2.39 0 01.37-.77 1 1 0 01.15-.16c.05-.05.1-.1.17-.14.11-.08.24-.16.38-.2v.02l-.29.28-.28.3c-.16.22-.3.45-.5.67z"/>
<path d="M79.5 123.78a2.18 2.18 0 01.42-.99l.15-.16c.1-.09.22-.18.36-.24v.02l-.26.33-.24.33c-.14.23-.26.47-.42.71z"/>
<path d="M82.96 122.95a2.38 2.38 0 01-.27-.81v-.22l.01-.22c.03-.14.06-.29.14-.41h.02v.83c.03.27.09.54.1.84z"/>
<path d="M81.44 121.53a.93.93 0 01-.16-.23.76.76 0 01-.08-.29.7.7 0 01.04-.31.6.6 0 01.18-.24l-.04.06c.07-.19.19-.35.31-.48l.4-.34c.12-.1.23-.22.34-.35l.32-.39.03.01c-.03.18-.09.35-.18.5-.1.15-.2.29-.33.41-.12.13-.26.24-.35.36-.1.11-.18.24-.23.38l-.01.02-.03.04-.1.13c-.02.05-.02.1-.02.15 0 .05.02.1.05.16l.09.15-.23.26z"/>
<path d="M81.01 119.87a1.4 1.4 0 01-.2.44l-.31.37c-.12.11-.23.23-.36.33-.13.1-.25.2-.4.3v.01l-.03.01-.04.03c-.03 0-.04.02-.06.04a.41.41 0 00-.08.12l-.32-.14a.72.72 0 01.15-.23l.1-.1.13-.06h-.04a4.33 4.33 0 001.06-.85c.12-.1.22-.21.36-.3l.04.03z"/>
<path d="M78.89 119.9c.09 0 .18.02.26.05a1.18 1.18 0 01.5.46l-.02.02a1.23 1.23 0 00-.36-.18c-.06-.02-.13-.02-.19-.02s-.11 0-.15.03l-.04-.37z"/>
<path d="M81.82 120.52c.02-.1.09-.2.17-.27a.86.86 0 01.29-.15.7.7 0 01.32.01c.1.04.2.1.25.2l-.02.04-.26.04-.22.03-.23.05-.13.02c-.06.01-.1.03-.17.03z"/>
<path d="M79.55 121.02l.06-.02.05-.01.08-.01h.16c.1 0 .2.04.27.08a1.32 1.32 0 01.43.3l-.02.03-.23-.1c-.08-.02-.16-.04-.23-.04a.46.46 0 00-.22.01c-.04.01-.07.01-.1.04 0 0-.02 0-.03.02l-.01.01s-.01.01 0 0l-.2-.3z"/>
<path d="M123.62 123.67a2 2 0 01.38-.21 1.73 1.73 0 01.63-.15l.22.01c.14.01.29.04.43.1l-.02.03a4.79 4.79 0 00-.82.07c-.26.04-.53.11-.82.15z"/>
<path d="M123.92 125.4a2.37 2.37 0 01.75-.42.5.5 0 01.22-.05l.21-.01c.15 0 .3.01.43.06v.02c-.14.01-.28.04-.41.06-.14.02-.27.04-.4.09-.26.07-.52.17-.8.24z"/>
<path d="M127.05 127.06a3.09 3.09 0 01.34-.8l.14-.17.16-.15c.12-.09.24-.17.38-.21l.01.02-.29.3-.26.3c-.15.25-.3.48-.48.7z"/>
<path d="M126.86 124.99c0-.1.02-.2.04-.29a.67.67 0 01.37-.46c.09-.04.2-.06.28-.07l-.07.03c.18-.1.37-.14.56-.15.18-.02.35 0 .51 0s.33-.02.49-.04c.16-.02.32-.06.5-.07v.04c-.13.11-.3.2-.47.25-.17.06-.34.08-.53.1-.17 0-.34 0-.5.03-.14.02-.3.05-.42.12l-.02.01-.05.02a.66.66 0 00-.16.04.35.35 0 00-.11.1.36.36 0 00-.07.14l-.02.18-.33.02z"/>
<path d="M127.65 123.47c-.14.1-.3.15-.45.19-.16.03-.32.05-.49.06-.16.02-.32.03-.48.02-.16 0-.32-.02-.5-.05h0l-.03-.01-.06-.01h-.06a.3.3 0 00-.14.03l-.15-.31a.7.7 0 01.26-.07h.14c.05.01.08.01.15.04l-.03-.02a5.86 5.86 0 00.9.08h.46c.15 0 .31-.02.48 0v.05z"/>
<path d="M126.05 122.08c.07.07.12.14.16.22l.08.23c.02.15.02.3 0 .45h-.04a1.38 1.38 0 00-.15-.38c-.03-.06-.08-.1-.11-.14a.41.41 0 00-.14-.08l.2-.3z"/>
<path d="M127.82 124.48c.09-.05.2-.09.3-.09.1 0 .22.04.3.08.1.06.2.14.24.23.06.1.08.2.06.32l-.05.02-.23-.15-.2-.12c-.07-.03-.12-.08-.2-.11a1.01 1.01 0 00-.1-.07c-.04-.03-.09-.05-.13-.1h0z"/>
<path d="M125.8 123.37c.03 0 .04 0 .05.02l.05.02.07.05a.77.77 0 01.26.34c.04.09.07.18.08.26l.05.25-.04.01a2.88 2.88 0 00-.25-.41.5.5 0 00-.17-.14c-.04-.01-.06-.03-.1-.03l-.04-.02h-.02s-.01 0 0 0l.05-.35z"/>
<path d="M109.05 122.14a2 2 0 01.38-.21 1.73 1.73 0 01.63-.15l.22.01c.14.01.29.04.43.1l-.02.03-.4.02a2.7 2.7 0 00-.41.05c-.28.04-.54.11-.83.15z"/>
<path d="M109.34 123.85a2.37 2.37 0 01.75-.41.46.46 0 01.21-.05l.22-.01c.15 0 .29.01.43.06v.02l-.42.06c-.13.02-.26.04-.39.09-.26.08-.51.17-.8.24z"/>
<path d="M112.47 125.53c.02-.14.08-.28.13-.41.06-.13.13-.26.21-.38l.14-.18.16-.15c.11-.09.24-.17.38-.21l.01.02-.29.3-.26.3c-.15.24-.3.48-.48.71z"/>
<path d="M112.3 123.46c0-.1 0-.2.03-.29a.67.67 0 01.37-.46c.09-.04.2-.06.28-.07l-.07.03c.18-.1.37-.14.56-.15.18-.02.35 0 .51 0s.33-.02.49-.04c.16-.02.32-.06.5-.07v.04c-.14.11-.3.2-.47.25-.17.06-.34.08-.53.1-.17 0-.34 0-.5.03-.14.02-.3.05-.42.12l-.02.01-.05.02a.66.66 0 00-.16.04l-.11.1a.36.36 0 00-.07.14l-.03.18-.32.02z"/>
<path d="M113.06 121.94c-.13.1-.28.15-.44.19l-.49.06c-.16.02-.32.03-.48.02-.16 0-.32-.02-.5-.05h0l-.03-.01-.06-.01H111a.3.3 0 00-.13.03l-.15-.3a.7.7 0 01.26-.08h.14c.04.01.08.01.15.04l-.04-.02a5.86 5.86 0 00.91.09c.15 0 .31 0 .46-.02h.47v.06z"/>
<path d="M111.47 120.55c.06.07.12.14.16.22l.08.23c.02.15.02.3 0 .45h-.04a1.1 1.1 0 00-.15-.38.46.46 0 00-.11-.14.41.41 0 00-.14-.08l.2-.3z"/>
<path d="M113.25 122.95c.09-.05.2-.09.3-.09.1 0 .22.04.3.08.1.06.2.14.24.23.05.1.08.2.05.32l-.04.02-.23-.15-.2-.12c-.07-.03-.12-.08-.2-.11a1.01 1.01 0 00-.1-.07c-.04-.03-.09-.05-.13-.1h0z"/>
<path d="M111.21 121.84l.06.02.05.02c.03.01.04.03.06.05a.77.77 0 01.27.35c.03.08.07.17.08.25l.05.25-.04.01a2.88 2.88 0 00-.25-.41.5.5 0 00-.17-.14c-.04-.01-.06-.03-.1-.03l-.04-.02h-.03s0 0 0 0l.06-.35z"/>
</g>
<g stroke-width=".115">
<path d="M79.33 91.2a3.37 3.37 0 00.79-2.32 4.75 4.75 0 00-.75-2.47 6.31 6.31 0 00-1.96-1.87c-.78-.5-1.63-.88-2.53-1.23-.05-.02-.08-.08-.05-.12 0-.05.05-.07.1-.07a7.45 7.45 0 015.1 2.8 5.5 5.5 0 011.03 2.91 4.32 4.32 0 01-.94 3.02"/>
<path d="M77.86 91.35s0-.01 0 0c.15-.39.22-.8.22-1.22a4.35 4.35 0 00-.78-2.46c-.24-.38-.53-.73-.84-1.1a.1.1 0 01.01-.15c.04-.02.07-.04.1-.01.48.18.88.5 1.22.87a4.88 4.88 0 011.24 2.8 3.9 3.9 0 01-.2 1.62"/>
<path d="M85.05 95.32c.01 0 .01 0 0 0 .63-.06 1.24-.16 1.85-.3a11.63 11.63 0 003.46-1.46c.54-.33 1.06-.7 1.6-1.08.05-.04.12-.02.14.02a.1.1 0 010 .12 6.6 6.6 0 01-1.38 1.45 10.99 10.99 0 01-5.58 2.26"/>
<path d="M86.44 97.7l2.4.32c.79.1 1.58.15 2.37.17a14.67 14.67 0 004.67-.7.1.1 0 01.13.07c.01.05 0 .1-.04.12a7.1 7.1 0 01-2.27.99c-.8.2-1.65.3-2.48.34-.82.05-1.65.01-2.48-.03-.82-.06-1.63-.15-2.44-.26"/>
<path d="M83.13 99.94c.01 0 .01 0 0 0a9.3 9.3 0 001.74.75 16.32 16.32 0 003.8.72c.66.07 1.31.14 1.98.27.06.01.1.07.08.11-.01.05-.05.07-.08.08-.67.12-1.33.15-2 .16a24 24 0 01-2.03-.08 11.15 11.15 0 01-3.96-1.11"/>
<path d="M91.24 101.8s0 0 0 0a9.3 9.3 0 001.73.74 16.32 16.32 0 003.81.73c.66.06 1.31.13 1.98.26.06.01.09.07.08.11-.01.05-.05.07-.08.09-.67.11-1.34.14-2 .16a24 24 0 01-2.03-.08 11.15 11.15 0 01-3.97-1.12"/>
<path d="M85.73 103.36c.78.29 1.57.54 2.38.75a25.63 25.63 0 004.92.79c.84.06 1.67.08 2.52.12.06 0 .1.05.1.1s-.04.09-.09.1c-.84.2-1.69.29-2.55.31a21.06 21.06 0 01-7.62-1.2"/>
<path d="M91.04 87.38c.01 0 .01 0 0 0a35.76 35.76 0 006.74-4.3 36.63 36.63 0 002.98-2.69c.95-.94 1.85-1.93 2.76-2.94a.1.1 0 01.14-.01c.03.03.04.09.02.12a23.25 23.25 0 01-2.46 3.26 34.49 34.49 0 01-6.17 5.38 34.1 34.1 0 01-3.54 2.1"/>
<path d="M100.22 87.82c.01 0 .01 0 0 0 1.88-.4 3.76-.8 5.62-1.25 1.86-.45 3.7-.98 5.5-1.61a31.97 31.97 0 005.2-2.35 27.34 27.34 0 004.65-3.3c.05-.03.1-.03.14.01a.1.1 0 010 .14 20.15 20.15 0 01-4.48 3.7 31.96 31.96 0 01-5.24 2.57 49.3 49.3 0 01-5.54 1.77c-1.87.5-3.76.9-5.63 1.33"/>
<path d="M100.45 89.81a72.76 72.76 0 0018.51-4.8 115 115 0 005.87-2.58c.04-.03.11 0 .14.04.02.05 0 .1-.04.13a49.95 49.95 0 01-5.71 2.99 69.41 69.41 0 01-6.03 2.33 63.17 63.17 0 01-12.6 2.9"/>
<path d="M103.28 92.08a47.33 47.33 0 0011.68-.4 46.7 46.7 0 005.73-1.26 66.4 66.4 0 005.59-1.87c.05-.03.11 0 .12.05.03.05 0 .1-.04.13-1.75.93-3.6 1.67-5.49 2.29a47.13 47.13 0 01-11.7 2.16c-1.98.1-3.98.07-5.97-.1"/>
<path d="M113.9 95.07s.01 0 0 0c1.76-.07 3.5-.15 5.25-.25 1.73-.09 3.47-.21 5.2-.37a59.95 59.95 0 0010.26-1.88c.06-.01.1.02.13.07.01.05-.01.1-.06.11a31.84 31.84 0 01-5.02 1.58c-1.72.4-3.45.68-5.2.92s-3.5.4-5.24.53c-1.75.14-3.5.22-5.25.3"/>
<path d="M124.4 98.16a66.33 66.33 0 007.4.01c1.24-.07 2.47-.18 3.7-.34l3.7-.48c.05 0 .1.04.1.1.02.04-.02.09-.06.1-1.2.4-2.42.67-3.65.9a57.4 57.4 0 01-3.72.53 50.75 50.75 0 01-3.76.25c-1.26.03-2.51.02-3.78-.05"/>
<path d="M127.5 101.47a103.96 103.96 0 006.52.54c1.09.05 2.18.07 3.27.07s2.19 0 3.3.02c.05 0 .1.05.1.1s-.04.1-.08.1c-1.09.2-2.19.33-3.28.4a63.72 63.72 0 01-6.63.05 52.4 52.4 0 01-3.3-.27"/>
<path d="M126.8 103.48s0 .02 0 0a34.44 34.44 0 004.81.97c.82.1 1.64.16 2.46.2.83.03 1.65.05 2.49.1.06 0 .1.05.09.1 0 .05-.03.08-.08.1-.82.19-1.67.28-2.5.33a26.52 26.52 0 01-5.07-.29 22.7 22.7 0 01-2.48-.53"/>
<path d="M118.57 92.8s.01 0 0 0c1.34-.25 2.66-.53 3.97-.8a74.1 74.1 0 003.9-.98 31.36 31.36 0 007.34-3.21c.04-.02.11-.01.13.03.03.05.01.1-.02.13-1.02.9-2.2 1.63-3.42 2.25a28 28 0 01-3.79 1.57c-1.29.45-2.61.8-3.93 1.13-1.33.33-2.65.6-3.97.88"/>
<path d="M120.33 96.42a38.4 38.4 0 0010.34-.32c1.14-.18 2.28-.41 3.43-.64.05-.01.1.02.11.08.01.04 0 .09-.06.11-1.08.46-2.2.8-3.35 1.07a35.6 35.6 0 01-7.02.85 30.3 30.3 0 01-3.54-.13"/>
<path d="M114.03 89.28a57.66 57.66 0 0012.88-4.48c1.37-.66 2.71-1.37 4.07-2.09.05-.02.12 0 .14.05.02.05.01.1-.04.13a34.31 34.31 0 01-3.9 2.47c-1.35.74-2.73 1.4-4.15 2.02a47.77 47.77 0 01-8.78 2.89"/>
<path d="M99.26 86.21a85.1 85.1 0 0011-5.6l3.54-2.15c.05-.03.1-.01.14.03.02.05 0 .1-.03.13-1.04.9-2.16 1.73-3.3 2.52a62.36 62.36 0 01-10.92 6.01"/>
<path d="M104.37 88.21s.01 0 0 0a98.97 98.97 0 007-4.32 84.6 84.6 0 003.34-2.42l3.28-2.52c.04-.03.1-.02.13.03.04.03.03.09 0 .12a37.12 37.12 0 01-3.02 2.86 64.19 64.19 0 01-6.66 4.98 62.24 62.24 0 01-3.55 2.16"/>
<path d="M106.2 97.2a52 52 0 006.47 1.82c1.1.23 2.21.42 3.33.57 1.11.16 2.23.28 3.35.43.06.01.1.06.1.12a.12.12 0 01-.1.09c-1.13.1-2.27.07-3.41 0a41.31 41.31 0 01-10.05-2.06"/>
<path d="M98.67 99.47c1.09.36 2.2.68 3.3.99a56.87 56.87 0 006.76 1.38l3.45.5c.06 0 .09.05.08.1a.12.12 0 01-.1.1c-1.17.07-2.33.04-3.5-.06-1.16-.1-2.32-.24-3.49-.42a43.48 43.48 0 01-3.45-.67 43.53 43.53 0 01-3.39-.93"/>
<path d="M115.09 101.99c.94.23 1.88.41 2.83.6a47.71 47.71 0 005.75.66c.96.06 1.93.1 2.9.17.06 0 .1.04.1.1 0 .04-.04.08-.08.1-.97.16-1.96.23-2.94.27a42.41 42.41 0 01-5.9-.37c-.97-.14-1.94-.31-2.9-.54"/>
<path d="M98.96 97.18a96.36 96.36 0 0115.27-3.53c1.72-.24 3.45-.44 5.18-.52.06 0 .1.05.1.1s-.03.09-.08.1c-1.7.32-3.41.6-5.1.94-1.7.32-3.4.67-5.07 1.07a123.26 123.26 0 00-9.96 2.8"/>
<path d="M95.5 94.08a21.44 21.44 0 014.45-2.56 29.1 29.1 0 014.86-1.56 45.68 45.68 0 0110.01-1.16c.06 0 .1.04.1.1 0 .05-.03.1-.07.1-1.66.26-3.32.47-4.96.74-1.65.27-3.28.59-4.88 1.01-1.6.44-3.16.97-4.65 1.65-1.5.69-2.93 1.5-4.22 2.5"/>
<path d="M92.36 90.52s.02 0 0 0a56.43 56.43 0 019.48-2.85c1.62-.33 3.24-.6 4.88-.78a39.1 39.1 0 014.92-.25c.06 0 .1.04.1.1a.1.1 0 01-.1.1c-1.61.2-3.23.4-4.84.67a66 66 0 00-14.05 3.96"/>
<path d="M111.5 103.31c1.14.43 2.29.8 3.45 1.16a52.79 52.79 0 003.52.93c1.18.28 2.38.51 3.58.7l3.62.55c.06 0 .09.05.08.11a.1.1 0 01-.1.08 28.3 28.3 0 01-3.69-.12c-1.23-.13-2.44-.3-3.65-.53a43.11 43.11 0 01-7.14-1.94"/>
<path d="M106.04 99.94a37 37 0 018.66-1.6 40 40 0 014.39-.05c1.46.06 2.92.23 4.35.54.05 0 .09.07.08.11a.11.11 0 01-.1.08 70.2 70.2 0 00-4.34-.1 41.51 41.51 0 00-8.57.9c-1.4.3-2.8.66-4.16 1.1"/>
<path d="M86.61 88.27a52.18 52.18 0 008.67-5.76l2.7-2.23c.04-.04.1-.04.13 0 .04.04.04.1 0 .13-.73.92-1.55 1.78-2.41 2.58a46.33 46.33 0 01-5.57 4.36c-.99.65-2 1.25-3.04 1.82"/>
<path d="M83.1 91.06c.93-.84 1.82-1.66 2.7-2.51.9-.86 1.74-1.74 2.55-2.65.8-.92 1.54-1.89 2.19-2.92l.47-.78.43-.8.4-.84c.13-.27.25-.56.37-.84.03-.04.08-.06.14-.04a.1.1 0 01.06.11 12.55 12.55 0 01-1.33 3.52 22.97 22.97 0 01-2.12 3.13c-.78.99-1.63 1.91-2.5 2.8a81.44 81.44 0 01-2.68 2.6"/>
<path d="M94 87.89a171.37 171.37 0 007.47-5.4c1.22-.92 2.42-1.9 3.61-2.86 1.2-.96 2.37-1.95 3.6-2.9a.1.1 0 01.13 0c.03.04.02.1 0 .13a55.08 55.08 0 01-3.31 3.24 124.65 124.65 0 01-7.14 5.9c-1.24.95-2.5 1.83-3.77 2.72"/>
<path d="M90.05 95.88c1.2-.04 2.4-.14 3.59-.25a61.58 61.58 0 007.1-1.1l3.54-.78c.05 0 .1.03.11.09.01.04 0 .09-.06.11a27.8 27.8 0 01-3.45 1.2c-1.17.32-2.35.6-3.55.85a48.22 48.22 0 01-3.61.6c-1.2.16-2.43.26-3.65.32"/>
<path d="M93.4 92c1.03.4 2.3.26 3.56.24a138.03 138.03 0 007.55-.52c1.25-.13 2.5-.25 3.77-.35.06 0 .1.04.1.1 0 .04-.02.09-.07.1-1.23.32-2.47.58-3.72.77a84.54 84.54 0 01-9.49.94c-.65 0-1.36-.05-2.03-.3"/>
<path d="M90.1 99.2s.01 0 0 0a80.03 80.03 0 0011.46-.78c1.9-.26 3.79-.6 5.67-1 1.88-.39 3.75-.85 5.62-1.3.05-.02.1.02.12.06.01.05-.01.1-.06.12a47.9 47.9 0 01-5.53 1.73 79.06 79.06 0 01-5.68 1.2 69.8 69.8 0 01-11.57 1"/>
<path d="M82.2 90.27s0-.01 0 0a5.29 5.29 0 001.8-3.36 5 5 0 00-.11-1.96 7.61 7.61 0 00-.76-1.9c-.02-.05-.01-.12.04-.14.03-.02.08-.01.11.01a4.4 4.4 0 011.2 1.84 5.8 5.8 0 01.33 2.23 5.91 5.91 0 01-.56 2.21c-.33.7-.8 1.32-1.38 1.84"/>
<path d="M81.1 90.73s0-.01 0 0a7.95 7.95 0 00-.52-6 11.4 11.4 0 00-1.13-1.8c-.04-.04-.02-.1.02-.13a.1.1 0 01.12 0c.62.42 1.12.98 1.54 1.62a8.4 8.4 0 011.27 4.33c.02.77-.1 1.54-.32 2.3"/>
<path d="M85.68 92.98c1-.39 2-.77 2.96-1.16.98-.4 1.92-.85 2.84-1.34a16.18 16.18 0 004.83-3.94.1.1 0 01.14-.02c.03.04.04.08.02.13-.5.96-1.2 1.83-1.99 2.56-.8.75-1.68 1.4-2.61 1.96a24.6 24.6 0 01-2.88 1.5 60 60 0 01-2.96 1.25"/>
<path d="M88.4 106.24c1.69.3 3.35.52 5.03.74a106.64 106.64 0 0010.14.76c1.7.06 3.4.07 5.1.11.06 0 .1.05.1.1a.1.1 0 01-.09.1c-1.69.2-3.4.29-5.1.32a84.4 84.4 0 01-10.24-.45 86 86 0 01-5.08-.66"/>
<path d="M121.86 100.84a53.53 53.53 0 008.81-2.17 55.57 55.57 0 004.24-1.63c1.4-.58 2.78-1.24 4.16-1.9.04-.02.11 0 .13.05.03.05.01.1-.03.13a32.57 32.57 0 01-4 2.29 47.32 47.32 0 01-8.62 3.23 46.3 46.3 0 01-4.5.99"/>
<path d="M79.4 94.02s.01 0 0 0a10.05 10.05 0 003.95-1.1c.6-.32 1.2-.7 1.72-1.15.54-.45 1.04-.95 1.53-1.47a.1.1 0 01.14 0c.03.04.05.09.02.12a6.26 6.26 0 01-1.27 1.82 9.5 9.5 0 01-6.01 2.82"/>
<path d="M81.56 92.2c.02 0 .02 0 0 0a10.1 10.1 0 003.47-3.1c.46-.62.85-1.32 1.15-2.05.3-.72.55-1.48.76-2.28a.1.1 0 01.12-.07c.05.02.07.05.08.1a7.2 7.2 0 01-.37 2.47 10.38 10.38 0 01-2.65 4.28 10 10 0 01-2.05 1.54"/>
<path d="M97.66 101.3a35.69 35.69 0 0012.42 4.15c1.45.2 2.93.32 4.4.4.06 0 .09.05.09.1a.1.1 0 01-.1.1c-1.48.16-2.97.14-4.47.02a34.23 34.23 0 01-8.75-1.98 30.6 30.6 0 01-4.1-1.88"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 30 KiB

15
charges/sabre2.svg Normal file
View file

@ -0,0 +1,15 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="#d7374a" stroke="#000" viewBox="50 50 200 200">
<metadata source="http://wappenwiki.org/images/1/1c/Astrakhan.svg" license="https://creativecommons.org/licenses/by-nc-sa/3.0"/>
<g id="sabre2" stroke-width="3" transform="translate(46 22) scale(0.13)">
<path d="M580 618l-13.3-41.8s-147.1 85.4-363.2-15.3c-26.7 25.4-71.9 46.1-94.6 48.5C305.6 773.5 580 618 580 618h0z"/>
<path d="M669.3 539l13.3 9.2-2.4 14.8s-90.5 42.6-90.2 42.2c-5 .7-10.9-3.1-13.6-9.4-2.7-6-1.9-13 1.9-16.4-.1.2 91-40.4 91-40.4h0z"/>
<path d="M713.6 569.7c5.3-5.9 7.3-15.4 3.9-23.4-3.1-7.4-8.6-15.5-16.3-16.7-8.9-1.5-28.5 8.3-38.9 12.8l.3.5c3.4 1 6.8 5 8.9 9.9 1.9 4.4 2.9 9.4 1.7 12.8l.3.7c5.6-2.4 17.5-8.1 22.8-3.5 5.3 4.8.9 7.7 4.5 10.3 3 2.2 8.7 1.2 12.8-3.4h0z"/>
<path d="M599.6 638c-2.2-7-13-34.5-16.9-43.2h0c-4-8.7-17.7-34.9-21.6-41.1-7.6-11.5-18.2-19.5-30.3-14-8.1 3.7-10.7 11-7.6 17.6 2.1 4.5 6 7.6 10.8 5.5 2.6-1.2 2.7-2.3 3.7-3.9 1.2-1.9 1-3 3.2-4 3.6-1.7 7 1.7 8.9 3.9 2.2 2.6 5.9 9.5 8.1 14.4 5.3 10.9 8.4 29.2 8.4 29.2h0s11.8 14.3 16.6 25.5c2.2 4.9 5 12.3 5.6 15.6.4 2.9.8 7.6-2.9 9.2-2.3 1.1-3 .3-5.2-.1-1.9-.4-2.8-.9-5.3.2-4.8 2.2-5 7.2-2.9 11.7 3 6.6 10.2 9.5 18.4 5.7 11.8-5.5 12.7-18.9 9-32.2h0z"/>
<path fill="none" d="M557.5 631.8c-6.3-7.6-14.9-5.3-14.9-5.3s-90.8 40.6-213.9 45.4c-80.3 3.1-173.6-35.4-219.6-62.4"/>
<path fill="none" d="M588.1 575.4c4-.4 8.4 4.3 11 10.2 2.5 5.6 3.2 12 .4 14.9"/>
<path fill="none" d="M603.1 568.5c4.1-.4 8.4 4.3 11 10.2 2.5 5.6 3.3 12 .4 14.9"/>
<path fill="none" d="M618.3 561.7c4-.4 8.4 4.3 11 10.2 2.5 5.5 3.3 12 .5 14.9"/>
<path fill="none" d="M633.6 554.7c4-.4 8.4 4.3 11 10.2 2.5 5.6 3.3 12 .4 14.9"/>
<path fill="none" d="M648.6 547.8c4-.4 8.4 4.4 11 10.2 2.5 5.6 3.3 12 .5 14.9"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

73
charges/snake.svg Normal file
View file

@ -0,0 +1,73 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="#d7374a" stroke="#000" viewBox="50 50 200 200">
<metadata source="http://wappenwiki.org/images/3/36/Colbert.svg" license="https://creativecommons.org/licenses/by-nc-sa/3.0"/>
<g id="snake" stroke-width=".3">
<g fill="#F6F6F6" stroke-width=".25">
<path d="M87.49 63.6c-.2.32-.32 1.14-.24 1.81.11.92.45 1.86.98 2.28 0-.22-.23-.99-.16-1.62.13-1.14.65-1.61.91-1.8"/>
<path d="M88.69 63.67c-.14.31-.14 1.06.02 1.65.22.81.64 1.6 1.17 1.91-.03-.2-.33-.86-.35-1.43-.03-1.03.37-1.53.58-1.73"/>
<path d="M89.58 71.24c-.1-.17-.15-.72-.1-1.09.07-.5.26-.9.56-1.12 0 .12-.14.53-.11.87.06.62.42 1.09.56 1.19"/>
<path d="M90.8 71.22c-.12-.11-.29-.5-.33-.79-.06-.39-.01-.74.15-.97.03.09.02.43.13.68.19.45.57.72.7.76"/>
</g>
<path d="M125.22 73.51a11.17 11.17 0 00-4.11-5.99c-.93-.7-1.91-1.24-2.87-1.67-.97-.43-1.93-.75-2.87-1.01a29.58 29.58 0 00-4.19-.83l-.69-.08-.35-.04-.31-.03s-3.07-.51-5.21-.53c-.94-.84-2.55-.83-4.34-1.78a15.36 15.36 0 00-5.54-1.24c-2.13-.05-5.09 1.19-4.79 1.11-.98.25-1.44.31-2.44.5-.21.04-.43.09-.59.22-.09.07-.16.17-.23.27.07-.1-.07.32-.1.97-.02.4.53.59.84.66.55.13 1.05.4 1.59.56.63.19 2.8.27 3.44.37.44.07 1.12.23 1.9.37.27.45.36 1.14.33 1.66-.05.94-.35 1.42-.74 2.05-.3.48-.75.7-1.18 1.07-.68.33-2.32.91-3.08.92-.28 0-.61-.01-.77.21-.05.13.06.19.1.24.06.07.13.11.21.14.16.07.34.09.52.13.59.15 1.54.05 2.12-.12.18-.05.35-.12.53-.14.67-.07 1.33-.14 2.01-.24.36-.05 1.14-.12 1.96-.2l1.69-.07c.85-.03 1.97.18 2.71-.31.86.75 4.27-.33 8.29.14l.31.04.28.04.56.08c1 .15 1.76.2 2.68.65l1.1.55c.43.21.86.43 1.31.58.52.17 1.11.09 1.11.09s.71 1.2.95 1.55l1.14 1.55s-.41 1-.52 1.36c-.19.67-.19 1.8-.29 1.99-.2.37-1.26.63-1.72.92-.47.29-1.99 1.11-1.99 1.11s-1.45-.05-3.14.19c-1.11.16-2.87.6-2.87.6s-1.4-.32-2.78-.27c-.81.03-2.23.28-3.06.27 0 0-.64-.28-3.05-.3-.83-.01-2.49.22-2.49.22-1.11-.26-2.54-.37-3.68-.26-.73.07-1.84.28-1.84.28s-1.37-.28-2.89-.12-2.55.67-2.55.67-1.6.04-2.13.2c-.52.16-1.04.35-1.56.58-.52.23-1.53 1.11-1.53 1.11s-.72-.1-2.66 1.7c-.9.84-1.05 2.16-1.05 2.16-.01.08-1.08 1.31-1.25 1.9-.79 2.79-.51 4.27-.51 4.27 0 .08.07 1.82.23 2.41a8.3 8.3 0 001.35 2.82s.59 1.41 1.28 2.2a7.1 7.1 0 003.52 2.09c.22.43 1.52 1.19 2.83 1.53.86.22 1.55.21 2.43.3l.71.07c.23.02.46-.04.68 0s1.05.27 1.26.34c.65.2 1.74.22 2.41.23 1.23.03 2.03-.08 2.03-.08.38.13 1.76.48 2.15.5.52.03 1.04.08 1.56.09 1.13.01 2.14-.19 2.14-.19s1.35.48 2.1.54c2.22.19 3.18-.2 3.58-.14.44.06 1.1.24 1.55.28 1.46.15 2.96.23 3.26.05.39.49 1.26.37 1.76.55.76.27 1.07.86 1.75.86 0 .44.52.23.52 1.31 0 .85-.65 1.07-.46 1.45.15.02-.74.14-1.79.81-1.04.67-1.61 1.15-1.61 1.15-.3.06-1.18.01-2.07.15-.89.14-1.78.47-2.08.5-1.14.12-1.24-.04-2.38.11-.78.1-1.41.34-2.19.47 0 0-1.18.01-1.94.18-.88.19-1.44.46-2.25.84 0 0-1.02.23-1.84.58-1.08.46-1.46 1.15-1.69 1.33a7.7 7.7 0 00-1.5 1.57 3.15 3.15 0 00-.61 1.66c0 .54-.25 1.03-.28 1.58-.03.54-.02 1.09.11 1.61.1.4.52 1.1.78 1.41 0 0-.02.51.95 1.48s1.6.95 1.87 1.01c0 0 .86.46 1.49.69.91.33 1.9.33 1.9.33.16.08.64.6 1.14.94.51.35 1.18.57 1.18.57l-.11.75c-.07.46-.01.77-.1.97-.08.18-.45.29-.6.41-.71.57-.76 1.04-.85 1.12-.09.08-.24.12-.34.19a1.9 1.9 0 00-.58.65 3.29 3.29 0 00-.3 1.75l.08.18c0 .3-.03.7.1 1.08.35 1.03.87 1.1 1.2 1.29.18.1.57.47.75.18.11-.18-.07-.48-.14-.64-.37-.78-.29-1.89.36-2.46 1.04-.91 1.51-.86 2.53-1.9.16-.16.29-.36.42-.57a4.68 4.68 0 00.64-1.38l.09-.37.07-.39.02-.21.01-.14.01-.07v-.32a5 5 0 00-.26-1.6 4.85 4.85 0 00-1.06-1.61c-1.31-1.24-3.25-1.75-4.74-2.41-.49-.22-1.8-.65-1.8-2.12 0-.91.36-1.53 1.23-1.9 1.06-.39 2.35-.76 6-1.07 2.83-.25 4.59-.45 5.72-.63a20.07 20.07 0 005.37-1.7c.79-.39 1.6-.86 2.39-1.5a8.11 8.11 0 002.12-2.52 7.1 7.1 0 00.8-2.59l.02-.22.02-.26.01-.17v-.22a8.1 8.1 0 00-.74-3.34 8.05 8.05 0 00-2.06-2.7 9.6 9.6 0 00-3.05-1.75l-.35-.12-.18-.06-.19-.06-.2-.06-.09-.02-.07-.02-.13-.03-.07-.02-.21-.04h-.02l-.03-.01c-4.7-1.1-14.5-1.5-17.96-2-3.46-.5-6.99-.8-9.33-1.74a7.1 7.1 0 01-1.53-.84 3.99 3.99 0 01-.96-.97 3.3 3.3 0 01-.49-1.18 5.48 5.48 0 01-.11-.74l-.01-.2v-.38.02-.06l.01-.21c.03-.56.13-1.07.29-1.5a3.6 3.6 0 011.71-2c.22-.13.45-.25.7-.35a9.65 9.65 0 011.66-.49l.31-.05.08-.01.04-.01h.03l-.04.01.13-.02.25-.04.26-.03a26.3 26.3 0 012.26-.17c1.57-.07 3.2-.07 4.85-.05l9.03.08 2.58.02 1.31-.01.66-.01.69-.02.66-.03.7-.04a26.37 26.37 0 004.25-.59 18.6 18.6 0 005.82-2.22c.96-.59 1.92-1.34 2.75-2.29a9.86 9.86 0 001.96-3.33c.44-1.23.61-2.5.61-3.69.02-1.1-.09-2.26-.41-3.43z"/>
<path fill="#F6F6F6" d="M92.42 61.88c-.02.19-.02.57.19.8.18.2.44.37.71.38.44.02.81-.16 1.01-.52.17-.3.2-.66.2-1a3.3 3.3 0 00-2.11.34z"/>
<g fill="#000" stroke="none">
<path d="M93.17 61.65c-.13.1-.13.21-.14.32-.02.31.19.71.4.85a2.5 2.5 0 01-.08-1.12"/>
<path d="M88.17 62.59l-.07-.02c-.04-.01-.09-.02-.15-.01s-.12.02-.16.06l-.02.01-.02.01-.03.03-.07.09-.04.05-.03.05-.06.1-.1.19-.07.15-.03.06s-.06-.09-.07-.25a.66.66 0 01.03-.27c.01-.05.03-.1.06-.14l.04-.07.05-.07a.68.68 0 01.19-.17.08.08 0 01.04-.02l.04-.02a.4.4 0 01.31.02c.08.04.13.09.15.13l.01.09z"/>
<path d="M87.67 63.29v-.04l.01-.07c.01-.05.03-.1.06-.14a.27.27 0 01.13-.07l.07-.01h.04l.02.03.02.08c.01.06-.01.13-.06.18s-.11.08-.17.07l-.08-.01-.04-.02z"/>
<path d="M91.59 62.28l.11-.1.26-.19.27-.17.13-.08.11.28-.14.03a15.54 15.54 0 00-.61.17l-.13.06z"/>
<path d="M100.11 65.47l.07.01.21.02a3.2 3.2 0 011.15.39l.17.1.06.04-.07-.03a3.34 3.34 0 00-.75-.22c-.21-.03-.42-.04-.58-.03l-.19.01-.07.01v-.3z"/>
<path d="M94.33 60.68l.1-.03.12-.03.15-.02.18-.01.2.01.22.03.22.06.21.08.2.1.17.11.14.11.11.11.08.09.06.08-.1-.04-.25-.1c-.2-.08-.46-.18-.72-.26l-.2-.06-.19-.06-.18-.05-.17-.04-.26-.06-.09-.02z"/>
<path d="M88.77 63.76s.04-.01.09 0 .11.03.16.06c.05.04.09.08.11.13l.03.09h-.1a.52.52 0 01-.16-.06.42.42 0 01-.11-.13l-.02-.09z"/>
<path d="M89.99 64.23s.03-.03.07-.04c.04-.02.1-.01.14.01.05.02.08.06.1.11.02.04.01.08.01.08l-.08.01c-.04 0-.08 0-.12-.02a.24.24 0 01-.09-.08l-.03-.07z"/>
<path d="M92.33 64.37l.06-.06c.04-.03.1-.04.15-.03.05.01.11.03.14.07l.05.07-.08.04c-.04.02-.09.02-.14.02a.5.5 0 01-.13-.05l-.05-.06z"/>
<path d="M93.36 64.62l.08-.05c.05-.02.1-.04.16-.03.06 0 .12.02.16.05l.07.06-.08.05a.29.29 0 01-.16.03.28.28 0 01-.16-.05.73.73 0 01-.07-.06z"/>
<path d="M94.37 64.7l.07-.06c.04-.03.1-.04.16-.02.06.01.11.05.14.09l.04.08-.08.03a.33.33 0 01-.14 0 .27.27 0 01-.12-.06.73.73 0 01-.07-.06z"/>
<path d="M95.27 64.91l.05-.05a.15.15 0 01.11-.04c.04 0 .07.02.1.05l.04.06-.05.06a.15.15 0 01-.11.04c-.04 0-.07-.02-.1-.05-.03-.03-.04-.07-.04-.07z"/>
</g>
<g fill="none">
<path d="M109.63 70.68c.54-1 .3-2.11.91-2.87"/>
<path d="M109.61 70.68c.54-1 .3-2.11.91-2.87"/>
<path d="M93.99 69.5l-1.23.61"/>
<path d="M100.77 70.67a6.9 6.9 0 001.54-1.47"/>
<path d="M102.31 69.19c.57-.71.84-1.66 1.11-2.03"/>
<path d="M93.99 69.5c1.15-.46 1.96-1.48 2.94-2.23.91-.68 2.13-1.21 3.18-1.65"/>
<path d="M94.35 65.34c.65.11 1.37.2 2.06.21 1.85.02 3.76.08 3.76.08"/>
<path d="M103.42 67.17s2.25.19 3.33.13c1.8-.09 5.45.49 5.45.49s9.65 1.7 9.65 8.43-4.78 8.16-11.12 8.9c-6.34.74-21.17-.74-25.91.8s-6.62 5.16-6.62 7.8.66 6.24 5.18 8.22c4.72 2.07 25.24 2.65 28.44 3.45 3.31.83 4.57 2.77 4.57 5.28 0 2.89-2.17 3.92-4.7 4.84-5.22 1.92-13.36 1.56-16.04 3.66-1.9 1.49-2.84 3.69-1.43 5.89 2.19 3.34 6.26 1.54 7.97 5.06a3.58 3.58 0 01-1.47 4.25c-1.71 1.16-2.66 3.1-.7 4.95"/>
<path d="M118.5 75.95c.11-.19 2.79-1.15 3.16-1.14"/>
<path d="M116.41 72.84c.14-1.06.76-2 1.36-2.89"/>
<path d="M111.71 71.21c0-1.15.4-2.29 1.11-3.18"/>
<path d="M106.91 70.45a5.07 5.07 0 01.67-3.12"/>
<path d="M117.8 79.28c.24-.04 2.04 1.48 2.37 2.24"/>
<path d="M113.98 81.34c.32.96.65 1.98.59 2.98"/>
<path d="M107.98 82.13c.33 1.01.4 2.09.2 3.13"/>
<path d="M102.14 82.13a7.96 7.96 0 01-.18 3.11"/>
<path d="M96.59 82.05c.39 1.07.39 2.08.01 3.16"/>
<path d="M91.07 82.06c.28 1.01.38 2.08.29 3.12"/>
<path d="M85.64 82.62c.44.87.72 1.83.82 2.8"/>
<path d="M80.45 84.51a5.83 5.83 0 011.66 2.54"/>
<path d="M76.7 88.45c.95.36 1.79 1 2.38 1.81"/>
<path d="M75.03 94.43A9.43 9.43 0 0177 94.1a2.1 2.1 0 011.19.19"/>
<path d="M76.54 99.77c.56-.64 1.98-1.03 2.82-1.06"/>
<path d="M82.21 101.5c-.52.7-.83 1.55-.87 2.42"/>
<path d="M88.38 103.09a8.3 8.3 0 00-.41 2.66"/>
<path d="M94.2 103.94a7.21 7.21 0 00-.51 2.52"/>
<path d="M99.92 104.4c-.35.69-.5 1.48-.42 2.25"/>
<path d="M105.47 104.73a10.7 10.7 0 00-.24 2.53"/>
<path d="M110.32 105.26a6.78 6.78 0 00-.28 2.33"/>
<path d="M114.8 107.16c-.52.63-.87 1.11-1.26 1.83"/>
<path d="M113.73 111.79c.73.3 1.19.73 1.76 1.27"/>
<path d="M110.21 113.72c.31.09.52.38.68.67.21.37.28.66.42 1.06"/>
<path d="M106.05 114.37c.25.78.36 1.51.3 2.33"/>
<path d="M101.49 115.06c.32.72.46 1.51.41 2.3"/>
<path d="M97.32 115.98c.42.55.68 1.33.72 2.03"/>
<path d="M93.77 117.98c.57.33 1.05.81 1.4 1.37"/>
<path d="M91.75 121.56c.66-.06 1.23.03 1.85.25"/>
<path d="M92.36 125.61a3.72 3.72 0 011.54-1.07"/>
<path d="M95.11 128.21a3.1 3.1 0 011.12-1.34"/>
<path d="M98.52 129.15a2 2 0 01.83-1.3"/>
<path d="M100.86 130.71c.34-.28.9-.41 1.34-.35"/>
<path d="M100.61 132.49c.44.13.86.35 1.21.65"/>
<path d="M99.28 134.11c.25.18.56.52.67.81"/>
<path d="M98 136.77c.36-.09.53-.15.9-.17"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Before After
Before After

159
index.css
View file

@ -36,6 +36,12 @@ textarea {
width: 100%;
}
iframe {
border: 0;
pointer-events: none;
width: 100%;
}
#map {
background-color: #000000;
mask-mode: alpha;
@ -222,18 +228,12 @@ t,
cursor: pointer;
}
#options .pressed {
background-color: #896c77 !important;
font-style: italic;
}
i.icon-lock {
cursor: pointer;
}
#routeEditor > *,
#labelEditor div,
#markerEditor div {
#labelEditor div {
display: inline-block;
}
@ -323,10 +323,21 @@ text.drag {
text-shadow: 0 0 1px red;
}
#dialogs {
background-color: var(--bg-dialogs);
}
.draggable {
cursor: move;
}
.ui-widget-header {
border-bottom: 1px solid var(--dark-solid);
background: var(--header);
color: #ffffff;
font-weight: bold;
}
.ui-dialog,
#optionsContainer {
user-select: none;
@ -338,6 +349,7 @@ text.drag {
border: solid 1px #5e4fa2;
margin: 10px;
padding-bottom: 0.3em;
background: var(--bg-light);
}
#options input,
@ -356,7 +368,7 @@ text.drag {
}
.tab {
border-bottom: 1px solid #5d4651;
border-bottom: 1px solid var(--dark-solid);
height: 2.2em;
display: flex;
justify-content: space-between;
@ -370,19 +382,19 @@ div.tab > button#optionsHide {
button.options {
width: 100%;
background-color: #997b89;
background-color: var(--bg-main);
font-weight: bold;
border: none;
transition: 0.2s;
}
button.options:hover {
background-color: #806070 !important;
color: white !important;
button.active {
background-color: var(--header);
color: white;
}
button.active {
background-color: #916e7f;
button.options:hover {
background-color: var(--header-active);
color: white;
}
@ -412,10 +424,35 @@ button.active {
#options i {
color: #31272c;
font-size: 0.8em;
font-size: 0.85em;
cursor: pointer;
}
#options button i.icon-cog {
position: absolute;
padding: 0.1em 0.3em;
background-color: var(--bg-lighter);
border-radius: 50%;
visibility: hidden;
opacity: 0;
transition: 0.4s ease-in-out;
}
#options button i.icon-cog:hover {
color: #111;
background-color: var(--bg-light);
transform: rotateZ(180deg);
}
#options button i.icon-cog:active {
transform: translateY(1px);
}
#options button:hover i.icon-cog {
visibility: visible;
opacity: 1;
}
input[type="color"] {
-webkit-appearance: none;
cursor: pointer;
@ -461,11 +498,11 @@ input[type="color"]::-webkit-color-swatch-wrapper {
border-radius: 15%;
width: 0.91em;
height: 0.91em;
background: #a58394;
border: 1px solid #5d4651;
background: var(--light-solid);
border: 1px solid var(--dark-solid);
cursor: pointer;
margin-top: -0.4em;
box-shadow: 0.5px 0.5px 0px #5d4651;
box-shadow: 0.5px 0.5px 0px var(--dark-solid);
}
#options input[type="range"]::-moz-range-thumb {
@ -473,10 +510,10 @@ input[type="color"]::-webkit-color-swatch-wrapper {
border-radius: 15%;
width: 0.73em;
height: 0.73em;
background: #a58394;
border: 1px solid #5d4651;
background: var(--light-solid);
border: 1px solid var(--dark-solid);
cursor: pointer;
box-shadow: 0.5px 0.5px 0px #5d4651;
box-shadow: 0.5px 0.5px 0px var(--dark-solid);
}
#options input[type="range"]::-webkit-slider-runnable-track {
@ -520,7 +557,7 @@ input[type="color"]::-webkit-color-swatch-wrapper {
}
#optionsContent input[type="number"]:hover {
outline: 1px solid #5d4651;
outline: 1px solid var(--dark-solid);
}
#optionsContent input.paired {
@ -542,10 +579,9 @@ input[type="color"]::-webkit-color-swatch-wrapper {
width: 100%;
}
#optionsSeedGenerate:before {
content: "✓";
margin-left: -2px;
font-weight: bold;
#options input[type="color"] {
width: 2em;
padding: 1px;
}
.tabcontent button.sideButton {
@ -601,7 +637,7 @@ input[type="color"]::-webkit-color-swatch-wrapper {
#exitCustomization > div {
width: 12em;
background: #5d4651;
background: var(--dark-solid);
cursor: move;
}
@ -637,7 +673,7 @@ input[type="color"]::-webkit-color-swatch-wrapper {
}
.tabcontent button {
background-color: #916e7f;
background-color: var(--bg-lighter);
border: none;
padding: 0.45em 0.75em;
margin: 0.35em 0;
@ -645,8 +681,13 @@ input[type="color"]::-webkit-color-swatch-wrapper {
font-size: 1em;
}
.tabcontent button.pressed {
background-color: var(--header);
font-style: italic;
}
.tabcontent button:hover {
background-color: #a8879d !important;
background-color: var(--header-active);
}
#toolsContent div {
@ -679,12 +720,12 @@ input[type="color"]::-webkit-color-swatch-wrapper {
}
fieldset {
border: 1px solid #5d4651;
border: 1px solid var(--dark-solid);
}
.tabcontent li {
list-style-type: none;
background-color: #997b89;
background-color: var(--bg-main);
cursor: pointer;
padding: 0.35em;
margin: 0.2em 0.3em;
@ -693,14 +734,17 @@ fieldset {
text-align: center;
}
#options .buttonoff {
background-color: #b6b4b440 !important;
color: #666;
.tabcontent .buttonoff {
background-color: var(--bg-disabled);
color: #444444aa;
}
.tabcontent li:hover {
box-shadow: 0 0 2px 2px var(--dark-solid) 17;
}
.tabcontent li:hover,
.tabcontent button:hover {
box-shadow: 0 0 2px 2px #5d465117;
background-color: var(--header);
}
#optionsContainer span {
@ -799,7 +843,7 @@ fieldset {
table.matrix-table th,
table.matrix-table td {
border: 1px solid #5d4651;
border: 1px solid var(--dark-solid);
height: 2em;
padding: 0.2em;
position: relative;
@ -815,7 +859,7 @@ table.matrix-table tr:hover th {
}
table.matrix-table td:hover {
outline: 2px solid #5d4651;
outline: 2px solid var(--dark-solid);
outline-offset: -1px;
z-index: 1;
}
@ -1142,7 +1186,7 @@ i.resetButton {
}
i.resetButton:active {
color: #5d4651;
color: var(--dark-solid);
}
.ui-dialog button.pressed {
@ -1183,7 +1227,7 @@ i.resetButton:active {
}
.ui-dialog input[type="number"] {
width: 3.5em;
width: 4.5em;
}
.ui-dialog .disabled {
@ -1266,16 +1310,19 @@ div.slider .ui-slider-handle {
scrollbar-width: thin;
}
#alertMessage::-webkit-scrollbar,
.table::-webkit-scrollbar {
width: 6px;
background-color: transparent;
}
#alertMessage::-webkit-scrollbar-thumb,
.table::-webkit-scrollbar-thumb {
background-color: #aaa;
border-radius: 6px;
}
#alertMessage::-webkit-scrollbar-thumb:hover,
.table::-webkit-scrollbar-thumb:hover {
background: #666;
}
@ -1364,11 +1411,16 @@ div.states > .statePopulation {
width: 3em;
}
div.states:hover > .hiddenIcon {
visibility: visible !important;
}
div.states .icon-pencil,
div.states .icon-trash-empty,
div.states .icon-eye,
div.states .icon-pin,
div.states .icon-flag-empty {
div.states .icon-flag-empty,
div.states .icon-cw {
cursor: pointer;
}
@ -1519,9 +1571,11 @@ div.states > .coaIcon > use {
#stateNameEditor div.label,
#provinceNameEditor div.label,
#regimentBody div.label {
#regimentBody div.label,
#markerEditor div.label {
display: inline-block;
width: 5.5em;
padding: 0.3em 0;
}
#saveTilesScreen div.label {
@ -1529,10 +1583,6 @@ div.states > .coaIcon > use {
width: 5em;
}
#regimentBody div {
margin: 0.1em 0;
}
#regimentBody input[type="number"] {
width: 5em;
}
@ -1677,8 +1727,8 @@ div.editorLine {
}
#pickerHeader {
fill: #916e7f;
stroke: #5d4651;
fill: var(--header);
stroke: var(--dark-solid);
cursor: move;
}
@ -1692,7 +1742,7 @@ div.editorLine {
#pickerCloseRect {
cursor: pointer;
fill: #916e7f;
fill: var(--header);
stroke: #f8ffff;
}
@ -1918,7 +1968,7 @@ input[type="checkbox"] {
.checkbox + .checkbox-label:before {
content: "";
display: inline-block;
vertical-align: text-top;
vertical-align: middle;
width: 0.6em;
height: 0.6em;
padding: 0.2em;
@ -1965,10 +2015,7 @@ div.textual span,
font-family: monospace;
user-select: none;
text-anchor: middle;
}
#markerEditor > button {
vertical-align: top;
dominant-baseline: central;
}
.highlighted {
@ -2198,14 +2245,14 @@ svg.button {
color: #920303;
background-color: #dabdbd91;
padding: 2px;
border: 1px solid #916e7f;
border: 1px solid var(--header);
}
.announcement {
background-color: #a18888;
color: white;
padding: 0.4em 0.5em;
border: dashed 1px #5d4651;
border: dashed 1px var(--dark-solid);
}
.speaker {

View file

@ -16,7 +16,7 @@
<link rel="canonical" href="https://azgaar.github.io/Fantasy-Map-Generator/">
<style type="text/css">
body {margin: 0; font-size: 11px; overflow: hidden;}
body {margin: 0; font-size: 10px; overflow: hidden;}
#map {position: absolute;}
#initial {fill: none; stroke: black; pointer-events: none;}
#init-rose {animation: 20s infinite spin; opacity: .7; transform-origin: center;}
@ -210,14 +210,6 @@
<g id="defs-emblems"></g>
</g>
<g id="defs-markers">
<symbol id="marker0" viewBox="0 0 30 30">
<path d="M6,19 l9,10 L24,19" fill="#000000" stroke="none" />
<circle cx="15" cy="15" r="10" stroke-width="1" stroke="#000000" fill="#ffffff" />
<text x="50%" y="50%" fill="#000000" stroke-width="0" stroke="#3200ff" font-size="22px" dominant-baseline="central">?</text>
</symbol>
</g>
<pattern id="oceanic" width="100" height="100" patternUnits="userSpaceOnUse">
<image id="oceanicPattern" href="./images/pattern1.png"></image>
</pattern>
@ -234,22 +226,22 @@
<div id="loading">
<div id="titleName"><t data-t="titleName">Azgaar's</t></div>
<div id="title"><t data-t="title">Fantasy Map Generator</t></div>
<div id="version"><t data-t="version">v. </t>1.66</div>
<div id="version"><t data-t="version">v. </t>1.71</div>
<p id="loading-text"><t data-t="loading">LOADING</t><span>.</span><span>.</span><span>.</span></p>
</div>
<div id="optionsContainer" style="opacity:0">
<div id="collapsible">
<button id="optionsTrigger" data-t="tipOptionsTrigger" data-tip="Click to show options pane. Shortcut: Tab" class="options glow" onclick="showOptions(event)" style="padding:.6em .45em"></button>
<button id="regenerate" data-t="tipRegenerate" data-tip="Click to generate a new map. Shortcut: F2" onclick="regeneratePrompt()" class="options" style="display: none"><t data-t="newMap">New Map!</t></button>
<button id="optionsTrigger" data-t="tipOptionsTrigger" data-tip="Click to show the Menu. Shortcut: Tab" class="options glow" onclick="showOptions(event)" style="padding:.6em .45em"></button>
<button id="regenerate" data-t="tipRegenerate" data-tip="Click to generate a new map. Shortcut: F2" onclick="regeneratePrompt('drawer')" class="options" style="display: none"><t data-t="newMap">New Map!</t></button>
</div>
<div id="options" style="display:none">
<div class="drag-trigger" data-t="optionsDragTrigger" data-tip="Drag to move options pane"></div>
<div class="drag-trigger" data-t="optionsDragTrigger" data-tip="Drag to move the Menu"></div>
<div class="tab">
<button id="optionsHide" data-t="optionsHide" data-tip="Click to hide options pane. Shortcut: Tab to close this or Esc to close all dialogs" class="options" onclick="hideOptions(event)"></button>
<button id="optionsHide" data-t="optionsHide" data-tip="Click to hide the Menu. Shortcut: Tab or Esc" class="options" onclick="hideOptions(event)"></button>
<button id="layersTab" data-t="layersTab" data-tip="Click to change map layers" class="options active"><t data-t="layers">Layers</t></button>
<button id="styleTab" data-t="styleTab" data-tip="Click to open style editor" class="options"><t data-t="style">Style</t></button>
<button id="optionsTab" data-t="optionsTab" data-tip="Click to change generation and UI options" class="options"><t data-t="options">Options</t></button>
@ -304,7 +296,7 @@
<li id="toggleMilitary" data-tip="Military forces: click to toggle, drag to raise or lower the layer. Ctrl + click to edit layer style. Shortcut: M" class="buttonoff" onclick="toggleMilitary(event)"><u>M</u>ilitary</li>
<li id="toggleMarkers" data-tip="Markers: click to toggle, drag to raise or lower the layer. Ctrl + click to edit layer style. Shortcut: K" class="buttonoff" onclick="toggleMarkers(event)">Mar<u>k</u>ers</li>
<li id="toggleRulers" data-tip="Rulers: click to toggle, drag to move, click on label to delete. Ctrl + click to edit layer style. Shortcut: = (equal)" class="buttonoff" onclick="toggleRulers(event)">Rulers</li>
<li id="toggleScaleBar" data-tip="Scale Bar: click to toggle. Ctrl + click to edit style. Shortcut: - (minus)" onclick="toggleScaleBar(event)" class="solid">Scale Bar</li>
<li id="toggleScaleBar" data-tip="Scale Bar: click to toggle. Ctrl + click to edit style. Shortcut: / (slash)" onclick="toggleScaleBar(event)" class="solid">Scale Bar</li>
</ul>
<div id="viewMode" data-tip="Set view node">
@ -438,18 +430,24 @@
<td>
<select id="styleTextureInput">
<option value="none">None</option>
<option value="default" selected>Default</option>
<option value="https://i.imgur.com/EWvXSou.jpg">Folded paper</option>
<option value="https://i2.wp.com/azgaar.files.wordpress.com/2019/07/marble-big.jpg">Marble big</option>
<option value="https://i2.wp.com/azgaar.files.wordpress.com/2021/10/folded-paper-big.jpg">Folded paper big</option>
<option value="https://i2.wp.com/azgaar.files.wordpress.com/2021/10/folded-paper-small.jpg">Folded paper small</option>
<option value="https://i2.wp.com/azgaar.files.wordpress.com/2021/10/gray-paper.jpg">Gray paper</option>
<option value="https://i2.wp.com/azgaar.files.wordpress.com/2021/10/soiled-paper.jpg">Soiled paper horizontal</option>
<option value="https://i2.wp.com/azgaar.files.wordpress.com/2021/10/soiled-paper-e1633784189147.jpg">Soided paper vertical</option>
<option value="https://i2.wp.com/azgaar.files.wordpress.com/2021/10/plaster.jpg">Plaster</option>
<option value="https://i2.wp.com/azgaar.files.wordpress.com/2021/10/ocean.jpg">Ocean</option>
<option value="https://i2.wp.com/azgaar.files.wordpress.com/2019/07/antique-small.jpg">Antique small</option>
<option value="https://i2.wp.com/azgaar.files.wordpress.com/2019/07/antique-big.jpg">Antique big</option>
<option value="https://i2.wp.com/azgaar.files.wordpress.com/2019/07/pergamena-small.jpg">Pergamena small</option>
<option value="https://i2.wp.com/azgaar.files.wordpress.com/2021/10/marble-big.jpg" selected>Marble big</option>
<option value="https://i2.wp.com/azgaar.files.wordpress.com/2019/07/marble-small.jpg">Marble small</option>
<option value="https://i2.wp.com/azgaar.files.wordpress.com/2019/07/marble-blue-small.jpg">Marble Blue</option>
<option value="https://i2.wp.com/azgaar.files.wordpress.com/2019/07/marble-blue-big.jpg">Marble Blue big</option>
<option value="https://i2.wp.com/azgaar.files.wordpress.com/2019/07/stone-small.jpg">Stone small</option>
<option value="https://i2.wp.com/azgaar.files.wordpress.com/2019/07/stone-big.jpg">Stone big</option>
<option value="https://i2.wp.com/azgaar.files.wordpress.com/2019/07/timbercut-small.jpg">Timber Cut small</option>
<option value="https://i2.wp.com/azgaar.files.wordpress.com/2019/07/timbercut-big.jpg">Timber Cut big</option>
<option value="https://i2.wp.com/azgaar.files.wordpress.com/2019/07/antique-small.jpg">Antique small</option>
<option value="https://i2.wp.com/azgaar.files.wordpress.com/2019/07/antique-big.jpg">Antique big</option>
<option value="https://i2.wp.com/azgaar.files.wordpress.com/2019/07/pergamena-small.jpg">Pergamena small</option>
<option value="https://i2.wp.com/azgaar.files.wordpress.com/2019/07/mars-small.jpg">Mars small</option>
<option value="https://i2.wp.com/azgaar.files.wordpress.com/2019/07/mars-big.jpg">Mars big</option>
<option value="https://i2.wp.com/azgaar.files.wordpress.com/2019/07/mercury-small.jpg">Mercury small</option>
@ -949,14 +947,13 @@
<tr data-tip="Map seed number. Seed produces the same map only if canvas size and options are the same">
<td>
<i data-tip="Click to generate a map for this seed" id="optionsSeedGenerate"></i>
<i data-tip="Show seed history to apply a previous seed" id="optionsMapHistory" class="icon-history"></i>
</td>
<td>Map seed</td>
<td>
<input id="optionsSeed" class="long" type="number" min=1 max=999999999 step=1>
</td>
<td>
<i data-tip="Show seed history to apply a previous seed" id="optionsMapHistory" class="icon-history"></i>
<i data-tip="Copy map seed as URL. It will produce the same map only if options are default or the same" id="optionsCopySeed" class="icon-docs"></i>
</td>
</tr>
@ -1133,6 +1130,21 @@
<output id="religionsOutput" data-stored="religions" value="auto"></output>
</td>
</tr>
<tr data-tip="Select state labels mode: display short or full names">
<td>
<i data-locked=0 id="lock_stateLabelsMode" class="icon-lock-open"></i>
</td>
<td>State labels</td>
<td>
<select id="stateLabelsModeInput" data-stored="stateLabelsMode">
<option value="auto">Auto </option>
<option value="short">Short names</option>
<option value="full">Full names</option>
</select>
</td>
<td></td>
</tr>
</table>
<p data-tip="Tool settings that don't affect maps. Changes are getting applied immediately">Generator settings:</p>
@ -1153,10 +1165,10 @@
<td></td>
<td>Interface size</td>
<td>
<input id="uiSizeInput" data-stored="uiSize" type="range" min=.6 max=3 step=.1 value=1>
<input id="uiSizeInput" data-stored="uiSize" type="range" min=.6 max=3 step=.1>
</td>
<td>
<input id="uiSizeOutput" data-stored="uiSize" type="number" min=.6 max=3 step=.1 value=1>
<input id="uiSizeOutput" data-stored="uiSize" type="number" min=.6 max=3 step=.1>
</td>
</tr>
@ -1171,14 +1183,27 @@
</td>
</tr>
<tr data-tip="Set theme hue for dialogs and tool windows">
<td>
<i data-tip="Restore default theme color: pale magenta" id="themeColorRestore" class="icon-ccw"></i>
</td>
<td>Theme color</td>
<td>
<input id="themeHueInput" type="range" min=0 max=359 >
</td>
<td>
<input id="themeColorInput" data-stored="themeColor" type="color" >
</td>
</tr>
<tr data-tip="Set dialog and tool windows transparency">
<td></td>
<td>Transparency</td>
<td>
<input id="transparencyInput" data-stored="transparency" type="range" min=0 max=100 value=15>
<input id="transparencyInput" data-stored="transparency" type="range" min=0 max=100 >
</td>
<td>
<input id="transparencyOutput" data-stored="transparency" type="number" min=0 max=100 value=15>
<input id="transparencyOutput" data-stored="transparency" type="number" min=0 max=100 >
</td>
</tr>
@ -1271,7 +1296,9 @@
</tr>
<tr data-tip="Set minimum and maximum possible zoom level">
<td></td>
<td>
<i data-tip="Restore default zoom extent: [1, 20]" id="zoomExtentDefault" class="icon-ccw"></i>
</td>
<td>Zoom extent</td>
<td>
<span data-tip="Mimimal possible zoom level (should be > 0)">min</span>
@ -1280,7 +1307,6 @@
<input data-tip="Maximal possible zoom level (should be > 1)" id="zoomExtentMax" class="paired" type="number" min=1 max=50 value=20>
</td>
<td>
<i data-tip="Restore default zoom extent (1, 20)" id="zoomExtentDefault" class="icon-ccw"></i>
<i data-tip="Allow to drag map beyond canvas borders" id="translateExtent" data-on=0 class="icon-hand-paper-o"></i>
</td>
</tr>
@ -1338,6 +1364,7 @@
<button id="overviewBurgsButton" data-tip="Click to open Burgs Overview. Shortcut: Shift + T">Burgs</button>
<button id="overviewRiversButton" data-tip="Click to open Rivers Overview. Shortcut: Shift + V">Rivers</button>
<button id="overviewMilitaryButton" data-tip="Click to open Military Forces Overview. Shortcut: Shift + M">Military</button>
<button id="overviewMarkersButton" data-tip="Click to open Markers Overview. Shortcut: Shift + K">Markers</button>
<button id="overviewCellsButton" data-tip="Click to open Cell details view. Shortcut: Shift + E">Cells</button>
</div>
@ -1356,7 +1383,7 @@
<button id="regenerateCultures" data-tip="Click to regenerate cultures">Cultures</button>
<button id="regenerateMilitary" data-tip="Click to recalculate military forces based on current military options">Military</button>
<button id="regenerateIce" data-tip="Click to icebergs and glaciers">Ice</button>
<button id="regenerateMarkers" data-tip="Click to regenerate markers. Hold Ctrl and click to set markers number multiplier">Markers</button>
<button id="regenerateMarkers" data-tip="Click to regenerate markers">Markers <i id="configRegenerateMarkers" class="icon-cog" data-tip="Click to set number multiplier"></i></button>
<button id="regenerateZones" data-tip="Click to regenerate zones. Hold Ctrl and click to set zones number multiplier">Zones</button>
</div>
@ -1467,8 +1494,7 @@
</div>
</div>
<div id="dialogs" style="background-color: #ffffff">
<div id="dialogs">
<div id="worldConfigurator" class="dialog stable" style="display: none">
<div id="worldControls">
@ -1952,8 +1978,9 @@
<div id="burgEditor" class="dialog" style="display: none">
<div id="burgBody" style="padding-bottom: .3em">
<svg viewBox="0 0 200 200" width="14em" height="14em"><use id="burgEmblem"></use></svg>
<div style="float: right">
<div style="display: flex; align-items: center">
<svg data-tip="Burg emblem. Click to edit" class="pointer" viewBox="0 0 200 200" width="13em" height="13em"><use id="burgEmblem"></use></svg>
<div>
<div id="burgProvinceAndState" style="font-style: italic; max-width: 16em"></div>
<div>
@ -2011,6 +2038,16 @@
</div>
</div>
<div id="mfcgPreviewSection" data-tip="Burg preview in the Medieval Fantasy City Generator. Default seed is a conbimation of map seed and burg id" style="display: flex; flex-direction: column">
<div>
See in <a id="mfcgLink" target="_blank">City Generator by Watabou</a>.
Seed: <input id="mfcgBurgSeed" style="width: 10em" type="number" min=1 max="1e13" step="1" />
<i id="regenerateMFCGBurgSeed" data-tip="Randomize Medieval Fantasy City Generator burg seed" class="icon-arrows-cw pointer" style="margin-left: .1em"></i>
</div>
<iframe id="mfcgPreview" sandbox="allow-scripts allow-same-origin"></iframe>
</div>
</div>
<div id="burgBottom">
<button id="burgGroupShow" data-tip="Show group change section" class="icon-tags"></button>
<div id="burgGroupSection" style="display: none">
@ -2029,59 +2066,78 @@
<button id="burgEditAnchorStyle" data-tip="Edit port icon (anchor) style for burg group in Style Editor" class="icon-anchor"></button>
</div>
<button id="burgSeeInMFCG" data-tip="Open burg in the Medieval Fantasy City Generator by Watabou. Ctrl + click to change the seed" class="icon-map-o"></button>
<button id="burgEditEmblem" data-tip="Edit emblem" class="icon-shield-alt"></button>
<button id="burgToggleMFCGMap" data-tip="Toggle MFCG map" class="icon-map"></button>
<button id="burgRelocate" data-tip="Relocate burg" class="icon-target"></button>
<button id="burglLegend" data-tip="Edit free text notes (legend) for this burg" class="icon-edit"></button>
<button id="burgLock" class="icon-lock-open"></button>
<button id="burgLock" class="icon-lock-open" onmouseover="showElementLockTip(event)"></button>
<button id="burgRemove" data-tip="Remove non-capital burg. Shortcut: Delete" class="icon-trash fastDelete"></button>
</div>
</div>
<div id="markerEditor" class="dialog" style="display: none">
<button id="markerGroup" data-tip="Change marker type" class="icon-tags"></button>
<div id="markerGroupSection" style="display: none">
<select id="markerSelectGroup" data-tip="Select type for the selected marker" style="width: 10em"></select>
<input id="markerInputGroup" data-tip="Create new type for selected marker" placeholder="type new name" style="display: none; width: 10em"/>
<i id="markerAddGroup" data-tip="Create new markers type" class="icon-plus pointer"></i>
<i id="markerRemoveGroup" data-tip="Remove all markers of that type" class="icon-trash pointer"></i>
<div id="markerBody" style="padding-bottom: .3em">
<div data-tip="Marker type. Style changes will apply to all markers of the same type. Leave blank if the marker is unique">
<div class="label">Type:</div>
<input id="markerType" style="width: 10.3em" />
</div>
<button id="markerIcon" data-tip="Change marker icon and edit positioning" class="icon-star"></button>
<div id="markerIconSection" style="display: none">
<i data-tip="Change marker icon size" class="icon-resize-full"></i>
<input id="markerIconSize" data-tip="Change marker icon size" type="range" min=5 max=30 step=.5 value=22 style="width:12em"><br>
<i data-tip="Marker Icon" class="icon-info"></i>
<button id="markerIconSelect" data-tip="Click to select icon"></button>
<i data-tip="Change marker horizontal shift" class="icon-resize-horizontal"></i>
<input id="markerIconShiftX" data-tip="Change icon horizontal shift" type="number" value=50>
<i data-tip="Change marker vertical shift" class="icon-resize-vertical"></i>
<input id="markerIconShiftY" data-tip="Change vertical shift" type="number" min=0 max=100 value=50>
<div data-tip="Marker icon. Paste any Unicode symbol or select from the predefined list">
<div class="label">Icon:</div>
<input id="markerIcon" style="width:5em" />
<button id="markerIconSelect" style="width: 5em">select</button>
</div>
<button id="markerStyle" data-tip="Change marker size and colors" class="icon-brush"></button>
<div id="markerStyleSection" style="display: none">
<i data-tip="Change marker base (pin) style" class="icon-map-pin"></i>
<input id="markerSize" data-tip="Change marker size" type="range" min=.01 max=10 step=.1 value=1 style="width:12em">
<input id="markerBaseStroke" data-tip="Change pin stroke color" type="color" value="#ffffff">
<input id="markerBaseFill" data-tip="Change pin fill color" type="color" alue="#000000">
<br><i data-tip="Change marker icon style" class="icon-star"></i>
<input id="markerIconStrokeWidth" data-tip="Change icon stroke width" type="range" min=0 max=1 step=.02 value=0 style="width:12em">
<input id="markerIconStroke" data-tip="Change icon stroke color. Ensure icon stroke width is non-zero" type="color" value="#3200ff">
<input id="markerIconFill" data-tip="Change icon fill color" type="color" value="#000000">
<div data-tip="Marker marker element and icon sizes in pixels">
<div class="label">Size:</div>
<input data-tip="Marker element size in pixels" id="markerSize" type="number" min="2" max="500" style="width: 5em" />
<input data-tip="Marker icon sizes in pixels" id="markerIconSize" type="number" min="2" max="20" step="0.5" style="width: 5em" />
</div>
<button id="markerToggleBubble" data-tip="Toggle pin (bubble) display" class="icon-info-circled"></button>
<button id="markerLegendButton" data-tip="Edit place legend (free text notes)" class="icon-edit"></button>
<div data-tip="Marker icon shift (by X and by Y axis), percent. Set to 50 to position icon in center">
<div class="label">Icon shift:</div>
<input id="markerIconShiftX" type="number" min="0" max="100" step="1" style="width:5em" />
<input id="markerIconShiftY" type="number" min="0" max="100" step="1" style="width:5em" />
</div>
<div data-tip="Marker pin shape">
<div class="label">Pin shape:</div>
<select id="markerPin" style="width: 10.3em">
<option value="bubble">Bubble</option>
<option value="pin">Pin</option>
<option value="square">Square</option>
<option value="squarish">Squarish</option>
<option value="diamond">Diamond</option>
<option value="hex">Hex</option>
<option value="hexy">Hexy</option>
<option value="shieldy">Shieldy</option>
<option value="shield">Shield</option>
<option value="pentagon">Pentagon</option>
<option value="heptagon">Heptagon</option>
<option value="circle">Circle</option>
<option value="no">No</option>
</select>
</div>
<div data-tip="Pin fill and stroke colors">
<div class="label">Pin colors:</div>
<input id="markerFill" type="color" style="width:5em; height:1.6em" />
<input id="markerStroke" type="color" style="width:5em; height:1.6em" />
</div>
</div>
<div id="markerBottom">
<button id="markerNotes" data-tip="Edit place legend (notes)" class="icon-edit"></button>
<button id="markerLock" class="icon-lock-open" onmouseover="showElementLockTip(event)"></button>
<button id="markerAdd" data-tip="Add additional marker of that type" class="icon-plus"></button>
<button id="markerRemove" data-tip="Remove the marker. Shortcut: Delete" class="icon-trash fastDelete"></button>
</div>
</div>
<div id="regimentEditor" class="dialog" style="display: none">
<div id="regimentBody">
<div>
<div id="regimentBody" style="padding-bottom: 0.3em">
<div style="padding-bottom: 0.2em">
<button id="regimentType" data-tip="Regiment type (land or naval). Click to change"></button>
<input id="regimentName" data-tip="Type to rename the regiment" autocorrect="off" spellcheck="false" style="width: 13em">
<span data-tip="Speak the name. You can change voice and language in options" class="speaker">🔊</span>
@ -2535,7 +2591,7 @@
</div>
<div id="stateNameEditor" class="dialog" data-state="0" style="display: none">
<div style="padding: .1em">
<div>
<div data-tip="State short name" class="label">Short name:</div>
<input id="stateNameEditorShort" data-tip="Type to change the short name" autocorrect="off" spellcheck="false" style="width: 11em">
<span data-tip="Speak the name. You can change voice and language in options" class="speaker">🔊</span>
@ -2543,7 +2599,7 @@
<span id="stateNameEditorShortRandom" data-tip="Generate random name" class="icon-globe pointer"></span>
</div>
<div style="padding: .1em" data-tip="Select form name">
<div data-tip="Select form name">
<div data-tip="State form name" class="label">Form name:</div>
<select id="stateNameEditorSelectForm" style="width: 11em">
<option value="">blank</option>
@ -2593,7 +2649,7 @@
<option value="United Provinces">United Provinces</option>
<option value="United Republic">United Republic</option>
<option value="United States">United States</option>
<option value="Tribes">United Tribes</option>
<option value="United Tribes">United Tribes</option>
</optgroup>
<optgroup label="Theocracy">
<option value="Bishopric">Bishopric</option>
@ -2622,7 +2678,7 @@
<span id="stateNameEditorAddForm" data-tip="Click to add custom state form name to the list" class="icon-plus pointer"></span>
</div>
<div style="padding: .1em">
<div>
<div data-tip="State full name" class="label">Full name:</div>
<input id="stateNameEditorFull" data-tip="Type to change the full name" autocorrect="off" spellcheck="false" style="width: 11em">
<span data-tip="Speak the name. You can change voice and language in options" class="speaker">🔊</span>
@ -2672,6 +2728,7 @@
<button id="provincesManuallyCancel" data-tip="Cancel assignment" class="icon-cancel"></button>
</div>
<button id="provincesRelease" data-tip="Release all provinces. It will make all provinces with burgs independent" class="icon-flag"></button>
<button id="provincesAdd" data-tip="Add a new province. Hold Shift to add multiple" class="icon-plus"></button>
<button id="provincesRemoveAll" data-tip="Remove all provinces. States will remain as they are" class="icon-trash"></button>
@ -2711,7 +2768,7 @@
</div>
<div id="provinceNameEditor" class="dialog" data-province="0" style="display: none">
<div style="padding: .1em">
<div>
<div data-tip="Province short name" class="label">Short name:</div>
<input id="provinceNameEditorShort" data-tip="Type to change the short name" autocorrect="off" spellcheck="false" style="width: 11em">
<span data-tip="Speak the name. You can change voice and language in options" class="speaker">🔊</span>
@ -2719,7 +2776,7 @@
<span id="provinceNameEditorShortRandom" data-tip="Generate random name" class="icon-globe pointer"></span>
</div>
<div style="padding: .1em" data-tip="Select form name">
<div data-tip="Select form name">
<div data-tip="Province form name" class="label">Form name:</div>
<select id="provinceNameEditorSelectForm" style="display: inline-block; width: 11em; height: 1.645em">
<option value="">blank</option>
@ -2759,7 +2816,7 @@
<span id="provinceNameEditorAddForm" data-tip="Click to add custom province form name to the list" class="icon-plus pointer"></span>
</div>
<div style="padding: .1em">
<div>
<div data-tip="Province full name" class="label">Full name:</div>
<input id="provinceNameEditorFull" data-tip="Type to change the full name" autocorrect="off" spellcheck="false" style="width: 11em">
<span data-tip="Speak the name. You can change voice and language in options" class="speaker">🔊</span>
@ -2770,13 +2827,13 @@
<div id="culturesEditor" class="dialog stable" style="display: none">
<div id="culturesHeader" class="header">
<div style="left:1.8em" data-tip="Click to sort by culture name" class="sortable alphabetically" data-sortby="name">Culture&nbsp;</div>
<div style="left:8.7em" data-tip="Click to sort by culture cells count" class="sortable hide" data-sortby="cells">Cells&nbsp;</div>
<div style="left:13.2em" data-tip="Click to sort by expansionism" class="sortable hide" data-sortby="expansionism">Expan.&nbsp;</div>
<div style="left:18.6em" data-tip="Click to sort by type" class="sortable alphabetically" data-sortby="type">Type&nbsp;</div>
<div style="left:24.9em" data-tip="Click to sort by culture area" class="sortable hide" data-sortby="area">Area&nbsp;</div>
<div style="left:28.8em" data-tip="Click to sort by culture population" class="sortable hide icon-sort-number-down" data-sortby="population">Population&nbsp;</div>
<div style="left:35.8em" data-tip="Click to sort by culture namesbase" class="sortable" data-sortby="base">Namesbase&nbsp;</div>
<div style="left:42.9em" data-tip="Click to sort by culture emblems shape" class="sortable alphabetically hide" data-sortby="emblems">Emblems&nbsp;</div>
<div style="left:9.8em" data-tip="Click to sort by culture cells count" class="sortable hide" data-sortby="cells">Cells&nbsp;</div>
<div style="left:14.3em" data-tip="Click to sort by expansionism" class="sortable hide" data-sortby="expansionism">Expan.&nbsp;</div>
<div style="left:19.7em" data-tip="Click to sort by type" class="sortable alphabetically" data-sortby="type">Type&nbsp;</div>
<div style="left:26em" data-tip="Click to sort by culture area" class="sortable hide" data-sortby="area">Area&nbsp;</div>
<div style="left:29.9em" data-tip="Click to sort by culture population" class="sortable hide icon-sort-number-down" data-sortby="population">Population&nbsp;</div>
<div style="left:36.9em" data-tip="Click to sort by culture namesbase" class="sortable" data-sortby="base">Namesbase&nbsp;</div>
<div style="left:44em" data-tip="Click to sort by culture emblems shape" class="sortable alphabetically hide" data-sortby="emblems">Emblems&nbsp;</div>
</div>
<div id="culturesBody" class="table" data-type="absolute"></div>
@ -3037,7 +3094,7 @@
<div data-tip="Set size of particular Emblem. To hide set to 0. To change the entire category go to Menu ⭢ Style ⭢ Emblems">
<div class="label" style="width: 2.8em">Size:</div>
<input id="emblemSizeSlider" type="range" min=0 max=5 step=.1 style="width: 8em"/>
<input id="emblemSizeSlider" type="range" min=0 max=5 step=.1 style="width: 7em"/>
<input id="emblemSizeNumber" type="number" min=0 max=5 step=.1 />
</div>
</div>
@ -3178,6 +3235,12 @@
<input id="urbanizationOutput" data-stored="urbanization" type="range" min=.01 max=5 step=.01 value=1 >
<input id="urbanizationInput" data-stored="urbanization" type="number" min=.01 max=5 step=.01 value=1 >
</div>
<div data-tip="Set urban density: average population per building in Medieval Fantasy City Generator">
<div>Urban density:</div>
<input id="urbanDensityOutput" data-stored="urbanDensity" type="range" min=1 max=200 step=1 value=10 >
<input id="urbanDensityInput" data-stored="urbanDensity" type="number" min=1 max=200 step=1 value=10 >
</div>
</div>
<div id="unitsBottom">
@ -3202,6 +3265,7 @@
<div style="left:20.1em" data-tip="Click to sort by culture name" class="sortable alphabetically" data-sortby="culture">Culture&nbsp;</div>
<div style="left:24.7em" data-tip="Click to sort by burg population" class="sortable" data-sortby="population">Population&nbsp;</div>
<div style="left:31.2em" data-tip="Click to sort by burg type" class="sortable alphabetically" data-sortby="type">Type&nbsp;</div>
<div id="burgsInvertLock" style="left:35.5em; color: #6e5e66" data-tip="Click to invert lock for all burgs" class="icon-lock pointer"></div>
</div>
<div id="burgsBody" class="table"></div>
@ -3317,6 +3381,10 @@
<tr>
<th data-tip="Unit icon">Icon</th>
<th data-tip="Unit name. If name is changed for existing unit, old unit will be replaced">Unit name</th>
<th style="width:5em" data-tip="Select allowed biomes">Biomes</th>
<th style="width:5em" data-tip="Select allowed states">States</th>
<th style="width:5em" data-tip="Select allowed cultures">Cultures</th>
<th style="width:5em" data-tip="Select allowed religions">Religions</th>
<th data-tip="Conscription percentage for rural population">Rural</th>
<th data-tip="Conscription percentage for urban population">Urban</th>
<th data-tip="Average number of people in crew (used for total personnel calculation)">Crew</th>
@ -3331,6 +3399,28 @@
</div>
</div>
<div id="markersOverview" class="dialog stable" style="display: none">
<div id="markersHeader" class="header">
<div style="left:1em" data-tip="Click to sort by marker type" class="sortable alphabetically" data-sortby="type">Type&nbsp;</div>
<div id="markersInverPin" style="left:14.9em; color: #6e5e66" data-tip="Click to invert pin state for all markers" class="icon-pin pointer"></div>
<div id="markersInverLock" style="left:16.1em; color: #6e5e66" data-tip="Click to invert lock state for all markers" class="icon-lock pointer"></div>
</div>
<div id="markersBody" class="table"></div>
<div id="markersFooter" class="totalLine">
<div data-tip="Markers number" style="margin-left: 4px">Total:&nbsp;<span id="markersFooterNumber">0</span>&nbsp;markers</div>
</div>
<div id="markersBottom">
<button id="markersOverviewRefresh" data-tip="Refresh the Overview screen" class="icon-cw"></button>
<button id="markersAddFromOverview" data-tip="Add a new marker. Hold Shift to add multiple" class="icon-plus"></button>
<button id="markersGenerationConfig" data-tip="Config markers generation options" class="icon-cog"></button>
<button id="markersRemoveAll" data-tip="Remove all unlocked markers" class="icon-trash"></button>
<button id="markersExport" data-tip="Save markers data as a text file (.csv)" class="icon-download"></button>
</div>
</div>
<div id="styleSaver" class="dialog stable textual" style="display: none">
<div id="styleSaverHeader" style="padding:2px 0">
<span>Preset name:</span>
@ -3505,7 +3595,7 @@
<div style="margin-top: .3em">
<strong>Save map to</strong>
<button onclick="dowloadMap()" data-tip="Download .map file to your local disk. Shortcut: Ctrl + S">machine</button>
<button onclick="saveToDropbox()" data-tip="Save .map file to your Dropbox">dropbox</button>
<button onclick="saveToDropbox()" data-tip="Save .map file to your Dropbox. Shortcut: Ctrl + C">dropbox</button>
<button onclick="quickSave()" data-tip="Save the project to browser storage. It can be unreliable. Shortcut: F6">browser</button>
</div>
<p>Maps are saved in <i>.map</i> format, that can be loaded back via the <i>Load</i> in menu. There is no way to restore the progress if file is lost. Please keep old <i>.map</i> files on your machine or cloud storage as backups.</p>
@ -3514,7 +3604,7 @@
<div id="loadMapData" style="display: none" class="dialog">
<div>
<strong>Load map from</strong>
<button onclick="mapToLoad.click()" data-tip="Load .map file from local disk">local disk</button>
<button onclick="mapToLoad.click()" data-tip="Load .map file from your local disk">machine</button>
<button onclick="loadURL()" data-tip="Load .map file from URL (server should allow CORS)">URL</button>
<button onclick="quickLoad()" data-tip="Load map from browser storage (if saved before)">storage</button>
</div>
@ -3540,12 +3630,12 @@
<p>Map will be split into tiles and downloaded as a single zip file. Avoid saving to big images</p>
<div data-tip="Number of columns" style="margin-bottom: .3em">
<div class="label">Columns:</div>
<input id="tileColsInput" data-stored="tileCols" type="range" min=2 max=20 value=8 style="width: 11em">
<input id="tileColsInput" data-stored="tileCols" type="range" min=2 max=20 value=8 style="width: 10em">
<input id="tileColsOutput" data-stored="tileCols" type="number" min=2 value=8 >
</div>
<div data-tip="Number of rows" style="margin-bottom: .3em">
<div class="label">Rows:</div>
<input id="tileRowsInput" data-stored="tileRows" type="range" min=2 max=20 value=8 style="width: 11em">
<input id="tileRowsInput" data-stored="tileRows" type="range" min=2 max=20 value=8 style="width: 10em">
<input id="tileRowsOutput" data-stored="tileRows" type="number" min=2 value=8 >
</div>
<div data-tip="Image scale relative to image size (e.g. 5x)" style="margin-bottom: .3em">
@ -4284,13 +4374,23 @@
</defs>
</svg>
<!-- <script src="libs/translate.js"></script> -->
<script src="libs/jquery-3.1.1.min.js"></script>
<script src="libs/d3.min.js"></script>
<script src="libs/priority-queue.min.js"></script>
<script src="libs/delaunator.min.js"></script>
<script src="libs/lodash.min.js"></script>
<script src="modules/utils.js"></script>
<script src="utils/commonUtils.js"></script>
<script src="utils/arrayUtils.js"></script>
<script src="utils/colorUtils.js"></script>
<script src="utils/graphUtils.js"></script>
<script src="utils/nodeUtils.js"></script>
<script src="utils/numberUtils.js"></script>
<script src="utils/polyfills.js"></script>
<script src="utils/probabilityUtils.js"></script>
<script src="utils/stringUtils.js"></script>
<script src="utils/unitUtils.js"></script>
<script src="modules/voronoi.js"></script>
<script src="modules/heightmap-templates.js"></script>
<script src="modules/heightmap-generator.js"></script>
@ -4303,6 +4403,7 @@
<script src="modules/routes-generator.js"></script>
<script src="modules/religions-generator.js"></script>
<script src="modules/military-generator.js"></script>
<script src="modules/markers-generator.js"></script>
<script src="modules/coa-generator.js"></script>
<script src="modules/submap.js"></script>
<script src="libs/polylabel.min.js"></script>
@ -4312,18 +4413,21 @@
<script src="modules/fonts.js"></script>
<script src="modules/ui/layers.js"></script>
<script src="modules/ui/measurers.js"></script>
<!-- <script src="libs/umami.js"></script> -->
<script defer src="https://unpkg.com/dropbox@10.8.0/dist/Dropbox-sdk.min.js"></script>
<script defer src="modules/ui/general.js"></script>
<script defer src="modules/ui/options.js"></script>
<script defer src="modules/ui/style.js"></script>
<script defer src="modules/save.js"></script>
<script defer src="modules/load.js"></script>
<script defer src="modules/cloud.js"></script>
<script defer src="main.js"></script>
<script defer src="modules/save.js"></script>
<script defer src="modules/export.js"></script>
<script defer src="modules/relief-icons.js"></script>
<script defer src="modules/ui/tools.js"></script>
<script defer src="modules/ui/world-configurator.js"></script>
<script defer src="modules/ui/editors.js"></script>
<script defer src="modules/ui/heightmap-editor.js"></script>
<script defer src="modules/ui/states-editor.js"></script>
<script defer src="modules/ui/provinces-editor.js"></script>
@ -4350,13 +4454,14 @@
<script defer src="modules/ui/rivers-overview.js"></script>
<script defer src="modules/ui/military-overview.js"></script>
<script defer src="modules/ui/regiments-overview.js"></script>
<script defer src="modules/ui/markers-overview.js"></script>
<script defer src="modules/ui/regiment-editor.js"></script>
<script defer src="modules/ui/battle-screen.js"></script>
<script defer src="modules/coa-renderer.js"></script>
<script defer src="modules/ui/emblems-editor.js"></script>
<script defer src="modules/ui/editors.js"></script>
<script defer src="modules/ui/3d.js"></script>
<script defer src="modules/ui/submap.js"></script>
<script defer src="modules/ui/hotkeys.js"></script>
<script defer src="libs/rgbquant.min.js"></script>
<script defer src="libs/jquery.ui.touch-punch.min.js"></script>
<script defer src="libs/pell.min.js"></script>

2
libs/dropins.min.js vendored

File diff suppressed because one or more lines are too long

44
libs/jquery-ui.css vendored
View file

@ -53,7 +53,6 @@
z-index: 100;
}
/* Interaction Cues
----------------------------------*/
.ui-state-disabled {
@ -61,13 +60,12 @@
pointer-events: none;
}
/* Icons
----------------------------------*/
.ui-icon {
display: inline-block;
vertical-align: middle;
margin-top: -.25em;
margin-top: -0.25em;
position: relative;
text-indent: -99999px;
overflow: hidden;
@ -166,11 +164,11 @@
touch-action: none;
}
.ui-button {
padding: .4em 1em;
padding: 0.4em 1em;
display: inline-block;
position: relative;
line-height: normal;
margin-right: .1em;
margin-right: 0.1em;
cursor: pointer;
vertical-align: middle;
text-align: center;
@ -213,7 +211,6 @@
height: 2.1em;
text-indent: -9999px;
white-space: nowrap;
}
input.ui-button.ui-icon-notext .ui-icon {
@ -221,7 +218,7 @@ input.ui-button.ui-icon-notext .ui-icon {
height: auto;
text-indent: 0;
white-space: normal;
padding: .4em 1em;
padding: 0.4em 1em;
}
/* workarounds */
@ -256,7 +253,7 @@ button.ui-button::-moz-focus-inner {
box-sizing: border-box;
}
.ui-controlgroup .ui-controlgroup-label {
padding: .4em 1em;
padding: 0.4em 1em;
}
.ui-controlgroup .ui-controlgroup-label span {
font-size: 80%;
@ -276,7 +273,6 @@ button.ui-button::-moz-focus-inner {
/* Spinner specific style fixes */
.ui-controlgroup-vertical .ui-spinner-input {
/* Support: IE8 only, Android < 4.4 only */
width: 75%;
width: calc(100% - 2.4em);
@ -287,7 +283,7 @@ button.ui-button::-moz-focus-inner {
.ui-checkboxradio-label .ui-icon-background {
box-shadow: inset 1px 1px 1px #ccc;
border-radius: .12em;
border-radius: 0.12em;
border: none;
}
.ui-checkboxradio-radio-label .ui-icon-background {
@ -317,14 +313,14 @@ body .ui-dialog {
background-color: inherit;
}
.ui-dialog .ui-dialog-titlebar {
padding: .4em 1em;
padding: 0.4em 1em;
position: relative;
font-size: 1.2em;
min-width: 150px;
}
.ui-dialog .ui-dialog-title {
float: left;
margin: .1em 0;
margin: 0.1em 0;
white-space: nowrap;
width: 90%;
overflow: hidden;
@ -333,14 +329,14 @@ body .ui-dialog {
.ui-dialog .ui-dialog-titlebar button {
position: absolute;
right: .5em;
right: 0.5em;
top: 53%;
padding: 0;
width: 1.8em;
height: 1.8em;
color: #ffffff;
background: none;
font-size: .75em;
font-size: 0.75em;
border: 1px solid #c5c5c5;
}
@ -360,7 +356,7 @@ body .ui-dialog {
.ui-dialog .ui-dialog-content {
position: relative;
border: 0;
padding: .5em 1em;
padding: 0.5em 1em;
background: none;
overflow-y: auto;
overflow-x: hidden;
@ -369,14 +365,14 @@ body .ui-dialog {
text-align: left;
border-width: 1px 0 0 0;
background-image: none;
margin-top: .5em;
padding: .3em 1em .5em .4em;
margin-top: 0.5em;
padding: 0.3em 1em 0.5em 0.4em;
}
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset {
float: right;
}
.ui-dialog .ui-dialog-buttonpane button {
margin: .5em .4em .5em 0;
margin: 0.5em 0.4em 0.5em 0;
cursor: pointer;
}
.ui-dialog .ui-resizable-n {
@ -448,12 +444,6 @@ body .ui-dialog {
.ui-widget-content a {
color: #333333;
}
.ui-widget-header {
border-bottom: 1px solid #5d4651;
background: #916e7f;
color: #ffffff;
font-weight: bold;
}
.ui-widget-header a {
color: #333333;
}
@ -548,14 +538,14 @@ a.ui-button:focus {
.ui-priority-secondary,
.ui-widget-content .ui-priority-secondary,
.ui-widget-header .ui-priority-secondary {
opacity: .7;
opacity: 0.7;
filter: Alpha(Opacity=70); /* support: IE8 */
font-weight: normal;
}
.ui-state-disabled,
.ui-widget-content .ui-state-disabled,
.ui-widget-header .ui-state-disabled {
opacity: .35;
opacity: 0.35;
filter: Alpha(Opacity=35); /* support: IE8 */
background-image: none;
}
@ -568,7 +558,7 @@ a.ui-button:focus {
/* Overlays */
.ui-widget-overlay {
background: #aaaaaa;
opacity: .3;
opacity: 0.3;
filter: Alpha(Opacity=30); /* support: IE8 */
}
.ui-widget-shadow {

View file

@ -1,157 +0,0 @@
"use strict";
window.Pell = (function () {
const defaultParagraphSeparatorString = "defaultParagraphSeparator";
const formatBlock = "formatBlock";
const addEventListener = (parent, type, listener) => parent.addEventListener(type, listener);
const appendChild = (parent, child) => parent.appendChild(child);
const createElement = tag => document.createElement(tag);
const queryCommandState = command => document.queryCommandState(command);
const queryCommandValue = command => document.queryCommandValue(command);
const exec = (command, value = null) => document.execCommand(command, false, value);
const defaultActions = {
bold: {
icon: "<b>B</b>",
title: "Bold",
state: () => queryCommandState("bold"),
result: () => exec("bold")
},
italic: {
icon: "<i>I</i>",
title: "Italic",
state: () => queryCommandState("italic"),
result: () => exec("italic")
},
underline: {
icon: "<u>U</u>",
title: "Underline",
state: () => queryCommandState("underline"),
result: () => exec("underline")
},
strikethrough: {
icon: "<strike>S</strike>",
title: "Strike-through",
state: () => queryCommandState("strikeThrough"),
result: () => exec("strikeThrough")
},
heading1: {
icon: "<b>H<sub>1</sub></b>",
title: "Heading 1",
result: () => exec(formatBlock, "<h1>")
},
heading2: {
icon: "<b>H<sub>2</sub></b>",
title: "Heading 2",
result: () => exec(formatBlock, "<h2>")
},
paragraph: {
icon: "&#182;",
title: "Paragraph",
result: () => exec(formatBlock, "<p>")
},
quote: {
icon: "&#8220; &#8221;",
title: "Quote",
result: () => exec(formatBlock, "<blockquote>")
},
olist: {
icon: "&#35;",
title: "Ordered List",
result: () => exec("insertOrderedList")
},
ulist: {
icon: "&#8226;",
title: "Unordered List",
result: () => exec("insertUnorderedList")
},
code: {
icon: "&lt;/&gt;",
title: "Code",
result: () => exec(formatBlock, "<pre>")
},
line: {
icon: "&#8213;",
title: "Horizontal Line",
result: () => exec("insertHorizontalRule")
},
link: {
icon: "&#128279;",
title: "Link",
result: () => navigator.clipboard.readText().then(url => exec("createLink", url))
},
image: {
icon: "&#128247;",
title: "Image",
result: () => {
navigator.clipboard.readText().then(url => exec("insertImage", url));
exec("enableObjectResizing");
}
}
};
const defaultClasses = {
actionbar: "pell-actionbar",
button: "pell-button",
content: "pell-content",
selected: "pell-button-selected"
};
const init = settings => {
const actions = settings.actions
? settings.actions.map(action => {
if (typeof action === "string") return defaultActions[action];
else if (defaultActions[action.name]) return {...defaultActions[action.name], ...action};
return action;
})
: Object.keys(defaultActions).map(action => defaultActions[action]);
const classes = {...defaultClasses, ...settings.classes};
const defaultParagraphSeparator = settings[defaultParagraphSeparatorString] || "div";
const actionbar = createElement("div");
actionbar.className = classes.actionbar;
appendChild(settings.element, actionbar);
const content = (settings.element.content = createElement("div"));
content.contentEditable = true;
content.className = classes.content;
content.oninput = ({target: {firstChild}}) => {
if (firstChild && firstChild.nodeType === 3) exec(formatBlock, `<${defaultParagraphSeparator}>`);
else if (content.innerHTML === "<br>") content.innerHTML = "";
settings.onChange(content.innerHTML);
};
content.onkeydown = event => {
if (event.key === "Enter" && queryCommandValue(formatBlock) === "blockquote") {
setTimeout(() => exec(formatBlock, `<${defaultParagraphSeparator}>`), 0);
}
};
appendChild(settings.element, content);
actions.forEach(action => {
const button = createElement("button");
button.className = classes.button;
button.innerHTML = action.icon;
button.title = action.title;
button.setAttribute("type", "button");
button.onclick = () => action.result() && content.focus();
if (action.state) {
const handler = () => button.classList[action.state() ? "add" : "remove"](classes.selected);
addEventListener(content, "keyup", handler);
addEventListener(content, "mouseup", handler);
addEventListener(button, "click", handler);
}
appendChild(actionbar, button);
});
if (settings.styleWithCSS) exec("styleWithCSS");
exec(defaultParagraphSeparatorString, defaultParagraphSeparator);
return settings.element;
};
return {exec, init};
})();

36
libs/umami.js Normal file
View file

@ -0,0 +1,36 @@
(window => {
const noTrack = !location.hostname || window.localStorage.getItem("noTrack");
const {
screen: {width, height},
navigator: {language},
location: {hostname, pathname, search},
document: {referrer}
} = window;
const website = "4f6fd0ae-646a-4946-a9da-7aad63284e48";
const root = "https://fmg-stats.herokuapp.com";
const screen = `${width}x${height}`;
const url = `${pathname}${search}`;
const post = (url, data) => {
const req = new XMLHttpRequest();
req.open("POST", url, true);
req.setRequestHeader("Content-Type", "application/json");
req.send(JSON.stringify(data));
};
const collect = (type, params) => {
if (noTrack) return;
const payload = {website, hostname, screen, language, cache: false};
Object.keys(params).forEach(key => {
payload[key] = params[key];
});
post(`${root}/api/collect`, {type, payload});
};
collect("pageview", {url, referrer});
window.track = (event_type = "reach", event_value = "") => collect("event", {event_type, event_value, url});
})(window);

350
main.js
View file

@ -2,11 +2,11 @@
// https://github.com/Azgaar/Fantasy-Map-Generator
"use strict";
const version = "1.661"; // generator version
const version = "1.71"; // generator version
document.title += " v" + version;
// Switches to disable/enable logging features
const PRODUCTION = window.location.host;
const PRODUCTION = location.hostname && location.hostname !== "localhost" && location.hostname !== "127.0.0.1";
const DEBUG = localStorage.getItem("debug");
const INFO = DEBUG || !PRODUCTION;
const TIME = DEBUG || !PRODUCTION;
@ -64,7 +64,7 @@ let icons = viewbox.append("g").attr("id", "icons");
let burgIcons = icons.append("g").attr("id", "burgIcons");
let anchors = icons.append("g").attr("id", "anchors");
let armies = viewbox.append("g").attr("id", "armies").style("display", "none");
let markers = viewbox.append("g").attr("id", "markers").style("display", "none");
let markers = viewbox.append("g").attr("id", "markers");
let fogging = viewbox.append("g").attr("id", "fogging-cont").attr("mask", "url(#fog)").append("g").attr("id", "fogging").style("display", "none");
let ruler = viewbox.append("g").attr("id", "ruler").style("display", "none");
let debug = viewbox.append("g").attr("id", "debug");
@ -111,14 +111,14 @@ legend.on("mousemove", () => tip("Drag to change the position. Click to hide the
// main data variables
let grid = {}; // initial grapg based on jittered square grid and data
let pack = {}; // packed graph and data
let seed,
mapId,
mapHistory = [],
elSelected,
modules = {},
notes = [];
let seed;
let mapId;
let mapHistory = [];
let elSelected;
let modules = {};
let notes = [];
let rulers = new Rulers();
let customization = 0; // 0 - no; 1 = heightmap draw; 2 - states draw; 3 - add state/burg; 4 - cultures draw
let customization = 0;
let biomesData = applyDefaultBiomesSystem();
let nameBases = Names.getNameBases(); // cultures-related data
@ -147,29 +147,37 @@ function zoomed() {
const zoom = d3.zoom().scaleExtent([1, 20]).on("zoom", zoomed);
// default options
let options = {pinNotes: false}; // options object
let options = {
pinNotes: false,
showMFCGMap: true,
winds: [225, 45, 225, 315, 135, 315],
stateLabelsMode: "auto"
};
let mapCoordinates = {}; // map coordinates on globe
options.winds = [225, 45, 225, 315, 135, 315]; // default wind directions
let populationRate = +document.getElementById("populationRateInput").value;
let distanceScale = +document.getElementById("distanceScaleInput").value;
let urbanization = +document.getElementById("urbanizationInput").value;
let urbanDensity = +document.getElementById("urbanDensityInput").value;
applyStoredOptions();
let graphWidth = +mapWidthInput.value,
graphHeight = +mapHeightInput.value; // voronoi graph extention, cannot be changed arter generation
let svgWidth = graphWidth,
svgHeight = graphHeight; // svg canvas resolution, can be changed
// voronoi graph extention, cannot be changed arter generation
let graphWidth = +mapWidthInput.value;
let graphHeight = +mapHeightInput.value;
// svg canvas resolution, can be changed
let svgWidth = graphWidth;
let svgHeight = graphHeight;
landmass.append("rect").attr("x", 0).attr("y", 0).attr("width", graphWidth).attr("height", graphHeight);
oceanPattern.append("rect").attr("fill", "url(#oceanic)").attr("x", 0).attr("y", 0).attr("width", graphWidth).attr("height", graphHeight);
oceanLayers.append("rect").attr("id", "oceanBase").attr("x", 0).attr("y", 0).attr("width", graphWidth).attr("height", graphHeight);
void (function removeLoading() {
// remove loading screen
d3.select("#loading").transition().duration(4000).style("opacity", 0).remove();
d3.select("#initial").transition().duration(4000).attr("opacity", 0).remove();
d3.select("#optionsContainer").transition().duration(3000).style("opacity", 1);
d3.select("#tooltip").transition().duration(4000).style("opacity", 1);
})();
// decide which map should be loaded or generated on page load
void (function checkLoadParameters() {
@ -319,7 +327,6 @@ function findBurgForMFCG(params) {
else if (p[0] === "shantytown") b.shanty = +p[1];
else b[p[0]] = +p[1]; // other parameters
}
b.MFCGlink = document.referrer; // set direct link to MFCG
if (params.get("name") && params.get("name") != "null") b.name = params.get("name");
const label = burgLabels.select("[data-id='" + burgId + "']");
@ -340,11 +347,39 @@ function findBurgForMFCG(params) {
// apply default biomes data
function applyDefaultBiomesSystem() {
const name = ["Marine", "Hot desert", "Cold desert", "Savanna", "Grassland", "Tropical seasonal forest", "Temperate deciduous forest", "Tropical rainforest", "Temperate rainforest", "Taiga", "Tundra", "Glacier", "Wetland"];
const name = [
"Marine",
"Hot desert",
"Cold desert",
"Savanna",
"Grassland",
"Tropical seasonal forest",
"Temperate deciduous forest",
"Tropical rainforest",
"Temperate rainforest",
"Taiga",
"Tundra",
"Glacier",
"Wetland"
];
const color = ["#466eab", "#fbe79f", "#b5b887", "#d2d082", "#c8d68f", "#b6d95d", "#29bc56", "#7dcb35", "#409c43", "#4b6b32", "#96784b", "#d5e7eb", "#0b9131"];
const habitability = [0, 4, 10, 22, 30, 50, 100, 80, 90, 12, 4, 0, 12];
const iconsDensity = [0, 3, 2, 120, 120, 120, 120, 150, 150, 100, 5, 0, 150];
const icons = [{}, {dune: 3, cactus: 6, deadTree: 1}, {dune: 9, deadTree: 1}, {acacia: 1, grass: 9}, {grass: 1}, {acacia: 8, palm: 1}, {deciduous: 1}, {acacia: 5, palm: 3, deciduous: 1, swamp: 1}, {deciduous: 6, swamp: 1}, {conifer: 1}, {grass: 1}, {}, {swamp: 1}];
const icons = [
{},
{dune: 3, cactus: 6, deadTree: 1},
{dune: 9, deadTree: 1},
{acacia: 1, grass: 9},
{grass: 1},
{acacia: 8, palm: 1},
{deciduous: 1},
{acacia: 5, palm: 3, deciduous: 1, swamp: 1},
{deciduous: 6, swamp: 1},
{conifer: 1},
{grass: 1},
{},
{swamp: 1}
];
const cost = [10, 200, 150, 60, 50, 70, 70, 80, 90, 200, 1000, 5000, 150]; // biome movement cost
const biomesMartix = [
// hot ↔ cold [>19°C; <-4°C]; dry ↕ wet
@ -378,15 +413,19 @@ function showWelcomeMessage() {
alertMessage.innerHTML = `The Fantasy Map Generator is updated up to version <b>${version}</b>.
This version is compatible with ${changelog}, loaded <i>.map</i> files will be auto-updated.
<ul>Main changes:
<li>Add custom fonts dialog</li>
<li>Save and load <i>.map</i> files to Dropbox</li>
<li>Ability to add control points on river edit</li>
<li>New heightmap template: Taklamakan</li>
<li>Option to not scale labels on zoom</li>
<li>Ability to limit military units by biome, state, culture and religion</li>
<li>New marker types</li>
<li>New markers editor</li>
<li>Markers overview screen</li>
<li>Markers regeneration menu</li>
<li>Burg editor update</li>
<li>Editable theme color</li>
<li>Add font dialog</li>
<li>Save to Dropbox</li>
</ul>
<p>Join our ${discord} and ${reddit} to ask questions, share maps, discuss the Generator and Worlbuilding, report bugs and propose new features.</p>
<span>Thanks for all supporters on ${patreon}!</i></span>`;
<span>Thanks for all supporters on <a href="https://www.patreon.com/azgaar" target="_blank">Patreon</a>!</i></span>`;
$("#alert").dialog({
resizable: false,
@ -438,10 +477,8 @@ function resetZoom(d = 1000) {
svg.transition().duration(d).call(zoom.transform, d3.zoomIdentity);
}
// calculate x,y extreme points of viewBox
// calculate x y extreme points of viewBox
function getViewBoxExtent() {
// x = trX / scale * -1 + graphWidth / scale
// y = trY / scale * -1 + graphHeight / scale
return [
[Math.abs(viewX / scale), Math.abs(viewY / scale)],
[Math.abs(viewX / scale) + graphWidth / scale, Math.abs(viewY / scale) + graphHeight / scale]
@ -495,19 +532,18 @@ function invokeActiveZooming() {
}
// rescale map markers
if (+markers.attr("rescale") && markers.style("display") !== "none") {
markers.selectAll("use").each(function () {
const x = +this.dataset.x,
y = +this.dataset.y,
desired = +this.dataset.size;
const size = Math.max(desired * 5 + 25 / scale, 1);
d3.select(this)
.attr("x", x - size / 2)
.attr("y", y - size)
.attr("width", size)
.attr("height", size);
+markers.attr("rescale") &&
pack.markers?.forEach(marker => {
const {i, x, y, size = 30, hidden} = marker;
const el = !hidden && document.getElementById(`marker${i}`);
if (!el) return;
const zoomedSize = Math.max(rn(size / 5 + 24 / scale, 2), 1);
el.setAttribute("width", zoomedSize);
el.setAttribute("height", zoomedSize);
el.setAttribute("x", rn(x - zoomedSize / 2, 1));
el.setAttribute("y", rn(y - zoomedSize, 1));
});
}
// rescale rulers to have always the same size
if (ruler.style("display") !== "none") {
@ -620,7 +656,7 @@ function generate() {
Lakes.generateName();
Military.generate();
addMarkers();
Markers.generate();
addZones();
Names.getMapName();
@ -629,11 +665,12 @@ function generate() {
INFO && console.groupEnd("Generated Map " + seed);
} catch (error) {
ERROR && console.error(error);
const parsedError = parseError(error);
clearMainTip();
alertMessage.innerHTML = `An error is occured on map generation. Please retry.
<br>If error is critical, clear the stored data and try again.
<p id="errorBox">${parseError(error)}</p>`;
<p id="errorBox">${parsedError}</p>`;
$("#alert").dialog({
resizable: false,
title: "Generation error",
@ -644,7 +681,7 @@ function generate() {
localStorage.setItem("version", version);
},
Regenerate: function () {
regenerateMap();
regenerateMap("generation error");
$(this).dialog("close");
},
Ignore: function () {
@ -673,6 +710,7 @@ function generateSeed() {
// Place points to calculate Voronoi diagram
function placePoints() {
TIME && console.time("placePoints");
Math.random = aleaPRNG(seed); // reset PRNG
const cellsDesired = +pointsInput.dataset.cells;
const spacing = (grid.spacing = rn(Math.sqrt((graphWidth * graphHeight) / cellsDesired), 2)); // spacing between points before jirrering
@ -922,7 +960,7 @@ function calculateTemperatures() {
const lat = Math.abs(mapCoordinates.latN - (y / graphHeight) * mapCoordinates.latT); // [0; 90]
const initTemp = tEq - int(lat / 90) * tDelta;
for (let i = r; i < r + grid.cellsX; i++) {
cells.temp[i] = Math.max(Math.min(initTemp - convertToFriendly(cells.h[i]), 127), -128);
cells.temp[i] = minmax(initTemp - convertToFriendly(cells.h[i]), -128, 127);
}
});
@ -1037,7 +1075,7 @@ function generatePrecipitation() {
const precipitation = isPassable ? getPrecipitation(humidity, current, next) : humidity;
cells.prec[current] += precipitation;
const evaporation = precipitation > 1.5 ? 1 : 0; // some humidity evaporates back to the atmosphere
humidity = isPassable ? Math.min(Math.max(humidity - precipitation + evaporation, 0), maxPrec) : 0;
humidity = isPassable ? minmax(humidity - precipitation + evaporation, 0, maxPrec) : 0;
}
}
}
@ -1046,7 +1084,7 @@ function generatePrecipitation() {
const normalLoss = Math.max(humidity / (10 * modifier), 1); // precipitation in normal conditions
const diff = Math.max(cells.h[i + n] - cells.h[i], 0); // difference in height
const mod = (cells.h[i + n] / 70) ** 2; // 50 stands for hills, 70 for mountains
return Math.min(Math.max(normalLoss + diff * mod, 1), humidity);
return minmax(normalLoss + diff * mod, 1, humidity);
}
void (function drawWindDirection() {
@ -1438,205 +1476,6 @@ function rankCells() {
TIME && console.timeEnd("rankCells");
}
// generate some markers
function addMarkers(number = 1) {
if (!number) return;
TIME && console.time("addMarkers");
const cells = pack.cells,
states = pack.states;
void (function addVolcanoes() {
let mounts = Array.from(cells.i)
.filter(i => cells.h[i] > 70)
.sort((a, b) => cells.h[b] - cells.h[a]);
let count = mounts.length < 10 ? 0 : Math.ceil((mounts.length / 300) * number);
if (count) addMarker("volcano", "🌋", 52, 50, 13);
while (count && mounts.length) {
const cell = mounts.splice(biased(0, mounts.length - 1, 5), 1);
const x = cells.p[cell][0],
y = cells.p[cell][1];
const id = appendMarker(cell, "volcano");
const proper = Names.getCulture(cells.culture[cell]);
const name = P(0.3) ? "Mount " + proper : Math.random() > 0.3 ? proper + " Volcano" : proper;
notes.push({id, name, legend: `Active volcano. Height: ${getFriendlyHeight([x, y])}`});
count--;
}
})();
void (function addHotSprings() {
let springs = Array.from(cells.i)
.filter(i => cells.h[i] > 50)
.sort((a, b) => cells.h[b] - cells.h[a]);
let count = springs.length < 30 ? 0 : Math.ceil((springs.length / 1000) * number);
if (count) addMarker("hot_springs", "♨️", 50, 52, 12.5);
while (count && springs.length) {
const cell = springs.splice(biased(1, springs.length - 1, 3), 1);
const id = appendMarker(cell, "hot_springs");
const proper = Names.getCulture(cells.culture[cell]);
const temp = convertTemperature(gauss(30, 15, 20, 100));
notes.push({id, name: proper + " Hot Springs", legend: `A hot springs area. Temperature: ${temp}`});
count--;
}
})();
void (function addMines() {
let hills = Array.from(cells.i).filter(i => cells.h[i] > 47 && cells.burg[i]);
let count = !hills.length ? 0 : Math.ceil((hills.length / 7) * number);
if (!count) return;
addMarker("mine", "⛏️", 48, 50, 13.5);
const resources = {salt: 5, gold: 2, silver: 4, copper: 2, iron: 3, lead: 1, tin: 1};
while (count && hills.length) {
const cell = hills.splice(Math.floor(Math.random() * hills.length), 1);
const id = appendMarker(cell, "mine");
const resource = rw(resources);
const burg = pack.burgs[cells.burg[cell]];
const name = `${burg.name}${resource} mining town`;
const population = rn(burg.population * populationRate * urbanization);
const legend = `${burg.name} is a mining town of ${population} people just nearby the ${resource} mine`;
notes.push({id, name, legend});
count--;
}
})();
void (function addBridges() {
const meanRoad = d3.mean(cells.road.filter(r => r));
const meanFlux = d3.mean(cells.fl.filter(fl => fl));
let bridges = Array.from(cells.i)
.filter(i => cells.burg[i] && cells.h[i] >= 20 && cells.r[i] && cells.fl[i] > meanFlux && cells.road[i] > meanRoad)
.sort((a, b) => cells.road[b] + cells.fl[b] / 10 - (cells.road[a] + cells.fl[a] / 10));
let count = !bridges.length ? 0 : Math.ceil((bridges.length / 12) * number);
if (count) addMarker("bridge", "🌉", 50, 50, 14);
while (count && bridges.length) {
const cell = bridges.splice(0, 1);
const id = appendMarker(cell, "bridge");
const burg = pack.burgs[cells.burg[cell]];
const river = pack.rivers.find(r => r.i === pack.cells.r[cell]);
const riverName = river ? `${river.name} ${river.type}` : "river";
const name = river && P(0.2) ? river.name : burg.name;
notes.push({id, name: `${name} Bridge`, legend: `A stone bridge over the ${riverName} near ${burg.name}`});
count--;
}
})();
void (function addInns() {
const maxRoad = d3.max(cells.road) * 0.9;
let taverns = Array.from(cells.i).filter(i => cells.crossroad[i] && cells.h[i] >= 20 && cells.road[i] > maxRoad);
if (!taverns.length) return;
const count = Math.ceil(4 * number);
addMarker("inn", "🍻", 50, 50, 14.5);
const color = ["Dark", "Light", "Bright", "Golden", "White", "Black", "Red", "Pink", "Purple", "Blue", "Green", "Yellow", "Amber", "Orange", "Brown", "Grey"];
const animal = ["Antelope", "Ape", "Badger", "Bear", "Beaver", "Bison", "Boar", "Buffalo", "Cat", "Crane", "Crocodile", "Crow", "Deer", "Dog", "Eagle", "Elk", "Fox", "Goat", "Goose", "Hare", "Hawk", "Heron", "Horse", "Hyena", "Ibis", "Jackal", "Jaguar", "Lark", "Leopard", "Lion", "Mantis", "Marten", "Moose", "Mule", "Narwhal", "Owl", "Panther", "Rat", "Raven", "Rook", "Scorpion", "Shark", "Sheep", "Snake", "Spider", "Swan", "Tiger", "Turtle", "Wolf", "Wolverine", "Camel", "Falcon", "Hound", "Ox"];
const adj = ["New", "Good", "High", "Old", "Great", "Big", "Major", "Happy", "Main", "Huge", "Far", "Beautiful", "Fair", "Prime", "Ancient", "Golden", "Proud", "Lucky", "Fat", "Honest", "Giant", "Distant", "Friendly", "Loud", "Hungry", "Magical", "Superior", "Peaceful", "Frozen", "Divine", "Favorable", "Brave", "Sunny", "Flying"];
for (let i = 0; i < taverns.length && i < count; i++) {
const cell = taverns.splice(Math.floor(Math.random() * taverns.length), 1);
const id = appendMarker(cell, "inn");
const type = P(0.3) ? "inn" : "tavern";
const name = P(0.5) ? ra(color) + " " + ra(animal) : P(0.6) ? ra(adj) + " " + ra(animal) : ra(adj) + " " + capitalize(type);
notes.push({id, name: "The " + name, legend: `A big and famous roadside ${type}`});
}
})();
void (function addLighthouses() {
const lands = cells.i.filter(i => cells.harbor[i] > 6 && cells.c[i].some(c => cells.h[c] < 20 && cells.road[c]));
const lighthouses = Array.from(lands).map(i => [i, cells.v[i][cells.c[i].findIndex(c => cells.h[c] < 20 && cells.road[c])]]);
if (lighthouses.length) addMarker("lighthouse", "🚨", 50, 50, 16);
const count = Math.ceil(4 * number);
for (let i = 0; i < lighthouses.length && i < count; i++) {
const cell = lighthouses[i][0],
vertex = lighthouses[i][1];
const id = appendMarker(cell, "lighthouse");
const proper = cells.burg[cell] ? pack.burgs[cells.burg[cell]].name : Names.getCulture(cells.culture[cell]);
notes.push({id, name: getAdjective(proper) + " Lighthouse" + name, legend: `A lighthouse to keep the navigation safe`});
}
})();
void (function addWaterfalls() {
const waterfalls = cells.i.filter(i => cells.r[i] && cells.h[i] > 70);
if (waterfalls.length) addMarker("waterfall", "⟱", 50, 54, 16.5);
const count = Math.ceil(3 * number);
for (let i = 0; i < waterfalls.length && i < count; i++) {
const cell = waterfalls[i];
const id = appendMarker(cell, "waterfall");
const proper = cells.burg[cell] ? pack.burgs[cells.burg[cell]].name : Names.getCulture(cells.culture[cell]);
notes.push({id, name: getAdjective(proper) + " Waterfall" + name, legend: `An extremely beautiful waterfall`});
}
})();
void (function addBattlefields() {
let battlefields = Array.from(cells.i).filter(i => cells.state[i] && cells.pop[i] > 2 && cells.h[i] < 50 && cells.h[i] > 25);
let count = battlefields.length < 100 ? 0 : Math.ceil((battlefields.length / 500) * number);
if (count) addMarker("battlefield", "⚔️", 50, 52, 12);
while (count && battlefields.length) {
const cell = battlefields.splice(Math.floor(Math.random() * battlefields.length), 1);
const id = appendMarker(cell, "battlefield");
const campaign = ra(states[cells.state[cell]].campaigns);
const date = generateDate(campaign.start, campaign.end);
const name = Names.getCulture(cells.culture[cell]) + " Battlefield";
const legend = `A historical battle of the ${campaign.name}. \r\nDate: ${date} ${options.era}`;
notes.push({id, name, legend});
count--;
}
})();
function addMarker(id, icon, x, y, size) {
const markers = svg.select("#defs-markers");
if (markers.select("#marker_" + id).size()) return;
const symbol = markers
.append("symbol")
.attr("id", "marker_" + id)
.attr("viewBox", "0 0 30 30");
symbol.append("path").attr("d", "M6,19 l9,10 L24,19").attr("fill", "#000000").attr("stroke", "none");
symbol.append("circle").attr("cx", 15).attr("cy", 15).attr("r", 10).attr("fill", "#ffffff").attr("stroke", "#000000").attr("stroke-width", 1);
symbol
.append("text")
.attr("x", x + "%")
.attr("y", y + "%")
.attr("fill", "#000000")
.attr("stroke", "#3200ff")
.attr("stroke-width", 0)
.attr("font-size", size + "px")
.attr("dominant-baseline", "central")
.text(icon);
}
function appendMarker(cell, type) {
const x = cells.p[cell][0],
y = cells.p[cell][1];
const id = getNextId("markerElement");
const name = "#marker_" + type;
markers
.append("use")
.attr("id", id)
.attr("xlink:href", name)
.attr("data-id", name)
.attr("data-x", x)
.attr("data-y", y)
.attr("x", x - 15)
.attr("y", y - 30)
.attr("data-size", 1)
.attr("width", 30)
.attr("height", 30);
return id;
}
TIME && console.timeEnd("addMarkers");
}
// regenerate some zones
function addZones(number = 1) {
TIME && console.time("addZones");
@ -1685,7 +1524,18 @@ function addZones(number = 1) {
});
}
const invasion = rw({Invasion: 4, Occupation: 3, Raid: 2, Conquest: 2, Subjugation: 1, Foray: 1, Skirmishes: 1, Incursion: 2, Pillaging: 1, Intervention: 1});
const invasion = rw({
Invasion: 4,
Occupation: 3,
Raid: 2,
Conquest: 2,
Subjugation: 1,
Foray: 1,
Skirmishes: 1,
Incursion: 2,
Pillaging: 1,
Intervention: 1
});
const name = getAdjective(invader.name) + " " + invasion;
data.push({name, type: "Invasion", cells: cellsArray, fill: "url(#hatch1)"});
}
@ -2002,7 +1852,7 @@ function addZones(number = 1) {
// show map stats on generation complete
function showStatistics() {
const template = templateInput.value;
const template = templateInput.options[templateInput.selectedIndex].text;
const templateRandom = locked("template") ? "" : "(random)";
const stats = ` Seed: ${seed}
Canvas size: ${graphWidth}x${graphHeight}

View file

@ -416,7 +416,7 @@ window.BurgsAndStates = (function () {
function getRiverCost(r, i, type) {
if (type === "River") return r ? 0 : 100; // penalty for river cultures
if (!r) return 0; // no penalty for others if there is no river
return Math.min(Math.max(cells.fl[i] / 10, 20), 100); // river penalty from 20 to 100 based on flux
return minmax(cells.fl[i] / 10, 20, 100); // river penalty from 20 to 100 based on flux
}
function getTypeCost(t, type) {
@ -480,6 +480,7 @@ window.BurgsAndStates = (function () {
const {cells, features, states} = pack;
const paths = []; // text paths
lineGen.curve(d3.curveBundle.beta(1));
const mode = options.stateLabelsMode || "auto";
for (const s of states) {
if (!s.i || s.removed || !s.cells || (list && !list.includes(s.i))) continue;
@ -586,7 +587,8 @@ window.BurgsAndStates = (function () {
paths.forEach(p => {
const id = p[0];
const s = states[p[0]];
const state = states[p[0]];
const {name, fullName} = state;
if (list) {
t.select("#textPath_stateLabel" + id).remove();
@ -600,22 +602,7 @@ window.BurgsAndStates = (function () {
.attr("id", "textPath_stateLabel" + id);
const pathLength = p[1].length > 1 ? textPath.node().getTotalLength() / letterLength : 0; // path length in letters
let lines = [];
let ratio = 100;
if (pathLength < s.name.length) {
// only short name will fit
lines = splitInTwo(s.name);
ratio = Math.max(Math.min(rn((pathLength / lines[0].length) * 60), 150), 50);
} else if (pathLength > s.fullName.length * 2.5) {
// full name will fit in one line
lines = [s.fullName];
ratio = Math.max(Math.min(rn((pathLength / lines[0].length) * 70), 170), 70);
} else {
// try miltilined label
lines = splitInTwo(s.fullName);
ratio = Math.max(Math.min(rn((pathLength / lines[0].length) * 60), 150), 70);
}
const [lines, ratio] = getLines(mode, name, fullName, pathLength);
// prolongate path if it's too short
if (pathLength && pathLength < lines[0].length) {
@ -647,7 +634,7 @@ window.BurgsAndStates = (function () {
.node();
el.insertAdjacentHTML("afterbegin", spans.join(""));
if (lines.length < 2) return;
if (mode === "full" || lines.length === 1) return;
// check whether multilined label is generally inside the state. If no, replace with short name label
const cs = pack.cells.state;
@ -658,29 +645,51 @@ window.BurgsAndStates = (function () {
const c4 = () => +cs[findCell(b.x + b.width, b.y + b.height)] === id;
const c5 = () => +cs[findCell(b.x + b.width / 2, b.y + b.height)] === id;
const c6 = () => +cs[findCell(b.x, b.y + b.height)] === id;
if (c1() + c2() + c3() + c4() + c5() + c6() > 3) return; // generally inside
if (c1() + c2() + c3() + c4() + c5() + c6() > 3) return; // generally inside => exit
// use one-line name
const name = pathLength > s.fullName.length * 1.8 ? s.fullName : s.name;
example.text(name);
// move to one-line name
const text = pathLength > fullName.length * 1.8 ? fullName : name;
example.text(text);
const left = example.node().getBBox().width / -2; // x offset
el.innerHTML = `<tspan x="${left}px">${name}</tspan>`;
ratio = Math.max(Math.min(rn((pathLength / name.length) * 60), 130), 40);
el.setAttribute("font-size", ratio + "%");
el.innerHTML = `<tspan x="${left}px">${text}</tspan>`;
const correctedRatio = minmax(rn((pathLength / text.length) * 60), 40, 130);
el.setAttribute("font-size", correctedRatio + "%");
});
example.remove();
if (!displayed) toggleLabels();
})();
function getLines(mode, name, fullName, pathLength) {
// short name
if (mode === "short" || (mode === "auto" && pathLength < name.length)) {
const lines = splitInTwo(name);
const ratio = pathLength / lines[0].length;
return [lines, minmax(rn(ratio * 60), 50, 150)];
}
// full name: one line
if (pathLength > fullName.length * 2.5) {
const lines = [fullName];
const ratio = pathLength / lines[0].length;
return [lines, minmax(rn(ratio * 70), 70, 170)];
}
// full name: two lines
const lines = splitInTwo(fullName);
const ratio = pathLength / lines[0].length;
return [lines, minmax(rn(ratio * 60), 70, 150)];
}
TIME && console.timeEnd("drawStateLabels");
};
// calculate states data like area, population etc.
const collectStatistics = function () {
TIME && console.time("collectStatistics");
const cells = pack.cells,
states = pack.states;
const {cells, states} = pack;
states.forEach(s => {
if (s.removed) return;
s.cells = s.area = s.burgs = s.rural = s.urban = 0;
@ -738,21 +747,24 @@ window.BurgsAndStates = (function () {
TIME && console.timeEnd("assignColors");
};
// generate historical conflicts of each state
const generateCampaigns = function () {
const wars = {War: 6, Conflict: 2, Campaign: 4, Invasion: 2, Rebellion: 2, Conquest: 2, Intervention: 1, Expedition: 1, Crusade: 1};
pack.states.forEach(s => {
if (!s.i || s.removed) return;
const n = s.neighbors.length ? s.neighbors : [0];
s.campaigns = n
const generateCampaign = state => {
const neighbors = state.neighbors.length ? state.neighbors : [0];
return neighbors
.map(i => {
const name = i && P(0.8) ? pack.states[i].name : Names.getCultureShort(s.culture);
const name = i && P(0.8) ? pack.states[i].name : Names.getCultureShort(state.culture);
const start = gauss(options.year - 100, 150, 1, options.year - 6);
const end = start + gauss(4, 5, 1, options.year - start - 1);
return {name: getAdjective(name) + " " + rw(wars), start, end};
})
.sort((a, b) => a.start - b.start);
};
// generate historical conflicts of each state
const generateCampaigns = function () {
pack.states.forEach(s => {
if (!s.i || s.removed) return;
s.campaigns = generateCampaign(s);
});
};
@ -947,7 +959,17 @@ window.BurgsAndStates = (function () {
});
const monarchy = ["Duchy", "Grand Duchy", "Principality", "Kingdom", "Empire"]; // per expansionism tier
const republic = {Republic: 75, Federation: 4, Oligarchy: 2, "Most Serene Republic": 2, Tetrarchy: 1, Triumvirate: 1, Diarchy: 1, "Trade Company": 4, Junta: 1}; // weighted random
const republic = {
Republic: 75,
Federation: 4,
Oligarchy: 2,
"Most Serene Republic": 2,
Tetrarchy: 1,
Triumvirate: 1,
Diarchy: 1,
"Trade Company": 4,
Junta: 1
}; // weighted random
const union = {Union: 3, League: 4, Confederation: 1, "United Kingdom": 1, "United Republic": 1, "United Provinces": 2, Commonwealth: 1, Heptarchy: 1}; // weighted random
const theocracy = {Theocracy: 20, Brotherhood: 1, Thearchy: 2, See: 1, "Holy State": 1};
const anarchy = {"Free Territory": 2, Council: 3, Commune: 1, Community: 1};
@ -957,7 +979,8 @@ window.BurgsAndStates = (function () {
const tier = expTiers[s.i];
const religion = pack.cells.religion[s.center];
const isTheocracy = (religion && pack.religions[religion].expansion === "state") || (P(0.1) && ["Organized", "Cult"].includes(pack.religions[religion].type));
const isTheocracy =
(religion && pack.religions[religion].expansion === "state") || (P(0.1) && ["Organized", "Cult"].includes(pack.religions[religion].type));
const isAnarchy = P(0.01 - tier / 500);
if (isTheocracy) s.form = "Theocracy";
@ -1025,7 +1048,25 @@ window.BurgsAndStates = (function () {
};
// state forms requiring Adjective + Name, all other forms use scheme Form + Of + Name
const adjForms = ["Empire", "Sultanate", "Khaganate", "Shogunate", "Caliphate", "Despotate", "Theocracy", "Oligarchy", "Union", "Confederation", "Trade Company", "League", "Tetrarchy", "Triumvirate", "Diarchy", "Horde", "Marches"];
const adjForms = [
"Empire",
"Sultanate",
"Khaganate",
"Shogunate",
"Caliphate",
"Despotate",
"Theocracy",
"Oligarchy",
"Union",
"Confederation",
"Trade Company",
"League",
"Tetrarchy",
"Triumvirate",
"Diarchy",
"Horde",
"Marches"
];
const getFullName = function (s) {
if (!s.formName) return s.name;
@ -1039,16 +1080,16 @@ window.BurgsAndStates = (function () {
const localSeed = regenerate ? Math.floor(Math.random() * 1e9).toString() : seed;
Math.random = aleaPRNG(localSeed);
const cells = pack.cells,
states = pack.states,
burgs = pack.burgs;
const {cells, states, burgs} = pack;
const provinces = (pack.provinces = [0]);
cells.province = new Uint16Array(cells.i.length); // cell state
const percentage = +provincesInput.value;
if (states.length < 2 || !percentage) {
states.forEach(s => (s.provinces = []));
return;
} // no provinces
const max = percentage == 100 ? 1000 : gauss(20, 5, 5, 100) * percentage ** 0.5; // max growth
const forms = {
@ -1061,7 +1102,6 @@ window.BurgsAndStates = (function () {
};
// generate provinces for a selected burgs
Math.random = aleaPRNG(localSeed);
states.forEach(s => {
s.provinces = [];
if (!s.i || s.removed) return;
@ -1223,5 +1263,23 @@ window.BurgsAndStates = (function () {
TIME && console.timeEnd("generateProvinces");
};
return {generate, expandStates, normalizeStates, assignColors, drawBurgs, specifyBurgs, defineBurgFeatures, getType, drawStateLabels, collectStatistics, generateCampaigns, generateDiplomacy, defineStateForms, getFullName, generateProvinces, updateCultures};
return {
generate,
expandStates,
normalizeStates,
assignColors,
drawBurgs,
specifyBurgs,
defineBurgFeatures,
getType,
drawStateLabels,
collectStatistics,
generateCampaign,
generateCampaigns,
generateDiplomacy,
defineStateForms,
getFullName,
generateProvinces,
updateCultures
};
})();

View file

@ -44,11 +44,45 @@ window.COA = (function () {
};
const charges = {
// categories selection
types: {conventional: 30, crosses: 10, animals: 2, animalHeads: 1, birds: 2, fantastic: 3, plants: 1, agriculture: 1, arms: 3, bodyparts: 1, people: 1, architecture: 1, miscellaneous: 3, inescutcheon: 3},
single: {conventional: 12, crosses: 8, plants: 2, animals: 10, animalHeads: 2, birds: 4, fantastic: 7, agriculture: 1, arms: 6, bodyparts: 1, people: 2, architecture: 1, miscellaneous: 10, inescutcheon: 5},
semy: {conventional: 12, crosses: 3, plants: 1},
// generic categories
types: {
conventional: 30,
crosses: 10,
animals: 2,
animalHeads: 1,
birds: 2,
aquatic: 1,
seafaring: 1,
fantastic: 3,
plants: 1,
agriculture: 1,
arms: 3,
bodyparts: 1,
people: 1,
architecture: 1,
miscellaneous: 3,
inescutcheon: 3,
uploaded: 0
},
single: {
conventional: 12,
crosses: 8,
plants: 2,
animals: 10,
animalHeads: 2,
birds: 4,
aquatic: 2,
seafaring: 2,
fantastic: 7,
agriculture: 1,
arms: 6,
bodyparts: 1,
people: 2,
architecture: 1,
miscellaneous: 10,
inescutcheon: 5,
uploaded: 0
},
semy: {conventional: 4, crosses: 1},
conventional: {
lozenge: 2,
fusil: 4,
@ -86,6 +120,51 @@ window.COA = (function () {
crescent: 5,
fountain: 1
},
inescutcheon: {
inescutcheonHeater: 1,
inescutcheonSpanish: 1,
inescutcheonFrench: 1,
inescutcheonHorsehead: 1,
inescutcheonHorsehead2: 1,
inescutcheonPolish: 1,
inescutcheonHessen: 1,
inescutcheonSwiss: 1,
inescutcheonBoeotian: 1,
inescutcheonRoman: 1,
inescutcheonKite: 1,
inescutcheonOldFrench: 1,
inescutcheonRenaissance: 1,
inescutcheonBaroque: 1,
inescutcheonTarge: 1,
inescutcheonTarge2: 1,
inescutcheonPavise: 1,
inescutcheonWedged: 1,
inescutcheonFlag: 1,
inescutcheonPennon: 1,
inescutcheonGuidon: 1,
inescutcheonBanner: 1,
inescutcheonDovetail: 1,
inescutcheonGonfalon: 1,
inescutcheonPennant: 1,
inescutcheonRound: 1,
inescutcheonOval: 1,
inescutcheonVesicaPiscis: 1,
inescutcheonSquare: 1,
inescutcheonDiamond: 1,
inescutcheonNo: 1,
inescutcheonFantasy1: 1,
inescutcheonFantasy2: 1,
inescutcheonFantasy3: 1,
inescutcheonFantasy4: 1,
inescutcheonFantasy5: 1,
inescutcheonNoldor: 1,
inescutcheonGondor: 1,
inescutcheonEasterling: 1,
inescutcheonErebor: 1,
inescutcheonIronHills: 1,
inescutcheonUrukHai: 1,
inescutcheonMoriaOrc: 1
},
crosses: {
crossHummetty: 15,
crossVoided: 1,
@ -129,35 +208,73 @@ window.COA = (function () {
crossAnkh: 1
},
animals: {
lionRampant: 5,
lionRampant: 6,
lionPassant: 2,
lionPassantGuardant: 1,
wolfRampant: 1,
wolfPassant: 1,
wolfStatant: 1,
greyhoundCourant: 1,
greyhoundSejant: 1,
mastiffStatant: 1,
boarRampant: 1,
horseRampant: 2,
horseSalient: 1,
horsePassant: 1,
bearRampant: 2,
bearPassant: 1,
bullPassant: 1,
goat: 1,
lamb: 1,
lambPassantReguardant: 1,
agnusDei: 1,
elephant: 1,
camel: 1
camel: 1,
porcupine: 1,
snake: 1
},
animalHeads: {wolfHeadErased: 1, bullHeadCaboshed: 1, deerHeadCaboshed: 1, lionHeadCaboshed: 2},
fantastic: {dragonPassant: 2, dragonRampant: 2, wyvern: 1, wyvernWithWingsDisplayed: 1, griffinPassant: 1, griffinRampant: 1, eagleTwoHeards: 2, unicornRampant: 1, pegasus: 1, serpent: 1},
birds: {eagle: 9, raven: 1, cock: 3, parrot: 1, swan: 2, swanErased: 1, heron: 1, owl: 1},
plants: {tree: 1, oak: 1, cinquefoil: 1, rose: 1},
agriculture: {garb: 1, rake: 1},
arms: {sword: 5, sabre: 1, sabresCrossed: 1, hatchet: 2, axe: 2, lochaberAxe: 1, mallet: 1, bowWithArrow: 2, bow: 1, arrow: 1, arrowsSheaf: 1, helmet: 2},
bodyparts: {hand: 4, head: 1, headWreathed: 1},
animalHeads: {wolfHeadErased: 2, bullHeadCaboshed: 1, deerHeadCaboshed: 1, lionHeadCaboshed: 2},
fantastic: {
dragonPassant: 2,
dragonRampant: 2,
wyvern: 1,
wyvernWithWingsDisplayed: 1,
griffinPassant: 1,
griffinRampant: 1,
eagleTwoHeards: 2,
unicornRampant: 1,
pegasus: 1,
serpent: 1,
basilisk: 1
},
birds: {eagle: 9, raven: 2, cock: 3, parrot: 1, swan: 2, swanErased: 1, heron: 1, owl: 1},
plants: {tree: 1, oak: 1, cinquefoil: 1, rose: 1, apple: 1},
aquatic: {escallop: 5, pike: 1, cancer: 1, dolphin: 1},
seafaring: {anchor: 6, boat: 2, boat2: 1, lymphad: 2, armillarySphere: 1},
agriculture: {garb: 2, rake: 1, plough: 2},
arms: {
sword: 4,
falchion: 1,
sabre: 1,
sabresCrossed: 1,
sabre2: 1,
hatchet: 3,
axe: 3,
lochaberAxe: 1,
mallet: 1,
bowWithArrow: 3,
bow: 1,
arrow: 1,
arrowsSheaf: 1,
helmet: 2,
cannon: 1
},
bodyparts: {hand: 4, head: 1, headWreathed: 1, foot: 1},
people: {cavalier: 3, monk: 1, angel: 2},
architecture: {tower: 1, castle: 1},
miscellaneous: {
crown: 3,
crown: 2,
crown2: 1,
orb: 1,
chalice: 1,
key: 1,
@ -179,19 +296,33 @@ window.COA = (function () {
wheel: 2,
crosier: 1,
fasces: 1,
log: 1
log: 1,
chain: 1,
anvil: 1
},
// selection based on culture type:
Naval: {anchor: 3, boat: 1, lymphad: 2, armillarySphere: 1, escallop: 1, dolphin: 1},
Highland: {tower: 1, raven: 1, wolfHeadErased: 1, wolfPassant: 1, goat: 1, axe: 1},
River: {tower: 1, garb: 1, rake: 1, boat: 1, pike: 2, bullHeadCaboshed: 1},
River: {tower: 1, garb: 1, rake: 1, boat: 1, pike: 2, bullHeadCaboshed: 1, apple: 1, plough: 1},
Lake: {cancer: 2, escallop: 1, pike: 2, heron: 1, boat: 1, boat2: 2},
Nomadic: {pot: 1, buckle: 1, wheel: 2, sabre: 2, sabresCrossed: 1, bow: 2, arrow: 1, horseRampant: 1, horseSalient: 1, crescent: 1, camel: 3},
Hunting: {bugleHorn: 2, bugleHorn2: 1, stagsAttires: 2, attire: 2, hatchet: 1, bowWithArrow: 1, arrowsSheaf: 1, deerHeadCaboshed: 1, wolfStatant: 1, oak: 1},
Hunting: {
bugleHorn: 2,
bugleHorn2: 1,
stagsAttires: 2,
attire: 2,
hatchet: 1,
bowWithArrow: 1,
arrowsSheaf: 1,
deerHeadCaboshed: 1,
wolfStatant: 1,
oak: 1,
greyhoundSejant: 1
},
// selection based on type
City: {key: 3, bell: 2, lute: 1, tower: 1, castle: 1, mallet: 1},
Capital: {crown: 4, orb: 1, lute: 1, castle: 3, tower: 1},
Сathedra: {chalice: 1, orb: 1, crosier: 2, lamb: 1, monk: 2, angel: 3, crossLatin: 2, crossPatriarchal: 1, crossOrthodox: 1, crossCalvary: 1},
City: {key: 3, bell: 2, lute: 1, tower: 1, castle: 1, mallet: 1, cannon: 1, anvil: 1},
Capital: {crown: 2, orb: 1, lute: 1, castle: 3, tower: 1, crown2: 2},
Сathedra: {chalice: 1, orb: 1, crosier: 2, lamb: 1, monk: 2, angel: 3, crossLatin: 2, crossPatriarchal: 1, crossOrthodox: 1, crossCalvary: 1, agnusDei: 3},
// specific cases
natural: {fountain: "azure", garb: "or", raven: "sable"}, // charges to mainly use predefined colours
sinister: [
@ -204,14 +335,19 @@ window.COA = (function () {
"wolfStatant",
"wolfHeadErased",
"greyhoundСourant",
"greyhoundSejant",
"mastiffStatant",
"boarRampant",
"horseRampant",
"horseSalient",
"horsePassant",
"bullPassant",
"bearRampant",
"bearPassant",
"goat",
"lamb",
"lambPassantReguardant",
"agnusDei",
"elephant",
"eagle",
"raven",
@ -252,7 +388,15 @@ window.COA = (function () {
"camel",
"fasces",
"lionPassantGuardant",
"helmet"
"helmet",
"foot",
"plough",
"sabre2",
"cannon",
"porcupine",
"basilisk",
"snake",
"anvil"
],
reversed: [
// charges that can be reversed
@ -263,6 +407,7 @@ window.COA = (function () {
"crossTau",
"cancer",
"sword",
"falchion",
"sabresCrossed",
"hand",
"horseshoe",
@ -272,12 +417,30 @@ window.COA = (function () {
"rake",
"crossTriquetra",
"crossLatin",
"crossTau"
"crossTau",
"sabre2"
]
};
const positions = {
conventional: {e: 20, abcdefgzi: 3, beh: 3, behdf: 2, acegi: 1, kn: 3, bhdf: 1, jeo: 1, abc: 3, jln: 6, jlh: 3, kmo: 2, jleh: 1, def: 3, abcpqh: 4, ABCDEFGHIJKL: 1},
conventional: {
e: 20,
abcdefgzi: 3,
beh: 3,
behdf: 2,
acegi: 1,
kn: 3,
bhdf: 1,
jeo: 1,
abc: 3,
jln: 6,
jlh: 3,
kmo: 2,
jleh: 1,
def: 3,
abcpqh: 4,
ABCDEFGHIJKL: 1
},
complex: {e: 40, beh: 1, kn: 1, jeo: 1, abc: 2, jln: 7, jlh: 2, def: 1, abcpqh: 1},
divisions: {
perPale: {e: 15, pq: 5, jo: 2, jl: 2, ABCDEFGHIJKL: 1},
@ -405,14 +568,47 @@ window.COA = (function () {
};
const divisions = {
variants: {perPale: 5, perFess: 5, perBend: 2, perBendSinister: 1, perChevron: 1, perChevronReversed: 1, perCross: 5, perPile: 1, perSaltire: 1, gyronny: 1, chevronny: 1},
variants: {
perPale: 5,
perFess: 5,
perBend: 2,
perBendSinister: 1,
perChevron: 1,
perChevronReversed: 1,
perCross: 5,
perPile: 1,
perSaltire: 1,
gyronny: 1,
chevronny: 1
},
perPale: lines,
perFess: lines,
perBend: lines,
perBendSinister: lines,
perChevron: lines,
perChevronReversed: lines,
perCross: {straight: 20, wavy: 5, engrailed: 4, invecked: 3, rayonne: 1, embattled: 1, raguly: 1, urdy: 1, indented: 2, dentilly: 1, bevilled: 1, angled: 1, embattledGhibellin: 1, embattledGrady: 1, dovetailedIndented: 1, dovetailed: 1, potenty: 1, potentyDexter: 1, potentySinister: 1, nebuly: 1},
perCross: {
straight: 20,
wavy: 5,
engrailed: 4,
invecked: 3,
rayonne: 1,
embattled: 1,
raguly: 1,
urdy: 1,
indented: 2,
dentilly: 1,
bevilled: 1,
angled: 1,
embattledGhibellin: 1,
embattledGrady: 1,
dovetailedIndented: 1,
dovetailed: 1,
potenty: 1,
potentyDexter: 1,
potentySinister: 1,
nebuly: 1
},
perPile: lines
};
@ -476,8 +672,9 @@ window.COA = (function () {
kinship = 0;
dominion = 0;
}
let usedPattern = null,
usedTinctures = [];
let usedPattern = null;
let usedTinctures = [];
const t1 = P(kinship) ? parent.t1 : getTincture("field");
if (t1.includes("-")) usedPattern = t1;
@ -489,7 +686,8 @@ window.COA = (function () {
const rareDivided = ["chief", "terrace", "chevron", "quarter", "flaunches"].includes(ordinary);
const divisioned = rareDivided ? P(0.03) : charge && ordinary ? P(0.03) : charge ? P(0.3) : ordinary ? P(0.7) : P(0.995); // 33% for division
const division = divisioned ? (parent?.division && P(kinship - 0.1) ? parent.division.division : rw(divisions.variants)) : null;
if (charge) charge = parent?.charges && P(kinship - 0.1) ? parent.charges[0].charge : type && type !== "Generic" && P(0.2) ? rw(charges[type]) : selectCharge();
if (charge)
charge = parent?.charges && P(kinship - 0.1) ? parent.charges[0].charge : type && type !== "Generic" && P(0.2) ? rw(charges[type]) : selectCharge();
if (division) {
const t = getTincture("division", usedTinctures, P(0.98) ? coa.t1 : null);

View file

@ -1452,19 +1452,27 @@ window.COArenderer = (function () {
heater: "m25,25 h150 v50 a150,150,0,0,1,-75,125 a150,150,0,0,1,-75,-125 z",
spanish: "m25,25 h150 v100 a75,75,0,0,1,-150,0 z",
french: "m 25,25 h 150 v 139.15 c 0,41.745 -66,18.15 -75,36.3 -9,-18.15 -75,5.445 -75,-36.3 v 0 z",
horsehead: "m 20,40 c 0,60 40,80 40,100 0,10 -4,15 -0.35,30 C 65,185.7 81,200 100,200 c 19.1,0 35.3,-14.6 40.5,-30.4 C 144.2,155 140,150 140,140 140,120 180,100 180,40 142.72,40 150,15 100,15 55,15 55,40 20,40 Z",
horsehead:
"m 20,40 c 0,60 40,80 40,100 0,10 -4,15 -0.35,30 C 65,185.7 81,200 100,200 c 19.1,0 35.3,-14.6 40.5,-30.4 C 144.2,155 140,150 140,140 140,120 180,100 180,40 142.72,40 150,15 100,15 55,15 55,40 20,40 Z",
horsehead2: "M60 20c-5 20-10 35-35 55 25 35 35 65 30 100 20 0 35 10 45 26 10-16 30-26 45-26-5-35 5-65 30-100a87 87 0 01-35-55c-25 3-55 3-80 0z",
polish: "m 90.3,6.3 c -12.7,0 -20.7,10.9 -40.5,14 0,11.8 -4.9,23.5 -11.4,31.1 0,0 12.7,6 12.7,19.3 C 51.1,90.8 30,90.8 30,90.8 c 0,0 -3.6,7.4 -3.6,22.4 0,34.3 23.1,60.2 40.7,68.2 17.6,8 27.7,11.4 32.9,18.6 5.2,-7.3 15.3,-10.7 32.8,-18.6 17.6,-8 40.7,-33.9 40.7,-68.2 0,-15 -3.6,-22.4 -3.6,-22.4 0,0 -21.1,0 -21.1,-20.1 0,-13.3 12.7,-19.3 12.7,-19.3 C 155.1,43.7 150.2,32.1 150.2,20.3 130.4,17.2 122.5,6.3 109.7,6.3 102.5,6.3 100,10 100,10 c 0,0 -2.5,-3.7 -9.7,-3.7 z",
polish:
"m 90.3,6.3 c -12.7,0 -20.7,10.9 -40.5,14 0,11.8 -4.9,23.5 -11.4,31.1 0,0 12.7,6 12.7,19.3 C 51.1,90.8 30,90.8 30,90.8 c 0,0 -3.6,7.4 -3.6,22.4 0,34.3 23.1,60.2 40.7,68.2 17.6,8 27.7,11.4 32.9,18.6 5.2,-7.3 15.3,-10.7 32.8,-18.6 17.6,-8 40.7,-33.9 40.7,-68.2 0,-15 -3.6,-22.4 -3.6,-22.4 0,0 -21.1,0 -21.1,-20.1 0,-13.3 12.7,-19.3 12.7,-19.3 C 155.1,43.7 150.2,32.1 150.2,20.3 130.4,17.2 122.5,6.3 109.7,6.3 102.5,6.3 100,10 100,10 c 0,0 -2.5,-3.7 -9.7,-3.7 z",
hessen: "M170 20c4 5 8 13 15 20 0 0-10 0-10 15 0 100-15 140-75 145-65-5-75-45-75-145 0-15-10-15-10-15l15-20c0 15 10-5 70-5s70 20 70 5z",
swiss: "m 25,20 c -0.1,0 25.2,8.5 37.6,8.5 C 75.1,28.5 99.1,20 100,20 c 0.6,0 24.9,8.5 37.3,8.5 C 149.8,28.5 174.4,20 175,20 l -0.3,22.6 C 173.2,160.3 100,200 100,200 100,200 26.5,160.9 25.2,42.6 Z",
boeotian: "M150 115c-5 0-10-5-10-15s5-15 10-15c10 0 7 10 15 10 10 0 0-30 0-30-10-25-30-55-65-55S45 40 35 65c0 0-10 30 0 30 8 0 5-10 15-10 5 0 10 5 10 15s-5 15-10 15c-10 0-7-10-15-10-10 0 0 30 0 30 10 25 30 55 65 55s55-30 65-55c0 0 10-30 0-30-8 0-5 10-15 10z",
swiss:
"m 25,20 c -0.1,0 25.2,8.5 37.6,8.5 C 75.1,28.5 99.1,20 100,20 c 0.6,0 24.9,8.5 37.3,8.5 C 149.8,28.5 174.4,20 175,20 l -0.3,22.6 C 173.2,160.3 100,200 100,200 100,200 26.5,160.9 25.2,42.6 Z",
boeotian:
"M150 115c-5 0-10-5-10-15s5-15 10-15c10 0 7 10 15 10 10 0 0-30 0-30-10-25-30-55-65-55S45 40 35 65c0 0-10 30 0 30 8 0 5-10 15-10 5 0 10 5 10 15s-5 15-10 15c-10 0-7-10-15-10-10 0 0 30 0 30 10 25 30 55 65 55s55-30 65-55c0 0 10-30 0-30-8 0-5 10-15 10z",
roman: "m 160,170 c -40,20 -80,20 -120,0 V 30 C 80,10 120,10 160,30 Z",
kite: "m 53.3,46.4 c 0,4.1 1,12.3 1,12.3 7.1,55.7 45.7,141.3 45.7,141.3 0,0 38.6,-85.6 45.7,-141.2 0,0 1,-8.1 1,-12.3 C 146.7,20.9 125.8,0.1 100,0.1 74.2,0.1 53.3,20.9 53.3,46.4 Z",
oldFrench: "m25,25 h150 v75 a100,100,0,0,1,-75,100 a100,100,0,0,1,-75,-100 z",
renaissance: "M 25,33.9 C 33.4,50.3 36.2,72.9 36.2,81.7 36.2,109.9 25,122.6 25,141 c 0,29.4 24.9,44.1 40.2,47.7 15.3,3.7 29.3,0 34.8,11.3 5.5,-11.3 19.6,-7.6 34.8,-11.3 C 150.1,185 175,170.3 175,141 c 0,-18.4 -11.2,-31.1 -11.2,-59.3 0,-8.8 2.8,-31.3 11.2,-47.7 L 155.7,14.4 C 138.2,21.8 119.3,25.7 100,25.7 c -19.3,0 -38.2,-3.9 -55.7,-11.3 z",
baroque: "m 100,25 c 18,0 50,2 75,14 v 37 l -2.7,3.2 c -4.9,5.4 -6.6,9.6 -6.7,16.2 0,6.5 2,11.6 6.9,17.2 l 2.8,3.1 v 10.2 c 0,17.7 -2.2,27.7 -7.8,35.9 -5,7.3 -11.7,11.3 -32.3,19.4 -12.6,5 -20.2,8.8 -28.6,14.5 C 103.3,198 100,200 100,200 c 0,0 -2.8,-2.3 -6.4,-4.7 C 85.6,189.8 78,186 65,180.9 32.4,168.1 26.9,160.9 25.8,129.3 L 25,116 l 3.3,-3.3 c 4.8,-5.2 7,-10.7 7,-17.3 0,-6.8 -1.8,-11.1 -6.5,-16.1 L 25,76 V 39 C 50,27 82,25 100,25 Z",
targe: "m 20,35 c 15,0 115,-60 155,-10 -5,10 -15,15 -10,50 5,45 10,70 -10,90 C 125,195 75,195 50,175 25,150 30,130 35,85 50,95 65,85 65,70 65,50 50,45 40,50 30,55 27,65 30,70 23,73 20,70 14,70 11,60 20,45 20,35 Z",
targe2: "m 84,32.2 c 6.2,-1 19.5,-31.4 94.1,-20.2 -30.57,33.64 -21.66,67.37 -11.2,95 20.2,69.5 -41.17549,84.7 -66.88,84.7 C 74.32,191.7071 8.38,168.95 32,105.9 36.88,92.88 31,89 31,82.6 35.15,82.262199 56.79,86.17 56.5,69.8 56.20,52.74 42.2,47.9 25.9,55.2 25.9,51.4 39.8,6.7 84,32.2 Z",
renaissance:
"M 25,33.9 C 33.4,50.3 36.2,72.9 36.2,81.7 36.2,109.9 25,122.6 25,141 c 0,29.4 24.9,44.1 40.2,47.7 15.3,3.7 29.3,0 34.8,11.3 5.5,-11.3 19.6,-7.6 34.8,-11.3 C 150.1,185 175,170.3 175,141 c 0,-18.4 -11.2,-31.1 -11.2,-59.3 0,-8.8 2.8,-31.3 11.2,-47.7 L 155.7,14.4 C 138.2,21.8 119.3,25.7 100,25.7 c -19.3,0 -38.2,-3.9 -55.7,-11.3 z",
baroque:
"m 100,25 c 18,0 50,2 75,14 v 37 l -2.7,3.2 c -4.9,5.4 -6.6,9.6 -6.7,16.2 0,6.5 2,11.6 6.9,17.2 l 2.8,3.1 v 10.2 c 0,17.7 -2.2,27.7 -7.8,35.9 -5,7.3 -11.7,11.3 -32.3,19.4 -12.6,5 -20.2,8.8 -28.6,14.5 C 103.3,198 100,200 100,200 c 0,0 -2.8,-2.3 -6.4,-4.7 C 85.6,189.8 78,186 65,180.9 32.4,168.1 26.9,160.9 25.8,129.3 L 25,116 l 3.3,-3.3 c 4.8,-5.2 7,-10.7 7,-17.3 0,-6.8 -1.8,-11.1 -6.5,-16.1 L 25,76 V 39 C 50,27 82,25 100,25 Z",
targe:
"m 20,35 c 15,0 115,-60 155,-10 -5,10 -15,15 -10,50 5,45 10,70 -10,90 C 125,195 75,195 50,175 25,150 30,130 35,85 50,95 65,85 65,70 65,50 50,45 40,50 30,55 27,65 30,70 23,73 20,70 14,70 11,60 20,45 20,35 Z",
targe2:
"m 84,32.2 c 6.2,-1 19.5,-31.4 94.1,-20.2 -30.57,33.64 -21.66,67.37 -11.2,95 20.2,69.5 -41.17549,84.7 -66.88,84.7 C 74.32,191.7071 8.38,168.95 32,105.9 36.88,92.88 31,89 31,82.6 35.15,82.262199 56.79,86.17 56.5,69.8 56.20,52.74 42.2,47.9 25.9,55.2 25.9,51.4 39.8,6.7 84,32.2 Z",
pavise: "M95 7L39.9 37.3a10 10 0 00-5.1 9.5L46 180c.4 5.2 3.7 10 9 10h90c5.3 0 9.6-4.8 10-10l10.6-133.2a10 10 0 00-5-9.5L105 7c-4.2-2.3-6.2-2.3-10 0z",
wedged: "m 51.2,19 h 96.4 c 3.1,12.7 10.7,20.9 26.5,20.8 C 175.7,94.5 165.3,144.3 100,200 43.5,154.2 22.8,102.8 25.1,39.7 37,38.9 47.1,34.7 51.2,19 Z",
round: "m 185,100 a 85,85 0 0 1 -85,85 85,85 0 0 1 -85,-85 85,85 0 0 1 85,-85 85,85 0 0 1 85,85",
@ -1481,7 +1489,8 @@ window.COArenderer = (function () {
gonfalon: "m 25,25 v 125 l 75,50 75,-50 V 25 Z",
pennant: "M 25,15 100,200 175,15 Z",
fantasy1: "M 100,5 C 85,30 40,35 15,40 c 40,35 20,90 40,115 15,25 40,30 45,45 5,-15 30,-20 45,-45 20,-25 0,-80 40,-115 C 160,35 115,30 100,5 Z",
fantasy2: "m 152,21 c 0,0 -27,14 -52,-4 C 75,35 48,21 48,21 50,45 30,55 30,75 60,75 60,115 32,120 c 3,40 53,50 68,80 15,-30 65,-40 68,-80 -28,-5 -28,-45 2,-45 C 170,55 150,45 152,21 Z",
fantasy2:
"m 152,21 c 0,0 -27,14 -52,-4 C 75,35 48,21 48,21 50,45 30,55 30,75 60,75 60,115 32,120 c 3,40 53,50 68,80 15,-30 65,-40 68,-80 -28,-5 -28,-45 2,-45 C 170,55 150,45 152,21 Z",
fantasy3: "M 167,67 C 165,0 35,0 33,67 c 32,-7 27,53 -3,43 -5,45 60,65 70,90 10,-25 75,-47.51058 70,-90 -30,10 -35,-50 -3,-43 z",
fantasy4: "M100 9C55 48 27 27 13 39c23 50 3 119 49 150 14 9 28 11 38 11s27-4 38-11c55-39 24-108 49-150-14-12-45 7-87-30z",
fantasy5: "M 100,0 C 75,25 30,25 30,25 c 0,69 20,145 70,175 50,-30 71,-106 70,-175 0,0 -45,0 -70,-25 z",
@ -1491,32 +1500,47 @@ window.COArenderer = (function () {
erebor: "M25 135 V60 l22-13 16-37 h75 l15 37 22 13 v75l-22 18-16 37 H63l-16-37z",
ironHills: "m 30,25 60,-10 10,10 10,-10 60,10 -5,125 -65,50 -65,-50 z",
urukHai: "M 30,60 C 40,60 60,50 60,20 l -5,-3 45,-17 75,40 -5,5 -35,155 -5,-35 H 70 v 35 z",
moriaOrc: "M45 35c5 3 7 10 13 9h19c4-2 7-4 9-9 6 1 9 9 16 11 7-2 14 0 21 0 6-3 6-10 10-15 2-5 1-10-2-15-2-4-5-14-4-16 3 6 7 11 12 14 7 3 3 12 7 16 3 6 4 12 9 18 2 4 6 8 5 14 0 6-1 12 3 18-3 6-2 13-1 20 1 6-2 12-1 18 0 6-3 13 0 18 8 4 0 8-5 7-4 3-9 3-13 9-5 5-5 13-8 19 0 6 0 15-7 16-1 6-7 6-10 12-1-6 0-6-2-9l2-19c2-4 5-12-3-12-4-5-11-5-15 1l-13-18c-3-4-2 9-3 12 2 2-4-6-7-5-8-2-8 7-11 11-2 4-5 10-8 9 3-10 3-16 1-23-1-4 2-9-4-11 0-6 1-13-2-19-4-2-9-6-13-7V91c4-7-5-13 0-19-3-7 2-11 2-18-1-6 1-12 3-17v-1z"
moriaOrc:
"M45 35c5 3 7 10 13 9h19c4-2 7-4 9-9 6 1 9 9 16 11 7-2 14 0 21 0 6-3 6-10 10-15 2-5 1-10-2-15-2-4-5-14-4-16 3 6 7 11 12 14 7 3 3 12 7 16 3 6 4 12 9 18 2 4 6 8 5 14 0 6-1 12 3 18-3 6-2 13-1 20 1 6-2 12-1 18 0 6-3 13 0 18 8 4 0 8-5 7-4 3-9 3-13 9-5 5-5 13-8 19 0 6 0 15-7 16-1 6-7 6-10 12-1-6 0-6-2-9l2-19c2-4 5-12-3-12-4-5-11-5-15 1l-13-18c-3-4-2 9-3 12 2 2-4-6-7-5-8-2-8 7-11 11-2 4-5 10-8 9 3-10 3-16 1-23-1-4 2-9-4-11 0-6 1-13-2-19-4-2-9-6-13-7V91c4-7-5-13 0-19-3-7 2-11 2-18-1-6 1-12 3-17v-1z"
};
const lines = {
straight: "m 0,100 v15 h 200 v -15 z",
engrailed: "m 0,95 a 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 v 20 H 0 Z",
invecked: "M0,102.5 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 v12.5 H0 z",
embattled: "M 0,105 H 2.5 V 95 h 15 v 10 h 15 V 95 h 15 v 10 h 15 V 95 h 15 v 10 h 15 V 95 h 15 v 10 h 15 V 95 h 15 v 10 h 15 V 95 h 15 v 10 h 15 V 95 h 15 v 10 h 2.5 v 10 H 0 Z",
engrailed:
"m 0,95 a 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 v 20 H 0 Z",
invecked:
"M0,102.5 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 v12.5 H0 z",
embattled:
"M 0,105 H 2.5 V 95 h 15 v 10 h 15 V 95 h 15 v 10 h 15 V 95 h 15 v 10 h 15 V 95 h 15 v 10 h 15 V 95 h 15 v 10 h 15 V 95 h 15 v 10 h 15 V 95 h 15 v 10 h 2.5 v 10 H 0 Z",
wavy: "m 200,115 v -15 c -8.9,3.5 -16,3.1 -25,0 -8.9,-3.5 -16,-3.1 -25,0 -8.9,3.5 -16,3.2 -25,0 -8.9,-3.5 -16,-3.2 -25,0 -8.9,3.5 -16,3.1 -25,0 -8.9,-3.5 -16,-3.1 -25,0 -8.9,3.5 -16,3.2 -25,0 -8.9,-3.5 -16,-3.2 -25,0 v 15 z",
raguly: "m 200,95 h -3 l -5,10 h -10 l 5,-10 h -10 l -5,10 h -10 l 5,-10 h -10 l -5,10 h -10 l 5,-10 h -10 l -5,10 h -10 l 5,-10 h -10 l -5,10 h -10 l 5,-10 H 97 l -5,10 H 82 L 87,95 H 77 l -5,10 H 62 L 67,95 H 57 l -5,10 H 42 L 47,95 H 37 l -5,10 H 22 L 27,95 H 17 l -5,10 H 2 L 7,95 H 0 v 20 h 200 z",
raguly:
"m 200,95 h -3 l -5,10 h -10 l 5,-10 h -10 l -5,10 h -10 l 5,-10 h -10 l -5,10 h -10 l 5,-10 h -10 l -5,10 h -10 l 5,-10 h -10 l -5,10 h -10 l 5,-10 H 97 l -5,10 H 82 L 87,95 H 77 l -5,10 H 62 L 67,95 H 57 l -5,10 H 42 L 47,95 H 37 l -5,10 H 22 L 27,95 H 17 l -5,10 H 2 L 7,95 H 0 v 20 h 200 z",
dancetty: "m 0,105 10,-15 15,20 15,-20 15,20 15,-20 15,20 15,-20 15,20 15,-20 15,20 15,-20 15,20 15,-20 10,15 v 10 H 0 Z",
dentilly: "M 180,105 170,95 v 10 L 160,95 v 10 L 150,95 v 10 L 140,95 v 10 L 130,95 v 10 L 120,95 v 10 L 110,95 v 10 L 100,95 v 10 L 90,95 v 10 L 80,95 v 10 L 70,95 v 10 L 60,95 v 10 L 50,95 v 10 L 40,95 v 10 L 30,95 v 10 L 20,95 v 10 L 10,95 v 10 L 0,95 v 20 H 200 V 105 L 190,95 v 10 L 180,95 Z",
dentilly:
"M 180,105 170,95 v 10 L 160,95 v 10 L 150,95 v 10 L 140,95 v 10 L 130,95 v 10 L 120,95 v 10 L 110,95 v 10 L 100,95 v 10 L 90,95 v 10 L 80,95 v 10 L 70,95 v 10 L 60,95 v 10 L 50,95 v 10 L 40,95 v 10 L 30,95 v 10 L 20,95 v 10 L 10,95 v 10 L 0,95 v 20 H 200 V 105 L 190,95 v 10 L 180,95 Z",
angled: "m 0,95 h 100 v 10 h 100 v 10 H 0 Z",
urdy: "m 200,90 -5,5 v 10 l -5,5 -5,-5 V 95 l -5,-5 -5,5 v 10 l -5,5 -5,-5 V 95 l -5,-5 -5,5 v 10 l -5,5 -5,-5 V 95 l -5,-5 -5,5 v 10 l -5,6 -5,-6 V 95 l -5,-5 -5,5 v 10 l -5,5 -5,-5 V 95 l -5,-5 -5,5 v 10 l -5,5 -5,-5 V 95 l -5,-5 -5,5 v 10 l -5,6 -5,-6 V 95 l -5,-5 -5,5 v 10 l -5,5 -5,-5 V 95 l -5,-5 -5,5 v 10 l -5,5 -5,-5 V 95 l -5,-5 -5,5 v 10 l -5,5 -5,-5 V 95 L 0,90 v 25 h 200",
indented: "m 100,95 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 v 20 H 0 V 95 l 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 z",
indented:
"m 100,95 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 v 20 H 0 V 95 l 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 z",
bevilled: "m 0,92.5 h 110 l -20,15 H 200 V 115 H 0 Z",
nowy: "m 0,95 h 80 c 0,0 0.1,20.1 20,20 19.9,-0.1 20,-20 20,-20 h 80 v 20 H 0 Z",
nowyReversed: "m 200,105 h -80 c 0,0 -0.1,-20.1 -20,-20 -19.9,0.1 -20,20 -20,20 H 0 v 10 h 200 z",
potenty: "m 3,95 v 5 h 5 v 5 H 0 v 10 h 200 l 0.5,-10 H 193 v -5 h 5 v -5 h -15 v 5 h 5 v 5 h -15 v -5 h 5 v -5 h -15 v 5 h 5 v 5 h -15 v -5 h 5 v -5 h -15 v 5 h 5 v 5 h -15 v -5 h 5 v -5 h -15 v 5 h 5 v 5 h -15 v -5 h 5 v -5 h -15 v 5 h 5 v 5 H 100.5 93 v -5 h 5 V 95 H 83 v 5 h 5 v 5 H 73 v -5 h 5 V 95 H 63 v 5 h 5 v 5 H 53 v -5 h 5 V 95 H 43 v 5 h 5 v 5 H 33 v -5 h 5 V 95 H 23 v 5 h 5 v 5 H 13 v -5 h 5 v -5 z",
potentyDexter: "m 200,105 h -2 v -10 0 0 h -10 v 5 h 5 v 5 H 183 V 95 h -10 v 5 h 5 v 5 H 168 V 95 h -10 v 5 h 5 v 5 H 153 V 95 h -10 v 5 h 5 v 5 H 138 V 95 h -10 v 5 h 5 v 5 H 123 V 95 h -10 v 5 h 5 v 5 h -10 v 0 0 -10 H 98 v 5 h 5 v 5 H 93 V 95 H 83 v 5 h 5 v 5 H 78 V 95 H 68 v 5 h 5 v 5 H 63 V 95 H 53 v 5 h 5 v 5 H 48 V 95 H 38 v 5 h 5 v 5 H 33 V 95 H 23 v 5 h 5 v 5 H 18 V 95 H 8 v 5 h 5 v 5 H 3 V 95 H 0 v 20 h 200 z",
potentySinister: "m 2.5,95 v 10 H 0 v 10 h 202.5 v -15 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 z",
embattledGhibellin: "M 200,200 V 100 l -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 v 15 h 200",
embattledNotched: "m 200,105 h -5 V 95 l -5,5 -5,-5 v 10 h -5 V 95 l -5,5 -5,-5 v 10 h -5 V 95 l -5,5 -5,-5 v 10 h -5 V 95 l -5,5 -5,-5 v 10 h -5 V 95 l -5,5 -5,-5 v 10 h -5 V 95 l -5,5 -5,-5 v 10 h -5 V 95 l -5,5 -5,-5 v 10 H 90 V 95 l -5,5 -5,-5 v 10 H 75 V 95 l -5,5 -5,-5 v 10 H 60 V 95 l -5,5 -5,-5 v 10 H 45 V 95 l -5,5 -5,-5 v 10 H 30 V 95 l -5,5 -5,-5 v 10 H 15 V 95 l -5,5 -5,-5 v 10 H 0 v 10 h 200",
embattledGrady: "m 0,95 v 20 H 200 V 95 h -2.5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 z",
dovetailed: "m 200,95 h -7 l 4,10 h -14 l 4,-10 h -14 l 4,10 h -14 l 4,-10 h -14 l 4,10 h -14 l 4,-10 h -14 l 4,10 h -14 l 4,-10 h -14 l 4,10 h -14 l 4,-10 H 93 l 4,10 H 83 L 87,95 H 73 l 4,10 H 63 L 67,95 H 53 l 4,10 H 43 L 47,95 H 33 l 4,10 H 23 L 27,95 H 13 l 4,10 H 3 L 7,95 H 0 v 20 h 200",
dovetailedIndented: "m 200,100 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 v 15 h 200",
potenty:
"m 3,95 v 5 h 5 v 5 H 0 v 10 h 200 l 0.5,-10 H 193 v -5 h 5 v -5 h -15 v 5 h 5 v 5 h -15 v -5 h 5 v -5 h -15 v 5 h 5 v 5 h -15 v -5 h 5 v -5 h -15 v 5 h 5 v 5 h -15 v -5 h 5 v -5 h -15 v 5 h 5 v 5 h -15 v -5 h 5 v -5 h -15 v 5 h 5 v 5 H 100.5 93 v -5 h 5 V 95 H 83 v 5 h 5 v 5 H 73 v -5 h 5 V 95 H 63 v 5 h 5 v 5 H 53 v -5 h 5 V 95 H 43 v 5 h 5 v 5 H 33 v -5 h 5 V 95 H 23 v 5 h 5 v 5 H 13 v -5 h 5 v -5 z",
potentyDexter:
"m 200,105 h -2 v -10 0 0 h -10 v 5 h 5 v 5 H 183 V 95 h -10 v 5 h 5 v 5 H 168 V 95 h -10 v 5 h 5 v 5 H 153 V 95 h -10 v 5 h 5 v 5 H 138 V 95 h -10 v 5 h 5 v 5 H 123 V 95 h -10 v 5 h 5 v 5 h -10 v 0 0 -10 H 98 v 5 h 5 v 5 H 93 V 95 H 83 v 5 h 5 v 5 H 78 V 95 H 68 v 5 h 5 v 5 H 63 V 95 H 53 v 5 h 5 v 5 H 48 V 95 H 38 v 5 h 5 v 5 H 33 V 95 H 23 v 5 h 5 v 5 H 18 V 95 H 8 v 5 h 5 v 5 H 3 V 95 H 0 v 20 h 200 z",
potentySinister:
"m 2.5,95 v 10 H 0 v 10 h 202.5 v -15 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 z",
embattledGhibellin:
"M 200,200 V 100 l -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 v 15 h 200",
embattledNotched:
"m 200,105 h -5 V 95 l -5,5 -5,-5 v 10 h -5 V 95 l -5,5 -5,-5 v 10 h -5 V 95 l -5,5 -5,-5 v 10 h -5 V 95 l -5,5 -5,-5 v 10 h -5 V 95 l -5,5 -5,-5 v 10 h -5 V 95 l -5,5 -5,-5 v 10 h -5 V 95 l -5,5 -5,-5 v 10 H 90 V 95 l -5,5 -5,-5 v 10 H 75 V 95 l -5,5 -5,-5 v 10 H 60 V 95 l -5,5 -5,-5 v 10 H 45 V 95 l -5,5 -5,-5 v 10 H 30 V 95 l -5,5 -5,-5 v 10 H 15 V 95 l -5,5 -5,-5 v 10 H 0 v 10 h 200",
embattledGrady:
"m 0,95 v 20 H 200 V 95 h -2.5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 z",
dovetailed:
"m 200,95 h -7 l 4,10 h -14 l 4,-10 h -14 l 4,10 h -14 l 4,-10 h -14 l 4,10 h -14 l 4,-10 h -14 l 4,10 h -14 l 4,-10 h -14 l 4,10 h -14 l 4,-10 H 93 l 4,10 H 83 L 87,95 H 73 l 4,10 H 63 L 67,95 H 53 l 4,10 H 43 L 47,95 H 33 l 4,10 H 23 L 27,95 H 13 l 4,10 H 3 L 7,95 H 0 v 20 h 200",
dovetailedIndented:
"m 200,100 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 v 15 h 200",
nebuly:
"m 13.1,89.8 c -4.1,0 -7.3,2 -7.3,4.5 0,1.2 0.7,2.3 1.8,3.1 1.2,0.7 1.9,1.8 1.9,3 0,2.5 -3.2,4.5 -7.3,4.5 -0.5,0 -2.2,-0.2 -2.2,-0.2 V 115 h 200 v -10.1 c -3.7,-0.2 -6.7,-2.2 -6.7,-4.5 0,-1.2 0.7,-2.3 1.9,-3 1.2,-0.8 1.8,-1.9 1.8,-3.1 0,-2.5 -3.2,-4.5 -7.2,-4.5 -4.1,0 -7.3,2 -7.3,4.5 0,1.2 0.7,2.3 1.8,3.1 1.2,0.7 1.9,1.8 1.9,3 0,2.5 -3.3,4.5 -7.3,4.5 -4,0 -7.3,-2 -7.3,-4.5 0,-1.2 0.7,-2.3 1.9,-3 1.2,-0.8 1.8,-1.9 1.8,-3.1 0,-2.5 -3.2,-4.5 -7.2,-4.5 -4.1,0 -7.3,2 -7.3,4.5 0,1.2 0.7,2.3 1.8,3.1 1.2,0.7 1.9,1.8 1.9,3 -1.5,4.1 -4.2,4.4 -8.8,4.5 -4.7,-0.1 -8.7,-1.5 -8.9,-4.5 0,-1.2 0.7,-2.3 1.9,-3 1.2,-0.8 1.9,-1.9 1.9,-3.1 0,-2.5 -3.3,-4.5 -7.3,-4.5 -4.1,0 -7.3,2 -7.3,4.5 0,1.2 0.7,2.3 1.8,3.1 1.2,0.7 1.9,1.8 1.9,3 0,2.5 -3.3,4.5 -7.3,4.5 -4,0 -7.3,-2 -7.3,-4.5 0,-1.2 0.7,-2.3 1.9,-3 1.2,-0.8 1.9,-1.9 1.9,-3.1 0,-2.5 -3.3,-4.5 -7.3,-4.5 -4.1,0 -7.3,2 -7.3,4.5 0,1.2 0.7,2.3 1.8,3.1 1.2,0.7 1.9,1.8 1.9,3 0,2.5 -3.3,4.5 -7.3,4.5 -4,0 -7.3,-2 -7.3,-4.5 0,-1.2 0.7,-2.3 1.9,-3 1.2,-0.8 1.9,-1.9 1.9,-3.1 0,-2.5 -3.3,-4.5 -7.3,-4.5 -4.1,0 -7.3,2 -7.3,4.5 0,1.2 0.7,2.3 1.8,3.1 1.2,0.7 1.9,1.8 1.9,3 0,2.5 -3.3,4.5 -7.3,4.5 -4,0 -7.3,-2 -7.3,-4.5 0,-1.2 0.7,-2.3 1.9,-3 1.2,-0.8 1.9,-1.9 1.9,-3.1 0,-2.5 -3.3,-4.5 -7.3,-4.5 -4.1,0 -7.3,2 -7.3,4.5 0,1.2 0.7,2.3 1.8,3.1 1.2,0.7 1.9,1.8 1.9,3 0,2.5 -3.3,4.5 -7.3,4.5 -4,0 -7.3,-2 -7.3,-4.5 0,-1.2 0.7,-2.3 1.9,-3 1.2,-0.8 1.9,-1.9 1.9,-3.1 0,-2.5 -3.3,-4.5 -7.3,-4.5 -4.1,0 -7.3,2 -7.3,4.5 0,1.2 0.7,2.3 1.8,3.1 1.2,0.7 1.9,1.8 1.9,3 0,2.5 -3.3,4.5 -7.3,4.5 -4,0 -7.3,-2 -7.3,-4.5 0,-1.2 0.7,-2.3 1.9,-3 1.2,-0.8 1.9,-1.9 1.9,-3.1 0,-2.5 -3.3,-4.5 -7.3,-4.5 -4.1,0 -7.3,2 -7.3,4.5 0,1.2 0.7,2.3 1.8,3.1 1.2,0.7 1.9,1.8 1.9,3 0,2.5 -3.3,4.5 -7.3,4.5 -4,0 -7.3,-2 -7.3,-4.5 0,-1.2 0.7,-2.3 1.9,-3 1.2,-0.8 1.9,-1.9 1.9,-3.1 0,-2.5 -3.3,-4.5 -7.3,-4.5 z",
rayonne:
@ -1525,7 +1549,8 @@ window.COArenderer = (function () {
"m 28.83,94.9 c -4.25,0 -7.16,3.17 -8.75,5.18 -1.59,2.01 -4.5,5.18 -8.75,5.18 -2.16,0 -3.91,-1.63 -3.91,-3.64 0,-2.01 1.44,-3.6 3.6,-3.6 0.7,0 1.36,0.17 1.93,0.48 -0.33,-2.03 -2.19,-3.56 -4.45,-3.56 -4.24,0 -6.91,3.13 -8.5,5.13 V 115 h 200 v -14.89 c -1.59,2.01 -4.5,5.18 -8.75,5.18 -2.16,0 -3.91,-1.63 -3.91,-3.64 0,-2.01 1.75,-3.64 3.91,-3.64 0.7,0 1.36,0.17 1.93,0.48 -0.34,-2.01 -2.2,-3.55 -4.46,-3.55 -4.25,0 -7.16,3.17 -8.75,5.18 -1.59,2.01 -4.5,5.18 -8.75,5.18 -2.16,0 -3.91,-1.63 -3.91,-3.64 0,-2.01 1.75,-3.64 3.91,-3.64 0.7,0 1.36,0.17 1.93,0.48 -0.34,-2.01 -2.21,-3.55 -4.46,-3.55 -4.25,0 -7.16,3.17 -8.75,5.18 -1.59,2.01 -4.5,5.18 -8.75,5.18 -2.16,0 -3.91,-1.63 -3.91,-3.64 0,-2.01 1.75,-3.64 3.91,-3.64 0.7,0 1.36,0.17 1.93,0.48 -0.34,-2.01 -2.21,-3.55 -4.46,-3.55 -4.25,0 -7.16,3.17 -8.75,5.18 -1.59,2.01 -4.5,5.18 -8.75,5.18 -2.16,0 -3.91,-1.63 -3.91,-3.64 0,-2.01 1.75,-3.64 3.91,-3.64 0.7,0 1.36,0.17 1.93,0.48 -0.34,-2.01 -2.2,-3.55 -4.46,-3.55 -4.25,0 -7.16,3.17 -8.75,5.18 -1.59,2.01 -4.5,5.18 -8.75,5.18 -2.16,0 -3.91,-1.63 -3.91,-3.64 0,-2.01 1.44,-3.6 3.6,-3.6 0.7,0 1.36,0.17 1.93,0.48 -0.34,-2.01 -2.21,-3.55 -4.46,-3.55 -4.25,0 -6.6,3.09 -8.19,5.09 -1.59,2.01 -4.5,5.18 -8.75,5.18 -2.16,0 -3.91,-1.63 -3.91,-3.64 0,-2.01 1.75,-3.64 3.91,-3.64 0.7,0 1.36,0.17 1.93,0.48 -0.34,-2.01 -2.21,-3.55 -4.46,-3.55 -4.25,0 -7.16,3.17 -8.75,5.18 -1.59,2.01 -4.5,5.18 -8.75,5.18 -2.16,0 -3.91,-1.63 -3.91,-3.64 0,-2.01 1.75,-3.64 3.91,-3.64 0.7,0 1.36,0.17 1.93,0.48 -0.34,-2.01 -2.2,-3.55 -4.46,-3.55 -4.25,0 -7.16,3.17 -8.75,5.18 -1.59,2.01 -4.5,5.18 -8.75,5.18 -2.16,0 -3.91,-1.63 -3.91,-3.64 0,-2.01 1.75,-3.64 3.91,-3.64 0.7,0 1.36,0.17 1.93,0.48 -0.34,-2.01 -2.2,-3.55 -4.46,-3.55 -4.25,0 -7.16,3.17 -8.75,5.18 -1.59,2.01 -4.5,5.18 -8.75,5.18 -2.16,0 -3.91,-1.63 -3.91,-3.64 0,-2.01 1.75,-3.64 3.91,-3.64 0.7,0 1.36,0.17 1.93,0.48 -0.34,-2.01 -2.21,-3.55 -4.46,-3.55 z",
dragonTeeth:
"M 9.4,85 C 6.5,88.1 4.1,92.9 3,98.8 1.9,104.6 2.3,110.4 3.8,115 2.4,113.5 0,106.6 0,109.3 v 5.7 h 200 v -5.7 c -1.1,-2.4 -2,-5.1 -2.6,-8 -1.1,-5.9 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.9 -0.7,11.6 0.8,16.2 -2.9,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.9 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.9 -0.7,11.6 0.8,16.2 -2.9,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.9 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.9 -0.7,11.6 0.8,16.2 -2.9,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.9 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.9 -0.7,11.6 0.8,16.2 -2.9,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.9 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.9 -0.7,11.6 0.8,16.2 -2.9,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.9 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.9 -0.7,11.6 0.8,16.2 -2.9,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.9 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.9 -0.7,11.6 0.8,16.2 -2.9,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.9 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.9 -0.7,11.6 0.8,16.2 -2.9,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.9 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.9 -0.7,11.6 0.8,16.2 -1.4,-1.5 -2.8,-3.9 -3.8,-6.1 -1.1,-2.4 -2.3,-6.1 -2.6,-7.7 -0.2,-5.9 0.2,-11.7 1.7,-16.3 -3,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.8 -0.7,11.6 0.8,16.2 -2.9,-3.1 -5.3,-7.9 -6.4,-13.8 -1,-5.8 -0.7,-11.6 0.9,-16.2 -3,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.8 -0.7,11.6 0.8,16.2 -2.9,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.8 -0.7,-11.6 0.9,-16.2 -3,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.8 -0.7,11.6 0.8,16.2 -2.9,-3.1 -5.3,-7.9 -6.4,-13.8 C 63,95.4 63.4,89.6 64.9,85 c -2.9,3.1 -5.3,7.9 -6.3,13.8 -1.1,5.8 -0.7,11.6 0.8,16.2 -3,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.8 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1,5.8 -0.6,11.6 0.9,16.2 -3,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.8 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1,5.8 -0.7,11.6 0.9,16.2 -3,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.8 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.8 -0.7,11.6 0.9,16.2 -3,-3.1 -5.3,-7.9 -6.4,-13.8 C 18.6,95.4 19,89.6 20.5,85 17.6,88.1 15.2,92.9 14.1,98.8 13,104.6 13.4,110.4 14.9,115 12,111.9 9.6,107.1 8.6,101.2 7.5,95.4 7.9,89.6 9.4,85 Z",
firTrees: "m 3.9,90 -4,7 2,-0.5 L 0,100 v 15 h 200 v -15 l -1.9,-3.5 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4.1,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4.1,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 z",
firTrees:
"m 3.9,90 -4,7 2,-0.5 L 0,100 v 15 h 200 v -15 l -1.9,-3.5 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4.1,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4.1,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 z",
flechy: "m 0,100 h 85 l 15,-15 15,15 h 85 v 15 H 0 Z",
barby: "m 0,100 h 85 l 15,15 15,-15 h 85 v 15 H 0 Z",
enclavy: "M 0,100 H 85 V 85 h 30 v 15 h 85 v 15 H 0 Z",
@ -1550,12 +1575,18 @@ window.COArenderer = (function () {
// lined divisions
perFessLined: line => `<path d="${line}"/><rect x="0" y="115" width="200" height="85" shape-rendering="crispedges"/>`,
perPaleLined: line => `<path d="${line}" transform="rotate(-90 100 100)"/><rect x="115" y="0" width="85" height="200" shape-rendering="crispedges"/>`,
perBendLined: line => `<path d="${line}" transform="translate(-10 -10) rotate(45 110 110) scale(1.1)"/><rect x="0" y="115" width="200" height="85" transform="translate(-10 -10) rotate(45 110 110) scale(1.1)" shape-rendering="crispedges"/>`,
perBendSinisterLined: line => `<path d="${line}" transform="translate(-10 -10) rotate(-45 110 110) scale(1.1)"/><rect x="0" y="115" width="200" height="85" transform="translate(-10 -10) rotate(-45 110 110) scale(1.1)" shape-rendering="crispedges"/>`,
perChevronLined: line => `<rect x="15" y="115" width="200" height="200" transform="translate(70 70) rotate(45 100 100)"/><path d="${line}" transform="translate(129 71) rotate(-45 -100 100) scale(-1 1)"/><path d="${line}" transform="translate(71 71) rotate(45 100 100)"/>`,
perChevronReversedLined: line => `<rect x="15" y="115" width="200" height="200" transform="translate(-70 -70) rotate(225.001 100 100)"/><path d="${line}" transform="translate(-70.7 -70.7) rotate(225 100 100) scale(1 1)"/><path d="${line}" transform="translate(270.7 -70.7) rotate(-225 -100 100) scale(-1 1)"/>`,
perCrossLined: line => `<rect x="100" y="0" width="100" height="92.5"/><rect x="0" y="107.5" width="100" height="92.5"/><path d="${line}" transform="translate(0 50) scale(.5001)"/><path d="${line}" transform="translate(200 150) scale(-.5)"/>`,
perPileLined: line => `<path d="${line}" transform="translate(161.66 10) rotate(66.66 -100 100) scale(-1 1)"/><path d="${line}" transform="translate(38.33 10) rotate(-66.66 100 100)"/><polygon points="-2.15,0 84.15,200 115.85,200 202.15,0 200,200 0,200"/>`,
perBendLined: line =>
`<path d="${line}" transform="translate(-10 -10) rotate(45 110 110) scale(1.1)"/><rect x="0" y="115" width="200" height="85" transform="translate(-10 -10) rotate(45 110 110) scale(1.1)" shape-rendering="crispedges"/>`,
perBendSinisterLined: line =>
`<path d="${line}" transform="translate(-10 -10) rotate(-45 110 110) scale(1.1)"/><rect x="0" y="115" width="200" height="85" transform="translate(-10 -10) rotate(-45 110 110) scale(1.1)" shape-rendering="crispedges"/>`,
perChevronLined: line =>
`<rect x="15" y="115" width="200" height="200" transform="translate(70 70) rotate(45 100 100)"/><path d="${line}" transform="translate(129 71) rotate(-45 -100 100) scale(-1 1)"/><path d="${line}" transform="translate(71 71) rotate(45 100 100)"/>`,
perChevronReversedLined: line =>
`<rect x="15" y="115" width="200" height="200" transform="translate(-70 -70) rotate(225.001 100 100)"/><path d="${line}" transform="translate(-70.7 -70.7) rotate(225 100 100) scale(1 1)"/><path d="${line}" transform="translate(270.7 -70.7) rotate(-225 -100 100) scale(-1 1)"/>`,
perCrossLined: line =>
`<rect x="100" y="0" width="100" height="92.5"/><rect x="0" y="107.5" width="100" height="92.5"/><path d="${line}" transform="translate(0 50) scale(.5001)"/><path d="${line}" transform="translate(200 150) scale(-.5)"/>`,
perPileLined: line =>
`<path d="${line}" transform="translate(161.66 10) rotate(66.66 -100 100) scale(-1 1)"/><path d="${line}" transform="translate(38.33 10) rotate(-66.66 100 100)"/><polygon points="-2.15,0 84.15,200 115.85,200 202.15,0 200,200 0,200"/>`,
// straight ordinaries
fess: `<rect x="0" y="75" width="200" height="50"/>`,
pale: `<rect x="75" y="0" width="50" height="200"/>`,
@ -1591,65 +1622,162 @@ window.COArenderer = (function () {
pilesInPoint: `<path d="M15,0 100,200 60,0Z M80,0 100,200 120,0Z M140,0 100,200 185,0Z"/>`,
label: `<path d="m 46,54.8 6.6,-15.6 95.1,0 5.9,15.5 -16.8,0.1 4.5,-11.8 L 104,43 l 4.3,11.9 -16.8,0 4.3,-11.8 -37.2,0 4.5,11.8 -16.9,0 z"/>`,
// lined ordinaries
fessLined: line => `<path d="${line}" transform="translate(0 -25)"/><path d="${line}" transform="translate(0 25) rotate(180 100 100)"/><rect x="0" y="88" width="200" height="24" stroke="none"/>`,
paleLined: line => `<path d="${line}" transform="rotate(-90 100 100) translate(0 -25)"/><path d="${line}" transform="rotate(90 100 100) translate(0 -25)"/><rect x="88" y="0" width="24" height="200" stroke="none"/>`,
bendLined: line => `<path d="${line}" transform="translate(8 -18) rotate(45 110 100) scale(1.1 1)"/><path d="${line}" transform="translate(-28 18) rotate(225 110 100) scale(1.1 1)"/><rect x="0" y="88" width="200" height="24" transform="translate(-10 0) rotate(45 110 100) scale(1.1 1)" stroke="none"/>`,
bendSinisterLined: line => `<path d="${line}" transform="translate(-28 -18) rotate(-45 110 100) scale(1.1 1)"/><path d="${line}" transform="translate(8 18) rotate(-225 110 100) scale(1.1 1)"/><rect x="0" y="88" width="200" height="24" transform="translate(-10 0) rotate(-45 110 100) scale(1.1 1)" stroke="none"/>`,
fessLined: line =>
`<path d="${line}" transform="translate(0 -25)"/><path d="${line}" transform="translate(0 25) rotate(180 100 100)"/><rect x="0" y="88" width="200" height="24" stroke="none"/>`,
paleLined: line =>
`<path d="${line}" transform="rotate(-90 100 100) translate(0 -25)"/><path d="${line}" transform="rotate(90 100 100) translate(0 -25)"/><rect x="88" y="0" width="24" height="200" stroke="none"/>`,
bendLined: line =>
`<path d="${line}" transform="translate(8 -18) rotate(45 110 100) scale(1.1 1)"/><path d="${line}" transform="translate(-28 18) rotate(225 110 100) scale(1.1 1)"/><rect x="0" y="88" width="200" height="24" transform="translate(-10 0) rotate(45 110 100) scale(1.1 1)" stroke="none"/>`,
bendSinisterLined: line =>
`<path d="${line}" transform="translate(-28 -18) rotate(-45 110 100) scale(1.1 1)"/><path d="${line}" transform="translate(8 18) rotate(-225 110 100) scale(1.1 1)"/><rect x="0" y="88" width="200" height="24" transform="translate(-10 0) rotate(-45 110 100) scale(1.1 1)" stroke="none"/>`,
chiefLined: line => `<path d="${line}" transform="translate(0,-25) rotate(180.00001 100 100)"/><rect width="200" height="62" stroke="none"/>`,
barLined: line => `<path d="${line}" transform="translate(0,-12.5)"/><path d="${line}" transform="translate(0,12.5) rotate(180.00001 100 100)"/><rect x="0" y="94" width="200" height="12" stroke="none"/>`,
barLined: line =>
`<path d="${line}" transform="translate(0,-12.5)"/><path d="${line}" transform="translate(0,12.5) rotate(180.00001 100 100)"/><rect x="0" y="94" width="200" height="12" stroke="none"/>`,
gemelleLined: line => `<path d="${line}" transform="translate(0,-22.5)"/><path d="${line}" transform="translate(0,22.5) rotate(180.00001 100 100)"/>`,
fessCotissedLined: line => `<path d="${line}" transform="translate(0 15) scale(1 .5)"/><path d="${line}" transform="translate(0 85) rotate(180 100 50) scale(1 .5)"/><rect x="0" y="80" width="200" height="40"/>`,
fessDoubleCotissedLined: line => `<rect x="0" y="85" width="200" height="30"/><rect x="0" y="72.5" width="200" height="7.5"/><rect x="0" y="120" width="200" height="7.5"/><path d="${line}" transform="translate(0 10) scale(1 .5)"/><path d="${line}" transform="translate(0 90) rotate(180 100 50) scale(1 .5)"/>`,
bendletLined: line => `<path d="${line}" transform="translate(2 -12) rotate(45 110 100) scale(1.1 1)"/><path d="${line}" transform="translate(-22 12) rotate(225 110 100) scale(1.1 1)"/><rect x="0" y="94" width="200" height="12" transform="translate(-10 0) rotate(45 110 100) scale(1.1 1)" stroke="none"/>`,
bendletSinisterLined: line => `<path d="${line}" transform="translate(-22 -12) rotate(-45 110 100) scale(1.1 1)"/><path d="${line}" transform="translate(2 12) rotate(-225 110 100) scale(1.1 1)"/><rect x="0" y="94" width="200" height="12" transform="translate(-10 0) rotate(-45 110 100) scale(1.1 1)" stroke="none"/>`,
fessCotissedLined: line =>
`<path d="${line}" transform="translate(0 15) scale(1 .5)"/><path d="${line}" transform="translate(0 85) rotate(180 100 50) scale(1 .5)"/><rect x="0" y="80" width="200" height="40"/>`,
fessDoubleCotissedLined: line =>
`<rect x="0" y="85" width="200" height="30"/><rect x="0" y="72.5" width="200" height="7.5"/><rect x="0" y="120" width="200" height="7.5"/><path d="${line}" transform="translate(0 10) scale(1 .5)"/><path d="${line}" transform="translate(0 90) rotate(180 100 50) scale(1 .5)"/>`,
bendletLined: line =>
`<path d="${line}" transform="translate(2 -12) rotate(45 110 100) scale(1.1 1)"/><path d="${line}" transform="translate(-22 12) rotate(225 110 100) scale(1.1 1)"/><rect x="0" y="94" width="200" height="12" transform="translate(-10 0) rotate(45 110 100) scale(1.1 1)" stroke="none"/>`,
bendletSinisterLined: line =>
`<path d="${line}" transform="translate(-22 -12) rotate(-45 110 100) scale(1.1 1)"/><path d="${line}" transform="translate(2 12) rotate(-225 110 100) scale(1.1 1)"/><rect x="0" y="94" width="200" height="12" transform="translate(-10 0) rotate(-45 110 100) scale(1.1 1)" stroke="none"/>`,
terraceLined: line => `<path d="${line}" transform="translate(0,50)"/><rect x="0" y="164" width="200" height="36" stroke="none"/>`,
crossLined: line => `<path d="${line}" transform="translate(0,-14.5)"/><path d="${line}" transform="rotate(180 100 100) translate(0,-14.5)"/><path d="${line}" transform="rotate(-90 100 100) translate(0,-14.5)"/><path d="${line}" transform="rotate(-270 100 100) translate(0,-14.5)"/>`,
crossPartedLined: line => `<path d="${line}" transform="translate(0,-20)"/><path d="${line}" transform="rotate(180 100 100) translate(0,-20)"/><path d="${line}" transform="rotate(-90 100 100) translate(0,-20)"/><path d="${line}" transform="rotate(-270 100 100) translate(0,-20)"/>`,
saltireLined: line => `<path d="${line}" transform="translate(0 -10) rotate(45 110 100) scale(1.1 1)"/><path d="${line}" transform="translate(-20 10) rotate(225 110 100) scale(1.1 1)"/><path d="${line}" transform="translate(-20 -10) rotate(-45 110 100) scale(1.1 1)"/><path d="${line}" transform="translate(0 10) rotate(-225 110 100) scale(1.1 1)"/>`,
saltirePartedLined: line => `<path d="${line}" transform="translate(3 -13) rotate(45 110 100) scale(1.1 1)"/><path d="${line}" transform="translate(-23 13) rotate(225 110 100) scale(1.1 1)"/><path d="${line}" transform="translate(-23 -13) rotate(-45 110 100) scale(1.1 1)"/><path d="${line}" transform="translate(3 13) rotate(-225 110 100) scale(1.1 1)"/>`
crossLined: line =>
`<path d="${line}" transform="translate(0,-14.5)"/><path d="${line}" transform="rotate(180 100 100) translate(0,-14.5)"/><path d="${line}" transform="rotate(-90 100 100) translate(0,-14.5)"/><path d="${line}" transform="rotate(-270 100 100) translate(0,-14.5)"/>`,
crossPartedLined: line =>
`<path d="${line}" transform="translate(0,-20)"/><path d="${line}" transform="rotate(180 100 100) translate(0,-20)"/><path d="${line}" transform="rotate(-90 100 100) translate(0,-20)"/><path d="${line}" transform="rotate(-270 100 100) translate(0,-20)"/>`,
saltireLined: line =>
`<path d="${line}" transform="translate(0 -10) rotate(45 110 100) scale(1.1 1)"/><path d="${line}" transform="translate(-20 10) rotate(225 110 100) scale(1.1 1)"/><path d="${line}" transform="translate(-20 -10) rotate(-45 110 100) scale(1.1 1)"/><path d="${line}" transform="translate(0 10) rotate(-225 110 100) scale(1.1 1)"/>`,
saltirePartedLined: line =>
`<path d="${line}" transform="translate(3 -13) rotate(45 110 100) scale(1.1 1)"/><path d="${line}" transform="translate(-23 13) rotate(225 110 100) scale(1.1 1)"/><path d="${line}" transform="translate(-23 -13) rotate(-45 110 100) scale(1.1 1)"/><path d="${line}" transform="translate(3 13) rotate(-225 110 100) scale(1.1 1)"/>`
};
const patterns = {
semy: (p, c1, c2, size, chargeId) => `<pattern id="${p}" width="${size * 0.125}" height="${size * 0.125}" viewBox="0 0 200 200" stroke="#000"><rect width="200" height="200" fill="${c1}" stroke="none"/><g fill="${c2}"><use transform="translate(-100 -50)" href="#${chargeId}"/><use transform="translate(100 -50)" href="#${chargeId}"/><use transform="translate(0 50)" href="#${chargeId}"/></g></pattern>`,
vair: (p, c1, c2, size) => `<pattern id="${p}" width="${size * 0.125}" height="${size * 0.25}" viewBox="0 0 25 50" stroke="#000" stroke-width=".2"><rect width="25" height="25" fill="${c1}" stroke="none"/><path d="m12.5,0 l6.25,6.25 v12.5 l6.25,6.25 h-25 l6.25,-6.25 v-12.5 z" fill="${c2}"/><rect x="0" y="25" width="25" height="25" fill="${c2}" stroke="none"/><path d="m25,25 l-6.25,6.25 v12.5 l-6.25,6.25 l-6.25,-6.25 v-12.5 l-6.25,-6.25 z" fill="${c1}"/><path d="M0 50 h25" fill="none"/></pattern>`,
counterVair: (p, c1, c2, size) => `<pattern id="${p}" width="${size * 0.125}" height="${size * 0.25}" viewBox="0 0 25 50" stroke="#000" stroke-width=".2"><rect width="25" height="50" fill="${c2}" stroke="none"/><path d="m 12.5,0 6.25,6.25 v 12.5 L 25,25 18.75,31.25 v 12.5 L 12.5,50 6.25,43.75 V 31.25 L 0,25 6.25,18.75 V 6.25 Z" fill="${c1}"/></pattern>`,
vairInPale: (p, c1, c2, size) => `<pattern id="${p}" width="${size * 0.125}" height="${size * 0.125}" viewBox="0 0 25 25"><rect width="25" height="25" fill="${c1}"/><path d="m12.5,0 l6.25,6.25 v12.5 l6.25,6.25 h-25 l6.25,-6.25 v-12.5 z" fill="${c2}" stroke="#000" stroke-width=".2"/></pattern>`,
vairEnPointe: (p, c1, c2, size) => `<pattern id="${p}" width="${size * 0.125}" height="${size * 0.25}" viewBox="0 0 25 50"><rect width="25" height="25" fill="${c2}"/><path d="m12.5,0 l6.25,6.25 v12.5 l6.25,6.25 h-25 l6.25,-6.25 v-12.5 z" fill="${c1}"/><rect x="0" y="25" width="25" height="25" fill="${c1}" stroke-width="1" stroke="${c1}"/><path d="m12.5,25 l6.25,6.25 v12.5 l6.25,6.25 h-25 l6.25,-6.25 v-12.5 z" fill="${c2}"/></pattern>`,
vairAncien: (p, c1, c2, size) => `<pattern id="${p}" width="${size * 0.125}" height="${size * 0.125}" viewBox="0 0 100 100"><rect width="100" height="100" fill="${c1}"/><path fill="${c2}" stroke="none" d="m 0,90 c 10,0 25,-5 25,-40 0,-25 10,-40 25,-40 15,0 25,15 25,40 0,35 15,40 25,40 v 10 H 0 Z"/><path fill="none" stroke="#000" d="M 0,90 c 10,0 25,-5 25,-40 0,-35 15,-40 25,-40 10,0 25,5 25,40 0,35 15,40 25,40 M0,100 h100"/></pattern>`,
potent: (p, c1, c2, size) => `<pattern id="${p}" width="${size * 0.125}" height="${size * 0.125}" viewBox="0 0 200 200" stroke="#000"><rect width="200" height="100" fill="${c1}" stroke="none"/><rect y="100" width="200" height="100" fill="${c2}" stroke="none"/><path d="m25 50h50v-50h50v50h50v50h-150z" fill="${c2}"/><path d="m25 100v50h50v50h50v-50h50v-50z" fill="${c1}"/><path d="m0 0h200 M0 100h200" fill="none"/></pattern>`,
counterPotent: (p, c1, c2, size) => `<pattern id="${p}" width="${size * 0.125}" height="${size * 0.125}" viewBox="0 0 200 200" stroke="none"><rect width="200" height="200" fill="${c1}"/><path d="m25 50h50v-50h50v50h50v100h-50v50h-50v-50h-50v-50z" fill="${c2}"/><path d="m0 0h200 M0 100h200 M0 200h200"/></pattern>`,
potentInPale: (p, c1, c2, size) => `<pattern id="${p}" width="${size * 0.125}" height="${size * 0.0625}" viewBox="0 0 200 100" stroke-width="1"><rect width="200" height="100" fill="${c1}" stroke="none"/><path d="m25 50h50v-50h50v50h50v50h-150z" fill="${c2}" stroke="#000"/><path d="m0 0h200 M0 100h200" fill="none" stroke="#000"/></pattern>`,
potentEnPointe: (p, c1, c2, size) => `<pattern id="${p}" width="${size * 0.125}" height="${size * 0.125}" viewBox="0 0 200 200" stroke="none"><rect width="200" height="200" fill="${c1}"/><path d="m0 0h25v50h50v50h50v-50h50v-50h25v100h-25v50h-50v50h-50v-50h-50v-50h-25v-100" fill="${c2}"/></pattern>`,
semy: (p, c1, c2, size, chargeId) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.125
}" viewBox="0 0 200 200" stroke="#000"><rect width="200" height="200" fill="${c1}" stroke="none"/><g fill="${c2}"><use transform="translate(-100 -50)" href="#${chargeId}"/><use transform="translate(100 -50)" href="#${chargeId}"/><use transform="translate(0 50)" href="#${chargeId}"/></g></pattern>`,
vair: (p, c1, c2, size) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.25
}" viewBox="0 0 25 50" stroke="#000" stroke-width=".2"><rect width="25" height="25" fill="${c1}" stroke="none"/><path d="m12.5,0 l6.25,6.25 v12.5 l6.25,6.25 h-25 l6.25,-6.25 v-12.5 z" fill="${c2}"/><rect x="0" y="25" width="25" height="25" fill="${c2}" stroke="none"/><path d="m25,25 l-6.25,6.25 v12.5 l-6.25,6.25 l-6.25,-6.25 v-12.5 l-6.25,-6.25 z" fill="${c1}"/><path d="M0 50 h25" fill="none"/></pattern>`,
counterVair: (p, c1, c2, size) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.25
}" viewBox="0 0 25 50" stroke="#000" stroke-width=".2"><rect width="25" height="50" fill="${c2}" stroke="none"/><path d="m 12.5,0 6.25,6.25 v 12.5 L 25,25 18.75,31.25 v 12.5 L 12.5,50 6.25,43.75 V 31.25 L 0,25 6.25,18.75 V 6.25 Z" fill="${c1}"/></pattern>`,
vairInPale: (p, c1, c2, size) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.125
}" viewBox="0 0 25 25"><rect width="25" height="25" fill="${c1}"/><path d="m12.5,0 l6.25,6.25 v12.5 l6.25,6.25 h-25 l6.25,-6.25 v-12.5 z" fill="${c2}" stroke="#000" stroke-width=".2"/></pattern>`,
vairEnPointe: (p, c1, c2, size) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.25
}" viewBox="0 0 25 50"><rect width="25" height="25" fill="${c2}"/><path d="m12.5,0 l6.25,6.25 v12.5 l6.25,6.25 h-25 l6.25,-6.25 v-12.5 z" fill="${c1}"/><rect x="0" y="25" width="25" height="25" fill="${c1}" stroke-width="1" stroke="${c1}"/><path d="m12.5,25 l6.25,6.25 v12.5 l6.25,6.25 h-25 l6.25,-6.25 v-12.5 z" fill="${c2}"/></pattern>`,
vairAncien: (p, c1, c2, size) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.125
}" viewBox="0 0 100 100"><rect width="100" height="100" fill="${c1}"/><path fill="${c2}" stroke="none" d="m 0,90 c 10,0 25,-5 25,-40 0,-25 10,-40 25,-40 15,0 25,15 25,40 0,35 15,40 25,40 v 10 H 0 Z"/><path fill="none" stroke="#000" d="M 0,90 c 10,0 25,-5 25,-40 0,-35 15,-40 25,-40 10,0 25,5 25,40 0,35 15,40 25,40 M0,100 h100"/></pattern>`,
potent: (p, c1, c2, size) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.125
}" viewBox="0 0 200 200" stroke="#000"><rect width="200" height="100" fill="${c1}" stroke="none"/><rect y="100" width="200" height="100" fill="${c2}" stroke="none"/><path d="m25 50h50v-50h50v50h50v50h-150z" fill="${c2}"/><path d="m25 100v50h50v50h50v-50h50v-50z" fill="${c1}"/><path d="m0 0h200 M0 100h200" fill="none"/></pattern>`,
counterPotent: (p, c1, c2, size) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.125
}" viewBox="0 0 200 200" stroke="none"><rect width="200" height="200" fill="${c1}"/><path d="m25 50h50v-50h50v50h50v100h-50v50h-50v-50h-50v-50z" fill="${c2}"/><path d="m0 0h200 M0 100h200 M0 200h200"/></pattern>`,
potentInPale: (p, c1, c2, size) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.0625
}" viewBox="0 0 200 100" stroke-width="1"><rect width="200" height="100" fill="${c1}" stroke="none"/><path d="m25 50h50v-50h50v50h50v50h-150z" fill="${c2}" stroke="#000"/><path d="m0 0h200 M0 100h200" fill="none" stroke="#000"/></pattern>`,
potentEnPointe: (p, c1, c2, size) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.125
}" viewBox="0 0 200 200" stroke="none"><rect width="200" height="200" fill="${c1}"/><path d="m0 0h25v50h50v50h50v-50h50v-50h25v100h-25v50h-50v50h-50v-50h-50v-50h-25v-100" fill="${c2}"/></pattern>`,
ermine: (p, c1, c2, size) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.125
}" viewBox="0 0 200 200" fill="${c2}"><rect width="200" height="200" fill="${c1}"/><g stroke="none" fill="${c2}"><g transform="translate(-100 -50)"><path d="m100 81.1c-4.25 17.6-12.7 29.8-21.2 38.9 3.65-0.607 7.9-3.04 11.5-5.47-2.42 4.86-4.86 8.51-7.3 12.7 1.82-0.607 6.07-4.86 12.7-10.9 1.21 8.51 2.42 17.6 4.25 23.6 1.82-5.47 3.04-15.2 4.25-23.6 3.65 3.65 7.3 7.9 12.7 10.9l-7.9-13.3c3.65 1.82 7.9 4.86 11.5 6.07-9.11-9.11-17-21.2-20.6-38.9z"/><path d="m82.4 81.7c-0.607-0.607-6.07 2.42-9.72-4.25 7.9 6.68 15.2-7.3 21.8 1.82 1.82 4.25-6.68 10.9-12.1 2.42z"/><path d="m117 81.7c0.607-1.21 6.07 2.42 9.11-4.86-7.3 7.3-15.2-7.3-21.2 2.42-1.82 4.25 6.68 10.9 12.1 2.42z"/><path d="m101 66.5c-1.02-0.607 3.58-4.25-3.07-8.51 5.63 7.9-10.2 10.9-1.54 17.6 3.58 2.42 12.2-2.42 4.6-9.11z"/></g><g transform="translate(100 -50)"><path d="m100 81.1c-4.25 17.6-12.7 29.8-21.2 38.9 3.65-0.607 7.9-3.04 11.5-5.47-2.42 4.86-4.86 8.51-7.3 12.7 1.82-0.607 6.07-4.86 12.7-10.9 1.21 8.51 2.42 17.6 4.25 23.6 1.82-5.47 3.04-15.2 4.25-23.6 3.65 3.65 7.3 7.9 12.7 10.9l-7.9-13.3c3.65 1.82 7.9 4.86 11.5 6.07-9.11-9.11-17-21.2-20.6-38.9z"/><path d="m82.4 81.7c-0.607-0.607-6.07 2.42-9.72-4.25 7.9 6.68 15.2-7.3 21.8 1.82 1.82 4.25-6.68 10.9-12.1 2.42z"/><path d="m117 81.7c0.607-1.21 6.07 2.42 9.11-4.86-7.3 7.3-15.2-7.3-21.2 2.42-1.82 4.25 6.68 10.9 12.1 2.42z"/><path d="m101 66.5c-1.02-0.607 3.58-4.25-3.07-8.51 5.63 7.9-10.2 10.9-1.54 17.6 3.58 2.42 12.2-2.42 4.6-9.11z"/></g><g transform="translate(0 50)"><path d="m100 81.1c-4.25 17.6-12.7 29.8-21.2 38.9 3.65-0.607 7.9-3.04 11.5-5.47-2.42 4.86-4.86 8.51-7.3 12.7 1.82-0.607 6.07-4.86 12.7-10.9 1.21 8.51 2.42 17.6 4.25 23.6 1.82-5.47 3.04-15.2 4.25-23.6 3.65 3.65 7.3 7.9 12.7 10.9l-7.9-13.3c3.65 1.82 7.9 4.86 11.5 6.07-9.11-9.11-17-21.2-20.6-38.9z"/><path d="m82.4 81.7c-0.607-0.607-6.07 2.42-9.72-4.25 7.9 6.68 15.2-7.3 21.8 1.82 1.82 4.25-6.68 10.9-12.1 2.42z"/><path d="m117 81.7c0.607-1.21 6.07 2.42 9.11-4.86-7.3 7.3-15.2-7.3-21.2 2.42-1.82 4.25 6.68 10.9 12.1 2.42z"/><path d="m101 66.5c-1.02-0.607 3.58-4.25-3.07-8.51 5.63 7.9-10.2 10.9-1.54 17.6 3.58 2.42 12.2-2.42 4.6-9.11z"/></g></g></pattern>`,
chequy: (p, c1, c2, size) => `<pattern id="${p}" width="${size * 0.25}" height="${size * 0.25}" viewBox="0 0 50 50" fill="${c2}"><rect width="50" height="50"/><rect width="25" height="25" fill="${c1}"/><rect x="25" y="25" width="25" height="25" fill="${c1}"/></pattern>`,
lozengy: (p, c1, c2, size) => `<pattern id="${p}" width="${size * 0.125}" height="${size * 0.125}" viewBox="0 0 50 50"><rect width="50" height="50" fill="${c1}"/><polygon points="25,0 50,25 25,50 0,25" fill="${c2}"/></pattern>`,
fusily: (p, c1, c2, size) => `<pattern id="${p}" width="${size * 0.125}" height="${size * 0.25}" viewBox="0 0 50 100"><rect width="50" height="100" fill="${c2}"/><polygon points="25,0 50,50 25,100 0,50" fill="${c1}"/></pattern>`,
pally: (p, c1, c2, size) => `<pattern id="${p}" width="${size * 0.5}" height="${size * 0.125}" viewBox="0 0 100 25"><rect width="100" height="25" fill="${c2}"/><rect x="25" y="0" width="25" height="25" fill="${c1}"/><rect x="75" y="0" width="25" height="25" fill="${c1}"/></pattern>`,
barry: (p, c1, c2, size) => `<pattern id="${p}" width="${size * 0.125}" height="${size * 0.5}" viewBox="0 0 25 100"><rect width="25" height="100" fill="${c2}"/><rect x="0" y="25" width="25" height="25" fill="${c1}"/><rect x="0" y="75" width="25" height="25" fill="${c1}"/></pattern>`,
gemelles: (p, c1, c2, size) => `<pattern id="${p}" width="${size * 0.125}" height="${size * 0.125}" viewBox="0 0 50 50"><rect width="50" height="50" fill="${c1}"/><rect y="5" width="50" height="10" fill="${c2}"/><rect y="40" width="50" height="10" fill="${c2}"/></pattern>`,
bendy: (p, c1, c2, size) => `<pattern id="${p}" width="${size * 0.5}" height="${size * 0.5}" viewBox="0 0 100 100"><rect width="100" height="100" fill="${c1}"/><polygon points="0,25 75,100 25,100 0,75" fill="${c2}"/><polygon points="25,0 75,0 100,25 100,75" fill="${c2}"/></pattern>`,
bendySinister: (p, c1, c2, size) => `<pattern id="${p}" width="${size * 0.5}" height="${size * 0.5}" viewBox="0 0 100 100"><rect width="100" height="100" fill="${c2}"/><polygon points="0,25 25,0 75,0 0,75" fill="${c1}"/><polygon points="25,100 100,25 100,75 75,100" fill="${c1}"/></pattern>`,
palyBendy: (p, c1, c2, size) => `<pattern id="${p}" width="${size * 0.6258}" height="${size * 0.3576}" viewBox="0 0 175 100"><rect y="0" x="0" width="175" height="100" fill="${c2}"/><g fill="${c1}"><path d="m0 20 35 30v50l-35-30z"/><path d="m35 0 35 30v50l-35-30z"/><path d="m70 0h23l12 10v50l-35-30z"/><path d="m70 80 23 20h-23z"/><path d="m105 60 35 30v10h-35z"/><path d="m105 0h35v40l-35-30z"/><path d="m 140,40 35,30 v 30 h -23 l -12,-10z"/><path d="M 175,0 V 20 L 152,0 Z"/></g></pattern>`,
barryBendy: (p, c1, c2, size) => `<pattern id="${p}" width="${size * 0.3572}" height="${size * 0.6251}" viewBox="0 0 100 175"><rect width="100" height="175" fill="${c2}"/><g fill="${c1}"><path d="m20 0 30 35h50l-30-35z"/><path d="m0 35 30 35h50l-30-35z"/><path d="m0 70v23l10 12h50l-30-35z"/><path d="m80 70 20 23v-23z"/><path d="m60 105 30 35h10v-35z"/><path d="m0 105v35h40l-30-35z"/><path d="m 40,140 30,35 h 30 v -23 l -10,-12 z"/><path d="m0 175h20l-20-23z"/></g></pattern>`,
pappellony: (p, c1, c2, size) => `<pattern id="${p}" width="${size * 0.125}" height="${size * 0.125}" viewBox="0 0 100 100"><rect width="100" height="100" fill="${c1}"/><circle cx="0" cy="51" r="45" stroke="${c2}" fill="${c1}" stroke-width="10"/><circle cx="100" cy="51" r="45" stroke="${c2}" fill="${c1}" stroke-width="10"/><circle cx="50" cy="1" r="45" stroke="${c2}" fill="${c1}" stroke-width="10"/></pattern>`,
pappellony2: (p, c1, c2, size) => `<pattern id="${p}" width="${size * 0.125}" height="${size * 0.125}" viewBox="0 0 100 100" stroke="#000" stroke-width="2"><rect width="100" height="100" fill="${c1}" stroke="none"/><circle cy="50" r="49" fill="${c2}"/><circle cx="100" cy="50" r="49" fill="${c2}"/><circle cx="50" cy="0" r="49" fill="${c1}"/></pattern>`,
scaly: (p, c1, c2, size) => `<pattern id="${p}" width="${size * 0.125}" height="${size * 0.125}" viewBox="0 0 100 100" stroke="#000"><rect width="100" height="100" fill="${c1}" stroke="none"/><path d="M 0,84 C -40,84 -50,49 -50,49 -50,79 -27,99 0,99 27,99 50,79 50,49 50,49 40,84 0,84 Z" fill="${c2}"/><path d="M 100,84 C 60,84 50,49 50,49 c 0,30 23,50 50,50 27,0 50,-20 50,-50 0,0 -10,35 -50,35 z" fill="${c2}"/><path d="M 50,35 C 10,35 0,0 0,0 0,30 23,50 50,50 77,50 100,30 100,0 100,0 90,35 50,35 Z" fill="${c2}"/></pattern>`,
chequy: (p, c1, c2, size) =>
`<pattern id="${p}" width="${size * 0.25}" height="${
size * 0.25
}" viewBox="0 0 50 50" fill="${c2}"><rect width="50" height="50"/><rect width="25" height="25" fill="${c1}"/><rect x="25" y="25" width="25" height="25" fill="${c1}"/></pattern>`,
lozengy: (p, c1, c2, size) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.125
}" viewBox="0 0 50 50"><rect width="50" height="50" fill="${c1}"/><polygon points="25,0 50,25 25,50 0,25" fill="${c2}"/></pattern>`,
fusily: (p, c1, c2, size) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.25
}" viewBox="0 0 50 100"><rect width="50" height="100" fill="${c2}"/><polygon points="25,0 50,50 25,100 0,50" fill="${c1}"/></pattern>`,
pally: (p, c1, c2, size) =>
`<pattern id="${p}" width="${size * 0.5}" height="${
size * 0.125
}" viewBox="0 0 100 25"><rect width="100" height="25" fill="${c2}"/><rect x="25" y="0" width="25" height="25" fill="${c1}"/><rect x="75" y="0" width="25" height="25" fill="${c1}"/></pattern>`,
barry: (p, c1, c2, size) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.5
}" viewBox="0 0 25 100"><rect width="25" height="100" fill="${c2}"/><rect x="0" y="25" width="25" height="25" fill="${c1}"/><rect x="0" y="75" width="25" height="25" fill="${c1}"/></pattern>`,
gemelles: (p, c1, c2, size) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.125
}" viewBox="0 0 50 50"><rect width="50" height="50" fill="${c1}"/><rect y="5" width="50" height="10" fill="${c2}"/><rect y="40" width="50" height="10" fill="${c2}"/></pattern>`,
bendy: (p, c1, c2, size) =>
`<pattern id="${p}" width="${size * 0.5}" height="${
size * 0.5
}" viewBox="0 0 100 100"><rect width="100" height="100" fill="${c1}"/><polygon points="0,25 75,100 25,100 0,75" fill="${c2}"/><polygon points="25,0 75,0 100,25 100,75" fill="${c2}"/></pattern>`,
bendySinister: (p, c1, c2, size) =>
`<pattern id="${p}" width="${size * 0.5}" height="${
size * 0.5
}" viewBox="0 0 100 100"><rect width="100" height="100" fill="${c2}"/><polygon points="0,25 25,0 75,0 0,75" fill="${c1}"/><polygon points="25,100 100,25 100,75 75,100" fill="${c1}"/></pattern>`,
palyBendy: (p, c1, c2, size) =>
`<pattern id="${p}" width="${size * 0.6258}" height="${
size * 0.3576
}" viewBox="0 0 175 100"><rect y="0" x="0" width="175" height="100" fill="${c2}"/><g fill="${c1}"><path d="m0 20 35 30v50l-35-30z"/><path d="m35 0 35 30v50l-35-30z"/><path d="m70 0h23l12 10v50l-35-30z"/><path d="m70 80 23 20h-23z"/><path d="m105 60 35 30v10h-35z"/><path d="m105 0h35v40l-35-30z"/><path d="m 140,40 35,30 v 30 h -23 l -12,-10z"/><path d="M 175,0 V 20 L 152,0 Z"/></g></pattern>`,
barryBendy: (p, c1, c2, size) =>
`<pattern id="${p}" width="${size * 0.3572}" height="${
size * 0.6251
}" viewBox="0 0 100 175"><rect width="100" height="175" fill="${c2}"/><g fill="${c1}"><path d="m20 0 30 35h50l-30-35z"/><path d="m0 35 30 35h50l-30-35z"/><path d="m0 70v23l10 12h50l-30-35z"/><path d="m80 70 20 23v-23z"/><path d="m60 105 30 35h10v-35z"/><path d="m0 105v35h40l-30-35z"/><path d="m 40,140 30,35 h 30 v -23 l -10,-12 z"/><path d="m0 175h20l-20-23z"/></g></pattern>`,
pappellony: (p, c1, c2, size) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.125
}" viewBox="0 0 100 100"><rect width="100" height="100" fill="${c1}"/><circle cx="0" cy="51" r="45" stroke="${c2}" fill="${c1}" stroke-width="10"/><circle cx="100" cy="51" r="45" stroke="${c2}" fill="${c1}" stroke-width="10"/><circle cx="50" cy="1" r="45" stroke="${c2}" fill="${c1}" stroke-width="10"/></pattern>`,
pappellony2: (p, c1, c2, size) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.125
}" viewBox="0 0 100 100" stroke="#000" stroke-width="2"><rect width="100" height="100" fill="${c1}" stroke="none"/><circle cy="50" r="49" fill="${c2}"/><circle cx="100" cy="50" r="49" fill="${c2}"/><circle cx="50" cy="0" r="49" fill="${c1}"/></pattern>`,
scaly: (p, c1, c2, size) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.125
}" viewBox="0 0 100 100" stroke="#000"><rect width="100" height="100" fill="${c1}" stroke="none"/><path d="M 0,84 C -40,84 -50,49 -50,49 -50,79 -27,99 0,99 27,99 50,79 50,49 50,49 40,84 0,84 Z" fill="${c2}"/><path d="M 100,84 C 60,84 50,49 50,49 c 0,30 23,50 50,50 27,0 50,-20 50,-50 0,0 -10,35 -50,35 z" fill="${c2}"/><path d="M 50,35 C 10,35 0,0 0,0 0,30 23,50 50,50 77,50 100,30 100,0 100,0 90,35 50,35 Z" fill="${c2}"/></pattern>`,
plumetty: (p, c1, c2, size) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.25
}" viewBox="0 0 50 100" stroke-width=".8"><rect width="50" height="100" fill="${c2}" stroke="none"/><path fill="${c1}" stroke="none" d="M 25,100 C 44,88 49.5,74 50,50 33.5,40 25,25 25,4e-7 25,25 16.5,40 0,50 0.5,74 6,88 25,100 Z"/><path fill="none" stroke="${c2}" d="m17 40c5.363 2.692 10.7 2.641 16 0m-19 7c7.448 4.105 14.78 3.894 22 0m-27 7c6-2 10.75 3.003 16 3 5.412-0.0031 10-5 16-3m-35 9c4-7 12 3 19 2 7 1 15-9 19-2m-35 6c6-2 11 3 16 3s10-5 16-3m-30 7c8 0 8 3 14 3s7-3 14-3m-25 8c7.385 4.048 14.72 3.951 22 0m-19 8c5.455 2.766 10.78 2.566 16 0m-8 6v-78"/><g fill="none" stroke="${c1}"><path d="m42 90c2.678 1.344 5.337 2.004 8 2m-11 5c3.686 2.032 7.344 3.006 10.97 3m0.0261-1.2e-4v-30"/><path d="m0 92c2.689 0.0045 5.328-0.6687 8-2m-8 10c3.709-0.0033 7.348-1.031 11-3m-11 3v-30"/><path d="m0 7c5.412-0.0031 10-5 16-3m-16 11c7 1 15-9 19-2m-19 9c5 0 10-5 16-3m-16 10c6 0 7-3 14-3m-14.02 11c3.685-0.002185 7.357-1.014 11.02-3m-11 10c2.694-0.01117 5.358-0.7036 7.996-2m-8 6v-48"/><path d="m34 4c6-2 10.75 3.003 16 3m-19 6c4-7 12 3 19 2m-16 4c6-2 11 3 16 3m-14 4c8 0 8 3 14 3m-11 5c3.641 1.996 7.383 2.985 11 3m-8 5c2.762 1.401 5.303 2.154 8.002 2.112m-0.00154 3.888v-48"/></g></pattern>`,
masoned: (p, c1, c2, size) => `<pattern id="${p}" width="${size * 0.125}" height="${size * 0.125}" viewBox="0 0 100 100" fill="none"><rect width="100" height="100" fill="${c1}"/><rect width="100" height="50" stroke="${c2}" stroke-width="4"/><line x1="50" y1="50" x2="50" y2="100" stroke="${c2}" stroke-width="5"/></pattern>`,
fretty: (p, c1, c2, size) => `<pattern id="${p}" width="${size * 0.2}" height="${size * 0.2}" viewBox="0 0 140 140" stroke="#000" stroke-width="2"><rect width="140" height="140" fill="${c1}" stroke="none"/><path d="m-15 5 150 150 20-20-150-150z" fill="${c2}"/><path d="m10 150 140-140-20-20-140 140z" fill="${c2}" stroke="none"/><path d="m0 120 20 20 120-120-20-20z" fill="none"/></pattern>`,
grillage: (p, c1, c2, size) => `<pattern id="${p}" width="${size * 0.25}" height="${size * 0.25}" viewBox="0 0 200 200" stroke="#000" stroke-width="2"><rect width="200" height="200" fill="${c1}" stroke="none"/><path d="m205 65v-30h-210v30z" fill="${c2}"/><path d="m65-5h-30v210h30z" fill="${c2}"/><path d="m205 165v-30h-210v30z" fill="${c2}"/><path d="m165,65h-30v140h30z" fill="${c2}"/><path d="m 165,-5h-30v40h30z" fill="${c2}"/></pattern>`,
chainy: (p, c1, c2, size) => `<pattern id="${p}" width="${size * 0.167}" height="${size * 0.167}" viewBox="0 0 200 200" stroke="#000" stroke-width="2"><rect x="-6.691e-6" width="200" height="200" fill="${c1}" stroke="none"/><path d="m155-5-20-20-160 160 20 20z" fill="${c2}"/><path d="m45 205 160-160 20 20-160 160z" fill="${c2}"/><path d="m45-5 20-20 160 160-20 20-160-160" fill="${c2}"/><path d="m-5 45-20 20 160 160 20-20-160-160" fill="${c2}"/></pattern>`,
masoned: (p, c1, c2, size) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.125
}" viewBox="0 0 100 100" fill="none"><rect width="100" height="100" fill="${c1}"/><rect width="100" height="50" stroke="${c2}" stroke-width="4"/><line x1="50" y1="50" x2="50" y2="100" stroke="${c2}" stroke-width="5"/></pattern>`,
fretty: (p, c1, c2, size) =>
`<pattern id="${p}" width="${size * 0.2}" height="${
size * 0.2
}" viewBox="0 0 140 140" stroke="#000" stroke-width="2"><rect width="140" height="140" fill="${c1}" stroke="none"/><path d="m-15 5 150 150 20-20-150-150z" fill="${c2}"/><path d="m10 150 140-140-20-20-140 140z" fill="${c2}" stroke="none"/><path d="m0 120 20 20 120-120-20-20z" fill="none"/></pattern>`,
grillage: (p, c1, c2, size) =>
`<pattern id="${p}" width="${size * 0.25}" height="${
size * 0.25
}" viewBox="0 0 200 200" stroke="#000" stroke-width="2"><rect width="200" height="200" fill="${c1}" stroke="none"/><path d="m205 65v-30h-210v30z" fill="${c2}"/><path d="m65-5h-30v210h30z" fill="${c2}"/><path d="m205 165v-30h-210v30z" fill="${c2}"/><path d="m165,65h-30v140h30z" fill="${c2}"/><path d="m 165,-5h-30v40h30z" fill="${c2}"/></pattern>`,
chainy: (p, c1, c2, size) =>
`<pattern id="${p}" width="${size * 0.167}" height="${
size * 0.167
}" viewBox="0 0 200 200" stroke="#000" stroke-width="2"><rect x="-6.691e-6" width="200" height="200" fill="${c1}" stroke="none"/><path d="m155-5-20-20-160 160 20 20z" fill="${c2}"/><path d="m45 205 160-160 20 20-160 160z" fill="${c2}"/><path d="m45-5 20-20 160 160-20 20-160-160" fill="${c2}"/><path d="m-5 45-20 20 160 160 20-20-160-160" fill="${c2}"/></pattern>`,
maily: (p, c1, c2, size) =>
`<pattern id="${p}" width="${size * 0.167}" height="${
size * 0.167
}" viewBox="0 0 200 200" stroke="#000" stroke-width="1.2"><path fill="${c1}" stroke="none" d="M0 0h200v200H0z"/><g fill="${c2}"><path d="m80-2c-5.27e-4 2.403-0.1094 6.806-0.3262 9.199 5.014-1.109 10.1-1.768 15.19-2.059 0.09325-1.712 0.1401-5.426 0.1406-7.141z"/><path d="m100 5a95 95 0 0 0-95 95 95 95 0 0 0 95 95 95 95 0 0 0 95-95 95 95 0 0 0-95-95zm0 15a80 80 0 0 1 80 80 80 80 0 0 1-80 80 80 80 0 0 1-80-80 80 80 0 0 1 80-80z"/><path d="m92.8 20.33c-5.562 0.4859-11.04 1.603-16.34 3.217-7.793 25.31-27.61 45.12-52.91 52.91-5.321 1.638-10.8 2.716-16.34 3.217-2.394 0.2168-6.796 0.3256-9.199 0.3262v15c1.714-4.79e-4 5.429-0.04737 7.141-0.1406 5.109-0.2761 10.19-0.9646 15.19-2.059 36.24-7.937 64.54-36.24 72.47-72.47z"/><path d="m202 80c-2.403-5.31e-4 -6.806-0.1094-9.199-0.3262 1.109 5.014 1.768 10.1 2.059 15.19 1.712 0.09326 5.426 0.1401 7.141 0.1406z"/><path d="m179.7 92.8c-0.4859-5.562-1.603-11.04-3.217-16.34-25.31-7.793-45.12-27.61-52.91-52.91-1.638-5.321-2.716-10.8-3.217-16.34-0.2168-2.394-0.3256-6.796-0.3262-9.199h-15c4.8e-4 1.714 0.0474 5.429 0.1406 7.141 0.2761 5.109 0.9646 10.19 2.059 15.19 7.937 36.24 36.24 64.54 72.47 72.47z"/><path d="m120 202c5.3e-4 -2.403 0.1094-6.806 0.3262-9.199-5.014 1.109-10.1 1.768-15.19 2.059-0.0933 1.712-0.1402 5.426-0.1406 7.141z"/><path d="m107.2 179.7c5.562-0.4859 11.04-1.603 16.34-3.217 7.793-25.31 27.61-45.12 52.91-52.91 5.321-1.638 10.8-2.716 16.34-3.217 2.394-0.2168 6.796-0.3256 9.199-0.3262v-15c-1.714 4.7e-4 -5.429 0.0474-7.141 0.1406-5.109 0.2761-10.19 0.9646-15.19 2.059-36.24 7.937-64.54 36.24-72.47 72.47z"/><path d="m -2,120 c 2.403,5.4e-4 6.806,0.1094 9.199,0.3262 -1.109,-5.014 -1.768,-10.1 -2.059,-15.19 -1.712,-0.0933 -5.426,-0.1402 -7.141,-0.1406 z"/><path d="m 20.33,107.2 c 0.4859,5.562 1.603,11.04 3.217,16.34 25.31,7.793 45.12,27.61 52.91,52.91 1.638,5.321 2.716,10.8 3.217,16.34 0.2168,2.394 0.3256,6.796 0.3262,9.199 L 95,202 c -4.8e-4,-1.714 -0.0472,-5.44 -0.1404,-7.152 -0.2761,-5.109 -0.9646,-10.19 -2.059,-15.19 -7.937,-36.24 -36.24,-64.54 -72.47,-72.47 z"/></g></pattern>`,
honeycombed: (p, c1, c2, size) => `<pattern id="${p}" width="${size * 0.143}" height="${size * 0.24514}" viewBox="0 0 70 120"><rect width="70" height="120" fill="${c1}"/><path d="M 70,0 V 20 L 35,40 m 35,80 V 100 L 35,80 M 0,120 V 100 L 35,80 V 40 L 0,20 V 0" stroke="${c2}" fill="none" stroke-width="3"/></pattern>`
honeycombed: (p, c1, c2, size) =>
`<pattern id="${p}" width="${size * 0.143}" height="${
size * 0.24514
}" viewBox="0 0 70 120"><rect width="70" height="120" fill="${c1}"/><path d="M 70,0 V 20 L 35,40 m 35,80 V 100 L 35,80 M 0,120 V 100 L 35,80 V 40 L 0,20 V 0" stroke="${c2}" fill="none" stroke-width="3"/></pattern>`
};
const draw = async function (id, coa) {
@ -1749,7 +1877,8 @@ window.COArenderer = (function () {
const fill = clr(tincture);
let svg = `<g fill="${fill}" stroke="none">`;
if (ordinary.ordinary === "bordure") svg += `<path d="${shieldPath}" fill="none" stroke="${fill}" stroke-width="16.7%"/>`;
else if (ordinary.ordinary === "orle") svg += `<path d="${shieldPath}" fill="none" stroke="${fill}" stroke-width="5%" transform="scale(.85)" transform-origin="center">`;
else if (ordinary.ordinary === "orle")
svg += `<path d="${shieldPath}" fill="none" stroke="${fill}" stroke-width="5%" transform="scale(.85)" transform-origin="center">`;
else svg += getTemplate(ordinary.ordinary, ordinary.line);
return svg + `</g>`;
}
@ -1795,7 +1924,7 @@ window.COArenderer = (function () {
return fetchedCharges.join("");
}
const url = PRODUCTION ? "./charges/" : "http://armoria.herokuapp.com/charges/"; // on local machine fetch files from server
const url = location.hostname ? "./charges/" : "http://armoria.herokuapp.com/charges/"; // on local machine fetch files from server
async function fetchCharge(charge, id) {
const fetched = fetch(url + charge + ".svg")
.then(res => {

View file

@ -117,7 +117,8 @@ window.Cultures = (function () {
if (cells.h[i] > 50) return "Highland"; // no penalty for hills and moutains, high for other elevations
const f = pack.features[cells.f[cells.haven[i]]]; // opposite feature
if (f.type === "lake" && f.cells > 5) return "Lake"; // low water cross penalty and high for growth not along coastline
if ((cells.harbor[i] && f.type !== "lake" && P(0.1)) || (cells.harbor[i] === 1 && P(0.6)) || (pack.features[cells.f[i]].group === "isle" && P(0.4))) return "Naval"; // low water cross penalty and high for non-along-coastline growth
if ((cells.harbor[i] && f.type !== "lake" && P(0.1)) || (cells.harbor[i] === 1 && P(0.6)) || (pack.features[cells.f[i]].group === "isle" && P(0.4)))
return "Naval"; // low water cross penalty and high for non-along-coastline growth
if (cells.r[i] && cells.fl[i] > 100) return "River"; // no River cross penalty, penalty for non-River growth
if (cells.t[i] > 2 && [3, 7, 8, 9, 10, 12].includes(cells.biome[i])) return "Hunting"; // high penalty in non-native biomes
return "Generic";
@ -435,7 +436,7 @@ window.Cultures = (function () {
function getRiverCost(r, i, type) {
if (type === "River") return r ? 0 : 100; // penalty for river cultures
if (!r) return 0; // no penalty for others if there is no river
return Math.min(Math.max(cells.fl[i] / 10, 20), 100); // river penalty from 20 to 100 based on flux
return minmax(cells.fl[i] / 10, 20, 100); // river penalty from 20 to 100 based on flux
}
function getTypeCost(t, type) {

494
modules/export.js Normal file
View file

@ -0,0 +1,494 @@
"use strict";
// Functions to export map to image or data files
// download map as SVG
async function saveSVG() {
TIME && console.time("saveSVG");
const url = await getMapURL("svg", {fullMap: true});
const link = document.createElement("a");
link.download = getFileName() + ".svg";
link.href = url;
link.click();
tip(`${link.download} is saved. Open "Downloads" screen (crtl + J) to check. You can set image scale in options`, true, "success", 5000);
TIME && console.timeEnd("saveSVG");
}
// download map as PNG
async function savePNG() {
TIME && console.time("savePNG");
const url = await getMapURL("png");
const link = document.createElement("a");
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
canvas.width = svgWidth * pngResolutionInput.value;
canvas.height = svgHeight * pngResolutionInput.value;
const img = new Image();
img.src = url;
img.onload = function () {
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
link.download = getFileName() + ".png";
canvas.toBlob(function (blob) {
link.href = window.URL.createObjectURL(blob);
link.click();
window.setTimeout(function () {
canvas.remove();
window.URL.revokeObjectURL(link.href);
tip(`${link.download} is saved. Open "Downloads" screen (crtl + J) to check. You can set image scale in options`, true, "success", 5000);
}, 1000);
});
};
TIME && console.timeEnd("savePNG");
}
// download map as JPEG
async function saveJPEG() {
TIME && console.time("saveJPEG");
const url = await getMapURL("png");
const canvas = document.createElement("canvas");
canvas.width = svgWidth * pngResolutionInput.value;
canvas.height = svgHeight * pngResolutionInput.value;
const img = new Image();
img.src = url;
img.onload = async function () {
canvas.getContext("2d").drawImage(img, 0, 0, canvas.width, canvas.height);
const quality = Math.min(rn(1 - pngResolutionInput.value / 20, 2), 0.92);
const URL = await canvas.toDataURL("image/jpeg", quality);
const link = document.createElement("a");
link.download = getFileName() + ".jpeg";
link.href = URL;
link.click();
tip(`${link.download} is saved. Open "Downloads" screen (CTRL + J) to check`, true, "success", 7000);
window.setTimeout(() => window.URL.revokeObjectURL(URL), 5000);
};
TIME && console.timeEnd("saveJPEG");
}
// download map as png tiles
async function saveTiles() {
return new Promise(async (resolve, reject) => {
// download schema
const urlSchema = await getMapURL("tiles", {debug: true, fullMap: true});
const zip = new JSZip();
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
canvas.width = graphWidth;
canvas.height = graphHeight;
const imgSchema = new Image();
imgSchema.src = urlSchema;
imgSchema.onload = function () {
ctx.drawImage(imgSchema, 0, 0, canvas.width, canvas.height);
canvas.toBlob(blob => zip.file(`fmg_tile_schema.png`, blob));
};
// download tiles
const url = await getMapURL("tiles", {fullMap: true});
const tilesX = +document.getElementById("tileColsInput").value;
const tilesY = +document.getElementById("tileRowsInput").value;
const scale = +document.getElementById("tileScaleInput").value;
const tileW = (graphWidth / tilesX) | 0;
const tileH = (graphHeight / tilesY) | 0;
const tolesTotal = tilesX * tilesY;
const width = graphWidth * scale;
const height = width * (tileH / tileW);
canvas.width = width;
canvas.height = height;
let loaded = 0;
const img = new Image();
img.src = url;
img.onload = function () {
for (let y = 0, i = 0; y + tileH <= graphHeight; y += tileH) {
for (let x = 0; x + tileW <= graphWidth; x += tileW, i++) {
ctx.drawImage(img, x, y, tileW, tileH, 0, 0, width, height);
const name = `fmg_tile_${i}.png`;
canvas.toBlob(blob => {
zip.file(name, blob);
loaded += 1;
if (loaded === tolesTotal) return downloadZip();
});
}
}
};
function downloadZip() {
const name = `${getFileName()}.zip`;
zip.generateAsync({type: "blob"}).then(blob => {
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = name;
link.click();
link.remove();
setTimeout(() => URL.revokeObjectURL(link.href), 5000);
resolve(true);
});
}
});
}
// parse map svg to object url
async function getMapURL(type, options = {}) {
const {debug = false, globe = false, noLabels = false, noWater = false, fullMap = false} = options;
if (fullMap) drawScaleBar(1);
const cloneEl = document.getElementById("map").cloneNode(true); // clone svg
cloneEl.id = "fantasyMap";
document.body.appendChild(cloneEl);
const clone = d3.select(cloneEl);
if (!debug) clone.select("#debug")?.remove();
const cloneDefs = cloneEl.getElementsByTagName("defs")[0];
const svgDefs = document.getElementById("defElements");
const isFirefox = navigator.userAgent.toLowerCase().indexOf("firefox") > -1;
if (isFirefox && type === "mesh") clone.select("#oceanPattern")?.remove();
if (globe) clone.select("#scaleBar")?.remove();
if (noLabels) {
clone.select("#labels #states")?.remove();
clone.select("#labels #burgLabels")?.remove();
clone.select("#icons #burgIcons")?.remove();
}
if (noWater) {
clone.select("#oceanBase").attr("opacity", 0);
clone.select("#oceanPattern").attr("opacity", 0);
}
if (fullMap) {
// reset transform to show the whole map
clone.attr("width", graphWidth).attr("height", graphHeight);
clone.select("#viewbox").attr("transform", null);
drawScaleBar(scale);
}
if (type === "svg") removeUnusedElements(clone);
if (customization && type === "mesh") updateMeshCells(clone);
inlineStyle(clone);
// remove unused filters
const filters = cloneEl.querySelectorAll("filter");
for (let i = 0; i < filters.length; i++) {
const id = filters[i].id;
if (cloneEl.querySelector("[filter='url(#" + id + ")']")) continue;
if (cloneEl.getAttribute("filter") === "url(#" + id + ")") continue;
filters[i].remove();
}
// remove unused patterns
const patterns = cloneEl.querySelectorAll("pattern");
for (let i = 0; i < patterns.length; i++) {
const id = patterns[i].id;
if (cloneEl.querySelector("[fill='url(#" + id + ")']")) continue;
patterns[i].remove();
}
// remove unused symbols
const symbols = cloneEl.querySelectorAll("symbol");
for (let i = 0; i < symbols.length; i++) {
const id = symbols[i].id;
if (cloneEl.querySelector("use[*|href='#" + id + "']")) continue;
symbols[i].remove();
}
// add displayed emblems
if (layerIsOn("toggleEmblems") && emblems.selectAll("use").size()) {
cloneEl
.getElementById("emblems")
?.querySelectorAll("use")
.forEach(el => {
const href = el.getAttribute("href") || el.getAttribute("xlink:href");
if (!href) return;
const emblem = document.getElementById(href.slice(1));
if (emblem) cloneDefs.append(emblem.cloneNode(true));
});
} else {
cloneDefs.querySelector("#defs-emblems")?.remove();
}
// replace ocean pattern href to base64
if (location.hostname && cloneEl.getElementById("oceanicPattern")) {
const el = cloneEl.getElementById("oceanicPattern");
const url = el.getAttribute("href");
await new Promise(resolve => {
getBase64(url, base64 => {
el.setAttribute("href", base64);
resolve();
});
});
}
// add relief icons
if (cloneEl.getElementById("terrain")) {
const uniqueElements = new Set();
const terrainNodes = cloneEl.getElementById("terrain").childNodes;
for (let i = 0; i < terrainNodes.length; i++) {
const href = terrainNodes[i].getAttribute("href") || terrainNodes[i].getAttribute("xlink:href");
uniqueElements.add(href);
}
const defsRelief = svgDefs.getElementById("defs-relief");
for (const terrain of [...uniqueElements]) {
const element = defsRelief.querySelector(terrain);
if (element) cloneDefs.appendChild(element.cloneNode(true));
}
}
// add wind rose
if (cloneEl.getElementById("compass")) {
const rose = svgDefs.getElementById("rose");
if (rose) cloneDefs.appendChild(rose.cloneNode(true));
}
// add port icon
if (cloneEl.getElementById("anchors")) {
const anchor = svgDefs.getElementById("icon-anchor");
if (anchor) cloneDefs.appendChild(anchor.cloneNode(true));
}
// add grid pattern
if (cloneEl.getElementById("gridOverlay")?.hasChildNodes()) {
const type = cloneEl.getElementById("gridOverlay").getAttribute("type");
const pattern = svgDefs.getElementById("pattern_" + type);
if (pattern) cloneDefs.appendChild(pattern.cloneNode(true));
}
if (!cloneEl.getElementById("hatching").children.length) cloneEl.getElementById("hatching")?.remove(); // remove unused hatching group
if (!cloneEl.getElementById("fogging-cont")) cloneEl.getElementById("fog")?.remove(); // remove unused fog
if (!cloneEl.getElementById("regions")) cloneEl.getElementById("statePaths")?.remove(); // removed unused statePaths
if (!cloneEl.getElementById("labels")) cloneEl.getElementById("textPaths")?.remove(); // removed unused textPaths
// add armies style
if (cloneEl.getElementById("armies"))
cloneEl.insertAdjacentHTML(
"afterbegin",
"<style>#armies text {stroke: none; fill: #fff; text-shadow: 0 0 4px #000; dominant-baseline: central; text-anchor: middle; font-family: Helvetica; fill-opacity: 1;}#armies text.regimentIcon {font-size: .8em;}</style>"
);
// add xlink: for href to support svg1.1
if (type === "svg") {
cloneEl.querySelectorAll("[href]").forEach(el => {
const href = el.getAttribute("href");
el.removeAttribute("href");
el.setAttribute("xlink:href", href);
});
}
const usedFonts = getUsedFonts(cloneEl);
const fontsToLoad = usedFonts.filter(font => font.src);
if (fontsToLoad.length) {
const dataURLfonts = await loadFontsAsDataURI(fontsToLoad);
const fontFaces = dataURLfonts
.map(({family, src, unicodeRange = "", variant = "normal"}) => {
return `@font-face {font-family: "${family}"; src: ${src}; unicode-range: ${unicodeRange}; font-variant: ${variant};}`;
})
.join("\n");
const style = document.createElement("style");
style.setAttribute("type", "text/css");
style.innerHTML = fontFaces;
cloneEl.querySelector("defs").appendChild(style);
}
clone.remove();
const serialized = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>` + new XMLSerializer().serializeToString(cloneEl);
const blob = new Blob([serialized], {type: "image/svg+xml;charset=utf-8"});
const url = window.URL.createObjectURL(blob);
window.setTimeout(() => window.URL.revokeObjectURL(url), 5000);
return url;
}
// remove hidden g elements and g elements without children to make downloaded svg smaller in size
function removeUnusedElements(clone) {
if (!terrain.selectAll("use").size()) clone.select("#defs-relief")?.remove();
for (let empty = 1; empty; ) {
empty = 0;
clone.selectAll("g").each(function () {
if (!this.hasChildNodes() || this.style.display === "none" || this.classList.contains("hidden")) {
empty++;
this.remove();
}
if (this.hasAttribute("display") && this.style.display === "inline") this.removeAttribute("display");
});
}
}
function updateMeshCells(clone) {
const data = renderOcean.checked ? grid.cells.i : grid.cells.i.filter(i => grid.cells.h[i] >= 20);
const scheme = getColorScheme();
clone.select("#heights").attr("filter", "url(#blur1)");
clone
.select("#heights")
.selectAll("polygon")
.data(data)
.join("polygon")
.attr("points", d => getGridPolygon(d))
.attr("id", d => "cell" + d)
.attr("stroke", d => getColor(grid.cells.h[d], scheme));
}
// for each g element get inline style
function inlineStyle(clone) {
const emptyG = clone.append("g").node();
const defaultStyles = window.getComputedStyle(emptyG);
clone.selectAll("g, #ruler *, #scaleBar > text").each(function () {
const compStyle = window.getComputedStyle(this);
let style = "";
for (let i = 0; i < compStyle.length; i++) {
const key = compStyle[i];
const value = compStyle.getPropertyValue(key);
// Firefox mask hack
if (key === "mask-image" && value !== defaultStyles.getPropertyValue(key)) {
style += "mask-image: url('#land');";
continue;
}
if (key === "cursor") continue; // cursor should be default
if (this.hasAttribute(key)) continue; // don't add style if there is the same attribute
if (value === defaultStyles.getPropertyValue(key)) continue;
style += key + ":" + value + ";";
}
for (const key in compStyle) {
const value = compStyle.getPropertyValue(key);
if (key === "cursor") continue; // cursor should be default
if (this.hasAttribute(key)) continue; // don't add style if there is the same attribute
if (value === defaultStyles.getPropertyValue(key)) continue;
style += key + ":" + value + ";";
}
if (style != "") this.setAttribute("style", style);
});
emptyG.remove();
}
function saveGeoJSON_Cells() {
const json = {type: "FeatureCollection", features: []};
const cells = pack.cells;
const getPopulation = i => {
const [r, u] = getCellPopulation(i);
return rn(r + u);
};
const getHeight = i => parseInt(getFriendlyHeight([cells.p[i][0], cells.p[i][1]]));
cells.i.forEach(i => {
const coordinates = getCellCoordinates(cells.v[i]);
const height = getHeight(i);
const biome = cells.biome[i];
const type = pack.features[cells.f[i]].type;
const population = getPopulation(i);
const state = cells.state[i];
const province = cells.province[i];
const culture = cells.culture[i];
const religion = cells.religion[i];
const neighbors = cells.c[i];
const properties = {id: i, height, biome, type, population, state, province, culture, religion, neighbors};
const feature = {type: "Feature", geometry: {type: "Polygon", coordinates}, properties};
json.features.push(feature);
});
const name = getFileName("Cells") + ".geojson";
downloadFile(JSON.stringify(json), name, "application/json");
}
function saveGeoJSON_Routes() {
const json = {type: "FeatureCollection", features: []};
routes.selectAll("g > path").each(function () {
const coordinates = getRoutePoints(this);
const id = this.id;
const type = this.parentElement.id;
const feature = {type: "Feature", geometry: {type: "LineString", coordinates}, properties: {id, type}};
json.features.push(feature);
});
const name = getFileName("Routes") + ".geojson";
downloadFile(JSON.stringify(json), name, "application/json");
}
function saveGeoJSON_Rivers() {
const json = {type: "FeatureCollection", features: []};
rivers.selectAll("path").each(function () {
const coordinates = getRiverPoints(this);
const id = this.id;
const width = +this.dataset.increment;
const increment = +this.dataset.increment;
const river = pack.rivers.find(r => r.i === +id.slice(5));
const name = river ? river.name : "";
const type = river ? river.type : "";
const i = river ? river.i : "";
const basin = river ? river.basin : "";
const feature = {type: "Feature", geometry: {type: "LineString", coordinates}, properties: {id, i, basin, name, type, width, increment}};
json.features.push(feature);
});
const name = getFileName("Rivers") + ".geojson";
downloadFile(JSON.stringify(json), name, "application/json");
}
function saveGeoJSON_Markers() {
const features = pack.markers.map(marker => {
const {i, type, icon, x, y, size, fill, stroke} = marker;
const coordinates = getCoordinates(x, y, 4);
const id = `marker${i}`;
const note = notes.find(note => note.id === id);
const properties = {id, type, icon, ...note, size, fill, stroke};
return {type: "Feature", geometry: {type: "Point", coordinates}, properties};
});
const json = {type: "FeatureCollection", features};
const fileName = getFileName("Markers") + ".geojson";
downloadFile(JSON.stringify(json), fileName, "application/json");
}
function getCellCoordinates(vertices) {
const p = pack.vertices.p;
const coordinates = vertices.map(n => getCoordinates(p[n][0], p[n][1], 2));
return [coordinates.concat([coordinates[0]])];
}
function getRoutePoints(node) {
let points = [];
const l = node.getTotalLength();
const increment = l / Math.ceil(l / 2);
for (let i = 0; i <= l; i += increment) {
const p = node.getPointAtLength(i);
points.push(getCoordinates(p.x, p.y, 4));
}
return points;
}
function getRiverPoints(node) {
let points = [];
const l = node.getTotalLength() / 2; // half-length
const increment = 0.25; // defines density of points
for (let i = l, c = i; i >= 0; i -= increment, c += increment) {
const p1 = node.getPointAtLength(i);
const p2 = node.getPointAtLength(c);
const [x, y] = getCoordinates((p1.x + p2.x) / 2, (p1.y + p2.y) / 2, 4);
points.push([x, y]);
}
return points;
}

View file

@ -1,5 +1,5 @@
// Functions to save and load the map
"use strict";
// Functions to load and parse .map files
function quickLoad() {
ldb.get("lastMap", blob => {
@ -221,8 +221,8 @@ function parseLoadedData(data) {
if (settings[11]) barPosY.value = settings[11];
if (settings[12]) populationRate = populationRateInput.value = populationRateOutput.value = settings[12];
if (settings[13]) urbanization = urbanizationInput.value = urbanizationOutput.value = settings[13];
if (settings[14]) mapSizeInput.value = mapSizeOutput.value = Math.max(Math.min(settings[14], 100), 1);
if (settings[15]) latitudeInput.value = latitudeOutput.value = Math.max(Math.min(settings[15], 100), 0);
if (settings[14]) mapSizeInput.value = mapSizeOutput.value = minmax(settings[14], 1, 100);
if (settings[15]) latitudeInput.value = latitudeOutput.value = minmax(settings[15], 0, 100);
if (settings[16]) temperatureEquatorInput.value = temperatureEquatorOutput.value = settings[16];
if (settings[17]) temperaturePoleInput.value = temperaturePoleOutput.value = settings[17];
if (settings[18]) precInput.value = precOutput.value = settings[18];
@ -230,7 +230,12 @@ function parseLoadedData(data) {
if (settings[20]) mapName.value = settings[20];
if (settings[21]) hideLabels.checked = +settings[21];
if (settings[22]) stylePreset.value = settings[22];
if (settings[23]) rescaleLabels.checked = settings[23];
if (settings[23]) rescaleLabels.checked = +settings[23];
if (settings[24]) urbanDensity = urbanDensityInput.value = urbanDensityOutput.value = +settings[24];
})();
void (function applyOptionsToUI() {
stateLabelsModeInput.value = options.stateLabelsMode;
})();
void (function parseConfiguration() {
@ -340,6 +345,7 @@ function parseLoadedData(data) {
pack.religions = data[29] ? JSON.parse(data[29]) : [{i: 0, name: "No religion"}];
pack.provinces = data[30] ? JSON.parse(data[30]) : [0];
pack.rivers = data[32] ? JSON.parse(data[32]) : [];
pack.markers = data[35] ? JSON.parse(data[35]) : [];
const cells = pack.cells;
cells.biome = Uint8Array.from(data[16].split(","));
@ -405,7 +411,7 @@ function parseLoadedData(data) {
if (notHidden(labels)) turnOn("toggleLabels");
if (notHidden(icons)) turnOn("toggleIcons");
if (hasChildren(armies) && notHidden(armies)) turnOn("toggleMilitary");
if (hasChildren(markers) && notHidden(markers)) turnOn("toggleMarkers");
if (hasChildren(markers)) turnOn("toggleMarkers");
if (notHidden(ruler)) turnOn("toggleRulers");
if (notHidden(scaleBar)) turnOn("toggleScaleBar");
@ -431,12 +437,27 @@ function parseLoadedData(data) {
// 1.0 adds a legend box
legend = svg.append("g").attr("id", "legend");
legend.attr("font-family", "Almendra SC").attr("font-size", 13).attr("data-size", 13).attr("data-x", 99).attr("data-y", 93).attr("stroke-width", 2.5).attr("stroke", "#812929").attr("stroke-dasharray", "0 4 10 4").attr("stroke-linecap", "round");
legend
.attr("font-family", "Almendra SC")
.attr("font-size", 13)
.attr("data-size", 13)
.attr("data-x", 99)
.attr("data-y", 93)
.attr("stroke-width", 2.5)
.attr("stroke", "#812929")
.attr("stroke-dasharray", "0 4 10 4")
.attr("stroke-linecap", "round");
// 1.0 separated drawBorders fron drawStates()
stateBorders = borders.append("g").attr("id", "stateBorders");
provinceBorders = borders.append("g").attr("id", "provinceBorders");
borders.attr("opacity", null).attr("stroke", null).attr("stroke-width", null).attr("stroke-dasharray", null).attr("stroke-linecap", null).attr("filter", null);
borders
.attr("opacity", null)
.attr("stroke", null)
.attr("stroke-width", null)
.attr("stroke-dasharray", null)
.attr("stroke-linecap", null)
.attr("filter", null);
stateBorders.attr("opacity", 0.8).attr("stroke", "#56566d").attr("stroke-width", 1).attr("stroke-dasharray", "2").attr("stroke-linecap", "butt");
provinceBorders.attr("opacity", 0.8).attr("stroke", "#56566d").attr("stroke-width", 0.5).attr("stroke-dasharray", "1").attr("stroke-linecap", "butt");
@ -460,7 +481,7 @@ function parseLoadedData(data) {
zones.attr("opacity", 0.6).attr("stroke", null).attr("stroke-width", 0).attr("stroke-dasharray", null).attr("stroke-linecap", "butt");
addZones();
if (!markers.selectAll("*").size()) {
addMarkers();
Markers.generate();
turnButtonOn("toggleMarkers");
}
@ -815,6 +836,7 @@ function parseLoadedData(data) {
const riverPoints = [];
const length = node.getTotalLength() / 2;
if (!length) continue;
const segments = Math.ceil(length / 6);
const increment = length / segments;
@ -848,6 +870,64 @@ function parseLoadedData(data) {
rivers.attr("style", null);
borders.attr("style", null);
}
if (version < 1.7) {
// v 1.7 changed markers data
const defs = document.getElementById("defs-markers");
const markersGroup = document.getElementById("markers");
if (defs && markersGroup) {
const markerElements = markersGroup.querySelectorAll("use");
const rescale = +markersGroup.getAttribute("rescale");
pack.markers = Array.from(markerElements).map((el, i) => {
const id = el.getAttribute("id");
const note = notes.find(note => note.id === id);
if (note) note.id = `marker${i}`;
let x = +el.dataset.x;
let y = +el.dataset.y;
const transform = el.getAttribute("transform");
if (transform) {
const [dx, dy] = parseTransform(transform);
if (dx) x += +dx;
if (dy) y += +dy;
}
const cell = findCell(x, y);
const size = rn(rescale ? el.dataset.size * 30 : el.getAttribute("width"), 1);
const href = el.href.baseVal;
const type = href.replace("#marker_", "");
const symbol = defs?.querySelector(`symbol${href}`);
const text = symbol?.querySelector("text");
const circle = symbol?.querySelector("circle");
const icon = text?.innerHTML;
const px = text && Number(text.getAttribute("font-size")?.replace("px", ""));
const dx = text && Number(text.getAttribute("x")?.replace("%", ""));
const dy = text && Number(text.getAttribute("y")?.replace("%", ""));
const fill = circle && circle.getAttribute("fill");
const stroke = circle && circle.getAttribute("stroke");
const marker = {i, icon, type, x, y, size, cell};
if (size && size !== 30) marker.size = size;
if (!isNaN(px) && px !== 12) marker.px = px;
if (!isNaN(dx) && dx !== 50) marker.dx = dx;
if (!isNaN(dy) && dy !== 50) marker.dy = dy;
if (fill && fill !== "#ffffff") marker.fill = fill;
if (stroke && stroke !== "#000000") marker.stroke = stroke;
if (circle?.getAttribute("opacity") === "0") marker.pin = "no";
return marker;
});
markersGroup.style.display = null;
defs?.remove();
markerElements.forEach(el => el.remove());
if (layerIsOn("markers")) drawMarkers();
}
}
})();
void (function checkDataIntegrity() {
@ -975,7 +1055,7 @@ function parseLoadedData(data) {
},
"New map": function () {
$(this).dialog("close");
regenerateMap();
regenerateMap("loading error");
},
Cancel: function () {
$(this).dialog("close");

View file

@ -0,0 +1,881 @@
"use strict";
window.Markers = (function () {
let config = [];
let occupied = [];
function getDefaultConfig() {
const culturesSet = document.getElementById("culturesSet").value;
const isFantasy = culturesSet.includes("Fantasy");
return [
{type: "volcanoes", icon: "🌋", multiplier: 1, fn: addVolcanoes},
{type: "hot-springs", icon: "♨️", multiplier: 1, fn: addHotSprings},
{type: "mines", icon: "⛏️", multiplier: 1, fn: addMines},
{type: "bridges", icon: "🌉", multiplier: 1, fn: addBridges},
{type: "inns", icon: "🍻", multiplier: 1, fn: addInns},
{type: "lighthouses", icon: "🚨", multiplier: 1, fn: addLighthouses},
{type: "waterfalls", icon: "⟱", multiplier: 1, fn: addWaterfalls},
{type: "battlefields", icon: "⚔️", multiplier: 1, fn: addBattlefields},
{type: "dungeons", icon: "🗝️", multiplier: 1, fn: addDungeons},
{type: "lake-monsters", icon: "🐉", multiplier: 1, fn: addLakeMonsters},
{type: "sea-monsters", icon: "🦑", multiplier: 1, fn: addSeaMonsters},
{type: "hill-monsters", icon: "👹", multiplier: 1, fn: addHillMonsters},
{type: "sacred-mountains", icon: "🗻", multiplier: 1, fn: addSacredMountains},
{type: "sacred-forests", icon: "🌳", multiplier: 1, fn: addSacredForests},
{type: "sacred-pineries", icon: "🌲", multiplier: 1, fn: addSacredPineries},
{type: "sacred-palm-groves", icon: "🌴", multiplier: 1, fn: addSacredPalmGroves},
{type: "brigands", icon: "💰", multiplier: 1, fn: addBrigands},
{type: "pirates", icon: "🏴‍☠️", multiplier: 1, fn: addPirates},
{type: "statues", icon: "🗿", multiplier: 1, fn: addStatues},
{type: "ruines", icon: "🏺", multiplier: 1, fn: addRuines},
{type: "portals", icon: "🌀", multiplier: +isFantasy, fn: addPortals}
];
}
const getConfig = () => config;
const setConfig = newConfig => {
config = newConfig;
};
const generate = function () {
setConfig(getDefaultConfig());
pack.markers = [];
generateTypes();
};
const regenerate = () => {
pack.markers = pack.markers.filter(({i, lock, cell}) => {
if (lock) {
occupied[cell] = true;
return true;
}
const id = `marker${i}`;
document.getElementById(id)?.remove();
const index = notes.findIndex(note => note.id === id);
if (index != -1) notes.splice(index, 1);
return false;
});
generateTypes();
};
function generateTypes() {
TIME && console.time("addMarkers");
config.forEach(({type, icon, multiplier, fn}) => {
if (multiplier === 0) return;
fn(type, icon, multiplier);
});
occupied = [];
TIME && console.timeEnd("addMarkers");
}
function getQuantity(array, min, each, multiplier) {
if (!array.length || array.length < min / multiplier) return 0;
const requestQty = Math.ceil((array.length / each) * multiplier);
return array.length < requestQty ? array.length : requestQty;
}
function extractAnyElement(array) {
const index = Math.floor(Math.random() * array.length);
return array.splice(index, 1);
}
function getMarkerCoordinates(cell) {
const {cells, burgs} = pack;
const burgId = cells.burg[cell];
if (burgId) {
const {x, y} = burgs[burgId];
return [x, y];
}
return cells.p[cell];
}
function addMarker({cell, type, icon, dx, dy, px}) {
const i = pack.markers.length;
const [x, y] = getMarkerCoordinates(cell);
const marker = {i, icon, type, x, y, cell};
if (dx) marker.dx = dx;
if (dy) marker.dy = dy;
if (px) marker.px = px;
pack.markers.push(marker);
occupied[cell] = true;
return "marker" + i;
}
function addVolcanoes(type, icon, multiplier) {
const {cells} = pack;
let mountains = Array.from(cells.i.filter(i => !occupied[i] && cells.h[i] >= 70).sort((a, b) => cells.h[b] - cells.h[a]));
let quantity = getQuantity(mountains, 10, 500, multiplier);
if (!quantity) return;
while (quantity) {
const [cell] = extractAnyElement(mountains);
const id = addMarker({cell, icon, type, dx: 52, px: 13});
const proper = Names.getCulture(cells.culture[cell]);
const name = P(0.3) ? "Mount " + proper : Math.random() > 0.3 ? proper + " Volcano" : proper;
notes.push({id, name, legend: `Active volcano. Height: ${getFriendlyHeight(cells.p[cell])}`});
quantity--;
}
}
function addHotSprings(type, icon, multiplier) {
const {cells} = pack;
let springs = Array.from(cells.i.filter(i => !occupied[i] && cells.h[i] > 50).sort((a, b) => cells.h[b] - cells.h[a]));
let quantity = getQuantity(springs, 30, 1200, multiplier);
if (!quantity) return;
while (quantity) {
const [cell] = extractAnyElement(springs);
const id = addMarker({cell, icon, type, dy: 52});
const proper = Names.getCulture(cells.culture[cell]);
const temp = convertTemperature(gauss(35, 15, 20, 100));
notes.push({id, name: proper + " Hot Springs", legend: `A hot springs area. Average temperature: ${temp}`});
quantity--;
}
}
function addMines(type, icon, multiplier) {
const {cells} = pack;
let hillyBurgs = Array.from(cells.i.filter(i => !occupied[i] && cells.h[i] > 47 && cells.burg[i]));
let quantity = getQuantity(hillyBurgs, 1, 15, multiplier);
if (!quantity) return;
const resources = {salt: 5, gold: 2, silver: 4, copper: 2, iron: 3, lead: 1, tin: 1};
while (quantity && hillyBurgs.length) {
const [cell] = extractAnyElement(hillyBurgs);
const id = addMarker({cell, icon, type, dx: 48, px: 13});
const resource = rw(resources);
const burg = pack.burgs[cells.burg[cell]];
const name = `${burg.name}${resource} mining town`;
const population = rn(burg.population * populationRate * urbanization);
const legend = `${burg.name} is a mining town of ${population} people just nearby the ${resource} mine`;
notes.push({id, name, legend});
quantity--;
}
}
function addBridges(type, icon, multiplier) {
const {cells, burgs} = pack;
const meanFlux = d3.mean(cells.fl.filter(fl => fl));
let bridges = Array.from(
cells.i.filter(i => !occupied[i] && cells.burg[i] && cells.t[i] !== 1 && burgs[cells.burg[i]].population > 20 && cells.r[i] && cells.fl[i] > meanFlux)
);
let quantity = getQuantity(bridges, 1, 5, multiplier);
if (!quantity) return;
while (quantity) {
const [cell] = extractAnyElement(bridges);
const id = addMarker({cell, icon, type, px: 14});
const burg = pack.burgs[cells.burg[cell]];
const river = pack.rivers.find(r => r.i === pack.cells.r[cell]);
const riverName = river ? `${river.name} ${river.type}` : "river";
const name = river && P(0.2) ? river.name : burg.name;
const weightedAdjectives = {
stone: 10,
wooden: 1,
lengthy: 2,
formidable: 2,
rickety: 1,
beaten: 1,
weathered: 1
};
notes.push({id, name: `${name} Bridge`, legend: `A ${rw(weightedAdjectives)} bridge spans over the ${riverName} near ${burg.name}`});
quantity--;
}
}
function addInns(type, icon, multiplier) {
const {cells} = pack;
let taverns = Array.from(cells.i.filter(i => !occupied[i] && cells.h[i] >= 20 && cells.road[i] > 4 && cells.pop[i] > 10));
let quantity = getQuantity(taverns, 1, 100, multiplier);
if (!quantity) return;
const colors = [
"Dark",
"Light",
"Bright",
"Golden",
"White",
"Black",
"Red",
"Pink",
"Purple",
"Blue",
"Green",
"Yellow",
"Amber",
"Orange",
"Brown",
"Grey"
];
const animals = [
"Antelope",
"Ape",
"Badger",
"Bear",
"Beaver",
"Bison",
"Boar",
"Buffalo",
"Cat",
"Crane",
"Crocodile",
"Crow",
"Deer",
"Dog",
"Eagle",
"Elk",
"Fox",
"Goat",
"Goose",
"Hare",
"Hawk",
"Heron",
"Horse",
"Hyena",
"Ibis",
"Jackal",
"Jaguar",
"Lark",
"Leopard",
"Lion",
"Mantis",
"Marten",
"Moose",
"Mule",
"Narwhal",
"Owl",
"Panther",
"Rat",
"Raven",
"Rook",
"Scorpion",
"Shark",
"Sheep",
"Snake",
"Spider",
"Swan",
"Tiger",
"Turtle",
"Wolf",
"Wolverine",
"Camel",
"Falcon",
"Hound",
"Ox"
];
const adjectives = [
"New",
"Good",
"High",
"Old",
"Great",
"Big",
"Major",
"Happy",
"Main",
"Huge",
"Far",
"Beautiful",
"Fair",
"Prime",
"Ancient",
"Golden",
"Proud",
"Lucky",
"Fat",
"Honest",
"Giant",
"Distant",
"Friendly",
"Loud",
"Hungry",
"Magical",
"Superior",
"Peaceful",
"Frozen",
"Divine",
"Favorable",
"Brave",
"Sunny",
"Flying"
];
const methods = [
"Boiled",
"Grilled",
"Roasted",
"Spit-roasted",
"Stewed",
"Stuffed",
"Jugged",
"Mashed",
"Baked",
"Braised",
"Poached",
"Marinated",
"Pickled",
"Smoked",
"Dried",
"Dry-aged",
"Corned",
"Fried",
"Pan-fried",
"Deep-fried",
"Dressed",
"Steamed",
"Cured",
"Syrupped",
"Flame-Broiled"
];
const courses = [
"beef",
"pork",
"bacon",
"chicken",
"lamb",
"chevon",
"hare",
"rabbit",
"hart",
"deer",
"antlers",
"bear",
"buffalo",
"badger",
"beaver",
"turkey",
"pheasant",
"duck",
"goose",
"teal",
"quail",
"pigeon",
"seal",
"carp",
"bass",
"pike",
"catfish",
"sturgeon",
"escallop",
"pie",
"cake",
"pottage",
"pudding",
"onions",
"carrot",
"potato",
"beet",
"garlic",
"cabbage",
"eggplant",
"eggs",
"broccoli",
"zucchini",
"pepper",
"olives",
"pumpkin",
"spinach",
"peas",
"chickpea",
"beans",
"rice",
"pasta",
"bread",
"apples",
"peaches",
"pears",
"melon",
"oranges",
"mango",
"tomatoes",
"cheese",
"corn",
"rat tails",
"pig ears"
];
const types = ["hot", "cold", "fire", "ice", "smoky", "misty", "shiny", "sweet", "bitter", "salty", "sour", "sparkling", "smelly"];
const drinks = [
"wine",
"brandy",
"jinn",
"whisky",
"rom",
"beer",
"cider",
"mead",
"liquor",
"spirit",
"vodka",
"tequila",
"absinthe",
"nectar",
"milk",
"kvass",
"kumis",
"tea",
"water",
"juice",
"sap"
];
while (quantity) {
const [cell] = extractAnyElement(taverns);
const id = addMarker({cell, icon, type, px: 14});
const typeName = P(0.3) ? "inn" : "tavern";
const isAnimalThemed = P(0.7);
const animal = ra(animals);
const name = isAnimalThemed ? (P(0.6) ? ra(colors) + " " + animal : ra(adjectives) + " " + animal) : ra(adjectives) + " " + capitalize(type);
const meal = isAnimalThemed && P(0.3) ? animal : ra(courses);
const course = `${ra(methods)} ${meal}`.toLowerCase();
const drink = `${P(0.5) ? ra(types) : ra(colors)} ${ra(drinks)}`.toLowerCase();
const legend = `A big and famous roadside ${typeName}. Delicious ${course} with ${drink} is served here`;
notes.push({id, name: "The " + name, legend});
quantity--;
}
}
function addLighthouses(type, icon, multiplier) {
const {cells} = pack;
const lighthouses = Array.from(cells.i.filter(i => !occupied[i] && cells.harbor[i] > 6 && cells.c[i].some(c => cells.h[c] < 20 && cells.road[c])));
let quantity = getQuantity(lighthouses, 1, 2, multiplier);
if (!quantity) return;
while (quantity) {
const [cell] = extractAnyElement(lighthouses);
const id = addMarker({cell, icon, type, px: 14});
const proper = cells.burg[cell] ? pack.burgs[cells.burg[cell]].name : Names.getCulture(cells.culture[cell]);
notes.push({id, name: getAdjective(proper) + " Lighthouse" + name, legend: `A lighthouse to serve as a beacon for ships in the open sea`});
quantity--;
}
}
function addWaterfalls(type, icon, multiplier) {
const {cells} = pack;
const waterfalls = Array.from(cells.i.filter(i => cells.r[i] && !occupied[i] && cells.h[i] >= 50 && cells.c[i].some(c => cells.h[c] < 40 && cells.r[c])));
const quantity = getQuantity(waterfalls, 1, 5, multiplier);
if (!quantity) return;
const descriptions = [
"A gorgeous waterfall flows here",
"The rapids of an exceptionally beautiful waterfall",
"An impressive waterfall has cut through the land",
"The cascades of a stunning waterfall",
"A river drops down from a great height forming a wonderous waterfall",
"A breathtaking waterfall cuts through the landscape"
];
for (let i = 0; i < waterfalls.length && i < quantity; i++) {
const cell = waterfalls[i];
const id = addMarker({cell, icon, type, dy: 54, px: 16});
const proper = cells.burg[cell] ? pack.burgs[cells.burg[cell]].name : Names.getCulture(cells.culture[cell]);
notes.push({id, name: getAdjective(proper) + " Waterfall" + name, legend: `${ra(descriptions)}`});
}
}
function addBattlefields(type, icon, multiplier) {
const {cells, states} = pack;
let battlefields = Array.from(cells.i.filter(i => !occupied[i] && cells.state[i] && cells.pop[i] > 2 && cells.h[i] < 50 && cells.h[i] > 25));
let quantity = getQuantity(battlefields, 50, 700, multiplier);
if (!quantity) return;
while (quantity && battlefields.length) {
const [cell] = extractAnyElement(battlefields);
const id = addMarker({cell, icon, type, dy: 52});
const state = states[cells.state[cell]];
if (!state.campaigns) state.campaigns = BurgsAndStates.generateCampaign(state);
const campaign = ra(state.campaigns);
const date = generateDate(campaign.start, campaign.end);
const name = Names.getCulture(cells.culture[cell]) + " Battlefield";
const legend = `A historical battle of the ${campaign.name}. \r\nDate: ${date} ${options.era}`;
notes.push({id, name, legend});
quantity--;
}
}
function addDungeons(type, icon, multiplier) {
const {cells} = pack;
let dungeons = Array.from(cells.i.filter(i => !occupied[i] && cells.pop[i] && cells.pop[i] < 3));
let quantity = getQuantity(dungeons, 30, 200, multiplier);
if (!quantity) return;
while (quantity) {
const [cell] = extractAnyElement(dungeons);
const id = addMarker({cell, icon, type, dy: 51, px: 13});
const dungeonSeed = `${seed}${cell}`;
const name = "Dungeon";
const legend = `<div>Undiscovered dungeon. See <a href="https://watabou.github.io/one-page-dungeon/?seed=${dungeonSeed}" target="_blank">One page dungeon</a></div><iframe style="height: 33vh" src="https://watabou.github.io/one-page-dungeon/?seed=${dungeonSeed}" sandbox="allow-scripts allow-same-origin"></iframe>`;
notes.push({id, name, legend});
quantity--;
}
}
function addLakeMonsters(type, icon, multiplier) {
const {features} = pack;
const lakes = features.filter(feature => feature.type === "lake" && feature.group === "freshwater" && !occupied[feature.firstCell]);
let quantity = getQuantity(lakes, 2, 10, multiplier);
if (!quantity) return;
while (quantity) {
const [lake] = extractAnyElement(lakes);
const cell = lake.firstCell;
const id = addMarker({cell, icon, type, dy: 48});
const name = `${lake.name} Monster`;
const length = gauss(10, 5, 5, 100);
const legend = `Rumors say a relic monster of ${length} ${heightUnit.value} long inhabits ${lake.name} Lake. Truth or lie, folks are afraid to fish in the lake`;
notes.push({id, name, legend});
quantity--;
}
}
function addSeaMonsters(type, icon, multiplier) {
const {cells, features} = pack;
const sea = Array.from(cells.i.filter(i => !occupied[i] && cells.h[i] < 20 && cells.road[i] && features[cells.f[i]].type === "ocean"));
let quantity = getQuantity(sea, 50, 700, multiplier);
if (!quantity) return;
while (quantity) {
const [cell] = extractAnyElement(sea);
const id = addMarker({cell, icon, type});
const name = `${Names.getCultureShort(0)} Monster`;
const length = gauss(25, 10, 10, 100);
const legend = `Old sailors tell stories of a gigantic sea monster inhabiting these dangerous waters. Rumors say it can be ${length} ${heightUnit.value} long`;
notes.push({id, name, legend});
quantity--;
}
}
function addHillMonsters(type, icon, multiplier) {
const {cells} = pack;
const hills = Array.from(cells.i.filter(i => !occupied[i] && cells.h[i] >= 50 && cells.pop[i]));
let quantity = getQuantity(hills, 30, 600, multiplier);
if (!quantity) return;
const adjectives = [
"great",
"big",
"huge",
"prime",
"golden",
"proud",
"lucky",
"fat",
"giant",
"hungry",
"magical",
"superior",
"terrifying",
"horrifying",
"feared"
];
const subjects = ["Locals", "Elders", "Inscriptions", "Tipplers", "Legends", "Whispers", "Rumors", "Journeying folk", "Tales"];
const species = [
"Ogre",
"Troll",
"Cyclops",
"Giant",
"Monster",
"Beast",
"Dragon",
"Undead",
"Ghoul",
"Vampire",
"Hag",
"Banshee",
"Bearded Devil",
"Roc",
"Hydra",
"Warg"
];
const modusOperandi = [
"steals cattle at night",
"prefers eating children",
"doesn't mind of human flesh",
"keeps the region at bay",
"eats kids whole",
"abducts young women",
"terrorizes the region",
"harasses travelers in the area",
"snatches people from homes",
"attacks anyone who dares to approach its lair",
"attacks unsuspecting victims"
];
while (quantity) {
const [cell] = extractAnyElement(hills);
const id = addMarker({cell, icon, type, dy: 54, px: 13});
const monster = ra(species);
const toponym = Names.getCulture(cells.culture[cell]);
const name = `${toponym} ${monster}`;
const legend = `${ra(subjects)} speak of a ${ra(adjectives)} ${monster} who inhabits ${toponym} hills and ${ra(modusOperandi)}`;
notes.push({id, name, legend});
quantity--;
}
}
function addSacredMountains(type, icon, multiplier) {
const {cells, cultures} = pack;
let lonelyMountains = Array.from(
cells.i.filter(i => !occupied[i] && cells.h[i] >= 70 && cells.c[i].some(c => cells.culture[c]) && cells.c[i].every(c => cells.h[c] < 60))
);
let quantity = getQuantity(lonelyMountains, 1, 5, multiplier);
if (!quantity) return;
while (quantity) {
const [cell] = extractAnyElement(lonelyMountains);
const id = addMarker({cell, icon, type, dy: 48});
const culture = cells.c[cell].map(c => cells.culture[c]).find(c => c);
const name = `${Names.getCulture(culture)} Mountain`;
const height = getFriendlyHeight(cells.p[cell]);
const legend = `A sacred mountain of ${cultures[culture].name} culture. Height: ${height}`;
notes.push({id, name, legend});
quantity--;
}
}
function addSacredForests(type, icon, multiplier) {
const {cells, cultures} = pack;
let temperateForests = Array.from(cells.i.filter(i => !occupied[i] && cells.culture[i] && [6, 8].includes(cells.biome[i])));
let quantity = getQuantity(temperateForests, 30, 1000, multiplier);
if (!quantity) return;
while (quantity) {
const [cell] = extractAnyElement(temperateForests);
const id = addMarker({cell, icon, type});
const culture = cells.culture[cell];
const name = `${Names.getCulture(culture)} Forest`;
const legend = `A sacred forest of ${cultures[culture].name} culture`;
notes.push({id, name, legend});
quantity--;
}
}
function addSacredPineries(type, icon, multiplier) {
const {cells, cultures} = pack;
let borealForests = Array.from(cells.i.filter(i => !occupied[i] && cells.culture[i] && cells.biome[i] === 9));
let quantity = getQuantity(borealForests, 30, 800, multiplier);
if (!quantity) return;
while (quantity) {
const [cell] = extractAnyElement(borealForests);
const id = addMarker({cell, icon, type, px: 13});
const culture = cells.culture[cell];
const name = `${Names.getCulture(culture)} Pinery`;
const legend = `A sacred pinery of ${cultures[culture].name} culture`;
notes.push({id, name, legend});
quantity--;
}
}
function addSacredPalmGroves(type, icon, multiplier) {
const {cells, cultures} = pack;
let oasises = Array.from(cells.i.filter(i => !occupied[i] && cells.culture[i] && cells.biome[i] === 1 && cells.pop[i] > 1 && cells.road[i]));
let quantity = getQuantity(oasises, 1, 100, multiplier);
if (!quantity) return;
while (quantity) {
const [cell] = extractAnyElement(oasises);
const id = addMarker({cell, icon, type, px: 13});
const culture = cells.culture[cell];
const name = `${Names.getCulture(culture)} Palm Grove`;
const legend = `A sacred palm grove of ${cultures[culture].name} culture`;
notes.push({id, name, legend});
quantity--;
}
}
function addBrigands(type, icon, multiplier) {
const {cells} = pack;
let roads = Array.from(cells.i.filter(i => !occupied[i] && cells.culture[i] && cells.road[i] > 4));
let quantity = getQuantity(roads, 50, 100, multiplier);
if (!quantity) return;
const animals = [
"Apes",
"Badgers",
"Bears",
"Beavers",
"Bisons",
"Boars",
"Cats",
"Crows",
"Dogs",
"Foxes",
"Hares",
"Hawks",
"Hyenas",
"Jackals",
"Jaguars",
"Leopards",
"Lions",
"Owls",
"Panthers",
"Rats",
"Ravens",
"Rooks",
"Scorpions",
"Sharks",
"Snakes",
"Spiders",
"Tigers",
"Wolfs",
"Wolverines",
"Falcons"
];
const types = {brigands: 4, bandits: 3, robbers: 1, highwaymen: 1};
while (quantity) {
const [cell] = extractAnyElement(roads);
const id = addMarker({cell, icon, type, px: 13});
const culture = cells.culture[cell];
const biome = cells.biome[cell];
const height = cells.p[cell];
const locality =
height >= 70
? "highlander"
: [1, 2].includes(biome)
? "desert"
: [3, 4].includes(biome)
? "mounted"
: [5, 6, 7, 8, 9].includes(biome)
? "forest"
: biome === 12
? "swamp"
: "angry";
const name = `${Names.getCulture(culture)} ${ra(animals)}`;
const legend = `A gang of ${locality} ${rw(types)}`;
notes.push({id, name, legend});
quantity--;
}
}
function addPirates(type, icon, multiplier) {
const {cells} = pack;
let searoutes = Array.from(cells.i.filter(i => !occupied[i] && cells.h[i] < 20 && cells.road[i]));
let quantity = getQuantity(searoutes, 40, 300, multiplier);
if (!quantity) return;
while (quantity) {
const [cell] = extractAnyElement(searoutes);
const id = addMarker({cell, icon, type, dx: 51});
const name = `Pirates`;
const legend = `Pirate ships have been spotted in these waters`;
notes.push({id, name, legend});
quantity--;
}
}
function addStatues(type, icon, multiplier) {
const {cells} = pack;
let statues = Array.from(cells.i.filter(i => !occupied[i] && cells.h[i] >= 20 && cells.h[i] < 40));
let quantity = getQuantity(statues, 80, 1200, multiplier);
if (!quantity) return;
const variants = ["Statue", "Obelisk", "Monument", "Column", "Monolith", "Pillar", "Megalith", "Stele", "Runestone", "Sculpture", "Effigy", "Idol"];
const scripts = {
cypriot: "𐠁𐠂𐠃𐠄𐠅𐠈𐠊𐠋𐠌𐠍𐠎𐠏𐠐𐠑𐠒𐠓𐠔𐠕𐠖𐠗𐠘𐠙𐠚𐠛𐠜𐠝𐠞𐠟𐠠𐠡𐠢𐠣𐠤𐠥𐠦𐠧𐠨𐠩𐠪𐠫𐠬𐠭𐠮𐠯𐠰𐠱𐠲𐠳𐠴𐠵𐠷𐠸𐠼𐠿 ",
geez: "ሀለሐመሠረሰቀበተኀነአከወዐዘየደገጠጰጸፀፈፐ ",
coptic: "ⲲⲴⲶⲸⲺⲼⲾⳀⳁⳂⳃⳄⳆⳈⳊⳌⳎⳐⳒⳔⳖⳘⳚⳜⳞⳠⳢⳤ⳥⳧⳩⳪ⳫⳬⳭⳲ⳹⳾ ",
tibetan: "ༀ༁༂༃༄༅༆༇༈༉༊་༌༐༑༒༓༔༕༖༗༘༙༚༛༜༠༡༢༣༤༥༦༧༨༩༪༫༬༭༮༯༰༱༲༳༴༵༶༷༸༹༺༻༼༽༾༿",
mongolian: "᠀᠐᠑᠒ᠠᠡᠦᠧᠨᠩᠪᠭᠮᠯᠰᠱᠲᠳᠵᠻᠼᠽᠾᠿᡀᡁᡆᡍᡎᡏᡐᡑᡒᡓᡔᡕᡖᡗᡙᡜᡝᡞᡟᡠᡡᡭᡮᡯᡰᡱᡲᡳᡴᢀᢁᢂᢋᢏᢐᢑᢒᢓᢛᢜᢞᢟᢠᢡᢢᢤᢥᢦ"
};
while (quantity) {
const [cell] = extractAnyElement(statues);
const id = addMarker({cell, icon, type});
const culture = cells.culture[cell];
const variant = ra(variants);
const name = `${Names.getCulture(culture)} ${variant}`;
const script = scripts[ra(Object.keys(scripts))];
const inscription = Array(rand(40, 100))
.fill(null)
.map(() => ra(script))
.join("");
const legend = `An ancient ${variant.toLowerCase()}. It has an inscription, but no one can translate it:
<div style="font-size: 1.8em; line-break: anywhere;">${inscription}</div>`;
notes.push({id, name, legend});
quantity--;
}
}
function addRuines(type, icon, multiplier) {
const {cells} = pack;
let ruins = Array.from(cells.i.filter(i => !occupied[i] && cells.culture[i] && cells.h[i] >= 20 && cells.h[i] < 60));
let quantity = getQuantity(ruins, 80, 1200, multiplier);
if (!quantity) return;
const types = [
"City",
"Town",
"Settlement",
"Pyramid",
"Fort",
"Stronghold",
"Temple",
"Sacred site",
"Mausoleum",
"Outpost",
"Fortification",
"Fortress",
"Castle"
];
while (quantity) {
const [cell] = extractAnyElement(ruins);
const id = addMarker({cell, icon, type});
const ruinType = ra(types);
const name = `Ruined ${ruinType}`;
const legend = `Ruins of an ancient ${ruinType.toLowerCase()}. Untold riches may lie within.`;
notes.push({id, name, legend});
quantity--;
}
}
function addPortals(type, icon, multiplier) {
const {burgs} = pack;
let portals = burgs
.slice(1, Math.ceil(burgs.length / 10) + 1)
.filter(({cell}) => !occupied[cell])
.map(burg => [burg.name, burg.cell]);
let quantity = getQuantity(portals, 16, 8, multiplier);
if (!quantity) return;
while (quantity) {
const [portal] = extractAnyElement(portals);
const [burgName, cell] = portal;
const id = addMarker({cell, icon, type, px: 14});
const name = `${burgName} Portal`;
const legend = `An element of the magic portal system connecting major cities. Portals installed centuries ago, but still work fine`;
notes.push({id, name, legend});
quantity--;
}
}
return {generate, regenerate, getConfig, setConfig};
})();

View file

@ -3,9 +3,8 @@
window.Military = (function () {
const generate = function () {
TIME && console.time("generateMilitaryForces");
const cells = pack.cells,
p = cells.p,
states = pack.states;
const {cells, states} = pack;
const {p} = cells;
const valid = states.filter(s => s.i && !s.removed); // valid states
if (!options.military) options.military = getDefaultOptions();
@ -19,7 +18,6 @@ window.Military = (function () {
mounted: {Nomadic: 2.3, Highland: 0.6, Lake: 0.7, Naval: 0.3, Hunting: 0.7, River: 0.8},
machinery: {Nomadic: 0.8, Highland: 1.4, Lake: 1.1, Naval: 1.4, Hunting: 0.4, River: 1.1},
naval: {Nomadic: 0.5, Highland: 0.5, Lake: 1.2, Naval: 1.8, Hunting: 0.7, River: 1.2},
// non-default generic:
armored: {Nomadic: 1, Highland: 0.5, Lake: 1, Naval: 1, Hunting: 0.7, River: 1.1},
aviation: {Nomadic: 0.5, Highland: 0.5, Lake: 1.2, Naval: 1.2, Hunting: 0.6, River: 1.2},
magical: {Nomadic: 1, Highland: 2, Lake: 1, Naval: 1, Hunting: 1, River: 1}
@ -38,27 +36,24 @@ window.Military = (function () {
};
valid.forEach(s => {
const temp = (s.temp = {}),
d = s.diplomacy;
const expansionRate = Math.min(Math.max(s.expansionism / expn / (s.area / area), 0.25), 4); // how much state expansionism is realized
s.temp = {};
const d = s.diplomacy;
const expansionRate = minmax(s.expansionism / expn / (s.area / area), 0.25, 4); // how much state expansionism is realized
const diplomacyRate = d.some(d => d === "Enemy") ? 1 : d.some(d => d === "Rival") ? 0.8 : d.some(d => d === "Suspicion") ? 0.5 : 0.1; // peacefulness
const neighborsRate = Math.min(
Math.max(
s.neighbors.map(n => (n ? pack.states[n].diplomacy[s.i] : "Suspicion")).reduce((s, r) => (s += rate[r]), 0.5),
0.3
),
3
); // neighbors rate
s.alert = Math.min(Math.max(rn(expansionRate * diplomacyRate * neighborsRate, 2), 0.1), 5); // war alert rate (army modifier)
temp.platoons = [];
const neighborsRateRaw = s.neighbors.map(n => (n ? pack.states[n].diplomacy[s.i] : "Suspicion")).reduce((s, r) => (s += rate[r]), 0.5);
const neighborsRate = minmax(neighborsRateRaw, 0.3, 3); // neighbors rate
s.alert = minmax(rn(expansionRate * diplomacyRate * neighborsRate, 2), 0.1, 5); // alert rate (area modifier)
s.temp.platoons = [];
// apply overall state modifiers for unit types based on state features
for (const unit of options.military) {
if (!stateModifier[unit.type]) continue;
let modifier = stateModifier[unit.type][s.type] || 1;
if (unit.type === "mounted" && s.formName.includes("Horde")) modifier *= 2;
else if (unit.type === "naval" && s.form === "Republic") modifier *= 1.2;
temp[unit.name] = modifier * s.alert;
s.temp[unit.name] = modifier * s.alert;
}
});
@ -69,66 +64,96 @@ window.Military = (function () {
return "generic";
};
function passUnitLimits(unit, biome, state, culture, religion) {
if (unit.biomes && !unit.biomes.includes(biome)) return false;
if (unit.states && !unit.states.includes(state)) return false;
if (unit.cultures && !unit.cultures.includes(culture)) return false;
if (unit.religions && !unit.religions.includes(religion)) return false;
return true;
}
// rural cells
for (const i of cells.i) {
if (!cells.pop[i]) continue;
const s = states[cells.state[i]]; // cell state
if (!s.i || s.removed) continue;
let m = cells.pop[i] / 100; // basic rural army in percentages
if (cells.culture[i] !== s.culture) m = s.form === "Union" ? m / 1.2 : m / 2; // non-dominant culture
if (cells.religion[i] !== cells.religion[s.center]) m = s.form === "Theocracy" ? m / 2.2 : m / 1.4; // non-dominant religion
if (cells.f[i] !== cells.f[s.center]) m = s.type === "Naval" ? m / 1.2 : m / 1.8; // different landmass
const biome = cells.biome[i];
const state = cells.state[i];
const culture = cells.culture[i];
const religion = cells.religion[i];
const stateObj = states[state];
if (!state || stateObj.removed) continue;
let modifier = cells.pop[i] / 100; // basic rural army in percentages
if (culture !== stateObj.culture) modifier = stateObj.form === "Union" ? modifier / 1.2 : modifier / 2; // non-dominant culture
if (religion !== cells.religion[stateObj.center]) modifier = stateObj.form === "Theocracy" ? modifier / 2.2 : modifier / 1.4; // non-dominant religion
if (cells.f[i] !== cells.f[stateObj.center]) modifier = stateObj.type === "Naval" ? modifier / 1.2 : modifier / 1.8; // different landmass
const type = getType(i);
for (const u of options.military) {
const perc = +u.rural;
if (isNaN(perc) || perc <= 0 || !s.temp[u.name]) continue;
for (const unit of options.military) {
const perc = +unit.rural;
if (isNaN(perc) || perc <= 0 || !stateObj.temp[unit.name]) continue;
if (!passUnitLimits(unit, biome, state, culture, religion)) continue;
if (unit.type === "naval" && !cells.haven[i]) continue; // only near-ocean cells create naval units
const mod = type === "generic" ? 1 : cellTypeModifier[type][u.type]; // cell specific modifier
const army = m * perc * mod; // rural cell army
const t = rn(army * s.temp[u.name] * populationRate); // total troops
if (!t) continue;
let x = p[i][0],
y = p[i][1],
n = 0;
if (u.type === "naval") {
let haven = cells.haven[i];
(x = p[haven][0]), (y = p[haven][1]);
const cellTypeMod = type === "generic" ? 1 : cellTypeModifier[type][unit.type]; // cell specific modifier
const army = modifier * perc * cellTypeMod; // rural cell army
const total = rn(army * stateObj.temp[unit.name] * populationRate); // total troops
if (!total) continue;
let [x, y] = p[i];
let n = 0;
// place naval units to sea
if (unit.type === "naval") {
const haven = cells.haven[i];
[x, y] = p[haven];
n = 1;
} // place naval to sea
s.temp.platoons.push({cell: i, a: t, t, x, y, u: u.name, n, s: u.separate, type: u.type});
}
stateObj.temp.platoons.push({cell: i, a: total, t: total, x, y, u: unit.name, n, s: unit.separate, type: unit.type});
}
}
// burgs
for (const b of pack.burgs) {
if (!b.i || b.removed || !b.state || !b.population) continue;
const s = states[b.state]; // burg state
const biome = cells.biome[b.cell];
const state = b.state;
const culture = b.culture;
const religion = cells.religion[b.cell];
const stateObj = states[state];
let m = (b.population * urbanization) / 100; // basic urban army in percentages
if (b.capital) m *= 1.2; // capital has household troops
if (b.culture !== s.culture) m = s.form === "Union" ? m / 1.2 : m / 2; // non-dominant culture
if (cells.religion[b.cell] !== cells.religion[s.center]) m = s.form === "Theocracy" ? m / 2.2 : m / 1.4; // non-dominant religion
if (cells.f[b.cell] !== cells.f[s.center]) m = s.type === "Naval" ? m / 1.2 : m / 1.8; // different landmass
if (culture !== stateObj.culture) m = stateObj.form === "Union" ? m / 1.2 : m / 2; // non-dominant culture
if (religion !== cells.religion[stateObj.center]) m = stateObj.form === "Theocracy" ? m / 2.2 : m / 1.4; // non-dominant religion
if (cells.f[b.cell] !== cells.f[stateObj.center]) m = stateObj.type === "Naval" ? m / 1.2 : m / 1.8; // different landmass
const type = getType(b.cell);
for (const u of options.military) {
if (u.type === "naval" && !b.port) continue; // only ports produce naval units
const perc = +u.urban;
if (isNaN(perc) || perc <= 0 || !s.temp || !s.temp[u.name]) continue;
for (const unit of options.military) {
const perc = +unit.urban;
if (isNaN(perc) || perc <= 0 || !stateObj.temp[unit.name]) continue;
if (!passUnitLimits(unit, biome, state, culture, religion)) continue;
if (unit.type === "naval" && (!b.port || !cells.haven[b.cell])) continue; // only ports create naval units
const mod = type === "generic" ? 1 : burgTypeModifier[type][u.type]; // cell specific modifier
const mod = type === "generic" ? 1 : burgTypeModifier[type][unit.type]; // cell specific modifier
const army = m * perc * mod; // urban cell army
const t = rn(army * s.temp[u.name] * populationRate); // total troops
if (!t) continue;
let x = p[b.cell][0],
y = p[b.cell][1],
n = 0;
if (u.type === "naval") {
let haven = cells.haven[b.cell];
(x = p[haven][0]), (y = p[haven][1]);
const total = rn(army * stateObj.temp[unit.name] * populationRate); // total troops
if (!total) continue;
let [x, y] = p[b.cell];
let n = 0;
// place naval to sea
if (unit.type === "naval") {
const haven = cells.haven[b.cell];
[x, y] = p[haven];
n = 1;
} // place naval in sea cell
s.temp.platoons.push({cell: b.cell, a: t, t, x, y, u: u.name, n, s: u.separate, type: u.type});
}
stateObj.temp.platoons.push({cell: b.cell, a: total, t: total, x, y, u: unit.name, n, s: unit.separate, type: unit.type});
}
}
@ -141,7 +166,7 @@ window.Military = (function () {
})();
const expected = 3 * populationRate; // expected regiment size
const mergeable = (n0, n1) => (!n0.s && !n1.s) || n0.type === n1.type; // check if regiments can be merged
const mergeable = (n0, n1) => (!n0.s && !n1.s) || n0.u === n1.u; // check if regiments can be merged
// get regiments for each state
valid.forEach(s => {
@ -152,25 +177,27 @@ window.Military = (function () {
function createRegiments(nodes, s) {
if (!nodes.length) return [];
nodes.sort((a, b) => a.a - b.a); // form regiments in cells with most troops
const tree = d3.quadtree(
nodes,
d => d.x,
d => d.y
);
nodes.forEach(n => {
tree.remove(n);
const overlap = tree.find(n.x, n.y, 20);
if (overlap && overlap.t && mergeable(n, overlap)) {
merge(n, overlap);
nodes.forEach(node => {
tree.remove(node);
const overlap = tree.find(node.x, node.y, 20);
if (overlap && overlap.t && mergeable(node, overlap)) {
merge(node, overlap);
return;
}
if (n.t > expected) return;
const r = (expected - n.t) / (n.s ? 40 : 20); // search radius
const candidates = tree.findAll(n.x, n.y, r);
if (node.t > expected) return;
const r = (expected - node.t) / (node.s ? 40 : 20); // search radius
const candidates = tree.findAll(node.x, node.y, r);
for (const c of candidates) {
if (c.t < expected && mergeable(n, c)) {
merge(n, c);
if (c.t < expected && mergeable(node, c)) {
merge(node, c);
break;
}
}
@ -334,7 +361,13 @@ window.Military = (function () {
const getName = function (r, regiments) {
const cells = pack.cells;
const proper = r.n ? null : cells.province[r.cell] && pack.provinces[cells.province[r.cell]] ? pack.provinces[cells.province[r.cell]].name : cells.burg[r.cell] && pack.burgs[cells.burg[r.cell]] ? pack.burgs[cells.burg[r.cell]].name : null;
const proper = r.n
? null
: cells.province[r.cell] && pack.provinces[cells.province[r.cell]]
? pack.provinces[cells.province[r.cell]].name
: cells.burg[r.cell] && pack.burgs[cells.burg[r.cell]]
? pack.burgs[cells.burg[r.cell]].name
: null;
const number = nth(regiments.filter(reg => reg.n === r.n && reg.i < r.i).length + 1);
const form = r.n ? "Fleet" : "Regiment";
return `${number}${proper ? ` (${proper}) ` : ` `}${form}`;
@ -351,7 +384,12 @@ window.Military = (function () {
const generateNote = function (r, s) {
const cells = pack.cells;
const base = cells.burg[r.cell] && pack.burgs[cells.burg[r.cell]] ? pack.burgs[cells.burg[r.cell]].name : cells.province[r.cell] && pack.provinces[cells.province[r.cell]] ? pack.provinces[cells.province[r.cell]].fullName : null;
const base =
cells.burg[r.cell] && pack.burgs[cells.burg[r.cell]]
? pack.burgs[cells.burg[r.cell]].name
: cells.province[r.cell] && pack.provinces[cells.province[r.cell]]
? pack.provinces[cells.province[r.cell]].fullName
: null;
const station = base ? `${r.name} is ${r.n ? "based" : "stationed"} in ${base}. ` : "";
const composition = r.a

View file

@ -128,20 +128,14 @@ window.Names = (function () {
// generate name for culture
const getCulture = function (culture, min, max, dupl) {
if (culture === undefined) {
ERROR && console.error("Please define a culture");
return;
}
if (culture === undefined) return ERROR && console.error("Please define a culture");
const base = pack.cultures[culture].base;
return getBase(base, min, max, dupl);
};
// generate short name for culture
const getCultureShort = function (culture) {
if (culture === undefined) {
ERROR && console.error("Please define a culture");
return;
}
if (culture === undefined) return ERROR && console.error("Please define a culture");
return getBaseShort(pack.cultures[culture].base);
};
@ -157,10 +151,9 @@ window.Names = (function () {
};
// generate state name based on capital or random name and culture-specific suffix
// prettier-ignore
const getState = function (name, culture, base) {
if (name === undefined) {ERROR && console.error("Please define a base name"); return;}
if (culture === undefined && base === undefined) {ERROR && console.error("Please define a culture"); return;}
if (name === undefined) return ERROR && console.error("Please define a base name");
if (culture === undefined && base === undefined) return ERROR && console.error("Please define a culture");
if (base === undefined) base = pack.cultures[culture].base;
// exclude endings inappropriate for states name
@ -168,44 +161,65 @@ window.Names = (function () {
if (name.length > 6 && name.slice(-4) === "berg") name = name.slice(0, -4); // remove -berg for any
if (name.length > 5 && name.slice(-3) === "ton") name = name.slice(0, -3); // remove -ton for any
if (base === 5 && ["sk", "ev", "ov"].includes(name.slice(-2))) name = name.slice(0,-2); // remove -sk/-ev/-ov for Ruthenian
else if (base === 12) return vowel(name.slice(-1)) ? name : name + "u"; // Japanese ends on any vowel or -u
else if (base === 18 && P(.4)) name = vowel(name.slice(0,1).toLowerCase()) ? "Al" + name.toLowerCase() : "Al " + name; // Arabic starts with -Al
if (base === 5 && ["sk", "ev", "ov"].includes(name.slice(-2))) name = name.slice(0, -2);
// remove -sk/-ev/-ov for Ruthenian
else if (base === 12) return vowel(name.slice(-1)) ? name : name + "u";
// Japanese ends on any vowel or -u
else if (base === 18 && P(0.4)) name = vowel(name.slice(0, 1).toLowerCase()) ? "Al" + name.toLowerCase() : "Al " + name; // Arabic starts with -Al
// no suffix for fantasy bases
if (base > 32 && base < 42) return name;
// define if suffix should be used
if (name.length > 3 && vowel(name.slice(-1))) {
if (vowel(name.slice(-2,-1)) && P(.85)) name = name.slice(0,-2); // 85% for vv
else if (P(.7)) name = name.slice(0,-1); // ~60% for cv
if (vowel(name.slice(-2, -1)) && P(0.85)) name = name.slice(0, -2);
// 85% for vv
else if (P(0.7)) name = name.slice(0, -1);
// ~60% for cv
else return name;
} else if (P(.4)) return name; // 60% for cc and vc
} else if (P(0.4)) return name; // 60% for cc and vc
// define suffix
let suffix = "ia"; // standard suffix
const rnd = Math.random(), l = name.length;
if (base === 3 && rnd < .03 && l < 7) suffix = "terra"; // Italian
else if (base === 4 && rnd < .03 && l < 7) suffix = "terra"; // Spanish
else if (base === 13 && rnd < .03 && l < 7) suffix = "terra"; // Portuguese
else if (base === 2 && rnd < .03 && l < 7) suffix = "terre"; // French
else if (base === 0 && rnd < .5 && l < 7) suffix = "land"; // German
else if (base === 1 && rnd < .4 && l < 7 ) suffix = "land"; // English
else if (base === 6 && rnd < .3 && l < 7) suffix = "land"; // Nordic
else if (base === 32 && rnd < .1 && l < 7) suffix = "land"; // generic Human
else if (base === 7 && rnd < .1) suffix = "eia"; // Greek
else if (base === 9 && rnd < .35) suffix = "maa"; // Finnic
else if (base === 15 && rnd < .4 && l < 6) suffix = "orszag"; // Hungarian
else if (base === 16) suffix = rnd < .6 ? "stan" : "ya"; // Turkish
else if (base === 10) suffix = "guk"; // Korean
else if (base === 11) suffix = " Guo"; // Chinese
else if (base === 14) suffix = rnd < .5 && l < 6 ? "tlan" : "co"; // Nahuatl
else if (base === 17 && rnd < .8) suffix = "a"; // Berber
else if (base === 18 && rnd < .8) suffix = "a"; // Arabic
const rnd = Math.random(),
l = name.length;
if (base === 3 && rnd < 0.03 && l < 7) suffix = "terra";
// Italian
else if (base === 4 && rnd < 0.03 && l < 7) suffix = "terra";
// Spanish
else if (base === 13 && rnd < 0.03 && l < 7) suffix = "terra";
// Portuguese
else if (base === 2 && rnd < 0.03 && l < 7) suffix = "terre";
// French
else if (base === 0 && rnd < 0.5 && l < 7) suffix = "land";
// German
else if (base === 1 && rnd < 0.4 && l < 7) suffix = "land";
// English
else if (base === 6 && rnd < 0.3 && l < 7) suffix = "land";
// Nordic
else if (base === 32 && rnd < 0.1 && l < 7) suffix = "land";
// generic Human
else if (base === 7 && rnd < 0.1) suffix = "eia";
// Greek
else if (base === 9 && rnd < 0.35) suffix = "maa";
// Finnic
else if (base === 15 && rnd < 0.4 && l < 6) suffix = "orszag";
// Hungarian
else if (base === 16) suffix = rnd < 0.6 ? "stan" : "ya";
// Turkish
else if (base === 10) suffix = "guk";
// Korean
else if (base === 11) suffix = " Guo";
// Chinese
else if (base === 14) suffix = rnd < 0.5 && l < 6 ? "tlan" : "co";
// Nahuatl
else if (base === 17 && rnd < 0.8) suffix = "a";
// Berber
else if (base === 18 && rnd < 0.8) suffix = "a"; // Arabic
return validateSuffix(name, suffix);
}
};
function validateSuffix(name, suffix) {
if (name.slice(-1 * suffix.length) === suffix) return name; // no suffix if name already ends with it
@ -248,7 +262,7 @@ window.Names = (function () {
{name: "English", i: 1, min: 6, max: 11, d: "", m: .1, b: "Abingdon,Albrighton,Alcester,Almondbury,Altrincham,Amersham,Andover,Appleby,Ashboume,Atherstone,Aveton,Axbridge,Aylesbury,Baldock,Bamburgh,Barton,Basingstoke,Berden,Bere,Berkeley,Berwick,Betley,Bideford,Bingley,Birmingham,Blandford,Blechingley,Bodmin,Bolton,Bootham,Boroughbridge,Boscastle,Bossinney,Bramber,Brampton,Brasted,Bretford,Bridgetown,Bridlington,Bromyard,Bruton,Buckingham,Bungay,Burton,Calne,Cambridge,Canterbury,Carlisle,Castleton,Caus,Charmouth,Chawleigh,Chichester,Chillington,Chinnor,Chipping,Chisbury,Cleobury,Clifford,Clifton,Clitheroe,Cockermouth,Coleshill,Combe,Congleton,Crafthole,Crediton,Cuddenbeck,Dalton,Darlington,Dodbrooke,Drax,Dudley,Dunstable,Dunster,Dunwich,Durham,Dymock,Exeter,Exning,Faringdon,Felton,Fenny,Finedon,Flookburgh,Fowey,Frampton,Gateshead,Gatton,Godmanchester,Grampound,Grantham,Guildford,Halesowen,Halton,Harbottle,Harlow,Hatfield,Hatherleigh,Haydon,Helston,Henley,Hertford,Heytesbury,Hinckley,Hitchin,Holme,Hornby,Horsham,Kendal,Kenilworth,Kilkhampton,Kineton,Kington,Kinver,Kirby,Knaresborough,Knutsford,Launceston,Leighton,Lewes,Linton,Louth,Luton,Lyme,Lympstone,Macclesfield,Madeley,Malborough,Maldon,Manchester,Manningtree,Marazion,Marlborough,Marshfield,Mere,Merryfield,Middlewich,Midhurst,Milborne,Mitford,Modbury,Montacute,Mousehole,Newbiggin,Newborough,Newbury,Newenden,Newent,Norham,Northleach,Noss,Oakham,Olney,Orford,Ormskirk,Oswestry,Padstow,Paignton,Penkneth,Penrith,Penzance,Pershore,Petersfield,Pevensey,Pickering,Pilton,Pontefract,Portsmouth,Preston,Quatford,Reading,Redcliff,Retford,Rockingham,Romney,Rothbury,Rothwell,Salisbury,Saltash,Seaford,Seasalter,Sherston,Shifnal,Shoreham,Sidmouth,Skipsea,Skipton,Solihull,Somerton,Southam,Southwark,Standon,Stansted,Stapleton,Stottesdon,Sudbury,Swavesey,Tamerton,Tarporley,Tetbury,Thatcham,Thaxted,Thetford,Thornbury,Tintagel,Tiverton,Torksey,Totnes,Towcester,Tregoney,Trematon,Tutbury,Uxbridge,Wallingford,Wareham,Warenmouth,Wargrave,Warton,Watchet,Watford,Wendover,Westbury,Westcheap,Weymouth,Whitford,Wickwar,Wigan,Wigmore,Winchelsea,Winkleigh,Wiscombe,Witham,Witheridge,Wiveliscombe,Woodbury,Yeovil"},
{name: "French", i: 2, min: 5, max: 13, d: "nlrs", m: .1, b: "Adon,Aillant,Amilly,Andonville,Ardon,Artenay,Ascheres,Ascoux,Attray,Aubin,Audeville,Aulnay,Autruy,Auvilliers,Auxy,Aveyron,Baccon,Bardon,Barville,Batilly,Baule,Bazoches,Beauchamps,Beaugency,Beaulieu,Beaune,Bellegarde,Boesses,Boigny,Boiscommun,Boismorand,Boisseaux,Bondaroy,Bonnee,Bonny,Bordes,Bou,Bougy,Bouilly,Boulay,Bouzonville,Bouzy,Boynes,Bray,Breteau,Briare,Briarres,Bricy,Bromeilles,Bucy,Cepoy,Cercottes,Cerdon,Cernoy,Cesarville,Chailly,Chaingy,Chalette,Chambon,Champoulet,Chanteau,Chantecoq,Chapell,Charme,Charmont,Charsonville,Chateau,Chateauneuf,Chatel,Chatenoy,Chatillon,Chaussy,Checy,Chevannes,Chevillon,Chevilly,Chevry,Chilleurs,Choux,Chuelles,Clery,Coinces,Coligny,Combleux,Combreux,Conflans,Corbeilles,Corquilleroy,Cortrat,Coudroy,Coullons,Coulmiers,Courcelles,Courcy,Courtemaux,Courtempierre,Courtenay,Cravant,Crottes,Dadonville,Dammarie,Dampierre,Darvoy,Desmonts,Dimancheville,Donnery,Dordives,Dossainville,Douchy,Dry,Echilleuses,Egry,Engenville,Epieds,Erceville,Ervauville,Escrennes,Escrignelles,Estouy,Faverelles,Fay,Feins,Ferolles,Ferrieres,Fleury,Fontenay,Foret,Foucherolles,Freville,Gatinais,Gaubertin,Gemigny,Germigny,Gidy,Gien,Girolles,Givraines,Gondreville,Grangermont,Greneville,Griselles,Guigneville,Guilly,Gyleslonains,Huetre,Huisseau,Ingrannes,Ingre,Intville,Isdes,Jargeau,Jouy,Juranville,Bussiere,Laas,Ladon,Lailly,Langesse,Leouville,Ligny,Lombreuil,Lorcy,Lorris,Loury,Louzouer,Malesherbois,Marcilly,Mardie,Mareau,Marigny,Marsainvilliers,Melleroy,Menestreau,Merinville,Messas,Meung,Mezieres,Migneres,Mignerette,Mirabeau,Montargis,Montbarrois,Montbouy,Montcresson,Montereau,Montigny,Montliard,Mormant,Morville,Moulinet,Moulon,Nancray,Nargis,Nesploy,Neuville,Neuvy,Nevoy,Nibelle,Nogent,Noyers,Ocre,Oison,Olivet,Ondreville,Onzerain,Orleans,Ormes,Orville,Oussoy,Outarville,Ouzouer,Pannecieres,Pannes,Patay,Paucourt,Pers,Pierrefitte,Pithiverais,Pithiviers,Poilly,Potier,Prefontaines,Presnoy,Pressigny,Puiseaux,Quiers,Ramoulu,Rebrechien,Rouvray,Rozieres,Rozoy,Ruan,Sandillon,Santeau,Saran,Sceaux,Seichebrieres,Semoy,Sennely,Sermaises,Sigloy,Solterre,Sougy,Sully,Sury,Tavers,Thignonville,Thimory,Thorailles,Thou,Tigy,Tivernon,Tournoisis,Trainou,Treilles,Trigueres,Trinay,Vannes,Varennes,Vennecy,Vieilles,Vienne,Viglain,Vignes,Villamblain,Villemandeur,Villemoutiers,Villemurlin,Villeneuve,Villereau,Villevoques,Villorceau,Vimory,Vitry,Vrigny,Ivre"},
{name: "Italian", i: 3, min: 5, max: 12, d: "cltr", m: .1, b: "Accumoli,Acquafondata,Acquapendente,Acuto,Affile,Agosta,Alatri,Albano,Allumiere,Alvito,Amaseno,Amatrice,Anagni,Anguillara,Anticoli,Antrodoco,Anzio,Aprilia,Aquino,Arce,Arcinazzo,Ardea,Ariccia,Arlena,Arnara,Arpino,Arsoli,Artena,Ascrea,Atina,Ausonia,Bagnoregio,Barbarano,Bassano,Bassiano,Bellegra,Belmonte,Blera,Bolsena,Bomarzo,Borbona,Borgo,Borgorose,Boville,Bracciano,Broccostella,Calcata,Camerata,Campagnano,Campodimele,Campoli,Canale,Canepina,Canino,Cantalice,Cantalupo,Canterano,Capena,Capodimonte,Capranica,Caprarola,Carbognano,Casalattico,Casalvieri,Casape,Casaprota,Casperia,Cassino,Castelforte,Castelliri,Castello,Castelnuovo,Castiglione,Castro,Castrocielo,Cave,Ceccano,Celleno,Cellere,Ceprano,Cerreto,Cervara,Cervaro,Cerveteri,Ciampino,Ciciliano,Cineto,Cisterna,Cittaducale,Cittareale,Civita,Civitavecchia,Civitella,Colfelice,Collalto,Colle,Colleferro,Collegiove,Collepardo,Collevecchio,Colli,Colonna,Concerviano,Configni,Contigliano,Corchiano,Coreno,Cori,Cottanello,Esperia,Fabrica,Faleria,Fara,Farnese,Ferentino,Fiamignano,Fiano,Filacciano,Filettino,Fiuggi,Fiumicino,Fondi,Fontana,Fonte,Fontechiari,Forano,Formello,Formia,Frascati,Frasso,Frosinone,Fumone,Gaeta,Gallese,Gallicano,Gallinaro,Gavignano,Genazzano,Genzano,Gerano,Giuliano,Gorga,Gradoli,Graffignano,Greccio,Grottaferrata,Grotte,Guarcino,Guidonia,Ischia,Isola,Itri,Jenne,Labico,Labro,Ladispoli,Lanuvio,Lariano,Latera,Lenola,Leonessa,Licenza,Longone,Lubriano,Maenza,Magliano,Mandela,Manziana,Marano,Marcellina,Marcetelli,Marino,Marta,Mazzano,Mentana,Micigliano,Minturno,Mompeo,Montalto,Montasola,Monte,Montebuono,Montefiascone,Monteflavio,Montelanico,Monteleone,Montelibretti,Montenero,Monterosi,Monterotondo,Montopoli,Montorio,Moricone,Morlupo,Morolo,Morro,Nazzano,Nemi,Nepi,Nerola,Nespolo,Nettuno,Norma,Olevano,Onano,Oriolo,Orte,Orvinio,Paganico,Palestrina,Paliano,Palombara,Pastena,Patrica,Percile,Pescorocchiano,Pescosolido,Petrella,Piansano,Picinisco,Pico,Piedimonte,Piglio,Pignataro,Pisoniano,Pofi,Poggio,Poli,Pomezia,Pontecorvo,Pontinia,Ponza,Ponzano,Posta,Pozzaglia,Priverno,Proceno,Prossedi,Riano,Rieti,Rignano,Riofreddo,Ripi,Rivodutri,Rocca,Roccagiovine,Roccagorga,Roccantica,Roccasecca,Roiate,Ronciglione,Roviano,Sabaudia,Sacrofano,Salisano,Sambuci,Santa,Santi,Santopadre,Saracinesco,Scandriglia,Segni,Selci,Sermoneta,Serrone,Settefrati,Sezze,Sgurgola,Sonnino,Sora,Soriano,Sperlonga,Spigno,Stimigliano,Strangolagalli,Subiaco,Supino,Sutri,Tarano,Tarquinia,Terelle,Terracina,Tessennano,Tivoli,Toffia,Tolfa,Torre,Torri,Torrice,Torricella,Torrita,Trevi,Trevignano,Trivigliano,Turania,Tuscania,Vacone,Valentano,Vallecorsa,Vallemaio,Vallepietra,Vallerano,Vallerotonda,Vallinfreda,Valmontone,Varco,Vasanello,Vejano,Velletri,Ventotene,Veroli,Vetralla,Vicalvi,Vico,Vicovaro,Vignanello,Viterbo,Viticuso,Vitorchiano,Vivaro,Zagarolo"},
{name: "Castillian", i: 4, min: 5, max: 11, d: "lr", m: 0, b: "Abanades,Ablanque,Adobes,Ajofrin,Alameda,Alaminos,Alarilla,Albalate,Albares,Albarreal,Albendiego,Alcabon,Alcanizo,Alcaudete,Alcocer,Alcolea,Alcoroches,Aldea,Aldeanueva,Algar,Algora,Alhondiga,Alique,Almadrones,Almendral,Almoguera,Almonacid,Almorox,Alocen,Alovera,Alustante,Angon,Anguita,Anover,Anquela,Arbancon,Arbeteta,Arcicollar,Argecilla,Arges,Armallones,Armuna,Arroyo,Atanzon,Atienza,Aunon,Azuqueca,Azutan,Baides,Banos,Banuelos,Barcience,Bargas,Barriopedro,Belvis,Berninches,Borox,Brihuega,Budia,Buenaventura,Bujalaro,Burguillos,Burujon,Bustares,Cabanas,Cabanillas,Calera,Caleruela,Calzada,Camarena,Campillo,Camunas,Canizar,Canredondo,Cantalojas,Cardiel,Carmena,Carranque,Carriches,Casa,Casarrubios,Casas,Casasbuenas,Caspuenas,Castejon,Castellar,Castilforte,Castillo,Castilnuevo,Cazalegas,Cebolla,Cedillo,Cendejas,Centenera,Cervera,Checa,Chequilla,Chillaron,Chiloeches,Chozas,Chueca,Cifuentes,Cincovillas,Ciruelas,Ciruelos,Cobeja,Cobeta,Cobisa,Cogollor,Cogolludo,Condemios,Congostrina,Consuegra,Copernal,Corduente,Corral,Cuerva,Domingo,Dosbarrios,Driebes,Duron,El,Embid,Erustes,Escalona,Escalonilla,Escamilla,Escariche,Escopete,Espinosa,Espinoso,Esplegares,Esquivias,Estables,Estriegana,Fontanar,Fuembellida,Fuensalida,Fuentelsaz,Gajanejos,Galve,Galvez,Garciotum,Gascuena,Gerindote,Guadamur,Henche,Heras,Herreria,Herreruela,Hijes,Hinojosa,Hita,Hombrados,Hontanar,Hontoba,Horche,Hormigos,Huecas,Huermeces,Huerta,Hueva,Humanes,Illan,Illana,Illescas,Iniestola,Irueste,Jadraque,Jirueque,Lagartera,Las,Layos,Ledanca,Lillo,Lominchar,Loranca,Los,Lucillos,Lupiana,Luzaga,Luzon,Madridejos,Magan,Majaelrayo,Malaga,Malaguilla,Malpica,Mandayona,Mantiel,Manzaneque,Maqueda,Maranchon,Marchamalo,Marjaliza,Marrupe,Mascaraque,Masegoso,Matarrubia,Matillas,Mazarete,Mazuecos,Medranda,Megina,Mejorada,Mentrida,Mesegar,Miedes,Miguel,Millana,Milmarcos,Mirabueno,Miralrio,Mocejon,Mochales,Mohedas,Molina,Monasterio,Mondejar,Montarron,Mora,Moratilla,Morenilla,Muduex,Nambroca,Navalcan,Negredo,Noblejas,Noez,Nombela,Noves,Numancia,Nuno,Ocana,Ocentejo,Olias,Olmeda,Ontigola,Orea,Orgaz,Oropesa,Otero,Palmaces,Palomeque,Pantoja,Pardos,Paredes,Pareja,Parrillas,Pastrana,Pelahustan,Penalen,Penalver,Pepino,Peralejos,Peralveche,Pinilla,Pioz,Piqueras,Polan,Portillo,Poveda,Pozo,Pradena,Prados,Puebla,Puerto,Pulgar,Quer,Quero,Quintanar,Quismondo,Rebollosa,Recas,Renera,Retamoso,Retiendas,Riba,Rielves,Rillo,Riofrio,Robledillo,Robledo,Romanillos,Romanones,Rueda,Sacecorbo,Sacedon,Saelices,Salmeron,San,Santa,Santiuste,Santo,Sartajada,Sauca,Sayaton,Segurilla,Selas,Semillas,Sesena,Setiles,Sevilleja,Sienes,Siguenza,Solanillos,Somolinos,Sonseca,Sotillo,Sotodosos,Talavera,Tamajon,Taragudo,Taravilla,Tartanedo,Tembleque,Tendilla,Terzaga,Tierzo,Tordellego,Tordelrabano,Tordesilos,Torija,Torralba,Torre,Torrecilla,Torrecuadrada,Torrejon,Torremocha,Torrico,Torrijos,Torrubia,Tortola,Tortuera,Tortuero,Totanes,Traid,Trijueque,Trillo,Turleque,Uceda,Ugena,Ujados,Urda,Utande,Valdarachas,Valdesotos,Valhermoso,Valtablado,Valverde,Velada,Viana,Vinuelas,Yebes,Yebra,Yelamos,Yeles,Yepes,Yuncler,Yunclillos,Yuncos,Yunquera,Zaorejas,Zarzuela,Zorita"},
{name: "Castillian", i: 4, min: 5, max: 11, d: "lr", m: 0, b: "Abanades,Ablanque,Adobes,Ajofrin,Alameda,Alaminos,Alarilla,Albalate,Albares,Albarreal,Albendiego,Alcabon,Alcanizo,Alcaudete,Alcocer,Alcolea,Alcoroches,Aldea,Aldeanueva,Algar,Algora,Alhondiga,Alique,Almadrones,Almendral,Almoguera,Almonacid,Almorox,Alocen,Alovera,Alustante,Angon,Anguita,Anover,Anquela,Arbancon,Arbeteta,Arcicollar,Argecilla,Arges,Armallones,Armuna,Arroyo,Atanzon,Atienza,Aunon,Azuqueca,Azutan,Baides,Banos,Banuelos,Barcience,Bargas,Barriopedro,Belvis,Berninches,Borox,Brihuega,Budia,Buenaventura,Bujalaro,Burguillos,Burujon,Bustares,Cabanas,Cabanillas,Calera,Caleruela,Calzada,Camarena,Campillo,Camunas,Canizar,Canredondo,Cantalojas,Cardiel,Carmena,Carranque,Carriches,Casa,Casarrubios,Casas,Casasbuenas,Caspuenas,Castejon,Castellar,Castilforte,Castillo,Castilnuevo,Cazalegas,Cebolla,Cedillo,Cendejas,Centenera,Cervera,Checa,Chequilla,Chillaron,Chiloeches,Chozas,Chueca,Cifuentes,Cincovillas,Ciruelas,Ciruelos,Cobeja,Cobeta,Cobisa,Cogollor,Cogolludo,Condemios,Congostrina,Consuegra,Copernal,Corduente,Corral,Cuerva,Domingo,Dosbarrios,Driebes,Duron,El,Embid,Erustes,Escalona,Escalonilla,Escamilla,Escariche,Escopete,Espinosa,Espinoso,Esplegares,Esquivias,Estables,Estriegana,Fontanar,Fuembellida,Fuensalida,Fuentelsaz,Gajanejos,Galve,Galvez,Garciotum,Gascuena,Gerindote,Guadamur,Henche,Heras,Herreria,Herreruela,Hijes,Hinojosa,Hita,Hombrados,Hontanar,Hontoba,Horche,Hormigos,Huecas,Huermeces,Huerta,Hueva,Humanes,Illan,Illana,Illescas,Iniestola,Irueste,Jadraque,Jirueque,Lagartera,Las,Layos,Ledanca,Lillo,Lominchar,Loranca,Los,Lucillos,Lupiana,Luzaga,Luzon,Madridejos,Magan,Majaelrayo,Malaga,Malaguilla,Malpica,Mandayona,Mantiel,Manzaneque,Maqueda,Maranchon,Marchamalo,Marjaliza,Marrupe,Mascaraque,Masegoso,Matarrubia,Matillas,Mazarete,Mazuecos,Medranda,Megina,Mejorada,Mentrida,Mesegar,Miedes,Miguel,Millana,Milmarcos,Mirabueno,Miralrio,Mocejon,Mochales,Mohedas,Molina,Monasterio,Mondejar,Montarron,Mora,Moratilla,Morenilla,Muduex,Nambroca,Navalcan,Negredo,Noblejas,Noez,Nombela,Noves,Numancia,Nuno,Ocana,Ocentejo,Olias,Olmeda,Ontigola,Orea,Orgaz,Oropesa,Otero,Palmaces,Palomeque,Pantoja,Pardos,Paredes,Pareja,Parrillas,Pastrana,Pelahustan,Penalen,Penalver,Pepino,Peralejos,Peralveche,Pinilla,Pioz,Piqueras,Polan,Portillo,Poveda,Pozo,Pradena,Prados,Puebla,Puerto,Pulgar,Quer,Quero,Quintanar,Quismondo,Rebollosa,Recas,Renera,Retamoso,Retiendas,Riba,Rielves,Rillo,Riofrio,Robledillo,Robledo,Romanillos,Romanones,Rueda,Sacecorbo,Sacedon,Saelices,Salmeron,San,Santa,Santiuste,Santo,Sartajada,Sauca,Sayaton,Segurilla,Selas,Semillas,Sesena,Setiles,Sevilleja,Sienes,Siguenza,Solanillos,Somolinos,Sonseca,Sotillo,Sotodasos,Talavera,Tamajon,Taragudo,Taravilla,Tartanedo,Tembleque,Tendilla,Terzaga,Tierzo,Tordellego,Tordelrabano,Tordesilos,Torija,Torralba,Torre,Torrecilla,Torrecuadrada,Torrejon,Torremocha,Torrico,Torrijos,Torrubia,Tortola,Tortuera,Tortuero,Totanes,Traid,Trijueque,Trillo,Turleque,Uceda,Ugena,Ujados,Urda,Utande,Valdarachas,Valdesotos,Valhermoso,Valtablado,Valverde,Velada,Viana,Vinuelas,Yebes,Yebra,Yelamos,Yeles,Yepes,Yuncler,Yunclillos,Yuncos,Yunquera,Zaorejas,Zarzuela,Zorita"},
{name: "Ruthenian", i: 5, min: 5, max: 10, d: "", m: 0, b: "Belgorod,Beloberezhye,Belyi,Belz,Berestiy,Berezhets,Berezovets,Berezutsk,Bobruisk,Bolonets,Borisov,Borovsk,Bozhesk,Bratslav,Bryansk,Brynsk,Buryn,Byhov,Chechersk,Chemesov,Cheremosh,Cherlen,Chern,Chernigov,Chernitsa,Chernobyl,Chernogorod,Chertoryesk,Chetvertnia,Demyansk,Derevesk,Devyagoresk,Dichin,Dmitrov,Dorogobuch,Dorogobuzh,Drestvin,Drokov,Drutsk,Dubechin,Dubichi,Dubki,Dubkov,Dveren,Galich,Glebovo,Glinsk,Goloty,Gomiy,Gorodets,Gorodische,Gorodno,Gorohovets,Goroshin,Gorval,Goryshon,Holm,Horobor,Hoten,Hotin,Hotmyzhsk,Ilovech,Ivan,Izborsk,Izheslavl,Kamenets,Kanev,Karachev,Karna,Kavarna,Klechesk,Klyapech,Kolomyya,Kolyvan,Kopyl,Korec,Kornik,Korochunov,Korshev,Korsun,Koshkin,Kotelno,Kovyla,Kozelsk,Kozelsk,Kremenets,Krichev,Krylatsk,Ksniatin,Kulatsk,Kursk,Kursk,Lebedev,Lida,Logosko,Lomihvost,Loshesk,Loshichi,Lubech,Lubno,Lubutsk,Lutsk,Luchin,Luki,Lukoml,Luzha,Lvov,Mtsensk,Mdin,Medniki,Melecha,Merech,Meretsk,Mescherskoe,Meshkovsk,Metlitsk,Mezetsk,Mglin,Mihailov,Mikitin,Mikulino,Miloslavichi,Mogilev,Mologa,Moreva,Mosalsk,Moschiny,Mozyr,Mstislav,Mstislavets,Muravin,Nemech,Nemiza,Nerinsk,Nichan,Novgorod,Novogorodok,Obolichi,Obolensk,Obolensk,Oleshsk,Olgov,Omelnik,Opoka,Opoki,Oreshek,Orlets,Osechen,Oster,Ostrog,Ostrov,Perelai,Peremil,Peremyshl,Pererov,Peresechen,Perevitsk,Pereyaslav,Pinsk,Ples,Polotsk,Pronsk,Proposhesk,Punia,Putivl,Rechitsa,Rodno,Rogachev,Romanov,Romny,Roslavl,Rostislavl,Rostovets,Rsha,Ruza,Rybchesk,Rylsk,Rzhavesk,Rzhev,Rzhischev,Sambor,Serensk,Serensk,Serpeysk,Shilov,Shuya,Sinech,Sizhka,Skala,Slovensk,Slutsk,Smedin,Sneporod,Snitin,Snovsk,Sochevo,Sokolec,Starica,Starodub,Stepan,Sterzh,Streshin,Sutesk,Svinetsk,Svisloch,Terebovl,Ternov,Teshilov,Teterin,Tiversk,Torchevsk,Toropets,Torzhok,Tripolye,Trubchevsk,Tur,Turov,Usvyaty,Uteshkov,Vasilkov,Velil,Velye,Venev,Venicha,Verderev,Vereya,Veveresk,Viazma,Vidbesk,Vidychev,Voino,Volodimer,Volok,Volyn,Vorobesk,Voronich,Voronok,Vorotynsk,Vrev,Vruchiy,Vselug,Vyatichsk,Vyatka,Vyshegorod,Vyshgorod,Vysokoe,Yagniatin,Yaropolch,Yasenets,Yuryev,Yuryevets,Zaraysk,Zhitomel,Zholvazh,Zizhech,Zubkov,Zudechev,Zvenigorod"},
{name: "Nordic", i: 6, min: 6, max: 10, d: "kln", m: .1, b: "Akureyri,Aldra,Alftanes,Andenes,Austbo,Auvog,Bakkafjordur,Ballangen,Bardal,Beisfjord,Bifrost,Bildudalur,Bjerka,Bjerkvik,Bjorkosen,Bliksvaer,Blokken,Blonduos,Bolga,Bolungarvik,Borg,Borgarnes,Bosmoen,Bostad,Bostrand,Botsvika,Brautarholt,Breiddalsvik,Bringsli,Brunahlid,Budardalur,Byggdakjarni,Dalvik,Djupivogur,Donnes,Drageid,Drangsnes,Egilsstadir,Eiteroga,Elvenes,Engavogen,Ertenvog,Eskifjordur,Evenes,Eyrarbakki,Fagernes,Fallmoen,Fellabaer,Fenes,Finnoya,Fjaer,Fjelldal,Flakstad,Flateyri,Flostrand,Fludir,Gardaber,Gardur,Gimstad,Givaer,Gjeroy,Gladstad,Godoya,Godoynes,Granmoen,Gravdal,Grenivik,Grimsey,Grindavik,Grytting,Hafnir,Halsa,Hauganes,Haugland,Hauknes,Hella,Helland,Hellissandur,Hestad,Higrav,Hnifsdalur,Hofn,Hofsos,Holand,Holar,Holen,Holkestad,Holmavik,Hopen,Hovden,Hrafnagil,Hrisey,Husavik,Husvik,Hvammstangi,Hvanneyri,Hveragerdi,Hvolsvollur,Igeroy,Indre,Inndyr,Innhavet,Innes,Isafjordur,Jarklaustur,Jarnsreykir,Junkerdal,Kaldvog,Kanstad,Karlsoy,Kavosen,Keflavik,Kjelde,Kjerstad,Klakk,Kopasker,Kopavogur,Korgen,Kristnes,Krutoga,Krystad,Kvina,Lande,Laugar,Laugaras,Laugarbakki,Laugarvatn,Laupstad,Leines,Leira,Leiren,Leland,Lenvika,Loding,Lodingen,Lonsbakki,Lopsmarka,Lovund,Luroy,Maela,Melahverfi,Meloy,Mevik,Misvaer,Mornes,Mosfellsber,Moskenes,Myken,Naurstad,Nesberg,Nesjahverfi,Nesset,Nevernes,Obygda,Ofoten,Ogskardet,Okervika,Oknes,Olafsfjordur,Oldervika,Olstad,Onstad,Oppeid,Oresvika,Orsnes,Orsvog,Osmyra,Overdal,Prestoya,Raudalaekur,Raufarhofn,Reipo,Reykholar,Reykholt,Reykjahlid,Rif,Rinoya,Rodoy,Rognan,Rosvika,Rovika,Salhus,Sanden,Sandgerdi,Sandoker,Sandset,Sandvika,Saudarkrokur,Selfoss,Selsoya,Sennesvik,Setso,Siglufjordur,Silvalen,Skagastrond,Skjerstad,Skonland,Skorvogen,Skrova,Sleneset,Snubba,Softing,Solheim,Solheimar,Sorarnoy,Sorfugloy,Sorland,Sormela,Sorvaer,Sovika,Stamsund,Stamsvika,Stave,Stokka,Stokkseyri,Storjord,Storo,Storvika,Strand,Straumen,Strendene,Sudavik,Sudureyri,Sundoya,Sydalen,Thingeyri,Thorlakshofn,Thorshofn,Tjarnabyggd,Tjotta,Tosbotn,Traelnes,Trofors,Trones,Tverro,Ulvsvog,Unnstad,Utskor,Valla,Vandved,Varmahlid,Vassos,Vevelstad,Vidrek,Vik,Vikholmen,Vogar,Vogehamn,Vopnafjordur"},
{name: "Greek", i: 7, min: 5, max: 11, d: "s", m: .1, b: "Abdera,Abila,Abydos,Acanthus,Acharnae,Actium,Adramyttium,Aegae,Aegina,Aegium,Aenus,Agrinion,Aigosthena,Akragas,Akrai,Akrillai,Akroinon,Akrotiri,Alalia,Alexandreia,Alexandretta,Alexandria,Alinda,Amarynthos,Amaseia,Ambracia,Amida,Amisos,Amnisos,Amphicaea,Amphigeneia,Amphipolis,Amphissa,Ankon,Antigona,Antipatrea,Antioch,Antioch,Antiochia,Andros,Apamea,Aphidnae,Apollonia,Argos,Arsuf,Artanes,Artemita,Argyroupoli,Asine,Asklepios,Aspendos,Assus,Astacus,Athenai,Athmonia,Aytos,Ancient,Baris,Bhrytos,Borysthenes,Berge,Boura,Bouthroton,Brauron,Byblos,Byllis,Byzantium,Bythinion,Callipolis,Cebrene,Chalcedon,Calydon,Carystus,Chamaizi,Chalcis,Chersonesos,Chios,Chytri,Clazomenae,Cleonae,Cnidus,Colosse,Corcyra,Croton,Cyme,Cyrene,Cythera,Decelea,Delos,Delphi,Demetrias,Dicaearchia,Dimale,Didyma,Dion,Dioscurias,Dodona,Dorylaion,Dyme,Edessa,Elateia,Eleusis,Eleutherna,Emporion,Ephesus,Ephyra,Epidamnos,Epidauros,Eresos,Eretria,Erythrae,Eubea,Gangra,Gaza,Gela,Golgi,Gonnos,Gorgippia,Gournia,Gortyn,Gythium,Hagios,Hagia,Halicarnassus,Halieis,Helike,Heliopolis,Hellespontos,Helorus,Hemeroskopeion,Heraclea,Hermione,Hermonassa,Hierapetra,Hierapolis,Himera,Histria,Hubla,Hyele,Ialysos,Iasus,Idalium,Imbros,Iolcus,Itanos,Ithaca,Juktas,Kallipolis,Kamares,Kameiros,Kannia,Kamarina,Kasmenai,Katane,Kerkinitida,Kepoi,Kimmerikon,Kios,Klazomenai,Knidos,Knossos,Korinthos,Kos,Kourion,Kume,Kydonia,Kynos,Kyrenia,Lamia,Lampsacus,Laodicea,Lapithos,Larissa,Lato,Laus,Lebena,Lefkada,Lekhaion,Leibethra,Leontinoi,Lepreum,Lessa,Lilaea,Lindus,Lissus,Epizephyrian,Madytos,Magnesia,Mallia,Mantineia,Marathon,Marmara,Maroneia,Masis,Massalia,Megalopolis,Megara,Mesembria,Messene,Metapontum,Methana,Methone,Methumna,Miletos,Misenum,Mochlos,Monastiraki,Morgantina,Mulai,Mukenai,Mylasa,Myndus,Myonia,Myra,Myrmekion,Mutilene,Myos,Nauplios,Naucratis,Naupactus,Naxos,Neapoli,Neapolis,Nemea,Nicaea,Nicopolis,Nirou,Nymphaion,Nysa,Oenoe,Oenus,Odessos,Olbia,Olous,Olympia,Olynthus,Opus,Orchomenus,Oricos,Orestias,Oreus,Oropus,Onchesmos,Pactye,Pagasae,Palaikastro,Pandosia,Panticapaeum,Paphos,Parium,Paros,Parthenope,Patrae,Pavlopetri,Pegai,Pelion,Peiraies,Pella,Percote,Pergamum,Petsofa,Phaistos,Phaleron,Phanagoria,Pharae,Pharnacia,Pharos,Phaselis,Philippi,Pithekussa,Philippopolis,Platanos,Phlius,Pherae,Phocaea,Pinara,Pisa,Pitane,Pitiunt,Pixous,Plataea,Poseidonia,Potidaea,Priapus,Priene,Prousa,Pseira,Psychro,Pteleum,Pydna,Pylos,Pyrgos,Rhamnus,Rhegion,Rhithymna,Rhodes,Rhypes,Rizinia,Salamis,Same,Samos,Scyllaeum,Selinus,Seleucia,Semasus,Sestos,Scidrus,Sicyon,Side,Sidon,Siteia,Sinope,Siris,Sklavokampos,Smyrna,Soli,Sozopolis,Sparta,Stagirus,Stratos,Stymphalos,Sybaris,Surakousai,Taras,Tanagra,Tanais,Tauromenion,Tegea,Temnos,Tenedos,Tenea,Teos,Thapsos,Thassos,Thebai,Theodosia,Therma,Thespiae,Thronion,Thoricus,Thurii,Thyreum,Thyria,Tiruns,Tithoraea,Tomis,Tragurion,Trapeze,Trapezus,Tripolis,Troizen,Troliton,Troy,Tylissos,Tyras,Tyros,Tyritake,Vasiliki,Vathypetros,Zakynthos,Zakros,Zankle"},
@ -264,7 +278,7 @@ window.Names = (function () {
{name: "Berber", i: 17, min: 4, max: 10, d: "s", m: .2, b: "Abkhouch,Adrar,Agadir,Agelmam,Aghmat,Agrakal,Agulmam,Ahaggar,Almou,Anfa,Annaba,Aousja,Arbat,Argoub,Arif,Asfi,Assamer,Assif,Azaghar,Azmour,Azrou,Beccar,Beja,Bennour,Benslimane,Berkane,Berrechid,Bizerte,Bouskoura,Boutferda,Dar Bouazza,Darallouch,Darchaabane,Dcheira,Denden,Djebel,Djedeida,Drargua,Essaouira,Ezzahra,Fas,Fnideq,Ghezeze,Goubellat,Grisaffen,Guelmim,Guercif,Hammamet,Harrouda,Hoceima,Idurar,Ifendassen,Ifoghas,Imilchil,Inezgane,Izoughar,Jendouba,Kacem,Kelibia,Kenitra,Kerrando,Khalidia,Khemisset,Khenifra,Khouribga,Kidal,Korba,Korbous,Lahraouyine,Larache,Leyun,Lqliaa,Manouba,Martil,Mazagan,Mcherga,Mdiq,Megrine,Mellal,Melloul,Midelt,Mohammedia,Mornag,Mrrakc,Nabeul,Nadhour,Nador,Nawaksut,Nefza,Ouarzazate,Ouazzane,Oued Zem,Oujda,Ouladteima,Qsentina,Rades,Rafraf,Safi,Sefrou,Sejnane,Settat,Sijilmassa,Skhirat,Slimane,Somaa,Sraghna,Susa,Tabarka,Taferka,Tafza,Tagbalut,Tagerdayt,Takelsa,Tanja,Tantan,Taourirt,Taroudant,Tasfelalayt,Tattiwin,Taza,Tazerka,Tazizawt,Tebourba,Teboursouk,Temara,Testour,Tetouan,Tibeskert,Tifelt,Tinariwen,Tinduf,Tinja,Tiznit,Toubkal,Trables,Tubqal,Tunes,Urup,Watlas,Wehran,Wejda,Youssoufia,Zaghouan,Zahret,Zemmour,Zriba"},
{name: "Arabic", i: 18, min: 4, max: 9, d: "ae", m: .2, b: "Abadilah,Abayt,Abha,Abud,Aden,Ahwar,Ajman,Alabadilah,Alabar,Alahjer,Alain,Alaraq,Alarish,Alarjam,Alashraf,Alaswaaq,Alawali,Albarar,Albawadi,Albirk,Aldhabiyah,Alduwaid,Alfareeq,Algayed,Alhada,Alhafirah,Alhamar,Alharam,Alharidhah,Alhawtah,Alhazim,Alhrateem,Alhudaydah,Alhujun,Alhuwaya,Aljahra,Aljohar,Aljubail,Alkawd,Alkhalas,Alkhawaneej,Alkhen,Alkhhafah,Alkhobar,Alkhuznah,Alkiranah,Allisafah,Allith,Almadeed,Almardamah,Almarwah,Almasnaah,Almejammah,Almojermah,Almshaykh,Almurjan,Almuwayh,Almuzaylif,Alnaheem,Alnashifah,Alqadeimah,Alqah,Alqahma,Alqalh,Alqouz,Alquaba,Alqunfudhah,Alqurayyat,Alradha,Alraqmiah,Alsadyah,Alsafa,Alshagab,Alshoqiq,Alshuqaiq,Alsilaa,Althafeer,Alwakrah,Alwasqah,Amaq,Amran,Annaseem,Aqbiyah,Arafat,Arar,Ardah,Arrawdah,Asfan,Ashayrah,Ashshahaniyah,Askar,Assaffaniyah,Ayaar,Aziziyah,Baesh,Bahrah,Baish,Balhaf,Banizayd,Baqaa,Baqal,Bidiyah,Bisha,Biyatah,Buqhayq,Burayda,Dafiyat,Damad,Dammam,Dariyah,Daynah,Dhafar,Dhahran,Dhalkut,Dhamar,Dhubab,Dhurma,Dibab,Dirab,Doha,Dukhan,Duwaibah,Enaker,Fadhla,Fahaheel,Fanateer,Farasan,Fardah,Fujairah,Ghalilah,Ghar,Ghizlan,Ghomgyah,Ghran,Hababah,Habil,Hadiyah,Haffah,Hajanbah,Hajrah,Halban,Haqqaq,Haradh,Hasar,Hathah,Hawarwar,Hawaya,Hawiyah,Hebaa,Hefar,Hijal,Husnah,Huwailat,Huwaitah,Irqah,Isharah,Ithrah,Jamalah,Jarab,Jareef,Jarwal,Jash,Jazan,Jeddah,Jiblah,Jihanah,Jilah,Jizan,Joha,Joraibah,Juban,Jubbah,Juddah,Jumeirah,Kamaran,Keyad,Khab,Khabtsaeed,Khaiybar,Khasab,Khathirah,Khawarah,Khulais,Khulays,Klayah,Kumzar,Limah,Linah,Mabar,Madrak,Mahab,Mahalah,Makhtar,Makshosh,Manfuhah,Manifah,Manshabah,Mareah,Masdar,Mashwar,Masirah,Maskar,Masliyah,Mastabah,Maysaan,Mazhar,Mdina,Meeqat,Mirbah,Mirbat,Mokhtara,Muharraq,Muladdah,Musandam,Musaykah,Muscat,Mushayrif,Musrah,Mussafah,Mutrah,Nafhan,Nahdah,Nahwa,Najran,Nakhab,Nizwa,Oman,Qadah,Qalhat,Qamrah,Qasam,Qatabah,Qawah,Qosmah,Qurain,Quraydah,Quriyat,Qurwa,Rabigh,Radaa,Rafha,Rahlah,Rakamah,Rasheedah,Rasmadrakah,Risabah,Rustaq,Ryadh,Saabah,Saabar,Sabtaljarah,Sabya,Sadad,Sadah,Safinah,Saham,Sahlat,Saihat,Salalah,Salmalzwaher,Salmiya,Sanaa,Sanaban,Sayaa,Sayyan,Shabayah,Shabwah,Shafa,Shalim,Shaqra,Sharjah,Sharkat,Sharurah,Shatifiyah,Shibam,Shidah,Shifiyah,Shihar,Shoqra,Shoqsan,Shuwaq,Sibah,Sihmah,Sinaw,Sirwah,Sohar,Suhailah,Sulaibiya,Sunbah,Tabuk,Taif,Taqah,Tarif,Tharban,Thumrait,Thuqbah,Thuwal,Tubarjal,Turaif,Turbah,Tuwaiq,Ubar,Umaljerem,Urayarah,Urwah,Wabrah,Warbah,Yabreen,Yadamah,Yafur,Yarim,Yemen,Yiyallah,Zabid,Zahwah,Zallaq,Zinjibar,Zulumah"},
{name: "Inuit", i: 19, min: 5, max: 15, d: "alutsn", m: 0, b: "Aaluik,Aappilattoq,Aasiaat,Agdleruussakasit,Aggas,Akia,Akilia,Akuliaruseq,Akuliarutsip,Akunnaaq,Agissat,Agssaussat,Alluitsup,Alluttoq,Aluit,Aluk,Ammassalik,Amarortalik,Amitsorsuaq,Anarusuk,Angisorsuaq,Anguniartarfik,Annertussoq,Annikitsoq,Anoraliuirsoq,Appat,Apparsuit,Apusiaajik,Arsivik,Arsuk,Ataa,Atammik,Ateqanngitsorsuaq,Atilissuaq,Attu,Aukarnersuaq,Augpalugtoq, Aumat,Auvilikavsak,Auvilkikavsaup,Avadtlek,Avallersuaq,Bjornesk,Blabaerdalen,Blomsterdalen,Brattalhid,Bredebrae,Brededal,Claushavn,Edderfulegoer,Egger,Eqalugalinnguit,Eqalugarssuit,Eqaluit,Eqqua,Etah,Graah,Hakluyt,Haredalen,Hareoen,Hundeo,Igdlorssuit,Igaliku,Igdlugdlip,Igdluluarssuk,Iginniafik,Ikamiuk,Ikamiut,Ikarissat,Ikateq,Ikeq,Ikerasak,Ikerasaarsuk,Ikermiut,Ikermoissuaq,Ikertivaq,Ikorfarssuit,Ikorfat,Ilimanaq,Illorsuit,Iluileq,Iluiteq,Ilulissat,Illunnguit,Imaarsivik,Imartunarssuk,Immikkoortukajik,Innaarsuit,Ingjald,Inneruulalik,Inussullissuaq,Iqek,Ikerasakassak,Iperaq,Ippik,Isortok,Isungartussoq,Itileq,Itivdleq,Itissaalik,Ittit,Ittoqqortoormiit,Ivingmiut,Ivittuut,Kanajoorartuut,Kangaamiut,Kangaarsuk,Kangaatsiaq,Kangeq,Kangerluk,Kangerlussuaq,Kanglinnguit,Kapisillit,Karrat,Kekertamiut,Kiatak,Kiatassuaq,Kiataussaq,Kigatak,Kigdlussat,Kinaussak,Kingittorsuaq,Kitak,Kitsissuarsuit,Kitsissut,Klenczner,Kook,Kraulshavn,Kujalleq,Kullorsuaq,Kulusuk,Kuurmiit,Kuusuaq,Laksedalen,Maniitsoq,Marrakajik,Mattaangassut,Mernoq,Mittivakkat,Moriusaq,Myggbukta,Naajaat,Nako,Nangissat,Nanortalik,Nanuuseq,Nappassoq,Narsarmijt,Narssaq,Narsarsuaq,Narssarssuk,Nasaussaq,Nasiffik,Natsiarsiorfik,Naujanguit,Niaqornaarsuk,Niaqornat,Nordfjordspasset,Nugatsiaq,Nuluuk,Nunaa,Nunarssit,Nunarsuaq,Nunataaq,Nunatakavsaup,Nutaarmiut,Nuugaatsiaq,Nuuk,Nuukullak,Nuuluk,Nuussuaq,Olonkinbyen,Oqaatsut,Oqaitsúnguit,Oqonermiut,Oodaaq,Paagussat,Palungataq,Pamialluk,Paamiut,Paatuut,Patuersoq,Perserajoq,Paornivik,Pituffik,Puugutaa,Puulkuip,Qaanaq,Qaarsorsuaq,Qaarsorsuatsiaq,Qaasuitsup,Qaersut,Qajartalik,Qallunaat,Qaneq,Qaqaarissorsuaq,Qaqit,Qaqortok,Qasigiannguit,Qasse,Qassimiut,Qeertartivaq,Qeertartivatsiaq,Qeqertaq,Qeqertarssdaq,Qeqertarsuaq,Qeqertasussuk,Qeqertarsuatsiaat,Qeqertat,Qeqqata,Qernertoq,Qernertunnguit,Qianarreq,Qilalugkiarfik,Qingagssat,Qingaq,Qoornuup,Qorlortorsuaq,Qullikorsuit,Qunnerit,Qutdleq,Ravnedalen,Ritenbenk,Rypedalen,Sarfannguit,Saarlia,Saarloq,Saatoq,Saatorsuaq,Saatup,Saattut,Sadeloe,Salleq,Salliaruseq,Sammeqqat,Sammisoq,Sanningassoq,Saqqaq,Saqqarlersuaq,Saqqarliit,Sarqaq,Sattiaatteq,Savissivik,Serfanguaq,Sermersooq,Sermersut,Sermilik,Sermiligaaq,Sermitsiaq,Simitakaja,Simiutaq,Singamaq,Siorapaluk,Sisimiut,Sisuarsuit,Skal,Skarvefjeld,Skjoldungen,Storoen,Sullorsuaq,Suunikajik,Sverdrup,Taartoq,Takiseeq,Talerua,Tarqo,Tasirliaq,Tasiusak,Tiilerilaaq,Timilersua,Timmiarmiut,Tingmjarmiut,Traill,Tukingassoq,Tuttorqortooq,Tuujuk,Tuttulissuup,Tussaaq,Uigordlit,Uigorlersuaq,Uilortussoq,Uiivaq,Ujuaakajiip,Ukkusissat,Umanat,Upernavik,Upernattivik,Upepnagssivik,Upernivik,Uttorsiutit,Uumannaq,Uummannaarsuk,Uunartoq,Uvkusigssat,Ymer"},
{name: "Basque", i: 20, min: 4, max: 11, d: "r", m: .1, b: "Abadio,Abaltzisketa,Abanto Zierbena,Aduna,Agurain,Aia,Aiara,Aizarnazabal,Ajangiz,Albiztur,Alegia,Alkiza,Alonsotegi,Altzaga,Altzo,Amezketa,Amorebieta,Amoroto,Amurrio,Andoain,Anoeta,Antzuola,Arakaldo,Arama,Aramaio,Arantzazu,Arbatzegi ,Areatza,Aretxabaleta,Arraia,Arrankudiaga,Arrasate,Arratzu,Arratzua,Arrieta,Arrigorriaga,Artea,Artzentales,Artziniega,Asparrena,Asteasu,Astigarraga,Ataun,Atxondo,Aulesti,Azkoitia,Azpeitia,Bakio,Baliarrain,Balmaseda,Barakaldo,Barrika,Barrundia,Basauri,Bastida,Beasain,Bedia,Beizama,Belauntza,Berango,Berantevilla,Berastegi,Bergara,Bermeo,Bernedo,Berriatua,Berriz,Berrobi,Bidania,Bilar,Bilbao,Burgelu,Busturia,Deba,Derio,Dima,Donemiliaga,Donostia,Dulantzi,Durango,Ea,Eibar,Elantxobe,Elduain,Elgeta,Elgoibar,Elorrio,Erandio,Ere-o,Ermua,Errenteria,Errezil,Erribera Beitia,Erriberagoitia,Errigoiti,Eskoriatza,Eskuernaga,Etxebarri,Etxebarria,Ezkio,Fika,Forua,Fruiz,Gabiria,Gaintza,Galdakao,Galdames,Gamiz,Garai,Gasteiz,Gatika,Gatzaga,Gaubea,Gauna,Gautegiz Arteaga,Gaztelu,Gernika,Gerrikaitz,Getaria,Getxo,Gizaburuaga,Goiatz,Gordexola,Gorliz,Harana,Hernani,Hernialde,Hondarribia,Ibarra,Ibarrangelu,Idiazabal,Iekora,Igorre,Ikaztegieta,Iru-a Oka,Irun,Irura,Iruraiz,Ispaster,Itsaso,Itsasondo,Iurreta,Izurtza,Jatabe,Kanpezu,Karrantza Harana,Kortezubi,Kripan,Kuartango,Lanestosa,Lantziego,Larrabetzu,Larraul,Lasarte,Laudio,Laukiz,Lazkao,Leaburu,Legazpi,Legorreta,Legutio,Leintz,Leioa,Lekeitio,Lemoa,Lemoiz,Leza,Lezama,Lezo,Lizartza,Loiu,Lumo,Ma-aria,Maeztu,Mallabia,Markina,Maruri,Ma-ueta,Me-aka,Mendaro,Mendata,Mendexa,Moreda Araba,Morga,Mundaka,Mungia,Munitibar,Murueta,Muskiz,Mutiloa,Mutriku,Muxika,Nabarniz,O-ati,Oiartzun,Oion,Okondo,Olaberria,Ondarroa,Ordizia,Orendain,Orexa,Oria,Orio,Ormaiztegi,Orozko,Ortuella,Otxandio,Pasaia,Plentzia,Portugalete,Samaniego,Santurtzi,Segura,Sestao,Sondika,Sopela,Sopuerta,Soraluze,Sukarrieta,Tolosa,Trapagaran,Turtzioz,Ubarrundia,Ubide,Ugao,Urdua,Urduliz,Urizaharra,Urkabustaiz,Urnieta,Urretxu,Usurbil,Xemein,Zaia,Zaldibar,Zaldibia,Zalduondo,Zambrana,Zamudio,Zaratamo,Zarautz,Zeanuri,Zeberio,Zegama,Zerain,Zestoa,Zierbena,Zigoitia,Ziortza,Zizurkil,Zuia,Zumaia,Zumarraga"},
{name: "Basque", i: 20, min: 4, max: 11, d: "r", m: .1, b: "Abadio,Abaltzisketa,Abanto Zierbena,Aduna,Agurain,Aia,Aiara,Aizarnazabal,Ajangiz,Albiztur,Alegia,Alkiza,Alonsotegi,Altzaga,Altzo,Amezketa,Amorebieta,Amoroto,Amurrio,Andoain,Anoeta,Antzuola,Arakaldo,Arama,Aramaio,Arantzazu,Arbatzegi ,Areatza,Aretxabaleta,Arraia,Arrankudiaga,Arrasate,Arratzu,Arratzua,Arrieta,Arrigorriaga,Artea,Artzentales,Artziniega,Asparrena,Asteasu,Astigarraga,Ataun,Atxondo,Aulesti,Azkoitia,Azpeitia,Bakio,Baliarrain,Balmaseda,Barakaldo,Barrika,Barrundia,Basauri,Bastida,Beasain,Bedia,Beizama,Belauntza,Berango,Berantevilla,Berastegi,Bergara,Bermeo,Bernedo,Berriatua,Berriz,Berrobi,Bidania,Bilar,Bilbao,Burgelu,Busturia,Deba,Derio,Dima,Donemiliaga,Donostia,Dulantzi,Durango,Ea,Eibar,Elantxobe,Elduain,Elgeta,Elgoibar,Elorrio,Erandio,Ereno,Ermua,Errenteria,Errezil,Erribera Beitia,Erriberagoitia,Errigoiti,Eskoriatza,Eskuernaga,Etxebarri,Etxebarria,Ezkio,Fika,Forua,Fruiz,Gabiria,Gaintza,Galdakao,Galdames,Gamiz,Garai,Gasteiz,Gatika,Gatzaga,Gaubea,Gauna,Gautegiz Arteaga,Gaztelu,Gernika,Gerrikaitz,Getaria,Getxo,Gizaburuaga,Goiatz,Gordexola,Gorliz,Harana,Hernani,Hernialde,Hondarribia,Ibarra,Ibarrangelu,Idiazabal,Iekora,Igorre,Ikaztegieta,Iruna Oka,Irun,Irura,Iruraiz,Ispaster,Itsaso,Itsasondo,Iurreta,Izurtza,Jatabe,Kanpezu,Karrantza Harana,Kortezubi,Kripan,Kuartango,Lanestosa,Lantziego,Larrabetzu,Larraul,Lasarte,Laudio,Laukiz,Lazkao,Leaburu,Legazpi,Legorreta,Legutio,Leintz,Leioa,Lekeitio,Lemoa,Lemoiz,Leza,Lezama,Lezo,Lizartza,Loiu,Lumo,Manaria,Maeztu,Mallabia,Markina,Maruri,Manueta,Menaka,Mendaro,Mendata,Mendexa,Moreda Araba,Morga,Mundaka,Mungia,Munitibar,Murueta,Muskiz,Mutiloa,Mutriku,Muxika,Nabarniz,Onati,Oiartzun,Oion,Okondo,Olaberria,Ondarroa,Ordizia,Orendain,Orexa,Oria,Orio,Ormaiztegi,Orozko,Ortuella,Otxandio,Pasaia,Plentzia,Portugalete,Samaniego,Santurtzi,Segura,Sestao,Sondika,Sopela,Sopuerta,Soraluze,Sukarrieta,Tolosa,Trapagaran,Turtzioz,Ubarrundia,Ubide,Ugao,Urdua,Urduliz,Urizaharra,Urkabustaiz,Urnieta,Urretxu,Usurbil,Xemein,Zaia,Zaldibar,Zaldibia,Zalduondo,Zambrana,Zamudio,Zaratamo,Zarautz,Zeanuri,Zeberio,Zegama,Zerain,Zestoa,Zierbena,Zigoitia,Ziortza,Zizurkil,Zuia,Zumaia,Zumarraga"},
{name: "Nigerian", i: 21, min: 4, max: 10, d: "", m: .3, b: "Abadogo,Abafon,Abdu,Acharu,Adaba,Adealesu,Adeto,Adyongo,Afaga,Afamju,Afuje,Agbelagba,Agigbigi,Agogoke,Ahute,Aiyelaboro,Ajebe,Ajola,Akarekwu,Akessan,Akunuba,Alawode,Alkaijji,Amangam,Amaoji,Amgbaye,Amtasa,Amunigun,Anase,Aniho,Animahun,Antul,Anyoko,Apekaa,Arapagi,Asamagidi,Asande,Ataibang,Awgbagba,Awhum,Awodu,Babanana,Babateduwa,Bagu,Bakura,Bandakwai,Bangdi,Barbo,Barkeje,Basa,Basabra,Basansagawa,Bieleshin,Bilikani,Birnindodo,Braidu,Bulakawa,Buriburi,Burisidna,Busum,Bwoi,Cainnan,Chakum,Charati,Chondugh,Dabibikiri,Dagwarga,Dallok,Danalili,Dandala,Darpi,Dhayaki,Dokatofa,Doma,Dozere,Duci,Dugan,Ebelibri,Efem,Efoi,Egudu,Egundugbo,Ekoku,Ekpe,Ekwere,Erhua,Eteu,Etikagbene,Ewhoeviri,Ewhotie,Ezemaowa,Fatima,Gadege,Galakura,Galea,Gamai,Gamen,Ganjin,Gantetudu,Garangamawa,Garema,Gargar,Gari,Garinbode,Garkuwa,Garu Kime,Gazabu,Gbure,Gerti,Gidan,Giringwe,Gitabaremu,Giyagiri,Giyawa,Gmawa,Golakochi,Golumba,Guchi,Gudugu,Gunji,Gusa,Gwambula,Gwamgwam,Gwodoti,Hayinlere,Hayinmaialewa,Hirishi,Hombo,Ibefum,Iberekodo,Ibodeipa,Icharge,Ideoro,Idofin,Idofinoka,Idya,Iganmeji,Igbetar,Igbogo,Ijoko,Ijuwa,Ikawga,Ikekogbe,Ikhin,Ikoro,Ikotefe,Ikotokpora,Ikpakidout,Ikpeoniong,Ilofa,Imuogo,Inyeneke,Iorsugh,Ipawo,Ipinlerere,Isicha,Itakpa,Itoki,Iyedeame,Jameri,Jangi,Jara,Jare,Jataudakum,Jaurogomki,Jepel,Jibam,Jirgu,Jirkange,Kafinmalama,Kamkem,Katab,Katanga,Katinda,Katirije,Kaurakimba,Keffinshanu,Kellumiri,Kiagbodor,Kibiare,Kingking,Kirbutu,Kita,Kogbo,Kogogo,Kopje,Koriga,Koroko,Korokorosei,Kotoku,Kuata,Kujum,Kukau,Kunboon,Kuonubogbene,Kurawe,Kushinahu,Kwaramakeri,Ladimeji,Lafiaro,Lahaga,Laindebajanle,Laindegoro,Lajere,Lakati,Ligeri,Litenswa,Lokobimagaji,Lusabe,Maba,Madarzai,Magoi,Maialewa,Maianita,Maijuja,Mairakuni,Maleh,Malikansaa,Mallamkola,Mallammaduri,Marmara,Masagu,Masoma,Mata,Matankali,Mbalare,Megoyo,Meku,Miama,Mige,Mkporagwu,Modi,Molafa,Mshi,Msugh,Muduvu,Murnachehu,Namnai,Nanumawa,Nasudu,Ndagawo,Ndamanma,Ndiebeleagu,Ndiwulunbe,Ndonutim,Ngaruwa,Ngbande,Nguengu,Nto Ekpe,Nubudi,Nyajo,Nyido,Nyior,Obafor,Obazuwa,Odajie,Odiama,Ofunatam,Ogali,Ogan,Ogbaga,Ogbahu,Ogultu,Ogunbunmi,Ogunmakin,Ojaota,Ojirami,Ojopode,Okehin,Olugunna,Omotunde,Onipede,Onisopi,Onma,Orhere,Orya,Oshotan,Otukwang,Otunade,Pepegbene,Poros,Rafin,Rampa,Rimi,Rinjim,Robertkiri,Rugan,Rumbukawa,Sabiu,Sabon,Sabongari,Sai,Salmatappare,Sangabama,Sarabe,Seboregetore,Seibiri,Sendowa,Shafar,Shagwa,Shata,Shefunda,Shengu,Sokoron,Sunnayu,Taberlma,Tafoki,Takula,Talontan,Taraku,Tarhemba,Tayu,Ter,Timtim,Timyam,Tindirke,Tirkalou,Tokunbo,Tonga,Torlwam,Tseakaadza,Tseanongo,Tseavungu,Tsebeeve,Tsekov,Tsepaegh,Tuba,Tumbo,Tungalombo,Tungamasu,Tunganrati,Tunganyakwe,Tungenzuri,Ubimimi,Uhkirhi,Umoru,Umuabai,Umuaja,Umuajuju,Umuimo,Umuojala,Unchida,Ungua,Unguwar,Unongo,Usha,Ute,Utongbo,Vembera,Vorokotok,Wachin,Walebaga,Wurawura,Wuro,Yanbashi,Yanmedi,Yenaka,Yoku,Zamangera,Zarunkwari,Zilumo,Zulika"},
{name: "Celtic", i: 22, min: 4, max: 12, d: "nld", m: 0, b: "Aberaman,Aberangell,Aberarth,Aberavon,Aberbanc,Aberbargoed,Aberbeeg,Abercanaid,Abercarn,Abercastle,Abercegir,Abercraf,Abercregan,Abercych,Abercynon,Aberdare,Aberdaron,Aberdaugleddau,Aberdeen,Aberdulais,Aberdyfi,Aberedw,Abereiddy,Abererch,Abereron,Aberfan,Aberffraw,Aberffrwd,Abergavenny,Abergele,Aberglasslyn,Abergorlech,Abergwaun,Abergwesyn,Abergwili,Abergwynfi,Abergwyngregyn,Abergynolwyn,Aberhafesp,Aberhonddu,Aberkenfig,Aberllefenni,Abermain,Abermaw,Abermorddu,Abermule,Abernant,Aberpennar,Aberporth,Aberriw,Abersoch,Abersychan,Abertawe,Aberteifi,Aberthin,Abertillery,Abertridwr,Aberystwyth,Achininver,Afonhafren,Alisaha,Antinbhearmor,Ardenna,Attacon,Beira,Bhrura,Boioduro,Bona,Boudobriga,Bravon,Brigant,Briganta,Briva,Cambodunum,Cambra,Caracta,Catumagos,Centobriga,Ceredigion,Chalain,Dinn,Diwa,Dubingen,Duro,Ebora,Ebruac,Eburodunum,Eccles,Eighe,Eireann,Ferkunos,Genua,Ghrainnse,Inbhear,Inbhir,Inbhirair,Innerleithen,Innerleven,Innerwick,Inver,Inveraldie,Inverallan,Inveralmond,Inveramsay,Inveran,Inveraray,Inverarnan,Inverbervie,Inverclyde,Inverell,Inveresk,Inverfarigaig,Invergarry,Invergordon,Invergowrie,Inverhaddon,Inverkeilor,Inverkeithing,Inverkeithney,Inverkip,Inverleigh,Inverleith,Inverloch,Inverlochlarig,Inverlochy,Invermay,Invermoriston,Inverness,Inveroran,Invershin,Inversnaid,Invertrossachs,Inverugie,Inveruglas,Inverurie,Kilninver,Kirkcaldy,Kirkintilloch,Krake,Latense,Leming,Lindomagos,Llanaber,Lochinver,Lugduno,Magoduro,Monmouthshire,Narann,Novioduno,Nowijonago,Octoduron,Penning,Pheofharain,Ricomago,Rossinver,Salodurum,Seguia,Sentica,Theorsa,Uige,Vitodurum,Windobona"},
{name: "Mesopotamian", i: 23, min: 4, max: 9, d: "srpl", m: .1, b: "Adab,Akkad,Akshak,Amnanum,Arbid,Arpachiyah,Arrapha,Assur,Babilim,Badtibira,Balawat,Barsip,Borsippa,Carchemish,Chagar Bazar,Chuera,Ctesiphon ,Der,Dilbat,Diniktum,Doura,Durkurigalzu,Ekallatum,Emar,Erbil,Eridu,Eshnunn,Fakhariya ,Gawra,Girsu,Hadatu,Hamoukar,Haradum,Harran,Hatra,Idu,Irisagrig,Isin,Jemdet,Kahat,Kartukulti,Khaiber,Kish ,Kisurra,Kuara,Kutha,Lagash,Larsa ,Leilan,Marad,Mardaman,Mari,Mashkan,Mumbaqat ,Nabada,Nagar,Nerebtum,Nimrud,Nineveh,Nippur,Nuzi,Qalatjarmo,Qatara,Rawda,Seleucia,Shaduppum,Shanidar,Sharrukin,Shemshara,Shibaniba,Shuruppak,Sippar,Tarbisu,Tellagrab,Tellessawwan,Tellessweyhat,Tellhassuna,Telltaya,Telul,Terqa,Thalathat,Tutub,Ubaid ,Umma,Ur,Urfa,Urkesh,Uruk,Urum,Zabalam,Zenobia"},

View file

@ -52,7 +52,7 @@ window.ReliefIcons = (function () {
function getReliefIcon(i, h) {
const temp = grid.cells.temp[pack.cells.g[i]];
const type = h > 70 && temp < 0 ? "mountSnow" : h > 70 ? "mount" : "hill";
const size = h > 70 ? (h - 45) * mod : Math.min(Math.max((h - 40) * mod, 3), 6);
const size = h > 70 ? (h - 45) * mod : minmax((h - 40) * mod, 3, 6);
return [getIcon(type), size];
}
}

View file

@ -2,7 +2,22 @@
window.Religions = (function () {
// name generation approach and relative chance to be selected
const approach = {Number: 1, Being: 3, Adjective: 5, "Color + Animal": 5, "Adjective + Animal": 5, "Adjective + Being": 5, "Adjective + Genitive": 1, "Color + Being": 3, "Color + Genitive": 3, "Being + of + Genitive": 2, "Being + of the + Genitive": 1, "Animal + of + Genitive": 1, "Adjective + Being + of + Genitive": 2, "Adjective + Animal + of + Genitive": 2};
const approach = {
Number: 1,
Being: 3,
Adjective: 5,
"Color + Animal": 5,
"Adjective + Animal": 5,
"Adjective + Being": 5,
"Adjective + Genitive": 1,
"Color + Being": 3,
"Color + Genitive": 3,
"Being + of + Genitive": 2,
"Being + of the + Genitive": 1,
"Animal + of + Genitive": 1,
"Adjective + Being + of + Genitive": 2,
"Adjective + Animal + of + Genitive": 2
};
// turn weighted array into simple array
const approaches = [];
@ -14,11 +29,254 @@ window.Religions = (function () {
const base = {
number: ["One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve"],
being: ["God", "Goddess", "Lord", "Lady", "Deity", "Creator", "Maker", "Overlord", "Ruler", "Chief", "Master", "Spirit", "Ancestor", "Father", "Forebear", "Forefather", "Mother", "Brother", "Sister", "Elder", "Numen", "Ancient", "Virgin", "Giver", "Council", "Guardian", "Reaper"],
animal: ["Dragon", "Wyvern", "Phoenix", "Unicorn", "Sphinx", "Centaur", "Pegasus", "Kraken", "Basilisk", "Chimera", "Cyclope", "Antelope", "Ape", "Badger", "Bear", "Beaver", "Bison", "Boar", "Buffalo", "Cat", "Cobra", "Crane", "Crocodile", "Crow", "Deer", "Dog", "Eagle", "Elk", "Fox", "Goat", "Goose", "Hare", "Hawk", "Heron", "Horse", "Hyena", "Ibis", "Jackal", "Jaguar", "Lark", "Leopard", "Lion", "Mantis", "Marten", "Moose", "Mule", "Narwhal", "Owl", "Panther", "Rat", "Raven", "Rook", "Scorpion", "Shark", "Sheep", "Snake", "Spider", "Swan", "Tiger", "Turtle", "Viper", "Vulture", "Walrus", "Wolf", "Wolverine", "Worm", "Camel", "Falcon", "Hound", "Ox", "Serpent"],
adjective: ["New", "Good", "High", "Old", "Great", "Big", "Young", "Major", "Strong", "Happy", "Last", "Main", "Huge", "Far", "Beautiful", "Wild", "Fair", "Prime", "Crazy", "Ancient", "Proud", "Secret", "Lucky", "Sad", "Silent", "Latter", "Severe", "Fat", "Holy", "Pure", "Aggressive", "Honest", "Giant", "Mad", "Pregnant", "Distant", "Lost", "Broken", "Blind", "Friendly", "Unknown", "Sleeping", "Slumbering", "Loud", "Hungry", "Wise", "Worried", "Sacred", "Magical", "Superior", "Patient", "Dead", "Deadly", "Peaceful", "Grateful", "Frozen", "Evil", "Scary", "Burning", "Divine", "Bloody", "Dying", "Waking", "Brutal", "Unhappy", "Calm", "Cruel", "Favorable", "Blond", "Explicit", "Disturbing", "Devastating", "Brave", "Sunny", "Troubled", "Flying", "Sustainable", "Marine", "Fatal", "Inherent", "Selected", "Naval", "Cheerful", "Almighty", "Benevolent", "Eternal", "Immutable", "Infallible"],
genitive: ["Day", "Life", "Death", "Night", "Home", "Fog", "Snow", "Winter", "Summer", "Cold", "Springs", "Gates", "Nature", "Thunder", "Lightning", "War", "Ice", "Frost", "Fire", "Doom", "Fate", "Pain", "Heaven", "Justice", "Light", "Love", "Time", "Victory"],
theGenitive: ["World", "Word", "South", "West", "North", "East", "Sun", "Moon", "Peak", "Fall", "Dawn", "Eclipse", "Abyss", "Blood", "Tree", "Earth", "Harvest", "Rainbow", "Sea", "Sky", "Stars", "Storm", "Underworld", "Wild"],
being: [
"God",
"Goddess",
"Lord",
"Lady",
"Deity",
"Creator",
"Maker",
"Overlord",
"Ruler",
"Chief",
"Master",
"Spirit",
"Ancestor",
"Father",
"Forebear",
"Forefather",
"Mother",
"Brother",
"Sister",
"Elder",
"Numen",
"Ancient",
"Virgin",
"Giver",
"Council",
"Guardian",
"Reaper"
],
animal: [
"Dragon",
"Wyvern",
"Phoenix",
"Unicorn",
"Sphinx",
"Centaur",
"Pegasus",
"Kraken",
"Basilisk",
"Chimera",
"Cyclope",
"Antelope",
"Ape",
"Badger",
"Bear",
"Beaver",
"Bison",
"Boar",
"Buffalo",
"Cat",
"Cobra",
"Crane",
"Crocodile",
"Crow",
"Deer",
"Dog",
"Eagle",
"Elk",
"Fox",
"Goat",
"Goose",
"Hare",
"Hawk",
"Heron",
"Horse",
"Hyena",
"Ibis",
"Jackal",
"Jaguar",
"Lark",
"Leopard",
"Lion",
"Mantis",
"Marten",
"Moose",
"Mule",
"Narwhal",
"Owl",
"Panther",
"Rat",
"Raven",
"Rook",
"Scorpion",
"Shark",
"Sheep",
"Snake",
"Spider",
"Swan",
"Tiger",
"Turtle",
"Viper",
"Vulture",
"Walrus",
"Wolf",
"Wolverine",
"Worm",
"Camel",
"Falcon",
"Hound",
"Ox",
"Serpent"
],
adjective: [
"New",
"Good",
"High",
"Old",
"Great",
"Big",
"Young",
"Major",
"Strong",
"Happy",
"Last",
"Main",
"Huge",
"Far",
"Beautiful",
"Wild",
"Fair",
"Prime",
"Crazy",
"Ancient",
"Proud",
"Secret",
"Lucky",
"Sad",
"Silent",
"Latter",
"Severe",
"Fat",
"Holy",
"Pure",
"Aggressive",
"Honest",
"Giant",
"Mad",
"Pregnant",
"Distant",
"Lost",
"Broken",
"Blind",
"Friendly",
"Unknown",
"Sleeping",
"Slumbering",
"Loud",
"Hungry",
"Wise",
"Worried",
"Sacred",
"Magical",
"Superior",
"Patient",
"Dead",
"Deadly",
"Peaceful",
"Grateful",
"Frozen",
"Evil",
"Scary",
"Burning",
"Divine",
"Bloody",
"Dying",
"Waking",
"Brutal",
"Unhappy",
"Calm",
"Cruel",
"Favorable",
"Blond",
"Explicit",
"Disturbing",
"Devastating",
"Brave",
"Sunny",
"Troubled",
"Flying",
"Sustainable",
"Marine",
"Fatal",
"Inherent",
"Selected",
"Naval",
"Cheerful",
"Almighty",
"Benevolent",
"Eternal",
"Immutable",
"Infallible"
],
genitive: [
"Day",
"Life",
"Death",
"Night",
"Home",
"Fog",
"Snow",
"Winter",
"Summer",
"Cold",
"Springs",
"Gates",
"Nature",
"Thunder",
"Lightning",
"War",
"Ice",
"Frost",
"Fire",
"Doom",
"Fate",
"Pain",
"Heaven",
"Justice",
"Light",
"Love",
"Time",
"Victory"
],
theGenitive: [
"World",
"Word",
"South",
"West",
"North",
"East",
"Sun",
"Moon",
"Peak",
"Fall",
"Dawn",
"Eclipse",
"Abyss",
"Blood",
"Tree",
"Earth",
"Harvest",
"Rainbow",
"Sea",
"Sky",
"Stars",
"Storm",
"Underworld",
"Wild"
],
color: ["Dark", "Light", "Bright", "Golden", "White", "Black", "Red", "Pink", "Purple", "Blue", "Green", "Yellow", "Amber", "Orange", "Brown", "Grey"]
};
@ -29,7 +287,16 @@ window.Religions = (function () {
Heresy: {Heresy: 1}
};
const methods = {"Random + type": 3, "Random + ism": 1, "Supreme + ism": 5, "Faith of + Supreme": 5, "Place + ism": 1, "Culture + ism": 2, "Place + ian + type": 6, "Culture + type": 4};
const methods = {
"Random + type": 3,
"Random + ism": 1,
"Supreme + ism": 5,
"Faith of + Supreme": 5,
"Place + ism": 1,
"Culture + ism": 2,
"Place + ian + type": 6,
"Culture + type": 4
};
const types = {
Shamanism: {Beliefs: 3, Shamanism: 2, Spirits: 1},
@ -78,7 +345,10 @@ window.Religions = (function () {
}
const burgs = pack.burgs.filter(b => b.i && !b.removed);
const sorted = burgs.length > +religionsInput.value ? burgs.sort((a, b) => b.population - a.population).map(b => b.cell) : cells.i.filter(i => cells.s[i] > 2).sort((a, b) => cells.s[b] - cells.s[a]);
const sorted =
burgs.length > +religionsInput.value
? burgs.sort((a, b) => b.population - a.population).map(b => b.cell)
: cells.i.filter(i => cells.s[i] > 2).sort((a, b) => cells.s[b] - cells.s[a]);
const religionsTree = d3.quadtree();
const spacing = (graphWidth + graphHeight) / 6 / religionsInput.value; // base min distance between towns
const cultsCount = Math.floor((rand(10, 40) / 100) * religionsInput.value);
@ -160,9 +430,20 @@ window.Religions = (function () {
const name = getCultName("Heresy", center);
const expansionism = gauss(1.2, 0.5, 0, 5);
const color = getMixedColor(r.color, 0.4, 0.2); // "url(#hatch6)";
religions.push({i: religions.length, name, color, culture, type: "Heresy", form: r.form, deity: r.deity, expansion: "global", expansionism, center, origin: r.i});
religions.push({
i: religions.length,
name,
color,
culture,
type: "Heresy",
form: r.form,
deity: r.deity,
expansion: "global",
expansionism,
center,
origin: r.i
});
religionsTree.add([x, y]);
//debug.append("circle").attr("cx", x).attr("cy", y).attr("r", 2).attr("fill", "green");
}
});
@ -195,7 +476,24 @@ window.Religions = (function () {
name,
religions.map(r => r.code)
);
religions.push({i, name, color, culture, type, form: formName, deity, expansion, expansionism: 0, center, cells: 0, area: 0, rural: 0, urban: 0, origin: r, code});
religions.push({
i,
name,
color,
culture,
type,
form: formName,
deity,
expansion,
expansionism: 0,
center,
cells: 0,
area: 0,
rural: 0,
urban: 0,
origin: r,
code
});
cells.religion[center] = i;
};
@ -292,20 +590,18 @@ window.Religions = (function () {
};
function checkCenters() {
const cells = pack.cells,
religions = pack.religions;
const {cells, religions} = pack;
const codes = religions.map(r => r.code);
religions
.filter(r => r.i)
.forEach(r => {
religions.forEach(r => {
if (!r.i) return;
r.code = abbreviate(r.name, codes);
// move religion center if it's not within religion area after expansion
if (cells.religion[r.center] === r.i) return; // in area
const religCells = cells.i.filter(i => cells.religion[i] === r.i);
if (!religCells.length) return; // extinct religion
r.center = religCells.sort((a, b) => b.pop - a.pop)[0];
r.center = religCells.sort((a, b) => cells.pop[b] - cells.pop[a])[0];
});
}

View file

@ -1,377 +1,5 @@
// Functions to save and load the map
"use strict";
// download map as SVG
async function saveSVG() {
TIME && console.time("saveSVG");
const url = await getMapURL("svg");
const link = document.createElement("a");
link.download = getFileName() + ".svg";
link.href = url;
link.click();
tip(`${link.download} is saved. Open "Downloads" screen (crtl + J) to check. You can set image scale in options`, true, "success", 5000);
TIME && console.timeEnd("saveSVG");
}
// download map as PNG
async function savePNG() {
TIME && console.time("savePNG");
const url = await getMapURL("png");
const link = document.createElement("a");
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
canvas.width = svgWidth * pngResolutionInput.value;
canvas.height = svgHeight * pngResolutionInput.value;
const img = new Image();
img.src = url;
img.onload = function () {
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
link.download = getFileName() + ".png";
canvas.toBlob(function (blob) {
link.href = window.URL.createObjectURL(blob);
link.click();
window.setTimeout(function () {
canvas.remove();
window.URL.revokeObjectURL(link.href);
tip(`${link.download} is saved. Open "Downloads" screen (crtl + J) to check. You can set image scale in options`, true, "success", 5000);
}, 1000);
});
};
TIME && console.timeEnd("savePNG");
}
// download map as JPEG
async function saveJPEG() {
TIME && console.time("saveJPEG");
const url = await getMapURL("png");
const canvas = document.createElement("canvas");
canvas.width = svgWidth * pngResolutionInput.value;
canvas.height = svgHeight * pngResolutionInput.value;
const img = new Image();
img.src = url;
img.onload = async function () {
canvas.getContext("2d").drawImage(img, 0, 0, canvas.width, canvas.height);
const quality = Math.min(rn(1 - pngResolutionInput.value / 20, 2), 0.92);
const URL = await canvas.toDataURL("image/jpeg", quality);
const link = document.createElement("a");
link.download = getFileName() + ".jpeg";
link.href = URL;
link.click();
tip(`${link.download} is saved. Open "Downloads" screen (CTRL + J) to check`, true, "success", 7000);
window.setTimeout(() => window.URL.revokeObjectURL(URL), 5000);
};
TIME && console.timeEnd("saveJPEG");
}
// download map as png tiles
async function saveTiles() {
return new Promise(async (resolve, reject) => {
// download schema
const urlSchema = await getMapURL("tiles", {debug: true});
const zip = new JSZip();
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
canvas.width = graphWidth;
canvas.height = graphHeight;
const imgSchema = new Image();
imgSchema.src = urlSchema;
imgSchema.onload = function () {
ctx.drawImage(imgSchema, 0, 0, canvas.width, canvas.height);
canvas.toBlob(blob => zip.file(`fmg_tile_schema.png`, blob));
};
// download tiles
const url = await getMapURL("tiles");
const tilesX = +document.getElementById("tileColsInput").value;
const tilesY = +document.getElementById("tileRowsInput").value;
const scale = +document.getElementById("tileScaleInput").value;
const tileW = (graphWidth / tilesX) | 0;
const tileH = (graphHeight / tilesY) | 0;
const tolesTotal = tilesX * tilesY;
const width = graphWidth * scale;
const height = width * (tileH / tileW);
canvas.width = width;
canvas.height = height;
let loaded = 0;
const img = new Image();
img.src = url;
img.onload = function () {
for (let y = 0, i = 0; y + tileH <= graphHeight; y += tileH) {
for (let x = 0; x + tileW <= graphWidth; x += tileW, i++) {
ctx.drawImage(img, x, y, tileW, tileH, 0, 0, width, height);
const name = `fmg_tile_${i}.png`;
canvas.toBlob(blob => {
zip.file(name, blob);
loaded += 1;
if (loaded === tolesTotal) return downloadZip();
});
}
}
};
function downloadZip() {
const name = `${getFileName()}.zip`;
zip.generateAsync({type: "blob"}).then(blob => {
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = name;
link.click();
link.remove();
setTimeout(() => URL.revokeObjectURL(link.href), 5000);
resolve(true);
});
}
});
}
// parse map svg to object url
async function getMapURL(type, options = {}) {
const {debug = false, globe = false, noLabels = false, noWater = false} = options;
const cloneEl = document.getElementById("map").cloneNode(true); // clone svg
cloneEl.id = "fantasyMap";
document.body.appendChild(cloneEl);
const clone = d3.select(cloneEl);
if (!debug) clone.select("#debug")?.remove();
const cloneDefs = cloneEl.getElementsByTagName("defs")[0];
const svgDefs = document.getElementById("defElements");
const isFirefox = navigator.userAgent.toLowerCase().indexOf("firefox") > -1;
if (isFirefox && type === "mesh") clone.select("#oceanPattern")?.remove();
if (globe) clone.select("#scaleBar")?.remove();
if (noLabels) {
clone.select("#labels #states")?.remove();
clone.select("#labels #burgLabels")?.remove();
clone.select("#icons #burgIcons")?.remove();
}
if (noWater) {
clone.select("#oceanBase").attr("opacity", 0);
clone.select("#oceanPattern").attr("opacity", 0);
}
if (type !== "png") {
// reset transform to show the whole map
clone.attr("width", graphWidth).attr("height", graphHeight);
clone.select("#viewbox").attr("transform", null);
}
if (type === "svg") removeUnusedElements(clone);
if (customization && type === "mesh") updateMeshCells(clone);
inlineStyle(clone);
// remove unused filters
const filters = cloneEl.querySelectorAll("filter");
for (let i = 0; i < filters.length; i++) {
const id = filters[i].id;
if (cloneEl.querySelector("[filter='url(#" + id + ")']")) continue;
if (cloneEl.getAttribute("filter") === "url(#" + id + ")") continue;
filters[i].remove();
}
// remove unused patterns
const patterns = cloneEl.querySelectorAll("pattern");
for (let i = 0; i < patterns.length; i++) {
const id = patterns[i].id;
if (cloneEl.querySelector("[fill='url(#" + id + ")']")) continue;
patterns[i].remove();
}
// remove unused symbols
const symbols = cloneEl.querySelectorAll("symbol");
for (let i = 0; i < symbols.length; i++) {
const id = symbols[i].id;
if (cloneEl.querySelector("use[*|href='#" + id + "']")) continue;
symbols[i].remove();
}
// add displayed emblems
if (layerIsOn("toggleEmblems") && emblems.selectAll("use").size()) {
cloneEl
.getElementById("emblems")
?.querySelectorAll("use")
.forEach(el => {
const href = el.getAttribute("href") || el.getAttribute("xlink:href");
if (!href) return;
const emblem = document.getElementById(href.slice(1));
if (emblem) cloneDefs.append(emblem.cloneNode(true));
});
} else {
cloneDefs.querySelector("#defs-emblems")?.remove();
}
// replace ocean pattern href to base64
if (PRODUCTION && cloneEl.getElementById("oceanicPattern")) {
const el = cloneEl.getElementById("oceanicPattern");
const url = el.getAttribute("href");
await new Promise(resolve => {
getBase64(url, base64 => {
el.setAttribute("href", base64);
resolve();
});
});
}
// add relief icons
if (cloneEl.getElementById("terrain")) {
const uniqueElements = new Set();
const terrainNodes = cloneEl.getElementById("terrain").childNodes;
for (let i = 0; i < terrainNodes.length; i++) {
const href = terrainNodes[i].getAttribute("href") || terrainNodes[i].getAttribute("xlink:href");
uniqueElements.add(href);
}
const defsRelief = svgDefs.getElementById("defs-relief");
for (const terrain of [...uniqueElements]) {
const element = defsRelief.querySelector(terrain);
if (element) cloneDefs.appendChild(element.cloneNode(true));
}
}
// add wind rose
if (cloneEl.getElementById("compass")) {
const rose = svgDefs.getElementById("rose");
if (rose) cloneDefs.appendChild(rose.cloneNode(true));
}
// add port icon
if (cloneEl.getElementById("anchors")) {
const anchor = svgDefs.getElementById("icon-anchor");
if (anchor) cloneDefs.appendChild(anchor.cloneNode(true));
}
// add grid pattern
if (cloneEl.getElementById("gridOverlay")?.hasChildNodes()) {
const type = cloneEl.getElementById("gridOverlay").getAttribute("type");
const pattern = svgDefs.getElementById("pattern_" + type);
if (pattern) cloneDefs.appendChild(pattern.cloneNode(true));
}
if (!cloneEl.getElementById("hatching").children.length) cloneEl.getElementById("hatching")?.remove(); // remove unused hatching group
if (!cloneEl.getElementById("fogging-cont")) cloneEl.getElementById("fog")?.remove(); // remove unused fog
if (!cloneEl.getElementById("regions")) cloneEl.getElementById("statePaths")?.remove(); // removed unused statePaths
if (!cloneEl.getElementById("labels")) cloneEl.getElementById("textPaths")?.remove(); // removed unused textPaths
// add armies style
if (cloneEl.getElementById("armies")) cloneEl.insertAdjacentHTML("afterbegin", "<style>#armies text {stroke: none; fill: #fff; text-shadow: 0 0 4px #000; dominant-baseline: central; text-anchor: middle; font-family: Helvetica; fill-opacity: 1;}#armies text.regimentIcon {font-size: .8em;}</style>");
// add xlink: for href to support svg1.1
if (type === "svg") {
cloneEl.querySelectorAll("[href]").forEach(el => {
const href = el.getAttribute("href");
el.removeAttribute("href");
el.setAttribute("xlink:href", href);
});
}
// TODO: add dataURL for all used fonts
const usedFonts = getUsedFonts(cloneEl);
const fontsToLoad = usedFonts.filter(font => font.src);
if (fontsToLoad.length) {
const dataURLfonts = await loadFontsAsDataURI(fontsToLoad);
const fontFaces = dataURLfonts
.map(({family, src, unicodeRange = "", variant = "normal"}) => {
return `@font-face {font-family: "${family}"; src: ${src}; unicode-range: ${unicodeRange}; font-variant: ${variant};}`;
})
.join("\n");
const style = document.createElement("style");
style.setAttribute("type", "text/css");
style.innerHTML = fontFaces;
cloneEl.querySelector("defs").appendChild(style);
}
clone.remove();
const serialized = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>` + new XMLSerializer().serializeToString(cloneEl);
const blob = new Blob([serialized], {type: "image/svg+xml;charset=utf-8"});
const url = window.URL.createObjectURL(blob);
window.setTimeout(() => window.URL.revokeObjectURL(url), 5000);
return url;
}
// remove hidden g elements and g elements without children to make downloaded svg smaller in size
function removeUnusedElements(clone) {
if (!terrain.selectAll("use").size()) clone.select("#defs-relief")?.remove();
if (markers.style("display") === "none") clone.select("#defs-markers")?.remove();
for (let empty = 1; empty; ) {
empty = 0;
clone.selectAll("g").each(function () {
if (!this.hasChildNodes() || this.style.display === "none" || this.classList.contains("hidden")) {
empty++;
this.remove();
}
if (this.hasAttribute("display") && this.style.display === "inline") this.removeAttribute("display");
});
}
}
function updateMeshCells(clone) {
const data = renderOcean.checked ? grid.cells.i : grid.cells.i.filter(i => grid.cells.h[i] >= 20);
const scheme = getColorScheme();
clone.select("#heights").attr("filter", "url(#blur1)");
clone
.select("#heights")
.selectAll("polygon")
.data(data)
.join("polygon")
.attr("points", d => getGridPolygon(d))
.attr("id", d => "cell" + d)
.attr("stroke", d => getColor(grid.cells.h[d], scheme));
}
// for each g element get inline style
function inlineStyle(clone) {
const emptyG = clone.append("g").node();
const defaultStyles = window.getComputedStyle(emptyG);
clone.selectAll("g, #ruler *, #scaleBar > text").each(function () {
const compStyle = window.getComputedStyle(this);
let style = "";
for (let i = 0; i < compStyle.length; i++) {
const key = compStyle[i];
const value = compStyle.getPropertyValue(key);
// Firefox mask hack
if (key === "mask-image" && value !== defaultStyles.getPropertyValue(key)) {
style += "mask-image: url('#land');";
continue;
}
if (key === "cursor") continue; // cursor should be default
if (this.hasAttribute(key)) continue; // don't add style if there is the same attribute
if (value === defaultStyles.getPropertyValue(key)) continue;
style += key + ":" + value + ";";
}
for (const key in compStyle) {
const value = compStyle.getPropertyValue(key);
if (key === "cursor") continue; // cursor should be default
if (this.hasAttribute(key)) continue; // don't add style if there is the same attribute
if (value === defaultStyles.getPropertyValue(key)) continue;
style += key + ":" + value + ";";
}
if (style != "") this.setAttribute("style", style);
});
emptyG.remove();
}
// functions to save project as .map file
// prepare map data for saving
function getMapData() {
@ -381,7 +9,33 @@ function getMapData() {
const dateString = date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate();
const license = "File can be loaded in azgaar.github.io/Fantasy-Map-Generator";
const params = [version, license, dateString, seed, graphWidth, graphHeight, mapId].join("|");
const settings = [distanceUnitInput.value, distanceScaleInput.value, areaUnit.value, heightUnit.value, heightExponentInput.value, temperatureScale.value, barSizeInput.value, barLabel.value, barBackOpacity.value, barBackColor.value, barPosX.value, barPosY.value, populationRate, urbanization, mapSizeOutput.value, latitudeOutput.value, temperatureEquatorOutput.value, temperaturePoleOutput.value, precOutput.value, JSON.stringify(options), mapName.value, +hideLabels.checked, stylePreset.value, +rescaleLabels.checked].join("|");
const settings = [
distanceUnitInput.value,
distanceScaleInput.value,
areaUnit.value,
heightUnit.value,
heightExponentInput.value,
temperatureScale.value,
barSizeInput.value,
barLabel.value,
barBackOpacity.value,
barBackColor.value,
barPosX.value,
barPosY.value,
populationRate,
urbanization,
mapSizeOutput.value,
latitudeOutput.value,
temperatureEquatorOutput.value,
temperaturePoleOutput.value,
precOutput.value,
JSON.stringify(options),
mapName.value,
+hideLabels.checked,
stylePreset.value,
+rescaleLabels.checked,
urbanDensity
].join("|");
const coords = JSON.stringify(mapCoordinates);
const biomes = [biomesData.color, biomesData.habitability, biomesData.name].join("|");
const notesData = JSON.stringify(notes);
@ -409,6 +63,7 @@ function getMapData() {
const religions = JSON.stringify(pack.religions);
const provinces = JSON.stringify(pack.provinces);
const rivers = JSON.stringify(pack.rivers);
const markers = JSON.stringify(pack.markers);
// store name array only if not the same as default
const defaultNB = Names.getNameBases();
@ -423,7 +78,44 @@ function getMapData() {
const pop = Array.from(pack.cells.pop).map(p => rn(p, 4));
// data format as below
const mapData = [params, settings, coords, biomes, notesData, serializedSVG, gridGeneral, grid.cells.h, grid.cells.prec, grid.cells.f, grid.cells.t, grid.cells.temp, packFeatures, cultures, states, burgs, pack.cells.biome, pack.cells.burg, pack.cells.conf, pack.cells.culture, pack.cells.fl, pop, pack.cells.r, pack.cells.road, pack.cells.s, pack.cells.state, pack.cells.religion, pack.cells.province, pack.cells.crossroad, religions, provinces, namesData, rivers, rulersString, fonts].join("\r\n");
const mapData = [
params,
settings,
coords,
biomes,
notesData,
serializedSVG,
gridGeneral,
grid.cells.h,
grid.cells.prec,
grid.cells.f,
grid.cells.t,
grid.cells.temp,
packFeatures,
cultures,
states,
burgs,
pack.cells.biome,
pack.cells.burg,
pack.cells.conf,
pack.cells.culture,
pack.cells.fl,
pop,
pack.cells.r,
pack.cells.road,
pack.cells.s,
pack.cells.state,
pack.cells.religion,
pack.cells.province,
pack.cells.crossroad,
religions,
provinces,
namesData,
rivers,
rulersString,
fonts,
markers
].join("\r\n");
TIME && console.timeEnd("createMapData");
return mapData;
}
@ -445,7 +137,6 @@ function dowloadMap() {
}
async function saveToDropbox() {
const sharableLinkContainer = document.getElementById("sharableLinkContainer");
if (customization) return tip("Map cannot be saved when edit mode is active, please exit the mode and retry", false, "error");
closeDialogs("#alert");
const mapData = getMapData();
@ -459,124 +150,6 @@ async function saveToDropbox() {
}
}
function saveGeoJSON_Cells() {
const json = {type: "FeatureCollection", features: []};
const cells = pack.cells;
const getPopulation = i => {
const [r, u] = getCellPopulation(i);
return rn(r + u);
};
const getHeight = i => parseInt(getFriendlyHeight([cells.p[i][0], cells.p[i][1]]));
cells.i.forEach(i => {
const coordinates = getCellCoordinates(cells.v[i]);
const height = getHeight(i);
const biome = cells.biome[i];
const type = pack.features[cells.f[i]].type;
const population = getPopulation(i);
const state = cells.state[i];
const province = cells.province[i];
const culture = cells.culture[i];
const religion = cells.religion[i];
const neighbors = cells.c[i];
const properties = {id: i, height, biome, type, population, state, province, culture, religion, neighbors};
const feature = {type: "Feature", geometry: {type: "Polygon", coordinates}, properties};
json.features.push(feature);
});
const name = getFileName("Cells") + ".geojson";
downloadFile(JSON.stringify(json), name, "application/json");
}
function saveGeoJSON_Routes() {
const json = {type: "FeatureCollection", features: []};
routes.selectAll("g > path").each(function () {
const coordinates = getRoutePoints(this);
const id = this.id;
const type = this.parentElement.id;
const feature = {type: "Feature", geometry: {type: "LineString", coordinates}, properties: {id, type}};
json.features.push(feature);
});
const name = getFileName("Routes") + ".geojson";
downloadFile(JSON.stringify(json), name, "application/json");
}
function saveGeoJSON_Rivers() {
const json = {type: "FeatureCollection", features: []};
rivers.selectAll("path").each(function () {
const coordinates = getRiverPoints(this);
const id = this.id;
const width = +this.dataset.increment;
const increment = +this.dataset.increment;
const river = pack.rivers.find(r => r.i === +id.slice(5));
const name = river ? river.name : "";
const type = river ? river.type : "";
const i = river ? river.i : "";
const basin = river ? river.basin : "";
const feature = {type: "Feature", geometry: {type: "LineString", coordinates}, properties: {id, i, basin, name, type, width, increment}};
json.features.push(feature);
});
const name = getFileName("Rivers") + ".geojson";
downloadFile(JSON.stringify(json), name, "application/json");
}
function saveGeoJSON_Markers() {
const json = {type: "FeatureCollection", features: []};
markers.selectAll("use").each(function () {
const coordinates = getQGIScoordinates(this.dataset.x, this.dataset.y);
const id = this.id;
const type = this.dataset.id.substring(1);
const icon = document.getElementById(type).textContent;
const note = notes.length ? notes.find(note => note.id === this.id) : null;
const name = note ? note.name : "";
const legend = note ? note.legend : "";
const feature = {type: "Feature", geometry: {type: "Point", coordinates}, properties: {id, type, icon, name, legend}};
json.features.push(feature);
});
const name = getFileName("Markers") + ".geojson";
downloadFile(JSON.stringify(json), name, "application/json");
}
function getCellCoordinates(vertices) {
const p = pack.vertices.p;
const coordinates = vertices.map(n => getQGIScoordinates(p[n][0], p[n][1]));
return [coordinates.concat([coordinates[0]])];
}
function getRoutePoints(node) {
let points = [];
const l = node.getTotalLength();
const increment = l / Math.ceil(l / 2);
for (let i = 0; i <= l; i += increment) {
const p = node.getPointAtLength(i);
points.push(getQGIScoordinates(p.x, p.y));
}
return points;
}
function getRiverPoints(node) {
let points = [];
const l = node.getTotalLength() / 2; // half-length
const increment = 0.25; // defines density of points
for (let i = l, c = i; i >= 0; i -= increment, c += increment) {
const p1 = node.getPointAtLength(i);
const p2 = node.getPointAtLength(c);
const [x, y] = getQGIScoordinates((p1.x + p2.x) / 2, (p1.y + p2.y) / 2);
points.push([x, y]);
}
return points;
}
function quickSave() {
if (customization) return tip("Map cannot be saved when edit mode is active, please exit the mode and retry", false, "error");
@ -588,15 +161,24 @@ function quickSave() {
const saveReminder = function () {
if (localStorage.getItem("noReminder")) return;
const message = ["Please don't forget to save your work as a .map file", "Please remember to save work as a .map file", "Saving in .map format will ensure your data won't be lost in case of issues", "Safety is number one priority. Please save the map", "Don't forget to save your map on a regular basis!", "Just a gentle reminder for you to save the map", "Please don't forget to save your progress (saving as .map is the best option)", "Don't want to be reminded about need to save? Press CTRL+Q"];
const message = [
"Please don't forget to save your work as a .map file",
"Please remember to save work as a .map file",
"Saving in .map format will ensure your data won't be lost in case of issues",
"Safety is number one priority. Please save the map",
"Don't forget to save your map on a regular basis!",
"Just a gentle reminder for you to save the map",
"Please don't forget to save your progress (saving as .map is the best option)",
"Don't want to be reminded about need to save? Press CTRL+Q"
];
const interval = 15 * 60 * 1000; // remind every 15 minutes
saveReminder.reminder = setInterval(() => {
if (customization) return;
tip(ra(message), true, "warn", 2500);
}, 1e6);
}, interval);
saveReminder.status = 1;
};
saveReminder();
function toggleSaveReminder() {

View file

@ -1,20 +1,43 @@
"use strict";
window.ThreeD = (function () {
// set default options
const options = {scale: 50, lightness: 0.7, shadow: 0.5, sun: {x: 100, y: 600, z: 1000}, rotateMesh: 0, rotateGlobe: 0.5, skyColor: "#9ecef5", waterColor: "#466eab", extendedWater: 0, labels3d: 0, resolution: 2};
const options = {
scale: 50,
lightness: 0.7,
shadow: 0.5,
sun: {x: 100, y: 600, z: 1000},
rotateMesh: 0,
rotateGlobe: 0.5,
skyColor: "#9ecef5",
waterColor: "#466eab",
extendedWater: 0,
labels3d: 0,
resolution: 2
};
// set variables
let Renderer, scene, camera, controls, animationFrame, material, texture, geometry, mesh, ambientLight, spotLight, waterPlane, waterMaterial, waterMesh, raycaster;
const drawCtx = document.createElement("canvas").getContext("2d");
const drawSVG = document.createElementNS("http://www.w3.org/2000/svg", "svg");
document.body.appendChild(drawSVG);
let Renderer,
scene,
camera,
controls,
animationFrame,
material,
texture,
geometry,
mesh,
ambientLight,
spotLight,
waterPlane,
waterMaterial,
waterMesh,
raycaster;
let labels = [];
let icons = [];
let lines = [];
const context2d = document.createElement("canvas").getContext("2d");
// initiate 3d scene
const create = async function (canvas, type = "viewMesh") {
options.isOn = true;
@ -210,16 +233,16 @@ window.ThreeD = (function () {
}
async function createTextLabel({text, font, size, color, quality}) {
drawCtx.font = `${size * quality}px ${font}`;
drawCtx.canvas.width = drawCtx.measureText(text).width;
drawCtx.canvas.height = size * quality * 1.25; // 25% margin as text can overflow the font size
drawCtx.clearRect(0, 0, drawCtx.canvas.width, drawCtx.canvas.height);
context2d.font = `${size * quality}px ${font}`;
context2d.canvas.width = context2d.measureText(text).width;
context2d.canvas.height = size * quality * 1.25; // 25% margin as text can overflow the font size
context2d.clearRect(0, 0, context2d.canvas.width, context2d.canvas.height);
drawCtx.font = `${size * quality}px ${font}`;
drawCtx.fillStyle = color;
drawCtx.fillText(text, 0, size * quality);
context2d.font = `${size * quality}px ${font}`;
context2d.fillStyle = color;
context2d.fillText(text, 0, size * quality);
return textureToSprite(drawCtx.canvas.toDataURL(), drawCtx.canvas.width / quality, drawCtx.canvas.height / quality);
return textureToSprite(context2d.canvas.toDataURL(), context2d.canvas.width / quality, context2d.canvas.height / quality);
}
function get3dCoords(baseX, baseY) {
@ -368,7 +391,8 @@ window.ThreeD = (function () {
async function createMesh(width, height, segmentsX, segmentsY) {
const mapOptions = {
noLabels: options.labels3d,
noWater: options.extendedWater
noWater: options.extendedWater,
fullMap: true
};
const url = await getMapURL("mesh", mapOptions);
window.setTimeout(() => window.URL.revokeObjectURL(url), 5000);
@ -422,7 +446,8 @@ window.ThreeD = (function () {
if (texture) texture.dispose();
const mapOptions = {
noLabels: options.labels3d,
noWater: options.extendedWater
noWater: options.extendedWater,
fullMap: true
};
const url = await getMapURL("mesh", mapOptions);
window.setTimeout(() => window.URL.revokeObjectURL(url), 4000);
@ -503,7 +528,7 @@ window.ThreeD = (function () {
material.map = texture;
if (addMesh) addGlobe3dMesh();
};
img2.src = await getMapURL("mesh", {globe: true});
img2.src = await getMapURL("mesh", {globe: true, fullMap: true});
}
async function getOBJ() {
@ -578,5 +603,21 @@ window.ThreeD = (function () {
});
}
return {create, redraw, update, stop, options, setScale, setLightness, setSun, setRotation, toggleLabels, toggleSky, setResolution, setColors, saveScreenshot, saveOBJ};
return {
create,
redraw,
update,
stop,
options,
setScale,
setLightness,
setSun,
setRotation,
toggleLabels,
toggleSky,
setResolution,
setColors,
saveScreenshot,
saveOBJ
};
})();

View file

@ -330,7 +330,7 @@ class Battle {
}
getInitialMorale() {
const powerFee = diff => Math.min(Math.max(100 - diff ** 1.5 * 10 + 10, 50), 100);
const powerFee = diff => minmax(100 - diff ** 1.5 * 10 + 10, 50, 100);
const distanceFee = dist => Math.min(d3.mean(dist) / 50, 15);
const powerDiff = this.defenders.power / this.attackers.power;
this.attackers.morale = powerFee(powerDiff) - distanceFee(this.attackers.distances);
@ -677,7 +677,22 @@ class Battle {
if (note) {
const status = side === "attackers" ? battleStatus[0] : battleStatus[1];
const losses = r.a ? Math.abs(d3.sum(Object.values(r.casualties))) / r.a : 1;
const regStatus = losses === 1 ? "is destroyed" : losses > 0.8 ? "is almost completely destroyed" : losses > 0.5 ? "suffered terrible losses" : losses > 0.3 ? "suffered severe losses" : losses > 0.2 ? "suffered heavy losses" : losses > 0.05 ? "suffered significant losses" : losses > 0 ? "suffered unsignificant losses" : "left the battle without loss";
const regStatus =
losses === 1
? "is destroyed"
: losses > 0.8
? "is almost completely destroyed"
: losses > 0.5
? "suffered terrible losses"
: losses > 0.3
? "suffered severe losses"
: losses > 0.2
? "suffered heavy losses"
: losses > 0.05
? "suffered significant losses"
: losses > 0
? "suffered unsignificant losses"
: "left the battle without loss";
const casualties = Object.keys(r.casualties)
.map(t => (r.casualties[t] ? `${Math.abs(r.casualties[t])} ${t}` : null))
.filter(c => c);
@ -691,40 +706,32 @@ class Battle {
armies.select(`g#${id} > text`).text(Military.getTotal(r)); // update reg box
}
const i = last(pack.markers)?.i + 1 || 0;
{
// append battlefield marker
void (function addMarkerSymbol() {
if (svg.select("#defs-markers").select("#marker_battlefield").size()) return;
const symbol = svg.select("#defs-markers").append("symbol").attr("id", "marker_battlefield").attr("viewBox", "0 0 30 30");
symbol.append("path").attr("d", "M6,19 l9,10 L24,19").attr("fill", "#000000").attr("stroke", "none");
symbol.append("circle").attr("cx", 15).attr("cy", 15).attr("r", 10).attr("fill", "#ffffff").attr("stroke", "#000000").attr("stroke-width", 1);
symbol.append("text").attr("x", "50%").attr("y", "52%").attr("fill", "#000000").attr("stroke", "#3200ff").attr("stroke-width", 0).attr("font-size", "12px").attr("dominant-baseline", "central").text("⚔️");
})();
const marker = {i, x: this.x, y: this.y, cell: this.cell, icon: "⚔️", type: "battlefields", dy: 52};
pack.markers.push(marker);
const markerHTML = drawMarker(marker);
document.getElementById("markers").insertAdjacentHTML("beforeend", markerHTML);
}
const getSide = (regs, n) => (regs.length > 1 ? `${n ? "regiments" : "forces"} of ${list([...new Set(regs.map(r => pack.states[r.state].name))])}` : getAdjective(pack.states[regs[0].state].name) + " " + regs[0].name);
const getSide = (regs, n) =>
regs.length > 1
? `${n ? "regiments" : "forces"} of ${list([...new Set(regs.map(r => pack.states[r.state].name))])}`
: getAdjective(pack.states[regs[0].state].name) + " " + regs[0].name;
const getLosses = casualties => Math.min(rn(casualties * 100), 100);
const status = battleStatus[+P(0.7)];
const result = `The ${this.getTypeName(this.type)} ended in ${status}`;
const legend = `${this.name} took place in ${options.year} ${options.eraShort}. It was fought between ${getSide(this.attackers.regiments, 1)} and ${getSide(this.defenders.regiments, 0)}. ${result}.
const legend = `${this.name} took place in ${options.year} ${options.eraShort}. It was fought between ${getSide(this.attackers.regiments, 1)} and ${getSide(
this.defenders.regiments,
0
)}. ${result}.
\r\nAttackers losses: ${getLosses(this.attackers.casualties)}%, defenders losses: ${getLosses(this.defenders.casualties)}%`;
const id = getNextId("markerElement");
notes.push({id, name: this.name, legend});
notes.push({id: `marker${i}`, name: this.name, legend});
tip(`${this.name} is over. ${result}`, true, "success", 4000);
markers
.append("use")
.attr("id", id)
.attr("xlink:href", "#marker_battlefield")
.attr("data-id", "#marker_battlefield")
.attr("data-x", this.x)
.attr("data-y", this.y)
.attr("x", this.x - 15)
.attr("y", this.y - 30)
.attr("data-size", 1)
.attr("width", 30)
.attr("height", 30);
$("#battleScreen").dialog("destroy");
this.cleanData();
}

View file

@ -94,10 +94,14 @@ function editBiomes() {
lines += `<div class="states biomes" data-id="${i}" data-name="${b.name[i]}" data-habitability="${b.habitability[i]}"
data-cells=${b.cells[i]} data-area=${area} data-population=${population} data-color=${b.color[i]}>
<svg data-tip="Biomes fill style. Click to change" width=".9em" height=".9em" style="margin-bottom:-1px"><rect x="0" y="0" width="100%" height="100%" fill="${b.color[i]}" class="fillRect pointer"></svg>
<svg data-tip="Biomes fill style. Click to change" width=".9em" height=".9em" style="margin-bottom:-1px"><rect x="0" y="0" width="100%" height="100%" fill="${
b.color[i]
}" class="fillRect pointer"></svg>
<input data-tip="Biome name. Click and type to change" class="biomeName" value="${b.name[i]}" autocorrect="off" spellcheck="false">
<span data-tip="Biome habitability percent" class="hide">%</span>
<input data-tip="Biome habitability percent. Click and set new value to change" type="number" min=0 max=9999 class="biomeHabitability hide" value=${b.habitability[i]}>
<input data-tip="Biome habitability percent. Click and set new value to change" type="number" min=0 max=9999 class="biomeHabitability hide" value=${
b.habitability[i]
}>
<span data-tip="Cells count" class="icon-check-empty hide"></span>
<div data-tip="Cells count" class="biomeCells hide">${b.cells[i]}</div>
<span data-tip="Biome area" style="padding-right: 4px" class="icon-map-o hide"></span>
@ -189,41 +193,27 @@ function editBiomes() {
}
function openWiki(el) {
const name = el.parentNode.dataset.name;
if (name === "Custom" || !name) {
tip("Please provide a biome name", false, "error");
return;
}
const wiki = "https://en.wikipedia.org/wiki/";
const biomeName = el.parentNode.dataset.name;
if (biomeName === "Custom" || !biomeName) return tip("Please fill in the biome name", false, "error");
switch (name) {
case "Hot desert":
openURL(wiki + "Desert_climate#Hot_desert_climates");
case "Cold desert":
openURL(wiki + "Desert_climate#Cold_desert_climates");
case "Savanna":
openURL(wiki + "Tropical_and_subtropical_grasslands,_savannas,_and_shrublands");
case "Grassland":
openURL(wiki + "Temperate_grasslands,_savannas,_and_shrublands");
case "Tropical seasonal forest":
openURL(wiki + "Seasonal_tropical_forest");
case "Temperate deciduous forest":
openURL(wiki + "Temperate_deciduous_forest");
case "Tropical rainforest":
openURL(wiki + "Tropical_rainforest");
case "Temperate rainforest":
openURL(wiki + "Temperate_rainforest");
case "Taiga":
openURL(wiki + "Taiga");
case "Tundra":
openURL(wiki + "Tundra");
case "Glacier":
openURL(wiki + "Glacier");
case "Wetland":
openURL(wiki + "Wetland");
default:
openURL(`https://en.wikipedia.org/w/index.php?search=${name}`);
}
const wikiBase = "https://en.wikipedia.org/wiki/";
const pages = {
"Hot desert": "Desert_climate#Hot_desert_climates",
"Cold desert": "Desert_climate#Cold_desert_climates",
Savanna: "Tropical_and_subtropical_grasslands,_savannas,_and_shrublands",
Grassland: "Temperate_grasslands,_savannas,_and_shrublands",
"Tropical seasonal forest": "Seasonal_tropical_forest",
"Temperate deciduous forest": "Temperate_deciduous_forest",
"Tropical rainforest": "Tropical_rainforest",
"Temperate rainforest": "Temperate_rainforest",
Taiga: "Taiga",
Tundra: "Tundra",
Glacier: "Glacier",
Wetland: "Wetland"
};
const customBiomeLink = `https://en.wikipedia.org/w/index.php?search=${biomeName}`;
const link = pages[biomeName] ? wikiBase + pages[biomeName] : customBiomeLink;
openURL(link);
}
function toggleLegend() {
@ -343,7 +333,11 @@ function editBiomes() {
$("#biomesEditor").dialog({position: {my: "right top", at: "right-10 top+10", of: "svg"}});
tip("Click on biome to select, drag the circle to change biome", true);
viewbox.style("cursor", "crosshair").on("click", selectBiomeOnMapClick).call(d3.drag().on("start", dragBiomeBrush)).on("touchmove mousemove", moveBiomeBrush);
viewbox
.style("cursor", "crosshair")
.on("click", selectBiomeOnMapClick)
.call(d3.drag().on("start", dragBiomeBrush))
.on("touchmove mousemove", moveBiomeBrush);
}
function selectBiomeOnLineClick(line) {

View file

@ -10,15 +10,11 @@ function editBurg(id) {
burgLabels.selectAll("text").call(d3.drag().on("start", dragBurgLabel)).classed("draggable", true);
updateBurgValues();
const my = id || d3.event.target.tagName === "text" ? "center bottom-20" : "center top+20";
const at = id ? "center" : d3.event.target.tagName === "text" ? "top" : "bottom";
const of = id ? "svg" : d3.event.target;
$("#burgEditor").dialog({
title: "Edit Burg",
resizable: false,
close: closeBurgEditor,
position: {my, at, of, collision: "fit"}
position: {my: "left top", at: "left+10 top+10", of: "svg", collision: "fit"}
});
if (modules.editBurg) return;
@ -39,6 +35,8 @@ function editBurg(id) {
document.getElementById("burgNameReCulture").addEventListener("click", generateNameCulture);
document.getElementById("burgPopulation").addEventListener("change", changePopulation);
burgBody.querySelectorAll(".burgFeature").forEach(el => el.addEventListener("click", toggleFeature));
document.getElementById("mfcgBurgSeed").addEventListener("change", changeSeed);
document.getElementById("regenerateMFCGBurgSeed").addEventListener("click", randomizeSeed);
document.getElementById("burgStyleShow").addEventListener("click", showStyleSection);
document.getElementById("burgStyleHide").addEventListener("click", hideStyleSection);
@ -46,12 +44,12 @@ function editBurg(id) {
document.getElementById("burgEditIconStyle").addEventListener("click", editGroupIconStyle);
document.getElementById("burgEditAnchorStyle").addEventListener("click", editGroupAnchorStyle);
document.getElementById("burgSeeInMFCG").addEventListener("click", openInMFCG);
document.getElementById("burgEmblem").addEventListener("click", openEmblemEdit);
document.getElementById("burgToggleMFCGMap").addEventListener("click", toggleMFCGMap);
document.getElementById("burgEditEmblem").addEventListener("click", openEmblemEdit);
document.getElementById("burgRelocate").addEventListener("click", toggleRelocateBurg);
document.getElementById("burglLegend").addEventListener("click", editBurgLegend);
document.getElementById("burgLock").addEventListener("click", toggleBurgLockButton);
document.getElementById("burgLock").addEventListener("mouseover", showBurgELockTip);
document.getElementById("burgRemove").addEventListener("click", removeSelectedBurg);
function updateBurgValues() {
@ -110,6 +108,14 @@ function editBurg(id) {
const coaID = "burgCOA" + id;
COArenderer.trigger(coaID, b.coa);
document.getElementById("burgEmblem").setAttribute("href", "#" + coaID);
if (options.showMFCGMap) {
document.getElementById("mfcgPreviewSection").style.display = "block";
updateMFCGFrame(b);
document.getElementById("mfcgBurgSeed").value = getBurgSeed(b);
} else {
document.getElementById("mfcgPreviewSection").style.display = "none";
}
}
// in °C, array from -1 °C; source: https://en.wikipedia.org/wiki/List_of_cities_by_average_temperature
@ -275,12 +281,12 @@ function editBurg(id) {
const capital = burgsToRemove.length < burgsInGroup.length;
alertMessage.innerHTML = `Are you sure you want to remove
${basic || capital ? "all unlocked elements in the group" : "the entire burg group"}?
${basic || capital ? "all unlocked elements in the burg group" : "the entire burg group"}?
<br>Please note that capital or locked burgs will not be deleted.
<br><br>Burgs to be removed: ${burgsToRemove.length}`;
$("#alert").dialog({
resizable: false,
title: "Remove route group",
title: "Remove burg group",
buttons: {
Remove: function () {
$(this).dialog("close");
@ -372,11 +378,6 @@ function editBurg(id) {
}
}
function showBurgELockTip() {
const id = +elSelected.attr("data-id");
showBurgLockTip(id);
}
function showStyleSection() {
document.querySelectorAll("#burgBottom > button").forEach(el => (el.style.display = "none"));
document.getElementById("burgStyleSection").style.display = "inline-block";
@ -402,59 +403,27 @@ function editBurg(id) {
editStyle("anchors", g);
}
function openInMFCG(event) {
const id = elSelected.attr("data-id");
function updateMFCGFrame(burg) {
const mfcgURL = getMFCGlink(burg);
document.getElementById("mfcgPreview").setAttribute("src", mfcgURL);
document.getElementById("mfcgLink").setAttribute("href", mfcgURL);
}
function changeSeed() {
const id = +elSelected.attr("data-id");
const burg = pack.burgs[id];
const defSeed = +(seed + id.padStart(4, 0));
if (isCtrlClick(event)) {
prompt(
`Please provide a Medieval Fantasy City Generator seed.
Seed should be a number. Default seed is FMG map seed + burg id padded to 4 chars with zeros (${defSeed}).
Please note that if seed is custom, "Overworld" button from MFCG will open a different map`,
{default: burg.MFCG || defSeed, step: 1, min: 1, max: 1e13 - 1},
v => {
burg.MFCG = v;
openMFCG(v);
}
);
} else openMFCG();
function openMFCG(seed) {
if (!seed && burg.MFCGlink) {
openURL(burg.MFCGlink);
return;
}
const cells = pack.cells;
const name = elSelected.text();
const size = Math.max(Math.min(rn(burg.population), 100), 6); // to be removed once change on MFDC is done
const population = rn(burg.population * populationRate * urbanization);
const s = burg.MFCG || defSeed;
const cell = burg.cell;
const hub = +cells.road[cell] > 50;
const river = cells.r[cell] ? 1 : 0;
const coast = +burg.port;
const citadel = +burg.citadel;
const walls = +burg.walls;
const plaza = +burg.plaza;
const temple = +burg.temple;
const shanty = +burg.shanty;
const sea = coast && cells.haven[burg.cell] ? getSeaDirections(burg.cell) : "";
function getSeaDirections(i) {
const p1 = cells.p[i];
const p2 = cells.p[cells.haven[i]];
let deg = (Math.atan2(p2[1] - p1[1], p2[0] - p1[0]) * 180) / Math.PI - 90;
if (deg < 0) deg += 360;
const norm = rn(normalize(deg, 0, 360) * 2, 2); // 0 = south, 0.5 = west, 1 = north, 1.5 = east
return "&sea=" + norm;
const burgSeed = +this.value;
burg.MFCG = burgSeed;
updateMFCGFrame(burg);
}
const site = "http://fantasycities.watabou.ru/?random=0&continuous=0";
const url = `${site}&name=${name}&population=${population}&size=${size}&seed=${s}&hub=${hub}&river=${river}&coast=${coast}&citadel=${citadel}&plaza=${plaza}&temple=${temple}&walls=${walls}&shantytown=${shanty}${sea}`;
openURL(url);
}
function randomizeSeed() {
const id = +elSelected.attr("data-id");
const burg = pack.burgs[id];
const burgSeed = rand(1e9 - 1);
burg.MFCG = burgSeed;
updateMFCGFrame(burg);
document.getElementById("mfcgBurgSeed").value = burgSeed;
}
function openEmblemEdit() {
@ -463,6 +432,12 @@ function editBurg(id) {
editEmblem("burg", "burgCOA" + id, burg);
}
function toggleMFCGMap() {
options.showMFCGMap = !options.showMFCGMap;
document.getElementById("mfcgPreviewSection").style.display = options.showMFCGMap ? "block" : "none";
document.getElementById("burgToggleMFCGMap").className = options.showMFCGMap ? "icon-map" : "icon-map-o";
}
function toggleRelocateBurg() {
const toggler = document.getElementById("toggleCells");
document.getElementById("burgRelocate").classList.toggle("pressed");

View file

@ -34,6 +34,7 @@ function overviewBurgs() {
uploadFile(this, importBurgNames);
});
document.getElementById("burgsRemoveAll").addEventListener("click", triggerAllBurgsRemove);
document.getElementById("burgsInvertLock").addEventListener("click", invertLock);
function refreshBurgsEditor() {
updateFilter();
@ -79,20 +80,26 @@ function overviewBurgs() {
const province = prov ? pack.provinces[prov].name : "";
const culture = pack.cultures[b.culture].name;
lines += `<div class="states" data-id=${b.i} data-name="${b.name}" data-state="${state}" data-province="${province}" data-culture="${culture}" data-population=${population} data-type="${type}">
lines += `<div class="states" data-id=${b.i} data-name="${
b.name
}" data-state="${state}" data-province="${province}" data-culture="${culture}" data-population=${population} data-type="${type}">
<span data-tip="Click to zoom into view" class="icon-dot-circled pointer"></span>
<input data-tip="Burg name. Click and type to change" class="burgName" value="${b.name}" autocorrect="off" spellcheck="false">
<input data-tip="Burg province" class="burgState" value="${province}" disabled>
<input data-tip="Burg state" class="burgState" value="${state}" disabled>
<select data-tip="Dominant culture. Click to change burg culture (to change cell cultrure use Cultures Editor)" class="stateCulture">${getCultureOptions(b.culture)}</select>
<select data-tip="Dominant culture. Click to change burg culture (to change cell cultrure use Cultures Editor)" class="stateCulture">${getCultureOptions(
b.culture
)}</select>
<span data-tip="Burg population" class="icon-male"></span>
<input data-tip="Burg population. Type to change" class="burgPopulation" value=${si(population)}>
<div class="burgType">
<span data-tip="${b.capital ? " This burg is a state capital" : "Click to assign a capital status"}" class="icon-star-empty${b.capital ? "" : " inactive pointer"}"></span>
<span data-tip="${b.capital ? " This burg is a state capital" : "Click to assign a capital status"}" class="icon-star-empty${
b.capital ? "" : " inactive pointer"
}"></span>
<span data-tip="Click to toggle port status" class="icon-anchor pointer${b.port ? "" : " inactive"}" style="font-size:.9em"></span>
</div>
<span data-tip="Edit burg" class="icon-pencil"></span>
<span class="locks pointer ${b.lock ? "icon-lock" : "icon-lock-open inactive"}"></span>
<span class="locks pointer ${b.lock ? "icon-lock" : "icon-lock-open inactive"}" onmouseover="showElementLockTip(event)"></span>
<span data-tip="Remove burg" class="icon-trash-empty"></span>
</div>`;
}
@ -112,7 +119,6 @@ function overviewBurgs() {
body.querySelectorAll("div > span.icon-star-empty").forEach(el => el.addEventListener("click", toggleCapitalStatus));
body.querySelectorAll("div > span.icon-anchor").forEach(el => el.addEventListener("click", togglePortStatus));
body.querySelectorAll("div > span.locks").forEach(el => el.addEventListener("click", toggleBurgLockStatus));
body.querySelectorAll("div > span.locks").forEach(el => el.addEventListener("mouseover", showBurgOLockTip));
body.querySelectorAll("div > span.icon-pencil").forEach(el => el.addEventListener("click", openBurgEditor));
body.querySelectorAll("div > span.icon-trash-empty").forEach(el => el.addEventListener("click", triggerBurgRemove));
@ -147,8 +153,8 @@ function overviewBurgs() {
function zoomIntoBurg() {
const burg = +this.parentNode.dataset.id;
const label = document.querySelector("#burgLabels [data-id='" + burg + "']");
const x = +label.getAttribute("x"),
y = +label.getAttribute("y");
const x = +label.getAttribute("x");
const y = +label.getAttribute("y");
zoomTo(x, y, 8, 2000);
}
@ -202,11 +208,6 @@ function overviewBurgs() {
}
}
function showBurgOLockTip() {
const burg = +this.parentNode.dataset.id;
showBurgLockTip(burg);
}
function openBurgEditor() {
const burg = +this.parentNode.dataset.id;
editBurg(burg);
@ -214,24 +215,15 @@ function overviewBurgs() {
function triggerBurgRemove() {
const burg = +this.parentNode.dataset.id;
if (pack.burgs[burg].capital) {
tip("You cannot remove the capital. Please change the capital first", false, "error");
return;
}
if (pack.burgs[burg].capital) return tip("You cannot remove the capital. Please change the capital first", false, "error");
alertMessage.innerHTML = "Are you sure you want to remove the burg?";
$("#alert").dialog({
resizable: false,
confirmationDialog({
title: "Remove burg",
buttons: {
Remove: function () {
$(this).dialog("close");
message: "Are you sure you want to remove the burg? This actiove cannot be reverted",
confirm: "Remove",
onConfirm: () => {
removeBurg(burg);
burgsOverviewAddLines();
},
Cancel: function () {
$(this).dialog("close");
}
}
});
}
@ -239,22 +231,19 @@ function overviewBurgs() {
function regenerateNames() {
body.querySelectorAll(":scope > div").forEach(function (el) {
const burg = +el.dataset.id;
//if (pack.burgs[burg].lock) return;
if (pack.burgs[burg].lock) return;
const culture = pack.burgs[burg].culture;
const name = Names.getCulture(culture);
if (!pack.burgs[burg].lock) {
el.querySelector(".burgName").value = name;
pack.burgs[burg].name = el.dataset.name = name;
burgLabels.select("[data-id='" + burg + "']").text(name);
}
});
}
function enterAddBurgMode() {
if (this.classList.contains("pressed")) {
exitAddBurgMode();
return;
}
if (this.classList.contains("pressed")) return exitAddBurgMode();
customization = 3;
this.classList.add("pressed");
tip("Click on the map to create a new burg. Hold Shift to add multiple", true, "warn");
@ -264,14 +253,9 @@ function overviewBurgs() {
function addBurgOnClick() {
const point = d3.mouse(this);
const cell = findCell(point[0], point[1]);
if (pack.cells.h[cell] < 20) {
tip("You cannot place state into the water. Please click on a land cell", false, "error");
return;
}
if (pack.cells.burg[cell]) {
tip("There is already a burg in this cell. Please select a free cell", false, "error");
return;
}
if (pack.cells.h[cell] < 20) return tip("You cannot place state into the water. Please click on a land cell", false, "error");
if (pack.cells.burg[cell]) return tip("There is already a burg in this cell. Please select a free cell", false, "error");
addBurg(point); // add new burg
if (d3.event.shiftKey === false) {
@ -295,6 +279,7 @@ function overviewBurgs() {
const name = s.fullName ? s.fullName : s.name;
return {id: s.i, state: s.i ? 0 : null, color, name};
});
const burgs = pack.burgs
.filter(b => b.i && !b.removed)
.map(b => {
@ -306,6 +291,7 @@ function overviewBurgs() {
return {id, i: b.i, state: b.state, culture: b.culture, province, parent, name: b.name, population, capital, x: b.x, y: b.y};
});
const data = states.concat(burgs);
if (data.length < 2) return tip("No burgs to show", false, "error");
const root = d3
.stratify()
@ -313,8 +299,8 @@ function overviewBurgs() {
.sum(d => d.population)
.sort((a, b) => b.value - a.value);
const width = 150 + 200 * uiSizeOutput.value,
height = 150 + 200 * uiSizeOutput.value;
const width = 150 + 200 * uiSizeOutput.value;
const height = 150 + 200 * uiSizeOutput.value;
const margin = {top: 0, right: -50, bottom: -10, left: -50};
const w = width - margin.left - margin.right;
const h = height - margin.top - margin.bottom;
@ -413,7 +399,14 @@ function overviewBurgs() {
if (this.value === "provinces") return d.province;
};
const base = this.value === "states" ? getStatesData() : this.value === "cultures" ? getCulturesData() : this.value === "parent" ? getParentData() : getProvincesData();
const mapping = {
states: getStatesData,
cultures: getCulturesData,
parent: getParentData,
provinces: getProvincesData
};
const base = mapping[this.value]();
burgs.forEach(b => (b.id = b.i + base.length - 1));
const data = base.concat(burgs);
@ -440,14 +433,15 @@ function overviewBurgs() {
width: fitContent(),
position: {my: "left bottom", at: "left+10 bottom-10", of: "svg"},
buttons: {},
close: () => {
alertMessage.innerHTML = "";
}
close: () => (alertMessage.innerHTML = "")
});
}
function downloadBurgsData() {
let data = "Id,Burg,Province,Province Full Name,State,State Full Name,Culture,Religion,Population,Longitude,Latitude,Elevation (" + heightUnit.value + "),Capital,Port,Citadel,Walls,Plaza,Temple,Shanty Town\n"; // headers
let data = `Id,Burg,Province,Province Full Name,State,State Full Name,Culture,Religion,Population,Latitude,Longitude,Elevation (${heightUnit.value}),Capital,Port,Citadel,Walls,Plaza,Temple,Shanty Town`; // headers
if (options.showMFCGMap) data += `,City Generator Link`;
data += "\n";
const valid = pack.burgs.filter(b => b.i && !b.removed); // all valid burgs
valid.forEach(b => {
@ -463,8 +457,8 @@ function overviewBurgs() {
data += rn(b.population * populationRate * urbanization) + ",";
// add geography data
data += mapCoordinates.lonW + (b.x / graphWidth) * mapCoordinates.lonT + ",";
data += mapCoordinates.latN - (b.y / graphHeight) * mapCoordinates.latT + ","; // this is inverted in QGIS otherwise
data += getLatitude(b.y, 2) + ",";
data += getLongitude(b.x, 2) + ",";
data += parseInt(getHeight(pack.cells.h[b.cell])) + ",";
// add status data
@ -474,7 +468,9 @@ function overviewBurgs() {
data += b.walls ? "walls," : ",";
data += b.plaza ? "plaza," : ",";
data += b.temple ? "temple," : ",";
data += b.shanty ? "shanty town\n" : "\n";
data += b.shanty ? "shanty town," : ",";
if (options.showMFCGMap) data += getMFCGlink(b);
data += "\n";
});
const name = getFileName("Burgs") + ".csv";
@ -508,19 +504,14 @@ function overviewBurgs() {
}
function importBurgNames(dataLoaded) {
if (!dataLoaded) {
tip("Cannot load the file, please check the format", false, "error");
return;
}
if (!dataLoaded) return tip("Cannot load the file, please check the format", false, "error");
const data = dataLoaded.split("\r\n");
if (!data.length) {
tip("Cannot parse the list, please check the file format", false, "error");
return;
}
if (!data.length) return tip("Cannot parse the list, please check the file format", false, "error");
let change = [],
message = `Burgs will be renamed as below. Please confirm`;
let change = [];
let message = `Burgs to be renamed as below:`;
message += `<table class="overflow-table"><tr><th>Id</th><th>Current name</th><th>New Name</th></tr>`;
const burgs = pack.burgs.filter(b => b.i && !b.removed);
for (let i = 0; i < data.length && i <= burgs.length; i++) {
const v = data[i];
@ -529,45 +520,36 @@ function overviewBurgs() {
message += `<tr><td style="width:20%">${burgs[i].i}</td><td style="width:40%">${burgs[i].name}</td><td style="width:40%">${v}</td></tr>`;
}
message += `</tr></table>`;
if (!change.length) message = "No changes found in the file. Please change some names to get a result";
alertMessage.innerHTML = message;
$("#alert").dialog({
title: "Burgs bulk renaming",
width: "22em",
position: {my: "center", at: "center", of: "svg"},
buttons: {
Cancel: function () {
$(this).dialog("close");
},
Confirm: function () {
const onConfirm = () => {
for (let i = 0; i < change.length; i++) {
const id = change[i].id;
pack.burgs[id].name = change[i].name;
burgLabels.select("[data-id='" + id + "']").text(change[i].name);
}
$(this).dialog("close");
burgsOverviewAddLines();
}
}
};
confirmationDialog({
title: "Burgs bulk renaming",
message,
confirm: "Rename",
onConfirm
});
}
function triggerAllBurgsRemove() {
alertMessage.innerHTML = `Are you sure you want to remove all unlocked burgs except for capitals?
<br><i>To remove a capital you have to remove a state first</i>`;
$("#alert").dialog({
resizable: false,
title: "Remove all burgs",
buttons: {
Remove: function () {
$(this).dialog("close");
removeAllBurgs();
},
Cancel: function () {
$(this).dialog("close");
}
}
const number = pack.burgs.filter(b => b.i && !b.removed && !b.capital && !b.lock).length;
confirmationDialog({
title: `Remove ${number} burgs`,
message: `
Are you sure you want to remove all <i>unlocked</i> burgs except for capitals?
<br><i>To remove a capital you have to remove a state first</i>`,
confirm: "Remove",
onConfirm: removeAllBurgs
});
}
@ -575,4 +557,9 @@ function overviewBurgs() {
pack.burgs.filter(b => b.i && !(b.capital || b.lock)).forEach(b => removeBurg(b.i));
burgsOverviewAddLines();
}
function invertLock() {
pack.burgs = pack.burgs.map(burg => ({...burg, lock: !burg.lock}));
burgsOverviewAddLines();
}
}

View file

@ -62,9 +62,9 @@ function editCultures() {
// add line for each culture
function culturesEditorAddLines() {
const unit = areaUnit.value === "square" ? " " + distanceUnitInput.value + "²" : " " + areaUnit.value;
let lines = "",
totalArea = 0,
totalPopulation = 0;
let lines = "";
let totalArea = 0;
let totalPopulation = 0;
const emblemShapeGroup = document.getElementById("emblemShape").selectedOptions[0].parentNode.label;
const selectShape = emblemShapeGroup === "Diversiform";
@ -84,7 +84,8 @@ function editCultures() {
lines += `<div class="states" data-id=${c.i} data-name="${c.name}" data-color="" data-cells=${c.cells}
data-area=${area} data-population=${population} data-base=${c.base} data-type="" data-expansionism="" data-emblems="${c.shield}">
<svg width="9" height="9" class="placeholder"></svg>
<input data-tip="Culture name. Click and type to change" class="cultureName italic" value="${c.name}" autocorrect="off" spellcheck="false">
<input data-tip="Neutral culture name. Click and type to change" class="cultureName italic" value="${c.name}" autocorrect="off" spellcheck="false">
<span class="icon-cw placeholder"></span>
<span data-tip="Cells count" class="icon-check-empty hide"></span>
<div data-tip="Cells count" class="stateCells hide">${c.cells}</div>
<span class="icon-resize-full placeholder hide"></span>
@ -96,19 +97,28 @@ function editCultures() {
<div data-tip="${populationTip}" class="culturePopulation hide">${si(population)}</div>
<span data-tip="Click to re-generate names for burgs with this culture assigned" class="icon-arrows-cw hide"></span>
<select data-tip="Culture namesbase. Click to change. Click on arrows to re-generate names" class="cultureBase">${getBaseOptions(c.base)}</select>
${selectShape ? `<select data-tip="Emblem shape associated with culture. Click to change" class="cultureShape hide">${getShapeOptions(c.shield)}</select>` : ""}
${
selectShape
? `<select data-tip="Emblem shape associated with culture. Click to change" class="cultureShape hide">${getShapeOptions(c.shield)}</select>`
: ""
}
</div>`;
continue;
}
lines += `<div class="states cultures" data-id=${c.i} data-name="${c.name}" data-color="${c.color}" data-cells=${c.cells}
data-area=${area} data-population=${population} data-base=${c.base} data-type=${c.type} data-expansionism=${c.expansionism} data-emblems="${c.shield}">
<svg data-tip="Culture fill style. Click to change" width=".9em" height=".9em" style="margin-bottom:-1px"><rect x="0" y="0" width="100%" height="100%" fill="${c.color}" class="fillRect pointer"></svg>
<svg data-tip="Culture fill style. Click to change" width=".9em" height=".9em" style="margin-bottom:-1px">
<rect x="0" y="0" width="100%" height="100%" fill="${c.color}" class="fillRect pointer">
</svg>
<input data-tip="Culture name. Click and type to change" class="cultureName" value="${c.name}" autocorrect="off" spellcheck="false">
<span data-tip="Regenerate culture name" class="icon-cw hiddenIcon" style="visibility: hidden"></span>
<span data-tip="Cells count" class="icon-check-empty hide"></span>
<div data-tip="Cells count" class="stateCells hide">${c.cells}</div>
<span data-tip="Culture expansionism. Defines competitive size" class="icon-resize-full hide"></span>
<input data-tip="Culture expansionism. Defines competitive size. Click to change, then click Recalculate to apply change" class="statePower hide" type="number" min=0 max=99 step=.1 value=${c.expansionism}>
<input data-tip="Culture expansionism. Defines competitive size. Click to change, then click Recalculate to apply change" class="statePower hide" type="number" min=0 max=99 step=.1 value=${
c.expansionism
}>
<select data-tip="Culture type. Defines growth model. Click to change" class="cultureType">${getTypeOptions(c.type)}</select>
<span data-tip="Culture area" style="padding-right: 4px" class="icon-map-o hide"></span>
<div data-tip="Culture area" class="biomeArea hide">${si(area) + unit}</div>
@ -116,7 +126,11 @@ function editCultures() {
<div data-tip="${populationTip}" class="culturePopulation hide">${si(population)}</div>
<span data-tip="Click to re-generate names for burgs with this culture assigned" class="icon-arrows-cw hide"></span>
<select data-tip="Culture namesbase. Click to change. Click on arrows to re-generate names" class="cultureBase">${getBaseOptions(c.base)}</select>
${selectShape ? `<select data-tip="Emblem shape associated with culture. Click to change" class="cultureShape hide">${getShapeOptions(c.shield)}</select>` : ""}
${
selectShape
? `<select data-tip="Emblem shape associated with culture. Click to change" class="cultureShape hide">${getShapeOptions(c.shield)}</select>`
: ""
}
<span data-tip="Remove culture" class="icon-trash-empty hide"></span>
</div>`;
}
@ -136,6 +150,7 @@ function editCultures() {
body.querySelectorAll("div.states").forEach(el => el.addEventListener("click", selectCultureOnLineClick));
body.querySelectorAll("rect.fillRect").forEach(el => el.addEventListener("click", cultureChangeColor));
body.querySelectorAll("div > input.cultureName").forEach(el => el.addEventListener("input", cultureChangeName));
body.querySelectorAll("div > span.icon-cw").forEach(el => el.addEventListener("click", cultureRegenerateName));
body.querySelectorAll("div > input.statePower").forEach(el => el.addEventListener("input", cultureChangeExpansionism));
body.querySelectorAll("div > select.cultureType").forEach(el => el.addEventListener("change", cultureChangeType));
body.querySelectorAll("div > select.cultureBase").forEach(el => el.addEventListener("change", cultureChangeBase));
@ -258,6 +273,13 @@ function editCultures() {
);
}
function cultureRegenerateName() {
const culture = +this.parentNode.dataset.id;
const name = Names.getCultureShort(culture);
this.parentNode.querySelector("input.cultureName").value = name;
pack.cultures[culture].name = name;
}
function cultureChangeExpansionism() {
const culture = +this.parentNode.dataset.id;
this.parentNode.dataset.expansionism = this.value;
@ -526,7 +548,13 @@ function editCultures() {
// prepare svg
alertMessage.innerHTML = "<div id='cultureInfo' class='chartInfo'>&#8205;</div>";
const svg = d3.select("#alertMessage").insert("svg", "#cultureInfo").attr("id", "hierarchy").attr("width", width).attr("height", height).style("text-anchor", "middle");
const svg = d3
.select("#alertMessage")
.insert("svg", "#cultureInfo")
.attr("id", "hierarchy")
.attr("width", width)
.attr("height", height)
.style("text-anchor", "middle");
const graph = svg.append("g").attr("transform", `translate(10, -45)`);
const links = graph.append("g").attr("fill", "none").attr("stroke", "#aaaaaa");
const nodes = graph.append("g");
@ -540,7 +568,24 @@ function editCultures() {
.enter()
.append("path")
.attr("d", d => {
return "M" + d.source.x + "," + d.source.y + "C" + d.source.x + "," + (d.source.y * 3 + d.target.y) / 4 + " " + d.target.x + "," + (d.source.y * 2 + d.target.y) / 3 + " " + d.target.x + "," + d.target.y;
return (
"M" +
d.source.x +
"," +
d.source.y +
"C" +
d.source.x +
"," +
(d.source.y * 3 + d.target.y) / 4 +
" " +
d.target.x +
"," +
(d.source.y * 2 + d.target.y) / 3 +
" " +
d.target.x +
"," +
d.target.y
);
});
const node = nodes
@ -661,7 +706,11 @@ function editCultures() {
$("#culturesEditor").dialog({position: {my: "right top", at: "right-10 top+10", of: "svg"}});
tip("Click on culture to select, drag the circle to change culture", true);
viewbox.style("cursor", "crosshair").on("click", selectCultureOnMapClick).call(d3.drag().on("start", dragCultureBrush)).on("touchmove mousemove", moveCultureBrush);
viewbox
.style("cursor", "crosshair")
.on("click", selectCultureOnMapClick)
.call(d3.drag().on("start", dragCultureBrush))
.on("touchmove mousemove", moveCultureBrush);
body.querySelector("div").classList.add("selected");
}
@ -712,7 +761,14 @@ function editCultures() {
// change of append new element
if (exists.size()) exists.attr("data-culture", cultureNew).attr("fill", color).attr("stroke", color);
else temp.append("polygon").attr("data-cell", i).attr("data-culture", cultureNew).attr("points", getPackPolygon(i)).attr("fill", color).attr("stroke", color);
else
temp
.append("polygon")
.attr("data-cell", i)
.attr("data-culture", cultureNew)
.attr("points", getPackPolygon(i))
.attr("fill", color)
.attr("stroke", color);
});
}

View file

@ -1,6 +1,7 @@
// module stub to store common functions for ui editors
"use strict";
modules.editors = true;
restoreDefaultEvents(); // apply default viewbox events on load
// restore default viewbox events
@ -28,7 +29,7 @@ function clicked() {
else if (grand.id === "burgIcons") editBurg();
else if (parent.id === "ice") editIce();
else if (parent.id === "terrain") editReliefIcon();
else if (parent.id === "markers") editMarker();
else if (grand.id === "markers" || great.id === "markers") editMarker();
else if (grand.id === "coastline") editCoastline();
else if (great.id === "armies") editRegiment();
else if (pack.cells.t[i] === 1) {
@ -259,20 +260,48 @@ function togglePort(burg) {
.attr("height", size);
}
function getBurgSeed(burg) {
return burg.MFCG || Number(`${seed}${String(burg.i).padStart(4, 0)}`);
}
function getMFCGlink(burg) {
const {cells} = pack;
const {name, population, cell} = burg;
const burgSeed = getBurgSeed(burg);
const sizeRaw = 2.13 * Math.pow((population * populationRate) / urbanDensity, 0.385);
const size = minmax(Math.ceil(sizeRaw), 6, 100);
const people = rn(population * populationRate * urbanization);
const hub = +cells.road[cell] > 50;
const river = cells.r[cell] ? 1 : 0;
const coast = +burg.port;
const citadel = +burg.citadel;
const walls = +burg.walls;
const plaza = +burg.plaza;
const temple = +burg.temple;
const shanty = +burg.shanty;
const sea = coast && cells.haven[cell] ? getSeaDirections(cell) : "";
function getSeaDirections(i) {
const p1 = cells.p[i];
const p2 = cells.p[cells.haven[i]];
let deg = (Math.atan2(p2[1] - p1[1], p2[0] - p1[0]) * 180) / Math.PI - 90;
if (deg < 0) deg += 360;
const norm = rn(normalize(deg, 0, 360) * 2, 2); // 0 = south, 0.5 = west, 1 = north, 1.5 = east
return "&sea=" + norm;
}
const baseURL = "https://watabou.github.io/city-generator/?random=0&continuous=0";
const url = `${baseURL}&name=${name}&population=${people}&size=${size}&seed=${burgSeed}&hub=${hub}&river=${river}&coast=${coast}&citadel=${citadel}&plaza=${plaza}&temple=${temple}&walls=${walls}&shantytown=${shanty}${sea}`;
return url;
}
function toggleBurgLock(burg) {
const b = pack.burgs[burg];
b.lock = b.lock ? 0 : 1;
}
function showBurgLockTip(burg) {
const b = pack.burgs[burg];
if (b.lock) {
tip("Click to Unlock burg and allow it to be change by regeneration tools");
} else {
tip("Click to Lock burg and prevent changes by regeneration tools");
}
}
// draw legend box
function drawLegend(name, data) {
legend.selectAll("*").remove(); // fully redraw every time
@ -331,7 +360,15 @@ function drawLegend(name, data) {
const width = bbox.width + colOffset * 2;
const height = bbox.height + colOffset / 2 + vOffset;
legend.insert("rect", ":first-child").attr("id", "legendBox").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height).attr("fill", backClr).attr("fill-opacity", opacity);
legend
.insert("rect", ":first-child")
.attr("id", "legendBox")
.attr("x", 0)
.attr("y", 0)
.attr("width", width)
.attr("height", height)
.attr("fill", backClr)
.attr("fill-opacity", opacity);
fitLegendBox();
}
@ -384,7 +421,15 @@ function createPicker() {
const closePicker = () => contaiter.style("display", "none");
const contaiter = d3.select("body").append("svg").attr("id", "pickerContainer").attr("width", "100%").attr("height", "100%");
contaiter.append("rect").attr("x", 0).attr("y", 0).attr("width", "100%").attr("height", "100%").attr("opacity", 0.2).on("mousemove", cl).on("click", closePicker);
contaiter
.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", "100%")
.attr("height", "100%")
.attr("opacity", 0.2)
.on("mousemove", cl)
.on("click", closePicker);
const picker = contaiter
.append("g")
.attr("id", "picker")
@ -483,9 +528,25 @@ function createPicker() {
const width = bbox.width + 8;
const height = bbox.height + 9;
picker.insert("rect", ":first-child").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height).attr("fill", "#ffffff").attr("stroke", "#5d4651").on("mousemove", pos);
picker
.insert("rect", ":first-child")
.attr("x", 0)
.attr("y", 0)
.attr("width", width)
.attr("height", height)
.attr("fill", "#ffffff")
.attr("stroke", "#5d4651")
.on("mousemove", pos);
picker.insert("text", ":first-child").attr("x", 291).attr("y", -10).attr("id", "pickerCloseText").text("✕");
picker.insert("rect", ":first-child").attr("x", 288).attr("y", -21).attr("id", "pickerCloseRect").attr("width", 14).attr("height", 14).on("mousemove", cl).on("click", closePicker);
picker
.insert("rect", ":first-child")
.attr("x", 288)
.attr("y", -21)
.attr("id", "pickerCloseRect")
.attr("width", 14)
.attr("height", 14)
.on("mousemove", cl)
.on("click", closePicker);
picker.insert("text", ":first-child").attr("x", 12).attr("y", -10).attr("id", "pickerLabel").text("Color Picker").on("mousemove", pos);
picker.insert("rect", ":first-child").attr("x", 0).attr("y", -30).attr("width", width).attr("height", 30).attr("id", "pickerHeader").on("mousemove", pos);
picker.attr("transform", `translate(${(svgWidth - width) / 2},${(svgHeight - height) / 2})`);
@ -695,23 +756,33 @@ function uploadFile(el, callback) {
fileReader.onload = loaded => callback(loaded.target.result);
}
function highlightElement(element) {
if (debug.select(".highlighted").size()) return; // allow only 1 highlight element simultaniosly
const box = element.getBBox();
function getBBox(element) {
const x = +element.getAttribute("x");
const y = +element.getAttribute("y");
const width = +element.getAttribute("width");
const height = +element.getAttribute("height");
return {x, y, width, height};
}
function highlightElement(element, zoom) {
if (debug.select(".highlighted").size()) return; // allow only 1 highlight element simultaneously
const box = element.tagName === "svg" ? getBBox(element) : element.getBBox();
const transform = element.getAttribute("transform") || null;
const enter = d3.transition().duration(1000).ease(d3.easeBounceOut);
const exit = d3.transition().duration(500).ease(d3.easeLinear);
const highlight = debug.append("rect").attr("x", box.x).attr("y", box.y).attr("width", box.width).attr("height", box.height).attr("transform", transform);
highlight.classed("highlighted", 1).transition(enter).style("outline-offset", "0px").transition(exit).style("outline-color", "transparent").delay(1000).remove();
const highlight = debug.append("rect").attr("x", box.x).attr("y", box.y).attr("width", box.width).attr("height", box.height);
highlight.classed("highlighted", 1).attr("transform", transform);
highlight.transition(enter).style("outline-offset", "0px").transition(exit).style("outline-color", "transparent").delay(1000).remove();
if (zoom) {
const tr = parseTransform(transform);
let x = box.x + box.width / 2;
if (tr[0]) x += tr[0];
let y = box.y + box.height / 2;
if (tr[1]) y += tr[1];
zoomTo(x, y, scale > 2 ? scale : 3, 1600);
zoomTo(x, y, scale > 2 ? scale : zoom, 1600);
}
}
function selectIcon(initial, callback) {
@ -921,6 +992,7 @@ function selectIcon(initial, callback) {
}
}
input.oninput = e => callback(input.value);
table.onclick = e => {
if (e.target.tagName === "TD") {
input.value = e.target.innerHTML;
@ -947,6 +1019,37 @@ function selectIcon(initial, callback) {
});
}
function confirmationDialog(options) {
const {
title = "Confirm action",
message = "Are you sure you want to continue? <br>The action cannot be reverted",
cancel = "Cancel",
confirm = "Continue",
onCancel,
onConfirm
} = options;
const buttons = {
[confirm]: function () {
if (onConfirm) onConfirm();
$(this).dialog("close");
},
[cancel]: function () {
if (onCancel) onCancel();
$(this).dialog("close");
}
};
document.getElementById("alertMessage").innerHTML = message;
$("#alert").dialog({resizable: false, title, buttons});
}
// add and register event listeners to clean up on editor closure
function listen(element, event, handler) {
element.addEventListener(event, handler);
return () => element.removeEventListener(event, handler);
}
// Calls the refresh functionality on all editors currently open.
function refreshAllEditors() {
TIME && console.time("refreshAllEditors");

View file

@ -1,15 +1,17 @@
// Module to store general UI functions
"use strict";
// Module to store general UI functions
// fit full-screen map if window is resized
$(window).resize(function (e) {
window.addEventListener("resize", function (e) {
if (localStorage.getItem("mapWidth") && localStorage.getItem("mapHeight")) return;
mapWidthInput.value = window.innerWidth;
mapHeightInput.value = window.innerHeight;
changeMapSize();
});
if (location.hostname && location.hostname !== "localhost" && location.hostname !== "127.0.0.1") {
window.onbeforeunload = () => "Are you sure you want to navigate away?";
}
// Tooltips
const tooltip = document.getElementById("tooltip");
@ -19,12 +21,6 @@ document.getElementById("dialogs").addEventListener("mousemove", showDataTip);
document.getElementById("optionsContainer").addEventListener("mousemove", showDataTip);
document.getElementById("exitCustomization").addEventListener("mousemove", showDataTip);
/**
* @param {string} tip Tooltip text
* @param {boolean} main Show above other tooltips
* @param {string} type Message type (color): error / warn / success
* @param {number} time Timeout to auto hide, ms
*/
function tip(tip = "Tip is undefined", main, type, time) {
tooltip.innerHTML = tip;
tooltip.style.background = "linear-gradient(0.1turn, #ffffff00, #5e5c5c80, #ffffff00)";
@ -60,6 +56,15 @@ function showDataTip(e) {
tip(dataTip);
}
function showElementLockTip(event) {
const locked = event?.target?.classList?.contains("icon-lock");
if (locked) {
tip("Click to unlock the element and allow it to be changed by regeneration tools");
} else {
tip("Click to lock the element and prevent changes to it by regeneration tools");
}
}
const moved = debounce(mouseMove, 100);
function mouseMove() {
const point = d3.mouse(this);
@ -84,7 +89,7 @@ function showNotes(e, i) {
document.getElementById("notes").style.display = "block";
document.getElementById("notesHeader").innerHTML = note.name;
document.getElementById("notesBody").innerHTML = note.legend;
} else if (!options.pinNotes) {
} else if (!options.pinNotes && !markerEditor.offsetParent) {
document.getElementById("notes").style.display = "none";
document.getElementById("notesHeader").innerHTML = "";
document.getElementById("notesBody").innerHTML = "";
@ -105,7 +110,8 @@ function showMapTooltip(point, e, i, g) {
if (group === "emblems" && e.target.tagName === "use") {
const parent = e.target.parentNode;
const [g, type] = parent.id === "burgEmblems" ? [pack.burgs, "burg"] : parent.id === "provinceEmblems" ? [pack.provinces, "province"] : [pack.states, "state"];
const [g, type] =
parent.id === "burgEmblems" ? [pack.burgs, "burg"] : parent.id === "provinceEmblems" ? [pack.provinces, "province"] : [pack.states, "state"];
const i = +e.target.dataset.i;
if (event.shiftKey) highlightEmblemElement(type, g[i]);
@ -140,7 +146,7 @@ function showMapTooltip(point, e, i, g) {
}
if (group === "labels") return tip("Click to edit the Label");
if (group === "markers") return tip("Click to edit the Marker");
if (group === "markers") return tip("Click to edit the Marker and pin the marker note");
if (group === "ruler") {
const tag = e.target.tagName;
@ -222,8 +228,8 @@ function updateCellInfo(point, i, g) {
const x = (infoX.innerHTML = rn(point[0]));
const y = (infoY.innerHTML = rn(point[1]));
const f = cells.f[i];
infoLat.innerHTML = toDMS(mapCoordinates.latN - (y / graphHeight) * mapCoordinates.latT, "lat");
infoLon.innerHTML = toDMS(mapCoordinates.lonW + (x / graphWidth) * mapCoordinates.lonT, "lon");
infoLat.innerHTML = toDMS(getLatitude(y, 4), "lat");
infoLon.innerHTML = toDMS(getLongitude(x, 4), "lon");
infoCell.innerHTML = i;
const unit = areaUnit.value === "square" ? " " + distanceUnitInput.value + "²" : " " + areaUnit.value;
@ -332,7 +338,20 @@ function highlightEmblemElement(type, el) {
if (type === "burg") {
const {x, y} = el;
debug.append("circle").attr("cx", x).attr("cy", y).attr("r", 0).attr("fill", "none").attr("stroke", "#d0240f").attr("stroke-width", 1).attr("opacity", 1).transition(animation).attr("r", 20).attr("opacity", 0.1).attr("stroke-width", 0).remove();
debug
.append("circle")
.attr("cx", x)
.attr("cy", y)
.attr("r", 0)
.attr("fill", "none")
.attr("stroke", "#d0240f")
.attr("stroke-width", 1)
.attr("opacity", 1)
.transition(animation)
.attr("r", 20)
.attr("opacity", 0.1)
.attr("stroke-width", 0)
.remove();
return;
}
@ -481,226 +500,3 @@ function showInfo() {
position: {my: "center", at: "center", of: "svg"}
});
}
// prevent default browser behavior for FMG-used hotkeys
document.addEventListener("keydown", event => {
if (event.altKey && event.keyCode !== 18) event.preventDefault(); // disallow alt key combinations
if (event.ctrlKey && event.code === "KeyS") event.preventDefault(); // disallow CTRL + C
if ([112, 113, 117, 120, 9].includes(event.keyCode)) event.preventDefault(); // F1, F2, F6, F9, Tab
});
// Hotkeys, see github.com/Azgaar/Fantasy-Map-Generator/wiki/Hotkeys
document.addEventListener("keyup", event => {
if (!window.closeDialogs) return; // not all modules are loaded
const canvas3d = document.getElementById("canvas3d"); // check if 3d mode is active
const active = document.activeElement.tagName;
if (active === "INPUT" || active === "SELECT" || active === "TEXTAREA") return; // don't trigger if user inputs a text
if (active === "DIV" && document.activeElement.contentEditable === "true") return; // don't trigger if user inputs a text
event.stopPropagation();
const key = event.keyCode;
const ctrl = event.ctrlKey || event.metaKey || key === 17;
const shift = event.shiftKey || key === 16;
const alt = event.altKey || key === 18;
if (key === 112) showInfo();
// "F1" to show info
else if (key === 113) regeneratePrompt();
// "F2" for new map
else if (key === 113) regeneratePrompt();
// "F2" for a new map
else if (key === 117) quickSave();
// "F6" for quick save
else if (key === 120) quickLoad();
// "F9" for quick load
else if (key === 9) toggleOptions(event);
// Tab to toggle options
else if (key === 27) {
closeDialogs();
hideOptions();
} // Escape to close all dialogs
else if (key === 46) removeElementOnKey();
// "Delete" to remove the selected element
else if (key === 79 && canvas3d) toggle3dOptions();
// "O" to toggle 3d options
else if (ctrl && key === 81) toggleSaveReminder();
// Ctrl + "Q" to toggle save reminder
else if (ctrl && key === 83) saveMap();
// Ctrl + "S" to save .map file
else if (undo.offsetParent && ctrl && key === 90) undo.click();
// Ctrl + "Z" to undo
else if (redo.offsetParent && ctrl && key === 89) redo.click();
// Ctrl + "Y" to redo
else if (shift && key === 72) editHeightmap();
// Shift + "H" to edit Heightmap
else if (shift && key === 66) editBiomes();
// Shift + "B" to edit Biomes
else if (shift && key === 83) editStates();
// Shift + "S" to edit States
else if (shift && key === 80) editProvinces();
// Shift + "P" to edit Provinces
else if (shift && key === 68) editDiplomacy();
// Shift + "D" to edit Diplomacy
else if (shift && key === 67) editCultures();
// Shift + "C" to edit Cultures
else if (shift && key === 78) editNamesbase();
// Shift + "N" to edit Namesbase
else if (shift && key === 90) editZones();
// Shift + "Z" to edit Zones
else if (shift && key === 82) editReligions();
// Shift + "R" to edit Religions
else if (shift && key === 89) openEmblemEditor();
// Shift + "Y" to edit Emblems
else if (shift && key === 81) editUnits();
// Shift + "Q" to edit Units
else if (shift && key === 79) editNotes();
// Shift + "O" to edit Notes
else if (shift && key === 84) overviewBurgs();
// Shift + "T" to open Burgs overview
else if (shift && key === 86) overviewRivers();
// Shift + "V" to open Rivers overview
else if (shift && key === 77) overviewMilitary();
// Shift + "M" to open Military overview
else if (shift && key === 69) viewCellDetails();
// Shift + "E" to open Cell Details
else if (shift && key === 49) toggleAddBurg();
// Shift + "1" to click to add Burg
else if (shift && key === 50) toggleAddLabel();
// Shift + "2" to click to add Label
else if (shift && key === 51) toggleAddRiver();
// Shift + "3" to click to add River
else if (shift && key === 52) toggleAddRoute();
// Shift + "4" to click to add Route
else if (shift && key === 53) toggleAddMarker();
// Shift + "5" to click to add Marker
else if (alt && key === 66) console.table(pack.burgs);
// Alt + "B" to log burgs data
else if (alt && key === 83) console.table(pack.states);
// Alt + "S" to log states data
else if (alt && key === 67) console.table(pack.cultures);
// Alt + "C" to log cultures data
else if (alt && key === 82) console.table(pack.religions);
// Alt + "R" to log religions data
else if (alt && key === 70) console.table(pack.features);
// Alt + "F" to log features data
else if (key === 88) toggleTexture();
// "X" to toggle Texture layer
else if (key === 72) toggleHeight();
// "H" to toggle Heightmap layer
else if (key === 66) toggleBiomes();
// "B" to toggle Biomes layer
else if (key === 69) toggleCells();
// "E" to toggle Cells layer
else if (key === 71) toggleGrid();
// "G" to toggle Grid layer
else if (key === 79) toggleCoordinates();
// "O" to toggle Coordinates layer
else if (key === 87) toggleCompass();
// "W" to toggle Compass Rose layer
else if (key === 86) toggleRivers();
// "V" to toggle Rivers layer
else if (key === 70) toggleRelief();
// "F" to toggle Relief icons layer
else if (key === 67) toggleCultures();
// "C" to toggle Cultures layer
else if (key === 83) toggleStates();
// "S" to toggle States layer
else if (key === 80) toggleProvinces();
// "P" to toggle Provinces layer
else if (key === 90) toggleZones();
// "Z" to toggle Zones
else if (key === 68) toggleBorders();
// "D" to toggle Borders layer
else if (key === 82) toggleReligions();
// "R" to toggle Religions layer
else if (key === 85) toggleRoutes();
// "U" to toggle Routes layer
else if (key === 84) toggleTemp();
// "T" to toggle Temperature layer
else if (key === 78) togglePopulation();
// "N" to toggle Population layer
else if (key === 74) toggleIce();
// "J" to toggle Ice layer
else if (key === 65) togglePrec();
// "A" to toggle Precipitation layer
else if (key === 89) toggleEmblems();
// "Y" to toggle Emblems layer
else if (key === 76) toggleLabels();
// "L" to toggle Labels layer
else if (key === 73) toggleIcons();
// "I" to toggle Icons layer
else if (key === 77) toggleMilitary();
// "M" to toggle Military layer
else if (key === 75) toggleMarkers();
// "K" to toggle Markers layer
else if (key === 187) toggleRulers();
// Equal (=) to toggle Rulers
else if (key === 189) toggleScaleBar();
// Minus (-) to toggle Scale bar
else if (key === 37) zoom.translateBy(svg, 10, 0);
// Left to scroll map left
else if (key === 39) zoom.translateBy(svg, -10, 0);
// Right to scroll map right
else if (key === 38) zoom.translateBy(svg, 0, 10);
// Up to scroll map up
else if (key === 40) zoom.translateBy(svg, 0, -10);
// Up to scroll map up
else if (key === 107 || key === 109) pressNumpadSign(key);
// Numpad Plus/Minus to zoom map or change brush size
else if (key === 48 || key === 96) resetZoom(1000);
// 0 to reset zoom
else if (key === 49 || key === 97) zoom.scaleTo(svg, 1);
// 1 to zoom to 1
else if (key === 50 || key === 98) zoom.scaleTo(svg, 2);
// 2 to zoom to 2
else if (key === 51 || key === 99) zoom.scaleTo(svg, 3);
// 3 to zoom to 3
else if (key === 52 || key === 100) zoom.scaleTo(svg, 4);
// 4 to zoom to 4
else if (key === 53 || key === 101) zoom.scaleTo(svg, 5);
// 5 to zoom to 5
else if (key === 54 || key === 102) zoom.scaleTo(svg, 6);
// 6 to zoom to 6
else if (key === 55 || key === 103) zoom.scaleTo(svg, 7);
// 7 to zoom to 7
else if (key === 56 || key === 104) zoom.scaleTo(svg, 8);
// 8 to zoom to 8
else if (key === 57 || key === 105) zoom.scaleTo(svg, 9);
// 9 to zoom to 9
else if (ctrl) pressControl(); // Control to toggle mode
});
function pressNumpadSign(key) {
// if brush sliders are displayed, decrease brush size
let brush = null;
const d = key === 107 ? 1 : -1;
if (brushRadius.offsetParent) brush = document.getElementById("brushRadius");
else if (biomesManuallyBrush.offsetParent) brush = document.getElementById("biomesManuallyBrush");
else if (statesManuallyBrush.offsetParent) brush = document.getElementById("statesManuallyBrush");
else if (provincesManuallyBrush.offsetParent) brush = document.getElementById("provincesManuallyBrush");
else if (culturesManuallyBrush.offsetParent) brush = document.getElementById("culturesManuallyBrush");
else if (zonesBrush.offsetParent) brush = document.getElementById("zonesBrush");
else if (religionsManuallyBrush.offsetParent) brush = document.getElementById("religionsManuallyBrush");
if (brush) {
const value = Math.max(Math.min(+brush.value + d, +brush.max), +brush.min);
brush.value = document.getElementById(brush.id + "Number").value = value;
return;
}
const scaleBy = key === 107 ? 1.2 : 0.8;
zoom.scaleBy(svg, scaleBy); // if no, zoom map
}
function pressControl() {
if (zonesRemove.offsetParent) {
zonesRemove.classList.contains("pressed") ? zonesRemove.classList.remove("pressed") : zonesRemove.classList.add("pressed");
}
}
// trigger trash button click on "Delete" keypress
function removeElementOnKey() {
$(".dialog:visible .fastDelete").click();
$("button:visible:contains('Remove')").click();
}

View file

@ -15,15 +15,9 @@ function editHeightmap() {
title: "Edit Heightmap",
width: "28em",
buttons: {
Erase: function () {
enterHeightmapEditMode("erase");
},
Keep: function () {
enterHeightmapEditMode("keep");
},
Risk: function () {
enterHeightmapEditMode("risk");
},
Erase: () => enterHeightmapEditMode("erase"),
Keep: () => enterHeightmapEditMode("keep"),
Risk: () => enterHeightmapEditMode("risk"),
Cancel: function () {
$(this).dialog("close");
}
@ -87,7 +81,16 @@ function editHeightmap() {
exitCustomization.style.bottom = svgHeight / 2 + "px";
exitCustomization.style.transform = "scale(2)";
exitCustomization.style.display = "block";
d3.select("#exitCustomization").transition().duration(1000).style("opacity", 1).transition().duration(2000).ease(d3.easeSinInOut).style("right", "10px").style("bottom", "10px").style("transform", "scale(1)");
d3.select("#exitCustomization")
.transition()
.duration(1000)
.style("opacity", 1)
.transition()
.duration(2000)
.ease(d3.easeSinInOut)
.style("right", "10px")
.style("bottom", "10px")
.style("transform", "scale(1)");
} else exitCustomization.style.display = "block";
openBrushesPanel();
@ -130,7 +133,8 @@ function editHeightmap() {
// Exit customization mode
function finalizeHeightmap() {
if (viewbox.select("#heights").selectAll("*").size() < 200) return tip("Insufficient land area! There should be at least 200 land cells to finalize the heightmap", null, "error");
if (viewbox.select("#heights").selectAll("*").size() < 200)
return tip("Insufficient land area! There should be at least 200 land cells to finalize the heightmap", null, "error");
if (document.getElementById("imageConverter").offsetParent) return tip("Please exit the Image Conversion mode first", null, "error");
delete window.edits; // remove global variable
@ -216,7 +220,7 @@ function editHeightmap() {
Lakes.generateName();
Military.generate();
addMarkers();
Markers.generate();
addZones();
TIME && console.timeEnd("regenerateErasedData");
INFO && console.groupEnd("Edit Heightmap");
@ -608,7 +612,7 @@ function editHeightmap() {
const interpolate = d3.interpolateRound(power, 1);
const land = changeOnlyLand.checked;
function lim(v) {
return Math.max(Math.min(v, 100), land ? 20 : 0);
return minmax(v, land ? 20 : 0, 100);
}
const h = grid.cells.h;
@ -618,7 +622,10 @@ function editHeightmap() {
else if (brush === "brushLower") s.forEach(i => (h[i] = lim(h[i] - power)));
else if (brush === "brushDepress") s.forEach((i, d) => (h[i] = lim(h[i] - interpolate(d / Math.max(s.length - 1, 1)))));
else if (brush === "brushAlign") s.forEach(i => (h[i] = lim(h[start])));
else if (brush === "brushSmooth") s.forEach(i => (h[i] = rn((d3.mean(grid.cells.c[i].filter(i => (land ? h[i] >= 20 : 1)).map(c => h[c])) + h[i] * (10 - power) + 0.6) / (11 - power), 1)));
else if (brush === "brushSmooth")
s.forEach(
i => (h[i] = rn((d3.mean(grid.cells.c[i].filter(i => (land ? h[i] >= 20 : 1)).map(c => h[c])) + h[i] * (10 - power) + 0.6) / (11 - power), 1))
);
else if (brush === "brushDisrupt") s.forEach(i => (h[i] = h[i] < 15 ? h[i] : lim(h[i] + power / 1.6 - Math.random() * power)));
mockHeightmapSelection(s);
@ -767,15 +774,29 @@ function editHeightmap() {
const TempY = `<span>y:<input class="templateY" data-tip="Placement range percentage along Y axis (minY-maxY)" value=${arg5 || "20-80"}></span>`;
const TempX = `<span>x:<input class="templateX" data-tip="Placement range percentage along X axis (minX-maxX)" value=${arg4 || "15-85"}></span>`;
const Height = `<span>h:<input class="templateHeight" data-tip="Blob maximum height, use hyphen to get a random number in range" value=${arg3 || "40-50"}></span>`;
const Height = `<span>h:<input class="templateHeight" data-tip="Blob maximum height, use hyphen to get a random number in range" value=${
arg3 || "40-50"
}></span>`;
const Count = `<span>n:<input class="templateCount" data-tip="Blobs to add, use hyphen to get a random number in range" value=${count || "1-2"}></span>`;
const blob = `${common}${TempY}${TempX}${Height}${Count}</div>`;
if (type === "Hill" || type === "Pit" || type === "Range" || type === "Trough") return blob;
if (type === "Strait") return `${common}<span>d:<select class="templateDist" data-tip="Strait direction"><option value="vertical" selected>vertical</option><option value="horizontal">horizontal</option></select></span><span>w:<input class="templateCount" data-tip="Strait width, use hyphen to get a random number in range" value=${count || "2-7"}></span></div>`;
if (type === "Add") return `${common}<span>to:<select class="templateDist" data-tip="Change only land or all cells"><option value="all" selected>all cells</option><option value="land">land only</option><option value="interval">interval</option></select></span><span>v:<input class="templateCount" data-tip="Add value to height of all cells (negative values are allowed)" type="number" value=${count || -10} min=-100 max=100 step=1></span></div>`;
if (type === "Multiply") return `${common}<span>to:<select class="templateDist" data-tip="Change only land or all cells"><option value="all" selected>all cells</option><option value="land">land only</option><option value="interval">interval</option></select></span><span>v:<input class="templateCount" data-tip="Multiply all cells Height by the value" type="number" value=${count || 1.1} min=0 max=10 step=.1></span></div>`;
if (type === "Smooth") return `${common}<span>f:<input class="templateCount" data-tip="Set smooth fraction. 1 - full smooth, 2 - half-smooth, etc." type="number" min=1 max=10 value=${count || 2}></span></div>`;
if (type === "Strait")
return `${common}<span>d:<select class="templateDist" data-tip="Strait direction"><option value="vertical" selected>vertical</option><option value="horizontal">horizontal</option></select></span><span>w:<input class="templateCount" data-tip="Strait width, use hyphen to get a random number in range" value=${
count || "2-7"
}></span></div>`;
if (type === "Add")
return `${common}<span>to:<select class="templateDist" data-tip="Change only land or all cells"><option value="all" selected>all cells</option><option value="land">land only</option><option value="interval">interval</option></select></span><span>v:<input class="templateCount" data-tip="Add value to height of all cells (negative values are allowed)" type="number" value=${
count || -10
} min=-100 max=100 step=1></span></div>`;
if (type === "Multiply")
return `${common}<span>to:<select class="templateDist" data-tip="Change only land or all cells"><option value="all" selected>all cells</option><option value="land">land only</option><option value="interval">interval</option></select></span><span>v:<input class="templateCount" data-tip="Multiply all cells Height by the value" type="number" value=${
count || 1.1
} min=0 max=10 step=.1></span></div>`;
if (type === "Smooth")
return `${common}<span>f:<input class="templateCount" data-tip="Set smooth fraction. 1 - full smooth, 2 - half-smooth, etc." type="number" min=1 max=10 value=${
count || 2
}></span></div>`;
}
function setRange(event) {
@ -1170,10 +1191,14 @@ function editHeightmap() {
}
function setConvertColorsNumber() {
prompt(`Please set maximum number of colors. <br>An actual number is usually lower and depends on color scheme`, {default: +convertColors.value, step: 1, min: 3, max: 255}, number => {
prompt(
`Please set maximum number of colors. <br>An actual number is usually lower and depends on color scheme`,
{default: +convertColors.value, step: 1, min: 3, max: 255},
number => {
convertColors.value = number;
heightsFromImage(number);
});
}
);
}
function setOverlayOpacity(v) {

153
modules/ui/hotkeys.js Normal file
View file

@ -0,0 +1,153 @@
"use strict";
// Hotkeys, see github.com/Azgaar/Fantasy-Map-Generator/wiki/Hotkeys
document.addEventListener("keydown", handleKeydown);
document.addEventListener("keyup", handleKeyup);
function handleKeydown(event) {
const {code, ctrlKey, altKey} = event;
if (altKey && !ctrlKey) event.preventDefault(); // disallow alt key combinations
if (ctrlKey && ["KeyS", "KeyC"].includes(code)) event.preventDefault(); // disallow CTRL + S and CTRL + C
if (["F1", "F2", "F6", "F9", "Tab"].includes(code)) event.preventDefault(); // disallow default Fn and Tab
}
function handleKeyup(event) {
if (!modules.editors) return; // if editors are not loaded, do nothing
const {tagName, contentEditable} = document.activeElement;
if (["INPUT", "SELECT", "TEXTAREA"].includes(tagName)) return; // don't trigger if user inputs text
if (tagName === "DIV" && contentEditable === "true") return; // don't trigger if user inputs a text
if (document.getSelection().toString()) return; // don't trigger if user selects text
event.stopPropagation();
const {code, key, ctrlKey, metaKey, shiftKey, altKey} = event;
const ctrl = ctrlKey || metaKey || key === "Control";
const shift = shiftKey || key === "Shift";
const alt = altKey || key === "Alt";
if (code === "F1") showInfo();
else if (code === "F2") regeneratePrompt("hotkey");
else if (code === "F6") quickSave();
else if (code === "F9") quickLoad();
else if (code === "Tab") toggleOptions(event);
else if (code === "Escape") closeAllDialogs();
else if (code === "Delete") removeElementOnKey();
else if (code === "KeyO" && document.getElementById("canvas3d")) toggle3dOptions();
else if (ctrl && code === "KeyQ") toggleSaveReminder();
else if (ctrl && code === "KeyS") dowloadMap();
else if (ctrl && code === "KeyC") saveToDropbox();
else if (ctrl && code === "KeyZ" && undo.offsetParent) undo.click();
else if (ctrl && code === "KeyY" && redo.offsetParent) redo.click();
else if (shift && code === "KeyH") editHeightmap();
else if (shift && code === "KeyB") editBiomes();
else if (shift && code === "KeyS") editStates();
else if (shift && code === "KeyP") editProvinces();
else if (shift && code === "KeyD") editDiplomacy();
else if (shift && code === "KeyC") editCultures();
else if (shift && code === "KeyN") editNamesbase();
else if (shift && code === "KeyZ") editZones();
else if (shift && code === "KeyR") editReligions();
else if (shift && code === "KeyY") openEmblemEditor();
else if (shift && code === "KeyQ") editUnits();
else if (shift && code === "KeyO") editNotes();
else if (shift && code === "KeyT") overviewBurgs();
else if (shift && code === "KeyV") overviewRivers();
else if (shift && code === "KeyM") overviewMilitary();
else if (shift && code === "KeyK") overviewMarkers();
else if (shift && code === "KeyE") viewCellDetails();
else if (key === "!") toggleAddBurg();
else if (key === "@") toggleAddLabel();
else if (key === "#") toggleAddRiver();
else if (key === "$") toggleAddRoute();
else if (key === "%") toggleAddMarker();
else if (alt && code === "KeyB") console.table(pack.burgs);
else if (alt && code === "KeyS") console.table(pack.states);
else if (alt && code === "KeyC") console.table(pack.cultures);
else if (alt && code === "KeyR") console.table(pack.religions);
else if (alt && code === "KeyF") console.table(pack.features);
else if (code === "KeyX") toggleTexture();
else if (code === "KeyH") toggleHeight();
else if (code === "KeyB") toggleBiomes();
else if (code === "KeyE") toggleCells();
else if (code === "KeyG") toggleGrid();
else if (code === "KeyO") toggleCoordinates();
else if (code === "KeyW") toggleCompass();
else if (code === "KeyV") toggleRivers();
else if (code === "KeyF") toggleRelief();
else if (code === "KeyC") toggleCultures();
else if (code === "KeyS") toggleStates();
else if (code === "KeyP") toggleProvinces();
else if (code === "KeyZ") toggleZones();
else if (code === "KeyD") toggleBorders();
else if (code === "KeyR") toggleReligions();
else if (code === "KeyU") toggleRoutes();
else if (code === "KeyT") toggleTemp();
else if (code === "KeyN") togglePopulation();
else if (code === "KeyJ") toggleIce();
else if (code === "KeyA") togglePrec();
else if (code === "KeyY") toggleEmblems();
else if (code === "KeyL") toggleLabels();
else if (code === "KeyI") toggleIcons();
else if (code === "KeyM") toggleMilitary();
else if (code === "KeyK") toggleMarkers();
else if (code === "Equal") toggleRulers();
else if (code === "Slash") toggleScaleBar();
else if (code === "ArrowLeft") zoom.translateBy(svg, 10, 0);
else if (code === "ArrowRight") zoom.translateBy(svg, -10, 0);
else if (code === "ArrowUp") zoom.translateBy(svg, 0, 10);
else if (code === "ArrowDown") zoom.translateBy(svg, 0, -10);
else if (key === "+" || key === "-") pressNumpadSign(key);
else if (key === "0") resetZoom(1000);
else if (key === "1") zoom.scaleTo(svg, 1);
else if (key === "2") zoom.scaleTo(svg, 2);
else if (key === "3") zoom.scaleTo(svg, 3);
else if (key === "4") zoom.scaleTo(svg, 4);
else if (key === "5") zoom.scaleTo(svg, 5);
else if (key === "6") zoom.scaleTo(svg, 6);
else if (key === "7") zoom.scaleTo(svg, 7);
else if (key === "8") zoom.scaleTo(svg, 8);
else if (key === "9") zoom.scaleTo(svg, 9);
else if (ctrl) toggleMode();
}
function pressNumpadSign(key) {
const change = key === "+" ? 1 : -1;
let brush = null;
if (brushRadius.offsetParent) brush = document.getElementById("brushRadius");
else if (biomesManuallyBrush.offsetParent) brush = document.getElementById("biomesManuallyBrush");
else if (statesManuallyBrush.offsetParent) brush = document.getElementById("statesManuallyBrush");
else if (provincesManuallyBrush.offsetParent) brush = document.getElementById("provincesManuallyBrush");
else if (culturesManuallyBrush.offsetParent) brush = document.getElementById("culturesManuallyBrush");
else if (zonesBrush.offsetParent) brush = document.getElementById("zonesBrush");
else if (religionsManuallyBrush.offsetParent) brush = document.getElementById("religionsManuallyBrush");
if (brush) {
const value = minmax(+brush.value + change, +brush.min, +brush.max);
brush.value = document.getElementById(brush.id + "Number").value = value;
return;
}
const scaleBy = key === "+" ? 1.2 : 0.8;
zoom.scaleBy(svg, scaleBy); // if no brush elements displayed, zoom map
}
function toggleMode() {
if (zonesRemove.offsetParent) {
zonesRemove.classList.contains("pressed") ? zonesRemove.classList.remove("pressed") : zonesRemove.classList.add("pressed");
}
}
function removeElementOnKey() {
const fastDelete = Array.from(document.querySelectorAll("[role='dialog'] .fastDelete")).find(dialog => dialog.style.display !== "none");
if (fastDelete) fastDelete.click();
const visibleDialogs = Array.from(document.querySelectorAll("[role='dialog']")).filter(dialog => dialog.style.display !== "none");
if (!visibleDialogs.length) return;
visibleDialogs.forEach(dialog => dialog.querySelectorAll("button").forEach(button => button.textContent === "Remove" && button.click()));
}
function closeAllDialogs() {
closeDialogs();
hideOptions();
}

View file

@ -11,7 +11,9 @@ function editLabel() {
viewbox.on("touchmove mousemove", showEditorTips);
$("#labelEditor").dialog({
title: "Edit Label", resizable: false, width: fitContent(),
title: "Edit Label",
resizable: false,
width: fitContent(),
position: {my: "center top+10", at: "bottom", of: text, collision: "fit"},
close: closeLabelEditor
});
@ -49,8 +51,8 @@ function editLabel() {
function showEditorTips() {
showMainTip();
if (d3.event.target.parentNode.parentNode.id === elSelected.attr("id")) tip("Drag to shift the label"); else
if (d3.event.target.parentNode.id === "controlPoints") {
if (d3.event.target.parentNode.parentNode.id === elSelected.attr("id")) tip("Drag to shift the label");
else if (d3.event.target.parentNode.id === "controlPoints") {
if (d3.event.target.tagName === "circle") tip("Drag to move, click to delete the control point");
if (d3.event.target.tagName === "path") tip("Click to add a control point");
}
@ -58,10 +60,18 @@ function editLabel() {
function selectLabelGroup(text) {
const group = text.parentNode.id;
if (group === "states" || group === "burgLabels") {
document.getElementById("labelGroupShow").style.display = "none";
return;
}
hideGroupSection();
const select = document.getElementById("labelGroupSelect");
select.options.length = 0; // remove all options
labels.selectAll(":scope > g").each(function () {
if (this.id === "states") return;
if (this.id === "burgLabels") return;
select.options.add(new Option(this.id, this.id, false, this.id === group));
});
@ -81,12 +91,19 @@ function editLabel() {
const l = path.getTotalLength();
if (!l) return;
const increment = l / Math.max(Math.ceil(l / 200), 2);
for (let i=0; i <= l; i += increment) {addControlPoint(path.getPointAtLength(i));}
for (let i = 0; i <= l; i += increment) {
addControlPoint(path.getPointAtLength(i));
}
}
function addControlPoint(point) {
debug.select("#controlPoints").append("circle")
.attr("cx", point.x).attr("cy", point.y).attr("r", 2.5).attr("stroke-width", .8)
debug
.select("#controlPoints")
.append("circle")
.attr("cx", point.x)
.attr("cy", point.y)
.attr("r", 2.5)
.attr("stroke-width", 0.8)
.call(d3.drag().on("drag", dragControlPoint))
.on("click", clickControlPoint);
}
@ -101,7 +118,10 @@ function editLabel() {
const path = document.getElementById("textPath_" + elSelected.attr("id"));
lineGen.curve(d3.curveBundle.beta(1));
const points = [];
debug.select("#controlPoints").selectAll("circle").each(function() {
debug
.select("#controlPoints")
.selectAll("circle")
.each(function () {
points.push([this.getAttribute("cx"), this.getAttribute("cy")]);
});
const d = round(lineGen(points));
@ -118,7 +138,10 @@ function editLabel() {
const point = d3.mouse(this);
const dists = [];
debug.select("#controlPoints").selectAll("circle").each(function() {
debug
.select("#controlPoints")
.selectAll("circle")
.each(function () {
const x = +this.getAttribute("cx");
const y = +this.getAttribute("cy");
dists.push((point[0] - x) ** 2 + (point[1] - y) ** 2);
@ -129,12 +152,18 @@ function editLabel() {
const sorted = dists.slice(0).sort((a, b) => a - b);
const closest = dists.indexOf(sorted[0]);
const next = dists.indexOf(sorted[1]);
if (closest <= next) index = closest+1; else index = next+1;
if (closest <= next) index = closest + 1;
else index = next + 1;
}
const before = ":nth-child(" + (index + 2) + ")";
debug.select("#controlPoints").insert("circle", before)
.attr("cx", point[0]).attr("cy", point[1]).attr("r", 2.5).attr("stroke-width", .8)
debug
.select("#controlPoints")
.insert("circle", before)
.attr("cx", point[0])
.attr("cy", point[1])
.attr("r", 2.5)
.attr("stroke-width", 0.8)
.call(d3.drag().on("drag", dragControlPoint))
.on("click", clickControlPoint);
@ -143,23 +172,25 @@ function editLabel() {
function dragLabel() {
const tr = parseTransform(elSelected.attr("transform"));
const dx = +tr[0] - d3.event.x, dy = +tr[1] - d3.event.y;
const dx = +tr[0] - d3.event.x,
dy = +tr[1] - d3.event.y;
d3.event.on("drag", function () {
const x = d3.event.x, y = d3.event.y;
const transform = `translate(${(dx+x)},${(dy+y)})`;
const x = d3.event.x,
y = d3.event.y;
const transform = `translate(${dx + x},${dy + y})`;
elSelected.attr("transform", transform);
debug.select("#controlPoints").attr("transform", transform);
});
}
function showGroupSection() {
document.querySelectorAll("#labelEditor > button").forEach(el => el.style.display = "none");
document.querySelectorAll("#labelEditor > button").forEach(el => (el.style.display = "none"));
document.getElementById("labelGroupSection").style.display = "inline-block";
}
function hideGroupSection() {
document.querySelectorAll("#labelEditor > button").forEach(el => el.style.display = "inline-block");
document.querySelectorAll("#labelEditor > button").forEach(el => (el.style.display = "inline-block"));
document.getElementById("labelGroupSection").style.display = "none";
document.getElementById("labelGroupInput").style.display = "none";
document.getElementById("labelGroupInput").value = "";
@ -182,8 +213,14 @@ function editLabel() {
}
function createNewGroup() {
if (!this.value) {tip("Please provide a valid group name"); return;}
const group = this.value.toLowerCase().replace(/ /g, "_").replace(/[^\w\s]/gi, "");
if (!this.value) {
tip("Please provide a valid group name");
return;
}
const group = this.value
.toLowerCase()
.replace(/ /g, "_")
.replace(/[^\w\s]/gi, "");
if (document.getElementById(group)) {
tip("Element with this id already exists. Please provide a unique name", false, "error");
@ -223,47 +260,54 @@ function editLabel() {
alertMessage.innerHTML = `Are you sure you want to remove
${basic ? "all elements in the group" : "the entire label group"}?
<br><br>Labels to be removed: ${count}`;
$("#alert").dialog({resizable: false, title: "Remove route group",
$("#alert").dialog({
resizable: false,
title: "Remove route group",
buttons: {
Remove: function () {
$(this).dialog("close");
$("#labelEditor").dialog("close");
hideGroupSection();
labels.select("#"+group).selectAll("text").each(function() {
labels
.select("#" + group)
.selectAll("text")
.each(function () {
document.getElementById("textPath_" + this.id).remove();
this.remove();
});
if (!basic) labels.select("#" + group).remove();
},
Cancel: function() {$(this).dialog("close");}
Cancel: function () {
$(this).dialog("close");
}
}
});
}
function showTextSection() {
document.querySelectorAll("#labelEditor > button").forEach(el => el.style.display = "none");
document.querySelectorAll("#labelEditor > button").forEach(el => (el.style.display = "none"));
document.getElementById("labelTextSection").style.display = "inline-block";
}
function hideTextSection() {
document.querySelectorAll("#labelEditor > button").forEach(el => el.style.display = "inline-block");
document.querySelectorAll("#labelEditor > button").forEach(el => (el.style.display = "inline-block"));
document.getElementById("labelTextSection").style.display = "none";
}
function changeText() {
const input = document.getElementById("labelText").value;
const el = elSelected.select("textPath").node();
const example = d3.select(elSelected.node().parentNode)
.append("text").attr("x", 0).attr("x", 0)
.attr("font-size", el.getAttribute("font-size")).node();
const example = d3.select(elSelected.node().parentNode).append("text").attr("x", 0).attr("x", 0).attr("font-size", el.getAttribute("font-size")).node();
const lines = input.split("|");
const top = (lines.length - 1) / -2; // y offset
const inner = lines.map((l, d) => {
const inner = lines
.map((l, d) => {
example.innerHTML = l;
const left = example.getBBox().width / -2; // x offset
return `<tspan x="${left}px" dy="${d ? 1 : top}em">${l}</tspan>`;
}).join("");
})
.join("");
el.innerHTML = inner;
example.remove();
@ -293,12 +337,12 @@ function editLabel() {
}
function showSizeSection() {
document.querySelectorAll("#labelEditor > button").forEach(el => el.style.display = "none");
document.querySelectorAll("#labelEditor > button").forEach(el => (el.style.display = "none"));
document.getElementById("labelSizeSection").style.display = "inline-block";
}
function hideSizeSection() {
document.querySelectorAll("#labelEditor > button").forEach(el => el.style.display = "inline-block");
document.querySelectorAll("#labelEditor > button").forEach(el => (el.style.display = "inline-block"));
document.getElementById("labelSizeSection").style.display = "none";
}
@ -329,7 +373,9 @@ function editLabel() {
function removeLabel() {
alertMessage.innerHTML = "Are you sure you want to remove the label?";
$("#alert").dialog({resizable: false, title: "Remove label",
$("#alert").dialog({
resizable: false,
title: "Remove label",
buttons: {
Remove: function () {
$(this).dialog("close");
@ -337,7 +383,9 @@ function editLabel() {
elSelected.remove();
$("#labelEditor").dialog("close");
},
Cancel: function() {$(this).dialog("close");}
Cancel: function () {
$(this).dialog("close");
}
}
});
}

View file

@ -47,8 +47,7 @@ function changePreset(preset) {
.querySelectorAll("li")
.forEach(function (e) {
if (layers.includes(e.id) && !layerIsOn(e.id)) e.click();
// turn on
else if (!layers.includes(e.id) && layerIsOn(e.id)) e.click(); // turn off
else if (!layers.includes(e.id) && layerIsOn(e.id)) e.click();
});
layersPreset.value = preset;
localStorage.setItem("preset", preset);
@ -121,6 +120,7 @@ function restoreLayers() {
if (layerIsOn("toggleReligions")) drawReligions();
if (layerIsOn("toggleIce")) drawIce();
if (layerIsOn("toggleEmblems")) drawEmblems();
if (layerIsOn("toggleMarkers")) drawMarkers();
// some layers are rendered each time, remove them if they are not on
if (!layerIsOn("toggleBorders")) borders.selectAll("path").remove();
@ -196,7 +196,8 @@ function drawHeightmap() {
for (const i of d3.range(20, 101)) {
if (paths[i].length < 10) continue;
const color = getColor(i, scheme);
if (terracing) terrs.append("path").attr("d", paths[i]).attr("transform", "translate(.7,1.4)").attr("fill", d3.color(color).darker(terracing)).attr("data-height", i);
if (terracing)
terrs.append("path").attr("d", paths[i]).attr("transform", "translate(.7,1.4)").attr("fill", d3.color(color).darker(terracing)).attr("data-height", i);
terrs.append("path").attr("d", paths[i]).attr("fill", color).attr("data-height", i);
}
@ -798,7 +799,10 @@ function drawReligions() {
if (!vArray[r]) vArray[r] = [];
vArray[r].push(points);
body[r] += "M" + points.join("L");
gap[r] += "M" + vertices.p[chain[0][0]] + chain.reduce((r2, v, i, d) => (!i ? r2 : !v[2] ? r2 + "L" + vertices.p[v[0]] : d[i + 1] && !d[i + 1][2] ? r2 + "M" + vertices.p[v[0]] : r2), "");
gap[r] +=
"M" +
vertices.p[chain[0][0]] +
chain.reduce((r2, v, i, d) => (!i ? r2 : !v[2] ? r2 + "L" + vertices.p[v[0]] : d[i + 1] && !d[i + 1][2] ? r2 + "M" + vertices.p[v[0]] : r2), "");
}
const bodyData = body.map((p, i) => [p.length > 10 ? p : null, i, religions[i].color]).filter(d => d[0]);
@ -965,7 +969,14 @@ function drawStates() {
const bodyString = bodyData.map(d => `<path id="state${d[1]}" d="${d[0]}" fill="${d[2]}" stroke="none"/>`).join("");
const gapString = gapData.map(d => `<path id="state-gap${d[1]}" d="${d[0]}" fill="none" stroke="${d[2]}"/>`).join("");
const clipString = bodyData.map(d => `<clipPath id="state-clip${d[1]}"><use href="#state${d[1]}"/></clipPath>`).join("");
const haloString = haloData.map(d => `<path id="state-border${d[1]}" d="${d[0]}" clip-path="url(#state-clip${d[1]})" stroke="${d3.color(d[2]) ? d3.color(d[2]).darker().hex() : "#666666"}"/>`).join("");
const haloString = haloData
.map(
d =>
`<path id="state-border${d[1]}" d="${d[0]}" clip-path="url(#state-clip${d[1]})" stroke="${
d3.color(d[2]) ? d3.color(d[2]).darker().hex() : "#666666"
}"/>`
)
.join("");
statesBody.html(bodyString + gapString);
defs.select("#statePaths").html(clipString);
@ -1217,7 +1228,10 @@ function getProvincesVertices() {
if (!vArray[p]) vArray[p] = [];
vArray[p].push(points);
body[p] += "M" + points.join("L");
gap[p] += "M" + vertices.p[chain[0][0]] + chain.reduce((r, v, i, d) => (!i ? r : !v[2] ? r + "L" + vertices.p[v[0]] : d[i + 1] && !d[i + 1][2] ? r + "M" + vertices.p[v[0]] : r), "");
gap[p] +=
"M" +
vertices.p[chain[0][0]] +
chain.reduce((r, v, i, d) => (!i ? r : !v[2] ? r + "L" + vertices.p[v[0]] : d[i + 1] && !d[i + 1][2] ? r + "M" + vertices.p[v[0]] : r), "");
}
// find province visual center
@ -1298,7 +1312,12 @@ function drawGrid() {
const maxWidth = Math.max(+mapWidthInput.value, graphWidth);
const maxHeight = Math.max(+mapHeightInput.value, graphHeight);
d3.select(pattern).attr("stroke", stroke).attr("stroke-width", width).attr("stroke-dasharray", dasharray).attr("stroke-linecap", linecap).attr("patternTransform", tr);
d3.select(pattern)
.attr("stroke", stroke)
.attr("stroke-width", width)
.attr("stroke-dasharray", dasharray)
.attr("stroke-linecap", linecap)
.attr("patternTransform", tr);
gridOverlay
.append("rect")
.attr("width", maxWidth)
@ -1416,8 +1435,8 @@ function toggleTexture(event) {
turnButtonOn("toggleTexture");
// append default texture image selected by default. Don't append on load to not harm performance
if (!texture.selectAll("*").size()) {
const x = +styleTextureShiftX.value,
y = +styleTextureShiftY.value;
const x = +styleTextureShiftX.value;
const y = +styleTextureShiftY.value;
const image = texture
.append("image")
.attr("id", "textureImage")
@ -1425,18 +1444,14 @@ function toggleTexture(event) {
.attr("y", y)
.attr("width", graphWidth - x)
.attr("height", graphHeight - y)
.attr("xlink:href", getDefaultTexture())
.attr("preserveAspectRatio", "xMidYMid slice");
if (styleTextureInput.value !== "default") getBase64(styleTextureInput.value, base64 => image.attr("xlink:href", base64));
getBase64(styleTextureInput.value, base64 => image.attr("xlink:href", base64));
}
$("#texture").fadeIn();
zoom.scaleBy(svg, 1.00001); // enforce browser re-draw
if (event && isCtrlClick(event)) editStyle("texture");
} else {
if (event && isCtrlClick(event)) {
editStyle("texture");
return;
}
if (event && isCtrlClick(event)) return editStyle("texture");
$("#texture").fadeOut();
turnButtonOff("toggleTexture");
}
@ -1505,18 +1520,53 @@ function toggleMilitary() {
function toggleMarkers(event) {
if (!layerIsOn("toggleMarkers")) {
turnButtonOn("toggleMarkers");
$("#markers").fadeIn();
drawMarkers();
if (event && isCtrlClick(event)) editStyle("markers");
} else {
if (event && isCtrlClick(event)) {
editStyle("markers");
return;
}
$("#markers").fadeOut();
if (event && isCtrlClick(event)) return editStyle("markers");
markers.selectAll("*").remove();
turnButtonOff("toggleMarkers");
}
}
function drawMarkers() {
const rescale = +markers.attr("rescale");
const pinned = +markers.attr("pinned");
const markersData = pinned ? pack.markers.filter(({pinned}) => pinned) : pack.markers;
const html = markersData.map(marker => drawMarker(marker, rescale));
markers.html(html.join(""));
}
const getPin = (shape = "bubble", fill = "#fff", stroke = "#000") => {
if (shape === "bubble")
return `<path d="M6,19 l9,10 L24,19" fill="${stroke}" stroke="none" /><circle cx="15" cy="15" r="10" fill="${fill}" stroke="${stroke}"/>`;
if (shape === "pin")
return `<path d="m 15,3 c -5.5,0 -9.7,4.09 -9.7,9.3 0,6.8 9.7,17 9.7,17 0,0 9.7,-10.2 9.7,-17 C 24.7,7.09 20.5,3 15,3 Z" fill="${fill}" stroke="${stroke}"/>`;
if (shape === "square") return `<path d="m 20,25 -5,4 -5,-4 z" fill="${stroke}"/><path d="M 5,5 H 25 V 25 H 5 Z" fill="${fill}" stroke="${stroke}"/>`;
if (shape === "squarish") return `<path d="m 5,5 h 20 v 20 h -6 l -4,4 -4,-4 H 5 Z" fill="${fill}" stroke="${stroke}" />`;
if (shape === "diamond") return `<path d="M 2,15 15,1 28,15 15,29 Z" fill="${fill}" stroke="${stroke}" />`;
if (shape === "hex") return `<path d="M 15,29 4.61,21 V 9 L 15,3 25.4,9 v 12 z" fill="${fill}" stroke="${stroke}" />`;
if (shape === "hexy") return `<path d="M 15,29 6,21 5,8 15,4 25,8 24,21 Z" fill="${fill}" stroke="${stroke}" />`;
if (shape === "shieldy") return `<path d="M 15,29 6,21 5,7 c 0,0 5,-3 10,-3 5,0 10,3 10,3 l -1,14 z" fill="${fill}" stroke="${stroke}" />`;
if (shape === "shield") return `<path d="M 4.6,5.2 H 25 v 6.7 A 20.3,20.4 0 0 1 15,29 20.3,20.4 0 0 1 4.6,11.9 Z" fill="${fill}" stroke="${stroke}" />`;
if (shape === "pentagon") return `<path d="M 4,16 9,4 h 12 l 5,12 -11,13 z" fill="${fill}" stroke="${stroke}" />`;
if (shape === "heptagon") return `<path d="M 15,29 6,22 4,12 10,4 h 10 l 6,8 -2,10 z" fill="${fill}" stroke="${stroke}" />`;
if (shape === "circle") return `<circle cx="15" cy="15" r="11" fill="${fill}" stroke="${stroke}" />`;
if (shape === "no") return "";
};
function drawMarker(marker, rescale = 1) {
const {i, icon, x, y, dx = 50, dy = 50, px = 12, size = 30, pin, fill, stroke} = marker;
const id = `marker${i}`;
const zoomSize = rescale ? Math.max(rn(size / 5 + 24 / scale, 2), 1) : size;
const viewX = rn(x - zoomSize / 2, 1);
const viewY = rn(y - zoomSize, 1);
const pinHTML = getPin(pin, fill, stroke);
return `<svg id="${id}" viewbox="0 0 30 30" width="${zoomSize}" height="${zoomSize}" x="${viewX}" y="${viewY}"><g>${pinHTML}</g><text x="${dx}%" y="${dy}%" font-size="${px}px" >${icon}</text></svg>`;
}
function toggleLabels(event) {
if (!layerIsOn("toggleLabels")) {
turnButtonOn("toggleLabels");
@ -1620,21 +1670,21 @@ function drawEmblems() {
const validBurgs = burgs.filter(b => b.i && !b.removed && b.coa && b.coaSize != 0);
const getStateEmblemsSize = () => {
const startSize = Math.min(Math.max((graphHeight + graphWidth) / 40, 10), 100);
const startSize = minmax((graphHeight + graphWidth) / 40, 10, 100);
const statesMod = 1 + validStates.length / 100 - (15 - validStates.length) / 200; // states number modifier
const sizeMod = +document.getElementById("emblemsStateSizeInput").value || 1;
return rn((startSize / statesMod) * sizeMod); // target size ~50px on 1536x754 map with 15 states
};
const getProvinceEmblemsSize = () => {
const startSize = Math.min(Math.max((graphHeight + graphWidth) / 100, 5), 70);
const startSize = minmax((graphHeight + graphWidth) / 100, 5, 70);
const provincesMod = 1 + validProvinces.length / 1000 - (115 - validProvinces.length) / 1000; // states number modifier
const sizeMod = +document.getElementById("emblemsProvinceSizeInput").value || 1;
return rn((startSize / provincesMod) * sizeMod); // target size ~20px on 1536x754 map with 115 provinces
};
const getBurgEmblemSize = () => {
const startSize = Math.min(Math.max((graphHeight + graphWidth) / 185, 2), 50);
const startSize = minmax((graphHeight + graphWidth) / 185, 2, 50);
const burgsMod = 1 + validBurgs.length / 1000 - (450 - validBurgs.length) / 1000; // states number modifier
const sizeMod = +document.getElementById("emblemsBurgSizeInput").value || 1;
return rn((startSize / burgsMod) * sizeMod); // target size ~8.5px on 1536x754 map with 450 burgs
@ -1684,15 +1734,21 @@ function drawEmblems() {
}
const burgNodes = nodes.filter(node => node.type === "burg");
const burgString = burgNodes.map(d => `<use data-i="${d.i}" x="${rn(d.x - d.shift)}" y="${rn(d.y - d.shift)}" width="${d.size}em" height="${d.size}em"/>`).join("");
const burgString = burgNodes
.map(d => `<use data-i="${d.i}" x="${rn(d.x - d.shift)}" y="${rn(d.y - d.shift)}" width="${d.size}em" height="${d.size}em"/>`)
.join("");
emblems.select("#burgEmblems").attr("font-size", sizeBurgs).html(burgString);
const provinceNodes = nodes.filter(node => node.type === "province");
const provinceString = provinceNodes.map(d => `<use data-i="${d.i}" x="${rn(d.x - d.shift)}" y="${rn(d.y - d.shift)}" width="${d.size}em" height="${d.size}em"/>`).join("");
const provinceString = provinceNodes
.map(d => `<use data-i="${d.i}" x="${rn(d.x - d.shift)}" y="${rn(d.y - d.shift)}" width="${d.size}em" height="${d.size}em"/>`)
.join("");
emblems.select("#provinceEmblems").attr("font-size", sizeProvinces).html(provinceString);
const stateNodes = nodes.filter(node => node.type === "state");
const stateString = stateNodes.map(d => `<use data-i="${d.i}" x="${rn(d.x - d.shift)}" y="${rn(d.y - d.shift)}" width="${d.size}em" height="${d.size}em"/>`).join("");
const stateString = stateNodes
.map(d => `<use data-i="${d.i}" x="${rn(d.x - d.shift)}" y="${rn(d.y - d.shift)}" width="${d.size}em" height="${d.size}em"/>`)
.join("");
emblems.select("#stateEmblems").attr("font-size", sizeStates).html(stateString);
invokeActiveZooming();

View file

@ -1,287 +1,260 @@
"use strict";
function editMarker() {
function editMarker(markerI) {
if (customization) return;
closeDialogs("#markerEditor, .stable");
$("#markerEditor").dialog();
closeDialogs(".stable");
const [element, marker] = getElement(markerI, d3.event);
if (!marker || !element) return;
elSelected = d3.select(element).raise().call(d3.drag().on("start", dragMarker)).classed("draggable", true);
if (document.getElementById("notesEditor").offsetParent) editNotes(element.id, element.id);
// dom elements
const markerType = document.getElementById("markerType");
const markerIcon = document.getElementById("markerIcon");
const markerIconSelect = document.getElementById("markerIconSelect");
const markerIconSize = document.getElementById("markerIconSize");
const markerIconShiftX = document.getElementById("markerIconShiftX");
const markerIconShiftY = document.getElementById("markerIconShiftY");
const markerSize = document.getElementById("markerSize");
const markerPin = document.getElementById("markerPin");
const markerFill = document.getElementById("markerFill");
const markerStroke = document.getElementById("markerStroke");
const markerNotes = document.getElementById("markerNotes");
const markerLock = document.getElementById("markerLock");
const addMarker = document.getElementById("addMarker");
const markerAdd = document.getElementById("markerAdd");
const markerRemove = document.getElementById("markerRemove");
elSelected = d3.select(d3.event.target).call(d3.drag().on("start", dragMarker)).classed("draggable", true);
updateInputs();
if (modules.editMarker) return;
modules.editMarker = true;
$("#markerEditor").dialog({
title: "Edit Marker", resizable: false,
position: {my: "center top+30", at: "bottom", of: d3.event, collision: "fit"},
title: "Edit Marker",
resizable: false,
position: {my: "left top", at: "left+10 top+10", of: "svg", collision: "fit"},
close: closeMarkerEditor
});
// add listeners
document.getElementById("markerGroup").addEventListener("click", toggleGroupSection);
document.getElementById("markerAddGroup").addEventListener("click", toggleGroupInput);
document.getElementById("markerSelectGroup").addEventListener("change", changeGroup);
document.getElementById("markerInputGroup").addEventListener("change", createGroup);
document.getElementById("markerRemoveGroup").addEventListener("click", removeGroup);
const listeners = [
listen(markerType, "change", changeMarkerType),
listen(markerIcon, "input", changeMarkerIcon),
listen(markerIconSelect, "click", selectMarkerIcon),
listen(markerIconSize, "input", changeIconSize),
listen(markerIconShiftX, "input", changeIconShiftX),
listen(markerIconShiftY, "input", changeIconShiftY),
listen(markerSize, "input", changeMarkerSize),
listen(markerPin, "change", changeMarkerPin),
listen(markerFill, "input", changePinFill),
listen(markerStroke, "input", changePinStroke),
listen(markerNotes, "click", editMarkerLegend),
listen(markerLock, "click", toggleMarkerLock),
listen(markerAdd, "click", toggleAddMarker),
listen(markerRemove, "click", confirmMarkerDeletion)
];
document.getElementById("markerIcon").addEventListener("click", toggleIconSection);
document.getElementById("markerIconSize").addEventListener("input", changeIconSize);
document.getElementById("markerIconShiftX").addEventListener("input", changeIconShiftX);
document.getElementById("markerIconShiftY").addEventListener("input", changeIconShiftY);
document.getElementById("markerIconSelect").addEventListener("click", selectMarkerIcon);
function getElement(markerI, event) {
if (event) {
const element = event.target?.closest("svg");
const marker = pack.markers.find(({i}) => Number(element.id.slice(6)) === i);
return [element, marker];
}
document.getElementById("markerStyle").addEventListener("click", toggleStyleSection);
document.getElementById("markerSize").addEventListener("input", changeMarkerSize);
document.getElementById("markerBaseStroke").addEventListener("input", changePinStroke);
document.getElementById("markerBaseFill").addEventListener("input", changePinFill);
document.getElementById("markerIconStrokeWidth").addEventListener("input", changeIconStrokeWidth);
document.getElementById("markerIconStroke").addEventListener("input", changeIconStroke);
document.getElementById("markerIconFill").addEventListener("input", changeIconFill);
const element = document.getElementById(`marker${markerI}`);
const marker = pack.markers.find(({i}) => i === markerI);
return [element, marker];
}
document.getElementById("markerToggleBubble").addEventListener("click", togglePinVisibility);
document.getElementById("markerLegendButton").addEventListener("click", editMarkerLegend);
document.getElementById("markerAdd").addEventListener("click", toggleAddMarker);
document.getElementById("markerRemove").addEventListener("click", removeMarker);
updateGroupOptions();
function getSameTypeMarkers() {
const currentType = marker.type;
if (!currentType) return [marker];
return pack.markers.filter(({type}) => type === currentType);
}
function dragMarker() {
const tr = parseTransform(this.getAttribute("transform"));
const x = +tr[0] - d3.event.x, y = +tr[1] - d3.event.y;
const dx = +this.getAttribute("x") - d3.event.x;
const dy = +this.getAttribute("y") - d3.event.y;
d3.event.on("drag", function () {
const transform = `translate(${(x + d3.event.x)},${(y + d3.event.y)})`;
this.setAttribute("transform", transform);
const {x, y} = d3.event;
this.setAttribute("x", dx + x);
this.setAttribute("y", dy + y);
});
d3.event.on("end", function () {
const {x, y} = d3.event;
this.setAttribute("x", rn(dx + x, 2));
this.setAttribute("y", rn(dy + y, 2));
const size = marker.size || 30;
const zoomSize = Math.max(rn(size / 5 + 24 / scale, 2), 1);
marker.x = rn(x + dx + zoomSize / 2, 1);
marker.y = rn(y + dy + zoomSize, 1);
marker.cell = findCell(marker.x, marker.y);
});
}
function updateInputs() {
const id = elSelected.attr("data-id");
const symbol = d3.select("#defs-markers").select(id);
const icon = symbol.select("text");
const {icon, type = "", size = 30, dx = 50, dy = 50, px = 12, stroke = "#000000", fill = "#ffffff", pin = "bubble", lock} = marker;
markerSelectGroup.value = id.slice(1);
markerIconSize.value = parseFloat(icon.attr("font-size"));
markerIconShiftX.value = parseFloat(icon.attr("x"));
markerIconShiftY.value = parseFloat(icon.attr("y"));
markerType.value = type;
markerIcon.value = icon;
markerIconSize.value = px;
markerIconShiftX.value = dx;
markerIconShiftY.value = dy;
markerSize.value = size;
markerPin.value = pin;
markerFill.value = fill;
markerStroke.value = stroke;
markerSize.value = elSelected.attr("data-size");
markerBaseStroke.value = symbol.select("path").attr("fill");
markerBaseFill.value = symbol.select("circle").attr("fill");
markerIconStrokeWidth.value = icon.attr("stroke-width");
markerIconStroke.value = icon.attr("stroke");
markerIconFill.value = icon.attr("fill");
markerToggleBubble.className = symbol.select("circle").attr("opacity") === "0" ? "icon-info" : "icon-info-circled";
markerIconSelect.innerHTML = icon.text();
markerLock.className = lock ? "icon-lock" : "icon-lock-open";
}
function toggleGroupSection() {
if (markerGroupSection.style.display === "inline-block") {
markerEditor.querySelectorAll("button:not(#markerGroup)").forEach(b => b.style.display = "inline-block");
markerGroupSection.style.display = "none";
} else {
markerEditor.querySelectorAll("button:not(#markerGroup)").forEach(b => b.style.display = "none");
markerGroupSection.style.display = "inline-block";
}
function changeMarkerType() {
marker.type = this.value;
}
function updateGroupOptions() {
markerSelectGroup.innerHTML = "";
d3.select("#defs-markers").selectAll("symbol").each(function() {
markerSelectGroup.options.add(new Option(this.id, this.id));
function changeMarkerIcon() {
const icon = this.value;
getSameTypeMarkers().forEach(marker => {
marker.icon = icon;
redrawIcon(marker);
});
markerSelectGroup.value = elSelected.attr("data-id").slice(1);
}
function toggleGroupInput() {
if (markerInputGroup.style.display === "inline-block") {
markerSelectGroup.style.display = "inline-block";
markerInputGroup.style.display = "none";
} else {
markerSelectGroup.style.display = "none";
markerInputGroup.style.display = "inline-block";
markerInputGroup.focus();
}
}
function changeGroup() {
elSelected.attr("xlink:href", "#"+this.value);
elSelected.attr("data-id", "#"+this.value);
}
function createGroup() {
let newGroup = this.value.toLowerCase().replace(/ /g, "_").replace(/[^\w\s]/gi, "");
if (Number.isFinite(+newGroup.charAt(0))) newGroup = "m" + newGroup;
if (document.getElementById(newGroup)) {
tip("Element with this id already exists. Please provide a unique name", false, "error");
return;
}
markerInputGroup.value = "";
// clone old group assigning new id
const id = elSelected.attr("data-id");
const clone = d3.select("#defs-markers").select(id).node().cloneNode(true);
clone.id = newGroup;
document.getElementById("defs-markers").insertBefore(clone, null);
elSelected.attr("xlink:href", "#"+newGroup).attr("data-id", "#"+newGroup);
// select new group
markerSelectGroup.options.add(new Option(newGroup, newGroup, false, true));
toggleGroupInput();
}
function removeGroup() {
const id = elSelected.attr("data-id");
const used = document.querySelectorAll("use[data-id='"+id+"']");
const count = used.length === 1 ? "1 element" : used.length + " elements";
alertMessage.innerHTML = "Are you sure you want to remove all markers of that type (" + count + ")?";
$("#alert").dialog({resizable: false, title: "Remove marker type",
buttons: {
Remove: function() {
$(this).dialog("close");
if (id !== "#marker0") d3.select("#defs-markers").select(id).remove();
used.forEach(e => {
const index = notes.findIndex(n => n.id === e.id);
if (index != -1) notes.splice(index, 1);
e.remove();
});
updateGroupOptions();
updateGroupOptions();
$("#markerEditor").dialog("close");
},
Cancel: function() {$(this).dialog("close");}
}
});
}
function toggleIconSection() {
if (markerIconSection.style.display === "inline-block") {
markerEditor.querySelectorAll("button:not(#markerIcon)").forEach(b => b.style.display = "inline-block");
markerIconSection.style.display = "none";
markerIconSelect.style.display = "none";
} else {
markerEditor.querySelectorAll("button:not(#markerIcon)").forEach(b => b.style.display = "none");
markerIconSection.style.display = "inline-block";
markerIconSelect.style.display = "inline-block";
}
}
function selectMarkerIcon() {
selectIcon(this.innerHTML, v => {
this.innerHTML = v;
const id = elSelected.attr("data-id");
d3.select("#defs-markers").select(id).select("text").text(v);
selectIcon(marker.icon, icon => {
markerIcon.value = icon;
getSameTypeMarkers().forEach(marker => {
marker.icon = icon;
redrawIcon(marker);
});
});
}
function changeIconSize() {
const id = elSelected.attr("data-id");
d3.select("#defs-markers").select(id).select("text").attr("font-size", this.value + "px");
const px = +this.value;
getSameTypeMarkers().forEach(marker => {
marker.px = px;
redrawIcon(marker);
});
}
function changeIconShiftX() {
const id = elSelected.attr("data-id");
d3.select("#defs-markers").select(id).select("text").attr("x", this.value + "%");
const dx = +this.value;
getSameTypeMarkers().forEach(marker => {
marker.dx = dx;
redrawIcon(marker);
});
}
function changeIconShiftY() {
const id = elSelected.attr("data-id");
d3.select("#defs-markers").select(id).select("text").attr("y", this.value + "%");
}
function toggleStyleSection() {
if (markerStyleSection.style.display === "inline-block") {
markerEditor.querySelectorAll("button:not(#markerStyle)").forEach(b => b.style.display = "inline-block");
markerStyleSection.style.display = "none";
} else {
markerEditor.querySelectorAll("button:not(#markerStyle)").forEach(b => b.style.display = "none");
markerStyleSection.style.display = "inline-block";
}
const dy = +this.value;
getSameTypeMarkers().forEach(marker => {
marker.dy = dy;
redrawIcon(marker);
});
}
function changeMarkerSize() {
const id = elSelected.attr("data-id");
document.querySelectorAll("use[data-id='"+id+"']").forEach(e => {
const x = +e.dataset.x, y = +e.dataset.y;
const desired = e.dataset.size = +markerSize.value;
const size = Math.max(desired * 5 + 25 / scale, 1);
const size = +this.value;
const rescale = +markers.attr("rescale");
e.setAttribute("x", x - size / 2);
e.setAttribute("y", y - size / 2);
e.setAttribute("width", size);
e.setAttribute("height", size);
getSameTypeMarkers().forEach(marker => {
marker.size = size;
const {i, x, y, hidden} = marker;
const el = !hidden && document.getElementById(`marker${i}`);
if (!el) return;
const zoomedSize = rescale ? Math.max(rn(size / 5 + 24 / scale, 2), 1) : size;
el.setAttribute("width", zoomedSize);
el.setAttribute("height", zoomedSize);
el.setAttribute("x", rn(x - zoomedSize / 2, 1));
el.setAttribute("y", rn(y - zoomedSize, 1));
});
invokeActiveZooming();
}
function changePinStroke() {
const id = elSelected.attr("data-id");
d3.select(id).select("path").attr("fill", this.value);
d3.select(id).select("circle").attr("stroke", this.value);
function changeMarkerPin() {
const pin = this.value;
getSameTypeMarkers().forEach(marker => {
marker.pin = pin;
redrawPin(marker);
});
}
function changePinFill() {
const id = elSelected.attr("data-id");
d3.select(id).select("circle").attr("fill", this.value);
}
function changeIconStrokeWidth() {
const id = elSelected.attr("data-id");
d3.select("#defs-markers").select(id).select("text").attr("stroke-width", this.value);
}
function changeIconStroke() {
const id = elSelected.attr("data-id");
d3.select("#defs-markers").select(id).select("text").attr("stroke", this.value);
}
function changeIconFill() {
const id = elSelected.attr("data-id");
d3.select("#defs-markers").select(id).select("text").attr("fill", this.value);
}
function togglePinVisibility() {
const id = elSelected.attr("data-id");
let show = 1;
if (this.className === "icon-info-circled") {this.className = "icon-info"; show = 0; }
else this.className = "icon-info-circled";
d3.select(id).select("circle").attr("opacity", show);
d3.select(id).select("path").attr("opacity", show);
}
function editMarkerLegend() {
const id = elSelected.attr("id");
editNotes(id, id);
}
function toggleAddMarker() {
document.getElementById("addMarker").click();
}
function removeMarker() {
alertMessage.innerHTML = "Are you sure you want to remove the marker?";
$("#alert").dialog({resizable: false, title: "Remove marker",
buttons: {
Remove: function() {
$(this).dialog("close");
const index = notes.findIndex(n => n.id === elSelected.attr("id"));
if (index != -1) notes.splice(index, 1);
elSelected.remove();
$("#markerEditor").dialog("close");
},
Cancel: function() {$(this).dialog("close");}
}
const fill = this.value;
getSameTypeMarkers().forEach(marker => {
marker.fill = fill;
redrawPin(marker);
});
}
function changePinStroke() {
const stroke = this.value;
getSameTypeMarkers().forEach(marker => {
marker.stroke = stroke;
redrawPin(marker);
});
}
function redrawIcon({i, hidden, icon, dx = 50, dy = 50, px = 12}) {
const iconElement = !hidden && document.querySelector(`#marker${i} > text`);
if (iconElement) {
iconElement.innerHTML = icon;
iconElement.setAttribute("x", dx + "%");
iconElement.setAttribute("y", dy + "%");
iconElement.setAttribute("font-size", px + "px");
}
}
function redrawPin({i, hidden, pin = "bubble", fill = "#fff", stroke = "#000"}) {
const pinGroup = !hidden && document.querySelector(`#marker${i} > g`);
if (pinGroup) pinGroup.innerHTML = getPin(pin, fill, stroke);
}
function editMarkerLegend() {
const id = element.id;
editNotes(id, id);
}
function toggleMarkerLock() {
marker.lock = !marker.lock;
markerLock.classList.toggle("icon-lock-open");
markerLock.classList.toggle("icon-lock");
}
function toggleAddMarker() {
markerAdd.classList.toggle("pressed");
addMarker.click();
}
function confirmMarkerDeletion() {
confirmationDialog({
title: "Remove marker",
message: "Are you sure you want to remove this marker? The action cannot be reverted",
confirm: "Remove",
onConfirm: deleteMarker
});
}
function deleteMarker() {
notes = notes.filter(note => note.id !== element.id);
pack.markers = pack.markers.filter(m => m.i !== marker.i);
element.remove();
$("#markerEditor").dialog("close");
if (document.getElementById("markersOverviewRefresh").offsetParent) markersOverviewRefresh.click();
}
function closeMarkerEditor() {
listeners.forEach(removeListener => removeListener());
unselect();
if (addMarker.classList.contains("pressed")) addMarker.classList.remove("pressed");
if (markerAdd.classList.contains("pressed")) markerAdd.classList.remove("pressed");
addMarker.classList.remove("pressed");
markerAdd.classList.remove("pressed");
restoreDefaultEvents();
clearMainTip();
}
}

View file

@ -0,0 +1,196 @@
"use strict";
function overviewMarkers() {
if (customization) return;
closeDialogs("#markersOverview, .stable");
if (!layerIsOn("toggleMarkers")) toggleMarkers();
const markerGroup = document.getElementById("markers");
const body = document.getElementById("markersBody");
const markersInverPin = document.getElementById("markersInverPin");
const markersInverLock = document.getElementById("markersInverLock");
const markersFooterNumber = document.getElementById("markersFooterNumber");
const markersOverviewRefresh = document.getElementById("markersOverviewRefresh");
const markersAddFromOverview = document.getElementById("markersAddFromOverview");
const markersGenerationConfig = document.getElementById("markersGenerationConfig");
const markersRemoveAll = document.getElementById("markersRemoveAll");
const markersExport = document.getElementById("markersExport");
addLines();
$("#markersOverview").dialog({
title: "Markers Overview",
resizable: false,
width: fitContent(),
close: close,
position: {my: "right top", at: "right-10 top+10", of: "svg", collision: "fit"}
});
const listeners = [
listen(body, "click", handleLineClick),
listen(markersInverPin, "click", invertPin),
listen(markersInverLock, "click", invertLock),
listen(markersOverviewRefresh, "click", addLines),
listen(markersAddFromOverview, "click", toggleAddMarker),
listen(markersGenerationConfig, "click", configMarkersGeneration),
listen(markersRemoveAll, "click", triggerRemoveAll),
listen(markersExport, "click", exportMarkers)
];
function handleLineClick(ev) {
const el = ev.target;
const i = +el.parentNode.dataset.i;
if (el.classList.contains("icon-pencil")) return openEditor(i);
if (el.classList.contains("icon-dot-circled")) return focusOnMarker(i);
if (el.classList.contains("icon-pin")) return pinMarker(el, i);
if (el.classList.contains("locks")) return toggleLockStatus(el, i);
if (el.classList.contains("icon-trash-empty")) return triggerRemove(i);
}
function addLines() {
const lines = pack.markers
.map(({i, type, icon, pinned, lock}) => {
return `<div class="states" data-i=${i} data-type="${type}">
<div data-tip="Marker icon and type" style="width:12em">${icon} ${type}</div>
<span style="padding-right:.1em" data-tip="Edit marker" class="icon-pencil"></span>
<span style="padding-right:.1em" data-tip="Focus on marker position" class="icon-dot-circled pointer"></span>
<span style="padding-right:.1em" data-tip="Pin marker (display only pinned markers)" class="icon-pin ${pinned ? "" : "inactive"}" pointer"></span>
<span style="padding-right:.1em" class="locks pointer ${lock ? "icon-lock" : "icon-lock-open inactive"}" onmouseover="showElementLockTip(event)"></span>
<span data-tip="Remove marker" class="icon-trash-empty"></span>
</div>`;
})
.join("");
body.innerHTML = lines;
markersFooterNumber.innerText = pack.markers.length;
applySorting(markersHeader);
}
function invertPin() {
let anyPinned = false;
pack.markers.forEach(marker => {
const pinned = !marker.pinned;
if (pinned) {
marker.pinned = true;
anyPinned = true;
} else delete marker.pinned;
});
markerGroup.setAttribute("pinned", anyPinned ? 1 : null);
drawMarkers();
addLines();
}
function invertLock() {
pack.markers = pack.markers.map(marker => ({...marker, lock: !marker.lock}));
addLines();
}
function openEditor(i) {
const marker = pack.markers.find(marker => marker.i === i);
if (!marker) return;
const {x, y} = marker;
zoomTo(x, y, 8, 2000);
editMarker(i);
}
function focusOnMarker(i) {
highlightElement(document.getElementById(`marker${i}`), 2);
}
function pinMarker(el, i) {
const marker = pack.markers.find(marker => marker.i === i);
if (marker.pinned) {
delete marker.pinned;
const anyPinned = pack.markers.some(marker => marker.pinned);
if (!anyPinned) markerGroup.removeAttribute("pinned");
} else {
marker.pinned = true;
markerGroup.setAttribute("pinned", 1);
}
el.classList.toggle("inactive");
drawMarkers();
}
function toggleLockStatus(el, i) {
const marker = pack.markers.find(marker => marker.i === i);
if (marker.lock) {
delete marker.lock;
el.className = "locks pointer icon-lock-open inactive";
} else {
marker.lock = true;
el.className = "locks pointer icon-lock";
}
}
function triggerRemove(i) {
confirmationDialog({
title: "Remove marker",
message: "Are you sure you want to remove this marker? The action cannot be reverted",
confirm: "Remove",
onConfirm: () => removeMarker(i)
});
}
function toggleAddMarker() {
markersAddFromOverview.classList.toggle("pressed");
addMarker.click();
}
function removeMarker(i) {
notes = notes.filter(note => note.id !== `marker${i}`);
pack.markers = pack.markers.filter(marker => marker.i !== i);
document.getElementById(`marker${i}`)?.remove();
addLines();
}
function triggerRemoveAll() {
confirmationDialog({
title: "Remove all markers",
message: "Are you sure you want to remove all non-locked markers? The action cannot be reverted",
confirm: "Remove all",
onConfirm: removeAllMarkers
});
}
function removeAllMarkers() {
pack.markers = pack.markers.filter(({i, lock}) => {
if (lock) return true;
const id = `marker${i}`;
document.getElementById(id)?.remove();
notes = notes.filter(note => note.id !== id);
return false;
});
addLines();
}
function exportMarkers() {
const headers = "Id,Type,Icon,Name,Note,X,Y\n";
const body = pack.markers.map(marker => {
const {i, type, icon, x, y} = marker;
const id = `marker${i}`;
const note = notes.find(note => note.id === id);
const legend = escape(note.legend);
return [id, type, icon, note.name, legend, x, y].join(",");
});
const data = headers + body.join("\n");
const fileName = getFileName("Markers") + ".csv";
downloadFile(data, fileName);
}
function close() {
listeners.forEach(removeListener => removeListener());
addMarker.classList.remove("pressed");
markerAdd.classList.remove("pressed");
restoreDefaultEvents();
clearMainTip();
}
}

View file

@ -20,7 +20,16 @@ class Rulers {
for (const rulerString of rulers) {
const [type, pointsString] = rulerString.split(": ");
const points = pointsString.split(" ").map(el => el.split(",").map(n => +n));
const Type = type === "Ruler" ? Ruler : type === "Opisometer" ? Opisometer : type === "RouteOpisometer" ? RouteOpisometer : type === "Planimeter" ? Planimeter : null;
const Type =
type === "Ruler"
? Ruler
: type === "Opisometer"
? Opisometer
: type === "RouteOpisometer"
? RouteOpisometer
: type === "Planimeter"
? Planimeter
: null;
this.create(Type, points);
}
}
@ -527,17 +536,18 @@ class Planimeter extends Measurer {
}
// Scale bar
function drawScaleBar() {
function drawScaleBar(requestedScale) {
if (scaleBar.style("display") === "none") return; // no need to re-draw hidden element
scaleBar.selectAll("*").remove(); // fully redraw every time
const scaleLevel = requestedScale || scale;
const dScale = distanceScaleInput.value;
const distanceScale = distanceScaleInput.value;
const unit = distanceUnitInput.value;
const size = +barSizeInput.value;
// calculate size
const init = 100; // actual length in pixels if scale, dScale and size = 1;
const size = +barSizeInput.value;
let val = (init * size * dScale) / scale; // bar length in distance unit
const init = 100;
let val = (init * size * distanceScale) / scaleLevel; // bar length in distance unit
if (val > 900) val = rn(val, -3);
// round to 1000
else if (val > 90) val = rn(val, -2);
@ -545,13 +555,13 @@ function drawScaleBar() {
else if (val > 9) val = rn(val, -1);
// round to 10
else val = rn(val); // round to 1
const l = (val * scale) / dScale; // actual length in pixels on this scale
const length = (val * scaleLevel) / distanceScale; // actual length in pixels on this scale
scaleBar
.append("line")
.attr("x1", 0.5)
.attr("y1", 0)
.attr("x2", l + size - 0.5)
.attr("x2", length + size - 0.5)
.attr("y2", 0)
.attr("stroke-width", size)
.attr("stroke", "white");
@ -559,16 +569,16 @@ function drawScaleBar() {
.append("line")
.attr("x1", 0)
.attr("y1", size)
.attr("x2", l + size)
.attr("x2", length + size)
.attr("y2", size)
.attr("stroke-width", size)
.attr("stroke", "#3d3d3d");
const dash = size + " " + rn(l / 5 - size, 2);
const dash = size + " " + rn(length / 5 - size, 2);
scaleBar
.append("line")
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", l + size)
.attr("x2", length + size)
.attr("y2", 0)
.attr("stroke-width", rn(size * 3, 2))
.attr("stroke-dasharray", dash)
@ -580,16 +590,16 @@ function drawScaleBar() {
.data(d3.range(0, 6))
.enter()
.append("text")
.attr("x", d => rn((d * l) / 5, 2))
.attr("x", d => rn((d * length) / 5, 2))
.attr("y", 0)
.attr("dy", "-.5em")
.attr("font-size", fontSize)
.text(d => rn((((d * l) / 5) * dScale) / scale) + (d < 5 ? "" : " " + unit));
.text(d => rn((((d * length) / 5) * distanceScale) / scaleLevel) + (d < 5 ? "" : " " + unit));
if (barLabel.value !== "") {
scaleBar
.append("text")
.attr("x", (l + 1) / 2)
.attr("x", (length + 1) / 2)
.attr("y", 2 * size)
.attr("dominant-baseline", "text-before-edge")
.attr("font-size", fontSize)

View file

@ -75,14 +75,21 @@ function overviewMilitary() {
const sortData = options.military.map(u => `data-${u.name}="${getForces(u)}"`).join(" ");
const lineData = options.military.map(u => `<div data-type="${u.name}" data-tip="State ${u.name} units number">${getForces(u)}</div>`).join(" ");
lines += `<div class="states" data-id=${s.i} data-state="${s.name}" ${sortData} data-total="${total}" data-population="${population}" data-rate="${rate}" data-alert="${s.alert}">
<svg data-tip="${s.fullName}" width=".9em" height=".9em" style="margin-bottom:-1px"><rect x="0" y="0" width="100%" height="100%" fill="${s.color}" class="fillRect"></svg>
lines += `<div class="states" data-id=${s.i} data-state="${
s.name
}" ${sortData} data-total="${total}" data-population="${population}" data-rate="${rate}" data-alert="${s.alert}">
<svg data-tip="${s.fullName}" width=".9em" height=".9em" style="margin-bottom:-1px"><rect x="0" y="0" width="100%" height="100%" fill="${
s.color
}" class="fillRect"></svg>
<input data-tip="${s.fullName}" style="width:6em" value="${s.name}" readonly>
${lineData}
<div data-type="total" data-tip="Total state military personnel (considering crew)" style="font-weight: bold">${si(total)}</div>
<div data-type="population" data-tip="State population">${si(population)}</div>
<div data-type="rate" data-tip="Military personnel rate (% of state population). Depends on war alert">${rn(rate, 2)}%</div>
<input data-tip="War Alert. Editable modifier to military forces number, depends of political situation" style="width:4.1em" type="number" min=0 step=.01 value="${rn(s.alert, 2)}">
<input data-tip="War Alert. Editable modifier to military forces number, depends of political situation" style="width:4.1em" type="number" min=0 step=.01 value="${rn(
s.alert,
2
)}">
<span data-tip="Show regiments list" class="icon-list-bullet pointer"></span>
</div>`;
}
@ -145,7 +152,15 @@ function overviewMilitary() {
if (!layerIsOn("toggleStates")) return;
const d = regions.select("#state" + state).attr("d");
const path = debug.append("path").attr("class", "highlight").attr("d", d).attr("fill", "none").attr("stroke", "red").attr("stroke-width", 1).attr("opacity", 1).attr("filter", "url(#blur1)");
const path = debug
.append("path")
.attr("class", "highlight")
.attr("d", d)
.attr("fill", "none")
.attr("stroke", "red")
.attr("stroke-width", 1)
.attr("opacity", 1)
.attr("filter", "url(#blur1)");
const l = path.node().getTotalLength(),
dur = (l + 5000) / 2;
@ -199,9 +214,9 @@ function overviewMilitary() {
function militaryCustomize() {
const types = ["melee", "ranged", "mounted", "machinery", "naval", "armored", "aviation", "magical"];
const table = document.getElementById("militaryOptions").querySelector("tbody");
const tableBody = document.getElementById("militaryOptions").querySelector("tbody");
removeUnitLines();
options.military.map(u => addUnitLine(u));
options.military.map(unit => addUnitLine(unit));
$("#militaryOptions").dialog({
title: "Edit Military Units",
@ -218,43 +233,135 @@ function overviewMilitary() {
},
open: function () {
const buttons = $(this).dialog("widget").find(".ui-dialog-buttonset > button");
buttons[0].addEventListener("mousemove", () => tip("Apply military units settings. <span style='color:#cb5858'>All forces will be recalculated!</span>"));
buttons[0].addEventListener("mousemove", () =>
tip("Apply military units settings. <span style='color:#cb5858'>All forces will be recalculated!</span>")
);
buttons[1].addEventListener("mousemove", () => tip("Add new military unit to the table"));
buttons[2].addEventListener("mousemove", () => tip("Restore default military units and settings"));
buttons[3].addEventListener("mousemove", () => tip("Close the window without saving the changes"));
}
});
if (modules.overviewMilitaryCustomize) return;
modules.overviewMilitaryCustomize = true;
tableBody.addEventListener("click", event => {
const el = event.target;
if (el.tagName !== "BUTTON") return;
const type = el.dataset.type;
if (type === "icon") return selectIcon(el.innerHTML, v => (el.innerHTML = v));
if (type === "biomes") {
const {i, name, color} = biomesData;
const biomesArray = Array(i.length).fill(null);
const biomes = biomesArray.map((_, i) => ({i, name: name[i], color: color[i]}));
return selectLimitation(el, biomes);
}
if (type === "states") return selectLimitation(el, pack.states);
if (type === "cultures") return selectLimitation(el, pack.cultures);
if (type === "religions") return selectLimitation(el, pack.religions);
});
function removeUnitLines() {
table.querySelectorAll("tr").forEach(el => el.remove());
tableBody.querySelectorAll("tr").forEach(el => el.remove());
}
function addUnitLine(u) {
function getLimitValue(attr) {
return attr?.join(",") || "";
}
function getLimitText(attr) {
return attr?.length ? "some" : "all";
}
function getLimitTip(attr, data) {
if (!attr || !attr.length) return "";
return attr.map(i => data?.[i]?.name || "").join(", ");
}
function addUnitLine(unit) {
const {type, icon, name, rural, urban, power, crew, separate} = unit;
const row = document.createElement("tr");
row.innerHTML = `<td><button type="button" data-tip="Click to select unit icon">${u.icon || " "}</button></td>
<td><input data-tip="Type unit name. If name is changed for existing unit, old unit will be replaced" value="${u.name}"></td>
<td><input data-tip="Enter conscription percentage for rural population" type="number" min=0 max=100 step=.01 value="${u.rural}"></td>
<td><input data-tip="Enter conscription percentage for urban population" type="number" min=0 max=100 step=.01 value="${u.urban}"></td>
<td><input data-tip="Enter average number of people in crew (used for total personnel calculation)" type="number" min=1 step=1 value="${u.crew}"></td>
<td><input data-tip="Enter military power (used for battle simulation)" type="number" min=0 step=.1 value="${u.power}"></td>
<td><select data-tip="Select unit type to apply special rules on forces recalculation">${types.map(t => `<option ${u.type === t ? "selected" : ""} value="${t}">${t}</option>`).join(" ")}</select></td>
<td data-tip="Check if unit is separate and can be stacked only with units of the same type">
<input id="${u.name}Separate" type="checkbox" class="checkbox" ${u.separate ? "checked" : ""}>
<label for="${u.name}Separate" class="checkbox-label"></label></td>
const typeOptions = types.map(t => `<option ${type === t ? "selected" : ""} value="${t}">${t}</option>`).join(" ");
const getLimitButton = attr =>
`<button
data-tip="Select allowed ${attr}"
data-type="${attr}"
title="${getLimitTip(unit[attr], pack[attr])}"
data-value="${getLimitValue(unit[attr])}">
${getLimitText(unit[attr])}
</button>`;
row.innerHTML = `<td><button data-type="icon" data-tip="Click to select unit icon">${icon || " "}</button></td>
<td><input data-tip="Type unit name. If name is changed for existing unit, old unit will be replaced" value="${name}"></td>
<td>${getLimitButton("biomes")}</td>
<td>${getLimitButton("states")}</td>
<td>${getLimitButton("cultures")}</td>
<td>${getLimitButton("religions")}</td>
<td><input data-tip="Enter conscription percentage for rural population" type="number" min=0 max=100 step=.01 value="${rural}"></td>
<td><input data-tip="Enter conscription percentage for urban population" type="number" min=0 max=100 step=.01 value="${urban}"></td>
<td><input data-tip="Enter average number of people in crew (for total personnel calculation)" type="number" min=1 step=1 value="${crew}"></td>
<td><input data-tip="Enter military power (used for battle simulation)" type="number" min=0 step=.1 value="${power}"></td>
<td><select data-tip="Select unit type to apply special rules on forces recalculation">${typeOptions}</select></td>
<td data-tip="Check if unit is <b>separate</b> and can be stacked only with the same units">
<input id="${name}Separate" type="checkbox" class="checkbox" ${separate ? "checked" : ""}>
<label for="${name}Separate" class="checkbox-label"></label></td>
<td data-tip="Remove the unit"><span data-tip="Remove unit type" class="icon-trash-empty pointer" onclick="this.parentElement.parentElement.remove();"></span></td>`;
row.querySelector("button").addEventListener("click", function (e) {
selectIcon(this.innerHTML, v => (this.innerHTML = v));
});
table.appendChild(row);
tableBody.appendChild(row);
}
function restoreDefaultUnits() {
removeUnitLines();
Military.getDefaultOptions().map(u => addUnitLine(u));
Military.getDefaultOptions().map(unit => addUnitLine(unit));
}
function selectLimitation(el, data) {
const type = el.dataset.type;
const value = el.dataset.value;
const initial = value ? value.split(",").map(v => +v) : [];
const filtered = data.filter(datum => datum.i && !datum.removed);
const lines = filtered.map(
({i, name, fullName, color}) =>
`<tr data-tip="${name}"><td><span style="color:${color}">⬤</span></td>
<td><input data-i="${i}" id="el${i}" type="checkbox" class="checkbox" ${!initial.length || initial.includes(i) ? "checked" : ""} >
<label for="el${i}" class="checkbox-label">${fullName || name}</label>
</td></tr>`
);
alertMessage.innerHTML = `<b>Limit unit by ${type}:</b><table style="margin-top:.3em"><tbody>${lines.join("")}</tbody></table>`;
$("#alert").dialog({
width: fitContent(),
title: `Limit unit`,
buttons: {
Invert: function () {
alertMessage.querySelectorAll("input").forEach(el => (el.checked = !el.checked));
},
Apply: function () {
const inputs = Array.from(alertMessage.querySelectorAll("input"));
const selected = inputs.reduce((acc, input) => {
if (input.checked) acc.push(input.dataset.i);
return acc;
}, []);
if (!selected.length) return tip("Select at least one element", false, "error");
const allAreSelected = selected.length === inputs.length;
el.dataset.value = allAreSelected ? "" : selected.join(",");
el.innerHTML = allAreSelected ? "all" : "some";
el.setAttribute("title", getLimitTip(selected, data));
$(this).dialog("close");
},
Cancel: function () {
$(this).dialog("close");
}
}
});
}
function applyMilitaryOptions() {
const unitLines = Array.from(table.querySelectorAll("tr"));
const unitLines = Array.from(tableBody.querySelectorAll("tr"));
const names = unitLines.map(r => r.querySelector("input").value.replace(/[&\/\\#, +()$~%.'":*?<>{}]/g, "_"));
if (new Set(names).size !== names.length) {
tip("All units should have unique names", false, "error");
@ -263,14 +370,22 @@ function overviewMilitary() {
$("#militaryOptions").dialog("close");
options.military = unitLines.map((r, i) => {
const [icon, name, rural, urban, crew, power, type, separate] = Array.from(r.querySelectorAll("input, select, button")).map(d => {
let value = d.value;
if (d.type === "number") value = +d.value || 0;
if (d.type === "checkbox") value = +d.checked || 0;
if (d.type === "button") value = d.innerHTML || "";
return value;
const elements = Array.from(r.querySelectorAll("input, button, select"));
const [icon, name, biomes, states, cultures, religions, rural, urban, crew, power, type, separate] = elements.map(el => {
const {type, value} = el.dataset || {};
if (type === "icon") return el.innerHTML || "";
if (type) return value ? value.split(",").map(v => parseInt(v)) : null;
if (el.type === "number") return +el.value || 0;
if (el.type === "checkbox") return +el.checked || 0;
return el.value;
});
return {icon, name: names[i], rural, urban, crew, power, type, separate};
const unit = {icon, name: names[i], rural, urban, crew, power, type, separate};
if (biomes) unit.biomes = biomes;
if (states) unit.states = states;
if (cultures) unit.cultures = cultures;
if (religions) unit.religions = religions;
return unit;
});
localStorage.setItem("military", JSON.stringify(options.military));
Military.generate();

View file

@ -1,4 +1,5 @@
"use strict";
function editNotes(id, name) {
// update list of objects
const select = document.getElementById("notesSelect");
@ -8,11 +9,12 @@ function editNotes(id, name) {
}
// initiate pell (html editor)
const notesText = document.getElementById("notesText");
notesText.innerHTML = "";
const editor = Pell.init({
element: document.getElementById("notesText"),
element: notesText,
onChange: html => {
const id = document.getElementById("notesSelect").value;
const note = notes.find(note => note.id === id);
const note = notes.find(note => note.id === select.value);
if (!note) return;
note.legend = html;
showNote(note);
@ -43,8 +45,7 @@ function editNotes(id, name) {
title: "Notes Editor",
minWidth: "40em",
width: "50vw",
position: {my: "center", at: "center", of: "svg"},
close: () => (notesText.innerHTML = "")
position: {my: "center", at: "center", of: "svg"}
});
if (modules.editNotes) return;
@ -108,7 +109,7 @@ function editNotes(id, name) {
return;
}
highlightElement(element); // if element is found
highlightElement(element, 3); // if element is found
}
function downloadLegends() {

View file

@ -89,19 +89,20 @@ function showSupporters() {
Maxwell Hill,Drunken_Legends,rob bee,Jesse Holmes,YYako,Detocroix,Anoplexian,Hannah,Paul,Sandra Krohn,Lucid,Richard Keating,Allen Varney,Rick Falkvinge,
Seth Fusion,Adam Butler,Gus,StroboWolf,Sadie Blackthorne,Zewen Senpai,Dell McKnight,Oneiris,Darinius Dragonclaw Studios,Christopher Whitney,Rhodes HvZ,
Jeppe Skov Jensen,María Martín López,Martin Seeger,Annie Rishor,Aram Sabatés,MadNomadMedia,Eric Foley,Vito Martono,James H. Anthony,Kevin Cossutta,
Thirty-OneR ,ThatGuyGW ,Dee Chiu,MontyBoosh ,Achillain ,Jaden ,SashaTK,Steve Johnson,Eric Foley,Vito Martono,James H. Anthony,Kevin Cossutta,Thirty-OneR,
ThatGuyGW,Dee Chiu,MontyBoosh,Achillain,Jaden,SashaTK,Steve Johnson,Pierrick Bertrand,Jared Kennedy,Dylan Devenny,Kyle Robertson,Andrew Rostaing,Daniel Gill,
Char,Jack,Barna Csíkos,Ian Rousseau,Nicholas Grabstas,Tom Van Orden jr,Bryan Brake,Akylos,Riley Seaman,MaxOliver,Evan-DiLeo,Alex Debus,Joshua Vaught,
Kyle S,Eric Moore,Dean Dunakin,Uniquenameosaurus,WarWizardGames,Chance Mena,Jan Ka,Miguel Alejandro,Dalton Clark,Simon Drapeau,Radovan Zapletal,Jmmat6,
Justa Badge,Blargh Blarghmoomoo,Vanessa Anjos,Grant A. Murray,Akirsop,Rikard Wolff,Jake Fish,teco 47,Antiroo,Jakob Siegel,Guilherme Aguiar,Jarno Hallikainen,
Justin Mcclain,Kristin Chernoff,Rowland Kingman,Esther Busch,Grayson McClead,Austin,Hakon the Viking,Chad Riley,Cooper Counts,Patrick Jones,Clonetone,
PlayByMail.Net,Brad Wardell,Lance Saba,Egoensis,Brea Richards,Tiber,Chris Bloom,Maxim Lowe,Aquelion,Page One Project,Spencer Morris,Paul Ingram,
Dust Bunny,Adrian Wright,Eric Alexander Cartaya,GameNight,Thomas Mortensen Hansen,Zklaus,Drinarius,Ed Wright,Lon Varnadore,Crys Cain,Heaven N Lee,
Jeffrey Henning,Lazer Elf,Jordan Bellah,Alex Beard,Kass Frisson,Petro Lombaard,Emanuel Pietri,Rox,PinkEvil,Gavin Madrigal,Martin Lorber,Prince of Morgoth,
Jaryd Armstrong,Andrew Pirkola,ThyHolyDevil,Gary Smith,Tyshaun Wise,Ethan Cook,Jon Stroman,Nobody679,良义 ,Chris Gray,Phoenix Boatwright,Mackenzie,
Milo Cohen,Jason Matthew Wuerfel,Rasmus Legêne,Andrew Hines,Wexxler,Espen Sæverud,Binks,Dominick Ormsby,Linn Browning,Václav Švec,Alan Buehne,
George J.Lekkas,Alexandre Boivin,Tommy Mayfield,Skylar Mangum-Turner,Karen Blythe,Stefan Gugerel,Mike Conley,Xavier privé,Hope You're Well,
Mark Sprietsma,Robert Landry,Nick Mowry"`;
Thirty-OneR,ThatGuyGW,Dee Chiu,MontyBoosh,Achillain,Jaden,SashaTK,Steve Johnson,Pierrick Bertrand,Jared Kennedy,Dylan Devenny,Kyle Robertson,
Andrew Rostaing,Daniel Gill,Char,Jack,Barna Csíkos,Ian Rousseau,Nicholas Grabstas,Tom Van Orden jr,Bryan Brake,Akylos,Riley Seaman,MaxOliver,Evan-DiLeo,
Alex Debus,Joshua Vaught,Kyle S,Eric Moore,Dean Dunakin,Uniquenameosaurus,WarWizardGames,Chance Mena,Jan Ka,Miguel Alejandro,Dalton Clark,Simon Drapeau,
Radovan Zapletal,Jmmat6,Justa Badge,Blargh Blarghmoomoo,Vanessa Anjos,Grant A. Murray,Akirsop,Rikard Wolff,Jake Fish,teco 47,Antiroo,Jakob Siegel,
Guilherme Aguiar,Jarno Hallikainen,Justin Mcclain,Kristin Chernoff,Rowland Kingman,Esther Busch,Grayson McClead,Austin,Hakon the Viking,Chad Riley,
Cooper Counts,Patrick Jones,Clonetone,PlayByMail.Net,Brad Wardell,Lance Saba,Egoensis,Brea Richards,Tiber,Chris Bloom,Maxim Lowe,Aquelion,
Page One Project,Spencer Morris,Paul Ingram,Dust Bunny,Adrian Wright,Eric Alexander Cartaya,GameNight,Thomas Mortensen Hansen,Zklaus,Drinarius,
Ed Wright,Lon Varnadore,Crys Cain,Heaven N Lee,Jeffrey Henning,Lazer Elf,Jordan Bellah,Alex Beard,Kass Frisson,Petro Lombaard,Emanuel Pietri,Rox,
PinkEvil,Gavin Madrigal,Martin Lorber,Prince of Morgoth,Jaryd Armstrong,Andrew Pirkola,ThyHolyDevil,Gary Smith,Tyshaun Wise,Ethan Cook,Jon Stroman,
Nobody679,良义 ,Chris Gray,Phoenix Boatwright,Mackenzie,Milo Cohen,Jason Matthew Wuerfel,Rasmus Legêne,Andrew Hines,Wexxler,Espen Sæverud,Binks,
Dominick Ormsby,Linn Browning,Václav Švec,Alan Buehne,George J.Lekkas,Alexandre Boivin,Tommy Mayfield,Skylar Mangum-Turner,Karen Blythe,Stefan Gugerel,
Mike Conley,Xavier privé,Hope You're Well,Mark Sprietsma,Robert Landry,Nick Mowry,steve hall,Markell,Josh Wren,Neutrix,BLRageQuit,Rocky,
Dario Spadavecchia,Bas Kroot,John Patrick Callahan Jr,Alexandra Vesey,D,Exp1nt,james,Braxton Istace,w,Rurikid,AntiBlock,Redsauz,BigE0021,
Jonathan Williams,ojacid .,Brian Wilson,A Patreon of the Ahts,Shubham Jakhotiya`;
const array = supporters
.replace(/(?:\r\n|\r|\n)/g, "")
@ -150,7 +151,9 @@ optionsContent.addEventListener("input", function (event) {
else if (id === "regionsInput" || id === "regionsOutput") changeStatesNumber(value);
else if (id === "emblemShape") changeEmblemShape(value);
else if (id === "tooltipSizeInput" || id === "tooltipSizeOutput") changeTooltipSize(value);
else if (id === "transparencyInput") changeDialogsTransparency(value);
else if (id === "themeHueInput") changeThemeHue(value);
else if (id === "themeColorInput") changeDialogsTheme(themeColorInput.value, transparencyInput.value);
else if (id === "transparencyInput") changeDialogsTheme(themeColorInput.value, value);
});
optionsContent.addEventListener("change", function (event) {
@ -158,23 +161,24 @@ optionsContent.addEventListener("change", function (event) {
const value = event.target.value;
if (id === "zoomExtentMin" || id === "zoomExtentMax") changeZoomExtent(value);
else if (id === "optionsSeed") generateMapWithSeed();
else if (id === "optionsSeed") generateMapWithSeed("seed change");
else if (id === "uiSizeInput" || id === "uiSizeOutput") changeUIsize(value);
if (id === "shapeRendering") viewbox.attr("shape-rendering", value);
else if (id === "yearInput") changeYear();
else if (id === "eraInput") changeEra();
else if (id === "stateLabelsModeInput") options.stateLabelsMode = value;
});
optionsContent.addEventListener("click", function (event) {
const id = event.target.id;
if (id === "toggleFullscreen") toggleFullscreen();
else if (id === "optionsSeedGenerate") generateMapWithSeed();
else if (id === "optionsMapHistory") showSeedHistoryDialog();
else if (id === "optionsCopySeed") copyMapURL();
else if (id === "optionsEraRegenerate") regenerateEra();
else if (id === "zoomExtentDefault") restoreDefaultZoomExtent();
else if (id === "translateExtent") toggleTranslateExtent(event.target);
else if (id === "speakerTest") testSpeaker();
else if (id === "themeColorRestore") restoreDefaultThemeColor();
});
function mapSizeInputChange() {
@ -208,8 +212,8 @@ function changeMapSize() {
// just apply canvas size that was already set
function applyMapSize() {
const zoomMin = +zoomExtentMin.value,
zoomMax = +zoomExtentMax.value;
const zoomMin = +zoomExtentMin.value;
const zoomMax = +zoomExtentMax.value;
graphWidth = +mapWidthInput.value;
graphHeight = +mapHeightInput.value;
svgWidth = Math.min(graphWidth, window.innerWidth);
@ -277,12 +281,9 @@ function testSpeaker() {
speechSynthesis.speak(speaker);
}
function generateMapWithSeed() {
if (optionsSeed.value == seed) {
tip("The current map already has this seed", false, "error");
return;
}
regeneratePrompt();
function generateMapWithSeed(source) {
if (optionsSeed.value == seed) return tip("The current map already has this seed", false, "error");
regeneratePrompt(source);
}
function showSeedHistoryDialog() {
@ -313,7 +314,7 @@ function restoreSeed(id) {
mapHeightInput.value = mapHistory[id].height;
templateInput.value = mapHistory[id].template;
if (locked("template")) unlock("template");
regeneratePrompt();
regeneratePrompt("seed history");
}
function restoreDefaultZoomExtent() {
@ -417,7 +418,7 @@ function changeUIsize(value) {
if (+value > max) value = max;
uiSizeInput.value = uiSizeOutput.value = value;
document.getElementsByTagName("body")[0].style.fontSize = value * 11 + "px";
document.getElementsByTagName("body")[0].style.fontSize = rn(value * 10, 2) + "px";
document.getElementById("options").style.width = value * 300 + "px";
}
@ -429,26 +430,56 @@ function changeTooltipSize(value) {
tooltip.style.fontSize = `calc(${value}px + 0.5vw)`;
}
// change transparency for modal windows
function changeDialogsTransparency(value) {
transparencyInput.value = transparencyOutput.value = value;
const alpha = (100 - +value) / 100;
const optionsColor = "rgba(164, 139, 149, " + alpha + ")";
const dialogsColor = "rgba(255, 255, 255, " + alpha + ")";
const optionButtonsColor = "rgba(145, 110, 127, " + Math.min(alpha + 0.3, 1) + ")";
const optionLiColor = "rgba(153, 123, 137, " + Math.min(alpha + 0.3, 1) + ")";
document.getElementById("options").style.backgroundColor = optionsColor;
document.getElementById("dialogs").style.backgroundColor = dialogsColor;
document.querySelectorAll(".tabcontent button").forEach(el => (el.style.backgroundColor = optionButtonsColor));
document.querySelectorAll(".tabcontent li").forEach(el => (el.style.backgroundColor = optionLiColor));
document.querySelectorAll("button.options").forEach(el => (el.style.backgroundColor = optionLiColor));
const THEME_COLOR = "#997787";
function restoreDefaultThemeColor() {
localStorage.removeItem("themeColor");
changeDialogsTheme(THEME_COLOR, transparencyInput.value);
}
function changeThemeHue(hue) {
const {s, l} = d3.hsl(themeColorInput.value);
const newColor = d3.hsl(+hue, s, l).hex();
changeDialogsTheme(newColor, transparencyInput.value);
}
// change color and transparency for modal windows
function changeDialogsTheme(themeColor, transparency) {
transparencyInput.value = transparencyOutput.value = transparency;
const alpha = (100 - +transparency) / 100;
const alphaReduced = Math.min(alpha + 0.3, 1);
const {h, s, l} = d3.hsl(themeColor || THEME_COLOR);
themeColorInput.value = themeColor || THEME_COLOR;
themeHueInput.value = h;
const getRGBA = (hue, saturation, lightness, alpha) => {
const color = d3.hsl(hue, saturation, lightness, alpha);
return color.toString();
};
const theme = [
{name: "--bg-main", h, s, l, alpha},
{name: "--bg-lighter", h, s, l: l + 0.02, alpha},
{name: "--bg-light", h, s: s - 0.02, l: l + 0.06, alpha},
{name: "--light-solid", h, s: s + 0.01, l: l + 0.05, alpha: 1},
{name: "--dark-solid", h, s, l: l - 0.2, alpha: 1},
{name: "--header", h, s: s, l: l - 0.03, alpha: alphaReduced},
{name: "--header-active", h, s: s, l: l - 0.09, alpha: alphaReduced},
{name: "--bg-disabled", h, s: s - 0.04, l: l + 0.09, alphaReduced},
{name: "--bg-dialogs", h: 0, s: 0, l: 0.98, alpha}
];
const sx = document.documentElement.style;
theme.forEach(({name, h, s, l, alpha}) => {
sx.setProperty(name, getRGBA(h, s, l, alpha));
});
}
function changeZoomExtent(value) {
const min = Math.max(+zoomExtentMin.value, 0.01),
max = Math.min(+zoomExtentMax.value, 200);
const min = Math.max(+zoomExtentMin.value, 0.01);
const max = Math.min(+zoomExtentMax.value, 200);
zoom.scaleExtent([min, max]);
const scale = Math.max(Math.min(+value, 200), 0.01);
const scale = minmax(+value, 0.01, 200);
zoom.scaleTo(svg, scale);
}
@ -484,13 +515,12 @@ function applyStoredOptions() {
.map(w => +w);
if (localStorage.getItem("military")) options.military = JSON.parse(localStorage.getItem("military"));
changeDialogsTransparency(localStorage.getItem("transparency") || 5);
if (localStorage.getItem("tooltipSize")) changeTooltipSize(localStorage.getItem("tooltipSize"));
if (localStorage.getItem("regions")) changeStatesNumber(localStorage.getItem("regions"));
uiSizeInput.max = uiSizeOutput.max = getUImaxSize();
if (localStorage.getItem("uiSize")) changeUIsize(localStorage.getItem("uiSize"));
else changeUIsize(Math.max(Math.min(rn(mapWidthInput.value / 1280, 1), 2.5), 1));
else changeUIsize(minmax(rn(mapWidthInput.value / 1280, 1), 1, 2.5));
// search params overwrite stored and default options
const params = new URL(window.location.href).searchParams;
@ -499,8 +529,14 @@ function applyStoredOptions() {
if (width) mapWidthInput.value = width;
if (height) mapHeightInput.value = height;
const transparency = localStorage.getItem("transparency") || 5;
const themeColor = localStorage.getItem("themeColor");
changeDialogsTheme(themeColor, transparency);
// set shape rendering
viewbox.attr("shape-rendering", shapeRendering.value);
options.stateLabelsMode = stateLabelsModeInput.value;
}
// randomize options if randomization is allowed (not locked or options='default')
@ -531,10 +567,9 @@ function randomizeOptions() {
// 'Units Editor' settings
const US = navigator.language === "en-US";
const UK = navigator.language === "en-GB";
if (randomize || !locked("distanceScale")) distanceScaleOutput.value = distanceScaleInput.value = gauss(3, 1, 1, 5);
if (!stored("distanceUnit")) distanceUnitInput.value = US || UK ? "mi" : "km";
if (!stored("heightUnit")) heightUnit.value = US || UK ? "ft" : "m";
if (!stored("distanceUnit")) distanceUnitInput.value = US ? "mi" : "km";
if (!stored("heightUnit")) heightUnit.value = US ? "ft" : "m";
if (!stored("temperatureScale")) temperatureScale.value = US ? "°F" : "°C";
// World settings
@ -621,23 +656,17 @@ function restoreDefaultOptions() {
// Sticked menu Options listeners
document.getElementById("sticked").addEventListener("click", function (event) {
const id = event.target.id;
if (id === "newMapButton") regeneratePrompt();
if (id === "newMapButton") regeneratePrompt("sticky button");
else if (id === "saveButton") showSavePane();
else if (id === "exportButton") showExportPane();
else if (id === "loadButton") showLoadPane();
else if (id === "zoomReset") resetZoom(1000);
});
function regeneratePrompt() {
if (customization) {
tip("New map cannot be generated when edit mode is active, please exit the mode and retry", false, "error");
return;
}
function regeneratePrompt(source) {
if (customization) return tip("New map cannot be generated when edit mode is active, please exit the mode and retry", false, "error");
const workingTime = (Date.now() - last(mapHistory).created) / 60000; // minutes
if (workingTime < 5) {
regenerateMap();
return;
}
if (workingTime < 5) return regenerateMap(source);
alertMessage.innerHTML = `Are you sure you want to generate a new map?<br>
All unsaved changes made to the current map will be lost`;
@ -650,7 +679,7 @@ function regeneratePrompt() {
},
Generate: function () {
closeDialogs();
regenerateMap();
regenerateMap(source);
}
}
});
@ -770,6 +799,9 @@ function openSaveTiles() {
status.innerHTML = "";
let loading = null;
const inputs = document.getElementById("saveTilesScreen").querySelectorAll("input");
inputs.forEach(input => input.addEventListener("input", updateTilesOptions));
$("#saveTilesScreen").dialog({
resizable: false,
title: "Download tiles",
@ -790,17 +822,13 @@ function openSaveTiles() {
}
},
close: () => {
inputs.forEach(input => input.removeEventListener("input", updateTilesOptions));
debug.selectAll("*").remove();
clearInterval(loading);
}
});
}
document
.getElementById("saveTilesScreen")
.querySelectorAll("input")
.forEach(el => el.addEventListener("input", updateTilesOptions));
function updateTilesOptions() {
if (this?.tagName === "INPUT") {
const {nextElementSibling: next, previousElementSibling: prev} = this;

View file

@ -34,6 +34,7 @@ function editProvinces() {
document.getElementById("provincesManually").addEventListener("click", enterProvincesManualAssignent);
document.getElementById("provincesManuallyApply").addEventListener("click", applyProvincesManualAssignent);
document.getElementById("provincesManuallyCancel").addEventListener("click", () => exitProvincesManualAssignment());
document.getElementById("provincesRelease").addEventListener("click", triggerProvincesRelease);
document.getElementById("provincesAdd").addEventListener("click", enterAddProvinceMode);
document.getElementById("provincesRecolor").addEventListener("click", recolorProvinces);
@ -129,19 +130,27 @@ function editProvinces() {
const separable = p.burg && p.burg !== pack.states[p.state].capital;
const focused = defs.select("#fog #focusProvince" + p.i).size();
COArenderer.trigger("provinceCOA" + p.i, p.coa);
lines += `<div class="states" data-id=${p.i} data-name="${p.name}" data-form="${p.formName}" data-color="${p.color}" data-capital="${capital}" data-state="${stateName}" data-area=${area} data-population=${population}>
<svg data-tip="Province fill style. Click to change" width=".9em" height=".9em" style="margin-bottom:-1px"><rect x="0" y="0" width="100%" height="100%" fill="${p.color}" class="fillRect pointer"></svg>
lines += `<div class="states" data-id=${p.i} data-name="${p.name}" data-form="${p.formName}" data-color="${
p.color
}" data-capital="${capital}" data-state="${stateName}" data-area=${area} data-population=${population}>
<svg data-tip="Province fill style. Click to change" width=".9em" height=".9em" style="margin-bottom:-1px"><rect x="0" y="0" width="100%" height="100%" fill="${
p.color
}" class="fillRect pointer"></svg>
<input data-tip="Province name. Click to change" class="name pointer" value="${p.name}" readonly>
<svg data-tip="Click to show and edit province emblem" class="coaIcon hide" viewBox="0 0 200 200"><use href="#provinceCOA${p.i}"></use></svg>
<input data-tip="Province form name. Click to change" class="name pointer hide" value="${p.formName}" readonly>
<span data-tip="Province capital. Click to zoom into view" class="icon-star-empty pointer hide ${p.burg ? "" : "placeholder"}"></span>
<select data-tip="Province capital. Click to select from burgs within the state. No capital means the province is governed from the state capital" class="cultureBase hide ${p.burgs.length ? "" : "placeholder"}">${p.burgs.length ? getCapitalOptions(p.burgs, p.burg) : ""}</select>
<select data-tip="Province capital. Click to select from burgs within the state. No capital means the province is governed from the state capital" class="cultureBase hide ${
p.burgs.length ? "" : "placeholder"
}">${p.burgs.length ? getCapitalOptions(p.burgs, p.burg) : ""}</select>
<input data-tip="Province owner" class="provinceOwner" value="${stateName}" disabled">
<span data-tip="Province area" style="padding-right: 4px" class="icon-map-o hide"></span>
<div data-tip="Province area" class="biomeArea hide">${si(area) + unit}</div>
<span data-tip="${populationTip}" class="icon-male hide"></span>
<div data-tip="${populationTip}" class="culturePopulation hide">${si(population)}</div>
<span data-tip="Declare province independence (turn non-capital province with burgs into a new state)" class="icon-flag-empty ${separable ? "" : "placeholder"} hide"></span>
<span data-tip="Declare province independence (turn non-capital province with burgs into a new state)" class="icon-flag-empty ${
separable ? "" : "placeholder"
} hide"></span>
<span data-tip="Toggle province focus" class="icon-pin ${focused ? "" : " inactive"} hide"></span>
<span data-tip="Remove the province" class="icon-trash-empty hide"></span>
</div>`;
@ -222,74 +231,64 @@ function editProvinces() {
function capitalZoomIn(p) {
const capital = pack.provinces[p].burg;
const l = burgLabels.select("[data-id='" + capital + "']");
const x = +l.attr("x"),
y = +l.attr("y");
const x = +l.attr("x");
const y = +l.attr("y");
zoomTo(x, y, 8, 2000);
}
function triggerIndependencePromps(p) {
alertMessage.innerHTML = "Are you sure you want to declare province independence? <br>It will turn province into a new state";
$("#alert").dialog({
resizable: false,
confirmationDialog({
title: "Declare independence",
buttons: {
Declare: function () {
declareProvinceIndependence(p);
$(this).dialog("close");
},
Cancel: function () {
$(this).dialog("close");
}
message: "Are you sure you want to declare province independence? <br>It will turn province into a new state",
confirm: "Declare",
onConfirm: () => {
const [oldStateId, newStateId] = declareProvinceIndependence(p);
updateStatesPostRelease([oldStateId], [newStateId]);
}
});
}
function declareProvinceIndependence(p) {
const states = pack.states,
provinces = pack.provinces,
cells = pack.cells;
if (provinces[p].burgs.some(b => pack.burgs[b].capital)) {
tip("Cannot declare independence of a province having capital burg. Please change capital first", false, "error");
return;
}
function declareProvinceIndependence(provinceId) {
const {states, provinces, cells, burgs} = pack;
const province = provinces[provinceId];
const {name, burg: burgId, burgs: provinceBurgs} = province;
const oldState = pack.provinces[p].state;
const newState = pack.states.length;
if (provinceBurgs.some(b => burgs[b].capital))
return tip("Cannot declare independence of a province having capital burg. Please change capital first", false, "error");
if (!burgId) return tip("Cannot declare independence of a province without burg", false, "error");
const oldStateId = province.state;
const newStateId = states.length;
// turn province burg into a capital
const burg = provinces[p].burg;
if (!burg) return;
pack.burgs[burg].capital = 1;
moveBurgToGroup(burg, "cities");
burgs[burgId].capital = 1;
moveBurgToGroup(burgId, "cities");
// move all burgs to a new state
provinces[p].burgs.forEach(b => (pack.burgs[b].state = newState));
province.burgs.forEach(b => (burgs[b].state = newStateId));
// difine new state attributes
const center = pack.burgs[burg].cell;
const culture = pack.burgs[burg].culture;
const name = provinces[p].name;
const {cell: center, culture} = burgs[burgId];
const color = getRandomColor();
const coa = provinces[p].coa;
const coaEl = document.getElementById("provinceCOA" + p);
if (coaEl) coaEl.id = "stateCOA" + newState;
emblems.select(`#provinceEmblems > use[data-i='${p}']`).remove();
const coa = province.coa;
const coaEl = document.getElementById("provinceCOA" + provinceId);
if (coaEl) coaEl.id = "stateCOA" + newStateId;
emblems.select(`#provinceEmblems > use[data-i='${provinceId}']`).remove();
// update cells
cells.i
.filter(i => cells.province[i] === p)
.filter(i => cells.province[i] === provinceId)
.forEach(i => {
cells.province[i] = 0;
cells.state[i] = newState;
cells.state[i] = newStateId;
});
// update diplomacy and reverse relations
const diplomacy = states.map(s => {
if (!s.i || s.removed) return "x";
let relations = states[oldState].diplomacy[s.i]; // relations between Nth state and old overlord
if (s.i === oldState) relations = "Enemy";
// new state is Enemy to its old overlord
let relations = states[oldStateId].diplomacy[s.i]; // relations between Nth state and old overlord
// new state is Enemy to its old owner
if (s.i === oldStateId) relations = "Enemy";
else if (relations === "Ally") relations = "Suspicion";
else if (relations === "Friendly") relations = "Suspicion";
else if (relations === "Suspicion") relations = "Neutral";
@ -301,28 +300,51 @@ function editProvinces() {
return relations;
});
diplomacy.push("x");
states[0].diplomacy.push([`Independance declaration`, `${name} declared its independance from ${states[oldState].name}`]);
states[0].diplomacy.push([`Independance declaration`, `${name} declared its independance from ${states[oldStateId].name}`]);
// create new state
states.push({i: newState, name, diplomacy, provinces: [], color, expansionism: 0.5, capital: burg, type: "Generic", center, culture, military: [], alert: 1, coa});
BurgsAndStates.collectStatistics();
BurgsAndStates.defineStateForms([newState]);
if (layerIsOn("toggleProvinces")) toggleProvinces();
if (!layerIsOn("toggleStates")) toggleStates();
else drawStates();
if (!layerIsOn("toggleBorders")) toggleBorders();
else drawBorders();
BurgsAndStates.drawStateLabels([newState, oldState]);
states.push({
i: newStateId,
name,
diplomacy,
provinces: [],
color,
expansionism: 0.5,
capital: burgId,
type: "Generic",
center,
culture,
military: [],
alert: 1,
coa
});
// remove old province
unfog("focusProvince" + p);
if (states[oldState].provinces.includes(p)) states[oldState].provinces.splice(states[oldState].provinces.indexOf(p), 1);
provinces[p] = {i: p, removed: true};
states[oldStateId].provinces = states[oldStateId].provinces.filter(p => p !== provinceId);
provinces[provinceId] = {i: provinceId, removed: true};
// draw emblem
COArenderer.add("state", newState, coa, pack.states[newState].pole[0], pack.states[newState].pole[1]);
return [oldStateId, newStateId];
}
function updateStatesPostRelease(oldStates, newStates) {
const allStates = unique([...oldStates, ...newStates]);
layerIsOn("toggleProvinces") && toggleProvinces();
layerIsOn("toggleStates") ? drawStates() : toggleStates();
layerIsOn("toggleBorders") ? drawBorders() : toggleBorders();
BurgsAndStates.collectStatistics();
BurgsAndStates.defineStateForms(newStates);
BurgsAndStates.drawStateLabels(allStates);
// redraw emblems
allStates.forEach(stateId => {
emblems.select(`#stateEmblems > use[data-i='${stateId}']`)?.remove();
const {coa, pole} = pack.states[stateId];
COArenderer.add("state", stateId, coa, ...pole);
});
unfog();
closeDialogs();
editStates();
}
@ -541,7 +563,17 @@ function editProvinces() {
const provinces = pack.provinces
.filter(p => p.i && !p.removed)
.map(p => {
return {id: p.i + states.length - 1, i: p.i, state: p.state, color: p.color, name: p.name, fullName: p.fullName, area: p.area, urban: p.urban, rural: p.rural};
return {
id: p.i + states.length - 1,
i: p.i,
state: p.state,
color: p.color,
name: p.name,
fullName: p.fullName,
area: p.area,
urban: p.urban,
rural: p.rural
};
});
const data = states.concat(provinces);
const root = d3
@ -564,7 +596,13 @@ function editProvinces() {
<option value="urban">Urban population</option>
</select>`;
alertMessage.innerHTML += `<div id='provinceInfo' class='chartInfo'>&#8205;</div>`;
const svg = d3.select("#alertMessage").insert("svg", "#provinceInfo").attr("id", "provincesTree").attr("width", width).attr("height", height).attr("font-size", "10px");
const svg = d3
.select("#alertMessage")
.insert("svg", "#provinceInfo")
.attr("id", "provincesTree")
.attr("width", width)
.attr("height", height)
.attr("font-size", "10px");
const graph = svg.append("g").attr("transform", `translate(10, 0)`);
document.getElementById("provincesTreeType").addEventListener("change", updateChart);
@ -589,7 +627,14 @@ function editProvinces() {
const rural = rn(d.data.rural * populationRate);
const urban = rn(d.data.urban * populationRate * urbanization);
const value = provincesTreeType.value === "area" ? "Area: " + area : provincesTreeType.value === "rural" ? "Rural population: " + si(rural) : provincesTreeType.value === "urban" ? "Urban population: " + si(urban) : "Population: " + si(rural + urban);
const value =
provincesTreeType.value === "area"
? "Area: " + area
: provincesTreeType.value === "rural"
? "Rural population: " + si(rural)
: provincesTreeType.value === "urban"
? "Urban population: " + si(urban)
: "Population: " + si(rural + urban);
provinceInfo.innerHTML = `${name}. ${state}. ${value}`;
provinceHighlightOn(ev);
@ -637,7 +682,8 @@ function editProvinces() {
}
function updateChart() {
const value = this.value === "area" ? d => d.area : this.value === "rural" ? d => d.rural : this.value === "urban" ? d => d.urban : d => d.rural + d.urban;
const value =
this.value === "area" ? d => d.area : this.value === "rural" ? d => d.rural : this.value === "urban" ? d => d.urban : d => d.rural + d.urban;
root.sum(value);
node.data(treeLayout(root).leaves());
@ -681,6 +727,34 @@ function editProvinces() {
provs.selectAll("text").call(d3.drag().on("drag", dragLabel)).classed("draggable", true);
}
function triggerProvincesRelease() {
confirmationDialog({
title: "Release provinces",
message: `Are you sure you want to release all provinces?
</br>It will turn all separable provinces into independent states.
</br>Capital province and provinces without any burgs will state as they are`,
confirm: "Release",
onConfirm: () => {
const oldStateIds = [];
const newStateIds = [];
body.querySelectorAll(":scope > div").forEach(el => {
const provinceId = +el.dataset.id;
const province = pack.provinces[provinceId];
if (!province.burg) return;
if (province.burg === pack.states[province.state].capital) return;
if (province.burgs.some(burgId => pack.burgs[burgId].capital)) return;
const [oldStateId, newStateId] = declareProvinceIndependence(provinceId);
oldStateIds.push(oldStateId);
newStateIds.push(newStateId);
});
updateStatesPostRelease(unique(oldStateIds), newStateIds);
}
});
}
function enterProvincesManualAssignent() {
if (!layerIsOn("toggleProvinces")) toggleProvinces();
if (!layerIsOn("toggleBorders")) toggleBorders();
@ -783,7 +857,13 @@ function editProvinces() {
if (pack.cells.province[i] === provinceNew) exists.remove();
else exists.attr("data-province", provinceNew).attr("fill", fill);
} else {
temp.append("polygon").attr("points", getPackPolygon(i)).attr("data-cell", i).attr("data-province", provinceNew).attr("fill", fill).attr("stroke", "#555");
temp
.append("polygon")
.attr("points", getPackPolygon(i))
.attr("data-cell", i)
.attr("data-province", provinceNew)
.attr("fill", fill)
.attr("stroke", "#555");
}
});
}
@ -839,10 +919,8 @@ function editProvinces() {
}
function enterAddProvinceMode() {
if (this.classList.contains("pressed")) {
exitAddProvinceMode();
return;
}
if (this.classList.contains("pressed")) return exitAddProvinceMode();
customization = 12;
this.classList.add("pressed");
tip("Click on the map to place a new province center", true);
@ -851,24 +929,17 @@ function editProvinces() {
}
function addProvince() {
const cells = pack.cells,
provinces = pack.provinces;
const {cells, provinces} = pack;
const point = d3.mouse(this);
const center = findCell(point[0], point[1]);
if (cells.h[center] < 20) {
tip("You cannot place province into the water. Please click on a land cell", false, "error");
return;
}
if (cells.h[center] < 20) return tip("You cannot place province into the water. Please click on a land cell", false, "error");
const oldProvince = cells.province[center];
if (oldProvince && provinces[oldProvince].center === center) {
tip("The cell is already a center of a different province. Select other cell", false, "error");
return;
}
if (oldProvince && provinces[oldProvince].center === center)
return tip("The cell is already a center of a different province. Select other cell", false, "error");
const state = cells.state[center];
if (!state) {
tip("You cannot create a province in neutral lands. Please assign this land to a state first", false, "error");
return;
}
if (!state) return tip("You cannot create a province in neutral lands. Please assign this land to a state first", false, "error");
if (d3.event.shiftKey === false) exitAddProvinceMode();
@ -879,8 +950,8 @@ function editProvinces() {
const name = burg ? pack.burgs[burg].name : Names.getState(Names.getCultureShort(c), c);
const formName = oldProvince ? provinces[oldProvince].formName : "Province";
const fullName = name + " " + formName;
const stateColor = pack.states[state].color,
rndColor = getRandomColor();
const stateColor = pack.states[state].color;
const rndColor = getRandomColor();
const color = stateColor[0] === "#" ? d3.color(d3.interpolate(stateColor, rndColor)(0.2)).hex() : rndColor;
// generate emblem

View file

@ -91,7 +91,7 @@ function overviewRivers() {
function zoomToRiver() {
const r = +this.parentNode.dataset.id;
const river = rivers.select("#river" + r).node();
highlightElement(river);
highlightElement(river, 3);
}
function toggleBasinsHightlight() {

View file

@ -126,9 +126,15 @@ function editStates() {
const capital = pack.burgs[s.capital].name;
COArenderer.trigger("stateCOA" + s.i, s.coa);
lines += `<div class="states" data-id=${s.i} data-name="${s.name}" data-form="${s.formName}" data-capital="${capital}" data-color="${s.color}" data-cells=${s.cells}
data-area=${area} data-population=${population} data-burgs=${s.burgs} data-culture=${pack.cultures[s.culture].name} data-type=${s.type} data-expansionism=${s.expansionism}>
<svg data-tip="State fill style. Click to change" width=".9em" height=".9em" style="margin-bottom:-1px"><rect x="0" y="0" width="100%" height="100%" fill="${s.color}" class="fillRect pointer"></svg>
lines += `<div class="states" data-id=${s.i} data-name="${s.name}" data-form="${s.formName}" data-capital="${capital}" data-color="${
s.color
}" data-cells=${s.cells}
data-area=${area} data-population=${population} data-burgs=${s.burgs} data-culture=${pack.cultures[s.culture].name} data-type=${
s.type
} data-expansionism=${s.expansionism}>
<svg data-tip="State fill style. Click to change" width=".9em" height=".9em" style="margin-bottom:-1px"><rect x="0" y="0" width="100%" height="100%" fill="${
s.color
}" class="fillRect pointer"></svg>
<input data-tip="State name. Click to change" class="stateName name pointer" value="${s.name}" readonly>
<svg data-tip="Click to show and edit state emblem" class="coaIcon hide" viewBox="0 0 200 200"><use href="#stateCOA${s.i}"></use></svg>
<input data-tip="State form name. Click to change" class="stateForm name pointer" value="${s.formName}" readonly>
@ -143,7 +149,9 @@ function editStates() {
<div data-tip="${populationTip}" class="culturePopulation hide">${si(population)}</div>
<select data-tip="State type. Defines growth model. Click to change" class="cultureType ${hidden} show hide">${getTypeOptions(s.type)}</select>
<span data-tip="State expansionism" class="icon-resize-full ${hidden} show hide"></span>
<input data-tip="Expansionism (defines competitive size). Change to re-calculate states based on new value" class="statePower ${hidden} show hide" type="number" min=0 max=99 step=.1 value=${s.expansionism}>
<input data-tip="Expansionism (defines competitive size). Change to re-calculate states based on new value" class="statePower ${hidden} show hide" type="number" min=0 max=99 step=.1 value=${
s.expansionism
}>
<span data-tip="Cells count" class="icon-check-empty ${hidden} show hide"></span>
<div data-tip="Cells count" class="stateCells ${hidden} show hide">${s.cells}</div>
<span data-tip="Toggle state focus" class="icon-pin ${focused ? "" : " inactive"} hide"></span>
@ -200,7 +208,15 @@ function editStates() {
if (customization || !state) return;
const d = regions.select("#state" + state).attr("d");
const path = debug.append("path").attr("class", "highlight").attr("d", d).attr("fill", "none").attr("stroke", "red").attr("stroke-width", 1).attr("opacity", 1).attr("filter", "url(#blur1)");
const path = debug
.append("path")
.attr("class", "highlight")
.attr("d", d)
.attr("fill", "none")
.attr("stroke", "red")
.attr("stroke-width", 1)
.attr("opacity", 1)
.attr("filter", "url(#blur1)");
const l = path.node().getTotalLength(),
dur = (l + 5000) / 2;
@ -498,6 +514,7 @@ function editStates() {
pack.cells.province.forEach((pr, i) => {
if (pr === p) pack.cells.province[i] = 0;
});
const coaId = "provinceCOA" + p;
if (document.getElementById(coaId)) document.getElementById(coaId).remove();
emblems.select(`#provinceEmblems > use[data-i='${p}']`).remove();
@ -564,19 +581,20 @@ function editStates() {
function showStatesChart() {
// build hierarchy tree
const data = pack.states.filter(s => !s.removed);
const statesData = pack.states.filter(s => !s.removed);
if (statesData.length < 2) return tip("There are no states to show", false, "error");
const root = d3
.stratify()
.id(d => d.i)
.parentId(d => (d.i ? 0 : null))(data)
.parentId(d => (d.i ? 0 : null))(statesData)
.sum(d => d.area)
.sort((a, b) => b.value - a.value);
const width = 150 + 200 * uiSizeOutput.value,
height = 150 + 200 * uiSizeOutput.value;
const size = 150 + 200 * uiSizeOutput.value;
const margin = {top: 0, right: -50, bottom: 0, left: -50};
const w = width - margin.left - margin.right;
const h = height - margin.top - margin.bottom;
const w = size - margin.left - margin.right;
const h = size - margin.top - margin.bottom;
const treeLayout = d3.pack().size([w, h]).padding(3);
// prepare svg
@ -588,7 +606,16 @@ function editStates() {
<option value="burgs">Burgs number</option>
</select>`;
alertMessage.innerHTML += `<div id='statesInfo' class='chartInfo'>&#8205;</div>`;
const svg = d3.select("#alertMessage").insert("svg", "#statesInfo").attr("id", "statesTree").attr("width", width).attr("height", height).style("font-family", "Almendra SC").attr("text-anchor", "middle").attr("dominant-baseline", "central");
const svg = d3
.select("#alertMessage")
.insert("svg", "#statesInfo")
.attr("id", "statesTree")
.attr("width", size)
.attr("height", size)
.style("font-family", "Almendra SC")
.attr("text-anchor", "middle")
.attr("dominant-baseline", "central");
const graph = svg.append("g").attr("transform", `translate(-50, 0)`);
document.getElementById("statesTreeType").addEventListener("change", updateChart);
@ -632,7 +659,16 @@ function editStates() {
const urban = rn(d.data.urban * populationRate * urbanization);
const option = statesTreeType.value;
const value = option === "area" ? "Area: " + area : option === "rural" ? "Rural population: " + si(rural) : option === "urban" ? "Urban population: " + si(urban) : option === "burgs" ? "Burgs number: " + d.data.burgs : "Population: " + si(rural + urban);
const value =
option === "area"
? "Area: " + area
: option === "rural"
? "Rural population: " + si(rural)
: option === "urban"
? "Urban population: " + si(urban)
: option === "burgs"
? "Burgs number: " + d.data.burgs
: "Population: " + si(rural + urban);
statesInfo.innerHTML = `${state}. ${value}`;
stateHighlightOn(ev);
@ -646,7 +682,16 @@ function editStates() {
}
function updateChart() {
const value = this.value === "area" ? d => d.area : this.value === "rural" ? d => d.rural : this.value === "urban" ? d => d.urban : this.value === "burgs" ? d => d.burgs : d => d.rural + d.urban;
const value =
this.value === "area"
? d => d.area
: this.value === "rural"
? d => d.rural
: this.value === "urban"
? d => d.urban
: this.value === "burgs"
? d => d.burgs
: d => d.rural + d.urban;
root.sum(value);
node.data(treeLayout(root).leaves());
@ -731,7 +776,11 @@ function editStates() {
$("#statesEditor").dialog({position: {my: "right top", at: "right-10 top+10", of: "svg", collision: "fit"}});
tip("Click on state to select, drag the circle to change state", true);
viewbox.style("cursor", "crosshair").on("click", selectStateOnMapClick).call(d3.drag().on("start", dragStateBrush)).on("touchmove mousemove", moveStateBrush);
viewbox
.style("cursor", "crosshair")
.on("click", selectStateOnMapClick)
.call(d3.drag().on("start", dragStateBrush))
.on("touchmove mousemove", moveStateBrush);
body.querySelector("div").classList.add("selected");
}
@ -797,9 +846,9 @@ function editStates() {
}
function applyStatesManualAssignent() {
const cells = pack.cells,
affectedStates = [],
affectedProvinces = [];
const {cells} = pack;
const affectedStates = [];
const affectedProvinces = [];
statesBody
.select("#temp")
@ -815,77 +864,145 @@ function editStates() {
if (affectedStates.length) {
refreshStatesEditor();
if (!layerIsOn("toggleStates")) toggleStates();
else drawStates();
layerIsOn("toggleStates") ? drawStates() : toggleStates();
if (adjustLabels.checked) BurgsAndStates.drawStateLabels([...new Set(affectedStates)]);
adjustProvinces([...new Set(affectedProvinces)]);
if (!layerIsOn("toggleBorders")) toggleBorders();
else drawBorders();
layerIsOn("toggleBorders") ? drawBorders() : toggleBorders();
if (layerIsOn("toggleProvinces")) drawProvinces();
}
exitStatesManualAssignment();
}
function adjustProvinces(affectedProvinces) {
const {cells, provinces, states} = pack;
const form = {Zone: 1, Area: 1, Territory: 2, Province: 1};
const {cells, provinces, states, burgs} = pack;
affectedProvinces.forEach(p => {
if (!p) return; // do nothing if neutral lands are captured
const old = provinces[p].state;
// remove province from state provinces list
if (states[old]?.provinces?.includes(p)) states[old].provinces.splice(states[old].provinces.indexOf(p), 1);
affectedProvinces.forEach(provinceId => {
if (!provinces[provinceId]) return; // lands without province captured => do nothing
// find states owning at least 1 province cell
const provCells = cells.i.filter(i => cells.province[i] === p);
const provCells = cells.i.filter(i => cells.province[i] === provinceId);
const provStates = [...new Set(provCells.map(i => cells.state[i]))];
// assign province to its center owner; if center is neutral, remove province
const owner = cells.state[provinces[p].center];
if (owner) {
const name = provinces[p].name;
// province is captured completely => change owner or remove
if (provinceId && provStates.length === 1) return changeProvinceOwner(provinceId, provStates[0], provCells);
// if province is a historical part of another state's province, unite with old province
const part = states[owner].provinces.find(n => name.includes(provinces[n].name));
if (part) {
provinces[p].removed = true;
provCells.filter(i => cells.state[i] === owner).forEach(i => (cells.province[i] = part));
} else {
provinces[p].state = owner;
states[owner].provinces.push(p);
provinces[p].color = getMixedColor(states[owner].color);
}
} else {
provinces[p].removed = true;
provCells.filter(i => !cells.state[i]).forEach(i => (cells.province[i] = 0));
}
// create new provinces for non-main part
provStates
.filter(s => s && s !== owner)
.forEach(s =>
createProvince(
p,
s,
provCells.filter(i => cells.state[i] === s)
)
);
// province is captured partially => split province
splitProvince(provinceId, provStates, provCells);
});
function createProvince(initProv, state, provCells) {
const province = provinces.length;
provCells.forEach(i => (cells.province[i] = province));
function changeProvinceOwner(provinceId, newOwnerId, provinceCells) {
const province = provinces[provinceId];
const prevOwner = states[province.state];
const burgCell = provCells.find(i => cells.burg[i]);
const center = burgCell ? burgCell : provCells[0];
const burg = burgCell ? cells.burg[burgCell] : 0;
// remove province from old owner list
prevOwner.provinces = prevOwner.provinces.filter(province => province !== provinceId);
const name = burgCell && P(0.7) ? getAdjective(pack.burgs[burg].name) : getAdjective(states[state].name) + " " + provinces[initProv].name.split(" ").slice(-1)[0];
const formName = name.split(" ").length > 1 ? provinces[initProv].formName : rw(form);
const fullName = name + " " + formName;
const color = getMixedColor(states[state].color);
provinces.push({i: province, state, center, burg, name, formName, fullName, color});
if (newOwnerId) {
// new owner is a state => change owner
province.state = newOwnerId;
states[newOwnerId].provinces.push(provinceId);
} else {
// new owner is neutral => remove province
provinces[provinceId] = {i: provinceId, removed: true};
provinceCells.forEach(i => {
cells.province[i] = 0;
});
}
}
function splitProvince(provinceId, provinceStates, provinceCells) {
const province = provinces[provinceId];
const prevOwner = states[province.state];
const provinceCenterOwner = cells.state[province.center];
provinceStates.forEach(stateId => {
const stateProvinceCells = provinceCells.filter(i => cells.state[i] === stateId);
if (stateId === provinceCenterOwner) {
// province center is owned by the same state => do nothing for this state
if (stateId === prevOwner.i) return;
// province center is captured by neutrals => remove province
if (!stateId) {
provinces[provinceId] = {i: provinceId, removed: true};
stateProvinceCells.forEach(i => {
cells.province[i] = 0;
});
return;
}
// reassign province ownership to province center owner
prevOwner.provinces = prevOwner.provinces.filter(province => province !== provinceId);
province.state = stateId;
province.color = getMixedColor(states[stateId].color);
states[stateId].provinces.push(provinceId);
return;
}
// province cells captured by neutrals => remove captured cells from province
if (!stateId) {
stateProvinceCells.forEach(i => {
cells.province[i] = 0;
});
return;
}
// a few province cells owned by state => add to closes province
if (stateProvinceCells.length < 20) {
const closestProvince = findClosestProvince(provinceId, stateId, stateProvinceCells);
if (closestProvince) {
stateProvinceCells.forEach(i => {
cells.province[i] = closestProvince;
});
return;
}
}
// some province cells owned by state => create new province
createProvince(province, stateId, stateProvinceCells);
});
}
function createProvince(oldProvince, stateId, provinceCells) {
const newProvinceId = provinces.length;
const burgCell = provinceCells.find(i => cells.burg[i]);
const center = burgCell ? burgCell : provinceCells[0];
const burgId = burgCell ? cells.burg[burgCell] : 0;
const burg = burgId ? burgs[burgId] : null;
const culture = cells.culture[center];
const nameByBurg = burgCell && P(0.5);
const name = nameByBurg ? burg.name : oldProvince.name || Names.getState(Names.getCultureShort(culture), culture);
const formOptions = ["Zone", "Area", "Territory", "Province"];
const formName = burgCell && oldProvince.formName ? oldProvince.formName : ra(formOptions);
const color = getMixedColor(states[stateId].color);
const kinship = nameByBurg ? 0.8 : 0.4;
const type = BurgsAndStates.getType(center, burg?.port);
const coa = COA.generate(burg?.coa || states[stateId].coa, kinship, burg ? null : 0.9, type);
coa.shield = COA.getShield(culture, stateId);
provinces.push({i: newProvinceId, state: stateId, center, burg: burgId, name, formName, fullName: `${name} ${formName}`, color, coa});
provinceCells.forEach(i => {
cells.province[i] = newProvinceId;
});
states[stateId].provinces.push(newProvinceId);
}
function findClosestProvince(provinceId, stateId, sourceCells) {
const borderCell = sourceCells.find(i =>
cells.c[i].some(c => {
return cells.state[c] === stateId && cells.province[c] && cells.province[c] !== provinceId;
})
);
const closesProvince = borderCell && cells.c[borderCell].map(c => cells.province[c]).find(province => province && province !== provinceId);
return closesProvince;
}
}
@ -921,20 +1038,14 @@ function editStates() {
}
function addState() {
const states = pack.states,
burgs = pack.burgs,
cells = pack.cells;
const {cells, states, burgs} = pack;
const point = d3.mouse(this);
const center = findCell(point[0], point[1]);
if (cells.h[center] < 20) {
tip("You cannot place state into the water. Please click on a land cell", false, "error");
return;
}
if (cells.h[center] < 20) return tip("You cannot place state into the water. Please click on a land cell", false, "error");
let burg = cells.burg[center];
if (burg && burgs[burg].capital) {
tip("Existing capital cannot be selected as a new state capital! Select other cell", false, "error");
return;
}
if (burg && burgs[burg].capital) return tip("Existing capital cannot be selected as a new state capital! Select other cell", false, "error");
if (!burg) burg = addBurg(point); // add new burg
const oldState = cells.state[center];
@ -985,7 +1096,22 @@ function editStates() {
cells.state[center] = newState;
cells.province[center] = 0;
states.push({i: newState, name, diplomacy, provinces: [], color, expansionism: 0.5, capital: burg, type: "Generic", center, culture, military: [], alert: 1, coa, pole});
states.push({
i: newState,
name,
diplomacy,
provinces: [],
color,
expansionism: 0.5,
capital: burg,
type: "Generic",
center,
culture,
military: [],
alert: 1,
coa,
pole
});
BurgsAndStates.collectStatistics();
BurgsAndStates.defineStateForms([newState]);
adjustProvinces([cells.province[center]]);
@ -1028,7 +1154,8 @@ function editStates() {
function downloadStatesData() {
const unit = areaUnit.value === "square" ? distanceUnitInput.value + "2" : areaUnit.value;
let data = "Id,State,Full Name,Form,Color,Capital,Culture,Type,Expansionism,Cells,Burgs,Area " + unit + ",Total Population,Rural Population,Urban Population\n"; // headers
let data =
"Id,State,Full Name,Form,Color,Capital,Culture,Type,Expansionism,Cells,Burgs,Area " + unit + ",Total Population,Rural Population,Urban Population\n"; // headers
body.querySelectorAll(":scope > div").forEach(function (el) {
const key = parseInt(el.dataset.id);
const statePack = pack.states[key];

View file

@ -75,7 +75,11 @@ function selectStyleElement() {
}
// stroke color and width
if (["armies", "routes", "lakes", "borders", "cults", "relig", "cells", "coastline", "prec", "ice", "icons", "coordinates", "zones", "gridOverlay"].includes(sel)) {
if (
["armies", "routes", "lakes", "borders", "cults", "relig", "cells", "coastline", "prec", "ice", "icons", "coordinates", "zones", "gridOverlay"].includes(
sel
)
) {
styleStroke.style.display = "block";
styleStrokeInput.value = styleStrokeOutput.value = el.attr("stroke");
styleStrokeWidth.style.display = "block";
@ -331,7 +335,6 @@ styleFilterInput.addEventListener("change", function () {
styleTextureInput.addEventListener("change", function () {
if (this.value === "none") texture.select("image").attr("xlink:href", "");
if (this.value === "default") texture.select("image").attr("xlink:href", getDefaultTexture());
else getBase64(this.value, base64 => texture.select("image").attr("xlink:href", base64));
});
@ -784,12 +787,42 @@ function applyDefaultStyle() {
biomes.attr("opacity", null).attr("filter", null).attr("mask", "url(#land)");
ice.attr("opacity", 0.9).attr("fill", "#e8f0f6").attr("stroke", "#e8f0f6").attr("stroke-width", 1).attr("filter", "url(#dropShadow05)");
stateBorders.attr("opacity", 0.8).attr("stroke", "#56566d").attr("stroke-width", 1).attr("stroke-dasharray", "2").attr("stroke-linecap", "butt").attr("filter", null);
provinceBorders.attr("opacity", 0.8).attr("stroke", "#56566d").attr("stroke-width", 0.5).attr("stroke-dasharray", "0 2").attr("stroke-linecap", "round").attr("filter", null);
stateBorders
.attr("opacity", 0.8)
.attr("stroke", "#56566d")
.attr("stroke-width", 1)
.attr("stroke-dasharray", "2")
.attr("stroke-linecap", "butt")
.attr("filter", null);
provinceBorders
.attr("opacity", 0.8)
.attr("stroke", "#56566d")
.attr("stroke-width", 0.5)
.attr("stroke-dasharray", "0 2")
.attr("stroke-linecap", "round")
.attr("filter", null);
cells.attr("opacity", null).attr("stroke", "#808080").attr("stroke-width", 0.1).attr("filter", null).attr("mask", null);
gridOverlay.attr("opacity", 0.8).attr("type", "pointyHex").attr("scale", 1).attr("dx", 0).attr("dy", 0).attr("stroke", "#777777").attr("stroke-width", 0.5).attr("stroke-dasharray", null).attr("filter", null).attr("mask", null);
coordinates.attr("opacity", 1).attr("data-size", 12).attr("font-size", 12).attr("stroke", "#d4d4d4").attr("stroke-width", 1).attr("stroke-dasharray", 5).attr("filter", null).attr("mask", null);
gridOverlay
.attr("opacity", 0.8)
.attr("type", "pointyHex")
.attr("scale", 1)
.attr("dx", 0)
.attr("dy", 0)
.attr("stroke", "#777777")
.attr("stroke-width", 0.5)
.attr("stroke-dasharray", null)
.attr("filter", null)
.attr("mask", null);
coordinates
.attr("opacity", 1)
.attr("data-size", 12)
.attr("font-size", 12)
.attr("stroke", "#d4d4d4")
.attr("stroke-width", 1)
.attr("stroke-dasharray", 5)
.attr("filter", null)
.attr("mask", null);
compass.attr("opacity", 0.8).attr("transform", null).attr("filter", null).attr("mask", "url(#water)").attr("shape-rendering", "optimizespeed");
if (!d3.select("#initial").size()) d3.select("#rose").attr("transform", "translate(80 80) scale(.25)");
@ -810,26 +843,68 @@ function applyDefaultStyle() {
lakes.select("#lava").attr("opacity", 0.7).attr("fill", "#90270d").attr("stroke", "#f93e0c").attr("stroke-width", 2).attr("filter", "url(#crumpled)");
lakes.select("#dry").attr("opacity", 1).attr("fill", "#c9bfa7").attr("stroke", "#8e816f").attr("stroke-width", 0.7).attr("filter", null);
coastline.select("#sea_island").attr("opacity", 0.5).attr("stroke", "#1f3846").attr("stroke-width", 0.7).attr("auto-filter", 1).attr("filter", "url(#dropShadow)");
coastline
.select("#sea_island")
.attr("opacity", 0.5)
.attr("stroke", "#1f3846")
.attr("stroke-width", 0.7)
.attr("auto-filter", 1)
.attr("filter", "url(#dropShadow)");
coastline.select("#lake_island").attr("opacity", 1).attr("stroke", "#7c8eaf").attr("stroke-width", 0.35).attr("filter", null);
terrain.attr("opacity", null).attr("set", "simple").attr("size", 1).attr("density", 0.4).attr("filter", null).attr("mask", null);
rivers.attr("opacity", null).attr("fill", "#5d97bb").attr("filter", null);
ruler.attr("opacity", null).attr("filter", null);
roads.attr("opacity", 0.9).attr("stroke", "#d06324").attr("stroke-width", 0.7).attr("stroke-dasharray", "2").attr("stroke-linecap", "butt").attr("filter", null).attr("mask", null);
trails.attr("opacity", 0.9).attr("stroke", "#d06324").attr("stroke-width", 0.25).attr("stroke-dasharray", ".8 1.6").attr("stroke-linecap", "butt").attr("filter", null).attr("mask", null);
searoutes.attr("opacity", 0.8).attr("stroke", "#ffffff").attr("stroke-width", 0.45).attr("stroke-dasharray", "1 2").attr("stroke-linecap", "round").attr("filter", null).attr("mask", null);
roads
.attr("opacity", 0.9)
.attr("stroke", "#d06324")
.attr("stroke-width", 0.7)
.attr("stroke-dasharray", "2")
.attr("stroke-linecap", "butt")
.attr("filter", null)
.attr("mask", null);
trails
.attr("opacity", 0.9)
.attr("stroke", "#d06324")
.attr("stroke-width", 0.25)
.attr("stroke-dasharray", ".8 1.6")
.attr("stroke-linecap", "butt")
.attr("filter", null)
.attr("mask", null);
searoutes
.attr("opacity", 0.8)
.attr("stroke", "#ffffff")
.attr("stroke-width", 0.45)
.attr("stroke-dasharray", "1 2")
.attr("stroke-linecap", "round")
.attr("filter", null)
.attr("mask", null);
statesBody.attr("opacity", 0.4).attr("filter", null);
statesHalo.attr("data-width", 10).attr("stroke-width", 10).attr("opacity", 0.4).attr("filter", "blur(5px)");
provs.attr("opacity", 0.7).attr("fill", "#000000").attr("font-family", "Georgia").attr("data-size", 10).attr("font-size", 10).attr("filter", null);
temperature.attr("opacity", null).attr("fill", "#000000").attr("stroke-width", 1.8).attr("fill-opacity", 0.3).attr("font-size", "8px").attr("stroke-dasharray", null).attr("filter", null).attr("mask", null);
temperature
.attr("opacity", null)
.attr("fill", "#000000")
.attr("stroke-width", 1.8)
.attr("fill-opacity", 0.3)
.attr("font-size", "8px")
.attr("stroke-dasharray", null)
.attr("filter", null)
.attr("mask", null);
texture.attr("opacity", null).attr("filter", null).attr("mask", "url(#land)");
texture.select("#textureImage").attr("x", 0).attr("y", 0);
zones.attr("opacity", 0.6).attr("stroke", "#333333").attr("stroke-width", 0).attr("stroke-dasharray", null).attr("stroke-linecap", "butt").attr("filter", null).attr("mask", null);
zones
.attr("opacity", 0.6)
.attr("stroke", "#333333")
.attr("stroke-width", 0)
.attr("stroke-dasharray", null)
.attr("stroke-linecap", "butt")
.attr("filter", null)
.attr("mask", null);
// ocean and svg default style
svg.attr("background-color", "#000000").attr("data-filter", null).attr("filter", null);
@ -838,24 +913,95 @@ function applyDefaultStyle() {
svg.select("#oceanicPattern").attr("href", "./images/pattern1.png").attr("opacity", 0.2);
// heightmap style
terrs.attr("opacity", null).attr("filter", null).attr("mask", "url(#land)").attr("stroke", "none").attr("scheme", "bright").attr("terracing", 0).attr("skip", 5).attr("relax", 0).attr("curve", 0);
terrs
.attr("opacity", null)
.attr("filter", null)
.attr("mask", "url(#land)")
.attr("stroke", "none")
.attr("scheme", "bright")
.attr("terracing", 0)
.attr("skip", 5)
.attr("relax", 0)
.attr("curve", 0);
// legend
legend.attr("font-family", "Almendra SC").attr("font-size", 13).attr("data-size", 13).attr("data-x", 99).attr("data-y", 93).attr("data-columns", 8).attr("stroke-width", 2.5).attr("stroke", "#812929").attr("stroke-dasharray", "0 4 10 4").attr("stroke-linecap", "round");
legend
.attr("font-family", "Almendra SC")
.attr("font-size", 13)
.attr("data-size", 13)
.attr("data-x", 99)
.attr("data-y", 93)
.attr("data-columns", 8)
.attr("stroke-width", 2.5)
.attr("stroke", "#812929")
.attr("stroke-dasharray", "0 4 10 4")
.attr("stroke-linecap", "round");
legend.select("#legendBox").attr("fill", "#ffffff").attr("fill-opacity", 0.8);
const citiesSize = Math.max(rn(8 - regionsInput.value / 20), 3);
burgLabels.select("#cities").attr("fill", "#3e3e4b").attr("opacity", 1).style("text-shadow", "white 0 0 4px").attr("font-family", "Almendra SC").attr("font-size", citiesSize).attr("data-size", citiesSize);
burgIcons.select("#cities").attr("opacity", 1).attr("size", 1).attr("stroke-width", 0.24).attr("fill", "#ffffff").attr("stroke", "#3e3e4b").attr("fill-opacity", 0.7).attr("stroke-dasharray", "").attr("stroke-linecap", "butt");
burgLabels
.select("#cities")
.attr("fill", "#3e3e4b")
.attr("opacity", 1)
.style("text-shadow", "white 0 0 4px")
.attr("font-family", "Almendra SC")
.attr("font-size", citiesSize)
.attr("data-size", citiesSize);
burgIcons
.select("#cities")
.attr("opacity", 1)
.attr("size", 1)
.attr("stroke-width", 0.24)
.attr("fill", "#ffffff")
.attr("stroke", "#3e3e4b")
.attr("fill-opacity", 0.7)
.attr("stroke-dasharray", "")
.attr("stroke-linecap", "butt");
anchors.select("#cities").attr("opacity", 1).attr("fill", "#ffffff").attr("stroke", "#3e3e4b").attr("stroke-width", 1.2).attr("size", 2);
burgLabels.select("#towns").attr("fill", "#3e3e4b").attr("opacity", 1).style("text-shadow", "white 0 0 4px").attr("font-family", "Almendra SC").attr("font-size", 3).attr("data-size", 4);
burgIcons.select("#towns").attr("opacity", 1).attr("size", 0.5).attr("stroke-width", 0.12).attr("fill", "#ffffff").attr("stroke", "#3e3e4b").attr("fill-opacity", 0.7).attr("stroke-dasharray", "").attr("stroke-linecap", "butt");
burgLabels
.select("#towns")
.attr("fill", "#3e3e4b")
.attr("opacity", 1)
.style("text-shadow", "white 0 0 4px")
.attr("font-family", "Almendra SC")
.attr("font-size", 3)
.attr("data-size", 4);
burgIcons
.select("#towns")
.attr("opacity", 1)
.attr("size", 0.5)
.attr("stroke-width", 0.12)
.attr("fill", "#ffffff")
.attr("stroke", "#3e3e4b")
.attr("fill-opacity", 0.7)
.attr("stroke-dasharray", "")
.attr("stroke-linecap", "butt");
anchors.select("#towns").attr("opacity", 1).attr("fill", "#ffffff").attr("stroke", "#3e3e4b").attr("stroke-width", 1.2).attr("size", 1);
const stateLabelSize = Math.max(rn(24 - regionsInput.value / 6), 6);
labels.select("#states").attr("fill", "#3e3e4b").attr("opacity", 1).attr("stroke", "#3a3a3a").attr("stroke-width", 0).style("text-shadow", "white 0 0 4px").attr("font-family", "Almendra SC").attr("font-size", stateLabelSize).attr("data-size", stateLabelSize).attr("filter", null);
labels.select("#addedLabels").attr("fill", "#3e3e4b").attr("opacity", 1).attr("stroke", "#3a3a3a").attr("stroke-width", 0).style("text-shadow", "white 0 0 4px").attr("font-family", "Almendra SC").attr("font-size", 18).attr("data-size", 18).attr("filter", null);
labels
.select("#states")
.attr("fill", "#3e3e4b")
.attr("opacity", 1)
.attr("stroke", "#3a3a3a")
.attr("stroke-width", 0)
.style("text-shadow", "white 0 0 4px")
.attr("font-family", "Almendra SC")
.attr("font-size", stateLabelSize)
.attr("data-size", stateLabelSize)
.attr("filter", null);
labels
.select("#addedLabels")
.attr("fill", "#3e3e4b")
.attr("opacity", 1)
.attr("stroke", "#3a3a3a")
.attr("stroke-width", 0)
.style("text-shadow", "white 0 0 4px")
.attr("font-family", "Almendra SC")
.attr("font-size", 18)
.attr("data-size", 18)
.attr("filter", null);
fogging.attr("opacity", 0.98).attr("fill", "#30426f");
emblems.attr("opacity", 0.9).attr("stroke-width", 1).attr("filter", null);
@ -887,6 +1033,10 @@ function applyStyle(style) {
function changeStylePreset(preset) {
if (customization) return tip("Please exit the customization mode first", false, "error");
if (sessionStorage.getItem("styleChangeWarningShown")) {
changeStyle();
} else {
sessionStorage.setItem("styleChangeWarningShown", true);
alertMessage.innerHTML = "Are you sure you want to change the style preset? All unsaved style changes will be lost";
$("#alert").dialog({
resizable: false,
@ -894,6 +1044,18 @@ function changeStylePreset(preset) {
width: "23em",
buttons: {
Change: function () {
changeStyle();
$(this).dialog("close");
},
Cancel: function () {
stylePreset.value = stylePreset.dataset.old;
$(this).dialog("close");
}
}
});
}
function changeStyle() {
const customPreset = localStorage.getItem(preset);
if (customPreset) {
if (JSON.isValid(customPreset)) applyStyle(JSON.parse(customPreset));
@ -913,15 +1075,8 @@ function changeStylePreset(preset) {
updateMapFilter();
localStorage.setItem("presetStyle", preset); // save preset to use it onload
stylePreset.dataset.old = stylePreset.value; // save current value
$(this).dialog("close");
},
Cancel: function () {
stylePreset.value = stylePreset.dataset.old;
$(this).dialog("close");
}
}
});
}
function updateElements() {
// burgIcons to desired size
@ -971,8 +1126,9 @@ function addStylePreset() {
position: {my: "center", at: "center", of: "svg"}
});
const currentStyle = document.getElementById("stylePreset").selectedOptions[0].text;
document.getElementById("styleSaverName").value = currentStyle;
const currentPreset = document.getElementById("stylePreset").selectedOptions[0];
const styleName = currentPreset ? currentPreset.text : "custom";
document.getElementById("styleSaverName").value = styleName;
styleSaverJSON.value = JSON.stringify(getStyle(), null, 2);
checkName();
@ -1092,6 +1248,11 @@ function addStylePreset() {
applyOption(stylePreset, preset, styleSaverName.value); // add option
localStorage.setItem("presetStyle", preset); // mark preset as default
localStorage.setItem(preset, styleSaverJSON.value); // save preset
applyStyle(JSON.parse(styleSaverJSON.value));
updateMapFilter();
invokeActiveZooming();
$("#styleSaver").dialog("close");
removeStyleButton.style.display = "inline-block";
tip("Style preset is saved", false, "success", 4000);
@ -1121,6 +1282,10 @@ function removeStylePreset() {
localStorage.removeItem(stylePreset.value);
stylePreset.selectedOptions[0].remove();
removeStyleButton.style.display = "none";
applyDefaultStyle();
updateMapFilter();
invokeActiveZooming();
}
// GLOBAL FILTERS

View file

@ -1,15 +1,15 @@
// module to control the Tools options (click to edit, to re-geenerate, tp add)
"use strict";
// module to control the Tools options (click to edit, to re-geenerate, tp add)
toolsContent.addEventListener("click", function (event) {
if (customization) {
tip("Please exit the customization mode first", false, "warning");
return;
}
if (event.target.tagName !== "BUTTON") return;
if (!["BUTTON", "I"].includes(event.target.tagName)) return;
const button = event.target.id;
// Click to open Editor buttons
// click on open Editor buttons
if (button === "editHeightmapButton") editHeightmap();
else if (button === "editBiomesButton") editBiomes();
else if (button === "editStatesButton") editStates();
@ -25,9 +25,10 @@ toolsContent.addEventListener("click", function (event) {
else if (button === "overviewBurgsButton") overviewBurgs();
else if (button === "overviewRiversButton") overviewRivers();
else if (button === "overviewMilitaryButton") overviewMilitary();
else if (button === "overviewMarkersButton") overviewMarkers();
else if (button === "overviewCellsButton") viewCellDetails();
// Click to Regenerate buttons
// click on Regenerate buttons
if (event.target.parentNode.id === "regenerateFeature") {
if (sessionStorage.getItem("regenerateFeatureDontAsk")) {
processFeatureRegeneration(event, button);
@ -49,7 +50,9 @@ toolsContent.addEventListener("click", function (event) {
},
open: function () {
const pane = $(this).dialog("widget").find(".ui-dialog-buttonpane");
$('<span><input id="dontAsk" class="checkbox" type="checkbox"><label for="dontAsk" class="checkbox-label dontAsk"><i>do not ask again</i></label><span>').prependTo(pane);
$(
'<span><input id="dontAsk" class="checkbox" type="checkbox"><label for="dontAsk" class="checkbox-label dontAsk"><i>do not ask again</i></label><span>'
).prependTo(pane);
},
close: function () {
const box = $(this).dialog("widget").find(".checkbox")[0];
@ -60,7 +63,10 @@ toolsContent.addEventListener("click", function (event) {
});
}
// Click to Add buttons
// click on Configure regenerate buttons
if (button === "configRegenerateMarkers") configMarkersGeneration();
// click on Add buttons
if (button === "addLabel") toggleAddLabel();
else if (button === "addBurgTool") toggleAddBurg();
else if (button === "addRiver") toggleAddRiver();
@ -88,7 +94,7 @@ function processFeatureRegeneration(event, button) {
else if (button === "regenerateCultures") regenerateCultures();
else if (button === "regenerateMilitary") regenerateMilitary();
else if (button === "regenerateIce") regenerateIce();
else if (button === "regenerateMarkers") regenerateMarkers(event);
else if (button === "regenerateMarkers") regenerateMarkers();
else if (button === "regenerateZones") regenerateZones(event);
}
@ -262,7 +268,8 @@ function regenerateBurgs() {
const score = new Int16Array(cells.s.map(s => s * Math.random())); // cell score for capitals placement
const sorted = cells.i.filter(i => score[i] > 0 && cells.culture[i]).sort((a, b) => score[b] - score[a]); // filtered and sorted array of indexes
const burgsCount = manorsInput.value == 1000 ? rn(sorted.length / 5 / (grid.points.length / 10000) ** 0.8) + states.length : +manorsInput.value + states.length;
const burgsCount =
manorsInput.value == 1000 ? rn(sorted.length / 5 / (grid.points.length / 10000) ** 0.8) + states.length : +manorsInput.value + states.length;
const spacing = (graphWidth + graphHeight) / 150 / (burgsCount ** 0.7 / 66); // base min distance between towns
//clear locked list since ids will change
@ -413,23 +420,11 @@ function regenerateIce() {
drawIce();
}
function regenerateMarkers(event) {
if (isCtrlClick(event)) prompt("Please provide markers number multiplier", {default: 1, step: 0.01, min: 0, max: 100}, v => addNumberOfMarkers(v));
else addNumberOfMarkers(gauss(1, 0.5, 0.3, 5, 2));
function addNumberOfMarkers(number) {
// remove existing markers and assigned notes
markers
.selectAll("use")
.each(function () {
const index = notes.findIndex(n => n.id === this.id);
if (index != -1) notes.splice(index, 1);
})
.remove();
addMarkers(number);
if (!layerIsOn("toggleMarkers")) toggleMarkers();
}
function regenerateMarkers() {
Markers.regenerate();
turnButtonOn("toggleMarkers");
drawMarkers();
if (document.getElementById("markersOverviewRefresh").offsetParent) markersOverviewRefresh.click();
}
function regenerateZones(event) {
@ -474,8 +469,23 @@ function addLabelOnClick() {
const name = Names.getCulture(culture);
const id = getNextId("label");
let group = labels.select("#addedLabels");
if (!group.size()) group = labels.append("g").attr("id", "addedLabels").attr("fill", "#3e3e4b").attr("opacity", 1).attr("stroke", "#3a3a3a").attr("stroke-width", 0).attr("font-family", "Almendra SC").attr("font-size", 18).attr("data-size", 18).attr("filter", null);
// use most recently selected label group
const lastSelected = labelGroupSelect.value;
const groupId = ["", "states", "burgLabels"].includes(lastSelected) ? "#addedLabels" : "#" + lastSelected;
let group = labels.select(groupId);
if (!group.size())
group = labels
.append("g")
.attr("id", "addedLabels")
.attr("fill", "#3e3e4b")
.attr("opacity", 1)
.attr("stroke", "#3a3a3a")
.attr("stroke-width", 0)
.attr("font-family", "Almendra SC")
.attr("font-size", 18)
.attr("data-size", 18)
.attr("filter", null);
const example = group.append("text").attr("x", 0).attr("x", 0).text(name);
const width = example.node().getBBox().width;
@ -674,7 +684,7 @@ function addRouteOnClick() {
}
function toggleAddMarker() {
const pressed = document.getElementById("addMarker").classList.contains("pressed");
const pressed = document.getElementById("addMarker")?.classList.contains("pressed");
if (pressed) {
unpressClickToAddButton();
return;
@ -682,45 +692,115 @@ function toggleAddMarker() {
addFeature.querySelectorAll("button.pressed").forEach(b => b.classList.remove("pressed"));
addMarker.classList.add("pressed");
closeDialogs(".stable");
markersAddFromOverview.classList.add("pressed");
viewbox.style("cursor", "crosshair").on("click", addMarkerOnClick);
tip("Click on map to add a marker. Hold Shift to add multiple", true);
if (!layerIsOn("toggleMarkers")) toggleMarkers();
}
function addMarkerOnClick() {
const {markers} = pack;
const point = d3.mouse(this);
const x = rn(point[0], 2),
y = rn(point[1], 2);
const id = getNextId("markerElement");
const x = rn(point[0], 2);
const y = rn(point[1], 2);
const i = markers.length ? last(markers).i + 1 : 0;
const selected = markerSelectGroup.value;
const valid =
selected &&
d3
.select("#defs-markers")
.select("#" + selected)
.size();
const symbol = valid ? "#" + selected : "#marker0";
const added = markers.select("[data-id='" + symbol + "']").size();
let desired = valid && added ? markers.select("[data-id='" + symbol + "']").attr("data-size") : 1;
if (isNaN(desired)) desired = 1;
const size = desired * 5 + 25 / scale;
const isMarkerSelected = markers.length && elSelected?.node()?.parentElement?.id === "markers";
const selectedMarker = isMarkerSelected ? markers.find(marker => marker.i === +elSelected.attr("id").slice(6)) : null;
const baseMarker = selectedMarker || {icon: "❓"};
const marker = {...baseMarker, i, x, y};
markers
.append("use")
.attr("id", id)
.attr("xlink:href", symbol)
.attr("data-id", symbol)
.attr("data-x", x)
.attr("data-y", y)
.attr("x", x - size / 2)
.attr("y", y - size)
.attr("data-size", desired)
.attr("width", size)
.attr("height", size);
markers.push(marker);
const markersElement = document.getElementById("markers");
const rescale = +markersElement.getAttribute("rescale");
markersElement.insertAdjacentHTML("beforeend", drawMarker(marker, rescale));
if (d3.event.shiftKey === false) unpressClickToAddButton();
if (d3.event.shiftKey === false) {
document.getElementById("markerAdd").classList.remove("pressed");
document.getElementById("markersAddFromOverview").classList.remove("pressed");
unpressClickToAddButton();
}
}
function configMarkersGeneration() {
drawConfigTable();
function drawConfigTable() {
const {markers} = pack;
const config = Markers.getConfig();
const headers = `<thead style='font-weight:bold'><tr>
<td data-tip="Marker type name">Type</td>
<td data-tip="Marker icon">Icon</td>
<td data-tip="Marker number multiplier">Multiplier</td>
<td data-tip="Number of markers of that type on the current map">Number</td>
</tr></thead>`;
const lines = config.map(({type, icon, multiplier}, index) => {
const inputId = `markerIconInput${index}`;
return `<tr>
<td><input value="${type}" /></td>
<td>
<input id="${inputId}" style="width: 5em" value="${icon}" />
<i class="icon-edit pointer" style="position: absolute; margin:.4em 0 0 -1.4em; font-size:.85em"></i>
</td>
<td><input type="number" min="0" max="100" step="0.1" value="${multiplier}" /></td>
<td style="text-align:center">${markers.filter(marker => marker.type === type).length}</td>
</tr>`;
});
const table = `<table class="table">${headers}<tbody>${lines.join("")}</tbody></table>`;
alertMessage.innerHTML = table;
alertMessage.querySelectorAll("i").forEach(selectIconButton => {
selectIconButton.addEventListener("click", function () {
const input = this.previousElementSibling;
selectIcon(input.value, icon => (input.value = icon));
});
});
}
const applyChanges = () => {
const rows = alertMessage.querySelectorAll("tbody > tr");
const rowsData = Array.from(rows).map(row => {
const inputs = row.querySelectorAll("input");
return {
type: inputs[0].value,
icon: inputs[1].value,
multiplier: parseFloat(inputs[2].value)
};
});
const config = Markers.getConfig();
const newConfig = config.map((markerType, index) => {
const {type, icon, multiplier} = rowsData[index];
return {...markerType, type, icon, multiplier};
});
Markers.setConfig(newConfig);
};
$("#alert").dialog({
resizable: false,
title: "Markers generation settings",
position: {my: "left top", at: "left+10 top+10", of: "svg", collision: "fit"},
buttons: {
Regenerate: () => {
applyChanges();
regenerateMarkers();
drawConfigTable();
},
Close: function () {
$(this).dialog("close");
}
},
open: function () {
const buttons = $(this).dialog("widget").find(".ui-dialog-buttonset > button");
buttons[0].addEventListener("mousemove", () => tip("Apply changes and regenerate markers"));
buttons[1].addEventListener("mousemove", () => tip("Close the window"));
},
close: function () {
$(this).dialog("destroy");
}
});
}
function viewCellDetails() {

View file

@ -31,6 +31,8 @@ function editUnits() {
document.getElementById("populationRateInput").addEventListener("change", changePopulationRate);
document.getElementById("urbanizationOutput").addEventListener("input", changeUrbanizationRate);
document.getElementById("urbanizationInput").addEventListener("change", changeUrbanizationRate);
document.getElementById("urbanDensityOutput").addEventListener("input", changeUrbanDensity);
document.getElementById("urbanDensityInput").addEventListener("change", changeUrbanDensity);
document.getElementById("addLinearRuler").addEventListener("click", addRuler);
document.getElementById("addOpisometer").addEventListener("click", toggleOpisometerMode);
@ -94,6 +96,10 @@ function editUnits() {
urbanization = +this.value;
}
function changeUrbanDensity() {
urbanDensity = +this.value;
}
function restoreDefaultUnits() {
// distanceScale
distanceScale = 3;
@ -137,8 +143,10 @@ function editUnits() {
// population
populationRate = populationRateOutput.value = populationRateInput.value = 1000;
urbanization = urbanizationOutput.value = urbanizationInput.value = 1;
urbanDensity = urbanDensityOutput.value = urbanDensityInput.value = 10;
localStorage.removeItem("populationRate");
localStorage.removeItem("urbanization");
localStorage.removeItem("urbanDensity");
}
function addRuler() {

View file

@ -18,6 +18,9 @@ function editWorld() {
buttons[2].addEventListener("mousemove", () => tip("Click to set map size to cover the Tropical latitudes"));
buttons[3].addEventListener("mousemove", () => tip("Click to set map size to cover the Southern latitudes"));
buttons[4].addEventListener("mousemove", () => tip("Click to restore default wind directions"));
},
close: function () {
$(this).dialog("destroy");
}
});

File diff suppressed because one or more lines are too long

17
utils/arrayUtils.js Normal file
View file

@ -0,0 +1,17 @@
"use strict";
// FMG utils related to arrays
// return the last element of array
function last(array) {
return array[array.length - 1];
}
// return array of values common for both array a and array b
function common(a, b) {
const setB = new Set(b);
return [...new Set(a)].filter(a => setB.has(a));
}
function unique(array) {
return [...new Set(array)];
}

33
utils/colorUtils.js Normal file
View file

@ -0,0 +1,33 @@
"use strict";
// FMG utils related to colors
// convert RGB color string to HEX without #
function toHEX(rgb) {
if (rgb.charAt(0) === "#") return rgb;
rgb = rgb.match(/^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?/i);
return rgb && rgb.length === 4
? "#" +
("0" + parseInt(rgb[1], 10).toString(16)).slice(-2) +
("0" + parseInt(rgb[2], 10).toString(16)).slice(-2) +
("0" + parseInt(rgb[3], 10).toString(16)).slice(-2)
: "";
}
// return array of standard shuffled colors
function getColors(number) {
const c12 = ["#dababf", "#fb8072", "#80b1d3", "#fdb462", "#b3de69", "#fccde5", "#c6b9c1", "#bc80bd", "#ccebc5", "#ffed6f", "#8dd3c7", "#eb8de7"];
const cRB = d3.scaleSequential(d3.interpolateRainbow);
const colors = d3.shuffle(d3.range(number).map(i => (i < 12 ? c12[i] : d3.color(cRB((i - 12) / (number - 12))).hex())));
return colors;
}
function getRandomColor() {
return d3.color(d3.scaleSequential(d3.interpolateRainbow)(Math.random())).hex();
}
// mix a color with a random color
function getMixedColor(color, mix = 0.2, bright = 0.3) {
const c = color && color[0] === "#" ? color : getRandomColor(); // if provided color is not hex (e.g. harching), generate random one
return d3.color(d3.interpolate(c, getRandomColor())(mix)).brighter(bright).hex();
}

225
utils/commonUtils.js Normal file
View file

@ -0,0 +1,225 @@
"use strict";
// FMG helper functions
// clip polygon by graph bbox
function clipPoly(points, secure = 0) {
return polygonclip(points, [0, 0, graphWidth, graphHeight], secure);
}
// get segment of any point on polyline
function getSegmentId(points, point, step = 10) {
if (points.length === 2) return 1;
const d2 = (p1, p2) => (p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2;
let minSegment = 1;
let minDist = Infinity;
for (let i = 0; i < points.length - 1; i++) {
const p1 = points[i];
const p2 = points[i + 1];
const length = Math.sqrt(d2(p1, p2));
const segments = Math.ceil(length / step);
const dx = (p2[0] - p1[0]) / segments;
const dy = (p2[1] - p1[1]) / segments;
for (let s = 0; s < segments; s++) {
const x = p1[0] + s * dx;
const y = p1[1] + s * dy;
const dist2 = d2(point, [x, y]);
if (dist2 >= minDist) continue;
minDist = dist2;
minSegment = i + 1;
}
}
return minSegment;
}
// return center point of common edge of 2 pack cells
function getMiddlePoint(cell1, cell2) {
const {cells, vertices} = pack;
const commonVertices = cells.v[cell1].filter(vertex => vertices.c[vertex].some(cell => cell === cell2));
const [x1, y1] = vertices.p[commonVertices[0]];
const [x2, y2] = vertices.p[commonVertices[1]];
const x = (x1 + x2) / 2;
const y = (y1 + y2) / 2;
return [x, y];
}
function debounce(func, ms) {
let isCooldown = false;
return function () {
if (isCooldown) return;
func.apply(this, arguments);
isCooldown = true;
setTimeout(() => (isCooldown = false), ms);
};
}
function throttle(func, ms) {
let isThrottled = false;
let savedArgs;
let savedThis;
function wrapper() {
if (isThrottled) {
savedArgs = arguments;
savedThis = this;
return;
}
func.apply(this, arguments);
isThrottled = true;
setTimeout(function () {
isThrottled = false;
if (savedArgs) {
wrapper.apply(savedThis, savedArgs);
savedArgs = savedThis = null;
}
}, ms);
}
return wrapper;
}
// parse error to get the readable string in Chrome and Firefox
function parseError(error) {
const isFirefox = navigator.userAgent.toLowerCase().indexOf("firefox") > -1;
const errorString = isFirefox ? error.toString() + " " + error.stack : error.stack;
const regex = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gi;
const errorNoURL = errorString.replace(regex, url => "<i>" + last(url.split("/")) + "</i>");
const errorParsed = errorNoURL.replace(/at /gi, "<br>&nbsp;&nbsp;at ");
return errorParsed;
}
function getBase64(url, callback) {
const xhr = new XMLHttpRequest();
xhr.onload = function () {
const reader = new FileReader();
reader.onloadend = function () {
callback(reader.result);
};
reader.readAsDataURL(xhr.response);
};
xhr.open("GET", url);
xhr.responseType = "blob";
xhr.send();
}
// open URL in a new tab or window
function openURL(url) {
window.open(url, "_blank");
}
// open project wiki-page
function wiki(page) {
window.open("https://github.com/Azgaar/Fantasy-Map-Generator/wiki/" + page, "_blank");
}
// wrap URL into html a element
function link(URL, description) {
return `<a href="${URL}" rel="noopener" target="_blank">${description}</a>`;
}
function isCtrlClick(event) {
// meta key is cmd key on MacOs
return event.ctrlKey || event.metaKey;
}
function generateDate(from = 100, to = 1000) {
return new Date(rand(from, to), rand(12), rand(31)).toLocaleDateString("en", {year: "numeric", month: "long", day: "numeric"});
}
function getLongitude(x, decimals = 2) {
return rn(mapCoordinates.lonW + (x / graphWidth) * mapCoordinates.lonT, decimals);
}
function getLatitude(y, decimals = 2) {
return rn(mapCoordinates.latN - (y / graphHeight) * mapCoordinates.latT, decimals);
}
function getCoordinates(x, y, decimals = 2) {
return [getLongitude(x, decimals), getLatitude(y, decimals)];
}
// prompt replacer (prompt does not work in Electron)
void (function () {
const prompt = document.getElementById("prompt");
const form = prompt.querySelector("#promptForm");
window.prompt = function (promptText = "Please provide an input", options = {default: 1, step: 0.01, min: 0, max: 100}, callback) {
if (options.default === undefined) {
ERROR && console.error("Prompt: options object does not have default value defined");
return;
}
const input = prompt.querySelector("#promptInput");
prompt.querySelector("#promptText").innerHTML = promptText;
const type = typeof options.default === "number" ? "number" : "text";
input.type = type;
if (options.step !== undefined) input.step = options.step;
if (options.min !== undefined) input.min = options.min;
if (options.max !== undefined) input.max = options.max;
input.placeholder = "type a " + type;
input.value = options.default;
prompt.style.display = "block";
form.addEventListener(
"submit",
event => {
prompt.style.display = "none";
const v = type === "number" ? +input.value : input.value;
event.preventDefault();
if (callback) callback(v);
},
{once: true}
);
};
const cancel = prompt.querySelector("#promptCancel");
cancel.addEventListener("click", () => (prompt.style.display = "none"));
})();
// indexedDB; ldb object
void (function () {
function e(t, o) {
return n
? void (n.transaction("s").objectStore("s").get(t).onsuccess = function (e) {
var t = (e.target.result && e.target.result.v) || null;
o(t);
})
: void setTimeout(function () {
e(t, o);
}, 100);
}
var t = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
if (!t) return void ERROR && console.error("indexedDB not supported");
var n,
o = {k: "", v: ""},
r = t.open("d2", 1);
(r.onsuccess = function (e) {
n = this.result;
}),
(r.onerror = function (e) {
ERROR && console.error("indexedDB request error"), INFO && console.log(e);
}),
(r.onupgradeneeded = function (e) {
n = null;
var t = e.target.result.createObjectStore("s", {keyPath: "k"});
t.transaction.oncomplete = function (e) {
n = e.target.db;
};
}),
(window.ldb = {
get: e,
set: function (e, t) {
(o.k = e), (o.v = t), n.transaction("s", "readwrite").objectStore("s").put(o);
}
});
})();

276
utils/graphUtils.js Normal file
View file

@ -0,0 +1,276 @@
"use strict";
// FMG utils related to graph
// add boundary points to pseudo-clip voronoi cells
function getBoundaryPoints(width, height, spacing) {
const offset = rn(-1 * spacing);
const bSpacing = spacing * 2;
const w = width - offset * 2;
const h = height - offset * 2;
const numberX = Math.ceil(w / bSpacing) - 1;
const numberY = Math.ceil(h / bSpacing) - 1;
let points = [];
for (let i = 0.5; i < numberX; i++) {
let x = Math.ceil((w * i) / numberX + offset);
points.push([x, offset], [x, h + offset]);
}
for (let i = 0.5; i < numberY; i++) {
let y = Math.ceil((h * i) / numberY + offset);
points.push([offset, y], [w + offset, y]);
}
return points;
}
// get points on a regular square grid and jitter them a bit
function getJitteredGrid(width, height, spacing) {
const radius = spacing / 2; // square radius
const jittering = radius * 0.9; // max deviation
const doubleJittering = jittering * 2;
const jitter = () => Math.random() * doubleJittering - jittering;
let points = [];
for (let y = radius; y < height; y += spacing) {
for (let x = radius; x < width; x += spacing) {
const xj = Math.min(rn(x + jitter(), 2), width);
const yj = Math.min(rn(y + jitter(), 2), height);
points.push([xj, yj]);
}
}
return points;
}
// return cell index on a regular square grid
function findGridCell(x, y) {
return Math.floor(Math.min(y / grid.spacing, grid.cellsY - 1)) * grid.cellsX + Math.floor(Math.min(x / grid.spacing, grid.cellsX - 1));
}
// return array of cell indexes in radius on a regular square grid
function findGridAll(x, y, radius) {
const c = grid.cells.c;
let r = Math.floor(radius / grid.spacing);
let found = [findGridCell(x, y)];
if (!r || radius === 1) return found;
if (r > 0) found = found.concat(c[found[0]]);
if (r > 1) {
let frontier = c[found[0]];
while (r > 1) {
let cycle = frontier.slice();
frontier = [];
cycle.forEach(function (s) {
c[s].forEach(function (e) {
if (found.indexOf(e) !== -1) return;
found.push(e);
frontier.push(e);
});
});
r--;
}
}
return found;
}
// return closest pack points quadtree datum
function find(x, y, radius = Infinity) {
return pack.cells.q.find(x, y, radius);
}
// return closest cell index
function findCell(x, y, radius = Infinity) {
const found = pack.cells.q.find(x, y, radius);
return found ? found[2] : undefined;
}
// return array of cell indexes in radius
function findAll(x, y, radius) {
const found = pack.cells.q.findAll(x, y, radius);
return found.map(r => r[2]);
}
// get polygon points for packed cells knowing cell id
function getPackPolygon(i) {
return pack.cells.v[i].map(v => pack.vertices.p[v]);
}
// get polygon points for initial cells knowing cell id
function getGridPolygon(i) {
return grid.cells.v[i].map(v => grid.vertices.p[v]);
}
// mbostock's poissonDiscSampler
function* poissonDiscSampler(x0, y0, x1, y1, r, k = 3) {
if (!(x1 >= x0) || !(y1 >= y0) || !(r > 0)) throw new Error();
const width = x1 - x0;
const height = y1 - y0;
const r2 = r * r;
const r2_3 = 3 * r2;
const cellSize = r * Math.SQRT1_2;
const gridWidth = Math.ceil(width / cellSize);
const gridHeight = Math.ceil(height / cellSize);
const grid = new Array(gridWidth * gridHeight);
const queue = [];
function far(x, y) {
const i = (x / cellSize) | 0;
const j = (y / cellSize) | 0;
const i0 = Math.max(i - 2, 0);
const j0 = Math.max(j - 2, 0);
const i1 = Math.min(i + 3, gridWidth);
const j1 = Math.min(j + 3, gridHeight);
for (let j = j0; j < j1; ++j) {
const o = j * gridWidth;
for (let i = i0; i < i1; ++i) {
const s = grid[o + i];
if (s) {
const dx = s[0] - x;
const dy = s[1] - y;
if (dx * dx + dy * dy < r2) return false;
}
}
}
return true;
}
function sample(x, y) {
queue.push((grid[gridWidth * ((y / cellSize) | 0) + ((x / cellSize) | 0)] = [x, y]));
return [x + x0, y + y0];
}
yield sample(width / 2, height / 2);
pick: while (queue.length) {
const i = (Math.random() * queue.length) | 0;
const parent = queue[i];
for (let j = 0; j < k; ++j) {
const a = 2 * Math.PI * Math.random();
const r = Math.sqrt(Math.random() * r2_3 + r2);
const x = parent[0] + r * Math.cos(a);
const y = parent[1] + r * Math.sin(a);
if (0 <= x && x < width && 0 <= y && y < height && far(x, y)) {
yield sample(x, y);
continue pick;
}
}
const r = queue.pop();
if (i < queue.length) queue[i] = r;
}
}
// filter land cells
function isLand(i) {
return pack.cells.h[i] >= 20;
}
// filter water cells
function isWater(i) {
return pack.cells.h[i] < 20;
}
// findAll d3.quandtree search from https://bl.ocks.org/lwthatcher/b41479725e0ff2277c7ac90df2de2b5e
void (function addFindAll() {
const Quad = function (node, x0, y0, x1, y1) {
this.node = node;
this.x0 = x0;
this.y0 = y0;
this.x1 = x1;
this.y1 = y1;
};
const tree_filter = function (x, y, radius) {
var t = {x, y, x0: this._x0, y0: this._y0, x3: this._x1, y3: this._y1, quads: [], node: this._root};
if (t.node) {
t.quads.push(new Quad(t.node, t.x0, t.y0, t.x3, t.y3));
}
radiusSearchInit(t, radius);
var i = 0;
while ((t.q = t.quads.pop())) {
i++;
// Stop searching if this quadrant cant contain a closer node.
if (!(t.node = t.q.node) || (t.x1 = t.q.x0) > t.x3 || (t.y1 = t.q.y0) > t.y3 || (t.x2 = t.q.x1) < t.x0 || (t.y2 = t.q.y1) < t.y0) continue;
// Bisect the current quadrant.
if (t.node.length) {
t.node.explored = true;
var xm = (t.x1 + t.x2) / 2,
ym = (t.y1 + t.y2) / 2;
t.quads.push(
new Quad(t.node[3], xm, ym, t.x2, t.y2),
new Quad(t.node[2], t.x1, ym, xm, t.y2),
new Quad(t.node[1], xm, t.y1, t.x2, ym),
new Quad(t.node[0], t.x1, t.y1, xm, ym)
);
// Visit the closest quadrant first.
if ((t.i = ((y >= ym) << 1) | (x >= xm))) {
t.q = t.quads[t.quads.length - 1];
t.quads[t.quads.length - 1] = t.quads[t.quads.length - 1 - t.i];
t.quads[t.quads.length - 1 - t.i] = t.q;
}
}
// Visit this point. (Visiting coincident points isnt necessary!)
else {
var dx = x - +this._x.call(null, t.node.data),
dy = y - +this._y.call(null, t.node.data),
d2 = dx * dx + dy * dy;
radiusSearchVisit(t, d2);
}
}
return t.result;
};
d3.quadtree.prototype.findAll = tree_filter;
var radiusSearchInit = function (t, radius) {
t.result = [];
(t.x0 = t.x - radius), (t.y0 = t.y - radius);
(t.x3 = t.x + radius), (t.y3 = t.y + radius);
t.radius = radius * radius;
};
var radiusSearchVisit = function (t, d2) {
t.node.data.scanned = true;
if (d2 < t.radius) {
do {
t.result.push(t.node.data);
t.node.data.selected = true;
} while ((t.node = t.node.next));
}
};
})();
// helper function non-used for the generation
function drawCellsValue(data) {
debug.selectAll("text").remove();
debug
.selectAll("text")
.data(data)
.enter()
.append("text")
.attr("x", (d, i) => pack.cells.p[i][0])
.attr("y", (d, i) => pack.cells.p[i][1])
.text(d => d);
}
// helper function non-used for the generation
function drawPolygons(data) {
const max = d3.max(data),
min = d3.min(data),
scheme = getColorScheme();
data = data.map(d => 1 - normalize(d, min, max));
debug.selectAll("polygon").remove();
debug
.selectAll("polygon")
.data(data)
.enter()
.append("polygon")
.attr("points", (d, i) => getPackPolygon(i))
.attr("fill", d => scheme(d))
.attr("stroke", d => scheme(d));
}

30
utils/nodeUtils.js Normal file
View file

@ -0,0 +1,30 @@
"use strict";
// FMG utils related to nodes
// remove parent element (usually if child is clicked)
function removeParent() {
this.parentNode.parentNode.removeChild(this.parentNode);
}
// polyfill for composedPath
function getComposedPath(node) {
let parent;
if (node.parentNode) parent = node.parentNode;
else if (node.host) parent = node.host;
else if (node.defaultView) parent = node.defaultView;
if (parent !== undefined) return [node].concat(getComposedPath(parent));
return [node];
}
// get next unused id
function getNextId(core, i = 1) {
while (document.getElementById(core + i)) i++;
return core + i;
}
function getAbsolutePath(href) {
if (!href) return "";
const link = document.createElement("a");
link.href = href;
return link.href;
}

22
utils/numberUtils.js Normal file
View file

@ -0,0 +1,22 @@
"use strict";
// FMG utils related to numbers
// round value to d decimals
function rn(v, d = 0) {
const m = Math.pow(10, d);
return Math.round(v * m) / m;
}
function minmax(value, min, max) {
return Math.min(Math.max(value, min), max);
}
// return value in range [0, 100]
function lim(v) {
return minmax(v, 0, 100);
}
// normalization function
function normalize(val, min, max) {
return minmax((val - min) / (max - min), 0, 1);
}

16
utils/polyfills.js Normal file
View file

@ -0,0 +1,16 @@
"use strict";
// replaceAll
if (String.prototype.replaceAll === undefined) {
String.prototype.replaceAll = function (str, newStr) {
if (Object.prototype.toString.call(str).toLowerCase() === "[object regexp]") return this.replace(str, newStr);
return this.replace(new RegExp(str, "g"), newStr);
};
}
// flat
if (Array.prototype.flat === undefined) {
Array.prototype.flat = function () {
return this.reduce((acc, val) => (Array.isArray(val) ? acc.concat(val.flat()) : acc.concat(val)), []);
};
}

76
utils/probabilityUtils.js Normal file
View file

@ -0,0 +1,76 @@
"use strict";
// FMG utils related to randomness
// random number in a range
function rand(min, max) {
if (min === undefined && max === undefined) return Math.random();
if (max === undefined) {
max = min;
min = 0;
}
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// probability shorthand
function P(probability) {
if (probability >= 1) return true;
if (probability <= 0) return false;
return Math.random() < probability;
}
function each(n) {
return i => i % n === 0;
}
// random number (normal or gaussian distribution)
function gauss(expected = 100, deviation = 30, min = 0, max = 300, round = 0) {
return rn(minmax(d3.randomNormal(expected, deviation)(), min, max), round);
}
// probability shorthand for floats
function Pint(float) {
return ~~float + +P(float % 1);
}
// return random value from the array
function ra(array) {
return array[Math.floor(Math.random() * array.length)];
}
// return random value from weighted array {"key1":weight1, "key2":weight2}
function rw(object) {
const array = [];
for (const key in object) {
for (let i = 0; i < object[key]; i++) {
array.push(key);
}
}
return array[Math.floor(Math.random() * array.length)];
}
// return a random integer from min to max biased towards one end based on exponent distribution (the bigger ex the higher bias towards min)
function biased(min, max, ex) {
return Math.round(min + (max - min) * Math.pow(Math.random(), ex));
}
// get number from string in format "1-3" or "2" or "0.5"
function getNumberInRange(r) {
if (typeof r !== "string") {
ERROR && console.error("The value should be a string", r);
return 0;
}
if (!isNaN(+r)) return ~~r + +P(r - ~~r);
const sign = r[0] === "-" ? -1 : 1;
if (isNaN(+r[0])) r = r.slice(1);
const range = r.includes("-") ? r.split("-") : null;
if (!range) {
ERROR && console.error("Cannot parse the number. Check the format", r);
return 0;
}
const count = rand(range[0] * sign, +range[1]);
if (isNaN(count) || count < 0) {
ERROR && console.error("Cannot parse number. Check the format", r);
return 0;
}
return count;
}

116
utils/stringUtils.js Normal file
View file

@ -0,0 +1,116 @@
"use strict";
// FMG utils related to strings
// round numbers in string to d decimals
function round(s, d = 1) {
return s.replace(/[\d\.-][\d\.e-]*/g, function (n) {
return rn(n, d);
});
}
// return string with 1st char capitalized
function capitalize(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
// check if char is vowel or can serve as vowel
function vowel(c) {
return `aeiouyɑ'əøɛœæɶɒɨɪɔɐʊɤɯаоиеёэыуюяàèìòùỳẁȁȅȉȍȕáéíóúýẃőűâêîôûŷŵäëïöüÿẅãẽĩõũỹąęįǫųāēīōūȳăĕĭŏŭǎěǐǒǔȧėȯẏẇạẹịọụỵẉḛḭṵṳ`.includes(c);
}
// remove vowels from the end of the string
function trimVowels(string) {
while (string.length > 3 && vowel(last(string))) {
string = string.slice(0, -1);
}
return string;
}
// get adjective form from noun
function getAdjective(string) {
// special cases for some suffixes
if (string.length > 8 && string.slice(-6) === "orszag") return string.slice(0, -6);
if (string.length > 6 && string.slice(-4) === "stan") return string.slice(0, -4);
if (P(0.5) && string.slice(-4) === "land") return string + "ic";
if (string.slice(-4) === " Guo") string = string.slice(0, -4);
// don't change is name ends on suffix
if (string.slice(-2) === "an") return string;
if (string.slice(-3) === "ese") return string;
if (string.slice(-1) === "i") return string;
const end = string.slice(-1); // last letter of string
if (end === "a") return (string += "n");
if (end === "o") return (string = trimVowels(string) + "an");
if (vowel(end) || end === "c") return (string += "an"); // ceiuy
if (end === "m" || end === "n") return (string += "ese");
if (end === "q") return (string += "i");
return trimVowels(string) + "ian";
}
// get ordinal out of integer: 1 => 1st
const nth = n => n + (["st", "nd", "rd"][((((n + 90) % 100) - 10) % 10) - 1] || "th");
// get two-letters code (abbreviation) from string
function abbreviate(name, restricted = []) {
const parsed = name.replace("Old ", "O ").replace(/[()]/g, ""); // remove Old prefix and parentheses
const words = parsed.split(" ");
const letters = words.join("");
let code = words.length === 2 ? words[0][0] + words[1][0] : letters.slice(0, 2);
for (let i = 1; i < letters.length - 1 && restricted.includes(code); i++) {
code = letters[0] + letters[i].toUpperCase();
}
return code;
}
// conjunct array: [A,B,C] => "A, B and C"
function list(array) {
if (!Intl.ListFormat) return array.join(", ");
const conjunction = new Intl.ListFormat(window.lang || "en", {style: "long", type: "conjunction"});
return conjunction.format(array);
}
// split string into 2 almost equal parts not breaking words
function splitInTwo(str) {
const half = str.length / 2;
const ar = str.split(" ");
if (ar.length < 2) return ar; // only one word
let first = "",
last = "",
middle = "",
rest = "";
ar.forEach((w, d) => {
if (d + 1 !== ar.length) w += " ";
rest += w;
if (!first || rest.length < half) first += w;
else if (!middle) middle = w;
else last += w;
});
if (!last) return [first, middle];
if (first.length < last.length) return [first + middle, last];
return [first, middle + last];
}
// transform string to array [translateX,translateY,rotateDeg,rotateX,rotateY,scale]
function parseTransform(string) {
if (!string) return [0, 0, 0, 0, 0, 1];
const a = string
.replace(/[a-z()]/g, "")
.replace(/[ ]/g, ",")
.split(",");
return [a[0] || 0, a[1] || 0, a[2] || 0, a[3] || 0, a[4] || 0, a[5] || 1];
}
// check if string is a valid for JSON parse
JSON.isValid = str => {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
};

45
utils/unitUtils.js Normal file
View file

@ -0,0 +1,45 @@
"use strict";
// FMG utils related to units
// conver temperature from °C to other scales
function convertTemperature(temp) {
switch (temperatureScale.value) {
case "°C":
return temp + "°C";
case "°F":
return rn((temp * 9) / 5 + 32) + "°F";
case "K":
return rn(temp + 273.15) + "K";
case "°R":
return rn(((temp + 273.15) * 9) / 5) + "°R";
case "°De":
return rn(((100 - temp) * 3) / 2) + "°De";
case "°N":
return rn((temp * 33) / 100) + "°N";
case "°Ré":
return rn((temp * 4) / 5) + "°Ré";
case "°Rø":
return rn((temp * 21) / 40 + 7.5) + "°Rø";
default:
return temp + "°C";
}
}
// corvent number to short string with SI postfix
function si(n) {
if (n >= 1e9) return rn(n / 1e9, 1) + "B";
if (n >= 1e8) return rn(n / 1e6) + "M";
if (n >= 1e6) return rn(n / 1e6, 1) + "M";
if (n >= 1e4) return rn(n / 1e3) + "K";
if (n >= 1e3) return rn(n / 1e3, 1) + "K";
return rn(n);
}
// getInteger number from user input data
function getInteger(value) {
const metric = value.slice(-1);
if (metric === "K") return parseInt(value.slice(0, -1) * 1e3);
if (metric === "M") return parseInt(value.slice(0, -1) * 1e6);
if (metric === "B") return parseInt(value.slice(0, -1) * 1e9);
return parseInt(value);
}