← Files PicsartARCHIVED FILE

skills/film/references/WIDGET-FEEDBACK.md

27 KB · Oct 10, 2026 · 18:02 UTC

↓ Download file

See the change to this file →

# Reading the film boards' feedback

Read the submitted decision from the current message and attached widget context; use a context-reading tool only when exposed by the host. Follow the host conventions in `../SKILL.md`. After opening a board, wait for the user's decision. If the payload is inaccessible, use the text fallback and preserve the feedback fields documented below.

The same silent channel also carries **work-in-progress state** while the user
is still marking things up, so a typed "go with the second one" can usually be
resolved without a send. In-progress state is never a decision. It stops
updating once a board is sent, so the payload of a send is never overwritten by
a half-finished markup behind it.

**A board is the whole turn. Send no prose with it — none above, none below.**
Not a preamble, not a summary of what is on it, not "let me know what you
think". Every board states its own ask: it has a header, a count, a hint line
and one button. Prose repeating that ask puts a second call to action beside the
first — the user is now looking at a text box and a button that want the same
decision, and the usual outcome is that they type what the board was built to
collect, which is the one thing this doc already tells you not to invite.

Anything the user genuinely needs to know before deciding belongs **inside** the
board, in the field that exists for it (`note` on the shot list, `purpose` and
`notes` on the scene editor, `judge` where a board has one) — never in a chat
message wrapped around it.

**Speak after they act.** Their feedback message is the cue: the readback, what
it changed, the cost, the next step all go there. That is also the only place a
readback is worth anything, because until they press the button there is nothing
to read back.

The single exception is a hard blocker: if the board cannot be rendered at all,
say so in one line and fall back.

**One board per decision set — and queue discipline when there are several.**
Things decided together go on ONE board (a batch of takes = one scene editor
carrying the whole film; a planning pass = one shotlist board with all scenes). Parallel boards each demanding
a send is the documented flunky-confirmation failure: the first send moves
the conversation forward and the other boards die unanswered. When several
boards ARE legitimately open (a review queue), one board's feedback is **one
item, not a green light** — act on it, return to the queue, and advance the
pipeline only when the queue is empty or the user says move on.

**Suggested prefills.** `picsart_film_setup` takes a `suggested` input:
your inferences from the material, with a one-line why each. Fill it before
every call with what the script already answers, so the console opens on the
material rather than on its defaults. `current` (previously locked state) always
wins over `suggested`. The film-setup console **applies suggestions silently**
and validates every id against its own options, dropping what it does not
recognise — so pass only what the material really decides: a wrong prefill reads
to the user as a decision someone already made. The feedback payloads below are
unchanged by this: what comes back is what the user confirmed, however it was
seeded.

Every payload carries `type` and `version`. If `version` differs from the one
documented here, read the block on its own terms. `shotlist_board_feedback` is at
**v3**; `asset_sheet_feedback` at **v3**; `asset_review_feedback` at **v4**;
`film_setup_feedback` at **v3**; the rest are v1 (versions read off the widget
code, 2026-09-10; `scene_editor_feedback` re-read on 2026-09-25). The contracts
for `model_choice_feedback` (the Stage 1 model pick) and `asset_review_feedback`
are documented in `REVIEW-FEEDBACK.md` beside this file and used unchanged here
—
with one film-only addition: an `approved` asset is archived with
`picsart_save_asset` — the tool the video flow does not have — carrying
`projectFolderUid`, as **`locked`, with no `stressTest`** — the approval is
the lock (2026-09-04; the gate accepts it since 2026-09-05). See `film-assets`
step 4.
## `scene_editor_feedback`

The scene editor (`picsart_scene_editor`, widget
`ui://widget/picsart-scene-editor-v1.html`) is where takes and cuts are
reviewed. It opens on the scene document you pass as `scene` (a film with
exactly one video may pass `videoUrl` instead), plays it in the user's browser,
and lets them trim, split, delete, duplicate, adjust, change speed, effects,
volume and size, pin comments on the picture and mark stretches of the
timeline. **It is free and renders nothing** — no file, no credits, no
`videoUrl` in the reply. It sends this when the user presses **Approve** or
**Send with notes**:

