(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.tc = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i= TimeUnit.MAX) { return (0, error_1.throwError)("Argument.Unit", "invalid time unit ".concat(unit)); } var result = TimeUnit[unit].toLowerCase(); if (amount === 1 || amount === -1) { return result; } else { return result + "s"; } } exports.timeUnitToString = timeUnitToString; /** * Convert a string to a numeric TimeUnit. Case-insensitive; time units can be singular or plural. * @param s * @throws timezonecomplete.Argument.S for invalid string */ function stringToTimeUnit(s) { var trimmed = s.trim().toLowerCase(); for (var i = 0; i < TimeUnit.MAX; ++i) { var other = timeUnitToString(i, 1); if (other === trimmed || (other + "s") === trimmed) { return i; } } return (0, error_1.throwError)("Argument.S", "Unknown time unit string '".concat(s, "'")); } exports.stringToTimeUnit = stringToTimeUnit; /** * @return True iff the given year is a leap year. * @throws timezonecomplete.Argument.Year if year is not integer */ function isLeapYear(year) { (0, assert_1.default)(Number.isInteger(year), "Argument.Year", "Invalid year ".concat(year)); // from Wikipedia: // if year is not divisible by 4 then common year // else if year is not divisible by 100 then leap year // else if year is not divisible by 400 then common year // else leap year if (year % 4 !== 0) { return false; } else if (year % 100 !== 0) { return true; } else if (year % 400 !== 0) { return false; } else { return true; } } exports.isLeapYear = isLeapYear; /** * The days in a given year * @throws timezonecomplete.Argument.Year if year is not integer */ function daysInYear(year) { // rely on validation by isLeapYear return (isLeapYear(year) ? 366 : 365); } exports.daysInYear = daysInYear; /** * @param year The full year * @param month The month 1-12 * @return The number of days in the given month * @throws timezonecomplete.Argument.Year if year is not integer * @throws timezonecomplete.Argument.Month for invalid month number */ function daysInMonth(year, month) { switch (month) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: return 31; case 2: return (isLeapYear(year) ? 29 : 28); case 4: case 6: case 9: case 11: return 30; default: return (0, error_1.throwError)("Argument.Month", "Invalid month: ".concat(month)); } } exports.daysInMonth = daysInMonth; /** * Returns the day of the year of the given date [0..365]. January first is 0. * * @param year The year e.g. 1986 * @param month Month 1-12 * @param day Day of month 1-31 * @throws timezonecomplete.Argument.Year for invalid year (non-integer) * @throws timezonecomplete.Argument.Month for invalid month * @throws timezonecomplete.Argument.Day for invalid day of month */ function dayOfYear(year, month, day) { (0, assert_1.default)(Number.isInteger(year), "Argument.Year", "Year out of range: ".concat(year)); (0, assert_1.default)(Number.isInteger(month) && month >= 1 && month <= 12, "Argument.Month", "Month out of range: ".concat(month)); (0, assert_1.default)(Number.isInteger(day) && day >= 1 && day <= daysInMonth(year, month), "Argument.Day", "day out of range"); var yearDay = 0; for (var i = 1; i < month; i++) { yearDay += daysInMonth(year, i); } yearDay += (day - 1); return yearDay; } exports.dayOfYear = dayOfYear; /** * Returns the last instance of the given weekday in the given month * * @param year The year * @param month the month 1-12 * @param weekDay the desired week day 0-6 * @return the last occurrence of the week day in the month * @throws timezonecomplete.Argument.Year for invalid year (non-integer) * @throws timezonecomplete.Argument.Month for invalid month * @throws timezonecomplete.Argument.WeekDay for invalid week day */ function lastWeekDayOfMonth(year, month, weekDay) { (0, assert_1.default)(Number.isInteger(year), "Argument.Year", "Year out of range: ".concat(year)); (0, assert_1.default)(Number.isInteger(month) && month >= 1 && month <= 12, "Argument.Month", "Month out of range: ".concat(month)); (0, assert_1.default)(Number.isInteger(weekDay) && weekDay >= 0 && weekDay <= 6, "Argument.WeekDay", "weekDay out of range: ".concat(weekDay)); var endOfMonth = new TimeStruct({ year: year, month: month, day: daysInMonth(year, month) }); var endOfMonthWeekDay = weekDayNoLeapSecs(endOfMonth.unixMillis); var diff = weekDay - endOfMonthWeekDay; if (diff > 0) { diff -= 7; } return endOfMonth.components.day + diff; } exports.lastWeekDayOfMonth = lastWeekDayOfMonth; /** * Returns the first instance of the given weekday in the given month * * @param year The year * @param month the month 1-12 * @param weekDay the desired week day * @return the first occurrence of the week day in the month * @throws timezonecomplete.Argument.Year for invalid year (non-integer) * @throws timezonecomplete.Argument.Month for invalid month * @throws timezonecomplete.Argument.WeekDay for invalid week day */ function firstWeekDayOfMonth(year, month, weekDay) { (0, assert_1.default)(Number.isInteger(year), "Argument.Year", "Year out of range: ".concat(year)); (0, assert_1.default)(Number.isInteger(month) && month >= 1 && month <= 12, "Argument.Month", "Month out of range: ".concat(month)); (0, assert_1.default)(Number.isInteger(weekDay) && weekDay >= 0 && weekDay <= 6, "Argument.WeekDay", "weekDay out of range: ".concat(weekDay)); var beginOfMonth = new TimeStruct({ year: year, month: month, day: 1 }); var beginOfMonthWeekDay = weekDayNoLeapSecs(beginOfMonth.unixMillis); var diff = weekDay - beginOfMonthWeekDay; if (diff < 0) { diff += 7; } return beginOfMonth.components.day + diff; } exports.firstWeekDayOfMonth = firstWeekDayOfMonth; /** * Returns the nth instance of the given weekday in the given month; throws if not found * * @param year The year * @param month the month 1-12 * @param weekDay the desired week day * @param dayInstance the desired week day instance, n * @return the first occurrence of the week day in the month * @throws timezonecomplete.Argument.Year for invalid year (non-integer) * @throws timezonecomplete.Argument.Month for invalid month * @throws timezonecomplete.Argument.WeekDay for invalid week day * @throws timezonecomplete.Arugment.DayInstance for invalid day instance (not 1-5) * @throws timezonecomplete.NotFound if the month has no such instance (i.e. 5th instance, where only 4 exist) */ function nthWeekDayOfMonth(year, month, weekDay, dayInstance) { (0, assert_1.default)(Number.isInteger(year), "Argument.Year", "Year out of range: ".concat(year)); (0, assert_1.default)(Number.isInteger(month) && month >= 1 && month <= 12, "Argument.Month", "Month out of range: ".concat(month)); (0, assert_1.default)(Number.isInteger(weekDay) && weekDay >= 0 && weekDay <= 6, "Argument.WeekDay", "weekDay out of range: ".concat(weekDay)); (0, assert_1.default)(Number.isInteger(dayInstance) && dayInstance >= 1 && dayInstance <= 5, "Argument.DayInstance", "dayInstance out of range: ".concat(dayInstance)); var beginOfMonth = new TimeStruct({ year: year, month: month, day: 1 }); var beginOfMonthWeekDay = weekDayNoLeapSecs(beginOfMonth.unixMillis); var diff = weekDay - beginOfMonthWeekDay; if (diff < 0) { diff += 7; } diff += (dayInstance - 1) * 7; (0, assert_1.default)(beginOfMonth.components.day + diff <= daysInMonth(year, month), "NotFound", "The given month has no such day"); return beginOfMonth.components.day + diff; } exports.nthWeekDayOfMonth = nthWeekDayOfMonth; /** * Returns the day-of-month that is on the given weekday and which is >= the given day; throws if not found * @throws timezonecomplete.Argument.Year for invalid year (non-integer) * @throws timezonecomplete.Argument.Month for invalid month * @throws timezonecomplete.Argument.Day for invalid day of month * @throws timezonecomplete.Argument.WeekDay for invalid week day * @throws timezonecomplete.NotFound if the month has no such day */ function weekDayOnOrAfter(year, month, day, weekDay) { (0, assert_1.default)(Number.isInteger(year), "Argument.Year", "Year out of range: ".concat(year)); (0, assert_1.default)(Number.isInteger(month) && month >= 1 && month <= 12, "Argument.Month", "Month out of range: ".concat(month)); (0, assert_1.default)(Number.isInteger(day) && day >= 1 && day <= daysInMonth(year, month), "Argument.Day", "day out of range"); (0, assert_1.default)(Number.isInteger(weekDay) && weekDay >= 0 && weekDay <= 6, "Argument.WeekDay", "weekDay out of range: ".concat(weekDay)); var start = new TimeStruct({ year: year, month: month, day: day }); var startWeekDay = weekDayNoLeapSecs(start.unixMillis); var diff = weekDay - startWeekDay; if (diff < 0) { diff += 7; } (0, assert_1.default)(start.components.day + diff <= daysInMonth(year, month), "NotFound", "The given month has no such weekday"); return start.components.day + diff; } exports.weekDayOnOrAfter = weekDayOnOrAfter; /** * Returns the day-of-month that is on the given weekday and which is <= the given day. * @throws timezonecomplete.Argument.Year for invalid year (non-integer) * @throws timezonecomplete.Argument.Month for invalid month * @throws timezonecomplete.Argument.Day for invalid day of month * @throws timezonecomplete.Argument.WeekDay for invalid week day * @throws timezonecomplete.NotFound if the month has no such day */ function weekDayOnOrBefore(year, month, day, weekDay) { (0, assert_1.default)(Number.isInteger(year), "Argument.Year", "Year out of range: ".concat(year)); (0, assert_1.default)(Number.isInteger(month) && month >= 1 && month <= 12, "Argument.Month", "Month out of range: ".concat(month)); (0, assert_1.default)(Number.isInteger(day) && day >= 1 && day <= daysInMonth(year, month), "Argument.Day", "day out of range"); (0, assert_1.default)(Number.isInteger(weekDay) && weekDay >= 0 && weekDay <= 6, "Argument.WeekDay", "weekDay out of range: ".concat(weekDay)); var start = new TimeStruct({ year: year, month: month, day: day }); var startWeekDay = weekDayNoLeapSecs(start.unixMillis); var diff = weekDay - startWeekDay; if (diff > 0) { diff -= 7; } (0, assert_1.default)(start.components.day + diff >= 1, "NotFound", "The given month has no such weekday"); return start.components.day + diff; } exports.weekDayOnOrBefore = weekDayOnOrBefore; /** * The week of this month. There is no official standard for this, but we assume the same rules for the weekNumber: * week 1 is the week that has the 4th day of the month in it * * @param year The year * @param month The month [1-12] * @param day The day [1-31] * @return Week number [1-5] * @throws timezonecomplete.Argument.Year for invalid year (non-integer) * @throws timezonecomplete.Argument.Month for invalid month * @throws timezonecomplete.Argument.Day for invalid day of month */ function weekOfMonth(year, month, day) { // rely on year/month validation in firstWeekDayOfMonth (0, assert_1.default)(Number.isInteger(day) && day >= 1 && day <= daysInMonth(year, month), "Argument.Day", "day out of range"); var firstThursday = firstWeekDayOfMonth(year, month, WeekDay.Thursday); var firstMonday = firstWeekDayOfMonth(year, month, WeekDay.Monday); // Corner case: check if we are in week 1 or last week of previous month if (day < firstMonday) { if (firstThursday < firstMonday) { // Week 1 return 1; } else { // Last week of previous month if (month > 1) { // Default case return weekOfMonth(year, month - 1, daysInMonth(year, month - 1)); } else { // January return weekOfMonth(year - 1, 12, 31); } } } var lastMonday = lastWeekDayOfMonth(year, month, WeekDay.Monday); var lastThursday = lastWeekDayOfMonth(year, month, WeekDay.Thursday); // Corner case: check if we are in last week or week 1 of previous month if (day >= lastMonday) { if (lastMonday > lastThursday) { // Week 1 of next month return 1; } } // Normal case var result = Math.floor((day - firstMonday) / 7) + 1; if (firstThursday < 4) { result += 1; } return result; } exports.weekOfMonth = weekOfMonth; /** * The week of this month, based on counting calendar weeks. Unlike weekOfMonth() the first day of the month is * always week 1, and no days count as the last week of the previous month. The week number returned can be from 1-6, * as a month can span up to 6 different weeks on the calendar. The first day of the week, i.e. when the week number * increases, is customizable, and defaults to Monday. * * @param year The year * @param month The month [1-12] * @param day The day [1-31] * @param weekStartDay The week day to use as the start of the week * @return Week number [1-6] * @throws timezonecomplete.Argument.Year for invalid year (non-integer) * @throws timezonecomplete.Argument.Month for invalid month * @throws timezonecomplete.Argument.Day for invalid day of month */ function calendarWeekInMonth(year, month, day, weekStartDay) { if (weekStartDay === void 0) { weekStartDay = WeekDay.Monday; } // rely on year/month validation in weekDayOnOrAfter (0, assert_1.default)(Number.isInteger(day) && day >= 1 && day <= daysInMonth(year, month), "Argument.Day", "day out of range"); var firstFullWeekStartDay = weekDayOnOrAfter(year, month, 1, weekStartDay); var result = Math.floor((day - firstFullWeekStartDay + 7) / 7); if (firstFullWeekStartDay > 1) { result++; } return result; } exports.calendarWeekInMonth = calendarWeekInMonth; /** * Returns the weekday instance number in the month for the given date * * @param year The year * @param month The month [1-12] * @param day The day [1-31] * @return Instance number [1-5] * @throws timezonecomplete.Argument.Year for invalid year (non-integer) * @throws timezonecomplete.Argument.Month for invalid month * @throws timezonecomplete.Argument.Day for invalid day of month */ function weekDayInstanceInMonth(year, month, day) { // rely on year/month validation in firstWeekDayOfMonth var weekDay = weekDayNoLeapSecs(new TimeStruct({ year: year, month: month, day: day }).unixMillis); var firstInstanceOfDay = firstWeekDayOfMonth(year, month, weekDay); var result = ((day - firstInstanceOfDay) / 7) + 1; return result; } exports.weekDayInstanceInMonth = weekDayInstanceInMonth; /** * Returns the day-of-year of the Monday of week 1 in the given year. * Note that the result may lie in the previous year, in which case it * will be (much) greater than 4 * @throws timezonecomplete.Argument.Year for invalid year (non-integer) */ function getWeekOneDayOfYear(year) { // relay on weekDayOnOrAfter for year validation // first monday of January, minus one because we want day-of-year var result = weekDayOnOrAfter(year, 1, 1, WeekDay.Monday) - 1; if (result > 3) { // greater than jan 4th result -= 7; if (result < 0) { result += exports.daysInYear(year - 1); } } return result; } /** * The ISO 8601 week number for the given date. Week 1 is the week * that has January 4th in it, and it starts on Monday. * See https://en.wikipedia.org/wiki/ISO_week_date * * @param year Year e.g. 1988 * @param month Month 1-12 * @param day Day of month 1-31 * @return Week number 1-53 * @throws timezonecomplete.Argument.Year for invalid year (non-integer) * @throws timezonecomplete.Argument.Month for invalid month * @throws timezonecomplete.Argument.Day for invalid day of month */ function weekNumber(year, month, day) { var doy = dayOfYear(year, month, day); // check end-of-year corner case: may be week 1 of next year if (doy >= dayOfYear(year, 12, 29)) { var nextYearWeekOne = getWeekOneDayOfYear(year + 1); if (nextYearWeekOne > 4 && nextYearWeekOne <= doy) { return 1; } } // check beginning-of-year corner case var thisYearWeekOne = getWeekOneDayOfYear(year); if (thisYearWeekOne > 4) { // week 1 is at end of last year var weekTwo = thisYearWeekOne + 7 - daysInYear(year - 1); if (doy < weekTwo) { return 1; } else { return Math.floor((doy - weekTwo) / 7) + 2; } } // Week 1 is entirely inside this year. if (doy < thisYearWeekOne) { // The date is part of the last week of prev year. return weekNumber(year - 1, 12, 31); } // normal cases; note that week numbers start from 1 so +1 return Math.floor((doy - thisYearWeekOne) / 7) + 1; } exports.weekNumber = weekNumber; /** * Convert a unix milli timestamp into a TimeT structure. * This does NOT take leap seconds into account. * @throws timezonecomplete.Argument.UnixMillis for non-integer `unixMillis` parameter */ function unixToTimeNoLeapSecs(unixMillis) { (0, assert_1.default)(Number.isInteger(unixMillis), "Argument.UnixMillis", "unixMillis should be an integer number"); var temp = unixMillis; var result = { year: 0, month: 0, day: 0, hour: 0, minute: 0, second: 0, milli: 0 }; var year; var month; if (unixMillis >= 0) { result.milli = math.positiveModulo(temp, 1000); temp = Math.floor(temp / 1000); result.second = math.positiveModulo(temp, 60); temp = Math.floor(temp / 60); result.minute = math.positiveModulo(temp, 60); temp = Math.floor(temp / 60); result.hour = math.positiveModulo(temp, 24); temp = Math.floor(temp / 24); year = 1970; while (temp >= daysInYear(year)) { temp -= daysInYear(year); year++; } result.year = year; month = 1; while (temp >= daysInMonth(year, month)) { temp -= daysInMonth(year, month); month++; } result.month = month; result.day = temp + 1; } else { // Note that a negative number modulo something yields a negative number. // We make it positive by adding the modulo. result.milli = math.positiveModulo(temp, 1000); temp = Math.floor(temp / 1000); result.second = math.positiveModulo(temp, 60); temp = Math.floor(temp / 60); result.minute = math.positiveModulo(temp, 60); temp = Math.floor(temp / 60); result.hour = math.positiveModulo(temp, 24); temp = Math.floor(temp / 24); year = 1969; while (temp < -daysInYear(year)) { temp += daysInYear(year); year--; } result.year = year; month = 12; while (temp < -daysInMonth(year, month)) { temp += daysInMonth(year, month); month--; } result.month = month; result.day = temp + 1 + daysInMonth(year, month); } return result; } exports.unixToTimeNoLeapSecs = unixToTimeNoLeapSecs; /** * Fill you any missing time component parts, defaults are 1970-01-01T00:00:00.000 * @throws timezonecomplete.Argument.Year for invalid year * @throws timezonecomplete.Argument.Month for invalid month * @throws timezonecomplete.Argument.Day for invalid day of month * @throws timezonecomplete.Argument.Hour for invalid hour * @throws timezonecomplete.Argument.Minute for invalid minute * @throws timezonecomplete.Argument.Second for invalid second * @throws timezonecomplete.Argument.Milli for invalid milliseconds */ function normalizeTimeComponents(components) { var input = { year: typeof components.year === "number" ? components.year : 1970, month: typeof components.month === "number" ? components.month : 1, day: typeof components.day === "number" ? components.day : 1, hour: typeof components.hour === "number" ? components.hour : 0, minute: typeof components.minute === "number" ? components.minute : 0, second: typeof components.second === "number" ? components.second : 0, milli: typeof components.milli === "number" ? components.milli : 0, }; (0, assert_1.default)(Number.isInteger(input.year), "Argument.Year", "invalid year ".concat(input.year)); (0, assert_1.default)(Number.isInteger(input.month) && input.month >= 1 && input.month <= 12, "Argument.Month", "invalid month ".concat(input.month)); (0, assert_1.default)(Number.isInteger(input.day) && input.day >= 1 && input.day <= daysInMonth(input.year, input.month), "Argument.Day", "invalid day ".concat(input.day)); (0, assert_1.default)(Number.isInteger(input.hour) && input.hour >= 0 && input.hour <= 23, "Argument.Hour", "invalid hour ".concat(input.hour)); (0, assert_1.default)(Number.isInteger(input.minute) && input.minute >= 0 && input.minute <= 59, "Argument.Minute", "invalid minute ".concat(input.minute)); (0, assert_1.default)(Number.isInteger(input.second) && input.second >= 0 && input.second <= 59, "Argument.Second", "invalid second ".concat(input.second)); (0, assert_1.default)(Number.isInteger(input.milli) && input.milli >= 0 && input.milli <= 999, "Argument.Milli", "invalid milli ".concat(input.milli)); return input; } function timeToUnixNoLeapSecs(a, month, day, hour, minute, second, milli) { var components = (typeof a === "number" ? { year: a, month: month, day: day, hour: hour, minute: minute, second: second, milli: milli } : a); var input = normalizeTimeComponents(components); return input.milli + 1000 * (input.second + input.minute * 60 + input.hour * 3600 + dayOfYear(input.year, input.month, input.day) * 86400 + (input.year - 1970) * 31536000 + Math.floor((input.year - 1969) / 4) * 86400 - Math.floor((input.year - 1901) / 100) * 86400 + Math.floor((input.year - 1900 + 299) / 400) * 86400); } exports.timeToUnixNoLeapSecs = timeToUnixNoLeapSecs; /** * Return the day-of-week. * This does NOT take leap seconds into account. * @throws timezonecomplete.Argument.UnixMillis for invalid `unixMillis` argument */ function weekDayNoLeapSecs(unixMillis) { (0, assert_1.default)(Number.isInteger(unixMillis), "Argument.UnixMillis", "unixMillis should be an integer number"); var epochDay = WeekDay.Thursday; var days = Math.floor(unixMillis / 1000 / 86400); return math.positiveModulo(epochDay + days, 7); } exports.weekDayNoLeapSecs = weekDayNoLeapSecs; /** * N-th second in the day, counting from 0 * @throws timezonecomplete.Argument.Hour for invalid hour * @throws timezonecomplete.Argument.Minute for invalid minute * @throws timezonecomplete.Argument.Second for invalid second */ function secondOfDay(hour, minute, second) { (0, assert_1.default)(Number.isInteger(hour) && hour >= 0 && hour <= 23, "Argument.Hour", "invalid hour ".concat(hour)); (0, assert_1.default)(Number.isInteger(minute) && minute >= 0 && minute <= 59, "Argument.Minute", "invalid minute ".concat(minute)); (0, assert_1.default)(Number.isInteger(second) && second >= 0 && second <= 61, "Argument.Second", "invalid second ".concat(second)); return (((hour * 60) + minute) * 60) + second; } exports.secondOfDay = secondOfDay; /** * Basic representation of a date and time */ var TimeStruct = /** @class */ (function () { /** * Constructor implementation */ function TimeStruct(a) { if (typeof a === "number") { (0, assert_1.default)(Number.isInteger(a), "Argument.UnixMillis", "invalid unix millis ".concat(a)); this._unixMillis = a; } else { (0, assert_1.default)(typeof a === "object" && a !== null, "Argument.Components", "invalid components object"); this._components = normalizeTimeComponents(a); } } /** * Returns a TimeStruct from the given year, month, day etc * * @param year Year e.g. 1970 * @param month Month 1-12 * @param day Day 1-31 * @param hour Hour 0-23 * @param minute Minute 0-59 * @param second Second 0-59 (no leap seconds) * @param milli Millisecond 0-999 * @throws timezonecomplete.Argument.Year for invalid year * @throws timezonecomplete.Argument.Month for invalid month * @throws timezonecomplete.Argument.Day for invalid day of month * @throws timezonecomplete.Argument.Hour for invalid hour * @throws timezonecomplete.Argument.Minute for invalid minute * @throws timezonecomplete.Argument.Second for invalid second * @throws timezonecomplete.Argument.Milli for invalid milliseconds */ TimeStruct.fromComponents = function (year, month, day, hour, minute, second, milli) { return new TimeStruct({ year: year, month: month, day: day, hour: hour, minute: minute, second: second, milli: milli }); }; /** * Create a TimeStruct from a number of unix milliseconds * (backward compatibility) * @throws timezonecomplete.Argument.UnixMillis for non-integer milliseconds */ TimeStruct.fromUnix = function (unixMillis) { return new TimeStruct(unixMillis); }; /** * Create a TimeStruct from a JavaScript date * * @param d The date * @param df Which functions to take (getX() or getUTCX()) * @throws nothing */ TimeStruct.fromDate = function (d, df) { if (df === javascript_1.DateFunctions.Get) { return new TimeStruct({ year: d.getFullYear(), month: d.getMonth() + 1, day: d.getDate(), hour: d.getHours(), minute: d.getMinutes(), second: d.getSeconds(), milli: d.getMilliseconds() }); } else { return new TimeStruct({ year: d.getUTCFullYear(), month: d.getUTCMonth() + 1, day: d.getUTCDate(), hour: d.getUTCHours(), minute: d.getUTCMinutes(), second: d.getUTCSeconds(), milli: d.getUTCMilliseconds() }); } }; /** * Returns a TimeStruct from an ISO 8601 string WITHOUT time zone * @throws timezonecomplete.Argument.S if `s` is not a proper iso string */ TimeStruct.fromString = function (s) { try { var year = 1970; var month = 1; var day = 1; var hour = 0; var minute = 0; var second = 0; var fractionMillis = 0; var lastUnit = TimeUnit.Year; // separate any fractional part var split = s.trim().split("."); (0, assert_1.default)(split.length >= 1 && split.length <= 2, "Argument.S", "Empty string or multiple dots."); // parse main part var isBasicFormat = (s.indexOf("-") === -1); if (isBasicFormat) { (0, assert_1.default)(split[0].match(/^((\d)+)|(\d\d\d\d\d\d\d\dT(\d)+)$/), "Argument.S", "ISO string in basic notation may only contain numbers before the fractional part"); // remove any "T" separator split[0] = split[0].replace("T", ""); (0, assert_1.default)([4, 8, 10, 12, 14].indexOf(split[0].length) !== -1, "Argument.S", "Padding or required components are missing. Note that YYYYMM is not valid per ISO 8601"); if (split[0].length >= 4) { year = parseInt(split[0].substr(0, 4), 10); lastUnit = TimeUnit.Year; } if (split[0].length >= 8) { month = parseInt(split[0].substr(4, 2), 10); day = parseInt(split[0].substr(6, 2), 10); // note that YYYYMM format is disallowed so if month is present, day is too lastUnit = TimeUnit.Day; } if (split[0].length >= 10) { hour = parseInt(split[0].substr(8, 2), 10); lastUnit = TimeUnit.Hour; } if (split[0].length >= 12) { minute = parseInt(split[0].substr(10, 2), 10); lastUnit = TimeUnit.Minute; } if (split[0].length >= 14) { second = parseInt(split[0].substr(12, 2), 10); lastUnit = TimeUnit.Second; } } else { (0, assert_1.default)(split[0].match(/^\d\d\d\d(-\d\d-\d\d((T)?\d\d(\:\d\d(:\d\d)?)?)?)?$/), "Argument.S", "Invalid ISO string"); var dateAndTime = []; if (s.indexOf("T") !== -1) { dateAndTime = split[0].split("T"); } else if (s.length > 10) { dateAndTime = [split[0].substr(0, 10), split[0].substr(10)]; } else { dateAndTime = [split[0], ""]; } (0, assert_1.default)([4, 10].indexOf(dateAndTime[0].length) !== -1, "Argument.S", "Padding or required components are missing. Note that YYYYMM is not valid per ISO 8601"); if (dateAndTime[0].length >= 4) { year = parseInt(dateAndTime[0].substr(0, 4), 10); lastUnit = TimeUnit.Year; } if (dateAndTime[0].length >= 10) { month = parseInt(dateAndTime[0].substr(5, 2), 10); day = parseInt(dateAndTime[0].substr(8, 2), 10); // note that YYYYMM format is disallowed so if month is present, day is too lastUnit = TimeUnit.Day; } if (dateAndTime[1].length >= 2) { hour = parseInt(dateAndTime[1].substr(0, 2), 10); lastUnit = TimeUnit.Hour; } if (dateAndTime[1].length >= 5) { minute = parseInt(dateAndTime[1].substr(3, 2), 10); lastUnit = TimeUnit.Minute; } if (dateAndTime[1].length >= 8) { second = parseInt(dateAndTime[1].substr(6, 2), 10); lastUnit = TimeUnit.Second; } } // parse fractional part if (split.length > 1 && split[1].length > 0) { var fraction = parseFloat("0." + split[1]); switch (lastUnit) { case TimeUnit.Year: fractionMillis = daysInYear(year) * 86400000 * fraction; break; case TimeUnit.Day: fractionMillis = 86400000 * fraction; break; case TimeUnit.Hour: fractionMillis = 3600000 * fraction; break; case TimeUnit.Minute: fractionMillis = 60000 * fraction; break; case TimeUnit.Second: fractionMillis = 1000 * fraction; break; } } // combine main and fractional part year = math.roundSym(year); month = math.roundSym(month); day = math.roundSym(day); hour = math.roundSym(hour); minute = math.roundSym(minute); second = math.roundSym(second); var unixMillis = timeToUnixNoLeapSecs({ year: year, month: month, day: day, hour: hour, minute: minute, second: second }); unixMillis = math.roundSym(unixMillis + fractionMillis); return new TimeStruct(unixMillis); } catch (e) { if ((0, error_1.errorIs)(e, [ "Argument.S", "Argument.Year", "Argument.Month", "Argument.Day", "Argument.Hour", "Argument.Minute", "Argument.Second", "Argument.Milli" ])) { return (0, error_1.throwError)("Argument.S", "Invalid ISO 8601 string: \"".concat(s, "\": ").concat(e.message)); } else { throw e; // programming error } } }; Object.defineProperty(TimeStruct.prototype, "unixMillis", { get: function () { if (this._unixMillis === undefined) { this._unixMillis = timeToUnixNoLeapSecs(this._components); } return this._unixMillis; }, enumerable: false, configurable: true }); Object.defineProperty(TimeStruct.prototype, "components", { get: function () { if (!this._components) { this._components = unixToTimeNoLeapSecs(this._unixMillis); } return this._components; }, enumerable: false, configurable: true }); Object.defineProperty(TimeStruct.prototype, "year", { get: function () { return this.components.year; }, enumerable: false, configurable: true }); Object.defineProperty(TimeStruct.prototype, "month", { get: function () { return this.components.month; }, enumerable: false, configurable: true }); Object.defineProperty(TimeStruct.prototype, "day", { get: function () { return this.components.day; }, enumerable: false, configurable: true }); Object.defineProperty(TimeStruct.prototype, "hour", { get: function () { return this.components.hour; }, enumerable: false, configurable: true }); Object.defineProperty(TimeStruct.prototype, "minute", { get: function () { return this.components.minute; }, enumerable: false, configurable: true }); Object.defineProperty(TimeStruct.prototype, "second", { get: function () { return this.components.second; }, enumerable: false, configurable: true }); Object.defineProperty(TimeStruct.prototype, "milli", { get: function () { return this.components.milli; }, enumerable: false, configurable: true }); /** * The day-of-year 0-365 * @throws nothing */ TimeStruct.prototype.yearDay = function () { return dayOfYear(this.components.year, this.components.month, this.components.day); }; /** * Equality function * @param other * @throws TypeError if other is not an Object */ TimeStruct.prototype.equals = function (other) { return this.valueOf() === other.valueOf(); }; /** * @throws nothing */ TimeStruct.prototype.valueOf = function () { return this.unixMillis; }; /** * @throws nothing */ TimeStruct.prototype.clone = function () { if (this._components) { return new TimeStruct(this._components); } else { return new TimeStruct(this._unixMillis); } }; /** * Validate a timestamp. Filters out non-existing values for all time components * @returns true iff the timestamp is valid * @throws nothing */ TimeStruct.prototype.validate = function () { if (this._components) { return this.components.month >= 1 && this.components.month <= 12 && this.components.day >= 1 && this.components.day <= daysInMonth(this.components.year, this.components.month) && this.components.hour >= 0 && this.components.hour <= 23 && this.components.minute >= 0 && this.components.minute <= 59 && this.components.second >= 0 && this.components.second <= 59 && this.components.milli >= 0 && this.components.milli <= 999; } else { return true; } }; /** * ISO 8601 string YYYY-MM-DDThh:mm:ss.nnn * @throws nothing */ TimeStruct.prototype.toString = function () { return strings.padLeft(this.components.year.toString(10), 4, "0") + "-" + strings.padLeft(this.components.month.toString(10), 2, "0") + "-" + strings.padLeft(this.components.day.toString(10), 2, "0") + "T" + strings.padLeft(this.components.hour.toString(10), 2, "0") + ":" + strings.padLeft(this.components.minute.toString(10), 2, "0") + ":" + strings.padLeft(this.components.second.toString(10), 2, "0") + "." + strings.padLeft(this.components.milli.toString(10), 3, "0"); }; return TimeStruct; }()); exports.TimeStruct = TimeStruct; /** * Binary search * @param array Array to search * @param compare Function that should return < 0 if given element is less than searched element etc * @returns The insertion index of the element to look for * @throws TypeError if arr is not an array * @throws whatever `compare()` throws */ function binaryInsertionIndex(arr, compare) { var minIndex = 0; var maxIndex = arr.length - 1; var currentIndex; var currentElement; // no array / empty array if (!arr) { return 0; } if (arr.length === 0) { return 0; } // out of bounds if (compare(arr[0]) > 0) { return 0; } if (compare(arr[maxIndex]) < 0) { return maxIndex + 1; } // element in range while (minIndex <= maxIndex) { currentIndex = Math.floor((minIndex + maxIndex) / 2); currentElement = arr[currentIndex]; if (compare(currentElement) < 0) { minIndex = currentIndex + 1; } else if (compare(currentElement) > 0) { maxIndex = currentIndex - 1; } else { return currentIndex; } } return maxIndex; } exports.binaryInsertionIndex = binaryInsertionIndex; },{"./assert":1,"./error":5,"./javascript":8,"./math":10,"./strings":13}],3:[function(require,module,exports){ /** * Copyright(c) 2014 ABB Switzerland Ltd. * * Date+time+timezone representation */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.isDateTime = exports.DateTime = exports.now = exports.nowUtc = exports.nowLocal = void 0; var assert_1 = require("./assert"); var basics = require("./basics"); var basics_1 = require("./basics"); var duration_1 = require("./duration"); var error_1 = require("./error"); var format = require("./format"); var javascript_1 = require("./javascript"); var math = require("./math"); var parseFuncs = require("./parse"); var timesource_1 = require("./timesource"); var timezone_1 = require("./timezone"); var tz_database_1 = require("./tz-database"); /** * Current date+time in local time * @throws nothing */ function nowLocal() { return DateTime.nowLocal(); } exports.nowLocal = nowLocal; /** * Current date+time in UTC time * @throws timezonecomplete.NotFound.Zone if the UTC time zone doesn't exist in the time zone database */ function nowUtc() { return DateTime.nowUtc(); } exports.nowUtc = nowUtc; /** * Current date+time in the given time zone * @param timeZone The desired time zone (optional, defaults to UTC). * @throws timezonecomplete.NotFound.Zone if the UTC time zone doesn't exist in the time zone database */ function now(timeZone) { if (timeZone === void 0) { timeZone = timezone_1.TimeZone.utc(); } return DateTime.now(timeZone); } exports.now = now; /** * * @param localTime * @param fromZone * @throws nothing */ function convertToUtc(localTime, fromZone) { if (fromZone) { var offset = fromZone.offsetForZone(localTime); return new basics_1.TimeStruct(localTime.unixMillis - offset * 60000); } else { return localTime.clone(); } } /** * * @param utcTime * @param toZone * @throws nothing */ function convertFromUtc(utcTime, toZone) { /* istanbul ignore else */ if (toZone) { var offset = toZone.offsetForUtc(utcTime); return toZone.normalizeZoneTime(new basics_1.TimeStruct(utcTime.unixMillis + offset * 60000)); } else { return utcTime.clone(); } } /** * DateTime class which is time zone-aware * and which can be mocked for testing purposes. */ var DateTime = /** @class */ (function () { /** * Constructor implementation, @see overrides */ function DateTime(a1, a2, a3, h, m, s, ms, timeZone) { /** * Allow not using instanceof */ this.kind = "DateTime"; switch (typeof (a1)) { case "number": { if (typeof a2 !== "number") { (0, assert_1.default)(a3 === undefined && h === undefined && m === undefined && s === undefined && ms === undefined && timeZone === undefined, "Argument.A3", "for unix timestamp datetime constructor, third through 8th argument must be undefined"); (0, assert_1.default)(a2 === undefined || a2 === null || isTimeZone(a2), "Argument.TimeZone", "DateTime.DateTime(): second arg should be a TimeZone object."); // unix timestamp constructor this._zone = (typeof (a2) === "object" && isTimeZone(a2) ? a2 : undefined); var unixMillis = (0, error_1.convertError)("Argument.UnixMillis", function () { return math.roundSym(a1); }); if (this._zone) { this._zoneDate = this._zone.normalizeZoneTime(new basics_1.TimeStruct(unixMillis)); } else { this._zoneDate = new basics_1.TimeStruct(unixMillis); } } else { // year month day constructor (0, assert_1.default)(typeof (a2) === "number", "Argument.Year", "DateTime.DateTime(): Expect month to be a number."); (0, assert_1.default)(typeof (a3) === "number", "Argument.Month", "DateTime.DateTime(): Expect day to be a number."); (0, assert_1.default)(timeZone === undefined || timeZone === null || isTimeZone(timeZone), "Argument.TimeZone", "DateTime.DateTime(): eighth arg should be a TimeZone object."); var year_1 = a1; var month_1 = a2; var day_1 = a3; var hour_1 = (typeof (h) === "number" ? h : 0); var minute_1 = (typeof (m) === "number" ? m : 0); var second_1 = (typeof (s) === "number" ? s : 0); var milli_1 = (typeof (ms) === "number" ? ms : 0); year_1 = (0, error_1.convertError)("Argument.Year", function () { return math.roundSym(year_1); }); month_1 = (0, error_1.convertError)("Argument.Month", function () { return math.roundSym(month_1); }); day_1 = (0, error_1.convertError)("Argument.Day", function () { return math.roundSym(day_1); }); hour_1 = (0, error_1.convertError)("Argument.Hour", function () { return math.roundSym(hour_1); }); minute_1 = (0, error_1.convertError)("Argument.Minute", function () { return math.roundSym(minute_1); }); second_1 = (0, error_1.convertError)("Argument.Second", function () { return math.roundSym(second_1); }); milli_1 = (0, error_1.convertError)("Argument.Milli", function () { return math.roundSym(milli_1); }); var tm = new basics_1.TimeStruct({ year: year_1, month: month_1, day: day_1, hour: hour_1, minute: minute_1, second: second_1, milli: milli_1 }); this._zone = (typeof (timeZone) === "object" && isTimeZone(timeZone) ? timeZone : undefined); // normalize local time (remove non-existing local time) if (this._zone) { this._zoneDate = this._zone.normalizeZoneTime(tm); } else { this._zoneDate = tm; } } } break; case "string": { if (typeof a2 === "string") { (0, assert_1.default)(h === undefined && m === undefined && s === undefined && ms === undefined && timeZone === undefined, "Argument.A4", "first two arguments are a string, therefore the fourth through 8th argument must be undefined"); (0, assert_1.default)(a3 === undefined || a3 === null || isTimeZone(a3), "Argument.TimeZone", "DateTime.DateTime(): third arg should be a TimeZone object."); // format string given var dateString = a1; var formatString = a2; var zone = void 0; if (typeof a3 === "object" && isTimeZone(a3)) { zone = (a3); } var parsed = parseFuncs.parse(dateString, formatString, zone); this._zoneDate = parsed.time; this._zone = parsed.zone; } else { (0, assert_1.default)(a3 === undefined && h === undefined && m === undefined && s === undefined && ms === undefined && timeZone === undefined, "Argument.A3", "first arguments is a string and the second is not, therefore the third through 8th argument must be undefined"); (0, assert_1.default)(a2 === undefined || a2 === null || isTimeZone(a2), "Argument.TimeZone", "DateTime.DateTime(): second arg should be a TimeZone object."); var givenString = a1.trim(); var ss = DateTime._splitDateFromTimeZone(givenString); (0, assert_1.default)(ss.length === 2, "Argument.S", "Invalid date string given: \"" + a1 + "\""); if (isTimeZone(a2)) { this._zone = (a2); } else { this._zone = (ss[1].trim() ? timezone_1.TimeZone.zone(ss[1]) : undefined); } // use our own ISO parsing because that it platform independent // (free of Date quirks) this._zoneDate = basics_1.TimeStruct.fromString(ss[0]); if (this._zone) { this._zoneDate = this._zone.normalizeZoneTime(this._zoneDate); } } } break; case "object": { if (a1 instanceof Date) { (0, assert_1.default)(h === undefined && m === undefined && s === undefined && ms === undefined && timeZone === undefined, "Argument.A4", "first argument is a Date, therefore the fourth through 8th argument must be undefined"); (0, assert_1.default)(typeof (a2) === "number" && (a2 === javascript_1.DateFunctions.Get || a2 === javascript_1.DateFunctions.GetUTC), "Argument.GetFuncs", "DateTime.DateTime(): for a Date object a DateFunctions must be passed as second argument"); (0, assert_1.default)(a3 === undefined || a3 === null || isTimeZone(a3), "Argument.TimeZone", "DateTime.DateTime(): third arg should be a TimeZone object."); var d = (a1); var dk = (a2); this._zone = (a3 ? a3 : undefined); this._zoneDate = basics_1.TimeStruct.fromDate(d, dk); if (this._zone) { this._zoneDate = this._zone.normalizeZoneTime(this._zoneDate); } } else { // a1 instanceof TimeStruct (0, assert_1.default)(a3 === undefined && h === undefined && m === undefined && s === undefined && ms === undefined && timeZone === undefined, "Argument.A3", "first argument is a TimeStruct, therefore the third through 8th argument must be undefined"); (0, assert_1.default)(a2 === undefined || a2 === null || isTimeZone(a2), "Argument.TimeZone", "expect a TimeZone as second argument"); this._zoneDate = a1.clone(); this._zone = (a2 ? a2 : undefined); } } break; case "undefined": { (0, assert_1.default)(a2 === undefined && a3 === undefined && h === undefined && m === undefined && s === undefined && ms === undefined && timeZone === undefined, "Argument.A2", "first argument is undefined, therefore the rest must also be undefined"); // nothing given, make local datetime this._zone = timezone_1.TimeZone.local(); this._utcDate = basics_1.TimeStruct.fromDate(DateTime.timeSource.now(), javascript_1.DateFunctions.GetUTC); } break; /* istanbul ignore next */ default: /* istanbul ignore next */ throw (0, error_1.error)("Argument.A1", "DateTime.DateTime(): unexpected first argument type."); } } Object.defineProperty(DateTime.prototype, "utcDate", { /** * UTC timestamp (lazily calculated) * @throws nothing */ get: function () { if (!this._utcDate) { this._utcDate = convertToUtc(this._zoneDate, this._zone); } return this._utcDate; }, set: function (value) { this._utcDate = value; this._zoneDate = undefined; }, enumerable: false, configurable: true }); Object.defineProperty(DateTime.prototype, "zoneDate", { /** * Local timestamp (lazily calculated) * @throws nothing */ get: function () { if (!this._zoneDate) { this._zoneDate = convertFromUtc(this._utcDate, this._zone); } return this._zoneDate; }, set: function (value) { this._zoneDate = value; this._utcDate = undefined; }, enumerable: false, configurable: true }); /** * Current date+time in local time * @throws nothing */ DateTime.nowLocal = function () { var n = DateTime.timeSource.now(); return new DateTime(n, javascript_1.DateFunctions.Get, timezone_1.TimeZone.local()); }; /** * Current date+time in UTC time * @throws timezonecomplete.NotFound.Zone if the UTC time zone doesn't exist in the time zone database */ DateTime.nowUtc = function () { return new DateTime(DateTime.timeSource.now(), javascript_1.DateFunctions.GetUTC, timezone_1.TimeZone.utc()); }; /** * Current date+time in the given time zone * @param timeZone The desired time zone (optional, defaults to UTC). * @throws timezonecomplete.NotFound.Zone if the UTC time zone doesn't exist in the time zone database */ DateTime.now = function (timeZone) { if (timeZone === void 0) { timeZone = timezone_1.TimeZone.utc(); } return new DateTime(DateTime.timeSource.now(), javascript_1.DateFunctions.GetUTC, timezone_1.TimeZone.utc()).toZone(timeZone); }; /** * Create a DateTime from a Lotus 123 / Microsoft Excel date-time value * i.e. a double representing days since 1-1-1900 where 1900 is incorrectly seen as leap year * Does not work for dates < 1900 * @param n excel date/time number * @param timeZone Time zone to assume that the excel value is in * @returns a DateTime * @throws timezonecomplete.Argument.N if n is not a finite number * @throws timezonecomplete.Argument.TimeZone if the given time zone is invalid */ DateTime.fromExcel = function (n, timeZone) { (0, assert_1.default)(Number.isFinite(n), "Argument.N", "invalid number"); var unixTimestamp = Math.round((n - 25569) * 24 * 60 * 60 * 1000); return new DateTime(unixTimestamp, timeZone); }; /** * Check whether a given date exists in the given time zone. * E.g. 2015-02-29 returns false (not a leap year) * and 2015-03-29T02:30:00 returns false (daylight saving time missing hour) * and 2015-04-31 returns false (April has 30 days). * By default, pre-1970 dates also return false since the time zone database does not contain accurate info * before that. You can change that with the allowPre1970 flag. * * @param allowPre1970 (optional, default false): return true for pre-1970 dates * @throws nothing */ DateTime.exists = function (year, month, day, hour, minute, second, millisecond, zone, allowPre1970) { if (month === void 0) { month = 1; } if (day === void 0) { day = 1; } if (hour === void 0) { hour = 0; } if (minute === void 0) { minute = 0; } if (second === void 0) { second = 0; } if (millisecond === void 0) { millisecond = 0; } if (allowPre1970 === void 0) { allowPre1970 = false; } if (!isFinite(year) || !isFinite(month) || !isFinite(day) || !isFinite(hour) || !isFinite(minute) || !isFinite(second) || !isFinite(millisecond)) { return false; } if (!allowPre1970 && year < 1970) { return false; } try { var dt = new DateTime(year, month, day, hour, minute, second, millisecond, zone); return (year === dt.year() && month === dt.month() && day === dt.day() && hour === dt.hour() && minute === dt.minute() && second === dt.second() && millisecond === dt.millisecond()); } catch (e) { return false; } }; /** * @return a copy of this object * @throws nothing */ DateTime.prototype.clone = function () { return new DateTime(this.zoneDate, this._zone); }; /** * @return The time zone that the date is in. May be undefined for unaware dates. * @throws nothing */ DateTime.prototype.zone = function () { return this._zone; }; /** * Zone name abbreviation at this time * @param dstDependent (default true) set to false for a DST-agnostic abbreviation * @return The abbreviation * @throws nothing */ DateTime.prototype.zoneAbbreviation = function (dstDependent) { if (dstDependent === void 0) { dstDependent = true; } if (this._zone) { return this._zone.abbreviationForUtc(this.utcDate, dstDependent); } else { return ""; } }; /** * @return the offset including DST w.r.t. UTC in minutes. Returns 0 for unaware dates and for UTC dates. * @throws nothing */ DateTime.prototype.offset = function () { return Math.round((this.zoneDate.unixMillis - this.utcDate.unixMillis) / 60000); }; /** * @return the offset including DST w.r.t. UTC as a Duration. * @throws nothing */ DateTime.prototype.offsetDuration = function () { return duration_1.Duration.milliseconds(Math.round(this.zoneDate.unixMillis - this.utcDate.unixMillis)); }; /** * @return the standard offset WITHOUT DST w.r.t. UTC as a Duration. * @throws nothing */ DateTime.prototype.standardOffsetDuration = function () { if (this._zone) { return duration_1.Duration.minutes(this._zone.standardOffsetForUtc(this.utcDate)); } return duration_1.Duration.minutes(0); }; /** * @return The full year e.g. 2014 * @throws nothing */ DateTime.prototype.year = function () { return this.zoneDate.components.year; }; /** * @return The month 1-12 (note this deviates from JavaScript Date) * @throws nothing */ DateTime.prototype.month = function () { return this.zoneDate.components.month; }; /** * @return The day of the month 1-31 * @throws nothing */ DateTime.prototype.day = function () { return this.zoneDate.components.day; }; /** * @return The hour 0-23 * @throws nothing */ DateTime.prototype.hour = function () { return this.zoneDate.components.hour; }; /** * @return the minutes 0-59 * @throws nothing */ DateTime.prototype.minute = function () { return this.zoneDate.components.minute; }; /** * @return the seconds 0-59 * @throws nothing */ DateTime.prototype.second = function () { return this.zoneDate.components.second; }; /** * @return the milliseconds 0-999 * @throws nothing */ DateTime.prototype.millisecond = function () { return this.zoneDate.components.milli; }; /** * @return the day-of-week (the enum values correspond to JavaScript * week day numbers) * @throws nothing */ DateTime.prototype.weekDay = function () { return basics.weekDayNoLeapSecs(this.zoneDate.unixMillis); }; /** * Returns the day number within the year: Jan 1st has number 0, * Jan 2nd has number 1 etc. * * @return the day-of-year [0-366] * @throws nothing */ DateTime.prototype.dayOfYear = function () { return this.zoneDate.yearDay(); }; /** * The ISO 8601 week number. Week 1 is the week * that has January 4th in it, and it starts on Monday. * See https://en.wikipedia.org/wiki/ISO_week_date * * @return Week number [1-53] * @throws nothing */ DateTime.prototype.weekNumber = function () { return basics.weekNumber(this.year(), this.month(), this.day()); }; /** * The week of this month. There is no official standard for this, * but we assume the same rules for the weekNumber (i.e. * week 1 is the week that has the 4th day of the month in it) * * @return Week number [1-5] * @throws nothing */ DateTime.prototype.weekOfMonth = function () { return basics.weekOfMonth(this.year(), this.month(), this.day()); }; /** * Returns the number of seconds that have passed on the current day * Does not consider leap seconds * * @return seconds [0-86399] * @throws nothing */ DateTime.prototype.secondOfDay = function () { return basics.secondOfDay(this.hour(), this.minute(), this.second()); }; /** * @return Milliseconds since 1970-01-01T00:00:00.000Z * @throws nothing */ DateTime.prototype.unixUtcMillis = function () { return this.utcDate.unixMillis; }; /** * @return The full year e.g. 2014 * @throws nothing */ DateTime.prototype.utcYear = function () { return this.utcDate.components.year; }; /** * @return The UTC month 1-12 (note this deviates from JavaScript Date) * @throws nothing */ DateTime.prototype.utcMonth = function () { return this.utcDate.components.month; }; /** * @return The UTC day of the month 1-31 * @throws nothing */ DateTime.prototype.utcDay = function () { return this.utcDate.components.day; }; /** * @return The UTC hour 0-23 * @throws nothing */ DateTime.prototype.utcHour = function () { return this.utcDate.components.hour; }; /** * @return The UTC minutes 0-59 * @throws nothing */ DateTime.prototype.utcMinute = function () { return this.utcDate.components.minute; }; /** * @return The UTC seconds 0-59 * @throws nothing */ DateTime.prototype.utcSecond = function () { return this.utcDate.components.second; }; /** * Returns the UTC day number within the year: Jan 1st has number 0, * Jan 2nd has number 1 etc. * * @return the day-of-year [0-366] * @throws nothing */ DateTime.prototype.utcDayOfYear = function () { return basics.dayOfYear(this.utcYear(), this.utcMonth(), this.utcDay()); }; /** * @return The UTC milliseconds 0-999 * @throws nothing */ DateTime.prototype.utcMillisecond = function () { return this.utcDate.components.milli; }; /** * @return the UTC day-of-week (the enum values correspond to JavaScript * week day numbers) * @throws nothing */ DateTime.prototype.utcWeekDay = function () { return basics.weekDayNoLeapSecs(this.utcDate.unixMillis); }; /** * The ISO 8601 UTC week number. Week 1 is the week * that has January 4th in it, and it starts on Monday. * See https://en.wikipedia.org/wiki/ISO_week_date * * @return Week number [1-53] * @throws nothing */ DateTime.prototype.utcWeekNumber = function () { return basics.weekNumber(this.utcYear(), this.utcMonth(), this.utcDay()); }; /** * The week of this month. There is no official standard for this, * but we assume the same rules for the weekNumber (i.e. * week 1 is the week that has the 4th day of the month in it) * * @return Week number [1-5] * @throws nothing */ DateTime.prototype.utcWeekOfMonth = function () { return basics.weekOfMonth(this.utcYear(), this.utcMonth(), this.utcDay()); }; /** * Returns the number of seconds that have passed on the current day * Does not consider leap seconds * * @return seconds [0-86399] * @throws nothing */ DateTime.prototype.utcSecondOfDay = function () { return basics.secondOfDay(this.utcHour(), this.utcMinute(), this.utcSecond()); }; /** * Returns a new DateTime which is the date+time reinterpreted as * in the new zone. So e.g. 08:00 America/Chicago can be set to 08:00 Europe/Brussels. * No conversion is done, the value is just assumed to be in a different zone. * Works for naive and aware dates. The new zone may be null. * * @param zone The new time zone * @return A new DateTime with the original timestamp and the new zone. * @throws nothing */ DateTime.prototype.withZone = function (zone) { return new DateTime(this.year(), this.month(), this.day(), this.hour(), this.minute(), this.second(), this.millisecond(), zone); }; /** * Convert this date to the given time zone (in-place). * @return this (for chaining) * @throws timezonecomplete.UnawareToAwareConversion if you try to convert a datetime without a zone to a datetime with a zone */ DateTime.prototype.convert = function (zone) { if (zone) { if (!this._zone) { // if-statement satisfies the compiler return (0, error_1.throwError)("UnawareToAwareConversion", "DateTime.toZone(): Cannot convert unaware date to an aware date"); } else if (this._zone.equals(zone)) { this._zone = zone; // still assign, because zones may be equal but not identical (UTC/GMT/+00) } else { if (!this._utcDate) { this._utcDate = convertToUtc(this._zoneDate, this._zone); // cause zone -> utc conversion } this._zone = zone; this._zoneDate = undefined; } } else { if (!this._zone) { return this; } if (!this._zoneDate) { this._zoneDate = convertFromUtc(this._utcDate, this._zone); } this._zone = undefined; this._utcDate = undefined; // cause later zone -> utc conversion } return this; }; /** * Returns this date converted to the given time zone. * Unaware dates can only be converted to unaware dates (clone) * Converting an unaware date to an aware date throws an exception. Use the constructor * if you really need to do that. * * @param zone The new time zone. This may be null or undefined to create unaware date. * @return The converted date * @throws timezonecomplete.UnawareToAwareConversion if you try to convert a naive datetime to an aware one. */ DateTime.prototype.toZone = function (zone) { if (zone) { (0, assert_1.default)(this._zone, "UnawareToAwareConversion", "DateTime.toZone(): Cannot convert unaware date to an aware date"); var result = new DateTime(); result.utcDate = this.utcDate; result._zone = zone; return result; } else { return new DateTime(this.zoneDate, undefined); } }; /** * Convert to JavaScript date with the zone time in the getX() methods. * Unless the timezone is local, the Date.getUTCX() methods will NOT be correct. * This is because Date calculates getUTCX() from getX() applying local time zone. * @throws nothing */ DateTime.prototype.toDate = function () { return new Date(this.year(), this.month() - 1, this.day(), this.hour(), this.minute(), this.second(), this.millisecond()); }; /** * Create an Excel timestamp for this datetime converted to the given zone. * Does not work for dates < 1900 * @param timeZone Optional. Zone to convert to, default the zone the datetime is already in. * @return an Excel date/time number i.e. days since 1-1-1900 where 1900 is incorrectly seen as leap year * @throws timezonecomplete.UnawareToAwareConversion if you try to convert a naive datetime to an aware one. */ DateTime.prototype.toExcel = function (timeZone) { var dt = this; if (timeZone && (!this._zone || !timeZone.equals(this._zone))) { dt = this.toZone(timeZone); } var offsetMillis = dt.offset() * 60 * 1000; var unixTimestamp = dt.unixUtcMillis(); return this._unixTimeStampToExcel(unixTimestamp + offsetMillis); }; /** * Create an Excel timestamp for this datetime converted to UTC * Does not work for dates < 1900 * @return an Excel date/time number i.e. days since 1-1-1900 where 1900 is incorrectly seen as leap year * @throws nothing */ DateTime.prototype.toUtcExcel = function () { var unixTimestamp = this.unixUtcMillis(); return this._unixTimeStampToExcel(unixTimestamp); }; /** * * @param n * @throws nothing */ DateTime.prototype._unixTimeStampToExcel = function (n) { var result = ((n) / (24 * 60 * 60 * 1000)) + 25569; // round to nearest millisecond var msecs = result / (1 / 86400000); return Math.round(msecs) * (1 / 86400000); }; /** * Implementation. */ DateTime.prototype.add = function (a1, unit) { var amount; var u; if (typeof (a1) === "object") { var duration = (a1); amount = duration.amount(); u = duration.unit(); } else { amount = (a1); u = unit; } var utcTm = this._addToTimeStruct(this.utcDate, amount, u); return new DateTime(utcTm, timezone_1.TimeZone.utc()).toZone(this._zone); }; DateTime.prototype.addLocal = function (a1, unit) { var amount; var u; if (typeof (a1) === "object") { var duration = (a1); amount = duration.amount(); u = duration.unit(); } else { amount = (a1); u = unit; } var localTm = this._addToTimeStruct(this.zoneDate, amount, u); if (this._zone) { var direction = (amount >= 0 ? tz_database_1.NormalizeOption.Up : tz_database_1.NormalizeOption.Down); var normalized = this._zone.normalizeZoneTime(localTm, direction); return new DateTime(normalized, this._zone); } else { return new DateTime(localTm, undefined); } }; /** * Add an amount of time to the given time struct. Note: does not normalize. * Keeps lower unit fields the same where possible, clamps day to end-of-month if * necessary. * @throws Argument.Amount if amount is not finite or if it's not an integer and you're adding months or years * @throws Argument.Unit for invalid time unit */ DateTime.prototype._addToTimeStruct = function (tm, amount, unit) { (0, assert_1.default)(Number.isFinite(amount), "Argument.Amount", "amount must be a finite number"); var year; var month; var day; var hour; var minute; var second; var milli; switch (unit) { case basics_1.TimeUnit.Millisecond: return new basics_1.TimeStruct(math.roundSym(tm.unixMillis + amount)); case basics_1.TimeUnit.Second: return new basics_1.TimeStruct(math.roundSym(tm.unixMillis + amount * 1000)); case basics_1.TimeUnit.Minute: // todo more intelligent approach needed when implementing leap seconds return new basics_1.TimeStruct(math.roundSym(tm.unixMillis + amount * 60000)); case basics_1.TimeUnit.Hour: // todo more intelligent approach needed when implementing leap seconds return new basics_1.TimeStruct(math.roundSym(tm.unixMillis + amount * 3600000)); case basics_1.TimeUnit.Day: // todo more intelligent approach needed when implementing leap seconds return new basics_1.TimeStruct(math.roundSym(tm.unixMillis + amount * 86400000)); case basics_1.TimeUnit.Week: // todo more intelligent approach needed when implementing leap seconds return new basics_1.TimeStruct(math.roundSym(tm.unixMillis + amount * 7 * 86400000)); case basics_1.TimeUnit.Month: { (0, assert_1.default)(math.isInt(amount), "Argument.Amount", "Cannot add/sub a non-integer amount of months"); // keep the day-of-month the same (clamp to end-of-month) if (amount >= 0) { year = tm.components.year + Math.ceil((amount - (12 - tm.components.month)) / 12); month = 1 + math.positiveModulo((tm.components.month - 1 + Math.floor(amount)), 12); } else { year = tm.components.year + Math.floor((amount + (tm.components.month - 1)) / 12); month = 1 + math.positiveModulo((tm.components.month - 1 + Math.ceil(amount)), 12); } day = Math.min(tm.components.day, basics.daysInMonth(year, month)); hour = tm.components.hour; minute = tm.components.minute; second = tm.components.second; milli = tm.components.milli; return new basics_1.TimeStruct({ year: year, month: month, day: day, hour: hour, minute: minute, second: second, milli: milli }); } case basics_1.TimeUnit.Year: { (0, assert_1.default)(math.isInt(amount), "Argument.Amount", "Cannot add/sub a non-integer amount of years"); year = tm.components.year + amount; month = tm.components.month; day = Math.min(tm.components.day, basics.daysInMonth(year, month)); hour = tm.components.hour; minute = tm.components.minute; second = tm.components.second; milli = tm.components.milli; return new basics_1.TimeStruct({ year: year, month: month, day: day, hour: hour, minute: minute, second: second, milli: milli }); } /* istanbul ignore next */ default: /* istanbul ignore next */ return (0, error_1.throwError)("Argument.Unit", "invalid time unit"); } }; DateTime.prototype.sub = function (a1, unit) { if (typeof a1 === "number") { var amount = a1; return this.add(-1 * amount, unit); } else { var duration = a1; return this.add(duration.multiply(-1)); } }; DateTime.prototype.subLocal = function (a1, unit) { if (typeof a1 === "number") { return this.addLocal(-1 * a1, unit); } else { return this.addLocal(a1.multiply(-1)); } }; /** * Time difference between two DateTimes * @return this - other * @throws nothing */ DateTime.prototype.diff = function (other) { return new duration_1.Duration(this.utcDate.unixMillis - other.utcDate.unixMillis); }; /** * Chops off the time part, yields the same date at 00:00:00.000 * @return a new DateTime * @throws nothing */ DateTime.prototype.startOfDay = function () { return new DateTime(this.year(), this.month(), this.day(), 0, 0, 0, 0, this.zone()); }; /** * Returns the first day of the month at 00:00:00 * @return a new DateTime * @throws nothing */ DateTime.prototype.startOfMonth = function () { return new DateTime(this.year(), this.month(), 1, 0, 0, 0, 0, this.zone()); }; /** * Returns the first day of the year at 00:00:00 * @return a new DateTime * @throws nothing */ DateTime.prototype.startOfYear = function () { return new DateTime(this.year(), 1, 1, 0, 0, 0, 0, this.zone()); }; /** * @return True iff (this < other) * @throws nothing */ DateTime.prototype.lessThan = function (other) { return this.utcDate.unixMillis < other.utcDate.unixMillis; }; /** * @return True iff (this <= other) * @throws nothing */ DateTime.prototype.lessEqual = function (other) { return this.utcDate.unixMillis <= other.utcDate.unixMillis; }; /** * @return True iff this and other represent the same moment in time in UTC * @throws nothing */ DateTime.prototype.equals = function (other) { return this.utcDate.equals(other.utcDate); }; /** * @return True iff this and other represent the same time and the same zone * @throws nothing */ DateTime.prototype.identical = function (other) { return !!(this.zoneDate.equals(other.zoneDate) && (!this._zone) === (!other._zone) && ((!this._zone && !other._zone) || (this._zone && other._zone && this._zone.identical(other._zone)))); }; /** * @return True iff this > other * @throws nothing */ DateTime.prototype.greaterThan = function (other) { return this.utcDate.unixMillis > other.utcDate.unixMillis; }; /** * @return True iff this >= other * @throws nothing */ DateTime.prototype.greaterEqual = function (other) { return this.utcDate.unixMillis >= other.utcDate.unixMillis; }; /** * @return The minimum of this and other * @throws nothing */ DateTime.prototype.min = function (other) { if (this.lessThan(other)) { return this.clone(); } return other.clone(); }; /** * @return The maximum of this and other * @throws nothing */ DateTime.prototype.max = function (other) { if (this.greaterThan(other)) { return this.clone(); } return other.clone(); }; /** * Proper ISO 8601 format string with any IANA zone converted to ISO offset * E.g. "2014-01-01T23:15:33+01:00" for Europe/Amsterdam * Unaware dates have no zone information at the end. * @throws nothing */ DateTime.prototype.toIsoString = function () { var s = this.zoneDate.toString(); if (this._zone) { return s + timezone_1.TimeZone.offsetToString(this.offset()); // convert IANA name to offset } else { return s; // no zone present } }; /** * Convert to UTC and then return ISO string ending in 'Z'. This is equivalent to Date#toISOString() * e.g. "2014-01-01T23:15:33 Europe/Amsterdam" becomes "2014-01-01T22:15:33Z". * Unaware dates are assumed to be in UTC * @throws timezonecomplete.NotFound.Zone if the UTC time zone doesn't exist in the time zone database */ DateTime.prototype.toUtcIsoString = function () { if (this._zone) { return this.toZone(timezone_1.TimeZone.utc()).format("yyyy-MM-ddTHH:mm:ss.SSSZZZZZ"); } else { return this.withZone(timezone_1.TimeZone.utc()).format("yyyy-MM-ddTHH:mm:ss.SSSZZZZZ"); } }; /** * Return a string representation of the DateTime according to the * specified format. See LDML.md for supported formats. * * @param formatString The format specification (e.g. "dd/MM/yyyy HH:mm:ss") * @param locale Optional, non-english format month names etc. * @return The string representation of this DateTime * @throws timezonecomplete.Argument.FormatString for invalid format pattern */ DateTime.prototype.format = function (formatString, locale) { return format.format(this.zoneDate, this.utcDate, this._zone, formatString, locale); }; /** * Parse a date in a given format * @param s the string to parse * @param format the format the string is in. See LDML.md for supported formats. * @param zone Optional, the zone to add (if no zone is given in the string) * @param locale Optional, different settings for constants like 'AM' etc * @param allowTrailing Allow trailing characters in the source string * @throws timezonecomplete.ParseError if the given dateTimeString is wrong or not according to the pattern * @throws timezonecomplete.Argument.FormatString if the given format string is invalid */ DateTime.parse = function (s, format, zone, locale, allowTrailing) { var parsed = parseFuncs.parse(s, format, zone, allowTrailing || false, locale); try { return new DateTime(parsed.time, parsed.zone); } catch (e) { if (!(0, error_1.errorIs)(e, "InvalidTimeZoneData")) { e = (0, error_1.error)("ParseError", e.message); } throw e; } }; /** * Modified ISO 8601 format string with IANA name if applicable. * E.g. "2014-01-01T23:15:33.000 Europe/Amsterdam" * @throws nothing */ DateTime.prototype.toString = function () { var s = this.zoneDate.toString(); if (this._zone) { if (this._zone.kind() !== timezone_1.TimeZoneKind.Offset) { return s + " " + this._zone.toString(); // separate IANA name or "localtime" with a space } else { return s + this._zone.toString(); // do not separate ISO zone } } else { return s; // no zone present } }; /** * The valueOf() method returns the primitive value of the specified object. * @throws nothing */ DateTime.prototype.valueOf = function () { return this.unixUtcMillis(); }; /** * Modified ISO 8601 format string in UTC without time zone info * @throws nothing */ DateTime.prototype.toUtcString = function () { return this.utcDate.toString(); }; /** * Split a combined ISO datetime and timezone into datetime and timezone * @throws nothing */ DateTime._splitDateFromTimeZone = function (s) { var trimmed = s.trim(); var result = ["", ""]; var index = trimmed.lastIndexOf("without DST"); if (index > -1) { var result_1 = DateTime._splitDateFromTimeZone(s.slice(0, index - 1)); result_1[1] += " without DST"; return result_1; } index = trimmed.lastIndexOf(" "); if (index > -1) { result[0] = trimmed.substr(0, index); result[1] = trimmed.substr(index + 1); return result; } index = trimmed.lastIndexOf("Z"); if (index > -1) { result[0] = trimmed.substr(0, index); result[1] = trimmed.substr(index, 1); return result; } index = trimmed.lastIndexOf("+"); if (index > -1) { result[0] = trimmed.substr(0, index); result[1] = trimmed.substr(index); return result; } index = trimmed.lastIndexOf("-"); if (index < 8) { index = -1; // any "-" we found was a date separator } if (index > -1) { result[0] = trimmed.substr(0, index); result[1] = trimmed.substr(index); return result; } result[0] = trimmed; return result; }; /** * Actual time source in use. Setting this property allows to * fake time in tests. DateTime.nowLocal() and DateTime.nowUtc() * use this property for obtaining the current time. */ DateTime.timeSource = new timesource_1.RealTimeSource(); return DateTime; }()); exports.DateTime = DateTime; /** * Checks whether `a` is similar to a TimeZone without using the instanceof operator. * It checks for the availability of the functions used in the DateTime implementation * @param a the object to check * @returns a is TimeZone-like * @throws nothing */ function isTimeZone(a) { if (a && typeof a === "object") { if (typeof a.normalizeZoneTime === "function" && typeof a.abbreviationForUtc === "function" && typeof a.standardOffsetForUtc === "function" && typeof a.identical === "function" && typeof a.equals === "function" && typeof a.kind === "function" && typeof a.clone === "function") { return true; } } return false; } /** * Checks if a given object is of type DateTime. Note that it does not work for sub classes. However, use this to be robust * against different versions of the library in one process instead of instanceof * @param value Value to check * @throws nothing */ function isDateTime(value) { return typeof value === "object" && value !== null && value.kind === "DateTime"; } exports.isDateTime = isDateTime; },{"./assert":1,"./basics":2,"./duration":4,"./error":5,"./format":6,"./javascript":8,"./math":10,"./parse":11,"./timesource":14,"./timezone":15,"./tz-database":17}],4:[function(require,module,exports){ /** * Copyright(c) 2014 ABB Switzerland Ltd. * * Time duration */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.isDuration = exports.Duration = exports.milliseconds = exports.seconds = exports.minutes = exports.hours = exports.days = exports.months = exports.years = void 0; var assert_1 = require("./assert"); var basics_1 = require("./basics"); var basics = require("./basics"); var strings = require("./strings"); /** * Construct a time duration * @param n Number of years (may be fractional or negative) * @return A duration of n years * @throws timezonecomplete.Argument.Amount if n is not a finite number */ function years(n) { return Duration.years(n); } exports.years = years; /** * Construct a time duration * @param n Number of months (may be fractional or negative) * @return A duration of n months * @throws timezonecomplete.Argument.Amount if n is not a finite number */ function months(n) { return Duration.months(n); } exports.months = months; /** * Construct a time duration * @param n Number of days (may be fractional or negative) * @return A duration of n days * @throws timezonecomplete.Argument.Amount if n is not a finite number */ function days(n) { return Duration.days(n); } exports.days = days; /** * Construct a time duration * @param n Number of hours (may be fractional or negative) * @return A duration of n hours * @throws timezonecomplete.Argument.Amount if n is not a finite number */ function hours(n) { return Duration.hours(n); } exports.hours = hours; /** * Construct a time duration * @param n Number of minutes (may be fractional or negative) * @return A duration of n minutes * @throws timezonecomplete.Argument.Amount if n is not a finite number */ function minutes(n) { return Duration.minutes(n); } exports.minutes = minutes; /** * Construct a time duration * @param n Number of seconds (may be fractional or negative) * @return A duration of n seconds * @throws timezonecomplete.Argument.Amount if n is not a finite number */ function seconds(n) { return Duration.seconds(n); } exports.seconds = seconds; /** * Construct a time duration * @param n Number of milliseconds (may be fractional or negative) * @return A duration of n milliseconds * @throws timezonecomplete.Argument.Amount if n is not a finite number */ function milliseconds(n) { return Duration.milliseconds(n); } exports.milliseconds = milliseconds; /** * Time duration which is represented as an amount and a unit e.g. * '1 Month' or '166 Seconds'. The unit is preserved through calculations. * * It has two sets of getter functions: * - second(), minute(), hour() etc, singular form: these can be used to create string representations. * These return a part of your string representation. E.g. for 2500 milliseconds, the millisecond() part would be 500 * - seconds(), minutes(), hours() etc, plural form: these return the total amount represented in the corresponding unit. */ var Duration = /** @class */ (function () { /** * Constructor implementation */ function Duration(i1, unit) { /** * Allow not using instanceof */ this.kind = "Duration"; if (typeof i1 === "number") { // amount+unit constructor var amount = i1; (0, assert_1.default)(Number.isFinite(amount), "Argument.Amount", "amount should be finite: ".concat(amount)); this._amount = amount; this._unit = (typeof unit === "number" ? unit : basics_1.TimeUnit.Millisecond); (0, assert_1.default)(Number.isInteger(this._unit) && this._unit >= 0 && this._unit < basics_1.TimeUnit.MAX, "Argument.Unit", "Invalid time unit ".concat(this._unit)); } else if (typeof i1 === "string") { // string constructor var s = i1; var trimmed = s.trim(); if (trimmed.match(/^-?\d\d?(:\d\d?(:\d\d?(.\d\d?\d?)?)?)?$/)) { var sign = 1; var hours_1 = 0; var minutes_1 = 0; var seconds_1 = 0; var milliseconds_1 = 0; var parts = trimmed.split(":"); (0, assert_1.default)(parts.length > 0 && parts.length < 4, "Argument.S", "Not a proper time duration string: \"" + trimmed + "\""); if (trimmed.charAt(0) === "-") { sign = -1; parts[0] = parts[0].substr(1); } if (parts.length > 0) { hours_1 = +parts[0]; } if (parts.length > 1) { minutes_1 = +parts[1]; } if (parts.length > 2) { var secondParts = parts[2].split("."); seconds_1 = +secondParts[0]; if (secondParts.length > 1) { milliseconds_1 = +strings.padRight(secondParts[1], 3, "0"); } } var amountMsec = sign * Math.round(milliseconds_1 + 1000 * seconds_1 + 60000 * minutes_1 + 3600000 * hours_1); // find lowest non-zero number and take that as unit if (milliseconds_1 !== 0) { this._unit = basics_1.TimeUnit.Millisecond; } else if (seconds_1 !== 0) { this._unit = basics_1.TimeUnit.Second; } else if (minutes_1 !== 0) { this._unit = basics_1.TimeUnit.Minute; } else if (hours_1 !== 0) { this._unit = basics_1.TimeUnit.Hour; } else { this._unit = basics_1.TimeUnit.Millisecond; } this._amount = amountMsec / basics.timeUnitToMilliseconds(this._unit); } else { var split = trimmed.toLowerCase().split(" "); (0, assert_1.default)(split.length === 2, "Argument.S", "Invalid time string '".concat(s, "'")); var amount = parseFloat(split[0]); (0, assert_1.default)(Number.isFinite(amount), "Argument.S", "Invalid time string '".concat(s, "', cannot parse amount")); this._amount = amount; this._unit = basics.stringToTimeUnit(split[1]); } } else if (i1 === undefined && unit === undefined) { // default constructor this._amount = 0; this._unit = basics_1.TimeUnit.Millisecond; } else { (0, assert_1.default)(false, "Argument.Amount", "invalid constructor arguments"); } } /** * Construct a time duration * @param amount Number of years (may be fractional or negative) * @return A duration of n years * @throws timezonecomplete.Argument.Amount if n is not a finite number */ Duration.years = function (amount) { return new Duration(amount, basics_1.TimeUnit.Year); }; /** * Construct a time duration * @param amount Number of months (may be fractional or negative) * @return A duration of n months * @throws timezonecomplete.Argument.Amount if n is not a finite number */ Duration.months = function (amount) { return new Duration(amount, basics_1.TimeUnit.Month); }; /** * Construct a time duration * @param amount Number of days (may be fractional or negative) * @return A duration of n days * @throws timezonecomplete.Argument.Amount if n is not a finite number */ Duration.days = function (amount) { return new Duration(amount, basics_1.TimeUnit.Day); }; /** * Construct a time duration * @param amount Number of hours (may be fractional or negative) * @return A duration of n hours * @throws timezonecomplete.Argument.Amount if n is not a finite number */ Duration.hours = function (amount) { return new Duration(amount, basics_1.TimeUnit.Hour); }; /** * Construct a time duration * @param amount Number of minutes (may be fractional or negative) * @return A duration of n minutes * @throws timezonecomplete.Argument.Amount if n is not a finite number */ Duration.minutes = function (amount) { return new Duration(amount, basics_1.TimeUnit.Minute); }; /** * Construct a time duration * @param amount Number of seconds (may be fractional or negative) * @return A duration of n seconds * @throws timezonecomplete.Argument.Amount if n is not a finite number */ Duration.seconds = function (amount) { return new Duration(amount, basics_1.TimeUnit.Second); }; /** * Construct a time duration * @param amount Number of milliseconds (may be fractional or negative) * @return A duration of n milliseconds * @throws timezonecomplete.Argument.Amount if n is not a finite number */ Duration.milliseconds = function (amount) { return new Duration(amount, basics_1.TimeUnit.Millisecond); }; /** * @return another instance of Duration with the same value. * @throws nothing */ Duration.prototype.clone = function () { return new Duration(this._amount, this._unit); }; /** * Returns this duration expressed in different unit (positive or negative, fractional). * This is precise for Year <-> Month and for time-to-time conversion (i.e. Hour-or-less to Hour-or-less). * It is approximate for any other conversion * @throws nothing */ Duration.prototype.as = function (unit) { if (this._unit === unit) { return this._amount; } else if (this._unit >= basics_1.TimeUnit.Month && unit >= basics_1.TimeUnit.Month) { var thisMonths = (this._unit === basics_1.TimeUnit.Year ? 12 : 1); var reqMonths = (unit === basics_1.TimeUnit.Year ? 12 : 1); return this._amount * thisMonths / reqMonths; } else { var thisMsec = basics.timeUnitToMilliseconds(this._unit); var reqMsec = basics.timeUnitToMilliseconds(unit); return this._amount * thisMsec / reqMsec; } }; /** * Convert this duration to a Duration in another unit. You always get a clone even if you specify * the same unit. * This is precise for Year <-> Month and for time-to-time conversion (i.e. Hour-or-less to Hour-or-less). * It is approximate for any other conversion * @throws nothing */ Duration.prototype.convert = function (unit) { return new Duration(this.as(unit), unit); }; /** * The entire duration in milliseconds (negative or positive) * For Day/Month/Year durations, this is approximate! * @throws nothing */ Duration.prototype.milliseconds = function () { return this.as(basics_1.TimeUnit.Millisecond); }; /** * The millisecond part of the duration (always positive) * For Day/Month/Year durations, this is approximate! * @return e.g. 400 for a -01:02:03.400 duration * @throws nothing */ Duration.prototype.millisecond = function () { return this._part(basics_1.TimeUnit.Millisecond); }; /** * The entire duration in seconds (negative or positive, fractional) * For Day/Month/Year durations, this is approximate! * @return e.g. 1.5 for a 1500 milliseconds duration * @throws nothing */ Duration.prototype.seconds = function () { return this.as(basics_1.TimeUnit.Second); }; /** * The second part of the duration (always positive) * For Day/Month/Year durations, this is approximate! * @return e.g. 3 for a -01:02:03.400 duration * @throws nothing */ Duration.prototype.second = function () { return this._part(basics_1.TimeUnit.Second); }; /** * The entire duration in minutes (negative or positive, fractional) * For Day/Month/Year durations, this is approximate! * @return e.g. 1.5 for a 90000 milliseconds duration * @throws nothing */ Duration.prototype.minutes = function () { return this.as(basics_1.TimeUnit.Minute); }; /** * The minute part of the duration (always positive) * For Day/Month/Year durations, this is approximate! * @return e.g. 2 for a -01:02:03.400 duration * @throws nothing */ Duration.prototype.minute = function () { return this._part(basics_1.TimeUnit.Minute); }; /** * The entire duration in hours (negative or positive, fractional) * For Day/Month/Year durations, this is approximate! * @return e.g. 1.5 for a 5400000 milliseconds duration * @throws nothing */ Duration.prototype.hours = function () { return this.as(basics_1.TimeUnit.Hour); }; /** * The hour part of a duration. This assumes that a day has 24 hours (which is not the case * during DST changes). * @throws nothing */ Duration.prototype.hour = function () { return this._part(basics_1.TimeUnit.Hour); }; /** * The hour part of the duration (always positive). * Note that this part can exceed 23 hours, because for * now, we do not have a days() function * For Day/Month/Year durations, this is approximate! * @return e.g. 25 for a -25:02:03.400 duration * @throws nothing */ Duration.prototype.wholeHours = function () { return Math.floor(basics.timeUnitToMilliseconds(this._unit) * Math.abs(this._amount) / 3600000); }; /** * The entire duration in days (negative or positive, fractional) * This is approximate if this duration is not in days! * @throws nothing */ Duration.prototype.days = function () { return this.as(basics_1.TimeUnit.Day); }; /** * The day part of a duration. This assumes that a month has 30 days. * @throws nothing */ Duration.prototype.day = function () { return this._part(basics_1.TimeUnit.Day); }; /** * The entire duration in days (negative or positive, fractional) * This is approximate if this duration is not in Months or Years! * @throws nothing */ Duration.prototype.months = function () { return this.as(basics_1.TimeUnit.Month); }; /** * The month part of a duration. * @throws nothing */ Duration.prototype.month = function () { return this._part(basics_1.TimeUnit.Month); }; /** * The entire duration in years (negative or positive, fractional) * This is approximate if this duration is not in Months or Years! * @throws nothing */ Duration.prototype.years = function () { return this.as(basics_1.TimeUnit.Year); }; /** * Non-fractional positive years * @throws nothing */ Duration.prototype.wholeYears = function () { if (this._unit === basics_1.TimeUnit.Year) { return Math.floor(Math.abs(this._amount)); } else if (this._unit === basics_1.TimeUnit.Month) { return Math.floor(Math.abs(this._amount) / 12); } else { return Math.floor(basics.timeUnitToMilliseconds(this._unit) * Math.abs(this._amount) / basics.timeUnitToMilliseconds(basics_1.TimeUnit.Year)); } }; /** * Amount of units (positive or negative, fractional) * @throws nothing */ Duration.prototype.amount = function () { return this._amount; }; /** * The unit this duration was created with * @throws nothing */ Duration.prototype.unit = function () { return this._unit; }; /** * Sign * @return "-" if the duration is negative * @throws nothing */ Duration.prototype.sign = function () { return (this._amount < 0 ? "-" : ""); }; /** * Approximate if the durations have units that cannot be converted * @return True iff (this < other) * @throws nothing */ Duration.prototype.lessThan = function (other) { return this.milliseconds() < other.milliseconds(); }; /** * Approximate if the durations have units that cannot be converted * @return True iff (this <= other) * @throws nothing */ Duration.prototype.lessEqual = function (other) { return this.milliseconds() <= other.milliseconds(); }; /** * Similar but not identical * Approximate if the durations have units that cannot be converted * @return True iff this and other represent the same time duration * @throws nothing */ Duration.prototype.equals = function (other) { var converted = other.convert(this._unit); return this._amount === converted.amount() && this._unit === converted.unit(); }; /** * Similar but not identical * Returns false if we cannot determine whether they are equal in all time zones * so e.g. 60 minutes equals 1 hour, but 24 hours do NOT equal 1 day * * @return True iff this and other represent the same time duration * @throws nothing */ Duration.prototype.equalsExact = function (other) { if (this._unit === other._unit) { return (this._amount === other._amount); } else if (this._unit >= basics_1.TimeUnit.Month && other.unit() >= basics_1.TimeUnit.Month) { return this.equals(other); // can compare months and years } else if (this._unit < basics_1.TimeUnit.Day && other.unit() < basics_1.TimeUnit.Day) { return this.equals(other); // can compare milliseconds through hours } else { return false; // cannot compare days to anything else } }; /** * Same unit and same amount * @throws nothing */ Duration.prototype.identical = function (other) { return this._amount === other.amount() && this._unit === other.unit(); }; /** * Returns true if this is a non-zero length duration */ Duration.prototype.nonZero = function () { return this._amount !== 0; }; /** * Returns true if this is a zero-length duration */ Duration.prototype.zero = function () { return this._amount === 0; }; /** * Approximate if the durations have units that cannot be converted * @return True iff this > other * @throws nothing */ Duration.prototype.greaterThan = function (other) { return this.milliseconds() > other.milliseconds(); }; /** * Approximate if the durations have units that cannot be converted * @return True iff this >= other * @throws nothing */ Duration.prototype.greaterEqual = function (other) { return this.milliseconds() >= other.milliseconds(); }; /** * Approximate if the durations have units that cannot be converted * @return The minimum (most negative) of this and other * @throws nothing */ Duration.prototype.min = function (other) { if (this.lessThan(other)) { return this.clone(); } return other.clone(); }; /** * Approximate if the durations have units that cannot be converted * @return The maximum (most positive) of this and other * @throws nothing */ Duration.prototype.max = function (other) { if (this.greaterThan(other)) { return this.clone(); } return other.clone(); }; /** * Multiply with a fixed number. * Approximate if the durations have units that cannot be converted * @return a new Duration of (this * value) * @throws nothing */ Duration.prototype.multiply = function (value) { return new Duration(this._amount * value, this._unit); }; Duration.prototype.divide = function (value) { if (typeof value === "number") { (0, assert_1.default)(Number.isFinite(value) && value !== 0, "Argument.Value", "cannot divide by ".concat(value)); return new Duration(this._amount / value, this._unit); } else { (0, assert_1.default)(value.amount() !== 0, "Argument.Value", "cannot divide by 0"); return this.milliseconds() / value.milliseconds(); } }; /** * Add a duration. * @return a new Duration of (this + value) with the unit of this duration * @throws nothing */ Duration.prototype.add = function (value) { return new Duration(this._amount + value.as(this._unit), this._unit); }; /** * Subtract a duration. * @return a new Duration of (this - value) with the unit of this duration * @throws nothing */ Duration.prototype.sub = function (value) { return new Duration(this._amount - value.as(this._unit), this._unit); }; /** * Return the absolute value of the duration i.e. remove the sign. * @throws nothing */ Duration.prototype.abs = function () { if (this._amount >= 0) { return this.clone(); } else { return this.multiply(-1); } }; /** * String in [-]hhhh:mm:ss.nnn notation. All fields are always present except the sign. * @throws nothing */ Duration.prototype.toFullString = function () { return this.toHmsString(true); }; /** * String in [-]hhhh:mm[:ss[.nnn]] notation. * @param full If true, then all fields are always present except the sign. Otherwise, seconds and milliseconds * are chopped off if zero * @throws nothing */ Duration.prototype.toHmsString = function (full) { if (full === void 0) { full = false; } var result = ""; if (full || this.millisecond() > 0) { result = "." + strings.padLeft(this.millisecond().toString(10), 3, "0"); } if (full || result.length > 0 || this.second() > 0) { result = ":" + strings.padLeft(this.second().toString(10), 2, "0") + result; } if (full || result.length > 0 || this.minute() > 0) { result = ":" + strings.padLeft(this.minute().toString(10), 2, "0") + result; } return this.sign() + strings.padLeft(this.wholeHours().toString(10), 2, "0") + result; }; /** * String in ISO 8601 notation e.g. 'P1M' for one month or 'PT1M' for one minute * @throws nothing */ Duration.prototype.toIsoString = function () { switch (this._unit) { case basics_1.TimeUnit.Millisecond: { return "P" + (this._amount / 1000).toFixed(3) + "S"; } case basics_1.TimeUnit.Second: { return "P" + this._amount.toString(10) + "S"; } case basics_1.TimeUnit.Minute: { return "PT" + this._amount.toString(10) + "M"; // note the "T" to disambiguate the "M" } case basics_1.TimeUnit.Hour: { return "P" + this._amount.toString(10) + "H"; } case basics_1.TimeUnit.Day: { return "P" + this._amount.toString(10) + "D"; } case basics_1.TimeUnit.Week: { return "P" + this._amount.toString(10) + "W"; } case basics_1.TimeUnit.Month: { return "P" + this._amount.toString(10) + "M"; } case basics_1.TimeUnit.Year: { return "P" + this._amount.toString(10) + "Y"; } /* istanbul ignore next */ default: /* istanbul ignore if */ /* istanbul ignore next */ if (true) { throw new Error("Unknown time unit."); // programming error } } }; /** * String representation with amount and unit e.g. '1.5 years' or '-1 day' * @throws nothing */ Duration.prototype.toString = function () { return this._amount.toString(10) + " " + basics.timeUnitToString(this._unit, this._amount); }; /** * The valueOf() method returns the primitive value of the specified object. * @throws nothing */ Duration.prototype.valueOf = function () { return this.milliseconds(); }; /** * Return this % unit, always positive * @throws nothing */ Duration.prototype._part = function (unit) { var nextUnit; // note not all units are used here: Weeks and Years are ruled out switch (unit) { case basics_1.TimeUnit.Millisecond: nextUnit = basics_1.TimeUnit.Second; break; case basics_1.TimeUnit.Second: nextUnit = basics_1.TimeUnit.Minute; break; case basics_1.TimeUnit.Minute: nextUnit = basics_1.TimeUnit.Hour; break; case basics_1.TimeUnit.Hour: nextUnit = basics_1.TimeUnit.Day; break; case basics_1.TimeUnit.Day: nextUnit = basics_1.TimeUnit.Month; break; case basics_1.TimeUnit.Month: nextUnit = basics_1.TimeUnit.Year; break; default: return Math.floor(Math.abs(this.as(basics_1.TimeUnit.Year))); } var msecs = (basics.timeUnitToMilliseconds(this._unit) * Math.abs(this._amount)) % basics.timeUnitToMilliseconds(nextUnit); return Math.floor(msecs / basics.timeUnitToMilliseconds(unit)); }; return Duration; }()); exports.Duration = Duration; /** * Checks if a given object is of type Duration. Note that it does not work for sub classes. However, use this to be robust * against different versions of the library in one process instead of instanceof * @param value Value to check * @throws nothing */ function isDuration(value) { return typeof value === "object" && value !== null && value.kind === "Duration"; } exports.isDuration = isDuration; },{"./assert":1,"./basics":2,"./strings":13}],5:[function(require,module,exports){ "use strict"; /** * Copyright (c) 2019 ABB Switzerland Ltd. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.convertError = exports.errorIs = exports.error = exports.throwError = void 0; /** * Throws an error with the given name and message * @param name error name, without timezonecomplete prefix * @param message message with percent-style placeholders * @param args arguments for the placeholders * @throws the given error */ function throwError(name, message) { var error = new Error(message); error.name = "timezonecomplete." + name; throw error; } exports.throwError = throwError; /** * Returns an error with the given name and message * @param name * @param format * @param args * @throws nothing */ function error(name, message) { var error = new Error(message); error.name = "timezonecomplete." + name; return error; } exports.error = error; /** * Returns true iff `error.name` is equal to or included by `name` * @param error * @param name string or array of strings * @throws nothing */ function errorIs(error, name) { if (typeof name === "string") { return error.name === "timezonecomplete." + name; } else { return error.name.startsWith("timezonecomplete.") && name.includes(error.name.substr("timezonecomplete.".length)); } } exports.errorIs = errorIs; /** * Converts all errors thrown by `cb` to the given error name * @param errorName * @param cb * @throws [errorName] */ function convertError(errorName, cb) { try { return cb(); } catch (e) { return throwError(errorName, e.message); } } exports.convertError = convertError; },{}],6:[function(require,module,exports){ /** * Copyright(c) 2014 ABB Switzerland Ltd. * * Functionality to parse a DateTime object to a string */ "use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.format = void 0; var basics = require("./basics"); var error_1 = require("./error"); var locale_1 = require("./locale"); var strings = require("./strings"); var token_1 = require("./token"); /** * Format the supplied dateTime with the formatting string. * * @param dateTime The current time to format * @param utcTime The time in UTC * @param localZone The zone that currentTime is in * @param formatString The LDML format pattern (see LDML.md) * @param locale Other format options such as month names * @return string * @throws timezonecomplete.Argument.FormatString for invalid format pattern * @throws timezonecomplete.InvalidTimeZoneData if values in the time zone database are invalid */ function format(dateTime, utcTime, localZone, formatString, locale) { if (locale === void 0) { locale = {}; } var mergedLocale = __assign(__assign({}, locale_1.DEFAULT_LOCALE), locale); var tokens = (0, token_1.tokenize)(formatString); var result = ""; for (var _i = 0, tokens_1 = tokens; _i < tokens_1.length; _i++) { var token = tokens_1[_i]; var tokenResult = void 0; switch (token.type) { case token_1.TokenType.ERA: tokenResult = _formatEra(dateTime, token, mergedLocale); break; case token_1.TokenType.YEAR: tokenResult = _formatYear(dateTime, token); break; case token_1.TokenType.QUARTER: tokenResult = _formatQuarter(dateTime, token, mergedLocale); break; case token_1.TokenType.MONTH: tokenResult = _formatMonth(dateTime, token, mergedLocale); break; case token_1.TokenType.DAY: tokenResult = _formatDay(dateTime, token); break; case token_1.TokenType.WEEKDAY: tokenResult = _formatWeekday(dateTime, token, mergedLocale); break; case token_1.TokenType.DAYPERIOD: tokenResult = _formatDayPeriod(dateTime, token, mergedLocale); break; case token_1.TokenType.HOUR: tokenResult = _formatHour(dateTime, token); break; case token_1.TokenType.MINUTE: tokenResult = _formatMinute(dateTime, token); break; case token_1.TokenType.SECOND: tokenResult = _formatSecond(dateTime, token); break; case token_1.TokenType.ZONE: tokenResult = _formatZone(dateTime, utcTime, localZone ? localZone : undefined, token); break; case token_1.TokenType.WEEK: tokenResult = _formatWeek(dateTime, token); break; case token_1.TokenType.IDENTITY: // intentional fallthrough /* istanbul ignore next */ default: tokenResult = token.raw; break; } result += tokenResult; } return result.trim(); } exports.format = format; /** * Format the era (BC or AD) * * @param dateTime The current time to format * @param token The token passed * @return string * @throws nothing */ function _formatEra(dateTime, token, locale) { var AD = dateTime.year > 0; switch (token.length) { case 1: case 2: case 3: return (AD ? locale.eraAbbreviated[0] : locale.eraAbbreviated[1]); case 4: return (AD ? locale.eraWide[0] : locale.eraWide[1]); case 5: return (AD ? locale.eraNarrow[0] : locale.eraNarrow[1]); /* istanbul ignore next */ default: // tokenizer should prevent this /* istanbul ignore next */ return token.raw; } } /** * Format the year * * @param dateTime The current time to format * @param token The token passed * @return string * @throws nothing */ function _formatYear(dateTime, token) { switch (token.symbol) { case "y": case "Y": case "r": var yearValue = strings.padLeft(dateTime.year.toString(), token.length, "0"); if (token.length === 2) { // Special case: exactly two characters are expected yearValue = yearValue.slice(-2); } return yearValue; /* istanbul ignore next */ default: // tokenizer should prevent this /* istanbul ignore next */ return token.raw; } } /** * Format the quarter * * @param dateTime The current time to format * @param token The token passed * @return string * @throws timezonecomplete.Argument.FormatString for invalid format pattern */ function _formatQuarter(dateTime, token, locale) { var quarter = Math.ceil(dateTime.month / 3); switch (token.symbol) { case "Q": switch (token.length) { case 1: case 2: return strings.padLeft(quarter.toString(), 2, "0"); case 3: return locale.quarterLetter + quarter; case 4: return locale.quarterAbbreviations[quarter - 1] + " " + locale.quarterWord; case 5: return quarter.toString(); /* istanbul ignore next */ default: // tokenizer should prevent this /* istanbul ignore next */ return token.raw; } case "q": switch (token.length) { case 1: case 2: return strings.padLeft(quarter.toString(), 2, "0"); case 3: return locale.standAloneQuarterLetter + quarter; case 4: return locale.standAloneQuarterAbbreviations[quarter - 1] + " " + locale.standAloneQuarterWord; case 5: return quarter.toString(); /* istanbul ignore next */ default: // tokenizer should prevent this /* istanbul ignore next */ return token.raw; } /* istanbul ignore next */ default: /* istanbul ignore next */ return (0, error_1.throwError)("Argument.FormatString", "invalid quarter pattern"); } } /** * Format the month * * @param dateTime The current time to format * @param token The token passed * @return string * @throws timezonecomplete.Argument.FormatString for invalid format pattern */ function _formatMonth(dateTime, token, locale) { switch (token.symbol) { case "M": switch (token.length) { case 1: case 2: return strings.padLeft(dateTime.month.toString(), token.length, "0"); case 3: return locale.shortMonthNames[dateTime.month - 1]; case 4: return locale.longMonthNames[dateTime.month - 1]; case 5: return locale.monthLetters[dateTime.month - 1]; /* istanbul ignore next */ default: // tokenizer should prevent this /* istanbul ignore next */ return token.raw; } case "L": switch (token.length) { case 1: case 2: return strings.padLeft(dateTime.month.toString(), token.length, "0"); case 3: return locale.standAloneShortMonthNames[dateTime.month - 1]; case 4: return locale.standAloneLongMonthNames[dateTime.month - 1]; case 5: return locale.standAloneMonthLetters[dateTime.month - 1]; /* istanbul ignore next */ default: // tokenizer should prevent this /* istanbul ignore next */ return token.raw; } /* istanbul ignore next */ default: /* istanbul ignore next */ return (0, error_1.throwError)("Argument.FormatString", "invalid month pattern"); } } /** * Format the week number * * @param dateTime The current time to format * @param token The token passed * @return string * @throws nothing */ function _formatWeek(dateTime, token) { if (token.symbol === "w") { return strings.padLeft(basics.weekNumber(dateTime.year, dateTime.month, dateTime.day).toString(), token.length, "0"); } else { return strings.padLeft(basics.weekOfMonth(dateTime.year, dateTime.month, dateTime.day).toString(), token.length, "0"); } } /** * Format the day of the month (or year) * * @param dateTime The current time to format * @param token The token passed * @return string * @throws nothing */ function _formatDay(dateTime, token) { switch (token.symbol) { case "d": return strings.padLeft(dateTime.day.toString(), token.length, "0"); case "D": var dayOfYear = basics.dayOfYear(dateTime.year, dateTime.month, dateTime.day) + 1; return strings.padLeft(dayOfYear.toString(), token.length, "0"); /* istanbul ignore next */ default: // tokenizer should prevent this /* istanbul ignore next */ return token.raw; } } /** * Format the day of the week * * @param dateTime The current time to format * @param token The token passed * @return string * @throws nothing */ function _formatWeekday(dateTime, token, locale) { var weekDayNumber = basics.weekDayNoLeapSecs(dateTime.unixMillis); switch (token.length) { case 1: case 2: if (token.symbol === "e") { return strings.padLeft(basics.weekDayNoLeapSecs(dateTime.unixMillis).toString(), token.length, "0"); } else { return locale.shortWeekdayNames[weekDayNumber]; } case 3: return locale.shortWeekdayNames[weekDayNumber]; case 4: return locale.longWeekdayNames[weekDayNumber]; case 5: return locale.weekdayLetters[weekDayNumber]; case 6: return locale.weekdayTwoLetters[weekDayNumber]; /* istanbul ignore next */ default: // tokenizer should prevent this /* istanbul ignore next */ return token.raw; } } /** * Format the Day Period (AM or PM) * * @param dateTime The current time to format * @param token The token passed * @return string * @throws nothing */ function _formatDayPeriod(dateTime, token, locale) { switch (token.symbol) { case "a": { if (token.length <= 3) { if (dateTime.hour < 12) { return locale.dayPeriodAbbreviated.am; } else { return locale.dayPeriodAbbreviated.pm; } } else if (token.length === 4) { if (dateTime.hour < 12) { return locale.dayPeriodWide.am; } else { return locale.dayPeriodWide.pm; } } else { if (dateTime.hour < 12) { return locale.dayPeriodNarrow.am; } else { return locale.dayPeriodNarrow.pm; } } } case "b": case "B": { if (token.length <= 3) { if (dateTime.hour === 0 && dateTime.minute === 0 && dateTime.second === 0 && dateTime.milli === 0) { return locale.dayPeriodAbbreviated.midnight; } else if (dateTime.hour === 12 && dateTime.minute === 0 && dateTime.second === 0 && dateTime.milli === 0) { return locale.dayPeriodAbbreviated.noon; } else if (dateTime.hour < 12) { return locale.dayPeriodAbbreviated.am; } else { return locale.dayPeriodAbbreviated.pm; } } else if (token.length === 4) { if (dateTime.hour === 0 && dateTime.minute === 0 && dateTime.second === 0 && dateTime.milli === 0) { return locale.dayPeriodWide.midnight; } else if (dateTime.hour === 12 && dateTime.minute === 0 && dateTime.second === 0 && dateTime.milli === 0) { return locale.dayPeriodWide.noon; } else if (dateTime.hour < 12) { return locale.dayPeriodWide.am; } else { return locale.dayPeriodWide.pm; } } else { if (dateTime.hour === 0 && dateTime.minute === 0 && dateTime.second === 0 && dateTime.milli === 0) { return locale.dayPeriodNarrow.midnight; } else if (dateTime.hour === 12 && dateTime.minute === 0 && dateTime.second === 0 && dateTime.milli === 0) { return locale.dayPeriodNarrow.noon; } else if (dateTime.hour < 12) { return locale.dayPeriodNarrow.am; } else { return locale.dayPeriodNarrow.pm; } } } /* istanbul ignore next */ default: // tokenizer should prevent this /* istanbul ignore next */ return token.raw; } } /** * Format the Hour * * @param dateTime The current time to format * @param token The token passed * @return string * @throws nothing */ function _formatHour(dateTime, token) { var hour = dateTime.hour; switch (token.symbol) { case "h": hour = hour % 12; if (hour === 0) { hour = 12; } return strings.padLeft(hour.toString(), token.length, "0"); case "H": return strings.padLeft(hour.toString(), token.length, "0"); case "K": hour = hour % 12; return strings.padLeft(hour.toString(), token.length, "0"); case "k": if (hour === 0) { hour = 24; } return strings.padLeft(hour.toString(), token.length, "0"); /* istanbul ignore next */ default: // tokenizer should prevent this /* istanbul ignore next */ return token.raw; } } /** * Format the minute * * @param dateTime The current time to format * @param token The token passed * @return string * @throws nothing */ function _formatMinute(dateTime, token) { return strings.padLeft(dateTime.minute.toString(), token.length, "0"); } /** * Format the seconds (or fraction of a second) * * @param dateTime The current time to format * @param token The token passed * @return string * @throws timezonecomplete.Argument.** if any of the given dateTime elements are invalid */ function _formatSecond(dateTime, token) { switch (token.symbol) { case "s": return strings.padLeft(dateTime.second.toString(), token.length, "0"); case "S": var fraction = dateTime.milli; var fractionString = strings.padLeft(fraction.toString(), 3, "0"); fractionString = strings.padRight(fractionString, token.length, "0"); return fractionString.slice(0, token.length); case "A": return strings.padLeft(basics.secondOfDay(dateTime.hour, dateTime.minute, dateTime.second).toString(), token.length, "0"); /* istanbul ignore next */ default: // tokenizer should prevent this /* istanbul ignore next */ return token.raw; } } /** * Format the time zone. For this, we need the current time, the time in UTC and the time zone * @param currentTime The time to format * @param utcTime The time in UTC * @param zone The timezone currentTime is in * @param token The token passed * @return string * @throws timezonecomplete.InvalidTimeZoneData if values in the time zone database are invalid */ function _formatZone(currentTime, utcTime, zone, token) { if (!zone) { return ""; } var offset = Math.round((currentTime.unixMillis - utcTime.unixMillis) / 60000); var offsetHours = Math.floor(Math.abs(offset) / 60); var offsetHoursString = strings.padLeft(offsetHours.toString(), 2, "0"); offsetHoursString = (offset >= 0 ? "+" + offsetHoursString : "-" + offsetHoursString); var offsetMinutes = Math.abs(offset % 60); var offsetMinutesString = strings.padLeft(offsetMinutes.toString(), 2, "0"); var result; switch (token.symbol) { case "O": result = "GMT"; if (offset >= 0) { result += "+"; } else { result += "-"; } result += offsetHours.toString(); if (token.length >= 4 || offsetMinutes !== 0) { result += ":" + offsetMinutesString; } if (token.length > 4) { result += token.raw.slice(4); } return result; case "Z": switch (token.length) { case 1: case 2: case 3: return offsetHoursString + offsetMinutesString; case 4: var newToken = { length: 4, raw: "OOOO", symbol: "O", type: token_1.TokenType.ZONE }; return _formatZone(currentTime, utcTime, zone, newToken); case 5: if (offset === 0) { return "Z"; } return offsetHoursString + ":" + offsetMinutesString; /* istanbul ignore next */ default: // tokenizer should prevent this /* istanbul ignore next */ return token.raw; } case "z": switch (token.length) { case 1: case 2: case 3: return zone.abbreviationForUtc(currentTime, true); case 4: return zone.toString(); /* istanbul ignore next */ default: // tokenizer should prevent this /* istanbul ignore next */ return token.raw; } case "v": if (token.length === 1) { return zone.abbreviationForUtc(currentTime, false); } else { return zone.toString(); } case "V": switch (token.length) { case 1: // Not implemented return "unk"; case 2: return zone.name(); case 3: case 4: return "Unknown"; /* istanbul ignore next */ default: // tokenizer should prevent this /* istanbul ignore next */ return token.raw; } case "X": case "x": if (token.symbol === "X" && offset === 0) { return "Z"; } switch (token.length) { case 1: result = offsetHoursString; if (offsetMinutes !== 0) { result += offsetMinutesString; } return result; case 2: case 4: // No seconds in our implementation, so this is the same return offsetHoursString + offsetMinutesString; case 3: case 5: // No seconds in our implementation, so this is the same return offsetHoursString + ":" + offsetMinutesString; /* istanbul ignore next */ default: // tokenizer should prevent this /* istanbul ignore next */ return token.raw; } /* istanbul ignore next */ default: // tokenizer should prevent this /* istanbul ignore next */ return token.raw; } } },{"./basics":2,"./error":5,"./locale":9,"./strings":13,"./token":16}],7:[function(require,module,exports){ /** * Copyright(c) 2014 ABB Switzerland Ltd. * * Global functions depending on DateTime/Duration etc */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.abs = exports.max = exports.min = void 0; var assert_1 = require("./assert"); /** * Returns the minimum of two DateTimes or Durations * @throws timezonecomplete.Argument.D1 if d1 is undefined/null * @throws timezonecomplete.Argument.D2 if d1 is undefined/null, or if d1 and d2 are not both datetimes */ function min(d1, d2) { (0, assert_1.default)(d1, "Argument.D1", "first argument is falsy"); (0, assert_1.default)(d2, "Argument.D2", "second argument is falsy"); /* istanbul ignore next */ (0, assert_1.default)(d1.kind === d2.kind, "Argument.D2", "expected either two datetimes or two durations"); return d1.min(d2); } exports.min = min; /** * Returns the maximum of two DateTimes or Durations * @throws timezonecomplete.Argument.D1 if d1 is undefined/null * @throws timezonecomplete.Argument.D2 if d1 is undefined/null, or if d1 and d2 are not both datetimes */ function max(d1, d2) { (0, assert_1.default)(d1, "Argument.D1", "first argument is falsy"); (0, assert_1.default)(d2, "Argument.D2", "second argument is falsy"); /* istanbul ignore next */ (0, assert_1.default)(d1.kind === d2.kind, "Argument.D2", "expected either two datetimes or two durations"); return d1.max(d2); } exports.max = max; /** * Returns the absolute value of a Duration * @throws timezonecomplete.Argument.D if d is undefined/null */ function abs(d) { (0, assert_1.default)(d, "Argument.D", "first argument is falsy"); return d.abs(); } exports.abs = abs; },{"./assert":1}],8:[function(require,module,exports){ /** * Copyright(c) 2014 ABB Switzerland Ltd. */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DateFunctions = void 0; /** * Indicates how a Date object should be interpreted. * Either we can take getYear(), getMonth() etc for our field * values, or we can take getUTCYear(), getUtcMonth() etc to do that. */ var DateFunctions; (function (DateFunctions) { /** * Use the Date.getFullYear(), Date.getMonth(), ... functions. */ DateFunctions[DateFunctions["Get"] = 0] = "Get"; /** * Use the Date.getUTCFullYear(), Date.getUTCMonth(), ... functions. */ DateFunctions[DateFunctions["GetUTC"] = 1] = "GetUTC"; })(DateFunctions || (exports.DateFunctions = DateFunctions = {})); },{}],9:[function(require,module,exports){ "use strict"; /** * Copyright(c) 2017 ABB Switzerland Ltd. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.DEFAULT_LOCALE = exports.DAY_PERIODS_NARROW = exports.DAY_PERIODS_WIDE = exports.DAY_PERIODS_ABBREVIATED = exports.WEEKDAY_LETTERS = exports.WEEKDAY_TWO_LETTERS = exports.SHORT_WEEKDAY_NAMES = exports.LONG_WEEKDAY_NAMES = exports.STAND_ALONE_MONTH_LETTERS = exports.STAND_ALONE_SHORT_MONTH_NAMES = exports.STAND_ALONE_LONG_MONTH_NAMES = exports.MONTH_LETTERS = exports.SHORT_MONTH_NAMES = exports.LONG_MONTH_NAMES = exports.STAND_ALONE_QUARTER_ABBREVIATIONS = exports.STAND_ALONE_QUARTER_WORD = exports.STAND_ALONE_QUARTER_LETTER = exports.QUARTER_ABBREVIATIONS = exports.QUARTER_WORD = exports.QUARTER_LETTER = exports.ERA_NAMES_ABBREVIATED = exports.ERA_NAMES_WIDE = exports.ERA_NAMES_NARROW = void 0; exports.ERA_NAMES_NARROW = ["A", "B"]; exports.ERA_NAMES_WIDE = ["Anno Domini", "Before Christ"]; exports.ERA_NAMES_ABBREVIATED = ["AD", "BC"]; exports.QUARTER_LETTER = "Q"; exports.QUARTER_WORD = "quarter"; exports.QUARTER_ABBREVIATIONS = ["1st", "2nd", "3rd", "4th"]; /** * In some languages, different words are necessary for stand-alone quarter names */ exports.STAND_ALONE_QUARTER_LETTER = exports.QUARTER_LETTER; exports.STAND_ALONE_QUARTER_WORD = exports.QUARTER_WORD; exports.STAND_ALONE_QUARTER_ABBREVIATIONS = exports.QUARTER_ABBREVIATIONS.slice(); exports.LONG_MONTH_NAMES = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; exports.SHORT_MONTH_NAMES = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; exports.MONTH_LETTERS = ["J", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D"]; exports.STAND_ALONE_LONG_MONTH_NAMES = exports.LONG_MONTH_NAMES.slice(); exports.STAND_ALONE_SHORT_MONTH_NAMES = exports.SHORT_MONTH_NAMES.slice(); exports.STAND_ALONE_MONTH_LETTERS = exports.MONTH_LETTERS.slice(); exports.LONG_WEEKDAY_NAMES = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; exports.SHORT_WEEKDAY_NAMES = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; exports.WEEKDAY_TWO_LETTERS = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"]; exports.WEEKDAY_LETTERS = ["S", "M", "T", "W", "T", "F", "S"]; exports.DAY_PERIODS_ABBREVIATED = { am: "AM", pm: "PM", noon: "noon", midnight: "mid." }; exports.DAY_PERIODS_WIDE = { am: "AM", pm: "PM", noon: "noon", midnight: "midnight" }; exports.DAY_PERIODS_NARROW = { am: "A", pm: "P", noon: "noon", midnight: "md" }; exports.DEFAULT_LOCALE = { eraNarrow: exports.ERA_NAMES_NARROW, eraWide: exports.ERA_NAMES_WIDE, eraAbbreviated: exports.ERA_NAMES_ABBREVIATED, quarterLetter: exports.QUARTER_LETTER, quarterWord: exports.QUARTER_WORD, quarterAbbreviations: exports.QUARTER_ABBREVIATIONS, standAloneQuarterLetter: exports.STAND_ALONE_QUARTER_LETTER, standAloneQuarterWord: exports.STAND_ALONE_QUARTER_WORD, standAloneQuarterAbbreviations: exports.STAND_ALONE_QUARTER_ABBREVIATIONS, longMonthNames: exports.LONG_MONTH_NAMES, shortMonthNames: exports.SHORT_MONTH_NAMES, monthLetters: exports.MONTH_LETTERS, standAloneLongMonthNames: exports.STAND_ALONE_LONG_MONTH_NAMES, standAloneShortMonthNames: exports.STAND_ALONE_SHORT_MONTH_NAMES, standAloneMonthLetters: exports.STAND_ALONE_MONTH_LETTERS, longWeekdayNames: exports.LONG_WEEKDAY_NAMES, shortWeekdayNames: exports.SHORT_WEEKDAY_NAMES, weekdayTwoLetters: exports.WEEKDAY_TWO_LETTERS, weekdayLetters: exports.WEEKDAY_LETTERS, dayPeriodAbbreviated: exports.DAY_PERIODS_ABBREVIATED, dayPeriodWide: exports.DAY_PERIODS_WIDE, dayPeriodNarrow: exports.DAY_PERIODS_NARROW }; },{}],10:[function(require,module,exports){ /** * Copyright(c) 2014 ABB Switzerland Ltd. * * Math utility functions */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.positiveModulo = exports.filterFloat = exports.roundSym = exports.isInt = void 0; var assert_1 = require("./assert"); /** * @return true iff given argument is an integer number * @throws nothing */ function isInt(n) { if (n === null || !isFinite(n)) { return false; } return (Math.floor(n) === n); } exports.isInt = isInt; /** * Rounds -1.5 to -2 instead of -1 * Rounds +1.5 to +2 * @throws timezonecomplete.Argument.N if n is not a finite number */ function roundSym(n) { (0, assert_1.default)(Number.isFinite(n), "Argument.N", "n must be a finite number but is: ".concat(n)); if (n < 0) { return -1 * Math.round(-1 * n); } else { return Math.round(n); } } exports.roundSym = roundSym; /** * Stricter variant of parseFloat(). * @param value Input string * @return the float if the string is a valid float, NaN otherwise * @throws nothing */ function filterFloat(value) { if (/^(\-|\+)?([0-9]+(\.[0-9]+)?|Infinity)$/.test(value)) { return Number(value); } return NaN; } exports.filterFloat = filterFloat; /** * Modulo function that only returns a positive result, in contrast to the % operator * @param value * @param modulo * @throws timezonecomplete.Argument.Value if value is not finite * @throws timezonecomplete.Argument.Modulo if modulo is not a finite number >= 1 */ function positiveModulo(value, modulo) { (0, assert_1.default)(Number.isFinite(value), "Argument.Value", "value should be finite"); (0, assert_1.default)(Number.isFinite(modulo) && modulo >= 1, "Argument.Modulo", "modulo should be >= 1"); if (value < 0) { return ((value % modulo) + modulo) % modulo; } else { return value % modulo; } } exports.positiveModulo = positiveModulo; },{"./assert":1}],11:[function(require,module,exports){ "use strict"; /** * Copyright(c) 2014 ABB Switzerland Ltd. * * Functionality to parse a DateTime object to a string */ var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.parse = exports.parseable = void 0; var basics_1 = require("./basics"); var error_1 = require("./error"); var locale_1 = require("./locale"); var math_1 = require("./math"); var timezone_1 = require("./timezone"); var token_1 = require("./token"); /** * Checks if a given datetime string is according to the given format * @param dateTimeString The string to test * @param formatString LDML format string (see LDML.md) * @param allowTrailing Allow trailing string after the date+time * @param locale Locale-specific constants such as month names * @returns true iff the string is valid * @throws nothing */ function parseable(dateTimeString, formatString, allowTrailing, locale) { if (allowTrailing === void 0) { allowTrailing = true; } if (locale === void 0) { locale = {}; } try { parse(dateTimeString, formatString, undefined, allowTrailing, locale); return true; } catch (e) { return false; } } exports.parseable = parseable; /** * Parse the supplied dateTime assuming the given format. * * @param dateTimeString The string to parse * @param formatString The formatting string to be applied * @param overrideZone Use this zone in the result * @param allowTrailing Allow trailing characters in the source string * @param locale Locale-specific constants such as month names * @return string * @throws timezonecomplete.ParseError if the given dateTimeString is wrong or not according to the pattern * @throws timezonecomplete.Argument.FormatString if the given format string is invalid */ function parse(dateTimeString, formatString, overrideZone, allowTrailing, locale) { var _a; if (allowTrailing === void 0) { allowTrailing = true; } if (locale === void 0) { locale = {}; } if (!dateTimeString) { return (0, error_1.throwError)("ParseError", "no date given"); } if (!formatString) { return (0, error_1.throwError)("Argument.FormatString", "no format given"); } var mergedLocale = __assign(__assign({}, locale_1.DEFAULT_LOCALE), locale); var yearCutoff = (0, math_1.positiveModulo)((new Date().getFullYear() + 50), 100); try { var tokens = (0, token_1.tokenize)(formatString); var time = { year: undefined }; var zone = void 0; var pnr = void 0; var pzr = void 0; var dpr = void 0; var era = 1; var quarter = void 0; var remaining = dateTimeString; for (var _i = 0, tokens_1 = tokens; _i < tokens_1.length; _i++) { var token = tokens_1[_i]; switch (token.type) { case token_1.TokenType.ERA: _a = stripEra(token, remaining, mergedLocale), era = _a[0], remaining = _a[1]; break; case token_1.TokenType.QUARTER: { var r = stripQuarter(token, remaining, mergedLocale); quarter = r.n; remaining = r.remaining; } break; case token_1.TokenType.WEEKDAY: { remaining = stripWeekDay(token, remaining, mergedLocale); } break; case token_1.TokenType.WEEK: remaining = stripNumber(remaining, 2).remaining; break; // nothing to learn from this case token_1.TokenType.DAYPERIOD: dpr = stripDayPeriod(token, remaining, mergedLocale); remaining = dpr.remaining; break; case token_1.TokenType.YEAR: pnr = stripNumber(remaining, Infinity); remaining = pnr.remaining; if (token.length === 2) { if (pnr.n > yearCutoff) { time.year = 1900 + pnr.n; } else { time.year = 2000 + pnr.n; } } else { time.year = pnr.n; } break; case token_1.TokenType.MONTH: pnr = stripMonth(token, remaining, mergedLocale); remaining = pnr.remaining; time.month = pnr.n; break; case token_1.TokenType.DAY: pnr = stripNumber(remaining, 2); remaining = pnr.remaining; time.day = pnr.n; break; case token_1.TokenType.HOUR: pnr = stripHour(token, remaining); remaining = pnr.remaining; time.hour = pnr.n; break; case token_1.TokenType.MINUTE: pnr = stripNumber(remaining, 2); remaining = pnr.remaining; time.minute = pnr.n; break; case token_1.TokenType.SECOND: { pnr = stripSecond(token, remaining); remaining = pnr.remaining; switch (token.symbol) { case "s": time.second = pnr.n; break; case "S": time.milli = 1000 * parseFloat("0." + Math.floor(pnr.n).toString(10).slice(0, 3)); break; case "A": time.hour = Math.floor((pnr.n / 3600E3)); time.minute = Math.floor((0, math_1.positiveModulo)(pnr.n / 60E3, 60)); time.second = Math.floor((0, math_1.positiveModulo)(pnr.n / 1000, 60)); time.milli = (0, math_1.positiveModulo)(pnr.n, 1000); break; /* istanbul ignore next */ default: /* istanbul ignore next */ return (0, error_1.throwError)("ParseError", "unsupported second format '".concat(token.raw, "'")); } } break; case token_1.TokenType.ZONE: pzr = stripZone(token, remaining); remaining = pzr.remaining; zone = pzr.zone; break; /* istanbul ignore next */ default: case token_1.TokenType.IDENTITY: remaining = stripRaw(remaining, token.raw); break; } } if (dpr) { switch (dpr.type) { case "am": if (time.hour !== undefined && time.hour >= 12) { time.hour -= 12; } break; case "pm": if (time.hour !== undefined && time.hour < 12) { time.hour += 12; } break; case "noon": if (time.hour === undefined || time.hour === 0) { time.hour = 12; } if (time.minute === undefined) { time.minute = 0; } if (time.second === undefined) { time.second = 0; } if (time.milli === undefined) { time.milli = 0; } if (time.hour !== 12 || time.minute !== 0 || time.second !== 0 || time.milli !== 0) { return (0, error_1.throwError)("ParseError", "invalid time, contains 'noon' specifier but time differs from noon"); } break; case "midnight": if (time.hour === undefined || time.hour === 12) { time.hour = 0; } if (time.hour === 12) { time.hour = 0; } if (time.minute === undefined) { time.minute = 0; } if (time.second === undefined) { time.second = 0; } if (time.milli === undefined) { time.milli = 0; } if (time.hour !== 0 || time.minute !== 0 || time.second !== 0 || time.milli !== 0) { return (0, error_1.throwError)("ParseError", "invalid time, contains 'midnight' specifier but time differs from midnight"); } break; } } if (time.year !== undefined) { time.year *= era; } if (quarter !== undefined) { if (time.month === undefined) { switch (quarter) { case 1: time.month = 1; break; case 2: time.month = 4; break; case 3: time.month = 7; break; case 4: time.month = 10; break; } } else { var error_2 = false; switch (quarter) { case 1: error_2 = !(time.month >= 1 && time.month <= 3); break; case 2: error_2 = !(time.month >= 4 && time.month <= 6); break; case 3: error_2 = !(time.month >= 7 && time.month <= 9); break; case 4: error_2 = !(time.month >= 10 && time.month <= 12); break; } if (error_2) { return (0, error_1.throwError)("ParseError", "the quarter does not match the month"); } } } if (time.year === undefined) { time.year = 1970; } var result = { time: new basics_1.TimeStruct(time), zone: zone }; if (!result.time.validate()) { return (0, error_1.throwError)("ParseError", "invalid resulting date"); } // always overwrite zone with given zone if (overrideZone) { result.zone = overrideZone; } if (remaining && !allowTrailing) { return (0, error_1.throwError)("ParseError", "invalid date '".concat(dateTimeString, "' not according to format '").concat(formatString, "': trailing characters: '").concat(remaining, "'")); } return result; } catch (e) { return (0, error_1.throwError)("ParseError", "invalid date '".concat(dateTimeString, "' not according to format '").concat(formatString, "': ").concat(e.message)); } } exports.parse = parse; var WHITESPACE = [" ", "\t", "\r", "\v", "\n"]; /** * * @param token * @param s * @throws timezonecomplete.NotImplemented if a pattern is used that isn't implemented yet (z, Z, v, V, x, X) * @throws timezonecomplete.ParseError if the given string is not parseable */ function stripZone(token, s) { var unsupported = (token.symbol === "z") || (token.symbol === "Z" && token.length === 5) || (token.symbol === "v") || (token.symbol === "V" && token.length !== 2) || (token.symbol === "x" && token.length >= 4) || (token.symbol === "X" && token.length >= 4); if (unsupported) { return (0, error_1.throwError)("NotImplemented", "time zone pattern '" + token.raw + "' is not implemented"); } var result = { remaining: s }; // chop off "GMT" prefix if needed var hadGMT = false; if ((token.symbol === "Z" && token.length === 4) || token.symbol === "O") { if (result.remaining.toUpperCase().startsWith("GMT")) { result.remaining = result.remaining.slice(3); hadGMT = true; } } // parse any zone, regardless of specified format var zoneString = ""; while (result.remaining.length > 0 && WHITESPACE.indexOf(result.remaining.charAt(0)) === -1) { zoneString += result.remaining.charAt(0); result.remaining = result.remaining.substr(1); } zoneString = zoneString.trim(); if (zoneString) { // ensure chopping off GMT does not hide time zone errors (bit of a sloppy regex but OK) if (hadGMT && !zoneString.match(/[\+\-]?[\d\:]+/i)) { return (0, error_1.throwError)("ParseError", "invalid time zone 'GMT" + zoneString + "'"); } try { result.zone = timezone_1.TimeZone.zone(zoneString); } catch (e) { if ((0, error_1.errorIs)(e, ["Argument.S", "NotFound.Zone"])) { e = (0, error_1.error)("ParseError", e.message); } throw e; } } else { return (0, error_1.throwError)("ParseError", "no time zone given"); } return result; } /** * * @param s * @param expected * @throws timezonecomplete.ParseError */ function stripRaw(s, expected) { var remaining = s; var eremaining = expected; while (remaining.length > 0 && eremaining.length > 0 && remaining.charAt(0) === eremaining.charAt(0)) { remaining = remaining.substr(1); eremaining = eremaining.substr(1); } if (eremaining.length > 0) { return (0, error_1.throwError)("ParseError", "expected '".concat(expected, "'")); } return remaining; } /** * * @param token * @param remaining * @param locale * @throws timezonecomplete.ParseError */ function stripDayPeriod(token, remaining, locale) { var _a, _b, _c, _d, _e, _f; var offsets; switch (token.symbol) { case "a": switch (token.length) { case 4: offsets = (_a = {}, _a[locale.dayPeriodWide.am] = "am", _a[locale.dayPeriodWide.pm] = "pm", _a); break; case 5: offsets = (_b = {}, _b[locale.dayPeriodNarrow.am] = "am", _b[locale.dayPeriodNarrow.pm] = "pm", _b); break; default: offsets = (_c = {}, _c[locale.dayPeriodAbbreviated.am] = "am", _c[locale.dayPeriodAbbreviated.pm] = "pm", _c); break; } break; default: switch (token.length) { case 4: offsets = (_d = {}, _d[locale.dayPeriodWide.am] = "am", _d[locale.dayPeriodWide.midnight] = "midnight", _d[locale.dayPeriodWide.pm] = "pm", _d[locale.dayPeriodWide.noon] = "noon", _d); break; case 5: offsets = (_e = {}, _e[locale.dayPeriodNarrow.am] = "am", _e[locale.dayPeriodNarrow.midnight] = "midnight", _e[locale.dayPeriodNarrow.pm] = "pm", _e[locale.dayPeriodNarrow.noon] = "noon", _e); break; default: offsets = (_f = {}, _f[locale.dayPeriodAbbreviated.am] = "am", _f[locale.dayPeriodAbbreviated.midnight] = "midnight", _f[locale.dayPeriodAbbreviated.pm] = "pm", _f[locale.dayPeriodAbbreviated.noon] = "noon", _f); break; } break; } // match longest possible day period string; sort keys by length descending var sortedKeys = Object.keys(offsets) .sort(function (a, b) { return (a.length < b.length ? 1 : a.length > b.length ? -1 : 0); }); var upper = remaining.toUpperCase(); for (var _i = 0, sortedKeys_1 = sortedKeys; _i < sortedKeys_1.length; _i++) { var key = sortedKeys_1[_i]; if (upper.startsWith(key.toUpperCase())) { return { type: offsets[key], remaining: remaining.slice(key.length) }; } } return (0, error_1.throwError)("ParseError", "missing day period i.e. " + Object.keys(offsets).join(", ")); } /** * Returns factor -1 or 1 depending on BC or AD * @param token * @param remaining * @param locale * @returns [factor, remaining] * @throws timezonecomplete.ParseError */ function stripEra(token, remaining, locale) { var allowed; switch (token.length) { case 4: allowed = locale.eraWide; break; case 5: allowed = locale.eraNarrow; break; default: allowed = locale.eraAbbreviated; break; } var result = stripStrings(token, remaining, allowed); return [allowed.indexOf(result.chosen) === 0 ? 1 : -1, result.remaining]; } /** * * @param token * @param remaining * @param locale * @throws timezonecomplete.ParseError * @throws timezonecomplete.Argument.FormatString */ function stripQuarter(token, remaining, locale) { var quarterLetter; var quarterWord; var quarterAbbreviations; switch (token.symbol) { case "Q": quarterLetter = locale.quarterLetter; quarterWord = locale.quarterWord; quarterAbbreviations = locale.quarterAbbreviations; break; case "q": { quarterLetter = locale.standAloneQuarterLetter; quarterWord = locale.standAloneQuarterWord; quarterAbbreviations = locale.standAloneQuarterAbbreviations; break; } /* istanbul ignore next */ default: /* istanbul ignore next */ return (0, error_1.throwError)("Argument.FormatString", "invalid quarter pattern"); } var allowed; switch (token.length) { case 1: case 5: return stripNumber(remaining, 1); case 2: return stripNumber(remaining, 2); case 3: allowed = [1, 2, 3, 4].map(function (n) { return quarterLetter + n.toString(10); }); break; case 4: allowed = quarterAbbreviations.map(function (a) { return a + " " + quarterWord; }); break; /* istanbul ignore next */ default: /* istanbul ignore next */ return (0, error_1.throwError)("Argument.FormatString", "invalid quarter pattern"); } var r = stripStrings(token, remaining, allowed); return { n: allowed.indexOf(r.chosen) + 1, remaining: r.remaining }; } /** * * @param token * @param remaining * @param locale * @returns remaining string * @throws timezonecomplete.ParseError * @throws timezonecomplete.Argument.FormatString */ function stripWeekDay(token, remaining, locale) { var allowed; switch (token.length) { case 1: { if (token.symbol === "e") { return stripNumber(remaining, 1).remaining; } else { allowed = locale.shortWeekdayNames; } } break; case 2: { if (token.symbol === "e") { return stripNumber(remaining, 2).remaining; } else { allowed = locale.shortWeekdayNames; } } break; case 3: allowed = locale.shortWeekdayNames; break; case 4: allowed = locale.longWeekdayNames; break; case 5: allowed = locale.weekdayLetters; break; case 6: allowed = locale.weekdayTwoLetters; break; /* istanbul ignore next */ default: /* istanbul ignore next */ return (0, error_1.throwError)("Argument.FormatString", "invalid quarter pattern"); } var r = stripStrings(token, remaining, allowed); return r.remaining; } /** * * @param token * @param remaining * @param locale * @throws timezonecomplete.ParseError * @throws timezonecomplete.Argument.FormatString */ function stripMonth(token, remaining, locale) { var shortMonthNames; var longMonthNames; var monthLetters; switch (token.symbol) { case "M": shortMonthNames = locale.shortMonthNames; longMonthNames = locale.longMonthNames; monthLetters = locale.monthLetters; break; case "L": shortMonthNames = locale.standAloneShortMonthNames; longMonthNames = locale.standAloneLongMonthNames; monthLetters = locale.standAloneMonthLetters; break; /* istanbul ignore next */ default: /* istanbul ignore next */ return (0, error_1.throwError)("Argument.FormatString", "invalid month pattern"); } var allowed; switch (token.length) { case 1: case 2: return stripNumber(remaining, 2); case 3: allowed = shortMonthNames; break; case 4: allowed = longMonthNames; break; case 5: allowed = monthLetters; break; /* istanbul ignore next */ default: /* istanbul ignore next */ return (0, error_1.throwError)("Argument.FormatString", "invalid month pattern"); } var r = stripStrings(token, remaining, allowed); return { n: allowed.indexOf(r.chosen) + 1, remaining: r.remaining }; } /** * * @param token * @param remaining * @throws timezonecomplete.ParseError */ function stripHour(token, remaining) { var result = stripNumber(remaining, 2); switch (token.symbol) { case "h": if (result.n === 12) { result.n = 0; } break; case "H": // nothing, in range 0-23 break; case "K": // nothing, in range 0-11 break; case "k": result.n -= 1; break; } return result; } /** * * @param token * @param remaining * @throws timezonecomplete.ParseError * @throws timezonecomplete.Argument.FormatString */ function stripSecond(token, remaining) { switch (token.symbol) { case "s": return stripNumber(remaining, 2); case "S": return stripNumber(remaining, token.length); case "A": return stripNumber(remaining, 8); /* istanbul ignore next */ default: /* istanbul ignore next */ return (0, error_1.throwError)("Argument.FormatString", "invalid seconds pattern"); } } /** * * @param s * @param maxLength * @throws timezonecomplete.ParseError */ function stripNumber(s, maxLength) { var result = { n: NaN, remaining: s }; var numberString = ""; while (numberString.length < maxLength && result.remaining.length > 0 && result.remaining.charAt(0).match(/\d/)) { numberString += result.remaining.charAt(0); result.remaining = result.remaining.substr(1); } // remove leading zeroes while (numberString.charAt(0) === "0" && numberString.length > 1) { numberString = numberString.substr(1); } result.n = parseInt(numberString, 10); if (numberString === "" || !Number.isFinite(result.n)) { return (0, error_1.throwError)("ParseError", "expected a number but got '".concat(numberString, "'")); } return result; } /** * * @param token * @param remaining * @param allowed * @throws timezonecomplete.ParseError */ function stripStrings(token, remaining, allowed) { // match longest possible string; sort keys by length descending var sortedKeys = allowed.slice() .sort(function (a, b) { return (a.length < b.length ? 1 : a.length > b.length ? -1 : 0); }); var upper = remaining.toUpperCase(); for (var _i = 0, sortedKeys_2 = sortedKeys; _i < sortedKeys_2.length; _i++) { var key = sortedKeys_2[_i]; if (upper.startsWith(key.toUpperCase())) { return { chosen: key, remaining: remaining.slice(key.length) }; } } return (0, error_1.throwError)("ParseError", "invalid " + token_1.TokenType[token.type].toLowerCase() + ", expected one of " + allowed.join(", ")); } },{"./basics":2,"./error":5,"./locale":9,"./math":10,"./timezone":15,"./token":16}],12:[function(require,module,exports){ /** * Copyright(c) 2014 ABB Switzerland Ltd. * * Periodic interval functions */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.timestampOnWeekTimeLessThan = exports.timestampOnWeekTimeGreaterThanOrEqualTo = exports.isPeriod = exports.isValidPeriodJson = exports.Period = exports.periodDstToString = exports.PeriodDst = void 0; var assert_1 = require("./assert"); var basics_1 = require("./basics"); var basics = require("./basics"); var datetime_1 = require("./datetime"); var duration_1 = require("./duration"); var error_1 = require("./error"); var timezone_1 = require("./timezone"); /** * Specifies how the period should repeat across the day * during DST changes. */ var PeriodDst; (function (PeriodDst) { /** * Keep repeating in similar intervals measured in UTC, * unaffected by Daylight Saving Time. * E.g. a repetition of one hour will take one real hour * every time, even in a time zone with DST. * Leap seconds, leap days and month length * differences will still make the intervals different. */ PeriodDst[PeriodDst["RegularIntervals"] = 0] = "RegularIntervals"; /** * Ensure that the time at which the intervals occur stay * at the same place in the day, local time. So e.g. * a period of one day, referenceing at 8:05AM Europe/Amsterdam time * will always reference at 8:05 Europe/Amsterdam. This means that * in UTC time, some intervals will be 25 hours and some * 23 hours during DST changes. * Another example: an hourly interval will be hourly in local time, * skipping an hour in UTC for a DST backward change. */ PeriodDst[PeriodDst["RegularLocalTime"] = 1] = "RegularLocalTime"; /** * End-of-enum marker */ PeriodDst[PeriodDst["MAX"] = 2] = "MAX"; })(PeriodDst || (exports.PeriodDst = PeriodDst = {})); /** * Convert a PeriodDst to a string: "regular intervals" or "regular local time" * @throws timezonecomplete.Argument.P for invalid PeriodDst value */ function periodDstToString(p) { switch (p) { case PeriodDst.RegularIntervals: return "regular intervals"; case PeriodDst.RegularLocalTime: return "regular local time"; /* istanbul ignore next */ default: /* istanbul ignore next */ return (0, error_1.throwError)("Argument.P", "invalid PerioDst value ".concat(p)); } } exports.periodDstToString = periodDstToString; /** * Repeating time period: consists of a reference date and * a time length. This class accounts for leap seconds and leap days. */ var Period = /** @class */ (function () { /** * Constructor implementation. See other constructors for explanation. */ function Period(a, amountOrInterval, unitOrDst, givenDst) { /** * Allow not using instanceof */ this.kind = "Period"; var reference; var interval; var dst = PeriodDst.RegularLocalTime; if ((0, datetime_1.isDateTime)(a)) { reference = a; if (typeof (amountOrInterval) === "object") { interval = amountOrInterval; dst = unitOrDst; } else { (0, assert_1.default)(typeof unitOrDst === "number" && unitOrDst >= 0 && unitOrDst < basics_1.TimeUnit.MAX, "Argument.Unit", "Invalid unit"); interval = new duration_1.Duration(amountOrInterval, unitOrDst); dst = givenDst; } if (typeof dst !== "number") { dst = PeriodDst.RegularLocalTime; } } else { try { reference = new datetime_1.DateTime(a.reference); interval = new duration_1.Duration(a.duration); dst = a.periodDst === "regular" ? PeriodDst.RegularIntervals : PeriodDst.RegularLocalTime; } catch (e) { return (0, error_1.throwError)("Argument.Json", e); } } (0, assert_1.default)(dst >= 0 && dst < PeriodDst.MAX, "Argument.Dst", "Invalid PeriodDst setting"); (0, assert_1.default)(interval.amount() > 0, "Argument.Interval", "Amount must be positive non-zero."); (0, assert_1.default)(Number.isInteger(interval.amount()), "Argument.Interval", "Amount must be a whole number"); this._reference = reference; this._interval = interval; this._dst = dst; this._calcInternalValues(); // regular local time keeping is only supported if we can reset each day // Note we use internal amounts to decide this because actually it is supported if // the input is a multiple of one day. if (this._dstRelevant() && dst === PeriodDst.RegularLocalTime) { switch (this._intInterval.unit()) { case basics_1.TimeUnit.Millisecond: (0, assert_1.default)(this._intInterval.amount() < 86400000, "Argument.Interval.NotImplemented", "When using Hour, Minute or (Milli)Second units, with Regular Local Times, " + "then the amount must be either less than a day or a multiple of the next unit."); break; case basics_1.TimeUnit.Second: (0, assert_1.default)(this._intInterval.amount() < 86400, "Argument.Interval.NotImplemented", "When using Hour, Minute or (Milli)Second units, with Regular Local Times, " + "then the amount must be either less than a day or a multiple of the next unit."); break; case basics_1.TimeUnit.Minute: (0, assert_1.default)(this._intInterval.amount() < 1440, "Argument.Interval.NotImplemented", "When using Hour, Minute or (Milli)Second units, with Regular Local Times, " + "then the amount must be either less than a day or a multiple of the next unit."); break; case basics_1.TimeUnit.Hour: (0, assert_1.default)(this._intInterval.amount() < 24, "Argument.Interval.NotImplemented", "When using Hour, Minute or (Milli)Second units, with Regular Local Times, " + "then the amount must be either less than a day or a multiple of the next unit."); break; } } } /** * Return a fresh copy of the period * @throws nothing */ Period.prototype.clone = function () { return new Period(this._reference, this._interval, this._dst); }; /** * The reference date * @throws nothing */ Period.prototype.reference = function () { return this._reference; }; /** * DEPRECATED: old name for the reference date * @throws nothing */ Period.prototype.start = function () { return this._reference; }; /** * The interval * @throws nothing */ Period.prototype.interval = function () { return this._interval.clone(); }; /** * The amount of units of the interval * @throws nothing */ Period.prototype.amount = function () { return this._interval.amount(); }; /** * The unit of the interval * @throws nothing */ Period.prototype.unit = function () { return this._interval.unit(); }; /** * The dst handling mode * @throws nothing */ Period.prototype.dst = function () { return this._dst; }; /** * The first occurrence of the period greater than * the given date. The given date need not be at a period boundary. * Pre: the fromdate and reference date must either both have timezones or not * @param fromDate: the date after which to return the next date * @return the first date matching the period after fromDate, given in the same zone as the fromDate. * @throws timezonecomplete.UnawareToAwareConversion if not both fromdate and the reference date are both aware or unaware of time zone * @throws timezonecomplete.NotFound.Zone if the UTC time zone doesn't exist in the time zone database */ Period.prototype.findFirst = function (fromDate) { (0, assert_1.default)(!!this._intReference.zone() === !!fromDate.zone(), "UnawareToAwareConversion", "The fromDate and reference date must both be aware or unaware"); var approx; var approx2; var approxMin; var periods; var diff; var newYear; var remainder; var imax; var imin; var imid; var normalFrom = this._normalizeDay(fromDate.toZone(this._intReference.zone())); if (this._intInterval.amount() === 1) { // simple cases: amount equals 1 (eliminates need for searching for referenceing point) if (this._intDst === PeriodDst.RegularIntervals) { // apply to UTC time switch (this._intInterval.unit()) { case basics_1.TimeUnit.Millisecond: approx = new datetime_1.DateTime(normalFrom.utcYear(), normalFrom.utcMonth(), normalFrom.utcDay(), normalFrom.utcHour(), normalFrom.utcMinute(), normalFrom.utcSecond(), normalFrom.utcMillisecond(), timezone_1.TimeZone.utc()); break; case basics_1.TimeUnit.Second: approx = new datetime_1.DateTime(normalFrom.utcYear(), normalFrom.utcMonth(), normalFrom.utcDay(), normalFrom.utcHour(), normalFrom.utcMinute(), normalFrom.utcSecond(), this._intReference.utcMillisecond(), timezone_1.TimeZone.utc()); break; case basics_1.TimeUnit.Minute: approx = new datetime_1.DateTime(normalFrom.utcYear(), normalFrom.utcMonth(), normalFrom.utcDay(), normalFrom.utcHour(), normalFrom.utcMinute(), this._intReference.utcSecond(), this._intReference.utcMillisecond(), timezone_1.TimeZone.utc()); break; case basics_1.TimeUnit.Hour: approx = new datetime_1.DateTime(normalFrom.utcYear(), normalFrom.utcMonth(), normalFrom.utcDay(), normalFrom.utcHour(), this._intReference.utcMinute(), this._intReference.utcSecond(), this._intReference.utcMillisecond(), timezone_1.TimeZone.utc()); break; case basics_1.TimeUnit.Day: approx = new datetime_1.DateTime(normalFrom.utcYear(), normalFrom.utcMonth(), normalFrom.utcDay(), this._intReference.utcHour(), this._intReference.utcMinute(), this._intReference.utcSecond(), this._intReference.utcMillisecond(), timezone_1.TimeZone.utc()); break; case basics_1.TimeUnit.Month: approx = new datetime_1.DateTime(normalFrom.utcYear(), normalFrom.utcMonth(), this._intReference.utcDay(), this._intReference.utcHour(), this._intReference.utcMinute(), this._intReference.utcSecond(), this._intReference.utcMillisecond(), timezone_1.TimeZone.utc()); break; case basics_1.TimeUnit.Year: approx = new datetime_1.DateTime(normalFrom.utcYear(), this._intReference.utcMonth(), this._intReference.utcDay(), this._intReference.utcHour(), this._intReference.utcMinute(), this._intReference.utcSecond(), this._intReference.utcMillisecond(), timezone_1.TimeZone.utc()); break; /* istanbul ignore next */ default: /* istanbul ignore if */ /* istanbul ignore next */ if (true) { return (0, error_1.throwError)("Assertion", "Unknown TimeUnit"); } } while (!approx.greaterThan(fromDate)) { approx = approx.add(this._intInterval.amount(), this._intInterval.unit()); } } else { // Try to keep regular local intervals switch (this._intInterval.unit()) { case basics_1.TimeUnit.Millisecond: approx = new datetime_1.DateTime(normalFrom.year(), normalFrom.month(), normalFrom.day(), normalFrom.hour(), normalFrom.minute(), normalFrom.second(), normalFrom.millisecond(), this._intReference.zone()); break; case basics_1.TimeUnit.Second: approx = new datetime_1.DateTime(normalFrom.year(), normalFrom.month(), normalFrom.day(), normalFrom.hour(), normalFrom.minute(), normalFrom.second(), this._intReference.millisecond(), this._intReference.zone()); break; case basics_1.TimeUnit.Minute: approx = new datetime_1.DateTime(normalFrom.year(), normalFrom.month(), normalFrom.day(), normalFrom.hour(), normalFrom.minute(), this._intReference.second(), this._intReference.millisecond(), this._intReference.zone()); break; case basics_1.TimeUnit.Hour: approx = new datetime_1.DateTime(normalFrom.year(), normalFrom.month(), normalFrom.day(), normalFrom.hour(), this._intReference.minute(), this._intReference.second(), this._intReference.millisecond(), this._intReference.zone()); break; case basics_1.TimeUnit.Day: approx = new datetime_1.DateTime(normalFrom.year(), normalFrom.month(), normalFrom.day(), this._intReference.hour(), this._intReference.minute(), this._intReference.second(), this._intReference.millisecond(), this._intReference.zone()); break; case basics_1.TimeUnit.Month: approx = new datetime_1.DateTime(normalFrom.year(), normalFrom.month(), this._intReference.day(), this._intReference.hour(), this._intReference.minute(), this._intReference.second(), this._intReference.millisecond(), this._intReference.zone()); break; case basics_1.TimeUnit.Year: approx = new datetime_1.DateTime(normalFrom.year(), this._intReference.month(), this._intReference.day(), this._intReference.hour(), this._intReference.minute(), this._intReference.second(), this._intReference.millisecond(), this._intReference.zone()); break; /* istanbul ignore next */ default: /* istanbul ignore if */ /* istanbul ignore next */ if (true) { return (0, error_1.throwError)("Assertion", "Unknown TimeUnit"); } } while (!approx.greaterThan(normalFrom)) { approx = approx.addLocal(this._intInterval.amount(), this._intInterval.unit()); } } } else { // Amount is not 1, if (this._intDst === PeriodDst.RegularIntervals) { // apply to UTC time switch (this._intInterval.unit()) { case basics_1.TimeUnit.Millisecond: diff = normalFrom.diff(this._intReference).milliseconds(); periods = Math.floor(diff / this._intInterval.amount()); approx = this._intReference.add(periods * this._intInterval.amount(), this._intInterval.unit()); break; case basics_1.TimeUnit.Second: diff = normalFrom.diff(this._intReference).seconds(); periods = Math.floor(diff / this._intInterval.amount()); approx = this._intReference.add(periods * this._intInterval.amount(), this._intInterval.unit()); break; case basics_1.TimeUnit.Minute: // only 25 leap seconds have ever been added so this should still be OK. diff = normalFrom.diff(this._intReference).minutes(); periods = Math.floor(diff / this._intInterval.amount()); approx = this._intReference.add(periods * this._intInterval.amount(), this._intInterval.unit()); break; case basics_1.TimeUnit.Hour: diff = normalFrom.diff(this._intReference).hours(); periods = Math.floor(diff / this._intInterval.amount()); approx = this._intReference.add(periods * this._intInterval.amount(), this._intInterval.unit()); break; case basics_1.TimeUnit.Day: diff = normalFrom.diff(this._intReference).hours() / 24; periods = Math.floor(diff / this._intInterval.amount()); approx = this._intReference.add(periods * this._intInterval.amount(), this._intInterval.unit()); break; case basics_1.TimeUnit.Month: diff = (normalFrom.utcYear() - this._intReference.utcYear()) * 12 + (normalFrom.utcMonth() - this._intReference.utcMonth()) - 1; periods = Math.floor(diff / this._intInterval.amount()); approx = this._intReference.add(periods * this._intInterval.amount(), this._intInterval.unit()); break; case basics_1.TimeUnit.Year: // The -1 below is because the day-of-month of reference date may be after the day of the fromDate diff = normalFrom.year() - this._intReference.year() - 1; periods = Math.floor(diff / this._intInterval.amount()); approx = this._intReference.add(periods * this._intInterval.amount(), basics_1.TimeUnit.Year); break; /* istanbul ignore next */ default: /* istanbul ignore if */ /* istanbul ignore next */ if (true) { return (0, error_1.throwError)("Assertion", "Unknown TimeUnit"); } } while (!approx.greaterThan(fromDate)) { approx = approx.add(this._intInterval.amount(), this._intInterval.unit()); } } else { // Try to keep regular local times. If the unit is less than a day, we reference each day anew switch (this._intInterval.unit()) { case basics_1.TimeUnit.Millisecond: if (this._intInterval.amount() < 1000 && (1000 % this._intInterval.amount()) === 0) { // optimization: same millisecond each second, so just take the fromDate // minus one second with the this._intReference milliseconds approx = new datetime_1.DateTime(normalFrom.year(), normalFrom.month(), normalFrom.day(), normalFrom.hour(), normalFrom.minute(), normalFrom.second(), this._intReference.millisecond(), this._intReference.zone()) .subLocal(1, basics_1.TimeUnit.Second); } else { // per constructor assert, the seconds are less than a day, so just go the fromDate reference-of-day approx = new datetime_1.DateTime(normalFrom.year(), normalFrom.month(), normalFrom.day(), this._intReference.hour(), this._intReference.minute(), this._intReference.second(), this._intReference.millisecond(), this._intReference.zone()); // since we start counting from this._intReference each day, we have to // take care of the shorter interval at the boundary remainder = Math.floor((86400000) % this._intInterval.amount()); if (approx.greaterThan(normalFrom)) { // todo /* istanbul ignore if */ if (approx.subLocal(remainder, basics_1.TimeUnit.Millisecond).greaterThan(normalFrom)) { // normalFrom lies outside the boundary period before the reference date approx = approx.subLocal(1, basics_1.TimeUnit.Day); } } else { if (approx.addLocal(1, basics_1.TimeUnit.Day).subLocal(remainder, basics_1.TimeUnit.Millisecond).lessEqual(normalFrom)) { // normalFrom lies in the boundary period, move to the next day approx = approx.addLocal(1, basics_1.TimeUnit.Day); } } // optimization: binary search imax = Math.floor((86400000) / this._intInterval.amount()); imin = 0; while (imax >= imin) { // calculate the midpoint for roughly equal partition imid = Math.floor((imin + imax) / 2); approx2 = approx.addLocal(imid * this._intInterval.amount(), basics_1.TimeUnit.Millisecond); approxMin = approx2.subLocal(this._intInterval.amount(), basics_1.TimeUnit.Millisecond); if (approx2.greaterThan(normalFrom) && approxMin.lessEqual(normalFrom)) { approx = approx2; break; } else if (approx2.lessEqual(normalFrom)) { // change min index to search upper subarray imin = imid + 1; } else { // change max index to search lower subarray imax = imid - 1; } } } break; case basics_1.TimeUnit.Second: if (this._intInterval.amount() < 60 && (60 % this._intInterval.amount()) === 0) { // optimization: same second each minute, so just take the fromDate // minus one minute with the this._intReference seconds approx = new datetime_1.DateTime(normalFrom.year(), normalFrom.month(), normalFrom.day(), normalFrom.hour(), normalFrom.minute(), this._intReference.second(), this._intReference.millisecond(), this._intReference.zone()) .subLocal(1, basics_1.TimeUnit.Minute); } else { // per constructor assert, the seconds are less than a day, so just go the fromDate reference-of-day approx = new datetime_1.DateTime(normalFrom.year(), normalFrom.month(), normalFrom.day(), this._intReference.hour(), this._intReference.minute(), this._intReference.second(), this._intReference.millisecond(), this._intReference.zone()); // since we start counting from this._intReference each day, we have to take // are of the shorter interval at the boundary remainder = Math.floor((86400) % this._intInterval.amount()); if (approx.greaterThan(normalFrom)) { if (approx.subLocal(remainder, basics_1.TimeUnit.Second).greaterThan(normalFrom)) { // normalFrom lies outside the boundary period before the reference date approx = approx.subLocal(1, basics_1.TimeUnit.Day); } } else { if (approx.addLocal(1, basics_1.TimeUnit.Day).subLocal(remainder, basics_1.TimeUnit.Second).lessEqual(normalFrom)) { // normalFrom lies in the boundary period, move to the next day approx = approx.addLocal(1, basics_1.TimeUnit.Day); } } // optimization: binary search imax = Math.floor((86400) / this._intInterval.amount()); imin = 0; while (imax >= imin) { // calculate the midpoint for roughly equal partition imid = Math.floor((imin + imax) / 2); approx2 = approx.addLocal(imid * this._intInterval.amount(), basics_1.TimeUnit.Second); approxMin = approx2.subLocal(this._intInterval.amount(), basics_1.TimeUnit.Second); if (approx2.greaterThan(normalFrom) && approxMin.lessEqual(normalFrom)) { approx = approx2; break; } else if (approx2.lessEqual(normalFrom)) { // change min index to search upper subarray imin = imid + 1; } else { // change max index to search lower subarray imax = imid - 1; } } } break; case basics_1.TimeUnit.Minute: if (this._intInterval.amount() < 60 && (60 % this._intInterval.amount()) === 0) { // optimization: same hour this._intReferenceary each time, so just take the fromDate minus one hour // with the this._intReference minutes, seconds approx = new datetime_1.DateTime(normalFrom.year(), normalFrom.month(), normalFrom.day(), normalFrom.hour(), this._intReference.minute(), this._intReference.second(), this._intReference.millisecond(), this._intReference.zone()) .subLocal(1, basics_1.TimeUnit.Hour); } else { // per constructor assert, the seconds fit in a day, so just go the fromDate previous day approx = new datetime_1.DateTime(normalFrom.year(), normalFrom.month(), normalFrom.day(), this._intReference.hour(), this._intReference.minute(), this._intReference.second(), this._intReference.millisecond(), this._intReference.zone()); // since we start counting from this._intReference each day, // we have to take care of the shorter interval at the boundary remainder = Math.floor((24 * 60) % this._intInterval.amount()); if (approx.greaterThan(normalFrom)) { if (approx.subLocal(remainder, basics_1.TimeUnit.Minute).greaterThan(normalFrom)) { // normalFrom lies outside the boundary period before the reference date approx = approx.subLocal(1, basics_1.TimeUnit.Day); } } else { if (approx.addLocal(1, basics_1.TimeUnit.Day).subLocal(remainder, basics_1.TimeUnit.Minute).lessEqual(normalFrom)) { // normalFrom lies in the boundary period, move to the next day approx = approx.addLocal(1, basics_1.TimeUnit.Day); } } } break; case basics_1.TimeUnit.Hour: approx = new datetime_1.DateTime(normalFrom.year(), normalFrom.month(), normalFrom.day(), this._intReference.hour(), this._intReference.minute(), this._intReference.second(), this._intReference.millisecond(), this._intReference.zone()); // since we start counting from this._intReference each day, // we have to take care of the shorter interval at the boundary remainder = Math.floor(24 % this._intInterval.amount()); if (approx.greaterThan(normalFrom)) { if (approx.subLocal(remainder, basics_1.TimeUnit.Hour).greaterThan(normalFrom)) { // normalFrom lies outside the boundary period before the reference date approx = approx.subLocal(1, basics_1.TimeUnit.Day); } } else { if (approx.addLocal(1, basics_1.TimeUnit.Day).subLocal(remainder, basics_1.TimeUnit.Hour).lessEqual(normalFrom)) { // normalFrom lies in the boundary period, move to the next day approx = approx.addLocal(1, basics_1.TimeUnit.Day); } } break; case basics_1.TimeUnit.Day: // we don't have leap days, so we can approximate by calculating with UTC timestamps diff = normalFrom.diff(this._intReference).hours() / 24; periods = Math.floor(diff / this._intInterval.amount()); approx = this._intReference.addLocal(periods * this._intInterval.amount(), this._intInterval.unit()); break; case basics_1.TimeUnit.Month: diff = (normalFrom.year() - this._intReference.year()) * 12 + (normalFrom.month() - this._intReference.month()); periods = Math.floor(diff / this._intInterval.amount()); approx = this._intReference.addLocal(this._interval.multiply(periods)); break; case basics_1.TimeUnit.Year: // The -1 below is because the day-of-month of reference date may be after the day of the fromDate diff = normalFrom.year() - this._intReference.year() - 1; periods = Math.floor(diff / this._intInterval.amount()); newYear = this._intReference.year() + periods * this._intInterval.amount(); approx = new datetime_1.DateTime(newYear, this._intReference.month(), this._intReference.day(), this._intReference.hour(), this._intReference.minute(), this._intReference.second(), this._intReference.millisecond(), this._intReference.zone()); break; /* istanbul ignore next */ default: /* istanbul ignore if */ /* istanbul ignore next */ if (true) { return (0, error_1.throwError)("Assertion", "Unknown TimeUnit"); } } while (!approx.greaterThan(normalFrom)) { approx = approx.addLocal(this._intInterval.amount(), this._intInterval.unit()); } } } return this._correctDay(approx).convert(fromDate.zone()); }; /** * Returns the next timestamp in the period. The given timestamp must * be at a period boundary, otherwise the answer is incorrect. * This function has MUCH better performance than findFirst. * Returns the datetime "count" times away from the given datetime. * @param prev Boundary date. Must have a time zone (any time zone) iff the period reference date has one. * @param count Number of periods to add. Optional. Must be an integer number, may be positive or negative, default 1 * @return (prev + count * period), in the same timezone as prev. * @throws timezonecomplete.Argument.Prev if prev is undefined * @throws timezonecomplete.Argument.Count if count is not an integer number */ Period.prototype.findNext = function (prev, count) { if (count === void 0) { count = 1; } (0, assert_1.default)(!!prev, "Argument.Prev", "Prev must be given"); (0, assert_1.default)(!!this._intReference.zone() === !!prev.zone(), "UnawareToAwareConversion", "The fromDate and referenceDate must both be aware or unaware"); (0, assert_1.default)(Number.isInteger(count), "Argument.Count", "Count must be an integer number"); var normalizedPrev = this._normalizeDay(prev.toZone(this._reference.zone())); if (this._intDst === PeriodDst.RegularIntervals) { return this._correctDay(normalizedPrev.add(this._intInterval.amount() * count, this._intInterval.unit())).convert(prev.zone()); } else { return this._correctDay(normalizedPrev.addLocal(this._intInterval.amount() * count, this._intInterval.unit())).convert(prev.zone()); } }; /** * The last occurrence of the period less than * the given date. The given date need not be at a period boundary. * Pre: the fromdate and the period reference date must either both have timezones or not * @param fromDate: the date before which to return the next date * @return the last date matching the period before fromDate, given * in the same zone as the fromDate. * @throws timezonecomplete.UnawareToAwareConversion if not both `from` and the reference date are both aware or unaware of time zone * @throws timezonecomplete.NotFound.Zone if the UTC time zone doesn't exist in the time zone database */ Period.prototype.findLast = function (from) { var result = this.findPrev(this.findFirst(from)); if (result.equals(from)) { result = this.findPrev(result); } return result; }; /** * Returns the previous timestamp in the period. The given timestamp must * be at a period boundary, otherwise the answer is incorrect. * @param prev Boundary date. Must have a time zone (any time zone) iff the period reference date has one. * @param count Number of periods to subtract. Optional. Must be an integer number, may be negative. * @return (next - count * period), in the same timezone as next. * @throws timezonecomplete.Argument.Next if prev is undefined * @throws timezonecomplete.Argument.Count if count is not an integer number */ Period.prototype.findPrev = function (next, count) { if (count === void 0) { count = 1; } try { return this.findNext(next, -1 * count); } catch (e) { if ((0, error_1.errorIs)(e, "Argument.Prev")) { e = (0, error_1.error)("Argument.Next", e.message); } throw e; } }; /** * Checks whether the given date is on a period boundary * (expensive!) * @throws timezonecomplete.UnawareToAwareConversion if not both `occurrence` and the reference date are both aware or unaware of time zone * @throws timezonecomplete.NotFound.Zone if the UTC time zone doesn't exist in the time zone database */ Period.prototype.isBoundary = function (occurrence) { if (!occurrence) { return false; } (0, assert_1.default)(!!this._intReference.zone() === !!occurrence.zone(), "UnawareToAwareConversion", "The occurrence and referenceDate must both be aware or unaware"); return (this.findFirst(occurrence.sub(duration_1.Duration.milliseconds(1))).equals(occurrence)); }; /** * Returns true iff this period has the same effect as the given one. * i.e. a period of 24 hours is equal to one of 1 day if they have the same UTC reference moment * and same dst. * @throws timezonecomplete.UnawareToAwareConversion if not both `other#reference()` and the reference date are both aware or unaware * of time zone * @throws timezonecomplete.NotFound.Zone if the UTC time zone doesn't exist in the time zone database */ Period.prototype.equals = function (other) { // note we take the non-normalized _reference because this has an influence on the outcome if (!this.isBoundary(other._reference) || !this._intInterval.equals(other._intInterval)) { return false; } var refZone = this._reference.zone(); var otherZone = other._reference.zone(); var thisIsRegular = (this._intDst === PeriodDst.RegularIntervals || !refZone || refZone.isUtc()); var otherIsRegular = (other._intDst === PeriodDst.RegularIntervals || !otherZone || otherZone.isUtc()); if (thisIsRegular && otherIsRegular) { return true; } if (this._intDst === other._intDst && refZone && otherZone && refZone.equals(otherZone)) { return true; } return false; }; /** * Returns true iff this period was constructed with identical arguments to the other one. * @throws nothing */ Period.prototype.identical = function (other) { return (this._reference.identical(other._reference) && this._interval.identical(other._interval) && this._dst === other._dst); }; /** * Returns an ISO duration string e.g. * 2014-01-01T12:00:00.000+01:00/P1H * 2014-01-01T12:00:00.000+01:00/PT1M (one minute) * 2014-01-01T12:00:00.000+01:00/P1M (one month) * @throws nothing */ Period.prototype.toIsoString = function () { return this._reference.toIsoString() + "/" + this._interval.toIsoString(); }; /** * A string representation e.g. * "10 years, referenceing at 2014-03-01T12:00:00 Europe/Amsterdam, keeping regular intervals". * @throws nothing */ Period.prototype.toString = function () { var result = this._interval.toString() + ", referenceing at " + this._reference.toString(); // only add the DST handling if it is relevant if (this._dstRelevant()) { result += ", keeping " + periodDstToString(this._dst); } return result; }; /** * Returns a JSON-compatible representation of this period * @throws nothing */ Period.prototype.toJson = function () { return { reference: this.reference().toString(), duration: this.interval().toString(), periodDst: this.dst() === PeriodDst.RegularIntervals ? "regular" : "local" }; }; /** * Corrects the difference between _reference and _intReference. * @throws nothing */ Period.prototype._correctDay = function (d) { if (this._reference !== this._intReference) { return new datetime_1.DateTime(d.year(), d.month(), Math.min(basics.daysInMonth(d.year(), d.month()), this._reference.day()), d.hour(), d.minute(), d.second(), d.millisecond(), d.zone()); } else { return d; } }; /** * If this._internalUnit in [Month, Year], normalizes the day-of-month * to <= 28. * @return a new date if different, otherwise the exact same object (no clone!) * @throws nothing */ Period.prototype._normalizeDay = function (d, anymonth) { if (anymonth === void 0) { anymonth = true; } if ((this._intInterval.unit() === basics_1.TimeUnit.Month && d.day() > 28) || (this._intInterval.unit() === basics_1.TimeUnit.Year && (d.month() === 2 || anymonth) && d.day() > 28)) { return new datetime_1.DateTime(d.year(), d.month(), 28, d.hour(), d.minute(), d.second(), d.millisecond(), d.zone()); } else { return d; // save on time by not returning a clone } }; /** * Returns true if DST handling is relevant for us. * (i.e. if the reference time zone has DST) * @throws nothing */ Period.prototype._dstRelevant = function () { var zone = this._reference.zone(); return !!(zone && zone.kind() === timezone_1.TimeZoneKind.Proper && zone.hasDst()); }; /** * Normalize the values where possible - not all values * are convertible into one another. Weeks are converted to days. * E.g. more than 60 minutes is transferred to hours, * but seconds cannot be transferred to minutes due to leap seconds. * Weeks are converted back to days. * @throws nothing */ Period.prototype._calcInternalValues = function () { // normalize any above-unit values var intAmount = this._interval.amount(); var intUnit = this._interval.unit(); if (intUnit === basics_1.TimeUnit.Millisecond && intAmount >= 1000 && intAmount % 1000 === 0) { // note this won't work if we account for leap seconds intAmount = intAmount / 1000; intUnit = basics_1.TimeUnit.Second; } if (intUnit === basics_1.TimeUnit.Second && intAmount >= 60 && intAmount % 60 === 0) { // note this won't work if we account for leap seconds intAmount = intAmount / 60; intUnit = basics_1.TimeUnit.Minute; } if (intUnit === basics_1.TimeUnit.Minute && intAmount >= 60 && intAmount % 60 === 0) { intAmount = intAmount / 60; intUnit = basics_1.TimeUnit.Hour; } if (intUnit === basics_1.TimeUnit.Hour && intAmount >= 24 && intAmount % 24 === 0) { intAmount = intAmount / 24; intUnit = basics_1.TimeUnit.Day; } // now remove weeks so we have one less case to worry about if (intUnit === basics_1.TimeUnit.Week) { intAmount = intAmount * 7; intUnit = basics_1.TimeUnit.Day; } if (intUnit === basics_1.TimeUnit.Month && intAmount >= 12 && intAmount % 12 === 0) { intAmount = intAmount / 12; intUnit = basics_1.TimeUnit.Year; } this._intInterval = new duration_1.Duration(intAmount, intUnit); // normalize dst handling if (this._dstRelevant()) { this._intDst = this._dst; } else { this._intDst = PeriodDst.RegularIntervals; } // normalize reference day this._intReference = this._normalizeDay(this._reference, false); }; return Period; }()); exports.Period = Period; /** * Returns true iff the given json value represents a valid period JSON * @param json * @throws nothing */ function isValidPeriodJson(json) { if (typeof json !== "object") { return false; } if (json === null) { return false; } if (typeof json.duration !== "string") { return false; } if (typeof json.periodDst !== "string") { return false; } if (typeof json.reference !== "string") { return false; } if (!["regular", "local"].includes(json.periodDst)) { return false; } try { // tslint:disable-next-line: no-unused-expression new Period(json); } catch (_a) { return false; } return true; } exports.isValidPeriodJson = isValidPeriodJson; /** * Checks if a given object is of type Period. Note that it does not work for sub classes. However, use this to be robust * against different versions of the library in one process instead of instanceof * @param value Value to check * @throws nothing */ function isPeriod(value) { return typeof value === "object" && value !== null && value.kind === "Period"; } exports.isPeriod = isPeriod; /** * Returns the first timestamp >= `opts.reference` that matches the given weekday and time. Uses the time zone and DST settings * of the given reference time. * @param opts * @throws timezonecomplete.Argument.Hour if opts.hour out of range * @throws timezonecomplete.Argument.Minute if opts.minute out of range * @throws timezonecomplete.Argument.Second if opts.second out of range * @throws timezonecomplete.Argument.Millisecond if opts.millisecond out of range * @throws timezonecomplete.Argument.Weekday if opts.weekday out of range */ function timestampOnWeekTimeGreaterThanOrEqualTo(opts) { var _a, _b, _c; // tslint:disable: max-line-length (0, assert_1.default)(opts.hour >= 0 && opts.hour < 24, "Argument.Hour", "opts.hour should be within [0..23]"); (0, assert_1.default)(opts.minute === undefined || (opts.minute >= 0 && opts.minute < 60 && Number.isInteger(opts.minute)), "Argument.Minute", "opts.minute should be within [0..59]"); (0, assert_1.default)(opts.second === undefined || (opts.second >= 0 && opts.second < 60 && Number.isInteger(opts.second)), "Argument.Second", "opts.second should be within [0..59]"); (0, assert_1.default)(opts.millisecond === undefined || (opts.millisecond >= 0 && opts.millisecond < 1000 && Number.isInteger(opts.millisecond)), "Argument.Millisecond", "opts.millisecond should be within [0.999]"); (0, assert_1.default)(opts.weekday >= 0 && opts.weekday < 7, "Argument.Weekday", "opts.weekday should be within [0..6]"); // tslint:enable: max-line-length var midnight = opts.reference.startOfDay(); while (midnight.weekDay() !== opts.weekday) { midnight = midnight.addLocal((0, duration_1.days)(1)); } var dt = new datetime_1.DateTime(midnight.year(), midnight.month(), midnight.day(), opts.hour, (_a = opts.minute) !== null && _a !== void 0 ? _a : 0, (_b = opts.second) !== null && _b !== void 0 ? _b : 0, (_c = opts.millisecond) !== null && _c !== void 0 ? _c : 0, opts.reference.zone()); if (dt < opts.reference) { // we've started out on the correct weekday and the reference timestamp was greater than the given time, need to skip a week return dt.addLocal((0, duration_1.days)(7)); } return dt; } exports.timestampOnWeekTimeGreaterThanOrEqualTo = timestampOnWeekTimeGreaterThanOrEqualTo; /** * Returns the first timestamp < `opts.reference` that matches the given weekday and time. Uses the time zone and DST settings * of the given reference time. * @param opts * @throws timezonecomplete.Argument.Hour if opts.hour out of range * @throws timezonecomplete.Argument.Minute if opts.minute out of range * @throws timezonecomplete.Argument.Second if opts.second out of range * @throws timezonecomplete.Argument.Millisecond if opts.millisecond out of range * @throws timezonecomplete.Argument.Weekday if opts.weekday out of range */ function timestampOnWeekTimeLessThan(opts) { var _a, _b, _c; // tslint:disable: max-line-length (0, assert_1.default)(opts.hour >= 0 && opts.hour < 24, "Argument.Hour", "opts.hour should be within [0..23]"); (0, assert_1.default)(opts.minute === undefined || (opts.minute >= 0 && opts.minute < 60 && Number.isInteger(opts.minute)), "Argument.Minute", "opts.minute should be within [0..59]"); (0, assert_1.default)(opts.second === undefined || (opts.second >= 0 && opts.second < 60 && Number.isInteger(opts.second)), "Argument.Second", "opts.second should be within [0..59]"); (0, assert_1.default)(opts.millisecond === undefined || (opts.millisecond >= 0 && opts.millisecond < 1000 && Number.isInteger(opts.millisecond)), "Argument.Millisecond", "opts.millisecond should be within [0.999]"); (0, assert_1.default)(opts.weekday >= 0 && opts.weekday < 7, "Argument.Weekday", "opts.weekday should be within [0..6]"); // tslint:enable: max-line-length var midnight = opts.reference.startOfDay().addLocal((0, duration_1.days)(1)); while (midnight.weekDay() !== opts.weekday) { midnight = midnight.subLocal((0, duration_1.days)(1)); } var dt = new datetime_1.DateTime(midnight.year(), midnight.month(), midnight.day(), opts.hour, (_a = opts.minute) !== null && _a !== void 0 ? _a : 0, (_b = opts.second) !== null && _b !== void 0 ? _b : 0, (_c = opts.millisecond) !== null && _c !== void 0 ? _c : 0, opts.reference.zone()); if (dt >= opts.reference) { // we've started out on the correct weekday and the reference timestamp was less than the given time, need to skip a week return dt.subLocal((0, duration_1.days)(7)); } return dt; } exports.timestampOnWeekTimeLessThan = timestampOnWeekTimeLessThan; },{"./assert":1,"./basics":2,"./datetime":3,"./duration":4,"./error":5,"./timezone":15}],13:[function(require,module,exports){ /** * Copyright(c) 2014 ABB Switzerland Ltd. * * String utility functions */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.padRight = exports.padLeft = void 0; var assert_1 = require("./assert"); /** * Pad a string by adding characters to the beginning. * @param s the string to pad * @param width the desired minimum string width * @param char the single character to pad with * @return the padded string * @throws timezonecomplete.Argument.Width if width is not an integer number >= 0 */ function padLeft(s, width, char) { (0, assert_1.default)(Number.isInteger(width) && width >= 0, "Argument.Width", "width should be an integer number >= 0 but is: ".concat(width)); var padding = ""; for (var i = 0; i < (width - s.length); i++) { padding += char; } return padding + s; } exports.padLeft = padLeft; /** * Pad a string by adding characters to the end. * @param s the string to pad * @param width the desired minimum string width * @param char the single character to pad with * @return the padded string * @throws timezonecomplete.Argument.Width if width is not an integer number >= 0 */ function padRight(s, width, char) { (0, assert_1.default)(Number.isInteger(width) && width >= 0, "Argument.Width", "width should be an integer number >= 0 but is: ".concat(width)); var padding = ""; for (var i = 0; i < (width - s.length); i++) { padding += char; } return s + padding; } exports.padRight = padRight; },{"./assert":1}],14:[function(require,module,exports){ /** * Copyright(c) 2014 ABB Switzerland Ltd. */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RealTimeSource = void 0; /** * Default time source, returns actual time */ var RealTimeSource = /** @class */ (function () { function RealTimeSource() { } /** @inheritdoc */ RealTimeSource.prototype.now = function () { /* istanbul ignore if */ /* istanbul ignore next */ if (true) { return new Date(); } }; return RealTimeSource; }()); exports.RealTimeSource = RealTimeSource; },{}],15:[function(require,module,exports){ /** * Copyright(c) 2014 ABB Switzerland Ltd. * * Time zone representation and offset calculation */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.isTimeZone = exports.TimeZone = exports.TimeZoneKind = exports.zone = exports.utc = exports.local = void 0; var assert_1 = require("./assert"); var basics_1 = require("./basics"); var error_1 = require("./error"); var strings = require("./strings"); var tz_database_1 = require("./tz-database"); /** * The local time zone for a given date as per OS settings. Note that time zones are cached * so you don't necessarily get a new object each time. * @throws nothing */ function local() { return TimeZone.local(); } exports.local = local; /** * Coordinated Universal Time zone. Note that time zones are cached * so you don't necessarily get a new object each time. * @throws timezonecomplete.NotFound.Zone if the UTC zone is not present in the time zone database */ function utc() { return TimeZone.utc(); } exports.utc = utc; /** * zone() implementation */ function zone(a, dst) { return TimeZone.zone(a, dst); } exports.zone = zone; /** * The type of time zone */ var TimeZoneKind; (function (TimeZoneKind) { /** * Local time offset as determined by JavaScript Date class. */ TimeZoneKind[TimeZoneKind["Local"] = 0] = "Local"; /** * Fixed offset from UTC, without DST. */ TimeZoneKind[TimeZoneKind["Offset"] = 1] = "Offset"; /** * IANA timezone managed through Olsen TZ database. Includes * DST if applicable. */ TimeZoneKind[TimeZoneKind["Proper"] = 2] = "Proper"; })(TimeZoneKind || (exports.TimeZoneKind = TimeZoneKind = {})); /** * Time zone. The object is immutable because it is cached: * requesting a time zone twice yields the very same object. * Note that we use time zone offsets inverted w.r.t. JavaScript Date.getTimezoneOffset(), * i.e. offset 90 means +01:30. * * Time zones come in three flavors: the local time zone, as calculated by JavaScript Date, * a fixed offset ("+01:30") without DST, or a IANA timezone ("Europe/Amsterdam") with DST * applied depending on the time zone rules. */ var TimeZone = /** @class */ (function () { /** * Do not use this constructor, use the static * TimeZone.zone() method instead. * @param name NORMALIZED name, assumed to be correct * @param dst Adhere to Daylight Saving Time if applicable, ignored for local time and fixed offsets * @throws timezonecomplete.NotFound.Zone if the given zone name doesn't exist * @throws timezonecomplete.InvalidTimeZoneData if the time zone database is invalid */ function TimeZone(name, dst) { if (dst === void 0) { dst = true; } /** * Allow not using instanceof */ this.classKind = "TimeZone"; this._name = name; this._dst = dst; if (name === "localtime") { this._kind = TimeZoneKind.Local; } else if (name.charAt(0) === "+" || name.charAt(0) === "-" || name.charAt(0).match(/\d/) || name === "Z") { this._kind = TimeZoneKind.Offset; this._offset = TimeZone.stringToOffset(name); } else { this._kind = TimeZoneKind.Proper; (0, assert_1.default)(tz_database_1.TzDatabase.instance().exists(name), "NotFound.Zone", "non-existing time zone name '".concat(name, "'")); } } /** * The local time zone for a given date. Note that * the time zone varies with the date: amsterdam time for * 2014-01-01 is +01:00 and amsterdam time for 2014-07-01 is +02:00 * @throws nothing */ TimeZone.local = function () { return TimeZone._findOrCreate("localtime", true); }; /** * The UTC time zone. * @throws timezonecomplete.NotFound.Zone if the UTC time zone doesn't exist in the time zone database */ TimeZone.utc = function () { return TimeZone._findOrCreate("UTC", true); // use 'true' for DST because we want it to display as "UTC", not "UTC without DST" }; /** * zone() implementations */ TimeZone.zone = function (a, dst) { if (dst === void 0) { dst = true; } var name = ""; switch (typeof (a)) { case "string": { var s = a; if (s.indexOf("without DST") >= 0) { dst = false; s = s.slice(0, s.indexOf("without DST") - 1); } name = TimeZone._normalizeString(s); } break; case "number": { var offset = a; (0, assert_1.default)(offset > -24 * 60 && offset < 24 * 60, "Argument.Offset", "TimeZone.zone(): offset out of range"); name = TimeZone.offsetToString(offset); } break; /* istanbul ignore next */ default: (0, error_1.throwError)("Argument.A", "unexpected type for first argument: ".concat(typeof a)); } return TimeZone._findOrCreate(name, dst); }; /** * Makes this class appear clonable. NOTE as time zone objects are immutable you will NOT * actually get a clone but the same object. * @throws nothing */ TimeZone.prototype.clone = function () { return this; }; /** * The time zone identifier. Can be an offset "-01:30" or an * IANA time zone name "Europe/Amsterdam", or "localtime" for * the local time zone. * @throws nothing */ TimeZone.prototype.name = function () { return this._name; }; /** * Whether DST is enabled * @throws nothing */ TimeZone.prototype.dst = function () { return this._dst; }; /** * The kind of time zone (Local/Offset/Proper) * @throws nothing */ TimeZone.prototype.kind = function () { return this._kind; }; /** * Equality operator. Maps zero offsets and different names for UTC onto * each other. Other time zones are not mapped onto each other. * @throws timezonecomplete.InvalidTimeZoneData if the global time zone data is invalid */ TimeZone.prototype.equals = function (other) { if (this.isUtc() && other.isUtc()) { return true; } switch (this._kind) { case TimeZoneKind.Local: return (other.kind() === TimeZoneKind.Local); case TimeZoneKind.Offset: return (other.kind() === TimeZoneKind.Offset && this._offset === other._offset); case TimeZoneKind.Proper: return (other.kind() === TimeZoneKind.Proper && this._name === other._name && (this._dst === other._dst || !this.hasDst())); /* istanbul ignore next */ default: // istanbul ignore next return (0, error_1.throwError)("Assertion", "unknown time zone kind"); } }; /** * Returns true iff the constructor arguments were identical, so UTC !== GMT * @throws nothing */ TimeZone.prototype.identical = function (other) { switch (this._kind) { case TimeZoneKind.Local: return (other.kind() === TimeZoneKind.Local); case TimeZoneKind.Offset: return (other.kind() === TimeZoneKind.Offset && this._offset === other._offset); case TimeZoneKind.Proper: return (other.kind() === TimeZoneKind.Proper && this._name === other._name && this._dst === other._dst); /* istanbul ignore next */ default: // istanbul ignore next return (0, error_1.throwError)("Assertion", "unknown time zone kind"); } }; /** * Is this zone equivalent to UTC? * @throws timezonecomplete.InvalidTimeZoneData if the global time zone data is invalid */ TimeZone.prototype.isUtc = function () { switch (this._kind) { case TimeZoneKind.Local: return false; case TimeZoneKind.Offset: return (this._offset === 0); case TimeZoneKind.Proper: return (tz_database_1.TzDatabase.instance().zoneIsUtc(this._name)); /* istanbul ignore next */ default: // istanbul ignore next return (0, error_1.throwError)("Assertion", "unknown time zone kind"); } }; /** * Does this zone have Daylight Saving Time at all? * @throws timezonecomplete.InvalidTimeZoneData if the global time zone data is invalid */ TimeZone.prototype.hasDst = function () { switch (this._kind) { case TimeZoneKind.Local: return false; case TimeZoneKind.Offset: return false; case TimeZoneKind.Proper: return (tz_database_1.TzDatabase.instance().hasDst(this._name)); /* istanbul ignore next */ default: // istanbul ignore next return (0, error_1.throwError)("Assertion", "unknown time zone kind"); } }; TimeZone.prototype.offsetForUtc = function (a, month, day, hour, minute, second, milli) { var utcTime = (typeof a === "number" ? new basics_1.TimeStruct({ year: a, month: month, day: day, hour: hour, minute: minute, second: second, milli: milli }) : typeof a === "undefined" ? new basics_1.TimeStruct({}) : a); switch (this._kind) { case TimeZoneKind.Local: { var date = new Date(Date.UTC(utcTime.components.year, utcTime.components.month - 1, utcTime.components.day, utcTime.components.hour, utcTime.components.minute, utcTime.components.second, utcTime.components.milli)); return -1 * date.getTimezoneOffset(); } case TimeZoneKind.Offset: { return this._offset; } case TimeZoneKind.Proper: { if (this._dst) { return tz_database_1.TzDatabase.instance().totalOffset(this._name, utcTime).minutes(); } else { return tz_database_1.TzDatabase.instance().standardOffset(this._name, utcTime).minutes(); } } /* istanbul ignore next */ default: // istanbul ignore next return (0, error_1.throwError)("Assertion", "unknown time zone kind"); } }; TimeZone.prototype.standardOffsetForUtc = function (a, month, day, hour, minute, second, milli) { var utcTime = (typeof a === "number" ? new basics_1.TimeStruct({ year: a, month: month, day: day, hour: hour, minute: minute, second: second, milli: milli }) : typeof a === "undefined" ? new basics_1.TimeStruct({}) : a); switch (this._kind) { case TimeZoneKind.Local: { var date = new Date(Date.UTC(utcTime.components.year, 0, 1, 0)); return -1 * date.getTimezoneOffset(); } case TimeZoneKind.Offset: { return this._offset; } case TimeZoneKind.Proper: { return tz_database_1.TzDatabase.instance().standardOffset(this._name, utcTime).minutes(); } /* istanbul ignore next */ default: // istanbul ignore next return (0, error_1.throwError)("Assertion", "unknown time zone kind"); } }; TimeZone.prototype.offsetForZone = function (a, month, day, hour, minute, second, milli) { var localTime = (typeof a === "number" ? new basics_1.TimeStruct({ year: a, month: month, day: day, hour: hour, minute: minute, second: second, milli: milli }) : typeof a === "undefined" ? new basics_1.TimeStruct({}) : a); switch (this._kind) { case TimeZoneKind.Local: { var date = new Date(localTime.components.year, localTime.components.month - 1, localTime.components.day, localTime.components.hour, localTime.components.minute, localTime.components.second, localTime.components.milli); return -1 * date.getTimezoneOffset(); } case TimeZoneKind.Offset: { return this._offset; } case TimeZoneKind.Proper: { // note that TzDatabase normalizes the given date so we don't have to do it if (this._dst) { return tz_database_1.TzDatabase.instance().totalOffsetLocal(this._name, localTime).minutes(); } else { return tz_database_1.TzDatabase.instance().standardOffset(this._name, localTime).minutes(); } } /* istanbul ignore next */ default: // istanbul ignore next return (0, error_1.throwError)("Assertion", "unknown time zone kind"); } }; /** * Note: will be removed in version 2.0.0 * * Convenience function, takes values from a Javascript Date * Calls offsetForUtc() with the contents of the date * * @param date: the date * @param funcs: the set of functions to use: get() or getUTC() * @throws timezonecomplete.InvalidTimeZoneData if values in the time zone database are invalid */ TimeZone.prototype.offsetForUtcDate = function (date, funcs) { return this.offsetForUtc(basics_1.TimeStruct.fromDate(date, funcs)); }; /** * Note: will be removed in version 2.0.0 * * Convenience function, takes values from a Javascript Date * Calls offsetForUtc() with the contents of the date * * @param date: the date * @param funcs: the set of functions to use: get() or getUTC() * @throws timezonecomplete.InvalidTimeZoneData if values in the time zone database are invalid */ TimeZone.prototype.offsetForZoneDate = function (date, funcs) { return this.offsetForZone(basics_1.TimeStruct.fromDate(date, funcs)); }; TimeZone.prototype.abbreviationForUtc = function (a, b, day, hour, minute, second, milli, c) { var utcTime; var dstDependent = true; if (typeof a !== "number" && !!a) { utcTime = a; dstDependent = (b === false ? false : true); } else { utcTime = new basics_1.TimeStruct({ year: a, month: b, day: day, hour: hour, minute: minute, second: second, milli: milli }); dstDependent = (c === false ? false : true); } switch (this._kind) { case TimeZoneKind.Local: { return "local"; } case TimeZoneKind.Offset: { return this.toString(); } case TimeZoneKind.Proper: { return tz_database_1.TzDatabase.instance().abbreviation(this._name, utcTime, dstDependent); } /* istanbul ignore next */ default: // istanbul ignore next return (0, error_1.throwError)("Assertion", "unknown time zone kind"); } }; TimeZone.prototype.normalizeZoneTime = function (localTime, opt) { if (opt === void 0) { opt = tz_database_1.NormalizeOption.Up; } var tzopt = (opt === tz_database_1.NormalizeOption.Down ? tz_database_1.NormalizeOption.Down : tz_database_1.NormalizeOption.Up); if (this.kind() === TimeZoneKind.Proper) { if (typeof localTime === "number") { return tz_database_1.TzDatabase.instance().normalizeLocal(this._name, new basics_1.TimeStruct(localTime), tzopt).unixMillis; } else { return tz_database_1.TzDatabase.instance().normalizeLocal(this._name, localTime, tzopt); } } else { return localTime; } }; /** * The time zone identifier (normalized). * Either "localtime", IANA name, or "+hh:mm" offset. * @throws nothing */ TimeZone.prototype.toString = function () { var result = this.name(); if (this.kind() === TimeZoneKind.Proper) { if (this.hasDst() && !this.dst()) { result += " without DST"; } } return result; }; /** * Convert an offset number into an offset string * @param offset The offset in minutes from UTC e.g. 90 minutes * @return the offset in ISO notation "+01:30" for +90 minutes * @throws Argument.Offset if offset is not a finite number or not within -24 * 60 ... +24 * 60 minutes */ TimeZone.offsetToString = function (offset) { (0, assert_1.default)(Number.isFinite(offset) && offset >= -24 * 60 && offset <= 24 * 60, "Argument.Offset", "invalid offset ".concat(offset)); var sign = (offset < 0 ? "-" : "+"); var hours = Math.floor(Math.abs(offset) / 60); var minutes = Math.floor(Math.abs(offset) % 60); return sign + strings.padLeft(hours.toString(10), 2, "0") + ":" + strings.padLeft(minutes.toString(10), 2, "0"); }; /** * String to offset conversion. * @param s Formats: "-01:00", "-0100", "-01", "Z" * @return offset w.r.t. UTC in minutes * @throws timezonecomplete.Argument.S if s cannot be parsed */ TimeZone.stringToOffset = function (s) { var t = s.trim(); // easy case if (t === "Z") { return 0; } // check that the remainder conforms to ISO time zone spec (0, assert_1.default)(t.match(/^[+-]\d$/) || t.match(/^[+-]\d\d$/) || t.match(/^[+-]\d\d(:?)\d\d$/), "Argument.S", "Wrong time zone format: \"" + t + "\""); var sign = (t.charAt(0) === "+" ? 1 : -1); var hours = 0; var minutes = 0; switch (t.length) { case 2: hours = parseInt(t.slice(1, 2), 10); break; case 3: hours = parseInt(t.slice(1, 3), 10); break; case 5: hours = parseInt(t.slice(1, 3), 10); minutes = parseInt(t.slice(3, 5), 10); break; case 6: hours = parseInt(t.slice(1, 3), 10); minutes = parseInt(t.slice(4, 6), 10); break; } (0, assert_1.default)(hours >= 0 && hours < 24, "Argument.S", "Invalid time zone (hours out of range): '".concat(t, "'")); (0, assert_1.default)(minutes >= 0 && minutes < 60, "Argument.S", "Invalid time zone (minutes out of range): '".concat(t, "'")); return sign * (hours * 60 + minutes); }; /** * Find in cache or create zone * @param name Time zone name * @param dst Adhere to Daylight Saving Time? * @throws timezonecomplete.NotFound.Zone if the zone doesn't exist in the time zone database */ TimeZone._findOrCreate = function (name, dst) { var key = name + (dst ? "_DST" : "_NO-DST"); if (key in TimeZone._cache) { return TimeZone._cache[key]; } else { var t = new TimeZone(name, dst); TimeZone._cache[key] = t; return t; } }; /** * Normalize a string so it can be used as a key for a cache lookup * @throws Argument.S if s is empty */ TimeZone._normalizeString = function (s) { var t = s.trim(); (0, assert_1.default)(t.length > 0, "Argument.S", "Empty time zone string given"); if (t === "localtime") { return t; } else if (t === "Z") { return "+00:00"; } else if (TimeZone._isOffsetString(t)) { // offset string // normalize by converting back and forth try { return TimeZone.offsetToString(TimeZone.stringToOffset(t)); } catch (e) { if ((0, error_1.errorIs)(e, "Argument.Offset")) { e = (0, error_1.error)("Argument.S", e.message); } throw e; } } else { // Olsen TZ database name return t; } }; /** * Returns true iff the first non-whitespace character of s is +, -, or Z * @param s * @throws nothing */ TimeZone._isOffsetString = function (s) { var t = s.trim(); return (t.charAt(0) === "+" || t.charAt(0) === "-" || t === "Z"); }; /** * Time zone cache. */ TimeZone._cache = {}; return TimeZone; }()); exports.TimeZone = TimeZone; /** * Checks if a given object is of type TimeZone. Note that it does not work for sub classes. However, use this to be robust * against different versions of the library in one process instead of instanceof * @param value Value to check * @throws nothing */ function isTimeZone(value) { return typeof value === "object" && value !== null && value.classKind === "TimeZone"; } exports.isTimeZone = isTimeZone; },{"./assert":1,"./basics":2,"./error":5,"./strings":13,"./tz-database":17}],16:[function(require,module,exports){ /** * Functionality to parse a DateTime object to a string */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.tokenize = exports.TokenType = void 0; /** * Different types of tokens, each for a DateTime "period type" (like year, month, hour etc.) */ var TokenType; (function (TokenType) { /** * Raw text */ TokenType[TokenType["IDENTITY"] = 0] = "IDENTITY"; TokenType[TokenType["ERA"] = 1] = "ERA"; TokenType[TokenType["YEAR"] = 2] = "YEAR"; TokenType[TokenType["QUARTER"] = 3] = "QUARTER"; TokenType[TokenType["MONTH"] = 4] = "MONTH"; TokenType[TokenType["WEEK"] = 5] = "WEEK"; TokenType[TokenType["DAY"] = 6] = "DAY"; TokenType[TokenType["WEEKDAY"] = 7] = "WEEKDAY"; TokenType[TokenType["DAYPERIOD"] = 8] = "DAYPERIOD"; TokenType[TokenType["HOUR"] = 9] = "HOUR"; TokenType[TokenType["MINUTE"] = 10] = "MINUTE"; TokenType[TokenType["SECOND"] = 11] = "SECOND"; TokenType[TokenType["ZONE"] = 12] = "ZONE"; })(TokenType || (exports.TokenType = TokenType = {})); /** * Tokenize an LDML date/time format string * @param formatString the string to tokenize * @throws nothing */ function tokenize(formatString) { if (!formatString) { return []; } var result = []; var appendToken = function (tokenString, raw) { // The tokenString may be longer than supported for a tokentype, e.g. "hhhh" which would be TWO hour specs. // We greedily consume LDML specs while possible while (tokenString !== "") { if (raw || !SYMBOL_MAPPING.hasOwnProperty(tokenString[0])) { var token = { length: tokenString.length, raw: tokenString, symbol: tokenString[0], type: TokenType.IDENTITY }; result.push(token); tokenString = ""; } else { // depending on the type of token, different lengths may be supported var info = SYMBOL_MAPPING[tokenString[0]]; var length_1 = void 0; if (info.maxLength === undefined && (!Array.isArray(info.lengths) || info.lengths.length === 0)) { // everything is allowed length_1 = tokenString.length; } else if (info.maxLength !== undefined) { // greedily gobble up length_1 = Math.min(tokenString.length, info.maxLength); } else /* istanbul ignore else */ if (Array.isArray(info.lengths) && info.lengths.length > 0) { // find maximum allowed length for (var _i = 0, _a = info.lengths; _i < _a.length; _i++) { var l = _a[_i]; if (l <= tokenString.length && (length_1 === undefined || length_1 < l)) { length_1 = l; } } } /* istanbul ignore if */ if (length_1 === undefined) { // no allowed length found (not possible with current symbol mapping since length 1 is always allowed) var token = { length: tokenString.length, raw: tokenString, symbol: tokenString[0], type: TokenType.IDENTITY }; result.push(token); tokenString = ""; } else { // prefix found var token = { length: length_1, raw: tokenString.slice(0, length_1), symbol: tokenString[0], type: info.type }; result.push(token); tokenString = tokenString.slice(length_1); } } } }; var currentToken = ""; var previousChar = ""; var quoting = false; var possibleEscaping = false; for (var _i = 0, formatString_1 = formatString; _i < formatString_1.length; _i++) { var currentChar = formatString_1[_i]; // Hanlde escaping and quoting if (currentChar === "'") { if (!quoting) { if (possibleEscaping) { // Escaped a single ' character without quoting if (currentChar !== previousChar) { appendToken(currentToken); currentToken = ""; } currentToken += "'"; possibleEscaping = false; } else { possibleEscaping = true; } } else { // Two possibilities: Were are done quoting, or we are escaping a ' character if (possibleEscaping) { // Escaping, add ' to the token currentToken += currentChar; possibleEscaping = false; } else { // Maybe escaping, wait for next token if we are escaping possibleEscaping = true; } } if (!possibleEscaping) { // Current character is relevant, so save it for inspecting next round previousChar = currentChar; } continue; } else if (possibleEscaping) { quoting = !quoting; possibleEscaping = false; // Flush current token appendToken(currentToken, !quoting); currentToken = ""; } if (quoting) { // Quoting mode, add character to token. currentToken += currentChar; previousChar = currentChar; continue; } if (currentChar !== previousChar) { // We stumbled upon a new token! appendToken(currentToken); currentToken = currentChar; } else { // We are repeating the token with more characters currentToken += currentChar; } previousChar = currentChar; } // Don't forget to add the last token to the result! appendToken(currentToken, quoting); return result; } exports.tokenize = tokenize; var SYMBOL_MAPPING = { G: { type: TokenType.ERA, maxLength: 5 }, y: { type: TokenType.YEAR }, Y: { type: TokenType.YEAR }, u: { type: TokenType.YEAR }, U: { type: TokenType.YEAR, maxLength: 5 }, r: { type: TokenType.YEAR }, Q: { type: TokenType.QUARTER, maxLength: 5 }, q: { type: TokenType.QUARTER, maxLength: 5 }, M: { type: TokenType.MONTH, maxLength: 5 }, L: { type: TokenType.MONTH, maxLength: 5 }, l: { type: TokenType.MONTH, maxLength: 1 }, w: { type: TokenType.WEEK, maxLength: 2 }, W: { type: TokenType.WEEK, maxLength: 1 }, d: { type: TokenType.DAY, maxLength: 2 }, D: { type: TokenType.DAY, maxLength: 3 }, F: { type: TokenType.DAY, maxLength: 1 }, g: { type: TokenType.DAY }, E: { type: TokenType.WEEKDAY, maxLength: 6 }, e: { type: TokenType.WEEKDAY, maxLength: 6 }, c: { type: TokenType.WEEKDAY, maxLength: 6 }, a: { type: TokenType.DAYPERIOD, maxLength: 5 }, b: { type: TokenType.DAYPERIOD, maxLength: 5 }, B: { type: TokenType.DAYPERIOD, maxLength: 5 }, h: { type: TokenType.HOUR, maxLength: 2 }, H: { type: TokenType.HOUR, maxLength: 2 }, k: { type: TokenType.HOUR, maxLength: 2 }, K: { type: TokenType.HOUR, maxLength: 2 }, j: { type: TokenType.HOUR, maxLength: 6 }, J: { type: TokenType.HOUR, maxLength: 2 }, m: { type: TokenType.MINUTE, maxLength: 2 }, s: { type: TokenType.SECOND, maxLength: 2 }, S: { type: TokenType.SECOND }, A: { type: TokenType.SECOND }, z: { type: TokenType.ZONE, maxLength: 4 }, Z: { type: TokenType.ZONE, maxLength: 5 }, O: { type: TokenType.ZONE, lengths: [1, 4] }, v: { type: TokenType.ZONE, lengths: [1, 4] }, V: { type: TokenType.ZONE, maxLength: 4 }, X: { type: TokenType.ZONE, maxLength: 5 }, x: { type: TokenType.ZONE, maxLength: 5 }, }; },{}],17:[function(require,module,exports){ (function (global){(function (){ /** * Copyright(c) 2014 ABB Switzerland Ltd. * * Olsen Timezone Database container * * DO NOT USE THIS CLASS DIRECTLY, USE TimeZone */ "use strict"; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.TzDatabase = exports.NormalizeOption = exports.Transition = exports.isValidOffsetString = exports.ZoneInfo = exports.RuleType = exports.RuleInfo = exports.AtType = exports.OnType = exports.ToType = void 0; var assert_1 = require("./assert"); var basics_1 = require("./basics"); var basics = require("./basics"); var duration_1 = require("./duration"); var error_1 = require("./error"); var math = require("./math"); /** * Type of rule TO column value */ var ToType; (function (ToType) { /** * Either a year number or "only" */ ToType[ToType["Year"] = 0] = "Year"; /** * "max" */ ToType[ToType["Max"] = 1] = "Max"; })(ToType || (exports.ToType = ToType = {})); /** * Type of rule ON column value */ var OnType; (function (OnType) { /** * Day-of-month number */ OnType[OnType["DayNum"] = 0] = "DayNum"; /** * "lastSun" or "lastWed" etc */ OnType[OnType["LastX"] = 1] = "LastX"; /** * e.g. "Sun>=8" */ OnType[OnType["GreqX"] = 2] = "GreqX"; /** * e.g. "Sun<=8" */ OnType[OnType["LeqX"] = 3] = "LeqX"; })(OnType || (exports.OnType = OnType = {})); var AtType; (function (AtType) { /** * Local time (no DST) */ AtType[AtType["Standard"] = 0] = "Standard"; /** * Wall clock time (local time with DST) */ AtType[AtType["Wall"] = 1] = "Wall"; /** * Utc time */ AtType[AtType["Utc"] = 2] = "Utc"; })(AtType || (exports.AtType = AtType = {})); /** * DO NOT USE THIS CLASS DIRECTLY, USE TimeZone * * See http://www.cstdbill.com/tzdb/tz-how-to.html */ var RuleInfo = /** @class */ (function () { /** * Constructor * @param from * @param toType * @param toYear * @param type * @param inMonth * @param onType * @param onDay * @param onWeekDay * @param atHour * @param atMinute * @param atSecond * @param atType * @param save * @param letter * @throws nothing */ function RuleInfo( /** * FROM column year number. */ from, /** * TO column type: Year for year numbers and "only" values, Max for "max" value. */ toType, /** * If TO column is a year, the year number. If TO column is "only", the FROM year. */ toYear, /** * TYPE column, not used so far */ type, /** * IN column month number 1-12 */ inMonth, /** * ON column type */ onType, /** * If onType is DayNum, the day number */ onDay, /** * If onType is not DayNum, the weekday */ onWeekDay, /** * AT column hour */ atHour, /** * AT column minute */ atMinute, /** * AT column second */ atSecond, /** * AT column type */ atType, /** * DST offset from local standard time (NOT from UTC!) */ save, /** * Character to insert in %s for time zone abbreviation * Note if TZ database indicates "-" this is the empty string */ letter) { this.from = from; this.toType = toType; this.toYear = toYear; this.type = type; this.inMonth = inMonth; this.onType = onType; this.onDay = onDay; this.onWeekDay = onWeekDay; this.atHour = atHour; this.atMinute = atMinute; this.atSecond = atSecond; this.atType = atType; this.save = save; this.letter = letter; if (this.save) { this.save = this.save.convert(basics_1.TimeUnit.Hour); } } /** * Returns true iff this rule is applicable in the year * @throws nothing */ RuleInfo.prototype.applicable = function (year) { if (year < this.from) { return false; } switch (this.toType) { case ToType.Max: return true; case ToType.Year: return (year <= this.toYear); } }; /** * Sort comparison * @return (first effective date is less than other's first effective date) * @throws timezonecomplete.InvalidTimeZoneData if this rule depends on a weekday and the weekday in question doesn't exist */ RuleInfo.prototype.effectiveLess = function (other) { if (this.from < other.from) { return true; } if (this.from > other.from) { return false; } if (this.inMonth < other.inMonth) { return true; } if (this.inMonth > other.inMonth) { return false; } if (this.effectiveDate(this.from) < other.effectiveDate(this.from)) { return true; } return false; }; /** * Sort comparison * @return (first effective date is equal to other's first effective date) * @throws timezonecomplete.InvalidTimeZoneData for invalid internal structure of the database */ RuleInfo.prototype.effectiveEqual = function (other) { if (this.from !== other.from) { return false; } if (this.inMonth !== other.inMonth) { return false; } if (!this.effectiveDate(this.from).equals(other.effectiveDate(this.from))) { return false; } return true; }; /** * Returns the year-relative date that the rule takes effect. Depending on the rule this can be a UTC time, a wall clock time, or a * time in standard offset (i.e. you still need to compensate for this.atType) * @throws timezonecomplete.NotApplicable if this rule is not applicable in the given year */ RuleInfo.prototype.effectiveDate = function (year) { (0, assert_1.default)(this.applicable(year), "timezonecomplete.NotApplicable", "Rule is not applicable in ".concat(year)); // year and month are given var y = year; var m = this.inMonth; var d = 0; // calculate day switch (this.onType) { case OnType.DayNum: { d = this.onDay; } break; case OnType.GreqX: { try { d = basics.weekDayOnOrAfter(y, m, this.onDay, this.onWeekDay); } catch (e) { if ((0, error_1.errorIs)(e, "NotFound")) { // Apr Sun>=27 actually means any sunday after April 27, i.e. it does not have to be in April. Try next month. if (m + 1 <= 12) { m = m + 1; } else { m = 1; y = y + 1; } d = basics.firstWeekDayOfMonth(y, m, this.onWeekDay); } } } break; case OnType.LeqX: { try { d = basics.weekDayOnOrBefore(y, m, this.onDay, this.onWeekDay); } catch (e) { if ((0, error_1.errorIs)(e, "NotFound")) { if (m > 1) { m = m - 1; } else { m = 12; y = y - 1; } d = basics.lastWeekDayOfMonth(y, m, this.onWeekDay); } } } break; case OnType.LastX: { d = basics.lastWeekDayOfMonth(y, m, this.onWeekDay); } break; } return basics_1.TimeStruct.fromComponents(y, m, d, this.atHour, this.atMinute, this.atSecond); }; /** * Effective date in UTC in the given year, in a specific time zone * @param year * @param standardOffset the standard offset from UT of the time zone * @param dstOffset the DST offset before the rule */ RuleInfo.prototype.effectiveDateUtc = function (year, standardOffset, dstOffset) { var d = this.effectiveDate(year); switch (this.atType) { case AtType.Utc: return d; case AtType.Standard: { // transition time is in zone local time without DST var millis = d.unixMillis; millis -= standardOffset.milliseconds(); return new basics_1.TimeStruct(millis); } case AtType.Wall: { // transition time is in zone local time with DST var millis = d.unixMillis; millis -= standardOffset.milliseconds(); if (dstOffset) { millis -= dstOffset.milliseconds(); } return new basics_1.TimeStruct(millis); } } }; return RuleInfo; }()); exports.RuleInfo = RuleInfo; /** * Type of reference from zone to rule */ var RuleType; (function (RuleType) { /** * No rule applies */ RuleType[RuleType["None"] = 0] = "None"; /** * Fixed given offset */ RuleType[RuleType["Offset"] = 1] = "Offset"; /** * Reference to a named set of rules */ RuleType[RuleType["RuleName"] = 2] = "RuleName"; })(RuleType || (exports.RuleType = RuleType = {})); /** * DO NOT USE THIS CLASS DIRECTLY, USE TimeZone * * See http://www.cstdbill.com/tzdb/tz-how-to.html * First, and somewhat trivially, whereas Rules are considered to contain one or more records, a Zone is considered to * be a single record with zero or more continuation lines. Thus, the keyword, “Zone,” and the zone name are not repeated. * The last line is the one without anything in the [UNTIL] column. * Second, and more fundamentally, each line of a Zone represents a steady state, not a transition between states. * The state exists from the date and time in the previous line’s [UNTIL] column up to the date and time in the current line’s * [UNTIL] column. In other words, the date and time in the [UNTIL] column is the instant that separates this state from the next. * Where that would be ambiguous because we’re setting our clocks back, the [UNTIL] column specifies the first occurrence of the instant. * The state specified by the last line, the one without anything in the [UNTIL] column, continues to the present. * The first line typically specifies the mean solar time observed before the introduction of standard time. Since there’s no line before * that, it has no beginning. 8-) For some places near the International Date Line, the first two lines will show solar times differing by * 24 hours; this corresponds to a movement of the Date Line. For example: * # Zone NAME GMTOFF RULES FORMAT [UNTIL] * Zone America/Juneau 15:02:19 - LMT 1867 Oct 18 * -8:57:41 - LMT ... * When Alaska was purchased from Russia in 1867, the Date Line moved from the Alaska/Canada border to the Bering Strait; and the time in * Alaska was then 24 hours earlier than it had been. * The abbreviation, “LMT,” stands for “local mean time,” which is an invention of the tz database and was probably never actually * used during the period. Furthermore, the value is almost certainly wrong except in the archetypal place after which the zone is named. * (The tz database usually doesn’t provide a separate Zone record for places where nothing significant happened after 1970.) */ var ZoneInfo = /** @class */ (function () { /** * Constructor * @param gmtoff * @param ruleType * @param ruleOffset * @param ruleName * @param format * @param until * @throws nothing */ function ZoneInfo( /** * GMT offset in fractional minutes, POSITIVE to UTC (note JavaScript.Date gives offsets * contrary to what you might expect). E.g. Europe/Amsterdam has +60 minutes in this field because * it is one hour ahead of UTC */ gmtoff, /** * The RULES column tells us whether daylight saving time is being observed: * A hyphen, a kind of null value, means that we have not set our clocks ahead of standard time. * An amount of time (usually but not necessarily “1:00” meaning one hour) means that we have set our clocks ahead by that amount. * Some alphabetic string means that we might have set our clocks ahead; and we need to check the rule * the name of which is the given alphabetic string. */ ruleType, /** * If the rule column is an offset, this is the offset */ ruleOffset, /** * If the rule column is a rule name, this is the rule name */ ruleName, /** * The FORMAT column specifies the usual abbreviation of the time zone name. It can have one of four forms: * the string, “zzz,” which is a kind of null value (don’t ask) * a single alphabetic string other than “zzz,” in which case that’s the abbreviation * a pair of strings separated by a slash (‘/’), in which case the first string is the abbreviation * for the standard time name and the second string is the abbreviation for the daylight saving time name * a string containing “%s,” in which case the “%s” will be replaced by the text in the appropriate Rule’s LETTER column */ format, /** * Until timestamp in unix utc millis. The zone info is valid up to * and excluding this timestamp. * Note this value can be undefined (for the first rule) */ until) { this.gmtoff = gmtoff; this.ruleType = ruleType; this.ruleOffset = ruleOffset; this.ruleName = ruleName; this.format = format; this.until = until; if (this.ruleOffset) { this.ruleOffset = this.ruleOffset.convert(basics.TimeUnit.Hour); } } return ZoneInfo; }()); exports.ZoneInfo = ZoneInfo; var TzMonthNames; (function (TzMonthNames) { TzMonthNames[TzMonthNames["Jan"] = 1] = "Jan"; TzMonthNames[TzMonthNames["Feb"] = 2] = "Feb"; TzMonthNames[TzMonthNames["Mar"] = 3] = "Mar"; TzMonthNames[TzMonthNames["Apr"] = 4] = "Apr"; TzMonthNames[TzMonthNames["May"] = 5] = "May"; TzMonthNames[TzMonthNames["Jun"] = 6] = "Jun"; TzMonthNames[TzMonthNames["Jul"] = 7] = "Jul"; TzMonthNames[TzMonthNames["Aug"] = 8] = "Aug"; TzMonthNames[TzMonthNames["Sep"] = 9] = "Sep"; TzMonthNames[TzMonthNames["Oct"] = 10] = "Oct"; TzMonthNames[TzMonthNames["Nov"] = 11] = "Nov"; TzMonthNames[TzMonthNames["Dec"] = 12] = "Dec"; })(TzMonthNames || (TzMonthNames = {})); /** * Turns a month name from the TZ database into a number 1-12 * @param name * @throws timezonecomplete.InvalidTimeZoneData for invalid month name */ function monthNameToNumber(name) { for (var i = 1; i <= 12; ++i) { if (TzMonthNames[i] === name) { return i; } } return (0, error_1.throwError)("InvalidTimeZoneData", "Invalid month name '".concat(name, "'")); } var TzDayNames; (function (TzDayNames) { TzDayNames[TzDayNames["Sun"] = 0] = "Sun"; TzDayNames[TzDayNames["Mon"] = 1] = "Mon"; TzDayNames[TzDayNames["Tue"] = 2] = "Tue"; TzDayNames[TzDayNames["Wed"] = 3] = "Wed"; TzDayNames[TzDayNames["Thu"] = 4] = "Thu"; TzDayNames[TzDayNames["Fri"] = 5] = "Fri"; TzDayNames[TzDayNames["Sat"] = 6] = "Sat"; })(TzDayNames || (TzDayNames = {})); /** * Returns true if the given string is a valid offset string i.e. * 1, -1, +1, 01, 1:00, 1:23:25.143 * @throws nothing */ function isValidOffsetString(s) { return /^(\-|\+)?([0-9]+((\:[0-9]+)?(\:[0-9]+(\.[0-9]+)?)?))$/.test(s); } exports.isValidOffsetString = isValidOffsetString; /** * Defines a moment at which the given rule becomes valid */ var Transition = /** @class */ (function () { /** * Constructor * @param at * @param offset * @param letter * @throws nothing */ function Transition( /** * Transition time in UTC millis */ at, /** * New offset (type of offset depends on the function) */ offset, /** * New timzone abbreviation letter */ letter) { this.at = at; this.offset = offset; this.letter = letter; if (this.offset) { this.offset = this.offset.convert(basics.TimeUnit.Hour); } } return Transition; }()); exports.Transition = Transition; /** * Option for TzDatabase#normalizeLocal() */ var NormalizeOption; (function (NormalizeOption) { /** * Normalize non-existing times by ADDING the DST offset */ NormalizeOption[NormalizeOption["Up"] = 0] = "Up"; /** * Normalize non-existing times by SUBTRACTING the DST offset */ NormalizeOption[NormalizeOption["Down"] = 1] = "Down"; })(NormalizeOption || (exports.NormalizeOption = NormalizeOption = {})); /** * This class is a wrapper around time zone data JSON object from the tzdata NPM module. * You usually do not need to use this directly, use TimeZone and DateTime instead. */ var TzDatabase = /** @class */ (function () { /** * Constructor - do not use, this is a singleton class. Use TzDatabase.instance() instead * @throws AlreadyCreated if an instance already exists * @throws timezonecomplete.InvalidTimeZoneData if `data` is empty or invalid */ function TzDatabase(data) { var _this = this; /** * Performance improvement: zone info cache */ this._zoneInfoCache = {}; /** * Performance improvement: rule info cache */ this._ruleInfoCache = {}; /** * pre-calculated transitions per zone */ this._zoneTransitionsCache = new Map(); /** * pre-calculated transitions per ruleset */ this._ruleTransitionsCache = new Map(); (0, assert_1.default)(!TzDatabase._instance, "AlreadyCreated", "You should not create an instance of the TzDatabase class yourself. Use TzDatabase.instance()"); (0, assert_1.default)(data.length > 0, "InvalidTimeZoneData", "Timezonecomplete needs time zone data. You need to install one of the tzdata NPM modules before using timezonecomplete."); if (data.length === 1) { this._data = data[0]; } else { this._data = { zones: {}, rules: {} }; data.forEach(function (d) { if (d && d.rules && d.zones) { for (var _i = 0, _a = Object.keys(d.rules); _i < _a.length; _i++) { var key = _a[_i]; _this._data.rules[key] = d.rules[key]; } for (var _b = 0, _c = Object.keys(d.zones); _b < _c.length; _b++) { var key = _c[_b]; _this._data.zones[key] = d.zones[key]; } } }); } this._minmax = validateData(this._data); } /** * (re-) initialize timezonecomplete with time zone data * * @param data TZ data as JSON object (from one of the tzdata NPM modules). * If not given, Timezonecomplete will search for installed modules. * @throws timezonecomplete.InvalidTimeZoneData if `data` or the global time zone data is invalid */ TzDatabase.init = function (data) { TzDatabase._instance = undefined; // needed for assert in constructor if (data) { TzDatabase._instance = new TzDatabase(Array.isArray(data) ? data : [data]); } else { var data_1 = []; // try to find TZ data in global variables var g = void 0; if (typeof window !== "undefined") { g = window; } else if (typeof global !== "undefined") { g = global; } else if (typeof self !== "undefined") { g = self; } else { g = {}; } if (g) { for (var _i = 0, _a = Object.keys(g); _i < _a.length; _i++) { var key = _a[_i]; if (key.startsWith("tzdata")) { if (typeof g[key] === "object" && g[key].rules && g[key].zones) { data_1.push(g[key]); } } } } // try to find TZ data as installed NPM modules var findNodeModules = function (require) { try { // first try tzdata which contains all data var tzDataName = "tzdata"; var d = require(tzDataName); // use variable to avoid browserify acting up data_1.push(d); } catch (e) { // then try subsets var moduleNames = [ "tzdata-africa", "tzdata-antarctica", "tzdata-asia", "tzdata-australasia", "tzdata-backward", "tzdata-backward-utc", "tzdata-etcetera", "tzdata-europe", "tzdata-northamerica", "tzdata-pacificnew", "tzdata-southamerica", "tzdata-systemv" ]; moduleNames.forEach(function (moduleName) { try { var d = require(moduleName); data_1.push(d); } catch (e) { // nothing } }); } }; if (data_1.length === 0) { if (typeof module === "object" && typeof module.exports === "object") { findNodeModules(require); // need to put require into a function to make webpack happy } } TzDatabase._instance = new TzDatabase(data_1); } }; /** * Single instance of this database * @throws timezonecomplete.InvalidTimeZoneData if the global time zone data is invalid */ TzDatabase.instance = function () { if (!TzDatabase._instance) { TzDatabase.init(); } return TzDatabase._instance; }; /** * Returns a sorted list of all zone names * @throws nothing */ TzDatabase.prototype.zoneNames = function () { if (!this._zoneNames) { this._zoneNames = Object.keys(this._data.zones); this._zoneNames.sort(); } return this._zoneNames; }; /** * Returns true iff the given zone name exists * @param zoneName * @throws nothing */ TzDatabase.prototype.exists = function (zoneName) { return this._data.zones.hasOwnProperty(zoneName); }; /** * Minimum non-zero DST offset (which excludes standard offset) of all rules in the database. * Note that DST offsets need not be whole hours. * * Does return zero if a zoneName is given and there is no DST at all for the zone. * * @param zoneName (optional) if given, the result for the given zone is returned * @throws timezonecomplete.NotFound.Zone if zone name not found or a linked zone not found * @throws timezonecomplete.InvalidTimeZoneData if values in the time zone database are invalid */ TzDatabase.prototype.minDstSave = function (zoneName) { try { if (zoneName) { var zoneInfos = this.getZoneInfos(zoneName); var result = void 0; var ruleNames = []; for (var _i = 0, zoneInfos_1 = zoneInfos; _i < zoneInfos_1.length; _i++) { var zoneInfo = zoneInfos_1[_i]; if (zoneInfo.ruleType === RuleType.Offset) { if (!result || result.greaterThan(zoneInfo.ruleOffset)) { if (zoneInfo.ruleOffset.milliseconds() !== 0) { result = zoneInfo.ruleOffset; } } } if (zoneInfo.ruleType === RuleType.RuleName && ruleNames.indexOf(zoneInfo.ruleName) === -1) { ruleNames.push(zoneInfo.ruleName); var temp = this.getRuleInfos(zoneInfo.ruleName); for (var _a = 0, temp_1 = temp; _a < temp_1.length; _a++) { var ruleInfo = temp_1[_a]; if (!result || result.greaterThan(ruleInfo.save)) { if (ruleInfo.save.milliseconds() !== 0) { result = ruleInfo.save; } } } } } if (!result) { result = duration_1.Duration.hours(0); } return result.clone(); } else { return duration_1.Duration.minutes(this._minmax.minDstSave); } } catch (e) { if ((0, error_1.errorIs)(e, ["NotFound.Rule", "Argument.N"])) { e = (0, error_1.error)("InvalidTimeZoneData", e.message); } throw e; } }; /** * Maximum DST offset (which excludes standard offset) of all rules in the database. * Note that DST offsets need not be whole hours. * * Returns 0 if zoneName given and no DST observed. * * @param zoneName (optional) if given, the result for the given zone is returned * @throws timezonecomplete.NotFound.Zone if zone name not found or a linked zone not found * @throws timezonecomplete.InvalidTimeZoneData if values in the time zone database are invalid */ TzDatabase.prototype.maxDstSave = function (zoneName) { try { if (zoneName) { var zoneInfos = this.getZoneInfos(zoneName); var result = void 0; var ruleNames = []; for (var _i = 0, zoneInfos_2 = zoneInfos; _i < zoneInfos_2.length; _i++) { var zoneInfo = zoneInfos_2[_i]; if (zoneInfo.ruleType === RuleType.Offset) { if (!result || result.lessThan(zoneInfo.ruleOffset)) { result = zoneInfo.ruleOffset; } } if (zoneInfo.ruleType === RuleType.RuleName && ruleNames.indexOf(zoneInfo.ruleName) === -1) { ruleNames.push(zoneInfo.ruleName); var temp = this.getRuleInfos(zoneInfo.ruleName); for (var _a = 0, temp_2 = temp; _a < temp_2.length; _a++) { var ruleInfo = temp_2[_a]; if (!result || result.lessThan(ruleInfo.save)) { result = ruleInfo.save; } } } } if (!result) { result = duration_1.Duration.hours(0); } return result.clone(); } else { return duration_1.Duration.minutes(this._minmax.maxDstSave); } } catch (e) { if ((0, error_1.errorIs)(e, ["NotFound.Rule", "Argument.N"])) { e = (0, error_1.error)("InvalidTimeZoneData", e.message); } throw e; } }; /** * Checks whether the zone has DST at all * @throws timezonecomplete.NotFound.Zone if zone name not found or a linked zone not found * @throws timezonecomplete.InvalidTimeZoneData if values in the time zone database are invalid */ TzDatabase.prototype.hasDst = function (zoneName) { return (this.maxDstSave(zoneName).milliseconds() !== 0); }; TzDatabase.prototype.nextDstChange = function (zoneName, a) { var utcTime = (typeof a === "number" ? new basics_1.TimeStruct(a) : a); var zone = this._getZoneTransitions(zoneName); var iterator = zone.findFirst(); if (iterator && iterator.transition.atUtc > utcTime) { return iterator.transition.atUtc.unixMillis; } while (iterator) { iterator = zone.findNext(iterator); if (iterator && iterator.transition.atUtc > utcTime) { return iterator.transition.atUtc.unixMillis; } } return undefined; }; /** * Returns true iff the given zone name eventually links to * "Etc/UTC", "Etc/GMT" or "Etc/UCT" in the TZ database. This is true e.g. for * "UTC", "GMT", "Etc/GMT" etc. * * @param zoneName IANA time zone name. * @throws nothing */ TzDatabase.prototype.zoneIsUtc = function (zoneName) { var actualZoneName = zoneName; var zoneEntries = this._data.zones[zoneName]; // follow links while (typeof (zoneEntries) === "string") { /* istanbul ignore if */ if (!this._data.zones.hasOwnProperty(zoneEntries)) { throw new Error("Zone \"" + zoneEntries + "\" not found (referred to in link from \"" + zoneName + "\" via \"" + actualZoneName + "\""); } actualZoneName = zoneEntries; zoneEntries = this._data.zones[actualZoneName]; } return (actualZoneName === "Etc/UTC" || actualZoneName === "Etc/GMT" || actualZoneName === "Etc/UCT"); }; TzDatabase.prototype.normalizeLocal = function (zoneName, a, opt) { if (opt === void 0) { opt = NormalizeOption.Up; } if (this.hasDst(zoneName)) { var localTime = (typeof a === "number" ? new basics_1.TimeStruct(a) : a); // local times behave like this during DST changes: // forward change (1h): 0 1 3 4 5 // forward change (2h): 0 1 4 5 6 // backward change (1h): 1 2 2 3 4 // backward change (2h): 1 2 1 2 3 // Therefore, binary searching is not possible. // Instead, we should check the DST forward transitions within a window around the local time // get all transitions (note this includes fake transition rules for zone offset changes) var zone = this._getZoneTransitions(zoneName); var transitions = zone.transitionsInYears(localTime.components.year - 1, localTime.components.year + 1); // find the DST forward transitions var prev = duration_1.Duration.hours(0); for (var _i = 0, transitions_1 = transitions; _i < transitions_1.length; _i++) { var transition = transitions_1[_i]; var offset = transition.newState.dstOffset.add(transition.newState.standardOffset); // forward transition? if (offset.greaterThan(prev)) { var localBefore = transition.atUtc.unixMillis + prev.milliseconds(); var localAfter = transition.atUtc.unixMillis + offset.milliseconds(); if (localTime.unixMillis >= localBefore && localTime.unixMillis < localAfter) { var forwardChange = offset.sub(prev); // non-existing time var factor = (opt === NormalizeOption.Up ? 1 : -1); var resultMillis = localTime.unixMillis + factor * forwardChange.milliseconds(); return (typeof a === "number" ? resultMillis : new basics_1.TimeStruct(resultMillis)); } } prev = offset; } // no non-existing time } return (typeof a === "number" ? a : a.clone()); }; /** * Returns the standard time zone offset from UTC, without DST. * Throws if info not found. * @param zoneName IANA time zone name * @param utcTime Timestamp in UTC, either as TimeStruct or as Unix millisecond value * @throws timezonecomplete.NotFound.Zone if zone name not found or a linked zone not found * @throws timezonecomplete.InvalidTimeZoneData if values in the time zone database are invalid */ TzDatabase.prototype.standardOffset = function (zoneName, utcTime) { var zoneInfo = this.getZoneInfo(zoneName, utcTime); return zoneInfo.gmtoff.clone(); }; /** * Returns the total time zone offset from UTC, including DST, at * the given UTC timestamp. * Throws if zone info not found. * * @param zoneName IANA time zone name * @param utcTime Timestamp in UTC, either as TimeStruct or as Unix millisecond value * @throws timezonecomplete.NotFound.Zone if zone name not found or a linked zone not found * @throws timezonecomplete.InvalidTimeZoneData if values in the time zone database are invalid */ TzDatabase.prototype.totalOffset = function (zoneName, utcTime) { var u = typeof utcTime === "number" ? new basics_1.TimeStruct(utcTime) : utcTime; var zone = this._getZoneTransitions(zoneName); var state = zone.stateAt(u); return state.dstOffset.add(state.standardOffset); }; /** * The time zone rule abbreviation, e.g. CEST for Central European Summer Time. * Note this is dependent on the time, because with time different rules are in effect * and therefore different abbreviations. They also change with DST: e.g. CEST or CET. * * @param zoneName IANA zone name * @param utcTime Timestamp in UTC unix milliseconds * @param dstDependent (default true) set to false for a DST-agnostic abbreviation * @return The abbreviation of the rule that is in effect * @throws timezonecomplete.NotFound.Zone if zone name not found or a linked zone not found * @throws timezonecomplete.InvalidTimeZoneData if values in the time zone database are invalid */ TzDatabase.prototype.abbreviation = function (zoneName, utcTime, dstDependent) { if (dstDependent === void 0) { dstDependent = true; } var u = typeof utcTime === "number" ? new basics_1.TimeStruct(utcTime) : utcTime; var zone = this._getZoneTransitions(zoneName); if (dstDependent) { var state = zone.stateAt(u); return state.abbreviation; } else { var lastNonDst = zone.initialState.dstOffset.milliseconds() === 0 ? zone.initialState.abbreviation : ""; var iterator = zone.findFirst(); if ((iterator === null || iterator === void 0 ? void 0 : iterator.transition.newState.dstOffset.milliseconds()) === 0) { lastNonDst = iterator.transition.newState.abbreviation; } while (iterator && iterator.transition.atUtc <= u) { iterator = zone.findNext(iterator); if ((iterator === null || iterator === void 0 ? void 0 : iterator.transition.newState.dstOffset.milliseconds()) === 0) { lastNonDst = iterator.transition.newState.abbreviation; } } return lastNonDst; } }; /** * Returns the standard time zone offset from UTC, excluding DST, at * the given LOCAL timestamp, again excluding DST. * * If the local timestamp exists twice (as can occur very rarely due to zone changes) * then the first occurrence is returned. * * Throws if zone info not found. * * @param zoneName IANA time zone name * @param localTime Timestamp in time zone time * @throws timezonecomplete.NotFound.Zone if zoneName not found * @throws timezonecomplete.InvalidTimeZoneData if an error is discovered in the time zone database */ TzDatabase.prototype.standardOffsetLocal = function (zoneName, localTime) { var unixMillis = (typeof localTime === "number" ? localTime : localTime.unixMillis); var zoneInfos = this.getZoneInfos(zoneName); for (var _i = 0, zoneInfos_3 = zoneInfos; _i < zoneInfos_3.length; _i++) { var zoneInfo = zoneInfos_3[_i]; if (zoneInfo.until === undefined || zoneInfo.until + zoneInfo.gmtoff.milliseconds() > unixMillis) { return zoneInfo.gmtoff.clone(); } } /* istanbul ignore if */ /* istanbul ignore next */ if (true) { return (0, error_1.throwError)("InvalidTimeZoneData", "No zone info found"); } }; /** * Returns the total time zone offset from UTC, including DST, at * the given LOCAL timestamp. Non-existing local time is normalized out. * There can be multiple UTC times and therefore multiple offsets for a local time * namely during a backward DST change. This returns the FIRST such offset. * Throws if zone info not found. * * @param zoneName IANA time zone name * @param localTime Timestamp in time zone time * @throws timezonecomplete.NotFound.Zone if zoneName not found * @throws timezonecomplete.InvalidTimeZoneData if an error is discovered in the time zone database */ TzDatabase.prototype.totalOffsetLocal = function (zoneName, localTime) { var ts = (typeof localTime === "number" ? new basics_1.TimeStruct(localTime) : localTime); var normalizedTm = this.normalizeLocal(zoneName, ts); /// Note: during offset changes, local time can behave like: // forward change (1h): 0 1 3 4 5 // forward change (2h): 0 1 4 5 6 // backward change (1h): 1 2 2 3 4 // backward change (2h): 1 2 1 2 3 <-- note time going BACKWARD // Therefore binary search does not apply. Linear search through transitions // and return the first offset that matches var zone = this._getZoneTransitions(zoneName); var transitions = zone.transitionsInYears(normalizedTm.components.year - 1, normalizedTm.components.year + 2); var prev; var prevPrev; for (var _i = 0, transitions_2 = transitions; _i < transitions_2.length; _i++) { var transition = transitions_2[_i]; var offset = transition.newState.dstOffset.add(transition.newState.standardOffset); if (transition.atUtc.unixMillis + offset.milliseconds() > normalizedTm.unixMillis) { // found offset: prev.offset applies break; } prevPrev = prev; prev = transition; } /* istanbul ignore else */ if (prev) { // special care during backward change: take first occurrence of local time var prevOffset = prev.newState.dstOffset.add(prev.newState.standardOffset); var prevPrevOffset = prevPrev ? prevPrev.newState.dstOffset.add(prevPrev.newState.standardOffset) : undefined; if (prevPrev && prevPrevOffset !== undefined && prevPrevOffset.greaterThan(prevOffset)) { // backward change var diff = prevPrevOffset.sub(prevOffset); if (normalizedTm.unixMillis >= prev.atUtc.unixMillis + prevOffset.milliseconds() && normalizedTm.unixMillis < prev.atUtc.unixMillis + prevOffset.milliseconds() + diff.milliseconds()) { // within duplicate range return prevPrevOffset.clone(); } else { return prevOffset.clone(); } } else { return prevOffset.clone(); } } else { var state = zone.stateAt(normalizedTm); return state.dstOffset.add(state.standardOffset); } }; /** * DEPRECATED because DST offset depends on the zone too, not just on the ruleset * Returns the DST offset (WITHOUT the standard zone offset) for the given ruleset and the given UTC timestamp * * @deprecated * @param ruleName name of ruleset * @param utcTime UTC timestamp * @param standardOffset Standard offset without DST for the time zone * @throws timezonecomplete.NotFound.Rule if ruleName not found * @throws timezonecomplete.InvalidTimeZoneData if an error is discovered in the time zone database */ TzDatabase.prototype.dstOffsetForRule = function (ruleName, utcTime, standardOffset) { var ts = (typeof utcTime === "number" ? new basics_1.TimeStruct(utcTime) : utcTime); // find applicable transition moments var transitions = this.getTransitionsDstOffsets(ruleName, ts.components.year - 1, ts.components.year, standardOffset); // find the last prior to given date var offset; for (var i = transitions.length - 1; i >= 0; i--) { var transition = transitions[i]; if (transition.at <= ts.unixMillis) { offset = transition.offset.clone(); break; } } /* istanbul ignore if */ if (!offset) { // apparently no longer DST, as e.g. for Asia/Tokyo offset = duration_1.Duration.minutes(0); } return offset; }; /** * Returns the time zone letter for the given * ruleset and the given UTC timestamp * * @deprecated * @param ruleName name of ruleset * @param utcTime UTC timestamp as TimeStruct or unix millis * @param standardOffset Standard offset without DST for the time zone * @throws timezonecomplete.NotFound.Rule if ruleName not found * @throws timezonecomplete.InvalidTimeZoneData if an error is discovered in the time zone database */ TzDatabase.prototype.letterForRule = function (ruleName, utcTime, standardOffset) { var ts = (typeof utcTime === "number" ? new basics_1.TimeStruct(utcTime) : utcTime); // find applicable transition moments var transitions = this.getTransitionsDstOffsets(ruleName, ts.components.year - 1, ts.components.year, standardOffset); // find the last prior to given date var letter; for (var i = transitions.length - 1; i >= 0; i--) { var transition = transitions[i]; if (transition.at <= ts.unixMillis) { letter = transition.letter; break; } } /* istanbul ignore if */ if (!letter) { // apparently no longer DST, as e.g. for Asia/Tokyo letter = ""; } return letter; }; /** * DEPRECATED because DST offset depends on the zone too, not just on the ruleset * Return a list of all transitions in [fromYear..toYear] sorted by effective date * * @deprecated * @param ruleName Name of the rule set * @param fromYear first year to return transitions for * @param toYear Last year to return transitions for * @param standardOffset Standard offset without DST for the time zone * * @return Transitions, with DST offsets (no standard offset included) * @throws timezonecomplete.Argument.FromYear if fromYear > toYear * @throws timezonecomplete.NotFound.Rule if ruleName not found * @throws timezonecomplete.InvalidTimeZoneData if an error is discovered in the time zone database */ TzDatabase.prototype.getTransitionsDstOffsets = function (ruleName, fromYear, toYear, standardOffset) { (0, assert_1.default)(fromYear <= toYear, "Argument.FromYear", "fromYear must be <= toYear"); var rules = this._getRuleTransitions(ruleName); var result = []; var prevDst = (0, duration_1.hours)(0); // wrong, but that's why the function is deprecated var iterator = rules.findFirst(); while (iterator && iterator.transition.at.year <= toYear) { if (iterator.transition.at.year >= fromYear && iterator.transition.at.year <= toYear) { result.push({ at: ruleTransitionUtc(iterator.transition, standardOffset, prevDst).unixMillis, letter: iterator.transition.newState.letter || "", offset: iterator.transition.newState.dstOffset }); } prevDst = iterator.transition.newState.dstOffset; iterator = rules.findNext(iterator); } result.sort(function (a, b) { return a.at - b.at; }); return result; }; /** * Return both zone and rule changes as total (std + dst) offsets. * Adds an initial transition if there is none within the range. * * @param zoneName IANA zone name * @param fromYear First year to include * @param toYear Last year to include * @throws timezonecomplete.Argument.FromYear if fromYear > toYear * @throws timezonecomplete.NotFound.Zone if zoneName not found * @throws timezonecomplete.InvalidTimeZoneData if an error is discovered in the time zone database */ TzDatabase.prototype.getTransitionsTotalOffsets = function (zoneName, fromYear, toYear) { (0, assert_1.default)(fromYear <= toYear, "Argument.FromYear", "fromYear must be <= toYear"); var zone = this._getZoneTransitions(zoneName); var result = []; var startState = zone.stateAt(new basics_1.TimeStruct({ year: fromYear, month: 1, day: 1 })); result.push({ at: new basics_1.TimeStruct({ year: fromYear }).unixMillis, letter: startState.letter, offset: startState.dstOffset.add(startState.standardOffset) }); var iterator = zone.findFirst(); while (iterator && iterator.transition.atUtc.year <= toYear) { if (iterator.transition.atUtc.year >= fromYear) { result.push({ at: iterator.transition.atUtc.unixMillis, letter: iterator.transition.newState.letter || "", offset: iterator.transition.newState.dstOffset.add(iterator.transition.newState.standardOffset) }); } iterator = zone.findNext(iterator); } result.sort(function (a, b) { return a.at - b.at; }); return result; }; /** * Get the zone info for the given UTC timestamp. Throws if not found. * @param zoneName IANA time zone name * @param utcTime UTC time stamp as unix milliseconds or as a TimeStruct * @returns ZoneInfo object. Do not change, we cache this object. * @throws timezonecomplete.NotFound.Zone if zone name not found or a linked zone not found * @throws timezonecomplete.InvalidTimeZoneData if values in the time zone database are invalid */ TzDatabase.prototype.getZoneInfo = function (zoneName, utcTime) { var unixMillis = (typeof utcTime === "number" ? utcTime : utcTime.unixMillis); var zoneInfos = this.getZoneInfos(zoneName); for (var _i = 0, zoneInfos_4 = zoneInfos; _i < zoneInfos_4.length; _i++) { var zoneInfo = zoneInfos_4[_i]; if (zoneInfo.until === undefined || zoneInfo.until > unixMillis) { return zoneInfo; } } return (0, error_1.throwError)("NotFound.Zone", "\"no zone info found for zone '".concat(zoneName, "'")); }; /** * Return the zone records for a given zone name sorted by UNTIL, after * following any links. * * @param zoneName IANA zone name like "Pacific/Efate" * @return Array of zone infos. Do not change, this is a cached value. * @throws timezonecomplete.NotFound.Zone if zone does not exist or a linked zone does not exit */ TzDatabase.prototype.getZoneInfos = function (zoneName) { // FIRST validate zone name before searching cache /* istanbul ignore if */ (0, assert_1.default)(this._data.zones.hasOwnProperty(zoneName), "NotFound.Zone", "zone not found: '".concat(zoneName, "'")); // Take from cache if (this._zoneInfoCache.hasOwnProperty(zoneName)) { return this._zoneInfoCache[zoneName]; } var result = []; var actualZoneName = zoneName; var zoneEntries = this._data.zones[zoneName]; // follow links while (typeof (zoneEntries) === "string") { /* istanbul ignore if */ if (!this._data.zones.hasOwnProperty(zoneEntries)) { return (0, error_1.throwError)("NotFound.Zone", "Zone \"" + zoneEntries + "\" not found (referred to in link from \"" + zoneName + "\" via \"" + actualZoneName + "\""); } actualZoneName = zoneEntries; zoneEntries = this._data.zones[actualZoneName]; } // final zone info found for (var _i = 0, zoneEntries_1 = zoneEntries; _i < zoneEntries_1.length; _i++) { var zoneEntry = zoneEntries_1[_i]; var ruleType = this.parseRuleType(zoneEntry[1]); var until = math.filterFloat(zoneEntry[3]); if (isNaN(until)) { until = undefined; } result.push(new ZoneInfo(duration_1.Duration.minutes(-1 * math.filterFloat(zoneEntry[0])), ruleType, ruleType === RuleType.Offset ? new duration_1.Duration(zoneEntry[1]) : new duration_1.Duration(), ruleType === RuleType.RuleName ? zoneEntry[1] : "", zoneEntry[2], until)); } result.sort(function (a, b) { // sort undefined last /* istanbul ignore if */ if (a.until === undefined && b.until === undefined) { return 0; } if (a.until !== undefined && b.until === undefined) { return -1; } if (a.until === undefined && b.until !== undefined) { return 1; } return (a.until - b.until); }); this._zoneInfoCache[zoneName] = result; return result; }; /** * Returns the rule set with the given rule name, * sorted by first effective date (uncompensated for "w" or "s" AtTime) * * @param ruleName Name of rule set * @return RuleInfo array. Do not change, this is a cached value. * @throws timezonecomplete.NotFound.Rule if rule not found * @throws timezonecomplete.InvalidTimeZoneData for invalid values in the time zone database */ TzDatabase.prototype.getRuleInfos = function (ruleName) { // validate name BEFORE searching cache (0, assert_1.default)(this._data.rules.hasOwnProperty(ruleName), "NotFound.Rule", "Rule set \"" + ruleName + "\" not found."); // return from cache if (this._ruleInfoCache.hasOwnProperty(ruleName)) { return this._ruleInfoCache[ruleName]; } try { var result = []; var ruleSet = this._data.rules[ruleName]; for (var _i = 0, ruleSet_1 = ruleSet; _i < ruleSet_1.length; _i++) { var rule = ruleSet_1[_i]; var fromYear = (rule[0] === "NaN" ? -10000 : parseInt(rule[0], 10)); var toType = this.parseToType(rule[1]); var toYear = (toType === ToType.Max ? 0 : (rule[1] === "only" ? fromYear : parseInt(rule[1], 10))); var onType = this.parseOnType(rule[4]); var onDay = this.parseOnDay(rule[4], onType); var onWeekDay = this.parseOnWeekDay(rule[4]); var monthName = rule[3]; var monthNumber = monthNameToNumber(monthName); result.push(new RuleInfo(fromYear, toType, toYear, rule[2], monthNumber, onType, onDay, onWeekDay, math.positiveModulo(parseInt(rule[5][0], 10), 24), // note the database sometimes contains "24" as hour value math.positiveModulo(parseInt(rule[5][1], 10), 60), math.positiveModulo(parseInt(rule[5][2], 10), 60), this.parseAtType(rule[5][3]), duration_1.Duration.minutes(parseInt(rule[6], 10)), rule[7] === "-" ? "" : rule[7])); } result.sort(function (a, b) { /* istanbul ignore if */ if (a.effectiveEqual(b)) { return 0; } else if (a.effectiveLess(b)) { return -1; } else { return 1; } }); this._ruleInfoCache[ruleName] = result; return result; } catch (e) { if ((0, error_1.errorIs)(e, ["Argument.To", "Argument.N", "Argument.Value", "Argument.Amount"])) { e = (0, error_1.error)("InvalidTimeZoneData", e.message); } throw e; } }; /** * Parse the RULES column of a zone info entry * and see what kind of entry it is. * @throws nothing */ TzDatabase.prototype.parseRuleType = function (rule) { if (rule === "-") { return RuleType.None; } else if (isValidOffsetString(rule)) { return RuleType.Offset; } else { return RuleType.RuleName; } }; /** * Parse the TO column of a rule info entry * and see what kind of entry it is. * @throws timezonecomplete.Argument.To for invalid TO */ TzDatabase.prototype.parseToType = function (to) { // istanbul ignore else if (to === "max") { return ToType.Max; } else if (to === "only") { return ToType.Year; // yes we return Year for only } else if (!isNaN(parseInt(to, 10))) { return ToType.Year; } else { return (0, error_1.throwError)("Argument.To", "TO column incorrect: ".concat(to)); } }; /** * Parse the ON column of a rule info entry * and see what kind of entry it is. * @throws nothing */ TzDatabase.prototype.parseOnType = function (on) { if (on.length > 4 && on.substr(0, 4) === "last") { return OnType.LastX; } if (on.indexOf("<=") !== -1) { return OnType.LeqX; } if (on.indexOf(">=") !== -1) { return OnType.GreqX; } return OnType.DayNum; }; /** * Get the day number from an ON column string, 0 if no day. * @throws nothing */ TzDatabase.prototype.parseOnDay = function (on, onType) { switch (onType) { case OnType.DayNum: return parseInt(on, 10); case OnType.LeqX: return parseInt(on.substr(on.indexOf("<=") + 2), 10); case OnType.GreqX: return parseInt(on.substr(on.indexOf(">=") + 2), 10); /* istanbul ignore next */ default: /* istanbul ignore if */ /* istanbul ignore next */ if (true) { return 0; } } }; /** * Get the day-of-week from an ON column string, Sunday if not present. * @throws nothing */ TzDatabase.prototype.parseOnWeekDay = function (on) { for (var i = 0; i < 7; i++) { if (on.indexOf(TzDayNames[i]) !== -1) { return i; } } /* istanbul ignore if */ /* istanbul ignore next */ if (true) { return basics_1.WeekDay.Sunday; } }; /** * Parse the AT column of a rule info entry * and see what kind of entry it is. * @throws nothing */ TzDatabase.prototype.parseAtType = function (at) { switch (at) { case "s": return AtType.Standard; case "u": return AtType.Utc; case "g": return AtType.Utc; case "z": return AtType.Utc; case "w": return AtType.Wall; case "": return AtType.Wall; case null: return AtType.Wall; default: /* istanbul ignore if */ /* istanbul ignore next */ if (true) { return AtType.Wall; } } }; /** * Get pre-calculated zone transitions * @param zoneName * @throws timezonecomplete.NotFound.Zone if zone does not exist or a linked zone does not exit * @throws timezonecomplete.InvalidTimeZoneData for invalid values in the time zone database */ TzDatabase.prototype._getZoneTransitions = function (zoneName) { var result = this._zoneTransitionsCache.get(zoneName); if (!result) { result = new CachedZoneTransitions(zoneName, this.getZoneInfos(zoneName), this._getRuleTransitionsForZone(zoneName)); this._zoneTransitionsCache.set(zoneName, result); } return result; }; /** * Get pre-calculated rule transitions * @param ruleName * @throws timezonecomplete.NotFound.Rule if rule not found * @throws timezonecomplete.InvalidTimeZoneData for invalid values in the time zone database */ TzDatabase.prototype._getRuleTransitions = function (ruleName) { var result = this._ruleTransitionsCache.get(ruleName); if (!result) { result = new CachedRuleTransitions(this.getRuleInfos(ruleName)); this._ruleTransitionsCache.set(ruleName, result); } return result; }; /** * Returns a map of ruleName->CachedRuleTransitions for all rule sets that are referenced by a zone * @param zoneName * @throws timezonecomplete.NotFound.Zone if zone does not exist or a linked zone does not exit * @throws timezonecomplete.NotFound.Rule if rule not found * @throws timezonecomplete.InvalidTimeZoneData for invalid values in the time zone database */ TzDatabase.prototype._getRuleTransitionsForZone = function (zoneName) { var result = new Map(); var zoneInfos = this.getZoneInfos(zoneName); for (var _i = 0, zoneInfos_5 = zoneInfos; _i < zoneInfos_5.length; _i++) { var zoneInfo = zoneInfos_5[_i]; if (zoneInfo.ruleType === RuleType.RuleName) { if (!result.has(zoneInfo.ruleName)) { result.set(zoneInfo.ruleName, this._getRuleTransitions(zoneInfo.ruleName)); } } } return result; }; return TzDatabase; }()); exports.TzDatabase = TzDatabase; /** * Sanity check on data. Returns min/max values. * @throws timezonecomplete.InvalidTimeZoneData for invalid data */ function validateData(data) { var result = {}; (0, assert_1.default)(typeof data === "object", "InvalidTimeZoneData", "time zone data should be an object"); (0, assert_1.default)(data.hasOwnProperty("rules"), "InvalidTimeZoneData", "time zone data should be an object with a 'rules' property"); (0, assert_1.default)(data.hasOwnProperty("zones"), "InvalidTimeZoneData", "time zone data should be an object with a 'zones' property"); // validate zones for (var zoneName in data.zones) { if (data.zones.hasOwnProperty(zoneName)) { var zoneArr = data.zones[zoneName]; if (typeof (zoneArr) === "string") { // ok, is link to other zone, check link (0, assert_1.default)(data.zones.hasOwnProperty(zoneArr), "InvalidTimeZoneData", "Entry for zone \"".concat(zoneName, "\" links to \"").concat(zoneArr, "\" but that doesn't exist")); } else { /* istanbul ignore if */ if (!Array.isArray(zoneArr)) { return (0, error_1.throwError)("InvalidTimeZoneData", "Entry for zone \"".concat(zoneName, "\" is neither a string nor an array")); } for (var i = 0; i < zoneArr.length; i++) { var entry = zoneArr[i]; /* istanbul ignore if */ if (!Array.isArray(entry)) { return (0, error_1.throwError)("InvalidTimeZoneData", "Entry " + i.toString(10) + " for zone \"" + zoneName + "\" is not an array"); } /* istanbul ignore if */ if (entry.length !== 4) { return (0, error_1.throwError)("InvalidTimeZoneData", "Entry " + i.toString(10) + " for zone \"" + zoneName + "\" has length != 4"); } /* istanbul ignore if */ if (typeof entry[0] !== "string") { return (0, error_1.throwError)("InvalidTimeZoneData", "Entry " + i.toString(10) + " for zone \"" + zoneName + "\" first column is not a string"); } var gmtoff = math.filterFloat(entry[0]); /* istanbul ignore if */ if (isNaN(gmtoff)) { return (0, error_1.throwError)("InvalidTimeZoneData", "Entry " + i.toString(10) + " for zone \"" + zoneName + "\" first column does not contain a number"); } /* istanbul ignore if */ if (typeof entry[1] !== "string") { return (0, error_1.throwError)("InvalidTimeZoneData", "Entry " + i.toString(10) + " for zone \"" + zoneName + "\" second column is not a string"); } /* istanbul ignore if */ if (typeof entry[2] !== "string") { return (0, error_1.throwError)("InvalidTimeZoneData", "Entry " + i.toString(10) + " for zone \"" + zoneName + "\" third column is not a string"); } /* istanbul ignore if */ if (typeof entry[3] !== "string" && entry[3] !== null) { return (0, error_1.throwError)("InvalidTimeZoneData", "Entry " + i.toString(10) + " for zone \"" + zoneName + "\" fourth column is not a string nor null"); } /* istanbul ignore if */ if (typeof entry[3] === "string" && isNaN(math.filterFloat(entry[3]))) { return (0, error_1.throwError)("InvalidTimeZoneData", "Entry " + i.toString(10) + " for zone \"" + zoneName + "\" fourth column does not contain a number"); } if (result.maxGmtOff === undefined || gmtoff > result.maxGmtOff) { result.maxGmtOff = gmtoff; } if (result.minGmtOff === undefined || gmtoff < result.minGmtOff) { result.minGmtOff = gmtoff; } } } } } // validate rules for (var ruleName in data.rules) { if (data.rules.hasOwnProperty(ruleName)) { var ruleArr = data.rules[ruleName]; /* istanbul ignore if */ if (!Array.isArray(ruleArr)) { return (0, error_1.throwError)("InvalidTimeZoneData", "Entry for rule \"" + ruleName + "\" is not an array"); } for (var i = 0; i < ruleArr.length; i++) { var rule = ruleArr[i]; /* istanbul ignore if */ if (!Array.isArray(rule)) { return (0, error_1.throwError)("InvalidTimeZoneData", "Rule " + ruleName + "[" + i.toString(10) + "] is not an array"); } /* istanbul ignore if */ if (rule.length < 8) { // note some rules > 8 exists but that seems to be a bug in tz file parsing return (0, error_1.throwError)("InvalidTimeZoneData", "Rule " + ruleName + "[" + i.toString(10) + "] is not of length 8"); } for (var j = 0; j < rule.length; j++) { /* istanbul ignore if */ if (j !== 5 && typeof rule[j] !== "string") { return (0, error_1.throwError)("InvalidTimeZoneData", "Rule " + ruleName + "[" + i.toString(10) + "][" + j.toString(10) + "] is not a string"); } } /* istanbul ignore if */ if (rule[0] !== "NaN" && isNaN(parseInt(rule[0], 10))) { return (0, error_1.throwError)("InvalidTimeZoneData", "Rule " + ruleName + "[" + i.toString(10) + "][0] is not a number"); } /* istanbul ignore if */ if (rule[1] !== "only" && rule[1] !== "max" && isNaN(parseInt(rule[1], 10))) { return (0, error_1.throwError)("InvalidTimeZoneData", "Rule " + ruleName + "[" + i.toString(10) + "][1] is not a number, only or max"); } /* istanbul ignore if */ if (!TzMonthNames.hasOwnProperty(rule[3])) { return (0, error_1.throwError)("InvalidTimeZoneData", "Rule " + ruleName + "[" + i.toString(10) + "][3] is not a month name"); } /* istanbul ignore if */ if (rule[4].substr(0, 4) !== "last" && rule[4].indexOf(">=") === -1 && rule[4].indexOf("<=") === -1 && isNaN(parseInt(rule[4], 10))) { return (0, error_1.throwError)("InvalidTimeZoneData", "Rule " + ruleName + "[" + i.toString(10) + "][4] is not a known type of expression"); } /* istanbul ignore if */ if (!Array.isArray(rule[5])) { return (0, error_1.throwError)("InvalidTimeZoneData", "Rule " + ruleName + "[" + i.toString(10) + "][5] is not an array"); } /* istanbul ignore if */ if (rule[5].length !== 4) { return (0, error_1.throwError)("InvalidTimeZoneData", "Rule " + ruleName + "[" + i.toString(10) + "][5] is not of length 4"); } /* istanbul ignore if */ if (isNaN(parseInt(rule[5][0], 10))) { return (0, error_1.throwError)("InvalidTimeZoneData", "Rule " + ruleName + "[" + i.toString(10) + "][5][0] is not a number"); } /* istanbul ignore if */ if (isNaN(parseInt(rule[5][1], 10))) { return (0, error_1.throwError)("InvalidTimeZoneData", "Rule " + ruleName + "[" + i.toString(10) + "][5][1] is not a number"); } /* istanbul ignore if */ if (isNaN(parseInt(rule[5][2], 10))) { return (0, error_1.throwError)("InvalidTimeZoneData", "Rule " + ruleName + "[" + i.toString(10) + "][5][2] is not a number"); } /* istanbul ignore if */ if (rule[5][3] !== "" && rule[5][3] !== "s" && rule[5][3] !== "w" && rule[5][3] !== "g" && rule[5][3] !== "u" && rule[5][3] !== "z" && rule[5][3] !== null) { return (0, error_1.throwError)("InvalidTimeZoneData", "Rule " + ruleName + "[" + i.toString(10) + "][5][3] is not empty, g, z, s, w, u or null"); } var save = parseInt(rule[6], 10); /* istanbul ignore if */ if (isNaN(save)) { return (0, error_1.throwError)("InvalidTimeZoneData", "Rule " + ruleName + "[" + i.toString(10) + "][6] does not contain a valid number"); } if (save !== 0) { if (result.maxDstSave === undefined || save > result.maxDstSave) { result.maxDstSave = save; } if (result.minDstSave === undefined || save < result.minDstSave) { result.minDstSave = save; } } } } } return result; } /** * Ready-made sorted rule transitions (uncompensated for stdoffset, as rules are used by multiple zones with different offsets) */ var CachedRuleTransitions = /** @class */ (function () { /** * Constructor * @param ruleInfos */ function CachedRuleTransitions(ruleInfos) { // determine maximum year to calculate transitions for var maxYear; for (var _i = 0, ruleInfos_1 = ruleInfos; _i < ruleInfos_1.length; _i++) { var ruleInfo = ruleInfos_1[_i]; if (ruleInfo.toType === ToType.Year) { if (maxYear === undefined || ruleInfo.toYear > maxYear) { maxYear = ruleInfo.toYear; } if (maxYear === undefined || ruleInfo.from > maxYear) { maxYear = ruleInfo.from; } } } // calculate all transitions until 'max' rules take effect this._transitions = []; for (var _a = 0, ruleInfos_2 = ruleInfos; _a < ruleInfos_2.length; _a++) { var ruleInfo = ruleInfos_2[_a]; var min = ruleInfo.from; var max = ruleInfo.toType === ToType.Year ? ruleInfo.toYear : maxYear; if (max !== undefined) { for (var year = min; year <= max; ++year) { this._transitions.push({ at: ruleInfo.effectiveDate(year), atType: ruleInfo.atType, newState: { dstOffset: ruleInfo.save, letter: ruleInfo.letter } }); } } } // sort transitions this._transitions = this._transitions.sort(function (a, b) { return (a.at < b.at ? -1 : a.at > b.at ? 1 : 0); }); // save the 'max' rules for transitions after that this._finalRulesByFromEffective = ruleInfos.filter(function (info) { return info.toType === ToType.Max; }); this._finalRulesByEffective = __spreadArray([], this._finalRulesByFromEffective, true); // sort final rules by FROM and then by year-relative date this._finalRulesByFromEffective = this._finalRulesByFromEffective.sort(function (a, b) { if (a.from < b.from) { return -1; } if (a.from > b.from) { return 1; } var ae = a.effectiveDate(a.from); var be = b.effectiveDate(b.from); return (ae < be ? -1 : ae > be ? 1 : 0); }); // sort final rules by year-relative date this._finalRulesByEffective = this._finalRulesByFromEffective.sort(function (a, b) { var ae = a.effectiveDate(a.from); var be = b.effectiveDate(b.from); return (ae < be ? -1 : ae > be ? 1 : 0); }); } Object.defineProperty(CachedRuleTransitions.prototype, "final", { /** * The 'max' type rules at the end, sorted by year-relative effective date */ get: function () { return this._finalRulesByEffective; }, enumerable: false, configurable: true }); /** * Returns the first ever transition as defined by the rule set */ CachedRuleTransitions.prototype.findFirst = function () { if (this._transitions.length > 0) { var transition = this._transitions[0]; var iterator = { transition: transition, index: 0 }; return iterator; } if (this._finalRulesByFromEffective.length > 0) { var rule = this._finalRulesByFromEffective[0]; var transition = { at: rule.effectiveDate(rule.from), atType: rule.atType, newState: { dstOffset: rule.save, letter: rule.letter } }; var iterator = { transition: transition, final: true }; return iterator; } return undefined; }; /** * Returns the next transition, given an iterator * @param prev the iterator */ CachedRuleTransitions.prototype.findNext = function (prev) { if (!prev.final && prev.index !== undefined) { if (prev.index < this._transitions.length - 1) { var transition = this._transitions[prev.index + 1]; var iterator = { transition: transition, index: prev.index + 1 }; return iterator; } } // find minimum applicable final rule after the prev transition var found; var foundEffective; for (var year = prev.transition.at.year; year < prev.transition.at.year + 2; ++year) { for (var _i = 0, _a = this._finalRulesByEffective; _i < _a.length; _i++) { var rule = _a[_i]; if (rule.applicable(year)) { var effective = rule.effectiveDate(year); if (effective > prev.transition.at && (!foundEffective || effective < foundEffective)) { found = rule; foundEffective = effective; } } } } if (found && foundEffective) { var transition = { at: foundEffective, atType: found.atType, newState: { dstOffset: found.save, letter: found.letter } }; var iterator = { transition: transition, final: true }; return iterator; } return undefined; }; /** * Dirty find function that only takes a standard offset from UTC into account * @param beforeUtc timestamp to search for * @param standardOffset zone standard offset to apply */ CachedRuleTransitions.prototype.findLastLessEqual = function (beforeUtc, standardOffset) { var prevTransition; var iterator = this.findFirst(); var effectiveUtc = (iterator === null || iterator === void 0 ? void 0 : iterator.transition) ? ruleTransitionUtc(iterator.transition, standardOffset, undefined) : undefined; while (iterator && effectiveUtc && effectiveUtc <= beforeUtc) { prevTransition = iterator.transition; iterator = this.findNext(iterator); effectiveUtc = (iterator === null || iterator === void 0 ? void 0 : iterator.transition) ? ruleTransitionUtc(iterator.transition, standardOffset, undefined) : undefined; } return prevTransition; }; /** * * @param afterUtc * @param standardOffset * @param dstOffset */ CachedRuleTransitions.prototype.firstTransitionWithoutDstAfter = function (afterUtc, standardOffset, dstOffset) { var _a; // todo inefficient - optimize var iterator = this.findFirst(); var effectiveUtc = (iterator === null || iterator === void 0 ? void 0 : iterator.transition) ? ruleTransitionUtc(iterator === null || iterator === void 0 ? void 0 : iterator.transition, standardOffset, dstOffset) : undefined; while (iterator && effectiveUtc && (!((_a = iterator === null || iterator === void 0 ? void 0 : iterator.transition) === null || _a === void 0 ? void 0 : _a.newState.dstOffset.zero()) || effectiveUtc <= afterUtc)) { iterator = this.findNext(iterator); effectiveUtc = (iterator === null || iterator === void 0 ? void 0 : iterator.transition) ? ruleTransitionUtc(iterator === null || iterator === void 0 ? void 0 : iterator.transition, standardOffset, dstOffset) : undefined; } return iterator === null || iterator === void 0 ? void 0 : iterator.transition; }; return CachedRuleTransitions; }()); /** * Rules depend on previous rules, hence you cannot calculate DST transitions witout starting at the start. * Next to that, zones sometimes transition into the middle of a rule set. * Due to this, we maintain a cache of transitions for zones */ var CachedZoneTransitions = /** @class */ (function () { /** * Constructor * @param zoneName * @param zoneInfos * @param rules * @throws timezonecomplete.InvalidTimeZoneData * @throws timezonecomplete.Argument.ZoneInfos if zoneInfos is empty */ function CachedZoneTransitions(zoneName, zoneInfos, rules) { var _a; (0, assert_1.default)(zoneInfos.length > 0, "timezonecomplete.Argument.ZoneInfos", "zone '".concat(zoneName, "' without information")); this._finalZoneInfo = zoneInfos[zoneInfos.length - 1]; this._initialState = this._calcInitialState(zoneName, zoneInfos, rules); _a = this._calcTransitions(zoneName, this._initialState, zoneInfos, rules), this._transitions = _a[0], this._finalRules = _a[1]; } Object.defineProperty(CachedZoneTransitions.prototype, "initialState", { get: function () { return this._initialState; }, enumerable: false, configurable: true }); /** * Find the first transition, if it exists */ CachedZoneTransitions.prototype.findFirst = function () { if (this._transitions.length > 0) { return { transition: this._transitions[0], index: 0 }; } return undefined; }; /** * Find next transition, if it exists * @param iterator previous iterator * @returns the next iterator */ CachedZoneTransitions.prototype.findNext = function (iterator) { if (!iterator.final) { if (iterator.index < this._transitions.length - 1) { return { transition: this._transitions[iterator.index + 1], index: iterator.index + 1 }; } } var found; for (var y = iterator.transition.atUtc.year; y < iterator.transition.atUtc.year + 2; ++y) { for (var _i = 0, _a = this._finalRules; _i < _a.length; _i++) { var ruleInfo = _a[_i]; if (ruleInfo.applicable(y)) { var transition = { atUtc: ruleInfo.effectiveDateUtc(y, iterator.transition.newState.standardOffset, iterator.transition.newState.dstOffset), newState: { abbreviation: zoneAbbreviation(this._finalZoneInfo.format, ruleInfo.save.nonZero(), ruleInfo.letter), letter: ruleInfo.letter, dstOffset: ruleInfo.save, standardOffset: iterator.transition.newState.standardOffset } }; if (transition.atUtc > iterator.transition.atUtc) { if (!found || found.atUtc > transition.atUtc) { found = transition; } } } } } if (found) { return { transition: found, index: 0, final: true }; } return undefined; }; /** * Returns the zone state at the given UTC time * @param utc */ CachedZoneTransitions.prototype.stateAt = function (utc) { var prevState = this._initialState; var iterator = this.findFirst(); while (iterator && iterator.transition.atUtc <= utc) { prevState = iterator.transition.newState; iterator = this.findNext(iterator); } return prevState; }; /** * The transitions in year [start, end) * @param start start year (inclusive) * @param end end year (exclusive) */ CachedZoneTransitions.prototype.transitionsInYears = function (start, end) { // check if start-1 is within the initial transitions or not. We use start-1 because we take an extra year in the else clause below var final = (this._transitions.length === 0 || this._transitions[this._transitions.length - 1].atUtc.year < start - 1); var result = []; if (!final) { // simply do linear search var iterator = this.findFirst(); while (iterator && iterator.transition.atUtc.year < end) { if (iterator.transition.atUtc.year >= start) { result.push(iterator.transition); } iterator = this.findNext(iterator); } } else { var transitionsWithRules = []; // Do something smart: first get all transitions with atUtc NOT compensated for standard offset // Take an extra year before start for (var year = start - 1; year < end; ++year) { for (var _i = 0, _a = this._finalRules; _i < _a.length; _i++) { var ruleInfo = _a[_i]; if (ruleInfo.applicable(year)) { var transition = { atUtc: ruleInfo.effectiveDateUtc(year, this._finalZoneInfo.gmtoff, (0, duration_1.hours)(0)), newState: { abbreviation: zoneAbbreviation(this._finalZoneInfo.format, ruleInfo.save.nonZero(), ruleInfo.letter), letter: ruleInfo.letter, dstOffset: ruleInfo.save, standardOffset: this._finalZoneInfo.gmtoff } }; transitionsWithRules.push({ transition: transition, ruleInfo: ruleInfo }); } } } transitionsWithRules.sort(function (a, b) { return a.transition.atUtc.unixMillis - b.transition.atUtc.unixMillis; }); // now apply DST offset retroactively var prevDst = (0, duration_1.hours)(0); for (var _b = 0, transitionsWithRules_1 = transitionsWithRules; _b < transitionsWithRules_1.length; _b++) { var tr = transitionsWithRules_1[_b]; if (tr.ruleInfo.atType === AtType.Wall) { tr.transition.atUtc = new basics_1.TimeStruct(tr.transition.atUtc.unixMillis - prevDst.milliseconds()); } prevDst = tr.transition.newState.dstOffset; if (tr.transition.atUtc.year >= start) { result.push(tr.transition); } } } return result; }; /** * Calculate the initial state for the zone * @param zoneName * @param infos * @param rules * @throws timezonecomplete.InvalidTimeZoneData */ CachedZoneTransitions.prototype._calcInitialState = function (zoneName, infos, rules) { var _a; // initial state if (infos.length === 0) { return { abbreviation: "", letter: "", dstOffset: (0, duration_1.hours)(0), standardOffset: (0, duration_1.hours)(0) }; } var info = infos[0]; switch (info.ruleType) { case RuleType.None: return { abbreviation: zoneAbbreviation(info.format, false, undefined), letter: "", dstOffset: (0, duration_1.hours)(0), standardOffset: info.gmtoff }; case RuleType.Offset: return { abbreviation: zoneAbbreviation(info.format, info.ruleOffset.nonZero(), undefined), letter: "", dstOffset: info.ruleOffset, standardOffset: info.gmtoff }; case RuleType.RuleName: { var rule = rules.get(info.ruleName); if (!rule) { (0, error_1.throwError)("InvalidTimeZoneData", "zone '".concat(zoneName, "' refers to non-existing rule '").concat(info.ruleName, "'")); } // find first rule transition without DST so that we have a letter var iterator = rule.findFirst(); while (iterator && iterator.transition.newState.dstOffset.nonZero()) { iterator = rule.findNext(iterator); } var letter = (_a = iterator === null || iterator === void 0 ? void 0 : iterator.transition.newState.letter) !== null && _a !== void 0 ? _a : ""; return { abbreviation: zoneAbbreviation(info.format, false, letter), dstOffset: (0, duration_1.hours)(0), letter: letter, standardOffset: info.gmtoff }; } default: (0, assert_1.default)(false, "timezonecomplete.Assertion", "Unknown RuleType"); } }; /** * Pre-calculate all transitions until there are only 'max' rules in effect * @param zoneName * @param initialState * @param zoneInfos * @param rules */ CachedZoneTransitions.prototype._calcTransitions = function (zoneName, initialState, zoneInfos, rules) { var _a; if (zoneInfos.length === 0) { return [[], []]; } // walk through the zone records and add a transition for each var transitions = []; var prevState = initialState; var prevUntil; var prevRules; for (var _i = 0, zoneInfos_6 = zoneInfos; _i < zoneInfos_6.length; _i++) { var zoneInfo = zoneInfos_6[_i]; // zones can have a DST offset or they can refer to a rule set switch (zoneInfo.ruleType) { case RuleType.None: case RuleType.Offset: { if (prevUntil) { transitions.push({ atUtc: prevUntil, newState: { abbreviation: zoneAbbreviation(zoneInfo.format, false, undefined), letter: "", dstOffset: zoneInfo.ruleType === RuleType.None ? (0, duration_1.hours)(0) : zoneInfo.ruleOffset, standardOffset: zoneInfo.gmtoff } }); prevRules = undefined; } } break; case RuleType.RuleName: { var rule = rules.get(zoneInfo.ruleName); if (!rule) { return (0, error_1.throwError)("InvalidTimeZoneData", "Zone '".concat(zoneName, "' refers to non-existing rule '").concat(zoneInfo.ruleName, "'")); } var t = this._zoneTransitions(prevUntil, zoneInfo, rule); transitions = transitions.concat(t); prevRules = rule; } break; default: (0, assert_1.default)(false, "timezonecomplete.Assertion", "Unknown RuleType"); } prevUntil = zoneInfo.until !== undefined ? new basics_1.TimeStruct(zoneInfo.until) : undefined; prevState = transitions.length > 0 ? transitions[transitions.length - 1].newState : prevState; } return [transitions, (_a = prevRules === null || prevRules === void 0 ? void 0 : prevRules.final) !== null && _a !== void 0 ? _a : []]; }; /** * Creates all the transitions for a time zone from fromUtc (inclusive) to zoneInfo.until (exclusive). * The result always contains an initial transition at fromUtc that signals the switch to this rule set * * @param fromUtc previous zone sub-record UNTIL time; undefined for first zone record * @param zoneInfo the current zone sub-record * @param rule the corresponding rule transitions */ CachedZoneTransitions.prototype._zoneTransitions = function (fromUtc, zoneInfo, rule) { // from tz-how-to.html: // One wrinkle, not fully explained in zic.8.txt, is what happens when switching to a named rule. To what values should the SAVE and // LETTER data be initialized? // - If at least one transition has happened, use the SAVE and LETTER data from the most recent. // - If switching to a named rule before any transition has happened, assume standard time (SAVE zero), and use the LETTER data from // the earliest transition with a SAVE of zero. var _a, _b, _c, _d; var result = []; // extra initial transition for switch to this rule set (but not for first zone info) var initial; if (fromUtc !== undefined) { var initialRuleTransition = rule.findLastLessEqual(fromUtc, zoneInfo.gmtoff); if (initialRuleTransition) { initial = { atUtc: fromUtc, newState: { abbreviation: zoneAbbreviation(zoneInfo.format, false, initialRuleTransition.newState.letter), letter: (_a = initialRuleTransition.newState.letter) !== null && _a !== void 0 ? _a : "", dstOffset: (0, duration_1.hours)(0), standardOffset: zoneInfo.gmtoff } }; } else { initialRuleTransition = rule.firstTransitionWithoutDstAfter(fromUtc, zoneInfo.gmtoff, undefined); initial = { atUtc: fromUtc, newState: { abbreviation: zoneAbbreviation(zoneInfo.format, false, initialRuleTransition === null || initialRuleTransition === void 0 ? void 0 : initialRuleTransition.newState.letter), letter: (_b = initialRuleTransition === null || initialRuleTransition === void 0 ? void 0 : initialRuleTransition.newState.letter) !== null && _b !== void 0 ? _b : "", dstOffset: (0, duration_1.hours)(0), standardOffset: zoneInfo.gmtoff } }; } result.push(initial); } // actual rule transitions; keep adding until the end of this zone info, or until only 'max' rules remain var prevDst = (_c = initial === null || initial === void 0 ? void 0 : initial.newState.dstOffset) !== null && _c !== void 0 ? _c : (0, duration_1.hours)(0); var iterator = rule.findFirst(); var effective = (iterator === null || iterator === void 0 ? void 0 : iterator.transition) && ruleTransitionUtc(iterator.transition, zoneInfo.gmtoff, prevDst); while (iterator && effective && ((zoneInfo.until && effective.unixMillis < zoneInfo.until) || (!zoneInfo.until && !iterator.final))) { prevDst = iterator.transition.newState.dstOffset; result.push({ atUtc: effective, newState: { abbreviation: zoneAbbreviation(zoneInfo.format, prevDst.nonZero(), iterator.transition.newState.letter), letter: (_d = iterator.transition.newState.letter) !== null && _d !== void 0 ? _d : "", dstOffset: prevDst, standardOffset: zoneInfo.gmtoff } }); iterator = rule.findNext(iterator); effective = iterator && ruleTransitionUtc(iterator.transition, zoneInfo.gmtoff, prevDst); } return result; }; return CachedZoneTransitions; }()); /** * Calculate the formatted abbreviation for a zone * @param format the abbreviation format string. Either 'zzz,' for NULL; 'A/B' for std/dst, or 'A%sB' for a format string where %s is * replaced by a letter * @param dst whether DST is observed * @param letter current rule letter, empty if no rule * @returns fully formatted abbreviation */ function zoneAbbreviation(format, dst, letter) { if (format === "zzz,") { return ""; } if (format.includes("/")) { return (dst ? format.split("/")[1] : format.split("/")[0]); } if (letter) { return format.replace("%s", letter); } return format.replace("%s", ""); } /** * Calculate the UTC time of a rule transition, given a particular time zone * @param transition * @param standardOffset zone offset from UT * @param dstOffset previous DST offset from UT+standardOffset * @returns UTC time */ function ruleTransitionUtc(transition, standardOffset, dstOffset) { switch (transition.atType) { case AtType.Utc: return transition.at; case AtType.Standard: { // transition time is in zone local time without DST var millis = transition.at.unixMillis; millis -= standardOffset.milliseconds(); return new basics_1.TimeStruct(millis); } case AtType.Wall: { // transition time is in zone local time with DST var millis = transition.at.unixMillis; millis -= standardOffset.milliseconds(); if (dstOffset) { millis -= dstOffset.milliseconds(); } return new basics_1.TimeStruct(millis); } } } }).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"./assert":1,"./basics":2,"./duration":4,"./error":5,"./math":10}],"timezonecomplete":[function(require,module,exports){ /** * Copyright(c) 2014 ABB Switzerland Ltd. * * Date and Time utility functions - main index */ "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ZoneInfo = exports.TzDatabase = exports.Transition = exports.ToType = exports.OnType = exports.RuleType = exports.RuleInfo = exports.NormalizeOption = exports.isValidOffsetString = exports.AtType = void 0; __exportStar(require("./basics"), exports); __exportStar(require("./datetime"), exports); __exportStar(require("./duration"), exports); __exportStar(require("./format"), exports); __exportStar(require("./globals"), exports); __exportStar(require("./javascript"), exports); __exportStar(require("./locale"), exports); __exportStar(require("./parse"), exports); __exportStar(require("./period"), exports); __exportStar(require("./timesource"), exports); __exportStar(require("./timezone"), exports); var tz_database_1 = require("./tz-database"); Object.defineProperty(exports, "AtType", { enumerable: true, get: function () { return tz_database_1.AtType; } }); Object.defineProperty(exports, "isValidOffsetString", { enumerable: true, get: function () { return tz_database_1.isValidOffsetString; } }); Object.defineProperty(exports, "NormalizeOption", { enumerable: true, get: function () { return tz_database_1.NormalizeOption; } }); Object.defineProperty(exports, "RuleInfo", { enumerable: true, get: function () { return tz_database_1.RuleInfo; } }); Object.defineProperty(exports, "RuleType", { enumerable: true, get: function () { return tz_database_1.RuleType; } }); Object.defineProperty(exports, "OnType", { enumerable: true, get: function () { return tz_database_1.OnType; } }); Object.defineProperty(exports, "ToType", { enumerable: true, get: function () { return tz_database_1.ToType; } }); Object.defineProperty(exports, "Transition", { enumerable: true, get: function () { return tz_database_1.Transition; } }); Object.defineProperty(exports, "TzDatabase", { enumerable: true, get: function () { return tz_database_1.TzDatabase; } }); Object.defineProperty(exports, "ZoneInfo", { enumerable: true, get: function () { return tz_database_1.ZoneInfo; } }); },{"./basics":2,"./datetime":3,"./duration":4,"./format":6,"./globals":7,"./javascript":8,"./locale":9,"./parse":11,"./period":12,"./timesource":14,"./timezone":15,"./tz-database":17}]},{},[])("timezonecomplete") }); //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJkaXN0L2xpYi9hc3NlcnQuanMiLCJkaXN0L2xpYi9iYXNpY3MuanMiLCJkaXN0L2xpYi9kYXRldGltZS5qcyIsImRpc3QvbGliL2R1cmF0aW9uLmpzIiwiZGlzdC9saWIvZXJyb3IuanMiLCJkaXN0L2xpYi9mb3JtYXQuanMiLCJkaXN0L2xpYi9nbG9iYWxzLmpzIiwiZGlzdC9saWIvamF2YXNjcmlwdC5qcyIsImRpc3QvbGliL2xvY2FsZS5qcyIsImRpc3QvbGliL21hdGguanMiLCJkaXN0L2xpYi9wYXJzZS5qcyIsImRpc3QvbGliL3BlcmlvZC5qcyIsImRpc3QvbGliL3N0cmluZ3MuanMiLCJkaXN0L2xpYi90aW1lc291cmNlLmpzIiwiZGlzdC9saWIvdGltZXpvbmUuanMiLCJkaXN0L2xpYi90b2tlbi5qcyIsImRpc3QvbGliL3R6LWRhdGFiYXNlLmpzIiwiZGlzdC9saWIvaW5kZXguanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3o4QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMza0NBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcnNCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOURBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3bEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbEVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeHNCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2MUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0NBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdmdCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FDbE5BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDcm9FQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbigpe2Z1bmN0aW9uIHIoZSxuLHQpe2Z1bmN0aW9uIG8oaSxmKXtpZighbltpXSl7aWYoIWVbaV0pe3ZhciBjPVwiZnVuY3Rpb25cIj09dHlwZW9mIHJlcXVpcmUmJnJlcXVpcmU7aWYoIWYmJmMpcmV0dXJuIGMoaSwhMCk7aWYodSlyZXR1cm4gdShpLCEwKTt2YXIgYT1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK2krXCInXCIpO3Rocm93IGEuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixhfXZhciBwPW5baV09e2V4cG9ydHM6e319O2VbaV1bMF0uY2FsbChwLmV4cG9ydHMsZnVuY3Rpb24ocil7dmFyIG49ZVtpXVsxXVtyXTtyZXR1cm4gbyhufHxyKX0scCxwLmV4cG9ydHMscixlLG4sdCl9cmV0dXJuIG5baV0uZXhwb3J0c31mb3IodmFyIHU9XCJmdW5jdGlvblwiPT10eXBlb2YgcmVxdWlyZSYmcmVxdWlyZSxpPTA7aTx0Lmxlbmd0aDtpKyspbyh0W2ldKTtyZXR1cm4gb31yZXR1cm4gcn0pKCkiLCIvKipcbiAqIENvcHlyaWdodChjKSAyMDE2IEFCQiBTd2l0emVybGFuZCBMdGQuXG4gKi9cblwidXNlIHN0cmljdFwiO1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7IHZhbHVlOiB0cnVlIH0pO1xudmFyIGVycm9yXzEgPSByZXF1aXJlKFwiLi9lcnJvclwiKTtcbi8qKlxuICogVGhyb3dzIGFuIEFzc2VydGlvbiBlcnJvciBpZiB0aGUgZ2l2ZW4gY29uZGl0aW9uIGlzIGZhbHN5XG4gKiBAcGFyYW0gY29uZGl0aW9uXG4gKiBAcGFyYW0gbmFtZSBlcnJvciBuYW1lXG4gKiBAcGFyYW0gbWVzc2FnZSBlcnJvciBtZXNzYWdlIHdpdGggcGVyY2VudC1zdHlsZSBwbGFjZWhvbGRlcnNcbiAqIEBwYXJhbSBhcmdzIGFyZ3VtZW50cyBmb3IgZXJyb3IgbWVzc2FnZSBmb3JtYXQgc3RyaW5nXG4gKiBAdGhyb3dzIFtuYW1lXSBpZiBgY29uZGl0aW9uYCBpcyBmYWxzeVxuICovXG5mdW5jdGlvbiBhc3NlcnQoY29uZGl0aW9uLCBuYW1lLCBtZXNzYWdlKSB7XG4gICAgaWYgKCFjb25kaXRpb24pIHtcbiAgICAgICAgKDAsIGVycm9yXzEudGhyb3dFcnJvcikobmFtZSwgbWVzc2FnZSk7XG4gICAgfVxufVxuZXhwb3J0cy5kZWZhdWx0ID0gYXNzZXJ0O1xuLy8jIHNvdXJjZU1hcHBpbmdVUkw9YXNzZXJ0LmpzLm1hcCIsIi8qKlxuICogQ29weXJpZ2h0KGMpIDIwMTQgQUJCIFN3aXR6ZXJsYW5kIEx0ZC5cbiAqXG4gKiBPbHNlbiBUaW1lem9uZSBEYXRhYmFzZSBjb250YWluZXJcbiAqL1xuXCJ1c2Ugc3RyaWN0XCI7XG5PYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgXCJfX2VzTW9kdWxlXCIsIHsgdmFsdWU6IHRydWUgfSk7XG5leHBvcnRzLmJpbmFyeUluc2VydGlvbkluZGV4ID0gZXhwb3J0cy5UaW1lU3RydWN0ID0gZXhwb3J0cy5zZWNvbmRPZkRheSA9IGV4cG9ydHMud2Vla0RheU5vTGVhcFNlY3MgPSBleHBvcnRzLnRpbWVUb1VuaXhOb0xlYXBTZWNzID0gZXhwb3J0cy51bml4VG9UaW1lTm9MZWFwU2VjcyA9IGV4cG9ydHMud2Vla051bWJlciA9IGV4cG9ydHMud2Vla0RheUluc3RhbmNlSW5Nb250aCA9IGV4cG9ydHMuY2FsZW5kYXJXZWVrSW5Nb250aCA9IGV4cG9ydHMud2Vla09mTW9udGggPSBleHBvcnRzLndlZWtEYXlPbk9yQmVmb3JlID0gZXhwb3J0cy53ZWVrRGF5T25PckFmdGVyID0gZXhwb3J0cy5udGhXZWVrRGF5T2ZNb250aCA9IGV4cG9ydHMuZmlyc3RXZWVrRGF5T2ZNb250aCA9IGV4cG9ydHMubGFzdFdlZWtEYXlPZk1vbnRoID0gZXhwb3J0cy5kYXlPZlllYXIgPSBleHBvcnRzLmRheXNJbk1vbnRoID0gZXhwb3J0cy5kYXlzSW5ZZWFyID0gZXhwb3J0cy5pc0xlYXBZZWFyID0gZXhwb3J0cy5zdHJpbmdUb1RpbWVVbml0ID0gZXhwb3J0cy50aW1lVW5pdFRvU3RyaW5nID0gZXhwb3J0cy50aW1lVW5pdFRvTWlsbGlzZWNvbmRzID0gZXhwb3J0cy5UaW1lVW5pdCA9IGV4cG9ydHMuV2Vla0RheSA9IHZvaWQgMDtcbnZhciBhc3NlcnRfMSA9IHJlcXVpcmUoXCIuL2Fzc2VydFwiKTtcbnZhciBlcnJvcl8xID0gcmVxdWlyZShcIi4vZXJyb3JcIik7XG52YXIgamF2YXNjcmlwdF8xID0gcmVxdWlyZShcIi4vamF2YXNjcmlwdFwiKTtcbnZhciBtYXRoID0gcmVxdWlyZShcIi4vbWF0aFwiKTtcbnZhciBzdHJpbmdzID0gcmVxdWlyZShcIi4vc3RyaW5nc1wiKTtcbi8qKlxuICogRGF5LW9mLXdlZWsuIE5vdGUgdGhlIGVudW0gdmFsdWVzIGNvcnJlc3BvbmQgdG8gSmF2YVNjcmlwdCBkYXktb2Ytd2VlazpcbiAqIFN1bmRheSA9IDAsIE1vbmRheSA9IDEgZXRjXG4gKi9cbnZhciBXZWVrRGF5O1xuKGZ1bmN0aW9uIChXZWVrRGF5KSB7XG4gICAgV2Vla0RheVtXZWVrRGF5W1wiU3VuZGF5XCJdID0gMF0gPSBcIlN1bmRheVwiO1xuICAgIFdlZWtEYXlbV2Vla0RheVtcIk1vbmRheVwiXSA9IDFdID0gXCJNb25kYXlcIjtcbiAgICBXZWVrRGF5W1dlZWtEYXlbXCJUdWVzZGF5XCJdID0gMl0gPSBcIlR1ZXNkYXlcIjtcbiAgICBXZWVrRGF5W1dlZWtEYXlbXCJXZWRuZXNkYXlcIl0gPSAzXSA9IFwiV2VkbmVzZGF5XCI7XG4gICAgV2Vla0RheVtXZWVrRGF5W1wiVGh1cnNkYXlcIl0gPSA0XSA9IFwiVGh1cnNkYXlcIjtcbiAgICBXZWVrRGF5W1dlZWtEYXlbXCJGcmlkYXlcIl0gPSA1XSA9IFwiRnJpZGF5XCI7XG4gICAgV2Vla0RheVtXZWVrRGF5W1wiU2F0dXJkYXlcIl0gPSA2XSA9IFwiU2F0dXJkYXlcIjtcbn0pKFdlZWtEYXkgfHwgKGV4cG9ydHMuV2Vla0RheSA9IFdlZWtEYXkgPSB7fSkpO1xuLyoqXG4gKiBUaW1lIHVuaXRzXG4gKi9cbnZhciBUaW1lVW5pdDtcbihmdW5jdGlvbiAoVGltZVVuaXQpIHtcbiAgICBUaW1lVW5pdFtUaW1lVW5pdFtcIk1pbGxpc2Vjb25kXCJdID0gMF0gPSBcIk1pbGxpc2Vjb25kXCI7XG4gICAgVGltZVVuaXRbVGltZVVuaXRbXCJTZWNvbmRcIl0gPSAxXSA9IFwiU2Vjb25kXCI7XG4gICAgVGltZVVuaXRbVGltZVVuaXRbXCJNaW51dGVcIl0gPSAyXSA9IFwiTWludXRlXCI7XG4gICAgVGltZVVuaXRbVGltZVVuaXRbXCJIb3VyXCJdID0gM10gPSBcIkhvdXJcIjtcbiAgICBUaW1lVW5pdFtUaW1lVW5pdFtcIkRheVwiXSA9IDRdID0gXCJEYXlcIjtcbiAgICBUaW1lVW5pdFtUaW1lVW5pdFtcIldlZWtcIl0gPSA1XSA9IFwiV2Vla1wiO1xuICAgIFRpbWVVbml0W1RpbWVVbml0W1wiTW9udGhcIl0gPSA2XSA9IFwiTW9udGhcIjtcbiAgICBUaW1lVW5pdFtUaW1lVW5pdFtcIlllYXJcIl0gPSA3XSA9IFwiWWVhclwiO1xuICAgIC8qKlxuICAgICAqIEVuZC1vZi1lbnVtIG1hcmtlciwgZG8gbm90IHVzZVxuICAgICAqL1xuICAgIFRpbWVVbml0W1RpbWVVbml0W1wiTUFYXCJdID0gOF0gPSBcIk1BWFwiO1xufSkoVGltZVVuaXQgfHwgKGV4cG9ydHMuVGltZVVuaXQgPSBUaW1lVW5pdCA9IHt9KSk7XG4vKipcbiAqIEFwcHJveGltYXRlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgZm9yIGEgdGltZSB1bml0LlxuICogQSBkYXkgaXMgYXNzdW1lZCB0byBoYXZlIDI0IGhvdXJzLCBhIG1vbnRoIGlzIGFzc3VtZWQgdG8gZXF1YWwgMzAgZGF5c1xuICogYW5kIGEgeWVhciBpcyBzZXQgdG8gMzYwIGRheXMgKGJlY2F1c2UgMTIgbW9udGhzIG9mIDMwIGRheXMpLlxuICpcbiAqIEBwYXJhbSB1bml0XHRUaW1lIHVuaXQgZS5nLiBUaW1lVW5pdC5Nb250aFxuICogQHJldHVybnNcdFRoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzLlxuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LlVuaXQgZm9yIGludmFsaWQgdW5pdFxuICovXG5mdW5jdGlvbiB0aW1lVW5pdFRvTWlsbGlzZWNvbmRzKHVuaXQpIHtcbiAgICBzd2l0Y2ggKHVuaXQpIHtcbiAgICAgICAgY2FzZSBUaW1lVW5pdC5NaWxsaXNlY29uZDogcmV0dXJuIDE7XG4gICAgICAgIGNhc2UgVGltZVVuaXQuU2Vjb25kOiByZXR1cm4gMTAwMDtcbiAgICAgICAgY2FzZSBUaW1lVW5pdC5NaW51dGU6IHJldHVybiA2MCAqIDEwMDA7XG4gICAgICAgIGNhc2UgVGltZVVuaXQuSG91cjogcmV0dXJuIDYwICogNjAgKiAxMDAwO1xuICAgICAgICBjYXNlIFRpbWVVbml0LkRheTogcmV0dXJuIDg2NDAwMDAwO1xuICAgICAgICBjYXNlIFRpbWVVbml0LldlZWs6IHJldHVybiA3ICogODY0MDAwMDA7XG4gICAgICAgIGNhc2UgVGltZVVuaXQuTW9udGg6IHJldHVybiAzMCAqIDg2NDAwMDAwO1xuICAgICAgICBjYXNlIFRpbWVVbml0LlllYXI6IHJldHVybiAxMiAqIDMwICogODY0MDAwMDA7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICByZXR1cm4gKDAsIGVycm9yXzEudGhyb3dFcnJvcikoXCJBcmd1bWVudC5Vbml0XCIsIFwidW5rbm93biB0aW1lIHVuaXQgXCIuY29uY2F0KHVuaXQpKTtcbiAgICB9XG59XG5leHBvcnRzLnRpbWVVbml0VG9NaWxsaXNlY29uZHMgPSB0aW1lVW5pdFRvTWlsbGlzZWNvbmRzO1xuLyoqXG4gKiBUaW1lIHVuaXQgdG8gbG93ZXJjYXNlIHN0cmluZy4gSWYgYW1vdW50IGlzIHNwZWNpZmllZCwgdGhlbiB0aGUgc3RyaW5nIGlzIHB1dCBpbiBwbHVyYWwgZm9ybVxuICogaWYgbmVjZXNzYXJ5LlxuICogQHBhcmFtIHVuaXQgVGhlIHVuaXRcbiAqIEBwYXJhbSBhbW91bnQgSWYgdGhpcyBpcyB1bmVxdWFsIHRvIC0xIGFuZCAxLCB0aGVuIHRoZSByZXN1bHQgaXMgcGx1cmFsaXplZFxuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LlVuaXQgZm9yIGludmFsaWQgdGltZSB1bml0XG4gKi9cbmZ1bmN0aW9uIHRpbWVVbml0VG9TdHJpbmcodW5pdCwgYW1vdW50KSB7XG4gICAgaWYgKGFtb3VudCA9PT0gdm9pZCAwKSB7IGFtb3VudCA9IDE7IH1cbiAgICBpZiAoIU51bWJlci5pc0ludGVnZXIodW5pdCkgfHwgdW5pdCA8IDAgfHwgdW5pdCA+PSBUaW1lVW5pdC5NQVgpIHtcbiAgICAgICAgcmV0dXJuICgwLCBlcnJvcl8xLnRocm93RXJyb3IpKFwiQXJndW1lbnQuVW5pdFwiLCBcImludmFsaWQgdGltZSB1bml0IFwiLmNvbmNhdCh1bml0KSk7XG4gICAgfVxuICAgIHZhciByZXN1bHQgPSBUaW1lVW5pdFt1bml0XS50b0xvd2VyQ2FzZSgpO1xuICAgIGlmIChhbW91bnQgPT09IDEgfHwgYW1vdW50ID09PSAtMSkge1xuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgcmV0dXJuIHJlc3VsdCArIFwic1wiO1xuICAgIH1cbn1cbmV4cG9ydHMudGltZVVuaXRUb1N0cmluZyA9IHRpbWVVbml0VG9TdHJpbmc7XG4vKipcbiAqIENvbnZlcnQgYSBzdHJpbmcgdG8gYSBudW1lcmljIFRpbWVVbml0LiBDYXNlLWluc2Vuc2l0aXZlOyB0aW1lIHVuaXRzIGNhbiBiZSBzaW5ndWxhciBvciBwbHVyYWwuXG4gKiBAcGFyYW0gc1xuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LlMgZm9yIGludmFsaWQgc3RyaW5nXG4gKi9cbmZ1bmN0aW9uIHN0cmluZ1RvVGltZVVuaXQocykge1xuICAgIHZhciB0cmltbWVkID0gcy50cmltKCkudG9Mb3dlckNhc2UoKTtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IFRpbWVVbml0Lk1BWDsgKytpKSB7XG4gICAgICAgIHZhciBvdGhlciA9IHRpbWVVbml0VG9TdHJpbmcoaSwgMSk7XG4gICAgICAgIGlmIChvdGhlciA9PT0gdHJpbW1lZCB8fCAob3RoZXIgKyBcInNcIikgPT09IHRyaW1tZWQpIHtcbiAgICAgICAgICAgIHJldHVybiBpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiAoMCwgZXJyb3JfMS50aHJvd0Vycm9yKShcIkFyZ3VtZW50LlNcIiwgXCJVbmtub3duIHRpbWUgdW5pdCBzdHJpbmcgJ1wiLmNvbmNhdChzLCBcIidcIikpO1xufVxuZXhwb3J0cy5zdHJpbmdUb1RpbWVVbml0ID0gc3RyaW5nVG9UaW1lVW5pdDtcbi8qKlxuICogQHJldHVybiBUcnVlIGlmZiB0aGUgZ2l2ZW4geWVhciBpcyBhIGxlYXAgeWVhci5cbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5ZZWFyIGlmIHllYXIgaXMgbm90IGludGVnZXJcbiAqL1xuZnVuY3Rpb24gaXNMZWFwWWVhcih5ZWFyKSB7XG4gICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKE51bWJlci5pc0ludGVnZXIoeWVhciksIFwiQXJndW1lbnQuWWVhclwiLCBcIkludmFsaWQgeWVhciBcIi5jb25jYXQoeWVhcikpO1xuICAgIC8vIGZyb20gV2lraXBlZGlhOlxuICAgIC8vIGlmIHllYXIgaXMgbm90IGRpdmlzaWJsZSBieSA0IHRoZW4gY29tbW9uIHllYXJcbiAgICAvLyBlbHNlIGlmIHllYXIgaXMgbm90IGRpdmlzaWJsZSBieSAxMDAgdGhlbiBsZWFwIHllYXJcbiAgICAvLyBlbHNlIGlmIHllYXIgaXMgbm90IGRpdmlzaWJsZSBieSA0MDAgdGhlbiBjb21tb24geWVhclxuICAgIC8vIGVsc2UgbGVhcCB5ZWFyXG4gICAgaWYgKHllYXIgJSA0ICE9PSAwKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgZWxzZSBpZiAoeWVhciAlIDEwMCAhPT0gMCkge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgZWxzZSBpZiAoeWVhciAlIDQwMCAhPT0gMCkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG59XG5leHBvcnRzLmlzTGVhcFllYXIgPSBpc0xlYXBZZWFyO1xuLyoqXG4gKiBUaGUgZGF5cyBpbiBhIGdpdmVuIHllYXJcbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5ZZWFyIGlmIHllYXIgaXMgbm90IGludGVnZXJcbiAqL1xuZnVuY3Rpb24gZGF5c0luWWVhcih5ZWFyKSB7XG4gICAgLy8gcmVseSBvbiB2YWxpZGF0aW9uIGJ5IGlzTGVhcFllYXJcbiAgICByZXR1cm4gKGlzTGVhcFllYXIoeWVhcikgPyAzNjYgOiAzNjUpO1xufVxuZXhwb3J0cy5kYXlzSW5ZZWFyID0gZGF5c0luWWVhcjtcbi8qKlxuICogQHBhcmFtIHllYXJcdFRoZSBmdWxsIHllYXJcbiAqIEBwYXJhbSBtb250aFx0VGhlIG1vbnRoIDEtMTJcbiAqIEByZXR1cm4gVGhlIG51bWJlciBvZiBkYXlzIGluIHRoZSBnaXZlbiBtb250aFxuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LlllYXIgaWYgeWVhciBpcyBub3QgaW50ZWdlclxuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50Lk1vbnRoIGZvciBpbnZhbGlkIG1vbnRoIG51bWJlclxuICovXG5mdW5jdGlvbiBkYXlzSW5Nb250aCh5ZWFyLCBtb250aCkge1xuICAgIHN3aXRjaCAobW9udGgpIHtcbiAgICAgICAgY2FzZSAxOlxuICAgICAgICBjYXNlIDM6XG4gICAgICAgIGNhc2UgNTpcbiAgICAgICAgY2FzZSA3OlxuICAgICAgICBjYXNlIDg6XG4gICAgICAgIGNhc2UgMTA6XG4gICAgICAgIGNhc2UgMTI6XG4gICAgICAgICAgICByZXR1cm4gMzE7XG4gICAgICAgIGNhc2UgMjpcbiAgICAgICAgICAgIHJldHVybiAoaXNMZWFwWWVhcih5ZWFyKSA/IDI5IDogMjgpO1xuICAgICAgICBjYXNlIDQ6XG4gICAgICAgIGNhc2UgNjpcbiAgICAgICAgY2FzZSA5OlxuICAgICAgICBjYXNlIDExOlxuICAgICAgICAgICAgcmV0dXJuIDMwO1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgcmV0dXJuICgwLCBlcnJvcl8xLnRocm93RXJyb3IpKFwiQXJndW1lbnQuTW9udGhcIiwgXCJJbnZhbGlkIG1vbnRoOiBcIi5jb25jYXQobW9udGgpKTtcbiAgICB9XG59XG5leHBvcnRzLmRheXNJbk1vbnRoID0gZGF5c0luTW9udGg7XG4vKipcbiAqIFJldHVybnMgdGhlIGRheSBvZiB0aGUgeWVhciBvZiB0aGUgZ2l2ZW4gZGF0ZSBbMC4uMzY1XS4gSmFudWFyeSBmaXJzdCBpcyAwLlxuICpcbiAqIEBwYXJhbSB5ZWFyXHRUaGUgeWVhciBlLmcuIDE5ODZcbiAqIEBwYXJhbSBtb250aCBNb250aCAxLTEyXG4gKiBAcGFyYW0gZGF5IERheSBvZiBtb250aCAxLTMxXG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuWWVhciBmb3IgaW52YWxpZCB5ZWFyIChub24taW50ZWdlcilcbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5Nb250aCBmb3IgaW52YWxpZCBtb250aFxuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LkRheSBmb3IgaW52YWxpZCBkYXkgb2YgbW9udGhcbiAqL1xuZnVuY3Rpb24gZGF5T2ZZZWFyKHllYXIsIG1vbnRoLCBkYXkpIHtcbiAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkoTnVtYmVyLmlzSW50ZWdlcih5ZWFyKSwgXCJBcmd1bWVudC5ZZWFyXCIsIFwiWWVhciBvdXQgb2YgcmFuZ2U6IFwiLmNvbmNhdCh5ZWFyKSk7XG4gICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKE51bWJlci5pc0ludGVnZXIobW9udGgpICYmIG1vbnRoID49IDEgJiYgbW9udGggPD0gMTIsIFwiQXJndW1lbnQuTW9udGhcIiwgXCJNb250aCBvdXQgb2YgcmFuZ2U6IFwiLmNvbmNhdChtb250aCkpO1xuICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KShOdW1iZXIuaXNJbnRlZ2VyKGRheSkgJiYgZGF5ID49IDEgJiYgZGF5IDw9IGRheXNJbk1vbnRoKHllYXIsIG1vbnRoKSwgXCJBcmd1bWVudC5EYXlcIiwgXCJkYXkgb3V0IG9mIHJhbmdlXCIpO1xuICAgIHZhciB5ZWFyRGF5ID0gMDtcbiAgICBmb3IgKHZhciBpID0gMTsgaSA8IG1vbnRoOyBpKyspIHtcbiAgICAgICAgeWVhckRheSArPSBkYXlzSW5Nb250aCh5ZWFyLCBpKTtcbiAgICB9XG4gICAgeWVhckRheSArPSAoZGF5IC0gMSk7XG4gICAgcmV0dXJuIHllYXJEYXk7XG59XG5leHBvcnRzLmRheU9mWWVhciA9IGRheU9mWWVhcjtcbi8qKlxuICogUmV0dXJucyB0aGUgbGFzdCBpbnN0YW5jZSBvZiB0aGUgZ2l2ZW4gd2Vla2RheSBpbiB0aGUgZ2l2ZW4gbW9udGhcbiAqXG4gKiBAcGFyYW0geWVhclx0VGhlIHllYXJcbiAqIEBwYXJhbSBtb250aFx0dGhlIG1vbnRoIDEtMTJcbiAqIEBwYXJhbSB3ZWVrRGF5XHR0aGUgZGVzaXJlZCB3ZWVrIGRheSAwLTZcbiAqIEByZXR1cm4gdGhlIGxhc3Qgb2NjdXJyZW5jZSBvZiB0aGUgd2VlayBkYXkgaW4gdGhlIG1vbnRoXG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuWWVhciBmb3IgaW52YWxpZCB5ZWFyIChub24taW50ZWdlcilcbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5Nb250aCBmb3IgaW52YWxpZCBtb250aFxuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LldlZWtEYXkgZm9yIGludmFsaWQgd2VlayBkYXlcbiAqL1xuZnVuY3Rpb24gbGFzdFdlZWtEYXlPZk1vbnRoKHllYXIsIG1vbnRoLCB3ZWVrRGF5KSB7XG4gICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKE51bWJlci5pc0ludGVnZXIoeWVhciksIFwiQXJndW1lbnQuWWVhclwiLCBcIlllYXIgb3V0IG9mIHJhbmdlOiBcIi5jb25jYXQoeWVhcikpO1xuICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KShOdW1iZXIuaXNJbnRlZ2VyKG1vbnRoKSAmJiBtb250aCA+PSAxICYmIG1vbnRoIDw9IDEyLCBcIkFyZ3VtZW50Lk1vbnRoXCIsIFwiTW9udGggb3V0IG9mIHJhbmdlOiBcIi5jb25jYXQobW9udGgpKTtcbiAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkoTnVtYmVyLmlzSW50ZWdlcih3ZWVrRGF5KSAmJiB3ZWVrRGF5ID49IDAgJiYgd2Vla0RheSA8PSA2LCBcIkFyZ3VtZW50LldlZWtEYXlcIiwgXCJ3ZWVrRGF5IG91dCBvZiByYW5nZTogXCIuY29uY2F0KHdlZWtEYXkpKTtcbiAgICB2YXIgZW5kT2ZNb250aCA9IG5ldyBUaW1lU3RydWN0KHsgeWVhcjogeWVhciwgbW9udGg6IG1vbnRoLCBkYXk6IGRheXNJbk1vbnRoKHllYXIsIG1vbnRoKSB9KTtcbiAgICB2YXIgZW5kT2ZNb250aFdlZWtEYXkgPSB3ZWVrRGF5Tm9MZWFwU2VjcyhlbmRPZk1vbnRoLnVuaXhNaWxsaXMpO1xuICAgIHZhciBkaWZmID0gd2Vla0RheSAtIGVuZE9mTW9udGhXZWVrRGF5O1xuICAgIGlmIChkaWZmID4gMCkge1xuICAgICAgICBkaWZmIC09IDc7XG4gICAgfVxuICAgIHJldHVybiBlbmRPZk1vbnRoLmNvbXBvbmVudHMuZGF5ICsgZGlmZjtcbn1cbmV4cG9ydHMubGFzdFdlZWtEYXlPZk1vbnRoID0gbGFzdFdlZWtEYXlPZk1vbnRoO1xuLyoqXG4gKiBSZXR1cm5zIHRoZSBmaXJzdCBpbnN0YW5jZSBvZiB0aGUgZ2l2ZW4gd2Vla2RheSBpbiB0aGUgZ2l2ZW4gbW9udGhcbiAqXG4gKiBAcGFyYW0geWVhclx0VGhlIHllYXJcbiAqIEBwYXJhbSBtb250aFx0dGhlIG1vbnRoIDEtMTJcbiAqIEBwYXJhbSB3ZWVrRGF5XHR0aGUgZGVzaXJlZCB3ZWVrIGRheVxuICogQHJldHVybiB0aGUgZmlyc3Qgb2NjdXJyZW5jZSBvZiB0aGUgd2VlayBkYXkgaW4gdGhlIG1vbnRoXG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuWWVhciBmb3IgaW52YWxpZCB5ZWFyIChub24taW50ZWdlcilcbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5Nb250aCBmb3IgaW52YWxpZCBtb250aFxuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LldlZWtEYXkgZm9yIGludmFsaWQgd2VlayBkYXlcbiAqL1xuZnVuY3Rpb24gZmlyc3RXZWVrRGF5T2ZNb250aCh5ZWFyLCBtb250aCwgd2Vla0RheSkge1xuICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KShOdW1iZXIuaXNJbnRlZ2VyKHllYXIpLCBcIkFyZ3VtZW50LlllYXJcIiwgXCJZZWFyIG91dCBvZiByYW5nZTogXCIuY29uY2F0KHllYXIpKTtcbiAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkoTnVtYmVyLmlzSW50ZWdlcihtb250aCkgJiYgbW9udGggPj0gMSAmJiBtb250aCA8PSAxMiwgXCJBcmd1bWVudC5Nb250aFwiLCBcIk1vbnRoIG91dCBvZiByYW5nZTogXCIuY29uY2F0KG1vbnRoKSk7XG4gICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKE51bWJlci5pc0ludGVnZXIod2Vla0RheSkgJiYgd2Vla0RheSA+PSAwICYmIHdlZWtEYXkgPD0gNiwgXCJBcmd1bWVudC5XZWVrRGF5XCIsIFwid2Vla0RheSBvdXQgb2YgcmFuZ2U6IFwiLmNvbmNhdCh3ZWVrRGF5KSk7XG4gICAgdmFyIGJlZ2luT2ZNb250aCA9IG5ldyBUaW1lU3RydWN0KHsgeWVhcjogeWVhciwgbW9udGg6IG1vbnRoLCBkYXk6IDEgfSk7XG4gICAgdmFyIGJlZ2luT2ZNb250aFdlZWtEYXkgPSB3ZWVrRGF5Tm9MZWFwU2VjcyhiZWdpbk9mTW9udGgudW5peE1pbGxpcyk7XG4gICAgdmFyIGRpZmYgPSB3ZWVrRGF5IC0gYmVnaW5PZk1vbnRoV2Vla0RheTtcbiAgICBpZiAoZGlmZiA8IDApIHtcbiAgICAgICAgZGlmZiArPSA3O1xuICAgIH1cbiAgICByZXR1cm4gYmVnaW5PZk1vbnRoLmNvbXBvbmVudHMuZGF5ICsgZGlmZjtcbn1cbmV4cG9ydHMuZmlyc3RXZWVrRGF5T2ZNb250aCA9IGZpcnN0V2Vla0RheU9mTW9udGg7XG4vKipcbiAqIFJldHVybnMgdGhlIG50aCBpbnN0YW5jZSBvZiB0aGUgZ2l2ZW4gd2Vla2RheSBpbiB0aGUgZ2l2ZW4gbW9udGg7IHRocm93cyBpZiBub3QgZm91bmRcbiAqXG4gKiBAcGFyYW0geWVhclx0VGhlIHllYXJcbiAqIEBwYXJhbSBtb250aFx0dGhlIG1vbnRoIDEtMTJcbiAqIEBwYXJhbSB3ZWVrRGF5XHR0aGUgZGVzaXJlZCB3ZWVrIGRheVxuICogQHBhcmFtIGRheUluc3RhbmNlXHR0aGUgZGVzaXJlZCB3ZWVrIGRheSBpbnN0YW5jZSwgblxuICogQHJldHVybiB0aGUgZmlyc3Qgb2NjdXJyZW5jZSBvZiB0aGUgd2VlayBkYXkgaW4gdGhlIG1vbnRoXG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuWWVhciBmb3IgaW52YWxpZCB5ZWFyIChub24taW50ZWdlcilcbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5Nb250aCBmb3IgaW52YWxpZCBtb250aFxuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LldlZWtEYXkgZm9yIGludmFsaWQgd2VlayBkYXlcbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5BcnVnbWVudC5EYXlJbnN0YW5jZSBmb3IgaW52YWxpZCBkYXkgaW5zdGFuY2UgKG5vdCAxLTUpXG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuTm90Rm91bmQgaWYgdGhlIG1vbnRoIGhhcyBubyBzdWNoIGluc3RhbmNlIChpLmUuIDV0aCBpbnN0YW5jZSwgd2hlcmUgb25seSA0IGV4aXN0KVxuICovXG5mdW5jdGlvbiBudGhXZWVrRGF5T2ZNb250aCh5ZWFyLCBtb250aCwgd2Vla0RheSwgZGF5SW5zdGFuY2UpIHtcbiAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkoTnVtYmVyLmlzSW50ZWdlcih5ZWFyKSwgXCJBcmd1bWVudC5ZZWFyXCIsIFwiWWVhciBvdXQgb2YgcmFuZ2U6IFwiLmNvbmNhdCh5ZWFyKSk7XG4gICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKE51bWJlci5pc0ludGVnZXIobW9udGgpICYmIG1vbnRoID49IDEgJiYgbW9udGggPD0gMTIsIFwiQXJndW1lbnQuTW9udGhcIiwgXCJNb250aCBvdXQgb2YgcmFuZ2U6IFwiLmNvbmNhdChtb250aCkpO1xuICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KShOdW1iZXIuaXNJbnRlZ2VyKHdlZWtEYXkpICYmIHdlZWtEYXkgPj0gMCAmJiB3ZWVrRGF5IDw9IDYsIFwiQXJndW1lbnQuV2Vla0RheVwiLCBcIndlZWtEYXkgb3V0IG9mIHJhbmdlOiBcIi5jb25jYXQod2Vla0RheSkpO1xuICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KShOdW1iZXIuaXNJbnRlZ2VyKGRheUluc3RhbmNlKSAmJiBkYXlJbnN0YW5jZSA+PSAxICYmIGRheUluc3RhbmNlIDw9IDUsIFwiQXJndW1lbnQuRGF5SW5zdGFuY2VcIiwgXCJkYXlJbnN0YW5jZSBvdXQgb2YgcmFuZ2U6IFwiLmNvbmNhdChkYXlJbnN0YW5jZSkpO1xuICAgIHZhciBiZWdpbk9mTW9udGggPSBuZXcgVGltZVN0cnVjdCh7IHllYXI6IHllYXIsIG1vbnRoOiBtb250aCwgZGF5OiAxIH0pO1xuICAgIHZhciBiZWdpbk9mTW9udGhXZWVrRGF5ID0gd2Vla0RheU5vTGVhcFNlY3MoYmVnaW5PZk1vbnRoLnVuaXhNaWxsaXMpO1xuICAgIHZhciBkaWZmID0gd2Vla0RheSAtIGJlZ2luT2ZNb250aFdlZWtEYXk7XG4gICAgaWYgKGRpZmYgPCAwKSB7XG4gICAgICAgIGRpZmYgKz0gNztcbiAgICB9XG4gICAgZGlmZiArPSAoZGF5SW5zdGFuY2UgLSAxKSAqIDc7XG4gICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKGJlZ2luT2ZNb250aC5jb21wb25lbnRzLmRheSArIGRpZmYgPD0gZGF5c0luTW9udGgoeWVhciwgbW9udGgpLCBcIk5vdEZvdW5kXCIsIFwiVGhlIGdpdmVuIG1vbnRoIGhhcyBubyBzdWNoIGRheVwiKTtcbiAgICByZXR1cm4gYmVnaW5PZk1vbnRoLmNvbXBvbmVudHMuZGF5ICsgZGlmZjtcbn1cbmV4cG9ydHMubnRoV2Vla0RheU9mTW9udGggPSBudGhXZWVrRGF5T2ZNb250aDtcbi8qKlxuICogUmV0dXJucyB0aGUgZGF5LW9mLW1vbnRoIHRoYXQgaXMgb24gdGhlIGdpdmVuIHdlZWtkYXkgYW5kIHdoaWNoIGlzID49IHRoZSBnaXZlbiBkYXk7IHRocm93cyBpZiBub3QgZm91bmRcbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5ZZWFyIGZvciBpbnZhbGlkIHllYXIgKG5vbi1pbnRlZ2VyKVxuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50Lk1vbnRoIGZvciBpbnZhbGlkIG1vbnRoXG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuRGF5IGZvciBpbnZhbGlkIGRheSBvZiBtb250aFxuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LldlZWtEYXkgZm9yIGludmFsaWQgd2VlayBkYXlcbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Ob3RGb3VuZCBpZiB0aGUgbW9udGggaGFzIG5vIHN1Y2ggZGF5XG4gKi9cbmZ1bmN0aW9uIHdlZWtEYXlPbk9yQWZ0ZXIoeWVhciwgbW9udGgsIGRheSwgd2Vla0RheSkge1xuICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KShOdW1iZXIuaXNJbnRlZ2VyKHllYXIpLCBcIkFyZ3VtZW50LlllYXJcIiwgXCJZZWFyIG91dCBvZiByYW5nZTogXCIuY29uY2F0KHllYXIpKTtcbiAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkoTnVtYmVyLmlzSW50ZWdlcihtb250aCkgJiYgbW9udGggPj0gMSAmJiBtb250aCA8PSAxMiwgXCJBcmd1bWVudC5Nb250aFwiLCBcIk1vbnRoIG91dCBvZiByYW5nZTogXCIuY29uY2F0KG1vbnRoKSk7XG4gICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKE51bWJlci5pc0ludGVnZXIoZGF5KSAmJiBkYXkgPj0gMSAmJiBkYXkgPD0gZGF5c0luTW9udGgoeWVhciwgbW9udGgpLCBcIkFyZ3VtZW50LkRheVwiLCBcImRheSBvdXQgb2YgcmFuZ2VcIik7XG4gICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKE51bWJlci5pc0ludGVnZXIod2Vla0RheSkgJiYgd2Vla0RheSA+PSAwICYmIHdlZWtEYXkgPD0gNiwgXCJBcmd1bWVudC5XZWVrRGF5XCIsIFwid2Vla0RheSBvdXQgb2YgcmFuZ2U6IFwiLmNvbmNhdCh3ZWVrRGF5KSk7XG4gICAgdmFyIHN0YXJ0ID0gbmV3IFRpbWVTdHJ1Y3QoeyB5ZWFyOiB5ZWFyLCBtb250aDogbW9udGgsIGRheTogZGF5IH0pO1xuICAgIHZhciBzdGFydFdlZWtEYXkgPSB3ZWVrRGF5Tm9MZWFwU2VjcyhzdGFydC51bml4TWlsbGlzKTtcbiAgICB2YXIgZGlmZiA9IHdlZWtEYXkgLSBzdGFydFdlZWtEYXk7XG4gICAgaWYgKGRpZmYgPCAwKSB7XG4gICAgICAgIGRpZmYgKz0gNztcbiAgICB9XG4gICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKHN0YXJ0LmNvbXBvbmVudHMuZGF5ICsgZGlmZiA8PSBkYXlzSW5Nb250aCh5ZWFyLCBtb250aCksIFwiTm90Rm91bmRcIiwgXCJUaGUgZ2l2ZW4gbW9udGggaGFzIG5vIHN1Y2ggd2Vla2RheVwiKTtcbiAgICByZXR1cm4gc3RhcnQuY29tcG9uZW50cy5kYXkgKyBkaWZmO1xufVxuZXhwb3J0cy53ZWVrRGF5T25PckFmdGVyID0gd2Vla0RheU9uT3JBZnRlcjtcbi8qKlxuICogUmV0dXJucyB0aGUgZGF5LW9mLW1vbnRoIHRoYXQgaXMgb24gdGhlIGdpdmVuIHdlZWtkYXkgYW5kIHdoaWNoIGlzIDw9IHRoZSBnaXZlbiBkYXkuXG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuWWVhciBmb3IgaW52YWxpZCB5ZWFyIChub24taW50ZWdlcilcbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5Nb250aCBmb3IgaW52YWxpZCBtb250aFxuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LkRheSBmb3IgaW52YWxpZCBkYXkgb2YgbW9udGhcbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5XZWVrRGF5IGZvciBpbnZhbGlkIHdlZWsgZGF5XG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuTm90Rm91bmQgaWYgdGhlIG1vbnRoIGhhcyBubyBzdWNoIGRheVxuICovXG5mdW5jdGlvbiB3ZWVrRGF5T25PckJlZm9yZSh5ZWFyLCBtb250aCwgZGF5LCB3ZWVrRGF5KSB7XG4gICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKE51bWJlci5pc0ludGVnZXIoeWVhciksIFwiQXJndW1lbnQuWWVhclwiLCBcIlllYXIgb3V0IG9mIHJhbmdlOiBcIi5jb25jYXQoeWVhcikpO1xuICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KShOdW1iZXIuaXNJbnRlZ2VyKG1vbnRoKSAmJiBtb250aCA+PSAxICYmIG1vbnRoIDw9IDEyLCBcIkFyZ3VtZW50Lk1vbnRoXCIsIFwiTW9udGggb3V0IG9mIHJhbmdlOiBcIi5jb25jYXQobW9udGgpKTtcbiAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkoTnVtYmVyLmlzSW50ZWdlcihkYXkpICYmIGRheSA+PSAxICYmIGRheSA8PSBkYXlzSW5Nb250aCh5ZWFyLCBtb250aCksIFwiQXJndW1lbnQuRGF5XCIsIFwiZGF5IG91dCBvZiByYW5nZVwiKTtcbiAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkoTnVtYmVyLmlzSW50ZWdlcih3ZWVrRGF5KSAmJiB3ZWVrRGF5ID49IDAgJiYgd2Vla0RheSA8PSA2LCBcIkFyZ3VtZW50LldlZWtEYXlcIiwgXCJ3ZWVrRGF5IG91dCBvZiByYW5nZTogXCIuY29uY2F0KHdlZWtEYXkpKTtcbiAgICB2YXIgc3RhcnQgPSBuZXcgVGltZVN0cnVjdCh7IHllYXI6IHllYXIsIG1vbnRoOiBtb250aCwgZGF5OiBkYXkgfSk7XG4gICAgdmFyIHN0YXJ0V2Vla0RheSA9IHdlZWtEYXlOb0xlYXBTZWNzKHN0YXJ0LnVuaXhNaWxsaXMpO1xuICAgIHZhciBkaWZmID0gd2Vla0RheSAtIHN0YXJ0V2Vla0RheTtcbiAgICBpZiAoZGlmZiA+IDApIHtcbiAgICAgICAgZGlmZiAtPSA3O1xuICAgIH1cbiAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkoc3RhcnQuY29tcG9uZW50cy5kYXkgKyBkaWZmID49IDEsIFwiTm90Rm91bmRcIiwgXCJUaGUgZ2l2ZW4gbW9udGggaGFzIG5vIHN1Y2ggd2Vla2RheVwiKTtcbiAgICByZXR1cm4gc3RhcnQuY29tcG9uZW50cy5kYXkgKyBkaWZmO1xufVxuZXhwb3J0cy53ZWVrRGF5T25PckJlZm9yZSA9IHdlZWtEYXlPbk9yQmVmb3JlO1xuLyoqXG4gKiBUaGUgd2VlayBvZiB0aGlzIG1vbnRoLiBUaGVyZSBpcyBubyBvZmZpY2lhbCBzdGFuZGFyZCBmb3IgdGhpcywgYnV0IHdlIGFzc3VtZSB0aGUgc2FtZSBydWxlcyBmb3IgdGhlIHdlZWtOdW1iZXI6XG4gKiB3ZWVrIDEgaXMgdGhlIHdlZWsgdGhhdCBoYXMgdGhlIDR0aCBkYXkgb2YgdGhlIG1vbnRoIGluIGl0XG4gKlxuICogQHBhcmFtIHllYXIgVGhlIHllYXJcbiAqIEBwYXJhbSBtb250aCBUaGUgbW9udGggWzEtMTJdXG4gKiBAcGFyYW0gZGF5IFRoZSBkYXkgWzEtMzFdXG4gKiBAcmV0dXJuIFdlZWsgbnVtYmVyIFsxLTVdXG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuWWVhciBmb3IgaW52YWxpZCB5ZWFyIChub24taW50ZWdlcilcbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5Nb250aCBmb3IgaW52YWxpZCBtb250aFxuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LkRheSBmb3IgaW52YWxpZCBkYXkgb2YgbW9udGhcbiAqL1xuZnVuY3Rpb24gd2Vla09mTW9udGgoeWVhciwgbW9udGgsIGRheSkge1xuICAgIC8vIHJlbHkgb24geWVhci9tb250aCB2YWxpZGF0aW9uIGluIGZpcnN0V2Vla0RheU9mTW9udGhcbiAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkoTnVtYmVyLmlzSW50ZWdlcihkYXkpICYmIGRheSA+PSAxICYmIGRheSA8PSBkYXlzSW5Nb250aCh5ZWFyLCBtb250aCksIFwiQXJndW1lbnQuRGF5XCIsIFwiZGF5IG91dCBvZiByYW5nZVwiKTtcbiAgICB2YXIgZmlyc3RUaHVyc2RheSA9IGZpcnN0V2Vla0RheU9mTW9udGgoeWVhciwgbW9udGgsIFdlZWtEYXkuVGh1cnNkYXkpO1xuICAgIHZhciBmaXJzdE1vbmRheSA9IGZpcnN0V2Vla0RheU9mTW9udGgoeWVhciwgbW9udGgsIFdlZWtEYXkuTW9uZGF5KTtcbiAgICAvLyBDb3JuZXIgY2FzZTogY2hlY2sgaWYgd2UgYXJlIGluIHdlZWsgMSBvciBsYXN0IHdlZWsgb2YgcHJldmlvdXMgbW9udGhcbiAgICBpZiAoZGF5IDwgZmlyc3RNb25kYXkpIHtcbiAgICAgICAgaWYgKGZpcnN0VGh1cnNkYXkgPCBmaXJzdE1vbmRheSkge1xuICAgICAgICAgICAgLy8gV2VlayAxXG4gICAgICAgICAgICByZXR1cm4gMTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIC8vIExhc3Qgd2VlayBvZiBwcmV2aW91cyBtb250aFxuICAgICAgICAgICAgaWYgKG1vbnRoID4gMSkge1xuICAgICAgICAgICAgICAgIC8vIERlZmF1bHQgY2FzZVxuICAgICAgICAgICAgICAgIHJldHVybiB3ZWVrT2ZNb250aCh5ZWFyLCBtb250aCAtIDEsIGRheXNJbk1vbnRoKHllYXIsIG1vbnRoIC0gMSkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgLy8gSmFudWFyeVxuICAgICAgICAgICAgICAgIHJldHVybiB3ZWVrT2ZNb250aCh5ZWFyIC0gMSwgMTIsIDMxKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbiAgICB2YXIgbGFzdE1vbmRheSA9IGxhc3RXZWVrRGF5T2ZNb250aCh5ZWFyLCBtb250aCwgV2Vla0RheS5Nb25kYXkpO1xuICAgIHZhciBsYXN0VGh1cnNkYXkgPSBsYXN0V2Vla0RheU9mTW9udGgoeWVhciwgbW9udGgsIFdlZWtEYXkuVGh1cnNkYXkpO1xuICAgIC8vIENvcm5lciBjYXNlOiBjaGVjayBpZiB3ZSBhcmUgaW4gbGFzdCB3ZWVrIG9yIHdlZWsgMSBvZiBwcmV2aW91cyBtb250aFxuICAgIGlmIChkYXkgPj0gbGFzdE1vbmRheSkge1xuICAgICAgICBpZiAobGFzdE1vbmRheSA+IGxhc3RUaHVyc2RheSkge1xuICAgICAgICAgICAgLy8gV2VlayAxIG9mIG5leHQgbW9udGhcbiAgICAgICAgICAgIHJldHVybiAxO1xuICAgICAgICB9XG4gICAgfVxuICAgIC8vIE5vcm1hbCBjYXNlXG4gICAgdmFyIHJlc3VsdCA9IE1hdGguZmxvb3IoKGRheSAtIGZpcnN0TW9uZGF5KSAvIDcpICsgMTtcbiAgICBpZiAoZmlyc3RUaHVyc2RheSA8IDQpIHtcbiAgICAgICAgcmVzdWx0ICs9IDE7XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQ7XG59XG5leHBvcnRzLndlZWtPZk1vbnRoID0gd2Vla09mTW9udGg7XG4vKipcbiAqIFRoZSB3ZWVrIG9mIHRoaXMgbW9udGgsIGJhc2VkIG9uIGNvdW50aW5nIGNhbGVuZGFyIHdlZWtzLiBVbmxpa2Ugd2Vla09mTW9udGgoKSB0aGUgZmlyc3QgZGF5IG9mIHRoZSBtb250aCBpc1xuICogYWx3YXlzIHdlZWsgMSwgYW5kIG5vIGRheXMgY291bnQgYXMgdGhlIGxhc3Qgd2VlayBvZiB0aGUgcHJldmlvdXMgbW9udGguIFRoZSB3ZWVrIG51bWJlciByZXR1cm5lZCBjYW4gYmUgZnJvbSAxLTYsXG4gKiBhcyBhIG1vbnRoIGNhbiBzcGFuIHVwIHRvIDYgZGlmZmVyZW50IHdlZWtzIG9uIHRoZSBjYWxlbmRhci4gVGhlIGZpcnN0IGRheSBvZiB0aGUgd2VlaywgaS5lLiB3aGVuIHRoZSB3ZWVrIG51bWJlclxuICogaW5jcmVhc2VzLCBpcyBjdXN0b21pemFibGUsIGFuZCBkZWZhdWx0cyB0byBNb25kYXkuXG4gKlxuICogQHBhcmFtIHllYXIgVGhlIHllYXJcbiAqIEBwYXJhbSBtb250aCBUaGUgbW9udGggWzEtMTJdXG4gKiBAcGFyYW0gZGF5IFRoZSBkYXkgWzEtMzFdXG4gKiBAcGFyYW0gd2Vla1N0YXJ0RGF5IFRoZSB3ZWVrIGRheSB0byB1c2UgYXMgdGhlIHN0YXJ0IG9mIHRoZSB3ZWVrXG4gKiBAcmV0dXJuIFdlZWsgbnVtYmVyIFsxLTZdXG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuWWVhciBmb3IgaW52YWxpZCB5ZWFyIChub24taW50ZWdlcilcbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5Nb250aCBmb3IgaW52YWxpZCBtb250aFxuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LkRheSBmb3IgaW52YWxpZCBkYXkgb2YgbW9udGhcbiAqL1xuZnVuY3Rpb24gY2FsZW5kYXJXZWVrSW5Nb250aCh5ZWFyLCBtb250aCwgZGF5LCB3ZWVrU3RhcnREYXkpIHtcbiAgICBpZiAod2Vla1N0YXJ0RGF5ID09PSB2b2lkIDApIHsgd2Vla1N0YXJ0RGF5ID0gV2Vla0RheS5Nb25kYXk7IH1cbiAgICAvLyByZWx5IG9uIHllYXIvbW9udGggdmFsaWRhdGlvbiBpbiB3ZWVrRGF5T25PckFmdGVyXG4gICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKE51bWJlci5pc0ludGVnZXIoZGF5KSAmJiBkYXkgPj0gMSAmJiBkYXkgPD0gZGF5c0luTW9udGgoeWVhciwgbW9udGgpLCBcIkFyZ3VtZW50LkRheVwiLCBcImRheSBvdXQgb2YgcmFuZ2VcIik7XG4gICAgdmFyIGZpcnN0RnVsbFdlZWtTdGFydERheSA9IHdlZWtEYXlPbk9yQWZ0ZXIoeWVhciwgbW9udGgsIDEsIHdlZWtTdGFydERheSk7XG4gICAgdmFyIHJlc3VsdCA9IE1hdGguZmxvb3IoKGRheSAtIGZpcnN0RnVsbFdlZWtTdGFydERheSArIDcpIC8gNyk7XG4gICAgaWYgKGZpcnN0RnVsbFdlZWtTdGFydERheSA+IDEpIHtcbiAgICAgICAgcmVzdWx0Kys7XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQ7XG59XG5leHBvcnRzLmNhbGVuZGFyV2Vla0luTW9udGggPSBjYWxlbmRhcldlZWtJbk1vbnRoO1xuLyoqXG4gKiBSZXR1cm5zIHRoZSB3ZWVrZGF5IGluc3RhbmNlIG51bWJlciBpbiB0aGUgbW9udGggZm9yIHRoZSBnaXZlbiBkYXRlXG4gKlxuICogQHBhcmFtIHllYXIgVGhlIHllYXJcbiAqIEBwYXJhbSBtb250aCBUaGUgbW9udGggWzEtMTJdXG4gKiBAcGFyYW0gZGF5IFRoZSBkYXkgWzEtMzFdXG4gKiBAcmV0dXJuIEluc3RhbmNlIG51bWJlciBbMS01XVxuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LlllYXIgZm9yIGludmFsaWQgeWVhciAobm9uLWludGVnZXIpXG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuTW9udGggZm9yIGludmFsaWQgbW9udGhcbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5EYXkgZm9yIGludmFsaWQgZGF5IG9mIG1vbnRoXG4gKi9cbmZ1bmN0aW9uIHdlZWtEYXlJbnN0YW5jZUluTW9udGgoeWVhciwgbW9udGgsIGRheSkge1xuICAgIC8vIHJlbHkgb24geWVhci9tb250aCB2YWxpZGF0aW9uIGluIGZpcnN0V2Vla0RheU9mTW9udGhcbiAgICB2YXIgd2Vla0RheSA9IHdlZWtEYXlOb0xlYXBTZWNzKG5ldyBUaW1lU3RydWN0KHsgeWVhcjogeWVhciwgbW9udGg6IG1vbnRoLCBkYXk6IGRheSB9KS51bml4TWlsbGlzKTtcbiAgICB2YXIgZmlyc3RJbnN0YW5jZU9mRGF5ID0gZmlyc3RXZWVrRGF5T2ZNb250aCh5ZWFyLCBtb250aCwgd2Vla0RheSk7XG4gICAgdmFyIHJlc3VsdCA9ICgoZGF5IC0gZmlyc3RJbnN0YW5jZU9mRGF5KSAvIDcpICsgMTtcbiAgICByZXR1cm4gcmVzdWx0O1xufVxuZXhwb3J0cy53ZWVrRGF5SW5zdGFuY2VJbk1vbnRoID0gd2Vla0RheUluc3RhbmNlSW5Nb250aDtcbi8qKlxuICogUmV0dXJucyB0aGUgZGF5LW9mLXllYXIgb2YgdGhlIE1vbmRheSBvZiB3ZWVrIDEgaW4gdGhlIGdpdmVuIHllYXIuXG4gKiBOb3RlIHRoYXQgdGhlIHJlc3VsdCBtYXkgbGllIGluIHRoZSBwcmV2aW91cyB5ZWFyLCBpbiB3aGljaCBjYXNlIGl0XG4gKiB3aWxsIGJlIChtdWNoKSBncmVhdGVyIHRoYW4gNFxuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LlllYXIgZm9yIGludmFsaWQgeWVhciAobm9uLWludGVnZXIpXG4gKi9cbmZ1bmN0aW9uIGdldFdlZWtPbmVEYXlPZlllYXIoeWVhcikge1xuICAgIC8vIHJlbGF5IG9uIHdlZWtEYXlPbk9yQWZ0ZXIgZm9yIHllYXIgdmFsaWRhdGlvblxuICAgIC8vIGZpcnN0IG1vbmRheSBvZiBKYW51YXJ5LCBtaW51cyBvbmUgYmVjYXVzZSB3ZSB3YW50IGRheS1vZi15ZWFyXG4gICAgdmFyIHJlc3VsdCA9IHdlZWtEYXlPbk9yQWZ0ZXIoeWVhciwgMSwgMSwgV2Vla0RheS5Nb25kYXkpIC0gMTtcbiAgICBpZiAocmVzdWx0ID4gMykgeyAvLyBncmVhdGVyIHRoYW4gamFuIDR0aFxuICAgICAgICByZXN1bHQgLT0gNztcbiAgICAgICAgaWYgKHJlc3VsdCA8IDApIHtcbiAgICAgICAgICAgIHJlc3VsdCArPSBleHBvcnRzLmRheXNJblllYXIoeWVhciAtIDEpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQ7XG59XG4vKipcbiAqIFRoZSBJU08gODYwMSB3ZWVrIG51bWJlciBmb3IgdGhlIGdpdmVuIGRhdGUuIFdlZWsgMSBpcyB0aGUgd2Vla1xuICogdGhhdCBoYXMgSmFudWFyeSA0dGggaW4gaXQsIGFuZCBpdCBzdGFydHMgb24gTW9uZGF5LlxuICogU2VlIGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0lTT193ZWVrX2RhdGVcbiAqXG4gKiBAcGFyYW0geWVhclx0WWVhciBlLmcuIDE5ODhcbiAqIEBwYXJhbSBtb250aFx0TW9udGggMS0xMlxuICogQHBhcmFtIGRheVx0RGF5IG9mIG1vbnRoIDEtMzFcbiAqIEByZXR1cm4gV2VlayBudW1iZXIgMS01M1xuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LlllYXIgZm9yIGludmFsaWQgeWVhciAobm9uLWludGVnZXIpXG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuTW9udGggZm9yIGludmFsaWQgbW9udGhcbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5EYXkgZm9yIGludmFsaWQgZGF5IG9mIG1vbnRoXG4gKi9cbmZ1bmN0aW9uIHdlZWtOdW1iZXIoeWVhciwgbW9udGgsIGRheSkge1xuICAgIHZhciBkb3kgPSBkYXlPZlllYXIoeWVhciwgbW9udGgsIGRheSk7XG4gICAgLy8gY2hlY2sgZW5kLW9mLXllYXIgY29ybmVyIGNhc2U6IG1heSBiZSB3ZWVrIDEgb2YgbmV4dCB5ZWFyXG4gICAgaWYgKGRveSA+PSBkYXlPZlllYXIoeWVhciwgMTIsIDI5KSkge1xuICAgICAgICB2YXIgbmV4dFllYXJXZWVrT25lID0gZ2V0V2Vla09uZURheU9mWWVhcih5ZWFyICsgMSk7XG4gICAgICAgIGlmIChuZXh0WWVhcldlZWtPbmUgPiA0ICYmIG5leHRZZWFyV2Vla09uZSA8PSBkb3kpIHtcbiAgICAgICAgICAgIHJldHVybiAxO1xuICAgICAgICB9XG4gICAgfVxuICAgIC8vIGNoZWNrIGJlZ2lubmluZy1vZi15ZWFyIGNvcm5lciBjYXNlXG4gICAgdmFyIHRoaXNZZWFyV2Vla09uZSA9IGdldFdlZWtPbmVEYXlPZlllYXIoeWVhcik7XG4gICAgaWYgKHRoaXNZZWFyV2Vla09uZSA+IDQpIHtcbiAgICAgICAgLy8gd2VlayAxIGlzIGF0IGVuZCBvZiBsYXN0IHllYXJcbiAgICAgICAgdmFyIHdlZWtUd28gPSB0aGlzWWVhcldlZWtPbmUgKyA3IC0gZGF5c0luWWVhcih5ZWFyIC0gMSk7XG4gICAgICAgIGlmIChkb3kgPCB3ZWVrVHdvKSB7XG4gICAgICAgICAgICByZXR1cm4gMTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBNYXRoLmZsb29yKChkb3kgLSB3ZWVrVHdvKSAvIDcpICsgMjtcbiAgICAgICAgfVxuICAgIH1cbiAgICAvLyBXZWVrIDEgaXMgZW50aXJlbHkgaW5zaWRlIHRoaXMgeWVhci5cbiAgICBpZiAoZG95IDwgdGhpc1llYXJXZWVrT25lKSB7XG4gICAgICAgIC8vIFRoZSBkYXRlIGlzIHBhcnQgb2YgdGhlIGxhc3Qgd2VlayBvZiBwcmV2IHllYXIuXG4gICAgICAgIHJldHVybiB3ZWVrTnVtYmVyKHllYXIgLSAxLCAxMiwgMzEpO1xuICAgIH1cbiAgICAvLyBub3JtYWwgY2FzZXM7IG5vdGUgdGhhdCB3ZWVrIG51bWJlcnMgc3RhcnQgZnJvbSAxIHNvICsxXG4gICAgcmV0dXJuIE1hdGguZmxvb3IoKGRveSAtIHRoaXNZZWFyV2Vla09uZSkgLyA3KSArIDE7XG59XG5leHBvcnRzLndlZWtOdW1iZXIgPSB3ZWVrTnVtYmVyO1xuLyoqXG4gKiBDb252ZXJ0IGEgdW5peCBtaWxsaSB0aW1lc3RhbXAgaW50byBhIFRpbWVUIHN0cnVjdHVyZS5cbiAqIFRoaXMgZG9lcyBOT1QgdGFrZSBsZWFwIHNlY29uZHMgaW50byBhY2NvdW50LlxuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LlVuaXhNaWxsaXMgZm9yIG5vbi1pbnRlZ2VyIGB1bml4TWlsbGlzYCBwYXJhbWV0ZXJcbiAqL1xuZnVuY3Rpb24gdW5peFRvVGltZU5vTGVhcFNlY3ModW5peE1pbGxpcykge1xuICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KShOdW1iZXIuaXNJbnRlZ2VyKHVuaXhNaWxsaXMpLCBcIkFyZ3VtZW50LlVuaXhNaWxsaXNcIiwgXCJ1bml4TWlsbGlzIHNob3VsZCBiZSBhbiBpbnRlZ2VyIG51bWJlclwiKTtcbiAgICB2YXIgdGVtcCA9IHVuaXhNaWxsaXM7XG4gICAgdmFyIHJlc3VsdCA9IHsgeWVhcjogMCwgbW9udGg6IDAsIGRheTogMCwgaG91cjogMCwgbWludXRlOiAwLCBzZWNvbmQ6IDAsIG1pbGxpOiAwIH07XG4gICAgdmFyIHllYXI7XG4gICAgdmFyIG1vbnRoO1xuICAgIGlmICh1bml4TWlsbGlzID49IDApIHtcbiAgICAgICAgcmVzdWx0Lm1pbGxpID0gbWF0aC5wb3NpdGl2ZU1vZHVsbyh0ZW1wLCAxMDAwKTtcbiAgICAgICAgdGVtcCA9IE1hdGguZmxvb3IodGVtcCAvIDEwMDApO1xuICAgICAgICByZXN1bHQuc2Vjb25kID0gbWF0aC5wb3NpdGl2ZU1vZHVsbyh0ZW1wLCA2MCk7XG4gICAgICAgIHRlbXAgPSBNYXRoLmZsb29yKHRlbXAgLyA2MCk7XG4gICAgICAgIHJlc3VsdC5taW51dGUgPSBtYXRoLnBvc2l0aXZlTW9kdWxvKHRlbXAsIDYwKTtcbiAgICAgICAgdGVtcCA9IE1hdGguZmxvb3IodGVtcCAvIDYwKTtcbiAgICAgICAgcmVzdWx0LmhvdXIgPSBtYXRoLnBvc2l0aXZlTW9kdWxvKHRlbXAsIDI0KTtcbiAgICAgICAgdGVtcCA9IE1hdGguZmxvb3IodGVtcCAvIDI0KTtcbiAgICAgICAgeWVhciA9IDE5NzA7XG4gICAgICAgIHdoaWxlICh0ZW1wID49IGRheXNJblllYXIoeWVhcikpIHtcbiAgICAgICAgICAgIHRlbXAgLT0gZGF5c0luWWVhcih5ZWFyKTtcbiAgICAgICAgICAgIHllYXIrKztcbiAgICAgICAgfVxuICAgICAgICByZXN1bHQueWVhciA9IHllYXI7XG4gICAgICAgIG1vbnRoID0gMTtcbiAgICAgICAgd2hpbGUgKHRlbXAgPj0gZGF5c0luTW9udGgoeWVhciwgbW9udGgpKSB7XG4gICAgICAgICAgICB0ZW1wIC09IGRheXNJbk1vbnRoKHllYXIsIG1vbnRoKTtcbiAgICAgICAgICAgIG1vbnRoKys7XG4gICAgICAgIH1cbiAgICAgICAgcmVzdWx0Lm1vbnRoID0gbW9udGg7XG4gICAgICAgIHJlc3VsdC5kYXkgPSB0ZW1wICsgMTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIC8vIE5vdGUgdGhhdCBhIG5lZ2F0aXZlIG51bWJlciBtb2R1bG8gc29tZXRoaW5nIHlpZWxkcyBhIG5lZ2F0aXZlIG51bWJlci5cbiAgICAgICAgLy8gV2UgbWFrZSBpdCBwb3NpdGl2ZSBieSBhZGRpbmcgdGhlIG1vZHVsby5cbiAgICAgICAgcmVzdWx0Lm1pbGxpID0gbWF0aC5wb3NpdGl2ZU1vZHVsbyh0ZW1wLCAxMDAwKTtcbiAgICAgICAgdGVtcCA9IE1hdGguZmxvb3IodGVtcCAvIDEwMDApO1xuICAgICAgICByZXN1bHQuc2Vjb25kID0gbWF0aC5wb3NpdGl2ZU1vZHVsbyh0ZW1wLCA2MCk7XG4gICAgICAgIHRlbXAgPSBNYXRoLmZsb29yKHRlbXAgLyA2MCk7XG4gICAgICAgIHJlc3VsdC5taW51dGUgPSBtYXRoLnBvc2l0aXZlTW9kdWxvKHRlbXAsIDYwKTtcbiAgICAgICAgdGVtcCA9IE1hdGguZmxvb3IodGVtcCAvIDYwKTtcbiAgICAgICAgcmVzdWx0LmhvdXIgPSBtYXRoLnBvc2l0aXZlTW9kdWxvKHRlbXAsIDI0KTtcbiAgICAgICAgdGVtcCA9IE1hdGguZmxvb3IodGVtcCAvIDI0KTtcbiAgICAgICAgeWVhciA9IDE5Njk7XG4gICAgICAgIHdoaWxlICh0ZW1wIDwgLWRheXNJblllYXIoeWVhcikpIHtcbiAgICAgICAgICAgIHRlbXAgKz0gZGF5c0luWWVhcih5ZWFyKTtcbiAgICAgICAgICAgIHllYXItLTtcbiAgICAgICAgfVxuICAgICAgICByZXN1bHQueWVhciA9IHllYXI7XG4gICAgICAgIG1vbnRoID0gMTI7XG4gICAgICAgIHdoaWxlICh0ZW1wIDwgLWRheXNJbk1vbnRoKHllYXIsIG1vbnRoKSkge1xuICAgICAgICAgICAgdGVtcCArPSBkYXlzSW5Nb250aCh5ZWFyLCBtb250aCk7XG4gICAgICAgICAgICBtb250aC0tO1xuICAgICAgICB9XG4gICAgICAgIHJlc3VsdC5tb250aCA9IG1vbnRoO1xuICAgICAgICByZXN1bHQuZGF5ID0gdGVtcCArIDEgKyBkYXlzSW5Nb250aCh5ZWFyLCBtb250aCk7XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQ7XG59XG5leHBvcnRzLnVuaXhUb1RpbWVOb0xlYXBTZWNzID0gdW5peFRvVGltZU5vTGVhcFNlY3M7XG4vKipcbiAqIEZpbGwgeW91IGFueSBtaXNzaW5nIHRpbWUgY29tcG9uZW50IHBhcnRzLCBkZWZhdWx0cyBhcmUgMTk3MC0wMS0wMVQwMDowMDowMC4wMDBcbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5ZZWFyIGZvciBpbnZhbGlkIHllYXJcbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5Nb250aCBmb3IgaW52YWxpZCBtb250aFxuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LkRheSBmb3IgaW52YWxpZCBkYXkgb2YgbW9udGhcbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5Ib3VyIGZvciBpbnZhbGlkIGhvdXJcbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5NaW51dGUgZm9yIGludmFsaWQgbWludXRlXG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuU2Vjb25kIGZvciBpbnZhbGlkIHNlY29uZFxuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50Lk1pbGxpIGZvciBpbnZhbGlkIG1pbGxpc2Vjb25kc1xuICovXG5mdW5jdGlvbiBub3JtYWxpemVUaW1lQ29tcG9uZW50cyhjb21wb25lbnRzKSB7XG4gICAgdmFyIGlucHV0ID0ge1xuICAgICAgICB5ZWFyOiB0eXBlb2YgY29tcG9uZW50cy55ZWFyID09PSBcIm51bWJlclwiID8gY29tcG9uZW50cy55ZWFyIDogMTk3MCxcbiAgICAgICAgbW9udGg6IHR5cGVvZiBjb21wb25lbnRzLm1vbnRoID09PSBcIm51bWJlclwiID8gY29tcG9uZW50cy5tb250aCA6IDEsXG4gICAgICAgIGRheTogdHlwZW9mIGNvbXBvbmVudHMuZGF5ID09PSBcIm51bWJlclwiID8gY29tcG9uZW50cy5kYXkgOiAxLFxuICAgICAgICBob3VyOiB0eXBlb2YgY29tcG9uZW50cy5ob3VyID09PSBcIm51bWJlclwiID8gY29tcG9uZW50cy5ob3VyIDogMCxcbiAgICAgICAgbWludXRlOiB0eXBlb2YgY29tcG9uZW50cy5taW51dGUgPT09IFwibnVtYmVyXCIgPyBjb21wb25lbnRzLm1pbnV0ZSA6IDAsXG4gICAgICAgIHNlY29uZDogdHlwZW9mIGNvbXBvbmVudHMuc2Vjb25kID09PSBcIm51bWJlclwiID8gY29tcG9uZW50cy5zZWNvbmQgOiAwLFxuICAgICAgICBtaWxsaTogdHlwZW9mIGNvbXBvbmVudHMubWlsbGkgPT09IFwibnVtYmVyXCIgPyBjb21wb25lbnRzLm1pbGxpIDogMCxcbiAgICB9O1xuICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KShOdW1iZXIuaXNJbnRlZ2VyKGlucHV0LnllYXIpLCBcIkFyZ3VtZW50LlllYXJcIiwgXCJpbnZhbGlkIHllYXIgXCIuY29uY2F0KGlucHV0LnllYXIpKTtcbiAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkoTnVtYmVyLmlzSW50ZWdlcihpbnB1dC5tb250aCkgJiYgaW5wdXQubW9udGggPj0gMSAmJiBpbnB1dC5tb250aCA8PSAxMiwgXCJBcmd1bWVudC5Nb250aFwiLCBcImludmFsaWQgbW9udGggXCIuY29uY2F0KGlucHV0Lm1vbnRoKSk7XG4gICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKE51bWJlci5pc0ludGVnZXIoaW5wdXQuZGF5KSAmJiBpbnB1dC5kYXkgPj0gMSAmJiBpbnB1dC5kYXkgPD0gZGF5c0luTW9udGgoaW5wdXQueWVhciwgaW5wdXQubW9udGgpLCBcIkFyZ3VtZW50LkRheVwiLCBcImludmFsaWQgZGF5IFwiLmNvbmNhdChpbnB1dC5kYXkpKTtcbiAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkoTnVtYmVyLmlzSW50ZWdlcihpbnB1dC5ob3VyKSAmJiBpbnB1dC5ob3VyID49IDAgJiYgaW5wdXQuaG91ciA8PSAyMywgXCJBcmd1bWVudC5Ib3VyXCIsIFwiaW52YWxpZCBob3VyIFwiLmNvbmNhdChpbnB1dC5ob3VyKSk7XG4gICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKE51bWJlci5pc0ludGVnZXIoaW5wdXQubWludXRlKSAmJiBpbnB1dC5taW51dGUgPj0gMCAmJiBpbnB1dC5taW51dGUgPD0gNTksIFwiQXJndW1lbnQuTWludXRlXCIsIFwiaW52YWxpZCBtaW51dGUgXCIuY29uY2F0KGlucHV0Lm1pbnV0ZSkpO1xuICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KShOdW1iZXIuaXNJbnRlZ2VyKGlucHV0LnNlY29uZCkgJiYgaW5wdXQuc2Vjb25kID49IDAgJiYgaW5wdXQuc2Vjb25kIDw9IDU5LCBcIkFyZ3VtZW50LlNlY29uZFwiLCBcImludmFsaWQgc2Vjb25kIFwiLmNvbmNhdChpbnB1dC5zZWNvbmQpKTtcbiAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkoTnVtYmVyLmlzSW50ZWdlcihpbnB1dC5taWxsaSkgJiYgaW5wdXQubWlsbGkgPj0gMCAmJiBpbnB1dC5taWxsaSA8PSA5OTksIFwiQXJndW1lbnQuTWlsbGlcIiwgXCJpbnZhbGlkIG1pbGxpIFwiLmNvbmNhdChpbnB1dC5taWxsaSkpO1xuICAgIHJldHVybiBpbnB1dDtcbn1cbmZ1bmN0aW9uIHRpbWVUb1VuaXhOb0xlYXBTZWNzKGEsIG1vbnRoLCBkYXksIGhvdXIsIG1pbnV0ZSwgc2Vjb25kLCBtaWxsaSkge1xuICAgIHZhciBjb21wb25lbnRzID0gKHR5cGVvZiBhID09PSBcIm51bWJlclwiID8geyB5ZWFyOiBhLCBtb250aDogbW9udGgsIGRheTogZGF5LCBob3VyOiBob3VyLCBtaW51dGU6IG1pbnV0ZSwgc2Vjb25kOiBzZWNvbmQsIG1pbGxpOiBtaWxsaSB9IDogYSk7XG4gICAgdmFyIGlucHV0ID0gbm9ybWFsaXplVGltZUNvbXBvbmVudHMoY29tcG9uZW50cyk7XG4gICAgcmV0dXJuIGlucHV0Lm1pbGxpICsgMTAwMCAqIChpbnB1dC5zZWNvbmQgKyBpbnB1dC5taW51dGUgKiA2MCArIGlucHV0LmhvdXIgKiAzNjAwICsgZGF5T2ZZZWFyKGlucHV0LnllYXIsIGlucHV0Lm1vbnRoLCBpbnB1dC5kYXkpICogODY0MDAgK1xuICAgICAgICAoaW5wdXQueWVhciAtIDE5NzApICogMzE1MzYwMDAgKyBNYXRoLmZsb29yKChpbnB1dC55ZWFyIC0gMTk2OSkgLyA0KSAqIDg2NDAwIC1cbiAgICAgICAgTWF0aC5mbG9vcigoaW5wdXQueWVhciAtIDE5MDEpIC8gMTAwKSAqIDg2NDAwICsgTWF0aC5mbG9vcigoaW5wdXQueWVhciAtIDE5MDAgKyAyOTkpIC8gNDAwKSAqIDg2NDAwKTtcbn1cbmV4cG9ydHMudGltZVRvVW5peE5vTGVhcFNlY3MgPSB0aW1lVG9Vbml4Tm9MZWFwU2Vjcztcbi8qKlxuICogUmV0dXJuIHRoZSBkYXktb2Ytd2Vlay5cbiAqIFRoaXMgZG9lcyBOT1QgdGFrZSBsZWFwIHNlY29uZHMgaW50byBhY2NvdW50LlxuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LlVuaXhNaWxsaXMgZm9yIGludmFsaWQgYHVuaXhNaWxsaXNgIGFyZ3VtZW50XG4gKi9cbmZ1bmN0aW9uIHdlZWtEYXlOb0xlYXBTZWNzKHVuaXhNaWxsaXMpIHtcbiAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkoTnVtYmVyLmlzSW50ZWdlcih1bml4TWlsbGlzKSwgXCJBcmd1bWVudC5Vbml4TWlsbGlzXCIsIFwidW5peE1pbGxpcyBzaG91bGQgYmUgYW4gaW50ZWdlciBudW1iZXJcIik7XG4gICAgdmFyIGVwb2NoRGF5ID0gV2Vla0RheS5UaHVyc2RheTtcbiAgICB2YXIgZGF5cyA9IE1hdGguZmxvb3IodW5peE1pbGxpcyAvIDEwMDAgLyA4NjQwMCk7XG4gICAgcmV0dXJuIG1hdGgucG9zaXRpdmVNb2R1bG8oZXBvY2hEYXkgKyBkYXlzLCA3KTtcbn1cbmV4cG9ydHMud2Vla0RheU5vTGVhcFNlY3MgPSB3ZWVrRGF5Tm9MZWFwU2Vjcztcbi8qKlxuICogTi10aCBzZWNvbmQgaW4gdGhlIGRheSwgY291bnRpbmcgZnJvbSAwXG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuSG91ciBmb3IgaW52YWxpZCBob3VyXG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuTWludXRlIGZvciBpbnZhbGlkIG1pbnV0ZVxuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LlNlY29uZCBmb3IgaW52YWxpZCBzZWNvbmRcbiAqL1xuZnVuY3Rpb24gc2Vjb25kT2ZEYXkoaG91ciwgbWludXRlLCBzZWNvbmQpIHtcbiAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkoTnVtYmVyLmlzSW50ZWdlcihob3VyKSAmJiBob3VyID49IDAgJiYgaG91ciA8PSAyMywgXCJBcmd1bWVudC5Ib3VyXCIsIFwiaW52YWxpZCBob3VyIFwiLmNvbmNhdChob3VyKSk7XG4gICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKE51bWJlci5pc0ludGVnZXIobWludXRlKSAmJiBtaW51dGUgPj0gMCAmJiBtaW51dGUgPD0gNTksIFwiQXJndW1lbnQuTWludXRlXCIsIFwiaW52YWxpZCBtaW51dGUgXCIuY29uY2F0KG1pbnV0ZSkpO1xuICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KShOdW1iZXIuaXNJbnRlZ2VyKHNlY29uZCkgJiYgc2Vjb25kID49IDAgJiYgc2Vjb25kIDw9IDYxLCBcIkFyZ3VtZW50LlNlY29uZFwiLCBcImludmFsaWQgc2Vjb25kIFwiLmNvbmNhdChzZWNvbmQpKTtcbiAgICByZXR1cm4gKCgoaG91ciAqIDYwKSArIG1pbnV0ZSkgKiA2MCkgKyBzZWNvbmQ7XG59XG5leHBvcnRzLnNlY29uZE9mRGF5ID0gc2Vjb25kT2ZEYXk7XG4vKipcbiAqIEJhc2ljIHJlcHJlc2VudGF0aW9uIG9mIGEgZGF0ZSBhbmQgdGltZVxuICovXG52YXIgVGltZVN0cnVjdCA9IC8qKiBAY2xhc3MgKi8gKGZ1bmN0aW9uICgpIHtcbiAgICAvKipcbiAgICAgKiBDb25zdHJ1Y3RvciBpbXBsZW1lbnRhdGlvblxuICAgICAqL1xuICAgIGZ1bmN0aW9uIFRpbWVTdHJ1Y3QoYSkge1xuICAgICAgICBpZiAodHlwZW9mIGEgPT09IFwibnVtYmVyXCIpIHtcbiAgICAgICAgICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KShOdW1iZXIuaXNJbnRlZ2VyKGEpLCBcIkFyZ3VtZW50LlVuaXhNaWxsaXNcIiwgXCJpbnZhbGlkIHVuaXggbWlsbGlzIFwiLmNvbmNhdChhKSk7XG4gICAgICAgICAgICB0aGlzLl91bml4TWlsbGlzID0gYTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KSh0eXBlb2YgYSA9PT0gXCJvYmplY3RcIiAmJiBhICE9PSBudWxsLCBcIkFyZ3VtZW50LkNvbXBvbmVudHNcIiwgXCJpbnZhbGlkIGNvbXBvbmVudHMgb2JqZWN0XCIpO1xuICAgICAgICAgICAgdGhpcy5fY29tcG9uZW50cyA9IG5vcm1hbGl6ZVRpbWVDb21wb25lbnRzKGEpO1xuICAgICAgICB9XG4gICAgfVxuICAgIC8qKlxuICAgICAqIFJldHVybnMgYSBUaW1lU3RydWN0IGZyb20gdGhlIGdpdmVuIHllYXIsIG1vbnRoLCBkYXkgZXRjXG4gICAgICpcbiAgICAgKiBAcGFyYW0geWVhclx0WWVhciBlLmcuIDE5NzBcbiAgICAgKiBAcGFyYW0gbW9udGhcdE1vbnRoIDEtMTJcbiAgICAgKiBAcGFyYW0gZGF5XHREYXkgMS0zMVxuICAgICAqIEBwYXJhbSBob3VyXHRIb3VyIDAtMjNcbiAgICAgKiBAcGFyYW0gbWludXRlXHRNaW51dGUgMC01OVxuICAgICAqIEBwYXJhbSBzZWNvbmRcdFNlY29uZCAwLTU5IChubyBsZWFwIHNlY29uZHMpXG4gICAgICogQHBhcmFtIG1pbGxpXHRNaWxsaXNlY29uZCAwLTk5OVxuICAgICAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5ZZWFyIGZvciBpbnZhbGlkIHllYXJcbiAgICAgKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuTW9udGggZm9yIGludmFsaWQgbW9udGhcbiAgICAgKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuRGF5IGZvciBpbnZhbGlkIGRheSBvZiBtb250aFxuICAgICAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5Ib3VyIGZvciBpbnZhbGlkIGhvdXJcbiAgICAgKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuTWludXRlIGZvciBpbnZhbGlkIG1pbnV0ZVxuICAgICAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5TZWNvbmQgZm9yIGludmFsaWQgc2Vjb25kXG4gICAgICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50Lk1pbGxpIGZvciBpbnZhbGlkIG1pbGxpc2Vjb25kc1xuICAgICAqL1xuICAgIFRpbWVTdHJ1Y3QuZnJvbUNvbXBvbmVudHMgPSBmdW5jdGlvbiAoeWVhciwgbW9udGgsIGRheSwgaG91ciwgbWludXRlLCBzZWNvbmQsIG1pbGxpKSB7XG4gICAgICAgIHJldHVybiBuZXcgVGltZVN0cnVjdCh7IHllYXI6IHllYXIsIG1vbnRoOiBtb250aCwgZGF5OiBkYXksIGhvdXI6IGhvdXIsIG1pbnV0ZTogbWludXRlLCBzZWNvbmQ6IHNlY29uZCwgbWlsbGk6IG1pbGxpIH0pO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogQ3JlYXRlIGEgVGltZVN0cnVjdCBmcm9tIGEgbnVtYmVyIG9mIHVuaXggbWlsbGlzZWNvbmRzXG4gICAgICogKGJhY2t3YXJkIGNvbXBhdGliaWxpdHkpXG4gICAgICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LlVuaXhNaWxsaXMgZm9yIG5vbi1pbnRlZ2VyIG1pbGxpc2Vjb25kc1xuICAgICAqL1xuICAgIFRpbWVTdHJ1Y3QuZnJvbVVuaXggPSBmdW5jdGlvbiAodW5peE1pbGxpcykge1xuICAgICAgICByZXR1cm4gbmV3IFRpbWVTdHJ1Y3QodW5peE1pbGxpcyk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYSBUaW1lU3RydWN0IGZyb20gYSBKYXZhU2NyaXB0IGRhdGVcbiAgICAgKlxuICAgICAqIEBwYXJhbSBkXHRUaGUgZGF0ZVxuICAgICAqIEBwYXJhbSBkZiBXaGljaCBmdW5jdGlvbnMgdG8gdGFrZSAoZ2V0WCgpIG9yIGdldFVUQ1goKSlcbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBUaW1lU3RydWN0LmZyb21EYXRlID0gZnVuY3Rpb24gKGQsIGRmKSB7XG4gICAgICAgIGlmIChkZiA9PT0gamF2YXNjcmlwdF8xLkRhdGVGdW5jdGlvbnMuR2V0KSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3IFRpbWVTdHJ1Y3Qoe1xuICAgICAgICAgICAgICAgIHllYXI6IGQuZ2V0RnVsbFllYXIoKSwgbW9udGg6IGQuZ2V0TW9udGgoKSArIDEsIGRheTogZC5nZXREYXRlKCksXG4gICAgICAgICAgICAgICAgaG91cjogZC5nZXRIb3VycygpLCBtaW51dGU6IGQuZ2V0TWludXRlcygpLCBzZWNvbmQ6IGQuZ2V0U2Vjb25kcygpLCBtaWxsaTogZC5nZXRNaWxsaXNlY29uZHMoKVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3IFRpbWVTdHJ1Y3Qoe1xuICAgICAgICAgICAgICAgIHllYXI6IGQuZ2V0VVRDRnVsbFllYXIoKSwgbW9udGg6IGQuZ2V0VVRDTW9udGgoKSArIDEsIGRheTogZC5nZXRVVENEYXRlKCksXG4gICAgICAgICAgICAgICAgaG91cjogZC5nZXRVVENIb3VycygpLCBtaW51dGU6IGQuZ2V0VVRDTWludXRlcygpLCBzZWNvbmQ6IGQuZ2V0VVRDU2Vjb25kcygpLCBtaWxsaTogZC5nZXRVVENNaWxsaXNlY29uZHMoKVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFJldHVybnMgYSBUaW1lU3RydWN0IGZyb20gYW4gSVNPIDg2MDEgc3RyaW5nIFdJVEhPVVQgdGltZSB6b25lXG4gICAgICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LlMgaWYgYHNgIGlzIG5vdCBhIHByb3BlciBpc28gc3RyaW5nXG4gICAgICovXG4gICAgVGltZVN0cnVjdC5mcm9tU3RyaW5nID0gZnVuY3Rpb24gKHMpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHZhciB5ZWFyID0gMTk3MDtcbiAgICAgICAgICAgIHZhciBtb250aCA9IDE7XG4gICAgICAgICAgICB2YXIgZGF5ID0gMTtcbiAgICAgICAgICAgIHZhciBob3VyID0gMDtcbiAgICAgICAgICAgIHZhciBtaW51dGUgPSAwO1xuICAgICAgICAgICAgdmFyIHNlY29uZCA9IDA7XG4gICAgICAgICAgICB2YXIgZnJhY3Rpb25NaWxsaXMgPSAwO1xuICAgICAgICAgICAgdmFyIGxhc3RVbml0ID0gVGltZVVuaXQuWWVhcjtcbiAgICAgICAgICAgIC8vIHNlcGFyYXRlIGFueSBmcmFjdGlvbmFsIHBhcnRcbiAgICAgICAgICAgIHZhciBzcGxpdCA9IHMudHJpbSgpLnNwbGl0KFwiLlwiKTtcbiAgICAgICAgICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KShzcGxpdC5sZW5ndGggPj0gMSAmJiBzcGxpdC5sZW5ndGggPD0gMiwgXCJBcmd1bWVudC5TXCIsIFwiRW1wdHkgc3RyaW5nIG9yIG11bHRpcGxlIGRvdHMuXCIpO1xuICAgICAgICAgICAgLy8gcGFyc2UgbWFpbiBwYXJ0XG4gICAgICAgICAgICB2YXIgaXNCYXNpY0Zvcm1hdCA9IChzLmluZGV4T2YoXCItXCIpID09PSAtMSk7XG4gICAgICAgICAgICBpZiAoaXNCYXNpY0Zvcm1hdCkge1xuICAgICAgICAgICAgICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KShzcGxpdFswXS5tYXRjaCgvXigoXFxkKSspfChcXGRcXGRcXGRcXGRcXGRcXGRcXGRcXGRUKFxcZCkrKSQvKSwgXCJBcmd1bWVudC5TXCIsIFwiSVNPIHN0cmluZyBpbiBiYXNpYyBub3RhdGlvbiBtYXkgb25seSBjb250YWluIG51bWJlcnMgYmVmb3JlIHRoZSBmcmFjdGlvbmFsIHBhcnRcIik7XG4gICAgICAgICAgICAgICAgLy8gcmVtb3ZlIGFueSBcIlRcIiBzZXBhcmF0b3JcbiAgICAgICAgICAgICAgICBzcGxpdFswXSA9IHNwbGl0WzBdLnJlcGxhY2UoXCJUXCIsIFwiXCIpO1xuICAgICAgICAgICAgICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KShbNCwgOCwgMTAsIDEyLCAxNF0uaW5kZXhPZihzcGxpdFswXS5sZW5ndGgpICE9PSAtMSwgXCJBcmd1bWVudC5TXCIsIFwiUGFkZGluZyBvciByZXF1aXJlZCBjb21wb25lbnRzIGFyZSBtaXNzaW5nLiBOb3RlIHRoYXQgWVlZWU1NIGlzIG5vdCB2YWxpZCBwZXIgSVNPIDg2MDFcIik7XG4gICAgICAgICAgICAgICAgaWYgKHNwbGl0WzBdLmxlbmd0aCA+PSA0KSB7XG4gICAgICAgICAgICAgICAgICAgIHllYXIgPSBwYXJzZUludChzcGxpdFswXS5zdWJzdHIoMCwgNCksIDEwKTtcbiAgICAgICAgICAgICAgICAgICAgbGFzdFVuaXQgPSBUaW1lVW5pdC5ZZWFyO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoc3BsaXRbMF0ubGVuZ3RoID49IDgpIHtcbiAgICAgICAgICAgICAgICAgICAgbW9udGggPSBwYXJzZUludChzcGxpdFswXS5zdWJzdHIoNCwgMiksIDEwKTtcbiAgICAgICAgICAgICAgICAgICAgZGF5ID0gcGFyc2VJbnQoc3BsaXRbMF0uc3Vic3RyKDYsIDIpLCAxMCk7IC8vIG5vdGUgdGhhdCBZWVlZTU0gZm9ybWF0IGlzIGRpc2FsbG93ZWQgc28gaWYgbW9udGggaXMgcHJlc2VudCwgZGF5IGlzIHRvb1xuICAgICAgICAgICAgICAgICAgICBsYXN0VW5pdCA9IFRpbWVVbml0LkRheTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKHNwbGl0WzBdLmxlbmd0aCA+PSAxMCkge1xuICAgICAgICAgICAgICAgICAgICBob3VyID0gcGFyc2VJbnQoc3BsaXRbMF0uc3Vic3RyKDgsIDIpLCAxMCk7XG4gICAgICAgICAgICAgICAgICAgIGxhc3RVbml0ID0gVGltZVVuaXQuSG91cjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKHNwbGl0WzBdLmxlbmd0aCA+PSAxMikge1xuICAgICAgICAgICAgICAgICAgICBtaW51dGUgPSBwYXJzZUludChzcGxpdFswXS5zdWJzdHIoMTAsIDIpLCAxMCk7XG4gICAgICAgICAgICAgICAgICAgIGxhc3RVbml0ID0gVGltZVVuaXQuTWludXRlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoc3BsaXRbMF0ubGVuZ3RoID49IDE0KSB7XG4gICAgICAgICAgICAgICAgICAgIHNlY29uZCA9IHBhcnNlSW50KHNwbGl0WzBdLnN1YnN0cigxMiwgMiksIDEwKTtcbiAgICAgICAgICAgICAgICAgICAgbGFzdFVuaXQgPSBUaW1lVW5pdC5TZWNvbmQ7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKHNwbGl0WzBdLm1hdGNoKC9eXFxkXFxkXFxkXFxkKC1cXGRcXGQtXFxkXFxkKChUKT9cXGRcXGQoXFw6XFxkXFxkKDpcXGRcXGQpPyk/KT8pPyQvKSwgXCJBcmd1bWVudC5TXCIsIFwiSW52YWxpZCBJU08gc3RyaW5nXCIpO1xuICAgICAgICAgICAgICAgIHZhciBkYXRlQW5kVGltZSA9IFtdO1xuICAgICAgICAgICAgICAgIGlmIChzLmluZGV4T2YoXCJUXCIpICE9PSAtMSkge1xuICAgICAgICAgICAgICAgICAgICBkYXRlQW5kVGltZSA9IHNwbGl0WzBdLnNwbGl0KFwiVFwiKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSBpZiAocy5sZW5ndGggPiAxMCkge1xuICAgICAgICAgICAgICAgICAgICBkYXRlQW5kVGltZSA9IFtzcGxpdFswXS5zdWJzdHIoMCwgMTApLCBzcGxpdFswXS5zdWJzdHIoMTApXTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGRhdGVBbmRUaW1lID0gW3NwbGl0WzBdLCBcIlwiXTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKFs0LCAxMF0uaW5kZXhPZihkYXRlQW5kVGltZVswXS5sZW5ndGgpICE9PSAtMSwgXCJBcmd1bWVudC5TXCIsIFwiUGFkZGluZyBvciByZXF1aXJlZCBjb21wb25lbnRzIGFyZSBtaXNzaW5nLiBOb3RlIHRoYXQgWVlZWU1NIGlzIG5vdCB2YWxpZCBwZXIgSVNPIDg2MDFcIik7XG4gICAgICAgICAgICAgICAgaWYgKGRhdGVBbmRUaW1lWzBdLmxlbmd0aCA+PSA0KSB7XG4gICAgICAgICAgICAgICAgICAgIHllYXIgPSBwYXJzZUludChkYXRlQW5kVGltZVswXS5zdWJzdHIoMCwgNCksIDEwKTtcbiAgICAgICAgICAgICAgICAgICAgbGFzdFVuaXQgPSBUaW1lVW5pdC5ZZWFyO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoZGF0ZUFuZFRpbWVbMF0ubGVuZ3RoID49IDEwKSB7XG4gICAgICAgICAgICAgICAgICAgIG1vbnRoID0gcGFyc2VJbnQoZGF0ZUFuZFRpbWVbMF0uc3Vic3RyKDUsIDIpLCAxMCk7XG4gICAgICAgICAgICAgICAgICAgIGRheSA9IHBhcnNlSW50KGRhdGVBbmRUaW1lWzBdLnN1YnN0cig4LCAyKSwgMTApOyAvLyBub3RlIHRoYXQgWVlZWU1NIGZvcm1hdCBpcyBkaXNhbGxvd2VkIHNvIGlmIG1vbnRoIGlzIHByZXNlbnQsIGRheSBpcyB0b29cbiAgICAgICAgICAgICAgICAgICAgbGFzdFVuaXQgPSBUaW1lVW5pdC5EYXk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmIChkYXRlQW5kVGltZVsxXS5sZW5ndGggPj0gMikge1xuICAgICAgICAgICAgICAgICAgICBob3VyID0gcGFyc2VJbnQoZGF0ZUFuZFRpbWVbMV0uc3Vic3RyKDAsIDIpLCAxMCk7XG4gICAgICAgICAgICAgICAgICAgIGxhc3RVbml0ID0gVGltZVVuaXQuSG91cjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKGRhdGVBbmRUaW1lWzFdLmxlbmd0aCA+PSA1KSB7XG4gICAgICAgICAgICAgICAgICAgIG1pbnV0ZSA9IHBhcnNlSW50KGRhdGVBbmRUaW1lWzFdLnN1YnN0cigzLCAyKSwgMTApO1xuICAgICAgICAgICAgICAgICAgICBsYXN0VW5pdCA9IFRpbWVVbml0Lk1pbnV0ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKGRhdGVBbmRUaW1lWzFdLmxlbmd0aCA+PSA4KSB7XG4gICAgICAgICAgICAgICAgICAgIHNlY29uZCA9IHBhcnNlSW50KGRhdGVBbmRUaW1lWzFdLnN1YnN0cig2LCAyKSwgMTApO1xuICAgICAgICAgICAgICAgICAgICBsYXN0VW5pdCA9IFRpbWVVbml0LlNlY29uZDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBwYXJzZSBmcmFjdGlvbmFsIHBhcnRcbiAgICAgICAgICAgIGlmIChzcGxpdC5sZW5ndGggPiAxICYmIHNwbGl0WzFdLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICB2YXIgZnJhY3Rpb24gPSBwYXJzZUZsb2F0KFwiMC5cIiArIHNwbGl0WzFdKTtcbiAgICAgICAgICAgICAgICBzd2l0Y2ggKGxhc3RVbml0KSB7XG4gICAgICAgICAgICAgICAgICAgIGNhc2UgVGltZVVuaXQuWWVhcjpcbiAgICAgICAgICAgICAgICAgICAgICAgIGZyYWN0aW9uTWlsbGlzID0gZGF5c0luWWVhcih5ZWFyKSAqIDg2NDAwMDAwICogZnJhY3Rpb247XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgY2FzZSBUaW1lVW5pdC5EYXk6XG4gICAgICAgICAgICAgICAgICAgICAgICBmcmFjdGlvbk1pbGxpcyA9IDg2NDAwMDAwICogZnJhY3Rpb247XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgY2FzZSBUaW1lVW5pdC5Ib3VyOlxuICAgICAgICAgICAgICAgICAgICAgICAgZnJhY3Rpb25NaWxsaXMgPSAzNjAwMDAwICogZnJhY3Rpb247XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgY2FzZSBUaW1lVW5pdC5NaW51dGU6XG4gICAgICAgICAgICAgICAgICAgICAgICBmcmFjdGlvbk1pbGxpcyA9IDYwMDAwICogZnJhY3Rpb247XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgY2FzZSBUaW1lVW5pdC5TZWNvbmQ6XG4gICAgICAgICAgICAgICAgICAgICAgICBmcmFjdGlvbk1pbGxpcyA9IDEwMDAgKiBmcmFjdGlvbjtcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIGNvbWJpbmUgbWFpbiBhbmQgZnJhY3Rpb25hbCBwYXJ0XG4gICAgICAgICAgICB5ZWFyID0gbWF0aC5yb3VuZFN5bSh5ZWFyKTtcbiAgICAgICAgICAgIG1vbnRoID0gbWF0aC5yb3VuZFN5bShtb250aCk7XG4gICAgICAgICAgICBkYXkgPSBtYXRoLnJvdW5kU3ltKGRheSk7XG4gICAgICAgICAgICBob3VyID0gbWF0aC5yb3VuZFN5bShob3VyKTtcbiAgICAgICAgICAgIG1pbnV0ZSA9IG1hdGgucm91bmRTeW0obWludXRlKTtcbiAgICAgICAgICAgIHNlY29uZCA9IG1hdGgucm91bmRTeW0oc2Vjb25kKTtcbiAgICAgICAgICAgIHZhciB1bml4TWlsbGlzID0gdGltZVRvVW5peE5vTGVhcFNlY3MoeyB5ZWFyOiB5ZWFyLCBtb250aDogbW9udGgsIGRheTogZGF5LCBob3VyOiBob3VyLCBtaW51dGU6IG1pbnV0ZSwgc2Vjb25kOiBzZWNvbmQgfSk7XG4gICAgICAgICAgICB1bml4TWlsbGlzID0gbWF0aC5yb3VuZFN5bSh1bml4TWlsbGlzICsgZnJhY3Rpb25NaWxsaXMpO1xuICAgICAgICAgICAgcmV0dXJuIG5ldyBUaW1lU3RydWN0KHVuaXhNaWxsaXMpO1xuICAgICAgICB9XG4gICAgICAgIGNhdGNoIChlKSB7XG4gICAgICAgICAgICBpZiAoKDAsIGVycm9yXzEuZXJyb3JJcykoZSwgW1xuICAgICAgICAgICAgICAgIFwiQXJndW1lbnQuU1wiLCBcIkFyZ3VtZW50LlllYXJcIiwgXCJBcmd1bWVudC5Nb250aFwiLCBcIkFyZ3VtZW50LkRheVwiLCBcIkFyZ3VtZW50LkhvdXJcIixcbiAgICAgICAgICAgICAgICBcIkFyZ3VtZW50Lk1pbnV0ZVwiLCBcIkFyZ3VtZW50LlNlY29uZFwiLCBcIkFyZ3VtZW50Lk1pbGxpXCJcbiAgICAgICAgICAgIF0pKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICgwLCBlcnJvcl8xLnRocm93RXJyb3IpKFwiQXJndW1lbnQuU1wiLCBcIkludmFsaWQgSVNPIDg2MDEgc3RyaW5nOiBcXFwiXCIuY29uY2F0KHMsIFwiXFxcIjogXCIpLmNvbmNhdChlLm1lc3NhZ2UpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIHRocm93IGU7IC8vIHByb2dyYW1taW5nIGVycm9yXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9O1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShUaW1lU3RydWN0LnByb3RvdHlwZSwgXCJ1bml4TWlsbGlzXCIsIHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5fdW5peE1pbGxpcyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5fdW5peE1pbGxpcyA9IHRpbWVUb1VuaXhOb0xlYXBTZWNzKHRoaXMuX2NvbXBvbmVudHMpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3VuaXhNaWxsaXM7XG4gICAgICAgIH0sXG4gICAgICAgIGVudW1lcmFibGU6IGZhbHNlLFxuICAgICAgICBjb25maWd1cmFibGU6IHRydWVcbiAgICB9KTtcbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoVGltZVN0cnVjdC5wcm90b3R5cGUsIFwiY29tcG9uZW50c1wiLCB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgaWYgKCF0aGlzLl9jb21wb25lbnRzKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5fY29tcG9uZW50cyA9IHVuaXhUb1RpbWVOb0xlYXBTZWNzKHRoaXMuX3VuaXhNaWxsaXMpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2NvbXBvbmVudHM7XG4gICAgICAgIH0sXG4gICAgICAgIGVudW1lcmFibGU6IGZhbHNlLFxuICAgICAgICBjb25maWd1cmFibGU6IHRydWVcbiAgICB9KTtcbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoVGltZVN0cnVjdC5wcm90b3R5cGUsIFwieWVhclwiLCB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuY29tcG9uZW50cy55ZWFyO1xuICAgICAgICB9LFxuICAgICAgICBlbnVtZXJhYmxlOiBmYWxzZSxcbiAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlXG4gICAgfSk7XG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KFRpbWVTdHJ1Y3QucHJvdG90eXBlLCBcIm1vbnRoXCIsIHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5jb21wb25lbnRzLm1vbnRoO1xuICAgICAgICB9LFxuICAgICAgICBlbnVtZXJhYmxlOiBmYWxzZSxcbiAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlXG4gICAgfSk7XG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KFRpbWVTdHJ1Y3QucHJvdG90eXBlLCBcImRheVwiLCB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuY29tcG9uZW50cy5kYXk7XG4gICAgICAgIH0sXG4gICAgICAgIGVudW1lcmFibGU6IGZhbHNlLFxuICAgICAgICBjb25maWd1cmFibGU6IHRydWVcbiAgICB9KTtcbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoVGltZVN0cnVjdC5wcm90b3R5cGUsIFwiaG91clwiLCB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuY29tcG9uZW50cy5ob3VyO1xuICAgICAgICB9LFxuICAgICAgICBlbnVtZXJhYmxlOiBmYWxzZSxcbiAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlXG4gICAgfSk7XG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KFRpbWVTdHJ1Y3QucHJvdG90eXBlLCBcIm1pbnV0ZVwiLCB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuY29tcG9uZW50cy5taW51dGU7XG4gICAgICAgIH0sXG4gICAgICAgIGVudW1lcmFibGU6IGZhbHNlLFxuICAgICAgICBjb25maWd1cmFibGU6IHRydWVcbiAgICB9KTtcbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoVGltZVN0cnVjdC5wcm90b3R5cGUsIFwic2Vjb25kXCIsIHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5jb21wb25lbnRzLnNlY29uZDtcbiAgICAgICAgfSxcbiAgICAgICAgZW51bWVyYWJsZTogZmFsc2UsXG4gICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZVxuICAgIH0pO1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShUaW1lU3RydWN0LnByb3RvdHlwZSwgXCJtaWxsaVwiLCB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuY29tcG9uZW50cy5taWxsaTtcbiAgICAgICAgfSxcbiAgICAgICAgZW51bWVyYWJsZTogZmFsc2UsXG4gICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZVxuICAgIH0pO1xuICAgIC8qKlxuICAgICAqIFRoZSBkYXktb2YteWVhciAwLTM2NVxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIFRpbWVTdHJ1Y3QucHJvdG90eXBlLnllYXJEYXkgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBkYXlPZlllYXIodGhpcy5jb21wb25lbnRzLnllYXIsIHRoaXMuY29tcG9uZW50cy5tb250aCwgdGhpcy5jb21wb25lbnRzLmRheSk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBFcXVhbGl0eSBmdW5jdGlvblxuICAgICAqIEBwYXJhbSBvdGhlclxuICAgICAqIEB0aHJvd3MgVHlwZUVycm9yIGlmIG90aGVyIGlzIG5vdCBhbiBPYmplY3RcbiAgICAgKi9cbiAgICBUaW1lU3RydWN0LnByb3RvdHlwZS5lcXVhbHMgPSBmdW5jdGlvbiAob3RoZXIpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMudmFsdWVPZigpID09PSBvdGhlci52YWx1ZU9mKCk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBUaW1lU3RydWN0LnByb3RvdHlwZS52YWx1ZU9mID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy51bml4TWlsbGlzO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgVGltZVN0cnVjdC5wcm90b3R5cGUuY2xvbmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICh0aGlzLl9jb21wb25lbnRzKSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3IFRpbWVTdHJ1Y3QodGhpcy5fY29tcG9uZW50cyk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3IFRpbWVTdHJ1Y3QodGhpcy5fdW5peE1pbGxpcyk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFZhbGlkYXRlIGEgdGltZXN0YW1wLiBGaWx0ZXJzIG91dCBub24tZXhpc3RpbmcgdmFsdWVzIGZvciBhbGwgdGltZSBjb21wb25lbnRzXG4gICAgICogQHJldHVybnMgdHJ1ZSBpZmYgdGhlIHRpbWVzdGFtcCBpcyB2YWxpZFxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIFRpbWVTdHJ1Y3QucHJvdG90eXBlLnZhbGlkYXRlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAodGhpcy5fY29tcG9uZW50cykge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuY29tcG9uZW50cy5tb250aCA+PSAxICYmIHRoaXMuY29tcG9uZW50cy5tb250aCA8PSAxMlxuICAgICAgICAgICAgICAgICYmIHRoaXMuY29tcG9uZW50cy5kYXkgPj0gMSAmJiB0aGlzLmNvbXBvbmVudHMuZGF5IDw9IGRheXNJbk1vbnRoKHRoaXMuY29tcG9uZW50cy55ZWFyLCB0aGlzLmNvbXBvbmVudHMubW9udGgpXG4gICAgICAgICAgICAgICAgJiYgdGhpcy5jb21wb25lbnRzLmhvdXIgPj0gMCAmJiB0aGlzLmNvbXBvbmVudHMuaG91ciA8PSAyM1xuICAgICAgICAgICAgICAgICYmIHRoaXMuY29tcG9uZW50cy5taW51dGUgPj0gMCAmJiB0aGlzLmNvbXBvbmVudHMubWludXRlIDw9IDU5XG4gICAgICAgICAgICAgICAgJiYgdGhpcy5jb21wb25lbnRzLnNlY29uZCA+PSAwICYmIHRoaXMuY29tcG9uZW50cy5zZWNvbmQgPD0gNTlcbiAgICAgICAgICAgICAgICAmJiB0aGlzLmNvbXBvbmVudHMubWlsbGkgPj0gMCAmJiB0aGlzLmNvbXBvbmVudHMubWlsbGkgPD0gOTk5O1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIC8qKlxuICAgICAqIElTTyA4NjAxIHN0cmluZyBZWVlZLU1NLUREVGhoOm1tOnNzLm5ublxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIFRpbWVTdHJ1Y3QucHJvdG90eXBlLnRvU3RyaW5nID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gc3RyaW5ncy5wYWRMZWZ0KHRoaXMuY29tcG9uZW50cy55ZWFyLnRvU3RyaW5nKDEwKSwgNCwgXCIwXCIpXG4gICAgICAgICAgICArIFwiLVwiICsgc3RyaW5ncy5wYWRMZWZ0KHRoaXMuY29tcG9uZW50cy5tb250aC50b1N0cmluZygxMCksIDIsIFwiMFwiKVxuICAgICAgICAgICAgKyBcIi1cIiArIHN0cmluZ3MucGFkTGVmdCh0aGlzLmNvbXBvbmVudHMuZGF5LnRvU3RyaW5nKDEwKSwgMiwgXCIwXCIpXG4gICAgICAgICAgICArIFwiVFwiICsgc3RyaW5ncy5wYWRMZWZ0KHRoaXMuY29tcG9uZW50cy5ob3VyLnRvU3RyaW5nKDEwKSwgMiwgXCIwXCIpXG4gICAgICAgICAgICArIFwiOlwiICsgc3RyaW5ncy5wYWRMZWZ0KHRoaXMuY29tcG9uZW50cy5taW51dGUudG9TdHJpbmcoMTApLCAyLCBcIjBcIilcbiAgICAgICAgICAgICsgXCI6XCIgKyBzdHJpbmdzLnBhZExlZnQodGhpcy5jb21wb25lbnRzLnNlY29uZC50b1N0cmluZygxMCksIDIsIFwiMFwiKVxuICAgICAgICAgICAgKyBcIi5cIiArIHN0cmluZ3MucGFkTGVmdCh0aGlzLmNvbXBvbmVudHMubWlsbGkudG9TdHJpbmcoMTApLCAzLCBcIjBcIik7XG4gICAgfTtcbiAgICByZXR1cm4gVGltZVN0cnVjdDtcbn0oKSk7XG5leHBvcnRzLlRpbWVTdHJ1Y3QgPSBUaW1lU3RydWN0O1xuLyoqXG4gKiBCaW5hcnkgc2VhcmNoXG4gKiBAcGFyYW0gYXJyYXkgQXJyYXkgdG8gc2VhcmNoXG4gKiBAcGFyYW0gY29tcGFyZSBGdW5jdGlvbiB0aGF0IHNob3VsZCByZXR1cm4gPCAwIGlmIGdpdmVuIGVsZW1lbnQgaXMgbGVzcyB0aGFuIHNlYXJjaGVkIGVsZW1lbnQgZXRjXG4gKiBAcmV0dXJucyBUaGUgaW5zZXJ0aW9uIGluZGV4IG9mIHRoZSBlbGVtZW50IHRvIGxvb2sgZm9yXG4gKiBAdGhyb3dzIFR5cGVFcnJvciBpZiBhcnIgaXMgbm90IGFuIGFycmF5XG4gKiBAdGhyb3dzIHdoYXRldmVyIGBjb21wYXJlKClgIHRocm93c1xuICovXG5mdW5jdGlvbiBiaW5hcnlJbnNlcnRpb25JbmRleChhcnIsIGNvbXBhcmUpIHtcbiAgICB2YXIgbWluSW5kZXggPSAwO1xuICAgIHZhciBtYXhJbmRleCA9IGFyci5sZW5ndGggLSAxO1xuICAgIHZhciBjdXJyZW50SW5kZXg7XG4gICAgdmFyIGN1cnJlbnRFbGVtZW50O1xuICAgIC8vIG5vIGFycmF5IC8gZW1wdHkgYXJyYXlcbiAgICBpZiAoIWFycikge1xuICAgICAgICByZXR1cm4gMDtcbiAgICB9XG4gICAgaWYgKGFyci5sZW5ndGggPT09IDApIHtcbiAgICAgICAgcmV0dXJuIDA7XG4gICAgfVxuICAgIC8vIG91dCBvZiBib3VuZHNcbiAgICBpZiAoY29tcGFyZShhcnJbMF0pID4gMCkge1xuICAgICAgICByZXR1cm4gMDtcbiAgICB9XG4gICAgaWYgKGNvbXBhcmUoYXJyW21heEluZGV4XSkgPCAwKSB7XG4gICAgICAgIHJldHVybiBtYXhJbmRleCArIDE7XG4gICAgfVxuICAgIC8vIGVsZW1lbnQgaW4gcmFuZ2VcbiAgICB3aGlsZSAobWluSW5kZXggPD0gbWF4SW5kZXgpIHtcbiAgICAgICAgY3VycmVudEluZGV4ID0gTWF0aC5mbG9vcigobWluSW5kZXggKyBtYXhJbmRleCkgLyAyKTtcbiAgICAgICAgY3VycmVudEVsZW1lbnQgPSBhcnJbY3VycmVudEluZGV4XTtcbiAgICAgICAgaWYgKGNvbXBhcmUoY3VycmVudEVsZW1lbnQpIDwgMCkge1xuICAgICAgICAgICAgbWluSW5kZXggPSBjdXJyZW50SW5kZXggKyAxO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKGNvbXBhcmUoY3VycmVudEVsZW1lbnQpID4gMCkge1xuICAgICAgICAgICAgbWF4SW5kZXggPSBjdXJyZW50SW5kZXggLSAxO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIGN1cnJlbnRJbmRleDtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gbWF4SW5kZXg7XG59XG5leHBvcnRzLmJpbmFyeUluc2VydGlvbkluZGV4ID0gYmluYXJ5SW5zZXJ0aW9uSW5kZXg7XG4vLyMgc291cmNlTWFwcGluZ1VSTD1iYXNpY3MuanMubWFwIiwiLyoqXG4gKiBDb3B5cmlnaHQoYykgMjAxNCBBQkIgU3dpdHplcmxhbmQgTHRkLlxuICpcbiAqIERhdGUrdGltZSt0aW1lem9uZSByZXByZXNlbnRhdGlvblxuICovXG5cInVzZSBzdHJpY3RcIjtcbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIl9fZXNNb2R1bGVcIiwgeyB2YWx1ZTogdHJ1ZSB9KTtcbmV4cG9ydHMuaXNEYXRlVGltZSA9IGV4cG9ydHMuRGF0ZVRpbWUgPSBleHBvcnRzLm5vdyA9IGV4cG9ydHMubm93VXRjID0gZXhwb3J0cy5ub3dMb2NhbCA9IHZvaWQgMDtcbnZhciBhc3NlcnRfMSA9IHJlcXVpcmUoXCIuL2Fzc2VydFwiKTtcbnZhciBiYXNpY3MgPSByZXF1aXJlKFwiLi9iYXNpY3NcIik7XG52YXIgYmFzaWNzXzEgPSByZXF1aXJlKFwiLi9iYXNpY3NcIik7XG52YXIgZHVyYXRpb25fMSA9IHJlcXVpcmUoXCIuL2R1cmF0aW9uXCIpO1xudmFyIGVycm9yXzEgPSByZXF1aXJlKFwiLi9lcnJvclwiKTtcbnZhciBmb3JtYXQgPSByZXF1aXJlKFwiLi9mb3JtYXRcIik7XG52YXIgamF2YXNjcmlwdF8xID0gcmVxdWlyZShcIi4vamF2YXNjcmlwdFwiKTtcbnZhciBtYXRoID0gcmVxdWlyZShcIi4vbWF0aFwiKTtcbnZhciBwYXJzZUZ1bmNzID0gcmVxdWlyZShcIi4vcGFyc2VcIik7XG52YXIgdGltZXNvdXJjZV8xID0gcmVxdWlyZShcIi4vdGltZXNvdXJjZVwiKTtcbnZhciB0aW1lem9uZV8xID0gcmVxdWlyZShcIi4vdGltZXpvbmVcIik7XG52YXIgdHpfZGF0YWJhc2VfMSA9IHJlcXVpcmUoXCIuL3R6LWRhdGFiYXNlXCIpO1xuLyoqXG4gKiBDdXJyZW50IGRhdGUrdGltZSBpbiBsb2NhbCB0aW1lXG4gKiBAdGhyb3dzIG5vdGhpbmdcbiAqL1xuZnVuY3Rpb24gbm93TG9jYWwoKSB7XG4gICAgcmV0dXJuIERhdGVUaW1lLm5vd0xvY2FsKCk7XG59XG5leHBvcnRzLm5vd0xvY2FsID0gbm93TG9jYWw7XG4vKipcbiAqIEN1cnJlbnQgZGF0ZSt0aW1lIGluIFVUQyB0aW1lXG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuTm90Rm91bmQuWm9uZSBpZiB0aGUgVVRDIHRpbWUgem9uZSBkb2Vzbid0IGV4aXN0IGluIHRoZSB0aW1lIHpvbmUgZGF0YWJhc2VcbiAqL1xuZnVuY3Rpb24gbm93VXRjKCkge1xuICAgIHJldHVybiBEYXRlVGltZS5ub3dVdGMoKTtcbn1cbmV4cG9ydHMubm93VXRjID0gbm93VXRjO1xuLyoqXG4gKiBDdXJyZW50IGRhdGUrdGltZSBpbiB0aGUgZ2l2ZW4gdGltZSB6b25lXG4gKiBAcGFyYW0gdGltZVpvbmVcdFRoZSBkZXNpcmVkIHRpbWUgem9uZSAob3B0aW9uYWwsIGRlZmF1bHRzIHRvIFVUQykuXG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuTm90Rm91bmQuWm9uZSBpZiB0aGUgVVRDIHRpbWUgem9uZSBkb2Vzbid0IGV4aXN0IGluIHRoZSB0aW1lIHpvbmUgZGF0YWJhc2VcbiAqL1xuZnVuY3Rpb24gbm93KHRpbWVab25lKSB7XG4gICAgaWYgKHRpbWVab25lID09PSB2b2lkIDApIHsgdGltZVpvbmUgPSB0aW1lem9uZV8xLlRpbWVab25lLnV0YygpOyB9XG4gICAgcmV0dXJuIERhdGVUaW1lLm5vdyh0aW1lWm9uZSk7XG59XG5leHBvcnRzLm5vdyA9IG5vdztcbi8qKlxuICpcbiAqIEBwYXJhbSBsb2NhbFRpbWVcbiAqIEBwYXJhbSBmcm9tWm9uZVxuICogQHRocm93cyBub3RoaW5nXG4gKi9cbmZ1bmN0aW9uIGNvbnZlcnRUb1V0Yyhsb2NhbFRpbWUsIGZyb21ab25lKSB7XG4gICAgaWYgKGZyb21ab25lKSB7XG4gICAgICAgIHZhciBvZmZzZXQgPSBmcm9tWm9uZS5vZmZzZXRGb3Jab25lKGxvY2FsVGltZSk7XG4gICAgICAgIHJldHVybiBuZXcgYmFzaWNzXzEuVGltZVN0cnVjdChsb2NhbFRpbWUudW5peE1pbGxpcyAtIG9mZnNldCAqIDYwMDAwKTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHJldHVybiBsb2NhbFRpbWUuY2xvbmUoKTtcbiAgICB9XG59XG4vKipcbiAqXG4gKiBAcGFyYW0gdXRjVGltZVxuICogQHBhcmFtIHRvWm9uZVxuICogQHRocm93cyBub3RoaW5nXG4gKi9cbmZ1bmN0aW9uIGNvbnZlcnRGcm9tVXRjKHV0Y1RpbWUsIHRvWm9uZSkge1xuICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBlbHNlICovXG4gICAgaWYgKHRvWm9uZSkge1xuICAgICAgICB2YXIgb2Zmc2V0ID0gdG9ab25lLm9mZnNldEZvclV0Yyh1dGNUaW1lKTtcbiAgICAgICAgcmV0dXJuIHRvWm9uZS5ub3JtYWxpemVab25lVGltZShuZXcgYmFzaWNzXzEuVGltZVN0cnVjdCh1dGNUaW1lLnVuaXhNaWxsaXMgKyBvZmZzZXQgKiA2MDAwMCkpO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgcmV0dXJuIHV0Y1RpbWUuY2xvbmUoKTtcbiAgICB9XG59XG4vKipcbiAqIERhdGVUaW1lIGNsYXNzIHdoaWNoIGlzIHRpbWUgem9uZS1hd2FyZVxuICogYW5kIHdoaWNoIGNhbiBiZSBtb2NrZWQgZm9yIHRlc3RpbmcgcHVycG9zZXMuXG4gKi9cbnZhciBEYXRlVGltZSA9IC8qKiBAY2xhc3MgKi8gKGZ1bmN0aW9uICgpIHtcbiAgICAvKipcbiAgICAgKiBDb25zdHJ1Y3RvciBpbXBsZW1lbnRhdGlvbiwgQHNlZSBvdmVycmlkZXNcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBEYXRlVGltZShhMSwgYTIsIGEzLCBoLCBtLCBzLCBtcywgdGltZVpvbmUpIHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEFsbG93IG5vdCB1c2luZyBpbnN0YW5jZW9mXG4gICAgICAgICAqL1xuICAgICAgICB0aGlzLmtpbmQgPSBcIkRhdGVUaW1lXCI7XG4gICAgICAgIHN3aXRjaCAodHlwZW9mIChhMSkpIHtcbiAgICAgICAgICAgIGNhc2UgXCJudW1iZXJcIjpcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgYTIgIT09IFwibnVtYmVyXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KShhMyA9PT0gdW5kZWZpbmVkICYmIGggPT09IHVuZGVmaW5lZCAmJiBtID09PSB1bmRlZmluZWRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAmJiBzID09PSB1bmRlZmluZWQgJiYgbXMgPT09IHVuZGVmaW5lZCAmJiB0aW1lWm9uZSA9PT0gdW5kZWZpbmVkLCBcIkFyZ3VtZW50LkEzXCIsIFwiZm9yIHVuaXggdGltZXN0YW1wIGRhdGV0aW1lIGNvbnN0cnVjdG9yLCB0aGlyZCB0aHJvdWdoIDh0aCBhcmd1bWVudCBtdXN0IGJlIHVuZGVmaW5lZFwiKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KShhMiA9PT0gdW5kZWZpbmVkIHx8IGEyID09PSBudWxsIHx8IGlzVGltZVpvbmUoYTIpLCBcIkFyZ3VtZW50LlRpbWVab25lXCIsIFwiRGF0ZVRpbWUuRGF0ZVRpbWUoKTogc2Vjb25kIGFyZyBzaG91bGQgYmUgYSBUaW1lWm9uZSBvYmplY3QuXCIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gdW5peCB0aW1lc3RhbXAgY29uc3RydWN0b3JcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuX3pvbmUgPSAodHlwZW9mIChhMikgPT09IFwib2JqZWN0XCIgJiYgaXNUaW1lWm9uZShhMikgPyBhMiA6IHVuZGVmaW5lZCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgdW5peE1pbGxpcyA9ICgwLCBlcnJvcl8xLmNvbnZlcnRFcnJvcikoXCJBcmd1bWVudC5Vbml4TWlsbGlzXCIsIGZ1bmN0aW9uICgpIHsgcmV0dXJuIG1hdGgucm91bmRTeW0oYTEpOyB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLl96b25lKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5fem9uZURhdGUgPSB0aGlzLl96b25lLm5vcm1hbGl6ZVpvbmVUaW1lKG5ldyBiYXNpY3NfMS5UaW1lU3RydWN0KHVuaXhNaWxsaXMpKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuX3pvbmVEYXRlID0gbmV3IGJhc2ljc18xLlRpbWVTdHJ1Y3QodW5peE1pbGxpcyk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyB5ZWFyIG1vbnRoIGRheSBjb25zdHJ1Y3RvclxuICAgICAgICAgICAgICAgICAgICAgICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKHR5cGVvZiAoYTIpID09PSBcIm51bWJlclwiLCBcIkFyZ3VtZW50LlllYXJcIiwgXCJEYXRlVGltZS5EYXRlVGltZSgpOiBFeHBlY3QgbW9udGggdG8gYmUgYSBudW1iZXIuXCIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKHR5cGVvZiAoYTMpID09PSBcIm51bWJlclwiLCBcIkFyZ3VtZW50Lk1vbnRoXCIsIFwiRGF0ZVRpbWUuRGF0ZVRpbWUoKTogRXhwZWN0IGRheSB0byBiZSBhIG51bWJlci5cIik7XG4gICAgICAgICAgICAgICAgICAgICAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkodGltZVpvbmUgPT09IHVuZGVmaW5lZCB8fCB0aW1lWm9uZSA9PT0gbnVsbCB8fCBpc1RpbWVab25lKHRpbWVab25lKSwgXCJBcmd1bWVudC5UaW1lWm9uZVwiLCBcIkRhdGVUaW1lLkRhdGVUaW1lKCk6IGVpZ2h0aCBhcmcgc2hvdWxkIGJlIGEgVGltZVpvbmUgb2JqZWN0LlwiKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciB5ZWFyXzEgPSBhMTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBtb250aF8xID0gYTI7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgZGF5XzEgPSBhMztcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBob3VyXzEgPSAodHlwZW9mIChoKSA9PT0gXCJudW1iZXJcIiA/IGggOiAwKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBtaW51dGVfMSA9ICh0eXBlb2YgKG0pID09PSBcIm51bWJlclwiID8gbSA6IDApO1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHNlY29uZF8xID0gKHR5cGVvZiAocykgPT09IFwibnVtYmVyXCIgPyBzIDogMCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgbWlsbGlfMSA9ICh0eXBlb2YgKG1zKSA9PT0gXCJudW1iZXJcIiA/IG1zIDogMCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB5ZWFyXzEgPSAoMCwgZXJyb3JfMS5jb252ZXJ0RXJyb3IpKFwiQXJndW1lbnQuWWVhclwiLCBmdW5jdGlvbiAoKSB7IHJldHVybiBtYXRoLnJvdW5kU3ltKHllYXJfMSk7IH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgbW9udGhfMSA9ICgwLCBlcnJvcl8xLmNvbnZlcnRFcnJvcikoXCJBcmd1bWVudC5Nb250aFwiLCBmdW5jdGlvbiAoKSB7IHJldHVybiBtYXRoLnJvdW5kU3ltKG1vbnRoXzEpOyB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGRheV8xID0gKDAsIGVycm9yXzEuY29udmVydEVycm9yKShcIkFyZ3VtZW50LkRheVwiLCBmdW5jdGlvbiAoKSB7IHJldHVybiBtYXRoLnJvdW5kU3ltKGRheV8xKTsgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBob3VyXzEgPSAoMCwgZXJyb3JfMS5jb252ZXJ0RXJyb3IpKFwiQXJndW1lbnQuSG91clwiLCBmdW5jdGlvbiAoKSB7IHJldHVybiBtYXRoLnJvdW5kU3ltKGhvdXJfMSk7IH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgbWludXRlXzEgPSAoMCwgZXJyb3JfMS5jb252ZXJ0RXJyb3IpKFwiQXJndW1lbnQuTWludXRlXCIsIGZ1bmN0aW9uICgpIHsgcmV0dXJuIG1hdGgucm91bmRTeW0obWludXRlXzEpOyB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlY29uZF8xID0gKDAsIGVycm9yXzEuY29udmVydEVycm9yKShcIkFyZ3VtZW50LlNlY29uZFwiLCBmdW5jdGlvbiAoKSB7IHJldHVybiBtYXRoLnJvdW5kU3ltKHNlY29uZF8xKTsgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBtaWxsaV8xID0gKDAsIGVycm9yXzEuY29udmVydEVycm9yKShcIkFyZ3VtZW50Lk1pbGxpXCIsIGZ1bmN0aW9uICgpIHsgcmV0dXJuIG1hdGgucm91bmRTeW0obWlsbGlfMSk7IH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHRtID0gbmV3IGJhc2ljc18xLlRpbWVTdHJ1Y3QoeyB5ZWFyOiB5ZWFyXzEsIG1vbnRoOiBtb250aF8xLCBkYXk6IGRheV8xLCBob3VyOiBob3VyXzEsIG1pbnV0ZTogbWludXRlXzEsIHNlY29uZDogc2Vjb25kXzEsIG1pbGxpOiBtaWxsaV8xIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5fem9uZSA9ICh0eXBlb2YgKHRpbWVab25lKSA9PT0gXCJvYmplY3RcIiAmJiBpc1RpbWVab25lKHRpbWVab25lKSA/IHRpbWVab25lIDogdW5kZWZpbmVkKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIG5vcm1hbGl6ZSBsb2NhbCB0aW1lIChyZW1vdmUgbm9uLWV4aXN0aW5nIGxvY2FsIHRpbWUpXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy5fem9uZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuX3pvbmVEYXRlID0gdGhpcy5fem9uZS5ub3JtYWxpemVab25lVGltZSh0bSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLl96b25lRGF0ZSA9IHRtO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBcInN0cmluZ1wiOlxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBhMiA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgICAgICAgICAgICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKGggPT09IHVuZGVmaW5lZCAmJiBtID09PSB1bmRlZmluZWRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAmJiBzID09PSB1bmRlZmluZWQgJiYgbXMgPT09IHVuZGVmaW5lZCAmJiB0aW1lWm9uZSA9PT0gdW5kZWZpbmVkLCBcIkFyZ3VtZW50LkE0XCIsIFwiZmlyc3QgdHdvIGFyZ3VtZW50cyBhcmUgYSBzdHJpbmcsIHRoZXJlZm9yZSB0aGUgZm91cnRoIHRocm91Z2ggOHRoIGFyZ3VtZW50IG11c3QgYmUgdW5kZWZpbmVkXCIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKGEzID09PSB1bmRlZmluZWQgfHwgYTMgPT09IG51bGwgfHwgaXNUaW1lWm9uZShhMyksIFwiQXJndW1lbnQuVGltZVpvbmVcIiwgXCJEYXRlVGltZS5EYXRlVGltZSgpOiB0aGlyZCBhcmcgc2hvdWxkIGJlIGEgVGltZVpvbmUgb2JqZWN0LlwiKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGZvcm1hdCBzdHJpbmcgZ2l2ZW5cbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBkYXRlU3RyaW5nID0gYTE7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgZm9ybWF0U3RyaW5nID0gYTI7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgem9uZSA9IHZvaWQgMDtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgYTMgPT09IFwib2JqZWN0XCIgJiYgaXNUaW1lWm9uZShhMykpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB6b25lID0gKGEzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBwYXJzZWQgPSBwYXJzZUZ1bmNzLnBhcnNlKGRhdGVTdHJpbmcsIGZvcm1hdFN0cmluZywgem9uZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLl96b25lRGF0ZSA9IHBhcnNlZC50aW1lO1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5fem9uZSA9IHBhcnNlZC56b25lO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKGEzID09PSB1bmRlZmluZWQgJiYgaCA9PT0gdW5kZWZpbmVkICYmIG0gPT09IHVuZGVmaW5lZFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICYmIHMgPT09IHVuZGVmaW5lZCAmJiBtcyA9PT0gdW5kZWZpbmVkICYmIHRpbWVab25lID09PSB1bmRlZmluZWQsIFwiQXJndW1lbnQuQTNcIiwgXCJmaXJzdCBhcmd1bWVudHMgaXMgYSBzdHJpbmcgYW5kIHRoZSBzZWNvbmQgaXMgbm90LCB0aGVyZWZvcmUgdGhlIHRoaXJkIHRocm91Z2ggOHRoIGFyZ3VtZW50IG11c3QgYmUgdW5kZWZpbmVkXCIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKGEyID09PSB1bmRlZmluZWQgfHwgYTIgPT09IG51bGwgfHwgaXNUaW1lWm9uZShhMiksIFwiQXJndW1lbnQuVGltZVpvbmVcIiwgXCJEYXRlVGltZS5EYXRlVGltZSgpOiBzZWNvbmQgYXJnIHNob3VsZCBiZSBhIFRpbWVab25lIG9iamVjdC5cIik7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgZ2l2ZW5TdHJpbmcgPSBhMS50cmltKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgc3MgPSBEYXRlVGltZS5fc3BsaXREYXRlRnJvbVRpbWVab25lKGdpdmVuU3RyaW5nKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KShzcy5sZW5ndGggPT09IDIsIFwiQXJndW1lbnQuU1wiLCBcIkludmFsaWQgZGF0ZSBzdHJpbmcgZ2l2ZW46IFxcXCJcIiArIGExICsgXCJcXFwiXCIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzVGltZVpvbmUoYTIpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5fem9uZSA9IChhMik7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLl96b25lID0gKHNzWzFdLnRyaW0oKSA/IHRpbWV6b25lXzEuVGltZVpvbmUuem9uZShzc1sxXSkgOiB1bmRlZmluZWQpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gdXNlIG91ciBvd24gSVNPIHBhcnNpbmcgYmVjYXVzZSB0aGF0IGl0IHBsYXRmb3JtIGluZGVwZW5kZW50XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAoZnJlZSBvZiBEYXRlIHF1aXJrcylcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuX3pvbmVEYXRlID0gYmFzaWNzXzEuVGltZVN0cnVjdC5mcm9tU3RyaW5nKHNzWzBdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLl96b25lKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5fem9uZURhdGUgPSB0aGlzLl96b25lLm5vcm1hbGl6ZVpvbmVUaW1lKHRoaXMuX3pvbmVEYXRlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgXCJvYmplY3RcIjpcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChhMSBpbnN0YW5jZW9mIERhdGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KShoID09PSB1bmRlZmluZWQgJiYgbSA9PT0gdW5kZWZpbmVkXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJiYgcyA9PT0gdW5kZWZpbmVkICYmIG1zID09PSB1bmRlZmluZWQgJiYgdGltZVpvbmUgPT09IHVuZGVmaW5lZCwgXCJBcmd1bWVudC5BNFwiLCBcImZpcnN0IGFyZ3VtZW50IGlzIGEgRGF0ZSwgdGhlcmVmb3JlIHRoZSBmb3VydGggdGhyb3VnaCA4dGggYXJndW1lbnQgbXVzdCBiZSB1bmRlZmluZWRcIik7XG4gICAgICAgICAgICAgICAgICAgICAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkodHlwZW9mIChhMikgPT09IFwibnVtYmVyXCIgJiYgKGEyID09PSBqYXZhc2NyaXB0XzEuRGF0ZUZ1bmN0aW9ucy5HZXQgfHwgYTIgPT09IGphdmFzY3JpcHRfMS5EYXRlRnVuY3Rpb25zLkdldFVUQyksIFwiQXJndW1lbnQuR2V0RnVuY3NcIiwgXCJEYXRlVGltZS5EYXRlVGltZSgpOiBmb3IgYSBEYXRlIG9iamVjdCBhIERhdGVGdW5jdGlvbnMgbXVzdCBiZSBwYXNzZWQgYXMgc2Vjb25kIGFyZ3VtZW50XCIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKGEzID09PSB1bmRlZmluZWQgfHwgYTMgPT09IG51bGwgfHwgaXNUaW1lWm9uZShhMyksIFwiQXJndW1lbnQuVGltZVpvbmVcIiwgXCJEYXRlVGltZS5EYXRlVGltZSgpOiB0aGlyZCBhcmcgc2hvdWxkIGJlIGEgVGltZVpvbmUgb2JqZWN0LlwiKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBkID0gKGExKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBkayA9IChhMik7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLl96b25lID0gKGEzID8gYTMgOiB1bmRlZmluZWQpO1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5fem9uZURhdGUgPSBiYXNpY3NfMS5UaW1lU3RydWN0LmZyb21EYXRlKGQsIGRrKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLl96b25lKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5fem9uZURhdGUgPSB0aGlzLl96b25lLm5vcm1hbGl6ZVpvbmVUaW1lKHRoaXMuX3pvbmVEYXRlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBlbHNlIHsgLy8gYTEgaW5zdGFuY2VvZiBUaW1lU3RydWN0XG4gICAgICAgICAgICAgICAgICAgICAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkoYTMgPT09IHVuZGVmaW5lZCAmJiBoID09PSB1bmRlZmluZWQgJiYgbSA9PT0gdW5kZWZpbmVkXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJiYgcyA9PT0gdW5kZWZpbmVkICYmIG1zID09PSB1bmRlZmluZWQgJiYgdGltZVpvbmUgPT09IHVuZGVmaW5lZCwgXCJBcmd1bWVudC5BM1wiLCBcImZpcnN0IGFyZ3VtZW50IGlzIGEgVGltZVN0cnVjdCwgdGhlcmVmb3JlIHRoZSB0aGlyZCB0aHJvdWdoIDh0aCBhcmd1bWVudCBtdXN0IGJlIHVuZGVmaW5lZFwiKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KShhMiA9PT0gdW5kZWZpbmVkIHx8IGEyID09PSBudWxsIHx8IGlzVGltZVpvbmUoYTIpLCBcIkFyZ3VtZW50LlRpbWVab25lXCIsIFwiZXhwZWN0IGEgVGltZVpvbmUgYXMgc2Vjb25kIGFyZ3VtZW50XCIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5fem9uZURhdGUgPSBhMS5jbG9uZSgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5fem9uZSA9IChhMiA/IGEyIDogdW5kZWZpbmVkKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgXCJ1bmRlZmluZWRcIjpcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KShhMiA9PT0gdW5kZWZpbmVkICYmIGEzID09PSB1bmRlZmluZWQgJiYgaCA9PT0gdW5kZWZpbmVkICYmIG0gPT09IHVuZGVmaW5lZFxuICAgICAgICAgICAgICAgICAgICAgICAgJiYgcyA9PT0gdW5kZWZpbmVkICYmIG1zID09PSB1bmRlZmluZWQgJiYgdGltZVpvbmUgPT09IHVuZGVmaW5lZCwgXCJBcmd1bWVudC5BMlwiLCBcImZpcnN0IGFyZ3VtZW50IGlzIHVuZGVmaW5lZCwgdGhlcmVmb3JlIHRoZSByZXN0IG11c3QgYWxzbyBiZSB1bmRlZmluZWRcIik7XG4gICAgICAgICAgICAgICAgICAgIC8vIG5vdGhpbmcgZ2l2ZW4sIG1ha2UgbG9jYWwgZGF0ZXRpbWVcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fem9uZSA9IHRpbWV6b25lXzEuVGltZVpvbmUubG9jYWwoKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fdXRjRGF0ZSA9IGJhc2ljc18xLlRpbWVTdHJ1Y3QuZnJvbURhdGUoRGF0ZVRpbWUudGltZVNvdXJjZS5ub3coKSwgamF2YXNjcmlwdF8xLkRhdGVGdW5jdGlvbnMuR2V0VVRDKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICAgICAgICAgIHRocm93ICgwLCBlcnJvcl8xLmVycm9yKShcIkFyZ3VtZW50LkExXCIsIFwiRGF0ZVRpbWUuRGF0ZVRpbWUoKTogdW5leHBlY3RlZCBmaXJzdCBhcmd1bWVudCB0eXBlLlwiKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoRGF0ZVRpbWUucHJvdG90eXBlLCBcInV0Y0RhdGVcIiwge1xuICAgICAgICAvKipcbiAgICAgICAgICogVVRDIHRpbWVzdGFtcCAobGF6aWx5IGNhbGN1bGF0ZWQpXG4gICAgICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAgICAgKi9cbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBpZiAoIXRoaXMuX3V0Y0RhdGUpIHtcbiAgICAgICAgICAgICAgICB0aGlzLl91dGNEYXRlID0gY29udmVydFRvVXRjKHRoaXMuX3pvbmVEYXRlLCB0aGlzLl96b25lKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB0aGlzLl91dGNEYXRlO1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICAgICAgdGhpcy5fdXRjRGF0ZSA9IHZhbHVlO1xuICAgICAgICAgICAgdGhpcy5fem9uZURhdGUgPSB1bmRlZmluZWQ7XG4gICAgICAgIH0sXG4gICAgICAgIGVudW1lcmFibGU6IGZhbHNlLFxuICAgICAgICBjb25maWd1cmFibGU6IHRydWVcbiAgICB9KTtcbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoRGF0ZVRpbWUucHJvdG90eXBlLCBcInpvbmVEYXRlXCIsIHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIExvY2FsIHRpbWVzdGFtcCAobGF6aWx5IGNhbGN1bGF0ZWQpXG4gICAgICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAgICAgKi9cbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBpZiAoIXRoaXMuX3pvbmVEYXRlKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5fem9uZURhdGUgPSBjb252ZXJ0RnJvbVV0Yyh0aGlzLl91dGNEYXRlLCB0aGlzLl96b25lKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB0aGlzLl96b25lRGF0ZTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMuX3pvbmVEYXRlID0gdmFsdWU7XG4gICAgICAgICAgICB0aGlzLl91dGNEYXRlID0gdW5kZWZpbmVkO1xuICAgICAgICB9LFxuICAgICAgICBlbnVtZXJhYmxlOiBmYWxzZSxcbiAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlXG4gICAgfSk7XG4gICAgLyoqXG4gICAgICogQ3VycmVudCBkYXRlK3RpbWUgaW4gbG9jYWwgdGltZVxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIERhdGVUaW1lLm5vd0xvY2FsID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgbiA9IERhdGVUaW1lLnRpbWVTb3VyY2Uubm93KCk7XG4gICAgICAgIHJldHVybiBuZXcgRGF0ZVRpbWUobiwgamF2YXNjcmlwdF8xLkRhdGVGdW5jdGlvbnMuR2V0LCB0aW1lem9uZV8xLlRpbWVab25lLmxvY2FsKCkpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogQ3VycmVudCBkYXRlK3RpbWUgaW4gVVRDIHRpbWVcbiAgICAgKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuTm90Rm91bmQuWm9uZSBpZiB0aGUgVVRDIHRpbWUgem9uZSBkb2Vzbid0IGV4aXN0IGluIHRoZSB0aW1lIHpvbmUgZGF0YWJhc2VcbiAgICAgKi9cbiAgICBEYXRlVGltZS5ub3dVdGMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBuZXcgRGF0ZVRpbWUoRGF0ZVRpbWUudGltZVNvdXJjZS5ub3coKSwgamF2YXNjcmlwdF8xLkRhdGVGdW5jdGlvbnMuR2V0VVRDLCB0aW1lem9uZV8xLlRpbWVab25lLnV0YygpKTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIEN1cnJlbnQgZGF0ZSt0aW1lIGluIHRoZSBnaXZlbiB0aW1lIHpvbmVcbiAgICAgKiBAcGFyYW0gdGltZVpvbmVcdFRoZSBkZXNpcmVkIHRpbWUgem9uZSAob3B0aW9uYWwsIGRlZmF1bHRzIHRvIFVUQykuXG4gICAgICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLk5vdEZvdW5kLlpvbmUgaWYgdGhlIFVUQyB0aW1lIHpvbmUgZG9lc24ndCBleGlzdCBpbiB0aGUgdGltZSB6b25lIGRhdGFiYXNlXG4gICAgICovXG4gICAgRGF0ZVRpbWUubm93ID0gZnVuY3Rpb24gKHRpbWVab25lKSB7XG4gICAgICAgIGlmICh0aW1lWm9uZSA9PT0gdm9pZCAwKSB7IHRpbWVab25lID0gdGltZXpvbmVfMS5UaW1lWm9uZS51dGMoKTsgfVxuICAgICAgICByZXR1cm4gbmV3IERhdGVUaW1lKERhdGVUaW1lLnRpbWVTb3VyY2Uubm93KCksIGphdmFzY3JpcHRfMS5EYXRlRnVuY3Rpb25zLkdldFVUQywgdGltZXpvbmVfMS5UaW1lWm9uZS51dGMoKSkudG9ab25lKHRpbWVab25lKTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIENyZWF0ZSBhIERhdGVUaW1lIGZyb20gYSBMb3R1cyAxMjMgLyBNaWNyb3NvZnQgRXhjZWwgZGF0ZS10aW1lIHZhbHVlXG4gICAgICogaS5lLiBhIGRvdWJsZSByZXByZXNlbnRpbmcgZGF5cyBzaW5jZSAxLTEtMTkwMCB3aGVyZSAxOTAwIGlzIGluY29ycmVjdGx5IHNlZW4gYXMgbGVhcCB5ZWFyXG4gICAgICogRG9lcyBub3Qgd29yayBmb3IgZGF0ZXMgPCAxOTAwXG4gICAgICogQHBhcmFtIG4gZXhjZWwgZGF0ZS90aW1lIG51bWJlclxuICAgICAqIEBwYXJhbSB0aW1lWm9uZSBUaW1lIHpvbmUgdG8gYXNzdW1lIHRoYXQgdGhlIGV4Y2VsIHZhbHVlIGlzIGluXG4gICAgICogQHJldHVybnMgYSBEYXRlVGltZVxuICAgICAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5OIGlmIG4gaXMgbm90IGEgZmluaXRlIG51bWJlclxuICAgICAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5UaW1lWm9uZSBpZiB0aGUgZ2l2ZW4gdGltZSB6b25lIGlzIGludmFsaWRcbiAgICAgKi9cbiAgICBEYXRlVGltZS5mcm9tRXhjZWwgPSBmdW5jdGlvbiAobiwgdGltZVpvbmUpIHtcbiAgICAgICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKE51bWJlci5pc0Zpbml0ZShuKSwgXCJBcmd1bWVudC5OXCIsIFwiaW52YWxpZCBudW1iZXJcIik7XG4gICAgICAgIHZhciB1bml4VGltZXN0YW1wID0gTWF0aC5yb3VuZCgobiAtIDI1NTY5KSAqIDI0ICogNjAgKiA2MCAqIDEwMDApO1xuICAgICAgICByZXR1cm4gbmV3IERhdGVUaW1lKHVuaXhUaW1lc3RhbXAsIHRpbWVab25lKTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIENoZWNrIHdoZXRoZXIgYSBnaXZlbiBkYXRlIGV4aXN0cyBpbiB0aGUgZ2l2ZW4gdGltZSB6b25lLlxuICAgICAqIEUuZy4gMjAxNS0wMi0yOSByZXR1cm5zIGZhbHNlIChub3QgYSBsZWFwIHllYXIpXG4gICAgICogYW5kIDIwMTUtMDMtMjlUMDI6MzA6MDAgcmV0dXJucyBmYWxzZSAoZGF5bGlnaHQgc2F2aW5nIHRpbWUgbWlzc2luZyBob3VyKVxuICAgICAqIGFuZCAyMDE1LTA0LTMxIHJldHVybnMgZmFsc2UgKEFwcmlsIGhhcyAzMCBkYXlzKS5cbiAgICAgKiBCeSBkZWZhdWx0LCBwcmUtMTk3MCBkYXRlcyBhbHNvIHJldHVybiBmYWxzZSBzaW5jZSB0aGUgdGltZSB6b25lIGRhdGFiYXNlIGRvZXMgbm90IGNvbnRhaW4gYWNjdXJhdGUgaW5mb1xuICAgICAqIGJlZm9yZSB0aGF0LiBZb3UgY2FuIGNoYW5nZSB0aGF0IHdpdGggdGhlIGFsbG93UHJlMTk3MCBmbGFnLlxuICAgICAqXG4gICAgICogQHBhcmFtIGFsbG93UHJlMTk3MCAob3B0aW9uYWwsIGRlZmF1bHQgZmFsc2UpOiByZXR1cm4gdHJ1ZSBmb3IgcHJlLTE5NzAgZGF0ZXNcbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBEYXRlVGltZS5leGlzdHMgPSBmdW5jdGlvbiAoeWVhciwgbW9udGgsIGRheSwgaG91ciwgbWludXRlLCBzZWNvbmQsIG1pbGxpc2Vjb25kLCB6b25lLCBhbGxvd1ByZTE5NzApIHtcbiAgICAgICAgaWYgKG1vbnRoID09PSB2b2lkIDApIHsgbW9udGggPSAxOyB9XG4gICAgICAgIGlmIChkYXkgPT09IHZvaWQgMCkgeyBkYXkgPSAxOyB9XG4gICAgICAgIGlmIChob3VyID09PSB2b2lkIDApIHsgaG91ciA9IDA7IH1cbiAgICAgICAgaWYgKG1pbnV0ZSA9PT0gdm9pZCAwKSB7IG1pbnV0ZSA9IDA7IH1cbiAgICAgICAgaWYgKHNlY29uZCA9PT0gdm9pZCAwKSB7IHNlY29uZCA9IDA7IH1cbiAgICAgICAgaWYgKG1pbGxpc2Vjb25kID09PSB2b2lkIDApIHsgbWlsbGlzZWNvbmQgPSAwOyB9XG4gICAgICAgIGlmIChhbGxvd1ByZTE5NzAgPT09IHZvaWQgMCkgeyBhbGxvd1ByZTE5NzAgPSBmYWxzZTsgfVxuICAgICAgICBpZiAoIWlzRmluaXRlKHllYXIpIHx8ICFpc0Zpbml0ZShtb250aCkgfHwgIWlzRmluaXRlKGRheSkgfHwgIWlzRmluaXRlKGhvdXIpIHx8ICFpc0Zpbml0ZShtaW51dGUpIHx8ICFpc0Zpbml0ZShzZWNvbmQpXG4gICAgICAgICAgICB8fCAhaXNGaW5pdGUobWlsbGlzZWNvbmQpKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFhbGxvd1ByZTE5NzAgJiYgeWVhciA8IDE5NzApIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgdmFyIGR0ID0gbmV3IERhdGVUaW1lKHllYXIsIG1vbnRoLCBkYXksIGhvdXIsIG1pbnV0ZSwgc2Vjb25kLCBtaWxsaXNlY29uZCwgem9uZSk7XG4gICAgICAgICAgICByZXR1cm4gKHllYXIgPT09IGR0LnllYXIoKSAmJiBtb250aCA9PT0gZHQubW9udGgoKSAmJiBkYXkgPT09IGR0LmRheSgpXG4gICAgICAgICAgICAgICAgJiYgaG91ciA9PT0gZHQuaG91cigpICYmIG1pbnV0ZSA9PT0gZHQubWludXRlKCkgJiYgc2Vjb25kID09PSBkdC5zZWNvbmQoKSAmJiBtaWxsaXNlY29uZCA9PT0gZHQubWlsbGlzZWNvbmQoKSk7XG4gICAgICAgIH1cbiAgICAgICAgY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgLyoqXG4gICAgICogQHJldHVybiBhIGNvcHkgb2YgdGhpcyBvYmplY3RcbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBEYXRlVGltZS5wcm90b3R5cGUuY2xvbmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBuZXcgRGF0ZVRpbWUodGhpcy56b25lRGF0ZSwgdGhpcy5fem9uZSk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBAcmV0dXJuIFRoZSB0aW1lIHpvbmUgdGhhdCB0aGUgZGF0ZSBpcyBpbi4gTWF5IGJlIHVuZGVmaW5lZCBmb3IgdW5hd2FyZSBkYXRlcy5cbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBEYXRlVGltZS5wcm90b3R5cGUuem9uZSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3pvbmU7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBab25lIG5hbWUgYWJicmV2aWF0aW9uIGF0IHRoaXMgdGltZVxuICAgICAqIEBwYXJhbSBkc3REZXBlbmRlbnQgKGRlZmF1bHQgdHJ1ZSkgc2V0IHRvIGZhbHNlIGZvciBhIERTVC1hZ25vc3RpYyBhYmJyZXZpYXRpb25cbiAgICAgKiBAcmV0dXJuIFRoZSBhYmJyZXZpYXRpb25cbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBEYXRlVGltZS5wcm90b3R5cGUuem9uZUFiYnJldmlhdGlvbiA9IGZ1bmN0aW9uIChkc3REZXBlbmRlbnQpIHtcbiAgICAgICAgaWYgKGRzdERlcGVuZGVudCA9PT0gdm9pZCAwKSB7IGRzdERlcGVuZGVudCA9IHRydWU7IH1cbiAgICAgICAgaWYgKHRoaXMuX3pvbmUpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl96b25lLmFiYnJldmlhdGlvbkZvclV0Yyh0aGlzLnV0Y0RhdGUsIGRzdERlcGVuZGVudCk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gXCJcIjtcbiAgICAgICAgfVxuICAgIH07XG4gICAgLyoqXG4gICAgICogQHJldHVybiB0aGUgb2Zmc2V0IGluY2x1ZGluZyBEU1Qgdy5yLnQuIFVUQyBpbiBtaW51dGVzLiBSZXR1cm5zIDAgZm9yIHVuYXdhcmUgZGF0ZXMgYW5kIGZvciBVVEMgZGF0ZXMuXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgRGF0ZVRpbWUucHJvdG90eXBlLm9mZnNldCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIE1hdGgucm91bmQoKHRoaXMuem9uZURhdGUudW5peE1pbGxpcyAtIHRoaXMudXRjRGF0ZS51bml4TWlsbGlzKSAvIDYwMDAwKTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIEByZXR1cm4gdGhlIG9mZnNldCBpbmNsdWRpbmcgRFNUIHcuci50LiBVVEMgYXMgYSBEdXJhdGlvbi5cbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBEYXRlVGltZS5wcm90b3R5cGUub2Zmc2V0RHVyYXRpb24gPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBkdXJhdGlvbl8xLkR1cmF0aW9uLm1pbGxpc2Vjb25kcyhNYXRoLnJvdW5kKHRoaXMuem9uZURhdGUudW5peE1pbGxpcyAtIHRoaXMudXRjRGF0ZS51bml4TWlsbGlzKSk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBAcmV0dXJuIHRoZSBzdGFuZGFyZCBvZmZzZXQgV0lUSE9VVCBEU1Qgdy5yLnQuIFVUQyBhcyBhIER1cmF0aW9uLlxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIERhdGVUaW1lLnByb3RvdHlwZS5zdGFuZGFyZE9mZnNldER1cmF0aW9uID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAodGhpcy5fem9uZSkge1xuICAgICAgICAgICAgcmV0dXJuIGR1cmF0aW9uXzEuRHVyYXRpb24ubWludXRlcyh0aGlzLl96b25lLnN0YW5kYXJkT2Zmc2V0Rm9yVXRjKHRoaXMudXRjRGF0ZSkpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBkdXJhdGlvbl8xLkR1cmF0aW9uLm1pbnV0ZXMoMCk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBAcmV0dXJuIFRoZSBmdWxsIHllYXIgZS5nLiAyMDE0XG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgRGF0ZVRpbWUucHJvdG90eXBlLnllYXIgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnpvbmVEYXRlLmNvbXBvbmVudHMueWVhcjtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIEByZXR1cm4gVGhlIG1vbnRoIDEtMTIgKG5vdGUgdGhpcyBkZXZpYXRlcyBmcm9tIEphdmFTY3JpcHQgRGF0ZSlcbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBEYXRlVGltZS5wcm90b3R5cGUubW9udGggPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnpvbmVEYXRlLmNvbXBvbmVudHMubW9udGg7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBAcmV0dXJuIFRoZSBkYXkgb2YgdGhlIG1vbnRoIDEtMzFcbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBEYXRlVGltZS5wcm90b3R5cGUuZGF5ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy56b25lRGF0ZS5jb21wb25lbnRzLmRheTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIEByZXR1cm4gVGhlIGhvdXIgMC0yM1xuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIERhdGVUaW1lLnByb3RvdHlwZS5ob3VyID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy56b25lRGF0ZS5jb21wb25lbnRzLmhvdXI7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBAcmV0dXJuIHRoZSBtaW51dGVzIDAtNTlcbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBEYXRlVGltZS5wcm90b3R5cGUubWludXRlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy56b25lRGF0ZS5jb21wb25lbnRzLm1pbnV0ZTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIEByZXR1cm4gdGhlIHNlY29uZHMgMC01OVxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIERhdGVUaW1lLnByb3RvdHlwZS5zZWNvbmQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnpvbmVEYXRlLmNvbXBvbmVudHMuc2Vjb25kO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogQHJldHVybiB0aGUgbWlsbGlzZWNvbmRzIDAtOTk5XG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgRGF0ZVRpbWUucHJvdG90eXBlLm1pbGxpc2Vjb25kID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy56b25lRGF0ZS5jb21wb25lbnRzLm1pbGxpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogQHJldHVybiB0aGUgZGF5LW9mLXdlZWsgKHRoZSBlbnVtIHZhbHVlcyBjb3JyZXNwb25kIHRvIEphdmFTY3JpcHRcbiAgICAgKiB3ZWVrIGRheSBudW1iZXJzKVxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIERhdGVUaW1lLnByb3RvdHlwZS53ZWVrRGF5ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gYmFzaWNzLndlZWtEYXlOb0xlYXBTZWNzKHRoaXMuem9uZURhdGUudW5peE1pbGxpcyk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBkYXkgbnVtYmVyIHdpdGhpbiB0aGUgeWVhcjogSmFuIDFzdCBoYXMgbnVtYmVyIDAsXG4gICAgICogSmFuIDJuZCBoYXMgbnVtYmVyIDEgZXRjLlxuICAgICAqXG4gICAgICogQHJldHVybiB0aGUgZGF5LW9mLXllYXIgWzAtMzY2XVxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIERhdGVUaW1lLnByb3RvdHlwZS5kYXlPZlllYXIgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnpvbmVEYXRlLnllYXJEYXkoKTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFRoZSBJU08gODYwMSB3ZWVrIG51bWJlci4gV2VlayAxIGlzIHRoZSB3ZWVrXG4gICAgICogdGhhdCBoYXMgSmFudWFyeSA0dGggaW4gaXQsIGFuZCBpdCBzdGFydHMgb24gTW9uZGF5LlxuICAgICAqIFNlZSBodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9JU09fd2Vla19kYXRlXG4gICAgICpcbiAgICAgKiBAcmV0dXJuIFdlZWsgbnVtYmVyIFsxLTUzXVxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIERhdGVUaW1lLnByb3RvdHlwZS53ZWVrTnVtYmVyID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gYmFzaWNzLndlZWtOdW1iZXIodGhpcy55ZWFyKCksIHRoaXMubW9udGgoKSwgdGhpcy5kYXkoKSk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBUaGUgd2VlayBvZiB0aGlzIG1vbnRoLiBUaGVyZSBpcyBubyBvZmZpY2lhbCBzdGFuZGFyZCBmb3IgdGhpcyxcbiAgICAgKiBidXQgd2UgYXNzdW1lIHRoZSBzYW1lIHJ1bGVzIGZvciB0aGUgd2Vla051bWJlciAoaS5lLlxuICAgICAqIHdlZWsgMSBpcyB0aGUgd2VlayB0aGF0IGhhcyB0aGUgNHRoIGRheSBvZiB0aGUgbW9udGggaW4gaXQpXG4gICAgICpcbiAgICAgKiBAcmV0dXJuIFdlZWsgbnVtYmVyIFsxLTVdXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgRGF0ZVRpbWUucHJvdG90eXBlLndlZWtPZk1vbnRoID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gYmFzaWNzLndlZWtPZk1vbnRoKHRoaXMueWVhcigpLCB0aGlzLm1vbnRoKCksIHRoaXMuZGF5KCkpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgbnVtYmVyIG9mIHNlY29uZHMgdGhhdCBoYXZlIHBhc3NlZCBvbiB0aGUgY3VycmVudCBkYXlcbiAgICAgKiBEb2VzIG5vdCBjb25zaWRlciBsZWFwIHNlY29uZHNcbiAgICAgKlxuICAgICAqIEByZXR1cm4gc2Vjb25kcyBbMC04NjM5OV1cbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBEYXRlVGltZS5wcm90b3R5cGUuc2Vjb25kT2ZEYXkgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBiYXNpY3Muc2Vjb25kT2ZEYXkodGhpcy5ob3VyKCksIHRoaXMubWludXRlKCksIHRoaXMuc2Vjb25kKCkpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogQHJldHVybiBNaWxsaXNlY29uZHMgc2luY2UgMTk3MC0wMS0wMVQwMDowMDowMC4wMDBaXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgRGF0ZVRpbWUucHJvdG90eXBlLnVuaXhVdGNNaWxsaXMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnV0Y0RhdGUudW5peE1pbGxpcztcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIEByZXR1cm4gVGhlIGZ1bGwgeWVhciBlLmcuIDIwMTRcbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBEYXRlVGltZS5wcm90b3R5cGUudXRjWWVhciA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMudXRjRGF0ZS5jb21wb25lbnRzLnllYXI7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBAcmV0dXJuIFRoZSBVVEMgbW9udGggMS0xMiAobm90ZSB0aGlzIGRldmlhdGVzIGZyb20gSmF2YVNjcmlwdCBEYXRlKVxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIERhdGVUaW1lLnByb3RvdHlwZS51dGNNb250aCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMudXRjRGF0ZS5jb21wb25lbnRzLm1vbnRoO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogQHJldHVybiBUaGUgVVRDIGRheSBvZiB0aGUgbW9udGggMS0zMVxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIERhdGVUaW1lLnByb3RvdHlwZS51dGNEYXkgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnV0Y0RhdGUuY29tcG9uZW50cy5kYXk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBAcmV0dXJuIFRoZSBVVEMgaG91ciAwLTIzXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgRGF0ZVRpbWUucHJvdG90eXBlLnV0Y0hvdXIgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnV0Y0RhdGUuY29tcG9uZW50cy5ob3VyO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogQHJldHVybiBUaGUgVVRDIG1pbnV0ZXMgMC01OVxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIERhdGVUaW1lLnByb3RvdHlwZS51dGNNaW51dGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnV0Y0RhdGUuY29tcG9uZW50cy5taW51dGU7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBAcmV0dXJuIFRoZSBVVEMgc2Vjb25kcyAwLTU5XG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgRGF0ZVRpbWUucHJvdG90eXBlLnV0Y1NlY29uZCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMudXRjRGF0ZS5jb21wb25lbnRzLnNlY29uZDtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIFVUQyBkYXkgbnVtYmVyIHdpdGhpbiB0aGUgeWVhcjogSmFuIDFzdCBoYXMgbnVtYmVyIDAsXG4gICAgICogSmFuIDJuZCBoYXMgbnVtYmVyIDEgZXRjLlxuICAgICAqXG4gICAgICogQHJldHVybiB0aGUgZGF5LW9mLXllYXIgWzAtMzY2XVxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIERhdGVUaW1lLnByb3RvdHlwZS51dGNEYXlPZlllYXIgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBiYXNpY3MuZGF5T2ZZZWFyKHRoaXMudXRjWWVhcigpLCB0aGlzLnV0Y01vbnRoKCksIHRoaXMudXRjRGF5KCkpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogQHJldHVybiBUaGUgVVRDIG1pbGxpc2Vjb25kcyAwLTk5OVxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIERhdGVUaW1lLnByb3RvdHlwZS51dGNNaWxsaXNlY29uZCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMudXRjRGF0ZS5jb21wb25lbnRzLm1pbGxpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogQHJldHVybiB0aGUgVVRDIGRheS1vZi13ZWVrICh0aGUgZW51bSB2YWx1ZXMgY29ycmVzcG9uZCB0byBKYXZhU2NyaXB0XG4gICAgICogd2VlayBkYXkgbnVtYmVycylcbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBEYXRlVGltZS5wcm90b3R5cGUudXRjV2Vla0RheSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIGJhc2ljcy53ZWVrRGF5Tm9MZWFwU2Vjcyh0aGlzLnV0Y0RhdGUudW5peE1pbGxpcyk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBUaGUgSVNPIDg2MDEgVVRDIHdlZWsgbnVtYmVyLiBXZWVrIDEgaXMgdGhlIHdlZWtcbiAgICAgKiB0aGF0IGhhcyBKYW51YXJ5IDR0aCBpbiBpdCwgYW5kIGl0IHN0YXJ0cyBvbiBNb25kYXkuXG4gICAgICogU2VlIGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0lTT193ZWVrX2RhdGVcbiAgICAgKlxuICAgICAqIEByZXR1cm4gV2VlayBudW1iZXIgWzEtNTNdXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgRGF0ZVRpbWUucHJvdG90eXBlLnV0Y1dlZWtOdW1iZXIgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBiYXNpY3Mud2Vla051bWJlcih0aGlzLnV0Y1llYXIoKSwgdGhpcy51dGNNb250aCgpLCB0aGlzLnV0Y0RheSgpKTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFRoZSB3ZWVrIG9mIHRoaXMgbW9udGguIFRoZXJlIGlzIG5vIG9mZmljaWFsIHN0YW5kYXJkIGZvciB0aGlzLFxuICAgICAqIGJ1dCB3ZSBhc3N1bWUgdGhlIHNhbWUgcnVsZXMgZm9yIHRoZSB3ZWVrTnVtYmVyIChpLmUuXG4gICAgICogd2VlayAxIGlzIHRoZSB3ZWVrIHRoYXQgaGFzIHRoZSA0dGggZGF5IG9mIHRoZSBtb250aCBpbiBpdClcbiAgICAgKlxuICAgICAqIEByZXR1cm4gV2VlayBudW1iZXIgWzEtNV1cbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBEYXRlVGltZS5wcm90b3R5cGUudXRjV2Vla09mTW9udGggPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBiYXNpY3Mud2Vla09mTW9udGgodGhpcy51dGNZZWFyKCksIHRoaXMudXRjTW9udGgoKSwgdGhpcy51dGNEYXkoKSk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBudW1iZXIgb2Ygc2Vjb25kcyB0aGF0IGhhdmUgcGFzc2VkIG9uIHRoZSBjdXJyZW50IGRheVxuICAgICAqIERvZXMgbm90IGNvbnNpZGVyIGxlYXAgc2Vjb25kc1xuICAgICAqXG4gICAgICogQHJldHVybiBzZWNvbmRzIFswLTg2Mzk5XVxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIERhdGVUaW1lLnByb3RvdHlwZS51dGNTZWNvbmRPZkRheSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIGJhc2ljcy5zZWNvbmRPZkRheSh0aGlzLnV0Y0hvdXIoKSwgdGhpcy51dGNNaW51dGUoKSwgdGhpcy51dGNTZWNvbmQoKSk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIGEgbmV3IERhdGVUaW1lIHdoaWNoIGlzIHRoZSBkYXRlK3RpbWUgcmVpbnRlcnByZXRlZCBhc1xuICAgICAqIGluIHRoZSBuZXcgem9uZS4gU28gZS5nLiAwODowMCBBbWVyaWNhL0NoaWNhZ28gY2FuIGJlIHNldCB0byAwODowMCBFdXJvcGUvQnJ1c3NlbHMuXG4gICAgICogTm8gY29udmVyc2lvbiBpcyBkb25lLCB0aGUgdmFsdWUgaXMganVzdCBhc3N1bWVkIHRvIGJlIGluIGEgZGlmZmVyZW50IHpvbmUuXG4gICAgICogV29ya3MgZm9yIG5haXZlIGFuZCBhd2FyZSBkYXRlcy4gVGhlIG5ldyB6b25lIG1heSBiZSBudWxsLlxuICAgICAqXG4gICAgICogQHBhcmFtIHpvbmUgVGhlIG5ldyB0aW1lIHpvbmVcbiAgICAgKiBAcmV0dXJuIEEgbmV3IERhdGVUaW1lIHdpdGggdGhlIG9yaWdpbmFsIHRpbWVzdGFtcCBhbmQgdGhlIG5ldyB6b25lLlxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIERhdGVUaW1lLnByb3RvdHlwZS53aXRoWm9uZSA9IGZ1bmN0aW9uICh6b25lKSB7XG4gICAgICAgIHJldHVybiBuZXcgRGF0ZVRpbWUodGhpcy55ZWFyKCksIHRoaXMubW9udGgoKSwgdGhpcy5kYXkoKSwgdGhpcy5ob3VyKCksIHRoaXMubWludXRlKCksIHRoaXMuc2Vjb25kKCksIHRoaXMubWlsbGlzZWNvbmQoKSwgem9uZSk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBDb252ZXJ0IHRoaXMgZGF0ZSB0byB0aGUgZ2l2ZW4gdGltZSB6b25lIChpbi1wbGFjZSkuXG4gICAgICogQHJldHVybiB0aGlzIChmb3IgY2hhaW5pbmcpXG4gICAgICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLlVuYXdhcmVUb0F3YXJlQ29udmVyc2lvbiBpZiB5b3UgdHJ5IHRvIGNvbnZlcnQgYSBkYXRldGltZSB3aXRob3V0IGEgem9uZSB0byBhIGRhdGV0aW1lIHdpdGggYSB6b25lXG4gICAgICovXG4gICAgRGF0ZVRpbWUucHJvdG90eXBlLmNvbnZlcnQgPSBmdW5jdGlvbiAoem9uZSkge1xuICAgICAgICBpZiAoem9uZSkge1xuICAgICAgICAgICAgaWYgKCF0aGlzLl96b25lKSB7IC8vIGlmLXN0YXRlbWVudCBzYXRpc2ZpZXMgdGhlIGNvbXBpbGVyXG4gICAgICAgICAgICAgICAgcmV0dXJuICgwLCBlcnJvcl8xLnRocm93RXJyb3IpKFwiVW5hd2FyZVRvQXdhcmVDb252ZXJzaW9uXCIsIFwiRGF0ZVRpbWUudG9ab25lKCk6IENhbm5vdCBjb252ZXJ0IHVuYXdhcmUgZGF0ZSB0byBhbiBhd2FyZSBkYXRlXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBpZiAodGhpcy5fem9uZS5lcXVhbHMoem9uZSkpIHtcbiAgICAgICAgICAgICAgICB0aGlzLl96b25lID0gem9uZTsgLy8gc3RpbGwgYXNzaWduLCBiZWNhdXNlIHpvbmVzIG1heSBiZSBlcXVhbCBidXQgbm90IGlkZW50aWNhbCAoVVRDL0dNVC8rMDApXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBpZiAoIXRoaXMuX3V0Y0RhdGUpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fdXRjRGF0ZSA9IGNvbnZlcnRUb1V0Yyh0aGlzLl96b25lRGF0ZSwgdGhpcy5fem9uZSk7IC8vIGNhdXNlIHpvbmUgLT4gdXRjIGNvbnZlcnNpb25cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdGhpcy5fem9uZSA9IHpvbmU7XG4gICAgICAgICAgICAgICAgdGhpcy5fem9uZURhdGUgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBpZiAoIXRoaXMuX3pvbmUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICghdGhpcy5fem9uZURhdGUpIHtcbiAgICAgICAgICAgICAgICB0aGlzLl96b25lRGF0ZSA9IGNvbnZlcnRGcm9tVXRjKHRoaXMuX3V0Y0RhdGUsIHRoaXMuX3pvbmUpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5fem9uZSA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgIHRoaXMuX3V0Y0RhdGUgPSB1bmRlZmluZWQ7IC8vIGNhdXNlIGxhdGVyIHpvbmUgLT4gdXRjIGNvbnZlcnNpb25cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhpcyBkYXRlIGNvbnZlcnRlZCB0byB0aGUgZ2l2ZW4gdGltZSB6b25lLlxuICAgICAqIFVuYXdhcmUgZGF0ZXMgY2FuIG9ubHkgYmUgY29udmVydGVkIHRvIHVuYXdhcmUgZGF0ZXMgKGNsb25lKVxuICAgICAqIENvbnZlcnRpbmcgYW4gdW5hd2FyZSBkYXRlIHRvIGFuIGF3YXJlIGRhdGUgdGhyb3dzIGFuIGV4Y2VwdGlvbi4gVXNlIHRoZSBjb25zdHJ1Y3RvclxuICAgICAqIGlmIHlvdSByZWFsbHkgbmVlZCB0byBkbyB0aGF0LlxuICAgICAqXG4gICAgICogQHBhcmFtIHpvbmVcdFRoZSBuZXcgdGltZSB6b25lLiBUaGlzIG1heSBiZSBudWxsIG9yIHVuZGVmaW5lZCB0byBjcmVhdGUgdW5hd2FyZSBkYXRlLlxuICAgICAqIEByZXR1cm4gVGhlIGNvbnZlcnRlZCBkYXRlXG4gICAgICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLlVuYXdhcmVUb0F3YXJlQ29udmVyc2lvbiBpZiB5b3UgdHJ5IHRvIGNvbnZlcnQgYSBuYWl2ZSBkYXRldGltZSB0byBhbiBhd2FyZSBvbmUuXG4gICAgICovXG4gICAgRGF0ZVRpbWUucHJvdG90eXBlLnRvWm9uZSA9IGZ1bmN0aW9uICh6b25lKSB7XG4gICAgICAgIGlmICh6b25lKSB7XG4gICAgICAgICAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkodGhpcy5fem9uZSwgXCJVbmF3YXJlVG9Bd2FyZUNvbnZlcnNpb25cIiwgXCJEYXRlVGltZS50b1pvbmUoKTogQ2Fubm90IGNvbnZlcnQgdW5hd2FyZSBkYXRlIHRvIGFuIGF3YXJlIGRhdGVcIik7XG4gICAgICAgICAgICB2YXIgcmVzdWx0ID0gbmV3IERhdGVUaW1lKCk7XG4gICAgICAgICAgICByZXN1bHQudXRjRGF0ZSA9IHRoaXMudXRjRGF0ZTtcbiAgICAgICAgICAgIHJlc3VsdC5fem9uZSA9IHpvbmU7XG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIG5ldyBEYXRlVGltZSh0aGlzLnpvbmVEYXRlLCB1bmRlZmluZWQpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBDb252ZXJ0IHRvIEphdmFTY3JpcHQgZGF0ZSB3aXRoIHRoZSB6b25lIHRpbWUgaW4gdGhlIGdldFgoKSBtZXRob2RzLlxuICAgICAqIFVubGVzcyB0aGUgdGltZXpvbmUgaXMgbG9jYWwsIHRoZSBEYXRlLmdldFVUQ1goKSBtZXRob2RzIHdpbGwgTk9UIGJlIGNvcnJlY3QuXG4gICAgICogVGhpcyBpcyBiZWNhdXNlIERhdGUgY2FsY3VsYXRlcyBnZXRVVENYKCkgZnJvbSBnZXRYKCkgYXBwbHlpbmcgbG9jYWwgdGltZSB6b25lLlxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIERhdGVUaW1lLnByb3RvdHlwZS50b0RhdGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBuZXcgRGF0ZSh0aGlzLnllYXIoKSwgdGhpcy5tb250aCgpIC0gMSwgdGhpcy5kYXkoKSwgdGhpcy5ob3VyKCksIHRoaXMubWludXRlKCksIHRoaXMuc2Vjb25kKCksIHRoaXMubWlsbGlzZWNvbmQoKSk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYW4gRXhjZWwgdGltZXN0YW1wIGZvciB0aGlzIGRhdGV0aW1lIGNvbnZlcnRlZCB0byB0aGUgZ2l2ZW4gem9uZS5cbiAgICAgKiBEb2VzIG5vdCB3b3JrIGZvciBkYXRlcyA8IDE5MDBcbiAgICAgKiBAcGFyYW0gdGltZVpvbmUgT3B0aW9uYWwuIFpvbmUgdG8gY29udmVydCB0bywgZGVmYXVsdCB0aGUgem9uZSB0aGUgZGF0ZXRpbWUgaXMgYWxyZWFkeSBpbi5cbiAgICAgKiBAcmV0dXJuIGFuIEV4Y2VsIGRhdGUvdGltZSBudW1iZXIgaS5lLiBkYXlzIHNpbmNlIDEtMS0xOTAwIHdoZXJlIDE5MDAgaXMgaW5jb3JyZWN0bHkgc2VlbiBhcyBsZWFwIHllYXJcbiAgICAgKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuVW5hd2FyZVRvQXdhcmVDb252ZXJzaW9uIGlmIHlvdSB0cnkgdG8gY29udmVydCBhIG5haXZlIGRhdGV0aW1lIHRvIGFuIGF3YXJlIG9uZS5cbiAgICAgKi9cbiAgICBEYXRlVGltZS5wcm90b3R5cGUudG9FeGNlbCA9IGZ1bmN0aW9uICh0aW1lWm9uZSkge1xuICAgICAgICB2YXIgZHQgPSB0aGlzO1xuICAgICAgICBpZiAodGltZVpvbmUgJiYgKCF0aGlzLl96b25lIHx8ICF0aW1lWm9uZS5lcXVhbHModGhpcy5fem9uZSkpKSB7XG4gICAgICAgICAgICBkdCA9IHRoaXMudG9ab25lKHRpbWVab25lKTtcbiAgICAgICAgfVxuICAgICAgICB2YXIgb2Zmc2V0TWlsbGlzID0gZHQub2Zmc2V0KCkgKiA2MCAqIDEwMDA7XG4gICAgICAgIHZhciB1bml4VGltZXN0YW1wID0gZHQudW5peFV0Y01pbGxpcygpO1xuICAgICAgICByZXR1cm4gdGhpcy5fdW5peFRpbWVTdGFtcFRvRXhjZWwodW5peFRpbWVzdGFtcCArIG9mZnNldE1pbGxpcyk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYW4gRXhjZWwgdGltZXN0YW1wIGZvciB0aGlzIGRhdGV0aW1lIGNvbnZlcnRlZCB0byBVVENcbiAgICAgKiBEb2VzIG5vdCB3b3JrIGZvciBkYXRlcyA8IDE5MDBcbiAgICAgKiBAcmV0dXJuIGFuIEV4Y2VsIGRhdGUvdGltZSBudW1iZXIgaS5lLiBkYXlzIHNpbmNlIDEtMS0xOTAwIHdoZXJlIDE5MDAgaXMgaW5jb3JyZWN0bHkgc2VlbiBhcyBsZWFwIHllYXJcbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBEYXRlVGltZS5wcm90b3R5cGUudG9VdGNFeGNlbCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHVuaXhUaW1lc3RhbXAgPSB0aGlzLnVuaXhVdGNNaWxsaXMoKTtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3VuaXhUaW1lU3RhbXBUb0V4Y2VsKHVuaXhUaW1lc3RhbXApO1xuICAgIH07XG4gICAgLyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0gblxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIERhdGVUaW1lLnByb3RvdHlwZS5fdW5peFRpbWVTdGFtcFRvRXhjZWwgPSBmdW5jdGlvbiAobikge1xuICAgICAgICB2YXIgcmVzdWx0ID0gKChuKSAvICgyNCAqIDYwICogNjAgKiAxMDAwKSkgKyAyNTU2OTtcbiAgICAgICAgLy8gcm91bmQgdG8gbmVhcmVzdCBtaWxsaXNlY29uZFxuICAgICAgICB2YXIgbXNlY3MgPSByZXN1bHQgLyAoMSAvIDg2NDAwMDAwKTtcbiAgICAgICAgcmV0dXJuIE1hdGgucm91bmQobXNlY3MpICogKDEgLyA4NjQwMDAwMCk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBJbXBsZW1lbnRhdGlvbi5cbiAgICAgKi9cbiAgICBEYXRlVGltZS5wcm90b3R5cGUuYWRkID0gZnVuY3Rpb24gKGExLCB1bml0KSB7XG4gICAgICAgIHZhciBhbW91bnQ7XG4gICAgICAgIHZhciB1O1xuICAgICAgICBpZiAodHlwZW9mIChhMSkgPT09IFwib2JqZWN0XCIpIHtcbiAgICAgICAgICAgIHZhciBkdXJhdGlvbiA9IChhMSk7XG4gICAgICAgICAgICBhbW91bnQgPSBkdXJhdGlvbi5hbW91bnQoKTtcbiAgICAgICAgICAgIHUgPSBkdXJhdGlvbi51bml0KCk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBhbW91bnQgPSAoYTEpO1xuICAgICAgICAgICAgdSA9IHVuaXQ7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHV0Y1RtID0gdGhpcy5fYWRkVG9UaW1lU3RydWN0KHRoaXMudXRjRGF0ZSwgYW1vdW50LCB1KTtcbiAgICAgICAgcmV0dXJuIG5ldyBEYXRlVGltZSh1dGNUbSwgdGltZXpvbmVfMS5UaW1lWm9uZS51dGMoKSkudG9ab25lKHRoaXMuX3pvbmUpO1xuICAgIH07XG4gICAgRGF0ZVRpbWUucHJvdG90eXBlLmFkZExvY2FsID0gZnVuY3Rpb24gKGExLCB1bml0KSB7XG4gICAgICAgIHZhciBhbW91bnQ7XG4gICAgICAgIHZhciB1O1xuICAgICAgICBpZiAodHlwZW9mIChhMSkgPT09IFwib2JqZWN0XCIpIHtcbiAgICAgICAgICAgIHZhciBkdXJhdGlvbiA9IChhMSk7XG4gICAgICAgICAgICBhbW91bnQgPSBkdXJhdGlvbi5hbW91bnQoKTtcbiAgICAgICAgICAgIHUgPSBkdXJhdGlvbi51bml0KCk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBhbW91bnQgPSAoYTEpO1xuICAgICAgICAgICAgdSA9IHVuaXQ7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIGxvY2FsVG0gPSB0aGlzLl9hZGRUb1RpbWVTdHJ1Y3QodGhpcy56b25lRGF0ZSwgYW1vdW50LCB1KTtcbiAgICAgICAgaWYgKHRoaXMuX3pvbmUpIHtcbiAgICAgICAgICAgIHZhciBkaXJlY3Rpb24gPSAoYW1vdW50ID49IDAgPyB0el9kYXRhYmFzZV8xLk5vcm1hbGl6ZU9wdGlvbi5VcCA6IHR6X2RhdGFiYXNlXzEuTm9ybWFsaXplT3B0aW9uLkRvd24pO1xuICAgICAgICAgICAgdmFyIG5vcm1hbGl6ZWQgPSB0aGlzLl96b25lLm5vcm1hbGl6ZVpvbmVUaW1lKGxvY2FsVG0sIGRpcmVjdGlvbik7XG4gICAgICAgICAgICByZXR1cm4gbmV3IERhdGVUaW1lKG5vcm1hbGl6ZWQsIHRoaXMuX3pvbmUpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIG5ldyBEYXRlVGltZShsb2NhbFRtLCB1bmRlZmluZWQpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBBZGQgYW4gYW1vdW50IG9mIHRpbWUgdG8gdGhlIGdpdmVuIHRpbWUgc3RydWN0LiBOb3RlOiBkb2VzIG5vdCBub3JtYWxpemUuXG4gICAgICogS2VlcHMgbG93ZXIgdW5pdCBmaWVsZHMgdGhlIHNhbWUgd2hlcmUgcG9zc2libGUsIGNsYW1wcyBkYXkgdG8gZW5kLW9mLW1vbnRoIGlmXG4gICAgICogbmVjZXNzYXJ5LlxuICAgICAqIEB0aHJvd3MgQXJndW1lbnQuQW1vdW50IGlmIGFtb3VudCBpcyBub3QgZmluaXRlIG9yIGlmIGl0J3Mgbm90IGFuIGludGVnZXIgYW5kIHlvdSdyZSBhZGRpbmcgbW9udGhzIG9yIHllYXJzXG4gICAgICogQHRocm93cyBBcmd1bWVudC5Vbml0IGZvciBpbnZhbGlkIHRpbWUgdW5pdFxuICAgICAqL1xuICAgIERhdGVUaW1lLnByb3RvdHlwZS5fYWRkVG9UaW1lU3RydWN0ID0gZnVuY3Rpb24gKHRtLCBhbW91bnQsIHVuaXQpIHtcbiAgICAgICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKE51bWJlci5pc0Zpbml0ZShhbW91bnQpLCBcIkFyZ3VtZW50LkFtb3VudFwiLCBcImFtb3VudCBtdXN0IGJlIGEgZmluaXRlIG51bWJlclwiKTtcbiAgICAgICAgdmFyIHllYXI7XG4gICAgICAgIHZhciBtb250aDtcbiAgICAgICAgdmFyIGRheTtcbiAgICAgICAgdmFyIGhvdXI7XG4gICAgICAgIHZhciBtaW51dGU7XG4gICAgICAgIHZhciBzZWNvbmQ7XG4gICAgICAgIHZhciBtaWxsaTtcbiAgICAgICAgc3dpdGNoICh1bml0KSB7XG4gICAgICAgICAgICBjYXNlIGJhc2ljc18xLlRpbWVVbml0Lk1pbGxpc2Vjb25kOlxuICAgICAgICAgICAgICAgIHJldHVybiBuZXcgYmFzaWNzXzEuVGltZVN0cnVjdChtYXRoLnJvdW5kU3ltKHRtLnVuaXhNaWxsaXMgKyBhbW91bnQpKTtcbiAgICAgICAgICAgIGNhc2UgYmFzaWNzXzEuVGltZVVuaXQuU2Vjb25kOlxuICAgICAgICAgICAgICAgIHJldHVybiBuZXcgYmFzaWNzXzEuVGltZVN0cnVjdChtYXRoLnJvdW5kU3ltKHRtLnVuaXhNaWxsaXMgKyBhbW91bnQgKiAxMDAwKSk7XG4gICAgICAgICAgICBjYXNlIGJhc2ljc18xLlRpbWVVbml0Lk1pbnV0ZTpcbiAgICAgICAgICAgICAgICAvLyB0b2RvIG1vcmUgaW50ZWxsaWdlbnQgYXBwcm9hY2ggbmVlZGVkIHdoZW4gaW1wbGVtZW50aW5nIGxlYXAgc2Vjb25kc1xuICAgICAgICAgICAgICAgIHJldHVybiBuZXcgYmFzaWNzXzEuVGltZVN0cnVjdChtYXRoLnJvdW5kU3ltKHRtLnVuaXhNaWxsaXMgKyBhbW91bnQgKiA2MDAwMCkpO1xuICAgICAgICAgICAgY2FzZSBiYXNpY3NfMS5UaW1lVW5pdC5Ib3VyOlxuICAgICAgICAgICAgICAgIC8vIHRvZG8gbW9yZSBpbnRlbGxpZ2VudCBhcHByb2FjaCBuZWVkZWQgd2hlbiBpbXBsZW1lbnRpbmcgbGVhcCBzZWNvbmRzXG4gICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBiYXNpY3NfMS5UaW1lU3RydWN0KG1hdGgucm91bmRTeW0odG0udW5peE1pbGxpcyArIGFtb3VudCAqIDM2MDAwMDApKTtcbiAgICAgICAgICAgIGNhc2UgYmFzaWNzXzEuVGltZVVuaXQuRGF5OlxuICAgICAgICAgICAgICAgIC8vIHRvZG8gbW9yZSBpbnRlbGxpZ2VudCBhcHByb2FjaCBuZWVkZWQgd2hlbiBpbXBsZW1lbnRpbmcgbGVhcCBzZWNvbmRzXG4gICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBiYXNpY3NfMS5UaW1lU3RydWN0KG1hdGgucm91bmRTeW0odG0udW5peE1pbGxpcyArIGFtb3VudCAqIDg2NDAwMDAwKSk7XG4gICAgICAgICAgICBjYXNlIGJhc2ljc18xLlRpbWVVbml0LldlZWs6XG4gICAgICAgICAgICAgICAgLy8gdG9kbyBtb3JlIGludGVsbGlnZW50IGFwcHJvYWNoIG5lZWRlZCB3aGVuIGltcGxlbWVudGluZyBsZWFwIHNlY29uZHNcbiAgICAgICAgICAgICAgICByZXR1cm4gbmV3IGJhc2ljc18xLlRpbWVTdHJ1Y3QobWF0aC5yb3VuZFN5bSh0bS51bml4TWlsbGlzICsgYW1vdW50ICogNyAqIDg2NDAwMDAwKSk7XG4gICAgICAgICAgICBjYXNlIGJhc2ljc18xLlRpbWVVbml0Lk1vbnRoOiB7XG4gICAgICAgICAgICAgICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKG1hdGguaXNJbnQoYW1vdW50KSwgXCJBcmd1bWVudC5BbW91bnRcIiwgXCJDYW5ub3QgYWRkL3N1YiBhIG5vbi1pbnRlZ2VyIGFtb3VudCBvZiBtb250aHNcIik7XG4gICAgICAgICAgICAgICAgLy8ga2VlcCB0aGUgZGF5LW9mLW1vbnRoIHRoZSBzYW1lIChjbGFtcCB0byBlbmQtb2YtbW9udGgpXG4gICAgICAgICAgICAgICAgaWYgKGFtb3VudCA+PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgIHllYXIgPSB0bS5jb21wb25lbnRzLnllYXIgKyBNYXRoLmNlaWwoKGFtb3VudCAtICgxMiAtIHRtLmNvbXBvbmVudHMubW9udGgpKSAvIDEyKTtcbiAgICAgICAgICAgICAgICAgICAgbW9udGggPSAxICsgbWF0aC5wb3NpdGl2ZU1vZHVsbygodG0uY29tcG9uZW50cy5tb250aCAtIDEgKyBNYXRoLmZsb29yKGFtb3VudCkpLCAxMik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICB5ZWFyID0gdG0uY29tcG9uZW50cy55ZWFyICsgTWF0aC5mbG9vcigoYW1vdW50ICsgKHRtLmNvbXBvbmVudHMubW9udGggLSAxKSkgLyAxMik7XG4gICAgICAgICAgICAgICAgICAgIG1vbnRoID0gMSArIG1hdGgucG9zaXRpdmVNb2R1bG8oKHRtLmNvbXBvbmVudHMubW9udGggLSAxICsgTWF0aC5jZWlsKGFtb3VudCkpLCAxMik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGRheSA9IE1hdGgubWluKHRtLmNvbXBvbmVudHMuZGF5LCBiYXNpY3MuZGF5c0luTW9udGgoeWVhciwgbW9udGgpKTtcbiAgICAgICAgICAgICAgICBob3VyID0gdG0uY29tcG9uZW50cy5ob3VyO1xuICAgICAgICAgICAgICAgIG1pbnV0ZSA9IHRtLmNvbXBvbmVudHMubWludXRlO1xuICAgICAgICAgICAgICAgIHNlY29uZCA9IHRtLmNvbXBvbmVudHMuc2Vjb25kO1xuICAgICAgICAgICAgICAgIG1pbGxpID0gdG0uY29tcG9uZW50cy5taWxsaTtcbiAgICAgICAgICAgICAgICByZXR1cm4gbmV3IGJhc2ljc18xLlRpbWVTdHJ1Y3QoeyB5ZWFyOiB5ZWFyLCBtb250aDogbW9udGgsIGRheTogZGF5LCBob3VyOiBob3VyLCBtaW51dGU6IG1pbnV0ZSwgc2Vjb25kOiBzZWNvbmQsIG1pbGxpOiBtaWxsaSB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhc2UgYmFzaWNzXzEuVGltZVVuaXQuWWVhcjoge1xuICAgICAgICAgICAgICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KShtYXRoLmlzSW50KGFtb3VudCksIFwiQXJndW1lbnQuQW1vdW50XCIsIFwiQ2Fubm90IGFkZC9zdWIgYSBub24taW50ZWdlciBhbW91bnQgb2YgeWVhcnNcIik7XG4gICAgICAgICAgICAgICAgeWVhciA9IHRtLmNvbXBvbmVudHMueWVhciArIGFtb3VudDtcbiAgICAgICAgICAgICAgICBtb250aCA9IHRtLmNvbXBvbmVudHMubW9udGg7XG4gICAgICAgICAgICAgICAgZGF5ID0gTWF0aC5taW4odG0uY29tcG9uZW50cy5kYXksIGJhc2ljcy5kYXlzSW5Nb250aCh5ZWFyLCBtb250aCkpO1xuICAgICAgICAgICAgICAgIGhvdXIgPSB0bS5jb21wb25lbnRzLmhvdXI7XG4gICAgICAgICAgICAgICAgbWludXRlID0gdG0uY29tcG9uZW50cy5taW51dGU7XG4gICAgICAgICAgICAgICAgc2Vjb25kID0gdG0uY29tcG9uZW50cy5zZWNvbmQ7XG4gICAgICAgICAgICAgICAgbWlsbGkgPSB0bS5jb21wb25lbnRzLm1pbGxpO1xuICAgICAgICAgICAgICAgIHJldHVybiBuZXcgYmFzaWNzXzEuVGltZVN0cnVjdCh7IHllYXI6IHllYXIsIG1vbnRoOiBtb250aCwgZGF5OiBkYXksIGhvdXI6IGhvdXIsIG1pbnV0ZTogbWludXRlLCBzZWNvbmQ6IHNlY29uZCwgbWlsbGk6IG1pbGxpIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbiAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbiAgICAgICAgICAgICAgICByZXR1cm4gKDAsIGVycm9yXzEudGhyb3dFcnJvcikoXCJBcmd1bWVudC5Vbml0XCIsIFwiaW52YWxpZCB0aW1lIHVuaXRcIik7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIERhdGVUaW1lLnByb3RvdHlwZS5zdWIgPSBmdW5jdGlvbiAoYTEsIHVuaXQpIHtcbiAgICAgICAgaWYgKHR5cGVvZiBhMSA9PT0gXCJudW1iZXJcIikge1xuICAgICAgICAgICAgdmFyIGFtb3VudCA9IGExO1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuYWRkKC0xICogYW1vdW50LCB1bml0KTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHZhciBkdXJhdGlvbiA9IGExO1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuYWRkKGR1cmF0aW9uLm11bHRpcGx5KC0xKSk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIERhdGVUaW1lLnByb3RvdHlwZS5zdWJMb2NhbCA9IGZ1bmN0aW9uIChhMSwgdW5pdCkge1xuICAgICAgICBpZiAodHlwZW9mIGExID09PSBcIm51bWJlclwiKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5hZGRMb2NhbCgtMSAqIGExLCB1bml0KTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmFkZExvY2FsKGExLm11bHRpcGx5KC0xKSk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFRpbWUgZGlmZmVyZW5jZSBiZXR3ZWVuIHR3byBEYXRlVGltZXNcbiAgICAgKiBAcmV0dXJuIHRoaXMgLSBvdGhlclxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIERhdGVUaW1lLnByb3RvdHlwZS5kaWZmID0gZnVuY3Rpb24gKG90aGVyKSB7XG4gICAgICAgIHJldHVybiBuZXcgZHVyYXRpb25fMS5EdXJhdGlvbih0aGlzLnV0Y0RhdGUudW5peE1pbGxpcyAtIG90aGVyLnV0Y0RhdGUudW5peE1pbGxpcyk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBDaG9wcyBvZmYgdGhlIHRpbWUgcGFydCwgeWllbGRzIHRoZSBzYW1lIGRhdGUgYXQgMDA6MDA6MDAuMDAwXG4gICAgICogQHJldHVybiBhIG5ldyBEYXRlVGltZVxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIERhdGVUaW1lLnByb3RvdHlwZS5zdGFydE9mRGF5ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gbmV3IERhdGVUaW1lKHRoaXMueWVhcigpLCB0aGlzLm1vbnRoKCksIHRoaXMuZGF5KCksIDAsIDAsIDAsIDAsIHRoaXMuem9uZSgpKTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIGZpcnN0IGRheSBvZiB0aGUgbW9udGggYXQgMDA6MDA6MDBcbiAgICAgKiBAcmV0dXJuIGEgbmV3IERhdGVUaW1lXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgRGF0ZVRpbWUucHJvdG90eXBlLnN0YXJ0T2ZNb250aCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIG5ldyBEYXRlVGltZSh0aGlzLnllYXIoKSwgdGhpcy5tb250aCgpLCAxLCAwLCAwLCAwLCAwLCB0aGlzLnpvbmUoKSk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBmaXJzdCBkYXkgb2YgdGhlIHllYXIgYXQgMDA6MDA6MDBcbiAgICAgKiBAcmV0dXJuIGEgbmV3IERhdGVUaW1lXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgRGF0ZVRpbWUucHJvdG90eXBlLnN0YXJ0T2ZZZWFyID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gbmV3IERhdGVUaW1lKHRoaXMueWVhcigpLCAxLCAxLCAwLCAwLCAwLCAwLCB0aGlzLnpvbmUoKSk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBAcmV0dXJuIFRydWUgaWZmICh0aGlzIDwgb3RoZXIpXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgRGF0ZVRpbWUucHJvdG90eXBlLmxlc3NUaGFuID0gZnVuY3Rpb24gKG90aGVyKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnV0Y0RhdGUudW5peE1pbGxpcyA8IG90aGVyLnV0Y0RhdGUudW5peE1pbGxpcztcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIEByZXR1cm4gVHJ1ZSBpZmYgKHRoaXMgPD0gb3RoZXIpXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgRGF0ZVRpbWUucHJvdG90eXBlLmxlc3NFcXVhbCA9IGZ1bmN0aW9uIChvdGhlcikge1xuICAgICAgICByZXR1cm4gdGhpcy51dGNEYXRlLnVuaXhNaWxsaXMgPD0gb3RoZXIudXRjRGF0ZS51bml4TWlsbGlzO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogQHJldHVybiBUcnVlIGlmZiB0aGlzIGFuZCBvdGhlciByZXByZXNlbnQgdGhlIHNhbWUgbW9tZW50IGluIHRpbWUgaW4gVVRDXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgRGF0ZVRpbWUucHJvdG90eXBlLmVxdWFscyA9IGZ1bmN0aW9uIChvdGhlcikge1xuICAgICAgICByZXR1cm4gdGhpcy51dGNEYXRlLmVxdWFscyhvdGhlci51dGNEYXRlKTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIEByZXR1cm4gVHJ1ZSBpZmYgdGhpcyBhbmQgb3RoZXIgcmVwcmVzZW50IHRoZSBzYW1lIHRpbWUgYW5kIHRoZSBzYW1lIHpvbmVcbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBEYXRlVGltZS5wcm90b3R5cGUuaWRlbnRpY2FsID0gZnVuY3Rpb24gKG90aGVyKSB7XG4gICAgICAgIHJldHVybiAhISh0aGlzLnpvbmVEYXRlLmVxdWFscyhvdGhlci56b25lRGF0ZSlcbiAgICAgICAgICAgICYmICghdGhpcy5fem9uZSkgPT09ICghb3RoZXIuX3pvbmUpXG4gICAgICAgICAgICAmJiAoKCF0aGlzLl96b25lICYmICFvdGhlci5fem9uZSkgfHwgKHRoaXMuX3pvbmUgJiYgb3RoZXIuX3pvbmUgJiYgdGhpcy5fem9uZS5pZGVudGljYWwob3RoZXIuX3pvbmUpKSkpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogQHJldHVybiBUcnVlIGlmZiB0aGlzID4gb3RoZXJcbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBEYXRlVGltZS5wcm90b3R5cGUuZ3JlYXRlclRoYW4gPSBmdW5jdGlvbiAob3RoZXIpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMudXRjRGF0ZS51bml4TWlsbGlzID4gb3RoZXIudXRjRGF0ZS51bml4TWlsbGlzO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogQHJldHVybiBUcnVlIGlmZiB0aGlzID49IG90aGVyXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgRGF0ZVRpbWUucHJvdG90eXBlLmdyZWF0ZXJFcXVhbCA9IGZ1bmN0aW9uIChvdGhlcikge1xuICAgICAgICByZXR1cm4gdGhpcy51dGNEYXRlLnVuaXhNaWxsaXMgPj0gb3RoZXIudXRjRGF0ZS51bml4TWlsbGlzO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogQHJldHVybiBUaGUgbWluaW11bSBvZiB0aGlzIGFuZCBvdGhlclxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIERhdGVUaW1lLnByb3RvdHlwZS5taW4gPSBmdW5jdGlvbiAob3RoZXIpIHtcbiAgICAgICAgaWYgKHRoaXMubGVzc1RoYW4ob3RoZXIpKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5jbG9uZSgpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBvdGhlci5jbG9uZSgpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogQHJldHVybiBUaGUgbWF4aW11bSBvZiB0aGlzIGFuZCBvdGhlclxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIERhdGVUaW1lLnByb3RvdHlwZS5tYXggPSBmdW5jdGlvbiAob3RoZXIpIHtcbiAgICAgICAgaWYgKHRoaXMuZ3JlYXRlclRoYW4ob3RoZXIpKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5jbG9uZSgpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBvdGhlci5jbG9uZSgpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogUHJvcGVyIElTTyA4NjAxIGZvcm1hdCBzdHJpbmcgd2l0aCBhbnkgSUFOQSB6b25lIGNvbnZlcnRlZCB0byBJU08gb2Zmc2V0XG4gICAgICogRS5nLiBcIjIwMTQtMDEtMDFUMjM6MTU6MzMrMDE6MDBcIiBmb3IgRXVyb3BlL0Ftc3RlcmRhbVxuICAgICAqIFVuYXdhcmUgZGF0ZXMgaGF2ZSBubyB6b25lIGluZm9ybWF0aW9uIGF0IHRoZSBlbmQuXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgRGF0ZVRpbWUucHJvdG90eXBlLnRvSXNvU3RyaW5nID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgcyA9IHRoaXMuem9uZURhdGUudG9TdHJpbmcoKTtcbiAgICAgICAgaWYgKHRoaXMuX3pvbmUpIHtcbiAgICAgICAgICAgIHJldHVybiBzICsgdGltZXpvbmVfMS5UaW1lWm9uZS5vZmZzZXRUb1N0cmluZyh0aGlzLm9mZnNldCgpKTsgLy8gY29udmVydCBJQU5BIG5hbWUgdG8gb2Zmc2V0XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gczsgLy8gbm8gem9uZSBwcmVzZW50XG4gICAgICAgIH1cbiAgICB9O1xuICAgIC8qKlxuICAgICAqIENvbnZlcnQgdG8gVVRDIGFuZCB0aGVuIHJldHVybiBJU08gc3RyaW5nIGVuZGluZyBpbiAnWicuIFRoaXMgaXMgZXF1aXZhbGVudCB0byBEYXRlI3RvSVNPU3RyaW5nKClcbiAgICAgKiBlLmcuIFwiMjAxNC0wMS0wMVQyMzoxNTozMyBFdXJvcGUvQW1zdGVyZGFtXCIgYmVjb21lcyBcIjIwMTQtMDEtMDFUMjI6MTU6MzNaXCIuXG4gICAgICogVW5hd2FyZSBkYXRlcyBhcmUgYXNzdW1lZCB0byBiZSBpbiBVVENcbiAgICAgKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuTm90Rm91bmQuWm9uZSBpZiB0aGUgVVRDIHRpbWUgem9uZSBkb2Vzbid0IGV4aXN0IGluIHRoZSB0aW1lIHpvbmUgZGF0YWJhc2VcbiAgICAgKi9cbiAgICBEYXRlVGltZS5wcm90b3R5cGUudG9VdGNJc29TdHJpbmcgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICh0aGlzLl96b25lKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy50b1pvbmUodGltZXpvbmVfMS5UaW1lWm9uZS51dGMoKSkuZm9ybWF0KFwieXl5eS1NTS1kZFRISDptbTpzcy5TU1NaWlpaWlwiKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLndpdGhab25lKHRpbWV6b25lXzEuVGltZVpvbmUudXRjKCkpLmZvcm1hdChcInl5eXktTU0tZGRUSEg6bW06c3MuU1NTWlpaWlpcIik7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFJldHVybiBhIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGUgRGF0ZVRpbWUgYWNjb3JkaW5nIHRvIHRoZVxuICAgICAqIHNwZWNpZmllZCBmb3JtYXQuIFNlZSBMRE1MLm1kIGZvciBzdXBwb3J0ZWQgZm9ybWF0cy5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBmb3JtYXRTdHJpbmcgVGhlIGZvcm1hdCBzcGVjaWZpY2F0aW9uIChlLmcuIFwiZGQvTU0veXl5eSBISDptbTpzc1wiKVxuICAgICAqIEBwYXJhbSBsb2NhbGUgT3B0aW9uYWwsIG5vbi1lbmdsaXNoIGZvcm1hdCBtb250aCBuYW1lcyBldGMuXG4gICAgICogQHJldHVybiBUaGUgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoaXMgRGF0ZVRpbWVcbiAgICAgKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuRm9ybWF0U3RyaW5nIGZvciBpbnZhbGlkIGZvcm1hdCBwYXR0ZXJuXG4gICAgICovXG4gICAgRGF0ZVRpbWUucHJvdG90eXBlLmZvcm1hdCA9IGZ1bmN0aW9uIChmb3JtYXRTdHJpbmcsIGxvY2FsZSkge1xuICAgICAgICByZXR1cm4gZm9ybWF0LmZvcm1hdCh0aGlzLnpvbmVEYXRlLCB0aGlzLnV0Y0RhdGUsIHRoaXMuX3pvbmUsIGZvcm1hdFN0cmluZywgbG9jYWxlKTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFBhcnNlIGEgZGF0ZSBpbiBhIGdpdmVuIGZvcm1hdFxuICAgICAqIEBwYXJhbSBzIHRoZSBzdHJpbmcgdG8gcGFyc2VcbiAgICAgKiBAcGFyYW0gZm9ybWF0IHRoZSBmb3JtYXQgdGhlIHN0cmluZyBpcyBpbi4gU2VlIExETUwubWQgZm9yIHN1cHBvcnRlZCBmb3JtYXRzLlxuICAgICAqIEBwYXJhbSB6b25lIE9wdGlvbmFsLCB0aGUgem9uZSB0byBhZGQgKGlmIG5vIHpvbmUgaXMgZ2l2ZW4gaW4gdGhlIHN0cmluZylcbiAgICAgKiBAcGFyYW0gbG9jYWxlIE9wdGlvbmFsLCBkaWZmZXJlbnQgc2V0dGluZ3MgZm9yIGNvbnN0YW50cyBsaWtlICdBTScgZXRjXG4gICAgICogQHBhcmFtIGFsbG93VHJhaWxpbmcgQWxsb3cgdHJhaWxpbmcgY2hhcmFjdGVycyBpbiB0aGUgc291cmNlIHN0cmluZ1xuICAgICAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5QYXJzZUVycm9yIGlmIHRoZSBnaXZlbiBkYXRlVGltZVN0cmluZyBpcyB3cm9uZyBvciBub3QgYWNjb3JkaW5nIHRvIHRoZSBwYXR0ZXJuXG4gICAgICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LkZvcm1hdFN0cmluZyBpZiB0aGUgZ2l2ZW4gZm9ybWF0IHN0cmluZyBpcyBpbnZhbGlkXG4gICAgICovXG4gICAgRGF0ZVRpbWUucGFyc2UgPSBmdW5jdGlvbiAocywgZm9ybWF0LCB6b25lLCBsb2NhbGUsIGFsbG93VHJhaWxpbmcpIHtcbiAgICAgICAgdmFyIHBhcnNlZCA9IHBhcnNlRnVuY3MucGFyc2UocywgZm9ybWF0LCB6b25lLCBhbGxvd1RyYWlsaW5nIHx8IGZhbHNlLCBsb2NhbGUpO1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgcmV0dXJuIG5ldyBEYXRlVGltZShwYXJzZWQudGltZSwgcGFyc2VkLnpvbmUpO1xuICAgICAgICB9XG4gICAgICAgIGNhdGNoIChlKSB7XG4gICAgICAgICAgICBpZiAoISgwLCBlcnJvcl8xLmVycm9ySXMpKGUsIFwiSW52YWxpZFRpbWVab25lRGF0YVwiKSkge1xuICAgICAgICAgICAgICAgIGUgPSAoMCwgZXJyb3JfMS5lcnJvcikoXCJQYXJzZUVycm9yXCIsIGUubWVzc2FnZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aHJvdyBlO1xuICAgICAgICB9XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBNb2RpZmllZCBJU08gODYwMSBmb3JtYXQgc3RyaW5nIHdpdGggSUFOQSBuYW1lIGlmIGFwcGxpY2FibGUuXG4gICAgICogRS5nLiBcIjIwMTQtMDEtMDFUMjM6MTU6MzMuMDAwIEV1cm9wZS9BbXN0ZXJkYW1cIlxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIERhdGVUaW1lLnByb3RvdHlwZS50b1N0cmluZyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHMgPSB0aGlzLnpvbmVEYXRlLnRvU3RyaW5nKCk7XG4gICAgICAgIGlmICh0aGlzLl96b25lKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5fem9uZS5raW5kKCkgIT09IHRpbWV6b25lXzEuVGltZVpvbmVLaW5kLk9mZnNldCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBzICsgXCIgXCIgKyB0aGlzLl96b25lLnRvU3RyaW5nKCk7IC8vIHNlcGFyYXRlIElBTkEgbmFtZSBvciBcImxvY2FsdGltZVwiIHdpdGggYSBzcGFjZVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHMgKyB0aGlzLl96b25lLnRvU3RyaW5nKCk7IC8vIGRvIG5vdCBzZXBhcmF0ZSBJU08gem9uZVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIHM7IC8vIG5vIHpvbmUgcHJlc2VudFxuICAgICAgICB9XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBUaGUgdmFsdWVPZigpIG1ldGhvZCByZXR1cm5zIHRoZSBwcmltaXRpdmUgdmFsdWUgb2YgdGhlIHNwZWNpZmllZCBvYmplY3QuXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgRGF0ZVRpbWUucHJvdG90eXBlLnZhbHVlT2YgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnVuaXhVdGNNaWxsaXMoKTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIE1vZGlmaWVkIElTTyA4NjAxIGZvcm1hdCBzdHJpbmcgaW4gVVRDIHdpdGhvdXQgdGltZSB6b25lIGluZm9cbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBEYXRlVGltZS5wcm90b3R5cGUudG9VdGNTdHJpbmcgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnV0Y0RhdGUudG9TdHJpbmcoKTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFNwbGl0IGEgY29tYmluZWQgSVNPIGRhdGV0aW1lIGFuZCB0aW1lem9uZSBpbnRvIGRhdGV0aW1lIGFuZCB0aW1lem9uZVxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIERhdGVUaW1lLl9zcGxpdERhdGVGcm9tVGltZVpvbmUgPSBmdW5jdGlvbiAocykge1xuICAgICAgICB2YXIgdHJpbW1lZCA9IHMudHJpbSgpO1xuICAgICAgICB2YXIgcmVzdWx0ID0gW1wiXCIsIFwiXCJdO1xuICAgICAgICB2YXIgaW5kZXggPSB0cmltbWVkLmxhc3RJbmRleE9mKFwid2l0aG91dCBEU1RcIik7XG4gICAgICAgIGlmIChpbmRleCA+IC0xKSB7XG4gICAgICAgICAgICB2YXIgcmVzdWx0XzEgPSBEYXRlVGltZS5fc3BsaXREYXRlRnJvbVRpbWVab25lKHMuc2xpY2UoMCwgaW5kZXggLSAxKSk7XG4gICAgICAgICAgICByZXN1bHRfMVsxXSArPSBcIiB3aXRob3V0IERTVFwiO1xuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdF8xO1xuICAgICAgICB9XG4gICAgICAgIGluZGV4ID0gdHJpbW1lZC5sYXN0SW5kZXhPZihcIiBcIik7XG4gICAgICAgIGlmIChpbmRleCA+IC0xKSB7XG4gICAgICAgICAgICByZXN1bHRbMF0gPSB0cmltbWVkLnN1YnN0cigwLCBpbmRleCk7XG4gICAgICAgICAgICByZXN1bHRbMV0gPSB0cmltbWVkLnN1YnN0cihpbmRleCArIDEpO1xuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfVxuICAgICAgICBpbmRleCA9IHRyaW1tZWQubGFzdEluZGV4T2YoXCJaXCIpO1xuICAgICAgICBpZiAoaW5kZXggPiAtMSkge1xuICAgICAgICAgICAgcmVzdWx0WzBdID0gdHJpbW1lZC5zdWJzdHIoMCwgaW5kZXgpO1xuICAgICAgICAgICAgcmVzdWx0WzFdID0gdHJpbW1lZC5zdWJzdHIoaW5kZXgsIDEpO1xuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfVxuICAgICAgICBpbmRleCA9IHRyaW1tZWQubGFzdEluZGV4T2YoXCIrXCIpO1xuICAgICAgICBpZiAoaW5kZXggPiAtMSkge1xuICAgICAgICAgICAgcmVzdWx0WzBdID0gdHJpbW1lZC5zdWJzdHIoMCwgaW5kZXgpO1xuICAgICAgICAgICAgcmVzdWx0WzFdID0gdHJpbW1lZC5zdWJzdHIoaW5kZXgpO1xuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfVxuICAgICAgICBpbmRleCA9IHRyaW1tZWQubGFzdEluZGV4T2YoXCItXCIpO1xuICAgICAgICBpZiAoaW5kZXggPCA4KSB7XG4gICAgICAgICAgICBpbmRleCA9IC0xOyAvLyBhbnkgXCItXCIgd2UgZm91bmQgd2FzIGEgZGF0ZSBzZXBhcmF0b3JcbiAgICAgICAgfVxuICAgICAgICBpZiAoaW5kZXggPiAtMSkge1xuICAgICAgICAgICAgcmVzdWx0WzBdID0gdHJpbW1lZC5zdWJzdHIoMCwgaW5kZXgpO1xuICAgICAgICAgICAgcmVzdWx0WzFdID0gdHJpbW1lZC5zdWJzdHIoaW5kZXgpO1xuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfVxuICAgICAgICByZXN1bHRbMF0gPSB0cmltbWVkO1xuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH07XG4gICAgLyoqXG4gICAgICogQWN0dWFsIHRpbWUgc291cmNlIGluIHVzZS4gU2V0dGluZyB0aGlzIHByb3BlcnR5IGFsbG93cyB0b1xuICAgICAqIGZha2UgdGltZSBpbiB0ZXN0cy4gRGF0ZVRpbWUubm93TG9jYWwoKSBhbmQgRGF0ZVRpbWUubm93VXRjKClcbiAgICAgKiB1c2UgdGhpcyBwcm9wZXJ0eSBmb3Igb2J0YWluaW5nIHRoZSBjdXJyZW50IHRpbWUuXG4gICAgICovXG4gICAgRGF0ZVRpbWUudGltZVNvdXJjZSA9IG5ldyB0aW1lc291cmNlXzEuUmVhbFRpbWVTb3VyY2UoKTtcbiAgICByZXR1cm4gRGF0ZVRpbWU7XG59KCkpO1xuZXhwb3J0cy5EYXRlVGltZSA9IERhdGVUaW1lO1xuLyoqXG4gKiBDaGVja3Mgd2hldGhlciBgYWAgaXMgc2ltaWxhciB0byBhIFRpbWVab25lIHdpdGhvdXQgdXNpbmcgdGhlIGluc3RhbmNlb2Ygb3BlcmF0b3IuXG4gKiBJdCBjaGVja3MgZm9yIHRoZSBhdmFpbGFiaWxpdHkgb2YgdGhlIGZ1bmN0aW9ucyB1c2VkIGluIHRoZSBEYXRlVGltZSBpbXBsZW1lbnRhdGlvblxuICogQHBhcmFtIGEgdGhlIG9iamVjdCB0byBjaGVja1xuICogQHJldHVybnMgYSBpcyBUaW1lWm9uZS1saWtlXG4gKiBAdGhyb3dzIG5vdGhpbmdcbiAqL1xuZnVuY3Rpb24gaXNUaW1lWm9uZShhKSB7XG4gICAgaWYgKGEgJiYgdHlwZW9mIGEgPT09IFwib2JqZWN0XCIpIHtcbiAgICAgICAgaWYgKHR5cGVvZiBhLm5vcm1hbGl6ZVpvbmVUaW1lID09PSBcImZ1bmN0aW9uXCJcbiAgICAgICAgICAgICYmIHR5cGVvZiBhLmFiYnJldmlhdGlvbkZvclV0YyA9PT0gXCJmdW5jdGlvblwiXG4gICAgICAgICAgICAmJiB0eXBlb2YgYS5zdGFuZGFyZE9mZnNldEZvclV0YyA9PT0gXCJmdW5jdGlvblwiXG4gICAgICAgICAgICAmJiB0eXBlb2YgYS5pZGVudGljYWwgPT09IFwiZnVuY3Rpb25cIlxuICAgICAgICAgICAgJiYgdHlwZW9mIGEuZXF1YWxzID09PSBcImZ1bmN0aW9uXCJcbiAgICAgICAgICAgICYmIHR5cGVvZiBhLmtpbmQgPT09IFwiZnVuY3Rpb25cIlxuICAgICAgICAgICAgJiYgdHlwZW9mIGEuY2xvbmUgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xufVxuLyoqXG4gKiBDaGVja3MgaWYgYSBnaXZlbiBvYmplY3QgaXMgb2YgdHlwZSBEYXRlVGltZS4gTm90ZSB0aGF0IGl0IGRvZXMgbm90IHdvcmsgZm9yIHN1YiBjbGFzc2VzLiBIb3dldmVyLCB1c2UgdGhpcyB0byBiZSByb2J1c3RcbiAqIGFnYWluc3QgZGlmZmVyZW50IHZlcnNpb25zIG9mIHRoZSBsaWJyYXJ5IGluIG9uZSBwcm9jZXNzIGluc3RlYWQgb2YgaW5zdGFuY2VvZlxuICogQHBhcmFtIHZhbHVlIFZhbHVlIHRvIGNoZWNrXG4gKiBAdGhyb3dzIG5vdGhpbmdcbiAqL1xuZnVuY3Rpb24gaXNEYXRlVGltZSh2YWx1ZSkge1xuICAgIHJldHVybiB0eXBlb2YgdmFsdWUgPT09IFwib2JqZWN0XCIgJiYgdmFsdWUgIT09IG51bGwgJiYgdmFsdWUua2luZCA9PT0gXCJEYXRlVGltZVwiO1xufVxuZXhwb3J0cy5pc0RhdGVUaW1lID0gaXNEYXRlVGltZTtcbi8vIyBzb3VyY2VNYXBwaW5nVVJMPWRhdGV0aW1lLmpzLm1hcCIsIi8qKlxuICogQ29weXJpZ2h0KGMpIDIwMTQgQUJCIFN3aXR6ZXJsYW5kIEx0ZC5cbiAqXG4gKiBUaW1lIGR1cmF0aW9uXG4gKi9cblwidXNlIHN0cmljdFwiO1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7IHZhbHVlOiB0cnVlIH0pO1xuZXhwb3J0cy5pc0R1cmF0aW9uID0gZXhwb3J0cy5EdXJhdGlvbiA9IGV4cG9ydHMubWlsbGlzZWNvbmRzID0gZXhwb3J0cy5zZWNvbmRzID0gZXhwb3J0cy5taW51dGVzID0gZXhwb3J0cy5ob3VycyA9IGV4cG9ydHMuZGF5cyA9IGV4cG9ydHMubW9udGhzID0gZXhwb3J0cy55ZWFycyA9IHZvaWQgMDtcbnZhciBhc3NlcnRfMSA9IHJlcXVpcmUoXCIuL2Fzc2VydFwiKTtcbnZhciBiYXNpY3NfMSA9IHJlcXVpcmUoXCIuL2Jhc2ljc1wiKTtcbnZhciBiYXNpY3MgPSByZXF1aXJlKFwiLi9iYXNpY3NcIik7XG52YXIgc3RyaW5ncyA9IHJlcXVpcmUoXCIuL3N0cmluZ3NcIik7XG4vKipcbiAqIENvbnN0cnVjdCBhIHRpbWUgZHVyYXRpb25cbiAqIEBwYXJhbSBuXHROdW1iZXIgb2YgeWVhcnMgKG1heSBiZSBmcmFjdGlvbmFsIG9yIG5lZ2F0aXZlKVxuICogQHJldHVybiBBIGR1cmF0aW9uIG9mIG4geWVhcnNcbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5BbW91bnQgaWYgbiBpcyBub3QgYSBmaW5pdGUgbnVtYmVyXG4gKi9cbmZ1bmN0aW9uIHllYXJzKG4pIHtcbiAgICByZXR1cm4gRHVyYXRpb24ueWVhcnMobik7XG59XG5leHBvcnRzLnllYXJzID0geWVhcnM7XG4vKipcbiAqIENvbnN0cnVjdCBhIHRpbWUgZHVyYXRpb25cbiAqIEBwYXJhbSBuXHROdW1iZXIgb2YgbW9udGhzIChtYXkgYmUgZnJhY3Rpb25hbCBvciBuZWdhdGl2ZSlcbiAqIEByZXR1cm4gQSBkdXJhdGlvbiBvZiBuIG1vbnRoc1xuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LkFtb3VudCBpZiBuIGlzIG5vdCBhIGZpbml0ZSBudW1iZXJcbiAqL1xuZnVuY3Rpb24gbW9udGhzKG4pIHtcbiAgICByZXR1cm4gRHVyYXRpb24ubW9udGhzKG4pO1xufVxuZXhwb3J0cy5tb250aHMgPSBtb250aHM7XG4vKipcbiAqIENvbnN0cnVjdCBhIHRpbWUgZHVyYXRpb25cbiAqIEBwYXJhbSBuXHROdW1iZXIgb2YgZGF5cyAobWF5IGJlIGZyYWN0aW9uYWwgb3IgbmVnYXRpdmUpXG4gKiBAcmV0dXJuIEEgZHVyYXRpb24gb2YgbiBkYXlzXG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuQW1vdW50IGlmIG4gaXMgbm90IGEgZmluaXRlIG51bWJlclxuICovXG5mdW5jdGlvbiBkYXlzKG4pIHtcbiAgICByZXR1cm4gRHVyYXRpb24uZGF5cyhuKTtcbn1cbmV4cG9ydHMuZGF5cyA9IGRheXM7XG4vKipcbiAqIENvbnN0cnVjdCBhIHRpbWUgZHVyYXRpb25cbiAqIEBwYXJhbSBuXHROdW1iZXIgb2YgaG91cnMgKG1heSBiZSBmcmFjdGlvbmFsIG9yIG5lZ2F0aXZlKVxuICogQHJldHVybiBBIGR1cmF0aW9uIG9mIG4gaG91cnNcbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5BbW91bnQgaWYgbiBpcyBub3QgYSBmaW5pdGUgbnVtYmVyXG4gKi9cbmZ1bmN0aW9uIGhvdXJzKG4pIHtcbiAgICByZXR1cm4gRHVyYXRpb24uaG91cnMobik7XG59XG5leHBvcnRzLmhvdXJzID0gaG91cnM7XG4vKipcbiAqIENvbnN0cnVjdCBhIHRpbWUgZHVyYXRpb25cbiAqIEBwYXJhbSBuXHROdW1iZXIgb2YgbWludXRlcyAobWF5IGJlIGZyYWN0aW9uYWwgb3IgbmVnYXRpdmUpXG4gKiBAcmV0dXJuIEEgZHVyYXRpb24gb2YgbiBtaW51dGVzXG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuQW1vdW50IGlmIG4gaXMgbm90IGEgZmluaXRlIG51bWJlclxuICovXG5mdW5jdGlvbiBtaW51dGVzKG4pIHtcbiAgICByZXR1cm4gRHVyYXRpb24ubWludXRlcyhuKTtcbn1cbmV4cG9ydHMubWludXRlcyA9IG1pbnV0ZXM7XG4vKipcbiAqIENvbnN0cnVjdCBhIHRpbWUgZHVyYXRpb25cbiAqIEBwYXJhbSBuXHROdW1iZXIgb2Ygc2Vjb25kcyAobWF5IGJlIGZyYWN0aW9uYWwgb3IgbmVnYXRpdmUpXG4gKiBAcmV0dXJuIEEgZHVyYXRpb24gb2YgbiBzZWNvbmRzXG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuQW1vdW50IGlmIG4gaXMgbm90IGEgZmluaXRlIG51bWJlclxuICovXG5mdW5jdGlvbiBzZWNvbmRzKG4pIHtcbiAgICByZXR1cm4gRHVyYXRpb24uc2Vjb25kcyhuKTtcbn1cbmV4cG9ydHMuc2Vjb25kcyA9IHNlY29uZHM7XG4vKipcbiAqIENvbnN0cnVjdCBhIHRpbWUgZHVyYXRpb25cbiAqIEBwYXJhbSBuXHROdW1iZXIgb2YgbWlsbGlzZWNvbmRzIChtYXkgYmUgZnJhY3Rpb25hbCBvciBuZWdhdGl2ZSlcbiAqIEByZXR1cm4gQSBkdXJhdGlvbiBvZiBuIG1pbGxpc2Vjb25kc1xuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LkFtb3VudCBpZiBuIGlzIG5vdCBhIGZpbml0ZSBudW1iZXJcbiAqL1xuZnVuY3Rpb24gbWlsbGlzZWNvbmRzKG4pIHtcbiAgICByZXR1cm4gRHVyYXRpb24ubWlsbGlzZWNvbmRzKG4pO1xufVxuZXhwb3J0cy5taWxsaXNlY29uZHMgPSBtaWxsaXNlY29uZHM7XG4vKipcbiAqIFRpbWUgZHVyYXRpb24gd2hpY2ggaXMgcmVwcmVzZW50ZWQgYXMgYW4gYW1vdW50IGFuZCBhIHVuaXQgZS5nLlxuICogJzEgTW9udGgnIG9yICcxNjYgU2Vjb25kcycuIFRoZSB1bml0IGlzIHByZXNlcnZlZCB0aHJvdWdoIGNhbGN1bGF0aW9ucy5cbiAqXG4gKiBJdCBoYXMgdHdvIHNldHMgb2YgZ2V0dGVyIGZ1bmN0aW9uczpcbiAqIC0gc2Vjb25kKCksIG1pbnV0ZSgpLCBob3VyKCkgZXRjLCBzaW5ndWxhciBmb3JtOiB0aGVzZSBjYW4gYmUgdXNlZCB0byBjcmVhdGUgc3RyaW5nIHJlcHJlc2VudGF0aW9ucy5cbiAqICAgVGhlc2UgcmV0dXJuIGEgcGFydCBvZiB5b3VyIHN0cmluZyByZXByZXNlbnRhdGlvbi4gRS5nLiBmb3IgMjUwMCBtaWxsaXNlY29uZHMsIHRoZSBtaWxsaXNlY29uZCgpIHBhcnQgd291bGQgYmUgNTAwXG4gKiAtIHNlY29uZHMoKSwgbWludXRlcygpLCBob3VycygpIGV0YywgcGx1cmFsIGZvcm06IHRoZXNlIHJldHVybiB0aGUgdG90YWwgYW1vdW50IHJlcHJlc2VudGVkIGluIHRoZSBjb3JyZXNwb25kaW5nIHVuaXQuXG4gKi9cbnZhciBEdXJhdGlvbiA9IC8qKiBAY2xhc3MgKi8gKGZ1bmN0aW9uICgpIHtcbiAgICAvKipcbiAgICAgKiBDb25zdHJ1Y3RvciBpbXBsZW1lbnRhdGlvblxuICAgICAqL1xuICAgIGZ1bmN0aW9uIER1cmF0aW9uKGkxLCB1bml0KSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBBbGxvdyBub3QgdXNpbmcgaW5zdGFuY2VvZlxuICAgICAgICAgKi9cbiAgICAgICAgdGhpcy5raW5kID0gXCJEdXJhdGlvblwiO1xuICAgICAgICBpZiAodHlwZW9mIGkxID09PSBcIm51bWJlclwiKSB7XG4gICAgICAgICAgICAvLyBhbW91bnQrdW5pdCBjb25zdHJ1Y3RvclxuICAgICAgICAgICAgdmFyIGFtb3VudCA9IGkxO1xuICAgICAgICAgICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKE51bWJlci5pc0Zpbml0ZShhbW91bnQpLCBcIkFyZ3VtZW50LkFtb3VudFwiLCBcImFtb3VudCBzaG91bGQgYmUgZmluaXRlOiBcIi5jb25jYXQoYW1vdW50KSk7XG4gICAgICAgICAgICB0aGlzLl9hbW91bnQgPSBhbW91bnQ7XG4gICAgICAgICAgICB0aGlzLl91bml0ID0gKHR5cGVvZiB1bml0ID09PSBcIm51bWJlclwiID8gdW5pdCA6IGJhc2ljc18xLlRpbWVVbml0Lk1pbGxpc2Vjb25kKTtcbiAgICAgICAgICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KShOdW1iZXIuaXNJbnRlZ2VyKHRoaXMuX3VuaXQpICYmIHRoaXMuX3VuaXQgPj0gMCAmJiB0aGlzLl91bml0IDwgYmFzaWNzXzEuVGltZVVuaXQuTUFYLCBcIkFyZ3VtZW50LlVuaXRcIiwgXCJJbnZhbGlkIHRpbWUgdW5pdCBcIi5jb25jYXQodGhpcy5fdW5pdCkpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKHR5cGVvZiBpMSA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgLy8gc3RyaW5nIGNvbnN0cnVjdG9yXG4gICAgICAgICAgICB2YXIgcyA9IGkxO1xuICAgICAgICAgICAgdmFyIHRyaW1tZWQgPSBzLnRyaW0oKTtcbiAgICAgICAgICAgIGlmICh0cmltbWVkLm1hdGNoKC9eLT9cXGRcXGQ/KDpcXGRcXGQ/KDpcXGRcXGQ/KC5cXGRcXGQ/XFxkPyk/KT8pPyQvKSkge1xuICAgICAgICAgICAgICAgIHZhciBzaWduID0gMTtcbiAgICAgICAgICAgICAgICB2YXIgaG91cnNfMSA9IDA7XG4gICAgICAgICAgICAgICAgdmFyIG1pbnV0ZXNfMSA9IDA7XG4gICAgICAgICAgICAgICAgdmFyIHNlY29uZHNfMSA9IDA7XG4gICAgICAgICAgICAgICAgdmFyIG1pbGxpc2Vjb25kc18xID0gMDtcbiAgICAgICAgICAgICAgICB2YXIgcGFydHMgPSB0cmltbWVkLnNwbGl0KFwiOlwiKTtcbiAgICAgICAgICAgICAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkocGFydHMubGVuZ3RoID4gMCAmJiBwYXJ0cy5sZW5ndGggPCA0LCBcIkFyZ3VtZW50LlNcIiwgXCJOb3QgYSBwcm9wZXIgdGltZSBkdXJhdGlvbiBzdHJpbmc6IFxcXCJcIiArIHRyaW1tZWQgKyBcIlxcXCJcIik7XG4gICAgICAgICAgICAgICAgaWYgKHRyaW1tZWQuY2hhckF0KDApID09PSBcIi1cIikge1xuICAgICAgICAgICAgICAgICAgICBzaWduID0gLTE7XG4gICAgICAgICAgICAgICAgICAgIHBhcnRzWzBdID0gcGFydHNbMF0uc3Vic3RyKDEpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAocGFydHMubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgICAgICBob3Vyc18xID0gK3BhcnRzWzBdO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAocGFydHMubGVuZ3RoID4gMSkge1xuICAgICAgICAgICAgICAgICAgICBtaW51dGVzXzEgPSArcGFydHNbMV07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmIChwYXJ0cy5sZW5ndGggPiAyKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBzZWNvbmRQYXJ0cyA9IHBhcnRzWzJdLnNwbGl0KFwiLlwiKTtcbiAgICAgICAgICAgICAgICAgICAgc2Vjb25kc18xID0gK3NlY29uZFBhcnRzWzBdO1xuICAgICAgICAgICAgICAgICAgICBpZiAoc2Vjb25kUGFydHMubGVuZ3RoID4gMSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgbWlsbGlzZWNvbmRzXzEgPSArc3RyaW5ncy5wYWRSaWdodChzZWNvbmRQYXJ0c1sxXSwgMywgXCIwXCIpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHZhciBhbW91bnRNc2VjID0gc2lnbiAqIE1hdGgucm91bmQobWlsbGlzZWNvbmRzXzEgKyAxMDAwICogc2Vjb25kc18xICsgNjAwMDAgKiBtaW51dGVzXzEgKyAzNjAwMDAwICogaG91cnNfMSk7XG4gICAgICAgICAgICAgICAgLy8gZmluZCBsb3dlc3Qgbm9uLXplcm8gbnVtYmVyIGFuZCB0YWtlIHRoYXQgYXMgdW5pdFxuICAgICAgICAgICAgICAgIGlmIChtaWxsaXNlY29uZHNfMSAhPT0gMCkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLl91bml0ID0gYmFzaWNzXzEuVGltZVVuaXQuTWlsbGlzZWNvbmQ7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2UgaWYgKHNlY29uZHNfMSAhPT0gMCkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLl91bml0ID0gYmFzaWNzXzEuVGltZVVuaXQuU2Vjb25kO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIGlmIChtaW51dGVzXzEgIT09IDApIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fdW5pdCA9IGJhc2ljc18xLlRpbWVVbml0Lk1pbnV0ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSBpZiAoaG91cnNfMSAhPT0gMCkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLl91bml0ID0gYmFzaWNzXzEuVGltZVVuaXQuSG91cjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX3VuaXQgPSBiYXNpY3NfMS5UaW1lVW5pdC5NaWxsaXNlY29uZDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdGhpcy5fYW1vdW50ID0gYW1vdW50TXNlYyAvIGJhc2ljcy50aW1lVW5pdFRvTWlsbGlzZWNvbmRzKHRoaXMuX3VuaXQpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgdmFyIHNwbGl0ID0gdHJpbW1lZC50b0xvd2VyQ2FzZSgpLnNwbGl0KFwiIFwiKTtcbiAgICAgICAgICAgICAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkoc3BsaXQubGVuZ3RoID09PSAyLCBcIkFyZ3VtZW50LlNcIiwgXCJJbnZhbGlkIHRpbWUgc3RyaW5nICdcIi5jb25jYXQocywgXCInXCIpKTtcbiAgICAgICAgICAgICAgICB2YXIgYW1vdW50ID0gcGFyc2VGbG9hdChzcGxpdFswXSk7XG4gICAgICAgICAgICAgICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKE51bWJlci5pc0Zpbml0ZShhbW91bnQpLCBcIkFyZ3VtZW50LlNcIiwgXCJJbnZhbGlkIHRpbWUgc3RyaW5nICdcIi5jb25jYXQocywgXCInLCBjYW5ub3QgcGFyc2UgYW1vdW50XCIpKTtcbiAgICAgICAgICAgICAgICB0aGlzLl9hbW91bnQgPSBhbW91bnQ7XG4gICAgICAgICAgICAgICAgdGhpcy5fdW5pdCA9IGJhc2ljcy5zdHJpbmdUb1RpbWVVbml0KHNwbGl0WzFdKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChpMSA9PT0gdW5kZWZpbmVkICYmIHVuaXQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgLy8gZGVmYXVsdCBjb25zdHJ1Y3RvclxuICAgICAgICAgICAgdGhpcy5fYW1vdW50ID0gMDtcbiAgICAgICAgICAgIHRoaXMuX3VuaXQgPSBiYXNpY3NfMS5UaW1lVW5pdC5NaWxsaXNlY29uZDtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KShmYWxzZSwgXCJBcmd1bWVudC5BbW91bnRcIiwgXCJpbnZhbGlkIGNvbnN0cnVjdG9yIGFyZ3VtZW50c1wiKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICAvKipcbiAgICAgKiBDb25zdHJ1Y3QgYSB0aW1lIGR1cmF0aW9uXG4gICAgICogQHBhcmFtIGFtb3VudCBOdW1iZXIgb2YgeWVhcnMgKG1heSBiZSBmcmFjdGlvbmFsIG9yIG5lZ2F0aXZlKVxuICAgICAqIEByZXR1cm4gQSBkdXJhdGlvbiBvZiBuIHllYXJzXG4gICAgICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LkFtb3VudCBpZiBuIGlzIG5vdCBhIGZpbml0ZSBudW1iZXJcbiAgICAgKi9cbiAgICBEdXJhdGlvbi55ZWFycyA9IGZ1bmN0aW9uIChhbW91bnQpIHtcbiAgICAgICAgcmV0dXJuIG5ldyBEdXJhdGlvbihhbW91bnQsIGJhc2ljc18xLlRpbWVVbml0LlllYXIpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogQ29uc3RydWN0IGEgdGltZSBkdXJhdGlvblxuICAgICAqIEBwYXJhbSBhbW91bnQgTnVtYmVyIG9mIG1vbnRocyAobWF5IGJlIGZyYWN0aW9uYWwgb3IgbmVnYXRpdmUpXG4gICAgICogQHJldHVybiBBIGR1cmF0aW9uIG9mIG4gbW9udGhzXG4gICAgICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LkFtb3VudCBpZiBuIGlzIG5vdCBhIGZpbml0ZSBudW1iZXJcbiAgICAgKi9cbiAgICBEdXJhdGlvbi5tb250aHMgPSBmdW5jdGlvbiAoYW1vdW50KSB7XG4gICAgICAgIHJldHVybiBuZXcgRHVyYXRpb24oYW1vdW50LCBiYXNpY3NfMS5UaW1lVW5pdC5Nb250aCk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBDb25zdHJ1Y3QgYSB0aW1lIGR1cmF0aW9uXG4gICAgICogQHBhcmFtIGFtb3VudCBOdW1iZXIgb2YgZGF5cyAobWF5IGJlIGZyYWN0aW9uYWwgb3IgbmVnYXRpdmUpXG4gICAgICogQHJldHVybiBBIGR1cmF0aW9uIG9mIG4gZGF5c1xuICAgICAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5BbW91bnQgaWYgbiBpcyBub3QgYSBmaW5pdGUgbnVtYmVyXG4gICAgICovXG4gICAgRHVyYXRpb24uZGF5cyA9IGZ1bmN0aW9uIChhbW91bnQpIHtcbiAgICAgICAgcmV0dXJuIG5ldyBEdXJhdGlvbihhbW91bnQsIGJhc2ljc18xLlRpbWVVbml0LkRheSk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBDb25zdHJ1Y3QgYSB0aW1lIGR1cmF0aW9uXG4gICAgICogQHBhcmFtIGFtb3VudCBOdW1iZXIgb2YgaG91cnMgKG1heSBiZSBmcmFjdGlvbmFsIG9yIG5lZ2F0aXZlKVxuICAgICAqIEByZXR1cm4gQSBkdXJhdGlvbiBvZiBuIGhvdXJzXG4gICAgICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LkFtb3VudCBpZiBuIGlzIG5vdCBhIGZpbml0ZSBudW1iZXJcbiAgICAgKi9cbiAgICBEdXJhdGlvbi5ob3VycyA9IGZ1bmN0aW9uIChhbW91bnQpIHtcbiAgICAgICAgcmV0dXJuIG5ldyBEdXJhdGlvbihhbW91bnQsIGJhc2ljc18xLlRpbWVVbml0LkhvdXIpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogQ29uc3RydWN0IGEgdGltZSBkdXJhdGlvblxuICAgICAqIEBwYXJhbSBhbW91bnQgTnVtYmVyIG9mIG1pbnV0ZXMgKG1heSBiZSBmcmFjdGlvbmFsIG9yIG5lZ2F0aXZlKVxuICAgICAqIEByZXR1cm4gQSBkdXJhdGlvbiBvZiBuIG1pbnV0ZXNcbiAgICAgKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuQW1vdW50IGlmIG4gaXMgbm90IGEgZmluaXRlIG51bWJlclxuICAgICAqL1xuICAgIER1cmF0aW9uLm1pbnV0ZXMgPSBmdW5jdGlvbiAoYW1vdW50KSB7XG4gICAgICAgIHJldHVybiBuZXcgRHVyYXRpb24oYW1vdW50LCBiYXNpY3NfMS5UaW1lVW5pdC5NaW51dGUpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogQ29uc3RydWN0IGEgdGltZSBkdXJhdGlvblxuICAgICAqIEBwYXJhbSBhbW91bnQgTnVtYmVyIG9mIHNlY29uZHMgKG1heSBiZSBmcmFjdGlvbmFsIG9yIG5lZ2F0aXZlKVxuICAgICAqIEByZXR1cm4gQSBkdXJhdGlvbiBvZiBuIHNlY29uZHNcbiAgICAgKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuQW1vdW50IGlmIG4gaXMgbm90IGEgZmluaXRlIG51bWJlclxuICAgICAqL1xuICAgIER1cmF0aW9uLnNlY29uZHMgPSBmdW5jdGlvbiAoYW1vdW50KSB7XG4gICAgICAgIHJldHVybiBuZXcgRHVyYXRpb24oYW1vdW50LCBiYXNpY3NfMS5UaW1lVW5pdC5TZWNvbmQpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogQ29uc3RydWN0IGEgdGltZSBkdXJhdGlvblxuICAgICAqIEBwYXJhbSBhbW91bnQgTnVtYmVyIG9mIG1pbGxpc2Vjb25kcyAobWF5IGJlIGZyYWN0aW9uYWwgb3IgbmVnYXRpdmUpXG4gICAgICogQHJldHVybiBBIGR1cmF0aW9uIG9mIG4gbWlsbGlzZWNvbmRzXG4gICAgICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LkFtb3VudCBpZiBuIGlzIG5vdCBhIGZpbml0ZSBudW1iZXJcbiAgICAgKi9cbiAgICBEdXJhdGlvbi5taWxsaXNlY29uZHMgPSBmdW5jdGlvbiAoYW1vdW50KSB7XG4gICAgICAgIHJldHVybiBuZXcgRHVyYXRpb24oYW1vdW50LCBiYXNpY3NfMS5UaW1lVW5pdC5NaWxsaXNlY29uZCk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBAcmV0dXJuIGFub3RoZXIgaW5zdGFuY2Ugb2YgRHVyYXRpb24gd2l0aCB0aGUgc2FtZSB2YWx1ZS5cbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBEdXJhdGlvbi5wcm90b3R5cGUuY2xvbmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBuZXcgRHVyYXRpb24odGhpcy5fYW1vdW50LCB0aGlzLl91bml0KTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhpcyBkdXJhdGlvbiBleHByZXNzZWQgaW4gZGlmZmVyZW50IHVuaXQgKHBvc2l0aXZlIG9yIG5lZ2F0aXZlLCBmcmFjdGlvbmFsKS5cbiAgICAgKiBUaGlzIGlzIHByZWNpc2UgZm9yIFllYXIgPC0+IE1vbnRoIGFuZCBmb3IgdGltZS10by10aW1lIGNvbnZlcnNpb24gKGkuZS4gSG91ci1vci1sZXNzIHRvIEhvdXItb3ItbGVzcykuXG4gICAgICogSXQgaXMgYXBwcm94aW1hdGUgZm9yIGFueSBvdGhlciBjb252ZXJzaW9uXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgRHVyYXRpb24ucHJvdG90eXBlLmFzID0gZnVuY3Rpb24gKHVuaXQpIHtcbiAgICAgICAgaWYgKHRoaXMuX3VuaXQgPT09IHVuaXQpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9hbW91bnQ7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAodGhpcy5fdW5pdCA+PSBiYXNpY3NfMS5UaW1lVW5pdC5Nb250aCAmJiB1bml0ID49IGJhc2ljc18xLlRpbWVVbml0Lk1vbnRoKSB7XG4gICAgICAgICAgICB2YXIgdGhpc01vbnRocyA9ICh0aGlzLl91bml0ID09PSBiYXNpY3NfMS5UaW1lVW5pdC5ZZWFyID8gMTIgOiAxKTtcbiAgICAgICAgICAgIHZhciByZXFNb250aHMgPSAodW5pdCA9PT0gYmFzaWNzXzEuVGltZVVuaXQuWWVhciA/IDEyIDogMSk7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fYW1vdW50ICogdGhpc01vbnRocyAvIHJlcU1vbnRocztcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHZhciB0aGlzTXNlYyA9IGJhc2ljcy50aW1lVW5pdFRvTWlsbGlzZWNvbmRzKHRoaXMuX3VuaXQpO1xuICAgICAgICAgICAgdmFyIHJlcU1zZWMgPSBiYXNpY3MudGltZVVuaXRUb01pbGxpc2Vjb25kcyh1bml0KTtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9hbW91bnQgKiB0aGlzTXNlYyAvIHJlcU1zZWM7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIC8qKlxuICAgICAqIENvbnZlcnQgdGhpcyBkdXJhdGlvbiB0byBhIER1cmF0aW9uIGluIGFub3RoZXIgdW5pdC4gWW91IGFsd2F5cyBnZXQgYSBjbG9uZSBldmVuIGlmIHlvdSBzcGVjaWZ5XG4gICAgICogdGhlIHNhbWUgdW5pdC5cbiAgICAgKiBUaGlzIGlzIHByZWNpc2UgZm9yIFllYXIgPC0+IE1vbnRoIGFuZCBmb3IgdGltZS10by10aW1lIGNvbnZlcnNpb24gKGkuZS4gSG91ci1vci1sZXNzIHRvIEhvdXItb3ItbGVzcykuXG4gICAgICogSXQgaXMgYXBwcm94aW1hdGUgZm9yIGFueSBvdGhlciBjb252ZXJzaW9uXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgRHVyYXRpb24ucHJvdG90eXBlLmNvbnZlcnQgPSBmdW5jdGlvbiAodW5pdCkge1xuICAgICAgICByZXR1cm4gbmV3IER1cmF0aW9uKHRoaXMuYXModW5pdCksIHVuaXQpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogVGhlIGVudGlyZSBkdXJhdGlvbiBpbiBtaWxsaXNlY29uZHMgKG5lZ2F0aXZlIG9yIHBvc2l0aXZlKVxuICAgICAqIEZvciBEYXkvTW9udGgvWWVhciBkdXJhdGlvbnMsIHRoaXMgaXMgYXBwcm94aW1hdGUhXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgRHVyYXRpb24ucHJvdG90eXBlLm1pbGxpc2Vjb25kcyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuYXMoYmFzaWNzXzEuVGltZVVuaXQuTWlsbGlzZWNvbmQpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogVGhlIG1pbGxpc2Vjb25kIHBhcnQgb2YgdGhlIGR1cmF0aW9uIChhbHdheXMgcG9zaXRpdmUpXG4gICAgICogRm9yIERheS9Nb250aC9ZZWFyIGR1cmF0aW9ucywgdGhpcyBpcyBhcHByb3hpbWF0ZSFcbiAgICAgKiBAcmV0dXJuIGUuZy4gNDAwIGZvciBhIC0wMTowMjowMy40MDAgZHVyYXRpb25cbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBEdXJhdGlvbi5wcm90b3R5cGUubWlsbGlzZWNvbmQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9wYXJ0KGJhc2ljc18xLlRpbWVVbml0Lk1pbGxpc2Vjb25kKTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFRoZSBlbnRpcmUgZHVyYXRpb24gaW4gc2Vjb25kcyAobmVnYXRpdmUgb3IgcG9zaXRpdmUsIGZyYWN0aW9uYWwpXG4gICAgICogRm9yIERheS9Nb250aC9ZZWFyIGR1cmF0aW9ucywgdGhpcyBpcyBhcHByb3hpbWF0ZSFcbiAgICAgKiBAcmV0dXJuIGUuZy4gMS41IGZvciBhIDE1MDAgbWlsbGlzZWNvbmRzIGR1cmF0aW9uXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgRHVyYXRpb24ucHJvdG90eXBlLnNlY29uZHMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmFzKGJhc2ljc18xLlRpbWVVbml0LlNlY29uZCk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBUaGUgc2Vjb25kIHBhcnQgb2YgdGhlIGR1cmF0aW9uIChhbHdheXMgcG9zaXRpdmUpXG4gICAgICogRm9yIERheS9Nb250aC9ZZWFyIGR1cmF0aW9ucywgdGhpcyBpcyBhcHByb3hpbWF0ZSFcbiAgICAgKiBAcmV0dXJuIGUuZy4gMyBmb3IgYSAtMDE6MDI6MDMuNDAwIGR1cmF0aW9uXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgRHVyYXRpb24ucHJvdG90eXBlLnNlY29uZCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3BhcnQoYmFzaWNzXzEuVGltZVVuaXQuU2Vjb25kKTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFRoZSBlbnRpcmUgZHVyYXRpb24gaW4gbWludXRlcyAobmVnYXRpdmUgb3IgcG9zaXRpdmUsIGZyYWN0aW9uYWwpXG4gICAgICogRm9yIERheS9Nb250aC9ZZWFyIGR1cmF0aW9ucywgdGhpcyBpcyBhcHByb3hpbWF0ZSFcbiAgICAgKiBAcmV0dXJuIGUuZy4gMS41IGZvciBhIDkwMDAwIG1pbGxpc2Vjb25kcyBkdXJhdGlvblxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIER1cmF0aW9uLnByb3RvdHlwZS5taW51dGVzID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5hcyhiYXNpY3NfMS5UaW1lVW5pdC5NaW51dGUpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogVGhlIG1pbnV0ZSBwYXJ0IG9mIHRoZSBkdXJhdGlvbiAoYWx3YXlzIHBvc2l0aXZlKVxuICAgICAqIEZvciBEYXkvTW9udGgvWWVhciBkdXJhdGlvbnMsIHRoaXMgaXMgYXBwcm94aW1hdGUhXG4gICAgICogQHJldHVybiBlLmcuIDIgZm9yIGEgLTAxOjAyOjAzLjQwMCBkdXJhdGlvblxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIER1cmF0aW9uLnByb3RvdHlwZS5taW51dGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9wYXJ0KGJhc2ljc18xLlRpbWVVbml0Lk1pbnV0ZSk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBUaGUgZW50aXJlIGR1cmF0aW9uIGluIGhvdXJzIChuZWdhdGl2ZSBvciBwb3NpdGl2ZSwgZnJhY3Rpb25hbClcbiAgICAgKiBGb3IgRGF5L01vbnRoL1llYXIgZHVyYXRpb25zLCB0aGlzIGlzIGFwcHJveGltYXRlIVxuICAgICAqIEByZXR1cm4gZS5nLiAxLjUgZm9yIGEgNTQwMDAwMCBtaWxsaXNlY29uZHMgZHVyYXRpb25cbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBEdXJhdGlvbi5wcm90b3R5cGUuaG91cnMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmFzKGJhc2ljc18xLlRpbWVVbml0LkhvdXIpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogVGhlIGhvdXIgcGFydCBvZiBhIGR1cmF0aW9uLiBUaGlzIGFzc3VtZXMgdGhhdCBhIGRheSBoYXMgMjQgaG91cnMgKHdoaWNoIGlzIG5vdCB0aGUgY2FzZVxuICAgICAqIGR1cmluZyBEU1QgY2hhbmdlcykuXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgRHVyYXRpb24ucHJvdG90eXBlLmhvdXIgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9wYXJ0KGJhc2ljc18xLlRpbWVVbml0LkhvdXIpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogVGhlIGhvdXIgcGFydCBvZiB0aGUgZHVyYXRpb24gKGFsd2F5cyBwb3NpdGl2ZSkuXG4gICAgICogTm90ZSB0aGF0IHRoaXMgcGFydCBjYW4gZXhjZWVkIDIzIGhvdXJzLCBiZWNhdXNlIGZvclxuICAgICAqIG5vdywgd2UgZG8gbm90IGhhdmUgYSBkYXlzKCkgZnVuY3Rpb25cbiAgICAgKiBGb3IgRGF5L01vbnRoL1llYXIgZHVyYXRpb25zLCB0aGlzIGlzIGFwcHJveGltYXRlIVxuICAgICAqIEByZXR1cm4gZS5nLiAyNSBmb3IgYSAtMjU6MDI6MDMuNDAwIGR1cmF0aW9uXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgRHVyYXRpb24ucHJvdG90eXBlLndob2xlSG91cnMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBNYXRoLmZsb29yKGJhc2ljcy50aW1lVW5pdFRvTWlsbGlzZWNvbmRzKHRoaXMuX3VuaXQpICogTWF0aC5hYnModGhpcy5fYW1vdW50KSAvIDM2MDAwMDApO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogVGhlIGVudGlyZSBkdXJhdGlvbiBpbiBkYXlzIChuZWdhdGl2ZSBvciBwb3NpdGl2ZSwgZnJhY3Rpb25hbClcbiAgICAgKiBUaGlzIGlzIGFwcHJveGltYXRlIGlmIHRoaXMgZHVyYXRpb24gaXMgbm90IGluIGRheXMhXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgRHVyYXRpb24ucHJvdG90eXBlLmRheXMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmFzKGJhc2ljc18xLlRpbWVVbml0LkRheSk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBUaGUgZGF5IHBhcnQgb2YgYSBkdXJhdGlvbi4gVGhpcyBhc3N1bWVzIHRoYXQgYSBtb250aCBoYXMgMzAgZGF5cy5cbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBEdXJhdGlvbi5wcm90b3R5cGUuZGF5ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fcGFydChiYXNpY3NfMS5UaW1lVW5pdC5EYXkpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogVGhlIGVudGlyZSBkdXJhdGlvbiBpbiBkYXlzIChuZWdhdGl2ZSBvciBwb3NpdGl2ZSwgZnJhY3Rpb25hbClcbiAgICAgKiBUaGlzIGlzIGFwcHJveGltYXRlIGlmIHRoaXMgZHVyYXRpb24gaXMgbm90IGluIE1vbnRocyBvciBZZWFycyFcbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBEdXJhdGlvbi5wcm90b3R5cGUubW9udGhzID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5hcyhiYXNpY3NfMS5UaW1lVW5pdC5Nb250aCk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBUaGUgbW9udGggcGFydCBvZiBhIGR1cmF0aW9uLlxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIER1cmF0aW9uLnByb3RvdHlwZS5tb250aCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3BhcnQoYmFzaWNzXzEuVGltZVVuaXQuTW9udGgpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogVGhlIGVudGlyZSBkdXJhdGlvbiBpbiB5ZWFycyAobmVnYXRpdmUgb3IgcG9zaXRpdmUsIGZyYWN0aW9uYWwpXG4gICAgICogVGhpcyBpcyBhcHByb3hpbWF0ZSBpZiB0aGlzIGR1cmF0aW9uIGlzIG5vdCBpbiBNb250aHMgb3IgWWVhcnMhXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgRHVyYXRpb24ucHJvdG90eXBlLnllYXJzID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5hcyhiYXNpY3NfMS5UaW1lVW5pdC5ZZWFyKTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIE5vbi1mcmFjdGlvbmFsIHBvc2l0aXZlIHllYXJzXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgRHVyYXRpb24ucHJvdG90eXBlLndob2xlWWVhcnMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICh0aGlzLl91bml0ID09PSBiYXNpY3NfMS5UaW1lVW5pdC5ZZWFyKSB7XG4gICAgICAgICAgICByZXR1cm4gTWF0aC5mbG9vcihNYXRoLmFicyh0aGlzLl9hbW91bnQpKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICh0aGlzLl91bml0ID09PSBiYXNpY3NfMS5UaW1lVW5pdC5Nb250aCkge1xuICAgICAgICAgICAgcmV0dXJuIE1hdGguZmxvb3IoTWF0aC5hYnModGhpcy5fYW1vdW50KSAvIDEyKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBNYXRoLmZsb29yKGJhc2ljcy50aW1lVW5pdFRvTWlsbGlzZWNvbmRzKHRoaXMuX3VuaXQpICogTWF0aC5hYnModGhpcy5fYW1vdW50KSAvXG4gICAgICAgICAgICAgICAgYmFzaWNzLnRpbWVVbml0VG9NaWxsaXNlY29uZHMoYmFzaWNzXzEuVGltZVVuaXQuWWVhcikpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBBbW91bnQgb2YgdW5pdHMgKHBvc2l0aXZlIG9yIG5lZ2F0aXZlLCBmcmFjdGlvbmFsKVxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIER1cmF0aW9uLnByb3RvdHlwZS5hbW91bnQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9hbW91bnQ7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBUaGUgdW5pdCB0aGlzIGR1cmF0aW9uIHdhcyBjcmVhdGVkIHdpdGhcbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBEdXJhdGlvbi5wcm90b3R5cGUudW5pdCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3VuaXQ7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBTaWduXG4gICAgICogQHJldHVybiBcIi1cIiBpZiB0aGUgZHVyYXRpb24gaXMgbmVnYXRpdmVcbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBEdXJhdGlvbi5wcm90b3R5cGUuc2lnbiA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuICh0aGlzLl9hbW91bnQgPCAwID8gXCItXCIgOiBcIlwiKTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIEFwcHJveGltYXRlIGlmIHRoZSBkdXJhdGlvbnMgaGF2ZSB1bml0cyB0aGF0IGNhbm5vdCBiZSBjb252ZXJ0ZWRcbiAgICAgKiBAcmV0dXJuIFRydWUgaWZmICh0aGlzIDwgb3RoZXIpXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgRHVyYXRpb24ucHJvdG90eXBlLmxlc3NUaGFuID0gZnVuY3Rpb24gKG90aGVyKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm1pbGxpc2Vjb25kcygpIDwgb3RoZXIubWlsbGlzZWNvbmRzKCk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBBcHByb3hpbWF0ZSBpZiB0aGUgZHVyYXRpb25zIGhhdmUgdW5pdHMgdGhhdCBjYW5ub3QgYmUgY29udmVydGVkXG4gICAgICogQHJldHVybiBUcnVlIGlmZiAodGhpcyA8PSBvdGhlcilcbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBEdXJhdGlvbi5wcm90b3R5cGUubGVzc0VxdWFsID0gZnVuY3Rpb24gKG90aGVyKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm1pbGxpc2Vjb25kcygpIDw9IG90aGVyLm1pbGxpc2Vjb25kcygpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogU2ltaWxhciBidXQgbm90IGlkZW50aWNhbFxuICAgICAqIEFwcHJveGltYXRlIGlmIHRoZSBkdXJhdGlvbnMgaGF2ZSB1bml0cyB0aGF0IGNhbm5vdCBiZSBjb252ZXJ0ZWRcbiAgICAgKiBAcmV0dXJuIFRydWUgaWZmIHRoaXMgYW5kIG90aGVyIHJlcHJlc2VudCB0aGUgc2FtZSB0aW1lIGR1cmF0aW9uXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgRHVyYXRpb24ucHJvdG90eXBlLmVxdWFscyA9IGZ1bmN0aW9uIChvdGhlcikge1xuICAgICAgICB2YXIgY29udmVydGVkID0gb3RoZXIuY29udmVydCh0aGlzLl91bml0KTtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2Ftb3VudCA9PT0gY29udmVydGVkLmFtb3VudCgpICYmIHRoaXMuX3VuaXQgPT09IGNvbnZlcnRlZC51bml0KCk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBTaW1pbGFyIGJ1dCBub3QgaWRlbnRpY2FsXG4gICAgICogUmV0dXJucyBmYWxzZSBpZiB3ZSBjYW5ub3QgZGV0ZXJtaW5lIHdoZXRoZXIgdGhleSBhcmUgZXF1YWwgaW4gYWxsIHRpbWUgem9uZXNcbiAgICAgKiBzbyBlLmcuIDYwIG1pbnV0ZXMgZXF1YWxzIDEgaG91ciwgYnV0IDI0IGhvdXJzIGRvIE5PVCBlcXVhbCAxIGRheVxuICAgICAqXG4gICAgICogQHJldHVybiBUcnVlIGlmZiB0aGlzIGFuZCBvdGhlciByZXByZXNlbnQgdGhlIHNhbWUgdGltZSBkdXJhdGlvblxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIER1cmF0aW9uLnByb3RvdHlwZS5lcXVhbHNFeGFjdCA9IGZ1bmN0aW9uIChvdGhlcikge1xuICAgICAgICBpZiAodGhpcy5fdW5pdCA9PT0gb3RoZXIuX3VuaXQpIHtcbiAgICAgICAgICAgIHJldHVybiAodGhpcy5fYW1vdW50ID09PSBvdGhlci5fYW1vdW50KTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICh0aGlzLl91bml0ID49IGJhc2ljc18xLlRpbWVVbml0Lk1vbnRoICYmIG90aGVyLnVuaXQoKSA+PSBiYXNpY3NfMS5UaW1lVW5pdC5Nb250aCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuZXF1YWxzKG90aGVyKTsgLy8gY2FuIGNvbXBhcmUgbW9udGhzIGFuZCB5ZWFyc1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKHRoaXMuX3VuaXQgPCBiYXNpY3NfMS5UaW1lVW5pdC5EYXkgJiYgb3RoZXIudW5pdCgpIDwgYmFzaWNzXzEuVGltZVVuaXQuRGF5KSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5lcXVhbHMob3RoZXIpOyAvLyBjYW4gY29tcGFyZSBtaWxsaXNlY29uZHMgdGhyb3VnaCBob3Vyc1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlOyAvLyBjYW5ub3QgY29tcGFyZSBkYXlzIHRvIGFueXRoaW5nIGVsc2VcbiAgICAgICAgfVxuICAgIH07XG4gICAgLyoqXG4gICAgICogU2FtZSB1bml0IGFuZCBzYW1lIGFtb3VudFxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIER1cmF0aW9uLnByb3RvdHlwZS5pZGVudGljYWwgPSBmdW5jdGlvbiAob3RoZXIpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2Ftb3VudCA9PT0gb3RoZXIuYW1vdW50KCkgJiYgdGhpcy5fdW5pdCA9PT0gb3RoZXIudW5pdCgpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0cnVlIGlmIHRoaXMgaXMgYSBub24temVybyBsZW5ndGggZHVyYXRpb25cbiAgICAgKi9cbiAgICBEdXJhdGlvbi5wcm90b3R5cGUubm9uWmVybyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2Ftb3VudCAhPT0gMDtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFJldHVybnMgdHJ1ZSBpZiB0aGlzIGlzIGEgemVyby1sZW5ndGggZHVyYXRpb25cbiAgICAgKi9cbiAgICBEdXJhdGlvbi5wcm90b3R5cGUuemVybyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2Ftb3VudCA9PT0gMDtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIEFwcHJveGltYXRlIGlmIHRoZSBkdXJhdGlvbnMgaGF2ZSB1bml0cyB0aGF0IGNhbm5vdCBiZSBjb252ZXJ0ZWRcbiAgICAgKiBAcmV0dXJuIFRydWUgaWZmIHRoaXMgPiBvdGhlclxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIER1cmF0aW9uLnByb3RvdHlwZS5ncmVhdGVyVGhhbiA9IGZ1bmN0aW9uIChvdGhlcikge1xuICAgICAgICByZXR1cm4gdGhpcy5taWxsaXNlY29uZHMoKSA+IG90aGVyLm1pbGxpc2Vjb25kcygpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogQXBwcm94aW1hdGUgaWYgdGhlIGR1cmF0aW9ucyBoYXZlIHVuaXRzIHRoYXQgY2Fubm90IGJlIGNvbnZlcnRlZFxuICAgICAqIEByZXR1cm4gVHJ1ZSBpZmYgdGhpcyA+PSBvdGhlclxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIER1cmF0aW9uLnByb3RvdHlwZS5ncmVhdGVyRXF1YWwgPSBmdW5jdGlvbiAob3RoZXIpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMubWlsbGlzZWNvbmRzKCkgPj0gb3RoZXIubWlsbGlzZWNvbmRzKCk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBBcHByb3hpbWF0ZSBpZiB0aGUgZHVyYXRpb25zIGhhdmUgdW5pdHMgdGhhdCBjYW5ub3QgYmUgY29udmVydGVkXG4gICAgICogQHJldHVybiBUaGUgbWluaW11bSAobW9zdCBuZWdhdGl2ZSkgb2YgdGhpcyBhbmQgb3RoZXJcbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBEdXJhdGlvbi5wcm90b3R5cGUubWluID0gZnVuY3Rpb24gKG90aGVyKSB7XG4gICAgICAgIGlmICh0aGlzLmxlc3NUaGFuKG90aGVyKSkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuY2xvbmUoKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gb3RoZXIuY2xvbmUoKTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIEFwcHJveGltYXRlIGlmIHRoZSBkdXJhdGlvbnMgaGF2ZSB1bml0cyB0aGF0IGNhbm5vdCBiZSBjb252ZXJ0ZWRcbiAgICAgKiBAcmV0dXJuIFRoZSBtYXhpbXVtIChtb3N0IHBvc2l0aXZlKSBvZiB0aGlzIGFuZCBvdGhlclxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIER1cmF0aW9uLnByb3RvdHlwZS5tYXggPSBmdW5jdGlvbiAob3RoZXIpIHtcbiAgICAgICAgaWYgKHRoaXMuZ3JlYXRlclRoYW4ob3RoZXIpKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5jbG9uZSgpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBvdGhlci5jbG9uZSgpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogTXVsdGlwbHkgd2l0aCBhIGZpeGVkIG51bWJlci5cbiAgICAgKiBBcHByb3hpbWF0ZSBpZiB0aGUgZHVyYXRpb25zIGhhdmUgdW5pdHMgdGhhdCBjYW5ub3QgYmUgY29udmVydGVkXG4gICAgICogQHJldHVybiBhIG5ldyBEdXJhdGlvbiBvZiAodGhpcyAqIHZhbHVlKVxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIER1cmF0aW9uLnByb3RvdHlwZS5tdWx0aXBseSA9IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICByZXR1cm4gbmV3IER1cmF0aW9uKHRoaXMuX2Ftb3VudCAqIHZhbHVlLCB0aGlzLl91bml0KTtcbiAgICB9O1xuICAgIER1cmF0aW9uLnByb3RvdHlwZS5kaXZpZGUgPSBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gXCJudW1iZXJcIikge1xuICAgICAgICAgICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKE51bWJlci5pc0Zpbml0ZSh2YWx1ZSkgJiYgdmFsdWUgIT09IDAsIFwiQXJndW1lbnQuVmFsdWVcIiwgXCJjYW5ub3QgZGl2aWRlIGJ5IFwiLmNvbmNhdCh2YWx1ZSkpO1xuICAgICAgICAgICAgcmV0dXJuIG5ldyBEdXJhdGlvbih0aGlzLl9hbW91bnQgLyB2YWx1ZSwgdGhpcy5fdW5pdCk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkodmFsdWUuYW1vdW50KCkgIT09IDAsIFwiQXJndW1lbnQuVmFsdWVcIiwgXCJjYW5ub3QgZGl2aWRlIGJ5IDBcIik7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5taWxsaXNlY29uZHMoKSAvIHZhbHVlLm1pbGxpc2Vjb25kcygpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBBZGQgYSBkdXJhdGlvbi5cbiAgICAgKiBAcmV0dXJuIGEgbmV3IER1cmF0aW9uIG9mICh0aGlzICsgdmFsdWUpIHdpdGggdGhlIHVuaXQgb2YgdGhpcyBkdXJhdGlvblxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIER1cmF0aW9uLnByb3RvdHlwZS5hZGQgPSBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgcmV0dXJuIG5ldyBEdXJhdGlvbih0aGlzLl9hbW91bnQgKyB2YWx1ZS5hcyh0aGlzLl91bml0KSwgdGhpcy5fdW5pdCk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBTdWJ0cmFjdCBhIGR1cmF0aW9uLlxuICAgICAqIEByZXR1cm4gYSBuZXcgRHVyYXRpb24gb2YgKHRoaXMgLSB2YWx1ZSkgd2l0aCB0aGUgdW5pdCBvZiB0aGlzIGR1cmF0aW9uXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgRHVyYXRpb24ucHJvdG90eXBlLnN1YiA9IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICByZXR1cm4gbmV3IER1cmF0aW9uKHRoaXMuX2Ftb3VudCAtIHZhbHVlLmFzKHRoaXMuX3VuaXQpLCB0aGlzLl91bml0KTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFJldHVybiB0aGUgYWJzb2x1dGUgdmFsdWUgb2YgdGhlIGR1cmF0aW9uIGkuZS4gcmVtb3ZlIHRoZSBzaWduLlxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIER1cmF0aW9uLnByb3RvdHlwZS5hYnMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICh0aGlzLl9hbW91bnQgPj0gMCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuY2xvbmUoKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLm11bHRpcGx5KC0xKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgLyoqXG4gICAgICogU3RyaW5nIGluIFstXWhoaGg6bW06c3Mubm5uIG5vdGF0aW9uLiBBbGwgZmllbGRzIGFyZSBhbHdheXMgcHJlc2VudCBleGNlcHQgdGhlIHNpZ24uXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgRHVyYXRpb24ucHJvdG90eXBlLnRvRnVsbFN0cmluZyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMudG9IbXNTdHJpbmcodHJ1ZSk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBTdHJpbmcgaW4gWy1daGhoaDptbVs6c3NbLm5ubl1dIG5vdGF0aW9uLlxuICAgICAqIEBwYXJhbSBmdWxsIElmIHRydWUsIHRoZW4gYWxsIGZpZWxkcyBhcmUgYWx3YXlzIHByZXNlbnQgZXhjZXB0IHRoZSBzaWduLiBPdGhlcndpc2UsIHNlY29uZHMgYW5kIG1pbGxpc2Vjb25kc1xuICAgICAqIGFyZSBjaG9wcGVkIG9mZiBpZiB6ZXJvXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgRHVyYXRpb24ucHJvdG90eXBlLnRvSG1zU3RyaW5nID0gZnVuY3Rpb24gKGZ1bGwpIHtcbiAgICAgICAgaWYgKGZ1bGwgPT09IHZvaWQgMCkgeyBmdWxsID0gZmFsc2U7IH1cbiAgICAgICAgdmFyIHJlc3VsdCA9IFwiXCI7XG4gICAgICAgIGlmIChmdWxsIHx8IHRoaXMubWlsbGlzZWNvbmQoKSA+IDApIHtcbiAgICAgICAgICAgIHJlc3VsdCA9IFwiLlwiICsgc3RyaW5ncy5wYWRMZWZ0KHRoaXMubWlsbGlzZWNvbmQoKS50b1N0cmluZygxMCksIDMsIFwiMFwiKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoZnVsbCB8fCByZXN1bHQubGVuZ3RoID4gMCB8fCB0aGlzLnNlY29uZCgpID4gMCkge1xuICAgICAgICAgICAgcmVzdWx0ID0gXCI6XCIgKyBzdHJpbmdzLnBhZExlZnQodGhpcy5zZWNvbmQoKS50b1N0cmluZygxMCksIDIsIFwiMFwiKSArIHJlc3VsdDtcbiAgICAgICAgfVxuICAgICAgICBpZiAoZnVsbCB8fCByZXN1bHQubGVuZ3RoID4gMCB8fCB0aGlzLm1pbnV0ZSgpID4gMCkge1xuICAgICAgICAgICAgcmVzdWx0ID0gXCI6XCIgKyBzdHJpbmdzLnBhZExlZnQodGhpcy5taW51dGUoKS50b1N0cmluZygxMCksIDIsIFwiMFwiKSArIHJlc3VsdDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy5zaWduKCkgKyBzdHJpbmdzLnBhZExlZnQodGhpcy53aG9sZUhvdXJzKCkudG9TdHJpbmcoMTApLCAyLCBcIjBcIikgKyByZXN1bHQ7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBTdHJpbmcgaW4gSVNPIDg2MDEgbm90YXRpb24gZS5nLiAnUDFNJyBmb3Igb25lIG1vbnRoIG9yICdQVDFNJyBmb3Igb25lIG1pbnV0ZVxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIER1cmF0aW9uLnByb3RvdHlwZS50b0lzb1N0cmluZyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgc3dpdGNoICh0aGlzLl91bml0KSB7XG4gICAgICAgICAgICBjYXNlIGJhc2ljc18xLlRpbWVVbml0Lk1pbGxpc2Vjb25kOiB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIFwiUFwiICsgKHRoaXMuX2Ftb3VudCAvIDEwMDApLnRvRml4ZWQoMykgKyBcIlNcIjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhc2UgYmFzaWNzXzEuVGltZVVuaXQuU2Vjb25kOiB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIFwiUFwiICsgdGhpcy5fYW1vdW50LnRvU3RyaW5nKDEwKSArIFwiU1wiO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FzZSBiYXNpY3NfMS5UaW1lVW5pdC5NaW51dGU6IHtcbiAgICAgICAgICAgICAgICByZXR1cm4gXCJQVFwiICsgdGhpcy5fYW1vdW50LnRvU3RyaW5nKDEwKSArIFwiTVwiOyAvLyBub3RlIHRoZSBcIlRcIiB0byBkaXNhbWJpZ3VhdGUgdGhlIFwiTVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXNlIGJhc2ljc18xLlRpbWVVbml0LkhvdXI6IHtcbiAgICAgICAgICAgICAgICByZXR1cm4gXCJQXCIgKyB0aGlzLl9hbW91bnQudG9TdHJpbmcoMTApICsgXCJIXCI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXNlIGJhc2ljc18xLlRpbWVVbml0LkRheToge1xuICAgICAgICAgICAgICAgIHJldHVybiBcIlBcIiArIHRoaXMuX2Ftb3VudC50b1N0cmluZygxMCkgKyBcIkRcIjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhc2UgYmFzaWNzXzEuVGltZVVuaXQuV2Vlazoge1xuICAgICAgICAgICAgICAgIHJldHVybiBcIlBcIiArIHRoaXMuX2Ftb3VudC50b1N0cmluZygxMCkgKyBcIldcIjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhc2UgYmFzaWNzXzEuVGltZVVuaXQuTW9udGg6IHtcbiAgICAgICAgICAgICAgICByZXR1cm4gXCJQXCIgKyB0aGlzLl9hbW91bnQudG9TdHJpbmcoMTApICsgXCJNXCI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXNlIGJhc2ljc18xLlRpbWVVbml0LlllYXI6IHtcbiAgICAgICAgICAgICAgICByZXR1cm4gXCJQXCIgKyB0aGlzLl9hbW91bnQudG9TdHJpbmcoMTApICsgXCJZXCI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgaWYgKi9cbiAgICAgICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICAgICAgICAgIGlmICh0cnVlKSB7XG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIlVua25vd24gdGltZSB1bml0LlwiKTsgLy8gcHJvZ3JhbW1pbmcgZXJyb3JcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFN0cmluZyByZXByZXNlbnRhdGlvbiB3aXRoIGFtb3VudCBhbmQgdW5pdCBlLmcuICcxLjUgeWVhcnMnIG9yICctMSBkYXknXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgRHVyYXRpb24ucHJvdG90eXBlLnRvU3RyaW5nID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fYW1vdW50LnRvU3RyaW5nKDEwKSArIFwiIFwiICsgYmFzaWNzLnRpbWVVbml0VG9TdHJpbmcodGhpcy5fdW5pdCwgdGhpcy5fYW1vdW50KTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFRoZSB2YWx1ZU9mKCkgbWV0aG9kIHJldHVybnMgdGhlIHByaW1pdGl2ZSB2YWx1ZSBvZiB0aGUgc3BlY2lmaWVkIG9iamVjdC5cbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBEdXJhdGlvbi5wcm90b3R5cGUudmFsdWVPZiA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMubWlsbGlzZWNvbmRzKCk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBSZXR1cm4gdGhpcyAlIHVuaXQsIGFsd2F5cyBwb3NpdGl2ZVxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIER1cmF0aW9uLnByb3RvdHlwZS5fcGFydCA9IGZ1bmN0aW9uICh1bml0KSB7XG4gICAgICAgIHZhciBuZXh0VW5pdDtcbiAgICAgICAgLy8gbm90ZSBub3QgYWxsIHVuaXRzIGFyZSB1c2VkIGhlcmU6IFdlZWtzIGFuZCBZZWFycyBhcmUgcnVsZWQgb3V0XG4gICAgICAgIHN3aXRjaCAodW5pdCkge1xuICAgICAgICAgICAgY2FzZSBiYXNpY3NfMS5UaW1lVW5pdC5NaWxsaXNlY29uZDpcbiAgICAgICAgICAgICAgICBuZXh0VW5pdCA9IGJhc2ljc18xLlRpbWVVbml0LlNlY29uZDtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgYmFzaWNzXzEuVGltZVVuaXQuU2Vjb25kOlxuICAgICAgICAgICAgICAgIG5leHRVbml0ID0gYmFzaWNzXzEuVGltZVVuaXQuTWludXRlO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBiYXNpY3NfMS5UaW1lVW5pdC5NaW51dGU6XG4gICAgICAgICAgICAgICAgbmV4dFVuaXQgPSBiYXNpY3NfMS5UaW1lVW5pdC5Ib3VyO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBiYXNpY3NfMS5UaW1lVW5pdC5Ib3VyOlxuICAgICAgICAgICAgICAgIG5leHRVbml0ID0gYmFzaWNzXzEuVGltZVVuaXQuRGF5O1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBiYXNpY3NfMS5UaW1lVW5pdC5EYXk6XG4gICAgICAgICAgICAgICAgbmV4dFVuaXQgPSBiYXNpY3NfMS5UaW1lVW5pdC5Nb250aDtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgYmFzaWNzXzEuVGltZVVuaXQuTW9udGg6XG4gICAgICAgICAgICAgICAgbmV4dFVuaXQgPSBiYXNpY3NfMS5UaW1lVW5pdC5ZZWFyO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICByZXR1cm4gTWF0aC5mbG9vcihNYXRoLmFicyh0aGlzLmFzKGJhc2ljc18xLlRpbWVVbml0LlllYXIpKSk7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIG1zZWNzID0gKGJhc2ljcy50aW1lVW5pdFRvTWlsbGlzZWNvbmRzKHRoaXMuX3VuaXQpICogTWF0aC5hYnModGhpcy5fYW1vdW50KSkgJSBiYXNpY3MudGltZVVuaXRUb01pbGxpc2Vjb25kcyhuZXh0VW5pdCk7XG4gICAgICAgIHJldHVybiBNYXRoLmZsb29yKG1zZWNzIC8gYmFzaWNzLnRpbWVVbml0VG9NaWxsaXNlY29uZHModW5pdCkpO1xuICAgIH07XG4gICAgcmV0dXJuIER1cmF0aW9uO1xufSgpKTtcbmV4cG9ydHMuRHVyYXRpb24gPSBEdXJhdGlvbjtcbi8qKlxuICogQ2hlY2tzIGlmIGEgZ2l2ZW4gb2JqZWN0IGlzIG9mIHR5cGUgRHVyYXRpb24uIE5vdGUgdGhhdCBpdCBkb2VzIG5vdCB3b3JrIGZvciBzdWIgY2xhc3Nlcy4gSG93ZXZlciwgdXNlIHRoaXMgdG8gYmUgcm9idXN0XG4gKiBhZ2FpbnN0IGRpZmZlcmVudCB2ZXJzaW9ucyBvZiB0aGUgbGlicmFyeSBpbiBvbmUgcHJvY2VzcyBpbnN0ZWFkIG9mIGluc3RhbmNlb2ZcbiAqIEBwYXJhbSB2YWx1ZSBWYWx1ZSB0byBjaGVja1xuICogQHRocm93cyBub3RoaW5nXG4gKi9cbmZ1bmN0aW9uIGlzRHVyYXRpb24odmFsdWUpIHtcbiAgICByZXR1cm4gdHlwZW9mIHZhbHVlID09PSBcIm9iamVjdFwiICYmIHZhbHVlICE9PSBudWxsICYmIHZhbHVlLmtpbmQgPT09IFwiRHVyYXRpb25cIjtcbn1cbmV4cG9ydHMuaXNEdXJhdGlvbiA9IGlzRHVyYXRpb247XG4vLyMgc291cmNlTWFwcGluZ1VSTD1kdXJhdGlvbi5qcy5tYXAiLCJcInVzZSBzdHJpY3RcIjtcbi8qKlxuICogQ29weXJpZ2h0IChjKSAyMDE5IEFCQiBTd2l0emVybGFuZCBMdGQuXG4gKi9cbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIl9fZXNNb2R1bGVcIiwgeyB2YWx1ZTogdHJ1ZSB9KTtcbmV4cG9ydHMuY29udmVydEVycm9yID0gZXhwb3J0cy5lcnJvcklzID0gZXhwb3J0cy5lcnJvciA9IGV4cG9ydHMudGhyb3dFcnJvciA9IHZvaWQgMDtcbi8qKlxuICogVGhyb3dzIGFuIGVycm9yIHdpdGggdGhlIGdpdmVuIG5hbWUgYW5kIG1lc3NhZ2VcbiAqIEBwYXJhbSBuYW1lIGVycm9yIG5hbWUsIHdpdGhvdXQgdGltZXpvbmVjb21wbGV0ZSBwcmVmaXhcbiAqIEBwYXJhbSBtZXNzYWdlIG1lc3NhZ2Ugd2l0aCBwZXJjZW50LXN0eWxlIHBsYWNlaG9sZGVyc1xuICogQHBhcmFtIGFyZ3MgYXJndW1lbnRzIGZvciB0aGUgcGxhY2Vob2xkZXJzXG4gKiBAdGhyb3dzIHRoZSBnaXZlbiBlcnJvclxuICovXG5mdW5jdGlvbiB0aHJvd0Vycm9yKG5hbWUsIG1lc3NhZ2UpIHtcbiAgICB2YXIgZXJyb3IgPSBuZXcgRXJyb3IobWVzc2FnZSk7XG4gICAgZXJyb3IubmFtZSA9IFwidGltZXpvbmVjb21wbGV0ZS5cIiArIG5hbWU7XG4gICAgdGhyb3cgZXJyb3I7XG59XG5leHBvcnRzLnRocm93RXJyb3IgPSB0aHJvd0Vycm9yO1xuLyoqXG4gKiBSZXR1cm5zIGFuIGVycm9yIHdpdGggdGhlIGdpdmVuIG5hbWUgYW5kIG1lc3NhZ2VcbiAqIEBwYXJhbSBuYW1lXG4gKiBAcGFyYW0gZm9ybWF0XG4gKiBAcGFyYW0gYXJnc1xuICogQHRocm93cyBub3RoaW5nXG4gKi9cbmZ1bmN0aW9uIGVycm9yKG5hbWUsIG1lc3NhZ2UpIHtcbiAgICB2YXIgZXJyb3IgPSBuZXcgRXJyb3IobWVzc2FnZSk7XG4gICAgZXJyb3IubmFtZSA9IFwidGltZXpvbmVjb21wbGV0ZS5cIiArIG5hbWU7XG4gICAgcmV0dXJuIGVycm9yO1xufVxuZXhwb3J0cy5lcnJvciA9IGVycm9yO1xuLyoqXG4gKiBSZXR1cm5zIHRydWUgaWZmIGBlcnJvci5uYW1lYCBpcyBlcXVhbCB0byBvciBpbmNsdWRlZCBieSBgbmFtZWBcbiAqIEBwYXJhbSBlcnJvclxuICogQHBhcmFtIG5hbWUgc3RyaW5nIG9yIGFycmF5IG9mIHN0cmluZ3NcbiAqIEB0aHJvd3Mgbm90aGluZ1xuICovXG5mdW5jdGlvbiBlcnJvcklzKGVycm9yLCBuYW1lKSB7XG4gICAgaWYgKHR5cGVvZiBuYW1lID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgIHJldHVybiBlcnJvci5uYW1lID09PSBcInRpbWV6b25lY29tcGxldGUuXCIgKyBuYW1lO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgcmV0dXJuIGVycm9yLm5hbWUuc3RhcnRzV2l0aChcInRpbWV6b25lY29tcGxldGUuXCIpICYmIG5hbWUuaW5jbHVkZXMoZXJyb3IubmFtZS5zdWJzdHIoXCJ0aW1lem9uZWNvbXBsZXRlLlwiLmxlbmd0aCkpO1xuICAgIH1cbn1cbmV4cG9ydHMuZXJyb3JJcyA9IGVycm9ySXM7XG4vKipcbiAqIENvbnZlcnRzIGFsbCBlcnJvcnMgdGhyb3duIGJ5IGBjYmAgdG8gdGhlIGdpdmVuIGVycm9yIG5hbWVcbiAqIEBwYXJhbSBlcnJvck5hbWVcbiAqIEBwYXJhbSBjYlxuICogQHRocm93cyBbZXJyb3JOYW1lXVxuICovXG5mdW5jdGlvbiBjb252ZXJ0RXJyb3IoZXJyb3JOYW1lLCBjYikge1xuICAgIHRyeSB7XG4gICAgICAgIHJldHVybiBjYigpO1xuICAgIH1cbiAgICBjYXRjaCAoZSkge1xuICAgICAgICByZXR1cm4gdGhyb3dFcnJvcihlcnJvck5hbWUsIGUubWVzc2FnZSk7XG4gICAgfVxufVxuZXhwb3J0cy5jb252ZXJ0RXJyb3IgPSBjb252ZXJ0RXJyb3I7XG4vLyMgc291cmNlTWFwcGluZ1VSTD1lcnJvci5qcy5tYXAiLCIvKipcbiAqIENvcHlyaWdodChjKSAyMDE0IEFCQiBTd2l0emVybGFuZCBMdGQuXG4gKlxuICogRnVuY3Rpb25hbGl0eSB0byBwYXJzZSBhIERhdGVUaW1lIG9iamVjdCB0byBhIHN0cmluZ1xuICovXG5cInVzZSBzdHJpY3RcIjtcbnZhciBfX2Fzc2lnbiA9ICh0aGlzICYmIHRoaXMuX19hc3NpZ24pIHx8IGZ1bmN0aW9uICgpIHtcbiAgICBfX2Fzc2lnbiA9IE9iamVjdC5hc3NpZ24gfHwgZnVuY3Rpb24odCkge1xuICAgICAgICBmb3IgKHZhciBzLCBpID0gMSwgbiA9IGFyZ3VtZW50cy5sZW5ndGg7IGkgPCBuOyBpKyspIHtcbiAgICAgICAgICAgIHMgPSBhcmd1bWVudHNbaV07XG4gICAgICAgICAgICBmb3IgKHZhciBwIGluIHMpIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwocywgcCkpXG4gICAgICAgICAgICAgICAgdFtwXSA9IHNbcF07XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHQ7XG4gICAgfTtcbiAgICByZXR1cm4gX19hc3NpZ24uYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbn07XG5PYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgXCJfX2VzTW9kdWxlXCIsIHsgdmFsdWU6IHRydWUgfSk7XG5leHBvcnRzLmZvcm1hdCA9IHZvaWQgMDtcbnZhciBiYXNpY3MgPSByZXF1aXJlKFwiLi9iYXNpY3NcIik7XG52YXIgZXJyb3JfMSA9IHJlcXVpcmUoXCIuL2Vycm9yXCIpO1xudmFyIGxvY2FsZV8xID0gcmVxdWlyZShcIi4vbG9jYWxlXCIpO1xudmFyIHN0cmluZ3MgPSByZXF1aXJlKFwiLi9zdHJpbmdzXCIpO1xudmFyIHRva2VuXzEgPSByZXF1aXJlKFwiLi90b2tlblwiKTtcbi8qKlxuICogRm9ybWF0IHRoZSBzdXBwbGllZCBkYXRlVGltZSB3aXRoIHRoZSBmb3JtYXR0aW5nIHN0cmluZy5cbiAqXG4gKiBAcGFyYW0gZGF0ZVRpbWUgVGhlIGN1cnJlbnQgdGltZSB0byBmb3JtYXRcbiAqIEBwYXJhbSB1dGNUaW1lIFRoZSB0aW1lIGluIFVUQ1xuICogQHBhcmFtIGxvY2FsWm9uZSBUaGUgem9uZSB0aGF0IGN1cnJlbnRUaW1lIGlzIGluXG4gKiBAcGFyYW0gZm9ybWF0U3RyaW5nIFRoZSBMRE1MIGZvcm1hdCBwYXR0ZXJuIChzZWUgTERNTC5tZClcbiAqIEBwYXJhbSBsb2NhbGUgT3RoZXIgZm9ybWF0IG9wdGlvbnMgc3VjaCBhcyBtb250aCBuYW1lc1xuICogQHJldHVybiBzdHJpbmdcbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5Gb3JtYXRTdHJpbmcgZm9yIGludmFsaWQgZm9ybWF0IHBhdHRlcm5cbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5JbnZhbGlkVGltZVpvbmVEYXRhIGlmIHZhbHVlcyBpbiB0aGUgdGltZSB6b25lIGRhdGFiYXNlIGFyZSBpbnZhbGlkXG4gKi9cbmZ1bmN0aW9uIGZvcm1hdChkYXRlVGltZSwgdXRjVGltZSwgbG9jYWxab25lLCBmb3JtYXRTdHJpbmcsIGxvY2FsZSkge1xuICAgIGlmIChsb2NhbGUgPT09IHZvaWQgMCkgeyBsb2NhbGUgPSB7fTsgfVxuICAgIHZhciBtZXJnZWRMb2NhbGUgPSBfX2Fzc2lnbihfX2Fzc2lnbih7fSwgbG9jYWxlXzEuREVGQVVMVF9MT0NBTEUpLCBsb2NhbGUpO1xuICAgIHZhciB0b2tlbnMgPSAoMCwgdG9rZW5fMS50b2tlbml6ZSkoZm9ybWF0U3RyaW5nKTtcbiAgICB2YXIgcmVzdWx0ID0gXCJcIjtcbiAgICBmb3IgKHZhciBfaSA9IDAsIHRva2Vuc18xID0gdG9rZW5zOyBfaSA8IHRva2Vuc18xLmxlbmd0aDsgX2krKykge1xuICAgICAgICB2YXIgdG9rZW4gPSB0b2tlbnNfMVtfaV07XG4gICAgICAgIHZhciB0b2tlblJlc3VsdCA9IHZvaWQgMDtcbiAgICAgICAgc3dpdGNoICh0b2tlbi50eXBlKSB7XG4gICAgICAgICAgICBjYXNlIHRva2VuXzEuVG9rZW5UeXBlLkVSQTpcbiAgICAgICAgICAgICAgICB0b2tlblJlc3VsdCA9IF9mb3JtYXRFcmEoZGF0ZVRpbWUsIHRva2VuLCBtZXJnZWRMb2NhbGUpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSB0b2tlbl8xLlRva2VuVHlwZS5ZRUFSOlxuICAgICAgICAgICAgICAgIHRva2VuUmVzdWx0ID0gX2Zvcm1hdFllYXIoZGF0ZVRpbWUsIHRva2VuKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgdG9rZW5fMS5Ub2tlblR5cGUuUVVBUlRFUjpcbiAgICAgICAgICAgICAgICB0b2tlblJlc3VsdCA9IF9mb3JtYXRRdWFydGVyKGRhdGVUaW1lLCB0b2tlbiwgbWVyZ2VkTG9jYWxlKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgdG9rZW5fMS5Ub2tlblR5cGUuTU9OVEg6XG4gICAgICAgICAgICAgICAgdG9rZW5SZXN1bHQgPSBfZm9ybWF0TW9udGgoZGF0ZVRpbWUsIHRva2VuLCBtZXJnZWRMb2NhbGUpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSB0b2tlbl8xLlRva2VuVHlwZS5EQVk6XG4gICAgICAgICAgICAgICAgdG9rZW5SZXN1bHQgPSBfZm9ybWF0RGF5KGRhdGVUaW1lLCB0b2tlbik7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIHRva2VuXzEuVG9rZW5UeXBlLldFRUtEQVk6XG4gICAgICAgICAgICAgICAgdG9rZW5SZXN1bHQgPSBfZm9ybWF0V2Vla2RheShkYXRlVGltZSwgdG9rZW4sIG1lcmdlZExvY2FsZSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIHRva2VuXzEuVG9rZW5UeXBlLkRBWVBFUklPRDpcbiAgICAgICAgICAgICAgICB0b2tlblJlc3VsdCA9IF9mb3JtYXREYXlQZXJpb2QoZGF0ZVRpbWUsIHRva2VuLCBtZXJnZWRMb2NhbGUpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSB0b2tlbl8xLlRva2VuVHlwZS5IT1VSOlxuICAgICAgICAgICAgICAgIHRva2VuUmVzdWx0ID0gX2Zvcm1hdEhvdXIoZGF0ZVRpbWUsIHRva2VuKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgdG9rZW5fMS5Ub2tlblR5cGUuTUlOVVRFOlxuICAgICAgICAgICAgICAgIHRva2VuUmVzdWx0ID0gX2Zvcm1hdE1pbnV0ZShkYXRlVGltZSwgdG9rZW4pO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSB0b2tlbl8xLlRva2VuVHlwZS5TRUNPTkQ6XG4gICAgICAgICAgICAgICAgdG9rZW5SZXN1bHQgPSBfZm9ybWF0U2Vjb25kKGRhdGVUaW1lLCB0b2tlbik7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIHRva2VuXzEuVG9rZW5UeXBlLlpPTkU6XG4gICAgICAgICAgICAgICAgdG9rZW5SZXN1bHQgPSBfZm9ybWF0Wm9uZShkYXRlVGltZSwgdXRjVGltZSwgbG9jYWxab25lID8gbG9jYWxab25lIDogdW5kZWZpbmVkLCB0b2tlbik7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIHRva2VuXzEuVG9rZW5UeXBlLldFRUs6XG4gICAgICAgICAgICAgICAgdG9rZW5SZXN1bHQgPSBfZm9ybWF0V2VlayhkYXRlVGltZSwgdG9rZW4pO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSB0b2tlbl8xLlRva2VuVHlwZS5JREVOVElUWTogLy8gaW50ZW50aW9uYWwgZmFsbHRocm91Z2hcbiAgICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgIHRva2VuUmVzdWx0ID0gdG9rZW4ucmF3O1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICAgIHJlc3VsdCArPSB0b2tlblJlc3VsdDtcbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdC50cmltKCk7XG59XG5leHBvcnRzLmZvcm1hdCA9IGZvcm1hdDtcbi8qKlxuICogRm9ybWF0IHRoZSBlcmEgKEJDIG9yIEFEKVxuICpcbiAqIEBwYXJhbSBkYXRlVGltZSBUaGUgY3VycmVudCB0aW1lIHRvIGZvcm1hdFxuICogQHBhcmFtIHRva2VuIFRoZSB0b2tlbiBwYXNzZWRcbiAqIEByZXR1cm4gc3RyaW5nXG4gKiBAdGhyb3dzIG5vdGhpbmdcbiAqL1xuZnVuY3Rpb24gX2Zvcm1hdEVyYShkYXRlVGltZSwgdG9rZW4sIGxvY2FsZSkge1xuICAgIHZhciBBRCA9IGRhdGVUaW1lLnllYXIgPiAwO1xuICAgIHN3aXRjaCAodG9rZW4ubGVuZ3RoKSB7XG4gICAgICAgIGNhc2UgMTpcbiAgICAgICAgY2FzZSAyOlxuICAgICAgICBjYXNlIDM6XG4gICAgICAgICAgICByZXR1cm4gKEFEID8gbG9jYWxlLmVyYUFiYnJldmlhdGVkWzBdIDogbG9jYWxlLmVyYUFiYnJldmlhdGVkWzFdKTtcbiAgICAgICAgY2FzZSA0OlxuICAgICAgICAgICAgcmV0dXJuIChBRCA/IGxvY2FsZS5lcmFXaWRlWzBdIDogbG9jYWxlLmVyYVdpZGVbMV0pO1xuICAgICAgICBjYXNlIDU6XG4gICAgICAgICAgICByZXR1cm4gKEFEID8gbG9jYWxlLmVyYU5hcnJvd1swXSA6IGxvY2FsZS5lcmFOYXJyb3dbMV0pO1xuICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgLy8gdG9rZW5pemVyIHNob3VsZCBwcmV2ZW50IHRoaXNcbiAgICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gICAgICAgICAgICByZXR1cm4gdG9rZW4ucmF3O1xuICAgIH1cbn1cbi8qKlxuICogRm9ybWF0IHRoZSB5ZWFyXG4gKlxuICogQHBhcmFtIGRhdGVUaW1lIFRoZSBjdXJyZW50IHRpbWUgdG8gZm9ybWF0XG4gKiBAcGFyYW0gdG9rZW4gVGhlIHRva2VuIHBhc3NlZFxuICogQHJldHVybiBzdHJpbmdcbiAqIEB0aHJvd3Mgbm90aGluZ1xuICovXG5mdW5jdGlvbiBfZm9ybWF0WWVhcihkYXRlVGltZSwgdG9rZW4pIHtcbiAgICBzd2l0Y2ggKHRva2VuLnN5bWJvbCkge1xuICAgICAgICBjYXNlIFwieVwiOlxuICAgICAgICBjYXNlIFwiWVwiOlxuICAgICAgICBjYXNlIFwiclwiOlxuICAgICAgICAgICAgdmFyIHllYXJWYWx1ZSA9IHN0cmluZ3MucGFkTGVmdChkYXRlVGltZS55ZWFyLnRvU3RyaW5nKCksIHRva2VuLmxlbmd0aCwgXCIwXCIpO1xuICAgICAgICAgICAgaWYgKHRva2VuLmxlbmd0aCA9PT0gMikgeyAvLyBTcGVjaWFsIGNhc2U6IGV4YWN0bHkgdHdvIGNoYXJhY3RlcnMgYXJlIGV4cGVjdGVkXG4gICAgICAgICAgICAgICAgeWVhclZhbHVlID0geWVhclZhbHVlLnNsaWNlKC0yKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB5ZWFyVmFsdWU7XG4gICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAvLyB0b2tlbml6ZXIgc2hvdWxkIHByZXZlbnQgdGhpc1xuICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbiAgICAgICAgICAgIHJldHVybiB0b2tlbi5yYXc7XG4gICAgfVxufVxuLyoqXG4gKiBGb3JtYXQgdGhlIHF1YXJ0ZXJcbiAqXG4gKiBAcGFyYW0gZGF0ZVRpbWUgVGhlIGN1cnJlbnQgdGltZSB0byBmb3JtYXRcbiAqIEBwYXJhbSB0b2tlbiBUaGUgdG9rZW4gcGFzc2VkXG4gKiBAcmV0dXJuIHN0cmluZ1xuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LkZvcm1hdFN0cmluZyBmb3IgaW52YWxpZCBmb3JtYXQgcGF0dGVyblxuICovXG5mdW5jdGlvbiBfZm9ybWF0UXVhcnRlcihkYXRlVGltZSwgdG9rZW4sIGxvY2FsZSkge1xuICAgIHZhciBxdWFydGVyID0gTWF0aC5jZWlsKGRhdGVUaW1lLm1vbnRoIC8gMyk7XG4gICAgc3dpdGNoICh0b2tlbi5zeW1ib2wpIHtcbiAgICAgICAgY2FzZSBcIlFcIjpcbiAgICAgICAgICAgIHN3aXRjaCAodG9rZW4ubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgY2FzZSAxOlxuICAgICAgICAgICAgICAgIGNhc2UgMjpcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHN0cmluZ3MucGFkTGVmdChxdWFydGVyLnRvU3RyaW5nKCksIDIsIFwiMFwiKTtcbiAgICAgICAgICAgICAgICBjYXNlIDM6XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBsb2NhbGUucXVhcnRlckxldHRlciArIHF1YXJ0ZXI7XG4gICAgICAgICAgICAgICAgY2FzZSA0OlxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gbG9jYWxlLnF1YXJ0ZXJBYmJyZXZpYXRpb25zW3F1YXJ0ZXIgLSAxXSArIFwiIFwiICsgbG9jYWxlLnF1YXJ0ZXJXb3JkO1xuICAgICAgICAgICAgICAgIGNhc2UgNTpcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHF1YXJ0ZXIudG9TdHJpbmcoKTtcbiAgICAgICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgICAgIC8vIHRva2VuaXplciBzaG91bGQgcHJldmVudCB0aGlzXG4gICAgICAgICAgICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB0b2tlbi5yYXc7XG4gICAgICAgICAgICB9XG4gICAgICAgIGNhc2UgXCJxXCI6XG4gICAgICAgICAgICBzd2l0Y2ggKHRva2VuLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIGNhc2UgMTpcbiAgICAgICAgICAgICAgICBjYXNlIDI6XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBzdHJpbmdzLnBhZExlZnQocXVhcnRlci50b1N0cmluZygpLCAyLCBcIjBcIik7XG4gICAgICAgICAgICAgICAgY2FzZSAzOlxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gbG9jYWxlLnN0YW5kQWxvbmVRdWFydGVyTGV0dGVyICsgcXVhcnRlcjtcbiAgICAgICAgICAgICAgICBjYXNlIDQ6XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBsb2NhbGUuc3RhbmRBbG9uZVF1YXJ0ZXJBYmJyZXZpYXRpb25zW3F1YXJ0ZXIgLSAxXSArIFwiIFwiICsgbG9jYWxlLnN0YW5kQWxvbmVRdWFydGVyV29yZDtcbiAgICAgICAgICAgICAgICBjYXNlIDU6XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBxdWFydGVyLnRvU3RyaW5nKCk7XG4gICAgICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbiAgICAgICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgICAgICAvLyB0b2tlbml6ZXIgc2hvdWxkIHByZXZlbnQgdGhpc1xuICAgICAgICAgICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdG9rZW4ucmF3O1xuICAgICAgICAgICAgfVxuICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbiAgICAgICAgICAgIHJldHVybiAoMCwgZXJyb3JfMS50aHJvd0Vycm9yKShcIkFyZ3VtZW50LkZvcm1hdFN0cmluZ1wiLCBcImludmFsaWQgcXVhcnRlciBwYXR0ZXJuXCIpO1xuICAgIH1cbn1cbi8qKlxuICogRm9ybWF0IHRoZSBtb250aFxuICpcbiAqIEBwYXJhbSBkYXRlVGltZSBUaGUgY3VycmVudCB0aW1lIHRvIGZvcm1hdFxuICogQHBhcmFtIHRva2VuIFRoZSB0b2tlbiBwYXNzZWRcbiAqIEByZXR1cm4gc3RyaW5nXG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuRm9ybWF0U3RyaW5nIGZvciBpbnZhbGlkIGZvcm1hdCBwYXR0ZXJuXG4gKi9cbmZ1bmN0aW9uIF9mb3JtYXRNb250aChkYXRlVGltZSwgdG9rZW4sIGxvY2FsZSkge1xuICAgIHN3aXRjaCAodG9rZW4uc3ltYm9sKSB7XG4gICAgICAgIGNhc2UgXCJNXCI6XG4gICAgICAgICAgICBzd2l0Y2ggKHRva2VuLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIGNhc2UgMTpcbiAgICAgICAgICAgICAgICBjYXNlIDI6XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBzdHJpbmdzLnBhZExlZnQoZGF0ZVRpbWUubW9udGgudG9TdHJpbmcoKSwgdG9rZW4ubGVuZ3RoLCBcIjBcIik7XG4gICAgICAgICAgICAgICAgY2FzZSAzOlxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gbG9jYWxlLnNob3J0TW9udGhOYW1lc1tkYXRlVGltZS5tb250aCAtIDFdO1xuICAgICAgICAgICAgICAgIGNhc2UgNDpcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGxvY2FsZS5sb25nTW9udGhOYW1lc1tkYXRlVGltZS5tb250aCAtIDFdO1xuICAgICAgICAgICAgICAgIGNhc2UgNTpcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGxvY2FsZS5tb250aExldHRlcnNbZGF0ZVRpbWUubW9udGggLSAxXTtcbiAgICAgICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgICAgIC8vIHRva2VuaXplciBzaG91bGQgcHJldmVudCB0aGlzXG4gICAgICAgICAgICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB0b2tlbi5yYXc7XG4gICAgICAgICAgICB9XG4gICAgICAgIGNhc2UgXCJMXCI6XG4gICAgICAgICAgICBzd2l0Y2ggKHRva2VuLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIGNhc2UgMTpcbiAgICAgICAgICAgICAgICBjYXNlIDI6XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBzdHJpbmdzLnBhZExlZnQoZGF0ZVRpbWUubW9udGgudG9TdHJpbmcoKSwgdG9rZW4ubGVuZ3RoLCBcIjBcIik7XG4gICAgICAgICAgICAgICAgY2FzZSAzOlxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gbG9jYWxlLnN0YW5kQWxvbmVTaG9ydE1vbnRoTmFtZXNbZGF0ZVRpbWUubW9udGggLSAxXTtcbiAgICAgICAgICAgICAgICBjYXNlIDQ6XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBsb2NhbGUuc3RhbmRBbG9uZUxvbmdNb250aE5hbWVzW2RhdGVUaW1lLm1vbnRoIC0gMV07XG4gICAgICAgICAgICAgICAgY2FzZSA1OlxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gbG9jYWxlLnN0YW5kQWxvbmVNb250aExldHRlcnNbZGF0ZVRpbWUubW9udGggLSAxXTtcbiAgICAgICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgICAgIC8vIHRva2VuaXplciBzaG91bGQgcHJldmVudCB0aGlzXG4gICAgICAgICAgICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB0b2tlbi5yYXc7XG4gICAgICAgICAgICB9XG4gICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICAgICAgcmV0dXJuICgwLCBlcnJvcl8xLnRocm93RXJyb3IpKFwiQXJndW1lbnQuRm9ybWF0U3RyaW5nXCIsIFwiaW52YWxpZCBtb250aCBwYXR0ZXJuXCIpO1xuICAgIH1cbn1cbi8qKlxuICogRm9ybWF0IHRoZSB3ZWVrIG51bWJlclxuICpcbiAqIEBwYXJhbSBkYXRlVGltZSBUaGUgY3VycmVudCB0aW1lIHRvIGZvcm1hdFxuICogQHBhcmFtIHRva2VuIFRoZSB0b2tlbiBwYXNzZWRcbiAqIEByZXR1cm4gc3RyaW5nXG4gKiBAdGhyb3dzIG5vdGhpbmdcbiAqL1xuZnVuY3Rpb24gX2Zvcm1hdFdlZWsoZGF0ZVRpbWUsIHRva2VuKSB7XG4gICAgaWYgKHRva2VuLnN5bWJvbCA9PT0gXCJ3XCIpIHtcbiAgICAgICAgcmV0dXJuIHN0cmluZ3MucGFkTGVmdChiYXNpY3Mud2Vla051bWJlcihkYXRlVGltZS55ZWFyLCBkYXRlVGltZS5tb250aCwgZGF0ZVRpbWUuZGF5KS50b1N0cmluZygpLCB0b2tlbi5sZW5ndGgsIFwiMFwiKTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHJldHVybiBzdHJpbmdzLnBhZExlZnQoYmFzaWNzLndlZWtPZk1vbnRoKGRhdGVUaW1lLnllYXIsIGRhdGVUaW1lLm1vbnRoLCBkYXRlVGltZS5kYXkpLnRvU3RyaW5nKCksIHRva2VuLmxlbmd0aCwgXCIwXCIpO1xuICAgIH1cbn1cbi8qKlxuICogRm9ybWF0IHRoZSBkYXkgb2YgdGhlIG1vbnRoIChvciB5ZWFyKVxuICpcbiAqIEBwYXJhbSBkYXRlVGltZSBUaGUgY3VycmVudCB0aW1lIHRvIGZvcm1hdFxuICogQHBhcmFtIHRva2VuIFRoZSB0b2tlbiBwYXNzZWRcbiAqIEByZXR1cm4gc3RyaW5nXG4gKiBAdGhyb3dzIG5vdGhpbmdcbiAqL1xuZnVuY3Rpb24gX2Zvcm1hdERheShkYXRlVGltZSwgdG9rZW4pIHtcbiAgICBzd2l0Y2ggKHRva2VuLnN5bWJvbCkge1xuICAgICAgICBjYXNlIFwiZFwiOlxuICAgICAgICAgICAgcmV0dXJuIHN0cmluZ3MucGFkTGVmdChkYXRlVGltZS5kYXkudG9TdHJpbmcoKSwgdG9rZW4ubGVuZ3RoLCBcIjBcIik7XG4gICAgICAgIGNhc2UgXCJEXCI6XG4gICAgICAgICAgICB2YXIgZGF5T2ZZZWFyID0gYmFzaWNzLmRheU9mWWVhcihkYXRlVGltZS55ZWFyLCBkYXRlVGltZS5tb250aCwgZGF0ZVRpbWUuZGF5KSArIDE7XG4gICAgICAgICAgICByZXR1cm4gc3RyaW5ncy5wYWRMZWZ0KGRheU9mWWVhci50b1N0cmluZygpLCB0b2tlbi5sZW5ndGgsIFwiMFwiKTtcbiAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgIC8vIHRva2VuaXplciBzaG91bGQgcHJldmVudCB0aGlzXG4gICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICAgICAgcmV0dXJuIHRva2VuLnJhdztcbiAgICB9XG59XG4vKipcbiAqIEZvcm1hdCB0aGUgZGF5IG9mIHRoZSB3ZWVrXG4gKlxuICogQHBhcmFtIGRhdGVUaW1lIFRoZSBjdXJyZW50IHRpbWUgdG8gZm9ybWF0XG4gKiBAcGFyYW0gdG9rZW4gVGhlIHRva2VuIHBhc3NlZFxuICogQHJldHVybiBzdHJpbmdcbiAqIEB0aHJvd3Mgbm90aGluZ1xuICovXG5mdW5jdGlvbiBfZm9ybWF0V2Vla2RheShkYXRlVGltZSwgdG9rZW4sIGxvY2FsZSkge1xuICAgIHZhciB3ZWVrRGF5TnVtYmVyID0gYmFzaWNzLndlZWtEYXlOb0xlYXBTZWNzKGRhdGVUaW1lLnVuaXhNaWxsaXMpO1xuICAgIHN3aXRjaCAodG9rZW4ubGVuZ3RoKSB7XG4gICAgICAgIGNhc2UgMTpcbiAgICAgICAgY2FzZSAyOlxuICAgICAgICAgICAgaWYgKHRva2VuLnN5bWJvbCA9PT0gXCJlXCIpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gc3RyaW5ncy5wYWRMZWZ0KGJhc2ljcy53ZWVrRGF5Tm9MZWFwU2VjcyhkYXRlVGltZS51bml4TWlsbGlzKS50b1N0cmluZygpLCB0b2tlbi5sZW5ndGgsIFwiMFwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIHJldHVybiBsb2NhbGUuc2hvcnRXZWVrZGF5TmFtZXNbd2Vla0RheU51bWJlcl07XG4gICAgICAgICAgICB9XG4gICAgICAgIGNhc2UgMzpcbiAgICAgICAgICAgIHJldHVybiBsb2NhbGUuc2hvcnRXZWVrZGF5TmFtZXNbd2Vla0RheU51bWJlcl07XG4gICAgICAgIGNhc2UgNDpcbiAgICAgICAgICAgIHJldHVybiBsb2NhbGUubG9uZ1dlZWtkYXlOYW1lc1t3ZWVrRGF5TnVtYmVyXTtcbiAgICAgICAgY2FzZSA1OlxuICAgICAgICAgICAgcmV0dXJuIGxvY2FsZS53ZWVrZGF5TGV0dGVyc1t3ZWVrRGF5TnVtYmVyXTtcbiAgICAgICAgY2FzZSA2OlxuICAgICAgICAgICAgcmV0dXJuIGxvY2FsZS53ZWVrZGF5VHdvTGV0dGVyc1t3ZWVrRGF5TnVtYmVyXTtcbiAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgIC8vIHRva2VuaXplciBzaG91bGQgcHJldmVudCB0aGlzXG4gICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICAgICAgcmV0dXJuIHRva2VuLnJhdztcbiAgICB9XG59XG4vKipcbiAqIEZvcm1hdCB0aGUgRGF5IFBlcmlvZCAoQU0gb3IgUE0pXG4gKlxuICogQHBhcmFtIGRhdGVUaW1lIFRoZSBjdXJyZW50IHRpbWUgdG8gZm9ybWF0XG4gKiBAcGFyYW0gdG9rZW4gVGhlIHRva2VuIHBhc3NlZFxuICogQHJldHVybiBzdHJpbmdcbiAqIEB0aHJvd3Mgbm90aGluZ1xuICovXG5mdW5jdGlvbiBfZm9ybWF0RGF5UGVyaW9kKGRhdGVUaW1lLCB0b2tlbiwgbG9jYWxlKSB7XG4gICAgc3dpdGNoICh0b2tlbi5zeW1ib2wpIHtcbiAgICAgICAgY2FzZSBcImFcIjoge1xuICAgICAgICAgICAgaWYgKHRva2VuLmxlbmd0aCA8PSAzKSB7XG4gICAgICAgICAgICAgICAgaWYgKGRhdGVUaW1lLmhvdXIgPCAxMikge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gbG9jYWxlLmRheVBlcmlvZEFiYnJldmlhdGVkLmFtO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGxvY2FsZS5kYXlQZXJpb2RBYmJyZXZpYXRlZC5wbTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmICh0b2tlbi5sZW5ndGggPT09IDQpIHtcbiAgICAgICAgICAgICAgICBpZiAoZGF0ZVRpbWUuaG91ciA8IDEyKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBsb2NhbGUuZGF5UGVyaW9kV2lkZS5hbTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBsb2NhbGUuZGF5UGVyaW9kV2lkZS5wbTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBpZiAoZGF0ZVRpbWUuaG91ciA8IDEyKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBsb2NhbGUuZGF5UGVyaW9kTmFycm93LmFtO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGxvY2FsZS5kYXlQZXJpb2ROYXJyb3cucG07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGNhc2UgXCJiXCI6XG4gICAgICAgIGNhc2UgXCJCXCI6IHtcbiAgICAgICAgICAgIGlmICh0b2tlbi5sZW5ndGggPD0gMykge1xuICAgICAgICAgICAgICAgIGlmIChkYXRlVGltZS5ob3VyID09PSAwICYmIGRhdGVUaW1lLm1pbnV0ZSA9PT0gMCAmJiBkYXRlVGltZS5zZWNvbmQgPT09IDAgJiYgZGF0ZVRpbWUubWlsbGkgPT09IDApIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGxvY2FsZS5kYXlQZXJpb2RBYmJyZXZpYXRlZC5taWRuaWdodDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSBpZiAoZGF0ZVRpbWUuaG91ciA9PT0gMTIgJiYgZGF0ZVRpbWUubWludXRlID09PSAwICYmIGRhdGVUaW1lLnNlY29uZCA9PT0gMCAmJiBkYXRlVGltZS5taWxsaSA9PT0gMCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gbG9jYWxlLmRheVBlcmlvZEFiYnJldmlhdGVkLm5vb247XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2UgaWYgKGRhdGVUaW1lLmhvdXIgPCAxMikge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gbG9jYWxlLmRheVBlcmlvZEFiYnJldmlhdGVkLmFtO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGxvY2FsZS5kYXlQZXJpb2RBYmJyZXZpYXRlZC5wbTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmICh0b2tlbi5sZW5ndGggPT09IDQpIHtcbiAgICAgICAgICAgICAgICBpZiAoZGF0ZVRpbWUuaG91ciA9PT0gMCAmJiBkYXRlVGltZS5taW51dGUgPT09IDAgJiYgZGF0ZVRpbWUuc2Vjb25kID09PSAwICYmIGRhdGVUaW1lLm1pbGxpID09PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBsb2NhbGUuZGF5UGVyaW9kV2lkZS5taWRuaWdodDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSBpZiAoZGF0ZVRpbWUuaG91ciA9PT0gMTIgJiYgZGF0ZVRpbWUubWludXRlID09PSAwICYmIGRhdGVUaW1lLnNlY29uZCA9PT0gMCAmJiBkYXRlVGltZS5taWxsaSA9PT0gMCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gbG9jYWxlLmRheVBlcmlvZFdpZGUubm9vbjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSBpZiAoZGF0ZVRpbWUuaG91ciA8IDEyKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBsb2NhbGUuZGF5UGVyaW9kV2lkZS5hbTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBsb2NhbGUuZGF5UGVyaW9kV2lkZS5wbTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBpZiAoZGF0ZVRpbWUuaG91ciA9PT0gMCAmJiBkYXRlVGltZS5taW51dGUgPT09IDAgJiYgZGF0ZVRpbWUuc2Vjb25kID09PSAwICYmIGRhdGVUaW1lLm1pbGxpID09PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBsb2NhbGUuZGF5UGVyaW9kTmFycm93Lm1pZG5pZ2h0O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIGlmIChkYXRlVGltZS5ob3VyID09PSAxMiAmJiBkYXRlVGltZS5taW51dGUgPT09IDAgJiYgZGF0ZVRpbWUuc2Vjb25kID09PSAwICYmIGRhdGVUaW1lLm1pbGxpID09PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBsb2NhbGUuZGF5UGVyaW9kTmFycm93Lm5vb247XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2UgaWYgKGRhdGVUaW1lLmhvdXIgPCAxMikge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gbG9jYWxlLmRheVBlcmlvZE5hcnJvdy5hbTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBsb2NhbGUuZGF5UGVyaW9kTmFycm93LnBtO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgLy8gdG9rZW5pemVyIHNob3VsZCBwcmV2ZW50IHRoaXNcbiAgICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gICAgICAgICAgICByZXR1cm4gdG9rZW4ucmF3O1xuICAgIH1cbn1cbi8qKlxuICogRm9ybWF0IHRoZSBIb3VyXG4gKlxuICogQHBhcmFtIGRhdGVUaW1lIFRoZSBjdXJyZW50IHRpbWUgdG8gZm9ybWF0XG4gKiBAcGFyYW0gdG9rZW4gVGhlIHRva2VuIHBhc3NlZFxuICogQHJldHVybiBzdHJpbmdcbiAqIEB0aHJvd3Mgbm90aGluZ1xuICovXG5mdW5jdGlvbiBfZm9ybWF0SG91cihkYXRlVGltZSwgdG9rZW4pIHtcbiAgICB2YXIgaG91ciA9IGRhdGVUaW1lLmhvdXI7XG4gICAgc3dpdGNoICh0b2tlbi5zeW1ib2wpIHtcbiAgICAgICAgY2FzZSBcImhcIjpcbiAgICAgICAgICAgIGhvdXIgPSBob3VyICUgMTI7XG4gICAgICAgICAgICBpZiAoaG91ciA9PT0gMCkge1xuICAgICAgICAgICAgICAgIGhvdXIgPSAxMjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBzdHJpbmdzLnBhZExlZnQoaG91ci50b1N0cmluZygpLCB0b2tlbi5sZW5ndGgsIFwiMFwiKTtcbiAgICAgICAgY2FzZSBcIkhcIjpcbiAgICAgICAgICAgIHJldHVybiBzdHJpbmdzLnBhZExlZnQoaG91ci50b1N0cmluZygpLCB0b2tlbi5sZW5ndGgsIFwiMFwiKTtcbiAgICAgICAgY2FzZSBcIktcIjpcbiAgICAgICAgICAgIGhvdXIgPSBob3VyICUgMTI7XG4gICAgICAgICAgICByZXR1cm4gc3RyaW5ncy5wYWRMZWZ0KGhvdXIudG9TdHJpbmcoKSwgdG9rZW4ubGVuZ3RoLCBcIjBcIik7XG4gICAgICAgIGNhc2UgXCJrXCI6XG4gICAgICAgICAgICBpZiAoaG91ciA9PT0gMCkge1xuICAgICAgICAgICAgICAgIGhvdXIgPSAyNDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBzdHJpbmdzLnBhZExlZnQoaG91ci50b1N0cmluZygpLCB0b2tlbi5sZW5ndGgsIFwiMFwiKTtcbiAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgIC8vIHRva2VuaXplciBzaG91bGQgcHJldmVudCB0aGlzXG4gICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICAgICAgcmV0dXJuIHRva2VuLnJhdztcbiAgICB9XG59XG4vKipcbiAqIEZvcm1hdCB0aGUgbWludXRlXG4gKlxuICogQHBhcmFtIGRhdGVUaW1lIFRoZSBjdXJyZW50IHRpbWUgdG8gZm9ybWF0XG4gKiBAcGFyYW0gdG9rZW4gVGhlIHRva2VuIHBhc3NlZFxuICogQHJldHVybiBzdHJpbmdcbiAqIEB0aHJvd3Mgbm90aGluZ1xuICovXG5mdW5jdGlvbiBfZm9ybWF0TWludXRlKGRhdGVUaW1lLCB0b2tlbikge1xuICAgIHJldHVybiBzdHJpbmdzLnBhZExlZnQoZGF0ZVRpbWUubWludXRlLnRvU3RyaW5nKCksIHRva2VuLmxlbmd0aCwgXCIwXCIpO1xufVxuLyoqXG4gKiBGb3JtYXQgdGhlIHNlY29uZHMgKG9yIGZyYWN0aW9uIG9mIGEgc2Vjb25kKVxuICpcbiAqIEBwYXJhbSBkYXRlVGltZSBUaGUgY3VycmVudCB0aW1lIHRvIGZvcm1hdFxuICogQHBhcmFtIHRva2VuIFRoZSB0b2tlbiBwYXNzZWRcbiAqIEByZXR1cm4gc3RyaW5nXG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuKiogaWYgYW55IG9mIHRoZSBnaXZlbiBkYXRlVGltZSBlbGVtZW50cyBhcmUgaW52YWxpZFxuICovXG5mdW5jdGlvbiBfZm9ybWF0U2Vjb25kKGRhdGVUaW1lLCB0b2tlbikge1xuICAgIHN3aXRjaCAodG9rZW4uc3ltYm9sKSB7XG4gICAgICAgIGNhc2UgXCJzXCI6XG4gICAgICAgICAgICByZXR1cm4gc3RyaW5ncy5wYWRMZWZ0KGRhdGVUaW1lLnNlY29uZC50b1N0cmluZygpLCB0b2tlbi5sZW5ndGgsIFwiMFwiKTtcbiAgICAgICAgY2FzZSBcIlNcIjpcbiAgICAgICAgICAgIHZhciBmcmFjdGlvbiA9IGRhdGVUaW1lLm1pbGxpO1xuICAgICAgICAgICAgdmFyIGZyYWN0aW9uU3RyaW5nID0gc3RyaW5ncy5wYWRMZWZ0KGZyYWN0aW9uLnRvU3RyaW5nKCksIDMsIFwiMFwiKTtcbiAgICAgICAgICAgIGZyYWN0aW9uU3RyaW5nID0gc3RyaW5ncy5wYWRSaWdodChmcmFjdGlvblN0cmluZywgdG9rZW4ubGVuZ3RoLCBcIjBcIik7XG4gICAgICAgICAgICByZXR1cm4gZnJhY3Rpb25TdHJpbmcuc2xpY2UoMCwgdG9rZW4ubGVuZ3RoKTtcbiAgICAgICAgY2FzZSBcIkFcIjpcbiAgICAgICAgICAgIHJldHVybiBzdHJpbmdzLnBhZExlZnQoYmFzaWNzLnNlY29uZE9mRGF5KGRhdGVUaW1lLmhvdXIsIGRhdGVUaW1lLm1pbnV0ZSwgZGF0ZVRpbWUuc2Vjb25kKS50b1N0cmluZygpLCB0b2tlbi5sZW5ndGgsIFwiMFwiKTtcbiAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgIC8vIHRva2VuaXplciBzaG91bGQgcHJldmVudCB0aGlzXG4gICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICAgICAgcmV0dXJuIHRva2VuLnJhdztcbiAgICB9XG59XG4vKipcbiAqIEZvcm1hdCB0aGUgdGltZSB6b25lLiBGb3IgdGhpcywgd2UgbmVlZCB0aGUgY3VycmVudCB0aW1lLCB0aGUgdGltZSBpbiBVVEMgYW5kIHRoZSB0aW1lIHpvbmVcbiAqIEBwYXJhbSBjdXJyZW50VGltZSBUaGUgdGltZSB0byBmb3JtYXRcbiAqIEBwYXJhbSB1dGNUaW1lIFRoZSB0aW1lIGluIFVUQ1xuICogQHBhcmFtIHpvbmUgVGhlIHRpbWV6b25lIGN1cnJlbnRUaW1lIGlzIGluXG4gKiBAcGFyYW0gdG9rZW4gVGhlIHRva2VuIHBhc3NlZFxuICogQHJldHVybiBzdHJpbmdcbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5JbnZhbGlkVGltZVpvbmVEYXRhIGlmIHZhbHVlcyBpbiB0aGUgdGltZSB6b25lIGRhdGFiYXNlIGFyZSBpbnZhbGlkXG4gKi9cbmZ1bmN0aW9uIF9mb3JtYXRab25lKGN1cnJlbnRUaW1lLCB1dGNUaW1lLCB6b25lLCB0b2tlbikge1xuICAgIGlmICghem9uZSkge1xuICAgICAgICByZXR1cm4gXCJcIjtcbiAgICB9XG4gICAgdmFyIG9mZnNldCA9IE1hdGgucm91bmQoKGN1cnJlbnRUaW1lLnVuaXhNaWxsaXMgLSB1dGNUaW1lLnVuaXhNaWxsaXMpIC8gNjAwMDApO1xuICAgIHZhciBvZmZzZXRIb3VycyA9IE1hdGguZmxvb3IoTWF0aC5hYnMob2Zmc2V0KSAvIDYwKTtcbiAgICB2YXIgb2Zmc2V0SG91cnNTdHJpbmcgPSBzdHJpbmdzLnBhZExlZnQob2Zmc2V0SG91cnMudG9TdHJpbmcoKSwgMiwgXCIwXCIpO1xuICAgIG9mZnNldEhvdXJzU3RyaW5nID0gKG9mZnNldCA+PSAwID8gXCIrXCIgKyBvZmZzZXRIb3Vyc1N0cmluZyA6IFwiLVwiICsgb2Zmc2V0SG91cnNTdHJpbmcpO1xuICAgIHZhciBvZmZzZXRNaW51dGVzID0gTWF0aC5hYnMob2Zmc2V0ICUgNjApO1xuICAgIHZhciBvZmZzZXRNaW51dGVzU3RyaW5nID0gc3RyaW5ncy5wYWRMZWZ0KG9mZnNldE1pbnV0ZXMudG9TdHJpbmcoKSwgMiwgXCIwXCIpO1xuICAgIHZhciByZXN1bHQ7XG4gICAgc3dpdGNoICh0b2tlbi5zeW1ib2wpIHtcbiAgICAgICAgY2FzZSBcIk9cIjpcbiAgICAgICAgICAgIHJlc3VsdCA9IFwiR01UXCI7XG4gICAgICAgICAgICBpZiAob2Zmc2V0ID49IDApIHtcbiAgICAgICAgICAgICAgICByZXN1bHQgKz0gXCIrXCI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXN1bHQgKz0gXCItXCI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXN1bHQgKz0gb2Zmc2V0SG91cnMudG9TdHJpbmcoKTtcbiAgICAgICAgICAgIGlmICh0b2tlbi5sZW5ndGggPj0gNCB8fCBvZmZzZXRNaW51dGVzICE9PSAwKSB7XG4gICAgICAgICAgICAgICAgcmVzdWx0ICs9IFwiOlwiICsgb2Zmc2V0TWludXRlc1N0cmluZztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICh0b2tlbi5sZW5ndGggPiA0KSB7XG4gICAgICAgICAgICAgICAgcmVzdWx0ICs9IHRva2VuLnJhdy5zbGljZSg0KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgIGNhc2UgXCJaXCI6XG4gICAgICAgICAgICBzd2l0Y2ggKHRva2VuLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIGNhc2UgMTpcbiAgICAgICAgICAgICAgICBjYXNlIDI6XG4gICAgICAgICAgICAgICAgY2FzZSAzOlxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gb2Zmc2V0SG91cnNTdHJpbmcgKyBvZmZzZXRNaW51dGVzU3RyaW5nO1xuICAgICAgICAgICAgICAgIGNhc2UgNDpcbiAgICAgICAgICAgICAgICAgICAgdmFyIG5ld1Rva2VuID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgbGVuZ3RoOiA0LFxuICAgICAgICAgICAgICAgICAgICAgICAgcmF3OiBcIk9PT09cIixcbiAgICAgICAgICAgICAgICAgICAgICAgIHN5bWJvbDogXCJPXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiB0b2tlbl8xLlRva2VuVHlwZS5aT05FXG4gICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBfZm9ybWF0Wm9uZShjdXJyZW50VGltZSwgdXRjVGltZSwgem9uZSwgbmV3VG9rZW4pO1xuICAgICAgICAgICAgICAgIGNhc2UgNTpcbiAgICAgICAgICAgICAgICAgICAgaWYgKG9mZnNldCA9PT0gMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIFwiWlwiO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBvZmZzZXRIb3Vyc1N0cmluZyArIFwiOlwiICsgb2Zmc2V0TWludXRlc1N0cmluZztcbiAgICAgICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgICAgIC8vIHRva2VuaXplciBzaG91bGQgcHJldmVudCB0aGlzXG4gICAgICAgICAgICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB0b2tlbi5yYXc7XG4gICAgICAgICAgICB9XG4gICAgICAgIGNhc2UgXCJ6XCI6XG4gICAgICAgICAgICBzd2l0Y2ggKHRva2VuLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIGNhc2UgMTpcbiAgICAgICAgICAgICAgICBjYXNlIDI6XG4gICAgICAgICAgICAgICAgY2FzZSAzOlxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gem9uZS5hYmJyZXZpYXRpb25Gb3JVdGMoY3VycmVudFRpbWUsIHRydWUpO1xuICAgICAgICAgICAgICAgIGNhc2UgNDpcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHpvbmUudG9TdHJpbmcoKTtcbiAgICAgICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgICAgIC8vIHRva2VuaXplciBzaG91bGQgcHJldmVudCB0aGlzXG4gICAgICAgICAgICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB0b2tlbi5yYXc7XG4gICAgICAgICAgICB9XG4gICAgICAgIGNhc2UgXCJ2XCI6XG4gICAgICAgICAgICBpZiAodG9rZW4ubGVuZ3RoID09PSAxKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHpvbmUuYWJicmV2aWF0aW9uRm9yVXRjKGN1cnJlbnRUaW1lLCBmYWxzZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gem9uZS50b1N0cmluZygpO1xuICAgICAgICAgICAgfVxuICAgICAgICBjYXNlIFwiVlwiOlxuICAgICAgICAgICAgc3dpdGNoICh0b2tlbi5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICBjYXNlIDE6XG4gICAgICAgICAgICAgICAgICAgIC8vIE5vdCBpbXBsZW1lbnRlZFxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gXCJ1bmtcIjtcbiAgICAgICAgICAgICAgICBjYXNlIDI6XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB6b25lLm5hbWUoKTtcbiAgICAgICAgICAgICAgICBjYXNlIDM6XG4gICAgICAgICAgICAgICAgY2FzZSA0OlxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gXCJVbmtub3duXCI7XG4gICAgICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbiAgICAgICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgICAgICAvLyB0b2tlbml6ZXIgc2hvdWxkIHByZXZlbnQgdGhpc1xuICAgICAgICAgICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdG9rZW4ucmF3O1xuICAgICAgICAgICAgfVxuICAgICAgICBjYXNlIFwiWFwiOlxuICAgICAgICBjYXNlIFwieFwiOlxuICAgICAgICAgICAgaWYgKHRva2VuLnN5bWJvbCA9PT0gXCJYXCIgJiYgb2Zmc2V0ID09PSAwKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIFwiWlwiO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgc3dpdGNoICh0b2tlbi5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICBjYXNlIDE6XG4gICAgICAgICAgICAgICAgICAgIHJlc3VsdCA9IG9mZnNldEhvdXJzU3RyaW5nO1xuICAgICAgICAgICAgICAgICAgICBpZiAob2Zmc2V0TWludXRlcyAhPT0gMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0ICs9IG9mZnNldE1pbnV0ZXNTdHJpbmc7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgICAgICAgICBjYXNlIDI6XG4gICAgICAgICAgICAgICAgY2FzZSA0OiAvLyBObyBzZWNvbmRzIGluIG91ciBpbXBsZW1lbnRhdGlvbiwgc28gdGhpcyBpcyB0aGUgc2FtZVxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gb2Zmc2V0SG91cnNTdHJpbmcgKyBvZmZzZXRNaW51dGVzU3RyaW5nO1xuICAgICAgICAgICAgICAgIGNhc2UgMzpcbiAgICAgICAgICAgICAgICBjYXNlIDU6IC8vIE5vIHNlY29uZHMgaW4gb3VyIGltcGxlbWVudGF0aW9uLCBzbyB0aGlzIGlzIHRoZSBzYW1lXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBvZmZzZXRIb3Vyc1N0cmluZyArIFwiOlwiICsgb2Zmc2V0TWludXRlc1N0cmluZztcbiAgICAgICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgICAgIC8vIHRva2VuaXplciBzaG91bGQgcHJldmVudCB0aGlzXG4gICAgICAgICAgICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB0b2tlbi5yYXc7XG4gICAgICAgICAgICB9XG4gICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAvLyB0b2tlbml6ZXIgc2hvdWxkIHByZXZlbnQgdGhpc1xuICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbiAgICAgICAgICAgIHJldHVybiB0b2tlbi5yYXc7XG4gICAgfVxufVxuLy8jIHNvdXJjZU1hcHBpbmdVUkw9Zm9ybWF0LmpzLm1hcCIsIi8qKlxuICogQ29weXJpZ2h0KGMpIDIwMTQgQUJCIFN3aXR6ZXJsYW5kIEx0ZC5cbiAqXG4gKiBHbG9iYWwgZnVuY3Rpb25zIGRlcGVuZGluZyBvbiBEYXRlVGltZS9EdXJhdGlvbiBldGNcbiAqL1xuXCJ1c2Ugc3RyaWN0XCI7XG5PYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgXCJfX2VzTW9kdWxlXCIsIHsgdmFsdWU6IHRydWUgfSk7XG5leHBvcnRzLmFicyA9IGV4cG9ydHMubWF4ID0gZXhwb3J0cy5taW4gPSB2b2lkIDA7XG52YXIgYXNzZXJ0XzEgPSByZXF1aXJlKFwiLi9hc3NlcnRcIik7XG4vKipcbiAqIFJldHVybnMgdGhlIG1pbmltdW0gb2YgdHdvIERhdGVUaW1lcyBvciBEdXJhdGlvbnNcbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5EMSBpZiBkMSBpcyB1bmRlZmluZWQvbnVsbFxuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LkQyIGlmIGQxIGlzIHVuZGVmaW5lZC9udWxsLCBvciBpZiBkMSBhbmQgZDIgYXJlIG5vdCBib3RoIGRhdGV0aW1lc1xuICovXG5mdW5jdGlvbiBtaW4oZDEsIGQyKSB7XG4gICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKGQxLCBcIkFyZ3VtZW50LkQxXCIsIFwiZmlyc3QgYXJndW1lbnQgaXMgZmFsc3lcIik7XG4gICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKGQyLCBcIkFyZ3VtZW50LkQyXCIsIFwic2Vjb25kIGFyZ3VtZW50IGlzIGZhbHN5XCIpO1xuICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKGQxLmtpbmQgPT09IGQyLmtpbmQsIFwiQXJndW1lbnQuRDJcIiwgXCJleHBlY3RlZCBlaXRoZXIgdHdvIGRhdGV0aW1lcyBvciB0d28gZHVyYXRpb25zXCIpO1xuICAgIHJldHVybiBkMS5taW4oZDIpO1xufVxuZXhwb3J0cy5taW4gPSBtaW47XG4vKipcbiAqIFJldHVybnMgdGhlIG1heGltdW0gb2YgdHdvIERhdGVUaW1lcyBvciBEdXJhdGlvbnNcbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5EMSBpZiBkMSBpcyB1bmRlZmluZWQvbnVsbFxuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LkQyIGlmIGQxIGlzIHVuZGVmaW5lZC9udWxsLCBvciBpZiBkMSBhbmQgZDIgYXJlIG5vdCBib3RoIGRhdGV0aW1lc1xuICovXG5mdW5jdGlvbiBtYXgoZDEsIGQyKSB7XG4gICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKGQxLCBcIkFyZ3VtZW50LkQxXCIsIFwiZmlyc3QgYXJndW1lbnQgaXMgZmFsc3lcIik7XG4gICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKGQyLCBcIkFyZ3VtZW50LkQyXCIsIFwic2Vjb25kIGFyZ3VtZW50IGlzIGZhbHN5XCIpO1xuICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKGQxLmtpbmQgPT09IGQyLmtpbmQsIFwiQXJndW1lbnQuRDJcIiwgXCJleHBlY3RlZCBlaXRoZXIgdHdvIGRhdGV0aW1lcyBvciB0d28gZHVyYXRpb25zXCIpO1xuICAgIHJldHVybiBkMS5tYXgoZDIpO1xufVxuZXhwb3J0cy5tYXggPSBtYXg7XG4vKipcbiAqIFJldHVybnMgdGhlIGFic29sdXRlIHZhbHVlIG9mIGEgRHVyYXRpb25cbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5EIGlmIGQgaXMgdW5kZWZpbmVkL251bGxcbiAqL1xuZnVuY3Rpb24gYWJzKGQpIHtcbiAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkoZCwgXCJBcmd1bWVudC5EXCIsIFwiZmlyc3QgYXJndW1lbnQgaXMgZmFsc3lcIik7XG4gICAgcmV0dXJuIGQuYWJzKCk7XG59XG5leHBvcnRzLmFicyA9IGFicztcbi8vIyBzb3VyY2VNYXBwaW5nVVJMPWdsb2JhbHMuanMubWFwIiwiLyoqXG4gKiBDb3B5cmlnaHQoYykgMjAxNCBBQkIgU3dpdHplcmxhbmQgTHRkLlxuICovXG5cInVzZSBzdHJpY3RcIjtcbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIl9fZXNNb2R1bGVcIiwgeyB2YWx1ZTogdHJ1ZSB9KTtcbmV4cG9ydHMuRGF0ZUZ1bmN0aW9ucyA9IHZvaWQgMDtcbi8qKlxuICogSW5kaWNhdGVzIGhvdyBhIERhdGUgb2JqZWN0IHNob3VsZCBiZSBpbnRlcnByZXRlZC5cbiAqIEVpdGhlciB3ZSBjYW4gdGFrZSBnZXRZZWFyKCksIGdldE1vbnRoKCkgZXRjIGZvciBvdXIgZmllbGRcbiAqIHZhbHVlcywgb3Igd2UgY2FuIHRha2UgZ2V0VVRDWWVhcigpLCBnZXRVdGNNb250aCgpIGV0YyB0byBkbyB0aGF0LlxuICovXG52YXIgRGF0ZUZ1bmN0aW9ucztcbihmdW5jdGlvbiAoRGF0ZUZ1bmN0aW9ucykge1xuICAgIC8qKlxuICAgICAqIFVzZSB0aGUgRGF0ZS5nZXRGdWxsWWVhcigpLCBEYXRlLmdldE1vbnRoKCksIC4uLiBmdW5jdGlvbnMuXG4gICAgICovXG4gICAgRGF0ZUZ1bmN0aW9uc1tEYXRlRnVuY3Rpb25zW1wiR2V0XCJdID0gMF0gPSBcIkdldFwiO1xuICAgIC8qKlxuICAgICAqIFVzZSB0aGUgRGF0ZS5nZXRVVENGdWxsWWVhcigpLCBEYXRlLmdldFVUQ01vbnRoKCksIC4uLiBmdW5jdGlvbnMuXG4gICAgICovXG4gICAgRGF0ZUZ1bmN0aW9uc1tEYXRlRnVuY3Rpb25zW1wiR2V0VVRDXCJdID0gMV0gPSBcIkdldFVUQ1wiO1xufSkoRGF0ZUZ1bmN0aW9ucyB8fCAoZXhwb3J0cy5EYXRlRnVuY3Rpb25zID0gRGF0ZUZ1bmN0aW9ucyA9IHt9KSk7XG4vLyMgc291cmNlTWFwcGluZ1VSTD1qYXZhc2NyaXB0LmpzLm1hcCIsIlwidXNlIHN0cmljdFwiO1xuLyoqXG4gKiBDb3B5cmlnaHQoYykgMjAxNyBBQkIgU3dpdHplcmxhbmQgTHRkLlxuICovXG5PYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgXCJfX2VzTW9kdWxlXCIsIHsgdmFsdWU6IHRydWUgfSk7XG5leHBvcnRzLkRFRkFVTFRfTE9DQUxFID0gZXhwb3J0cy5EQVlfUEVSSU9EU19OQVJST1cgPSBleHBvcnRzLkRBWV9QRVJJT0RTX1dJREUgPSBleHBvcnRzLkRBWV9QRVJJT0RTX0FCQlJFVklBVEVEID0gZXhwb3J0cy5XRUVLREFZX0xFVFRFUlMgPSBleHBvcnRzLldFRUtEQVlfVFdPX0xFVFRFUlMgPSBleHBvcnRzLlNIT1JUX1dFRUtEQVlfTkFNRVMgPSBleHBvcnRzLkxPTkdfV0VFS0RBWV9OQU1FUyA9IGV4cG9ydHMuU1RBTkRfQUxPTkVfTU9OVEhfTEVUVEVSUyA9IGV4cG9ydHMuU1RBTkRfQUxPTkVfU0hPUlRfTU9OVEhfTkFNRVMgPSBleHBvcnRzLlNUQU5EX0FMT05FX0xPTkdfTU9OVEhfTkFNRVMgPSBleHBvcnRzLk1PTlRIX0xFVFRFUlMgPSBleHBvcnRzLlNIT1JUX01PTlRIX05BTUVTID0gZXhwb3J0cy5MT05HX01PTlRIX05BTUVTID0gZXhwb3J0cy5TVEFORF9BTE9ORV9RVUFSVEVSX0FCQlJFVklBVElPTlMgPSBleHBvcnRzLlNUQU5EX0FMT05FX1FVQVJURVJfV09SRCA9IGV4cG9ydHMuU1RBTkRfQUxPTkVfUVVBUlRFUl9MRVRURVIgPSBleHBvcnRzLlFVQVJURVJfQUJCUkVWSUFUSU9OUyA9IGV4cG9ydHMuUVVBUlRFUl9XT1JEID0gZXhwb3J0cy5RVUFSVEVSX0xFVFRFUiA9IGV4cG9ydHMuRVJBX05BTUVTX0FCQlJFVklBVEVEID0gZXhwb3J0cy5FUkFfTkFNRVNfV0lERSA9IGV4cG9ydHMuRVJBX05BTUVTX05BUlJPVyA9IHZvaWQgMDtcbmV4cG9ydHMuRVJBX05BTUVTX05BUlJPVyA9IFtcIkFcIiwgXCJCXCJdO1xuZXhwb3J0cy5FUkFfTkFNRVNfV0lERSA9IFtcIkFubm8gRG9taW5pXCIsIFwiQmVmb3JlIENocmlzdFwiXTtcbmV4cG9ydHMuRVJBX05BTUVTX0FCQlJFVklBVEVEID0gW1wiQURcIiwgXCJCQ1wiXTtcbmV4cG9ydHMuUVVBUlRFUl9MRVRURVIgPSBcIlFcIjtcbmV4cG9ydHMuUVVBUlRFUl9XT1JEID0gXCJxdWFydGVyXCI7XG5leHBvcnRzLlFVQVJURVJfQUJCUkVWSUFUSU9OUyA9IFtcIjFzdFwiLCBcIjJuZFwiLCBcIjNyZFwiLCBcIjR0aFwiXTtcbi8qKlxuICogSW4gc29tZSBsYW5ndWFnZXMsIGRpZmZlcmVudCB3b3JkcyBhcmUgbmVjZXNzYXJ5IGZvciBzdGFuZC1hbG9uZSBxdWFydGVyIG5hbWVzXG4gKi9cbmV4cG9ydHMuU1RBTkRfQUxPTkVfUVVBUlRFUl9MRVRURVIgPSBleHBvcnRzLlFVQVJURVJfTEVUVEVSO1xuZXhwb3J0cy5TVEFORF9BTE9ORV9RVUFSVEVSX1dPUkQgPSBleHBvcnRzLlFVQVJURVJfV09SRDtcbmV4cG9ydHMuU1RBTkRfQUxPTkVfUVVBUlRFUl9BQkJSRVZJQVRJT05TID0gZXhwb3J0cy5RVUFSVEVSX0FCQlJFVklBVElPTlMuc2xpY2UoKTtcbmV4cG9ydHMuTE9OR19NT05USF9OQU1FUyA9IFtcIkphbnVhcnlcIiwgXCJGZWJydWFyeVwiLCBcIk1hcmNoXCIsIFwiQXByaWxcIiwgXCJNYXlcIiwgXCJKdW5lXCIsIFwiSnVseVwiLCBcIkF1Z3VzdFwiLCBcIlNlcHRlbWJlclwiLCBcIk9jdG9iZXJcIiwgXCJOb3ZlbWJlclwiLCBcIkRlY2VtYmVyXCJdO1xuZXhwb3J0cy5TSE9SVF9NT05USF9OQU1FUyA9IFtcIkphblwiLCBcIkZlYlwiLCBcIk1hclwiLCBcIkFwclwiLCBcIk1heVwiLCBcIkp1blwiLCBcIkp1bFwiLCBcIkF1Z1wiLCBcIlNlcFwiLCBcIk9jdFwiLCBcIk5vdlwiLCBcIkRlY1wiXTtcbmV4cG9ydHMuTU9OVEhfTEVUVEVSUyA9IFtcIkpcIiwgXCJGXCIsIFwiTVwiLCBcIkFcIiwgXCJNXCIsIFwiSlwiLCBcIkpcIiwgXCJBXCIsIFwiU1wiLCBcIk9cIiwgXCJOXCIsIFwiRFwiXTtcbmV4cG9ydHMuU1RBTkRfQUxPTkVfTE9OR19NT05USF9OQU1FUyA9IGV4cG9ydHMuTE9OR19NT05USF9OQU1FUy5zbGljZSgpO1xuZXhwb3J0cy5TVEFORF9BTE9ORV9TSE9SVF9NT05USF9OQU1FUyA9IGV4cG9ydHMuU0hPUlRfTU9OVEhfTkFNRVMuc2xpY2UoKTtcbmV4cG9ydHMuU1RBTkRfQUxPTkVfTU9OVEhfTEVUVEVSUyA9IGV4cG9ydHMuTU9OVEhfTEVUVEVSUy5zbGljZSgpO1xuZXhwb3J0cy5MT05HX1dFRUtEQVlfTkFNRVMgPSBbXCJTdW5kYXlcIiwgXCJNb25kYXlcIiwgXCJUdWVzZGF5XCIsIFwiV2VkbmVzZGF5XCIsIFwiVGh1cnNkYXlcIiwgXCJGcmlkYXlcIiwgXCJTYXR1cmRheVwiXTtcbmV4cG9ydHMuU0hPUlRfV0VFS0RBWV9OQU1FUyA9IFtcIlN1blwiLCBcIk1vblwiLCBcIlR1ZVwiLCBcIldlZFwiLCBcIlRodVwiLCBcIkZyaVwiLCBcIlNhdFwiXTtcbmV4cG9ydHMuV0VFS0RBWV9UV09fTEVUVEVSUyA9IFtcIlN1XCIsIFwiTW9cIiwgXCJUdVwiLCBcIldlXCIsIFwiVGhcIiwgXCJGclwiLCBcIlNhXCJdO1xuZXhwb3J0cy5XRUVLREFZX0xFVFRFUlMgPSBbXCJTXCIsIFwiTVwiLCBcIlRcIiwgXCJXXCIsIFwiVFwiLCBcIkZcIiwgXCJTXCJdO1xuZXhwb3J0cy5EQVlfUEVSSU9EU19BQkJSRVZJQVRFRCA9IHsgYW06IFwiQU1cIiwgcG06IFwiUE1cIiwgbm9vbjogXCJub29uXCIsIG1pZG5pZ2h0OiBcIm1pZC5cIiB9O1xuZXhwb3J0cy5EQVlfUEVSSU9EU19XSURFID0geyBhbTogXCJBTVwiLCBwbTogXCJQTVwiLCBub29uOiBcIm5vb25cIiwgbWlkbmlnaHQ6IFwibWlkbmlnaHRcIiB9O1xuZXhwb3J0cy5EQVlfUEVSSU9EU19OQVJST1cgPSB7IGFtOiBcIkFcIiwgcG06IFwiUFwiLCBub29uOiBcIm5vb25cIiwgbWlkbmlnaHQ6IFwibWRcIiB9O1xuZXhwb3J0cy5ERUZBVUxUX0xPQ0FMRSA9IHtcbiAgICBlcmFOYXJyb3c6IGV4cG9ydHMuRVJBX05BTUVTX05BUlJPVyxcbiAgICBlcmFXaWRlOiBleHBvcnRzLkVSQV9OQU1FU19XSURFLFxuICAgIGVyYUFiYnJldmlhdGVkOiBleHBvcnRzLkVSQV9OQU1FU19BQkJSRVZJQVRFRCxcbiAgICBxdWFydGVyTGV0dGVyOiBleHBvcnRzLlFVQVJURVJfTEVUVEVSLFxuICAgIHF1YXJ0ZXJXb3JkOiBleHBvcnRzLlFVQVJURVJfV09SRCxcbiAgICBxdWFydGVyQWJicmV2aWF0aW9uczogZXhwb3J0cy5RVUFSVEVSX0FCQlJFVklBVElPTlMsXG4gICAgc3RhbmRBbG9uZVF1YXJ0ZXJMZXR0ZXI6IGV4cG9ydHMuU1RBTkRfQUxPTkVfUVVBUlRFUl9MRVRURVIsXG4gICAgc3RhbmRBbG9uZVF1YXJ0ZXJXb3JkOiBleHBvcnRzLlNUQU5EX0FMT05FX1FVQVJURVJfV09SRCxcbiAgICBzdGFuZEFsb25lUXVhcnRlckFiYnJldmlhdGlvbnM6IGV4cG9ydHMuU1RBTkRfQUxPTkVfUVVBUlRFUl9BQkJSRVZJQVRJT05TLFxuICAgIGxvbmdNb250aE5hbWVzOiBleHBvcnRzLkxPTkdfTU9OVEhfTkFNRVMsXG4gICAgc2hvcnRNb250aE5hbWVzOiBleHBvcnRzLlNIT1JUX01PTlRIX05BTUVTLFxuICAgIG1vbnRoTGV0dGVyczogZXhwb3J0cy5NT05USF9MRVRURVJTLFxuICAgIHN0YW5kQWxvbmVMb25nTW9udGhOYW1lczogZXhwb3J0cy5TVEFORF9BTE9ORV9MT05HX01PTlRIX05BTUVTLFxuICAgIHN0YW5kQWxvbmVTaG9ydE1vbnRoTmFtZXM6IGV4cG9ydHMuU1RBTkRfQUxPTkVfU0hPUlRfTU9OVEhfTkFNRVMsXG4gICAgc3RhbmRBbG9uZU1vbnRoTGV0dGVyczogZXhwb3J0cy5TVEFORF9BTE9ORV9NT05USF9MRVRURVJTLFxuICAgIGxvbmdXZWVrZGF5TmFtZXM6IGV4cG9ydHMuTE9OR19XRUVLREFZX05BTUVTLFxuICAgIHNob3J0V2Vla2RheU5hbWVzOiBleHBvcnRzLlNIT1JUX1dFRUtEQVlfTkFNRVMsXG4gICAgd2Vla2RheVR3b0xldHRlcnM6IGV4cG9ydHMuV0VFS0RBWV9UV09fTEVUVEVSUyxcbiAgICB3ZWVrZGF5TGV0dGVyczogZXhwb3J0cy5XRUVLREFZX0xFVFRFUlMsXG4gICAgZGF5UGVyaW9kQWJicmV2aWF0ZWQ6IGV4cG9ydHMuREFZX1BFUklPRFNfQUJCUkVWSUFURUQsXG4gICAgZGF5UGVyaW9kV2lkZTogZXhwb3J0cy5EQVlfUEVSSU9EU19XSURFLFxuICAgIGRheVBlcmlvZE5hcnJvdzogZXhwb3J0cy5EQVlfUEVSSU9EU19OQVJST1dcbn07XG4vLyMgc291cmNlTWFwcGluZ1VSTD1sb2NhbGUuanMubWFwIiwiLyoqXG4gKiBDb3B5cmlnaHQoYykgMjAxNCBBQkIgU3dpdHplcmxhbmQgTHRkLlxuICpcbiAqIE1hdGggdXRpbGl0eSBmdW5jdGlvbnNcbiAqL1xuXCJ1c2Ugc3RyaWN0XCI7XG5PYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgXCJfX2VzTW9kdWxlXCIsIHsgdmFsdWU6IHRydWUgfSk7XG5leHBvcnRzLnBvc2l0aXZlTW9kdWxvID0gZXhwb3J0cy5maWx0ZXJGbG9hdCA9IGV4cG9ydHMucm91bmRTeW0gPSBleHBvcnRzLmlzSW50ID0gdm9pZCAwO1xudmFyIGFzc2VydF8xID0gcmVxdWlyZShcIi4vYXNzZXJ0XCIpO1xuLyoqXG4gKiBAcmV0dXJuIHRydWUgaWZmIGdpdmVuIGFyZ3VtZW50IGlzIGFuIGludGVnZXIgbnVtYmVyXG4gKiBAdGhyb3dzIG5vdGhpbmdcbiAqL1xuZnVuY3Rpb24gaXNJbnQobikge1xuICAgIGlmIChuID09PSBudWxsIHx8ICFpc0Zpbml0ZShuKSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIHJldHVybiAoTWF0aC5mbG9vcihuKSA9PT0gbik7XG59XG5leHBvcnRzLmlzSW50ID0gaXNJbnQ7XG4vKipcbiAqIFJvdW5kcyAtMS41IHRvIC0yIGluc3RlYWQgb2YgLTFcbiAqIFJvdW5kcyArMS41IHRvICsyXG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuTiBpZiBuIGlzIG5vdCBhIGZpbml0ZSBudW1iZXJcbiAqL1xuZnVuY3Rpb24gcm91bmRTeW0obikge1xuICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KShOdW1iZXIuaXNGaW5pdGUobiksIFwiQXJndW1lbnQuTlwiLCBcIm4gbXVzdCBiZSBhIGZpbml0ZSBudW1iZXIgYnV0IGlzOiBcIi5jb25jYXQobikpO1xuICAgIGlmIChuIDwgMCkge1xuICAgICAgICByZXR1cm4gLTEgKiBNYXRoLnJvdW5kKC0xICogbik7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICByZXR1cm4gTWF0aC5yb3VuZChuKTtcbiAgICB9XG59XG5leHBvcnRzLnJvdW5kU3ltID0gcm91bmRTeW07XG4vKipcbiAqIFN0cmljdGVyIHZhcmlhbnQgb2YgcGFyc2VGbG9hdCgpLlxuICogQHBhcmFtIHZhbHVlXHRJbnB1dCBzdHJpbmdcbiAqIEByZXR1cm4gdGhlIGZsb2F0IGlmIHRoZSBzdHJpbmcgaXMgYSB2YWxpZCBmbG9hdCwgTmFOIG90aGVyd2lzZVxuICogQHRocm93cyBub3RoaW5nXG4gKi9cbmZ1bmN0aW9uIGZpbHRlckZsb2F0KHZhbHVlKSB7XG4gICAgaWYgKC9eKFxcLXxcXCspPyhbMC05XSsoXFwuWzAtOV0rKT98SW5maW5pdHkpJC8udGVzdCh2YWx1ZSkpIHtcbiAgICAgICAgcmV0dXJuIE51bWJlcih2YWx1ZSk7XG4gICAgfVxuICAgIHJldHVybiBOYU47XG59XG5leHBvcnRzLmZpbHRlckZsb2F0ID0gZmlsdGVyRmxvYXQ7XG4vKipcbiAqIE1vZHVsbyBmdW5jdGlvbiB0aGF0IG9ubHkgcmV0dXJucyBhIHBvc2l0aXZlIHJlc3VsdCwgaW4gY29udHJhc3QgdG8gdGhlICUgb3BlcmF0b3JcbiAqIEBwYXJhbSB2YWx1ZVxuICogQHBhcmFtIG1vZHVsb1xuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LlZhbHVlIGlmIHZhbHVlIGlzIG5vdCBmaW5pdGVcbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5Nb2R1bG8gaWYgbW9kdWxvIGlzIG5vdCBhIGZpbml0ZSBudW1iZXIgPj0gMVxuICovXG5mdW5jdGlvbiBwb3NpdGl2ZU1vZHVsbyh2YWx1ZSwgbW9kdWxvKSB7XG4gICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKE51bWJlci5pc0Zpbml0ZSh2YWx1ZSksIFwiQXJndW1lbnQuVmFsdWVcIiwgXCJ2YWx1ZSBzaG91bGQgYmUgZmluaXRlXCIpO1xuICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KShOdW1iZXIuaXNGaW5pdGUobW9kdWxvKSAmJiBtb2R1bG8gPj0gMSwgXCJBcmd1bWVudC5Nb2R1bG9cIiwgXCJtb2R1bG8gc2hvdWxkIGJlID49IDFcIik7XG4gICAgaWYgKHZhbHVlIDwgMCkge1xuICAgICAgICByZXR1cm4gKCh2YWx1ZSAlIG1vZHVsbykgKyBtb2R1bG8pICUgbW9kdWxvO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgcmV0dXJuIHZhbHVlICUgbW9kdWxvO1xuICAgIH1cbn1cbmV4cG9ydHMucG9zaXRpdmVNb2R1bG8gPSBwb3NpdGl2ZU1vZHVsbztcbi8vIyBzb3VyY2VNYXBwaW5nVVJMPW1hdGguanMubWFwIiwiXCJ1c2Ugc3RyaWN0XCI7XG4vKipcbiAqIENvcHlyaWdodChjKSAyMDE0IEFCQiBTd2l0emVybGFuZCBMdGQuXG4gKlxuICogRnVuY3Rpb25hbGl0eSB0byBwYXJzZSBhIERhdGVUaW1lIG9iamVjdCB0byBhIHN0cmluZ1xuICovXG52YXIgX19hc3NpZ24gPSAodGhpcyAmJiB0aGlzLl9fYXNzaWduKSB8fCBmdW5jdGlvbiAoKSB7XG4gICAgX19hc3NpZ24gPSBPYmplY3QuYXNzaWduIHx8IGZ1bmN0aW9uKHQpIHtcbiAgICAgICAgZm9yICh2YXIgcywgaSA9IDEsIG4gPSBhcmd1bWVudHMubGVuZ3RoOyBpIDwgbjsgaSsrKSB7XG4gICAgICAgICAgICBzID0gYXJndW1lbnRzW2ldO1xuICAgICAgICAgICAgZm9yICh2YXIgcCBpbiBzKSBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHMsIHApKVxuICAgICAgICAgICAgICAgIHRbcF0gPSBzW3BdO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0O1xuICAgIH07XG4gICAgcmV0dXJuIF9fYXNzaWduLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59O1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7IHZhbHVlOiB0cnVlIH0pO1xuZXhwb3J0cy5wYXJzZSA9IGV4cG9ydHMucGFyc2VhYmxlID0gdm9pZCAwO1xudmFyIGJhc2ljc18xID0gcmVxdWlyZShcIi4vYmFzaWNzXCIpO1xudmFyIGVycm9yXzEgPSByZXF1aXJlKFwiLi9lcnJvclwiKTtcbnZhciBsb2NhbGVfMSA9IHJlcXVpcmUoXCIuL2xvY2FsZVwiKTtcbnZhciBtYXRoXzEgPSByZXF1aXJlKFwiLi9tYXRoXCIpO1xudmFyIHRpbWV6b25lXzEgPSByZXF1aXJlKFwiLi90aW1lem9uZVwiKTtcbnZhciB0b2tlbl8xID0gcmVxdWlyZShcIi4vdG9rZW5cIik7XG4vKipcbiAqIENoZWNrcyBpZiBhIGdpdmVuIGRhdGV0aW1lIHN0cmluZyBpcyBhY2NvcmRpbmcgdG8gdGhlIGdpdmVuIGZvcm1hdFxuICogQHBhcmFtIGRhdGVUaW1lU3RyaW5nIFRoZSBzdHJpbmcgdG8gdGVzdFxuICogQHBhcmFtIGZvcm1hdFN0cmluZyBMRE1MIGZvcm1hdCBzdHJpbmcgKHNlZSBMRE1MLm1kKVxuICogQHBhcmFtIGFsbG93VHJhaWxpbmcgQWxsb3cgdHJhaWxpbmcgc3RyaW5nIGFmdGVyIHRoZSBkYXRlK3RpbWVcbiAqIEBwYXJhbSBsb2NhbGUgTG9jYWxlLXNwZWNpZmljIGNvbnN0YW50cyBzdWNoIGFzIG1vbnRoIG5hbWVzXG4gKiBAcmV0dXJucyB0cnVlIGlmZiB0aGUgc3RyaW5nIGlzIHZhbGlkXG4gKiBAdGhyb3dzIG5vdGhpbmdcbiAqL1xuZnVuY3Rpb24gcGFyc2VhYmxlKGRhdGVUaW1lU3RyaW5nLCBmb3JtYXRTdHJpbmcsIGFsbG93VHJhaWxpbmcsIGxvY2FsZSkge1xuICAgIGlmIChhbGxvd1RyYWlsaW5nID09PSB2b2lkIDApIHsgYWxsb3dUcmFpbGluZyA9IHRydWU7IH1cbiAgICBpZiAobG9jYWxlID09PSB2b2lkIDApIHsgbG9jYWxlID0ge307IH1cbiAgICB0cnkge1xuICAgICAgICBwYXJzZShkYXRlVGltZVN0cmluZywgZm9ybWF0U3RyaW5nLCB1bmRlZmluZWQsIGFsbG93VHJhaWxpbmcsIGxvY2FsZSk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICBjYXRjaCAoZSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxufVxuZXhwb3J0cy5wYXJzZWFibGUgPSBwYXJzZWFibGU7XG4vKipcbiAqIFBhcnNlIHRoZSBzdXBwbGllZCBkYXRlVGltZSBhc3N1bWluZyB0aGUgZ2l2ZW4gZm9ybWF0LlxuICpcbiAqIEBwYXJhbSBkYXRlVGltZVN0cmluZyBUaGUgc3RyaW5nIHRvIHBhcnNlXG4gKiBAcGFyYW0gZm9ybWF0U3RyaW5nIFRoZSBmb3JtYXR0aW5nIHN0cmluZyB0byBiZSBhcHBsaWVkXG4gKiBAcGFyYW0gb3ZlcnJpZGVab25lIFVzZSB0aGlzIHpvbmUgaW4gdGhlIHJlc3VsdFxuICogQHBhcmFtIGFsbG93VHJhaWxpbmcgQWxsb3cgdHJhaWxpbmcgY2hhcmFjdGVycyBpbiB0aGUgc291cmNlIHN0cmluZ1xuICogQHBhcmFtIGxvY2FsZSBMb2NhbGUtc3BlY2lmaWMgY29uc3RhbnRzIHN1Y2ggYXMgbW9udGggbmFtZXNcbiAqIEByZXR1cm4gc3RyaW5nXG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuUGFyc2VFcnJvciBpZiB0aGUgZ2l2ZW4gZGF0ZVRpbWVTdHJpbmcgaXMgd3Jvbmcgb3Igbm90IGFjY29yZGluZyB0byB0aGUgcGF0dGVyblxuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LkZvcm1hdFN0cmluZyBpZiB0aGUgZ2l2ZW4gZm9ybWF0IHN0cmluZyBpcyBpbnZhbGlkXG4gKi9cbmZ1bmN0aW9uIHBhcnNlKGRhdGVUaW1lU3RyaW5nLCBmb3JtYXRTdHJpbmcsIG92ZXJyaWRlWm9uZSwgYWxsb3dUcmFpbGluZywgbG9jYWxlKSB7XG4gICAgdmFyIF9hO1xuICAgIGlmIChhbGxvd1RyYWlsaW5nID09PSB2b2lkIDApIHsgYWxsb3dUcmFpbGluZyA9IHRydWU7IH1cbiAgICBpZiAobG9jYWxlID09PSB2b2lkIDApIHsgbG9jYWxlID0ge307IH1cbiAgICBpZiAoIWRhdGVUaW1lU3RyaW5nKSB7XG4gICAgICAgIHJldHVybiAoMCwgZXJyb3JfMS50aHJvd0Vycm9yKShcIlBhcnNlRXJyb3JcIiwgXCJubyBkYXRlIGdpdmVuXCIpO1xuICAgIH1cbiAgICBpZiAoIWZvcm1hdFN0cmluZykge1xuICAgICAgICByZXR1cm4gKDAsIGVycm9yXzEudGhyb3dFcnJvcikoXCJBcmd1bWVudC5Gb3JtYXRTdHJpbmdcIiwgXCJubyBmb3JtYXQgZ2l2ZW5cIik7XG4gICAgfVxuICAgIHZhciBtZXJnZWRMb2NhbGUgPSBfX2Fzc2lnbihfX2Fzc2lnbih7fSwgbG9jYWxlXzEuREVGQVVMVF9MT0NBTEUpLCBsb2NhbGUpO1xuICAgIHZhciB5ZWFyQ3V0b2ZmID0gKDAsIG1hdGhfMS5wb3NpdGl2ZU1vZHVsbykoKG5ldyBEYXRlKCkuZ2V0RnVsbFllYXIoKSArIDUwKSwgMTAwKTtcbiAgICB0cnkge1xuICAgICAgICB2YXIgdG9rZW5zID0gKDAsIHRva2VuXzEudG9rZW5pemUpKGZvcm1hdFN0cmluZyk7XG4gICAgICAgIHZhciB0aW1lID0geyB5ZWFyOiB1bmRlZmluZWQgfTtcbiAgICAgICAgdmFyIHpvbmUgPSB2b2lkIDA7XG4gICAgICAgIHZhciBwbnIgPSB2b2lkIDA7XG4gICAgICAgIHZhciBwenIgPSB2b2lkIDA7XG4gICAgICAgIHZhciBkcHIgPSB2b2lkIDA7XG4gICAgICAgIHZhciBlcmEgPSAxO1xuICAgICAgICB2YXIgcXVhcnRlciA9IHZvaWQgMDtcbiAgICAgICAgdmFyIHJlbWFpbmluZyA9IGRhdGVUaW1lU3RyaW5nO1xuICAgICAgICBmb3IgKHZhciBfaSA9IDAsIHRva2Vuc18xID0gdG9rZW5zOyBfaSA8IHRva2Vuc18xLmxlbmd0aDsgX2krKykge1xuICAgICAgICAgICAgdmFyIHRva2VuID0gdG9rZW5zXzFbX2ldO1xuICAgICAgICAgICAgc3dpdGNoICh0b2tlbi50eXBlKSB7XG4gICAgICAgICAgICAgICAgY2FzZSB0b2tlbl8xLlRva2VuVHlwZS5FUkE6XG4gICAgICAgICAgICAgICAgICAgIF9hID0gc3RyaXBFcmEodG9rZW4sIHJlbWFpbmluZywgbWVyZ2VkTG9jYWxlKSwgZXJhID0gX2FbMF0sIHJlbWFpbmluZyA9IF9hWzFdO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBjYXNlIHRva2VuXzEuVG9rZW5UeXBlLlFVQVJURVI6XG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciByID0gc3RyaXBRdWFydGVyKHRva2VuLCByZW1haW5pbmcsIG1lcmdlZExvY2FsZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBxdWFydGVyID0gci5uO1xuICAgICAgICAgICAgICAgICAgICAgICAgcmVtYWluaW5nID0gci5yZW1haW5pbmc7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgY2FzZSB0b2tlbl8xLlRva2VuVHlwZS5XRUVLREFZOlxuICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZW1haW5pbmcgPSBzdHJpcFdlZWtEYXkodG9rZW4sIHJlbWFpbmluZywgbWVyZ2VkTG9jYWxlKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBjYXNlIHRva2VuXzEuVG9rZW5UeXBlLldFRUs6XG4gICAgICAgICAgICAgICAgICAgIHJlbWFpbmluZyA9IHN0cmlwTnVtYmVyKHJlbWFpbmluZywgMikucmVtYWluaW5nO1xuICAgICAgICAgICAgICAgICAgICBicmVhazsgLy8gbm90aGluZyB0byBsZWFybiBmcm9tIHRoaXNcbiAgICAgICAgICAgICAgICBjYXNlIHRva2VuXzEuVG9rZW5UeXBlLkRBWVBFUklPRDpcbiAgICAgICAgICAgICAgICAgICAgZHByID0gc3RyaXBEYXlQZXJpb2QodG9rZW4sIHJlbWFpbmluZywgbWVyZ2VkTG9jYWxlKTtcbiAgICAgICAgICAgICAgICAgICAgcmVtYWluaW5nID0gZHByLnJlbWFpbmluZztcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgY2FzZSB0b2tlbl8xLlRva2VuVHlwZS5ZRUFSOlxuICAgICAgICAgICAgICAgICAgICBwbnIgPSBzdHJpcE51bWJlcihyZW1haW5pbmcsIEluZmluaXR5KTtcbiAgICAgICAgICAgICAgICAgICAgcmVtYWluaW5nID0gcG5yLnJlbWFpbmluZztcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRva2VuLmxlbmd0aCA9PT0gMikge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHBuci5uID4geWVhckN1dG9mZikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpbWUueWVhciA9IDE5MDAgKyBwbnIubjtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpbWUueWVhciA9IDIwMDAgKyBwbnIubjtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRpbWUueWVhciA9IHBuci5uO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIGNhc2UgdG9rZW5fMS5Ub2tlblR5cGUuTU9OVEg6XG4gICAgICAgICAgICAgICAgICAgIHBuciA9IHN0cmlwTW9udGgodG9rZW4sIHJlbWFpbmluZywgbWVyZ2VkTG9jYWxlKTtcbiAgICAgICAgICAgICAgICAgICAgcmVtYWluaW5nID0gcG5yLnJlbWFpbmluZztcbiAgICAgICAgICAgICAgICAgICAgdGltZS5tb250aCA9IHBuci5uO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBjYXNlIHRva2VuXzEuVG9rZW5UeXBlLkRBWTpcbiAgICAgICAgICAgICAgICAgICAgcG5yID0gc3RyaXBOdW1iZXIocmVtYWluaW5nLCAyKTtcbiAgICAgICAgICAgICAgICAgICAgcmVtYWluaW5nID0gcG5yLnJlbWFpbmluZztcbiAgICAgICAgICAgICAgICAgICAgdGltZS5kYXkgPSBwbnIubjtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgY2FzZSB0b2tlbl8xLlRva2VuVHlwZS5IT1VSOlxuICAgICAgICAgICAgICAgICAgICBwbnIgPSBzdHJpcEhvdXIodG9rZW4sIHJlbWFpbmluZyk7XG4gICAgICAgICAgICAgICAgICAgIHJlbWFpbmluZyA9IHBuci5yZW1haW5pbmc7XG4gICAgICAgICAgICAgICAgICAgIHRpbWUuaG91ciA9IHBuci5uO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBjYXNlIHRva2VuXzEuVG9rZW5UeXBlLk1JTlVURTpcbiAgICAgICAgICAgICAgICAgICAgcG5yID0gc3RyaXBOdW1iZXIocmVtYWluaW5nLCAyKTtcbiAgICAgICAgICAgICAgICAgICAgcmVtYWluaW5nID0gcG5yLnJlbWFpbmluZztcbiAgICAgICAgICAgICAgICAgICAgdGltZS5taW51dGUgPSBwbnIubjtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgY2FzZSB0b2tlbl8xLlRva2VuVHlwZS5TRUNPTkQ6XG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHBuciA9IHN0cmlwU2Vjb25kKHRva2VuLCByZW1haW5pbmcpO1xuICAgICAgICAgICAgICAgICAgICAgICAgcmVtYWluaW5nID0gcG5yLnJlbWFpbmluZztcbiAgICAgICAgICAgICAgICAgICAgICAgIHN3aXRjaCAodG9rZW4uc3ltYm9sKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSBcInNcIjpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGltZS5zZWNvbmQgPSBwbnIubjtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSBcIlNcIjpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGltZS5taWxsaSA9IDEwMDAgKiBwYXJzZUZsb2F0KFwiMC5cIiArIE1hdGguZmxvb3IocG5yLm4pLnRvU3RyaW5nKDEwKS5zbGljZSgwLCAzKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgXCJBXCI6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpbWUuaG91ciA9IE1hdGguZmxvb3IoKHBuci5uIC8gMzYwMEUzKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpbWUubWludXRlID0gTWF0aC5mbG9vcigoMCwgbWF0aF8xLnBvc2l0aXZlTW9kdWxvKShwbnIubiAvIDYwRTMsIDYwKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpbWUuc2Vjb25kID0gTWF0aC5mbG9vcigoMCwgbWF0aF8xLnBvc2l0aXZlTW9kdWxvKShwbnIubiAvIDEwMDAsIDYwKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpbWUubWlsbGkgPSAoMCwgbWF0aF8xLnBvc2l0aXZlTW9kdWxvKShwbnIubiwgMTAwMCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuICgwLCBlcnJvcl8xLnRocm93RXJyb3IpKFwiUGFyc2VFcnJvclwiLCBcInVuc3VwcG9ydGVkIHNlY29uZCBmb3JtYXQgJ1wiLmNvbmNhdCh0b2tlbi5yYXcsIFwiJ1wiKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgY2FzZSB0b2tlbl8xLlRva2VuVHlwZS5aT05FOlxuICAgICAgICAgICAgICAgICAgICBwenIgPSBzdHJpcFpvbmUodG9rZW4sIHJlbWFpbmluZyk7XG4gICAgICAgICAgICAgICAgICAgIHJlbWFpbmluZyA9IHB6ci5yZW1haW5pbmc7XG4gICAgICAgICAgICAgICAgICAgIHpvbmUgPSBwenIuem9uZTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbiAgICAgICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgIGNhc2UgdG9rZW5fMS5Ub2tlblR5cGUuSURFTlRJVFk6XG4gICAgICAgICAgICAgICAgICAgIHJlbWFpbmluZyA9IHN0cmlwUmF3KHJlbWFpbmluZywgdG9rZW4ucmF3KTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGRwcikge1xuICAgICAgICAgICAgc3dpdGNoIChkcHIudHlwZSkge1xuICAgICAgICAgICAgICAgIGNhc2UgXCJhbVwiOlxuICAgICAgICAgICAgICAgICAgICBpZiAodGltZS5ob3VyICE9PSB1bmRlZmluZWQgJiYgdGltZS5ob3VyID49IDEyKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aW1lLmhvdXIgLT0gMTI7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgY2FzZSBcInBtXCI6XG4gICAgICAgICAgICAgICAgICAgIGlmICh0aW1lLmhvdXIgIT09IHVuZGVmaW5lZCAmJiB0aW1lLmhvdXIgPCAxMikge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGltZS5ob3VyICs9IDEyO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIGNhc2UgXCJub29uXCI6XG4gICAgICAgICAgICAgICAgICAgIGlmICh0aW1lLmhvdXIgPT09IHVuZGVmaW5lZCB8fCB0aW1lLmhvdXIgPT09IDApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRpbWUuaG91ciA9IDEyO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGlmICh0aW1lLm1pbnV0ZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aW1lLm1pbnV0ZSA9IDA7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgaWYgKHRpbWUuc2Vjb25kID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRpbWUuc2Vjb25kID0gMDtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBpZiAodGltZS5taWxsaSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aW1lLm1pbGxpID0gMDtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBpZiAodGltZS5ob3VyICE9PSAxMiB8fCB0aW1lLm1pbnV0ZSAhPT0gMCB8fCB0aW1lLnNlY29uZCAhPT0gMCB8fCB0aW1lLm1pbGxpICE9PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gKDAsIGVycm9yXzEudGhyb3dFcnJvcikoXCJQYXJzZUVycm9yXCIsIFwiaW52YWxpZCB0aW1lLCBjb250YWlucyAnbm9vbicgc3BlY2lmaWVyIGJ1dCB0aW1lIGRpZmZlcnMgZnJvbSBub29uXCIpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIGNhc2UgXCJtaWRuaWdodFwiOlxuICAgICAgICAgICAgICAgICAgICBpZiAodGltZS5ob3VyID09PSB1bmRlZmluZWQgfHwgdGltZS5ob3VyID09PSAxMikge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGltZS5ob3VyID0gMDtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBpZiAodGltZS5ob3VyID09PSAxMikge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGltZS5ob3VyID0gMDtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBpZiAodGltZS5taW51dGUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGltZS5taW51dGUgPSAwO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGlmICh0aW1lLnNlY29uZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aW1lLnNlY29uZCA9IDA7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgaWYgKHRpbWUubWlsbGkgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGltZS5taWxsaSA9IDA7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgaWYgKHRpbWUuaG91ciAhPT0gMCB8fCB0aW1lLm1pbnV0ZSAhPT0gMCB8fCB0aW1lLnNlY29uZCAhPT0gMCB8fCB0aW1lLm1pbGxpICE9PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gKDAsIGVycm9yXzEudGhyb3dFcnJvcikoXCJQYXJzZUVycm9yXCIsIFwiaW52YWxpZCB0aW1lLCBjb250YWlucyAnbWlkbmlnaHQnIHNwZWNpZmllciBidXQgdGltZSBkaWZmZXJzIGZyb20gbWlkbmlnaHRcIik7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRpbWUueWVhciAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICB0aW1lLnllYXIgKj0gZXJhO1xuICAgICAgICB9XG4gICAgICAgIGlmIChxdWFydGVyICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIGlmICh0aW1lLm1vbnRoID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICBzd2l0Y2ggKHF1YXJ0ZXIpIHtcbiAgICAgICAgICAgICAgICAgICAgY2FzZSAxOlxuICAgICAgICAgICAgICAgICAgICAgICAgdGltZS5tb250aCA9IDE7XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgY2FzZSAyOlxuICAgICAgICAgICAgICAgICAgICAgICAgdGltZS5tb250aCA9IDQ7XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgY2FzZSAzOlxuICAgICAgICAgICAgICAgICAgICAgICAgdGltZS5tb250aCA9IDc7XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgY2FzZSA0OlxuICAgICAgICAgICAgICAgICAgICAgICAgdGltZS5tb250aCA9IDEwO1xuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgdmFyIGVycm9yXzIgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICBzd2l0Y2ggKHF1YXJ0ZXIpIHtcbiAgICAgICAgICAgICAgICAgICAgY2FzZSAxOlxuICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JfMiA9ICEodGltZS5tb250aCA+PSAxICYmIHRpbWUubW9udGggPD0gMyk7XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgY2FzZSAyOlxuICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JfMiA9ICEodGltZS5tb250aCA+PSA0ICYmIHRpbWUubW9udGggPD0gNik7XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgY2FzZSAzOlxuICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JfMiA9ICEodGltZS5tb250aCA+PSA3ICYmIHRpbWUubW9udGggPD0gOSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgY2FzZSA0OlxuICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JfMiA9ICEodGltZS5tb250aCA+PSAxMCAmJiB0aW1lLm1vbnRoIDw9IDEyKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoZXJyb3JfMikge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gKDAsIGVycm9yXzEudGhyb3dFcnJvcikoXCJQYXJzZUVycm9yXCIsIFwidGhlIHF1YXJ0ZXIgZG9lcyBub3QgbWF0Y2ggdGhlIG1vbnRoXCIpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAodGltZS55ZWFyID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIHRpbWUueWVhciA9IDE5NzA7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHJlc3VsdCA9IHsgdGltZTogbmV3IGJhc2ljc18xLlRpbWVTdHJ1Y3QodGltZSksIHpvbmU6IHpvbmUgfTtcbiAgICAgICAgaWYgKCFyZXN1bHQudGltZS52YWxpZGF0ZSgpKSB7XG4gICAgICAgICAgICByZXR1cm4gKDAsIGVycm9yXzEudGhyb3dFcnJvcikoXCJQYXJzZUVycm9yXCIsIFwiaW52YWxpZCByZXN1bHRpbmcgZGF0ZVwiKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBhbHdheXMgb3ZlcndyaXRlIHpvbmUgd2l0aCBnaXZlbiB6b25lXG4gICAgICAgIGlmIChvdmVycmlkZVpvbmUpIHtcbiAgICAgICAgICAgIHJlc3VsdC56b25lID0gb3ZlcnJpZGVab25lO1xuICAgICAgICB9XG4gICAgICAgIGlmIChyZW1haW5pbmcgJiYgIWFsbG93VHJhaWxpbmcpIHtcbiAgICAgICAgICAgIHJldHVybiAoMCwgZXJyb3JfMS50aHJvd0Vycm9yKShcIlBhcnNlRXJyb3JcIiwgXCJpbnZhbGlkIGRhdGUgJ1wiLmNvbmNhdChkYXRlVGltZVN0cmluZywgXCInIG5vdCBhY2NvcmRpbmcgdG8gZm9ybWF0ICdcIikuY29uY2F0KGZvcm1hdFN0cmluZywgXCInOiB0cmFpbGluZyBjaGFyYWN0ZXJzOiAnXCIpLmNvbmNhdChyZW1haW5pbmcsIFwiJ1wiKSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG4gICAgY2F0Y2ggKGUpIHtcbiAgICAgICAgcmV0dXJuICgwLCBlcnJvcl8xLnRocm93RXJyb3IpKFwiUGFyc2VFcnJvclwiLCBcImludmFsaWQgZGF0ZSAnXCIuY29uY2F0KGRhdGVUaW1lU3RyaW5nLCBcIicgbm90IGFjY29yZGluZyB0byBmb3JtYXQgJ1wiKS5jb25jYXQoZm9ybWF0U3RyaW5nLCBcIic6IFwiKS5jb25jYXQoZS5tZXNzYWdlKSk7XG4gICAgfVxufVxuZXhwb3J0cy5wYXJzZSA9IHBhcnNlO1xudmFyIFdISVRFU1BBQ0UgPSBbXCIgXCIsIFwiXFx0XCIsIFwiXFxyXCIsIFwiXFx2XCIsIFwiXFxuXCJdO1xuLyoqXG4gKlxuICogQHBhcmFtIHRva2VuXG4gKiBAcGFyYW0gc1xuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLk5vdEltcGxlbWVudGVkIGlmIGEgcGF0dGVybiBpcyB1c2VkIHRoYXQgaXNuJ3QgaW1wbGVtZW50ZWQgeWV0ICh6LCBaLCB2LCBWLCB4LCBYKVxuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLlBhcnNlRXJyb3IgaWYgdGhlIGdpdmVuIHN0cmluZyBpcyBub3QgcGFyc2VhYmxlXG4gKi9cbmZ1bmN0aW9uIHN0cmlwWm9uZSh0b2tlbiwgcykge1xuICAgIHZhciB1bnN1cHBvcnRlZCA9ICh0b2tlbi5zeW1ib2wgPT09IFwielwiKVxuICAgICAgICB8fCAodG9rZW4uc3ltYm9sID09PSBcIlpcIiAmJiB0b2tlbi5sZW5ndGggPT09IDUpXG4gICAgICAgIHx8ICh0b2tlbi5zeW1ib2wgPT09IFwidlwiKVxuICAgICAgICB8fCAodG9rZW4uc3ltYm9sID09PSBcIlZcIiAmJiB0b2tlbi5sZW5ndGggIT09IDIpXG4gICAgICAgIHx8ICh0b2tlbi5zeW1ib2wgPT09IFwieFwiICYmIHRva2VuLmxlbmd0aCA+PSA0KVxuICAgICAgICB8fCAodG9rZW4uc3ltYm9sID09PSBcIlhcIiAmJiB0b2tlbi5sZW5ndGggPj0gNCk7XG4gICAgaWYgKHVuc3VwcG9ydGVkKSB7XG4gICAgICAgIHJldHVybiAoMCwgZXJyb3JfMS50aHJvd0Vycm9yKShcIk5vdEltcGxlbWVudGVkXCIsIFwidGltZSB6b25lIHBhdHRlcm4gJ1wiICsgdG9rZW4ucmF3ICsgXCInIGlzIG5vdCBpbXBsZW1lbnRlZFwiKTtcbiAgICB9XG4gICAgdmFyIHJlc3VsdCA9IHtcbiAgICAgICAgcmVtYWluaW5nOiBzXG4gICAgfTtcbiAgICAvLyBjaG9wIG9mZiBcIkdNVFwiIHByZWZpeCBpZiBuZWVkZWRcbiAgICB2YXIgaGFkR01UID0gZmFsc2U7XG4gICAgaWYgKCh0b2tlbi5zeW1ib2wgPT09IFwiWlwiICYmIHRva2VuLmxlbmd0aCA9PT0gNCkgfHwgdG9rZW4uc3ltYm9sID09PSBcIk9cIikge1xuICAgICAgICBpZiAocmVzdWx0LnJlbWFpbmluZy50b1VwcGVyQ2FzZSgpLnN0YXJ0c1dpdGgoXCJHTVRcIikpIHtcbiAgICAgICAgICAgIHJlc3VsdC5yZW1haW5pbmcgPSByZXN1bHQucmVtYWluaW5nLnNsaWNlKDMpO1xuICAgICAgICAgICAgaGFkR01UID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgIH1cbiAgICAvLyBwYXJzZSBhbnkgem9uZSwgcmVnYXJkbGVzcyBvZiBzcGVjaWZpZWQgZm9ybWF0XG4gICAgdmFyIHpvbmVTdHJpbmcgPSBcIlwiO1xuICAgIHdoaWxlIChyZXN1bHQucmVtYWluaW5nLmxlbmd0aCA+IDAgJiYgV0hJVEVTUEFDRS5pbmRleE9mKHJlc3VsdC5yZW1haW5pbmcuY2hhckF0KDApKSA9PT0gLTEpIHtcbiAgICAgICAgem9uZVN0cmluZyArPSByZXN1bHQucmVtYWluaW5nLmNoYXJBdCgwKTtcbiAgICAgICAgcmVzdWx0LnJlbWFpbmluZyA9IHJlc3VsdC5yZW1haW5pbmcuc3Vic3RyKDEpO1xuICAgIH1cbiAgICB6b25lU3RyaW5nID0gem9uZVN0cmluZy50cmltKCk7XG4gICAgaWYgKHpvbmVTdHJpbmcpIHtcbiAgICAgICAgLy8gZW5zdXJlIGNob3BwaW5nIG9mZiBHTVQgZG9lcyBub3QgaGlkZSB0aW1lIHpvbmUgZXJyb3JzIChiaXQgb2YgYSBzbG9wcHkgcmVnZXggYnV0IE9LKVxuICAgICAgICBpZiAoaGFkR01UICYmICF6b25lU3RyaW5nLm1hdGNoKC9bXFwrXFwtXT9bXFxkXFw6XSsvaSkpIHtcbiAgICAgICAgICAgIHJldHVybiAoMCwgZXJyb3JfMS50aHJvd0Vycm9yKShcIlBhcnNlRXJyb3JcIiwgXCJpbnZhbGlkIHRpbWUgem9uZSAnR01UXCIgKyB6b25lU3RyaW5nICsgXCInXCIpO1xuICAgICAgICB9XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICByZXN1bHQuem9uZSA9IHRpbWV6b25lXzEuVGltZVpvbmUuem9uZSh6b25lU3RyaW5nKTtcbiAgICAgICAgfVxuICAgICAgICBjYXRjaCAoZSkge1xuICAgICAgICAgICAgaWYgKCgwLCBlcnJvcl8xLmVycm9ySXMpKGUsIFtcIkFyZ3VtZW50LlNcIiwgXCJOb3RGb3VuZC5ab25lXCJdKSkge1xuICAgICAgICAgICAgICAgIGUgPSAoMCwgZXJyb3JfMS5lcnJvcikoXCJQYXJzZUVycm9yXCIsIGUubWVzc2FnZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aHJvdyBlO1xuICAgICAgICB9XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICByZXR1cm4gKDAsIGVycm9yXzEudGhyb3dFcnJvcikoXCJQYXJzZUVycm9yXCIsIFwibm8gdGltZSB6b25lIGdpdmVuXCIpO1xuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0O1xufVxuLyoqXG4gKlxuICogQHBhcmFtIHNcbiAqIEBwYXJhbSBleHBlY3RlZFxuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLlBhcnNlRXJyb3JcbiAqL1xuZnVuY3Rpb24gc3RyaXBSYXcocywgZXhwZWN0ZWQpIHtcbiAgICB2YXIgcmVtYWluaW5nID0gcztcbiAgICB2YXIgZXJlbWFpbmluZyA9IGV4cGVjdGVkO1xuICAgIHdoaWxlIChyZW1haW5pbmcubGVuZ3RoID4gMCAmJiBlcmVtYWluaW5nLmxlbmd0aCA+IDAgJiYgcmVtYWluaW5nLmNoYXJBdCgwKSA9PT0gZXJlbWFpbmluZy5jaGFyQXQoMCkpIHtcbiAgICAgICAgcmVtYWluaW5nID0gcmVtYWluaW5nLnN1YnN0cigxKTtcbiAgICAgICAgZXJlbWFpbmluZyA9IGVyZW1haW5pbmcuc3Vic3RyKDEpO1xuICAgIH1cbiAgICBpZiAoZXJlbWFpbmluZy5sZW5ndGggPiAwKSB7XG4gICAgICAgIHJldHVybiAoMCwgZXJyb3JfMS50aHJvd0Vycm9yKShcIlBhcnNlRXJyb3JcIiwgXCJleHBlY3RlZCAnXCIuY29uY2F0KGV4cGVjdGVkLCBcIidcIikpO1xuICAgIH1cbiAgICByZXR1cm4gcmVtYWluaW5nO1xufVxuLyoqXG4gKlxuICogQHBhcmFtIHRva2VuXG4gKiBAcGFyYW0gcmVtYWluaW5nXG4gKiBAcGFyYW0gbG9jYWxlXG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuUGFyc2VFcnJvclxuICovXG5mdW5jdGlvbiBzdHJpcERheVBlcmlvZCh0b2tlbiwgcmVtYWluaW5nLCBsb2NhbGUpIHtcbiAgICB2YXIgX2EsIF9iLCBfYywgX2QsIF9lLCBfZjtcbiAgICB2YXIgb2Zmc2V0cztcbiAgICBzd2l0Y2ggKHRva2VuLnN5bWJvbCkge1xuICAgICAgICBjYXNlIFwiYVwiOlxuICAgICAgICAgICAgc3dpdGNoICh0b2tlbi5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICBjYXNlIDQ6XG4gICAgICAgICAgICAgICAgICAgIG9mZnNldHMgPSAoX2EgPSB7fSxcbiAgICAgICAgICAgICAgICAgICAgICAgIF9hW2xvY2FsZS5kYXlQZXJpb2RXaWRlLmFtXSA9IFwiYW1cIixcbiAgICAgICAgICAgICAgICAgICAgICAgIF9hW2xvY2FsZS5kYXlQZXJpb2RXaWRlLnBtXSA9IFwicG1cIixcbiAgICAgICAgICAgICAgICAgICAgICAgIF9hKTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgY2FzZSA1OlxuICAgICAgICAgICAgICAgICAgICBvZmZzZXRzID0gKF9iID0ge30sXG4gICAgICAgICAgICAgICAgICAgICAgICBfYltsb2NhbGUuZGF5UGVyaW9kTmFycm93LmFtXSA9IFwiYW1cIixcbiAgICAgICAgICAgICAgICAgICAgICAgIF9iW2xvY2FsZS5kYXlQZXJpb2ROYXJyb3cucG1dID0gXCJwbVwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgX2IpO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgICAgICBvZmZzZXRzID0gKF9jID0ge30sXG4gICAgICAgICAgICAgICAgICAgICAgICBfY1tsb2NhbGUuZGF5UGVyaW9kQWJicmV2aWF0ZWQuYW1dID0gXCJhbVwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgX2NbbG9jYWxlLmRheVBlcmlvZEFiYnJldmlhdGVkLnBtXSA9IFwicG1cIixcbiAgICAgICAgICAgICAgICAgICAgICAgIF9jKTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgIHN3aXRjaCAodG9rZW4ubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgY2FzZSA0OlxuICAgICAgICAgICAgICAgICAgICBvZmZzZXRzID0gKF9kID0ge30sXG4gICAgICAgICAgICAgICAgICAgICAgICBfZFtsb2NhbGUuZGF5UGVyaW9kV2lkZS5hbV0gPSBcImFtXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBfZFtsb2NhbGUuZGF5UGVyaW9kV2lkZS5taWRuaWdodF0gPSBcIm1pZG5pZ2h0XCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBfZFtsb2NhbGUuZGF5UGVyaW9kV2lkZS5wbV0gPSBcInBtXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBfZFtsb2NhbGUuZGF5UGVyaW9kV2lkZS5ub29uXSA9IFwibm9vblwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgX2QpO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBjYXNlIDU6XG4gICAgICAgICAgICAgICAgICAgIG9mZnNldHMgPSAoX2UgPSB7fSxcbiAgICAgICAgICAgICAgICAgICAgICAgIF9lW2xvY2FsZS5kYXlQZXJpb2ROYXJyb3cuYW1dID0gXCJhbVwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgX2VbbG9jYWxlLmRheVBlcmlvZE5hcnJvdy5taWRuaWdodF0gPSBcIm1pZG5pZ2h0XCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBfZVtsb2NhbGUuZGF5UGVyaW9kTmFycm93LnBtXSA9IFwicG1cIixcbiAgICAgICAgICAgICAgICAgICAgICAgIF9lW2xvY2FsZS5kYXlQZXJpb2ROYXJyb3cubm9vbl0gPSBcIm5vb25cIixcbiAgICAgICAgICAgICAgICAgICAgICAgIF9lKTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICAgICAgb2Zmc2V0cyA9IChfZiA9IHt9LFxuICAgICAgICAgICAgICAgICAgICAgICAgX2ZbbG9jYWxlLmRheVBlcmlvZEFiYnJldmlhdGVkLmFtXSA9IFwiYW1cIixcbiAgICAgICAgICAgICAgICAgICAgICAgIF9mW2xvY2FsZS5kYXlQZXJpb2RBYmJyZXZpYXRlZC5taWRuaWdodF0gPSBcIm1pZG5pZ2h0XCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBfZltsb2NhbGUuZGF5UGVyaW9kQWJicmV2aWF0ZWQucG1dID0gXCJwbVwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgX2ZbbG9jYWxlLmRheVBlcmlvZEFiYnJldmlhdGVkLm5vb25dID0gXCJub29uXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBfZik7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgYnJlYWs7XG4gICAgfVxuICAgIC8vIG1hdGNoIGxvbmdlc3QgcG9zc2libGUgZGF5IHBlcmlvZCBzdHJpbmc7IHNvcnQga2V5cyBieSBsZW5ndGggZGVzY2VuZGluZ1xuICAgIHZhciBzb3J0ZWRLZXlzID0gT2JqZWN0LmtleXMob2Zmc2V0cylcbiAgICAgICAgLnNvcnQoZnVuY3Rpb24gKGEsIGIpIHsgcmV0dXJuIChhLmxlbmd0aCA8IGIubGVuZ3RoID8gMSA6IGEubGVuZ3RoID4gYi5sZW5ndGggPyAtMSA6IDApOyB9KTtcbiAgICB2YXIgdXBwZXIgPSByZW1haW5pbmcudG9VcHBlckNhc2UoKTtcbiAgICBmb3IgKHZhciBfaSA9IDAsIHNvcnRlZEtleXNfMSA9IHNvcnRlZEtleXM7IF9pIDwgc29ydGVkS2V5c18xLmxlbmd0aDsgX2krKykge1xuICAgICAgICB2YXIga2V5ID0gc29ydGVkS2V5c18xW19pXTtcbiAgICAgICAgaWYgKHVwcGVyLnN0YXJ0c1dpdGgoa2V5LnRvVXBwZXJDYXNlKCkpKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIHR5cGU6IG9mZnNldHNba2V5XSxcbiAgICAgICAgICAgICAgICByZW1haW5pbmc6IHJlbWFpbmluZy5zbGljZShrZXkubGVuZ3RoKVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gKDAsIGVycm9yXzEudGhyb3dFcnJvcikoXCJQYXJzZUVycm9yXCIsIFwibWlzc2luZyBkYXkgcGVyaW9kIGkuZS4gXCIgKyBPYmplY3Qua2V5cyhvZmZzZXRzKS5qb2luKFwiLCBcIikpO1xufVxuLyoqXG4gKiBSZXR1cm5zIGZhY3RvciAtMSBvciAxIGRlcGVuZGluZyBvbiBCQyBvciBBRFxuICogQHBhcmFtIHRva2VuXG4gKiBAcGFyYW0gcmVtYWluaW5nXG4gKiBAcGFyYW0gbG9jYWxlXG4gKiBAcmV0dXJucyBbZmFjdG9yLCByZW1haW5pbmddXG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuUGFyc2VFcnJvclxuICovXG5mdW5jdGlvbiBzdHJpcEVyYSh0b2tlbiwgcmVtYWluaW5nLCBsb2NhbGUpIHtcbiAgICB2YXIgYWxsb3dlZDtcbiAgICBzd2l0Y2ggKHRva2VuLmxlbmd0aCkge1xuICAgICAgICBjYXNlIDQ6XG4gICAgICAgICAgICBhbGxvd2VkID0gbG9jYWxlLmVyYVdpZGU7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSA1OlxuICAgICAgICAgICAgYWxsb3dlZCA9IGxvY2FsZS5lcmFOYXJyb3c7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgIGFsbG93ZWQgPSBsb2NhbGUuZXJhQWJicmV2aWF0ZWQ7XG4gICAgICAgICAgICBicmVhaztcbiAgICB9XG4gICAgdmFyIHJlc3VsdCA9IHN0cmlwU3RyaW5ncyh0b2tlbiwgcmVtYWluaW5nLCBhbGxvd2VkKTtcbiAgICByZXR1cm4gW2FsbG93ZWQuaW5kZXhPZihyZXN1bHQuY2hvc2VuKSA9PT0gMCA/IDEgOiAtMSwgcmVzdWx0LnJlbWFpbmluZ107XG59XG4vKipcbiAqXG4gKiBAcGFyYW0gdG9rZW5cbiAqIEBwYXJhbSByZW1haW5pbmdcbiAqIEBwYXJhbSBsb2NhbGVcbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5QYXJzZUVycm9yXG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuRm9ybWF0U3RyaW5nXG4gKi9cbmZ1bmN0aW9uIHN0cmlwUXVhcnRlcih0b2tlbiwgcmVtYWluaW5nLCBsb2NhbGUpIHtcbiAgICB2YXIgcXVhcnRlckxldHRlcjtcbiAgICB2YXIgcXVhcnRlcldvcmQ7XG4gICAgdmFyIHF1YXJ0ZXJBYmJyZXZpYXRpb25zO1xuICAgIHN3aXRjaCAodG9rZW4uc3ltYm9sKSB7XG4gICAgICAgIGNhc2UgXCJRXCI6XG4gICAgICAgICAgICBxdWFydGVyTGV0dGVyID0gbG9jYWxlLnF1YXJ0ZXJMZXR0ZXI7XG4gICAgICAgICAgICBxdWFydGVyV29yZCA9IGxvY2FsZS5xdWFydGVyV29yZDtcbiAgICAgICAgICAgIHF1YXJ0ZXJBYmJyZXZpYXRpb25zID0gbG9jYWxlLnF1YXJ0ZXJBYmJyZXZpYXRpb25zO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgXCJxXCI6IHtcbiAgICAgICAgICAgIHF1YXJ0ZXJMZXR0ZXIgPSBsb2NhbGUuc3RhbmRBbG9uZVF1YXJ0ZXJMZXR0ZXI7XG4gICAgICAgICAgICBxdWFydGVyV29yZCA9IGxvY2FsZS5zdGFuZEFsb25lUXVhcnRlcldvcmQ7XG4gICAgICAgICAgICBxdWFydGVyQWJicmV2aWF0aW9ucyA9IGxvY2FsZS5zdGFuZEFsb25lUXVhcnRlckFiYnJldmlhdGlvbnM7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbiAgICAgICAgICAgIHJldHVybiAoMCwgZXJyb3JfMS50aHJvd0Vycm9yKShcIkFyZ3VtZW50LkZvcm1hdFN0cmluZ1wiLCBcImludmFsaWQgcXVhcnRlciBwYXR0ZXJuXCIpO1xuICAgIH1cbiAgICB2YXIgYWxsb3dlZDtcbiAgICBzd2l0Y2ggKHRva2VuLmxlbmd0aCkge1xuICAgICAgICBjYXNlIDE6XG4gICAgICAgIGNhc2UgNTpcbiAgICAgICAgICAgIHJldHVybiBzdHJpcE51bWJlcihyZW1haW5pbmcsIDEpO1xuICAgICAgICBjYXNlIDI6XG4gICAgICAgICAgICByZXR1cm4gc3RyaXBOdW1iZXIocmVtYWluaW5nLCAyKTtcbiAgICAgICAgY2FzZSAzOlxuICAgICAgICAgICAgYWxsb3dlZCA9IFsxLCAyLCAzLCA0XS5tYXAoZnVuY3Rpb24gKG4pIHsgcmV0dXJuIHF1YXJ0ZXJMZXR0ZXIgKyBuLnRvU3RyaW5nKDEwKTsgfSk7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSA0OlxuICAgICAgICAgICAgYWxsb3dlZCA9IHF1YXJ0ZXJBYmJyZXZpYXRpb25zLm1hcChmdW5jdGlvbiAoYSkgeyByZXR1cm4gYSArIFwiIFwiICsgcXVhcnRlcldvcmQ7IH0pO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICAgICAgcmV0dXJuICgwLCBlcnJvcl8xLnRocm93RXJyb3IpKFwiQXJndW1lbnQuRm9ybWF0U3RyaW5nXCIsIFwiaW52YWxpZCBxdWFydGVyIHBhdHRlcm5cIik7XG4gICAgfVxuICAgIHZhciByID0gc3RyaXBTdHJpbmdzKHRva2VuLCByZW1haW5pbmcsIGFsbG93ZWQpO1xuICAgIHJldHVybiB7IG46IGFsbG93ZWQuaW5kZXhPZihyLmNob3NlbikgKyAxLCByZW1haW5pbmc6IHIucmVtYWluaW5nIH07XG59XG4vKipcbiAqXG4gKiBAcGFyYW0gdG9rZW5cbiAqIEBwYXJhbSByZW1haW5pbmdcbiAqIEBwYXJhbSBsb2NhbGVcbiAqIEByZXR1cm5zIHJlbWFpbmluZyBzdHJpbmdcbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5QYXJzZUVycm9yXG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuRm9ybWF0U3RyaW5nXG4gKi9cbmZ1bmN0aW9uIHN0cmlwV2Vla0RheSh0b2tlbiwgcmVtYWluaW5nLCBsb2NhbGUpIHtcbiAgICB2YXIgYWxsb3dlZDtcbiAgICBzd2l0Y2ggKHRva2VuLmxlbmd0aCkge1xuICAgICAgICBjYXNlIDE6XG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgaWYgKHRva2VuLnN5bWJvbCA9PT0gXCJlXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHN0cmlwTnVtYmVyKHJlbWFpbmluZywgMSkucmVtYWluaW5nO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgYWxsb3dlZCA9IGxvY2FsZS5zaG9ydFdlZWtkYXlOYW1lcztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAyOlxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGlmICh0b2tlbi5zeW1ib2wgPT09IFwiZVwiKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBzdHJpcE51bWJlcihyZW1haW5pbmcsIDIpLnJlbWFpbmluZztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGFsbG93ZWQgPSBsb2NhbGUuc2hvcnRXZWVrZGF5TmFtZXM7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgMzpcbiAgICAgICAgICAgIGFsbG93ZWQgPSBsb2NhbGUuc2hvcnRXZWVrZGF5TmFtZXM7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSA0OlxuICAgICAgICAgICAgYWxsb3dlZCA9IGxvY2FsZS5sb25nV2Vla2RheU5hbWVzO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgNTpcbiAgICAgICAgICAgIGFsbG93ZWQgPSBsb2NhbGUud2Vla2RheUxldHRlcnM7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSA2OlxuICAgICAgICAgICAgYWxsb3dlZCA9IGxvY2FsZS53ZWVrZGF5VHdvTGV0dGVycztcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbiAgICAgICAgICAgIHJldHVybiAoMCwgZXJyb3JfMS50aHJvd0Vycm9yKShcIkFyZ3VtZW50LkZvcm1hdFN0cmluZ1wiLCBcImludmFsaWQgcXVhcnRlciBwYXR0ZXJuXCIpO1xuICAgIH1cbiAgICB2YXIgciA9IHN0cmlwU3RyaW5ncyh0b2tlbiwgcmVtYWluaW5nLCBhbGxvd2VkKTtcbiAgICByZXR1cm4gci5yZW1haW5pbmc7XG59XG4vKipcbiAqXG4gKiBAcGFyYW0gdG9rZW5cbiAqIEBwYXJhbSByZW1haW5pbmdcbiAqIEBwYXJhbSBsb2NhbGVcbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5QYXJzZUVycm9yXG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuRm9ybWF0U3RyaW5nXG4gKi9cbmZ1bmN0aW9uIHN0cmlwTW9udGgodG9rZW4sIHJlbWFpbmluZywgbG9jYWxlKSB7XG4gICAgdmFyIHNob3J0TW9udGhOYW1lcztcbiAgICB2YXIgbG9uZ01vbnRoTmFtZXM7XG4gICAgdmFyIG1vbnRoTGV0dGVycztcbiAgICBzd2l0Y2ggKHRva2VuLnN5bWJvbCkge1xuICAgICAgICBjYXNlIFwiTVwiOlxuICAgICAgICAgICAgc2hvcnRNb250aE5hbWVzID0gbG9jYWxlLnNob3J0TW9udGhOYW1lcztcbiAgICAgICAgICAgIGxvbmdNb250aE5hbWVzID0gbG9jYWxlLmxvbmdNb250aE5hbWVzO1xuICAgICAgICAgICAgbW9udGhMZXR0ZXJzID0gbG9jYWxlLm1vbnRoTGV0dGVycztcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIFwiTFwiOlxuICAgICAgICAgICAgc2hvcnRNb250aE5hbWVzID0gbG9jYWxlLnN0YW5kQWxvbmVTaG9ydE1vbnRoTmFtZXM7XG4gICAgICAgICAgICBsb25nTW9udGhOYW1lcyA9IGxvY2FsZS5zdGFuZEFsb25lTG9uZ01vbnRoTmFtZXM7XG4gICAgICAgICAgICBtb250aExldHRlcnMgPSBsb2NhbGUuc3RhbmRBbG9uZU1vbnRoTGV0dGVycztcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbiAgICAgICAgICAgIHJldHVybiAoMCwgZXJyb3JfMS50aHJvd0Vycm9yKShcIkFyZ3VtZW50LkZvcm1hdFN0cmluZ1wiLCBcImludmFsaWQgbW9udGggcGF0dGVyblwiKTtcbiAgICB9XG4gICAgdmFyIGFsbG93ZWQ7XG4gICAgc3dpdGNoICh0b2tlbi5sZW5ndGgpIHtcbiAgICAgICAgY2FzZSAxOlxuICAgICAgICBjYXNlIDI6XG4gICAgICAgICAgICByZXR1cm4gc3RyaXBOdW1iZXIocmVtYWluaW5nLCAyKTtcbiAgICAgICAgY2FzZSAzOlxuICAgICAgICAgICAgYWxsb3dlZCA9IHNob3J0TW9udGhOYW1lcztcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIDQ6XG4gICAgICAgICAgICBhbGxvd2VkID0gbG9uZ01vbnRoTmFtZXM7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSA1OlxuICAgICAgICAgICAgYWxsb3dlZCA9IG1vbnRoTGV0dGVycztcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbiAgICAgICAgICAgIHJldHVybiAoMCwgZXJyb3JfMS50aHJvd0Vycm9yKShcIkFyZ3VtZW50LkZvcm1hdFN0cmluZ1wiLCBcImludmFsaWQgbW9udGggcGF0dGVyblwiKTtcbiAgICB9XG4gICAgdmFyIHIgPSBzdHJpcFN0cmluZ3ModG9rZW4sIHJlbWFpbmluZywgYWxsb3dlZCk7XG4gICAgcmV0dXJuIHsgbjogYWxsb3dlZC5pbmRleE9mKHIuY2hvc2VuKSArIDEsIHJlbWFpbmluZzogci5yZW1haW5pbmcgfTtcbn1cbi8qKlxuICpcbiAqIEBwYXJhbSB0b2tlblxuICogQHBhcmFtIHJlbWFpbmluZ1xuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLlBhcnNlRXJyb3JcbiAqL1xuZnVuY3Rpb24gc3RyaXBIb3VyKHRva2VuLCByZW1haW5pbmcpIHtcbiAgICB2YXIgcmVzdWx0ID0gc3RyaXBOdW1iZXIocmVtYWluaW5nLCAyKTtcbiAgICBzd2l0Y2ggKHRva2VuLnN5bWJvbCkge1xuICAgICAgICBjYXNlIFwiaFwiOlxuICAgICAgICAgICAgaWYgKHJlc3VsdC5uID09PSAxMikge1xuICAgICAgICAgICAgICAgIHJlc3VsdC5uID0gMDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIFwiSFwiOlxuICAgICAgICAgICAgLy8gbm90aGluZywgaW4gcmFuZ2UgMC0yM1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgXCJLXCI6XG4gICAgICAgICAgICAvLyBub3RoaW5nLCBpbiByYW5nZSAwLTExXG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSBcImtcIjpcbiAgICAgICAgICAgIHJlc3VsdC5uIC09IDE7XG4gICAgICAgICAgICBicmVhaztcbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdDtcbn1cbi8qKlxuICpcbiAqIEBwYXJhbSB0b2tlblxuICogQHBhcmFtIHJlbWFpbmluZ1xuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLlBhcnNlRXJyb3JcbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5Gb3JtYXRTdHJpbmdcbiAqL1xuZnVuY3Rpb24gc3RyaXBTZWNvbmQodG9rZW4sIHJlbWFpbmluZykge1xuICAgIHN3aXRjaCAodG9rZW4uc3ltYm9sKSB7XG4gICAgICAgIGNhc2UgXCJzXCI6XG4gICAgICAgICAgICByZXR1cm4gc3RyaXBOdW1iZXIocmVtYWluaW5nLCAyKTtcbiAgICAgICAgY2FzZSBcIlNcIjpcbiAgICAgICAgICAgIHJldHVybiBzdHJpcE51bWJlcihyZW1haW5pbmcsIHRva2VuLmxlbmd0aCk7XG4gICAgICAgIGNhc2UgXCJBXCI6XG4gICAgICAgICAgICByZXR1cm4gc3RyaXBOdW1iZXIocmVtYWluaW5nLCA4KTtcbiAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gICAgICAgICAgICByZXR1cm4gKDAsIGVycm9yXzEudGhyb3dFcnJvcikoXCJBcmd1bWVudC5Gb3JtYXRTdHJpbmdcIiwgXCJpbnZhbGlkIHNlY29uZHMgcGF0dGVyblwiKTtcbiAgICB9XG59XG4vKipcbiAqXG4gKiBAcGFyYW0gc1xuICogQHBhcmFtIG1heExlbmd0aFxuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLlBhcnNlRXJyb3JcbiAqL1xuZnVuY3Rpb24gc3RyaXBOdW1iZXIocywgbWF4TGVuZ3RoKSB7XG4gICAgdmFyIHJlc3VsdCA9IHtcbiAgICAgICAgbjogTmFOLFxuICAgICAgICByZW1haW5pbmc6IHNcbiAgICB9O1xuICAgIHZhciBudW1iZXJTdHJpbmcgPSBcIlwiO1xuICAgIHdoaWxlIChudW1iZXJTdHJpbmcubGVuZ3RoIDwgbWF4TGVuZ3RoICYmIHJlc3VsdC5yZW1haW5pbmcubGVuZ3RoID4gMCAmJiByZXN1bHQucmVtYWluaW5nLmNoYXJBdCgwKS5tYXRjaCgvXFxkLykpIHtcbiAgICAgICAgbnVtYmVyU3RyaW5nICs9IHJlc3VsdC5yZW1haW5pbmcuY2hhckF0KDApO1xuICAgICAgICByZXN1bHQucmVtYWluaW5nID0gcmVzdWx0LnJlbWFpbmluZy5zdWJzdHIoMSk7XG4gICAgfVxuICAgIC8vIHJlbW92ZSBsZWFkaW5nIHplcm9lc1xuICAgIHdoaWxlIChudW1iZXJTdHJpbmcuY2hhckF0KDApID09PSBcIjBcIiAmJiBudW1iZXJTdHJpbmcubGVuZ3RoID4gMSkge1xuICAgICAgICBudW1iZXJTdHJpbmcgPSBudW1iZXJTdHJpbmcuc3Vic3RyKDEpO1xuICAgIH1cbiAgICByZXN1bHQubiA9IHBhcnNlSW50KG51bWJlclN0cmluZywgMTApO1xuICAgIGlmIChudW1iZXJTdHJpbmcgPT09IFwiXCIgfHwgIU51bWJlci5pc0Zpbml0ZShyZXN1bHQubikpIHtcbiAgICAgICAgcmV0dXJuICgwLCBlcnJvcl8xLnRocm93RXJyb3IpKFwiUGFyc2VFcnJvclwiLCBcImV4cGVjdGVkIGEgbnVtYmVyIGJ1dCBnb3QgJ1wiLmNvbmNhdChudW1iZXJTdHJpbmcsIFwiJ1wiKSk7XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQ7XG59XG4vKipcbiAqXG4gKiBAcGFyYW0gdG9rZW5cbiAqIEBwYXJhbSByZW1haW5pbmdcbiAqIEBwYXJhbSBhbGxvd2VkXG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuUGFyc2VFcnJvclxuICovXG5mdW5jdGlvbiBzdHJpcFN0cmluZ3ModG9rZW4sIHJlbWFpbmluZywgYWxsb3dlZCkge1xuICAgIC8vIG1hdGNoIGxvbmdlc3QgcG9zc2libGUgc3RyaW5nOyBzb3J0IGtleXMgYnkgbGVuZ3RoIGRlc2NlbmRpbmdcbiAgICB2YXIgc29ydGVkS2V5cyA9IGFsbG93ZWQuc2xpY2UoKVxuICAgICAgICAuc29ydChmdW5jdGlvbiAoYSwgYikgeyByZXR1cm4gKGEubGVuZ3RoIDwgYi5sZW5ndGggPyAxIDogYS5sZW5ndGggPiBiLmxlbmd0aCA/IC0xIDogMCk7IH0pO1xuICAgIHZhciB1cHBlciA9IHJlbWFpbmluZy50b1VwcGVyQ2FzZSgpO1xuICAgIGZvciAodmFyIF9pID0gMCwgc29ydGVkS2V5c18yID0gc29ydGVkS2V5czsgX2kgPCBzb3J0ZWRLZXlzXzIubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgIHZhciBrZXkgPSBzb3J0ZWRLZXlzXzJbX2ldO1xuICAgICAgICBpZiAodXBwZXIuc3RhcnRzV2l0aChrZXkudG9VcHBlckNhc2UoKSkpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgY2hvc2VuOiBrZXksXG4gICAgICAgICAgICAgICAgcmVtYWluaW5nOiByZW1haW5pbmcuc2xpY2Uoa2V5Lmxlbmd0aClcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuICgwLCBlcnJvcl8xLnRocm93RXJyb3IpKFwiUGFyc2VFcnJvclwiLCBcImludmFsaWQgXCIgKyB0b2tlbl8xLlRva2VuVHlwZVt0b2tlbi50eXBlXS50b0xvd2VyQ2FzZSgpICsgXCIsIGV4cGVjdGVkIG9uZSBvZiBcIiArIGFsbG93ZWQuam9pbihcIiwgXCIpKTtcbn1cbi8vIyBzb3VyY2VNYXBwaW5nVVJMPXBhcnNlLmpzLm1hcCIsIi8qKlxuICogQ29weXJpZ2h0KGMpIDIwMTQgQUJCIFN3aXR6ZXJsYW5kIEx0ZC5cbiAqXG4gKiBQZXJpb2RpYyBpbnRlcnZhbCBmdW5jdGlvbnNcbiAqL1xuXCJ1c2Ugc3RyaWN0XCI7XG5PYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgXCJfX2VzTW9kdWxlXCIsIHsgdmFsdWU6IHRydWUgfSk7XG5leHBvcnRzLnRpbWVzdGFtcE9uV2Vla1RpbWVMZXNzVGhhbiA9IGV4cG9ydHMudGltZXN0YW1wT25XZWVrVGltZUdyZWF0ZXJUaGFuT3JFcXVhbFRvID0gZXhwb3J0cy5pc1BlcmlvZCA9IGV4cG9ydHMuaXNWYWxpZFBlcmlvZEpzb24gPSBleHBvcnRzLlBlcmlvZCA9IGV4cG9ydHMucGVyaW9kRHN0VG9TdHJpbmcgPSBleHBvcnRzLlBlcmlvZERzdCA9IHZvaWQgMDtcbnZhciBhc3NlcnRfMSA9IHJlcXVpcmUoXCIuL2Fzc2VydFwiKTtcbnZhciBiYXNpY3NfMSA9IHJlcXVpcmUoXCIuL2Jhc2ljc1wiKTtcbnZhciBiYXNpY3MgPSByZXF1aXJlKFwiLi9iYXNpY3NcIik7XG52YXIgZGF0ZXRpbWVfMSA9IHJlcXVpcmUoXCIuL2RhdGV0aW1lXCIpO1xudmFyIGR1cmF0aW9uXzEgPSByZXF1aXJlKFwiLi9kdXJhdGlvblwiKTtcbnZhciBlcnJvcl8xID0gcmVxdWlyZShcIi4vZXJyb3JcIik7XG52YXIgdGltZXpvbmVfMSA9IHJlcXVpcmUoXCIuL3RpbWV6b25lXCIpO1xuLyoqXG4gKiBTcGVjaWZpZXMgaG93IHRoZSBwZXJpb2Qgc2hvdWxkIHJlcGVhdCBhY3Jvc3MgdGhlIGRheVxuICogZHVyaW5nIERTVCBjaGFuZ2VzLlxuICovXG52YXIgUGVyaW9kRHN0O1xuKGZ1bmN0aW9uIChQZXJpb2REc3QpIHtcbiAgICAvKipcbiAgICAgKiBLZWVwIHJlcGVhdGluZyBpbiBzaW1pbGFyIGludGVydmFscyBtZWFzdXJlZCBpbiBVVEMsXG4gICAgICogdW5hZmZlY3RlZCBieSBEYXlsaWdodCBTYXZpbmcgVGltZS5cbiAgICAgKiBFLmcuIGEgcmVwZXRpdGlvbiBvZiBvbmUgaG91ciB3aWxsIHRha2Ugb25lIHJlYWwgaG91clxuICAgICAqIGV2ZXJ5IHRpbWUsIGV2ZW4gaW4gYSB0aW1lIHpvbmUgd2l0aCBEU1QuXG4gICAgICogTGVhcCBzZWNvbmRzLCBsZWFwIGRheXMgYW5kIG1vbnRoIGxlbmd0aFxuICAgICAqIGRpZmZlcmVuY2VzIHdpbGwgc3RpbGwgbWFrZSB0aGUgaW50ZXJ2YWxzIGRpZmZlcmVudC5cbiAgICAgKi9cbiAgICBQZXJpb2REc3RbUGVyaW9kRHN0W1wiUmVndWxhckludGVydmFsc1wiXSA9IDBdID0gXCJSZWd1bGFySW50ZXJ2YWxzXCI7XG4gICAgLyoqXG4gICAgICogRW5zdXJlIHRoYXQgdGhlIHRpbWUgYXQgd2hpY2ggdGhlIGludGVydmFscyBvY2N1ciBzdGF5XG4gICAgICogYXQgdGhlIHNhbWUgcGxhY2UgaW4gdGhlIGRheSwgbG9jYWwgdGltZS4gU28gZS5nLlxuICAgICAqIGEgcGVyaW9kIG9mIG9uZSBkYXksIHJlZmVyZW5jZWluZyBhdCA4OjA1QU0gRXVyb3BlL0Ftc3RlcmRhbSB0aW1lXG4gICAgICogd2lsbCBhbHdheXMgcmVmZXJlbmNlIGF0IDg6MDUgRXVyb3BlL0Ftc3RlcmRhbS4gVGhpcyBtZWFucyB0aGF0XG4gICAgICogaW4gVVRDIHRpbWUsIHNvbWUgaW50ZXJ2YWxzIHdpbGwgYmUgMjUgaG91cnMgYW5kIHNvbWVcbiAgICAgKiAyMyBob3VycyBkdXJpbmcgRFNUIGNoYW5nZXMuXG4gICAgICogQW5vdGhlciBleGFtcGxlOiBhbiBob3VybHkgaW50ZXJ2YWwgd2lsbCBiZSBob3VybHkgaW4gbG9jYWwgdGltZSxcbiAgICAgKiBza2lwcGluZyBhbiBob3VyIGluIFVUQyBmb3IgYSBEU1QgYmFja3dhcmQgY2hhbmdlLlxuICAgICAqL1xuICAgIFBlcmlvZERzdFtQZXJpb2REc3RbXCJSZWd1bGFyTG9jYWxUaW1lXCJdID0gMV0gPSBcIlJlZ3VsYXJMb2NhbFRpbWVcIjtcbiAgICAvKipcbiAgICAgKiBFbmQtb2YtZW51bSBtYXJrZXJcbiAgICAgKi9cbiAgICBQZXJpb2REc3RbUGVyaW9kRHN0W1wiTUFYXCJdID0gMl0gPSBcIk1BWFwiO1xufSkoUGVyaW9kRHN0IHx8IChleHBvcnRzLlBlcmlvZERzdCA9IFBlcmlvZERzdCA9IHt9KSk7XG4vKipcbiAqIENvbnZlcnQgYSBQZXJpb2REc3QgdG8gYSBzdHJpbmc6IFwicmVndWxhciBpbnRlcnZhbHNcIiBvciBcInJlZ3VsYXIgbG9jYWwgdGltZVwiXG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuUCBmb3IgaW52YWxpZCBQZXJpb2REc3QgdmFsdWVcbiAqL1xuZnVuY3Rpb24gcGVyaW9kRHN0VG9TdHJpbmcocCkge1xuICAgIHN3aXRjaCAocCkge1xuICAgICAgICBjYXNlIFBlcmlvZERzdC5SZWd1bGFySW50ZXJ2YWxzOiByZXR1cm4gXCJyZWd1bGFyIGludGVydmFsc1wiO1xuICAgICAgICBjYXNlIFBlcmlvZERzdC5SZWd1bGFyTG9jYWxUaW1lOiByZXR1cm4gXCJyZWd1bGFyIGxvY2FsIHRpbWVcIjtcbiAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gICAgICAgICAgICByZXR1cm4gKDAsIGVycm9yXzEudGhyb3dFcnJvcikoXCJBcmd1bWVudC5QXCIsIFwiaW52YWxpZCBQZXJpb0RzdCB2YWx1ZSBcIi5jb25jYXQocCkpO1xuICAgIH1cbn1cbmV4cG9ydHMucGVyaW9kRHN0VG9TdHJpbmcgPSBwZXJpb2REc3RUb1N0cmluZztcbi8qKlxuICogUmVwZWF0aW5nIHRpbWUgcGVyaW9kOiBjb25zaXN0cyBvZiBhIHJlZmVyZW5jZSBkYXRlIGFuZFxuICogYSB0aW1lIGxlbmd0aC4gVGhpcyBjbGFzcyBhY2NvdW50cyBmb3IgbGVhcCBzZWNvbmRzIGFuZCBsZWFwIGRheXMuXG4gKi9cbnZhciBQZXJpb2QgPSAvKiogQGNsYXNzICovIChmdW5jdGlvbiAoKSB7XG4gICAgLyoqXG4gICAgICogQ29uc3RydWN0b3IgaW1wbGVtZW50YXRpb24uIFNlZSBvdGhlciBjb25zdHJ1Y3RvcnMgZm9yIGV4cGxhbmF0aW9uLlxuICAgICAqL1xuICAgIGZ1bmN0aW9uIFBlcmlvZChhLCBhbW91bnRPckludGVydmFsLCB1bml0T3JEc3QsIGdpdmVuRHN0KSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBBbGxvdyBub3QgdXNpbmcgaW5zdGFuY2VvZlxuICAgICAgICAgKi9cbiAgICAgICAgdGhpcy5raW5kID0gXCJQZXJpb2RcIjtcbiAgICAgICAgdmFyIHJlZmVyZW5jZTtcbiAgICAgICAgdmFyIGludGVydmFsO1xuICAgICAgICB2YXIgZHN0ID0gUGVyaW9kRHN0LlJlZ3VsYXJMb2NhbFRpbWU7XG4gICAgICAgIGlmICgoMCwgZGF0ZXRpbWVfMS5pc0RhdGVUaW1lKShhKSkge1xuICAgICAgICAgICAgcmVmZXJlbmNlID0gYTtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgKGFtb3VudE9ySW50ZXJ2YWwpID09PSBcIm9iamVjdFwiKSB7XG4gICAgICAgICAgICAgICAgaW50ZXJ2YWwgPSBhbW91bnRPckludGVydmFsO1xuICAgICAgICAgICAgICAgIGRzdCA9IHVuaXRPckRzdDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KSh0eXBlb2YgdW5pdE9yRHN0ID09PSBcIm51bWJlclwiICYmIHVuaXRPckRzdCA+PSAwICYmIHVuaXRPckRzdCA8IGJhc2ljc18xLlRpbWVVbml0Lk1BWCwgXCJBcmd1bWVudC5Vbml0XCIsIFwiSW52YWxpZCB1bml0XCIpO1xuICAgICAgICAgICAgICAgIGludGVydmFsID0gbmV3IGR1cmF0aW9uXzEuRHVyYXRpb24oYW1vdW50T3JJbnRlcnZhbCwgdW5pdE9yRHN0KTtcbiAgICAgICAgICAgICAgICBkc3QgPSBnaXZlbkRzdDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICh0eXBlb2YgZHN0ICE9PSBcIm51bWJlclwiKSB7XG4gICAgICAgICAgICAgICAgZHN0ID0gUGVyaW9kRHN0LlJlZ3VsYXJMb2NhbFRpbWU7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIHJlZmVyZW5jZSA9IG5ldyBkYXRldGltZV8xLkRhdGVUaW1lKGEucmVmZXJlbmNlKTtcbiAgICAgICAgICAgICAgICBpbnRlcnZhbCA9IG5ldyBkdXJhdGlvbl8xLkR1cmF0aW9uKGEuZHVyYXRpb24pO1xuICAgICAgICAgICAgICAgIGRzdCA9IGEucGVyaW9kRHN0ID09PSBcInJlZ3VsYXJcIiA/IFBlcmlvZERzdC5SZWd1bGFySW50ZXJ2YWxzIDogUGVyaW9kRHN0LlJlZ3VsYXJMb2NhbFRpbWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgIHJldHVybiAoMCwgZXJyb3JfMS50aHJvd0Vycm9yKShcIkFyZ3VtZW50Lkpzb25cIiwgZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKGRzdCA+PSAwICYmIGRzdCA8IFBlcmlvZERzdC5NQVgsIFwiQXJndW1lbnQuRHN0XCIsIFwiSW52YWxpZCBQZXJpb2REc3Qgc2V0dGluZ1wiKTtcbiAgICAgICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKGludGVydmFsLmFtb3VudCgpID4gMCwgXCJBcmd1bWVudC5JbnRlcnZhbFwiLCBcIkFtb3VudCBtdXN0IGJlIHBvc2l0aXZlIG5vbi16ZXJvLlwiKTtcbiAgICAgICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKE51bWJlci5pc0ludGVnZXIoaW50ZXJ2YWwuYW1vdW50KCkpLCBcIkFyZ3VtZW50LkludGVydmFsXCIsIFwiQW1vdW50IG11c3QgYmUgYSB3aG9sZSBudW1iZXJcIik7XG4gICAgICAgIHRoaXMuX3JlZmVyZW5jZSA9IHJlZmVyZW5jZTtcbiAgICAgICAgdGhpcy5faW50ZXJ2YWwgPSBpbnRlcnZhbDtcbiAgICAgICAgdGhpcy5fZHN0ID0gZHN0O1xuICAgICAgICB0aGlzLl9jYWxjSW50ZXJuYWxWYWx1ZXMoKTtcbiAgICAgICAgLy8gcmVndWxhciBsb2NhbCB0aW1lIGtlZXBpbmcgaXMgb25seSBzdXBwb3J0ZWQgaWYgd2UgY2FuIHJlc2V0IGVhY2ggZGF5XG4gICAgICAgIC8vIE5vdGUgd2UgdXNlIGludGVybmFsIGFtb3VudHMgdG8gZGVjaWRlIHRoaXMgYmVjYXVzZSBhY3R1YWxseSBpdCBpcyBzdXBwb3J0ZWQgaWZcbiAgICAgICAgLy8gdGhlIGlucHV0IGlzIGEgbXVsdGlwbGUgb2Ygb25lIGRheS5cbiAgICAgICAgaWYgKHRoaXMuX2RzdFJlbGV2YW50KCkgJiYgZHN0ID09PSBQZXJpb2REc3QuUmVndWxhckxvY2FsVGltZSkge1xuICAgICAgICAgICAgc3dpdGNoICh0aGlzLl9pbnRJbnRlcnZhbC51bml0KCkpIHtcbiAgICAgICAgICAgICAgICBjYXNlIGJhc2ljc18xLlRpbWVVbml0Lk1pbGxpc2Vjb25kOlxuICAgICAgICAgICAgICAgICAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkodGhpcy5faW50SW50ZXJ2YWwuYW1vdW50KCkgPCA4NjQwMDAwMCwgXCJBcmd1bWVudC5JbnRlcnZhbC5Ob3RJbXBsZW1lbnRlZFwiLCBcIldoZW4gdXNpbmcgSG91ciwgTWludXRlIG9yIChNaWxsaSlTZWNvbmQgdW5pdHMsIHdpdGggUmVndWxhciBMb2NhbCBUaW1lcywgXCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgXCJ0aGVuIHRoZSBhbW91bnQgbXVzdCBiZSBlaXRoZXIgbGVzcyB0aGFuIGEgZGF5IG9yIGEgbXVsdGlwbGUgb2YgdGhlIG5leHQgdW5pdC5cIik7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIGNhc2UgYmFzaWNzXzEuVGltZVVuaXQuU2Vjb25kOlxuICAgICAgICAgICAgICAgICAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkodGhpcy5faW50SW50ZXJ2YWwuYW1vdW50KCkgPCA4NjQwMCwgXCJBcmd1bWVudC5JbnRlcnZhbC5Ob3RJbXBsZW1lbnRlZFwiLCBcIldoZW4gdXNpbmcgSG91ciwgTWludXRlIG9yIChNaWxsaSlTZWNvbmQgdW5pdHMsIHdpdGggUmVndWxhciBMb2NhbCBUaW1lcywgXCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgXCJ0aGVuIHRoZSBhbW91bnQgbXVzdCBiZSBlaXRoZXIgbGVzcyB0aGFuIGEgZGF5IG9yIGEgbXVsdGlwbGUgb2YgdGhlIG5leHQgdW5pdC5cIik7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIGNhc2UgYmFzaWNzXzEuVGltZVVuaXQuTWludXRlOlxuICAgICAgICAgICAgICAgICAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkodGhpcy5faW50SW50ZXJ2YWwuYW1vdW50KCkgPCAxNDQwLCBcIkFyZ3VtZW50LkludGVydmFsLk5vdEltcGxlbWVudGVkXCIsIFwiV2hlbiB1c2luZyBIb3VyLCBNaW51dGUgb3IgKE1pbGxpKVNlY29uZCB1bml0cywgd2l0aCBSZWd1bGFyIExvY2FsIFRpbWVzLCBcIiArXG4gICAgICAgICAgICAgICAgICAgICAgICBcInRoZW4gdGhlIGFtb3VudCBtdXN0IGJlIGVpdGhlciBsZXNzIHRoYW4gYSBkYXkgb3IgYSBtdWx0aXBsZSBvZiB0aGUgbmV4dCB1bml0LlwiKTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgY2FzZSBiYXNpY3NfMS5UaW1lVW5pdC5Ib3VyOlxuICAgICAgICAgICAgICAgICAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkodGhpcy5faW50SW50ZXJ2YWwuYW1vdW50KCkgPCAyNCwgXCJBcmd1bWVudC5JbnRlcnZhbC5Ob3RJbXBsZW1lbnRlZFwiLCBcIldoZW4gdXNpbmcgSG91ciwgTWludXRlIG9yIChNaWxsaSlTZWNvbmQgdW5pdHMsIHdpdGggUmVndWxhciBMb2NhbCBUaW1lcywgXCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgXCJ0aGVuIHRoZSBhbW91bnQgbXVzdCBiZSBlaXRoZXIgbGVzcyB0aGFuIGEgZGF5IG9yIGEgbXVsdGlwbGUgb2YgdGhlIG5leHQgdW5pdC5cIik7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuICAgIC8qKlxuICAgICAqIFJldHVybiBhIGZyZXNoIGNvcHkgb2YgdGhlIHBlcmlvZFxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIFBlcmlvZC5wcm90b3R5cGUuY2xvbmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBuZXcgUGVyaW9kKHRoaXMuX3JlZmVyZW5jZSwgdGhpcy5faW50ZXJ2YWwsIHRoaXMuX2RzdCk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBUaGUgcmVmZXJlbmNlIGRhdGVcbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBQZXJpb2QucHJvdG90eXBlLnJlZmVyZW5jZSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3JlZmVyZW5jZTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIERFUFJFQ0FURUQ6IG9sZCBuYW1lIGZvciB0aGUgcmVmZXJlbmNlIGRhdGVcbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBQZXJpb2QucHJvdG90eXBlLnN0YXJ0ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fcmVmZXJlbmNlO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogVGhlIGludGVydmFsXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgUGVyaW9kLnByb3RvdHlwZS5pbnRlcnZhbCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2ludGVydmFsLmNsb25lKCk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBUaGUgYW1vdW50IG9mIHVuaXRzIG9mIHRoZSBpbnRlcnZhbFxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIFBlcmlvZC5wcm90b3R5cGUuYW1vdW50ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5faW50ZXJ2YWwuYW1vdW50KCk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBUaGUgdW5pdCBvZiB0aGUgaW50ZXJ2YWxcbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBQZXJpb2QucHJvdG90eXBlLnVuaXQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9pbnRlcnZhbC51bml0KCk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBUaGUgZHN0IGhhbmRsaW5nIG1vZGVcbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBQZXJpb2QucHJvdG90eXBlLmRzdCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2RzdDtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFRoZSBmaXJzdCBvY2N1cnJlbmNlIG9mIHRoZSBwZXJpb2QgZ3JlYXRlciB0aGFuXG4gICAgICogdGhlIGdpdmVuIGRhdGUuIFRoZSBnaXZlbiBkYXRlIG5lZWQgbm90IGJlIGF0IGEgcGVyaW9kIGJvdW5kYXJ5LlxuICAgICAqIFByZTogdGhlIGZyb21kYXRlIGFuZCByZWZlcmVuY2UgZGF0ZSBtdXN0IGVpdGhlciBib3RoIGhhdmUgdGltZXpvbmVzIG9yIG5vdFxuICAgICAqIEBwYXJhbSBmcm9tRGF0ZTogdGhlIGRhdGUgYWZ0ZXIgd2hpY2ggdG8gcmV0dXJuIHRoZSBuZXh0IGRhdGVcbiAgICAgKiBAcmV0dXJuIHRoZSBmaXJzdCBkYXRlIG1hdGNoaW5nIHRoZSBwZXJpb2QgYWZ0ZXIgZnJvbURhdGUsIGdpdmVuIGluIHRoZSBzYW1lIHpvbmUgYXMgdGhlIGZyb21EYXRlLlxuICAgICAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5VbmF3YXJlVG9Bd2FyZUNvbnZlcnNpb24gaWYgbm90IGJvdGggZnJvbWRhdGUgYW5kIHRoZSByZWZlcmVuY2UgZGF0ZSBhcmUgYm90aCBhd2FyZSBvciB1bmF3YXJlIG9mIHRpbWUgem9uZVxuICAgICAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Ob3RGb3VuZC5ab25lIGlmIHRoZSBVVEMgdGltZSB6b25lIGRvZXNuJ3QgZXhpc3QgaW4gdGhlIHRpbWUgem9uZSBkYXRhYmFzZVxuICAgICAqL1xuICAgIFBlcmlvZC5wcm90b3R5cGUuZmluZEZpcnN0ID0gZnVuY3Rpb24gKGZyb21EYXRlKSB7XG4gICAgICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KSghIXRoaXMuX2ludFJlZmVyZW5jZS56b25lKCkgPT09ICEhZnJvbURhdGUuem9uZSgpLCBcIlVuYXdhcmVUb0F3YXJlQ29udmVyc2lvblwiLCBcIlRoZSBmcm9tRGF0ZSBhbmQgcmVmZXJlbmNlIGRhdGUgbXVzdCBib3RoIGJlIGF3YXJlIG9yIHVuYXdhcmVcIik7XG4gICAgICAgIHZhciBhcHByb3g7XG4gICAgICAgIHZhciBhcHByb3gyO1xuICAgICAgICB2YXIgYXBwcm94TWluO1xuICAgICAgICB2YXIgcGVyaW9kcztcbiAgICAgICAgdmFyIGRpZmY7XG4gICAgICAgIHZhciBuZXdZZWFyO1xuICAgICAgICB2YXIgcmVtYWluZGVyO1xuICAgICAgICB2YXIgaW1heDtcbiAgICAgICAgdmFyIGltaW47XG4gICAgICAgIHZhciBpbWlkO1xuICAgICAgICB2YXIgbm9ybWFsRnJvbSA9IHRoaXMuX25vcm1hbGl6ZURheShmcm9tRGF0ZS50b1pvbmUodGhpcy5faW50UmVmZXJlbmNlLnpvbmUoKSkpO1xuICAgICAgICBpZiAodGhpcy5faW50SW50ZXJ2YWwuYW1vdW50KCkgPT09IDEpIHtcbiAgICAgICAgICAgIC8vIHNpbXBsZSBjYXNlczogYW1vdW50IGVxdWFscyAxIChlbGltaW5hdGVzIG5lZWQgZm9yIHNlYXJjaGluZyBmb3IgcmVmZXJlbmNlaW5nIHBvaW50KVxuICAgICAgICAgICAgaWYgKHRoaXMuX2ludERzdCA9PT0gUGVyaW9kRHN0LlJlZ3VsYXJJbnRlcnZhbHMpIHtcbiAgICAgICAgICAgICAgICAvLyBhcHBseSB0byBVVEMgdGltZVxuICAgICAgICAgICAgICAgIHN3aXRjaCAodGhpcy5faW50SW50ZXJ2YWwudW5pdCgpKSB7XG4gICAgICAgICAgICAgICAgICAgIGNhc2UgYmFzaWNzXzEuVGltZVVuaXQuTWlsbGlzZWNvbmQ6XG4gICAgICAgICAgICAgICAgICAgICAgICBhcHByb3ggPSBuZXcgZGF0ZXRpbWVfMS5EYXRlVGltZShub3JtYWxGcm9tLnV0Y1llYXIoKSwgbm9ybWFsRnJvbS51dGNNb250aCgpLCBub3JtYWxGcm9tLnV0Y0RheSgpLCBub3JtYWxGcm9tLnV0Y0hvdXIoKSwgbm9ybWFsRnJvbS51dGNNaW51dGUoKSwgbm9ybWFsRnJvbS51dGNTZWNvbmQoKSwgbm9ybWFsRnJvbS51dGNNaWxsaXNlY29uZCgpLCB0aW1lem9uZV8xLlRpbWVab25lLnV0YygpKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICBjYXNlIGJhc2ljc18xLlRpbWVVbml0LlNlY29uZDpcbiAgICAgICAgICAgICAgICAgICAgICAgIGFwcHJveCA9IG5ldyBkYXRldGltZV8xLkRhdGVUaW1lKG5vcm1hbEZyb20udXRjWWVhcigpLCBub3JtYWxGcm9tLnV0Y01vbnRoKCksIG5vcm1hbEZyb20udXRjRGF5KCksIG5vcm1hbEZyb20udXRjSG91cigpLCBub3JtYWxGcm9tLnV0Y01pbnV0ZSgpLCBub3JtYWxGcm9tLnV0Y1NlY29uZCgpLCB0aGlzLl9pbnRSZWZlcmVuY2UudXRjTWlsbGlzZWNvbmQoKSwgdGltZXpvbmVfMS5UaW1lWm9uZS51dGMoKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgY2FzZSBiYXNpY3NfMS5UaW1lVW5pdC5NaW51dGU6XG4gICAgICAgICAgICAgICAgICAgICAgICBhcHByb3ggPSBuZXcgZGF0ZXRpbWVfMS5EYXRlVGltZShub3JtYWxGcm9tLnV0Y1llYXIoKSwgbm9ybWFsRnJvbS51dGNNb250aCgpLCBub3JtYWxGcm9tLnV0Y0RheSgpLCBub3JtYWxGcm9tLnV0Y0hvdXIoKSwgbm9ybWFsRnJvbS51dGNNaW51dGUoKSwgdGhpcy5faW50UmVmZXJlbmNlLnV0Y1NlY29uZCgpLCB0aGlzLl9pbnRSZWZlcmVuY2UudXRjTWlsbGlzZWNvbmQoKSwgdGltZXpvbmVfMS5UaW1lWm9uZS51dGMoKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgY2FzZSBiYXNpY3NfMS5UaW1lVW5pdC5Ib3VyOlxuICAgICAgICAgICAgICAgICAgICAgICAgYXBwcm94ID0gbmV3IGRhdGV0aW1lXzEuRGF0ZVRpbWUobm9ybWFsRnJvbS51dGNZZWFyKCksIG5vcm1hbEZyb20udXRjTW9udGgoKSwgbm9ybWFsRnJvbS51dGNEYXkoKSwgbm9ybWFsRnJvbS51dGNIb3VyKCksIHRoaXMuX2ludFJlZmVyZW5jZS51dGNNaW51dGUoKSwgdGhpcy5faW50UmVmZXJlbmNlLnV0Y1NlY29uZCgpLCB0aGlzLl9pbnRSZWZlcmVuY2UudXRjTWlsbGlzZWNvbmQoKSwgdGltZXpvbmVfMS5UaW1lWm9uZS51dGMoKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgY2FzZSBiYXNpY3NfMS5UaW1lVW5pdC5EYXk6XG4gICAgICAgICAgICAgICAgICAgICAgICBhcHByb3ggPSBuZXcgZGF0ZXRpbWVfMS5EYXRlVGltZShub3JtYWxGcm9tLnV0Y1llYXIoKSwgbm9ybWFsRnJvbS51dGNNb250aCgpLCBub3JtYWxGcm9tLnV0Y0RheSgpLCB0aGlzLl9pbnRSZWZlcmVuY2UudXRjSG91cigpLCB0aGlzLl9pbnRSZWZlcmVuY2UudXRjTWludXRlKCksIHRoaXMuX2ludFJlZmVyZW5jZS51dGNTZWNvbmQoKSwgdGhpcy5faW50UmVmZXJlbmNlLnV0Y01pbGxpc2Vjb25kKCksIHRpbWV6b25lXzEuVGltZVpvbmUudXRjKCkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgIGNhc2UgYmFzaWNzXzEuVGltZVVuaXQuTW9udGg6XG4gICAgICAgICAgICAgICAgICAgICAgICBhcHByb3ggPSBuZXcgZGF0ZXRpbWVfMS5EYXRlVGltZShub3JtYWxGcm9tLnV0Y1llYXIoKSwgbm9ybWFsRnJvbS51dGNNb250aCgpLCB0aGlzLl9pbnRSZWZlcmVuY2UudXRjRGF5KCksIHRoaXMuX2ludFJlZmVyZW5jZS51dGNIb3VyKCksIHRoaXMuX2ludFJlZmVyZW5jZS51dGNNaW51dGUoKSwgdGhpcy5faW50UmVmZXJlbmNlLnV0Y1NlY29uZCgpLCB0aGlzLl9pbnRSZWZlcmVuY2UudXRjTWlsbGlzZWNvbmQoKSwgdGltZXpvbmVfMS5UaW1lWm9uZS51dGMoKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgY2FzZSBiYXNpY3NfMS5UaW1lVW5pdC5ZZWFyOlxuICAgICAgICAgICAgICAgICAgICAgICAgYXBwcm94ID0gbmV3IGRhdGV0aW1lXzEuRGF0ZVRpbWUobm9ybWFsRnJvbS51dGNZZWFyKCksIHRoaXMuX2ludFJlZmVyZW5jZS51dGNNb250aCgpLCB0aGlzLl9pbnRSZWZlcmVuY2UudXRjRGF5KCksIHRoaXMuX2ludFJlZmVyZW5jZS51dGNIb3VyKCksIHRoaXMuX2ludFJlZmVyZW5jZS51dGNNaW51dGUoKSwgdGhpcy5faW50UmVmZXJlbmNlLnV0Y1NlY29uZCgpLCB0aGlzLl9pbnRSZWZlcmVuY2UudXRjTWlsbGlzZWNvbmQoKSwgdGltZXpvbmVfMS5UaW1lWm9uZS51dGMoKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbiAgICAgICAgICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBpZiAqL1xuICAgICAgICAgICAgICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0cnVlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuICgwLCBlcnJvcl8xLnRocm93RXJyb3IpKFwiQXNzZXJ0aW9uXCIsIFwiVW5rbm93biBUaW1lVW5pdFwiKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgd2hpbGUgKCFhcHByb3guZ3JlYXRlclRoYW4oZnJvbURhdGUpKSB7XG4gICAgICAgICAgICAgICAgICAgIGFwcHJveCA9IGFwcHJveC5hZGQodGhpcy5faW50SW50ZXJ2YWwuYW1vdW50KCksIHRoaXMuX2ludEludGVydmFsLnVuaXQoKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgLy8gVHJ5IHRvIGtlZXAgcmVndWxhciBsb2NhbCBpbnRlcnZhbHNcbiAgICAgICAgICAgICAgICBzd2l0Y2ggKHRoaXMuX2ludEludGVydmFsLnVuaXQoKSkge1xuICAgICAgICAgICAgICAgICAgICBjYXNlIGJhc2ljc18xLlRpbWVVbml0Lk1pbGxpc2Vjb25kOlxuICAgICAgICAgICAgICAgICAgICAgICAgYXBwcm94ID0gbmV3IGRhdGV0aW1lXzEuRGF0ZVRpbWUobm9ybWFsRnJvbS55ZWFyKCksIG5vcm1hbEZyb20ubW9udGgoKSwgbm9ybWFsRnJvbS5kYXkoKSwgbm9ybWFsRnJvbS5ob3VyKCksIG5vcm1hbEZyb20ubWludXRlKCksIG5vcm1hbEZyb20uc2Vjb25kKCksIG5vcm1hbEZyb20ubWlsbGlzZWNvbmQoKSwgdGhpcy5faW50UmVmZXJlbmNlLnpvbmUoKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgY2FzZSBiYXNpY3NfMS5UaW1lVW5pdC5TZWNvbmQ6XG4gICAgICAgICAgICAgICAgICAgICAgICBhcHByb3ggPSBuZXcgZGF0ZXRpbWVfMS5EYXRlVGltZShub3JtYWxGcm9tLnllYXIoKSwgbm9ybWFsRnJvbS5tb250aCgpLCBub3JtYWxGcm9tLmRheSgpLCBub3JtYWxGcm9tLmhvdXIoKSwgbm9ybWFsRnJvbS5taW51dGUoKSwgbm9ybWFsRnJvbS5zZWNvbmQoKSwgdGhpcy5faW50UmVmZXJlbmNlLm1pbGxpc2Vjb25kKCksIHRoaXMuX2ludFJlZmVyZW5jZS56b25lKCkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgIGNhc2UgYmFzaWNzXzEuVGltZVVuaXQuTWludXRlOlxuICAgICAgICAgICAgICAgICAgICAgICAgYXBwcm94ID0gbmV3IGRhdGV0aW1lXzEuRGF0ZVRpbWUobm9ybWFsRnJvbS55ZWFyKCksIG5vcm1hbEZyb20ubW9udGgoKSwgbm9ybWFsRnJvbS5kYXkoKSwgbm9ybWFsRnJvbS5ob3VyKCksIG5vcm1hbEZyb20ubWludXRlKCksIHRoaXMuX2ludFJlZmVyZW5jZS5zZWNvbmQoKSwgdGhpcy5faW50UmVmZXJlbmNlLm1pbGxpc2Vjb25kKCksIHRoaXMuX2ludFJlZmVyZW5jZS56b25lKCkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgIGNhc2UgYmFzaWNzXzEuVGltZVVuaXQuSG91cjpcbiAgICAgICAgICAgICAgICAgICAgICAgIGFwcHJveCA9IG5ldyBkYXRldGltZV8xLkRhdGVUaW1lKG5vcm1hbEZyb20ueWVhcigpLCBub3JtYWxGcm9tLm1vbnRoKCksIG5vcm1hbEZyb20uZGF5KCksIG5vcm1hbEZyb20uaG91cigpLCB0aGlzLl9pbnRSZWZlcmVuY2UubWludXRlKCksIHRoaXMuX2ludFJlZmVyZW5jZS5zZWNvbmQoKSwgdGhpcy5faW50UmVmZXJlbmNlLm1pbGxpc2Vjb25kKCksIHRoaXMuX2ludFJlZmVyZW5jZS56b25lKCkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgIGNhc2UgYmFzaWNzXzEuVGltZVVuaXQuRGF5OlxuICAgICAgICAgICAgICAgICAgICAgICAgYXBwcm94ID0gbmV3IGRhdGV0aW1lXzEuRGF0ZVRpbWUobm9ybWFsRnJvbS55ZWFyKCksIG5vcm1hbEZyb20ubW9udGgoKSwgbm9ybWFsRnJvbS5kYXkoKSwgdGhpcy5faW50UmVmZXJlbmNlLmhvdXIoKSwgdGhpcy5faW50UmVmZXJlbmNlLm1pbnV0ZSgpLCB0aGlzLl9pbnRSZWZlcmVuY2Uuc2Vjb25kKCksIHRoaXMuX2ludFJlZmVyZW5jZS5taWxsaXNlY29uZCgpLCB0aGlzLl9pbnRSZWZlcmVuY2Uuem9uZSgpKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICBjYXNlIGJhc2ljc18xLlRpbWVVbml0Lk1vbnRoOlxuICAgICAgICAgICAgICAgICAgICAgICAgYXBwcm94ID0gbmV3IGRhdGV0aW1lXzEuRGF0ZVRpbWUobm9ybWFsRnJvbS55ZWFyKCksIG5vcm1hbEZyb20ubW9udGgoKSwgdGhpcy5faW50UmVmZXJlbmNlLmRheSgpLCB0aGlzLl9pbnRSZWZlcmVuY2UuaG91cigpLCB0aGlzLl9pbnRSZWZlcmVuY2UubWludXRlKCksIHRoaXMuX2ludFJlZmVyZW5jZS5zZWNvbmQoKSwgdGhpcy5faW50UmVmZXJlbmNlLm1pbGxpc2Vjb25kKCksIHRoaXMuX2ludFJlZmVyZW5jZS56b25lKCkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgIGNhc2UgYmFzaWNzXzEuVGltZVVuaXQuWWVhcjpcbiAgICAgICAgICAgICAgICAgICAgICAgIGFwcHJveCA9IG5ldyBkYXRldGltZV8xLkRhdGVUaW1lKG5vcm1hbEZyb20ueWVhcigpLCB0aGlzLl9pbnRSZWZlcmVuY2UubW9udGgoKSwgdGhpcy5faW50UmVmZXJlbmNlLmRheSgpLCB0aGlzLl9pbnRSZWZlcmVuY2UuaG91cigpLCB0aGlzLl9pbnRSZWZlcmVuY2UubWludXRlKCksIHRoaXMuX2ludFJlZmVyZW5jZS5zZWNvbmQoKSwgdGhpcy5faW50UmVmZXJlbmNlLm1pbGxpc2Vjb25kKCksIHRoaXMuX2ludFJlZmVyZW5jZS56b25lKCkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gICAgICAgICAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgaWYgKi9cbiAgICAgICAgICAgICAgICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAodHJ1ZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiAoMCwgZXJyb3JfMS50aHJvd0Vycm9yKShcIkFzc2VydGlvblwiLCBcIlVua25vd24gVGltZVVuaXRcIik7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHdoaWxlICghYXBwcm94LmdyZWF0ZXJUaGFuKG5vcm1hbEZyb20pKSB7XG4gICAgICAgICAgICAgICAgICAgIGFwcHJveCA9IGFwcHJveC5hZGRMb2NhbCh0aGlzLl9pbnRJbnRlcnZhbC5hbW91bnQoKSwgdGhpcy5faW50SW50ZXJ2YWwudW5pdCgpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAvLyBBbW91bnQgaXMgbm90IDEsXG4gICAgICAgICAgICBpZiAodGhpcy5faW50RHN0ID09PSBQZXJpb2REc3QuUmVndWxhckludGVydmFscykge1xuICAgICAgICAgICAgICAgIC8vIGFwcGx5IHRvIFVUQyB0aW1lXG4gICAgICAgICAgICAgICAgc3dpdGNoICh0aGlzLl9pbnRJbnRlcnZhbC51bml0KCkpIHtcbiAgICAgICAgICAgICAgICAgICAgY2FzZSBiYXNpY3NfMS5UaW1lVW5pdC5NaWxsaXNlY29uZDpcbiAgICAgICAgICAgICAgICAgICAgICAgIGRpZmYgPSBub3JtYWxGcm9tLmRpZmYodGhpcy5faW50UmVmZXJlbmNlKS5taWxsaXNlY29uZHMoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHBlcmlvZHMgPSBNYXRoLmZsb29yKGRpZmYgLyB0aGlzLl9pbnRJbnRlcnZhbC5hbW91bnQoKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBhcHByb3ggPSB0aGlzLl9pbnRSZWZlcmVuY2UuYWRkKHBlcmlvZHMgKiB0aGlzLl9pbnRJbnRlcnZhbC5hbW91bnQoKSwgdGhpcy5faW50SW50ZXJ2YWwudW5pdCgpKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICBjYXNlIGJhc2ljc18xLlRpbWVVbml0LlNlY29uZDpcbiAgICAgICAgICAgICAgICAgICAgICAgIGRpZmYgPSBub3JtYWxGcm9tLmRpZmYodGhpcy5faW50UmVmZXJlbmNlKS5zZWNvbmRzKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBwZXJpb2RzID0gTWF0aC5mbG9vcihkaWZmIC8gdGhpcy5faW50SW50ZXJ2YWwuYW1vdW50KCkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgYXBwcm94ID0gdGhpcy5faW50UmVmZXJlbmNlLmFkZChwZXJpb2RzICogdGhpcy5faW50SW50ZXJ2YWwuYW1vdW50KCksIHRoaXMuX2ludEludGVydmFsLnVuaXQoKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgY2FzZSBiYXNpY3NfMS5UaW1lVW5pdC5NaW51dGU6XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBvbmx5IDI1IGxlYXAgc2Vjb25kcyBoYXZlIGV2ZXIgYmVlbiBhZGRlZCBzbyB0aGlzIHNob3VsZCBzdGlsbCBiZSBPSy5cbiAgICAgICAgICAgICAgICAgICAgICAgIGRpZmYgPSBub3JtYWxGcm9tLmRpZmYodGhpcy5faW50UmVmZXJlbmNlKS5taW51dGVzKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBwZXJpb2RzID0gTWF0aC5mbG9vcihkaWZmIC8gdGhpcy5faW50SW50ZXJ2YWwuYW1vdW50KCkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgYXBwcm94ID0gdGhpcy5faW50UmVmZXJlbmNlLmFkZChwZXJpb2RzICogdGhpcy5faW50SW50ZXJ2YWwuYW1vdW50KCksIHRoaXMuX2ludEludGVydmFsLnVuaXQoKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgY2FzZSBiYXNpY3NfMS5UaW1lVW5pdC5Ib3VyOlxuICAgICAgICAgICAgICAgICAgICAgICAgZGlmZiA9IG5vcm1hbEZyb20uZGlmZih0aGlzLl9pbnRSZWZlcmVuY2UpLmhvdXJzKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBwZXJpb2RzID0gTWF0aC5mbG9vcihkaWZmIC8gdGhpcy5faW50SW50ZXJ2YWwuYW1vdW50KCkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgYXBwcm94ID0gdGhpcy5faW50UmVmZXJlbmNlLmFkZChwZXJpb2RzICogdGhpcy5faW50SW50ZXJ2YWwuYW1vdW50KCksIHRoaXMuX2ludEludGVydmFsLnVuaXQoKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgY2FzZSBiYXNpY3NfMS5UaW1lVW5pdC5EYXk6XG4gICAgICAgICAgICAgICAgICAgICAgICBkaWZmID0gbm9ybWFsRnJvbS5kaWZmKHRoaXMuX2ludFJlZmVyZW5jZSkuaG91cnMoKSAvIDI0O1xuICAgICAgICAgICAgICAgICAgICAgICAgcGVyaW9kcyA9IE1hdGguZmxvb3IoZGlmZiAvIHRoaXMuX2ludEludGVydmFsLmFtb3VudCgpKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGFwcHJveCA9IHRoaXMuX2ludFJlZmVyZW5jZS5hZGQocGVyaW9kcyAqIHRoaXMuX2ludEludGVydmFsLmFtb3VudCgpLCB0aGlzLl9pbnRJbnRlcnZhbC51bml0KCkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgIGNhc2UgYmFzaWNzXzEuVGltZVVuaXQuTW9udGg6XG4gICAgICAgICAgICAgICAgICAgICAgICBkaWZmID0gKG5vcm1hbEZyb20udXRjWWVhcigpIC0gdGhpcy5faW50UmVmZXJlbmNlLnV0Y1llYXIoKSkgKiAxMiArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKG5vcm1hbEZyb20udXRjTW9udGgoKSAtIHRoaXMuX2ludFJlZmVyZW5jZS51dGNNb250aCgpKSAtIDE7XG4gICAgICAgICAgICAgICAgICAgICAgICBwZXJpb2RzID0gTWF0aC5mbG9vcihkaWZmIC8gdGhpcy5faW50SW50ZXJ2YWwuYW1vdW50KCkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgYXBwcm94ID0gdGhpcy5faW50UmVmZXJlbmNlLmFkZChwZXJpb2RzICogdGhpcy5faW50SW50ZXJ2YWwuYW1vdW50KCksIHRoaXMuX2ludEludGVydmFsLnVuaXQoKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgY2FzZSBiYXNpY3NfMS5UaW1lVW5pdC5ZZWFyOlxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gVGhlIC0xIGJlbG93IGlzIGJlY2F1c2UgdGhlIGRheS1vZi1tb250aCBvZiByZWZlcmVuY2UgZGF0ZSBtYXkgYmUgYWZ0ZXIgdGhlIGRheSBvZiB0aGUgZnJvbURhdGVcbiAgICAgICAgICAgICAgICAgICAgICAgIGRpZmYgPSBub3JtYWxGcm9tLnllYXIoKSAtIHRoaXMuX2ludFJlZmVyZW5jZS55ZWFyKCkgLSAxO1xuICAgICAgICAgICAgICAgICAgICAgICAgcGVyaW9kcyA9IE1hdGguZmxvb3IoZGlmZiAvIHRoaXMuX2ludEludGVydmFsLmFtb3VudCgpKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGFwcHJveCA9IHRoaXMuX2ludFJlZmVyZW5jZS5hZGQocGVyaW9kcyAqIHRoaXMuX2ludEludGVydmFsLmFtb3VudCgpLCBiYXNpY3NfMS5UaW1lVW5pdC5ZZWFyKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICAgICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIGlmICovXG4gICAgICAgICAgICAgICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRydWUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gKDAsIGVycm9yXzEudGhyb3dFcnJvcikoXCJBc3NlcnRpb25cIiwgXCJVbmtub3duIFRpbWVVbml0XCIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB3aGlsZSAoIWFwcHJveC5ncmVhdGVyVGhhbihmcm9tRGF0ZSkpIHtcbiAgICAgICAgICAgICAgICAgICAgYXBwcm94ID0gYXBwcm94LmFkZCh0aGlzLl9pbnRJbnRlcnZhbC5hbW91bnQoKSwgdGhpcy5faW50SW50ZXJ2YWwudW5pdCgpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAvLyBUcnkgdG8ga2VlcCByZWd1bGFyIGxvY2FsIHRpbWVzLiBJZiB0aGUgdW5pdCBpcyBsZXNzIHRoYW4gYSBkYXksIHdlIHJlZmVyZW5jZSBlYWNoIGRheSBhbmV3XG4gICAgICAgICAgICAgICAgc3dpdGNoICh0aGlzLl9pbnRJbnRlcnZhbC51bml0KCkpIHtcbiAgICAgICAgICAgICAgICAgICAgY2FzZSBiYXNpY3NfMS5UaW1lVW5pdC5NaWxsaXNlY29uZDpcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLl9pbnRJbnRlcnZhbC5hbW91bnQoKSA8IDEwMDAgJiYgKDEwMDAgJSB0aGlzLl9pbnRJbnRlcnZhbC5hbW91bnQoKSkgPT09IDApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBvcHRpbWl6YXRpb246IHNhbWUgbWlsbGlzZWNvbmQgZWFjaCBzZWNvbmQsIHNvIGp1c3QgdGFrZSB0aGUgZnJvbURhdGVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBtaW51cyBvbmUgc2Vjb25kIHdpdGggdGhlIHRoaXMuX2ludFJlZmVyZW5jZSBtaWxsaXNlY29uZHNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcHByb3ggPSBuZXcgZGF0ZXRpbWVfMS5EYXRlVGltZShub3JtYWxGcm9tLnllYXIoKSwgbm9ybWFsRnJvbS5tb250aCgpLCBub3JtYWxGcm9tLmRheSgpLCBub3JtYWxGcm9tLmhvdXIoKSwgbm9ybWFsRnJvbS5taW51dGUoKSwgbm9ybWFsRnJvbS5zZWNvbmQoKSwgdGhpcy5faW50UmVmZXJlbmNlLm1pbGxpc2Vjb25kKCksIHRoaXMuX2ludFJlZmVyZW5jZS56b25lKCkpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5zdWJMb2NhbCgxLCBiYXNpY3NfMS5UaW1lVW5pdC5TZWNvbmQpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gcGVyIGNvbnN0cnVjdG9yIGFzc2VydCwgdGhlIHNlY29uZHMgYXJlIGxlc3MgdGhhbiBhIGRheSwgc28ganVzdCBnbyB0aGUgZnJvbURhdGUgcmVmZXJlbmNlLW9mLWRheVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFwcHJveCA9IG5ldyBkYXRldGltZV8xLkRhdGVUaW1lKG5vcm1hbEZyb20ueWVhcigpLCBub3JtYWxGcm9tLm1vbnRoKCksIG5vcm1hbEZyb20uZGF5KCksIHRoaXMuX2ludFJlZmVyZW5jZS5ob3VyKCksIHRoaXMuX2ludFJlZmVyZW5jZS5taW51dGUoKSwgdGhpcy5faW50UmVmZXJlbmNlLnNlY29uZCgpLCB0aGlzLl9pbnRSZWZlcmVuY2UubWlsbGlzZWNvbmQoKSwgdGhpcy5faW50UmVmZXJlbmNlLnpvbmUoKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gc2luY2Ugd2Ugc3RhcnQgY291bnRpbmcgZnJvbSB0aGlzLl9pbnRSZWZlcmVuY2UgZWFjaCBkYXksIHdlIGhhdmUgdG9cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyB0YWtlIGNhcmUgb2YgdGhlIHNob3J0ZXIgaW50ZXJ2YWwgYXQgdGhlIGJvdW5kYXJ5XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVtYWluZGVyID0gTWF0aC5mbG9vcigoODY0MDAwMDApICUgdGhpcy5faW50SW50ZXJ2YWwuYW1vdW50KCkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChhcHByb3guZ3JlYXRlclRoYW4obm9ybWFsRnJvbSkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gdG9kb1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgaWYgKi9cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGFwcHJveC5zdWJMb2NhbChyZW1haW5kZXIsIGJhc2ljc18xLlRpbWVVbml0Lk1pbGxpc2Vjb25kKS5ncmVhdGVyVGhhbihub3JtYWxGcm9tKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gbm9ybWFsRnJvbSBsaWVzIG91dHNpZGUgdGhlIGJvdW5kYXJ5IHBlcmlvZCBiZWZvcmUgdGhlIHJlZmVyZW5jZSBkYXRlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcHByb3ggPSBhcHByb3guc3ViTG9jYWwoMSwgYmFzaWNzXzEuVGltZVVuaXQuRGF5KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGFwcHJveC5hZGRMb2NhbCgxLCBiYXNpY3NfMS5UaW1lVW5pdC5EYXkpLnN1YkxvY2FsKHJlbWFpbmRlciwgYmFzaWNzXzEuVGltZVVuaXQuTWlsbGlzZWNvbmQpLmxlc3NFcXVhbChub3JtYWxGcm9tKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gbm9ybWFsRnJvbSBsaWVzIGluIHRoZSBib3VuZGFyeSBwZXJpb2QsIG1vdmUgdG8gdGhlIG5leHQgZGF5XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcHByb3ggPSBhcHByb3guYWRkTG9jYWwoMSwgYmFzaWNzXzEuVGltZVVuaXQuRGF5KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBvcHRpbWl6YXRpb246IGJpbmFyeSBzZWFyY2hcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbWF4ID0gTWF0aC5mbG9vcigoODY0MDAwMDApIC8gdGhpcy5faW50SW50ZXJ2YWwuYW1vdW50KCkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGltaW4gPSAwO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWxlIChpbWF4ID49IGltaW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gY2FsY3VsYXRlIHRoZSBtaWRwb2ludCBmb3Igcm91Z2hseSBlcXVhbCBwYXJ0aXRpb25cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW1pZCA9IE1hdGguZmxvb3IoKGltaW4gKyBpbWF4KSAvIDIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcHByb3gyID0gYXBwcm94LmFkZExvY2FsKGltaWQgKiB0aGlzLl9pbnRJbnRlcnZhbC5hbW91bnQoKSwgYmFzaWNzXzEuVGltZVVuaXQuTWlsbGlzZWNvbmQpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcHByb3hNaW4gPSBhcHByb3gyLnN1YkxvY2FsKHRoaXMuX2ludEludGVydmFsLmFtb3VudCgpLCBiYXNpY3NfMS5UaW1lVW5pdC5NaWxsaXNlY29uZCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChhcHByb3gyLmdyZWF0ZXJUaGFuKG5vcm1hbEZyb20pICYmIGFwcHJveE1pbi5sZXNzRXF1YWwobm9ybWFsRnJvbSkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFwcHJveCA9IGFwcHJveDI7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbHNlIGlmIChhcHByb3gyLmxlc3NFcXVhbChub3JtYWxGcm9tKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gY2hhbmdlIG1pbiBpbmRleCB0byBzZWFyY2ggdXBwZXIgc3ViYXJyYXlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGltaW4gPSBpbWlkICsgMTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGNoYW5nZSBtYXggaW5kZXggdG8gc2VhcmNoIGxvd2VyIHN1YmFycmF5XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbWF4ID0gaW1pZCAtIDE7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgY2FzZSBiYXNpY3NfMS5UaW1lVW5pdC5TZWNvbmQ6XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy5faW50SW50ZXJ2YWwuYW1vdW50KCkgPCA2MCAmJiAoNjAgJSB0aGlzLl9pbnRJbnRlcnZhbC5hbW91bnQoKSkgPT09IDApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBvcHRpbWl6YXRpb246IHNhbWUgc2Vjb25kIGVhY2ggbWludXRlLCBzbyBqdXN0IHRha2UgdGhlIGZyb21EYXRlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gbWludXMgb25lIG1pbnV0ZSB3aXRoIHRoZSB0aGlzLl9pbnRSZWZlcmVuY2Ugc2Vjb25kc1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFwcHJveCA9IG5ldyBkYXRldGltZV8xLkRhdGVUaW1lKG5vcm1hbEZyb20ueWVhcigpLCBub3JtYWxGcm9tLm1vbnRoKCksIG5vcm1hbEZyb20uZGF5KCksIG5vcm1hbEZyb20uaG91cigpLCBub3JtYWxGcm9tLm1pbnV0ZSgpLCB0aGlzLl9pbnRSZWZlcmVuY2Uuc2Vjb25kKCksIHRoaXMuX2ludFJlZmVyZW5jZS5taWxsaXNlY29uZCgpLCB0aGlzLl9pbnRSZWZlcmVuY2Uuem9uZSgpKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuc3ViTG9jYWwoMSwgYmFzaWNzXzEuVGltZVVuaXQuTWludXRlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHBlciBjb25zdHJ1Y3RvciBhc3NlcnQsIHRoZSBzZWNvbmRzIGFyZSBsZXNzIHRoYW4gYSBkYXksIHNvIGp1c3QgZ28gdGhlIGZyb21EYXRlIHJlZmVyZW5jZS1vZi1kYXlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcHByb3ggPSBuZXcgZGF0ZXRpbWVfMS5EYXRlVGltZShub3JtYWxGcm9tLnllYXIoKSwgbm9ybWFsRnJvbS5tb250aCgpLCBub3JtYWxGcm9tLmRheSgpLCB0aGlzLl9pbnRSZWZlcmVuY2UuaG91cigpLCB0aGlzLl9pbnRSZWZlcmVuY2UubWludXRlKCksIHRoaXMuX2ludFJlZmVyZW5jZS5zZWNvbmQoKSwgdGhpcy5faW50UmVmZXJlbmNlLm1pbGxpc2Vjb25kKCksIHRoaXMuX2ludFJlZmVyZW5jZS56b25lKCkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHNpbmNlIHdlIHN0YXJ0IGNvdW50aW5nIGZyb20gdGhpcy5faW50UmVmZXJlbmNlIGVhY2ggZGF5LCB3ZSBoYXZlIHRvIHRha2VcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBhcmUgb2YgdGhlIHNob3J0ZXIgaW50ZXJ2YWwgYXQgdGhlIGJvdW5kYXJ5XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVtYWluZGVyID0gTWF0aC5mbG9vcigoODY0MDApICUgdGhpcy5faW50SW50ZXJ2YWwuYW1vdW50KCkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChhcHByb3guZ3JlYXRlclRoYW4obm9ybWFsRnJvbSkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGFwcHJveC5zdWJMb2NhbChyZW1haW5kZXIsIGJhc2ljc18xLlRpbWVVbml0LlNlY29uZCkuZ3JlYXRlclRoYW4obm9ybWFsRnJvbSkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIG5vcm1hbEZyb20gbGllcyBvdXRzaWRlIHRoZSBib3VuZGFyeSBwZXJpb2QgYmVmb3JlIHRoZSByZWZlcmVuY2UgZGF0ZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXBwcm94ID0gYXBwcm94LnN1YkxvY2FsKDEsIGJhc2ljc18xLlRpbWVVbml0LkRheSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChhcHByb3guYWRkTG9jYWwoMSwgYmFzaWNzXzEuVGltZVVuaXQuRGF5KS5zdWJMb2NhbChyZW1haW5kZXIsIGJhc2ljc18xLlRpbWVVbml0LlNlY29uZCkubGVzc0VxdWFsKG5vcm1hbEZyb20pKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBub3JtYWxGcm9tIGxpZXMgaW4gdGhlIGJvdW5kYXJ5IHBlcmlvZCwgbW92ZSB0byB0aGUgbmV4dCBkYXlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFwcHJveCA9IGFwcHJveC5hZGRMb2NhbCgxLCBiYXNpY3NfMS5UaW1lVW5pdC5EYXkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIG9wdGltaXphdGlvbjogYmluYXJ5IHNlYXJjaFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGltYXggPSBNYXRoLmZsb29yKCg4NjQwMCkgLyB0aGlzLl9pbnRJbnRlcnZhbC5hbW91bnQoKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaW1pbiA9IDA7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgd2hpbGUgKGltYXggPj0gaW1pbikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBjYWxjdWxhdGUgdGhlIG1pZHBvaW50IGZvciByb3VnaGx5IGVxdWFsIHBhcnRpdGlvblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbWlkID0gTWF0aC5mbG9vcigoaW1pbiArIGltYXgpIC8gMik7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFwcHJveDIgPSBhcHByb3guYWRkTG9jYWwoaW1pZCAqIHRoaXMuX2ludEludGVydmFsLmFtb3VudCgpLCBiYXNpY3NfMS5UaW1lVW5pdC5TZWNvbmQpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcHByb3hNaW4gPSBhcHByb3gyLnN1YkxvY2FsKHRoaXMuX2ludEludGVydmFsLmFtb3VudCgpLCBiYXNpY3NfMS5UaW1lVW5pdC5TZWNvbmQpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoYXBwcm94Mi5ncmVhdGVyVGhhbihub3JtYWxGcm9tKSAmJiBhcHByb3hNaW4ubGVzc0VxdWFsKG5vcm1hbEZyb20pKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcHByb3ggPSBhcHByb3gyO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSBpZiAoYXBwcm94Mi5sZXNzRXF1YWwobm9ybWFsRnJvbSkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGNoYW5nZSBtaW4gaW5kZXggdG8gc2VhcmNoIHVwcGVyIHN1YmFycmF5XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbWluID0gaW1pZCArIDE7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBjaGFuZ2UgbWF4IGluZGV4IHRvIHNlYXJjaCBsb3dlciBzdWJhcnJheVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW1heCA9IGltaWQgLSAxO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgIGNhc2UgYmFzaWNzXzEuVGltZVVuaXQuTWludXRlOlxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMuX2ludEludGVydmFsLmFtb3VudCgpIDwgNjAgJiYgKDYwICUgdGhpcy5faW50SW50ZXJ2YWwuYW1vdW50KCkpID09PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gb3B0aW1pemF0aW9uOiBzYW1lIGhvdXIgdGhpcy5faW50UmVmZXJlbmNlYXJ5IGVhY2ggdGltZSwgc28ganVzdCB0YWtlIHRoZSBmcm9tRGF0ZSBtaW51cyBvbmUgaG91clxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHdpdGggdGhlIHRoaXMuX2ludFJlZmVyZW5jZSBtaW51dGVzLCBzZWNvbmRzXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYXBwcm94ID0gbmV3IGRhdGV0aW1lXzEuRGF0ZVRpbWUobm9ybWFsRnJvbS55ZWFyKCksIG5vcm1hbEZyb20ubW9udGgoKSwgbm9ybWFsRnJvbS5kYXkoKSwgbm9ybWFsRnJvbS5ob3VyKCksIHRoaXMuX2ludFJlZmVyZW5jZS5taW51dGUoKSwgdGhpcy5faW50UmVmZXJlbmNlLnNlY29uZCgpLCB0aGlzLl9pbnRSZWZlcmVuY2UubWlsbGlzZWNvbmQoKSwgdGhpcy5faW50UmVmZXJlbmNlLnpvbmUoKSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLnN1YkxvY2FsKDEsIGJhc2ljc18xLlRpbWVVbml0LkhvdXIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gcGVyIGNvbnN0cnVjdG9yIGFzc2VydCwgdGhlIHNlY29uZHMgZml0IGluIGEgZGF5LCBzbyBqdXN0IGdvIHRoZSBmcm9tRGF0ZSBwcmV2aW91cyBkYXlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcHByb3ggPSBuZXcgZGF0ZXRpbWVfMS5EYXRlVGltZShub3JtYWxGcm9tLnllYXIoKSwgbm9ybWFsRnJvbS5tb250aCgpLCBub3JtYWxGcm9tLmRheSgpLCB0aGlzLl9pbnRSZWZlcmVuY2UuaG91cigpLCB0aGlzLl9pbnRSZWZlcmVuY2UubWludXRlKCksIHRoaXMuX2ludFJlZmVyZW5jZS5zZWNvbmQoKSwgdGhpcy5faW50UmVmZXJlbmNlLm1pbGxpc2Vjb25kKCksIHRoaXMuX2ludFJlZmVyZW5jZS56b25lKCkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHNpbmNlIHdlIHN0YXJ0IGNvdW50aW5nIGZyb20gdGhpcy5faW50UmVmZXJlbmNlIGVhY2ggZGF5LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHdlIGhhdmUgdG8gdGFrZSBjYXJlIG9mIHRoZSBzaG9ydGVyIGludGVydmFsIGF0IHRoZSBib3VuZGFyeVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbWFpbmRlciA9IE1hdGguZmxvb3IoKDI0ICogNjApICUgdGhpcy5faW50SW50ZXJ2YWwuYW1vdW50KCkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChhcHByb3guZ3JlYXRlclRoYW4obm9ybWFsRnJvbSkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGFwcHJveC5zdWJMb2NhbChyZW1haW5kZXIsIGJhc2ljc18xLlRpbWVVbml0Lk1pbnV0ZSkuZ3JlYXRlclRoYW4obm9ybWFsRnJvbSkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIG5vcm1hbEZyb20gbGllcyBvdXRzaWRlIHRoZSBib3VuZGFyeSBwZXJpb2QgYmVmb3JlIHRoZSByZWZlcmVuY2UgZGF0ZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXBwcm94ID0gYXBwcm94LnN1YkxvY2FsKDEsIGJhc2ljc18xLlRpbWVVbml0LkRheSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChhcHByb3guYWRkTG9jYWwoMSwgYmFzaWNzXzEuVGltZVVuaXQuRGF5KS5zdWJMb2NhbChyZW1haW5kZXIsIGJhc2ljc18xLlRpbWVVbml0Lk1pbnV0ZSkubGVzc0VxdWFsKG5vcm1hbEZyb20pKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBub3JtYWxGcm9tIGxpZXMgaW4gdGhlIGJvdW5kYXJ5IHBlcmlvZCwgbW92ZSB0byB0aGUgbmV4dCBkYXlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFwcHJveCA9IGFwcHJveC5hZGRMb2NhbCgxLCBiYXNpY3NfMS5UaW1lVW5pdC5EYXkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgIGNhc2UgYmFzaWNzXzEuVGltZVVuaXQuSG91cjpcbiAgICAgICAgICAgICAgICAgICAgICAgIGFwcHJveCA9IG5ldyBkYXRldGltZV8xLkRhdGVUaW1lKG5vcm1hbEZyb20ueWVhcigpLCBub3JtYWxGcm9tLm1vbnRoKCksIG5vcm1hbEZyb20uZGF5KCksIHRoaXMuX2ludFJlZmVyZW5jZS5ob3VyKCksIHRoaXMuX2ludFJlZmVyZW5jZS5taW51dGUoKSwgdGhpcy5faW50UmVmZXJlbmNlLnNlY29uZCgpLCB0aGlzLl9pbnRSZWZlcmVuY2UubWlsbGlzZWNvbmQoKSwgdGhpcy5faW50UmVmZXJlbmNlLnpvbmUoKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBzaW5jZSB3ZSBzdGFydCBjb3VudGluZyBmcm9tIHRoaXMuX2ludFJlZmVyZW5jZSBlYWNoIGRheSxcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHdlIGhhdmUgdG8gdGFrZSBjYXJlIG9mIHRoZSBzaG9ydGVyIGludGVydmFsIGF0IHRoZSBib3VuZGFyeVxuICAgICAgICAgICAgICAgICAgICAgICAgcmVtYWluZGVyID0gTWF0aC5mbG9vcigyNCAlIHRoaXMuX2ludEludGVydmFsLmFtb3VudCgpKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChhcHByb3guZ3JlYXRlclRoYW4obm9ybWFsRnJvbSkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoYXBwcm94LnN1YkxvY2FsKHJlbWFpbmRlciwgYmFzaWNzXzEuVGltZVVuaXQuSG91cikuZ3JlYXRlclRoYW4obm9ybWFsRnJvbSkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gbm9ybWFsRnJvbSBsaWVzIG91dHNpZGUgdGhlIGJvdW5kYXJ5IHBlcmlvZCBiZWZvcmUgdGhlIHJlZmVyZW5jZSBkYXRlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFwcHJveCA9IGFwcHJveC5zdWJMb2NhbCgxLCBiYXNpY3NfMS5UaW1lVW5pdC5EYXkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChhcHByb3guYWRkTG9jYWwoMSwgYmFzaWNzXzEuVGltZVVuaXQuRGF5KS5zdWJMb2NhbChyZW1haW5kZXIsIGJhc2ljc18xLlRpbWVVbml0LkhvdXIpLmxlc3NFcXVhbChub3JtYWxGcm9tKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBub3JtYWxGcm9tIGxpZXMgaW4gdGhlIGJvdW5kYXJ5IHBlcmlvZCwgbW92ZSB0byB0aGUgbmV4dCBkYXlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXBwcm94ID0gYXBwcm94LmFkZExvY2FsKDEsIGJhc2ljc18xLlRpbWVVbml0LkRheSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgIGNhc2UgYmFzaWNzXzEuVGltZVVuaXQuRGF5OlxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gd2UgZG9uJ3QgaGF2ZSBsZWFwIGRheXMsIHNvIHdlIGNhbiBhcHByb3hpbWF0ZSBieSBjYWxjdWxhdGluZyB3aXRoIFVUQyB0aW1lc3RhbXBzXG4gICAgICAgICAgICAgICAgICAgICAgICBkaWZmID0gbm9ybWFsRnJvbS5kaWZmKHRoaXMuX2ludFJlZmVyZW5jZSkuaG91cnMoKSAvIDI0O1xuICAgICAgICAgICAgICAgICAgICAgICAgcGVyaW9kcyA9IE1hdGguZmxvb3IoZGlmZiAvIHRoaXMuX2ludEludGVydmFsLmFtb3VudCgpKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGFwcHJveCA9IHRoaXMuX2ludFJlZmVyZW5jZS5hZGRMb2NhbChwZXJpb2RzICogdGhpcy5faW50SW50ZXJ2YWwuYW1vdW50KCksIHRoaXMuX2ludEludGVydmFsLnVuaXQoKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgY2FzZSBiYXNpY3NfMS5UaW1lVW5pdC5Nb250aDpcbiAgICAgICAgICAgICAgICAgICAgICAgIGRpZmYgPSAobm9ybWFsRnJvbS55ZWFyKCkgLSB0aGlzLl9pbnRSZWZlcmVuY2UueWVhcigpKSAqIDEyICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAobm9ybWFsRnJvbS5tb250aCgpIC0gdGhpcy5faW50UmVmZXJlbmNlLm1vbnRoKCkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgcGVyaW9kcyA9IE1hdGguZmxvb3IoZGlmZiAvIHRoaXMuX2ludEludGVydmFsLmFtb3VudCgpKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGFwcHJveCA9IHRoaXMuX2ludFJlZmVyZW5jZS5hZGRMb2NhbCh0aGlzLl9pbnRlcnZhbC5tdWx0aXBseShwZXJpb2RzKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgY2FzZSBiYXNpY3NfMS5UaW1lVW5pdC5ZZWFyOlxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gVGhlIC0xIGJlbG93IGlzIGJlY2F1c2UgdGhlIGRheS1vZi1tb250aCBvZiByZWZlcmVuY2UgZGF0ZSBtYXkgYmUgYWZ0ZXIgdGhlIGRheSBvZiB0aGUgZnJvbURhdGVcbiAgICAgICAgICAgICAgICAgICAgICAgIGRpZmYgPSBub3JtYWxGcm9tLnllYXIoKSAtIHRoaXMuX2ludFJlZmVyZW5jZS55ZWFyKCkgLSAxO1xuICAgICAgICAgICAgICAgICAgICAgICAgcGVyaW9kcyA9IE1hdGguZmxvb3IoZGlmZiAvIHRoaXMuX2ludEludGVydmFsLmFtb3VudCgpKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIG5ld1llYXIgPSB0aGlzLl9pbnRSZWZlcmVuY2UueWVhcigpICsgcGVyaW9kcyAqIHRoaXMuX2ludEludGVydmFsLmFtb3VudCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgYXBwcm94ID0gbmV3IGRhdGV0aW1lXzEuRGF0ZVRpbWUobmV3WWVhciwgdGhpcy5faW50UmVmZXJlbmNlLm1vbnRoKCksIHRoaXMuX2ludFJlZmVyZW5jZS5kYXkoKSwgdGhpcy5faW50UmVmZXJlbmNlLmhvdXIoKSwgdGhpcy5faW50UmVmZXJlbmNlLm1pbnV0ZSgpLCB0aGlzLl9pbnRSZWZlcmVuY2Uuc2Vjb25kKCksIHRoaXMuX2ludFJlZmVyZW5jZS5taWxsaXNlY29uZCgpLCB0aGlzLl9pbnRSZWZlcmVuY2Uuem9uZSgpKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICAgICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIGlmICovXG4gICAgICAgICAgICAgICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRydWUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gKDAsIGVycm9yXzEudGhyb3dFcnJvcikoXCJBc3NlcnRpb25cIiwgXCJVbmtub3duIFRpbWVVbml0XCIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB3aGlsZSAoIWFwcHJveC5ncmVhdGVyVGhhbihub3JtYWxGcm9tKSkge1xuICAgICAgICAgICAgICAgICAgICBhcHByb3ggPSBhcHByb3guYWRkTG9jYWwodGhpcy5faW50SW50ZXJ2YWwuYW1vdW50KCksIHRoaXMuX2ludEludGVydmFsLnVuaXQoKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLl9jb3JyZWN0RGF5KGFwcHJveCkuY29udmVydChmcm9tRGF0ZS56b25lKCkpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgbmV4dCB0aW1lc3RhbXAgaW4gdGhlIHBlcmlvZC4gVGhlIGdpdmVuIHRpbWVzdGFtcCBtdXN0XG4gICAgICogYmUgYXQgYSBwZXJpb2QgYm91bmRhcnksIG90aGVyd2lzZSB0aGUgYW5zd2VyIGlzIGluY29ycmVjdC5cbiAgICAgKiBUaGlzIGZ1bmN0aW9uIGhhcyBNVUNIIGJldHRlciBwZXJmb3JtYW5jZSB0aGFuIGZpbmRGaXJzdC5cbiAgICAgKiBSZXR1cm5zIHRoZSBkYXRldGltZSBcImNvdW50XCIgdGltZXMgYXdheSBmcm9tIHRoZSBnaXZlbiBkYXRldGltZS5cbiAgICAgKiBAcGFyYW0gcHJldlx0Qm91bmRhcnkgZGF0ZS4gTXVzdCBoYXZlIGEgdGltZSB6b25lIChhbnkgdGltZSB6b25lKSBpZmYgdGhlIHBlcmlvZCByZWZlcmVuY2UgZGF0ZSBoYXMgb25lLlxuICAgICAqIEBwYXJhbSBjb3VudFx0TnVtYmVyIG9mIHBlcmlvZHMgdG8gYWRkLiBPcHRpb25hbC4gTXVzdCBiZSBhbiBpbnRlZ2VyIG51bWJlciwgbWF5IGJlIHBvc2l0aXZlIG9yIG5lZ2F0aXZlLCBkZWZhdWx0IDFcbiAgICAgKiBAcmV0dXJuIChwcmV2ICsgY291bnQgKiBwZXJpb2QpLCBpbiB0aGUgc2FtZSB0aW1lem9uZSBhcyBwcmV2LlxuICAgICAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5QcmV2IGlmIHByZXYgaXMgdW5kZWZpbmVkXG4gICAgICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LkNvdW50IGlmIGNvdW50IGlzIG5vdCBhbiBpbnRlZ2VyIG51bWJlclxuICAgICAqL1xuICAgIFBlcmlvZC5wcm90b3R5cGUuZmluZE5leHQgPSBmdW5jdGlvbiAocHJldiwgY291bnQpIHtcbiAgICAgICAgaWYgKGNvdW50ID09PSB2b2lkIDApIHsgY291bnQgPSAxOyB9XG4gICAgICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KSghIXByZXYsIFwiQXJndW1lbnQuUHJldlwiLCBcIlByZXYgbXVzdCBiZSBnaXZlblwiKTtcbiAgICAgICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKCEhdGhpcy5faW50UmVmZXJlbmNlLnpvbmUoKSA9PT0gISFwcmV2LnpvbmUoKSwgXCJVbmF3YXJlVG9Bd2FyZUNvbnZlcnNpb25cIiwgXCJUaGUgZnJvbURhdGUgYW5kIHJlZmVyZW5jZURhdGUgbXVzdCBib3RoIGJlIGF3YXJlIG9yIHVuYXdhcmVcIik7XG4gICAgICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KShOdW1iZXIuaXNJbnRlZ2VyKGNvdW50KSwgXCJBcmd1bWVudC5Db3VudFwiLCBcIkNvdW50IG11c3QgYmUgYW4gaW50ZWdlciBudW1iZXJcIik7XG4gICAgICAgIHZhciBub3JtYWxpemVkUHJldiA9IHRoaXMuX25vcm1hbGl6ZURheShwcmV2LnRvWm9uZSh0aGlzLl9yZWZlcmVuY2Uuem9uZSgpKSk7XG4gICAgICAgIGlmICh0aGlzLl9pbnREc3QgPT09IFBlcmlvZERzdC5SZWd1bGFySW50ZXJ2YWxzKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fY29ycmVjdERheShub3JtYWxpemVkUHJldi5hZGQodGhpcy5faW50SW50ZXJ2YWwuYW1vdW50KCkgKiBjb3VudCwgdGhpcy5faW50SW50ZXJ2YWwudW5pdCgpKSkuY29udmVydChwcmV2LnpvbmUoKSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fY29ycmVjdERheShub3JtYWxpemVkUHJldi5hZGRMb2NhbCh0aGlzLl9pbnRJbnRlcnZhbC5hbW91bnQoKSAqIGNvdW50LCB0aGlzLl9pbnRJbnRlcnZhbC51bml0KCkpKS5jb252ZXJ0KHByZXYuem9uZSgpKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgLyoqXG4gICAgICogVGhlIGxhc3Qgb2NjdXJyZW5jZSBvZiB0aGUgcGVyaW9kIGxlc3MgdGhhblxuICAgICAqIHRoZSBnaXZlbiBkYXRlLiBUaGUgZ2l2ZW4gZGF0ZSBuZWVkIG5vdCBiZSBhdCBhIHBlcmlvZCBib3VuZGFyeS5cbiAgICAgKiBQcmU6IHRoZSBmcm9tZGF0ZSBhbmQgdGhlIHBlcmlvZCByZWZlcmVuY2UgZGF0ZSBtdXN0IGVpdGhlciBib3RoIGhhdmUgdGltZXpvbmVzIG9yIG5vdFxuICAgICAqIEBwYXJhbSBmcm9tRGF0ZTogdGhlIGRhdGUgYmVmb3JlIHdoaWNoIHRvIHJldHVybiB0aGUgbmV4dCBkYXRlXG4gICAgICogQHJldHVybiB0aGUgbGFzdCBkYXRlIG1hdGNoaW5nIHRoZSBwZXJpb2QgYmVmb3JlIGZyb21EYXRlLCBnaXZlblxuICAgICAqICAgICAgICAgaW4gdGhlIHNhbWUgem9uZSBhcyB0aGUgZnJvbURhdGUuXG4gICAgICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLlVuYXdhcmVUb0F3YXJlQ29udmVyc2lvbiBpZiBub3QgYm90aCBgZnJvbWAgYW5kIHRoZSByZWZlcmVuY2UgZGF0ZSBhcmUgYm90aCBhd2FyZSBvciB1bmF3YXJlIG9mIHRpbWUgem9uZVxuICAgICAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Ob3RGb3VuZC5ab25lIGlmIHRoZSBVVEMgdGltZSB6b25lIGRvZXNuJ3QgZXhpc3QgaW4gdGhlIHRpbWUgem9uZSBkYXRhYmFzZVxuICAgICAqL1xuICAgIFBlcmlvZC5wcm90b3R5cGUuZmluZExhc3QgPSBmdW5jdGlvbiAoZnJvbSkge1xuICAgICAgICB2YXIgcmVzdWx0ID0gdGhpcy5maW5kUHJldih0aGlzLmZpbmRGaXJzdChmcm9tKSk7XG4gICAgICAgIGlmIChyZXN1bHQuZXF1YWxzKGZyb20pKSB7XG4gICAgICAgICAgICByZXN1bHQgPSB0aGlzLmZpbmRQcmV2KHJlc3VsdCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIHByZXZpb3VzIHRpbWVzdGFtcCBpbiB0aGUgcGVyaW9kLiBUaGUgZ2l2ZW4gdGltZXN0YW1wIG11c3RcbiAgICAgKiBiZSBhdCBhIHBlcmlvZCBib3VuZGFyeSwgb3RoZXJ3aXNlIHRoZSBhbnN3ZXIgaXMgaW5jb3JyZWN0LlxuICAgICAqIEBwYXJhbSBwcmV2XHRCb3VuZGFyeSBkYXRlLiBNdXN0IGhhdmUgYSB0aW1lIHpvbmUgKGFueSB0aW1lIHpvbmUpIGlmZiB0aGUgcGVyaW9kIHJlZmVyZW5jZSBkYXRlIGhhcyBvbmUuXG4gICAgICogQHBhcmFtIGNvdW50XHROdW1iZXIgb2YgcGVyaW9kcyB0byBzdWJ0cmFjdC4gT3B0aW9uYWwuIE11c3QgYmUgYW4gaW50ZWdlciBudW1iZXIsIG1heSBiZSBuZWdhdGl2ZS5cbiAgICAgKiBAcmV0dXJuIChuZXh0IC0gY291bnQgKiBwZXJpb2QpLCBpbiB0aGUgc2FtZSB0aW1lem9uZSBhcyBuZXh0LlxuICAgICAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5OZXh0IGlmIHByZXYgaXMgdW5kZWZpbmVkXG4gICAgICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LkNvdW50IGlmIGNvdW50IGlzIG5vdCBhbiBpbnRlZ2VyIG51bWJlclxuICAgICAqL1xuICAgIFBlcmlvZC5wcm90b3R5cGUuZmluZFByZXYgPSBmdW5jdGlvbiAobmV4dCwgY291bnQpIHtcbiAgICAgICAgaWYgKGNvdW50ID09PSB2b2lkIDApIHsgY291bnQgPSAxOyB9XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5maW5kTmV4dChuZXh0LCAtMSAqIGNvdW50KTtcbiAgICAgICAgfVxuICAgICAgICBjYXRjaCAoZSkge1xuICAgICAgICAgICAgaWYgKCgwLCBlcnJvcl8xLmVycm9ySXMpKGUsIFwiQXJndW1lbnQuUHJldlwiKSkge1xuICAgICAgICAgICAgICAgIGUgPSAoMCwgZXJyb3JfMS5lcnJvcikoXCJBcmd1bWVudC5OZXh0XCIsIGUubWVzc2FnZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aHJvdyBlO1xuICAgICAgICB9XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBDaGVja3Mgd2hldGhlciB0aGUgZ2l2ZW4gZGF0ZSBpcyBvbiBhIHBlcmlvZCBib3VuZGFyeVxuICAgICAqIChleHBlbnNpdmUhKVxuICAgICAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5VbmF3YXJlVG9Bd2FyZUNvbnZlcnNpb24gaWYgbm90IGJvdGggYG9jY3VycmVuY2VgIGFuZCB0aGUgcmVmZXJlbmNlIGRhdGUgYXJlIGJvdGggYXdhcmUgb3IgdW5hd2FyZSBvZiB0aW1lIHpvbmVcbiAgICAgKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuTm90Rm91bmQuWm9uZSBpZiB0aGUgVVRDIHRpbWUgem9uZSBkb2Vzbid0IGV4aXN0IGluIHRoZSB0aW1lIHpvbmUgZGF0YWJhc2VcbiAgICAgKi9cbiAgICBQZXJpb2QucHJvdG90eXBlLmlzQm91bmRhcnkgPSBmdW5jdGlvbiAob2NjdXJyZW5jZSkge1xuICAgICAgICBpZiAoIW9jY3VycmVuY2UpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkoISF0aGlzLl9pbnRSZWZlcmVuY2Uuem9uZSgpID09PSAhIW9jY3VycmVuY2Uuem9uZSgpLCBcIlVuYXdhcmVUb0F3YXJlQ29udmVyc2lvblwiLCBcIlRoZSBvY2N1cnJlbmNlIGFuZCByZWZlcmVuY2VEYXRlIG11c3QgYm90aCBiZSBhd2FyZSBvciB1bmF3YXJlXCIpO1xuICAgICAgICByZXR1cm4gKHRoaXMuZmluZEZpcnN0KG9jY3VycmVuY2Uuc3ViKGR1cmF0aW9uXzEuRHVyYXRpb24ubWlsbGlzZWNvbmRzKDEpKSkuZXF1YWxzKG9jY3VycmVuY2UpKTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFJldHVybnMgdHJ1ZSBpZmYgdGhpcyBwZXJpb2QgaGFzIHRoZSBzYW1lIGVmZmVjdCBhcyB0aGUgZ2l2ZW4gb25lLlxuICAgICAqIGkuZS4gYSBwZXJpb2Qgb2YgMjQgaG91cnMgaXMgZXF1YWwgdG8gb25lIG9mIDEgZGF5IGlmIHRoZXkgaGF2ZSB0aGUgc2FtZSBVVEMgcmVmZXJlbmNlIG1vbWVudFxuICAgICAqIGFuZCBzYW1lIGRzdC5cbiAgICAgKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuVW5hd2FyZVRvQXdhcmVDb252ZXJzaW9uIGlmIG5vdCBib3RoIGBvdGhlciNyZWZlcmVuY2UoKWAgYW5kIHRoZSByZWZlcmVuY2UgZGF0ZSBhcmUgYm90aCBhd2FyZSBvciB1bmF3YXJlXG4gICAgICogb2YgdGltZSB6b25lXG4gICAgICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLk5vdEZvdW5kLlpvbmUgaWYgdGhlIFVUQyB0aW1lIHpvbmUgZG9lc24ndCBleGlzdCBpbiB0aGUgdGltZSB6b25lIGRhdGFiYXNlXG4gICAgICovXG4gICAgUGVyaW9kLnByb3RvdHlwZS5lcXVhbHMgPSBmdW5jdGlvbiAob3RoZXIpIHtcbiAgICAgICAgLy8gbm90ZSB3ZSB0YWtlIHRoZSBub24tbm9ybWFsaXplZCBfcmVmZXJlbmNlIGJlY2F1c2UgdGhpcyBoYXMgYW4gaW5mbHVlbmNlIG9uIHRoZSBvdXRjb21lXG4gICAgICAgIGlmICghdGhpcy5pc0JvdW5kYXJ5KG90aGVyLl9yZWZlcmVuY2UpIHx8ICF0aGlzLl9pbnRJbnRlcnZhbC5lcXVhbHMob3RoZXIuX2ludEludGVydmFsKSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIHZhciByZWZab25lID0gdGhpcy5fcmVmZXJlbmNlLnpvbmUoKTtcbiAgICAgICAgdmFyIG90aGVyWm9uZSA9IG90aGVyLl9yZWZlcmVuY2Uuem9uZSgpO1xuICAgICAgICB2YXIgdGhpc0lzUmVndWxhciA9ICh0aGlzLl9pbnREc3QgPT09IFBlcmlvZERzdC5SZWd1bGFySW50ZXJ2YWxzIHx8ICFyZWZab25lIHx8IHJlZlpvbmUuaXNVdGMoKSk7XG4gICAgICAgIHZhciBvdGhlcklzUmVndWxhciA9IChvdGhlci5faW50RHN0ID09PSBQZXJpb2REc3QuUmVndWxhckludGVydmFscyB8fCAhb3RoZXJab25lIHx8IG90aGVyWm9uZS5pc1V0YygpKTtcbiAgICAgICAgaWYgKHRoaXNJc1JlZ3VsYXIgJiYgb3RoZXJJc1JlZ3VsYXIpIHtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0aGlzLl9pbnREc3QgPT09IG90aGVyLl9pbnREc3QgJiYgcmVmWm9uZSAmJiBvdGhlclpvbmUgJiYgcmVmWm9uZS5lcXVhbHMob3RoZXJab25lKSkge1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0cnVlIGlmZiB0aGlzIHBlcmlvZCB3YXMgY29uc3RydWN0ZWQgd2l0aCBpZGVudGljYWwgYXJndW1lbnRzIHRvIHRoZSBvdGhlciBvbmUuXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgUGVyaW9kLnByb3RvdHlwZS5pZGVudGljYWwgPSBmdW5jdGlvbiAob3RoZXIpIHtcbiAgICAgICAgcmV0dXJuICh0aGlzLl9yZWZlcmVuY2UuaWRlbnRpY2FsKG90aGVyLl9yZWZlcmVuY2UpXG4gICAgICAgICAgICAmJiB0aGlzLl9pbnRlcnZhbC5pZGVudGljYWwob3RoZXIuX2ludGVydmFsKVxuICAgICAgICAgICAgJiYgdGhpcy5fZHN0ID09PSBvdGhlci5fZHN0KTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFJldHVybnMgYW4gSVNPIGR1cmF0aW9uIHN0cmluZyBlLmcuXG4gICAgICogMjAxNC0wMS0wMVQxMjowMDowMC4wMDArMDE6MDAvUDFIXG4gICAgICogMjAxNC0wMS0wMVQxMjowMDowMC4wMDArMDE6MDAvUFQxTSAgIChvbmUgbWludXRlKVxuICAgICAqIDIwMTQtMDEtMDFUMTI6MDA6MDAuMDAwKzAxOjAwL1AxTSAgIChvbmUgbW9udGgpXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgUGVyaW9kLnByb3RvdHlwZS50b0lzb1N0cmluZyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3JlZmVyZW5jZS50b0lzb1N0cmluZygpICsgXCIvXCIgKyB0aGlzLl9pbnRlcnZhbC50b0lzb1N0cmluZygpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogQSBzdHJpbmcgcmVwcmVzZW50YXRpb24gZS5nLlxuICAgICAqIFwiMTAgeWVhcnMsIHJlZmVyZW5jZWluZyBhdCAyMDE0LTAzLTAxVDEyOjAwOjAwIEV1cm9wZS9BbXN0ZXJkYW0sIGtlZXBpbmcgcmVndWxhciBpbnRlcnZhbHNcIi5cbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBQZXJpb2QucHJvdG90eXBlLnRvU3RyaW5nID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgcmVzdWx0ID0gdGhpcy5faW50ZXJ2YWwudG9TdHJpbmcoKSArIFwiLCByZWZlcmVuY2VpbmcgYXQgXCIgKyB0aGlzLl9yZWZlcmVuY2UudG9TdHJpbmcoKTtcbiAgICAgICAgLy8gb25seSBhZGQgdGhlIERTVCBoYW5kbGluZyBpZiBpdCBpcyByZWxldmFudFxuICAgICAgICBpZiAodGhpcy5fZHN0UmVsZXZhbnQoKSkge1xuICAgICAgICAgICAgcmVzdWx0ICs9IFwiLCBrZWVwaW5nIFwiICsgcGVyaW9kRHN0VG9TdHJpbmcodGhpcy5fZHN0KTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH07XG4gICAgLyoqXG4gICAgICogUmV0dXJucyBhIEpTT04tY29tcGF0aWJsZSByZXByZXNlbnRhdGlvbiBvZiB0aGlzIHBlcmlvZFxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIFBlcmlvZC5wcm90b3R5cGUudG9Kc29uID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgcmVmZXJlbmNlOiB0aGlzLnJlZmVyZW5jZSgpLnRvU3RyaW5nKCksXG4gICAgICAgICAgICBkdXJhdGlvbjogdGhpcy5pbnRlcnZhbCgpLnRvU3RyaW5nKCksXG4gICAgICAgICAgICBwZXJpb2REc3Q6IHRoaXMuZHN0KCkgPT09IFBlcmlvZERzdC5SZWd1bGFySW50ZXJ2YWxzID8gXCJyZWd1bGFyXCIgOiBcImxvY2FsXCJcbiAgICAgICAgfTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIENvcnJlY3RzIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gX3JlZmVyZW5jZSBhbmQgX2ludFJlZmVyZW5jZS5cbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBQZXJpb2QucHJvdG90eXBlLl9jb3JyZWN0RGF5ID0gZnVuY3Rpb24gKGQpIHtcbiAgICAgICAgaWYgKHRoaXMuX3JlZmVyZW5jZSAhPT0gdGhpcy5faW50UmVmZXJlbmNlKSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3IGRhdGV0aW1lXzEuRGF0ZVRpbWUoZC55ZWFyKCksIGQubW9udGgoKSwgTWF0aC5taW4oYmFzaWNzLmRheXNJbk1vbnRoKGQueWVhcigpLCBkLm1vbnRoKCkpLCB0aGlzLl9yZWZlcmVuY2UuZGF5KCkpLCBkLmhvdXIoKSwgZC5taW51dGUoKSwgZC5zZWNvbmQoKSwgZC5taWxsaXNlY29uZCgpLCBkLnpvbmUoKSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gZDtcbiAgICAgICAgfVxuICAgIH07XG4gICAgLyoqXG4gICAgICogSWYgdGhpcy5faW50ZXJuYWxVbml0IGluIFtNb250aCwgWWVhcl0sIG5vcm1hbGl6ZXMgdGhlIGRheS1vZi1tb250aFxuICAgICAqIHRvIDw9IDI4LlxuICAgICAqIEByZXR1cm4gYSBuZXcgZGF0ZSBpZiBkaWZmZXJlbnQsIG90aGVyd2lzZSB0aGUgZXhhY3Qgc2FtZSBvYmplY3QgKG5vIGNsb25lISlcbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBQZXJpb2QucHJvdG90eXBlLl9ub3JtYWxpemVEYXkgPSBmdW5jdGlvbiAoZCwgYW55bW9udGgpIHtcbiAgICAgICAgaWYgKGFueW1vbnRoID09PSB2b2lkIDApIHsgYW55bW9udGggPSB0cnVlOyB9XG4gICAgICAgIGlmICgodGhpcy5faW50SW50ZXJ2YWwudW5pdCgpID09PSBiYXNpY3NfMS5UaW1lVW5pdC5Nb250aCAmJiBkLmRheSgpID4gMjgpXG4gICAgICAgICAgICB8fCAodGhpcy5faW50SW50ZXJ2YWwudW5pdCgpID09PSBiYXNpY3NfMS5UaW1lVW5pdC5ZZWFyICYmIChkLm1vbnRoKCkgPT09IDIgfHwgYW55bW9udGgpICYmIGQuZGF5KCkgPiAyOCkpIHtcbiAgICAgICAgICAgIHJldHVybiBuZXcgZGF0ZXRpbWVfMS5EYXRlVGltZShkLnllYXIoKSwgZC5tb250aCgpLCAyOCwgZC5ob3VyKCksIGQubWludXRlKCksIGQuc2Vjb25kKCksIGQubWlsbGlzZWNvbmQoKSwgZC56b25lKCkpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIGQ7IC8vIHNhdmUgb24gdGltZSBieSBub3QgcmV0dXJuaW5nIGEgY2xvbmVcbiAgICAgICAgfVxuICAgIH07XG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0cnVlIGlmIERTVCBoYW5kbGluZyBpcyByZWxldmFudCBmb3IgdXMuXG4gICAgICogKGkuZS4gaWYgdGhlIHJlZmVyZW5jZSB0aW1lIHpvbmUgaGFzIERTVClcbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBQZXJpb2QucHJvdG90eXBlLl9kc3RSZWxldmFudCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHpvbmUgPSB0aGlzLl9yZWZlcmVuY2Uuem9uZSgpO1xuICAgICAgICByZXR1cm4gISEoem9uZVxuICAgICAgICAgICAgJiYgem9uZS5raW5kKCkgPT09IHRpbWV6b25lXzEuVGltZVpvbmVLaW5kLlByb3BlclxuICAgICAgICAgICAgJiYgem9uZS5oYXNEc3QoKSk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBOb3JtYWxpemUgdGhlIHZhbHVlcyB3aGVyZSBwb3NzaWJsZSAtIG5vdCBhbGwgdmFsdWVzXG4gICAgICogYXJlIGNvbnZlcnRpYmxlIGludG8gb25lIGFub3RoZXIuIFdlZWtzIGFyZSBjb252ZXJ0ZWQgdG8gZGF5cy5cbiAgICAgKiBFLmcuIG1vcmUgdGhhbiA2MCBtaW51dGVzIGlzIHRyYW5zZmVycmVkIHRvIGhvdXJzLFxuICAgICAqIGJ1dCBzZWNvbmRzIGNhbm5vdCBiZSB0cmFuc2ZlcnJlZCB0byBtaW51dGVzIGR1ZSB0byBsZWFwIHNlY29uZHMuXG4gICAgICogV2Vla3MgYXJlIGNvbnZlcnRlZCBiYWNrIHRvIGRheXMuXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgUGVyaW9kLnByb3RvdHlwZS5fY2FsY0ludGVybmFsVmFsdWVzID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyBub3JtYWxpemUgYW55IGFib3ZlLXVuaXQgdmFsdWVzXG4gICAgICAgIHZhciBpbnRBbW91bnQgPSB0aGlzLl9pbnRlcnZhbC5hbW91bnQoKTtcbiAgICAgICAgdmFyIGludFVuaXQgPSB0aGlzLl9pbnRlcnZhbC51bml0KCk7XG4gICAgICAgIGlmIChpbnRVbml0ID09PSBiYXNpY3NfMS5UaW1lVW5pdC5NaWxsaXNlY29uZCAmJiBpbnRBbW91bnQgPj0gMTAwMCAmJiBpbnRBbW91bnQgJSAxMDAwID09PSAwKSB7XG4gICAgICAgICAgICAvLyBub3RlIHRoaXMgd29uJ3Qgd29yayBpZiB3ZSBhY2NvdW50IGZvciBsZWFwIHNlY29uZHNcbiAgICAgICAgICAgIGludEFtb3VudCA9IGludEFtb3VudCAvIDEwMDA7XG4gICAgICAgICAgICBpbnRVbml0ID0gYmFzaWNzXzEuVGltZVVuaXQuU2Vjb25kO1xuICAgICAgICB9XG4gICAgICAgIGlmIChpbnRVbml0ID09PSBiYXNpY3NfMS5UaW1lVW5pdC5TZWNvbmQgJiYgaW50QW1vdW50ID49IDYwICYmIGludEFtb3VudCAlIDYwID09PSAwKSB7XG4gICAgICAgICAgICAvLyBub3RlIHRoaXMgd29uJ3Qgd29yayBpZiB3ZSBhY2NvdW50IGZvciBsZWFwIHNlY29uZHNcbiAgICAgICAgICAgIGludEFtb3VudCA9IGludEFtb3VudCAvIDYwO1xuICAgICAgICAgICAgaW50VW5pdCA9IGJhc2ljc18xLlRpbWVVbml0Lk1pbnV0ZTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoaW50VW5pdCA9PT0gYmFzaWNzXzEuVGltZVVuaXQuTWludXRlICYmIGludEFtb3VudCA+PSA2MCAmJiBpbnRBbW91bnQgJSA2MCA9PT0gMCkge1xuICAgICAgICAgICAgaW50QW1vdW50ID0gaW50QW1vdW50IC8gNjA7XG4gICAgICAgICAgICBpbnRVbml0ID0gYmFzaWNzXzEuVGltZVVuaXQuSG91cjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoaW50VW5pdCA9PT0gYmFzaWNzXzEuVGltZVVuaXQuSG91ciAmJiBpbnRBbW91bnQgPj0gMjQgJiYgaW50QW1vdW50ICUgMjQgPT09IDApIHtcbiAgICAgICAgICAgIGludEFtb3VudCA9IGludEFtb3VudCAvIDI0O1xuICAgICAgICAgICAgaW50VW5pdCA9IGJhc2ljc18xLlRpbWVVbml0LkRheTtcbiAgICAgICAgfVxuICAgICAgICAvLyBub3cgcmVtb3ZlIHdlZWtzIHNvIHdlIGhhdmUgb25lIGxlc3MgY2FzZSB0byB3b3JyeSBhYm91dFxuICAgICAgICBpZiAoaW50VW5pdCA9PT0gYmFzaWNzXzEuVGltZVVuaXQuV2Vlaykge1xuICAgICAgICAgICAgaW50QW1vdW50ID0gaW50QW1vdW50ICogNztcbiAgICAgICAgICAgIGludFVuaXQgPSBiYXNpY3NfMS5UaW1lVW5pdC5EYXk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGludFVuaXQgPT09IGJhc2ljc18xLlRpbWVVbml0Lk1vbnRoICYmIGludEFtb3VudCA+PSAxMiAmJiBpbnRBbW91bnQgJSAxMiA9PT0gMCkge1xuICAgICAgICAgICAgaW50QW1vdW50ID0gaW50QW1vdW50IC8gMTI7XG4gICAgICAgICAgICBpbnRVbml0ID0gYmFzaWNzXzEuVGltZVVuaXQuWWVhcjtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLl9pbnRJbnRlcnZhbCA9IG5ldyBkdXJhdGlvbl8xLkR1cmF0aW9uKGludEFtb3VudCwgaW50VW5pdCk7XG4gICAgICAgIC8vIG5vcm1hbGl6ZSBkc3QgaGFuZGxpbmdcbiAgICAgICAgaWYgKHRoaXMuX2RzdFJlbGV2YW50KCkpIHtcbiAgICAgICAgICAgIHRoaXMuX2ludERzdCA9IHRoaXMuX2RzdDtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuX2ludERzdCA9IFBlcmlvZERzdC5SZWd1bGFySW50ZXJ2YWxzO1xuICAgICAgICB9XG4gICAgICAgIC8vIG5vcm1hbGl6ZSByZWZlcmVuY2UgZGF5XG4gICAgICAgIHRoaXMuX2ludFJlZmVyZW5jZSA9IHRoaXMuX25vcm1hbGl6ZURheSh0aGlzLl9yZWZlcmVuY2UsIGZhbHNlKTtcbiAgICB9O1xuICAgIHJldHVybiBQZXJpb2Q7XG59KCkpO1xuZXhwb3J0cy5QZXJpb2QgPSBQZXJpb2Q7XG4vKipcbiAqIFJldHVybnMgdHJ1ZSBpZmYgdGhlIGdpdmVuIGpzb24gdmFsdWUgcmVwcmVzZW50cyBhIHZhbGlkIHBlcmlvZCBKU09OXG4gKiBAcGFyYW0ganNvblxuICogQHRocm93cyBub3RoaW5nXG4gKi9cbmZ1bmN0aW9uIGlzVmFsaWRQZXJpb2RKc29uKGpzb24pIHtcbiAgICBpZiAodHlwZW9mIGpzb24gIT09IFwib2JqZWN0XCIpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBpZiAoanNvbiA9PT0gbnVsbCkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGlmICh0eXBlb2YganNvbi5kdXJhdGlvbiAhPT0gXCJzdHJpbmdcIikge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGlmICh0eXBlb2YganNvbi5wZXJpb2REc3QgIT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBpZiAodHlwZW9mIGpzb24ucmVmZXJlbmNlICE9PSBcInN0cmluZ1wiKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgaWYgKCFbXCJyZWd1bGFyXCIsIFwibG9jYWxcIl0uaW5jbHVkZXMoanNvbi5wZXJpb2REc3QpKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOiBuby11bnVzZWQtZXhwcmVzc2lvblxuICAgICAgICBuZXcgUGVyaW9kKGpzb24pO1xuICAgIH1cbiAgICBjYXRjaCAoX2EpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbn1cbmV4cG9ydHMuaXNWYWxpZFBlcmlvZEpzb24gPSBpc1ZhbGlkUGVyaW9kSnNvbjtcbi8qKlxuICogQ2hlY2tzIGlmIGEgZ2l2ZW4gb2JqZWN0IGlzIG9mIHR5cGUgUGVyaW9kLiBOb3RlIHRoYXQgaXQgZG9lcyBub3Qgd29yayBmb3Igc3ViIGNsYXNzZXMuIEhvd2V2ZXIsIHVzZSB0aGlzIHRvIGJlIHJvYnVzdFxuICogYWdhaW5zdCBkaWZmZXJlbnQgdmVyc2lvbnMgb2YgdGhlIGxpYnJhcnkgaW4gb25lIHByb2Nlc3MgaW5zdGVhZCBvZiBpbnN0YW5jZW9mXG4gKiBAcGFyYW0gdmFsdWUgVmFsdWUgdG8gY2hlY2tcbiAqIEB0aHJvd3Mgbm90aGluZ1xuICovXG5mdW5jdGlvbiBpc1BlcmlvZCh2YWx1ZSkge1xuICAgIHJldHVybiB0eXBlb2YgdmFsdWUgPT09IFwib2JqZWN0XCIgJiYgdmFsdWUgIT09IG51bGwgJiYgdmFsdWUua2luZCA9PT0gXCJQZXJpb2RcIjtcbn1cbmV4cG9ydHMuaXNQZXJpb2QgPSBpc1BlcmlvZDtcbi8qKlxuICogUmV0dXJucyB0aGUgZmlyc3QgdGltZXN0YW1wID49IGBvcHRzLnJlZmVyZW5jZWAgdGhhdCBtYXRjaGVzIHRoZSBnaXZlbiB3ZWVrZGF5IGFuZCB0aW1lLiBVc2VzIHRoZSB0aW1lIHpvbmUgYW5kIERTVCBzZXR0aW5nc1xuICogb2YgdGhlIGdpdmVuIHJlZmVyZW5jZSB0aW1lLlxuICogQHBhcmFtIG9wdHNcbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5Ib3VyIGlmIG9wdHMuaG91ciBvdXQgb2YgcmFuZ2VcbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5NaW51dGUgaWYgb3B0cy5taW51dGUgb3V0IG9mIHJhbmdlXG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuU2Vjb25kIGlmIG9wdHMuc2Vjb25kIG91dCBvZiByYW5nZVxuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50Lk1pbGxpc2Vjb25kIGlmIG9wdHMubWlsbGlzZWNvbmQgb3V0IG9mIHJhbmdlXG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuV2Vla2RheSBpZiBvcHRzLndlZWtkYXkgb3V0IG9mIHJhbmdlXG4gKi9cbmZ1bmN0aW9uIHRpbWVzdGFtcE9uV2Vla1RpbWVHcmVhdGVyVGhhbk9yRXF1YWxUbyhvcHRzKSB7XG4gICAgdmFyIF9hLCBfYiwgX2M7XG4gICAgLy8gdHNsaW50OmRpc2FibGU6IG1heC1saW5lLWxlbmd0aFxuICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KShvcHRzLmhvdXIgPj0gMCAmJiBvcHRzLmhvdXIgPCAyNCwgXCJBcmd1bWVudC5Ib3VyXCIsIFwib3B0cy5ob3VyIHNob3VsZCBiZSB3aXRoaW4gWzAuLjIzXVwiKTtcbiAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkob3B0cy5taW51dGUgPT09IHVuZGVmaW5lZCB8fCAob3B0cy5taW51dGUgPj0gMCAmJiBvcHRzLm1pbnV0ZSA8IDYwICYmIE51bWJlci5pc0ludGVnZXIob3B0cy5taW51dGUpKSwgXCJBcmd1bWVudC5NaW51dGVcIiwgXCJvcHRzLm1pbnV0ZSBzaG91bGQgYmUgd2l0aGluIFswLi41OV1cIik7XG4gICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKG9wdHMuc2Vjb25kID09PSB1bmRlZmluZWQgfHwgKG9wdHMuc2Vjb25kID49IDAgJiYgb3B0cy5zZWNvbmQgPCA2MCAmJiBOdW1iZXIuaXNJbnRlZ2VyKG9wdHMuc2Vjb25kKSksIFwiQXJndW1lbnQuU2Vjb25kXCIsIFwib3B0cy5zZWNvbmQgc2hvdWxkIGJlIHdpdGhpbiBbMC4uNTldXCIpO1xuICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KShvcHRzLm1pbGxpc2Vjb25kID09PSB1bmRlZmluZWQgfHwgKG9wdHMubWlsbGlzZWNvbmQgPj0gMCAmJiBvcHRzLm1pbGxpc2Vjb25kIDwgMTAwMCAmJiBOdW1iZXIuaXNJbnRlZ2VyKG9wdHMubWlsbGlzZWNvbmQpKSwgXCJBcmd1bWVudC5NaWxsaXNlY29uZFwiLCBcIm9wdHMubWlsbGlzZWNvbmQgc2hvdWxkIGJlIHdpdGhpbiBbMC45OTldXCIpO1xuICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KShvcHRzLndlZWtkYXkgPj0gMCAmJiBvcHRzLndlZWtkYXkgPCA3LCBcIkFyZ3VtZW50LldlZWtkYXlcIiwgXCJvcHRzLndlZWtkYXkgc2hvdWxkIGJlIHdpdGhpbiBbMC4uNl1cIik7XG4gICAgLy8gdHNsaW50OmVuYWJsZTogbWF4LWxpbmUtbGVuZ3RoXG4gICAgdmFyIG1pZG5pZ2h0ID0gb3B0cy5yZWZlcmVuY2Uuc3RhcnRPZkRheSgpO1xuICAgIHdoaWxlIChtaWRuaWdodC53ZWVrRGF5KCkgIT09IG9wdHMud2Vla2RheSkge1xuICAgICAgICBtaWRuaWdodCA9IG1pZG5pZ2h0LmFkZExvY2FsKCgwLCBkdXJhdGlvbl8xLmRheXMpKDEpKTtcbiAgICB9XG4gICAgdmFyIGR0ID0gbmV3IGRhdGV0aW1lXzEuRGF0ZVRpbWUobWlkbmlnaHQueWVhcigpLCBtaWRuaWdodC5tb250aCgpLCBtaWRuaWdodC5kYXkoKSwgb3B0cy5ob3VyLCAoX2EgPSBvcHRzLm1pbnV0ZSkgIT09IG51bGwgJiYgX2EgIT09IHZvaWQgMCA/IF9hIDogMCwgKF9iID0gb3B0cy5zZWNvbmQpICE9PSBudWxsICYmIF9iICE9PSB2b2lkIDAgPyBfYiA6IDAsIChfYyA9IG9wdHMubWlsbGlzZWNvbmQpICE9PSBudWxsICYmIF9jICE9PSB2b2lkIDAgPyBfYyA6IDAsIG9wdHMucmVmZXJlbmNlLnpvbmUoKSk7XG4gICAgaWYgKGR0IDwgb3B0cy5yZWZlcmVuY2UpIHtcbiAgICAgICAgLy8gd2UndmUgc3RhcnRlZCBvdXQgb24gdGhlIGNvcnJlY3Qgd2Vla2RheSBhbmQgdGhlIHJlZmVyZW5jZSB0aW1lc3RhbXAgd2FzIGdyZWF0ZXIgdGhhbiB0aGUgZ2l2ZW4gdGltZSwgbmVlZCB0byBza2lwIGEgd2Vla1xuICAgICAgICByZXR1cm4gZHQuYWRkTG9jYWwoKDAsIGR1cmF0aW9uXzEuZGF5cykoNykpO1xuICAgIH1cbiAgICByZXR1cm4gZHQ7XG59XG5leHBvcnRzLnRpbWVzdGFtcE9uV2Vla1RpbWVHcmVhdGVyVGhhbk9yRXF1YWxUbyA9IHRpbWVzdGFtcE9uV2Vla1RpbWVHcmVhdGVyVGhhbk9yRXF1YWxUbztcbi8qKlxuICogUmV0dXJucyB0aGUgZmlyc3QgdGltZXN0YW1wIDwgYG9wdHMucmVmZXJlbmNlYCB0aGF0IG1hdGNoZXMgdGhlIGdpdmVuIHdlZWtkYXkgYW5kIHRpbWUuIFVzZXMgdGhlIHRpbWUgem9uZSBhbmQgRFNUIHNldHRpbmdzXG4gKiBvZiB0aGUgZ2l2ZW4gcmVmZXJlbmNlIHRpbWUuXG4gKiBAcGFyYW0gb3B0c1xuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LkhvdXIgaWYgb3B0cy5ob3VyIG91dCBvZiByYW5nZVxuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50Lk1pbnV0ZSBpZiBvcHRzLm1pbnV0ZSBvdXQgb2YgcmFuZ2VcbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5TZWNvbmQgaWYgb3B0cy5zZWNvbmQgb3V0IG9mIHJhbmdlXG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuTWlsbGlzZWNvbmQgaWYgb3B0cy5taWxsaXNlY29uZCBvdXQgb2YgcmFuZ2VcbiAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5XZWVrZGF5IGlmIG9wdHMud2Vla2RheSBvdXQgb2YgcmFuZ2VcbiAqL1xuZnVuY3Rpb24gdGltZXN0YW1wT25XZWVrVGltZUxlc3NUaGFuKG9wdHMpIHtcbiAgICB2YXIgX2EsIF9iLCBfYztcbiAgICAvLyB0c2xpbnQ6ZGlzYWJsZTogbWF4LWxpbmUtbGVuZ3RoXG4gICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKG9wdHMuaG91ciA+PSAwICYmIG9wdHMuaG91ciA8IDI0LCBcIkFyZ3VtZW50LkhvdXJcIiwgXCJvcHRzLmhvdXIgc2hvdWxkIGJlIHdpdGhpbiBbMC4uMjNdXCIpO1xuICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KShvcHRzLm1pbnV0ZSA9PT0gdW5kZWZpbmVkIHx8IChvcHRzLm1pbnV0ZSA+PSAwICYmIG9wdHMubWludXRlIDwgNjAgJiYgTnVtYmVyLmlzSW50ZWdlcihvcHRzLm1pbnV0ZSkpLCBcIkFyZ3VtZW50Lk1pbnV0ZVwiLCBcIm9wdHMubWludXRlIHNob3VsZCBiZSB3aXRoaW4gWzAuLjU5XVwiKTtcbiAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkob3B0cy5zZWNvbmQgPT09IHVuZGVmaW5lZCB8fCAob3B0cy5zZWNvbmQgPj0gMCAmJiBvcHRzLnNlY29uZCA8IDYwICYmIE51bWJlci5pc0ludGVnZXIob3B0cy5zZWNvbmQpKSwgXCJBcmd1bWVudC5TZWNvbmRcIiwgXCJvcHRzLnNlY29uZCBzaG91bGQgYmUgd2l0aGluIFswLi41OV1cIik7XG4gICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKG9wdHMubWlsbGlzZWNvbmQgPT09IHVuZGVmaW5lZCB8fCAob3B0cy5taWxsaXNlY29uZCA+PSAwICYmIG9wdHMubWlsbGlzZWNvbmQgPCAxMDAwICYmIE51bWJlci5pc0ludGVnZXIob3B0cy5taWxsaXNlY29uZCkpLCBcIkFyZ3VtZW50Lk1pbGxpc2Vjb25kXCIsIFwib3B0cy5taWxsaXNlY29uZCBzaG91bGQgYmUgd2l0aGluIFswLjk5OV1cIik7XG4gICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKG9wdHMud2Vla2RheSA+PSAwICYmIG9wdHMud2Vla2RheSA8IDcsIFwiQXJndW1lbnQuV2Vla2RheVwiLCBcIm9wdHMud2Vla2RheSBzaG91bGQgYmUgd2l0aGluIFswLi42XVwiKTtcbiAgICAvLyB0c2xpbnQ6ZW5hYmxlOiBtYXgtbGluZS1sZW5ndGhcbiAgICB2YXIgbWlkbmlnaHQgPSBvcHRzLnJlZmVyZW5jZS5zdGFydE9mRGF5KCkuYWRkTG9jYWwoKDAsIGR1cmF0aW9uXzEuZGF5cykoMSkpO1xuICAgIHdoaWxlIChtaWRuaWdodC53ZWVrRGF5KCkgIT09IG9wdHMud2Vla2RheSkge1xuICAgICAgICBtaWRuaWdodCA9IG1pZG5pZ2h0LnN1YkxvY2FsKCgwLCBkdXJhdGlvbl8xLmRheXMpKDEpKTtcbiAgICB9XG4gICAgdmFyIGR0ID0gbmV3IGRhdGV0aW1lXzEuRGF0ZVRpbWUobWlkbmlnaHQueWVhcigpLCBtaWRuaWdodC5tb250aCgpLCBtaWRuaWdodC5kYXkoKSwgb3B0cy5ob3VyLCAoX2EgPSBvcHRzLm1pbnV0ZSkgIT09IG51bGwgJiYgX2EgIT09IHZvaWQgMCA/IF9hIDogMCwgKF9iID0gb3B0cy5zZWNvbmQpICE9PSBudWxsICYmIF9iICE9PSB2b2lkIDAgPyBfYiA6IDAsIChfYyA9IG9wdHMubWlsbGlzZWNvbmQpICE9PSBudWxsICYmIF9jICE9PSB2b2lkIDAgPyBfYyA6IDAsIG9wdHMucmVmZXJlbmNlLnpvbmUoKSk7XG4gICAgaWYgKGR0ID49IG9wdHMucmVmZXJlbmNlKSB7XG4gICAgICAgIC8vIHdlJ3ZlIHN0YXJ0ZWQgb3V0IG9uIHRoZSBjb3JyZWN0IHdlZWtkYXkgYW5kIHRoZSByZWZlcmVuY2UgdGltZXN0YW1wIHdhcyBsZXNzIHRoYW4gdGhlIGdpdmVuIHRpbWUsIG5lZWQgdG8gc2tpcCBhIHdlZWtcbiAgICAgICAgcmV0dXJuIGR0LnN1YkxvY2FsKCgwLCBkdXJhdGlvbl8xLmRheXMpKDcpKTtcbiAgICB9XG4gICAgcmV0dXJuIGR0O1xufVxuZXhwb3J0cy50aW1lc3RhbXBPbldlZWtUaW1lTGVzc1RoYW4gPSB0aW1lc3RhbXBPbldlZWtUaW1lTGVzc1RoYW47XG4vLyMgc291cmNlTWFwcGluZ1VSTD1wZXJpb2QuanMubWFwIiwiLyoqXG4gKiBDb3B5cmlnaHQoYykgMjAxNCBBQkIgU3dpdHplcmxhbmQgTHRkLlxuICpcbiAqIFN0cmluZyB1dGlsaXR5IGZ1bmN0aW9uc1xuICovXG5cInVzZSBzdHJpY3RcIjtcbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIl9fZXNNb2R1bGVcIiwgeyB2YWx1ZTogdHJ1ZSB9KTtcbmV4cG9ydHMucGFkUmlnaHQgPSBleHBvcnRzLnBhZExlZnQgPSB2b2lkIDA7XG52YXIgYXNzZXJ0XzEgPSByZXF1aXJlKFwiLi9hc3NlcnRcIik7XG4vKipcbiAqIFBhZCBhIHN0cmluZyBieSBhZGRpbmcgY2hhcmFjdGVycyB0byB0aGUgYmVnaW5uaW5nLlxuICogQHBhcmFtIHNcdHRoZSBzdHJpbmcgdG8gcGFkXG4gKiBAcGFyYW0gd2lkdGhcdHRoZSBkZXNpcmVkIG1pbmltdW0gc3RyaW5nIHdpZHRoXG4gKiBAcGFyYW0gY2hhclx0dGhlIHNpbmdsZSBjaGFyYWN0ZXIgdG8gcGFkIHdpdGhcbiAqIEByZXR1cm5cdHRoZSBwYWRkZWQgc3RyaW5nXG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuV2lkdGggaWYgd2lkdGggaXMgbm90IGFuIGludGVnZXIgbnVtYmVyID49IDBcbiAqL1xuZnVuY3Rpb24gcGFkTGVmdChzLCB3aWR0aCwgY2hhcikge1xuICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KShOdW1iZXIuaXNJbnRlZ2VyKHdpZHRoKSAmJiB3aWR0aCA+PSAwLCBcIkFyZ3VtZW50LldpZHRoXCIsIFwid2lkdGggc2hvdWxkIGJlIGFuIGludGVnZXIgbnVtYmVyID49IDAgYnV0IGlzOiBcIi5jb25jYXQod2lkdGgpKTtcbiAgICB2YXIgcGFkZGluZyA9IFwiXCI7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCAod2lkdGggLSBzLmxlbmd0aCk7IGkrKykge1xuICAgICAgICBwYWRkaW5nICs9IGNoYXI7XG4gICAgfVxuICAgIHJldHVybiBwYWRkaW5nICsgcztcbn1cbmV4cG9ydHMucGFkTGVmdCA9IHBhZExlZnQ7XG4vKipcbiAqIFBhZCBhIHN0cmluZyBieSBhZGRpbmcgY2hhcmFjdGVycyB0byB0aGUgZW5kLlxuICogQHBhcmFtIHNcdHRoZSBzdHJpbmcgdG8gcGFkXG4gKiBAcGFyYW0gd2lkdGhcdHRoZSBkZXNpcmVkIG1pbmltdW0gc3RyaW5nIHdpZHRoXG4gKiBAcGFyYW0gY2hhclx0dGhlIHNpbmdsZSBjaGFyYWN0ZXIgdG8gcGFkIHdpdGhcbiAqIEByZXR1cm5cdHRoZSBwYWRkZWQgc3RyaW5nXG4gKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuV2lkdGggaWYgd2lkdGggaXMgbm90IGFuIGludGVnZXIgbnVtYmVyID49IDBcbiAqL1xuZnVuY3Rpb24gcGFkUmlnaHQocywgd2lkdGgsIGNoYXIpIHtcbiAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkoTnVtYmVyLmlzSW50ZWdlcih3aWR0aCkgJiYgd2lkdGggPj0gMCwgXCJBcmd1bWVudC5XaWR0aFwiLCBcIndpZHRoIHNob3VsZCBiZSBhbiBpbnRlZ2VyIG51bWJlciA+PSAwIGJ1dCBpczogXCIuY29uY2F0KHdpZHRoKSk7XG4gICAgdmFyIHBhZGRpbmcgPSBcIlwiO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgKHdpZHRoIC0gcy5sZW5ndGgpOyBpKyspIHtcbiAgICAgICAgcGFkZGluZyArPSBjaGFyO1xuICAgIH1cbiAgICByZXR1cm4gcyArIHBhZGRpbmc7XG59XG5leHBvcnRzLnBhZFJpZ2h0ID0gcGFkUmlnaHQ7XG4vLyMgc291cmNlTWFwcGluZ1VSTD1zdHJpbmdzLmpzLm1hcCIsIi8qKlxuICogQ29weXJpZ2h0KGMpIDIwMTQgQUJCIFN3aXR6ZXJsYW5kIEx0ZC5cbiAqL1xuXCJ1c2Ugc3RyaWN0XCI7XG5PYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgXCJfX2VzTW9kdWxlXCIsIHsgdmFsdWU6IHRydWUgfSk7XG5leHBvcnRzLlJlYWxUaW1lU291cmNlID0gdm9pZCAwO1xuLyoqXG4gKiBEZWZhdWx0IHRpbWUgc291cmNlLCByZXR1cm5zIGFjdHVhbCB0aW1lXG4gKi9cbnZhciBSZWFsVGltZVNvdXJjZSA9IC8qKiBAY2xhc3MgKi8gKGZ1bmN0aW9uICgpIHtcbiAgICBmdW5jdGlvbiBSZWFsVGltZVNvdXJjZSgpIHtcbiAgICB9XG4gICAgLyoqIEBpbmhlcml0ZG9jICovXG4gICAgUmVhbFRpbWVTb3VyY2UucHJvdG90eXBlLm5vdyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIGlmICovXG4gICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gICAgICAgIGlmICh0cnVlKSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3IERhdGUoKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgcmV0dXJuIFJlYWxUaW1lU291cmNlO1xufSgpKTtcbmV4cG9ydHMuUmVhbFRpbWVTb3VyY2UgPSBSZWFsVGltZVNvdXJjZTtcbi8vIyBzb3VyY2VNYXBwaW5nVVJMPXRpbWVzb3VyY2UuanMubWFwIiwiLyoqXG4gKiBDb3B5cmlnaHQoYykgMjAxNCBBQkIgU3dpdHplcmxhbmQgTHRkLlxuICpcbiAqIFRpbWUgem9uZSByZXByZXNlbnRhdGlvbiBhbmQgb2Zmc2V0IGNhbGN1bGF0aW9uXG4gKi9cblwidXNlIHN0cmljdFwiO1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7IHZhbHVlOiB0cnVlIH0pO1xuZXhwb3J0cy5pc1RpbWVab25lID0gZXhwb3J0cy5UaW1lWm9uZSA9IGV4cG9ydHMuVGltZVpvbmVLaW5kID0gZXhwb3J0cy56b25lID0gZXhwb3J0cy51dGMgPSBleHBvcnRzLmxvY2FsID0gdm9pZCAwO1xudmFyIGFzc2VydF8xID0gcmVxdWlyZShcIi4vYXNzZXJ0XCIpO1xudmFyIGJhc2ljc18xID0gcmVxdWlyZShcIi4vYmFzaWNzXCIpO1xudmFyIGVycm9yXzEgPSByZXF1aXJlKFwiLi9lcnJvclwiKTtcbnZhciBzdHJpbmdzID0gcmVxdWlyZShcIi4vc3RyaW5nc1wiKTtcbnZhciB0el9kYXRhYmFzZV8xID0gcmVxdWlyZShcIi4vdHotZGF0YWJhc2VcIik7XG4vKipcbiAqIFRoZSBsb2NhbCB0aW1lIHpvbmUgZm9yIGEgZ2l2ZW4gZGF0ZSBhcyBwZXIgT1Mgc2V0dGluZ3MuIE5vdGUgdGhhdCB0aW1lIHpvbmVzIGFyZSBjYWNoZWRcbiAqIHNvIHlvdSBkb24ndCBuZWNlc3NhcmlseSBnZXQgYSBuZXcgb2JqZWN0IGVhY2ggdGltZS5cbiAqIEB0aHJvd3Mgbm90aGluZ1xuICovXG5mdW5jdGlvbiBsb2NhbCgpIHtcbiAgICByZXR1cm4gVGltZVpvbmUubG9jYWwoKTtcbn1cbmV4cG9ydHMubG9jYWwgPSBsb2NhbDtcbi8qKlxuICogQ29vcmRpbmF0ZWQgVW5pdmVyc2FsIFRpbWUgem9uZS4gTm90ZSB0aGF0IHRpbWUgem9uZXMgYXJlIGNhY2hlZFxuICogc28geW91IGRvbid0IG5lY2Vzc2FyaWx5IGdldCBhIG5ldyBvYmplY3QgZWFjaCB0aW1lLlxuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLk5vdEZvdW5kLlpvbmUgaWYgdGhlIFVUQyB6b25lIGlzIG5vdCBwcmVzZW50IGluIHRoZSB0aW1lIHpvbmUgZGF0YWJhc2VcbiAqL1xuZnVuY3Rpb24gdXRjKCkge1xuICAgIHJldHVybiBUaW1lWm9uZS51dGMoKTtcbn1cbmV4cG9ydHMudXRjID0gdXRjO1xuLyoqXG4gKiB6b25lKCkgaW1wbGVtZW50YXRpb25cbiAqL1xuZnVuY3Rpb24gem9uZShhLCBkc3QpIHtcbiAgICByZXR1cm4gVGltZVpvbmUuem9uZShhLCBkc3QpO1xufVxuZXhwb3J0cy56b25lID0gem9uZTtcbi8qKlxuICogVGhlIHR5cGUgb2YgdGltZSB6b25lXG4gKi9cbnZhciBUaW1lWm9uZUtpbmQ7XG4oZnVuY3Rpb24gKFRpbWVab25lS2luZCkge1xuICAgIC8qKlxuICAgICAqIExvY2FsIHRpbWUgb2Zmc2V0IGFzIGRldGVybWluZWQgYnkgSmF2YVNjcmlwdCBEYXRlIGNsYXNzLlxuICAgICAqL1xuICAgIFRpbWVab25lS2luZFtUaW1lWm9uZUtpbmRbXCJMb2NhbFwiXSA9IDBdID0gXCJMb2NhbFwiO1xuICAgIC8qKlxuICAgICAqIEZpeGVkIG9mZnNldCBmcm9tIFVUQywgd2l0aG91dCBEU1QuXG4gICAgICovXG4gICAgVGltZVpvbmVLaW5kW1RpbWVab25lS2luZFtcIk9mZnNldFwiXSA9IDFdID0gXCJPZmZzZXRcIjtcbiAgICAvKipcbiAgICAgKiBJQU5BIHRpbWV6b25lIG1hbmFnZWQgdGhyb3VnaCBPbHNlbiBUWiBkYXRhYmFzZS4gSW5jbHVkZXNcbiAgICAgKiBEU1QgaWYgYXBwbGljYWJsZS5cbiAgICAgKi9cbiAgICBUaW1lWm9uZUtpbmRbVGltZVpvbmVLaW5kW1wiUHJvcGVyXCJdID0gMl0gPSBcIlByb3BlclwiO1xufSkoVGltZVpvbmVLaW5kIHx8IChleHBvcnRzLlRpbWVab25lS2luZCA9IFRpbWVab25lS2luZCA9IHt9KSk7XG4vKipcbiAqIFRpbWUgem9uZS4gVGhlIG9iamVjdCBpcyBpbW11dGFibGUgYmVjYXVzZSBpdCBpcyBjYWNoZWQ6XG4gKiByZXF1ZXN0aW5nIGEgdGltZSB6b25lIHR3aWNlIHlpZWxkcyB0aGUgdmVyeSBzYW1lIG9iamVjdC5cbiAqIE5vdGUgdGhhdCB3ZSB1c2UgdGltZSB6b25lIG9mZnNldHMgaW52ZXJ0ZWQgdy5yLnQuIEphdmFTY3JpcHQgRGF0ZS5nZXRUaW1lem9uZU9mZnNldCgpLFxuICogaS5lLiBvZmZzZXQgOTAgbWVhbnMgKzAxOjMwLlxuICpcbiAqIFRpbWUgem9uZXMgY29tZSBpbiB0aHJlZSBmbGF2b3JzOiB0aGUgbG9jYWwgdGltZSB6b25lLCBhcyBjYWxjdWxhdGVkIGJ5IEphdmFTY3JpcHQgRGF0ZSxcbiAqIGEgZml4ZWQgb2Zmc2V0IChcIiswMTozMFwiKSB3aXRob3V0IERTVCwgb3IgYSBJQU5BIHRpbWV6b25lIChcIkV1cm9wZS9BbXN0ZXJkYW1cIikgd2l0aCBEU1RcbiAqIGFwcGxpZWQgZGVwZW5kaW5nIG9uIHRoZSB0aW1lIHpvbmUgcnVsZXMuXG4gKi9cbnZhciBUaW1lWm9uZSA9IC8qKiBAY2xhc3MgKi8gKGZ1bmN0aW9uICgpIHtcbiAgICAvKipcbiAgICAgKiBEbyBub3QgdXNlIHRoaXMgY29uc3RydWN0b3IsIHVzZSB0aGUgc3RhdGljXG4gICAgICogVGltZVpvbmUuem9uZSgpIG1ldGhvZCBpbnN0ZWFkLlxuICAgICAqIEBwYXJhbSBuYW1lIE5PUk1BTElaRUQgbmFtZSwgYXNzdW1lZCB0byBiZSBjb3JyZWN0XG4gICAgICogQHBhcmFtIGRzdCBBZGhlcmUgdG8gRGF5bGlnaHQgU2F2aW5nIFRpbWUgaWYgYXBwbGljYWJsZSwgaWdub3JlZCBmb3IgbG9jYWwgdGltZSBhbmQgZml4ZWQgb2Zmc2V0c1xuICAgICAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Ob3RGb3VuZC5ab25lIGlmIHRoZSBnaXZlbiB6b25lIG5hbWUgZG9lc24ndCBleGlzdFxuICAgICAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5JbnZhbGlkVGltZVpvbmVEYXRhIGlmIHRoZSB0aW1lIHpvbmUgZGF0YWJhc2UgaXMgaW52YWxpZFxuICAgICAqL1xuICAgIGZ1bmN0aW9uIFRpbWVab25lKG5hbWUsIGRzdCkge1xuICAgICAgICBpZiAoZHN0ID09PSB2b2lkIDApIHsgZHN0ID0gdHJ1ZTsgfVxuICAgICAgICAvKipcbiAgICAgICAgICogQWxsb3cgbm90IHVzaW5nIGluc3RhbmNlb2ZcbiAgICAgICAgICovXG4gICAgICAgIHRoaXMuY2xhc3NLaW5kID0gXCJUaW1lWm9uZVwiO1xuICAgICAgICB0aGlzLl9uYW1lID0gbmFtZTtcbiAgICAgICAgdGhpcy5fZHN0ID0gZHN0O1xuICAgICAgICBpZiAobmFtZSA9PT0gXCJsb2NhbHRpbWVcIikge1xuICAgICAgICAgICAgdGhpcy5fa2luZCA9IFRpbWVab25lS2luZC5Mb2NhbDtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChuYW1lLmNoYXJBdCgwKSA9PT0gXCIrXCIgfHwgbmFtZS5jaGFyQXQoMCkgPT09IFwiLVwiIHx8IG5hbWUuY2hhckF0KDApLm1hdGNoKC9cXGQvKSB8fCBuYW1lID09PSBcIlpcIikge1xuICAgICAgICAgICAgdGhpcy5fa2luZCA9IFRpbWVab25lS2luZC5PZmZzZXQ7XG4gICAgICAgICAgICB0aGlzLl9vZmZzZXQgPSBUaW1lWm9uZS5zdHJpbmdUb09mZnNldChuYW1lKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuX2tpbmQgPSBUaW1lWm9uZUtpbmQuUHJvcGVyO1xuICAgICAgICAgICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKHR6X2RhdGFiYXNlXzEuVHpEYXRhYmFzZS5pbnN0YW5jZSgpLmV4aXN0cyhuYW1lKSwgXCJOb3RGb3VuZC5ab25lXCIsIFwibm9uLWV4aXN0aW5nIHRpbWUgem9uZSBuYW1lICdcIi5jb25jYXQobmFtZSwgXCInXCIpKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICAvKipcbiAgICAgKiBUaGUgbG9jYWwgdGltZSB6b25lIGZvciBhIGdpdmVuIGRhdGUuIE5vdGUgdGhhdFxuICAgICAqIHRoZSB0aW1lIHpvbmUgdmFyaWVzIHdpdGggdGhlIGRhdGU6IGFtc3RlcmRhbSB0aW1lIGZvclxuICAgICAqIDIwMTQtMDEtMDEgaXMgKzAxOjAwIGFuZCBhbXN0ZXJkYW0gdGltZSBmb3IgMjAxNC0wNy0wMSBpcyArMDI6MDBcbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBUaW1lWm9uZS5sb2NhbCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIFRpbWVab25lLl9maW5kT3JDcmVhdGUoXCJsb2NhbHRpbWVcIiwgdHJ1ZSk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBUaGUgVVRDIHRpbWUgem9uZS5cbiAgICAgKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuTm90Rm91bmQuWm9uZSBpZiB0aGUgVVRDIHRpbWUgem9uZSBkb2Vzbid0IGV4aXN0IGluIHRoZSB0aW1lIHpvbmUgZGF0YWJhc2VcbiAgICAgKi9cbiAgICBUaW1lWm9uZS51dGMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBUaW1lWm9uZS5fZmluZE9yQ3JlYXRlKFwiVVRDXCIsIHRydWUpOyAvLyB1c2UgJ3RydWUnIGZvciBEU1QgYmVjYXVzZSB3ZSB3YW50IGl0IHRvIGRpc3BsYXkgYXMgXCJVVENcIiwgbm90IFwiVVRDIHdpdGhvdXQgRFNUXCJcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIHpvbmUoKSBpbXBsZW1lbnRhdGlvbnNcbiAgICAgKi9cbiAgICBUaW1lWm9uZS56b25lID0gZnVuY3Rpb24gKGEsIGRzdCkge1xuICAgICAgICBpZiAoZHN0ID09PSB2b2lkIDApIHsgZHN0ID0gdHJ1ZTsgfVxuICAgICAgICB2YXIgbmFtZSA9IFwiXCI7XG4gICAgICAgIHN3aXRjaCAodHlwZW9mIChhKSkge1xuICAgICAgICAgICAgY2FzZSBcInN0cmluZ1wiOlxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHMgPSBhO1xuICAgICAgICAgICAgICAgICAgICBpZiAocy5pbmRleE9mKFwid2l0aG91dCBEU1RcIikgPj0gMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgZHN0ID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgICAgICAgICBzID0gcy5zbGljZSgwLCBzLmluZGV4T2YoXCJ3aXRob3V0IERTVFwiKSAtIDEpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIG5hbWUgPSBUaW1lWm9uZS5fbm9ybWFsaXplU3RyaW5nKHMpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgXCJudW1iZXJcIjpcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBvZmZzZXQgPSBhO1xuICAgICAgICAgICAgICAgICAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkob2Zmc2V0ID4gLTI0ICogNjAgJiYgb2Zmc2V0IDwgMjQgKiA2MCwgXCJBcmd1bWVudC5PZmZzZXRcIiwgXCJUaW1lWm9uZS56b25lKCk6IG9mZnNldCBvdXQgb2YgcmFuZ2VcIik7XG4gICAgICAgICAgICAgICAgICAgIG5hbWUgPSBUaW1lWm9uZS5vZmZzZXRUb1N0cmluZyhvZmZzZXQpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgICgwLCBlcnJvcl8xLnRocm93RXJyb3IpKFwiQXJndW1lbnQuQVwiLCBcInVuZXhwZWN0ZWQgdHlwZSBmb3IgZmlyc3QgYXJndW1lbnQ6IFwiLmNvbmNhdCh0eXBlb2YgYSkpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBUaW1lWm9uZS5fZmluZE9yQ3JlYXRlKG5hbWUsIGRzdCk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBNYWtlcyB0aGlzIGNsYXNzIGFwcGVhciBjbG9uYWJsZS4gTk9URSBhcyB0aW1lIHpvbmUgb2JqZWN0cyBhcmUgaW1tdXRhYmxlIHlvdSB3aWxsIE5PVFxuICAgICAqIGFjdHVhbGx5IGdldCBhIGNsb25lIGJ1dCB0aGUgc2FtZSBvYmplY3QuXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgVGltZVpvbmUucHJvdG90eXBlLmNsb25lID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFRoZSB0aW1lIHpvbmUgaWRlbnRpZmllci4gQ2FuIGJlIGFuIG9mZnNldCBcIi0wMTozMFwiIG9yIGFuXG4gICAgICogSUFOQSB0aW1lIHpvbmUgbmFtZSBcIkV1cm9wZS9BbXN0ZXJkYW1cIiwgb3IgXCJsb2NhbHRpbWVcIiBmb3JcbiAgICAgKiB0aGUgbG9jYWwgdGltZSB6b25lLlxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIFRpbWVab25lLnByb3RvdHlwZS5uYW1lID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fbmFtZTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFdoZXRoZXIgRFNUIGlzIGVuYWJsZWRcbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBUaW1lWm9uZS5wcm90b3R5cGUuZHN0ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fZHN0O1xuICAgIH07XG4gICAgLyoqXG4gICAgICogVGhlIGtpbmQgb2YgdGltZSB6b25lIChMb2NhbC9PZmZzZXQvUHJvcGVyKVxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIFRpbWVab25lLnByb3RvdHlwZS5raW5kID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fa2luZDtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIEVxdWFsaXR5IG9wZXJhdG9yLiBNYXBzIHplcm8gb2Zmc2V0cyBhbmQgZGlmZmVyZW50IG5hbWVzIGZvciBVVEMgb250b1xuICAgICAqIGVhY2ggb3RoZXIuIE90aGVyIHRpbWUgem9uZXMgYXJlIG5vdCBtYXBwZWQgb250byBlYWNoIG90aGVyLlxuICAgICAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5JbnZhbGlkVGltZVpvbmVEYXRhIGlmIHRoZSBnbG9iYWwgdGltZSB6b25lIGRhdGEgaXMgaW52YWxpZFxuICAgICAqL1xuICAgIFRpbWVab25lLnByb3RvdHlwZS5lcXVhbHMgPSBmdW5jdGlvbiAob3RoZXIpIHtcbiAgICAgICAgaWYgKHRoaXMuaXNVdGMoKSAmJiBvdGhlci5pc1V0YygpKSB7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgICBzd2l0Y2ggKHRoaXMuX2tpbmQpIHtcbiAgICAgICAgICAgIGNhc2UgVGltZVpvbmVLaW5kLkxvY2FsOiByZXR1cm4gKG90aGVyLmtpbmQoKSA9PT0gVGltZVpvbmVLaW5kLkxvY2FsKTtcbiAgICAgICAgICAgIGNhc2UgVGltZVpvbmVLaW5kLk9mZnNldDogcmV0dXJuIChvdGhlci5raW5kKCkgPT09IFRpbWVab25lS2luZC5PZmZzZXQgJiYgdGhpcy5fb2Zmc2V0ID09PSBvdGhlci5fb2Zmc2V0KTtcbiAgICAgICAgICAgIGNhc2UgVGltZVpvbmVLaW5kLlByb3BlcjogcmV0dXJuIChvdGhlci5raW5kKCkgPT09IFRpbWVab25lS2luZC5Qcm9wZXJcbiAgICAgICAgICAgICAgICAmJiB0aGlzLl9uYW1lID09PSBvdGhlci5fbmFtZVxuICAgICAgICAgICAgICAgICYmICh0aGlzLl9kc3QgPT09IG90aGVyLl9kc3QgfHwgIXRoaXMuaGFzRHN0KCkpKTtcbiAgICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgIC8vIGlzdGFuYnVsIGlnbm9yZSBuZXh0XG4gICAgICAgICAgICAgICAgcmV0dXJuICgwLCBlcnJvcl8xLnRocm93RXJyb3IpKFwiQXNzZXJ0aW9uXCIsIFwidW5rbm93biB0aW1lIHpvbmUga2luZFwiKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0cnVlIGlmZiB0aGUgY29uc3RydWN0b3IgYXJndW1lbnRzIHdlcmUgaWRlbnRpY2FsLCBzbyBVVEMgIT09IEdNVFxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIFRpbWVab25lLnByb3RvdHlwZS5pZGVudGljYWwgPSBmdW5jdGlvbiAob3RoZXIpIHtcbiAgICAgICAgc3dpdGNoICh0aGlzLl9raW5kKSB7XG4gICAgICAgICAgICBjYXNlIFRpbWVab25lS2luZC5Mb2NhbDogcmV0dXJuIChvdGhlci5raW5kKCkgPT09IFRpbWVab25lS2luZC5Mb2NhbCk7XG4gICAgICAgICAgICBjYXNlIFRpbWVab25lS2luZC5PZmZzZXQ6IHJldHVybiAob3RoZXIua2luZCgpID09PSBUaW1lWm9uZUtpbmQuT2Zmc2V0ICYmIHRoaXMuX29mZnNldCA9PT0gb3RoZXIuX29mZnNldCk7XG4gICAgICAgICAgICBjYXNlIFRpbWVab25lS2luZC5Qcm9wZXI6IHJldHVybiAob3RoZXIua2luZCgpID09PSBUaW1lWm9uZUtpbmQuUHJvcGVyICYmIHRoaXMuX25hbWUgPT09IG90aGVyLl9uYW1lICYmIHRoaXMuX2RzdCA9PT0gb3RoZXIuX2RzdCk7XG4gICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICAvLyBpc3RhbmJ1bCBpZ25vcmUgbmV4dFxuICAgICAgICAgICAgICAgIHJldHVybiAoMCwgZXJyb3JfMS50aHJvd0Vycm9yKShcIkFzc2VydGlvblwiLCBcInVua25vd24gdGltZSB6b25lIGtpbmRcIik7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIC8qKlxuICAgICAqIElzIHRoaXMgem9uZSBlcXVpdmFsZW50IHRvIFVUQz9cbiAgICAgKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuSW52YWxpZFRpbWVab25lRGF0YSBpZiB0aGUgZ2xvYmFsIHRpbWUgem9uZSBkYXRhIGlzIGludmFsaWRcbiAgICAgKi9cbiAgICBUaW1lWm9uZS5wcm90b3R5cGUuaXNVdGMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHN3aXRjaCAodGhpcy5fa2luZCkge1xuICAgICAgICAgICAgY2FzZSBUaW1lWm9uZUtpbmQuTG9jYWw6IHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIGNhc2UgVGltZVpvbmVLaW5kLk9mZnNldDogcmV0dXJuICh0aGlzLl9vZmZzZXQgPT09IDApO1xuICAgICAgICAgICAgY2FzZSBUaW1lWm9uZUtpbmQuUHJvcGVyOiByZXR1cm4gKHR6X2RhdGFiYXNlXzEuVHpEYXRhYmFzZS5pbnN0YW5jZSgpLnpvbmVJc1V0Yyh0aGlzLl9uYW1lKSk7XG4gICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICAvLyBpc3RhbmJ1bCBpZ25vcmUgbmV4dFxuICAgICAgICAgICAgICAgIHJldHVybiAoMCwgZXJyb3JfMS50aHJvd0Vycm9yKShcIkFzc2VydGlvblwiLCBcInVua25vd24gdGltZSB6b25lIGtpbmRcIik7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIC8qKlxuICAgICAqIERvZXMgdGhpcyB6b25lIGhhdmUgRGF5bGlnaHQgU2F2aW5nIFRpbWUgYXQgYWxsP1xuICAgICAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5JbnZhbGlkVGltZVpvbmVEYXRhIGlmIHRoZSBnbG9iYWwgdGltZSB6b25lIGRhdGEgaXMgaW52YWxpZFxuICAgICAqL1xuICAgIFRpbWVab25lLnByb3RvdHlwZS5oYXNEc3QgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHN3aXRjaCAodGhpcy5fa2luZCkge1xuICAgICAgICAgICAgY2FzZSBUaW1lWm9uZUtpbmQuTG9jYWw6IHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIGNhc2UgVGltZVpvbmVLaW5kLk9mZnNldDogcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgY2FzZSBUaW1lWm9uZUtpbmQuUHJvcGVyOiByZXR1cm4gKHR6X2RhdGFiYXNlXzEuVHpEYXRhYmFzZS5pbnN0YW5jZSgpLmhhc0RzdCh0aGlzLl9uYW1lKSk7XG4gICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICAvLyBpc3RhbmJ1bCBpZ25vcmUgbmV4dFxuICAgICAgICAgICAgICAgIHJldHVybiAoMCwgZXJyb3JfMS50aHJvd0Vycm9yKShcIkFzc2VydGlvblwiLCBcInVua25vd24gdGltZSB6b25lIGtpbmRcIik7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIFRpbWVab25lLnByb3RvdHlwZS5vZmZzZXRGb3JVdGMgPSBmdW5jdGlvbiAoYSwgbW9udGgsIGRheSwgaG91ciwgbWludXRlLCBzZWNvbmQsIG1pbGxpKSB7XG4gICAgICAgIHZhciB1dGNUaW1lID0gKHR5cGVvZiBhID09PSBcIm51bWJlclwiID8gbmV3IGJhc2ljc18xLlRpbWVTdHJ1Y3QoeyB5ZWFyOiBhLCBtb250aDogbW9udGgsIGRheTogZGF5LCBob3VyOiBob3VyLCBtaW51dGU6IG1pbnV0ZSwgc2Vjb25kOiBzZWNvbmQsIG1pbGxpOiBtaWxsaSB9KSA6XG4gICAgICAgICAgICB0eXBlb2YgYSA9PT0gXCJ1bmRlZmluZWRcIiA/IG5ldyBiYXNpY3NfMS5UaW1lU3RydWN0KHt9KSA6XG4gICAgICAgICAgICAgICAgYSk7XG4gICAgICAgIHN3aXRjaCAodGhpcy5fa2luZCkge1xuICAgICAgICAgICAgY2FzZSBUaW1lWm9uZUtpbmQuTG9jYWw6IHtcbiAgICAgICAgICAgICAgICB2YXIgZGF0ZSA9IG5ldyBEYXRlKERhdGUuVVRDKHV0Y1RpbWUuY29tcG9uZW50cy55ZWFyLCB1dGNUaW1lLmNvbXBvbmVudHMubW9udGggLSAxLCB1dGNUaW1lLmNvbXBvbmVudHMuZGF5LCB1dGNUaW1lLmNvbXBvbmVudHMuaG91ciwgdXRjVGltZS5jb21wb25lbnRzLm1pbnV0ZSwgdXRjVGltZS5jb21wb25lbnRzLnNlY29uZCwgdXRjVGltZS5jb21wb25lbnRzLm1pbGxpKSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIC0xICogZGF0ZS5nZXRUaW1lem9uZU9mZnNldCgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FzZSBUaW1lWm9uZUtpbmQuT2Zmc2V0OiB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuX29mZnNldDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhc2UgVGltZVpvbmVLaW5kLlByb3Blcjoge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLl9kc3QpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHR6X2RhdGFiYXNlXzEuVHpEYXRhYmFzZS5pbnN0YW5jZSgpLnRvdGFsT2Zmc2V0KHRoaXMuX25hbWUsIHV0Y1RpbWUpLm1pbnV0ZXMoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB0el9kYXRhYmFzZV8xLlR6RGF0YWJhc2UuaW5zdGFuY2UoKS5zdGFuZGFyZE9mZnNldCh0aGlzLl9uYW1lLCB1dGNUaW1lKS5taW51dGVzKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbiAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgLy8gaXN0YW5idWwgaWdub3JlIG5leHRcbiAgICAgICAgICAgICAgICByZXR1cm4gKDAsIGVycm9yXzEudGhyb3dFcnJvcikoXCJBc3NlcnRpb25cIiwgXCJ1bmtub3duIHRpbWUgem9uZSBraW5kXCIpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICBUaW1lWm9uZS5wcm90b3R5cGUuc3RhbmRhcmRPZmZzZXRGb3JVdGMgPSBmdW5jdGlvbiAoYSwgbW9udGgsIGRheSwgaG91ciwgbWludXRlLCBzZWNvbmQsIG1pbGxpKSB7XG4gICAgICAgIHZhciB1dGNUaW1lID0gKHR5cGVvZiBhID09PSBcIm51bWJlclwiID8gbmV3IGJhc2ljc18xLlRpbWVTdHJ1Y3QoeyB5ZWFyOiBhLCBtb250aDogbW9udGgsIGRheTogZGF5LCBob3VyOiBob3VyLCBtaW51dGU6IG1pbnV0ZSwgc2Vjb25kOiBzZWNvbmQsIG1pbGxpOiBtaWxsaSB9KSA6XG4gICAgICAgICAgICB0eXBlb2YgYSA9PT0gXCJ1bmRlZmluZWRcIiA/IG5ldyBiYXNpY3NfMS5UaW1lU3RydWN0KHt9KSA6XG4gICAgICAgICAgICAgICAgYSk7XG4gICAgICAgIHN3aXRjaCAodGhpcy5fa2luZCkge1xuICAgICAgICAgICAgY2FzZSBUaW1lWm9uZUtpbmQuTG9jYWw6IHtcbiAgICAgICAgICAgICAgICB2YXIgZGF0ZSA9IG5ldyBEYXRlKERhdGUuVVRDKHV0Y1RpbWUuY29tcG9uZW50cy55ZWFyLCAwLCAxLCAwKSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIC0xICogZGF0ZS5nZXRUaW1lem9uZU9mZnNldCgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FzZSBUaW1lWm9uZUtpbmQuT2Zmc2V0OiB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuX29mZnNldDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhc2UgVGltZVpvbmVLaW5kLlByb3Blcjoge1xuICAgICAgICAgICAgICAgIHJldHVybiB0el9kYXRhYmFzZV8xLlR6RGF0YWJhc2UuaW5zdGFuY2UoKS5zdGFuZGFyZE9mZnNldCh0aGlzLl9uYW1lLCB1dGNUaW1lKS5taW51dGVzKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICAvLyBpc3RhbmJ1bCBpZ25vcmUgbmV4dFxuICAgICAgICAgICAgICAgIHJldHVybiAoMCwgZXJyb3JfMS50aHJvd0Vycm9yKShcIkFzc2VydGlvblwiLCBcInVua25vd24gdGltZSB6b25lIGtpbmRcIik7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIFRpbWVab25lLnByb3RvdHlwZS5vZmZzZXRGb3Jab25lID0gZnVuY3Rpb24gKGEsIG1vbnRoLCBkYXksIGhvdXIsIG1pbnV0ZSwgc2Vjb25kLCBtaWxsaSkge1xuICAgICAgICB2YXIgbG9jYWxUaW1lID0gKHR5cGVvZiBhID09PSBcIm51bWJlclwiID8gbmV3IGJhc2ljc18xLlRpbWVTdHJ1Y3QoeyB5ZWFyOiBhLCBtb250aDogbW9udGgsIGRheTogZGF5LCBob3VyOiBob3VyLCBtaW51dGU6IG1pbnV0ZSwgc2Vjb25kOiBzZWNvbmQsIG1pbGxpOiBtaWxsaSB9KSA6XG4gICAgICAgICAgICB0eXBlb2YgYSA9PT0gXCJ1bmRlZmluZWRcIiA/IG5ldyBiYXNpY3NfMS5UaW1lU3RydWN0KHt9KSA6XG4gICAgICAgICAgICAgICAgYSk7XG4gICAgICAgIHN3aXRjaCAodGhpcy5fa2luZCkge1xuICAgICAgICAgICAgY2FzZSBUaW1lWm9uZUtpbmQuTG9jYWw6IHtcbiAgICAgICAgICAgICAgICB2YXIgZGF0ZSA9IG5ldyBEYXRlKGxvY2FsVGltZS5jb21wb25lbnRzLnllYXIsIGxvY2FsVGltZS5jb21wb25lbnRzLm1vbnRoIC0gMSwgbG9jYWxUaW1lLmNvbXBvbmVudHMuZGF5LCBsb2NhbFRpbWUuY29tcG9uZW50cy5ob3VyLCBsb2NhbFRpbWUuY29tcG9uZW50cy5taW51dGUsIGxvY2FsVGltZS5jb21wb25lbnRzLnNlY29uZCwgbG9jYWxUaW1lLmNvbXBvbmVudHMubWlsbGkpO1xuICAgICAgICAgICAgICAgIHJldHVybiAtMSAqIGRhdGUuZ2V0VGltZXpvbmVPZmZzZXQoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhc2UgVGltZVpvbmVLaW5kLk9mZnNldDoge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLl9vZmZzZXQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXNlIFRpbWVab25lS2luZC5Qcm9wZXI6IHtcbiAgICAgICAgICAgICAgICAvLyBub3RlIHRoYXQgVHpEYXRhYmFzZSBub3JtYWxpemVzIHRoZSBnaXZlbiBkYXRlIHNvIHdlIGRvbid0IGhhdmUgdG8gZG8gaXRcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5fZHN0KSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB0el9kYXRhYmFzZV8xLlR6RGF0YWJhc2UuaW5zdGFuY2UoKS50b3RhbE9mZnNldExvY2FsKHRoaXMuX25hbWUsIGxvY2FsVGltZSkubWludXRlcygpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHR6X2RhdGFiYXNlXzEuVHpEYXRhYmFzZS5pbnN0YW5jZSgpLnN0YW5kYXJkT2Zmc2V0KHRoaXMuX25hbWUsIGxvY2FsVGltZSkubWludXRlcygpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgIC8vIGlzdGFuYnVsIGlnbm9yZSBuZXh0XG4gICAgICAgICAgICAgICAgcmV0dXJuICgwLCBlcnJvcl8xLnRocm93RXJyb3IpKFwiQXNzZXJ0aW9uXCIsIFwidW5rbm93biB0aW1lIHpvbmUga2luZFwiKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgLyoqXG4gICAgICogTm90ZTogd2lsbCBiZSByZW1vdmVkIGluIHZlcnNpb24gMi4wLjBcbiAgICAgKlxuICAgICAqIENvbnZlbmllbmNlIGZ1bmN0aW9uLCB0YWtlcyB2YWx1ZXMgZnJvbSBhIEphdmFzY3JpcHQgRGF0ZVxuICAgICAqIENhbGxzIG9mZnNldEZvclV0YygpIHdpdGggdGhlIGNvbnRlbnRzIG9mIHRoZSBkYXRlXG4gICAgICpcbiAgICAgKiBAcGFyYW0gZGF0ZTogdGhlIGRhdGVcbiAgICAgKiBAcGFyYW0gZnVuY3M6IHRoZSBzZXQgb2YgZnVuY3Rpb25zIHRvIHVzZTogZ2V0KCkgb3IgZ2V0VVRDKClcbiAgICAgKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuSW52YWxpZFRpbWVab25lRGF0YSBpZiB2YWx1ZXMgaW4gdGhlIHRpbWUgem9uZSBkYXRhYmFzZSBhcmUgaW52YWxpZFxuICAgICAqL1xuICAgIFRpbWVab25lLnByb3RvdHlwZS5vZmZzZXRGb3JVdGNEYXRlID0gZnVuY3Rpb24gKGRhdGUsIGZ1bmNzKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm9mZnNldEZvclV0YyhiYXNpY3NfMS5UaW1lU3RydWN0LmZyb21EYXRlKGRhdGUsIGZ1bmNzKSk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBOb3RlOiB3aWxsIGJlIHJlbW92ZWQgaW4gdmVyc2lvbiAyLjAuMFxuICAgICAqXG4gICAgICogQ29udmVuaWVuY2UgZnVuY3Rpb24sIHRha2VzIHZhbHVlcyBmcm9tIGEgSmF2YXNjcmlwdCBEYXRlXG4gICAgICogQ2FsbHMgb2Zmc2V0Rm9yVXRjKCkgd2l0aCB0aGUgY29udGVudHMgb2YgdGhlIGRhdGVcbiAgICAgKlxuICAgICAqIEBwYXJhbSBkYXRlOiB0aGUgZGF0ZVxuICAgICAqIEBwYXJhbSBmdW5jczogdGhlIHNldCBvZiBmdW5jdGlvbnMgdG8gdXNlOiBnZXQoKSBvciBnZXRVVEMoKVxuICAgICAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5JbnZhbGlkVGltZVpvbmVEYXRhIGlmIHZhbHVlcyBpbiB0aGUgdGltZSB6b25lIGRhdGFiYXNlIGFyZSBpbnZhbGlkXG4gICAgICovXG4gICAgVGltZVpvbmUucHJvdG90eXBlLm9mZnNldEZvclpvbmVEYXRlID0gZnVuY3Rpb24gKGRhdGUsIGZ1bmNzKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm9mZnNldEZvclpvbmUoYmFzaWNzXzEuVGltZVN0cnVjdC5mcm9tRGF0ZShkYXRlLCBmdW5jcykpO1xuICAgIH07XG4gICAgVGltZVpvbmUucHJvdG90eXBlLmFiYnJldmlhdGlvbkZvclV0YyA9IGZ1bmN0aW9uIChhLCBiLCBkYXksIGhvdXIsIG1pbnV0ZSwgc2Vjb25kLCBtaWxsaSwgYykge1xuICAgICAgICB2YXIgdXRjVGltZTtcbiAgICAgICAgdmFyIGRzdERlcGVuZGVudCA9IHRydWU7XG4gICAgICAgIGlmICh0eXBlb2YgYSAhPT0gXCJudW1iZXJcIiAmJiAhIWEpIHtcbiAgICAgICAgICAgIHV0Y1RpbWUgPSBhO1xuICAgICAgICAgICAgZHN0RGVwZW5kZW50ID0gKGIgPT09IGZhbHNlID8gZmFsc2UgOiB0cnVlKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHV0Y1RpbWUgPSBuZXcgYmFzaWNzXzEuVGltZVN0cnVjdCh7IHllYXI6IGEsIG1vbnRoOiBiLCBkYXk6IGRheSwgaG91cjogaG91ciwgbWludXRlOiBtaW51dGUsIHNlY29uZDogc2Vjb25kLCBtaWxsaTogbWlsbGkgfSk7XG4gICAgICAgICAgICBkc3REZXBlbmRlbnQgPSAoYyA9PT0gZmFsc2UgPyBmYWxzZSA6IHRydWUpO1xuICAgICAgICB9XG4gICAgICAgIHN3aXRjaCAodGhpcy5fa2luZCkge1xuICAgICAgICAgICAgY2FzZSBUaW1lWm9uZUtpbmQuTG9jYWw6IHtcbiAgICAgICAgICAgICAgICByZXR1cm4gXCJsb2NhbFwiO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FzZSBUaW1lWm9uZUtpbmQuT2Zmc2V0OiB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMudG9TdHJpbmcoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhc2UgVGltZVpvbmVLaW5kLlByb3Blcjoge1xuICAgICAgICAgICAgICAgIHJldHVybiB0el9kYXRhYmFzZV8xLlR6RGF0YWJhc2UuaW5zdGFuY2UoKS5hYmJyZXZpYXRpb24odGhpcy5fbmFtZSwgdXRjVGltZSwgZHN0RGVwZW5kZW50KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgIC8vIGlzdGFuYnVsIGlnbm9yZSBuZXh0XG4gICAgICAgICAgICAgICAgcmV0dXJuICgwLCBlcnJvcl8xLnRocm93RXJyb3IpKFwiQXNzZXJ0aW9uXCIsIFwidW5rbm93biB0aW1lIHpvbmUga2luZFwiKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgVGltZVpvbmUucHJvdG90eXBlLm5vcm1hbGl6ZVpvbmVUaW1lID0gZnVuY3Rpb24gKGxvY2FsVGltZSwgb3B0KSB7XG4gICAgICAgIGlmIChvcHQgPT09IHZvaWQgMCkgeyBvcHQgPSB0el9kYXRhYmFzZV8xLk5vcm1hbGl6ZU9wdGlvbi5VcDsgfVxuICAgICAgICB2YXIgdHpvcHQgPSAob3B0ID09PSB0el9kYXRhYmFzZV8xLk5vcm1hbGl6ZU9wdGlvbi5Eb3duID8gdHpfZGF0YWJhc2VfMS5Ob3JtYWxpemVPcHRpb24uRG93biA6IHR6X2RhdGFiYXNlXzEuTm9ybWFsaXplT3B0aW9uLlVwKTtcbiAgICAgICAgaWYgKHRoaXMua2luZCgpID09PSBUaW1lWm9uZUtpbmQuUHJvcGVyKSB7XG4gICAgICAgICAgICBpZiAodHlwZW9mIGxvY2FsVGltZSA9PT0gXCJudW1iZXJcIikge1xuICAgICAgICAgICAgICAgIHJldHVybiB0el9kYXRhYmFzZV8xLlR6RGF0YWJhc2UuaW5zdGFuY2UoKS5ub3JtYWxpemVMb2NhbCh0aGlzLl9uYW1lLCBuZXcgYmFzaWNzXzEuVGltZVN0cnVjdChsb2NhbFRpbWUpLCB0em9wdCkudW5peE1pbGxpcztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIHJldHVybiB0el9kYXRhYmFzZV8xLlR6RGF0YWJhc2UuaW5zdGFuY2UoKS5ub3JtYWxpemVMb2NhbCh0aGlzLl9uYW1lLCBsb2NhbFRpbWUsIHR6b3B0KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBsb2NhbFRpbWU7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFRoZSB0aW1lIHpvbmUgaWRlbnRpZmllciAobm9ybWFsaXplZCkuXG4gICAgICogRWl0aGVyIFwibG9jYWx0aW1lXCIsIElBTkEgbmFtZSwgb3IgXCIraGg6bW1cIiBvZmZzZXQuXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgVGltZVpvbmUucHJvdG90eXBlLnRvU3RyaW5nID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgcmVzdWx0ID0gdGhpcy5uYW1lKCk7XG4gICAgICAgIGlmICh0aGlzLmtpbmQoKSA9PT0gVGltZVpvbmVLaW5kLlByb3Blcikge1xuICAgICAgICAgICAgaWYgKHRoaXMuaGFzRHN0KCkgJiYgIXRoaXMuZHN0KCkpIHtcbiAgICAgICAgICAgICAgICByZXN1bHQgKz0gXCIgd2l0aG91dCBEU1RcIjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH07XG4gICAgLyoqXG4gICAgICogQ29udmVydCBhbiBvZmZzZXQgbnVtYmVyIGludG8gYW4gb2Zmc2V0IHN0cmluZ1xuICAgICAqIEBwYXJhbSBvZmZzZXQgVGhlIG9mZnNldCBpbiBtaW51dGVzIGZyb20gVVRDIGUuZy4gOTAgbWludXRlc1xuICAgICAqIEByZXR1cm4gdGhlIG9mZnNldCBpbiBJU08gbm90YXRpb24gXCIrMDE6MzBcIiBmb3IgKzkwIG1pbnV0ZXNcbiAgICAgKiBAdGhyb3dzIEFyZ3VtZW50Lk9mZnNldCBpZiBvZmZzZXQgaXMgbm90IGEgZmluaXRlIG51bWJlciBvciBub3Qgd2l0aGluIC0yNCAqIDYwIC4uLiArMjQgKiA2MCBtaW51dGVzXG4gICAgICovXG4gICAgVGltZVpvbmUub2Zmc2V0VG9TdHJpbmcgPSBmdW5jdGlvbiAob2Zmc2V0KSB7XG4gICAgICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KShOdW1iZXIuaXNGaW5pdGUob2Zmc2V0KSAmJiBvZmZzZXQgPj0gLTI0ICogNjAgJiYgb2Zmc2V0IDw9IDI0ICogNjAsIFwiQXJndW1lbnQuT2Zmc2V0XCIsIFwiaW52YWxpZCBvZmZzZXQgXCIuY29uY2F0KG9mZnNldCkpO1xuICAgICAgICB2YXIgc2lnbiA9IChvZmZzZXQgPCAwID8gXCItXCIgOiBcIitcIik7XG4gICAgICAgIHZhciBob3VycyA9IE1hdGguZmxvb3IoTWF0aC5hYnMob2Zmc2V0KSAvIDYwKTtcbiAgICAgICAgdmFyIG1pbnV0ZXMgPSBNYXRoLmZsb29yKE1hdGguYWJzKG9mZnNldCkgJSA2MCk7XG4gICAgICAgIHJldHVybiBzaWduICsgc3RyaW5ncy5wYWRMZWZ0KGhvdXJzLnRvU3RyaW5nKDEwKSwgMiwgXCIwXCIpICsgXCI6XCIgKyBzdHJpbmdzLnBhZExlZnQobWludXRlcy50b1N0cmluZygxMCksIDIsIFwiMFwiKTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFN0cmluZyB0byBvZmZzZXQgY29udmVyc2lvbi5cbiAgICAgKiBAcGFyYW0gc1x0Rm9ybWF0czogXCItMDE6MDBcIiwgXCItMDEwMFwiLCBcIi0wMVwiLCBcIlpcIlxuICAgICAqIEByZXR1cm4gb2Zmc2V0IHcuci50LiBVVEMgaW4gbWludXRlc1xuICAgICAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5TIGlmIHMgY2Fubm90IGJlIHBhcnNlZFxuICAgICAqL1xuICAgIFRpbWVab25lLnN0cmluZ1RvT2Zmc2V0ID0gZnVuY3Rpb24gKHMpIHtcbiAgICAgICAgdmFyIHQgPSBzLnRyaW0oKTtcbiAgICAgICAgLy8gZWFzeSBjYXNlXG4gICAgICAgIGlmICh0ID09PSBcIlpcIikge1xuICAgICAgICAgICAgcmV0dXJuIDA7XG4gICAgICAgIH1cbiAgICAgICAgLy8gY2hlY2sgdGhhdCB0aGUgcmVtYWluZGVyIGNvbmZvcm1zIHRvIElTTyB0aW1lIHpvbmUgc3BlY1xuICAgICAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkodC5tYXRjaCgvXlsrLV1cXGQkLykgfHwgdC5tYXRjaCgvXlsrLV1cXGRcXGQkLykgfHwgdC5tYXRjaCgvXlsrLV1cXGRcXGQoOj8pXFxkXFxkJC8pLCBcIkFyZ3VtZW50LlNcIiwgXCJXcm9uZyB0aW1lIHpvbmUgZm9ybWF0OiBcXFwiXCIgKyB0ICsgXCJcXFwiXCIpO1xuICAgICAgICB2YXIgc2lnbiA9ICh0LmNoYXJBdCgwKSA9PT0gXCIrXCIgPyAxIDogLTEpO1xuICAgICAgICB2YXIgaG91cnMgPSAwO1xuICAgICAgICB2YXIgbWludXRlcyA9IDA7XG4gICAgICAgIHN3aXRjaCAodC5sZW5ndGgpIHtcbiAgICAgICAgICAgIGNhc2UgMjpcbiAgICAgICAgICAgICAgICBob3VycyA9IHBhcnNlSW50KHQuc2xpY2UoMSwgMiksIDEwKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgMzpcbiAgICAgICAgICAgICAgICBob3VycyA9IHBhcnNlSW50KHQuc2xpY2UoMSwgMyksIDEwKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgNTpcbiAgICAgICAgICAgICAgICBob3VycyA9IHBhcnNlSW50KHQuc2xpY2UoMSwgMyksIDEwKTtcbiAgICAgICAgICAgICAgICBtaW51dGVzID0gcGFyc2VJbnQodC5zbGljZSgzLCA1KSwgMTApO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSA2OlxuICAgICAgICAgICAgICAgIGhvdXJzID0gcGFyc2VJbnQodC5zbGljZSgxLCAzKSwgMTApO1xuICAgICAgICAgICAgICAgIG1pbnV0ZXMgPSBwYXJzZUludCh0LnNsaWNlKDQsIDYpLCAxMCk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKGhvdXJzID49IDAgJiYgaG91cnMgPCAyNCwgXCJBcmd1bWVudC5TXCIsIFwiSW52YWxpZCB0aW1lIHpvbmUgKGhvdXJzIG91dCBvZiByYW5nZSk6ICdcIi5jb25jYXQodCwgXCInXCIpKTtcbiAgICAgICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKG1pbnV0ZXMgPj0gMCAmJiBtaW51dGVzIDwgNjAsIFwiQXJndW1lbnQuU1wiLCBcIkludmFsaWQgdGltZSB6b25lIChtaW51dGVzIG91dCBvZiByYW5nZSk6ICdcIi5jb25jYXQodCwgXCInXCIpKTtcbiAgICAgICAgcmV0dXJuIHNpZ24gKiAoaG91cnMgKiA2MCArIG1pbnV0ZXMpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogRmluZCBpbiBjYWNoZSBvciBjcmVhdGUgem9uZVxuICAgICAqIEBwYXJhbSBuYW1lXHRUaW1lIHpvbmUgbmFtZVxuICAgICAqIEBwYXJhbSBkc3RcdEFkaGVyZSB0byBEYXlsaWdodCBTYXZpbmcgVGltZT9cbiAgICAgKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuTm90Rm91bmQuWm9uZSBpZiB0aGUgem9uZSBkb2Vzbid0IGV4aXN0IGluIHRoZSB0aW1lIHpvbmUgZGF0YWJhc2VcbiAgICAgKi9cbiAgICBUaW1lWm9uZS5fZmluZE9yQ3JlYXRlID0gZnVuY3Rpb24gKG5hbWUsIGRzdCkge1xuICAgICAgICB2YXIga2V5ID0gbmFtZSArIChkc3QgPyBcIl9EU1RcIiA6IFwiX05PLURTVFwiKTtcbiAgICAgICAgaWYgKGtleSBpbiBUaW1lWm9uZS5fY2FjaGUpIHtcbiAgICAgICAgICAgIHJldHVybiBUaW1lWm9uZS5fY2FjaGVba2V5XTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHZhciB0ID0gbmV3IFRpbWVab25lKG5hbWUsIGRzdCk7XG4gICAgICAgICAgICBUaW1lWm9uZS5fY2FjaGVba2V5XSA9IHQ7XG4gICAgICAgICAgICByZXR1cm4gdDtcbiAgICAgICAgfVxuICAgIH07XG4gICAgLyoqXG4gICAgICogTm9ybWFsaXplIGEgc3RyaW5nIHNvIGl0IGNhbiBiZSB1c2VkIGFzIGEga2V5IGZvciBhIGNhY2hlIGxvb2t1cFxuICAgICAqIEB0aHJvd3MgQXJndW1lbnQuUyBpZiBzIGlzIGVtcHR5XG4gICAgICovXG4gICAgVGltZVpvbmUuX25vcm1hbGl6ZVN0cmluZyA9IGZ1bmN0aW9uIChzKSB7XG4gICAgICAgIHZhciB0ID0gcy50cmltKCk7XG4gICAgICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KSh0Lmxlbmd0aCA+IDAsIFwiQXJndW1lbnQuU1wiLCBcIkVtcHR5IHRpbWUgem9uZSBzdHJpbmcgZ2l2ZW5cIik7XG4gICAgICAgIGlmICh0ID09PSBcImxvY2FsdGltZVwiKSB7XG4gICAgICAgICAgICByZXR1cm4gdDtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICh0ID09PSBcIlpcIikge1xuICAgICAgICAgICAgcmV0dXJuIFwiKzAwOjAwXCI7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoVGltZVpvbmUuX2lzT2Zmc2V0U3RyaW5nKHQpKSB7XG4gICAgICAgICAgICAvLyBvZmZzZXQgc3RyaW5nXG4gICAgICAgICAgICAvLyBub3JtYWxpemUgYnkgY29udmVydGluZyBiYWNrIGFuZCBmb3J0aFxuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICByZXR1cm4gVGltZVpvbmUub2Zmc2V0VG9TdHJpbmcoVGltZVpvbmUuc3RyaW5nVG9PZmZzZXQodCkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICBpZiAoKDAsIGVycm9yXzEuZXJyb3JJcykoZSwgXCJBcmd1bWVudC5PZmZzZXRcIikpIHtcbiAgICAgICAgICAgICAgICAgICAgZSA9ICgwLCBlcnJvcl8xLmVycm9yKShcIkFyZ3VtZW50LlNcIiwgZS5tZXNzYWdlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdGhyb3cgZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIC8vIE9sc2VuIFRaIGRhdGFiYXNlIG5hbWVcbiAgICAgICAgICAgIHJldHVybiB0O1xuICAgICAgICB9XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRydWUgaWZmIHRoZSBmaXJzdCBub24td2hpdGVzcGFjZSBjaGFyYWN0ZXIgb2YgcyBpcyArLCAtLCBvciBaXG4gICAgICogQHBhcmFtIHNcbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBUaW1lWm9uZS5faXNPZmZzZXRTdHJpbmcgPSBmdW5jdGlvbiAocykge1xuICAgICAgICB2YXIgdCA9IHMudHJpbSgpO1xuICAgICAgICByZXR1cm4gKHQuY2hhckF0KDApID09PSBcIitcIiB8fCB0LmNoYXJBdCgwKSA9PT0gXCItXCIgfHwgdCA9PT0gXCJaXCIpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogVGltZSB6b25lIGNhY2hlLlxuICAgICAqL1xuICAgIFRpbWVab25lLl9jYWNoZSA9IHt9O1xuICAgIHJldHVybiBUaW1lWm9uZTtcbn0oKSk7XG5leHBvcnRzLlRpbWVab25lID0gVGltZVpvbmU7XG4vKipcbiAqIENoZWNrcyBpZiBhIGdpdmVuIG9iamVjdCBpcyBvZiB0eXBlIFRpbWVab25lLiBOb3RlIHRoYXQgaXQgZG9lcyBub3Qgd29yayBmb3Igc3ViIGNsYXNzZXMuIEhvd2V2ZXIsIHVzZSB0aGlzIHRvIGJlIHJvYnVzdFxuICogYWdhaW5zdCBkaWZmZXJlbnQgdmVyc2lvbnMgb2YgdGhlIGxpYnJhcnkgaW4gb25lIHByb2Nlc3MgaW5zdGVhZCBvZiBpbnN0YW5jZW9mXG4gKiBAcGFyYW0gdmFsdWUgVmFsdWUgdG8gY2hlY2tcbiAqIEB0aHJvd3Mgbm90aGluZ1xuICovXG5mdW5jdGlvbiBpc1RpbWVab25lKHZhbHVlKSB7XG4gICAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PT0gXCJvYmplY3RcIiAmJiB2YWx1ZSAhPT0gbnVsbCAmJiB2YWx1ZS5jbGFzc0tpbmQgPT09IFwiVGltZVpvbmVcIjtcbn1cbmV4cG9ydHMuaXNUaW1lWm9uZSA9IGlzVGltZVpvbmU7XG4vLyMgc291cmNlTWFwcGluZ1VSTD10aW1lem9uZS5qcy5tYXAiLCIvKipcbiAqIEZ1bmN0aW9uYWxpdHkgdG8gcGFyc2UgYSBEYXRlVGltZSBvYmplY3QgdG8gYSBzdHJpbmdcbiAqL1xuXCJ1c2Ugc3RyaWN0XCI7XG5PYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgXCJfX2VzTW9kdWxlXCIsIHsgdmFsdWU6IHRydWUgfSk7XG5leHBvcnRzLnRva2VuaXplID0gZXhwb3J0cy5Ub2tlblR5cGUgPSB2b2lkIDA7XG4vKipcbiAqIERpZmZlcmVudCB0eXBlcyBvZiB0b2tlbnMsIGVhY2ggZm9yIGEgRGF0ZVRpbWUgXCJwZXJpb2QgdHlwZVwiIChsaWtlIHllYXIsIG1vbnRoLCBob3VyIGV0Yy4pXG4gKi9cbnZhciBUb2tlblR5cGU7XG4oZnVuY3Rpb24gKFRva2VuVHlwZSkge1xuICAgIC8qKlxuICAgICAqIFJhdyB0ZXh0XG4gICAgICovXG4gICAgVG9rZW5UeXBlW1Rva2VuVHlwZVtcIklERU5USVRZXCJdID0gMF0gPSBcIklERU5USVRZXCI7XG4gICAgVG9rZW5UeXBlW1Rva2VuVHlwZVtcIkVSQVwiXSA9IDFdID0gXCJFUkFcIjtcbiAgICBUb2tlblR5cGVbVG9rZW5UeXBlW1wiWUVBUlwiXSA9IDJdID0gXCJZRUFSXCI7XG4gICAgVG9rZW5UeXBlW1Rva2VuVHlwZVtcIlFVQVJURVJcIl0gPSAzXSA9IFwiUVVBUlRFUlwiO1xuICAgIFRva2VuVHlwZVtUb2tlblR5cGVbXCJNT05USFwiXSA9IDRdID0gXCJNT05USFwiO1xuICAgIFRva2VuVHlwZVtUb2tlblR5cGVbXCJXRUVLXCJdID0gNV0gPSBcIldFRUtcIjtcbiAgICBUb2tlblR5cGVbVG9rZW5UeXBlW1wiREFZXCJdID0gNl0gPSBcIkRBWVwiO1xuICAgIFRva2VuVHlwZVtUb2tlblR5cGVbXCJXRUVLREFZXCJdID0gN10gPSBcIldFRUtEQVlcIjtcbiAgICBUb2tlblR5cGVbVG9rZW5UeXBlW1wiREFZUEVSSU9EXCJdID0gOF0gPSBcIkRBWVBFUklPRFwiO1xuICAgIFRva2VuVHlwZVtUb2tlblR5cGVbXCJIT1VSXCJdID0gOV0gPSBcIkhPVVJcIjtcbiAgICBUb2tlblR5cGVbVG9rZW5UeXBlW1wiTUlOVVRFXCJdID0gMTBdID0gXCJNSU5VVEVcIjtcbiAgICBUb2tlblR5cGVbVG9rZW5UeXBlW1wiU0VDT05EXCJdID0gMTFdID0gXCJTRUNPTkRcIjtcbiAgICBUb2tlblR5cGVbVG9rZW5UeXBlW1wiWk9ORVwiXSA9IDEyXSA9IFwiWk9ORVwiO1xufSkoVG9rZW5UeXBlIHx8IChleHBvcnRzLlRva2VuVHlwZSA9IFRva2VuVHlwZSA9IHt9KSk7XG4vKipcbiAqIFRva2VuaXplIGFuIExETUwgZGF0ZS90aW1lIGZvcm1hdCBzdHJpbmdcbiAqIEBwYXJhbSBmb3JtYXRTdHJpbmcgdGhlIHN0cmluZyB0byB0b2tlbml6ZVxuICogQHRocm93cyBub3RoaW5nXG4gKi9cbmZ1bmN0aW9uIHRva2VuaXplKGZvcm1hdFN0cmluZykge1xuICAgIGlmICghZm9ybWF0U3RyaW5nKSB7XG4gICAgICAgIHJldHVybiBbXTtcbiAgICB9XG4gICAgdmFyIHJlc3VsdCA9IFtdO1xuICAgIHZhciBhcHBlbmRUb2tlbiA9IGZ1bmN0aW9uICh0b2tlblN0cmluZywgcmF3KSB7XG4gICAgICAgIC8vIFRoZSB0b2tlblN0cmluZyBtYXkgYmUgbG9uZ2VyIHRoYW4gc3VwcG9ydGVkIGZvciBhIHRva2VudHlwZSwgZS5nLiBcImhoaGhcIiB3aGljaCB3b3VsZCBiZSBUV08gaG91ciBzcGVjcy5cbiAgICAgICAgLy8gV2UgZ3JlZWRpbHkgY29uc3VtZSBMRE1MIHNwZWNzIHdoaWxlIHBvc3NpYmxlXG4gICAgICAgIHdoaWxlICh0b2tlblN0cmluZyAhPT0gXCJcIikge1xuICAgICAgICAgICAgaWYgKHJhdyB8fCAhU1lNQk9MX01BUFBJTkcuaGFzT3duUHJvcGVydHkodG9rZW5TdHJpbmdbMF0pKSB7XG4gICAgICAgICAgICAgICAgdmFyIHRva2VuID0ge1xuICAgICAgICAgICAgICAgICAgICBsZW5ndGg6IHRva2VuU3RyaW5nLmxlbmd0aCxcbiAgICAgICAgICAgICAgICAgICAgcmF3OiB0b2tlblN0cmluZyxcbiAgICAgICAgICAgICAgICAgICAgc3ltYm9sOiB0b2tlblN0cmluZ1swXSxcbiAgICAgICAgICAgICAgICAgICAgdHlwZTogVG9rZW5UeXBlLklERU5USVRZXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICByZXN1bHQucHVzaCh0b2tlbik7XG4gICAgICAgICAgICAgICAgdG9rZW5TdHJpbmcgPSBcIlwiO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgLy8gZGVwZW5kaW5nIG9uIHRoZSB0eXBlIG9mIHRva2VuLCBkaWZmZXJlbnQgbGVuZ3RocyBtYXkgYmUgc3VwcG9ydGVkXG4gICAgICAgICAgICAgICAgdmFyIGluZm8gPSBTWU1CT0xfTUFQUElOR1t0b2tlblN0cmluZ1swXV07XG4gICAgICAgICAgICAgICAgdmFyIGxlbmd0aF8xID0gdm9pZCAwO1xuICAgICAgICAgICAgICAgIGlmIChpbmZvLm1heExlbmd0aCA9PT0gdW5kZWZpbmVkICYmICghQXJyYXkuaXNBcnJheShpbmZvLmxlbmd0aHMpIHx8IGluZm8ubGVuZ3Rocy5sZW5ndGggPT09IDApKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGV2ZXJ5dGhpbmcgaXMgYWxsb3dlZFxuICAgICAgICAgICAgICAgICAgICBsZW5ndGhfMSA9IHRva2VuU3RyaW5nLmxlbmd0aDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSBpZiAoaW5mby5tYXhMZW5ndGggIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgICAgICAvLyBncmVlZGlseSBnb2JibGUgdXBcbiAgICAgICAgICAgICAgICAgICAgbGVuZ3RoXzEgPSBNYXRoLm1pbih0b2tlblN0cmluZy5sZW5ndGgsIGluZm8ubWF4TGVuZ3RoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSAvKiBpc3RhbmJ1bCBpZ25vcmUgZWxzZSAqLyBpZiAoQXJyYXkuaXNBcnJheShpbmZvLmxlbmd0aHMpICYmIGluZm8ubGVuZ3Rocy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGZpbmQgbWF4aW11bSBhbGxvd2VkIGxlbmd0aFxuICAgICAgICAgICAgICAgICAgICBmb3IgKHZhciBfaSA9IDAsIF9hID0gaW5mby5sZW5ndGhzOyBfaSA8IF9hLmxlbmd0aDsgX2krKykge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGwgPSBfYVtfaV07XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAobCA8PSB0b2tlblN0cmluZy5sZW5ndGggJiYgKGxlbmd0aF8xID09PSB1bmRlZmluZWQgfHwgbGVuZ3RoXzEgPCBsKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aF8xID0gbDtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgaWYgKi9cbiAgICAgICAgICAgICAgICBpZiAobGVuZ3RoXzEgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgICAgICAvLyBubyBhbGxvd2VkIGxlbmd0aCBmb3VuZCAobm90IHBvc3NpYmxlIHdpdGggY3VycmVudCBzeW1ib2wgbWFwcGluZyBzaW5jZSBsZW5ndGggMSBpcyBhbHdheXMgYWxsb3dlZClcbiAgICAgICAgICAgICAgICAgICAgdmFyIHRva2VuID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgbGVuZ3RoOiB0b2tlblN0cmluZy5sZW5ndGgsXG4gICAgICAgICAgICAgICAgICAgICAgICByYXc6IHRva2VuU3RyaW5nLFxuICAgICAgICAgICAgICAgICAgICAgICAgc3ltYm9sOiB0b2tlblN0cmluZ1swXSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6IFRva2VuVHlwZS5JREVOVElUWVxuICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgICAgICByZXN1bHQucHVzaCh0b2tlbik7XG4gICAgICAgICAgICAgICAgICAgIHRva2VuU3RyaW5nID0gXCJcIjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIHByZWZpeCBmb3VuZFxuICAgICAgICAgICAgICAgICAgICB2YXIgdG9rZW4gPSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBsZW5ndGg6IGxlbmd0aF8xLFxuICAgICAgICAgICAgICAgICAgICAgICAgcmF3OiB0b2tlblN0cmluZy5zbGljZSgwLCBsZW5ndGhfMSksXG4gICAgICAgICAgICAgICAgICAgICAgICBzeW1ib2w6IHRva2VuU3RyaW5nWzBdLFxuICAgICAgICAgICAgICAgICAgICAgICAgdHlwZTogaW5mby50eXBlXG4gICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgICAgIHJlc3VsdC5wdXNoKHRva2VuKTtcbiAgICAgICAgICAgICAgICAgICAgdG9rZW5TdHJpbmcgPSB0b2tlblN0cmluZy5zbGljZShsZW5ndGhfMSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfTtcbiAgICB2YXIgY3VycmVudFRva2VuID0gXCJcIjtcbiAgICB2YXIgcHJldmlvdXNDaGFyID0gXCJcIjtcbiAgICB2YXIgcXVvdGluZyA9IGZhbHNlO1xuICAgIHZhciBwb3NzaWJsZUVzY2FwaW5nID0gZmFsc2U7XG4gICAgZm9yICh2YXIgX2kgPSAwLCBmb3JtYXRTdHJpbmdfMSA9IGZvcm1hdFN0cmluZzsgX2kgPCBmb3JtYXRTdHJpbmdfMS5sZW5ndGg7IF9pKyspIHtcbiAgICAgICAgdmFyIGN1cnJlbnRDaGFyID0gZm9ybWF0U3RyaW5nXzFbX2ldO1xuICAgICAgICAvLyBIYW5sZGUgZXNjYXBpbmcgYW5kIHF1b3RpbmdcbiAgICAgICAgaWYgKGN1cnJlbnRDaGFyID09PSBcIidcIikge1xuICAgICAgICAgICAgaWYgKCFxdW90aW5nKSB7XG4gICAgICAgICAgICAgICAgaWYgKHBvc3NpYmxlRXNjYXBpbmcpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gRXNjYXBlZCBhIHNpbmdsZSAnIGNoYXJhY3RlciB3aXRob3V0IHF1b3RpbmdcbiAgICAgICAgICAgICAgICAgICAgaWYgKGN1cnJlbnRDaGFyICE9PSBwcmV2aW91c0NoYXIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGFwcGVuZFRva2VuKGN1cnJlbnRUb2tlbik7XG4gICAgICAgICAgICAgICAgICAgICAgICBjdXJyZW50VG9rZW4gPSBcIlwiO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGN1cnJlbnRUb2tlbiArPSBcIidcIjtcbiAgICAgICAgICAgICAgICAgICAgcG9zc2libGVFc2NhcGluZyA9IGZhbHNlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgcG9zc2libGVFc2NhcGluZyA9IHRydWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgLy8gVHdvIHBvc3NpYmlsaXRpZXM6IFdlcmUgYXJlIGRvbmUgcXVvdGluZywgb3Igd2UgYXJlIGVzY2FwaW5nIGEgJyBjaGFyYWN0ZXJcbiAgICAgICAgICAgICAgICBpZiAocG9zc2libGVFc2NhcGluZykge1xuICAgICAgICAgICAgICAgICAgICAvLyBFc2NhcGluZywgYWRkICcgdG8gdGhlIHRva2VuXG4gICAgICAgICAgICAgICAgICAgIGN1cnJlbnRUb2tlbiArPSBjdXJyZW50Q2hhcjtcbiAgICAgICAgICAgICAgICAgICAgcG9zc2libGVFc2NhcGluZyA9IGZhbHNlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gTWF5YmUgZXNjYXBpbmcsIHdhaXQgZm9yIG5leHQgdG9rZW4gaWYgd2UgYXJlIGVzY2FwaW5nXG4gICAgICAgICAgICAgICAgICAgIHBvc3NpYmxlRXNjYXBpbmcgPSB0cnVlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICghcG9zc2libGVFc2NhcGluZykge1xuICAgICAgICAgICAgICAgIC8vIEN1cnJlbnQgY2hhcmFjdGVyIGlzIHJlbGV2YW50LCBzbyBzYXZlIGl0IGZvciBpbnNwZWN0aW5nIG5leHQgcm91bmRcbiAgICAgICAgICAgICAgICBwcmV2aW91c0NoYXIgPSBjdXJyZW50Q2hhcjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKHBvc3NpYmxlRXNjYXBpbmcpIHtcbiAgICAgICAgICAgIHF1b3RpbmcgPSAhcXVvdGluZztcbiAgICAgICAgICAgIHBvc3NpYmxlRXNjYXBpbmcgPSBmYWxzZTtcbiAgICAgICAgICAgIC8vIEZsdXNoIGN1cnJlbnQgdG9rZW5cbiAgICAgICAgICAgIGFwcGVuZFRva2VuKGN1cnJlbnRUb2tlbiwgIXF1b3RpbmcpO1xuICAgICAgICAgICAgY3VycmVudFRva2VuID0gXCJcIjtcbiAgICAgICAgfVxuICAgICAgICBpZiAocXVvdGluZykge1xuICAgICAgICAgICAgLy8gUXVvdGluZyBtb2RlLCBhZGQgY2hhcmFjdGVyIHRvIHRva2VuLlxuICAgICAgICAgICAgY3VycmVudFRva2VuICs9IGN1cnJlbnRDaGFyO1xuICAgICAgICAgICAgcHJldmlvdXNDaGFyID0gY3VycmVudENoYXI7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoY3VycmVudENoYXIgIT09IHByZXZpb3VzQ2hhcikge1xuICAgICAgICAgICAgLy8gV2Ugc3R1bWJsZWQgdXBvbiBhIG5ldyB0b2tlbiFcbiAgICAgICAgICAgIGFwcGVuZFRva2VuKGN1cnJlbnRUb2tlbik7XG4gICAgICAgICAgICBjdXJyZW50VG9rZW4gPSBjdXJyZW50Q2hhcjtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIC8vIFdlIGFyZSByZXBlYXRpbmcgdGhlIHRva2VuIHdpdGggbW9yZSBjaGFyYWN0ZXJzXG4gICAgICAgICAgICBjdXJyZW50VG9rZW4gKz0gY3VycmVudENoYXI7XG4gICAgICAgIH1cbiAgICAgICAgcHJldmlvdXNDaGFyID0gY3VycmVudENoYXI7XG4gICAgfVxuICAgIC8vIERvbid0IGZvcmdldCB0byBhZGQgdGhlIGxhc3QgdG9rZW4gdG8gdGhlIHJlc3VsdCFcbiAgICBhcHBlbmRUb2tlbihjdXJyZW50VG9rZW4sIHF1b3RpbmcpO1xuICAgIHJldHVybiByZXN1bHQ7XG59XG5leHBvcnRzLnRva2VuaXplID0gdG9rZW5pemU7XG52YXIgU1lNQk9MX01BUFBJTkcgPSB7XG4gICAgRzogeyB0eXBlOiBUb2tlblR5cGUuRVJBLCBtYXhMZW5ndGg6IDUgfSxcbiAgICB5OiB7IHR5cGU6IFRva2VuVHlwZS5ZRUFSIH0sXG4gICAgWTogeyB0eXBlOiBUb2tlblR5cGUuWUVBUiB9LFxuICAgIHU6IHsgdHlwZTogVG9rZW5UeXBlLllFQVIgfSxcbiAgICBVOiB7IHR5cGU6IFRva2VuVHlwZS5ZRUFSLCBtYXhMZW5ndGg6IDUgfSxcbiAgICByOiB7IHR5cGU6IFRva2VuVHlwZS5ZRUFSIH0sXG4gICAgUTogeyB0eXBlOiBUb2tlblR5cGUuUVVBUlRFUiwgbWF4TGVuZ3RoOiA1IH0sXG4gICAgcTogeyB0eXBlOiBUb2tlblR5cGUuUVVBUlRFUiwgbWF4TGVuZ3RoOiA1IH0sXG4gICAgTTogeyB0eXBlOiBUb2tlblR5cGUuTU9OVEgsIG1heExlbmd0aDogNSB9LFxuICAgIEw6IHsgdHlwZTogVG9rZW5UeXBlLk1PTlRILCBtYXhMZW5ndGg6IDUgfSxcbiAgICBsOiB7IHR5cGU6IFRva2VuVHlwZS5NT05USCwgbWF4TGVuZ3RoOiAxIH0sXG4gICAgdzogeyB0eXBlOiBUb2tlblR5cGUuV0VFSywgbWF4TGVuZ3RoOiAyIH0sXG4gICAgVzogeyB0eXBlOiBUb2tlblR5cGUuV0VFSywgbWF4TGVuZ3RoOiAxIH0sXG4gICAgZDogeyB0eXBlOiBUb2tlblR5cGUuREFZLCBtYXhMZW5ndGg6IDIgfSxcbiAgICBEOiB7IHR5cGU6IFRva2VuVHlwZS5EQVksIG1heExlbmd0aDogMyB9LFxuICAgIEY6IHsgdHlwZTogVG9rZW5UeXBlLkRBWSwgbWF4TGVuZ3RoOiAxIH0sXG4gICAgZzogeyB0eXBlOiBUb2tlblR5cGUuREFZIH0sXG4gICAgRTogeyB0eXBlOiBUb2tlblR5cGUuV0VFS0RBWSwgbWF4TGVuZ3RoOiA2IH0sXG4gICAgZTogeyB0eXBlOiBUb2tlblR5cGUuV0VFS0RBWSwgbWF4TGVuZ3RoOiA2IH0sXG4gICAgYzogeyB0eXBlOiBUb2tlblR5cGUuV0VFS0RBWSwgbWF4TGVuZ3RoOiA2IH0sXG4gICAgYTogeyB0eXBlOiBUb2tlblR5cGUuREFZUEVSSU9ELCBtYXhMZW5ndGg6IDUgfSxcbiAgICBiOiB7IHR5cGU6IFRva2VuVHlwZS5EQVlQRVJJT0QsIG1heExlbmd0aDogNSB9LFxuICAgIEI6IHsgdHlwZTogVG9rZW5UeXBlLkRBWVBFUklPRCwgbWF4TGVuZ3RoOiA1IH0sXG4gICAgaDogeyB0eXBlOiBUb2tlblR5cGUuSE9VUiwgbWF4TGVuZ3RoOiAyIH0sXG4gICAgSDogeyB0eXBlOiBUb2tlblR5cGUuSE9VUiwgbWF4TGVuZ3RoOiAyIH0sXG4gICAgazogeyB0eXBlOiBUb2tlblR5cGUuSE9VUiwgbWF4TGVuZ3RoOiAyIH0sXG4gICAgSzogeyB0eXBlOiBUb2tlblR5cGUuSE9VUiwgbWF4TGVuZ3RoOiAyIH0sXG4gICAgajogeyB0eXBlOiBUb2tlblR5cGUuSE9VUiwgbWF4TGVuZ3RoOiA2IH0sXG4gICAgSjogeyB0eXBlOiBUb2tlblR5cGUuSE9VUiwgbWF4TGVuZ3RoOiAyIH0sXG4gICAgbTogeyB0eXBlOiBUb2tlblR5cGUuTUlOVVRFLCBtYXhMZW5ndGg6IDIgfSxcbiAgICBzOiB7IHR5cGU6IFRva2VuVHlwZS5TRUNPTkQsIG1heExlbmd0aDogMiB9LFxuICAgIFM6IHsgdHlwZTogVG9rZW5UeXBlLlNFQ09ORCB9LFxuICAgIEE6IHsgdHlwZTogVG9rZW5UeXBlLlNFQ09ORCB9LFxuICAgIHo6IHsgdHlwZTogVG9rZW5UeXBlLlpPTkUsIG1heExlbmd0aDogNCB9LFxuICAgIFo6IHsgdHlwZTogVG9rZW5UeXBlLlpPTkUsIG1heExlbmd0aDogNSB9LFxuICAgIE86IHsgdHlwZTogVG9rZW5UeXBlLlpPTkUsIGxlbmd0aHM6IFsxLCA0XSB9LFxuICAgIHY6IHsgdHlwZTogVG9rZW5UeXBlLlpPTkUsIGxlbmd0aHM6IFsxLCA0XSB9LFxuICAgIFY6IHsgdHlwZTogVG9rZW5UeXBlLlpPTkUsIG1heExlbmd0aDogNCB9LFxuICAgIFg6IHsgdHlwZTogVG9rZW5UeXBlLlpPTkUsIG1heExlbmd0aDogNSB9LFxuICAgIHg6IHsgdHlwZTogVG9rZW5UeXBlLlpPTkUsIG1heExlbmd0aDogNSB9LFxufTtcbi8vIyBzb3VyY2VNYXBwaW5nVVJMPXRva2VuLmpzLm1hcCIsIi8qKlxuICogQ29weXJpZ2h0KGMpIDIwMTQgQUJCIFN3aXR6ZXJsYW5kIEx0ZC5cbiAqXG4gKiBPbHNlbiBUaW1lem9uZSBEYXRhYmFzZSBjb250YWluZXJcbiAqXG4gKiBETyBOT1QgVVNFIFRISVMgQ0xBU1MgRElSRUNUTFksIFVTRSBUaW1lWm9uZVxuICovXG5cInVzZSBzdHJpY3RcIjtcbnZhciBfX3NwcmVhZEFycmF5ID0gKHRoaXMgJiYgdGhpcy5fX3NwcmVhZEFycmF5KSB8fCBmdW5jdGlvbiAodG8sIGZyb20sIHBhY2spIHtcbiAgICBpZiAocGFjayB8fCBhcmd1bWVudHMubGVuZ3RoID09PSAyKSBmb3IgKHZhciBpID0gMCwgbCA9IGZyb20ubGVuZ3RoLCBhcjsgaSA8IGw7IGkrKykge1xuICAgICAgICBpZiAoYXIgfHwgIShpIGluIGZyb20pKSB7XG4gICAgICAgICAgICBpZiAoIWFyKSBhciA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGZyb20sIDAsIGkpO1xuICAgICAgICAgICAgYXJbaV0gPSBmcm9tW2ldO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiB0by5jb25jYXQoYXIgfHwgQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoZnJvbSkpO1xufTtcbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIl9fZXNNb2R1bGVcIiwgeyB2YWx1ZTogdHJ1ZSB9KTtcbmV4cG9ydHMuVHpEYXRhYmFzZSA9IGV4cG9ydHMuTm9ybWFsaXplT3B0aW9uID0gZXhwb3J0cy5UcmFuc2l0aW9uID0gZXhwb3J0cy5pc1ZhbGlkT2Zmc2V0U3RyaW5nID0gZXhwb3J0cy5ab25lSW5mbyA9IGV4cG9ydHMuUnVsZVR5cGUgPSBleHBvcnRzLlJ1bGVJbmZvID0gZXhwb3J0cy5BdFR5cGUgPSBleHBvcnRzLk9uVHlwZSA9IGV4cG9ydHMuVG9UeXBlID0gdm9pZCAwO1xudmFyIGFzc2VydF8xID0gcmVxdWlyZShcIi4vYXNzZXJ0XCIpO1xudmFyIGJhc2ljc18xID0gcmVxdWlyZShcIi4vYmFzaWNzXCIpO1xudmFyIGJhc2ljcyA9IHJlcXVpcmUoXCIuL2Jhc2ljc1wiKTtcbnZhciBkdXJhdGlvbl8xID0gcmVxdWlyZShcIi4vZHVyYXRpb25cIik7XG52YXIgZXJyb3JfMSA9IHJlcXVpcmUoXCIuL2Vycm9yXCIpO1xudmFyIG1hdGggPSByZXF1aXJlKFwiLi9tYXRoXCIpO1xuLyoqXG4gKiBUeXBlIG9mIHJ1bGUgVE8gY29sdW1uIHZhbHVlXG4gKi9cbnZhciBUb1R5cGU7XG4oZnVuY3Rpb24gKFRvVHlwZSkge1xuICAgIC8qKlxuICAgICAqIEVpdGhlciBhIHllYXIgbnVtYmVyIG9yIFwib25seVwiXG4gICAgICovXG4gICAgVG9UeXBlW1RvVHlwZVtcIlllYXJcIl0gPSAwXSA9IFwiWWVhclwiO1xuICAgIC8qKlxuICAgICAqIFwibWF4XCJcbiAgICAgKi9cbiAgICBUb1R5cGVbVG9UeXBlW1wiTWF4XCJdID0gMV0gPSBcIk1heFwiO1xufSkoVG9UeXBlIHx8IChleHBvcnRzLlRvVHlwZSA9IFRvVHlwZSA9IHt9KSk7XG4vKipcbiAqIFR5cGUgb2YgcnVsZSBPTiBjb2x1bW4gdmFsdWVcbiAqL1xudmFyIE9uVHlwZTtcbihmdW5jdGlvbiAoT25UeXBlKSB7XG4gICAgLyoqXG4gICAgICogRGF5LW9mLW1vbnRoIG51bWJlclxuICAgICAqL1xuICAgIE9uVHlwZVtPblR5cGVbXCJEYXlOdW1cIl0gPSAwXSA9IFwiRGF5TnVtXCI7XG4gICAgLyoqXG4gICAgICogXCJsYXN0U3VuXCIgb3IgXCJsYXN0V2VkXCIgZXRjXG4gICAgICovXG4gICAgT25UeXBlW09uVHlwZVtcIkxhc3RYXCJdID0gMV0gPSBcIkxhc3RYXCI7XG4gICAgLyoqXG4gICAgICogZS5nLiBcIlN1bj49OFwiXG4gICAgICovXG4gICAgT25UeXBlW09uVHlwZVtcIkdyZXFYXCJdID0gMl0gPSBcIkdyZXFYXCI7XG4gICAgLyoqXG4gICAgICogZS5nLiBcIlN1bjw9OFwiXG4gICAgICovXG4gICAgT25UeXBlW09uVHlwZVtcIkxlcVhcIl0gPSAzXSA9IFwiTGVxWFwiO1xufSkoT25UeXBlIHx8IChleHBvcnRzLk9uVHlwZSA9IE9uVHlwZSA9IHt9KSk7XG52YXIgQXRUeXBlO1xuKGZ1bmN0aW9uIChBdFR5cGUpIHtcbiAgICAvKipcbiAgICAgKiBMb2NhbCB0aW1lIChubyBEU1QpXG4gICAgICovXG4gICAgQXRUeXBlW0F0VHlwZVtcIlN0YW5kYXJkXCJdID0gMF0gPSBcIlN0YW5kYXJkXCI7XG4gICAgLyoqXG4gICAgICogV2FsbCBjbG9jayB0aW1lIChsb2NhbCB0aW1lIHdpdGggRFNUKVxuICAgICAqL1xuICAgIEF0VHlwZVtBdFR5cGVbXCJXYWxsXCJdID0gMV0gPSBcIldhbGxcIjtcbiAgICAvKipcbiAgICAgKiBVdGMgdGltZVxuICAgICAqL1xuICAgIEF0VHlwZVtBdFR5cGVbXCJVdGNcIl0gPSAyXSA9IFwiVXRjXCI7XG59KShBdFR5cGUgfHwgKGV4cG9ydHMuQXRUeXBlID0gQXRUeXBlID0ge30pKTtcbi8qKlxuICogRE8gTk9UIFVTRSBUSElTIENMQVNTIERJUkVDVExZLCBVU0UgVGltZVpvbmVcbiAqXG4gKiBTZWUgaHR0cDovL3d3dy5jc3RkYmlsbC5jb20vdHpkYi90ei1ob3ctdG8uaHRtbFxuICovXG52YXIgUnVsZUluZm8gPSAvKiogQGNsYXNzICovIChmdW5jdGlvbiAoKSB7XG4gICAgLyoqXG4gICAgICogQ29uc3RydWN0b3JcbiAgICAgKiBAcGFyYW0gZnJvbVxuICAgICAqIEBwYXJhbSB0b1R5cGVcbiAgICAgKiBAcGFyYW0gdG9ZZWFyXG4gICAgICogQHBhcmFtIHR5cGVcbiAgICAgKiBAcGFyYW0gaW5Nb250aFxuICAgICAqIEBwYXJhbSBvblR5cGVcbiAgICAgKiBAcGFyYW0gb25EYXlcbiAgICAgKiBAcGFyYW0gb25XZWVrRGF5XG4gICAgICogQHBhcmFtIGF0SG91clxuICAgICAqIEBwYXJhbSBhdE1pbnV0ZVxuICAgICAqIEBwYXJhbSBhdFNlY29uZFxuICAgICAqIEBwYXJhbSBhdFR5cGVcbiAgICAgKiBAcGFyYW0gc2F2ZVxuICAgICAqIEBwYXJhbSBsZXR0ZXJcbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBSdWxlSW5mbyhcbiAgICAvKipcbiAgICAgKiBGUk9NIGNvbHVtbiB5ZWFyIG51bWJlci5cbiAgICAgKi9cbiAgICBmcm9tLCBcbiAgICAvKipcbiAgICAgKiBUTyBjb2x1bW4gdHlwZTogWWVhciBmb3IgeWVhciBudW1iZXJzIGFuZCBcIm9ubHlcIiB2YWx1ZXMsIE1heCBmb3IgXCJtYXhcIiB2YWx1ZS5cbiAgICAgKi9cbiAgICB0b1R5cGUsIFxuICAgIC8qKlxuICAgICAqIElmIFRPIGNvbHVtbiBpcyBhIHllYXIsIHRoZSB5ZWFyIG51bWJlci4gSWYgVE8gY29sdW1uIGlzIFwib25seVwiLCB0aGUgRlJPTSB5ZWFyLlxuICAgICAqL1xuICAgIHRvWWVhciwgXG4gICAgLyoqXG4gICAgICogVFlQRSBjb2x1bW4sIG5vdCB1c2VkIHNvIGZhclxuICAgICAqL1xuICAgIHR5cGUsIFxuICAgIC8qKlxuICAgICAqIElOIGNvbHVtbiBtb250aCBudW1iZXIgMS0xMlxuICAgICAqL1xuICAgIGluTW9udGgsIFxuICAgIC8qKlxuICAgICAqIE9OIGNvbHVtbiB0eXBlXG4gICAgICovXG4gICAgb25UeXBlLCBcbiAgICAvKipcbiAgICAgKiBJZiBvblR5cGUgaXMgRGF5TnVtLCB0aGUgZGF5IG51bWJlclxuICAgICAqL1xuICAgIG9uRGF5LCBcbiAgICAvKipcbiAgICAgKiBJZiBvblR5cGUgaXMgbm90IERheU51bSwgdGhlIHdlZWtkYXlcbiAgICAgKi9cbiAgICBvbldlZWtEYXksIFxuICAgIC8qKlxuICAgICAqIEFUIGNvbHVtbiBob3VyXG4gICAgICovXG4gICAgYXRIb3VyLCBcbiAgICAvKipcbiAgICAgKiBBVCBjb2x1bW4gbWludXRlXG4gICAgICovXG4gICAgYXRNaW51dGUsIFxuICAgIC8qKlxuICAgICAqIEFUIGNvbHVtbiBzZWNvbmRcbiAgICAgKi9cbiAgICBhdFNlY29uZCwgXG4gICAgLyoqXG4gICAgICogQVQgY29sdW1uIHR5cGVcbiAgICAgKi9cbiAgICBhdFR5cGUsIFxuICAgIC8qKlxuICAgICAqIERTVCBvZmZzZXQgZnJvbSBsb2NhbCBzdGFuZGFyZCB0aW1lIChOT1QgZnJvbSBVVEMhKVxuICAgICAqL1xuICAgIHNhdmUsIFxuICAgIC8qKlxuICAgICAqIENoYXJhY3RlciB0byBpbnNlcnQgaW4gJXMgZm9yIHRpbWUgem9uZSBhYmJyZXZpYXRpb25cbiAgICAgKiBOb3RlIGlmIFRaIGRhdGFiYXNlIGluZGljYXRlcyBcIi1cIiB0aGlzIGlzIHRoZSBlbXB0eSBzdHJpbmdcbiAgICAgKi9cbiAgICBsZXR0ZXIpIHtcbiAgICAgICAgdGhpcy5mcm9tID0gZnJvbTtcbiAgICAgICAgdGhpcy50b1R5cGUgPSB0b1R5cGU7XG4gICAgICAgIHRoaXMudG9ZZWFyID0gdG9ZZWFyO1xuICAgICAgICB0aGlzLnR5cGUgPSB0eXBlO1xuICAgICAgICB0aGlzLmluTW9udGggPSBpbk1vbnRoO1xuICAgICAgICB0aGlzLm9uVHlwZSA9IG9uVHlwZTtcbiAgICAgICAgdGhpcy5vbkRheSA9IG9uRGF5O1xuICAgICAgICB0aGlzLm9uV2Vla0RheSA9IG9uV2Vla0RheTtcbiAgICAgICAgdGhpcy5hdEhvdXIgPSBhdEhvdXI7XG4gICAgICAgIHRoaXMuYXRNaW51dGUgPSBhdE1pbnV0ZTtcbiAgICAgICAgdGhpcy5hdFNlY29uZCA9IGF0U2Vjb25kO1xuICAgICAgICB0aGlzLmF0VHlwZSA9IGF0VHlwZTtcbiAgICAgICAgdGhpcy5zYXZlID0gc2F2ZTtcbiAgICAgICAgdGhpcy5sZXR0ZXIgPSBsZXR0ZXI7XG4gICAgICAgIGlmICh0aGlzLnNhdmUpIHtcbiAgICAgICAgICAgIHRoaXMuc2F2ZSA9IHRoaXMuc2F2ZS5jb252ZXJ0KGJhc2ljc18xLlRpbWVVbml0LkhvdXIpO1xuICAgICAgICB9XG4gICAgfVxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdHJ1ZSBpZmYgdGhpcyBydWxlIGlzIGFwcGxpY2FibGUgaW4gdGhlIHllYXJcbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBSdWxlSW5mby5wcm90b3R5cGUuYXBwbGljYWJsZSA9IGZ1bmN0aW9uICh5ZWFyKSB7XG4gICAgICAgIGlmICh5ZWFyIDwgdGhpcy5mcm9tKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgc3dpdGNoICh0aGlzLnRvVHlwZSkge1xuICAgICAgICAgICAgY2FzZSBUb1R5cGUuTWF4OiByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgIGNhc2UgVG9UeXBlLlllYXI6IHJldHVybiAoeWVhciA8PSB0aGlzLnRvWWVhcik7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFNvcnQgY29tcGFyaXNvblxuICAgICAqIEByZXR1cm4gKGZpcnN0IGVmZmVjdGl2ZSBkYXRlIGlzIGxlc3MgdGhhbiBvdGhlcidzIGZpcnN0IGVmZmVjdGl2ZSBkYXRlKVxuICAgICAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5JbnZhbGlkVGltZVpvbmVEYXRhIGlmIHRoaXMgcnVsZSBkZXBlbmRzIG9uIGEgd2Vla2RheSBhbmQgdGhlIHdlZWtkYXkgaW4gcXVlc3Rpb24gZG9lc24ndCBleGlzdFxuICAgICAqL1xuICAgIFJ1bGVJbmZvLnByb3RvdHlwZS5lZmZlY3RpdmVMZXNzID0gZnVuY3Rpb24gKG90aGVyKSB7XG4gICAgICAgIGlmICh0aGlzLmZyb20gPCBvdGhlci5mcm9tKSB7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy5mcm9tID4gb3RoZXIuZnJvbSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0aGlzLmluTW9udGggPCBvdGhlci5pbk1vbnRoKSB7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy5pbk1vbnRoID4gb3RoZXIuaW5Nb250aCkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0aGlzLmVmZmVjdGl2ZURhdGUodGhpcy5mcm9tKSA8IG90aGVyLmVmZmVjdGl2ZURhdGUodGhpcy5mcm9tKSkge1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogU29ydCBjb21wYXJpc29uXG4gICAgICogQHJldHVybiAoZmlyc3QgZWZmZWN0aXZlIGRhdGUgaXMgZXF1YWwgdG8gb3RoZXIncyBmaXJzdCBlZmZlY3RpdmUgZGF0ZSlcbiAgICAgKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuSW52YWxpZFRpbWVab25lRGF0YSBmb3IgaW52YWxpZCBpbnRlcm5hbCBzdHJ1Y3R1cmUgb2YgdGhlIGRhdGFiYXNlXG4gICAgICovXG4gICAgUnVsZUluZm8ucHJvdG90eXBlLmVmZmVjdGl2ZUVxdWFsID0gZnVuY3Rpb24gKG90aGVyKSB7XG4gICAgICAgIGlmICh0aGlzLmZyb20gIT09IG90aGVyLmZyb20pIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy5pbk1vbnRoICE9PSBvdGhlci5pbk1vbnRoKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCF0aGlzLmVmZmVjdGl2ZURhdGUodGhpcy5mcm9tKS5lcXVhbHMob3RoZXIuZWZmZWN0aXZlRGF0ZSh0aGlzLmZyb20pKSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgeWVhci1yZWxhdGl2ZSBkYXRlIHRoYXQgdGhlIHJ1bGUgdGFrZXMgZWZmZWN0LiBEZXBlbmRpbmcgb24gdGhlIHJ1bGUgdGhpcyBjYW4gYmUgYSBVVEMgdGltZSwgYSB3YWxsIGNsb2NrIHRpbWUsIG9yIGFcbiAgICAgKiB0aW1lIGluIHN0YW5kYXJkIG9mZnNldCAoaS5lLiB5b3Ugc3RpbGwgbmVlZCB0byBjb21wZW5zYXRlIGZvciB0aGlzLmF0VHlwZSlcbiAgICAgKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuTm90QXBwbGljYWJsZSBpZiB0aGlzIHJ1bGUgaXMgbm90IGFwcGxpY2FibGUgaW4gdGhlIGdpdmVuIHllYXJcbiAgICAgKi9cbiAgICBSdWxlSW5mby5wcm90b3R5cGUuZWZmZWN0aXZlRGF0ZSA9IGZ1bmN0aW9uICh5ZWFyKSB7XG4gICAgICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KSh0aGlzLmFwcGxpY2FibGUoeWVhciksIFwidGltZXpvbmVjb21wbGV0ZS5Ob3RBcHBsaWNhYmxlXCIsIFwiUnVsZSBpcyBub3QgYXBwbGljYWJsZSBpbiBcIi5jb25jYXQoeWVhcikpO1xuICAgICAgICAvLyB5ZWFyIGFuZCBtb250aCBhcmUgZ2l2ZW5cbiAgICAgICAgdmFyIHkgPSB5ZWFyO1xuICAgICAgICB2YXIgbSA9IHRoaXMuaW5Nb250aDtcbiAgICAgICAgdmFyIGQgPSAwO1xuICAgICAgICAvLyBjYWxjdWxhdGUgZGF5XG4gICAgICAgIHN3aXRjaCAodGhpcy5vblR5cGUpIHtcbiAgICAgICAgICAgIGNhc2UgT25UeXBlLkRheU51bTpcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIGQgPSB0aGlzLm9uRGF5O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgT25UeXBlLkdyZXFYOlxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGQgPSBiYXNpY3Mud2Vla0RheU9uT3JBZnRlcih5LCBtLCB0aGlzLm9uRGF5LCB0aGlzLm9uV2Vla0RheSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICgoMCwgZXJyb3JfMS5lcnJvcklzKShlLCBcIk5vdEZvdW5kXCIpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQXByIFN1bj49MjcgYWN0dWFsbHkgbWVhbnMgYW55IHN1bmRheSBhZnRlciBBcHJpbCAyNywgaS5lLiBpdCBkb2VzIG5vdCBoYXZlIHRvIGJlIGluIEFwcmlsLiBUcnkgbmV4dCBtb250aC5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAobSArIDEgPD0gMTIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbSA9IG0gKyAxO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbSA9IDE7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSB5ICsgMTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZCA9IGJhc2ljcy5maXJzdFdlZWtEYXlPZk1vbnRoKHksIG0sIHRoaXMub25XZWVrRGF5KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgT25UeXBlLkxlcVg6XG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICAgICAgZCA9IGJhc2ljcy53ZWVrRGF5T25PckJlZm9yZSh5LCBtLCB0aGlzLm9uRGF5LCB0aGlzLm9uV2Vla0RheSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICgoMCwgZXJyb3JfMS5lcnJvcklzKShlLCBcIk5vdEZvdW5kXCIpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG0gPiAxKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG0gPSBtIC0gMTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG0gPSAxMjtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IHkgLSAxO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkID0gYmFzaWNzLmxhc3RXZWVrRGF5T2ZNb250aCh5LCBtLCB0aGlzLm9uV2Vla0RheSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIE9uVHlwZS5MYXN0WDpcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIGQgPSBiYXNpY3MubGFzdFdlZWtEYXlPZk1vbnRoKHksIG0sIHRoaXMub25XZWVrRGF5KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGJhc2ljc18xLlRpbWVTdHJ1Y3QuZnJvbUNvbXBvbmVudHMoeSwgbSwgZCwgdGhpcy5hdEhvdXIsIHRoaXMuYXRNaW51dGUsIHRoaXMuYXRTZWNvbmQpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogRWZmZWN0aXZlIGRhdGUgaW4gVVRDIGluIHRoZSBnaXZlbiB5ZWFyLCBpbiBhIHNwZWNpZmljIHRpbWUgem9uZVxuICAgICAqIEBwYXJhbSB5ZWFyXG4gICAgICogQHBhcmFtIHN0YW5kYXJkT2Zmc2V0IHRoZSBzdGFuZGFyZCBvZmZzZXQgZnJvbSBVVCBvZiB0aGUgdGltZSB6b25lXG4gICAgICogQHBhcmFtIGRzdE9mZnNldCB0aGUgRFNUIG9mZnNldCBiZWZvcmUgdGhlIHJ1bGVcbiAgICAgKi9cbiAgICBSdWxlSW5mby5wcm90b3R5cGUuZWZmZWN0aXZlRGF0ZVV0YyA9IGZ1bmN0aW9uICh5ZWFyLCBzdGFuZGFyZE9mZnNldCwgZHN0T2Zmc2V0KSB7XG4gICAgICAgIHZhciBkID0gdGhpcy5lZmZlY3RpdmVEYXRlKHllYXIpO1xuICAgICAgICBzd2l0Y2ggKHRoaXMuYXRUeXBlKSB7XG4gICAgICAgICAgICBjYXNlIEF0VHlwZS5VdGM6IHJldHVybiBkO1xuICAgICAgICAgICAgY2FzZSBBdFR5cGUuU3RhbmRhcmQ6IHtcbiAgICAgICAgICAgICAgICAvLyB0cmFuc2l0aW9uIHRpbWUgaXMgaW4gem9uZSBsb2NhbCB0aW1lIHdpdGhvdXQgRFNUXG4gICAgICAgICAgICAgICAgdmFyIG1pbGxpcyA9IGQudW5peE1pbGxpcztcbiAgICAgICAgICAgICAgICBtaWxsaXMgLT0gc3RhbmRhcmRPZmZzZXQubWlsbGlzZWNvbmRzKCk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBiYXNpY3NfMS5UaW1lU3RydWN0KG1pbGxpcyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXNlIEF0VHlwZS5XYWxsOiB7XG4gICAgICAgICAgICAgICAgLy8gdHJhbnNpdGlvbiB0aW1lIGlzIGluIHpvbmUgbG9jYWwgdGltZSB3aXRoIERTVFxuICAgICAgICAgICAgICAgIHZhciBtaWxsaXMgPSBkLnVuaXhNaWxsaXM7XG4gICAgICAgICAgICAgICAgbWlsbGlzIC09IHN0YW5kYXJkT2Zmc2V0Lm1pbGxpc2Vjb25kcygpO1xuICAgICAgICAgICAgICAgIGlmIChkc3RPZmZzZXQpIHtcbiAgICAgICAgICAgICAgICAgICAgbWlsbGlzIC09IGRzdE9mZnNldC5taWxsaXNlY29uZHMoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBiYXNpY3NfMS5UaW1lU3RydWN0KG1pbGxpcyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9O1xuICAgIHJldHVybiBSdWxlSW5mbztcbn0oKSk7XG5leHBvcnRzLlJ1bGVJbmZvID0gUnVsZUluZm87XG4vKipcbiAqIFR5cGUgb2YgcmVmZXJlbmNlIGZyb20gem9uZSB0byBydWxlXG4gKi9cbnZhciBSdWxlVHlwZTtcbihmdW5jdGlvbiAoUnVsZVR5cGUpIHtcbiAgICAvKipcbiAgICAgKiBObyBydWxlIGFwcGxpZXNcbiAgICAgKi9cbiAgICBSdWxlVHlwZVtSdWxlVHlwZVtcIk5vbmVcIl0gPSAwXSA9IFwiTm9uZVwiO1xuICAgIC8qKlxuICAgICAqIEZpeGVkIGdpdmVuIG9mZnNldFxuICAgICAqL1xuICAgIFJ1bGVUeXBlW1J1bGVUeXBlW1wiT2Zmc2V0XCJdID0gMV0gPSBcIk9mZnNldFwiO1xuICAgIC8qKlxuICAgICAqIFJlZmVyZW5jZSB0byBhIG5hbWVkIHNldCBvZiBydWxlc1xuICAgICAqL1xuICAgIFJ1bGVUeXBlW1J1bGVUeXBlW1wiUnVsZU5hbWVcIl0gPSAyXSA9IFwiUnVsZU5hbWVcIjtcbn0pKFJ1bGVUeXBlIHx8IChleHBvcnRzLlJ1bGVUeXBlID0gUnVsZVR5cGUgPSB7fSkpO1xuLyoqXG4gKiBETyBOT1QgVVNFIFRISVMgQ0xBU1MgRElSRUNUTFksIFVTRSBUaW1lWm9uZVxuICpcbiAqIFNlZSBodHRwOi8vd3d3LmNzdGRiaWxsLmNvbS90emRiL3R6LWhvdy10by5odG1sXG4gKiBGaXJzdCwgYW5kIHNvbWV3aGF0IHRyaXZpYWxseSwgd2hlcmVhcyBSdWxlcyBhcmUgY29uc2lkZXJlZCB0byBjb250YWluIG9uZSBvciBtb3JlIHJlY29yZHMsIGEgWm9uZSBpcyBjb25zaWRlcmVkIHRvXG4gKiBiZSBhIHNpbmdsZSByZWNvcmQgd2l0aCB6ZXJvIG9yIG1vcmUgY29udGludWF0aW9uIGxpbmVzLiBUaHVzLCB0aGUga2V5d29yZCwg4oCcWm9uZSzigJ0gYW5kIHRoZSB6b25lIG5hbWUgYXJlIG5vdCByZXBlYXRlZC5cbiAqIFRoZSBsYXN0IGxpbmUgaXMgdGhlIG9uZSB3aXRob3V0IGFueXRoaW5nIGluIHRoZSBbVU5USUxdIGNvbHVtbi5cbiAqIFNlY29uZCwgYW5kIG1vcmUgZnVuZGFtZW50YWxseSwgZWFjaCBsaW5lIG9mIGEgWm9uZSByZXByZXNlbnRzIGEgc3RlYWR5IHN0YXRlLCBub3QgYSB0cmFuc2l0aW9uIGJldHdlZW4gc3RhdGVzLlxuICogVGhlIHN0YXRlIGV4aXN0cyBmcm9tIHRoZSBkYXRlIGFuZCB0aW1lIGluIHRoZSBwcmV2aW91cyBsaW5l4oCZcyBbVU5USUxdIGNvbHVtbiB1cCB0byB0aGUgZGF0ZSBhbmQgdGltZSBpbiB0aGUgY3VycmVudCBsaW5l4oCZc1xuICogW1VOVElMXSBjb2x1bW4uIEluIG90aGVyIHdvcmRzLCB0aGUgZGF0ZSBhbmQgdGltZSBpbiB0aGUgW1VOVElMXSBjb2x1bW4gaXMgdGhlIGluc3RhbnQgdGhhdCBzZXBhcmF0ZXMgdGhpcyBzdGF0ZSBmcm9tIHRoZSBuZXh0LlxuICogV2hlcmUgdGhhdCB3b3VsZCBiZSBhbWJpZ3VvdXMgYmVjYXVzZSB3ZeKAmXJlIHNldHRpbmcgb3VyIGNsb2NrcyBiYWNrLCB0aGUgW1VOVElMXSBjb2x1bW4gc3BlY2lmaWVzIHRoZSBmaXJzdCBvY2N1cnJlbmNlIG9mIHRoZSBpbnN0YW50LlxuICogVGhlIHN0YXRlIHNwZWNpZmllZCBieSB0aGUgbGFzdCBsaW5lLCB0aGUgb25lIHdpdGhvdXQgYW55dGhpbmcgaW4gdGhlIFtVTlRJTF0gY29sdW1uLCBjb250aW51ZXMgdG8gdGhlIHByZXNlbnQuXG4gKiBUaGUgZmlyc3QgbGluZSB0eXBpY2FsbHkgc3BlY2lmaWVzIHRoZSBtZWFuIHNvbGFyIHRpbWUgb2JzZXJ2ZWQgYmVmb3JlIHRoZSBpbnRyb2R1Y3Rpb24gb2Ygc3RhbmRhcmQgdGltZS4gU2luY2UgdGhlcmXigJlzIG5vIGxpbmUgYmVmb3JlXG4gKiB0aGF0LCBpdCBoYXMgbm8gYmVnaW5uaW5nLiA4LSkgRm9yIHNvbWUgcGxhY2VzIG5lYXIgdGhlIEludGVybmF0aW9uYWwgRGF0ZSBMaW5lLCB0aGUgZmlyc3QgdHdvIGxpbmVzIHdpbGwgc2hvdyBzb2xhciB0aW1lcyBkaWZmZXJpbmcgYnlcbiAqIDI0IGhvdXJzOyB0aGlzIGNvcnJlc3BvbmRzIHRvIGEgbW92ZW1lbnQgb2YgdGhlIERhdGUgTGluZS4gRm9yIGV4YW1wbGU6XG4gKiAjIFpvbmVcdE5BTUVcdFx0R01UT0ZGXHRSVUxFU1x0Rk9STUFUXHRbVU5USUxdXG4gKiBab25lIEFtZXJpY2EvSnVuZWF1XHQgMTU6MDI6MTkgLVx0TE1UXHQxODY3IE9jdCAxOFxuICogXHRcdFx0IC04OjU3OjQxIC1cdExNVFx0Li4uXG4gKiBXaGVuIEFsYXNrYSB3YXMgcHVyY2hhc2VkIGZyb20gUnVzc2lhIGluIDE4NjcsIHRoZSBEYXRlIExpbmUgbW92ZWQgZnJvbSB0aGUgQWxhc2thL0NhbmFkYSBib3JkZXIgdG8gdGhlIEJlcmluZyBTdHJhaXQ7IGFuZCB0aGUgdGltZSBpblxuICogQWxhc2thIHdhcyB0aGVuIDI0IGhvdXJzIGVhcmxpZXIgdGhhbiBpdCBoYWQgYmVlbi4gPGFzaWRlPig2IE9jdG9iZXIgaW4gdGhlIEp1bGlhbiBjYWxlbmRhciwgd2hpY2ggUnVzc2lhIHdhcyBzdGlsbCB1c2luZyB0aGVuIGZvclxuICogcmVsaWdpb3VzIHJlYXNvbnMsIHdhcyBmb2xsb3dlZCBieSBhIHNlY29uZCBpbnN0YW5jZSBvZiB0aGUgc2FtZSBkYXkgd2l0aCBhIGRpZmZlcmVudCBuYW1lLCAxOCBPY3RvYmVyIGluIHRoZSBHcmVnb3JpYW4gY2FsZW5kYXIuXG4gKiBJc27igJl0IGNpdmlsIHRpbWUgd29uZGVyZnVsPyA4LSkpPC9hc2lkZT5cbiAqIFRoZSBhYmJyZXZpYXRpb24sIOKAnExNVCzigJ0gc3RhbmRzIGZvciDigJxsb2NhbCBtZWFuIHRpbWUs4oCdIHdoaWNoIGlzIGFuIGludmVudGlvbiBvZiB0aGUgdHogZGF0YWJhc2UgYW5kIHdhcyBwcm9iYWJseSBuZXZlciBhY3R1YWxseVxuICogdXNlZCBkdXJpbmcgdGhlIHBlcmlvZC4gRnVydGhlcm1vcmUsIHRoZSB2YWx1ZSBpcyBhbG1vc3QgY2VydGFpbmx5IHdyb25nIGV4Y2VwdCBpbiB0aGUgYXJjaGV0eXBhbCBwbGFjZSBhZnRlciB3aGljaCB0aGUgem9uZSBpcyBuYW1lZC5cbiAqIChUaGUgdHogZGF0YWJhc2UgdXN1YWxseSBkb2VzbuKAmXQgcHJvdmlkZSBhIHNlcGFyYXRlIFpvbmUgcmVjb3JkIGZvciBwbGFjZXMgd2hlcmUgbm90aGluZyBzaWduaWZpY2FudCBoYXBwZW5lZCBhZnRlciAxOTcwLilcbiAqL1xudmFyIFpvbmVJbmZvID0gLyoqIEBjbGFzcyAqLyAoZnVuY3Rpb24gKCkge1xuICAgIC8qKlxuICAgICAqIENvbnN0cnVjdG9yXG4gICAgICogQHBhcmFtIGdtdG9mZlxuICAgICAqIEBwYXJhbSBydWxlVHlwZVxuICAgICAqIEBwYXJhbSBydWxlT2Zmc2V0XG4gICAgICogQHBhcmFtIHJ1bGVOYW1lXG4gICAgICogQHBhcmFtIGZvcm1hdFxuICAgICAqIEBwYXJhbSB1bnRpbFxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIGZ1bmN0aW9uIFpvbmVJbmZvKFxuICAgIC8qKlxuICAgICAqIEdNVCBvZmZzZXQgaW4gZnJhY3Rpb25hbCBtaW51dGVzLCBQT1NJVElWRSB0byBVVEMgKG5vdGUgSmF2YVNjcmlwdC5EYXRlIGdpdmVzIG9mZnNldHNcbiAgICAgKiBjb250cmFyeSB0byB3aGF0IHlvdSBtaWdodCBleHBlY3QpLiAgRS5nLiBFdXJvcGUvQW1zdGVyZGFtIGhhcyArNjAgbWludXRlcyBpbiB0aGlzIGZpZWxkIGJlY2F1c2VcbiAgICAgKiBpdCBpcyBvbmUgaG91ciBhaGVhZCBvZiBVVENcbiAgICAgKi9cbiAgICBnbXRvZmYsIFxuICAgIC8qKlxuICAgICAqIFRoZSBSVUxFUyBjb2x1bW4gdGVsbHMgdXMgd2hldGhlciBkYXlsaWdodCBzYXZpbmcgdGltZSBpcyBiZWluZyBvYnNlcnZlZDpcbiAgICAgKiBBIGh5cGhlbiwgYSBraW5kIG9mIG51bGwgdmFsdWUsIG1lYW5zIHRoYXQgd2UgaGF2ZSBub3Qgc2V0IG91ciBjbG9ja3MgYWhlYWQgb2Ygc3RhbmRhcmQgdGltZS5cbiAgICAgKiBBbiBhbW91bnQgb2YgdGltZSAodXN1YWxseSBidXQgbm90IG5lY2Vzc2FyaWx5IOKAnDE6MDDigJ0gbWVhbmluZyBvbmUgaG91cikgbWVhbnMgdGhhdCB3ZSBoYXZlIHNldCBvdXIgY2xvY2tzIGFoZWFkIGJ5IHRoYXQgYW1vdW50LlxuICAgICAqIFNvbWUgYWxwaGFiZXRpYyBzdHJpbmcgbWVhbnMgdGhhdCB3ZSBtaWdodCBoYXZlIHNldCBvdXIgY2xvY2tzIGFoZWFkOyBhbmQgd2UgbmVlZCB0byBjaGVjayB0aGUgcnVsZVxuICAgICAqIHRoZSBuYW1lIG9mIHdoaWNoIGlzIHRoZSBnaXZlbiBhbHBoYWJldGljIHN0cmluZy5cbiAgICAgKi9cbiAgICBydWxlVHlwZSwgXG4gICAgLyoqXG4gICAgICogSWYgdGhlIHJ1bGUgY29sdW1uIGlzIGFuIG9mZnNldCwgdGhpcyBpcyB0aGUgb2Zmc2V0XG4gICAgICovXG4gICAgcnVsZU9mZnNldCwgXG4gICAgLyoqXG4gICAgICogSWYgdGhlIHJ1bGUgY29sdW1uIGlzIGEgcnVsZSBuYW1lLCB0aGlzIGlzIHRoZSBydWxlIG5hbWVcbiAgICAgKi9cbiAgICBydWxlTmFtZSwgXG4gICAgLyoqXG4gICAgICogVGhlIEZPUk1BVCBjb2x1bW4gc3BlY2lmaWVzIHRoZSB1c3VhbCBhYmJyZXZpYXRpb24gb2YgdGhlIHRpbWUgem9uZSBuYW1lLiBJdCBjYW4gaGF2ZSBvbmUgb2YgZm91ciBmb3JtczpcbiAgICAgKiB0aGUgc3RyaW5nLCDigJx6enos4oCdIHdoaWNoIGlzIGEga2luZCBvZiBudWxsIHZhbHVlIChkb27igJl0IGFzaylcbiAgICAgKiBhIHNpbmdsZSBhbHBoYWJldGljIHN0cmluZyBvdGhlciB0aGFuIOKAnHp6eizigJ0gaW4gd2hpY2ggY2FzZSB0aGF04oCZcyB0aGUgYWJicmV2aWF0aW9uXG4gICAgICogYSBwYWlyIG9mIHN0cmluZ3Mgc2VwYXJhdGVkIGJ5IGEgc2xhc2ggKOKAmC/igJkpLCBpbiB3aGljaCBjYXNlIHRoZSBmaXJzdCBzdHJpbmcgaXMgdGhlIGFiYnJldmlhdGlvblxuICAgICAqIGZvciB0aGUgc3RhbmRhcmQgdGltZSBuYW1lIGFuZCB0aGUgc2Vjb25kIHN0cmluZyBpcyB0aGUgYWJicmV2aWF0aW9uIGZvciB0aGUgZGF5bGlnaHQgc2F2aW5nIHRpbWUgbmFtZVxuICAgICAqIGEgc3RyaW5nIGNvbnRhaW5pbmcg4oCcJXMs4oCdIGluIHdoaWNoIGNhc2UgdGhlIOKAnCVz4oCdIHdpbGwgYmUgcmVwbGFjZWQgYnkgdGhlIHRleHQgaW4gdGhlIGFwcHJvcHJpYXRlIFJ1bGXigJlzIExFVFRFUiBjb2x1bW5cbiAgICAgKi9cbiAgICBmb3JtYXQsIFxuICAgIC8qKlxuICAgICAqIFVudGlsIHRpbWVzdGFtcCBpbiB1bml4IHV0YyBtaWxsaXMuIFRoZSB6b25lIGluZm8gaXMgdmFsaWQgdXAgdG9cbiAgICAgKiBhbmQgZXhjbHVkaW5nIHRoaXMgdGltZXN0YW1wLlxuICAgICAqIE5vdGUgdGhpcyB2YWx1ZSBjYW4gYmUgdW5kZWZpbmVkIChmb3IgdGhlIGZpcnN0IHJ1bGUpXG4gICAgICovXG4gICAgdW50aWwpIHtcbiAgICAgICAgdGhpcy5nbXRvZmYgPSBnbXRvZmY7XG4gICAgICAgIHRoaXMucnVsZVR5cGUgPSBydWxlVHlwZTtcbiAgICAgICAgdGhpcy5ydWxlT2Zmc2V0ID0gcnVsZU9mZnNldDtcbiAgICAgICAgdGhpcy5ydWxlTmFtZSA9IHJ1bGVOYW1lO1xuICAgICAgICB0aGlzLmZvcm1hdCA9IGZvcm1hdDtcbiAgICAgICAgdGhpcy51bnRpbCA9IHVudGlsO1xuICAgICAgICBpZiAodGhpcy5ydWxlT2Zmc2V0KSB7XG4gICAgICAgICAgICB0aGlzLnJ1bGVPZmZzZXQgPSB0aGlzLnJ1bGVPZmZzZXQuY29udmVydChiYXNpY3MuVGltZVVuaXQuSG91cik7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIFpvbmVJbmZvO1xufSgpKTtcbmV4cG9ydHMuWm9uZUluZm8gPSBab25lSW5mbztcbnZhciBUek1vbnRoTmFtZXM7XG4oZnVuY3Rpb24gKFR6TW9udGhOYW1lcykge1xuICAgIFR6TW9udGhOYW1lc1tUek1vbnRoTmFtZXNbXCJKYW5cIl0gPSAxXSA9IFwiSmFuXCI7XG4gICAgVHpNb250aE5hbWVzW1R6TW9udGhOYW1lc1tcIkZlYlwiXSA9IDJdID0gXCJGZWJcIjtcbiAgICBUek1vbnRoTmFtZXNbVHpNb250aE5hbWVzW1wiTWFyXCJdID0gM10gPSBcIk1hclwiO1xuICAgIFR6TW9udGhOYW1lc1tUek1vbnRoTmFtZXNbXCJBcHJcIl0gPSA0XSA9IFwiQXByXCI7XG4gICAgVHpNb250aE5hbWVzW1R6TW9udGhOYW1lc1tcIk1heVwiXSA9IDVdID0gXCJNYXlcIjtcbiAgICBUek1vbnRoTmFtZXNbVHpNb250aE5hbWVzW1wiSnVuXCJdID0gNl0gPSBcIkp1blwiO1xuICAgIFR6TW9udGhOYW1lc1tUek1vbnRoTmFtZXNbXCJKdWxcIl0gPSA3XSA9IFwiSnVsXCI7XG4gICAgVHpNb250aE5hbWVzW1R6TW9udGhOYW1lc1tcIkF1Z1wiXSA9IDhdID0gXCJBdWdcIjtcbiAgICBUek1vbnRoTmFtZXNbVHpNb250aE5hbWVzW1wiU2VwXCJdID0gOV0gPSBcIlNlcFwiO1xuICAgIFR6TW9udGhOYW1lc1tUek1vbnRoTmFtZXNbXCJPY3RcIl0gPSAxMF0gPSBcIk9jdFwiO1xuICAgIFR6TW9udGhOYW1lc1tUek1vbnRoTmFtZXNbXCJOb3ZcIl0gPSAxMV0gPSBcIk5vdlwiO1xuICAgIFR6TW9udGhOYW1lc1tUek1vbnRoTmFtZXNbXCJEZWNcIl0gPSAxMl0gPSBcIkRlY1wiO1xufSkoVHpNb250aE5hbWVzIHx8IChUek1vbnRoTmFtZXMgPSB7fSkpO1xuLyoqXG4gKiBUdXJucyBhIG1vbnRoIG5hbWUgZnJvbSB0aGUgVFogZGF0YWJhc2UgaW50byBhIG51bWJlciAxLTEyXG4gKiBAcGFyYW0gbmFtZVxuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkludmFsaWRUaW1lWm9uZURhdGEgZm9yIGludmFsaWQgbW9udGggbmFtZVxuICovXG5mdW5jdGlvbiBtb250aE5hbWVUb051bWJlcihuYW1lKSB7XG4gICAgZm9yICh2YXIgaSA9IDE7IGkgPD0gMTI7ICsraSkge1xuICAgICAgICBpZiAoVHpNb250aE5hbWVzW2ldID09PSBuYW1lKSB7XG4gICAgICAgICAgICByZXR1cm4gaTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gKDAsIGVycm9yXzEudGhyb3dFcnJvcikoXCJJbnZhbGlkVGltZVpvbmVEYXRhXCIsIFwiSW52YWxpZCBtb250aCBuYW1lICdcIi5jb25jYXQobmFtZSwgXCInXCIpKTtcbn1cbnZhciBUekRheU5hbWVzO1xuKGZ1bmN0aW9uIChUekRheU5hbWVzKSB7XG4gICAgVHpEYXlOYW1lc1tUekRheU5hbWVzW1wiU3VuXCJdID0gMF0gPSBcIlN1blwiO1xuICAgIFR6RGF5TmFtZXNbVHpEYXlOYW1lc1tcIk1vblwiXSA9IDFdID0gXCJNb25cIjtcbiAgICBUekRheU5hbWVzW1R6RGF5TmFtZXNbXCJUdWVcIl0gPSAyXSA9IFwiVHVlXCI7XG4gICAgVHpEYXlOYW1lc1tUekRheU5hbWVzW1wiV2VkXCJdID0gM10gPSBcIldlZFwiO1xuICAgIFR6RGF5TmFtZXNbVHpEYXlOYW1lc1tcIlRodVwiXSA9IDRdID0gXCJUaHVcIjtcbiAgICBUekRheU5hbWVzW1R6RGF5TmFtZXNbXCJGcmlcIl0gPSA1XSA9IFwiRnJpXCI7XG4gICAgVHpEYXlOYW1lc1tUekRheU5hbWVzW1wiU2F0XCJdID0gNl0gPSBcIlNhdFwiO1xufSkoVHpEYXlOYW1lcyB8fCAoVHpEYXlOYW1lcyA9IHt9KSk7XG4vKipcbiAqIFJldHVybnMgdHJ1ZSBpZiB0aGUgZ2l2ZW4gc3RyaW5nIGlzIGEgdmFsaWQgb2Zmc2V0IHN0cmluZyBpLmUuXG4gKiAxLCAtMSwgKzEsIDAxLCAxOjAwLCAxOjIzOjI1LjE0M1xuICogQHRocm93cyBub3RoaW5nXG4gKi9cbmZ1bmN0aW9uIGlzVmFsaWRPZmZzZXRTdHJpbmcocykge1xuICAgIHJldHVybiAvXihcXC18XFwrKT8oWzAtOV0rKChcXDpbMC05XSspPyhcXDpbMC05XSsoXFwuWzAtOV0rKT8pPykpJC8udGVzdChzKTtcbn1cbmV4cG9ydHMuaXNWYWxpZE9mZnNldFN0cmluZyA9IGlzVmFsaWRPZmZzZXRTdHJpbmc7XG4vKipcbiAqIERlZmluZXMgYSBtb21lbnQgYXQgd2hpY2ggdGhlIGdpdmVuIHJ1bGUgYmVjb21lcyB2YWxpZFxuICovXG52YXIgVHJhbnNpdGlvbiA9IC8qKiBAY2xhc3MgKi8gKGZ1bmN0aW9uICgpIHtcbiAgICAvKipcbiAgICAgKiBDb25zdHJ1Y3RvclxuICAgICAqIEBwYXJhbSBhdFxuICAgICAqIEBwYXJhbSBvZmZzZXRcbiAgICAgKiBAcGFyYW0gbGV0dGVyXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgZnVuY3Rpb24gVHJhbnNpdGlvbihcbiAgICAvKipcbiAgICAgKiBUcmFuc2l0aW9uIHRpbWUgaW4gVVRDIG1pbGxpc1xuICAgICAqL1xuICAgIGF0LCBcbiAgICAvKipcbiAgICAgKiBOZXcgb2Zmc2V0ICh0eXBlIG9mIG9mZnNldCBkZXBlbmRzIG9uIHRoZSBmdW5jdGlvbilcbiAgICAgKi9cbiAgICBvZmZzZXQsIFxuICAgIC8qKlxuICAgICAqIE5ldyB0aW16b25lIGFiYnJldmlhdGlvbiBsZXR0ZXJcbiAgICAgKi9cbiAgICBsZXR0ZXIpIHtcbiAgICAgICAgdGhpcy5hdCA9IGF0O1xuICAgICAgICB0aGlzLm9mZnNldCA9IG9mZnNldDtcbiAgICAgICAgdGhpcy5sZXR0ZXIgPSBsZXR0ZXI7XG4gICAgICAgIGlmICh0aGlzLm9mZnNldCkge1xuICAgICAgICAgICAgdGhpcy5vZmZzZXQgPSB0aGlzLm9mZnNldC5jb252ZXJ0KGJhc2ljcy5UaW1lVW5pdC5Ib3VyKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gVHJhbnNpdGlvbjtcbn0oKSk7XG5leHBvcnRzLlRyYW5zaXRpb24gPSBUcmFuc2l0aW9uO1xuLyoqXG4gKiBPcHRpb24gZm9yIFR6RGF0YWJhc2Ujbm9ybWFsaXplTG9jYWwoKVxuICovXG52YXIgTm9ybWFsaXplT3B0aW9uO1xuKGZ1bmN0aW9uIChOb3JtYWxpemVPcHRpb24pIHtcbiAgICAvKipcbiAgICAgKiBOb3JtYWxpemUgbm9uLWV4aXN0aW5nIHRpbWVzIGJ5IEFERElORyB0aGUgRFNUIG9mZnNldFxuICAgICAqL1xuICAgIE5vcm1hbGl6ZU9wdGlvbltOb3JtYWxpemVPcHRpb25bXCJVcFwiXSA9IDBdID0gXCJVcFwiO1xuICAgIC8qKlxuICAgICAqIE5vcm1hbGl6ZSBub24tZXhpc3RpbmcgdGltZXMgYnkgU1VCVFJBQ1RJTkcgdGhlIERTVCBvZmZzZXRcbiAgICAgKi9cbiAgICBOb3JtYWxpemVPcHRpb25bTm9ybWFsaXplT3B0aW9uW1wiRG93blwiXSA9IDFdID0gXCJEb3duXCI7XG59KShOb3JtYWxpemVPcHRpb24gfHwgKGV4cG9ydHMuTm9ybWFsaXplT3B0aW9uID0gTm9ybWFsaXplT3B0aW9uID0ge30pKTtcbi8qKlxuICogVGhpcyBjbGFzcyBpcyBhIHdyYXBwZXIgYXJvdW5kIHRpbWUgem9uZSBkYXRhIEpTT04gb2JqZWN0IGZyb20gdGhlIHR6ZGF0YSBOUE0gbW9kdWxlLlxuICogWW91IHVzdWFsbHkgZG8gbm90IG5lZWQgdG8gdXNlIHRoaXMgZGlyZWN0bHksIHVzZSBUaW1lWm9uZSBhbmQgRGF0ZVRpbWUgaW5zdGVhZC5cbiAqL1xudmFyIFR6RGF0YWJhc2UgPSAvKiogQGNsYXNzICovIChmdW5jdGlvbiAoKSB7XG4gICAgLyoqXG4gICAgICogQ29uc3RydWN0b3IgLSBkbyBub3QgdXNlLCB0aGlzIGlzIGEgc2luZ2xldG9uIGNsYXNzLiBVc2UgVHpEYXRhYmFzZS5pbnN0YW5jZSgpIGluc3RlYWRcbiAgICAgKiBAdGhyb3dzIEFscmVhZHlDcmVhdGVkIGlmIGFuIGluc3RhbmNlIGFscmVhZHkgZXhpc3RzXG4gICAgICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkludmFsaWRUaW1lWm9uZURhdGEgaWYgYGRhdGFgIGlzIGVtcHR5IG9yIGludmFsaWRcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBUekRhdGFiYXNlKGRhdGEpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFBlcmZvcm1hbmNlIGltcHJvdmVtZW50OiB6b25lIGluZm8gY2FjaGVcbiAgICAgICAgICovXG4gICAgICAgIHRoaXMuX3pvbmVJbmZvQ2FjaGUgPSB7fTtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFBlcmZvcm1hbmNlIGltcHJvdmVtZW50OiBydWxlIGluZm8gY2FjaGVcbiAgICAgICAgICovXG4gICAgICAgIHRoaXMuX3J1bGVJbmZvQ2FjaGUgPSB7fTtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIHByZS1jYWxjdWxhdGVkIHRyYW5zaXRpb25zIHBlciB6b25lXG4gICAgICAgICAqL1xuICAgICAgICB0aGlzLl96b25lVHJhbnNpdGlvbnNDYWNoZSA9IG5ldyBNYXAoKTtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIHByZS1jYWxjdWxhdGVkIHRyYW5zaXRpb25zIHBlciBydWxlc2V0XG4gICAgICAgICAqL1xuICAgICAgICB0aGlzLl9ydWxlVHJhbnNpdGlvbnNDYWNoZSA9IG5ldyBNYXAoKTtcbiAgICAgICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKCFUekRhdGFiYXNlLl9pbnN0YW5jZSwgXCJBbHJlYWR5Q3JlYXRlZFwiLCBcIllvdSBzaG91bGQgbm90IGNyZWF0ZSBhbiBpbnN0YW5jZSBvZiB0aGUgVHpEYXRhYmFzZSBjbGFzcyB5b3Vyc2VsZi4gVXNlIFR6RGF0YWJhc2UuaW5zdGFuY2UoKVwiKTtcbiAgICAgICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKGRhdGEubGVuZ3RoID4gMCwgXCJJbnZhbGlkVGltZVpvbmVEYXRhXCIsIFwiVGltZXpvbmVjb21wbGV0ZSBuZWVkcyB0aW1lIHpvbmUgZGF0YS4gWW91IG5lZWQgdG8gaW5zdGFsbCBvbmUgb2YgdGhlIHR6ZGF0YSBOUE0gbW9kdWxlcyBiZWZvcmUgdXNpbmcgdGltZXpvbmVjb21wbGV0ZS5cIik7XG4gICAgICAgIGlmIChkYXRhLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICAgICAgdGhpcy5fZGF0YSA9IGRhdGFbMF07XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICB0aGlzLl9kYXRhID0geyB6b25lczoge30sIHJ1bGVzOiB7fSB9O1xuICAgICAgICAgICAgZGF0YS5mb3JFYWNoKGZ1bmN0aW9uIChkKSB7XG4gICAgICAgICAgICAgICAgaWYgKGQgJiYgZC5ydWxlcyAmJiBkLnpvbmVzKSB7XG4gICAgICAgICAgICAgICAgICAgIGZvciAodmFyIF9pID0gMCwgX2EgPSBPYmplY3Qua2V5cyhkLnJ1bGVzKTsgX2kgPCBfYS5sZW5ndGg7IF9pKyspIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBrZXkgPSBfYVtfaV07XG4gICAgICAgICAgICAgICAgICAgICAgICBfdGhpcy5fZGF0YS5ydWxlc1trZXldID0gZC5ydWxlc1trZXldO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGZvciAodmFyIF9iID0gMCwgX2MgPSBPYmplY3Qua2V5cyhkLnpvbmVzKTsgX2IgPCBfYy5sZW5ndGg7IF9iKyspIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBrZXkgPSBfY1tfYl07XG4gICAgICAgICAgICAgICAgICAgICAgICBfdGhpcy5fZGF0YS56b25lc1trZXldID0gZC56b25lc1trZXldO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5fbWlubWF4ID0gdmFsaWRhdGVEYXRhKHRoaXMuX2RhdGEpO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiAocmUtKSBpbml0aWFsaXplIHRpbWV6b25lY29tcGxldGUgd2l0aCB0aW1lIHpvbmUgZGF0YVxuICAgICAqXG4gICAgICogQHBhcmFtIGRhdGEgVFogZGF0YSBhcyBKU09OIG9iamVjdCAoZnJvbSBvbmUgb2YgdGhlIHR6ZGF0YSBOUE0gbW9kdWxlcykuXG4gICAgICogICAgICAgICAgICAgSWYgbm90IGdpdmVuLCBUaW1lem9uZWNvbXBsZXRlIHdpbGwgc2VhcmNoIGZvciBpbnN0YWxsZWQgbW9kdWxlcy5cbiAgICAgKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuSW52YWxpZFRpbWVab25lRGF0YSBpZiBgZGF0YWAgb3IgdGhlIGdsb2JhbCB0aW1lIHpvbmUgZGF0YSBpcyBpbnZhbGlkXG4gICAgICovXG4gICAgVHpEYXRhYmFzZS5pbml0ID0gZnVuY3Rpb24gKGRhdGEpIHtcbiAgICAgICAgVHpEYXRhYmFzZS5faW5zdGFuY2UgPSB1bmRlZmluZWQ7IC8vIG5lZWRlZCBmb3IgYXNzZXJ0IGluIGNvbnN0cnVjdG9yXG4gICAgICAgIGlmIChkYXRhKSB7XG4gICAgICAgICAgICBUekRhdGFiYXNlLl9pbnN0YW5jZSA9IG5ldyBUekRhdGFiYXNlKEFycmF5LmlzQXJyYXkoZGF0YSkgPyBkYXRhIDogW2RhdGFdKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHZhciBkYXRhXzEgPSBbXTtcbiAgICAgICAgICAgIC8vIHRyeSB0byBmaW5kIFRaIGRhdGEgaW4gZ2xvYmFsIHZhcmlhYmxlc1xuICAgICAgICAgICAgdmFyIGcgPSB2b2lkIDA7XG4gICAgICAgICAgICBpZiAodHlwZW9mIHdpbmRvdyAhPT0gXCJ1bmRlZmluZWRcIikge1xuICAgICAgICAgICAgICAgIGcgPSB3aW5kb3c7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmICh0eXBlb2YgZ2xvYmFsICE9PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgICAgICAgICAgZyA9IGdsb2JhbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2UgaWYgKHR5cGVvZiBzZWxmICE9PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgICAgICAgICAgZyA9IHNlbGY7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBnID0ge307XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoZykge1xuICAgICAgICAgICAgICAgIGZvciAodmFyIF9pID0gMCwgX2EgPSBPYmplY3Qua2V5cyhnKTsgX2kgPCBfYS5sZW5ndGg7IF9pKyspIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGtleSA9IF9hW19pXTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGtleS5zdGFydHNXaXRoKFwidHpkYXRhXCIpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIGdba2V5XSA9PT0gXCJvYmplY3RcIiAmJiBnW2tleV0ucnVsZXMgJiYgZ1trZXldLnpvbmVzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YV8xLnB1c2goZ1trZXldKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIHRyeSB0byBmaW5kIFRaIGRhdGEgYXMgaW5zdGFsbGVkIE5QTSBtb2R1bGVzXG4gICAgICAgICAgICB2YXIgZmluZE5vZGVNb2R1bGVzID0gZnVuY3Rpb24gKHJlcXVpcmUpIHtcbiAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICAvLyBmaXJzdCB0cnkgdHpkYXRhIHdoaWNoIGNvbnRhaW5zIGFsbCBkYXRhXG4gICAgICAgICAgICAgICAgICAgIHZhciB0ekRhdGFOYW1lID0gXCJ0emRhdGFcIjtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGQgPSByZXF1aXJlKHR6RGF0YU5hbWUpOyAvLyB1c2UgdmFyaWFibGUgdG8gYXZvaWQgYnJvd3NlcmlmeSBhY3RpbmcgdXBcbiAgICAgICAgICAgICAgICAgICAgZGF0YV8xLnB1c2goZCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIHRoZW4gdHJ5IHN1YnNldHNcbiAgICAgICAgICAgICAgICAgICAgdmFyIG1vZHVsZU5hbWVzID0gW1xuICAgICAgICAgICAgICAgICAgICAgICAgXCJ0emRhdGEtYWZyaWNhXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBcInR6ZGF0YS1hbnRhcmN0aWNhXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBcInR6ZGF0YS1hc2lhXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBcInR6ZGF0YS1hdXN0cmFsYXNpYVwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgXCJ0emRhdGEtYmFja3dhcmRcIixcbiAgICAgICAgICAgICAgICAgICAgICAgIFwidHpkYXRhLWJhY2t3YXJkLXV0Y1wiLFxuICAgICAgICAgICAgICAgICAgICAgICAgXCJ0emRhdGEtZXRjZXRlcmFcIixcbiAgICAgICAgICAgICAgICAgICAgICAgIFwidHpkYXRhLWV1cm9wZVwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgXCJ0emRhdGEtbm9ydGhhbWVyaWNhXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBcInR6ZGF0YS1wYWNpZmljbmV3XCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBcInR6ZGF0YS1zb3V0aGFtZXJpY2FcIixcbiAgICAgICAgICAgICAgICAgICAgICAgIFwidHpkYXRhLXN5c3RlbXZcIlxuICAgICAgICAgICAgICAgICAgICBdO1xuICAgICAgICAgICAgICAgICAgICBtb2R1bGVOYW1lcy5mb3JFYWNoKGZ1bmN0aW9uIChtb2R1bGVOYW1lKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBkID0gcmVxdWlyZShtb2R1bGVOYW1lKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhXzEucHVzaChkKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gbm90aGluZ1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgaWYgKGRhdGFfMS5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIG1vZHVsZSA9PT0gXCJvYmplY3RcIiAmJiB0eXBlb2YgbW9kdWxlLmV4cG9ydHMgPT09IFwib2JqZWN0XCIpIHtcbiAgICAgICAgICAgICAgICAgICAgZmluZE5vZGVNb2R1bGVzKHJlcXVpcmUpOyAvLyBuZWVkIHRvIHB1dCByZXF1aXJlIGludG8gYSBmdW5jdGlvbiB0byBtYWtlIHdlYnBhY2sgaGFwcHlcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBUekRhdGFiYXNlLl9pbnN0YW5jZSA9IG5ldyBUekRhdGFiYXNlKGRhdGFfMSk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFNpbmdsZSBpbnN0YW5jZSBvZiB0aGlzIGRhdGFiYXNlXG4gICAgICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkludmFsaWRUaW1lWm9uZURhdGEgaWYgdGhlIGdsb2JhbCB0aW1lIHpvbmUgZGF0YSBpcyBpbnZhbGlkXG4gICAgICovXG4gICAgVHpEYXRhYmFzZS5pbnN0YW5jZSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKCFUekRhdGFiYXNlLl9pbnN0YW5jZSkge1xuICAgICAgICAgICAgVHpEYXRhYmFzZS5pbml0KCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIFR6RGF0YWJhc2UuX2luc3RhbmNlO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogUmV0dXJucyBhIHNvcnRlZCBsaXN0IG9mIGFsbCB6b25lIG5hbWVzXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgVHpEYXRhYmFzZS5wcm90b3R5cGUuem9uZU5hbWVzID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAoIXRoaXMuX3pvbmVOYW1lcykge1xuICAgICAgICAgICAgdGhpcy5fem9uZU5hbWVzID0gT2JqZWN0LmtleXModGhpcy5fZGF0YS56b25lcyk7XG4gICAgICAgICAgICB0aGlzLl96b25lTmFtZXMuc29ydCgpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLl96b25lTmFtZXM7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRydWUgaWZmIHRoZSBnaXZlbiB6b25lIG5hbWUgZXhpc3RzXG4gICAgICogQHBhcmFtIHpvbmVOYW1lXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgVHpEYXRhYmFzZS5wcm90b3R5cGUuZXhpc3RzID0gZnVuY3Rpb24gKHpvbmVOYW1lKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9kYXRhLnpvbmVzLmhhc093blByb3BlcnR5KHpvbmVOYW1lKTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIE1pbmltdW0gbm9uLXplcm8gRFNUIG9mZnNldCAod2hpY2ggZXhjbHVkZXMgc3RhbmRhcmQgb2Zmc2V0KSBvZiBhbGwgcnVsZXMgaW4gdGhlIGRhdGFiYXNlLlxuICAgICAqIE5vdGUgdGhhdCBEU1Qgb2Zmc2V0cyBuZWVkIG5vdCBiZSB3aG9sZSBob3Vycy5cbiAgICAgKlxuICAgICAqIERvZXMgcmV0dXJuIHplcm8gaWYgYSB6b25lTmFtZSBpcyBnaXZlbiBhbmQgdGhlcmUgaXMgbm8gRFNUIGF0IGFsbCBmb3IgdGhlIHpvbmUuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gem9uZU5hbWVcdChvcHRpb25hbCkgaWYgZ2l2ZW4sIHRoZSByZXN1bHQgZm9yIHRoZSBnaXZlbiB6b25lIGlzIHJldHVybmVkXG4gICAgICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLk5vdEZvdW5kLlpvbmUgaWYgem9uZSBuYW1lIG5vdCBmb3VuZCBvciBhIGxpbmtlZCB6b25lIG5vdCBmb3VuZFxuICAgICAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5JbnZhbGlkVGltZVpvbmVEYXRhIGlmIHZhbHVlcyBpbiB0aGUgdGltZSB6b25lIGRhdGFiYXNlIGFyZSBpbnZhbGlkXG4gICAgICovXG4gICAgVHpEYXRhYmFzZS5wcm90b3R5cGUubWluRHN0U2F2ZSA9IGZ1bmN0aW9uICh6b25lTmFtZSkge1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgaWYgKHpvbmVOYW1lKSB7XG4gICAgICAgICAgICAgICAgdmFyIHpvbmVJbmZvcyA9IHRoaXMuZ2V0Wm9uZUluZm9zKHpvbmVOYW1lKTtcbiAgICAgICAgICAgICAgICB2YXIgcmVzdWx0ID0gdm9pZCAwO1xuICAgICAgICAgICAgICAgIHZhciBydWxlTmFtZXMgPSBbXTtcbiAgICAgICAgICAgICAgICBmb3IgKHZhciBfaSA9IDAsIHpvbmVJbmZvc18xID0gem9uZUluZm9zOyBfaSA8IHpvbmVJbmZvc18xLmxlbmd0aDsgX2krKykge1xuICAgICAgICAgICAgICAgICAgICB2YXIgem9uZUluZm8gPSB6b25lSW5mb3NfMVtfaV07XG4gICAgICAgICAgICAgICAgICAgIGlmICh6b25lSW5mby5ydWxlVHlwZSA9PT0gUnVsZVR5cGUuT2Zmc2V0KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoIXJlc3VsdCB8fCByZXN1bHQuZ3JlYXRlclRoYW4oem9uZUluZm8ucnVsZU9mZnNldCkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoem9uZUluZm8ucnVsZU9mZnNldC5taWxsaXNlY29uZHMoKSAhPT0gMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXN1bHQgPSB6b25lSW5mby5ydWxlT2Zmc2V0O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBpZiAoem9uZUluZm8ucnVsZVR5cGUgPT09IFJ1bGVUeXBlLlJ1bGVOYW1lICYmIHJ1bGVOYW1lcy5pbmRleE9mKHpvbmVJbmZvLnJ1bGVOYW1lKSA9PT0gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJ1bGVOYW1lcy5wdXNoKHpvbmVJbmZvLnJ1bGVOYW1lKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciB0ZW1wID0gdGhpcy5nZXRSdWxlSW5mb3Moem9uZUluZm8ucnVsZU5hbWUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgZm9yICh2YXIgX2EgPSAwLCB0ZW1wXzEgPSB0ZW1wOyBfYSA8IHRlbXBfMS5sZW5ndGg7IF9hKyspIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgcnVsZUluZm8gPSB0ZW1wXzFbX2FdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICghcmVzdWx0IHx8IHJlc3VsdC5ncmVhdGVyVGhhbihydWxlSW5mby5zYXZlKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAocnVsZUluZm8uc2F2ZS5taWxsaXNlY29uZHMoKSAhPT0gMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0ID0gcnVsZUluZm8uc2F2ZTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoIXJlc3VsdCkge1xuICAgICAgICAgICAgICAgICAgICByZXN1bHQgPSBkdXJhdGlvbl8xLkR1cmF0aW9uLmhvdXJzKDApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm4gcmVzdWx0LmNsb25lKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZHVyYXRpb25fMS5EdXJhdGlvbi5taW51dGVzKHRoaXMuX21pbm1heC5taW5Ec3RTYXZlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBjYXRjaCAoZSkge1xuICAgICAgICAgICAgaWYgKCgwLCBlcnJvcl8xLmVycm9ySXMpKGUsIFtcIk5vdEZvdW5kLlJ1bGVcIiwgXCJBcmd1bWVudC5OXCJdKSkge1xuICAgICAgICAgICAgICAgIGUgPSAoMCwgZXJyb3JfMS5lcnJvcikoXCJJbnZhbGlkVGltZVpvbmVEYXRhXCIsIGUubWVzc2FnZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aHJvdyBlO1xuICAgICAgICB9XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBNYXhpbXVtIERTVCBvZmZzZXQgKHdoaWNoIGV4Y2x1ZGVzIHN0YW5kYXJkIG9mZnNldCkgb2YgYWxsIHJ1bGVzIGluIHRoZSBkYXRhYmFzZS5cbiAgICAgKiBOb3RlIHRoYXQgRFNUIG9mZnNldHMgbmVlZCBub3QgYmUgd2hvbGUgaG91cnMuXG4gICAgICpcbiAgICAgKiBSZXR1cm5zIDAgaWYgem9uZU5hbWUgZ2l2ZW4gYW5kIG5vIERTVCBvYnNlcnZlZC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB6b25lTmFtZVx0KG9wdGlvbmFsKSBpZiBnaXZlbiwgdGhlIHJlc3VsdCBmb3IgdGhlIGdpdmVuIHpvbmUgaXMgcmV0dXJuZWRcbiAgICAgKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuTm90Rm91bmQuWm9uZSBpZiB6b25lIG5hbWUgbm90IGZvdW5kIG9yIGEgbGlua2VkIHpvbmUgbm90IGZvdW5kXG4gICAgICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkludmFsaWRUaW1lWm9uZURhdGEgaWYgdmFsdWVzIGluIHRoZSB0aW1lIHpvbmUgZGF0YWJhc2UgYXJlIGludmFsaWRcbiAgICAgKi9cbiAgICBUekRhdGFiYXNlLnByb3RvdHlwZS5tYXhEc3RTYXZlID0gZnVuY3Rpb24gKHpvbmVOYW1lKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBpZiAoem9uZU5hbWUpIHtcbiAgICAgICAgICAgICAgICB2YXIgem9uZUluZm9zID0gdGhpcy5nZXRab25lSW5mb3Moem9uZU5hbWUpO1xuICAgICAgICAgICAgICAgIHZhciByZXN1bHQgPSB2b2lkIDA7XG4gICAgICAgICAgICAgICAgdmFyIHJ1bGVOYW1lcyA9IFtdO1xuICAgICAgICAgICAgICAgIGZvciAodmFyIF9pID0gMCwgem9uZUluZm9zXzIgPSB6b25lSW5mb3M7IF9pIDwgem9uZUluZm9zXzIubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciB6b25lSW5mbyA9IHpvbmVJbmZvc18yW19pXTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHpvbmVJbmZvLnJ1bGVUeXBlID09PSBSdWxlVHlwZS5PZmZzZXQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghcmVzdWx0IHx8IHJlc3VsdC5sZXNzVGhhbih6b25lSW5mby5ydWxlT2Zmc2V0KSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdCA9IHpvbmVJbmZvLnJ1bGVPZmZzZXQ7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgaWYgKHpvbmVJbmZvLnJ1bGVUeXBlID09PSBSdWxlVHlwZS5SdWxlTmFtZVxuICAgICAgICAgICAgICAgICAgICAgICAgJiYgcnVsZU5hbWVzLmluZGV4T2Yoem9uZUluZm8ucnVsZU5hbWUpID09PSAtMSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcnVsZU5hbWVzLnB1c2goem9uZUluZm8ucnVsZU5hbWUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHRlbXAgPSB0aGlzLmdldFJ1bGVJbmZvcyh6b25lSW5mby5ydWxlTmFtZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBmb3IgKHZhciBfYSA9IDAsIHRlbXBfMiA9IHRlbXA7IF9hIDwgdGVtcF8yLmxlbmd0aDsgX2ErKykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBydWxlSW5mbyA9IHRlbXBfMltfYV07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFyZXN1bHQgfHwgcmVzdWx0Lmxlc3NUaGFuKHJ1bGVJbmZvLnNhdmUpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdCA9IHJ1bGVJbmZvLnNhdmU7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmICghcmVzdWx0KSB7XG4gICAgICAgICAgICAgICAgICAgIHJlc3VsdCA9IGR1cmF0aW9uXzEuRHVyYXRpb24uaG91cnMoMCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybiByZXN1bHQuY2xvbmUoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIHJldHVybiBkdXJhdGlvbl8xLkR1cmF0aW9uLm1pbnV0ZXModGhpcy5fbWlubWF4Lm1heERzdFNhdmUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGNhdGNoIChlKSB7XG4gICAgICAgICAgICBpZiAoKDAsIGVycm9yXzEuZXJyb3JJcykoZSwgW1wiTm90Rm91bmQuUnVsZVwiLCBcIkFyZ3VtZW50Lk5cIl0pKSB7XG4gICAgICAgICAgICAgICAgZSA9ICgwLCBlcnJvcl8xLmVycm9yKShcIkludmFsaWRUaW1lWm9uZURhdGFcIiwgZS5tZXNzYWdlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRocm93IGU7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIC8qKlxuICAgICAqIENoZWNrcyB3aGV0aGVyIHRoZSB6b25lIGhhcyBEU1QgYXQgYWxsXG4gICAgICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLk5vdEZvdW5kLlpvbmUgaWYgem9uZSBuYW1lIG5vdCBmb3VuZCBvciBhIGxpbmtlZCB6b25lIG5vdCBmb3VuZFxuICAgICAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5JbnZhbGlkVGltZVpvbmVEYXRhIGlmIHZhbHVlcyBpbiB0aGUgdGltZSB6b25lIGRhdGFiYXNlIGFyZSBpbnZhbGlkXG4gICAgICovXG4gICAgVHpEYXRhYmFzZS5wcm90b3R5cGUuaGFzRHN0ID0gZnVuY3Rpb24gKHpvbmVOYW1lKSB7XG4gICAgICAgIHJldHVybiAodGhpcy5tYXhEc3RTYXZlKHpvbmVOYW1lKS5taWxsaXNlY29uZHMoKSAhPT0gMCk7XG4gICAgfTtcbiAgICBUekRhdGFiYXNlLnByb3RvdHlwZS5uZXh0RHN0Q2hhbmdlID0gZnVuY3Rpb24gKHpvbmVOYW1lLCBhKSB7XG4gICAgICAgIHZhciB1dGNUaW1lID0gKHR5cGVvZiBhID09PSBcIm51bWJlclwiID8gbmV3IGJhc2ljc18xLlRpbWVTdHJ1Y3QoYSkgOiBhKTtcbiAgICAgICAgdmFyIHpvbmUgPSB0aGlzLl9nZXRab25lVHJhbnNpdGlvbnMoem9uZU5hbWUpO1xuICAgICAgICB2YXIgaXRlcmF0b3IgPSB6b25lLmZpbmRGaXJzdCgpO1xuICAgICAgICBpZiAoaXRlcmF0b3IgJiYgaXRlcmF0b3IudHJhbnNpdGlvbi5hdFV0YyA+IHV0Y1RpbWUpIHtcbiAgICAgICAgICAgIHJldHVybiBpdGVyYXRvci50cmFuc2l0aW9uLmF0VXRjLnVuaXhNaWxsaXM7XG4gICAgICAgIH1cbiAgICAgICAgd2hpbGUgKGl0ZXJhdG9yKSB7XG4gICAgICAgICAgICBpdGVyYXRvciA9IHpvbmUuZmluZE5leHQoaXRlcmF0b3IpO1xuICAgICAgICAgICAgaWYgKGl0ZXJhdG9yICYmIGl0ZXJhdG9yLnRyYW5zaXRpb24uYXRVdGMgPiB1dGNUaW1lKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGl0ZXJhdG9yLnRyYW5zaXRpb24uYXRVdGMudW5peE1pbGxpcztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0cnVlIGlmZiB0aGUgZ2l2ZW4gem9uZSBuYW1lIGV2ZW50dWFsbHkgbGlua3MgdG9cbiAgICAgKiBcIkV0Yy9VVENcIiwgXCJFdGMvR01UXCIgb3IgXCJFdGMvVUNUXCIgaW4gdGhlIFRaIGRhdGFiYXNlLiBUaGlzIGlzIHRydWUgZS5nLiBmb3JcbiAgICAgKiBcIlVUQ1wiLCBcIkdNVFwiLCBcIkV0Yy9HTVRcIiBldGMuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gem9uZU5hbWVcdElBTkEgdGltZSB6b25lIG5hbWUuXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgVHpEYXRhYmFzZS5wcm90b3R5cGUuem9uZUlzVXRjID0gZnVuY3Rpb24gKHpvbmVOYW1lKSB7XG4gICAgICAgIHZhciBhY3R1YWxab25lTmFtZSA9IHpvbmVOYW1lO1xuICAgICAgICB2YXIgem9uZUVudHJpZXMgPSB0aGlzLl9kYXRhLnpvbmVzW3pvbmVOYW1lXTtcbiAgICAgICAgLy8gZm9sbG93IGxpbmtzXG4gICAgICAgIHdoaWxlICh0eXBlb2YgKHpvbmVFbnRyaWVzKSA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIGlmICovXG4gICAgICAgICAgICBpZiAoIXRoaXMuX2RhdGEuem9uZXMuaGFzT3duUHJvcGVydHkoem9uZUVudHJpZXMpKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiWm9uZSBcXFwiXCIgKyB6b25lRW50cmllcyArIFwiXFxcIiBub3QgZm91bmQgKHJlZmVycmVkIHRvIGluIGxpbmsgZnJvbSBcXFwiXCJcbiAgICAgICAgICAgICAgICAgICAgKyB6b25lTmFtZSArIFwiXFxcIiB2aWEgXFxcIlwiICsgYWN0dWFsWm9uZU5hbWUgKyBcIlxcXCJcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBhY3R1YWxab25lTmFtZSA9IHpvbmVFbnRyaWVzO1xuICAgICAgICAgICAgem9uZUVudHJpZXMgPSB0aGlzLl9kYXRhLnpvbmVzW2FjdHVhbFpvbmVOYW1lXTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gKGFjdHVhbFpvbmVOYW1lID09PSBcIkV0Yy9VVENcIiB8fCBhY3R1YWxab25lTmFtZSA9PT0gXCJFdGMvR01UXCIgfHwgYWN0dWFsWm9uZU5hbWUgPT09IFwiRXRjL1VDVFwiKTtcbiAgICB9O1xuICAgIFR6RGF0YWJhc2UucHJvdG90eXBlLm5vcm1hbGl6ZUxvY2FsID0gZnVuY3Rpb24gKHpvbmVOYW1lLCBhLCBvcHQpIHtcbiAgICAgICAgaWYgKG9wdCA9PT0gdm9pZCAwKSB7IG9wdCA9IE5vcm1hbGl6ZU9wdGlvbi5VcDsgfVxuICAgICAgICBpZiAodGhpcy5oYXNEc3Qoem9uZU5hbWUpKSB7XG4gICAgICAgICAgICB2YXIgbG9jYWxUaW1lID0gKHR5cGVvZiBhID09PSBcIm51bWJlclwiID8gbmV3IGJhc2ljc18xLlRpbWVTdHJ1Y3QoYSkgOiBhKTtcbiAgICAgICAgICAgIC8vIGxvY2FsIHRpbWVzIGJlaGF2ZSBsaWtlIHRoaXMgZHVyaW5nIERTVCBjaGFuZ2VzOlxuICAgICAgICAgICAgLy8gZm9yd2FyZCBjaGFuZ2UgKDFoKTogICAwIDEgMyA0IDVcbiAgICAgICAgICAgIC8vIGZvcndhcmQgY2hhbmdlICgyaCk6ICAgMCAxIDQgNSA2XG4gICAgICAgICAgICAvLyBiYWNrd2FyZCBjaGFuZ2UgKDFoKTogIDEgMiAyIDMgNFxuICAgICAgICAgICAgLy8gYmFja3dhcmQgY2hhbmdlICgyaCk6ICAxIDIgMSAyIDNcbiAgICAgICAgICAgIC8vIFRoZXJlZm9yZSwgYmluYXJ5IHNlYXJjaGluZyBpcyBub3QgcG9zc2libGUuXG4gICAgICAgICAgICAvLyBJbnN0ZWFkLCB3ZSBzaG91bGQgY2hlY2sgdGhlIERTVCBmb3J3YXJkIHRyYW5zaXRpb25zIHdpdGhpbiBhIHdpbmRvdyBhcm91bmQgdGhlIGxvY2FsIHRpbWVcbiAgICAgICAgICAgIC8vIGdldCBhbGwgdHJhbnNpdGlvbnMgKG5vdGUgdGhpcyBpbmNsdWRlcyBmYWtlIHRyYW5zaXRpb24gcnVsZXMgZm9yIHpvbmUgb2Zmc2V0IGNoYW5nZXMpXG4gICAgICAgICAgICB2YXIgem9uZSA9IHRoaXMuX2dldFpvbmVUcmFuc2l0aW9ucyh6b25lTmFtZSk7XG4gICAgICAgICAgICB2YXIgdHJhbnNpdGlvbnMgPSB6b25lLnRyYW5zaXRpb25zSW5ZZWFycyhsb2NhbFRpbWUuY29tcG9uZW50cy55ZWFyIC0gMSwgbG9jYWxUaW1lLmNvbXBvbmVudHMueWVhciArIDEpO1xuICAgICAgICAgICAgLy8gZmluZCB0aGUgRFNUIGZvcndhcmQgdHJhbnNpdGlvbnNcbiAgICAgICAgICAgIHZhciBwcmV2ID0gZHVyYXRpb25fMS5EdXJhdGlvbi5ob3VycygwKTtcbiAgICAgICAgICAgIGZvciAodmFyIF9pID0gMCwgdHJhbnNpdGlvbnNfMSA9IHRyYW5zaXRpb25zOyBfaSA8IHRyYW5zaXRpb25zXzEubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgICAgICAgICAgdmFyIHRyYW5zaXRpb24gPSB0cmFuc2l0aW9uc18xW19pXTtcbiAgICAgICAgICAgICAgICB2YXIgb2Zmc2V0ID0gdHJhbnNpdGlvbi5uZXdTdGF0ZS5kc3RPZmZzZXQuYWRkKHRyYW5zaXRpb24ubmV3U3RhdGUuc3RhbmRhcmRPZmZzZXQpO1xuICAgICAgICAgICAgICAgIC8vIGZvcndhcmQgdHJhbnNpdGlvbj9cbiAgICAgICAgICAgICAgICBpZiAob2Zmc2V0LmdyZWF0ZXJUaGFuKHByZXYpKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBsb2NhbEJlZm9yZSA9IHRyYW5zaXRpb24uYXRVdGMudW5peE1pbGxpcyArIHByZXYubWlsbGlzZWNvbmRzKCk7XG4gICAgICAgICAgICAgICAgICAgIHZhciBsb2NhbEFmdGVyID0gdHJhbnNpdGlvbi5hdFV0Yy51bml4TWlsbGlzICsgb2Zmc2V0Lm1pbGxpc2Vjb25kcygpO1xuICAgICAgICAgICAgICAgICAgICBpZiAobG9jYWxUaW1lLnVuaXhNaWxsaXMgPj0gbG9jYWxCZWZvcmUgJiYgbG9jYWxUaW1lLnVuaXhNaWxsaXMgPCBsb2NhbEFmdGVyKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgZm9yd2FyZENoYW5nZSA9IG9mZnNldC5zdWIocHJldik7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBub24tZXhpc3RpbmcgdGltZVxuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGZhY3RvciA9IChvcHQgPT09IE5vcm1hbGl6ZU9wdGlvbi5VcCA/IDEgOiAtMSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgcmVzdWx0TWlsbGlzID0gbG9jYWxUaW1lLnVuaXhNaWxsaXMgKyBmYWN0b3IgKiBmb3J3YXJkQ2hhbmdlLm1pbGxpc2Vjb25kcygpO1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuICh0eXBlb2YgYSA9PT0gXCJudW1iZXJcIiA/IHJlc3VsdE1pbGxpcyA6IG5ldyBiYXNpY3NfMS5UaW1lU3RydWN0KHJlc3VsdE1pbGxpcykpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHByZXYgPSBvZmZzZXQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBubyBub24tZXhpc3RpbmcgdGltZVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiAodHlwZW9mIGEgPT09IFwibnVtYmVyXCIgPyBhIDogYS5jbG9uZSgpKTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIHN0YW5kYXJkIHRpbWUgem9uZSBvZmZzZXQgZnJvbSBVVEMsIHdpdGhvdXQgRFNULlxuICAgICAqIFRocm93cyBpZiBpbmZvIG5vdCBmb3VuZC5cbiAgICAgKiBAcGFyYW0gem9uZU5hbWVcdElBTkEgdGltZSB6b25lIG5hbWVcbiAgICAgKiBAcGFyYW0gdXRjVGltZVx0VGltZXN0YW1wIGluIFVUQywgZWl0aGVyIGFzIFRpbWVTdHJ1Y3Qgb3IgYXMgVW5peCBtaWxsaXNlY29uZCB2YWx1ZVxuICAgICAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Ob3RGb3VuZC5ab25lIGlmIHpvbmUgbmFtZSBub3QgZm91bmQgb3IgYSBsaW5rZWQgem9uZSBub3QgZm91bmRcbiAgICAgKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuSW52YWxpZFRpbWVab25lRGF0YSBpZiB2YWx1ZXMgaW4gdGhlIHRpbWUgem9uZSBkYXRhYmFzZSBhcmUgaW52YWxpZFxuICAgICAqL1xuICAgIFR6RGF0YWJhc2UucHJvdG90eXBlLnN0YW5kYXJkT2Zmc2V0ID0gZnVuY3Rpb24gKHpvbmVOYW1lLCB1dGNUaW1lKSB7XG4gICAgICAgIHZhciB6b25lSW5mbyA9IHRoaXMuZ2V0Wm9uZUluZm8oem9uZU5hbWUsIHV0Y1RpbWUpO1xuICAgICAgICByZXR1cm4gem9uZUluZm8uZ210b2ZmLmNsb25lKCk7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSB0b3RhbCB0aW1lIHpvbmUgb2Zmc2V0IGZyb20gVVRDLCBpbmNsdWRpbmcgRFNULCBhdFxuICAgICAqIHRoZSBnaXZlbiBVVEMgdGltZXN0YW1wLlxuICAgICAqIFRocm93cyBpZiB6b25lIGluZm8gbm90IGZvdW5kLlxuICAgICAqXG4gICAgICogQHBhcmFtIHpvbmVOYW1lXHRJQU5BIHRpbWUgem9uZSBuYW1lXG4gICAgICogQHBhcmFtIHV0Y1RpbWVcdFRpbWVzdGFtcCBpbiBVVEMsIGVpdGhlciBhcyBUaW1lU3RydWN0IG9yIGFzIFVuaXggbWlsbGlzZWNvbmQgdmFsdWVcbiAgICAgKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuTm90Rm91bmQuWm9uZSBpZiB6b25lIG5hbWUgbm90IGZvdW5kIG9yIGEgbGlua2VkIHpvbmUgbm90IGZvdW5kXG4gICAgICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkludmFsaWRUaW1lWm9uZURhdGEgaWYgdmFsdWVzIGluIHRoZSB0aW1lIHpvbmUgZGF0YWJhc2UgYXJlIGludmFsaWRcbiAgICAgKi9cbiAgICBUekRhdGFiYXNlLnByb3RvdHlwZS50b3RhbE9mZnNldCA9IGZ1bmN0aW9uICh6b25lTmFtZSwgdXRjVGltZSkge1xuICAgICAgICB2YXIgdSA9IHR5cGVvZiB1dGNUaW1lID09PSBcIm51bWJlclwiID8gbmV3IGJhc2ljc18xLlRpbWVTdHJ1Y3QodXRjVGltZSkgOiB1dGNUaW1lO1xuICAgICAgICB2YXIgem9uZSA9IHRoaXMuX2dldFpvbmVUcmFuc2l0aW9ucyh6b25lTmFtZSk7XG4gICAgICAgIHZhciBzdGF0ZSA9IHpvbmUuc3RhdGVBdCh1KTtcbiAgICAgICAgcmV0dXJuIHN0YXRlLmRzdE9mZnNldC5hZGQoc3RhdGUuc3RhbmRhcmRPZmZzZXQpO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogVGhlIHRpbWUgem9uZSBydWxlIGFiYnJldmlhdGlvbiwgZS5nLiBDRVNUIGZvciBDZW50cmFsIEV1cm9wZWFuIFN1bW1lciBUaW1lLlxuICAgICAqIE5vdGUgdGhpcyBpcyBkZXBlbmRlbnQgb24gdGhlIHRpbWUsIGJlY2F1c2Ugd2l0aCB0aW1lIGRpZmZlcmVudCBydWxlcyBhcmUgaW4gZWZmZWN0XG4gICAgICogYW5kIHRoZXJlZm9yZSBkaWZmZXJlbnQgYWJicmV2aWF0aW9ucy4gVGhleSBhbHNvIGNoYW5nZSB3aXRoIERTVDogZS5nLiBDRVNUIG9yIENFVC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB6b25lTmFtZVx0SUFOQSB6b25lIG5hbWVcbiAgICAgKiBAcGFyYW0gdXRjVGltZVx0VGltZXN0YW1wIGluIFVUQyB1bml4IG1pbGxpc2Vjb25kc1xuICAgICAqIEBwYXJhbSBkc3REZXBlbmRlbnQgKGRlZmF1bHQgdHJ1ZSkgc2V0IHRvIGZhbHNlIGZvciBhIERTVC1hZ25vc3RpYyBhYmJyZXZpYXRpb25cbiAgICAgKiBAcmV0dXJuXHRUaGUgYWJicmV2aWF0aW9uIG9mIHRoZSBydWxlIHRoYXQgaXMgaW4gZWZmZWN0XG4gICAgICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLk5vdEZvdW5kLlpvbmUgaWYgem9uZSBuYW1lIG5vdCBmb3VuZCBvciBhIGxpbmtlZCB6b25lIG5vdCBmb3VuZFxuICAgICAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5JbnZhbGlkVGltZVpvbmVEYXRhIGlmIHZhbHVlcyBpbiB0aGUgdGltZSB6b25lIGRhdGFiYXNlIGFyZSBpbnZhbGlkXG4gICAgICovXG4gICAgVHpEYXRhYmFzZS5wcm90b3R5cGUuYWJicmV2aWF0aW9uID0gZnVuY3Rpb24gKHpvbmVOYW1lLCB1dGNUaW1lLCBkc3REZXBlbmRlbnQpIHtcbiAgICAgICAgaWYgKGRzdERlcGVuZGVudCA9PT0gdm9pZCAwKSB7IGRzdERlcGVuZGVudCA9IHRydWU7IH1cbiAgICAgICAgdmFyIHUgPSB0eXBlb2YgdXRjVGltZSA9PT0gXCJudW1iZXJcIiA/IG5ldyBiYXNpY3NfMS5UaW1lU3RydWN0KHV0Y1RpbWUpIDogdXRjVGltZTtcbiAgICAgICAgdmFyIHpvbmUgPSB0aGlzLl9nZXRab25lVHJhbnNpdGlvbnMoem9uZU5hbWUpO1xuICAgICAgICBpZiAoZHN0RGVwZW5kZW50KSB7XG4gICAgICAgICAgICB2YXIgc3RhdGUgPSB6b25lLnN0YXRlQXQodSk7XG4gICAgICAgICAgICByZXR1cm4gc3RhdGUuYWJicmV2aWF0aW9uO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgdmFyIGxhc3ROb25Ec3QgPSB6b25lLmluaXRpYWxTdGF0ZS5kc3RPZmZzZXQubWlsbGlzZWNvbmRzKCkgPT09IDAgPyB6b25lLmluaXRpYWxTdGF0ZS5hYmJyZXZpYXRpb24gOiBcIlwiO1xuICAgICAgICAgICAgdmFyIGl0ZXJhdG9yID0gem9uZS5maW5kRmlyc3QoKTtcbiAgICAgICAgICAgIGlmICgoaXRlcmF0b3IgPT09IG51bGwgfHwgaXRlcmF0b3IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGl0ZXJhdG9yLnRyYW5zaXRpb24ubmV3U3RhdGUuZHN0T2Zmc2V0Lm1pbGxpc2Vjb25kcygpKSA9PT0gMCkge1xuICAgICAgICAgICAgICAgIGxhc3ROb25Ec3QgPSBpdGVyYXRvci50cmFuc2l0aW9uLm5ld1N0YXRlLmFiYnJldmlhdGlvbjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHdoaWxlIChpdGVyYXRvciAmJiBpdGVyYXRvci50cmFuc2l0aW9uLmF0VXRjIDw9IHUpIHtcbiAgICAgICAgICAgICAgICBpdGVyYXRvciA9IHpvbmUuZmluZE5leHQoaXRlcmF0b3IpO1xuICAgICAgICAgICAgICAgIGlmICgoaXRlcmF0b3IgPT09IG51bGwgfHwgaXRlcmF0b3IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGl0ZXJhdG9yLnRyYW5zaXRpb24ubmV3U3RhdGUuZHN0T2Zmc2V0Lm1pbGxpc2Vjb25kcygpKSA9PT0gMCkge1xuICAgICAgICAgICAgICAgICAgICBsYXN0Tm9uRHN0ID0gaXRlcmF0b3IudHJhbnNpdGlvbi5uZXdTdGF0ZS5hYmJyZXZpYXRpb247XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGxhc3ROb25Ec3Q7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIHN0YW5kYXJkIHRpbWUgem9uZSBvZmZzZXQgZnJvbSBVVEMsIGV4Y2x1ZGluZyBEU1QsIGF0XG4gICAgICogdGhlIGdpdmVuIExPQ0FMIHRpbWVzdGFtcCwgYWdhaW4gZXhjbHVkaW5nIERTVC5cbiAgICAgKlxuICAgICAqIElmIHRoZSBsb2NhbCB0aW1lc3RhbXAgZXhpc3RzIHR3aWNlIChhcyBjYW4gb2NjdXIgdmVyeSByYXJlbHkgZHVlIHRvIHpvbmUgY2hhbmdlcylcbiAgICAgKiB0aGVuIHRoZSBmaXJzdCBvY2N1cnJlbmNlIGlzIHJldHVybmVkLlxuICAgICAqXG4gICAgICogVGhyb3dzIGlmIHpvbmUgaW5mbyBub3QgZm91bmQuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gem9uZU5hbWVcdElBTkEgdGltZSB6b25lIG5hbWVcbiAgICAgKiBAcGFyYW0gbG9jYWxUaW1lXHRUaW1lc3RhbXAgaW4gdGltZSB6b25lIHRpbWVcbiAgICAgKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuTm90Rm91bmQuWm9uZSBpZiB6b25lTmFtZSBub3QgZm91bmRcbiAgICAgKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuSW52YWxpZFRpbWVab25lRGF0YSBpZiBhbiBlcnJvciBpcyBkaXNjb3ZlcmVkIGluIHRoZSB0aW1lIHpvbmUgZGF0YWJhc2VcbiAgICAgKi9cbiAgICBUekRhdGFiYXNlLnByb3RvdHlwZS5zdGFuZGFyZE9mZnNldExvY2FsID0gZnVuY3Rpb24gKHpvbmVOYW1lLCBsb2NhbFRpbWUpIHtcbiAgICAgICAgdmFyIHVuaXhNaWxsaXMgPSAodHlwZW9mIGxvY2FsVGltZSA9PT0gXCJudW1iZXJcIiA/IGxvY2FsVGltZSA6IGxvY2FsVGltZS51bml4TWlsbGlzKTtcbiAgICAgICAgdmFyIHpvbmVJbmZvcyA9IHRoaXMuZ2V0Wm9uZUluZm9zKHpvbmVOYW1lKTtcbiAgICAgICAgZm9yICh2YXIgX2kgPSAwLCB6b25lSW5mb3NfMyA9IHpvbmVJbmZvczsgX2kgPCB6b25lSW5mb3NfMy5sZW5ndGg7IF9pKyspIHtcbiAgICAgICAgICAgIHZhciB6b25lSW5mbyA9IHpvbmVJbmZvc18zW19pXTtcbiAgICAgICAgICAgIGlmICh6b25lSW5mby51bnRpbCA9PT0gdW5kZWZpbmVkIHx8IHpvbmVJbmZvLnVudGlsICsgem9uZUluZm8uZ210b2ZmLm1pbGxpc2Vjb25kcygpID4gdW5peE1pbGxpcykge1xuICAgICAgICAgICAgICAgIHJldHVybiB6b25lSW5mby5nbXRvZmYuY2xvbmUoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgaWYgKi9cbiAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbiAgICAgICAgaWYgKHRydWUpIHtcbiAgICAgICAgICAgIHJldHVybiAoMCwgZXJyb3JfMS50aHJvd0Vycm9yKShcIkludmFsaWRUaW1lWm9uZURhdGFcIiwgXCJObyB6b25lIGluZm8gZm91bmRcIik7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIHRvdGFsIHRpbWUgem9uZSBvZmZzZXQgZnJvbSBVVEMsIGluY2x1ZGluZyBEU1QsIGF0XG4gICAgICogdGhlIGdpdmVuIExPQ0FMIHRpbWVzdGFtcC4gTm9uLWV4aXN0aW5nIGxvY2FsIHRpbWUgaXMgbm9ybWFsaXplZCBvdXQuXG4gICAgICogVGhlcmUgY2FuIGJlIG11bHRpcGxlIFVUQyB0aW1lcyBhbmQgdGhlcmVmb3JlIG11bHRpcGxlIG9mZnNldHMgZm9yIGEgbG9jYWwgdGltZVxuICAgICAqIG5hbWVseSBkdXJpbmcgYSBiYWNrd2FyZCBEU1QgY2hhbmdlLiBUaGlzIHJldHVybnMgdGhlIEZJUlNUIHN1Y2ggb2Zmc2V0LlxuICAgICAqIFRocm93cyBpZiB6b25lIGluZm8gbm90IGZvdW5kLlxuICAgICAqXG4gICAgICogQHBhcmFtIHpvbmVOYW1lXHRJQU5BIHRpbWUgem9uZSBuYW1lXG4gICAgICogQHBhcmFtIGxvY2FsVGltZVx0VGltZXN0YW1wIGluIHRpbWUgem9uZSB0aW1lXG4gICAgICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLk5vdEZvdW5kLlpvbmUgaWYgem9uZU5hbWUgbm90IGZvdW5kXG4gICAgICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkludmFsaWRUaW1lWm9uZURhdGEgaWYgYW4gZXJyb3IgaXMgZGlzY292ZXJlZCBpbiB0aGUgdGltZSB6b25lIGRhdGFiYXNlXG4gICAgICovXG4gICAgVHpEYXRhYmFzZS5wcm90b3R5cGUudG90YWxPZmZzZXRMb2NhbCA9IGZ1bmN0aW9uICh6b25lTmFtZSwgbG9jYWxUaW1lKSB7XG4gICAgICAgIHZhciB0cyA9ICh0eXBlb2YgbG9jYWxUaW1lID09PSBcIm51bWJlclwiID8gbmV3IGJhc2ljc18xLlRpbWVTdHJ1Y3QobG9jYWxUaW1lKSA6IGxvY2FsVGltZSk7XG4gICAgICAgIHZhciBub3JtYWxpemVkVG0gPSB0aGlzLm5vcm1hbGl6ZUxvY2FsKHpvbmVOYW1lLCB0cyk7XG4gICAgICAgIC8vLyBOb3RlOiBkdXJpbmcgb2Zmc2V0IGNoYW5nZXMsIGxvY2FsIHRpbWUgY2FuIGJlaGF2ZSBsaWtlOlxuICAgICAgICAvLyBmb3J3YXJkIGNoYW5nZSAoMWgpOiAgIDAgMSAzIDQgNVxuICAgICAgICAvLyBmb3J3YXJkIGNoYW5nZSAoMmgpOiAgIDAgMSA0IDUgNlxuICAgICAgICAvLyBiYWNrd2FyZCBjaGFuZ2UgKDFoKTogIDEgMiAyIDMgNFxuICAgICAgICAvLyBiYWNrd2FyZCBjaGFuZ2UgKDJoKTogIDEgMiAxIDIgMyAgPC0tIG5vdGUgdGltZSBnb2luZyBCQUNLV0FSRFxuICAgICAgICAvLyBUaGVyZWZvcmUgYmluYXJ5IHNlYXJjaCBkb2VzIG5vdCBhcHBseS4gTGluZWFyIHNlYXJjaCB0aHJvdWdoIHRyYW5zaXRpb25zXG4gICAgICAgIC8vIGFuZCByZXR1cm4gdGhlIGZpcnN0IG9mZnNldCB0aGF0IG1hdGNoZXNcbiAgICAgICAgdmFyIHpvbmUgPSB0aGlzLl9nZXRab25lVHJhbnNpdGlvbnMoem9uZU5hbWUpO1xuICAgICAgICB2YXIgdHJhbnNpdGlvbnMgPSB6b25lLnRyYW5zaXRpb25zSW5ZZWFycyhub3JtYWxpemVkVG0uY29tcG9uZW50cy55ZWFyIC0gMSwgbm9ybWFsaXplZFRtLmNvbXBvbmVudHMueWVhciArIDIpO1xuICAgICAgICB2YXIgcHJldjtcbiAgICAgICAgdmFyIHByZXZQcmV2O1xuICAgICAgICBmb3IgKHZhciBfaSA9IDAsIHRyYW5zaXRpb25zXzIgPSB0cmFuc2l0aW9uczsgX2kgPCB0cmFuc2l0aW9uc18yLmxlbmd0aDsgX2krKykge1xuICAgICAgICAgICAgdmFyIHRyYW5zaXRpb24gPSB0cmFuc2l0aW9uc18yW19pXTtcbiAgICAgICAgICAgIHZhciBvZmZzZXQgPSB0cmFuc2l0aW9uLm5ld1N0YXRlLmRzdE9mZnNldC5hZGQodHJhbnNpdGlvbi5uZXdTdGF0ZS5zdGFuZGFyZE9mZnNldCk7XG4gICAgICAgICAgICBpZiAodHJhbnNpdGlvbi5hdFV0Yy51bml4TWlsbGlzICsgb2Zmc2V0Lm1pbGxpc2Vjb25kcygpID4gbm9ybWFsaXplZFRtLnVuaXhNaWxsaXMpIHtcbiAgICAgICAgICAgICAgICAvLyBmb3VuZCBvZmZzZXQ6IHByZXYub2Zmc2V0IGFwcGxpZXNcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHByZXZQcmV2ID0gcHJldjtcbiAgICAgICAgICAgIHByZXYgPSB0cmFuc2l0aW9uO1xuICAgICAgICB9XG4gICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBlbHNlICovXG4gICAgICAgIGlmIChwcmV2KSB7XG4gICAgICAgICAgICAvLyBzcGVjaWFsIGNhcmUgZHVyaW5nIGJhY2t3YXJkIGNoYW5nZTogdGFrZSBmaXJzdCBvY2N1cnJlbmNlIG9mIGxvY2FsIHRpbWVcbiAgICAgICAgICAgIHZhciBwcmV2T2Zmc2V0ID0gcHJldi5uZXdTdGF0ZS5kc3RPZmZzZXQuYWRkKHByZXYubmV3U3RhdGUuc3RhbmRhcmRPZmZzZXQpO1xuICAgICAgICAgICAgdmFyIHByZXZQcmV2T2Zmc2V0ID0gcHJldlByZXYgPyBwcmV2UHJldi5uZXdTdGF0ZS5kc3RPZmZzZXQuYWRkKHByZXZQcmV2Lm5ld1N0YXRlLnN0YW5kYXJkT2Zmc2V0KSA6IHVuZGVmaW5lZDtcbiAgICAgICAgICAgIGlmIChwcmV2UHJldiAmJiBwcmV2UHJldk9mZnNldCAhPT0gdW5kZWZpbmVkICYmIHByZXZQcmV2T2Zmc2V0LmdyZWF0ZXJUaGFuKHByZXZPZmZzZXQpKSB7XG4gICAgICAgICAgICAgICAgLy8gYmFja3dhcmQgY2hhbmdlXG4gICAgICAgICAgICAgICAgdmFyIGRpZmYgPSBwcmV2UHJldk9mZnNldC5zdWIocHJldk9mZnNldCk7XG4gICAgICAgICAgICAgICAgaWYgKG5vcm1hbGl6ZWRUbS51bml4TWlsbGlzID49IHByZXYuYXRVdGMudW5peE1pbGxpcyArIHByZXZPZmZzZXQubWlsbGlzZWNvbmRzKClcbiAgICAgICAgICAgICAgICAgICAgJiYgbm9ybWFsaXplZFRtLnVuaXhNaWxsaXMgPCBwcmV2LmF0VXRjLnVuaXhNaWxsaXMgKyBwcmV2T2Zmc2V0Lm1pbGxpc2Vjb25kcygpICsgZGlmZi5taWxsaXNlY29uZHMoKSkge1xuICAgICAgICAgICAgICAgICAgICAvLyB3aXRoaW4gZHVwbGljYXRlIHJhbmdlXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBwcmV2UHJldk9mZnNldC5jbG9uZSgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHByZXZPZmZzZXQuY2xvbmUoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gcHJldk9mZnNldC5jbG9uZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgdmFyIHN0YXRlID0gem9uZS5zdGF0ZUF0KG5vcm1hbGl6ZWRUbSk7XG4gICAgICAgICAgICByZXR1cm4gc3RhdGUuZHN0T2Zmc2V0LmFkZChzdGF0ZS5zdGFuZGFyZE9mZnNldCk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIC8qKlxuICAgICAqIERFUFJFQ0FURUQgYmVjYXVzZSBEU1Qgb2Zmc2V0IGRlcGVuZHMgb24gdGhlIHpvbmUgdG9vLCBub3QganVzdCBvbiB0aGUgcnVsZXNldFxuICAgICAqIFJldHVybnMgdGhlIERTVCBvZmZzZXQgKFdJVEhPVVQgdGhlIHN0YW5kYXJkIHpvbmUgb2Zmc2V0KSBmb3IgdGhlIGdpdmVuIHJ1bGVzZXQgYW5kIHRoZSBnaXZlbiBVVEMgdGltZXN0YW1wXG4gICAgICpcbiAgICAgKiBAZGVwcmVjYXRlZFxuICAgICAqIEBwYXJhbSBydWxlTmFtZVx0bmFtZSBvZiBydWxlc2V0XG4gICAgICogQHBhcmFtIHV0Y1RpbWVcdFVUQyB0aW1lc3RhbXBcbiAgICAgKiBAcGFyYW0gc3RhbmRhcmRPZmZzZXRcdFN0YW5kYXJkIG9mZnNldCB3aXRob3V0IERTVCBmb3IgdGhlIHRpbWUgem9uZVxuICAgICAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Ob3RGb3VuZC5SdWxlIGlmIHJ1bGVOYW1lIG5vdCBmb3VuZFxuICAgICAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5JbnZhbGlkVGltZVpvbmVEYXRhIGlmIGFuIGVycm9yIGlzIGRpc2NvdmVyZWQgaW4gdGhlIHRpbWUgem9uZSBkYXRhYmFzZVxuICAgICAqL1xuICAgIFR6RGF0YWJhc2UucHJvdG90eXBlLmRzdE9mZnNldEZvclJ1bGUgPSBmdW5jdGlvbiAocnVsZU5hbWUsIHV0Y1RpbWUsIHN0YW5kYXJkT2Zmc2V0KSB7XG4gICAgICAgIHZhciB0cyA9ICh0eXBlb2YgdXRjVGltZSA9PT0gXCJudW1iZXJcIiA/IG5ldyBiYXNpY3NfMS5UaW1lU3RydWN0KHV0Y1RpbWUpIDogdXRjVGltZSk7XG4gICAgICAgIC8vIGZpbmQgYXBwbGljYWJsZSB0cmFuc2l0aW9uIG1vbWVudHNcbiAgICAgICAgdmFyIHRyYW5zaXRpb25zID0gdGhpcy5nZXRUcmFuc2l0aW9uc0RzdE9mZnNldHMocnVsZU5hbWUsIHRzLmNvbXBvbmVudHMueWVhciAtIDEsIHRzLmNvbXBvbmVudHMueWVhciwgc3RhbmRhcmRPZmZzZXQpO1xuICAgICAgICAvLyBmaW5kIHRoZSBsYXN0IHByaW9yIHRvIGdpdmVuIGRhdGVcbiAgICAgICAgdmFyIG9mZnNldDtcbiAgICAgICAgZm9yICh2YXIgaSA9IHRyYW5zaXRpb25zLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7XG4gICAgICAgICAgICB2YXIgdHJhbnNpdGlvbiA9IHRyYW5zaXRpb25zW2ldO1xuICAgICAgICAgICAgaWYgKHRyYW5zaXRpb24uYXQgPD0gdHMudW5peE1pbGxpcykge1xuICAgICAgICAgICAgICAgIG9mZnNldCA9IHRyYW5zaXRpb24ub2Zmc2V0LmNsb25lKCk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIGlmICovXG4gICAgICAgIGlmICghb2Zmc2V0KSB7XG4gICAgICAgICAgICAvLyBhcHBhcmVudGx5IG5vIGxvbmdlciBEU1QsIGFzIGUuZy4gZm9yIEFzaWEvVG9reW9cbiAgICAgICAgICAgIG9mZnNldCA9IGR1cmF0aW9uXzEuRHVyYXRpb24ubWludXRlcygwKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gb2Zmc2V0O1xuICAgIH07XG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgdGltZSB6b25lIGxldHRlciBmb3IgdGhlIGdpdmVuXG4gICAgICogcnVsZXNldCBhbmQgdGhlIGdpdmVuIFVUQyB0aW1lc3RhbXBcbiAgICAgKlxuICAgICAqIEBkZXByZWNhdGVkXG4gICAgICogQHBhcmFtIHJ1bGVOYW1lXHRuYW1lIG9mIHJ1bGVzZXRcbiAgICAgKiBAcGFyYW0gdXRjVGltZVx0VVRDIHRpbWVzdGFtcCBhcyBUaW1lU3RydWN0IG9yIHVuaXggbWlsbGlzXG4gICAgICogQHBhcmFtIHN0YW5kYXJkT2Zmc2V0XHRTdGFuZGFyZCBvZmZzZXQgd2l0aG91dCBEU1QgZm9yIHRoZSB0aW1lIHpvbmVcbiAgICAgKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuTm90Rm91bmQuUnVsZSBpZiBydWxlTmFtZSBub3QgZm91bmRcbiAgICAgKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuSW52YWxpZFRpbWVab25lRGF0YSBpZiBhbiBlcnJvciBpcyBkaXNjb3ZlcmVkIGluIHRoZSB0aW1lIHpvbmUgZGF0YWJhc2VcbiAgICAgKi9cbiAgICBUekRhdGFiYXNlLnByb3RvdHlwZS5sZXR0ZXJGb3JSdWxlID0gZnVuY3Rpb24gKHJ1bGVOYW1lLCB1dGNUaW1lLCBzdGFuZGFyZE9mZnNldCkge1xuICAgICAgICB2YXIgdHMgPSAodHlwZW9mIHV0Y1RpbWUgPT09IFwibnVtYmVyXCIgPyBuZXcgYmFzaWNzXzEuVGltZVN0cnVjdCh1dGNUaW1lKSA6IHV0Y1RpbWUpO1xuICAgICAgICAvLyBmaW5kIGFwcGxpY2FibGUgdHJhbnNpdGlvbiBtb21lbnRzXG4gICAgICAgIHZhciB0cmFuc2l0aW9ucyA9IHRoaXMuZ2V0VHJhbnNpdGlvbnNEc3RPZmZzZXRzKHJ1bGVOYW1lLCB0cy5jb21wb25lbnRzLnllYXIgLSAxLCB0cy5jb21wb25lbnRzLnllYXIsIHN0YW5kYXJkT2Zmc2V0KTtcbiAgICAgICAgLy8gZmluZCB0aGUgbGFzdCBwcmlvciB0byBnaXZlbiBkYXRlXG4gICAgICAgIHZhciBsZXR0ZXI7XG4gICAgICAgIGZvciAodmFyIGkgPSB0cmFuc2l0aW9ucy5sZW5ndGggLSAxOyBpID49IDA7IGktLSkge1xuICAgICAgICAgICAgdmFyIHRyYW5zaXRpb24gPSB0cmFuc2l0aW9uc1tpXTtcbiAgICAgICAgICAgIGlmICh0cmFuc2l0aW9uLmF0IDw9IHRzLnVuaXhNaWxsaXMpIHtcbiAgICAgICAgICAgICAgICBsZXR0ZXIgPSB0cmFuc2l0aW9uLmxldHRlcjtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgaWYgKi9cbiAgICAgICAgaWYgKCFsZXR0ZXIpIHtcbiAgICAgICAgICAgIC8vIGFwcGFyZW50bHkgbm8gbG9uZ2VyIERTVCwgYXMgZS5nLiBmb3IgQXNpYS9Ub2t5b1xuICAgICAgICAgICAgbGV0dGVyID0gXCJcIjtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbGV0dGVyO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogREVQUkVDQVRFRCBiZWNhdXNlIERTVCBvZmZzZXQgZGVwZW5kcyBvbiB0aGUgem9uZSB0b28sIG5vdCBqdXN0IG9uIHRoZSBydWxlc2V0XG4gICAgICogUmV0dXJuIGEgbGlzdCBvZiBhbGwgdHJhbnNpdGlvbnMgaW4gW2Zyb21ZZWFyLi50b1llYXJdIHNvcnRlZCBieSBlZmZlY3RpdmUgZGF0ZVxuICAgICAqXG4gICAgICogQGRlcHJlY2F0ZWRcbiAgICAgKiBAcGFyYW0gcnVsZU5hbWVcdE5hbWUgb2YgdGhlIHJ1bGUgc2V0XG4gICAgICogQHBhcmFtIGZyb21ZZWFyXHRmaXJzdCB5ZWFyIHRvIHJldHVybiB0cmFuc2l0aW9ucyBmb3JcbiAgICAgKiBAcGFyYW0gdG9ZZWFyXHRMYXN0IHllYXIgdG8gcmV0dXJuIHRyYW5zaXRpb25zIGZvclxuICAgICAqIEBwYXJhbSBzdGFuZGFyZE9mZnNldFx0U3RhbmRhcmQgb2Zmc2V0IHdpdGhvdXQgRFNUIGZvciB0aGUgdGltZSB6b25lXG4gICAgICpcbiAgICAgKiBAcmV0dXJuIFRyYW5zaXRpb25zLCB3aXRoIERTVCBvZmZzZXRzIChubyBzdGFuZGFyZCBvZmZzZXQgaW5jbHVkZWQpXG4gICAgICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LkZyb21ZZWFyIGlmIGZyb21ZZWFyID4gdG9ZZWFyXG4gICAgICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLk5vdEZvdW5kLlJ1bGUgaWYgcnVsZU5hbWUgbm90IGZvdW5kXG4gICAgICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkludmFsaWRUaW1lWm9uZURhdGEgaWYgYW4gZXJyb3IgaXMgZGlzY292ZXJlZCBpbiB0aGUgdGltZSB6b25lIGRhdGFiYXNlXG4gICAgICovXG4gICAgVHpEYXRhYmFzZS5wcm90b3R5cGUuZ2V0VHJhbnNpdGlvbnNEc3RPZmZzZXRzID0gZnVuY3Rpb24gKHJ1bGVOYW1lLCBmcm9tWWVhciwgdG9ZZWFyLCBzdGFuZGFyZE9mZnNldCkge1xuICAgICAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkoZnJvbVllYXIgPD0gdG9ZZWFyLCBcIkFyZ3VtZW50LkZyb21ZZWFyXCIsIFwiZnJvbVllYXIgbXVzdCBiZSA8PSB0b1llYXJcIik7XG4gICAgICAgIHZhciBydWxlcyA9IHRoaXMuX2dldFJ1bGVUcmFuc2l0aW9ucyhydWxlTmFtZSk7XG4gICAgICAgIHZhciByZXN1bHQgPSBbXTtcbiAgICAgICAgdmFyIHByZXZEc3QgPSAoMCwgZHVyYXRpb25fMS5ob3VycykoMCk7IC8vIHdyb25nLCBidXQgdGhhdCdzIHdoeSB0aGUgZnVuY3Rpb24gaXMgZGVwcmVjYXRlZFxuICAgICAgICB2YXIgaXRlcmF0b3IgPSBydWxlcy5maW5kRmlyc3QoKTtcbiAgICAgICAgd2hpbGUgKGl0ZXJhdG9yICYmIGl0ZXJhdG9yLnRyYW5zaXRpb24uYXQueWVhciA8PSB0b1llYXIpIHtcbiAgICAgICAgICAgIGlmIChpdGVyYXRvci50cmFuc2l0aW9uLmF0LnllYXIgPj0gZnJvbVllYXIgJiYgaXRlcmF0b3IudHJhbnNpdGlvbi5hdC55ZWFyIDw9IHRvWWVhcikge1xuICAgICAgICAgICAgICAgIHJlc3VsdC5wdXNoKHtcbiAgICAgICAgICAgICAgICAgICAgYXQ6IHJ1bGVUcmFuc2l0aW9uVXRjKGl0ZXJhdG9yLnRyYW5zaXRpb24sIHN0YW5kYXJkT2Zmc2V0LCBwcmV2RHN0KS51bml4TWlsbGlzLFxuICAgICAgICAgICAgICAgICAgICBsZXR0ZXI6IGl0ZXJhdG9yLnRyYW5zaXRpb24ubmV3U3RhdGUubGV0dGVyIHx8IFwiXCIsXG4gICAgICAgICAgICAgICAgICAgIG9mZnNldDogaXRlcmF0b3IudHJhbnNpdGlvbi5uZXdTdGF0ZS5kc3RPZmZzZXRcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHByZXZEc3QgPSBpdGVyYXRvci50cmFuc2l0aW9uLm5ld1N0YXRlLmRzdE9mZnNldDtcbiAgICAgICAgICAgIGl0ZXJhdG9yID0gcnVsZXMuZmluZE5leHQoaXRlcmF0b3IpO1xuICAgICAgICB9XG4gICAgICAgIHJlc3VsdC5zb3J0KGZ1bmN0aW9uIChhLCBiKSB7XG4gICAgICAgICAgICByZXR1cm4gYS5hdCAtIGIuYXQ7XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH07XG4gICAgLyoqXG4gICAgICogUmV0dXJuIGJvdGggem9uZSBhbmQgcnVsZSBjaGFuZ2VzIGFzIHRvdGFsIChzdGQgKyBkc3QpIG9mZnNldHMuXG4gICAgICogQWRkcyBhbiBpbml0aWFsIHRyYW5zaXRpb24gaWYgdGhlcmUgaXMgbm9uZSB3aXRoaW4gdGhlIHJhbmdlLlxuICAgICAqXG4gICAgICogQHBhcmFtIHpvbmVOYW1lXHRJQU5BIHpvbmUgbmFtZVxuICAgICAqIEBwYXJhbSBmcm9tWWVhclx0Rmlyc3QgeWVhciB0byBpbmNsdWRlXG4gICAgICogQHBhcmFtIHRvWWVhclx0TGFzdCB5ZWFyIHRvIGluY2x1ZGVcbiAgICAgKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuRnJvbVllYXIgaWYgZnJvbVllYXIgPiB0b1llYXJcbiAgICAgKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuTm90Rm91bmQuWm9uZSBpZiB6b25lTmFtZSBub3QgZm91bmRcbiAgICAgKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuSW52YWxpZFRpbWVab25lRGF0YSBpZiBhbiBlcnJvciBpcyBkaXNjb3ZlcmVkIGluIHRoZSB0aW1lIHpvbmUgZGF0YWJhc2VcbiAgICAgKi9cbiAgICBUekRhdGFiYXNlLnByb3RvdHlwZS5nZXRUcmFuc2l0aW9uc1RvdGFsT2Zmc2V0cyA9IGZ1bmN0aW9uICh6b25lTmFtZSwgZnJvbVllYXIsIHRvWWVhcikge1xuICAgICAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkoZnJvbVllYXIgPD0gdG9ZZWFyLCBcIkFyZ3VtZW50LkZyb21ZZWFyXCIsIFwiZnJvbVllYXIgbXVzdCBiZSA8PSB0b1llYXJcIik7XG4gICAgICAgIHZhciB6b25lID0gdGhpcy5fZ2V0Wm9uZVRyYW5zaXRpb25zKHpvbmVOYW1lKTtcbiAgICAgICAgdmFyIHJlc3VsdCA9IFtdO1xuICAgICAgICB2YXIgc3RhcnRTdGF0ZSA9IHpvbmUuc3RhdGVBdChuZXcgYmFzaWNzXzEuVGltZVN0cnVjdCh7IHllYXI6IGZyb21ZZWFyLCBtb250aDogMSwgZGF5OiAxIH0pKTtcbiAgICAgICAgcmVzdWx0LnB1c2goe1xuICAgICAgICAgICAgYXQ6IG5ldyBiYXNpY3NfMS5UaW1lU3RydWN0KHsgeWVhcjogZnJvbVllYXIgfSkudW5peE1pbGxpcyxcbiAgICAgICAgICAgIGxldHRlcjogc3RhcnRTdGF0ZS5sZXR0ZXIsXG4gICAgICAgICAgICBvZmZzZXQ6IHN0YXJ0U3RhdGUuZHN0T2Zmc2V0LmFkZChzdGFydFN0YXRlLnN0YW5kYXJkT2Zmc2V0KVxuICAgICAgICB9KTtcbiAgICAgICAgdmFyIGl0ZXJhdG9yID0gem9uZS5maW5kRmlyc3QoKTtcbiAgICAgICAgd2hpbGUgKGl0ZXJhdG9yICYmIGl0ZXJhdG9yLnRyYW5zaXRpb24uYXRVdGMueWVhciA8PSB0b1llYXIpIHtcbiAgICAgICAgICAgIGlmIChpdGVyYXRvci50cmFuc2l0aW9uLmF0VXRjLnllYXIgPj0gZnJvbVllYXIpIHtcbiAgICAgICAgICAgICAgICByZXN1bHQucHVzaCh7XG4gICAgICAgICAgICAgICAgICAgIGF0OiBpdGVyYXRvci50cmFuc2l0aW9uLmF0VXRjLnVuaXhNaWxsaXMsXG4gICAgICAgICAgICAgICAgICAgIGxldHRlcjogaXRlcmF0b3IudHJhbnNpdGlvbi5uZXdTdGF0ZS5sZXR0ZXIgfHwgXCJcIixcbiAgICAgICAgICAgICAgICAgICAgb2Zmc2V0OiBpdGVyYXRvci50cmFuc2l0aW9uLm5ld1N0YXRlLmRzdE9mZnNldC5hZGQoaXRlcmF0b3IudHJhbnNpdGlvbi5uZXdTdGF0ZS5zdGFuZGFyZE9mZnNldClcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGl0ZXJhdG9yID0gem9uZS5maW5kTmV4dChpdGVyYXRvcik7XG4gICAgICAgIH1cbiAgICAgICAgcmVzdWx0LnNvcnQoZnVuY3Rpb24gKGEsIGIpIHtcbiAgICAgICAgICAgIHJldHVybiBhLmF0IC0gYi5hdDtcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBHZXQgdGhlIHpvbmUgaW5mbyBmb3IgdGhlIGdpdmVuIFVUQyB0aW1lc3RhbXAuIFRocm93cyBpZiBub3QgZm91bmQuXG4gICAgICogQHBhcmFtIHpvbmVOYW1lXHRJQU5BIHRpbWUgem9uZSBuYW1lXG4gICAgICogQHBhcmFtIHV0Y1RpbWVcdFVUQyB0aW1lIHN0YW1wIGFzIHVuaXggbWlsbGlzZWNvbmRzIG9yIGFzIGEgVGltZVN0cnVjdFxuICAgICAqIEByZXR1cm5zXHRab25lSW5mbyBvYmplY3QuIERvIG5vdCBjaGFuZ2UsIHdlIGNhY2hlIHRoaXMgb2JqZWN0LlxuICAgICAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Ob3RGb3VuZC5ab25lIGlmIHpvbmUgbmFtZSBub3QgZm91bmQgb3IgYSBsaW5rZWQgem9uZSBub3QgZm91bmRcbiAgICAgKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuSW52YWxpZFRpbWVab25lRGF0YSBpZiB2YWx1ZXMgaW4gdGhlIHRpbWUgem9uZSBkYXRhYmFzZSBhcmUgaW52YWxpZFxuICAgICAqL1xuICAgIFR6RGF0YWJhc2UucHJvdG90eXBlLmdldFpvbmVJbmZvID0gZnVuY3Rpb24gKHpvbmVOYW1lLCB1dGNUaW1lKSB7XG4gICAgICAgIHZhciB1bml4TWlsbGlzID0gKHR5cGVvZiB1dGNUaW1lID09PSBcIm51bWJlclwiID8gdXRjVGltZSA6IHV0Y1RpbWUudW5peE1pbGxpcyk7XG4gICAgICAgIHZhciB6b25lSW5mb3MgPSB0aGlzLmdldFpvbmVJbmZvcyh6b25lTmFtZSk7XG4gICAgICAgIGZvciAodmFyIF9pID0gMCwgem9uZUluZm9zXzQgPSB6b25lSW5mb3M7IF9pIDwgem9uZUluZm9zXzQubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgICAgICB2YXIgem9uZUluZm8gPSB6b25lSW5mb3NfNFtfaV07XG4gICAgICAgICAgICBpZiAoem9uZUluZm8udW50aWwgPT09IHVuZGVmaW5lZCB8fCB6b25lSW5mby51bnRpbCA+IHVuaXhNaWxsaXMpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gem9uZUluZm87XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuICgwLCBlcnJvcl8xLnRocm93RXJyb3IpKFwiTm90Rm91bmQuWm9uZVwiLCBcIlxcXCJubyB6b25lIGluZm8gZm91bmQgZm9yIHpvbmUgJ1wiLmNvbmNhdCh6b25lTmFtZSwgXCInXCIpKTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFJldHVybiB0aGUgem9uZSByZWNvcmRzIGZvciBhIGdpdmVuIHpvbmUgbmFtZSBzb3J0ZWQgYnkgVU5USUwsIGFmdGVyXG4gICAgICogZm9sbG93aW5nIGFueSBsaW5rcy5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB6b25lTmFtZVx0SUFOQSB6b25lIG5hbWUgbGlrZSBcIlBhY2lmaWMvRWZhdGVcIlxuICAgICAqIEByZXR1cm4gQXJyYXkgb2Ygem9uZSBpbmZvcy4gRG8gbm90IGNoYW5nZSwgdGhpcyBpcyBhIGNhY2hlZCB2YWx1ZS5cbiAgICAgKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuTm90Rm91bmQuWm9uZSBpZiB6b25lIGRvZXMgbm90IGV4aXN0IG9yIGEgbGlua2VkIHpvbmUgZG9lcyBub3QgZXhpdFxuICAgICAqL1xuICAgIFR6RGF0YWJhc2UucHJvdG90eXBlLmdldFpvbmVJbmZvcyA9IGZ1bmN0aW9uICh6b25lTmFtZSkge1xuICAgICAgICAvLyBGSVJTVCB2YWxpZGF0ZSB6b25lIG5hbWUgYmVmb3JlIHNlYXJjaGluZyBjYWNoZVxuICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgaWYgKi9cbiAgICAgICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKHRoaXMuX2RhdGEuem9uZXMuaGFzT3duUHJvcGVydHkoem9uZU5hbWUpLCBcIk5vdEZvdW5kLlpvbmVcIiwgXCJ6b25lIG5vdCBmb3VuZDogJ1wiLmNvbmNhdCh6b25lTmFtZSwgXCInXCIpKTtcbiAgICAgICAgLy8gVGFrZSBmcm9tIGNhY2hlXG4gICAgICAgIGlmICh0aGlzLl96b25lSW5mb0NhY2hlLmhhc093blByb3BlcnR5KHpvbmVOYW1lKSkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3pvbmVJbmZvQ2FjaGVbem9uZU5hbWVdO1xuICAgICAgICB9XG4gICAgICAgIHZhciByZXN1bHQgPSBbXTtcbiAgICAgICAgdmFyIGFjdHVhbFpvbmVOYW1lID0gem9uZU5hbWU7XG4gICAgICAgIHZhciB6b25lRW50cmllcyA9IHRoaXMuX2RhdGEuem9uZXNbem9uZU5hbWVdO1xuICAgICAgICAvLyBmb2xsb3cgbGlua3NcbiAgICAgICAgd2hpbGUgKHR5cGVvZiAoem9uZUVudHJpZXMpID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgaWYgKi9cbiAgICAgICAgICAgIGlmICghdGhpcy5fZGF0YS56b25lcy5oYXNPd25Qcm9wZXJ0eSh6b25lRW50cmllcykpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gKDAsIGVycm9yXzEudGhyb3dFcnJvcikoXCJOb3RGb3VuZC5ab25lXCIsIFwiWm9uZSBcXFwiXCIgKyB6b25lRW50cmllcyArIFwiXFxcIiBub3QgZm91bmQgKHJlZmVycmVkIHRvIGluIGxpbmsgZnJvbSBcXFwiXCJcbiAgICAgICAgICAgICAgICAgICAgKyB6b25lTmFtZSArIFwiXFxcIiB2aWEgXFxcIlwiICsgYWN0dWFsWm9uZU5hbWUgKyBcIlxcXCJcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBhY3R1YWxab25lTmFtZSA9IHpvbmVFbnRyaWVzO1xuICAgICAgICAgICAgem9uZUVudHJpZXMgPSB0aGlzLl9kYXRhLnpvbmVzW2FjdHVhbFpvbmVOYW1lXTtcbiAgICAgICAgfVxuICAgICAgICAvLyBmaW5hbCB6b25lIGluZm8gZm91bmRcbiAgICAgICAgZm9yICh2YXIgX2kgPSAwLCB6b25lRW50cmllc18xID0gem9uZUVudHJpZXM7IF9pIDwgem9uZUVudHJpZXNfMS5sZW5ndGg7IF9pKyspIHtcbiAgICAgICAgICAgIHZhciB6b25lRW50cnkgPSB6b25lRW50cmllc18xW19pXTtcbiAgICAgICAgICAgIHZhciBydWxlVHlwZSA9IHRoaXMucGFyc2VSdWxlVHlwZSh6b25lRW50cnlbMV0pO1xuICAgICAgICAgICAgdmFyIHVudGlsID0gbWF0aC5maWx0ZXJGbG9hdCh6b25lRW50cnlbM10pO1xuICAgICAgICAgICAgaWYgKGlzTmFOKHVudGlsKSkge1xuICAgICAgICAgICAgICAgIHVudGlsID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmVzdWx0LnB1c2gobmV3IFpvbmVJbmZvKGR1cmF0aW9uXzEuRHVyYXRpb24ubWludXRlcygtMSAqIG1hdGguZmlsdGVyRmxvYXQoem9uZUVudHJ5WzBdKSksIHJ1bGVUeXBlLCBydWxlVHlwZSA9PT0gUnVsZVR5cGUuT2Zmc2V0ID8gbmV3IGR1cmF0aW9uXzEuRHVyYXRpb24oem9uZUVudHJ5WzFdKSA6IG5ldyBkdXJhdGlvbl8xLkR1cmF0aW9uKCksIHJ1bGVUeXBlID09PSBSdWxlVHlwZS5SdWxlTmFtZSA/IHpvbmVFbnRyeVsxXSA6IFwiXCIsIHpvbmVFbnRyeVsyXSwgdW50aWwpKTtcbiAgICAgICAgfVxuICAgICAgICByZXN1bHQuc29ydChmdW5jdGlvbiAoYSwgYikge1xuICAgICAgICAgICAgLy8gc29ydCB1bmRlZmluZWQgbGFzdFxuICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIGlmICovXG4gICAgICAgICAgICBpZiAoYS51bnRpbCA9PT0gdW5kZWZpbmVkICYmIGIudW50aWwgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIHJldHVybiAwO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGEudW50aWwgIT09IHVuZGVmaW5lZCAmJiBiLnVudGlsID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gLTE7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoYS51bnRpbCA9PT0gdW5kZWZpbmVkICYmIGIudW50aWwgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIHJldHVybiAxO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIChhLnVudGlsIC0gYi51bnRpbCk7XG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLl96b25lSW5mb0NhY2hlW3pvbmVOYW1lXSA9IHJlc3VsdDtcbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIHJ1bGUgc2V0IHdpdGggdGhlIGdpdmVuIHJ1bGUgbmFtZSxcbiAgICAgKiBzb3J0ZWQgYnkgZmlyc3QgZWZmZWN0aXZlIGRhdGUgKHVuY29tcGVuc2F0ZWQgZm9yIFwid1wiIG9yIFwic1wiIEF0VGltZSlcbiAgICAgKlxuICAgICAqIEBwYXJhbSBydWxlTmFtZVx0TmFtZSBvZiBydWxlIHNldFxuICAgICAqIEByZXR1cm4gUnVsZUluZm8gYXJyYXkuIERvIG5vdCBjaGFuZ2UsIHRoaXMgaXMgYSBjYWNoZWQgdmFsdWUuXG4gICAgICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLk5vdEZvdW5kLlJ1bGUgaWYgcnVsZSBub3QgZm91bmRcbiAgICAgKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuSW52YWxpZFRpbWVab25lRGF0YSBmb3IgaW52YWxpZCB2YWx1ZXMgaW4gdGhlIHRpbWUgem9uZSBkYXRhYmFzZVxuICAgICAqL1xuICAgIFR6RGF0YWJhc2UucHJvdG90eXBlLmdldFJ1bGVJbmZvcyA9IGZ1bmN0aW9uIChydWxlTmFtZSkge1xuICAgICAgICAvLyB2YWxpZGF0ZSBuYW1lIEJFRk9SRSBzZWFyY2hpbmcgY2FjaGVcbiAgICAgICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKHRoaXMuX2RhdGEucnVsZXMuaGFzT3duUHJvcGVydHkocnVsZU5hbWUpLCBcIk5vdEZvdW5kLlJ1bGVcIiwgXCJSdWxlIHNldCBcXFwiXCIgKyBydWxlTmFtZSArIFwiXFxcIiBub3QgZm91bmQuXCIpO1xuICAgICAgICAvLyByZXR1cm4gZnJvbSBjYWNoZVxuICAgICAgICBpZiAodGhpcy5fcnVsZUluZm9DYWNoZS5oYXNPd25Qcm9wZXJ0eShydWxlTmFtZSkpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9ydWxlSW5mb0NhY2hlW3J1bGVOYW1lXTtcbiAgICAgICAgfVxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgdmFyIHJlc3VsdCA9IFtdO1xuICAgICAgICAgICAgdmFyIHJ1bGVTZXQgPSB0aGlzLl9kYXRhLnJ1bGVzW3J1bGVOYW1lXTtcbiAgICAgICAgICAgIGZvciAodmFyIF9pID0gMCwgcnVsZVNldF8xID0gcnVsZVNldDsgX2kgPCBydWxlU2V0XzEubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgICAgICAgICAgdmFyIHJ1bGUgPSBydWxlU2V0XzFbX2ldO1xuICAgICAgICAgICAgICAgIHZhciBmcm9tWWVhciA9IChydWxlWzBdID09PSBcIk5hTlwiID8gLTEwMDAwIDogcGFyc2VJbnQocnVsZVswXSwgMTApKTtcbiAgICAgICAgICAgICAgICB2YXIgdG9UeXBlID0gdGhpcy5wYXJzZVRvVHlwZShydWxlWzFdKTtcbiAgICAgICAgICAgICAgICB2YXIgdG9ZZWFyID0gKHRvVHlwZSA9PT0gVG9UeXBlLk1heCA/IDAgOiAocnVsZVsxXSA9PT0gXCJvbmx5XCIgPyBmcm9tWWVhciA6IHBhcnNlSW50KHJ1bGVbMV0sIDEwKSkpO1xuICAgICAgICAgICAgICAgIHZhciBvblR5cGUgPSB0aGlzLnBhcnNlT25UeXBlKHJ1bGVbNF0pO1xuICAgICAgICAgICAgICAgIHZhciBvbkRheSA9IHRoaXMucGFyc2VPbkRheShydWxlWzRdLCBvblR5cGUpO1xuICAgICAgICAgICAgICAgIHZhciBvbldlZWtEYXkgPSB0aGlzLnBhcnNlT25XZWVrRGF5KHJ1bGVbNF0pO1xuICAgICAgICAgICAgICAgIHZhciBtb250aE5hbWUgPSBydWxlWzNdO1xuICAgICAgICAgICAgICAgIHZhciBtb250aE51bWJlciA9IG1vbnRoTmFtZVRvTnVtYmVyKG1vbnRoTmFtZSk7XG4gICAgICAgICAgICAgICAgcmVzdWx0LnB1c2gobmV3IFJ1bGVJbmZvKGZyb21ZZWFyLCB0b1R5cGUsIHRvWWVhciwgcnVsZVsyXSwgbW9udGhOdW1iZXIsIG9uVHlwZSwgb25EYXksIG9uV2Vla0RheSwgbWF0aC5wb3NpdGl2ZU1vZHVsbyhwYXJzZUludChydWxlWzVdWzBdLCAxMCksIDI0KSwgLy8gbm90ZSB0aGUgZGF0YWJhc2Ugc29tZXRpbWVzIGNvbnRhaW5zIFwiMjRcIiBhcyBob3VyIHZhbHVlXG4gICAgICAgICAgICAgICAgbWF0aC5wb3NpdGl2ZU1vZHVsbyhwYXJzZUludChydWxlWzVdWzFdLCAxMCksIDYwKSwgbWF0aC5wb3NpdGl2ZU1vZHVsbyhwYXJzZUludChydWxlWzVdWzJdLCAxMCksIDYwKSwgdGhpcy5wYXJzZUF0VHlwZShydWxlWzVdWzNdKSwgZHVyYXRpb25fMS5EdXJhdGlvbi5taW51dGVzKHBhcnNlSW50KHJ1bGVbNl0sIDEwKSksIHJ1bGVbN10gPT09IFwiLVwiID8gXCJcIiA6IHJ1bGVbN10pKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJlc3VsdC5zb3J0KGZ1bmN0aW9uIChhLCBiKSB7XG4gICAgICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIGlmICovXG4gICAgICAgICAgICAgICAgaWYgKGEuZWZmZWN0aXZlRXF1YWwoYikpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIDA7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2UgaWYgKGEuZWZmZWN0aXZlTGVzcyhiKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gLTE7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gMTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHRoaXMuX3J1bGVJbmZvQ2FjaGVbcnVsZU5hbWVdID0gcmVzdWx0O1xuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfVxuICAgICAgICBjYXRjaCAoZSkge1xuICAgICAgICAgICAgaWYgKCgwLCBlcnJvcl8xLmVycm9ySXMpKGUsIFtcIkFyZ3VtZW50LlRvXCIsIFwiQXJndW1lbnQuTlwiLCBcIkFyZ3VtZW50LlZhbHVlXCIsIFwiQXJndW1lbnQuQW1vdW50XCJdKSkge1xuICAgICAgICAgICAgICAgIGUgPSAoMCwgZXJyb3JfMS5lcnJvcikoXCJJbnZhbGlkVGltZVpvbmVEYXRhXCIsIGUubWVzc2FnZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aHJvdyBlO1xuICAgICAgICB9XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBQYXJzZSB0aGUgUlVMRVMgY29sdW1uIG9mIGEgem9uZSBpbmZvIGVudHJ5XG4gICAgICogYW5kIHNlZSB3aGF0IGtpbmQgb2YgZW50cnkgaXQgaXMuXG4gICAgICogQHRocm93cyBub3RoaW5nXG4gICAgICovXG4gICAgVHpEYXRhYmFzZS5wcm90b3R5cGUucGFyc2VSdWxlVHlwZSA9IGZ1bmN0aW9uIChydWxlKSB7XG4gICAgICAgIGlmIChydWxlID09PSBcIi1cIikge1xuICAgICAgICAgICAgcmV0dXJuIFJ1bGVUeXBlLk5vbmU7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoaXNWYWxpZE9mZnNldFN0cmluZyhydWxlKSkge1xuICAgICAgICAgICAgcmV0dXJuIFJ1bGVUeXBlLk9mZnNldDtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBSdWxlVHlwZS5SdWxlTmFtZTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgLyoqXG4gICAgICogUGFyc2UgdGhlIFRPIGNvbHVtbiBvZiBhIHJ1bGUgaW5mbyBlbnRyeVxuICAgICAqIGFuZCBzZWUgd2hhdCBraW5kIG9mIGVudHJ5IGl0IGlzLlxuICAgICAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Bcmd1bWVudC5UbyBmb3IgaW52YWxpZCBUT1xuICAgICAqL1xuICAgIFR6RGF0YWJhc2UucHJvdG90eXBlLnBhcnNlVG9UeXBlID0gZnVuY3Rpb24gKHRvKSB7XG4gICAgICAgIC8vIGlzdGFuYnVsIGlnbm9yZSBlbHNlXG4gICAgICAgIGlmICh0byA9PT0gXCJtYXhcIikge1xuICAgICAgICAgICAgcmV0dXJuIFRvVHlwZS5NYXg7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAodG8gPT09IFwib25seVwiKSB7XG4gICAgICAgICAgICByZXR1cm4gVG9UeXBlLlllYXI7IC8vIHllcyB3ZSByZXR1cm4gWWVhciBmb3Igb25seVxuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKCFpc05hTihwYXJzZUludCh0bywgMTApKSkge1xuICAgICAgICAgICAgcmV0dXJuIFRvVHlwZS5ZZWFyO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuICgwLCBlcnJvcl8xLnRocm93RXJyb3IpKFwiQXJndW1lbnQuVG9cIiwgXCJUTyBjb2x1bW4gaW5jb3JyZWN0OiBcIi5jb25jYXQodG8pKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgLyoqXG4gICAgICogUGFyc2UgdGhlIE9OIGNvbHVtbiBvZiBhIHJ1bGUgaW5mbyBlbnRyeVxuICAgICAqIGFuZCBzZWUgd2hhdCBraW5kIG9mIGVudHJ5IGl0IGlzLlxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIFR6RGF0YWJhc2UucHJvdG90eXBlLnBhcnNlT25UeXBlID0gZnVuY3Rpb24gKG9uKSB7XG4gICAgICAgIGlmIChvbi5sZW5ndGggPiA0ICYmIG9uLnN1YnN0cigwLCA0KSA9PT0gXCJsYXN0XCIpIHtcbiAgICAgICAgICAgIHJldHVybiBPblR5cGUuTGFzdFg7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG9uLmluZGV4T2YoXCI8PVwiKSAhPT0gLTEpIHtcbiAgICAgICAgICAgIHJldHVybiBPblR5cGUuTGVxWDtcbiAgICAgICAgfVxuICAgICAgICBpZiAob24uaW5kZXhPZihcIj49XCIpICE9PSAtMSkge1xuICAgICAgICAgICAgcmV0dXJuIE9uVHlwZS5HcmVxWDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gT25UeXBlLkRheU51bTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIEdldCB0aGUgZGF5IG51bWJlciBmcm9tIGFuIE9OIGNvbHVtbiBzdHJpbmcsIDAgaWYgbm8gZGF5LlxuICAgICAqIEB0aHJvd3Mgbm90aGluZ1xuICAgICAqL1xuICAgIFR6RGF0YWJhc2UucHJvdG90eXBlLnBhcnNlT25EYXkgPSBmdW5jdGlvbiAob24sIG9uVHlwZSkge1xuICAgICAgICBzd2l0Y2ggKG9uVHlwZSkge1xuICAgICAgICAgICAgY2FzZSBPblR5cGUuRGF5TnVtOiByZXR1cm4gcGFyc2VJbnQob24sIDEwKTtcbiAgICAgICAgICAgIGNhc2UgT25UeXBlLkxlcVg6IHJldHVybiBwYXJzZUludChvbi5zdWJzdHIob24uaW5kZXhPZihcIjw9XCIpICsgMiksIDEwKTtcbiAgICAgICAgICAgIGNhc2UgT25UeXBlLkdyZXFYOiByZXR1cm4gcGFyc2VJbnQob24uc3Vic3RyKG9uLmluZGV4T2YoXCI+PVwiKSArIDIpLCAxMCk7XG4gICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgaWYgKi9cbiAgICAgICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICAgICAgICAgIGlmICh0cnVlKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiAwO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH07XG4gICAgLyoqXG4gICAgICogR2V0IHRoZSBkYXktb2Ytd2VlayBmcm9tIGFuIE9OIGNvbHVtbiBzdHJpbmcsIFN1bmRheSBpZiBub3QgcHJlc2VudC5cbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBUekRhdGFiYXNlLnByb3RvdHlwZS5wYXJzZU9uV2Vla0RheSA9IGZ1bmN0aW9uIChvbikge1xuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IDc7IGkrKykge1xuICAgICAgICAgICAgaWYgKG9uLmluZGV4T2YoVHpEYXlOYW1lc1tpXSkgIT09IC0xKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIGlmICovXG4gICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gICAgICAgIGlmICh0cnVlKSB7XG4gICAgICAgICAgICByZXR1cm4gYmFzaWNzXzEuV2Vla0RheS5TdW5kYXk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFBhcnNlIHRoZSBBVCBjb2x1bW4gb2YgYSBydWxlIGluZm8gZW50cnlcbiAgICAgKiBhbmQgc2VlIHdoYXQga2luZCBvZiBlbnRyeSBpdCBpcy5cbiAgICAgKiBAdGhyb3dzIG5vdGhpbmdcbiAgICAgKi9cbiAgICBUekRhdGFiYXNlLnByb3RvdHlwZS5wYXJzZUF0VHlwZSA9IGZ1bmN0aW9uIChhdCkge1xuICAgICAgICBzd2l0Y2ggKGF0KSB7XG4gICAgICAgICAgICBjYXNlIFwic1wiOiByZXR1cm4gQXRUeXBlLlN0YW5kYXJkO1xuICAgICAgICAgICAgY2FzZSBcInVcIjogcmV0dXJuIEF0VHlwZS5VdGM7XG4gICAgICAgICAgICBjYXNlIFwiZ1wiOiByZXR1cm4gQXRUeXBlLlV0YztcbiAgICAgICAgICAgIGNhc2UgXCJ6XCI6IHJldHVybiBBdFR5cGUuVXRjO1xuICAgICAgICAgICAgY2FzZSBcIndcIjogcmV0dXJuIEF0VHlwZS5XYWxsO1xuICAgICAgICAgICAgY2FzZSBcIlwiOiByZXR1cm4gQXRUeXBlLldhbGw7XG4gICAgICAgICAgICBjYXNlIG51bGw6IHJldHVybiBBdFR5cGUuV2FsbDtcbiAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIGlmICovXG4gICAgICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbiAgICAgICAgICAgICAgICBpZiAodHJ1ZSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gQXRUeXBlLldhbGw7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBHZXQgcHJlLWNhbGN1bGF0ZWQgem9uZSB0cmFuc2l0aW9uc1xuICAgICAqIEBwYXJhbSB6b25lTmFtZVxuICAgICAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Ob3RGb3VuZC5ab25lIGlmIHpvbmUgZG9lcyBub3QgZXhpc3Qgb3IgYSBsaW5rZWQgem9uZSBkb2VzIG5vdCBleGl0XG4gICAgICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkludmFsaWRUaW1lWm9uZURhdGEgZm9yIGludmFsaWQgdmFsdWVzIGluIHRoZSB0aW1lIHpvbmUgZGF0YWJhc2VcbiAgICAgKi9cbiAgICBUekRhdGFiYXNlLnByb3RvdHlwZS5fZ2V0Wm9uZVRyYW5zaXRpb25zID0gZnVuY3Rpb24gKHpvbmVOYW1lKSB7XG4gICAgICAgIHZhciByZXN1bHQgPSB0aGlzLl96b25lVHJhbnNpdGlvbnNDYWNoZS5nZXQoem9uZU5hbWUpO1xuICAgICAgICBpZiAoIXJlc3VsdCkge1xuICAgICAgICAgICAgcmVzdWx0ID0gbmV3IENhY2hlZFpvbmVUcmFuc2l0aW9ucyh6b25lTmFtZSwgdGhpcy5nZXRab25lSW5mb3Moem9uZU5hbWUpLCB0aGlzLl9nZXRSdWxlVHJhbnNpdGlvbnNGb3Jab25lKHpvbmVOYW1lKSk7XG4gICAgICAgICAgICB0aGlzLl96b25lVHJhbnNpdGlvbnNDYWNoZS5zZXQoem9uZU5hbWUsIHJlc3VsdCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIEdldCBwcmUtY2FsY3VsYXRlZCBydWxlIHRyYW5zaXRpb25zXG4gICAgICogQHBhcmFtIHJ1bGVOYW1lXG4gICAgICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLk5vdEZvdW5kLlJ1bGUgaWYgcnVsZSBub3QgZm91bmRcbiAgICAgKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuSW52YWxpZFRpbWVab25lRGF0YSBmb3IgaW52YWxpZCB2YWx1ZXMgaW4gdGhlIHRpbWUgem9uZSBkYXRhYmFzZVxuICAgICAqL1xuICAgIFR6RGF0YWJhc2UucHJvdG90eXBlLl9nZXRSdWxlVHJhbnNpdGlvbnMgPSBmdW5jdGlvbiAocnVsZU5hbWUpIHtcbiAgICAgICAgdmFyIHJlc3VsdCA9IHRoaXMuX3J1bGVUcmFuc2l0aW9uc0NhY2hlLmdldChydWxlTmFtZSk7XG4gICAgICAgIGlmICghcmVzdWx0KSB7XG4gICAgICAgICAgICByZXN1bHQgPSBuZXcgQ2FjaGVkUnVsZVRyYW5zaXRpb25zKHRoaXMuZ2V0UnVsZUluZm9zKHJ1bGVOYW1lKSk7XG4gICAgICAgICAgICB0aGlzLl9ydWxlVHJhbnNpdGlvbnNDYWNoZS5zZXQocnVsZU5hbWUsIHJlc3VsdCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFJldHVybnMgYSBtYXAgb2YgcnVsZU5hbWUtPkNhY2hlZFJ1bGVUcmFuc2l0aW9ucyBmb3IgYWxsIHJ1bGUgc2V0cyB0aGF0IGFyZSByZWZlcmVuY2VkIGJ5IGEgem9uZVxuICAgICAqIEBwYXJhbSB6b25lTmFtZVxuICAgICAqIEB0aHJvd3MgdGltZXpvbmVjb21wbGV0ZS5Ob3RGb3VuZC5ab25lIGlmIHpvbmUgZG9lcyBub3QgZXhpc3Qgb3IgYSBsaW5rZWQgem9uZSBkb2VzIG5vdCBleGl0XG4gICAgICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLk5vdEZvdW5kLlJ1bGUgaWYgcnVsZSBub3QgZm91bmRcbiAgICAgKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuSW52YWxpZFRpbWVab25lRGF0YSBmb3IgaW52YWxpZCB2YWx1ZXMgaW4gdGhlIHRpbWUgem9uZSBkYXRhYmFzZVxuICAgICAqL1xuICAgIFR6RGF0YWJhc2UucHJvdG90eXBlLl9nZXRSdWxlVHJhbnNpdGlvbnNGb3Jab25lID0gZnVuY3Rpb24gKHpvbmVOYW1lKSB7XG4gICAgICAgIHZhciByZXN1bHQgPSBuZXcgTWFwKCk7XG4gICAgICAgIHZhciB6b25lSW5mb3MgPSB0aGlzLmdldFpvbmVJbmZvcyh6b25lTmFtZSk7XG4gICAgICAgIGZvciAodmFyIF9pID0gMCwgem9uZUluZm9zXzUgPSB6b25lSW5mb3M7IF9pIDwgem9uZUluZm9zXzUubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgICAgICB2YXIgem9uZUluZm8gPSB6b25lSW5mb3NfNVtfaV07XG4gICAgICAgICAgICBpZiAoem9uZUluZm8ucnVsZVR5cGUgPT09IFJ1bGVUeXBlLlJ1bGVOYW1lKSB7XG4gICAgICAgICAgICAgICAgaWYgKCFyZXN1bHQuaGFzKHpvbmVJbmZvLnJ1bGVOYW1lKSkge1xuICAgICAgICAgICAgICAgICAgICByZXN1bHQuc2V0KHpvbmVJbmZvLnJ1bGVOYW1lLCB0aGlzLl9nZXRSdWxlVHJhbnNpdGlvbnMoem9uZUluZm8ucnVsZU5hbWUpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9O1xuICAgIHJldHVybiBUekRhdGFiYXNlO1xufSgpKTtcbmV4cG9ydHMuVHpEYXRhYmFzZSA9IFR6RGF0YWJhc2U7XG4vKipcbiAqIFNhbml0eSBjaGVjayBvbiBkYXRhLiBSZXR1cm5zIG1pbi9tYXggdmFsdWVzLlxuICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkludmFsaWRUaW1lWm9uZURhdGEgZm9yIGludmFsaWQgZGF0YVxuICovXG5mdW5jdGlvbiB2YWxpZGF0ZURhdGEoZGF0YSkge1xuICAgIHZhciByZXN1bHQgPSB7fTtcbiAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkodHlwZW9mIGRhdGEgPT09IFwib2JqZWN0XCIsIFwiSW52YWxpZFRpbWVab25lRGF0YVwiLCBcInRpbWUgem9uZSBkYXRhIHNob3VsZCBiZSBhbiBvYmplY3RcIik7XG4gICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKGRhdGEuaGFzT3duUHJvcGVydHkoXCJydWxlc1wiKSwgXCJJbnZhbGlkVGltZVpvbmVEYXRhXCIsIFwidGltZSB6b25lIGRhdGEgc2hvdWxkIGJlIGFuIG9iamVjdCB3aXRoIGEgJ3J1bGVzJyBwcm9wZXJ0eVwiKTtcbiAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkoZGF0YS5oYXNPd25Qcm9wZXJ0eShcInpvbmVzXCIpLCBcIkludmFsaWRUaW1lWm9uZURhdGFcIiwgXCJ0aW1lIHpvbmUgZGF0YSBzaG91bGQgYmUgYW4gb2JqZWN0IHdpdGggYSAnem9uZXMnIHByb3BlcnR5XCIpO1xuICAgIC8vIHZhbGlkYXRlIHpvbmVzXG4gICAgZm9yICh2YXIgem9uZU5hbWUgaW4gZGF0YS56b25lcykge1xuICAgICAgICBpZiAoZGF0YS56b25lcy5oYXNPd25Qcm9wZXJ0eSh6b25lTmFtZSkpIHtcbiAgICAgICAgICAgIHZhciB6b25lQXJyID0gZGF0YS56b25lc1t6b25lTmFtZV07XG4gICAgICAgICAgICBpZiAodHlwZW9mICh6b25lQXJyKSA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgICAgIC8vIG9rLCBpcyBsaW5rIHRvIG90aGVyIHpvbmUsIGNoZWNrIGxpbmtcbiAgICAgICAgICAgICAgICAoMCwgYXNzZXJ0XzEuZGVmYXVsdCkoZGF0YS56b25lcy5oYXNPd25Qcm9wZXJ0eSh6b25lQXJyKSwgXCJJbnZhbGlkVGltZVpvbmVEYXRhXCIsIFwiRW50cnkgZm9yIHpvbmUgXFxcIlwiLmNvbmNhdCh6b25lTmFtZSwgXCJcXFwiIGxpbmtzIHRvIFxcXCJcIikuY29uY2F0KHpvbmVBcnIsIFwiXFxcIiBidXQgdGhhdCBkb2Vzbid0IGV4aXN0XCIpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBpZiAqL1xuICAgICAgICAgICAgICAgIGlmICghQXJyYXkuaXNBcnJheSh6b25lQXJyKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gKDAsIGVycm9yXzEudGhyb3dFcnJvcikoXCJJbnZhbGlkVGltZVpvbmVEYXRhXCIsIFwiRW50cnkgZm9yIHpvbmUgXFxcIlwiLmNvbmNhdCh6b25lTmFtZSwgXCJcXFwiIGlzIG5laXRoZXIgYSBzdHJpbmcgbm9yIGFuIGFycmF5XCIpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB6b25lQXJyLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBlbnRyeSA9IHpvbmVBcnJbaV07XG4gICAgICAgICAgICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBpZiAqL1xuICAgICAgICAgICAgICAgICAgICBpZiAoIUFycmF5LmlzQXJyYXkoZW50cnkpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gKDAsIGVycm9yXzEudGhyb3dFcnJvcikoXCJJbnZhbGlkVGltZVpvbmVEYXRhXCIsIFwiRW50cnkgXCIgKyBpLnRvU3RyaW5nKDEwKSArIFwiIGZvciB6b25lIFxcXCJcIiArIHpvbmVOYW1lICsgXCJcXFwiIGlzIG5vdCBhbiBhcnJheVwiKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgaWYgKi9cbiAgICAgICAgICAgICAgICAgICAgaWYgKGVudHJ5Lmxlbmd0aCAhPT0gNCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuICgwLCBlcnJvcl8xLnRocm93RXJyb3IpKFwiSW52YWxpZFRpbWVab25lRGF0YVwiLCBcIkVudHJ5IFwiICsgaS50b1N0cmluZygxMCkgKyBcIiBmb3Igem9uZSBcXFwiXCIgKyB6b25lTmFtZSArIFwiXFxcIiBoYXMgbGVuZ3RoICE9IDRcIik7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIGlmICovXG4gICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgZW50cnlbMF0gIT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiAoMCwgZXJyb3JfMS50aHJvd0Vycm9yKShcIkludmFsaWRUaW1lWm9uZURhdGFcIiwgXCJFbnRyeSBcIiArIGkudG9TdHJpbmcoMTApICsgXCIgZm9yIHpvbmUgXFxcIlwiICsgem9uZU5hbWUgKyBcIlxcXCIgZmlyc3QgY29sdW1uIGlzIG5vdCBhIHN0cmluZ1wiKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB2YXIgZ210b2ZmID0gbWF0aC5maWx0ZXJGbG9hdChlbnRyeVswXSk7XG4gICAgICAgICAgICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBpZiAqL1xuICAgICAgICAgICAgICAgICAgICBpZiAoaXNOYU4oZ210b2ZmKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuICgwLCBlcnJvcl8xLnRocm93RXJyb3IpKFwiSW52YWxpZFRpbWVab25lRGF0YVwiLCBcIkVudHJ5IFwiICsgaS50b1N0cmluZygxMCkgKyBcIiBmb3Igem9uZSBcXFwiXCIgKyB6b25lTmFtZSArIFwiXFxcIiBmaXJzdCBjb2x1bW4gZG9lcyBub3QgY29udGFpbiBhIG51bWJlclwiKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgaWYgKi9cbiAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBlbnRyeVsxXSAhPT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuICgwLCBlcnJvcl8xLnRocm93RXJyb3IpKFwiSW52YWxpZFRpbWVab25lRGF0YVwiLCBcIkVudHJ5IFwiICsgaS50b1N0cmluZygxMCkgKyBcIiBmb3Igem9uZSBcXFwiXCIgKyB6b25lTmFtZSArIFwiXFxcIiBzZWNvbmQgY29sdW1uIGlzIG5vdCBhIHN0cmluZ1wiKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgaWYgKi9cbiAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBlbnRyeVsyXSAhPT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuICgwLCBlcnJvcl8xLnRocm93RXJyb3IpKFwiSW52YWxpZFRpbWVab25lRGF0YVwiLCBcIkVudHJ5IFwiICsgaS50b1N0cmluZygxMCkgKyBcIiBmb3Igem9uZSBcXFwiXCIgKyB6b25lTmFtZSArIFwiXFxcIiB0aGlyZCBjb2x1bW4gaXMgbm90IGEgc3RyaW5nXCIpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBpZiAqL1xuICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIGVudHJ5WzNdICE9PSBcInN0cmluZ1wiICYmIGVudHJ5WzNdICE9PSBudWxsKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gKDAsIGVycm9yXzEudGhyb3dFcnJvcikoXCJJbnZhbGlkVGltZVpvbmVEYXRhXCIsIFwiRW50cnkgXCIgKyBpLnRvU3RyaW5nKDEwKSArIFwiIGZvciB6b25lIFxcXCJcIiArIHpvbmVOYW1lICsgXCJcXFwiIGZvdXJ0aCBjb2x1bW4gaXMgbm90IGEgc3RyaW5nIG5vciBudWxsXCIpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBpZiAqL1xuICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIGVudHJ5WzNdID09PSBcInN0cmluZ1wiICYmIGlzTmFOKG1hdGguZmlsdGVyRmxvYXQoZW50cnlbM10pKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuICgwLCBlcnJvcl8xLnRocm93RXJyb3IpKFwiSW52YWxpZFRpbWVab25lRGF0YVwiLCBcIkVudHJ5IFwiICsgaS50b1N0cmluZygxMCkgKyBcIiBmb3Igem9uZSBcXFwiXCIgKyB6b25lTmFtZSArIFwiXFxcIiBmb3VydGggY29sdW1uIGRvZXMgbm90IGNvbnRhaW4gYSBudW1iZXJcIik7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgaWYgKHJlc3VsdC5tYXhHbXRPZmYgPT09IHVuZGVmaW5lZCB8fCBnbXRvZmYgPiByZXN1bHQubWF4R210T2ZmKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXN1bHQubWF4R210T2ZmID0gZ210b2ZmO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGlmIChyZXN1bHQubWluR210T2ZmID09PSB1bmRlZmluZWQgfHwgZ210b2ZmIDwgcmVzdWx0Lm1pbkdtdE9mZikge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0Lm1pbkdtdE9mZiA9IGdtdG9mZjtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbiAgICAvLyB2YWxpZGF0ZSBydWxlc1xuICAgIGZvciAodmFyIHJ1bGVOYW1lIGluIGRhdGEucnVsZXMpIHtcbiAgICAgICAgaWYgKGRhdGEucnVsZXMuaGFzT3duUHJvcGVydHkocnVsZU5hbWUpKSB7XG4gICAgICAgICAgICB2YXIgcnVsZUFyciA9IGRhdGEucnVsZXNbcnVsZU5hbWVdO1xuICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIGlmICovXG4gICAgICAgICAgICBpZiAoIUFycmF5LmlzQXJyYXkocnVsZUFycikpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gKDAsIGVycm9yXzEudGhyb3dFcnJvcikoXCJJbnZhbGlkVGltZVpvbmVEYXRhXCIsIFwiRW50cnkgZm9yIHJ1bGUgXFxcIlwiICsgcnVsZU5hbWUgKyBcIlxcXCIgaXMgbm90IGFuIGFycmF5XCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBydWxlQXJyLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgdmFyIHJ1bGUgPSBydWxlQXJyW2ldO1xuICAgICAgICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBpZiAqL1xuICAgICAgICAgICAgICAgIGlmICghQXJyYXkuaXNBcnJheShydWxlKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gKDAsIGVycm9yXzEudGhyb3dFcnJvcikoXCJJbnZhbGlkVGltZVpvbmVEYXRhXCIsIFwiUnVsZSBcIiArIHJ1bGVOYW1lICsgXCJbXCIgKyBpLnRvU3RyaW5nKDEwKSArIFwiXSBpcyBub3QgYW4gYXJyYXlcIik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBpZiAqL1xuICAgICAgICAgICAgICAgIGlmIChydWxlLmxlbmd0aCA8IDgpIHsgLy8gbm90ZSBzb21lIHJ1bGVzID4gOCBleGlzdHMgYnV0IHRoYXQgc2VlbXMgdG8gYmUgYSBidWcgaW4gdHogZmlsZSBwYXJzaW5nXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiAoMCwgZXJyb3JfMS50aHJvd0Vycm9yKShcIkludmFsaWRUaW1lWm9uZURhdGFcIiwgXCJSdWxlIFwiICsgcnVsZU5hbWUgKyBcIltcIiArIGkudG9TdHJpbmcoMTApICsgXCJdIGlzIG5vdCBvZiBsZW5ndGggOFwiKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBydWxlLmxlbmd0aDsgaisrKSB7XG4gICAgICAgICAgICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBpZiAqL1xuICAgICAgICAgICAgICAgICAgICBpZiAoaiAhPT0gNSAmJiB0eXBlb2YgcnVsZVtqXSAhPT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuICgwLCBlcnJvcl8xLnRocm93RXJyb3IpKFwiSW52YWxpZFRpbWVab25lRGF0YVwiLCBcIlJ1bGUgXCIgKyBydWxlTmFtZSArIFwiW1wiICsgaS50b1N0cmluZygxMCkgKyBcIl1bXCIgKyBqLnRvU3RyaW5nKDEwKSArIFwiXSBpcyBub3QgYSBzdHJpbmdcIik7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIGlmICovXG4gICAgICAgICAgICAgICAgaWYgKHJ1bGVbMF0gIT09IFwiTmFOXCIgJiYgaXNOYU4ocGFyc2VJbnQocnVsZVswXSwgMTApKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gKDAsIGVycm9yXzEudGhyb3dFcnJvcikoXCJJbnZhbGlkVGltZVpvbmVEYXRhXCIsIFwiUnVsZSBcIiArIHJ1bGVOYW1lICsgXCJbXCIgKyBpLnRvU3RyaW5nKDEwKSArIFwiXVswXSBpcyBub3QgYSBudW1iZXJcIik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBpZiAqL1xuICAgICAgICAgICAgICAgIGlmIChydWxlWzFdICE9PSBcIm9ubHlcIiAmJiBydWxlWzFdICE9PSBcIm1heFwiICYmIGlzTmFOKHBhcnNlSW50KHJ1bGVbMV0sIDEwKSkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuICgwLCBlcnJvcl8xLnRocm93RXJyb3IpKFwiSW52YWxpZFRpbWVab25lRGF0YVwiLCBcIlJ1bGUgXCIgKyBydWxlTmFtZSArIFwiW1wiICsgaS50b1N0cmluZygxMCkgKyBcIl1bMV0gaXMgbm90IGEgbnVtYmVyLCBvbmx5IG9yIG1heFwiKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIGlmICovXG4gICAgICAgICAgICAgICAgaWYgKCFUek1vbnRoTmFtZXMuaGFzT3duUHJvcGVydHkocnVsZVszXSkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuICgwLCBlcnJvcl8xLnRocm93RXJyb3IpKFwiSW52YWxpZFRpbWVab25lRGF0YVwiLCBcIlJ1bGUgXCIgKyBydWxlTmFtZSArIFwiW1wiICsgaS50b1N0cmluZygxMCkgKyBcIl1bM10gaXMgbm90IGEgbW9udGggbmFtZVwiKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIGlmICovXG4gICAgICAgICAgICAgICAgaWYgKHJ1bGVbNF0uc3Vic3RyKDAsIDQpICE9PSBcImxhc3RcIiAmJiBydWxlWzRdLmluZGV4T2YoXCI+PVwiKSA9PT0gLTFcbiAgICAgICAgICAgICAgICAgICAgJiYgcnVsZVs0XS5pbmRleE9mKFwiPD1cIikgPT09IC0xICYmIGlzTmFOKHBhcnNlSW50KHJ1bGVbNF0sIDEwKSkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuICgwLCBlcnJvcl8xLnRocm93RXJyb3IpKFwiSW52YWxpZFRpbWVab25lRGF0YVwiLCBcIlJ1bGUgXCIgKyBydWxlTmFtZSArIFwiW1wiICsgaS50b1N0cmluZygxMCkgKyBcIl1bNF0gaXMgbm90IGEga25vd24gdHlwZSBvZiBleHByZXNzaW9uXCIpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgaWYgKi9cbiAgICAgICAgICAgICAgICBpZiAoIUFycmF5LmlzQXJyYXkocnVsZVs1XSkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuICgwLCBlcnJvcl8xLnRocm93RXJyb3IpKFwiSW52YWxpZFRpbWVab25lRGF0YVwiLCBcIlJ1bGUgXCIgKyBydWxlTmFtZSArIFwiW1wiICsgaS50b1N0cmluZygxMCkgKyBcIl1bNV0gaXMgbm90IGFuIGFycmF5XCIpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgaWYgKi9cbiAgICAgICAgICAgICAgICBpZiAocnVsZVs1XS5sZW5ndGggIT09IDQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuICgwLCBlcnJvcl8xLnRocm93RXJyb3IpKFwiSW52YWxpZFRpbWVab25lRGF0YVwiLCBcIlJ1bGUgXCIgKyBydWxlTmFtZSArIFwiW1wiICsgaS50b1N0cmluZygxMCkgKyBcIl1bNV0gaXMgbm90IG9mIGxlbmd0aCA0XCIpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgaWYgKi9cbiAgICAgICAgICAgICAgICBpZiAoaXNOYU4ocGFyc2VJbnQocnVsZVs1XVswXSwgMTApKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gKDAsIGVycm9yXzEudGhyb3dFcnJvcikoXCJJbnZhbGlkVGltZVpvbmVEYXRhXCIsIFwiUnVsZSBcIiArIHJ1bGVOYW1lICsgXCJbXCIgKyBpLnRvU3RyaW5nKDEwKSArIFwiXVs1XVswXSBpcyBub3QgYSBudW1iZXJcIik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBpZiAqL1xuICAgICAgICAgICAgICAgIGlmIChpc05hTihwYXJzZUludChydWxlWzVdWzFdLCAxMCkpKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiAoMCwgZXJyb3JfMS50aHJvd0Vycm9yKShcIkludmFsaWRUaW1lWm9uZURhdGFcIiwgXCJSdWxlIFwiICsgcnVsZU5hbWUgKyBcIltcIiArIGkudG9TdHJpbmcoMTApICsgXCJdWzVdWzFdIGlzIG5vdCBhIG51bWJlclwiKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIGlmICovXG4gICAgICAgICAgICAgICAgaWYgKGlzTmFOKHBhcnNlSW50KHJ1bGVbNV1bMl0sIDEwKSkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuICgwLCBlcnJvcl8xLnRocm93RXJyb3IpKFwiSW52YWxpZFRpbWVab25lRGF0YVwiLCBcIlJ1bGUgXCIgKyBydWxlTmFtZSArIFwiW1wiICsgaS50b1N0cmluZygxMCkgKyBcIl1bNV1bMl0gaXMgbm90IGEgbnVtYmVyXCIpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgaWYgKi9cbiAgICAgICAgICAgICAgICBpZiAocnVsZVs1XVszXSAhPT0gXCJcIiAmJiBydWxlWzVdWzNdICE9PSBcInNcIiAmJiBydWxlWzVdWzNdICE9PSBcIndcIlxuICAgICAgICAgICAgICAgICAgICAmJiBydWxlWzVdWzNdICE9PSBcImdcIiAmJiBydWxlWzVdWzNdICE9PSBcInVcIiAmJiBydWxlWzVdWzNdICE9PSBcInpcIiAmJiBydWxlWzVdWzNdICE9PSBudWxsKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiAoMCwgZXJyb3JfMS50aHJvd0Vycm9yKShcIkludmFsaWRUaW1lWm9uZURhdGFcIiwgXCJSdWxlIFwiICsgcnVsZU5hbWUgKyBcIltcIiArIGkudG9TdHJpbmcoMTApICsgXCJdWzVdWzNdIGlzIG5vdCBlbXB0eSwgZywgeiwgcywgdywgdSBvciBudWxsXCIpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB2YXIgc2F2ZSA9IHBhcnNlSW50KHJ1bGVbNl0sIDEwKTtcbiAgICAgICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgaWYgKi9cbiAgICAgICAgICAgICAgICBpZiAoaXNOYU4oc2F2ZSkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuICgwLCBlcnJvcl8xLnRocm93RXJyb3IpKFwiSW52YWxpZFRpbWVab25lRGF0YVwiLCBcIlJ1bGUgXCIgKyBydWxlTmFtZSArIFwiW1wiICsgaS50b1N0cmluZygxMCkgKyBcIl1bNl0gZG9lcyBub3QgY29udGFpbiBhIHZhbGlkIG51bWJlclwiKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKHNhdmUgIT09IDApIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHJlc3VsdC5tYXhEc3RTYXZlID09PSB1bmRlZmluZWQgfHwgc2F2ZSA+IHJlc3VsdC5tYXhEc3RTYXZlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXN1bHQubWF4RHN0U2F2ZSA9IHNhdmU7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgaWYgKHJlc3VsdC5taW5Ec3RTYXZlID09PSB1bmRlZmluZWQgfHwgc2F2ZSA8IHJlc3VsdC5taW5Ec3RTYXZlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXN1bHQubWluRHN0U2F2ZSA9IHNhdmU7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdDtcbn1cbi8qKlxuICogUmVhZHktbWFkZSBzb3J0ZWQgcnVsZSB0cmFuc2l0aW9ucyAodW5jb21wZW5zYXRlZCBmb3Igc3Rkb2Zmc2V0LCBhcyBydWxlcyBhcmUgdXNlZCBieSBtdWx0aXBsZSB6b25lcyB3aXRoIGRpZmZlcmVudCBvZmZzZXRzKVxuICovXG52YXIgQ2FjaGVkUnVsZVRyYW5zaXRpb25zID0gLyoqIEBjbGFzcyAqLyAoZnVuY3Rpb24gKCkge1xuICAgIC8qKlxuICAgICAqIENvbnN0cnVjdG9yXG4gICAgICogQHBhcmFtIHJ1bGVJbmZvc1xuICAgICAqL1xuICAgIGZ1bmN0aW9uIENhY2hlZFJ1bGVUcmFuc2l0aW9ucyhydWxlSW5mb3MpIHtcbiAgICAgICAgLy8gZGV0ZXJtaW5lIG1heGltdW0geWVhciB0byBjYWxjdWxhdGUgdHJhbnNpdGlvbnMgZm9yXG4gICAgICAgIHZhciBtYXhZZWFyO1xuICAgICAgICBmb3IgKHZhciBfaSA9IDAsIHJ1bGVJbmZvc18xID0gcnVsZUluZm9zOyBfaSA8IHJ1bGVJbmZvc18xLmxlbmd0aDsgX2krKykge1xuICAgICAgICAgICAgdmFyIHJ1bGVJbmZvID0gcnVsZUluZm9zXzFbX2ldO1xuICAgICAgICAgICAgaWYgKHJ1bGVJbmZvLnRvVHlwZSA9PT0gVG9UeXBlLlllYXIpIHtcbiAgICAgICAgICAgICAgICBpZiAobWF4WWVhciA9PT0gdW5kZWZpbmVkIHx8IHJ1bGVJbmZvLnRvWWVhciA+IG1heFllYXIpIHtcbiAgICAgICAgICAgICAgICAgICAgbWF4WWVhciA9IHJ1bGVJbmZvLnRvWWVhcjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKG1heFllYXIgPT09IHVuZGVmaW5lZCB8fCBydWxlSW5mby5mcm9tID4gbWF4WWVhcikge1xuICAgICAgICAgICAgICAgICAgICBtYXhZZWFyID0gcnVsZUluZm8uZnJvbTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgLy8gY2FsY3VsYXRlIGFsbCB0cmFuc2l0aW9ucyB1bnRpbCAnbWF4JyBydWxlcyB0YWtlIGVmZmVjdFxuICAgICAgICB0aGlzLl90cmFuc2l0aW9ucyA9IFtdO1xuICAgICAgICBmb3IgKHZhciBfYSA9IDAsIHJ1bGVJbmZvc18yID0gcnVsZUluZm9zOyBfYSA8IHJ1bGVJbmZvc18yLmxlbmd0aDsgX2ErKykge1xuICAgICAgICAgICAgdmFyIHJ1bGVJbmZvID0gcnVsZUluZm9zXzJbX2FdO1xuICAgICAgICAgICAgdmFyIG1pbiA9IHJ1bGVJbmZvLmZyb207XG4gICAgICAgICAgICB2YXIgbWF4ID0gcnVsZUluZm8udG9UeXBlID09PSBUb1R5cGUuWWVhciA/IHJ1bGVJbmZvLnRvWWVhciA6IG1heFllYXI7XG4gICAgICAgICAgICBpZiAobWF4ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICBmb3IgKHZhciB5ZWFyID0gbWluOyB5ZWFyIDw9IG1heDsgKyt5ZWFyKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX3RyYW5zaXRpb25zLnB1c2goe1xuICAgICAgICAgICAgICAgICAgICAgICAgYXQ6IHJ1bGVJbmZvLmVmZmVjdGl2ZURhdGUoeWVhciksXG4gICAgICAgICAgICAgICAgICAgICAgICBhdFR5cGU6IHJ1bGVJbmZvLmF0VHlwZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG5ld1N0YXRlOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZHN0T2Zmc2V0OiBydWxlSW5mby5zYXZlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldHRlcjogcnVsZUluZm8ubGV0dGVyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICAvLyBzb3J0IHRyYW5zaXRpb25zXG4gICAgICAgIHRoaXMuX3RyYW5zaXRpb25zID0gdGhpcy5fdHJhbnNpdGlvbnMuc29ydChmdW5jdGlvbiAoYSwgYikge1xuICAgICAgICAgICAgcmV0dXJuIChhLmF0IDwgYi5hdCA/IC0xIDpcbiAgICAgICAgICAgICAgICBhLmF0ID4gYi5hdCA/IDEgOlxuICAgICAgICAgICAgICAgICAgICAwKTtcbiAgICAgICAgfSk7XG4gICAgICAgIC8vIHNhdmUgdGhlICdtYXgnIHJ1bGVzIGZvciB0cmFuc2l0aW9ucyBhZnRlciB0aGF0XG4gICAgICAgIHRoaXMuX2ZpbmFsUnVsZXNCeUZyb21FZmZlY3RpdmUgPSBydWxlSW5mb3MuZmlsdGVyKGZ1bmN0aW9uIChpbmZvKSB7IHJldHVybiBpbmZvLnRvVHlwZSA9PT0gVG9UeXBlLk1heDsgfSk7XG4gICAgICAgIHRoaXMuX2ZpbmFsUnVsZXNCeUVmZmVjdGl2ZSA9IF9fc3ByZWFkQXJyYXkoW10sIHRoaXMuX2ZpbmFsUnVsZXNCeUZyb21FZmZlY3RpdmUsIHRydWUpO1xuICAgICAgICAvLyBzb3J0IGZpbmFsIHJ1bGVzIGJ5IEZST00gYW5kIHRoZW4gYnkgeWVhci1yZWxhdGl2ZSBkYXRlXG4gICAgICAgIHRoaXMuX2ZpbmFsUnVsZXNCeUZyb21FZmZlY3RpdmUgPSB0aGlzLl9maW5hbFJ1bGVzQnlGcm9tRWZmZWN0aXZlLnNvcnQoZnVuY3Rpb24gKGEsIGIpIHtcbiAgICAgICAgICAgIGlmIChhLmZyb20gPCBiLmZyb20pIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gLTE7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoYS5mcm9tID4gYi5mcm9tKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIDE7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgYWUgPSBhLmVmZmVjdGl2ZURhdGUoYS5mcm9tKTtcbiAgICAgICAgICAgIHZhciBiZSA9IGIuZWZmZWN0aXZlRGF0ZShiLmZyb20pO1xuICAgICAgICAgICAgcmV0dXJuIChhZSA8IGJlID8gLTEgOlxuICAgICAgICAgICAgICAgIGFlID4gYmUgPyAxIDpcbiAgICAgICAgICAgICAgICAgICAgMCk7XG4gICAgICAgIH0pO1xuICAgICAgICAvLyBzb3J0IGZpbmFsIHJ1bGVzIGJ5IHllYXItcmVsYXRpdmUgZGF0ZVxuICAgICAgICB0aGlzLl9maW5hbFJ1bGVzQnlFZmZlY3RpdmUgPSB0aGlzLl9maW5hbFJ1bGVzQnlGcm9tRWZmZWN0aXZlLnNvcnQoZnVuY3Rpb24gKGEsIGIpIHtcbiAgICAgICAgICAgIHZhciBhZSA9IGEuZWZmZWN0aXZlRGF0ZShhLmZyb20pO1xuICAgICAgICAgICAgdmFyIGJlID0gYi5lZmZlY3RpdmVEYXRlKGIuZnJvbSk7XG4gICAgICAgICAgICByZXR1cm4gKGFlIDwgYmUgPyAtMSA6XG4gICAgICAgICAgICAgICAgYWUgPiBiZSA/IDEgOlxuICAgICAgICAgICAgICAgICAgICAwKTtcbiAgICAgICAgfSk7XG4gICAgfVxuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShDYWNoZWRSdWxlVHJhbnNpdGlvbnMucHJvdG90eXBlLCBcImZpbmFsXCIsIHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSAnbWF4JyB0eXBlIHJ1bGVzIGF0IHRoZSBlbmQsIHNvcnRlZCBieSB5ZWFyLXJlbGF0aXZlIGVmZmVjdGl2ZSBkYXRlXG4gICAgICAgICAqL1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9maW5hbFJ1bGVzQnlFZmZlY3RpdmU7XG4gICAgICAgIH0sXG4gICAgICAgIGVudW1lcmFibGU6IGZhbHNlLFxuICAgICAgICBjb25maWd1cmFibGU6IHRydWVcbiAgICB9KTtcbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBmaXJzdCBldmVyIHRyYW5zaXRpb24gYXMgZGVmaW5lZCBieSB0aGUgcnVsZSBzZXRcbiAgICAgKi9cbiAgICBDYWNoZWRSdWxlVHJhbnNpdGlvbnMucHJvdG90eXBlLmZpbmRGaXJzdCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKHRoaXMuX3RyYW5zaXRpb25zLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIHZhciB0cmFuc2l0aW9uID0gdGhpcy5fdHJhbnNpdGlvbnNbMF07XG4gICAgICAgICAgICB2YXIgaXRlcmF0b3IgPSB7XG4gICAgICAgICAgICAgICAgdHJhbnNpdGlvbjogdHJhbnNpdGlvbixcbiAgICAgICAgICAgICAgICBpbmRleDogMFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJldHVybiBpdGVyYXRvcjtcbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy5fZmluYWxSdWxlc0J5RnJvbUVmZmVjdGl2ZS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICB2YXIgcnVsZSA9IHRoaXMuX2ZpbmFsUnVsZXNCeUZyb21FZmZlY3RpdmVbMF07XG4gICAgICAgICAgICB2YXIgdHJhbnNpdGlvbiA9IHtcbiAgICAgICAgICAgICAgICBhdDogcnVsZS5lZmZlY3RpdmVEYXRlKHJ1bGUuZnJvbSksXG4gICAgICAgICAgICAgICAgYXRUeXBlOiBydWxlLmF0VHlwZSxcbiAgICAgICAgICAgICAgICBuZXdTdGF0ZToge1xuICAgICAgICAgICAgICAgICAgICBkc3RPZmZzZXQ6IHJ1bGUuc2F2ZSxcbiAgICAgICAgICAgICAgICAgICAgbGV0dGVyOiBydWxlLmxldHRlclxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICB2YXIgaXRlcmF0b3IgPSB7XG4gICAgICAgICAgICAgICAgdHJhbnNpdGlvbjogdHJhbnNpdGlvbixcbiAgICAgICAgICAgICAgICBmaW5hbDogdHJ1ZVxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJldHVybiBpdGVyYXRvcjtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgbmV4dCB0cmFuc2l0aW9uLCBnaXZlbiBhbiBpdGVyYXRvclxuICAgICAqIEBwYXJhbSBwcmV2IHRoZSBpdGVyYXRvclxuICAgICAqL1xuICAgIENhY2hlZFJ1bGVUcmFuc2l0aW9ucy5wcm90b3R5cGUuZmluZE5leHQgPSBmdW5jdGlvbiAocHJldikge1xuICAgICAgICBpZiAoIXByZXYuZmluYWwgJiYgcHJldi5pbmRleCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICBpZiAocHJldi5pbmRleCA8IHRoaXMuX3RyYW5zaXRpb25zLmxlbmd0aCAtIDEpIHtcbiAgICAgICAgICAgICAgICB2YXIgdHJhbnNpdGlvbiA9IHRoaXMuX3RyYW5zaXRpb25zW3ByZXYuaW5kZXggKyAxXTtcbiAgICAgICAgICAgICAgICB2YXIgaXRlcmF0b3IgPSB7XG4gICAgICAgICAgICAgICAgICAgIHRyYW5zaXRpb246IHRyYW5zaXRpb24sXG4gICAgICAgICAgICAgICAgICAgIGluZGV4OiBwcmV2LmluZGV4ICsgMVxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgcmV0dXJuIGl0ZXJhdG9yO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIC8vIGZpbmQgbWluaW11bSBhcHBsaWNhYmxlIGZpbmFsIHJ1bGUgYWZ0ZXIgdGhlIHByZXYgdHJhbnNpdGlvblxuICAgICAgICB2YXIgZm91bmQ7XG4gICAgICAgIHZhciBmb3VuZEVmZmVjdGl2ZTtcbiAgICAgICAgZm9yICh2YXIgeWVhciA9IHByZXYudHJhbnNpdGlvbi5hdC55ZWFyOyB5ZWFyIDwgcHJldi50cmFuc2l0aW9uLmF0LnllYXIgKyAyOyArK3llYXIpIHtcbiAgICAgICAgICAgIGZvciAodmFyIF9pID0gMCwgX2EgPSB0aGlzLl9maW5hbFJ1bGVzQnlFZmZlY3RpdmU7IF9pIDwgX2EubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgICAgICAgICAgdmFyIHJ1bGUgPSBfYVtfaV07XG4gICAgICAgICAgICAgICAgaWYgKHJ1bGUuYXBwbGljYWJsZSh5ZWFyKSkge1xuICAgICAgICAgICAgICAgICAgICB2YXIgZWZmZWN0aXZlID0gcnVsZS5lZmZlY3RpdmVEYXRlKHllYXIpO1xuICAgICAgICAgICAgICAgICAgICBpZiAoZWZmZWN0aXZlID4gcHJldi50cmFuc2l0aW9uLmF0ICYmICghZm91bmRFZmZlY3RpdmUgfHwgZWZmZWN0aXZlIDwgZm91bmRFZmZlY3RpdmUpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBmb3VuZCA9IHJ1bGU7XG4gICAgICAgICAgICAgICAgICAgICAgICBmb3VuZEVmZmVjdGl2ZSA9IGVmZmVjdGl2ZTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoZm91bmQgJiYgZm91bmRFZmZlY3RpdmUpIHtcbiAgICAgICAgICAgIHZhciB0cmFuc2l0aW9uID0ge1xuICAgICAgICAgICAgICAgIGF0OiBmb3VuZEVmZmVjdGl2ZSxcbiAgICAgICAgICAgICAgICBhdFR5cGU6IGZvdW5kLmF0VHlwZSxcbiAgICAgICAgICAgICAgICBuZXdTdGF0ZToge1xuICAgICAgICAgICAgICAgICAgICBkc3RPZmZzZXQ6IGZvdW5kLnNhdmUsXG4gICAgICAgICAgICAgICAgICAgIGxldHRlcjogZm91bmQubGV0dGVyXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHZhciBpdGVyYXRvciA9IHtcbiAgICAgICAgICAgICAgICB0cmFuc2l0aW9uOiB0cmFuc2l0aW9uLFxuICAgICAgICAgICAgICAgIGZpbmFsOiB0cnVlXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgcmV0dXJuIGl0ZXJhdG9yO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBEaXJ0eSBmaW5kIGZ1bmN0aW9uIHRoYXQgb25seSB0YWtlcyBhIHN0YW5kYXJkIG9mZnNldCBmcm9tIFVUQyBpbnRvIGFjY291bnRcbiAgICAgKiBAcGFyYW0gYmVmb3JlVXRjIHRpbWVzdGFtcCB0byBzZWFyY2ggZm9yXG4gICAgICogQHBhcmFtIHN0YW5kYXJkT2Zmc2V0IHpvbmUgc3RhbmRhcmQgb2Zmc2V0IHRvIGFwcGx5XG4gICAgICovXG4gICAgQ2FjaGVkUnVsZVRyYW5zaXRpb25zLnByb3RvdHlwZS5maW5kTGFzdExlc3NFcXVhbCA9IGZ1bmN0aW9uIChiZWZvcmVVdGMsIHN0YW5kYXJkT2Zmc2V0KSB7XG4gICAgICAgIHZhciBwcmV2VHJhbnNpdGlvbjtcbiAgICAgICAgdmFyIGl0ZXJhdG9yID0gdGhpcy5maW5kRmlyc3QoKTtcbiAgICAgICAgdmFyIGVmZmVjdGl2ZVV0YyA9IChpdGVyYXRvciA9PT0gbnVsbCB8fCBpdGVyYXRvciA9PT0gdm9pZCAwID8gdm9pZCAwIDogaXRlcmF0b3IudHJhbnNpdGlvbikgPyBydWxlVHJhbnNpdGlvblV0YyhpdGVyYXRvci50cmFuc2l0aW9uLCBzdGFuZGFyZE9mZnNldCwgdW5kZWZpbmVkKSA6IHVuZGVmaW5lZDtcbiAgICAgICAgd2hpbGUgKGl0ZXJhdG9yICYmIGVmZmVjdGl2ZVV0YyAmJiBlZmZlY3RpdmVVdGMgPD0gYmVmb3JlVXRjKSB7XG4gICAgICAgICAgICBwcmV2VHJhbnNpdGlvbiA9IGl0ZXJhdG9yLnRyYW5zaXRpb247XG4gICAgICAgICAgICBpdGVyYXRvciA9IHRoaXMuZmluZE5leHQoaXRlcmF0b3IpO1xuICAgICAgICAgICAgZWZmZWN0aXZlVXRjID0gKGl0ZXJhdG9yID09PSBudWxsIHx8IGl0ZXJhdG9yID09PSB2b2lkIDAgPyB2b2lkIDAgOiBpdGVyYXRvci50cmFuc2l0aW9uKSA/IHJ1bGVUcmFuc2l0aW9uVXRjKGl0ZXJhdG9yLnRyYW5zaXRpb24sIHN0YW5kYXJkT2Zmc2V0LCB1bmRlZmluZWQpIDogdW5kZWZpbmVkO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBwcmV2VHJhbnNpdGlvbjtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqXG4gICAgICogQHBhcmFtIGFmdGVyVXRjXG4gICAgICogQHBhcmFtIHN0YW5kYXJkT2Zmc2V0XG4gICAgICogQHBhcmFtIGRzdE9mZnNldFxuICAgICAqL1xuICAgIENhY2hlZFJ1bGVUcmFuc2l0aW9ucy5wcm90b3R5cGUuZmlyc3RUcmFuc2l0aW9uV2l0aG91dERzdEFmdGVyID0gZnVuY3Rpb24gKGFmdGVyVXRjLCBzdGFuZGFyZE9mZnNldCwgZHN0T2Zmc2V0KSB7XG4gICAgICAgIHZhciBfYTtcbiAgICAgICAgLy8gdG9kbyBpbmVmZmljaWVudCAtIG9wdGltaXplXG4gICAgICAgIHZhciBpdGVyYXRvciA9IHRoaXMuZmluZEZpcnN0KCk7XG4gICAgICAgIHZhciBlZmZlY3RpdmVVdGMgPSAoaXRlcmF0b3IgPT09IG51bGwgfHwgaXRlcmF0b3IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGl0ZXJhdG9yLnRyYW5zaXRpb24pID8gcnVsZVRyYW5zaXRpb25VdGMoaXRlcmF0b3IgPT09IG51bGwgfHwgaXRlcmF0b3IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGl0ZXJhdG9yLnRyYW5zaXRpb24sIHN0YW5kYXJkT2Zmc2V0LCBkc3RPZmZzZXQpIDogdW5kZWZpbmVkO1xuICAgICAgICB3aGlsZSAoaXRlcmF0b3IgJiYgZWZmZWN0aXZlVXRjICYmICghKChfYSA9IGl0ZXJhdG9yID09PSBudWxsIHx8IGl0ZXJhdG9yID09PSB2b2lkIDAgPyB2b2lkIDAgOiBpdGVyYXRvci50cmFuc2l0aW9uKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EubmV3U3RhdGUuZHN0T2Zmc2V0Lnplcm8oKSkgfHwgZWZmZWN0aXZlVXRjIDw9IGFmdGVyVXRjKSkge1xuICAgICAgICAgICAgaXRlcmF0b3IgPSB0aGlzLmZpbmROZXh0KGl0ZXJhdG9yKTtcbiAgICAgICAgICAgIGVmZmVjdGl2ZVV0YyA9IChpdGVyYXRvciA9PT0gbnVsbCB8fCBpdGVyYXRvciA9PT0gdm9pZCAwID8gdm9pZCAwIDogaXRlcmF0b3IudHJhbnNpdGlvbikgPyBydWxlVHJhbnNpdGlvblV0YyhpdGVyYXRvciA9PT0gbnVsbCB8fCBpdGVyYXRvciA9PT0gdm9pZCAwID8gdm9pZCAwIDogaXRlcmF0b3IudHJhbnNpdGlvbiwgc3RhbmRhcmRPZmZzZXQsIGRzdE9mZnNldCkgOiB1bmRlZmluZWQ7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGl0ZXJhdG9yID09PSBudWxsIHx8IGl0ZXJhdG9yID09PSB2b2lkIDAgPyB2b2lkIDAgOiBpdGVyYXRvci50cmFuc2l0aW9uO1xuICAgIH07XG4gICAgcmV0dXJuIENhY2hlZFJ1bGVUcmFuc2l0aW9ucztcbn0oKSk7XG4vKipcbiAqIFJ1bGVzIGRlcGVuZCBvbiBwcmV2aW91cyBydWxlcywgaGVuY2UgeW91IGNhbm5vdCBjYWxjdWxhdGUgRFNUIHRyYW5zaXRpb25zIHdpdG91dCBzdGFydGluZyBhdCB0aGUgc3RhcnQuXG4gKiBOZXh0IHRvIHRoYXQsIHpvbmVzIHNvbWV0aW1lcyB0cmFuc2l0aW9uIGludG8gdGhlIG1pZGRsZSBvZiBhIHJ1bGUgc2V0LlxuICogRHVlIHRvIHRoaXMsIHdlIG1haW50YWluIGEgY2FjaGUgb2YgdHJhbnNpdGlvbnMgZm9yIHpvbmVzXG4gKi9cbnZhciBDYWNoZWRab25lVHJhbnNpdGlvbnMgPSAvKiogQGNsYXNzICovIChmdW5jdGlvbiAoKSB7XG4gICAgLyoqXG4gICAgICogQ29uc3RydWN0b3JcbiAgICAgKiBAcGFyYW0gem9uZU5hbWVcbiAgICAgKiBAcGFyYW0gem9uZUluZm9zXG4gICAgICogQHBhcmFtIHJ1bGVzXG4gICAgICogQHRocm93cyB0aW1lem9uZWNvbXBsZXRlLkludmFsaWRUaW1lWm9uZURhdGFcbiAgICAgKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuQXJndW1lbnQuWm9uZUluZm9zIGlmIHpvbmVJbmZvcyBpcyBlbXB0eVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIENhY2hlZFpvbmVUcmFuc2l0aW9ucyh6b25lTmFtZSwgem9uZUluZm9zLCBydWxlcykge1xuICAgICAgICB2YXIgX2E7XG4gICAgICAgICgwLCBhc3NlcnRfMS5kZWZhdWx0KSh6b25lSW5mb3MubGVuZ3RoID4gMCwgXCJ0aW1lem9uZWNvbXBsZXRlLkFyZ3VtZW50LlpvbmVJbmZvc1wiLCBcInpvbmUgJ1wiLmNvbmNhdCh6b25lTmFtZSwgXCInIHdpdGhvdXQgaW5mb3JtYXRpb25cIikpO1xuICAgICAgICB0aGlzLl9maW5hbFpvbmVJbmZvID0gem9uZUluZm9zW3pvbmVJbmZvcy5sZW5ndGggLSAxXTtcbiAgICAgICAgdGhpcy5faW5pdGlhbFN0YXRlID0gdGhpcy5fY2FsY0luaXRpYWxTdGF0ZSh6b25lTmFtZSwgem9uZUluZm9zLCBydWxlcyk7XG4gICAgICAgIF9hID0gdGhpcy5fY2FsY1RyYW5zaXRpb25zKHpvbmVOYW1lLCB0aGlzLl9pbml0aWFsU3RhdGUsIHpvbmVJbmZvcywgcnVsZXMpLCB0aGlzLl90cmFuc2l0aW9ucyA9IF9hWzBdLCB0aGlzLl9maW5hbFJ1bGVzID0gX2FbMV07XG4gICAgfVxuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShDYWNoZWRab25lVHJhbnNpdGlvbnMucHJvdG90eXBlLCBcImluaXRpYWxTdGF0ZVwiLCB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2luaXRpYWxTdGF0ZTtcbiAgICAgICAgfSxcbiAgICAgICAgZW51bWVyYWJsZTogZmFsc2UsXG4gICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZVxuICAgIH0pO1xuICAgIC8qKlxuICAgICAqIEZpbmQgdGhlIGZpcnN0IHRyYW5zaXRpb24sIGlmIGl0IGV4aXN0c1xuICAgICAqL1xuICAgIENhY2hlZFpvbmVUcmFuc2l0aW9ucy5wcm90b3R5cGUuZmluZEZpcnN0ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAodGhpcy5fdHJhbnNpdGlvbnMubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICB0cmFuc2l0aW9uOiB0aGlzLl90cmFuc2l0aW9uc1swXSxcbiAgICAgICAgICAgICAgICBpbmRleDogMFxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogRmluZCBuZXh0IHRyYW5zaXRpb24sIGlmIGl0IGV4aXN0c1xuICAgICAqIEBwYXJhbSBpdGVyYXRvciBwcmV2aW91cyBpdGVyYXRvclxuICAgICAqIEByZXR1cm5zIHRoZSBuZXh0IGl0ZXJhdG9yXG4gICAgICovXG4gICAgQ2FjaGVkWm9uZVRyYW5zaXRpb25zLnByb3RvdHlwZS5maW5kTmV4dCA9IGZ1bmN0aW9uIChpdGVyYXRvcikge1xuICAgICAgICBpZiAoIWl0ZXJhdG9yLmZpbmFsKSB7XG4gICAgICAgICAgICBpZiAoaXRlcmF0b3IuaW5kZXggPCB0aGlzLl90cmFuc2l0aW9ucy5sZW5ndGggLSAxKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAgICAgdHJhbnNpdGlvbjogdGhpcy5fdHJhbnNpdGlvbnNbaXRlcmF0b3IuaW5kZXggKyAxXSxcbiAgICAgICAgICAgICAgICAgICAgaW5kZXg6IGl0ZXJhdG9yLmluZGV4ICsgMVxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgdmFyIGZvdW5kO1xuICAgICAgICBmb3IgKHZhciB5ID0gaXRlcmF0b3IudHJhbnNpdGlvbi5hdFV0Yy55ZWFyOyB5IDwgaXRlcmF0b3IudHJhbnNpdGlvbi5hdFV0Yy55ZWFyICsgMjsgKyt5KSB7XG4gICAgICAgICAgICBmb3IgKHZhciBfaSA9IDAsIF9hID0gdGhpcy5fZmluYWxSdWxlczsgX2kgPCBfYS5sZW5ndGg7IF9pKyspIHtcbiAgICAgICAgICAgICAgICB2YXIgcnVsZUluZm8gPSBfYVtfaV07XG4gICAgICAgICAgICAgICAgaWYgKHJ1bGVJbmZvLmFwcGxpY2FibGUoeSkpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHRyYW5zaXRpb24gPSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBhdFV0YzogcnVsZUluZm8uZWZmZWN0aXZlRGF0ZVV0Yyh5LCBpdGVyYXRvci50cmFuc2l0aW9uLm5ld1N0YXRlLnN0YW5kYXJkT2Zmc2V0LCBpdGVyYXRvci50cmFuc2l0aW9uLm5ld1N0YXRlLmRzdE9mZnNldCksXG4gICAgICAgICAgICAgICAgICAgICAgICBuZXdTdGF0ZToge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFiYnJldmlhdGlvbjogem9uZUFiYnJldmlhdGlvbih0aGlzLl9maW5hbFpvbmVJbmZvLmZvcm1hdCwgcnVsZUluZm8uc2F2ZS5ub25aZXJvKCksIHJ1bGVJbmZvLmxldHRlciksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV0dGVyOiBydWxlSW5mby5sZXR0ZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZHN0T2Zmc2V0OiBydWxlSW5mby5zYXZlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YW5kYXJkT2Zmc2V0OiBpdGVyYXRvci50cmFuc2l0aW9uLm5ld1N0YXRlLnN0YW5kYXJkT2Zmc2V0XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgICAgIGlmICh0cmFuc2l0aW9uLmF0VXRjID4gaXRlcmF0b3IudHJhbnNpdGlvbi5hdFV0Yykge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFmb3VuZCB8fCBmb3VuZC5hdFV0YyA+IHRyYW5zaXRpb24uYXRVdGMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3VuZCA9IHRyYW5zaXRpb247XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGZvdW5kKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIHRyYW5zaXRpb246IGZvdW5kLFxuICAgICAgICAgICAgICAgIGluZGV4OiAwLFxuICAgICAgICAgICAgICAgIGZpbmFsOiB0cnVlXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSB6b25lIHN0YXRlIGF0IHRoZSBnaXZlbiBVVEMgdGltZVxuICAgICAqIEBwYXJhbSB1dGNcbiAgICAgKi9cbiAgICBDYWNoZWRab25lVHJhbnNpdGlvbnMucHJvdG90eXBlLnN0YXRlQXQgPSBmdW5jdGlvbiAodXRjKSB7XG4gICAgICAgIHZhciBwcmV2U3RhdGUgPSB0aGlzLl9pbml0aWFsU3RhdGU7XG4gICAgICAgIHZhciBpdGVyYXRvciA9IHRoaXMuZmluZEZpcnN0KCk7XG4gICAgICAgIHdoaWxlIChpdGVyYXRvciAmJiBpdGVyYXRvci50cmFuc2l0aW9uLmF0VXRjIDw9IHV0Yykge1xuICAgICAgICAgICAgcHJldlN0YXRlID0gaXRlcmF0b3IudHJhbnNpdGlvbi5uZXdTdGF0ZTtcbiAgICAgICAgICAgIGl0ZXJhdG9yID0gdGhpcy5maW5kTmV4dChpdGVyYXRvcik7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHByZXZTdGF0ZTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFRoZSB0cmFuc2l0aW9ucyBpbiB5ZWFyIFtzdGFydCwgZW5kKVxuICAgICAqIEBwYXJhbSBzdGFydCBzdGFydCB5ZWFyIChpbmNsdXNpdmUpXG4gICAgICogQHBhcmFtIGVuZCBlbmQgeWVhciAoZXhjbHVzaXZlKVxuICAgICAqL1xuICAgIENhY2hlZFpvbmVUcmFuc2l0aW9ucy5wcm90b3R5cGUudHJhbnNpdGlvbnNJblllYXJzID0gZnVuY3Rpb24gKHN0YXJ0LCBlbmQpIHtcbiAgICAgICAgLy8gY2hlY2sgaWYgc3RhcnQtMSBpcyB3aXRoaW4gdGhlIGluaXRpYWwgdHJhbnNpdGlvbnMgb3Igbm90LiBXZSB1c2Ugc3RhcnQtMSBiZWNhdXNlIHdlIHRha2UgYW4gZXh0cmEgeWVhciBpbiB0aGUgZWxzZSBjbGF1c2UgYmVsb3dcbiAgICAgICAgdmFyIGZpbmFsID0gKHRoaXMuX3RyYW5zaXRpb25zLmxlbmd0aCA9PT0gMCB8fCB0aGlzLl90cmFuc2l0aW9uc1t0aGlzLl90cmFuc2l0aW9ucy5sZW5ndGggLSAxXS5hdFV0Yy55ZWFyIDwgc3RhcnQgLSAxKTtcbiAgICAgICAgdmFyIHJlc3VsdCA9IFtdO1xuICAgICAgICBpZiAoIWZpbmFsKSB7XG4gICAgICAgICAgICAvLyBzaW1wbHkgZG8gbGluZWFyIHNlYXJjaFxuICAgICAgICAgICAgdmFyIGl0ZXJhdG9yID0gdGhpcy5maW5kRmlyc3QoKTtcbiAgICAgICAgICAgIHdoaWxlIChpdGVyYXRvciAmJiBpdGVyYXRvci50cmFuc2l0aW9uLmF0VXRjLnllYXIgPCBlbmQpIHtcbiAgICAgICAgICAgICAgICBpZiAoaXRlcmF0b3IudHJhbnNpdGlvbi5hdFV0Yy55ZWFyID49IHN0YXJ0KSB7XG4gICAgICAgICAgICAgICAgICAgIHJlc3VsdC5wdXNoKGl0ZXJhdG9yLnRyYW5zaXRpb24pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpdGVyYXRvciA9IHRoaXMuZmluZE5leHQoaXRlcmF0b3IpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgdmFyIHRyYW5zaXRpb25zV2l0aFJ1bGVzID0gW107XG4gICAgICAgICAgICAvLyBEbyBzb21ldGhpbmcgc21hcnQ6IGZpcnN0IGdldCBhbGwgdHJhbnNpdGlvbnMgd2l0aCBhdFV0YyBOT1QgY29tcGVuc2F0ZWQgZm9yIHN0YW5kYXJkIG9mZnNldFxuICAgICAgICAgICAgLy8gVGFrZSBhbiBleHRyYSB5ZWFyIGJlZm9yZSBzdGFydFxuICAgICAgICAgICAgZm9yICh2YXIgeWVhciA9IHN0YXJ0IC0gMTsgeWVhciA8IGVuZDsgKyt5ZWFyKSB7XG4gICAgICAgICAgICAgICAgZm9yICh2YXIgX2kgPSAwLCBfYSA9IHRoaXMuX2ZpbmFsUnVsZXM7IF9pIDwgX2EubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBydWxlSW5mbyA9IF9hW19pXTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHJ1bGVJbmZvLmFwcGxpY2FibGUoeWVhcikpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciB0cmFuc2l0aW9uID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF0VXRjOiBydWxlSW5mby5lZmZlY3RpdmVEYXRlVXRjKHllYXIsIHRoaXMuX2ZpbmFsWm9uZUluZm8uZ210b2ZmLCAoMCwgZHVyYXRpb25fMS5ob3VycykoMCkpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5ld1N0YXRlOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFiYnJldmlhdGlvbjogem9uZUFiYnJldmlhdGlvbih0aGlzLl9maW5hbFpvbmVJbmZvLmZvcm1hdCwgcnVsZUluZm8uc2F2ZS5ub25aZXJvKCksIHJ1bGVJbmZvLmxldHRlciksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldHRlcjogcnVsZUluZm8ubGV0dGVyLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkc3RPZmZzZXQ6IHJ1bGVJbmZvLnNhdmUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YW5kYXJkT2Zmc2V0OiB0aGlzLl9maW5hbFpvbmVJbmZvLmdtdG9mZlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2l0aW9uc1dpdGhSdWxlcy5wdXNoKHsgdHJhbnNpdGlvbjogdHJhbnNpdGlvbiwgcnVsZUluZm86IHJ1bGVJbmZvIH0pO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdHJhbnNpdGlvbnNXaXRoUnVsZXMuc29ydChmdW5jdGlvbiAoYSwgYikgeyByZXR1cm4gYS50cmFuc2l0aW9uLmF0VXRjLnVuaXhNaWxsaXMgLSBiLnRyYW5zaXRpb24uYXRVdGMudW5peE1pbGxpczsgfSk7XG4gICAgICAgICAgICAvLyBub3cgYXBwbHkgRFNUIG9mZnNldCByZXRyb2FjdGl2ZWx5XG4gICAgICAgICAgICB2YXIgcHJldkRzdCA9ICgwLCBkdXJhdGlvbl8xLmhvdXJzKSgwKTtcbiAgICAgICAgICAgIGZvciAodmFyIF9iID0gMCwgdHJhbnNpdGlvbnNXaXRoUnVsZXNfMSA9IHRyYW5zaXRpb25zV2l0aFJ1bGVzOyBfYiA8IHRyYW5zaXRpb25zV2l0aFJ1bGVzXzEubGVuZ3RoOyBfYisrKSB7XG4gICAgICAgICAgICAgICAgdmFyIHRyID0gdHJhbnNpdGlvbnNXaXRoUnVsZXNfMVtfYl07XG4gICAgICAgICAgICAgICAgaWYgKHRyLnJ1bGVJbmZvLmF0VHlwZSA9PT0gQXRUeXBlLldhbGwpIHtcbiAgICAgICAgICAgICAgICAgICAgdHIudHJhbnNpdGlvbi5hdFV0YyA9IG5ldyBiYXNpY3NfMS5UaW1lU3RydWN0KHRyLnRyYW5zaXRpb24uYXRVdGMudW5peE1pbGxpcyAtIHByZXZEc3QubWlsbGlzZWNvbmRzKCkpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBwcmV2RHN0ID0gdHIudHJhbnNpdGlvbi5uZXdTdGF0ZS5kc3RPZmZzZXQ7XG4gICAgICAgICAgICAgICAgaWYgKHRyLnRyYW5zaXRpb24uYXRVdGMueWVhciA+PSBzdGFydCkge1xuICAgICAgICAgICAgICAgICAgICByZXN1bHQucHVzaCh0ci50cmFuc2l0aW9uKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIENhbGN1bGF0ZSB0aGUgaW5pdGlhbCBzdGF0ZSBmb3IgdGhlIHpvbmVcbiAgICAgKiBAcGFyYW0gem9uZU5hbWVcbiAgICAgKiBAcGFyYW0gaW5mb3NcbiAgICAgKiBAcGFyYW0gcnVsZXNcbiAgICAgKiBAdGhyb3dzIHRpbWV6b25lY29tcGxldGUuSW52YWxpZFRpbWVab25lRGF0YVxuICAgICAqL1xuICAgIENhY2hlZFpvbmVUcmFuc2l0aW9ucy5wcm90b3R5cGUuX2NhbGNJbml0aWFsU3RhdGUgPSBmdW5jdGlvbiAoem9uZU5hbWUsIGluZm9zLCBydWxlcykge1xuICAgICAgICB2YXIgX2E7XG4gICAgICAgIC8vIGluaXRpYWwgc3RhdGVcbiAgICAgICAgaWYgKGluZm9zLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICBhYmJyZXZpYXRpb246IFwiXCIsXG4gICAgICAgICAgICAgICAgbGV0dGVyOiBcIlwiLFxuICAgICAgICAgICAgICAgIGRzdE9mZnNldDogKDAsIGR1cmF0aW9uXzEuaG91cnMpKDApLFxuICAgICAgICAgICAgICAgIHN0YW5kYXJkT2Zmc2V0OiAoMCwgZHVyYXRpb25fMS5ob3VycykoMClcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICAgdmFyIGluZm8gPSBpbmZvc1swXTtcbiAgICAgICAgc3dpdGNoIChpbmZvLnJ1bGVUeXBlKSB7XG4gICAgICAgICAgICBjYXNlIFJ1bGVUeXBlLk5vbmU6XG4gICAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAgICAgYWJicmV2aWF0aW9uOiB6b25lQWJicmV2aWF0aW9uKGluZm8uZm9ybWF0LCBmYWxzZSwgdW5kZWZpbmVkKSxcbiAgICAgICAgICAgICAgICAgICAgbGV0dGVyOiBcIlwiLFxuICAgICAgICAgICAgICAgICAgICBkc3RPZmZzZXQ6ICgwLCBkdXJhdGlvbl8xLmhvdXJzKSgwKSxcbiAgICAgICAgICAgICAgICAgICAgc3RhbmRhcmRPZmZzZXQ6IGluZm8uZ210b2ZmXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGNhc2UgUnVsZVR5cGUuT2Zmc2V0OlxuICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICAgIGFiYnJldmlhdGlvbjogem9uZUFiYnJldmlhdGlvbihpbmZvLmZvcm1hdCwgaW5mby5ydWxlT2Zmc2V0Lm5vblplcm8oKSwgdW5kZWZpbmVkKSxcbiAgICAgICAgICAgICAgICAgICAgbGV0dGVyOiBcIlwiLFxuICAgICAgICAgICAgICAgICAgICBkc3RPZmZzZXQ6IGluZm8ucnVsZU9mZnNldCxcbiAgICAgICAgICAgICAgICAgICAgc3RhbmRhcmRPZmZzZXQ6IGluZm8uZ210b2ZmXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGNhc2UgUnVsZVR5cGUuUnVsZU5hbWU6IHtcbiAgICAgICAgICAgICAgICB2YXIgcnVsZSA9IHJ1bGVzLmdldChpbmZvLnJ1bGVOYW1lKTtcbiAgICAgICAgICAgICAgICBpZiAoIXJ1bGUpIHtcbiAgICAgICAgICAgICAgICAgICAgKDAsIGVycm9yXzEudGhyb3dFcnJvcikoXCJJbnZhbGlkVGltZVpvbmVEYXRhXCIsIFwiem9uZSAnXCIuY29uY2F0KHpvbmVOYW1lLCBcIicgcmVmZXJzIHRvIG5vbi1leGlzdGluZyBydWxlICdcIikuY29uY2F0KGluZm8ucnVsZU5hbWUsIFwiJ1wiKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIC8vIGZpbmQgZmlyc3QgcnVsZSB0cmFuc2l0aW9uIHdpdGhvdXQgRFNUIHNvIHRoYXQgd2UgaGF2ZSBhIGxldHRlclxuICAgICAgICAgICAgICAgIHZhciBpdGVyYXRvciA9IHJ1bGUuZmluZEZpcnN0KCk7XG4gICAgICAgICAgICAgICAgd2hpbGUgKGl0ZXJhdG9yICYmIGl0ZXJhdG9yLnRyYW5zaXRpb24ubmV3U3RhdGUuZHN0T2Zmc2V0Lm5vblplcm8oKSkge1xuICAgICAgICAgICAgICAgICAgICBpdGVyYXRvciA9IHJ1bGUuZmluZE5leHQoaXRlcmF0b3IpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB2YXIgbGV0dGVyID0gKF9hID0gaXRlcmF0b3IgPT09IG51bGwgfHwgaXRlcmF0b3IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IGl0ZXJhdG9yLnRyYW5zaXRpb24ubmV3U3RhdGUubGV0dGVyKSAhPT0gbnVsbCAmJiBfYSAhPT0gdm9pZCAwID8gX2EgOiBcIlwiO1xuICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICAgIGFiYnJldmlhdGlvbjogem9uZUFiYnJldmlhdGlvbihpbmZvLmZvcm1hdCwgZmFsc2UsIGxldHRlciksXG4gICAgICAgICAgICAgICAgICAgIGRzdE9mZnNldDogKDAsIGR1cmF0aW9uXzEuaG91cnMpKDApLFxuICAgICAgICAgICAgICAgICAgICBsZXR0ZXI6IGxldHRlcixcbiAgICAgICAgICAgICAgICAgICAgc3RhbmRhcmRPZmZzZXQ6IGluZm8uZ210b2ZmXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKGZhbHNlLCBcInRpbWV6b25lY29tcGxldGUuQXNzZXJ0aW9uXCIsIFwiVW5rbm93biBSdWxlVHlwZVwiKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgLyoqXG4gICAgICogUHJlLWNhbGN1bGF0ZSBhbGwgdHJhbnNpdGlvbnMgdW50aWwgdGhlcmUgYXJlIG9ubHkgJ21heCcgcnVsZXMgaW4gZWZmZWN0XG4gICAgICogQHBhcmFtIHpvbmVOYW1lXG4gICAgICogQHBhcmFtIGluaXRpYWxTdGF0ZVxuICAgICAqIEBwYXJhbSB6b25lSW5mb3NcbiAgICAgKiBAcGFyYW0gcnVsZXNcbiAgICAgKi9cbiAgICBDYWNoZWRab25lVHJhbnNpdGlvbnMucHJvdG90eXBlLl9jYWxjVHJhbnNpdGlvbnMgPSBmdW5jdGlvbiAoem9uZU5hbWUsIGluaXRpYWxTdGF0ZSwgem9uZUluZm9zLCBydWxlcykge1xuICAgICAgICB2YXIgX2E7XG4gICAgICAgIGlmICh6b25lSW5mb3MubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICByZXR1cm4gW1tdLCBbXV07XG4gICAgICAgIH1cbiAgICAgICAgLy8gd2FsayB0aHJvdWdoIHRoZSB6b25lIHJlY29yZHMgYW5kIGFkZCBhIHRyYW5zaXRpb24gZm9yIGVhY2hcbiAgICAgICAgdmFyIHRyYW5zaXRpb25zID0gW107XG4gICAgICAgIHZhciBwcmV2U3RhdGUgPSBpbml0aWFsU3RhdGU7XG4gICAgICAgIHZhciBwcmV2VW50aWw7XG4gICAgICAgIHZhciBwcmV2UnVsZXM7XG4gICAgICAgIGZvciAodmFyIF9pID0gMCwgem9uZUluZm9zXzYgPSB6b25lSW5mb3M7IF9pIDwgem9uZUluZm9zXzYubGVuZ3RoOyBfaSsrKSB7XG4gICAgICAgICAgICB2YXIgem9uZUluZm8gPSB6b25lSW5mb3NfNltfaV07XG4gICAgICAgICAgICAvLyB6b25lcyBjYW4gaGF2ZSBhIERTVCBvZmZzZXQgb3IgdGhleSBjYW4gcmVmZXIgdG8gYSBydWxlIHNldFxuICAgICAgICAgICAgc3dpdGNoICh6b25lSW5mby5ydWxlVHlwZSkge1xuICAgICAgICAgICAgICAgIGNhc2UgUnVsZVR5cGUuTm9uZTpcbiAgICAgICAgICAgICAgICBjYXNlIFJ1bGVUeXBlLk9mZnNldDpcbiAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHByZXZVbnRpbCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zaXRpb25zLnB1c2goe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhdFV0YzogcHJldlVudGlsLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXdTdGF0ZToge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWJicmV2aWF0aW9uOiB6b25lQWJicmV2aWF0aW9uKHpvbmVJbmZvLmZvcm1hdCwgZmFsc2UsIHVuZGVmaW5lZCksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXR0ZXI6IFwiXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkc3RPZmZzZXQ6IHpvbmVJbmZvLnJ1bGVUeXBlID09PSBSdWxlVHlwZS5Ob25lID8gKDAsIGR1cmF0aW9uXzEuaG91cnMpKDApIDogem9uZUluZm8ucnVsZU9mZnNldCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YW5kYXJkT2Zmc2V0OiB6b25lSW5mby5nbXRvZmZcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByZXZSdWxlcyA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBjYXNlIFJ1bGVUeXBlLlJ1bGVOYW1lOlxuICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgcnVsZSA9IHJ1bGVzLmdldCh6b25lSW5mby5ydWxlTmFtZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoIXJ1bGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gKDAsIGVycm9yXzEudGhyb3dFcnJvcikoXCJJbnZhbGlkVGltZVpvbmVEYXRhXCIsIFwiWm9uZSAnXCIuY29uY2F0KHpvbmVOYW1lLCBcIicgcmVmZXJzIHRvIG5vbi1leGlzdGluZyBydWxlICdcIikuY29uY2F0KHpvbmVJbmZvLnJ1bGVOYW1lLCBcIidcIikpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHQgPSB0aGlzLl96b25lVHJhbnNpdGlvbnMocHJldlVudGlsLCB6b25lSW5mbywgcnVsZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2l0aW9ucyA9IHRyYW5zaXRpb25zLmNvbmNhdCh0KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHByZXZSdWxlcyA9IHJ1bGU7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICAgICAgKDAsIGFzc2VydF8xLmRlZmF1bHQpKGZhbHNlLCBcInRpbWV6b25lY29tcGxldGUuQXNzZXJ0aW9uXCIsIFwiVW5rbm93biBSdWxlVHlwZVwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHByZXZVbnRpbCA9IHpvbmVJbmZvLnVudGlsICE9PSB1bmRlZmluZWQgPyBuZXcgYmFzaWNzXzEuVGltZVN0cnVjdCh6b25lSW5mby51bnRpbCkgOiB1bmRlZmluZWQ7XG4gICAgICAgICAgICBwcmV2U3RhdGUgPSB0cmFuc2l0aW9ucy5sZW5ndGggPiAwID8gdHJhbnNpdGlvbnNbdHJhbnNpdGlvbnMubGVuZ3RoIC0gMV0ubmV3U3RhdGUgOiBwcmV2U3RhdGU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIFt0cmFuc2l0aW9ucywgKF9hID0gcHJldlJ1bGVzID09PSBudWxsIHx8IHByZXZSdWxlcyA9PT0gdm9pZCAwID8gdm9pZCAwIDogcHJldlJ1bGVzLmZpbmFsKSAhPT0gbnVsbCAmJiBfYSAhPT0gdm9pZCAwID8gX2EgOiBbXV07XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFsbCB0aGUgdHJhbnNpdGlvbnMgZm9yIGEgdGltZSB6b25lIGZyb20gZnJvbVV0YyAoaW5jbHVzaXZlKSB0byB6b25lSW5mby51bnRpbCAoZXhjbHVzaXZlKS5cbiAgICAgKiBUaGUgcmVzdWx0IGFsd2F5cyBjb250YWlucyBhbiBpbml0aWFsIHRyYW5zaXRpb24gYXQgZnJvbVV0YyB0aGF0IHNpZ25hbHMgdGhlIHN3aXRjaCB0byB0aGlzIHJ1bGUgc2V0XG4gICAgICpcbiAgICAgKiBAcGFyYW0gZnJvbVV0YyBwcmV2aW91cyB6b25lIHN1Yi1yZWNvcmQgVU5USUwgdGltZTsgdW5kZWZpbmVkIGZvciBmaXJzdCB6b25lIHJlY29yZFxuICAgICAqIEBwYXJhbSB6b25lSW5mbyB0aGUgY3VycmVudCB6b25lIHN1Yi1yZWNvcmRcbiAgICAgKiBAcGFyYW0gcnVsZSB0aGUgY29ycmVzcG9uZGluZyBydWxlIHRyYW5zaXRpb25zXG4gICAgICovXG4gICAgQ2FjaGVkWm9uZVRyYW5zaXRpb25zLnByb3RvdHlwZS5fem9uZVRyYW5zaXRpb25zID0gZnVuY3Rpb24gKGZyb21VdGMsIHpvbmVJbmZvLCBydWxlKSB7XG4gICAgICAgIC8vIGZyb20gdHotaG93LXRvLmh0bWw6XG4gICAgICAgIC8vIE9uZSB3cmlua2xlLCBub3QgZnVsbHkgZXhwbGFpbmVkIGluIHppYy44LnR4dCwgaXMgd2hhdCBoYXBwZW5zIHdoZW4gc3dpdGNoaW5nIHRvIGEgbmFtZWQgcnVsZS4gVG8gd2hhdCB2YWx1ZXMgc2hvdWxkIHRoZSBTQVZFIGFuZFxuICAgICAgICAvLyBMRVRURVIgZGF0YSBiZSBpbml0aWFsaXplZD9cbiAgICAgICAgLy8gLSBJZiBhdCBsZWFzdCBvbmUgdHJhbnNpdGlvbiBoYXMgaGFwcGVuZWQsIHVzZSB0aGUgU0FWRSBhbmQgTEVUVEVSIGRhdGEgZnJvbSB0aGUgbW9zdCByZWNlbnQuXG4gICAgICAgIC8vIC0gSWYgc3dpdGNoaW5nIHRvIGEgbmFtZWQgcnVsZSBiZWZvcmUgYW55IHRyYW5zaXRpb24gaGFzIGhhcHBlbmVkLCBhc3N1bWUgc3RhbmRhcmQgdGltZSAoU0FWRSB6ZXJvKSwgYW5kIHVzZSB0aGUgTEVUVEVSIGRhdGEgZnJvbVxuICAgICAgICAvLyB0aGUgZWFybGllc3QgdHJhbnNpdGlvbiB3aXRoIGEgU0FWRSBvZiB6ZXJvLlxuICAgICAgICB2YXIgX2EsIF9iLCBfYywgX2Q7XG4gICAgICAgIHZhciByZXN1bHQgPSBbXTtcbiAgICAgICAgLy8gZXh0cmEgaW5pdGlhbCB0cmFuc2l0aW9uIGZvciBzd2l0Y2ggdG8gdGhpcyBydWxlIHNldCAoYnV0IG5vdCBmb3IgZmlyc3Qgem9uZSBpbmZvKVxuICAgICAgICB2YXIgaW5pdGlhbDtcbiAgICAgICAgaWYgKGZyb21VdGMgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgdmFyIGluaXRpYWxSdWxlVHJhbnNpdGlvbiA9IHJ1bGUuZmluZExhc3RMZXNzRXF1YWwoZnJvbVV0Yywgem9uZUluZm8uZ210b2ZmKTtcbiAgICAgICAgICAgIGlmIChpbml0aWFsUnVsZVRyYW5zaXRpb24pIHtcbiAgICAgICAgICAgICAgICBpbml0aWFsID0ge1xuICAgICAgICAgICAgICAgICAgICBhdFV0YzogZnJvbVV0YyxcbiAgICAgICAgICAgICAgICAgICAgbmV3U3RhdGU6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGFiYnJldmlhdGlvbjogem9uZUFiYnJldmlhdGlvbih6b25lSW5mby5mb3JtYXQsIGZhbHNlLCBpbml0aWFsUnVsZVRyYW5zaXRpb24ubmV3U3RhdGUubGV0dGVyKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGxldHRlcjogKF9hID0gaW5pdGlhbFJ1bGVUcmFuc2l0aW9uLm5ld1N0YXRlLmxldHRlcikgIT09IG51bGwgJiYgX2EgIT09IHZvaWQgMCA/IF9hIDogXCJcIixcbiAgICAgICAgICAgICAgICAgICAgICAgIGRzdE9mZnNldDogKDAsIGR1cmF0aW9uXzEuaG91cnMpKDApLFxuICAgICAgICAgICAgICAgICAgICAgICAgc3RhbmRhcmRPZmZzZXQ6IHpvbmVJbmZvLmdtdG9mZlxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIGluaXRpYWxSdWxlVHJhbnNpdGlvbiA9IHJ1bGUuZmlyc3RUcmFuc2l0aW9uV2l0aG91dERzdEFmdGVyKGZyb21VdGMsIHpvbmVJbmZvLmdtdG9mZiwgdW5kZWZpbmVkKTtcbiAgICAgICAgICAgICAgICBpbml0aWFsID0ge1xuICAgICAgICAgICAgICAgICAgICBhdFV0YzogZnJvbVV0YyxcbiAgICAgICAgICAgICAgICAgICAgbmV3U3RhdGU6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGFiYnJldmlhdGlvbjogem9uZUFiYnJldmlhdGlvbih6b25lSW5mby5mb3JtYXQsIGZhbHNlLCBpbml0aWFsUnVsZVRyYW5zaXRpb24gPT09IG51bGwgfHwgaW5pdGlhbFJ1bGVUcmFuc2l0aW9uID09PSB2b2lkIDAgPyB2b2lkIDAgOiBpbml0aWFsUnVsZVRyYW5zaXRpb24ubmV3U3RhdGUubGV0dGVyKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGxldHRlcjogKF9iID0gaW5pdGlhbFJ1bGVUcmFuc2l0aW9uID09PSBudWxsIHx8IGluaXRpYWxSdWxlVHJhbnNpdGlvbiA9PT0gdm9pZCAwID8gdm9pZCAwIDogaW5pdGlhbFJ1bGVUcmFuc2l0aW9uLm5ld1N0YXRlLmxldHRlcikgIT09IG51bGwgJiYgX2IgIT09IHZvaWQgMCA/IF9iIDogXCJcIixcbiAgICAgICAgICAgICAgICAgICAgICAgIGRzdE9mZnNldDogKDAsIGR1cmF0aW9uXzEuaG91cnMpKDApLFxuICAgICAgICAgICAgICAgICAgICAgICAgc3RhbmRhcmRPZmZzZXQ6IHpvbmVJbmZvLmdtdG9mZlxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJlc3VsdC5wdXNoKGluaXRpYWwpO1xuICAgICAgICB9XG4gICAgICAgIC8vIGFjdHVhbCBydWxlIHRyYW5zaXRpb25zOyBrZWVwIGFkZGluZyB1bnRpbCB0aGUgZW5kIG9mIHRoaXMgem9uZSBpbmZvLCBvciB1bnRpbCBvbmx5ICdtYXgnIHJ1bGVzIHJlbWFpblxuICAgICAgICB2YXIgcHJldkRzdCA9IChfYyA9IGluaXRpYWwgPT09IG51bGwgfHwgaW5pdGlhbCA9PT0gdm9pZCAwID8gdm9pZCAwIDogaW5pdGlhbC5uZXdTdGF0ZS5kc3RPZmZzZXQpICE9PSBudWxsICYmIF9jICE9PSB2b2lkIDAgPyBfYyA6ICgwLCBkdXJhdGlvbl8xLmhvdXJzKSgwKTtcbiAgICAgICAgdmFyIGl0ZXJhdG9yID0gcnVsZS5maW5kRmlyc3QoKTtcbiAgICAgICAgdmFyIGVmZmVjdGl2ZSA9IChpdGVyYXRvciA9PT0gbnVsbCB8fCBpdGVyYXRvciA9PT0gdm9pZCAwID8gdm9pZCAwIDogaXRlcmF0b3IudHJhbnNpdGlvbikgJiYgcnVsZVRyYW5zaXRpb25VdGMoaXRlcmF0b3IudHJhbnNpdGlvbiwgem9uZUluZm8uZ210b2ZmLCBwcmV2RHN0KTtcbiAgICAgICAgd2hpbGUgKGl0ZXJhdG9yICYmIGVmZmVjdGl2ZSAmJlxuICAgICAgICAgICAgKCh6b25lSW5mby51bnRpbCAmJiBlZmZlY3RpdmUudW5peE1pbGxpcyA8IHpvbmVJbmZvLnVudGlsKSB8fCAoIXpvbmVJbmZvLnVudGlsICYmICFpdGVyYXRvci5maW5hbCkpKSB7XG4gICAgICAgICAgICBwcmV2RHN0ID0gaXRlcmF0b3IudHJhbnNpdGlvbi5uZXdTdGF0ZS5kc3RPZmZzZXQ7XG4gICAgICAgICAgICByZXN1bHQucHVzaCh7XG4gICAgICAgICAgICAgICAgYXRVdGM6IGVmZmVjdGl2ZSxcbiAgICAgICAgICAgICAgICBuZXdTdGF0ZToge1xuICAgICAgICAgICAgICAgICAgICBhYmJyZXZpYXRpb246IHpvbmVBYmJyZXZpYXRpb24oem9uZUluZm8uZm9ybWF0LCBwcmV2RHN0Lm5vblplcm8oKSwgaXRlcmF0b3IudHJhbnNpdGlvbi5uZXdTdGF0ZS5sZXR0ZXIpLFxuICAgICAgICAgICAgICAgICAgICBsZXR0ZXI6IChfZCA9IGl0ZXJhdG9yLnRyYW5zaXRpb24ubmV3U3RhdGUubGV0dGVyKSAhPT0gbnVsbCAmJiBfZCAhPT0gdm9pZCAwID8gX2QgOiBcIlwiLFxuICAgICAgICAgICAgICAgICAgICBkc3RPZmZzZXQ6IHByZXZEc3QsXG4gICAgICAgICAgICAgICAgICAgIHN0YW5kYXJkT2Zmc2V0OiB6b25lSW5mby5nbXRvZmZcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGl0ZXJhdG9yID0gcnVsZS5maW5kTmV4dChpdGVyYXRvcik7XG4gICAgICAgICAgICBlZmZlY3RpdmUgPSBpdGVyYXRvciAmJiBydWxlVHJhbnNpdGlvblV0YyhpdGVyYXRvci50cmFuc2l0aW9uLCB6b25lSW5mby5nbXRvZmYsIHByZXZEc3QpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfTtcbiAgICByZXR1cm4gQ2FjaGVkWm9uZVRyYW5zaXRpb25zO1xufSgpKTtcbi8qKlxuICogQ2FsY3VsYXRlIHRoZSBmb3JtYXR0ZWQgYWJicmV2aWF0aW9uIGZvciBhIHpvbmVcbiAqIEBwYXJhbSBmb3JtYXQgdGhlIGFiYnJldmlhdGlvbiBmb3JtYXQgc3RyaW5nLiBFaXRoZXIgJ3p6eiwnIGZvciBOVUxMOyAgJ0EvQicgZm9yIHN0ZC9kc3QsIG9yICdBJXNCJyBmb3IgYSBmb3JtYXQgc3RyaW5nIHdoZXJlICVzIGlzXG4gKiByZXBsYWNlZCBieSBhIGxldHRlclxuICogQHBhcmFtIGRzdCB3aGV0aGVyIERTVCBpcyBvYnNlcnZlZFxuICogQHBhcmFtIGxldHRlciBjdXJyZW50IHJ1bGUgbGV0dGVyLCBlbXB0eSBpZiBubyBydWxlXG4gKiBAcmV0dXJucyBmdWxseSBmb3JtYXR0ZWQgYWJicmV2aWF0aW9uXG4gKi9cbmZ1bmN0aW9uIHpvbmVBYmJyZXZpYXRpb24oZm9ybWF0LCBkc3QsIGxldHRlcikge1xuICAgIGlmIChmb3JtYXQgPT09IFwienp6LFwiKSB7XG4gICAgICAgIHJldHVybiBcIlwiO1xuICAgIH1cbiAgICBpZiAoZm9ybWF0LmluY2x1ZGVzKFwiL1wiKSkge1xuICAgICAgICByZXR1cm4gKGRzdCA/IGZvcm1hdC5zcGxpdChcIi9cIilbMV0gOiBmb3JtYXQuc3BsaXQoXCIvXCIpWzBdKTtcbiAgICB9XG4gICAgaWYgKGxldHRlcikge1xuICAgICAgICByZXR1cm4gZm9ybWF0LnJlcGxhY2UoXCIlc1wiLCBsZXR0ZXIpO1xuICAgIH1cbiAgICByZXR1cm4gZm9ybWF0LnJlcGxhY2UoXCIlc1wiLCBcIlwiKTtcbn1cbi8qKlxuICogQ2FsY3VsYXRlIHRoZSBVVEMgdGltZSBvZiBhIHJ1bGUgdHJhbnNpdGlvbiwgZ2l2ZW4gYSBwYXJ0aWN1bGFyIHRpbWUgem9uZVxuICogQHBhcmFtIHRyYW5zaXRpb25cbiAqIEBwYXJhbSBzdGFuZGFyZE9mZnNldCB6b25lIG9mZnNldCBmcm9tIFVUXG4gKiBAcGFyYW0gZHN0T2Zmc2V0IHByZXZpb3VzIERTVCBvZmZzZXQgZnJvbSBVVCtzdGFuZGFyZE9mZnNldFxuICogQHJldHVybnMgVVRDIHRpbWVcbiAqL1xuZnVuY3Rpb24gcnVsZVRyYW5zaXRpb25VdGModHJhbnNpdGlvbiwgc3RhbmRhcmRPZmZzZXQsIGRzdE9mZnNldCkge1xuICAgIHN3aXRjaCAodHJhbnNpdGlvbi5hdFR5cGUpIHtcbiAgICAgICAgY2FzZSBBdFR5cGUuVXRjOiByZXR1cm4gdHJhbnNpdGlvbi5hdDtcbiAgICAgICAgY2FzZSBBdFR5cGUuU3RhbmRhcmQ6IHtcbiAgICAgICAgICAgIC8vIHRyYW5zaXRpb24gdGltZSBpcyBpbiB6b25lIGxvY2FsIHRpbWUgd2l0aG91dCBEU1RcbiAgICAgICAgICAgIHZhciBtaWxsaXMgPSB0cmFuc2l0aW9uLmF0LnVuaXhNaWxsaXM7XG4gICAgICAgICAgICBtaWxsaXMgLT0gc3RhbmRhcmRPZmZzZXQubWlsbGlzZWNvbmRzKCk7XG4gICAgICAgICAgICByZXR1cm4gbmV3IGJhc2ljc18xLlRpbWVTdHJ1Y3QobWlsbGlzKTtcbiAgICAgICAgfVxuICAgICAgICBjYXNlIEF0VHlwZS5XYWxsOiB7XG4gICAgICAgICAgICAvLyB0cmFuc2l0aW9uIHRpbWUgaXMgaW4gem9uZSBsb2NhbCB0aW1lIHdpdGggRFNUXG4gICAgICAgICAgICB2YXIgbWlsbGlzID0gdHJhbnNpdGlvbi5hdC51bml4TWlsbGlzO1xuICAgICAgICAgICAgbWlsbGlzIC09IHN0YW5kYXJkT2Zmc2V0Lm1pbGxpc2Vjb25kcygpO1xuICAgICAgICAgICAgaWYgKGRzdE9mZnNldCkge1xuICAgICAgICAgICAgICAgIG1pbGxpcyAtPSBkc3RPZmZzZXQubWlsbGlzZWNvbmRzKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gbmV3IGJhc2ljc18xLlRpbWVTdHJ1Y3QobWlsbGlzKTtcbiAgICAgICAgfVxuICAgIH1cbn1cbi8vIyBzb3VyY2VNYXBwaW5nVVJMPXR6LWRhdGFiYXNlLmpzLm1hcCIsIi8qKlxuICogQ29weXJpZ2h0KGMpIDIwMTQgQUJCIFN3aXR6ZXJsYW5kIEx0ZC5cbiAqXG4gKiBEYXRlIGFuZCBUaW1lIHV0aWxpdHkgZnVuY3Rpb25zIC0gbWFpbiBpbmRleFxuICovXG5cInVzZSBzdHJpY3RcIjtcbnZhciBfX2NyZWF0ZUJpbmRpbmcgPSAodGhpcyAmJiB0aGlzLl9fY3JlYXRlQmluZGluZykgfHwgKE9iamVjdC5jcmVhdGUgPyAoZnVuY3Rpb24obywgbSwgaywgazIpIHtcbiAgICBpZiAoazIgPT09IHVuZGVmaW5lZCkgazIgPSBrO1xuICAgIHZhciBkZXNjID0gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihtLCBrKTtcbiAgICBpZiAoIWRlc2MgfHwgKFwiZ2V0XCIgaW4gZGVzYyA/ICFtLl9fZXNNb2R1bGUgOiBkZXNjLndyaXRhYmxlIHx8IGRlc2MuY29uZmlndXJhYmxlKSkge1xuICAgICAgZGVzYyA9IHsgZW51bWVyYWJsZTogdHJ1ZSwgZ2V0OiBmdW5jdGlvbigpIHsgcmV0dXJuIG1ba107IH0gfTtcbiAgICB9XG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KG8sIGsyLCBkZXNjKTtcbn0pIDogKGZ1bmN0aW9uKG8sIG0sIGssIGsyKSB7XG4gICAgaWYgKGsyID09PSB1bmRlZmluZWQpIGsyID0gaztcbiAgICBvW2syXSA9IG1ba107XG59KSk7XG52YXIgX19leHBvcnRTdGFyID0gKHRoaXMgJiYgdGhpcy5fX2V4cG9ydFN0YXIpIHx8IGZ1bmN0aW9uKG0sIGV4cG9ydHMpIHtcbiAgICBmb3IgKHZhciBwIGluIG0pIGlmIChwICE9PSBcImRlZmF1bHRcIiAmJiAhT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGV4cG9ydHMsIHApKSBfX2NyZWF0ZUJpbmRpbmcoZXhwb3J0cywgbSwgcCk7XG59O1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7IHZhbHVlOiB0cnVlIH0pO1xuZXhwb3J0cy5ab25lSW5mbyA9IGV4cG9ydHMuVHpEYXRhYmFzZSA9IGV4cG9ydHMuVHJhbnNpdGlvbiA9IGV4cG9ydHMuVG9UeXBlID0gZXhwb3J0cy5PblR5cGUgPSBleHBvcnRzLlJ1bGVUeXBlID0gZXhwb3J0cy5SdWxlSW5mbyA9IGV4cG9ydHMuTm9ybWFsaXplT3B0aW9uID0gZXhwb3J0cy5pc1ZhbGlkT2Zmc2V0U3RyaW5nID0gZXhwb3J0cy5BdFR5cGUgPSB2b2lkIDA7XG5fX2V4cG9ydFN0YXIocmVxdWlyZShcIi4vYmFzaWNzXCIpLCBleHBvcnRzKTtcbl9fZXhwb3J0U3RhcihyZXF1aXJlKFwiLi9kYXRldGltZVwiKSwgZXhwb3J0cyk7XG5fX2V4cG9ydFN0YXIocmVxdWlyZShcIi4vZHVyYXRpb25cIiksIGV4cG9ydHMpO1xuX19leHBvcnRTdGFyKHJlcXVpcmUoXCIuL2Zvcm1hdFwiKSwgZXhwb3J0cyk7XG5fX2V4cG9ydFN0YXIocmVxdWlyZShcIi4vZ2xvYmFsc1wiKSwgZXhwb3J0cyk7XG5fX2V4cG9ydFN0YXIocmVxdWlyZShcIi4vamF2YXNjcmlwdFwiKSwgZXhwb3J0cyk7XG5fX2V4cG9ydFN0YXIocmVxdWlyZShcIi4vbG9jYWxlXCIpLCBleHBvcnRzKTtcbl9fZXhwb3J0U3RhcihyZXF1aXJlKFwiLi9wYXJzZVwiKSwgZXhwb3J0cyk7XG5fX2V4cG9ydFN0YXIocmVxdWlyZShcIi4vcGVyaW9kXCIpLCBleHBvcnRzKTtcbl9fZXhwb3J0U3RhcihyZXF1aXJlKFwiLi90aW1lc291cmNlXCIpLCBleHBvcnRzKTtcbl9fZXhwb3J0U3RhcihyZXF1aXJlKFwiLi90aW1lem9uZVwiKSwgZXhwb3J0cyk7XG52YXIgdHpfZGF0YWJhc2VfMSA9IHJlcXVpcmUoXCIuL3R6LWRhdGFiYXNlXCIpO1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiQXRUeXBlXCIsIHsgZW51bWVyYWJsZTogdHJ1ZSwgZ2V0OiBmdW5jdGlvbiAoKSB7IHJldHVybiB0el9kYXRhYmFzZV8xLkF0VHlwZTsgfSB9KTtcbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcImlzVmFsaWRPZmZzZXRTdHJpbmdcIiwgeyBlbnVtZXJhYmxlOiB0cnVlLCBnZXQ6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHR6X2RhdGFiYXNlXzEuaXNWYWxpZE9mZnNldFN0cmluZzsgfSB9KTtcbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIk5vcm1hbGl6ZU9wdGlvblwiLCB7IGVudW1lcmFibGU6IHRydWUsIGdldDogZnVuY3Rpb24gKCkgeyByZXR1cm4gdHpfZGF0YWJhc2VfMS5Ob3JtYWxpemVPcHRpb247IH0gfSk7XG5PYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgXCJSdWxlSW5mb1wiLCB7IGVudW1lcmFibGU6IHRydWUsIGdldDogZnVuY3Rpb24gKCkgeyByZXR1cm4gdHpfZGF0YWJhc2VfMS5SdWxlSW5mbzsgfSB9KTtcbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIlJ1bGVUeXBlXCIsIHsgZW51bWVyYWJsZTogdHJ1ZSwgZ2V0OiBmdW5jdGlvbiAoKSB7IHJldHVybiB0el9kYXRhYmFzZV8xLlJ1bGVUeXBlOyB9IH0pO1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiT25UeXBlXCIsIHsgZW51bWVyYWJsZTogdHJ1ZSwgZ2V0OiBmdW5jdGlvbiAoKSB7IHJldHVybiB0el9kYXRhYmFzZV8xLk9uVHlwZTsgfSB9KTtcbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIlRvVHlwZVwiLCB7IGVudW1lcmFibGU6IHRydWUsIGdldDogZnVuY3Rpb24gKCkgeyByZXR1cm4gdHpfZGF0YWJhc2VfMS5Ub1R5cGU7IH0gfSk7XG5PYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgXCJUcmFuc2l0aW9uXCIsIHsgZW51bWVyYWJsZTogdHJ1ZSwgZ2V0OiBmdW5jdGlvbiAoKSB7IHJldHVybiB0el9kYXRhYmFzZV8xLlRyYW5zaXRpb247IH0gfSk7XG5PYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgXCJUekRhdGFiYXNlXCIsIHsgZW51bWVyYWJsZTogdHJ1ZSwgZ2V0OiBmdW5jdGlvbiAoKSB7IHJldHVybiB0el9kYXRhYmFzZV8xLlR6RGF0YWJhc2U7IH0gfSk7XG5PYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgXCJab25lSW5mb1wiLCB7IGVudW1lcmFibGU6IHRydWUsIGdldDogZnVuY3Rpb24gKCkgeyByZXR1cm4gdHpfZGF0YWJhc2VfMS5ab25lSW5mbzsgfSB9KTtcbi8vIyBzb3VyY2VNYXBwaW5nVVJMPWluZGV4LmpzLm1hcCJdfQ==