UNPKG

22.1 kBJavaScriptView Raw
1import { getNodeKeyForPreboot } from '../common/get-node-key';
2import { initAll, start, createOverlay, getAppRoot, handleEvents, createListenHandler, getSelection, createBuffer } from './event.recorder';
3const eventRecorder = {
4 start,
5 createOverlay,
6 getAppRoot,
7 handleEvents,
8 createListenHandler,
9 getSelection,
10 createBuffer
11};
12export const initFunctionName = 'prebootInitFn';
13// exporting default options in case developer wants to use these + custom on
14// top
15export const defaultOptions = {
16 buffer: true,
17 replay: true,
18 disableOverlay: false,
19 // these are the default events are are listening for an transferring from
20 // server view to client view
21 eventSelectors: [
22 // for recording changes in form elements
23 {
24 selector: 'input,textarea',
25 events: ['keypress', 'keyup', 'keydown', 'input', 'change']
26 },
27 { selector: 'select,option', events: ['change'] },
28 // when user hits return button in an input box
29 {
30 selector: 'input',
31 events: ['keyup'],
32 preventDefault: true,
33 keyCodes: [13],
34 freeze: true
35 },
36 // when user submit form (press enter, click on button/input[type="submit"])
37 {
38 selector: 'form',
39 events: ['submit'],
40 preventDefault: true,
41 freeze: true
42 },
43 // for tracking focus (no need to replay)
44 {
45 selector: 'input,textarea',
46 events: ['focusin', 'focusout', 'mousedown', 'mouseup'],
47 replay: false
48 },
49 // user clicks on a button
50 {
51 selector: 'button',
52 events: ['click'],
53 preventDefault: true,
54 freeze: true
55 }
56 ]
57};
58/**
59 * Get the event recorder code based on all functions in event.recorder.ts
60 * and the getNodeKeyForPreboot function.
61 */
62export function getEventRecorderCode() {
63 const eventRecorderFunctions = [];
64 for (const funcName in eventRecorder) {
65 if (eventRecorder.hasOwnProperty(funcName)) {
66 const fn = eventRecorder[funcName].toString();
67 const fnCleaned = fn.replace('common_1.', '');
68 eventRecorderFunctions.push(fnCleaned);
69 }
70 }
71 // this is common function used to get the node key
72 eventRecorderFunctions.push(getNodeKeyForPreboot.toString());
73 // add new line characters for readability
74 return '\n\n' + eventRecorderFunctions.join('\n\n') + '\n\n';
75}
76/**
77 * Used by the server side version of preboot. The main purpose is to get the
78 * inline code that can be inserted into the server view.
79 * Returns the definitions of the prebootInit function called in code returned by
80 * getInlineInvocation for each server node separately.
81 *
82 * @param customOptions PrebootRecordOptions that override the defaults
83 * @returns Generated inline preboot code with just functions definitions
84 * to be used separately
85 */
86export function getInlineDefinition(customOptions) {
87 const opts = assign({}, defaultOptions, customOptions);
88 // safety check to make sure options passed in are valid
89 validateOptions(opts);
90 const scriptCode = getEventRecorderCode();
91 const optsStr = stringifyWithFunctions(opts);
92 // wrap inline preboot code with a self executing function in order to create scope
93 const initAllStr = initAll.toString();
94 return `var ${initFunctionName} = (function() {
95 ${scriptCode}
96 return (${initAllStr.replace('common_1.', '')})(${optsStr});
97 })();`;
98}
99/**
100 * Used by the server side version of preboot. The main purpose is to get the
101 * inline code that can be inserted into the server view.
102 * Invokes the prebootInit function defined in getInlineDefinition with proper
103 * parameters. Each appRoot should get a separate inlined code from a separate
104 * call to getInlineInvocation but only one inlined code from getInlineDefinition.
105 *
106 * @returns Generated inline preboot code with just invocations of functions from
107 * getInlineDefinition
108 */
109export function getInlineInvocation() {
110 return `${initFunctionName}();`;
111}
112/**
113 * Throw an error if issues with any options
114 * @param opts
115 */
116export function validateOptions(opts) {
117 if (!opts.appRoot || !opts.appRoot.length) {
118 throw new Error('The appRoot is missing from preboot options. ' +
119 'This is needed to find the root of your application. ' +
120 'Set this value in the preboot options to be a selector for the root element of your app.');
121 }
122}
123/**
124 * Object.assign() is not fully supporting in TypeScript, so
125 * this is just a simple implementation of it
126 *
127 * @param target The target object
128 * @param optionSets Any number of addition objects that are added on top of the
129 * target
130 * @returns A new object that contains all the merged values
131 */
132export function assign(target, ...optionSets) {
133 if (target === undefined || target === null) {
134 throw new TypeError('Cannot convert undefined or null to object');
135 }
136 const output = Object(target);
137 for (let index = 0; index < optionSets.length; index++) {
138 const source = optionSets[index];
139 if (source !== undefined && source !== null) {
140 for (const nextKey in source) {
141 if (source.hasOwnProperty && source.hasOwnProperty(nextKey)) {
142 output[nextKey] = source[nextKey];
143 }
144 }
145 }
146 }
147 return output;
148}
149/**
150 * Stringify an object and include functions. This is needed since we are
151 * letting users pass in options that include custom functions for things like
152 * the freeze handler or action when an event occurs
153 *
154 * @param obj This is the object you want to stringify that includes some
155 * functions
156 * @returns The stringified version of an object
157 */
158export function stringifyWithFunctions(obj) {
159 const FUNC_START = 'START_FUNCTION_HERE';
160 const FUNC_STOP = 'STOP_FUNCTION_HERE';
161 // first stringify except mark off functions with markers
162 let str = JSON.stringify(obj, function (_key, value) {
163 // if the value is a function, we want to wrap it with markers
164 if (!!(value && value.constructor && value.call && value.apply)) {
165 return FUNC_START + value.toString() + FUNC_STOP;
166 }
167 else {
168 return value;
169 }
170 });
171 // now we use the markers to replace function strings with actual functions
172 let startFuncIdx = str.indexOf(FUNC_START);
173 let stopFuncIdx;
174 let fn;
175 while (startFuncIdx >= 0) {
176 stopFuncIdx = str.indexOf(FUNC_STOP);
177 // pull string out
178 fn = str.substring(startFuncIdx + FUNC_START.length, stopFuncIdx);
179 fn = fn.replace(/\\n/g, '\n');
180 str = str.substring(0, startFuncIdx - 1) + fn +
181 str.substring(stopFuncIdx + FUNC_STOP.length + 1);
182 startFuncIdx = str.indexOf(FUNC_START);
183 }
184 return str;
185}
186//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5saW5lLnByZWJvb3QuY29kZS5qcyIsInNvdXJjZVJvb3QiOiIuLi8uLi9zcmMvbGliLyIsInNvdXJjZXMiOlsiYXBpL2lubGluZS5wcmVib290LmNvZGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBUUEsT0FBTyxFQUFDLG9CQUFvQixFQUFDLE1BQU0sd0JBQXdCLENBQUM7QUFFNUQsT0FBTyxFQUNMLE9BQU8sRUFDUCxLQUFLLEVBQ0wsYUFBYSxFQUNiLFVBQVUsRUFDVixZQUFZLEVBQ1osbUJBQW1CLEVBQ25CLFlBQVksRUFDWixZQUFZLEVBQ2IsTUFBTSxrQkFBa0IsQ0FBQztBQUUxQixNQUFNLGFBQWEsR0FBRztJQUNwQixLQUFLO0lBQ0wsYUFBYTtJQUNiLFVBQVU7SUFDVixZQUFZO0lBQ1osbUJBQW1CO0lBQ25CLFlBQVk7SUFDWixZQUFZO0NBQ2IsQ0FBQztBQUVGLE1BQU0sQ0FBQyxNQUFNLGdCQUFnQixHQUFHLGVBQWUsQ0FBQztBQUVoRCw2RUFBNkU7QUFDN0UsTUFBTTtBQUNOLE1BQU0sQ0FBQyxNQUFNLGNBQWMsR0FBbUI7SUFDNUMsTUFBTSxFQUFFLElBQUk7SUFDWixNQUFNLEVBQUUsSUFBSTtJQUNaLGNBQWMsRUFBRSxLQUFLO0lBRXJCLDBFQUEwRTtJQUMxRSw2QkFBNkI7SUFDN0IsY0FBYyxFQUFFO1FBQ2QseUNBQXlDO1FBQ3pDO1lBQ0UsUUFBUSxFQUFFLGdCQUFnQjtZQUMxQixNQUFNLEVBQUUsQ0FBQyxVQUFVLEVBQUUsT0FBTyxFQUFFLFNBQVMsRUFBRSxPQUFPLEVBQUUsUUFBUSxDQUFDO1NBQzVEO1FBQ0QsRUFBRSxRQUFRLEVBQUUsZUFBZSxFQUFFLE1BQU0sRUFBRSxDQUFDLFFBQVEsQ0FBQyxFQUFFO1FBRWpELCtDQUErQztRQUMvQztZQUNFLFFBQVEsRUFBRSxPQUFPO1lBQ2pCLE1BQU0sRUFBRSxDQUFDLE9BQU8sQ0FBQztZQUNqQixjQUFjLEVBQUUsSUFBSTtZQUNwQixRQUFRLEVBQUUsQ0FBQyxFQUFFLENB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V0FBbUIsQ0FBQztJQUN4QixJQUFJLEVBQVUsQ0FBQztJQUNmLE9BQU8sWUFBWSxJQUFJLENBQUMsRUFBRTtRQUN4QixXQUFXLEdBQUcsR0FBRyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUVyQyxrQkFBa0I7UUFDbEIsRUFBRSxHQUFHLEdBQUcsQ0FBQyxTQUFTLENBQUMsWUFBWSxHQUFHLFVBQVUsQ0FBQyxNQUFNLEVBQUUsV0FBVyxDQUFDLENBQUM7UUFDbEUsRUFBRSxHQUFHLEVBQUUsQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxDQUFDO1FBRTlCLEdBQUcsR0FBRyxHQUFHLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxZQUFZLEdBQUcsQ0FBQyxDQUFDLEdBQUcsRUFBRTtZQUMzQyxHQUFHLENBQUMsU0FBUyxDQUFDLFdBQVcsR0FBRyxTQUFTLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQ3BELFlBQVksR0FBRyxHQUFHLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUFDO0tBQ3hDO0lBRUQsT0FBTyxHQUFHLENBQUM7QUFDYixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IEdvb2dsZSBMTEMgQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuICogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBhdCBodHRwczovL2FuZ3VsYXIuaW8vbGljZW5zZVxuICovXG5pbXBvcnQge1ByZWJvb3RPcHRpb25zfSBmcm9tICcuLi9jb21tb24vcHJlYm9vdC5pbnRlcmZhY2VzJztcbmltcG9ydCB7Z2V0Tm9kZUtleUZvclByZWJvb3R9IGZyb20gJy4uL2NvbW1vbi9nZXQtbm9kZS1rZXknO1xuXG5pbXBvcnQge1xuICBpbml0QWxsLFxuICBzdGFydCxcbiAgY3JlYXRlT3ZlcmxheSxcbiAgZ2V0QXBwUm9vdCxcbiAgaGFuZGxlRXZlbnRzLFxuICBjcmVhdGVMaXN0ZW5IYW5kbGVyLFxuICBnZXRTZWxlY3Rpb24sXG4gIGNyZWF0ZUJ1ZmZlclxufSBmcm9tICcuL2V2ZW50LnJlY29yZGVyJztcblxuY29uc3QgZXZlbnRSZWNvcmRlciA9IHtcbiAgc3RhcnQsXG4gIGNyZWF0ZU92ZXJsYXksXG4gIGdldEFwcFJvb3QsXG4gIGhhbmRsZUV2ZW50cyxcbiAgY3JlYXRlTGlzdGVuSGFuZGxlcixcbiAgZ2V0U2VsZWN0aW9uLFxuICBjcmVhdGVCdWZmZXJcbn07XG5cbmV4cG9ydCBjb25zdCBpbml0RnVuY3Rpb25OYW1lID0gJ3ByZWJvb3RJbml0Rm4nO1xuXG4vLyBleHBvcnRpbmcgZGVmYXVsdCBvcHRpb25zIGluIGNhc2UgZGV2ZWxvcGVyIHdhbnRzIHRvIHVzZSB0aGVzZSArIGN1c3RvbSBvblxuLy8gdG9wXG5leHBvcnQgY29uc3QgZGVmYXVsdE9wdGlvbnMgPSA8UHJlYm9vdE9wdGlvbnM+e1xuICBidWZmZXI6IHRydWUsXG4gIHJlcGxheTogdHJ1ZSxcbiAgZGlzYWJsZU92ZXJsYXk6IGZhbHNlLFxuXG4gIC8vIHRoZXNlIGFyZSB0aGUgZGVmYXVsdCBldmVudHMgYXJlIGFyZSBsaXN0ZW5pbmcgZm9yIGFuIHRyYW5zZmVycmluZyBmcm9tXG4gIC8vIHNlcnZlciB2aWV3IHRvIGNsaWVudCB2aWV3XG4gIGV2ZW50U2VsZWN0b3JzOiBbXG4gICAgLy8gZm9yIHJlY29yZGluZyBjaGFuZ2VzIGluIGZvcm0gZWxlbWVudHNcbiAgICB7XG4gICAgICBzZWxlY3RvcjogJ2lucHV0LHRleHRhcmVhJyxcbiAgICAgIGV2ZW50czogWydrZXlwcmVzcycsICdrZXl1cCcsICdrZXlkb3duJywgJ2lucHV0JywgJ2NoYW5nZSddXG4gICAgfSxcbiAgICB7IHNlbGVjdG9yOiAnc2VsZWN0LG9wdGlvbicsIGV2ZW50czogWydjaGFuZ2UnXSB9LFxuXG4gICAgLy8gd2hlbiB1c2VyIGhpdHMgcmV0dXJuIGJ1dHRvbiBpbiBhbiBpbnB1dCBib3hcbiAgICB7XG4gICAgICBzZWxlY3RvcjogJ2lucHV0JyxcbiAgICAgIGV2ZW50czogWydrZXl1cCddLFxuICAgICAgcHJldmVudERlZmF1bHQ6IHRydWUsXG4gICAgICBrZXlDb2RlczogWzEzXSxcbiAgICAgIGZyZWV6ZTogdHJ1ZVxuICAgIH0sXG5cbiAgICAvLyB3aGVuIHVzZXIgc3VibWl0IGZvcm0gKHByZXNzIGVudGVyLCBjbGljayBvbiBidXR0b24vaW5wdXRbdHlwZT1cInN1Ym1pdFwiXSlcbiAgICB7XG4gICAgICBzZWxlY3RvcjogJ2Zvcm0nLFxuICAgICAgZXZlbnRzOiBbJ3N1Ym1pdCddLFxuICAgICAgcHJldmVudERlZmF1bHQ6IHRydWUsXG4gICAgICBmcmVlemU6IHRydWVcbiAgICB9LFxuXG4gICAgLy8gZm9yIHRyYWNraW5nIGZvY3VzIChubyBuZWVkIHRvIHJlcGxheSlcbiAgICB7XG4gICAgICBzZWxlY3RvcjogJ2lucHV0LHRleHRhcmVhJyxcbiAgICAgIGV2ZW50czogWydmb2N1c2luJywgJ2ZvY3Vzb3V0JywgJ21vdXNlZG93bicsICdtb3VzZXVwJ10sXG4gICAgICByZXBsYXk6IGZhbHNlXG4gICAgfSxcblxuICAgIC8vIHVzZXIgY2xpY2tzIG9uIGEgYnV0dG9uXG4gICAge1xuICAgICAgc2VsZWN0b3I6ICdidXR0b24nLFxuICAgICAgZXZlbnRzOiBbJ2NsaWNrJ10sXG4gICAgICBwcmV2ZW50RGVmYXVsdDogdHJ1ZSxcbiAgICAgIGZyZWV6ZTogdHJ1ZVxuICAgIH1cbiAgXVxufTtcblxuLyoqXG4gKiBHZXQgdGhlIGV2ZW50IHJlY29yZGVyIGNvZGUgYmFzZWQgb24gYWxsIGZ1bmN0aW9ucyBpbiBldmVudC5yZWNvcmRlci50c1xuICogYW5kIHRoZSBnZXROb2RlS2V5Rm9yUHJlYm9vdCBmdW5jdGlvbi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldEV2ZW50UmVjb3JkZXJDb2RlKCk6IHN0cmluZyB7XG4gIGNvbnN0IGV2ZW50UmVjb3JkZXJGdW5jdGlvbnM6IHN0cmluZ1tdID0gW107XG5cbiAgZm9yIChjb25zdCBmdW5jTmFtZSBpbiBldmVudFJlY29yZGVyKSB7XG4gICAgaWYgKGV2ZW50UmVjb3JkZXIuaGFzT3duUHJvcGVydHkoZnVuY05hbWUpKSB7XG4gICAgICBjb25zdCBmbiA9ICg8YW55PmV2ZW50UmVjb3JkZXIpW2Z1bmNOYW1lXS50b1N0cmluZygpO1xuICAgICAgY29uc3QgZm5DbGVhbmVkID0gZm4ucmVwbGFjZSgnY29tbW9uXzEuJywgJycpO1xuICAgICAgZXZlbnRSZWNvcmRlckZ1bmN0aW9ucy5wdXNoKGZuQ2xlYW5lZCk7XG4gICAgfVxuICB9XG5cbiAgLy8gdGhpcyBpcyBjb21tb24gZnVuY3Rpb24gdXNlZCB0byBnZXQgdGhlIG5vZGUga2V5XG4gIGV2ZW50UmVjb3JkZXJGdW5jdGlvbnMucHVzaChnZXROb2RlS2V5Rm9yUHJlYm9vdC50b1N0cmluZygpKTtcblxuICAvLyBhZGQgbmV3IGxpbmUgY2hhcmFjdGVycyBmb3IgcmVhZGFiaWxpdHlcbiAgcmV0dXJuICdcXG5cXG4nICsgZXZlbnRSZWNvcmRlckZ1bmN0aW9ucy5qb2luKCdcXG5cXG4nKSArICdcXG5cXG4nO1xufVxuXG4vKipcbiAqIFVzZWQgYnkgdGhlIHNlcnZlciBzaWRlIHZlcnNpb24gb2YgcHJlYm9vdC4gVGhlIG1haW4gcHVycG9zZSBpcyB0byBnZXQgdGhlXG4gKiBpbmxpbmUgY29kZSB0aGF0IGNhbiBiZSBpbnNlcnRlZCBpbnRvIHRoZSBzZXJ2ZXIgdmlldy5cbiAqIFJldHVybnMgdGhlIGRlZmluaXRpb25zIG9mIHRoZSBwcmVib290SW5pdCBmdW5jdGlvbiBjYWxsZWQgaW4gY29kZSByZXR1cm5lZCBieVxuICogZ2V0SW5saW5lSW52b2NhdGlvbiBmb3IgZWFjaCBzZXJ2ZXIgbm9kZSBzZXBhcmF0ZWx5LlxuICpcbiAqIEBwYXJhbSBjdXN0b21PcHRpb25zIFByZWJvb3RSZWNvcmRPcHRpb25zIHRoYXQgb3ZlcnJpZGUgdGhlIGRlZmF1bHRzXG4gKiBAcmV0dXJucyBHZW5lcmF0ZWQgaW5saW5lIHByZWJvb3QgY29kZSB3aXRoIGp1c3QgZnVuY3Rpb25zIGRlZmluaXRpb25zXG4gKiB0byBiZSB1c2VkIHNlcGFyYXRlbHlcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldElubGluZURlZmluaXRpb24oY3VzdG9tT3B0aW9ucz86IFByZWJvb3RPcHRpb25zKTogc3RyaW5nIHtcbiAgY29uc3Qgb3B0cyA9IDxQcmVib290T3B0aW9ucz5hc3NpZ24oe30sIGRlZmF1bHRPcHRpb25zLCBjdXN0b21PcHRpb25zKTtcblxuICAvLyBzYWZldHkgY2hlY2sgdG8gbWFrZSBzdXJlIG9wdGlvbnMgcGFzc2VkIGluIGFyZSB2YWxpZFxuICB2YWxpZGF0ZU9wdGlvbnMob3B0cyk7XG5cbiAgY29uc3Qgc2NyaXB0Q29kZSA9IGdldEV2ZW50UmVjb3JkZXJDb2RlKCk7XG4gIGNvbnN0IG9wdHNTdHIgPSBzdHJpbmdpZnlXaXRoRnVuY3Rpb25zKG9wdHMpO1xuXG4gIC8vIHdyYXAgaW5saW5lIHByZWJvb3QgY29kZSB3aXRoIGEgc2VsZiBleGVjdXRpbmcgZnVuY3Rpb24gaW4gb3JkZXIgdG8gY3JlYXRlIHNjb3BlXG4gIGNvbnN0IGluaXRBbGxTdHIgPSBpbml0QWxsLnRvU3RyaW5nKCk7XG4gIHJldHVybiBgdmFyICR7aW5pdEZ1bmN0aW9uTmFtZX0gPSAoZnVuY3Rpb24oKSB7XG4gICAgICAke3NjcmlwdENvZGV9XG4gICAgICByZXR1cm4gKCR7aW5pdEFsbFN0ci5yZXBsYWNlKCdjb21tb25fMS4nLCAnJyl9KSgke29wdHNTdHJ9KTtcbiAgICB9KSgpO2A7XG59XG5cblxuLyoqXG4gKiBVc2VkIGJ5IHRoZSBzZXJ2ZXIgc2lkZSB2ZXJzaW9uIG9mIHByZWJvb3QuIFRoZSBtYWluIHB1cnBvc2UgaXMgdG8gZ2V0IHRoZVxuICogaW5saW5lIGNvZGUgdGhhdCBjYW4gYmUgaW5zZXJ0ZWQgaW50byB0aGUgc2VydmVyIHZpZXcuXG4gKiBJbnZva2VzIHRoZSBwcmVib290SW5pdCBmdW5jdGlvbiBkZWZpbmVkIGluIGdldElubGluZURlZmluaXRpb24gd2l0aCBwcm9wZXJcbiAqIHBhcmFtZXRlcnMuIEVhY2ggYXBwUm9vdCBzaG91bGQgZ2V0IGEgc2VwYXJhdGUgaW5saW5lZCBjb2RlIGZyb20gYSBzZXBhcmF0ZVxuICogY2FsbCB0byBnZXRJbmxpbmVJbnZvY2F0aW9uIGJ1dCBvbmx5IG9uZSBpbmxpbmVkIGNvZGUgZnJvbSBnZXRJbmxpbmVEZWZpbml0aW9uLlxuICpcbiAqIEByZXR1cm5zIEdlbmVyYXRlZCBpbmxpbmUgcHJlYm9vdCBjb2RlIHdpdGgganVzdCBpbnZvY2F0aW9ucyBvZiBmdW5jdGlvbnMgZnJvbVxuICogZ2V0SW5saW5lRGVmaW5pdGlvblxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0SW5saW5lSW52b2NhdGlvbigpOiBzdHJpbmcge1xuICByZXR1cm4gYCR7aW5pdEZ1bmN0aW9uTmFtZX0oKTtgO1xufVxuXG4vKipcbiAqIFRocm93IGFuIGVycm9yIGlmIGlzc3VlcyB3aXRoIGFueSBvcHRpb25zXG4gKiBAcGFyYW0gb3B0c1xuICovXG5leHBvcnQgZnVuY3Rpb24gdmFsaWRhdGVPcHRpb25zKG9wdHM6IFByZWJvb3RPcHRpb25zKSB7XG4gIGlmICghb3B0cy5hcHBSb290IHx8ICFvcHRzLmFwcFJvb3QubGVuZ3RoKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgJ1RoZSBhcHBSb290IGlzIG1pc3NpbmcgZnJvbSBwcmVib290IG9wdGlvbnMuICcgK1xuICAgICAgICAnVGhpcyBpcyBuZWVkZWQgdG8gZmluZCB0aGUgcm9vdCBvZiB5b3VyIGFwcGxpY2F0aW9uLiAnICtcbiAgICAgICAgJ1NldCB0aGlzIHZhbHVlIGluIHRoZSBwcmVib290IG9wdGlvbnMgdG8gYmUgYSBzZWxlY3RvciBmb3IgdGhlIHJvb3QgZWxlbWVudCBvZiB5b3VyIGFwcC4nXG4gICAgKTtcbiAgfVxufVxuXG4vKipcbiAqIE9iamVjdC5hc3NpZ24oKSBpcyBub3QgZnVsbHkgc3VwcG9ydGluZyBpbiBUeXBlU2NyaXB0LCBzb1xuICogdGhpcyBpcyBqdXN0IGEgc2ltcGxlIGltcGxlbWVudGF0aW9uIG9mIGl0XG4gKlxuICogQHBhcmFtIHRhcmdldCBUaGUgdGFyZ2V0IG9iamVjdFxuICogQHBhcmFtIG9wdGlvblNldHMgQW55IG51bWJlciBvZiBhZGRpdGlvbiBvYmplY3RzIHRoYXQgYXJlIGFkZGVkIG9uIHRvcCBvZiB0aGVcbiAqIHRhcmdldFxuICogQHJldHVybnMgQSBuZXcgb2JqZWN0IHRoYXQgY29udGFpbnMgYWxsIHRoZSBtZXJnZWQgdmFsdWVzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhc3NpZ24odGFyZ2V0OiBPYmplY3QsIC4uLm9wdGlvblNldHM6IGFueVtdKTogT2JqZWN0IHtcbiAgaWYgKHRhcmdldCA9PT0gdW5kZWZpbmVkIHx8IHRhcmdldCA9PT0gbnVsbCkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0Nhbm5vdCBjb252ZXJ0IHVuZGVmaW5lZCBvciBudWxsIHRvIG9iamVjdCcpO1xuICB9XG5cbiAgY29uc3Qgb3V0cHV0ID0gT2JqZWN0KHRhcmdldCk7XG4gIGZvciAobGV0IGluZGV4ID0gMDsgaW5kZXggPCBvcHRpb25TZXRzLmxlbmd0aDsgaW5kZXgrKykge1xuICAgIGNvbnN0IHNvdXJjZSA9IG9wdGlvblNldHNbaW5kZXhdO1xuICAgIGlmIChzb3VyY2UgIT09IHVuZGVmaW5lZCAmJiBzb3VyY2UgIT09IG51bGwpIHtcbiAgICAgIGZvciAoY29uc3QgbmV4dEtleSBpbiBzb3VyY2UpIHtcbiAgICAgICAgaWYgKHNvdXJjZS5oYXNPd25Qcm9wZXJ0eSAmJiBzb3VyY2UuaGFzT3duUHJvcGVydHkobmV4dEtleSkpIHtcbiAgICAgICAgICBvdXRwdXRbbmV4dEtleV0gPSBzb3VyY2VbbmV4dEtleV07XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICByZXR1cm4gb3V0cHV0O1xufVxuXG4vKipcbiAqIFN0cmluZ2lmeSBhbiBvYmplY3QgYW5kIGluY2x1ZGUgZnVuY3Rpb25zLiBUaGlzIGlzIG5lZWRlZCBzaW5jZSB3ZSBhcmVcbiAqIGxldHRpbmcgdXNlcnMgcGFzcyBpbiBvcHRpb25zIHRoYXQgaW5jbHVkZSBjdXN0b20gZnVuY3Rpb25zIGZvciB0aGluZ3MgbGlrZVxuICogdGhlIGZyZWV6ZSBoYW5kbGVyIG9yIGFjdGlvbiB3aGVuIGFuIGV2ZW50IG9jY3Vyc1xuICpcbiAqIEBwYXJhbSBvYmogVGhpcyBpcyB0aGUgb2JqZWN0IHlvdSB3YW50IHRvIHN0cmluZ2lmeSB0aGF0IGluY2x1ZGVzIHNvbWVcbiAqIGZ1bmN0aW9uc1xuICogQHJldHVybnMgVGhlIHN0cmluZ2lmaWVkIHZlcnNpb24gb2YgYW4gb2JqZWN0XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzdHJpbmdpZnlXaXRoRnVuY3Rpb25zKG9iajogT2JqZWN0KTogc3RyaW5nIHtcbiAgY29uc3QgRlVOQ19TVEFSVCA9ICdTVEFSVF9GVU5DVElPTl9IRVJFJztcbiAgY29uc3QgRlVOQ19TVE9QID0gJ1NUT1BfRlVOQ1RJT05fSEVSRSc7XG5cbiAgLy8gZmlyc3Qgc3RyaW5naWZ5IGV4Y2VwdCBtYXJrIG9mZiBmdW5jdGlvbnMgd2l0aCBtYXJrZXJzXG4gIGxldCBzdHIgPSBKU09OLnN0cmluZ2lmeShvYmosIGZ1bmN0aW9uKF9rZXksIHZhbHVlKSB7XG4gICAgLy8gaWYgdGhlIHZhbHVlIGlzIGEgZnVuY3Rpb24sIHdlIHdhbnQgdG8gd3JhcCBpdCB3aXRoIG1hcmtlcnNcbiAgICBpZiAoISEodmFsdWUgJiYgdmFsdWUuY29uc3RydWN0b3IgJiYgdmFsdWUuY2FsbCAmJiB2YWx1ZS5hcHBseSkpIHtcbiAgICAgIHJldHVybiBGVU5DX1NUQVJUICsgdmFsdWUudG9TdHJpbmcoKSArIEZVTkNfU1RPUDtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHZhbHVlO1xuICAgIH1cbiAgfSk7XG5cbiAgLy8gbm93IHdlIHVzZSB0aGUgbWFya2VycyB0byByZXBsYWNlIGZ1bmN0aW9uIHN0cmluZ3Mgd2l0aCBhY3R1YWwgZnVuY3Rpb25zXG4gIGxldCBzdGFydEZ1bmNJZHggPSBzdHIuaW5kZXhPZihGVU5DX1NUQVJUKTtcbiAgbGV0IHN0b3BGdW5jSWR4OiBudW1iZXI7XG4gIGxldCBmbjogc3RyaW5nO1xuICB3aGlsZSAoc3RhcnRGdW5jSWR4ID49IDApIHtcbiAgICBzdG9wRnVuY0lkeCA9IHN0ci5pbmRleE9mKEZVTkNfU1RPUCk7XG5cbiAgICAvLyBwdWxsIHN0cmluZyBvdXRcbiAgICBmbiA9IHN0ci5zdWJzdHJpbmcoc3RhcnRGdW5jSWR4ICsgRlVOQ19TVEFSVC5sZW5ndGgsIHN0b3BGdW5jSWR4KTtcbiAgICBmbiA9IGZuLnJlcGxhY2UoL1xcXFxuL2csICdcXG4nKTtcblxuICAgIHN0ciA9IHN0ci5zdWJzdHJpbmcoMCwgc3RhcnRGdW5jSWR4IC0gMSkgKyBmbiArXG4gICAgICBzdHIuc3Vic3RyaW5nKHN0b3BGdW5jSWR4ICsgRlVOQ19TVE9QLmxlbmd0aCArIDEpO1xuICAgIHN0YXJ0RnVuY0lkeCA9IHN0ci5pbmRleE9mKEZVTkNfU1RBUlQpO1xuICB9XG5cbiAgcmV0dXJuIHN0cjtcbn1cbiJdfQ==
\No newline at end of file