@milldr/crono 0.3.0 → 0.3.2
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/README.md +20 -3
- package/dist/kernel/diary.d.ts +3 -3
- package/dist/kernel/diary.d.ts.map +1 -1
- package/dist/kernel/diary.js +31 -29
- package/dist/kernel/diary.js.map +1 -1
- package/dist/kernel/quick-add.d.ts.map +1 -1
- package/dist/kernel/quick-add.js +19 -8
- package/dist/kernel/quick-add.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,6 +8,12 @@ Cronometer has no public API, so crono automates the web UI through Kernel.sh br
|
|
|
8
8
|
|
|
9
9
|

|
|
10
10
|
|
|
11
|
+
## Motivation
|
|
12
|
+
|
|
13
|
+
Cronometer is great for logging food — barcode scanning and manual search cover most meals at home. But when you're eating out or don't have a barcode, the workflow gets clunky: take a photo, ask an AI to estimate the macros, then manually punch those numbers into the app as a quick add.
|
|
14
|
+
|
|
15
|
+
crono closes that loop. Give your AI agent a skill that knows how to call crono, and it goes from estimating macros to actually logging them — no manual step in between. On top of that, your agent can query your diary, pull export data, and answer questions about your nutrition without you ever opening the app.
|
|
16
|
+
|
|
11
17
|
## Quickstart
|
|
12
18
|
|
|
13
19
|
### 1. Install
|
|
@@ -49,7 +55,7 @@ You'll be prompted for three things:
|
|
|
49
55
|
### 3. Log a meal
|
|
50
56
|
|
|
51
57
|
```bash
|
|
52
|
-
crono quick-add -p 30 -c 100 -f 20 -m Dinner
|
|
58
|
+
crono quick-add -p 30 -c 100 -f 20 -a 14 -m Dinner -d yesterday
|
|
53
59
|
```
|
|
54
60
|
|
|
55
61
|
```
|
|
@@ -58,7 +64,7 @@ crono quick-add -p 30 -c 100 -f 20 -m Dinner
|
|
|
58
64
|
◒ Logging into Cronometer...
|
|
59
65
|
◇ Done.
|
|
60
66
|
│
|
|
61
|
-
└ Added: 30g protein, 100g carbs, 20g fat → Dinner
|
|
67
|
+
└ Added: 30g protein, 100g carbs, 20g fat, 14g alcohol → Dinner on 2026-02-15
|
|
62
68
|
```
|
|
63
69
|
|
|
64
70
|
## Commands
|
|
@@ -86,9 +92,11 @@ crono quick-add [options]
|
|
|
86
92
|
| `-p` | `--protein <g>` | Grams of protein |
|
|
87
93
|
| `-c` | `--carbs <g>` | Grams of carbohydrates |
|
|
88
94
|
| `-f` | `--fat <g>` | Grams of fat |
|
|
95
|
+
| `-a` | `--alcohol <g>` | Grams of alcohol |
|
|
89
96
|
| `-m` | `--meal <name>` | Meal category (Breakfast, Lunch, Dinner, Snacks) |
|
|
97
|
+
| `-d` | `--date <date>` | Date (YYYY-MM-DD, yesterday, -1d) |
|
|
90
98
|
|
|
91
|
-
At least one macro flag (`-p`, `-c`, or `-
|
|
99
|
+
At least one macro flag (`-p`, `-c`, `-f`, or `-a`) is required.
|
|
92
100
|
|
|
93
101
|
**Examples:**
|
|
94
102
|
|
|
@@ -101,6 +109,15 @@ crono quick-add -p 30 -c 100 -f 20
|
|
|
101
109
|
|
|
102
110
|
# Log to Dinner category
|
|
103
111
|
crono quick-add -p 30 -c 50 -f 15 --meal Dinner
|
|
112
|
+
|
|
113
|
+
# Log to yesterday
|
|
114
|
+
crono quick-add -p 30 -d yesterday -m Dinner
|
|
115
|
+
|
|
116
|
+
# Log alcohol
|
|
117
|
+
crono quick-add -a 14 -m Dinner
|
|
118
|
+
|
|
119
|
+
# Combine everything
|
|
120
|
+
crono quick-add -p 30 -c 50 -f 10 -a 14 -d -3d -m Dinner
|
|
104
121
|
```
|
|
105
122
|
|
|
106
123
|
### `crono add custom-food`
|
package/dist/kernel/diary.d.ts
CHANGED
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
* navigate to diary → set date via prev/next arrows → read nutrition totals
|
|
13
13
|
*
|
|
14
14
|
* Cronometer diary layout (energy summary):
|
|
15
|
-
*
|
|
16
|
-
* "
|
|
17
|
-
*
|
|
15
|
+
* The Energy Summary section shows daily totals like:
|
|
16
|
+
* "Energy 1847 kcal", "Protein 168 g", "Carbs 200 g", "Fat 60 g"
|
|
17
|
+
* Per-meal summaries are also present but may include non-food rows.
|
|
18
18
|
*
|
|
19
19
|
* Returns { success: true, entries: [{ date, calories, protein, carbs, fat }] }
|
|
20
20
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diary.d.ts","sourceRoot":"","sources":["../../src/kernel/diary.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"diary.d.ts","sourceRoot":"","sources":["../../src/kernel/diary.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAyItD"}
|
package/dist/kernel/diary.js
CHANGED
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
* navigate to diary → set date via prev/next arrows → read nutrition totals
|
|
13
13
|
*
|
|
14
14
|
* Cronometer diary layout (energy summary):
|
|
15
|
-
*
|
|
16
|
-
* "
|
|
17
|
-
*
|
|
15
|
+
* The Energy Summary section shows daily totals like:
|
|
16
|
+
* "Energy 1847 kcal", "Protein 168 g", "Carbs 200 g", "Fat 60 g"
|
|
17
|
+
* Per-meal summaries are also present but may include non-food rows.
|
|
18
18
|
*
|
|
19
19
|
* Returns { success: true, entries: [{ date, calories, protein, carbs, fat }] }
|
|
20
20
|
*/
|
|
@@ -63,26 +63,44 @@ export function buildDiaryCode(dates) {
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
// Helper: extract nutrition totals from the currently displayed diary page.
|
|
66
|
-
// Cronometer shows
|
|
67
|
-
//
|
|
68
|
-
//
|
|
66
|
+
// Cronometer shows an Energy Summary section with daily totals
|
|
67
|
+
// ("Energy X kcal", "Protein X g", etc.) and per-meal summary lines
|
|
68
|
+
// ("302 kcal • 1 g protein • 8 g carbs • 0 g fat").
|
|
69
|
+
//
|
|
70
|
+
// We prefer the Energy Summary totals (Strategy 1) because the
|
|
71
|
+
// per-meal summary regex can match non-food rows (exercise, targets)
|
|
72
|
+
// and inflate the calorie count. See: https://github.com/milldr/crono/issues/20
|
|
69
73
|
async function extractNutrition() {
|
|
70
74
|
return await page.evaluate(() => {
|
|
71
75
|
const bodyText = document.body.innerText;
|
|
72
76
|
|
|
73
|
-
// Strategy 1: Look for the Energy Summary
|
|
74
|
-
// Cronometer
|
|
75
|
-
//
|
|
77
|
+
// Strategy 1: Look for individual nutrient totals in the Energy Summary.
|
|
78
|
+
// Cronometer displays "Energy 1847 kcal", "Protein 168 g", etc.
|
|
79
|
+
// .match() returns the first occurrence — the daily total.
|
|
80
|
+
const calMatch = bodyText.match(/Energy\\s+(\\d+\\.?\\d*)\\s*kcal/i);
|
|
81
|
+
const protMatch = bodyText.match(/Protein\\s+(\\d+\\.?\\d*)\\s*g/i);
|
|
82
|
+
const carbMatch = bodyText.match(/Carbs\\s+(\\d+\\.?\\d*)\\s*g/i);
|
|
83
|
+
const fatMatch = bodyText.match(/Fat\\s+(\\d+\\.?\\d*)\\s*g/i);
|
|
84
|
+
|
|
85
|
+
if (calMatch || protMatch || carbMatch || fatMatch) {
|
|
86
|
+
return {
|
|
87
|
+
calories: calMatch ? Math.round(parseFloat(calMatch[1])) : 0,
|
|
88
|
+
protein: protMatch ? Math.round(parseFloat(protMatch[1])) : 0,
|
|
89
|
+
carbs: carbMatch ? Math.round(parseFloat(carbMatch[1])) : 0,
|
|
90
|
+
fat: fatMatch ? Math.round(parseFloat(fatMatch[1])) : 0,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Strategy 2 (fallback): Sum per-meal summary lines.
|
|
95
|
+
// Each line matches: "N kcal • N g protein • N g carbs • N g fat"
|
|
96
|
+
const mealPattern = /(\\d+\\.?\\d*)\\s*kcal\\s*[•·]\\s*(\\d+\\.?\\d*)\\s*g\\s*protein\\s*[•·]\\s*(\\d+\\.?\\d*)\\s*g\\s*carbs\\s*[•·]\\s*(\\d+\\.?\\d*)\\s*g\\s*fat/gi;
|
|
76
97
|
let calories = 0;
|
|
77
98
|
let protein = 0;
|
|
78
99
|
let carbs = 0;
|
|
79
100
|
let fat = 0;
|
|
80
101
|
let found = false;
|
|
81
|
-
|
|
82
|
-
// Strategy 2: Sum all meal category summary lines.
|
|
83
|
-
// Each line matches: "N kcal • N g protein • N g carbs • N g fat"
|
|
84
|
-
const mealPattern = /(\\d+\\.?\\d*)\\s*kcal\\s*[•·]\\s*(\\d+\\.?\\d*)\\s*g\\s*protein\\s*[•·]\\s*(\\d+\\.?\\d*)\\s*g\\s*carbs\\s*[•·]\\s*(\\d+\\.?\\d*)\\s*g\\s*fat/gi;
|
|
85
102
|
let match;
|
|
103
|
+
|
|
86
104
|
while ((match = mealPattern.exec(bodyText)) !== null) {
|
|
87
105
|
calories += parseFloat(match[1]);
|
|
88
106
|
protein += parseFloat(match[2]);
|
|
@@ -100,22 +118,6 @@ export function buildDiaryCode(dates) {
|
|
|
100
118
|
};
|
|
101
119
|
}
|
|
102
120
|
|
|
103
|
-
// Strategy 3: Look for individual nutrient totals in the page.
|
|
104
|
-
// Cronometer may display "Energy 1847 kcal" and "Protein 168 g" etc.
|
|
105
|
-
const calMatch = bodyText.match(/Energy\\s+(\\d+\\.?\\d*)\\s*kcal/i);
|
|
106
|
-
const protMatch = bodyText.match(/Protein\\s+(\\d+\\.?\\d*)\\s*g/i);
|
|
107
|
-
const carbMatch = bodyText.match(/Carbs\\s+(\\d+\\.?\\d*)\\s*g/i);
|
|
108
|
-
const fatMatch = bodyText.match(/Fat\\s+(\\d+\\.?\\d*)\\s*g/i);
|
|
109
|
-
|
|
110
|
-
if (calMatch || protMatch || carbMatch || fatMatch) {
|
|
111
|
-
return {
|
|
112
|
-
calories: calMatch ? Math.round(parseFloat(calMatch[1])) : 0,
|
|
113
|
-
protein: protMatch ? Math.round(parseFloat(protMatch[1])) : 0,
|
|
114
|
-
carbs: carbMatch ? Math.round(parseFloat(carbMatch[1])) : 0,
|
|
115
|
-
fat: fatMatch ? Math.round(parseFloat(fatMatch[1])) : 0,
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
|
|
119
121
|
// No nutrition data found — empty diary day
|
|
120
122
|
return { calories: 0, protein: 0, carbs: 0, fat: 0 };
|
|
121
123
|
});
|
package/dist/kernel/diary.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diary.js","sourceRoot":"","sources":["../../src/kernel/diary.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,cAAc,CAAC,KAAe;IAC5C,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAExC,OAAO;oBACW,SAAS
|
|
1
|
+
{"version":3,"file":"diary.js","sourceRoot":"","sources":["../../src/kernel/diary.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,cAAc,CAAC,KAAe;IAC5C,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAExC,OAAO;oBACW,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoI1B,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quick-add.d.ts","sourceRoot":"","sources":["../../src/kernel/quick-add.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C;;;GAGG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAKrD,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"quick-add.d.ts","sourceRoot":"","sources":["../../src/kernel/quick-add.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C;;;GAGG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAKrD,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAmR3D"}
|
package/dist/kernel/quick-add.js
CHANGED
|
@@ -93,7 +93,7 @@ export function buildQuickAddCode(entry) {
|
|
|
93
93
|
try {
|
|
94
94
|
const el = page.locator(sel);
|
|
95
95
|
if (await el.count() > 0) {
|
|
96
|
-
await el.first().click();
|
|
96
|
+
await el.first().click({ timeout: 5000 });
|
|
97
97
|
return true;
|
|
98
98
|
}
|
|
99
99
|
} catch {}
|
|
@@ -107,7 +107,7 @@ export function buildQuickAddCode(entry) {
|
|
|
107
107
|
try {
|
|
108
108
|
const el = page.locator(sel);
|
|
109
109
|
if (await el.count() > 0) {
|
|
110
|
-
await el.first().click({ button: 'right' });
|
|
110
|
+
await el.first().click({ button: 'right', timeout: 5000 });
|
|
111
111
|
return true;
|
|
112
112
|
}
|
|
113
113
|
} catch {}
|
|
@@ -125,9 +125,12 @@ export function buildQuickAddCode(entry) {
|
|
|
125
125
|
if (!clicked) {
|
|
126
126
|
return { success: false, error: 'Could not find meal category "' + mealLabel + '" in diary' };
|
|
127
127
|
}
|
|
128
|
-
await page.waitForSelector('text="Add Food..."', { timeout: 3000 })
|
|
129
|
-
|
|
130
|
-
|
|
128
|
+
const menuVisible = await page.waitForSelector('text="Add Food..."', { timeout: 3000 })
|
|
129
|
+
.then(() => true)
|
|
130
|
+
.catch(() => page.waitForSelector('text="Add Food"', { timeout: 2000 }).then(() => true).catch(() => false));
|
|
131
|
+
if (!menuVisible) {
|
|
132
|
+
return { success: false, error: 'Context menu did not appear after right-clicking "' + mealLabel + '"' };
|
|
133
|
+
}
|
|
131
134
|
|
|
132
135
|
// Click "Add Food..." in context menu
|
|
133
136
|
const addFoodClicked = await clickFirst([
|
|
@@ -185,7 +188,11 @@ export function buildQuickAddCode(entry) {
|
|
|
185
188
|
'button:has-text("SEARCH")',
|
|
186
189
|
'button:has-text("Search")',
|
|
187
190
|
]);
|
|
188
|
-
await page.waitForSelector('td:has-text("' + macro.searchName + '")', { timeout: 8000 })
|
|
191
|
+
const resultsAppeared = await page.waitForSelector('td:has-text("' + macro.searchName + '")', { timeout: 8000 })
|
|
192
|
+
.then(() => true).catch(() => false);
|
|
193
|
+
if (!resultsAppeared) {
|
|
194
|
+
return { success: false, error: 'Search results did not appear for "' + macro.searchName + '"' };
|
|
195
|
+
}
|
|
189
196
|
|
|
190
197
|
// Select the search result row (not the search input)
|
|
191
198
|
// Target table rows/cells containing the macro name
|
|
@@ -276,8 +283,12 @@ export function buildQuickAddCode(entry) {
|
|
|
276
283
|
if (!addClicked) {
|
|
277
284
|
return { success: false, error: 'Could not find "Add to Diary" button for "' + macro.name + '"' };
|
|
278
285
|
}
|
|
279
|
-
await page.waitForSelector('text="Add Food to Diary"', { state: 'hidden', timeout: 8000 })
|
|
280
|
-
|
|
286
|
+
const dialogDismissed = await page.waitForSelector('text="Add Food to Diary"', { state: 'hidden', timeout: 8000 })
|
|
287
|
+
.then(() => true).catch(() => false);
|
|
288
|
+
if (!dialogDismissed) {
|
|
289
|
+
return { success: false, error: '"Add Food to Diary" dialog did not close after adding "' + macro.name + '"' };
|
|
290
|
+
}
|
|
291
|
+
await page.waitForTimeout(500);
|
|
281
292
|
}
|
|
282
293
|
|
|
283
294
|
return { success: true };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quick-add.js","sourceRoot":"","sources":["../../src/kernel/quick-add.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;;GAGG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAA2B;IACxD,OAAO,EAAE,oBAAoB;IAC7B,KAAK,EAAE,yBAAyB;IAChC,GAAG,EAAE,gBAAgB;IACrB,OAAO,EAAE,oBAAoB;CAC9B,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAiB;IACjD,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC;IAE3D,MAAM,SAAS,GAAG,IAAI;QACpB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE;QAC5D,CAAC,CAAC,eAAe,CAAC;IAEpB,8BAA8B;IAC9B,MAAM,MAAM,GAA0D,EAAE,CAAC;IACzE,IAAI,OAAO,KAAK,SAAS;QACvB,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,SAAS;YACf,UAAU,EAAE,kBAAkB,CAAC,OAAO;YACtC,KAAK,EAAE,OAAO;SACf,CAAC,CAAC;IACL,IAAI,KAAK,KAAK,SAAS;QACrB,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,OAAO;YACb,UAAU,EAAE,kBAAkB,CAAC,KAAK;YACpC,KAAK,EAAE,KAAK;SACb,CAAC,CAAC;IACL,IAAI,GAAG,KAAK,SAAS;QACnB,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,KAAK;YACX,UAAU,EAAE,kBAAkB,CAAC,GAAG;YAClC,KAAK,EAAE,GAAG;SACX,CAAC,CAAC;IACL,IAAI,OAAO,KAAK,SAAS;QACvB,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,SAAS;YACf,UAAU,EAAE,kBAAkB,CAAC,OAAO;YACtC,KAAK,EAAE,OAAO;SACf,CAAC,CAAC;IAEL,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAE1C,OAAO;qBACY,UAAU;wBACP,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC;yBACxB,IAAI,CAAC,SAAS,CAAC,IAAI,IAAI,IAAI,CAAC
|
|
1
|
+
{"version":3,"file":"quick-add.js","sourceRoot":"","sources":["../../src/kernel/quick-add.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;;GAGG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAA2B;IACxD,OAAO,EAAE,oBAAoB;IAC7B,KAAK,EAAE,yBAAyB;IAChC,GAAG,EAAE,gBAAgB;IACrB,OAAO,EAAE,oBAAoB;CAC9B,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAiB;IACjD,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC;IAE3D,MAAM,SAAS,GAAG,IAAI;QACpB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE;QAC5D,CAAC,CAAC,eAAe,CAAC;IAEpB,8BAA8B;IAC9B,MAAM,MAAM,GAA0D,EAAE,CAAC;IACzE,IAAI,OAAO,KAAK,SAAS;QACvB,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,SAAS;YACf,UAAU,EAAE,kBAAkB,CAAC,OAAO;YACtC,KAAK,EAAE,OAAO;SACf,CAAC,CAAC;IACL,IAAI,KAAK,KAAK,SAAS;QACrB,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,OAAO;YACb,UAAU,EAAE,kBAAkB,CAAC,KAAK;YACpC,KAAK,EAAE,KAAK;SACb,CAAC,CAAC;IACL,IAAI,GAAG,KAAK,SAAS;QACnB,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,KAAK;YACX,UAAU,EAAE,kBAAkB,CAAC,GAAG;YAClC,KAAK,EAAE,GAAG;SACX,CAAC,CAAC;IACL,IAAI,OAAO,KAAK,SAAS;QACvB,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,SAAS;YACf,UAAU,EAAE,kBAAkB,CAAC,OAAO;YACtC,KAAK,EAAE,OAAO;SACf,CAAC,CAAC;IAEL,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAE1C,OAAO;qBACY,UAAU;wBACP,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC;yBACxB,IAAI,CAAC,SAAS,CAAC,IAAI,IAAI,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2OlD,CAAC;AACJ,CAAC"}
|