gooseworks 0.3.5 → 0.3.7
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"master-skill.d.ts","sourceRoot":"","sources":["../../src/skills/master-skill.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,WAAW,UAAU;IACzB,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,oDAAoD;AACpD,wBAAgB,cAAc,IAAI,UAAU,EAAE,CAM7C;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CA8K9C;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,
|
|
1
|
+
{"version":3,"file":"master-skill.d.ts","sourceRoot":"","sources":["../../src/skills/master-skill.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,WAAW,UAAU;IACzB,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,oDAAoD;AACpD,wBAAgB,cAAc,IAAI,UAAU,EAAE,CAM7C;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CA8K9C;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,CAoOhD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,yBAAyB,IAAI,MAAM,CAiPlD"}
|
|
@@ -226,7 +226,7 @@ description: >
|
|
|
226
226
|
app uses) — credits are reserved and billed server-side. Analytics recipes are fetched from
|
|
227
227
|
goose-skills on demand.
|
|
228
228
|
category: ads
|
|
229
|
-
version: 2.
|
|
229
|
+
version: 2.1.0
|
|
230
230
|
author: GooseWorks
|
|
231
231
|
tags: [gooseworks, ads, remix, static-ad, brand, creative, image, analytics, meta-ads, performance]
|
|
232
232
|
---
|
|
@@ -269,8 +269,10 @@ what they'd get in the UI. **Pass these explicitly:**
|
|
|
269
269
|
- \`ratios\`: **["4:5"]** (Meta feed vertical)
|
|
270
270
|
- \`engine\`: **"gpt_image_2"**
|
|
271
271
|
- \`quality\`: **"medium"**
|
|
272
|
-
- \`preserve_source_styling\`: **
|
|
273
|
-
|
|
272
|
+
- \`preserve_source_styling\`: **ASK the user** — "Keep original" (the template's own
|
|
273
|
+
colours/fonts → \`preserve_source_styling: true\`) vs "Match brand" (restyle to the brand
|
|
274
|
+
palette/fonts → \`preserve_source_styling: false\`). This mirrors the app's Styling control.
|
|
275
|
+
**The default is "Keep original"** — if the user doesn't answer or doesn't care, send \`true\`.
|
|
274
276
|
|
|
275
277
|
If the user asks for something the app exposes (more variants, a different ratio like 1:1 or
|
|
276
278
|
9:16, a faster engine, higher quality), pass that instead. Omitting a field lets backend policy
|
|
@@ -296,6 +298,12 @@ decide — fine, but prefer sending the app defaults for predictable parity.
|
|
|
296
298
|
\`status\` is \`"failed"\` — never assume a stall and re-submit, that double-bills.
|
|
297
299
|
- \`list_brand_creatives { brand_id, limit?, offset? }\` — the brand's gallery feed (newest
|
|
298
300
|
first) + \`brand_url\`. Alternative poll target; also use to show everything made for a brand.
|
|
301
|
+
- \`surprise_me_templates { brand_id, count? }\` — the **"Surprise me" recommender**. Picks
|
|
302
|
+
brand-relevant templates (SAME logic as the web /create "Surprise me" button — templates
|
|
303
|
+
whose category overlaps the brand float to the top, bucketed + shuffled so picks stay fresh).
|
|
304
|
+
Returns the picked templates (id, slug, title, image, ratio) AND a ready-to-open \`create_url\`
|
|
305
|
+
(the /create page with \`cli=true\` and the picks pre-selected). This is how you recommend
|
|
306
|
+
templates — do NOT hand-pick from the raw catalog yourself (see "Picking templates" below).
|
|
299
307
|
- \`regenerate_creative { project_id, mode?, prompt?, source_render_id?, ... }\` — **edit / re-roll
|
|
300
308
|
one existing creative** through the same pipeline. \`mode: "variation"\` (default) re-rolls from
|
|
301
309
|
the template; \`"edit"\` makes a targeted change to a specific render (\`prompt\` + \`source_render_id\`
|
|
@@ -319,21 +327,53 @@ decide — fine, but prefer sending the app defaults for predictable parity.
|
|
|
319
327
|
image as a private template, then remix it like any other.
|
|
320
328
|
- \`get_ad_project\` / \`append_project_message\` — inspect a creative / leave a note on its thread.
|
|
321
329
|
|
|
330
|
+
## Picking templates — ASK the user; don't freelance from the catalog
|
|
331
|
+
|
|
332
|
+
When the user wants to make ads but has NOT named a specific template (id/slug/Community
|
|
333
|
+
ad/upload), do NOT silently browse the raw catalog and hand-pick for them. Instead run this
|
|
334
|
+
short ask flow — it mirrors the web app and keeps the human in the loop:
|
|
335
|
+
|
|
336
|
+
1. **Ask what kind of ads they want** — the angle/offer/theme/season, the vibe, and which
|
|
337
|
+
product from the brand kit to feature. This shapes both the template choice and your steering
|
|
338
|
+
\`prompt\`. Keep it to one or two quick questions.
|
|
339
|
+
2. **Ask how to pick templates: "Choose explicitly" or "Surprise me".**
|
|
340
|
+
- **Surprise me** (they want you/the app to pick) → call
|
|
341
|
+
\`surprise_me_templates { brand_id, count }\` and hand the user the returned \`create_url\`.
|
|
342
|
+
It opens /create in **CLI mode** with the picks pre-selected, a preview modal, and the
|
|
343
|
+
**copyable remix prompt at the bottom** (in place of the Generate input). They can swap
|
|
344
|
+
picks and copy that prompt. If they'd rather you "just make them" without reviewing in the
|
|
345
|
+
app, you MAY submit the \`surprise_me_templates\` picks directly (skip to submit).
|
|
346
|
+
- **Choose explicitly** (they want to browse and select) → hand the user this URL, with the
|
|
347
|
+
active brand's slug filled in:
|
|
348
|
+
\`https://make.gooseworks.ai/create?brand=<brand-slug>&cli=true\`
|
|
349
|
+
In CLI mode the app shows the copyable remix prompt at the bottom (dismissable / switchable
|
|
350
|
+
back to the UI composer). They browse, select templates, and copy the prompt.
|
|
351
|
+
3. **Ask the styling** — "Keep original" (default) vs "Match brand" — per the Defaults section.
|
|
352
|
+
4. **Close the loop.** When the user **pastes back the copyable remix prompt** from the app
|
|
353
|
+
(it names the brand + the templates they chose), THAT is your cue to generate: resolve the
|
|
354
|
+
named template(s), then \`submit_remix_batch\` with the app defaults + the styling they chose.
|
|
355
|
+
|
|
356
|
+
If the user already named a template (id/slug), a Community ad, or an upload, skip the ask flow
|
|
357
|
+
for template choice — they've chosen — but still confirm the styling default and steer the prompt.
|
|
358
|
+
|
|
322
359
|
## Workflow — make ads from a template
|
|
323
360
|
|
|
324
361
|
1. **Resolve the brand.** \`list_ad_brands\` by name/site → \`get_brand_kit { brand_id }\`. If the
|
|
325
362
|
kit's \`researchStatus\` isn't \`complete\`, you can still submit (the batch queues and runs when
|
|
326
363
|
research finishes) — just tell the user. Use the kit to pick \`product_name\` (a real entry from
|
|
327
364
|
\`products[]\`, not a guess) and, if the user supplied product photos, \`reference_image_urls\`.
|
|
328
|
-
2. **
|
|
329
|
-
|
|
365
|
+
2. **Pick the template(s) via the ask flow above** (kind of ads → Choose explicitly vs Surprise
|
|
366
|
+
me → styling). Once you have concrete ids: \`get_static_ad_template { template_id }\` for each.
|
|
367
|
+
For a Community ad, \`remix_community_ad\` first; for an uploaded image, \`create_user_ad_template\`
|
|
368
|
+
first.
|
|
330
369
|
3. **(Optional) Craft the steering prompt.** The \`prompt\` is OPTIONAL — this is where the skill
|
|
331
|
-
adds value: turn the user's intent into a concise steering note (e.g. tone,
|
|
332
|
-
Don't over-specify; the backend pipeline + brand kit handle palette, fonts,
|
|
370
|
+
adds value: turn the user's intent (from step 1) into a concise steering note (e.g. tone,
|
|
371
|
+
season, emphasis). Don't over-specify; the backend pipeline + brand kit handle palette, fonts,
|
|
372
|
+
product swap.
|
|
333
373
|
4. **(Optional) Quote the cost.** \`estimate_remix_batch { items, engine, quality }\` → tell the user.
|
|
334
374
|
5. **Submit ONE batch.** \`submit_remix_batch { brand_id, items, prompt?, product_name?, engine,
|
|
335
|
-
quality, preserve_source_styling }\` using the app defaults above
|
|
336
|
-
and \`links\`.
|
|
375
|
+
quality, preserve_source_styling }\` using the app defaults above and the styling the user chose.
|
|
376
|
+
Keep the returned \`batch_id\` and \`links\`.
|
|
337
377
|
6. **Poll until done.** \`get_remix_batch { batch_id }\` (or \`list_brand_creatives\`) every ~20-30s
|
|
338
378
|
until every creative's \`pending\` is 0. Most images finish in a few minutes; text-heavy templates
|
|
339
379
|
and \`quality: high\` take longer. Read each render's \`elapsed_seconds\` rather than guessing — a
|
|
@@ -390,6 +430,12 @@ run through the \`gooseworks\` CLI (\`gooseworks fetch\` / \`gooseworks call\`),
|
|
|
390
430
|
each creative's \`app_url\`), copied verbatim. Never end on just "done" or a file path.
|
|
391
431
|
- **Quote cost before generating** when it's non-trivial (use \`estimate_remix_batch\`), and
|
|
392
432
|
relay \`insufficient_credits\` plainly if the submit is rejected — don't retry blindly.
|
|
433
|
+
- **Don't hand-pick templates silently.** If the user didn't name a template, run the ask flow
|
|
434
|
+
(kind of ads → Choose explicitly vs Surprise me → styling). "Surprise me" goes through
|
|
435
|
+
\`surprise_me_templates\`; "Choose explicitly" sends them to \`/create?brand=<slug>&cli=true\`.
|
|
436
|
+
Generate when they paste the app's copyable remix prompt back (or submit the surprise picks
|
|
437
|
+
directly if they'd rather not review).
|
|
438
|
+
- **Ask the styling** — Keep original (default) vs Match brand — before you submit.
|
|
393
439
|
- **Don't busy-loop** — poll \`get_remix_batch\` on a sensible interval (~20-30s); a \`queued\`
|
|
394
440
|
batch is waiting on research and will start on its own.
|
|
395
441
|
`;
|
|
@@ -450,9 +496,24 @@ id). The app NEVER runs you — it is the viewer + review surface; you are the r
|
|
|
450
496
|
(the render-file route) from the org's DEFAULT agent, but MCP file writes default to your
|
|
451
497
|
token's pinned agent — which can be a DIFFERENT agent, so a render written with the default
|
|
452
498
|
scope is **invisible in the app**. First resolve the Ads agent: \`list_accessible_scopes\` → the
|
|
453
|
-
scope with \`is_org_default: true\`
|
|
454
|
-
|
|
455
|
-
|
|
499
|
+
scope with \`is_org_default: true\` (the ORG default — NOT the \`is_default\` / \`default_agent_id\`
|
|
500
|
+
fields, which are the *user's* default agent and are often a DIFFERENT agent). Its \`agent_id\` is
|
|
501
|
+
\`ADS_AGENT\` (name "Ads agent", slug \`org-default\`; usually also the \`agent_id\` in
|
|
502
|
+
credentials.json). Then pass \`target: { type: "agent", agent_id: ADS_AGENT }\` on EVERY
|
|
503
|
+
\`get_upload_url\` / \`get_download_url\` / \`write_file\` / \`list_directory\` / \`read_file\` — NEVER
|
|
504
|
+
omit \`target\`.
|
|
505
|
+
- **CRITICAL — publish under the PROJECT FOLDER, not the workspace root (the #1 "video renders but
|
|
506
|
+
is invisible" bug).** \`get_upload_url\` stores at \`<ADS_AGENT>/files/<path>\` verbatim, but the
|
|
507
|
+
render-file route reads from
|
|
508
|
+
\`<ADS_AGENT>/files/agent-config/brands/<brand_slug>/projects/<project_id>/<path>\`
|
|
509
|
+
(see backend \`resolveProjectFileKey\`). So EVERY publish/preview \`path\` MUST be prefixed with
|
|
510
|
+
\`agent-config/brands/<brand_slug>/projects/<project_id>/\` — e.g. upload to
|
|
511
|
+
\`agent-config/brands/<brand_slug>/projects/<project_id>/working/final.mp4\`, NEVER bare
|
|
512
|
+
\`working/final.mp4\`. A bare path 404s in the app even though the render row AND a bare-path
|
|
513
|
+
\`get_download_url\` both "succeed" (they resolve the wrong key). The render \`output_url\` still
|
|
514
|
+
stays the project-relative \`...render-file?path=working/final.mp4\` — the route re-prepends the
|
|
515
|
+
prefix itself. Always verify with \`get_download_url\` on the FULL \`agent-config/...\` path (must
|
|
516
|
+
be non-empty; curl it for HTTP 200) BEFORE marking the render complete.
|
|
456
517
|
- Media generation (FAL / ElevenLabs) is billed to the agent through the GooseWorks proxies.
|
|
457
518
|
\`submit_render { kind: "full" }\` debits **1 ad credit at row creation** — so sequence it LAST
|
|
458
519
|
(render + verify a good MP4 first), and never re-submit on a guess (that double-bills). Call
|
|
@@ -469,14 +530,21 @@ id). The app NEVER runs you — it is the viewer + review surface; you are the r
|
|
|
469
530
|
|
|
470
531
|
## Step 2 — fetch the recipe + its pack skills for the format
|
|
471
532
|
|
|
472
|
-
The video-ad format skills live in
|
|
473
|
-
|
|
533
|
+
The video-ad format skills live in two goose-skills packs — **\`video-ad-formats\`** (phone-surface
|
|
534
|
+
HTML-mockup renders) and **\`ugc-video-formats\`** (GPT-image-2 + Seedance 2.0 reference-to-video).
|
|
535
|
+
Map the project's \`format\` to its recipe slug:
|
|
474
536
|
|
|
475
537
|
| format | recipe slug | renderer + atoms it drives |
|
|
476
538
|
| --- | --- | --- |
|
|
477
539
|
| \`imessage\` | \`remix-imessage-ad-from-sample\` | create-imessage-video-ad, create-imessage-mockup, stitch-videos-ffmpeg, mix-master, watch |
|
|
478
540
|
| \`chatgpt\` | \`remix-chatgpt-ad-from-sample\` | create-chatgpt-video-ad, create-chatgpt-mockup, render-ios-keyboard, stitch-videos-ffmpeg, watch |
|
|
479
541
|
| \`apple-notes\` | \`remix-apple-notes-ad-from-sample\` | create-apple-notes-video-ad, create-apple-notes-mockup, stitch-videos-ffmpeg, watch |
|
|
542
|
+
| \`ugc-product\` | \`remix-ugc-product-from-sample\` | create-ugc-product-video-from-refs, create-video-seedance-2-fal, create-image-gpt-image-fal, watch |
|
|
543
|
+
| \`ugc-grwm\` | \`remix-ugc-grwm-from-sample\` | create-ugc-grwm-video-from-refs, create-video-seedance-2-fal, create-image-gpt-image-fal, watch |
|
|
544
|
+
| \`ugc-skincare\` | \`remix-ugc-skincare-from-sample\` | create-ugc-skincare-demo-video-from-refs, create-video-seedance-2-fal, create-image-gpt-image-fal, watch |
|
|
545
|
+
| \`ugc-car-confessional\` | \`remix-ugc-car-confessional-from-sample\` | create-ugc-car-confessional-video-from-refs, create-video-seedance-2-fal, create-image-gpt-image-fal, watch |
|
|
546
|
+
| \`ugc-walk-and-talk\` | \`remix-ugc-walk-and-talk-from-sample\` | create-ugc-walk-and-talk-video-from-refs, create-video-seedance-2-fal, create-image-gpt-image-fal, watch |
|
|
547
|
+
| \`ugc-street-testimonial\` | \`remix-ugc-street-testimonial-from-sample\` | create-ugc-street-testimonial-video-from-refs, create-video-seedance-2-fal, create-image-gpt-image-fal, watch |
|
|
480
548
|
|
|
481
549
|
(photo-grid + music-video coming.) Pack skills are fetchable individually by slug but do NOT
|
|
482
550
|
auto-resolve dependencies (no \`dependencySkills\`), so \`gooseworks fetch\` the recipe **and** each
|
|
@@ -503,7 +571,10 @@ ingredients out one at a time.
|
|
|
503
571
|
that's typically: the **script** (the bubble thread), the **image(s)** shown in the conversation
|
|
504
572
|
(one or more), and the **end card**. Richer templates add more (hook frame, background, product
|
|
505
573
|
shots, music bed…). Read the recipe for the exact ingredient list. Generate the visuals NOW
|
|
506
|
-
(media proxies / recipe), and \`get_upload_url\` each preview asset to
|
|
574
|
+
(media proxies / recipe), and \`get_upload_url\` each preview asset to the project folder
|
|
575
|
+
\`agent-config/brands/<brand_slug>/projects/<project_id>/working/review/<name>\` (the same
|
|
576
|
+
path-prefix rule as final publish — a bare \`working/review/<name>\` won't render in the panel).
|
|
577
|
+
In \`script_drafts\`, set each ingredient's \`path\` to the project-relative \`working/review/<name>\`.
|
|
507
578
|
You may ask the user a couple of clarifying questions about the generation first if the recipe
|
|
508
579
|
calls for it (angle, which product, offer/code) — batch them, then prepare everything.
|
|
509
580
|
2. **Mirror the whole ingredient set for review** — \`update_ad_project_script { project_id,
|
|
@@ -535,11 +606,18 @@ ingredients out one at a time.
|
|
|
535
606
|
\`append_project_message\` instead.
|
|
536
607
|
3. QC by watching: run the \`watch\` skill on the master — verify bubble/beat order + SFX, that
|
|
537
608
|
the brand's product (not the source's) is shown, the end card has the real wordmark + code,
|
|
538
|
-
and the duration is within ~20% of the source.
|
|
609
|
+
and the duration is within ~20% of the source. For UGC/Seedance formats there are no captions
|
|
610
|
+
and often no local Whisper key: extract frames with ffmpeg for the visual pass, and get the
|
|
611
|
+
spoken transcript by running \`fal-ai/whisper\` through the SAME \`fal-proxy\` (upload the audio,
|
|
612
|
+
pass its \`get_download_url\` as \`audio_url\`) — confirm the transcript matches the script and the
|
|
613
|
+
brand name is pronounced right, with no word-repeat dysfluency, BEFORE spending the render credit.
|
|
539
614
|
4. Publish: \`get_upload_url { target: { type: "agent", agent_id: ADS_AGENT } }\` → PUT the master
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
615
|
+
and poster **under the project folder** (see Identity's path-prefix rule) — to
|
|
616
|
+
\`agent-config/brands/<brand_slug>/projects/<project_id>/working/final.mp4\` and
|
|
617
|
+
\`.../working/final-thumb.jpg\`. **Always target ADS_AGENT AND use the full project-folder path**
|
|
618
|
+
— a bare \`working/final.mp4\`, even on the right agent, 404s in the app. Verify servable:
|
|
619
|
+
\`get_download_url { target: ADS_AGENT, path: "agent-config/brands/<brand_slug>/projects/<project_id>/working/final.mp4" }\`
|
|
620
|
+
must return a non-empty URL (curl it for HTTP 200).
|
|
543
621
|
Then \`update_render_status { render_id, status: "complete", output_url, thumbnail_url }\` where
|
|
544
622
|
**output_url MUST be the durable render-file URL**
|
|
545
623
|
\`/api/ads/projects/<project_id>/render-file?path=working/final.mp4\` (the app re-presigns it on
|
|
@@ -597,7 +675,9 @@ def fal_generate(model_path, payload, timeout_s=180, poll_s=3):
|
|
|
597
675
|
|
|
598
676
|
ElevenLabs (VO / music) is the same shape against \`<api_base>/api/internal/elevenlabs-proxy\`
|
|
599
677
|
with \`?token=&agent_id=\`. Feed FAL a local image by storing it (\`get_upload_url\`) and passing its
|
|
600
|
-
\`get_download_url\` presigned URL as an \`image_urls\` entry
|
|
678
|
+
\`get_download_url\` presigned URL as an \`image_urls\` / \`audio_url\` entry — this is the reliable
|
|
679
|
+
path. (\`fal-storage-proxy\` may 404 depending on the install; don't block on it — prefer the
|
|
680
|
+
\`get_download_url\` presigned URL.)
|
|
601
681
|
|
|
602
682
|
## Rules
|
|
603
683
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"master-skill.js","sourceRoot":"","sources":["../../src/skills/master-skill.ts"],"names":[],"mappings":";;AA4BA,wCAMC;AAWD,sDA8KC;AAiBD,
|
|
1
|
+
{"version":3,"file":"master-skill.js","sourceRoot":"","sources":["../../src/skills/master-skill.ts"],"names":[],"mappings":";;AA4BA,wCAMC;AAWD,sDA8KC;AAiBD,0DAoOC;AAcD,8DAiPC;AAprBD,oDAAoD;AACpD,SAAgB,cAAc;IAC5B,OAAO;QACL,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,qBAAqB,EAAE,EAAE;QACxD,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,uBAAuB,EAAE,EAAE;QACzD,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,yBAAyB,EAAE,EAAE;KAC9D,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,SAAgB,qBAAqB;IACnC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4KR,CAAC;AACF,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,SAAgB,uBAAuB;IACrC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkOR,CAAC;AACF,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAgB,yBAAyB;IACvC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+OR,CAAC;AACF,CAAC"}
|