1 | ;
|
2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
4 | return new (P || (P = Promise))(function (resolve, reject) {
|
5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
8 | step((generator = generator.apply(thisArg, _arguments || [])).next());
|
9 | });
|
10 | };
|
11 | Object.defineProperty(exports, "__esModule", { value: true });
|
12 | exports.TextEditorSyncAdapter = void 0;
|
13 | const convert_1 = require("../convert");
|
14 | const languageclient_1 = require("../languageclient");
|
15 | const apply_edit_adapter_1 = require("./apply-edit-adapter");
|
16 | const atom_1 = require("atom");
|
17 | const Utils = require("../utils");
|
18 | /**
|
19 | * Public: Synchronizes the documents between Atom and the language server by notifying each end of changes, opening,
|
20 | * closing and other events as well as sending and applying changes either in whole or in part depending on what the
|
21 | * language server supports.
|
22 | */
|
23 | class DocumentSyncAdapter {
|
24 | /**
|
25 | * Public: Create a new {DocumentSyncAdapter} for the given language server.
|
26 | *
|
27 | * @param _connection A {LanguageClientConnection} to the language server to be kept in sync.
|
28 | * @param documentSync The document syncing options.
|
29 | * @param _editorSelector A predicate function that takes a {TextEditor} and returns a {boolean} indicating whether
|
30 | * this adapter should care about the contents of the editor.
|
31 | * @param _getLanguageIdFromEditor A function that returns a {string} of `languageId` used for `textDocument/didOpen`
|
32 | * notification.
|
33 | */
|
34 | constructor(_connection, _editorSelector, documentSync, _reportBusyWhile, _getLanguageIdFromEditor) {
|
35 | this._connection = _connection;
|
36 | this._editorSelector = _editorSelector;
|
37 | this._reportBusyWhile = _reportBusyWhile;
|
38 | this._getLanguageIdFromEditor = _getLanguageIdFromEditor;
|
39 | this._disposable = new atom_1.CompositeDisposable();
|
40 | this._editors = new WeakMap();
|
41 | this._versions = new Map();
|
42 | if (typeof documentSync === "object") {
|
43 | this._documentSync = documentSync;
|
44 | }
|
45 | else {
|
46 | this._documentSync = {
|
47 | change: documentSync || languageclient_1.TextDocumentSyncKind.Full,
|
48 | };
|
49 | }
|
50 | this._disposable.add(atom.textEditors.observe(this.observeTextEditor.bind(this)));
|
51 | }
|
52 | /**
|
53 | * Public: Determine whether this adapter can be used to adapt a language server based on the serverCapabilities
|
54 | * matrix textDocumentSync capability either being Full or Incremental.
|
55 | *
|
56 | * @param serverCapabilities The {ServerCapabilities} of the language server to consider.
|
57 | * @returns A {Boolean} indicating adapter can adapt the server based on the given serverCapabilities.
|
58 | */
|
59 | static canAdapt(serverCapabilities) {
|
60 | return this.canAdaptV2(serverCapabilities) || this.canAdaptV3(serverCapabilities);
|
61 | }
|
62 | static canAdaptV2(serverCapabilities) {
|
63 | return (serverCapabilities.textDocumentSync === languageclient_1.TextDocumentSyncKind.Incremental ||
|
64 | serverCapabilities.textDocumentSync === languageclient_1.TextDocumentSyncKind.Full);
|
65 | }
|
66 | static canAdaptV3(serverCapabilities) {
|
67 | const options = serverCapabilities.textDocumentSync;
|
68 | return (options !== null &&
|
69 | typeof options === "object" &&
|
70 | (options.change === languageclient_1.TextDocumentSyncKind.Incremental || options.change === languageclient_1.TextDocumentSyncKind.Full));
|
71 | }
|
72 | /** Dispose this adapter ensuring any resources are freed and events unhooked. */
|
73 | dispose() {
|
74 | this._disposable.dispose();
|
75 | }
|
76 | /**
|
77 | * Examine a {TextEditor} and decide if we wish to observe it. If so ensure that we stop observing it when it is
|
78 | * closed or otherwise destroyed.
|
79 | *
|
80 | * @param editor A {TextEditor} to consider for observation.
|
81 | */
|
82 | observeTextEditor(editor) {
|
83 | const listener = editor.observeGrammar((_grammar) => this._handleGrammarChange(editor));
|
84 | this._disposable.add(editor.onDidDestroy(() => {
|
85 | this._disposable.remove(listener);
|
86 | listener.dispose();
|
87 | }));
|
88 | this._disposable.add(listener);
|
89 | if (!this._editors.has(editor) && this._editorSelector(editor)) {
|
90 | this._handleNewEditor(editor);
|
91 | }
|
92 | }
|
93 | _handleGrammarChange(editor) {
|
94 | const sync = this._editors.get(editor);
|
95 | if (sync != null && !this._editorSelector(editor)) {
|
96 | this._editors.delete(editor);
|
97 | this._disposable.remove(sync);
|
98 | sync.didClose();
|
99 | sync.dispose();
|
100 | }
|
101 | else if (sync == null && this._editorSelector(editor)) {
|
102 | this._handleNewEditor(editor);
|
103 | }
|
104 | }
|
105 | _handleNewEditor(editor) {
|
106 | const sync = new TextEditorSyncAdapter(editor, this._connection, this._documentSync, this._versions, this._reportBusyWhile, this._getLanguageIdFromEditor);
|
107 | this._editors.set(editor, sync);
|
108 | this._disposable.add(sync);
|
109 | this._disposable.add(editor.onDidDestroy(() => {
|
110 | const destroyedSync = this._editors.get(editor);
|
111 | if (destroyedSync) {
|
112 | this._editors.delete(editor);
|
113 | this._disposable.remove(destroyedSync);
|
114 | destroyedSync.dispose();
|
115 | }
|
116 | }));
|
117 | }
|
118 | getEditorSyncAdapter(editor) {
|
119 | return this._editors.get(editor);
|
120 | }
|
121 | }
|
122 | exports.default = DocumentSyncAdapter;
|
123 | /** Public: Keep a single {TextEditor} in sync with a given language server. */
|
124 | class TextEditorSyncAdapter {
|
125 | /**
|
126 | * Public: Create a {TextEditorSyncAdapter} in sync with a given language server.
|
127 | *
|
128 | * @param _editor A {TextEditor} to keep in sync.
|
129 | * @param _connection A {LanguageClientConnection} to a language server to keep in sync.
|
130 | * @param _documentSync The document syncing options.
|
131 | */
|
132 | constructor(_editor, _connection, _documentSync, _versions, _reportBusyWhile, _getLanguageIdFromEditor) {
|
133 | this._editor = _editor;
|
134 | this._connection = _connection;
|
135 | this._documentSync = _documentSync;
|
136 | this._versions = _versions;
|
137 | this._reportBusyWhile = _reportBusyWhile;
|
138 | this._getLanguageIdFromEditor = _getLanguageIdFromEditor;
|
139 | this._disposable = new atom_1.CompositeDisposable();
|
140 | this._fakeDidChangeWatchedFiles = atom.project.onDidChangeFiles == null;
|
141 | const changeTracking = this.setupChangeTracking(_documentSync);
|
142 | if (changeTracking != null) {
|
143 | this._disposable.add(changeTracking);
|
144 | }
|
145 | // These handlers are attached only if server supports them
|
146 | if (_documentSync.willSave) {
|
147 | this._disposable.add(_editor.getBuffer().onWillSave(this.willSave.bind(this)));
|
148 | }
|
149 | if (_documentSync.willSaveWaitUntil) {
|
150 | this._disposable.add(_editor.getBuffer().onWillSave(this.willSaveWaitUntil.bind(this)));
|
151 | }
|
152 | // Send close notifications unless it's explicitly disabled
|
153 | if (_documentSync.openClose !== false) {
|
154 | this._disposable.add(_editor.onDidDestroy(this.didClose.bind(this)));
|
155 | }
|
156 | this._disposable.add(_editor.onDidSave(this.didSave.bind(this)), _editor.onDidChangePath(this.didRename.bind(this)));
|
157 | this._currentUri = this.getEditorUri();
|
158 | if (_documentSync.openClose !== false) {
|
159 | this.didOpen();
|
160 | }
|
161 | }
|
162 | /** The change tracking disposable listener that will ensure that changes are sent to the language server as appropriate. */
|
163 | setupChangeTracking(documentSync) {
|
164 | switch (documentSync.change) {
|
165 | case languageclient_1.TextDocumentSyncKind.Full:
|
166 | return this._editor.onDidChange(this.sendFullChanges.bind(this));
|
167 | case languageclient_1.TextDocumentSyncKind.Incremental:
|
168 | return this._editor.getBuffer().onDidChangeText(this.sendIncrementalChanges.bind(this));
|
169 | }
|
170 | return null;
|
171 | }
|
172 | /** Dispose this adapter ensuring any resources are freed and events unhooked. */
|
173 | dispose() {
|
174 | this._disposable.dispose();
|
175 | }
|
176 | /** Get the languageId field that will be sent to the language server by simply using the `_getLanguageIdFromEditor`. */
|
177 | getLanguageId() {
|
178 | return this._getLanguageIdFromEditor(this._editor);
|
179 | }
|
180 | /**
|
181 | * Public: Create a {VersionedTextDocumentIdentifier} for the document observed by this adapter including both the Uri
|
182 | * and the current Version.
|
183 | */
|
184 | getVersionedTextDocumentIdentifier() {
|
185 | return {
|
186 | uri: this.getEditorUri(),
|
187 | version: this._getVersion(this._editor.getPath() || ""),
|
188 | };
|
189 | }
|
190 | /** Public: Send the entire document to the language server. This is used when operating in Full (1) sync mode. */
|
191 | sendFullChanges() {
|
192 | if (!this._isPrimaryAdapter()) {
|
193 | return;
|
194 | } // Multiple editors, we are not first
|
195 | this._bumpVersion();
|
196 | this._connection.didChangeTextDocument({
|
197 | textDocument: this.getVersionedTextDocumentIdentifier(),
|
198 | contentChanges: [{ text: this._editor.getText() }],
|
199 | });
|
200 | }
|
201 | /**
|
202 | * Public: Send the incremental text changes to the language server. This is used when operating in Incremental (2) sync mode.
|
203 | *
|
204 | * @param event The event fired by Atom to indicate the document has stopped changing including a list of changes
|
205 | * since the last time this event fired for this text editor. NOTE: The order of changes in the event is guaranteed
|
206 | * top to bottom. Language server expects this in reverse.
|
207 | */
|
208 | sendIncrementalChanges(event) {
|
209 | if (event.changes.length > 0) {
|
210 | if (!this._isPrimaryAdapter()) {
|
211 | return;
|
212 | } // Multiple editors, we are not first
|
213 | this._bumpVersion();
|
214 | this._connection.didChangeTextDocument({
|
215 | textDocument: this.getVersionedTextDocumentIdentifier(),
|
216 | contentChanges: event.changes.map(TextEditorSyncAdapter.textEditToContentChange).reverse(),
|
217 | });
|
218 | }
|
219 | }
|
220 | /**
|
221 | * Public: Convert an Atom {TextEditEvent} to a language server {TextDocumentContentChangeEvent} object.
|
222 | *
|
223 | * @param change The Atom {TextEditEvent} to convert.
|
224 | * @returns A {TextDocumentContentChangeEvent} that represents the converted {TextEditEvent}.
|
225 | */
|
226 | static textEditToContentChange(change) {
|
227 | return {
|
228 | range: convert_1.default.atomRangeToLSRange(change.oldRange),
|
229 | rangeLength: change.oldText.length,
|
230 | text: change.newText,
|
231 | };
|
232 | }
|
233 | _isPrimaryAdapter() {
|
234 | const lowestIdForBuffer = Math.min(...atom.workspace
|
235 | .getTextEditors()
|
236 | .filter((t) => t.getBuffer() === this._editor.getBuffer())
|
237 | .map((t) => t.id));
|
238 | return lowestIdForBuffer === this._editor.id;
|
239 | }
|
240 | _bumpVersion() {
|
241 | const filePath = this._editor.getPath();
|
242 | if (filePath == null) {
|
243 | return;
|
244 | }
|
245 | this._versions.set(filePath, this._getVersion(filePath) + 1);
|
246 | }
|
247 | /**
|
248 | * Ensure when the document is opened we send notification to the language server so it can load it in and keep track
|
249 | * of diagnostics etc.
|
250 | */
|
251 | didOpen() {
|
252 | const filePath = this._editor.getPath();
|
253 | if (filePath == null) {
|
254 | return;
|
255 | } // Not yet saved
|
256 | if (!this._isPrimaryAdapter()) {
|
257 | return;
|
258 | } // Multiple editors, we are not first
|
259 | this._connection.didOpenTextDocument({
|
260 | textDocument: {
|
261 | uri: this.getEditorUri(),
|
262 | languageId: this.getLanguageId().toLowerCase(),
|
263 | version: this._getVersion(filePath),
|
264 | text: this._editor.getText(),
|
265 | },
|
266 | });
|
267 | }
|
268 | _getVersion(filePath) {
|
269 | return this._versions.get(filePath) || 1;
|
270 | }
|
271 | /** Called when the {TextEditor} is closed and sends the 'didCloseTextDocument' notification to the connected language server. */
|
272 | didClose() {
|
273 | if (this._editor.getPath() == null) {
|
274 | return;
|
275 | } // Not yet saved
|
276 | const fileStillOpen = atom.workspace.getTextEditors().find((t) => t.getBuffer() === this._editor.getBuffer());
|
277 | if (fileStillOpen) {
|
278 | return; // Other windows or editors still have this file open
|
279 | }
|
280 | this._connection.didCloseTextDocument({ textDocument: { uri: this.getEditorUri() } });
|
281 | }
|
282 | /** Called just before the {TextEditor} saves and sends the 'willSaveTextDocument' notification to the connected language server. */
|
283 | willSave() {
|
284 | if (!this._isPrimaryAdapter()) {
|
285 | return;
|
286 | }
|
287 | const uri = this.getEditorUri();
|
288 | this._connection.willSaveTextDocument({
|
289 | textDocument: { uri },
|
290 | reason: languageclient_1.TextDocumentSaveReason.Manual,
|
291 | });
|
292 | }
|
293 | /**
|
294 | * Called just before the {TextEditor} saves, sends the 'willSaveWaitUntilTextDocument' request to the connected
|
295 | * language server and waits for the response before saving the buffer.
|
296 | */
|
297 | willSaveWaitUntil() {
|
298 | return __awaiter(this, void 0, void 0, function* () {
|
299 | if (!this._isPrimaryAdapter()) {
|
300 | return Promise.resolve();
|
301 | }
|
302 | const buffer = this._editor.getBuffer();
|
303 | const uri = this.getEditorUri();
|
304 | const title = this._editor.getLongTitle();
|
305 | const applyEditsOrTimeout = Utils.promiseWithTimeout(2500, // 2.5 seconds timeout
|
306 | this._connection.willSaveWaitUntilTextDocument({
|
307 | textDocument: { uri },
|
308 | reason: languageclient_1.TextDocumentSaveReason.Manual,
|
309 | }))
|
310 | .then((edits) => {
|
311 | const cursor = this._editor.getCursorBufferPosition();
|
312 | apply_edit_adapter_1.default.applyEdits(buffer, convert_1.default.convertLsTextEdits(edits));
|
313 | this._editor.setCursorBufferPosition(cursor);
|
314 | })
|
315 | .catch((err) => {
|
316 | atom.notifications.addError("On-save action failed", {
|
317 | description: `Failed to apply edits to ${title}`,
|
318 | detail: err.message,
|
319 | });
|
320 | return;
|
321 | });
|
322 | const withBusySignal = this._reportBusyWhile(`Applying on-save edits for ${title}`, () => applyEditsOrTimeout);
|
323 | return withBusySignal || applyEditsOrTimeout;
|
324 | });
|
325 | }
|
326 | /**
|
327 | * Called when the {TextEditor} saves and sends the 'didSaveTextDocument' notification to the connected language
|
328 | * server. Note: Right now this also sends the `didChangeWatchedFiles` notification as well but that will be sent from
|
329 | * elsewhere soon.
|
330 | */
|
331 | didSave() {
|
332 | if (!this._isPrimaryAdapter()) {
|
333 | return;
|
334 | }
|
335 | const uri = this.getEditorUri();
|
336 | const didSaveNotification = {
|
337 | textDocument: { uri, version: this._getVersion(uri) },
|
338 | };
|
339 | if (typeof this._documentSync.save === "object" && this._documentSync.save.includeText) {
|
340 | didSaveNotification.text = this._editor.getText();
|
341 | }
|
342 | this._connection.didSaveTextDocument(didSaveNotification);
|
343 | if (this._fakeDidChangeWatchedFiles) {
|
344 | this._connection.didChangeWatchedFiles({
|
345 | changes: [{ uri, type: languageclient_1.FileChangeType.Changed }],
|
346 | });
|
347 | }
|
348 | }
|
349 | didRename() {
|
350 | if (!this._isPrimaryAdapter()) {
|
351 | return;
|
352 | }
|
353 | const oldUri = this._currentUri;
|
354 | this._currentUri = this.getEditorUri();
|
355 | if (!oldUri) {
|
356 | return; // Didn't previously have a name
|
357 | }
|
358 | if (this._documentSync.openClose !== false) {
|
359 | this._connection.didCloseTextDocument({ textDocument: { uri: oldUri } });
|
360 | }
|
361 | if (this._fakeDidChangeWatchedFiles) {
|
362 | this._connection.didChangeWatchedFiles({
|
363 | changes: [
|
364 | { uri: oldUri, type: languageclient_1.FileChangeType.Deleted },
|
365 | { uri: this._currentUri, type: languageclient_1.FileChangeType.Created },
|
366 | ],
|
367 | });
|
368 | }
|
369 | // Send an equivalent open event for this editor, which will now use the new
|
370 | // file path.
|
371 | if (this._documentSync.openClose !== false) {
|
372 | this.didOpen();
|
373 | }
|
374 | }
|
375 | /** Public: Obtain the current {TextEditor} path and convert it to a Uri. */
|
376 | getEditorUri() {
|
377 | return convert_1.default.pathToUri(this._editor.getPath() || "");
|
378 | }
|
379 | }
|
380 | exports.TextEditorSyncAdapter = TextEditorSyncAdapter;
|
381 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZG9jdW1lbnQtc3luYy1hZGFwdGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vbGliL2FkYXB0ZXJzL2RvY3VtZW50LXN5bmMtYWRhcHRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7QUFBQSx3Q0FBZ0M7QUFDaEMsc0RBVTBCO0FBQzFCLDZEQUFtRDtBQUNuRCwrQkFBMEc7QUFDMUcsa0NBQWlDO0FBRWpDOzs7O0dBSUc7QUFDSCxNQUFxQixtQkFBbUI7SUFpQ3RDOzs7Ozs7Ozs7T0FTRztJQUNILFlBQ1UsV0FBcUMsRUFDckMsZUFBZ0QsRUFDeEQsWUFBd0UsRUFDaEUsZ0JBQXVDLEVBQ3ZDLHdCQUF3RDtRQUp4RCxnQkFBVyxHQUFYLFdBQVcsQ0FBMEI7UUFDckMsb0JBQWUsR0FBZixlQUFlLENBQWlDO1FBRWhELHFCQUFnQixHQUFoQixnQkFBZ0IsQ0FBdUI7UUFDdkMsNkJBQXdCLEdBQXhCLHdCQUF3QixDQUFnQztRQS9DMUQsZ0JBQVcsR0FBRyxJQUFJLDBCQUFtQixFQUFFLENBQUE7UUFFdkMsYUFBUSxHQUErQyxJQUFJLE9BQU8sRUFBRSxDQUFBO1FBQ3BFLGNBQVMsR0FBd0IsSUFBSSxHQUFHLEVBQUUsQ0FBQTtRQThDaEQsSUFBSSxPQUFPLFlBQVksS0FBSyxRQUFRLEVBQUU7WUFDcEMsSUFBSSxDQUFDLGFBQWEsR0FBRyxZQUFZLENBQUE7U0FDbEM7YUFBTTtZQUNMLElBQUksQ0FBQyxhQUFhLEdBQUc7Z0JBQ25CLE1BQU0sRUFBRSxZQUFZLElBQUkscUNBQW9CLENBQUMsSUFBSTthQUNsRCxDQUFBO1NBQ0Y7UUFDRCxJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQTtJQUNuRixDQUFDO0lBcEREOzs7Ozs7T0FNRztJQUNJLE1B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QUFhLENBQUMsU0FBUyxLQUFLLEtBQUssRUFBRTtZQUMxQyxJQUFJLENBQUMsV0FBVyxDQUFDLG9CQUFvQixDQUFDLEVBQUUsWUFBWSxFQUFFLEVBQUUsR0FBRyxFQUFFLE1BQU0sRUFBRSxFQUFFLENBQUMsQ0FBQTtTQUN6RTtRQUVELElBQUksSUFBSSxDQUFDLDBCQUEwQixFQUFFO1lBQ25DLElBQUksQ0FBQyxXQUFXLENBQUMscUJBQXFCLENBQUM7Z0JBQ3JDLE9BQU8sRUFBRTtvQkFDUCxFQUFFLEdBQUcsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLCtCQUFjLENBQUMsT0FBTyxFQUFFO29CQUM3QyxFQUFFLEdBQUcsRUFBRSxJQUFJLENBQUMsV0FBVyxFQUFFLElBQUksRUFBRSwrQkFBYyxDQUFDLE9BQU8sRUFBRTtpQkFDeEQ7YUFDRixDQUFDLENBQUE7U0FDSDtRQUVELDRFQUE0RTtRQUM1RSxhQUFhO1FBQ2IsSUFBSSxJQUFJLENBQUMsYUFBYSxDQUFDLFNBQVMsS0FBSyxLQUFLLEVBQUU7WUFDMUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFBO1NBQ2Y7SUFDSCxDQUFDO0lBRUQsNEVBQTRFO0lBQ3JFLFlBQVk7UUFDakIsT0FBTyxpQkFBTyxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFBO0lBQ3hELENBQUM7Q0FDRjtBQXpTRCxzREF5U0MiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgQ29udmVydCBmcm9tIFwiLi4vY29udmVydFwiXG5pbXBvcnQge1xuICBMYW5ndWFnZUNsaWVudENvbm5lY3Rpb24sXG4gIEZpbGVDaGFuZ2VUeXBlLFxuICBUZXh0RG9jdW1lbnRTYXZlUmVhc29uLFxuICBUZXh0RG9jdW1lbnRTeW5jS2luZCxcbiAgVGV4dERvY3VtZW50U3luY09wdGlvbnMsXG4gIFRleHREb2N1bWVudENvbnRlbnRDaGFuZ2VFdmVudCxcbiAgVmVyc2lvbmVkVGV4dERvY3VtZW50SWRlbnRpZmllcixcbiAgU2VydmVyQ2FwYWJpbGl0aWVzLFxuICBEaWRTYXZlVGV4dERvY3VtZW50UGFyYW1zLFxufSBmcm9tIFwiLi4vbGFuZ3VhZ2VjbGllbnRcIlxuaW1wb3J0IEFwcGx5RWRpdEFkYXB0ZXIgZnJvbSBcIi4vYXBwbHktZWRpdC1hZGFwdGVyXCJcbmltcG9ydCB7IENvbXBvc2l0ZURpc3Bvc2FibGUsIERpc3Bvc2FibGUsIFRleHRFZGl0b3IsIEJ1ZmZlclN0b3BwZWRDaGFuZ2luZ0V2ZW50LCBUZXh0Q2hhbmdlIH0gZnJvbSBcImF0b21cIlxuaW1wb3J0ICogYXMgVXRpbHMgZnJvbSBcIi4uL3V0aWxzXCJcblxuLyoqXG4gKiBQdWJsaWM6IFN5bmNocm9uaXplcyB0aGUgZG9jdW1lbnRzIGJldHdlZW4gQXRvbSBhbmQgdGhlIGxhbmd1YWdlIHNlcnZlciBieSBub3RpZnlpbmcgZWFjaCBlbmQgb2YgY2hhbmdlcywgb3BlbmluZyxcbiAqIGNsb3NpbmcgYW5kIG90aGVyIGV2ZW50cyBhcyB3ZWxsIGFzIHNlbmRpbmcgYW5kIGFwcGx5aW5nIGNoYW5nZXMgZWl0aGVyIGluIHdob2xlIG9yIGluIHBhcnQgZGVwZW5kaW5nIG9uIHdoYXQgdGhlXG4gKiBsYW5ndWFnZSBzZXJ2ZXIgc3VwcG9ydHMuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIERvY3VtZW50U3luY0FkYXB0ZXIge1xuICBwcml2YXRlIF9kaXNwb3NhYmxlID0gbmV3IENvbXBvc2l0ZURpc3Bvc2FibGUoKVxuICBwdWJsaWMgX2RvY3VtZW50U3luYzogVGV4dERvY3VtZW50U3luY09wdGlvbnNcbiAgcHJpdmF0ZSBfZWRpdG9yczogV2Vha01hcDxUZXh0RWRpdG9yLCBUZXh0RWRpdG9yU3luY0FkYXB0ZXI+ID0gbmV3IFdlYWtNYXAoKVxuICBwcml2YXRlIF92ZXJzaW9uczogTWFwPHN0cmluZywgbnVtYmVyPiA9IG5ldyBNYXAoKVxuXG4gIC8qKlxuICAgKiBQdWJsaWM6IERldGVybWluZSB3aGV0aGVyIHRoaXMgYWRhcHRlciBjYW4gYmUgdXNlZCB0byBhZGFwdCBhIGxhbmd1YWdlIHNlcnZlciBiYXNlZCBvbiB0aGUgc2VydmVyQ2FwYWJpbGl0aWVzXG4gICAqIG1hdHJpeCB0ZXh0RG9jdW1lbnRTeW5jIGNhcGFiaWxpdHkgZWl0aGVyIGJlaW5nIEZ1bGwgb3IgSW5jcmVtZW50YWwuXG4gICAqXG4gICAqIEBwYXJhbSBzZXJ2ZXJDYXBhYmlsaXRpZXMgVGhlIHtTZXJ2ZXJDYXBhYmlsaXRpZXN9IG9mIHRoZSBsYW5ndWFnZSBzZXJ2ZXIgdG8gY29uc2lkZXIuXG4gICAqIEByZXR1cm5zIEEge0Jvb2xlYW59IGluZGljYXRpbmcgYWRhcHRlciBjYW4gYWRhcHQgdGhlIHNlcnZlciBiYXNlZCBvbiB0aGUgZ2l2ZW4gc2VydmVyQ2FwYWJpbGl0aWVzLlxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBjYW5BZGFwdChzZXJ2ZXJDYXBhYmlsaXRpZXM6IFNlcnZlckNhcGFiaWxpdGllcyk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmNhbkFkYXB0VjIoc2VydmVyQ2FwYWJpbGl0aWVzKSB8fCB0aGlzLmNhbkFkYXB0VjMoc2VydmVyQ2FwYWJpbGl0aWVzKVxuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgY2FuQWRhcHRWMihzZXJ2ZXJDYXBhYmlsaXRpZXM6IFNlcnZlckNhcGFiaWxpdGllcyk6IGJvb2xlYW4ge1xuICAgIHJldHVybiAoXG4gICAgICBzZXJ2ZXJDYXBhYmlsaXRpZXMudGV4dERvY3VtZW50U3luYyA9PT0gVGV4dERvY3VtZW50U3luY0tpbmQuSW5jcmVtZW50YWwgfHxcbiAgICAgIHNlcnZlckNhcGFiaWxpdGllcy50ZXh0RG9jdW1lbnRTeW5jID09PSBUZXh0RG9jdW1lbnRTeW5jS2luZC5GdWxsXG4gICAgKVxuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgY2FuQWRhcHRWMyhzZXJ2ZXJDYXBhYmlsaXRpZXM6IFNlcnZlckNhcGFiaWxpdGllcyk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IG9wdGlvbnMgPSBzZXJ2ZXJDYXBhYmlsaXRpZXMudGV4dERvY3VtZW50U3luY1xuICAgIHJldHVybiAoXG4gICAgICBvcHRpb25zICE9PSBudWxsICYmXG4gICAgICB0eXBlb2Ygb3B0aW9ucyA9PT0gXCJvYmplY3RcIiAmJlxuICAgICAgKG9wdGlvbnMuY2hhbmdlID09PSBUZXh0RG9jdW1lbnRTeW5jS2luZC5JbmNyZW1lbnRhbCB8fCBvcHRpb25zLmNoYW5nZSA9PT0gVGV4dERvY3VtZW50U3luY0tpbmQuRnVsbClcbiAgICApXG4gIH1cblxuICAvKipcbiAgICogUHVibGljOiBDcmVhdGUgYSBuZXcge0RvY3VtZW50U3luY0FkYXB0ZXJ9IGZvciB0aGUgZ2l2ZW4gbGFuZ3VhZ2Ugc2VydmVyLlxuICAgKlxuICAgKiBAcGFyYW0gX2Nvbm5lY3Rpb24gQSB7TGFuZ3VhZ2VDbGllbnRDb25uZWN0aW9ufSB0byB0aGUgbGFuZ3VhZ2Ugc2VydmVyIHRvIGJlIGtlcHQgaW4gc3luYy5cbiAgICogQHBhcmFtIGRvY3VtZW50U3luYyBUaGUgZG9jdW1lbnQgc3luY2luZyBvcHRpb25zLlxuICAgKiBAcGFyYW0gX2VkaXRvclNlbGVjdG9yIEEgcHJlZGljYXRlIGZ1bmN0aW9uIHRoYXQgdGFrZXMgYSB7VGV4dEVkaXRvcn0gYW5kIHJldHVybnMgYSB7Ym9vbGVhbn0gaW5kaWNhdGluZyB3aGV0aGVyXG4gICAqICAgdGhpcyBhZGFwdGVyIHNob3VsZCBjYXJlIGFib3V0IHRoZSBjb250ZW50cyBvZiB0aGUgZWRpdG9yLlxuICAgKiBAcGFyYW0gX2dldExhbmd1YWdlSWRGcm9tRWRpdG9yIEEgZnVuY3Rpb24gdGhhdCByZXR1cm5zIGEge3N0cmluZ30gb2YgYGxhbmd1YWdlSWRgIHVzZWQgZm9yIGB0ZXh0RG9jdW1lbnQvZGlkT3BlbmBcbiAgICogICBub3RpZmljYXRpb24uXG4gICAqL1xuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIF9jb25uZWN0aW9uOiBMYW5ndWFnZUNsaWVudENvbm5lY3Rpb24sXG4gICAgcHJpdmF0ZSBfZWRpdG9yU2VsZWN0b3I6IChlZGl0b3I6IFRleHRFZGl0b3IpID0+IGJvb2xlYW4sXG4gICAgZG9jdW1lbnRTeW5jOiBUZXh0RG9jdW1lbnRTeW5jT3B0aW9ucyB8IFRleHREb2N1bWVudFN5bmNLaW5kIHwgdW5kZWZpbmVkLFxuICAgIHByaXZhdGUgX3JlcG9ydEJ1c3lXaGlsZTogVXRpbHMuUmVwb3J0QnVzeVdoaWxlLFxuICAgIHByaXZhdGUgX2dldExhbmd1YWdlSWRGcm9tRWRpdG9yOiAoZWRpdG9yOiBUZXh0RWRpdG9yKSA9PiBzdHJpbmdcbiAgKSB7XG4gICAgaWYgKHR5cGVvZiBkb2N1bWVudFN5bmMgPT09IFwib2JqZWN0XCIpIHtcbiAgICAgIHRoaXMuX2RvY3VtZW50U3luYyA9IGRvY3VtZW50U3luY1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLl9kb2N1bWVudFN5bmMgPSB7XG4gICAgICAgIGNoYW5nZTogZG9jdW1lbnRTeW5jIHx8IFRleHREb2N1bWVudFN5bmNLaW5kLkZ1bGwsXG4gICAgICB9XG4gICAgfVxuICAgIHRoaXMuX2Rpc3Bvc2FibGUuYWRkKGF0b20udGV4dEVkaXRvcnMub2JzZXJ2ZSh0aGlzLm9ic2VydmVUZXh0RWRpdG9yLmJpbmQodGhpcykpKVxuICB9XG5cbiAgLyoqIERpc3Bvc2UgdGhpcyBhZGFwdGVyIGVuc3VyaW5nIGFueSByZXNvdXJjZXMgYXJlIGZyZWVkIGFuZCBldmVudHMgdW5ob29rZWQuICovXG4gIHB1YmxpYyBkaXNwb3NlKCk6IHZvaWQge1xuICAgIHRoaXMuX2Rpc3Bvc2FibGUuZGlzcG9zZSgpXG4gIH1cblxuICAvKipcbiAgICogRXhhbWluZSBhIHtUZXh0RWRpdG9yfSBhbmQgZGVjaWRlIGlmIHdlIHdpc2ggdG8gb2JzZXJ2ZSBpdC4gSWYgc28gZW5zdXJlIHRoYXQgd2Ugc3RvcCBvYnNlcnZpbmcgaXQgd2hlbiBpdCBpc1xuICAgKiBjbG9zZWQgb3Igb3RoZXJ3aXNlIGRlc3Ryb3llZC5cbiAgICpcbiAgICogQHBhcmFtIGVkaXRvciBBIHtUZXh0RWRpdG9yfSB0byBjb25zaWRlciBmb3Igb2JzZXJ2YXRpb24uXG4gICAqL1xuICBwdWJsaWMgb2JzZXJ2ZVRleHRFZGl0b3IoZWRpdG9yOiBUZXh0RWRpdG9yKTogdm9pZCB7XG4gICAgY29uc3QgbGlzdGVuZXIgPSBlZGl0b3Iub2JzZXJ2ZUdyYW1tYXIoKF9ncmFtbWFyKSA9PiB0aGlzLl9oYW5kbGVHcmFtbWFyQ2hhbmdlKGVkaXRvcikpXG4gICAgdGhpcy5fZGlzcG9zYWJsZS5hZGQoXG4gICAgICBlZGl0b3Iub25EaWREZXN0cm95KCgpID0+IHtcbiAgICAgICAgdGhpcy5fZGlzcG9zYWJsZS5yZW1vdmUobGlzdGVuZXIpXG4gICAgICAgIGxpc3RlbmVyLmRpc3Bvc2UoKVxuICAgICAgfSlcbiAgICApXG4gICAgdGhpcy5fZGlzcG9zYWJsZS5hZGQobGlzdGVuZXIpXG4gICAgaWYgKCF0aGlzLl9lZGl0b3JzLmhhcyhlZGl0b3IpICYmIHRoaXMuX2VkaXRvclNlbGVjdG9yKGVkaXRvcikpIHtcbiAgICAgIHRoaXMuX2hhbmRsZU5ld0VkaXRvcihlZGl0b3IpXG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBfaGFuZGxlR3JhbW1hckNoYW5nZShlZGl0b3I6IFRleHRFZGl0b3IpOiB2b2lkIHtcbiAgICBjb25zdCBzeW5jID0gdGhpcy5fZWRpdG9ycy5nZXQoZWRpdG9yKVxuICAgIGlmIChzeW5jICE9IG51bGwgJiYgIXRoaXMuX2VkaXRvclNlbGVjdG9yKGVkaXRvcikpIHtcbiAgICAgIHRoaXMuX2VkaXRvcnMuZGVsZXRlKGVkaXRvcilcbiAgICAgIHRoaXMuX2Rpc3Bvc2FibGUucmVtb3ZlKHN5bmMpXG4gICAgICBzeW5jLmRpZENsb3NlKClcbiAgICAgIHN5bmMuZGlzcG9zZSgpXG4gICAgfSBlbHNlIGlmIChzeW5jID09IG51bGwgJiYgdGhpcy5fZWRpdG9yU2VsZWN0b3IoZWRpdG9yKSkge1xuICAgICAgdGhpcy5faGFuZGxlTmV3RWRpdG9yKGVkaXRvcilcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIF9oYW5kbGVOZXdFZGl0b3IoZWRpdG9yOiBUZXh0RWRpdG9yKTogdm9pZCB7XG4gICAgY29uc3Qgc3luYyA9IG5ldyBUZXh0RWRpdG9yU3luY0FkYXB0ZXIoXG4gICAgICBlZGl0b3IsXG4gICAgICB0aGlzLl9jb25uZWN0aW9uLFxuICAgICAgdGhpcy5fZG9jdW1lbnRTeW5jLFxuICAgICAgdGhpcy5fdmVyc2lvbnMsXG4gICAgICB0aGlzLl9yZXBvcnRCdXN5V2hpbGUsXG4gICAgICB0aGlzLl9nZXRMYW5ndWFnZUlkRnJvbUVkaXRvclxuICAgIClcbiAgICB0aGlzLl9lZGl0b3JzLnNldChlZGl0b3IsIHN5bmMpXG4gICAgdGhpcy5fZGlzcG9zYWJsZS5hZGQoc3luYylcbiAgICB0aGlzLl9kaXNwb3NhYmxlLmFkZChcbiAgICAgIGVkaXRvci5vbkRpZERlc3Ryb3koKCkgPT4ge1xuICAgICAgICBjb25zdCBkZXN0cm95ZWRTeW5jID0gdGhpcy5fZWRpdG9ycy5nZXQoZWRpdG9yKVxuICAgICAgICBpZiAoZGVzdHJveWVkU3luYykge1xuICAgICAgICAgIHRoaXMuX2VkaXRvcnMuZGVsZXRlKGVkaXRvcilcbiAgICAgICAgICB0aGlzLl9kaXNwb3NhYmxlLnJlbW92ZShkZXN0cm95ZWRTeW5jKVxuICAgICAgICAgIGRlc3Ryb3llZFN5bmMuZGlzcG9zZSgpXG4gICAgICAgIH1cbiAgICAgIH0pXG4gICAgKVxuICB9XG5cbiAgcHVibGljIGdldEVkaXRvclN5bmNBZGFwdGVyKGVkaXRvcjogVGV4dEVkaXRvcik6IFRleHRFZGl0b3JTeW5jQWRhcHRlciB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMuX2VkaXRvcnMuZ2V0KGVkaXRvcilcbiAgfVxufVxuXG4vKiogUHVibGljOiBLZWVwIGEgc2luZ2xlIHtUZXh0RWRpdG9yfSBpbiBzeW5jIHdpdGggYSBnaXZlbiBsYW5ndWFnZSBzZXJ2ZXIuICovXG5leHBvcnQgY2xhc3MgVGV4dEVkaXRvclN5bmNBZGFwdGVyIHtcbiAgcHJpdmF0ZSBfZGlzcG9zYWJsZSA9IG5ldyBDb21wb3NpdGVEaXNwb3NhYmxlKClcbiAgcHJpdmF0ZSBfY3VycmVudFVyaTogc3RyaW5nXG4gIHByaXZhdGUgX2Zha2VEaWRDaGFuZ2VXYXRjaGVkRmlsZXM6IGJvb2xlYW5cblxuICAvKipcbiAgICogUHVibGljOiBDcmVhdGUgYSB7VGV4dEVkaXRvclN5bmNBZGFwdGVyfSBpbiBzeW5jIHdpdGggYSBnaXZlbiBsYW5ndWFnZSBzZXJ2ZXIuXG4gICAqXG4gICAqIEBwYXJhbSBfZWRpdG9yIEEge1RleHRFZGl0b3J9IHRvIGtlZXAgaW4gc3luYy5cbiAgICogQHBhcmFtIF9jb25uZWN0aW9uIEEge0xhbmd1YWdlQ2xpZW50Q29ubmVjdGlvbn0gdG8gYSBsYW5ndWFnZSBzZXJ2ZXIgdG8ga2VlcCBpbiBzeW5jLlxuICAgKiBAcGFyYW0gX2RvY3VtZW50U3luYyBUaGUgZG9jdW1lbnQgc3luY2luZyBvcHRpb25zLlxuICAgKi9cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBfZWRpdG9yOiBUZXh0RWRpdG9yLFxuICAgIHByaXZhdGUgX2Nvbm5lY3Rpb246IExhbmd1YWdlQ2xpZW50Q29ubmVjdGlvbixcbiAgICBwcml2YXRlIF9kb2N1bWVudFN5bmM6IFRleHREb2N1bWVudFN5bmNPcHRpb25zLFxuICAgIHByaXZhdGUgX3ZlcnNpb25zOiBNYXA8c3RyaW5nLCBudW1iZXI+LFxuICAgIHByaXZhdGUgX3JlcG9ydEJ1c3lXaGlsZTogVXRpbHMuUmVwb3J0QnVzeVdoaWxlLFxuICAgIHByaXZhdGUgX2dldExhbmd1YWdlSWRGcm9tRWRpdG9yOiAoZWRpdG9yOiBUZXh0RWRpdG9yKSA9PiBzdHJpbmdcbiAgKSB7XG4gICAgdGhpcy5fZmFrZURpZENoYW5nZVdhdGNoZWRGaWxlcyA9IGF0b20ucHJvamVjdC5vbkRpZENoYW5nZUZpbGVzID09IG51bGxcblxuICAgIGNvbnN0IGNoYW5nZVRyYWNraW5nID0gdGhpcy5zZXR1cENoYW5nZVRyYWNraW5nKF9kb2N1bWVudFN5bmMpXG4gICAgaWYgKGNoYW5nZVRyYWNraW5nICE9IG51bGwpIHtcbiAgICAgIHRoaXMuX2Rpc3Bvc2FibGUuYWRkKGNoYW5nZVRyYWNraW5nKVxuICAgIH1cblxuICAgIC8vIFRoZXNlIGhhbmRsZXJzIGFyZSBhdHRhY2hlZCBvbmx5IGlmIHNlcnZlciBzdXBwb3J0cyB0aGVtXG4gICAgaWYgKF9kb2N1bWVudFN5bmMud2lsbFNhdmUpIHtcbiAgICAgIHRoaXMuX2Rpc3Bvc2FibGUuYWRkKF9lZGl0b3IuZ2V0QnVmZmVyKCkub25XaWxsU2F2ZSh0aGlzLndpbGxTYXZlLmJpbmQodGhpcykpKVxuICAgIH1cbiAgICBpZiAoX2RvY3VtZW50U3luYy53aWxsU2F2ZVdhaXRVbnRpbCkge1xuICAgICAgdGhpcy5fZGlzcG9zYWJsZS5hZGQoX2VkaXRvci5nZXRCdWZmZXIoKS5vbldpbGxTYXZlKHRoaXMud2lsbFNhdmVXYWl0VW50aWwuYmluZCh0aGlzKSkpXG4gICAgfVxuICAgIC8vIFNlbmQgY2xvc2Ugbm90aWZpY2F0aW9ucyB1bmxlc3MgaXQncyBleHBsaWNpdGx5IGRpc2FibGVkXG4gICAgaWYgKF9kb2N1bWVudFN5bmMub3BlbkNsb3NlICE9PSBmYWxzZSkge1xuICAgICAgdGhpcy5fZGlzcG9zYWJsZS5hZGQoX2VkaXRvci5vbkRpZERlc3Ryb3kodGhpcy5kaWRDbG9zZS5iaW5kKHRoaXMpKSlcbiAgICB9XG4gICAgdGhpcy5fZGlzcG9zYWJsZS5hZGQoX2VkaXRvci5vbkRpZFNhdmUodGhpcy5kaWRTYXZlLmJpbmQodGhpcykpLCBfZWRpdG9yLm9uRGlkQ2hhbmdlUGF0aCh0aGlzLmRpZFJlbmFtZS5iaW5kKHRoaXMpKSlcblxuICAgIHRoaXMuX2N1cnJlbnRVcmkgPSB0aGlzLmdldEVkaXRvclVyaSgpXG5cbiAgICBpZiAoX2RvY3VtZW50U3luYy5vcGVuQ2xvc2UgIT09IGZhbHNlKSB7XG4gICAgICB0aGlzLmRpZE9wZW4oKVxuICAgIH1cbiAgfVxuXG4gIC8qKiBUaGUgY2hhbmdlIHRyYWNraW5nIGRpc3Bvc2FibGUgbGlzdGVuZXIgdGhhdCB3aWxsIGVuc3VyZSB0aGF0IGNoYW5nZXMgYXJlIHNlbnQgdG8gdGhlIGxhbmd1YWdlIHNlcnZlciBhcyBhcHByb3ByaWF0ZS4gKi9cbiAgcHVibGljIHNldHVwQ2hhbmdlVHJhY2tpbmcoZG9jdW1lbnRTeW5jOiBUZXh0RG9jdW1lbnRTeW5jT3B0aW9ucyk6IERpc3Bvc2FibGUgfCBudWxsIHtcbiAgICBzd2l0Y2ggKGRvY3VtZW50U3luYy5jaGFuZ2UpIHtcbiAgICAgIGNhc2UgVGV4dERvY3VtZW50U3luY0tpbmQuRnVsbDpcbiAgICAgICAgcmV0dXJuIHRoaXMuX2VkaXRvci5vbkRpZENoYW5nZSh0aGlzLnNlbmRGdWxsQ2hhbmdlcy5iaW5kKHRoaXMpKVxuICAgICAgY2FzZSBUZXh0RG9jdW1lbnRTeW5jS2luZC5JbmNyZW1lbnRhbDpcbiAgICAgICAgcmV0dXJuIHRoaXMuX2VkaXRvci5nZXRCdWZmZXIoKS5vbkRpZENoYW5nZVRleHQodGhpcy5zZW5kSW5jcmVtZW50YWxDaGFuZ2VzLmJpbmQodGhpcykpXG4gICAgfVxuICAgIHJldHVybiBudWxsXG4gIH1cblxuICAvKiogRGlzcG9zZSB0aGlzIGFkYXB0ZXIgZW5zdXJpbmcgYW55IHJlc291cmNlcyBhcmUgZnJlZWQgYW5kIGV2ZW50cyB1bmhvb2tlZC4gKi9cbiAgcHVibGljIGRpc3Bvc2UoKTogdm9pZCB7XG4gICAgdGhpcy5fZGlzcG9zYWJsZS5kaXNwb3NlKClcbiAgfVxuXG4gIC8qKiBHZXQgdGhlIGxhbmd1YWdlSWQgZmllbGQgdGhhdCB3aWxsIGJlIHNlbnQgdG8gdGhlIGxhbmd1YWdlIHNlcnZlciBieSBzaW1wbHkgdXNpbmcgdGhlIGBfZ2V0TGFuZ3VhZ2VJZEZyb21FZGl0b3JgLiAqL1xuICBwdWJsaWMgZ2V0TGFuZ3VhZ2VJZCgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLl9nZXRMYW5ndWFnZUlkRnJvbUVkaXRvcih0aGlzLl9lZGl0b3IpXG4gIH1cblxuICAvKipcbiAgICogUHVibGljOiBDcmVhdGUgYSB7VmVyc2lvbmVkVGV4dERvY3VtZW50SWRlbnRpZmllcn0gZm9yIHRoZSBkb2N1bWVudCBvYnNlcnZlZCBieSB0aGlzIGFkYXB0ZXIgaW5jbHVkaW5nIGJvdGggdGhlIFVyaVxuICAgKiBhbmQgdGhlIGN1cnJlbnQgVmVyc2lvbi5cbiAgICovXG4gIHB1YmxpYyBnZXRWZXJzaW9uZWRUZXh0RG9jdW1lbnRJZGVudGlmaWVyKCk6IFZlcnNpb25lZFRleHREb2N1bWVudElkZW50aWZpZXIge1xuICAgIHJldHVybiB7XG4gICAgICB1cmk6IHRoaXMuZ2V0RWRpdG9yVXJpKCksXG4gICAgICB2ZXJzaW9uOiB0aGlzLl9nZXRWZXJzaW9uKHRoaXMuX2VkaXRvci5nZXRQYXRoKCkgfHwgXCJcIiksXG4gICAgfVxuICB9XG5cbiAgLyoqIFB1YmxpYzogU2VuZCB0aGUgZW50aXJlIGRvY3VtZW50IHRvIHRoZSBsYW5ndWFnZSBzZXJ2ZXIuIFRoaXMgaXMgdXNlZCB3aGVuIG9wZXJhdGluZyBpbiBGdWxsICgxKSBzeW5jIG1vZGUuICovXG4gIHB1YmxpYyBzZW5kRnVsbENoYW5nZXMoKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLl9pc1ByaW1hcnlBZGFwdGVyKCkpIHtcbiAgICAgIHJldHVyblxuICAgIH0gLy8gTXVsdGlwbGUgZWRpdG9ycywgd2UgYXJlIG5vdCBmaXJzdFxuXG4gICAgdGhpcy5fYnVtcFZlcnNpb24oKVxuICAgIHRoaXMuX2Nvbm5lY3Rpb24uZGlkQ2hhbmdlVGV4dERvY3VtZW50KHtcbiAgICAgIHRleHREb2N1bWVudDogdGhpcy5nZXRWZXJzaW9uZWRUZXh0RG9jdW1lbnRJZGVudGlmaWVyKCksXG4gICAgICBjb250ZW50Q2hhbmdlczogW3sgdGV4dDogdGhpcy5fZWRpdG9yLmdldFRleHQoKSB9XSxcbiAgICB9KVxuICB9XG5cbiAgLyoqXG4gICAqIFB1YmxpYzogU2VuZCB0aGUgaW5jcmVtZW50YWwgdGV4dCBjaGFuZ2VzIHRvIHRoZSBsYW5ndWFnZSBzZXJ2ZXIuIFRoaXMgaXMgdXNlZCB3aGVuIG9wZXJhdGluZyBpbiBJbmNyZW1lbnRhbCAoMikgc3luYyBtb2RlLlxuICAgKlxuICAgKiBAcGFyYW0gZXZlbnQgVGhlIGV2ZW50IGZpcmVkIGJ5IEF0b20gdG8gaW5kaWNhdGUgdGhlIGRvY3VtZW50IGhhcyBzdG9wcGVkIGNoYW5naW5nIGluY2x1ZGluZyBhIGxpc3Qgb2YgY2hhbmdlc1xuICAgKiAgIHNpbmNlIHRoZSBsYXN0IHRpbWUgdGhpcyBldmVudCBmaXJlZCBmb3IgdGhpcyB0ZXh0IGVkaXRvci4gTk9URTogVGhlIG9yZGVyIG9mIGNoYW5nZXMgaW4gdGhlIGV2ZW50IGlzIGd1YXJhbnRlZWRcbiAgICogICB0b3AgdG8gYm90dG9tLiBMYW5ndWFnZSBzZXJ2ZXIgZXhwZWN0cyB0aGlzIGluIHJldmVyc2UuXG4gICAqL1xuICBwdWJsaWMgc2VuZEluY3JlbWVudGFsQ2hhbmdlcyhldmVudDogQnVmZmVyU3RvcHBlZENoYW5naW5nRXZlbnQpOiB2b2lkIHtcbiAgICBpZiAoZXZlbnQuY2hhbmdlcy5sZW5ndGggPiAwKSB7XG4gICAgICBpZiAoIXRoaXMuX2lzUHJpbWFyeUFkYXB0ZXIoKSkge1xuICAgICAgICByZXR1cm5cbiAgICAgIH0gLy8gTXVsdGlwbGUgZWRpdG9ycywgd2UgYXJlIG5vdCBmaXJzdFxuXG4gICAgICB0aGlzLl9idW1wVmVyc2lvbigpXG4gICAgICB0aGlzLl9jb25uZWN0aW9uLmRpZENoYW5nZVRleHREb2N1bWVudCh7XG4gICAgICAgIHRleHREb2N1bWVudDogdGhpcy5nZXRWZXJzaW9uZWRUZXh0RG9jdW1lbnRJZGVudGlmaWVyKCksXG4gICAgICAgIGNvbnRlbnRDaGFuZ2VzOiBldmVudC5jaGFuZ2VzLm1hcChUZXh0RWRpdG9yU3luY0FkYXB0ZXIudGV4dEVkaXRUb0NvbnRlbnRDaGFuZ2UpLnJldmVyc2UoKSxcbiAgICAgIH0pXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFB1YmxpYzogQ29udmVydCBhbiBBdG9tIHtUZXh0RWRpdEV2ZW50fSB0byBhIGxhbmd1YWdlIHNlcnZlciB7VGV4dERvY3VtZW50Q29udGVudENoYW5nZUV2ZW50fSBvYmplY3QuXG4gICAqXG4gICAqIEBwYXJhbSBjaGFuZ2UgVGhlIEF0b20ge1RleHRFZGl0RXZlbnR9IHRvIGNvbnZlcnQuXG4gICAqIEByZXR1cm5zIEEge1RleHREb2N1bWVudENvbnRlbnRDaGFuZ2VFdmVudH0gdGhhdCByZXByZXNlbnRzIHRoZSBjb252ZXJ0ZWQge1RleHRFZGl0RXZlbnR9LlxuICAgKi9cbiAgcHVibGljIHN0YXRpYyB0ZXh0RWRpdFRvQ29udGVudENoYW5nZShjaGFuZ2U6IFRleHRDaGFuZ2UpOiBUZXh0RG9jdW1lbnRDb250ZW50Q2hhbmdlRXZlbnQge1xuICAgIHJldHVybiB7XG4gICAgICByYW5nZTogQ29udmVydC5hdG9tUmFuZ2VUb0xTUmFuZ2UoY2hhbmdlLm9sZFJhbmdlKSxcbiAgICAgIHJhbmdlTGVuZ3RoOiBjaGFuZ2Uub2xkVGV4dC5sZW5ndGgsXG4gICAgICB0ZXh0OiBjaGFuZ2UubmV3VGV4dCxcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIF9pc1ByaW1hcnlBZGFwdGVyKCk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IGxvd2VzdElkRm9yQnVmZmVyID0gTWF0aC5taW4oXG4gICAgICAuLi5hdG9tLndvcmtzcGFjZVxuICAgICAgICAuZ2V0VGV4dEVkaXRvcnMoKVxuICAgICAgICAuZmlsdGVyKCh0KSA9PiB0LmdldEJ1ZmZlcigpID09PSB0aGlzLl9lZGl0b3IuZ2V0QnVmZmVyKCkpXG4gICAgICAgIC5tYXAoKHQpID0+IHQuaWQpXG4gICAgKVxuICAgIHJldHVybiBsb3dlc3RJZEZvckJ1ZmZlciA9PT0gdGhpcy5fZWRpdG9yLmlkXG4gIH1cblxuICBwcml2YXRlIF9idW1wVmVyc2lvbigpOiB2b2lkIHtcbiAgICBjb25zdCBmaWxlUGF0aCA9IHRoaXMuX2VkaXRvci5nZXRQYXRoKClcbiAgICBpZiAoZmlsZVBhdGggPT0gbnVsbCkge1xuICAgICAgcmV0dXJuXG4gICAgfVxuICAgIHRoaXMuX3ZlcnNpb25zLnNldChmaWxlUGF0aCwgdGhpcy5fZ2V0VmVyc2lvbihmaWxlUGF0aCkgKyAxKVxuICB9XG5cbiAgLyoqXG4gICAqIEVuc3VyZSB3aGVuIHRoZSBkb2N1bWVudCBpcyBvcGVuZWQgd2Ugc2VuZCBub3RpZmljYXRpb24gdG8gdGhlIGxhbmd1YWdlIHNlcnZlciBzbyBpdCBjYW4gbG9hZCBpdCBpbiBhbmQga2VlcCB0cmFja1xuICAgKiBvZiBkaWFnbm9zdGljcyBldGMuXG4gICAqL1xuICBwcml2YXRlIGRpZE9wZW4oKTogdm9pZCB7XG4gICAgY29uc3QgZmlsZVBhdGggPSB0aGlzLl9lZGl0b3IuZ2V0UGF0aCgpXG4gICAgaWYgKGZpbGVQYXRoID09IG51bGwpIHtcbiAgICAgIHJldHVyblxuICAgIH0gLy8gTm90IHlldCBzYXZlZFxuXG4gICAgaWYgKCF0aGlzLl9pc1ByaW1hcnlBZGFwdGVyKCkpIHtcbiAgICAgIHJldHVyblxuICAgIH0gLy8gTXVsdGlwbGUgZWRpdG9ycywgd2UgYXJlIG5vdCBmaXJzdFxuXG4gICAgdGhpcy5fY29ubmVjdGlvbi5kaWRPcGVuVGV4dERvY3VtZW50KHtcbiAgICAgIHRleHREb2N1bWVudDoge1xuICAgICAgICB1cmk6IHRoaXMuZ2V0RWRpdG9yVXJpKCksXG4gICAgICAgIGxhbmd1YWdlSWQ6IHRoaXMuZ2V0TGFuZ3VhZ2VJZCgpLnRvTG93ZXJDYXNlKCksXG4gICAgICAgIHZlcnNpb246IHRoaXMuX2dldFZlcnNpb24oZmlsZVBhdGgpLFxuICAgICAgICB0ZXh0OiB0aGlzLl9lZGl0b3IuZ2V0VGV4dCgpLFxuICAgICAgfSxcbiAgICB9KVxuICB9XG5cbiAgcHJpdmF0ZSBfZ2V0VmVyc2lvbihmaWxlUGF0aDogc3RyaW5nKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5fdmVyc2lvbnMuZ2V0KGZpbGVQYXRoKSB8fCAxXG4gIH1cblxuICAvKiogQ2FsbGVkIHdoZW4gdGhlIHtUZXh0RWRpdG9yfSBpcyBjbG9zZWQgYW5kIHNlbmRzIHRoZSAnZGlkQ2xvc2VUZXh0RG9jdW1lbnQnIG5vdGlmaWNhdGlvbiB0byB0aGUgY29ubmVjdGVkIGxhbmd1YWdlIHNlcnZlci4gKi9cbiAgcHVibGljIGRpZENsb3NlKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLl9lZGl0b3IuZ2V0UGF0aCgpID09IG51bGwpIHtcbiAgICAgIHJldHVyblxuICAgIH0gLy8gTm90IHlldCBzYXZlZFxuXG4gICAgY29uc3QgZmlsZVN0aWxsT3BlbiA9IGF0b20ud29ya3NwYWNlLmdldFRleHRFZGl0b3JzKCkuZmluZCgodCkgPT4gdC5nZXRCdWZmZXIoKSA9PT0gdGhpcy5fZWRpdG9yLmdldEJ1ZmZlcigpKVxuICAgIGlmIChmaWxlU3RpbGxPcGVuKSB7XG4gICAgICByZXR1cm4gLy8gT3RoZXIgd2luZG93cyBvciBlZGl0b3JzIHN0aWxsIGhhdmUgdGhpcyBmaWxlIG9wZW5cbiAgICB9XG5cbiAgICB0aGlzLl9jb25uZWN0aW9uLmRpZENsb3NlVGV4dERvY3VtZW50KHsgdGV4dERvY3VtZW50OiB7IHVyaTogdGhpcy5nZXRFZGl0b3JVcmkoKSB9IH0pXG4gIH1cblxuICAvKiogQ2FsbGVkIGp1c3QgYmVmb3JlIHRoZSB7VGV4dEVkaXRvcn0gc2F2ZXMgYW5kIHNlbmRzIHRoZSAnd2lsbFNhdmVUZXh0RG9jdW1lbnQnIG5vdGlmaWNhdGlvbiB0byB0aGUgY29ubmVjdGVkIGxhbmd1YWdlIHNlcnZlci4gKi9cbiAgcHVibGljIHdpbGxTYXZlKCk6IHZvaWQge1xuICAgIGlmICghdGhpcy5faXNQcmltYXJ5QWRhcHRlcigpKSB7XG4gICAgICByZXR1cm5cbiAgICB9XG5cbiAgICBjb25zdCB1cmkgPSB0aGlzLmdldEVkaXRvclVyaSgpXG4gICAgdGhpcy5fY29ubmVjdGlvbi53aWxsU2F2ZVRleHREb2N1bWVudCh7XG4gICAgICB0ZXh0RG9jdW1lbnQ6IHsgdXJpIH0sXG4gICAgICByZWFzb246IFRleHREb2N1bWVudFNhdmVSZWFzb24uTWFudWFsLFxuICAgIH0pXG4gIH1cblxuICAvKipcbiAgICogQ2FsbGVkIGp1c3QgYmVmb3JlIHRoZSB7VGV4dEVkaXRvcn0gc2F2ZXMsIHNlbmRzIHRoZSAnd2lsbFNhdmVXYWl0VW50aWxUZXh0RG9jdW1lbnQnIHJlcXVlc3QgdG8gdGhlIGNvbm5lY3RlZFxuICAgKiBsYW5ndWFnZSBzZXJ2ZXIgYW5kIHdhaXRzIGZvciB0aGUgcmVzcG9uc2UgYmVmb3JlIHNhdmluZyB0aGUgYnVmZmVyLlxuICAgKi9cbiAgcHVibGljIGFzeW5jIHdpbGxTYXZlV2FpdFVudGlsKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICghdGhpcy5faXNQcmltYXJ5QWRhcHRlcigpKSB7XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKClcbiAgICB9XG5cbiAgICBjb25zdCBidWZmZXIgPSB0aGlzLl9lZGl0b3IuZ2V0QnVmZmVyKClcbiAgICBjb25zdCB1cmkgPSB0aGlzLmdldEVkaXRvclVyaSgpXG4gICAgY29uc3QgdGl0bGUgPSB0aGlzLl9lZGl0b3IuZ2V0TG9uZ1RpdGxlKClcblxuICAgIGNvbnN0IGFwcGx5RWRpdHNPclRpbWVvdXQgPSBVdGlscy5wcm9taXNlV2l0aFRpbWVvdXQoXG4gICAgICAyNTAwLCAvLyAyLjUgc2Vjb25kcyB0aW1lb3V0XG4gICAgICB0aGlzLl9jb25uZWN0aW9uLndpbGxTYXZlV2FpdFVudGlsVGV4dERvY3VtZW50KHtcbiAgICAgICAgdGV4dERvY3VtZW50OiB7IHVyaSB9LFxuICAgICAgICByZWFzb246IFRleHREb2N1bWVudFNhdmVSZWFzb24uTWFudWFsLFxuICAgICAgfSlcbiAgICApXG4gICAgICAudGhlbigoZWRpdHMpID0+IHtcbiAgICAgICAgY29uc3QgY3Vyc29yID0gdGhpcy5fZWRpdG9yLmdldEN1cnNvckJ1ZmZlclBvc2l0aW9uKClcbiAgICAgICAgQXBwbHlFZGl0QWRhcHRlci5hcHBseUVkaXRzKGJ1ZmZlciwgQ29udmVydC5jb252ZXJ0THNUZXh0RWRpdHMoZWRpdHMpKVxuICAgICAgICB0aGlzLl9lZGl0b3Iuc2V0Q3Vyc29yQnVmZmVyUG9zaXRpb24oY3Vyc29yKVxuICAgICAgfSlcbiAgICAgIC5jYXRjaCgoZXJyKSA9PiB7XG4gICAgICAgIGF0b20ubm90aWZpY2F0aW9ucy5hZGRFcnJvcihcIk9uLXNhdmUgYWN0aW9uIGZhaWxlZFwiLCB7XG4gICAgICAgICAgZGVzY3JpcHRpb246IGBGYWlsZWQgdG8gYXBwbHkgZWRpdHMgdG8gJHt0aXRsZX1gLFxuICAgICAgICAgIGRldGFpbDogZXJyLm1lc3NhZ2UsXG4gICAgICAgIH0pXG4gICAgICAgIHJldHVyblxuICAgICAgfSlcblxuICAgIGNvbnN0IHdpdGhCdXN5U2lnbmFsID0gdGhpcy5fcmVwb3J0QnVzeVdoaWxlKGBBcHBseWluZyBvbi1zYXZlIGVkaXRzIGZvciAke3RpdGxlfWAsICgpID0+IGFwcGx5RWRpdHNPclRpbWVvdXQpXG4gICAgcmV0dXJuIHdpdGhCdXN5U2lnbmFsIHx8IGFwcGx5RWRpdHNPclRpbWVvdXRcbiAgfVxuXG4gIC8qKlxuICAgKiBDYWxsZWQgd2hlbiB0aGUge1RleHRFZGl0b3J9IHNhdmVzIGFuZCBzZW5kcyB0aGUgJ2RpZFNhdmVUZXh0RG9jdW1lbnQnIG5vdGlmaWNhdGlvbiB0byB0aGUgY29ubmVjdGVkIGxhbmd1YWdlXG4gICAqIHNlcnZlci4gTm90ZTogUmlnaHQgbm93IHRoaXMgYWxzbyBzZW5kcyB0aGUgYGRpZENoYW5nZVdhdGNoZWRGaWxlc2Agbm90aWZpY2F0aW9uIGFzIHdlbGwgYnV0IHRoYXQgd2lsbCBiZSBzZW50IGZyb21cbiAgICogZWxzZXdoZXJlIHNvb24uXG4gICAqL1xuICBwdWJsaWMgZGlkU2F2ZSgpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuX2lzUHJpbWFyeUFkYXB0ZXIoKSkge1xuICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgY29uc3QgdXJpID0gdGhpcy5nZXRFZGl0b3JVcmkoKVxuICAgIGNvbnN0IGRpZFNhdmVOb3RpZmljYXRpb24gPSB7XG4gICAgICB0ZXh0RG9jdW1lbnQ6IHsgdXJpLCB2ZXJzaW9uOiB0aGlzLl9nZXRWZXJzaW9uKHVyaSkgfSxcbiAgICB9IGFzIERpZFNhdmVUZXh0RG9jdW1lbnRQYXJhbXNcbiAgICBpZiAodHlwZW9mIHRoaXMuX2RvY3VtZW50U3luYy5zYXZlID09PSBcIm9iamVjdFwiICYmIHRoaXMuX2RvY3VtZW50U3luYy5zYXZlLmluY2x1ZGVUZXh0KSB7XG4gICAgICBkaWRTYXZlTm90aWZpY2F0aW9uLnRleHQgPSB0aGlzLl9lZGl0b3IuZ2V0VGV4dCgpXG4gICAgfVxuICAgIHRoaXMuX2Nvbm5lY3Rpb24uZGlkU2F2ZVRleHREb2N1bWVudChkaWRTYXZlTm90aWZpY2F0aW9uKVxuICAgIGlmICh0aGlzLl9mYWtlRGlkQ2hhbmdlV2F0Y2hlZEZpbGVzKSB7XG4gICAgICB0aGlzLl9jb25uZWN0aW9uLmRpZENoYW5nZVdhdGNoZWRGaWxlcyh7XG4gICAgICAgIGNoYW5nZXM6IFt7IHVyaSwgdHlwZTogRmlsZUNoYW5nZVR5cGUuQ2hhbmdlZCB9XSxcbiAgICAgIH0pXG4gICAgfVxuICB9XG5cbiAgcHVibGljIGRpZFJlbmFtZSgpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuX2lzUHJpbWFyeUFkYXB0ZXIoKSkge1xuICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgY29uc3Qgb2xkVXJpID0gdGhpcy5fY3VycmVudFVyaVxuICAgIHRoaXMuX2N1cnJlbnRVcmkgPSB0aGlzLmdldEVkaXRvclVyaSgpXG4gICAgaWYgKCFvbGRVcmkpIHtcbiAgICAgIHJldHVybiAvLyBEaWRuJ3QgcHJldmlvdXNseSBoYXZlIGEgbmFtZVxuICAgIH1cblxuICAgIGlmICh0aGlzLl9kb2N1bWVudFN5bmMub3BlbkNsb3NlICE9PSBmYWxzZSkge1xuICAgICAgdGhpcy5fY29ubmVjdGlvbi5kaWRDbG9zZVRleHREb2N1bWVudCh7IHRleHREb2N1bWVudDogeyB1cmk6IG9sZFVyaSB9IH0pXG4gICAgfVxuXG4gICAgaWYgKHRoaXMuX2Zha2VEaWRDaGFuZ2VXYXRjaGVkRmlsZXMpIHtcbiAgICAgIHRoaXMuX2Nvbm5lY3Rpb24uZGlkQ2hhbmdlV2F0Y2hlZEZpbGVzKHtcbiAgICAgICAgY2hhbmdlczogW1xuICAgICAgICAgIHsgdXJpOiBvbGRVcmksIHR5cGU6IEZpbGVDaGFuZ2VUeXBlLkRlbGV0ZWQgfSxcbiAgICAgICAgICB7IHVyaTogdGhpcy5fY3VycmVudFVyaSwgdHlwZTogRmlsZUNoYW5nZVR5cGUuQ3JlYXRlZCB9LFxuICAgICAgICBdLFxuICAgICAgfSlcbiAgICB9XG5cbiAgICAvLyBTZW5kIGFuIGVxdWl2YWxlbnQgb3BlbiBldmVudCBmb3IgdGhpcyBlZGl0b3IsIHdoaWNoIHdpbGwgbm93IHVzZSB0aGUgbmV3XG4gICAgLy8gZmlsZSBwYXRoLlxuICAgIGlmICh0aGlzLl9kb2N1bWVudFN5bmMub3BlbkNsb3NlICE9PSBmYWxzZSkge1xuICAgICAgdGhpcy5kaWRPcGVuKClcbiAgICB9XG4gIH1cblxuICAvKiogUHVibGljOiBPYnRhaW4gdGhlIGN1cnJlbnQge1RleHRFZGl0b3J9IHBhdGggYW5kIGNvbnZlcnQgaXQgdG8gYSBVcmkuICovXG4gIHB1YmxpYyBnZXRFZGl0b3JVcmkoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gQ29udmVydC5wYXRoVG9VcmkodGhpcy5fZWRpdG9yLmdldFBhdGgoKSB8fCBcIlwiKVxuICB9XG59XG4iXX0= |
\ | No newline at end of file |