heatmap-builder 0.2.0 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +2 -5
  3. data/CHANGELOG.md +70 -3
  4. data/Gemfile.lock +27 -24
  5. data/README.md +105 -135
  6. data/bin/generate_examples +42 -99
  7. data/examples/calendar_blue_ocean.svg +1 -1
  8. data/examples/calendar_cell_borders.svg +1 -0
  9. data/examples/calendar_default.svg +1 -1
  10. data/examples/calendar_github_style.svg +1 -1
  11. data/examples/calendar_month_spacing_rounded.svg +1 -0
  12. data/examples/calendar_no_borders.svg +1 -0
  13. data/examples/calendar_purple_vibes.svg +1 -1
  14. data/examples/calendar_red_to_green.svg +1 -1
  15. data/examples/calendar_rounded_corners.svg +1 -1
  16. data/examples/calendar_rounded_corners_max_radius.svg +1 -1
  17. data/examples/calendar_sunday_start.svg +1 -1
  18. data/examples/calendar_warm_sunset.svg +1 -1
  19. data/examples/calendar_with_outside_cells.svg +1 -1
  20. data/heatmap-builder.gemspec +4 -4
  21. data/lib/heatmap-builder.rb +5 -31
  22. data/lib/heatmap_builder/calendar.rb +426 -0
  23. data/lib/heatmap_builder/color_helpers.rb +121 -141
  24. data/lib/heatmap_builder/svg_helpers.rb +11 -4
  25. data/lib/heatmap_builder/value_conversion.rb +9 -5
  26. data/lib/heatmap_builder/version.rb +1 -1
  27. metadata +13 -22
  28. data/examples/large_cells.svg +0 -1
  29. data/examples/linear_blue_ocean.svg +0 -1
  30. data/examples/linear_github_green.svg +0 -1
  31. data/examples/linear_neon_gradient.svg +0 -1
  32. data/examples/linear_purple_vibes.svg +0 -1
  33. data/examples/linear_red_to_green.svg +0 -1
  34. data/examples/linear_rounded_corners.svg +0 -1
  35. data/examples/linear_rounded_corners_max_radius.svg +0 -1
  36. data/examples/linear_warm_sunset.svg +0 -1
  37. data/examples/weekly_progress.svg +0 -1
  38. data/lib/heatmap_builder/builder.rb +0 -100
  39. data/lib/heatmap_builder/calendar_heatmap_builder.rb +0 -310
  40. data/lib/heatmap_builder/linear_heatmap_builder.rb +0 -74
@@ -1,170 +1,150 @@
1
1
  module HeatmapBuilder
2
2
  module ColorHelpers
3
- private
3
+ class << self
4
+ def score_to_color(score, colors:)
5
+ return colors.first if score == 0
4
6
 
5
- def score_to_color(score, colors:)
6
- # Generate color palette if colors is a hash
7
- if colors.is_a?(Hash)
8
- colors = generate_color_palette(colors[:from], colors[:to], colors[:steps])
7
+ max_color_index = colors.length - 1
8
+ color_index = 1 + (score - 1) % max_color_index
9
+ colors[color_index]
9
10
  end
10
11
 
11
- return colors.first if score == 0
12
+ def adjust_lightness(hex_color, factor:)
13
+ rgb = hex_to_rgb(hex_color)
14
+ oklch = rgb_to_oklch(*rgb)
12
15
 
13
- max_color_index = colors.length - 1
14
- color_index = 1 + (score - 1) % max_color_index
15
- colors[color_index]
16
- end
16
+ darker_oklch = [oklch[0] * factor, oklch[1], oklch[2]]
17
+ darker_rgb = oklch_to_rgb(*darker_oklch)
17
18
 
18
- def darker_color(hex_color, factor: 0.9)
19
- rgb = hex_to_rgb(hex_color)
20
- oklch = rgb_to_oklch(*rgb)
19
+ rgb_to_hex(*darker_rgb)
20
+ end
21
21
 
22
- # Reduce lightness (L component) by factor
23
- darker_oklch = [oklch[0] * factor, oklch[1], oklch[2]]
24
- darker_rgb = oklch_to_rgb(*darker_oklch)
22
+ def make_color_inactive(hex_color)
23
+ rgb = hex_to_rgb(hex_color)
24
+ oklch = rgb_to_oklch(*rgb)
25
25
 
26
- rgb_to_hex(*darker_rgb)
27
- end
26
+ inactive_oklch = [
27
+ oklch[0] * 0.85, # Slightly reduce lightness
28
+ oklch[1] * 0.4, # Significantly reduce chroma (saturation)
29
+ oklch[2] # Keep hue unchanged
30
+ ]
28
31
 
29
- def make_color_inactive(hex_color)
30
- # Convert to OKLCH for blending
31
- rgb = hex_to_rgb(hex_color)
32
- oklch = rgb_to_oklch(*rgb)
33
-
34
- # Reduce chroma (saturation) to make it more muted
35
- # Also slightly reduce lightness
36
- inactive_oklch = [
37
- oklch[0] * 0.85, # Slightly reduce lightness
38
- oklch[1] * 0.4, # Significantly reduce chroma (saturation)
39
- oklch[2] # Keep hue unchanged
40
- ]
41
-
42
- inactive_rgb = oklch_to_rgb(*inactive_oklch)
43
- rgb_to_hex(*inactive_rgb)
44
- end
32
+ inactive_rgb = oklch_to_rgb(*inactive_oklch)
33
+ rgb_to_hex(*inactive_rgb)
34
+ end
45
35
 
