lepus-saga 0.3.0

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 (84) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +28 -0
  3. data/Gemfile +5 -0
  4. data/Gemfile.lock +237 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +337 -0
  7. data/Rakefile +8 -0
  8. data/docs/brand/BRAND.md +67 -0
  9. data/docs/brand/apple-touch-icon.png +0 -0
  10. data/docs/brand/favicon-16.png +0 -0
  11. data/docs/brand/favicon-32.png +0 -0
  12. data/docs/brand/favicon.ico +0 -0
  13. data/docs/brand/favicon.svg +1 -0
  14. data/docs/brand/icon-512.png +0 -0
  15. data/docs/brand/lockup-lepus-mono.svg +1 -0
  16. data/docs/brand/lockup-lepus-on-dark.svg +1 -0
  17. data/docs/brand/lockup-lepus-on-light.svg +1 -0
  18. data/docs/brand/lockup-lepus-saga-mono.svg +1 -0
  19. data/docs/brand/lockup-lepus-saga-on-dark.svg +1 -0
  20. data/docs/brand/lockup-lepus-saga-on-light.svg +1 -0
  21. data/docs/brand/lockup-lepus-saga.svg +1 -0
  22. data/docs/brand/lockup-lepus.svg +1 -0
  23. data/docs/brand/mark-mono.svg +1 -0
  24. data/docs/brand/mark-on-dark.svg +1 -0
  25. data/docs/brand/mark-on-light.svg +1 -0
  26. data/docs/brand/mark-small-mono.svg +1 -0
  27. data/docs/brand/mark-small-on-dark.svg +1 -0
  28. data/docs/brand/mark-small-on-light.svg +1 -0
  29. data/docs/brand/mark-small.svg +1 -0
  30. data/docs/brand/mark.svg +1 -0
  31. data/lib/lepus/saga/configuration.rb +48 -0
  32. data/lib/lepus/saga/control.rb +27 -0
  33. data/lib/lepus/saga/definition.rb +123 -0
  34. data/lib/lepus/saga/execution_behaviour.rb +58 -0
  35. data/lib/lepus/saga/executor.rb +282 -0
  36. data/lib/lepus/saga/executor_consumer.rb +38 -0
  37. data/lib/lepus/saga/instrumentation.rb +41 -0
  38. data/lib/lepus/saga/log_subscriber.rb +42 -0
  39. data/lib/lepus/saga/queue_depth.rb +28 -0
  40. data/lib/lepus/saga/resume_stuck_job.rb +19 -0
  41. data/lib/lepus/saga/retry_policy.rb +19 -0
  42. data/lib/lepus/saga/rspec/engine_examples.rb +635 -0
  43. data/lib/lepus/saga/rspec/helpers.rb +22 -0
  44. data/lib/lepus/saga/rspec/query_examples.rb +378 -0
  45. data/lib/lepus/saga/rspec/store_examples.rb +514 -0
  46. data/lib/lepus/saga/rspec.rb +6 -0
  47. data/lib/lepus/saga/step.rb +9 -0
  48. data/lib/lepus/saga/step_attempt_behaviour.rb +35 -0
  49. data/lib/lepus/saga/step_producer.rb +37 -0
  50. data/lib/lepus/saga/stores/base.rb +305 -0
  51. data/lib/lepus/saga/stores/memory.rb +375 -0
  52. data/lib/lepus/saga/stores.rb +40 -0
  53. data/lib/lepus/saga/testing.rb +35 -0
  54. data/lib/lepus/saga/version.rb +7 -0
  55. data/lib/lepus/saga/web/api.rb +326 -0
  56. data/lib/lepus/saga/web/configuration.rb +49 -0
  57. data/lib/lepus/saga/web/guard.rb +38 -0
  58. data/lib/lepus/saga/web/serializer.rb +59 -0
  59. data/lib/lepus/saga/web/static.rb +108 -0
  60. data/lib/lepus/saga/web.rb +61 -0
  61. data/lib/lepus/saga.rb +212 -0
  62. data/lib/lepus-saga.rb +3 -0
  63. data/mise.toml +2 -0
  64. data/web/assets/app.css +913 -0
  65. data/web/assets/apple-touch-icon.png +0 -0
  66. data/web/assets/favicon-32.png +0 -0
  67. data/web/assets/favicon.svg +1 -0
  68. data/web/assets/fonts/overpass/OFL.txt +93 -0
  69. data/web/assets/fonts/overpass/overpass-latin-wght.woff2 +0 -0
  70. data/web/assets/js/api.js +50 -0
  71. data/web/assets/js/dom.js +84 -0
  72. data/web/assets/js/format.js +79 -0
  73. data/web/assets/js/live.js +74 -0
  74. data/web/assets/js/main.js +143 -0
  75. data/web/assets/js/map.js +639 -0
  76. data/web/assets/js/range.js +19 -0
  77. data/web/assets/js/sagas.js +18 -0
  78. data/web/assets/js/theme.js +8 -0
  79. data/web/assets/js/throughput.js +262 -0
  80. data/web/assets/js/views/execution.js +426 -0
  81. data/web/assets/js/views/executions.js +165 -0
  82. data/web/assets/js/views/overview.js +465 -0
  83. data/web/index.html +63 -0
  84. metadata +323 -0
