@dbx-tools/shared-genie 0.3.43 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ export * as event from "./src/event.js";
2
+ export * as genieModel from "./src/genie-model.js";
3
+ export { eventDetector, detectStatus, detectAttachmentAdded, detectThinking, detectText, detectQuery, detectStatement, detectRows, detectSuggestedQuestions, eventsFromMessage } from "./src/event.js";
4
+ export { MessageStatusSchema, GenieThoughtSchema, ATTACHMENT_TYPES, GenieQueryAttachmentSchema, GenieAttachmentSchema, GenieMessageSchema, GenieResponseSchema, GenieSpaceSchema, TERMINAL_STATUSES, isTerminalStatus, humanizeStatus, detectAttachmentType, GenieChatLocationSchema, QuestionEventSchema, MessageEventSchema, StatusEventSchema, AttachmentEventSchema, ThinkingEventSchema, TextEventSchema, QueryEventSchema, StatementEventSchema, RowsEventSchema, SuggestedQuestionsEventSchema, ResultEventSchema, GenieChatEventSchema } from "./src/genie-model.js";
5
+ export type { MessageStatus, GenieThoughtType, GenieThought, KnownAttachmentType, AttachmentType, GenieQueryAttachment, GenieAttachment, GenieMessage, GenieResponse, GenieSpace, TerminalStatus, GenieChatLocation, QuestionEvent, MessageEvent, StatusEvent, AttachmentEvent, ThinkingEvent, TextEvent, QueryEvent, StatementEvent, RowsEvent, SuggestedQuestionsEvent, ResultEvent, GenieChatEvent, GenieChatEventType, GenieChatEventFields } from "./src/genie-model.js";
package/lib/index.js ADDED
@@ -0,0 +1,8 @@
1
+ // GENERATED by projen watch - DO NOT EDIT.
2
+ // Regenerated from the exporting modules in ./src.
3
+ // Hand edits are overwritten on the next watch; this file is read-only.
4
+ export * as event from "./src/event.js";
5
+ export * as genieModel from "./src/genie-model.js";
6
+ export { eventDetector, detectStatus, detectAttachmentAdded, detectThinking, detectText, detectQuery, detectStatement, detectRows, detectSuggestedQuestions, eventsFromMessage } from "./src/event.js";
7
+ export { MessageStatusSchema, GenieThoughtSchema, ATTACHMENT_TYPES, GenieQueryAttachmentSchema, GenieAttachmentSchema, GenieMessageSchema, GenieResponseSchema, GenieSpaceSchema, TERMINAL_STATUSES, isTerminalStatus, humanizeStatus, detectAttachmentType, GenieChatLocationSchema, QuestionEventSchema, MessageEventSchema, StatusEventSchema, AttachmentEventSchema, ThinkingEventSchema, TextEventSchema, QueryEventSchema, StatementEventSchema, RowsEventSchema, SuggestedQuestionsEventSchema, ResultEventSchema, GenieChatEventSchema } from "./src/genie-model.js";
8
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwyQ0FBMkM7QUFDM0MsbURBQW1EO0FBQ25ELHdFQUF3RTtBQUV4RSxPQUFPLEtBQUssS0FBSyxNQUFNLGFBQWEsQ0FBQztBQUNyQyxPQUFPLEtBQUssVUFBVSxNQUFNLG1CQUFtQixDQUFDO0FBQ2hELE9BQU8sRUFBRSxhQUFhLEVBQUUsWUFBWSxFQUFFLHFCQUFxQixFQUFFLGNBQWMsRUFBRSxVQUFVLEVBQUUsV0FBVyxFQUFFLGVBQWUsRUFBRSxVQUFVLEVBQUUsd0JBQXdCLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDcE0sT0FBTyxFQUFFLG1CQUFtQixFQUFFLGtCQUFrQixFQUFFLGdCQUFnQixFQUFFLDBCQUEwQixFQUFFLHFCQUFxQixFQUFFLGtCQUFrQixFQUFFLG1CQUFtQixFQUFFLGdCQUFnQixFQUFFLGlCQUFpQixFQUFFLGdCQUFnQixFQUFFLGNBQWMsRUFBRSxvQkFBb0IsRUFBRSx1QkFBdUIsRUFBRSxtQkFBbUIsRUFBRSxrQkFBa0IsRUFBRSxpQkFBaUIsRUFBRSxxQkFBcUIsRUFBRSxtQkFBbUIsRUFBRSxlQUFlLEVBQUUsZ0JBQWdCLEVBQUUsb0JBQW9CLEVBQUUsZUFBZSxFQUFFLDZCQUE2QixFQUFFLGlCQUFpQixFQUFFLG9CQUFvQixFQUFFLE1BQU0sbUJBQW1CLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBHRU5FUkFURUQgYnkgcHJvamVuIHdhdGNoIC0gRE8gTk9UIEVESVQuXG4vLyBSZWdlbmVyYXRlZCBmcm9tIHRoZSBleHBvcnRpbmcgbW9kdWxlcyBpbiAuL3NyYy5cbi8vIEhhbmQgZWRpdHMgYXJlIG92ZXJ3cml0dGVuIG9uIHRoZSBuZXh0IHdhdGNoOyB0aGlzIGZpbGUgaXMgcmVhZC1vbmx5LlxuXG5leHBvcnQgKiBhcyBldmVudCBmcm9tIFwiLi9zcmMvZXZlbnRcIjtcbmV4cG9ydCAqIGFzIGdlbmllTW9kZWwgZnJvbSBcIi4vc3JjL2dlbmllLW1vZGVsXCI7XG5leHBvcnQgeyBldmVudERldGVjdG9yLCBkZXRlY3RTdGF0dXMsIGRldGVjdEF0dGFjaG1lbnRBZGRlZCwgZGV0ZWN0VGhpbmtpbmcsIGRldGVjdFRleHQsIGRldGVjdFF1ZXJ5LCBkZXRlY3RTdGF0ZW1lbnQsIGRldGVjdFJvd3MsIGRldGVjdFN1Z2dlc3RlZFF1ZXN0aW9ucywgZXZlbnRzRnJvbU1lc3NhZ2UgfSBmcm9tIFwiLi9zcmMvZXZlbnRcIjtcbmV4cG9ydCB7IE1lc3NhZ2VTdGF0dXNTY2hlbWEsIEdlbmllVGhvdWdodFNjaGVtYSwgQVRUQUNITUVOVF9UWVBFUywgR2VuaWVRdWVyeUF0dGFjaG1lbnRTY2hlbWEsIEdlbmllQXR0YWNobWVudFNjaGVtYSwgR2VuaWVNZXNzYWdlU2NoZW1hLCBHZW5pZVJlc3BvbnNlU2NoZW1hLCBHZW5pZVNwYWNlU2NoZW1hLCBURVJNSU5BTF9TVEFUVVNFUywgaXNUZXJtaW5hbFN0YXR1cywgaHVtYW5pemVTdGF0dXMsIGRldGVjdEF0dGFjaG1lbnRUeXBlLCBHZW5pZUNoYXRMb2NhdGlvblNjaGVtYSwgUXVlc3Rpb25FdmVudFNjaGVtYSwgTWVzc2FnZUV2ZW50U2NoZW1hLCBTdGF0dXNFdmVudFNjaGVtYSwgQXR0YWNobWVudEV2ZW50U2NoZW1hLCBUaGlua2luZ0V2ZW50U2NoZW1hLCBUZXh0RXZlbnRTY2hlbWEsIFF1ZXJ5RXZlbnRTY2hlbWEsIFN0YXRlbWVudEV2ZW50U2NoZW1hLCBSb3dzRXZlbnRTY2hlbWEsIFN1Z2dlc3RlZFF1ZXN0aW9uc0V2ZW50U2NoZW1hLCBSZXN1bHRFdmVudFNjaGVtYSwgR2VuaWVDaGF0RXZlbnRTY2hlbWEgfSBmcm9tIFwiLi9zcmMvZ2VuaWUtbW9kZWxcIjtcbmV4cG9ydCB0eXBlIHsgTWVzc2FnZVN0YXR1cywgR2VuaWVUaG91Z2h0VHlwZSwgR2VuaWVUaG91Z2h0LCBLbm93bkF0dGFjaG1lbnRUeXBlLCBBdHRhY2htZW50VHlwZSwgR2VuaWVRdWVyeUF0dGFjaG1lbnQsIEdlbmllQXR0YWNobWVudCwgR2VuaWVNZXNzYWdlLCBHZW5pZVJlc3BvbnNlLCBHZW5pZVNwYWNlLCBUZXJtaW5hbFN0YXR1cywgR2VuaWVDaGF0TG9jYXRpb24sIFF1ZXN0aW9uRXZlbnQsIE1lc3NhZ2VFdmVudCwgU3RhdHVzRXZlbnQsIEF0dGFjaG1lbnRFdmVudCwgVGhpbmtpbmdFdmVudCwgVGV4dEV2ZW50LCBRdWVyeUV2ZW50LCBTdGF0ZW1lbnRFdmVudCwgUm93c0V2ZW50LCBTdWdnZXN0ZWRRdWVzdGlvbnNFdmVudCwgUmVzdWx0RXZlbnQsIEdlbmllQ2hhdEV2ZW50LCBHZW5pZUNoYXRFdmVudFR5cGUsIEdlbmllQ2hhdEV2ZW50RmllbGRzIH0gZnJvbSBcIi4vc3JjL2dlbmllLW1vZGVsXCI7XG4iXX0=
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Pure event-detection for `genieEventChat`. Given two
3
+ * `GenieMessage` snapshots (current + prior) and the surrounding
4
+ * `space_id`, derive the semantic deltas (status transitions, new
5
+ * attachments, new thoughts, SQL emission, warehouse submission,
6
+ * row-count progress, follow-up suggestions, text deltas) and
7
+ * yield them as typed {@link GenieChatEvent}s.
8
+ *
9
+ * Detectors are built through a single typed factory that ties
10
+ * each event's name to its scope (whole-message vs per-attachment)
11
+ * and payload shape, so a misnamed event or a payload that doesn't
12
+ * match its event fails to compile. An orchestrator walks the
13
+ * snapshot diff and yields every detector that fires in a stable
14
+ * order (status first, then per-attachment field deltas) so a
15
+ * subscriber that logs events as they arrive sees a sensible
16
+ * sequence.
17
+ *
18
+ * The module is intentionally pure: no `EventEmitter`, no `this`,
19
+ * no I/O, no module-level mutable state. The `message` and
20
+ * `result` events are NOT derived here - they belong to the chat
21
+ * lifecycle layer (the `genieEventChat` driver) because they track
22
+ * per-yield / per-turn-completion semantics rather than a
23
+ * field-level snapshot diff.
24
+ *
25
+ * @module
26
+ */
27
+ import { type GenieAttachment, type GenieChatEvent, type GenieChatEventFields, type GenieChatEventType, type GenieChatLocation, type GenieMessage } from "./genie-model.js";
28
+ /**
29
+ * What a single detector call returns: zero (`undefined`), one
30
+ * (fields object), or many (`fields[]`) events of the same type.
31
+ * Each result is the variant's payload fields **without** the
32
+ * `type` discriminator - the orchestrator stamps `type` when it
33
+ * yields the event.
34
+ */
35
+ type DetectorResult<T extends GenieChatEventType> = GenieChatEventFields<T> | GenieChatEventFields<T>[] | undefined;
36
+ /**
37
+ * Where in the wire shape a given event is derived from. Drives
38
+ * which arguments `detect` receives. `"message"` events watch
39
+ * `GenieMessage` itself; `"attachment"` events watch one slot of
40
+ * `message.attachments[]`. `"lifecycle"` events (`message`,
41
+ * `result`) are emitted by the chat driver directly and can't be
42
+ * built with {@link eventDetector} - they have no diff signature.
43
+ */
44
+ interface DetectorScope {
45
+ status: "message";
46
+ attachment: "attachment";
47
+ thinking: "attachment";
48
+ text: "attachment";
49
+ query: "attachment";
50
+ statement: "attachment";
51
+ rows: "attachment";
52
+ suggested_questions: "attachment";
53
+ question: "lifecycle";
54
+ message: "lifecycle";
55
+ result: "lifecycle";
56
+ }
57
+ /**
58
+ * `detect` callback signature for a given event type. Resolved
59
+ * from {@link DetectorScope}: `"message"` events get the top-level
60
+ * snapshot triple, `"attachment"` events get the per-slot quad,
61
+ * `"lifecycle"` events resolve to `never` (no diff-based detector
62
+ * exists for them).
63
+ */
64
+ type DetectFn<T extends GenieChatEventType> = DetectorScope[T] extends "message" ? (current: GenieMessage, previous: GenieMessage | undefined, space_id: string) => DetectorResult<T> : DetectorScope[T] extends "attachment" ? (current: GenieAttachment, previous: GenieAttachment | undefined, location: GenieChatLocation, index: number) => DetectorResult<T> : never;
65
+ /**
66
+ * Typed detector for one event in the {@link GenieChatEvent}
67
+ * union. The `type` field is the event name; `detect`'s signature
68
+ * is picked from {@link DetectorScope} based on `T`.
69
+ */
70
+ interface EventDetector<T extends GenieChatEventType> {
71
+ readonly type: T;
72
+ detect: DetectFn<T>;
73
+ }
74
+ /**
75
+ * Build an {@link EventDetector}. Pass the event name as the
76
+ * literal first arg and the matching `detect` callback as the
77
+ * second. TS infers `T` from the literal, narrows `detect`'s
78
+ * signature accordingly, and types the return as
79
+ * `EventDetector<T>`.
80
+ *
81
+ * Build-time guarantees:
82
+ *
83
+ * - `eventDetector("status2", ...)` fails - the name isn't in
84
+ * {@link GenieChatEvent}.
85
+ * - `eventDetector("status", attachmentArgsCallback)` fails -
86
+ * `"status"` is message-scoped, so `detect` must take
87
+ * `(GenieMessage, GenieMessage | undefined, string)`.
88
+ * - Returning a `ThinkingEvent`-shaped fields object from a
89
+ * `"status"` detector fails - the return type is constrained
90
+ * to `DetectorResult<"status">`.
91
+ *
92
+ * Lifecycle event names (`"message"`, `"result"`) resolve `detect`
93
+ * to `never` and won't compile, which is intentional: those have
94
+ * no diff signature and are emitted directly by the chat driver.
95
+ */
96
+ export declare function eventDetector<T extends GenieChatEventType>(type: T, detect: DetectFn<T>): EventDetector<T>;
97
+ /** Top-level `message.status` transitioned. */
98
+ export declare const detectStatus: EventDetector<"status">;
99
+ /** First time we see an attachment slot. */
100
+ export declare const detectAttachmentAdded: EventDetector<"attachment">;
101
+ /**
102
+ * One emit per new `(thought_type, content)` tuple on a query
103
+ * attachment. Value-based set diff: Genie can mutate existing
104
+ * thought slots in place (e.g. re-typing index 0 from
105
+ * `DATA_SOURCING` to `DESCRIPTION` while re-appending the
106
+ * original at index 1), so positional / append-only diff would
107
+ * miss re-types and double-count re-orders.
108
+ */
109
+ export declare const detectThinking: EventDetector<"thinking">;
110
+ /** Text-attachment `content` appeared or changed. */
111
+ export declare const detectText: EventDetector<"text">;
112
+ /** SQL transitioned undefined -> string, or changed. */
113
+ export declare const detectQuery: EventDetector<"query">;
114
+ /** Warehouse-statement id assigned. */
115
+ export declare const detectStatement: EventDetector<"statement">;
116
+ /**
117
+ * `row_count` changed - fires on every transition including the
118
+ * initial `undefined -> 0` and the post-execution `0 -> N`.
119
+ * Carries the statement id when available for correlation.
120
+ */
121
+ export declare const detectRows: EventDetector<"rows">;
122
+ /**
123
+ * Follow-up suggested-questions array appeared or changed.
124
+ * Compares structurally so a length-preserving content rewrite still fires.
125
+ */
126
+ export declare const detectSuggestedQuestions: EventDetector<"suggested_questions">;
127
+ /**
128
+ * Walk the diff between `current` and `previous` and yield every
129
+ * derived event the snapshot produced. Detector order mirrors
130
+ * Genie's wire ordering (status first, then per-attachment field
131
+ * deltas) so a subscriber that simply logs events as they arrive
132
+ * sees them in a sensible sequence.
133
+ *
134
+ * Caller responsibilities (not handled here):
135
+ *
136
+ * - Yield `{ type: "message", message: current }` BEFORE
137
+ * calling this, once per poll yield.
138
+ * - Yield `{ type: "result", ... }` AFTER calling this when
139
+ * `isTerminalStatus(current.status)` - per-turn lifecycle,
140
+ * not a per-snapshot field diff.
141
+ * - Decide what counts as a "fresh turn" and pass `undefined`
142
+ * for `previous` on turn boundaries, so anonymous-attachment
143
+ * state from a prior turn doesn't bleed in.
144
+ *
145
+ * Sync generator: the diff is pure CPU work, no awaits. Use
146
+ * `yield*` from an async generator to splice the events into a
147
+ * stream.
148
+ */
149
+ export declare function eventsFromMessage(current: GenieMessage, previous: GenieMessage | undefined, space_id: string): Generator<GenieChatEvent, void, void>;
150
+ export {};
@@ -0,0 +1,248 @@
1
+ /**
2
+ * Pure event-detection for `genieEventChat`. Given two
3
+ * `GenieMessage` snapshots (current + prior) and the surrounding
4
+ * `space_id`, derive the semantic deltas (status transitions, new
5
+ * attachments, new thoughts, SQL emission, warehouse submission,
6
+ * row-count progress, follow-up suggestions, text deltas) and
7
+ * yield them as typed {@link GenieChatEvent}s.
8
+ *
9
+ * Detectors are built through a single typed factory that ties
10
+ * each event's name to its scope (whole-message vs per-attachment)
11
+ * and payload shape, so a misnamed event or a payload that doesn't
12
+ * match its event fails to compile. An orchestrator walks the
13
+ * snapshot diff and yields every detector that fires in a stable
14
+ * order (status first, then per-attachment field deltas) so a
15
+ * subscriber that logs events as they arrive sees a sensible
16
+ * sequence.
17
+ *
18
+ * The module is intentionally pure: no `EventEmitter`, no `this`,
19
+ * no I/O, no module-level mutable state. The `message` and
20
+ * `result` events are NOT derived here - they belong to the chat
21
+ * lifecycle layer (the `genieEventChat` driver) because they track
22
+ * per-yield / per-turn-completion semantics rather than a
23
+ * field-level snapshot diff.
24
+ *
25
+ * @module
26
+ */
27
+ import { object } from "@dbx-tools/shared-core";
28
+ import { detectAttachmentType, } from "./genie-model.js";
29
+ /* ----------------------- detector factory ----------------------- */
30
+ /**
31
+ * Build an {@link EventDetector}. Pass the event name as the
32
+ * literal first arg and the matching `detect` callback as the
33
+ * second. TS infers `T` from the literal, narrows `detect`'s
34
+ * signature accordingly, and types the return as
35
+ * `EventDetector<T>`.
36
+ *
37
+ * Build-time guarantees:
38
+ *
39
+ * - `eventDetector("status2", ...)` fails - the name isn't in
40
+ * {@link GenieChatEvent}.
41
+ * - `eventDetector("status", attachmentArgsCallback)` fails -
42
+ * `"status"` is message-scoped, so `detect` must take
43
+ * `(GenieMessage, GenieMessage | undefined, string)`.
44
+ * - Returning a `ThinkingEvent`-shaped fields object from a
45
+ * `"status"` detector fails - the return type is constrained
46
+ * to `DetectorResult<"status">`.
47
+ *
48
+ * Lifecycle event names (`"message"`, `"result"`) resolve `detect`
49
+ * to `never` and won't compile, which is intentional: those have
50
+ * no diff signature and are emitted directly by the chat driver.
51
+ */
52
+ export function eventDetector(type, detect) {
53
+ return { type, detect };
54
+ }
55
+ /* ---------------------------- detectors ---------------------------- */
56
+ /** Top-level `message.status` transitioned. */
57
+ export const detectStatus = eventDetector("status", (current, previous, space_id) => {
58
+ if (!current.status || current.status === previous?.status)
59
+ return;
60
+ return {
61
+ status: current.status,
62
+ previous_status: previous?.status,
63
+ space_id,
64
+ conversation_id: current.conversation_id,
65
+ message_id: current.message_id,
66
+ };
67
+ });
68
+ /** First time we see an attachment slot. */
69
+ export const detectAttachmentAdded = eventDetector("attachment", (current, previous, location, index) => {
70
+ if (previous)
71
+ return;
72
+ return {
73
+ ...location,
74
+ index,
75
+ attachment_type: detectAttachmentType(current),
76
+ };
77
+ });
78
+ /**
79
+ * One emit per new `(thought_type, content)` tuple on a query
80
+ * attachment. Value-based set diff: Genie can mutate existing
81
+ * thought slots in place (e.g. re-typing index 0 from
82
+ * `DATA_SOURCING` to `DESCRIPTION` while re-appending the
83
+ * original at index 1), so positional / append-only diff would
84
+ * miss re-types and double-count re-orders.
85
+ */
86
+ export const detectThinking = eventDetector("thinking", (current, previous, location) => {
87
+ const currThoughts = current.query?.thoughts ?? [];
88
+ if (currThoughts.length === 0)
89
+ return;
90
+ const seen = new Set((previous?.query?.thoughts ?? []).map(thoughtKey));
91
+ const out = [];
92
+ for (const t of currThoughts) {
93
+ const key = thoughtKey(t);
94
+ if (seen.has(key))
95
+ continue;
96
+ // Defensive: dedupe within a single snapshot in case Genie
97
+ // ever ships the same thought twice in one `thoughts[]`.
98
+ seen.add(key);
99
+ out.push({ ...location, text: t.content, thought_type: t.thought_type });
100
+ }
101
+ return out;
102
+ });
103
+ /** Text-attachment `content` appeared or changed. */
104
+ export const detectText = eventDetector("text", (current, previous, location) => {
105
+ const curr = current.text?.content;
106
+ const prev = previous?.text?.content;
107
+ if (curr === undefined || curr === prev)
108
+ return;
109
+ return { ...location, text: curr };
110
+ });
111
+ /** SQL transitioned undefined -> string, or changed. */
112
+ export const detectQuery = eventDetector("query", (current, previous, location) => {
113
+ const curr = current.query?.query;
114
+ const prev = previous?.query?.query;
115
+ if (!curr || curr === prev)
116
+ return;
117
+ return {
118
+ ...location,
119
+ sql: curr,
120
+ title: current.query?.title,
121
+ description: current.query?.description,
122
+ };
123
+ });
124
+ /** Warehouse-statement id assigned. */
125
+ export const detectStatement = eventDetector("statement", (current, previous, location) => {
126
+ const curr = current.query?.statement_id;
127
+ const prev = previous?.query?.statement_id;
128
+ if (!curr || curr === prev)
129
+ return;
130
+ return { ...location, statement_id: curr };
131
+ });
132
+ /**
133
+ * `row_count` changed - fires on every transition including the
134
+ * initial `undefined -> 0` and the post-execution `0 -> N`.
135
+ * Carries the statement id when available for correlation.
136
+ */
137
+ export const detectRows = eventDetector("rows", (current, previous, location) => {
138
+ const curr = current.query?.query_result_metadata?.row_count;
139
+ const prev = previous?.query?.query_result_metadata?.row_count;
140
+ if (curr === undefined || curr === prev)
141
+ return;
142
+ return {
143
+ ...location,
144
+ row_count: curr,
145
+ previous_row_count: prev,
146
+ statement_id: current.query?.statement_id ?? previous?.query?.statement_id,
147
+ };
148
+ });
149
+ /**
150
+ * Follow-up suggested-questions array appeared or changed.
151
+ * Compares structurally so a length-preserving content rewrite still fires.
152
+ */
153
+ export const detectSuggestedQuestions = eventDetector("suggested_questions", (current, previous, location) => {
154
+ const curr = current.suggested_questions?.questions;
155
+ const prev = previous?.suggested_questions?.questions;
156
+ if (!curr || curr.length === 0)
157
+ return;
158
+ if (object.deepEqual(curr, prev))
159
+ return;
160
+ return { ...location, questions: curr };
161
+ });
162
+ /* --------------------------- orchestrator --------------------------- */
163
+ /**
164
+ * Walk the diff between `current` and `previous` and yield every
165
+ * derived event the snapshot produced. Detector order mirrors
166
+ * Genie's wire ordering (status first, then per-attachment field
167
+ * deltas) so a subscriber that simply logs events as they arrive
168
+ * sees them in a sensible sequence.
169
+ *
170
+ * Caller responsibilities (not handled here):
171
+ *
172
+ * - Yield `{ type: "message", message: current }` BEFORE
173
+ * calling this, once per poll yield.
174
+ * - Yield `{ type: "result", ... }` AFTER calling this when
175
+ * `isTerminalStatus(current.status)` - per-turn lifecycle,
176
+ * not a per-snapshot field diff.
177
+ * - Decide what counts as a "fresh turn" and pass `undefined`
178
+ * for `previous` on turn boundaries, so anonymous-attachment
179
+ * state from a prior turn doesn't bleed in.
180
+ *
181
+ * Sync generator: the diff is pure CPU work, no awaits. Use
182
+ * `yield*` from an async generator to splice the events into a
183
+ * stream.
184
+ */
185
+ export function* eventsFromMessage(current, previous, space_id) {
186
+ // Stamp `type` onto each detector result and yield it. Returning
187
+ // a typed generator keeps the `yield*` callsite tidy. The double
188
+ // cast (`unknown` -> `GenieChatEvent`) is needed because the
189
+ // generic merge `{type: T} & GenieChatEventFields<T>` doesn't
190
+ // structurally narrow back to a discriminated-union member -
191
+ // each detector's runtime output is shaped correctly by
192
+ // construction, so the cast is sound.
193
+ function* emit(detector, result) {
194
+ if (result === undefined)
195
+ return;
196
+ if (Array.isArray(result)) {
197
+ for (const fields of result) {
198
+ yield { type: detector.type, ...fields };
199
+ }
200
+ }
201
+ else {
202
+ yield { type: detector.type, ...result };
203
+ }
204
+ }
205
+ // Message-scoped detectors run once per snapshot.
206
+ yield* emit(detectStatus, detectStatus.detect(current, previous, space_id));
207
+ // Per-attachment detectors run once per attachment slot.
208
+ const currAtts = current.attachments ?? [];
209
+ const prevAtts = previous?.attachments ?? [];
210
+ for (let i = 0; i < currAtts.length; i++) {
211
+ const curr = currAtts[i];
212
+ const prev = matchPrevAttachment(curr, prevAtts, i);
213
+ const location = {
214
+ space_id,
215
+ conversation_id: current.conversation_id,
216
+ message_id: current.message_id,
217
+ attachment_id: curr.attachment_id,
218
+ };
219
+ yield* emit(detectAttachmentAdded, detectAttachmentAdded.detect(curr, prev, location, i));
220
+ yield* emit(detectThinking, detectThinking.detect(curr, prev, location, i));
221
+ yield* emit(detectText, detectText.detect(curr, prev, location, i));
222
+ yield* emit(detectQuery, detectQuery.detect(curr, prev, location, i));
223
+ yield* emit(detectStatement, detectStatement.detect(curr, prev, location, i));
224
+ yield* emit(detectRows, detectRows.detect(curr, prev, location, i));
225
+ yield* emit(detectSuggestedQuestions, detectSuggestedQuestions.detect(curr, prev, location, i));
226
+ }
227
+ }
228
+ /* ----------------------------- helpers ----------------------------- */
229
+ /**
230
+ * Find the prior version of `curr` in `prevAtts`. Attachments
231
+ * with ids match by id (Genie keeps ids stable across polls);
232
+ * anonymous attachments (Genie's main-answer text doesn't get
233
+ * one) match positionally against an anonymous prev at the same
234
+ * index, so they don't accidentally bind to an id'd predecessor
235
+ * that happened to share the slot.
236
+ */
237
+ function matchPrevAttachment(curr, prevAtts, i) {
238
+ if (curr.attachment_id) {
239
+ return prevAtts.find((a) => a.attachment_id === curr.attachment_id);
240
+ }
241
+ const p = prevAtts[i];
242
+ return p && !p.attachment_id ? p : undefined;
243
+ }
244
+ /** Stable key for {@link detectThinking}'s value-based set diff. */
245
+ function thoughtKey(t) {
246
+ return `${t.thought_type}|${t.content}`;
247
+ }
248
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXZlbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZXZlbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0F5Qkc7QUFFSCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFFaEQsT0FBTyxFQUNMLG9CQUFvQixHQVFyQixNQUFNLGVBQWUsQ0FBQztBQXVFdkIsc0VBQXNFO0FBRXRFOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FxQkc7QUFDSCxNQUFNLFVBQVUsYUFBYSxDQUMzQixJQUFPLEVBQ1AsTUFBbUI7SUFFbkIsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsQ0FBQztBQUMxQixDQUFDO0FBRUQseUVBQXlFO0FBRXpFLCtDQUErQztBQUMvQyxNQUFNLENBQUMsTUFBTSxZQUFZLEdBQUcsYUFBYSxDQUFDLFFBQVEsRUFBRSxDQUFDLE9BQU8sRUFBRSxRQUFRLEVBQUUsUUFBUSxFQUFFLEVBQUU7SUFDbEYsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLElBQUksT0FBTyxDQUFDLE1BQU0sS0FBSyxRQUFRLEVBQUUsTUFBTTtRQUFFLE9BQU87SUFDbkUsT0FBTztRQUNMLE1BQU0sRUFBRSxPQUFPLENBQUMsTUFBTTtRQUN0QixlQUFlLEVBQUUsUUFBUSxFQUFFLE1BQU07UUFDakMsUUFBUTtRQUNSLGVBQWUsRUFBRSxPQUFPLENBQUMsZUFBZTtRQUN4QyxVQUFVLEVBQUUsT0FBTyxDQUFDLFVBQVU7S0FDL0IsQ0FBQztBQUNKLENBQUMsQ0FBQyxDQUFDO0FBRUgsNENBQTRDO0FBQzVDLE1BQU0sQ0FBQyxNQUFNLHFCQUFxQixHQUFHLGFBQWEsQ0FDaEQsWUFBWSxFQUNaLENBQUMsT0FBTyxFQUFFLFFBQVEsRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLEVBQUU7SUFDckMsSUFBSSxRQUFRO1FBQUUsT0FBTztJQUNyQixPQUFPO1FBQ0wsR0FBRyxR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LENBQUMsTUFBTSxDQUFDLElBQUksRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDcEUsS0FBSyxDQUFDLENBQUMsSUFBSSxDQUFDLHdCQUF3QixFQUFFLHdCQUF3QixDQUFDLE1BQU0sQ0FBQyxJQUFJLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ2xHLENBQUM7QUFDSCxDQUFDO0FBRUQseUVBQXlFO0FBRXpFOzs7Ozs7O0dBT0c7QUFDSCxTQUFTLG1CQUFtQixDQUMxQixJQUFxQixFQUNyQixRQUEyQixFQUMzQixDQUFTO0lBRVQsSUFBSSxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7UUFDdkIsT0FBTyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsYUFBYSxLQUFLLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FBQztJQUN0RSxDQUFDO0lBQ0QsTUFBTSxDQUFDLEdBQUcsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3RCLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7QUFDL0MsQ0FBQztBQUVELG9FQUFvRTtBQUNwRSxTQUFTLFVBQVUsQ0FBQyxDQUFlO0lBQ2pDLE9BQU8sR0FBRyxDQUFDLENBQUMsWUFBWSxJQUFJLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQztBQUMxQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBQdXJlIGV2ZW50LWRldGVjdGlvbiBmb3IgYGdlbmllRXZlbnRDaGF0YC4gR2l2ZW4gdHdvXG4gKiBgR2VuaWVNZXNzYWdlYCBzbmFwc2hvdHMgKGN1cnJlbnQgKyBwcmlvcikgYW5kIHRoZSBzdXJyb3VuZGluZ1xuICogYHNwYWNlX2lkYCwgZGVyaXZlIHRoZSBzZW1hbnRpYyBkZWx0YXMgKHN0YXR1cyB0cmFuc2l0aW9ucywgbmV3XG4gKiBhdHRhY2htZW50cywgbmV3IHRob3VnaHRzLCBTUUwgZW1pc3Npb24sIHdhcmVob3VzZSBzdWJtaXNzaW9uLFxuICogcm93LWNvdW50IHByb2dyZXNzLCBmb2xsb3ctdXAgc3VnZ2VzdGlvbnMsIHRleHQgZGVsdGFzKSBhbmRcbiAqIHlpZWxkIHRoZW0gYXMgdHlwZWQge0BsaW5rIEdlbmllQ2hhdEV2ZW50fXMuXG4gKlxuICogRGV0ZWN0b3JzIGFyZSBidWlsdCB0aHJvdWdoIGEgc2luZ2xlIHR5cGVkIGZhY3RvcnkgdGhhdCB0aWVzXG4gKiBlYWNoIGV2ZW50J3MgbmFtZSB0byBpdHMgc2NvcGUgKHdob2xlLW1lc3NhZ2UgdnMgcGVyLWF0dGFjaG1lbnQpXG4gKiBhbmQgcGF5bG9hZCBzaGFwZSwgc28gYSBtaXNuYW1lZCBldmVudCBvciBhIHBheWxvYWQgdGhhdCBkb2Vzbid0XG4gKiBtYXRjaCBpdHMgZXZlbnQgZmFpbHMgdG8gY29tcGlsZS4gQW4gb3JjaGVzdHJhdG9yIHdhbGtzIHRoZVxuICogc25hcHNob3QgZGlmZiBhbmQgeWllbGRzIGV2ZXJ5IGRldGVjdG9yIHRoYXQgZmlyZXMgaW4gYSBzdGFibGVcbiAqIG9yZGVyIChzdGF0dXMgZmlyc3QsIHRoZW4gcGVyLWF0dGFjaG1lbnQgZmllbGQgZGVsdGFzKSBzbyBhXG4gKiBzdWJzY3JpYmVyIHRoYXQgbG9ncyBldmVudHMgYXMgdGhleSBhcnJpdmUgc2VlcyBhIHNlbnNpYmxlXG4gKiBzZXF1ZW5jZS5cbiAqXG4gKiBUaGUgbW9kdWxlIGlzIGludGVudGlvbmFsbHkgcHVyZTogbm8gYEV2ZW50RW1pdHRlcmAsIG5vIGB0aGlzYCxcbiAqIG5vIEkvTywgbm8gbW9kdWxlLWxldmVsIG11dGFibGUgc3RhdGUuIFRoZSBgbWVzc2FnZWAgYW5kXG4gKiBgcmVzdWx0YCBldmVudHMgYXJlIE5PVCBkZXJpdmVkIGhlcmUgLSB0aGV5IGJlbG9uZyB0byB0aGUgY2hhdFxuICogbGlmZWN5Y2xlIGxheWVyICh0aGUgYGdlbmllRXZlbnRDaGF0YCBkcml2ZXIpIGJlY2F1c2UgdGhleSB0cmFja1xuICogcGVyLXlpZWxkIC8gcGVyLXR1cm4tY29tcGxldGlvbiBzZW1hbnRpY3MgcmF0aGVyIHRoYW4gYVxuICogZmllbGQtbGV2ZWwgc25hcHNob3QgZGlmZi5cbiAqXG4gKiBAbW9kdWxlXG4gKi9cblxuaW1wb3J0IHsgb2JqZWN0IH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWNvcmVcIjtcblxuaW1wb3J0IHtcbiAgZGV0ZWN0QXR0YWNobWVudFR5cGUsXG4gIHR5cGUgR2VuaWVBdHRhY2htZW50LFxuICB0eXBlIEdlbmllQ2hhdEV2ZW50LFxuICB0eXBlIEdlbmllQ2hhdEV2ZW50RmllbGRzLFxuICB0eXBlIEdlbmllQ2hhdEV2ZW50VHlwZSxcbiAgdHlwZSBHZW5pZUNoYXRMb2NhdGlvbixcbiAgdHlwZSBHZW5pZU1lc3NhZ2UsXG4gIHR5cGUgR2VuaWVUaG91Z2h0LFxufSBmcm9tIFwiLi9nZW5pZS1tb2RlbFwiO1xuXG4vKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBjb250cmFjdCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovXG5cbi8qKlxuICogV2hhdCBhIHNpbmdsZSBkZXRlY3RvciBjYWxsIHJldHVybnM6IHplcm8gKGB1bmRlZmluZWRgKSwgb25lXG4gKiAoZmllbGRzIG9iamVjdCksIG9yIG1hbnkgKGBmaWVsZHNbXWApIGV2ZW50cyBvZiB0aGUgc2FtZSB0eXBlLlxuICogRWFjaCByZXN1bHQgaXMgdGhlIHZhcmlhbnQncyBwYXlsb2FkIGZpZWxkcyAqKndpdGhvdXQqKiB0aGVcbiAqIGB0eXBlYCBkaXNjcmltaW5hdG9yIC0gdGhlIG9yY2hlc3RyYXRvciBzdGFtcHMgYHR5cGVgIHdoZW4gaXRcbiAqIHlpZWxkcyB0aGUgZXZlbnQuXG4gKi9cbnR5cGUgRGV0ZWN0b3JSZXN1bHQ8VCBleHRlbmRzIEdlbmllQ2hhdEV2ZW50VHlwZT4gPVxuICBHZW5pZUNoYXRFdmVudEZpZWxkczxUPiB8IEdlbmllQ2hhdEV2ZW50RmllbGRzPFQ+W10gfCB1bmRlZmluZWQ7XG5cbi8qKlxuICogV2hlcmUgaW4gdGhlIHdpcmUgc2hhcGUgYSBnaXZlbiBldmVudCBpcyBkZXJpdmVkIGZyb20uIERyaXZlc1xuICogd2hpY2ggYXJndW1lbnRzIGBkZXRlY3RgIHJlY2VpdmVzLiBgXCJtZXNzYWdlXCJgIGV2ZW50cyB3YXRjaFxuICogYEdlbmllTWVzc2FnZWAgaXRzZWxmOyBgXCJhdHRhY2htZW50XCJgIGV2ZW50cyB3YXRjaCBvbmUgc2xvdCBvZlxuICogYG1lc3NhZ2UuYXR0YWNobWVudHNbXWAuIGBcImxpZmVjeWNsZVwiYCBldmVudHMgKGBtZXNzYWdlYCxcbiAqIGByZXN1bHRgKSBhcmUgZW1pdHRlZCBieSB0aGUgY2hhdCBkcml2ZXIgZGlyZWN0bHkgYW5kIGNhbid0IGJlXG4gKiBidWlsdCB3aXRoIHtAbGluayBldmVudERldGVjdG9yfSAtIHRoZXkgaGF2ZSBubyBkaWZmIHNpZ25hdHVyZS5cbiAqL1xuaW50ZXJmYWNlIERldGVjdG9yU2NvcGUge1xuICAvLyBNZXNzYWdlLXNjb3BlZDogdG9wLWxldmVsIGZpZWxkIGRpZmYgb24gYEdlbmllTWVzc2FnZWAuXG4gIHN0YXR1czogXCJtZXNzYWdlXCI7XG4gIC8vIFBlci1hdHRhY2htZW50OiBmaWVsZCBkaWZmIG9uIG9uZSBgR2VuaWVBdHRhY2htZW50YCBzbG90LlxuICBhdHRhY2htZW50OiBcImF0dGFjaG1lbnRcIjtcbiAgdGhpbmtpbmc6IFwiYXR0YWNobWVudFwiO1xuICB0ZXh0OiBcImF0dGFjaG1lbnRcIjtcbiAgcXVlcnk6IFwiYXR0YWNobWVudFwiO1xuICBzdGF0ZW1lbnQ6IFwiYXR0YWNobWVudFwiO1xuICByb3dzOiBcImF0dGFjaG1lbnRcIjtcbiAgc3VnZ2VzdGVkX3F1ZXN0aW9uczogXCJhdHRhY2htZW50XCI7XG4gIC8vIExpZmVjeWNsZTogbm90IGRlcml2ZWQgdmlhIGRpZmYsIGhhbmRsZWQgYnkgdGhlIGNoYXQgZHJpdmVyLlxuICBxdWVzdGlvbjogXCJsaWZlY3ljbGVcIjtcbiAgbWVzc2FnZTogXCJsaWZlY3ljbGVcIjtcbiAgcmVzdWx0OiBcImxpZmVjeWNsZVwiO1xufVxuXG4vKipcbiAqIGBkZXRlY3RgIGNhbGxiYWNrIHNpZ25hdHVyZSBmb3IgYSBnaXZlbiBldmVudCB0eXBlLiBSZXNvbHZlZFxuICogZnJvbSB7QGxpbmsgRGV0ZWN0b3JTY29wZX06IGBcIm1lc3NhZ2VcImAgZXZlbnRzIGdldCB0aGUgdG9wLWxldmVsXG4gKiBzbmFwc2hvdCB0cmlwbGUsIGBcImF0dGFjaG1lbnRcImAgZXZlbnRzIGdldCB0aGUgcGVyLXNsb3QgcXVhZCxcbiAqIGBcImxpZmVjeWNsZVwiYCBldmVudHMgcmVzb2x2ZSB0byBgbmV2ZXJgIChubyBkaWZmLWJhc2VkIGRldGVjdG9yXG4gKiBleGlzdHMgZm9yIHRoZW0pLlxuICovXG50eXBlIERldGVjdEZuPFQgZXh0ZW5kcyBHZW5pZUNoYXRFdmVudFR5cGU+ID0gRGV0ZWN0b3JTY29wZVtUXSBleHRlbmRzIFwibWVzc2FnZVwiXG4gID8gKFxuICAgICAgY3VycmVudDogR2VuaWVNZXNzYWdlLFxuICAgICAgcHJldmlvdXM6IEdlbmllTWVzc2FnZSB8IHVuZGVmaW5lZCxcbiAgICAgIHNwYWNlX2lkOiBzdHJpbmcsXG4gICAgKSA9PiBEZXRlY3RvclJlc3VsdDxUPlxuICA6IERldGVjdG9yU2NvcGVbVF0gZXh0ZW5kcyBcImF0dGFjaG1lbnRcIlxuICAgID8gKFxuICAgICAgICBjdXJyZW50OiBHZW5pZUF0dGFjaG1lbnQsXG4gICAgICAgIHByZXZpb3VzOiBHZW5pZUF0dGFjaG1lbnQgfCB1bmRlZmluZWQsXG4gICAgICAgIGxvY2F0aW9uOiBHZW5pZUNoYXRMb2NhdGlvbixcbiAgICAgICAgaW5kZXg6IG51bWJlcixcbiAgICAgICkgPT4gRGV0ZWN0b3JSZXN1bHQ8VD5cbiAgICA6IG5ldmVyO1xuXG4vKipcbiAqIFR5cGVkIGRldGVjdG9yIGZvciBvbmUgZXZlbnQgaW4gdGhlIHtAbGluayBHZW5pZUNoYXRFdmVudH1cbiAqIHVuaW9uLiBUaGUgYHR5cGVgIGZpZWxkIGlzIHRoZSBldmVudCBuYW1lOyBgZGV0ZWN0YCdzIHNpZ25hdHVyZVxuICogaXMgcGlja2VkIGZyb20ge0BsaW5rIERldGVjdG9yU2NvcGV9IGJhc2VkIG9uIGBUYC5cbiAqL1xuaW50ZXJmYWNlIEV2ZW50RGV0ZWN0b3I8VCBleHRlbmRzIEdlbmllQ2hhdEV2ZW50VHlwZT4ge1xuICByZWFkb25seSB0eXBlOiBUO1xuICBkZXRlY3Q6IERldGVjdEZuPFQ+O1xufVxuXG4vKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBkZXRlY3RvciBmYWN0b3J5IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovXG5cbi8qKlxuICogQnVpbGQgYW4ge0BsaW5rIEV2ZW50RGV0ZWN0b3J9LiBQYXNzIHRoZSBldmVudCBuYW1lIGFzIHRoZVxuICogbGl0ZXJhbCBmaXJzdCBhcmcgYW5kIHRoZSBtYXRjaGluZyBgZGV0ZWN0YCBjYWxsYmFjayBhcyB0aGVcbiAqIHNlY29uZC4gVFMgaW5mZXJzIGBUYCBmcm9tIHRoZSBsaXRlcmFsLCBuYXJyb3dzIGBkZXRlY3RgJ3NcbiAqIHNpZ25hdHVyZSBhY2NvcmRpbmdseSwgYW5kIHR5cGVzIHRoZSByZXR1cm4gYXNcbiAqIGBFdmVudERldGVjdG9yPFQ+YC5cbiAqXG4gKiBCdWlsZC10aW1lIGd1YXJhbnRlZXM6XG4gKlxuICogICAtIGBldmVudERldGVjdG9yKFwic3RhdHVzMlwiLCAuLi4pYCBmYWlscyAtIHRoZSBuYW1lIGlzbid0IGluXG4gKiAgICAge0BsaW5rIEdlbmllQ2hhdEV2ZW50fS5cbiAqICAgLSBgZXZlbnREZXRlY3RvcihcInN0YXR1c1wiLCBhdHRhY2htZW50QXJnc0NhbGxiYWNrKWAgZmFpbHMgLVxuICogICAgIGBcInN0YXR1c1wiYCBpcyBtZXNzYWdlLXNjb3BlZCwgc28gYGRldGVjdGAgbXVzdCB0YWtlXG4gKiAgICAgYChHZW5pZU1lc3NhZ2UsIEdlbmllTWVzc2FnZSB8IHVuZGVmaW5lZCwgc3RyaW5nKWAuXG4gKiAgIC0gUmV0dXJuaW5nIGEgYFRoaW5raW5nRXZlbnRgLXNoYXBlZCBmaWVsZHMgb2JqZWN0IGZyb20gYVxuICogICAgIGBcInN0YXR1c1wiYCBkZXRlY3RvciBmYWlscyAtIHRoZSByZXR1cm4gdHlwZSBpcyBjb25zdHJhaW5lZFxuICogICAgIHRvIGBEZXRlY3RvclJlc3VsdDxcInN0YXR1c1wiPmAuXG4gKlxuICogTGlmZWN5Y2xlIGV2ZW50IG5hbWVzIChgXCJtZXNzYWdlXCJgLCBgXCJyZXN1bHRcImApIHJlc29sdmUgYGRldGVjdGBcbiAqIHRvIGBuZXZlcmAgYW5kIHdvbid0IGNvbXBpbGUsIHdoaWNoIGlzIGludGVudGlvbmFsOiB0aG9zZSBoYXZlXG4gKiBubyBkaWZmIHNpZ25hdHVyZSBhbmQgYXJlIGVtaXR0ZWQgZGlyZWN0bHkgYnkgdGhlIGNoYXQgZHJpdmVyLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZXZlbnREZXRlY3RvcjxUIGV4dGVuZHMgR2VuaWVDaGF0RXZlbnRUeXBlPihcbiAgdHlwZTogVCxcbiAgZGV0ZWN0OiBEZXRlY3RGbjxUPixcbik6IEV2ZW50RGV0ZWN0b3I8VD4ge1xuICByZXR1cm4geyB0eXBlLCBkZXRlY3QgfTtcbn1cblxuLyogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBkZXRlY3RvcnMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqL1xuXG4vKiogVG9wLWxldmVsIGBtZXNzYWdlLnN0YXR1c2AgdHJhbnNpdGlvbmVkLiAqL1xuZXhwb3J0IGNvbnN0IGRldGVjdFN0YXR1cyA9IGV2ZW50RGV0ZWN0b3IoXCJzdGF0dXNcIiwgKGN1cnJlbnQsIHByZXZpb3VzLCBzcGFjZV9pZCkgPT4ge1xuICBpZiAoIWN1cnJlbnQuc3RhdHVzIHx8IGN1cnJlbnQuc3RhdHVzID09PSBwcmV2aW91cz8uc3RhdHVzKSByZXR1cm47XG4gIHJldHVybiB7XG4gICAgc3RhdHVzOiBjdXJyZW50LnN0YXR1cyxcbiAgICBwcmV2aW91c19zdGF0dXM6IHByZXZpb3VzPy5zdGF0dXMsXG4gICAgc3BhY2VfaWQsXG4gICAgY29udmVyc2F0aW9uX2lkOiBjdXJyZW50LmNvbnZlcnNhdGlvbl9pZCxcbiAgICBtZXNzYWdlX2lkOiBjdXJyZW50Lm1lc3NhZ2VfaWQsXG4gIH07XG59KTtcblxuLyoqIEZpcnN0IHRpbWUgd2Ugc2VlIGFuIGF0dGFjaG1lbnQgc2xvdC4gKi9cbmV4cG9ydCBjb25zdCBkZXRlY3RBdHRhY2htZW50QWRkZWQgPSBldmVudERldGVjdG9yKFxuICBcImF0dGFjaG1lbnRcIixcbiAgKGN1cnJlbnQsIHByZXZpb3VzLCBsb2NhdGlvbiwgaW5kZXgpID0+IHtcbiAgICBpZiAocHJldmlvdXMpIHJldHVybjtcbiAgICByZXR1cm4ge1xuICAgICAgLi4ubG9jYXRpb24sXG4gICAgICBpbmRleCxcbiAgICAgIGF0dGFjaG1lbnRfdHlwZTogZGV0ZWN0QXR0YWNobWVudFR5cGUoY3VycmVudCksXG4gICAgfTtcbiAgfSxcbik7XG5cbi8qKlxuICogT25lIGVtaXQgcGVyIG5ldyBgKHRob3VnaHRfdHlwZSwgY29udGVudClgIHR1cGxlIG9uIGEgcXVlcnlcbiAqIGF0dGFjaG1lbnQuIFZhbHVlLWJhc2VkIHNldCBkaWZmOiBHZW5pZSBjYW4gbXV0YXRlIGV4aXN0aW5nXG4gKiB0aG91Z2h0IHNsb3RzIGluIHBsYWNlIChlLmcuIHJlLXR5cGluZyBpbmRleCAwIGZyb21cbiAqIGBEQVRBX1NPVVJDSU5HYCB0byBgREVTQ1JJUFRJT05gIHdoaWxlIHJlLWFwcGVuZGluZyB0aGVcbiAqIG9yaWdpbmFsIGF0IGluZGV4IDEpLCBzbyBwb3NpdGlvbmFsIC8gYXBwZW5kLW9ubHkgZGlmZiB3b3VsZFxuICogbWlzcyByZS10eXBlcyBhbmQgZG91YmxlLWNvdW50IHJlLW9yZGVycy5cbiAqL1xuZXhwb3J0IGNvbnN0IGRldGVjdFRoaW5raW5nID0gZXZlbnREZXRlY3RvcihcInRoaW5raW5nXCIsIChjdXJyZW50LCBwcmV2aW91cywgbG9jYXRpb24pID0+IHtcbiAgY29uc3QgY3VyclRob3VnaHRzID0gY3VycmVudC5xdWVyeT8udGhvdWdodHMgPz8gW107XG4gIGlmIChjdXJyVGhvdWdodHMubGVuZ3RoID09PSAwKSByZXR1cm47XG4gIGNvbnN0IHNlZW4gPSBuZXcgU2V0KChwcmV2aW91cz8ucXVlcnk/LnRob3VnaHRzID8/IFtdKS5tYXAodGhvdWdodEtleSkpO1xuICBjb25zdCBvdXQ6IEdlbmllQ2hhdEV2ZW50RmllbGRzPFwidGhpbmtpbmdcIj5bXSA9IFtdO1xuICBmb3IgKGNvbnN0IHQgb2YgY3VyclRob3VnaHRzKSB7XG4gICAgY29uc3Qga2V5ID0gdGhvdWdodEtleSh0KTtcbiAgICBpZiAoc2Vlbi5oYXMoa2V5KSkgY29udGludWU7XG4gICAgLy8gRGVmZW5zaXZlOiBkZWR1cGUgd2l0aGluIGEgc2luZ2xlIHNuYXBzaG90IGluIGNhc2UgR2VuaWVcbiAgICAvLyBldmVyIHNoaXBzIHRoZSBzYW1lIHRob3VnaHQgdHdpY2UgaW4gb25lIGB0aG91Z2h0c1tdYC5cbiAgICBzZWVuLmFkZChrZXkpO1xuICAgIG91dC5wdXNoKHsgLi4ubG9jYXRpb24sIHRleHQ6IHQuY29udGVudCwgdGhvdWdodF90eXBlOiB0LnRob3VnaHRfdHlwZSB9KTtcbiAgfVxuICByZXR1cm4gb3V0O1xufSk7XG5cbi8qKiBUZXh0LWF0dGFjaG1lbnQgYGNvbnRlbnRgIGFwcGVhcmVkIG9yIGNoYW5nZWQuICovXG5leHBvcnQgY29uc3QgZGV0ZWN0VGV4dCA9IGV2ZW50RGV0ZWN0b3IoXCJ0ZXh0XCIsIChjdXJyZW50LCBwcmV2aW91cywgbG9jYXRpb24pID0+IHtcbiAgY29uc3QgY3VyciA9IGN1cnJlbnQudGV4dD8uY29udGVudDtcbiAgY29uc3QgcHJldiA9IHByZXZpb3VzPy50ZXh0Py5jb250ZW50O1xuICBpZiAoY3VyciA9PT0gdW5kZWZpbmVkIHx8IGN1cnIgPT09IHByZXYpIHJldHVybjtcbiAgcmV0dXJuIHsgLi4ubG9jYXRpb24sIHRleHQ6IGN1cnIgfTtcbn0pO1xuXG4vKiogU1FMIHRyYW5zaXRpb25lZCB1bmRlZmluZWQgLT4gc3RyaW5nLCBvciBjaGFuZ2VkLiAqL1xuZXhwb3J0IGNvbnN0IGRldGVjdFF1ZXJ5ID0gZXZlbnREZXRlY3RvcihcInF1ZXJ5XCIsIChjdXJyZW50LCBwcmV2aW91cywgbG9jYXRpb24pID0+IHtcbiAgY29uc3QgY3VyciA9IGN1cnJlbnQucXVlcnk/LnF1ZXJ5O1xuICBjb25zdCBwcmV2ID0gcHJldmlvdXM/LnF1ZXJ5Py5xdWVyeTtcbiAgaWYgKCFjdXJyIHx8IGN1cnIgPT09IHByZXYpIHJldHVybjtcbiAgcmV0dXJuIHtcbiAgICAuLi5sb2NhdGlvbixcbiAgICBzcWw6IGN1cnIsXG4gICAgdGl0bGU6IGN1cnJlbnQucXVlcnk/LnRpdGxlLFxuICAgIGRlc2NyaXB0aW9uOiBjdXJyZW50LnF1ZXJ5Py5kZXNjcmlwdGlvbixcbiAgfTtcbn0pO1xuXG4vKiogV2FyZWhvdXNlLXN0YXRlbWVudCBpZCBhc3NpZ25lZC4gKi9cbmV4cG9ydCBjb25zdCBkZXRlY3RTdGF0ZW1lbnQgPSBldmVudERldGVjdG9yKFwic3RhdGVtZW50XCIsIChjdXJyZW50LCBwcmV2aW91cywgbG9jYXRpb24pID0+IHtcbiAgY29uc3QgY3VyciA9IGN1cnJlbnQucXVlcnk/LnN0YXRlbWVudF9pZDtcbiAgY29uc3QgcHJldiA9IHByZXZpb3VzPy5xdWVyeT8uc3RhdGVtZW50X2lkO1xuICBpZiAoIWN1cnIgfHwgY3VyciA9PT0gcHJldikgcmV0dXJuO1xuICByZXR1cm4geyAuLi5sb2NhdGlvbiwgc3RhdGVtZW50X2lkOiBjdXJyIH07XG59KTtcblxuLyoqXG4gKiBgcm93X2NvdW50YCBjaGFuZ2VkIC0gZmlyZXMgb24gZXZlcnkgdHJhbnNpdGlvbiBpbmNsdWRpbmcgdGhlXG4gKiBpbml0aWFsIGB1bmRlZmluZWQgLT4gMGAgYW5kIHRoZSBwb3N0LWV4ZWN1dGlvbiBgMCAtPiBOYC5cbiAqIENhcnJpZXMgdGhlIHN0YXRlbWVudCBpZCB3aGVuIGF2YWlsYWJsZSBmb3IgY29ycmVsYXRpb24uXG4gKi9cbmV4cG9ydCBjb25zdCBkZXRlY3RSb3dzID0gZXZlbnREZXRlY3RvcihcInJvd3NcIiwgKGN1cnJlbnQsIHByZXZpb3VzLCBsb2NhdGlvbikgPT4ge1xuICBjb25zdCBjdXJyID0gY3VycmVudC5xdWVyeT8ucXVlcnlfcmVzdWx0X21ldGFkYXRhPy5yb3dfY291bnQ7XG4gIGNvbnN0IHByZXYgPSBwcmV2aW91cz8ucXVlcnk/LnF1ZXJ5X3Jlc3VsdF9tZXRhZGF0YT8ucm93X2NvdW50O1xuICBpZiAoY3VyciA9PT0gdW5kZWZpbmVkIHx8IGN1cnIgPT09IHByZXYpIHJldHVybjtcbiAgcmV0dXJuIHtcbiAgICAuLi5sb2NhdGlvbixcbiAgICByb3dfY291bnQ6IGN1cnIsXG4gICAgcHJldmlvdXNfcm93X2NvdW50OiBwcmV2LFxuICAgIHN0YXRlbWVudF9pZDogY3VycmVudC5xdWVyeT8uc3RhdGVtZW50X2lkID8/IHByZXZpb3VzPy5xdWVyeT8uc3RhdGVtZW50X2lkLFxuICB9O1xufSk7XG5cbi8qKlxuICogRm9sbG93LXVwIHN1Z2dlc3RlZC1xdWVzdGlvbnMgYXJyYXkgYXBwZWFyZWQgb3IgY2hhbmdlZC5cbiAqIENvbXBhcmVzIHN0cnVjdHVyYWxseSBzbyBhIGxlbmd0aC1wcmVzZXJ2aW5nIGNvbnRlbnQgcmV3cml0ZSBzdGlsbCBmaXJlcy5cbiAqL1xuZXhwb3J0IGNvbnN0IGRldGVjdFN1Z2dlc3RlZFF1ZXN0aW9ucyA9IGV2ZW50RGV0ZWN0b3IoXG4gIFwic3VnZ2VzdGVkX3F1ZXN0aW9uc1wiLFxuICAoY3VycmVudCwgcHJldmlvdXMsIGxvY2F0aW9uKSA9PiB7XG4gICAgY29uc3QgY3VyciA9IGN1cnJlbnQuc3VnZ2VzdGVkX3F1ZXN0aW9ucz8ucXVlc3Rpb25zO1xuICAgIGNvbnN0IHByZXYgPSBwcmV2aW91cz8uc3VnZ2VzdGVkX3F1ZXN0aW9ucz8ucXVlc3Rpb25zO1xuICAgIGlmICghY3VyciB8fCBjdXJyLmxlbmd0aCA9PT0gMCkgcmV0dXJuO1xuICAgIGlmIChvYmplY3QuZGVlcEVxdWFsKGN1cnIsIHByZXYpKSByZXR1cm47XG4gICAgcmV0dXJuIHsgLi4ubG9jYXRpb24sIHF1ZXN0aW9uczogY3VyciB9O1xuICB9LFxuKTtcblxuLyogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIG9yY2hlc3RyYXRvciAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi9cblxuLyoqXG4gKiBXYWxrIHRoZSBkaWZmIGJldHdlZW4gYGN1cnJlbnRgIGFuZCBgcHJldmlvdXNgIGFuZCB5aWVsZCBldmVyeVxuICogZGVyaXZlZCBldmVudCB0aGUgc25hcHNob3QgcHJvZHVjZWQuIERldGVjdG9yIG9yZGVyIG1pcnJvcnNcbiAqIEdlbmllJ3Mgd2lyZSBvcmRlcmluZyAoc3RhdHVzIGZpcnN0LCB0aGVuIHBlci1hdHRhY2htZW50IGZpZWxkXG4gKiBkZWx0YXMpIHNvIGEgc3Vic2NyaWJlciB0aGF0IHNpbXBseSBsb2dzIGV2ZW50cyBhcyB0aGV5IGFycml2ZVxuICogc2VlcyB0aGVtIGluIGEgc2Vuc2libGUgc2VxdWVuY2UuXG4gKlxuICogQ2FsbGVyIHJlc3BvbnNpYmlsaXRpZXMgKG5vdCBoYW5kbGVkIGhlcmUpOlxuICpcbiAqICAgLSBZaWVsZCBgeyB0eXBlOiBcIm1lc3NhZ2VcIiwgbWVzc2FnZTogY3VycmVudCB9YCBCRUZPUkVcbiAqICAgICBjYWxsaW5nIHRoaXMsIG9uY2UgcGVyIHBvbGwgeWllbGQuXG4gKiAgIC0gWWllbGQgYHsgdHlwZTogXCJyZXN1bHRcIiwgLi4uIH1gIEFGVEVSIGNhbGxpbmcgdGhpcyB3aGVuXG4gKiAgICAgYGlzVGVybWluYWxTdGF0dXMoY3VycmVudC5zdGF0dXMpYCAtIHBlci10dXJuIGxpZmVjeWNsZSxcbiAqICAgICBub3QgYSBwZXItc25hcHNob3QgZmllbGQgZGlmZi5cbiAqICAgLSBEZWNpZGUgd2hhdCBjb3VudHMgYXMgYSBcImZyZXNoIHR1cm5cIiBhbmQgcGFzcyBgdW5kZWZpbmVkYFxuICogICAgIGZvciBgcHJldmlvdXNgIG9uIHR1cm4gYm91bmRhcmllcywgc28gYW5vbnltb3VzLWF0dGFjaG1lbnRcbiAqICAgICBzdGF0ZSBmcm9tIGEgcHJpb3IgdHVybiBkb2Vzbid0IGJsZWVkIGluLlxuICpcbiAqIFN5bmMgZ2VuZXJhdG9yOiB0aGUgZGlmZiBpcyBwdXJlIENQVSB3b3JrLCBubyBhd2FpdHMuIFVzZVxuICogYHlpZWxkKmAgZnJvbSBhbiBhc3luYyBnZW5lcmF0b3IgdG8gc3BsaWNlIHRoZSBldmVudHMgaW50byBhXG4gKiBzdHJlYW0uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiogZXZlbnRzRnJvbU1lc3NhZ2UoXG4gIGN1cnJlbnQ6IEdlbmllTWVzc2FnZSxcbiAgcHJldmlvdXM6IEdlbmllTWVzc2FnZSB8IHVuZGVmaW5lZCxcbiAgc3BhY2VfaWQ6IHN0cmluZyxcbik6IEdlbmVyYXRvcjxHZW5pZUNoYXRFdmVudCwgdm9pZCwgdm9pZD4ge1xuICAvLyBTdGFtcCBgdHlwZWAgb250byBlYWNoIGRldGVjdG9yIHJlc3VsdCBhbmQgeWllbGQgaXQuIFJldHVybmluZ1xuICAvLyBhIHR5cGVkIGdlbmVyYXRvciBrZWVwcyB0aGUgYHlpZWxkKmAgY2FsbHNpdGUgdGlkeS4gVGhlIGRvdWJsZVxuICAvLyBjYXN0IChgdW5rbm93bmAgLT4gYEdlbmllQ2hhdEV2ZW50YCkgaXMgbmVlZGVkIGJlY2F1c2UgdGhlXG4gIC8vIGdlbmVyaWMgbWVyZ2UgYHt0eXBlOiBUfSAmIEdlbmllQ2hhdEV2ZW50RmllbGRzPFQ+YCBkb2Vzbid0XG4gIC8vIHN0cnVjdHVyYWxseSBuYXJyb3cgYmFjayB0byBhIGRpc2NyaW1pbmF0ZWQtdW5pb24gbWVtYmVyIC1cbiAgLy8gZWFjaCBkZXRlY3RvcidzIHJ1bnRpbWUgb3V0cHV0IGlzIHNoYXBlZCBjb3JyZWN0bHkgYnlcbiAgLy8gY29uc3RydWN0aW9uLCBzbyB0aGUgY2FzdCBpcyBzb3VuZC5cbiAgZnVuY3Rpb24qIGVtaXQ8VCBleHRlbmRzIEdlbmllQ2hhdEV2ZW50VHlwZT4oXG4gICAgZGV0ZWN0b3I6IEV2ZW50RGV0ZWN0b3I8VD4sXG4gICAgcmVzdWx0OiBEZXRlY3RvclJlc3VsdDxUPixcbiAgKTogR2VuZXJhdG9yPEdlbmllQ2hhdEV2ZW50LCB2b2lkLCB2b2lkPiB7XG4gICAgaWYgKHJlc3VsdCA9PT0gdW5kZWZpbmVkKSByZXR1cm47XG4gICAgaWYgKEFycmF5LmlzQXJyYXkocmVzdWx0KSkge1xuICAgICAgZm9yIChjb25zdCBmaWVsZHMgb2YgcmVzdWx0KSB7XG4gICAgICAgIHlpZWxkIHsgdHlwZTogZGV0ZWN0b3IudHlwZSwgLi4uZmllbGRzIH0gYXMgdW5rbm93biBhcyBHZW5pZUNoYXRFdmVudDtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgeWllbGQgeyB0eXBlOiBkZXRlY3Rvci50eXBlLCAuLi5yZXN1bHQgfSBhcyB1bmtub3duIGFzIEdlbmllQ2hhdEV2ZW50O1xuICAgIH1cbiAgfVxuXG4gIC8vIE1lc3NhZ2Utc2NvcGVkIGRldGVjdG9ycyBydW4gb25jZSBwZXIgc25hcHNob3QuXG4gIHlpZWxkKiBlbWl0KGRldGVjdFN0YXR1cywgZGV0ZWN0U3RhdHVzLmRldGVjdChjdXJyZW50LCBwcmV2aW91cywgc3BhY2VfaWQpKTtcblxuICAvLyBQZXItYXR0YWNobWVudCBkZXRlY3RvcnMgcnVuIG9uY2UgcGVyIGF0dGFjaG1lbnQgc2xvdC5cbiAgY29uc3QgY3VyckF0dHMgPSBjdXJyZW50LmF0dGFjaG1lbnRzID8/IFtdO1xuICBjb25zdCBwcmV2QXR0cyA9IHByZXZpb3VzPy5hdHRhY2htZW50cyA/PyBbXTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBjdXJyQXR0cy5sZW5ndGg7IGkrKykge1xuICAgIGNvbnN0IGN1cnIgPSBjdXJyQXR0c1tpXSE7XG4gICAgY29uc3QgcHJldiA9IG1hdGNoUHJldkF0dGFjaG1lbnQoY3VyciwgcHJldkF0dHMsIGkpO1xuICAgIGNvbnN0IGxvY2F0aW9uOiBHZW5pZUNoYXRMb2NhdGlvbiA9IHtcbiAgICAgIHNwYWNlX2lkLFxuICAgICAgY29udmVyc2F0aW9uX2lkOiBjdXJyZW50LmNvbnZlcnNhdGlvbl9pZCxcbiAgICAgIG1lc3NhZ2VfaWQ6IGN1cnJlbnQubWVzc2FnZV9pZCxcbiAgICAgIGF0dGFjaG1lbnRfaWQ6IGN1cnIuYXR0YWNobWVudF9pZCxcbiAgICB9O1xuICAgIHlpZWxkKiBlbWl0KGRldGVjdEF0dGFjaG1lbnRBZGRlZCwgZGV0ZWN0QXR0YWNobWVudEFkZGVkLmRldGVjdChjdXJyLCBwcmV2LCBsb2NhdGlvbiwgaSkpO1xuICAgIHlpZWxkKiBlbWl0KGRldGVjdFRoaW5raW5nLCBkZXRlY3RUaGlua2luZy5kZXRlY3QoY3VyciwgcHJldiwgbG9jYXRpb24sIGkpKTtcbiAgICB5aWVsZCogZW1pdChkZXRlY3RUZXh0LCBkZXRlY3RUZXh0LmRldGVjdChjdXJyLCBwcmV2LCBsb2NhdGlvbiwgaSkpO1xuICAgIHlpZWxkKiBlbWl0KGRldGVjdFF1ZXJ5LCBkZXRlY3RRdWVyeS5kZXRlY3QoY3VyciwgcHJldiwgbG9jYXRpb24sIGkpKTtcbiAgICB5aWVsZCogZW1pdChkZXRlY3RTdGF0ZW1lbnQsIGRldGVjdFN0YXRlbWVudC5kZXRlY3QoY3VyciwgcHJldiwgbG9jYXRpb24sIGkpKTtcbiAgICB5aWVsZCogZW1pdChkZXRlY3RSb3dzLCBkZXRlY3RSb3dzLmRldGVjdChjdXJyLCBwcmV2LCBsb2NhdGlvbiwgaSkpO1xuICAgIHlpZWxkKiBlbWl0KGRldGVjdFN1Z2dlc3RlZFF1ZXN0aW9ucywgZGV0ZWN0U3VnZ2VzdGVkUXVlc3Rpb25zLmRldGVjdChjdXJyLCBwcmV2LCBsb2NhdGlvbiwgaSkpO1xuICB9XG59XG5cbi8qIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIGhlbHBlcnMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi9cblxuLyoqXG4gKiBGaW5kIHRoZSBwcmlvciB2ZXJzaW9uIG9mIGBjdXJyYCBpbiBgcHJldkF0dHNgLiBBdHRhY2htZW50c1xuICogd2l0aCBpZHMgbWF0Y2ggYnkgaWQgKEdlbmllIGtlZXBzIGlkcyBzdGFibGUgYWNyb3NzIHBvbGxzKTtcbiAqIGFub255bW91cyBhdHRhY2htZW50cyAoR2VuaWUncyBtYWluLWFuc3dlciB0ZXh0IGRvZXNuJ3QgZ2V0XG4gKiBvbmUpIG1hdGNoIHBvc2l0aW9uYWxseSBhZ2FpbnN0IGFuIGFub255bW91cyBwcmV2IGF0IHRoZSBzYW1lXG4gKiBpbmRleCwgc28gdGhleSBkb24ndCBhY2NpZGVudGFsbHkgYmluZCB0byBhbiBpZCdkIHByZWRlY2Vzc29yXG4gKiB0aGF0IGhhcHBlbmVkIHRvIHNoYXJlIHRoZSBzbG90LlxuICovXG5mdW5jdGlvbiBtYXRjaFByZXZBdHRhY2htZW50KFxuICBjdXJyOiBHZW5pZUF0dGFjaG1lbnQsXG4gIHByZXZBdHRzOiBHZW5pZUF0dGFjaG1lbnRbXSxcbiAgaTogbnVtYmVyLFxuKTogR2VuaWVBdHRhY2htZW50IHwgdW5kZWZpbmVkIHtcbiAgaWYgKGN1cnIuYXR0YWNobWVudF9pZCkge1xuICAgIHJldHVybiBwcmV2QXR0cy5maW5kKChhKSA9PiBhLmF0dGFjaG1lbnRfaWQgPT09IGN1cnIuYXR0YWNobWVudF9pZCk7XG4gIH1cbiAgY29uc3QgcCA9IHByZXZBdHRzW2ldO1xuICByZXR1cm4gcCAmJiAhcC5hdHRhY2htZW50X2lkID8gcCA6IHVuZGVmaW5lZDtcbn1cblxuLyoqIFN0YWJsZSBrZXkgZm9yIHtAbGluayBkZXRlY3RUaGlua2luZ30ncyB2YWx1ZS1iYXNlZCBzZXQgZGlmZi4gKi9cbmZ1bmN0aW9uIHRob3VnaHRLZXkodDogR2VuaWVUaG91Z2h0KTogc3RyaW5nIHtcbiAgcmV0dXJuIGAke3QudGhvdWdodF90eXBlfXwke3QuY29udGVudH1gO1xufVxuIl19