coverband 5.1.1 → 5.2.0.rc.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/diagram.yml +16 -0
- data/.github/workflows/main.yml +4 -4
- data/README.md +7 -1
- data/changes.md +17 -2
- data/coverband.gemspec +8 -0
- data/diagram.svg +1 -0
- data/lib/coverband/adapters/base.rb +8 -7
- data/lib/coverband/adapters/file_store.rb +1 -1
- data/lib/coverband/adapters/hash_redis_store.rb +1 -1
- data/lib/coverband/adapters/null_store.rb +1 -1
- data/lib/coverband/adapters/redis_store.rb +1 -1
- data/lib/coverband/collectors/coverage.rb +19 -1
- data/lib/coverband/collectors/view_tracker.rb +27 -20
- data/lib/coverband/collectors/view_tracker_service.rb +3 -3
- data/lib/coverband/configuration.rb +9 -2
- data/lib/coverband/integrations/background.rb +6 -3
- data/lib/coverband/reporters/base.rb +1 -1
- data/lib/coverband/reporters/web.rb +4 -4
- data/lib/coverband/utils/railtie.rb +1 -1
- data/lib/coverband/utils/result.rb +1 -1
- data/lib/coverband/utils/source_file.rb +2 -2
- data/lib/coverband/version.rb +1 -1
- data/public/dependencies.js +4 -4
- data/test/coverband/configuration_test.rb +5 -5
- data/test/forked/rails_full_stack_test.rb +1 -1
- data/test/integration/full_stack_deferred_eager_test.rb +51 -0
- data/views/file_list.erb +2 -2
- metadata +15 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d0a758df9e83a3c4a146dc3c14a9d5a400a8acc842b535e1f6b1c10d6fce5e1d
|
4
|
+
data.tar.gz: 450e780dd71dacaaab91bf82a1f65a2504e17b433a0c9e85d57dd3d9b191cc67
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8a50d8a5858ab8291a54da9e3b3744c90e0229cf11fa3dfa9a598117d4e547ae2aa460ee356b5c0ba4930cfb5eff501c3c90bf1acd37b22f588c458ededcbe43
|
7
|
+
data.tar.gz: abbfe9d3debe2c58c60bdec9391e73fe2df1f44c10e03599993cdc351567b91fcfce92a9045ec3388e7f797e589a264f27ea6e5187d8491b17b5878377f03a67
|
@@ -0,0 +1,16 @@
|
|
1
|
+
name: Create diagram
|
2
|
+
on:
|
3
|
+
workflow_dispatch: {}
|
4
|
+
push:
|
5
|
+
branches:
|
6
|
+
- main
|
7
|
+
jobs:
|
8
|
+
get_data:
|
9
|
+
runs-on: ubuntu-latest
|
10
|
+
steps:
|
11
|
+
- name: Checkout code
|
12
|
+
uses: actions/checkout@master
|
13
|
+
- name: Update diagram
|
14
|
+
uses: githubocto/repo-visualizer@main
|
15
|
+
with:
|
16
|
+
excluded_paths: "ignore,.github"
|
data/.github/workflows/main.yml
CHANGED
@@ -3,9 +3,9 @@ name: CI
|
|
3
3
|
on:
|
4
4
|
# Triggers the workflow on push or pull request events but only for the master branch
|
5
5
|
push:
|
6
|
-
branches: [
|
6
|
+
branches: [main]
|
7
7
|
pull_request:
|
8
|
-
branches: [
|
8
|
+
branches: [main]
|
9
9
|
jobs:
|
10
10
|
test:
|
11
11
|
strategy:
|
@@ -17,12 +17,12 @@ jobs:
|
|
17
17
|
# remove until I sort out CI issues for truffle
|
18
18
|
# truffleruby,
|
19
19
|
# truffleruby-head,
|
20
|
-
ruby: [2.3, 2.4, 2.5, 2.6, 2.7, 3.0, jruby, jruby-head]
|
20
|
+
ruby: [2.3, 2.4, 2.5, 2.6, 2.7, "3.0", jruby, jruby-head]
|
21
21
|
redis-version: [4, 5, 6]
|
22
22
|
runs-on: ${{ matrix.os }}-latest
|
23
23
|
steps:
|
24
24
|
- uses: actions/checkout@v2
|
25
|
-
- uses: supercharge/redis-github-action@1.
|
25
|
+
- uses: supercharge/redis-github-action@1.2.0
|
26
26
|
- uses: ruby/setup-ruby@v1
|
27
27
|
with:
|
28
28
|
ruby-version: ${{ matrix.ruby }}
|
data/README.md
CHANGED
@@ -284,7 +284,7 @@ Between the release of 4.0 and 4.1 our data format changed. This resets all your
|
|
284
284
|
|
285
285
|
### Adding Rake Tasks outside of Rails
|
286
286
|
|
287
|
-
Rails apps should
|
287
|
+
Rails apps should automatically include the tasks via the Railtie.
|
288
288
|
|
289
289
|
For non Rails apps, either add the below to your `Rakefile` or to a file included in your `Rakefile` such as `lib/tasks/coverband.rake` if you want to break it up that way.
|
290
290
|
|
@@ -427,6 +427,12 @@ What is the coverage data in Redis?
|
|
427
427
|
|
428
428
|
`Coverband.configuration.store.coverage`
|
429
429
|
|
430
|
+
### Diagram
|
431
|
+
|
432
|
+
A diagram of the code.
|
433
|
+
|
434
|
+
![Visualization of this repo](./diagram.svg)
|
435
|
+
|
430
436
|
## Logo
|
431
437
|
|
432
438
|
The Coverband logo was created by [Dave Woodall](http://davewoodall.com). Thanks Dave!
|
data/changes.md
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
### Coverband 5.2.0
|
2
|
+
|
3
|
+
- (Fumiaki MATSUSHIMA) Fix CI setting for Ruby 3.0
|
4
|
+
- (Fumiaki MATSUSHIMA) Avoid calling coverage with the same type twice on get_coverage_report
|
5
|
+
- (kei-s) Fix filling zero for not loaded files
|
6
|
+
- (wonda-tea-coffee) cleanup readme / fix typos
|
7
|
+
- support deferred eager loading data
|
8
|
+
- (Donatas Stundys) Fix disabling views tracking
|
9
|
+
- (Simon) Improve View tracker to track render collection too
|
10
|
+
|
11
|
+
### Coverband 5.1.1
|
12
|
+
|
13
|
+
- Fix early report error
|
14
|
+
- Improved view tracker perf Hosam Aly
|
15
|
+
|
1
16
|
### Coverband 5.1.0
|
2
17
|
|
3
18
|
- add support for dead method detection rake task
|
@@ -93,7 +108,7 @@
|
|
93
108
|
- larger changes
|
94
109
|
- reduce memory usage
|
95
110
|
- fix issue where reports didn't include files with 0 activity
|
96
|
-
- updated runtime
|
111
|
+
- updated runtime relevant lines and runtime percentages
|
97
112
|
- add Oneshot coverage support for Ruby 2.6.0 thanks @zwalker
|
98
113
|
- I would consider this our test oneshot release, please report any issues
|
99
114
|
- improved control over memory vs functionality
|
@@ -125,7 +140,7 @@
|
|
125
140
|
|
126
141
|
### Coverband 4.2.0
|
127
142
|
|
128
|
-
**NOTE:** This release introduces load time and runtime Coverage. To get the full
|
143
|
+
**NOTE:** This release introduces load time and runtime Coverage. To get the full benefit of this feature you need to reset you coverage data (`rake coverband:clear` or clear via the web UI). Until you clear the combined result is still correct, but your runtime data will be mixed with previous data. This is due to an additive change in how we store coverage. We didn't reset by default as the coverage history for some folks may be more important than runtime breakdown.
|
129
144
|
|
130
145
|
- loadtime vs runtime coverage
|
131
146
|
- This fixes the coverage last seen date to exclude just load time data
|
data/coverband.gemspec
CHANGED
@@ -23,6 +23,14 @@ Gem::Specification.new do |spec|
|
|
23
23
|
|
24
24
|
spec.required_ruby_version = '>= 2.3'
|
25
25
|
|
26
|
+
spec.metadata = {
|
27
|
+
"homepage_uri" => "https://github.com/danmayer/coverband",
|
28
|
+
"bug_tracker_uri" => "https://github.com/danmayer/coverband/issues",
|
29
|
+
"documentation_uri" => "https://github.com/danmayer/coverband",
|
30
|
+
"changelog_uri" => "https://github.com/danmayer/coverband/blob/main/changes.md",
|
31
|
+
"source_code_uri" => "https://github.com/danmayer/coverband",
|
32
|
+
}
|
33
|
+
|
26
34
|
spec.add_development_dependency "benchmark-ips"
|
27
35
|
spec.add_development_dependency "capybara"
|
28
36
|
spec.add_development_dependency "m"
|
data/diagram.svg
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
<svg width="1000" height="1000" style="background:white;font-family:sans-serif;overflow:visible" xmlns="http://www.w3.org/2000/svg"><defs><filter id="glow" x="-50%" y="-50%" width="200%" height="200%"><feGaussianBlur stdDeviation="4" result="coloredBlur"></feGaussianBlur><feMerge><feMergeNode in="coloredBlur"></feMergeNode><feMergeNode in="SourceGraphic"></feMergeNode></feMerge></filter></defs><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(319.99422221520257, 687.2164700211342)"><circle r="41.02921418068235" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(661.4377379675747, 565.1941312103406)"><circle r="305.5618666214336" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#89e051;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(288.8905634421281, 583.3369571703405)"><circle r="51.43203365598711" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(198.2622918656833, 337.650139496829)"><circle r="194.43813337856645" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(208.84229622707048, 675.5867014055564)"><circle r="54.712402162993705" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(467.6116292400953, 199.49715021934765)"><circle r="92.27512036255078" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(310.03350878582086, 685.7453349516641)"><circle style="transition:all 0.5s ease-out" r="13.30180606880021" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(345.959434313262, 685.9068702798954)"><circle style="transition:all 0.5s ease-out" r="12.030997111439614" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(328.8897152183017, 706.7783546079727)"><circle style="transition:all 0.5s ease-out" r="11.746091118173574" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(328.97908581034545, 668.1974072999602)"><circle style="transition:all 0.5s ease-out" r="9.31783640763901" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(309.00647670688085, 660.3234640997664)"><circle style="transition:all 0.5s ease-out" r="8.978150192553253" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(305.70723567837626, 710.3828616614179)"><circle style="transition:all 0.5s ease-out" r="8.51267696816497" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(345.64899473131675, 666.4312437404108)"><circle style="transition:all 0.5s ease-out" r="4.245373231470868" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(344.7614849724372, 702.5671111663205)"><circle style="transition:all 0.5s ease-out" r="1.4748603506155034" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(703.8101203273987, 527.1527369126792)"><circle style="transition:all 0.5s ease-out" r="16.536485579985868" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(778.8592125527111, 570.0827446562124)"><circle r="61.702355060114236" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(717.5459367246649, 693.1394072463729)"><circle r="61.862375247277605" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(725.4752043456411, 443.3464320959712)"><circle r="61.702355060114215" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(815.9230212367876, 665.2141060036499)"><circle r="26.458426135215838" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(830.9853756043558, 473.38933293249397)"><circle r="34.078018549283044" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(896.5990215299141, 619.8107385171486)"><circle r="52.169847346054155" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(853.6296143526785, 527.4139968947751)"><circle style="transition:all 0.5s ease-out" r="15.96473679592113" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(526.6706855709276, 561.9800413946193)"><circle r="155.78797315176226" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(917.8131106864573, 514.6120585177536)"><circle r="41.24428624341126" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(856.6122524498119, 560.7951755125868)"><circle style="transition:all 0.5s ease-out" r="8.027979530205487" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(871.1970555375348, 548.2846838240425)"><circle style="transition:all 0.5s ease-out" r="8.008602288503555" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(851.9429346996435, 574.2987540814191)"><circle style="transition:all 0.5s ease-out" r="3.073538603630714" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(718.5679782589528, 611.3698533832043)"><circle style="transition:all 0.5s ease-out" r="2.798350763171706" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(792.2638950596225, 498.56989406564423)"><circle style="transition:all 0.5s ease-out" r="2.391171864237444" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(728.3549015220763, 518.0377980239389)"><circle style="transition:all 0.5s ease-out" r="2.1733199888659107" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#000080;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(271.08448903099156, 583.3369571703405)"><circle r="29.927708660521365" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#000080;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(320.6673973948141, 583.3369571703405)"><circle style="transition:all 0.5s ease-out" r="15.956949118971922" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#89e051;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(304.5764790203213, 600.9996183033574)"><circle style="transition:all 0.5s ease-out" r="4.238047301540488" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(24.105806761514003, 337.650139496829)"><circle style="transition:all 0.5s ease-out" r="16.58339769006793" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(216.69481484791584, 337.650139496829)"><circle r="172.30735981200468" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(39.162976295998305, 354.5129730018694)"><circle style="transition:all 0.5s ease-out" r="2.3252866839051953" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(181.62212425820078, 668.7863787424532)"><circle style="transition:all 0.5s ease-out" r="23.65563559346268" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(235.26760587143946, 666.1470864897661)"><circle style="transition:all 0.5s ease-out" r="23.651694410707957" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#ff9900;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(210.5705714922894, 709.4694568808314)"><circle r="17.7855978043505" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#083fa1;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(217.6116626371666, 634.3547232001796)"><circle style="transition:all 0.5s ease-out" r="9.558187498701981" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#083fa1;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(196.05568390646692, 636.9792930631887)"><circle style="transition:all 0.5s ease-out" r="8.051170660454732" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(207.8399724900223, 655.6862952725725)"><circle style="transition:all 0.5s ease-out" r="2.5907693827582245" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(183.99483991335063, 698.1094000508928)"><circle style="transition:all 0.5s ease-out" r="2.5787471861822056" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(235.88363383674653, 695.5452960269216)"><circle style="transition:all 0.5s ease-out" r="2.5666686786275803" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(211.908778416179, 648.3920329970198)"><circle style="transition:all 0.5s ease-out" r="2.554533061334901" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(203.60667185089102, 648.4904756803166)"><circle style="transition:all 0.5s ease-out" r="2.5300872065332993" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(209.03249951101728, 679.2091076479431)"><circle style="transition:all 0.5s ease-out" r="2.517775273583543" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#f1e05a;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(414.80683990819495, 225.22631291636873)"><circle style="transition:all 0.5s ease-out" r="30.53556308233156" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#563d7c;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(512.4571013879283, 234.7504090693131)"><circle style="transition:all 0.5s ease-out" r="30.53250998398045" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(458.95943358587135, 257.86354977626803)"><circle style="transition:all 0.5s ease-out" r="21.235647871647426" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#f1e05a;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(463.6210275819494, 209.8535735427391)"><circle style="transition:all 0.5s ease-out" r="17.643810882955766" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(429.94733392039217, 163.4979749857882)"><circle r="24.555665603024796" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(500.15832910431885, 164.94941980931233)"><circle r="31.81109874052291" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(450.82558698952977, 229.51694765004308)"><circle style="transition:all 0.5s ease-out" r="2.6146479463642924" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(476.36476833146503, 237.3603736814449)"><circle style="transition:all 0.5s ease-out" r="2.5787471861822056" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(469.25318530535196, 232.60526691231775)"><circle style="transition:all 0.5s ease-out" r="2.5666686786275803" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(431.98218614958677, 257.18271848114114)"><circle style="transition:all 0.5s ease-out" r="2.554533061334901" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(476.7622353670526, 229.04803927125838)"><circle style="transition:all 0.5s ease-out" r="2.5423395164804927" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#083fa1;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(320.00958704794687, 807.6027914744386)"><circle style="transition:all 0.5s ease-out" r="30.542685791623068" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#083fa1;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(392.2829724508863, 809.1010151493219)"><circle style="transition:all 0.5s ease-out" r="29.284693676112123" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#083fa1;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(363.6278477646056, 856.1133193551365)"><circle style="transition:all 0.5s ease-out" r="14.43556062491978" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#083fa1;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(363.9956151092209, 763.9617920796633)"><circle style="transition:all 0.5s ease-out" r="13.862342373087381" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(334.36240795245504, 763.5676255543302)"><circle style="transition:all 0.5s ease-out" r="12.57652827630675" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(356.42058836474627, 830.2653182750355)"><circle style="transition:all 0.5s ease-out" r="9.163144868295092" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#cb171e;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(394.101138686625, 767.2374341210409)"><circle style="transition:all 0.5s ease-out" r="8.94347200119149" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(357.28628156982023, 788.3481569001303)"><circle style="transition:all 0.5s ease-out" r="8.226797702990359" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#199f4b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(340.7950570880013, 844.0206887635807)"><circle style="transition:all 0.5s ease-out" r="8.192732141744557" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(407.97194652908416, 776.0621710493327)"><circle style="transition:all 0.5s ease-out" r="4.556067100895268" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#000000;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(386.9380834496869, 845.3891973459426)"><circle style="transition:all 0.5s ease-out" r="4.193822989078803" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(380.9155009052245, 775.2363751349797)"><circle style="transition:all 0.5s ease-out" r="3.278988774042822" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(316.7170549122837, 770.7364911636618)"><circle style="transition:all 0.5s ease-out" r="3.2694981932865566" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(370.2613660354364, 836.6846955612831)"><circle style="transition:all 0.5s ease-out" r="2.8965682269362802" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#ff9900;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(377.8131348332271, 841.1437681171224)"><circle style="transition:all 0.5s ease-out" r="2.6734114171599117" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#083fa1;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(345.4861052581486, 780.9530665231163)"><circle style="transition:all 0.5s ease-out" r="2.4929690009061694" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(369.0034548279796, 783.7991864393258)"><circle style="transition:all 0.5s ease-out" r="1.1424219151830952" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(753.5559755983531, 535.6383459642083)"><circle style="transition:all 0.5s ease-out" r="15.962790232871045" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(798.6609077135887, 548.1162537815725)"><circle r="19.78767480101326" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(766.2855715465157, 588.9585035139102)"><circle r="36.022171625965505" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(769.033752156919, 545.452076252546)"><circle style="transition:all 0.5s ease-out" r="3.7560365250643617" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(778.6722029258943, 548.3675857775355)"><circle style="transition:all 0.5s ease-out" r="3.113717284145656" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(696.0196659934778, 656.031536614714)"><circle style="transition:all 0.5s ease-out" r="15.962790232871045" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(737.4982567413759, 671.8403077091855)"><circle r="20.305200179760106" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(703.4860447237852, 711.1549469088552)"><circle r="36.00979919102366" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(711.4735153029711, 668.6361656914793)"><circle style="transition:all 0.5s ease-out" r="3.7560365250643617" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(719.0705565267546, 673.3684832311789)"><circle style="transition:all 0.5s ease-out" r="1.9943752007249353" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(700.1719673912833, 408.902033403967)"><circle style="transition:all 0.5s ease-out" r="15.962790232871045" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(745.2768995065188, 421.3799412213313)"><circle r="19.78767480101326" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(712.9015633394456, 462.22219095366887)"><circle r="36.022171625965505" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(715.6497439498492, 418.7157636923048)"><circle style="transition:all 0.5s ease-out" r="3.7560365250643617" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(725.2881947188245, 421.6312732172943)"><circle style="transition:all 0.5s ease-out" r="3.113717284145656" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(803.6629517499538, 665.2141060036499)"><circle style="transition:all 0.5s ease-out" r="10.500106064052844" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(828.2722525930051, 665.2141060036499)"><circle style="transition:all 0.5s ease-out" r="10.410944194669167" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(814.8800858543933, 471.897689164889)"><circle style="transition:all 0.5s ease-out" r="14.205549002058543" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(842.9440722815704, 471.897689164889)"><circle style="transition:all 0.5s ease-out" r="10.160186840789294" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(832.661460831498, 493.57006181085046)"><circle style="transition:all 0.5s ease-out" r="10.129556120373689" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(832.4662202804312, 451.8354846024064)"><circle style="transition:all 0.5s ease-out" r="8.775109236080548" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(884.8885008614398, 619.8120754407543)"><circle r="37.45932660126524" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(936.6056848227626, 619.8667324149177)"><circle style="transition:all 0.5s ease-out" r="9.163144868295092" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(931.2305356359143, 633.1132579937947)"><circle style="transition:all 0.5s ease-out" r="3.0634115955276804" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(930.7486071074376, 607.9335001134996)"><circle style="transition:all 0.5s ease-out" r="2.2297792607303717" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(927.9980069013866, 601.2877698794412)"><circle style="transition:all 0.5s ease-out" r="1.7627952858286047" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(927.1404461478616, 639.8248825812485)"><circle style="transition:all 0.5s ease-out" r="1.5962790232871045" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(924.6824086343264, 596.1941403218046)"><circle style="transition:all 0.5s ease-out" r="1.1148896303651858" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(509.4171044352229, 562.1917603192146)"><circle style="transition:all 0.5s ease-out" r="16.915488168942034" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(594.3062912083872, 565.9804397585089)"><circle r="57.33320972162033" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(458.0816638954804, 593.1265242233236)"><circle r="35.253566773238525" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(414.8758296553668, 523.3580839612646)"><circle r="34.5097190001014" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(524.6060115057035, 653.8840051120144)"><circle r="42.501117020807236" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(504.2518553343613, 488.50593912578586)"><circle r="49.116129162646736" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(582.9945078259908, 639.9750511944035)"><circle style="transition:all 0.5s ease-out" r="9.751301704081884" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(527.645184289383, 545.4441904397316)"><circle style="transition:all 0.5s ease-out" r="4.670575926218484" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(907.9855335666233, 514.4888056134556)"><circle style="transition:all 0.5s ease-out" r="26.694564923045178" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#89e051;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(946.8511951339568, 512.6689056384696)"><circle style="transition:all 0.5s ease-out" r="9.002345443872255" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#89e051;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(941.3447532984862, 531.7563265483296)"><circle style="transition:all 0.5s ease-out" r="7.663599184004703" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(934.2800492399537, 492.76665548351286)"><circle style="transition:all 0.5s ease-out" r="4.201226036304242" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(937.4378773274523, 501.8054636583465)"><circle style="transition:all 0.5s ease-out" r="2.1733199888659107" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#000000;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(930.2147611372303, 536.0271700744597)"><circle style="transition:all 0.5s ease-out" r="1.0576771714971624" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#000080;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(259.50639450702926, 583.3369571703405)"><circle style="transition:all 0.5s ease-out" r="14.651363552229816" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#000080;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(287.58497787538596, 583.3369571703405)"><circle style="transition:all 0.5s ease-out" r="9.728969231797723" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#000080;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(277.22350397684926, 598.6848047757594)"><circle style="transition:all 0.5s ease-out" r="5.090786757724965" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#000080;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(276.7363407435365, 571.9340420987187)"><circle style="transition:all 0.5s ease-out" r="2.3118843435500898" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(145.35236821742998, 347.7474478059432)"><circle style="transition:all 0.5s ease-out" r="23.12825035332259" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(238.23521648313155, 347.7474478059432)"><circle r="66.05634732804975" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(150.4169405380807, 415.6211520126936)"><circle r="41.235894079982856" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(157.3145013973165, 295.9731192592728)"><circle r="26.311750131346653" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(227.16624740950257, 461.3906122075975)"><circle r="44.42635886927701" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(207.21743410746618, 225.65633483009964)"><circle r="56.21501227668346" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(127.82674597229911, 318.6174108341751)"><circle style="transition:all 0.5s ease-out" r="7.169182450913925" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(248.7929608681725, 274.51189920246037)"><circle style="transition:all 0.5s ease-out" r="4.238047301540488" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#ff9900;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(207.42735027885925, 708.6951437921741)"><circle style="transition:all 0.5s ease-out" r="2.5666686786275803" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#ff9900;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(215.47903071613914, 710.7959504080628)"><circle style="transition:all 0.5s ease-out" r="2.554533061334901" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#ff9900;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(209.65086356217867, 716.7010906461754)"><circle style="transition:all 0.5s ease-out" r="2.5423395164804927" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#ff9900;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(213.27078732811043, 702.8052905566826)"><circle style="transition:all 0.5s ease-out" r="2.5300872065332993" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(200.05401611132078, 704.918139868741)"><circle style="transition:all 0.5s ease-out" r="2.517775273583543" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#ff9900;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(201.60209235444364, 714.5682369155626)"><circle style="transition:all 0.5s ease-out" r="2.505402838641701" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(221.2273660037037, 704.881707944755)"><circle style="transition:all 0.5s ease-out" r="2.4929690009061694" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(425.61239936026266, 162.4669254658571)"><circle style="transition:all 0.5s ease-out" r="2.638310401036352" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(434.07418614729835, 162.69627082756668)"><circle style="transition:all 0.5s ease-out" r="2.626505821014262" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(429.65936745343845, 169.8908278163945)"><circle style="transition:all 0.5s ease-out" r="2.6146479463642924" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(430.0534273707054, 155.28793263010792)"><circle style="transition:all 0.5s ease-out" r="2.602736048667291" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(421.66455565447404, 155.01311229583553)"><circle style="transition:all 0.5s ease-out" r="2.5907693827582245" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(421.26817543265906, 169.67626507318604)"><circle style="transition:all 0.5s ease-out" r="2.5787471861822056" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(438.4196387930949, 155.51486555860424)"><circle style="transition:all 0.5s ease-out" r="2.5666686786275803" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(438.2848073939843, 169.94261520585496)"><circle style="transition:all 0.5s ease-out" r="2.554533061334901" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(417.2409010633938, 162.07509360910962)"><circle style="transition:all 0.5s ease-out" r="2.5423395164804927" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(412.9748066708989, 169.16265189912102)"><circle style="transition:all 0.5s ease-out" r="2.5300872065332993" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(442.4181410393257, 162.77026434518692)"><circle style="transition:all 0.5s ease-out" r="2.517775273583543" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(446.54717626459643, 169.88164440616796)"><circle style="transition:all 0.5s ease-out" r="2.505402838641701" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(434.4660771243392, 148.26311788184591)"><circle style="transition:all 0.5s ease-out" r="2.4929690009061694" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(495.69864839840363, 164.911732467699)"><circle style="transition:all 0.5s ease-out" r="23.653008211259493" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(525.5799944005257, 164.911732467699)"><circle style="transition:all 0.5s ease-out" r="2.5300872065332993" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(524.2789683300209, 173.5480254541209)"><circle style="transition:all 0.5s ease-out" r="2.505402838641701" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#CED6E0;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(524.2701789343807, 156.28934442256914)"><circle style="transition:all 0.5s ease-out" r="2.4929690009061694" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(794.3084562792575, 548.3854730785346)"><circle style="transition:all 0.5s ease-out" r="4.480413936180172" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(806.0881115981031, 549.4862011247503)"><circle style="transition:all 0.5s ease-out" r="4.149127329614881" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#cb171e;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(799.6692309728492, 557.8113160642935)"><circle style="transition:all 0.5s ease-out" r="3.1632230473934895" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(801.3106644221552, 540.1970430747616)"><circle style="transition:all 0.5s ease-out" r="3.0936931710817444" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(788.3053319464401, 539.7033112712119)"><circle style="transition:all 0.5s ease-out" r="2.8750321049524312" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(788.303653801866, 556.6435953096267)"><circle style="transition:all 0.5s ease-out" r="2.5300872065332993" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(809.9338169638595, 540.5944554233872)"><circle style="transition:all 0.5s ease-out" r="2.338612218120313" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(749.1091628976864, 588.9585035139102)"><circle r="9.230311457880166" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(780.3236087640239, 588.9585035139102)"><circle r="12.368682889201382" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(729.4358967297371, 672.5389209403234)"><circle style="transition:all 0.5s ease-out" r="7.059989617883471" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(748.6692945611723, 671.6151231199971)"><circle style="transition:all 0.5s ease-out" r="6.131892967008523" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(740.2355641600319, 682.4369272267728)"><circle style="transition:all 0.5s ease-out" r="4.389324864074795" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(739.2438885164338, 661.9889698879966)"><circle style="transition:all 0.5s ease-out" r="4.141631158488443" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(730.0618618918625, 660.3003604587748)"><circle style="transition:all 0.5s ease-out" r="1.9943752007249353" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(686.3220085098977, 711.1549469088552)"><circle r="9.230311457880166" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(717.5240819412934, 711.1549469088552)"><circle r="12.356310454259537" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(740.9244480721876, 421.6491605182933)"><circle style="transition:all 0.5s ease-out" r="4.480413936180172" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(752.7041033910331, 422.74988856450926)"><circle style="transition:all 0.5s ease-out" r="4.149127329614881" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#cb171e;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(746.2852227657792, 431.07500350405235)"><circle style="transition:all 0.5s ease-out" r="3.1632230473934895" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(747.9266562150855, 413.4607305145205)"><circle style="transition:all 0.5s ease-out" r="3.0936931710817444" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(734.9213237393701, 412.96699871097064)"><circle style="transition:all 0.5s ease-out" r="2.8750321049524312" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(734.9196455947963, 429.9072827493856)"><circle style="transition:all 0.5s ease-out" r="2.5300872065332993" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(756.5498087567897, 413.85814286314627)"><circle style="transition:all 0.5s ease-out" r="2.338612218120313" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(695.7251546906163, 462.22219095366887)"><circle r="9.230311457880166" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(726.9396005569538, 462.22219095366887)"><circle r="12.368682889201382" style="transition:all 0.5s ease-out" stroke="#290819" stroke-opacity="0.2" stroke-width="1" fill="white"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(867.0843739634756, 619.8120754407543)"><circle style="transition:all 0.5s ease-out" r="15.956949118971922" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(902.6945752725762, 619.8120754407543)"><circle style="transition:all 0.5s ease-out" r="15.955001605799483" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(580.3921342375612, 567.2474605155954)"><circle style="transition:all 0.5s ease-out" r="16.95585494070716" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(615.54892688306, 566.37871912528)"><circle style="transition:all 0.5s ease-out" r="15.01173115851441" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(600.5734521957364, 595.8771650857434)"><circle style="transition:all 0.5s ease-out" r="14.870304104377505" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(599.0992384024407, 539.319530037255)"><circle style="transition:all 0.5s ease-out" r="13.455105908985864" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(569.3599637413832, 535.6535804473974)"><circle style="transition:all 0.5s ease-out" r="13.308812551281742" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(568.5244202732299, 596.4863140404705)"><circle style="transition:all 0.5s ease-out" r="11.399712396789143" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(626.753582025773, 539.41027774004)"><circle style="transition:all 0.5s ease-out" r="10.991703594232959" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(628.5358085380284, 591.6520052855279)"><circle style="transition:all 0.5s ease-out" r="10.202915360879704" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(552.5611494147806, 555.9905907971399)"><circle style="transition:all 0.5s ease-out" r="9.865355894352863" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(553.1602794516452, 578.2747490953171)"><circle style="transition:all 0.5s ease-out" r="9.223985303352826" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(639.3473345839908, 557.3479863732003)"><circle style="transition:all 0.5s ease-out" r="7.242493290932592" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(639.1246071510704, 574.523032088991)"><circle style="transition:all 0.5s ease-out" r="6.731016302446656" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(443.11852020517836, 589.7061140661632)"><circle style="transition:all 0.5s ease-out" r="16.206216060894253" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(476.1697056182889, 589.7061140661632)"><circle style="transition:all 0.5s ease-out" r="13.14671876788706" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(462.3362705869451, 613.5349054762272)"><circle style="transition:all 0.5s ease-out" r="10.708165221380808" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(461.998157027928, 570.4602367727)"><circle style="transition:all 0.5s ease-out" r="7.055586755205241" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(405.5569452888239, 526.6696537563533)"><circle style="transition:all 0.5s ease-out" r="10.372069357046513" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(436.4581111318186, 522.2683524858188)"><circle style="transition:all 0.5s ease-out" r="9.899943702394749" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(423.59805599010997, 540.2158287803786)"><circle style="transition:all 0.5s ease-out" r="8.988527560909425" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(419.1712671192247, 509.1287181175611)"><circle style="transition:all 0.5s ease-out" r="8.625096314857295" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(399.71836680738704, 506.0361139356462)"><circle style="transition:all 0.5s ease-out" r="7.87162610656824" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(408.69643698319004, 542.8905072124011)"><circle style="transition:all 0.5s ease-out" r="2.9497207012310076" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(506.4152745337826, 644.0376483763788)"><circle style="transition:all 0.5s ease-out" r="18.118242858878073" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(544.6778071963926, 644.0376483763788)"><circle style="transition:all 0.5s ease-out" r="16.446039219402664" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(527.1805505560818, 676.130185923027)"><circle style="transition:all 0.5s ease-out" r="16.40820609080209" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(485.9645741559032, 488.27286157520666)"><circle style="transition:all 0.5s ease-out" r="19.06428668533753" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(534.2710102313399, 486.01623661763927)"><circle style="transition:all 0.5s ease-out" r="15.993906812563338" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(513.5447027152892, 512.4774473579608)"><circle style="transition:all 0.5s ease-out" r="14.42694752115482" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(511.18965205826174, 467.8165092578682)"><circle style="transition:all 0.5s ease-out" r="10.209004836420863" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(490.8248310327502, 456.4771465535253)"><circle style="transition:all 0.5s ease-out" r="9.899943702394749" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(488.9832878541166, 517.9124219808067)"><circle style="transition:all 0.5s ease-out" r="7.528601283641565" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(218.9824466882351, 348.9466077434991)"><circle style="transition:all 0.5s ease-out" r="23.243510355019925" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(263.98404318009864, 348.9466077434991)"><circle style="transition:all 0.5s ease-out" r="18.059835552514407" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(245.84326807751088, 379.18120248548524)"><circle style="transition:all 0.5s ease-out" r="13.501216756645386" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(245.7250379645878, 319.989741465146)"><circle style="transition:all 0.5s ease-out" r="12.474812894971882" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(219.25469799242958, 309.82336084319115)"><circle style="transition:all 0.5s ease-out" r="12.182433222257409" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(217.90124581810235, 387.9636481031643)"><circle style="transition:all 0.5s ease-out" r="12.090257119538382" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(273.59528142323325, 316.69966685628435)"><circle style="transition:all 0.5s ease-out" r="11.89070428940816" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(274.16382958716224, 380.23064505792473)"><circle style="transition:all 0.5s ease-out" r="11.14053149344311" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(195.0090358034781, 320.1976263658228)"><circle style="transition:all 0.5s ease-out" r="10.491223976408802" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(194.75710912532176, 376.74506745475134)"><circle style="transition:all 0.5s ease-out" r="9.93128263390653" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(239.87084856109337, 294.95334306980504)"><circle style="transition:all 0.5s ease-out" r="9.53866104828" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(236.5441426781616, 402.3310725581411)"><circle style="transition:all 0.5s ease-out" r="7.748282408725701" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(286.98479259284227, 333.5401600578917)"><circle style="transition:all 0.5s ease-out" r="5.925719667943881" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(286.00346040738305, 364.24480437869096)"><circle style="transition:all 0.5s ease-out" r="5.054029693844222" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(132.79498340086212, 415.6211520126936)"><circle style="transition:all 0.5s ease-out" r="19.91568635843506" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(172.18175218868038, 415.6211520126936)"><circle style="transition:all 0.5s ease-out" r="15.772831845053968" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(155.73997633638484, 439.31790794192233)"><circle style="transition:all 0.5s ease-out" r="9.371043614765634" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(155.3293871665507, 397.23825020062196)"><circle style="transition:all 0.5s ease-out" r="5.46750786500527" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(149.1246518624414, 295.9338023462044)"><circle style="transition:all 0.5s ease-out" r="10.209004836420863" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(169.96307846973517, 295.9338023462044)"><circle style="transition:all 0.5s ease-out" r="6.93117118654369" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(162.48791101368582, 311.28836827561685)"><circle style="transition:all 0.5s ease-out" r="6.448072874907293" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(162.14944317520576, 283.21671059769596)"><circle style="transition:all 0.5s ease-out" r="4.296304980474843" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(151.32885629641498, 278.2533460262186)"><circle style="transition:all 0.5s ease-out" r="3.9100690941617127" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(205.3788627196585, 457.96021668739337)"><circle style="transition:all 0.5s ease-out" r="18.67232117479714" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(243.0441599324174, 457.96021668739337)"><circle style="transition:all 0.5s ease-out" r="15.294725453632486" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(227.3688952539737, 487.59010779397755)"><circle style="transition:all 0.5s ease-out" r="14.527828990069725" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(227.0896061854986, 432.07593786623744)"><circle style="transition:all 0.5s ease-out" r="11.41333375712294" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(195.49180936598424, 225.25900365043145)"><circle style="transition:all 0.5s ease-out" r="19.713379956279145" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(237.16007674882795, 225.25900365043145)"><circle style="transition:all 0.5s ease-out" r="18.256636842235327" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(217.7222880177454, 259.31448187655974)"><circle style="transition:all 0.5s ease-out" r="17.2573967196631" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(217.63941821360382, 194.0136925297257)"><circle style="transition:all 0.5s ease-out" r="14.887012316506791" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(187.069289677189, 190.6941828566019)"><circle style="transition:all 0.5s ease-out" r="12.164564793037087" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(190.03551238186506, 255.21124380971486)"><circle style="transition:all 0.5s ease-out" r="7.033531100254954" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(242.8599969610752, 197.0561738403739)"><circle style="transition:all 0.5s ease-out" r="6.818167672278506" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(745.6662674888516, 587.1321655686634)"><circle style="transition:all 0.5s ease-out" r="1.6347490966432783" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#2b2b2b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(752.5955461931113, 587.1321655686634)"><circle style="transition:all 0.5s ease-out" r="1.5962790232871045" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#ece2a9;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(749.1687121807647, 592.9943436825869)"><circle style="transition:all 0.5s ease-out" r="1.4957814005437016" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(775.9567081982758, 588.9585035139102)"><circle style="transition:all 0.5s ease-out" r="4.30353173912401" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(786.4762657953125, 588.9585035139102)"><circle style="transition:all 0.5s ease-out" r="2.517775273583543" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(682.879113101063, 709.3286089636084)"><circle style="transition:all 0.5s ease-out" r="1.6347490966432783" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#2b2b2b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(689.8083918053227, 709.3286089636084)"><circle style="transition:all 0.5s ease-out" r="1.5962790232871045" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#ece2a9;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(686.3815577929761, 715.1907870775319)"><circle style="transition:all 0.5s ease-out" r="1.4957814005437016" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(713.1695538104871, 711.1549469088552)"><circle style="transition:all 0.5s ease-out" r="4.30353173912401" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(723.676738972582, 711.1549469088552)"><circle style="transition:all 0.5s ease-out" r="2.505402838641701" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(692.2822592817815, 460.3958530084221)"><circle style="transition:all 0.5s ease-out" r="1.6347490966432783" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#2b2b2b;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(699.2115379860412, 460.3958530084221)"><circle style="transition:all 0.5s ease-out" r="1.5962790232871045" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#ece2a9;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(695.7847039736946, 466.2580311223456)"><circle style="transition:all 0.5s ease-out" r="1.4957814005437016" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(722.5726999912057, 462.22219095366887)"><circle style="transition:all 0.5s ease-out" r="4.30353173912401" stroke-width="0" stroke="#374151"></circle></g><g style="fill:#701516;transition:transform 0s ease-out, fill 0.1s ease-out" transform="translate(733.0922575882424, 462.22219095366887)"><circle style="transition:all 0.5s ease-out" r="2.517775273583543" stroke-width="0" stroke="#374151"></circle></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(319.99422221520257, 687.2164700211342)"><path fill="none" d="M 0 46.02921418068235 A 46.02921418068235 46.02921418068235 0 0 1 0 -46.02921418068235 A 46.02921418068235 46.02921418068235 0 0 1 0 46.02921418068235" id="CircleText--1" transform="rotate(1)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:15px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--1" startOffset="50%">views</textPath></text><path fill="none" d="M 0 46.02921418068235 A 46.02921418068235 46.02921418068235 0 0 1 0 -46.02921418068235 A 46.02921418068235 46.02921418068235 0 0 1 0 46.02921418068235" id="CircleText--2" transform="rotate(1)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:15px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--2" startOffset="50%">views</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(661.4377379675747, 565.1941312103406)"><path fill="none" d="M 0 310.5618666214336 A 310.5618666214336 310.5618666214336 0 0 1 0 -310.5618666214336 A 310.5618666214336 310.5618666214336 0 0 1 0 310.5618666214336" id="CircleText--3" transform="rotate(1)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:15px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--3" startOffset="50%">test</textPath></text><path fill="none" d="M 0 310.5618666214336 A 310.5618666214336 310.5618666214336 0 0 1 0 -310.5618666214336 A 310.5618666214336 310.5618666214336 0 0 1 0 310.5618666214336" id="CircleText--4" transform="rotate(1)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:15px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--4" startOffset="50%">test</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(288.8905634421281, 583.3369571703405)"><path fill="none" d="M 0 56.43203365598711 A 56.43203365598711 56.43203365598711 0 0 1 0 -56.43203365598711 A 56.43203365598711 56.43203365598711 0 0 1 0 56.43203365598711" id="CircleText--5" transform="rotate(1)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:15px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--5" startOffset="50%">lua</textPath></text><path fill="none" d="M 0 56.43203365598711 A 56.43203365598711 56.43203365598711 0 0 1 0 -56.43203365598711 A 56.43203365598711 56.43203365598711 0 0 1 0 56.43203365598711" id="CircleText--6" transform="rotate(1)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:15px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--6" startOffset="50%">lua</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(198.2622918656833, 337.650139496829)"><path fill="none" d="M 0 199.43813337856645 A 199.43813337856645 199.43813337856645 0 0 1 0 -199.43813337856645 A 199.43813337856645 199.43813337856645 0 0 1 0 199.43813337856645" id="CircleText--7" transform="rotate(1)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:15px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--7" startOffset="50%">lib</textPath></text><path fill="none" d="M 0 199.43813337856645 A 199.43813337856645 199.43813337856645 0 0 1 0 -199.43813337856645 A 199.43813337856645 199.43813337856645 0 0 1 0 199.43813337856645" id="CircleText--8" transform="rotate(1)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:15px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--8" startOffset="50%">lib</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(208.84229622707048, 675.5867014055564)"><path fill="none" d="M 0 59.7124021629937 A 59.7124021629937 59.7124021629937 0 0 1 0 -59.7124021629937 A 59.7124021629937 59.7124021629937 0 0 1 0 59.7124021629937" id="CircleText--9" transform="rotate(1)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:15px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--9" startOffset="50%">docs</textPath></text><path fill="none" d="M 0 59.7124021629937 A 59.7124021629937 59.7124021629937 0 0 1 0 -59.7124021629937 A 59.7124021629937 59.7124021629937 0 0 1 0 59.7124021629937" id="CircleText--10" transform="rotate(1)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:15px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--10" startOffset="50%">docs</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(467.6116292400953, 199.49715021934765)"><path fill="none" d="M 0 97.27512036255078 A 97.27512036255078 97.27512036255078 0 0 1 0 -97.27512036255078 A 97.27512036255078 97.27512036255078 0 0 1 0 97.27512036255078" id="CircleText--11" transform="rotate(1)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:15px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--11" startOffset="50%">public</textPath></text><path fill="none" d="M 0 97.27512036255078 A 97.27512036255078 97.27512036255078 0 0 1 0 -97.27512036255078 A 97.27512036255078 97.27512036255078 0 0 1 0 97.27512036255078" id="CircleText--12" transform="rotate(1)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:15px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--12" startOffset="50%">public</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(778.8592125527111, 570.0827446562124)"><path fill="none" d="M 0 62.70235506011423 A 62.70235506011423 62.70235506011423 0 0 1 0 -62.70235506011423 A 62.70235506011423 62.70235506011423 0 0 1 0 62.70235506011423" id="CircleText--13" transform="rotate(2)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--13" startOffset="50%">rails6_dummy</textPath></text><path fill="none" d="M 0 62.70235506011423 A 62.70235506011423 62.70235506011423 0 0 1 0 -62.70235506011423 A 62.70235506011423 62.70235506011423 0 0 1 0 62.70235506011423" id="CircleText--14" transform="rotate(2)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--14" startOffset="50%">rails6_dummy</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(717.5459367246649, 693.1394072463729)"><path fill="none" d="M 0 62.86237524727761 A 62.86237524727761 62.86237524727761 0 0 1 0 -62.86237524727761 A 62.86237524727761 62.86237524727761 0 0 1 0 62.86237524727761" id="CircleText--15" transform="rotate(2)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--15" startOffset="50%">rails5_dummy</textPath></text><path fill="none" d="M 0 62.86237524727761 A 62.86237524727761 62.86237524727761 0 0 1 0 -62.86237524727761 A 62.86237524727761 62.86237524727761 0 0 1 0 62.86237524727761" id="CircleText--16" transform="rotate(2)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--16" startOffset="50%">rails5_dummy</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(725.4752043456411, 443.3464320959712)"><path fill="none" d="M 0 62.702355060114215 A 62.702355060114215 62.702355060114215 0 0 1 0 -62.702355060114215 A 62.702355060114215 62.702355060114215 0 0 1 0 62.702355060114215" id="CircleText--17" transform="rotate(2)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--17" startOffset="50%">rails4_dummy</textPath></text><path fill="none" d="M 0 62.702355060114215 A 62.702355060114215 62.702355060114215 0 0 1 0 -62.702355060114215 A 62.702355060114215 62.702355060114215 0 0 1 0 62.702355060114215" id="CircleText--18" transform="rotate(2)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--18" startOffset="50%">rails4_dummy</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(815.9230212367876, 665.2141060036499)"><path fill="none" d="M 0 27.458426135215838 A 27.458426135215838 27.458426135215838 0 0 1 0 -27.458426135215838 A 27.458426135215838 27.458426135215838 0 0 1 0 27.458426135215838" id="CircleText--19" transform="rotate(2)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--19" startOffset="50%">integration</textPath></text><path fill="none" d="M 0 27.458426135215838 A 27.458426135215838 27.458426135215838 0 0 1 0 -27.458426135215838 A 27.458426135215838 27.458426135215838 0 0 1 0 27.458426135215838" id="CircleText--20" transform="rotate(2)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--20" startOffset="50%">integration</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(830.9853756043558, 473.38933293249397)"><path fill="none" d="M 0 35.078018549283044 A 35.078018549283044 35.078018549283044 0 0 1 0 -35.078018549283044 A 35.078018549283044 35.078018549283044 0 0 1 0 35.078018549283044" id="CircleText--21" transform="rotate(2)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--21" startOffset="50%">forked</textPath></text><path fill="none" d="M 0 35.078018549283044 A 35.078018549283044 35.078018549283044 0 0 1 0 -35.078018549283044 A 35.078018549283044 35.078018549283044 0 0 1 0 35.078018549283044" id="CircleText--22" transform="rotate(2)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--22" startOffset="50%">forked</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(896.5990215299141, 619.8107385171486)"><path fill="none" d="M 0 53.169847346054155 A 53.169847346054155 53.169847346054155 0 0 1 0 -53.169847346054155 A 53.169847346054155 53.169847346054155 0 0 1 0 53.169847346054155" id="CircleText--23" transform="rotate(2)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--23" startOffset="50%">fixtures</textPath></text><path fill="none" d="M 0 53.169847346054155 A 53.169847346054155 53.169847346054155 0 0 1 0 -53.169847346054155 A 53.169847346054155 53.169847346054155 0 0 1 0 53.169847346054155" id="CircleText--24" transform="rotate(2)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--24" startOffset="50%">fixtures</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(526.6706855709276, 561.9800413946193)"><path fill="none" d="M 0 156.78797315176226 A 156.78797315176226 156.78797315176226 0 0 1 0 -156.78797315176226 A 156.78797315176226 156.78797315176226 0 0 1 0 156.78797315176226" id="CircleText--25" transform="rotate(2)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--25" startOffset="50%">coverband</textPath></text><path fill="none" d="M 0 156.78797315176226 A 156.78797315176226 156.78797315176226 0 0 1 0 -156.78797315176226 A 156.78797315176226 156.78797315176226 0 0 1 0 156.78797315176226" id="CircleText--26" transform="rotate(2)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--26" startOffset="50%">coverband</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(917.8131106864573, 514.6120585177536)"><path fill="none" d="M 0 42.24428624341126 A 42.24428624341126 42.24428624341126 0 0 1 0 -42.24428624341126 A 42.24428624341126 42.24428624341126 0 0 1 0 42.24428624341126" id="CircleText--27" transform="rotate(2)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--27" startOffset="50%">benchmarks</textPath></text><path fill="none" d="M 0 42.24428624341126 A 42.24428624341126 42.24428624341126 0 0 1 0 -42.24428624341126 A 42.24428624341126 42.24428624341126 0 0 1 0 42.24428624341126" id="CircleText--28" transform="rotate(2)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--28" startOffset="50%">benchmarks</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(271.08448903099156, 583.3369571703405)"><path fill="none" d="M 0 30.92770866052136 A 30.92770866052136 30.92770866052136 0 0 1 0 -30.92770866052136 A 30.92770866052136 30.92770866052136 0 0 1 0 30.92770866052136" id="CircleText--29" transform="rotate(2)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--29" startOffset="50%">test</textPath></text><path fill="none" d="M 0 30.92770866052136 A 30.92770866052136 30.92770866052136 0 0 1 0 -30.92770866052136 A 30.92770866052136 30.92770866052136 0 0 1 0 30.92770866052136" id="CircleText--30" transform="rotate(2)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--30" startOffset="50%">test</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(216.69481484791584, 337.650139496829)"><path fill="none" d="M 0 173.30735981200468 A 173.30735981200468 173.30735981200468 0 0 1 0 -173.30735981200468 A 173.30735981200468 173.30735981200468 0 0 1 0 173.30735981200468" id="CircleText--31" transform="rotate(2)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--31" startOffset="50%">coverband</textPath></text><path fill="none" d="M 0 173.30735981200468 A 173.30735981200468 173.30735981200468 0 0 1 0 -173.30735981200468 A 173.30735981200468 173.30735981200468 0 0 1 0 173.30735981200468" id="CircleText--32" transform="rotate(2)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--32" startOffset="50%">coverband</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(429.94733392039217, 163.4979749857882)"><path fill="none" d="M 0 25.555665603024792 A 25.555665603024792 25.555665603024792 0 0 1 0 -25.555665603024792 A 25.555665603024792 25.555665603024792 0 0 1 0 25.555665603024792" id="CircleText--33" transform="rotate(2)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--33" startOffset="50%">images</textPath></text><path fill="none" d="M 0 25.555665603024792 A 25.555665603024792 25.555665603024792 0 0 1 0 -25.555665603024792 A 25.555665603024792 25.555665603024792 0 0 1 0 25.555665603024792" id="CircleText--34" transform="rotate(2)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--34" startOffset="50%">images</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(500.15832910431885, 164.94941980931233)"><path fill="none" d="M 0 32.81109874052291 A 32.81109874052291 32.81109874052291 0 0 1 0 -32.81109874052291 A 32.81109874052291 32.81109874052291 0 0 1 0 32.81109874052291" id="CircleText--35" transform="rotate(2)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--35" startOffset="50%">colorbox</textPath></text><path fill="none" d="M 0 32.81109874052291 A 32.81109874052291 32.81109874052291 0 0 1 0 -32.81109874052291 A 32.81109874052291 32.81109874052291 0 0 1 0 32.81109874052291" id="CircleText--36" transform="rotate(2)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:14px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--36" startOffset="50%">colorbox</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(798.6609077135887, 548.1162537815725)"><path fill="none" d="M 0 20 A 20 20 0 0 1 0 -20 A 20 20 0 0 1 0 20" id="CircleText--37" transform="rotate(3)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:13px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--37" startOffset="50%">config</textPath></text><path fill="none" d="M 0 20 A 20 20 0 0 1 0 -20 A 20 20 0 0 1 0 20" id="CircleText--38" transform="rotate(3)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:13px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--38" startOffset="50%">config</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(766.2855715465157, 588.9585035139102)"><path fill="none" d="M 0 33.022171625965505 A 33.022171625965505 33.022171625965505 0 0 1 0 -33.022171625965505 A 33.022171625965505 33.022171625965505 0 0 1 0 33.022171625965505" id="CircleText--39" transform="rotate(3)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:13px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--39" startOffset="50%">app</textPath></text><path fill="none" d="M 0 33.022171625965505 A 33.022171625965505 33.022171625965505 0 0 1 0 -33.022171625965505 A 33.022171625965505 33.022171625965505 0 0 1 0 33.022171625965505" id="CircleText--40" transform="rotate(3)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:13px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--40" startOffset="50%">app</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(737.4982567413759, 671.8403077091855)"><path fill="none" d="M 0 20 A 20 20 0 0 1 0 -20 A 20 20 0 0 1 0 20" id="CircleText--41" transform="rotate(3)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:13px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--41" startOffset="50%">config</textPath></text><path fill="none" d="M 0 20 A 20 20 0 0 1 0 -20 A 20 20 0 0 1 0 20" id="CircleText--42" transform="rotate(3)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:13px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--42" startOffset="50%">config</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(703.4860447237852, 711.1549469088552)"><path fill="none" d="M 0 33.00979919102366 A 33.00979919102366 33.00979919102366 0 0 1 0 -33.00979919102366 A 33.00979919102366 33.00979919102366 0 0 1 0 33.00979919102366" id="CircleText--43" transform="rotate(3)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:13px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--43" startOffset="50%">app</textPath></text><path fill="none" d="M 0 33.00979919102366 A 33.00979919102366 33.00979919102366 0 0 1 0 -33.00979919102366 A 33.00979919102366 33.00979919102366 0 0 1 0 33.00979919102366" id="CircleText--44" transform="rotate(3)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:13px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--44" startOffset="50%">app</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(745.2768995065188, 421.3799412213313)"><path fill="none" d="M 0 20 A 20 20 0 0 1 0 -20 A 20 20 0 0 1 0 20" id="CircleText--45" transform="rotate(3)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:13px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--45" startOffset="50%">config</textPath></text><path fill="none" d="M 0 20 A 20 20 0 0 1 0 -20 A 20 20 0 0 1 0 20" id="CircleText--46" transform="rotate(3)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:13px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--46" startOffset="50%">config</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(712.9015633394456, 462.22219095366887)"><path fill="none" d="M 0 33.022171625965505 A 33.022171625965505 33.022171625965505 0 0 1 0 -33.022171625965505 A 33.022171625965505 33.022171625965505 0 0 1 0 33.022171625965505" id="CircleText--47" transform="rotate(3)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:13px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--47" startOffset="50%">app</textPath></text><path fill="none" d="M 0 33.022171625965505 A 33.022171625965505 33.022171625965505 0 0 1 0 -33.022171625965505 A 33.022171625965505 33.022171625965505 0 0 1 0 33.022171625965505" id="CircleText--48" transform="rotate(3)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:13px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--48" startOffset="50%">app</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(884.8885008614398, 619.8120754407543)"><path fill="none" d="M 0 34.45932660126524 A 34.45932660126524 34.45932660126524 0 0 1 0 -34.45932660126524 A 34.45932660126524 34.45932660126524 0 0 1 0 34.45932660126524" id="CircleText--49" transform="rotate(3)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:13px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--49" startOffset="50%">app</textPath></text><path fill="none" d="M 0 34.45932660126524 A 34.45932660126524 34.45932660126524 0 0 1 0 -34.45932660126524 A 34.45932660126524 34.45932660126524 0 0 1 0 34.45932660126524" id="CircleText--50" transform="rotate(3)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:13px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--50" startOffset="50%">app</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(594.3062912083872, 565.9804397585089)"><path fill="none" d="M 0 54.333209721620335 A 54.333209721620335 54.333209721620335 0 0 1 0 -54.333209721620335 A 54.333209721620335 54.333209721620335 0 0 1 0 54.333209721620335" id="CircleText--51" transform="rotate(3)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:13px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--51" startOffset="50%">utils</textPath></text><path fill="none" d="M 0 54.333209721620335 A 54.333209721620335 54.333209721620335 0 0 1 0 -54.333209721620335 A 54.333209721620335 54.333209721620335 0 0 1 0 54.333209721620335" id="CircleText--52" transform="rotate(3)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:13px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--52" startOffset="50%">utils</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(458.0816638954804, 593.1265242233236)"><path fill="none" d="M 0 32.253566773238525 A 32.253566773238525 32.253566773238525 0 0 1 0 -32.253566773238525 A 32.253566773238525 32.253566773238525 0 0 1 0 32.253566773238525" id="CircleText--53" transform="rotate(3)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:13px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--53" startOffset="50%">reporters</textPath></text><path fill="none" d="M 0 32.253566773238525 A 32.253566773238525 32.253566773238525 0 0 1 0 -32.253566773238525 A 32.253566773238525 32.253566773238525 0 0 1 0 32.253566773238525" id="CircleText--54" transform="rotate(3)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:13px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--54" startOffset="50%">reporters</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(414.8758296553668, 523.3580839612646)"><path fill="none" d="M 0 31.5097190001014 A 31.5097190001014 31.5097190001014 0 0 1 0 -31.5097190001014 A 31.5097190001014 31.5097190001014 0 0 1 0 31.5097190001014" id="CircleText--55" transform="rotate(3)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:13px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--55" startOffset="50%">integrations</textPath></text><path fill="none" d="M 0 31.5097190001014 A 31.5097190001014 31.5097190001014 0 0 1 0 -31.5097190001014 A 31.5097190001014 31.5097190001014 0 0 1 0 31.5097190001014" id="CircleText--56" transform="rotate(3)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:13px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--56" startOffset="50%">integrations</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(524.6060115057035, 653.8840051120144)"><path fill="none" d="M 0 39.501117020807236 A 39.501117020807236 39.501117020807236 0 0 1 0 -39.501117020807236 A 39.501117020807236 39.501117020807236 0 0 1 0 39.501117020807236" id="CircleText--57" transform="rotate(3)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:13px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--57" startOffset="50%">collectors</textPath></text><path fill="none" d="M 0 39.501117020807236 A 39.501117020807236 39.501117020807236 0 0 1 0 -39.501117020807236 A 39.501117020807236 39.501117020807236 0 0 1 0 39.501117020807236" id="CircleText--58" transform="rotate(3)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:13px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--58" startOffset="50%">collectors</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(504.2518553343613, 488.50593912578586)"><path fill="none" d="M 0 46.116129162646736 A 46.116129162646736 46.116129162646736 0 0 1 0 -46.116129162646736 A 46.116129162646736 46.116129162646736 0 0 1 0 46.116129162646736" id="CircleText--59" transform="rotate(3)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:13px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--59" startOffset="50%">adapters</textPath></text><path fill="none" d="M 0 46.116129162646736 A 46.116129162646736 46.116129162646736 0 0 1 0 -46.116129162646736 A 46.116129162646736 46.116129162646736 0 0 1 0 46.116129162646736" id="CircleText--60" transform="rotate(3)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:13px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--60" startOffset="50%">adapters</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(238.23521648313155, 347.7474478059432)"><path fill="none" d="M 0 63.05634732804975 A 63.05634732804975 63.05634732804975 0 0 1 0 -63.05634732804975 A 63.05634732804975 63.05634732804975 0 0 1 0 63.05634732804975" id="CircleText--61" transform="rotate(3)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:13px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--61" startOffset="50%">utils</textPath></text><path fill="none" d="M 0 63.05634732804975 A 63.05634732804975 63.05634732804975 0 0 1 0 -63.05634732804975 A 63.05634732804975 63.05634732804975 0 0 1 0 63.05634732804975" id="CircleText--62" transform="rotate(3)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:13px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--62" startOffset="50%">utils</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(150.4169405380807, 415.6211520126936)"><path fill="none" d="M 0 38.235894079982856 A 38.235894079982856 38.235894079982856 0 0 1 0 -38.235894079982856 A 38.235894079982856 38.235894079982856 0 0 1 0 38.235894079982856" id="CircleText--63" transform="rotate(3)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:13px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--63" startOffset="50%">reporters</textPath></text><path fill="none" d="M 0 38.235894079982856 A 38.235894079982856 38.235894079982856 0 0 1 0 -38.235894079982856 A 38.235894079982856 38.235894079982856 0 0 1 0 38.235894079982856" id="CircleText--64" transform="rotate(3)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:13px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--64" startOffset="50%">reporters</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(157.3145013973165, 295.9731192592728)"><path fill="none" d="M 0 23.311750131346656 A 23.311750131346656 23.311750131346656 0 0 1 0 -23.311750131346656 A 23.311750131346656 23.311750131346656 0 0 1 0 23.311750131346656" id="CircleText--65" transform="rotate(3)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:13px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--65" startOffset="50%">integrations</textPath></text><path fill="none" d="M 0 23.311750131346656 A 23.311750131346656 23.311750131346656 0 0 1 0 -23.311750131346656 A 23.311750131346656 23.311750131346656 0 0 1 0 23.311750131346656" id="CircleText--66" transform="rotate(3)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:13px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--66" startOffset="50%">integrations</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(227.16624740950257, 461.3906122075975)"><path fill="none" d="M 0 41.42635886927701 A 41.42635886927701 41.42635886927701 0 0 1 0 -41.42635886927701 A 41.42635886927701 41.42635886927701 0 0 1 0 41.42635886927701" id="CircleText--67" transform="rotate(3)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:13px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--67" startOffset="50%">collectors</textPath></text><path fill="none" d="M 0 41.42635886927701 A 41.42635886927701 41.42635886927701 0 0 1 0 -41.42635886927701 A 41.42635886927701 41.42635886927701 0 0 1 0 41.42635886927701" id="CircleText--68" transform="rotate(3)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:13px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--68" startOffset="50%">collectors</textPath></text></g><g style="pointer-events:none;transition:all 0.5s ease-out" transform="translate(207.21743410746618, 225.65633483009964)"><path fill="none" d="M 0 53.21501227668347 A 53.21501227668347 53.21501227668347 0 0 1 0 -53.21501227668347 A 53.21501227668347 53.21501227668347 0 0 1 0 53.21501227668347" id="CircleText--69" transform="rotate(3)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:13px;transition:all 0.5s ease-out" fill="#374151" stroke="white" stroke-width="6"><textPath href="#CircleText--69" startOffset="50%">adapters</textPath></text><path fill="none" d="M 0 53.21501227668347 A 53.21501227668347 53.21501227668347 0 0 1 0 -53.21501227668347 A 53.21501227668347 53.21501227668347 0 0 1 0 53.21501227668347" id="CircleText--70" transform="rotate(3)" style="pointer-events:none"></path><text text-anchor="middle" style="font-size:13px;transition:all 0.5s ease-out" fill="#374151"><textPath href="#CircleText--70" startOffset="50%">adapters</textPath></text></g><g style="fill:#CED6E0;transition:transform 0s ease-out" transform="translate(181.62212425820078, 668.7863787424532)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">coverban...</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">coverban...</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">coverban...</text></g><g style="fill:#CED6E0;transition:transform 0s ease-out" transform="translate(235.26760587143946, 666.1470864897661)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">coverban...</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">coverban...</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">coverban...</text></g><g style="fill:#f1e05a;transition:transform 0s ease-out" transform="translate(414.80683990819495, 225.22631291636873)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">dependenci...</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">dependenci...</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">dependenci...</text></g><g style="fill:#563d7c;transition:transform 0s ease-out" transform="translate(512.4571013879283, 234.7504090693131)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">applicatio...</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">applicatio...</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">applicatio...</text></g><g style="fill:#083fa1;transition:transform 0s ease-out" transform="translate(320.00958704794687, 807.6027914744386)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">README.md</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">README.md</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">README.md</text></g><g style="fill:#083fa1;transition:transform 0s ease-out" transform="translate(392.2829724508863, 809.1010151493219)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">changes.md</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">changes.md</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">changes.md</text></g><g style="fill:#701516;transition:transform 0s ease-out" transform="translate(907.9855335666233, 514.4888056134556)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">benchmark...</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">benchmark...</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">benchmark...</text></g><g style="fill:#701516;transition:transform 0s ease-out" transform="translate(145.35236821742998, 347.7474478059432)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">configur...</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">configur...</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">configur...</text></g><g style="fill:#CED6E0;transition:transform 0s ease-out" transform="translate(495.69864839840363, 164.911732467699)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">loading.gif</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">loading.gif</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">loading.gif</text></g><g style="fill:#701516;transition:transform 0s ease-out" transform="translate(218.9824466882351, 348.9466077434991)"><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;transition:all 0.5s ease-out" fill="#4B5563" text-anchor="middle" dominant-baseline="middle" stroke="white" stroke-width="3" stroke-linejoin="round">source_f...</text><text style="pointer-events:none;opacity:1;font-size:14px;font-weight:500;transition:all 0.5s ease-out" text-anchor="middle" dominant-baseline="middle">source_f...</text><text style="pointer-events:none;opacity:0.9;font-size:14px;font-weight:500;mix-blend-mode:color-burn;transition:all 0.5s ease-out" fill="#110101" text-anchor="middle" dominant-baseline="middle">source_f...</text></g><g transform="translate(940, 740)"><g transform="translate(0, 0)"><circle r="5" fill="#563d7c"></circle><text x="10" style="font-size:14px;font-weight:300" dominant-baseline="middle">.css</text></g><g transform="translate(0, 15)"><circle r="5" fill="#701516"></circle><text x="10" style="font-size:14px;font-weight:300" dominant-baseline="middle">.erb</text></g><g transform="translate(0, 30)"><circle r="5" fill="#701516"></circle><text x="10" style="font-size:14px;font-weight:300" dominant-baseline="middle">.gemspec</text></g><g transform="translate(0, 45)"><circle r="5" fill="#000000"></circle><text x="10" style="font-size:14px;font-weight:300" dominant-baseline="middle">.gitignore</text></g><g transform="translate(0, 60)"><circle r="5" fill="#ece2a9"></circle><text x="10" style="font-size:14px;font-weight:300" dominant-baseline="middle">.haml</text></g><g transform="translate(0, 75)"><circle r="5" fill="#f1e05a"></circle><text x="10" style="font-size:14px;font-weight:300" dominant-baseline="middle">.js</text></g><g transform="translate(0, 90)"><circle r="5" fill="#000080"></circle><text x="10" style="font-size:14px;font-weight:300" dominant-baseline="middle">.lua</text></g><g transform="translate(0, 105)"><circle r="5" fill="#083fa1"></circle><text x="10" style="font-size:14px;font-weight:300" dominant-baseline="middle">.md</text></g><g transform="translate(0, 120)"><circle r="5" fill="#701516"></circle><text x="10" style="font-size:14px;font-weight:300" dominant-baseline="middle">.rake</text></g><g transform="translate(0, 135)"><circle r="5" fill="#701516"></circle><text x="10" style="font-size:14px;font-weight:300" dominant-baseline="middle">.rb</text></g><g transform="translate(0, 150)"><circle r="5" fill="#701516"></circle><text x="10" style="font-size:14px;font-weight:300" dominant-baseline="middle">.ru</text></g><g transform="translate(0, 165)"><circle r="5" fill="#89e051"></circle><text x="10" style="font-size:14px;font-weight:300" dominant-baseline="middle">.sh</text></g><g transform="translate(0, 180)"><circle r="5" fill="#2b2b2b"></circle><text x="10" style="font-size:14px;font-weight:300" dominant-baseline="middle">.slim</text></g><g transform="translate(0, 195)"><circle r="5" fill="#ff9900"></circle><text x="10" style="font-size:14px;font-weight:300" dominant-baseline="middle">.svg</text></g><g transform="translate(0, 210)"><circle r="5" fill="#199f4b"></circle><text x="10" style="font-size:14px;font-weight:300" dominant-baseline="middle">.txt</text></g><g transform="translate(0, 225)"><circle r="5" fill="#cb171e"></circle><text x="10" style="font-size:14px;font-weight:300" dominant-baseline="middle">.yml</text></g><g fill="#9CA3AF" style="font-weight:300;font-style:italic;font-size:12px">each dot sized by file size</g></g></svg>
|
@@ -52,8 +52,9 @@ module Coverband
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def get_coverage_report
|
55
|
-
|
56
|
-
data
|
55
|
+
coverage_cache = {}
|
56
|
+
data = Coverband.configuration.store.split_coverage(Coverband::TYPES, coverage_cache)
|
57
|
+
data.merge(Coverband::MERGED_TYPE => Coverband.configuration.store.merged_coverage(Coverband::TYPES, coverage_cache))
|
57
58
|
end
|
58
59
|
|
59
60
|
def covered_files
|
@@ -66,12 +67,12 @@ module Coverband
|
|
66
67
|
|
67
68
|
protected
|
68
69
|
|
69
|
-
def split_coverage(types)
|
70
|
+
def split_coverage(types, coverage_cache)
|
70
71
|
types.reduce({}) do |data, type|
|
71
72
|
if type == Coverband::RUNTIME_TYPE && Coverband.configuration.simulate_oneshot_lines_coverage
|
72
|
-
data.update(type => simulated_runtime_coverage)
|
73
|
+
data.update(type => coverage_cache[type] ||= simulated_runtime_coverage)
|
73
74
|
else
|
74
|
-
data.update(type => coverage(type))
|
75
|
+
data.update(type => coverage_cache[type] ||= coverage(type))
|
75
76
|
end
|
76
77
|
end
|
77
78
|
end
|
@@ -85,9 +86,9 @@ module Coverband
|
|
85
86
|
merge_reports(runtime_data, eager_data, skip_expansion: true)
|
86
87
|
end
|
87
88
|
|
88
|
-
def merged_coverage(types)
|
89
|
+
def merged_coverage(types, coverage_cache)
|
89
90
|
types.reduce({}) do |data, type|
|
90
|
-
merge_reports(data, coverage(type), skip_expansion: true)
|
91
|
+
merge_reports(data, coverage_cache[type] ||= coverage(type), skip_expansion: true)
|
91
92
|
end
|
92
93
|
end
|
93
94
|
|
@@ -14,7 +14,7 @@ module Coverband
|
|
14
14
|
#
|
15
15
|
# View Reports:
|
16
16
|
# Using this assumes you are syncing the coverage files
|
17
|
-
# to some shared storage that is
|
17
|
+
# to some shared storage that is accessible outside of the production server
|
18
18
|
# download files to a system where you want to view the reports..
|
19
19
|
# When viewing coverage from the filestore adapter it merges all coverage
|
20
20
|
# files matching the path pattern, in this case `log/coverage.log.*`
|
@@ -9,7 +9,7 @@ module Coverband
|
|
9
9
|
FILE_LENGTH_KEY = "file_length"
|
10
10
|
META_DATA_KEYS = [DATA_KEY, FIRST_UPDATED_KEY, LAST_UPDATED_KEY, FILE_HASH].freeze
|
11
11
|
###
|
12
|
-
# This key isn't related to the coverband version, but to the
|
12
|
+
# This key isn't related to the coverband version, but to the internal format
|
13
13
|
# used to store data to redis. It is changed only when breaking changes to our
|
14
14
|
# redis format are required.
|
15
15
|
###
|
@@ -4,7 +4,7 @@ module Coverband
|
|
4
4
|
module Adapters
|
5
5
|
###
|
6
6
|
# NullStore is for benchmarking the impacts of calculating
|
7
|
-
# and storing coverage data
|
7
|
+
# and storing coverage data independent of Coverband/Coverage
|
8
8
|
#
|
9
9
|
# Usage:
|
10
10
|
# config.store = Coverband::Adapters::NullStore.new
|
@@ -7,7 +7,7 @@ module Coverband
|
|
7
7
|
###
|
8
8
|
class RedisStore < Base
|
9
9
|
###
|
10
|
-
# This key isn't related to the coverband version, but to the
|
10
|
+
# This key isn't related to the coverband version, but to the internal format
|
11
11
|
# used to store data to redis. It is changed only when breaking changes to our
|
12
12
|
# redis format are required.
|
13
13
|
###
|
@@ -46,12 +46,30 @@ module Coverband
|
|
46
46
|
@store.type = old_coverage_type
|
47
47
|
end
|
48
48
|
|
49
|
+
def toggle_eager_loading
|
50
|
+
old_coverage_type = @store.type
|
51
|
+
eager_loading!
|
52
|
+
yield
|
53
|
+
ensure
|
54
|
+
@store.type = old_coverage_type
|
55
|
+
end
|
56
|
+
|
49
57
|
def report_coverage
|
50
58
|
@semaphore.synchronize do
|
51
59
|
raise "no Coverband store set" unless @store
|
52
60
|
|
53
61
|
files_with_line_usage = filtered_files(Delta.results)
|
54
|
-
@store.
|
62
|
+
if @store.type == Coverband::EAGER_TYPE && Coverband.configuration.defer_eager_loading_data?
|
63
|
+
@deferred_eager_loading_data = files_with_line_usage
|
64
|
+
else
|
65
|
+
if @deferred_eager_loading_data && Coverband.configuration.defer_eager_loading_data?
|
66
|
+
toggle_eager_loading do
|
67
|
+
@store.save_report(@deferred_eager_loading_data)
|
68
|
+
@deferred_eager_loading_data = nil
|
69
|
+
end
|
70
|
+
end
|
71
|
+
@store.save_report(files_with_line_usage)
|
72
|
+
end
|
55
73
|
end
|
56
74
|
rescue => e
|
57
75
|
@logger&.error "coverage failed to store"
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "set"
|
3
4
|
require "singleton"
|
4
5
|
|
5
6
|
module Coverband
|
@@ -12,7 +13,7 @@ module Coverband
|
|
12
13
|
# https://github.com/livingsocial/flatfoot
|
13
14
|
###
|
14
15
|
class ViewTracker
|
15
|
-
attr_accessor :target
|
16
|
+
attr_accessor :target
|
16
17
|
attr_reader :logger, :roots, :store, :ignore_patterns
|
17
18
|
|
18
19
|
def initialize(options = {})
|
@@ -29,8 +30,16 @@ module Coverband
|
|
29
30
|
@roots = @roots.split(",") if @roots.is_a?(String)
|
30
31
|
@one_time_timestamp = false
|
31
32
|
|
32
|
-
@logged_views =
|
33
|
-
@views_to_record =
|
33
|
+
@logged_views = Set.new
|
34
|
+
@views_to_record = Set.new
|
35
|
+
end
|
36
|
+
|
37
|
+
def logged_views
|
38
|
+
@logged_views.to_a
|
39
|
+
end
|
40
|
+
|
41
|
+
def views_to_record
|
42
|
+
@views_to_record.to_a
|
34
43
|
end
|
35
44
|
|
36
45
|
###
|
@@ -40,8 +49,8 @@ module Coverband
|
|
40
49
|
def track_views(_name, _start, _finish, _id, payload)
|
41
50
|
if (file = payload[:identifier])
|
42
51
|
if newly_seen_file?(file)
|
43
|
-
logged_views << file
|
44
|
-
views_to_record << file if track_file?(file)
|
52
|
+
@logged_views << file
|
53
|
+
@views_to_record << file if track_file?(file)
|
45
54
|
end
|
46
55
|
end
|
47
56
|
|
@@ -54,8 +63,8 @@ module Coverband
|
|
54
63
|
return unless (layout_file = payload[:layout])
|
55
64
|
return unless newly_seen_file?(layout_file)
|
56
65
|
|
57
|
-
logged_views << layout_file
|
58
|
-
views_to_record << layout_file if track_file?(layout_file, layout: true)
|
66
|
+
@logged_views << layout_file
|
67
|
+
@views_to_record << layout_file if track_file?(layout_file, layout: true)
|
59
68
|
end
|
60
69
|
|
61
70
|
def used_views
|
@@ -81,16 +90,17 @@ module Coverband
|
|
81
90
|
all_views.uniq
|
82
91
|
end
|
83
92
|
|
84
|
-
def unused_views
|
85
|
-
recently_used_views = used_views.keys
|
86
|
-
unused_views = all_views
|
93
|
+
def unused_views(used_views = nil)
|
94
|
+
recently_used_views = (used_views || self.used_views).keys
|
95
|
+
unused_views = all_views - recently_used_views
|
87
96
|
# since layouts don't include format we count them used if they match with ANY formats
|
88
97
|
unused_views.reject { |view| view.match(/\/layouts\//) && recently_used_views.any? { |used_view| view.include?(used_view) } }
|
89
98
|
end
|
90
99
|
|
91
100
|
def as_json
|
101
|
+
used_views = self.used_views
|
92
102
|
{
|
93
|
-
unused_views: unused_views,
|
103
|
+
unused_views: unused_views(used_views),
|
94
104
|
used_views: used_views
|
95
105
|
}.to_json
|
96
106
|
end
|
@@ -113,17 +123,17 @@ module Coverband
|
|
113
123
|
|
114
124
|
filename = "#{@project_directory}/#{filename}"
|
115
125
|
redis_store.hdel(tracker_key, filename)
|
116
|
-
logged_views.delete(filename)
|
126
|
+
@logged_views.delete(filename)
|
117
127
|
end
|
118
128
|
|
119
129
|
def report_views_tracked
|
120
130
|
redis_store.set(tracker_time_key, Time.now.to_i) unless @one_time_timestamp || tracker_time_key_exists?
|
121
131
|
@one_time_timestamp = true
|
122
132
|
reported_time = Time.now.to_i
|
123
|
-
views_to_record.each do |file|
|
133
|
+
@views_to_record.each do |file|
|
124
134
|
redis_store.hset(tracker_key, file, reported_time)
|
125
135
|
end
|
126
|
-
|
136
|
+
@views_to_record.clear
|
127
137
|
rescue => e
|
128
138
|
# we don't want to raise errors if Coverband can't reach redis.
|
129
139
|
# This is a nice to have not a bring the system down
|
@@ -137,15 +147,12 @@ module Coverband
|
|
137
147
|
protected
|
138
148
|
|
139
149
|
def newly_seen_file?(file)
|
140
|
-
|
141
|
-
|
142
|
-
true
|
150
|
+
!@logged_views.include?(file)
|
143
151
|
end
|
144
152
|
|
145
153
|
def track_file?(file, options = {})
|
146
|
-
|
147
|
-
file.include?(pattern)
|
148
|
-
end && (file.start_with?(@project_directory) || options[:layout])
|
154
|
+
(file.start_with?(@project_directory) || options[:layout]) &&
|
155
|
+
@ignore_patterns.none? { |pattern| file.include?(pattern) }
|
149
156
|
end
|
150
157
|
|
151
158
|
private
|
@@ -8,8 +8,8 @@ module Coverband
|
|
8
8
|
class ViewTrackerService < ViewTracker
|
9
9
|
def report_views_tracked
|
10
10
|
reported_time = Time.now.to_i
|
11
|
-
if views_to_record.any?
|
12
|
-
relative_views = views_to_record.map! do |view|
|
11
|
+
if @views_to_record.any?
|
12
|
+
relative_views = @views_to_record.map! do |view|
|
13
13
|
roots.each do |root|
|
14
14
|
view = view.gsub(/#{root}/, "")
|
15
15
|
end
|
@@ -17,7 +17,7 @@ module Coverband
|
|
17
17
|
end
|
18
18
|
save_tracked_views(views: relative_views, reported_time: reported_time)
|
19
19
|
end
|
20
|
-
|
20
|
+
@views_to_record = []
|
21
21
|
rescue => e
|
22
22
|
# we don't want to raise errors if Coverband can't reach the service
|
23
23
|
logger&.error "Coverband: view_tracker failed to store, error #{e.class.name}" if Coverband.configuration.verbose || Coverband.configuration.service_dev_mode
|
@@ -8,7 +8,7 @@ module Coverband
|
|
8
8
|
:background_reporting_enabled,
|
9
9
|
:test_env, :web_enable_clear, :gem_details, :web_debug, :report_on_exit,
|
10
10
|
:simulate_oneshot_lines_coverage,
|
11
|
-
:view_tracker
|
11
|
+
:view_tracker, :defer_eager_loading_data
|
12
12
|
attr_writer :logger, :s3_region, :s3_bucket, :s3_access_key_id,
|
13
13
|
:s3_secret_access_key, :password, :api_key, :service_url, :coverband_timeout, :service_dev_mode,
|
14
14
|
:service_test_mode, :process_type, :track_views, :redis_url,
|
@@ -62,6 +62,7 @@ module Coverband
|
|
62
62
|
@store = nil
|
63
63
|
@background_reporting_enabled = true
|
64
64
|
@background_reporting_sleep_seconds = nil
|
65
|
+
@defer_eager_loading_data = false
|
65
66
|
@test_env = nil
|
66
67
|
@web_enable_clear = false
|
67
68
|
@track_views = true
|
@@ -147,7 +148,9 @@ module Coverband
|
|
147
148
|
end
|
148
149
|
|
149
150
|
def track_views
|
150
|
-
|
151
|
+
return false if service_disabled_dev_test_env?
|
152
|
+
|
153
|
+
@track_views
|
151
154
|
end
|
152
155
|
|
153
156
|
###
|
@@ -241,6 +244,10 @@ module Coverband
|
|
241
244
|
Coverband.coverband_service? || !api_key.nil?
|
242
245
|
end
|
243
246
|
|
247
|
+
def defer_eager_loading_data?
|
248
|
+
@defer_eager_loading_data
|
249
|
+
end
|
250
|
+
|
244
251
|
def service_disabled_dev_test_env?
|
245
252
|
(coverband_env == "test" && !Coverband.configuration.service_test_mode) ||
|
246
253
|
(coverband_env == "development" && !Coverband.configuration.service_dev_mode)
|
@@ -31,15 +31,18 @@ module Coverband
|
|
31
31
|
sleep_seconds = Coverband.configuration.background_reporting_sleep_seconds.to_i
|
32
32
|
@thread = Thread.new {
|
33
33
|
loop do
|
34
|
-
Coverband.report_coverage
|
35
|
-
Coverband.configuration.view_tracker&.report_views_tracked
|
36
34
|
if Coverband.configuration.reporting_wiggle
|
37
35
|
sleep_seconds = Coverband.configuration.background_reporting_sleep_seconds.to_i + rand(Coverband.configuration.reporting_wiggle.to_i)
|
38
36
|
end
|
37
|
+
# NOTE: Normally as processes first start we immediately report, this causes a redis spike on deploys
|
38
|
+
# if deferred is set also sleep frst to spread load
|
39
|
+
sleep(sleep_seconds.to_i) if Coverband.configuration.defer_eager_loading_data?
|
40
|
+
Coverband.report_coverage
|
41
|
+
Coverband.configuration.view_tracker&.report_views_tracked
|
39
42
|
if Coverband.configuration.verbose
|
40
43
|
logger.debug("Coverband: background reporting coverage (#{Coverband.configuration.store.type}). Sleeping #{sleep_seconds}s")
|
41
44
|
end
|
42
|
-
sleep(sleep_seconds.to_i)
|
45
|
+
sleep(sleep_seconds.to_i) unless Coverband.configuration.defer_eager_loading_data?
|
43
46
|
end
|
44
47
|
}
|
45
48
|
end
|
@@ -15,7 +15,7 @@ module Coverband
|
|
15
15
|
scov_style_report = get_current_scov_data_imp(store, all_roots)
|
16
16
|
|
17
17
|
# These are extremelhy verbose but useful during coverband development, not generally for users
|
18
|
-
# Only
|
18
|
+
# Only available by uncommenting this mode is never released
|
19
19
|
# if Coverband.configuration.verbose
|
20
20
|
# # msg = "report:\n #{scov_style_report.inspect}"
|
21
21
|
# # Coverband.configuration.logger.debug msg
|
@@ -124,7 +124,7 @@ module Coverband
|
|
124
124
|
Coverband.configuration.store.clear!
|
125
125
|
notice = "coverband coverage cleared"
|
126
126
|
else
|
127
|
-
notice = "web_enable_clear
|
127
|
+
notice = "web_enable_clear isn't enabled in your configuration"
|
128
128
|
end
|
129
129
|
[301, {"Location" => "#{base_path}?notice=#{notice}"}, []]
|
130
130
|
end
|
@@ -135,7 +135,7 @@ module Coverband
|
|
135
135
|
Coverband.configuration.store.clear_file!(filename)
|
136
136
|
notice = "coverage for file #{filename} cleared"
|
137
137
|
else
|
138
|
-
notice = "web_enable_clear
|
138
|
+
notice = "web_enable_clear isn't enabled in your configuration"
|
139
139
|
end
|
140
140
|
[301, {"Location" => "#{base_path}?notice=#{notice}"}, []]
|
141
141
|
end
|
@@ -146,7 +146,7 @@ module Coverband
|
|
146
146
|
tracker.reset_recordings
|
147
147
|
notice = "view tracking reset"
|
148
148
|
else
|
149
|
-
notice = "web_enable_clear
|
149
|
+
notice = "web_enable_clear isn't enabled in your configuration"
|
150
150
|
end
|
151
151
|
[301, {"Location" => "#{base_path}/view_tracker?notice=#{notice}"}, []]
|
152
152
|
end
|
@@ -158,7 +158,7 @@ module Coverband
|
|
158
158
|
tracker.clear_file!(filename)
|
159
159
|
notice = "coverage for file #{filename} cleared"
|
160
160
|
else
|
161
|
-
notice = "web_enable_clear
|
161
|
+
notice = "web_enable_clear isn't enabled in your configuration"
|
162
162
|
end
|
163
163
|
[301, {"Location" => "#{base_path}/view_tracker?notice=#{notice}"}, []]
|
164
164
|
end
|
@@ -37,7 +37,7 @@ module Coverband
|
|
37
37
|
|
38
38
|
Coverband.configuration.view_tracker = COVERBAND_VIEW_TRACKER
|
39
39
|
|
40
|
-
ActiveSupport::Notifications.subscribe(/
|
40
|
+
ActiveSupport::Notifications.subscribe(/render_(template|partial|collection).action_view/) do |name, start, finish, id, payload|
|
41
41
|
COVERBAND_VIEW_TRACKER.track_views(name, start, finish, id, payload) unless name.include?("!")
|
42
42
|
end
|
43
43
|
end
|
@@ -101,7 +101,7 @@ module Coverband
|
|
101
101
|
@last_updated_at = Time.at(file_data["last_updated_at"]) if file_data["last_updated_at"]
|
102
102
|
@never_loaded = file_data["never_loaded"] || false
|
103
103
|
else
|
104
|
-
# TODO: Deprecate this code path this was backwards
|
104
|
+
# TODO: Deprecate this code path this was backwards compatibility from 3-4
|
105
105
|
@coverage = file_data
|
106
106
|
@first_updated_at = NOT_AVAILABLE
|
107
107
|
@last_updated_at = NOT_AVAILABLE
|
@@ -139,7 +139,7 @@ module Coverband
|
|
139
139
|
coverage_exceeding_source_warn if coverage.size > src.size
|
140
140
|
|
141
141
|
lines = src.map.with_index(1) { |src, i|
|
142
|
-
Coverband::Utils::SourceFile::Line.new(src, i, coverage[i - 1])
|
142
|
+
Coverband::Utils::SourceFile::Line.new(src, i, never_loaded ? 0 : coverage[i - 1])
|
143
143
|
}
|
144
144
|
|
145
145
|
process_skipped_lines(lines)
|
data/lib/coverband/version.rb
CHANGED
data/public/dependencies.js
CHANGED
@@ -103,7 +103,7 @@ var hljs=new function(){function l(o){return o.replace(/&/gm,"&").replace(/<
|
|
103
103
|
return this.rel;
|
104
104
|
},
|
105
105
|
href: function() {
|
106
|
-
// using this.href would give the absolute url, when the href may have been
|
106
|
+
// using this.href would give the absolute url, when the href may have been intedned as a selector (e.g. '#container')
|
107
107
|
return $(this).attr('href');
|
108
108
|
},
|
109
109
|
title: function() {
|
@@ -397,7 +397,7 @@ var hljs=new function(){function l(o){return o.replace(/&/gm,"&").replace(/<
|
|
397
397
|
loadedHeight = $loaded.outerHeight(true);
|
398
398
|
loadedWidth = $loaded.outerWidth(true);
|
399
399
|
|
400
|
-
// Opens
|
400
|
+
// Opens initial empty Colorbox prior to content being loaded.
|
401
401
|
var initialWidth = setSize(settings.get('initialWidth'), 'x');
|
402
402
|
var initialHeight = setSize(settings.get('initialHeight'), 'y');
|
403
403
|
var maxWidth = settings.get('maxWidth');
|
@@ -983,7 +983,7 @@ var hljs=new function(){function l(o){return o.replace(/&/gm,"&").replace(/<
|
|
983
983
|
return;
|
984
984
|
}
|
985
985
|
|
986
|
-
// A small pause because some browsers will
|
986
|
+
// A small pause because some browsers will occasionally report a
|
987
987
|
// img.width and img.height of zero immediately after the img.onload fires
|
988
988
|
setTimeout(function(){
|
989
989
|
var percent;
|
@@ -1236,7 +1236,7 @@ u;this.oApi._fnAddColumn=y;this.oApi._fnColumnOptions=C;this.oApi._fnAddData=w;t
|
|
1236
1236
|
Q;this.oApi._fnFilterCreateSearch=fa;this.oApi._fnDataToSearch=ga;this.oApi._fnSort=O;this.oApi._fnSortAttachListener=$;this.oApi._fnSortingClasses=W;this.oApi._fnFeatureHtmlPaginate=wa;this.oApi._fnPageChange=Ba;this.oApi._fnFeatureHtmlInfo=va;this.oApi._fnUpdateInfo=Ca;this.oApi._fnFeatureHtmlLength=ra;this.oApi._fnFeatureHtmlProcessing=ta;this.oApi._fnProcessingDisplay=K;this.oApi._fnVisibleToColumnIndex=da;this.oApi._fnColumnIndexToVisible=N;this.oApi._fnNodeToDataIndex=R;this.oApi._fnVisbleColumns=
|
1237
1237
|
T;this.oApi._fnCalculateEnd=F;this.oApi._fnConvertToWidth=Da;this.oApi._fnCalculateColumnWidths=ea;this.oApi._fnScrollingWidthAdjust=ia;this.oApi._fnGetWidestNode=Ea;this.oApi._fnGetMaxLenString=Fa;this.oApi._fnStringToCss=v;this.oApi._fnArrayCmp=La;this.oApi._fnDetectType=Z;this.oApi._fnSettingsFromNode=B;this.oApi._fnGetDataMaster=V;this.oApi._fnGetTrNodes=S;this.oApi._fnGetTdNodes=X;this.oApi._fnEscapeRegex=ha;this.oApi._fnDeleteIndex=ja;this.oApi._fnReOrderIndex=qa;this.oApi._fnColumnOrdering=
|
1238
1238
|
aa;this.oApi._fnLog=J;this.oApi._fnClearTable=ba;this.oApi._fnSaveState=Ga;this.oApi._fnLoadState=Ia;this.oApi._fnCreateCookie=Ha;this.oApi._fnReadCookie=ka;this.oApi._fnGetUniqueThs=ca;this.oApi._fnScrollBarWidth=Ja;this.oApi._fnApplyToChildren=M;this.oApi._fnMap=n;var Ka=this;return this.each(function(){var a=0,b,c,d,f;a=0;for(b=E.length;a<b;a++){if(E[a].nTable==this)if(typeof g=="undefined"||typeof g.bRetrieve!="undefined"&&g.bRetrieve===true)return E[a].oInstance;else if(typeof g.bDestroy!="undefined"&&
|
1239
|
-
g.bDestroy===true){E[a].oInstance.fnDestroy();break}else{J(E[a],0,"Cannot reinitialise DataTable.\n\nTo retrieve the DataTables object for this table, please pass either no arguments to the dataTable() function, or set bRetrieve to true. Alternatively, to
|
1239
|
+
g.bDestroy===true){E[a].oInstance.fnDestroy();break}else{J(E[a],0,"Cannot reinitialise DataTable.\n\nTo retrieve the DataTables object for this table, please pass either no arguments to the dataTable() function, or set bRetrieve to true. Alternatively, to destroy the old table and create a new one, set bDestroy to true (note that a lot of changes to the configuration can be made through the API which is usually much faster).");return}if(E[a].sTableId!==""&&E[a].sTableId==this.getAttribute("id")){E.splice(a,
|
1240
1240
|
1);break}}var e=new l;E.push(e);var i=false,h=false;a=this.getAttribute("id");if(a!==null){e.sTableId=a;e.sInstance=a}else e.sInstance=m._oExternConfig.iNextUnique++;e.oInstance=Ka;e.nTable=this;e.oApi=Ka.oApi;if(typeof g!="undefined"&&g!==null){e.oInit=g;n(e.oFeatures,g,"bPaginate");n(e.oFeatures,g,"bLengthChange");n(e.oFeatures,g,"bFilter");n(e.oFeatures,g,"bSort");n(e.oFeatures,g,"bInfo");n(e.oFeatures,g,"bProcessing");n(e.oFeatures,g,"bAutoWidth");n(e.oFeatures,g,"bSortClasses");n(e.oFeatures,
|
1241
1241
|
g,"bServerSide");n(e.oScroll,g,"sScrollX","sX");n(e.oScroll,g,"sScrollXInner","sXInner");n(e.oScroll,g,"sScrollY","sY");n(e.oScroll,g,"bScrollCollapse","bCollapse");n(e,g,"asStripClasses");n(e,g,"fnRowCallback");n(e,g,"fnHeaderCallback");n(e,g,"fnFooterCallback");n(e,g,"fnInitComplete");n(e,g,"fnServerData");n(e,g,"fnFormatNumber");n(e,g,"aaSorting");n(e,g,"aaSortingFixed");n(e,g,"aLengthMenu");n(e,g,"sPaginationType");n(e,g,"sAjaxSource");n(e,g,"iCookieDuration");n(e,g,"sCookiePrefix");n(e,g,"sDom");
|
1242
1242
|
n(e,g,"oSearch","oPreviousSearch");n(e,g,"aoSearchCols","aoPreSearchCols");n(e,g,"iDisplayLength","_iDisplayLength");n(e,g,"bJQueryUI","bJUI");typeof g.fnDrawCallback=="function"&&e.aoDrawCallback.push({fn:g.fnDrawCallback,sName:"user"});e.oFeatures.bServerSide&&e.oFeatures.bSort&&e.oFeatures.bSortClasses&&e.aoDrawCallback.push({fn:W,sName:"server_side_sort_classes"});if(typeof g.bJQueryUI!="undefined"&&g.bJQueryUI){e.oClasses=m.oJUIClasses;if(typeof g.sDom=="undefined")e.sDom='<"H"lfr>t<"F"ip>'}if(e.oScroll.sX!==
|
@@ -10,7 +10,7 @@ class BaseTest < Minitest::Test
|
|
10
10
|
Coverband.configure do |config|
|
11
11
|
config.root = Dir.pwd
|
12
12
|
config.root_paths = ["/app_path/"]
|
13
|
-
config.ignore = ["config/
|
13
|
+
config.ignore = ["config/environments"]
|
14
14
|
config.reporter = "std_out"
|
15
15
|
config.store = Coverband::Adapters::RedisStore.new(Coverband::Test.redis, redis_namespace: "coverband_test")
|
16
16
|
end
|
@@ -18,7 +18,7 @@ class BaseTest < Minitest::Test
|
|
18
18
|
|
19
19
|
test "ignore works with equal" do
|
20
20
|
Coverband::Collectors::Coverage.instance.reset_instance
|
21
|
-
expected = ["vendor/", ".erb$", ".slim$", "/tmp", "internal:prelude", "db/schema.rb", "config/
|
21
|
+
expected = ["vendor/", ".erb$", ".slim$", "/tmp", "internal:prelude", "db/schema.rb", "config/environments"]
|
22
22
|
assert_equal expected, Coverband.configuration.ignore
|
23
23
|
end
|
24
24
|
|
@@ -33,7 +33,7 @@ class BaseTest < Minitest::Test
|
|
33
33
|
"/tmp",
|
34
34
|
"internal:prelude",
|
35
35
|
"db/schema.rb",
|
36
|
-
"config/
|
36
|
+
"config/environments",
|
37
37
|
"config/initializers"]
|
38
38
|
assert_equal expected, Coverband.configuration.ignore
|
39
39
|
end
|
@@ -47,7 +47,7 @@ class BaseTest < Minitest::Test
|
|
47
47
|
Coverband::Collectors::Coverage.instance.reset_instance
|
48
48
|
current_paths = Coverband.configuration.root_paths.dup
|
49
49
|
# verify previous bug fix
|
50
|
-
# it would extend the root_paths instance variable on each
|
50
|
+
# it would extend the root_paths instance variable on each invocation
|
51
51
|
Coverband.configuration.all_root_paths
|
52
52
|
Coverband.configuration.all_root_paths
|
53
53
|
assert_equal current_paths, Coverband.configuration.root_paths
|
@@ -103,7 +103,7 @@ class BaseTest < Minitest::Test
|
|
103
103
|
end
|
104
104
|
end
|
105
105
|
|
106
|
-
test "store
|
106
|
+
test "store doesn't raises when api key and redis_url" do
|
107
107
|
Coverband::Collectors::Coverage.instance.reset_instance
|
108
108
|
Coverband.configuration.reset
|
109
109
|
Coverband.configure do |config|
|
@@ -58,7 +58,7 @@ class RailsFullStackTest < Minitest::Test
|
|
58
58
|
|
59
59
|
# we don't want this to run during our standard test suite
|
60
60
|
# as the below profiler changes the runtime
|
61
|
-
# and
|
61
|
+
# and should only be included for isolated processes
|
62
62
|
begin
|
63
63
|
require "memory_profiler"
|
64
64
|
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require File.expand_path("../test_helper", File.dirname(__FILE__))
|
4
|
+
require "rack"
|
5
|
+
|
6
|
+
class FullStackDeferredEagerTest < Minitest::Test
|
7
|
+
REDIS_STORAGE_FORMAT_VERSION = Coverband::Adapters::RedisStore::REDIS_STORAGE_FORMAT_VERSION
|
8
|
+
TEST_RACK_APP = "../fake_app/basic_rack.rb"
|
9
|
+
|
10
|
+
def setup
|
11
|
+
super
|
12
|
+
Coverband::Collectors::Coverage.instance.reset_instance
|
13
|
+
Coverband.configure do |config|
|
14
|
+
config.background_reporting_enabled = false
|
15
|
+
config.track_gems = true
|
16
|
+
config.defer_eager_loading_data = true
|
17
|
+
end
|
18
|
+
Coverband.start
|
19
|
+
Coverband::Collectors::Coverage.instance.eager_loading!
|
20
|
+
@rack_file = require_unique_file "fake_app/basic_rack.rb"
|
21
|
+
Coverband.report_coverage
|
22
|
+
Coverband::Collectors::Coverage.instance.runtime!
|
23
|
+
end
|
24
|
+
|
25
|
+
test "call app" do
|
26
|
+
# eager loaded class coverage starts empty
|
27
|
+
Coverband.eager_loading_coverage!
|
28
|
+
expected = {}
|
29
|
+
assert_equal expected, Coverband.configuration.store.coverage
|
30
|
+
|
31
|
+
Coverband::Collectors::Coverage.instance.runtime!
|
32
|
+
request = Rack::MockRequest.env_for("/anything.json")
|
33
|
+
middleware = Coverband::BackgroundMiddleware.new(fake_app_with_lines)
|
34
|
+
results = middleware.call(request)
|
35
|
+
assert_equal "Hello Rack!", results.last
|
36
|
+
Coverband.report_coverage
|
37
|
+
expected = [nil, nil, 0, nil, 0, 0, 1, nil, nil]
|
38
|
+
assert_equal expected, Coverband.configuration.store.coverage[@rack_file]["data"]
|
39
|
+
|
40
|
+
# eager loaded class coverage is saved at first normal coverage report
|
41
|
+
Coverband.eager_loading_coverage!
|
42
|
+
expected = [nil, nil, 1, nil, 1, 1, 0, nil, nil]
|
43
|
+
assert_equal expected, Coverband.configuration.store.coverage[@rack_file]["data"]
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def fake_app_with_lines
|
49
|
+
@fake_app_with_lines ||= ::HelloWorld.new
|
50
|
+
end
|
51
|
+
end
|
data/views/file_list.erb
CHANGED
@@ -22,8 +22,8 @@
|
|
22
22
|
<thead>
|
23
23
|
<tr>
|
24
24
|
<th title="The source file name">File</th>
|
25
|
-
<th title="Percentage of
|
26
|
-
<th title="Runtime Percentage of
|
25
|
+
<th title="Percentage of relevant lines covered (load & runtime)">% covered</th>
|
26
|
+
<th title="Runtime Percentage of relevant lines covered">% runtime</th>
|
27
27
|
<th title="The total line number count for the file">Lines</th>
|
28
28
|
<th title="Line number count excluding comments, whitespace, etc...">Relevant Lines</th>
|
29
29
|
<th title="The number of lines covered (load & runtime)">Lines covered</th>
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: coverband
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.2.0.rc.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dan Mayer
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2022-01-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: benchmark-ips
|
@@ -272,6 +272,7 @@ extra_rdoc_files: []
|
|
272
272
|
files:
|
273
273
|
- ".github/ISSUE_TEMPLATE/bug_report.md"
|
274
274
|
- ".github/ISSUE_TEMPLATE/feature_request.md"
|
275
|
+
- ".github/workflows/diagram.yml"
|
275
276
|
- ".github/workflows/main.yml"
|
276
277
|
- ".gitignore"
|
277
278
|
- ".jrubyrc"
|
@@ -288,6 +289,7 @@ files:
|
|
288
289
|
- changes.md
|
289
290
|
- config.ru
|
290
291
|
- coverband.gemspec
|
292
|
+
- diagram.svg
|
291
293
|
- lib/alternative_coverband_patch.rb
|
292
294
|
- lib/coverband.rb
|
293
295
|
- lib/coverband/adapters/base.rb
|
@@ -416,6 +418,7 @@ files:
|
|
416
418
|
- test/forked/rails_full_stack_views_test.rb
|
417
419
|
- test/forked/rails_rake_full_stack_test.rb
|
418
420
|
- test/forked/rails_view_tracker_stack_test.rb
|
421
|
+
- test/integration/full_stack_deferred_eager_test.rb
|
419
422
|
- test/integration/full_stack_test.rb
|
420
423
|
- test/jruby_check.rb
|
421
424
|
- test/rails4_dummy/Rakefile
|
@@ -475,7 +478,12 @@ files:
|
|
475
478
|
homepage: https://github.com/danmayer/coverband
|
476
479
|
licenses:
|
477
480
|
- MIT
|
478
|
-
metadata:
|
481
|
+
metadata:
|
482
|
+
homepage_uri: https://github.com/danmayer/coverband
|
483
|
+
bug_tracker_uri: https://github.com/danmayer/coverband/issues
|
484
|
+
documentation_uri: https://github.com/danmayer/coverband
|
485
|
+
changelog_uri: https://github.com/danmayer/coverband/blob/main/changes.md
|
486
|
+
source_code_uri: https://github.com/danmayer/coverband
|
479
487
|
post_install_message:
|
480
488
|
rdoc_options: []
|
481
489
|
require_paths:
|
@@ -487,11 +495,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
487
495
|
version: '2.3'
|
488
496
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
489
497
|
requirements:
|
490
|
-
- - "
|
498
|
+
- - ">"
|
491
499
|
- !ruby/object:Gem::Version
|
492
|
-
version:
|
500
|
+
version: 1.3.1
|
493
501
|
requirements: []
|
494
|
-
rubygems_version: 3.
|
502
|
+
rubygems_version: 3.0.3
|
495
503
|
signing_key:
|
496
504
|
specification_version: 4
|
497
505
|
summary: Rack middleware to measure production code usage (LOC runtime usage)
|
@@ -552,6 +560,7 @@ test_files:
|
|
552
560
|
- test/forked/rails_full_stack_views_test.rb
|
553
561
|
- test/forked/rails_rake_full_stack_test.rb
|
554
562
|
- test/forked/rails_view_tracker_stack_test.rb
|
563
|
+
- test/integration/full_stack_deferred_eager_test.rb
|
555
564
|
- test/integration/full_stack_test.rb
|
556
565
|
- test/jruby_check.rb
|
557
566
|
- test/rails4_dummy/Rakefile
|