this repo has no description
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

♻️ Construct our own SVG trees (#61)

authored by

Gwenn Le Bihan and committed by
GitHub
edbe6fbd 06bf9780

+783 -616
+1 -7
Cargo.lock
··· 4573 4573 "ndarray", 4574 4574 "nih_plug", 4575 4575 "once_cell", 4576 + "quick-xml", 4576 4577 "rand 0.9.2", 4577 4578 "rayon", 4578 4579 "resvg", ··· 4584 4585 "slug", 4585 4586 "strum", 4586 4587 "strum_macros", 4587 - "svg", 4588 4588 "tiny-skia", 4589 4589 "tokio", 4590 4590 "toml 0.9.8", ··· 4812 4812 version = "3.0.0" 4813 4813 source = "registry+https://github.com/rust-lang/crates.io-index" 4814 4814 checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2" 4815 - 4816 - [[package]] 4817 - name = "svg" 4818 - version = "0.18.0" 4819 - source = "registry+https://github.com/rust-lang/crates.io-index" 4820 - checksum = "94afda9cd163c04f6bee8b4bf2501c91548deae308373c436f36aeff3cf3c4a3" 4821 4815 4822 4816 [[package]] 4823 4817 name = "svgtypes"
+1 -1
Cargo.toml
··· 68 68 ] } 69 69 serde_cbor = "0.11.2" 70 70 serde_json = "1.0.145" 71 - svg = "0.18.0" 72 71 wasm-bindgen = { version = "0.2.104", optional = true } 73 72 getrandom = { version = "0.2", features = ["js"] } 74 73 web-sys = { version = "0.3.81", optional = true, features = [ ··· 107 106 url = "2.5.7" 108 107 tungstenite = { version = "0.28.0", optional = true } 109 108 axum = { version = "0.8.6", optional = true, features = ["json"] } 109 + quick-xml = "0.38.3" 110 110 111 111 112 112 [dev-dependencies]
+193 -320
examples/dna-analysis-machine/src/snapshots/dna_analysis_machine__artwork.snap
··· 5 5 <svg height="470" viewBox="-10 -10 820 470" width="820" xmlns="http://www.w3.org/2000/svg"> 6 6 <rect fill="#000000" height="470" width="820" x="-10" y="-10"/> 7 7 <g class="layer" data-layer="hatches"> 8 - <rect data-object="hatches--anon-0" height="50" style="fill: url(#pattern-hatched-45deg-white-0.5-0.25);" width="50" x="50" y="50"/> 9 - <rect data-object="hatches--anon-1" height="50" style="fill: url(#pattern-hatched-45deg-white-0.6-0.25);" width="50" x="100" y="50"/> 8 + <rect data-object="hatches--anon-0" height="50" width="50" x="50" y="50" style="fill: url(#pattern-hatched-45deg-white-0.5-0.25);"/> 9 + <rect data-object="hatches--anon-1" height="50" width="50" x="100" y="50" style="fill: url(#pattern-hatched-45deg-white-0.6-0.25);"/> 10 10 <circle cx="575" cy="75" data-object="hatches--anon-10" r="25" style="fill: url(#pattern-hatched-45deg-white-1.5-0.25);"/> 11 11 <circle cx="625" cy="75" data-object="hatches--anon-11" r="25" style="fill: url(#pattern-hatched-45deg-white-1.6-0.25);"/> 12 - <rect data-object="hatches--anon-12" height="50" style="fill: url(#pattern-hatched-45deg-white-1.7-0.25);" width="50" x="650" y="50"/> 13 - <rect data-object="hatches--anon-13" height="50" style="fill: url(#pattern-hatched-45deg-white-1.8-0.25);" width="50" x="700" y="50"/> 14 - <rect data-object="hatches--anon-14" height="50" style="fill: url(#pattern-hatched-45deg-white-1.9-0.25);" width="50" x="50" y="100"/> 15 - <rect data-object="hatches--anon-15" height="50" style="fill: url(#pattern-hatched-45deg-white-2-0.25);" width="50" x="100" y="100"/> 16 - <rect data-object="hatches--anon-16" height="50" style="fill: url(#pattern-hatched-45deg-white-2.1-0.25);" width="50" x="150" y="100"/> 17 - <rect data-object="hatches--anon-17" height="50" style="fill: url(#pattern-hatched-45deg-white-2.2-0.25);" width="50" x="200" y="100"/> 18 - <rect data-object="hatches--anon-18" height="50" style="fill: url(#pattern-hatched-45deg-white-2.3-0.25);" width="50" x="250" y="100"/> 12 + <rect data-object="hatches--anon-12" height="50" width="50" x="650" y="50" style="fill: url(#pattern-hatched-45deg-white-1.7-0.25);"/> 13 + <rect data-object="hatches--anon-13" height="50" width="50" x="700" y="50" style="fill: url(#pattern-hatched-45deg-white-1.8-0.25);"/> 14 + <rect data-object="hatches--anon-14" height="50" width="50" x="50" y="100" style="fill: url(#pattern-hatched-45deg-white-1.9-0.25);"/> 15 + <rect data-object="hatches--anon-15" height="50" width="50" x="100" y="100" style="fill: url(#pattern-hatched-45deg-white-2-0.25);"/> 16 + <rect data-object="hatches--anon-16" height="50" width="50" x="150" y="100" style="fill: url(#pattern-hatched-45deg-white-2.1-0.25);"/> 17 + <rect data-object="hatches--anon-17" height="50" width="50" x="200" y="100" style="fill: url(#pattern-hatched-45deg-white-2.2-0.25);"/> 18 + <rect data-object="hatches--anon-18" height="50" width="50" x="250" y="100" style="fill: url(#pattern-hatched-45deg-white-2.3-0.25);"/> 19 19 <circle cx="325" cy="125" data-object="hatches--anon-19" r="25" style="fill: url(#pattern-hatched-45deg-white-2.4-0.25);"/> 20 20 <circle cx="175" cy="75" data-object="hatches--anon-2" r="25" style="fill: url(#pattern-hatched-45deg-white-0.7-0.25);"/> 21 - <rect data-object="hatches--anon-20" height="50" style="fill: url(#pattern-hatched-45deg-white-2.5-0.25);" width="50" x="350" y="100"/> 21 + <rect data-object="hatches--anon-20" height="50" width="50" x="350" y="100" style="fill: url(#pattern-hatched-45deg-white-2.5-0.25);"/> 22 22 <circle cx="425" cy="125" data-object="hatches--anon-21" r="25" style="fill: url(#pattern-hatched-45deg-white-2.6-0.25);"/> 23 - <rect data-object="hatches--anon-22" height="50" style="fill: url(#pattern-hatched-45deg-white-2.7-0.25);" width="50" x="450" y="100"/> 24 - <rect data-object="hatches--anon-23" height="50" style="fill: url(#pattern-hatched-45deg-white-2.8-0.25);" width="50" x="500" y="100"/> 23 + <rect data-object="hatches--anon-22" height="50" width="50" x="450" y="100" style="fill: url(#pattern-hatched-45deg-white-2.7-0.25);"/> 24 + <rect data-object="hatches--anon-23" height="50" width="50" x="500" y="100" style="fill: url(#pattern-hatched-45deg-white-2.8-0.25);"/> 25 25 <circle cx="575" cy="125" data-object="hatches--anon-24" r="25" style="fill: url(#pattern-hatched-45deg-white-2.9-0.25);"/> 26 - <rect data-object="hatches--anon-25" height="50" style="fill: url(#pattern-hatched-45deg-white-3-0.25);" width="50" x="600" y="100"/> 27 - <rect data-object="hatches--anon-26" height="50" style="fill: url(#pattern-hatched-45deg-white-3.1-0.25);" width="50" x="650" y="100"/> 28 - <rect data-object="hatches--anon-27" height="50" style="fill: url(#pattern-hatched-45deg-white-3.2-0.25);" width="50" x="700" y="100"/> 26 + <rect data-object="hatches--anon-25" height="50" width="50" x="600" y="100" style="fill: url(#pattern-hatched-45deg-white-3-0.25);"/> 27 + <rect data-object="hatches--anon-26" height="50" width="50" x="650" y="100" style="fill: url(#pattern-hatched-45deg-white-3.1-0.25);"/> 28 + <rect data-object="hatches--anon-27" height="50" width="50" x="700" y="100" style="fill: url(#pattern-hatched-45deg-white-3.2-0.25);"/> 29 29 <circle cx="75" cy="175" data-object="hatches--anon-28" r="25" style="fill: url(#pattern-hatched-45deg-white-3.3-0.25);"/> 30 30 <circle cx="125" cy="175" data-object="hatches--anon-29" r="25" style="fill: url(#pattern-hatched-45deg-white-3.4-0.25);"/> 31 31 <circle cx="225" cy="75" data-object="hatches--anon-3" r="25" style="fill: url(#pattern-hatched-45deg-white-0.8-0.25);"/> 32 - <rect data-object="hatches--anon-30" height="50" style="fill: url(#pattern-hatched-45deg-white-3.5-0.25);" width="50" x="150" y="150"/> 33 - <rect data-object="hatches--anon-31" height="50" style="fill: url(#pattern-hatched-45deg-white-3.6-0.25);" width="50" x="200" y="150"/> 32 + <rect data-object="hatches--anon-30" height="50" width="50" x="150" y="150" style="fill: url(#pattern-hatched-45deg-white-3.5-0.25);"/> 33 + <rect data-object="hatches--anon-31" height="50" width="50" x="200" y="150" style="fill: url(#pattern-hatched-45deg-white-3.6-0.25);"/> 34 34 <circle cx="275" cy="175" data-object="hatches--anon-32" r="25" style="fill: url(#pattern-hatched-45deg-white-3.7-0.25);"/> 35 - <rect data-object="hatches--anon-33" height="50" style="fill: url(#pattern-hatched-45deg-white-3.8-0.25);" width="50" x="300" y="150"/> 36 - <rect data-object="hatches--anon-34" height="50" style="fill: url(#pattern-hatched-45deg-white-3.9-0.25);" width="50" x="350" y="150"/> 37 - <rect data-object="hatches--anon-35" height="50" style="fill: url(#pattern-hatched-45deg-white-4-0.25);" width="50" x="400" y="150"/> 35 + <rect data-object="hatches--anon-33" height="50" width="50" x="300" y="150" style="fill: url(#pattern-hatched-45deg-white-3.8-0.25);"/> 36 + <rect data-object="hatches--anon-34" height="50" width="50" x="350" y="150" style="fill: url(#pattern-hatched-45deg-white-3.9-0.25);"/> 37 + <rect data-object="hatches--anon-35" height="50" width="50" x="400" y="150" style="fill: url(#pattern-hatched-45deg-white-4-0.25);"/> 38 38 <circle cx="475" cy="175" data-object="hatches--anon-36" r="25" style="fill: url(#pattern-hatched-45deg-white-4.1-0.25);"/> 39 39 <circle cx="525" cy="175" data-object="hatches--anon-37" r="25" style="fill: url(#pattern-hatched-45deg-white-4.2-0.25);"/> 40 40 <circle cx="575" cy="175" data-object="hatches--anon-38" r="25" style="fill: url(#pattern-hatched-45deg-white-4.3-0.25);"/> 41 - <rect data-object="hatches--anon-39" height="50" style="fill: url(#pattern-hatched-45deg-white-4.4-0.25);" width="50" x="600" y="150"/> 41 + <rect data-object="hatches--anon-39" height="50" width="50" x="600" y="150" style="fill: url(#pattern-hatched-45deg-white-4.4-0.25);"/> 42 42 <circle cx="275" cy="75" data-object="hatches--anon-4" r="25" style="fill: url(#pattern-hatched-45deg-white-0.9-0.25);"/> 43 43 <circle cx="675" cy="175" data-object="hatches--anon-40" r="25" style="fill: url(#pattern-hatched-45deg-white-4.5-0.25);"/> 44 - <rect data-object="hatches--anon-41" height="50" style="fill: url(#pattern-hatched-45deg-white-4.6-0.25);" width="50" x="700" y="150"/> 44 + <rect data-object="hatches--anon-41" height="50" width="50" x="700" y="150" style="fill: url(#pattern-hatched-45deg-white-4.6-0.25);"/> 45 45 <circle cx="75" cy="225" data-object="hatches--anon-42" r="25" style="fill: url(#pattern-hatched-45deg-white-4.7-0.25);"/> 46 46 <circle cx="125" cy="225" data-object="hatches--anon-43" r="25" style="fill: url(#pattern-hatched-45deg-white-4.8-0.25);"/> 47 47 <circle cx="325" cy="225" data-object="hatches--anon-44" r="25" style="fill: url(#pattern-hatched-45deg-white-4.9-0.25);"/> 48 - <rect data-object="hatches--anon-45" height="50" style="fill: url(#pattern-hatched-45deg-white-5-0.25);" width="50" x="350" y="200"/> 49 - <rect data-object="hatches--anon-46" height="50" style="fill: url(#pattern-hatched-45deg-white-5.1-0.25);" width="50" x="400" y="200"/> 50 - <rect data-object="hatches--anon-47" height="50" style="fill: url(#pattern-hatched-45deg-white-5.2-0.25);" width="50" x="450" y="200"/> 51 - <rect data-object="hatches--anon-48" height="50" style="fill: url(#pattern-hatched-45deg-white-5.3-0.25);" width="50" x="500" y="200"/> 52 - <rect data-object="hatches--anon-49" height="50" style="fill: url(#pattern-hatched-45deg-white-5.5-0.25);" width="50" x="600" y="200"/> 48 + <rect data-object="hatches--anon-45" height="50" width="50" x="350" y="200" style="fill: url(#pattern-hatched-45deg-white-5-0.25);"/> 49 + <rect data-object="hatches--anon-46" height="50" width="50" x="400" y="200" style="fill: url(#pattern-hatched-45deg-white-5.1-0.25);"/> 50 + <rect data-object="hatches--anon-47" height="50" width="50" x="450" y="200" style="fill: url(#pattern-hatched-45deg-white-5.2-0.25);"/> 51 + <rect data-object="hatches--anon-48" height="50" width="50" x="500" y="200" style="fill: url(#pattern-hatched-45deg-white-5.3-0.25);"/> 52 + <rect data-object="hatches--anon-49" height="50" width="50" x="600" y="200" style="fill: url(#pattern-hatched-45deg-white-5.5-0.25);"/> 53 53 <circle cx="325" cy="75" data-object="hatches--anon-5" r="25" style="fill: url(#pattern-hatched-45deg-white-1-0.25);"/> 54 - <rect data-object="hatches--anon-50" height="50" style="fill: url(#pattern-hatched-45deg-white-5.6-0.25);" width="50" x="650" y="200"/> 54 + <rect data-object="hatches--anon-50" height="50" width="50" x="650" y="200" style="fill: url(#pattern-hatched-45deg-white-5.6-0.25);"/> 55 55 <circle cx="725" cy="225" data-object="hatches--anon-51" r="25" style="fill: url(#pattern-hatched-45deg-white-5.7-0.25);"/> 56 56 <circle cx="75" cy="275" data-object="hatches--anon-52" r="25" style="fill: url(#pattern-hatched-45deg-white-5.8-0.25);"/> 57 - <rect data-object="hatches--anon-53" height="50" style="fill: url(#pattern-hatched-45deg-white-5.9-0.25);" width="50" x="100" y="250"/> 58 - <rect data-object="hatches--anon-54" height="50" style="fill: url(#pattern-hatched-45deg-white-6-0.25);" width="50" x="300" y="250"/> 59 - <rect data-object="hatches--anon-55" height="50" style="fill: url(#pattern-hatched-45deg-white-6.1-0.25);" width="50" x="350" y="250"/> 60 - <rect data-object="hatches--anon-56" height="50" style="fill: url(#pattern-hatched-45deg-white-6.2-0.25);" width="50" x="400" y="250"/> 57 + <rect data-object="hatches--anon-53" height="50" width="50" x="100" y="250" style="fill: url(#pattern-hatched-45deg-white-5.9-0.25);"/> 58 + <rect data-object="hatches--anon-54" height="50" width="50" x="300" y="250" style="fill: url(#pattern-hatched-45deg-white-6-0.25);"/> 59 + <rect data-object="hatches--anon-55" height="50" width="50" x="350" y="250" style="fill: url(#pattern-hatched-45deg-white-6.1-0.25);"/> 60 + <rect data-object="hatches--anon-56" height="50" width="50" x="400" y="250" style="fill: url(#pattern-hatched-45deg-white-6.2-0.25);"/> 61 61 <circle cx="475" cy="275" data-object="hatches--anon-57" r="25" style="fill: url(#pattern-hatched-45deg-white-6.3-0.25);"/> 62 62 <circle cx="525" cy="275" data-object="hatches--anon-58" r="25" style="fill: url(#pattern-hatched-45deg-white-6.4-0.25);"/> 63 63 <circle cx="575" cy="275" data-object="hatches--anon-59" r="25" style="fill: url(#pattern-hatched-45deg-white-6.5-0.25);"/> 64 64 <circle cx="375" cy="75" data-object="hatches--anon-6" r="25" style="fill: url(#pattern-hatched-45deg-white-1.1-0.25);"/> 65 - <rect data-object="hatches--anon-60" height="50" style="fill: url(#pattern-hatched-45deg-white-6.6-0.25);" width="50" x="600" y="250"/> 66 - <rect data-object="hatches--anon-61" height="50" style="fill: url(#pattern-hatched-45deg-white-6.7-0.25);" width="50" x="650" y="250"/> 67 - <rect data-object="hatches--anon-62" height="50" style="fill: url(#pattern-hatched-45deg-white-6.8-0.25);" width="50" x="700" y="250"/> 65 + <rect data-object="hatches--anon-60" height="50" width="50" x="600" y="250" style="fill: url(#pattern-hatched-45deg-white-6.6-0.25);"/> 66 + <rect data-object="hatches--anon-61" height="50" width="50" x="650" y="250" style="fill: url(#pattern-hatched-45deg-white-6.7-0.25);"/> 67 + <rect data-object="hatches--anon-62" height="50" width="50" x="700" y="250" style="fill: url(#pattern-hatched-45deg-white-6.8-0.25);"/> 68 68 <circle cx="75" cy="325" data-object="hatches--anon-63" r="25" style="fill: url(#pattern-hatched-45deg-white-6.9-0.25);"/> 69 - <rect data-object="hatches--anon-64" height="50" style="fill: url(#pattern-hatched-45deg-white-7-0.25);" width="50" x="100" y="300"/> 70 - <rect data-object="hatches--anon-65" height="50" style="fill: url(#pattern-hatched-45deg-white-7.1-0.25);" width="50" x="300" y="300"/> 71 - <rect data-object="hatches--anon-66" height="50" style="fill: url(#pattern-hatched-45deg-white-7.2-0.25);" width="50" x="350" y="300"/> 72 - <rect data-object="hatches--anon-67" height="50" style="fill: url(#pattern-hatched-45deg-white-7.3-0.25);" width="50" x="400" y="300"/> 69 + <rect data-object="hatches--anon-64" height="50" width="50" x="100" y="300" style="fill: url(#pattern-hatched-45deg-white-7-0.25);"/> 70 + <rect data-object="hatches--anon-65" height="50" width="50" x="300" y="300" style="fill: url(#pattern-hatched-45deg-white-7.1-0.25);"/> 71 + <rect data-object="hatches--anon-66" height="50" width="50" x="350" y="300" style="fill: url(#pattern-hatched-45deg-white-7.2-0.25);"/> 72 + <rect data-object="hatches--anon-67" height="50" width="50" x="400" y="300" style="fill: url(#pattern-hatched-45deg-white-7.3-0.25);"/> 73 73 <circle cx="475" cy="325" data-object="hatches--anon-68" r="25" style="fill: url(#pattern-hatched-45deg-white-7.4-0.25);"/> 74 74 <circle cx="525" cy="325" data-object="hatches--anon-69" r="25" style="fill: url(#pattern-hatched-45deg-white-7.5-0.25);"/> 75 - <rect data-object="hatches--anon-7" height="50" style="fill: url(#pattern-hatched-45deg-white-1.2-0.25);" width="50" x="400" y="50"/> 76 - <rect data-object="hatches--anon-70" height="50" style="fill: url(#pattern-hatched-45deg-white-7.6-0.25);" width="50" x="550" y="300"/> 77 - <rect data-object="hatches--anon-71" height="50" style="fill: url(#pattern-hatched-45deg-white-7.7-0.25);" width="50" x="600" y="300"/> 75 + <rect data-object="hatches--anon-7" height="50" width="50" x="400" y="50" style="fill: url(#pattern-hatched-45deg-white-1.2-0.25);"/> 76 + <rect data-object="hatches--anon-70" height="50" width="50" x="550" y="300" style="fill: url(#pattern-hatched-45deg-white-7.6-0.25);"/> 77 + <rect data-object="hatches--anon-71" height="50" width="50" x="600" y="300" style="fill: url(#pattern-hatched-45deg-white-7.7-0.25);"/> 78 78 <circle cx="675" cy="325" data-object="hatches--anon-72" r="25" style="fill: url(#pattern-hatched-45deg-white-7.8-0.25);"/> 79 79 <circle cx="725" cy="325" data-object="hatches--anon-73" r="25" style="fill: url(#pattern-hatched-45deg-white-7.9-0.25);"/> 80 - <rect data-object="hatches--anon-74" height="50" style="fill: url(#pattern-hatched-45deg-white-8-0.25);" width="50" x="50" y="350"/> 81 - <rect data-object="hatches--anon-75" height="50" style="fill: url(#pattern-hatched-45deg-white-8.1-0.25);" width="50" x="100" y="350"/> 80 + <rect data-object="hatches--anon-74" height="50" width="50" x="50" y="350" style="fill: url(#pattern-hatched-45deg-white-8-0.25);"/> 81 + <rect data-object="hatches--anon-75" height="50" width="50" x="100" y="350" style="fill: url(#pattern-hatched-45deg-white-8.1-0.25);"/> 82 82 <circle cx="175" cy="375" data-object="hatches--anon-76" r="25" style="fill: url(#pattern-hatched-45deg-white-8.2-0.25);"/> 83 83 <circle cx="225" cy="375" data-object="hatches--anon-77" r="25" style="fill: url(#pattern-hatched-45deg-white-8.3-0.25);"/> 84 84 <circle cx="275" cy="375" data-object="hatches--anon-78" r="25" style="fill: url(#pattern-hatched-45deg-white-8.4-0.25);"/> 85 - <rect data-object="hatches--anon-79" height="50" style="fill: url(#pattern-hatched-45deg-white-8.5-0.25);" width="50" x="300" y="350"/> 85 + <rect data-object="hatches--anon-79" height="50" width="50" x="300" y="350" style="fill: url(#pattern-hatched-45deg-white-8.5-0.25);"/> 86 86 <circle cx="475" cy="75" data-object="hatches--anon-8" r="25" style="fill: url(#pattern-hatched-45deg-white-1.3-0.25);"/> 87 87 <circle cx="375" cy="375" data-object="hatches--anon-80" r="25" style="fill: url(#pattern-hatched-45deg-white-8.6-0.25);"/> 88 - <rect data-object="hatches--anon-81" height="50" style="fill: url(#pattern-hatched-45deg-white-8.7-0.25);" width="50" x="400" y="350"/> 89 - <rect data-object="hatches--anon-82" height="50" style="fill: url(#pattern-hatched-45deg-white-8.8-0.25);" width="50" x="450" y="350"/> 88 + <rect data-object="hatches--anon-81" height="50" width="50" x="400" y="350" style="fill: url(#pattern-hatched-45deg-white-8.7-0.25);"/> 89 + <rect data-object="hatches--anon-82" height="50" width="50" x="450" y="350" style="fill: url(#pattern-hatched-45deg-white-8.8-0.25);"/> 90 90 <circle cx="525" cy="375" data-object="hatches--anon-83" r="25" style="fill: url(#pattern-hatched-45deg-white-8.9-0.25);"/> 91 91 <circle cx="575" cy="375" data-object="hatches--anon-84" r="25" style="fill: url(#pattern-hatched-45deg-white-9-0.25);"/> 92 92 <circle cx="625" cy="375" data-object="hatches--anon-85" r="25" style="fill: url(#pattern-hatched-45deg-white-9.1-0.25);"/> 93 - <rect data-object="hatches--anon-86" height="50" style="fill: url(#pattern-hatched-45deg-white-9.2-0.25);" width="50" x="650" y="350"/> 94 - <rect data-object="hatches--anon-87" height="50" style="fill: url(#pattern-hatched-45deg-white-9.3-0.25);" width="50" x="700" y="350"/> 93 + <rect data-object="hatches--anon-86" height="50" width="50" x="650" y="350" style="fill: url(#pattern-hatched-45deg-white-9.2-0.25);"/> 94 + <rect data-object="hatches--anon-87" height="50" width="50" x="700" y="350" style="fill: url(#pattern-hatched-45deg-white-9.3-0.25);"/> 95 95 <circle cx="525" cy="75" data-object="hatches--anon-9" r="25" style="fill: url(#pattern-hatched-45deg-white-1.4-0.25);"/> 96 - </g> 97 - <g class="layer" data-layer="red dot"> 98 - <g data-object="red dot--anon-0" style="fill: #cf0a2b;transform-box: fill-box;filter: url(#filter-glow-5); overflow: visible;" transform-origin="575 225"> 96 + </g><g class="layer" data-layer="red dot"> 97 + <g style="fill: #cf0a2b;transform-box: fill-box;filter: url(#filter-glow-5); overflow: visible;"> 99 98 <circle cx="575" cy="225" data-object="red dot--anon-0" r="25"/> 100 - </g> 101 - </g> 102 - <g class="layer" data-layer="strands"> 103 - <g data-object="strands--strands#0" style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="200 300"> 104 - <path d="M150,250 Q200,250,200,300" data-object="strands--strands#0" stroke-width="2"/> 105 - </g> 106 - <g data-object="strands--strands#1" style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="200 275"> 99 + </g></g><g class="layer" data-layer="strands"> 100 + <g style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;"> 101 + <path d="M 150 250 Q 200 250 200 300" data-object="strands--strands#0" stroke-width="2"/> 102 + </g><g style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;"> 107 103 <line data-object="strands--strands#1" stroke-width="2" x1="150" x2="200" y1="250" y2="250"/> 108 - </g> 109 - <g data-object="strands--strands#10" style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="200 250"> 110 - <path d="M200,250 Q150,250,150,200" data-object="strands--strands#10" stroke-width="2"/> 111 - </g> 112 - <g data-object="strands--strands#11" style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="300 350"> 113 - <path d="M250,300 Q250,350,300,350" data-object="strands--strands#11" stroke-width="2"/> 114 - </g> 115 - <g data-object="strands--strands#12" style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="250 250"> 116 - <path d="M250,200 Q200,200,200,250" data-object="strands--strands#12" stroke-width="2"/> 117 - </g> 118 - <g data-object="strands--strands#13" style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="275 300"> 104 + </g><g style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;"> 105 + <path d="M 200 250 Q 150 250 150 200" data-object="strands--strands#10" stroke-width="2"/> 106 + </g><g style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;"> 107 + <path d="M 250 300 Q 250 350 300 350" data-object="strands--strands#11" stroke-width="2"/> 108 + </g><g style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;"> 109 + <path d="M 250 200 Q 200 200 200 250" data-object="strands--strands#12" stroke-width="2"/> 110 + </g><g style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;"> 119 111 <line data-object="strands--strands#13" stroke-width="2" x1="250" x2="250" y1="250" y2="300"/> 120 - </g> 121 - <g data-object="strands--strands#14" style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="200 325"> 112 + </g><g style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;"> 122 113 <line data-object="strands--strands#14" stroke-width="2" x1="150" x2="200" y1="300" y2="300"/> 123 - </g> 124 - <g data-object="strands--strands#15" style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="225 300"> 125 - <path d="M150,300 Q150,200,250,200" data-object="strands--strands#15" stroke-width="2"/> 126 - </g> 127 - <g data-object="strands--strands#16" style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="200 300"> 114 + </g><g style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;"> 115 + <path d="M 150 300 Q 150 200 250 200" data-object="strands--strands#15" stroke-width="2"/> 116 + </g><g style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;"> 128 117 <line data-object="strands--strands#16" stroke-width="2" x1="150" x2="200" y1="300" y2="200"/> 129 - </g> 130 - <g data-object="strands--strands#17" style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="225 325"> 131 - <path d="M150,250 Q250,250,250,350" data-object="strands--strands#17" stroke-width="2"/> 132 - </g> 133 - <g data-object="strands--strands#18" style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="250 300"> 134 - <path d="M250,300 Q250,200,150,200" data-object="strands--strands#18" stroke-width="2"/> 135 - </g> 136 - <g data-object="strands--strands#19" style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="175 275"> 118 + </g><g style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;"> 119 + <path d="M 150 250 Q 250 250 250 350" data-object="strands--strands#17" stroke-width="2"/> 120 + </g><g style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;"> 121 + <path d="M 250 300 Q 250 200 150 200" data-object="strands--strands#18" stroke-width="2"/> 122 + </g><g style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;"> 137 123 <line data-object="strands--strands#19" stroke-width="2" x1="150" x2="150" y1="250" y2="250"/> 138 - </g> 139 - <g data-object="strands--strands#2" style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="200 250"> 140 - <path d="M200,200 Q200,250,150,250" data-object="strands--strands#2" stroke-width="2"/> 141 - </g> 142 - <g data-object="strands--strands#20" style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="250 300"> 143 - <path d="M250,300 Q250,250,200,250" data-object="strands--strands#20" stroke-width="2"/> 144 - </g> 145 - <g data-object="strands--strands#21" style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="250 300"> 146 - <path d="M250,250 Q200,250,200,300" data-object="strands--strands#21" stroke-width="2"/> 147 - </g> 148 - <g data-object="strands--strands#22" style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="250 275"> 124 + </g><g style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;"> 125 + <path d="M 200 200 Q 200 250 150 250" data-object="strands--strands#2" stroke-width="2"/> 126 + </g><g style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;"> 127 + <path d="M 250 300 Q 250 250 200 250" data-object="strands--strands#20" stroke-width="2"/> 128 + </g><g style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;"> 129 + <path d="M 250 250 Q 200 250 200 300" data-object="strands--strands#21" stroke-width="2"/> 130 + </g><g style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;"> 149 131 <line data-object="strands--strands#22" stroke-width="2" x1="250" x2="200" y1="250" y2="250"/> 150 - </g> 151 - <g data-object="strands--strands#23" style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="250 225"> 132 + </g><g style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;"> 152 133 <line data-object="strands--strands#23" stroke-width="2" x1="250" x2="150" y1="200" y2="200"/> 153 - </g> 154 - <g data-object="strands--strands#24" style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="250 250"> 134 + </g><g style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;"> 155 135 <line data-object="strands--strands#24" stroke-width="2" x1="250" x2="150" y1="200" y2="250"/> 156 - </g> 157 - <g data-object="strands--strands#25" style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="175 325"> 136 + </g><g style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;"> 158 137 <line data-object="strands--strands#25" stroke-width="2" x1="150" x2="150" y1="300" y2="300"/> 159 - </g> 160 - <g data-object="strands--strands#26" style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="225 225"> 138 + </g><g style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;"> 161 139 <line data-object="strands--strands#26" stroke-width="2" x1="200" x2="200" y1="200" y2="200"/> 162 - </g> 163 - <g data-object="strands--strands#27" style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="225 250"> 140 + </g><g style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;"> 164 141 <line data-object="strands--strands#27" stroke-width="2" x1="200" x2="200" y1="200" y2="250"/> 165 - </g> 166 - <g data-object="strands--strands#28" style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="225 275"> 167 - <path d="M150,200 Q150,300,250,300" data-object="strands--strands#28" stroke-width="2"/> 168 - </g> 169 - <g data-object="strands--strands#29" style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="250 300"> 170 - <path d="M250,300 Q150,300,150,200" data-object="strands--strands#29" stroke-width="2"/> 171 - </g> 172 - <g data-object="strands--strands#3" style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="200 325"> 142 + </g><g style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;"> 143 + <path d="M 150 200 Q 150 300 250 300" data-object="strands--strands#28" stroke-width="2"/> 144 + </g><g style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;"> 145 + <path d="M 250 300 Q 150 300 150 200" data-object="strands--strands#29" stroke-width="2"/> 146 + </g><g style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;"> 173 147 <line data-object="strands--strands#3" stroke-width="2" x1="200" x2="150" y1="300" y2="300"/> 174 - </g> 175 - <g data-object="strands--strands#4" style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="200 250"> 176 - <path d="M150,250 Q150,200,200,200" data-object="strands--strands#4" stroke-width="2"/> 177 - </g> 178 - <g data-object="strands--strands#5" style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="275 325"> 179 - <path d="M200,250 Q300,250,300,350" data-object="strands--strands#5" stroke-width="2"/> 180 - </g> 181 - <g data-object="strands--strands#6" style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="200 250"> 182 - <path d="M200,250 Q200,200,150,200" data-object="strands--strands#6" stroke-width="2"/> 183 - </g> 184 - <g data-object="strands--strands#7" style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="200 300"> 185 - <path d="M150,300 Q200,300,200,250" data-object="strands--strands#7" stroke-width="2"/> 186 - </g> 187 - <g data-object="strands--strands#8" style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="200 300"> 188 - <path d="M200,300 Q150,300,150,250" data-object="strands--strands#8" stroke-width="2"/> 189 - </g> 190 - <g data-object="strands--strands#9" style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;" transform-origin="250 250"> 148 + </g><g style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;"> 149 + <path d="M 150 250 Q 150 200 200 200" data-object="strands--strands#4" stroke-width="2"/> 150 + </g><g style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;"> 151 + <path d="M 200 250 Q 300 250 300 350" data-object="strands--strands#5" stroke-width="2"/> 152 + </g><g style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;"> 153 + <path d="M 200 250 Q 200 200 150 200" data-object="strands--strands#6" stroke-width="2"/> 154 + </g><g style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;"> 155 + <path d="M 150 300 Q 200 300 200 250" data-object="strands--strands#7" stroke-width="2"/> 156 + </g><g style="stroke: #4fecec; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;"> 157 + <path d="M 200 300 Q 150 300 150 250" data-object="strands--strands#8" stroke-width="2"/> 158 + </g><g style="stroke: #e92e76; fill: transparent;transform-box: fill-box;filter: url(#filter-glow-4); overflow: visible;"> 191 159 <line data-object="strands--strands#9" stroke-width="2" x1="200" x2="250" y1="250" y2="200"/> 192 - </g> 193 - </g> 194 - <g class="layer" data-layer="root"/> 195 - <defs> 160 + </g></g><g class="layer" data-layer="root"/> 161 + <defs > 196 162 <filter filterUnit="userSpaceOnUse" id="filter-glow-4"> 197 163 <feGaussianBlur result="coloredBlur" stdDeviation="4"/> 198 - <feMerge> 164 + <feMerge > 199 165 <feMergeNode in="coloredBlur"/> 200 166 <feMergeNode in="SourceGraphic"/> 201 - </feMerge> 202 - </filter> 203 - <filter filterUnit="userSpaceOnUse" id="filter-glow-5"> 167 + </feMerge></filter><filter filterUnit="userSpaceOnUse" id="filter-glow-5"> 204 168 <feGaussianBlur result="coloredBlur" stdDeviation="5"/> 205 - <feMerge> 169 + <feMerge > 206 170 <feMergeNode in="coloredBlur"/> 207 171 <feMergeNode in="SourceGraphic"/> 208 - </feMerge> 209 - </filter> 210 - <pattern height="1" id="pattern-hatched-45deg-white-0.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,0.5,0.5" width="1"> 172 + </feMerge></filter><pattern height="1" id="pattern-hatched-45deg-white-0.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,0.5,0.5" width="1"> 211 173 <polygon fill="#ffffff" points="0,0 0.125,0 0,0.125"/> 212 174 <polygon fill="#ffffff" points="0,0.5 0.5,0 0.5,0.125 0.125,0.5"/> 213 - </pattern> 214 - <pattern height="1.2" id="pattern-hatched-45deg-white-0.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,0.6,0.6" width="1.2"> 175 + </pattern><pattern height="1.2" id="pattern-hatched-45deg-white-0.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,0.6,0.6" width="1.2"> 215 176 <polygon fill="#ffffff" points="0,0 0.15,0 0,0.15"/> 216 177 <polygon fill="#ffffff" points="0,0.6 0.6,0 0.6,0.15 0.15,0.6"/> 217 - </pattern> 218 - <pattern height="1.4" id="pattern-hatched-45deg-white-0.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,0.7,0.7" width="1.4"> 178 + </pattern><pattern height="1.4" id="pattern-hatched-45deg-white-0.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,0.7,0.7" width="1.4"> 219 179 <polygon fill="#ffffff" points="0,0 0.175,0 0,0.175"/> 220 180 <polygon fill="#ffffff" points="0,0.7 0.7,0 0.7,0.175 0.175,0.7"/> 221 - </pattern> 222 - <pattern height="1.6" id="pattern-hatched-45deg-white-0.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,0.8,0.8" width="1.6"> 181 + </pattern><pattern height="1.6" id="pattern-hatched-45deg-white-0.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,0.8,0.8" width="1.6"> 223 182 <polygon fill="#ffffff" points="0,0 0.2,0 0,0.2"/> 224 183 <polygon fill="#ffffff" points="0,0.8 0.8,0 0.8,0.2 0.2,0.8"/> 225 - </pattern> 226 - <pattern height="1.8" id="pattern-hatched-45deg-white-0.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,0.9,0.9" width="1.8"> 184 + </pattern><pattern height="1.8" id="pattern-hatched-45deg-white-0.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,0.9,0.9" width="1.8"> 227 185 <polygon fill="#ffffff" points="0,0 0.225,0 0,0.225"/> 228 186 <polygon fill="#ffffff" points="0,0.9 0.9,0 0.9,0.225 0.225,0.9"/> 229 - </pattern> 230 - <pattern height="2" id="pattern-hatched-45deg-white-1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1,1" width="2"> 187 + </pattern><pattern height="2" id="pattern-hatched-45deg-white-1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1,1" width="2"> 231 188 <polygon fill="#ffffff" points="0,0 0.25,0 0,0.25"/> 232 189 <polygon fill="#ffffff" points="0,1 1,0 1,0.25 0.25,1"/> 233 - </pattern> 234 - <pattern height="2.2" id="pattern-hatched-45deg-white-1.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.1,1.1" width="2.2"> 190 + </pattern><pattern height="2.2" id="pattern-hatched-45deg-white-1.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.1,1.1" width="2.2"> 235 191 <polygon fill="#ffffff" points="0,0 0.275,0 0,0.275"/> 236 192 <polygon fill="#ffffff" points="0,1.1 1.1,0 1.1,0.275 0.275,1.1"/> 237 - </pattern> 238 - <pattern height="2.4" id="pattern-hatched-45deg-white-1.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.2,1.2" width="2.4"> 193 + </pattern><pattern height="2.4" id="pattern-hatched-45deg-white-1.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.2,1.2" width="2.4"> 239 194 <polygon fill="#ffffff" points="0,0 0.3,0 0,0.3"/> 240 195 <polygon fill="#ffffff" points="0,1.2 1.2,0 1.2,0.3 0.3,1.2"/> 241 - </pattern> 242 - <pattern height="2.6" id="pattern-hatched-45deg-white-1.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.3,1.3" width="2.6"> 196 + </pattern><pattern height="2.6" id="pattern-hatched-45deg-white-1.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.3,1.3" width="2.6"> 243 197 <polygon fill="#ffffff" points="0,0 0.325,0 0,0.325"/> 244 198 <polygon fill="#ffffff" points="0,1.3 1.3,0 1.3,0.325 0.325,1.3"/> 245 - </pattern> 246 - <pattern height="2.8" id="pattern-hatched-45deg-white-1.4-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.4,1.4" width="2.8"> 199 + </pattern><pattern height="2.8" id="pattern-hatched-45deg-white-1.4-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.4,1.4" width="2.8"> 247 200 <polygon fill="#ffffff" points="0,0 0.35,0 0,0.35"/> 248 201 <polygon fill="#ffffff" points="0,1.4 1.4,0 1.4,0.35 0.35,1.4"/> 249 - </pattern> 250 - <pattern height="3" id="pattern-hatched-45deg-white-1.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.5,1.5" width="3"> 202 + </pattern><pattern height="3" id="pattern-hatched-45deg-white-1.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.5,1.5" width="3"> 251 203 <polygon fill="#ffffff" points="0,0 0.375,0 0,0.375"/> 252 204 <polygon fill="#ffffff" points="0,1.5 1.5,0 1.5,0.375 0.375,1.5"/> 253 - </pattern> 254 - <pattern height="3.2" id="pattern-hatched-45deg-white-1.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.6,1.6" width="3.2"> 205 + </pattern><pattern height="3.2" id="pattern-hatched-45deg-white-1.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.6,1.6" width="3.2"> 255 206 <polygon fill="#ffffff" points="0,0 0.4,0 0,0.4"/> 256 207 <polygon fill="#ffffff" points="0,1.6 1.6,0 1.6,0.4 0.4,1.6"/> 257 - </pattern> 258 - <pattern height="3.4" id="pattern-hatched-45deg-white-1.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.7,1.7" width="3.4"> 208 + </pattern><pattern height="3.4" id="pattern-hatched-45deg-white-1.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.7,1.7" width="3.4"> 259 209 <polygon fill="#ffffff" points="0,0 0.425,0 0,0.425"/> 260 210 <polygon fill="#ffffff" points="0,1.7 1.7,0 1.7,0.425 0.425,1.7"/> 261 - </pattern> 262 - <pattern height="3.6" id="pattern-hatched-45deg-white-1.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.8,1.8" width="3.6"> 211 + </pattern><pattern height="3.6" id="pattern-hatched-45deg-white-1.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.8,1.8" width="3.6"> 263 212 <polygon fill="#ffffff" points="0,0 0.45,0 0,0.45"/> 264 213 <polygon fill="#ffffff" points="0,1.8 1.8,0 1.8,0.45 0.45,1.8"/> 265 - </pattern> 266 - <pattern height="3.8" id="pattern-hatched-45deg-white-1.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.9,1.9" width="3.8"> 214 + </pattern><pattern height="3.8" id="pattern-hatched-45deg-white-1.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,1.9,1.9" width="3.8"> 267 215 <polygon fill="#ffffff" points="0,0 0.475,0 0,0.475"/> 268 216 <polygon fill="#ffffff" points="0,1.9 1.9,0 1.9,0.475 0.475,1.9"/> 269 - </pattern> 270 - <pattern height="4" id="pattern-hatched-45deg-white-2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2,2" width="4"> 217 + </pattern><pattern height="4" id="pattern-hatched-45deg-white-2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2,2" width="4"> 271 218 <polygon fill="#ffffff" points="0,0 0.5,0 0,0.5"/> 272 219 <polygon fill="#ffffff" points="0,2 2,0 2,0.5 0.5,2"/> 273 - </pattern> 274 - <pattern height="4.2" id="pattern-hatched-45deg-white-2.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.1,2.1" width="4.2"> 220 + </pattern><pattern height="4.2" id="pattern-hatched-45deg-white-2.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.1,2.1" width="4.2"> 275 221 <polygon fill="#ffffff" points="0,0 0.525,0 0,0.525"/> 276 222 <polygon fill="#ffffff" points="0,2.1 2.1,0 2.1,0.525 0.525,2.1"/> 277 - </pattern> 278 - <pattern height="4.4" id="pattern-hatched-45deg-white-2.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.2,2.2" width="4.4"> 223 + </pattern><pattern height="4.4" id="pattern-hatched-45deg-white-2.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.2,2.2" width="4.4"> 279 224 <polygon fill="#ffffff" points="0,0 0.55,0 0,0.55"/> 280 225 <polygon fill="#ffffff" points="0,2.2 2.2,0 2.2,0.55 0.55,2.2"/> 281 - </pattern> 282 - <pattern height="4.6" id="pattern-hatched-45deg-white-2.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.3,2.3" width="4.6"> 226 + </pattern><pattern height="4.6" id="pattern-hatched-45deg-white-2.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.3,2.3" width="4.6"> 283 227 <polygon fill="#ffffff" points="0,0 0.575,0 0,0.575"/> 284 228 <polygon fill="#ffffff" points="0,2.3 2.3,0 2.3,0.575 0.575,2.3"/> 285 - </pattern> 286 - <pattern height="4.8" id="pattern-hatched-45deg-white-2.4-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.4,2.4" width="4.8"> 229 + </pattern><pattern height="4.8" id="pattern-hatched-45deg-white-2.4-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.4,2.4" width="4.8"> 287 230 <polygon fill="#ffffff" points="0,0 0.6,0 0,0.6"/> 288 231 <polygon fill="#ffffff" points="0,2.4 2.4,0 2.4,0.6 0.6,2.4"/> 289 - </pattern> 290 - <pattern height="5" id="pattern-hatched-45deg-white-2.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.5,2.5" width="5"> 232 + </pattern><pattern height="5" id="pattern-hatched-45deg-white-2.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.5,2.5" width="5"> 291 233 <polygon fill="#ffffff" points="0,0 0.625,0 0,0.625"/> 292 234 <polygon fill="#ffffff" points="0,2.5 2.5,0 2.5,0.625 0.625,2.5"/> 293 - </pattern> 294 - <pattern height="5.2" id="pattern-hatched-45deg-white-2.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.6,2.6" width="5.2"> 235 + </pattern><pattern height="5.2" id="pattern-hatched-45deg-white-2.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.6,2.6" width="5.2"> 295 236 <polygon fill="#ffffff" points="0,0 0.65,0 0,0.65"/> 296 237 <polygon fill="#ffffff" points="0,2.6 2.6,0 2.6,0.65 0.65,2.6"/> 297 - </pattern> 298 - <pattern height="5.4" id="pattern-hatched-45deg-white-2.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.7,2.7" width="5.4"> 238 + </pattern><pattern height="5.4" id="pattern-hatched-45deg-white-2.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.7,2.7" width="5.4"> 299 239 <polygon fill="#ffffff" points="0,0 0.675,0 0,0.675"/> 300 240 <polygon fill="#ffffff" points="0,2.7 2.7,0 2.7,0.675 0.675,2.7"/> 301 - </pattern> 302 - <pattern height="5.6" id="pattern-hatched-45deg-white-2.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.8,2.8" width="5.6"> 241 + </pattern><pattern height="5.6" id="pattern-hatched-45deg-white-2.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.8,2.8" width="5.6"> 303 242 <polygon fill="#ffffff" points="0,0 0.7,0 0,0.7"/> 304 243 <polygon fill="#ffffff" points="0,2.8 2.8,0 2.8,0.7 0.7,2.8"/> 305 - </pattern> 306 - <pattern height="5.8" id="pattern-hatched-45deg-white-2.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.9,2.9" width="5.8"> 244 + </pattern><pattern height="5.8" id="pattern-hatched-45deg-white-2.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,2.9,2.9" width="5.8"> 307 245 <polygon fill="#ffffff" points="0,0 0.725,0 0,0.725"/> 308 246 <polygon fill="#ffffff" points="0,2.9 2.9,0 2.9,0.725 0.725,2.9"/> 309 - </pattern> 310 - <pattern height="6" id="pattern-hatched-45deg-white-3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3,3" width="6"> 247 + </pattern><pattern height="6" id="pattern-hatched-45deg-white-3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3,3" width="6"> 311 248 <polygon fill="#ffffff" points="0,0 0.75,0 0,0.75"/> 312 249 <polygon fill="#ffffff" points="0,3 3,0 3,0.75 0.75,3"/> 313 - </pattern> 314 - <pattern height="6.2" id="pattern-hatched-45deg-white-3.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.1,3.1" width="6.2"> 250 + </pattern><pattern height="6.2" id="pattern-hatched-45deg-white-3.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.1,3.1" width="6.2"> 315 251 <polygon fill="#ffffff" points="0,0 0.775,0 0,0.775"/> 316 252 <polygon fill="#ffffff" points="0,3.1 3.1,0 3.1,0.775 0.775,3.1"/> 317 - </pattern> 318 - <pattern height="6.4" id="pattern-hatched-45deg-white-3.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.2,3.2" width="6.4"> 253 + </pattern><pattern height="6.4" id="pattern-hatched-45deg-white-3.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.2,3.2" width="6.4"> 319 254 <polygon fill="#ffffff" points="0,0 0.8,0 0,0.8"/> 320 255 <polygon fill="#ffffff" points="0,3.2 3.2,0 3.2,0.8 0.8,3.2"/> 321 - </pattern> 322 - <pattern height="6.6" id="pattern-hatched-45deg-white-3.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.3,3.3" width="6.6"> 256 + </pattern><pattern height="6.6" id="pattern-hatched-45deg-white-3.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.3,3.3" width="6.6"> 323 257 <polygon fill="#ffffff" points="0,0 0.825,0 0,0.825"/> 324 258 <polygon fill="#ffffff" points="0,3.3 3.3,0 3.3,0.825 0.825,3.3"/> 325 - </pattern> 326 - <pattern height="6.8" id="pattern-hatched-45deg-white-3.4-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.4,3.4" width="6.8"> 259 + </pattern><pattern height="6.8" id="pattern-hatched-45deg-white-3.4-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.4,3.4" width="6.8"> 327 260 <polygon fill="#ffffff" points="0,0 0.85,0 0,0.85"/> 328 261 <polygon fill="#ffffff" points="0,3.4 3.4,0 3.4,0.85 0.85,3.4"/> 329 - </pattern> 330 - <pattern height="7" id="pattern-hatched-45deg-white-3.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.5,3.5" width="7"> 262 + </pattern><pattern height="7" id="pattern-hatched-45deg-white-3.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.5,3.5" width="7"> 331 263 <polygon fill="#ffffff" points="0,0 0.875,0 0,0.875"/> 332 264 <polygon fill="#ffffff" points="0,3.5 3.5,0 3.5,0.875 0.875,3.5"/> 333 - </pattern> 334 - <pattern height="7.2" id="pattern-hatched-45deg-white-3.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.6,3.6" width="7.2"> 265 + </pattern><pattern height="7.2" id="pattern-hatched-45deg-white-3.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.6,3.6" width="7.2"> 335 266 <polygon fill="#ffffff" points="0,0 0.9,0 0,0.9"/> 336 267 <polygon fill="#ffffff" points="0,3.6 3.6,0 3.6,0.9 0.9,3.6"/> 337 - </pattern> 338 - <pattern height="7.4" id="pattern-hatched-45deg-white-3.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.7,3.7" width="7.4"> 268 + </pattern><pattern height="7.4" id="pattern-hatched-45deg-white-3.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.7,3.7" width="7.4"> 339 269 <polygon fill="#ffffff" points="0,0 0.925,0 0,0.925"/> 340 270 <polygon fill="#ffffff" points="0,3.7 3.7,0 3.7,0.925 0.925,3.7"/> 341 - </pattern> 342 - <pattern height="7.6" id="pattern-hatched-45deg-white-3.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.8,3.8" width="7.6"> 271 + </pattern><pattern height="7.6" id="pattern-hatched-45deg-white-3.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.8,3.8" width="7.6"> 343 272 <polygon fill="#ffffff" points="0,0 0.95,0 0,0.95"/> 344 273 <polygon fill="#ffffff" points="0,3.8 3.8,0 3.8,0.95 0.95,3.8"/> 345 - </pattern> 346 - <pattern height="7.8" id="pattern-hatched-45deg-white-3.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.9,3.9" width="7.8"> 274 + </pattern><pattern height="7.8" id="pattern-hatched-45deg-white-3.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,3.9,3.9" width="7.8"> 347 275 <polygon fill="#ffffff" points="0,0 0.975,0 0,0.975"/> 348 276 <polygon fill="#ffffff" points="0,3.9 3.9,0 3.9,0.975 0.975,3.9"/> 349 - </pattern> 350 - <pattern height="8" id="pattern-hatched-45deg-white-4-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4,4" width="8"> 277 + </pattern><pattern height="8" id="pattern-hatched-45deg-white-4-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4,4" width="8"> 351 278 <polygon fill="#ffffff" points="0,0 1,0 0,1"/> 352 279 <polygon fill="#ffffff" points="0,4 4,0 4,1 1,4"/> 353 - </pattern> 354 - <pattern height="8.2" id="pattern-hatched-45deg-white-4.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.1,4.1" width="8.2"> 280 + </pattern><pattern height="8.2" id="pattern-hatched-45deg-white-4.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.1,4.1" width="8.2"> 355 281 <polygon fill="#ffffff" points="0,0 1.025,0 0,1.025"/> 356 282 <polygon fill="#ffffff" points="0,4.1 4.1,0 4.1,1.025 1.025,4.1"/> 357 - </pattern> 358 - <pattern height="8.4" id="pattern-hatched-45deg-white-4.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.2,4.2" width="8.4"> 283 + </pattern><pattern height="8.4" id="pattern-hatched-45deg-white-4.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.2,4.2" width="8.4"> 359 284 <polygon fill="#ffffff" points="0,0 1.05,0 0,1.05"/> 360 285 <polygon fill="#ffffff" points="0,4.2 4.2,0 4.2,1.05 1.05,4.2"/> 361 - </pattern> 362 - <pattern height="8.6" id="pattern-hatched-45deg-white-4.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.3,4.3" width="8.6"> 286 + </pattern><pattern height="8.6" id="pattern-hatched-45deg-white-4.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.3,4.3" width="8.6"> 363 287 <polygon fill="#ffffff" points="0,0 1.075,0 0,1.075"/> 364 288 <polygon fill="#ffffff" points="0,4.3 4.3,0 4.3,1.075 1.075,4.3"/> 365 - </pattern> 366 - <pattern height="8.8" id="pattern-hatched-45deg-white-4.4-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.4,4.4" width="8.8"> 289 + </pattern><pattern height="8.8" id="pattern-hatched-45deg-white-4.4-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.4,4.4" width="8.8"> 367 290 <polygon fill="#ffffff" points="0,0 1.1,0 0,1.1"/> 368 291 <polygon fill="#ffffff" points="0,4.4 4.4,0 4.4,1.1 1.1,4.4"/> 369 - </pattern> 370 - <pattern height="9" id="pattern-hatched-45deg-white-4.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.5,4.5" width="9"> 292 + </pattern><pattern height="9" id="pattern-hatched-45deg-white-4.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.5,4.5" width="9"> 371 293 <polygon fill="#ffffff" points="0,0 1.125,0 0,1.125"/> 372 294 <polygon fill="#ffffff" points="0,4.5 4.5,0 4.5,1.125 1.125,4.5"/> 373 - </pattern> 374 - <pattern height="9.2" id="pattern-hatched-45deg-white-4.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.6,4.6" width="9.2"> 295 + </pattern><pattern height="9.2" id="pattern-hatched-45deg-white-4.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.6,4.6" width="9.2"> 375 296 <polygon fill="#ffffff" points="0,0 1.15,0 0,1.15"/> 376 297 <polygon fill="#ffffff" points="0,4.6 4.6,0 4.6,1.15 1.15,4.6"/> 377 - </pattern> 378 - <pattern height="9.4" id="pattern-hatched-45deg-white-4.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.7,4.7" width="9.4"> 298 + </pattern><pattern height="9.4" id="pattern-hatched-45deg-white-4.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.7,4.7" width="9.4"> 379 299 <polygon fill="#ffffff" points="0,0 1.175,0 0,1.175"/> 380 300 <polygon fill="#ffffff" points="0,4.7 4.7,0 4.7,1.175 1.175,4.7"/> 381 - </pattern> 382 - <pattern height="9.6" id="pattern-hatched-45deg-white-4.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.8,4.8" width="9.6"> 301 + </pattern><pattern height="9.6" id="pattern-hatched-45deg-white-4.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.8,4.8" width="9.6"> 383 302 <polygon fill="#ffffff" points="0,0 1.2,0 0,1.2"/> 384 303 <polygon fill="#ffffff" points="0,4.8 4.8,0 4.8,1.2 1.2,4.8"/> 385 - </pattern> 386 - <pattern height="9.8" id="pattern-hatched-45deg-white-4.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.9,4.9" width="9.8"> 304 + </pattern><pattern height="9.8" id="pattern-hatched-45deg-white-4.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,4.9,4.9" width="9.8"> 387 305 <polygon fill="#ffffff" points="0,0 1.225,0 0,1.225"/> 388 306 <polygon fill="#ffffff" points="0,4.9 4.9,0 4.9,1.225 1.225,4.9"/> 389 - </pattern> 390 - <pattern height="10" id="pattern-hatched-45deg-white-5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5,5" width="10"> 307 + </pattern><pattern height="10" id="pattern-hatched-45deg-white-5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5,5" width="10"> 391 308 <polygon fill="#ffffff" points="0,0 1.25,0 0,1.25"/> 392 309 <polygon fill="#ffffff" points="0,5 5,0 5,1.25 1.25,5"/> 393 - </pattern> 394 - <pattern height="10.2" id="pattern-hatched-45deg-white-5.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5.1,5.1" width="10.2"> 310 + </pattern><pattern height="10.2" id="pattern-hatched-45deg-white-5.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5.1,5.1" width="10.2"> 395 311 <polygon fill="#ffffff" points="0,0 1.275,0 0,1.275"/> 396 312 <polygon fill="#ffffff" points="0,5.1 5.1,0 5.1,1.275 1.275,5.1"/> 397 - </pattern> 398 - <pattern height="10.4" id="pattern-hatched-45deg-white-5.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5.2,5.2" width="10.4"> 313 + </pattern><pattern height="10.4" id="pattern-hatched-45deg-white-5.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5.2,5.2" width="10.4"> 399 314 <polygon fill="#ffffff" points="0,0 1.3,0 0,1.3"/> 400 315 <polygon fill="#ffffff" points="0,5.2 5.2,0 5.2,1.3 1.3,5.2"/> 401 - </pattern> 402 - <pattern height="10.6" id="pattern-hatched-45deg-white-5.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5.3,5.3" width="10.6"> 316 + </pattern><pattern height="10.6" id="pattern-hatched-45deg-white-5.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5.3,5.3" width="10.6"> 403 317 <polygon fill="#ffffff" points="0,0 1.325,0 0,1.325"/> 404 318 <polygon fill="#ffffff" points="0,5.3 5.3,0 5.3,1.325 1.325,5.3"/> 405 - </pattern> 406 - <pattern height="11" id="pattern-hatched-45deg-white-5.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5.5,5.5" width="11"> 319 + </pattern><pattern height="11" id="pattern-hatched-45deg-white-5.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5.5,5.5" width="11"> 407 320 <polygon fill="#ffffff" points="0,0 1.375,0 0,1.375"/> 408 321 <polygon fill="#ffffff" points="0,5.5 5.5,0 5.5,1.375 1.375,5.5"/> 409 - </pattern> 410 - <pattern height="11.2" id="pattern-hatched-45deg-white-5.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5.6,5.6" width="11.2"> 322 + </pattern><pattern height="11.2" id="pattern-hatched-45deg-white-5.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5.6,5.6" width="11.2"> 411 323 <polygon fill="#ffffff" points="0,0 1.4,0 0,1.4"/> 412 324 <polygon fill="#ffffff" points="0,5.6 5.6,0 5.6,1.4 1.4,5.6"/> 413 - </pattern> 414 - <pattern height="11.4" id="pattern-hatched-45deg-white-5.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5.7,5.7" width="11.4"> 325 + </pattern><pattern height="11.4" id="pattern-hatched-45deg-white-5.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5.7,5.7" width="11.4"> 415 326 <polygon fill="#ffffff" points="0,0 1.425,0 0,1.425"/> 416 327 <polygon fill="#ffffff" points="0,5.7 5.7,0 5.7,1.425 1.425,5.7"/> 417 - </pattern> 418 - <pattern height="11.6" id="pattern-hatched-45deg-white-5.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5.8,5.8" width="11.6"> 328 + </pattern><pattern height="11.6" id="pattern-hatched-45deg-white-5.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5.8,5.8" width="11.6"> 419 329 <polygon fill="#ffffff" points="0,0 1.45,0 0,1.45"/> 420 330 <polygon fill="#ffffff" points="0,5.8 5.8,0 5.8,1.45 1.45,5.8"/> 421 - </pattern> 422 - <pattern height="11.8" id="pattern-hatched-45deg-white-5.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5.9,5.9" width="11.8"> 331 + </pattern><pattern height="11.8" id="pattern-hatched-45deg-white-5.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,5.9,5.9" width="11.8"> 423 332 <polygon fill="#ffffff" points="0,0 1.475,0 0,1.475"/> 424 333 <polygon fill="#ffffff" points="0,5.9 5.9,0 5.9,1.475 1.475,5.9"/> 425 - </pattern> 426 - <pattern height="12" id="pattern-hatched-45deg-white-6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6,6" width="12"> 334 + </pattern><pattern height="12" id="pattern-hatched-45deg-white-6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6,6" width="12"> 427 335 <polygon fill="#ffffff" points="0,0 1.5,0 0,1.5"/> 428 336 <polygon fill="#ffffff" points="0,6 6,0 6,1.5 1.5,6"/> 429 - </pattern> 430 - <pattern height="12.2" id="pattern-hatched-45deg-white-6.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.1,6.1" width="12.2"> 337 + </pattern><pattern height="12.2" id="pattern-hatched-45deg-white-6.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.1,6.1" width="12.2"> 431 338 <polygon fill="#ffffff" points="0,0 1.525,0 0,1.525"/> 432 339 <polygon fill="#ffffff" points="0,6.1 6.1,0 6.1,1.525 1.525,6.1"/> 433 - </pattern> 434 - <pattern height="12.4" id="pattern-hatched-45deg-white-6.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.2,6.2" width="12.4"> 340 + </pattern><pattern height="12.4" id="pattern-hatched-45deg-white-6.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.2,6.2" width="12.4"> 435 341 <polygon fill="#ffffff" points="0,0 1.55,0 0,1.55"/> 436 342 <polygon fill="#ffffff" points="0,6.2 6.2,0 6.2,1.55 1.55,6.2"/> 437 - </pattern> 438 - <pattern height="12.6" id="pattern-hatched-45deg-white-6.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.3,6.3" width="12.6"> 343 + </pattern><pattern height="12.6" id="pattern-hatched-45deg-white-6.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.3,6.3" width="12.6"> 439 344 <polygon fill="#ffffff" points="0,0 1.575,0 0,1.575"/> 440 345 <polygon fill="#ffffff" points="0,6.3 6.3,0 6.3,1.575 1.575,6.3"/> 441 - </pattern> 442 - <pattern height="12.8" id="pattern-hatched-45deg-white-6.4-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.4,6.4" width="12.8"> 346 + </pattern><pattern height="12.8" id="pattern-hatched-45deg-white-6.4-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.4,6.4" width="12.8"> 443 347 <polygon fill="#ffffff" points="0,0 1.6,0 0,1.6"/> 444 348 <polygon fill="#ffffff" points="0,6.4 6.4,0 6.4,1.6 1.6,6.4"/> 445 - </pattern> 446 - <pattern height="13" id="pattern-hatched-45deg-white-6.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.5,6.5" width="13"> 349 + </pattern><pattern height="13" id="pattern-hatched-45deg-white-6.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.5,6.5" width="13"> 447 350 <polygon fill="#ffffff" points="0,0 1.625,0 0,1.625"/> 448 351 <polygon fill="#ffffff" points="0,6.5 6.5,0 6.5,1.625 1.625,6.5"/> 449 - </pattern> 450 - <pattern height="13.2" id="pattern-hatched-45deg-white-6.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.6,6.6" width="13.2"> 352 + </pattern><pattern height="13.2" id="pattern-hatched-45deg-white-6.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.6,6.6" width="13.2"> 451 353 <polygon fill="#ffffff" points="0,0 1.65,0 0,1.65"/> 452 354 <polygon fill="#ffffff" points="0,6.6 6.6,0 6.6,1.65 1.65,6.6"/> 453 - </pattern> 454 - <pattern height="13.4" id="pattern-hatched-45deg-white-6.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.7,6.7" width="13.4"> 355 + </pattern><pattern height="13.4" id="pattern-hatched-45deg-white-6.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.7,6.7" width="13.4"> 455 356 <polygon fill="#ffffff" points="0,0 1.675,0 0,1.675"/> 456 357 <polygon fill="#ffffff" points="0,6.7 6.7,0 6.7,1.675 1.675,6.7"/> 457 - </pattern> 458 - <pattern height="13.6" id="pattern-hatched-45deg-white-6.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.8,6.8" width="13.6"> 358 + </pattern><pattern height="13.6" id="pattern-hatched-45deg-white-6.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.8,6.8" width="13.6"> 459 359 <polygon fill="#ffffff" points="0,0 1.7,0 0,1.7"/> 460 360 <polygon fill="#ffffff" points="0,6.8 6.8,0 6.8,1.7 1.7,6.8"/> 461 - </pattern> 462 - <pattern height="13.8" id="pattern-hatched-45deg-white-6.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.9,6.9" width="13.8"> 361 + </pattern><pattern height="13.8" id="pattern-hatched-45deg-white-6.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,6.9,6.9" width="13.8"> 463 362 <polygon fill="#ffffff" points="0,0 1.725,0 0,1.725"/> 464 363 <polygon fill="#ffffff" points="0,6.9 6.9,0 6.9,1.725 1.725,6.9"/> 465 - </pattern> 466 - <pattern height="14" id="pattern-hatched-45deg-white-7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7,7" width="14"> 364 + </pattern><pattern height="14" id="pattern-hatched-45deg-white-7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7,7" width="14"> 467 365 <polygon fill="#ffffff" points="0,0 1.75,0 0,1.75"/> 468 366 <polygon fill="#ffffff" points="0,7 7,0 7,1.75 1.75,7"/> 469 - </pattern> 470 - <pattern height="14.2" id="pattern-hatched-45deg-white-7.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.1,7.1" width="14.2"> 367 + </pattern><pattern height="14.2" id="pattern-hatched-45deg-white-7.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.1,7.1" width="14.2"> 471 368 <polygon fill="#ffffff" points="0,0 1.775,0 0,1.775"/> 472 369 <polygon fill="#ffffff" points="0,7.1 7.1,0 7.1,1.775 1.775,7.1"/> 473 - </pattern> 474 - <pattern height="14.4" id="pattern-hatched-45deg-white-7.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.2,7.2" width="14.4"> 370 + </pattern><pattern height="14.4" id="pattern-hatched-45deg-white-7.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.2,7.2" width="14.4"> 475 371 <polygon fill="#ffffff" points="0,0 1.8,0 0,1.8"/> 476 372 <polygon fill="#ffffff" points="0,7.2 7.2,0 7.2,1.8 1.8,7.2"/> 477 - </pattern> 478 - <pattern height="14.6" id="pattern-hatched-45deg-white-7.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.3,7.3" width="14.6"> 373 + </pattern><pattern height="14.6" id="pattern-hatched-45deg-white-7.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.3,7.3" width="14.6"> 479 374 <polygon fill="#ffffff" points="0,0 1.825,0 0,1.825"/> 480 375 <polygon fill="#ffffff" points="0,7.3 7.3,0 7.3,1.825 1.825,7.3"/> 481 - </pattern> 482 - <pattern height="14.8" id="pattern-hatched-45deg-white-7.4-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.4,7.4" width="14.8"> 376 + </pattern><pattern height="14.8" id="pattern-hatched-45deg-white-7.4-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.4,7.4" width="14.8"> 483 377 <polygon fill="#ffffff" points="0,0 1.85,0 0,1.85"/> 484 378 <polygon fill="#ffffff" points="0,7.4 7.4,0 7.4,1.85 1.85,7.4"/> 485 - </pattern> 486 - <pattern height="15" id="pattern-hatched-45deg-white-7.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.5,7.5" width="15"> 379 + </pattern><pattern height="15" id="pattern-hatched-45deg-white-7.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.5,7.5" width="15"> 487 380 <polygon fill="#ffffff" points="0,0 1.875,0 0,1.875"/> 488 381 <polygon fill="#ffffff" points="0,7.5 7.5,0 7.5,1.875 1.875,7.5"/> 489 - </pattern> 490 - <pattern height="15.2" id="pattern-hatched-45deg-white-7.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.6,7.6" width="15.2"> 382 + </pattern><pattern height="15.2" id="pattern-hatched-45deg-white-7.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.6,7.6" width="15.2"> 491 383 <polygon fill="#ffffff" points="0,0 1.9,0 0,1.9"/> 492 384 <polygon fill="#ffffff" points="0,7.6 7.6,0 7.6,1.9 1.9,7.6"/> 493 - </pattern> 494 - <pattern height="15.4" id="pattern-hatched-45deg-white-7.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.7,7.7" width="15.4"> 385 + </pattern><pattern height="15.4" id="pattern-hatched-45deg-white-7.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.7,7.7" width="15.4"> 495 386 <polygon fill="#ffffff" points="0,0 1.925,0 0,1.925"/> 496 387 <polygon fill="#ffffff" points="0,7.7 7.7,0 7.7,1.925 1.925,7.7"/> 497 - </pattern> 498 - <pattern height="15.6" id="pattern-hatched-45deg-white-7.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.8,7.8" width="15.6"> 388 + </pattern><pattern height="15.6" id="pattern-hatched-45deg-white-7.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.8,7.8" width="15.6"> 499 389 <polygon fill="#ffffff" points="0,0 1.95,0 0,1.95"/> 500 390 <polygon fill="#ffffff" points="0,7.8 7.8,0 7.8,1.95 1.95,7.8"/> 501 - </pattern> 502 - <pattern height="15.8" id="pattern-hatched-45deg-white-7.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.9,7.9" width="15.8"> 391 + </pattern><pattern height="15.8" id="pattern-hatched-45deg-white-7.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,7.9,7.9" width="15.8"> 503 392 <polygon fill="#ffffff" points="0,0 1.975,0 0,1.975"/> 504 393 <polygon fill="#ffffff" points="0,7.9 7.9,0 7.9,1.975 1.975,7.9"/> 505 - </pattern> 506 - <pattern height="16" id="pattern-hatched-45deg-white-8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8,8" width="16"> 394 + </pattern><pattern height="16" id="pattern-hatched-45deg-white-8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8,8" width="16"> 507 395 <polygon fill="#ffffff" points="0,0 2,0 0,2"/> 508 396 <polygon fill="#ffffff" points="0,8 8,0 8,2 2,8"/> 509 - </pattern> 510 - <pattern height="16.2" id="pattern-hatched-45deg-white-8.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.1,8.1" width="16.2"> 397 + </pattern><pattern height="16.2" id="pattern-hatched-45deg-white-8.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.1,8.1" width="16.2"> 511 398 <polygon fill="#ffffff" points="0,0 2.025,0 0,2.025"/> 512 399 <polygon fill="#ffffff" points="0,8.1 8.1,0 8.1,2.025 2.025,8.1"/> 513 - </pattern> 514 - <pattern height="16.4" id="pattern-hatched-45deg-white-8.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.2,8.2" width="16.4"> 400 + </pattern><pattern height="16.4" id="pattern-hatched-45deg-white-8.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.2,8.2" width="16.4"> 515 401 <polygon fill="#ffffff" points="0,0 2.05,0 0,2.05"/> 516 402 <polygon fill="#ffffff" points="0,8.2 8.2,0 8.2,2.05 2.05,8.2"/> 517 - </pattern> 518 - <pattern height="16.6" id="pattern-hatched-45deg-white-8.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.3,8.3" width="16.6"> 403 + </pattern><pattern height="16.6" id="pattern-hatched-45deg-white-8.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.3,8.3" width="16.6"> 519 404 <polygon fill="#ffffff" points="0,0 2.075,0 0,2.075"/> 520 405 <polygon fill="#ffffff" points="0,8.3 8.3,0 8.3,2.075 2.075,8.3"/> 521 - </pattern> 522 - <pattern height="16.8" id="pattern-hatched-45deg-white-8.4-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.4,8.4" width="16.8"> 406 + </pattern><pattern height="16.8" id="pattern-hatched-45deg-white-8.4-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.4,8.4" width="16.8"> 523 407 <polygon fill="#ffffff" points="0,0 2.1,0 0,2.1"/> 524 408 <polygon fill="#ffffff" points="0,8.4 8.4,0 8.4,2.1 2.1,8.4"/> 525 - </pattern> 526 - <pattern height="17" id="pattern-hatched-45deg-white-8.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.5,8.5" width="17"> 409 + </pattern><pattern height="17" id="pattern-hatched-45deg-white-8.5-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.5,8.5" width="17"> 527 410 <polygon fill="#ffffff" points="0,0 2.125,0 0,2.125"/> 528 411 <polygon fill="#ffffff" points="0,8.5 8.5,0 8.5,2.125 2.125,8.5"/> 529 - </pattern> 530 - <pattern height="17.2" id="pattern-hatched-45deg-white-8.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.6,8.6" width="17.2"> 412 + </pattern><pattern height="17.2" id="pattern-hatched-45deg-white-8.6-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.6,8.6" width="17.2"> 531 413 <polygon fill="#ffffff" points="0,0 2.15,0 0,2.15"/> 532 414 <polygon fill="#ffffff" points="0,8.6 8.6,0 8.6,2.15 2.15,8.6"/> 533 - </pattern> 534 - <pattern height="17.4" id="pattern-hatched-45deg-white-8.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.7,8.7" width="17.4"> 415 + </pattern><pattern height="17.4" id="pattern-hatched-45deg-white-8.7-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.7,8.7" width="17.4"> 535 416 <polygon fill="#ffffff" points="0,0 2.175,0 0,2.175"/> 536 417 <polygon fill="#ffffff" points="0,8.7 8.7,0 8.7,2.175 2.175,8.7"/> 537 - </pattern> 538 - <pattern height="17.6" id="pattern-hatched-45deg-white-8.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.8,8.8" width="17.6"> 418 + </pattern><pattern height="17.6" id="pattern-hatched-45deg-white-8.8-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.8,8.8" width="17.6"> 539 419 <polygon fill="#ffffff" points="0,0 2.2,0 0,2.2"/> 540 420 <polygon fill="#ffffff" points="0,8.8 8.8,0 8.8,2.2 2.2,8.8"/> 541 - </pattern> 542 - <pattern height="17.8" id="pattern-hatched-45deg-white-8.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.9,8.9" width="17.8"> 421 + </pattern><pattern height="17.8" id="pattern-hatched-45deg-white-8.9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,8.9,8.9" width="17.8"> 543 422 <polygon fill="#ffffff" points="0,0 2.225,0 0,2.225"/> 544 423 <polygon fill="#ffffff" points="0,8.9 8.9,0 8.9,2.225 2.225,8.9"/> 545 - </pattern> 546 - <pattern height="18" id="pattern-hatched-45deg-white-9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,9,9" width="18"> 424 + </pattern><pattern height="18" id="pattern-hatched-45deg-white-9-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,9,9" width="18"> 547 425 <polygon fill="#ffffff" points="0,0 2.25,0 0,2.25"/> 548 426 <polygon fill="#ffffff" points="0,9 9,0 9,2.25 2.25,9"/> 549 - </pattern> 550 - <pattern height="18.2" id="pattern-hatched-45deg-white-9.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,9.1,9.1" width="18.2"> 427 + </pattern><pattern height="18.2" id="pattern-hatched-45deg-white-9.1-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,9.1,9.1" width="18.2"> 551 428 <polygon fill="#ffffff" points="0,0 2.275,0 0,2.275"/> 552 429 <polygon fill="#ffffff" points="0,9.1 9.1,0 9.1,2.275 2.275,9.1"/> 553 - </pattern> 554 - <pattern height="18.4" id="pattern-hatched-45deg-white-9.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,9.2,9.2" width="18.4"> 430 + </pattern><pattern height="18.4" id="pattern-hatched-45deg-white-9.2-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,9.2,9.2" width="18.4"> 555 431 <polygon fill="#ffffff" points="0,0 2.3,0 0,2.3"/> 556 432 <polygon fill="#ffffff" points="0,9.2 9.2,0 9.2,2.3 2.3,9.2"/> 557 - </pattern> 558 - <pattern height="18.6" id="pattern-hatched-45deg-white-9.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,9.3,9.3" width="18.6"> 433 + </pattern><pattern height="18.6" id="pattern-hatched-45deg-white-9.3-0.25" patternTransform="rotate(0)" patternUnits="userSpaceOnUse" viewBox="0,0,9.3,9.3" width="18.6"> 559 434 <polygon fill="#ffffff" points="0,0 2.325,0 0,2.325"/> 560 435 <polygon fill="#ffffff" points="0,9.3 9.3,0 9.3,2.325 2.325,9.3"/> 561 - </pattern> 562 - </defs> 563 - </svg> 436 + </pattern></defs></svg>
+11 -12
examples/specimen/src/snapshots/specimen__colors_shed.snap
··· 5 5 <svg height="150" viewBox="0 0 150 150" width="150" xmlns="http://www.w3.org/2000/svg"> 6 6 <rect fill="white" height="150" width="150" x="0" y="0"/> 7 7 <g class="layer" data-layer="root"> 8 - <rect data-object="root--anon-0" height="50" style="fill: blue;" width="50" x="0" y="0"/> 9 - <rect data-object="root--anon-1" height="50" style="fill: cyan;" width="50" x="50" y="0"/> 10 - <rect data-object="root--anon-2" height="50" style="fill: yellow;" width="50" x="100" y="0"/> 11 - <rect data-object="root--anon-3" height="50" style="fill: orange;" width="50" x="0" y="50"/> 12 - <rect data-object="root--anon-4" height="50" style="fill: red;" width="50" x="50" y="50"/> 13 - <rect data-object="root--anon-5" height="50" style="fill: brown;" width="50" x="100" y="50"/> 14 - <rect data-object="root--anon-6" height="50" style="fill: purple;" width="50" x="0" y="100"/> 15 - <rect data-object="root--anon-7" height="50" style="fill: pink;" width="50" x="50" y="100"/> 16 - <rect data-object="root--anon-8" height="50" style="fill: green;" width="50" x="100" y="100"/> 17 - </g> 18 - <g class="layer" data-layer="circles"/> 19 - <defs/> 8 + <rect data-object="root--anon-0" height="50" width="50" x="0" y="0" style="fill: blue;"/> 9 + <rect data-object="root--anon-1" height="50" width="50" x="50" y="0" style="fill: cyan;"/> 10 + <rect data-object="root--anon-2" height="50" width="50" x="100" y="0" style="fill: yellow;"/> 11 + <rect data-object="root--anon-3" height="50" width="50" x="0" y="50" style="fill: orange;"/> 12 + <rect data-object="root--anon-4" height="50" width="50" x="50" y="50" style="fill: red;"/> 13 + <rect data-object="root--anon-5" height="50" width="50" x="100" y="50" style="fill: brown;"/> 14 + <rect data-object="root--anon-6" height="50" width="50" x="0" y="100" style="fill: purple;"/> 15 + <rect data-object="root--anon-7" height="50" width="50" x="50" y="100" style="fill: pink;"/> 16 + <rect data-object="root--anon-8" height="50" width="50" x="100" y="100" style="fill: green;"/> 17 + </g><g class="layer" data-layer="circles"/> 18 + <defs /> 20 19 </svg>
+1 -2
examples/specimen/src/snapshots/specimen__grid.snap
··· 14 14 <circle cx="0" cy="100" data-object="root--anon-6" r="2" style="fill: black;"/> 15 15 <circle cx="50" cy="100" data-object="root--anon-7" r="2" style="fill: black;"/> 16 16 <circle cx="100" cy="100" data-object="root--anon-8" r="2" style="fill: black;"/> 17 - </g> 18 - <defs/> 17 + </g><defs /> 19 18 </svg>
+7 -8
examples/specimen/src/snapshots/specimen__shapes_shed.snap
··· 6 6 <rect fill="white" height="170" width="170" x="-10" y="-10"/> 7 7 <g class="layer" data-layer="root"> 8 8 <circle cx="25" cy="25" data-object="root--anon-0" r="25" style="fill: black;"/> 9 - <path d="M50,50 Q100,50,100,0" data-object="root--anon-1" stroke-width="5" style="stroke: black; fill: transparent;"/> 10 - <path d="M100,50 Q100,0,150,0" data-object="root--anon-2" stroke-width="5" style="stroke: black; fill: transparent;"/> 9 + <path d="M 50 50 Q 100 50 100 0" data-object="root--anon-1" stroke-width="5" style="stroke: black; fill: transparent;"/> 10 + <path d="M 100 50 Q 100 0 150 0" data-object="root--anon-2" stroke-width="5" style="stroke: black; fill: transparent;"/> 11 11 <circle cx="0" cy="50" data-object="root--anon-3" r="5" style="fill: black;"/> 12 - <line data-object="root--anon-4" stroke-width="5" style="stroke: black; fill: transparent;" x1="50" x2="100" y1="50" y2="100"/> 13 - <rect data-object="root--anon-5" height="50" style="fill: black;" width="50" x="0" y="100"/> 12 + <line data-object="root--anon-4" stroke-width="5" x1="50" x2="100" y1="50" y2="100" style="stroke: black; fill: transparent;"/> 13 + <rect data-object="root--anon-5" height="50" width="50" x="0" y="100" style="fill: black;"/> 14 14 <circle cx="100" cy="150" data-object="root--anon-6" r="2" style="fill: black;"/> 15 - <path d="M100,50 L150,50 L150,100 z" data-object="root--anon-7" style="fill: black;"/> 16 - <text data-object="root--anon-8" dominant-baseline="hanging" font-family="Inconsolata" font-size="5pt" style="fill: black;" x="0" y="0">test</text> 17 - </g> 18 - <defs/> 15 + <path d="M 100 50 L 150 50 L 150 100 Z" data-object="root--anon-7" style="fill: black;"/> 16 + <text data-object="root--anon-8" dominant-baseline="hanging" font-family="Inconsolata" font-size="5pt" text-anchor="start" x="0" y="0" style="fill: black;"> 17 + test</text></g><defs /> 19 18 </svg>
+44 -50
src/graphics/fill.rs
··· 1 - use crate::{Angle, Color, ColorMapping}; 1 + use crate::{rendering::svg, Angle, Color, ColorMapping}; 2 2 3 3 #[derive(Debug, Clone, Copy)] 4 4 pub enum Fill { ··· 78 78 pub fn pattern_definition( 79 79 &self, 80 80 colormapping: &ColorMapping, 81 - ) -> Option<svg::node::element::Pattern> { 81 + ) -> Option<svg::Node> { 82 82 match self { 83 83 Fill::Hatches(color, angle, size, thickness_ratio) => { 84 84 let thickness = size * (2.0 * thickness_ratio); 85 85 86 - let pattern = svg::node::element::Pattern::new() 87 - .set("id", self.pattern_id()) 88 - .set("patternUnits", "userSpaceOnUse") 89 - .set("height", size * 2.0) 90 - .set("width", size * 2.0) 91 - .set("viewBox", format!("0,0,{},{}", size, size)) 92 - .set( 86 + let pattern = svg::tag("pattern") 87 + .attr("id", self.pattern_id()) 88 + .attr("patternUnits", "userSpaceOnUse") 89 + .attr("height", size * 2.0) 90 + .attr("width", size * 2.0) 91 + .attr("viewBox", format!("0,0,{},{}", size, size)) 92 + .attr( 93 93 "patternTransform", 94 94 format!("rotate({})", (*angle - Angle(45.0)).degrees()), 95 95 ) 96 96 // https://stackoverflow.com/a/55104220/9943464 97 - .add( 98 - svg::node::element::Polygon::new() 99 - .set( 100 - "points", 101 - format!( 102 - "0,0 {},0 0,{}", 103 - thickness / 2.0, 104 - thickness / 2.0 105 - ), 106 - ) 107 - .set("fill", color.render(colormapping)), 108 - ) 109 - .add( 110 - svg::node::element::Polygon::new() 111 - .set( 112 - "points", 113 - format!( 114 - "0,{} {},0 {},{} {},{}", 115 - size, 116 - size, 117 - size, 118 - thickness / 2.0, 119 - thickness / 2.0, 120 - size, 121 - ), 122 - ) 123 - .set("fill", color.render(colormapping)), 124 - ); 97 + .wrapping(vec![ 98 + svg::tag("polygon").fill(*color, colormapping).attr( 99 + "points", 100 + format!( 101 + "0,0 {},0 0,{}", 102 + thickness / 2.0, 103 + thickness / 2.0 104 + ), 105 + ), 106 + svg::tag("polygon").fill(*color, colormapping).attr( 107 + "points", 108 + format!( 109 + "0,{} {},0 {},{} {},{}", 110 + size, 111 + size, 112 + size, 113 + thickness / 2.0, 114 + thickness / 2.0, 115 + size, 116 + ), 117 + ), 118 + ]) 119 + .node(); 125 120 126 121 Some(pattern) 127 122 } 128 123 Fill::Dotted(color, diameter, spacing) => { 129 124 let box_size = diameter + 2.0 * spacing; 130 - let pattern = svg::node::element::Pattern::new() 131 - .set("id", self.pattern_id()) 132 - .set("patternUnits", "userSpaceOnUse") 133 - .set("height", box_size) 134 - .set("width", box_size) 135 - .set("viewBox", format!("0,0,{},{}", box_size, box_size)) 136 - .add( 137 - svg::node::element::Circle::new() 138 - .set("cx", box_size / 2.0) 139 - .set("cy", box_size / 2.0) 140 - .set("r", diameter / 2.0) 141 - .set("fill", color.render(colormapping)), 142 - ); 125 + let pattern = svg::tag("pattern") 126 + .attr("id", self.pattern_id()) 127 + .attr("patternUnits", "userSpaceOnUse") 128 + .attr("height", box_size) 129 + .attr("width", box_size) 130 + .attr("viewBox", format!("0,0,{},{}", box_size, box_size)) 131 + .wrapping(vec![svg::tag("circle") 132 + .fill(*color, colormapping) 133 + .attr("cx", box_size / 2.0) 134 + .attr("cy", box_size / 2.0) 135 + .attr("r", diameter / 2.0)]) 136 + .node(); 143 137 144 138 Some(pattern) 145 139 }
+1 -1
src/graphics/objects.rs
··· 25 25 // FittedText(Region, String), 26 26 Rectangle(Point, Point), 27 27 Image(Region, String), 28 - RawSVG(svg::node::element::Element), 28 + RawSVG(String), 29 29 // Tiling(Region, Box<Object>), 30 30 } 31 31
+20 -18
src/rendering/canvas.rs
··· 1 1 use super::renderable::SVGRenderable; 2 - use crate::graphics::canvas::Canvas; 2 + use crate::{graphics::canvas::Canvas, rendering::svg}; 3 3 use measure_time::debug_time; 4 4 use resvg::usvg; 5 5 use std::sync::Arc; ··· 11 11 cell_size: usize, 12 12 object_sizes: crate::graphics::objects::ObjectSizes, 13 13 _id: &str, 14 - ) -> anyhow::Result<svg::node::element::Element> { 14 + ) -> anyhow::Result<svg::Node> { 15 15 debug_time!("render_to_svg/canvas"); 16 16 let background_color = self.background.unwrap_or_default(); 17 - let mut svg = svg::Document::new(); 18 - svg = svg.add( 19 - svg::node::element::Rectangle::new() 20 - .set("x", -(self.canvas_outter_padding as i32)) 21 - .set("y", -(self.canvas_outter_padding as i32)) 22 - .set("width", self.width()) 23 - .set("height", self.height()) 24 - .set("fill", background_color.render(&self.colormap)), 17 + let mut svg = svg::tag("svg").attr("xmlns", "http://www.w3.org/2000/svg"); 18 + 19 + svg.add( 20 + svg::tag("rect") 21 + .attr("x", -(self.canvas_outter_padding as i32)) 22 + .attr("y", -(self.canvas_outter_padding as i32)) 23 + .attr("width", self.width()) 24 + .attr("height", self.height()) 25 + .attr("fill", background_color.render(&self.colormap)), 25 26 ); 26 27 27 28 for layer in self.layers.iter().filter(|layer| !layer.hidden).rev() { 28 - svg = svg.add(layer.render_to_svg( 29 + svg.add(layer.render_to_svg( 29 30 colormap.clone(), 30 31 cell_size, 31 32 layer.object_sizes, ··· 33 34 )?); 34 35 } 35 36 36 - let mut defs = svg::node::element::Definitions::new(); 37 + let mut defs = svg::tag("defs"); 37 38 for filter in self.unique_filters() { 38 - defs = defs.add(filter.render_to_svg( 39 + defs.add(filter.render_to_svg( 39 40 colormap.clone(), 40 41 cell_size, 41 42 object_sizes, ··· 47 48 if let Some(patterndef) = 48 49 pattern_fill.pattern_definition(&self.colormap) 49 50 { 50 - defs = defs.add(patterndef) 51 + defs.add(patterndef); 51 52 } 52 53 } 53 54 55 + svg.add(defs); 56 + 54 57 Ok(svg 55 - .add(defs) 56 - .set( 58 + .attr( 57 59 "viewBox", 58 60 format!( 59 61 "{0} {0} {1} {2}", ··· 62 64 self.height() 63 65 ), 64 66 ) 65 - .set("width", self.width()) 66 - .set("height", self.height()) 67 + .attr("width", self.width()) 68 + .attr("height", self.height()) 67 69 .into()) 68 70 } 69 71 }
+30 -50
src/rendering/filter.rs
··· 2 2 3 3 use crate::{ColorMapping, Filter, FilterType}; 4 4 5 - use super::{renderable::SVGRenderable, CSSRenderable}; 5 + use super::{renderable::SVGRenderable, svg, CSSRenderable}; 6 6 7 7 impl SVGRenderable for Filter { 8 8 fn render_to_svg( ··· 11 11 _cell_size: usize, 12 12 _object_sizes: crate::graphics::objects::ObjectSizes, 13 13 _id: &str, 14 - ) -> anyhow::Result<svg::node::element::Element> { 14 + ) -> anyhow::Result<svg::Node> { 15 15 { 16 16 debug_time!("render_to_svg/filter"); 17 17 Ok(match self.kind { ··· 28 28 // "#, 29 29 // 2.5 30 30 // ) // TODO parameterize stdDeviation 31 - svg::node::element::Filter::new() 32 - .add( 33 - // TODO parameterize stdDeviation 34 - svg::node::element::FilterEffectGaussianBlur::new() 35 - .set("stdDeviation", self.parameter) 36 - .set("result", "coloredBlur"), 37 - ) 38 - .add( 39 - svg::node::element::FilterEffectMerge::new() 40 - .add( 41 - svg::node::element::FilterEffectMergeNode::new() 42 - .set("in", "coloredBlur"), 43 - ) 44 - .add( 45 - svg::node::element::FilterEffectMergeNode::new() 46 - .set("in", "SourceGraphic"), 47 - ), 48 - ) 31 + svg::tag("filter").wrapping(vec![ 32 + // TODO parameterize stdDeviation 33 + svg::tag("feGaussianBlur") 34 + .attr("stdDeviation", self.parameter) 35 + .attr("result", "coloredBlur"), 36 + svg::tag("feMerge").wrapping(vec![ 37 + svg::tag("feMergeNode").attr("in", "coloredBlur"), 38 + svg::tag("feMergeNode").attr("in", "SourceGraphic"), 39 + ]), 40 + ]) 49 41 } 50 42 FilterType::NaturalShadow => { 51 43 /* ··· 58 50 </feMerge> 59 51 </filter> 60 52 */ 61 - svg::node::element::Filter::new() 62 - .add( 63 - svg::node::element::FilterEffectOffset::new() 64 - .set("in", "SourceGraphic") 65 - .set("dx", self.parameter) 66 - .set("dy", self.parameter), 67 - ) 68 - .add( 69 - svg::node::element::FilterEffectGaussianBlur::new() 70 - .set("stdDeviation", self.parameter * 4.0) 71 - .set("result", "blur"), 72 - ) 73 - .add( 74 - svg::node::element::FilterEffectMerge::new() 75 - .add( 76 - svg::node::element::FilterEffectMergeNode::new() 77 - .set("in", "blur"), 78 - ) 79 - .add( 80 - svg::node::element::FilterEffectMergeNode::new() 81 - .set("in", "SourceGraphic"), 82 - ), 83 - ) 53 + svg::tag("filter").wrapping(vec![ 54 + svg::tag("feOffset") 55 + .attr("in", "SourceGraphic") 56 + .attr("dx", self.parameter) 57 + .attr("dy", self.parameter), 58 + svg::tag("feGaussianBlur") 59 + .attr("stdDeviation", self.parameter * 4.0) 60 + .attr("result", "blur"), 61 + svg::tag("feMerge").wrapping(vec![ 62 + svg::tag("feMergeNode").attr("in", "blur"), 63 + svg::tag("feMergeNode").attr("in", "SourceGraphic"), 64 + ]), 65 + ]) 84 66 } 85 67 FilterType::Saturation => { 86 68 /* ··· 88 70 <feColorMatrix type="saturate" values="0.5"/> 89 71 </filter> 90 72 */ 91 - svg::node::element::Filter::new().add( 92 - svg::node::element::FilterEffectColorMatrix::new() 93 - .set("type", "saturate") 94 - .set("values", self.parameter), 95 - ) 73 + svg::tag("filter").wrapping(vec![svg::tag("feColorMatrix") 74 + .attr("type", "saturate") 75 + .attr("values", self.parameter)]) 96 76 } 97 77 } 98 - .set("id", self.id()) 99 - .set("filterUnit", "userSpaceOnUse") 78 + .attr("id", self.id()) 79 + .attr("filterUnit", "userSpaceOnUse") 100 80 .into()) 101 81 } 102 82 }
+8 -13
src/rendering/layer.rs
··· 1 1 use itertools::Itertools; 2 2 use measure_time::debug_time; 3 3 4 - use super::renderable::SVGRenderable; 4 + use super::{renderable::SVGRenderable, svg}; 5 5 use crate::Layer; 6 6 7 7 impl SVGRenderable for Layer { ··· 11 11 cell_size: usize, 12 12 object_sizes: crate::graphics::objects::ObjectSizes, 13 13 id: &str, 14 - ) -> anyhow::Result<svg::node::element::Element> { 14 + ) -> anyhow::Result<svg::Node> { 15 15 debug_time!("render_to_svg/layer"); 16 - let mut layer_group = svg::node::element::Group::new() 17 - .set("class", "layer") 18 - .set("data-layer", self.name.clone()); 19 - 20 - for (object_id, obj) in 21 - self.objects.iter().sorted_by_key(|(oid, _)| (*oid).clone()) 22 - { 23 - layer_group = layer_group.add(obj.render_to_svg( 16 + let mut group = svg::tag("g").class("layer").dataset("layer", &self.name); 17 + for (object_id, object) in 18 + self.objects.iter().sorted_by_key(|(oid, _)| (*oid).clone()) { 19 + group.add(object.render_to_svg( 24 20 colormap.clone(), 25 21 cell_size, 26 22 object_sizes, 27 - &[id, object_id].join("--"), 23 + &format!("{}--{}", id, object_id), 28 24 )?); 29 25 } 30 - 31 - Ok(layer_group.into()) 26 + Ok(group.into()) 32 27 } 33 28 }
+2 -1
src/rendering/mod.rs
··· 1 1 pub mod canvas; 2 + pub mod svg; 2 3 pub mod fill; 3 4 pub mod filter; 4 5 pub mod fonts; ··· 10 11 use measure_time::debug_time; 11 12 pub use renderable::{CSSRenderable, SVGAttributesRenderable, SVGRenderable}; 12 13 13 - pub fn stringify_svg(element: svg::node::element::Element) -> String { 14 + pub fn stringify_svg(element: svg::Node) -> String { 14 15 debug_time!("stringify_svg"); 15 16 16 17 return element.to_string();
+119 -132
src/rendering/objects.rs
··· 6 6 ColoredObject, Object, 7 7 }; 8 8 9 - use super::{renderable::SVGRenderable, CSSRenderable, SVGAttributesRenderable}; 9 + use super::{ 10 + renderable::SVGRenderable, svg, CSSRenderable, SVGAttributesRenderable, 11 + }; 10 12 11 13 impl SVGRenderable for ColoredObject { 12 14 fn render_to_svg( ··· 15 17 cell_size: usize, 16 18 object_sizes: crate::graphics::objects::ObjectSizes, 17 19 id: &str, 18 - ) -> anyhow::Result<svg::node::element::Element> { 20 + ) -> anyhow::Result<svg::Node> { 19 21 debug_time!("render_to_svg/colored_object"); 20 - let mut obj = self.object.render_to_svg( 22 + let plain_obj = self.object.render_to_svg( 21 23 colormap.clone(), 22 24 cell_size, 23 25 object_sizes, 24 26 id, 25 27 )?; 26 28 27 - let mut css = String::new(); 28 - if !matches!(self.object, Object::RawSVG(..)) { 29 - css = self 30 - .fill 31 - .render_to_css(&colormap.clone(), !self.object.fillable()); 32 - } 29 + let mut css = self 30 + .fill 31 + .render_to_css(&colormap.clone(), !self.object.fillable()); 33 32 34 33 if !self.transformations.is_empty() || !self.filters.is_empty() { 35 - obj = svg::node::element::Group::new() 36 - .set("data-object", id) 37 - .add(obj) 38 - .into(); 39 - 40 - let attributes = obj.get_attributes_mut(); 41 - 42 - for (key, value) in self.transformations.render_to_svg_attributes( 43 - colormap.clone(), 44 - cell_size, 45 - object_sizes, 46 - id, 47 - )? { 48 - attributes.insert(key, value.into()); 49 - } 50 - 51 34 let start = self.object.region().start.coords(cell_size); 52 35 let (w, h) = ( 53 36 self.object.region().width() * cell_size, 54 37 self.object.region().height() * cell_size, 55 38 ); 56 39 57 - attributes.insert( 58 - "transform-origin".to_string(), 59 - format!( 60 - "{} {}", 61 - start.0 + (w as f32 / 2.0), 62 - start.1 + (h as f32 / 2.0) 63 - ) 64 - .into(), 65 - ); 66 - 67 40 css += "transform-box: fill-box;"; 68 41 69 42 css += self ··· 72 45 .map(|f| f.render_to_css_filled(&colormap)) 73 46 .join(" ") 74 47 .as_ref(); 75 - } 76 48 77 - obj.get_attributes_mut().insert("style".into(), css.into()); 78 - 79 - Ok(obj) 49 + Ok(svg::tag("g") 50 + .dataset("object", id) 51 + .attr( 52 + "transform-origin", 53 + &format!( 54 + "{} {}", 55 + start.0 + (w as f32 / 2.0), 56 + start.1 + (h as f32 / 2.0) 57 + ), 58 + ) 59 + .with_attributes(self.transformations.render_to_svg_attributes( 60 + colormap, 61 + cell_size, 62 + object_sizes, 63 + id, 64 + )?) 65 + .wrapping(vec![plain_obj]) 66 + .attr("style", &css) 67 + .into()) 68 + } else { 69 + Ok(match plain_obj { 70 + svg::Node::Element(el) => el.attr("style", &css).into(), 71 + _ => plain_obj, 72 + }) 73 + } 80 74 } 81 75 } 82 76 ··· 87 81 cell_size: usize, 88 82 object_sizes: crate::graphics::objects::ObjectSizes, 89 83 id: &str, 90 - ) -> anyhow::Result<svg::node::element::Element> { 84 + ) -> anyhow::Result<svg::Node> { 91 85 debug_time!("render_to_svg/object"); 92 - let mut rendered = match self { 86 + let rendered = match self { 93 87 Object::Text(..) | Object::CenteredText(..) => { 94 88 self.render_text(cell_size) 95 89 } ··· 108 102 Object::RawSVG(..) => self.render_raw_svg(), 109 103 }; 110 104 111 - // Ok(group.set("data-object", id).add(rendered).into()) 112 - rendered 113 - .get_attributes_mut() 114 - .insert("data-object".into(), id.into()); 115 - Ok(rendered) 105 + Ok(match rendered { 106 + svg::Node::Element(el) => el.dataset("object", id).into(), 107 + svg::Node::SVG(svg) => { 108 + if svg.trim().starts_with("<") { 109 + let (before, after) = 110 + svg.split_once(' ').unwrap_or(svg.split_once(">").expect("Malformed SVG tag, {svg} starts with < but doesn't contain a space or >")); 111 + svg::Node::SVG(format!( 112 + r#"{before} data-object="{id}" {after}"# 113 + )) 114 + } else { 115 + eprintln!("Malformed raw SVG, {svg} doesn't start with <"); 116 + svg::Node::SVG(svg) 117 + } 118 + } 119 + _ => { 120 + panic!("Expected Element or SVG, got {:?}", rendered); 121 + } 122 + }) 116 123 } 117 124 } 118 125 119 126 impl Object { 120 - fn render_image(&self, cell_size: usize) -> svg::node::element::Element { 127 + fn render_image(&self, cell_size: usize) -> svg::Node { 121 128 if let Object::Image(region, path) = self { 122 - let (x, y) = region.start.coords(cell_size); 123 - return svg::node::element::Image::new() 124 - .set("x", x) 125 - .set("y", y) 126 - .set("width", region.width() * cell_size) 127 - .set("height", region.height() * cell_size) 128 - .set("href", path.clone()) 129 + return svg::tag("image") 130 + .coords(region.start.coords(cell_size)) 131 + .attr("width", region.width() * cell_size) 132 + .attr("height", region.height() * cell_size) 133 + .attr("href", path.clone()) 129 134 .into(); 130 135 } 131 136 132 137 panic!("Expected Image, got {:?}", self); 133 138 } 134 139 135 - fn render_raw_svg(&self) -> svg::node::element::Element { 140 + fn render_raw_svg(&self) -> svg::Node { 136 141 if let Object::RawSVG(svg) = self { 137 - return svg.clone(); 142 + return svg::Node::SVG(svg.clone()); 138 143 } 139 144 140 145 panic!("Expected RawSVG, got {:?}", self); 141 146 } 142 147 143 - fn render_text(&self, cell_size: usize) -> svg::node::element::Element { 144 - if let Object::Text(position, content, font_size) 145 - | Object::CenteredText(position, content, font_size) = self 146 - { 147 - let centered = matches!(self, Object::CenteredText(..)); 148 + fn render_text(&self, cell_size: usize) -> svg::Node { 149 + match self { 150 + Object::Text(position, content, font_size) 151 + | Object::CenteredText(position, content, font_size) => { 152 + let centered = matches!(self, Object::CenteredText(..)); 148 153 149 - let coords = if centered { 150 - position.center_coords(cell_size) 151 - } else { 152 - position.coords(cell_size) 153 - }; 154 - 155 - let mut node = svg::node::element::Text::new(content.clone()) 156 - .set("x", coords.0) 157 - .set("y", coords.1) 158 - .set("font-size", format!("{}pt", font_size)) 159 - .set("font-family", "Inconsolata"); 160 - 161 - if centered { 162 - node = node 163 - .set("text-anchor", "middle") 164 - // FIXME does not work with imagemagick 165 - .set("dominant-baseline", "middle"); 166 - } else { 167 - // FIXME does not work with imagemagick 168 - // see https://legacy.imagemagick.org/discourse-server/viewtopic.php?t=31540 169 - node = node.set("dominant-baseline", "hanging") 154 + svg::tag("text") 155 + .coords(if centered { 156 + position.center_coords(cell_size) 157 + } else { 158 + position.coords(cell_size) 159 + }) 160 + .attr("font-size", format!("{}pt", font_size)) 161 + .attr("font-family", "Inconsolata") 162 + .attr( 163 + "dominant-baseline", 164 + if centered { "middle" } else { "hanging" }, 165 + ) 166 + .attr( 167 + "text-anchor", 168 + if centered { "middle" } else { "start" }, 169 + ) 170 + .wrapping(vec![svg::Node::Text(content.to_string())]) 171 + .into() 170 172 } 171 - 172 - return node.into(); 173 + _ => panic!("Expected Text, got {:?}", self), 173 174 } 174 - 175 - panic!("Expected Text, got {:?}", self); 176 175 } 177 176 178 - // fn render_fitted_text(&self, cell_size: usize) -> svg::node::element::Element { 177 + // fn render_fitted_text(&self, cell_size: usize) -> svg::Node { 179 178 // if let Object::FittedText(region, content) = self { 180 179 // let (x, y) = region.start.coords(cell_size); 181 180 // let width = region.width() * cell_size as f32; ··· 194 193 // panic!("Expected FittedText, got {:?}", self); 195 194 // } 196 195 197 - fn render_rectangle(&self, cell_size: usize) -> svg::node::element::Element { 196 + fn render_rectangle(&self, cell_size: usize) -> svg::Node { 198 197 if let Object::Rectangle(start, end) = self { 199 - return svg::node::element::Rectangle::new() 200 - .set("x", start.coords(cell_size).0) 201 - .set("y", start.coords(cell_size).1) 202 - .set("width", start.distances(end).0 * cell_size) 203 - .set("height", start.distances(end).1 * cell_size) 204 - .into(); 198 + return svg::tag("rect").region((start, end), cell_size).into(); 205 199 } 206 200 207 201 panic!("Expected Rectangle, got {:?}", self); 208 202 } 209 203 210 - fn render_polygon(&self, cell_size: usize) -> svg::node::element::Element { 204 + fn render_polygon(&self, cell_size: usize) -> svg::Node { 211 205 if let Object::Polygon(start, lines) = self { 212 - let mut path = svg::node::element::path::Data::new(); 213 - path = path.move_to(start.coords(cell_size)); 206 + let mut path = svg::Path::new(); 207 + path.move_to(*start, cell_size); 214 208 for line in lines { 215 - path = match line { 209 + match line { 216 210 LineSegment::Straight(end) 217 211 | LineSegment::InwardCurve(end) 218 212 | LineSegment::OutwardCurve(end) => { 219 - path.line_to(end.coords(cell_size)) 213 + path.line_to(*end, cell_size); 220 214 } 221 215 }; 222 216 } 223 - path = path.close(); 224 - return svg::node::element::Path::new().set("d", path).into(); 217 + path.close(); 218 + return path.node(); 225 219 } 226 220 227 221 panic!("Expected Polygon, got {:?}", self); 228 222 } 229 223 230 - fn render_line(&self, cell_size: usize) -> svg::node::element::Element { 224 + fn render_line(&self, cell_size: usize) -> svg::Node { 231 225 if let Object::Line(start, end, width) = self { 232 - return svg::node::element::Line::new() 233 - .set("x1", start.coords(cell_size).0) 234 - .set("y1", start.coords(cell_size).1) 235 - .set("x2", end.coords(cell_size).0) 236 - .set("y2", end.coords(cell_size).1) 237 - .set("stroke-width", *width) 226 + return svg::tag("line") 227 + .position_pair(*start, *end, cell_size) 228 + .attr("stroke-width", *width) 238 229 .into(); 239 230 } 240 231 241 232 panic!("Expected Line, got {:?}", self); 242 233 } 243 234 244 - fn render_curve(&self, cell_size: usize) -> svg::node::element::Element { 235 + fn render_curve(&self, cell_size: usize) -> svg::Node { 245 236 if let Object::CurveOutward(start, end, stroke_width) 246 237 | Object::CurveInward(start, end, stroke_width) = self 247 238 { ··· 309 300 } 310 301 }; 311 302 312 - return svg::node::element::Path::new() 313 - .set( 314 - "d", 315 - svg::node::element::path::Data::new() 316 - .move_to(start.coords(cell_size)) 317 - .quadratic_curve_to((control, end.coords(cell_size))), 318 - ) 319 - .set("stroke-width", format!("{stroke_width}")) 303 + let mut path = svg::Path::new(); 304 + path.move_to(*start, cell_size); 305 + path.quadratic_curve_to(control, *end, cell_size); 306 + return path 307 + .element() 308 + .attr("stroke-width", format!("{stroke_width}")) 320 309 .into(); 321 310 } 322 311 ··· 327 316 &self, 328 317 cell_size: usize, 329 318 object_sizes: ObjectSizes, 330 - ) -> svg::node::element::Element { 319 + ) -> svg::Node { 331 320 if let Object::SmallCircle(center) = self { 332 - return svg::node::element::Circle::new() 333 - .set("cx", center.coords(cell_size).0) 334 - .set("cy", center.coords(cell_size).1) 335 - .set("r", object_sizes.small_circle_radius) 321 + return svg::tag("circle") 322 + .center_position(*center, cell_size) 323 + .attr("r", object_sizes.small_circle_radius) 336 324 .into(); 337 325 } 338 326 ··· 343 331 &self, 344 332 cell_size: usize, 345 333 object_sizes: ObjectSizes, 346 - ) -> svg::node::element::Element { 334 + ) -> svg::Node { 347 335 if let Object::Dot(center) = self { 348 - return svg::node::element::Circle::new() 349 - .set("cx", center.coords(cell_size).0) 350 - .set("cy", center.coords(cell_size).1) 351 - .set("r", object_sizes.dot_radius) 336 + return svg::tag("circle") 337 + .center_position(*center, cell_size) 338 + .attr("r", object_sizes.dot_radius) 352 339 .into(); 353 340 } 354 341 355 342 panic!("Expected Dot, got {:?}", self); 356 343 } 357 344 358 - fn render_big_circle(&self, cell_size: usize) -> svg::node::element::Element { 345 + fn render_big_circle(&self, cell_size: usize) -> svg::Node { 359 346 if let Object::BigCircle(topleft) = self { 360 347 let (cx, cy) = { 361 348 let (x, y) = topleft.coords(cell_size); 362 349 (x + cell_size as f32 / 2.0, y + cell_size as f32 / 2.0) 363 350 }; 364 351 365 - return svg::node::element::Circle::new() 366 - .set("cx", cx) 367 - .set("cy", cy) 368 - .set("r", cell_size / 2) 352 + return svg::tag("circle") 353 + .attr("cx", cx) 354 + .attr("cy", cy) 355 + .attr("r", cell_size / 2) 369 356 .into(); 370 357 } 371 358
+2 -1
src/rendering/renderable.rs
··· 1 + use super::svg; 1 2 use crate::{graphics::objects::ObjectSizes, ColorMapping}; 2 3 use anyhow::Result; 3 4 use itertools::Itertools; ··· 11 12 cell_size: usize, 12 13 object_sizes: ObjectSizes, 13 14 id: &str, 14 - ) -> Result<svg::node::element::Element>; 15 + ) -> Result<svg::Node>; 15 16 } 16 17 17 18 /// Struct can be rendered as attributes of a SVG element
+343
src/rendering/svg.rs
··· 1 + use std::{collections::HashMap, fmt::Display}; 2 + 3 + use itertools::Itertools; 4 + 5 + use crate::{Color, ColorMapping, Point, Region}; 6 + 7 + #[derive(Debug, Clone)] 8 + pub struct Element { 9 + pub tag: String, 10 + pub attributes: HashMap<String, String>, 11 + pub styles: HashMap<String, String>, 12 + pub children: Vec<Node>, 13 + } 14 + 15 + #[derive(Debug, Clone)] 16 + pub enum Node { 17 + Element(Element), 18 + Text(String), 19 + SVG(String), 20 + } 21 + 22 + impl Into<Node> for Element { 23 + fn into(self) -> Node { 24 + self.node() 25 + } 26 + } 27 + 28 + pub fn tag(tag: &str) -> Element { 29 + Element::new(tag) 30 + } 31 + 32 + impl Element { 33 + pub fn node(self) -> Node { 34 + Node::Element(self) 35 + } 36 + 37 + pub fn new(tag: &str) -> Self { 38 + Element { 39 + tag: tag.to_string(), 40 + attributes: HashMap::new(), 41 + styles: HashMap::new(), 42 + children: Vec::new(), 43 + } 44 + } 45 + 46 + pub fn attr(self, key: &str, value: impl Display) -> Self { 47 + // assert!( 48 + // key != "style", 49 + // "Use `style` method instead of `attr` for style attributes." 50 + // ); 51 + let mut attributes = self.attributes.clone(); 52 + attributes.insert(key.to_string(), value.to_string()); 53 + Element { attributes, ..self } 54 + } 55 + 56 + /// Sets x and y 57 + pub fn coords(self, p: impl Into<(f32, f32)>) -> Self { 58 + let (x, y) = p.into(); 59 + self.attr("x", x).attr("y", y) 60 + } 61 + 62 + pub fn fill(self, c: Color, colormap: &ColorMapping) -> Self { 63 + self.attr("fill", c.render(colormap)) 64 + } 65 + 66 + /// Sets cx and cy 67 + pub fn center_position(self, p: impl Into<Point>, cell_size: usize) -> Self { 68 + let (x, y) = p.into().coords(cell_size); 69 + self.attr("cx", x).attr("cy", y) 70 + } 71 + 72 + /// Sets x1, y1 and x2, y2 73 + pub fn position_pair( 74 + self, 75 + p1: impl Into<Point>, 76 + p2: impl Into<Point>, 77 + cell_size: usize, 78 + ) -> Self { 79 + let (x1, y1) = p1.into().coords(cell_size); 80 + let (x2, y2) = p2.into().coords(cell_size); 81 + self.attr("x1", x1) 82 + .attr("y1", y1) 83 + .attr("x2", x2) 84 + .attr("y2", y2) 85 + } 86 + 87 + /// Sets x and y 88 + pub fn position(self, p: impl Into<Point>, cell_size: usize) -> Self { 89 + self.coords(p.into().coords(cell_size)) 90 + } 91 + 92 + /// Sets width and height 93 + pub fn dimensions(self, p: impl Into<(usize, usize)>) -> Self { 94 + let (w, h) = p.into(); 95 + self.attr("width", w).attr("height", h) 96 + } 97 + 98 + /// Sets width and height 99 + pub fn size(self, r: impl Into<Region>, cell_size: usize) -> Self { 100 + self.dimensions(r.into().size(cell_size)) 101 + } 102 + 103 + /// Sets x, y, width and height according to the region 104 + pub fn region(self, r: impl Into<Region>, cell_size: usize) -> Self { 105 + let region: Region = r.into(); 106 + self.position(region.start, cell_size) 107 + .size(region, cell_size) 108 + } 109 + 110 + pub fn style(self, key: &str, value: &str) -> Self { 111 + let mut styles = self.styles.clone(); 112 + styles.insert(key.to_string(), value.to_string()); 113 + Element { styles, ..self } 114 + } 115 + 116 + pub fn dataset(self, key: &str, value: &str) -> Self { 117 + let mut attributes = self.attributes.clone(); 118 + attributes.insert(format!("data-{key}"), value.to_string()); 119 + Element { attributes, ..self } 120 + } 121 + 122 + pub fn class(self, class: &str) -> Self { 123 + self.attr("class", class) 124 + } 125 + 126 + pub fn add(&mut self, child: impl Into<Node>) -> &mut Self { 127 + self.children.push(child.into()); 128 + self 129 + } 130 + 131 + pub fn with_attributes(self, attributes: HashMap<String, String>) -> Self { 132 + Element { attributes, ..self } 133 + } 134 + 135 + pub fn wrapping( 136 + self, 137 + children: impl IntoIterator<Item = impl Into<Node>>, 138 + ) -> Self { 139 + Element { 140 + children: children.into_iter().map(|n| n.into()).collect(), 141 + ..self 142 + } 143 + } 144 + 145 + pub fn wrap(self, tag: &str, attrs: HashMap<String, String>) -> Self { 146 + Element { 147 + tag: tag.to_string(), 148 + styles: HashMap::new(), 149 + attributes: attrs, 150 + children: vec![Node::Element(self)], 151 + } 152 + } 153 + } 154 + 155 + pub enum PathInstruction { 156 + MoveTo((f32, f32)), 157 + LineTo((f32, f32)), 158 + HorizontalLineTo(f32), 159 + VerticalLineTo(f32), 160 + CurveTo((f32, f32), (f32, f32), (f32, f32)), 161 + SmoothCurveTo((f32, f32), (f32, f32)), 162 + QuadraticCurveTo((f32, f32), (f32, f32)), 163 + SmoothQuadraticCurveTo((f32, f32)), 164 + ArcTo((f32, f32), f32, bool, bool, (f32, f32)), 165 + ClosePath, 166 + } 167 + 168 + pub struct Path(Vec<PathInstruction>); 169 + 170 + impl Path { 171 + pub fn new() -> Self { 172 + Path(Vec::new()) 173 + } 174 + 175 + pub fn node(self) -> Node { 176 + self.element().node() 177 + } 178 + 179 + pub fn element(self) -> Element { 180 + tag("path").attr("d", self.to_string()) 181 + } 182 + 183 + pub fn move_to( 184 + &mut self, 185 + p: impl Into<Point>, 186 + cell_size: usize, 187 + ) -> &mut Self { 188 + self.0 189 + .push(PathInstruction::MoveTo(p.into().coords(cell_size))); 190 + self 191 + } 192 + 193 + pub fn line_to( 194 + &mut self, 195 + p: impl Into<Point>, 196 + cell_size: usize, 197 + ) -> &mut Self { 198 + self.0 199 + .push(PathInstruction::LineTo(p.into().coords(cell_size))); 200 + self 201 + } 202 + 203 + pub fn quadratic_curve_to( 204 + &mut self, 205 + control: impl Into<(f32, f32)>, 206 + end: impl Into<Point>, 207 + cell_size: usize, 208 + ) -> &mut Self { 209 + self.0.push(PathInstruction::QuadraticCurveTo( 210 + control.into(), 211 + end.into().coords(cell_size), 212 + )); 213 + self 214 + } 215 + 216 + pub fn close(&mut self) -> &mut Self { 217 + self.0.push(PathInstruction::ClosePath); 218 + self 219 + } 220 + } 221 + 222 + impl Display for Path { 223 + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 224 + f.write_str( 225 + &self 226 + .0 227 + .iter() 228 + .map(|i| i.to_string()) 229 + .collect::<Vec<_>>() 230 + .join(" "), 231 + ) 232 + } 233 + } 234 + 235 + impl Display for PathInstruction { 236 + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 237 + match self { 238 + Self::MoveTo((x, y)) => write!(f, "M {} {}", x, y), 239 + Self::LineTo((x, y)) => write!(f, "L {} {}", x, y), 240 + Self::HorizontalLineTo(x) => write!(f, "H {}", x), 241 + Self::VerticalLineTo(y) => write!(f, "V {}", y), 242 + Self::CurveTo((x1, y1), (x2, y2), (x3, y3)) => { 243 + write!(f, "C {} {} {} {} {} {}", x1, y1, x2, y2, x3, y3) 244 + } 245 + Self::SmoothCurveTo((x2, y2), (x3, y3)) => { 246 + write!(f, "S {} {} {} {}", x2, y2, x3, y3) 247 + } 248 + Self::QuadraticCurveTo((x1, y1), (x2, y2)) => { 249 + write!(f, "Q {} {} {} {}", x1, y1, x2, y2) 250 + } 251 + Self::SmoothQuadraticCurveTo((x2, y2)) => { 252 + write!(f, "T {} {}", x2, y2) 253 + } 254 + Self::ArcTo( 255 + (rx, ry), 256 + angle, 257 + large_arc_flag, 258 + sweep_flag, 259 + (x2, y2), 260 + ) => { 261 + write!( 262 + f, 263 + "A {rx} {ry} {angle} {large_arc_flag} {sweep_flag} {x2} {y2}" 264 + ) 265 + } 266 + Self::ClosePath => write!(f, "Z"), 267 + } 268 + } 269 + } 270 + 271 + fn space_if(add_space: bool) -> &'static str { 272 + if add_space { 273 + " " 274 + } else { 275 + "" 276 + } 277 + } 278 + 279 + impl Display for Node { 280 + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 281 + match self { 282 + Node::Text(text) => write!(f, "{}", quick_xml::escape::escape(text)), 283 + Node::SVG(svg) => write!(f, "{}", svg), 284 + Node::Element(Element { 285 + tag, 286 + attributes, 287 + styles, 288 + children, 289 + }) => { 290 + write!(f, "<{tag} ")?; 291 + 292 + let non_style_attributes: Vec<_> = attributes 293 + .iter() 294 + .filter(|(k, _)| *k != "style") 295 + .sorted_by_key(|(k, _)| *k) 296 + .collect(); 297 + 298 + for (i, (key, value)) in non_style_attributes.iter().enumerate() { 299 + write!( 300 + f, 301 + r#"{spacing}{key}="{value}""#, 302 + spacing = space_if(i > 0), 303 + key = key, 304 + value = value 305 + .replace("&", "&amp;") 306 + .replace('"', "&quot;") 307 + .replace("'", "&apos;") 308 + )?; 309 + } 310 + 311 + if attributes.contains_key("style") || !styles.is_empty() { 312 + write!( 313 + f, 314 + r#"{spacing}style="{value}""#, 315 + spacing = space_if(non_style_attributes.len() > 0), 316 + value = styles 317 + .iter() 318 + .map(|(k, v)| format!("{k}: {v};")) 319 + .chain::<Option<String>>( 320 + attributes.get("style").map(|s| s.to_string()), 321 + ) 322 + .collect::<Vec<_>>() 323 + .join(" ") 324 + )?; 325 + } 326 + 327 + if children.is_empty() { 328 + write!(f, "/>\n")?; 329 + } else { 330 + write!(f, ">\n")?; 331 + 332 + for child in children { 333 + write!(f, "{}", child)?; 334 + } 335 + 336 + write!(f, "</{tag}>")?; 337 + } 338 + 339 + Ok(()) 340 + } 341 + } 342 + } 343 + }