@aixnn/aixautots 0.0.0-stage → 0.5.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 +239 -2
- package/dist/ScriptStudio-DaCqOF5H.d.ts +43 -0
- package/dist/agent-runner-V60B0is1.d.ts +57 -0
- package/dist/automation-queue-8HqRJV_K.d.ts +72 -0
- package/dist/chunk-536WVCTB.js +5744 -0
- package/dist/chunk-5BMFMDQR.js +18 -0
- package/dist/chunk-64Q7BBIQ.js +1347 -0
- package/dist/chunk-6YUAACW6.js +866 -0
- package/dist/chunk-AIUOLJZA.js +412 -0
- package/dist/chunk-CVV7FOMQ.js +175 -0
- package/dist/chunk-EHF2WQUR.js +2042 -0
- package/dist/chunk-EVHTAXQG.js +273 -0
- package/dist/chunk-FW23FLAF.js +56 -0
- package/dist/chunk-GKEPMDXO.js +410 -0
- package/dist/chunk-H7MHGYF3.js +341 -0
- package/dist/chunk-MRQ7VJFJ.js +1074 -0
- package/dist/chunk-NWFYTFMI.js +65 -0
- package/dist/chunk-OEZFYKL6.js +1 -0
- package/dist/chunk-PCYERBNZ.js +1564 -0
- package/dist/chunk-PUPVZRKZ.js +668 -0
- package/dist/chunk-SUKFJ73W.js +217 -0
- package/dist/config-Bm1hmXhD.d.ts +1380 -0
- package/dist/coords-LPR_MPyp.d.ts +22 -0
- package/dist/core/index.d.ts +135 -0
- package/dist/core/index.js +5 -0
- package/dist/device-normalize-BaThgnH7.d.ts +43 -0
- package/dist/device-session-KZVGLPOI.js +2 -0
- package/dist/i18n/index.d.ts +30 -0
- package/dist/i18n/index.js +1 -0
- package/dist/mirror-session-C_1vFkRV.d.ts +108 -0
- package/dist/nav/index.d.ts +19 -0
- package/dist/nav/index.js +1 -0
- package/dist/react/index.d.ts +487 -0
- package/dist/react/index.js +7 -0
- package/dist/script-debugger-Cw5jVRoz.d.ts +114 -0
- package/dist/task-agent-runner-eD9-SCJz.d.ts +160 -0
- package/dist/types-C2WXVcam.d.ts +1005 -0
- package/dist/ui/billing.d.ts +48 -0
- package/dist/ui/billing.js +425 -0
- package/dist/ui/device-create.d.ts +55 -0
- package/dist/ui/device-create.js +9 -0
- package/dist/ui/device-mirror.d.ts +42 -0
- package/dist/ui/device-mirror.js +10 -0
- package/dist/ui/devices.d.ts +223 -0
- package/dist/ui/devices.js +15 -0
- package/dist/ui/editor.d.ts +64 -0
- package/dist/ui/editor.js +344 -0
- package/dist/ui/index.d.ts +104 -0
- package/dist/ui/index.js +676 -0
- package/dist/ui/inspector.d.ts +5 -0
- package/dist/ui/inspector.js +1250 -0
- package/dist/ui/market.d.ts +10 -0
- package/dist/ui/market.js +60 -0
- package/dist/ui/mirror.d.ts +52 -0
- package/dist/ui/mirror.js +3 -0
- package/dist/ui/primitives/index.d.ts +101 -0
- package/dist/ui/primitives/index.js +1 -0
- package/dist/ui/script-studio.d.ts +85 -0
- package/dist/ui/script-studio.js +10 -0
- package/dist/ui/scripts.d.ts +18 -0
- package/dist/ui/scripts.js +210 -0
- package/dist/ui/tasks.d.ts +10 -0
- package/dist/ui/tasks.js +1039 -0
- package/dist/use-script-run-Diay7ibY.d.ts +50 -0
- package/package.json +76 -4
- package/styles.css +97 -0
- package/tailwind-preset.cjs +84 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/** Run lifecycle status (mirrors the frontend runner store). */
|
|
2
|
+
type ScriptRunStatus = 'idle' | 'running' | 'paused' | 'completed' | 'failed';
|
|
3
|
+
/** Severity of a console line — drives the Logcat-style colour + level filter. */
|
|
4
|
+
type LogLevel = 'system' | 'error' | 'warn' | 'info' | 'debug';
|
|
5
|
+
/** One structured console line (colour by level, tag the device, filter/search). */
|
|
6
|
+
interface LogEntry {
|
|
7
|
+
/** ISO timestamp. */
|
|
8
|
+
ts: string;
|
|
9
|
+
level: LogLevel;
|
|
10
|
+
/** Originating device (per-device transitions), if any. */
|
|
11
|
+
device?: string;
|
|
12
|
+
msg: string;
|
|
13
|
+
}
|
|
14
|
+
/** A step/timeline event (kept for API parity with the frontend runner; the
|
|
15
|
+
* fleet backend has no step stream, so this stays empty in practice). */
|
|
16
|
+
interface StepEvent {
|
|
17
|
+
step_index: number;
|
|
18
|
+
step_type: string;
|
|
19
|
+
status: 'pending' | 'running' | 'success' | 'failed';
|
|
20
|
+
description?: string;
|
|
21
|
+
error?: string;
|
|
22
|
+
screenshot?: string;
|
|
23
|
+
timestamp: string;
|
|
24
|
+
}
|
|
25
|
+
interface UseScriptRun {
|
|
26
|
+
runId: string | null;
|
|
27
|
+
status: ScriptRunStatus;
|
|
28
|
+
progress: number;
|
|
29
|
+
steps: StepEvent[];
|
|
30
|
+
logs: LogEntry[];
|
|
31
|
+
error: string | null;
|
|
32
|
+
/** Submit a persisted script (fetched by id) to the selected devices. */
|
|
33
|
+
startRun(scriptId: string, deviceIds: string[]): Promise<void>;
|
|
34
|
+
/** Submit an inline script body (full file or a selected segment). */
|
|
35
|
+
runCode(code: string, language: string, variables: Record<string, unknown>, deviceIds: string[], platform?: string): Promise<void>;
|
|
36
|
+
stopRun(): Promise<void>;
|
|
37
|
+
pauseRun(): Promise<void>;
|
|
38
|
+
resumeRun(): Promise<void>;
|
|
39
|
+
clearLogs(): void;
|
|
40
|
+
reset(): void;
|
|
41
|
+
}
|
|
42
|
+
/** Single-device (or small fleet) script run with a Logcat-style console.
|
|
43
|
+
*
|
|
44
|
+
* Ports the frontend `useRunnerStore` engine into the SDK: it submits a script
|
|
45
|
+
* body via `fleet.start`, polls `fleet.get`, and turns every per-device status
|
|
46
|
+
* TRANSITION (and captured `output`) into a console `LogEntry`. Behaviourally
|
|
47
|
+
* identical to the store's `startWithBody`/`runCode`/`stop`/`pause`/`resume`. */
|
|
48
|
+
declare function useScriptRun(pollMs?: number): UseScriptRun;
|
|
49
|
+
|
|
50
|
+
export { type LogEntry as L, type ScriptRunStatus as S, type UseScriptRun as U, type StepEvent as a, type LogLevel as b, useScriptRun as u };
|
package/package.json
CHANGED
|
@@ -1,6 +1,78 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aixnn/aixautots",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
}
|
|
3
|
+
"version": "0.5.2",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"license": "UNLICENSED",
|
|
6
|
+
"publishConfig": { "access": "public", "registry": "https://registry.npmjs.org/" },
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"exports": {
|
|
9
|
+
"./core": { "types": "./dist/core/index.d.ts", "import": "./dist/core/index.js" },
|
|
10
|
+
"./react": { "types": "./dist/react/index.d.ts", "import": "./dist/react/index.js" },
|
|
11
|
+
"./ui": { "types": "./dist/ui/index.d.ts", "import": "./dist/ui/index.js" },
|
|
12
|
+
"./ui/mirror": { "types": "./dist/ui/mirror.d.ts", "import": "./dist/ui/mirror.js" },
|
|
13
|
+
"./ui/device-mirror": { "types": "./dist/ui/device-mirror.d.ts", "import": "./dist/ui/device-mirror.js" },
|
|
14
|
+
"./ui/device-create": { "types": "./dist/ui/device-create.d.ts", "import": "./dist/ui/device-create.js" },
|
|
15
|
+
"./ui/devices": { "types": "./dist/ui/devices.d.ts", "import": "./dist/ui/devices.js" },
|
|
16
|
+
"./ui/tasks": { "types": "./dist/ui/tasks.d.ts", "import": "./dist/ui/tasks.js" },
|
|
17
|
+
"./ui/billing": { "types": "./dist/ui/billing.d.ts", "import": "./dist/ui/billing.js" },
|
|
18
|
+
"./ui/market": { "types": "./dist/ui/market.d.ts", "import": "./dist/ui/market.js" },
|
|
19
|
+
"./ui/scripts": { "types": "./dist/ui/scripts.d.ts", "import": "./dist/ui/scripts.js" },
|
|
20
|
+
"./ui/editor": { "types": "./dist/ui/editor.d.ts", "import": "./dist/ui/editor.js" },
|
|
21
|
+
"./ui/inspector": { "types": "./dist/ui/inspector.d.ts", "import": "./dist/ui/inspector.js" },
|
|
22
|
+
"./ui/script-studio": { "types": "./dist/ui/script-studio.d.ts", "import": "./dist/ui/script-studio.js" },
|
|
23
|
+
"./ui/primitives": { "types": "./dist/ui/primitives/index.d.ts", "import": "./dist/ui/primitives/index.js" },
|
|
24
|
+
"./nav": { "types": "./dist/nav/index.d.ts", "import": "./dist/nav/index.js" },
|
|
25
|
+
"./i18n": { "types": "./dist/i18n/index.d.ts", "import": "./dist/i18n/index.js" },
|
|
26
|
+
"./tailwind-preset": "./tailwind-preset.cjs",
|
|
27
|
+
"./styles.css": "./styles.css"
|
|
28
|
+
},
|
|
29
|
+
"files": ["dist", "tailwind-preset.cjs", "styles.css"],
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "tsup",
|
|
32
|
+
"test": "vitest run",
|
|
33
|
+
"test:watch": "vitest",
|
|
34
|
+
"typecheck": "tsc --noEmit"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"clsx": "^2.1.1",
|
|
38
|
+
"tailwind-merge": "^2.5.0",
|
|
39
|
+
"class-variance-authority": "^0.7.0",
|
|
40
|
+
"@radix-ui/react-dialog": "^1.1.1"
|
|
41
|
+
},
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"react": "^18.3.0",
|
|
44
|
+
"lucide-react": "^0.441.0",
|
|
45
|
+
"@uiw/react-codemirror": "^4.23.0",
|
|
46
|
+
"@codemirror/lang-javascript": "^6.2.0",
|
|
47
|
+
"@xterm/xterm": "^5.5.0",
|
|
48
|
+
"@xterm/addon-fit": "^0.10.0"
|
|
49
|
+
},
|
|
50
|
+
"peerDependenciesMeta": {
|
|
51
|
+
"react": { "optional": true },
|
|
52
|
+
"lucide-react": { "optional": true },
|
|
53
|
+
"@uiw/react-codemirror": { "optional": true },
|
|
54
|
+
"@codemirror/lang-javascript": { "optional": true },
|
|
55
|
+
"@xterm/xterm": { "optional": true },
|
|
56
|
+
"@xterm/addon-fit": { "optional": true }
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"lucide-react": "^0.441.0",
|
|
60
|
+
"@radix-ui/react-dialog": "^1.1.1",
|
|
61
|
+
"clsx": "^2.1.1",
|
|
62
|
+
"tailwind-merge": "^2.5.0",
|
|
63
|
+
"class-variance-authority": "^0.7.0",
|
|
64
|
+
"@uiw/react-codemirror": "^4.23.0",
|
|
65
|
+
"@codemirror/lang-javascript": "^6.2.0",
|
|
66
|
+
"@xterm/xterm": "^5.5.0",
|
|
67
|
+
"@xterm/addon-fit": "^0.10.0",
|
|
68
|
+
"@testing-library/react": "^16.0.0",
|
|
69
|
+
"@types/node": "^26.2.0",
|
|
70
|
+
"@types/react": "^18.3.5",
|
|
71
|
+
"jsdom": "^25.0.0",
|
|
72
|
+
"react": "^18.3.1",
|
|
73
|
+
"react-dom": "^18.3.1",
|
|
74
|
+
"tsup": "^8.3.0",
|
|
75
|
+
"typescript": "^5.5.4",
|
|
76
|
+
"vitest": "^2.1.0"
|
|
77
|
+
}
|
|
78
|
+
}
|
package/styles.css
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* aixautots 默认主题 token。接入方在自己的入口 CSS 里:
|
|
3
|
+
* @import "@aixnn/aixautots/styles.css";
|
|
4
|
+
* 即可获得一套可用的浅色(:root) / 深色(.dark) 主题;覆盖任意 --token 即可换肤。
|
|
5
|
+
* 颜色值为 HSL 通道(与 tailwind-preset 的 `hsl(var(--token))` 配套)。
|
|
6
|
+
*
|
|
7
|
+
* 纯 CSS 变量,不含 @tailwind / @apply,可被任意构建直接 @import。
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/* ===== Light theme (默认 :root) ===== */
|
|
11
|
+
:root {
|
|
12
|
+
--background: 210 20% 98%;
|
|
13
|
+
--foreground: 222 47% 11%;
|
|
14
|
+
--surface: 0 0% 100%;
|
|
15
|
+
--card: 0 0% 100%;
|
|
16
|
+
--card-foreground: 222 47% 11%;
|
|
17
|
+
--popover: 0 0% 100%;
|
|
18
|
+
--popover-foreground: 222 47% 11%;
|
|
19
|
+
--primary: 217 91% 60%;
|
|
20
|
+
--primary-foreground: 0 0% 100%;
|
|
21
|
+
--secondary: 220 14% 96%;
|
|
22
|
+
--secondary-foreground: 222 47% 11%;
|
|
23
|
+
--muted: 220 14% 96%;
|
|
24
|
+
--muted-foreground: 220 9% 46%;
|
|
25
|
+
--accent: 220 14% 96%;
|
|
26
|
+
--accent-foreground: 222 47% 11%;
|
|
27
|
+
--destructive: 0 72% 51%;
|
|
28
|
+
--destructive-foreground: 0 0% 100%;
|
|
29
|
+
--success: 142 71% 45%;
|
|
30
|
+
--success-foreground: 0 0% 100%;
|
|
31
|
+
--warning: 38 92% 50%;
|
|
32
|
+
--warning-foreground: 0 0% 100%;
|
|
33
|
+
--border: 220 13% 91%;
|
|
34
|
+
--input: 220 13% 91%;
|
|
35
|
+
--ring: 217 91% 60%;
|
|
36
|
+
--radius: 0.5rem;
|
|
37
|
+
|
|
38
|
+
/* aixautots 既有组件(script-studio/CodeMirror 等)用的 --aix-* 变量:由语义 token 推导,
|
|
39
|
+
使其与整体主题一致。代码编辑器固定深色(常见做法)。 */
|
|
40
|
+
--aix-bg: hsl(var(--background));
|
|
41
|
+
--aix-fg: hsl(var(--foreground));
|
|
42
|
+
--aix-muted: hsl(var(--muted-foreground));
|
|
43
|
+
--aix-accent: hsl(var(--primary));
|
|
44
|
+
--aix-danger: hsl(var(--destructive));
|
|
45
|
+
--aix-border: hsl(var(--border));
|
|
46
|
+
--aix-radius: var(--radius);
|
|
47
|
+
--aix-font: "Inter", -apple-system, BlinkMacSystemFont, sans-serif;
|
|
48
|
+
--aix-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
49
|
+
--aix-editor-bg: #1e1e1e;
|
|
50
|
+
--aix-editor-fg: #d4d4d4;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* ===== Dark theme (.dark) ===== */
|
|
54
|
+
.dark {
|
|
55
|
+
--background: 0 0% 7%;
|
|
56
|
+
--foreground: 0 0% 93%;
|
|
57
|
+
--surface: 0 0% 9%;
|
|
58
|
+
--card: 0 0% 10%;
|
|
59
|
+
--card-foreground: 0 0% 93%;
|
|
60
|
+
--popover: 0 0% 10%;
|
|
61
|
+
--popover-foreground: 0 0% 93%;
|
|
62
|
+
--primary: 217 91% 60%;
|
|
63
|
+
--primary-foreground: 0 0% 100%;
|
|
64
|
+
--secondary: 0 0% 14%;
|
|
65
|
+
--secondary-foreground: 0 0% 80%;
|
|
66
|
+
--muted: 0 0% 14%;
|
|
67
|
+
--muted-foreground: 0 0% 55%;
|
|
68
|
+
--accent: 0 0% 14%;
|
|
69
|
+
--accent-foreground: 0 0% 93%;
|
|
70
|
+
--destructive: 0 84% 60%;
|
|
71
|
+
--destructive-foreground: 0 0% 100%;
|
|
72
|
+
--success: 142 69% 45%;
|
|
73
|
+
--success-foreground: 0 0% 100%;
|
|
74
|
+
--warning: 38 92% 50%;
|
|
75
|
+
--warning-foreground: 0 0% 0%;
|
|
76
|
+
--border: 0 0% 18%;
|
|
77
|
+
--input: 0 0% 18%;
|
|
78
|
+
--ring: 217 91% 60%;
|
|
79
|
+
--radius: 0.5rem;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* 细滚动条(可选,跟随 muted-foreground) */
|
|
83
|
+
.aix-scroll::-webkit-scrollbar,
|
|
84
|
+
::-webkit-scrollbar {
|
|
85
|
+
width: 6px;
|
|
86
|
+
height: 6px;
|
|
87
|
+
}
|
|
88
|
+
::-webkit-scrollbar-track {
|
|
89
|
+
background: transparent;
|
|
90
|
+
}
|
|
91
|
+
::-webkit-scrollbar-thumb {
|
|
92
|
+
background: hsl(var(--muted-foreground) / 0.3);
|
|
93
|
+
border-radius: 3px;
|
|
94
|
+
}
|
|
95
|
+
::-webkit-scrollbar-thumb:hover {
|
|
96
|
+
background: hsl(var(--muted-foreground) / 0.5);
|
|
97
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* aixautots 的 Tailwind 预设。接入方在自己的 tailwind.config 里:
|
|
3
|
+
* presets: [require('@aixnn/aixautots/tailwind-preset')]
|
|
4
|
+
* 即可获得 aixautots UI 组件依赖的全部语义 token(颜色/字号/间距/圆角),无需手抄。
|
|
5
|
+
*
|
|
6
|
+
* 颜色走 `hsl(var(--token))` 约定,token 的实际值由 `@aixnn/aixautots/styles.css` 提供
|
|
7
|
+
* (浅色 :root + 深色 .dark)。接入方覆盖 token 值即可换肤。
|
|
8
|
+
*
|
|
9
|
+
* 注意:接入方仍需在 content 里加入 aixautots(否则其类名不会被生成):
|
|
10
|
+
* content: [..., './node_modules/@aixnn/aixautots/dist/** /*.js'] // 或源码路径
|
|
11
|
+
*/
|
|
12
|
+
module.exports = {
|
|
13
|
+
darkMode: 'class',
|
|
14
|
+
theme: {
|
|
15
|
+
extend: {
|
|
16
|
+
colors: {
|
|
17
|
+
border: 'hsl(var(--border))',
|
|
18
|
+
input: 'hsl(var(--input))',
|
|
19
|
+
ring: 'hsl(var(--ring))',
|
|
20
|
+
background: 'hsl(var(--background))',
|
|
21
|
+
foreground: 'hsl(var(--foreground))',
|
|
22
|
+
surface: 'hsl(var(--surface))',
|
|
23
|
+
primary: {
|
|
24
|
+
DEFAULT: 'hsl(var(--primary))',
|
|
25
|
+
foreground: 'hsl(var(--primary-foreground))',
|
|
26
|
+
},
|
|
27
|
+
secondary: {
|
|
28
|
+
DEFAULT: 'hsl(var(--secondary))',
|
|
29
|
+
foreground: 'hsl(var(--secondary-foreground))',
|
|
30
|
+
},
|
|
31
|
+
destructive: {
|
|
32
|
+
DEFAULT: 'hsl(var(--destructive))',
|
|
33
|
+
foreground: 'hsl(var(--destructive-foreground))',
|
|
34
|
+
},
|
|
35
|
+
success: {
|
|
36
|
+
DEFAULT: 'hsl(var(--success))',
|
|
37
|
+
foreground: 'hsl(var(--success-foreground))',
|
|
38
|
+
},
|
|
39
|
+
warning: {
|
|
40
|
+
DEFAULT: 'hsl(var(--warning))',
|
|
41
|
+
foreground: 'hsl(var(--warning-foreground))',
|
|
42
|
+
},
|
|
43
|
+
muted: {
|
|
44
|
+
DEFAULT: 'hsl(var(--muted))',
|
|
45
|
+
foreground: 'hsl(var(--muted-foreground))',
|
|
46
|
+
},
|
|
47
|
+
accent: {
|
|
48
|
+
DEFAULT: 'hsl(var(--accent))',
|
|
49
|
+
foreground: 'hsl(var(--accent-foreground))',
|
|
50
|
+
},
|
|
51
|
+
popover: {
|
|
52
|
+
DEFAULT: 'hsl(var(--popover))',
|
|
53
|
+
foreground: 'hsl(var(--popover-foreground))',
|
|
54
|
+
},
|
|
55
|
+
card: {
|
|
56
|
+
DEFAULT: 'hsl(var(--card))',
|
|
57
|
+
foreground: 'hsl(var(--card-foreground))',
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
fontFamily: {
|
|
61
|
+
sans: ['"Inter"', '-apple-system', 'BlinkMacSystemFont', 'sans-serif'],
|
|
62
|
+
mono: ['"JetBrains Mono"', 'ui-monospace', 'SFMono-Regular', 'monospace'],
|
|
63
|
+
},
|
|
64
|
+
fontSize: {
|
|
65
|
+
'headline-lg': ['24px', { lineHeight: '32px', letterSpacing: '-0.02em', fontWeight: '600' }],
|
|
66
|
+
'headline-md': ['18px', { lineHeight: '24px', letterSpacing: '-0.01em', fontWeight: '600' }],
|
|
67
|
+
'body-md': ['14px', { lineHeight: '20px' }],
|
|
68
|
+
'body-sm': ['13px', { lineHeight: '18px' }],
|
|
69
|
+
'code-md': ['13px', { lineHeight: '20px' }],
|
|
70
|
+
'code-sm': ['12px', { lineHeight: '18px' }],
|
|
71
|
+
'label-caps': ['11px', { lineHeight: '16px', letterSpacing: '0.05em', fontWeight: '700' }],
|
|
72
|
+
},
|
|
73
|
+
spacing: {
|
|
74
|
+
sidebar: '240px',
|
|
75
|
+
header: '56px',
|
|
76
|
+
},
|
|
77
|
+
borderRadius: {
|
|
78
|
+
lg: 'var(--radius)',
|
|
79
|
+
md: 'calc(var(--radius) - 2px)',
|
|
80
|
+
sm: 'calc(var(--radius) - 4px)',
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
}
|