@audienti/cli 0.2.0-exora.1 → 0.2.0-exora.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 +28 -4
- package/cli/approach-operations.mjs +14 -4
- package/cli/experiment-operations.mjs +1 -1
- package/cli/offer-operations.mjs +1 -1
- package/cli/progress.mjs +3 -3
- package/package.json +1 -1
- package/source-manifest.json +7 -6
package/README.md
CHANGED
|
@@ -16,14 +16,21 @@ Give the agent the profile path, not your password or a human API token.
|
|
|
16
16
|
audienti agent poll --profile "$HOME/.audienti/exo-agent.json"
|
|
17
17
|
audienti workspace list --profile "$HOME/.audienti/exo-agent.json"
|
|
18
18
|
audienti workspace use WORKSPACE_UUID --profile "$HOME/.audienti/exo-agent.json"
|
|
19
|
-
audienti tools balance --profile "$HOME/.audienti/exo-agent.json"
|
|
20
19
|
audienti profiles list --profile "$HOME/.audienti/exo-agent.json"
|
|
21
20
|
audienti skills show audienti
|
|
22
21
|
```
|
|
23
22
|
|
|
24
|
-
Approval initially grants read access.
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
Approval initially grants read access. Before checking tool credits or the hosted tool catalog, making CRM writes
|
|
24
|
+
or using paid tools, open **Settings → Agents** and choose **Allow workspace changes**
|
|
25
|
+
for this agent. Then check its workspace balance:
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
audienti tools balance --profile "$HOME/.audienti/exo-agent.json"
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Balance reads also require this permission because they settle expired credit lots.
|
|
32
|
+
Workspace policy and current permissions still apply. Only a verified human Admin
|
|
33
|
+
can purchase or redeem credits through Billing.
|
|
27
34
|
Paid calls spend shared workspace credits; development credits are local-only.
|
|
28
35
|
|
|
29
36
|
To connect an MCP client, use this command and environment after selecting a workspace:
|
|
@@ -43,3 +50,20 @@ providers or execute hidden workflows.
|
|
|
43
50
|
Start with saved-record reads and inspect the credit balance. Explicit enrichment
|
|
44
51
|
uses the configured hosted provider; registration of an external agent-managed
|
|
45
52
|
connection does not configure a hosted provider or imply successful synchronization.
|
|
53
|
+
|
|
54
|
+
## Approach plays and review
|
|
55
|
+
|
|
56
|
+
`audienti approach show ID` reads the versioned stage plays, waits, voice and
|
|
57
|
+
completion rules. Your agent performs the work externally and cites stored
|
|
58
|
+
evidence when reporting progress with `audienti approach record --file report.json`.
|
|
59
|
+
Use exactly one of `stageKey`, `offRampKey` or `finishStage: true`. Finishing a play
|
|
60
|
+
resolves its next/stay/off-ramp rule from the participation’s admitted version.
|
|
61
|
+
|
|
62
|
+
When human review is required, use `audienti approach suggest --file report.json`
|
|
63
|
+
and `audienti approach suggestions`. Suggestions do not move anyone. The assigned
|
|
64
|
+
human or a workspace Admin approves or dismisses in Operator → Queue. Agents
|
|
65
|
+
cannot approve suggestions. Stay completion records work without moving a stage.
|
|
66
|
+
|
|
67
|
+
MCP exposes `approach_progress_suggest` and `approach_suggestions_list` alongside
|
|
68
|
+
the existing approach tools. These operations require current workspace permission
|
|
69
|
+
and do not send messages or call providers.
|
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
import {z} from 'zod';
|
|
2
|
-
const uuid=z.string().uuid(),scope={workspaceId:uuid.optional()}
|
|
3
|
-
const
|
|
2
|
+
const uuid=z.string().uuid(),scope={workspaceId:uuid.optional()};
|
|
3
|
+
const label=z.string().trim().min(1).max(120).refine(value=>!/[\u0000-\u001f\u007f]/.test(value),'Control characters are not allowed.');
|
|
4
|
+
const text=z.string().trim().max(5000);
|
|
5
|
+
const identity=z.object({key:z.string().uuid(),name:label}).strict();
|
|
6
|
+
const approachStepSchema=z.object({key:z.string().uuid(),channel:z.enum(['LinkedIn','Email','Phone']),action:label,condition:z.enum(['Always','Only if viable','Only if connected']),viability:text.optional(),instructions:text.optional(),waitDays:z.number().int().min(1).max(60)}).strict();
|
|
7
|
+
const completion=z.discriminatedUnion('kind',[z.object({kind:z.literal('next')}).strict(),z.object({kind:z.literal('stay')}).strict(),z.object({kind:z.literal('off_ramp'),offRampKey:z.string().uuid()}).strict()]);
|
|
8
|
+
const stage=identity.extend({movesInWhen:text.optional(),owner:z.enum(['Agent','Assignee']).optional(),goalDays:z.number().int().min(0).max(365).optional(),optional:z.boolean().optional(),enabled:z.boolean().optional(),steps:z.array(approachStepSchema).max(20).optional(),completion:completion.optional()});
|
|
9
|
+
const approachRulesSchema=z.object({autoMove:z.boolean().optional(),flagOverdue:z.boolean().optional(),allowBackward:z.boolean().optional(),emailWindow:z.enum(['weekdays_morning','weekdays','any_day']).optional(),nurtureDays:z.union([z.literal(60),z.literal(90),z.literal(180),z.null()]).optional()}).strict();
|
|
10
|
+
const approachFieldsSchema=z.object({name:label,stages:z.array(stage).min(2).max(30),goalKey:z.string().uuid(),offRamps:z.array(identity.extend({reason:z.enum(['rejected','not_fit','nurture','unresponsive','other'])})).max(30),voice:text.optional(),rules:approachRulesSchema.optional()}).strict();
|
|
11
|
+
const fields=approachFieldsSchema;
|
|
4
12
|
const base=a=>`/workspaces/${a.workspaceId}`,query=(a,skip=[])=>new URLSearchParams(Object.entries(a).filter(([k,v])=>k!=='workspaceId'&&!skip.includes(k)&&v!==undefined).map(([k,v])=>[k,String(v)]));
|
|
5
13
|
export const approachOperations={
|
|
6
14
|
approach_list:{schema:z.object({...scope,cursor:uuid.optional(),limit:z.number().int().min(1).max(100).optional()}).strict(),method:'GET',path:a=>`${base(a)}/approaches?${query(a)}`,scoped:true,description:'List immutable versioned approaches in the current workspace. Free CRM read.'},
|
|
7
|
-
approach_get:{schema:z.object({...scope,id:uuid,revision:z.number().int().positive().optional()}).strict(),method:'GET',path:a=>`${base(a)}/approaches/${a.id}?${query(a,['id'])}`,scoped:true,description:'Read an approach version:
|
|
15
|
+
approach_get:{schema:z.object({...scope,id:uuid,revision:z.number().int().positive().optional()}).strict(),method:'GET',path:a=>`${base(a)}/approaches/${a.id}?${query(a,['id'])}`,scoped:true,description:'Read an approach version: stage plays, step waits, completion, goal, voice and agent rules. Instructions are executed by the external agent, never by a hosted sequence runner.'},
|
|
8
16
|
approach_save:{schema:z.object({...scope,id:uuid.optional(),requestId:uuid,expectedRevision:z.number().int().nonnegative(),fields}).strict(),method:'POST',path:a=>`${base(a)}/approaches`,body:({workspaceId,...a})=>a,scoped:true,description:'Create or revise an approach with optimistic version and idempotent request. Does not change existing experiment or participation pins.'},
|
|
9
17
|
approach_progress_get:{schema:z.object({...scope,participationId:uuid}).strict(),method:'GET',path:a=>`${base(a)}/participations/${a.participationId}/progress`,scoped:true,description:'Read the participation’s admitted approach pin and recorded stage/outcome history.'},
|
|
10
|
-
approach_progress_record:{schema:z.object({...scope,participationId:uuid,expectedVersion:z.number().int().nonnegative(),requestId:uuid,stageKey:uuid.optional(),offRampKey:uuid.optional(),reason:z.string().trim().min(1).max(2000),evidence:z.array(z.object({kind:z.enum(['observation','conversation']),id:uuid}).strict()).max(20)}).strict(),method:'POST',path:a=>`${base(a)}/participations/${a.participationId}/progress`,body:({workspaceId,participationId,...a})=>a,scoped:true,description:'
|
|
18
|
+
approach_progress_record:{schema:z.object({...scope,participationId:uuid,expectedVersion:z.number().int().nonnegative(),requestId:uuid,stageKey:uuid.optional(),offRampKey:uuid.optional(),finishStage:z.literal(true).optional(),reason:z.string().trim().min(1).max(2000),evidence:z.array(z.object({kind:z.enum(['observation','conversation']),id:uuid}).strict()).max(20)}).strict(),method:'POST',path:a=>`${base(a)}/participations/${a.participationId}/progress`,body:({workspaceId,participationId,...a})=>a,scoped:true,description:'Report a stage, off-ramp, or finishStage:true after externally completing the current play and waits. Finish resolves next/stay/off-ramp from the admitted version. Stored evidence required for agents; human-review and backward-move rules apply. Assigned owner/Admin only. Goal ends prospecting; post-goal forward reporting never reactivates. No send or provider call.'},
|
|
19
|
+
approach_progress_suggest:{schema:z.object({...scope,participationId:uuid,expectedVersion:z.number().int().nonnegative(),requestId:uuid,stageKey:uuid.optional(),offRampKey:uuid.optional(),finishStage:z.literal(true).optional(),reason:z.string().trim().min(1).max(2000),evidence:z.array(z.object({kind:z.enum(['observation','conversation']),id:uuid}).strict()).max(20)}).strict(),method:'POST',path:a=>`${base(a)}/participations/${a.participationId}/suggestions`,body:({workspaceId,participationId,...a})=>a,scoped:true,description:'Suggest a pinned stage move, off-ramp or play completion for human review in Operator. Stored evidence required. Does not change progress or send anything. Assigned owner/Admin; current human approval revalidates progress.'},
|
|
20
|
+
approach_suggestions_list:{schema:z.object({...scope,cursor:uuid.optional(),limit:z.number().int().min(1).max(100).optional()}).strict(),method:'GET',path:a=>`${base(a)}/approach-suggestions?${query(a)}`,scoped:true,description:'List pending stage suggestions visible to the current owner or Admin. Humans approve or dismiss in Operator; agents cannot approve.'},
|
|
11
21
|
workspace_analytics_get:{schema:z.object({...scope,experimentId:uuid.optional(),pinId:uuid.optional(),from:z.string().datetime(),to:z.string().datetime()}).strict(),method:'GET',path:a=>`${base(a)}/analytics?${query(a)}`,scoped:true,description:'Read UTC-period distinct outcomes and explicit stage events. Missing activity or cost attribution is not tracked, never fabricated zero. Maximum 366 days; narrow large scopes.'}
|
|
12
22
|
};
|
|
@@ -7,7 +7,7 @@ const signal=z.discriminatedUnion('kind',[
|
|
|
7
7
|
z.object({...signalBase,kind:z.literal('topic'),topic:z.string()}).strict(),
|
|
8
8
|
z.object({...signalBase,kind:z.literal('profile'),url:z.string(),track:z.enum(['audience','activity']).optional(),interactions:z.array(z.enum(['comments','reactions'])).optional()}).strict(),
|
|
9
9
|
]);
|
|
10
|
-
const fields=z.object({name:z.string(),audienceId:uuid,audienceRevision:z.number().int(),offerId:uuid,offerRevision:z.number().int(),premise:z.string(),approach:z.string().optional(),approachPin:z.object({id:uuid,revision:z.number().int().positive()}).strict().optional(),notes:z.string().optional(),ownerUserId:uuid.nullable().optional(),tags:z.array(z.string()).optional(),signalMatch:z.enum(['any','all']).optional(),signals:z.array(signal).optional(),targets:z.discriminatedUnion('kind',[
|
|
10
|
+
const fields=z.object({name:z.string(),audienceId:uuid,audienceRevision:z.number().int(),offerId:uuid,offerRevision:z.number().int(),premise:z.string().optional(),approach:z.string().optional(),approachPin:z.object({id:uuid,revision:z.number().int().positive()}).strict().optional(),notes:z.string().optional(),ownerUserId:uuid.nullable().optional(),tags:z.array(z.string()).optional(),signalMatch:z.enum(['any','all']).optional(),signals:z.array(signal).optional(),targets:z.discriminatedUnion('kind',[
|
|
11
11
|
z.object({kind:z.literal('none'),values:z.array(z.never())}).strict(),
|
|
12
12
|
z.object({kind:z.literal('companies'),values:z.array(z.object({type:z.enum(['domain','linkedin-company']),value:z.string()}).strict())}).strict(),
|
|
13
13
|
z.object({kind:z.literal('people'),values:z.array(z.object({type:z.literal('linkedin-person'),value:z.string()}).strict())}).strict(),
|
package/cli/offer-operations.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {z} from 'zod';
|
|
2
2
|
const uuid=z.string().uuid(),workspace={workspaceId:uuid.optional()},locator={...workspace,offerId:uuid};
|
|
3
|
-
const fields=z.object({name:z.string(),description:z.string().optional(),url:z.string().optional(),avoidClaims:z.array(z.string()).optional(),pricing:z.object({currency:z.string().optional(),oneTimeAmountCents:z.number().optional(),recurringAmountCents:z.number().optional(),recurringInterval:z.enum(['monthly','annual']).optional(),notes:z.string().optional()}).strict().optional()}).strict();
|
|
3
|
+
const fields=z.object({name:z.string(),description:z.string().optional(),outcome:z.string().trim().max(2000).optional(),benefits:z.array(z.string().trim().min(1).max(1000)).max(20).optional(),url:z.string().optional(),avoidClaims:z.array(z.string()).optional(),pricing:z.object({currency:z.string().optional(),oneTimeAmountCents:z.number().optional(),recurringAmountCents:z.number().optional(),recurringInterval:z.enum(['monthly','annual']).optional(),notes:z.string().optional()}).strict().optional()}).strict();
|
|
4
4
|
const path=a=>`/workspaces/${a.workspaceId}/offers`;
|
|
5
5
|
export const offerOperations={
|
|
6
6
|
offer_list:{schema:z.object({...workspace,archived:z.boolean().optional(),limit:z.number().int().optional(),after:uuid.optional(),q:z.string().optional()}).strict(),method:'GET',path:a=>path(a)+'?'+new URLSearchParams(Object.fromEntries(Object.entries({archived:a.archived,limit:a.limit,after:a.after,q:a.q}).filter(([,v])=>v!==undefined).map(([k,v])=>[k,String(v)]))),scoped:true},
|
package/cli/progress.mjs
CHANGED
|
@@ -2,9 +2,9 @@ import {callWorkspace,configuration} from './workspaces.mjs';
|
|
|
2
2
|
import {readJsonFile} from './json-file.mjs';
|
|
3
3
|
export async function progressCli(args){
|
|
4
4
|
const positions=[],flags={};for(let i=0;i<args.length;i++){const arg=args[i];if(!arg.startsWith('--')){positions.push(arg);continue;}const key=arg.slice(2);if(!['profile','workspace','file','cursor','limit','revision','from','to','experiment','approach-version','kind','user'].includes(key)||!args[i+1]||args[i+1].startsWith('--')||Object.hasOwn(flags,key))throw new Error('Unknown or incomplete option.');flags[key]=args[++i];}
|
|
5
|
-
const names={approach:{list:'approach_list',show:'approach_get',save:'approach_save',progress:'approach_progress_get',record:'approach_progress_record'},analytics:{show:'workspace_analytics_get'},connections:{list:'workspace_connections_list',register:'workspace_connection_register',report:'workspace_connection_report'}};
|
|
6
|
-
const name=names[positions[0]]?.[positions[1]];if(!name)throw new Error('Use approach list|show ID|save --file PATH|progress ID|record --file PATH; analytics show --from ISO --to ISO; connections list|register --file PATH|report --file PATH.');
|
|
7
|
-
const fileNames=['approach_save','approach_progress_record','workspace_connection_register','workspace_connection_report'];const withId=['approach_get','approach_progress_get'].includes(name);if(positions.length!==(withId?3:2))throw new Error('Unexpected arguments.');
|
|
5
|
+
const names={approach:{list:'approach_list',show:'approach_get',save:'approach_save',progress:'approach_progress_get',record:'approach_progress_record',suggest:'approach_progress_suggest',suggestions:'approach_suggestions_list'},analytics:{show:'workspace_analytics_get'},connections:{list:'workspace_connections_list',register:'workspace_connection_register',report:'workspace_connection_report'}};
|
|
6
|
+
const name=names[positions[0]]?.[positions[1]];if(!name)throw new Error('Use approach list|show ID|save --file PATH|progress ID|record|suggest --file PATH|suggestions; analytics show --from ISO --to ISO; connections list|register --file PATH|report --file PATH.');
|
|
7
|
+
const fileNames=['approach_save','approach_progress_record','approach_progress_suggest','workspace_connection_register','workspace_connection_report'];const withId=['approach_get','approach_progress_get'].includes(name);if(positions.length!==(withId?3:2))throw new Error('Unexpected arguments.');
|
|
8
8
|
if(fileNames.includes(name)&&!flags.file)throw new Error('Supply a JSON request with --file PATH.');if(!fileNames.includes(name)&&flags.file)throw new Error('--file is only accepted for mutations.');
|
|
9
9
|
const input=fileNames.includes(name)?readJsonFile(flags.file,65536,'Request file'):{};if(!input||typeof input!=='object'||Array.isArray(input))throw new Error('Request must be an object.');if(flags.workspace)input.workspaceId=flags.workspace;if(withId)input[name==='approach_get'?'id':'participationId']=positions[2];
|
|
10
10
|
for(const[key,value]of Object.entries(flags)){if(['workspace','profile','file'].includes(key))continue;const field={experiment:'experimentId','approach-version':'pinId',user:'userId'}[key]??key;input[field]=['limit','revision'].includes(key)?Number(value):value;}
|
package/package.json
CHANGED
package/source-manifest.json
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"repository": "https://github.com/omalab/exora",
|
|
3
|
-
"sourceCommit": "
|
|
3
|
+
"sourceCommit": "258d7e4d3f13e24006411b970b281c4e84fc620a",
|
|
4
4
|
"files": {
|
|
5
5
|
"LICENSE": "220f297cfcd5c38eb64e6b4b4a77cab4ebc7f4686d4d99c6260a475d02ca11e5",
|
|
6
|
+
"README.md": "87a67b553f899a9ffdc12b9561e8c467d20463ce5d60c8ea8b744e9517a4b661",
|
|
6
7
|
"bin/audienti-mcp.mjs": "6df1d6eb3a5bc65e7592e5b8f73cd4c98c159f2583723d042338633b356301df",
|
|
7
8
|
"cli/account-intake-operations.mjs": "b43d764c628beabafad753d711ddb2af2c64276e4a6506ed0b854839091ea5db",
|
|
8
9
|
"cli/account-intake.mjs": "aa77f2f96fd030f8830d6de278932186aea7c82cfda086a5a6cf569202feebc8",
|
|
9
10
|
"cli/account-replies.mjs": "699e34e5c736ba316df8f164b4c50f82a7e4e2d5e51303e6b13944c3f2c854ab",
|
|
10
11
|
"cli/account-reply-operations.mjs": "b4d65cf4459138909dba916012f78cc6cf4580748ed350d220132ec96adbdd83",
|
|
11
12
|
"cli/agents.mjs": "8d0f7a940f61a74408956b2c597aceb107a25d08877d733db9fddfa68aa33bdb",
|
|
12
|
-
"cli/approach-operations.mjs": "
|
|
13
|
+
"cli/approach-operations.mjs": "9ae0a5797eb6502824c16f34a129283296a2dc603f46a57d6315ba6173bf7a33",
|
|
13
14
|
"cli/assignment-operations.mjs": "60d672702dcaca9514a7eff5cfde094844884361a22a7cf667c465a80c59a75d",
|
|
14
15
|
"cli/assignment.mjs": "44255a329529f897af1055828d5ca0bd2ea5182df62c4983006f4c5ab2547f0a",
|
|
15
16
|
"cli/audience-operations.mjs": "632fe13f59dbeeb0d264943b5df5643d1dc631a504363e2d1dbe1297f5ab9b78",
|
|
@@ -19,15 +20,15 @@
|
|
|
19
20
|
"cli/content.mjs": "db3fcbf7f96c314227a8172a442b70b46405126e0d61f8358cee1bfe6c627ebd",
|
|
20
21
|
"cli/discovery-operations.mjs": "dc564a591bd920df67ba2df65f31d973491c21687e6fba12125430a8ecad2c95",
|
|
21
22
|
"cli/discovery.mjs": "c0c23378ff93ecd86cba8d9e0add1fcc5a26f5e849cbc561860b93f50f0adb27",
|
|
22
|
-
"cli/experiment-operations.mjs": "
|
|
23
|
+
"cli/experiment-operations.mjs": "274f6d45f25cb93e0eeec04f792bf014a9924c492e5d2b7b63f9babd08cb7e8e",
|
|
23
24
|
"cli/experiments.mjs": "80a672d056b1f2cdff882c63ee39420c0b9e68167fbe4f8486a905e51c0de4cb",
|
|
24
25
|
"cli/json-file.mjs": "e1fa747c2ba7cdb1f013ed99789a7e4811c3f569cd7d9715f30ddededa34159e",
|
|
25
26
|
"cli/mcp.mjs": "4e746d5eb34ca68b32f544eb9085777a57e2e9bbddd3d2810c51cf9e10a1e6df",
|
|
26
|
-
"cli/offer-operations.mjs": "
|
|
27
|
+
"cli/offer-operations.mjs": "868933828053a58e05108607a47d7968e0ff1d4db0a6d1598cce5b83a0439837",
|
|
27
28
|
"cli/offers.mjs": "4a97007e1e25352707bbecda0b2519affcd0024e52ae8d9446d76d459460feca",
|
|
28
29
|
"cli/owner-account-client.mjs": "712b2fd5a8cb21f1baa88ebce1ee1750a44b34cf7d15a93be61e530aacf202c4",
|
|
29
30
|
"cli/profiles.mjs": "45929b224ffc916b6dbd7a94e06ac09a1ff7feec430633b10d160c1608fc2d32",
|
|
30
|
-
"cli/progress.mjs": "
|
|
31
|
+
"cli/progress.mjs": "62ef3599a0ea3c58f8f33b486f6be48a1d61fcf8fcaace415a0aa50385f1d822",
|
|
31
32
|
"cli/prospecting-settings-operations.mjs": "37b881a867c19d9e5f2d02316038284ea0cf09de4f37b6dee2370a1faedf245e",
|
|
32
33
|
"cli/prospecting-settings.mjs": "b09f47c84416d9892d7d5b17dcf684cbb560e1cacb25513826ff04ef9307626e",
|
|
33
34
|
"cli/recipient-operations.mjs": "efc06c75d263169a35f5bac76dce133d4e78cf96a4b4a661531234a4d4007cdf",
|
|
@@ -47,7 +48,7 @@
|
|
|
47
48
|
"cli/work-operations.mjs": "f6544b69b424f839919e2c6c336b70a7be3aa0d147b18bc25479ca7a634117a5",
|
|
48
49
|
"cli/work.mjs": "b029727fb2a9e931e9e077d04e1976bfedc496e2ffcd74ccfa6490d109b5f139",
|
|
49
50
|
"cli/workspaces.mjs": "58e28acf3f5f82bbee35ea03478ec948390c908c6714330ace90118d552249cd",
|
|
50
|
-
"package.json": "
|
|
51
|
+
"package.json": "fb0d6e371369bdd9dde2b82ccfc69a4824fcfb051001d39811b3e440df0be099",
|
|
51
52
|
"skills/audienti/SKILL.md": "f6f8b3d74979c0e2e214d17a7fc77dcb93e957c37304d76791ddab88a6187914",
|
|
52
53
|
"skills/audienti/references/helpers.md": "b1eda3787dc0b10746c1272ada2689bfc29f014c2ea432d94733a8205a7d8dc3",
|
|
53
54
|
"skills/audienti/references/profile-workflows.md": "c44fcc0ce9142281aa309c3f0e771883a084100c86fbdd06561a3dc16e58c6db",
|