@omnitronix/bonnys-fortune-game-engine 1.3.2 → 1.5.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 (175) hide show
  1. package/README.md +25 -15
  2. package/dist/__tests__/base-game.test.js +255 -0
  3. package/dist/__tests__/base-game.test.js.map +1 -0
  4. package/dist/__tests__/bonnys-fortune-v1.game-engine.test.js +1 -1
  5. package/dist/__tests__/bonus-handlers.test.js +303 -0
  6. package/dist/__tests__/bonus-handlers.test.js.map +1 -0
  7. package/dist/__tests__/bonus-meters.test.js +508 -0
  8. package/dist/__tests__/bonus-meters.test.js.map +1 -0
  9. package/dist/__tests__/collect-feature-handler.test.js +386 -0
  10. package/dist/__tests__/collect-feature-handler.test.js.map +1 -0
  11. package/dist/__tests__/comprehensive.test.js +747 -0
  12. package/dist/__tests__/comprehensive.test.js.map +1 -0
  13. package/dist/__tests__/error-paths.test.js +373 -0
  14. package/dist/__tests__/error-paths.test.js.map +1 -0
  15. package/dist/__tests__/helpers/test-engine-factory.js +268 -0
  16. package/dist/__tests__/helpers/test-engine-factory.js.map +1 -0
  17. package/dist/__tests__/rng-gli19-compliance.test.js +292 -0
  18. package/dist/__tests__/rng-gli19-compliance.test.js.map +1 -0
  19. package/dist/__tests__/rng-security.test.js +383 -0
  20. package/dist/__tests__/rng-security.test.js.map +1 -0
  21. package/dist/__tests__/rtp-simulation.test.js +242 -0
  22. package/dist/__tests__/rtp-simulation.test.js.map +1 -0
  23. package/dist/__tests__/state-transitions.test.js +307 -0
  24. package/dist/__tests__/state-transitions.test.js.map +1 -0
  25. package/dist/__tests__/steering-fortune-handler.test.js +286 -0
  26. package/dist/__tests__/steering-fortune-handler.test.js.map +1 -0
  27. package/dist/__tests__/symbol-distribution.test.js +195 -0
  28. package/dist/__tests__/symbol-distribution.test.js.map +1 -0
  29. package/dist/__tests__/treasure-hunt-handler.test.js +295 -0
  30. package/dist/__tests__/treasure-hunt-handler.test.js.map +1 -0
  31. package/dist/__tests__/win-calculator.test.js +515 -0
  32. package/dist/__tests__/win-calculator.test.js.map +1 -0
  33. package/dist/bonnys-fortune-v1.game-engine.js +14 -25
  34. package/dist/bonnys-fortune-v1.game-engine.js.map +1 -1
  35. package/dist/config/game-logic-config/game-logic-config.js +0 -2
  36. package/dist/config/game-logic-config/game-logic-config.js.map +1 -1
  37. package/dist/domain/types/{cheat-trigger-bonus-command.js → debug-trigger-bonus-command.js} +1 -1
  38. package/dist/domain/types/debug-trigger-bonus-command.js.map +1 -0
  39. package/dist/domain/types/{cheat-trigger-bonus-request.dto.js → debug-trigger-bonus-request.dto.js} +1 -1
  40. package/dist/domain/types/debug-trigger-bonus-request.dto.js.map +1 -0
  41. package/dist/domain/types/{cheat-update-bonus-meter-progress-command.js → debug-update-bonus-meter-progress-command.js} +1 -1
  42. package/dist/domain/types/debug-update-bonus-meter-progress-command.js.map +1 -0
  43. package/dist/domain/types/{cheat-update-bonus-meter-progress-request.dto.js → debug-update-bonus-meter-progress-request.dto.js} +1 -1
  44. package/dist/domain/types/debug-update-bonus-meter-progress-request.dto.js.map +1 -0
  45. package/dist/index.js.map +1 -1
  46. package/dist/logic/bonnys-fortune.game-logic.js +37 -17
  47. package/dist/logic/bonnys-fortune.game-logic.js.map +1 -1
  48. package/dist/logic/handlers/base-game.handler.js +1 -5
  49. package/dist/logic/handlers/base-game.handler.js.map +1 -1
  50. package/dist/rng/DummyRngClient.js +8 -1
  51. package/dist/rng/DummyRngClient.js.map +1 -1
  52. package/dist/rng/rng-client.factory.js.map +1 -1
  53. package/dist/validation/bonnys-fortune/bonnys-fortune-config.dto.js +0 -9
  54. package/dist/validation/bonnys-fortune/bonnys-fortune-config.dto.js.map +1 -1
  55. package/package.json +6 -6
  56. package/dist/__tests__/bonnys-fortune-v1.game-engine.test.d.ts +0 -1
  57. package/dist/bonnys-fortune-v1.game-engine.d.ts +0 -36
  58. package/dist/config/game-logic-config/file-system.game-logic-config-loader.d.ts +0 -4
  59. package/dist/config/game-logic-config/game-logic-config-loader.d.ts +0 -3
  60. package/dist/config/game-logic-config/game-logic-config.d.ts +0 -2
  61. package/dist/config/reel-strips-config/file-system.reel-strips-config-loader.d.ts +0 -4
  62. package/dist/config/reel-strips-config/reel-strip-option.dto.d.ts +0 -4
  63. package/dist/config/reel-strips-config/reel-strips-config-loader.d.ts +0 -3
  64. package/dist/config/reel-strips-config/reel-strips-config.dto.d.ts +0 -5
  65. package/dist/config/reel-strips-config/reel.dto.d.ts +0 -5
  66. package/dist/domain/game-round.types.d.ts +0 -9
  67. package/dist/domain/mappers/reel-strips-config.mapper.d.ts +0 -4
  68. package/dist/domain/reel-strip-option.d.ts +0 -7
  69. package/dist/domain/reel-strips-config.d.ts +0 -9
  70. package/dist/domain/reel.d.ts +0 -8
  71. package/dist/domain/types/cheat-trigger-bonus-command.d.ts +0 -5
  72. package/dist/domain/types/cheat-trigger-bonus-command.js.map +0 -1
  73. package/dist/domain/types/cheat-trigger-bonus-request.dto.d.ts +0 -5
  74. package/dist/domain/types/cheat-trigger-bonus-request.dto.js.map +0 -1
  75. package/dist/domain/types/cheat-update-bonus-meter-progress-command.d.ts +0 -5
  76. package/dist/domain/types/cheat-update-bonus-meter-progress-command.js.map +0 -1
  77. package/dist/domain/types/cheat-update-bonus-meter-progress-request.dto.d.ts +0 -5
  78. package/dist/domain/types/cheat-update-bonus-meter-progress-request.dto.js.map +0 -1
  79. package/dist/domain/types/game-spin-command.d.ts +0 -8
  80. package/dist/domain/types/game-spin-input.dto.d.ts +0 -8
  81. package/dist/domain/types/game-spin-output.dto.d.ts +0 -119
  82. package/dist/domain/types/game-symbols.response.dto.d.ts +0 -10
  83. package/dist/domain/types/reel-strip-option.dto.d.ts +0 -4
  84. package/dist/domain/types/reel-strips-config.dto.d.ts +0 -5
  85. package/dist/domain/types/reel.dto.d.ts +0 -5
  86. package/dist/domain/types/start-bonus-round-command.d.ts +0 -8
  87. package/dist/domain/types/start-bonus-round-input.dto.d.ts +0 -10
  88. package/dist/game-engine.interface.d.ts +0 -41
  89. package/dist/helpers/generate-hash.d.ts +0 -1
  90. package/dist/helpers/number-helper.d.ts +0 -23
  91. package/dist/helpers/optional-boolean-mapper.d.ts +0 -1
  92. package/dist/helpers/uuid-helper.d.ts +0 -3
  93. package/dist/helpers/validation-helper.d.ts +0 -14
  94. package/dist/index.d.ts +0 -2
  95. package/dist/logger/logger.d.ts +0 -22
  96. package/dist/logger/logger.js +0 -140
  97. package/dist/logger/logger.js.map +0 -1
  98. package/dist/logic/bonnys-fortune.game-logic.d.ts +0 -32
  99. package/dist/logic/bonnys-fortune.spin-generator.d.ts +0 -19
  100. package/dist/logic/bonnys-fortune.types.d.ts +0 -170
  101. package/dist/logic/bonnys-fortune.win-calculator.d.ts +0 -10
  102. package/dist/logic/game-logic-config.interface.d.ts +0 -180
  103. package/dist/logic/handlers/base-game.handler.d.ts +0 -15
  104. package/dist/logic/handlers/collect-feature-bonus.handler.d.ts +0 -13
  105. package/dist/logic/handlers/free-spins-bonus.handler.d.ts +0 -11
  106. package/dist/logic/handlers/steering-to-the-fortune-bonus.handler.d.ts +0 -11
  107. package/dist/logic/handlers/treasure-hunt-bonus.handler.d.ts +0 -15
  108. package/dist/rng/DummyRngClient.d.ts +0 -18
  109. package/dist/rng/rng-client.factory.d.ts +0 -7
  110. package/dist/rng/rng-client.interface.d.ts +0 -16
  111. package/dist/rng/rng-service.d.ts +0 -26
  112. package/dist/validation/abstract-game-logic-config.validator.d.ts +0 -4
  113. package/dist/validation/bonnys-fortune/bonnys-fortune-config.dto.d.ts +0 -131
  114. package/dist/validation/bonnys-fortune/bonnys-fortune-config.validator.d.ts +0 -5
  115. package/dist/validation/custom-decorators/IsNestedIntArray.d.ts +0 -2
  116. package/dist/validation/game-logic-config-validation.service.d.ts +0 -8
  117. package/dist/validation/reel-strips-config-validation.service.d.ts +0 -5
  118. package/src/__tests__/bonnys-fortune-v1.game-engine.test.ts +0 -80
  119. package/src/bonnys-fortune-v1.game-engine.ts +0 -314
  120. package/src/config/game-logic-config/file-system.game-logic-config-loader.ts +0 -27
  121. package/src/config/game-logic-config/game-logic-config-loader.ts +0 -3
  122. package/src/config/game-logic-config/game-logic-config.ts +0 -382
  123. package/src/config/reel-strips-config/file-system.reel-strips-config-loader.ts +0 -43
  124. package/src/config/reel-strips-config/reel-strip-option.dto.ts +0 -13
  125. package/src/config/reel-strips-config/reel-strips-config-loader.ts +0 -9
  126. package/src/config/reel-strips-config/reel-strips-config.dto.ts +0 -16
  127. package/src/config/reel-strips-config/reel.dto.ts +0 -16
  128. package/src/config/reel-strips-config/reels-BASE.csv +0 -52
  129. package/src/config/reel-strips-config/reels-BONUS.csv +0 -52
  130. package/src/domain/game-round.types.ts +0 -10
  131. package/src/domain/mappers/reel-strips-config.mapper.ts +0 -16
  132. package/src/domain/reel-strip-option.ts +0 -15
  133. package/src/domain/reel-strips-config.ts +0 -21
  134. package/src/domain/reel.ts +0 -17
  135. package/src/domain/types/cheat-trigger-bonus-command.ts +0 -5
  136. package/src/domain/types/cheat-trigger-bonus-request.dto.ts +0 -5
  137. package/src/domain/types/cheat-update-bonus-meter-progress-command.ts +0 -6
  138. package/src/domain/types/cheat-update-bonus-meter-progress-request.dto.ts +0 -5
  139. package/src/domain/types/game-spin-command.ts +0 -8
  140. package/src/domain/types/game-spin-input.dto.ts +0 -8
  141. package/src/domain/types/game-spin-output.dto.ts +0 -142
  142. package/src/domain/types/game-symbols.response.dto.ts +0 -11
  143. package/src/domain/types/reel-strip-option.dto.ts +0 -13
  144. package/src/domain/types/reel-strips-config.dto.ts +0 -15
  145. package/src/domain/types/reel.dto.ts +0 -15
  146. package/src/domain/types/start-bonus-round-command.ts +0 -8
  147. package/src/domain/types/start-bonus-round-input.dto.ts +0 -10
  148. package/src/game-engine.interface.ts +0 -59
  149. package/src/helpers/generate-hash.ts +0 -5
  150. package/src/helpers/number-helper.ts +0 -41
  151. package/src/helpers/optional-boolean-mapper.ts +0 -5
  152. package/src/helpers/uuid-helper.ts +0 -7
  153. package/src/helpers/validation-helper.ts +0 -27
  154. package/src/index.ts +0 -3
  155. package/src/logger/logger.ts +0 -178
  156. package/src/logic/bonnys-fortune.game-logic.ts +0 -490
  157. package/src/logic/bonnys-fortune.spin-generator.ts +0 -277
  158. package/src/logic/bonnys-fortune.types.ts +0 -223
  159. package/src/logic/bonnys-fortune.win-calculator.ts +0 -210
  160. package/src/logic/game-logic-config.interface.ts +0 -176
  161. package/src/logic/handlers/base-game.handler.ts +0 -221
  162. package/src/logic/handlers/collect-feature-bonus.handler.ts +0 -301
  163. package/src/logic/handlers/free-spins-bonus.handler.ts +0 -119
  164. package/src/logic/handlers/steering-to-the-fortune-bonus.handler.ts +0 -118
  165. package/src/logic/handlers/treasure-hunt-bonus.handler.ts +0 -232
  166. package/src/rng/DummyRngClient.ts +0 -108
  167. package/src/rng/rng-client.factory.ts +0 -27
  168. package/src/rng/rng-client.interface.ts +0 -38
  169. package/src/rng/rng-service.ts +0 -130
  170. package/src/validation/abstract-game-logic-config.validator.ts +0 -20
  171. package/src/validation/bonnys-fortune/bonnys-fortune-config.dto.ts +0 -379
  172. package/src/validation/bonnys-fortune/bonnys-fortune-config.validator.ts +0 -8
  173. package/src/validation/custom-decorators/IsNestedIntArray.ts +0 -29
  174. package/src/validation/game-logic-config-validation.service.ts +0 -28
  175. package/src/validation/reel-strips-config-validation.service.ts +0 -29
