github-issue-tower-defence-management 1.82.0 → 1.83.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.
- package/.github/workflows/commit-lint.yml +7 -2
- package/.github/workflows/create-pr.yml +23 -5
- package/CHANGELOG.md +14 -0
- package/README.md +4 -4
- package/bin/domain/usecases/StartPreparationUseCase.js +70 -49
- package/bin/domain/usecases/StartPreparationUseCase.js.map +1 -1
- package/package.json +1 -1
- package/src/domain/usecases/StartPreparationUseCase.test.ts +594 -87
- package/src/domain/usecases/StartPreparationUseCase.ts +118 -78
- package/types/domain/usecases/StartPreparationUseCase.d.ts +1 -0
- package/types/domain/usecases/StartPreparationUseCase.d.ts.map +1 -1
|
@@ -61,6 +61,29 @@ export class StartPreparationUseCase {
|
|
|
61
61
|
return general !== undefined && general.rejected;
|
|
62
62
|
};
|
|
63
63
|
|
|
64
|
+
private selectModelForToken = (
|
|
65
|
+
usage: ClaudeTokenUsage,
|
|
66
|
+
defaultModelName: string | null,
|
|
67
|
+
fallbackModelName: string | null,
|
|
68
|
+
): string | null => {
|
|
69
|
+
const generalWeeklyLimit = usage.modelWeeklyLimits['seven_day'];
|
|
70
|
+
if (generalWeeklyLimit !== undefined && generalWeeklyLimit.rejected) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
const candidateModelNames = [defaultModelName, fallbackModelName].filter(
|
|
74
|
+
(modelName): modelName is string =>
|
|
75
|
+
modelName !== null && modelName !== '',
|
|
76
|
+
);
|
|
77
|
+
for (const candidateModelName of candidateModelNames) {
|
|
78
|
+
const weeklyLimitType = this.weeklyLimitTypeForModel(candidateModelName);
|
|
79
|
+
const specificWeeklyLimit = usage.modelWeeklyLimits[weeklyLimitType];
|
|
80
|
+
if (specificWeeklyLimit === undefined || !specificWeeklyLimit.rejected) {
|
|
81
|
+
return candidateModelName;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return null;
|
|
85
|
+
};
|
|
86
|
+
|
|
64
87
|
private secondsUntilSevenDayReset = (
|
|
65
88
|
usage: ClaudeTokenUsage,
|
|
66
89
|
weeklyLimitType: string,
|
|
@@ -79,18 +102,19 @@ export class StartPreparationUseCase {
|
|
|
79
102
|
|
|
80
103
|
private compareBySevenDayDeadlineThenUtilization = (
|
|
81
104
|
a: ClaudeTokenUsage,
|
|
105
|
+
aWeeklyLimitType: string,
|
|
82
106
|
b: ClaudeTokenUsage,
|
|
83
|
-
|
|
107
|
+
bWeeklyLimitType: string,
|
|
84
108
|
nowEpochSeconds: number,
|
|
85
109
|
): number => {
|
|
86
110
|
const aSecondsUntilReset = this.secondsUntilSevenDayReset(
|
|
87
111
|
a,
|
|
88
|
-
|
|
112
|
+
aWeeklyLimitType,
|
|
89
113
|
nowEpochSeconds,
|
|
90
114
|
);
|
|
91
115
|
const bSecondsUntilReset = this.secondsUntilSevenDayReset(
|
|
92
116
|
b,
|
|
93
|
-
|
|
117
|
+
bWeeklyLimitType,
|
|
94
118
|
nowEpochSeconds,
|
|
95
119
|
);
|
|
96
120
|
if (aSecondsUntilReset !== bSecondsUntilReset) {
|
|
@@ -128,31 +152,43 @@ export class StartPreparationUseCase {
|
|
|
128
152
|
private selectRotationTokens = (
|
|
129
153
|
tokenUsages: ClaudeTokenUsage[],
|
|
130
154
|
utilizationPercentageThreshold: number,
|
|
131
|
-
|
|
155
|
+
defaultModelName: string | null,
|
|
156
|
+
fallbackModelName: string | null,
|
|
132
157
|
maxConcurrent: number,
|
|
133
158
|
): {
|
|
134
159
|
tokens: string[];
|
|
135
160
|
effectiveCap: number;
|
|
136
|
-
tokensWithLimits: Array<{
|
|
161
|
+
tokensWithLimits: Array<{
|
|
162
|
+
token: string;
|
|
163
|
+
model: string;
|
|
164
|
+
limit: number;
|
|
165
|
+
secondsUntilSevenDayReset: number;
|
|
166
|
+
}>;
|
|
137
167
|
} => {
|
|
138
|
-
const weeklyLimitType = this.weeklyLimitTypeForModel(modelName);
|
|
139
168
|
const nowEpochSeconds = Date.now() / 1000;
|
|
140
169
|
const eligibleTokens = tokenUsages
|
|
141
170
|
.filter((usage) => !usage.blocked)
|
|
142
171
|
.filter((usage) => !usage.rejected)
|
|
143
172
|
.filter((usage) => !this.isWithinCooldown(usage, nowEpochSeconds))
|
|
144
|
-
.filter(
|
|
145
|
-
(usage) => !this.isModelWeeklyLimitRejected(usage, weeklyLimitType),
|
|
146
|
-
)
|
|
147
173
|
.filter(
|
|
148
174
|
(usage) =>
|
|
149
175
|
usage.fiveHourUtilization * 100 < utilizationPercentageThreshold,
|
|
150
176
|
)
|
|
177
|
+
.flatMap((usage) => {
|
|
178
|
+
const model = this.selectModelForToken(
|
|
179
|
+
usage,
|
|
180
|
+
defaultModelName,
|
|
181
|
+
fallbackModelName,
|
|
182
|
+
);
|
|
183
|
+
if (model === null) return [];
|
|
184
|
+
return [{ usage, model }];
|
|
185
|
+
})
|
|
151
186
|
.sort((a, b) =>
|
|
152
187
|
this.compareBySevenDayDeadlineThenUtilization(
|
|
153
|
-
a,
|
|
154
|
-
|
|
155
|
-
|
|
188
|
+
a.usage,
|
|
189
|
+
this.weeklyLimitTypeForModel(a.model),
|
|
190
|
+
b.usage,
|
|
191
|
+
this.weeklyLimitTypeForModel(b.model),
|
|
156
192
|
nowEpochSeconds,
|
|
157
193
|
),
|
|
158
194
|
);
|
|
@@ -161,12 +197,18 @@ export class StartPreparationUseCase {
|
|
|
161
197
|
return { tokens: [], effectiveCap: 0, tokensWithLimits: [] };
|
|
162
198
|
}
|
|
163
199
|
|
|
164
|
-
const tokensWithLimits = eligibleTokens.map((usage) => ({
|
|
200
|
+
const tokensWithLimits = eligibleTokens.map(({ usage, model }) => ({
|
|
165
201
|
token: usage.token,
|
|
202
|
+
model,
|
|
166
203
|
limit: this.getTokenConcurrentLimit(
|
|
167
204
|
usage.fiveHourUtilization,
|
|
168
205
|
usage.sevenDayUtilization,
|
|
169
206
|
),
|
|
207
|
+
secondsUntilSevenDayReset: this.secondsUntilSevenDayReset(
|
|
208
|
+
usage,
|
|
209
|
+
this.weeklyLimitTypeForModel(model),
|
|
210
|
+
nowEpochSeconds,
|
|
211
|
+
),
|
|
170
212
|
}));
|
|
171
213
|
|
|
172
214
|
const totalCapacity = tokensWithLimits.reduce((sum, t) => sum + t.limit, 0);
|
|
@@ -206,6 +248,7 @@ export class StartPreparationUseCase {
|
|
|
206
248
|
.sort((a, b) =>
|
|
207
249
|
this.compareBySevenDayDeadlineThenUtilization(
|
|
208
250
|
a,
|
|
251
|
+
weeklyLimitType,
|
|
209
252
|
b,
|
|
210
253
|
weeklyLimitType,
|
|
211
254
|
nowEpochSeconds,
|
|
@@ -261,7 +304,12 @@ export class StartPreparationUseCase {
|
|
|
261
304
|
await this.claudeTokenUsageRepository.getAvailableTokenUsages();
|
|
262
305
|
let rotationTokens: string[] | null = null;
|
|
263
306
|
let proxyBaseUrl: string | null = null;
|
|
264
|
-
let selectedTokensWithLimits: Array<{
|
|
307
|
+
let selectedTokensWithLimits: Array<{
|
|
308
|
+
token: string;
|
|
309
|
+
model: string;
|
|
310
|
+
limit: number;
|
|
311
|
+
secondsUntilSevenDayReset: number;
|
|
312
|
+
}> = [];
|
|
265
313
|
let tokenInFlightCounts: Record<string, number> = {};
|
|
266
314
|
const rotationOrder: RotationOrderEntry[] | null =
|
|
267
315
|
tokenUsages.length > 0
|
|
@@ -274,51 +322,23 @@ export class StartPreparationUseCase {
|
|
|
274
322
|
const maximumPreparingIssuesCount =
|
|
275
323
|
params.maximumPreparingIssuesCount ?? NORMAL_CONCURRENT_LIMIT;
|
|
276
324
|
let effectiveMaxPreparingIssuesCount = maximumPreparingIssuesCount;
|
|
277
|
-
|
|
325
|
+
const fallbackLlmModelName =
|
|
326
|
+
params.fallbackLlmModelName ?? DEFAULT_FALLBACK_LLM_MODEL_NAME;
|
|
278
327
|
if (tokenUsages.length > 0) {
|
|
279
328
|
const {
|
|
280
|
-
tokens:
|
|
281
|
-
effectiveCap,
|
|
282
|
-
tokensWithLimits:
|
|
329
|
+
tokens: selectedTokens,
|
|
330
|
+
effectiveCap: selectedCap,
|
|
331
|
+
tokensWithLimits: selectedTokensWithLimitsLocal,
|
|
283
332
|
} = this.selectRotationTokens(
|
|
284
333
|
tokenUsages,
|
|
285
334
|
params.utilizationPercentageThreshold,
|
|
286
335
|
params.defaultLlmModelName,
|
|
336
|
+
fallbackLlmModelName,
|
|
287
337
|
maximumPreparingIssuesCount,
|
|
288
338
|
);
|
|
289
|
-
let selectedTokens = ranked;
|
|
290
|
-
let selectedCap = effectiveCap;
|
|
291
|
-
let selectedTokensWithLimitsLocal = rankedTokensWithLimits;
|
|
292
|
-
if (
|
|
293
|
-
selectedTokens.length === 0 &&
|
|
294
|
-
this.weeklyLimitTypeForModel(params.defaultLlmModelName) ===
|
|
295
|
-
'seven_day_sonnet'
|
|
296
|
-
) {
|
|
297
|
-
const fallbackModelName =
|
|
298
|
-
params.fallbackLlmModelName ?? DEFAULT_FALLBACK_LLM_MODEL_NAME;
|
|
299
|
-
const {
|
|
300
|
-
tokens: fallbackRanked,
|
|
301
|
-
effectiveCap: fallbackCap,
|
|
302
|
-
tokensWithLimits: fallbackTokensWithLimits,
|
|
303
|
-
} = this.selectRotationTokens(
|
|
304
|
-
tokenUsages,
|
|
305
|
-
params.utilizationPercentageThreshold,
|
|
306
|
-
fallbackModelName,
|
|
307
|
-
maximumPreparingIssuesCount,
|
|
308
|
-
);
|
|
309
|
-
if (fallbackRanked.length > 0) {
|
|
310
|
-
console.warn(
|
|
311
|
-
`Sonnet 7-day weekly limit (${this.weeklyLimitTypeForModel(params.defaultLlmModelName)}) is exhausted across all configured Claude OAuth token(s). Falling back to ${fallbackModelName}.`,
|
|
312
|
-
);
|
|
313
|
-
selectedTokens = fallbackRanked;
|
|
314
|
-
selectedCap = fallbackCap;
|
|
315
|
-
selectedTokensWithLimitsLocal = fallbackTokensWithLimits;
|
|
316
|
-
effectiveDefaultLlmModelName = fallbackModelName;
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
339
|
if (selectedTokens.length === 0) {
|
|
320
340
|
console.warn(
|
|
321
|
-
`All ${tokenUsages.length} configured Claude OAuth token(s) are unavailable (blocked, rejected, weekly
|
|
341
|
+
`All ${tokenUsages.length} configured Claude OAuth token(s) are unavailable (blocked, rejected, weekly limits for the configured model(s) exhausted, or 5h utilization >= ${params.utilizationPercentageThreshold}%). Skipping starting preparation.`,
|
|
322
342
|
);
|
|
323
343
|
return { rotationOrder };
|
|
324
344
|
}
|
|
@@ -421,12 +441,15 @@ export class StartPreparationUseCase {
|
|
|
421
441
|
.trim() ||
|
|
422
442
|
params.defaultLlmAgentName ||
|
|
423
443
|
params.defaultAgentName;
|
|
424
|
-
const
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
444
|
+
const labelModelName = issue.labels
|
|
445
|
+
.find((label: string) => label.startsWith('llm-model:'))
|
|
446
|
+
?.replace('llm-model:', '')
|
|
447
|
+
.trim();
|
|
448
|
+
if (
|
|
449
|
+
!labelModelName &&
|
|
450
|
+
!params.defaultLlmModelName &&
|
|
451
|
+
rotationTokens === null
|
|
452
|
+
) {
|
|
430
453
|
console.error(
|
|
431
454
|
`No LLM model configured for issue ${issue.url}. Provide --defaultLlmModelName or add an llm-model: label.`,
|
|
432
455
|
);
|
|
@@ -509,41 +532,31 @@ export class StartPreparationUseCase {
|
|
|
509
532
|
);
|
|
510
533
|
issue.status = PREPARATION_STATUS_NAME;
|
|
511
534
|
|
|
512
|
-
const awArgs: string[] = [
|
|
513
|
-
issue.url,
|
|
514
|
-
agent,
|
|
515
|
-
model,
|
|
516
|
-
'--configFilePath',
|
|
517
|
-
params.configFilePath,
|
|
518
|
-
'--branch',
|
|
519
|
-
branchName,
|
|
520
|
-
];
|
|
521
|
-
if (
|
|
522
|
-
params.codexHomeCandidates !== null &&
|
|
523
|
-
params.codexHomeCandidates.length > 0
|
|
524
|
-
) {
|
|
525
|
-
const codexHome =
|
|
526
|
-
params.codexHomeCandidates[
|
|
527
|
-
startedInThisRunCount % params.codexHomeCandidates.length
|
|
528
|
-
];
|
|
529
|
-
awArgs.push('--codexHome', codexHome);
|
|
530
|
-
}
|
|
531
535
|
let spawnEnv: Record<string, string> | undefined;
|
|
536
|
+
let routedModelName: string | null = null;
|
|
532
537
|
if (rotationTokens !== null && proxyBaseUrl !== null) {
|
|
533
|
-
const
|
|
538
|
+
const tokenWithSoonestResetAmongAvailable = selectedTokensWithLimits
|
|
534
539
|
.map((t) => ({
|
|
535
540
|
token: t.token,
|
|
541
|
+
model: t.model,
|
|
536
542
|
remaining:
|
|
537
543
|
t.limit -
|
|
538
544
|
(tokenInFlightCounts[t.token] ?? 0) -
|
|
539
545
|
(spawnedInThisRunByToken[t.token] ?? 0),
|
|
546
|
+
secondsUntilSevenDayReset: t.secondsUntilSevenDayReset,
|
|
540
547
|
}))
|
|
541
548
|
.filter((t) => t.remaining > 0)
|
|
542
|
-
.sort((a, b) =>
|
|
543
|
-
|
|
549
|
+
.sort((a, b) => {
|
|
550
|
+
if (a.secondsUntilSevenDayReset !== b.secondsUntilSevenDayReset) {
|
|
551
|
+
return a.secondsUntilSevenDayReset - b.secondsUntilSevenDayReset;
|
|
552
|
+
}
|
|
553
|
+
return b.remaining - a.remaining;
|
|
554
|
+
})[0];
|
|
555
|
+
if (tokenWithSoonestResetAmongAvailable === undefined) {
|
|
544
556
|
break;
|
|
545
557
|
}
|
|
546
|
-
const selected =
|
|
558
|
+
const selected = tokenWithSoonestResetAmongAvailable.token;
|
|
559
|
+
routedModelName = tokenWithSoonestResetAmongAvailable.model;
|
|
547
560
|
spawnedInThisRunByToken[selected] =
|
|
548
561
|
(spawnedInThisRunByToken[selected] ?? 0) + 1;
|
|
549
562
|
spawnEnv = {
|
|
@@ -551,6 +564,33 @@ export class StartPreparationUseCase {
|
|
|
551
564
|
ANTHROPIC_BASE_URL: proxyBaseUrl,
|
|
552
565
|
};
|
|
553
566
|
}
|
|
567
|
+
const model =
|
|
568
|
+
labelModelName || routedModelName || params.defaultLlmModelName;
|
|
569
|
+
if (!model) {
|
|
570
|
+
console.error(
|
|
571
|
+
`No LLM model configured for issue ${issue.url}. Provide --defaultLlmModelName or add an llm-model: label.`,
|
|
572
|
+
);
|
|
573
|
+
continue;
|
|
574
|
+
}
|
|
575
|
+
const awArgs: string[] = [
|
|
576
|
+
issue.url,
|
|
577
|
+
agent,
|
|
578
|
+
model,
|
|
579
|
+
'--configFilePath',
|
|
580
|
+
params.configFilePath,
|
|
581
|
+
'--branch',
|
|
582
|
+
branchName,
|
|
583
|
+
];
|
|
584
|
+
if (
|
|
585
|
+
params.codexHomeCandidates !== null &&
|
|
586
|
+
params.codexHomeCandidates.length > 0
|
|
587
|
+
) {
|
|
588
|
+
const codexHome =
|
|
589
|
+
params.codexHomeCandidates[
|
|
590
|
+
startedInThisRunCount % params.codexHomeCandidates.length
|
|
591
|
+
];
|
|
592
|
+
awArgs.push('--codexHome', codexHome);
|
|
593
|
+
}
|
|
554
594
|
await this.localCommandRunner.runCommand(
|
|
555
595
|
'aw',
|
|
556
596
|
awArgs,
|
|
@@ -21,6 +21,7 @@ export declare class StartPreparationUseCase {
|
|
|
21
21
|
private weeklyLimitTypeForModel;
|
|
22
22
|
private isWithinCooldown;
|
|
23
23
|
private isModelWeeklyLimitRejected;
|
|
24
|
+
private selectModelForToken;
|
|
24
25
|
private secondsUntilSevenDayReset;
|
|
25
26
|
private compareBySevenDayDeadlineThenUtilization;
|
|
26
27
|
private taperedConcurrentLimit;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StartPreparationUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/StartPreparationUseCase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,EAAE,0BAA0B,EAAE,MAAM,iDAAiD,CAAC;AAC7F,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAShE,eAAO,MAAM,+BAA+B,oBAAoB,CAAC;AAEjE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,mBAAmB,EAAE,MAAM,CAAC;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,gBAAgB,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEF,qBAAa,uBAAuB;IAEhC,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAClC,OAAO,CAAC,QAAQ,CAAC,eAAe;IAUhC,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IACnC,OAAO,CAAC,QAAQ,CAAC,0BAA0B;gBAZ1B,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,EAAE,UAAU,CAAC,EACtD,eAAe,EAAE,IAAI,CACpC,eAAe,EACb,mBAAmB,GACnB,cAAc,GACd,oBAAoB,GACpB,oBAAoB,GACpB,kBAAkB,GAClB,yBAAyB,GACzB,oBAAoB,CACvB,EACgB,kBAAkB,EAAE,kBAAkB,EACtC,0BAA0B,EAAE,0BAA0B;IAGzE,OAAO,CAAC,uBAAuB,CAK7B;IAEF,OAAO,CAAC,gBAAgB,CAGgC;IAExD,OAAO,CAAC,0BAA0B,CAQhC;IAEF,OAAO,CAAC,yBAAyB,CAc/B;IAEF,OAAO,CAAC,wCAAwC,
|
|
1
|
+
{"version":3,"file":"StartPreparationUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/StartPreparationUseCase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,EAAE,0BAA0B,EAAE,MAAM,iDAAiD,CAAC;AAC7F,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAShE,eAAO,MAAM,+BAA+B,oBAAoB,CAAC;AAEjE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,mBAAmB,EAAE,MAAM,CAAC;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,gBAAgB,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEF,qBAAa,uBAAuB;IAEhC,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAClC,OAAO,CAAC,QAAQ,CAAC,eAAe;IAUhC,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IACnC,OAAO,CAAC,QAAQ,CAAC,0BAA0B;gBAZ1B,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,EAAE,UAAU,CAAC,EACtD,eAAe,EAAE,IAAI,CACpC,eAAe,EACb,mBAAmB,GACnB,cAAc,GACd,oBAAoB,GACpB,oBAAoB,GACpB,kBAAkB,GAClB,yBAAyB,GACzB,oBAAoB,CACvB,EACgB,kBAAkB,EAAE,kBAAkB,EACtC,0BAA0B,EAAE,0BAA0B;IAGzE,OAAO,CAAC,uBAAuB,CAK7B;IAEF,OAAO,CAAC,gBAAgB,CAGgC;IAExD,OAAO,CAAC,0BAA0B,CAQhC;IAEF,OAAO,CAAC,mBAAmB,CAqBzB;IAEF,OAAO,CAAC,yBAAyB,CAc/B;IAEF,OAAO,CAAC,wCAAwC,CAqB9C;IAEF,OAAO,CAAC,sBAAsB,CAS5B;IAEF,uBAAuB,GACrB,qBAAqB,MAAM,EAC3B,qBAAqB,MAAM,KAC1B,MAAM,CAUP;IAEF,OAAO,CAAC,oBAAoB,CA4E1B;IAEF,kBAAkB,GAChB,aAAa,gBAAgB,EAAE,EAC/B,gCAAgC,MAAM,EACtC,WAAW,MAAM,GAAG,IAAI,KACvB,kBAAkB,EAAE,CAqDrB;IAEF,GAAG,GAAU,QAAQ;QACnB,UAAU,EAAE,MAAM,CAAC;QACnB,gBAAgB,EAAE,MAAM,CAAC;QACzB,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;QACnC,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;QACpC,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;QACnC,cAAc,EAAE,MAAM,CAAC;QACvB,2BAA2B,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3C,8BAA8B,EAAE,MAAM,CAAC;QACvC,mBAAmB,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;QACrC,mBAAmB,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;QACrC,sBAAsB,EAAE,MAAM,CAAC;QAC/B,oBAAoB,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;KACvC,KAAG,OAAO,CAAC;QAAE,aAAa,EAAE,kBAAkB,EAAE,GAAG,IAAI,CAAA;KAAE,CAAC,CA6SzD;CACH"}
|