46
- def rgb_to_oklch(r, g, b)
47
- # Convert to linear RGB first
48
- r_linear = srgb_to_linear(r / 255.0)
49
- g_linear = srgb_to_linear(g / 255.0)
50
- b_linear = srgb_to_linear(b / 255.0)
51
-
52
- # Linear RGB to OKLab using the Oklab transformation matrix
53
- l = 0.4122214708 * r_linear + 0.5363325363 * g_linear + 0.0514459929 * b_linear
54
- m = 0.2119034982 * r_linear + 0.6806995451 * g_linear + 0.1073969566 * b_linear
55
- s = 0.0883024619 * r_linear + 0.2817188376 * g_linear + 0.6299787005 * b_linear
56
-
57
- # Apply cube root
58
- l_root = (l >= 0) ? l**(1.0 / 3) : -((-l)**(1.0 / 3))
59
- m_root = (m >= 0) ? m**(1.0 / 3) : -((-m)**(1.0 / 3))
60
- s_root = (s >= 0) ? s**(1.0 / 3) : -((-s)**(1.0 / 3))
61
-
62
- # Convert to OKLab
63
- ok_l = 0.2104542553 * l_root + 0.7936177850 * m_root - 0.0040720468 * s_root
64
- ok_a = 1.9779984951 * l_root - 2.4285922050 * m_root + 0.4505937099 * s_root
65
- ok_b = 0.0259040371 * l_root + 0.7827717662 * m_root - 0.8086757660 * s_root
66
-
67
- # Convert OKLab to OKLCH
68
- chroma = Math.sqrt(ok_a * ok_a + ok_b * ok_b)
69
- hue = Math.atan2(ok_b, ok_a) * 180.0 / Math::PI
70
- hue += 360 if hue < 0
71
-
72
- [ok_l, chroma, hue]
73
- end
36
+ def generate_color_palette(from_color, to_color, steps)
37
+ from_rgb = hex_to_rgb(from_color)
38
+ to_rgb = hex_to_rgb(to_color)
74
39
 
75
- def oklch_to_rgb(ok_l, chroma, hue)
76
- # Convert OKLCH to OKLab
77
- hue_rad = hue * Math::PI / 180.0
78
- ok_a = chroma * Math.cos(hue_rad)
79
- ok_b = chroma * Math.sin(hue_rad)
80
-
81
- # OKLab to linear RGB
82
- l_root = ok_l + 0.3963377774 * ok_a + 0.2158037573 * ok_b
83
- m_root = ok_l - 0.1055613458 * ok_a - 0.0638541728 * ok_b
84
- s_root = ok_l - 0.0894841775 * ok_a - 1.2914855480 * ok_b
85
-
86
- # Cube the values
87
- l = l_root * l_root * l_root
88
- m = m_root * m_root * m_root
89
- s = s_root * s_root * s_root
90
-
91
- # Convert to linear RGB
92
- r_linear = +4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s
93
- g_linear = -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s
94
- b_linear = -0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s
95
-
96
- # Convert to sRGB
97
- r = linear_to_srgb(r_linear)
98
- g = linear_to_srgb(g_linear)
99
- b = linear_to_srgb(b_linear)
100
-
101
- # Clamp to 0-255 and convert to integers
102
- r = (r * 255).clamp(0, 255).round
103
- g = (g * 255).clamp(0, 255).round
104
- b = (b * 255).clamp(0, 255).round
105
-
106
- [r, g, b]
107
- end
40
+ from_oklch = rgb_to_oklch(*from_rgb)
41
+ to_oklch = rgb_to_oklch(*to_rgb)
108
42
 
109
- def srgb_to_linear(component)
110
- (component <= 0.04045) ? component / 12.92 : ((component + 0.055) / 1.055)**2.4
111
- end
43
+ colors = []
44
+ (0...steps).each do |i|
45
+ ratio = i.to_f / (steps - 1)
46
+ interpolated_oklch = interpolate_oklch(from_oklch, to_oklch, ratio)
47
+ interpolated_rgb = oklch_to_rgb(*interpolated_oklch)
48
+ colors << rgb_to_hex(*interpolated_rgb)
49
+ end
112
50
 
113
- def linear_to_srgb(component)
114
- (component <= 0.0031308) ? component * 12.92 : 1.055 * (component**(1.0 / 2.4)) - 0.055
115
- end
51
+ colors
52
+ end
53
+
54
+ private
55
+
56
+ def rgb_to_oklch(r, g, b)
57
+ r_linear = srgb_to_linear(r / 255.0)
58
+ g_linear = srgb_to_linear(g / 255.0)
59
+ b_linear = srgb_to_linear(b / 255.0)
60
+
61
+ l = 0.4122214708 * r_linear + 0.5363325363 * g_linear + 0.0514459929 * b_linear
62
+ m = 0.2119034982 * r_linear + 0.6806995451 * g_linear + 0.1073969566 * b_linear
63
+ s = 0.0883024619 * r_linear + 0.2817188376 * g_linear + 0.6299787005 * b_linear
64
+
65
+ l_root = (l >= 0) ? l**(1.0 / 3) : -((-l)**(1.0 / 3))
66
+ m_root = (m >= 0) ? m**(1.0 / 3) : -((-m)**(1.0 / 3))
67
+ s_root = (s >= 0) ? s**(1.0 / 3) : -((-s)**(1.0 / 3))
116
68
 
117
- def interpolate_oklch(oklch1, oklch2, ratio)
118
- # Handle hue interpolation (shortest path around the circle)
119
- hue1, hue2 = oklch1[2], oklch2[2]
120
- hue_diff = hue2 - hue1
69
+ ok_l = 0.2104542553 * l_root + 0.7936177850 * m_root - 0.0040720468 * s_root
70
+ ok_a = 1.9779984951 * l_root - 2.4285922050 * m_root + 0.4505937099 * s_root
71
+ ok_b = 0.0259040371 * l_root + 0.7827717662 * m_root - 0.8086757660 * s_root
121
72
 