@@ -0,0 +1,268 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AssertionBounds = exports.SEED_STABLE_99999 = exports.SEED_STABLE_77777 = exports.SEED_STABLE_54321 = exports.SEED_STABLE_12345 = exports.SEED_DEFAULT = exports.RTP_10K_UPPER_BOUND = exports.RTP_10K_LOWER_BOUND = exports.diffStates = exports.roundTripState = exports.statesEqual = exports.cloneState = exports.deserializeState = exports.serializeState = exports.validateRngOutcomeRecord = exports.validateRngOutcome = exports.isValidSha256 = exports.hashString = exports.hashRngOutcome = exports.canonicalizeRngOutcome = exports.getCommandIdCounter = exports.resetCommandIdCounter = exports.nextCommandId = exports.LcgRngClient = exports.MockRngClient = void 0;
4
+ exports.createEngine = createEngine;
5
+ exports.createEngineWithMockRng = createEngineWithMockRng;
6
+ exports.createEngineWithLcgRng = createEngineWithLcgRng;
7
+ exports.injectMockRng = injectMockRng;
8
+ exports.waitForEngineReady = waitForEngineReady;
9
+ exports.initSession = initSession;
10
+ exports.executeSpin = executeSpin;
11
+ exports.safeExecuteSpin = safeExecuteSpin;
12
+ exports.executeSpins = executeSpins;
13
+ exports.startBonusRound = startBonusRound;
14
+ exports.debugTriggerBonus = debugTriggerBonus;
15
+ exports.debugUpdateBonusMeter = debugUpdateBonusMeter;
16
+ exports.extractFinalBonusState = extractFinalBonusState;
17
+ exports.getRngOutcome = getRngOutcome;
18
+ exports.getAllRngOutcomes = getAllRngOutcomes;
19
+ exports.runSpinCycle = runSpinCycle;
20
+ /**
21
+ * Bonnys Fortune Test Engine Factory.
22
+ * Creates engine instances with controllable RNG for deterministic testing.
23
+ *
24
+ * Mock injection strategy:
25
+ * The engine, gameLogic, and all handlers share a SINGLE RngService instance.
26
+ * We replace the `rngClient` on that shared instance so all RNG calls go
27
+ * through our mock — no need to rebuild gameLogic or handlers.
28
+ */
29
+ const bonnys_fortune_v1_game_engine_1 = require("../../bonnys-fortune-v1.game-engine");
30
+ const game_test_utils_1 = require("@omnitronix/game-test-utils");
31
+ // Re-export for convenience
32
+ var game_test_utils_2 = require("@omnitronix/game-test-utils");
33
+ Object.defineProperty(exports, "MockRngClient", { enumerable: true, get: function () { return game_test_utils_2.MockRngClient; } });
34
+ Object.defineProperty(exports, "LcgRngClient", { enumerable: true, get: function () { return game_test_utils_2.LcgRngClient; } });
35
+ Object.defineProperty(exports, "nextCommandId", { enumerable: true, get: function () { return game_test_utils_2.nextCommandId; } });
36
+ Object.defineProperty(exports, "resetCommandIdCounter", { enumerable: true, get: function () { return game_test_utils_2.resetCommandIdCounter; } });
37
+ Object.defineProperty(exports, "getCommandIdCounter", { enumerable: true, get: function () { return game_test_utils_2.getCommandIdCounter; } });
38
+ Object.defineProperty(exports, "canonicalizeRngOutcome", { enumerable: true, get: function () { return game_test_utils_2.canonicalizeRngOutcome; } });
39
+ Object.defineProperty(exports, "hashRngOutcome", { enumerable: true, get: function () { return game_test_utils_2.hashRngOutcome; } });
40
+ Object.defineProperty(exports, "hashString", { enumerable: true, get: function () { return game_test_utils_2.hashString; } });
41
+ Object.defineProperty(exports, "isValidSha256", { enumerable: true, get: function () { return game_test_utils_2.isValidSha256; } });
42
+ Object.defineProperty(exports, "validateRngOutcome", { enumerable: true, get: function () { return game_test_utils_2.validateRngOutcome; } });
43
+ Object.defineProperty(exports, "validateRngOutcomeRecord", { enumerable: true, get: function () { return game_test_utils_2.validateRngOutcomeRecord; } });
44
+ Object.defineProperty(exports, "serializeState", { enumerable: true, get: function () { return game_test_utils_2.serializeState; } });
45
+ Object.defineProperty(exports, "deserializeState", { enumerable: true, get: function () { return game_test_utils_2.deserializeState; } });
46
+ Object.defineProperty(exports, "cloneState", { enumerable: true, get: function () { return game_test_utils_2.cloneState; } });
47
+ Object.defineProperty(exports, "statesEqual", { enumerable: true, get: function () { return game_test_utils_2.statesEqual; } });
48
+ Object.defineProperty(exports, "roundTripState", { enumerable: true, get: function () { return game_test_utils_2.roundTripState; } });
49
+ Object.defineProperty(exports, "diffStates", { enumerable: true, get: function () { return game_test_utils_2.diffStates; } });
50
+ // Constants
51
+ Object.defineProperty(exports, "RTP_10K_LOWER_BOUND", { enumerable: true, get: function () { return game_test_utils_2.RTP_10K_LOWER_BOUND; } });
52
+ Object.defineProperty(exports, "RTP_10K_UPPER_BOUND", { enumerable: true, get: function () { return game_test_utils_2.RTP_10K_UPPER_BOUND; } });
53
+ Object.defineProperty(exports, "SEED_DEFAULT", { enumerable: true, get: function () { return game_test_utils_2.SEED_DEFAULT; } });
54
+ Object.defineProperty(exports, "SEED_STABLE_12345", { enumerable: true, get: function () { return game_test_utils_2.SEED_STABLE_12345; } });
55
+ Object.defineProperty(exports, "SEED_STABLE_54321", { enumerable: true, get: function () { return game_test_utils_2.SEED_STABLE_54321; } });
56
+ Object.defineProperty(exports, "SEED_STABLE_77777", { enumerable: true, get: function () { return game_test_utils_2.SEED_STABLE_77777; } });
57
+ Object.defineProperty(exports, "SEED_STABLE_99999", { enumerable: true, get: function () { return game_test_utils_2.SEED_STABLE_99999; } });
58
+ Object.defineProperty(exports, "AssertionBounds", { enumerable: true, get: function () { return game_test_utils_2.AssertionBounds; } });
59
+ /**
60
+ * Create a standard engine with default (DummyRngClient) RNG.
61
+ */
62
+ function createEngine() {
63
+ return new bonnys_fortune_v1_game_engine_1.BonnysFortuneV1GameEngine();
64
+ }
65
+ /**
66
+ * Create an engine with a MockRngClient injected.
67
+ */
68
+ function createEngineWithMockRng(values = 0) {
69
+ const engine = new bonnys_fortune_v1_game_engine_1.BonnysFortuneV1GameEngine();
70
+ const mockRng = new game_test_utils_1.MockRngClient(values);
71
+ engine.rngService.rngClient = mockRng;
72
+ return { engine, mockRng };
73
+ }
74
+ /**
75
+ * Create an engine with an LCG RNG for reproducible simulations.
76
+ */
77
+ function createEngineWithLcgRng(seed = 12345) {
78
+ const engine = new bonnys_fortune_v1_game_engine_1.BonnysFortuneV1GameEngine();
79
+ const lcgRng = new game_test_utils_1.LcgRngClient(seed);
80
+ engine.rngService.rngClient = lcgRng;
81
+ return { engine, lcgRng };
82
+ }
83
+ /**
84
+ * Inject a mock RNG client into an existing engine.
85
+ */
86
+ function injectMockRng(engine, mockRng) {
87
+ engine.rngService.rngClient = mockRng;
88
+ }
89
+ // ---------------------------------------------------------------------------
90
+ // Engine Readiness
91
+ // ---------------------------------------------------------------------------
92
+ /**
93
+ * Wait for the engine's async preload() to finish.
94
+ * The engine constructor fires preload() without await (fire-and-forget).
95
+ * We poll for `engine.reels` to be defined before proceeding.
96
+ */
97
+ async function waitForEngineReady(engine, timeout = 5000) {
98
+ const start = Date.now();
99
+ while (!engine.reels && Date.now() - start < timeout) {
100
+ await new Promise(resolve => setTimeout(resolve, 10));
101
+ }
102
+ if (!engine.reels) {
103
+ throw new Error('Engine preload did not complete within timeout');
104
+ }
105
+ }
106
+ /**
107
+ * Initialize a session on the engine.
108
+ * Waits for engine preload to complete before issuing any commands.
109
+ */
110
+ async function initSession(engine, betAmount = 1.0, betAmountThresholds = [0.1, 0.2, 0.5, 1, 2, 5, 10, 20, 50, 100]) {
111
+ await waitForEngineReady(engine);
112
+ const result = await engine.processCommand(null, null, {
113
+ id: (0, game_test_utils_1.nextCommandId)('init'),
114
+ type: 'INIT_SESSION_STATE',
115
+ payload: {
116
+ betAmountThresholds,
117
+ defaultBetAmount: betAmount,
118
+ },
119
+ });
120
+ expect(result.success).toBe(true);
121
+ return {
122
+ publicState: result.publicState,
123
+ privateState: result.privateState,
124
+ };
125
+ }
126
+ /**
127
+ * Execute a SPIN command.
128
+ */
129
+ async function executeSpin(engine, publicState, privateState, betAmount = 1.0) {
130
+ const result = await engine.processCommand(publicState, privateState, {
131
+ id: (0, game_test_utils_1.nextCommandId)('spin'),
132
+ type: 'SPIN',
133
+ payload: {
134
+ sessionId: 'test-session',
135
+ betAmount,
136
+ gameCode: 'bonnys-fortune',
137
+ gameVersion: '1.0.0',
138
+ },
139
+ });
140
+ return result;
141
+ }
142
+ /**
143
+ * Execute a SPIN command with error tolerance for known engine bugs.
144
+ * BF's DummyRng can trigger bonus meters (COLLECT_FEATURE, bonusGame1, etc.),
145
+ * causing subsequent SPIN commands to throw DomainException when
146
+ * nextSpinType != BASE_GAME_SPIN. This helper catches those errors and
147
+ * returns null, allowing multi-spin loops to skip them.
148
+ */
149
+ async function safeExecuteSpin(engine, publicState, privateState, betAmount = 1.0) {
150
+ try {
151
+ return await executeSpin(engine, publicState, privateState, betAmount);
152
+ }
153
+ catch (error) {
154
+ if (error.message?.includes('Cannot execute base spin')) {
155
+ return null;
156
+ }
157
+ throw error;
158
+ }
159
+ }
160
+ /**
161
+ * Execute multiple spins, threading state through each one.
162
+ */
163
+ async function executeSpins(engine, publicState, privateState, count, betAmount = 1.0) {
164
+ const results = [];
165
+ let currentPublic = publicState;
166
+ let currentPrivate = privateState;
167
+ for (let i = 0; i < count; i++) {
168
+ const result = await executeSpin(engine, currentPublic, currentPrivate, betAmount);
169
+ results.push(result);
170
+ currentPublic = result.publicState;
171
+ currentPrivate = result.privateState;
172
+ }
173
+ return results;
174
+ }
175
+ /**
176
+ * Start a bonus round.
177
+ */
178
+ async function startBonusRound(engine, publicState, privateState, bonusType = 'bonusGame1', betAmount = 1.0) {
179
+ const bonusId = privateState.pendingBonuses?.[0]?.bonusId ?? 'test-bonus-id';
180
+ const result = await engine.processCommand(publicState, privateState, {
181
+ id: (0, game_test_utils_1.nextCommandId)('bonus'),
182
+ type: 'START_BONUS_ROUND',
183
+ payload: {
184
+ sessionId: 'test-session',
185
+ bonusId,
186
+ bonusType,
187
+ betAmount,
188
+ gameCode: 'bonnys-fortune',
189
+ gameVersion: '1.0.0',
190
+ },
191
+ });
192
+ return result;
193
+ }
194
+ /**
195
+ * Trigger a debug bonus.
196
+ */
197
+ async function debugTriggerBonus(engine, publicState, privateState, bonusType = 'bonusGame1', betAmount = 1.0) {
198
+ const result = await engine.processCommand(publicState, privateState, {
199
+ id: (0, game_test_utils_1.nextCommandId)('debug'),
200
+ type: 'DEBUG_TRIGGER_BONUS',
201
+ payload: {
202
+ sessionId: 'test-session',
203
+ bonusType,
204
+ betAmount,
205
+ },
206
+ });
207
+ return result;
208
+ }
209
+ /**
210
+ * Debug update bonus meter progress.
211
+ */
212
+ async function debugUpdateBonusMeter(engine, publicState, privateState, meterId, progress) {
213
+ const result = await engine.processCommand(publicState, privateState, {
214
+ id: (0, game_test_utils_1.nextCommandId)('debug-meter'),
215
+ type: 'DEBUG_UPDATE_BONUS_METER_PROGRESS',
216
+ payload: {
217
+ meterId,
218
+ progress,
219
+ },
220
+ });
221
+ return result;
222
+ }
223
+ /**
224
+ * Extract the final state from a START_BONUS_ROUND result.
225
+ * BF generates all bonus results upfront. The top-level publicState/privateState
226
+ * are the ORIGINAL input states. The actual final state (with nextSpinType
227
+ * transitioned back to BASE_GAME_SPIN) is in the last result entry.
228
+ */
229
+ function extractFinalBonusState(bonusResult) {
230
+ const results = bonusResult.outcome?.results;
231
+ if (results?.length > 0) {
232
+ const lastResult = results[results.length - 1];
233
+ return {
234
+ publicState: lastResult.publicState ?? bonusResult.publicState,
235
+ privateState: lastResult.privateState ?? bonusResult.privateState,
236
+ };
237
+ }
238
+ return {
239
+ publicState: bonusResult.publicState,
240
+ privateState: bonusResult.privateState,
241
+ };
242
+ }
243
+ /**
244
+ * Get the rngOutcome from the engine's RNG service for a specific command.
245
+ */
246
+ function getRngOutcome(engine, commandId) {
247
+ return engine.rngService.getRngOutcomeForCommand(commandId);
248
+ }
249
+ /**
250
+ * Get all RNG outcomes currently tracked by the engine.
251
+ */
252
+ function getAllRngOutcomes(engine) {
253
+ return engine.rngService.getAllRngOutcome();
254
+ }
255
+ /**
256
+ * Run a full init + N spins cycle.
257
+ */
258
+ async function runSpinCycle(engine, spinCount, betAmount = 1.0) {
259
+ const session = await initSession(engine, betAmount);
260
+ const results = await executeSpins(engine, session.publicState, session.privateState, spinCount, betAmount);
261
+ const lastResult = results[results.length - 1];
262
+ return {
263
+ results,
264
+ finalPublicState: lastResult.publicState,
265
+ finalPrivateState: lastResult.privateState,
266
+ };
267
+ }
268
+ //# sourceMappingURL=test-engine-factory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-engine-factory.js","sourceRoot":"","sources":["../../../src/__tests__/helpers/test-engine-factory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,292 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /**
4
+ * GLI-19 Compliance Tests — Bonnys Fortune
5
+ *
6
+ * Validates RNG audit trail requirements per GLI-19 standard:
7
+ * 3.4: All RNG outcomes must have tamper-evident audit trails
8
+ * 3.5: Deterministic replay from recorded seeds
9
+ * 3.6: Hash chain integrity for audit verification
10
+ */
11
+ const test_engine_factory_1 = require("./helpers/test-engine-factory");
12
+ describe('GLI-19 Compliance — Bonnys Fortune', () => {
13
+ beforeEach(() => {
14
+ (0, test_engine_factory_1.resetCommandIdCounter)();
15
+ });
16
+ describe('Audit Trail Completeness', () => {
17
+ it('should include rngOutcome in every spin result', async () => {
18
+ const engine = (0, test_engine_factory_1.createEngine)();
19
+ const session = await (0, test_engine_factory_1.initSession)(engine);
20
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, session.privateState);
21
+ expect(result.rngOutcome).toBeDefined();
22
+ expect(typeof result.rngOutcome).toBe('object');
23
+ expect(Object.keys(result.rngOutcome || {}).length).toBeGreaterThan(0);
24
+ });
25
+ it('should have non-empty rngOutcome for spins', async () => {
26
+ const engine = (0, test_engine_factory_1.createEngine)();
27
+ const session = await (0, test_engine_factory_1.initSession)(engine);
28
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, session.privateState);
29
+ const keys = Object.keys(result.rngOutcome || {});
30
+ // A spin must produce at least 1 RNG action (screen generation)
31
+ expect(keys.length).toBeGreaterThanOrEqual(1);
32
+ // Validate structure of each record
33
+ for (const key of keys) {
34
+ const record = result.rngOutcome[key];
35
+ expect(typeof record.result).toBe('number');
36
+ expect(record.seed !== null && record.seed !== undefined).toBe(true);
37
+ }
38
+ });
39
+ it('should include seed, result, min, max for each RNG action', async () => {
40
+ const engine = (0, test_engine_factory_1.createEngine)();
41
+ const session = await (0, test_engine_factory_1.initSession)(engine);
42
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, session.privateState);
43
+ const outcome = result.rngOutcome;
44
+ const validation = (0, test_engine_factory_1.validateRngOutcome)(outcome);
45
+ expect(validation.valid).toBe(true);
46
+ if (!validation.valid) {
47
+ console.error('Validation errors:', validation.errors);
48
+ }
49
+ });
50
+ it('should record all RNG actions with unique actionIds', async () => {
51
+ const engine = (0, test_engine_factory_1.createEngine)();
52
+ const session = await (0, test_engine_factory_1.initSession)(engine);
53
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, session.privateState);
54
+ const actionIds = Object.keys(result.rngOutcome || {});
55
+ const uniqueIds = new Set(actionIds);
56
+ expect(uniqueIds.size).toBe(actionIds.length);
57
+ });
58
+ it('should have results within declared min/max bounds', async () => {
59
+ const engine = (0, test_engine_factory_1.createEngine)();
60
+ const session = await (0, test_engine_factory_1.initSession)(engine);
61
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, session.privateState);
62
+ for (const [, record] of Object.entries(result.rngOutcome || {})) {
63
+ const rec = record;
64
+ expect(rec.result).toBeGreaterThanOrEqual(rec.min);
65
+ expect(rec.result).toBeLessThanOrEqual(rec.max);
66
+ }
67
+ });
68
+ it('should provide audit trails for multiple consecutive spins', async () => {
69
+ const engine = (0, test_engine_factory_1.createEngine)();
70
+ const session = await (0, test_engine_factory_1.initSession)(engine);
71
+ let pub = session.publicState;
72
+ let priv = session.privateState;
73
+ for (let i = 0; i < 5; i++) {
74
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, pub, priv);
75
+ expect(result.rngOutcome).toBeDefined();
76
+ expect(Object.keys(result.rngOutcome || {}).length).toBeGreaterThan(0);
77
+ const validation = (0, test_engine_factory_1.validateRngOutcome)(result.rngOutcome);
78
+ expect(validation.valid).toBe(true);
79
+ pub = result.publicState;
80
+ priv = result.privateState;
81
+ }
82
+ });
83
+ it('should track bonus meter RNG actions in audit trail', async () => {
84
+ const engine = (0, test_engine_factory_1.createEngine)();
85
+ const session = await (0, test_engine_factory_1.initSession)(engine);
86
+ // Run spins - bonus meter threshold randomization should appear in rngOutcome
87
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, session.privateState);
88
+ const actionIds = Object.keys(result.rngOutcome || {});
89
+ // Should have at least screen generation RNG actions (minimum 1)
90
+ expect(actionIds.length).toBeGreaterThanOrEqual(1);
91
+ // Each action should have proper structure
92
+ for (const actionId of actionIds) {
93
+ const record = result.rngOutcome[actionId];
94
+ expect(typeof record.result).toBe('number');
95
+ expect(typeof record.min).toBe('number');
96
+ expect(typeof record.max).toBe('number');
97
+ }
98
+ });
99
+ });
100
+ describe('Tamper Detection via SHA-256', () => {
101
+ it('should produce valid SHA-256 hashes from rngOutcome', async () => {
102
+ const engine = (0, test_engine_factory_1.createEngine)();
103
+ const session = await (0, test_engine_factory_1.initSession)(engine);
104
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, session.privateState);
105
+ const hash = (0, test_engine_factory_1.hashRngOutcome)(result.rngOutcome);
106
+ expect((0, test_engine_factory_1.isValidSha256)(hash)).toBe(true);
107
+ });
108
+ it('should produce different hashes for different outcomes', async () => {
109
+ const engine = (0, test_engine_factory_1.createEngine)();
110
+ const session = await (0, test_engine_factory_1.initSession)(engine);
111
+ const result1 = await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, session.privateState);
112
+ const result2 = await (0, test_engine_factory_1.executeSpin)(engine, result1.publicState, result1.privateState);
113
+ const hash1 = (0, test_engine_factory_1.hashRngOutcome)(result1.rngOutcome);
114
+ const hash2 = (0, test_engine_factory_1.hashRngOutcome)(result2.rngOutcome);
115
+ expect(hash1).not.toBe(hash2);
116
+ });
117
+ it('should produce identical hashes for identical outcomes', async () => {
118
+ const { engine } = (0, test_engine_factory_1.createEngineWithMockRng)([5, 10, 3, 7, 2, 8, 1, 4, 6, 9]);
119
+ const session = await (0, test_engine_factory_1.initSession)(engine);
120
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, session.privateState);
121
+ const hash1 = (0, test_engine_factory_1.hashRngOutcome)(result.rngOutcome);
122
+ const hash2 = (0, test_engine_factory_1.hashRngOutcome)(result.rngOutcome);
123
+ expect(hash1).toBe(hash2);
124
+ });
125
+ it('should detect tampering when a single field is modified', async () => {
126
+ const engine = (0, test_engine_factory_1.createEngine)();
127
+ const session = await (0, test_engine_factory_1.initSession)(engine);
128
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, session.privateState);
129
+ const originalHash = (0, test_engine_factory_1.hashRngOutcome)(result.rngOutcome);
130
+ const tampered = (0, test_engine_factory_1.cloneState)(result.rngOutcome);
131
+ const firstKey = Object.keys(tampered)[0];
132
+ expect(firstKey).toBeDefined();
133
+ tampered[firstKey].result += 1;
134
+ const tamperedHash = (0, test_engine_factory_1.hashRngOutcome)(tampered);
135
+ expect(tamperedHash).not.toBe(originalHash);
136
+ });
137
+ it('should produce consistent canonical form regardless of key order', async () => {
138
+ const engine = (0, test_engine_factory_1.createEngine)();
139
+ const session = await (0, test_engine_factory_1.initSession)(engine);
140
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, session.privateState);
141
+ const canonical1 = (0, test_engine_factory_1.canonicalizeRngOutcome)(result.rngOutcome);
142
+ const reversed = {};
143
+ const keys = Object.keys(result.rngOutcome).reverse();
144
+ for (const key of keys) {
145
+ reversed[key] = result.rngOutcome[key];
146
+ }
147
+ const canonical2 = (0, test_engine_factory_1.canonicalizeRngOutcome)(reversed);
148
+ expect(canonical1).toBe(canonical2);
149
+ });
150
+ });
151
+ describe('Deterministic Replay', () => {
152
+ it('should produce identical outcomes with same mock RNG sequence', async () => {
153
+ const sequence = [5, 10, 3, 7, 2, 8, 1, 4, 6, 9, 0, 11, 12, 13, 14, 15, 16, 17, 18, 19];
154
+ const { engine: engine1 } = (0, test_engine_factory_1.createEngineWithMockRng)([...sequence]);
155
+ const session1 = await (0, test_engine_factory_1.initSession)(engine1);
156
+ const result1 = await (0, test_engine_factory_1.executeSpin)(engine1, session1.publicState, session1.privateState);
157
+ const { engine: engine2 } = (0, test_engine_factory_1.createEngineWithMockRng)([...sequence]);
158
+ const session2 = await (0, test_engine_factory_1.initSession)(engine2);
159
+ const result2 = await (0, test_engine_factory_1.executeSpin)(engine2, session2.publicState, session2.privateState);
160
+ expect(result1.outcome).toEqual(result2.outcome);
161
+ });
162
+ it('should produce identical hash chains with same mock sequence', async () => {
163
+ const sequence = [5, 10, 3, 7, 2, 8, 1, 4, 6, 9, 0, 11, 12, 13, 14, 15, 16, 17, 18, 19];
164
+ const { engine: engine1 } = (0, test_engine_factory_1.createEngineWithMockRng)([...sequence]);
165
+ const session1 = await (0, test_engine_factory_1.initSession)(engine1);
166
+ const result1 = await (0, test_engine_factory_1.executeSpin)(engine1, session1.publicState, session1.privateState);
167
+ const { engine: engine2 } = (0, test_engine_factory_1.createEngineWithMockRng)([...sequence]);
168
+ const session2 = await (0, test_engine_factory_1.initSession)(engine2);
169
+ const result2 = await (0, test_engine_factory_1.executeSpin)(engine2, session2.publicState, session2.privateState);
170
+ const hash1 = (0, test_engine_factory_1.hashRngOutcome)(result1.rngOutcome);
171
+ const hash2 = (0, test_engine_factory_1.hashRngOutcome)(result2.rngOutcome);
172
+ expect(hash1).toBe(hash2);
173
+ });
174
+ it('should produce different outcomes with different mock sequences', async () => {
175
+ const { engine: engine1 } = (0, test_engine_factory_1.createEngineWithMockRng)([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
176
+ const session1 = await (0, test_engine_factory_1.initSession)(engine1);
177
+ const result1 = await (0, test_engine_factory_1.executeSpin)(engine1, session1.publicState, session1.privateState);
178
+ const { engine: engine2 } = (0, test_engine_factory_1.createEngineWithMockRng)([9, 9, 9, 9, 9, 9, 9, 9, 9, 9]);
179
+ const session2 = await (0, test_engine_factory_1.initSession)(engine2);
180
+ const result2 = await (0, test_engine_factory_1.executeSpin)(engine2, session2.publicState, session2.privateState);
181
+ const hash1 = (0, test_engine_factory_1.hashRngOutcome)(result1.rngOutcome);
182
+ const hash2 = (0, test_engine_factory_1.hashRngOutcome)(result2.rngOutcome);
183
+ expect(hash1).not.toBe(hash2);
184
+ });
185
+ });
186
+ describe('Hash Chain Integrity', () => {
187
+ it('should maintain a hash chain across multiple spins', async () => {
188
+ const engine = (0, test_engine_factory_1.createEngine)();
189
+ const session = await (0, test_engine_factory_1.initSession)(engine);
190
+ const hashChain = [];
191
+ let pub = session.publicState;
192
+ let priv = session.privateState;
193
+ for (let i = 0; i < 10; i++) {
194
+ // Handle bonus triggers before spinning
195
+ if (priv.nextSpinType !== 'BASE_GAME_SPIN') {
196
+ if (priv.pendingBonuses?.length > 0) {
197
+ const bonus = priv.pendingBonuses[0];
198
+ const bonusResult = await (0, test_engine_factory_1.startBonusRound)(engine, pub, priv, bonus.bonusType);
199
+ const finalState = (0, test_engine_factory_1.extractFinalBonusState)(bonusResult);
200
+ pub = finalState.publicState;
201
+ priv = finalState.privateState;
202
+ while (priv.pendingBonuses?.length > 0) {
203
+ const nextBonus = priv.pendingBonuses[0];
204
+ const chainResult = await (0, test_engine_factory_1.startBonusRound)(engine, pub, priv, nextBonus.bonusType);
205
+ const chainFinal = (0, test_engine_factory_1.extractFinalBonusState)(chainResult);
206
+ pub = chainFinal.publicState;
207
+ priv = chainFinal.privateState;
208
+ }
209
+ }
210
+ if (priv.nextSpinType !== 'BASE_GAME_SPIN')
211
+ break;
212
+ }
213
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, pub, priv);
214
+ const hash = (0, test_engine_factory_1.hashRngOutcome)(result.rngOutcome);
215
+ expect((0, test_engine_factory_1.isValidSha256)(hash)).toBe(true);
216
+ hashChain.push(hash);
217
+ pub = result.publicState;
218
+ priv = result.privateState;
219
+ if (hashChain.length >= 5)
220
+ break;
221
+ }
222
+ expect(hashChain.length).toBeGreaterThanOrEqual(2);
223
+ const uniqueHashes = new Set(hashChain);
224
+ expect(uniqueHashes.size).toBe(hashChain.length);
225
+ });
226
+ it('should allow chained hash verification', async () => {
227
+ const engine = (0, test_engine_factory_1.createEngine)();
228
+ const session = await (0, test_engine_factory_1.initSession)(engine);
229
+ let pub = session.publicState;
230
+ let priv = session.privateState;
231
+ let prevHash = (0, test_engine_factory_1.hashString)('genesis');
232
+ for (let i = 0; i < 3; i++) {
233
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, pub, priv);
234
+ const outcomeHash = (0, test_engine_factory_1.hashRngOutcome)(result.rngOutcome);
235
+ const chainedHash = (0, test_engine_factory_1.hashString)(prevHash + outcomeHash);
236
+ expect((0, test_engine_factory_1.isValidSha256)(chainedHash)).toBe(true);
237
+ prevHash = chainedHash;
238
+ pub = result.publicState;
239
+ priv = result.privateState;
240
+ }
241
+ });
242
+ });
243
+ describe('RNG Record Validation', () => {
244
+ it('should have numeric result values', async () => {
245
+ const engine = (0, test_engine_factory_1.createEngine)();
246
+ const session = await (0, test_engine_factory_1.initSession)(engine);
247
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, session.privateState);
248
+ for (const [, record] of Object.entries(result.rngOutcome || {})) {
249
+ const rec = record;
250
+ expect(typeof rec.result).toBe('number');
251
+ expect(isFinite(rec.result)).toBe(true);
252
+ }
253
+ });
254
+ it('should have numeric min/max values', async () => {
255
+ const engine = (0, test_engine_factory_1.createEngine)();
256
+ const session = await (0, test_engine_factory_1.initSession)(engine);
257
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, session.privateState);
258
+ for (const [, record] of Object.entries(result.rngOutcome || {})) {
259
+ const rec = record;
260
+ expect(typeof rec.min).toBe('number');
261
+ expect(typeof rec.max).toBe('number');
262
+ expect(rec.min).toBeLessThanOrEqual(rec.max);
263
+ }
264
+ });
265
+ it('should have seed values present for every record', async () => {
266
+ const engine = (0, test_engine_factory_1.createEngine)();
267
+ const session = await (0, test_engine_factory_1.initSession)(engine);
268
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, session.publicState, session.privateState);
269
+ for (const [, record] of Object.entries(result.rngOutcome || {})) {
270
+ const rec = record;
271
+ expect(rec.seed).toBeDefined();
272
+ expect(rec.seed !== null).toBe(true);
273
+ // Seed should be a number or string
274
+ expect(['number', 'string'].includes(typeof rec.seed)).toBe(true);
275
+ }
276
+ });
277
+ it('should pass full outcome validation across 10 spins', async () => {
278
+ const engine = (0, test_engine_factory_1.createEngine)();
279
+ const session = await (0, test_engine_factory_1.initSession)(engine);
280
+ let pub = session.publicState;
281
+ let priv = session.privateState;
282
+ for (let i = 0; i < 10; i++) {
283
+ const result = await (0, test_engine_factory_1.executeSpin)(engine, pub, priv);
284
+ const validation = (0, test_engine_factory_1.validateRngOutcome)(result.rngOutcome);
285
+ expect(validation.valid).toBe(true);
286
+ pub = result.publicState;
287
+ priv = result.privateState;
288
+ }
289
+ });
290
+ });
291
+ });
292
+ //# sourceMappingURL=rng-gli19-compliance.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rng-gli19-compliance.test.js","sourceRoot":"","sources":["../../src/__tests__/rng-gli19-compliance.test.ts"],"names":[],"mappings":";;AAAA;;;;;;;GAOG;AACH,uEAeuC;AAEvC,QAAQ,CAAC,oCAAoC,EAAE,GAAG,EAAE;IAClD,UAAU,CAAC,GAAG,EAAE;QACd,IAAA,2CAAqB,GAAE,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;QACxC,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;YAC9D,MAAM,MAAM,GAAG,IAAA,kCAAY,GAAE,CAAC;YAC9B,MAAM,OAAO,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,CAAC,CAAC;YAC1C,MAAM,MAAM,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,EAAE,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;YAEpF,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE,CAAC;YACxC,MAAM,CAAC,OAAO,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAChD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QACzE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;YAC1D,MAAM,MAAM,GAAG,IAAA,kCAAY,GAAE,CAAC;YAC9B,MAAM,OAAO,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,CAAC,CAAC;YAC1C,MAAM,MAAM,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,EAAE,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;YAEpF,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC;YAClD,gEAAgE;YAChE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;YAC9C,oCAAoC;YACpC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;gBACvB,MAAM,MAAM,GAAI,MAAM,CAAC,UAAsC,CAAC,GAAG,CAKhE,CAAC;gBACF,MAAM,CAAC,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBAC5C,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,IAAI,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACvE,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2DAA2D,EAAE,KAAK,IAAI,EAAE;YACzE,MAAM,MAAM,GAAG,IAAA,kCAAY,GAAE,CAAC;YAC9B,MAAM,OAAO,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,CAAC,CAAC;YAC1C,MAAM,MAAM,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,EAAE,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;YAEpF,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC;YAClC,MAAM,UAAU,GAAG,IAAA,wCAAkB,EAAC,OAAO,CAAC,CAAC;YAE/C,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACpC,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;gBACtB,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;YACzD,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;YACnE,MAAM,MAAM,GAAG,IAAA,kCAAY,GAAE,CAAC;YAC9B,MAAM,OAAO,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,CAAC,CAAC;YAC1C,MAAM,MAAM,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,EAAE,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;YAEpF,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC;YACvD,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;YACrC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;YAClE,MAAM,MAAM,GAAG,IAAA,kCAAY,GAAE,CAAC;YAC9B,MAAM,OAAO,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,CAAC,CAAC;YAC1C,MAAM,MAAM,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,EAAE,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;YASpF,KAAK,MAAM,CAAC,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC,EAAE,CAAC;gBACjE,MAAM,GAAG,GAAG,MAA0B,CAAC;gBACvC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBACnD,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,mBAAmB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAClD,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4DAA4D,EAAE,KAAK,IAAI,EAAE;YAC1E,MAAM,MAAM,GAAG,IAAA,kCAAY,GAAE,CAAC;YAC9B,MAAM,OAAO,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,CAAC,CAAC;YAE1C,IAAI,GAAG,GAAG,OAAO,CAAC,WAAW,CAAC;YAC9B,IAAI,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC;YAEhC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC3B,MAAM,MAAM,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;gBACpD,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE,CAAC;gBACxC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;gBAEvE,MAAM,UAAU,GAAG,IAAA,wCAAkB,EAAC,MAAM,CAAC,UAAU,CAAC,CAAC;gBACzD,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAEpC,GAAG,GAAG,MAAM,CAAC,WAAW,CAAC;gBACzB,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC;YAC7B,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;YACnE,MAAM,MAAM,GAAG,IAAA,kCAAY,GAAE,CAAC;YAC9B,MAAM,OAAO,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,CAAC,CAAC;YAE1C,8EAA8E;YAC9E,MAAM,MAAM,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,EAAE,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;YACpF,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC;YAEvD,iEAAiE;YACjE,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;YACnD,2CAA2C;YAC3C,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;gBACjC,MAAM,MAAM,GAAI,MAAM,CAAC,UAAsC,CAAC,QAAQ,CAKrE,CAAC;gBACF,MAAM,CAAC,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBAC5C,MAAM,CAAC,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBACzC,MAAM,CAAC,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC3C,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,8BAA8B,EAAE,GAAG,EAAE;QAC5C,EAAE,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;YACnE,MAAM,MAAM,GAAG,IAAA,kCAAY,GAAE,CAAC;YAC9B,MAAM,OAAO,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,CAAC,CAAC;YAC1C,MAAM,MAAM,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,EAAE,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;YAEpF,MAAM,IAAI,GAAG,IAAA,oCAAc,EAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YAC/C,MAAM,CAAC,IAAA,mCAAa,EAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wDAAwD,EAAE,KAAK,IAAI,EAAE;YACtE,MAAM,MAAM,GAAG,IAAA,kCAAY,GAAE,CAAC;YAC9B,MAAM,OAAO,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,CAAC,CAAC;YAE1C,MAAM,OAAO,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,EAAE,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;YACrF,MAAM,OAAO,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,EAAE,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;YAErF,MAAM,KAAK,GAAG,IAAA,oCAAc,EAAC,OAAO,CAAC,UAAU,CAAC,CAAC;YACjD,MAAM,KAAK,GAAG,IAAA,oCAAc,EAAC,OAAO,CAAC,UAAU,CAAC,CAAC;YAEjD,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wDAAwD,EAAE,KAAK,IAAI,EAAE;YACtE,MAAM,EAAE,MAAM,EAAE,GAAG,IAAA,6CAAuB,EAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YAC5E,MAAM,OAAO,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,CAAC,CAAC;YAC1C,MAAM,MAAM,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,EAAE,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;YAEpF,MAAM,KAAK,GAAG,IAAA,oCAAc,EAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YAChD,MAAM,KAAK,GAAG,IAAA,oCAAc,EAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YAEhD,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yDAAyD,EAAE,KAAK,IAAI,EAAE;YACvE,MAAM,MAAM,GAAG,IAAA,kCAAY,GAAE,CAAC;YAC9B,MAAM,OAAO,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,CAAC,CAAC;YAC1C,MAAM,MAAM,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,EAAE,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;YAEpF,MAAM,YAAY,GAAG,IAAA,oCAAc,EAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YASvD,MAAM,QAAQ,GAAG,IAAA,gCAAU,EAAC,MAAM,CAAC,UAAU,CAAqC,CAAC;YACnF,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;YAC1C,MAAM,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;YAC/B,QAAQ,CAAC,QAAQ,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC;YAE/B,MAAM,YAAY,GAAG,IAAA,oCAAc,EAAC,QAAQ,CAAC,CAAC;YAC9C,MAAM,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC9C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kEAAkE,EAAE,KAAK,IAAI,EAAE;YAChF,MAAM,MAAM,GAAG,IAAA,kCAAY,GAAE,CAAC;YAC9B,MAAM,OAAO,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,CAAC,CAAC;YAC1C,MAAM,MAAM,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,EAAE,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;YASpF,MAAM,UAAU,GAAG,IAAA,4CAAsB,EAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YAC7D,MAAM,QAAQ,GAAqC,EAAE,CAAC;YACtD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,CAAC;YACtD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;gBACvB,QAAQ,CAAC,GAAG,CAAC,GAAI,MAAM,CAAC,UAA+C,CAAC,GAAG,CAAC,CAAC;YAC/E,CAAC;YACD,MAAM,UAAU,GAAG,IAAA,4CAAsB,EAAC,QAAQ,CAAC,CAAC;YAEpD,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;QACpC,EAAE,CAAC,+DAA+D,EAAE,KAAK,IAAI,EAAE;YAC7E,MAAM,QAAQ,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;YAExF,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,IAAA,6CAAuB,EAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC;YACnE,MAAM,QAAQ,GAAG,MAAM,IAAA,iCAAW,EAAC,OAAO,CAAC,CAAC;YAC5C,MAAM,OAAO,GAAG,MAAM,IAAA,iCAAW,EAAC,OAAO,EAAE,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC;YAExF,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,IAAA,6CAAuB,EAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC;YACnE,MAAM,QAAQ,GAAG,MAAM,IAAA,iCAAW,EAAC,OAAO,CAAC,CAAC;YAC5C,MAAM,OAAO,GAAG,MAAM,IAAA,iCAAW,EAAC,OAAO,EAAE,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC;YAExF,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACnD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8DAA8D,EAAE,KAAK,IAAI,EAAE;YAC5E,MAAM,QAAQ,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;YAExF,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,IAAA,6CAAuB,EAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC;YACnE,MAAM,QAAQ,GAAG,MAAM,IAAA,iCAAW,EAAC,OAAO,CAAC,CAAC;YAC5C,MAAM,OAAO,GAAG,MAAM,IAAA,iCAAW,EAAC,OAAO,EAAE,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC;YAExF,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,IAAA,6CAAuB,EAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC;YACnE,MAAM,QAAQ,GAAG,MAAM,IAAA,iCAAW,EAAC,OAAO,CAAC,CAAC;YAC5C,MAAM,OAAO,GAAG,MAAM,IAAA,iCAAW,EAAC,OAAO,EAAE,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC;YAExF,MAAM,KAAK,GAAG,IAAA,oCAAc,EAAC,OAAO,CAAC,UAAU,CAAC,CAAC;YACjD,MAAM,KAAK,GAAG,IAAA,oCAAc,EAAC,OAAO,CAAC,UAAU,CAAC,CAAC;YACjD,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iEAAiE,EAAE,KAAK,IAAI,EAAE;YAC/E,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,IAAA,6CAAuB,EAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YACpF,MAAM,QAAQ,GAAG,MAAM,IAAA,iCAAW,EAAC,OAAO,CAAC,CAAC;YAC5C,MAAM,OAAO,GAAG,MAAM,IAAA,iCAAW,EAAC,OAAO,EAAE,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC;YAExF,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,IAAA,6CAAuB,EAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YACpF,MAAM,QAAQ,GAAG,MAAM,IAAA,iCAAW,EAAC,OAAO,CAAC,CAAC;YAC5C,MAAM,OAAO,GAAG,MAAM,IAAA,iCAAW,EAAC,OAAO,EAAE,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC;YAExF,MAAM,KAAK,GAAG,IAAA,oCAAc,EAAC,OAAO,CAAC,UAAU,CAAC,CAAC;YACjD,MAAM,KAAK,GAAG,IAAA,oCAAc,EAAC,OAAO,CAAC,UAAU,CAAC,CAAC;YACjD,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;QACpC,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;YAClE,MAAM,MAAM,GAAG,IAAA,kCAAY,GAAE,CAAC;YAC9B,MAAM,OAAO,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,CAAC,CAAC;YAE1C,MAAM,SAAS,GAAa,EAAE,CAAC;YAC/B,IAAI,GAAG,GAAG,OAAO,CAAC,WAAW,CAAC;YAC9B,IAAI,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC;YAEhC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC5B,wCAAwC;gBACxC,IAAI,IAAI,CAAC,YAAY,KAAK,gBAAgB,EAAE,CAAC;oBAC3C,IAAI,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,CAAC,EAAE,CAAC;wBACpC,MAAM,KAAK,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;wBACrC,MAAM,WAAW,GAAG,MAAM,IAAA,qCAAe,EAAC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;wBAC9E,MAAM,UAAU,GAAG,IAAA,4CAAsB,EAAC,WAAW,CAAC,CAAC;wBACvD,GAAG,GAAG,UAAU,CAAC,WAAW,CAAC;wBAC7B,IAAI,GAAG,UAAU,CAAC,YAAY,CAAC;wBAC/B,OAAO,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,CAAC,EAAE,CAAC;4BACvC,MAAM,SAAS,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;4BACzC,MAAM,WAAW,GAAG,MAAM,IAAA,qCAAe,EAAC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;4BAClF,MAAM,UAAU,GAAG,IAAA,4CAAsB,EAAC,WAAW,CAAC,CAAC;4BACvD,GAAG,GAAG,UAAU,CAAC,WAAW,CAAC;4BAC7B,IAAI,GAAG,UAAU,CAAC,YAAY,CAAC;wBACjC,CAAC;oBACH,CAAC;oBACD,IAAI,IAAI,CAAC,YAAY,KAAK,gBAAgB;wBAAE,MAAM;gBACpD,CAAC;gBAED,MAAM,MAAM,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;gBACpD,MAAM,IAAI,GAAG,IAAA,oCAAc,EAAC,MAAM,CAAC,UAAU,CAAC,CAAC;gBAC/C,MAAM,CAAC,IAAA,mCAAa,EAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACvC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAErB,GAAG,GAAG,MAAM,CAAC,WAAW,CAAC;gBACzB,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC;gBAE3B,IAAI,SAAS,CAAC,MAAM,IAAI,CAAC;oBAAE,MAAM;YACnC,CAAC;YAED,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;YACnD,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;YACxC,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACnD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;YACtD,MAAM,MAAM,GAAG,IAAA,kCAAY,GAAE,CAAC;YAC9B,MAAM,OAAO,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,CAAC,CAAC;YAE1C,IAAI,GAAG,GAAG,OAAO,CAAC,WAAW,CAAC;YAC9B,IAAI,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC;YAChC,IAAI,QAAQ,GAAG,IAAA,gCAAU,EAAC,SAAS,CAAC,CAAC;YAErC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC3B,MAAM,MAAM,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;gBACpD,MAAM,WAAW,GAAG,IAAA,oCAAc,EAAC,MAAM,CAAC,UAAU,CAAC,CAAC;gBACtD,MAAM,WAAW,GAAG,IAAA,gCAAU,EAAC,QAAQ,GAAG,WAAW,CAAC,CAAC;gBAEvD,MAAM,CAAC,IAAA,mCAAa,EAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC9C,QAAQ,GAAG,WAAW,CAAC;gBAEvB,GAAG,GAAG,MAAM,CAAC,WAAW,CAAC;gBACzB,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC;YAC7B,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;QACrC,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;YACjD,MAAM,MAAM,GAAG,IAAA,kCAAY,GAAE,CAAC;YAC9B,MAAM,OAAO,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,CAAC,CAAC;YAC1C,MAAM,MAAM,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,EAAE,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;YASpF,KAAK,MAAM,CAAC,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC,EAAE,CAAC;gBACjE,MAAM,GAAG,GAAG,MAA0B,CAAC;gBACvC,MAAM,CAAC,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBACzC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC1C,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;YAClD,MAAM,MAAM,GAAG,IAAA,kCAAY,GAAE,CAAC;YAC9B,MAAM,OAAO,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,CAAC,CAAC;YAC1C,MAAM,MAAM,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,EAAE,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;YASpF,KAAK,MAAM,CAAC,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC,EAAE,CAAC;gBACjE,MAAM,GAAG,GAAG,MAA0B,CAAC;gBACvC,MAAM,CAAC,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBACtC,MAAM,CAAC,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBACtC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,mBAAmB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC/C,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;YAChE,MAAM,MAAM,GAAG,IAAA,kCAAY,GAAE,CAAC;YAC9B,MAAM,OAAO,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,CAAC,CAAC;YAC1C,MAAM,MAAM,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,EAAE,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;YASpF,KAAK,MAAM,CAAC,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC,EAAE,CAAC;gBACjE,MAAM,GAAG,GAAG,MAA0B,CAAC;gBACvC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;gBAC/B,MAAM,CAAC,GAAG,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACrC,oCAAoC;gBACpC,MAAM,CAAC,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACpE,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;YACnE,MAAM,MAAM,GAAG,IAAA,kCAAY,GAAE,CAAC;YAC9B,MAAM,OAAO,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,CAAC,CAAC;YAE1C,IAAI,GAAG,GAAG,OAAO,CAAC,WAAW,CAAC;YAC9B,IAAI,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC;YAEhC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC5B,MAAM,MAAM,GAAG,MAAM,IAAA,iCAAW,EAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;gBACpD,MAAM,UAAU,GAAG,IAAA,wCAAkB,EAAC,MAAM,CAAC,UAAU,CAAC,CAAC;gBACzD,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAEpC,GAAG,GAAG,MAAM,CAAC,WAAW,CAAC;gBACzB,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC;YAC7B,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}