{
  "schemaVersion": "1.0",
  "title": "Hermes streaming cursors, deadlines, and cancellation",
  "description": "Use this reference when a Hermes-backed Action must survive a delivery disconnect, deadline, or cancellation request. It defines the native AIP action-event position and the evidence available after interruption.",
  "canonical": "https://getaip.org/docs/connectors/hermes-agent/reference/streaming-cursors-and-cancellation",
  "route": "/docs/connectors/hermes-agent/reference/streaming-cursors-and-cancellation",
  "source": "docs/connectors/hermes-agent/reference/streaming-cursors-and-cancellation.md",
  "protocol": "Agent Interoperability Protocol",
  "protocolVersion": "1.0",
  "section": "Connectors",
  "documentType": "Connector",
  "language": "en",
  "downloads": {
    "md": "/docs/download/connectors/hermes-agent/reference/streaming-cursors-and-cancellation.md",
    "txt": "/docs/download/connectors/hermes-agent/reference/streaming-cursors-and-cancellation.txt",
    "json": "/docs/download/connectors/hermes-agent/reference/streaming-cursors-and-cancellation.json",
    "pdf": "/docs/download/connectors/hermes-agent/reference/streaming-cursors-and-cancellation.pdf"
  },
  "content": {
    "format": "text/markdown",
    "markdown": "---\ntitle: Hermes streaming cursors, deadlines, and cancellation\ndescription: >-\n  Look up the exact AIP action-event resume cursor, native SSE delivery,\n  deadline, and cancellation behavior for Hermes-backed actions\nkind: reference\naudience: application-developer\nappliesTo: \"1.x\"\nwritingStandard: \"aip-docs/1.0\"\nlastReviewedRevision: \"97be86e9efedf07ecf1783b03800f683f107fb04\"\nconnector: hermes-agent\ncapabilityIds:\n  - cap:hermes_agent:<endpoint_id>:chat_stream\n  - cap:hermes_agent:<endpoint_id>:responses_stream\n  - cap:hermes_agent:<endpoint_id>:run_events\n  - cap:hermes_agent:<endpoint_id>:operator\n  - cap:hermes_agent:<endpoint_id>:session_chat_stream\n---\n\n# Hermes streaming cursors, deadlines, and cancellation\n\nUse this reference when a Hermes-backed Action must survive a delivery\ndisconnect, deadline, or cancellation request. It defines the native AIP\naction-event position and the evidence available after interruption.\n\nThe AIP cursor resumes delivery. It does not restart provider execution,\nguarantee exactly-once consumption, or prove that cancellation stopped a model,\ntool, message, memory, or network effect.\n\n## Position types\n\nThese positions are not interchangeable.\n\n| Position | Example | Owner | Valid use |\n|---|---|---|---|\n| AIP action-event cursor | `aev_cursor_42_17` | AIP runtime | Resume the same Action event route |\n| Legacy event-only cursor | `evt_cursor_42` | AIP runtime | Accepted input without a retained chunk position |\n| AIP chunk sequence | `17` | AIP lifecycle store | Order chunks inside one Action |\n| Native SSE event ID | AIP event ID or `chunk:17` | `aipd` renderer | Identify one delivered SSE frame, not route position |\n| Hermes SSE `id` | Provider-defined or absent | Hermes endpoint | Interpret an upstream frame only |\n| Responses `sequence_number` | Provider integer | Hermes Responses API | Order provider Responses events |\n| Structured-run event sequence | Provider integer | Hermes run store | Page provider run events through `run_events` |\n\nPersist the cursor emitted by the `aip.stream.cursor` frame. Keep provider IDs\nand sequences with their payloads, but never submit them as an AIP route cursor.\n\n## Native routes\n\nThe action-scoped routes are:\n\n```text\nGET /aip/v1/actions/{action_id}/events\nGET /aip/v1/actions/{action_id}/chunks\nPOST /aip/v1/actions/{action_id}/cancel\n```\n\nThe events route accepts these query parameters:\n\n| Parameter | Type | Default | Behavior |\n|---|---|---|---|\n| `cursor` | String | Start of retained view | Opaque action-event continuation |\n| `limit` | Integer | `100` | Clamped to `1..1000` across events and chunks |\n| `kind` or `kinds` | String list | All event kinds | Filters stored AIP events, not included chunks |\n| `include_chunks` | Boolean | `false` | Adds chunks after the selected events |\n| `follow` | Boolean | `false` | Returns native SSE and polls until terminal |\n\nThe chunks route fixes the event-kind filter to `aip.stream.chunk` and enables\nchunk inclusion. Both routes use the same combined cursor implementation.\n\nReading requires visibility to the Action and its tenant. Cancellation is a\nseparate authorized lifecycle write.\n\n## Cursor grammar\n\nThe current runtime emits:\n\n```text\naev_cursor_<event_offset>_<last_chunk_sequence|none>\n```\n\nFor example:\n\n```text\naev_cursor_42_17\naev_cursor_42_none\n```\n\nThe route also accepts the legacy event-only form:\n\n```text\nevt_cursor_<event_offset>\n```\n\nTreat all forms as opaque. The event offset is an implementation position in\nthe retained event store, not the number of matching Action events returned to\nthe caller. Filtering can advance it across records that are not returned.\n\nA legacy cursor carries no chunk position. With `include_chunks=true`, the\nruntime can return retained chunks from the beginning. Prefer the combined\ncursor once the route has emitted one.\n\nMalformed prefixes, missing components, non-numeric event offsets, and invalid\nchunk sequences return `query.invalid_cursor`. An event position outside the\nretained replay window returns `stream.cursor_expired`.\n\n## Page selection\n\nOne action-event read proceeds in this order:\n\n1. parse the event and chunk positions;\n2. read stored events for the Action using the event position and kind filters;\n3. subtract the returned event count from the page limit;\n4. when requested, append chunks whose AIP sequence is greater than the chunk\n   position until the remaining row capacity is used;\n5. return the advanced combined cursor and current Action terminal flag.\n\nThe default page has at most 100 combined records. The caller's requested\nlimit is clamped to 1,000. Stored event selection also stops before exceeding a\n4 MiB event-page bound.\n\nThe JSON response has separate arrays:\n\n```json\n{\n  \"action_id\": \"act_0123456789abcdef0123456789abcdef\",\n  \"events\": [],\n  \"chunks\": [],\n  \"cursor\": \"aev_cursor_42_17\",\n  \"terminal\": false\n}\n```\n\nEvents are returned before chunks. The arrays are not merged into one\nchronological sequence. Within `chunks`, order by the AIP `sequence`; within\n`events`, retain the store order. Use domain identifiers to correlate an event\nand chunk rather than comparing their array positions.\n\nThe kind filter applies only to `events`. Setting\n`kind=aip.stream.chunk` does not replace `include_chunks=true` when the caller\nneeds lifecycle chunks.\n\n## Native SSE frames\n\nWith `follow=true`, `aipd` renders repeated action-event pages as SSE.\n\n| SSE event name | SSE `id` | Data | Resume meaning |\n|---|---|---|---|\n| Stored AIP event kind | AIP event ID | `{ \"event\": ... }` | One record only; not a route cursor |\n| `aip.stream.chunk` | `chunk:<sequence>` | `{ \"chunk\": ... }` | One chunk only; not a route cursor |\n| `aip.stream.cursor` | Combined AIP cursor | `{ \"next_cursor\": ... }` | Persist this value for route resume |\n| `aip.stream.terminal` | Combined AIP cursor | Action ID and terminal flag | Delivery reached a terminal Action view |\n| `aip.error` | No resumable ID | Typed protocol error | Stop and apply the error decision |\n\nThe follow implementation polls every 500 milliseconds when no frame is\nready. The outer SSE connection sends a `keep-alive` comment every 15 seconds.\nNeither value is an Action SLA or a provider heartbeat.\n\nFollow stops after the Action view is terminal or after a protocol error. The\nterminal frame means the lifecycle is terminal; read status or result for its\nauthoritative outcome and receipts.\n\n## `Last-Event-ID` handling\n\nThe HTTP binding selects the query `cursor` first. Only when it is absent does\nit read the `Last-Event-ID` header.\n\nThis precedence lets a client override an automatically retained SSE event ID\nwith its last verified combined cursor. That matters because a connection can\nbreak after an AIP event ID or `chunk:<sequence>` frame but before the following\n`aip.stream.cursor` frame.\n\nSafe persistence rules:\n\n1. accept a cursor only from `aip.stream.cursor.data.next_cursor` or the\n   terminal frame's combined ID;\n2. commit application processing before committing that cursor;\n3. reconnect to the same Action route and authorization context;\n4. send the committed value as the `cursor` query parameter;\n5. tolerate a repeated event or chunk and reject conflicting duplicate data.\n\nDo not persist the latest arbitrary SSE `id`. Do not construct a combined\ncursor from an AIP event ID and chunk sequence.\n\n## Cursor error decisions\n\n| Error or observation | Meaning | Decision |\n|---|---|---|\n| `query.invalid_cursor` | The supplied value is not a valid route cursor | Restore the last committed combined cursor; do not guess a position |\n| `stream.cursor_expired` | The event position is outside retained replay | Read Action status/result, record the delivery gap, and reconcile required effects |\n| Empty non-terminal page | No new matching record is currently retained | Continue bounded polling or follow; do not submit a replacement Action |\n| Repeated AIP event ID | Delivery replayed a stored event | De-duplicate by event ID and compare content |\n| Repeated chunk sequence | Delivery replayed a chunk | Accept only identical content for that Action and sequence |\n| Conflicting chunk sequence | Retained evidence is inconsistent | Stop consumption and investigate storage/publication integrity |\n| Terminal frame without expected provider evidence | AIP lifecycle settled before the client saw all expected provider detail | Read the result and preserve the evidence gap |\n\nCursor expiry is a delivery-evidence gap. It is not evidence that the Action\ndid not run.\n\n## Deadline boundaries\n\nThe connector publishes these timeout classes:\n\n| Capability family | Published timeout | Connector request boundary |\n|---|---:|---|\n| `chat_stream`, `responses_stream`, `run_events`, `session_chat_stream` | 300,000 ms | Trusted deadline or cancellation can stop earlier; default client permits up to 900,000 ms |\n| `operator` | 900,000 ms | Operator deadline, policy timeout, and provider state can settle earlier |\n| Non-streaming Hermes operation | 60,000 ms | Some operation-specific clients use a shorter or longer request timeout |\n\nPublished values are contract declarations, not observed latency or\navailability. A trusted execution deadline is carried separately from the\nconnector client's HTTP timeout. Reaching either boundary does not roll back\nwork already accepted by Hermes or an external tool.\n\n## Native Action cancellation\n\n`POST /aip/v1/actions/{action_id}/cancel` accepts an optional JSON reason:\n\n```json\n{\n  \"reason\": \"The requester no longer needs this operation\"\n}\n```\n\nThe runtime performs these lifecycle actions:\n\n1. authorize a write against the target Action;\n2. if the Action is currently active, wake its trusted cancellation token and\n   invoke the active connector cancellation callback;\n3. mark the Action lifecycle and queued record cancelled;\n4. append `aip.action.cancelled`;\n5. return an AIP `ActionResult` with status `cancelled` and\n   `{ \"cancelled\": true }` output.\n\nThe connector callback is active-only. Cancelling an inactive record can\nchange the AIP lifecycle without calling Hermes. The returned result is an AIP\nacknowledgement, not provider terminal evidence.\n\nClosing a follow connection performs none of these steps.\n\n## Hermes cancellation effects\n\n| Active Action family | Connector/provider effect | Required reconciliation |\n|---|---|---|\n| Chat or Responses stream | Wakes the connector token and drops the active provider stream; Hermes attempts to interrupt its task after disconnect | Read original AIP result; inspect session, stored response, tools, and delivery effects |\n| Session chat stream | Drops the active session stream cooperatively | Read the transcript and external effects; do not infer rollback |\n| Structured `run_events` read | Stops the observation Action, not necessarily the bound Hermes run | Read `run_status`; invoke separately governed `run_stop` when provider interruption is required |\n| Active operator source or resume | Records cancellation intent, maps resume to source, attempts provider stop, and reconciles within its grace | Inspect operator binding and provider state; native cancel output omits the provider classification |\n| Operator already at `requires_human` | No active connector callback exists | Use a governed `deny` resume for the prompt or separately approved `run_stop` for full interruption |\n\nProvider completion can win a race with cancellation. Conversely, the AIP\nlifecycle can report cancelled while provider state remains unknown. Preserve\nboth observations and do not replace one with the other.\n\n`run_stop` is a provider mutation with its own capability contract, approval,\nAction ID, and idempotency key. It is not an alias for native Action cancel.\n\n## Security and evidence\n\nAction-event reads and cancellation use the transport-authenticated principal\nand Action ownership or tenant context. Do not move a cursor to another tenant,\nprincipal, Action, route, or deployment.\n\nEvent and chunk payloads can contain prompts, model output, reasoning, tool\narguments, results, personal data, and provider identifiers. Encrypt retained\ncursors with their application record, but redact or minimize the payloads\nstored beside them.\n\nFor an interrupted operation, retain:\n\n- deployment and endpoint identity;\n- capability and Action ID;\n- last committed combined cursor;\n- last accepted AIP chunk sequence and event IDs;\n- cancellation reason and timestamp when present;\n- final AIP status/result and receipts;\n- separately verified Hermes and external-system state.\n\nThis evidence is source-aligned. It does not establish live cancellation,\ndurable retention, provider availability, or production qualification.\n\n## Related documentation\n\n- [Stream chat and Responses](../guides/chat-and-response-streaming.md)\n- [Run an operator lifecycle](../guides/operator-lifecycle.md)\n- [Structured runs and approvals](../capabilities/durable-runs-and-approvals.md)\n- [Use native AIP](../../../guides/use-native-aip.md)\n- [Transport bindings](../../../reference/transport-bindings.md)\n- [Errors and recovery](../../../reference/errors.md)\n",
    "text": "Hermes streaming cursors, deadlines, and cancellation\n\nUse this reference when a Hermes-backed Action must survive a delivery\ndisconnect, deadline, or cancellation request. It defines the native AIP\naction-event position and the evidence available after interruption.\n\nThe AIP cursor resumes delivery. It does not restart provider execution,\nguarantee exactly-once consumption, or prove that cancellation stopped a model,\ntool, message, memory, or network effect.\n\nPosition types\n\nThese positions are not interchangeable.\n\n| Position | Example | Owner | Valid use |\n\n| AIP action-event cursor | aevcursor4217 | AIP runtime | Resume the same Action event route |\n| Legacy event-only cursor | evtcursor42 | AIP runtime | Accepted input without a retained chunk position |\n| AIP chunk sequence | 17 | AIP lifecycle store | Order chunks inside one Action |\n| Native SSE event ID | AIP event ID or chunk:17 | aipd renderer | Identify one delivered SSE frame, not route position |\n| Hermes SSE id | Provider-defined or absent | Hermes endpoint | Interpret an upstream frame only |\n| Responses sequencenumber | Provider integer | Hermes Responses API | Order provider Responses events |\n| Structured-run event sequence | Provider integer | Hermes run store | Page provider run events through runevents |\n\nPersist the cursor emitted by the aip.stream.cursor frame. Keep provider IDs\nand sequences with their payloads, but never submit them as an AIP route cursor.\n\nNative routes\n\nThe action-scoped routes are:\n\nGET /aip/v1/actions/{actionid}/events\nGET /aip/v1/actions/{actionid}/chunks\nPOST /aip/v1/actions/{actionid}/cancel\n\nThe events route accepts these query parameters:\n\n| Parameter | Type | Default | Behavior |\n\n| cursor | String | Start of retained view | Opaque action-event continuation |\n| limit | Integer | 100 | Clamped to 1..1000 across events and chunks |\n| kind or kinds | String list | All event kinds | Filters stored AIP events, not included chunks |\n| includechunks | Boolean | false | Adds chunks after the selected events |\n| follow | Boolean | false | Returns native SSE and polls until terminal |\n\nThe chunks route fixes the event-kind filter to aip.stream.chunk and enables\nchunk inclusion. Both routes use the same combined cursor implementation.\n\nReading requires visibility to the Action and its tenant. Cancellation is a\nseparate authorized lifecycle write.\n\nCursor grammar\n\nThe current runtime emits:\n\naevcursor\n\nFor example:\n\naevcursor4217\naevcursor42none\n\nThe route also accepts the legacy event-only form:\n\nevtcursor\n\nTreat all forms as opaque. The event offset is an implementation position in\nthe retained event store, not the number of matching Action events returned to\nthe caller. Filtering can advance it across records that are not returned.\n\nA legacy cursor carries no chunk position. With includechunks=true, the\nruntime can return retained chunks from the beginning. Prefer the combined\ncursor once the route has emitted one.\n\nMalformed prefixes, missing components, non-numeric event offsets, and invalid\nchunk sequences return query.invalidcursor. An event position outside the\nretained replay window returns stream.cursorexpired.\n\nPage selection\n\nOne action-event read proceeds in this order:\n1. parse the event and chunk positions;\n2. read stored events for the Action using the event position and kind filters;\n3. subtract the returned event count from the page limit;\n4. when requested, append chunks whose AIP sequence is greater than the chunk\n   position until the remaining row capacity is used;\n5. return the advanced combined cursor and current Action terminal flag.\n\nThe default page has at most 100 combined records. The caller's requested\nlimit is clamped to 1,000. Stored event selection also stops before exceeding a\n4 MiB event-page bound.\n\nThe JSON response has separate arrays:\n\n{\n  \"actionid\": \"act0123456789abcdef0123456789abcdef\",\n  \"events\": [],\n  \"chunks\": [],\n  \"cursor\": \"aevcursor4217\",\n  \"terminal\": false\n}\n\nEvents are returned before chunks. The arrays are not merged into one\nchronological sequence. Within chunks, order by the AIP sequence; within\nevents, retain the store order. Use domain identifiers to correlate an event\nand chunk rather than comparing their array positions.\n\nThe kind filter applies only to events. Setting\nkind=aip.stream.chunk does not replace includechunks=true when the caller\nneeds lifecycle chunks.\n\nNative SSE frames\n\nWith follow=true, aipd renders repeated action-event pages as SSE.\n\n| SSE event name | SSE id | Data | Resume meaning |\n\n| Stored AIP event kind | AIP event ID | { \"event\": ... } | One record only; not a route cursor |\n| aip.stream.chunk | chunk: | { \"chunk\": ... } | One chunk only; not a route cursor |\n| aip.stream.cursor | Combined AIP cursor | { \"nextcursor\": ... } | Persist this value for route resume |\n| aip.stream.terminal | Combined AIP cursor | Action ID and terminal flag | Delivery reached a terminal Action view |\n| aip.error | No resumable ID | Typed protocol error | Stop and apply the error decision |\n\nThe follow implementation polls every 500 milliseconds when no frame is\nready. The outer SSE connection sends a keep-alive comment every 15 seconds.\nNeither value is an Action SLA or a provider heartbeat.\n\nFollow stops after the Action view is terminal or after a protocol error. The\nterminal frame means the lifecycle is terminal; read status or result for its\nauthoritative outcome and receipts.\n\nLast-Event-ID handling\n\nThe HTTP binding selects the query cursor first. Only when it is absent does\nit read the Last-Event-ID header.\n\nThis precedence lets a client override an automatically retained SSE event ID\nwith its last verified combined cursor. That matters because a connection can\nbreak after an AIP event ID or chunk: frame but before the following\naip.stream.cursor frame.\n\nSafe persistence rules:\n1. accept a cursor only from aip.stream.cursor.data.nextcursor or the\n   terminal frame's combined ID;\n2. commit application processing before committing that cursor;\n3. reconnect to the same Action route and authorization context;\n4. send the committed value as the cursor query parameter;\n5. tolerate a repeated event or chunk and reject conflicting duplicate data.\n\nDo not persist the latest arbitrary SSE id. Do not construct a combined\ncursor from an AIP event ID and chunk sequence.\n\nCursor error decisions\n\n| Error or observation | Meaning | Decision |\n\n| query.invalidcursor | The supplied value is not a valid route cursor | Restore the last committed combined cursor; do not guess a position |\n| stream.cursorexpired | The event position is outside retained replay | Read Action status/result, record the delivery gap, and reconcile required effects |\n| Empty non-terminal page | No new matching record is currently retained | Continue bounded polling or follow; do not submit a replacement Action |\n| Repeated AIP event ID | Delivery replayed a stored event | De-duplicate by event ID and compare content |\n| Repeated chunk sequence | Delivery replayed a chunk | Accept only identical content for that Action and sequence |\n| Conflicting chunk sequence | Retained evidence is inconsistent | Stop consumption and investigate storage/publication integrity |\n| Terminal frame without expected provider evidence | AIP lifecycle settled before the client saw all expected provider detail | Read the result and preserve the evidence gap |\n\nCursor expiry is a delivery-evidence gap. It is not evidence that the Action\ndid not run.\n\nDeadline boundaries\n\nThe connector publishes these timeout classes:\n\n| Capability family | Published timeout | Connector request boundary |\n\n| chatstream, responsesstream, runevents, sessionchatstream | 300,000 ms | Trusted deadline or cancellation can stop earlier; default client permits up to 900,000 ms |\n| operator | 900,000 ms | Operator deadline, policy timeout, and provider state can settle earlier |\n| Non-streaming Hermes operation | 60,000 ms | Some operation-specific clients use a shorter or longer request timeout |\n\nPublished values are contract declarations, not observed latency or\navailability. A trusted execution deadline is carried separately from the\nconnector client's HTTP timeout. Reaching either boundary does not roll back\nwork already accepted by Hermes or an external tool.\n\nNative Action cancellation\n\nPOST /aip/v1/actions/{actionid}/cancel accepts an optional JSON reason:\n\n{\n  \"reason\": \"The requester no longer needs this operation\"\n}\n\nThe runtime performs these lifecycle actions:\n1. authorize a write against the target Action;\n2. if the Action is currently active, wake its trusted cancellation token and\n   invoke the active connector cancellation callback;\n3. mark the Action lifecycle and queued record cancelled;\n4. append aip.action.cancelled;\n5. return an AIP ActionResult with status cancelled and\n   { \"cancelled\": true } output.\n\nThe connector callback is active-only. Cancelling an inactive record can\nchange the AIP lifecycle without calling Hermes. The returned result is an AIP\nacknowledgement, not provider terminal evidence.\n\nClosing a follow connection performs none of these steps.\n\nHermes cancellation effects\n\n| Active Action family | Connector/provider effect | Required reconciliation |\n\n| Chat or Responses stream | Wakes the connector token and drops the active provider stream; Hermes attempts to interrupt its task after disconnect | Read original AIP result; inspect session, stored response, tools, and delivery effects |\n| Session chat stream | Drops the active session stream cooperatively | Read the transcript and external effects; do not infer rollback |\n| Structured runevents read | Stops the observation Action, not necessarily the bound Hermes run | Read runstatus; invoke separately governed runstop when provider interruption is required |\n| Active operator source or resume | Records cancellation intent, maps resume to source, attempts provider stop, and reconciles within its grace | Inspect operator binding and provider state; native cancel output omits the provider classification |\n| Operator already at requireshuman | No active connector callback exists | Use a governed deny resume for the prompt or separately approved runstop for full interruption |\n\nProvider completion can win a race with cancellation. Conversely, the AIP\nlifecycle can report cancelled while provider state remains unknown. Preserve\nboth observations and do not replace one with the other.\n\nrunstop is a provider mutation with its own capability contract, approval,\nAction ID, and idempotency key. It is not an alias for native Action cancel.\n\nSecurity and evidence\n\nAction-event reads and cancellation use the transport-authenticated principal\nand Action ownership or tenant context. Do not move a cursor to another tenant,\nprincipal, Action, route, or deployment.\n\nEvent and chunk payloads can contain prompts, model output, reasoning, tool\narguments, results, personal data, and provider identifiers. Encrypt retained\ncursors with their application record, but redact or minimize the payloads\nstored beside them.\n\nFor an interrupted operation, retain:\n• deployment and endpoint identity;\n• capability and Action ID;\n• last committed combined cursor;\n• last accepted AIP chunk sequence and event IDs;\n• cancellation reason and timestamp when present;\n• final AIP status/result and receipts;\n• separately verified Hermes and external-system state.\n\nThis evidence is source-aligned. It does not establish live cancellation,\ndurable retention, provider availability, or production qualification.\n\nRelated documentation\n• Stream chat and Responses (../guides/chat-and-response-streaming.md)\n• Run an operator lifecycle (../guides/operator-lifecycle.md)\n• Structured runs and approvals (../capabilities/durable-runs-and-approvals.md)\n• Use native AIP (../../../guides/use-native-aip.md)\n• Transport bindings (../../../reference/transport-bindings.md)\n• Errors and recovery (../../../reference/errors.md)\n"
  },
  "integrity": {
    "algorithm": "sha256",
    "sourceDigest": "608e510725f9320f671dd7577c7b33894e5115ce07f33c031c97244c54957c8d"
  }
}
