/ cloudformation-templates / node_modules / aws-cdk / test / util / stack-monitor.test.js
stack-monitor.test.js
  1  "use strict";
  2  Object.defineProperty(exports, "__esModule", { value: true });
  3  const stack_activity_monitor_1 = require("../../lib/api/util/cloudformation/stack-activity-monitor");
  4  const aws_1 = require("../integ/helpers/aws");
  5  const mock_sdk_1 = require("./mock-sdk");
  6  let sdk;
  7  let printer;
  8  beforeEach(() => {
  9      sdk = new mock_sdk_1.MockSdk();
 10      printer = new FakePrinter();
 11  });
 12  test('continue to the next page if it exists', async () => {
 13      await testMonitorWithEventCalls([
 14          (request) => {
 15              expect(request.NextToken).toBeUndefined();
 16              return {
 17                  StackEvents: [event(102)],
 18                  NextToken: 'some-token',
 19              };
 20          },
 21          (request) => {
 22              expect(request.NextToken).toBe('some-token');
 23              return {
 24                  StackEvents: [event(101)],
 25              };
 26          },
 27      ]);
 28      // Printer sees them in chronological order
 29      expect(printer.eventIds).toEqual(['101', '102']);
 30  });
 31  test('do not page further if we already saw the last event', async () => {
 32      await testMonitorWithEventCalls([
 33          (request) => {
 34              expect(request.NextToken).toBeUndefined();
 35              return {
 36                  StackEvents: [event(101)],
 37              };
 38          },
 39          (request) => {
 40              expect(request.NextToken).toBeUndefined();
 41              return {
 42                  StackEvents: [event(102), event(101)],
 43                  NextToken: 'some-token',
 44              };
 45          },
 46          (request) => {
 47              // Did not use the token
 48              expect(request.NextToken).toBeUndefined();
 49              return {};
 50          },
 51      ]);
 52      // Seen in chronological order
 53      expect(printer.eventIds).toEqual(['101', '102']);
 54  });
 55  test('do not page further if the last event is too old', async () => {
 56      await testMonitorWithEventCalls([
 57          (request) => {
 58              expect(request.NextToken).toBeUndefined();
 59              return {
 60                  StackEvents: [event(101), event(95)],
 61                  NextToken: 'some-token',
 62              };
 63          },
 64          (request) => {
 65              // Start again from the top
 66              expect(request.NextToken).toBeUndefined();
 67              return {};
 68          },
 69      ]);
 70      // Seen only the new one
 71      expect(printer.eventIds).toEqual(['101']);
 72  });
 73  test('do a final request after the monitor is stopped', async () => {
 74      await testMonitorWithEventCalls([
 75          // Before stop
 76          (request) => {
 77              expect(request.NextToken).toBeUndefined();
 78              return {
 79                  StackEvents: [event(101)],
 80              };
 81          },
 82      ], 
 83      // After stop
 84      [
 85          (request) => {
 86              expect(request.NextToken).toBeUndefined();
 87              return {
 88                  StackEvents: [event(102), event(101)],
 89              };
 90          },
 91      ]);
 92      // Seen both
 93      expect(printer.eventIds).toEqual(['101', '102']);
 94  });
 95  const T0 = 1597837230504;
 96  // Events 0-99 are before we started paying attention
 97  const T100 = T0 + 100 * 1000;
 98  function event(nr) {
 99      return {
100          EventId: `${nr}`,
101          StackId: 'StackId',
102          StackName: 'StackName',
103          Timestamp: new Date(T0 + nr * 1000),
104      };
105  }
106  async function testMonitorWithEventCalls(beforeStopInvocations, afterStopInvocations = []) {
107      let describeStackEvents = jest.fn();
108      let finished = false;
109      for (const invocation of beforeStopInvocations) {
110          const invocation_ = invocation; // Capture loop variable in local because of closure semantics
111          const isLast = invocation === beforeStopInvocations[beforeStopInvocations.length - 1];
112          describeStackEvents = describeStackEvents.mockImplementationOnce(request => {
113              const ret = invocation_(request);
114              if (isLast) {
115                  finished = true;
116              }
117              return ret;
118          });
119      }
120      for (const invocation of afterStopInvocations) {
121          describeStackEvents = describeStackEvents.mockImplementationOnce(invocation);
122      }
123      describeStackEvents.mockImplementation(() => { return {}; });
124      sdk.stubCloudFormation({ describeStackEvents });
125      const monitor = new stack_activity_monitor_1.StackActivityMonitor(sdk.cloudFormation(), 'StackName', printer, undefined, new Date(T100)).start();
126      await waitForCondition(() => finished);
127      await monitor.stop();
128  }
129  class FakePrinter {
130      constructor() {
131          this.updateSleep = 0;
132          this.activities = [];
133      }
134      get eventIds() {
135          return this.activities.map(a => a.event.EventId);
136      }
137      addActivity(activity) {
138          this.activities.push(activity);
139      }
140      print() { }
141      start() { }
142      stop() { }
143  }
144  async function waitForCondition(cb) {
145      while (!cb()) {
146          await aws_1.sleep(10);
147      }
148  }
149  //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhY2stbW9uaXRvci50ZXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsic3RhY2stbW9uaXRvci50ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEscUdBQWlJO0FBQ2pJLDhDQUE2QztBQUM3Qyx5Q0FBcUM7QUFFckMsSUFBSSxHQUFZLENBQUM7QUFDakIsSUFBSSxPQUFvQixDQUFDO0FBQ3pCLFVBQVUsQ0FBQyxHQUFHLEVBQUU7SUFDZCxHQUFHLEdBQUcsSUFBSSxrQkFBTyxFQUFFLENBQUM7SUFDcEIsT0FBTyxHQUFHLElBQUksV0FBVyxFQUFFLENBQUM7QUFDOUIsQ0FBQyxDQUFDLENBQUM7QUFFSCxJQUFJLENBQUMsd0NBQXdDLEVBQUUsS0FBSyxJQUFJLEVBQUU7SUFDeEQsTUFBTSx5QkFBeUIsQ0FBQztRQUM5QixDQUFDLE9BQU8sRUFBRSxFQUFFO1lBQ1YsTUFBTSxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUMxQyxPQUFPO2dCQUNMLFdBQVcsRUFBRSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztnQkFDekIsU0FBUyxFQUFFLFlBQVk7YUFDeEIsQ0FBQztRQUNKLENBQUM7UUFDRCxDQUFDLE9BQU8sRUFBRSxFQUFFO1lBQ1YsTUFBTSxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUM7WUFDN0MsT0FBTztnQkFDTCxXQUFXLEVBQUUsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7YUFDMUIsQ0FBQztRQUNKLENBQUM7S0FDRixDQUFDLENBQUM7SUFFSCwyQ0FBMkM7SUFDM0MsTUFBTSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQztBQUNuRCxDQUFDLENBQUMsQ0FBQztBQUVILElBQUksQ0FBQyxzREFBc0QsRUFBRSxLQUFLLElBQUksRUFBRTtJQUN0RSxNQUFNLHlCQUF5QixDQUFDO1FBQzlCLENBQUMsT0FBTyxFQUFFLEVBQUU7WUFDVixNQUFNLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDLGFBQWEsRUFBRSxDQUFDO1lBQzFDLE9BQU87Z0JBQ0wsV0FBVyxFQUFFLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO2FBQzFCLENBQUM7UUFDSixDQUFDO1FBQ0QsQ0FBQyxPQUFPLEVBQUUsRUFBRTtZQUNWLE1BQU0sQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUMsYUFBYSxFQUFFLENBQUM7WUFDMUMsT0FBTztnQkFDTCxXQUFXLEVBQUUsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUUsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO2dCQUNyQyxTQUFTLEVBQUUsWUFBWTthQUN4QixDQUFDO1FBQ0osQ0FBQztRQUNELENBQUMsT0FBTyxFQUFFLEVBQUU7WUFDVix3QkFBd0I7WUFDeEIsTUFBTSxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUMxQyxPQUFPLEVBQUUsQ0FBQztRQUNaLENBQUM7S0FDRixDQUFDLENBQUM7SUFFSCw4QkFBOEI7SUFDOUIsTUFBTSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQztBQUNuRCxDQUFDLENBQUMsQ0FBQztBQUVILElBQUksQ0FBQyxrREFBa0QsRUFBRSxLQUFLLElBQUksRUFBRTtJQUNsRSxNQUFNLHlCQUF5QixDQUFDO1FBQzlCLENBQUMsT0FBTyxFQUFFLEVBQUU7WUFDVixNQUFNLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDLGFBQWEsRUFBRSxDQUFDO1lBQzFDLE9BQU87Z0JBQ0wsV0FBVyxFQUFFLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxFQUFFLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQztnQkFDcEMsU0FBUyxFQUFFLFlBQVk7YUFDeEIsQ0FBQztRQUNKLENBQUM7UUFDRCxDQUFDLE9BQU8sRUFBRSxFQUFFO1lBQ1YsMkJBQTJCO1lBQzNCLE1BQU0sQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUMsYUFBYSxFQUFFLENBQUM7WUFDMUMsT0FBTyxFQUFFLENBQUM7UUFDWixDQUFDO0tBQ0YsQ0FBQyxDQUFDO0lBRUgsd0JBQXdCO0lBQ3hCLE1BQU0sQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztBQUM1QyxDQUFDLENBQUMsQ0FBQztBQUVILElBQUksQ0FBQyxpREFBaUQsRUFBRSxLQUFLLElBQUksRUFBRTtJQUNqRSxNQUFNLHlCQUF5QixDQUFDO1FBQzlCLGNBQWM7UUFDZCxDQUFDLE9BQU8sRUFBRSxFQUFFO1lBQ1YsTUFBTSxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUMxQyxPQUFPO2dCQUNMLFdBQVcsRUFBRSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQzthQUMxQixDQUFDO1FBQ0osQ0FBQztLQUNGO0lBQ0QsYUFBYTtJQUNiO1FBQ0UsQ0FBQyxPQUFPLEVBQUUsRUFBRTtZQUNWLE1BQU0sQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUMsYUFBYSxFQUFFLENBQUM7WUFDMUMsT0FBTztnQkFDTCxXQUFXLEVBQUUsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUUsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO2FBQ3RDLENBQUM7UUFDSixDQUFDO0tBQ0YsQ0FBQyxDQUFDO0lBRUgsWUFBWTtJQUNaLE1BQU0sQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsS0FBSyxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUM7QUFDbkQsQ0FBQyxDQUFDLENBQUM7QUFFSCxNQUFNLEVBQUUsR0FBRyxhQUFhLENBQUM7QUFFekIscURBQXFEO0FBQ3JELE1BQU0sSUFBSSxHQUFHLEVBQUUsR0FBRyxHQUFHLEdBQUcsSUFBSSxDQUFDO0FBRTdCLFNBQVMsS0FBSyxDQUFDLEVBQVU7SUFDdkIsT0FBTztRQUNMLE9BQU8sRUFBRSxHQUFHLEVBQUUsRUFBRTtRQUNoQixPQUFPLEVBQUUsU0FBUztRQUNsQixTQUFTLEVBQUUsV0FBVztRQUN0QixTQUFTLEVBQUUsSUFBSSxJQUFJLENBQUMsRUFBRSxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUM7S0FDcEMsQ0FBQztBQUNKLENBQUM7QUFFRCxLQUFLLFVBQVUseUJBQXlCLENBQ3RDLHFCQUE4SCxFQUM5SCx1QkFBZ0ksRUFBRTtJQUVsSSxJQUFJLG1CQUFtQixHQUFJLElBQUksQ0FBQyxFQUFFLEVBQTZHLENBQUM7SUFFaEosSUFBSSxRQUFRLEdBQUcsS0FBSyxDQUFDO0lBRXJCLEtBQUssTUFBTSxVQUFVLElBQUkscUJBQXFCLEVBQUU7UUFDOUMsTUFBTSxXQUFXLEdBQUcsVUFBVSxDQUFDLENBQUMsOERBQThEO1FBQzlGLE1BQU0sTUFBTSxHQUFHLFVBQVUsS0FBSyxxQkFBcUIsQ0FBQyxxQkFBcUIsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFDdEYsbUJBQW1CLEdBQUcsbUJBQW1CLENBQUMsc0JBQXNCLENBQUMsT0FBTyxDQUFDLEVBQUU7WUFDekUsTUFBTSxHQUFHLEdBQUcsV0FBVyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQ2pDLElBQUksTUFBTSxFQUFFO2dCQUNWLFFBQVEsR0FBRyxJQUFJLENBQUM7YUFDakI7WUFDRCxPQUFPLEdBQUcsQ0FBQztRQUNiLENBQUMsQ0FBQyxDQUFDO0tBQ0o7SUFDRCxLQUFLLE1BQU0sVUFBVSxJQUFJLG9CQUFvQixFQUFFO1FBQzdDLG1CQUFtQixHQUFHLG1CQUFtQixDQUFDLHNCQUFzQixDQUFDLFVBQVUsQ0FBQyxDQUFDO0tBQzlFO0lBQ0QsbUJBQW1CLENBQUMsa0JBQWtCLENBQUMsR0FBRyxFQUFFLEdBQUcsT0FBTyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUU3RCxHQUFHLENBQUMsa0JBQWtCLENBQUMsRUFBRSxtQkFBbUIsRUFBRSxDQUFDLENBQUM7SUFFaEQsTUFBTSxPQUFPLEdBQUcsSUFBSSw2Q0FBb0IsQ0FBQyxHQUFHLENBQUMsY0FBYyxFQUFFLEVBQUUsV0FBVyxFQUFFLE9BQU8sRUFBRSxTQUFTLEVBQUUsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUN4SCxNQUFNLGdCQUFnQixDQUFDLEdBQUcsRUFBRSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQ3ZDLE1BQU0sT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDO0FBQ3ZCLENBQUM7QUFHRCxNQUFNLFdBQVc7SUFBakI7UUFDUyxnQkFBVyxHQUFXLENBQUMsQ0FBQztRQUNmLGVBQVUsR0FBb0IsRUFBRSxDQUFDO0lBYW5ELENBQUM7SUFYQyxJQUFXLFFBQVE7UUFDakIsT0FBTyxJQUFJLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDbkQsQ0FBQztJQUVNLFdBQVcsQ0FBQyxRQUF1QjtRQUN4QyxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUNqQyxDQUFDO0lBRU0sS0FBSyxLQUFXLENBQUM7SUFDakIsS0FBSyxLQUFXLENBQUM7SUFDakIsSUFBSSxLQUFXLENBQUM7Q0FDeEI7QUFFRCxLQUFLLFVBQVUsZ0JBQWdCLENBQUMsRUFBaUI7SUFDL0MsT0FBTyxDQUFDLEVBQUUsRUFBRSxFQUFFO1FBQ1osTUFBTSxXQUFLLENBQUMsRUFBRSxDQUFDLENBQUM7S0FDakI7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgU3RhY2tBY3Rpdml0eU1vbml0b3IsIElBY3Rpdml0eVByaW50ZXIsIFN0YWNrQWN0aXZpdHkgfSBmcm9tICcuLi8uLi9saWIvYXBpL3V0aWwvY2xvdWRmb3JtYXRpb24vc3RhY2stYWN0aXZpdHktbW9uaXRvcic7XG5pbXBvcnQgeyBzbGVlcCB9IGZyb20gJy4uL2ludGVnL2hlbHBlcnMvYXdzJztcbmltcG9ydCB7IE1vY2tTZGsgfSBmcm9tICcuL21vY2stc2RrJztcblxubGV0IHNkazogTW9ja1NkaztcbmxldCBwcmludGVyOiBGYWtlUHJpbnRlcjtcbmJlZm9yZUVhY2goKCkgPT4ge1xuICBzZGsgPSBuZXcgTW9ja1NkaygpO1xuICBwcmludGVyID0gbmV3IEZha2VQcmludGVyKCk7XG59KTtcblxudGVzdCgnY29udGludWUgdG8gdGhlIG5leHQgcGFnZSBpZiBpdCBleGlzdHMnLCBhc3luYyAoKSA9PiB7XG4gIGF3YWl0IHRlc3RNb25pdG9yV2l0aEV2ZW50Q2FsbHMoW1xuICAgIChyZXF1ZXN0KSA9PiB7XG4gICAgICBleHBlY3QocmVxdWVzdC5OZXh0VG9rZW4pLnRvQmVVbmRlZmluZWQoKTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIFN0YWNrRXZlbnRzOiBbZXZlbnQoMTAyKV0sXG4gICAgICAgIE5leHRUb2tlbjogJ3NvbWUtdG9rZW4nLFxuICAgICAgfTtcbiAgICB9LFxuICAgIChyZXF1ZXN0KSA9PiB7XG4gICAgICBleHBlY3QocmVxdWVzdC5OZXh0VG9rZW4pLnRvQmUoJ3NvbWUtdG9rZW4nKTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIFN0YWNrRXZlbnRzOiBbZXZlbnQoMTAxKV0sXG4gICAgICB9O1xuICAgIH0sXG4gIF0pO1xuXG4gIC8vIFByaW50ZXIgc2VlcyB0aGVtIGluIGNocm9ub2xvZ2ljYWwgb3JkZXJcbiAgZXhwZWN0KHByaW50ZXIuZXZlbnRJZHMpLnRvRXF1YWwoWycxMDEnLCAnMTAyJ10pO1xufSk7XG5cbnRlc3QoJ2RvIG5vdCBwYWdlIGZ1cnRoZXIgaWYgd2UgYWxyZWFkeSBzYXcgdGhlIGxhc3QgZXZlbnQnLCBhc3luYyAoKSA9PiB7XG4gIGF3YWl0IHRlc3RNb25pdG9yV2l0aEV2ZW50Q2FsbHMoW1xuICAgIChyZXF1ZXN0KSA9PiB7XG4gICAgICBleHBlY3QocmVxdWVzdC5OZXh0VG9rZW4pLnRvQmVVbmRlZmluZWQoKTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIFN0YWNrRXZlbnRzOiBbZXZlbnQoMTAxKV0sXG4gICAgICB9O1xuICAgIH0sXG4gICAgKHJlcXVlc3QpID0+IHtcbiAgICAgIGV4cGVjdChyZXF1ZXN0Lk5leHRUb2tlbikudG9CZVVuZGVmaW5lZCgpO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgU3RhY2tFdmVudHM6IFtldmVudCgxMDIpLCBldmVudCgxMDEpXSxcbiAgICAgICAgTmV4dFRva2VuOiAnc29tZS10b2tlbicsXG4gICAgICB9O1xuICAgIH0sXG4gICAgKHJlcXVlc3QpID0+IHtcbiAgICAgIC8vIERpZCBub3QgdXNlIHRoZSB0b2tlblxuICAgICAgZXhwZWN0KHJlcXVlc3QuTmV4dFRva2VuKS50b0JlVW5kZWZpbmVkKCk7XG4gICAgICByZXR1cm4ge307XG4gICAgfSxcbiAgXSk7XG5cbiAgLy8gU2VlbiBpbiBjaHJvbm9sb2dpY2FsIG9yZGVyXG4gIGV4cGVjdChwcmludGVyLmV2ZW50SWRzKS50b0VxdWFsKFsnMTAxJywgJzEwMiddKTtcbn0pO1xuXG50ZXN0KCdkbyBub3QgcGFnZSBmdXJ0aGVyIGlmIHRoZSBsYXN0IGV2ZW50IGlzIHRvbyBvbGQnLCBhc3luYyAoKSA9PiB7XG4gIGF3YWl0IHRlc3RNb25pdG9yV2l0aEV2ZW50Q2FsbHMoW1xuICAgIChyZXF1ZXN0KSA9PiB7XG4gICAgICBleHBlY3QocmVxdWVzdC5OZXh0VG9rZW4pLnRvQmVVbmRlZmluZWQoKTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIFN0YWNrRXZlbnRzOiBbZXZlbnQoMTAxKSwgZXZlbnQoOTUpXSxcbiAgICAgICAgTmV4dFRva2VuOiAnc29tZS10b2tlbicsXG4gICAgICB9O1xuICAgIH0sXG4gICAgKHJlcXVlc3QpID0+IHtcbiAgICAgIC8vIFN0YXJ0IGFnYWluIGZyb20gdGhlIHRvcFxuICAgICAgZXhwZWN0KHJlcXVlc3QuTmV4dFRva2VuKS50b0JlVW5kZWZpbmVkKCk7XG4gICAgICByZXR1cm4ge307XG4gICAgfSxcbiAgXSk7XG5cbiAgLy8gU2VlbiBvbmx5IHRoZSBuZXcgb25lXG4gIGV4cGVjdChwcmludGVyLmV2ZW50SWRzKS50b0VxdWFsKFsnMTAxJ10pO1xufSk7XG5cbnRlc3QoJ2RvIGEgZmluYWwgcmVxdWVzdCBhZnRlciB0aGUgbW9uaXRvciBpcyBzdG9wcGVkJywgYXN5bmMgKCkgPT4ge1xuICBhd2FpdCB0ZXN0TW9uaXRvcldpdGhFdmVudENhbGxzKFtcbiAgICAvLyBCZWZvcmUgc3RvcFxuICAgIChyZXF1ZXN0KSA9PiB7XG4gICAgICBleHBlY3QocmVxdWVzdC5OZXh0VG9rZW4pLnRvQmVVbmRlZmluZWQoKTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIFN0YWNrRXZlbnRzOiBbZXZlbnQoMTAxKV0sXG4gICAgICB9O1xuICAgIH0sXG4gIF0sXG4gIC8vIEFmdGVyIHN0b3BcbiAgW1xuICAgIChyZXF1ZXN0KSA9PiB7XG4gICAgICBleHBlY3QocmVxdWVzdC5OZXh0VG9rZW4pLnRvQmVVbmRlZmluZWQoKTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIFN0YWNrRXZlbnRzOiBbZXZlbnQoMTAyKSwgZXZlbnQoMTAxKV0sXG4gICAgICB9O1xuICAgIH0sXG4gIF0pO1xuXG4gIC8vIFNlZW4gYm90aFxuICBleHBlY3QocHJpbnRlci5ldmVudElkcykudG9FcXVhbChbJzEwMScsICcxMDInXSk7XG59KTtcblxuY29uc3QgVDAgPSAxNTk3ODM3MjMwNTA0O1xuXG4vLyBFdmVudHMgMC05OSBhcmUgYmVmb3JlIHdlIHN0YXJ0ZWQgcGF5aW5nIGF0dGVudGlvblxuY29uc3QgVDEwMCA9IFQwICsgMTAwICogMTAwMDtcblxuZnVuY3Rpb24gZXZlbnQobnI6IG51bWJlcik6IEFXUy5DbG91ZEZvcm1hdGlvbi5TdGFja0V2ZW50IHtcbiAgcmV0dXJuIHtcbiAgICBFdmVudElkOiBgJHtucn1gLFxuICAgIFN0YWNrSWQ6ICdTdGFja0lkJyxcbiAgICBTdGFja05hbWU6ICdTdGFja05hbWUnLFxuICAgIFRpbWVzdGFtcDogbmV3IERhdGUoVDAgKyBuciAqIDEwMDApLFxuICB9O1xufVxuXG5hc3luYyBmdW5jdGlvbiB0ZXN0TW9uaXRvcldpdGhFdmVudENhbGxzKFxuICBiZWZvcmVTdG9wSW52b2NhdGlvbnM6IEFycmF5PCh4OiBBV1MuQ2xvdWRGb3JtYXRpb24uRGVzY3JpYmVTdGFja0V2ZW50c0lucHV0KSA9PiBBV1MuQ2xvdWRGb3JtYXRpb24uRGVzY3JpYmVTdGFja0V2ZW50c091dHB1dD4sXG4gIGFmdGVyU3RvcEludm9jYXRpb25zOiBBcnJheTwoeDogQVdTLkNsb3VkRm9ybWF0aW9uLkRlc2NyaWJlU3RhY2tFdmVudHNJbnB1dCkgPT4gQVdTLkNsb3VkRm9ybWF0aW9uLkRlc2NyaWJlU3RhY2tFdmVudHNPdXRwdXQ+ID0gW10sXG4pIHtcbiAgbGV0IGRlc2NyaWJlU3RhY2tFdmVudHMgPSAoamVzdC5mbigpIGFzIGplc3QuTW9jazxBV1MuQ2xvdWRGb3JtYXRpb24uRGVzY3JpYmVTdGFja0V2ZW50c091dHB1dCwgW0FXUy5DbG91ZEZvcm1hdGlvbi5EZXNjcmliZVN0YWNrRXZlbnRzSW5wdXRdPik7XG5cbiAgbGV0IGZpbmlzaGVkID0gZmFsc2U7XG5cbiAgZm9yIChjb25zdCBpbnZvY2F0aW9uIG9mIGJlZm9yZVN0b3BJbnZvY2F0aW9ucykge1xuICAgIGNvbnN0IGludm9jYXRpb25fID0gaW52b2NhdGlvbjsgLy8gQ2FwdHVyZSBsb29wIHZhcmlhYmxlIGluIGxvY2FsIGJlY2F1c2Ugb2YgY2xvc3VyZSBzZW1hbnRpY3NcbiAgICBjb25zdCBpc0xhc3QgPSBpbnZvY2F0aW9uID09PSBiZWZvcmVTdG9wSW52b2NhdGlvbnNbYmVmb3JlU3RvcEludm9jYXRpb25zLmxlbmd0aCAtIDFdO1xuICAgIGRlc2NyaWJlU3RhY2tFdmVudHMgPSBkZXNjcmliZVN0YWNrRXZlbnRzLm1vY2tJbXBsZW1lbnRhdGlvbk9uY2UocmVxdWVzdCA9PiB7XG4gICAgICBjb25zdCByZXQgPSBpbnZvY2F0aW9uXyhyZXF1ZXN0KTtcbiAgICAgIGlmIChpc0xhc3QpIHtcbiAgICAgICAgZmluaXNoZWQgPSB0cnVlO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHJldDtcbiAgICB9KTtcbiAgfVxuICBmb3IgKGNvbnN0IGludm9jYXRpb24gb2YgYWZ0ZXJTdG9wSW52b2NhdGlvbnMpIHtcbiAgICBkZXNjcmliZVN0YWNrRXZlbnRzID0gZGVzY3JpYmVTdGFja0V2ZW50cy5tb2NrSW1wbGVtZW50YXRpb25PbmNlKGludm9jYXRpb24pO1xuICB9XG4gIGRlc2NyaWJlU3RhY2tFdmVudHMubW9ja0ltcGxlbWVudGF0aW9uKCgpID0+IHsgcmV0dXJuIHt9OyB9KTtcblxuICBzZGsuc3R1YkNsb3VkRm9ybWF0aW9uKHsgZGVzY3JpYmVTdGFja0V2ZW50cyB9KTtcblxuICBjb25zdCBtb25pdG9yID0gbmV3IFN0YWNrQWN0aXZpdHlNb25pdG9yKHNkay5jbG91ZEZvcm1hdGlvbigpLCAnU3RhY2tOYW1lJywgcHJpbnRlciwgdW5kZWZpbmVkLCBuZXcgRGF0ZShUMTAwKSkuc3RhcnQoKTtcbiAgYXdhaXQgd2FpdEZvckNvbmRpdGlvbigoKSA9PiBmaW5pc2hlZCk7XG4gIGF3YWl0IG1vbml0b3Iuc3RvcCgpO1xufVxuXG5cbmNsYXNzIEZha2VQcmludGVyIGltcGxlbWVudHMgSUFjdGl2aXR5UHJpbnRlciB7XG4gIHB1YmxpYyB1cGRhdGVTbGVlcDogbnVtYmVyID0gMDtcbiAgcHVibGljIHJlYWRvbmx5IGFjdGl2aXRpZXM6IFN0YWNrQWN0aXZpdHlbXSA9IFtdO1xuXG4gIHB1YmxpYyBnZXQgZXZlbnRJZHMoKSB7XG4gICAgcmV0dXJuIHRoaXMuYWN0aXZpdGllcy5tYXAoYSA9PiBhLmV2ZW50LkV2ZW50SWQpO1xuICB9XG5cbiAgcHVibGljIGFkZEFjdGl2aXR5KGFjdGl2aXR5OiBTdGFja0FjdGl2aXR5KTogdm9pZCB7XG4gICAgdGhpcy5hY3Rpdml0aWVzLnB1c2goYWN0aXZpdHkpO1xuICB9XG5cbiAgcHVibGljIHByaW50KCk6IHZvaWQgeyB9XG4gIHB1YmxpYyBzdGFydCgpOiB2b2lkIHsgfVxuICBwdWJsaWMgc3RvcCgpOiB2b2lkIHsgfVxufVxuXG5hc3luYyBmdW5jdGlvbiB3YWl0Rm9yQ29uZGl0aW9uKGNiOiAoKSA9PiBib29sZWFuKTogUHJvbWlzZTx2b2lkPiB7XG4gIHdoaWxlICghY2IoKSkge1xuICAgIGF3YWl0IHNsZWVwKDEwKTtcbiAgfVxufVxuIl19