aws-delivlib
Version:
A fabulous library for defining continuous pipelines for building, testing and releasing code libraries.
117 lines • 17 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.shouldBlockPipeline = void 0;
// eslint-disable-next-line @typescript-eslint/no-require-imports,import/no-extraneous-dependencies
const ical = require('node-ical');
/**
* Evaluates whether a deployment pipeline should have promotions suspended due to the imminent start of a blocked
* time window.
*
* @param ical is an iCal document that describes "blocked" time windows (there needs to be an event only for times
* during which promotions should not happen).
* @param now is the reference time considered when assessing the need to block or not.
* @param advanceMarginSec how many seconds from `now` should be free of any "blocked" time window for the pipeline to
* not be blocked (defaults to 1 hour).
*
* @returns the events that represent the blocked time, or `undefined` if `now` is not "blocked".
*/
function shouldBlockPipeline(icalData, now = new Date(), advanceMarginSec = 3600) {
validateTz();
const events = ical.parseICS(icalData.toString('utf8'));
const blocks = containingEventsWithMargin(events, now, advanceMarginSec);
return blocks.length > 0 ? blocks[0] : undefined;
}
exports.shouldBlockPipeline = shouldBlockPipeline;
/**
* A function to build a CalendarEvent given a start date and a duration.
*
* @param start a start date for the event
* @param duration a duration for the event in milliseconds
* @param summary a summary to apply to the event
*/
function buildEventForDuration(start, duration, summary) {
const end = new Date(start.getTime() + duration);
return {
summary,
start,
end,
datetype: 'date-time',
type: 'VEVENT',
};
}
/**
* If the event is not recurring (i.e. event.rrule is null or undefined), then
* the event will be returned.
*
* If the event is recurring, this method calculates the recurring events surrounding
* the provided date. If the date provided is equal to the start of an event,
* the event for that date and the following event will be returend. If
* CalendarEvent.rrule is not null, then the event is considered recurring.
*
* @param event a calendar event.
* @param date the date for which the previous and next event should be returned.
*/
function flattenEvent(event, date) {
if (event.rrule) {
const events = [];
// Calculate the duration of initial event in the recurring series.
const duration = new Date(event.end).getTime() - new Date(event.start).getTime();
// Obtain the start date of the most recent event in the series, inclusive of
// 'date' and calculate a new event based on the duration of the initial.
const previousEventStart = event.rrule.before(date, true);
if (previousEventStart) {
events.push(buildEventForDuration(previousEventStart, duration, event.summary));
}
// Obtain the start date of the next event in the series, exclusive of
// 'date' and calculate a new event based on the duration of the initial.
const nextEventStart = event.rrule.after(date, false);
if (nextEventStart) {
events.push(buildEventForDuration(nextEventStart, duration, event.summary));
}
return events;
}
else {
return [event];
}
}
function containingEventsWithMargin(events, date, advanceMarginSec) {
const bufferedDate = new Date(date.getTime() + advanceMarginSec * 1000);
return Object.values(events)
.filter(e => e.type === 'VEVENT')
.reduce((arr, e) => {
arr.push(...flattenEvent(e, date));
return arr;
}, [])
.filter(e => overlaps(e, { start: date, end: bufferedDate }));
}
/**
* Checks whether an event occurs within a specified time period, which should match the following:
* |------------------<=========LEFT=========>------------------------->
* <WITHIN LEFT>
* <OVERLAP AT START>
* <OVERLAP AT END>
* <===COMPLETELY INCLUDES LEFT=====>
* |------------------<=========LEFT=========>------------------------->
*
* @param left the first time window.
* @param right the second time window.
*
* @returns true if `left` and `right` overlap
*/
function overlaps(left, right) {
// Neutering out the milliseconds portions, so they don't interfere
[left.start, left.end, right.start, right.end].forEach(d => d.setMilliseconds(0));
return isBetween(right.start, left.start, left.end)
|| isBetween(right.end, left.start, left.end)
|| isBetween(left.start, right.start, right.end)
|| isBetween(left.end, right.start, right.end);
}
function isBetween(date, left, right) {
return date >= left && date <= right;
}
function validateTz() {
if (new Date().getTimezoneOffset() !== 0) {
throw new Error('Because of a bug in "node-ical", this module can only be used when the system time zone is set to UTC. Run this command again with "TZ=UTC"');
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGltZS13aW5kb3cuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJ0aW1lLXdpbmRvdy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFFQSxtR0FBbUc7QUFDbkcsTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLFdBQVcsQ0FBQyxDQUFDO0FBeUJsQzs7Ozs7Ozs7Ozs7R0FXRztBQUNILFNBQWdCLG1CQUFtQixDQUFDLFFBQXlCLEVBQUUsR0FBRyxHQUFHLElBQUksSUFBSSxFQUFFLEVBQUUsZ0JBQWdCLEdBQUcsSUFBSTtJQUN0RyxVQUFVLEVBQUUsQ0FBQztJQUNiLE1BQU0sTUFBTSxHQUFXLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO0lBQ2hFLE1BQU0sTUFBTSxHQUFHLDBCQUEwQixDQUFDLE1BQU0sRUFBRSxHQUFHLEVBQUUsZ0JBQWdCLENBQUMsQ0FBQztJQUN6RSxPQUFPLE1BQU0sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztBQUNuRCxDQUFDO0FBTEQsa0RBS0M7QUFFRDs7Ozs7O0dBTUc7QUFDSCxTQUFTLHFCQUFxQixDQUFDLEtBQVcsRUFBRSxRQUFnQixFQUFFLE9BQWU7SUFDM0UsTUFBTSxHQUFHLEdBQUcsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sRUFBRSxHQUFHLFFBQVEsQ0FBQyxDQUFDO0lBQ2pELE9BQU87UUFDTCxPQUFPO1FBQ1AsS0FBSztRQUNMLEdBQUc7UUFDSCxRQUFRLEVBQUUsV0FBVztRQUNyQixJQUFJLEVBQUUsUUFBUTtLQUNmLENBQUM7QUFDSixDQUFDO0FBRUQ7Ozs7Ozs7Ozs7O0dBV0c7QUFDSCxTQUFTLFlBQVksQ0FBQyxLQUFvQixFQUFFLElBQVU7SUFDcEQsSUFBSSxLQUFLLENBQUMsS0FBSyxFQUFFO1FBQ2YsTUFBTSxNQUFN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QUFFLElBQVUsRUFBRSxLQUFXO0lBQ3BELE9BQU8sSUFBSSxJQUFJLElBQUksSUFBSSxJQUFJLElBQUksS0FBSyxDQUFDO0FBQ3ZDLENBQUM7QUFFRCxTQUFTLFVBQVU7SUFDakIsSUFBSSxJQUFJLElBQUksRUFBRSxDQUFDLGlCQUFpQixFQUFFLEtBQUssQ0FBQyxFQUFFO1FBQ3hDLE1BQU0sSUFBSSxLQUFLLENBQUMsNklBQTZJLENBQUMsQ0FBQztLQUNoSztBQUNILENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgaW1wb3J0L25vLWV4dHJhbmVvdXMtZGVwZW5kZW5jaWVzXG5pbXBvcnQgeyBSUnVsZSB9IGZyb20gJ3JydWxlJztcbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tcmVxdWlyZS1pbXBvcnRzLGltcG9ydC9uby1leHRyYW5lb3VzLWRlcGVuZGVuY2llc1xuY29uc3QgaWNhbCA9IHJlcXVpcmUoJ25vZGUtaWNhbCcpO1xuXG4vKipcbiAqIEEgY2FsZW5kYXIgZXZlbnQgZGVzY3JpYmluZyBhIFwiYmxvY2tlZFwiIHRpbWUgd2luZG93LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIENhbGVuZGFyRXZlbnQge1xuICAvKiogVGhlIGRlc2NyaXB0aW9uIG9mIHRoZSBldmVudCAqL1xuICBzdW1tYXJ5OiBzdHJpbmc7XG4gIC8qKiBUaGUgdGltZSBhdCB3aGljaCB0aGUgYmxvY2sgc3RhcnRzICovXG4gIHN0YXJ0OiBEYXRlO1xuICAvKiogVGhlIHRpbWUgYXQgd2hpY2ggdGhlIGJsb2NrIGVuZHMgKi9cbiAgZW5kOiBEYXRlO1xuICAvKiogVGhlIHRpbWUgYXQgd2hpY2ggdGhlIGV2ZW50IHdhcyBsYXN0IG1vZGlmaWVkLiAqL1xuICBkdHN0YW1wPzogRGF0ZTtcbiAgLyoqIFRoZSB0eXBlIG9mIGEgY2FsZW5kYXIgZXZlbnQgKi9cbiAgdHlwZTogJ1ZFVkVOVCcgfCBzdHJpbmc7XG4gIC8qKiBQYXJhbWV0ZXJzIHRvIHRoZSBldmVudCwgaWYgYW55LiAqL1xuICBwYXJhbXM/OiBhbnlbXTtcbiAgLyoqIFRoZSB0eXBlIG9mIHRoZSBib3VuZGFyaWVzIGZvciB0aGUgZXZlbnQgKi9cbiAgZGF0ZXR5cGU6ICdkYXRlLXRpbWUnO1xuICAvKiogQSByZWN1cnJlbmNlIHJ1bGUgZm9yIHRoZSBldmVudC4gKi9cbiAgcnJ1bGU/OiBSUnVsZTtcbn1cbnR5cGUgRXZlbnRzID0geyBbdXVpZDogc3RyaW5nXTogQ2FsZW5kYXJFdmVudCB9O1xuXG4vKipcbiAqIEV2YWx1YXRlcyB3aGV0aGVyIGEgZGVwbG95bWVudCBwaXBlbGluZSBzaG91bGQgaGF2ZSBwcm9tb3Rpb25zIHN1c3BlbmRlZCBkdWUgdG8gdGhlIGltbWluZW50IHN0YXJ0IG9mIGEgYmxvY2tlZFxuICogdGltZSB3aW5kb3cuXG4gKlxuICogQHBhcmFtIGljYWwgaXMgYW4gaUNhbCBkb2N1bWVudCB0aGF0IGRlc2NyaWJlcyBcImJsb2NrZWRcIiB0aW1lIHdpbmRvd3MgKHRoZXJlIG5lZWRzIHRvIGJlIGFuIGV2ZW50IG9ubHkgZm9yIHRpbWVzXG4gKiAgICAgICAgICAgICBkdXJpbmcgd2hpY2ggcHJvbW90aW9ucyBzaG91bGQgbm90IGhhcHBlbikuXG4gKiBAcGFyYW0gbm93ICBpcyB0aGUgcmVmZXJlbmNlIHRpbWUgY29uc2lkZXJlZCB3aGVuIGFzc2Vzc2luZyB0aGUgbmVlZCB0byBibG9jayBvciBub3QuXG4gKiBAcGFyYW0gYWR2YW5jZU1hcmdpblNlYyBob3cgbWFueSBzZWNvbmRzIGZyb20gYG5vd2Agc2hvdWxkIGJlIGZyZWUgb2YgYW55IFwiYmxvY2tlZFwiIHRpbWUgd2luZG93IGZvciB0aGUgcGlwZWxpbmUgdG9cbiAqICAgICAgICAgICAgIG5vdCBiZSBibG9ja2VkIChkZWZhdWx0cyB0byAxIGhvdXIpLlxuICpcbiAqIEByZXR1cm5zIHRoZSBldmVudHMgdGhhdCByZXByZXNlbnQgdGhlIGJsb2NrZWQgdGltZSwgb3IgYHVuZGVmaW5lZGAgaWYgYG5vd2AgaXMgbm90IFwiYmxvY2tlZFwiLlxuICovXG5leHBvcnQgZnVuY3Rpb24gc2hvdWxkQmxvY2tQaXBlbGluZShpY2FsRGF0YTogc3RyaW5nIHwgQnVmZmVyLCBub3cgPSBuZXcgRGF0ZSgpLCBhZHZhbmNlTWFyZ2luU2VjID0gMzYwMCk6IENhbGVuZGFyRXZlbnQgfCB1bmRlZmluZWQge1xuICB2YWxpZGF0ZVR6KCk7XG4gIGNvbnN0IGV2ZW50czogRXZlbnRzID0gaWNhbC5wYXJzZUlDUyhpY2FsRGF0YS50b1N0cmluZygndXRmOCcpKTtcbiAgY29uc3QgYmxvY2tzID0gY29udGFpbmluZ0V2ZW50c1dpdGhNYXJnaW4oZXZlbnRzLCBub3csIGFkdmFuY2VNYXJnaW5TZWMpO1xuICByZXR1cm4gYmxvY2tzLmxlbmd0aCA+IDAgPyBibG9ja3NbMF0gOiB1bmRlZmluZWQ7XG59XG5cbi8qKlxuICogQSBmdW5jdGlvbiB0byBidWlsZCBhIENhbGVuZGFyRXZlbnQgZ2l2ZW4gYSBzdGFydCBkYXRlIGFuZCBhIGR1cmF0aW9uLlxuICpcbiAqIEBwYXJhbSBzdGFydCBhIHN0YXJ0IGRhdGUgZm9yIHRoZSBldmVudFxuICogQHBhcmFtIGR1cmF0aW9uIGEgZHVyYXRpb24gZm9yIHRoZSBldmVudCBpbiBtaWxsaXNlY29uZHNcbiAqIEBwYXJhbSBzdW1tYXJ5IGEgc3VtbWFyeSB0byBhcHBseSB0byB0aGUgZXZlbnRcbiAqL1xuZnVuY3Rpb24gYnVpbGRFdmVudEZvckR1cmF0aW9uKHN0YXJ0OiBEYXRlLCBkdXJhdGlvbjogbnVtYmVyLCBzdW1tYXJ5OiBzdHJpbmcpOiBDYWxlbmRhckV2ZW50IHtcbiAgY29uc3QgZW5kID0gbmV3IERhdGUoc3RhcnQuZ2V0VGltZSgpICsgZHVyYXRpb24pO1xuICByZXR1cm4ge1xuICAgIHN1bW1hcnksXG4gICAgc3RhcnQsXG4gICAgZW5kLFxuICAgIGRhdGV0eXBlOiAnZGF0ZS10aW1lJyxcbiAgICB0eXBlOiAnVkVWRU5UJyxcbiAgfTtcbn1cblxuLyoqXG4gKiBJZiB0aGUgZXZlbnQgaXMgbm90IHJlY3VycmluZyAoaS5lLiBldmVudC5ycnVsZSBpcyBudWxsIG9yIHVuZGVmaW5lZCksIHRoZW5cbiAqIHRoZSBldmVudCB3aWxsIGJlIHJldHVybmVkLlxuICpcbiAqIElmIHRoZSBldmVudCBpcyByZWN1cnJpbmcsIHRoaXMgbWV0aG9kIGNhbGN1bGF0ZXMgdGhlIHJlY3VycmluZyBldmVudHMgc3Vycm91bmRpbmdcbiAqIHRoZSBwcm92aWRlZCBkYXRlLiBJZiB0aGUgZGF0ZSBwcm92aWRlZCBpcyBlcXVhbCB0byB0aGUgc3RhcnQgb2YgYW4gZXZlbnQsXG4gKiB0aGUgZXZlbnQgZm9yIHRoYXQgZGF0ZSBhbmQgdGhlIGZvbGxvd2luZyBldmVudCB3aWxsIGJlIHJldHVyZW5kLiBJZlxuICogQ2FsZW5kYXJFdmVudC5ycnVsZSBpcyBub3QgbnVsbCwgdGhlbiB0aGUgZXZlbnQgaXMgY29uc2lkZXJlZCByZWN1cnJpbmcuXG4gKlxuICogQHBhcmFtIGV2ZW50IGEgY2FsZW5kYXIgZXZlbnQuXG4gKiBAcGFyYW0gZGF0ZSB0aGUgZGF0ZSBmb3Igd2hpY2ggdGhlIHByZXZpb3VzIGFuZCBuZXh0IGV2ZW50IHNob3VsZCBiZSByZXR1cm5lZC5cbiAqL1xuZnVuY3Rpb24gZmxhdHRlbkV2ZW50KGV2ZW50OiBDYWxlbmRhckV2ZW50LCBkYXRlOiBEYXRlKTogQ2FsZW5kYXJFdmVudFtdIHtcbiAgaWYgKGV2ZW50LnJydWxlKSB7XG4gICAgY29uc3QgZXZlbnRzOiBDYWxlbmRhckV2ZW50W10gPSBbXTtcblxuICAgIC8vIENhbGN1bGF0ZSB0aGUgZHVyYXRpb24gb2YgaW5pdGlhbCBldmVudCBpbiB0aGUgcmVjdXJyaW5nIHNlcmllcy5cbiAgICBjb25zdCBkdXJhdGlvbiA9IG5ldyBEYXRlKGV2ZW50LmVuZCkuZ2V0VGltZSgpIC0gbmV3IERhdGUoZXZlbnQuc3RhcnQpLmdldFRpbWUoKTtcblxuICAgIC8vIE9idGFpbiB0aGUgc3RhcnQgZGF0ZSBvZiB0aGUgbW9zdCByZWNlbnQgZXZlbnQgaW4gdGhlIHNlcmllcywgaW5jbHVzaXZlIG9mXG4gICAgLy8gJ2RhdGUnIGFuZCBjYWxjdWxhdGUgYSBuZXcgZXZlbnQgYmFzZWQgb24gdGhlIGR1cmF0aW9uIG9mIHRoZSBpbml0aWFsLlxuICAgIGNvbnN0IHByZXZpb3VzRXZlbnRTdGFydCA9IGV2ZW50LnJydWxlLmJlZm9yZShkYXRlLCB0cnVlKTtcbiAgICBpZiAocHJldmlvdXNFdmVudFN0YXJ0KSB7XG4gICAgICBldmVudHMucHVzaChidWlsZEV2ZW50Rm9yRHVyYXRpb24ocHJldmlvdXNFdmVudFN0YXJ0LCBkdXJhdGlvbiwgZXZlbnQuc3VtbWFyeSkpO1xuICAgIH1cblxuICAgIC8vIE9idGFpbiB0aGUgc3RhcnQgZGF0ZSBvZiB0aGUgbmV4dCBldmVudCBpbiB0aGUgc2VyaWVzLCBleGNsdXNpdmUgb2ZcbiAgICAvLyAnZGF0ZScgYW5kIGNhbGN1bGF0ZSBhIG5ldyBldmVudCBiYXNlZCBvbiB0aGUgZHVyYXRpb24gb2YgdGhlIGluaXRpYWwuXG4gICAgY29uc3QgbmV4dEV2ZW50U3RhcnQgPSBldmVudC5ycnVsZS5hZnRlcihkYXRlLCBmYWxzZSk7XG4gICAgaWYgKG5leHRFdmVudFN0YXJ0KSB7XG4gICAgICBldmVudHMucHVzaChidWlsZEV2ZW50Rm9yRHVyYXRpb24obmV4dEV2ZW50U3RhcnQsIGR1cmF0aW9uLCBldmVudC5zdW1tYXJ5KSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGV2ZW50cztcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gW2V2ZW50XTtcbiAgfVxufVxuXG5mdW5jdGlvbiBjb250YWluaW5nRXZlbnRzV2l0aE1hcmdpbihldmVudHM6IEV2ZW50cywgZGF0ZTogRGF0ZSwgYWR2YW5jZU1hcmdpblNlYzogbnVtYmVyKTogQ2FsZW5kYXJFdmVudFtdIHtcbiAgY29uc3QgYnVmZmVyZWREYXRlID0gbmV3IERhdGUoZGF0ZS5nZXRUaW1lKCkgKyBhZHZhbmNlTWFyZ2luU2VjICogMV8wMDApO1xuXG4gIHJldHVybiBPYmplY3QudmFsdWVzKGV2ZW50cylcbiAgICAuZmlsdGVyKGUgPT4gZS50eXBlID09PSAnVkVWRU5UJylcbiAgICAucmVkdWNlKChhcnIsIGUpID0+IHtcbiAgICAgIGFyci5wdXNoKC4uLmZsYXR0ZW5FdmVudChlLCBkYXRlKSk7XG4gICAgICByZXR1cm4gYXJyO1xuICAgIH0sIFtdIGFzIENhbGVuZGFyRXZlbnRbXSlcbiAgICAuZmlsdGVyKGUgPT4gb3ZlcmxhcHMoZSwgeyBzdGFydDogZGF0ZSwgZW5kOiBidWZmZXJlZERhdGUgfSkpO1xufVxuXG4vKipcbiAqIENoZWNrcyB3aGV0aGVyIGFuIGV2ZW50IG9jY3VycyB3aXRoaW4gYSBzcGVjaWZpZWQgdGltZSBwZXJpb2QsIHdoaWNoIHNob3VsZCBtYXRjaCB0aGUgZm9sbG93aW5nOlxuICogfC0tLS0tLS0tLS0tLS0tLS0tLTw9PT09PT09PT1MRUZUPT09PT09PT09Pi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0+XG4gKiAgICAgICAgICAgICAgICAgICAgICAgICA8V0lUSElOIExFRlQ+XG4gKiAgICAgICAgICAgIDxPVkVSTEFQIEFUIFNUQVJUPlxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxPVkVSTEFQIEFUIEVORD5cbiAqICAgICAgICAgICAgICAgPD09PUNPTVBMRVRFTFkgSU5DTFVERVMgTEVGVD09PT09PlxuICogfC0tLS0tLS0tLS0tLS0tLS0tLTw9PT09PT09PT1MRUZUPT09PT09PT09Pi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0+XG4gKlxuICogQHBhcmFtIGxlZnQgIHRoZSBmaXJzdCB0aW1lIHdpbmRvdy5cbiAqIEBwYXJhbSByaWdodCB0aGUgc2Vjb25kIHRpbWUgd2luZG93LlxuICpcbiAqIEByZXR1cm5zIHRydWUgaWYgYGxlZnRgIGFuZCBgcmlnaHRgIG92ZXJsYXBcbiAqL1xuZnVuY3Rpb24gb3ZlcmxhcHMobGVmdDogeyBzdGFydDogRGF0ZTsgZW5kOiBEYXRlIH0sIHJpZ2h0OiB7IHN0YXJ0OiBEYXRlOyBlbmQ6IERhdGUgfSk6IGJvb2xlYW4ge1xuICAvLyBOZXV0ZXJpbmcgb3V0IHRoZSBtaWxsaXNlY29uZHMgcG9ydGlvbnMsIHNvIHRoZXkgZG9uJ3QgaW50ZXJmZXJlXG4gIFtsZWZ0LnN0YXJ0LCBsZWZ0LmVuZCwgcmlnaHQuc3RhcnQsIHJpZ2h0LmVuZF0uZm9yRWFjaChkID0+IGQuc2V0TWlsbGlzZWNvbmRzKDApKTtcblxuICByZXR1cm4gaXNCZXR3ZWVuKHJpZ2h0LnN0YXJ0LCBsZWZ0LnN0YXJ0LCBsZWZ0LmVuZClcbiAgICB8fCBpc0JldHdlZW4ocmlnaHQuZW5kLCBsZWZ0LnN0YXJ0LCBsZWZ0LmVuZClcbiAgICB8fCBpc0JldHdlZW4obGVmdC5zdGFydCwgcmlnaHQuc3RhcnQsIHJpZ2h0LmVuZClcbiAgICB8fCBpc0JldHdlZW4obGVmdC5lbmQsIHJpZ2h0LnN0YXJ0LCByaWdodC5lbmQpO1xufVxuXG5mdW5jdGlvbiBpc0JldHdlZW4oZGF0ZTogRGF0ZSwgbGVmdDogRGF0ZSwgcmlnaHQ6IERhdGUpOiBib29sZWFuIHtcbiAgcmV0dXJuIGRhdGUgPj0gbGVmdCAmJiBkYXRlIDw9IHJpZ2h0O1xufVxuXG5mdW5jdGlvbiB2YWxpZGF0ZVR6KCkge1xuICBpZiAobmV3IERhdGUoKS5nZXRUaW1lem9uZU9mZnNldCgpICE9PSAwKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdCZWNhdXNlIG9mIGEgYnVnIGluIFwibm9kZS1pY2FsXCIsIHRoaXMgbW9kdWxlIGNhbiBvbmx5IGJlIHVzZWQgd2hlbiB0aGUgc3lzdGVtIHRpbWUgem9uZSBpcyBzZXQgdG8gVVRDLiBSdW4gdGhpcyBjb21tYW5kIGFnYWluIHdpdGggXCJUWj1VVENcIicpO1xuICB9XG59XG4iXX0=