122
- # Take shorter path around the circle
123
- if hue_diff > 180
124
- hue_diff -= 360
125
- elsif hue_diff < -180
126
- hue_diff += 360
73
+ chroma = Math.sqrt(ok_a * ok_a + ok_b * ok_b)
74
+ hue = Math.atan2(ok_b, ok_a) * 180.0 / Math::PI
75
+ hue += 360 if hue < 0
76
+
77
+ [ok_l, chroma, hue]
127
78
  end
128
79
 
129
- interpolated_hue = hue1 + hue_diff * ratio
130
- interpolated_hue += 360 if interpolated_hue < 0
131
- interpolated_hue -= 360 if interpolated_hue >= 360
80
+ def oklch_to_rgb(ok_l, chroma, hue)
81
+ hue_rad = hue * Math::PI / 180.0
82
+ ok_a = chroma * Math.cos(hue_rad)
83
+ ok_b = chroma * Math.sin(hue_rad)
132
84
 
133
- [
134
- oklch1[0] + (oklch2[0] - oklch1[0]) * ratio, # L (lightness)
135
- oklch1[1] + (oklch2[1] - oklch1[1]) * ratio, # C (chroma)
136
- interpolated_hue # H (hue)
137
- ]
138
- end
85
+ l_root = ok_l + 0.3963377774 * ok_a + 0.2158037573 * ok_b
86
+ m_root = ok_l - 0.1055613458 * ok_a - 0.0638541728 * ok_b
87
+ s_root = ok_l - 0.0894841775 * ok_a - 1.2914855480 * ok_b
139
88
 
140
- def hex_to_rgb(hex_color)
141
- hex = hex_color.delete("#")
142
- r = hex[0..1].to_i(16)
143
- g = hex[2..3].to_i(16)
144
- b = hex[4..5].to_i(16)
145
- [r, g, b]
146
- end
89
+ l = l_root * l_root * l_root
90
+ m = m_root * m_root * m_root
91
+ s = s_root * s_root * s_root
147
92
 
148
- def rgb_to_hex(r, g, b)
149
- "#%02x%02x%02x" % [r, g, b]
150
- end
93
+ r_linear = +4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s
94
+ g_linear = -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s
95
+ b_linear = -0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s
151
96
 
152
- def generate_color_palette(from_color, to_color, steps)
153
- from_rgb = hex_to_rgb(from_color)
154
- to_rgb = hex_to_rgb(to_color)
97
+ r = linear_to_srgb(r_linear)
98
+ g = linear_to_srgb(g_linear)
99
+ b = linear_to_srgb(b_linear)
155
100
 
156
- from_oklch = rgb_to_oklch(*from_rgb)
157
- to_oklch = rgb_to_oklch(*to_rgb)
101
+ r = (r * 255).clamp(0, 255).round
102
+ g = (g * 255).clamp(0, 255).round
103
+ b = (b * 255).clamp(0, 255).round
158
104
 
159
- colors = []
160
- (0...steps).each do |i|
161
- ratio = i.to_f / (steps - 1)
162
- interpolated_oklch = interpolate_oklch(from_oklch, to_oklch, ratio)
163
- interpolated_rgb = oklch_to_rgb(*interpolated_oklch)
164
- colors << rgb_to_hex(*interpolated_rgb)
105
+ [r, g, b]
165
106
  end
166
107
 
167
- colors
108
+ def srgb_to_linear(component)
109
+ (component <= 0.04045) ? component / 12.92 : ((component + 0.055) / 1.055)**2.4
110
+ end
111
+
112
+ def linear_to_srgb(component)
113
+ (component <= 0.0031308) ? component * 12.92 : 1.055 * (component**(1.0 / 2.4)) - 0.055
114
+ end
115
+
116
+ def interpolate_oklch(oklch1, oklch2, ratio)
117
+ hue1, hue2 = oklch1[2], oklch2[2]
118
+ hue_diff = hue2 - hue1
119
+
120
+ if hue_diff > 180
121
+ hue_diff -= 360
122
+ elsif hue_diff < -180
123
+ hue_diff += 360
124
+ end
125
+
126
+ interpolated_hue = hue1 + hue_diff * ratio
127
+ interpolated_hue += 360 if interpolated_hue < 0
128
+ interpolated_hue -= 360 if interpolated_hue >= 360
129
+
130
+ [
131
+ oklch1[0] + (oklch2[0] - oklch1[0]) * ratio,
132
+ oklch1[1] + (oklch2[1] - oklch1[1]) * ratio,
133
+ interpolated_hue
134
+ ]
135
+ end
136
+
137
+ def hex_to_rgb(hex_color)
138
+ hex = hex_color.delete("#")
139
+ r = hex[0..1].to_i(16)
140
+ g = hex[2..3].to_i(16)
141
+ b = hex[4..5].to_i(16)
142
+ [r, g, b]
143
+ end
144
+
145
+ def rgb_to_hex(r, g, b)
146
+ "#%02x%02x%02x" % [r, g, b]
147
+ end
168
148
  end
169
149
  end
170
150
  end
@@ -4,7 +4,7 @@ module HeatmapBuilder
4
4
 
5
5
  def svg_element(tag, attributes = {}, &block)
6
6
  attr_string = attributes.map do |key, value|
7
- "#{kebab_case(key)}=\"#{value}\""
7
+ "#{kebab_case(key)}=\"#{escape_xml(value.to_s)}\""
8
8
  end.join(" ")
9
9
 
10
10
  attr_string = " #{attr_string}" unless attr_string.empty?
@@ -35,7 +35,7 @@ module HeatmapBuilder
35
35
  font_family: "Arial, sans-serif"
36
36
  }
37
37
 
