diff options
| author | Ruben Beltran del Rio <jj@r.bdr.sh> | 2025-12-13 01:17:52 +0100 |
|---|---|---|
| committer | Ruben Beltran del Rio <jj@r.bdr.sh> | 2025-12-14 09:15:07 +0100 |
| commit | 03f1a7389afeadf9aa2b1d62a38e5cb0a2a7e60d (patch) | |
| tree | 2efefc34a61c62d55d8436180acfc3590287f5fd | |
Initial implementation
38 files changed, 4527 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0023a53 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.DS_Store +/.build +/Packages +xcuserdata/ +DerivedData/ +.swiftpm/configuration/registries.json +.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +.netrc diff --git a/Benchmarks/ParseBenchmarkTarget/ParseBenchmarkTarget.swift b/Benchmarks/ParseBenchmarkTarget/ParseBenchmarkTarget.swift new file mode 100644 index 0000000..c99814f --- /dev/null +++ b/Benchmarks/ParseBenchmarkTarget/ParseBenchmarkTarget.swift @@ -0,0 +1,48 @@ +import Benchmark +import Foundation +import WmapParser + +let benchmarks: @Sendable () -> Benchmark? = { + // Load the wmap files from Documentation directory + let fileManager = FileManager.default + let currentDirectory = fileManager.currentDirectoryPath + let documentationPath = (currentDirectory as NSString).appendingPathComponent("Documentation") + + let examplePath = (documentationPath as NSString).appendingPathComponent("example.wmap") + let hugePath = (documentationPath as NSString).appendingPathComponent("huge.wmap") + + let exampleSource: String + let hugeSource: String + + do { + exampleSource = try String(contentsOfFile: examplePath, encoding: .utf8) + } catch { + print("Current directory: \(currentDirectory)") + print("Failed to load example.wmap from: \(examplePath)") + print("Error: \(error)") + fatalError("Failed to load example.wmap") + } + + do { + hugeSource = try String(contentsOfFile: hugePath, encoding: .utf8) + } catch { + print("Failed to load huge.wmap from: \(hugePath)") + print("Error: \(error)") + fatalError("Failed to load huge.wmap") + } + + Benchmark.defaultConfiguration.maxDuration = .seconds(3) + Benchmark.defaultConfiguration.maxIterations = 500 + + Benchmark("parse example") { benchmark in + for _ in benchmark.scaledIterations { + blackHole(parse(exampleSource)) + } + } + + return Benchmark("parse huge") { benchmark in + for _ in benchmark.scaledIterations { + blackHole(parse(hugeSource)) + } + } +} diff --git a/Documentation/example.wmap b/Documentation/example.wmap new file mode 100644 index 0000000..a238ab1 --- /dev/null +++ b/Documentation/example.wmap @@ -0,0 +1,122 @@ +Anchor (40, 0) +Tinker (4,30) [x] +Tailor (7.03, 49.21) [Square] +Soldier (28, 15) [Triangle] +AMnchor (28.22, 45.27) +Tonker (67.3, 4.4) [X] +Tailor1 (1,1) [Square] +Tailor2 (10,1) [Square] +Tailor3 (1,10) [Square] +Tailor4 (20,1) [Square] +Tailor5 (1,20) [Square] +Tailor7 (20,10) [Square] +Tailor8 (9.36, 16.97) [Square] +Tailor777(30,10) [Square] +Tailor10 (18.77, 26.25) [Square] +Tailor11 (10,10) [Square] +Tailor12 (30,20) +Tailor13 (31.10, 28.89) +Tailor14 (13.44, 21.48) [Square] +Tailor19 (45, 2) [triangle] +B (50, 50) +Hellele + +TailorX (20, 50) [Square] + +Hello World (90, 20) [x] + +Anchor -> Soldier… this is changing. +Anchor -> A +Masdlajksd -- Tailor13 + +Mabanchorn -- Anchornalsdjalks + +A +--B + +X (58.52, 27.07) + +Tailor11--Tailor12 +Tailor12--Tailor13 +Tailor777--Tailor8 +Tailor777--Tailor7 +Tailor777--Tailor6 +Tailor7-Tailor6 + +Tinker -- Tailor +Soldier -- Tinker + +[Evolution] Tinker +20 +[Inertia] Soldier + +[i] 15 +[ii] 35 +[iii] 80 + +this is kind of ok … a little bit better to be honest. (69.76, 89.84) + +OK. + +This map so far is fst. asdasd asda + +Holy shit, this is still indeed fast. But everything flashes as I type! This is now happening so fast + +Hello my old friend. + +OK so this map should eventually start getting slow too! + +let’s see how long after.asd asda sda + +asda sdasdasd asdasdasdasdasdasd +OK… Well we are typing. asd as asd as dasd a asdasda sdasd asd + + asd asd asd asdasd asdasd +Alright, the whole text is still fa asdlashing. Wow. This is pretty bad. +aas dasd adsa sd a asd asd asdjlkasjd laksdjasd basldjas!!! + +we have deleted this (20, 40) [triangle] + +a(12, 12) +Time to see if we get the same performance loss as withthis the other one. Well I will continue. Hello this is me. and i’m +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +b(75,75) +c(9, 90) + +a -- b +b -- c + +d (45, 88) + +c -- d +d -- a +d -- b + +q (90, 60) +b -- q +q -- a +q -- c + +[Evolution] c +20 +[Evolution] d +10 +[Evolution] a -20 +[Evolution] q +5 + +m(50, 60) +n (65, 65) +o (45, 63) + +m -- o +o -- n +n -- m +o -- c +n -- q +m -- d + +testasd asdas +test2asdasa asdasd asd + +[Note] (5, 35) Notes also influence the placement of\n labels. + +[Group] Tailor2, Tailor7, Tailor11, Tailor12, Tailor10, Anchor, Tinker +[Group] Tailor3, Tailor5, Tailor14pr
\ No newline at end of file diff --git a/Documentation/huge.wmap b/Documentation/huge.wmap new file mode 100644 index 0000000..c58f8c3 --- /dev/null +++ b/Documentation/huge.wmap @@ -0,0 +1,1960 @@ +[I] 0.25 +[II] 0.5 +[III] 0.75 +[IV] 1.0 + +Component0 (9.95, 32.86) [X] +Component1 (61.12, 59.35) +Component2 (27.46, 61.14) +Component3 (22.90, 50.28) [Circle] +Component4 (8.84, 45.75) [Square] +Component5 (34.22, 13.13) [Circle] +Component6 (53.14, 32.02) [X] +Component7 (88.66, 94.82) +Component8 (26.58, 14.30) [Square] +Component9 (87.07, 57.55) [X] +Component10 (90.63, 12.80) +Component11 (91.14, 18.89) [X] +Component12 (9.25, 15.82) [Square] +Component13 (23.84, 91.04) [Circle] +Component14 (53.42, 50.15) +Component15 (23.20, 1.09) +Component16 (74.50, 14.99) +Component17 (23.36, 83.91) [Triangle] +Component18 (55.63, 41.97) [Triangle] +Component19 (77.86, 4.08) [X] +Component20 (16.02, 71.88) [X] +Component21 (52.76, 85.80) +Component22 (88.56, 76.18) [Square] +Component23 (87.30, 28.67) +Component24 (63.18, 77.45) +Component25 (64.67, 24.42) +Component26 (77.91, 68.51) [Square] +Component27 (12.78, 49.59) +Component28 (44.77, 15.02) [Circle] +Component29 (58.72, 28.35) [Circle] +Component30 (24.99, 58.90) [X] +Component31 (25.36, 96.80) +Component32 (39.32, 99.80) [Circle] +Component33 (99.43, 39.47) [Circle] +Component34 (81.44, 13.95) +Component35 (16.49, 68.99) +Component36 (7.24, 32.21) +Component37 (3.68, 64.60) [X] +Component38 (86.45, 26.42) [Circle] +Component39 (76.81, 52.14) +Component40 (58.24, 33.89) +Component41 (69.90, 96.05) +Component42 (32.45, 5.36) [Triangle] +Component43 (64.31, 59.01) [Triangle] +Component44 (85.51, 61.89) +Component45 (74.47, 3.03) +Component46 (59.49, 69.43) [Circle] +Component47 (61.68, 28.42) [Square] +Component48 (44.39, 8.48) [X] +Component49 (72.53, 49.68) +Component50 (36.04, 88.93) [Triangle] +Component51 (5.46, 8.03) +Component52 (70.84, 53.51) [X] +Component53 (66.45, 12.27) +Component54 (30.46, 81.10) +Component55 (44.12, 3.73) [X] +Component56 (38.53, 69.63) [Triangle] +Component57 (3.78, 33.06) [Triangle] +Component58 (6.34, 59.23) +Component59 (44.77, 51.09) [Triangle] +Component60 (34.70, 66.24) [Triangle] +Component61 (68.32, 34.01) +Component62 (2.66, 12.55) +Component63 (48.15, 67.40) [X] +Component64 (22.94, 92.05) +Component65 (64.35, 62.72) [X] +Component66 (62.49, 91.18) [Triangle] +Component67 (37.77, 62.48) [Square] +Component68 (61.24, 64.54) +Component69 (8.86, 51.61) [Triangle] +Component70 (4.27, 58.35) [Circle] +Component71 (24.95, 89.36) [X] +Component72 (63.65, 53.32) [Square] +Component73 (71.29, 60.36) [Circle] +Component74 (80.72, 87.52) +Component75 (54.05, 36.18) +Component76 (72.89, 59.69) +Component77 (52.20, 58.81) [Circle] +Component78 (55.08, 77.07) [Triangle] +Component79 (55.84, 53.48) +Component80 (29.05, 95.03) +Component81 (49.75, 3.88) +Component82 (45.87, 5.24) +Component83 (52.70, 54.81) +Component84 (77.16, 2.60) [Triangle] +Component85 (57.90, 6.89) [Square] +Component86 (31.42, 51.43) [Square] +Component87 (84.99, 31.15) +Component88 (97.75, 43.72) [Triangle] +Component89 (62.25, 37.18) [X] +Component90 (47.25, 5.86) [X] +Component91 (44.99, 84.43) [Triangle] +Component92 (83.02, 78.80) [X] +Component93 (86.53, 22.19) [X] +Component94 (29.50, 81.88) [Circle] +Component95 (83.80, 12.03) [Circle] +Component96 (6.33, 24.74) +Component97 (96.48, 25.86) +Component98 (35.34, 79.18) +Component99 (58.59, 46.39) [Square] +Component100 (87.06, 39.03) [Circle] +Component101 (87.26, 56.31) +Component102 (12.81, 16.15) +Component103 (68.88, 6.87) [Square] +Component104 (81.35, 46.02) +Component105 (78.60, 19.95) +Component106 (11.24, 77.61) [Circle] +Component107 (19.09, 51.26) +Component108 (76.93, 23.58) +Component109 (1.85, 22.92) +Component110 (18.90, 65.14) [Square] +Component111 (24.65, 75.25) +Component112 (1.87, 54.60) +Component113 (88.58, 63.71) +Component114 (97.17, 48.17) [Square] +Component115 (51.49, 11.93) [Square] +Component116 (17.79, 63.02) [X] +Component117 (89.77, 18.04) +Component118 (18.87, 79.15) +Component119 (8.76, 76.67) +Component120 (81.32, 63.54) +Component121 (92.71, 98.97) +Component122 (16.09, 28.54) [X] +Component123 (48.43, 97.65) +Component124 (50.37, 37.20) +Component125 (50.74, 43.05) [Square] +Component126 (75.40, 23.34) +Component127 (73.92, 79.49) [Circle] +Component128 (51.55, 20.51) [Circle] +Component129 (70.45, 13.55) [Square] +Component130 (57.22, 85.64) [X] +Component131 (64.87, 52.42) +Component132 (33.35, 93.91) [Square] +Component133 (73.38, 47.59) +Component134 (65.04, 86.19) +Component135 (68.33, 7.91) [Triangle] +Component136 (64.96, 64.20) [Circle] +Component137 (12.52, 38.35) +Component138 (10.65, 57.44) [Circle] +Component139 (14.10, 12.62) +Component140 (52.85, 26.35) [Triangle] +Component141 (99.33, 72.83) [X] +Component142 (58.66, 65.70) [X] +Component143 (42.10, 3.23) [Triangle] +Component144 (36.20, 47.76) [Circle] +Component145 (75.65, 26.66) [Square] +Component146 (21.33, 14.84) +Component147 (21.88, 24.88) [Triangle] +Component148 (55.89, 55.79) [Triangle] +Component149 (10.73, 30.74) [Triangle] +Component150 (13.37, 91.16) +Component151 (83.17, 21.74) +Component152 (95.03, 90.75) +Component153 (84.26, 35.34) [X] +Component154 (94.45, 87.23) [Triangle] +Component155 (36.59, 75.57) [Circle] +Component156 (42.65, 46.60) [Square] +Component157 (6.47, 56.77) [Square] +Component158 (44.90, 59.64) [Square] +Component159 (76.18, 37.02) [Circle] +Component160 (95.09, 86.50) +Component161 (55.14, 41.38) [Triangle] +Component162 (60.83, 35.01) [Circle] +Component163 (10.27, 67.00) [Square] +Component164 (76.09, 65.99) [Square] +Component165 (49.23, 79.02) [Circle] +Component166 (73.02, 29.83) +Component167 (54.87, 64.16) [X] +Component168 (52.68, 30.53) [Circle] +Component169 (29.26, 87.91) [Triangle] +Component170 (76.81, 44.95) [Triangle] +Component171 (78.63, 55.50) [Circle] +Component172 (72.66, 55.50) [X] +Component173 (27.73, 64.42) [Triangle] +Component174 (70.81, 23.22) +Component175 (87.42, 5.68) +Component176 (98.01, 65.20) [Triangle] +Component177 (94.00, 8.83) [Circle] +Component178 (80.21, 42.24) +Component179 (10.48, 27.78) [Circle] +Component180 (24.51, 49.49) [Square] +Component181 (43.33, 70.82) +Component182 (11.32, 32.01) [Circle] +Component183 (99.25, 72.09) +Component184 (48.90, 59.71) +Component185 (57.10, 16.75) [Circle] +Component186 (83.37, 34.12) [Triangle] +Component187 (8.87, 29.27) +Component188 (65.57, 61.54) +Component189 (51.83, 71.22) [X] +Component190 (27.04, 61.86) [Circle] +Component191 (6.69, 41.47) +Component192 (23.48, 62.15) +Component193 (2.86, 64.07) +Component194 (69.27, 74.67) [Circle] +Component195 (66.48, 9.12) [Square] +Component196 (28.76, 87.81) +Component197 (26.97, 6.71) +Component198 (15.19, 94.43) [Triangle] +Component199 (57.23, 82.51) [Triangle] +Component200 (42.97, 37.53) +Component201 (29.44, 2.29) +Component202 (76.46, 16.24) [Circle] +Component203 (94.20, 17.90) [Circle] +Component204 (30.13, 51.44) [Triangle] +Component205 (68.98, 48.39) +Component206 (24.23, 62.30) [Triangle] +Component207 (24.83, 48.06) +Component208 (8.33, 26.57) [X] +Component209 (77.02, 35.30) [X] +Component210 (74.96, 30.66) [Circle] +Component211 (81.52, 58.49) +Component212 (69.30, 92.38) [Circle] +Component213 (40.11, 41.45) [Square] +Component214 (73.47, 31.71) [X] +Component215 (71.39, 7.86) [Triangle] +Component216 (77.89, 60.06) [Circle] +Component217 (44.90, 74.67) [Circle] +Component218 (16.20, 4.97) +Component219 (69.28, 44.39) +Component220 (0.28, 68.43) [Circle] +Component221 (8.56, 43.62) +Component222 (5.11, 15.54) [X] +Component223 (12.17, 11.72) +Component224 (54.72, 10.39) [X] +Component225 (30.14, 65.32) [Circle] +Component226 (81.92, 66.20) [Circle] +Component227 (43.65, 77.82) [Triangle] +Component228 (56.60, 57.50) +Component229 (28.99, 49.69) [Circle] +Component230 (0.07, 44.12) +Component231 (7.19, 10.93) [X] +Component232 (54.32, 11.62) [X] +Component233 (10.16, 30.70) [Triangle] +Component234 (52.36, 88.84) [Square] +Component235 (29.22, 81.16) [Square] +Component236 (56.28, 34.89) +Component237 (70.98, 18.55) [Triangle] +Component238 (95.70, 52.33) [X] +Component239 (86.93, 77.86) [Triangle] +Component240 (43.57, 61.46) [Circle] +Component241 (63.10, 56.33) [Circle] +Component242 (90.98, 98.11) +Component243 (43.27, 79.39) [Triangle] +Component244 (14.72, 5.66) +Component245 (92.51, 69.32) [Square] +Component246 (78.17, 82.06) [X] +Component247 (87.01, 27.90) [Triangle] +Component248 (35.33, 38.07) +Component249 (74.21, 13.77) [Circle] +Component250 (94.92, 12.62) +Component251 (85.66, 59.81) +Component252 (96.82, 40.39) [X] +Component253 (53.31, 54.76) [X] +Component254 (78.65, 34.31) +Component255 (63.15, 35.91) [X] +Component256 (93.70, 14.87) [Square] +Component257 (87.74, 38.01) [X] +Component258 (59.70, 23.06) [Triangle] +Component259 (24.24, 39.58) [Triangle] +Component260 (70.42, 43.34) +Component261 (11.55, 10.52) [Circle] +Component262 (44.08, 56.93) [X] +Component263 (67.31, 47.53) [Circle] +Component264 (37.36, 90.08) +Component265 (66.67, 53.36) [Triangle] +Component266 (29.99, 41.40) +Component267 (41.91, 74.03) [Triangle] +Component268 (19.68, 31.07) [Triangle] +Component269 (22.36, 32.00) +Component270 (91.55, 6.41) [Square] +Component271 (44.01, 17.22) [Square] +Component272 (30.74, 29.46) +Component273 (94.66, 90.42) [Triangle] +Component274 (72.88, 98.16) [X] +Component275 (67.60, 71.55) +Component276 (15.18, 43.38) [Triangle] +Component277 (35.33, 39.53) +Component278 (94.24, 15.72) [Square] +Component279 (7.41, 46.96) [X] +Component280 (89.81, 55.32) +Component281 (46.56, 78.51) [Circle] +Component282 (82.99, 9.68) [Triangle] +Component283 (47.47, 92.82) [X] +Component284 (13.31, 26.85) [Square] +Component285 (46.03, 43.09) +Component286 (2.34, 57.09) +Component287 (49.65, 31.24) [Circle] +Component288 (83.79, 57.32) +Component289 (6.61, 42.28) [Square] +Component290 (47.25, 10.20) [Triangle] +Component291 (20.57, 45.07) [Square] +Component292 (15.35, 49.21) [Circle] +Component293 (72.98, 80.41) [Triangle] +Component294 (40.77, 79.66) +Component295 (91.69, 47.22) [X] +Component296 (10.54, 48.39) [X] +Component297 (71.89, 61.99) [Square] +Component298 (10.28, 43.01) +Component299 (53.88, 72.55) +Component300 (9.35, 56.50) +Component301 (28.09, 6.29) [Circle] +Component302 (58.57, 73.35) +Component303 (84.96, 51.81) +Component304 (83.02, 53.58) [X] +Component305 (79.51, 51.53) [X] +Component306 (14.24, 99.49) +Component307 (8.57, 85.13) +Component308 (43.93, 30.83) +Component309 (80.62, 29.87) [X] +Component310 (68.72, 48.61) [X] +Component311 (2.37, 81.53) +Component312 (72.73, 68.09) [Circle] +Component313 (30.74, 2.94) [Circle] +Component314 (62.13, 68.91) [X] +Component315 (73.38, 43.60) [Circle] +Component316 (27.37, 98.57) +Component317 (85.82, 67.69) [Circle] +Component318 (45.24, 69.35) [Circle] +Component319 (2.34, 66.07) [X] +Component320 (67.45, 72.20) +Component321 (88.21, 91.50) [Triangle] +Component322 (47.99, 43.92) +Component323 (40.33, 85.89) +Component324 (1.64, 52.02) [Square] +Component325 (82.44, 91.99) [Square] +Component326 (64.93, 6.74) +Component327 (69.13, 32.76) +Component328 (18.83, 7.75) [X] +Component329 (83.61, 30.14) [Square] +Component330 (49.46, 98.58) +Component331 (53.31, 1.37) [Circle] +Component332 (15.54, 23.31) [Circle] +Component333 (81.39, 44.90) +Component334 (40.59, 17.35) [Square] +Component335 (96.35, 80.15) [Circle] +Component336 (57.23, 15.80) [X] +Component337 (69.45, 58.61) +Component338 (75.96, 32.46) [X] +Component339 (6.37, 65.81) [Triangle] +Component340 (59.14, 70.50) +Component341 (79.03, 41.50) [Square] +Component342 (35.41, 80.78) +Component343 (87.18, 45.70) +Component344 (81.33, 58.50) +Component345 (50.63, 17.49) [Square] +Component346 (10.10, 83.23) +Component347 (74.57, 16.10) [X] +Component348 (42.80, 0.78) +Component349 (58.17, 89.85) [Triangle] +Component350 (80.79, 52.51) [X] +Component351 (56.34, 15.08) [Circle] +Component352 (98.43, 1.47) [Circle] +Component353 (19.88, 99.79) [Circle] +Component354 (51.99, 2.67) [Square] +Component355 (44.85, 23.76) [Square] +Component356 (14.24, 98.11) [Circle] +Component357 (25.68, 57.61) [Square] +Component358 (5.75, 71.94) [Square] +Component359 (68.05, 63.63) [Square] +Component360 (12.81, 46.56) [Square] +Component361 (56.35, 20.51) [Square] +Component362 (43.13, 82.54) [Circle] +Component363 (72.98, 59.02) [Triangle] +Component364 (67.80, 56.66) [Circle] +Component365 (58.12, 58.28) [Square] +Component366 (81.73, 0.72) +Component367 (22.11, 82.65) +Component368 (98.81, 19.86) [X] +Component369 (17.27, 57.91) +Component370 (71.83, 47.45) +Component371 (44.85, 0.45) [Square] +Component372 (57.89, 51.13) [Circle] +Component373 (63.17, 2.05) [Square] +Component374 (44.72, 91.15) +Component375 (71.04, 46.51) [Triangle] +Component376 (3.32, 46.78) [Triangle] +Component377 (72.48, 23.81) [Circle] +Component378 (98.32, 26.85) +Component379 (23.27, 92.77) [X] +Component380 (70.01, 22.45) [Square] +Component381 (86.92, 0.65) [X] +Component382 (0.25, 21.60) [Square] +Component383 (3.44, 79.21) +Component384 (35.36, 27.11) [X] +Component385 (45.80, 29.73) [Triangle] +Component386 (21.58, 74.37) [X] +Component387 (76.83, 29.78) +Component388 (11.95, 69.94) +Component389 (10.05, 71.48) +Component390 (11.26, 80.96) +Component391 (89.52, 30.54) [Square] +Component392 (59.05, 40.71) [Triangle] +Component393 (60.09, 97.03) [X] +Component394 (17.57, 50.48) [X] +Component395 (36.74, 53.99) [Triangle] +Component396 (70.58, 10.19) +Component397 (70.27, 24.32) [Circle] +Component398 (96.61, 90.28) [Triangle] +Component399 (85.63, 16.61) [X] +Component400 (22.40, 43.77) [Circle] +Component401 (31.86, 93.15) [Triangle] +Component402 (10.49, 77.04) [X] +Component403 (61.76, 14.09) [Circle] +Component404 (14.98, 44.56) [Square] +Component405 (1.37, 41.79) +Component406 (66.89, 99.29) +Component407 (54.72, 26.16) [Circle] +Component408 (4.02, 78.88) [X] +Component409 (61.57, 55.03) [X] +Component410 (15.00, 72.61) [Circle] +Component411 (30.84, 58.13) +Component412 (74.62, 34.29) +Component413 (87.16, 42.02) +Component414 (42.56, 13.70) [Triangle] +Component415 (63.00, 19.68) [Circle] +Component416 (84.00, 85.81) [Circle] +Component417 (99.85, 26.55) +Component418 (2.32, 39.70) +Component419 (50.24, 60.73) +Component420 (50.87, 91.30) [Square] +Component421 (89.47, 44.46) +Component422 (57.31, 31.98) [Circle] +Component423 (35.68, 39.96) [Circle] +Component424 (25.96, 65.24) +Component425 (18.03, 51.91) +Component426 (29.60, 99.06) [Triangle] +Component427 (19.24, 90.42) +Component428 (41.83, 16.49) [X] +Component429 (23.20, 79.00) [Square] +Component430 (58.74, 20.49) [Circle] +Component431 (12.51, 51.74) [Triangle] +Component432 (36.63, 90.02) [Square] +Component433 (2.31, 38.41) +Component434 (71.42, 22.16) +Component435 (19.13, 72.21) [Triangle] +Component436 (96.97, 89.38) +Component437 (36.78, 84.85) +Component438 (41.40, 18.25) +Component439 (99.42, 98.89) [X] +Component440 (65.90, 64.04) [Triangle] +Component441 (66.50, 54.30) +Component442 (25.00, 1.22) +Component443 (91.63, 77.36) [X] +Component444 (91.54, 35.26) [Square] +Component445 (68.43, 4.16) [Circle] +Component446 (51.33, 47.47) [Circle] +Component447 (19.82, 70.34) [Triangle] +Component448 (87.82, 97.43) +Component449 (47.41, 73.13) [X] +Component450 (9.65, 4.74) [Circle] +Component451 (16.64, 31.95) [Circle] +Component452 (98.44, 49.75) [Triangle] +Component453 (12.91, 75.20) +Component454 (68.13, 57.99) +Component455 (88.52, 73.61) [Circle] +Component456 (43.00, 47.91) +Component457 (67.28, 76.60) [Circle] +Component458 (30.11, 20.41) [Triangle] +Component459 (32.38, 7.73) +Component460 (48.65, 59.39) [Circle] +Component461 (95.93, 13.43) [Circle] +Component462 (76.05, 97.64) [Triangle] +Component463 (10.57, 5.86) +Component464 (15.16, 65.67) [Triangle] +Component465 (49.29, 37.41) +Component466 (62.86, 55.21) +Component467 (41.70, 22.98) [X] +Component468 (11.40, 42.51) [Square] +Component469 (99.96, 9.88) [X] +Component470 (74.36, 18.50) [Triangle] +Component471 (27.71, 2.13) [X] +Component472 (37.76, 41.14) +Component473 (54.41, 69.25) [Triangle] +Component474 (19.69, 0.90) +Component475 (33.44, 22.53) [X] +Component476 (78.46, 53.81) +Component477 (27.36, 94.83) [X] +Component478 (53.98, 15.10) [Triangle] +Component479 (49.75, 90.23) [Square] +Component480 (26.13, 83.45) +Component481 (75.99, 39.97) +Component482 (17.03, 54.73) [Triangle] +Component483 (10.89, 86.65) +Component484 (37.28, 90.48) +Component485 (59.96, 76.87) [Triangle] +Component486 (80.36, 98.15) +Component487 (9.26, 96.01) +Component488 (62.92, 30.57) [Square] +Component489 (50.52, 20.80) [X] +Component490 (23.88, 11.84) +Component491 (77.93, 5.51) +Component492 (56.88, 8.00) +Component493 (86.70, 55.53) [Square] +Component494 (62.22, 67.78) [Triangle] +Component495 (50.63, 55.06) [Circle] +Component496 (6.86, 22.43) [X] +Component497 (93.32, 40.43) [Circle] +Component498 (96.81, 51.60) +Component499 (59.56, 57.21) [Square] +Component500 (2.54, 51.36) +Component501 (88.77, 48.72) [Square] +Component502 (80.17, 78.87) [Circle] +Component503 (63.34, 14.75) [Square] +Component504 (21.89, 35.77) [Circle] +Component505 (17.52, 41.69) [X] +Component506 (59.66, 93.27) [X] +Component507 (44.93, 75.12) [Square] +Component508 (2.75, 88.38) [Triangle] +Component509 (21.28, 6.63) [Square] +Component510 (86.03, 50.85) [Circle] +Component511 (44.85, 98.92) [Square] +Component512 (82.29, 88.28) +Component513 (99.39, 16.41) [Square] +Component514 (38.85, 11.93) [Circle] +Component515 (79.06, 95.86) [X] +Component516 (0.49, 66.17) [X] +Component517 (34.87, 73.24) +Component518 (57.08, 37.29) +Component519 (59.70, 27.17) +Component520 (26.20, 98.63) [Square] +Component521 (73.63, 43.73) [X] +Component522 (52.00, 34.57) [X] +Component523 (61.51, 25.40) [Triangle] +Component524 (49.91, 28.64) +Component525 (5.83, 22.08) [X] +Component526 (62.78, 28.57) +Component527 (17.11, 32.92) [X] +Component528 (76.93, 82.48) [Circle] +Component529 (18.24, 51.31) +Component530 (35.40, 4.42) +Component531 (65.91, 71.77) [X] +Component532 (51.22, 26.10) [X] +Component533 (32.79, 13.41) [X] +Component534 (91.34, 95.42) [X] +Component535 (84.52, 23.28) [Circle] +Component536 (46.75, 70.21) +Component537 (73.34, 99.55) [Triangle] +Component538 (21.28, 97.53) [Square] +Component539 (53.13, 34.63) [Circle] +Component540 (45.98, 67.68) +Component541 (76.47, 11.65) [Square] +Component542 (8.72, 99.30) [Square] +Component543 (40.19, 84.35) [Square] +Component544 (54.66, 66.40) [Triangle] +Component545 (30.53, 31.73) [Square] +Component546 (72.43, 41.03) +Component547 (77.05, 93.93) +Component548 (84.24, 4.94) +Component549 (48.93, 2.90) [Square] +Component550 (22.94, 7.40) +Component551 (91.81, 28.17) +Component552 (12.27, 44.62) [Circle] +Component553 (85.09, 90.79) [Circle] +Component554 (14.90, 44.18) [X] +Component555 (77.18, 32.00) [X] +Component556 (90.01, 54.51) +Component557 (21.88, 92.41) [Circle] +Component558 (3.92, 26.93) [X] +Component559 (17.08, 7.74) +Component560 (96.04, 1.34) [Circle] +Component561 (32.55, 12.12) [X] +Component562 (32.12, 73.08) [Triangle] +Component563 (34.09, 73.03) [Triangle] +Component564 (83.10, 17.21) [Triangle] +Component565 (47.20, 62.09) [Square] +Component566 (66.85, 41.75) [X] +Component567 (56.32, 73.47) [Square] +Component568 (63.74, 14.66) +Component569 (29.04, 21.96) [X] +Component570 (40.40, 10.86) +Component571 (5.16, 84.97) [Circle] +Component572 (38.42, 2.42) [Square] +Component573 (85.44, 74.93) [Square] +Component574 (87.91, 0.60) [Square] +Component575 (26.21, 7.64) [X] +Component576 (74.56, 16.79) [Square] +Component577 (77.85, 68.39) +Component578 (62.92, 87.85) [X] +Component579 (70.76, 28.86) [Circle] +Component580 (82.86, 24.47) [X] +Component581 (4.56, 9.62) [Triangle] +Component582 (37.45, 94.56) [Circle] +Component583 (12.14, 30.34) [X] +Component584 (3.95, 57.21) [Square] +Component585 (38.37, 72.37) +Component586 (25.84, 82.02) +Component587 (23.21, 59.31) [Square] +Component588 (45.93, 79.55) +Component589 (55.65, 75.30) [Square] +Component590 (75.80, 51.42) +Component591 (12.33, 87.97) +Component592 (76.12, 25.18) [X] +Component593 (42.48, 48.63) +Component594 (83.10, 44.41) [Triangle] +Component595 (85.27, 79.81) [Triangle] +Component596 (2.29, 76.07) +Component597 (79.85, 49.82) +Component598 (48.10, 41.86) [X] +Component599 (30.99, 12.78) [Circle] +Component600 (85.67, 2.54) [Circle] +Component601 (34.27, 62.27) +Component602 (64.46, 94.92) [Triangle] +Component603 (39.70, 37.16) +Component604 (17.25, 23.20) [Circle] +Component605 (84.77, 93.12) [Circle] +Component606 (20.36, 65.56) +Component607 (40.75, 34.65) +Component608 (78.99, 67.22) [X] +Component609 (33.60, 63.19) [X] +Component610 (96.15, 23.34) [X] +Component611 (94.94, 23.74) +Component612 (18.31, 38.34) [Triangle] +Component613 (60.20, 31.49) [Square] +Component614 (71.73, 44.16) [X] +Component615 (93.85, 69.80) [Triangle] +Component616 (4.89, 51.46) +Component617 (92.34, 23.59) [Square] +Component618 (79.12, 23.87) [X] +Component619 (5.24, 26.52) [Circle] +Component620 (66.10, 17.05) [X] +Component621 (80.15, 91.21) +Component622 (60.56, 35.33) +Component623 (38.84, 73.56) [X] +Component624 (32.94, 65.46) [Square] +Component625 (72.03, 93.52) +Component626 (51.66, 1.88) +Component627 (43.42, 69.63) +Component628 (68.93, 78.58) [Triangle] +Component629 (12.17, 88.50) [Square] +Component630 (25.74, 39.64) +Component631 (89.94, 17.59) [Triangle] +Component632 (18.03, 5.97) [Square] +Component633 (63.08, 82.42) [Circle] +Component634 (64.06, 7.17) [Circle] +Component635 (30.33, 44.27) [Triangle] +Component636 (89.42, 2.98) [Square] +Component637 (11.69, 51.64) [Triangle] +Component638 (27.67, 38.16) [X] +Component639 (82.42, 96.29) [Square] +Component640 (94.21, 94.49) +Component641 (8.58, 71.71) +Component642 (70.45, 91.93) +Component643 (10.96, 1.29) [Triangle] +Component644 (10.57, 19.18) [Triangle] +Component645 (57.76, 83.31) [Square] +Component646 (12.13, 8.42) [Circle] +Component647 (44.58, 80.07) [X] +Component648 (81.68, 24.58) +Component649 (52.65, 92.38) +Component650 (39.35, 41.67) [Triangle] +Component651 (55.90, 65.04) +Component652 (67.25, 14.83) [Square] +Component653 (8.49, 24.18) +Component654 (65.87, 40.83) [X] +Component655 (3.18, 17.64) [Square] +Component656 (25.59, 33.81) +Component657 (73.70, 19.39) +Component658 (21.35, 87.93) [Square] +Component659 (64.18, 97.24) [Square] +Component660 (32.48, 6.54) [X] +Component661 (86.73, 65.34) [Circle] +Component662 (98.31, 91.84) [Triangle] +Component663 (48.72, 75.26) [Square] +Component664 (33.81, 25.98) [Triangle] +Component665 (83.92, 87.11) [Triangle] +Component666 (36.37, 54.35) +Component667 (70.76, 58.70) [Circle] +Component668 (87.91, 69.42) +Component669 (5.06, 12.39) +Component670 (22.26, 4.78) +Component671 (82.28, 96.57) [Triangle] +Component672 (28.71, 40.93) [Circle] +Component673 (6.42, 25.09) [Square] +Component674 (57.90, 76.51) +Component675 (46.54, 26.90) [Triangle] +Component676 (6.60, 37.36) +Component677 (67.94, 26.83) +Component678 (70.57, 66.78) [Triangle] +Component679 (92.63, 29.54) +Component680 (21.06, 56.15) +Component681 (30.12, 87.84) [Square] +Component682 (22.50, 17.49) [Triangle] +Component683 (22.16, 99.28) [Square] +Component684 (86.25, 85.65) [Triangle] +Component685 (42.38, 97.43) [Square] +Component686 (82.82, 98.13) [Triangle] +Component687 (85.99, 22.81) [Square] +Component688 (92.42, 13.14) [Circle] +Component689 (86.08, 22.54) [Circle] +Component690 (78.61, 48.10) [Square] +Component691 (2.95, 70.77) +Component692 (96.12, 92.64) [Square] +Component693 (12.50, 97.26) [Square] +Component694 (86.32, 25.85) +Component695 (80.51, 28.95) [Triangle] +Component696 (46.82, 6.61) +Component697 (66.87, 17.17) [Circle] +Component698 (99.04, 68.95) [Triangle] +Component699 (77.10, 12.58) [Triangle] +Component700 (81.22, 95.50) [Square] +Component701 (58.44, 84.13) +Component702 (80.19, 61.91) +Component703 (96.80, 74.86) [Circle] +Component704 (83.91, 79.21) [Circle] +Component705 (94.51, 96.03) [Triangle] +Component706 (51.67, 13.80) +Component707 (29.79, 8.71) [Circle] +Component708 (36.15, 69.18) [Triangle] +Component709 (68.99, 71.52) [Circle] +Component710 (88.45, 64.95) [Circle] +Component711 (80.05, 71.13) [Circle] +Component712 (50.04, 22.87) [Triangle] +Component713 (17.38, 28.08) [Circle] +Component714 (88.91, 43.58) [Triangle] +Component715 (82.29, 88.78) [Circle] +Component716 (68.36, 82.95) [Square] +Component717 (10.29, 93.22) +Component718 (92.84, 27.40) +Component719 (39.48, 91.46) [Triangle] +Component720 (69.69, 83.40) +Component721 (33.85, 40.52) [Square] +Component722 (97.83, 99.99) [Triangle] +Component723 (62.84, 11.09) [X] +Component724 (43.10, 47.36) [Triangle] +Component725 (17.38, 82.24) [Triangle] +Component726 (54.82, 94.05) +Component727 (5.63, 25.27) [X] +Component728 (80.85, 80.59) [Triangle] +Component729 (59.77, 7.37) [X] +Component730 (68.88, 77.36) [X] +Component731 (93.49, 80.85) [Square] +Component732 (52.99, 75.23) [Circle] +Component733 (37.52, 58.87) +Component734 (9.84, 11.57) [Triangle] +Component735 (32.67, 39.28) [X] +Component736 (46.91, 23.64) [Square] +Component737 (33.46, 92.43) [Triangle] +Component738 (60.48, 16.10) [X] +Component739 (60.30, 74.77) +Component740 (97.63, 8.09) +Component741 (11.78, 92.13) +Component742 (41.21, 41.45) [Circle] +Component743 (4.93, 37.13) [X] +Component744 (13.29, 7.31) +Component745 (69.09, 18.30) [Circle] +Component746 (49.88, 88.56) +Component747 (66.69, 64.64) [X] +Component748 (71.42, 24.62) [Triangle] +Component749 (39.46, 93.61) +Component750 (2.08, 22.34) [Circle] +Component751 (89.58, 41.54) +Component752 (47.94, 84.87) +Component753 (65.47, 55.58) [X] +Component754 (53.54, 5.12) [Square] +Component755 (74.49, 17.69) [Square] +Component756 (12.88, 88.92) [X] +Component757 (52.18, 50.44) [X] +Component758 (68.05, 52.05) [Circle] +Component759 (93.47, 30.01) [Circle] +Component760 (94.90, 99.55) [X] +Component761 (84.05, 4.44) [Circle] +Component762 (42.74, 36.71) [Square] +Component763 (85.63, 69.38) [X] +Component764 (65.40, 66.21) [Triangle] +Component765 (21.67, 14.78) [Circle] +Component766 (53.61, 70.93) [Triangle] +Component767 (5.07, 78.99) +Component768 (53.15, 36.64) [Circle] +Component769 (46.97, 1.41) +Component770 (33.90, 44.43) +Component771 (39.45, 36.48) +Component772 (67.78, 90.87) [Circle] +Component773 (96.24, 3.57) [Triangle] +Component774 (41.37, 82.60) [Triangle] +Component775 (95.15, 52.79) [Square] +Component776 (20.68, 54.81) +Component777 (84.49, 48.27) [Circle] +Component778 (99.01, 87.63) +Component779 (49.10, 13.34) +Component780 (65.15, 86.57) +Component781 (91.51, 32.85) +Component782 (60.79, 26.62) [Triangle] +Component783 (34.55, 24.16) +Component784 (25.73, 57.46) +Component785 (23.74, 52.01) +Component786 (21.19, 90.75) [Triangle] +Component787 (83.22, 80.23) [Square] +Component788 (48.28, 63.70) [Triangle] +Component789 (47.02, 71.16) +Component790 (98.87, 44.60) +Component791 (80.99, 3.44) [Circle] +Component792 (41.82, 95.50) [Triangle] +Component793 (69.54, 96.23) [Triangle] +Component794 (49.78, 89.18) +Component795 (43.14, 80.71) [Triangle] +Component796 (70.04, 8.33) +Component797 (32.29, 29.23) [Square] +Component798 (58.10, 42.58) +Component799 (64.07, 98.61) [Circle] +Component800 (35.86, 61.33) [X] +Component801 (8.55, 54.52) +Component802 (55.95, 99.76) [Triangle] +Component803 (19.90, 4.60) [Circle] +Component804 (49.99, 96.57) +Component805 (73.19, 42.31) [Triangle] +Component806 (52.10, 15.63) [Circle] +Component807 (89.95, 99.16) [Square] +Component808 (82.80, 94.93) +Component809 (90.47, 43.12) +Component810 (36.98, 51.49) +Component811 (99.92, 14.67) [Square] +Component812 (62.57, 8.28) +Component813 (36.85, 24.38) +Component814 (2.59, 63.52) [Square] +Component815 (98.73, 86.84) +Component816 (29.92, 3.73) +Component817 (90.50, 63.09) +Component818 (76.17, 28.16) [Triangle] +Component819 (75.38, 42.93) [Square] +Component820 (86.39, 19.53) +Component821 (65.52, 54.88) +Component822 (31.16, 50.90) [Square] +Component823 (58.12, 53.66) +Component824 (95.46, 46.39) [X] +Component825 (76.11, 29.03) +Component826 (38.60, 28.10) [X] +Component827 (96.21, 96.79) +Component828 (58.19, 88.64) +Component829 (94.16, 47.60) [Square] +Component830 (40.67, 86.94) +Component831 (30.28, 55.52) [Square] +Component832 (17.24, 40.01) [Square] +Component833 (83.82, 84.98) [X] +Component834 (67.50, 79.68) +Component835 (30.15, 53.82) [Circle] +Component836 (92.23, 78.01) [Triangle] +Component837 (27.23, 92.60) [Square] +Component838 (31.61, 25.63) [X] +Component839 (61.71, 44.33) [Square] +Component840 (78.48, 69.79) [Circle] +Component841 (44.89, 97.80) [X] +Component842 (48.90, 49.06) [Triangle] +Component843 (15.44, 16.25) [Triangle] +Component844 (8.31, 94.22) +Component845 (31.64, 49.32) +Component846 (75.81, 94.49) [X] +Component847 (99.41, 85.31) [Circle] +Component848 (91.64, 32.44) [Square] +Component849 (49.66, 55.99) +Component850 (90.85, 80.95) +Component851 (20.72, 44.29) [X] +Component852 (66.52, 1.30) [Square] +Component853 (9.92, 86.11) [X] +Component854 (33.23, 85.49) +Component855 (65.31, 70.68) [Square] +Component856 (17.92, 62.02) [Square] +Component857 (95.52, 64.69) +Component858 (11.31, 0.13) +Component859 (59.34, 97.52) +Component860 (17.28, 96.61) +Component861 (33.92, 80.85) [Square] +Component862 (54.06, 3.36) [Circle] +Component863 (46.14, 16.09) [Triangle] +Component864 (77.52, 15.25) +Component865 (1.65, 25.12) [X] +Component866 (11.77, 25.49) +Component867 (41.81, 74.80) [Circle] +Component868 (6.72, 7.94) [X] +Component869 (78.18, 76.61) +Component870 (84.57, 14.90) [Circle] +Component871 (27.36, 76.49) [Square] +Component872 (74.01, 20.52) [Circle] +Component873 (72.83, 82.87) +Component874 (9.74, 46.82) [X] +Component875 (85.55, 26.40) [X] +Component876 (90.96, 12.96) [Circle] +Component877 (83.21, 30.43) +Component878 (18.32, 76.50) [X] +Component879 (64.86, 10.96) [Circle] +Component880 (20.28, 82.11) [Square] +Component881 (53.75, 89.58) [X] +Component882 (60.19, 95.72) [Square] +Component883 (18.98, 48.08) [X] +Component884 (72.61, 93.24) [Circle] +Component885 (35.46, 4.72) +Component886 (52.80, 41.57) [Square] +Component887 (53.44, 29.95) +Component888 (10.23, 58.60) [Square] +Component889 (68.29, 30.06) [Square] +Component890 (76.88, 68.56) +Component891 (31.04, 37.55) [Square] +Component892 (17.55, 78.76) +Component893 (10.10, 12.05) [X] +Component894 (73.22, 27.89) [Square] +Component895 (60.35, 81.53) +Component896 (4.47, 73.49) [Triangle] +Component897 (8.72, 67.26) +Component898 (26.71, 23.78) +Component899 (81.72, 36.94) [Triangle] +Component900 (16.01, 86.38) [Square] +Component901 (55.07, 85.27) [Triangle] +Component902 (70.30, 12.88) +Component903 (60.31, 62.86) [Triangle] +Component904 (41.00, 37.55) [Triangle] +Component905 (9.64, 61.89) [Circle] +Component906 (54.10, 31.77) [X] +Component907 (76.54, 62.41) +Component908 (86.17, 96.56) +Component909 (46.85, 49.44) +Component910 (37.67, 41.22) [Triangle] +Component911 (26.66, 62.43) [Triangle] +Component912 (69.43, 3.66) +Component913 (33.47, 70.71) [Square] +Component914 (93.21, 77.98) [Circle] +Component915 (90.74, 9.07) +Component916 (93.97, 16.70) [Square] +Component917 (8.15, 60.87) +Component918 (50.09, 96.07) [Square] +Component919 (75.88, 86.17) [Circle] +Component920 (68.31, 86.98) [X] +Component921 (67.83, 79.88) +Component922 (97.10, 82.63) [X] +Component923 (83.01, 1.06) [X] +Component924 (39.58, 86.43) [Circle] +Component925 (47.55, 84.77) +Component926 (96.69, 55.45) [X] +Component927 (77.39, 79.82) +Component928 (43.07, 76.23) [X] +Component929 (78.14, 10.36) [Triangle] +Component930 (30.33, 63.76) [X] +Component931 (41.25, 52.50) +Component932 (31.96, 82.30) +Component933 (65.06, 59.05) [Circle] +Component934 (26.94, 44.22) [Circle] +Component935 (27.72, 29.76) +Component936 (70.78, 0.65) [Triangle] +Component937 (58.58, 74.89) +Component938 (98.48, 3.16) +Component939 (17.30, 75.27) +Component940 (48.66, 72.60) [X] +Component941 (85.22, 46.47) [Triangle] +Component942 (67.36, 93.17) [Triangle] +Component943 (79.00, 3.03) +Component944 (93.55, 16.21) +Component945 (33.57, 39.55) +Component946 (30.28, 29.41) +Component947 (98.43, 70.60) [X] +Component948 (96.67, 13.72) [Triangle] +Component949 (38.28, 48.43) [Triangle] +Component950 (88.84, 46.42) [Circle] +Component951 (73.14, 28.70) [X] +Component952 (64.62, 10.80) [X] +Component953 (17.27, 35.05) +Component954 (28.44, 50.29) [Circle] +Component955 (68.78, 52.58) +Component956 (92.74, 72.49) +Component957 (74.46, 73.66) [Circle] +Component958 (91.38, 5.63) [Square] +Component959 (17.30, 2.57) [Triangle] +Component960 (77.85, 76.45) [Square] +Component961 (67.51, 95.09) +Component962 (22.14, 74.92) [Circle] +Component963 (11.07, 79.09) [Circle] +Component964 (93.58, 6.56) +Component965 (30.32, 76.50) [Circle] +Component966 (88.27, 78.61) [Circle] +Component967 (99.07, 68.94) [X] +Component968 (4.65, 2.36) [Square] +Component969 (58.21, 65.30) [Triangle] +Component970 (97.18, 30.96) [Square] +Component971 (14.96, 34.69) +Component972 (24.39, 36.35) +Component973 (68.87, 87.50) +Component974 (8.47, 85.32) [Square] +Component975 (22.83, 76.01) [Circle] +Component976 (49.17, 0.04) [Circle] +Component977 (68.21, 48.73) +Component978 (89.13, 91.30) [Triangle] +Component979 (65.46, 59.78) [Triangle] +Component980 (90.34, 57.29) +Component981 (96.18, 5.07) [Triangle] +Component982 (76.27, 45.30) [Circle] +Component983 (46.02, 62.58) [Circle] +Component984 (85.41, 20.20) [X] +Component985 (87.32, 88.29) [X] +Component986 (99.07, 66.28) +Component987 (80.59, 74.45) +Component988 (4.96, 92.28) +Component989 (29.93, 45.09) [Triangle] +Component990 (41.97, 25.00) +Component991 (17.13, 20.49) +Component992 (95.65, 87.44) [Circle] +Component993 (98.97, 40.15) [Circle] +Component994 (18.60, 5.01) +Component995 (3.77, 53.31) [Triangle] +Component996 (39.81, 95.10) [X] +Component997 (0.87, 96.79) +Component998 (9.14, 29.01) [Triangle] +Component999 (40.79, 92.24) [Circle] + +Component387 -> Component728 +Component563 -- Component366 +Component537 -- Component292 +Component166 -- Component631 +Component300 -> Component112 +Component878 -> Component414 +Component988 -> Component49 +Component174 -- Component89 +Component585 -- Component354 +Component681 -- Component25 +Component994 -- Component479 +Component68 -- Component702 +Component619 -> Component448 +Component899 -> Component43 +Component927 -> Component175 +Component732 -> Component404 +Component751 -- Component519 +Component982 -- Component595 +Component101 -- Component259 +Component933 -- Component208 +Component717 -- Component607 +Component897 -- Component386 +Component66 -> Component18 +Component517 -> Component829 +Component132 -> Component214 +Component228 -- Component446 +Component578 -- Component369 +Component841 -> Component805 +Component787 -- Component789 +Component478 -- Component421 +Component281 -> Component863 +Component218 -- Component232 +Component853 -> Component598 +Component277 -> Component714 +Component815 -- Component66 +Component17 -> Component878 +Component973 -- Component631 +Component855 -> Component787 +Component326 -- Component670 +Component535 -> Component24 +Component347 -> Component624 +Component921 -> Component172 +Component543 -- Component130 +Component879 -- Component456 +Component50 -> Component120 +Component243 -> Component753 +Component549 -> Component971 +Component563 -- Component895 +Component23 -- Component650 +Component772 -- Component980 +Component379 -- Component342 +Component744 -> Component785 +Component746 -- Component138 +Component188 -> Component96 +Component486 -> Component400 +Component40 -> Component475 +Component860 -- Component88 +Component30 -> Component105 +Component479 -> Component790 +Component542 -> Component193 +Component143 -> Component966 +Component183 -> Component260 +Component8 -- Component437 +Component579 -- Component4 +Component120 -- Component488 +Component961 -> Component470 +Component952 -> Component581 +Component60 -- Component682 +Component918 -- Component235 +Component9 -> Component1 +Component503 -- Component452 +Component74 -- Component911 +Component184 -> Component260 +Component370 -- Component927 +Component678 -> Component506 +Component152 -> Component403 +Component877 -- Component649 +Component108 -- Component944 +Component580 -> Component726 +Component691 -> Component384 +Component953 -- Component452 +Component660 -> Component582 +Component695 -> Component152 +Component222 -> Component858 +Component161 -- Component275 +Component604 -- Component112 +Component130 -- Component203 +Component256 -- Component892 +Component120 -- Component946 +Component97 -> Component208 +Component905 -> Component632 +Component918 -- Component195 +Component961 -- Component860 +Component33 -> Component336 +Component613 -- Component222 +Component466 -> Component796 +Component861 -> Component867 +Component145 -> Component425 +Component239 -- Component549 +Component340 -> Component634 +Component752 -> Component53 +Component633 -> Component681 +Component456 -> Component373 +Component71 -> Component343 +Component358 -- Component157 +Component615 -- Component657 +Component570 -- Component433 +Component561 -> Component90 +Component600 -- Component344 +Component254 -> Component746 +Component14 -> Component41 +Component340 -> Component126 +Component957 -> Component684 +Component259 -> Component949 +Component521 -- Component792 +Component90 -- Component929 +Component150 -> Component617 +Component854 -> Component538 +Component485 -> Component426 +Component639 -> Component596 +Component603 -> Component540 +Component815 -> Component365 +Component724 -> Component309 +Component736 -> Component800 +Component448 -> Component715 +Component507 -> Component303 +Component610 -> Component201 +Component712 -- Component599 +Component263 -> Component206 +Component321 -> Component519 +Component861 -> Component0 +Component160 -- Component223 +Component9 -> Component686 +Component866 -- Component200 +Component829 -- Component8 +Component73 -> Component557 +Component350 -> Component93 +Component379 -- Component467 +Component870 -> Component402 +Component385 -> Component675 +Component415 -- Component296 +Component698 -> Component36 +Component708 -> Component117 +Component550 -- Component427 +Component268 -> Component550 +Component573 -- Component124 +Component385 -- Component737 +Component968 -- Component7 +Component850 -> Component992 +Component166 -- Component337 +Component654 -- Component476 +Component768 -- Component834 +Component381 -- Component663 +Component540 -- Component770 +Component231 -> Component234 +Component602 -> Component180 +Component632 -- Component186 +Component568 -> Component583 +Component842 -- Component311 +Component23 -- Component344 +Component914 -- Component732 +Component514 -> Component426 +Component952 -> Component412 +Component192 -> Component734 +Component828 -> Component295 +Component341 -> Component530 +Component650 -- Component169 +Component668 -- Component446 +Component745 -> Component15 +Component995 -> Component321 +Component311 -> Component585 +Component16 -> Component94 +Component41 -> Component459 +Component576 -> Component647 +Component783 -- Component311 +Component842 -> Component857 +Component646 -> Component312 +Component252 -> Component703 +Component519 -- Component884 +Component767 -- Component465 +Component18 -> Component738 +Component743 -> Component828 +Component844 -> Component119 +Component270 -- Component552 +Component372 -- Component539 +Component259 -- Component720 +Component334 -- Component338 +Component357 -- Component551 +Component417 -- Component367 +Component905 -> Component693 +Component272 -> Component469 +Component127 -- Component888 +Component621 -- Component662 +Component424 -- Component512 +Component982 -> Component456 +Component58 -- Component333 +Component28 -> Component200 +Component110 -- Component703 +Component809 -> Component46 +Component414 -> Component881 +Component909 -- Component662 +Component804 -> Component531 +Component307 -> Component133 +Component815 -> Component64 +Component124 -- Component936 +Component413 -- Component299 +Component802 -- Component799 +Component448 -- Component874 +Component225 -- Component18 +Component553 -- Component730 +Component33 -> Component181 +Component751 -> Component567 +Component279 -> Component873 +Component768 -- Component982 +Component313 -> Component955 +Component375 -- Component681 +Component13 -> Component206 +Component772 -> Component981 +Component140 -> Component46 +Component462 -- Component533 +Component244 -- Component341 +Component471 -- Component172 +Component54 -- Component759 +Component923 -> Component449 +Component669 -> Component697 +Component646 -> Component19 +Component802 -> Component306 +Component756 -- Component343 +Component768 -- Component727 +Component906 -- Component19 +Component238 -- Component296 +Component599 -> Component74 +Component969 -- Component186 +Component249 -> Component355 +Component483 -- Component988 +Component669 -> Component226 +Component772 -- Component104 +Component533 -> Component890 +Component788 -- Component259 +Component967 -- Component260 +Component670 -- Component94 +Component291 -> Component139 +Component361 -> Component901 +Component338 -> Component953 +Component944 -- Component600 +Component40 -- Component464 +Component286 -- Component354 +Component599 -- Component912 +Component213 -- Component185 +Component63 -> Component48 +Component271 -- Component811 +Component112 -- Component782 +Component384 -- Component552 +Component351 -> Component162 +Component502 -- Component173 +Component81 -- Component405 +Component866 -- Component777 +Component219 -> Component279 +Component121 -> Component448 +Component437 -> Component890 +Component889 -> Component471 +Component436 -> Component705 +Component938 -- Component670 +Component733 -> Component709 +Component220 -- Component386 +Component57 -> Component652 +Component500 -- Component495 +Component282 -> Component724 +Component786 -> Component103 +Component844 -> Component822 +Component218 -- Component48 +Component662 -- Component544 +Component8 -- Component580 +Component137 -> Component943 +Component924 -> Component822 +Component562 -> Component337 +Component20 -- Component847 +Component60 -- Component310 +Component709 -- Component48 +Component476 -> Component453 +Component315 -- Component896 +Component29 -- Component429 +Component136 -> Component357 +Component782 -> Component890 +Component737 -> Component89 +Component806 -- Component929 +Component28 -> Component659 +Component698 -- Component852 +Component298 -> Component241 +Component64 -> Component863 +Component489 -> Component295 +Component204 -- Component248 +Component165 -> Component554 +Component970 -- Component465 +Component52 -- Component748 +Component900 -> Component759 +Component509 -> Component135 +Component187 -> Component516 +Component787 -- Component587 +Component939 -> Component917 +Component764 -> Component139 +Component64 -- Component79 +Component93 -> Component852 +Component589 -- Component991 +Component410 -- Component660 +Component242 -> Component87 +Component381 -> Component245 +Component413 -- Component262 +Component912 -- Component869 +Component334 -> Component483 +Component629 -> Component369 +Component293 -> Component159 +Component749 -- Component129 +Component244 -- Component394 +Component29 -- Component388 +Component523 -> Component443 +Component265 -- Component973 +Component380 -- Component983 +Component608 -- Component227 +Component119 -> Component472 +Component743 -- Component766 +Component83 -- Component942 +Component110 -- Component696 +Component754 -> Component24 +Component571 -- Component898 +Component290 -> Component615 +Component793 -- Component490 +Component746 -> Component992 +Component871 -- Component756 +Component623 -> Component259 +Component188 -> Component778 +Component348 -- Component392 +Component5 -- Component401 +Component162 -> Component680 +Component233 -- Component276 +Component859 -- Component42 +Component505 -- Component917 +Component328 -> Component892 +Component34 -- Component828 +Component526 -- Component744 +Component130 -- Component970 +Component673 -> Component884 +Component852 -> Component630 +Component102 -- Component41 +Component756 -- Component573 +Component31 -- Component592 +Component558 -> Component400 +Component1 -- Component576 +Component575 -> Component184 +Component19 -- Component732 +Component30 -- Component534 +Component343 -- Component614 +Component562 -> Component480 +Component361 -- Component979 +Component86 -> Component597 +Component192 -- Component600 +Component553 -- Component491 +Component530 -> Component323 +Component995 -> Component720 +Component40 -- Component963 +Component438 -- Component271 +Component941 -> Component86 +Component161 -> Component997 +Component493 -> Component351 +Component907 -- Component307 +Component803 -> Component218 +Component232 -> Component372 +Component74 -> Component63 +Component386 -- Component365 +Component445 -- Component476 +Component633 -- Component463 +Component605 -- Component387 +Component650 -> Component693 +Component338 -> Component843 +Component518 -> Component188 +Component349 -> Component454 +Component889 -> Component874 +Component764 -> Component65 +Component112 -- Component780 +Component253 -- Component757 +Component924 -- Component893 +Component547 -- Component297 +Component372 -> Component852 +Component682 -> Component865 +Component743 -> Component716 +Component31 -> Component618 +Component896 -> Component951 +Component157 -- Component649 +Component22 -- Component966 +Component811 -> Component86 +Component212 -> Component80 +Component473 -> Component236 +Component979 -> Component43 +Component668 -- Component995 +Component412 -> Component594 +Component516 -- Component472 +Component500 -> Component554 +Component148 -- Component185 +Component769 -- Component438 +Component512 -- Component570 +Component249 -> Component990 +Component185 -> Component233 +Component94 -- Component320 +Component858 -- Component197 +Component268 -- Component6 +Component529 -- Component806 +Component184 -- Component779 +Component235 -- Component894 +Component215 -> Component990 +Component7 -- Component427 +Component583 -> Component297 +Component504 -- Component148 +Component92 -- Component223 +Component693 -> Component151 +Component858 -- Component241 +Component523 -- Component919 +Component938 -> Component926 +Component550 -- Component761 +Component25 -- Component532 +Component789 -- Component151 +Component497 -- Component190 +Component443 -- Component319 +Component82 -> Component780 +Component523 -> Component205 +Component176 -- Component456 +Component600 -> Component231 +Component609 -- Component908 +Component374 -> Component895 +Component919 -> Component605 +Component74 -- Component953 +Component70 -> Component75 +Component757 -- Component405 +Component756 -- Component342 +Component847 -- Component252 +Component596 -> Component131 +Component407 -- Component957 +Component493 -> Component691 +Component618 -- Component506 +Component788 -- Component107 +Component700 -- Component258 +Component419 -> Component896 +Component936 -> Component433 +Component221 -> Component206 +Component167 -> Component57 +Component86 -> Component1 +Component825 -> Component326 +Component643 -- Component121 +Component912 -- Component132 +Component307 -- Component636 +Component218 -- Component84 +Component192 -> Component656 +Component346 -- Component347 +Component45 -- Component260 +Component962 -- Component33 +Component693 -> Component197 +Component308 -- Component622 +Component23 -> Component24 +Component625 -- Component402 +Component437 -> Component114 +Component186 -- Component586 +Component93 -- Component96 +Component830 -- Component485 +Component177 -> Component323 +Component727 -> Component725 +Component519 -> Component669 +Component213 -- Component611 +Component500 -- Component763 +Component638 -> Component337 +Component5 -> Component622 +Component814 -> Component914 +Component699 -> Component337 +Component472 -> Component262 +Component105 -> Component108 +Component519 -> Component575 +Component122 -> Component641 +Component27 -> Component683 +Component30 -> Component368 +Component947 -> Component361 +Component473 -> Component551 +Component195 -- Component865 +Component758 -> Component781 +Component988 -- Component322 +Component292 -- Component562 +Component94 -> Component179 +Component769 -- Component428 +Component813 -- Component177 +Component957 -> Component952 +Component361 -> Component268 +Component982 -- Component600 +Component771 -- Component657 +Component2 -> Component345 +Component90 -- Component447 +Component583 -> Component289 +Component478 -- Component980 +Component712 -- Component343 +Component203 -- Component449 +Component871 -> Component245 +Component446 -> Component557 +Component371 -- Component359 +Component664 -- Component272 +Component130 -> Component795 +Component383 -> Component371 +Component743 -> Component357 +Component949 -- Component591 +Component224 -> Component809 +Component401 -- Component928 +Component697 -- Component52 +Component523 -> Component549 +Component73 -> Component447 +Component39 -- Component682 +Component406 -- Component180 +Component653 -- Component605 +Component287 -> Component464 +Component600 -- Component794 +Component625 -> Component881 +Component402 -> Component53 +Component991 -- Component287 +Component267 -- Component157 +Component935 -- Component182 +Component368 -> Component689 +Component446 -> Component623 +Component95 -> Component969 +Component853 -> Component313 +Component227 -> Component415 +Component70 -- Component535 +Component877 -- Component64 +Component394 -> Component905 +Component811 -> Component339 +Component828 -- Component15 +Component4 -> Component752 +Component453 -> Component49 +Component604 -> Component990 +Component295 -- Component723 +Component562 -- Component691 +Component45 -- Component472 +Component284 -- Component226 +Component488 -- Component236 +Component542 -- Component143 +Component199 -> Component149 +Component629 -> Component805 +Component251 -- Component13 +Component44 -- Component301 +Component949 -> Component961 +Component187 -- Component713 +Component295 -- Component477 +Component284 -- Component505 +Component430 -- Component61 +Component504 -- Component579 +Component928 -- Component585 +Component864 -- Component173 +Component446 -> Component141 +Component471 -- Component749 +Component252 -> Component631 +Component520 -> Component375 +Component711 -> Component337 +Component360 -> Component985 +Component425 -- Component916 +Component288 -> Component466 +Component789 -> Component740 +Component235 -- Component578 +Component126 -- Component959 +Component800 -- Component367 +Component926 -> Component626 +Component19 -- Component799 +Component711 -> Component119 +Component31 -- Component805 +Component962 -> Component268 +Component254 -- Component192 +Component129 -> Component374 +Component173 -> Component244 +Component699 -- Component508 +Component767 -> Component372 +Component491 -> Component357 +Component301 -> Component935 +Component648 -- Component899 +Component748 -> Component97 +Component140 -> Component901 +Component503 -> Component68 +Component28 -- Component646 +Component38 -- Component713 +Component109 -- Component540 +Component186 -> Component519 +Component478 -- Component507 +Component885 -- Component794 +Component929 -- Component165 +Component207 -- Component615 +Component198 -- Component434 +Component919 -- Component880 +Component668 -> Component164 +Component1 -- Component792 +Component17 -- Component22 +Component215 -- Component796 +Component118 -> Component670 +Component480 -> Component506 +Component403 -- Component709 +Component864 -- Component180 +Component316 -> Component167 +Component652 -- Component916 +Component86 -- Component250 +Component664 -> Component26 + +[Note] (2.94, 40.45) Note 0: Important information here +[Note] (52.51, 36.04) Note 1: Important information here +[Note] (58.98, 66.79) Note 2: Important information here +[Note] (78.33, 13.50) Note 3: Important information here +[Note] (79.45, 45.42) Note 4: Important information here +[Note] (73.48, 17.13) Note 5: Important information here +[Note] (50.74, 42.61) Note 6: Important information here +[Note] (78.16, 67.95) Note 7: Important information here +[Note] (39.81, 97.76) Note 8: Important information here +[Note] (20.44, 8.41) Note 9: Important information here +[Note] (57.71, 68.13) Note 10: Important information here +[Note] (4.50, 43.31) Note 11: Important information here +[Note] (81.32, 0.57) Note 12: Important information here +[Note] (28.05, 35.60) Note 13: Important information here +[Note] (32.09, 5.25) Note 14: Important information here +[Note] (15.56, 33.99) Note 15: Important information here +[Note] (6.30, 36.55) Note 16: Important information here +[Note] (26.69, 87.57) Note 17: Important information here +[Note] (84.58, 54.27) Note 18: Important information here +[Note] (51.43, 97.01) Note 19: Important information here +[Note] (52.32, 80.60) Note 20: Important information here +[Note] (25.39, 94.75) Note 21: Important information here +[Note] (14.65, 36.06) Note 22: Important information here +[Note] (33.20, 19.14) Note 23: Important information here +[Note] (61.89, 14.32) Note 24: Important information here +[Note] (19.45, 14.75) Note 25: Important information here +[Note] (72.54, 34.44) Note 26: Important information here +[Note] (30.25, 60.76) Note 27: Important information here +[Note] (97.08, 95.72) Note 28: Important information here +[Note] (36.72, 82.06) Note 29: Important information here +[Note] (66.76, 96.51) Note 30: Important information here +[Note] (44.97, 98.71) Note 31: Important information here +[Note] (33.53, 71.85) Note 32: Important information here +[Note] (1.12, 36.27) Note 33: Important information here +[Note] (93.86, 41.54) Note 34: Important information here +[Note] (45.49, 97.58) Note 35: Important information here +[Note] (11.85, 27.02) Note 36: Important information here +[Note] (22.05, 41.78) Note 37: Important information here +[Note] (24.21, 47.46) Note 38: Important information here +[Note] (35.59, 77.67) Note 39: Important information here +[Note] (60.38, 33.28) Note 40: Important information here +[Note] (11.99, 57.45) Note 41: Important information here +[Note] (36.12, 68.56) Note 42: Important information here +[Note] (12.09, 2.53) Note 43: Important information here +[Note] (76.81, 69.61) Note 44: Important information here +[Note] (90.95, 51.34) Note 45: Important information here +[Note] (62.74, 25.63) Note 46: Important information here +[Note] (23.00, 12.92) Note 47: Important information here +[Note] (89.56, 11.80) Note 48: Important information here +[Note] (91.20, 54.14) Note 49: Important information here +[Note] (9.82, 29.43) Note 50: Important information here +[Note] (39.10, 54.60) Note 51: Important information here +[Note] (18.37, 26.61) Note 52: Important information here +[Note] (73.22, 5.28) Note 53: Important information here +[Note] (48.00, 29.66) Note 54: Important information here +[Note] (29.62, 96.82) Note 55: Important information here +[Note] (43.04, 99.15) Note 56: Important information here +[Note] (35.35, 59.90) Note 57: Important information here +[Note] (14.89, 41.05) Note 58: Important information here +[Note] (63.43, 25.91) Note 59: Important information here +[Note] (8.89, 85.37) Note 60: Important information here +[Note] (40.78, 28.82) Note 61: Important information here +[Note] (45.40, 95.24) Note 62: Important information here +[Note] (38.42, 69.68) Note 63: Important information here +[Note] (98.58, 97.72) Note 64: Important information here +[Note] (55.42, 94.26) Note 65: Important information here +[Note] (79.78, 9.46) Note 66: Important information here +[Note] (74.35, 80.17) Note 67: Important information here +[Note] (51.98, 69.94) Note 68: Important information here +[Note] (10.33, 99.47) Note 69: Important information here +[Note] (49.91, 26.62) Note 70: Important information here +[Note] (99.67, 89.15) Note 71: Important information here +[Note] (83.91, 73.43) Note 72: Important information here +[Note] (96.77, 80.50) Note 73: Important information here +[Note] (79.78, 29.10) Note 74: Important information here +[Note] (73.99, 22.14) Note 75: Important information here +[Note] (0.40, 71.89) Note 76: Important information here +[Note] (96.44, 0.13) Note 77: Important information here +[Note] (37.22, 36.88) Note 78: Important information here +[Note] (49.86, 14.12) Note 79: Important information here +[Note] (54.71, 0.77) Note 80: Important information here +[Note] (91.08, 10.71) Note 81: Important information here +[Note] (82.91, 82.87) Note 82: Important information here +[Note] (16.74, 3.24) Note 83: Important information here +[Note] (72.61, 55.76) Note 84: Important information here +[Note] (11.39, 18.81) Note 85: Important information here +[Note] (95.79, 22.32) Note 86: Important information here +[Note] (2.01, 62.41) Note 87: Important information here +[Note] (13.64, 62.81) Note 88: Important information here +[Note] (57.72, 29.73) Note 89: Important information here +[Note] (75.37, 73.59) Note 90: Important information here +[Note] (61.03, 3.80) Note 91: Important information here +[Note] (48.59, 37.15) Note 92: Important information here +[Note] (22.25, 75.74) Note 93: Important information here +[Note] (93.34, 15.31) Note 94: Important information here +[Note] (29.08, 62.29) Note 95: Important information here +[Note] (90.50, 87.93) Note 96: Important information here +[Note] (16.57, 55.43) Note 97: Important information here +[Note] (94.92, 72.00) Note 98: Important information here +[Note] (76.78, 69.76) Note 99: Important information here + +[Group] Component166, Component358, Component162, Component735, Component888, Component887 +[Group] Component813, Component533, Component171, Component890, Component903, Component427, Component946, Component701, Component485 +[Group] Component361, Component442, Component616, Component723, Component141 +[Group] Component928, Component96, Component157, Component210, Component556 +[Group] Component640, Component776, Component24, Component77, Component122, Component770, Component749, Component138, Component885 +[Group] Component321, Component517, Component33, Component560, Component553, Component851, Component109, Component798, Component164 +[Group] Component750, Component439, Component500, Component242, Component758 +[Group] Component631, Component186, Component77, Component263, Component342, Component988, Component55, Component868 +[Group] Component700, Component735, Component71, Component491, Component265, Component584, Component703, Component858 +[Group] Component34, Component461, Component400, Component364, Component53 +[Group] Component328, Component186, Component561, Component769, Component403, Component477, Component319, Component319, Component512 +[Group] Component773, Component847, Component838, Component153, Component187, Component545, Component450, Component125, Component610, Component328 +[Group] Component7, Component340, Component456, Component183, Component990, Component303, Component767 +[Group] Component777, Component607, Component466, Component751, Component848, Component803, Component994, Component561 +[Group] Component773, Component278, Component623, Component201, Component281 +[Group] Component357, Component963, Component582, Component828, Component733, Component258, Component904, Component261, Component277, Component949 +[Group] Component906, Component471, Component230, Component135, Component370, Component930, Component74, Component177, Component389 +[Group] Component836, Component154, Component590, Component2, Component459, Component732, Component512, Component759, Component760, Component840 +[Group] Component625, Component499, Component9, Component58, Component259, Component602, Component488, Component176, Component221, Component781 +[Group] Component202, Component212, Component576, Component111, Component612, Component856, Component916 +[Group] Component517, Component296, Component112, Component53, Component760, Component856, Component209, Component31, Component638 +[Group] Component237, Component717, Component314, Component724, Component896, Component946, Component228, Component563, Component994, Component18 +[Group] Component102, Component958, Component317, Component552, Component821, Component802, Component725, Component856, Component878, Component922 +[Group] Component638, Component280, Component163, Component527, Component205, Component74, Component753, Component170, Component172, Component610 +[Group] Component885, Component857, Component835, Component834, Component599, Component965 +[Group] Component355, Component341, Component305, Component329, Component705, Component665 +[Group] Component933, Component454, Component769, Component783, Component454, Component118, Component616 +[Group] Component659, Component141, Component574, Component505, Component259, Component538, Component250, Component383, Component374, Component948 +[Group] Component22, Component487, Component234, Component640, Component450, Component55 +[Group] Component110, Component166, Component875, Component745, Component109 +[Group] Component536, Component346, Component210, Component131, Component732, Component786, Component506, Component834, Component773, Component285 +[Group] Component562, Component401, Component560, Component186, Component710, Component41, Component519, Component902, Component489, Component304 +[Group] Component895, Component503, Component939, Component501, Component255 +[Group] Component344, Component39, Component167, Component74, Component680, Component962, Component789, Component528, Component199 +[Group] Component24, Component917, Component390, Component67, Component184, Component502, Component131 +[Group] Component146, Component868, Component949, Component619, Component382 +[Group] Component263, Component544, Component629, Component77, Component983, Component303 +[Group] Component873, Component161, Component398, Component672, Component847, Component834, Component364 +[Group] Component78, Component511, Component14, Component998, Component276 +[Group] Component161, Component681, Component53, Component139, Component606 +[Group] Component651, Component241, Component157, Component273, Component316, Component233, Component725, Component317 +[Group] Component347, Component471, Component365, Component748, Component266, Component849, Component868, Component478, Component320 +[Group] Component702, Component625, Component547, Component230, Component791, Component492, Component484 +[Group] Component294, Component37, Component146, Component889, Component343, Component761, Component100 +[Group] Component62, Component902, Component833, Component184, Component124, Component322, Component346, Component874, Component785 +[Group] Component838, Component501, Component979, Component48, Component404, Component24, Component644, Component759, Component138, Component470 +[Group] Component764, Component133, Component294, Component987, Component134, Component160, Component60 +[Group] Component916, Component310, Component269, Component134, Component967, Component418, Component946, Component333 +[Group] Component983, Component468, Component392, Component878, Component42, Component643, Component428, Component967, Component559, Component133 +[Group] Component928, Component925, Component32, Component478, Component979, Component488, Component674 + +[Inertia] Component269 +[Inertia] Component778 +[Inertia] Component942 +[Inertia] Component159 +[Inertia] Component579 +[Inertia] Component156 +[Inertia] Component864 +[Inertia] Component25 +[Inertia] Component940 +[Inertia] Component571 +[Inertia] Component124 +[Inertia] Component206 +[Inertia] Component353 +[Inertia] Component695 +[Inertia] Component549 +[Inertia] Component118 +[Inertia] Component914 +[Inertia] Component67 +[Inertia] Component73 +[Inertia] Component688 +[Inertia] Component413 +[Inertia] Component828 +[Inertia] Component720 +[Inertia] Component31 +[Inertia] Component203 +[Inertia] Component835 +[Inertia] Component73 +[Inertia] Component770 +[Inertia] Component340 +[Inertia] Component608 +[Inertia] Component82 +[Inertia] Component349 +[Inertia] Component972 +[Inertia] Component63 +[Inertia] Component30 +[Inertia] Component392 +[Inertia] Component455 +[Inertia] Component910 +[Inertia] Component76 +[Inertia] Component843 +[Inertia] Component120 +[Inertia] Component831 +[Inertia] Component555 +[Inertia] Component531 +[Inertia] Component850 +[Inertia] Component991 +[Inertia] Component789 +[Inertia] Component834 +[Inertia] Component341 +[Inertia] Component611 +[Inertia] Component990 +[Inertia] Component599 +[Inertia] Component872 +[Inertia] Component44 +[Inertia] Component574 +[Inertia] Component727 +[Inertia] Component525 +[Inertia] Component73 +[Inertia] Component539 +[Inertia] Component596 +[Inertia] Component458 +[Inertia] Component982 +[Inertia] Component1 +[Inertia] Component604 +[Inertia] Component573 +[Inertia] Component208 +[Inertia] Component317 +[Inertia] Component815 +[Inertia] Component81 +[Inertia] Component703 +[Inertia] Component949 +[Inertia] Component634 +[Inertia] Component651 +[Inertia] Component687 +[Inertia] Component430 +[Inertia] Component407 +[Inertia] Component802 +[Inertia] Component716 +[Inertia] Component348 +[Inertia] Component769 +[Inertia] Component684 +[Inertia] Component260 +[Inertia] Component52 +[Inertia] Component707 +[Inertia] Component99 +[Inertia] Component100 +[Inertia] Component776 +[Inertia] Component104 +[Inertia] Component489 +[Inertia] Component702 +[Inertia] Component923 +[Inertia] Component927 +[Inertia] Component409 +[Inertia] Component149 +[Inertia] Component816 +[Inertia] Component170 +[Inertia] Component953 +[Inertia] Component816 +[Inertia] Component83 +[Inertia] Component65 + +[Evolution] Component902 + 9.56 +[Evolution] Component565 + 6.91 +[Evolution] Component691 + 46.82 +[Evolution] Component502 - 45.86 +[Evolution] Component298 - 11.79 +[Evolution] Component902 - 29.01 +[Evolution] Component313 + 20.43 +[Evolution] Component452 - 21.03 +[Evolution] Component489 + 42.37 +[Evolution] Component59 + 26.46 +[Evolution] Component124 - 48.39 +[Evolution] Component920 - 47.99 +[Evolution] Component835 - 44.60 +[Evolution] Component408 + 9.26 +[Evolution] Component381 + 7.89 +[Evolution] Component822 + 37.66 +[Evolution] Component244 + 3.26 +[Evolution] Component294 + 38.15 +[Evolution] Component985 - 14.38 +[Evolution] Component810 + 3.40 +[Evolution] Component0 - 19.05 +[Evolution] Component976 + 6.90 +[Evolution] Component516 + 30.13 +[Evolution] Component193 + 10.17 +[Evolution] Component653 - 28.96 +[Evolution] Component29 + 48.14 +[Evolution] Component810 + 6.28 +[Evolution] Component617 + 2.99 +[Evolution] Component228 + 35.90 +[Evolution] Component164 + 33.70 +[Evolution] Component297 - 42.43 +[Evolution] Component42 + 47.32 +[Evolution] Component752 + 21.97 +[Evolution] Component930 - 38.23 +[Evolution] Component305 - 49.76 +[Evolution] Component748 + 41.84 +[Evolution] Component2 - 41.73 +[Evolution] Component524 + 6.93 +[Evolution] Component350 + 36.75 +[Evolution] Component129 + 24.85 +[Evolution] Component934 + 42.24 +[Evolution] Component568 - 45.29 +[Evolution] Component18 + 27.95 +[Evolution] Component125 + 42.13 +[Evolution] Component843 - 25.92 +[Evolution] Component502 - 7.53 +[Evolution] Component845 + 41.54 +[Evolution] Component269 + 47.41 +[Evolution] Component440 + 23.12 +[Evolution] Component370 - 14.15 +[Evolution] Component885 + 27.46 +[Evolution] Component512 - 18.65 +[Evolution] Component313 - 41.73 +[Evolution] Component173 + 21.42 +[Evolution] Component182 + 32.77 +[Evolution] Component681 + 0.34 +[Evolution] Component71 - 0.81 +[Evolution] Component256 + 30.35 +[Evolution] Component380 - 30.76 +[Evolution] Component790 - 4.48 +[Evolution] Component329 - 8.79 +[Evolution] Component456 - 22.37 +[Evolution] Component829 - 40.43 +[Evolution] Component586 + 20.49 +[Evolution] Component918 - 13.15 +[Evolution] Component638 + 22.34 +[Evolution] Component41 + 31.82 +[Evolution] Component958 - 26.38 +[Evolution] Component43 - 19.16 +[Evolution] Component287 + 19.71 +[Evolution] Component33 - 17.17 +[Evolution] Component826 - 44.03 +[Evolution] Component290 + 24.18 +[Evolution] Component17 - 4.30 +[Evolution] Component550 + 3.36 +[Evolution] Component262 - 29.09 +[Evolution] Component472 + 10.38 +[Evolution] Component792 - 2.78 +[Evolution] Component79 + 20.09 +[Evolution] Component695 + 36.78 +[Evolution] Component413 + 7.77 +[Evolution] Component937 + 41.23 +[Evolution] Component749 + 39.04 +[Evolution] Component970 + 37.45 +[Evolution] Component748 - 10.69 +[Evolution] Component16 - 19.91 +[Evolution] Component10 + 2.90 +[Evolution] Component337 + 21.52 +[Evolution] Component190 + 13.97 +[Evolution] Component773 + 25.37 +[Evolution] Component16 - 41.09 +[Evolution] Component387 + 46.74 +[Evolution] Component355 - 46.48 +[Evolution] Component511 - 26.32 +[Evolution] Component4 + 36.69 +[Evolution] Component811 + 30.11 +[Evolution] Component885 - 28.46 +[Evolution] Component854 - 41.72 +[Evolution] Component493 + 40.34 +[Evolution] Component541 - 6.05
\ No newline at end of file diff --git a/Documentation/wmap-spec.ebnf b/Documentation/wmap-spec.ebnf new file mode 100644 index 0000000..6ad79c6 --- /dev/null +++ b/Documentation/wmap-spec.ebnf @@ -0,0 +1,52 @@ +(* wmap Language Specification *) + +(* Top-level structure *) +program = { line } ; +line = ( entity line_ending ) | ( ignored_line line_ending ) | line_ending ; + +entity = component | dependency | note | stage | group | inertia | evolution ; +ignored_line = ? any sequence of tokens that doesn't match entity grammar ? ; + +(* Entities *) +component = component_label position [ shape ] ; +dependency = component_label dependency_type component_label ; +note = case_insensitive("[Note]") position text ; +stage = "[" stage_number "]" real_number ; +group = case_insensitive("[Group]") component_label { "," component_label } ; +inertia = case_insensitive("[Inertia]") component_label ; +evolution = case_insensitive("[Evolution]") component_label sign real_number ; + +(* Component definitions *) +position = "(" real_number "," real_number ")" ; +shape = "[" shape_label "]" ; +dependency_type = "--" | "->" ; +sign = "+" | "-" ; + +(* Terminal symbols *) +component_label = preserved_case( { character - ( "-" | "+" | "," | "[" | "]" | "(" | ")" | line_ending ) } ) ; +text = preserved_case( { character - line_ending } ) ; +real_number = [ digit ] { digit } [ "." { digit } ] | "." digit { digit } ; +stage_number = case_insensitive( "i" | "ii" | "iii" | "iv" ) ; +shape_label = case_insensitive( "x" | "square" | "triangle" | "circle" ) ; + +(* Lexical elements *) +character = ? any Unicode character ? ; +digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ; +line_ending = lf | crlf | cr ; +lf = ? U+000A (Line Feed) ? ; +cr = ? U+000D (Carriage Return) ? ; +crlf = cr lf ; + +(* Lexical rules *) +case_insensitive(x) = ? case-insensitive match of x ? ; +preserved_case(x) = ? case-insensitive match of x, preserving original case for display ? ; + +(* Notes *) +(* - Keywords and shape labels are case-insensitive *) +(* - Component labels are case-insensitive for matching but preserve original case *) +(* - Text content preserves original case *) +(* - Whitespace (except line endings) may appear between any tokens *) +(* - Each line contains exactly one entity *) +(* - Invalid lines should be ignored *) +(* - Line endings support Unix (LF), Windows (CRLF), and classic Mac (CR) formats *) +(* - CRLF is treated as a single line ending, not separate CR and LF *) @@ -0,0 +1,661 @@ +GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + wmap-parser-rust, Javascript wmap wardley map file parser. + Copyright (C) 2025 Ruben Beltran del Rio + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +<https://www.gnu.org/licenses/>. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..14a2e2c --- /dev/null +++ b/Makefile @@ -0,0 +1,32 @@ +profile := debug +target = $(shell rustc -vV | grep host | awk '{print $$2}') + +default: build + +set_rust: + rustup default stable + +build: + swift build -c $(profile) + +test: + swift test + +coverage: + swift test --enable-code-coverage + xcrun llvm-cov report \ + .build/debug/WmapParserPackageTests.xctest/Contents/MacOS/WmapParserPackageTests \ + -instr-profile=.build/debug/codecov/default.profdata + +benchmark: + swift package benchmark --target ParseBenchmarkTarget + +format: + swiftlint --fix Sources Tests + +lint: + swiftlint Sources Tests + +ci: lint test + +.PHONY: default set_rust build test coverage format lint benchmark ci diff --git a/Package.resolved b/Package.resolved new file mode 100644 index 0000000..afa9e79 --- /dev/null +++ b/Package.resolved @@ -0,0 +1,78 @@ +{ + "originHash" : "96ef41dfb49c835cb0b8ea3eb973652f1b78224f412d02ea25fb3c40dbac6758", + "pins" : [ + { + "identity" : "hdrhistogram-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/HdrHistogram/hdrhistogram-swift.git", + "state" : { + "revision" : "93a1618c8aa20f6a521a9da656a3e0591889e9dc", + "version" : "0.1.3" + } + }, + { + "identity" : "package-benchmark", + "kind" : "remoteSourceControl", + "location" : "https://github.com/ordo-one/package-benchmark", + "state" : { + "revision" : "5dcae6e635a33731a9385be50a972e099b08e429", + "version" : "1.29.6" + } + }, + { + "identity" : "package-jemalloc", + "kind" : "remoteSourceControl", + "location" : "https://github.com/ordo-one/package-jemalloc.git", + "state" : { + "revision" : "e8a5db026963f5bfeac842d9d3f2cc8cde323b49", + "version" : "1.0.0" + } + }, + { + "identity" : "swift-argument-parser", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-argument-parser.git", + "state" : { + "revision" : "cdd0ef3755280949551dc26dee5de9ddeda89f54", + "version" : "1.6.2" + } + }, + { + "identity" : "swift-atomics", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-atomics.git", + "state" : { + "revision" : "b601256eab081c0f92f059e12818ac1d4f178ff7", + "version" : "1.3.0" + } + }, + { + "identity" : "swift-numerics", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-numerics", + "state" : { + "revision" : "0c0290ff6b24942dadb83a929ffaaa1481df04a2", + "version" : "1.1.1" + } + }, + { + "identity" : "swift-system", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-system.git", + "state" : { + "revision" : "395a77f0aa927f0ff73941d7ac35f2b46d47c9db", + "version" : "1.6.3" + } + }, + { + "identity" : "texttable", + "kind" : "remoteSourceControl", + "location" : "https://github.com/ordo-one/TextTable.git", + "state" : { + "revision" : "a27a07300cf4ae322e0079ca0a475c5583dd575f", + "version" : "0.0.2" + } + } + ], + "version" : 3 +} diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..130ae82 --- /dev/null +++ b/Package.swift @@ -0,0 +1,49 @@ +// swift-tools-version: 6.2 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "WmapParser", + platforms: [ + .macOS(.v13), + .iOS(.v16), + .macCatalyst(.v16) + ], + products: [ + // Products define the executables and libraries a package produces, making them visible to other packages. + .library( + name: "WmapParser", + targets: ["WmapParser"] + ) + ], + dependencies: [ + .package(url: "https://github.com/ordo-one/package-benchmark", .upToNextMajor(from: "1.0.0")) + ], + targets: [ + // Targets are the basic building blocks of a package, defining a module or a test suite. + // Targets can depend on other targets in this package and products from dependencies. + .target( + name: "WmapParser" + ), + .testTarget( + name: "WmapParserTests", + dependencies: ["WmapParser"] + ) + ] +) + +// Benchmark of ParseBenchmarkTarget +package.targets += [ + .executableTarget( + name: "ParseBenchmarkTarget", + dependencies: [ + .product(name: "Benchmark", package: "package-benchmark"), + "WmapParser" + ], + path: "Benchmarks/ParseBenchmarkTarget", + plugins: [ + .plugin(name: "BenchmarkPlugin", package: "package-benchmark") + ] + ) +] diff --git a/README.md b/README.md new file mode 100644 index 0000000..eefb8d7 --- /dev/null +++ b/README.md @@ -0,0 +1,117 @@ +# wmap-parser-swift + +A parser for `wmap` formatted Wardley Map files built in Swift. + +## Features + +* No dependencies. +* Free software. +* Reasonably fast. + +## Installation + +Add it to your project using Swift Package Manager by adding the following to your `Package.swift`: + +```swift +dependencies: [ + .package(url: "https://git.sr.ht/~rbdr/wmap-parser-swift", from: "1.0.0") +] +``` + +Or add it directly in Xcode using File > Add Packages... + +## Usage + +```swift +import WmapParser + +let wmapSource = """ +[I] 0.25 +[II] 0.5 +[III] 0.75 +[IV] 1.0 + +Tea (0.9, 0.5) [Circle] +Cup (0.8, 0.4) +Hot Water (0.6, 0.2) + +Tea -> Cup +Cup -> Hot Water + +[Note] (0.5, 0.5) Supply chain for tea +[Group] Tea, Cup +[Inertia] Cup +[Evolution] Tea + 0.1 +""" + +let map = parse(wmapSource) + +print(map.components) +// [ +// Component(label: "Tea", coordinates: (0.9, 0.5), shape: .circle), +// Component(label: "Cup", coordinates: (0.8, 0.4), shape: .circle), +// ... +// ] + +print(map.dependencies) +// [ +// Dependency(from: "Tea", to: "Cup", isDirected: true), +// ... +// ] +``` + +## API + +### `parse(_ source: String) -> Map` + +Parses a wmap formatted string and returns a Map object. + +**Parameters:** + +- `source` (String): The wmap source code to parse + +**Returns:** + +- `Map`: A Map struct containing the parsed components, dependencies, notes, + stages, groups, inertias, and evolutions + +## Format Specification + +See [The map website](https://map.tranquil.systems) for more information on the +format. + +## Reasonably Fast + +Benchmarked on an M1 Pro mac. A map with around 120 entities parses in 14µs. +While a larger map with slightly under 2000 entities does so in 230µs. + +You can run the benchmarks by using: + +```bash +make benchmark +``` + +## Development + +This project uses a Makefile to run all commands. This is to keep the +commands uniform with the other wmap-parser projects. + +### Running Tests + +```bash +make test +``` + +Or to see coverage + +```bash +make coverage +``` + +## See Also + +- [wmap specification](doc/wmap-spec.ebnf) - Formal grammar +- [wmap specification](https://git.sr.ht/~rbdr/wmap-parser-js) - Javascript wmap-parser +- [wmap specification](https://git.sr.ht/~rbdr/wmap-parser-c) - ANSI C wmap-parser +- [wmap specification](https://git.sr.ht/~rbdr/wmap-parser-rust) - Rust wmap-parser +- [Wardley Maps](https://wardleymaps.com/) - Learn about Wardley Mapping diff --git a/Sources/WmapParser/Component.swift b/Sources/WmapParser/Component.swift new file mode 100644 index 0000000..027ac59 --- /dev/null +++ b/Sources/WmapParser/Component.swift @@ -0,0 +1,6 @@ +/// A component in the map. +public struct Component: Sendable, Equatable { + public let label: String + public let coordinates: MapPoint + public let shape: Shape +} diff --git a/Sources/WmapParser/ComponentParser.swift b/Sources/WmapParser/ComponentParser.swift new file mode 100644 index 0000000..c899637 --- /dev/null +++ b/Sources/WmapParser/ComponentParser.swift @@ -0,0 +1,78 @@ +/// Parses a component with its coordinates. +func parseComponent<T: Collection>(_ bytes: T, _ start: Int, _ end: Int) -> Component? +where T.Element == UInt8, T.Index == Int { + guard let (label, parenthesisIndex) = extractComponentLabel(bytes, start, end) else { + return nil + } + + guard + let (coordinates, endIndex) = parseCoordinates( + bytes, parenthesisIndex + 1, end) + else { + return nil + } + + let shape = extractComponentShape(bytes, endIndex, end) + + return Component(label: label, coordinates: coordinates, shape: shape) +} + +/// Looks for a component label by taking the string before the first open +/// parenthesis. +@inline(__always) +private func extractComponentLabel<T: Collection>(_ bytes: T, _ start: Int, _ end: Int) -> ( + String, Int +)? +where T.Element == UInt8, T.Index == Int { + var index = start + while index < end { + if bytes[index] == kOpenParenthesis { + guard index > start else { return nil } + guard let label = extractTrimmedString(bytes, start, index) else { return nil } + return (label, index) + } + index += 1 + } + return nil +} + +/// Extracts a shape by looking for a shape label in square brackets. +/// If missing, incomplete or invalid, it returns a circle +@inline(__always) +private func extractComponentShape<T: Collection>(_ bytes: T, _ start: Int, _ end: Int) -> Shape +where T.Element == UInt8, T.Index == Int { + var index = skipWhitespace(bytes, end, start) + + guard index < end && bytes[index] == kOpenSquareBracket else { return .circle } + + index += 1 + let shapeStart = index + while index < end && bytes[index] != kCloseSquareBracket { index += 1 } + + guard index > shapeStart && index < end else { return .circle } + + let shapeName = bytes[shapeStart..<index] + return parseShapeFromBytes(shapeName) +} + +/// Given the contents of a shape label, return the right type. +@inline(__always) +private func parseShapeFromBytes<T: Collection>(_ shapeName: T) -> Shape +where T.Element == UInt8, T.Index == Int { + var trimStart = shapeName.startIndex + var trimEnd = shapeName.endIndex + + trimStart = skipWhitespace(shapeName, trimEnd, trimStart) + trimEnd = shaveWhitespace(shapeName, trimStart, trimEnd) + + let trimmedName = shapeName[trimStart..<trimEnd] + + // "x" + if matchesKeyword(trimmedName, [120]) { return .xMark } + // "square" + if matchesKeyword(trimmedName, [115, 113, 117, 97, 114, 101]) { return .square } + // "triangle" + if matchesKeyword(trimmedName, [116, 114, 105, 97, 110, 103, 108, 101]) { return .triangle } + + return .circle +} diff --git a/Sources/WmapParser/Constants.swift b/Sources/WmapParser/Constants.swift new file mode 100644 index 0000000..73340b6 --- /dev/null +++ b/Sources/WmapParser/Constants.swift @@ -0,0 +1,35 @@ +// Whitespace +let kNewline = 10 +let kCarriageReturn = 13 +let kTab = 9 +let kSpace = 32 + +// Punctuation +let kOpenParenthesis = 40 +let kCloseParenthesis = 41 +let kPlus = 43 +let kComma = 44 +let kDash = 45 +let kPeriod = 46 +let kGreaterThan = 62 +let kOpenSquareBracket = 91 +let kCloseSquareBracket = 93 + +// Letters +let kCapitalA = 65 +let kCapitalZ = 90 +let kCapsToLowercaseDistance: UInt8 = 32 + +// Numbers +let kZero = 48 +let kNine = 57 + +// Keywords. ASCII representations of the keywords. +let kInertiaKeyword: [UInt8] = [105, 110, 101, 114, 116, 105, 97] +let kEvolutionKeyword: [UInt8] = [101, 118, 111, 108, 117, 116, 105, 111, 110] +let kNoteKeyword: [UInt8] = [110, 111, 116, 101] +let kGroupKeyword: [UInt8] = [103, 114, 111, 117, 112] +let kIKeyword: [UInt8] = [105] +let kIIKeyword: [UInt8] = [105, 105] +let kIIIKeyword: [UInt8] = [105, 105, 105] +let kIVKeyword: [UInt8] = [105, 118] diff --git a/Sources/WmapParser/Dependency.swift b/Sources/WmapParser/Dependency.swift new file mode 100644 index 0000000..38f03be --- /dev/null +++ b/Sources/WmapParser/Dependency.swift @@ -0,0 +1,6 @@ +/// A dependency between two components. +public struct Dependency: Sendable, Equatable { + public let fromComponent: String + public let toComponent: String + public let isDirected: Bool +} diff --git a/Sources/WmapParser/DependencyParser.swift b/Sources/WmapParser/DependencyParser.swift new file mode 100644 index 0000000..9964d5a --- /dev/null +++ b/Sources/WmapParser/DependencyParser.swift @@ -0,0 +1,50 @@ +/// Looks for -- or ->. If found, returns where this arrow starts. +@inline(__always) +func hasDependency<T: Collection>(_ bytes: T, _ start: Int, _ end: Int) -> Int? +where T.Element == UInt8, T.Index == Int { + var index = start + while index < end { + if bytes[index] == kOpenParenthesis { return nil } + if bytes[index] == kDash && index + 1 < end { + let next = bytes[index + 1] + if next == kGreaterThan || next == kDash { return index } + } + index += 1 + } + return nil +} + +/// Finds a dependency and whether it's directed. It assumes we previously +/// checked for the location of our separator to speed things up. +func parseDependency<T: Collection>(_ bytes: T, _ start: Int, _ end: Int, _ separatorIndex: Int) + -> Dependency? +where T.Element == UInt8, T.Index == Int { + guard let isDirected = extractIsDirected(bytes, separatorIndex, end) else { + return nil + } + + guard let fromComponent = extractTrimmedString(bytes, start, separatorIndex) else { + return nil + } + + guard let toComponent = extractTrimmedString(bytes, separatorIndex + 2, end) else { + return nil + } + + return Dependency(fromComponent: fromComponent, toComponent: toComponent, isDirected: isDirected) +} + +/// Checks the second character of the separator to see if it's directed. +/// It assumes we already checked for -- or ->, so it only checks for +/// Whether it's greaterThan or not. +@inline(__always) +private func extractIsDirected<T: Collection>(_ bytes: T, _ separatorIndex: Int, _ end: Int) + -> Bool? +where T.Element == UInt8, T.Index == Int { + let followingCharacter = separatorIndex + 1 + guard followingCharacter < end else { return nil } + if bytes[followingCharacter] == kGreaterThan { + return true + } + return false +} diff --git a/Sources/WmapParser/Evolution.swift b/Sources/WmapParser/Evolution.swift new file mode 100644 index 0000000..df6dd33 --- /dev/null +++ b/Sources/WmapParser/Evolution.swift @@ -0,0 +1,5 @@ +/// Evolution associated with a component. +public struct Evolution: Sendable, Equatable { + public let component: String + public let value: Double +} diff --git a/Sources/WmapParser/Group.swift b/Sources/WmapParser/Group.swift new file mode 100644 index 0000000..5204d45 --- /dev/null +++ b/Sources/WmapParser/Group.swift @@ -0,0 +1,4 @@ +/// A group of components. +public struct Group: Sendable, Equatable { + public let components: [String] +} diff --git a/Sources/WmapParser/Inertia.swift b/Sources/WmapParser/Inertia.swift new file mode 100644 index 0000000..e9be9c0 --- /dev/null +++ b/Sources/WmapParser/Inertia.swift @@ -0,0 +1,4 @@ +/// Inertia associated with a component. +public struct Inertia: Sendable, Equatable { + public let component: String +} diff --git a/Sources/WmapParser/KeywordParser.swift b/Sources/WmapParser/KeywordParser.swift new file mode 100644 index 0000000..8db1164 --- /dev/null +++ b/Sources/WmapParser/KeywordParser.swift @@ -0,0 +1,184 @@ +/// Checks which keyword we're dealing with and routes it to the right parser. +func parseKeywordLine<T: Collection>( + _ bytes: T, _ start: Int, _ end: Int, + _ context: inout KeywordParserContext +) where T.Element == UInt8, T.Index == Int { + guard let (keyword, rest) = extractKeyword(bytes, start, end) else { return } + + if matchesKeyword(keyword, kInertiaKeyword), let inertia = parseInertia(bytes, rest, end) { + context.inertias.append(inertia) + } else if matchesKeyword(keyword, kEvolutionKeyword), + let evolution = parseEvolution(bytes, rest, end) { + context.evolutions.append(evolution) + } else if matchesKeyword(keyword, kNoteKeyword), let note = parseNote(bytes, rest, end) { + context.notes.append(note) + } else if matchesKeyword(keyword, kGroupKeyword), let group = parseGroup(bytes, rest, end) { + context.groups.append(group) + } else if let stageNumber = isStageKeyword(keyword), + let stage = parseStage(bytes, stageNumber, rest, end) { + context.stages.append(stage) + } +} + +/// Extracts a keyword from inside brackets. + the index of the rest of the +/// line. +@inline(__always) +func extractKeyword<T: Collection>(_ bytes: T, _ start: Int, _ end: Int) -> (T.SubSequence, Int)? +where T.Element == UInt8, T.Index == Int { + var index = start + 1 // Skip '[' + let keywordStart = index + + while index < end && bytes[index] != kCloseSquareBracket { index += 1 } // Find ']' + if index >= end { return nil } + + let keywordEnd = index + index += 1 + + // Skip whitespace after ']' + index = skipWhitespace(bytes, end, index) + + return (bytes[keywordStart..<keywordEnd], index) +} + +/// Checks the four potential values for the stage keyword. +@inline(__always) +func isStageKeyword<T: Collection>(_ keyword: T) -> StageNumber? +where T.Element == UInt8, T.Index == Int { + if matchesKeyword(keyword, kIKeyword) { + return .stageI + } + if matchesKeyword(keyword, kIIKeyword) { + return .stageII + } + if matchesKeyword(keyword, kIIIKeyword) { + return .stageIII + } + if matchesKeyword(keyword, kIVKeyword) { + return .stageIV + } + return nil +} + +/// Compares a collection of bytes against a list of bytes. +/// Short-Circuits by length, only two have the same length (ii and iv) +@inline(__always) +func matchesKeyword<T: Collection>(_ keyword: T, _ expected: [UInt8]) -> Bool +where T.Element == UInt8, T.Index == Int { + guard keyword.count == expected.count else { return false } + var keywordIndex = keyword.startIndex + for index in 0..<expected.count { + let currentKeyword = keyword[keywordIndex] + let expectedKeyword = expected[index] + + let lowercasedKeyword = + (currentKeyword >= kCapitalA && currentKeyword <= kCapitalZ) + ? currentKeyword + kCapsToLowercaseDistance : currentKeyword + if lowercasedKeyword != expectedKeyword { return false } + keywordIndex += 1 + } + return true +} + +/// Parses the stage. Assumes we got the stage number in the keyword check +/// to avoid checking twice. +func parseStage<T: Collection>( + _ bytes: T, _ stageNumber: StageNumber, _ start: Int, _ end: Int +) -> Stage? +where T.Element == UInt8, T.Index == Int { + guard let value = parseDouble(bytes, start, end) else { return nil } + + return Stage(stage: stageNumber, value: value) +} + +/// Parses the note coordinates and text. +func parseNote<T: Collection>(_ bytes: T, _ start: Int, _ end: Int) -> Note? +where T.Element == UInt8, T.Index == Int { + var index = skipWhitespace(bytes, end, start) + + guard index < end && bytes[index] == kOpenParenthesis else { return nil } + index += 1 + + guard let (coordinates, endIndex) = parseCoordinates(bytes, index, end) else { + return nil + } + index = skipWhitespace(bytes, end, endIndex) + + let textEnd = shaveWhitespace(bytes, index, end) + + // Why not String(data:encoding:)? This is much faster. + // swiftlint:disable:next optional_data_string_conversion + let text = String(decoding: bytes[index..<textEnd], as: UTF8.self) + return Note(text: text, coordinates: coordinates) +} + +/// Parses the comma separated labels for a group +func parseGroup<T: Collection>(_ bytes: T, _ start: Int, _ end: Int) -> Group? +where T.Element == UInt8, T.Index == Int { + var components = [String]() + var index = start + var componentStart = start + + while index <= end { + if index == end || bytes[index] == kComma { + let trimStart = skipWhitespace(bytes, index, componentStart) + let trimEnd = shaveWhitespace(bytes, trimStart, index) + + if trimStart < trimEnd { + // Why not String(data:encoding:)? This is much faster. + // swiftlint:disable:next optional_data_string_conversion + let component = String(decoding: bytes[trimStart..<trimEnd], as: UTF8.self) + components.append(component) + } + + componentStart = index + 1 + } + index += 1 + } + + return components.isEmpty ? nil : Group(components: components) +} + +/// Parses the component label for inertia +func parseInertia<T: Collection>(_ bytes: T, _ start: Int, _ end: Int) -> Inertia? +where T.Element == UInt8, T.Index == Int { + let trimStart = skipWhitespace(bytes, end, start) + let trimEnd = shaveWhitespace(bytes, trimStart, end) + + guard trimStart < trimEnd else { return nil } + + // Why not String(data:encoding:)? This is much faster. + // swiftlint:disable:next optional_data_string_conversion + let component = String(decoding: bytes[trimStart..<trimEnd], as: UTF8.self) + return Inertia(component: component) +} + +/// Parses the component label and value for inertia +func parseEvolution<T: Collection>(_ bytes: T, _ start: Int, _ end: Int) -> Evolution? +where T.Element == UInt8, T.Index == Int { + var signIndex: Int? + var sign = 1.0 + + var index = start + while index < end { + if bytes[index] == kPlus || bytes[index] == kDash { + signIndex = index + sign = bytes[index] == 45 ? -1.0 : 1.0 + break + } + index += 1 + } + + guard let signIndex, signIndex > start else { return nil } + + let trimStart = skipWhitespace(bytes, signIndex, start) + let trimEnd = shaveWhitespace(bytes, trimStart, signIndex) + + guard trimStart < trimEnd else { return nil } + + // Why not String(data:encoding:)? This is much faster. + // swiftlint:disable:next optional_data_string_conversion + let component = String(decoding: bytes[trimStart..<trimEnd], as: UTF8.self) + guard let value = parseDouble(bytes, signIndex + 1, end) else { return nil } + + return Evolution(component: component, value: sign * value) +} diff --git a/Sources/WmapParser/KeywordParserContext.swift b/Sources/WmapParser/KeywordParserContext.swift new file mode 100644 index 0000000..1b889b3 --- /dev/null +++ b/Sources/WmapParser/KeywordParserContext.swift @@ -0,0 +1,7 @@ +struct KeywordParserContext { + var stages: [Stage] + var notes: [Note] + var groups: [Group] + var inertias: [Inertia] + var evolutions: [Evolution] +} diff --git a/Sources/WmapParser/Map.swift b/Sources/WmapParser/Map.swift new file mode 100644 index 0000000..7a25686 --- /dev/null +++ b/Sources/WmapParser/Map.swift @@ -0,0 +1,10 @@ +/// A parsed wardley map. +public struct Map: Sendable { + public let components: [Component] + public let dependencies: [Dependency] + public let notes: [Note] + public let stages: [Stage] + public let groups: [Group] + public let inertias: [Inertia] + public let evolutions: [Evolution] +} diff --git a/Sources/WmapParser/MapPoint.swift b/Sources/WmapParser/MapPoint.swift new file mode 100644 index 0000000..718ecab --- /dev/null +++ b/Sources/WmapParser/MapPoint.swift @@ -0,0 +1,5 @@ +/// A point in the map +public struct MapPoint: Sendable, Equatable { + let xCoordinate: Double + let yCoordinate: Double +} diff --git a/Sources/WmapParser/Note.swift b/Sources/WmapParser/Note.swift new file mode 100644 index 0000000..0db3739 --- /dev/null +++ b/Sources/WmapParser/Note.swift @@ -0,0 +1,5 @@ +/// A note. +public struct Note: Sendable, Equatable { + public let text: String + public let coordinates: MapPoint +} diff --git a/Sources/WmapParser/Shape.swift b/Sources/WmapParser/Shape.swift new file mode 100644 index 0000000..ea1844e --- /dev/null +++ b/Sources/WmapParser/Shape.swift @@ -0,0 +1,8 @@ +/// Any of the potential shapes in a component. +@frozen +public enum Shape: Sendable, Equatable { + case circle + case xMark + case square + case triangle +} diff --git a/Sources/WmapParser/Stage.swift b/Sources/WmapParser/Stage.swift new file mode 100644 index 0000000..78429e0 --- /dev/null +++ b/Sources/WmapParser/Stage.swift @@ -0,0 +1,5 @@ +/// An override for the width of an evolution stage. +public struct Stage: Sendable, Equatable { + public let stage: StageNumber + public let value: Double +} diff --git a/Sources/WmapParser/StageNumber.swift b/Sources/WmapParser/StageNumber.swift new file mode 100644 index 0000000..2e8a2da --- /dev/null +++ b/Sources/WmapParser/StageNumber.swift @@ -0,0 +1,8 @@ +/// The potential stages of evolution. +@frozen +public enum StageNumber: Sendable, Equatable { + case stageI + case stageII + case stageIII + case stageIV +} diff --git a/Sources/WmapParser/Utils.swift b/Sources/WmapParser/Utils.swift new file mode 100644 index 0000000..8bea13a --- /dev/null +++ b/Sources/WmapParser/Utils.swift @@ -0,0 +1,136 @@ +/// Check if a byte is a digit +@inline(__always) +func isDigit(_ byte: UInt8) -> Bool { + byte >= kZero && byte <= kNine +} + +/// Looks for x and y separated by a comma. +func parseCoordinates<T: Collection>(_ bytes: T, _ start: Int, _ end: Int) -> ( + MapPoint, Int +)? +where T.Element == UInt8, T.Index == Int { + var index = skipWhitespace(bytes, end, start) + + guard let (xCoordinate, nextIndex) = parseSingleCoordinate(bytes, index, end) else { + return nil + } + index = nextIndex + + guard expectComma(bytes, &index, end) else { return nil } + + guard let (yCoordinate, nextIndex) = parseSingleCoordinate(bytes, index, end) else { + return nil + } + index = nextIndex + + guard expectClosingParen(bytes, &index, end) else { return nil } + + return (MapPoint(xCoordinate: xCoordinate, yCoordinate: yCoordinate), index) +} + +/// Checks if a candidate for a coordinate is a digit, and parses it. +@inline(__always) +func parseSingleCoordinate<T: Collection>(_ bytes: T, _ start: Int, _ end: Int) -> (Double, Int)? +where T.Element == UInt8, T.Index == Int { + var index = start + while index < end && (isDigit(bytes[index]) || bytes[index] == 46) { index += 1 } + guard index > start else { return nil } + guard let value = parseDouble(bytes, start, index) else { return nil } + return (value, index) +} + +/// Advances the index until we find a comma. +@inline(__always) +func expectComma<T: Collection>(_ bytes: T, _ index: inout Int, _ end: Int) -> Bool +where T.Element == UInt8, T.Index == Int { + index = skipWhitespace(bytes, end, index) + guard index < end && bytes[index] == kComma else { return false } + index += 1 + index = skipWhitespace(bytes, end, index) + return true +} + +/// Advances the index until we find a closing parenthesis +@inline(__always) +func expectClosingParen<T: Collection>(_ bytes: T, _ index: inout Int, _ end: Int) -> Bool +where T.Element == UInt8, T.Index == Int { + index = skipWhitespace(bytes, end, index) + guard index < end && bytes[index] == kCloseParenthesis else { return false } + index += 1 + return true +} + +/// Parses a double +@inline(__always) +func parseDouble<T: Collection>(_ bytes: T, _ start: Int, _ end: Int) -> Double? +where T.Element == UInt8, T.Index == Int { + var index = skipWhitespace(bytes, end, start) + + let numStart = index + while index < end && (isDigit(bytes[index]) || bytes[index] == kPeriod) { index += 1 } + + guard index > numStart else { return nil } + + // Why not String(data:encoding:)? This is much faster. + // swiftlint:disable:next optional_data_string_conversion + let str = String(decoding: bytes[numStart..<index], as: UTF8.self) + return Double(str) +} + +/// Advances an index by looking for whitespace left-to-right +func skipWhitespace<T: Collection>(_ bytes: T, _ end: Int, _ start: Int) -> Int +where T.Element == UInt8, T.Index == Int { + var index = start + while index < end && (bytes[index] == kSpace || bytes[index] == kTab) { index += 1 } + return index +} + +/// Decreases an index by looking for whitespace right-to-left +func shaveWhitespace<T: Collection>(_ bytes: T, _ start: Int, _ end: Int) -> Int +where T.Element == UInt8, T.Index == Int { + var index = end + while index > start && (bytes[index - 1] == kSpace || bytes[index - 1] == kTab) { index -= 1 } + return index +} + +/// Given the bytes buffer, finds the next non-empty line. +@inline(__always) +func extractLine<T: Collection>(_ bytes: T, _ index: inout Int, _ length: Int) -> ( + Int, Int +)? +where T.Element == UInt8, T.Index == Int { + while index < length && (bytes[index] == kNewline || bytes[index] == kCarriageReturn) { + index += 1 + } + let lineStart = index + + while index < length && bytes[index] != kNewline && bytes[index] != kCarriageReturn { index += 1 } + if lineStart == index { return nil } + + var start = lineStart + var end = index + + start = skipWhitespace(bytes, end, start) + end = shaveWhitespace(bytes, start, end) + + if start == end { return nil } + + return (start, end) +} + +/// Trims a byte collection and returns a string +@inline(__always) +func extractTrimmedString<T: Collection>(_ bytes: T, _ start: Int, _ end: Int) -> String? +where T.Element == UInt8, T.Index == Int { + var trimStart = start + var trimEnd = end + + trimStart = skipWhitespace(bytes, trimEnd, trimStart) + trimEnd = shaveWhitespace(bytes, trimStart, trimEnd) + + guard trimStart < trimEnd else { return nil } + + // Why not String(data:encoding:)? This is much faster. + // swiftlint:disable:next optional_data_string_conversion + return String(decoding: bytes[trimStart..<trimEnd], as: UTF8.self) +} diff --git a/Sources/WmapParser/WmapParser.swift b/Sources/WmapParser/WmapParser.swift new file mode 100644 index 0000000..f2bef8f --- /dev/null +++ b/Sources/WmapParser/WmapParser.swift @@ -0,0 +1,79 @@ +import Foundation + +// Public API ////////////////////////////////////////////////////////////////// + +/// Parses a wmap source string. +public func parse(_ source: String) -> Map { + source.utf8.withContiguousStorageIfAvailable { bytes in + parseBytes(bytes) + } ?? parseBytes(Array(source.utf8)) +} + +// Parsers ///////////////////////////////////////////////////////////////////// + +struct LineParserContext { + var components: [Component] + var dependencies: [Dependency] + var keywordContext: KeywordParserContext +} + +/// Main parsing function, we work on bytes as it's faster. +private func parseBytes<T: Collection>(_ bytes: T) -> Map where T.Element == UInt8, T.Index == Int { + let estimatedLines = bytes.count / 30 + + var context = LineParserContext( + components: [], + dependencies: [], + keywordContext: KeywordParserContext( + stages: [], + notes: [], + groups: [], + inertias: [], + evolutions: [] + ) + ) + + context.components.reserveCapacity(estimatedLines) + context.dependencies.reserveCapacity(estimatedLines) + context.keywordContext.notes.reserveCapacity(estimatedLines / 10) + context.keywordContext.stages.reserveCapacity(4) + context.keywordContext.groups.reserveCapacity(estimatedLines / 20) + context.keywordContext.inertias.reserveCapacity(estimatedLines / 20) + context.keywordContext.evolutions.reserveCapacity(estimatedLines / 20) + + var index = 0 + let length = bytes.count + + while index < length { + guard let (start, end) = extractLine(bytes, &index, length) else { continue } + parseLine(bytes, start, end, &context) + } + + return Map( + components: context.components, + dependencies: context.dependencies, + notes: context.keywordContext.notes, + stages: context.keywordContext.stages, + groups: context.keywordContext.groups, + inertias: context.keywordContext.inertias, + evolutions: context.keywordContext.evolutions + ) +} + +/// Given a trimmed line, checks if it's a keyword, dependency or component +/// and parses it. +@inline(__always) +private func parseLine<T: Collection>( + _ bytes: T, _ start: Int, _ end: Int, + _ context: inout LineParserContext +) where T.Element == UInt8, T.Index == Int { + if bytes[start] == kOpenSquareBracket { + parseKeywordLine(bytes, start, end, &context.keywordContext) + } else if let separatorIndex = hasDependency(bytes, start, end) { + if let dependency = parseDependency(bytes, start, end, separatorIndex) { + context.dependencies.append(dependency) + } + } else if let component = parseComponent(bytes, start, end) { + context.components.append(component) + } +} diff --git a/Tests/WmapParserTests/ComponentParserTests.swift b/Tests/WmapParserTests/ComponentParserTests.swift new file mode 100644 index 0000000..52e347a --- /dev/null +++ b/Tests/WmapParserTests/ComponentParserTests.swift @@ -0,0 +1,131 @@ +import Testing + +@testable import WmapParser + +@Test func shouldParseABasicComponent() { + let source = "Dominoes (0.9, 0.5)" + let result = parse(source) + #expect(result.components.count == 1) + #expect( + result.components.first + == Component( + label: "Dominoes", coordinates: MapPoint(xCoordinate: 0.9, yCoordinate: 0.5), shape: .circle + ) + ) +} + +@Test func shouldParseAComponentWithAShape() { + let source = "Database (0.33, 0.81) [Square]" + let result = parse(source) + #expect(result.components.count == 1) + #expect( + result.components.first + == Component( + label: "Database", coordinates: MapPoint(xCoordinate: 0.33, yCoordinate: 0.81), + shape: .square) + ) +} + +@Test func shouldParseAComponentWithXShape() { + let source = "API (0.5, 0.6) [x]" + let result = parse(source) + #expect(result.components.count == 1) + #expect( + result.components.first + == Component( + label: "API", coordinates: MapPoint(xCoordinate: 0.5, yCoordinate: 0.6), shape: .xMark) + ) +} + +@Test func shouldParseAComponentWithTriangleShape() { + let source = "Service (0.4, 0.7) [Triangle]" + let result = parse(source) + #expect(result.components.count == 1) + #expect( + result.components.first + == Component( + label: "Service", coordinates: MapPoint(xCoordinate: 0.4, yCoordinate: 0.7), + shape: .triangle) + ) +} + +@Test func shouldParseAComponentWithCircleShape() { + let source = "Process (0.2, 0.9) [CIRCLE]" + let result = parse(source) + #expect(result.components.count == 1) + #expect( + result.components.first + == Component( + label: "Process", coordinates: MapPoint(xCoordinate: 0.2, yCoordinate: 0.9), shape: .circle) + ) +} + +@Test func shouldDefaultShapeToCircleIfInvalid() { + let source = "Figures (0.12, 0.711) [" + let result = parse(source) + #expect(result.components.count == 1) + #expect( + result.components.first + == Component( + label: "Figures", coordinates: MapPoint(xCoordinate: 0.12, yCoordinate: 0.711), + shape: .circle) + ) +} + +@Test func shouldHandleDecimalNumbers() { + let source = "Item (.5, .123)" + let result = parse(source) + #expect(result.components.count == 1) + #expect( + result.components.first + == Component( + label: "Item", coordinates: MapPoint(xCoordinate: 0.5, yCoordinate: 0.123), shape: .circle) + ) +} + +@Test func shouldHandleIntegersAsCoordinates() { + let source = "Item (1, 0)" + let result = parse(source) + #expect(result.components.count == 1) + #expect( + result.components.first + == Component( + label: "Item", coordinates: MapPoint(xCoordinate: 1.0, yCoordinate: 0.0), shape: .circle) + ) +} + +@Test func shouldPreserveCaseInComponentLabels() { + let source = "RubberGaskets (0.5, 0.5)" + let result = parse(source) + #expect(result.components.count == 1) + #expect( + result.components.first + == Component( + label: "RubberGaskets", coordinates: MapPoint(xCoordinate: 0.5, yCoordinate: 0.5), + shape: .circle) + ) +} + +@Test func shouldHandleComponentLabelsWithSpaces() { + let source = "Big Lawnmowers (0.5, 0.5)" + let result = parse(source) + #expect(result.components.count == 1) + #expect( + result.components.first + == Component( + label: "Big Lawnmowers", coordinates: MapPoint(xCoordinate: 0.5, yCoordinate: 0.5), + shape: .circle) + ) +} + +@Test func shouldHandleWhitespaceAroundTokens() { + let source = " Outer Space ( 0.9 , 0.5 ) [ Square ] " + let result = parse(source) + #expect(result.components.count == 1) + #expect( + result.components.first + == Component( + label: "Outer Space", coordinates: MapPoint(xCoordinate: 0.9, yCoordinate: 0.5), + shape: .square) + ) +} diff --git a/Tests/WmapParserTests/DependenciesParserTests.swift b/Tests/WmapParserTests/DependenciesParserTests.swift new file mode 100644 index 0000000..88e6e99 --- /dev/null +++ b/Tests/WmapParserTests/DependenciesParserTests.swift @@ -0,0 +1,44 @@ +import Testing + +@testable import WmapParser + +@Test func shouldParseUndirectedDependency() { + let source = "Smoke -- Fire" + let result = parse(source) + #expect(result.dependencies.count == 1) + #expect( + result.dependencies.first + == Dependency(fromComponent: "Smoke", toComponent: "Fire", isDirected: false) + ) +} + +@Test func shouldParseDirectedDependency() { + let source = "Cool Thing -> Different Cool Thing" + let result = parse(source) + #expect(result.dependencies.count == 1) + #expect( + result.dependencies.first + == Dependency( + fromComponent: "Cool Thing", toComponent: "Different Cool Thing", isDirected: true) + ) +} + +@Test func shouldPreserveCaseInDependencyLabels() { + let source = "SaRcAsM -> Seriousness." + let result = parse(source) + #expect(result.dependencies.count == 1) + #expect( + result.dependencies.first + == Dependency(fromComponent: "SaRcAsM", toComponent: "Seriousness.", isDirected: true) + ) +} + +@Test func shouldIgnoreWhitespaceInDependencies() { + let source = " loose --TIGHT" + let result = parse(source) + #expect(result.dependencies.count == 1) + #expect( + result.dependencies.first + == Dependency(fromComponent: "loose", toComponent: "TIGHT", isDirected: false) + ) +} diff --git a/Tests/WmapParserTests/EvolutionParserTests.swift b/Tests/WmapParserTests/EvolutionParserTests.swift new file mode 100644 index 0000000..e87bf9e --- /dev/null +++ b/Tests/WmapParserTests/EvolutionParserTests.swift @@ -0,0 +1,48 @@ +import Testing + +@testable import WmapParser + +@Test func shouldParsePositiveEvolution() { + let source = "[Evolution] Nanomachines + 0.5" + let result = parse(source) + #expect(result.evolutions.count == 1) + #expect( + result.evolutions.first == Evolution(component: "Nanomachines", value: 0.5) + ) +} + +@Test func shouldParseNegativeEvolution() { + let source = "[Evolution] FOXDIE - 0.3" + let result = parse(source) + #expect(result.evolutions.count == 1) + #expect( + result.evolutions.first == Evolution(component: "FOXDIE", value: -0.3) + ) +} + +@Test func shouldHandleCaseInsensitiveEvolutionKeyword() { + let source = "[Evolution] tamales + 0.73" + let result = parse(source) + #expect(result.evolutions.count == 1) + #expect( + result.evolutions.first == Evolution(component: "tamales", value: 0.73) + ) +} + +@Test func shouldPreserveCaseInEvolutionComponentLabel() { + let source = "[EVOLUTION] iMac - 0.2" + let result = parse(source) + #expect(result.evolutions.count == 1) + #expect( + result.evolutions.first == Evolution(component: "iMac", value: -0.2) + ) +} + +@Test func shouldHandleDecimalEvolutionValues() { + let source = "[Evolution] Numerals + .75" + let result = parse(source) + #expect(result.evolutions.count == 1) + #expect( + result.evolutions.first == Evolution(component: "Numerals", value: 0.75) + ) +} diff --git a/Tests/WmapParserTests/GroupsParserTests.swift b/Tests/WmapParserTests/GroupsParserTests.swift new file mode 100644 index 0000000..dced486 --- /dev/null +++ b/Tests/WmapParserTests/GroupsParserTests.swift @@ -0,0 +1,38 @@ +import Testing + +@testable import WmapParser + +@Test func shouldParseAGroupWithASingleComponent() { + let source = "[Group] Lonely" + let result = parse(source) + #expect(result.groups.count == 1) + #expect(result.groups.first?.components == ["Lonely"]) +} + +@Test func shouldParseAGroupWithMultipleComponents() { + let source = "[GrouP] Huey, Dewey, Louie" + let result = parse(source) + #expect(result.groups.count == 1) + #expect(result.groups.first?.components == ["Huey", "Dewey", "Louie"]) +} + +@Test func shouldHandleCaseInsensitiveGroupKeyword() { + let source = "[group] Salt, Pepper" + let result = parse(source) + #expect(result.groups.count == 1) + #expect(result.groups.first?.components == ["Salt", "Pepper"]) +} + +@Test func shouldPreserveCaseInGroupComponentLabel() { + let source = "[GROUP] XML, LaTeX" + let result = parse(source) + #expect(result.groups.count == 1) + #expect(result.groups.first?.components == ["XML", "LaTeX"]) +} + +@Test func shouldHandleWhitespaceAroundCommas() { + let source = "[Group] sky, is large, emperor" + let result = parse(source) + #expect(result.groups.count == 1) + #expect(result.groups.first?.components == ["sky", "is large", "emperor"]) +} diff --git a/Tests/WmapParserTests/InertiaParserTests.swift b/Tests/WmapParserTests/InertiaParserTests.swift new file mode 100644 index 0000000..92d9868 --- /dev/null +++ b/Tests/WmapParserTests/InertiaParserTests.swift @@ -0,0 +1,24 @@ +import Testing + +@testable import WmapParser + +@Test func shouldParseInertia() { + let source = "[Inertia] Print Media" + let result = parse(source) + #expect(result.inertias.count == 1) + #expect(result.inertias.first?.component == "Print Media") +} + +@Test func shouldHandleCaseInsensitiveInertiaKeyword() { + let source = "[inertia] Yes" + let result = parse(source) + #expect(result.inertias.count == 1) + #expect(result.inertias.first?.component == "Yes") +} + +@Test func shouldPreserveCaseInInertiaComponentLabel() { + let source = "[INERTIA] SpOnGeBoB" + let result = parse(source) + #expect(result.inertias.count == 1) + #expect(result.inertias.first?.component == "SpOnGeBoB") +} diff --git a/Tests/WmapParserTests/NotesParserTests.swift b/Tests/WmapParserTests/NotesParserTests.swift new file mode 100644 index 0000000..655bef6 --- /dev/null +++ b/Tests/WmapParserTests/NotesParserTests.swift @@ -0,0 +1,42 @@ +import Testing + +@testable import WmapParser + +@Test func shouldParseANote() { + let source = "[Note] (0.5, 0.5) This is a note" + let result = parse(source) + #expect(result.notes.count == 1) + #expect( + result.notes.first + == Note(text: "This is a note", coordinates: MapPoint(xCoordinate: 0.5, yCoordinate: 0.5)) + ) +} + +@Test func shouldHandleCaseInsensitiveNoteKeyword() { + let source = "[note] (0.1, 0.2) Text" + let result = parse(source) + #expect(result.notes.count == 1) + #expect( + result.notes.first + == Note(text: "Text", coordinates: MapPoint(xCoordinate: 0.1, yCoordinate: 0.2)) + ) +} + +@Test func shouldPreserveCaseInNoteText() { + let source = "[NOTE] (0.77, 0.19) Important NOTE" + let result = parse(source) + #expect(result.notes.count == 1) + #expect( + result.notes.first + == Note(text: "Important NOTE", coordinates: MapPoint(xCoordinate: 0.77, yCoordinate: 0.19)) + ) +} + +@Test func shouldHandleEmptyNoteText() { + let source = "[Note] (0.5, 0.5) " + let result = parse(source) + #expect(result.notes.count == 1) + #expect( + result.notes.first == Note(text: "", coordinates: MapPoint(xCoordinate: 0.5, yCoordinate: 0.5)) + ) +} diff --git a/Tests/WmapParserTests/StagesParserTests.swift b/Tests/WmapParserTests/StagesParserTests.swift new file mode 100644 index 0000000..50bab4b --- /dev/null +++ b/Tests/WmapParserTests/StagesParserTests.swift @@ -0,0 +1,48 @@ +import Testing + +@testable import WmapParser + +@Test func shouldParseStageI() { + let source = "[I] 0.25" + let result = parse(source) + #expect(result.stages.count == 1) + #expect( + result.stages.first == Stage(stage: .stageI, value: 0.25) + ) +} + +@Test func shouldParseStageII() { + let source = "[ii] 0.5" + let result = parse(source) + #expect(result.stages.count == 1) + #expect( + result.stages.first == Stage(stage: .stageII, value: 0.5) + ) +} + +@Test func shouldParseStageIII() { + let source = "[III] 0.75" + let result = parse(source) + #expect(result.stages.count == 1) + #expect( + result.stages.first == Stage(stage: .stageIII, value: 0.75) + ) +} + +@Test func shouldParseStageIV() { + let source = "[Iv] 1.0" + let result = parse(source) + #expect(result.stages.count == 1) + #expect( + result.stages.first == Stage(stage: .stageIV, value: 1.0) + ) +} + +@Test func shouldHandleDecimalValues() { + let source = "[i] .333" + let result = parse(source) + #expect(result.stages.count == 1) + #expect( + result.stages.first == Stage(stage: .stageI, value: 0.333) + ) +} diff --git a/Tests/WmapParserTests/WmapParserTests.swift b/Tests/WmapParserTests/WmapParserTests.swift new file mode 100644 index 0000000..b141dc9 --- /dev/null +++ b/Tests/WmapParserTests/WmapParserTests.swift @@ -0,0 +1,312 @@ +import Testing + +@testable import WmapParser + +@Test func shouldParseMultipleEntities() { + let source = """ + Water (0.9, 0.5) + Bucket (0.8, 0.4) [x] + Water -> Bucket + """ + let result = parse(source) + #expect(result.components.count == 2) + #expect( + result.components.first + == Component( + label: "Water", coordinates: MapPoint(xCoordinate: 0.9, yCoordinate: 0.5), shape: .circle) + ) + #expect( + result.components[1] + == Component( + label: "Bucket", coordinates: MapPoint(xCoordinate: 0.8, yCoordinate: 0.4), shape: .xMark) + ) + #expect(result.dependencies.count == 1) + #expect( + result.dependencies.first + == Dependency(fromComponent: "Water", toComponent: "Bucket", isDirected: true) + ) +} + +@Test func shouldHandleUnixLineEndings() { + let source = "Penguins (0.9, 0.5)\nI Use Arch BTW (0.8, 0.4) [x]" + let result = parse(source) + #expect(result.components.count == 2) + #expect( + result.components.first + == Component( + label: "Penguins", coordinates: MapPoint(xCoordinate: 0.9, yCoordinate: 0.5), shape: .circle + ) + ) + #expect( + result.components[1] + == Component( + label: "I Use Arch BTW", coordinates: MapPoint(xCoordinate: 0.8, yCoordinate: 0.4), + shape: .xMark) + ) +} + +@Test func shouldHandleWindowsLineEndings() { + let source = "Clippy (0.9, 0.5)\r\nSpace Cadet (0.8, 0.4) [x]" + let result = parse(source) + #expect(result.components.count == 2) + #expect( + result.components.first + == Component( + label: "Clippy", coordinates: MapPoint(xCoordinate: 0.9, yCoordinate: 0.5), shape: .circle) + ) + #expect( + result.components[1] + == Component( + label: "Space Cadet", coordinates: MapPoint(xCoordinate: 0.8, yCoordinate: 0.4), + shape: .xMark) + ) +} + +@Test func shouldHandleMacLineEndings() { + let source = "SE/30 (0.9, 0.5)\rPerforma (0.8, 0.4) [x]" + let result = parse(source) + #expect(result.components.count == 2) + #expect( + result.components.first + == Component( + label: "SE/30", coordinates: MapPoint(xCoordinate: 0.9, yCoordinate: 0.5), shape: .circle) + ) + #expect( + result.components[1] + == Component( + label: "Performa", coordinates: MapPoint(xCoordinate: 0.8, yCoordinate: 0.4), shape: .xMark) + ) +} + +@Test func shouldIgnoreEmptyLines() { + let source = """ + The Void (0.9, 0.5) + + The Abyss (0.8, 0.4) + """ + let result = parse(source) + #expect(result.components.count == 2) + #expect( + result.components.first + == Component( + label: "The Void", coordinates: MapPoint(xCoordinate: 0.9, yCoordinate: 0.5), shape: .circle + ) + ) + #expect( + result.components[1] + == Component( + label: "The Abyss", coordinates: MapPoint(xCoordinate: 0.8, yCoordinate: 0.4), + shape: .circle) + ) +} + +@Test func shouldHandleIncompleteNotes() { + let source = "[Note]" + let result = parse(source) + #expect(result.components.count == 0) +} + +@Test func shouldHandleIncompleteGroups() { + let source = "[Group]" + let result = parse(source) + #expect(result.components.count == 0) +} + +@Test func shouldHandleIncompleteNodesWithNoCoordinates() { + let source = "I am a node? (" + let result = parse(source) + #expect(result.components.count == 0) +} + +@Test func shouldHandleIncompleteNodesWithIncompleteCoordinates() { + let source = "I am a node? (12" + let result = parse(source) + #expect(result.components.count == 0) +} + +@Test func shouldHandleIncompleteNodesWithMissingYCoordinates() { + let source = "I am a node? (12," + let result = parse(source) + #expect(result.components.count == 0) +} + +@Test func shouldHandleIncompleteNodesWithUnclosedCoordinates() { + let source = "I am a node? (12,21" + let result = parse(source) + #expect(result.components.count == 0) +} + +@Test func shouldHandleIncompleteEvolutionWithoutValue() { + let source = "[Evolution] I accidentally a +" + let result = parse(source) + #expect(result.components.count == 0) +} + +@Test func shouldHandleIncompleteEvolutionWithoutComponent() { + let source = "[Evolution]+" + let result = parse(source) + #expect(result.components.count == 0) +} + +@Test func shouldHandleJustAParenthesis() { + let source = " (" + let result = parse(source) + #expect(result.components.count == 0) +} + +@Test func shouldIgnoreInvalidLines() { + let source = """ + Hello (0.9, 0.5) + Oh No + It's OK (0.8, 0.4) + [ijole] NO IT ISN'T + A-- + B-> + ( + Hello -> It's OK + [ + """ + let result = parse(source) + #expect(result.components.count == 2) + #expect( + result.components.first + == Component( + label: "Hello", coordinates: MapPoint(xCoordinate: 0.9, yCoordinate: 0.5), shape: .circle) + ) + #expect( + result.components[1] + == Component( + label: "It's OK", coordinates: MapPoint(xCoordinate: 0.8, yCoordinate: 0.4), shape: .circle) + ) + #expect(result.dependencies.count == 1) + #expect( + result.dependencies.first + == Dependency(fromComponent: "Hello", toComponent: "It's OK", isDirected: true) + ) +} + +// Edge Cases + +@Test func shouldHandleEmptyInput() { + let source = "" + let result = parse(source) + #expect(result.components.count == 0) +} + +@Test func shouldHandleOnlyWhitespace() { + let source = " \n \n " + let result = parse(source) + #expect(result.components.count == 0) +} + +@Test func onlyLineBreaks() { + let source = "\n" + let result = parse(source) + #expect(result.components.count == 0) +} + +@Test func shouldHandleOnlyInvalidLines() { + let source = "invalid\nstill invalid" + let result = parse(source) + #expect(result.components.count == 0) +} + +@Test func shouldHandleComplexComponentLabels() { + let source = "My Sü'per Complex Label 123 (0.5, 0.5)" + let result = parse(source) + #expect(result.components.count == 1) + #expect( + result.components.first + == Component( + label: "My Sü'per Complex Label 123", + coordinates: MapPoint(xCoordinate: 0.5, yCoordinate: 0.5), shape: .circle) + ) +} + +// Comprehensive Example +// swiftlint:disable:next function_body_length +@Test func shouldParseACompleteWardleyMap() { + let source = """ + [I] 0.25 + [II] 0.5 + [III] 0.75 + [IV] 1.0 + + Tea (0.9, 0.5) [Circle] + Cup (0.8, 0.4) + Kettle (0.7, 0.3) [Square] + Hot Water (0.6, 0.2) + + Tea -> Cup + Cup -> Kettle + Kettle -> Hot Water + + [Note] (0.5, 0.5) This is our tea supply chain + + [Group] Tea, Cup, Kettle + [Inertia] Kettle + [Evolution] Tea + 0.1 + """ + + let result = parse(source) + + // 4 stages + 4 components + 3 dependencies + 1 note + 1 group + 1 inertia + 1 evolution + #expect(result.stages.count == 4) + #expect(result.components.count == 4) + #expect(result.dependencies.count == 3) + #expect(result.notes.count == 1) + #expect(result.groups.count == 1) + #expect(result.inertias.count == 1) + #expect(result.evolutions.count == 1) + + #expect(result.stages.first == Stage(stage: .stageI, value: 0.25)) + #expect(result.stages[1] == Stage(stage: .stageII, value: 0.5)) + #expect(result.stages[2] == Stage(stage: .stageIII, value: 0.75)) + #expect(result.stages[3] == Stage(stage: .stageIV, value: 1.0)) + + #expect( + result.components.first + == Component( + label: "Tea", coordinates: MapPoint(xCoordinate: 0.9, yCoordinate: 0.5), shape: .circle) + ) + #expect( + result.components[1] + == Component( + label: "Cup", coordinates: MapPoint(xCoordinate: 0.8, yCoordinate: 0.4), shape: .circle) + ) + #expect( + result.components[2] + == Component( + label: "Kettle", coordinates: MapPoint(xCoordinate: 0.7, yCoordinate: 0.3), shape: .square) + ) + #expect( + result.components[3] + == Component( + label: "Hot Water", coordinates: MapPoint(xCoordinate: 0.6, yCoordinate: 0.2), + shape: .circle) + ) + + #expect( + result.dependencies.first + == Dependency(fromComponent: "Tea", toComponent: "Cup", isDirected: true) + ) + #expect( + result.dependencies[1] + == Dependency(fromComponent: "Cup", toComponent: "Kettle", isDirected: true) + ) + #expect( + result.dependencies[2] + == Dependency(fromComponent: "Kettle", toComponent: "Hot Water", isDirected: true) + ) + + #expect( + result.notes.first + == Note( + text: "This is our tea supply chain", + coordinates: MapPoint(xCoordinate: 0.5, yCoordinate: 0.5)) + ) + + #expect(result.groups.first?.components == ["Tea", "Cup", "Kettle"]) + #expect(result.inertias.first?.component == "Kettle") + #expect(result.evolutions.first == Evolution(component: "Tea", value: 0.1)) +} diff --git a/target/rust-analyzer/flycheck0/stderr b/target/rust-analyzer/flycheck0/stderr new file mode 100644 index 0000000..d3510cb --- /dev/null +++ b/target/rust-analyzer/flycheck0/stderr @@ -0,0 +1 @@ + Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.08s diff --git a/target/rust-analyzer/flycheck0/stdout b/target/rust-analyzer/flycheck0/stdout new file mode 100644 index 0000000..c9d6158 --- /dev/null +++ b/target/rust-analyzer/flycheck0/stdout @@ -0,0 +1,77 @@ +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.103","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/proc-macro2-1.0.103/Cargo.toml","target":{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/proc-macro2-1.0.103/build.rs","edition":"2021","doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":0,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","proc-macro"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/build/proc-macro2-d1ce00ff3654ae6d/build-script-build"],"executable":null,"fresh":true} +{"reason":"build-script-executed","package_id":"registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.103","linked_libs":[],"linked_paths":[],"cfgs":["wrap_proc_macro","proc_macro_span_location","proc_macro_span_file"],"env":[],"out_dir":"/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/build/proc-macro2-02343e2882138b6d/out"} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#quote@1.0.42","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/quote-1.0.42/Cargo.toml","target":{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/quote-1.0.42/build.rs","edition":"2018","doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":0,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","proc-macro"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/build/quote-c88cbe7a015637c2/build-script-build"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#unicode-ident@1.0.22","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/unicode-ident-1.0.22/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"unicode_ident","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/unicode-ident-1.0.22/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":0,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libunicode_ident-ff24541d0273ed5a.rlib","/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libunicode_ident-ff24541d0273ed5a.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#crossbeam-utils@0.8.21","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/crossbeam-utils-0.8.21/Cargo.toml","target":{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/crossbeam-utils-0.8.21/build.rs","edition":"2021","doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":0,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","std"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/build/crossbeam-utils-6d0c505069b87f3f/build-script-build"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#serde_core@1.0.228","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/serde_core-1.0.228/Cargo.toml","target":{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/serde_core-1.0.228/build.rs","edition":"2021","doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":0,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["alloc","result","std"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/build/serde_core-b0753111d424f06e/build-script-build"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#zerocopy@0.8.31","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/zerocopy-0.8.31/Cargo.toml","target":{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/zerocopy-0.8.31/build.rs","edition":"2021","doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":0,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["derive","simd","zerocopy-derive"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/build/zerocopy-22acc40cf1b8c3e8/build-script-build"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#serde@1.0.228","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/serde-1.0.228/Cargo.toml","target":{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/serde-1.0.228/build.rs","edition":"2021","doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":0,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["alloc","default","derive","serde_derive","std"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/build/serde-ecd9eabf8fe98ee3/build-script-build"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#autocfg@1.5.0","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/autocfg-1.5.0/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"autocfg","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/autocfg-1.5.0/src/lib.rs","edition":"2015","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":0,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libautocfg-e2e21eab783460c2.rlib","/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libautocfg-e2e21eab783460c2.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#shlex@1.3.0","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/shlex-1.3.0/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"shlex","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/shlex-1.3.0/src/lib.rs","edition":"2015","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":0,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","std"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libshlex-712ea22829555143.rlib","/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libshlex-712ea22829555143.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#find-msvc-tools@0.1.5","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/find-msvc-tools-0.1.5/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"find_msvc_tools","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/find-msvc-tools-0.1.5/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":0,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libfind_msvc_tools-097a342ea7647ca5.rlib","/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libfind_msvc_tools-097a342ea7647ca5.rmeta"],"executable":null,"fresh":true} +{"reason":"build-script-executed","package_id":"registry+https://github.com/rust-lang/crates.io-index#quote@1.0.42","linked_libs":[],"linked_paths":[],"cfgs":[],"env":[],"out_dir":"/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/build/quote-81aa7bbf6f05440f/out"} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.103","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/proc-macro2-1.0.103/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"proc_macro2","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/proc-macro2-1.0.103/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":0,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","proc-macro"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libproc_macro2-028483108b7d1ae7.rlib","/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libproc_macro2-028483108b7d1ae7.rmeta"],"executable":null,"fresh":true} +{"reason":"build-script-executed","package_id":"registry+https://github.com/rust-lang/crates.io-index#serde_core@1.0.228","linked_libs":[],"linked_paths":[],"cfgs":[],"env":[],"out_dir":"/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/build/serde_core-4bdf6487753557d2/out"} +{"reason":"build-script-executed","package_id":"registry+https://github.com/rust-lang/crates.io-index#crossbeam-utils@0.8.21","linked_libs":[],"linked_paths":[],"cfgs":[],"env":[],"out_dir":"/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/build/crossbeam-utils-fb91737d6607221c/out"} +{"reason":"build-script-executed","package_id":"registry+https://github.com/rust-lang/crates.io-index#zerocopy@0.8.31","linked_libs":[],"linked_paths":[],"cfgs":[],"env":[],"out_dir":"/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/build/zerocopy-57a70249d6eaf33c/out"} +{"reason":"build-script-executed","package_id":"registry+https://github.com/rust-lang/crates.io-index#serde@1.0.228","linked_libs":[],"linked_paths":[],"cfgs":["if_docsrs_then_no_serde_core"],"env":[],"out_dir":"/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/build/serde-7ceb09fb5009e528/out"} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#cc@1.2.49","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/cc-1.2.49/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"cc","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/cc-1.2.49/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":0,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libcc-1b0dbadcf628c4b1.rlib","/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libcc-1b0dbadcf628c4b1.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#num-traits@0.2.19","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/num-traits-0.2.19/Cargo.toml","target":{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/num-traits-0.2.19/build.rs","edition":"2021","doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":0,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","std"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/build/num-traits-151c990202d10603/build-script-build"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#either@1.15.0","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/either-1.15.0/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"either","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/either-1.15.0/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["std","use_std"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libeither-f215abcbb0658c55.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#libc@0.2.178","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/libc-0.2.178/Cargo.toml","target":{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/libc-0.2.178/build.rs","edition":"2021","doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":0,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","std"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/build/libc-6eafcf2ca2535e6e/build-script-build"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#quote@1.0.42","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/quote-1.0.42/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"quote","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/quote-1.0.42/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":0,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","proc-macro"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libquote-b0045370011366e6.rlib","/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libquote-b0045370011366e6.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#crossbeam-utils@0.8.21","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/crossbeam-utils-0.8.21/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"crossbeam_utils","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/crossbeam-utils-0.8.21/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","std"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libcrossbeam_utils-caa8cfc45f06ae2a.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#serde_core@1.0.228","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/serde_core-1.0.228/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"serde_core","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/serde_core-1.0.228/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["alloc","result","std"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libserde_core-d449c5cde8501661.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.4","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/cfg-if-1.0.4/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"cfg_if","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/cfg-if-1.0.4/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libcfg_if-eed30869daa6a03e.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#rayon-core@1.13.0","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/rayon-core-1.13.0/Cargo.toml","target":{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/rayon-core-1.13.0/build.rs","edition":"2021","doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":0,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/build/rayon-core-66393fd3ff70fbcc/build-script-build"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#serde_json@1.0.145","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/serde_json-1.0.145/Cargo.toml","target":{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/serde_json-1.0.145/build.rs","edition":"2021","doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":0,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","std"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/build/serde_json-070dabf5ff6dc429/build-script-build"],"executable":null,"fresh":true} +{"reason":"build-script-executed","package_id":"registry+https://github.com/rust-lang/crates.io-index#libc@0.2.178","linked_libs":[],"linked_paths":[],"cfgs":["freebsd12"],"env":[],"out_dir":"/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/build/libc-d4b7796c341a2886/out"} +{"reason":"build-script-executed","package_id":"registry+https://github.com/rust-lang/crates.io-index#num-traits@0.2.19","linked_libs":[],"linked_paths":[],"cfgs":["has_total_cmp"],"env":[],"out_dir":"/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/build/num-traits-da6afca2f0b36689/out"} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#alloca@0.4.0","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/alloca-0.4.0/Cargo.toml","target":{"kind":["custom-build"],"crate_types":["bin"],"name":"build-script-build","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/alloca-0.4.0/build.rs","edition":"2021","doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":0,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/build/alloca-5b7d6307ea57e890/build-script-build"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#itoa@1.0.15","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/itoa-1.0.15/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"itoa","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/itoa-1.0.15/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libitoa-aac1ae89bc8c8867.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#syn@2.0.111","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/syn-2.0.111/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"syn","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/syn-2.0.111/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":0,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["clone-impls","default","derive","full","parsing","printing","proc-macro"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libsyn-e34163557634371f.rlib","/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libsyn-e34163557634371f.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#crossbeam-epoch@0.9.18","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/crossbeam-epoch-0.9.18/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"crossbeam_epoch","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/crossbeam-epoch-0.9.18/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["alloc","std"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libcrossbeam_epoch-9c36ae68c05dbbd3.rmeta"],"executable":null,"fresh":true} +{"reason":"build-script-executed","package_id":"registry+https://github.com/rust-lang/crates.io-index#serde_json@1.0.145","linked_libs":[],"linked_paths":[],"cfgs":["fast_arithmetic=\"64\""],"env":[],"out_dir":"/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/build/serde_json-56098e60694e05a6/out"} +{"reason":"build-script-executed","package_id":"registry+https://github.com/rust-lang/crates.io-index#rayon-core@1.13.0","linked_libs":[],"linked_paths":[],"cfgs":[],"env":[],"out_dir":"/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/build/rayon-core-06da785709dbc36e/out"} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#regex-syntax@0.8.8","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/regex-syntax-0.8.8/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"regex_syntax","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/regex-syntax-0.8.8/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["std"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libregex_syntax-a87402582f25fabe.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#anstyle@1.0.13","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/anstyle-1.0.13/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"anstyle","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/anstyle-1.0.13/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","std"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libanstyle-440ef011c636d365.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#memchr@2.7.6","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/memchr-2.7.6/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"memchr","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/memchr-2.7.6/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["alloc","std"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libmemchr-867c662323befbc1.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#ryu@1.0.20","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/ryu-1.0.20/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"ryu","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/ryu-1.0.20/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libryu-5dca68e756b6c3fe.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#plotters-backend@0.3.7","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/plotters-backend-0.3.7/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"plotters_backend","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/plotters-backend-0.3.7/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libplotters_backend-e2de490f33e8365d.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#ciborium-io@0.2.2","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/ciborium-io-0.2.2/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"ciborium_io","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/ciborium-io-0.2.2/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["alloc","std"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libciborium_io-8ddccaf02fa2dabf.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#zerocopy-derive@0.8.31","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/zerocopy-derive-0.8.31/Cargo.toml","target":{"kind":["proc-macro"],"crate_types":["proc-macro"],"name":"zerocopy_derive","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/zerocopy-derive-0.8.31/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":0,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libzerocopy_derive-2a836ef848538f79.dylib"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#serde_derive@1.0.228","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/serde_derive-1.0.228/Cargo.toml","target":{"kind":["proc-macro"],"crate_types":["proc-macro"],"name":"serde_derive","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/serde_derive-1.0.228/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":0,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libserde_derive-aff0e54826aa3c72.dylib"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#crossbeam-deque@0.8.6","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/crossbeam-deque-0.8.6/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"crossbeam_deque","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/crossbeam-deque-0.8.6/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","std"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libcrossbeam_deque-c16017a42af09801.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#clap_lex@0.7.6","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/clap_lex-0.7.6/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"clap_lex","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/clap_lex-0.7.6/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libclap_lex-5523af2f3124e780.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#regex-automata@0.4.13","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/regex-automata-0.4.13/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"regex_automata","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/regex-automata-0.4.13/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["alloc","meta","nfa-pikevm","nfa-thompson","std","syntax"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libregex_automata-e206950956956a65.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#plotters-svg@0.3.7","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/plotters-svg-0.3.7/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"plotters_svg","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/plotters-svg-0.3.7/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libplotters_svg-4075f1a41488548d.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#serde_json@1.0.145","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/serde_json-1.0.145/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"serde_json","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/serde_json-1.0.145/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","std"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libserde_json-88dd7061c1c2df1e.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#num-traits@0.2.19","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/num-traits-0.2.19/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"num_traits","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/num-traits-0.2.19/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","std"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libnum_traits-60c04ad9e53f4206.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#libc@0.2.178","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/libc-0.2.178/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"libc","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/libc-0.2.178/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","std"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/liblibc-a61e62fa55b770d6.rmeta"],"executable":null,"fresh":true} +{"reason":"build-script-executed","package_id":"registry+https://github.com/rust-lang/crates.io-index#alloca@0.4.0","linked_libs":["static=calloca"],"linked_paths":["native=/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/build/alloca-f86b93f60059fdb5/out"],"cfgs":[],"env":[],"out_dir":"/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/build/alloca-f86b93f60059fdb5/out"} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#zerocopy@0.8.31","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/zerocopy-0.8.31/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"zerocopy","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/zerocopy-0.8.31/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["derive","simd","zerocopy-derive"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libzerocopy-3ff92c8a2c7146aa.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#serde@1.0.228","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/serde-1.0.228/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"serde","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/serde-1.0.228/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["alloc","default","derive","serde_derive","std"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libserde-3b00b55083c7a4c5.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#clap_builder@4.5.53","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/clap_builder-4.5.53/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"clap_builder","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/clap_builder-4.5.53/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["help","std"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libclap_builder-3f824052b89083bd.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#rayon-core@1.13.0","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/rayon-core-1.13.0/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"rayon_core","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/rayon-core-1.13.0/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/librayon_core-0b35ed4d486fc6e9.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#itertools@0.13.0","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/itertools-0.13.0/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"itertools","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/itertools-0.13.0/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":false},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","use_alloc","use_std"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libitertools-638c9be9a66358f2.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#cast@0.3.0","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/cast-0.3.0/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"cast","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/cast-0.3.0/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libcast-027321e6601be789.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#same-file@1.0.6","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/same-file-1.0.6/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"same_file","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/same-file-1.0.6/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libsame_file-1a494771e40bea10.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#alloca@0.4.0","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/alloca-0.4.0/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"alloca","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/alloca-0.4.0/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/liballoca-e30ffb103a4dd653.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#regex@1.12.2","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/regex-1.12.2/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"regex","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/regex-1.12.2/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["std"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libregex-d96e94c4e477712b.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#plotters@0.3.7","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/plotters-0.3.7/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"plotters","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/plotters-0.3.7/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["area_series","line_series","plotters-svg","svg_backend"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libplotters-6e935cc61655f4dc.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#half@2.7.1","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/half-2.7.1/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"half","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/half-2.7.1/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libhalf-914ad4cb14ae9f06.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#clap@4.5.53","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/clap-4.5.53/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"clap","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/clap-4.5.53/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["help","std"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libclap-1512d4912cd7344b.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#walkdir@2.5.0","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/walkdir-2.5.0/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"walkdir","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/walkdir-2.5.0/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libwalkdir-ae2182fcdf4b005d.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#tinytemplate@1.2.1","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tinytemplate-1.2.1/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"tinytemplate","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tinytemplate-1.2.1/src/lib.rs","edition":"2015","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libtinytemplate-70c2f1cf0a5fb551.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#rayon@1.11.0","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/rayon-1.11.0/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"rayon","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/rayon-1.11.0/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/librayon-28657c9ea4ca8f0e.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#criterion-plot@0.8.1","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/criterion-plot-0.8.1/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"criterion_plot","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/criterion-plot-0.8.1/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libcriterion_plot-9048d2fb096b0d7e.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#page_size@0.6.0","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/page_size-0.6.0/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"page_size","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/page_size-0.6.0/src/lib.rs","edition":"2015","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libpage_size-ed3b131ad9761fae.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#anes@0.1.6","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/anes-0.1.6/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"anes","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/anes-0.1.6/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libanes-c4bb1a46b1d0f431.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#oorandom@11.1.5","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/oorandom-11.1.5/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"oorandom","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/oorandom-11.1.5/src/lib.rs","edition":"2018","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/liboorandom-b44a1544b73e5712.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"path+file:///Users/rbdr/projects/lib/wmap-parser-rust#wmap-parser@0.1.0","manifest_path":"/Users/rbdr/projects/lib/wmap-parser-rust/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"wmap_parser","src_path":"/Users/rbdr/projects/lib/wmap-parser-rust/src/lib.rs","edition":"2024","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libwmap_parser-94fda8f160b78f62.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#ciborium-ll@0.2.2","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/ciborium-ll-0.2.2/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"ciborium_ll","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/ciborium-ll-0.2.2/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libciborium_ll-8a964560e6758c07.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#ciborium@0.2.2","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/ciborium-0.2.2/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"ciborium","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/ciborium-0.2.2/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["default","std"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libciborium-275e5a38000473e0.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"registry+https://github.com/rust-lang/crates.io-index#criterion@0.8.1","manifest_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/criterion-0.8.1/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"criterion","src_path":"/Users/rbdr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/criterion-0.8.1/src/lib.rs","edition":"2021","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":["cargo_bench_support","default","plotters","rayon"],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libcriterion-0c5113a27e28a43c.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"path+file:///Users/rbdr/projects/lib/wmap-parser-rust#wmap-parser@0.1.0","manifest_path":"/Users/rbdr/projects/lib/wmap-parser-rust/Cargo.toml","target":{"kind":["lib"],"crate_types":["lib"],"name":"wmap_parser","src_path":"/Users/rbdr/projects/lib/wmap-parser-rust/src/lib.rs","edition":"2024","doc":true,"doctest":true,"test":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":true},"features":[],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libwmap_parser-3edfdfdb5fd80985.rmeta"],"executable":null,"fresh":true} +{"reason":"compiler-artifact","package_id":"path+file:///Users/rbdr/projects/lib/wmap-parser-rust#wmap-parser@0.1.0","manifest_path":"/Users/rbdr/projects/lib/wmap-parser-rust/Cargo.toml","target":{"kind":["bench"],"crate_types":["bin"],"name":"parse","src_path":"/Users/rbdr/projects/lib/wmap-parser-rust/benches/parse.rs","edition":"2024","doc":false,"doctest":false,"test":false},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":true},"features":[],"filenames":["/Users/rbdr/projects/lib/wmap-parser-rust/target/debug/deps/libparse-c48900d70b6ea966.rmeta"],"executable":null,"fresh":true} +{"reason":"build-finished","success":true} |