@astur-mobile/core 0.1.0-beta.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.
@@ -0,0 +1,22 @@
1
+ import type { NativeAgentCommandParams, NativeAgentCommandResponse, NativeAgentInfo, NativeAgentMethod, PlatformName } from '@astur-mobile/protocol';
2
+ export interface NativeAgentClient {
3
+ readonly endpoint: string;
4
+ readonly platform: PlatformName;
5
+ readonly info: NativeAgentInfo;
6
+ readonly commandTimeout: number;
7
+ command<M extends NativeAgentMethod>(method: M, params?: NativeAgentCommandParams<M>): Promise<NativeAgentCommandResponse<M>>;
8
+ }
9
+ export interface NativeAgentClientOptions {
10
+ endpoint: string;
11
+ platform: PlatformName;
12
+ /**
13
+ * Legacy timeout that applies to both handshake and commands when specific values are omitted.
14
+ */
15
+ timeout?: number;
16
+ commandTimeout?: number;
17
+ handshakeTimeout?: number;
18
+ fetchImpl?: typeof fetch;
19
+ }
20
+ export declare function connectNativeAgentClient(options: NativeAgentClientOptions): Promise<NativeAgentClient>;
21
+ export declare function normalizeNativeAgentEndpoint(endpoint: string): string;
22
+ //# sourceMappingURL=agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,wBAAwB,EACxB,0BAA0B,EAE1B,eAAe,EACf,iBAAiB,EACjB,YAAY,EACb,MAAM,wBAAwB,CAAC;AAGhC,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAC/B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,OAAO,CAAC,CAAC,SAAS,iBAAiB,EACjC,MAAM,EAAE,CAAC,EACT,MAAM,CAAC,EAAE,wBAAwB,CAAC,CAAC,CAAC,GACnC,OAAO,CAAC,0BAA0B,CAAC,CAAC,CAAC,CAAC,CAAC;CAC3C;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,YAAY,CAAC;IACvB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAYD,wBAAsB,wBAAwB,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA6B5G;AAED,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CA4BrE"}
package/dist/agent.js ADDED
@@ -0,0 +1,147 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { AsturError } from './errors.js';
3
+ export async function connectNativeAgentClient(options) {
4
+ const client = createNativeAgentClient(options);
5
+ const commandTimeout = options.commandTimeout ?? options.timeout ?? 10_000;
6
+ const handshakeTimeout = options.handshakeTimeout ?? options.timeout ?? commandTimeout;
7
+ const handshakeClient = handshakeTimeout === commandTimeout
8
+ ? client
9
+ : createNativeAgentClient({
10
+ ...options,
11
+ commandTimeout: handshakeTimeout
12
+ });
13
+ const info = await handshakeClient.command('agent.ping');
14
+ if (info.platform !== options.platform) {
15
+ throw new AsturError('AGENT_PLATFORM_MISMATCH', `Native agent at ${client.endpoint} reported platform ${info.platform}, expected ${options.platform}.`, {
16
+ endpoint: client.endpoint,
17
+ expectedPlatform: options.platform,
18
+ reportedPlatform: info.platform,
19
+ info
20
+ });
21
+ }
22
+ return {
23
+ ...client,
24
+ info
25
+ };
26
+ }
27
+ export function normalizeNativeAgentEndpoint(endpoint) {
28
+ const trimmed = endpoint.trim();
29
+ if (!trimmed) {
30
+ throw new AsturError('AGENT_ENDPOINT_INVALID', 'Native agent endpoint must not be empty.');
31
+ }
32
+ const candidate = trimmed.startsWith('tcp:')
33
+ ? `http://${trimmed.slice('tcp:'.length)}`
34
+ : /^[a-z][a-z0-9+.-]*:/i.test(trimmed)
35
+ ? trimmed
36
+ : `http://${trimmed}`;
37
+ let parsed;
38
+ try {
39
+ parsed = new URL(candidate);
40
+ }
41
+ catch {
42
+ throw new AsturError('AGENT_ENDPOINT_INVALID', `Invalid native agent endpoint: ${endpoint}`);
43
+ }
44
+ if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
45
+ throw new AsturError('AGENT_ENDPOINT_UNSUPPORTED_PROTOCOL', `Native agent endpoint must use http or https, got ${parsed.protocol}`, { endpoint });
46
+ }
47
+ return parsed.toString();
48
+ }
49
+ function createNativeAgentClient(options) {
50
+ const endpoint = normalizeNativeAgentEndpoint(options.endpoint);
51
+ const timeout = options.commandTimeout ?? options.timeout ?? 10_000;
52
+ const fetchImpl = options.fetchImpl ?? getGlobalFetch();
53
+ if (!fetchImpl) {
54
+ throw new AsturError('AGENT_FETCH_UNAVAILABLE', 'Global fetch is not available in this Node runtime. Provide NativeAgentClientOptions.fetchImpl.');
55
+ }
56
+ return {
57
+ endpoint,
58
+ platform: options.platform,
59
+ commandTimeout: timeout,
60
+ command: async (method, params) => {
61
+ return sendNativeAgentCommand(fetchImpl, endpoint, timeout, method, params);
62
+ }
63
+ };
64
+ }
65
+ async function sendNativeAgentCommand(fetchImpl, endpoint, timeout, method, params) {
66
+ const id = randomUUID();
67
+ const envelope = {
68
+ id,
69
+ protocolVersion: '1.0',
70
+ command: method,
71
+ deadlineMs: Date.now() + timeout,
72
+ payload: params,
73
+ method,
74
+ params
75
+ };
76
+ const controller = new AbortController();
77
+ const timer = setTimeout(() => controller.abort(), timeout);
78
+ let response;
79
+ try {
80
+ response = await fetchImpl(endpoint, {
81
+ method: 'POST',
82
+ headers: {
83
+ 'content-type': 'application/json'
84
+ },
85
+ body: JSON.stringify(envelope),
86
+ signal: controller.signal
87
+ });
88
+ }
89
+ catch (error) {
90
+ throw new AsturError('AGENT_TRANSPORT_FAILED', `Native agent command ${method} failed to reach ${endpoint}.`, {
91
+ endpoint,
92
+ method,
93
+ timeout,
94
+ cause: stringifyUnknownError(error)
95
+ });
96
+ }
97
+ finally {
98
+ clearTimeout(timer);
99
+ }
100
+ if (!response.ok) {
101
+ throw new AsturError('AGENT_TRANSPORT_FAILED', `Native agent command ${method} failed with HTTP ${response.status}.`, {
102
+ endpoint,
103
+ method,
104
+ status: response.status,
105
+ statusText: response.statusText
106
+ });
107
+ }
108
+ let payload;
109
+ try {
110
+ payload = await response.json();
111
+ }
112
+ catch (error) {
113
+ throw new AsturError('AGENT_RESPONSE_INVALID', `Native agent command ${method} returned invalid JSON.`, {
114
+ endpoint,
115
+ method,
116
+ cause: stringifyUnknownError(error)
117
+ });
118
+ }
119
+ if (!payload || payload.id !== id) {
120
+ throw new AsturError('AGENT_RESPONSE_MISMATCH', `Native agent command ${method} returned a mismatched command id.`, {
121
+ endpoint,
122
+ method,
123
+ expectedId: id,
124
+ receivedId: payload?.id
125
+ });
126
+ }
127
+ if (!payload.ok) {
128
+ throw new AsturError(payload.error?.code ?? 'AGENT_COMMAND_FAILED', payload.error?.message ?? `Native agent command ${method} failed.`, {
129
+ endpoint,
130
+ method,
131
+ error: payload.error,
132
+ diagnostics: payload.diagnostics,
133
+ timing: payload.timing
134
+ });
135
+ }
136
+ return (payload.result ?? payload.data);
137
+ }
138
+ function getGlobalFetch() {
139
+ return globalThis.fetch;
140
+ }
141
+ function stringifyUnknownError(error) {
142
+ if (error instanceof Error) {
143
+ return `${error.name}: ${error.message}`;
144
+ }
145
+ return String(error);
146
+ }
147
+ //# sourceMappingURL=agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { AsturConfig, NormalizedCapabilities } from '@astur-mobile/protocol';
2
+ export declare function normalizeCapabilities(config: AsturConfig): NormalizedCapabilities;
3
+ export declare function materializeCapabilities(capabilities: NormalizedCapabilities): Promise<NormalizedCapabilities>;
4
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAGV,WAAW,EAGX,sBAAsB,EAGvB,MAAM,wBAAwB,CAAC;AAGhC,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,WAAW,GAAG,sBAAsB,CAiBjF;AAED,wBAAsB,uBAAuB,CAC3C,YAAY,EAAE,sBAAsB,GACnC,OAAO,CAAC,sBAAsB,CAAC,CAmBjC"}
package/dist/config.js ADDED
@@ -0,0 +1,179 @@
1
+ import { createWriteStream } from 'node:fs';
2
+ import { copyFile, mkdir, stat, unlink } from 'node:fs/promises';
3
+ import { get as httpGet } from 'node:http';
4
+ import { get as httpsGet } from 'node:https';
5
+ import { basename, dirname, join } from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+ import { AsturError } from './errors.js';
8
+ export function normalizeCapabilities(config) {
9
+ const automation = normalizeAutomation(config.platform, config.automation, config.agent);
10
+ const agent = normalizeAgent(config.agent, automation);
11
+ return {
12
+ platform: config.platform,
13
+ device: config.device ?? {},
14
+ app: normalizeApp(config.app),
15
+ timeout: config.timeout ?? 10_000,
16
+ artifactsDir: config.artifactsDir ?? 'test-results/astur',
17
+ artifacts: config.artifacts ?? {},
18
+ keyboard: {
19
+ dismiss: config.keyboard?.dismiss ?? 'auto'
20
+ },
21
+ automation,
22
+ agent
23
+ };
24
+ }
25
+ export async function materializeCapabilities(capabilities) {
26
+ if (!capabilities.app?.url || capabilities.app.path) {
27
+ return capabilities;
28
+ }
29
+ const path = capabilities.app.downloadPath ?? defaultDownloadPath(capabilities.app.url, capabilities.artifactsDir);
30
+ await mkdir(dirname(path), { recursive: true });
31
+ const alreadyDownloaded = await stat(path).then(() => true).catch(() => false);
32
+ if (!alreadyDownloaded) {
33
+ await downloadApp(capabilities.app.url, path);
34
+ }
35
+ return {
36
+ ...capabilities,
37
+ app: {
38
+ ...capabilities.app,
39
+ path
40
+ }
41
+ };
42
+ }
43
+ function normalizeApp(app) {
44
+ if (!app) {
45
+ return undefined;
46
+ }
47
+ if (typeof app === 'string') {
48
+ return { path: app };
49
+ }
50
+ return app;
51
+ }
52
+ function normalizeAutomation(platform, automation, agent) {
53
+ const defaults = defaultAutomationForPlatform(platform);
54
+ const engine = automation?.engine ?? agentModeToEngine(agent?.mode) ?? defaults.engine;
55
+ const commandTimeoutMs = automation?.commandTimeoutMs ?? agent?.commandTimeout ?? defaults.commandTimeoutMs;
56
+ const startupTimeoutMs = automation?.startupTimeoutMs ?? agent?.launchTimeout ?? defaults.startupTimeoutMs;
57
+ return {
58
+ engine,
59
+ transport: automation?.transport ?? agent?.transport ?? 'auto',
60
+ legacyFallback: automation?.legacyFallback ?? agent?.legacyFallback ?? defaultLegacyFallback(engine),
61
+ commandTimeoutMs,
62
+ startupTimeoutMs,
63
+ strictLocators: automation?.strictLocators ?? true,
64
+ snapshot: {
65
+ mode: automation?.snapshot?.mode ?? 'on-failure',
66
+ cacheTtlMs: automation?.snapshot?.cacheTtlMs ?? 200
67
+ },
68
+ timings: {
69
+ enabled: automation?.timings?.enabled ?? true,
70
+ slowCommandThresholdMs: automation?.timings?.slowCommandThresholdMs ?? 1_000
71
+ }
72
+ };
73
+ }
74
+ function defaultAutomationForPlatform(platform) {
75
+ if (platform === 'ios') {
76
+ return {
77
+ engine: 'agent',
78
+ commandTimeoutMs: 15_000,
79
+ startupTimeoutMs: 60_000
80
+ };
81
+ }
82
+ return {
83
+ engine: 'agent',
84
+ commandTimeoutMs: 20_000,
85
+ startupTimeoutMs: 30_000
86
+ };
87
+ }
88
+ function defaultLegacyFallback(engine) {
89
+ return engine === 'auto' ? 'on-agent-failure' : 'never';
90
+ }
91
+ function normalizeAgent(agent, automation) {
92
+ return {
93
+ mode: agent?.mode ?? engineToAgentMode(automation.engine),
94
+ install: agent?.install ?? true,
95
+ endpoint: agent?.endpoint,
96
+ launchTimeout: agent?.launchTimeout ?? automation.startupTimeoutMs,
97
+ commandTimeout: agent?.commandTimeout ?? automation.commandTimeoutMs,
98
+ legacyFallback: agent?.legacyFallback ?? automation.legacyFallback,
99
+ transport: agent?.transport ?? automation.transport
100
+ };
101
+ }
102
+ function agentModeToEngine(mode) {
103
+ if (mode === 'required') {
104
+ return 'agent';
105
+ }
106
+ if (mode === 'off') {
107
+ return 'legacy-adb';
108
+ }
109
+ if (mode === 'auto') {
110
+ return 'auto';
111
+ }
112
+ return undefined;
113
+ }
114
+ function engineToAgentMode(engine) {
115
+ switch (engine) {
116
+ case 'agent':
117
+ return 'required';
118
+ case 'legacy-adb':
119
+ return 'off';
120
+ case 'auto':
121
+ return 'auto';
122
+ }
123
+ }
124
+ function defaultDownloadPath(url, artifactsDir) {
125
+ const parsed = new URL(url);
126
+ const fileName = basename(parsed.pathname) || `app-${Date.now()}`;
127
+ return join(artifactsDir, 'apps', fileName);
128
+ }
129
+ async function downloadApp(url, path) {
130
+ const parsed = new URL(url);
131
+ if (parsed.protocol === 'file:') {
132
+ await copyFile(fileURLToPath(parsed), path);
133
+ return;
134
+ }
135
+ if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
136
+ throw new AsturError('APP_DOWNLOAD_UNSUPPORTED_PROTOCOL', `Unsupported app download URL protocol: ${parsed.protocol}`);
137
+ }
138
+ await downloadHttp(url, path);
139
+ }
140
+ function downloadHttp(url, path, redirects = 0) {
141
+ if (redirects > 5) {
142
+ return Promise.reject(new AsturError('APP_DOWNLOAD_REDIRECT_LIMIT', `Too many redirects while downloading ${url}.`));
143
+ }
144
+ return new Promise((resolve, reject) => {
145
+ const get = url.startsWith('https:') ? httpsGet : httpGet;
146
+ const request = get(url, (response) => {
147
+ const status = response.statusCode ?? 0;
148
+ const location = response.headers.location;
149
+ if (status >= 300 && status < 400 && location) {
150
+ response.resume();
151
+ downloadHttp(new URL(location, url).toString(), path, redirects + 1).then(resolve, reject);
152
+ return;
153
+ }
154
+ if (status < 200 || status >= 300) {
155
+ response.resume();
156
+ reject(new AsturError('APP_DOWNLOAD_FAILED', `Downloading ${url} failed with HTTP ${status}.`));
157
+ return;
158
+ }
159
+ const file = createWriteStream(path);
160
+ response.pipe(file);
161
+ file.on('finish', () => {
162
+ file.close((error) => {
163
+ if (error) {
164
+ reject(error);
165
+ return;
166
+ }
167
+ resolve();
168
+ });
169
+ });
170
+ file.on('error', (error) => {
171
+ file.close(() => undefined);
172
+ void unlink(path).catch(() => undefined);
173
+ reject(error);
174
+ });
175
+ });
176
+ request.on('error', reject);
177
+ });
178
+ }
179
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export declare class AsturError extends Error {
2
+ readonly code: string;
3
+ readonly details?: unknown;
4
+ constructor(code: string, message: string, details?: unknown);
5
+ }
6
+ export declare class TimeoutError extends AsturError {
7
+ constructor(message: string, details?: unknown);
8
+ }
9
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,UAAW,SAAQ,KAAK;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;gBAEf,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO;CAM7D;AAED,qBAAa,YAAa,SAAQ,UAAU;gBAC9B,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO;CAI/C"}
package/dist/errors.js ADDED
@@ -0,0 +1,17 @@
1
+ export class AsturError extends Error {
2
+ code;
3
+ details;
4
+ constructor(code, message, details) {
5
+ super(message);
6
+ this.name = 'AsturError';
7
+ this.code = code;
8
+ this.details = details;
9
+ }
10
+ }
11
+ export class TimeoutError extends AsturError {
12
+ constructor(message, details) {
13
+ super('TIMEOUT', message, details);
14
+ this.name = 'TimeoutError';
15
+ }
16
+ }
17
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,UAAW,SAAQ,KAAK;IAC1B,IAAI,CAAS;IACb,OAAO,CAAW;IAE3B,YAAY,IAAY,EAAE,OAAe,EAAE,OAAiB;QAC1D,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;QACzB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;CACF;AAED,MAAM,OAAO,YAAa,SAAQ,UAAU;IAC1C,YAAY,OAAe,EAAE,OAAiB;QAC5C,KAAK,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QACnC,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;IAC7B,CAAC;CACF"}
@@ -0,0 +1,10 @@
1
+ export * from '@astur-mobile/protocol';
2
+ export * from './agent.js';
3
+ export * from './config.js';
4
+ export * from './errors.js';
5
+ export * from './inspector.js';
6
+ export * from './keyboard.js';
7
+ export * from './locator.js';
8
+ export * from './session.js';
9
+ export * from './wait.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ export * from '@astur-mobile/protocol';
2
+ export * from './agent.js';
3
+ export * from './config.js';
4
+ export * from './errors.js';
5
+ export * from './inspector.js';
6
+ export * from './keyboard.js';
7
+ export * from './locator.js';
8
+ export * from './session.js';
9
+ export * from './wait.js';
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { InspectorSession } from '@astur-mobile/protocol';
2
+ import type { PlatformSession } from './session.js';
3
+ export interface RuntimeInspectorSessionOptions {
4
+ pollIntervalMs?: number;
5
+ }
6
+ export declare function createInspectorSession(session: PlatformSession, options?: RuntimeInspectorSessionOptions): InspectorSession;
7
+ //# sourceMappingURL=inspector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inspector.d.ts","sourceRoot":"","sources":["../src/inspector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAIV,gBAAgB,EAMjB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAkBpD,MAAM,WAAW,8BAA8B;IAC7C,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAUD,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,eAAe,EACxB,OAAO,GAAE,8BAAmC,GAC3C,gBAAgB,CAElB"}