@@ -0,0 +1,67 @@
1
+ # Lepus brand kit
2
+
3
+ ## The mark
4
+
5
+ A capital L drawn as a single route. The upright is the hare's ear; the foot curls back into a rounded body, and the amber dot inside it is a message in transit. One line, one stop, one message: the mark reads as "L", as a hare, and as a route carrying work.
6
+
7
+ ## Colours
8
+
9
+ | Role | Light background | Dark background |
10
+ |-------|------------------|-----------------|
11
+ | Ink | `#1a2233` | `#e3e9f3` |
12
+ | Amber | `#f2a30f` | `#f2a30f` |
13
+ | Tile (app icons) | `#1a2233` | `#1a2233` |
14
+
15
+ Amber is reserved for the message dot and the rule under "SAGA". Do not recolour the line in amber or put the dot in ink (except in the mono files).
16
+
17
+ ## Clear space and minimum size
18
+
19
+ - Clear space: keep at least the height of the mark's body (the rounded loop, about one third of the mark's height) empty on every side.
20
+ - `mark*.svg`: 48 px and up.
21
+ - `mark-small*.svg` / `favicon.svg`: 16 to 48 px. Its line is heavier and every edge sits on the 16, 32, 48 and 64 px pixel grids, so it stays sharp at favicon sizes. Do not use it large.
22
+ - `lockup-lepus*`: 120 px wide minimum. `lockup-lepus-saga*`: 180 px wide minimum (below that, "SAGA" gets too small; use `lockup-lepus` or the mark alone).
23
+
24
+ ## Which file where
25
+
26
+ | Use | File |
27
+ |-----|------|
28
+ | README header, Lepus | `lockup-lepus-on-light.svg` + `lockup-lepus-on-dark.svg` in a `<picture>` (below) |
29
+ | README header, Lepus saga | `lockup-lepus-saga-on-light.svg` + `lockup-lepus-saga-on-dark.svg` |
30
+ | Web page header that follows the OS theme | `lockup-lepus.svg`, `lockup-lepus-saga.svg`, `mark.svg` (ink switches with `prefers-color-scheme`) |
31
+ | Inline in an app that sets its own text colour | `*-mono.svg` (everything is `currentColor`) |
32
+ | Fixed background you control | `*-on-light.svg` / `*-on-dark.svg` |
33
+ | Browser tab | `favicon.svg` (adaptive), with `favicon.ico` (16/32/48) as fallback |
34
+ | iOS home screen | `apple-touch-icon.png` (180, solid tile) |
35
+ | Web manifest / PWA | `icon-512.png` (solid tile, mark inside the maskable safe zone) |
36
+ | Legacy PNG favicons | `favicon-16.png`, `favicon-32.png` (transparent, light-background ink) |
37
+
38
+ All wordmark text is outlined Overpass (SIL Open Font License), so no font is needed to render it.
39
+
40
+ ### README
41
+
42
+ GitHub follows the viewer's GitHub theme only through `<picture>`, so use the light/dark pair rather than the adaptive file:
43
+
44
+ ```html
45
+ <p align="center">
46
+ <picture>
47
+ <source media="(prefers-color-scheme: dark)" srcset="docs/brand/lockup-lepus-on-dark.svg">
48
+ <img alt="Lepus" src="docs/brand/lockup-lepus-on-light.svg" width="278">
49
+ </picture>
50
+ </p>
51
+ ```
52
+
53
+ For Lepus saga, swap in `lockup-lepus-saga-on-dark.svg` / `lockup-lepus-saga-on-light.svg` and `width="359"`.
54
+
55
+ ### HTML head
56
+
57
+ ```html
58
+ <link rel="icon" href="/favicon.ico" sizes="48x48">
59
+ <link rel="icon" href="/favicon.svg" type="image/svg+xml">
60
+ <link rel="apple-touch-icon" href="/apple-touch-icon.png">
61
+ ```
62
+
63
+ ## Don'ts
64
+
65
+ - Don't redraw the wordmark in live text or another typeface.
66
+ - Don't stretch, rotate, outline or add effects to the mark.
67
+ - Don't put the ink mark on mid-tone or busy backgrounds; use the tile or the mono file instead.
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" role="img" aria-label="Lepus"><title>Lepus</title><style>.i{stroke:#1a2233}.f{fill:#1a2233}@media (prefers-color-scheme:dark){.i{stroke:#e3e9f3}.f{fill:#e3e9f3}}</style><path class="i" d="M12 6 V40 A16 16 0 0 0 28 56 H42 A10 10 0 0 0 42 36 H28 V18" fill="none" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/><circle cx="40" cy="46" r="5" fill="#f2a30f"/></svg>
Binary file
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="-6.00 -64.40 259.67 84.00" width="278" height="90" role="img" aria-label="Lepus"><title>Lepus</title><g transform="translate(-13.03 -60.26) scale(1.2414)"><path d="M14 5 V42 A14 14 0 0 0 28 56 H42 A10 10 0 0 0 42 36 H28 V15" fill="none" stroke="currentColor" stroke-width="7" stroke-linecap="round" stroke-linejoin="round"/><circle cx="40.5" cy="46" r="4" fill="currentColor"/></g><path fill="currentColor" d="M80.05 0V-44.8H89.26V-8.91H110.81V0H80.05ZM128.16 0.77Q123.38 0.77 119.92 -1.31Q116.46 -3.39 114.61 -7.24Q112.76 -11.08 112.76 -16.38Q112.76 -21.64 114.65 -25.48Q116.54 -29.31 120 -31.39Q123.45 -33.47 128.16 -33.47Q132.23 -33.47 135.52 -31.8Q138.81 -30.12 140.75 -26.68Q142.69 -23.24 142.69 -17.97Q142.69 -17.1 142.66 -15.84Q142.62 -14.57 142.45 -13.31H121.38Q121.44 -11.31 122.29 -9.82Q123.13 -8.34 124.64 -7.52Q126.14 -6.71 128.19 -6.71Q130.6 -6.71 132.3 -7.49Q134 -8.28 135.56 -10.07L140.62 -4.94Q138.41 -2.35 135.33 -0.79Q132.26 0.77 128.16 0.77ZM121.47 -20.02H134.24Q134.04 -21.93 133.27 -23.27Q132.5 -24.6 131.17 -25.3Q129.85 -26 127.96 -26Q125.38 -26 123.59 -24.46Q121.8 -22.92 121.47 -20.02ZM148.64 12.99V-32.7H157.43V-30.41Q159.85 -33.47 164.23 -33.47Q168.44 -33.47 171.47 -31.4Q174.51 -29.34 176.15 -25.5Q177.78 -21.66 177.78 -16.33Q177.78 -11.21 176.07 -7.37Q174.35 -3.53 171.28 -1.38Q168.2 0.77 164.12 0.77Q161.97 0.77 160.28 0Q158.6 -0.76 157.43 -2.25V9.04L148.64 12.99ZM162.75 -7.69Q165.73 -7.69 167.35 -9.96Q168.96 -12.24 168.96 -16.33Q168.96 -20.51 167.35 -22.77Q165.74 -25.02 162.75 -25.02Q161 -25.02 159.72 -24.46Q158.44 -23.9 157.43 -22.71V-10.11Q158 -9.03 159.47 -8.36Q160.94 -7.69 162.75 -7.69ZM195.02 0.77Q189.74 0.77 186.71 -2.57Q183.68 -5.91 183.68 -11.78V-32.7H192.47V-15.4Q192.47 -11.26 193.74 -9.48Q195.02 -7.69 197.92 -7.69Q201.03 -7.69 202.46 -9.53Q203.89 -11.37 203.89 -15.27V-32.7H212.68V0H203.89V-3.03Q202.42 -1.17 200.15 -0.2Q197.87 0.77 195.02 0.77ZM231.57 0.77Q227.63 0.77 224.02 -0.91Q220.41 -2.59 218.35 -5.4L224 -10.18Q225.63 -8.5 227.77 -7.49Q229.9 -6.48 231.85 -6.48Q234.11 -6.48 235.33 -7.2Q236.55 -7.92 236.55 -9.25Q236.55 -10.07 235.97 -10.74Q235.39 -11.4 233.84 -12.14Q232.3 -12.88 229.42 -13.93Q223.86 -15.94 221.58 -18.28Q219.31 -20.63 219.31 -24.27Q219.31 -28.39 222.64 -30.93Q225.98 -33.47 231.34 -33.47Q234.98 -33.47 238.08 -32.09Q241.17 -30.71 243.42 -28.08L237.74 -23.4Q234.87 -26.23 231.17 -26.23Q229.41 -26.23 228.31 -25.58Q227.22 -24.94 227.22 -23.91Q227.22 -22.87 228.53 -22.03Q229.85 -21.2 233.5 -20.06Q237.33 -18.91 239.75 -17.4Q242.17 -15.9 243.31 -13.9Q244.44 -11.9 244.44 -9.28Q244.44 -4.58 241.01 -1.9Q237.57 0.77 231.57 0.77Z"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="-6.00 -64.40 259.67 84.00" width="278" height="90" role="img" aria-label="Lepus"><title>Lepus</title><g transform="translate(-13.03 -60.26) scale(1.2414)"><path d="M14 5 V42 A14 14 0 0 0 28 56 H42 A10 10 0 0 0 42 36 H28 V15" fill="none" stroke="#e3e9f3" stroke-width="7" stroke-linecap="round" stroke-linejoin="round"/><circle cx="40.5" cy="46" r="4" fill="#f2a30f"/></g><path fill="#e3e9f3" d="M80.05 0V-44.8H89.26V-8.91H110.81V0H80.05ZM128.16 0.77Q123.38 0.77 119.92 -1.31Q116.46 -3.39 114.61 -7.24Q112.76 -11.08 112.76 -16.38Q112.76 -21.64 114.65 -25.48Q116.54 -29.31 120 -31.39Q123.45 -33.47 128.16 -33.47Q132.23 -33.47 135.52 -31.8Q138.81 -30.12 140.75 -26.68Q142.69 -23.24 142.69 -17.97Q142.69 -17.1 142.66 -15.84Q142.62 -14.57 142.45 -13.31H121.38Q121.44 -11.31 122.29 -9.82Q123.13 -8.34 124.64 -7.52Q126.14 -6.71 128.19 -6.71Q130.6 -6.71 132.3 -7.49Q134 -8.28 135.56 -10.07L140.62 -4.94Q138.41 -2.35 135.33 -0.79Q132.26 0.77 128.16 0.77ZM121.47 -20.02H134.24Q134.04 -21.93 133.27 -23.27Q132.5 -24.6 131.17 -25.3Q129.85 -26 127.96 -26Q125.38 -26 123.59 -24.46Q121.8 -22.92 121.47 -20.02ZM148.64 12.99V-32.7H157.43V-30.41Q159.85 -33.47 164.23 -33.47Q168.44 -33.47 171.47 -31.4Q174.51 -29.34 176.15 -25.5Q177.78 -21.66 177.78 -16.33Q177.78 -11.21 176.07 -7.37Q174.35 -3.53 171.28 -1.38Q168.2 0.77 164.12 0.77Q161.97 0.77 160.28 0Q158.6 -0.76 157.43 -2.25V9.04L148.64 12.99ZM162.75 -7.69Q165.73 -7.69 167.35 -9.96Q168.96 -12.24 168.96 -16.33Q168.96 -20.51 167.35 -22.77Q165.74 -25.02 162.75 -25.02Q161 -25.02 159.72 -24.46Q158.44 -23.9 157.43 -22.71V-10.11Q158 -9.03 159.47 -8.36Q160.94 -7.69 162.75 -7.69ZM195.02 0.77Q189.74 0.77 186.71 -2.57Q183.68 -5.91 183.68 -11.78V-32.7H192.47V-15.4Q192.47 -11.26 193.74 -9.48Q195.02 -7.69 197.92 -7.69Q201.03 -7.69 202.46 -9.53Q203.89 -11.37 203.89 -15.27V-32.7H212.68V0H203.89V-3.03Q202.42 -1.17 200.15 -0.2Q197.87 0.77 195.02 0.77ZM231.57 0.77Q227.63 0.77 224.02 -0.91Q220.41 -2.59 218.35 -5.4L224 -10.18Q225.63 -8.5 227.77 -7.49Q229.9 -6.48 231.85 -6.48Q234.11 -6.48 235.33 -7.2Q236.55 -7.92 236.55 -9.25Q236.55 -10.07 235.97 -10.74Q235.39 -11.4 233.84 -12.14Q232.3 -12.88 229.42 -13.93Q223.86 -15.94 221.58 -18.28Q219.31 -20.63 219.31 -24.27Q219.31 -28.39 222.64 -30.93Q225.98 -33.47 231.34 -33.47Q234.98 -33.47 238.08 -32.09Q241.17 -30.71 243.42 -28.08L237.74 -23.4Q234.87 -26.23 231.17 -26.23Q229.41 -26.23 228.31 -25.58Q227.22 -24.94 227.22 -23.91Q227.22 -22.87 228.53 -22.03Q229.85 -21.2 233.5 -20.06Q237.33 -18.91 239.75 -17.4Q242.17 -15.9 243.31 -13.9Q244.44 -11.9 244.44 -9.28Q244.44 -4.58 241.01 -1.9Q237.57 0.77 231.57 0.77Z"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="-6.00 -64.40 259.67 84.00" width="278" height="90" role="img" aria-label="Lepus"><title>Lepus</title><g transform="translate(-13.03 -60.26) scale(1.2414)"><path d="M14 5 V42 A14 14 0 0 0 28 56 H42 A10 10 0 0 0 42 36 H28 V15" fill="none" stroke="#1a2233" stroke-width="7" stroke-linecap="round" stroke-linejoin="round"/><circle cx="40.5" cy="46" r="4" fill="#f2a30f"/></g><path fill="#1a2233" d="M80.05 0V-44.8H89.26V-8.91H110.81V0H80.05ZM128.16 0.77Q123.38 0.77 119.92 -1.31Q116.46 -3.39 114.61 -7.24Q112.76 -11.08 112.76 -16.38Q112.76 -21.64 114.65 -25.48Q116.54 -29.31 120 -31.39Q123.45 -33.47 128.16 -33.47Q132.23 -33.47 135.52 -31.8Q138.81 -30.12 140.75 -26.68Q142.69 -23.24 142.69 -17.97Q142.69 -17.1 142.66 -15.84Q142.62 -14.57 142.45 -13.31H121.38Q121.44 -11.31 122.29 -9.82Q123.13 -8.34 124.64 -7.52Q126.14 -6.71 128.19 -6.71Q130.6 -6.71 132.3 -7.49Q134 -8.28 135.56 -10.07L140.62 -4.94Q138.41 -2.35 135.33 -0.79Q132.26 0.77 128.16 0.77ZM121.47 -20.02H134.24Q134.04 -21.93 133.27 -23.27Q132.5 -24.6 131.17 -25.3Q129.85 -26 127.96 -26Q125.38 -26 123.59 -24.46Q121.8 -22.92 121.47 -20.02ZM148.64 12.99V-32.7H157.43V-30.41Q159.85 -33.47 164.23 -33.47Q168.44 -33.47 171.47 -31.4Q174.51 -29.34 176.15 -25.5Q177.78 -21.66 177.78 -16.33Q177.78 -11.21 176.07 -7.37Q174.35 -3.53 171.28 -1.38Q168.2 0.77 164.12 0.77Q161.97 0.77 160.28 0Q158.6 -0.76 157.43 -2.25V9.04L148.64 12.99ZM162.75 -7.69Q165.73 -7.69 167.35 -9.96Q168.96 -12.24 168.96 -16.33Q168.96 -20.51 167.35 -22.77Q165.74 -25.02 162.75 -25.02Q161 -25.02 159.72 -24.46Q158.44 -23.9 157.43 -22.71V-10.11Q158 -9.03 159.47 -8.36Q160.94 -7.69 162.75 -7.69ZM195.02 0.77Q189.74 0.77 186.71 -2.57Q183.68 -5.91 183.68 -11.78V-32.7H192.47V-15.4Q192.47 -11.26 193.74 -9.48Q195.02 -7.69 197.92 -7.69Q201.03 -7.69 202.46 -9.53Q203.89 -11.37 203.89 -15.27V-32.7H212.68V0H203.89V-3.03Q202.42 -1.17 200.15 -0.2Q197.87 0.77 195.02 0.77ZM231.57 0.77Q227.63 0.77 224.02 -0.91Q220.41 -2.59 218.35 -5.4L224 -10.18Q225.63 -8.5 227.77 -7.49Q229.9 -6.48 231.85 -6.48Q234.11 -6.48 235.33 -7.2Q236.55 -7.92 236.55 -9.25Q236.55 -10.07 235.97 -10.74Q235.39 -11.4 233.84 -12.14Q232.3 -12.88 229.42 -13.93Q223.86 -15.94 221.58 -18.28Q219.31 -20.63 219.31 -24.27Q219.31 -28.39 222.64 -30.93Q225.98 -33.47 231.34 -33.47Q234.98 -33.47 238.08 -32.09Q241.17 -30.71 243.42 -28.08L237.74 -23.4Q234.87 -26.23 231.17 -26.23Q229.41 -26.23 228.31 -25.58Q227.22 -24.94 227.22 -23.91Q227.22 -22.87 228.53 -22.03Q229.85 -21.2 233.5 -20.06Q237.33 -18.91 239.75 -17.4Q242.17 -15.9 243.31 -13.9Q244.44 -11.9 244.44 -9.28Q244.44 -4.58 241.01 -1.9Q237.57 0.77 231.57 0.77Z"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="-6.00 -64.40 372.21 84.00" width="359" height="81" role="img" aria-label="Lepus saga"><title>Lepus saga</title><g transform="translate(-13.03 -60.26) scale(1.2414)"><path d="M14 5 V42 A14 14 0 0 0 28 56 H42 A10 10 0 0 0 42 36 H28 V15" fill="none" stroke="currentColor" stroke-width="7" stroke-linecap="round" stroke-linejoin="round"/><circle cx="40.5" cy="46" r="4" fill="currentColor"/></g><path fill="currentColor" d="M80.05 0V-44.8H89.26V-8.91H110.81V0H80.05ZM128.16 0.77Q123.38 0.77 119.92 -1.31Q116.46 -3.39 114.61 -7.24Q112.76 -11.08 112.76 -16.38Q112.76 -21.64 114.65 -25.48Q116.54 -29.31 120 -31.39Q123.45 -33.47 128.16 -33.47Q132.23 -33.47 135.52 -31.8Q138.81 -30.12 140.75 -26.68Q142.69 -23.24 142.69 -17.97Q142.69 -17.1 142.66 -15.84Q142.62 -14.57 142.45 -13.31H121.38Q121.44 -11.31 122.29 -9.82Q123.13 -8.34 124.64 -7.52Q126.14 -6.71 128.19 -6.71Q130.6 -6.71 132.3 -7.49Q134 -8.28 135.56 -10.07L140.62 -4.94Q138.41 -2.35 135.33 -0.79Q132.26 0.77 128.16 0.77ZM121.47 -20.02H134.24Q134.04 -21.93 133.27 -23.27Q132.5 -24.6 131.17 -25.3Q129.85 -26 127.96 -26Q125.38 -26 123.59 -24.46Q121.8 -22.92 121.47 -20.02ZM148.64 12.99V-32.7H157.43V-30.41Q159.85 -33.47 164.23 -33.47Q168.44 -33.47 171.47 -31.4Q174.51 -29.34 176.15 -25.5Q177.78 -21.66 177.78 -16.33Q177.78 -11.21 176.07 -7.37Q174.35 -3.53 171.28 -1.38Q168.2 0.77 164.12 0.77Q161.97 0.77 160.28 0Q158.6 -0.76 157.43 -2.25V9.04L148.64 12.99ZM162.75 -7.69Q165.73 -7.69 167.35 -9.96Q168.96 -12.24 168.96 -16.33Q168.96 -20.51 167.35 -22.77Q165.74 -25.02 162.75 -25.02Q161 -25.02 159.72 -24.46Q158.44 -23.9 157.43 -22.71V-10.11Q158 -9.03 159.47 -8.36Q160.94 -7.69 162.75 -7.69ZM195.02 0.77Q189.74 0.77 186.71 -2.57Q183.68 -5.91 183.68 -11.78V-32.7H192.47V-15.4Q192.47 -11.26 193.74 -9.48Q195.02 -7.69 197.92 -7.69Q201.03 -7.69 202.46 -9.53Q203.89 -11.37 203.89 -15.27V-32.7H212.68V0H203.89V-3.03Q202.42 -1.17 200.15 -0.2Q197.87 0.77 195.02 0.77ZM231.57 0.77Q227.63 0.77 224.02 -0.91Q220.41 -2.59 218.35 -5.4L224 -10.18Q225.63 -8.5 227.77 -7.49Q229.9 -6.48 231.85 -6.48Q234.11 -6.48 235.33 -7.2Q236.55 -7.92 236.55 -9.25Q236.55 -10.07 235.97 -10.74Q235.39 -11.4 233.84 -12.14Q232.3 -12.88 229.42 -13.93Q223.86 -15.94 221.58 -18.28Q219.31 -20.63 219.31 -24.27Q219.31 -28.39 222.64 -30.93Q225.98 -33.47 231.34 -33.47Q234.98 -33.47 238.08 -32.09Q241.17 -30.71 243.42 -28.08L237.74 -23.4Q234.87 -26.23 231.17 -26.23Q229.41 -26.23 228.31 -25.58Q227.22 -24.94 227.22 -23.91Q227.22 -22.87 228.53 -22.03Q229.85 -21.2 233.5 -20.06Q237.33 -18.91 239.75 -17.4Q242.17 -15.9 243.31 -13.9Q244.44 -11.9 244.44 -9.28Q244.44 -4.58 241.01 -1.9Q237.57 0.77 231.57 0.77Z"/><path fill="currentColor" d="M272 0.4Q269.87 0.4 268.13 -0.34Q266.4 -1.07 265.17 -2.4Q263.94 -3.73 263.35 -5.5L266.86 -6.8Q267.59 -5.22 268.96 -4.22Q270.33 -3.22 272.09 -3.22Q273.97 -3.22 275.1 -4.06Q276.22 -4.89 276.22 -6.48Q276.22 -7.58 275.55 -8.33Q274.89 -9.07 273.78 -9.59Q272.67 -10.12 271.33 -10.58Q270.08 -11.03 268.81 -11.56Q267.53 -12.1 266.48 -12.87Q265.43 -13.64 264.79 -14.78Q264.15 -15.93 264.15 -17.58Q264.15 -19.24 265.05 -20.63Q265.94 -22.02 267.64 -22.86Q269.33 -23.7 271.73 -23.7Q273.71 -23.7 275.22 -23.05Q276.74 -22.41 277.73 -21.31Q278.71 -20.21 279.1 -18.82L275.64 -17.66Q275.19 -18.69 274.19 -19.39Q273.18 -20.09 271.51 -20.09Q269.87 -20.09 268.96 -19.42Q268.04 -18.75 268.04 -17.54Q268.04 -16.68 268.66 -16.09Q269.27 -15.5 270.31 -15.04Q271.34 -14.59 272.6 -14.14Q273.93 -13.66 275.26 -13.08Q276.58 -12.49 277.68 -11.64Q278.78 -10.79 279.45 -9.55Q280.11 -8.3 280.11 -6.51Q280.11 -4.31 279.04 -2.77Q277.97 -1.23 276.14 -0.41Q274.3 0.4 272 0.4ZM286.33 0 294.99 -23.3H298.62L307.3 0H303.22L301.33 -5.18H292.3L290.45 0H286.33ZM293.53 -8.67H300.07L297.52 -15.7Q297.41 -15.99 297.27 -16.38Q297.14 -16.76 297.01 -17.13Q296.88 -17.51 296.81 -17.8Q296.73 -17.51 296.61 -17.13Q296.48 -16.76 296.35 -16.38Q296.21 -15.99 296.11 -15.7L293.53 -8.67ZM323.19 0.4Q320.53 0.4 318.62 -0.61Q316.71 -1.61 315.5 -3.34Q314.29 -5.06 313.71 -7.21Q313.13 -9.37 313.13 -11.65Q313.13 -13.85 313.74 -15.99Q314.34 -18.12 315.57 -19.87Q316.8 -21.61 318.69 -22.65Q320.59 -23.7 323.19 -23.7Q325.4 -23.7 326.91 -23.03Q328.42 -22.37 329.43 -21.31Q330.45 -20.25 331.19 -19.07L327.79 -17.13Q327.01 -18.3 325.95 -19.17Q324.88 -20.05 323.19 -20.05Q321.46 -20.05 320.29 -19.28Q319.12 -18.51 318.43 -17.27Q317.73 -16.02 317.42 -14.54Q317.11 -13.07 317.11 -11.65Q317.11 -10.04 317.46 -8.54Q317.81 -7.04 318.54 -5.85Q319.26 -4.66 320.42 -3.96Q321.58 -3.27 323.19 -3.27Q324.49 -3.27 325.51 -3.84Q326.52 -4.41 327.1 -5.4Q327.68 -6.39 327.68 -7.64V-8.24H323.64V-11.85H331.66V-8.68Q331.66 -5.74 330.54 -3.71Q329.42 -1.69 327.5 -0.64Q325.58 0.4 323.19 0.4ZM338.01 0 346.68 -23.3H350.3L358.98 0H354.9L353.01 -5.18H343.99L342.13 0H338.01ZM345.21 -8.67H351.76L349.2 -15.7Q349.09 -15.99 348.96 -16.38Q348.82 -16.76 348.69 -17.13Q348.57 -17.51 348.49 -17.8Q348.41 -17.51 348.29 -17.13Q348.17 -16.76 348.03 -16.38Q347.9 -15.99 347.79 -15.7L345.21 -8.67Z"/><rect x="261.75" y="6.00" width="98.46" height="4.5" rx="2.25" fill="currentColor"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="-6.00 -64.40 372.21 84.00" width="359" height="81" role="img" aria-label="Lepus saga"><title>Lepus saga</title><g transform="translate(-13.03 -60.26) scale(1.2414)"><path d="M14 5 V42 A14 14 0 0 0 28 56 H42 A10 10 0 0 0 42 36 H28 V15" fill="none" stroke="#e3e9f3" stroke-width="7" stroke-linecap="round" stroke-linejoin="round"/><circle cx="40.5" cy="46" r="4" fill="#f2a30f"/></g><path fill="#e3e9f3" d="M80.05 0V-44.8H89.26V-8.91H110.81V0H80.05ZM128.16 0.77Q123.38 0.77 119.92 -1.31Q116.46 -3.39 114.61 -7.24Q112.76 -11.08 112.76 -16.38Q112.76 -21.64 114.65 -25.48Q116.54 -29.31 120 -31.39Q123.45 -33.47 128.16 -33.47Q132.23 -33.47 135.52 -31.8Q138.81 -30.12 140.75 -26.68Q142.69 -23.24 142.69 -17.97Q142.69 -17.1 142.66 -15.84Q142.62 -14.57 142.45 -13.31H121.38Q121.44 -11.31 122.29 -9.82Q123.13 -8.34 124.64 -7.52Q126.14 -6.71 128.19 -6.71Q130.6 -6.71 132.3 -7.49Q134 -8.28 135.56 -10.07L140.62 -4.94Q138.41 -2.35 135.33 -0.79Q132.26 0.77 128.16 0.77ZM121.47 -20.02H134.24Q134.04 -21.93 133.27 -23.27Q132.5 -24.6 131.17 -25.3Q129.85 -26 127.96 -26Q125.38 -26 123.59 -24.46Q121.8 -22.92 121.47 -20.02ZM148.64 12.99V-32.7H157.43V-30.41Q159.85 -33.47 164.23 -33.47Q168.44 -33.47 171.47 -31.4Q174.51 -29.34 176.15 -25.5Q177.78 -21.66 177.78 -16.33Q177.78 -11.21 176.07 -7.37Q174.35 -3.53 171.28 -1.38Q168.2 0.77 164.12 0.77Q161.97 0.77 160.28 0Q158.6 -0.76 157.43 -2.25V9.04L148.64 12.99ZM162.75 -7.69Q165.73 -7.69 167.35 -9.96Q168.96 -12.24 168.96 -16.33Q168.96 -20.51 167.35 -22.77Q165.74 -25.02 162.75 -25.02Q161 -25.02 159.72 -24.46Q158.44 -23.9 157.43 -22.71V-10.11Q158 -9.03 159.47 -8.36Q160.94 -7.69 162.75 -7.69ZM195.02 0.77Q189.74 0.77 186.71 -2.57Q183.68 -5.91 183.68 -11.78V-32.7H192.47V-15.4Q192.47 -11.26 193.74 -9.48Q195.02 -7.69 197.92 -7.69Q201.03 -7.69 202.46 -9.53Q203.89 -11.37 203.89 -15.27V-32.7H212.68V0H203.89V-3.03Q202.42 -1.17 200.15 -0.2Q197.87 0.77 195.02 0.77ZM231.57 0.77Q227.63 0.77 224.02 -0.91Q220.41 -2.59 218.35 -5.4L224 -10.18Q225.63 -8.5 227.77 -7.49Q229.9 -6.48 231.85 -6.48Q234.11 -6.48 235.33 -7.2Q236.55 -7.92 236.55 -9.25Q236.55 -10.07 235.97 -10.74Q235.39 -11.4 233.84 -12.14Q232.3 -12.88 229.42 -13.93Q223.86 -15.94 221.58 -18.28Q219.31 -20.63 219.31 -24.27Q219.31 -28.39 222.64 -30.93Q225.98 -33.47 231.34 -33.47Q234.98 -33.47 238.08 -32.09Q241.17 -30.71 243.42 -28.08L237.74 -23.4Q234.87 -26.23 231.17 -26.23Q229.41 -26.23 228.31 -25.58Q227.22 -24.94 227.22 -23.91Q227.22 -22.87 228.53 -22.03Q229.85 -21.2 233.5 -20.06Q237.33 -18.91 239.75 -17.4Q242.17 -15.9 243.31 -13.9Q244.44 -11.9 244.44 -9.28Q244.44 -4.58 241.01 -1.9Q237.57 0.77 231.57 0.77Z"/><path fill="#e3e9f3" d="M272 0.4Q269.87 0.4 268.13 -0.34Q266.4 -1.07 265.17 -2.4Q263.94 -3.73 263.35 -5.5L266.86 -6.8Q267.59 -5.22 268.96 -4.22Q270.33 -3.22 272.09 -3.22Q273.97 -3.22 275.1 -4.06Q276.22 -4.89 276.22 -6.48Q276.22 -7.58 275.55 -8.33Q274.89 -9.07 273.78 -9.59Q272.67 -10.12 271.33 -10.58Q270.08 -11.03 268.81 -11.56Q267.53 -12.1 266.48 -12.87Q265.43 -13.64 264.79 -14.78Q264.15 -15.93 264.15 -17.58Q264.15 -19.24 265.05 -20.63Q265.94 -22.02 267.64 -22.86Q269.33 -23.7 271.73 -23.7Q273.71 -23.7 275.22 -23.05Q276.74 -22.41 277.73 -21.31Q278.71 -20.21 279.1 -18.82L275.64 -17.66Q275.19 -18.69 274.19 -19.39Q273.18 -20.09 271.51 -20.09Q269.87 -20.09 268.96 -19.42Q268.04 -18.75 268.04 -17.54Q268.04 -16.68 268.66 -16.09Q269.27 -15.5 270.31 -15.04Q271.34 -14.59 272.6 -14.14Q273.93 -13.66 275.26 -13.08Q276.58 -12.49 277.68 -11.64Q278.78 -10.79 279.45 -9.55Q280.11 -8.3 280.11 -6.51Q280.11 -4.31 279.04 -2.77Q277.97 -1.23 276.14 -0.41Q274.3 0.4 272 0.4ZM286.33 0 294.99 -23.3H298.62L307.3 0H303.22L301.33 -5.18H292.3L290.45 0H286.33ZM293.53 -8.67H300.07L297.52 -15.7Q297.41 -15.99 297.27 -16.38Q297.14 -16.76 297.01 -17.13Q296.88 -17.51 296.81 -17.8Q296.73 -17.51 296.61 -17.13Q296.48 -16.76 296.35 -16.38Q296.21 -15.99 296.11 -15.7L293.53 -8.67ZM323.19 0.4Q320.53 0.4 318.62 -0.61Q316.71 -1.61 315.5 -3.34Q314.29 -5.06 313.71 -7.21Q313.13 -9.37 313.13 -11.65Q313.13 -13.85 313.74 -15.99Q314.34 -18.12 315.57 -19.87Q316.8 -21.61 318.69 -22.65Q320.59 -23.7 323.19 -23.7Q325.4 -23.7 326.91 -23.03Q328.42 -22.37 329.43 -21.31Q330.45 -20.25 331.19 -19.07L327.79 -17.13Q327.01 -18.3 325.95 -19.17Q324.88 -20.05 323.19 -20.05Q321.46 -20.05 320.29 -19.28Q319.12 -18.51 318.43 -17.27Q317.73 -16.02 317.42 -14.54Q317.11 -13.07 317.11 -11.65Q317.11 -10.04 317.46 -8.54Q317.81 -7.04 318.54 -5.85Q319.26 -4.66 320.42 -3.96Q321.58 -3.27 323.19 -3.27Q324.49 -3.27 325.51 -3.84Q326.52 -4.41 327.1 -5.4Q327.68 -6.39 327.68 -7.64V-8.24H323.64V-11.85H331.66V-8.68Q331.66 -5.74 330.54 -3.71Q329.42 -1.69 327.5 -0.64Q325.58 0.4 323.19 0.4ZM338.01 0 346.68 -23.3H350.3L358.98 0H354.9L353.01 -5.18H343.99L342.13 0H338.01ZM345.21 -8.67H351.76L349.2 -15.7Q349.09 -15.99 348.96 -16.38Q348.82 -16.76 348.69 -17.13Q348.57 -17.51 348.49 -17.8Q348.41 -17.51 348.29 -17.13Q348.17 -16.76 348.03 -16.38Q347.9 -15.99 347.79 -15.7L345.21 -8.67Z"/><rect x="261.75" y="6.00" width="98.46" height="4.5" rx="2.25" fill="#f2a30f"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="-6.00 -64.40 372.21 84.00" width="359" height="81" role="img" aria-label="Lepus saga"><title>Lepus saga</title><g transform="translate(-13.03 -60.26) scale(1.2414)"><path d="M14 5 V42 A14 14 0 0 0 28 56 H42 A10 10 0 0 0 42 36 H28 V15" fill="none" stroke="#1a2233" stroke-width="7" stroke-linecap="round" stroke-linejoin="round"/><circle cx="40.5" cy="46" r="4" fill="#f2a30f"/></g><path fill="#1a2233" d="M80.05 0V-44.8H89.26V-8.91H110.81V0H80.05ZM128.16 0.77Q123.38 0.77 119.92 -1.31Q116.46 -3.39 114.61 -7.24Q112.76 -11.08 112.76 -16.38Q112.76 -21.64 114.65 -25.48Q116.54 -29.31 120 -31.39Q123.45 -33.47 128.16 -33.47Q132.23 -33.47 135.52 -31.8Q138.81 -30.12 140.75 -26.68Q142.69 -23.24 142.69 -17.97Q142.69 -17.1 142.66 -15.84Q142.62 -14.57 142.45 -13.31H121.38Q121.44 -11.31 122.29 -9.82Q123.13 -8.34 124.64 -7.52Q126.14 -6.71 128.19 -6.71Q130.6 -6.71 132.3 -7.49Q134 -8.28 135.56 -10.07L140.62 -4.94Q138.41 -2.35 135.33 -0.79Q132.26 0.77 128.16 0.77ZM121.47 -20.02H134.24Q134.04 -21.93 133.27 -23.27Q132.5 -24.6 131.17 -25.3Q129.85 -26 127.96 -26Q125.38 -26 123.59 -24.46Q121.8 -22.92 121.47 -20.02ZM148.64 12.99V-32.7H157.43V-30.41Q159.85 -33.47 164.23 -33.47Q168.44 -33.47 171.47 -31.4Q174.51 -29.34 176.15 -25.5Q177.78 -21.66 177.78 -16.33Q177.78 -11.21 176.07 -7.37Q174.35 -3.53 171.28 -1.38Q168.2 0.77 164.12 0.77Q161.97 0.77 160.28 0Q158.6 -0.76 157.43 -2.25V9.04L148.64 12.99ZM162.75 -7.69Q165.73 -7.69 167.35 -9.96Q168.96 -12.24 168.96 -16.33Q168.96 -20.51 167.35 -22.77Q165.74 -25.02 162.75 -25.02Q161 -25.02 159.72 -24.46Q158.44 -23.9 157.43 -22.71V-10.11Q158 -9.03 159.47 -8.36Q160.94 -7.69 162.75 -7.69ZM195.02 0.77Q189.74 0.77 186.71 -2.57Q183.68 -5.91 183.68 -11.78V-32.7H192.47V-15.4Q192.47 -11.26 193.74 -9.48Q195.02 -7.69 197.92 -7.69Q201.03 -7.69 202.46 -9.53Q203.89 -11.37 203.89 -15.27V-32.7H212.68V0H203.89V-3.03Q202.42 -1.17 200.15 -0.2Q197.87 0.77 195.02 0.77ZM231.57 0.77Q227.63 0.77 224.02 -0.91Q220.41 -2.59 218.35 -5.4L224 -10.18Q225.63 -8.5 227.77 -7.49Q229.9 -6.48 231.85 -6.48Q234.11 -6.48 235.33 -7.2Q236.55 -7.92 236.55 -9.25Q236.55 -10.07 235.97 -10.74Q235.39 -11.4 233.84 -12.14Q232.3 -12.88 229.42 -13.93Q223.86 -15.94 221.58 -18.28Q219.31 -20.63 219.31 -24.27Q219.31 -28.39 222.64 -30.93Q225.98 -33.47 231.34 -33.47Q234.98 -33.47 238.08 -32.09Q241.17 -30.71 243.42 -28.08L237.74 -23.4Q234.87 -26.23 231.17 -26.23Q229.41 -26.23 228.31 -25.58Q227.22 -24.94 227.22 -23.91Q227.22 -22.87 228.53 -22.03Q229.85 -21.2 233.5 -20.06Q237.33 -18.91 239.75 -17.4Q242.17 -15.9 243.31 -13.9Q244.44 -11.9 244.44 -9.28Q244.44 -4.58 241.01 -1.9Q237.57 0.77 231.57 0.77Z"/><path fill="#1a2233" d="M272 0.4Q269.87 0.4 268.13 -0.34Q266.4 -1.07 265.17 -2.4Q263.94 -3.73 263.35 -5.5L266.86 -6.8Q267.59 -5.22 268.96 -4.22Q270.33 -3.22 272.09 -3.22Q273.97 -3.22 275.1 -4.06Q276.22 -4.89 276.22 -6.48Q276.22 -7.58 275.55 -8.33Q274.89 -9.07 273.78 -9.59Q272.67 -10.12 271.33 -10.58Q270.08 -11.03 268.81 -11.56Q267.53 -12.1 266.48 -12.87Q265.43 -13.64 264.79 -14.78Q264.15 -15.93 264.15 -17.58Q264.15 -19.24 265.05 -20.63Q265.94 -22.02 267.64 -22.86Q269.33 -23.7 271.73 -23.7Q273.71 -23.7 275.22 -23.05Q276.74 -22.41 277.73 -21.31Q278.71 -20.21 279.1 -18.82L275.64 -17.66Q275.19 -18.69 274.19 -19.39Q273.18 -20.09 271.51 -20.09Q269.87 -20.09 268.96 -19.42Q268.04 -18.75 268.04 -17.54Q268.04 -16.68 268.66 -16.09Q269.27 -15.5 270.31 -15.04Q271.34 -14.59 272.6 -14.14Q273.93 -13.66 275.26 -13.08Q276.58 -12.49 277.68 -11.64Q278.78 -10.79 279.45 -9.55Q280.11 -8.3 280.11 -6.51Q280.11 -4.31 279.04 -2.77Q277.97 -1.23 276.14 -0.41Q274.3 0.4 272 0.4ZM286.33 0 294.99 -23.3H298.62L307.3 0H303.22L301.33 -5.18H292.3L290.45 0H286.33ZM293.53 -8.67H300.07L297.52 -15.7Q297.41 -15.99 297.27 -16.38Q297.14 -16.76 297.01 -17.13Q296.88 -17.51 296.81 -17.8Q296.73 -17.51 296.61 -17.13Q296.48 -16.76 296.35 -16.38Q296.21 -15.99 296.11 -15.7L293.53 -8.67ZM323.19 0.4Q320.53 0.4 318.62 -0.61Q316.71 -1.61 315.5 -3.34Q314.29 -5.06 313.71 -7.21Q313.13 -9.37 313.13 -11.65Q313.13 -13.85 313.74 -15.99Q314.34 -18.12 315.57 -19.87Q316.8 -21.61 318.69 -22.65Q320.59 -23.7 323.19 -23.7Q325.4 -23.7 326.91 -23.03Q328.42 -22.37 329.43 -21.31Q330.45 -20.25 331.19 -19.07L327.79 -17.13Q327.01 -18.3 325.95 -19.17Q324.88 -20.05 323.19 -20.05Q321.46 -20.05 320.29 -19.28Q319.12 -18.51 318.43 -17.27Q317.73 -16.02 317.42 -14.54Q317.11 -13.07 317.11 -11.65Q317.11 -10.04 317.46 -8.54Q317.81 -7.04 318.54 -5.85Q319.26 -4.66 320.42 -3.96Q321.58 -3.27 323.19 -3.27Q324.49 -3.27 325.51 -3.84Q326.52 -4.41 327.1 -5.4Q327.68 -6.39 327.68 -7.64V-8.24H323.64V-11.85H331.66V-8.68Q331.66 -5.74 330.54 -3.71Q329.42 -1.69 327.5 -0.64Q325.58 0.4 323.19 0.4ZM338.01 0 346.68 -23.3H350.3L358.98 0H354.9L353.01 -5.18H343.99L342.13 0H338.01ZM345.21 -8.67H351.76L349.2 -15.7Q349.09 -15.99 348.96 -16.38Q348.82 -16.76 348.69 -17.13Q348.57 -17.51 348.49 -17.8Q348.41 -17.51 348.29 -17.13Q348.17 -16.76 348.03 -16.38Q347.9 -15.99 347.79 -15.7L345.21 -8.67Z"/><rect x="261.75" y="6.00" width="98.46" height="4.5" rx="2.25" fill="#f2a30f"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="-6.00 -64.40 372.21 84.00" width="359" height="81" role="img" aria-label="Lepus saga"><title>Lepus saga</title><style>.i{stroke:#1a2233}.f{fill:#1a2233}@media (prefers-color-scheme:dark){.i{stroke:#e3e9f3}.f{fill:#e3e9f3}}</style><g transform="translate(-13.03 -60.26) scale(1.2414)"><path class="i" d="M14 5 V42 A14 14 0 0 0 28 56 H42 A10 10 0 0 0 42 36 H28 V15" fill="none" stroke-width="7" stroke-linecap="round" stroke-linejoin="round"/><circle cx="40.5" cy="46" r="4" fill="#f2a30f"/></g><path class="f" d="M80.05 0V-44.8H89.26V-8.91H110.81V0H80.05ZM128.16 0.77Q123.38 0.77 119.92 -1.31Q116.46 -3.39 114.61 -7.24Q112.76 -11.08 112.76 -16.38Q112.76 -21.64 114.65 -25.48Q116.54 -29.31 120 -31.39Q123.45 -33.47 128.16 -33.47Q132.23 -33.47 135.52 -31.8Q138.81 -30.12 140.75 -26.68Q142.69 -23.24 142.69 -17.97Q142.69 -17.1 142.66 -15.84Q142.62 -14.57 142.45 -13.31H121.38Q121.44 -11.31 122.29 -9.82Q123.13 -8.34 124.64 -7.52Q126.14 -6.71 128.19 -6.71Q130.6 -6.71 132.3 -7.49Q134 -8.28 135.56 -10.07L140.62 -4.94Q138.41 -2.35 135.33 -0.79Q132.26 0.77 128.16 0.77ZM121.47 -20.02H134.24Q134.04 -21.93 133.27 -23.27Q132.5 -24.6 131.17 -25.3Q129.85 -26 127.96 -26Q125.38 -26 123.59 -24.46Q121.8 -22.92 121.47 -20.02ZM148.64 12.99V-32.7H157.43V-30.41Q159.85 -33.47 164.23 -33.47Q168.44 -33.47 171.47 -31.4Q174.51 -29.34 176.15 -25.5Q177.78 -21.66 177.78 -16.33Q177.78 -11.21 176.07 -7.37Q174.35 -3.53 171.28 -1.38Q168.2 0.77 164.12 0.77Q161.97 0.77 160.28 0Q158.6 -0.76 157.43 -2.25V9.04L148.64 12.99ZM162.75 -7.69Q165.73 -7.69 167.35 -9.96Q168.96 -12.24 168.96 -16.33Q168.96 -20.51 167.35 -22.77Q165.74 -25.02 162.75 -25.02Q161 -25.02 159.72 -24.46Q158.44 -23.9 157.43 -22.71V-10.11Q158 -9.03 159.47 -8.36Q160.94 -7.69 162.75 -7.69ZM195.02 0.77Q189.74 0.77 186.71 -2.57Q183.68 -5.91 183.68 -11.78V-32.7H192.47V-15.4Q192.47 -11.26 193.74 -9.48Q195.02 -7.69 197.92 -7.69Q201.03 -7.69 202.46 -9.53Q203.89 -11.37 203.89 -15.27V-32.7H212.68V0H203.89V-3.03Q202.42 -1.17 200.15 -0.2Q197.87 0.77 195.02 0.77ZM231.57 0.77Q227.63 0.77 224.02 -0.91Q220.41 -2.59 218.35 -5.4L224 -10.18Q225.63 -8.5 227.77 -7.49Q229.9 -6.48 231.85 -6.48Q234.11 -6.48 235.33 -7.2Q236.55 -7.92 236.55 -9.25Q236.55 -10.07 235.97 -10.74Q235.39 -11.4 233.84 -12.14Q232.3 -12.88 229.42 -13.93Q223.86 -15.94 221.58 -18.28Q219.31 -20.63 219.31 -24.27Q219.31 -28.39 222.64 -30.93Q225.98 -33.47 231.34 -33.47Q234.98 -33.47 238.08 -32.09Q241.17 -30.71 243.42 -28.08L237.74 -23.4Q234.87 -26.23 231.17 -26.23Q229.41 -26.23 228.31 -25.58Q227.22 -24.94 227.22 -23.91Q227.22 -22.87 228.53 -22.03Q229.85 -21.2 233.5 -20.06Q237.33 -18.91 239.75 -17.4Q242.17 -15.9 243.31 -13.9Q244.44 -11.9 244.44 -9.28Q244.44 -4.58 241.01 -1.9Q237.57 0.77 231.57 0.77Z"/><path class="f" d="M272 0.4Q269.87 0.4 268.13 -0.34Q266.4 -1.07 265.17 -2.4Q263.94 -3.73 263.35 -5.5L266.86 -6.8Q267.59 -5.22 268.96 -4.22Q270.33 -3.22 272.09 -3.22Q273.97 -3.22 275.1 -4.06Q276.22 -4.89 276.22 -6.48Q276.22 -7.58 275.55 -8.33Q274.89 -9.07 273.78 -9.59Q272.67 -10.12 271.33 -10.58Q270.08 -11.03 268.81 -11.56Q267.53 -12.1 266.48 -12.87Q265.43 -13.64 264.79 -14.78Q264.15 -15.93 264.15 -17.58Q264.15 -19.24 265.05 -20.63Q265.94 -22.02 267.64 -22.86Q269.33 -23.7 271.73 -23.7Q273.71 -23.7 275.22 -23.05Q276.74 -22.41 277.73 -21.31Q278.71 -20.21 279.1 -18.82L275.64 -17.66Q275.19 -18.69 274.19 -19.39Q273.18 -20.09 271.51 -20.09Q269.87 -20.09 268.96 -19.42Q268.04 -18.75 268.04 -17.54Q268.04 -16.68 268.66 -16.09Q269.27 -15.5 270.31 -15.04Q271.34 -14.59 272.6 -14.14Q273.93 -13.66 275.26 -13.08Q276.58 -12.49 277.68 -11.64Q278.78 -10.79 279.45 -9.55Q280.11 -8.3 280.11 -6.51Q280.11 -4.31 279.04 -2.77Q277.97 -1.23 276.14 -0.41Q274.3 0.4 272 0.4ZM286.33 0 294.99 -23.3H298.62L307.3 0H303.22L301.33 -5.18H292.3L290.45 0H286.33ZM293.53 -8.67H300.07L297.52 -15.7Q297.41 -15.99 297.27 -16.38Q297.14 -16.76 297.01 -17.13Q296.88 -17.51 296.81 -17.8Q296.73 -17.51 296.61 -17.13Q296.48 -16.76 296.35 -16.38Q296.21 -15.99 296.11 -15.7L293.53 -8.67ZM323.19 0.4Q320.53 0.4 318.62 -0.61Q316.71 -1.61 315.5 -3.34Q314.29 -5.06 313.71 -7.21Q313.13 -9.37 313.13 -11.65Q313.13 -13.85 313.74 -15.99Q314.34 -18.12 315.57 -19.87Q316.8 -21.61 318.69 -22.65Q320.59 -23.7 323.19 -23.7Q325.4 -23.7 326.91 -23.03Q328.42 -22.37 329.43 -21.31Q330.45 -20.25 331.19 -19.07L327.79 -17.13Q327.01 -18.3 325.95 -19.17Q324.88 -20.05 323.19 -20.05Q321.46 -20.05 320.29 -19.28Q319.12 -18.51 318.43 -17.27Q317.73 -16.02 317.42 -14.54Q317.11 -13.07 317.11 -11.65Q317.11 -10.04 317.46 -8.54Q317.81 -7.04 318.54 -5.85Q319.26 -4.66 320.42 -3.96Q321.58 -3.27 323.19 -3.27Q324.49 -3.27 325.51 -3.84Q326.52 -4.41 327.1 -5.4Q327.68 -6.39 327.68 -7.64V-8.24H323.64V-11.85H331.66V-8.68Q331.66 -5.74 330.54 -3.71Q329.42 -1.69 327.5 -0.64Q325.58 0.4 323.19 0.4ZM338.01 0 346.68 -23.3H350.3L358.98 0H354.9L353.01 -5.18H343.99L342.13 0H338.01ZM345.21 -8.67H351.76L349.2 -15.7Q349.09 -15.99 348.96 -16.38Q348.82 -16.76 348.69 -17.13Q348.57 -17.51 348.49 -17.8Q348.41 -17.51 348.29 -17.13Q348.17 -16.76 348.03 -16.38Q347.9 -15.99 347.79 -15.7L345.21 -8.67Z"/><rect x="261.75" y="6.00" width="98.46" height="4.5" rx="2.25" fill="#f2a30f"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="-6.00 -64.40 259.67 84.00" width="278" height="90" role="img" aria-label="Lepus"><title>Lepus</title><style>.i{stroke:#1a2233}.f{fill:#1a2233}@media (prefers-color-scheme:dark){.i{stroke:#e3e9f3}.f{fill:#e3e9f3}}</style><g transform="translate(-13.03 -60.26) scale(1.2414)"><path class="i" d="M14 5 V42 A14 14 0 0 0 28 56 H42 A10 10 0 0 0 42 36 H28 V15" fill="none" stroke-width="7" stroke-linecap="round" stroke-linejoin="round"/><circle cx="40.5" cy="46" r="4" fill="#f2a30f"/></g><path class="f" d="M80.05 0V-44.8H89.26V-8.91H110.81V0H80.05ZM128.16 0.77Q123.38 0.77 119.92 -1.31Q116.46 -3.39 114.61 -7.24Q112.76 -11.08 112.76 -16.38Q112.76 -21.64 114.65 -25.48Q116.54 -29.31 120 -31.39Q123.45 -33.47 128.16 -33.47Q132.23 -33.47 135.52 -31.8Q138.81 -30.12 140.75 -26.68Q142.69 -23.24 142.69 -17.97Q142.69 -17.1 142.66 -15.84Q142.62 -14.57 142.45 -13.31H121.38Q121.44 -11.31 122.29 -9.82Q123.13 -8.34 124.64 -7.52Q126.14 -6.71 128.19 -6.71Q130.6 -6.71 132.3 -7.49Q134 -8.28 135.56 -10.07L140.62 -4.94Q138.41 -2.35 135.33 -0.79Q132.26 0.77 128.16 0.77ZM121.47 -20.02H134.24Q134.04 -21.93 133.27 -23.27Q132.5 -24.6 131.17 -25.3Q129.85 -26 127.96 -26Q125.38 -26 123.59 -24.46Q121.8 -22.92 121.47 -20.02ZM148.64 12.99V-32.7H157.43V-30.41Q159.85 -33.47 164.23 -33.47Q168.44 -33.47 171.47 -31.4Q174.51 -29.34 176.15 -25.5Q177.78 -21.66 177.78 -16.33Q177.78 -11.21 176.07 -7.37Q174.35 -3.53 171.28 -1.38Q168.2 0.77 164.12 0.77Q161.97 0.77 160.28 0Q158.6 -0.76 157.43 -2.25V9.04L148.64 12.99ZM162.75 -7.69Q165.73 -7.69 167.35 -9.96Q168.96 -12.24 168.96 -16.33Q168.96 -20.51 167.35 -22.77Q165.74 -25.02 162.75 -25.02Q161 -25.02 159.72 -24.46Q158.44 -23.9 157.43 -22.71V-10.11Q158 -9.03 159.47 -8.36Q160.94 -7.69 162.75 -7.69ZM195.02 0.77Q189.74 0.77 186.71 -2.57Q183.68 -5.91 183.68 -11.78V-32.7H192.47V-15.4Q192.47 -11.26 193.74 -9.48Q195.02 -7.69 197.92 -7.69Q201.03 -7.69 202.46 -9.53Q203.89 -11.37 203.89 -15.27V-32.7H212.68V0H203.89V-3.03Q202.42 -1.17 200.15 -0.2Q197.87 0.77 195.02 0.77ZM231.57 0.77Q227.63 0.77 224.02 -0.91Q220.41 -2.59 218.35 -5.4L224 -10.18Q225.63 -8.5 227.77 -7.49Q229.9 -6.48 231.85 -6.48Q234.11 -6.48 235.33 -7.2Q236.55 -7.92 236.55 -9.25Q236.55 -10.07 235.97 -10.74Q235.39 -11.4 233.84 -12.14Q232.3 -12.88 229.42 -13.93Q223.86 -15.94 221.58 -18.28Q219.31 -20.63 219.31 -24.27Q219.31 -28.39 222.64 -30.93Q225.98 -33.47 231.34 -33.47Q234.98 -33.47 238.08 -32.09Q241.17 -30.71 243.42 -28.08L237.74 -23.4Q234.87 -26.23 231.17 -26.23Q229.41 -26.23 228.31 -25.58Q227.22 -24.94 227.22 -23.91Q227.22 -22.87 228.53 -22.03Q229.85 -21.2 233.5 -20.06Q237.33 -18.91 239.75 -17.4Q242.17 -15.9 243.31 -13.9Q244.44 -11.9 244.44 -9.28Q244.44 -4.58 241.01 -1.9Q237.57 0.77 231.57 0.77Z"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="1 0 64 64" role="img" aria-label="Lepus"><title>Lepus</title><path d="M14 5 V42 A14 14 0 0 0 28 56 H42 A10 10 0 0 0 42 36 H28 V15" fill="none" stroke="currentColor" stroke-width="7" stroke-linecap="round" stroke-linejoin="round"/><circle cx="40.5" cy="46" r="4" fill="currentColor"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="1 0 64 64" role="img" aria-label="Lepus"><title>Lepus</title><path d="M14 5 V42 A14 14 0 0 0 28 56 H42 A10 10 0 0 0 42 36 H28 V15" fill="none" stroke="#e3e9f3" stroke-width="7" stroke-linecap="round" stroke-linejoin="round"/><circle cx="40.5" cy="46" r="4" fill="#f2a30f"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="1 0 64 64" role="img" aria-label="Lepus"><title>Lepus</title><path d="M14 5 V42 A14 14 0 0 0 28 56 H42 A10 10 0 0 0 42 36 H28 V15" fill="none" stroke="#1a2233" stroke-width="7" stroke-linecap="round" stroke-linejoin="round"/><circle cx="40.5" cy="46" r="4" fill="#f2a30f"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" role="img" aria-label="Lepus"><title>Lepus</title><path d="M12 6 V40 A16 16 0 0 0 28 56 H42 A10 10 0 0 0 42 36 H28 V18" fill="none" stroke="currentColor" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/><circle cx="40" cy="46" r="5" fill="currentColor"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" role="img" aria-label="Lepus"><title>Lepus</title><path d="M12 6 V40 A16 16 0 0 0 28 56 H42 A10 10 0 0 0 42 36 H28 V18" fill="none" stroke="#e3e9f3" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/><circle cx="40" cy="46" r="5" fill="#f2a30f"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" role="img" aria-label="Lepus"><title>Lepus</title><path d="M12 6 V40 A16 16 0 0 0 28 56 H42 A10 10 0 0 0 42 36 H28 V18" fill="none" stroke="#1a2233" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/><circle cx="40" cy="46" r="5" fill="#f2a30f"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" role="img" aria-label="Lepus"><title>Lepus</title><style>.i{stroke:#1a2233}.f{fill:#1a2233}@media (prefers-color-scheme:dark){.i{stroke:#e3e9f3}.f{fill:#e3e9f3}}</style><path class="i" d="M12 6 V40 A16 16 0 0 0 28 56 H42 A10 10 0 0 0 42 36 H28 V18" fill="none" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/><circle cx="40" cy="46" r="5" fill="#f2a30f"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="1 0 64 64" role="img" aria-label="Lepus"><title>Lepus</title><style>.i{stroke:#1a2233}.f{fill:#1a2233}@media (prefers-color-scheme:dark){.i{stroke:#e3e9f3}.f{fill:#e3e9f3}}</style><path class="i" d="M14 5 V42 A14 14 0 0 0 28 56 H42 A10 10 0 0 0 42 36 H28 V15" fill="none" stroke-width="7" stroke-linecap="round" stroke-linejoin="round"/><circle cx="40.5" cy="46" r="4" fill="#f2a30f"/></svg>
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lepus
4
+ module Saga
5
+ class Configuration
6
+ # Topic exchange carrying step messages. Queues are named after it.
7
+ attr_accessor :exchange_name
8
+
9
+ # How many times resume_stuck re-publishes an execution that is not moving
10
+ # before it gives up on it. Without a ceiling a wedged execution is
11
+ # re-published every few minutes forever and stays "running": it never
12
+ # reaches a failed state, so nothing watching for failures ever sees it.
13
+ attr_accessor :max_resumes
14
+
15
+ # Ready messages above which a partition's queue counts as backlogged.
16
+ # A busy but healthy queue hands messages to consumers as they arrive and
17
+ # rarely holds more than a few ready ones.
18
+ attr_accessor :backlog_threshold
19
+
20
+ # How long an execution may stall behind a backlog before resume_stuck
21
+ # re-publishes it anyway (once), in case its message was lost meanwhile.
22
+ attr_accessor :backlog_patience
23
+
24
+ # A running attempt older than this is considered abandoned (worker died
25
+ # or lost the message) and is closed as failed before a new one opens.
26
+ attr_accessor :stale_running_attempt_after
27
+
28
+ # Where executions and step attempts live (see Lepus::Saga::Stores::Base).
29
+ attr_reader :store
30
+
31
+ def initialize
32
+ @exchange_name = "lepus.saga"
33
+ @max_resumes = 5
34
+ @backlog_threshold = 100
35
+ @backlog_patience = 2 * 3600
36
+ @stale_running_attempt_after = 5 * 60
37
+ @store = nil
38
+ end
39
+
40
+ # Accepts a store instance, a store class, or the name of a store
41
+ # (`:memory`, `:active_record`, ...) which is required from
42
+ # "lepus/saga/stores/<name>" and resolved to Lepus::Saga::Stores::<Name>.
43
+ def store=(value)
44
+ @store = Stores.build(value)
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lepus
4
+ module Saga
5
+ # Signal exceptions raised by step code to control the execution flow.
6
+ # They are caught by the Executor and never bubble out of it.
7
+ module Control
8
+ class Signal < StandardError
9
+ attr_reader :reason
10
+
11
+ def initialize(reason = nil)
12
+ @reason = reason
13
+ super(reason || self.class.name.split("::").last.downcase)
14
+ end
15
+ end
16
+
17
+ # Skip the current step (success-equivalent) and continue with the next.
18
+ class Skip < Signal; end
19
+
20
+ # Finish the whole execution successfully right now (fast-path).
21
+ class Complete < Signal; end
22
+
23
+ # Permanent business failure: no retries, compensate immediately.
24
+ class Fail < Signal; end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lepus
4
+ module Saga
5
+ # Base class for declarative saga definitions.
6
+ #
7
+ # class Orders::CheckoutSaga < Lepus::Saga::Definition
8
+ # saga_name "orders.checkout"
9
+ #
10
+ # step :reserve_stock, compensate: :release_stock, retry: { attempts: 5 }
11
+ # step :persist_local
12
+ #
13
+ # def reserve_stock
14
+ # context["reservation_id"] = ...
15
+ # end
16
+ # end
17
+ #
18
+ # Step methods run with `execution`, `context` and `resource` available.
19
+ # Mutations to `context` are persisted when the step succeeds. Steps may
20
+ # run more than once (at-least-once delivery) and must be idempotent.
21
+ class Definition
22
+ class << self
23
+ def inherited(subclass)
24
+ super
25
+ subclass.instance_variable_set(:@steps, [])
26
+ end
27
+
28
+ def saga_name(value = nil)
29
+ if value
30
+ @saga_name = value.to_s
31
+ Lepus::Saga.register(@saga_name, self)
32
+ end
33
+ @saga_name
34
+ end
35
+
36
+ def partition(value = nil)
37
+ @partition = value.to_s if value
38
+ @partition || ((superclass < Definition) ? superclass.partition : "default")
39
+ end
40
+
41
+ def step(name, compensate: nil, **options)
42
+ steps << Step.new(
43
+ name: name.to_s,
44
+ compensate: compensate&.to_s,
45
+ retry_policy: RetryPolicy.build(options[:retry])
46
+ )
47
+ end
48
+
49
+ def steps
50
+ @steps ||= []
51
+ end
52
+
53
+ def find_step!(name)
54
+ steps.find { |step| step.name == name.to_s } ||
55
+ raise(UnknownStepError, "Unknown step #{name.inspect} in #{saga_name}")
56
+ end
57
+
58
+ def step_index(name)
59
+ steps.index { |step| step.name == name.to_s }
60
+ end
61
+
62
+ # Starts a new execution and publishes its first step message.
63
+ # Call it after the local transaction that created/changed the
64
+ # resource has committed. `partition` overrides the definition's
65
+ # partition for this execution only.
66
+ def start(resource:, context: {}, correlation_id: nil, partition: nil)
67
+ raise ArgumentError, "#{name} has no saga_name" if saga_name.to_s.strip.empty?
68
+ raise ArgumentError, "#{name} has no steps" if steps.empty?
69
+
70
+ type, id = resource_reference(resource)
71
+ now = Time.now.utc
72
+ execution = Lepus::Saga.store.create_execution(
73
+ saga_name: saga_name,
74
+ resource_type: type,
75
+ resource_id: id,
76
+ current_step: steps.first.name,
77
+ context: context.transform_keys(&:to_s),
78
+ correlation_id: correlation_id,
79
+ partition: partition,
80
+ started_at: now,
81
+ last_progress_at: now
82
+ )
83
+ Instrumentation.saga_event("saga.started", execution)
84
+ StepProducer.publish_step(execution)
85
+ execution
86
+ end
87
+
88
+ private
89
+
90
+ def resource_reference(resource)
91
+ case resource
92
+ when Hash then [resource.fetch(:type).to_s, resource.fetch(:id).to_s]
93
+ else [resource.class.name, Array(resource.id).first.to_s]
94
+ end
95
+ end
96
+ end
97
+
98
+ attr_reader :execution, :step_attempt
99
+
100
+ def initialize(execution, step_attempt: nil)
101
+ @execution = execution
102
+ @step_attempt = step_attempt
103
+ end
104
+
105
+ def context = execution.context
106
+
107
+ def resource
108
+ @resource ||= find_resource
109
+ end
110
+
111
+ # Override for resources that need a custom lookup (composite keys etc).
112
+ def find_resource
113
+ Lepus::Primitive::String.new(execution.resource_type).constantize.find(execution.resource_id)
114
+ end
115
+
116
+ def complete!(reason = nil) = raise(Control::Complete, reason)
117
+
118
+ def skip!(reason = nil) = raise(Control::Skip, reason)
119
+
120
+ def fail!(reason) = raise(Control::Fail, reason)
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lepus
4
+ module Saga
5
+ # What the engine expects of an execution record, whatever stores it.
6
+ # Adapters include it into their execution class.
7
+ module ExecutionBehaviour
8
+ ATTRIBUTES = %i[
9
+ id saga_name resource_type resource_id status current_step direction
10
+ epoch context correlation_id failure_reason partition started_at
11
+ finished_at last_progress_at resume_count created_at updated_at
12
+ ].freeze
13
+
14
+ STATUSES = %w[running completed compensating compensated failed compensation_failed].freeze
15
+ TERMINAL_STATUSES = %w[completed compensated failed compensation_failed].freeze
16
+ IN_PROGRESS_STATUSES = %w[running compensating].freeze
17
+ DIRECTIONS = %w[execute compensate].freeze
18
+
19
+ STATUSES.each do |value|
20
+ define_method(:"#{value}?") { status == value }
21
+ end
22
+
23
+ def terminal? = TERMINAL_STATUSES.include?(status)
24
+
25
+ def in_progress? = IN_PROGRESS_STATUSES.include?(status)
26
+
27
+ def compensate_direction? = direction == "compensate"
28
+
29
+ # The cursor moved, so the stall clock restarts and the resume budget is
30
+ # spent fresh on the step we just reached.
31
+ def record_progress
32
+ self.last_progress_at = Time.now.utc
33
+ self.resume_count = 0
34
+ end
35
+
36
+ def definition_class
37
+ Lepus::Saga.find_definition!(saga_name)
38
+ end
39
+
40
+ def steps = definition_class.steps
41
+
42
+ def partition = self[:partition] || definition_class.partition
43
+
44
+ def current_step_definition
45
+ definition_class.find_step!(current_step) if current_step
46
+ end
47
+
48
+ # Filters for the attempts of the step the cursor points at.
49
+ def current_step_scope
50
+ {step_name: current_step, direction: direction, epoch: epoch}
51
+ end
52
+
53
+ def duration
54
+ (finished_at || Time.now.utc) - started_at
55
+ end
56
+ end
57
+ end
58
+ end