38
- svg_element("text", {x: x, y: y}.merge(default_attrs).merge(attributes)) { content }
38
+ svg_element("text", {x: x, y: y}.merge(default_attrs).merge(attributes)) { escape_xml(content) }
39
39
  end
40
40
 
41
41
  def svg_container(width:, height:, &block)
@@ -50,14 +50,21 @@ module HeatmapBuilder
50
50
  key.to_s.tr("_", "-")
51
51
  end
52
52
 
53
- def cell_border(x, y, color, cell_size:, border_width:, corner_radius:)
53
+ def escape_xml(str)
54
+ str.gsub("&", "&amp;").gsub("<", "&lt;").gsub(">", "&gt;").gsub('"', "&quot;")
55
+ end
56
+
57
+ def cell_border(x, y, color, cell_size:, border_width:, corner_radius:, border_lightness_factor: 0.9)
54
58
  return "" unless border_width > 0
59
+ # A factor of 1 leaves the color unchanged, so the border matches the
60
+ # fill exactly and would be invisible. Skip drawing it entirely.
61
+ return "" if border_lightness_factor == 1
55
62
 
56
63
  inset = border_width / 2.0
57
64
  border_x = x + inset
58
65
  border_y = y + inset
59
66
  border_size = cell_size - border_width
60
- border_color = darker_color(color)
67
+ border_color = ColorHelpers.adjust_lightness(color, factor: border_lightness_factor)
61
68
  border_radius = (corner_radius > 0) ? [corner_radius - inset, 0].max : 0
62
69
 
