1 | import { getNodeKeyForPreboot } from '../common/get-node-key';
|
2 | /**
|
3 | * Called right away to initialize preboot
|
4 | *
|
5 | * @param opts All the preboot options
|
6 | * @param win
|
7 | */
|
8 | export function initAll(opts, win) {
|
9 | const theWindow = (win || window);
|
10 | // Add the preboot options to the preboot data and then add the data to
|
11 | // the window so it can be used later by the client.
|
12 | // Only set new options if they're not already set - we may have multiple app roots
|
13 | // and each of them invokes the init function separately.
|
14 | const data = (theWindow.prebootData = {
|
15 | opts: opts,
|
16 | apps: [],
|
17 | listeners: []
|
18 | });
|
19 | return () => start(data, theWindow);
|
20 | }
|
21 | /**
|
22 | * Start up preboot by going through each app and assigning the appropriate
|
23 | * handlers. Normally this wouldn't be called directly, but we have set it up so
|
24 | * that it can for older versions of Universal.
|
25 | *
|
26 | * @param prebootData Global preboot data object that contains options and will
|
27 | * have events
|
28 | * @param win Optional param to pass in mock window for testing purposes
|
29 | */
|
30 | export function start(prebootData, win) {
|
31 | const theWindow = (win || window);
|
32 | const _document = (theWindow.document || {});
|
33 | // Remove the current script from the DOM so that child indexes match
|
34 | // between the client & the server. The script is already running so it
|
35 | // doesn't affect it.
|
36 | const currentScript = _document.currentScript ||
|
37 | // Support: IE 9-11 only
|
38 | // IE doesn't support document.currentScript. Since the script is invoked
|
39 | // synchronously, though, the current running script is just the last one
|
40 | // currently in the document.
|
41 | [].slice.call(_document.getElementsByTagName('script'), -1)[0];
|
42 | if (!currentScript) {
|
43 | console.error('Preboot initialization failed, no currentScript has been detected.');
|
44 | return;
|
45 | }
|
46 | let serverNode = currentScript.parentNode;
|
47 | if (!serverNode) {
|
48 | console.error('Preboot initialization failed, the script is detached');
|
49 | return;
|
50 | }
|
51 | serverNode.removeChild(currentScript);
|
52 | const opts = prebootData.opts || {};
|
53 | let eventSelectors = opts.eventSelectors || [];
|
54 | // get the root info
|
55 | const appRoot = prebootData.opts ? getAppRoot(_document, prebootData.opts, serverNode) : null;
|
56 | // we track all events for each app in the prebootData object which is on
|
57 | // the global scope; each `start` invocation adds data for one app only.
|
58 | const appData = { root: appRoot, events: [] };
|
59 | if (prebootData.apps) {
|
60 | prebootData.apps.push(appData);
|
61 | }
|
62 | eventSelectors = eventSelectors.map(eventSelector => {
|
63 | if (!eventSelector.hasOwnProperty('replay')) {
|
64 | eventSelector.replay = true;
|
65 | }
|
66 | return eventSelector;
|
67 | });
|
68 | // loop through all the eventSelectors and create event handlers
|
69 | eventSelectors.forEach(eventSelector => handleEvents(_document, prebootData, appData, eventSelector));
|
70 | }
|
71 | /**
|
72 | * Create an overlay div and add it to the DOM so it can be used
|
73 | * if a freeze event occurs
|
74 | *
|
75 | * @param _document The global document object (passed in for testing purposes)
|
76 | * @returns Element The overlay node is returned
|
77 | */
|
78 | export function createOverlay(_document) {
|
79 | let overlay = _document.createElement('div');
|
80 | overlay.setAttribute('id', 'prebootOverlay');
|
81 | overlay.setAttribute('style', 'display:none;position:absolute;left:0;' +
|
82 | 'top:0;width:100%;height:100%;z-index:999999;background:black;opacity:.3');
|
83 | _document.documentElement.appendChild(overlay);
|
84 | return overlay;
|
85 | }
|
86 | /**
|
87 | * Get references to the current app root node based on input options. Users can
|
88 | * initialize preboot either by specifying appRoot which is just one or more
|
89 | * selectors for apps. This section option is useful for people that are doing their own
|
90 | * buffering (i.e. they have their own client and server view)
|
91 | *
|
92 | * @param _document The global document object used to attach the overlay
|
93 | * @param opts Options passed in by the user to init()
|
94 | * @param serverNode The server node serving as application root
|
95 | * @returns ServerClientRoot An array of root info for the current app
|
96 | */
|
97 | export function getAppRoot(_document, opts, serverNode) {
|
98 | const root = { serverNode };
|
99 | // if we are doing buffering, we need to create the buffer for the client
|
100 | // else the client root is the same as the server
|
101 | root.clientNode = opts.buffer ? createBuffer(root) : root.serverNode;
|
102 | // create an overlay if not disabled ,that can be used later if a freeze event occurs
|
103 | if (!opts.disableOverlay) {
|
104 | root.overlay = createOverlay(_document);
|
105 | }
|
106 | return root;
|
107 | }
|
108 | /**
|
109 | * Under given server root, for given selector, record events
|
110 | *
|
111 | * @param _document
|
112 | * @param prebootData
|
113 | * @param appData
|
114 | * @param eventSelector
|
115 | */
|
116 | export function handleEvents(_document, prebootData, appData, eventSelector) {
|
117 | const serverRoot = appData.root.serverNode;
|
118 | // don't do anything if no server root
|
119 | if (!serverRoot) {
|
120 | return;
|
121 | }
|
122 | // Attach delegated event listeners for each event selector.
|
123 | // We need to use delegated events as only the top level server node
|
124 | // exists at this point.
|
125 | eventSelector.events.forEach((eventName) => {
|
126 | // get the appropriate handler and add it as an event listener
|
127 | const handler = createListenHandler(_document, prebootData, eventSelector, appData);
|
128 | // attach the handler in the capture phase so that it fires even if
|
129 | // one of the handlers below calls stopPropagation()
|
130 | serverRoot.addEventListener(eventName, handler, true);
|
131 | // need to keep track of listeners so we can do node.removeEventListener()
|
132 | // when preboot done
|
133 | if (prebootData.listeners) {
|
134 | prebootData.listeners.push({
|
135 | node: serverRoot,
|
136 | eventName,
|
137 | handler
|
138 | });
|
139 | }
|
140 | });
|
141 | }
|
142 | /**
|
143 | * Create handler for events that we will record
|
144 | */
|
145 | export function createListenHandler(_document, prebootData, eventSelector, appData) {
|
146 | const CARET_EVENTS = ['keyup', 'keydown', 'focusin', 'mouseup', 'mousedown'];
|
147 | const CARET_NODES = ['INPUT', 'TEXTAREA'];
|
148 | // Support: IE 9-11 only
|
149 | // IE uses a prefixed `matches` version
|
150 | const matches = _document.documentElement.matches ||
|
151 | _document.documentElement.msMatchesSelector;
|
152 | const opts = prebootData.opts;
|
153 | return function (event) {
|
154 | const node = event.target;
|
155 | // a delegated handlers on document is used so we need to check if
|
156 | // event target matches a desired selector
|
157 | if (!matches.call(node, eventSelector.selector)) {
|
158 | return;
|
159 | }
|
160 | const root = appData.root;
|
161 | const eventName = event.type;
|
162 | // if no node or no event name, just return
|
163 | if (!node || !eventName) {
|
164 | return;
|
165 | }
|
166 | // if key codes set for eventSelector, then don't do anything if event
|
167 | // doesn't include key
|
168 | const keyCodes = eventSelector.keyCodes;
|
169 | if (keyCodes && keyCodes.length) {
|
170 | const matchingKeyCodes = keyCodes.filter(keyCode => event.which === keyCode);
|
171 | // if there are not matches (i.e. key entered NOT one of the key codes)
|
172 | // then don't do anything
|
173 | if (!matchingKeyCodes.length) {
|
174 | return;
|
175 | }
|
176 | }
|
177 | // if for a given set of events we are preventing default, do that
|
178 | if (eventSelector.preventDefault) {
|
179 | event.preventDefault();
|
180 | }
|
181 | // if an action handler passed in, use that
|
182 | if (eventSelector.action) {
|
183 | eventSelector.action(node, event);
|
184 | }
|
185 | // get the node key for a given node
|
186 | const nodeKey = getNodeKeyForPreboot({ root: root, node: node });
|
187 | // record active node
|
188 | if (CARET_EVENTS.indexOf(eventName) >= 0) {
|
189 | // if it's an caret node, get the selection for the active node
|
190 | const isCaretNode = CARET_NODES.indexOf(node.tagName ? node.tagName : '') >= 0;
|
191 | prebootData.activeNode = {
|
192 | root: root,
|
193 | node: node,
|
194 | nodeKey: nodeKey,
|
195 | selection: isCaretNode ? getSelection(node) : undefined
|
196 | };
|
197 | }
|
198 | else if (eventName !== 'change' && eventName !== 'focusout') {
|
199 | prebootData.activeNode = undefined;
|
200 | }
|
201 | // if overlay is not disabled and we are freezing the UI
|
202 | if (opts && !opts.disableOverlay && eventSelector.freeze) {
|
203 | const overlay = root.overlay;
|
204 | // show the overlay
|
205 | overlay.style.display = 'block';
|
206 | // hide the overlay after 10 seconds just in case preboot.complete() never
|
207 | // called
|
208 | setTimeout(() => {
|
209 | overlay.style.display = 'none';
|
210 | }, 10000);
|
211 | }
|
212 | // we will record events for later replay unless explicitly marked as
|
213 | // doNotReplay
|
214 | if (eventSelector.replay) {
|
215 | appData.events.push({
|
216 | node,
|
217 | nodeKey,
|
218 | event,
|
219 | name: eventName
|
220 | });
|
221 | }
|
222 | };
|
223 | }
|
224 | /**
|
225 | * Get the selection data that is later used to set the cursor after client view
|
226 | * is active
|
227 | */
|
228 | export function getSelection(node) {
|
229 | node = node || {};
|
230 | const nodeValue = node.value || '';
|
231 | const selection = {
|
232 | start: nodeValue.length,
|
233 | end: nodeValue.length,
|
234 | direction: 'forward'
|
235 | };
|
236 | // if browser support selectionStart on node (Chrome, FireFox, IE9+)
|
237 | try {
|
238 | if (node.selectionStart || node.selectionStart === 0) {
|
239 | selection.start = node.selectionStart;
|
240 | selection.end = node.selectionEnd ? node.selectionEnd : 0;
|
241 | selection.direction = node.selectionDirection ?
|
242 | node.selectionDirection : 'none';
|
243 | }
|
244 | }
|
245 | catch (ex) { }
|
246 | return selection;
|
247 | }
|
248 | /**
|
249 | * Create buffer for a given node
|
250 | *
|
251 | * @param root All the data related to a particular app
|
252 | * @returns Returns the root client node.
|
253 | */
|
254 | export function createBuffer(root) {
|
255 | const serverNode = root.serverNode;
|
256 | // if no rootServerNode OR the selector is on the entire html doc or the body
|
257 | // OR no parentNode, don't buffer
|
258 | if (!serverNode || !serverNode.parentNode ||
|
259 | serverNode === document.documentElement || serverNode === document.body) {
|
260 | return serverNode;
|
261 | }
|
262 | // create shallow clone of server root
|
263 | const rootClientNode = serverNode.cloneNode(false);
|
264 | // we want the client to write to a hidden div until the time for switching
|
265 | // the buffers
|
266 | rootClientNode.style.display = 'none';
|
267 | // insert the client node before the server and return it
|
268 | serverNode.parentNode.insertBefore(rootClientNode, serverNode);
|
269 | // mark server node as not to be touched by AngularJS - needed for ngUpgrade
|
270 | serverNode.setAttribute('ng-non-bindable', '');
|
271 | // return the rootClientNode
|
272 | return rootClientNode;
|
273 | }
|
274 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXZlbnQucmVjb3JkZXIuanMiLCJzb3VyY2VSb290IjoiLi4vLi4vc3JjL2xpYi8iLCJzb3VyY2VzIjpbImFwaS9ldmVudC5yZWNvcmRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFrQkEsT0FBTyxFQUFDLG9CQUFvQixFQUFDLE1BQU0sd0JBQXdCLENBQUM7QUFFNUQ7Ozs7O0dBS0c7QUFDSCxNQUFNLFVBQVUsT0FBTyxDQUFDLElBQW9CLEVBQUUsR0FBbUI7SUFDL0QsTUFBTSxTQUFTLEdBQWtCLENBQUMsR0FBRyxJQUFJLE1BQU0sQ0FBQyxDQUFDO0lBRWpELHVFQUF1RTtJQUN2RSxvREFBb0Q7SUFDcEQsbUZBQW1GO0lBQ25GLHlEQUF5RDtJQUN6RCxNQUFNLElBQUksR0FBRyxDQUFDLFNBQVMsQ0FBQyxXQUFXLEdBQWdCO1FBQ2pELElBQUksRUFBRSxJQUFJO1FBQ1YsSUFBSSxFQUFFLEVBQUU7UUFDUixTQUFTLEVBQUUsRUFBRTtLQUNkLENBQUMsQ0FBQztJQUVILE9BQU8sR0FBRyxFQUFFLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxTQUFTLENBQUMsQ0FBQztBQUN0QyxDQUFDO0FBRUQ7Ozs7Ozs7O0dBUUc7QUFDSCxNQUFNLFVBQVUsS0FBSyxDQUFDLFdBQXdCLEVBQUUsR0FBbUI7SUFDakUsTUFBTSxTQUFTLEdBQWtCLENBQUMsR0FBRyxJQUFJLE1BQU0sQ0FBQyxDQUFDO0lBQ2pELE1BQU0sU0FBUyxHQUFhLENBQUMsU0FBUyxDQUFDLFFBQVEsSUFBSSxFQUFFLENBQUMsQ0FBQztJQUV2RCxxRUFBcUU7SUFDckUsdUVBQXVFO0lBQ3ZFLHFCQUFxQjtJQUNyQixNQUFNLGFBQWEsR0FBRyxTQUFTLENBQUMsYUFBYTtRQUMzQyx3QkFBd0I7UUFDeEIseUVBQXlFO1FBQ3pFLHlFQUF5RTtRQUN6RSw2QkFBNkI7UUFDN0IsRUFBRSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLG9CQUFvQixDQUFDLFFBQVEsQ0FBQyxFQUFF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QUMsVUFBVSxDQUFDLFVBQVU7UUFDdkMsVUFBVSxLQUFLLFFBQVEsQ0FBQyxlQUFlLElBQUksVUFBVSxLQUFLLFFBQVEsQ0FBQyxJQUFJLEVBQUU7UUFDekUsT0FBTyxVQUF5QixDQUFDO0tBQ2xDO0lBRUQsc0NBQXNDO0lBQ3RDLE1BQU0sY0FBYyxHQUFHLFVBQVUsQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFnQixDQUFDO0lBQ2xFLDJFQUEyRTtJQUMzRSxjQUFjO0lBQ2QsY0FBYyxDQUFDLEtBQUssQ0FBQyxPQUFPLEdBQUcsTUFBTSxDQUFDO0lBRXRDLHlEQUF5RDtJQUN6RCxVQUFVLENBQUMsVUFBVSxDQUFDLFlBQVksQ0FBQyxjQUFjLEVBQUUsVUFBVSxDQUFDLENBQUM7SUFFL0QsNEVBQTRFO0lBQzVFLFVBQVUsQ0FBQyxZQUFZLENBQUMsaUJBQWlCLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFFL0MsNEJBQTRCO0lBQzVCLE9BQU8sY0FBYyxDQUFDO0FBQ3hCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgR29vZ2xlIExMQyBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGFuIE1JVC1zdHlsZSBsaWNlbnNlIHRoYXQgY2FuIGJlXG4gKiBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGF0IGh0dHBzOi8vYW5ndWxhci5pby9saWNlbnNlXG4gKi9cbmltcG9ydCB7XG4gIEV2ZW50U2VsZWN0b3IsXG4gIFByZWJvb3RPcHRpb25zLFxuICBQcmVib290QXBwRGF0YSxcbiAgUHJlYm9vdERhdGEsXG4gIERvbUV2ZW50LFxuICBQcmVib290V2luZG93LFxuICBTZXJ2ZXJDbGllbnRSb290LFxuICBQcmVib290U2VsZWN0aW9uLFxuICBQcmVib290U2VsZWN0aW9uRGlyZWN0aW9uLFxufSBmcm9tICcuLi9jb21tb24vcHJlYm9vdC5pbnRlcmZhY2VzJztcbmltcG9ydCB7Z2V0Tm9kZUtleUZvclByZWJvb3R9IGZyb20gJy4uL2NvbW1vbi9nZXQtbm9kZS1rZXknO1xuXG4vKipcbiAqIENhbGxlZCByaWdodCBhd2F5IHRvIGluaXRpYWxpemUgcHJlYm9vdFxuICpcbiAqIEBwYXJhbSBvcHRzIEFsbCB0aGUgcHJlYm9vdCBvcHRpb25zXG4gKiBAcGFyYW0gd2luXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpbml0QWxsKG9wdHM6IFByZWJvb3RPcHRpb25zLCB3aW4/OiBQcmVib290V2luZG93KSB7XG4gIGNvbnN0IHRoZVdpbmRvdyA9IDxQcmVib290V2luZG93Pih3aW4gfHwgd2luZG93KTtcblxuICAvLyBBZGQgdGhlIHByZWJvb3Qgb3B0aW9ucyB0byB0aGUgcHJlYm9vdCBkYXRhIGFuZCB0aGVuIGFkZCB0aGUgZGF0YSB0b1xuICAvLyB0aGUgd2luZG93IHNvIGl0IGNhbiBiZSB1c2VkIGxhdGVyIGJ5IHRoZSBjbGllbnQuXG4gIC8vIE9ubHkgc2V0IG5ldyBvcHRpb25zIGlmIHRoZXkncmUgbm90IGFscmVhZHkgc2V0IC0gd2UgbWF5IGhhdmUgbXVsdGlwbGUgYXBwIHJvb3RzXG4gIC8vIGFuZCBlYWNoIG9mIHRoZW0gaW52b2tlcyB0aGUgaW5pdCBmdW5jdGlvbiBzZXBhcmF0ZWx5LlxuICBjb25zdCBkYXRhID0gKHRoZVdpbmRvdy5wcmVib290RGF0YSA9IDxQcmVib290RGF0YT57XG4gICAgb3B0czogb3B0cyxcbiAgICBhcHBzOiBbXSxcbiAgICBsaXN0ZW5lcnM6IFtdXG4gIH0pO1xuXG4gIHJldHVybiAoKSA9PiBzdGFydChkYXRhLCB0aGVXaW5kb3cpO1xufVxuXG4vKipcbiAqIFN0YXJ0IHVwIHByZWJvb3QgYnkgZ29pbmcgdGhyb3VnaCBlYWNoIGFwcCBhbmQgYXNzaWduaW5nIHRoZSBhcHByb3ByaWF0ZVxuICogaGFuZGxlcnMuIE5vcm1hbGx5IHRoaXMgd291bGRuJ3QgYmUgY2FsbGVkIGRpcmVjdGx5LCBidXQgd2UgaGF2ZSBzZXQgaXQgdXAgc29cbiAqIHRoYXQgaXQgY2FuIGZvciBvbGRlciB2ZXJzaW9ucyBvZiBVbml2ZXJzYWwuXG4gKlxuICogQHBhcmFtIHByZWJvb3REYXRhIEdsb2JhbCBwcmVib290IGRhdGEgb2JqZWN0IHRoYXQgY29udGFpbnMgb3B0aW9ucyBhbmQgd2lsbFxuICogaGF2ZSBldmVudHNcbiAqIEBwYXJhbSB3aW4gT3B0aW9uYWwgcGFyYW0gdG8gcGFzcyBpbiBtb2NrIHdpbmRvdyBmb3IgdGVzdGluZyBwdXJwb3Nlc1xuICovXG5leHBvcnQgZnVuY3Rpb24gc3RhcnQocHJlYm9vdERhdGE6IFByZWJvb3REYXRhLCB3aW4/OiBQcmVib290V2luZG93KSB7XG4gIGNvbnN0IHRoZVdpbmRvdyA9IDxQcmVib290V2luZG93Pih3aW4gfHwgd2luZG93KTtcbiAgY29uc3QgX2RvY3VtZW50ID0gPERvY3VtZW50Pih0aGVXaW5kb3cuZG9jdW1lbnQgfHwge30pO1xuXG4gIC8vIFJlbW92ZSB0aGUgY3VycmVudCBzY3JpcHQgZnJvbSB0aGUgRE9NIHNvIHRoYXQgY2hpbGQgaW5kZXhlcyBtYXRjaFxuICAvLyBiZXR3ZWVuIHRoZSBjbGllbnQgJiB0aGUgc2VydmVyLiBUaGUgc2NyaXB0IGlzIGFscmVhZHkgcnVubmluZyBzbyBpdFxuICAvLyBkb2Vzbid0IGFmZmVjdCBpdC5cbiAgY29uc3QgY3VycmVudFNjcmlwdCA9IF9kb2N1bWVudC5jdXJyZW50U2NyaXB0IHx8XG4gICAgLy8gU3VwcG9ydDogSUUgOS0xMSBvbmx5XG4gICAgLy8gSUUgZG9lc24ndCBzdXBwb3J0IGRvY3VtZW50LmN1cnJlbnRTY3JpcHQuIFNpbmNlIHRoZSBzY3JpcHQgaXMgaW52b2tlZFxuICAgIC8vIHN5bmNocm9ub3VzbHksIHRob3VnaCwgdGhlIGN1cnJlbnQgcnVubmluZyBzY3JpcHQgaXMganVzdCB0aGUgbGFzdCBvbmVcbiAgICAvLyBjdXJyZW50bHkgaW4gdGhlIGRvY3VtZW50LlxuICAgIFtdLnNsaWNlLmNhbGwoX2RvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzY3JpcHQnKSwgLTEpWzBdO1xuXG4gIGlmICghY3VycmVudFNjcmlwdCkge1xuICAgIGNvbnNvbGUuZXJyb3IoJ1ByZWJvb3QgaW5pdGlhbGl6YXRpb24gZmFpbGVkLCBubyBjdXJyZW50U2NyaXB0IGhhcyBiZWVuIGRldGVjdGVkLicpO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGxldCBzZXJ2ZXJOb2RlID0gY3VycmVudFNjcmlwdC5wYXJlbnROb2RlO1xuICBpZiAoIXNlcnZlck5vZGUpIHtcbiAgICBjb25zb2xlLmVycm9yKCdQcmVib290IGluaXRpYWxpemF0aW9uIGZhaWxlZCwgdGhlIHNjcmlwdCBpcyBkZXRhY2hlZCcpO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIHNlcnZlck5vZGUucmVtb3ZlQ2hpbGQoY3VycmVudFNjcmlwdCk7XG5cbiAgY29uc3Qgb3B0cyA9IHByZWJvb3REYXRhLm9wdHMgfHwgKHt9IGFzIFByZWJvb3RPcHRpb25zKTtcbiAgbGV0IGV2ZW50U2VsZWN0b3JzID0gb3B0cy5ldmVudFNlbGVjdG9ycyB8fCBbXTtcblxuICAvLyBnZXQgdGhlIHJvb3QgaW5mb1xuICBjb25zdCBhcHBSb290ID0gcHJlYm9vdERhdGEub3B0cyA/IGdldEFwcFJvb3QoX2RvY3VtZW50LCBwcmVib290RGF0YS5vcHRzLCBzZXJ2ZXJOb2RlKSA6IG51bGw7XG5cbiAgLy8gd2UgdHJhY2sgYWxsIGV2ZW50cyBmb3IgZWFjaCBhcHAgaW4gdGhlIHByZWJvb3REYXRhIG9iamVjdCB3aGljaCBpcyBvblxuICAvLyB0aGUgZ2xvYmFsIHNjb3BlOyBlYWNoIGBzdGFydGAgaW52b2NhdGlvbiBhZGRzIGRhdGEgZm9yIG9uZSBhcHAgb25seS5cbiAgY29uc3QgYXBwRGF0YSA9IDxQcmVib290QXBwRGF0YT57IHJvb3Q6IGFwcFJvb3QsIGV2ZW50czogW10gfTtcbiAgaWYgKHByZWJvb3REYXRhLmFwcHMpIHtcbiAgICBwcmVib290RGF0YS5hcHBzLnB1c2goYXBwRGF0YSk7XG4gIH1cblxuICBldmVudFNlbGVjdG9ycyA9IGV2ZW50U2VsZWN0b3JzLm1hcChldmVudFNlbGVjdG9yID0+IHtcbiAgICBpZiAoIWV2ZW50U2VsZWN0b3IuaGFzT3duUHJvcGVydHkoJ3JlcGxheScpKSB7XG4gICAgICBldmVudFNlbGVjdG9yLnJlcGxheSA9IHRydWU7XG4gICAgfVxuICAgIHJldHVybiBldmVudFNlbGVjdG9yO1xuICB9KTtcblxuICAvLyBsb29wIHRocm91Z2ggYWxsIHRoZSBldmVudFNlbGVjdG9ycyBhbmQgY3JlYXRlIGV2ZW50IGhhbmRsZXJzXG4gIGV2ZW50U2VsZWN0b3JzLmZvckVhY2goZXZlbnRTZWxlY3RvciA9PlxuICAgIGhhbmRsZUV2ZW50cyhfZG9jdW1lbnQsIHByZWJvb3REYXRhLCBhcHBEYXRhLCBldmVudFNlbGVjdG9yKSk7XG59XG5cbi8qKlxuICogQ3JlYXRlIGFuIG92ZXJsYXkgZGl2IGFuZCBhZGQgaXQgdG8gdGhlIERPTSBzbyBpdCBjYW4gYmUgdXNlZFxuICogaWYgYSBmcmVlemUgZXZlbnQgb2NjdXJzXG4gKlxuICogQHBhcmFtIF9kb2N1bWVudCBUaGUgZ2xvYmFsIGRvY3VtZW50IG9iamVjdCAocGFzc2VkIGluIGZvciB0ZXN0aW5nIHB1cnBvc2VzKVxuICogQHJldHVybnMgRWxlbWVudCBUaGUgb3ZlcmxheSBub2RlIGlzIHJldHVybmVkXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVPdmVybGF5KF9kb2N1bWVudDogRG9jdW1lbnQpOiBIVE1MRWxlbWVudCB8IHVuZGVmaW5lZCB7XG4gIGxldCBvdmVybGF5ID0gX2RvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xuICBvdmVybGF5LnNldEF0dHJpYnV0ZSgnaWQnLCAncHJlYm9vdE92ZXJsYXknKTtcbiAgb3ZlcmxheS5zZXRBdHRyaWJ1dGUoXG4gICAgJ3N0eWxlJyxcbiAgICAnZGlzcGxheTpub25lO3Bvc2l0aW9uOmFic29sdXRlO2xlZnQ6MDsnICtcbiAgICAndG9wOjA7d2lkdGg6MTAwJTtoZWlnaHQ6MTAwJTt6LWluZGV4Ojk5OTk5OTtiYWNrZ3JvdW5kOmJsYWNrO29wYWNpdHk6LjMnXG4gICk7XG4gIF9kb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuYXBwZW5kQ2hpbGQob3ZlcmxheSk7XG5cbiAgcmV0dXJuIG92ZXJsYXk7XG59XG5cbi8qKlxuICogR2V0IHJlZmVyZW5jZXMgdG8gdGhlIGN1cnJlbnQgYXBwIHJvb3Qgbm9kZSBiYXNlZCBvbiBpbnB1dCBvcHRpb25zLiBVc2VycyBjYW5cbiAqIGluaXRpYWxpemUgcHJlYm9vdCBlaXRoZXIgYnkgc3BlY2lmeWluZyBhcHBSb290IHdoaWNoIGlzIGp1c3Qgb25lIG9yIG1vcmVcbiAqIHNlbGVjdG9ycyBmb3IgYXBwcy4gVGhpcyBzZWN0aW9uIG9wdGlvbiBpcyB1c2VmdWwgZm9yIHBlb3BsZSB0aGF0IGFyZSBkb2luZyB0aGVpciBvd25cbiAqIGJ1ZmZlcmluZyAoaS5lLiB0aGV5IGhhdmUgdGhlaXIgb3duIGNsaWVudCBhbmQgc2VydmVyIHZpZXcpXG4gKlxuICogQHBhcmFtIF9kb2N1bWVudCBUaGUgZ2xvYmFsIGRvY3VtZW50IG9iamVjdCB1c2VkIHRvIGF0dGFjaCB0aGUgb3ZlcmxheVxuICogQHBhcmFtIG9wdHMgT3B0aW9ucyBwYXNzZWQgaW4gYnkgdGhlIHVzZXIgdG8gaW5pdCgpXG4gKiBAcGFyYW0gc2VydmVyTm9kZSBUaGUgc2VydmVyIG5vZGUgc2VydmluZyBhcyBhcHBsaWNhdGlvbiByb290XG4gKiBAcmV0dXJucyBTZXJ2ZXJDbGllbnRSb290IEFuIGFycmF5IG9mIHJvb3QgaW5mbyBmb3IgdGhlIGN1cnJlbnQgYXBwXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRBcHBSb290KFxuICBfZG9jdW1lbnQ6IERvY3VtZW50LFxuICBvcHRzOiBQcmVib290T3B0aW9ucyxcbiAgc2VydmVyTm9kZTogSFRNTEVsZW1lbnRcbik6IFNlcnZlckNsaWVudFJvb3Qge1xuICBjb25zdCByb290OiBTZXJ2ZXJDbGllbnRSb290ID0ge3NlcnZlck5vZGV9O1xuXG4gIC8vIGlmIHdlIGFyZSBkb2luZyBidWZmZXJpbmcsIHdlIG5lZWQgdG8gY3JlYXRlIHRoZSBidWZmZXIgZm9yIHRoZSBjbGllbnRcbiAgLy8gZWxzZSB0aGUgY2xpZW50IHJvb3QgaXMgdGhlIHNhbWUgYXMgdGhlIHNlcnZlclxuICByb290LmNsaWVudE5vZGUgPSBvcHRzLmJ1ZmZlciA/IGNyZWF0ZUJ1ZmZlcihyb290KSA6IHJvb3Quc2VydmVyTm9kZTtcblxuICAvLyBjcmVhdGUgYW4gb3ZlcmxheSBpZiBub3QgZGlzYWJsZWQgLHRoYXQgY2FuIGJlIHVzZWQgbGF0ZXIgaWYgYSBmcmVlemUgZXZlbnQgb2NjdXJzXG4gIGlmICghb3B0cy5kaXNhYmxlT3ZlcmxheSkge1xuICAgIHJvb3Qub3ZlcmxheSA9IGNyZWF0ZU92ZXJsYXkoX2RvY3VtZW50KTtcbiAgfVxuXG4gIHJldHVybiByb290O1xufVxuXG4vKipcbiAqIFVuZGVyIGdpdmVuIHNlcnZlciByb290LCBmb3IgZ2l2ZW4gc2VsZWN0b3IsIHJlY29yZCBldmVudHNcbiAqXG4gKiBAcGFyYW0gX2RvY3VtZW50XG4gKiBAcGFyYW0gcHJlYm9vdERhdGFcbiAqIEBwYXJhbSBhcHBEYXRhXG4gKiBAcGFyYW0gZXZlbnRTZWxlY3RvclxuICovXG5leHBvcnQgZnVuY3Rpb24gaGFuZGxlRXZlbnRzKF9kb2N1bWVudDogRG9jdW1lbnQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByZWJvb3REYXRhOiBQcmVib290RGF0YSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXBwRGF0YTogUHJlYm9vdEFwcERhdGEsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50U2VsZWN0b3I6IEV2ZW50U2VsZWN0b3IpIHtcbiAgY29uc3Qgc2VydmVyUm9vdCA9IGFwcERhdGEucm9vdC5zZXJ2ZXJOb2RlO1xuXG4gIC8vIGRvbid0IGRvIGFueXRoaW5nIGlmIG5vIHNlcnZlciByb290XG4gIGlmICghc2VydmVyUm9vdCkge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIC8vIEF0dGFjaCBkZWxlZ2F0ZWQgZXZlbnQgbGlzdGVuZXJzIGZvciBlYWNoIGV2ZW50IHNlbGVjdG9yLlxuICAvLyBXZSBuZWVkIHRvIHVzZSBkZWxlZ2F0ZWQgZXZlbnRzIGFzIG9ubHkgdGhlIHRvcCBsZXZlbCBzZXJ2ZXIgbm9kZVxuICAvLyBleGlzdHMgYXQgdGhpcyBwb2ludC5cbiAgZXZlbnRTZWxlY3Rvci5ldmVudHMuZm9yRWFjaCgoZXZlbnROYW1lOiBzdHJpbmcpID0+IHtcbiAgICAvLyBnZXQgdGhlIGFwcHJvcHJpYXRlIGhhbmRsZXIgYW5kIGFkZCBpdCBhcyBhbiBldmVudCBsaXN0ZW5lclxuICAgIGNvbnN0IGhhbmRsZXIgPSBjcmVhdGVMaXN0ZW5IYW5kbGVyKF9kb2N1bWVudCwgcHJlYm9vdERhdGEsIGV2ZW50U2VsZWN0b3IsIGFwcERhdGEpO1xuICAgIC8vIGF0dGFjaCB0aGUgaGFuZGxlciBpbiB0aGUgY2FwdHVyZSBwaGFzZSBzbyB0aGF0IGl0IGZpcmVzIGV2ZW4gaWZcbiAgICAvLyBvbmUgb2YgdGhlIGhhbmRsZXJzIGJlbG93IGNhbGxzIHN0b3BQcm9wYWdhdGlvbigpXG4gICAgc2VydmVyUm9vdC5hZGRFdmVudExpc3RlbmVyKGV2ZW50TmFtZSwgaGFuZGxlciwgdHJ1ZSk7XG5cbiAgICAvLyBuZWVkIHRvIGtlZXAgdHJhY2sgb2YgbGlzdGVuZXJzIHNvIHdlIGNhbiBkbyBub2RlLnJlbW92ZUV2ZW50TGlzdGVuZXIoKVxuICAgIC8vIHdoZW4gcHJlYm9vdCBkb25lXG4gICAgaWYgKHByZWJvb3REYXRhLmxpc3RlbmVycykge1xuICAgICAgcHJlYm9vdERhdGEubGlzdGVuZXJzLnB1c2goe1xuICAgICAgICBub2RlOiBzZXJ2ZXJSb290LFxuICAgICAgICBldmVudE5hbWUsXG4gICAgICAgIGhhbmRsZXJcbiAgICAgIH0pO1xuICAgIH1cbiAgfSk7XG59XG5cbi8qKlxuICogQ3JlYXRlIGhhbmRsZXIgZm9yIGV2ZW50cyB0aGF0IHdlIHdpbGwgcmVjb3JkXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVMaXN0ZW5IYW5kbGVyKFxuICBfZG9jdW1lbnQ6IERvY3VtZW50LFxuICBwcmVib290RGF0YTogUHJlYm9vdERhdGEsXG4gIGV2ZW50U2VsZWN0b3I6IEV2ZW50U2VsZWN0b3IsXG4gIGFwcERhdGE6IFByZWJvb3RBcHBEYXRhXG4pOiBFdmVudExpc3RlbmVyIHtcbiAgY29uc3QgQ0FSRVRfRVZFTlRTID0gWydrZXl1cCcsICdrZXlkb3duJywgJ2ZvY3VzaW4nLCAnbW91c2V1cCcsICdtb3VzZWRvd24nXTtcbiAgY29uc3QgQ0FSRVRfTk9ERVMgPSBbJ0lOUFVUJywgJ1RFWFRBUkVBJ107XG5cbiAgLy8gU3VwcG9ydDogSUUgOS0xMSBvbmx5XG4gIC8vIElFIHVzZXMgYSBwcmVmaXhlZCBgbWF0Y2hlc2AgdmVyc2lvblxuICBjb25zdCBtYXRjaGVzID0gX2RvY3VtZW50LmRvY3VtZW50RWxlbWVudC5tYXRjaGVzIHx8XG4gICAgKF9kb2N1bWVudC5kb2N1bWVudEVsZW1lbnQgYXMgYW55KS5tc01hdGNoZXNTZWxlY3RvcjtcbiAgY29uc3Qgb3B0cyA9IHByZWJvb3REYXRhLm9wdHM7XG5cbiAgcmV0dXJuIGZ1bmN0aW9uKGV2ZW50OiBEb21FdmVudCkge1xuICAgIGNvbnN0IG5vZGU6IEVsZW1lbnQgPSBldmVudC50YXJnZXQ7XG5cbiAgICAvLyBhIGRlbGVnYXRlZCBoYW5kbGVycyBvbiBkb2N1bWVudCBpcyB1c2VkIHNvIHdlIG5lZWQgdG8gY2hlY2sgaWZcbiAgICAvLyBldmVudCB0YXJnZXQgbWF0Y2hlcyBhIGRlc2lyZWQgc2VsZWN0b3JcbiAgICBpZiAoIW1hdGNoZXMuY2FsbChub2RlLCBldmVudFNlbGVjdG9yLnNlbGVjdG9yKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHJvb3QgPSBhcHBEYXRhLnJvb3Q7XG4gICAgY29uc3QgZXZlbnROYW1lID0gZXZlbnQudHlwZTtcblxuICAgIC8vIGlmIG5vIG5vZGUgb3Igbm8gZXZlbnQgbmFtZSwganVzdCByZXR1cm5cbiAgICBpZiAoIW5vZGUgfHwgIWV2ZW50TmFtZSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIGlmIGtleSBjb2RlcyBzZXQgZm9yIGV2ZW50U2VsZWN0b3IsIHRoZW4gZG9uJ3QgZG8gYW55dGhpbmcgaWYgZXZlbnRcbiAgICAvLyBkb2Vzbid0IGluY2x1ZGUga2V5XG4gICAgY29uc3Qga2V5Q29kZXMgPSBldmVudFNlbGVjdG9yLmtleUNvZGVzO1xuICAgIGlmIChrZXlDb2RlcyAmJiBrZXlDb2Rlcy5sZW5ndGgpIHtcbiAgICAgIGNvbnN0IG1hdGNoaW5nS2V5Q29kZXMgPSBrZXlDb2Rlcy5maWx0ZXIoa2V5Q29kZSA9PiBldmVudC53aGljaCA9PT0ga2V5Q29kZSk7XG5cbiAgICAgIC8vIGlmIHRoZXJlIGFyZSBub3QgbWF0Y2hlcyAoaS5lLiBrZXkgZW50ZXJlZCBOT1Qgb25lIG9mIHRoZSBrZXkgY29kZXMpXG4gICAgICAvLyB0aGVuIGRvbid0IGRvIGFueXRoaW5nXG4gICAgICBpZiAoIW1hdGNoaW5nS2V5Q29kZXMubGVuZ3RoKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBpZiBmb3IgYSBnaXZlbiBzZXQgb2YgZXZlbnRzIHdlIGFyZSBwcmV2ZW50aW5nIGRlZmF1bHQsIGRvIHRoYXRcbiAgICBpZiAoZXZlbnRTZWxlY3Rvci5wcmV2ZW50RGVmYXVsdCkge1xuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICB9XG5cbiAgICAvLyBpZiBhbiBhY3Rpb24gaGFuZGxlciBwYXNzZWQgaW4sIHVzZSB0aGF0XG4gICAgaWYgKGV2ZW50U2VsZWN0b3IuYWN0aW9uKSB7XG4gICAgICBldmVudFNlbGVjdG9yLmFjdGlvbihub2RlLCBldmVudCk7XG4gICAgfVxuXG4gICAgLy8gZ2V0IHRoZSBub2RlIGtleSBmb3IgYSBnaXZlbiBub2RlXG4gICAgY29uc3Qgbm9kZUtleSA9IGdldE5vZGVLZXlGb3JQcmVib290KHsgcm9vdDogcm9vdCwgbm9kZTogbm9kZSB9KTtcblxuICAgIC8vIHJlY29yZCBhY3RpdmUgbm9kZVxuICAgIGlmIChDQVJFVF9FVkVOVFMuaW5kZXhPZihldmVudE5hbWUpID49IDApIHtcbiAgICAgIC8vIGlmIGl0J3MgYW4gY2FyZXQgbm9kZSwgZ2V0IHRoZSBzZWxlY3Rpb24gZm9yIHRoZSBhY3RpdmUgbm9kZVxuICAgICAgY29uc3QgaXNDYXJldE5vZGUgPSBDQVJFVF9OT0RFUy5pbmRleE9mKG5vZGUudGFnTmFtZSA/IG5vZGUudGFnTmFtZSA6ICcnKSA+PSAwO1xuXG4gICAgICBwcmVib290RGF0YS5hY3RpdmVOb2RlID0ge1xuICAgICAgICByb290OiByb290LFxuICAgICAgICBub2RlOiBub2RlLFxuICAgICAgICBub2RlS2V5OiBub2RlS2V5LFxuICAgICAgICBzZWxlY3Rpb246IGlzQ2FyZXROb2RlID8gZ2V0U2VsZWN0aW9uKG5vZGUgYXMgSFRNTElucHV0RWxlbWVudCkgOiB1bmRlZmluZWRcbiAgICAgIH07XG4gICAgfSBlbHNlIGlmIChldmVudE5hbWUgIT09ICdjaGFuZ2UnICYmIGV2ZW50TmFtZSAhPT0gJ2ZvY3Vzb3V0Jykge1xuICAgICAgcHJlYm9vdERhdGEuYWN0aXZlTm9kZSA9IHVuZGVmaW5lZDtcbiAgICB9XG5cbiAgICAvLyBpZiBvdmVybGF5IGlzIG5vdCBkaXNhYmxlZCBhbmQgd2UgYXJlIGZyZWV6aW5nIHRoZSBVSVxuICAgIGlmIChvcHRzICYmICFvcHRzLmRpc2FibGVPdmVybGF5ICYmIGV2ZW50U2VsZWN0b3IuZnJlZXplKSB7XG4gICAgICBjb25zdCBvdmVybGF5ID0gcm9vdC5vdmVybGF5IGFzIEhUTUxFbGVtZW50O1xuXG4gICAgICAvLyBzaG93IHRoZSBvdmVybGF5XG4gICAgICBvdmVybGF5LnN0eWxlLmRpc3BsYXkgPSAnYmxvY2snO1xuXG4gICAgICAvLyBoaWRlIHRoZSBvdmVybGF5IGFmdGVyIDEwIHNlY29uZHMganVzdCBpbiBjYXNlIHByZWJvb3QuY29tcGxldGUoKSBuZXZlclxuICAgICAgLy8gY2FsbGVkXG4gICAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgb3ZlcmxheS5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xuICAgICAgfSwgMTAwMDApO1xuICAgIH1cblxuICAgIC8vIHdlIHdpbGwgcmVjb3JkIGV2ZW50cyBmb3IgbGF0ZXIgcmVwbGF5IHVubGVzcyBleHBsaWNpdGx5IG1hcmtlZCBhc1xuICAgIC8vIGRvTm90UmVwbGF5XG4gICAgaWYgKGV2ZW50U2VsZWN0b3IucmVwbGF5KSB7XG4gICAgICBhcHBEYXRhLmV2ZW50cy5wdXNoKHtcbiAgICAgICAgbm9kZSxcbiAgICAgICAgbm9kZUtleSxcbiAgICAgICAgZXZlbnQsXG4gICAgICAgIG5hbWU6IGV2ZW50TmFtZVxuICAgICAgfSk7XG4gICAgfVxuICB9O1xufVxuXG4vKipcbiAqIEdldCB0aGUgc2VsZWN0aW9uIGRhdGEgdGhhdCBpcyBsYXRlciB1c2VkIHRvIHNldCB0aGUgY3Vyc29yIGFmdGVyIGNsaWVudCB2aWV3XG4gKiBpcyBhY3RpdmVcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFNlbGVjdGlvbihub2RlOiBIVE1MSW5wdXRFbGVtZW50KTogUHJlYm9vdFNlbGVjdGlvbiB7XG4gIG5vZGUgPSBub2RlIHx8IHt9IGFzIEhUTUxJbnB1dEVsZW1lbnQ7XG5cbiAgY29uc3Qgbm9kZVZhbHVlID0gbm9kZS52YWx1ZSB8fCAnJztcbiAgY29uc3Qgc2VsZWN0aW9uOiBQcmVib290U2VsZWN0aW9uID0ge1xuICAgIHN0YXJ0OiBub2RlVmFsdWUubGVuZ3RoLFxuICAgIGVuZDogbm9kZVZhbHVlLmxlbmd0aCxcbiAgICBkaXJlY3Rpb246ICdmb3J3YXJkJ1xuICB9O1xuXG4gIC8vIGlmIGJyb3dzZXIgc3VwcG9ydCBzZWxlY3Rpb25TdGFydCBvbiBub2RlIChDaHJvbWUsIEZpcmVGb3gsIElFOSspXG4gIHRyeSB7XG4gICAgaWYgKG5vZGUuc2VsZWN0aW9uU3RhcnQgfHwgbm9kZS5zZWxlY3Rpb25TdGFydCA9PT0gMCkge1xuICAgICAgc2VsZWN0aW9uLnN0YXJ0ID0gbm9kZS5zZWxlY3Rpb25TdGFydDtcbiAgICAgIHNlbGVjdGlvbi5lbmQgPSBub2RlLnNlbGVjdGlvbkVuZCA/IG5vZGUuc2VsZWN0aW9uRW5kIDogMDtcbiAgICAgIHNlbGVjdGlvbi5kaXJlY3Rpb24gPSBub2RlLnNlbGVjdGlvbkRpcmVjdGlvbiA/XG4gICAgICAgIG5vZGUuc2VsZWN0aW9uRGlyZWN0aW9uIGFzIFByZWJvb3RTZWxlY3Rpb25EaXJlY3Rpb24gOiAnbm9uZSc7XG4gICAgfVxuICB9IGNhdGNoIChleCkge31cblxuICByZXR1cm4gc2VsZWN0aW9uO1xufVxuXG4vKipcbiAqIENyZWF0ZSBidWZmZXIgZm9yIGEgZ2l2ZW4gbm9kZVxuICpcbiAqIEBwYXJhbSByb290IEFsbCB0aGUgZGF0YSByZWxhdGVkIHRvIGEgcGFydGljdWxhciBhcHBcbiAqIEByZXR1cm5zIFJldHVybnMgdGhlIHJvb3QgY2xpZW50IG5vZGUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVCdWZmZXIocm9vdDogU2VydmVyQ2xpZW50Um9vdCk6IEhUTUxFbGVtZW50IHtcbiAgY29uc3Qgc2VydmVyTm9kZSA9IHJvb3Quc2VydmVyTm9kZTtcblxuICAvLyBpZiBubyByb290U2VydmVyTm9kZSBPUiB0aGUgc2VsZWN0b3IgaXMgb24gdGhlIGVudGlyZSBodG1sIGRvYyBvciB0aGUgYm9keVxuICAvLyBPUiBubyBwYXJlbnROb2RlLCBkb24ndCBidWZmZXJcbiAgaWYgKCFzZXJ2ZXJOb2RlIHx8ICFzZXJ2ZXJOb2RlLnBhcmVudE5vZGUgfHxcbiAgICBzZXJ2ZXJOb2RlID09PSBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQgfHwgc2VydmVyTm9kZSA9PT0gZG9jdW1lbnQuYm9keSkge1xuICAgIHJldHVybiBzZXJ2ZXJOb2RlIGFzIEhUTUxFbGVtZW50O1xuICB9XG5cbiAgLy8gY3JlYXRlIHNoYWxsb3cgY2xvbmUgb2Ygc2VydmVyIHJvb3RcbiAgY29uc3Qgcm9vdENsaWVudE5vZGUgPSBzZXJ2ZXJOb2RlLmNsb25lTm9kZShmYWxzZSkgYXMgSFRNTEVsZW1lbnQ7XG4gIC8vIHdlIHdhbnQgdGhlIGNsaWVudCB0byB3cml0ZSB0byBhIGhpZGRlbiBkaXYgdW50aWwgdGhlIHRpbWUgZm9yIHN3aXRjaGluZ1xuICAvLyB0aGUgYnVmZmVyc1xuICByb290Q2xpZW50Tm9kZS5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xuXG4gIC8vIGluc2VydCB0aGUgY2xpZW50IG5vZGUgYmVmb3JlIHRoZSBzZXJ2ZXIgYW5kIHJldHVybiBpdFxuICBzZXJ2ZXJOb2RlLnBhcmVudE5vZGUuaW5zZXJ0QmVmb3JlKHJvb3RDbGllbnROb2RlLCBzZXJ2ZXJOb2RlKTtcblxuICAvLyBtYXJrIHNlcnZlciBub2RlIGFzIG5vdCB0byBiZSB0b3VjaGVkIGJ5IEFuZ3VsYXJKUyAtIG5lZWRlZCBmb3IgbmdVcGdyYWRlXG4gIHNlcnZlck5vZGUuc2V0QXR0cmlidXRlKCduZy1ub24tYmluZGFibGUnLCAnJyk7XG5cbiAgLy8gcmV0dXJuIHRoZSByb290Q2xpZW50Tm9kZVxuICByZXR1cm4gcm9vdENsaWVudE5vZGU7XG59XG4iXX0= |
\ | No newline at end of file |