```json
{
  "type": "scene_editor_feedback",
  "version": 1,
  "title": "Cully Hill Boys — sc01 to sc03",
  "duration": 21.4,
  "verdict": "needs_changes",
  "edited": true,
  "stateHash": "9f2c41d0",
  "document": { "…": "the whole scene document, as the user left it" },
  "comments": [
    { "id": "c1", "instruction": "five fingers on his left hand here", "time": 14.6,
      "scenePoint": { "x": 312, "y": 260 }, "layerId": "clip-3",
      "layerPoint": { "x": 0.41, "y": 0.62 },
      "createdAt": 1790000000000, "updatedAt": 1790000000000 }
  ],
  "timelineComments": [
    { "id": "t1", "text": "the push-in is too fast here, make it a slow creep",
      "start": 8.2, "end": 11.0,
      "createdAt": 1790000000000, "updatedAt": 1790000000000 }
  ]
}
```

Every field (the widget's own `feedback.ts`):

- **`type`** / **`version`** — `scene_editor_feedback`, `1`.
- **`title`** — echoes the `title` you opened it with.
- **`verdict`** — `approved` | `needs_changes`.
- **`edited`** — whether the user committed any edit at all.
- **`document`** — the scene as they left it, their edits applied. When
  `edited` is true it supersedes the scene you opened.
- **`stateHash`** names the committed edit. Record it beside the cut in
  `film.json`: reopening the same state round-trips as the same edit, not a new
  one.
- **`duration`** is the scene's length as the engine resolved it — the cut's
  real running time, and what the ±10% runtime gate reads.
- **`comments`** are pins on the picture: `instruction` (the user's words),
  `time` (seconds on the scene's timeline), `scenePoint`, and `layerId` — the
  clip under the pin, `null` on a bare frame spot — with `layerPoint` inside it.
  A comment with several spots also carries `targets`, every spot in order.
- **`timelineComments`** are marked stretches: `text` (the user's words) and
  `start`/`end` in seconds on the scene's timeline. `start === end` is a note on
  one frame.
- **`generalComment`** — legacy; the editor no longer sends it. The comment
  sets are the whole of what the user wrote.

How to act on it — the verdict, the spend rules, the camera-change retake, kept
frames and mapping a time back to a shot — is in `REVIEW-FEEDBACK.md`
(`scene_editor_feedback`). The film's deltas:

- **`document` is the cut the user already made.** Its clips, in playback order —
  the clips of the montage's `track` layer, or top-level media layers in a scene
  built by hand — are the pieces: each over a source file with `content.trim`
  in that file's seconds. Write each window to its shot's `trim` with
  `trimSource: "user"`, record `stateHash` beside the cut, and carry `document`
  forward as the film's scene. Nothing is rendered to realise it: the next
  round reopens the editor on `document` itself, whose clips still reach into
  the whole source, so a shot trimmed a second too short can still be opened
  back up. Render with `picsart_media_export` only when a file is wanted — the
  settled cut, not every round. The originals in `Shots/` are never moved,
  overwritten or deleted. `film-edit` carries the sequence.
- **One editor carrying the whole film, not one per piece (2026-09-07).** The
  user has just watched this picture and cut it themselves; opening the editor
  for each resulting piece shows them their own edit N times over. Record the
  cut, say in one line what changed, and open the editor again only when the
  picture contains something they have **not** seen — a regenerated shot
  spliced in, an edit or extend that came back. Then it is one editor on the
  **whole cut** in playback order, never a single clip and never several at
  once.
- **Every retake is seen inside the cut.** A retake — like an edit or extend
  return — goes **into the cut**, the scene is rebuilt, and the whole cut goes
  back up with the changed seconds said in a line. The scene is one timeline,
  never several takes side by side. Every superseded url stays in the log, so
  going back to an earlier take is one call and no credits. `film-scenes` step 6
  carries the routing. (`picsart_video_compare` is out of the film flow,
  2026-09-07, the user's call: "let's get rid of `picsart_video_compare`, it's
  not needed".)

## `film_setup_feedback`

The console runs before the story and shot list. Its submitted v3 payload is:

```json
{
  "type": "film_setup_feedback", "version": 3,
  "world": "main",
  "selections": {
    "genre": "drama", "tone": "auto", "palette": "auto",
    "scheme": "analogous", "hue": "amber", "hueDegrees": 60,
    "ratio": "169", "duration": "90", "camera": "35mm", "lens": "ana"
  },
  "stylePrefix": "<the compiled prefix, verbatim>",
  "summary": "Drama · analogous around amber — 35mm film, Anamorphic, 16:9 · 1 min 30 sec.",
  "verdict": "locked"
}
```

- Store `stylePrefix` verbatim in `bible.stylePrefix`, selections in `bible.setup`,
  and `Number(selections.duration)` in `film.json.target.duration`. Keep the
  returned summary for readback. The submitted `locked` verdict is the look's
  lock; an initial tool result or unsent widget state is only a preview.
- If the prefix is empty, compile the accepted selections with
  `picsart_film_compile_prompt`, `kind: "look"`; map `ratio` to `look.frame`.
- Colour is `scheme` plus the optional hue. `palette` is always `auto` here;
  each shot may choose its own palette. With scheme Auto, the console omits
  `scheme`, `hue` and `hueDegrees`. With a scheme selected but no hue selected,
  keep the scheme without inventing a hue. Preserve both hue fields exactly
  when present: `green` + `130` reopens at 130°, not at green's 120° anchor.
- Pass `look.scheme` / `look.hue` inside `look` to
  `picsart_film_compile_prompt`. Pass top-level `scheme` / `hue` to
  `picsart_film_compile_asset_prompt`, which has no `look` object and silently
  drops one. Neither compiler consumes `hueDegrees`.
- A tone is `auto`, `italian60`, `american80`, `summer80`, `hongkong80`,
  `neonhk90`, `american90`, `imax`, or `custom`. It seeds camera and lens only.
  Changing camera or lens resets tone to Auto; changing colour does not.
  Seed tone before any explicitly requested rig values.
- A custom genre is `genre: "custom"` plus `customGenre` on the console.
  For the scene/look compiler, pass `look.customGenre` and omit `look.genre`;
  its enum does not accept `custom`. A custom tone uses `look.tone: "custom"`
  plus `look.customTone`. Use each tool's own exposed schema; the asset tool
  has a separate top-level contract.
- Colour reference images are handled from chat, outside the console. Inspect
  them for colour only; keep the durable URL with the bible, and pass
  `look.paletteReference: true` plus `look.customPalette` when there is wording
  to the scene/look compiler. Supply the image to generation only when the
  model supports a colour reference distinct from identity. Reuse a confirmed
  Drive copy; removing the reference from the look does not delete that file.
- Focal length, aperture, light, shot length and camera move are per shot.
  The console sends no `focal`, `aperture`, `light`, `shotlen` or `move` keys.
  Grain rides in camera stock; `grain`, `shot` and `pace` remain retired.
  The web console also sends no `handles`; preserve the film's existing
  handle policy independently of this feedback.
- `ratio` is `169`, `43`, `sq`, `34` or `vert`; filter models against it.
  Suggested ratios also accept labels and words (`9:16`, `vertical`, `tiktok`).
  Retired landscape ratios reopen as `169`, and `45` as `34`.
- Reopen with `current.selections`, which wins over suggestions. One setup is
  stored per world. Decide what carries the accent when designing assets;
  the scheme determines hue relationships, not objects. Resolve `bible.palette`
  per `PRESETS-LOOKS.md`; with scheme Auto use each location's own colours.

### Older setups

Preserve an already locked `bible.stylePrefix` verbatim until the user reopens
and changes the look. When reopening a pre-scheme setup, send `palette: "auto"`,
name the former palette in `suggested.why`, and omit old `focal` and `aperture`.
An old `lens: "zoom"` reopens as `auto`. Invite the user to choose a matching
scheme if they want to retain the old palette direction; do not silently map it.

For v1 payloads, retain the stored prefix and translate deliberately: most
genre ids survive, `general` does not; old lens labels need current ids, and
`era`, `stock`, `texture`, `tempo` and a free-text palette are not current
controls. Unknown ids fall back to defaults, so do not guess a mapping.

## `asset_review_feedback`

Shape and rules in `REVIEW-FEEDBACK.md` beside this file (**v2**):
`total`, `approved[]`, `changes[]`, no `verdict`, and the invariant
`approved.length + changes.length === total`. The film-only parts:

- **Each `approved` entry is LOCKED immediately (2026-09-04)** —
  `picsart_save_asset`, one call per asset, `status: "locked"`, no
  `stressTest` (the gate locks on approval since 2026-09-05).
  The approval is the lock for every asset; there is no v1-review → v2-locked
  step and no passport board on the path. Batch the calls into one report, not
  one message per asset, and read `locked` in each result.
- **The tile carries the descriptor.** Pass it as `prompt` and its key lines as
  `info`, so a note on a tile is a note on one descriptor line or one panel.
- **Each `changes` entry is one regeneration, its `note` folded into that asset's
  own prompt and nothing else touched.** Then a fresh board with only those,
  `version` bumped and `previousUrl` set. Approved assets never reappear on a
  board.
- One board carries a whole scene block's assets, deduped — so one send settles
  a batch, and a lead is reviewed once rather than once per scene.
- **A user's own photo is never a tile.** They gave it; it is locked on save.
  Only a sheet generated *from* the photo comes to the board, with the judge
  line *"the same person as the photo — face, build. Ignore the pose."*

## `asset_sheet_feedback` — disabled (2026-09-05)

`picsart_asset_sheet` is disabled on the server: its decorator was swapped for a
no-op, so the tool is not registered and the board cannot open. The film's only
asset board is `picsart_asset_review`; approval there is the lock, and there is
no stress test. Descriptor edits, a narrator's voice pick and any "show me the
face again" happen in chat. The v3 contract text lives in git history should
the board ever be re-registered.

## `shotlist_board_feedback`

```json
{
  "type": "shotlist_board_feedback", "version": 3,
  "scope": ["sc01"], "verdict": "approved",
  "scenes": [
    { "scene": "sc01", "slug": "INT. GARAGE — DAY",
      "order": ["12A", "12C", "12A′"], "cut": ["12B"], "reordered": true,
      "shots": [
        { "id": "12A", "action": "Cal stops on the threshold.",
          "tags": "@cal @garage_day",
          "values": { "size": "WS", "move": "locked off", "lens": "54°",
                      "light": "window", "palette": "slate", "sec": "7" },
          "recap": "Wide · Locked off · 35mm · 7s" },
        { "id": "12B", "action": "…", "values": { }, "recap": "…", "cut": true },
        { "id": "12C", "action": "Tobin goes still before he answers.",
          "values": { }, "recap": "…", "edited": true },
        { "id": "12A′", "action": "", "values": { }, "recap": "…", "added": true }
      ] }
  ]
}
```

- **Each scene's `shots` is the FINAL list** — every shot, every one of its six
  values, in `order`. **Replace what the board owns with it wholesale — `action`,
  `line`, `tags`, `values`, `order`, `cut` / `added` / `edited` — never merge
  those field by field.** v2 sent a diff (`edits` as changed-keys only); v3 sends
  the finished list, because the board is now where the plan is written rather
  than annotated. What the board never carried stays on the shot by id: `design`,
  `refs`, `run`, `trim`. A changed `action` that tells a different story than
  the story's paragraph is a story note: the paragraph in `docs/story.md` is
  rewritten and shown for the yes, then the cards are rebuilt from it — never a
  prompt edit, and never another board in reply (`film-development`,
  2026-09-09).
- **`scope` is the law of the payload**: the approval covers exactly the scenes
  it names — all of them, none beyond. It approves the **list**, not the spend:
  each dispatch is quoted with `picsart_preflight` in chat and waits for its own
  yes (2026-09-07, `film-scenes`).
- One board carries **all scenes of a planning pass** (`scenes` on the tool
  call), so one approval covers the set.
- `verdict` is always `approved` — the board has one button. v2's
  `needs_changes` is gone: edits are not objections, they are the plan.
- **Every shared vocabulary is one library now, and several grew.** The board's
  moves, sizes, lens anchors, lights and rhythm are the same lists the film-setup
  console and the review board draw, and the same ones `PRESETS-CAMERA.md`,
  `PRESETS-LIGHTING.md` and `PRESETS-ACTING.md` define — so a plan and the board
  that renders it can no longer mean different things by the same word. Ids
  retired in the merge still **resolve**, and what comes back is always the
  canonical one:

  | Old id | Resolves to |
  |---|---|
  | `pull back` · `handheld` · `tracking` · `pan` | `slow pull-back` · `handheld settle` · `tracking lateral` · `slow pan` |
  | `14°` · `36°` · `75°` · `94°` | `15°` · `40°` · `74°` · `90°` — the board's four mislabelled anchors |
  | `top-down` | `overhead` |
  | `hard sun` | `overhead fall` |
  | `hold` | `calm` |

  Two do **not** resolve, on purpose. `ots` as a *size* is dropped — it names an
  arrangement, and `arrangement` is where it goes. The review board's `neutral`,
  `tense`, `wary`, `relief` and `broken` are dropped — they were blends with no
  position on the acting wheel, and guessing one is worse than asking again.
- **Every shot carries TWO durations, and they are different numbers.**
  `values.sec` is the CUT length — what the animatic holds and what the ±10%
  runtime gate measures. `genSec` is the GENERATION length — `sec` plus a handle
  at each end, snapped **up** to a duration the model offers. **Generate at
  `genSec`, then trim to `sec`.** They were one number until 2026-08-28, which
  made "generate long, cut short" structurally impossible: lengthening a take to
  buy trim room would have inflated the animatic and broken the runtime gate.

  `genSec === sec` means this shot has no handles — either the film turned them
  off (`handles: "off"` on the tool call) or the card did (`values.handles`).
  Never assume the handle is 2s: snapping to the model's ladder can give more,
  and at the ceiling it gives less. Derive it as `(genSec − sec) / 2`.
- **A preset id is a KEY, not prose.** Every id below names one line of
  compiled text in a reference file, and that line is the hint you were waiting
  for: **look it up and paste it into the block verbatim**, resolving only its
  `<placeholders>` from the scene. Do not paraphrase it, do not "improve" it,
  and do not write your own sentence about the light or the move because the id
  reads self-explanatory. The whole point of the console is that what the user
  saw is what gets compiled — `light: 'firelight'` means one specific sentence
  about a low flickering source below the eyeline and what it does to the far
  side of the face, and nothing else. The user picked it from a picture of that
  sentence. `picsart_film_compile_prompt` is what turns the id into it.
- `values` are preset ids, the **six the board asks** always present:
  `size` establishing|EWS|WS|MWS|MS|MCU|CU|ECU|detail — a DISTANCE only ·
  `move` a camera-move id from
  `../../film-scenes/references/PRESETS-CAMERA.md` (`locked off`, `slow push-in`,
  `orbit`, `whip pan`, `time-lapse`, …) ·
  `lens` as its field of view, ten anchors 10°|15°|24°|31°|40°|54°|65°|74°|90°|104° ·
  `light` any of the **seventeen setups** in `../../film-scenes/references/PRESETS-LIGHTING.md`
  (auto|window|practicals|night practical|work light|firelight|silhouette|
  contre-jour|overhead fall|soft cross|overcast|golden hour|blue hour|
  open shade|dappled shade|street light|moonlight — the last six are the
  exterior row) ·
  `palette` `auto` or one of the **seventeen shot palette ids** (slate…ink — the board offers
  the shot palettes retain their own preview stills; the setup uses scheme/hue) ·
  `sec` 3|5|7|8|10|12. There is no `pace` (retired 2026-09-04): a value you
  still pass under that key is dropped, not displayed.
  A value you passed that the board has no preset for **comes back unchanged** —
  it is displayed verbatim and never snapped to a neighbour.
- `arrangement`, `height` and `handles` are **pass-throughs, not controls.** The
  board dropped their pills — an arrangement and a camera height are decisions
  the plan makes, not adjectives a card carries — so they come back only if you
  sent them, resolved through their alias maps (`top-down` → `overhead`) but
  never asked about. Absent means the user was never given the chance to change
  what you sent, not that they cleared it.
- **The board currently lists only the camera moves that have a preview clip**,
  by owner decision — a tile that plays the move teaches it, a 30px arrow does
  not. The vocabulary is unchanged: all 50 ids still resolve, a plan already
  written against one of the unpreviewed moves still comes back carrying it, and
  the pill shows an unknown value as itself. So do not read a short move list as
  the library having shrunk, and do not rewrite a shot's move because the board
  could not offer it back.
- Per-shot flags, at most one each: **`cut`** — dropped from the scene, generate
  nothing for it, and it stays out of `order`. **`added`** — created on the board,
  so it has no prompt history and needs one written from scratch. **`edited`** —
  differs from what you passed.
- `recap` is the board's own one-line readback of the five decisions that matter
  at a glance. Quote it back rather than reassembling it from ids.
- `reordered` compares only the shots that survived, so cutting a middle shot is
  reported as a cut and not also as a move.

**Take review is not on this board any more.** v2 carried `takeAction`
(`accept` / `reshoot` / `approve_start_frame`), an embedded shot `design`, its
compiled `blocks`, and a `request: "video_review"` escalation. All are gone with
the surfaces that produced them: this board plans, and a take is judged in
the scene editor (`picsart_scene_editor`), which owns the verdict, the user's own
trims and splits, and the comments that direct another take. Do not look for a take verdict here.

## `final_cut_feedback`

The Final Cut console (`picsart_final_cut`) is the one surface here that **changes
the picture instead of reporting an opinion about it**. It mounts a real editor in
the chat; the user trims, splits and polishes the assembled cut, and saving renders
the file in their browser. Spec: `../../../docs/widget-specs/final-cut.md`.

```json
{
  "type": "final_cut_feedback", "version": 1,
  "verdict": "saved",
  "title": "Cully Hill Boys — final cut",
  "videoUrl": "https://…/export.mp4",
  "replayUrl": "https://…/export.json",
  "duration": 78.4,
  "stateHash": "b3f1…"
}
```

- **`verdict: "saved"` means the picture changed.** `videoUrl` is the new cut —
  rendered by the same engine that drew the preview the user was watching, so there
  is nothing to verify, no seam to re-check and no draft to compare against.
- **Save BOTH URLs to `picsart_drive` before anything else.** They are temporary
  CDN URLs. The replay document is the one that matters longer: hand it back as
  `replayUrl` on the next `picsart_final_cut` call and the user resumes inside their
  own edit rather than restarting from a flattened file. An mp4 alone loses the
  edit history.
- **This spent nothing**, and that is a rule, not a happy accident: the render ran
  in the browser, not through `picsart_media_export`. Do not re-export the result
  server-side to "make it real" — that spends a GPU render and a second Drive file
  to reproduce something you were already handed.
- Record `stateHash` in `film.json` alongside the URLs. It names the exact edit both
  files came from, so a later save of the same edit is recognisable as the same edit.
- **`verdict: "discarded"` means they closed the editor, not that they rejected the
  cut.** Nothing was produced and nothing changed. Ask what they want; do not read
  it as a request for changes.
- A save carrying an **`error`** means the export or its upload failed. The verdict
  is still theirs — only the file is missing, and their edit is still on screen until
  they close it. Report the failure plainly and offer to reopen the console; never
  fall back to a server-side render, which would re-render work the browser
  already did.

## Grading — no board for now

`picsart_grade_console` was retired on 2026-08-21 while the earlier stages are
made right, and no grading panel exists yet. Until one does it has no
feedback contract: resolve looks with `picsart_media_resolve_looks`, choose with
the host's question interface, and apply via `picsart_media_apply_look` (see
`film-finishing`).

## `render_monitor_feedback`

```json
{
  "type": "render_monitor_feedback", "version": 1,
  "title": "sc01 drafts",
  "done": [
    { "label": "1A", "model": "<the film's video model>", "url": "https://…", "jobId": "job_…" }
  ],
  "failed": [
    { "label": "1B", "model": "<the film's video model>", "error": "FAILED" }
  ],
  "generalComment": null
}
```

- The monitor polls `picsart_job_status` itself and sends this **automatically
  when every job reaches a terminal state** (the user can also send early).
  This is what replaces "ping me when it's done" — the message wakes you; act
  on it: log `done[]` takes into the plan (URLs expire — Drive what matters),
  and regenerate only `failed[]`.
- A monitor left open with jobs still running publishes silent progress
  context; as everywhere, that is awareness, not a decision.

## When the boards are not available

Every board has a working text form and the flow must not stall without widgets
(the docs used to call this "tier 1"; it means only this — no boards):
the shotlist renders as a markdown table (so does the pipeline map, which has no
board at all any more); setup, shot design, and acting
run as the host's question interface menus built from the `PRESETS-*.md` files (previews = the
compiled fragment text); asset sheets show reference images inline with the
descriptor as a numbered list so edits can name a line. Keep the same JSON
bookkeeping in `film.json` either way — the state schema does not know whether a
widget or a question produced the decision.

SHA-256: 04e844e8871ede5cb9ff3db0801c964f4bc671c50fef5468a530c267416a95e6