63
70
  svg_rect(
@@ -32,11 +32,9 @@ module HeatmapBuilder
32
32
  end
33
33
 
34
34
  def convert_value_to_score(value, **params)
35
- value = value_min if value.nil?
36
-
37
35
  if options[:value_to_score]
38
36
  score = options[:value_to_score].call(
39
- value: value,
37
+ value: value.nil? ? value_min : value,
40
38
  min: value_min,
41
39
  max: value_max,
42
40
  max_score: color_count - 1,
@@ -50,14 +48,20 @@ module HeatmapBuilder
50
48
  return score
51
49
  end
52
50
 
51
+ # Score 0 is reserved for empty cells (zero or missing values). Any
52
+ # non-zero value maps into 1..max_score so even the smallest activity is
53
+ # visibly distinct from an empty day.
54
+ return 0 if value.nil? || value.zero?
55
+
56
+ max_score = color_count - 1
53
57
  clamped_value = value.clamp(value_min, value_max)
54
58
 
55
59
  if value_min == value_max
56
- 0
60
+ max_score
57
61
  else
58
62
  range = value_max - value_min
59
63
  normalized = (clamped_value - value_min).to_f / range
60
- (normalized * (color_count - 1)).round
64
+ 1 + (normalized * (max_score - 1)).round
61
65
  end
62
66
  end
63
67
  end
@@ -1,3 +1,3 @@
1
1
  module HeatmapBuilder
2
- VERSION = "0.2.0"
2
+ VERSION = "0.4.3"
3
3
  end
metadata CHANGED
@@ -1,55 +1,55 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: heatmap-builder
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Musayev
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-10-02 00:00:00.000000000 Z
11
+ date: 2026-06-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '2.0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '13.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '13.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: minitest
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '5.0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '5.0'
55
55
  - !ruby/object:Gem::Dependency
@@ -102,8 +102,11 @@ files:
102
102
  - bin/generate_examples
103
103
  - bin/setup
104
104
  - examples/calendar_blue_ocean.svg
105
+ - examples/calendar_cell_borders.svg
105
106
  - examples/calendar_default.svg
106
107
  - examples/calendar_github_style.svg
108
+ - examples/calendar_month_spacing_rounded.svg
109
+ - examples/calendar_no_borders.svg
107
110
  - examples/calendar_purple_vibes.svg
108
111
  - examples/calendar_red_to_green.svg
109
112
  - examples/calendar_rounded_corners.svg
@@ -111,22 +114,10 @@ files:
111
114
  - examples/calendar_sunday_start.svg
112
115
  - examples/calendar_warm_sunset.svg
113
116
  - examples/calendar_with_outside_cells.svg
114
- - examples/large_cells.svg
115
- - examples/linear_blue_ocean.svg
116
- - examples/linear_github_green.svg
117
- - examples/linear_neon_gradient.svg
118
- - examples/linear_purple_vibes.svg
119
- - examples/linear_red_to_green.svg
120
- - examples/linear_rounded_corners.svg
121
- - examples/linear_rounded_corners_max_radius.svg
122
- - examples/linear_warm_sunset.svg
123
- - examples/weekly_progress.svg
124
117
  - heatmap-builder.gemspec
125
118
  - lib/heatmap-builder.rb
126
- - lib/heatmap_builder/builder.rb
127
- - lib/heatmap_builder/calendar_heatmap_builder.rb
119
+ - lib/heatmap_builder/calendar.rb
128
120
  - lib/heatmap_builder/color_helpers.rb
129
- - lib/heatmap_builder/linear_heatmap_builder.rb
130
121
  - lib/heatmap_builder/svg_helpers.rb
131
122
  - lib/heatmap_builder/value_conversion.rb
132
123
  - lib/heatmap_builder/version.rb
@@ -146,7 +137,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
146
137
  requirements:
147
138
  - - ">="
148
139
  - !ruby/object:Gem::Version
149
- version: '3.0'
140
+ version: '3.3'
150
141
  required_rubygems_version: !ruby/object:Gem::Requirement
151
142
  requirements:
152
143
  - - ">="
@@ -1 +0,0 @@
1
- <svg width="251" height="35" xmlns="http://www.w3.org/2000/svg"><rect x="0" y="0" width="35" height="35" fill="#9be9a8"/><rect x="0.5" y="0.5" width="34" height="34" fill="none" stroke="#7fcc8d" stroke-width="1"/><text x="17" y="24.0" text-anchor="middle" font-family="Arial, sans-serif" font-size="20" fill="#000000">1</text><rect x="36" y="0" width="35" height="35" fill="#40c463"/><rect x="36.5" y="0.5" width="34" height="34" fill="none" stroke="#1dac4d" stroke-width="1"/><text x="53" y="24.0" text-anchor="middle" font-family="Arial, sans-serif" font-size="20" fill="#000000">2</text><rect x="72" y="0" width="35" height="35" fill="#30a14e"/><rect x="72.5" y="0.5" width="34" height="34" fill="none" stroke="#108d3b" stroke-width="1"/><text x="89" y="24.0" text-anchor="middle" font-family="Arial, sans-serif" font-size="20" fill="#000000">3</text><rect x="108" y="0" width="35" height="35" fill="#216e39"/><rect x="108.5" y="0.5" width="34" height="34" fill="none" stroke="#0d602c" stroke-width="1"/><text x="125" y="24.0" text-anchor="middle" font-family="Arial, sans-serif" font-size="20" fill="#000000">4</text><rect x="144" y="0" width="35" height="35" fill="#9be9a8"/><rect x="144.5" y="0.5" width="34" height="34" fill="none" stroke="#7fcc8d" stroke-width="1"/><text x="161" y="24.0" text-anchor="middle" font-family="Arial, sans-serif" font-size="20" fill="#000000">5</text><rect x="180" y="0" width="35" height="35" fill="#40c463"/><rect x="180.5" y="0.5" width="34" height="34" fill="none" stroke="#1dac4d" stroke-width="1"/><text x="197" y="24.0" text-anchor="middle" font-family="Arial, sans-serif" font-size="20" fill="#000000">6</text><rect x="216" y="0" width="35" height="35" fill="#30a14e"/><rect x="216.5" y="0.5" width="34" height="34" fill="none" stroke="#108d3b" stroke-width="1"/><text x="233" y="24.0" text-anchor="middle" font-family="Arial, sans-serif" font-size="20" fill="#000000">7</text></svg>
@@ -1 +0,0 @@
1
- <svg width="189" height="18" xmlns="http://www.w3.org/2000/svg"><rect x="0" y="0" width="18" height="18" fill="#f0f9ff"/><rect x="0.5" y="0.5" width="17" height="17" fill="none" stroke="#d0d9df" stroke-width="1"/><text x="9" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">0</text><rect x="19" y="0" width="18" height="18" fill="#bae6fd"/><rect x="19.5" y="0.5" width="17" height="17" fill="none" stroke="#9dc9df" stroke-width="1"/><text x="28" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">1</text><rect x="38" y="0" width="18" height="18" fill="#7dd3fc"/><rect x="38.5" y="0.5" width="17" height="17" fill="none" stroke="#62b8e0" stroke-width="1"/><text x="47" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">2</text><rect x="57" y="0" width="18" height="18" fill="#38bdf8"/><rect x="57.5" y="0.5" width="17" height="17" fill="none" stroke="#03a5df" stroke-width="1"/><text x="66" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">3</text><rect x="76" y="0" width="18" height="18" fill="#0ea5e9"/><rect x="76.5" y="0.5" width="17" height="17" fill="none" stroke="#008fd2" stroke-width="1"/><text x="85" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">4</text><rect x="95" y="0" width="18" height="18" fill="#bae6fd"/><rect x="95.5" y="0.5" width="17" height="17" fill="none" stroke="#9dc9df" stroke-width="1"/><text x="104" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">5</text><rect x="114" y="0" width="18" height="18" fill="#7dd3fc"/><rect x="114.5" y="0.5" width="17" height="17" fill="none" stroke="#62b8e0" stroke-width="1"/><text x="123" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">6</text><rect x="133" y="0" width="18" height="18" fill="#38bdf8"/><rect x="133.5" y="0.5" width="17" height="17" fill="none" stroke="#03a5df" stroke-width="1"/><text x="142" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">7</text><rect x="152" y="0" width="18" height="18" fill="#0ea5e9"/><rect x="152.5" y="0.5" width="17" height="17" fill="none" stroke="#008fd2" stroke-width="1"/><text x="161" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">8</text><rect x="171" y="0" width="18" height="18" fill="#bae6fd"/><rect x="171.5" y="0.5" width="17" height="17" fill="none" stroke="#9dc9df" stroke-width="1"/><text x="180" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">9</text></svg>
@@ -1 +0,0 @@
1
- <svg width="189" height="18" xmlns="http://www.w3.org/2000/svg"><rect x="0" y="0" width="18" height="18" fill="#ebedf0"/><rect x="0.5" y="0.5" width="17" height="17" fill="none" stroke="#ccced1" stroke-width="1"/><text x="9" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">0</text><rect x="19" y="0" width="18" height="18" fill="#9be9a8"/><rect x="19.5" y="0.5" width="17" height="17" fill="none" stroke="#7fcc8d" stroke-width="1"/><text x="28" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">1</text><rect x="38" y="0" width="18" height="18" fill="#40c463"/><rect x="38.5" y="0.5" width="17" height="17" fill="none" stroke="#1dac4d" stroke-width="1"/><text x="47" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">2</text><rect x="57" y="0" width="18" height="18" fill="#30a14e"/><rect x="57.5" y="0.5" width="17" height="17" fill="none" stroke="#108d3b" stroke-width="1"/><text x="66" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">3</text><rect x="76" y="0" width="18" height="18" fill="#216e39"/><rect x="76.5" y="0.5" width="17" height="17" fill="none" stroke="#0d602c" stroke-width="1"/><text x="85" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">4</text><rect x="95" y="0" width="18" height="18" fill="#9be9a8"/><rect x="95.5" y="0.5" width="17" height="17" fill="none" stroke="#7fcc8d" stroke-width="1"/><text x="104" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">5</text><rect x="114" y="0" width="18" height="18" fill="#40c463"/><rect x="114.5" y="0.5" width="17" height="17" fill="none" stroke="#1dac4d" stroke-width="1"/><text x="123" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">6</text><rect x="133" y="0" width="18" height="18" fill="#30a14e"/><rect x="133.5" y="0.5" width="17" height="17" fill="none" stroke="#108d3b" stroke-width="1"/><text x="142" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">7</text><rect x="152" y="0" width="18" height="18" fill="#216e39"/><rect x="152.5" y="0.5" width="17" height="17" fill="none" stroke="#0d602c" stroke-width="1"/><text x="161" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">8</text><rect x="171" y="0" width="18" height="18" fill="#9be9a8"/><rect x="171.5" y="0.5" width="17" height="17" fill="none" stroke="#7fcc8d" stroke-width="1"/><text x="180" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">9</text></svg>
@@ -1 +0,0 @@
1
- <svg width="189" height="18" xmlns="http://www.w3.org/2000/svg"><rect x="0" y="0" width="18" height="18" fill="#00ffff"/><rect x="0.5" y="0.5" width="17" height="17" fill="none" stroke="#00e0e1" stroke-width="1"/><text x="9" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">0</text><rect x="19" y="0" width="18" height="18" fill="#00dbff"/><rect x="19.5" y="0.5" width="17" height="17" fill="none" stroke="#00c0e3" stroke-width="1"/><text x="28" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">1</text><rect x="38" y="0" width="18" height="18" fill="#96a6ff"/><rect x="38.5" y="0.5" width="17" height="17" fill="none" stroke="#808fe5" stroke-width="1"/><text x="47" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">2</text><rect x="57" y="0" width="18" height="18" fill="#db69ff"/><rect x="57.5" y="0.5" width="17" height="17" fill="none" stroke="#c351e6" stroke-width="1"/><text x="66" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">3</text><rect x="76" y="0" width="18" height="18" fill="#ff1493"/><rect x="76.5" y="0.5" width="17" height="17" fill="none" stroke="#e6007f" stroke-width="1"/><text x="85" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">4</text><rect x="95" y="0" width="18" height="18" fill="#00dbff"/><rect x="95.5" y="0.5" width="17" height="17" fill="none" stroke="#00c0e3" stroke-width="1"/><text x="104" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">5</text><rect x="114" y="0" width="18" height="18" fill="#96a6ff"/><rect x="114.5" y="0.5" width="17" height="17" fill="none" stroke="#808fe5" stroke-width="1"/><text x="123" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">6</text><rect x="133" y="0" width="18" height="18" fill="#db69ff"/><rect x="133.5" y="0.5" width="17" height="17" fill="none" stroke="#c351e6" stroke-width="1"/><text x="142" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">7</text><rect x="152" y="0" width="18" height="18" fill="#ff1493"/><rect x="152.5" y="0.5" width="17" height="17" fill="none" stroke="#e6007f" stroke-width="1"/><text x="161" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">8</text><rect x="171" y="0" width="18" height="18" fill="#00dbff"/><rect x="171.5" y="0.5" width="17" height="17" fill="none" stroke="#00c0e3" stroke-width="1"/><text x="180" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">9</text></svg>
@@ -1 +0,0 @@
1
- <svg width="189" height="18" xmlns="http://www.w3.org/2000/svg"><rect x="0" y="0" width="18" height="18" fill="#f3e8ff"/><rect x="0.5" y="0.5" width="17" height="17" fill="none" stroke="#d4c9e0" stroke-width="1"/><text x="9" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">0</text><rect x="19" y="0" width="18" height="18" fill="#d8b4fe"/><rect x="19.5" y="0.5" width="17" height="17" fill="none" stroke="#bd9ae2" stroke-width="1"/><text x="28" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">1</text><rect x="38" y="0" width="18" height="18" fill="#c084fc"/><rect x="38.5" y="0.5" width="17" height="17" fill="none" stroke="#a96de3" stroke-width="1"/><text x="47" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">2</text><rect x="57" y="0" width="18" height="18" fill="#a855f7"/><rect x="57.5" y="0.5" width="17" height="17" fill="none" stroke="#953fe1" stroke-width="1"/><text x="66" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">3</text><rect x="76" y="0" width="18" height="18" fill="#9333ea"/><rect x="76.5" y="0.5" width="17" height="17" fill="none" stroke="#8316d7" stroke-width="1"/><text x="85" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">4</text><rect x="95" y="0" width="18" height="18" fill="#d8b4fe"/><rect x="95.5" y="0.5" width="17" height="17" fill="none" stroke="#bd9ae2" stroke-width="1"/><text x="104" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">5</text><rect x="114" y="0" width="18" height="18" fill="#c084fc"/><rect x="114.5" y="0.5" width="17" height="17" fill="none" stroke="#a96de3" stroke-width="1"/><text x="123" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">6</text><rect x="133" y="0" width="18" height="18" fill="#a855f7"/><rect x="133.5" y="0.5" width="17" height="17" fill="none" stroke="#953fe1" stroke-width="1"/><text x="142" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">7</text><rect x="152" y="0" width="18" height="18" fill="#9333ea"/><rect x="152.5" y="0.5" width="17" height="17" fill="none" stroke="#8316d7" stroke-width="1"/><text x="161" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">8</text><rect x="171" y="0" width="18" height="18" fill="#d8b4fe"/><rect x="171.5" y="0.5" width="17" height="17" fill="none" stroke="#bd9ae2" stroke-width="1"/><text x="180" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">9</text></svg>
@@ -1 +0,0 @@
1
- <svg width="189" height="18" xmlns="http://www.w3.org/2000/svg"><rect x="0" y="0" width="18" height="18" fill="#f5f5f5"/><rect x="0.5" y="0.5" width="17" height="17" fill="none" stroke="#d5d5d5" stroke-width="1"/><text x="9" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">0</text><rect x="19" y="0" width="18" height="18" fill="#ff9999"/><rect x="19.5" y="0.5" width="17" height="17" fill="none" stroke="#e48081" stroke-width="1"/><text x="28" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">1</text><rect x="38" y="0" width="18" height="18" fill="#f7ad6a"/><rect x="38.5" y="0.5" width="17" height="17" fill="none" stroke="#dc9450" stroke-width="1"/><text x="47" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">2</text><rect x="57" y="0" width="18" height="18" fill="#d2c768"/><rect x="57.5" y="0.5" width="17" height="17" fill="none" stroke="#b8ad4d" stroke-width="1"/><text x="66" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">3</text><rect x="76" y="0" width="18" height="18" fill="#99dd99"/><rect x="76.5" y="0.5" width="17" height="17" fill="none" stroke="#7fc27f" stroke-width="1"/><text x="85" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">4</text><rect x="95" y="0" width="18" height="18" fill="#ff9999"/><rect x="95.5" y="0.5" width="17" height="17" fill="none" stroke="#e48081" stroke-width="1"/><text x="104" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">5</text><rect x="114" y="0" width="18" height="18" fill="#f7ad6a"/><rect x="114.5" y="0.5" width="17" height="17" fill="none" stroke="#dc9450" stroke-width="1"/><text x="123" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">6</text><rect x="133" y="0" width="18" height="18" fill="#d2c768"/><rect x="133.5" y="0.5" width="17" height="17" fill="none" stroke="#b8ad4d" stroke-width="1"/><text x="142" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">7</text><rect x="152" y="0" width="18" height="18" fill="#99dd99"/><rect x="152.5" y="0.5" width="17" height="17" fill="none" stroke="#7fc27f" stroke-width="1"/><text x="161" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">8</text><rect x="171" y="0" width="18" height="18" fill="#ff9999"/><rect x="171.5" y="0.5" width="17" height="17" fill="none" stroke="#e48081" stroke-width="1"/><text x="180" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">9</text></svg>
@@ -1 +0,0 @@
1
- <svg width="189" height="18" xmlns="http://www.w3.org/2000/svg"><rect x="0" y="0" width="18" height="18" rx="2" fill="#ebedf0"/><rect x="0.5" y="0.5" width="17" height="17" rx="1.5" fill="none" stroke="#ccced1" stroke-width="1"/><text x="9" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">0</text><rect x="19" y="0" width="18" height="18" rx="2" fill="#9be9a8"/><rect x="19.5" y="0.5" width="17" height="17" rx="1.5" fill="none" stroke="#7fcc8d" stroke-width="1"/><text x="28" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">1</text><rect x="38" y="0" width="18" height="18" rx="2" fill="#40c463"/><rect x="38.5" y="0.5" width="17" height="17" rx="1.5" fill="none" stroke="#1dac4d" stroke-width="1"/><text x="47" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">2</text><rect x="57" y="0" width="18" height="18" rx="2" fill="#30a14e"/><rect x="57.5" y="0.5" width="17" height="17" rx="1.5" fill="none" stroke="#108d3b" stroke-width="1"/><text x="66" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">3</text><rect x="76" y="0" width="18" height="18" rx="2" fill="#216e39"/><rect x="76.5" y="0.5" width="17" height="17" rx="1.5" fill="none" stroke="#0d602c" stroke-width="1"/><text x="85" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">4</text><rect x="95" y="0" width="18" height="18" rx="2" fill="#9be9a8"/><rect x="95.5" y="0.5" width="17" height="17" rx="1.5" fill="none" stroke="#7fcc8d" stroke-width="1"/><text x="104" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">5</text><rect x="114" y="0" width="18" height="18" rx="2" fill="#40c463"/><rect x="114.5" y="0.5" width="17" height="17" rx="1.5" fill="none" stroke="#1dac4d" stroke-width="1"/><text x="123" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">6</text><rect x="133" y="0" width="18" height="18" rx="2" fill="#30a14e"/><rect x="133.5" y="0.5" width="17" height="17" rx="1.5" fill="none" stroke="#108d3b" stroke-width="1"/><text x="142" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">7</text><rect x="152" y="0" width="18" height="18" rx="2" fill="#216e39"/><rect x="152.5" y="0.5" width="17" height="17" rx="1.5" fill="none" stroke="#0d602c" stroke-width="1"/><text x="161" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">8</text><rect x="171" y="0" width="18" height="18" rx="2" fill="#9be9a8"/><rect x="171.5" y="0.5" width="17" height="17" rx="1.5" fill="none" stroke="#7fcc8d" stroke-width="1"/><text x="180" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">9</text></svg>
@@ -1 +0,0 @@
1
- <svg width="189" height="18" xmlns="http://www.w3.org/2000/svg"><rect x="0" y="0" width="18" height="18" rx="9" fill="#ebedf0"/><rect x="0.5" y="0.5" width="17" height="17" rx="8.5" fill="none" stroke="#ccced1" stroke-width="1"/><text x="9" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">0</text><rect x="19" y="0" width="18" height="18" rx="9" fill="#9be9a8"/><rect x="19.5" y="0.5" width="17" height="17" rx="8.5" fill="none" stroke="#7fcc8d" stroke-width="1"/><text x="28" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">1</text><rect x="38" y="0" width="18" height="18" rx="9" fill="#40c463"/><rect x="38.5" y="0.5" width="17" height="17" rx="8.5" fill="none" stroke="#1dac4d" stroke-width="1"/><text x="47" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">2</text><rect x="57" y="0" width="18" height="18" rx="9" fill="#30a14e"/><rect x="57.5" y="0.5" width="17" height="17" rx="8.5" fill="none" stroke="#108d3b" stroke-width="1"/><text x="66" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">3</text><rect x="76" y="0" width="18" height="18" rx="9" fill="#216e39"/><rect x="76.5" y="0.5" width="17" height="17" rx="8.5" fill="none" stroke="#0d602c" stroke-width="1"/><text x="85" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">4</text><rect x="95" y="0" width="18" height="18" rx="9" fill="#9be9a8"/><rect x="95.5" y="0.5" width="17" height="17" rx="8.5" fill="none" stroke="#7fcc8d" stroke-width="1"/><text x="104" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">5</text><rect x="114" y="0" width="18" height="18" rx="9" fill="#40c463"/><rect x="114.5" y="0.5" width="17" height="17" rx="8.5" fill="none" stroke="#1dac4d" stroke-width="1"/><text x="123" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">6</text><rect x="133" y="0" width="18" height="18" rx="9" fill="#30a14e"/><rect x="133.5" y="0.5" width="17" height="17" rx="8.5" fill="none" stroke="#108d3b" stroke-width="1"/><text x="142" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">7</text><rect x="152" y="0" width="18" height="18" rx="9" fill="#216e39"/><rect x="152.5" y="0.5" width="17" height="17" rx="8.5" fill="none" stroke="#0d602c" stroke-width="1"/><text x="161" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">8</text><rect x="171" y="0" width="18" height="18" rx="9" fill="#9be9a8"/><rect x="171.5" y="0.5" width="17" height="17" rx="8.5" fill="none" stroke="#7fcc8d" stroke-width="1"/><text x="180" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">9</text></svg>
@@ -1 +0,0 @@
1
- <svg width="189" height="18" xmlns="http://www.w3.org/2000/svg"><rect x="0" y="0" width="18" height="18" fill="#fef3e2"/><rect x="0.5" y="0.5" width="17" height="17" fill="none" stroke="#ded3c3" stroke-width="1"/><text x="9" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">0</text><rect x="19" y="0" width="18" height="18" fill="#fed7aa"/><rect x="19.5" y="0.5" width="17" height="17" fill="none" stroke="#e0ba8e" stroke-width="1"/><text x="28" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">1</text><rect x="38" y="0" width="18" height="18" fill="#fdba74"/><rect x="38.5" y="0.5" width="17" height="17" fill="none" stroke="#e19f59" stroke-width="1"/><text x="47" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">2</text><rect x="57" y="0" width="18" height="18" fill="#fb923c"/><rect x="57.5" y="0.5" width="17" height="17" fill="none" stroke="#e17a1a" stroke-width="1"/><text x="66" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">3</text><rect x="76" y="0" width="18" height="18" fill="#f97316"/><rect x="76.5" y="0.5" width="17" height="17" fill="none" stroke="#e05c00" stroke-width="1"/><text x="85" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">4</text><rect x="95" y="0" width="18" height="18" fill="#fed7aa"/><rect x="95.5" y="0.5" width="17" height="17" fill="none" stroke="#e0ba8e" stroke-width="1"/><text x="104" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">5</text><rect x="114" y="0" width="18" height="18" fill="#fdba74"/><rect x="114.5" y="0.5" width="17" height="17" fill="none" stroke="#e19f59" stroke-width="1"/><text x="123" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">6</text><rect x="133" y="0" width="18" height="18" fill="#fb923c"/><rect x="133.5" y="0.5" width="17" height="17" fill="none" stroke="#e17a1a" stroke-width="1"/><text x="142" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">7</text><rect x="152" y="0" width="18" height="18" fill="#f97316"/><rect x="152.5" y="0.5" width="17" height="17" fill="none" stroke="#e05c00" stroke-width="1"/><text x="161" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">8</text><rect x="171" y="0" width="18" height="18" fill="#fed7aa"/><rect x="171.5" y="0.5" width="17" height="17" fill="none" stroke="#e0ba8e" stroke-width="1"/><text x="180" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">9</text></svg>
@@ -1 +0,0 @@
1
- <svg width="132" height="18" xmlns="http://www.w3.org/2000/svg"><rect x="0" y="0" width="18" height="18" fill="#ebedf0"/><rect x="0.5" y="0.5" width="17" height="17" fill="none" stroke="#ccced1" stroke-width="1"/><text x="9" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">0</text><rect x="19" y="0" width="18" height="18" fill="#9be9a8"/><rect x="19.5" y="0.5" width="17" height="17" fill="none" stroke="#7fcc8d" stroke-width="1"/><text x="28" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">1</text><rect x="38" y="0" width="18" height="18" fill="#30a14e"/><rect x="38.5" y="0.5" width="17" height="17" fill="none" stroke="#108d3b" stroke-width="1"/><text x="47" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">3</text><rect x="57" y="0" width="18" height="18" fill="#40c463"/><rect x="57.5" y="0.5" width="17" height="17" fill="none" stroke="#1dac4d" stroke-width="1"/><text x="66" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">2</text><rect x="76" y="0" width="18" height="18" fill="#216e39"/><rect x="76.5" y="0.5" width="17" height="17" fill="none" stroke="#0d602c" stroke-width="1"/><text x="85" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">4</text><rect x="95" y="0" width="18" height="18" fill="#9be9a8"/><rect x="95.5" y="0.5" width="17" height="17" fill="none" stroke="#7fcc8d" stroke-width="1"/><text x="104" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">1</text><rect x="114" y="0" width="18" height="18" fill="#ebedf0"/><rect x="114.5" y="0.5" width="17" height="17" fill="none" stroke="#ccced1" stroke-width="1"/><text x="123" y="11.8" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#000000">0</text></svg>