| 1 |
/**
|
| 2 |
* =====================================================================================================================
|
| 3 |
* JavaScript Util Functions ../includes/__js/utils/wpbc_utils.js
|
| 4 |
* =====================================================================================================================
|
| 5 |
*/
|
| 6 |
|
| 7 |
/**
|
| 8 |
* Trim strings and array joined with (,)
|
| 9 |
*
|
| 10 |
* @param string_to_trim string / array
|
| 11 |
* @returns string
|
| 12 |
*/
|
| 13 |
function wpbc_trim(string_to_trim) {
|
| 14 |
|
| 15 |
if ( Array.isArray( string_to_trim ) ) {
|
| 16 |
string_to_trim = string_to_trim.join( ',' );
|
| 17 |
}
|
| 18 |
|
| 19 |
if ( 'string' == typeof (string_to_trim) ) {
|
| 20 |
string_to_trim = string_to_trim.trim();
|
| 21 |
}
|
| 22 |
|
| 23 |
return string_to_trim;
|
| 24 |
}
|
| 25 |
|
| 26 |
/**
|
| 27 |
* Check if element in array
|
| 28 |
*
|
| 29 |
* @param array_here array
|
| 30 |
* @param p_val element to check
|
| 31 |
* @returns {boolean}
|
| 32 |
*/
|
| 33 |
function wpbc_in_array(array_here, p_val) {
|
| 34 |
for ( var i = 0, l = array_here.length; i < l; i++ ) {
|
| 35 |
if ( array_here[i] == p_val ) {
|
| 36 |
return true;
|
| 37 |
}
|
| 38 |
}
|
| 39 |
return false;
|
| 40 |
}
|
| 41 |
|
| 42 |
/**
|
| 43 |
* Prevent opening blank windows on WordPress playground for pseudo links like this: <a href="javascript:void(0)"> or # to stay in the same tab.
|
| 44 |
*/
|
| 45 |
(function () {
|
| 46 |
'use strict';
|
| 47 |
|
| 48 |
function is_playground_origin() {
|
| 49 |
return location.origin === 'https://playground.wordpress.net';
|
| 50 |
}
|
| 51 |
|
| 52 |
function is_pseudo_link(a) {
|
| 53 |
if ( !a || !a.getAttribute ) return true;
|
| 54 |
var href = (a.getAttribute( 'href' ) || '').trim().toLowerCase();
|
| 55 |
return (
|
| 56 |
!href ||
|
| 57 |
href === '#' ||
|
| 58 |
href.indexOf( '#' ) === 0 ||
|
| 59 |
href.indexOf( 'javascript:' ) === 0 ||
|
| 60 |
href.indexOf( 'mailto:' ) === 0 ||
|
| 61 |
href.indexOf( 'tel:' ) === 0
|
| 62 |
);
|
| 63 |
}
|
| 64 |
|
| 65 |
function fix_target(a) {
|
| 66 |
if ( ! a ) return;
|
| 67 |
if ( is_pseudo_link( a ) || a.hasAttribute( 'data-wp-no-blank' ) ) {
|
| 68 |
a.target = '_self';
|
| 69 |
}
|
| 70 |
}
|
| 71 |
|
| 72 |
function init_fix() {
|
| 73 |
// Optional: clean up current DOM (harmless—affects only pseudo/datamarked links).
|
| 74 |
var nodes = document.querySelectorAll( 'a[href]' );
|
| 75 |
for ( var i = 0; i < nodes.length; i++ ) fix_target( nodes[i] );
|
| 76 |
|
| 77 |
// Late bubble-phase listeners (run after Playground's handlers)
|
| 78 |
document.addEventListener( 'click', function (e) {
|
| 79 |
var a = e.target && e.target.closest ? e.target.closest( 'a[href]' ) : null;
|
| 80 |
if ( a ) fix_target( a );
|
| 81 |
}, false );
|
| 82 |
|
| 83 |
document.addEventListener( 'focusin', function (e) {
|
| 84 |
var a = e.target && e.target.closest ? e.target.closest( 'a[href]' ) : null;
|
| 85 |
if ( a ) fix_target( a );
|
| 86 |
} );
|
| 87 |
}
|
| 88 |
|
| 89 |
function schedule_init() {
|
| 90 |
if ( !is_playground_origin() ) return;
|
| 91 |
setTimeout( init_fix, 1000 ); // ensure we attach after Playground's script.
|
| 92 |
}
|
| 93 |
|
| 94 |
if ( document.readyState === 'loading' ) {
|
| 95 |
document.addEventListener( 'DOMContentLoaded', schedule_init );
|
| 96 |
} else {
|
| 97 |
schedule_init();
|
| 98 |
}
|
| 99 |
})(); |
| 100 |
"use strict";
|
| 101 |
/**
|
| 102 |
* =====================================================================================================================
|
| 103 |
* includes/__js/wpbc/wpbc.js
|
| 104 |
* =====================================================================================================================
|
| 105 |
*/
|
| 106 |
|
| 107 |
/**
|
| 108 |
* Deep Clone of object or array
|
| 109 |
*
|
| 110 |
* @param obj
|
| 111 |
* @returns {any}
|
| 112 |
*/
|
| 113 |
function wpbc_clone_obj( obj ){
|
| 114 |
|
| 115 |
return JSON.parse( JSON.stringify( obj ) );
|
| 116 |
}
|
| 117 |
|
| 118 |
|
| 119 |
|
| 120 |
/**
|
| 121 |
* Main _wpbc JS object
|
| 122 |
*/
|
| 123 |
|
| 124 |
var _wpbc = (function ( obj, $) {
|
| 125 |
|
| 126 |
// Secure parameters for Ajax ------------------------------------------------------------------------------------
|
| 127 |
var p_secure = obj.security_obj = obj.security_obj || {
|
| 128 |
user_id: 0,
|
| 129 |
nonce : '',
|
| 130 |
locale : ''
|
| 131 |
};
|
| 132 |
obj.set_secure_param = function ( param_key, param_val ) {
|
| 133 |
p_secure[ param_key ] = param_val;
|
| 134 |
};
|
| 135 |
|
| 136 |
obj.get_secure_param = function ( param_key ) {
|
| 137 |
return p_secure[ param_key ];
|
| 138 |
};
|
| 139 |
|
| 140 |
|
| 141 |
// Calendars ----------------------------------------------------------------------------------------------------
|
| 142 |
var p_calendars = obj.calendars_obj = obj.calendars_obj || {
|
| 143 |
// sort : "booking_id",
|
| 144 |
// sort_type : "DESC",
|
| 145 |
// page_num : 1,
|
| 146 |
// page_items_count: 10,
|
| 147 |
// create_date : "",
|
| 148 |
// keyword : "",
|
| 149 |
// source : ""
|
| 150 |
};
|
| 151 |
|
| 152 |
/**
|
| 153 |
* Check if calendar for specific booking resource defined :: true | false
|
| 154 |
*
|
| 155 |
* @param {string|int} resource_id
|
| 156 |
* @returns {boolean}
|
| 157 |
*/
|
| 158 |
obj.calendar__is_defined = function ( resource_id ) {
|
| 159 |
|
| 160 |
return ('undefined' !== typeof( p_calendars[ 'calendar_' + resource_id ] ) );
|
| 161 |
};
|
| 162 |
|
| 163 |
/**
|
| 164 |
* Create Calendar initializing
|
| 165 |
*
|
| 166 |
* @param {string|int} resource_id
|
| 167 |
*/
|
| 168 |
obj.calendar__init = function ( resource_id ) {
|
| 169 |
|
| 170 |
p_calendars[ 'calendar_' + resource_id ] = {};
|
| 171 |
p_calendars[ 'calendar_' + resource_id ][ 'id' ] = resource_id;
|
| 172 |
p_calendars[ 'calendar_' + resource_id ][ 'pending_days_selectable' ] = false;
|
| 173 |
|
| 174 |
};
|
| 175 |
|
| 176 |
/**
|
| 177 |
* Check if the type of this property is INT
|
| 178 |
* @param property_name
|
| 179 |
* @returns {boolean}
|
| 180 |
*/
|
| 181 |
obj.calendar__is_prop_int = function ( property_name ) { // FixIn: 9.9.0.29.
|
| 182 |
|
| 183 |
var p_calendar_int_properties = ['dynamic__days_min', 'dynamic__days_max', 'fixed__days_num'];
|
| 184 |
|
| 185 |
var is_include = p_calendar_int_properties.includes( property_name );
|
| 186 |
|
| 187 |
return is_include;
|
| 188 |
};
|
| 189 |
|
| 190 |
|
| 191 |
/**
|
| 192 |
* Set params for all calendars
|
| 193 |
*
|
| 194 |
* @param {object} calendars_obj Object { calendar_1: {} }
|
| 195 |
* calendar_3: {}, ... }
|
| 196 |
*/
|
| 197 |
obj.calendars_all__set = function ( calendars_obj ) {
|
| 198 |
p_calendars = calendars_obj;
|
| 199 |
};
|
| 200 |
|
| 201 |
/**
|
| 202 |
* Get bookings in all calendars
|
| 203 |
*
|
| 204 |
* @returns {object|{}}
|
| 205 |
*/
|
| 206 |
obj.calendars_all__get = function () {
|
| 207 |
return p_calendars;
|
| 208 |
};
|
| 209 |
|
| 210 |
/**
|
| 211 |
* Get calendar object :: { id: 1, … }
|
| 212 |
*
|
| 213 |
* @param {string|int} resource_id '2'
|
| 214 |
* @returns {object|boolean} { id: 2 ,… }
|
| 215 |
*/
|
| 216 |
obj.calendar__get_parameters = function ( resource_id ) {
|
| 217 |
|
| 218 |
if ( obj.calendar__is_defined( resource_id ) ){
|
| 219 |
|
| 220 |
return p_calendars[ 'calendar_' + resource_id ];
|
| 221 |
} else {
|
| 222 |
return false;
|
| 223 |
}
|
| 224 |
};
|
| 225 |
|
| 226 |
/**
|
| 227 |
* Set calendar object :: { dates: Object { "2023-07-21": {…}, "2023-07-22": {…}, "2023-07-23": {…}, … }
|
| 228 |
*
|
| 229 |
* if calendar object not defined, then it's will be defined and ID set
|
| 230 |
* if calendar exist, then system set as new or overwrite only properties from calendar_property_obj parameter, but other properties will be existed and not overwrite, like 'id'
|
| 231 |
*
|
| 232 |
* @param {string|int} resource_id '2'
|
| 233 |
* @param {object} calendar_property_obj { dates: Object { "2023-07-21": {…}, "2023-07-22": {…}, "2023-07-23": {…}, … } }
|
| 234 |
* @param {boolean} is_complete_overwrite if 'true' (default: 'false'), then only overwrite or add new properties in calendar_property_obj
|
| 235 |
* @returns {*}
|
| 236 |
*
|
| 237 |
* Examples:
|
| 238 |
*
|
| 239 |
* Common usage in PHP:
|
| 240 |
* echo " _wpbc.calendar__set( " .intval( $resource_id ) . ", { 'dates': " . wp_json_encode( $availability_per_days_arr ) . " } );";
|
| 241 |
*/
|
| 242 |
obj.calendar__set_parameters = function ( resource_id, calendar_property_obj, is_complete_overwrite = false ) {
|
| 243 |
|
| 244 |
if ( (!obj.calendar__is_defined( resource_id )) || (true === is_complete_overwrite) ){
|
| 245 |
obj.calendar__init( resource_id );
|
| 246 |
}
|
| 247 |
|
| 248 |
for ( var prop_name in calendar_property_obj ){
|
| 249 |
|
| 250 |
p_calendars[ 'calendar_' + resource_id ][ prop_name ] = calendar_property_obj[ prop_name ];
|
| 251 |
}
|
| 252 |
|
| 253 |
return p_calendars[ 'calendar_' + resource_id ];
|
| 254 |
};
|
| 255 |
|
| 256 |
/**
|
| 257 |
* Set property to calendar
|
| 258 |
* @param resource_id "1"
|
| 259 |
* @param prop_name name of property
|
| 260 |
* @param prop_value value of property
|
| 261 |
* @returns {*} calendar object
|
| 262 |
*/
|
| 263 |
obj.calendar__set_param_value = function ( resource_id, prop_name, prop_value ) {
|
| 264 |
|
| 265 |
if ( (!obj.calendar__is_defined( resource_id )) ){
|
| 266 |
obj.calendar__init( resource_id );
|
| 267 |
}
|
| 268 |
|
| 269 |
p_calendars[ 'calendar_' + resource_id ][ prop_name ] = prop_value;
|
| 270 |
|
| 271 |
return p_calendars[ 'calendar_' + resource_id ];
|
| 272 |
};
|
| 273 |
|
| 274 |
/**
|
| 275 |
* Get calendar property value :: mixed | null
|
| 276 |
*
|
| 277 |
* @param {string|int} resource_id '1'
|
| 278 |
* @param {string} prop_name 'selection_mode'
|
| 279 |
* @returns {*|null} mixed | null
|
| 280 |
*/
|
| 281 |
obj.calendar__get_param_value = function( resource_id, prop_name ){
|
| 282 |
|
| 283 |
if (
|
| 284 |
( obj.calendar__is_defined( resource_id ) )
|
| 285 |
&& ( 'undefined' !== typeof ( p_calendars[ 'calendar_' + resource_id ][ prop_name ] ) )
|
| 286 |
){
|
| 287 |
// FixIn: 9.9.0.29.
|
| 288 |
if ( obj.calendar__is_prop_int( prop_name ) ){
|
| 289 |
p_calendars[ 'calendar_' + resource_id ][ prop_name ] = parseInt( p_calendars[ 'calendar_' + resource_id ][ prop_name ] );
|
| 290 |
}
|
| 291 |
return p_calendars[ 'calendar_' + resource_id ][ prop_name ];
|
| 292 |
}
|
| 293 |
|
| 294 |
return null; // If some property not defined, then null;
|
| 295 |
};
|
| 296 |
// -----------------------------------------------------------------------------------------------------------------
|
| 297 |
|
| 298 |
|
| 299 |
// Bookings ----------------------------------------------------------------------------------------------------
|
| 300 |
var p_bookings = obj.bookings_obj = obj.bookings_obj || {
|
| 301 |
// calendar_1: Object {
|
| 302 |
// id: 1
|
| 303 |
// , dates: Object { "2023-07-21": {…}, "2023-07-22": {…}, "2023-07-23": {…}, …
|
| 304 |
// }
|
| 305 |
};
|
| 306 |
|
| 307 |
/**
|
| 308 |
* Check if bookings for specific booking resource defined :: true | false
|
| 309 |
*
|
| 310 |
* @param {string|int} resource_id
|
| 311 |
* @returns {boolean}
|
| 312 |
*/
|
| 313 |
obj.bookings_in_calendar__is_defined = function ( resource_id ) {
|
| 314 |
|
| 315 |
return ('undefined' !== typeof( p_bookings[ 'calendar_' + resource_id ] ) );
|
| 316 |
};
|
| 317 |
|
| 318 |
/**
|
| 319 |
* Get bookings calendar object :: { id: 1 , dates: Object { "2023-07-21": {…}, "2023-07-22": {…}, "2023-07-23": {…}, … }
|
| 320 |
*
|
| 321 |
* @param {string|int} resource_id '2'
|
| 322 |
* @returns {object|boolean} { id: 2 , dates: Object { "2023-07-21": {…}, "2023-07-22": {…}, "2023-07-23": {…}, … }
|
| 323 |
*/
|
| 324 |
obj.bookings_in_calendar__get = function( resource_id ){
|
| 325 |
|
| 326 |
if ( obj.bookings_in_calendar__is_defined( resource_id ) ){
|
| 327 |
|
| 328 |
return p_bookings[ 'calendar_' + resource_id ];
|
| 329 |
} else {
|
| 330 |
return false;
|
| 331 |
}
|
| 332 |
};
|
| 333 |
|
| 334 |
/**
|
| 335 |
* Set bookings calendar object :: { dates: Object { "2023-07-21": {…}, "2023-07-22": {…}, "2023-07-23": {…}, … }
|
| 336 |
*
|
| 337 |
* if calendar object not defined, then it's will be defined and ID set
|
| 338 |
* if calendar exist, then system set as new or overwrite only properties from calendar_obj parameter, but other properties will be existed and not overwrite, like 'id'
|
| 339 |
*
|
| 340 |
* @param {string|int} resource_id '2'
|
| 341 |
* @param {object} calendar_obj { dates: Object { "2023-07-21": {…}, "2023-07-22": {…}, "2023-07-23": {…}, … } }
|
| 342 |
* @returns {*}
|
| 343 |
*
|
| 344 |
* Examples:
|
| 345 |
*
|
| 346 |
* Common usage in PHP:
|
| 347 |
* echo " _wpbc.bookings_in_calendar__set( " .intval( $resource_id ) . ", { 'dates': " . wp_json_encode( $availability_per_days_arr ) . " } );";
|
| 348 |
*/
|
| 349 |
obj.bookings_in_calendar__set = function( resource_id, calendar_obj ){
|
| 350 |
|
| 351 |
if ( ! obj.bookings_in_calendar__is_defined( resource_id ) ){
|
| 352 |
p_bookings[ 'calendar_' + resource_id ] = {};
|
| 353 |
p_bookings[ 'calendar_' + resource_id ][ 'id' ] = resource_id;
|
| 354 |
}
|
| 355 |
|
| 356 |
for ( var prop_name in calendar_obj ){
|
| 357 |
|
| 358 |
p_bookings[ 'calendar_' + resource_id ][ prop_name ] = calendar_obj[ prop_name ];
|
| 359 |
}
|
| 360 |
|
| 361 |
return p_bookings[ 'calendar_' + resource_id ];
|
| 362 |
};
|
| 363 |
|
| 364 |
// Dates
|
| 365 |
|
| 366 |
/**
|
| 367 |
* Get bookings data for ALL Dates in calendar :: false | { "2023-07-22": {…}, "2023-07-23": {…}, … }
|
| 368 |
*
|
| 369 |
* @param {string|int} resource_id '1'
|
| 370 |
* @returns {object|boolean} false | Object {
|
| 371 |
"2023-07-24": Object { ['summary']['status_for_day']: "available", day_availability: 1, max_capacity: 1, … }
|
| 372 |
"2023-07-26": Object { ['summary']['status_for_day']: "full_day_booking", ['summary']['status_for_bookings']: "pending", day_availability: 0, … }
|
| 373 |
"2023-07-29": Object { ['summary']['status_for_day']: "resource_availability", day_availability: 0, max_capacity: 1, … }
|
| 374 |
"2023-07-30": {…}, "2023-07-31": {…}, …
|
| 375 |
}
|
| 376 |
*/
|
| 377 |
obj.bookings_in_calendar__get_dates = function( resource_id){
|
| 378 |
|
| 379 |
if (
|
| 380 |
( obj.bookings_in_calendar__is_defined( resource_id ) )
|
| 381 |
&& ( 'undefined' !== typeof ( p_bookings[ 'calendar_' + resource_id ][ 'dates' ] ) )
|
| 382 |
){
|
| 383 |
return p_bookings[ 'calendar_' + resource_id ][ 'dates' ];
|
| 384 |
}
|
| 385 |
|
| 386 |
return false; // If some property not defined, then false;
|
| 387 |
};
|
| 388 |
|
| 389 |
/**
|
| 390 |
* Set bookings dates in calendar object :: { "2023-07-21": {…}, "2023-07-22": {…}, "2023-07-23": {…}, … }
|
| 391 |
*
|
| 392 |
* if calendar object not defined, then it's will be defined and 'id', 'dates' set
|
| 393 |
* if calendar exist, then system add a new or overwrite only dates from dates_obj parameter,
|
| 394 |
* but other dates not from parameter dates_obj will be existed and not overwrite.
|
| 395 |
*
|
| 396 |
* @param {string|int} resource_id '2'
|
| 397 |
* @param {object} dates_obj { "2023-07-21": {…}, "2023-07-22": {…}, "2023-07-23": {…}, … }
|
| 398 |
* @param {boolean} is_complete_overwrite if false, then only overwrite or add dates from dates_obj
|
| 399 |
* @returns {*}
|
| 400 |
*
|
| 401 |
* Examples:
|
| 402 |
* _wpbc.bookings_in_calendar__set_dates( resource_id, { "2023-07-21": {…}, "2023-07-22": {…}, … } ); <- overwrite ALL dates
|
| 403 |
* _wpbc.bookings_in_calendar__set_dates( resource_id, { "2023-07-22": {…} }, false ); <- add or overwrite only "2023-07-22": {}
|
| 404 |
*
|
| 405 |
* Common usage in PHP:
|
| 406 |
* echo " _wpbc.bookings_in_calendar__set_dates( " . intval( $resource_id ) . ", " . wp_json_encode( $availability_per_days_arr ) . " ); ";
|
| 407 |
*/
|
| 408 |
obj.bookings_in_calendar__set_dates = function( resource_id, dates_obj , is_complete_overwrite = true ){
|
| 409 |
|
| 410 |
if ( !obj.bookings_in_calendar__is_defined( resource_id ) ){
|
| 411 |
obj.bookings_in_calendar__set( resource_id, { 'dates': {} } );
|
| 412 |
}
|
| 413 |
|
| 414 |
if ( 'undefined' === typeof (p_bookings[ 'calendar_' + resource_id ][ 'dates' ]) ){
|
| 415 |
p_bookings[ 'calendar_' + resource_id ][ 'dates' ] = {}
|
| 416 |
}
|
| 417 |
|
| 418 |
if (is_complete_overwrite){
|
| 419 |
|
| 420 |
// Complete overwrite all booking dates
|
| 421 |
p_bookings[ 'calendar_' + resource_id ][ 'dates' ] = dates_obj;
|
| 422 |
} else {
|
| 423 |
|
| 424 |
// Add only new or overwrite exist booking dates from parameter. Booking dates not from parameter will be without chnanges
|
| 425 |
for ( var prop_name in dates_obj ){
|
| 426 |
|
| 427 |
p_bookings[ 'calendar_' + resource_id ]['dates'][ prop_name ] = dates_obj[ prop_name ];
|
| 428 |
}
|
| 429 |
}
|
| 430 |
|
| 431 |
return p_bookings[ 'calendar_' + resource_id ];
|
| 432 |
};
|
| 433 |
|
| 434 |
|
| 435 |
/**
|
| 436 |
* Get bookings data for specific date in calendar :: false | { day_availability: 1, ... }
|
| 437 |
*
|
| 438 |
* @param {string|int} resource_id '1'
|
| 439 |
* @param {string} sql_class_day '2023-07-21'
|
| 440 |
* @returns {object|boolean} false | {
|
| 441 |
day_availability: 4
|
| 442 |
max_capacity: 4 // >= Business Large
|
| 443 |
2: Object { is_day_unavailable: false, _day_status: "available" }
|
| 444 |
10: Object { is_day_unavailable: false, _day_status: "available" } // >= Business Large ...
|
| 445 |
11: Object { is_day_unavailable: false, _day_status: "available" }
|
| 446 |
12: Object { is_day_unavailable: false, _day_status: "available" }
|
| 447 |
}
|
| 448 |
*/
|
| 449 |
obj.bookings_in_calendar__get_for_date = function( resource_id, sql_class_day ){
|
| 450 |
|
| 451 |
if (
|
| 452 |
( obj.bookings_in_calendar__is_defined( resource_id ) )
|
| 453 |
&& ( 'undefined' !== typeof ( p_bookings[ 'calendar_' + resource_id ][ 'dates' ] ) )
|
| 454 |
&& ( 'undefined' !== typeof ( p_bookings[ 'calendar_' + resource_id ][ 'dates' ][ sql_class_day ] ) )
|
| 455 |
){
|
| 456 |
return p_bookings[ 'calendar_' + resource_id ][ 'dates' ][ sql_class_day ];
|
| 457 |
}
|
| 458 |
|
| 459 |
return false; // If some property not defined, then false;
|
| 460 |
};
|
| 461 |
|
| 462 |
|
| 463 |
// Any PARAMS in bookings
|
| 464 |
|
| 465 |
/**
|
| 466 |
* Set property to booking
|
| 467 |
* @param resource_id "1"
|
| 468 |
* @param prop_name name of property
|
| 469 |
* @param prop_value value of property
|
| 470 |
* @returns {*} booking object
|
| 471 |
*/
|
| 472 |
obj.booking__set_param_value = function ( resource_id, prop_name, prop_value ) {
|
| 473 |
|
| 474 |
if ( ! obj.bookings_in_calendar__is_defined( resource_id ) ){
|
| 475 |
p_bookings[ 'calendar_' + resource_id ] = {};
|
| 476 |
p_bookings[ 'calendar_' + resource_id ][ 'id' ] = resource_id;
|
| 477 |
}
|
| 478 |
|
| 479 |
p_bookings[ 'calendar_' + resource_id ][ prop_name ] = prop_value;
|
| 480 |
|
| 481 |
return p_bookings[ 'calendar_' + resource_id ];
|
| 482 |
};
|
| 483 |
|
| 484 |
/**
|
| 485 |
* Get booking property value :: mixed | null
|
| 486 |
*
|
| 487 |
* @param {string|int} resource_id '1'
|
| 488 |
* @param {string} prop_name 'selection_mode'
|
| 489 |
* @returns {*|null} mixed | null
|
| 490 |
*/
|
| 491 |
obj.booking__get_param_value = function( resource_id, prop_name ){
|
| 492 |
|
| 493 |
if (
|
| 494 |
( obj.bookings_in_calendar__is_defined( resource_id ) )
|
| 495 |
&& ( 'undefined' !== typeof ( p_bookings[ 'calendar_' + resource_id ][ prop_name ] ) )
|
| 496 |
){
|
| 497 |
return p_bookings[ 'calendar_' + resource_id ][ prop_name ];
|
| 498 |
}
|
| 499 |
|
| 500 |
return null; // If some property not defined, then null;
|
| 501 |
};
|
| 502 |
|
| 503 |
|
| 504 |
|
| 505 |
|
| 506 |
/**
|
| 507 |
* Set bookings for all calendars
|
| 508 |
*
|
| 509 |
* @param {object} calendars_obj Object { calendar_1: { id: 1, dates: Object { "2023-07-22": {…}, "2023-07-23": {…}, "2023-07-24": {…}, … } }
|
| 510 |
* calendar_3: {}, ... }
|
| 511 |
*/
|
| 512 |
obj.bookings_in_calendars__set_all = function ( calendars_obj ) {
|
| 513 |
p_bookings = calendars_obj;
|
| 514 |
};
|
| 515 |
|
| 516 |
/**
|
| 517 |
* Get bookings in all calendars
|
| 518 |
*
|
| 519 |
* @returns {object|{}}
|
| 520 |
*/
|
| 521 |
obj.bookings_in_calendars__get_all = function () {
|
| 522 |
return p_bookings;
|
| 523 |
};
|
| 524 |
// -----------------------------------------------------------------------------------------------------------------
|
| 525 |
|
| 526 |
|
| 527 |
|
| 528 |
|
| 529 |
// Seasons ----------------------------------------------------------------------------------------------------
|
| 530 |
var p_seasons = obj.seasons_obj = obj.seasons_obj || {
|
| 531 |
// calendar_1: Object {
|
| 532 |
// id: 1
|
| 533 |
// , dates: Object { "2023-07-21": {…}, "2023-07-22": {…}, "2023-07-23": {…}, …
|
| 534 |
// }
|
| 535 |
};
|
| 536 |
|
| 537 |
/**
|
| 538 |
* Add season names for dates in calendar object :: { "2023-07-21": [ 'wpbc_season_september_2023', 'wpbc_season_september_2024' ], "2023-07-22": [...], ... }
|
| 539 |
*
|
| 540 |
*
|
| 541 |
* @param {string|int} resource_id '2'
|
| 542 |
* @param {object} dates_obj { "2023-07-21": {…}, "2023-07-22": {…}, "2023-07-23": {…}, … }
|
| 543 |
* @param {boolean} is_complete_overwrite if false, then only add dates from dates_obj
|
| 544 |
* @returns {*}
|
| 545 |
*
|
| 546 |
* Examples:
|
| 547 |
* _wpbc.seasons__set( resource_id, { "2023-07-21": [ 'wpbc_season_september_2023', 'wpbc_season_september_2024' ], "2023-07-22": [...], ... } );
|
| 548 |
*/
|
| 549 |
obj.seasons__set = function( resource_id, dates_obj , is_complete_overwrite = false ){
|
| 550 |
|
| 551 |
if ( 'undefined' === typeof (p_seasons[ 'calendar_' + resource_id ]) ){
|
| 552 |
p_seasons[ 'calendar_' + resource_id ] = {};
|
| 553 |
}
|
| 554 |
|
| 555 |
if ( is_complete_overwrite ){
|
| 556 |
|
| 557 |
// Complete overwrite all season dates
|
| 558 |
p_seasons[ 'calendar_' + resource_id ] = dates_obj;
|
| 559 |
|
| 560 |
} else {
|
| 561 |
|
| 562 |
// Add only new or overwrite exist booking dates from parameter. Booking dates not from parameter will be without chnanges
|
| 563 |
for ( var prop_name in dates_obj ){
|
| 564 |
|
| 565 |
if ( 'undefined' === typeof (p_seasons[ 'calendar_' + resource_id ][ prop_name ]) ){
|
| 566 |
p_seasons[ 'calendar_' + resource_id ][ prop_name ] = [];
|
| 567 |
}
|
| 568 |
for ( var season_name_key in dates_obj[ prop_name ] ){
|
| 569 |
p_seasons[ 'calendar_' + resource_id ][ prop_name ].push( dates_obj[ prop_name ][ season_name_key ] );
|
| 570 |
}
|
| 571 |
}
|
| 572 |
}
|
| 573 |
|
| 574 |
return p_seasons[ 'calendar_' + resource_id ];
|
| 575 |
};
|
| 576 |
|
| 577 |
|
| 578 |
/**
|
| 579 |
* Get bookings data for specific date in calendar :: [] | [ 'wpbc_season_september_2023', 'wpbc_season_september_2024' ]
|
| 580 |
*
|
| 581 |
* @param {string|int} resource_id '1'
|
| 582 |
* @param {string} sql_class_day '2023-07-21'
|
| 583 |
* @returns {object|boolean} [] | [ 'wpbc_season_september_2023', 'wpbc_season_september_2024' ]
|
| 584 |
*/
|
| 585 |
obj.seasons__get_for_date = function( resource_id, sql_class_day ){
|
| 586 |
|
| 587 |
if (
|
| 588 |
( 'undefined' !== typeof ( p_seasons[ 'calendar_' + resource_id ] ) )
|
| 589 |
&& ( 'undefined' !== typeof ( p_seasons[ 'calendar_' + resource_id ][ sql_class_day ] ) )
|
| 590 |
){
|
| 591 |
return p_seasons[ 'calendar_' + resource_id ][ sql_class_day ];
|
| 592 |
}
|
| 593 |
|
| 594 |
return []; // If not defined, then [];
|
| 595 |
};
|
| 596 |
|
| 597 |
|
| 598 |
// Other parameters ------------------------------------------------------------------------------------
|
| 599 |
var p_other = obj.other_obj = obj.other_obj || { };
|
| 600 |
|
| 601 |
obj.set_other_param = function ( param_key, param_val ) {
|
| 602 |
p_other[ param_key ] = param_val;
|
| 603 |
};
|
| 604 |
|
| 605 |
obj.get_other_param = function ( param_key ) {
|
| 606 |
return p_other[ param_key ];
|
| 607 |
};
|
| 608 |
|
| 609 |
/**
|
| 610 |
* Get all other params
|
| 611 |
*
|
| 612 |
* @returns {object|{}}
|
| 613 |
*/
|
| 614 |
obj.get_other_param__all = function () {
|
| 615 |
return p_other;
|
| 616 |
};
|
| 617 |
|
| 618 |
// Messages ------------------------------------------------------------------------------------
|
| 619 |
var p_messages = obj.messages_obj = obj.messages_obj || { };
|
| 620 |
|
| 621 |
obj.set_message = function ( param_key, param_val ) {
|
| 622 |
p_messages[ param_key ] = param_val;
|
| 623 |
};
|
| 624 |
|
| 625 |
obj.get_message = function ( param_key ) {
|
| 626 |
return p_messages[ param_key ];
|
| 627 |
};
|
| 628 |
|
| 629 |
/**
|
| 630 |
* Get all other params
|
| 631 |
*
|
| 632 |
* @returns {object|{}}
|
| 633 |
*/
|
| 634 |
obj.get_messages__all = function () {
|
| 635 |
return p_messages;
|
| 636 |
};
|
| 637 |
|
| 638 |
// -----------------------------------------------------------------------------------------------------------------
|
| 639 |
|
| 640 |
return obj;
|
| 641 |
|
| 642 |
}( _wpbc || {}, jQuery ));
|
| 643 |
|
| 644 |
window.__WPBC_DEV = true;
|
| 645 |
|
| 646 |
/**
|
| 647 |
* Extend _wpbc with new methods
|
| 648 |
*
|
| 649 |
* @type {*|{}}
|
| 650 |
* @private
|
| 651 |
*/
|
| 652 |
_wpbc = (function (obj, $) {
|
| 653 |
|
| 654 |
/**
|
| 655 |
* Dev logger (no-op unless window.__WPBC_DEV = true)
|
| 656 |
*
|
| 657 |
* @type {*|{warn: (function(*, *, *): void), error: (function(*, *, *): void), once: obj.dev.once, try: ((function(*, *, *): (*|undefined))|*)}}
|
| 658 |
*/
|
| 659 |
obj.dev = obj.dev || (() => {
|
| 660 |
const seen = new Set();
|
| 661 |
const enabled = () => !!window.__WPBC_DEV;
|
| 662 |
|
| 663 |
function out(level, code, msg, extra) {
|
| 664 |
if ( !enabled() ) return;
|
| 665 |
try {
|
| 666 |
(console[level] || console.warn)( `[WPBC][${code}] ${msg}`, extra ?? '' );
|
| 667 |
} catch {
|
| 668 |
}
|
| 669 |
}
|
| 670 |
|
| 671 |
return {
|
| 672 |
log : (code, msg, extra) => out('log', code, msg, extra),
|
| 673 |
debug: (code, msg, extra) => out('debug', code, msg, extra),
|
| 674 |
warn : (code, msg, extra) => out( 'warn', code, msg, extra ),
|
| 675 |
error: (code, errOrMsg, extra) =>
|
| 676 |
out( 'error', code,
|
| 677 |
errOrMsg instanceof Error ? errOrMsg.message : String( errOrMsg ),
|
| 678 |
errOrMsg instanceof Error ? errOrMsg : extra ),
|
| 679 |
once : (code, msg, extra) => {
|
| 680 |
if ( !enabled() ) return;
|
| 681 |
const key = `${code}|${msg}`;
|
| 682 |
if ( seen.has( key ) ) return;
|
| 683 |
seen.add( key );
|
| 684 |
out( 'error', code, msg, extra );
|
| 685 |
},
|
| 686 |
try : (code, fn, extra) => {
|
| 687 |
try {
|
| 688 |
return fn();
|
| 689 |
} catch ( e ) {
|
| 690 |
out( 'error', code, e, extra );
|
| 691 |
}
|
| 692 |
}
|
| 693 |
};
|
| 694 |
})();
|
| 695 |
|
| 696 |
// Optional: global traps in dev.
|
| 697 |
if ( window.__WPBC_DEV ) {
|
| 698 |
window.addEventListener( 'error', (e) => {
|
| 699 |
try { _wpbc?.dev?.error( 'GLOBAL-ERROR', e?.error || e?.message, e ); } catch ( _ ) {}
|
| 700 |
} );
|
| 701 |
window.addEventListener( 'unhandledrejection', (e) => {
|
| 702 |
try { _wpbc?.dev?.error( 'GLOBAL-REJECTION', e?.reason ); } catch ( _ ) {}
|
| 703 |
} );
|
| 704 |
}
|
| 705 |
|
| 706 |
return obj;
|
| 707 |
}( _wpbc || {}, jQuery ));
|
| 708 |
|
| 709 |
/**
|
| 710 |
* Extend _wpbc with new methods // FixIn: 9.8.6.2.
|
| 711 |
*
|
| 712 |
* @type {*|{}}
|
| 713 |
* @private
|
| 714 |
*/
|
| 715 |
_wpbc = (function ( obj, $) {
|
| 716 |
|
| 717 |
// Load Balancer -----------------------------------------------------------------------------------------------
|
| 718 |
|
| 719 |
var p_balancer = obj.balancer_obj = obj.balancer_obj || {
|
| 720 |
'max_threads': 2,
|
| 721 |
'in_process' : [],
|
| 722 |
'wait' : []
|
| 723 |
};
|
| 724 |
|
| 725 |
/**
|
| 726 |
* Set max parallel request to load
|
| 727 |
*
|
| 728 |
* @param max_threads
|
| 729 |
*/
|
| 730 |
obj.balancer__set_max_threads = function ( max_threads ){
|
| 731 |
|
| 732 |
p_balancer[ 'max_threads' ] = max_threads;
|
| 733 |
};
|
| 734 |
|
| 735 |
/**
|
| 736 |
* Check if balancer for specific booking resource defined :: true | false
|
| 737 |
*
|
| 738 |
* @param {string|int} resource_id
|
| 739 |
* @returns {boolean}
|
| 740 |
*/
|
| 741 |
obj.balancer__is_defined = function ( resource_id ) {
|
| 742 |
|
| 743 |
return ('undefined' !== typeof( p_balancer[ 'balancer_' + resource_id ] ) );
|
| 744 |
};
|
| 745 |
|
| 746 |
|
| 747 |
/**
|
| 748 |
* Create balancer initializing
|
| 749 |
*
|
| 750 |
* @param {string|int} resource_id
|
| 751 |
*/
|
| 752 |
obj.balancer__init = function ( resource_id, function_name , params ={}) {
|
| 753 |
|
| 754 |
var balance_obj = {};
|
| 755 |
balance_obj[ 'resource_id' ] = resource_id;
|
| 756 |
balance_obj[ 'priority' ] = 1;
|
| 757 |
balance_obj[ 'function_name' ] = function_name;
|
| 758 |
balance_obj[ 'params' ] = wpbc_clone_obj( params );
|
| 759 |
|
| 760 |
|
| 761 |
if ( obj.balancer__is_already_run( resource_id, function_name ) ){
|
| 762 |
return 'run';
|
| 763 |
}
|
| 764 |
if ( obj.balancer__is_already_wait( resource_id, function_name ) ){
|
| 765 |
return 'wait';
|
| 766 |
}
|
| 767 |
|
| 768 |
|
| 769 |
if ( obj.balancer__can_i_run() ){
|
| 770 |
obj.balancer__add_to__run( balance_obj );
|
| 771 |
return 'run';
|
| 772 |
} else {
|
| 773 |
obj.balancer__add_to__wait( balance_obj );
|
| 774 |
return 'wait';
|
| 775 |
}
|
| 776 |
};
|
| 777 |
|
| 778 |
/**
|
| 779 |
* Can I Run ?
|
| 780 |
* @returns {boolean}
|
| 781 |
*/
|
| 782 |
obj.balancer__can_i_run = function (){
|
| 783 |
return ( p_balancer[ 'in_process' ].length < p_balancer[ 'max_threads' ] );
|
| 784 |
}
|
| 785 |
|
| 786 |
/**
|
| 787 |
* Add to WAIT
|
| 788 |
* @param balance_obj
|
| 789 |
*/
|
| 790 |
obj.balancer__add_to__wait = function ( balance_obj ) {
|
| 791 |
p_balancer['wait'].push( balance_obj );
|
| 792 |
}
|
| 793 |
|
| 794 |
/**
|
| 795 |
* Remove from Wait
|
| 796 |
*
|
| 797 |
* @param resource_id
|
| 798 |
* @param function_name
|
| 799 |
* @returns {*|boolean}
|
| 800 |
*/
|
| 801 |
obj.balancer__remove_from__wait_list = function ( resource_id, function_name ){
|
| 802 |
|
| 803 |
var removed_el = false;
|
| 804 |
|
| 805 |
if ( p_balancer[ 'wait' ].length ){ // FixIn: 9.8.10.1.
|
| 806 |
for ( var i in p_balancer[ 'wait' ] ){
|
| 807 |
if (
|
| 808 |
(resource_id === p_balancer[ 'wait' ][ i ][ 'resource_id' ])
|
| 809 |
&& (function_name === p_balancer[ 'wait' ][ i ][ 'function_name' ])
|
| 810 |
){
|
| 811 |
removed_el = p_balancer[ 'wait' ].splice( i, 1 );
|
| 812 |
removed_el = removed_el.pop();
|
| 813 |
p_balancer[ 'wait' ] = p_balancer[ 'wait' ].filter( function ( v ){
|
| 814 |
return v;
|
| 815 |
} ); // Reindex array
|
| 816 |
return removed_el;
|
| 817 |
}
|
| 818 |
}
|
| 819 |
}
|
| 820 |
return removed_el;
|
| 821 |
}
|
| 822 |
|
| 823 |
/**
|
| 824 |
* Is already WAIT
|
| 825 |
*
|
| 826 |
* @param resource_id
|
| 827 |
* @param function_name
|
| 828 |
* @returns {boolean}
|
| 829 |
*/
|
| 830 |
obj.balancer__is_already_wait = function ( resource_id, function_name ){
|
| 831 |
|
| 832 |
if ( p_balancer[ 'wait' ].length ){ // FixIn: 9.8.10.1.
|
| 833 |
for ( var i in p_balancer[ 'wait' ] ){
|
| 834 |
if (
|
| 835 |
(resource_id === p_balancer[ 'wait' ][ i ][ 'resource_id' ])
|
| 836 |
&& (function_name === p_balancer[ 'wait' ][ i ][ 'function_name' ])
|
| 837 |
){
|
| 838 |
return true;
|
| 839 |
}
|
| 840 |
}
|
| 841 |
}
|
| 842 |
return false;
|
| 843 |
}
|
| 844 |
|
| 845 |
|
| 846 |
/**
|
| 847 |
* Add to RUN
|
| 848 |
* @param balance_obj
|
| 849 |
*/
|
| 850 |
obj.balancer__add_to__run = function ( balance_obj ) {
|
| 851 |
p_balancer['in_process'].push( balance_obj );
|
| 852 |
}
|
| 853 |
|
| 854 |
/**
|
| 855 |
* Remove from RUN list
|
| 856 |
*
|
| 857 |
* @param resource_id
|
| 858 |
* @param function_name
|
| 859 |
* @returns {*|boolean}
|
| 860 |
*/
|
| 861 |
obj.balancer__remove_from__run_list = function ( resource_id, function_name ){
|
| 862 |
|
| 863 |
var removed_el = false;
|
| 864 |
|
| 865 |
if ( p_balancer[ 'in_process' ].length ){ // FixIn: 9.8.10.1.
|
| 866 |
for ( var i in p_balancer[ 'in_process' ] ){
|
| 867 |
if (
|
| 868 |
(resource_id === p_balancer[ 'in_process' ][ i ][ 'resource_id' ])
|
| 869 |
&& (function_name === p_balancer[ 'in_process' ][ i ][ 'function_name' ])
|
| 870 |
){
|
| 871 |
removed_el = p_balancer[ 'in_process' ].splice( i, 1 );
|
| 872 |
removed_el = removed_el.pop();
|
| 873 |
p_balancer[ 'in_process' ] = p_balancer[ 'in_process' ].filter( function ( v ){
|
| 874 |
return v;
|
| 875 |
} ); // Reindex array
|
| 876 |
return removed_el;
|
| 877 |
}
|
| 878 |
}
|
| 879 |
}
|
| 880 |
return removed_el;
|
| 881 |
}
|
| 882 |
|
| 883 |
/**
|
| 884 |
* Is already RUN
|
| 885 |
*
|
| 886 |
* @param resource_id
|
| 887 |
* @param function_name
|
| 888 |
* @returns {boolean}
|
| 889 |
*/
|
| 890 |
obj.balancer__is_already_run = function ( resource_id, function_name ){
|
| 891 |
|
| 892 |
if ( p_balancer[ 'in_process' ].length ){ // FixIn: 9.8.10.1.
|
| 893 |
for ( var i in p_balancer[ 'in_process' ] ){
|
| 894 |
if (
|
| 895 |
(resource_id === p_balancer[ 'in_process' ][ i ][ 'resource_id' ])
|
| 896 |
&& (function_name === p_balancer[ 'in_process' ][ i ][ 'function_name' ])
|
| 897 |
){
|
| 898 |
return true;
|
| 899 |
}
|
| 900 |
}
|
| 901 |
}
|
| 902 |
return false;
|
| 903 |
}
|
| 904 |
|
| 905 |
|
| 906 |
|
| 907 |
obj.balancer__run_next = function (){
|
| 908 |
|
| 909 |
// Get 1st from Wait list
|
| 910 |
var removed_el = false;
|
| 911 |
if ( p_balancer[ 'wait' ].length ){ // FixIn: 9.8.10.1.
|
| 912 |
for ( var i in p_balancer[ 'wait' ] ){
|
| 913 |
removed_el = obj.balancer__remove_from__wait_list( p_balancer[ 'wait' ][ i ][ 'resource_id' ], p_balancer[ 'wait' ][ i ][ 'function_name' ] );
|
| 914 |
break;
|
| 915 |
}
|
| 916 |
}
|
| 917 |
|
| 918 |
if ( false !== removed_el ){
|
| 919 |
|
| 920 |
// Run
|
| 921 |
obj.balancer__run( removed_el );
|
| 922 |
}
|
| 923 |
}
|
| 924 |
|
| 925 |
/**
|
| 926 |
* Run
|
| 927 |
* @param balance_obj
|
| 928 |
*/
|
| 929 |
obj.balancer__run = function ( balance_obj ){
|
| 930 |
|
| 931 |
switch ( balance_obj[ 'function_name' ] ){
|
| 932 |
|
| 933 |
case 'wpbc_calendar__load_data__ajx':
|
| 934 |
|
| 935 |
// Add to run list
|
| 936 |
obj.balancer__add_to__run( balance_obj );
|
| 937 |
|
| 938 |
wpbc_calendar__load_data__ajx( balance_obj[ 'params' ] )
|
| 939 |
break;
|
| 940 |
|
| 941 |
default:
|
| 942 |
}
|
| 943 |
}
|
| 944 |
|
| 945 |
return obj;
|
| 946 |
|
| 947 |
}( _wpbc || {}, jQuery ));
|
| 948 |
|
| 949 |
|
| 950 |
/**
|
| 951 |
* -- Help functions ----------------------------------------------------------------------------------------------
|
| 952 |
*/
|
| 953 |
|
| 954 |
function wpbc_balancer__is_wait( params, function_name ){
|
| 955 |
//console.log('::wpbc_balancer__is_wait',params , function_name );
|
| 956 |
if ( 'undefined' !== typeof (params[ 'resource_id' ]) ){
|
| 957 |
|
| 958 |
var balancer_status = _wpbc.balancer__init( params[ 'resource_id' ], function_name, params );
|
| 959 |
|
| 960 |
return ( 'wait' === balancer_status );
|
| 961 |
}
|
| 962 |
|
| 963 |
return false;
|
| 964 |
}
|
| 965 |
|
| 966 |
|
| 967 |
function wpbc_balancer__completed( resource_id , function_name ){
|
| 968 |
//console.log('::wpbc_balancer__completed',resource_id , function_name );
|
| 969 |
_wpbc.balancer__remove_from__run_list( resource_id, function_name );
|
| 970 |
_wpbc.balancer__run_next();
|
| 971 |
} |
| 972 |
/**
|
| 973 |
* =====================================================================================================================
|
| 974 |
* includes/__js/cal/wpbc_cal.js
|
| 975 |
* =====================================================================================================================
|
| 976 |
*/
|
| 977 |
|
| 978 |
/**
|
| 979 |
* Order or child booking resources saved here: _wpbc.booking__get_param_value( resource_id,
|
| 980 |
* 'resources_id_arr__in_dates' ) [2,10,12,11]
|
| 981 |
*/
|
| 982 |
|
| 983 |
/**
|
| 984 |
* How to check booked times on specific date: ?
|
| 985 |
*
|
| 986 |
_wpbc.bookings_in_calendar__get_for_date(2,'2023-08-21');
|
| 987 |
|
| 988 |
console.log(
|
| 989 |
_wpbc.bookings_in_calendar__get_for_date(2,'2023-08-21')[2].booked_time_slots.merged_seconds,
|
| 990 |
_wpbc.bookings_in_calendar__get_for_date(2,'2023-08-21')[10].booked_time_slots.merged_seconds,
|
| 991 |
_wpbc.bookings_in_calendar__get_for_date(2,'2023-08-21')[11].booked_time_slots.merged_seconds,
|
| 992 |
_wpbc.bookings_in_calendar__get_for_date(2,'2023-08-21')[12].booked_time_slots.merged_seconds
|
| 993 |
);
|
| 994 |
* OR
|
| 995 |
console.log(
|
| 996 |
_wpbc.bookings_in_calendar__get_for_date(2,'2023-08-21')[2].booked_time_slots.merged_readable,
|
| 997 |
_wpbc.bookings_in_calendar__get_for_date(2,'2023-08-21')[10].booked_time_slots.merged_readable,
|
| 998 |
_wpbc.bookings_in_calendar__get_for_date(2,'2023-08-21')[11].booked_time_slots.merged_readable,
|
| 999 |
_wpbc.bookings_in_calendar__get_for_date(2,'2023-08-21')[12].booked_time_slots.merged_readable
|
| 1000 |
);
|
| 1001 |
*
|
| 1002 |
*/
|
| 1003 |
|
| 1004 |
/**
|
| 1005 |
* Days selection:
|
| 1006 |
* wpbc_calendar__unselect_all_dates( resource_id );
|
| 1007 |
*
|
| 1008 |
* var resource_id = 1;
|
| 1009 |
* Example 1: var num_selected_days = wpbc_auto_select_dates_in_calendar( resource_id, '2024-05-15',
|
| 1010 |
* '2024-05-25' ); Example 2: var num_selected_days = wpbc_auto_select_dates_in_calendar( resource_id,
|
| 1011 |
* ['2024-05-09','2024-05-19','2024-05-25'] );
|
| 1012 |
*
|
| 1013 |
*/
|
| 1014 |
|
| 1015 |
|
| 1016 |
/**
|
| 1017 |
* C A L E N D A R ---------------------------------------------------------------------------------------------------
|
| 1018 |
*/
|
| 1019 |
|
| 1020 |
|
| 1021 |
/**
|
| 1022 |
* Show WPBC Calendar
|
| 1023 |
*
|
| 1024 |
* @param resource_id - resource ID
|
| 1025 |
* @returns {boolean}
|
| 1026 |
*/
|
| 1027 |
function wpbc_calendar_show( resource_id ){
|
| 1028 |
|
| 1029 |
// If no calendar HTML tag, then exit
|
| 1030 |
if ( 0 === jQuery( '#calendar_booking' + resource_id ).length ){ return false; }
|
| 1031 |
|
| 1032 |
// If the calendar with the same Booking resource is activated already, then exit. But in Elementor the class can be stale, so verify instance.
|
| 1033 |
if ( jQuery( '#calendar_booking' + resource_id ).hasClass( 'hasDatepick' ) ) {
|
| 1034 |
|
| 1035 |
var existing_inst = null;
|
| 1036 |
|
| 1037 |
try {
|
| 1038 |
existing_inst = jQuery.datepick._getInst( jQuery( '#calendar_booking' + resource_id ).get( 0 ) );
|
| 1039 |
} catch ( e ) {
|
| 1040 |
existing_inst = null;
|
| 1041 |
}
|
| 1042 |
|
| 1043 |
if ( existing_inst ) {
|
| 1044 |
return false;
|
| 1045 |
}
|
| 1046 |
|
| 1047 |
// Stale marker: remove and continue with init.
|
| 1048 |
jQuery( '#calendar_booking' + resource_id ).removeClass( 'hasDatepick' );
|
| 1049 |
}
|
| 1050 |
|
| 1051 |
wpbc_range_selection__prepare_guidance( resource_id );
|
| 1052 |
|
| 1053 |
|
| 1054 |
|
| 1055 |
// -----------------------------------------------------------------------------------------------------------------
|
| 1056 |
// Days selection
|
| 1057 |
// -----------------------------------------------------------------------------------------------------------------
|
| 1058 |
var local__is_range_select = false;
|
| 1059 |
var local__multi_days_select_num = 365; // multiple | fixed
|
| 1060 |
if ( 'dynamic' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ) ){
|
| 1061 |
local__is_range_select = true;
|
| 1062 |
local__multi_days_select_num = 0;
|
| 1063 |
}
|
| 1064 |
if ( 'single' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ) ){
|
| 1065 |
local__multi_days_select_num = 0;
|
| 1066 |
}
|
| 1067 |
|
| 1068 |
// -----------------------------------------------------------------------------------------------------------------
|
| 1069 |
// Min - Max days to scroll/show
|
| 1070 |
// -----------------------------------------------------------------------------------------------------------------
|
| 1071 |
var local__min_date = 0;
|
| 1072 |
local__min_date = new Date( _wpbc.get_other_param( 'today_arr' )[ 0 ], (parseInt( _wpbc.get_other_param( 'today_arr' )[ 1 ] ) - 1), _wpbc.get_other_param( 'today_arr' )[ 2 ], 0, 0, 0 ); // FixIn: 9.9.0.17.
|
| 1073 |
//console.log( local__min_date );
|
| 1074 |
var local__max_date = _wpbc.calendar__get_param_value( resource_id, 'booking_max_monthes_in_calendar' );
|
| 1075 |
//local__max_date = new Date(2024, 5, 28); It is here issue of not selectable dates, but some dates showing in calendar as available, but we can not select it.
|
| 1076 |
|
| 1077 |
//// Define last day in calendar (as a last day of month (and not date, which is related to actual 'Today' date).
|
| 1078 |
//// E.g. if today is 2023-09-25, and we set 'Number of months to scroll' as 5 months, then last day will be 2024-02-29 and not the 2024-02-25.
|
| 1079 |
// var cal_last_day_in_month = jQuery.datepick._determineDate( null, local__max_date, new Date() );
|
| 1080 |
// cal_last_day_in_month = new Date( cal_last_day_in_month.getFullYear(), cal_last_day_in_month.getMonth() + 1, 0 );
|
| 1081 |
// local__max_date = cal_last_day_in_month; // FixIn: 10.0.0.26.
|
| 1082 |
|
| 1083 |
// Get start / end dates from the Booking Calendar shortcode. Example: [booking calendar_dates_start='2026-01-01' calendar_dates_end='2026-12-31' resource_id=1] // FixIn: 10.13.1.4.
|
| 1084 |
if ( false !== wpbc_calendar__get_dates_start( resource_id ) ) {
|
| 1085 |
local__min_date = wpbc_calendar__get_dates_start( resource_id ); // E.g. - local__min_date = new Date( 2025, 0, 1 );
|
| 1086 |
}
|
| 1087 |
if ( false !== wpbc_calendar__get_dates_end( resource_id ) ) {
|
| 1088 |
local__max_date = wpbc_calendar__get_dates_end( resource_id ); // E.g. - local__max_date = new Date( 2025, 11, 31 );
|
| 1089 |
}
|
| 1090 |
|
| 1091 |
// In case we edit booking in past or have specific parameter in URL.
|
| 1092 |
var wpbc_edit_booking_hash = _wpbc.get_other_param( 'this_page_booking_hash' );
|
| 1093 |
var wpbc_is_edit_booking_context = ( 'undefined' !== typeof wpbc_edit_booking_hash ) && ( '' !== wpbc_edit_booking_hash );
|
| 1094 |
var wpbc_allow_past_context = _wpbc.get_other_param( 'this_page_allow_past' );
|
| 1095 |
var wpbc_is_allow_past_context = ( '1' === String( wpbc_allow_past_context ) ) || ( 1 === wpbc_allow_past_context ) || ( true === wpbc_allow_past_context );
|
| 1096 |
var wpbc_allow_past_date_arr = _wpbc.get_other_param( 'this_page_allow_past_arr' );
|
| 1097 |
var wpbc_is_add_booking_admin_page = ( location.href.indexOf( 'page=wpbc' ) != -1 ) && ( location.href.indexOf( 'tab=add-booking' ) != -1 );
|
| 1098 |
if ( ( wpbc_is_add_booking_admin_page || wpbc_is_edit_booking_context || wpbc_is_allow_past_context )
|
| 1099 |
&& (
|
| 1100 |
wpbc_is_edit_booking_context
|
| 1101 |
|| wpbc_is_allow_past_context
|
| 1102 |
|| ( location.href.indexOf('booking_hash') != -1 ) // Comment this line for ability to add booking in past days at Booking > Add booking page.
|
| 1103 |
|| ( location.href.indexOf('allow_past') != -1 ) // FixIn: 10.7.1.2.
|
| 1104 |
)
|
| 1105 |
){
|
| 1106 |
// local__min_date = null;
|
| 1107 |
// FixIn: 10.14.1.4.
|
| 1108 |
var wpbc_min_date_arr = ( wpbc_is_allow_past_context && wpbc_allow_past_date_arr && ( 5 <= wpbc_allow_past_date_arr.length ) ) ? wpbc_allow_past_date_arr : _wpbc.get_other_param( 'time_local_arr' );
|
| 1109 |
local__min_date = new Date( wpbc_min_date_arr[0], ( parseInt( wpbc_min_date_arr[1] ) - 1), wpbc_min_date_arr[2], wpbc_min_date_arr[3], wpbc_min_date_arr[4], 0 );
|
| 1110 |
local__max_date = null;
|
| 1111 |
}
|
| 1112 |
|
| 1113 |
var local__start_weekday = _wpbc.calendar__get_param_value( resource_id, 'booking_start_day_weeek' );
|
| 1114 |
var local__number_of_months = parseInt( _wpbc.calendar__get_param_value( resource_id, 'calendar_number_of_months' ) );
|
| 1115 |
|
| 1116 |
jQuery( '#calendar_booking' + resource_id ).text( '' ); // Remove all HTML in calendar tag
|
| 1117 |
// -----------------------------------------------------------------------------------------------------------------
|
| 1118 |
// Show calendar
|
| 1119 |
// -----------------------------------------------------------------------------------------------------------------
|
| 1120 |
jQuery('#calendar_booking'+ resource_id).datepick(
|
| 1121 |
{ |
| 1122 |
beforeSelectDay: function ( js_date, inst ) { |
| 1123 |
return 'function' === typeof wpbc__calendar__before_select_days__bs |
| 1124 |
? wpbc__calendar__before_select_days__bs( js_date, resource_id, inst ) : true; |
| 1125 |
}, |
| 1126 |
beforeShowDay: function ( js_date ){ |
| 1127 |
return wpbc__calendar__apply_css_to_days( js_date, {'resource_id': resource_id}, this );
|
| 1128 |
},
|
| 1129 |
onSelect: function ( string_dates, js_dates_arr ){ /**
|
| 1130 |
* string_dates = '23.08.2023 - 26.08.2023'
|
| 1131 |
* | '23.08.2023 - 23.08.2023' |
|
| 1132 |
* '19.09.2023, 24.08.2023, 30.09.2023'
|
| 1133 |
* js_dates_arr = range: [ Date (Aug 23 2023),
|
| 1134 |
* Date (Aug 25 2023)] | multiple: [
|
| 1135 |
* Date(Oct 24 2023), Date(Oct 20 2023), Date(Oct
|
| 1136 |
* 16 2023) ]
|
| 1137 |
*/
|
| 1138 |
return wpbc__calendar__on_select_days( string_dates, {'resource_id': resource_id}, this );
|
| 1139 |
},
|
| 1140 |
onHover: function ( string_date, js_date ){
|
| 1141 |
return wpbc__calendar__on_hover_days( string_date, js_date, {'resource_id': resource_id}, this );
|
| 1142 |
},
|
| 1143 |
onChangeMonthYear: function ( year, real_month, js_date__1st_day_in_month ){ },
|
| 1144 |
showOn : 'both',
|
| 1145 |
numberOfMonths: local__number_of_months,
|
| 1146 |
stepMonths : 1,
|
| 1147 |
// prevText : '«',
|
| 1148 |
// nextText : '»',
|
| 1149 |
prevText : '‹',
|
| 1150 |
nextText : '›',
|
| 1151 |
dateFormat : 'dd.mm.yy',
|
| 1152 |
changeMonth : false,
|
| 1153 |
changeYear : false,
|
| 1154 |
minDate : local__min_date,
|
| 1155 |
maxDate : local__max_date, // '1Y',
|
| 1156 |
// minDate: new Date(2020, 2, 1), maxDate: new Date(2020, 9, 31), // Ability to set any start and end date in calendar
|
| 1157 |
showStatus : false,
|
| 1158 |
multiSeparator : ', ',
|
| 1159 |
closeAtTop : false,
|
| 1160 |
firstDay : local__start_weekday,
|
| 1161 |
gotoCurrent : false,
|
| 1162 |
hideIfNoPrevNext: true,
|
| 1163 |
multiSelect : local__multi_days_select_num,
|
| 1164 |
rangeSelect : local__is_range_select,
|
| 1165 |
// showWeeks: true,
|
| 1166 |
useThemeRoller: false
|
| 1167 |
}
|
| 1168 |
);
|
| 1169 |
|
| 1170 |
|
| 1171 |
|
| 1172 |
// -----------------------------------------------------------------------------------------------------------------
|
| 1173 |
// Clear today date highlighting
|
| 1174 |
// -----------------------------------------------------------------------------------------------------------------
|
| 1175 |
setTimeout( function (){ wpbc_calendars__clear_days_highlighting( resource_id ); }, 500 ); // FixIn: 7.1.2.8.
|
| 1176 |
|
| 1177 |
// -----------------------------------------------------------------------------------------------------------------
|
| 1178 |
// Scroll calendar to specific month
|
| 1179 |
// -----------------------------------------------------------------------------------------------------------------
|
| 1180 |
var start_bk_month = _wpbc.calendar__get_param_value( resource_id, 'calendar_scroll_to' );
|
| 1181 |
if ( false !== start_bk_month ){
|
| 1182 |
wpbc_calendar__scroll_to( resource_id, start_bk_month[ 0 ], start_bk_month[ 1 ] );
|
| 1183 |
}
|
| 1184 |
}
|
| 1185 |
|
| 1186 |
|
| 1187 |
/**
|
| 1188 |
* Get booking statuses as array from the structured summary field, with fallback to the legacy string field.
|
| 1189 |
*
|
| 1190 |
* @param date_bookings_obj
|
| 1191 |
* @returns {[]}
|
| 1192 |
*/
|
| 1193 |
function wpbc_get_booking_statuses__as_arr( date_bookings_obj ){
|
| 1194 |
|
| 1195 |
if (
|
| 1196 |
( ! date_bookings_obj )
|
| 1197 |
|| ( 'undefined' === typeof (date_bookings_obj[ 'summary' ]) )
|
| 1198 |
){
|
| 1199 |
return [];
|
| 1200 |
}
|
| 1201 |
|
| 1202 |
if ( Array.isArray( date_bookings_obj[ 'summary' ][ 'status_for_bookings_arr' ] ) ){
|
| 1203 |
return date_bookings_obj[ 'summary' ][ 'status_for_bookings_arr' ].filter( function ( booking_status ){
|
| 1204 |
return '' !== booking_status;
|
| 1205 |
} );
|
| 1206 |
}
|
| 1207 |
|
| 1208 |
if ( ! date_bookings_obj[ 'summary' ][ 'status_for_bookings' ] ){
|
| 1209 |
return [];
|
| 1210 |
}
|
| 1211 |
|
| 1212 |
return date_bookings_obj[ 'summary' ][ 'status_for_bookings' ].toString().trim().split( /\s+/ ).filter( function ( booking_status ){
|
| 1213 |
return '' !== booking_status;
|
| 1214 |
} );
|
| 1215 |
}
|
| 1216 |
|
| 1217 |
|
| 1218 |
/**
|
| 1219 |
* Check exact booking status in statuses array.
|
| 1220 |
*
|
| 1221 |
* @param {[]} booking_statuses_arr
|
| 1222 |
* @param {string} booking_status
|
| 1223 |
* @returns {boolean}
|
| 1224 |
*/
|
| 1225 |
function wpbc_booking_statuses__has( booking_statuses_arr, booking_status ){
|
| 1226 |
return booking_statuses_arr.indexOf( booking_status ) > -1;
|
| 1227 |
}
|
| 1228 |
|
| 1229 |
|
| 1230 |
/**
|
| 1231 |
* Check booking status part, e.g. "pending" in "approved_pending".
|
| 1232 |
*
|
| 1233 |
* @param {[]} booking_statuses_arr
|
| 1234 |
* @param {string} booking_status_part
|
| 1235 |
* @returns {boolean}
|
| 1236 |
*/
|
| 1237 |
function wpbc_booking_statuses__has_part( booking_statuses_arr, booking_status_part ){
|
| 1238 |
|
| 1239 |
for ( var i = 0; i < booking_statuses_arr.length; i++ ){
|
| 1240 |
if ( booking_statuses_arr[ i ].split( '_' ).indexOf( booking_status_part ) > -1 ){
|
| 1241 |
return true;
|
| 1242 |
}
|
| 1243 |
}
|
| 1244 |
|
| 1245 |
return false;
|
| 1246 |
} |
| 1247 |
|
| 1248 |
|
| 1249 |
/** |
| 1250 |
* Apply optional, one-way date constraints to a native availability result. |
| 1251 |
* |
| 1252 |
* Listeners receive only a new constraint object. No booking, availability, |
| 1253 |
* season, or calendar parameter objects are exposed. Core availability stays |
| 1254 |
* authoritative because the returned state can only change from selectable to |
| 1255 |
* blocked; a listener cannot reopen a natively unavailable date. |
| 1256 |
* |
| 1257 |
* Event: wpbc_calendar__apply_date_constraints |
| 1258 |
* |
| 1259 |
* Constraint object: |
| 1260 |
* { |
| 1261 |
* resource_id: resource_id, |
| 1262 |
* sql_date: sql_date, |
| 1263 |
* is_blocked: false, |
| 1264 |
* css_classes: [] |
| 1265 |
* } |
| 1266 |
* |
| 1267 |
* Listeners may set is_blocked to the boolean true and append individual, |
| 1268 |
* valid CSS class names to css_classes. Core-owned availability classes are |
| 1269 |
* ignored when supplied by listeners. |
| 1270 |
* |
| 1271 |
* @param {number|string} resource_id Booking resource ID. |
| 1272 |
* @param {string} sql_date Calendar date in YYYY-MM-DD format. |
| 1273 |
* @param {boolean} is_natively_selectable Whether core marked the date selectable. |
| 1274 |
* @param {string[]} native_css_classes Core-generated CSS classes. |
| 1275 |
* @returns {{is_selectable: boolean, css_classes: string[]}} Constrained result. |
| 1276 |
*/ |
| 1277 |
function wpbc_calendar__evaluate_date_constraints( resource_id, sql_date, is_natively_selectable, native_css_classes ) { |
| 1278 |
|
| 1279 |
var date_constraint = { |
| 1280 |
'resource_id': resource_id, |
| 1281 |
'sql_date': sql_date, |
| 1282 |
'is_blocked': false, |
| 1283 |
'css_classes': [] |
| 1284 |
}; |
| 1285 |
var result_css_classes = Array.isArray( native_css_classes ) ? native_css_classes.slice( 0 ) : []; |
| 1286 |
var constraint_class_index; |
| 1287 |
var constraint_css_class; |
| 1288 |
|
| 1289 |
jQuery( 'body' ).trigger( 'wpbc_calendar__apply_date_constraints', [ date_constraint ] ); |
| 1290 |
|
| 1291 |
if ( true === date_constraint.is_blocked ) { |
| 1292 |
for ( constraint_class_index = result_css_classes.length - 1; constraint_class_index >= 0; constraint_class_index-- ) { |
| 1293 |
if ( 'date_available' === result_css_classes[ constraint_class_index ] ) { |
| 1294 |
result_css_classes.splice( constraint_class_index, 1 ); |
| 1295 |
} |
| 1296 |
} |
| 1297 |
|
| 1298 |
if ( -1 === result_css_classes.indexOf( 'date_user_unavailable' ) ) { |
| 1299 |
result_css_classes.push( 'date_user_unavailable' ); |
| 1300 |
} |
| 1301 |
} |
| 1302 |
|
| 1303 |
if ( Array.isArray( date_constraint.css_classes ) ) { |
| 1304 |
for ( constraint_class_index = 0; constraint_class_index < date_constraint.css_classes.length; constraint_class_index++ ) { |
| 1305 |
if ( 'string' !== typeof date_constraint.css_classes[ constraint_class_index ] ) { |
| 1306 |
continue; |
| 1307 |
} |
| 1308 |
|
| 1309 |
constraint_css_class = date_constraint.css_classes[ constraint_class_index ].trim(); |
| 1310 |
if ( |
| 1311 |
'' === constraint_css_class |
| 1312 |
|| 'date_available' === constraint_css_class |
| 1313 |
|| 'date_user_unavailable' === constraint_css_class |
| 1314 |
|| ! /^-?[_a-zA-Z]+[_a-zA-Z0-9-]*$/.test( constraint_css_class ) |
| 1315 |
) { |
| 1316 |
continue; |
| 1317 |
} |
| 1318 |
|
| 1319 |
if ( -1 === result_css_classes.indexOf( constraint_css_class ) ) { |
| 1320 |
result_css_classes.push( constraint_css_class ); |
| 1321 |
} |
| 1322 |
} |
| 1323 |
} |
| 1324 |
|
| 1325 |
return { |
| 1326 |
'is_selectable': Boolean( is_natively_selectable ) && true !== date_constraint.is_blocked, |
| 1327 |
'css_classes': result_css_classes |
| 1328 |
}; |
| 1329 |
} |
| 1330 |
|
| 1331 |
|
| 1332 |
/** |
| 1333 |
* Apply CSS to calendar date cells |
| 1334 |
*
|
| 1335 |
* @param date - JavaScript Date Obj: Mon Dec 11 2023 00:00:00
|
| 1336 |
* GMT+0200 (Eastern European Standard Time)
|
| 1337 |
* @param calendar_params_arr - Calendar Settings Object: {
|
| 1338 |
* "resource_id": 4
|
| 1339 |
* }
|
| 1340 |
* @param datepick_this - this of datepick Obj
|
| 1341 |
* @returns {(*|string)[]|(boolean|string)[]} - [ {true -available | false - unavailable}, 'CSS classes for
|
| 1342 |
* calendar day cell' ]
|
| 1343 |
*/
|
| 1344 |
function wpbc__calendar__apply_css_to_days( date, calendar_params_arr, datepick_this ){
|
| 1345 |
|
| 1346 |
var today_date = new Date( _wpbc.get_other_param( 'today_arr' )[ 0 ], (parseInt( _wpbc.get_other_param( 'today_arr' )[ 1 ] ) - 1), _wpbc.get_other_param( 'today_arr' )[ 2 ], 0, 0, 0 ); // Today JS_Date_Obj.
|
| 1347 |
var class_day = wpbc__get__td_class_date( date ); // '1-9-2023'
|
| 1348 |
var sql_class_day = wpbc__get__sql_class_date( date ); // '2023-01-09'
|
| 1349 |
var resource_id = ( 'undefined' !== typeof(calendar_params_arr[ 'resource_id' ]) ) ? calendar_params_arr[ 'resource_id' ] : '1'; // '1'
|
| 1350 |
|
| 1351 |
// Get Selected dates in calendar
|
| 1352 |
var selected_dates_sql = wpbc_get__selected_dates_sql__as_arr( resource_id );
|
| 1353 |
|
| 1354 |
// Get Data --------------------------------------------------------------------------------------------------------
|
| 1355 |
var date_bookings_obj = _wpbc.bookings_in_calendar__get_for_date( resource_id, sql_class_day );
|
| 1356 |
|
| 1357 |
|
| 1358 |
// Array with CSS classes for date ---------------------------------------------------------------------------------
|
| 1359 |
var css_classes__for_date = [];
|
| 1360 |
css_classes__for_date.push( 'sql_date_' + sql_class_day ); // 'sql_date_2023-07-21'
|
| 1361 |
css_classes__for_date.push( 'cal4date-' + class_day ); // 'cal4date-7-21-2023'
|
| 1362 |
css_classes__for_date.push( 'wpbc_weekday_' + date.getDay() ); // 'wpbc_weekday_4'
|
| 1363 |
|
| 1364 |
// Define Selected Check In/Out dates in TD -----------------------------------------------------------------------
|
| 1365 |
if (
|
| 1366 |
( selected_dates_sql.length )
|
| 1367 |
//&& ( selected_dates_sql[ 0 ] !== selected_dates_sql[ (selected_dates_sql.length - 1) ] )
|
| 1368 |
){
|
| 1369 |
if ( sql_class_day === selected_dates_sql[ 0 ] ){
|
| 1370 |
css_classes__for_date.push( 'selected_check_in' );
|
| 1371 |
css_classes__for_date.push( 'selected_check_in_out' );
|
| 1372 |
}
|
| 1373 |
if ( ( selected_dates_sql.length > 1 ) && ( sql_class_day === selected_dates_sql[ (selected_dates_sql.length - 1) ] ) ) {
|
| 1374 |
css_classes__for_date.push( 'selected_check_out' );
|
| 1375 |
css_classes__for_date.push( 'selected_check_in_out' );
|
| 1376 |
}
|
| 1377 |
}
|
| 1378 |
|
| 1379 |
|
| 1380 |
var is_day_selectable = false; |
| 1381 |
var date_constraint_result; |
| 1382 |
|
| 1383 |
// If something not defined, then this date closed --------------------------------------------------------------- // FixIn: 10.12.4.6.
|
| 1384 |
if ( (false === date_bookings_obj) || ('undefined' === typeof (date_bookings_obj[resource_id])) ) { |
| 1385 |
|
| 1386 |
css_classes__for_date.push( 'date_user_unavailable' ); |
| 1387 |
date_constraint_result = wpbc_calendar__evaluate_date_constraints( resource_id, sql_class_day, is_day_selectable, css_classes__for_date ); |
| 1388 |
|
| 1389 |
return [ date_constraint_result.is_selectable, date_constraint_result.css_classes.join( ' ' ) ]; |
| 1390 |
}
|
| 1391 |
|
| 1392 |
|
| 1393 |
// -----------------------------------------------------------------------------------------------------------------
|
| 1394 |
// date_bookings_obj - Defined. Dates can be selectable.
|
| 1395 |
// -----------------------------------------------------------------------------------------------------------------
|
| 1396 |
var booking_statuses_arr = wpbc_get_booking_statuses__as_arr( date_bookings_obj );
|
| 1397 |
|
| 1398 |
// -----------------------------------------------------------------------------------------------------------------
|
| 1399 |
// Add season names to the day CSS classes -- it is required for correct work of conditional fields --------------
|
| 1400 |
var season_names_arr = _wpbc.seasons__get_for_date( resource_id, sql_class_day );
|
| 1401 |
|
| 1402 |
for ( var season_key in season_names_arr ){
|
| 1403 |
|
| 1404 |
css_classes__for_date.push( season_names_arr[ season_key ] ); // 'wpdevbk_season_september_2023'
|
| 1405 |
}
|
| 1406 |
// -----------------------------------------------------------------------------------------------------------------
|
| 1407 |
|
| 1408 |
|
| 1409 |
// Cost Rate -------------------------------------------------------------------------------------------------------
|
| 1410 |
css_classes__for_date.push( 'rate_' + date_bookings_obj[ resource_id ][ 'date_cost_rate' ].toString().replace( /[\.\s]/g, '_' ) ); // 'rate_99_00' -> 99.00
|
| 1411 |
|
| 1412 |
|
| 1413 |
if ( parseInt( date_bookings_obj[ 'day_availability' ] ) > 0 ){
|
| 1414 |
is_day_selectable = true;
|
| 1415 |
css_classes__for_date.push( 'date_available' );
|
| 1416 |
css_classes__for_date.push( 'reserved_days_count' + parseInt( date_bookings_obj[ 'max_capacity' ] - date_bookings_obj[ 'day_availability' ] ) );
|
| 1417 |
} else {
|
| 1418 |
is_day_selectable = false;
|
| 1419 |
css_classes__for_date.push( 'date_user_unavailable' );
|
| 1420 |
}
|
| 1421 |
|
| 1422 |
|
| 1423 |
switch ( date_bookings_obj[ 'summary']['status_for_day' ] ){
|
| 1424 |
|
| 1425 |
case 'available':
|
| 1426 |
break;
|
| 1427 |
|
| 1428 |
case 'time_slots_booking':
|
| 1429 |
css_classes__for_date.push( 'timespartly', 'times_clock' );
|
| 1430 |
break;
|
| 1431 |
|
| 1432 |
case 'full_day_booking':
|
| 1433 |
css_classes__for_date.push( 'full_day_booking' );
|
| 1434 |
break;
|
| 1435 |
|
| 1436 |
case 'season_filter':
|
| 1437 |
css_classes__for_date.push( 'date_user_unavailable', 'season_unavailable' );
|
| 1438 |
date_bookings_obj[ 'summary']['status_for_bookings' ] = ''; // Reset booking status color for possible old bookings on this date
|
| 1439 |
date_bookings_obj[ 'summary']['status_for_bookings_arr' ] = [];
|
| 1440 |
booking_statuses_arr = [];
|
| 1441 |
break;
|
| 1442 |
|
| 1443 |
case 'resource_availability':
|
| 1444 |
css_classes__for_date.push( 'date_user_unavailable', 'resource_unavailable' );
|
| 1445 |
date_bookings_obj[ 'summary']['status_for_bookings' ] = ''; // Reset booking status color for possible old bookings on this date
|
| 1446 |
date_bookings_obj[ 'summary']['status_for_bookings_arr' ] = [];
|
| 1447 |
booking_statuses_arr = [];
|
| 1448 |
break;
|
| 1449 |
|
| 1450 |
case 'weekday_unavailable':
|
| 1451 |
css_classes__for_date.push( 'date_user_unavailable', 'weekday_unavailable' );
|
| 1452 |
date_bookings_obj[ 'summary']['status_for_bookings' ] = ''; // Reset booking status color for possible old bookings on this date
|
| 1453 |
date_bookings_obj[ 'summary']['status_for_bookings_arr' ] = [];
|
| 1454 |
booking_statuses_arr = [];
|
| 1455 |
break;
|
| 1456 |
|
| 1457 |
case 'from_today_unavailable':
|
| 1458 |
css_classes__for_date.push( 'date_user_unavailable', 'from_today_unavailable' );
|
| 1459 |
date_bookings_obj[ 'summary']['status_for_bookings' ] = ''; // Reset booking status color for possible old bookings on this date
|
| 1460 |
date_bookings_obj[ 'summary']['status_for_bookings_arr' ] = [];
|
| 1461 |
booking_statuses_arr = [];
|
| 1462 |
break;
|
| 1463 |
|
| 1464 |
case 'limit_available_from_today':
|
| 1465 |
css_classes__for_date.push( 'date_user_unavailable', 'limit_available_from_today' );
|
| 1466 |
date_bookings_obj[ 'summary']['status_for_bookings' ] = ''; // Reset booking status color for possible old bookings on this date
|
| 1467 |
date_bookings_obj[ 'summary']['status_for_bookings_arr' ] = [];
|
| 1468 |
booking_statuses_arr = [];
|
| 1469 |
break;
|
| 1470 |
|
| 1471 |
case 'change_over':
|
| 1472 |
/*
|
| 1473 |
*
|
| 1474 |
// check_out_time_date2approve check_in_time_date2approve
|
| 1475 |
// check_out_time_date2approve check_in_time_date_approved
|
| 1476 |
// check_in_time_date2approve check_out_time_date_approved
|
| 1477 |
// check_out_time_date_approved check_in_time_date_approved
|
| 1478 |
*/
|
| 1479 |
|
| 1480 |
css_classes__for_date.push( 'timespartly', 'check_in_time', 'check_out_time' );
|
| 1481 |
// FixIn: 10.0.0.2.
|
| 1482 |
if ( wpbc_booking_statuses__has( booking_statuses_arr, 'approved_pending' ) ){
|
| 1483 |
css_classes__for_date.push( 'check_out_time_date_approved', 'check_in_time_date2approve' );
|
| 1484 |
}
|
| 1485 |
if ( wpbc_booking_statuses__has( booking_statuses_arr, 'pending_approved' ) ){
|
| 1486 |
css_classes__for_date.push( 'check_out_time_date2approve', 'check_in_time_date_approved' );
|
| 1487 |
}
|
| 1488 |
break;
|
| 1489 |
|
| 1490 |
case 'check_in':
|
| 1491 |
css_classes__for_date.push( 'timespartly', 'check_in_time' );
|
| 1492 |
|
| 1493 |
// FixIn: 9.9.0.33.
|
| 1494 |
if ( wpbc_booking_statuses__has_part( booking_statuses_arr, 'pending' ) ){
|
| 1495 |
css_classes__for_date.push( 'check_in_time_date2approve' );
|
| 1496 |
} else if ( wpbc_booking_statuses__has_part( booking_statuses_arr, 'approved' ) ){
|
| 1497 |
css_classes__for_date.push( 'check_in_time_date_approved' );
|
| 1498 |
}
|
| 1499 |
break;
|
| 1500 |
|
| 1501 |
case 'check_out':
|
| 1502 |
css_classes__for_date.push( 'timespartly', 'check_out_time' );
|
| 1503 |
|
| 1504 |
// FixIn: 9.9.0.33.
|
| 1505 |
if ( wpbc_booking_statuses__has_part( booking_statuses_arr, 'pending' ) ){
|
| 1506 |
css_classes__for_date.push( 'check_out_time_date2approve' );
|
| 1507 |
} else if ( wpbc_booking_statuses__has_part( booking_statuses_arr, 'approved' ) ){
|
| 1508 |
css_classes__for_date.push( 'check_out_time_date_approved' );
|
| 1509 |
}
|
| 1510 |
break;
|
| 1511 |
|
| 1512 |
default:
|
| 1513 |
// mixed statuses: 'change_over check_out' .... variations.... check more in function wpbc_get_availability_per_days_arr()
|
| 1514 |
date_bookings_obj[ 'summary']['status_for_day' ] = 'available';
|
| 1515 |
}
|
| 1516 |
|
| 1517 |
|
| 1518 |
|
| 1519 |
if ( 'available' != date_bookings_obj[ 'summary']['status_for_day' ] ){
|
| 1520 |
|
| 1521 |
var is_set_pending_days_selectable = _wpbc.calendar__get_param_value( resource_id, 'pending_days_selectable' ); // set pending days selectable // FixIn: 8.6.1.18.
|
| 1522 |
|
| 1523 |
if ( wpbc_booking_statuses__has( booking_statuses_arr, 'pending' ) ){
|
| 1524 |
css_classes__for_date.push( 'date2approve' );
|
| 1525 |
is_day_selectable = (is_day_selectable) ? true : is_set_pending_days_selectable;
|
| 1526 |
}
|
| 1527 |
if ( wpbc_booking_statuses__has( booking_statuses_arr, 'approved' ) ){
|
| 1528 |
css_classes__for_date.push( 'date_approved' );
|
| 1529 |
}
|
| 1530 |
if ( wpbc_booking_statuses__has( booking_statuses_arr, 'pending_pending' ) ){
|
| 1531 |
css_classes__for_date.push( 'check_out_time_date2approve', 'check_in_time_date2approve' );
|
| 1532 |
is_day_selectable = (is_day_selectable) ? true : is_set_pending_days_selectable;
|
| 1533 |
}
|
| 1534 |
if ( wpbc_booking_statuses__has( booking_statuses_arr, 'pending_approved' ) ){
|
| 1535 |
css_classes__for_date.push( 'check_out_time_date2approve', 'check_in_time_date_approved' );
|
| 1536 |
is_day_selectable = (is_day_selectable) ? true : is_set_pending_days_selectable;
|
| 1537 |
}
|
| 1538 |
if ( wpbc_booking_statuses__has( booking_statuses_arr, 'approved_pending' ) ){
|
| 1539 |
css_classes__for_date.push( 'check_out_time_date_approved', 'check_in_time_date2approve' );
|
| 1540 |
is_day_selectable = (is_day_selectable) ? true : is_set_pending_days_selectable;
|
| 1541 |
}
|
| 1542 |
if ( wpbc_booking_statuses__has( booking_statuses_arr, 'approved_approved' ) ){
|
| 1543 |
css_classes__for_date.push( 'check_out_time_date_approved', 'check_in_time_date_approved' );
|
| 1544 |
}
|
| 1545 |
}
|
| 1546 |
|
| 1547 |
date_constraint_result = wpbc_calendar__evaluate_date_constraints( resource_id, sql_class_day, is_day_selectable, css_classes__for_date ); |
| 1548 |
|
| 1549 |
return [ date_constraint_result.is_selectable, date_constraint_result.css_classes.join( ' ' ) ]; |
| 1550 |
}
|
| 1551 |
|
| 1552 |
|
| 1553 |
/**
|
| 1554 |
* Mouseover calendar date cells
|
| 1555 |
*
|
| 1556 |
* @param string_date
|
| 1557 |
* @param date - JavaScript Date Obj: Mon Dec 11 2023 00:00:00
|
| 1558 |
* GMT+0200 (Eastern European Standard Time)
|
| 1559 |
* @param calendar_params_arr - Calendar Settings Object: {
|
| 1560 |
* "resource_id": 4
|
| 1561 |
* }
|
| 1562 |
* @param datepick_this - this of datepick Obj
|
| 1563 |
* @returns {boolean}
|
| 1564 |
*/
|
| 1565 |
function wpbc__calendar__on_hover_days( string_date, date, calendar_params_arr, datepick_this ) {
|
| 1566 |
|
| 1567 |
if ( null === date ) {
|
| 1568 |
wpbc_calendars__clear_days_highlighting( ('undefined' !== typeof (calendar_params_arr[ 'resource_id' ])) ? calendar_params_arr[ 'resource_id' ] : '1' ); // FixIn: 10.5.2.4.
|
| 1569 |
return false;
|
| 1570 |
}
|
| 1571 |
|
| 1572 |
var class_day = wpbc__get__td_class_date( date ); // '1-9-2023'
|
| 1573 |
var sql_class_day = wpbc__get__sql_class_date( date ); // '2023-01-09'
|
| 1574 |
var resource_id = ( 'undefined' !== typeof(calendar_params_arr[ 'resource_id' ]) ) ? calendar_params_arr[ 'resource_id' ] : '1'; // '1'
|
| 1575 |
|
| 1576 |
// Get Data --------------------------------------------------------------------------------------------------------
|
| 1577 |
var date_booking_obj = _wpbc.bookings_in_calendar__get_for_date( resource_id, sql_class_day ); // {...}
|
| 1578 |
|
| 1579 |
if ( ! date_booking_obj ){ return false; }
|
| 1580 |
|
| 1581 |
|
| 1582 |
// T o o l t i p s -------------------------------------------------------------------------------------------------
|
| 1583 |
var tooltip_text = '';
|
| 1584 |
if ( date_booking_obj[ 'summary']['tooltip_availability' ].length > 0 ){
|
| 1585 |
tooltip_text += date_booking_obj[ 'summary']['tooltip_availability' ];
|
| 1586 |
}
|
| 1587 |
if ( date_booking_obj[ 'summary']['tooltip_day_cost' ].length > 0 ){
|
| 1588 |
tooltip_text += date_booking_obj[ 'summary']['tooltip_day_cost' ];
|
| 1589 |
}
|
| 1590 |
if ( date_booking_obj[ 'summary']['tooltip_times' ].length > 0 ){
|
| 1591 |
tooltip_text += date_booking_obj[ 'summary']['tooltip_times' ];
|
| 1592 |
}
|
| 1593 |
if ( date_booking_obj[ 'summary']['tooltip_booking_details' ].length > 0 ){
|
| 1594 |
tooltip_text += date_booking_obj[ 'summary']['tooltip_booking_details' ];
|
| 1595 |
}
|
| 1596 |
wpbc_set_tooltip___for__calendar_date( tooltip_text, resource_id, class_day );
|
| 1597 |
|
| 1598 |
|
| 1599 |
|
| 1600 |
// U n h o v e r i n g in UNSELECTABLE_CALENDAR ------------------------------------------------------------
|
| 1601 |
var is_unselectable_calendar = ( jQuery( '#calendar_booking_unselectable' + resource_id ).length > 0); // FixIn: 8.0.1.2.
|
| 1602 |
var is_booking_form_exist = ( jQuery( '#booking_form_div' + resource_id ).length > 0 );
|
| 1603 |
var is_add_booking_modal_calendar = ( jQuery( '#calendar_booking' + resource_id ).closest( '#wpbc_modal__add_booking__section' ).length > 0 );
|
| 1604 |
var is_admin_calendar_preview = ( jQuery( '#calendar_booking' + resource_id ).closest( '[data-wpbc-admin-calendar-preview="1"]' ).length > 0 );
|
| 1605 |
|
| 1606 |
if ( ( is_unselectable_calendar ) && ( ! is_booking_form_exist ) ){
|
| 1607 |
|
| 1608 |
/**
|
| 1609 |
* Un Hover all dates in calendar (without the booking form), if only Availability Calendar here and we do
|
| 1610 |
* not insert Booking form by mistake.
|
| 1611 |
*/
|
| 1612 |
|
| 1613 |
wpbc_calendars__clear_days_highlighting( resource_id ); // Clear days highlighting
|
| 1614 |
|
| 1615 |
var css_of_calendar = '.wpbc_only_calendar #calendar_booking' + resource_id;
|
| 1616 |
jQuery( css_of_calendar + ' .datepick-days-cell, '
|
| 1617 |
+ css_of_calendar + ' .datepick-days-cell a' ).css( 'cursor', 'default' ); // Set cursor to Default
|
| 1618 |
return false;
|
| 1619 |
}
|
| 1620 |
|
| 1621 |
|
| 1622 |
|
| 1623 |
// D a y s H o v e r i n g ------------------------------------------------------------------------------------
|
| 1624 |
if (
|
| 1625 |
( location.href.indexOf( 'page=wpbc' ) == -1 )
|
| 1626 |
|| ( ( location.href.indexOf( 'page=wpbc' ) > 0 ) && ( location.href.indexOf( 'tab=add-booking' ) > 0 ) )
|
| 1627 |
|| ( is_add_booking_modal_calendar )
|
| 1628 |
|| ( is_admin_calendar_preview )
|
| 1629 |
|| ( location.href.indexOf( 'page=wpbc-setup' ) > 0 )
|
| 1630 |
|| ( location.href.indexOf( 'page=wpbc-availability' ) > 0 )
|
| 1631 |
|| ( ( location.href.indexOf( 'page=wpbc-settings' ) > 0 ) &&
|
| 1632 |
( location.href.indexOf( 'tab=builder_booking_form' ) > 0 )
|
| 1633 |
)
|
| 1634 |
){
|
| 1635 |
// The same as dates selection, but for days hovering
|
| 1636 |
|
| 1637 |
if ( 'function' == typeof( wpbc__calendar__do_days_highlight__bs ) ){
|
| 1638 |
wpbc__calendar__do_days_highlight__bs( sql_class_day, date, resource_id );
|
| 1639 |
} else if ( 'dynamic' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ) ) {
|
| 1640 |
wpbc__calendar__do_days_highlight__unrestricted_range( sql_class_day, date, resource_id );
|
| 1641 |
}
|
| 1642 |
}
|
| 1643 |
|
| 1644 |
}
|
| 1645 |
|
| 1646 |
|
| 1647 |
/**
|
| 1648 |
* Highlight an unrestricted proposed range after the first click when Business Small is not loaded.
|
| 1649 |
*
|
| 1650 |
* @param {string} sql_class_day Hovered date in SQL format.
|
| 1651 |
* @param {Date} date Hovered date.
|
| 1652 |
* @param {number|string} resource_id Booking resource ID.
|
| 1653 |
* @returns {boolean} True when the complete proposed range is available and highlighted.
|
| 1654 |
*/
|
| 1655 |
function wpbc__calendar__do_days_highlight__unrestricted_range( sql_class_day, date, resource_id ){
|
| 1656 |
|
| 1657 |
var inst = wpbc_calendar__get_inst( resource_id );
|
| 1658 |
var range_start;
|
| 1659 |
var range_end;
|
| 1660 |
var working_date;
|
| 1661 |
var td_overs = [];
|
| 1662 |
|
| 1663 |
wpbc_calendars__clear_days_highlighting( resource_id );
|
| 1664 |
|
| 1665 |
if (
|
| 1666 |
null === inst
|
| 1667 |
|| 'dynamic' !== _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' )
|
| 1668 |
) {
|
| 1669 |
return false;
|
| 1670 |
}
|
| 1671 |
|
| 1672 |
// Before a range starts, or after it is complete, preview the hovered date as the possible first day.
|
| 1673 |
if ( 1 !== inst.dates.length || ! inst.dates[ 0 ] ) {
|
| 1674 |
if ( ! wpbc_is_this_day_selectable( resource_id, sql_class_day ) ) {
|
| 1675 |
return false;
|
| 1676 |
}
|
| 1677 |
|
| 1678 |
jQuery( '#calendar_booking' + resource_id + ' .cal4date-' + wpbc__get__td_class_date( date ) )
|
| 1679 |
.addClass( 'datepick-days-cell-over' );
|
| 1680 |
return true;
|
| 1681 |
}
|
| 1682 |
|
| 1683 |
range_start = new Date( inst.dates[ 0 ].getFullYear(), inst.dates[ 0 ].getMonth(), inst.dates[ 0 ].getDate(), 0, 0, 0 );
|
| 1684 |
range_end = new Date( date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0 );
|
| 1685 |
|
| 1686 |
// Datepick only permits a check-out date on/after the first click. Do not preview a backward range.
|
| 1687 |
if ( range_end.getTime() < range_start.getTime() ) {
|
| 1688 |
return false;
|
| 1689 |
}
|
| 1690 |
|
| 1691 |
working_date = new Date( range_start.getTime() );
|
| 1692 |
while ( working_date.getTime() <= range_end.getTime() ) {
|
| 1693 |
sql_class_day = wpbc__get__sql_class_date( working_date );
|
| 1694 |
if ( ! wpbc_is_this_day_selectable( resource_id, sql_class_day ) ) {
|
| 1695 |
return false;
|
| 1696 |
}
|
| 1697 |
|
| 1698 |
td_overs.push( '#calendar_booking' + resource_id + ' .cal4date-' + wpbc__get__td_class_date( working_date ) );
|
| 1699 |
working_date.setDate( working_date.getDate() + 1 );
|
| 1700 |
}
|
| 1701 |
|
| 1702 |
if ( td_overs.length ) {
|
| 1703 |
jQuery( td_overs.join( ',' ) ).addClass( 'datepick-days-cell-over' );
|
| 1704 |
}
|
| 1705 |
|
| 1706 |
return true;
|
| 1707 |
}
|
| 1708 |
|
| 1709 |
|
| 1710 |
/**
|
| 1711 |
* Complete an unrestricted two-click range when the Business Small range engine is not loaded.
|
| 1712 |
* The hidden booking field must contain every date because Free time/hint handlers consume a comma-separated list.
|
| 1713 |
*
|
| 1714 |
* @param {string} selected_dates Datepick's endpoint string.
|
| 1715 |
* @param {number|string} resource_id Booking resource ID.
|
| 1716 |
* @returns {boolean} True after a complete valid range, false while incomplete or invalid.
|
| 1717 |
*/
|
| 1718 |
function wpbc__calendar__do_days_select__unrestricted_range( selected_dates, resource_id ){
|
| 1719 |
|
| 1720 |
var inst = wpbc_calendar__get_inst( resource_id );
|
| 1721 |
var range_start;
|
| 1722 |
var range_end;
|
| 1723 |
var current_date;
|
| 1724 |
var selected_range = [];
|
| 1725 |
|
| 1726 |
if ( null === inst ) {
|
| 1727 |
return false;
|
| 1728 |
}
|
| 1729 |
|
| 1730 |
// Datepick writes "start - start" after click one. Keep its internal endpoint, but do not expose a submittable range yet.
|
| 1731 |
if ( true === inst.stayOpen || inst.dates.length < 2 || ! inst.dates[ 0 ] || ! inst.dates[ 1 ] ) {
|
| 1732 |
jQuery( '#date_booking' + resource_id ).val( '' );
|
| 1733 |
return false;
|
| 1734 |
}
|
| 1735 |
|
| 1736 |
range_start = new Date( inst.dates[ 0 ].getFullYear(), inst.dates[ 0 ].getMonth(), inst.dates[ 0 ].getDate(), 0, 0, 0 );
|
| 1737 |
range_end = new Date( inst.dates[ 1 ].getFullYear(), inst.dates[ 1 ].getMonth(), inst.dates[ 1 ].getDate(), 0, 0, 0 );
|
| 1738 |
|
| 1739 |
// Defensive normalization. Datepick normally prevents an end date before the first endpoint.
|
| 1740 |
if ( range_end.getTime() < range_start.getTime() ) {
|
| 1741 |
current_date = range_start;
|
| 1742 |
range_start = range_end;
|
| 1743 |
range_end = current_date;
|
| 1744 |
}
|
| 1745 |
|
| 1746 |
current_date = new Date( range_start.getTime() );
|
| 1747 |
while ( current_date.getTime() <= range_end.getTime() ) {
|
| 1748 |
if ( ! wpbc_is_this_day_selectable( resource_id, wpbc__get__sql_class_date( current_date ) ) ) {
|
| 1749 |
wpbc_calendar__unselect_all_dates( resource_id );
|
| 1750 |
if ( 'function' === typeof ( wpbc_front_end__show_message__warning ) ) {
|
| 1751 |
wpbc_front_end__show_message__warning(
|
| 1752 |
'#booking_form_div' + resource_id + ' .bk_calendar_frame',
|
| 1753 |
_wpbc.get_message( 'message_range_selection_has_unavailable_dates' ),
|
| 1754 |
'text'
|
| 1755 |
);
|
| 1756 |
}
|
| 1757 |
return false;
|
| 1758 |
}
|
| 1759 |
|
| 1760 |
selected_range.push( jQuery.datepick._formatDate( inst, current_date ) );
|
| 1761 |
current_date.setDate( current_date.getDate() + 1 );
|
| 1762 |
}
|
| 1763 |
|
| 1764 |
jQuery( '#date_booking' + resource_id ).val( selected_range.join( ', ' ) );
|
| 1765 |
return true;
|
| 1766 |
}
|
| 1767 |
|
| 1768 |
|
| 1769 |
/**
|
| 1770 |
* Prepare a collapsed range-selection guidance note for one calendar.
|
| 1771 |
* Keeping one reusable node avoids repeated insertion while inactive guidance occupies no layout space.
|
| 1772 |
*
|
| 1773 |
* @param {number|string} resource_id Booking resource ID.
|
| 1774 |
* @returns {jQuery} The prepared note, or an empty collection when guidance is unavailable.
|
| 1775 |
*/
|
| 1776 |
function wpbc_range_selection__prepare_guidance( resource_id ){
|
| 1777 |
|
| 1778 |
var is_enabled = _wpbc.calendar__get_param_value( resource_id, 'range_selection_guidance_is_enabled' );
|
| 1779 |
var $booking_form = jQuery( '#booking_form_div' + resource_id );
|
| 1780 |
var $calendar_frame;
|
| 1781 |
var $note = jQuery( '#wpbc_range_selection_guidance' + resource_id );
|
| 1782 |
|
| 1783 |
if (
|
| 1784 |
false === is_enabled
|
| 1785 |
|| 0 === is_enabled
|
| 1786 |
|| '0' === is_enabled
|
| 1787 |
|| 'off' === String( is_enabled ).toLowerCase()
|
| 1788 |
|| 'false' === String( is_enabled ).toLowerCase()
|
| 1789 |
|| 'dynamic' !== _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' )
|
| 1790 |
|| 0 === $booking_form.length
|
| 1791 |
) {
|
| 1792 |
$note.remove();
|
| 1793 |
return jQuery();
|
| 1794 |
}
|
| 1795 |
|
| 1796 |
if ( 0 < $note.length ) {
|
| 1797 |
$note.stop( true, true ).hide().attr( 'aria-hidden', 'true' );
|
| 1798 |
return $note;
|
| 1799 |
}
|
| 1800 |
|
| 1801 |
$calendar_frame = $booking_form.find( '.block_hints.datepick' ).first();
|
| 1802 |
if ( 0 === $calendar_frame.length ) {
|
| 1803 |
$calendar_frame = $booking_form.find( '.wpbc_cal_powered_by' ).first();
|
| 1804 |
if ( 0 === $calendar_frame.length ) {
|
| 1805 |
$calendar_frame = $booking_form.find( '.bk_calendar_frame' ).first();
|
| 1806 |
if ( 0 === $calendar_frame.length ) {
|
| 1807 |
return jQuery();
|
| 1808 |
}
|
| 1809 |
}
|
| 1810 |
}
|
| 1811 |
|
| 1812 |
$note = jQuery( '<div>', {
|
| 1813 |
'id': 'wpbc_range_selection_guidance' + resource_id,
|
| 1814 |
'class': 'wpbc_range_selection_guidance wpbc_front_end__message wpbc_fe_message_info',
|
| 1815 |
'role': 'status',
|
| 1816 |
'aria-live': 'polite',
|
| 1817 |
'aria-hidden': 'true',
|
| 1818 |
'style': 'display: none;'
|
| 1819 |
} );
|
| 1820 |
$note.append( jQuery( '<i>', {
|
| 1821 |
'class': 'menu_icon icon-1x wpbc_icn_info_outline',
|
| 1822 |
'aria-hidden': 'true'
|
| 1823 |
} ) );
|
| 1824 |
$note.append( jQuery( '<span>' ).text( _wpbc.get_message( 'message_range_selection_click_last_date' ) ) );
|
| 1825 |
$calendar_frame.after( $note );
|
| 1826 |
|
| 1827 |
return $note;
|
| 1828 |
}
|
| 1829 |
|
| 1830 |
|
| 1831 |
/**
|
| 1832 |
* Get the range-guidance animation duration for the current motion preference.
|
| 1833 |
*
|
| 1834 |
* @returns {number} Animation duration in milliseconds, or zero when reduced motion is preferred.
|
| 1835 |
*/
|
| 1836 |
function wpbc_range_selection__get_guidance_animation_duration(){
|
| 1837 |
|
| 1838 |
if (
|
| 1839 |
'function' === typeof window.matchMedia
|
| 1840 |
&& window.matchMedia( '(prefers-reduced-motion: reduce)' ).matches
|
| 1841 |
) {
|
| 1842 |
return 0;
|
| 1843 |
}
|
| 1844 |
|
| 1845 |
return 160;
|
| 1846 |
}
|
| 1847 |
|
| 1848 |
|
| 1849 |
/**
|
| 1850 |
* Collapse the range-selection guidance so it does not reserve empty layout space.
|
| 1851 |
*
|
| 1852 |
* @param {number|string} resource_id Booking resource ID.
|
| 1853 |
*/
|
| 1854 |
function wpbc_range_selection__hide_guidance( resource_id ){
|
| 1855 |
|
| 1856 |
jQuery( '#wpbc_range_selection_guidance' + resource_id )
|
| 1857 |
.attr( 'aria-hidden', 'true' )
|
| 1858 |
.stop( true, true )
|
| 1859 |
.slideUp( wpbc_range_selection__get_guidance_animation_duration() );
|
| 1860 |
}
|
| 1861 |
|
| 1862 |
|
| 1863 |
/**
|
| 1864 |
* Show the prepared informational note after the first range click.
|
| 1865 |
* The calendar parameter can be set to false by PHP or JavaScript to suppress this UI per resource.
|
| 1866 |
*
|
| 1867 |
* @param {number|string} resource_id Booking resource ID.
|
| 1868 |
* @returns {boolean} True when the note was shown.
|
| 1869 |
*/
|
| 1870 |
function wpbc_range_selection__show_guidance( resource_id ){
|
| 1871 |
|
| 1872 |
var $note = wpbc_range_selection__prepare_guidance( resource_id );
|
| 1873 |
|
| 1874 |
if ( 0 === $note.length ) {
|
| 1875 |
return false;
|
| 1876 |
}
|
| 1877 |
|
| 1878 |
$note
|
| 1879 |
.stop( true, true )
|
| 1880 |
.slideDown( wpbc_range_selection__get_guidance_animation_duration() )
|
| 1881 |
.removeAttr( 'aria-hidden' );
|
| 1882 |
$note.find( 'span' ).text( _wpbc.get_message( 'message_range_selection_click_last_date' ) );
|
| 1883 |
|
| 1884 |
return true;
|
| 1885 |
}
|
| 1886 |
|
| 1887 |
|
| 1888 |
/**
|
| 1889 |
* Synchronize the guidance with Datepick's two-click range state.
|
| 1890 |
*
|
| 1891 |
* @param {number|string} resource_id Booking resource ID.
|
| 1892 |
*/
|
| 1893 |
function wpbc_range_selection__sync_guidance( resource_id ){
|
| 1894 |
|
| 1895 |
var inst = wpbc_calendar__get_inst( resource_id );
|
| 1896 |
|
| 1897 |
if (
|
| 1898 |
null !== inst
|
| 1899 |
&& 'dynamic' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' )
|
| 1900 |
&& true === inst.stayOpen
|
| 1901 |
&& 1 === inst.dates.length
|
| 1902 |
&& inst.dates[ 0 ]
|
| 1903 |
) {
|
| 1904 |
wpbc_range_selection__show_guidance( resource_id );
|
| 1905 |
return;
|
| 1906 |
}
|
| 1907 |
|
| 1908 |
wpbc_range_selection__hide_guidance( resource_id );
|
| 1909 |
}
|
| 1910 |
|
| 1911 |
|
| 1912 |
/**
|
| 1913 |
* Select calendar date cells
|
| 1914 |
*
|
| 1915 |
* @param date - JavaScript Date Obj: Mon Dec 11 2023 00:00:00
|
| 1916 |
* GMT+0200 (Eastern European Standard Time)
|
| 1917 |
* @param calendar_params_arr - Calendar Settings Object: {
|
| 1918 |
* "resource_id": 4
|
| 1919 |
* }
|
| 1920 |
* @param datepick_this - this of datepick Obj
|
| 1921 |
*
|
| 1922 |
*/
|
| 1923 |
function wpbc__calendar__on_select_days( date, calendar_params_arr, datepick_this ){
|
| 1924 |
|
| 1925 |
var resource_id = ( 'undefined' !== typeof(calendar_params_arr[ 'resource_id' ]) ) ? calendar_params_arr[ 'resource_id' ] : '1'; // '1'
|
| 1926 |
|
| 1927 |
// Set unselectable, if only Availability Calendar here (and we do not insert Booking form by mistake).
|
| 1928 |
var is_unselectable_calendar = ( jQuery( '#calendar_booking_unselectable' + resource_id ).length > 0); // FixIn: 8.0.1.2.
|
| 1929 |
var is_booking_form_exist = ( jQuery( '#booking_form_div' + resource_id ).length > 0 );
|
| 1930 |
if ( ( is_unselectable_calendar ) && ( ! is_booking_form_exist ) ){
|
| 1931 |
wpbc_calendar__unselect_all_dates( resource_id ); // Unselect Dates
|
| 1932 |
jQuery('.wpbc_only_calendar .popover_calendar_hover').remove(); // Hide all opened popovers
|
| 1933 |
return false;
|
| 1934 |
}
|
| 1935 |
|
| 1936 |
jQuery( '#date_booking' + resource_id ).val( date ); // Add selected dates to hidden textarea
|
| 1937 |
|
| 1938 |
|
| 1939 |
if ( 'function' === typeof (wpbc__calendar__do_days_select__bs) ) {
|
| 1940 |
wpbc__calendar__do_days_select__bs( date, resource_id );
|
| 1941 |
} else if ( 'dynamic' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ) ) {
|
| 1942 |
wpbc__calendar__do_days_select__unrestricted_range( date, resource_id );
|
| 1943 |
}
|
| 1944 |
|
| 1945 |
wpbc_range_selection__sync_guidance( resource_id );
|
| 1946 |
|
| 1947 |
wpbc_disable_time_fields_in_booking_form( resource_id );
|
| 1948 |
|
| 1949 |
// Hook -- trigger day selection -----------------------------------------------------------------------------------
|
| 1950 |
var mouse_clicked_dates = date; // Can be: "05.10.2023 - 07.10.2023" | "10.10.2023 - 10.10.2023" |
|
| 1951 |
var all_selected_dates_arr = wpbc_get__selected_dates_sql__as_arr( resource_id ); // Can be: [ "2023-10-05", "2023-10-06", "2023-10-07", … ]
|
| 1952 |
jQuery( ".booking_form_div" ).trigger( "date_selected", [ resource_id, mouse_clicked_dates, all_selected_dates_arr ] );
|
| 1953 |
}
|
| 1954 |
|
| 1955 |
// Mark middle selected dates with 0.5 opacity // FixIn: 10.3.0.9.
|
| 1956 |
jQuery( document ).ready( function (){
|
| 1957 |
jQuery( ".booking_form_div" ).on( 'date_selected', function ( event, resource_id, date ){
|
| 1958 |
if (
|
| 1959 |
( 'fixed' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ))
|
| 1960 |
|| ('dynamic' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ))
|
| 1961 |
){
|
| 1962 |
var closed_timer = setTimeout( function (){
|
| 1963 |
var middle_days_opacity = _wpbc.get_other_param( 'calendars__days_selection__middle_days_opacity' );
|
| 1964 |
jQuery( '#calendar_booking' + resource_id + ' .datepick-current-day' ).not( ".selected_check_in_out" ).css( 'opacity', middle_days_opacity );
|
| 1965 |
}, 10 );
|
| 1966 |
}
|
| 1967 |
} );
|
| 1968 |
} );
|
| 1969 |
|
| 1970 |
|
| 1971 |
/**
|
| 1972 |
* -- T i m e F i e l d s start --------------------------------------------------------------------------
|
| 1973 |
*/
|
| 1974 |
|
| 1975 |
/**
|
| 1976 |
* Disable time slots in booking form depend on selected dates and booked dates/times
|
| 1977 |
*
|
| 1978 |
* @param resource_id
|
| 1979 |
*/
|
| 1980 |
function wpbc_disable_time_fields_in_booking_form( resource_id ){
|
| 1981 |
|
| 1982 |
/**
|
| 1983 |
* 1. Get all time fields in the booking form as array of objects
|
| 1984 |
* [
|
| 1985 |
* { jquery_option: jQuery_Object {}
|
| 1986 |
* name: 'rangetime2[]'
|
| 1987 |
* times_as_seconds: [ 21600, 23400 ]
|
| 1988 |
* value_option_24h: '06:00 - 06:30'
|
| 1989 |
* }
|
| 1990 |
* ...
|
| 1991 |
* { jquery_option: jQuery_Object {}
|
| 1992 |
* name: 'starttime2[]'
|
| 1993 |
* times_as_seconds: [ 21600 ]
|
| 1994 |
* value_option_24h: '06:00'
|
| 1995 |
* }
|
| 1996 |
* ]
|
| 1997 |
*/
|
| 1998 |
var time_fields_obj_arr = wpbc_get__time_fields__in_booking_form__as_arr( resource_id );
|
| 1999 |
|
| 2000 |
// 2. Get all selected dates in SQL format like this [ "2023-08-23", "2023-08-24", "2023-08-25", ... ]
|
| 2001 |
var selected_dates_arr = wpbc_get__selected_dates_sql__as_arr( resource_id );
|
| 2002 |
|
| 2003 |
// 3. Get child booking resources or single booking resource that exist in dates
|
| 2004 |
var child_resources_arr = wpbc_clone_obj( _wpbc.booking__get_param_value( resource_id, 'resources_id_arr__in_dates' ) );
|
| 2005 |
|
| 2006 |
var sql_date;
|
| 2007 |
var child_resource_id;
|
| 2008 |
var merged_seconds;
|
| 2009 |
var time_fields_obj;
|
| 2010 |
var is_intersect;
|
| 2011 |
var is_check_in;
|
| 2012 |
|
| 2013 |
var today_time__real = new Date( _wpbc.get_other_param( 'time_local_arr' )[0], ( parseInt( _wpbc.get_other_param( 'time_local_arr' )[1] ) - 1), _wpbc.get_other_param( 'time_local_arr' )[2], _wpbc.get_other_param( 'time_local_arr' )[3], _wpbc.get_other_param( 'time_local_arr' )[4], 0 );
|
| 2014 |
var today_time__shift = new Date( _wpbc.get_other_param( 'today_arr' )[0], ( parseInt( _wpbc.get_other_param( 'today_arr' )[1] ) - 1), _wpbc.get_other_param( 'today_arr' )[2], _wpbc.get_other_param( 'today_arr' )[3], _wpbc.get_other_param( 'today_arr' )[4], 0 );
|
| 2015 |
var allow_past_context = _wpbc.get_other_param( 'this_page_allow_past' );
|
| 2016 |
var edit_booking_hash_context = _wpbc.get_other_param( 'this_page_booking_hash' );
|
| 2017 |
var is_allow_past_context =
|
| 2018 |
( '1' === String( allow_past_context ) )
|
| 2019 |
|| ( 1 === allow_past_context )
|
| 2020 |
|| ( true === allow_past_context )
|
| 2021 |
|| ( '' !== String( edit_booking_hash_context || '' ) )
|
| 2022 |
|| ( location.href.indexOf( 'booking_hash' ) > -1 )
|
| 2023 |
|| ( location.href.indexOf( 'allow_past' ) > -1 );
|
| 2024 |
|
| 2025 |
// 4. Loop all time Fields options // FixIn: 10.3.0.2.
|
| 2026 |
for ( let field_key = 0; field_key < time_fields_obj_arr.length; field_key++ ){
|
| 2027 |
|
| 2028 |
time_fields_obj_arr[ field_key ].disabled = 0; // By default, this time field is not disabled.
|
| 2029 |
|
| 2030 |
time_fields_obj = time_fields_obj_arr[ field_key ]; // { times_as_seconds: [ 21600, 23400 ], value_option_24h: '06:00 - 06:30', name: 'rangetime2[]', jquery_option: jQuery_Object {}}
|
| 2031 |
|
| 2032 |
// Loop all selected dates.
|
| 2033 |
for ( var i = 0; i < selected_dates_arr.length; i++ ) {
|
| 2034 |
|
| 2035 |
// Get Date: '2023-08-18'.
|
| 2036 |
sql_date = selected_dates_arr[i];
|
| 2037 |
|
| 2038 |
var is_time_in_past = is_allow_past_context ? false : wpbc_check_is_time_in_past( today_time__shift, sql_date, time_fields_obj );
|
| 2039 |
// Exception for 'End Time' field, when selected several dates. // FixIn: 10.14.1.5.
|
| 2040 |
if ( ( ! is_allow_past_context ) &&
|
| 2041 |
('On' !== _wpbc.calendar__get_param_value( resource_id, 'booking_recurrent_time' )) &&
|
| 2042 |
(-1 !== time_fields_obj.name.indexOf( 'endtime' )) &&
|
| 2043 |
(selected_dates_arr.length > 1)
|
| 2044 |
) {
|
| 2045 |
is_time_in_past = wpbc_check_is_time_in_past( today_time__shift, selected_dates_arr[(selected_dates_arr.length - 1)], time_fields_obj );
|
| 2046 |
}
|
| 2047 |
if ( is_time_in_past ) {
|
| 2048 |
// This time for selected date already in the past.
|
| 2049 |
time_fields_obj_arr[field_key].disabled = 1;
|
| 2050 |
break; // exist from Dates LOOP.
|
| 2051 |
}
|
| 2052 |
// FixIn: 9.9.0.31.
|
| 2053 |
if (
|
| 2054 |
( 'Off' === _wpbc.calendar__get_param_value( resource_id, 'booking_recurrent_time' ) )
|
| 2055 |
&& ( selected_dates_arr.length>1 )
|
| 2056 |
){
|
| 2057 |
//TODO: skip some fields checking if it's start / end time for mulple dates selection mode.
|
| 2058 |
//TODO: we need to fix situation for entimes, when user select several dates, and in start time booked 00:00 - 15:00 , but systsme block untill 15:00 the end time as well, which is wrong, because it 2 or 3 dates selection and end date can be fullu available
|
| 2059 |
|
| 2060 |
if ( (0 == i) && (time_fields_obj[ 'name' ].indexOf( 'endtime' ) >= 0) ){
|
| 2061 |
break;
|
| 2062 |
}
|
| 2063 |
if ( ( (selected_dates_arr.length-1) == i ) && (time_fields_obj[ 'name' ].indexOf( 'starttime' ) >= 0) ){
|
| 2064 |
break;
|
| 2065 |
}
|
| 2066 |
}
|
| 2067 |
|
| 2068 |
|
| 2069 |
|
| 2070 |
var how_many_resources_intersected = 0;
|
| 2071 |
// Loop all resources ID
|
| 2072 |
// for ( var res_key in child_resources_arr ){ // FixIn: 10.3.0.2.
|
| 2073 |
if ( null === child_resources_arr ) {
|
| 2074 |
child_resources_arr = [];
|
| 2075 |
}
|
| 2076 |
for ( let res_key = 0; res_key < child_resources_arr.length; res_key++ ){
|
| 2077 |
|
| 2078 |
child_resource_id = child_resources_arr[ res_key ];
|
| 2079 |
|
| 2080 |
// _wpbc.bookings_in_calendar__get_for_date(2,'2023-08-21')[12].booked_time_slots.merged_seconds = [ "07:00:11 - 07:30:02", "10:00:11 - 00:00:00" ]
|
| 2081 |
// _wpbc.bookings_in_calendar__get_for_date(2,'2023-08-21')[2].booked_time_slots.merged_seconds = [ [ 25211, 27002 ], [ 36011, 86400 ] ]
|
| 2082 |
|
| 2083 |
if ( false !== _wpbc.bookings_in_calendar__get_for_date( resource_id, sql_date ) ){
|
| 2084 |
merged_seconds = _wpbc.bookings_in_calendar__get_for_date( resource_id, sql_date )[ child_resource_id ].booked_time_slots.merged_seconds; // [ [ 25211, 27002 ], [ 36011, 86400 ] ]
|
| 2085 |
} else {
|
| 2086 |
merged_seconds = [];
|
| 2087 |
}
|
| 2088 |
if ( time_fields_obj.times_as_seconds.length > 1 ){
|
| 2089 |
is_intersect = wpbc_is_intersect__range_time_interval( [
|
| 2090 |
[
|
| 2091 |
( parseInt( time_fields_obj.times_as_seconds[0] ) + 20 ),
|
| 2092 |
( parseInt( time_fields_obj.times_as_seconds[1] ) - 20 )
|
| 2093 |
]
|
| 2094 |
]
|
| 2095 |
, merged_seconds );
|
| 2096 |
} else {
|
| 2097 |
is_check_in = (-1 !== time_fields_obj.name.indexOf( 'start' ));
|
| 2098 |
is_intersect = wpbc_is_intersect__one_time_interval(
|
| 2099 |
( ( is_check_in )
|
| 2100 |
? parseInt( time_fields_obj.times_as_seconds ) + 20
|
| 2101 |
: parseInt( time_fields_obj.times_as_seconds ) - 20
|
| 2102 |
)
|
| 2103 |
, merged_seconds );
|
| 2104 |
}
|
| 2105 |
if (is_intersect){
|
| 2106 |
how_many_resources_intersected++; // Increase
|
| 2107 |
}
|
| 2108 |
|
| 2109 |
}
|
| 2110 |
|
| 2111 |
if ( child_resources_arr.length == how_many_resources_intersected ) {
|
| 2112 |
// All resources intersected, then it's means that this time-slot or time must be Disabled, and we can exist from selected_dates_arr LOOP
|
| 2113 |
|
| 2114 |
time_fields_obj_arr[ field_key ].disabled = 1;
|
| 2115 |
break; // exist from Dates LOOP
|
| 2116 |
}
|
| 2117 |
}
|
| 2118 |
}
|
| 2119 |
|
| 2120 |
|
| 2121 |
// 5. Now we can disable time slot in HTML by using ( field.disabled == 1 ) property
|
| 2122 |
wpbc__html__time_field_options__set_disabled( time_fields_obj_arr );
|
| 2123 |
|
| 2124 |
jQuery( ".booking_form_div" ).trigger( 'wpbc_hook_timeslots_disabled', [resource_id, selected_dates_arr] ); // Trigger hook on disabling timeslots. Usage: jQuery( ".booking_form_div" ).on( 'wpbc_hook_timeslots_disabled', function ( event, bk_type, all_dates ){ ... } ); // FixIn: 8.7.11.9.
|
| 2125 |
}
|
| 2126 |
|
| 2127 |
|
| 2128 |
/**
|
| 2129 |
* Check if specific time(-slot) already in the past for selected date
|
| 2130 |
*
|
| 2131 |
* @param js_current_time_to_check - JS Date
|
| 2132 |
* @param sql_date - '2025-01-26'
|
| 2133 |
* @param time_fields_obj - Object
|
| 2134 |
* @returns {boolean}
|
| 2135 |
*/
|
| 2136 |
function wpbc_check_is_time_in_past( js_current_time_to_check, sql_date, time_fields_obj ) {
|
| 2137 |
|
| 2138 |
// FixIn: 10.9.6.4
|
| 2139 |
var sql_date_arr = sql_date.split( '-' );
|
| 2140 |
var sql_date__midnight = new Date( parseInt( sql_date_arr[0] ), ( parseInt( sql_date_arr[1] ) - 1 ), parseInt( sql_date_arr[2] ), 0, 0, 0 );
|
| 2141 |
var sql_date__midnight_miliseconds = sql_date__midnight.getTime();
|
| 2142 |
|
| 2143 |
var is_intersect = false;
|
| 2144 |
|
| 2145 |
if ( time_fields_obj.times_as_seconds.length > 1 ) {
|
| 2146 |
|
| 2147 |
if ( js_current_time_to_check.getTime() > (sql_date__midnight_miliseconds + (parseInt( time_fields_obj.times_as_seconds[0] ) + 20) * 1000) ) {
|
| 2148 |
is_intersect = true;
|
| 2149 |
}
|
| 2150 |
if ( js_current_time_to_check.getTime() > (sql_date__midnight_miliseconds + (parseInt( time_fields_obj.times_as_seconds[1] ) - 20) * 1000) ) {
|
| 2151 |
is_intersect = true;
|
| 2152 |
}
|
| 2153 |
|
| 2154 |
} else {
|
| 2155 |
var is_check_in = (-1 !== time_fields_obj.name.indexOf( 'start' ));
|
| 2156 |
|
| 2157 |
var times_as_seconds_check = (is_check_in) ? parseInt( time_fields_obj.times_as_seconds ) + 20 : parseInt( time_fields_obj.times_as_seconds ) - 20;
|
| 2158 |
|
| 2159 |
times_as_seconds_check = sql_date__midnight_miliseconds + times_as_seconds_check * 1000;
|
| 2160 |
|
| 2161 |
if ( js_current_time_to_check.getTime() > times_as_seconds_check ) {
|
| 2162 |
is_intersect = true;
|
| 2163 |
}
|
| 2164 |
}
|
| 2165 |
|
| 2166 |
return is_intersect;
|
| 2167 |
}
|
| 2168 |
|
| 2169 |
/**
|
| 2170 |
* Is number inside /intersect of array of intervals ?
|
| 2171 |
*
|
| 2172 |
* @param time_A - 25800
|
| 2173 |
* @param time_interval_B - [ [ 25211, 27002 ], [ 36011, 86400 ] ]
|
| 2174 |
* @returns {boolean}
|
| 2175 |
*/
|
| 2176 |
function wpbc_is_intersect__one_time_interval( time_A, time_interval_B ){
|
| 2177 |
|
| 2178 |
for ( var j = 0; j < time_interval_B.length; j++ ){
|
| 2179 |
|
| 2180 |
if ( (parseInt( time_A ) > parseInt( time_interval_B[ j ][ 0 ] )) && (parseInt( time_A ) < parseInt( time_interval_B[ j ][ 1 ] )) ){
|
| 2181 |
return true
|
| 2182 |
}
|
| 2183 |
|
| 2184 |
// if ( ( parseInt( time_A ) == parseInt( time_interval_B[ j ][ 0 ] ) ) || ( parseInt( time_A ) == parseInt( time_interval_B[ j ][ 1 ] ) ) ) {
|
| 2185 |
// // Time A just at the border of interval
|
| 2186 |
// }
|
| 2187 |
}
|
| 2188 |
|
| 2189 |
return false;
|
| 2190 |
}
|
| 2191 |
|
| 2192 |
/**
|
| 2193 |
* Is these array of intervals intersected ?
|
| 2194 |
*
|
| 2195 |
* @param time_interval_A - [ [ 21600, 23400 ] ]
|
| 2196 |
* @param time_interval_B - [ [ 25211, 27002 ], [ 36011, 86400 ] ]
|
| 2197 |
* @returns {boolean}
|
| 2198 |
*/
|
| 2199 |
function wpbc_is_intersect__range_time_interval( time_interval_A, time_interval_B ){
|
| 2200 |
|
| 2201 |
var is_intersect;
|
| 2202 |
|
| 2203 |
for ( var i = 0; i < time_interval_A.length; i++ ){
|
| 2204 |
|
| 2205 |
for ( var j = 0; j < time_interval_B.length; j++ ){
|
| 2206 |
|
| 2207 |
is_intersect = wpbc_intervals__is_intersected( time_interval_A[ i ], time_interval_B[ j ] );
|
| 2208 |
|
| 2209 |
if ( is_intersect ){
|
| 2210 |
return true;
|
| 2211 |
}
|
| 2212 |
}
|
| 2213 |
}
|
| 2214 |
|
| 2215 |
return false;
|
| 2216 |
}
|
| 2217 |
|
| 2218 |
/**
|
| 2219 |
* Get all time fields in the booking form as array of objects
|
| 2220 |
*
|
| 2221 |
* @param resource_id
|
| 2222 |
* @returns []
|
| 2223 |
*
|
| 2224 |
* Example:
|
| 2225 |
* [
|
| 2226 |
* {
|
| 2227 |
* value_option_24h: '06:00 - 06:30'
|
| 2228 |
* times_as_seconds: [ 21600, 23400 ]
|
| 2229 |
* jquery_option: jQuery_Object {}
|
| 2230 |
* name: 'rangetime2[]'
|
| 2231 |
* }
|
| 2232 |
* ...
|
| 2233 |
* {
|
| 2234 |
* value_option_24h: '06:00'
|
| 2235 |
* times_as_seconds: [ 21600 ]
|
| 2236 |
* jquery_option: jQuery_Object {}
|
| 2237 |
* name: 'starttime2[]'
|
| 2238 |
* }
|
| 2239 |
* ]
|
| 2240 |
*/
|
| 2241 |
function wpbc_get__time_fields__in_booking_form__as_arr( resource_id ){
|
| 2242 |
/**
|
| 2243 |
* Fields with [] like this select[name="rangetime1[]"]
|
| 2244 |
* it's when we have 'multiple' in shortcode: [select* rangetime multiple "06:00 - 06:30" ... ]
|
| 2245 |
*/
|
| 2246 |
var time_fields_arr=[
|
| 2247 |
'select[name="rangetime' + resource_id + '"]',
|
| 2248 |
'select[name="rangetime' + resource_id + '[]"]',
|
| 2249 |
'select[name="starttime' + resource_id + '"]',
|
| 2250 |
'select[name="starttime' + resource_id + '[]"]',
|
| 2251 |
'select[name="endtime' + resource_id + '"]',
|
| 2252 |
'select[name="endtime' + resource_id + '[]"]'
|
| 2253 |
];
|
| 2254 |
|
| 2255 |
var time_fields_obj_arr = [];
|
| 2256 |
|
| 2257 |
// Loop all Time Fields
|
| 2258 |
for ( var ctf= 0; ctf < time_fields_arr.length; ctf++ ){
|
| 2259 |
|
| 2260 |
var time_field = time_fields_arr[ ctf ];
|
| 2261 |
var time_option = jQuery( time_field + ' option' );
|
| 2262 |
|
| 2263 |
// Loop all options in time field
|
| 2264 |
for ( var j = 0; j < time_option.length; j++ ){
|
| 2265 |
|
| 2266 |
var jquery_option = jQuery( time_field + ' option:eq(' + j + ')' );
|
| 2267 |
var value_option_seconds_arr = jquery_option.val().split( '-' );
|
| 2268 |
var times_as_seconds = [];
|
| 2269 |
|
| 2270 |
// Get time as seconds
|
| 2271 |
if ( value_option_seconds_arr.length ){ // FixIn: 9.8.10.1.
|
| 2272 |
for ( let i = 0; i < value_option_seconds_arr.length; i++ ){ // FixIn: 10.0.0.56.
|
| 2273 |
// value_option_seconds_arr[i] = '14:00 ' | ' 16:00' (if from 'rangetime') and '16:00' if (start/end time)
|
| 2274 |
|
| 2275 |
var start_end_times_arr = value_option_seconds_arr[ i ].trim().split( ':' );
|
| 2276 |
|
| 2277 |
var time_in_seconds = parseInt( start_end_times_arr[ 0 ] ) * 60 * 60 + parseInt( start_end_times_arr[ 1 ] ) * 60;
|
| 2278 |
|
| 2279 |
times_as_seconds.push( time_in_seconds );
|
| 2280 |
}
|
| 2281 |
}
|
| 2282 |
|
| 2283 |
time_fields_obj_arr.push( {
|
| 2284 |
'name' : jQuery( time_field ).attr( 'name' ),
|
| 2285 |
'value_option_24h': jquery_option.val(),
|
| 2286 |
'jquery_option' : jquery_option,
|
| 2287 |
'times_as_seconds': times_as_seconds
|
| 2288 |
} );
|
| 2289 |
}
|
| 2290 |
}
|
| 2291 |
|
| 2292 |
return time_fields_obj_arr;
|
| 2293 |
}
|
| 2294 |
|
| 2295 |
/**
|
| 2296 |
* Disable HTML options and add booked CSS class
|
| 2297 |
*
|
| 2298 |
* @param time_fields_obj_arr - this value is from the func:
|
| 2299 |
* wpbc_get__time_fields__in_booking_form__as_arr( resource_id )
|
| 2300 |
* [
|
| 2301 |
* { jquery_option: jQuery_Object {}
|
| 2302 |
* name: 'rangetime2[]'
|
| 2303 |
* times_as_seconds: [ 21600, 23400 ]
|
| 2304 |
* value_option_24h: '06:00 - 06:30'
|
| 2305 |
* disabled = 1
|
| 2306 |
* }
|
| 2307 |
* ...
|
| 2308 |
* { jquery_option: jQuery_Object {}
|
| 2309 |
* name: 'starttime2[]'
|
| 2310 |
* times_as_seconds: [ 21600 ]
|
| 2311 |
* value_option_24h: '06:00'
|
| 2312 |
* disabled = 0
|
| 2313 |
* }
|
| 2314 |
* ]
|
| 2315 |
*
|
| 2316 |
*/
|
| 2317 |
function wpbc__html__time_field_options__set_disabled( time_fields_obj_arr ){
|
| 2318 |
|
| 2319 |
var jquery_option;
|
| 2320 |
|
| 2321 |
for ( var i = 0; i < time_fields_obj_arr.length; i++ ){
|
| 2322 |
|
| 2323 |
var jquery_option = time_fields_obj_arr[ i ].jquery_option;
|
| 2324 |
|
| 2325 |
if ( 1 == time_fields_obj_arr[ i ].disabled ){
|
| 2326 |
jquery_option.prop( 'disabled', true ); // Make disable some options
|
| 2327 |
jquery_option.addClass( 'booked' ); // Add "booked" CSS class
|
| 2328 |
|
| 2329 |
// if this booked element selected --> then deselect it
|
| 2330 |
if ( jquery_option.prop( 'selected' ) ){
|
| 2331 |
jquery_option.prop( 'selected', false );
|
| 2332 |
|
| 2333 |
jquery_option.parent().find( 'option:not([disabled]):first' ).prop( 'selected', true ).trigger( "change" );
|
| 2334 |
}
|
| 2335 |
|
| 2336 |
} else {
|
| 2337 |
jquery_option.prop( 'disabled', false ); // Make active all times
|
| 2338 |
jquery_option.removeClass( 'booked' ); // Remove class "booked"
|
| 2339 |
}
|
| 2340 |
}
|
| 2341 |
|
| 2342 |
}
|
| 2343 |
|
| 2344 |
/**
|
| 2345 |
* Check if this time_range | Time_Slot is Full Day booked
|
| 2346 |
*
|
| 2347 |
* @param timeslot_arr_in_seconds - [ 36011, 86400 ]
|
| 2348 |
* @returns {boolean}
|
| 2349 |
*/
|
| 2350 |
function wpbc_is_this_timeslot__full_day_booked( timeslot_arr_in_seconds ){
|
| 2351 |
|
| 2352 |
if (
|
| 2353 |
( timeslot_arr_in_seconds.length > 1 )
|
| 2354 |
&& ( parseInt( timeslot_arr_in_seconds[ 0 ] ) < 30 )
|
| 2355 |
&& ( parseInt( timeslot_arr_in_seconds[ 1 ] ) > ( (24 * 60 * 60) - 30) )
|
| 2356 |
){
|
| 2357 |
return true;
|
| 2358 |
}
|
| 2359 |
|
| 2360 |
return false;
|
| 2361 |
}
|
| 2362 |
|
| 2363 |
|
| 2364 |
// -----------------------------------------------------------------------------------------------------------------
|
| 2365 |
/* == S e l e c t e d D a t e s / T i m e - F i e l d s ==
|
| 2366 |
// ----------------------------------------------------------------------------------------------------------------- */
|
| 2367 |
|
| 2368 |
/**
|
| 2369 |
* Get all selected dates in SQL format like this [ "2023-08-23", "2023-08-24" , ... ]
|
| 2370 |
*
|
| 2371 |
* @param resource_id
|
| 2372 |
* @returns {[]} [ "2023-08-23", "2023-08-24", "2023-08-25", "2023-08-26", "2023-08-27", "2023-08-28",
|
| 2373 |
* "2023-08-29" ]
|
| 2374 |
*/
|
| 2375 |
function wpbc_get__selected_dates_sql__as_arr( resource_id ){
|
| 2376 |
|
| 2377 |
var selected_dates_arr = [];
|
| 2378 |
selected_dates_arr = jQuery( '#date_booking' + resource_id ).val().split(',');
|
| 2379 |
|
| 2380 |
if ( selected_dates_arr.length ){ // FixIn: 9.8.10.1.
|
| 2381 |
for ( let i = 0; i < selected_dates_arr.length; i++ ){ // FixIn: 10.0.0.56.
|
| 2382 |
selected_dates_arr[ i ] = selected_dates_arr[ i ].trim();
|
| 2383 |
selected_dates_arr[ i ] = selected_dates_arr[ i ].split( '.' );
|
| 2384 |
if ( selected_dates_arr[ i ].length > 1 ){
|
| 2385 |
selected_dates_arr[ i ] = selected_dates_arr[ i ][ 2 ] + '-' + selected_dates_arr[ i ][ 1 ] + '-' + selected_dates_arr[ i ][ 0 ];
|
| 2386 |
}
|
| 2387 |
}
|
| 2388 |
}
|
| 2389 |
|
| 2390 |
// Remove empty elements from an array
|
| 2391 |
selected_dates_arr = selected_dates_arr.filter( function ( n ){ return parseInt(n); } );
|
| 2392 |
|
| 2393 |
selected_dates_arr.sort();
|
| 2394 |
|
| 2395 |
return selected_dates_arr;
|
| 2396 |
}
|
| 2397 |
|
| 2398 |
|
| 2399 |
/**
|
| 2400 |
* Get all time fields in the booking form as array of objects
|
| 2401 |
*
|
| 2402 |
* @param resource_id
|
| 2403 |
* @param is_only_selected_time
|
| 2404 |
* @returns []
|
| 2405 |
*
|
| 2406 |
* Example:
|
| 2407 |
* [
|
| 2408 |
* {
|
| 2409 |
* value_option_24h: '06:00 - 06:30'
|
| 2410 |
* times_as_seconds: [ 21600, 23400 ]
|
| 2411 |
* jquery_option: jQuery_Object {}
|
| 2412 |
* name: 'rangetime2[]'
|
| 2413 |
* }
|
| 2414 |
* ...
|
| 2415 |
* {
|
| 2416 |
* value_option_24h: '06:00'
|
| 2417 |
* times_as_seconds: [ 21600 ]
|
| 2418 |
* jquery_option: jQuery_Object {}
|
| 2419 |
* name: 'starttime2[]'
|
| 2420 |
* }
|
| 2421 |
* ]
|
| 2422 |
*/
|
| 2423 |
function wpbc_get__selected_time_fields__in_booking_form__as_arr( resource_id, is_only_selected_time = true ){
|
| 2424 |
/**
|
| 2425 |
* Fields with [] like this select[name="rangetime1[]"]
|
| 2426 |
* it's when we have 'multiple' in shortcode: [select* rangetime multiple "06:00 - 06:30" ... ]
|
| 2427 |
*/
|
| 2428 |
var time_fields_arr=[
|
| 2429 |
'select[name="rangetime' + resource_id + '"]',
|
| 2430 |
'select[name="rangetime' + resource_id + '[]"]',
|
| 2431 |
'select[name="starttime' + resource_id + '"]',
|
| 2432 |
'select[name="starttime' + resource_id + '[]"]',
|
| 2433 |
'select[name="endtime' + resource_id + '"]',
|
| 2434 |
'select[name="endtime' + resource_id + '[]"]',
|
| 2435 |
'select[name="durationtime' + resource_id + '"]',
|
| 2436 |
'select[name="durationtime' + resource_id + '[]"]'
|
| 2437 |
];
|
| 2438 |
|
| 2439 |
var time_fields_obj_arr = [];
|
| 2440 |
|
| 2441 |
// Loop all Time Fields
|
| 2442 |
for ( var ctf= 0; ctf < time_fields_arr.length; ctf++ ){
|
| 2443 |
|
| 2444 |
var time_field = time_fields_arr[ ctf ];
|
| 2445 |
|
| 2446 |
var time_option;
|
| 2447 |
if ( is_only_selected_time ){
|
| 2448 |
time_option = jQuery( '#booking_form' + resource_id + ' ' + time_field + ' option:selected' ); // Exclude conditional fields, because of using '#booking_form3 ...'
|
| 2449 |
} else {
|
| 2450 |
time_option = jQuery( '#booking_form' + resource_id + ' ' + time_field + ' option' ); // All time fields
|
| 2451 |
}
|
| 2452 |
|
| 2453 |
|
| 2454 |
// Loop all options in time field
|
| 2455 |
for ( var j = 0; j < time_option.length; j++ ){
|
| 2456 |
|
| 2457 |
var jquery_option = jQuery( time_option[ j ] ); // Get only selected options //jQuery( time_field + ' option:eq(' + j + ')' );
|
| 2458 |
var value_option_seconds_arr = jquery_option.val().split( '-' );
|
| 2459 |
var times_as_seconds = [];
|
| 2460 |
|
| 2461 |
// Get time as seconds
|
| 2462 |
if ( value_option_seconds_arr.length ){ // FixIn: 9.8.10.1.
|
| 2463 |
for ( let i = 0; i < value_option_seconds_arr.length; i++ ){ // FixIn: 10.0.0.56.
|
| 2464 |
// value_option_seconds_arr[i] = '14:00 ' | ' 16:00' (if from 'rangetime') and '16:00' if (start/end time)
|
| 2465 |
|
| 2466 |
var start_end_times_arr = value_option_seconds_arr[ i ].trim().split( ':' );
|
| 2467 |
|
| 2468 |
var time_in_seconds = parseInt( start_end_times_arr[ 0 ] ) * 60 * 60 + parseInt( start_end_times_arr[ 1 ] ) * 60;
|
| 2469 |
|
| 2470 |
times_as_seconds.push( time_in_seconds );
|
| 2471 |
}
|
| 2472 |
}
|
| 2473 |
|
| 2474 |
time_fields_obj_arr.push( {
|
| 2475 |
'name' : jQuery( '#booking_form' + resource_id + ' ' + time_field ).attr( 'name' ),
|
| 2476 |
'value_option_24h': jquery_option.val(),
|
| 2477 |
'jquery_option' : jquery_option,
|
| 2478 |
'times_as_seconds': times_as_seconds
|
| 2479 |
} );
|
| 2480 |
}
|
| 2481 |
}
|
| 2482 |
|
| 2483 |
// Text: [starttime] - [endtime] -----------------------------------------------------------------------------
|
| 2484 |
|
| 2485 |
var text_time_fields_arr=[
|
| 2486 |
'input[name="starttime' + resource_id + '"]',
|
| 2487 |
'input[name="endtime' + resource_id + '"]',
|
| 2488 |
];
|
| 2489 |
for ( var tf= 0; tf < text_time_fields_arr.length; tf++ ){
|
| 2490 |
|
| 2491 |
var text_jquery = jQuery( '#booking_form' + resource_id + ' ' + text_time_fields_arr[ tf ] ); // Exclude conditional fields, because of using '#booking_form3 ...'
|
| 2492 |
if ( text_jquery.length > 0 ){
|
| 2493 |
|
| 2494 |
var time__h_m__arr = text_jquery.val().trim().split( ':' ); // '14:00'
|
| 2495 |
if ( 0 == time__h_m__arr.length ){
|
| 2496 |
continue; // Not entered time value in a field
|
| 2497 |
}
|
| 2498 |
if ( 1 == time__h_m__arr.length ){
|
| 2499 |
if ( '' === time__h_m__arr[ 0 ] ){
|
| 2500 |
continue; // Not entered time value in a field
|
| 2501 |
}
|
| 2502 |
time__h_m__arr[ 1 ] = 0;
|
| 2503 |
}
|
| 2504 |
var text_time_in_seconds = parseInt( time__h_m__arr[ 0 ] ) * 60 * 60 + parseInt( time__h_m__arr[ 1 ] ) * 60;
|
| 2505 |
|
| 2506 |
var text_times_as_seconds = [];
|
| 2507 |
text_times_as_seconds.push( text_time_in_seconds );
|
| 2508 |
|
| 2509 |
time_fields_obj_arr.push( {
|
| 2510 |
'name' : text_jquery.attr( 'name' ),
|
| 2511 |
'value_option_24h': text_jquery.val(),
|
| 2512 |
'jquery_option' : text_jquery,
|
| 2513 |
'times_as_seconds': text_times_as_seconds
|
| 2514 |
} );
|
| 2515 |
}
|
| 2516 |
}
|
| 2517 |
|
| 2518 |
return time_fields_obj_arr;
|
| 2519 |
}
|
| 2520 |
|
| 2521 |
|
| 2522 |
|
| 2523 |
// ---------------------------------------------------------------------------------------------------------------------
|
| 2524 |
/* == S U P P O R T for C A L E N D A R ==
|
| 2525 |
// --------------------------------------------------------------------------------------------------------------------- */
|
| 2526 |
|
| 2527 |
/**
|
| 2528 |
* Get Calendar datepick Instance.
|
| 2529 |
*
|
| 2530 |
* @param {int|string} resource_id
|
| 2531 |
* @returns {*|null}
|
| 2532 |
*/
|
| 2533 |
function wpbc_calendar__get_inst(resource_id) {
|
| 2534 |
|
| 2535 |
if ( 'undefined' === typeof (resource_id) ) {
|
| 2536 |
resource_id = '1';
|
| 2537 |
}
|
| 2538 |
|
| 2539 |
if ( jQuery( '#calendar_booking' + resource_id ).length > 0 ) {
|
| 2540 |
|
| 2541 |
try {
|
| 2542 |
var inst = jQuery.datepick._getInst( jQuery( '#calendar_booking' + resource_id ).get( 0 ) );
|
| 2543 |
return inst ? inst : null;
|
| 2544 |
} catch ( e ) {
|
| 2545 |
return null;
|
| 2546 |
}
|
| 2547 |
}
|
| 2548 |
|
| 2549 |
return null;
|
| 2550 |
}
|
| 2551 |
|
| 2552 |
|
| 2553 |
/**
|
| 2554 |
* Unselect all dates in calendar and visually update this calendar
|
| 2555 |
*
|
| 2556 |
* @param resource_id ID of booking resource
|
| 2557 |
* @returns {boolean} true on success | false, if no such calendar
|
| 2558 |
*/
|
| 2559 |
function wpbc_calendar__unselect_all_dates( resource_id ){
|
| 2560 |
|
| 2561 |
if ( 'undefined' === typeof (resource_id) ){
|
| 2562 |
resource_id = '1';
|
| 2563 |
}
|
| 2564 |
|
| 2565 |
wpbc_range_selection__hide_guidance( resource_id );
|
| 2566 |
|
| 2567 |
var inst = wpbc_calendar__get_inst( resource_id )
|
| 2568 |
|
| 2569 |
if ( null !== inst ){
|
| 2570 |
|
| 2571 |
// Unselect all dates and set properties of Datepick
|
| 2572 |
jQuery( '#date_booking' + resource_id ).val( '' ); //FixIn: 5.4.3
|
| 2573 |
inst.stayOpen = false;
|
| 2574 |
inst.dates = [];
|
| 2575 |
jQuery.datepick._updateDatepick( inst );
|
| 2576 |
|
| 2577 |
return true
|
| 2578 |
}
|
| 2579 |
|
| 2580 |
return false;
|
| 2581 |
|
| 2582 |
}
|
| 2583 |
|
| 2584 |
/**
|
| 2585 |
* Clear days highlighting in All or specific Calendars
|
| 2586 |
*
|
| 2587 |
* @param resource_id - can be skiped to clear highlighting in all calendars
|
| 2588 |
*/
|
| 2589 |
function wpbc_calendars__clear_days_highlighting( resource_id ){
|
| 2590 |
|
| 2591 |
if ( 'undefined' !== typeof ( resource_id ) ){
|
| 2592 |
|
| 2593 |
jQuery( '#calendar_booking' + resource_id + ' .datepick-days-cell-over' ).removeClass( 'datepick-days-cell-over' ); // Clear in specific calendar
|
| 2594 |
|
| 2595 |
} else {
|
| 2596 |
jQuery( '.datepick-days-cell-over' ).removeClass( 'datepick-days-cell-over' ); // Clear in all calendars
|
| 2597 |
}
|
| 2598 |
}
|
| 2599 |
|
| 2600 |
/**
|
| 2601 |
* Scroll to specific month in calendar
|
| 2602 |
*
|
| 2603 |
* @param resource_id ID of resource
|
| 2604 |
* @param year - real year - 2023
|
| 2605 |
* @param month - real month - 12
|
| 2606 |
* @returns {boolean}
|
| 2607 |
*/
|
| 2608 |
function wpbc_calendar__scroll_to( resource_id, year, month ){
|
| 2609 |
|
| 2610 |
if ( 'undefined' === typeof (resource_id) ){ resource_id = '1'; }
|
| 2611 |
var inst = wpbc_calendar__get_inst( resource_id )
|
| 2612 |
if ( null !== inst ){
|
| 2613 |
|
| 2614 |
year = parseInt( year );
|
| 2615 |
month = parseInt( month ) - 1; // In JS date, month -1
|
| 2616 |
|
| 2617 |
inst.cursorDate = new Date();
|
| 2618 |
// In some cases, the setFullYear can set only Year, and not the Month and day // FixIn: 6.2.3.5.
|
| 2619 |
inst.cursorDate.setFullYear( year, month, 1 );
|
| 2620 |
inst.cursorDate.setMonth( month );
|
| 2621 |
inst.cursorDate.setDate( 1 );
|
| 2622 |
|
| 2623 |
inst.drawMonth = inst.cursorDate.getMonth();
|
| 2624 |
inst.drawYear = inst.cursorDate.getFullYear();
|
| 2625 |
|
| 2626 |
jQuery.datepick._notifyChange( inst );
|
| 2627 |
jQuery.datepick._adjustInstDate( inst );
|
| 2628 |
jQuery.datepick._showDate( inst );
|
| 2629 |
jQuery.datepick._updateDatepick( inst );
|
| 2630 |
|
| 2631 |
return true;
|
| 2632 |
}
|
| 2633 |
return false;
|
| 2634 |
}
|
| 2635 |
|
| 2636 |
/** |
| 2637 |
* Determine native date selectability without optional date constraints. |
| 2638 |
* |
| 2639 |
* This helper exposes the canonical calendar result for algorithms, such as |
| 2640 |
* gap discovery, that must not consume their own derived constraints. It does |
| 2641 |
* not trigger wpbc_calendar__apply_date_constraints and must remain free of |
| 2642 |
* optional-module state. |
| 2643 |
* |
| 2644 |
* @param {number|string} resource_id Booking resource ID. |
| 2645 |
* @param {string} sql_date Calendar date in YYYY-MM-DD format. |
| 2646 |
* @returns {boolean} True when core calendar data marks the date selectable. |
| 2647 |
*/ |
| 2648 |
function wpbc_is_this_day_selectable__raw( resource_id, sql_date ){ |
| 2649 |
|
| 2650 |
// Get Data -------------------------------------------------------------------------------------------------------- |
| 2651 |
var date_bookings_obj = _wpbc.bookings_in_calendar__get_for_date( resource_id, sql_date ); |
| 2652 |
var is_day_selectable = false; |
| 2653 |
|
| 2654 |
if ( date_bookings_obj && 'undefined' !== typeof ( date_bookings_obj[ 'day_availability' ] ) ) { |
| 2655 |
is_day_selectable = ( parseInt( date_bookings_obj[ 'day_availability' ] ) > 0 ); |
| 2656 |
|
| 2657 |
if ( 'undefined' !== typeof ( date_bookings_obj[ 'summary' ] ) && 'available' != date_bookings_obj[ 'summary']['status_for_day' ] ){ |
| 2658 |
|
| 2659 |
var is_set_pending_days_selectable = _wpbc.calendar__get_param_value( resource_id, 'pending_days_selectable' ); // set pending days selectable // FixIn: 8.6.1.18. |
| 2660 |
var booking_statuses_arr = wpbc_get_booking_statuses__as_arr( date_bookings_obj ); |
| 2661 |
|
| 2662 |
if ( |
| 2663 |
( wpbc_booking_statuses__has( booking_statuses_arr, 'pending' ) ) |
| 2664 |
|| ( wpbc_booking_statuses__has( booking_statuses_arr, 'pending_pending' ) ) |
| 2665 |
|| ( wpbc_booking_statuses__has( booking_statuses_arr, 'pending_approved' ) ) |
| 2666 |
|| ( wpbc_booking_statuses__has( booking_statuses_arr, 'approved_pending' ) ) |
| 2667 |
){ |
| 2668 |
is_day_selectable = (is_day_selectable) ? true : is_set_pending_days_selectable; |
| 2669 |
} |
| 2670 |
} |
| 2671 |
} |
| 2672 |
|
| 2673 |
return Boolean( is_day_selectable ); |
| 2674 |
} |
| 2675 |
|
| 2676 |
/** |
| 2677 |
* Determine final date selectability after native and optional constraints. |
| 2678 |
* |
| 2679 |
* Native unavailability returns immediately. Optional modules may therefore |
| 2680 |
* only block a natively selectable date and can never reopen a core-unavailable |
| 2681 |
* date. |
| 2682 |
* |
| 2683 |
* @param {number|string} resource_id Booking resource ID. |
| 2684 |
* @param {string} sql_date Calendar date in YYYY-MM-DD format. |
| 2685 |
* @returns {boolean} True when the date remains selectable after constraints. |
| 2686 |
*/ |
| 2687 |
function wpbc_is_this_day_selectable( resource_id, sql_date ){ |
| 2688 |
|
| 2689 |
var is_natively_selectable = wpbc_is_this_day_selectable__raw( resource_id, sql_date ); |
| 2690 |
|
| 2691 |
if ( ! is_natively_selectable ) { |
| 2692 |
return false; |
| 2693 |
} |
| 2694 |
|
| 2695 |
return wpbc_calendar__evaluate_date_constraints( resource_id, sql_date, is_natively_selectable, [] ).is_selectable; |
| 2696 |
} |
| 2697 |
|
| 2698 |
/**
|
| 2699 |
* Is date to check IN array of selected dates
|
| 2700 |
*
|
| 2701 |
* @param {date}js_date_to_check - JS Date - simple JavaScript Date object
|
| 2702 |
* @param {[]} js_dates_arr - [ JSDate, ... ] - array of JS dates
|
| 2703 |
* @returns {boolean}
|
| 2704 |
*/
|
| 2705 |
function wpbc_is_this_day_among_selected_days( js_date_to_check, js_dates_arr ){
|
| 2706 |
|
| 2707 |
for ( var date_index = 0; date_index < js_dates_arr.length ; date_index++ ){ // FixIn: 8.4.5.16.
|
| 2708 |
if ( ( js_dates_arr[ date_index ].getFullYear() === js_date_to_check.getFullYear() ) &&
|
| 2709 |
( js_dates_arr[ date_index ].getMonth() === js_date_to_check.getMonth() ) &&
|
| 2710 |
( js_dates_arr[ date_index ].getDate() === js_date_to_check.getDate() ) ) {
|
| 2711 |
return true;
|
| 2712 |
}
|
| 2713 |
}
|
| 2714 |
|
| 2715 |
return false;
|
| 2716 |
}
|
| 2717 |
|
| 2718 |
/**
|
| 2719 |
* Get SQL Class Date '2023-08-01' from JS Date
|
| 2720 |
*
|
| 2721 |
* @param date JS Date
|
| 2722 |
* @returns {string} '2023-08-12'
|
| 2723 |
*/
|
| 2724 |
function wpbc__get__sql_class_date( date ){
|
| 2725 |
|
| 2726 |
var sql_class_day = date.getFullYear() + '-';
|
| 2727 |
sql_class_day += ( ( date.getMonth() + 1 ) < 10 ) ? '0' : '';
|
| 2728 |
sql_class_day += ( date.getMonth() + 1 ) + '-'
|
| 2729 |
sql_class_day += ( date.getDate() < 10 ) ? '0' : '';
|
| 2730 |
sql_class_day += date.getDate();
|
| 2731 |
|
| 2732 |
return sql_class_day;
|
| 2733 |
}
|
| 2734 |
|
| 2735 |
/**
|
| 2736 |
* Get JS Date from the SQL date format '2024-05-14'
|
| 2737 |
* @param sql_class_date
|
| 2738 |
* @returns {Date}
|
| 2739 |
*/
|
| 2740 |
function wpbc__get__js_date( sql_class_date ){
|
| 2741 |
|
| 2742 |
var sql_class_date_arr = sql_class_date.split( '-' );
|
| 2743 |
|
| 2744 |
var date_js = new Date();
|
| 2745 |
|
| 2746 |
date_js.setFullYear( parseInt( sql_class_date_arr[ 0 ] ), (parseInt( sql_class_date_arr[ 1 ] ) - 1), parseInt( sql_class_date_arr[ 2 ] ) ); // year, month, date
|
| 2747 |
|
| 2748 |
// Without this time adjust Dates selection in Datepicker can not work!!!
|
| 2749 |
date_js.setHours(0);
|
| 2750 |
date_js.setMinutes(0);
|
| 2751 |
date_js.setSeconds(0);
|
| 2752 |
date_js.setMilliseconds(0);
|
| 2753 |
|
| 2754 |
return date_js;
|
| 2755 |
}
|
| 2756 |
|
| 2757 |
/**
|
| 2758 |
* Get TD Class Date '1-31-2023' from JS Date
|
| 2759 |
*
|
| 2760 |
* @param date JS Date
|
| 2761 |
* @returns {string} '1-31-2023'
|
| 2762 |
*/
|
| 2763 |
function wpbc__get__td_class_date( date ){
|
| 2764 |
|
| 2765 |
var td_class_day = (date.getMonth() + 1) + '-' + date.getDate() + '-' + date.getFullYear(); // '1-9-2023'
|
| 2766 |
|
| 2767 |
return td_class_day;
|
| 2768 |
}
|
| 2769 |
|
| 2770 |
/**
|
| 2771 |
* Get date params from string date
|
| 2772 |
*
|
| 2773 |
* @param date string date like '31.5.2023'
|
| 2774 |
* @param separator default '.' can be skipped.
|
| 2775 |
* @returns { {date: number, month: number, year: number} }
|
| 2776 |
*/
|
| 2777 |
function wpbc__get__date_params__from_string_date( date , separator){
|
| 2778 |
|
| 2779 |
separator = ( 'undefined' !== typeof (separator) ) ? separator : '.';
|
| 2780 |
|
| 2781 |
var date_arr = date.split( separator );
|
| 2782 |
var date_obj = {
|
| 2783 |
'year' : parseInt( date_arr[ 2 ] ),
|
| 2784 |
'month': (parseInt( date_arr[ 1 ] ) - 1),
|
| 2785 |
'date' : parseInt( date_arr[ 0 ] )
|
| 2786 |
};
|
| 2787 |
return date_obj; // for = new Date( date_obj.year , date_obj.month , date_obj.date );
|
| 2788 |
}
|
| 2789 |
|
| 2790 |
/**
|
| 2791 |
* Add Spin Loader to calendar
|
| 2792 |
* @param resource_id
|
| 2793 |
*/
|
| 2794 |
function wpbc_calendar__loading__start( resource_id ){
|
| 2795 |
if ( ! jQuery( '#calendar_booking' + resource_id ).next().hasClass( 'wpbc_spins_loader_wrapper' ) ){
|
| 2796 |
jQuery( '#calendar_booking' + resource_id ).after( '<div class="wpbc_spins_loader_wrapper"><div class="wpbc_spin_loader_one_new"></div></div>' );
|
| 2797 |
}
|
| 2798 |
if ( ! jQuery( '#calendar_booking' + resource_id ).hasClass( 'wpbc_calendar_blur_small' ) ){
|
| 2799 |
jQuery( '#calendar_booking' + resource_id ).addClass( 'wpbc_calendar_blur_small' );
|
| 2800 |
}
|
| 2801 |
wpbc_calendar__blur__start( resource_id );
|
| 2802 |
}
|
| 2803 |
|
| 2804 |
/**
|
| 2805 |
* Remove Spin Loader to calendar
|
| 2806 |
* @param resource_id
|
| 2807 |
*/
|
| 2808 |
function wpbc_calendar__loading__stop( resource_id ){
|
| 2809 |
jQuery( '#calendar_booking' + resource_id + ' + .wpbc_spins_loader_wrapper' ).remove();
|
| 2810 |
jQuery( '#calendar_booking' + resource_id ).removeClass( 'wpbc_calendar_blur_small' );
|
| 2811 |
wpbc_calendar__blur__stop( resource_id );
|
| 2812 |
}
|
| 2813 |
|
| 2814 |
/**
|
| 2815 |
* Add Blur to calendar
|
| 2816 |
* @param resource_id
|
| 2817 |
*/
|
| 2818 |
function wpbc_calendar__blur__start( resource_id ){
|
| 2819 |
if ( ! jQuery( '#calendar_booking' + resource_id ).hasClass( 'wpbc_calendar_blur' ) ){
|
| 2820 |
jQuery( '#calendar_booking' + resource_id ).addClass( 'wpbc_calendar_blur' );
|
| 2821 |
}
|
| 2822 |
}
|
| 2823 |
|
| 2824 |
/**
|
| 2825 |
* Remove Blur in calendar
|
| 2826 |
* @param resource_id
|
| 2827 |
*/
|
| 2828 |
function wpbc_calendar__blur__stop( resource_id ){
|
| 2829 |
jQuery( '#calendar_booking' + resource_id ).removeClass( 'wpbc_calendar_blur' );
|
| 2830 |
}
|
| 2831 |
|
| 2832 |
|
| 2833 |
// .................................................................................................................
|
| 2834 |
/* == Calendar Update - View ==
|
| 2835 |
// ................................................................................................................. */
|
| 2836 |
|
| 2837 |
/**
|
| 2838 |
* Update look of calendar (safe).
|
| 2839 |
*
|
| 2840 |
* In Elementor preview the DOM can be re-rendered, so the calendar element may exist
|
| 2841 |
* while the Datepick instance is missing. In that case try to (re)initialize.
|
| 2842 |
*
|
| 2843 |
* @param {int|string} resource_id
|
| 2844 |
* @return {boolean} true if updated, false if not possible
|
| 2845 |
*/
|
| 2846 |
function wpbc_calendar__update_look(resource_id) {
|
| 2847 |
|
| 2848 |
var inst = wpbc_calendar__get_inst( resource_id );
|
| 2849 |
|
| 2850 |
// If instance missing, try to re-init calendar once.
|
| 2851 |
if ( null === inst ) {
|
| 2852 |
|
| 2853 |
var jq_cal = jQuery( '#calendar_booking' + resource_id );
|
| 2854 |
|
| 2855 |
if ( jq_cal.length && ('function' === typeof wpbc_calendar_show) ) {
|
| 2856 |
|
| 2857 |
// Elementor sometimes leaves stale class without real instance.
|
| 2858 |
if ( jq_cal.hasClass( 'hasDatepick' ) ) {
|
| 2859 |
jq_cal.removeClass( 'hasDatepick' );
|
| 2860 |
}
|
| 2861 |
|
| 2862 |
// Try to init datepick markup now.
|
| 2863 |
wpbc_calendar_show( resource_id );
|
| 2864 |
|
| 2865 |
// Try again.
|
| 2866 |
inst = wpbc_calendar__get_inst( resource_id );
|
| 2867 |
}
|
| 2868 |
}
|
| 2869 |
|
| 2870 |
// Still no instance -> do not crash the whole ajax flow.
|
| 2871 |
if ( null === inst ) {
|
| 2872 |
return false;
|
| 2873 |
}
|
| 2874 |
|
| 2875 |
jQuery.datepick._updateDatepick( inst );
|
| 2876 |
return true;
|
| 2877 |
}
|
| 2878 |
|
| 2879 |
|
| 2880 |
|
| 2881 |
/**
|
| 2882 |
* Update dynamically Number of Months in calendar
|
| 2883 |
*
|
| 2884 |
* @param resource_id int
|
| 2885 |
* @param months_number int
|
| 2886 |
*/
|
| 2887 |
function wpbc_calendar__update_months_number( resource_id, months_number ){
|
| 2888 |
var inst = wpbc_calendar__get_inst( resource_id );
|
| 2889 |
if ( null !== inst ){
|
| 2890 |
inst.settings[ 'numberOfMonths' ] = months_number;
|
| 2891 |
//_wpbc.calendar__set_param_value( resource_id, 'calendar_number_of_months', months_number );
|
| 2892 |
wpbc_calendar__update_look( resource_id );
|
| 2893 |
}
|
| 2894 |
}
|
| 2895 |
|
| 2896 |
|
| 2897 |
/**
|
| 2898 |
* Show calendar in different Skin
|
| 2899 |
*
|
| 2900 |
* @param selected_skin_url
|
| 2901 |
*/
|
| 2902 |
function wpbc__calendar__change_skin( selected_skin_url ){
|
| 2903 |
|
| 2904 |
//console.log( 'SKIN SELECTION ::', selected_skin_url );
|
| 2905 |
|
| 2906 |
// Remove CSS skin
|
| 2907 |
var stylesheet = document.getElementById( 'wpbc-calendar-skin-css' );
|
| 2908 |
stylesheet.parentNode.removeChild( stylesheet );
|
| 2909 |
|
| 2910 |
|
| 2911 |
// Add new CSS skin
|
| 2912 |
var headID = document.getElementsByTagName( "head" )[ 0 ];
|
| 2913 |
var cssNode = document.createElement( 'link' );
|
| 2914 |
cssNode.type = 'text/css';
|
| 2915 |
cssNode.setAttribute( "id", "wpbc-calendar-skin-css" );
|
| 2916 |
cssNode.rel = 'stylesheet';
|
| 2917 |
cssNode.media = 'screen';
|
| 2918 |
cssNode.href = selected_skin_url; //"http://beta/wp-content/plugins/booking/css/skins/green-01.css";
|
| 2919 |
headID.appendChild( cssNode );
|
| 2920 |
}
|
| 2921 |
|
| 2922 |
|
| 2923 |
function wpbc__css__change_skin( selected_skin_url, stylesheet_id = 'wpbc-time_picker-skin-css' ){
|
| 2924 |
|
| 2925 |
// Remove CSS skin
|
| 2926 |
var stylesheet = document.getElementById( stylesheet_id );
|
| 2927 |
stylesheet.parentNode.removeChild( stylesheet );
|
| 2928 |
|
| 2929 |
|
| 2930 |
// Add new CSS skin
|
| 2931 |
var headID = document.getElementsByTagName( "head" )[ 0 ];
|
| 2932 |
var cssNode = document.createElement( 'link' );
|
| 2933 |
cssNode.type = 'text/css';
|
| 2934 |
cssNode.setAttribute( "id", stylesheet_id );
|
| 2935 |
cssNode.rel = 'stylesheet';
|
| 2936 |
cssNode.media = 'screen';
|
| 2937 |
cssNode.href = selected_skin_url; //"http://beta/wp-content/plugins/booking/css/skins/green-01.css";
|
| 2938 |
headID.appendChild( cssNode );
|
| 2939 |
}
|
| 2940 |
|
| 2941 |
|
| 2942 |
// ---------------------------------------------------------------------------------------------------------------------
|
| 2943 |
/* == S U P P O R T M A T H ==
|
| 2944 |
// --------------------------------------------------------------------------------------------------------------------- */
|
| 2945 |
|
| 2946 |
/**
|
| 2947 |
* Merge several intersected intervals or return not intersected:
|
| 2948 |
* [[1,3],[2,6],[8,10],[15,18]] -> [[1,6],[8,10],[15,18]]
|
| 2949 |
*
|
| 2950 |
* @param [] intervals [ [1,3],[2,4],[6,8],[9,10],[3,7] ]
|
| 2951 |
* @returns [] [ [1,8],[9,10] ]
|
| 2952 |
*
|
| 2953 |
* Exmample: wpbc_intervals__merge_inersected( [ [1,3],[2,4],[6,8],[9,10],[3,7] ] );
|
| 2954 |
*/
|
| 2955 |
function wpbc_intervals__merge_inersected( intervals ){
|
| 2956 |
|
| 2957 |
if ( ! intervals || intervals.length === 0 ){
|
| 2958 |
return [];
|
| 2959 |
}
|
| 2960 |
|
| 2961 |
var merged = [];
|
| 2962 |
intervals.sort( function ( a, b ){
|
| 2963 |
return a[ 0 ] - b[ 0 ];
|
| 2964 |
} );
|
| 2965 |
|
| 2966 |
var mergedInterval = intervals[ 0 ];
|
| 2967 |
|
| 2968 |
for ( var i = 1; i < intervals.length; i++ ){
|
| 2969 |
var interval = intervals[ i ];
|
| 2970 |
|
| 2971 |
if ( interval[ 0 ] <= mergedInterval[ 1 ] ){
|
| 2972 |
mergedInterval[ 1 ] = Math.max( mergedInterval[ 1 ], interval[ 1 ] );
|
| 2973 |
} else {
|
| 2974 |
merged.push( mergedInterval );
|
| 2975 |
mergedInterval = interval;
|
| 2976 |
}
|
| 2977 |
}
|
| 2978 |
|
| 2979 |
merged.push( mergedInterval );
|
| 2980 |
return merged;
|
| 2981 |
}
|
| 2982 |
|
| 2983 |
|
| 2984 |
/**
|
| 2985 |
* Is 2 intervals intersected: [36011, 86392] <=> [1, 43192] => true ( intersected )
|
| 2986 |
*
|
| 2987 |
* Good explanation here
|
| 2988 |
* https://stackoverflow.com/questions/3269434/whats-the-most-efficient-way-to-test-if-two-ranges-overlap
|
| 2989 |
*
|
| 2990 |
* @param interval_A - [ 36011, 86392 ]
|
| 2991 |
* @param interval_B - [ 1, 43192 ]
|
| 2992 |
*
|
| 2993 |
* @return bool
|
| 2994 |
*/
|
| 2995 |
function wpbc_intervals__is_intersected( interval_A, interval_B ) {
|
| 2996 |
|
| 2997 |
if (
|
| 2998 |
( 0 == interval_A.length )
|
| 2999 |
|| ( 0 == interval_B.length )
|
| 3000 |
){
|
| 3001 |
return false;
|
| 3002 |
}
|
| 3003 |
|
| 3004 |
interval_A[ 0 ] = parseInt( interval_A[ 0 ] );
|
| 3005 |
interval_A[ 1 ] = parseInt( interval_A[ 1 ] );
|
| 3006 |
interval_B[ 0 ] = parseInt( interval_B[ 0 ] );
|
| 3007 |
interval_B[ 1 ] = parseInt( interval_B[ 1 ] );
|
| 3008 |
|
| 3009 |
var is_intersected = Math.max( interval_A[ 0 ], interval_B[ 0 ] ) - Math.min( interval_A[ 1 ], interval_B[ 1 ] );
|
| 3010 |
|
| 3011 |
// if ( 0 == is_intersected ) {
|
| 3012 |
// // Such ranges going one after other, e.g.: [ 12, 15 ] and [ 15, 21 ]
|
| 3013 |
// }
|
| 3014 |
|
| 3015 |
if ( is_intersected < 0 ) {
|
| 3016 |
return true; // INTERSECTED
|
| 3017 |
}
|
| 3018 |
|
| 3019 |
return false; // Not intersected
|
| 3020 |
}
|
| 3021 |
|
| 3022 |
|
| 3023 |
/**
|
| 3024 |
* Get the closets ABS value of element in array to the current myValue
|
| 3025 |
*
|
| 3026 |
* @param myValue - int element to search closet 4
|
| 3027 |
* @param myArray - array of elements where to search [5,8,1,7]
|
| 3028 |
* @returns int 5
|
| 3029 |
*/
|
| 3030 |
function wpbc_get_abs_closest_value_in_arr( myValue, myArray ){
|
| 3031 |
|
| 3032 |
if ( myArray.length == 0 ){ // If the array is empty -> return the myValue
|
| 3033 |
return myValue;
|
| 3034 |
}
|
| 3035 |
|
| 3036 |
var obj = myArray[ 0 ];
|
| 3037 |
var diff = Math.abs( myValue - obj ); // Get distance between 1st element
|
| 3038 |
var closetValue = myArray[ 0 ]; // Save 1st element
|
| 3039 |
|
| 3040 |
for ( var i = 1; i < myArray.length; i++ ){
|
| 3041 |
obj = myArray[ i ];
|
| 3042 |
|
| 3043 |
if ( Math.abs( myValue - obj ) < diff ){ // we found closer value -> save it
|
| 3044 |
diff = Math.abs( myValue - obj );
|
| 3045 |
closetValue = obj;
|
| 3046 |
}
|
| 3047 |
}
|
| 3048 |
|
| 3049 |
return closetValue;
|
| 3050 |
}
|
| 3051 |
|
| 3052 |
|
| 3053 |
// ---------------------------------------------------------------------------------------------------------------------
|
| 3054 |
/* == T O O L T I P S ==
|
| 3055 |
// --------------------------------------------------------------------------------------------------------------------- */
|
| 3056 |
|
| 3057 |
/**
|
| 3058 |
* Define tooltip to show, when mouse over Date in Calendar
|
| 3059 |
*
|
| 3060 |
* @param tooltip_text - Text to show 'Booked time: 12:00 - 13:00<br>Cost: $20.00'
|
| 3061 |
* @param resource_id - ID of booking resource '1'
|
| 3062 |
* @param td_class - SQL class '1-9-2023'
|
| 3063 |
* @returns {boolean} - defined to show or not
|
| 3064 |
*/
|
| 3065 |
function wpbc_set_tooltip___for__calendar_date( tooltip_text, resource_id, td_class ){
|
| 3066 |
|
| 3067 |
//TODO: make escaping of text for quot symbols, and JS/HTML...
|
| 3068 |
|
| 3069 |
jQuery( '#calendar_booking' + resource_id + ' td.cal4date-' + td_class ).attr( 'data-content', tooltip_text );
|
| 3070 |
|
| 3071 |
var td_el = jQuery( '#calendar_booking' + resource_id + ' td.cal4date-' + td_class ).get( 0 ); // FixIn: 9.0.1.1.
|
| 3072 |
|
| 3073 |
if (
|
| 3074 |
( 'undefined' !== typeof(td_el) )
|
| 3075 |
&& ( undefined == td_el._tippy )
|
| 3076 |
&& ( '' !== tooltip_text )
|
| 3077 |
){
|
| 3078 |
|
| 3079 |
wpbc_tippy( td_el , {
|
| 3080 |
content( reference ){
|
| 3081 |
|
| 3082 |
var popover_content = reference.getAttribute( 'data-content' );
|
| 3083 |
|
| 3084 |
return '<div class="popover popover_tippy">'
|
| 3085 |
+ '<div class="popover-content">'
|
| 3086 |
+ popover_content
|
| 3087 |
+ '</div>'
|
| 3088 |
+ '</div>';
|
| 3089 |
},
|
| 3090 |
allowHTML : true,
|
| 3091 |
trigger : 'mouseenter focus',
|
| 3092 |
interactive : false,
|
| 3093 |
hideOnClick : true,
|
| 3094 |
interactiveBorder: 10,
|
| 3095 |
maxWidth : 550,
|
| 3096 |
theme : 'wpbc-tippy-times',
|
| 3097 |
placement : 'top',
|
| 3098 |
delay : [400, 0], // FixIn: 9.4.2.2.
|
| 3099 |
//delay : [0, 9999999999], // Debuge tooltip
|
| 3100 |
ignoreAttributes : true,
|
| 3101 |
touch : true, //['hold', 500], // 500ms delay // FixIn: 9.2.1.5.
|
| 3102 |
appendTo: () => document.body,
|
| 3103 |
});
|
| 3104 |
|
| 3105 |
return true;
|
| 3106 |
}
|
| 3107 |
|
| 3108 |
return false;
|
| 3109 |
}
|
| 3110 |
|
| 3111 |
|
| 3112 |
// ---------------------------------------------------------------------------------------------------------------------
|
| 3113 |
/* == Dates Functions ==
|
| 3114 |
// --------------------------------------------------------------------------------------------------------------------- */
|
| 3115 |
|
| 3116 |
/**
|
| 3117 |
* Get number of dates between 2 JS Dates
|
| 3118 |
*
|
| 3119 |
* @param date1 JS Date
|
| 3120 |
* @param date2 JS Date
|
| 3121 |
* @returns {number}
|
| 3122 |
*/
|
| 3123 |
function wpbc_dates__days_between(date1, date2) {
|
| 3124 |
|
| 3125 |
// The number of milliseconds in one day
|
| 3126 |
var ONE_DAY = 1000 * 60 * 60 * 24;
|
| 3127 |
|
| 3128 |
// Convert both dates to milliseconds
|
| 3129 |
var date1_ms = date1.getTime();
|
| 3130 |
var date2_ms = date2.getTime();
|
| 3131 |
|
| 3132 |
// Calculate the difference in milliseconds
|
| 3133 |
var difference_ms = date1_ms - date2_ms;
|
| 3134 |
|
| 3135 |
// Convert back to days and return
|
| 3136 |
return Math.round(difference_ms/ONE_DAY);
|
| 3137 |
}
|
| 3138 |
|
| 3139 |
|
| 3140 |
/**
|
| 3141 |
* Check if this array of dates is consecutive array of dates or not.
|
| 3142 |
* e.g. ['2024-05-09','2024-05-19','2024-05-30'] -> false
|
| 3143 |
* e.g. ['2024-05-09','2024-05-10','2024-05-11'] -> true
|
| 3144 |
* @param sql_dates_arr array e.g.: ['2024-05-09','2024-05-19','2024-05-30']
|
| 3145 |
* @returns {boolean}
|
| 3146 |
*/
|
| 3147 |
function wpbc_dates__is_consecutive_dates_arr_range( sql_dates_arr ){ // FixIn: 10.0.0.50.
|
| 3148 |
|
| 3149 |
if ( sql_dates_arr.length > 1 ){
|
| 3150 |
var previos_date = wpbc__get__js_date( sql_dates_arr[ 0 ] );
|
| 3151 |
var current_date;
|
| 3152 |
|
| 3153 |
for ( var i = 1; i < sql_dates_arr.length; i++ ){
|
| 3154 |
current_date = wpbc__get__js_date( sql_dates_arr[i] );
|
| 3155 |
|
| 3156 |
if ( wpbc_dates__days_between( current_date, previos_date ) != 1 ){
|
| 3157 |
return false;
|
| 3158 |
}
|
| 3159 |
|
| 3160 |
previos_date = current_date;
|
| 3161 |
}
|
| 3162 |
}
|
| 3163 |
|
| 3164 |
return true;
|
| 3165 |
}
|
| 3166 |
|
| 3167 |
|
| 3168 |
// ---------------------------------------------------------------------------------------------------------------------
|
| 3169 |
/* == Auto Dates Selection ==
|
| 3170 |
// --------------------------------------------------------------------------------------------------------------------- */
|
| 3171 |
|
| 3172 |
/**
|
| 3173 |
* == How to use ? ==
|
| 3174 |
*
|
| 3175 |
* For Dates selection, we need to use this logic! We need select the dates only after booking data loaded!
|
| 3176 |
*
|
| 3177 |
* Check example bellow.
|
| 3178 |
*
|
| 3179 |
* // Fire on all booking dates loaded
|
| 3180 |
* jQuery( 'body' ).on( 'wpbc_calendar_ajx__loaded_data', function ( event, loaded_resource_id ){
|
| 3181 |
*
|
| 3182 |
* if ( loaded_resource_id == select_dates_in_calendar_id ){
|
| 3183 |
* wpbc_auto_select_dates_in_calendar( select_dates_in_calendar_id, '2024-05-15', '2024-05-25' );
|
| 3184 |
* }
|
| 3185 |
* } );
|
| 3186 |
*
|
| 3187 |
*/
|
| 3188 |
|
| 3189 |
|
| 3190 |
/**
|
| 3191 |
* Try to Auto select dates in specific calendar by simulated clicks in datepicker
|
| 3192 |
*
|
| 3193 |
* @param resource_id 1
|
| 3194 |
* @param check_in_ymd '2024-05-09' OR ['2024-05-09','2024-05-19','2024-05-20']
|
| 3195 |
* @param check_out_ymd '2024-05-15' Optional
|
| 3196 |
*
|
| 3197 |
* @returns {number} number of selected dates
|
| 3198 |
*
|
| 3199 |
* Example 1: var num_selected_days = wpbc_auto_select_dates_in_calendar( 1, '2024-05-15',
|
| 3200 |
* '2024-05-25' ); Example 2: var num_selected_days = wpbc_auto_select_dates_in_calendar( 1,
|
| 3201 |
* ['2024-05-09','2024-05-19','2024-05-20'] );
|
| 3202 |
*/
|
| 3203 |
function wpbc_auto_select_dates_in_calendar( resource_id, check_in_ymd, check_out_ymd = '' ){ // FixIn: 10.0.0.47.
|
| 3204 |
|
| 3205 |
console.log( 'WPBC_AUTO_SELECT_DATES_IN_CALENDAR( RESOURCE_ID, CHECK_IN_YMD, CHECK_OUT_YMD )', resource_id, check_in_ymd, check_out_ymd );
|
| 3206 |
|
| 3207 |
if (
|
| 3208 |
( '2100-01-01' == check_in_ymd )
|
| 3209 |
|| ( '2100-01-01' == check_out_ymd )
|
| 3210 |
|| ( ( '' == check_in_ymd ) && ( '' == check_out_ymd ) )
|
| 3211 |
){
|
| 3212 |
return 0;
|
| 3213 |
}
|
| 3214 |
|
| 3215 |
// -----------------------------------------------------------------------------------------------------------------
|
| 3216 |
// If check_in_ymd = [ '2024-05-09','2024-05-19','2024-05-30' ] ARRAY of DATES // FixIn: 10.0.0.50.
|
| 3217 |
// -----------------------------------------------------------------------------------------------------------------
|
| 3218 |
var dates_to_select_arr = [];
|
| 3219 |
if ( Array.isArray( check_in_ymd ) ){
|
| 3220 |
dates_to_select_arr = wpbc_clone_obj( check_in_ymd );
|
| 3221 |
|
| 3222 |
// -------------------------------------------------------------------------------------------------------------
|
| 3223 |
// Exceptions to set MULTIPLE DAYS mode
|
| 3224 |
// -------------------------------------------------------------------------------------------------------------
|
| 3225 |
// if dates as NOT CONSECUTIVE: ['2024-05-09','2024-05-19','2024-05-30'], -> set MULTIPLE DAYS mode
|
| 3226 |
if (
|
| 3227 |
( dates_to_select_arr.length > 0 )
|
| 3228 |
&& ( '' == check_out_ymd )
|
| 3229 |
&& ( ! wpbc_dates__is_consecutive_dates_arr_range( dates_to_select_arr ) )
|
| 3230 |
){
|
| 3231 |
wpbc_cal_days_select__multiple( resource_id );
|
| 3232 |
}
|
| 3233 |
// if multiple days to select, but enabled SINGLE day mode, -> set MULTIPLE DAYS mode
|
| 3234 |
if (
|
| 3235 |
( dates_to_select_arr.length > 1 )
|
| 3236 |
&& ( '' == check_out_ymd )
|
| 3237 |
&& ( 'single' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ) )
|
| 3238 |
){
|
| 3239 |
wpbc_cal_days_select__multiple( resource_id );
|
| 3240 |
}
|
| 3241 |
// -------------------------------------------------------------------------------------------------------------
|
| 3242 |
check_in_ymd = dates_to_select_arr[ 0 ];
|
| 3243 |
if ( '' == check_out_ymd ){
|
| 3244 |
check_out_ymd = dates_to_select_arr[ (dates_to_select_arr.length-1) ];
|
| 3245 |
}
|
| 3246 |
}
|
| 3247 |
// -----------------------------------------------------------------------------------------------------------------
|
| 3248 |
|
| 3249 |
|
| 3250 |
if ( '' == check_in_ymd ){
|
| 3251 |
check_in_ymd = check_out_ymd;
|
| 3252 |
}
|
| 3253 |
if ( '' == check_out_ymd ){
|
| 3254 |
check_out_ymd = check_in_ymd;
|
| 3255 |
}
|
| 3256 |
|
| 3257 |
if ( 'undefined' === typeof (resource_id) ){
|
| 3258 |
resource_id = '1';
|
| 3259 |
}
|
| 3260 |
|
| 3261 |
|
| 3262 |
var inst = wpbc_calendar__get_inst( resource_id );
|
| 3263 |
|
| 3264 |
if ( null !== inst ){
|
| 3265 |
|
| 3266 |
// Unselect all dates and set properties of Datepick
|
| 3267 |
jQuery( '#date_booking' + resource_id ).val( '' ); //FixIn: 5.4.3
|
| 3268 |
inst.stayOpen = false;
|
| 3269 |
inst.dates = [];
|
| 3270 |
var check_in_js = wpbc__get__js_date( check_in_ymd );
|
| 3271 |
var td_cell = wpbc_get_clicked_td( inst.id, check_in_js );
|
| 3272 |
|
| 3273 |
// Is ome type of error, then select multiple days selection mode.
|
| 3274 |
if ( '' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ) ) {
|
| 3275 |
_wpbc.calendar__set_param_value( resource_id, 'days_select_mode', 'multiple' );
|
| 3276 |
}
|
| 3277 |
|
| 3278 |
|
| 3279 |
// ---------------------------------------------------------------------------------------------------------
|
| 3280 |
// == DYNAMIC ==
|
| 3281 |
if ( 'dynamic' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ) ){
|
| 3282 |
// 1-st click
|
| 3283 |
inst.stayOpen = false;
|
| 3284 |
jQuery.datepick._selectDay( td_cell, '#' + inst.id, check_in_js.getTime() );
|
| 3285 |
if ( 0 === inst.dates.length ){
|
| 3286 |
return 0; // First click was unsuccessful, so we must not make other click
|
| 3287 |
}
|
| 3288 |
|
| 3289 |
// 2-nd click
|
| 3290 |
var check_out_js = wpbc__get__js_date( check_out_ymd );
|
| 3291 |
var td_cell_out = wpbc_get_clicked_td( inst.id, check_out_js );
|
| 3292 |
inst.stayOpen = true;
|
| 3293 |
jQuery.datepick._selectDay( td_cell_out, '#' + inst.id, check_out_js.getTime() );
|
| 3294 |
}
|
| 3295 |
|
| 3296 |
// ---------------------------------------------------------------------------------------------------------
|
| 3297 |
// == FIXED ==
|
| 3298 |
if ( 'fixed' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' )) {
|
| 3299 |
jQuery.datepick._selectDay( td_cell, '#' + inst.id, check_in_js.getTime() );
|
| 3300 |
}
|
| 3301 |
|
| 3302 |
// ---------------------------------------------------------------------------------------------------------
|
| 3303 |
// == SINGLE ==
|
| 3304 |
if ( 'single' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ) ){
|
| 3305 |
//jQuery.datepick._restrictMinMax( inst, jQuery.datepick._determineDate( inst, check_in_js, null ) ); // Do we need to run this ? Please note, check_in_js must have time, min, sec defined to 0!
|
| 3306 |
jQuery.datepick._selectDay( td_cell, '#' + inst.id, check_in_js.getTime() );
|
| 3307 |
}
|
| 3308 |
|
| 3309 |
// ---------------------------------------------------------------------------------------------------------
|
| 3310 |
// == MULTIPLE ==
|
| 3311 |
if ( 'multiple' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ) ){
|
| 3312 |
|
| 3313 |
var dates_arr;
|
| 3314 |
|
| 3315 |
if ( dates_to_select_arr.length > 0 ){
|
| 3316 |
// Situation, when we have dates array: ['2024-05-09','2024-05-19','2024-05-30']. and not the Check In / Check out dates as parameter in this function
|
| 3317 |
dates_arr = wpbc_get_selection_dates_js_str_arr__from_arr( dates_to_select_arr );
|
| 3318 |
} else {
|
| 3319 |
dates_arr = wpbc_get_selection_dates_js_str_arr__from_check_in_out( check_in_ymd, check_out_ymd, inst );
|
| 3320 |
}
|
| 3321 |
|
| 3322 |
if ( 0 === dates_arr.dates_js.length ){
|
| 3323 |
return 0;
|
| 3324 |
}
|
| 3325 |
|
| 3326 |
// For Calendar Days selection
|
| 3327 |
for ( var j = 0; j < dates_arr.dates_js.length; j++ ){ // Loop array of dates
|
| 3328 |
|
| 3329 |
var str_date = wpbc__get__sql_class_date( dates_arr.dates_js[ j ] );
|
| 3330 |
|
| 3331 |
// Date unavailable !
|
| 3332 |
if ( 0 == _wpbc.bookings_in_calendar__get_for_date( resource_id, str_date ).day_availability ){
|
| 3333 |
return 0;
|
| 3334 |
}
|
| 3335 |
|
| 3336 |
if ( dates_arr.dates_js[ j ] != -1 ) {
|
| 3337 |
inst.dates.push( dates_arr.dates_js[ j ] );
|
| 3338 |
}
|
| 3339 |
}
|
| 3340 |
|
| 3341 |
var check_out_date = dates_arr.dates_js[ (dates_arr.dates_js.length - 1) ];
|
| 3342 |
|
| 3343 |
inst.dates.push( check_out_date ); // Need add one additional SAME date for correct works of dates selection !!!!!
|
| 3344 |
|
| 3345 |
var checkout_timestamp = check_out_date.getTime();
|
| 3346 |
var td_cell = wpbc_get_clicked_td( inst.id, check_out_date );
|
| 3347 |
|
| 3348 |
jQuery.datepick._selectDay( td_cell, '#' + inst.id, checkout_timestamp );
|
| 3349 |
}
|
| 3350 |
|
| 3351 |
|
| 3352 |
if ( 0 !== inst.dates.length ){
|
| 3353 |
// Scroll to specific month, if we set dates in some future months
|
| 3354 |
wpbc_calendar__scroll_to( resource_id, inst.dates[ 0 ].getFullYear(), inst.dates[ 0 ].getMonth()+1 );
|
| 3355 |
}
|
| 3356 |
|
| 3357 |
return wpbc_get__selected_dates_sql__as_arr( resource_id ).length; |
| 3358 |
}
|
| 3359 |
|
| 3360 |
return 0;
|
| 3361 |
}
|
| 3362 |
|
| 3363 |
/**
|
| 3364 |
* Get HTML td element (where was click in calendar day cell)
|
| 3365 |
*
|
| 3366 |
* @param calendar_html_id 'calendar_booking1'
|
| 3367 |
* @param date_js JS Date
|
| 3368 |
* @returns {*|jQuery} Dom HTML td element
|
| 3369 |
*/
|
| 3370 |
function wpbc_get_clicked_td( calendar_html_id, date_js ){
|
| 3371 |
|
| 3372 |
var td_cell = jQuery( '#' + calendar_html_id + ' .sql_date_' + wpbc__get__sql_class_date( date_js ) ).get( 0 );
|
| 3373 |
|
| 3374 |
return td_cell;
|
| 3375 |
}
|
| 3376 |
|
| 3377 |
/**
|
| 3378 |
* Get arrays of JS and SQL dates as dates array
|
| 3379 |
*
|
| 3380 |
* @param check_in_ymd '2024-05-15'
|
| 3381 |
* @param check_out_ymd '2024-05-25'
|
| 3382 |
* @param inst Datepick Inst. Use wpbc_calendar__get_inst( resource_id );
|
| 3383 |
* @returns {{dates_js: *[], dates_str: *[]}}
|
| 3384 |
*/
|
| 3385 |
function wpbc_get_selection_dates_js_str_arr__from_check_in_out( check_in_ymd, check_out_ymd , inst ){
|
| 3386 |
|
| 3387 |
var original_array = [];
|
| 3388 |
var date;
|
| 3389 |
var bk_distinct_dates = [];
|
| 3390 |
|
| 3391 |
var check_in_date = check_in_ymd.split( '-' );
|
| 3392 |
var check_out_date = check_out_ymd.split( '-' );
|
| 3393 |
|
| 3394 |
date = new Date();
|
| 3395 |
date.setFullYear( check_in_date[ 0 ], (check_in_date[ 1 ] - 1), check_in_date[ 2 ] ); // year, month, date
|
| 3396 |
var original_check_in_date = date;
|
| 3397 |
original_array.push( jQuery.datepick._restrictMinMax( inst, jQuery.datepick._determineDate( inst, date, null ) ) ); //add date
|
| 3398 |
if ( ! wpbc_in_array( bk_distinct_dates, (check_in_date[ 2 ] + '.' + check_in_date[ 1 ] + '.' + check_in_date[ 0 ]) ) ){
|
| 3399 |
bk_distinct_dates.push( parseInt(check_in_date[ 2 ]) + '.' + parseInt(check_in_date[ 1 ]) + '.' + check_in_date[ 0 ] );
|
| 3400 |
}
|
| 3401 |
|
| 3402 |
var date_out = new Date();
|
| 3403 |
date_out.setFullYear( check_out_date[ 0 ], (check_out_date[ 1 ] - 1), check_out_date[ 2 ] ); // year, month, date
|
| 3404 |
var original_check_out_date = date_out;
|
| 3405 |
|
| 3406 |
var mewDate = new Date( original_check_in_date.getFullYear(), original_check_in_date.getMonth(), original_check_in_date.getDate() );
|
| 3407 |
mewDate.setDate( original_check_in_date.getDate() + 1 );
|
| 3408 |
|
| 3409 |
while (
|
| 3410 |
(original_check_out_date > date) &&
|
| 3411 |
(original_check_in_date != original_check_out_date) ){
|
| 3412 |
date = new Date( mewDate.getFullYear(), mewDate.getMonth(), mewDate.getDate() );
|
| 3413 |
|
| 3414 |
original_array.push( jQuery.datepick._restrictMinMax( inst, jQuery.datepick._determineDate( inst, date, null ) ) ); //add date
|
| 3415 |
if ( !wpbc_in_array( bk_distinct_dates, (date.getDate() + '.' + parseInt( date.getMonth() + 1 ) + '.' + date.getFullYear()) ) ){
|
| 3416 |
bk_distinct_dates.push( (parseInt(date.getDate()) + '.' + parseInt( date.getMonth() + 1 ) + '.' + date.getFullYear()) );
|
| 3417 |
}
|
| 3418 |
|
| 3419 |
mewDate = new Date( date.getFullYear(), date.getMonth(), date.getDate() );
|
| 3420 |
mewDate.setDate( mewDate.getDate() + 1 );
|
| 3421 |
}
|
| 3422 |
original_array.pop();
|
| 3423 |
bk_distinct_dates.pop();
|
| 3424 |
|
| 3425 |
return {'dates_js': original_array, 'dates_str': bk_distinct_dates};
|
| 3426 |
}
|
| 3427 |
|
| 3428 |
/**
|
| 3429 |
* Get arrays of JS and SQL dates as dates array
|
| 3430 |
*
|
| 3431 |
* @param dates_to_select_arr = ['2024-05-09','2024-05-19','2024-05-30']
|
| 3432 |
*
|
| 3433 |
* @returns {{dates_js: *[], dates_str: *[]}}
|
| 3434 |
*/
|
| 3435 |
function wpbc_get_selection_dates_js_str_arr__from_arr( dates_to_select_arr ){ // FixIn: 10.0.0.50.
|
| 3436 |
|
| 3437 |
var original_array = [];
|
| 3438 |
var bk_distinct_dates = [];
|
| 3439 |
var one_date_str;
|
| 3440 |
|
| 3441 |
for ( var d = 0; d < dates_to_select_arr.length; d++ ){
|
| 3442 |
|
| 3443 |
original_array.push( wpbc__get__js_date( dates_to_select_arr[ d ] ) );
|
| 3444 |
|
| 3445 |
one_date_str = dates_to_select_arr[ d ].split('-')
|
| 3446 |
if ( ! wpbc_in_array( bk_distinct_dates, (one_date_str[ 2 ] + '.' + one_date_str[ 1 ] + '.' + one_date_str[ 0 ]) ) ){
|
| 3447 |
bk_distinct_dates.push( parseInt(one_date_str[ 2 ]) + '.' + parseInt(one_date_str[ 1 ]) + '.' + one_date_str[ 0 ] );
|
| 3448 |
}
|
| 3449 |
}
|
| 3450 |
|
| 3451 |
return {'dates_js': original_array, 'dates_str': original_array};
|
| 3452 |
}
|
| 3453 |
|
| 3454 |
// =====================================================================================================================
|
| 3455 |
/* == Auto Fill Fields / Auto Select Dates ==
|
| 3456 |
// ===================================================================================================================== */
|
| 3457 |
|
| 3458 |
jQuery( document ).ready( function (){
|
| 3459 |
|
| 3460 |
var url_params = new URLSearchParams( window.location.search );
|
| 3461 |
|
| 3462 |
// Disable days selection in calendar, after redirection from the "Search results page, after search availability" // FixIn: 8.8.2.3.
|
| 3463 |
if ( 'On' != _wpbc.get_other_param( 'is_enabled_booking_search_results_days_select' ) ) {
|
| 3464 |
if (
|
| 3465 |
( url_params.has( 'wpbc_select_check_in' ) ) &&
|
| 3466 |
( url_params.has( 'wpbc_select_check_out' ) ) &&
|
| 3467 |
( url_params.has( 'wpbc_select_calendar_id' ) )
|
| 3468 |
){
|
| 3469 |
|
| 3470 |
var select_dates_in_calendar_id = parseInt( url_params.get( 'wpbc_select_calendar_id' ) );
|
| 3471 |
|
| 3472 |
// Fire on all booking dates loaded
|
| 3473 |
jQuery( 'body' ).on( 'wpbc_calendar_ajx__loaded_data', function ( event, loaded_resource_id ){
|
| 3474 |
|
| 3475 |
if ( loaded_resource_id == select_dates_in_calendar_id ){
|
| 3476 |
wpbc_auto_select_dates_in_calendar( select_dates_in_calendar_id, url_params.get( 'wpbc_select_check_in' ), url_params.get( 'wpbc_select_check_out' ) );
|
| 3477 |
}
|
| 3478 |
} );
|
| 3479 |
}
|
| 3480 |
}
|
| 3481 |
|
| 3482 |
if ( |
| 3483 |
url_params.has( 'wpbc_auto_fill' ) |
| 3484 |
&& ! jQuery( 'body' ).hasClass( 'wp-admin' ) |
| 3485 |
){ |
| 3486 |
|
| 3487 |
var wpbc_auto_fill_value = url_params.get( 'wpbc_auto_fill' );
|
| 3488 |
|
| 3489 |
// Convert back. Some systems do not like symbol '~' in URL, so we need to replace to some other symbols
|
| 3490 |
wpbc_auto_fill_value = wpbc_auto_fill_value.replaceAll( '_^_', '~' );
|
| 3491 |
|
| 3492 |
wpbc_auto_fill_booking_fields( wpbc_auto_fill_value );
|
| 3493 |
}
|
| 3494 |
|
| 3495 |
} );
|
| 3496 |
|
| 3497 |
/**
|
| 3498 |
* Autofill / select booking form fields by values from the GET request parameter: ?wpbc_auto_fill=
|
| 3499 |
*
|
| 3500 |
* URL-provided field names are resolved through the exact-name DOM API so |
| 3501 |
* they can never be interpreted as CSS selector syntax. |
| 3502 |
* |
| 3503 |
* @param {string} auto_fill_str Serialized field-name and value pairs. |
| 3504 |
* @return {void} |
| 3505 |
*/
|
| 3506 |
function wpbc_auto_fill_booking_fields( auto_fill_str ){ // FixIn: 10.0.0.48.
|
| 3507 |
|
| 3508 |
if ( '' == auto_fill_str ){
|
| 3509 |
return;
|
| 3510 |
}
|
| 3511 |
|
| 3512 |
// console.log( 'WPBC_AUTO_FILL_BOOKING_FIELDS( AUTO_FILL_STR )', auto_fill_str);
|
| 3513 |
|
| 3514 |
var fields_arr = wpbc_auto_fill_booking_fields__parse( auto_fill_str ); |
| 3515 |
|
| 3516 |
for ( let i = 0; i < fields_arr.length; i++ ){ |
| 3517 |
var field_name = String( fields_arr[ i ][ 'name' ] || '' ); |
| 3518 |
if ( '' === field_name ) { |
| 3519 |
continue; |
| 3520 |
} |
| 3521 |
|
| 3522 |
var field_elements = document.getElementsByName( field_name ); |
| 3523 |
if ( 0 < field_elements.length ) { |
| 3524 |
jQuery( field_elements ).val( fields_arr[ i ][ 'value' ] ); |
| 3525 |
} |
| 3526 |
} |
| 3527 |
} |
| 3528 |
|
| 3529 |
/**
|
| 3530 |
* Parse data from get parameter: ?wpbc_auto_fill=visitors231^2~max_capacity231^2
|
| 3531 |
*
|
| 3532 |
* @param data_str = 'visitors231^2~max_capacity231^2';
|
| 3533 |
* @returns {*}
|
| 3534 |
*/
|
| 3535 |
function wpbc_auto_fill_booking_fields__parse( data_str ){
|
| 3536 |
|
| 3537 |
var filter_options_arr = [];
|
| 3538 |
|
| 3539 |
var data_arr = data_str.split( '~' );
|
| 3540 |
|
| 3541 |
for ( var j = 0; j < data_arr.length; j++ ){
|
| 3542 |
|
| 3543 |
var my_form_field = data_arr[ j ].split( '^' );
|
| 3544 |
|
| 3545 |
var filter_name = ('undefined' !== typeof (my_form_field[ 0 ])) ? my_form_field[ 0 ] : '';
|
| 3546 |
var filter_value = ('undefined' !== typeof (my_form_field[ 1 ])) ? my_form_field[ 1 ] : '';
|
| 3547 |
|
| 3548 |
filter_options_arr.push(
|
| 3549 |
{
|
| 3550 |
'name' : filter_name,
|
| 3551 |
'value' : filter_value
|
| 3552 |
}
|
| 3553 |
);
|
| 3554 |
}
|
| 3555 |
return filter_options_arr;
|
| 3556 |
}
|
| 3557 |
|
| 3558 |
/**
|
| 3559 |
* Parse data from get parameter: ?search_get__custom_params=...
|
| 3560 |
*
|
| 3561 |
* @param data_str = 'text^search_field__display_check_in^23.05.2024~text^search_field__display_check_out^26.05.2024~selectbox-one^search_quantity^2~selectbox-one^location^Spain~selectbox-one^max_capacity^2~selectbox-one^amenity^parking~checkbox^search_field__extend_search_days^5~submit^^Search~hidden^search_get__check_in_ymd^2024-05-23~hidden^search_get__check_out_ymd^2024-05-26~hidden^search_get__time^~hidden^search_get__quantity^2~hidden^search_get__extend^5~hidden^search_get__users_id^~hidden^search_get__custom_params^~';
|
| 3562 |
* @returns {*}
|
| 3563 |
*/
|
| 3564 |
function wpbc_auto_fill_search_fields__parse( data_str ){
|
| 3565 |
|
| 3566 |
var filter_options_arr = [];
|
| 3567 |
|
| 3568 |
var data_arr = data_str.split( '~' );
|
| 3569 |
|
| 3570 |
for ( var j = 0; j < data_arr.length; j++ ){
|
| 3571 |
|
| 3572 |
var my_form_field = data_arr[ j ].split( '^' );
|
| 3573 |
|
| 3574 |
var filter_type = ('undefined' !== typeof (my_form_field[ 0 ])) ? my_form_field[ 0 ] : '';
|
| 3575 |
var filter_name = ('undefined' !== typeof (my_form_field[ 1 ])) ? my_form_field[ 1 ] : '';
|
| 3576 |
var filter_value = ('undefined' !== typeof (my_form_field[ 2 ])) ? my_form_field[ 2 ] : '';
|
| 3577 |
|
| 3578 |
filter_options_arr.push(
|
| 3579 |
{
|
| 3580 |
'type' : filter_type,
|
| 3581 |
'name' : filter_name,
|
| 3582 |
'value' : filter_value
|
| 3583 |
}
|
| 3584 |
);
|
| 3585 |
}
|
| 3586 |
return filter_options_arr;
|
| 3587 |
}
|
| 3588 |
|
| 3589 |
|
| 3590 |
// ---------------------------------------------------------------------------------------------------------------------
|
| 3591 |
/* == Auto Update number of months in calendars ON screen size changed ==
|
| 3592 |
// --------------------------------------------------------------------------------------------------------------------- */
|
| 3593 |
|
| 3594 |
/**
|
| 3595 |
* Auto Update Number of Months in Calendar, e.g.: if ( WINDOW_WIDTH <= 782px ) >>> MONTHS_NUMBER = 1
|
| 3596 |
* ELSE: number of months defined in shortcode.
|
| 3597 |
* @param resource_id int
|
| 3598 |
*
|
| 3599 |
*/
|
| 3600 |
function wpbc_calendar__auto_update_months_number__on_resize( resource_id ){
|
| 3601 |
|
| 3602 |
if ( true === _wpbc.get_other_param( 'is_allow_several_months_on_mobile' ) ) {
|
| 3603 |
return false;
|
| 3604 |
}
|
| 3605 |
|
| 3606 |
var local__number_of_months = parseInt( _wpbc.calendar__get_param_value( resource_id, 'calendar_number_of_months' ) );
|
| 3607 |
|
| 3608 |
if ( local__number_of_months > 1 ){
|
| 3609 |
|
| 3610 |
if ( jQuery( window ).width() <= 782 ){
|
| 3611 |
wpbc_calendar__update_months_number( resource_id, 1 );
|
| 3612 |
} else {
|
| 3613 |
wpbc_calendar__update_months_number( resource_id, local__number_of_months );
|
| 3614 |
}
|
| 3615 |
|
| 3616 |
}
|
| 3617 |
}
|
| 3618 |
|
| 3619 |
/**
|
| 3620 |
* Auto Update Number of Months in ALL Calendars
|
| 3621 |
*
|
| 3622 |
*/
|
| 3623 |
function wpbc_calendars__auto_update_months_number(){
|
| 3624 |
|
| 3625 |
var all_calendars_arr = _wpbc.calendars_all__get();
|
| 3626 |
|
| 3627 |
// This LOOP "for in" is GOOD, because we check here keys 'calendar_' === calendar_id.slice( 0, 9 )
|
| 3628 |
for ( var calendar_id in all_calendars_arr ){
|
| 3629 |
if ( 'calendar_' === calendar_id.slice( 0, 9 ) ){
|
| 3630 |
var resource_id = parseInt( calendar_id.slice( 9 ) ); // 'calendar_3' -> 3
|
| 3631 |
if ( resource_id > 0 ){
|
| 3632 |
wpbc_calendar__auto_update_months_number__on_resize( resource_id );
|
| 3633 |
}
|
| 3634 |
}
|
| 3635 |
}
|
| 3636 |
}
|
| 3637 |
|
| 3638 |
/**
|
| 3639 |
* If browser window changed, then update number of months.
|
| 3640 |
*/
|
| 3641 |
jQuery( window ).on( 'resize', function (){
|
| 3642 |
wpbc_calendars__auto_update_months_number();
|
| 3643 |
} );
|
| 3644 |
|
| 3645 |
/**
|
| 3646 |
* Auto update calendar number of months on initial page load
|
| 3647 |
*/
|
| 3648 |
jQuery( document ).ready( function (){
|
| 3649 |
var closed_timer = setTimeout( function (){
|
| 3650 |
wpbc_calendars__auto_update_months_number();
|
| 3651 |
}, 100 );
|
| 3652 |
});
|
| 3653 |
|
| 3654 |
// ---------------------------------------------------------------------------------------------------------------------
|
| 3655 |
/* == Check: calendar_dates_start: "2026-01-01", calendar_dates_end: "2026-12-31" == // FixIn: 10.13.1.4.
|
| 3656 |
// --------------------------------------------------------------------------------------------------------------------- */
|
| 3657 |
/**
|
| 3658 |
* Get Start JS Date of starting dates in calendar, from the _wpbc object.
|
| 3659 |
*
|
| 3660 |
* @param integer resource_id - resource ID, e.g.: 1.
|
| 3661 |
*/
|
| 3662 |
function wpbc_calendar__get_dates_start( resource_id ) {
|
| 3663 |
return wpbc_calendar__get_date_parameter( resource_id, 'calendar_dates_start' );
|
| 3664 |
}
|
| 3665 |
|
| 3666 |
/**
|
| 3667 |
* Get End JS Date of ending dates in calendar, from the _wpbc object.
|
| 3668 |
*
|
| 3669 |
* @param integer resource_id - resource ID, e.g.: 1.
|
| 3670 |
*/
|
| 3671 |
function wpbc_calendar__get_dates_end(resource_id) {
|
| 3672 |
return wpbc_calendar__get_date_parameter( resource_id, 'calendar_dates_end' );
|
| 3673 |
}
|
| 3674 |
|
| 3675 |
/**
|
| 3676 |
* Get validates date parameter.
|
| 3677 |
*
|
| 3678 |
* @param resource_id - 1
|
| 3679 |
* @param parameter_str - 'calendar_dates_start' | 'calendar_dates_end' | ...
|
| 3680 |
*/
|
| 3681 |
function wpbc_calendar__get_date_parameter(resource_id, parameter_str) {
|
| 3682 |
|
| 3683 |
var date_expected_ymd = _wpbc.calendar__get_param_value( resource_id, parameter_str );
|
| 3684 |
|
| 3685 |
if ( ! date_expected_ymd ) {
|
| 3686 |
return false; // '' | 0 | null | undefined -> false.
|
| 3687 |
}
|
| 3688 |
|
| 3689 |
if ( -1 !== date_expected_ymd.indexOf( '-' ) ) {
|
| 3690 |
|
| 3691 |
var date_expected_ymd_arr = date_expected_ymd.split( '-' ); // '2025-07-26' -> ['2025', '07', '26']
|
| 3692 |
|
| 3693 |
if ( date_expected_ymd_arr.length > 0 ) {
|
| 3694 |
var year = (date_expected_ymd_arr.length > 0) ? parseInt( date_expected_ymd_arr[0] ) : new Date().getFullYear(); // Year.
|
| 3695 |
var month = (date_expected_ymd_arr.length > 1) ? (parseInt( date_expected_ymd_arr[1] ) - 1) : 0; // (month - 1) or 0 - Jan.
|
| 3696 |
var day = (date_expected_ymd_arr.length > 2) ? parseInt( date_expected_ymd_arr[2] ) : 1; // date or Otherwise 1st of month
|
| 3697 |
|
| 3698 |
var date_js = new Date( year, month, day, 0, 0, 0, 0 );
|
| 3699 |
|
| 3700 |
return date_js;
|
| 3701 |
}
|
| 3702 |
}
|
| 3703 |
|
| 3704 |
return false; // Fallback, if we not parsed this parameter 'calendar_dates_start' = '2025-07-26', for example because of 'calendar_dates_start' = 'sfsdf'.
|
| 3705 |
}
|
| 3706 |
|
| 3707 |
/**
|
| 3708 |
* ====================================================================================================================
|
| 3709 |
* includes/__js/cal/days_select_custom.js
|
| 3710 |
* ====================================================================================================================
|
| 3711 |
*/
|
| 3712 |
|
| 3713 |
// FixIn: 9.8.9.2.
|
| 3714 |
|
| 3715 |
/**
|
| 3716 |
* Re-Init Calendar and Re-Render it.
|
| 3717 |
*
|
| 3718 |
* @param resource_id
|
| 3719 |
*/
|
| 3720 |
function wpbc_cal__re_init( resource_id ){
|
| 3721 |
|
| 3722 |
// Remove CLASS for ability to re-render and reinit calendar.
|
| 3723 |
jQuery( '#calendar_booking' + resource_id ).removeClass( 'hasDatepick' );
|
| 3724 |
wpbc_calendar_show( resource_id );
|
| 3725 |
}
|
| 3726 |
|
| 3727 |
|
| 3728 |
/**
|
| 3729 |
* Re-Init previously saved days selection variables.
|
| 3730 |
*
|
| 3731 |
* @param resource_id
|
| 3732 |
*/
|
| 3733 |
function wpbc_cal_days_select__re_init( resource_id ){
|
| 3734 |
|
| 3735 |
_wpbc.calendar__set_param_value( resource_id, 'saved_variable___days_select_initial'
|
| 3736 |
, {
|
| 3737 |
'dynamic__days_min' : _wpbc.calendar__get_param_value( resource_id, 'dynamic__days_min' ),
|
| 3738 |
'dynamic__days_max' : _wpbc.calendar__get_param_value( resource_id, 'dynamic__days_max' ),
|
| 3739 |
'dynamic__days_specific' : _wpbc.calendar__get_param_value( resource_id, 'dynamic__days_specific' ),
|
| 3740 |
'dynamic__week_days__start': _wpbc.calendar__get_param_value( resource_id, 'dynamic__week_days__start' ),
|
| 3741 |
'fixed__days_num' : _wpbc.calendar__get_param_value( resource_id, 'fixed__days_num' ),
|
| 3742 |
'fixed__week_days__start' : _wpbc.calendar__get_param_value( resource_id, 'fixed__week_days__start' )
|
| 3743 |
}
|
| 3744 |
);
|
| 3745 |
}
|
| 3746 |
|
| 3747 |
// ---------------------------------------------------------------------------------------------------------------------
|
| 3748 |
|
| 3749 |
/**
|
| 3750 |
* Set Single Day selection - after page load
|
| 3751 |
*
|
| 3752 |
* @param resource_id ID of booking resource
|
| 3753 |
*/
|
| 3754 |
function wpbc_cal_ready_days_select__single( resource_id ){
|
| 3755 |
|
| 3756 |
// Re-define selection, only after page loaded with all init vars
|
| 3757 |
jQuery(document).ready(function(){
|
| 3758 |
|
| 3759 |
// Wait 1 second, just to be sure, that all init vars defined
|
| 3760 |
setTimeout(function(){
|
| 3761 |
|
| 3762 |
wpbc_cal_days_select__single( resource_id );
|
| 3763 |
|
| 3764 |
}, 1000);
|
| 3765 |
});
|
| 3766 |
}
|
| 3767 |
|
| 3768 |
/**
|
| 3769 |
* Set Single Day selection
|
| 3770 |
* Can be run at any time, when calendar defined - useful for console run.
|
| 3771 |
*
|
| 3772 |
* @param resource_id ID of booking resource
|
| 3773 |
*/
|
| 3774 |
function wpbc_cal_days_select__single( resource_id ){
|
| 3775 |
|
| 3776 |
_wpbc.calendar__set_parameters( resource_id, {'days_select_mode': 'single'} );
|
| 3777 |
|
| 3778 |
wpbc_cal_days_select__re_init( resource_id );
|
| 3779 |
wpbc_cal__re_init( resource_id );
|
| 3780 |
}
|
| 3781 |
|
| 3782 |
// ---------------------------------------------------------------------------------------------------------------------
|
| 3783 |
|
| 3784 |
/**
|
| 3785 |
* Set Multiple Days selection - after page load
|
| 3786 |
*
|
| 3787 |
* @param resource_id ID of booking resource
|
| 3788 |
*/
|
| 3789 |
function wpbc_cal_ready_days_select__multiple( resource_id ){
|
| 3790 |
|
| 3791 |
// Re-define selection, only after page loaded with all init vars
|
| 3792 |
jQuery(document).ready(function(){
|
| 3793 |
|
| 3794 |
// Wait 1 second, just to be sure, that all init vars defined
|
| 3795 |
setTimeout(function(){
|
| 3796 |
|
| 3797 |
wpbc_cal_days_select__multiple( resource_id );
|
| 3798 |
|
| 3799 |
}, 1000);
|
| 3800 |
});
|
| 3801 |
}
|
| 3802 |
|
| 3803 |
|
| 3804 |
/**
|
| 3805 |
* Set Multiple Days selection
|
| 3806 |
* Can be run at any time, when calendar defined - useful for console run.
|
| 3807 |
*
|
| 3808 |
* @param resource_id ID of booking resource
|
| 3809 |
*/
|
| 3810 |
function wpbc_cal_days_select__multiple( resource_id ){
|
| 3811 |
|
| 3812 |
_wpbc.calendar__set_parameters( resource_id, {'days_select_mode': 'multiple'} );
|
| 3813 |
|
| 3814 |
wpbc_cal_days_select__re_init( resource_id );
|
| 3815 |
wpbc_cal__re_init( resource_id );
|
| 3816 |
}
|
| 3817 |
|
| 3818 |
|
| 3819 |
// ---------------------------------------------------------------------------------------------------------------------
|
| 3820 |
|
| 3821 |
/**
|
| 3822 |
* Set Fixed Days selection with 1 mouse click - after page load
|
| 3823 |
*
|
| 3824 |
* @integer resource_id - 1 -- ID of booking resource (calendar) -
|
| 3825 |
* @integer days_number - 3 -- number of days to select -
|
| 3826 |
* @array week_days__start - [-1] | [ 1, 5] -- { -1 - Any | 0 - Su, 1 - Mo, 2 - Tu, 3 - We, 4 - Th, 5 - Fr, 6 - Sat }
|
| 3827 |
*/
|
| 3828 |
function wpbc_cal_ready_days_select__fixed( resource_id, days_number, week_days__start = [-1] ){
|
| 3829 |
|
| 3830 |
// Re-define selection, only after page loaded with all init vars
|
| 3831 |
jQuery(document).ready(function(){
|
| 3832 |
|
| 3833 |
// Wait 1 second, just to be sure, that all init vars defined
|
| 3834 |
setTimeout(function(){
|
| 3835 |
|
| 3836 |
wpbc_cal_days_select__fixed( resource_id, days_number, week_days__start );
|
| 3837 |
|
| 3838 |
}, 1000);
|
| 3839 |
});
|
| 3840 |
}
|
| 3841 |
|
| 3842 |
|
| 3843 |
/**
|
| 3844 |
* Set Fixed Days selection with 1 mouse click
|
| 3845 |
* Can be run at any time, when calendar defined - useful for console run.
|
| 3846 |
*
|
| 3847 |
* @integer resource_id - 1 -- ID of booking resource (calendar) -
|
| 3848 |
* @integer days_number - 3 -- number of days to select -
|
| 3849 |
* @array week_days__start - [-1] | [ 1, 5] -- { -1 - Any | 0 - Su, 1 - Mo, 2 - Tu, 3 - We, 4 - Th, 5 - Fr, 6 - Sat }
|
| 3850 |
*/
|
| 3851 |
function wpbc_cal_days_select__fixed( resource_id, days_number, week_days__start = [-1] ){
|
| 3852 |
|
| 3853 |
_wpbc.calendar__set_parameters( resource_id, {'days_select_mode': 'fixed'} );
|
| 3854 |
|
| 3855 |
_wpbc.calendar__set_parameters( resource_id, {'fixed__days_num': parseInt( days_number )} ); // Number of days selection with 1 mouse click
|
| 3856 |
_wpbc.calendar__set_parameters( resource_id, {'fixed__week_days__start': week_days__start} ); // { -1 - Any | 0 - Su, 1 - Mo, 2 - Tu, 3 - We, 4 - Th, 5 - Fr, 6 - Sat }
|
| 3857 |
|
| 3858 |
wpbc_cal_days_select__re_init( resource_id );
|
| 3859 |
wpbc_cal__re_init( resource_id );
|
| 3860 |
}
|
| 3861 |
|
| 3862 |
// --------------------------------------------------------------------------------------------------------------------- |
| 3863 |
|
| 3864 |
/** |
| 3865 |
* Set the existing calendar parameters to two-click range mode after page load. |
| 3866 |
* Free uses the unrestricted shared handler; Business Small+ keeps its already initialized advanced range rules. |
| 3867 |
* |
| 3868 |
* @param resource_id ID of booking resource. |
| 3869 |
*/ |
| 3870 |
function wpbc_cal_ready_days_select__range_mode( resource_id ){ |
| 3871 |
|
| 3872 |
jQuery(document).ready(function(){ |
| 3873 |
setTimeout(function(){ |
| 3874 |
wpbc_cal_days_select__range_mode( resource_id ); |
| 3875 |
}, 1000); |
| 3876 |
}); |
| 3877 |
} |
| 3878 |
|
| 3879 |
/** |
| 3880 |
* Switch to two-click range mode without changing any advanced range parameters. |
| 3881 |
* |
| 3882 |
* @param resource_id ID of booking resource. |
| 3883 |
*/ |
| 3884 |
function wpbc_cal_days_select__range_mode( resource_id ){ |
| 3885 |
|
| 3886 |
_wpbc.calendar__set_parameters( resource_id, {'days_select_mode': 'dynamic'} ); |
| 3887 |
|
| 3888 |
wpbc_cal_days_select__re_init( resource_id ); |
| 3889 |
wpbc_cal__re_init( resource_id ); |
| 3890 |
} |
| 3891 |
|
| 3892 |
// --------------------------------------------------------------------------------------------------------------------- |
| 3893 |
|
| 3894 |
/** |
| 3895 |
* Set Range Days selection with 2 mouse clicks - after page load |
| 3896 |
*
|
| 3897 |
* @integer resource_id - 1 -- ID of booking resource (calendar)
|
| 3898 |
* @integer days_min - 7 -- Min number of days to select
|
| 3899 |
* @integer days_max - 30 -- Max number of days to select
|
| 3900 |
* @array days_specific - [] | [7,14,21,28] -- Restriction for Specific number of days selection
|
| 3901 |
* @array week_days__start - [-1] | [ 1, 5] -- { -1 - Any | 0 - Su, 1 - Mo, 2 - Tu, 3 - We, 4 - Th, 5 - Fr, 6 - Sat }
|
| 3902 |
*/
|
| 3903 |
function wpbc_cal_ready_days_select__range( resource_id, days_min, days_max, days_specific = [], week_days__start = [-1] ){
|
| 3904 |
|
| 3905 |
// Re-define selection, only after page loaded with all init vars
|
| 3906 |
jQuery(document).ready(function(){
|
| 3907 |
|
| 3908 |
// Wait 1 second, just to be sure, that all init vars defined
|
| 3909 |
setTimeout(function(){
|
| 3910 |
|
| 3911 |
wpbc_cal_days_select__range( resource_id, days_min, days_max, days_specific, week_days__start );
|
| 3912 |
}, 1000);
|
| 3913 |
});
|
| 3914 |
}
|
| 3915 |
|
| 3916 |
/**
|
| 3917 |
* Set Range Days selection with 2 mouse clicks
|
| 3918 |
* Can be run at any time, when calendar defined - useful for console run.
|
| 3919 |
*
|
| 3920 |
* @integer resource_id - 1 -- ID of booking resource (calendar)
|
| 3921 |
* @integer days_min - 7 -- Min number of days to select
|
| 3922 |
* @integer days_max - 30 -- Max number of days to select
|
| 3923 |
* @array days_specific - [] | [7,14,21,28] -- Restriction for Specific number of days selection
|
| 3924 |
* @array week_days__start - [-1] | [ 1, 5] -- { -1 - Any | 0 - Su, 1 - Mo, 2 - Tu, 3 - We, 4 - Th, 5 - Fr, 6 - Sat }
|
| 3925 |
*/
|
| 3926 |
function wpbc_cal_days_select__range( resource_id, days_min, days_max, days_specific = [], week_days__start = [-1] ){
|
| 3927 |
|
| 3928 |
_wpbc.calendar__set_parameters( resource_id, {'days_select_mode': 'dynamic'} );
|
| 3929 |
_wpbc.calendar__set_param_value( resource_id, 'dynamic__days_min' , parseInt( days_min ) ); // Min. Number of days selection with 2 mouse clicks
|
| 3930 |
_wpbc.calendar__set_param_value( resource_id, 'dynamic__days_max' , parseInt( days_max ) ); // Max. Number of days selection with 2 mouse clicks
|
| 3931 |
_wpbc.calendar__set_param_value( resource_id, 'dynamic__days_specific' , days_specific ); // Example [5,7]
|
| 3932 |
_wpbc.calendar__set_param_value( resource_id, 'dynamic__week_days__start' , week_days__start ); // { -1 - Any | 0 - Su, 1 - Mo, 2 - Tu, 3 - We, 4 - Th, 5 - Fr, 6 - Sat }
|
| 3933 |
|
| 3934 |
wpbc_cal_days_select__re_init( resource_id );
|
| 3935 |
wpbc_cal__re_init( resource_id );
|
| 3936 |
}
|
| 3937 |
|
| 3938 |
/**
|
| 3939 |
* ====================================================================================================================
|
| 3940 |
* includes/__js/cal_ajx_load/wpbc_cal_ajx.js
|
| 3941 |
* ====================================================================================================================
|
| 3942 |
*/
|
| 3943 |
|
| 3944 |
// ---------------------------------------------------------------------------------------------------------------------
|
| 3945 |
// A j a x L o a d C a l e n d a r D a t a
|
| 3946 |
// ---------------------------------------------------------------------------------------------------------------------
|
| 3947 |
|
| 3948 |
function wpbc_calendar__load_data__ajx( params ){
|
| 3949 |
|
| 3950 |
// FixIn: 9.8.6.2.
|
| 3951 |
wpbc_calendar__loading__start( params['resource_id'] );
|
| 3952 |
|
| 3953 |
// Trigger event for calendar before loading Booking data, but after showing Calendar.
|
| 3954 |
if ( jQuery( '#calendar_booking' + params['resource_id'] ).length > 0 ){
|
| 3955 |
var target_elm = jQuery( 'body' ).trigger( "wpbc_calendar_ajx__before_loaded_data", [params['resource_id']] );
|
| 3956 |
//jQuery( 'body' ).on( 'wpbc_calendar_ajx__before_loaded_data', function( event, resource_id ) { ... } );
|
| 3957 |
}
|
| 3958 |
|
| 3959 |
if ( wpbc_balancer__is_wait( params , 'wpbc_calendar__load_data__ajx' ) ){
|
| 3960 |
return false;
|
| 3961 |
}
|
| 3962 |
|
| 3963 |
// FixIn: 9.8.6.2.
|
| 3964 |
wpbc_calendar__blur__stop( params['resource_id'] );
|
| 3965 |
|
| 3966 |
// -----------------------------------------------------------------------------------------------------------------
|
| 3967 |
// == Get start / end dates from the Booking Calendar shortcode. ==
|
| 3968 |
// Example: [booking calendar_dates_start='2026-01-01' calendar_dates_end='2026-12-31' resource_id=1] // FixIn: 10.13.1.4.
|
| 3969 |
// -----------------------------------------------------------------------------------------------------------------
|
| 3970 |
if ( false !== wpbc_calendar__get_dates_start( params['resource_id'] ) ) {
|
| 3971 |
if ( ! params['dates_to_check'] ) { params['dates_to_check'] = []; }
|
| 3972 |
var dates_start = wpbc_calendar__get_dates_start( params['resource_id'] ); // E.g. - local__min_date = new Date( 2025, 0, 1 );
|
| 3973 |
if ( false !== dates_start ){
|
| 3974 |
params['dates_to_check'][0] = wpbc__get__sql_class_date( dates_start );
|
| 3975 |
}
|
| 3976 |
}
|
| 3977 |
if ( false !== wpbc_calendar__get_dates_end( params['resource_id'] ) ) {
|
| 3978 |
if ( !params['dates_to_check'] ) { params['dates_to_check'] = []; }
|
| 3979 |
var dates_end = wpbc_calendar__get_dates_end( params['resource_id'] ); // E.g. - local__min_date = new Date( 2025, 0, 1 );
|
| 3980 |
if ( false !== dates_end ) {
|
| 3981 |
params['dates_to_check'][1] = wpbc__get__sql_class_date( dates_end );
|
| 3982 |
if ( !params['dates_to_check'][0] ) {
|
| 3983 |
params['dates_to_check'][0] = wpbc__get__sql_class_date( new Date() );
|
| 3984 |
}
|
| 3985 |
}
|
| 3986 |
}
|
| 3987 |
// -----------------------------------------------------------------------------------------------------------------
|
| 3988 |
|
| 3989 |
// console.groupEnd(); console.time('resource_id_' + params['resource_id']);
|
| 3990 |
console.groupCollapsed( 'WPBC_AJX_CALENDAR_LOAD' ); console.log( ' == Before Ajax Send - calendars_all__get() == ' , _wpbc.calendars_all__get() );
|
| 3991 |
if ( 'function' === typeof (wpbc_hook__init_timeselector) ) {
|
| 3992 |
wpbc_hook__init_timeselector();
|
| 3993 |
}
|
| 3994 |
|
| 3995 |
// Start Ajax
|
| 3996 |
jQuery.post( wpbc_url_ajax,
|
| 3997 |
{
|
| 3998 |
action : 'WPBC_AJX_CALENDAR_LOAD',
|
| 3999 |
wpbc_ajx_user_id: _wpbc.get_secure_param( 'user_id' ),
|
| 4000 |
nonce : _wpbc.get_secure_param( 'nonce' ),
|
| 4001 |
wpbc_ajx_locale : _wpbc.get_secure_param( 'locale' ),
|
| 4002 |
|
| 4003 |
calendar_request_params : params // Usually like: { 'resource_id': 1, 'max_days_count': 365 }
|
| 4004 |
},
|
| 4005 |
|
| 4006 |
/**
|
| 4007 |
* S u c c e s s
|
| 4008 |
*
|
| 4009 |
* @param response_data - its object returned from Ajax - class-live-search.php
|
| 4010 |
* @param textStatus - 'success'
|
| 4011 |
* @param jqXHR - Object
|
| 4012 |
*/
|
| 4013 |
function ( response_data, textStatus, jqXHR ) {
|
| 4014 |
// console.timeEnd('resource_id_' + response_data['resource_id']);
|
| 4015 |
console.log( ' == Response WPBC_AJX_CALENDAR_LOAD == ', response_data ); console.groupEnd();
|
| 4016 |
|
| 4017 |
// FixIn: 9.8.6.2.
|
| 4018 |
var ajx_post_data__resource_id = wpbc_get_resource_id__from_ajx_post_data_url( this.data );
|
| 4019 |
wpbc_balancer__completed( ajx_post_data__resource_id , 'wpbc_calendar__load_data__ajx' );
|
| 4020 |
|
| 4021 |
var is_valid_response = ( |
| 4022 |
(typeof response_data === 'object') |
| 4023 |
&& (response_data !== null) |
| 4024 |
&& (! Array.isArray( response_data )) |
| 4025 |
&& Object.prototype.hasOwnProperty.call( response_data, 'resource_id' ) |
| 4026 |
&& (typeof response_data[ 'ajx_data' ] === 'object') |
| 4027 |
&& (response_data[ 'ajx_data' ] !== null) |
| 4028 |
&& (! Array.isArray( response_data[ 'ajx_data' ] )) |
| 4029 |
&& Object.prototype.hasOwnProperty.call( response_data[ 'ajx_data' ], 'dates' ) |
| 4030 |
&& Object.prototype.hasOwnProperty.call( response_data[ 'ajx_data' ], 'resources_id_arr__in_dates' ) |
| 4031 |
&& Object.prototype.hasOwnProperty.call( response_data[ 'ajx_data' ], 'aggregate_resource_id_arr' ) |
| 4032 |
); |
| 4033 |
|
| 4034 |
if ( ! is_valid_response ) { |
| 4035 |
var jq_node = wpbc_get_calendar__jq_node__for_messages( this.data ); |
| 4036 |
var response_error_message = _wpbc.get_message( 'message_unexpected_server_response' ) || 'The server returned an unexpected response. Please reload the page and try again.'; |
| 4037 |
|
| 4038 |
wpbc_front_end__log_unexpected_ajax_response( 'WPBC_AJX_CALENDAR_LOAD', response_data, jqXHR, textStatus, 'Invalid response structure' ); |
| 4039 |
wpbc_calendar__loading__stop( ajx_post_data__resource_id ); |
| 4040 |
|
| 4041 |
wpbc_front_end__show_message( response_error_message, { 'type' : 'error', |
| 4042 |
'show_here' : {'jq_node': jq_node, 'where': 'after'}, |
| 4043 |
'is_append' : true, |
| 4044 |
'style' : 'text-align:left;', |
| 4045 |
'content_mode': 'text', |
| 4046 |
'delay' : 0 |
| 4047 |
} ); |
| 4048 |
return; |
| 4049 |
} |
| 4050 |
|
| 4051 |
// Show Calendar
|
| 4052 |
wpbc_calendar__loading__stop( response_data[ 'resource_id' ] );
|
| 4053 |
|
| 4054 |
// -------------------------------------------------------------------------------------------------
|
| 4055 |
// Bookings - Dates
|
| 4056 |
_wpbc.bookings_in_calendar__set_dates( response_data[ 'resource_id' ], response_data[ 'ajx_data' ]['dates'] );
|
| 4057 |
|
| 4058 |
// Bookings - Child or only single booking resource in dates
|
| 4059 |
_wpbc.booking__set_param_value( response_data[ 'resource_id' ], 'resources_id_arr__in_dates', response_data[ 'ajx_data' ][ 'resources_id_arr__in_dates' ] );
|
| 4060 |
|
| 4061 |
// Aggregate booking resources, if any ?
|
| 4062 |
_wpbc.booking__set_param_value( response_data[ 'resource_id' ], 'aggregate_resource_id_arr', response_data[ 'ajx_data' ][ 'aggregate_resource_id_arr' ] ); |
| 4063 |
// ------------------------------------------------------------------------------------------------- |
| 4064 |
|
| 4065 |
/** |
| 4066 |
* Allow optional modules to calculate derived calendar state after canonical |
| 4067 |
* AJAX data is stored and before the first refreshed calendar render. |
| 4068 |
* |
| 4069 |
* @param {number|string} resource_id Booking resource ID. |
| 4070 |
*/ |
| 4071 |
jQuery( 'body' ).trigger( 'wpbc_calendar_ajx__before_update_look', [ response_data[ 'resource_id' ] ] ); |
| 4072 |
|
| 4073 |
// Update calendar |
| 4074 |
wpbc_calendar__update_look( response_data[ 'resource_id' ] ); |
| 4075 |
|
| 4076 |
if ( 'function' === typeof (wpbc_hook__init_timeselector) ) {
|
| 4077 |
wpbc_hook__init_timeselector();
|
| 4078 |
}
|
| 4079 |
|
| 4080 |
if (
|
| 4081 |
( 'undefined' !== typeof (response_data[ 'ajx_data' ][ 'ajx_after_action_message' ]) )
|
| 4082 |
&& ( '' != response_data[ 'ajx_data' ][ 'ajx_after_action_message' ].replace( /\n/g, "<br />" ) )
|
| 4083 |
){
|
| 4084 |
|
| 4085 |
var jq_node = wpbc_get_calendar__jq_node__for_messages( this.data );
|
| 4086 |
|
| 4087 |
// Show Message
|
| 4088 |
wpbc_front_end__show_message( response_data[ 'ajx_data' ][ 'ajx_after_action_message' ].replace( /\n/g, "<br />" ),
|
| 4089 |
{ 'type' : ( 'undefined' !== typeof( response_data[ 'ajx_data' ][ 'ajx_after_action_message_status' ] ) )
|
| 4090 |
? response_data[ 'ajx_data' ][ 'ajx_after_action_message_status' ] : 'info',
|
| 4091 |
'show_here': {'jq_node': jq_node, 'where': 'after'},
|
| 4092 |
'is_append': true,
|
| 4093 |
'style' : 'text-align:left;',
|
| 4094 |
'delay' : 10000
|
| 4095 |
} );
|
| 4096 |
}
|
| 4097 |
|
| 4098 |
if ( 'function' === typeof (wpbc_update_capacity_hint) ) {
|
| 4099 |
wpbc_update_capacity_hint( response_data['resource_id'] );
|
| 4100 |
}
|
| 4101 |
|
| 4102 |
// Trigger event that calendar has been // FixIn: 10.0.0.44. // FixIn: 10.14.17.2.
|
| 4103 |
if ( (jQuery( '#calendar_booking' + response_data['resource_id'] ).length > 0) || (jQuery( '#date_booking' + response_data['resource_id'] ).length > 0) ) {
|
| 4104 |
var target_elm = jQuery( 'body' ).trigger( "wpbc_calendar_ajx__loaded_data", [response_data[ 'resource_id' ]] );
|
| 4105 |
//jQuery( 'body' ).on( 'wpbc_calendar_ajx__loaded_data', function( event, resource_id ) { ... } );
|
| 4106 |
}
|
| 4107 |
|
| 4108 |
//jQuery( '#ajax_respond' ).html( response_data ); // For ability to show response, add such DIV element to page
|
| 4109 |
}
|
| 4110 |
).fail( function ( jqXHR, textStatus, errorThrown ) { |
| 4111 |
wpbc_front_end__log_unexpected_ajax_response( 'WPBC_AJX_CALENDAR_LOAD', jqXHR.responseText || '', jqXHR, textStatus, errorThrown ); |
| 4112 |
|
| 4113 |
var ajx_post_data__resource_id = wpbc_get_resource_id__from_ajx_post_data_url( this.data ); |
| 4114 |
wpbc_balancer__completed( ajx_post_data__resource_id , 'wpbc_calendar__load_data__ajx' ); |
| 4115 |
wpbc_calendar__loading__stop( ajx_post_data__resource_id ); |
| 4116 |
|
| 4117 |
var fallback_error_message = _wpbc.get_message( 'message_unexpected_server_response' ) || 'The server returned an unexpected response. Please reload the page and try again.'; |
| 4118 |
var conflict_cache_hint = _wpbc.get_message( 'message_http_conflict_cache_hint' ) || 'A cached or optimized version of this page may be outdated. Clear the browser cache and reload the page. Website administrators should also purge page, server, and CDN caches and regenerate minified or optimized files.'; |
| 4119 |
var error_message = wpbc_front_end__get_ajax_error_message( jqXHR, fallback_error_message, conflict_cache_hint ); |
| 4120 |
var message_show_delay = 3000; |
| 4121 |
|
| 4122 |
var jq_node = wpbc_get_calendar__jq_node__for_messages( this.data ); |
| 4123 |
|
| 4124 |
/**
|
| 4125 |
* If we make fast clicking on different pages,
|
| 4126 |
* then under calendar will show error message with empty text, because ajax was not received.
|
| 4127 |
* To not show such warnings we are set delay in 3 seconds. var message_show_delay = 3000;
|
| 4128 |
*/
|
| 4129 |
var closed_timer = setTimeout( function (){
|
| 4130 |
|
| 4131 |
// Show Message
|
| 4132 |
wpbc_front_end__show_message( error_message , { 'type' : 'error',
|
| 4133 |
'show_here': {'jq_node': jq_node, 'where': 'after'},
|
| 4134 |
'is_append': true, |
| 4135 |
'style' : 'text-align:left;', |
| 4136 |
'css_class':'wpbc_fe_message_alt', |
| 4137 |
'content_mode': 'text', |
| 4138 |
'delay' : 0 |
| 4139 |
} );
|
| 4140 |
} ,
|
| 4141 |
parseInt( message_show_delay ) );
|
| 4142 |
|
| 4143 |
})
|
| 4144 |
// .done( function ( data, textStatus, jqXHR ) { if ( window.console && window.console.log ){ console.log( 'second success', data, textStatus, jqXHR ); } })
|
| 4145 |
// .always( function ( data_jqXHR, textStatus, jqXHR_errorThrown ) { if ( window.console && window.console.log ){ console.log( 'always finished', data_jqXHR, textStatus, jqXHR_errorThrown ); } })
|
| 4146 |
; // End Ajax
|
| 4147 |
}
|
| 4148 |
|
| 4149 |
|
| 4150 |
|
| 4151 |
// ---------------------------------------------------------------------------------------------------------------------
|
| 4152 |
// Support
|
| 4153 |
// ---------------------------------------------------------------------------------------------------------------------
|
| 4154 |
|
| 4155 |
/**
|
| 4156 |
* Get Calendar jQuery node for showing messages during Ajax
|
| 4157 |
* This parameter: calendar_request_params[resource_id] parsed from this.data Ajax post data
|
| 4158 |
*
|
| 4159 |
* @param ajx_post_data_url_params 'action=WPBC_AJX_CALENDAR_LOAD...&calendar_request_params%5Bresource_id%5D=2&calendar_request_params%5Bbooking_hash%5D=&calendar_request_params'
|
| 4160 |
* @returns {string} ''#calendar_booking1' | '.booking_form_div' ...
|
| 4161 |
*
|
| 4162 |
* Example var jq_node = wpbc_get_calendar__jq_node__for_messages( this.data );
|
| 4163 |
*/
|
| 4164 |
function wpbc_get_calendar__jq_node__for_messages( ajx_post_data_url_params ){
|
| 4165 |
|
| 4166 |
var jq_node = '.booking_form_div';
|
| 4167 |
|
| 4168 |
var calendar_resource_id = wpbc_get_resource_id__from_ajx_post_data_url( ajx_post_data_url_params );
|
| 4169 |
|
| 4170 |
if ( calendar_resource_id > 0 ){
|
| 4171 |
jq_node = '#calendar_booking' + calendar_resource_id;
|
| 4172 |
}
|
| 4173 |
|
| 4174 |
return jq_node;
|
| 4175 |
}
|
| 4176 |
|
| 4177 |
|
| 4178 |
/**
|
| 4179 |
* Get resource ID from ajx post data url usually from this.data =
|
| 4180 |
* 'action=WPBC_AJX_CALENDAR_LOAD...&calendar_request_params%5Bresource_id%5D=2&calendar_request_params%5Bbooking_hash%5D=&calendar_request_params'
|
| 4181 |
*
|
| 4182 |
* @param ajx_post_data_url_params 'action=WPBC_AJX_CALENDAR_LOAD...&calendar_request_params%5Bresource_id%5D=2&calendar_request_params%5Bbooking_hash%5D=&calendar_request_params'
|
| 4183 |
* @returns {int} 1 | 0 (if errror then 0)
|
| 4184 |
*
|
| 4185 |
* Example var jq_node = wpbc_get_calendar__jq_node__for_messages( this.data );
|
| 4186 |
*/
|
| 4187 |
function wpbc_get_resource_id__from_ajx_post_data_url( ajx_post_data_url_params ){
|
| 4188 |
|
| 4189 |
// Get booking resource ID from Ajax Post Request -> this.data = 'action=WPBC_AJX_CALENDAR_LOAD...&calendar_request_params%5Bresource_id%5D=2&calendar_request_params%5Bbooking_hash%5D=&calendar_request_params'
|
| 4190 |
var calendar_resource_id = wpbc_get_uri_param_by_name( 'calendar_request_params[resource_id]', ajx_post_data_url_params );
|
| 4191 |
if ( (null !== calendar_resource_id) && ('' !== calendar_resource_id) ){
|
| 4192 |
calendar_resource_id = parseInt( calendar_resource_id );
|
| 4193 |
if ( calendar_resource_id > 0 ){
|
| 4194 |
return calendar_resource_id;
|
| 4195 |
}
|
| 4196 |
}
|
| 4197 |
return 0;
|
| 4198 |
}
|
| 4199 |
|
| 4200 |
|
| 4201 |
/**
|
| 4202 |
* Get parameter from URL - parse URL parameters, like this:
|
| 4203 |
* action=WPBC_AJX_CALENDAR_LOAD...&calendar_request_params%5Bresource_id%5D=2&calendar_request_params%5Bbooking_hash%5D=&calendar_request_params
|
| 4204 |
* @param name parameter name, like 'calendar_request_params[resource_id]'
|
| 4205 |
* @param url 'parameter string URL'
|
| 4206 |
* @returns {string|null} parameter value
|
| 4207 |
*
|
| 4208 |
* Example: wpbc_get_uri_param_by_name( 'calendar_request_params[resource_id]', this.data ); -> '2'
|
| 4209 |
*/
|
| 4210 |
function wpbc_get_uri_param_by_name( name, url ){
|
| 4211 |
|
| 4212 |
url = decodeURIComponent( url );
|
| 4213 |
|
| 4214 |
name = name.replace( /[\[\]]/g, '\\$&' );
|
| 4215 |
var regex = new RegExp( '[?&]' + name + '(=([^&#]*)|&|#|$)' ),
|
| 4216 |
results = regex.exec( url );
|
| 4217 |
if ( !results ) return null;
|
| 4218 |
if ( !results[ 2 ] ) return '';
|
| 4219 |
return decodeURIComponent( results[ 2 ].replace( /\+/g, ' ' ) );
|
| 4220 |
}
|
| 4221 |
|
| 4222 |
/**
|
| 4223 |
* =====================================================================================================================
|
| 4224 |
* includes/__js/front_end_messages/wpbc_fe_messages.js
|
| 4225 |
* =====================================================================================================================
|
| 4226 |
*/
|
| 4227 |
|
| 4228 |
// ---------------------------------------------------------------------------------------------------------------------
|
| 4229 |
// Show Messages at Front-Edn side |
| 4230 |
// --------------------------------------------------------------------------------------------------------------------- |
| 4231 |
|
| 4232 |
/** |
| 4233 |
* Extract a safe plain-text message from a recognized JSON AJAX error response. |
| 4234 |
* |
| 4235 |
* Only documented message properties are accepted. Callers must still render the returned value in text mode so an |
| 4236 |
* upstream response cannot inject markup into the public booking page. |
| 4237 |
* |
| 4238 |
* @param {jqXHR|null} jq_xhr jQuery XHR object, when available. |
| 4239 |
* @return {string} Bounded server message, or an empty string when the response is not recognized. |
| 4240 |
*/ |
| 4241 |
function wpbc_front_end__get_safe_ajax_error_message( jq_xhr ) { |
| 4242 |
if ( |
| 4243 |
! jq_xhr |
| 4244 |
|| ! jq_xhr.responseJSON |
| 4245 |
|| 'object' !== typeof jq_xhr.responseJSON |
| 4246 |
|| Array.isArray( jq_xhr.responseJSON ) |
| 4247 |
) { |
| 4248 |
return ''; |
| 4249 |
} |
| 4250 |
|
| 4251 |
var response_json = jq_xhr.responseJSON; |
| 4252 |
var message_candidates = []; |
| 4253 |
|
| 4254 |
if ( 'string' === typeof response_json.message ) { |
| 4255 |
message_candidates.push( response_json.message ); |
| 4256 |
} |
| 4257 |
if ( |
| 4258 |
response_json.data |
| 4259 |
&& 'object' === typeof response_json.data |
| 4260 |
&& ! Array.isArray( response_json.data ) |
| 4261 |
&& 'string' === typeof response_json.data.message |
| 4262 |
) { |
| 4263 |
message_candidates.push( response_json.data.message ); |
| 4264 |
} |
| 4265 |
|
| 4266 |
for ( var candidate_index = 0; candidate_index < message_candidates.length; candidate_index++ ) { |
| 4267 |
var server_message = message_candidates[ candidate_index ].trim(); |
| 4268 |
if ( server_message ) { |
| 4269 |
return server_message.slice( 0, 1000 ); |
| 4270 |
} |
| 4271 |
} |
| 4272 |
|
| 4273 |
return ''; |
| 4274 |
} |
| 4275 |
|
| 4276 |
/** |
| 4277 |
* Build a public-safe AJAX failure message with optional HTTP 409 cache troubleshooting guidance. |
| 4278 |
* |
| 4279 |
* @param {jqXHR|null} jq_xhr jQuery XHR object, when available. |
| 4280 |
* @param {string} fallback_message Localized fallback shown when no safe server message exists. |
| 4281 |
* @param {string} http_conflict_cache_hint Optional localized cache guidance for HTTP 409 responses. |
| 4282 |
* @return {string} Plain-text message including the HTTP status when available. |
| 4283 |
*/ |
| 4284 |
function wpbc_front_end__get_ajax_error_message( jq_xhr, fallback_message, http_conflict_cache_hint ) { |
| 4285 |
var http_status = jq_xhr && jq_xhr.status ? parseInt( jq_xhr.status, 10 ) : 0; |
| 4286 |
var safe_server_message = wpbc_front_end__get_safe_ajax_error_message( jq_xhr ); |
| 4287 |
var error_message = safe_server_message || String( fallback_message || '' ).trim(); |
| 4288 |
|
| 4289 |
if ( 409 === http_status && http_conflict_cache_hint ) { |
| 4290 |
error_message += ( error_message ? ' ' : '' ) + String( http_conflict_cache_hint ).trim(); |
| 4291 |
} |
| 4292 |
if ( http_status ) { |
| 4293 |
error_message += ' (' + http_status + ')'; |
| 4294 |
} |
| 4295 |
|
| 4296 |
return error_message; |
| 4297 |
} |
| 4298 |
|
| 4299 |
/** |
| 4300 |
* Log an unexpected AJAX response for browser-console diagnostics. |
| 4301 |
* |
| 4302 |
* The response is intentionally kept out of frontend notices because it can contain a complete HTML error or login page. |
| 4303 |
* Logging it here preserves the server payload and request context for support troubleshooting. |
| 4304 |
* |
| 4305 |
* @param {string} ajax_action WordPress AJAX action that produced the unexpected response. |
| 4306 |
* @param {*} response_data Raw response payload returned by the server. |
| 4307 |
* @param {jqXHR|null} jq_xhr jQuery XHR object, when available. |
| 4308 |
* @param {string} text_status jQuery request status or success state. |
| 4309 |
* @param {string|Error} error_thrown Error description or exception reported by jQuery. |
| 4310 |
* @return {void} |
| 4311 |
*/ |
| 4312 |
function wpbc_front_end__log_unexpected_ajax_response( ajax_action, response_data, jq_xhr, text_status, error_thrown ) { |
| 4313 |
if ( ! window.console || 'function' !== typeof window.console.error ) { |
| 4314 |
return; |
| 4315 |
} |
| 4316 |
|
| 4317 |
try { |
| 4318 |
var content_type = ''; |
| 4319 |
var response_text = 'string' === typeof response_data ? response_data : ''; |
| 4320 |
var response_length = response_text.length; |
| 4321 |
var response_format = response_text ? 'text' : 'empty'; |
| 4322 |
var http_status = jq_xhr && jq_xhr.status ? parseInt( jq_xhr.status, 10 ) : 0; |
| 4323 |
var diagnostic_action = String( ajax_action || 'AJAX' ).replace( /^WPBC_AJX_/, '' ).replace( /[^A-Za-z0-9]+/g, '-' ).toUpperCase(); |
| 4324 |
var diagnostic_code = 'WPBC-' + diagnostic_action + '-' + ( http_status || 'NETWORK' ); |
| 4325 |
var response_headers = {}; |
| 4326 |
if ( jq_xhr && 'function' === typeof jq_xhr.getResponseHeader ) { |
| 4327 |
content_type = jq_xhr.getResponseHeader( 'content-type' ) || ''; |
| 4328 |
response_headers = { |
| 4329 |
'server' : jq_xhr.getResponseHeader( 'server' ) || '', |
| 4330 |
'cf_ray' : jq_xhr.getResponseHeader( 'cf-ray' ) || '', |
| 4331 |
'x_cache' : jq_xhr.getResponseHeader( 'x-cache' ) || '', |
| 4332 |
'x_cache_status' : jq_xhr.getResponseHeader( 'x-cache-status' ) || '', |
| 4333 |
'x_litespeed_cache': jq_xhr.getResponseHeader( 'x-litespeed-cache' ) || '', |
| 4334 |
'x_request_id' : jq_xhr.getResponseHeader( 'x-request-id' ) || '' |
| 4335 |
}; |
| 4336 |
} |
| 4337 |
if ( jq_xhr && jq_xhr.responseJSON && 'object' === typeof jq_xhr.responseJSON ) { |
| 4338 |
response_format = 'json'; |
| 4339 |
try { |
| 4340 |
response_length = JSON.stringify( jq_xhr.responseJSON ).length; |
| 4341 |
} catch ( response_json_error ) { |
| 4342 |
response_length = 0; |
| 4343 |
} |
| 4344 |
} else if ( -1 !== content_type.toLowerCase().indexOf( 'html' ) || /^\s*(?:<!doctype|<html)/i.test( response_text ) ) { |
| 4345 |
response_format = 'html'; |
| 4346 |
} |
| 4347 |
|
| 4348 |
window.console.error( '[WPBC][AJAX-UNEXPECTED-RESPONSE] ' + ajax_action, { |
| 4349 |
'action' : ajax_action, |
| 4350 |
'diagnostic_code' : diagnostic_code, |
| 4351 |
'http_status' : http_status, |
| 4352 |
'http_status_text': jq_xhr && jq_xhr.statusText ? jq_xhr.statusText : '', |
| 4353 |
'text_status' : text_status || '', |
| 4354 |
'error' : error_thrown || '', |
| 4355 |
'content_type' : content_type, |
| 4356 |
'response_format' : response_format, |
| 4357 |
'response_length' : response_length, |
| 4358 |
'server_message' : wpbc_front_end__get_safe_ajax_error_message( jq_xhr ), |
| 4359 |
'response_headers': response_headers, |
| 4360 |
'response' : response_data |
| 4361 |
} ); |
| 4362 |
} catch ( logging_error ) { |
| 4363 |
// Console diagnostics must never interrupt frontend error recovery. |
| 4364 |
} |
| 4365 |
} |
| 4366 |
|
| 4367 |
/** |
| 4368 |
* Show message in content |
| 4369 |
*
|
| 4370 |
* @param message Message HTML
|
| 4371 |
* @param params = {
|
| 4372 |
* 'type' : 'warning', // 'error' | 'warning' | 'info' | 'success'
|
| 4373 |
* 'show_here' : {
|
| 4374 |
* 'jq_node' : '', // any jQuery node definition
|
| 4375 |
* 'where' : 'inside' // 'inside' | 'before' | 'after' | 'right' | 'left'
|
| 4376 |
* },
|
| 4377 |
* 'is_append': true, // Apply only if 'where' : 'inside'
|
| 4378 |
* 'style' : 'text-align:left;', // styles, if needed
|
| 4379 |
* 'css_class': '', // For example can be: 'wpbc_fe_message_alt'
|
| 4380 |
* 'delay' : 0, // how many microsecond to show, if 0 then show forever
|
| 4381 |
* 'if_visible_not_show': false // if true, then do not show message, if previos message was not hided (not apply if 'where' : 'inside' )
|
| 4382 |
* };
|
| 4383 |
* Examples:
|
| 4384 |
* var html_id = wpbc_front_end__show_message( 'You can test days selection in calendar', {} );
|
| 4385 |
*
|
| 4386 |
* var notice_message_id = wpbc_front_end__show_message( _wpbc.get_message( 'message_check_required' ), { 'type': 'warning', 'delay': 10000, 'if_visible_not_show': true,
|
| 4387 |
* 'show_here': {'where': 'right', 'jq_node': el,} } );
|
| 4388 |
*
|
| 4389 |
* wpbc_front_end__show_message( response_data[ 'ajx_data' ][ 'ajx_after_action_message' ].replace( /\n/g, "<br />" ),
|
| 4390 |
* { 'type' : ( 'undefined' !== typeof( response_data[ 'ajx_data' ][ 'ajx_after_action_message_status' ] ) )
|
| 4391 |
* ? response_data[ 'ajx_data' ][ 'ajx_after_action_message_status' ] : 'info',
|
| 4392 |
* 'show_here': {'jq_node': jq_node, 'where': 'after'},
|
| 4393 |
* 'css_class':'wpbc_fe_message_alt',
|
| 4394 |
* 'delay' : 10000
|
| 4395 |
* } );
|
| 4396 |
*
|
| 4397 |
*
|
| 4398 |
* @returns string - HTML ID or 0 if not showing during this time.
|
| 4399 |
*/
|
| 4400 |
function wpbc_front_end__show_message( message, params = {} ){
|
| 4401 |
|
| 4402 |
var params_default = {
|
| 4403 |
'type' : 'warning', // 'error' | 'warning' | 'info' | 'success'
|
| 4404 |
'show_here' : {
|
| 4405 |
'jq_node' : '', // any jQuery node definition
|
| 4406 |
'where' : 'inside' // 'inside' | 'before' | 'after' | 'right' | 'left'
|
| 4407 |
},
|
| 4408 |
'is_append': true, // Apply only if 'where' : 'inside'
|
| 4409 |
'style' : 'text-align:left;', // styles, if needed
|
| 4410 |
'css_class': '', // For example can be: 'wpbc_fe_message_alt'
|
| 4411 |
'delay' : 0, // how many microsecond to show, if 0 then show forever |
| 4412 |
'if_visible_not_show': false, // if true, then do not show message, if previos message was not hided (not apply if 'where' : 'inside' ) |
| 4413 |
'is_scroll': true, // is scroll to this element |
| 4414 |
'content_mode': 'html' // 'html' for trusted legacy content | 'text' for editable/user content |
| 4415 |
};
|
| 4416 |
for ( var p_key in params ){
|
| 4417 |
params_default[ p_key ] = params[ p_key ];
|
| 4418 |
}
|
| 4419 |
params = params_default; |
| 4420 |
|
| 4421 |
if ( 'text' === params[ 'content_mode' ] ) { |
| 4422 |
message = jQuery( '<div>' ).text( null === message || 'undefined' === typeof message ? '' : String( message ) ).html().replace( /\n/g, '<br />' ); |
| 4423 |
} |
| 4424 |
|
| 4425 |
var unique_div_id = new Date();
|
| 4426 |
unique_div_id = 'wpbc_notice_' + unique_div_id.getTime();
|
| 4427 |
|
| 4428 |
params['css_class'] += ' wpbc_fe_message';
|
| 4429 |
if ( params['type'] == 'error' ){
|
| 4430 |
params['css_class'] += ' wpbc_fe_message_error';
|
| 4431 |
message = '<i class="menu_icon icon-1x wpbc_icn_report_gmailerrorred"></i>' + message;
|
| 4432 |
}
|
| 4433 |
if ( params['type'] == 'warning' ){
|
| 4434 |
params['css_class'] += ' wpbc_fe_message_warning';
|
| 4435 |
message = '<i class="menu_icon icon-1x wpbc_icn_warning"></i>' + message;
|
| 4436 |
}
|
| 4437 |
if ( params['type'] == 'info' ){
|
| 4438 |
params['css_class'] += ' wpbc_fe_message_info';
|
| 4439 |
}
|
| 4440 |
if ( params['type'] == 'success' ){
|
| 4441 |
params['css_class'] += ' wpbc_fe_message_success';
|
| 4442 |
message = '<i class="menu_icon icon-1x wpbc_icn_done_outline"></i>' + message;
|
| 4443 |
}
|
| 4444 |
|
| 4445 |
var scroll_to_element = '<div id="' + unique_div_id + '_scroll" style="display:none;"></div>';
|
| 4446 |
message = '<div id="' + unique_div_id + '" class="wpbc_front_end__message ' + params['css_class'] + '" style="' + params[ 'style' ] + '">' + message + '</div>';
|
| 4447 |
|
| 4448 |
|
| 4449 |
var jq_el_message = false;
|
| 4450 |
var is_show_message = true;
|
| 4451 |
|
| 4452 |
if ( 'inside' === params[ 'show_here' ][ 'where' ] ){
|
| 4453 |
|
| 4454 |
if ( params[ 'is_append' ] ){
|
| 4455 |
jQuery( params[ 'show_here' ][ 'jq_node' ] ).append( scroll_to_element );
|
| 4456 |
jQuery( params[ 'show_here' ][ 'jq_node' ] ).append( message );
|
| 4457 |
} else {
|
| 4458 |
jQuery( params[ 'show_here' ][ 'jq_node' ] ).html( scroll_to_element + message );
|
| 4459 |
}
|
| 4460 |
|
| 4461 |
} else if ( 'before' === params[ 'show_here' ][ 'where' ] ){
|
| 4462 |
|
| 4463 |
jq_el_message = jQuery( params[ 'show_here' ][ 'jq_node' ] ).siblings( '[id^="wpbc_notice_"]' );
|
| 4464 |
if ( (params[ 'if_visible_not_show' ]) && (jq_el_message.is( ':visible' )) ){
|
| 4465 |
is_show_message = false;
|
| 4466 |
unique_div_id = jQuery( jq_el_message.get( 0 ) ).attr( 'id' );
|
| 4467 |
}
|
| 4468 |
if ( is_show_message ){
|
| 4469 |
jQuery( params[ 'show_here' ][ 'jq_node' ] ).before( scroll_to_element );
|
| 4470 |
jQuery( params[ 'show_here' ][ 'jq_node' ] ).before( message );
|
| 4471 |
}
|
| 4472 |
|
| 4473 |
} else if ( 'after' === params[ 'show_here' ][ 'where' ] ){
|
| 4474 |
|
| 4475 |
jq_el_message = jQuery( params[ 'show_here' ][ 'jq_node' ] ).nextAll( '[id^="wpbc_notice_"]' );
|
| 4476 |
if ( (params[ 'if_visible_not_show' ]) && (jq_el_message.is( ':visible' )) ){
|
| 4477 |
is_show_message = false;
|
| 4478 |
unique_div_id = jQuery( jq_el_message.get( 0 ) ).attr( 'id' );
|
| 4479 |
}
|
| 4480 |
if ( is_show_message ){
|
| 4481 |
jQuery( params[ 'show_here' ][ 'jq_node' ] ).before( scroll_to_element ); // We need to set here before(for handy scroll)
|
| 4482 |
jQuery( params[ 'show_here' ][ 'jq_node' ] ).after( message );
|
| 4483 |
}
|
| 4484 |
|
| 4485 |
} else if ( 'right' === params[ 'show_here' ][ 'where' ] ){
|
| 4486 |
|
| 4487 |
jq_el_message = jQuery( params[ 'show_here' ][ 'jq_node' ] ).nextAll( '.wpbc_front_end__message_container_right' ).find( '[id^="wpbc_notice_"]' );
|
| 4488 |
if ( (params[ 'if_visible_not_show' ]) && (jq_el_message.is( ':visible' )) ){
|
| 4489 |
is_show_message = false;
|
| 4490 |
unique_div_id = jQuery( jq_el_message.get( 0 ) ).attr( 'id' );
|
| 4491 |
}
|
| 4492 |
if ( is_show_message ){
|
| 4493 |
jQuery( params[ 'show_here' ][ 'jq_node' ] ).before( scroll_to_element ); // We need to set here before(for handy scroll)
|
| 4494 |
jQuery( params[ 'show_here' ][ 'jq_node' ] ).after( '<div class="wpbc_front_end__message_container_right">' + message + '</div>' );
|
| 4495 |
}
|
| 4496 |
} else if ( 'left' === params[ 'show_here' ][ 'where' ] ){
|
| 4497 |
|
| 4498 |
jq_el_message = jQuery( params[ 'show_here' ][ 'jq_node' ] ).siblings( '.wpbc_front_end__message_container_left' ).find( '[id^="wpbc_notice_"]' );
|
| 4499 |
if ( (params[ 'if_visible_not_show' ]) && (jq_el_message.is( ':visible' )) ){
|
| 4500 |
is_show_message = false;
|
| 4501 |
unique_div_id = jQuery( jq_el_message.get( 0 ) ).attr( 'id' );
|
| 4502 |
}
|
| 4503 |
if ( is_show_message ){
|
| 4504 |
jQuery( params[ 'show_here' ][ 'jq_node' ] ).before( scroll_to_element ); // We need to set here before(for handy scroll)
|
| 4505 |
jQuery( params[ 'show_here' ][ 'jq_node' ] ).before( '<div class="wpbc_front_end__message_container_left">' + message + '</div>' );
|
| 4506 |
}
|
| 4507 |
}
|
| 4508 |
|
| 4509 |
if ( ( is_show_message ) && ( parseInt( params[ 'delay' ] ) > 0 ) ){
|
| 4510 |
var closed_timer = setTimeout( function (){
|
| 4511 |
jQuery( '#' + unique_div_id ).fadeOut( 1500 );
|
| 4512 |
} , parseInt( params[ 'delay' ] ) );
|
| 4513 |
|
| 4514 |
var closed_timer2 = setTimeout( function (){
|
| 4515 |
jQuery( '#' + unique_div_id ).trigger( 'hide' );
|
| 4516 |
}, ( parseInt( params[ 'delay' ] ) + 1501 ) );
|
| 4517 |
}
|
| 4518 |
|
| 4519 |
// Check if showed message in some hidden parent section and show it. But it must be lower than '.wpbc_container'
|
| 4520 |
var parent_els = jQuery( '#' + unique_div_id ).parents().map( function (){
|
| 4521 |
if ( (!jQuery( this ).is( 'visible' )) && (jQuery( '.wpbc_container' ).has( this )) ){
|
| 4522 |
jQuery( this ).show();
|
| 4523 |
}
|
| 4524 |
} );
|
| 4525 |
|
| 4526 |
if ( params[ 'is_scroll' ] ){
|
| 4527 |
wpbc_do_scroll( '#' + unique_div_id + '_scroll' );
|
| 4528 |
}
|
| 4529 |
|
| 4530 |
return unique_div_id;
|
| 4531 |
}
|
| 4532 |
|
| 4533 |
|
| 4534 |
/**
|
| 4535 |
* Error message. Preset of parameters for real message function.
|
| 4536 |
*
|
| 4537 |
* @param el - any jQuery node definition
|
| 4538 |
* @param message - Message HTML
|
| 4539 |
* @returns string - HTML ID or 0 if not showing during this time.
|
| 4540 |
*/
|
| 4541 |
function wpbc_front_end__show_message__error( jq_node, message, content_mode ){ |
| 4542 |
|
| 4543 |
content_mode = ( 'undefined' === typeof content_mode ) ? 'html' : content_mode; |
| 4544 |
|
| 4545 |
var notice_message_id = wpbc_front_end__show_message(
|
| 4546 |
message,
|
| 4547 |
{
|
| 4548 |
'type' : 'error',
|
| 4549 |
'delay' : 10000,
|
| 4550 |
'if_visible_not_show': true, |
| 4551 |
'content_mode' : content_mode, |
| 4552 |
'show_here' : {
|
| 4553 |
'where' : 'right',
|
| 4554 |
'jq_node': jq_node
|
| 4555 |
}
|
| 4556 |
}
|
| 4557 |
);
|
| 4558 |
return notice_message_id;
|
| 4559 |
}
|
| 4560 |
|
| 4561 |
|
| 4562 |
/**
|
| 4563 |
* Error message UNDER element. Preset of parameters for real message function.
|
| 4564 |
*
|
| 4565 |
* @param el - any jQuery node definition
|
| 4566 |
* @param message - Message HTML
|
| 4567 |
* @returns string - HTML ID or 0 if not showing during this time.
|
| 4568 |
*/
|
| 4569 |
function wpbc_front_end__show_message__error_under_element( jq_node, message, message_delay, content_mode ){ |
| 4570 |
|
| 4571 |
if ( 'undefined' === typeof (message_delay) ){ |
| 4572 |
message_delay = 0 |
| 4573 |
} |
| 4574 |
content_mode = ( 'undefined' === typeof content_mode ) ? 'html' : content_mode; |
| 4575 |
|
| 4576 |
var notice_message_id = wpbc_front_end__show_message(
|
| 4577 |
message,
|
| 4578 |
{
|
| 4579 |
'type' : 'error',
|
| 4580 |
'delay' : message_delay,
|
| 4581 |
'if_visible_not_show': true, |
| 4582 |
'content_mode' : content_mode, |
| 4583 |
'show_here' : {
|
| 4584 |
'where' : 'after',
|
| 4585 |
'jq_node': jq_node
|
| 4586 |
}
|
| 4587 |
}
|
| 4588 |
);
|
| 4589 |
return notice_message_id;
|
| 4590 |
}
|
| 4591 |
|
| 4592 |
|
| 4593 |
/**
|
| 4594 |
* Error message UNDER element. Preset of parameters for real message function.
|
| 4595 |
*
|
| 4596 |
* @param el - any jQuery node definition
|
| 4597 |
* @param message - Message HTML
|
| 4598 |
* @returns string - HTML ID or 0 if not showing during this time.
|
| 4599 |
*/
|
| 4600 |
function wpbc_front_end__show_message__error_above_element( jq_node, message, message_delay, content_mode ){ |
| 4601 |
|
| 4602 |
if ( 'undefined' === typeof (message_delay) ){ |
| 4603 |
message_delay = 10000 |
| 4604 |
} |
| 4605 |
content_mode = ( 'undefined' === typeof content_mode ) ? 'html' : content_mode; |
| 4606 |
|
| 4607 |
var notice_message_id = wpbc_front_end__show_message(
|
| 4608 |
message,
|
| 4609 |
{
|
| 4610 |
'type' : 'error',
|
| 4611 |
'delay' : message_delay,
|
| 4612 |
'if_visible_not_show': true, |
| 4613 |
'content_mode' : content_mode, |
| 4614 |
'show_here' : {
|
| 4615 |
'where' : 'before',
|
| 4616 |
'jq_node': jq_node
|
| 4617 |
}
|
| 4618 |
}
|
| 4619 |
);
|
| 4620 |
return notice_message_id;
|
| 4621 |
}
|
| 4622 |
|
| 4623 |
|
| 4624 |
/**
|
| 4625 |
* Warning message. Preset of parameters for real message function.
|
| 4626 |
*
|
| 4627 |
* @param el - any jQuery node definition
|
| 4628 |
* @param message - Message HTML
|
| 4629 |
* @returns string - HTML ID or 0 if not showing during this time.
|
| 4630 |
*/
|
| 4631 |
function wpbc_front_end__show_message__warning( jq_node, message, content_mode ){ |
| 4632 |
|
| 4633 |
content_mode = ( 'undefined' === typeof content_mode ) ? 'html' : content_mode; |
| 4634 |
|
| 4635 |
var notice_message_id = wpbc_front_end__show_message(
|
| 4636 |
message,
|
| 4637 |
{
|
| 4638 |
'type' : 'warning',
|
| 4639 |
'delay' : 10000,
|
| 4640 |
'if_visible_not_show': true, |
| 4641 |
'content_mode' : content_mode, |
| 4642 |
'show_here' : {
|
| 4643 |
'where' : 'right',
|
| 4644 |
'jq_node': jq_node
|
| 4645 |
}
|
| 4646 |
}
|
| 4647 |
);
|
| 4648 |
wpbc_highlight_error_on_form_field( jq_node );
|
| 4649 |
return notice_message_id;
|
| 4650 |
}
|
| 4651 |
|
| 4652 |
|
| 4653 |
/**
|
| 4654 |
* Warning message UNDER element. Preset of parameters for real message function.
|
| 4655 |
*
|
| 4656 |
* @param el - any jQuery node definition
|
| 4657 |
* @param message - Message HTML
|
| 4658 |
* @returns string - HTML ID or 0 if not showing during this time.
|
| 4659 |
*/
|
| 4660 |
function wpbc_front_end__show_message__warning_under_element( jq_node, message, content_mode ){ |
| 4661 |
|
| 4662 |
content_mode = ( 'undefined' === typeof content_mode ) ? 'html' : content_mode; |
| 4663 |
|
| 4664 |
var notice_message_id = wpbc_front_end__show_message(
|
| 4665 |
message,
|
| 4666 |
{
|
| 4667 |
'type' : 'warning',
|
| 4668 |
'delay' : 10000,
|
| 4669 |
'if_visible_not_show': true, |
| 4670 |
'content_mode' : content_mode, |
| 4671 |
'show_here' : {
|
| 4672 |
'where' : 'after',
|
| 4673 |
'jq_node': jq_node
|
| 4674 |
}
|
| 4675 |
}
|
| 4676 |
);
|
| 4677 |
return notice_message_id;
|
| 4678 |
}
|
| 4679 |
|
| 4680 |
|
| 4681 |
/**
|
| 4682 |
* Warning message ABOVE element. Preset of parameters for real message function.
|
| 4683 |
*
|
| 4684 |
* @param el - any jQuery node definition
|
| 4685 |
* @param message - Message HTML
|
| 4686 |
* @returns string - HTML ID or 0 if not showing during this time.
|
| 4687 |
*/
|
| 4688 |
function wpbc_front_end__show_message__warning_above_element( jq_node, message, content_mode ){ |
| 4689 |
|
| 4690 |
content_mode = ( 'undefined' === typeof content_mode ) ? 'html' : content_mode; |
| 4691 |
|
| 4692 |
var notice_message_id = wpbc_front_end__show_message(
|
| 4693 |
message,
|
| 4694 |
{
|
| 4695 |
'type' : 'warning',
|
| 4696 |
'delay' : 10000,
|
| 4697 |
'if_visible_not_show': true, |
| 4698 |
'content_mode' : content_mode, |
| 4699 |
'show_here' : {
|
| 4700 |
'where' : 'before',
|
| 4701 |
'jq_node': jq_node
|
| 4702 |
}
|
| 4703 |
}
|
| 4704 |
);
|
| 4705 |
return notice_message_id;
|
| 4706 |
}
|
| 4707 |
|
| 4708 |
/**
|
| 4709 |
* Highlight Error in specific field
|
| 4710 |
*
|
| 4711 |
* @param jq_node string or jQuery element, where scroll to
|
| 4712 |
*/
|
| 4713 |
function wpbc_highlight_error_on_form_field( jq_node ){
|
| 4714 |
|
| 4715 |
if ( !jQuery( jq_node ).length ){
|
| 4716 |
return;
|
| 4717 |
}
|
| 4718 |
if ( ! jQuery( jq_node ).is( ':input' ) ){
|
| 4719 |
// Situation with checkboxes or radio buttons
|
| 4720 |
var jq_node_arr = jQuery( jq_node ).find( ':input' );
|
| 4721 |
if ( !jq_node_arr.length ){
|
| 4722 |
return
|
| 4723 |
}
|
| 4724 |
jq_node = jq_node_arr.get( 0 );
|
| 4725 |
}
|
| 4726 |
var params = {};
|
| 4727 |
params[ 'delay' ] = 10000;
|
| 4728 |
|
| 4729 |
if ( !jQuery( jq_node ).hasClass( 'wpbc_form_field_error' ) ){
|
| 4730 |
|
| 4731 |
jQuery( jq_node ).addClass( 'wpbc_form_field_error' )
|
| 4732 |
|
| 4733 |
if ( parseInt( params[ 'delay' ] ) > 0 ){
|
| 4734 |
var closed_timer = setTimeout( function (){
|
| 4735 |
jQuery( jq_node ).removeClass( 'wpbc_form_field_error' );
|
| 4736 |
}
|
| 4737 |
, parseInt( params[ 'delay' ] )
|
| 4738 |
);
|
| 4739 |
|
| 4740 |
}
|
| 4741 |
}
|
| 4742 |
}
|
| 4743 |
|
| 4744 |
/**
|
| 4745 |
* Scroll to specific element
|
| 4746 |
*
|
| 4747 |
* @param jq_node string or jQuery element, where scroll to
|
| 4748 |
* @param extra_shift_offset int shift offset from jq_node
|
| 4749 |
*/
|
| 4750 |
function wpbc_do_scroll( jq_node , extra_shift_offset = 0 ){
|
| 4751 |
|
| 4752 |
if ( !jQuery( jq_node ).length ){
|
| 4753 |
return;
|
| 4754 |
}
|
| 4755 |
var targetOffset = jQuery( jq_node ).offset().top;
|
| 4756 |
|
| 4757 |
if ( targetOffset <= 0 ){
|
| 4758 |
if ( 0 != jQuery( jq_node ).nextAll( ':visible' ).length ){
|
| 4759 |
targetOffset = jQuery( jq_node ).nextAll( ':visible' ).first().offset().top;
|
| 4760 |
} else if ( 0 != jQuery( jq_node ).parent().nextAll( ':visible' ).length ){
|
| 4761 |
targetOffset = jQuery( jq_node ).parent().nextAll( ':visible' ).first().offset().top;
|
| 4762 |
}
|
| 4763 |
}
|
| 4764 |
|
| 4765 |
if ( jQuery( '#wpadminbar' ).length > 0 ){
|
| 4766 |
targetOffset = targetOffset - 50 - 50;
|
| 4767 |
} else {
|
| 4768 |
targetOffset = targetOffset - 20 - 50;
|
| 4769 |
}
|
| 4770 |
targetOffset += extra_shift_offset;
|
| 4771 |
|
| 4772 |
// Scroll only if we did not scroll before
|
| 4773 |
if ( ! jQuery( 'html,body' ).is( ':animated' ) ){
|
| 4774 |
jQuery( 'html,body' ).animate( {scrollTop: targetOffset}, 500 );
|
| 4775 |
}
|
| 4776 |
}
|
| 4777 |
|
| 4778 |
|
| 4779 |
|
| 4780 |
// FixIn: 10.2.0.4.
|
| 4781 |
/**
|
| 4782 |
* Define Popovers for Timelines in WP Booking Calendar
|
| 4783 |
*
|
| 4784 |
* @returns {string|boolean}
|
| 4785 |
*/
|
| 4786 |
function wpbc_define_tippy_popover(){
|
| 4787 |
if ( 'function' !== typeof (wpbc_tippy) ){
|
| 4788 |
console.log( 'WPBC Error. wpbc_tippy was not defined.' );
|
| 4789 |
return false;
|
| 4790 |
}
|
| 4791 |
wpbc_tippy( '.popover_bottom.popover_click', {
|
| 4792 |
content( reference ){
|
| 4793 |
var popover_title = reference.getAttribute( 'data-original-title' );
|
| 4794 |
var popover_content = reference.getAttribute( 'data-content' );
|
| 4795 |
return '<div class="popover popover_tippy">'
|
| 4796 |
+ '<div class="popover-close"><a href="javascript:void(0)" onclick="javascript:this.parentElement.parentElement.parentElement.parentElement.parentElement._tippy.hide();" >×</a></div>'
|
| 4797 |
+ popover_content
|
| 4798 |
+ '</div>';
|
| 4799 |
},
|
| 4800 |
allowHTML : true,
|
| 4801 |
trigger : 'manual',
|
| 4802 |
interactive : true,
|
| 4803 |
hideOnClick : false,
|
| 4804 |
interactiveBorder: 10,
|
| 4805 |
maxWidth : 550,
|
| 4806 |
theme : 'wpbc-tippy-popover',
|
| 4807 |
placement : 'bottom-start',
|
| 4808 |
touch : ['hold', 500],
|
| 4809 |
} );
|
| 4810 |
jQuery( '.popover_bottom.popover_click' ).on( 'click', function (){
|
| 4811 |
if ( this._tippy.state.isVisible ){
|
| 4812 |
this._tippy.hide();
|
| 4813 |
} else {
|
| 4814 |
this._tippy.show();
|
| 4815 |
}
|
| 4816 |
} );
|
| 4817 |
wpbc_define_hide_tippy_on_scroll();
|
| 4818 |
}
|
| 4819 |
|
| 4820 |
|
| 4821 |
|
| 4822 |
function wpbc_define_hide_tippy_on_scroll(){
|
| 4823 |
jQuery( '.flex_tl__scrolling_section2,.flex_tl__scrolling_sections' ).on( 'scroll', function ( event ){
|
| 4824 |
if ( 'function' === typeof (wpbc_tippy) ){
|
| 4825 |
wpbc_tippy.hideAll();
|
| 4826 |
}
|
| 4827 |
} );
|
| 4828 |
}
|
| 4829 |
|
| 4830 |
/**
|
| 4831 |
* WPBC calendar loader bootstrap.
|
| 4832 |
* ==============================================================================================
|
| 4833 |
* - Finds every .calendar_loader_frame[data-wpbc-rid] on the page (now or later).
|
| 4834 |
* - For each loader element, waits a "grace" period (data-wpbc-grace, default 8000 ms):
|
| 4835 |
* - If the real calendar appears: do nothing (loader naturally replaced).
|
| 4836 |
* - If not: show a helpful message (missing jQuery/_wpbc/datepick) or a duplicate notice.
|
| 4837 |
* - Works with multiple calendars and even duplicate RIDs on the same page.
|
| 4838 |
* - No inline JS needed in the shortcode/template output.
|
| 4839 |
*
|
| 4840 |
* File: ../includes/__js/client/cal/wpbc_cal_loader.js
|
| 4841 |
*
|
| 4842 |
* @since 10.14.5
|
| 4843 |
* @modified 2025-09-07 12:21
|
| 4844 |
* @version 1.0.0
|
| 4845 |
*
|
| 4846 |
*/
|
| 4847 |
/**
|
| 4848 |
* WPBC calendar loader bootstrap.
|
| 4849 |
* - Auto-detects .calendar_loader_frame[data-wpbc-rid] blocks.
|
| 4850 |
* - Waits a "grace" period per element before showing a helpful message
|
| 4851 |
* if the real calendar hasn't replaced the loader.
|
| 4852 |
* - Multiple calendars and duplicate RIDs are handled.
|
| 4853 |
*/
|
| 4854 |
(function (w, d) {
|
| 4855 |
'use strict';
|
| 4856 |
|
| 4857 |
/* ---------------------------------------------------------------------------
|
| 4858 |
* Small utilities (snake_case)
|
| 4859 |
* ------------------------------------------------------------------------ */
|
| 4860 |
|
| 4861 |
/** Track processed loader elements; fallback to data flag if WeakSet missing. */
|
| 4862 |
var processed_set = typeof WeakSet === 'function' ? new WeakSet() : null;
|
| 4863 |
|
| 4864 |
/** Return first match inside optional root. */
|
| 4865 |
function query_one(selector, root) {
|
| 4866 |
return (root || d).querySelector( selector );
|
| 4867 |
}
|
| 4868 |
|
| 4869 |
/** Return NodeList of matches inside optional root. */
|
| 4870 |
function query_all(selector, root) {
|
| 4871 |
return (root || d).querySelectorAll( selector );
|
| 4872 |
}
|
| 4873 |
|
| 4874 |
/** Run a callback when DOM is ready. */
|
| 4875 |
function on_ready(fn) {
|
| 4876 |
if ( d.readyState === 'loading' ) {
|
| 4877 |
d.addEventListener( 'DOMContentLoaded', fn );
|
| 4878 |
} else {
|
| 4879 |
fn();
|
| 4880 |
}
|
| 4881 |
}
|
| 4882 |
|
| 4883 |
/** Clear interval safely. */
|
| 4884 |
function safe_clear(interval_id) {
|
| 4885 |
try {
|
| 4886 |
w.clearInterval( interval_id );
|
| 4887 |
} catch ( e ) {
|
| 4888 |
}
|
| 4889 |
}
|
| 4890 |
|
| 4891 |
/** Mark element processed (WeakSet or data attribute). */
|
| 4892 |
function mark_processed(el) {
|
| 4893 |
if ( processed_set ) {
|
| 4894 |
processed_set.add( el );
|
| 4895 |
} else {
|
| 4896 |
try {
|
| 4897 |
el.dataset.wpbcProcessed = '1';
|
| 4898 |
} catch ( e ) {
|
| 4899 |
}
|
| 4900 |
}
|
| 4901 |
}
|
| 4902 |
|
| 4903 |
/** Check if element was processed. */
|
| 4904 |
function is_processed(el) {
|
| 4905 |
return processed_set ? processed_set.has( el ) : (el && el.dataset && el.dataset.wpbcProcessed === '1');
|
| 4906 |
}
|
| 4907 |
|
| 4908 |
/* --------------------------------------------------------------------------- |
| 4909 |
* Messages |
| 4910 |
* ------------------------------------------------------------------------ */ |
| 4911 |
|
| 4912 |
/** |
| 4913 |
* Build visitor messages for a resource, using localized Form Messages when available. |
| 4914 |
* @param {string|number} rid |
| 4915 |
* @return {{duplicate:string,init_failed:string,support:string,lib_jq:string,lib_dp:string,lib_wpbc:string}} |
| 4916 |
*/ |
| 4917 |
function get_messages(rid) { |
| 4918 |
var rid_int = parseInt( rid, 10 ); |
| 4919 |
var duplicate_message = |
| 4920 |
'More than one calendar or booking form for Booking Resource ID {resource_id} is present on this page. ' + |
| 4921 |
'A hidden copy still conflicts with the visible form and can prevent booking submission. ' + |
| 4922 |
'The site administrator must keep only one calendar or form for this Booking Resource. ' + |
| 4923 |
'After the page is corrected, reload it and try again.'; |
| 4924 |
|
| 4925 |
if ( w._wpbc && typeof w._wpbc.get_message === 'function' ) { |
| 4926 |
duplicate_message = w._wpbc.get_message( 'message_duplicate_booking_resource_on_page' ) || duplicate_message; |
| 4927 |
} |
| 4928 |
duplicate_message = String( duplicate_message ).replace( /\{resource_id\}/g, String( rid_int ) ); |
| 4929 |
|
| 4930 |
return { |
| 4931 |
duplicate : duplicate_message, |
| 4932 |
init_failed:
|
| 4933 |
'The calendar could not be initialized on this page.' + '\n' +
|
| 4934 |
'Please check your browser console for JavaScript errors and conflicts with other scripts/plugins.',
|
| 4935 |
support : '', /* 'Contact [email protected] if you have any questions.', */
|
| 4936 |
lib_jq :
|
| 4937 |
'It appears that the "jQuery" library is not loading correctly.' + '\n' +
|
| 4938 |
'For more information, please refer to this page: https://wpbookingcalendar.com/faq/',
|
| 4939 |
lib_dp :
|
| 4940 |
'It appears that the "jQuery.datepick" library is not loading correctly.' + '\n' +
|
| 4941 |
'For more information, please refer to this page: https://wpbookingcalendar.com/faq/',
|
| 4942 |
lib_wpbc :
|
| 4943 |
'It appears that the "_wpbc" library is not loading correctly.' + '\n' +
|
| 4944 |
'Please enable the loading of JS/CSS files for this page on the "WP Booking Calendar" - "Settings General" - "Advanced" page' + '\n' +
|
| 4945 |
'For more information, please refer to this page: https://wpbookingcalendar.com/faq/'
|
| 4946 |
};
|
| 4947 |
}
|
| 4948 |
|
| 4949 |
/** |
| 4950 |
* Escape a plain-text loader message before inserting its wrapper markup. |
| 4951 |
* |
| 4952 |
* @param {string} plain_text Visitor-facing plain text. |
| 4953 |
* @return {string} HTML-safe text. |
| 4954 |
*/ |
| 4955 |
function escape_html(plain_text) { |
| 4956 |
return String( plain_text || '' ) |
| 4957 |
.replace( /&/g, '&' ) |
| 4958 |
.replace( /</g, '<' ) |
| 4959 |
.replace( />/g, '>' ) |
| 4960 |
.replace( /"/g, '"' ) |
| 4961 |
.replace( /'/g, ''' ); |
| 4962 |
} |
| 4963 |
|
| 4964 |
/** |
| 4965 |
* Wrap plain text (with newlines) in a small HTML container. |
| 4966 |
* @param {string} msg |
| 4967 |
* @return {string} |
| 4968 |
*/ |
| 4969 |
function wrap_html(msg) { |
| 4970 |
return '<div style="font-size:13px;margin:10px;">' + escape_html( msg ).replace( /\n/g, '<br>' ) + '</div>'; |
| 4971 |
} |
| 4972 |
|
| 4973 |
/** Library presence checks (fast & cheap). */
|
| 4974 |
function has_jq() {
|
| 4975 |
return !!(w.jQuery && jQuery.fn && typeof jQuery.fn.on === 'function');
|
| 4976 |
}
|
| 4977 |
|
| 4978 |
function has_dp() {
|
| 4979 |
return !!(w.jQuery && jQuery.datepick);
|
| 4980 |
}
|
| 4981 |
|
| 4982 |
function has_wpbc() {
|
| 4983 |
return !!(w._wpbc && typeof w._wpbc.set_other_param === 'function');
|
| 4984 |
}
|
| 4985 |
|
| 4986 |
function normalize_rid(rid) {
|
| 4987 |
var n = parseInt( rid, 10 );
|
| 4988 |
return (n > 0) ? String( n ) : '';
|
| 4989 |
}
|
| 4990 |
|
| 4991 |
function get_rid_counts(rid) {
|
| 4992 |
var r = normalize_rid( rid );
|
| 4993 |
return {
|
| 4994 |
rid : r,
|
| 4995 |
loaders : r ? query_all( '.calendar_loader_frame[data-wpbc-rid="' + r + '"]' ).length : 0,
|
| 4996 |
containers: r ? query_all( '#calendar_booking' + r ).length : 0
|
| 4997 |
};
|
| 4998 |
}
|
| 4999 |
|
| 5000 |
function is_duplicate_rid(rid) {
|
| 5001 |
var c = get_rid_counts( rid );
|
| 5002 |
return (c.loaders > 1) || (c.containers > 1);
|
| 5003 |
}
|
| 5004 |
|
| 5005 |
/**
|
| 5006 |
* Determine if the loader has been replaced by the real calendar.
|
| 5007 |
*
|
| 5008 |
* @param {Element} el Loader element
|
| 5009 |
* @param {string} rid Resource ID
|
| 5010 |
* @param {Element|null} container Optional #calendar_booking{rid} element
|
| 5011 |
* @return {boolean}
|
| 5012 |
*/
|
| 5013 |
function is_replaced(el, rid, container) {
|
| 5014 |
var loader_still_in_dom = d.body.contains( el );
|
| 5015 |
var calendar_exists = !!query_one( '.wpbc_calendar_id_' + rid, container || d );
|
| 5016 |
return (!loader_still_in_dom) || calendar_exists;
|
| 5017 |
}
|
| 5018 |
|
| 5019 |
/**
|
| 5020 |
* Start watcher for a single loader element.
|
| 5021 |
* - Polls and observes the calendar container.
|
| 5022 |
* - After grace, injects a suitable message if not replaced.
|
| 5023 |
*
|
| 5024 |
* @param {Element} el
|
| 5025 |
*/
|
| 5026 |
function start_for(el) {
|
| 5027 |
if ( ! el || is_processed( el ) ) {
|
| 5028 |
return;
|
| 5029 |
}
|
| 5030 |
mark_processed( el );
|
| 5031 |
|
| 5032 |
var rid = el.dataset.wpbcRid;
|
| 5033 |
if ( ! rid ) {
|
| 5034 |
return;
|
| 5035 |
}
|
| 5036 |
|
| 5037 |
var grace_ms = parseInt( el.dataset.wpbcGrace || '8000', 10 );
|
| 5038 |
if ( ! (grace_ms > 0) ) {
|
| 5039 |
grace_ms = 8000;
|
| 5040 |
}
|
| 5041 |
|
| 5042 |
var container_id = 'calendar_booking' + rid;
|
| 5043 |
var container = d.getElementById( container_id );
|
| 5044 |
var text_el = query_one( '.calendar_loader_text', el );
|
| 5045 |
|
| 5046 |
function replaced_now() {
|
| 5047 |
return is_replaced( el, rid, container );
|
| 5048 |
}
|
| 5049 |
|
| 5050 |
// Already replaced -> nothing to do.
|
| 5051 |
if ( replaced_now() ) {
|
| 5052 |
return;
|
| 5053 |
}
|
| 5054 |
|
| 5055 |
// 1) Cheap polling.
|
| 5056 |
var poll_id = w.setInterval( function () {
|
| 5057 |
if ( replaced_now() ) {
|
| 5058 |
safe_clear( poll_id );
|
| 5059 |
if ( observer ) {
|
| 5060 |
try {
|
| 5061 |
observer.disconnect();
|
| 5062 |
} catch ( e ) {
|
| 5063 |
}
|
| 5064 |
}
|
| 5065 |
}
|
| 5066 |
}, 250 );
|
| 5067 |
|
| 5068 |
// 2) MutationObserver for faster reaction.
|
| 5069 |
var observer = null;
|
| 5070 |
if ( container && 'MutationObserver' in w ) {
|
| 5071 |
try {
|
| 5072 |
observer = new MutationObserver( function () {
|
| 5073 |
if ( replaced_now() ) {
|
| 5074 |
safe_clear( poll_id );
|
| 5075 |
try {
|
| 5076 |
observer.disconnect();
|
| 5077 |
} catch ( e ) {
|
| 5078 |
}
|
| 5079 |
}
|
| 5080 |
} );
|
| 5081 |
observer.observe( container, { childList: true, subtree: true } );
|
| 5082 |
} catch ( e ) {
|
| 5083 |
}
|
| 5084 |
}
|
| 5085 |
|
| 5086 |
// 3) Final decision after grace period.
|
| 5087 |
w.setTimeout( function finalize_after_grace() {
|
| 5088 |
if ( replaced_now() ) {
|
| 5089 |
safe_clear( poll_id );
|
| 5090 |
if ( observer ) {
|
| 5091 |
try {
|
| 5092 |
observer.disconnect();
|
| 5093 |
} catch ( e ) {
|
| 5094 |
}
|
| 5095 |
}
|
| 5096 |
return;
|
| 5097 |
}
|
| 5098 |
|
| 5099 |
var M = get_messages( rid );
|
| 5100 |
var msg;
|
| 5101 |
if ( ! has_jq() ) {
|
| 5102 |
msg = M.lib_jq;
|
| 5103 |
} else if ( ! has_wpbc() ) {
|
| 5104 |
msg = M.lib_wpbc;
|
| 5105 |
} else if ( ! has_dp() ) {
|
| 5106 |
msg = M.lib_dp;
|
| 5107 |
} else {
|
| 5108 |
// Libraries are present, but loader wasn't replaced -> decide what is most likely.
|
| 5109 |
if ( is_duplicate_rid( rid ) ) {
|
| 5110 |
msg = M.duplicate + '\n\n' + M.support;
|
| 5111 |
} else {
|
| 5112 |
msg = M.init_failed + '\n\n' + M.support;
|
| 5113 |
}
|
| 5114 |
}
|
| 5115 |
|
| 5116 |
try {
|
| 5117 |
if ( text_el ) {
|
| 5118 |
text_el.innerHTML = wrap_html( msg );
|
| 5119 |
}
|
| 5120 |
} catch ( e ) {
|
| 5121 |
}
|
| 5122 |
|
| 5123 |
safe_clear( poll_id );
|
| 5124 |
if ( observer ) {
|
| 5125 |
try {
|
| 5126 |
observer.disconnect();
|
| 5127 |
} catch ( e ) {
|
| 5128 |
}
|
| 5129 |
}
|
| 5130 |
}, grace_ms );
|
| 5131 |
}
|
| 5132 |
|
| 5133 |
/**
|
| 5134 |
* Initialize watchers for loader elements already in the DOM.
|
| 5135 |
*/
|
| 5136 |
function bootstrap_existing() {
|
| 5137 |
query_all( '.calendar_loader_frame[data-wpbc-rid]' ).forEach( start_for );
|
| 5138 |
}
|
| 5139 |
|
| 5140 |
/**
|
| 5141 |
* Observe the document for any new loader elements inserted later (AJAX, block render).
|
| 5142 |
*/
|
| 5143 |
function observe_new_loaders() {
|
| 5144 |
if ( ! ('MutationObserver' in w) ) {
|
| 5145 |
return;
|
| 5146 |
}
|
| 5147 |
try {
|
| 5148 |
var doc_observer = new MutationObserver( function (mutations) {
|
| 5149 |
for ( var i = 0; i < mutations.length; i++ ) {
|
| 5150 |
var nodes = mutations[i].addedNodes || [];
|
| 5151 |
for ( var j = 0; j < nodes.length; j++ ) {
|
| 5152 |
var node = nodes[j];
|
| 5153 |
if ( ! node || node.nodeType !== 1 ) {
|
| 5154 |
continue;
|
| 5155 |
}
|
| 5156 |
if ( node.matches && node.matches( '.calendar_loader_frame[data-wpbc-rid]' ) ) {
|
| 5157 |
start_for( node );
|
| 5158 |
}
|
| 5159 |
if ( node.querySelectorAll ) {
|
| 5160 |
var inner = node.querySelectorAll( '.calendar_loader_frame[data-wpbc-rid]' );
|
| 5161 |
if ( inner && inner.length ) {
|
| 5162 |
inner.forEach( start_for );
|
| 5163 |
}
|
| 5164 |
}
|
| 5165 |
}
|
| 5166 |
}
|
| 5167 |
} );
|
| 5168 |
doc_observer.observe( d.documentElement, { childList: true, subtree: true } );
|
| 5169 |
} catch ( e ) {
|
| 5170 |
}
|
| 5171 |
}
|
| 5172 |
|
| 5173 |
/* ---------------------------------------------------------------------------
|
| 5174 |
* Boot
|
| 5175 |
* ------------------------------------------------------------------------ */
|
| 5176 |
on_ready( function () {
|
| 5177 |
bootstrap_existing();
|
| 5178 |
observe_new_loaders();
|
| 5179 |
} );
|
| 5180 |
|
| 5181 |
})( window, document );
|
| 5182 |
|
| 5183 |
(function( w ) {
|
| 5184 |
|
| 5185 |
'use strict';
|
| 5186 |
|
| 5187 |
if ( ! w.WPBC_FE ) {
|
| 5188 |
w.WPBC_FE = {};
|
| 5189 |
}
|
| 5190 |
|
| 5191 |
/**
|
| 5192 |
* Auto-fill booking form fields (text/email) based on input "name" patterns.
|
| 5193 |
*
|
| 5194 |
* Form ID format: booking_form{resource_id}
|
| 5195 |
* Skips date field: date_booking{resource_id}
|
| 5196 |
*
|
| 5197 |
* @param {number} resource_id Booking resource ID.
|
| 5198 |
* @param {Object} fill_values Values to inject (strings).
|
| 5199 |
*
|
| 5200 |
* @return {boolean} True if form found and processed, false otherwise.
|
| 5201 |
*/
|
| 5202 |
w.WPBC_FE.autofill_booking_form_fields = function( resource_id, fill_values ) {
|
| 5203 |
|
| 5204 |
resource_id = parseInt( resource_id, 10 ) || 0;
|
| 5205 |
fill_values = fill_values || {};
|
| 5206 |
|
| 5207 |
var form_id = 'booking_form' + resource_id;
|
| 5208 |
var date_name = 'date_booking' + resource_id;
|
| 5209 |
|
| 5210 |
var submit_form = document.getElementById( form_id );
|
| 5211 |
|
| 5212 |
if ( ! submit_form ) {
|
| 5213 |
/* eslint-disable no-console */
|
| 5214 |
console.error( 'WPBC: No booking form: ' + form_id );
|
| 5215 |
/* eslint-enable no-console */
|
| 5216 |
return false;
|
| 5217 |
}
|
| 5218 |
|
| 5219 |
// Keep same regex rules and priority order as legacy inline JS.
|
| 5220 |
var rules = array_rules( fill_values );
|
| 5221 |
|
| 5222 |
var elements = submit_form.elements || [];
|
| 5223 |
var count = elements.length;
|
| 5224 |
var el;
|
| 5225 |
var i;
|
| 5226 |
var j;
|
| 5227 |
|
| 5228 |
for ( i = 0; i < count; i++ ) {
|
| 5229 |
|
| 5230 |
el = elements[ i ];
|
| 5231 |
|
| 5232 |
if ( ! el || ! el.name ) {
|
| 5233 |
continue;
|
| 5234 |
}
|
| 5235 |
|
| 5236 |
// Only text/email inputs.
|
| 5237 |
if ( ( el.type !== 'text' ) && ( el.type !== 'email' ) ) {
|
| 5238 |
continue;
|
| 5239 |
}
|
| 5240 |
|
| 5241 |
// Skip date field.
|
| 5242 |
if ( el.name === date_name ) {
|
| 5243 |
continue;
|
| 5244 |
}
|
| 5245 |
|
| 5246 |
// Fill only empty values (legacy behavior: == "").
|
| 5247 |
if ( el.value !== '' ) {
|
| 5248 |
continue;
|
| 5249 |
}
|
| 5250 |
|
| 5251 |
for ( j = 0; j < rules.length; j++ ) {
|
| 5252 |
|
| 5253 |
if ( rules[ j ].re.test( el.name ) ) {
|
| 5254 |
|
| 5255 |
if ( rules[ j ].val !== '' ) {
|
| 5256 |
el.value = rules[ j ].val;
|
| 5257 |
}
|
| 5258 |
|
| 5259 |
break; // Stop at first matching rule (priority).
|
| 5260 |
}
|
| 5261 |
}
|
| 5262 |
}
|
| 5263 |
|
| 5264 |
return true;
|
| 5265 |
};
|
| 5266 |
|
| 5267 |
/**
|
| 5268 |
* Build rules array for autofill.
|
| 5269 |
*
|
| 5270 |
* @param {Object} fill_values Values to inject.
|
| 5271 |
*
|
| 5272 |
* @return {Array} Rules list.
|
| 5273 |
*/
|
| 5274 |
function array_rules( fill_values ) {
|
| 5275 |
|
| 5276 |
// Normalize to strings (prevent "undefined" in fields).
|
| 5277 |
var nickname = ( fill_values.nickname != null ) ? String( fill_values.nickname ) : '';
|
| 5278 |
var last_name = ( fill_values.last_name != null ) ? String( fill_values.last_name ) : '';
|
| 5279 |
var first_name = ( fill_values.first_name != null ) ? String( fill_values.first_name ) : '';
|
| 5280 |
var email = ( fill_values.email != null ) ? String( fill_values.email ) : '';
|
| 5281 |
var phone = ( fill_values.phone != null ) ? String( fill_values.phone ) : '';
|
| 5282 |
var nb_enfant = ( fill_values.nb_enfant != null ) ? String( fill_values.nb_enfant ) : '';
|
| 5283 |
var url = ( fill_values.url != null ) ? String( fill_values.url ) : '';
|
| 5284 |
|
| 5285 |
return [
|
| 5286 |
{ re: /^([A-Za-z0-9_\-\.])*(nickname){1}([A-Za-z0-9_\-\.])*$/, val: nickname },
|
| 5287 |
{ re: /^([A-Za-z0-9_\-\.])*(last|second){1}([_\-\.])?name([A-Za-z0-9_\-\.])*$/, val: last_name },
|
| 5288 |
{ re: /^name([0-9_\-\.])*$/, val: first_name },
|
| 5289 |
{ re: /^([A-Za-z0-9_\-\.])*(first|my){1}([_\-\.])?name([A-Za-z0-9_\-\.])*$/, val: first_name },
|
| 5290 |
{ re: /^(e)?([_\-\.])?mail([0-9_\-\.]*)$/, val: email },
|
| 5291 |
{ re: /^([A-Za-z0-9_\-\.])*(phone|fone){1}([A-Za-z0-9_\-\.])*$/, val: phone },
|
| 5292 |
{ re: /^(e)?([_\-\.])?nb_enfant([0-9_\-\.]*)$/, val: nb_enfant },
|
| 5293 |
{ re: /^([A-Za-z0-9_\-\.])*(URL|site|web|WEB){1}([A-Za-z0-9_\-\.])*$/, val: url }
|
| 5294 |
];
|
| 5295 |
}
|
| 5296 |
|
| 5297 |
})( window );
|
| 5298 |
|
| 5299 |
// == Submit Booking Data ==============================================================================================
|
| 5300 |
// Refactored (safe), with new wpbc_* names.
|
| 5301 |
// Backward-compatible wrappers for legacy function names are included at the bottom.
|
| 5302 |
// @file: includes/__js/client/front_end_form/booking_form_submit.js
|
| 5303 |
|
| 5304 |
/** |
| 5305 |
* Check whether a form belongs to a request-local booking preview. |
| 5306 |
* |
| 5307 |
* Signed iframe and new-window previews intentionally do not use this marker; |
| 5308 |
* they retain the complete Booking Calendar preview lifecycle. |
| 5309 |
* |
| 5310 |
* @param {HTMLFormElement} submit_form Booking form being submitted. |
| 5311 |
* @return {boolean} True when final submission must remain local and non-mutating. |
| 5312 |
*/ |
| 5313 |
function wpbc_booking_form__is_inline_preview_submission( submit_form ) { |
| 5314 |
return 0 < jQuery( submit_form ).closest( '[data-wpbc-inline-booking-preview="1"]' ).length; |
| 5315 |
} |
| 5316 |
|
| 5317 |
/** |
| 5318 |
* Explain below the form why a request-local preview cannot create a booking. |
| 5319 |
* |
| 5320 |
* @param {HTMLFormElement} submit_form Booking form being submitted. |
| 5321 |
* @return {void} |
| 5322 |
*/ |
| 5323 |
function wpbc_booking_form__show_inline_preview_submission_notice( submit_form ) { |
| 5324 |
wpbc_front_end__show_message__warning_under_element( |
| 5325 |
submit_form, |
| 5326 |
_wpbc.get_message( 'message_inline_preview_submission_disabled' ), |
| 5327 |
'text' |
| 5328 |
); |
| 5329 |
} |
| 5330 |
|
| 5331 |
/** |
| 5332 |
* Check fields at form and then send request (legacy: mybooking_submit). |
| 5333 |
*
|
| 5334 |
* @param {HTMLFormElement} submit_form
|
| 5335 |
* @param {number|string} resource_id
|
| 5336 |
* @param {string} wpdev_active_locale
|
| 5337 |
*
|
| 5338 |
* @return {false|undefined} Legacy behavior: returns false in some cases, otherwise undefined.
|
| 5339 |
*/
|
| 5340 |
function wpbc_booking_form_submit( submit_form, resource_id, wpdev_active_locale ) {
|
| 5341 |
|
| 5342 |
resource_id = parseInt( resource_id, 10 );
|
| 5343 |
|
| 5344 |
// Safety guard (legacy code assumed valid form).
|
| 5345 |
if ( ! submit_form || ! submit_form.elements ) {
|
| 5346 |
/* eslint-disable no-console */
|
| 5347 |
console.error( 'WPBC: Invalid submit form in wpbc_booking_form_submit().' );
|
| 5348 |
/* eslint-enable no-console */
|
| 5349 |
return false;
|
| 5350 |
}
|
| 5351 |
|
| 5352 |
// -------------------------------------------------------------------------
|
| 5353 |
// External hook: allow pause submit on confirmation/summary step.
|
| 5354 |
// -------------------------------------------------------------------------
|
| 5355 |
var target_elm = jQuery( '.booking_form_div' ).trigger( 'booking_form_submit_click', [ resource_id, submit_form, wpdev_active_locale ] ); // FixIn: 8.8.3.13.
|
| 5356 |
|
| 5357 |
if (
|
| 5358 |
( jQuery( target_elm ).find( 'input[name="booking_form_show_summary"]' ).length > 0 ) &&
|
| 5359 |
( 'pause_submit' === jQuery( target_elm ).find( 'input[name="booking_form_show_summary"]' ).val() )
|
| 5360 |
) { |
| 5361 |
return false; |
| 5362 |
} |
| 5363 |
|
| 5364 |
if ( wpbc_booking_form__is_inline_preview_submission( submit_form ) ) { |
| 5365 |
wpbc_booking_form__show_inline_preview_submission_notice( submit_form ); |
| 5366 |
return false; |
| 5367 |
} |
| 5368 |
|
| 5369 |
// FixIn: 8.4.0.2. |
| 5370 |
var is_error = wpbc_check_errors_in_booking_form( resource_id );
|
| 5371 |
if ( is_error ) {
|
| 5372 |
return false;
|
| 5373 |
}
|
| 5374 |
|
| 5375 |
// -------------------------------------------------------------------------
|
| 5376 |
// Show message if no selected days in Calendar(s).
|
| 5377 |
// -------------------------------------------------------------------------
|
| 5378 |
var date_input = document.getElementById( 'date_booking' + resource_id );
|
| 5379 |
var date_value = ( date_input ) ? date_input.value : '';
|
| 5380 |
|
| 5381 |
if ( '' === date_value ) {
|
| 5382 |
|
| 5383 |
var arr_of_selected_additional_calendars = wpbc_get_arr_of_selected_additional_calendars( resource_id ); // FixIn: 8.5.2.26.
|
| 5384 |
|
| 5385 |
if ( ! arr_of_selected_additional_calendars || ( arr_of_selected_additional_calendars.length === 0 ) ) {
|
| 5386 |
wpbc_front_end__show_message__warning( |
| 5387 |
'#booking_form_div' + resource_id + ' .bk_calendar_frame', |
| 5388 |
_wpbc.get_message( 'message_check_no_selected_dates' ), |
| 5389 |
'text' |
| 5390 |
); |
| 5391 |
return;
|
| 5392 |
}
|
| 5393 |
}
|
| 5394 |
|
| 5395 |
// -------------------------------------------------------------------------
|
| 5396 |
// FixIn: 6.1.1.3. Time selection availability checks.
|
| 5397 |
// -------------------------------------------------------------------------
|
| 5398 |
if ( typeof wpbc_is_this_time_selection_not_available === 'function' ) {
|
| 5399 |
|
| 5400 |
if ( '' === date_value ) { // Primary calendar not selected.
|
| 5401 |
|
| 5402 |
var additional_calendars_el = document.getElementById( 'additional_calendars' + resource_id );
|
| 5403 |
|
| 5404 |
if ( additional_calendars_el !== null ) { // Checking additional calendars.
|
| 5405 |
|
| 5406 |
var id_additional_str = additional_calendars_el.value;
|
| 5407 |
var id_additional_arr = id_additional_str.split( ',' );
|
| 5408 |
var is_times_dates_ok = false;
|
| 5409 |
|
| 5410 |
for ( var ia = 0; ia < id_additional_arr.length; ia++ ) {
|
| 5411 |
|
| 5412 |
var add_id = id_additional_arr[ ia ];
|
| 5413 |
|
| 5414 |
var add_date_el = document.getElementById( 'date_booking' + add_id );
|
| 5415 |
var add_date_val = ( add_date_el ) ? add_date_el.value : '';
|
| 5416 |
|
| 5417 |
if (
|
| 5418 |
( '' !== add_date_val ) &&
|
| 5419 |
( ! wpbc_is_this_time_selection_not_available( add_id, submit_form.elements ) )
|
| 5420 |
) {
|
| 5421 |
is_times_dates_ok = true;
|
| 5422 |
}
|
| 5423 |
}
|
| 5424 |
|
| 5425 |
if ( ! is_times_dates_ok ) {
|
| 5426 |
return;
|
| 5427 |
}
|
| 5428 |
}
|
| 5429 |
|
| 5430 |
} else { // Primary calendar selected.
|
| 5431 |
|
| 5432 |
if ( wpbc_is_this_time_selection_not_available( resource_id, submit_form.elements ) ) {
|
| 5433 |
return;
|
| 5434 |
}
|
| 5435 |
}
|
| 5436 |
}
|
| 5437 |
|
| 5438 |
// -------------------------------------------------------------------------
|
| 5439 |
// Serialize form (legacy format).
|
| 5440 |
// -------------------------------------------------------------------------
|
| 5441 |
var count = submit_form.elements.length;
|
| 5442 |
var formdata = '';
|
| 5443 |
var inp_value;
|
| 5444 |
var inp_title_value;
|
| 5445 |
var element;
|
| 5446 |
var el_type;
|
| 5447 |
|
| 5448 |
// Helper: legacy escaping for the serialized value.
|
| 5449 |
function wpbc_escape_serialized_value( val ) {
|
| 5450 |
|
| 5451 |
val = ( val == null ) ? '' : String( val );
|
| 5452 |
|
| 5453 |
// Replace registered characters.
|
| 5454 |
val = val.replace( new RegExp( '\\^', 'g' ), '^' );
|
| 5455 |
val = val.replace( new RegExp( '~', 'g' ), '~' );
|
| 5456 |
|
| 5457 |
// Replace quotes.
|
| 5458 |
val = val.replace( /"/g, '"' );
|
| 5459 |
val = val.replace( /'/g, ''' );
|
| 5460 |
|
| 5461 |
return val;
|
| 5462 |
}
|
| 5463 |
|
| 5464 |
// Helper: determine UI type for title extraction (legacy logic).
|
| 5465 |
function wpbc_get_input_element_type( el ) {
|
| 5466 |
|
| 5467 |
if ( ! el || ! el.tagName ) {
|
| 5468 |
return '';
|
| 5469 |
}
|
| 5470 |
|
| 5471 |
var tag = String( el.tagName ).toLowerCase();
|
| 5472 |
|
| 5473 |
if ( 'input' === tag ) {
|
| 5474 |
return ( el.type ) ? String( el.type ).toLowerCase() : 'text';
|
| 5475 |
}
|
| 5476 |
|
| 5477 |
// Legacy used "select" string here.
|
| 5478 |
if ( 'select' === tag ) {
|
| 5479 |
return 'select';
|
| 5480 |
}
|
| 5481 |
|
| 5482 |
return tag;
|
| 5483 |
}
|
| 5484 |
|
| 5485 |
for ( var i = 0; i < count; i++ ) { // FixIn: 9.1.5.1.
|
| 5486 |
|
| 5487 |
element = submit_form.elements[ i ];
|
| 5488 |
|
| 5489 |
if ( ! element ) {
|
| 5490 |
continue;
|
| 5491 |
}
|
| 5492 |
|
| 5493 |
if ( jQuery( element ).closest( '.booking_form_garbage' ).length ) {
|
| 5494 |
continue; // Skip elements from garbage. FixIn: 7.1.2.14.
|
| 5495 |
}
|
| 5496 |
|
| 5497 |
if ( '1' === String( jQuery( element ).attr( 'data-wpbc-booking-submit-ignore' ) || '' ) ) {
|
| 5498 |
continue;
|
| 5499 |
}
|
| 5500 |
|
| 5501 |
if (
|
| 5502 |
( element.type !== 'button' ) &&
|
| 5503 |
( element.type !== 'hidden' ) &&
|
| 5504 |
( element.name !== ( 'date_booking' + resource_id ) )
|
| 5505 |
// && ( jQuery( element ).is( ':visible' ) ) //FixIn: 7.2.1.12.2
|
| 5506 |
) {
|
| 5507 |
|
| 5508 |
// -------------------------------------------------------------
|
| 5509 |
// Get element value.
|
| 5510 |
// -------------------------------------------------------------
|
| 5511 |
if ( element.type === 'checkbox' ) {
|
| 5512 |
|
| 5513 |
if ( element.value === '' ) {
|
| 5514 |
inp_value = element.checked;
|
| 5515 |
} else {
|
| 5516 |
inp_value = ( element.checked ) ? element.value : '';
|
| 5517 |
}
|
| 5518 |
|
| 5519 |
} else if ( element.type === 'radio' ) {
|
| 5520 |
|
| 5521 |
if ( element.checked ) {
|
| 5522 |
inp_value = element.value;
|
| 5523 |
} else {
|
| 5524 |
|
| 5525 |
// Required radio: show warning if none checked.
|
| 5526 |
// FixIn: 7.0.1.62.
|
| 5527 |
if (
|
| 5528 |
( element.className.indexOf( 'wpdev-validates-as-required' ) !== -1 ) &&
|
| 5529 |
( jQuery( element ).is( ':visible' ) ) && // FixIn: 7.2.1.12.2.
|
| 5530 |
( ! jQuery( ':radio[name="' + element.name + '"]', submit_form ).is( ':checked' ) )
|
| 5531 |
) {
|
| 5532 |
wpbc_front_end__show_message__warning( element, _wpbc.get_message( 'message_check_required_for_radio_box' ), 'text' ); // FixIn: 8.5.1.3. |
| 5533 |
return;
|
| 5534 |
}
|
| 5535 |
|
| 5536 |
// Skip storing empty radio options.
|
| 5537 |
continue;
|
| 5538 |
}
|
| 5539 |
|
| 5540 |
} else {
|
| 5541 |
inp_value = element.value;
|
| 5542 |
}
|
| 5543 |
|
| 5544 |
inp_title_value = '';
|
| 5545 |
|
| 5546 |
// -------------------------------------------------------------
|
| 5547 |
// Get human-friendly title value (legacy behavior).
|
| 5548 |
// -------------------------------------------------------------
|
| 5549 |
var input_element_type = wpbc_get_input_element_type( element );
|
| 5550 |
|
| 5551 |
switch ( input_element_type ) {
|
| 5552 |
|
| 5553 |
case 'text':
|
| 5554 |
case 'email':
|
| 5555 |
inp_title_value = inp_value;
|
| 5556 |
break;
|
| 5557 |
|
| 5558 |
case 'select':
|
| 5559 |
inp_title_value = jQuery( element ).find( 'option:selected' ).text();
|
| 5560 |
break;
|
| 5561 |
|
| 5562 |
case 'radio':
|
| 5563 |
case 'checkbox':
|
| 5564 |
if ( jQuery( element ).is( ':checked' ) ) {
|
| 5565 |
var label_element = jQuery( element ).parents( '.wpdev-list-item' ).find( '.wpdev-list-item-label' );
|
| 5566 |
if ( label_element.length ) {
|
| 5567 |
inp_title_value = label_element.html();
|
| 5568 |
}
|
| 5569 |
}
|
| 5570 |
break;
|
| 5571 |
|
| 5572 |
default:
|
| 5573 |
inp_title_value = inp_value;
|
| 5574 |
}
|
| 5575 |
|
| 5576 |
// -------------------------------------------------------------
|
| 5577 |
// Multiple select value extraction.
|
| 5578 |
// -------------------------------------------------------------
|
| 5579 |
if ( ( element.type === 'selectbox-multiple' ) || ( element.type === 'select-multiple' ) ) {
|
| 5580 |
inp_value = jQuery( '[name="' + element.name + '"]' ).val();
|
| 5581 |
if ( ( inp_value === null ) || ( String( inp_value ) === '' ) ) {
|
| 5582 |
inp_value = '';
|
| 5583 |
}
|
| 5584 |
}
|
| 5585 |
|
| 5586 |
// -------------------------------------------------------------
|
| 5587 |
// Make validation only for visible elements.
|
| 5588 |
// -------------------------------------------------------------
|
| 5589 |
if ( jQuery( element ).is( ':visible' ) ) { // FixIn: 7.2.1.12.2.
|
| 5590 |
|
| 5591 |
// Recheck max available visitors selection.
|
| 5592 |
if ( typeof wpbc__is_less_than_required__of_max_available_slots__bl === 'function' ) {
|
| 5593 |
if ( wpbc__is_less_than_required__of_max_available_slots__bl( resource_id, element ) ) {
|
| 5594 |
return;
|
| 5595 |
}
|
| 5596 |
}
|
| 5597 |
|
| 5598 |
// Required fields.
|
| 5599 |
if ( element.className.indexOf( 'wpdev-validates-as-required' ) !== -1 ) {
|
| 5600 |
|
| 5601 |
if ( ( element.type === 'checkbox' ) && ( element.checked === false ) ) {
|
| 5602 |
|
| 5603 |
if ( ! jQuery( ':checkbox[name="' + element.name + '"]', submit_form ).is( ':checked' ) ) {
|
| 5604 |
wpbc_front_end__show_message__warning( element, _wpbc.get_message( 'message_check_required_for_check_box' ), 'text' ); // FixIn: 8.5.1.3. |
| 5605 |
return;
|
| 5606 |
}
|
| 5607 |
}
|
| 5608 |
|
| 5609 |
if ( element.type === 'radio' ) {
|
| 5610 |
|
| 5611 |
if ( ! jQuery( ':radio[name="' + element.name + '"]', submit_form ).is( ':checked' ) ) {
|
| 5612 |
wpbc_front_end__show_message__warning( element, _wpbc.get_message( 'message_check_required_for_radio_box' ), 'text' ); // FixIn: 8.5.1.3. |
| 5613 |
return;
|
| 5614 |
}
|
| 5615 |
}
|
| 5616 |
|
| 5617 |
if ( ( element.type !== 'checkbox' ) && ( element.type !== 'radio' ) && ( '' === wpbc_trim( inp_value ) ) ) {
|
| 5618 |
wpbc_front_end__show_message__warning( element, _wpbc.get_message( 'message_check_required' ), 'text' ); // FixIn: 8.5.1.3. |
| 5619 |
return;
|
| 5620 |
}
|
| 5621 |
}
|
| 5622 |
|
| 5623 |
// Email format validation.
|
| 5624 |
if ( element.className.indexOf( 'wpdev-validates-as-email' ) !== -1 ) {
|
| 5625 |
|
| 5626 |
inp_value = String( inp_value ).replace( /^\s+|\s+$/gm, '' ); // Trim white space. FixIn: 5.4.5.
|
| 5627 |
var reg_email = /^([A-Za-z0-9_\-\.\+])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,})$/;
|
| 5628 |
|
| 5629 |
if ( inp_value !== '' ) {
|
| 5630 |
if ( reg_email.test( inp_value ) === false ) {
|
| 5631 |
wpbc_front_end__show_message__warning( element, _wpbc.get_message( 'message_check_email' ), 'text' ); // FixIn: 8.5.1.3. |
| 5632 |
return;
|
| 5633 |
}
|
| 5634 |
}
|
| 5635 |
}
|
| 5636 |
|
| 5637 |
// Same email field validation (verification field).
|
| 5638 |
if ( ( element.className.indexOf( 'wpdev-validates-as-email' ) !== -1 ) && ( element.className.indexOf( 'same_as_' ) !== -1 ) ) {
|
| 5639 |
|
| 5640 |
var primary_email_name = element.className.match( /same_as_([^\s])+/gi );
|
| 5641 |
|
| 5642 |
if ( primary_email_name !== null ) {
|
| 5643 |
|
| 5644 |
primary_email_name = primary_email_name[ 0 ].substr( 8 );
|
| 5645 |
|
| 5646 |
if ( jQuery( '[name="' + primary_email_name + resource_id + '"]' ).length > 0 ) {
|
| 5647 |
|
| 5648 |
if ( jQuery( '[name="' + primary_email_name + resource_id + '"]' ).val() !== inp_value ) {
|
| 5649 |
wpbc_front_end__show_message__warning( element, _wpbc.get_message( 'message_check_same_email' ), 'text' ); // FixIn: 8.5.1.3. |
| 5650 |
return;
|
| 5651 |
}
|
| 5652 |
}
|
| 5653 |
}
|
| 5654 |
|
| 5655 |
// Skip one loop for the email verification field.
|
| 5656 |
continue; // FixIn: 8.1.2.15.
|
| 5657 |
}
|
| 5658 |
}
|
| 5659 |
|
| 5660 |
// -------------------------------------------------------------
|
| 5661 |
// Get Form Data (legacy format).
|
| 5662 |
// -------------------------------------------------------------
|
| 5663 |
if ( element.name !== ( 'captcha_input' + resource_id ) ) {
|
| 5664 |
|
| 5665 |
if ( formdata !== '' ) {
|
| 5666 |
formdata += '~';
|
| 5667 |
}
|
| 5668 |
|
| 5669 |
el_type = element.type;
|
| 5670 |
|
| 5671 |
if ( element.className.indexOf( 'wpdev-validates-as-email' ) !== -1 ) {
|
| 5672 |
el_type = 'email';
|
| 5673 |
}
|
| 5674 |
if ( element.className.indexOf( 'wpdev-validates-as-coupon' ) !== -1 ) {
|
| 5675 |
el_type = 'coupon';
|
| 5676 |
}
|
| 5677 |
|
| 5678 |
inp_value = wpbc_escape_serialized_value( inp_value );
|
| 5679 |
|
| 5680 |
if ( el_type === 'select-one' ) {
|
| 5681 |
el_type = 'selectbox-one';
|
| 5682 |
}
|
| 5683 |
if ( el_type === 'select-multiple' ) {
|
| 5684 |
el_type = 'selectbox-multiple';
|
| 5685 |
}
|
| 5686 |
|
| 5687 |
formdata += el_type + '^' + element.name + '^' + inp_value;
|
| 5688 |
|
| 5689 |
// Add title/label value (legacy).
|
| 5690 |
var clean_field_name = String( element.name );
|
| 5691 |
|
| 5692 |
// BUGFIX: replaceAll(RegExp) is not supported in older browsers.
|
| 5693 |
// Keep legacy intent: remove [] suffix occurrences.
|
| 5694 |
clean_field_name = clean_field_name.replace( /\[\]/gi, '' );
|
| 5695 |
|
| 5696 |
var resource_id_str = String( resource_id );
|
| 5697 |
|
| 5698 |
// Legacy assumed suffix ends with resource_id, make it safe.
|
| 5699 |
if (
|
| 5700 |
( clean_field_name.length >= resource_id_str.length ) &&
|
| 5701 |
( clean_field_name.substr( clean_field_name.length - resource_id_str.length ) === resource_id_str )
|
| 5702 |
) {
|
| 5703 |
clean_field_name = clean_field_name.substr( 0, clean_field_name.length - resource_id_str.length );
|
| 5704 |
}
|
| 5705 |
|
| 5706 |
formdata += '~' + el_type + '^' + clean_field_name + '_val' + resource_id + '^' + inp_title_value;
|
| 5707 |
}
|
| 5708 |
}
|
| 5709 |
}
|
| 5710 |
|
| 5711 |
// TODO: here was function for 'Check if visitor finish dates selection.
|
| 5712 |
|
| 5713 |
// Captcha verify.
|
| 5714 |
var captcha = document.getElementById( 'wpdev_captcha_challenge_' + resource_id );
|
| 5715 |
|
| 5716 |
if ( captcha !== null ) {
|
| 5717 |
wpbc_form_submit_send( resource_id, formdata, captcha.value, document.getElementById( 'captcha_input' + resource_id ).value, wpdev_active_locale );
|
| 5718 |
} else {
|
| 5719 |
wpbc_form_submit_send( resource_id, formdata, '', '', wpdev_active_locale );
|
| 5720 |
}
|
| 5721 |
|
| 5722 |
return;
|
| 5723 |
}
|
| 5724 |
|
| 5725 |
|
| 5726 |
/**
|
| 5727 |
* Gathering params for sending Ajax request and then send it (legacy: form_submit_send).
|
| 5728 |
*
|
| 5729 |
* @param {number|string} resource_id
|
| 5730 |
* @param {string} formdata
|
| 5731 |
* @param {string} captcha_chalange
|
| 5732 |
* @param {string} user_captcha
|
| 5733 |
* @param {string} wpdev_active_locale
|
| 5734 |
*
|
| 5735 |
* @return {undefined} Legacy behavior.
|
| 5736 |
*/
|
| 5737 |
function wpbc_form_submit_send( resource_id, formdata, captcha_chalange, user_captcha, wpdev_active_locale ) {
|
| 5738 |
|
| 5739 |
resource_id = parseInt( resource_id, 10 );
|
| 5740 |
|
| 5741 |
var my_booking_form = '';
|
| 5742 |
var booking_form_type_el = document.getElementById( 'booking_form_type' + resource_id );
|
| 5743 |
if ( booking_form_type_el !== null ) {
|
| 5744 |
my_booking_form = booking_form_type_el.value;
|
| 5745 |
}
|
| 5746 |
|
| 5747 |
var my_booking_hash = '';
|
| 5748 |
if ( _wpbc.get_other_param( 'this_page_booking_hash' ) !== '' ) {
|
| 5749 |
my_booking_hash = _wpbc.get_other_param( 'this_page_booking_hash' );
|
| 5750 |
}
|
| 5751 |
|
| 5752 |
var is_send_emeils = 1;
|
| 5753 |
var $is_send_email_toggle = jQuery( '#is_send_email_for_pending' );
|
| 5754 |
var $modal_send_email_toggle = jQuery( '#booking_form' + resource_id ).closest( '.wpbc_modal__add_booking__section' ).find( '[data-wpbc-add-booking-send-emails]' ).first();
|
| 5755 |
if ( $modal_send_email_toggle.length ) {
|
| 5756 |
$is_send_email_toggle = $modal_send_email_toggle;
|
| 5757 |
}
|
| 5758 |
if ( $is_send_email_toggle.length ) { // FixIn: 8.7.9.5.
|
| 5759 |
|
| 5760 |
is_send_emeils = $is_send_email_toggle.is( ':checked' );
|
| 5761 |
|
| 5762 |
if ( false === is_send_emeils ) {
|
| 5763 |
is_send_emeils = 0;
|
| 5764 |
} else {
|
| 5765 |
is_send_emeils = 1;
|
| 5766 |
}
|
| 5767 |
}
|
| 5768 |
|
| 5769 |
var date_el = document.getElementById( 'date_booking' + resource_id );
|
| 5770 |
var date_value = ( date_el ) ? date_el.value : '';
|
| 5771 |
|
| 5772 |
if ( '' !== date_value ) { // FixIn: 6.1.1.3.
|
| 5773 |
wpbc_send_ajax_submit( resource_id, formdata, captcha_chalange, user_captcha, is_send_emeils, my_booking_hash, my_booking_form, wpdev_active_locale );
|
| 5774 |
} else {
|
| 5775 |
jQuery( '#booking_form_div' + resource_id ).hide();
|
| 5776 |
jQuery( '#submiting' + resource_id ).hide();
|
| 5777 |
}
|
| 5778 |
|
| 5779 |
// -------------------------------------------------------------------------
|
| 5780 |
// Additional calendars submit.
|
| 5781 |
// -------------------------------------------------------------------------
|
| 5782 |
var additional_calendars_el = document.getElementById( 'additional_calendars' + resource_id );
|
| 5783 |
if ( additional_calendars_el === null ) {
|
| 5784 |
return;
|
| 5785 |
}
|
| 5786 |
|
| 5787 |
var id_additional_str = additional_calendars_el.value;
|
| 5788 |
var id_additional_arr = id_additional_str.split( ',' );
|
| 5789 |
|
| 5790 |
// FixIn: 10.9.4.1.
|
| 5791 |
for ( var ia = 0; ia < id_additional_arr.length; ia++ ) {
|
| 5792 |
id_additional_arr[ ia ] = parseInt( id_additional_arr[ ia ], 10 );
|
| 5793 |
}
|
| 5794 |
|
| 5795 |
if ( ! jQuery( '#booking_form_div' + resource_id ).is( ':visible' ) ) {
|
| 5796 |
wpbc_booking_form__spin_loader__show( resource_id ); // Show Spinner
|
| 5797 |
}
|
| 5798 |
|
| 5799 |
// Helper: rewrite field name suffix from resource_id -> id_additional.
|
| 5800 |
function wpbc_rewrite_field_name_suffix( field_name, old_id, new_id ) {
|
| 5801 |
|
| 5802 |
field_name = String( field_name );
|
| 5803 |
|
| 5804 |
var old_id_str = String( old_id );
|
| 5805 |
var new_id_str = String( new_id );
|
| 5806 |
|
| 5807 |
// Handle fields with [].
|
| 5808 |
if (
|
| 5809 |
( field_name.length >= ( old_id_str.length + 2 ) ) &&
|
| 5810 |
( field_name.substr( field_name.length - ( old_id_str.length + 2 ) ) === ( old_id_str + '[]' ) )
|
| 5811 |
) {
|
| 5812 |
return field_name.substr( 0, field_name.length - ( old_id_str.length + 2 ) ) + new_id_str + '[]';
|
| 5813 |
}
|
| 5814 |
|
| 5815 |
// Handle fields without [].
|
| 5816 |
if (
|
| 5817 |
( field_name.length >= old_id_str.length ) &&
|
| 5818 |
( field_name.substr( field_name.length - old_id_str.length ) === old_id_str )
|
| 5819 |
) {
|
| 5820 |
return field_name.substr( 0, field_name.length - old_id_str.length ) + new_id_str;
|
| 5821 |
}
|
| 5822 |
|
| 5823 |
// Fallback: return unchanged (safer than breaking name).
|
| 5824 |
return field_name;
|
| 5825 |
}
|
| 5826 |
|
| 5827 |
for ( ia = 0; ia < id_additional_arr.length; ia++ ) {
|
| 5828 |
|
| 5829 |
var id_additional = id_additional_arr[ ia ];
|
| 5830 |
|
| 5831 |
// FixIn: 10.9.4.1.
|
| 5832 |
if ( id_additional <= 0 ) {
|
| 5833 |
continue;
|
| 5834 |
}
|
| 5835 |
|
| 5836 |
// Rebuild formdata for each additional calendar (legacy behavior).
|
| 5837 |
var formdata_additional_arr = String( formdata ).split( '~' );
|
| 5838 |
var formdata_additional = '';
|
| 5839 |
|
| 5840 |
for ( var j = 0; j < formdata_additional_arr.length; j++ ) {
|
| 5841 |
|
| 5842 |
var my_form_field = formdata_additional_arr[ j ].split( '^' );
|
| 5843 |
|
| 5844 |
if ( formdata_additional !== '' ) {
|
| 5845 |
formdata_additional += '~';
|
| 5846 |
}
|
| 5847 |
|
| 5848 |
// Safety: ensure we have at least type ^ name ^ value.
|
| 5849 |
if ( my_form_field.length < 3 ) {
|
| 5850 |
formdata_additional += formdata_additional_arr[ j ];
|
| 5851 |
continue;
|
| 5852 |
}
|
| 5853 |
|
| 5854 |
my_form_field[ 1 ] = wpbc_rewrite_field_name_suffix( my_form_field[ 1 ], resource_id, id_additional );
|
| 5855 |
formdata_additional += my_form_field[ 0 ] + '^' + my_form_field[ 1 ] + '^' + my_form_field[ 2 ];
|
| 5856 |
}
|
| 5857 |
|
| 5858 |
// If payment form for main booking resource is showing, append for additional calendars.
|
| 5859 |
if ( jQuery( '#gateway_payment_forms' + resource_id ).length > 0 ) {
|
| 5860 |
jQuery( '#gateway_payment_forms' + resource_id ).after( '<div id="gateway_payment_forms' + id_additional + '"></div>' );
|
| 5861 |
jQuery( '#gateway_payment_forms' + resource_id ).after( '<div id="ajax_respond_insert' + id_additional + '" style="display:none;"></div>' );
|
| 5862 |
}
|
| 5863 |
|
| 5864 |
// FixIn: 8.5.2.17.
|
| 5865 |
wpbc_send_ajax_submit( id_additional, formdata_additional, captcha_chalange, user_captcha, is_send_emeils, my_booking_hash, my_booking_form, wpdev_active_locale );
|
| 5866 |
}
|
| 5867 |
}
|
| 5868 |
|
| 5869 |
|
| 5870 |
/**
|
| 5871 |
* Send Ajax submit (legacy: send_ajax_submit).
|
| 5872 |
*
|
| 5873 |
* @param {number|string} resource_id
|
| 5874 |
* @param {string} formdata
|
| 5875 |
* @param {string} captcha_chalange
|
| 5876 |
* @param {string} user_captcha
|
| 5877 |
* @param {number} is_send_emeils
|
| 5878 |
* @param {string} my_booking_hash
|
| 5879 |
* @param {string} my_booking_form
|
| 5880 |
* @param {string} wpdev_active_locale
|
| 5881 |
*
|
| 5882 |
* @return {undefined} Legacy behavior.
|
| 5883 |
*/
|
| 5884 |
function wpbc_send_ajax_submit(resource_id, formdata, captcha_chalange, user_captcha, is_send_emeils, my_booking_hash, my_booking_form, wpdev_active_locale) {
|
| 5885 |
|
| 5886 |
resource_id = parseInt( resource_id, 10 );
|
| 5887 |
|
| 5888 |
// Disable Submit | Show spin loader.
|
| 5889 |
wpbc_booking_form__on_submit__ui_elements_disable( resource_id );
|
| 5890 |
|
| 5891 |
// FixIn: 2026-02-05 - pass preview context to booking create Ajax.
|
| 5892 |
var form_status = wpbc__get_form_status_for_submit( resource_id );
|
| 5893 |
var preview_args = (form_status === 'preview') ? wpbc__get_bfb_preview_args_from_location() : null;
|
| 5894 |
var $add_booking_modal = jQuery( '#booking_form' + resource_id ).closest( '#wpbc_modal__add_booking__section' ); |
| 5895 |
var is_allow_past = 0; |
| 5896 |
var classic_booking_context_token = ''; |
| 5897 |
var admin_booking_nonce = ''; |
| 5898 |
var has_add_booking_modal_context = ( $add_booking_modal.length && $add_booking_modal.is( ':visible' ) ); |
| 5899 |
if ( 'undefined' !== typeof _wpbc ) { |
| 5900 |
admin_booking_nonce = String( _wpbc.get_other_param( 'this_page_admin_booking_nonce' ) || '' ); |
| 5901 |
} |
| 5902 |
|
| 5903 |
if ( has_add_booking_modal_context ) {
|
| 5904 |
is_allow_past = $add_booking_modal.find( '[data-wpbc-add-booking-allow-past]' ).first().is( ':checked' ) ? 1 : 0;
|
| 5905 |
if ( ! is_allow_past ) {
|
| 5906 |
is_allow_past = ( '1' === String( $add_booking_modal.attr( 'data-wpbc-add-booking-allow-past' ) || '0' ) ) ? 1 : 0;
|
| 5907 |
}
|
| 5908 |
}
|
| 5909 |
if ( ! has_add_booking_modal_context && ( 'undefined' !== typeof _wpbc ) ) { |
| 5910 |
is_allow_past = ( '1' === String( _wpbc.get_other_param( 'this_page_allow_past' ) || '0' ) ) ? 1 : 0; |
| 5911 |
classic_booking_context_token = String( _wpbc.booking__get_param_value( resource_id, 'classic_booking_context_token' ) || '' ); |
| 5912 |
} |
| 5913 |
|
| 5914 |
var request_params = {
|
| 5915 |
'resource_id' : resource_id,
|
| 5916 |
'dates_ddmmyy_csv' : document.getElementById( 'date_booking' + resource_id ).value,
|
| 5917 |
'formdata' : formdata,
|
| 5918 |
'booking_hash' : my_booking_hash,
|
| 5919 |
'custom_form' : my_booking_form,
|
| 5920 |
'aggregate_resource_id_arr': ( ( null !== _wpbc.booking__get_param_value( resource_id, 'aggregate_resource_id_arr' ) ) ? _wpbc.booking__get_param_value( resource_id, 'aggregate_resource_id_arr' ).join( ',' ) : '' ),
|
| 5921 |
'captcha_chalange' : captcha_chalange,
|
| 5922 |
'captcha_user_input' : user_captcha,
|
| 5923 |
'is_emails_send' : is_send_emeils,
|
| 5924 |
'active_locale' : wpdev_active_locale,
|
| 5925 |
'form_status' : form_status, |
| 5926 |
'allow_past' : is_allow_past, |
| 5927 |
'classic_booking_context_token': classic_booking_context_token, |
| 5928 |
'wpbc_admin_booking_nonce' : admin_booking_nonce |
| 5929 |
}; |
| 5930 |
|
| 5931 |
var $time_override_panel = jQuery( '#booking_form' + resource_id ).find( '[data-wpbc-add-booking-time-override-panel]' ).first();
|
| 5932 |
if ( ! $time_override_panel.length ) {
|
| 5933 |
$time_override_panel = jQuery( '#wpbc_modal__add_booking__section:visible' ).find( '[data-wpbc-add-booking-time-override-panel]' ).first();
|
| 5934 |
}
|
| 5935 |
if (
|
| 5936 |
$time_override_panel.length
|
| 5937 |
&& $time_override_panel.find( '[data-wpbc-add-booking-time-override-enabled]' ).first().is( ':checked' )
|
| 5938 |
) {
|
| 5939 |
request_params['wpbc_time_override_enabled'] = 1;
|
| 5940 |
request_params['wpbc_time_override_source'] = $time_override_panel.attr( 'data-wpbc-add-booking-time-override-source' ) || '';
|
| 5941 |
request_params['wpbc_time_override_start'] = $time_override_panel.find( '[data-wpbc-add-booking-time-override-field="start"]' ).first().val() || '';
|
| 5942 |
request_params['wpbc_time_override_end'] = $time_override_panel.find( '[data-wpbc-add-booking-time-override-field="end"]' ).first().val() || '';
|
| 5943 |
}
|
| 5944 |
|
| 5945 |
var selected_dates_count = String( request_params['dates_ddmmyy_csv'] || '' ).split( ',' ).filter( function( date_text ){
|
| 5946 |
return '' !== String( date_text || '' ).replace( /^\s+|\s+$/g, '' );
|
| 5947 |
} ).length;
|
| 5948 |
var is_times_availability_override = (
|
| 5949 |
( 1 === parseInt( request_params['wpbc_time_override_enabled'] || 0, 10 ) )
|
| 5950 |
&& ( 'times_availability' === String( request_params['wpbc_time_override_source'] || '' ) )
|
| 5951 |
);
|
| 5952 |
if (
|
| 5953 |
(
|
| 5954 |
has_add_booking_modal_context
|
| 5955 |
&& '1' === String( $add_booking_modal.attr( 'data-wpbc-add-booking-force-recurrent-time' ) || '0' )
|
| 5956 |
)
|
| 5957 |
|| (
|
| 5958 |
is_times_availability_override
|
| 5959 |
&& ( selected_dates_count > 1 )
|
| 5960 |
)
|
| 5961 |
) {
|
| 5962 |
request_params['is_use_booking_recurrent_time'] = 1;
|
| 5963 |
}
|
| 5964 |
|
| 5965 |
// If preview, pass session identifiers so PHP can load transient snapshot.
|
| 5966 |
if ( preview_args && preview_args.token && preview_args.form_id ) {
|
| 5967 |
request_params['wpbc_bfb_preview'] = 1;
|
| 5968 |
request_params['wpbc_bfb_preview_token'] = preview_args.token;
|
| 5969 |
request_params['wpbc_bfb_preview_form_id'] = preview_args.form_id;
|
| 5970 |
request_params['wpbc_bfb_preview_nonce'] = preview_args.nonce; // note: URL param is `nonce`.
|
| 5971 |
}
|
| 5972 |
|
| 5973 |
var is_exit = wpbc_ajx_booking__create( request_params );
|
| 5974 |
|
| 5975 |
if ( true === is_exit ) {
|
| 5976 |
return;
|
| 5977 |
}
|
| 5978 |
}
|
| 5979 |
|
| 5980 |
|
| 5981 |
|
| 5982 |
// == Helper Functions =================================================================================================
|
| 5983 |
|
| 5984 |
/**
|
| 5985 |
* Parse query string into {key:value} (old-browser safe).
|
| 5986 |
*
|
| 5987 |
* @param {string} qs
|
| 5988 |
* @return {Object}
|
| 5989 |
*/
|
| 5990 |
function wpbc__parse_query_string(qs) {
|
| 5991 |
var out = {};
|
| 5992 |
qs = (qs || '');
|
| 5993 |
qs = qs.replace( /^\?/, '' );
|
| 5994 |
if ( ! qs ) {
|
| 5995 |
return out;
|
| 5996 |
}
|
| 5997 |
|
| 5998 |
var parts = qs.split( '&' );
|
| 5999 |
for ( var i = 0; i < parts.length; i++ ) {
|
| 6000 |
var kv = parts[i].split( '=' );
|
| 6001 |
var k = decodeURIComponent( kv[0] || '' );
|
| 6002 |
if ( ! k ) {
|
| 6003 |
continue;
|
| 6004 |
}
|
| 6005 |
var v = decodeURIComponent( kv.slice( 1 ).join( '=' ) || '' );
|
| 6006 |
out[k] = v;
|
| 6007 |
}
|
| 6008 |
return out;
|
| 6009 |
}
|
| 6010 |
|
| 6011 |
/**
|
| 6012 |
* Detect preview args from current URL (iframe URL).
|
| 6013 |
*
|
| 6014 |
* @return {Object|null} { token, form_id, nonce } or null
|
| 6015 |
*/
|
| 6016 |
function wpbc__get_bfb_preview_args_from_location() {
|
| 6017 |
try {
|
| 6018 |
var p = wpbc__parse_query_string( (window.location && window.location.search) ? window.location.search : '' );
|
| 6019 |
|
| 6020 |
if ( ! p.wpbc_bfb_preview || (p.wpbc_bfb_preview === '0') ) {
|
| 6021 |
return null;
|
| 6022 |
}
|
| 6023 |
|
| 6024 |
if ( ! p.wpbc_bfb_preview_token || ! p.wpbc_bfb_preview_form_id ) {
|
| 6025 |
return null;
|
| 6026 |
}
|
| 6027 |
|
| 6028 |
return {
|
| 6029 |
token : String( p.wpbc_bfb_preview_token ),
|
| 6030 |
form_id: parseInt( p.wpbc_bfb_preview_form_id, 10 ) || 0,
|
| 6031 |
nonce : (p.nonce) ? String( p.nonce ) : ''
|
| 6032 |
};
|
| 6033 |
} catch ( e ) {
|
| 6034 |
return null;
|
| 6035 |
}
|
| 6036 |
}
|
| 6037 |
|
| 6038 |
/**
|
| 6039 |
* Resolve form status for submit.
|
| 6040 |
*
|
| 6041 |
* Priority:
|
| 6042 |
* 1) shortcode param exposed via _wpbc.booking__get_param_value(..., 'form_status')
|
| 6043 |
* 2) detect preview URL args
|
| 6044 |
* 3) fallback: published
|
| 6045 |
*
|
| 6046 |
* @param {number} resource_id
|
| 6047 |
* @return {string} 'preview'|'published'
|
| 6048 |
*/
|
| 6049 |
function wpbc__get_form_status_for_submit(resource_id) {
|
| 6050 |
|
| 6051 |
var status = '';
|
| 6052 |
|
| 6053 |
try {
|
| 6054 |
if ( (typeof _wpbc !== 'undefined') && _wpbc.booking__get_param_value ) {
|
| 6055 |
status = _wpbc.booking__get_param_value( resource_id, 'form_status' );
|
| 6056 |
}
|
| 6057 |
} catch ( e ) {}
|
| 6058 |
|
| 6059 |
status = (status == null) ? '' : String( status );
|
| 6060 |
status = status.toLowerCase();
|
| 6061 |
|
| 6062 |
// URL-based detection for preview iframe.
|
| 6063 |
var preview_args = wpbc__get_bfb_preview_args_from_location();
|
| 6064 |
if ( preview_args ) {
|
| 6065 |
return 'preview';
|
| 6066 |
}
|
| 6067 |
|
| 6068 |
return (status === 'preview') ? 'preview' : 'published';
|
| 6069 |
}
|
| 6070 |
|
| 6071 |
|
| 6072 |
|
| 6073 |
// == Backward-compatible wrappers (keep old global names working 100% as before). =====================================
|
| 6074 |
function mybooking_submit( submit_form, resource_id, wpdev_active_locale ) {
|
| 6075 |
return wpbc_booking_form_submit( submit_form, resource_id, wpdev_active_locale );
|
| 6076 |
}
|
| 6077 |
|
| 6078 |
try {
|
| 6079 |
var ev = (typeof CustomEvent === 'function') ? new CustomEvent( 'wpbc-ready' ) : document.createEvent( 'Event' );
|
| 6080 |
if ( ev.initEvent ) {
|
| 6081 |
ev.initEvent( 'wpbc-ready', true, true );
|
| 6082 |
}
|
| 6083 |
document.dispatchEvent( ev );
|
| 6084 |
console.log( 'wpbc-ready' );
|
| 6085 |
} catch ( e ) {
|
| 6086 |
console.error( "WPBC event 'wpbc-ready' failed!", e );
|
| 6087 |
}
|
| 6088 |
|
| 6089 |
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndwYmNfdXRpbHMuanMiLCJ3cGJjLmpzIiwiZGV2X2xvZy5qcyIsImFqeF9sb2FkX2JhbGFuY2VyLmpzIiwid3BiY19jYWwuanMiLCJkYXlzX3NlbGVjdF9jdXN0b20uanMiLCJ3cGJjX2NhbF9hanguanMiLCJ3cGJjX2ZlX21lc3NhZ2VzLmpzIiwidGltZWxpbmVfcG9wb3Zlci5qcyIsIndwYmNfY2FsX2xvYWRlci5qcyIsImF1dG9maWxsX2ZpZWxkcy5qcyIsImJvb2tpbmdfZm9ybV9zdWJtaXQuanMiLCJ3cGJjX3JlYWR5X2V2ZW50LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQ2xHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQy9oQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQ2hFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FDdFFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUM5cUZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQ3RPQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FDM1JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUM1aUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQ2xEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FDaFdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUNuSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQzF3QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJ3cGJjX2FsbC5qcyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxyXG4gKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuICogSmF2YVNjcmlwdCBVdGlsIEZ1bmN0aW9uc1x0XHQuLi9pbmNsdWRlcy9fX2pzL3V0aWxzL3dwYmNfdXRpbHMuanNcclxuICogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcbiAqL1xyXG5cclxuLyoqXHJcbiAqIFRyaW0gIHN0cmluZ3MgYW5kIGFycmF5IGpvaW5lZCB3aXRoICAoLClcclxuICpcclxuICogQHBhcmFtIHN0cmluZ190b190cmltICAgc3RyaW5nIC8gYXJyYXlcclxuICogQHJldHVybnMgc3RyaW5nXHJcbiAqL1xyXG5mdW5jdGlvbiB3cGJjX3RyaW0oc3RyaW5nX3RvX3RyaW0pIHtcclxuXHJcblx0aWYgKCBBcnJheS5pc0FycmF5KCBzdHJpbmdfdG9fdHJpbSApICkge1xyXG5cdFx0c3RyaW5nX3RvX3RyaW0gPSBzdHJpbmdfdG9fdHJpbS5qb2luKCAnLCcgKTtcclxuXHR9XHJcblxyXG5cdGlmICggJ3N0cmluZycgPT0gdHlwZW9mIChzdHJpbmdfdG9fdHJpbSkgKSB7XHJcblx0XHRzdHJpbmdfdG9fdHJpbSA9IHN0cmluZ190b190cmltLnRyaW0oKTtcclxuXHR9XHJcblxyXG5cdHJldHVybiBzdHJpbmdfdG9fdHJpbTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENoZWNrIGlmIGVsZW1lbnQgaW4gYXJyYXlcclxuICpcclxuICogQHBhcmFtIGFycmF5X2hlcmVcdFx0YXJyYXlcclxuICogQHBhcmFtIHBfdmFsXHRcdFx0XHRlbGVtZW50IHRvICBjaGVja1xyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn1cclxuICovXHJcbmZ1bmN0aW9uIHdwYmNfaW5fYXJyYXkoYXJyYXlfaGVyZSwgcF92YWwpIHtcclxuXHRmb3IgKCB2YXIgaSA9IDAsIGwgPSBhcnJheV9oZXJlLmxlbmd0aDsgaSA8IGw7IGkrKyApIHtcclxuXHRcdGlmICggYXJyYXlfaGVyZVtpXSA9PSBwX3ZhbCApIHtcclxuXHRcdFx0cmV0dXJuIHRydWU7XHJcblx0XHR9XHJcblx0fVxyXG5cdHJldHVybiBmYWxzZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFByZXZlbnQgb3BlbmluZyBibGFuayB3aW5kb3dzIG9uIFdvcmRQcmVzcyBwbGF5Z3JvdW5kIGZvciBwc2V1ZG8gbGlua3MgbGlrZSB0aGlzOiA8YSBocmVmPVwiamF2YXNjcmlwdDp2b2lkKDApXCI+IG9yICMgdG8gc3RheSBpbiB0aGUgc2FtZSB0YWIuXHJcbiAqL1xyXG4oZnVuY3Rpb24gKCkge1xyXG5cdCd1c2Ugc3RyaWN0JztcclxuXHJcblx0ZnVuY3Rpb24gaXNfcGxheWdyb3VuZF9vcmlnaW4oKSB7XHJcblx0XHRyZXR1cm4gbG9jYXRpb24ub3JpZ2luID09PSAnaHR0cHM6Ly9wbGF5Z3JvdW5kLndvcmRwcmVzcy5uZXQnO1xyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gaXNfcHNldWRvX2xpbmsoYSkge1xyXG5cdFx0aWYgKCAhYSB8fCAhYS5nZXRBdHRyaWJ1dGUgKSByZXR1cm4gdHJ1ZTtcclxuXHRcdHZhciBocmVmID0gKGEuZ2V0QXR0cmlidXRlKCAnaHJlZicgKSB8fCAnJykudHJpbSgpLnRvTG93ZXJDYXNlKCk7XHJcblx0XHRyZXR1cm4gKFxyXG5cdFx0XHQhaHJlZiB8fFxyXG5cdFx0XHRocmVmID09PSAnIycgfHxcclxuXHRcdFx0aHJlZi5pbmRleE9mKCAnIycgKSA9PT0gMCB8fFxyXG5cdFx0XHRocmVmLmluZGV4T2YoICdqYXZhc2NyaXB0OicgKSA9PT0gMCB8fFxyXG5cdFx0XHRocmVmLmluZGV4T2YoICdtYWlsdG86JyApID09PSAwIHx8XHJcblx0XHRcdGhyZWYuaW5kZXhPZiggJ3RlbDonICkgPT09IDBcclxuXHRcdCk7XHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBmaXhfdGFyZ2V0KGEpIHtcclxuXHRcdGlmICggISBhICkgcmV0dXJuO1xyXG5cdFx0aWYgKCBpc19wc2V1ZG9fbGluayggYSApIHx8IGEuaGFzQXR0cmlidXRlKCAnZGF0YS13cC1uby1ibGFuaycgKSApIHtcclxuXHRcdFx0YS50YXJnZXQgPSAnX3NlbGYnO1xyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gaW5pdF9maXgoKSB7XHJcblx0XHQvLyBPcHRpb25hbDogY2xlYW4gdXAgY3VycmVudCBET00gKGhhcm1sZXNz4oCUYWZmZWN0cyBvbmx5IHBzZXVkby9kYXRhbWFya2VkIGxpbmtzKS5cclxuXHRcdHZhciBub2RlcyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoICdhW2hyZWZdJyApO1xyXG5cdFx0Zm9yICggdmFyIGkgPSAwOyBpIDwgbm9kZXMubGVuZ3RoOyBpKysgKSBmaXhfdGFyZ2V0KCBub2Rlc1tpXSApO1xyXG5cclxuXHRcdC8vIExhdGUgYnViYmxlLXBoYXNlIGxpc3RlbmVycyAocnVuIGFmdGVyIFBsYXlncm91bmQncyBoYW5kbGVycylcclxuXHRcdGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoICdjbGljaycsIGZ1bmN0aW9uIChlKSB7XHJcblx0XHRcdHZhciBhID0gZS50YXJnZXQgJiYgZS50YXJnZXQuY2xvc2VzdCA/IGUudGFyZ2V0LmNsb3Nlc3QoICdhW2hyZWZdJyApIDogbnVsbDtcclxuXHRcdFx0aWYgKCBhICkgZml4X3RhcmdldCggYSApO1xyXG5cdFx0fSwgZmFsc2UgKTtcclxuXHJcblx0XHRkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCAnZm9jdXNpbicsIGZ1bmN0aW9uIChlKSB7XHJcblx0XHRcdHZhciBhID0gZS50YXJnZXQgJiYgZS50YXJnZXQuY2xvc2VzdCA/IGUudGFyZ2V0LmNsb3Nlc3QoICdhW2hyZWZdJyApIDogbnVsbDtcclxuXHRcdFx0aWYgKCBhICkgZml4X3RhcmdldCggYSApO1xyXG5cdFx0fSApO1xyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gc2NoZWR1bGVfaW5pdCgpIHtcclxuXHRcdGlmICggIWlzX3BsYXlncm91bmRfb3JpZ2luKCkgKSByZXR1cm47XHJcblx0XHRzZXRUaW1lb3V0KCBpbml0X2ZpeCwgMTAwMCApOyAvLyBlbnN1cmUgd2UgYXR0YWNoIGFmdGVyIFBsYXlncm91bmQncyBzY3JpcHQuXHJcblx0fVxyXG5cclxuXHRpZiAoIGRvY3VtZW50LnJlYWR5U3RhdGUgPT09ICdsb2FkaW5nJyApIHtcclxuXHRcdGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoICdET01Db250ZW50TG9hZGVkJywgc2NoZWR1bGVfaW5pdCApO1xyXG5cdH0gZWxzZSB7XHJcblx0XHRzY2hlZHVsZV9pbml0KCk7XHJcblx0fVxyXG59KSgpOyIsIlwidXNlIHN0cmljdFwiO1xyXG4vKipcclxuICogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcbiAqXHRpbmNsdWRlcy9fX2pzL3dwYmMvd3BiYy5qc1xyXG4gKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuICovXHJcblxyXG4vKipcclxuICogRGVlcCBDbG9uZSBvZiBvYmplY3Qgb3IgYXJyYXlcclxuICpcclxuICogQHBhcmFtIG9ialxyXG4gKiBAcmV0dXJucyB7YW55fVxyXG4gKi9cclxuZnVuY3Rpb24gd3BiY19jbG9uZV9vYmooIG9iaiApe1xyXG5cclxuXHRyZXR1cm4gSlNPTi5wYXJzZSggSlNPTi5zdHJpbmdpZnkoIG9iaiApICk7XHJcbn1cclxuXHJcblxyXG5cclxuLyoqXHJcbiAqIE1haW4gX3dwYmMgSlMgb2JqZWN0XHJcbiAqL1xyXG5cclxudmFyIF93cGJjID0gKGZ1bmN0aW9uICggb2JqLCAkKSB7XHJcblxyXG5cdC8vIFNlY3VyZSBwYXJhbWV0ZXJzIGZvciBBamF4XHQtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHR2YXIgcF9zZWN1cmUgPSBvYmouc2VjdXJpdHlfb2JqID0gb2JqLnNlY3VyaXR5X29iaiB8fCB7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdHVzZXJfaWQ6IDAsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdG5vbmNlICA6ICcnLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRsb2NhbGUgOiAnJ1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0ICB9O1xyXG5cdG9iai5zZXRfc2VjdXJlX3BhcmFtID0gZnVuY3Rpb24gKCBwYXJhbV9rZXksIHBhcmFtX3ZhbCApIHtcclxuXHRcdHBfc2VjdXJlWyBwYXJhbV9rZXkgXSA9IHBhcmFtX3ZhbDtcclxuXHR9O1xyXG5cclxuXHRvYmouZ2V0X3NlY3VyZV9wYXJhbSA9IGZ1bmN0aW9uICggcGFyYW1fa2V5ICkge1xyXG5cdFx0cmV0dXJuIHBfc2VjdXJlWyBwYXJhbV9rZXkgXTtcclxuXHR9O1xyXG5cclxuXHJcblx0Ly8gQ2FsZW5kYXJzIFx0LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdHZhciBwX2NhbGVuZGFycyA9IG9iai5jYWxlbmRhcnNfb2JqID0gb2JqLmNhbGVuZGFyc19vYmogfHwge1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQvLyBzb3J0ICAgICAgICAgICAgOiBcImJvb2tpbmdfaWRcIixcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gc29ydF90eXBlICAgICAgIDogXCJERVNDXCIsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vIHBhZ2VfbnVtICAgICAgICA6IDEsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vIHBhZ2VfaXRlbXNfY291bnQ6IDEwLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQvLyBjcmVhdGVfZGF0ZSAgICAgOiBcIlwiLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQvLyBrZXl3b3JkICAgICAgICAgOiBcIlwiLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQvLyBzb3VyY2UgICAgICAgICAgOiBcIlwiXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0fTtcclxuXHJcblx0LyoqXHJcblx0ICogIENoZWNrIGlmIGNhbGVuZGFyIGZvciBzcGVjaWZpYyBib29raW5nIHJlc291cmNlIGRlZmluZWQgICA6OiAgIHRydWUgfCBmYWxzZVxyXG5cdCAqXHJcblx0ICogQHBhcmFtIHtzdHJpbmd8aW50fSByZXNvdXJjZV9pZFxyXG5cdCAqIEByZXR1cm5zIHtib29sZWFufVxyXG5cdCAqL1xyXG5cdG9iai5jYWxlbmRhcl9faXNfZGVmaW5lZCA9IGZ1bmN0aW9uICggcmVzb3VyY2VfaWQgKSB7XHJcblxyXG5cdFx0cmV0dXJuICgndW5kZWZpbmVkJyAhPT0gdHlwZW9mKCBwX2NhbGVuZGFyc1sgJ2NhbGVuZGFyXycgKyByZXNvdXJjZV9pZCBdICkgKTtcclxuXHR9O1xyXG5cclxuXHQvKipcclxuXHQgKiAgQ3JlYXRlIENhbGVuZGFyIGluaXRpYWxpemluZ1xyXG5cdCAqXHJcblx0ICogQHBhcmFtIHtzdHJpbmd8aW50fSByZXNvdXJjZV9pZFxyXG5cdCAqL1xyXG5cdG9iai5jYWxlbmRhcl9faW5pdCA9IGZ1bmN0aW9uICggcmVzb3VyY2VfaWQgKSB7XHJcblxyXG5cdFx0cF9jYWxlbmRhcnNbICdjYWxlbmRhcl8nICsgcmVzb3VyY2VfaWQgXSA9IHt9O1xyXG5cdFx0cF9jYWxlbmRhcnNbICdjYWxlbmRhcl8nICsgcmVzb3VyY2VfaWQgXVsgJ2lkJyBdID0gcmVzb3VyY2VfaWQ7XHJcblx0XHRwX2NhbGVuZGFyc1sgJ2NhbGVuZGFyXycgKyByZXNvdXJjZV9pZCBdWyAncGVuZGluZ19kYXlzX3NlbGVjdGFibGUnIF0gPSBmYWxzZTtcclxuXHJcblx0fTtcclxuXHJcblx0LyoqXHJcblx0ICogQ2hlY2sgIGlmIHRoZSB0eXBlIG9mIHRoaXMgcHJvcGVydHkgIGlzIElOVFxyXG5cdCAqIEBwYXJhbSBwcm9wZXJ0eV9uYW1lXHJcblx0ICogQHJldHVybnMge2Jvb2xlYW59XHJcblx0ICovXHJcblx0b2JqLmNhbGVuZGFyX19pc19wcm9wX2ludCA9IGZ1bmN0aW9uICggcHJvcGVydHlfbmFtZSApIHtcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vIEZpeEluOiA5LjkuMC4yOS5cclxuXHJcblx0XHR2YXIgcF9jYWxlbmRhcl9pbnRfcHJvcGVydGllcyA9IFsnZHluYW1pY19fZGF5c19taW4nLCAnZHluYW1pY19fZGF5c19tYXgnLCAnZml4ZWRfX2RheXNfbnVtJ107XHJcblxyXG5cdFx0dmFyIGlzX2luY2x1ZGUgPSBwX2NhbGVuZGFyX2ludF9wcm9wZXJ0aWVzLmluY2x1ZGVzKCBwcm9wZXJ0eV9uYW1lICk7XHJcblxyXG5cdFx0cmV0dXJuIGlzX2luY2x1ZGU7XHJcblx0fTtcclxuXHJcblxyXG5cdC8qKlxyXG5cdCAqIFNldCBwYXJhbXMgZm9yIGFsbCAgY2FsZW5kYXJzXHJcblx0ICpcclxuXHQgKiBAcGFyYW0ge29iamVjdH0gY2FsZW5kYXJzX29ialx0XHRPYmplY3QgeyBjYWxlbmRhcl8xOiB7fSB9XHJcblx0ICogXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0IGNhbGVuZGFyXzM6IHt9LCAuLi4gfVxyXG5cdCAqL1xyXG5cdG9iai5jYWxlbmRhcnNfYWxsX19zZXQgPSBmdW5jdGlvbiAoIGNhbGVuZGFyc19vYmogKSB7XHJcblx0XHRwX2NhbGVuZGFycyA9IGNhbGVuZGFyc19vYmo7XHJcblx0fTtcclxuXHJcblx0LyoqXHJcblx0ICogR2V0IGJvb2tpbmdzIGluIGFsbCBjYWxlbmRhcnNcclxuXHQgKlxyXG5cdCAqIEByZXR1cm5zIHtvYmplY3R8e319XHJcblx0ICovXHJcblx0b2JqLmNhbGVuZGFyc19hbGxfX2dldCA9IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiBwX2NhbGVuZGFycztcclxuXHR9O1xyXG5cclxuXHQvKipcclxuXHQgKiBHZXQgY2FsZW5kYXIgb2JqZWN0ICAgOjogICB7IGlkOiAxLCDigKYgfVxyXG5cdCAqXHJcblx0ICogQHBhcmFtIHtzdHJpbmd8aW50fSByZXNvdXJjZV9pZFx0XHRcdFx0ICAnMidcclxuXHQgKiBAcmV0dXJucyB7b2JqZWN0fGJvb2xlYW59XHRcdFx0XHRcdHsgaWQ6IDIgLOKApiB9XHJcblx0ICovXHJcblx0b2JqLmNhbGVuZGFyX19nZXRfcGFyYW1ldGVycyA9IGZ1bmN0aW9uICggcmVzb3VyY2VfaWQgKSB7XHJcblxyXG5cdFx0aWYgKCBvYmouY2FsZW5kYXJfX2lzX2RlZmluZWQoIHJlc291cmNlX2lkICkgKXtcclxuXHJcblx0XHRcdHJldHVybiBwX2NhbGVuZGFyc1sgJ2NhbGVuZGFyXycgKyByZXNvdXJjZV9pZCBdO1xyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0cmV0dXJuIGZhbHNlO1xyXG5cdFx0fVxyXG5cdH07XHJcblxyXG5cdC8qKlxyXG5cdCAqIFNldCBjYWxlbmRhciBvYmplY3QgICA6OiAgIHsgZGF0ZXM6ICBPYmplY3QgeyBcIjIwMjMtMDctMjFcIjoge+KApn0sIFwiMjAyMy0wNy0yMlwiOiB74oCmfSwgXCIyMDIzLTA3LTIzXCI6IHvigKZ9LCDigKYgfVxyXG5cdCAqXHJcblx0ICogaWYgY2FsZW5kYXIgb2JqZWN0ICBub3QgZGVmaW5lZCwgdGhlbiAgaXQncyB3aWxsIGJlIGRlZmluZWQgYW5kIElEIHNldFxyXG5cdCAqIGlmIGNhbGVuZGFyIGV4aXN0LCB0aGVuICBzeXN0ZW0gc2V0ICBhcyBuZXcgb3Igb3ZlcndyaXRlIG9ubHkgcHJvcGVydGllcyBmcm9tIGNhbGVuZGFyX3Byb3BlcnR5X29iaiBwYXJhbWV0ZXIsICBidXQgb3RoZXIgcHJvcGVydGllcyB3aWxsIGJlIGV4aXN0ZWQgYW5kIG5vdCBvdmVyd3JpdGUsIGxpa2UgJ2lkJ1xyXG5cdCAqXHJcblx0ICogQHBhcmFtIHtzdHJpbmd8aW50fSByZXNvdXJjZV9pZFx0XHRcdFx0ICAnMidcclxuXHQgKiBAcGFyYW0ge29iamVjdH0gY2FsZW5kYXJfcHJvcGVydHlfb2JqXHRcdFx0XHRcdCAgeyAgZGF0ZXM6ICBPYmplY3QgeyBcIjIwMjMtMDctMjFcIjoge+KApn0sIFwiMjAyMy0wNy0yMlwiOiB74oCmfSwgXCIyMDIzLTA3LTIzXCI6IHvigKZ9LCDigKYgfSAgfVxyXG5cdCAqIEBwYXJhbSB7Ym9vbGVhbn0gaXNfY29tcGxldGVfb3ZlcndyaXRlXHRcdCAgaWYgJ3RydWUnIChkZWZhdWx0OiAnZmFsc2UnKSwgIHRoZW4gIG9ubHkgb3ZlcndyaXRlIG9yIGFkZCAgbmV3IHByb3BlcnRpZXMgaW4gIGNhbGVuZGFyX3Byb3BlcnR5X29ialxyXG5cdCAqIEByZXR1cm5zIHsqfVxyXG5cdCAqXHJcblx0ICogRXhhbXBsZXM6XHJcblx0ICpcclxuXHQgKiBDb21tb24gdXNhZ2UgaW4gUEhQOlxyXG5cdCAqICAgXHRcdFx0ZWNobyBcIiAgX3dwYmMuY2FsZW5kYXJfX3NldCggIFwiIC5pbnR2YWwoICRyZXNvdXJjZV9pZCApIC4gXCIsIHsgJ2RhdGVzJzogXCIgLiB3cF9qc29uX2VuY29kZSggJGF2YWlsYWJpbGl0eV9wZXJfZGF5c19hcnIgKSAuIFwiIH0gKTtcIjtcclxuXHQgKi9cclxuXHRvYmouY2FsZW5kYXJfX3NldF9wYXJhbWV0ZXJzID0gZnVuY3Rpb24gKCByZXNvdXJjZV9pZCwgY2FsZW5kYXJfcHJvcGVydHlfb2JqLCBpc19jb21wbGV0ZV9vdmVyd3JpdGUgPSBmYWxzZSAgKSB7XHJcblxyXG5cdFx0aWYgKCAoIW9iai5jYWxlbmRhcl9faXNfZGVmaW5lZCggcmVzb3VyY2VfaWQgKSkgfHwgKHRydWUgPT09IGlzX2NvbXBsZXRlX292ZXJ3cml0ZSkgKXtcclxuXHRcdFx0b2JqLmNhbGVuZGFyX19pbml0KCByZXNvdXJjZV9pZCApO1xyXG5cdFx0fVxyXG5cclxuXHRcdGZvciAoIHZhciBwcm9wX25hbWUgaW4gY2FsZW5kYXJfcHJvcGVydHlfb2JqICl7XHJcblxyXG5cdFx0XHRwX2NhbGVuZGFyc1sgJ2NhbGVuZGFyXycgKyByZXNvdXJjZV9pZCBdWyBwcm9wX25hbWUgXSA9IGNhbGVuZGFyX3Byb3BlcnR5X29ialsgcHJvcF9uYW1lIF07XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHBfY2FsZW5kYXJzWyAnY2FsZW5kYXJfJyArIHJlc291cmNlX2lkIF07XHJcblx0fTtcclxuXHJcblx0LyoqXHJcblx0ICogU2V0IHByb3BlcnR5ICB0byAgY2FsZW5kYXJcclxuXHQgKiBAcGFyYW0gcmVzb3VyY2VfaWRcdFwiMVwiXHJcblx0ICogQHBhcmFtIHByb3BfbmFtZVx0XHRuYW1lIG9mIHByb3BlcnR5XHJcblx0ICogQHBhcmFtIHByb3BfdmFsdWVcdHZhbHVlIG9mIHByb3BlcnR5XHJcblx0ICogQHJldHVybnMgeyp9XHRcdFx0Y2FsZW5kYXIgb2JqZWN0XHJcblx0ICovXHJcblx0b2JqLmNhbGVuZGFyX19zZXRfcGFyYW1fdmFsdWUgPSBmdW5jdGlvbiAoIHJlc291cmNlX2lkLCBwcm9wX25hbWUsIHByb3BfdmFsdWUgKSB7XHJcblxyXG5cdFx0aWYgKCAoIW9iai5jYWxlbmRhcl9faXNfZGVmaW5lZCggcmVzb3VyY2VfaWQgKSkgKXtcclxuXHRcdFx0b2JqLmNhbGVuZGFyX19pbml0KCByZXNvdXJjZV9pZCApO1xyXG5cdFx0fVxyXG5cclxuXHRcdHBfY2FsZW5kYXJzWyAnY2FsZW5kYXJfJyArIHJlc291cmNlX2lkIF1bIHByb3BfbmFtZSBdID0gcHJvcF92YWx1ZTtcclxuXHJcblx0XHRyZXR1cm4gcF9jYWxlbmRhcnNbICdjYWxlbmRhcl8nICsgcmVzb3VyY2VfaWQgXTtcclxuXHR9O1xyXG5cclxuXHQvKipcclxuXHQgKiAgR2V0IGNhbGVuZGFyIHByb3BlcnR5IHZhbHVlICAgXHQ6OiAgIG1peGVkIHwgbnVsbFxyXG5cdCAqXHJcblx0ICogQHBhcmFtIHtzdHJpbmd8aW50fSAgcmVzb3VyY2VfaWRcdFx0JzEnXHJcblx0ICogQHBhcmFtIHtzdHJpbmd9IHByb3BfbmFtZVx0XHRcdCdzZWxlY3Rpb25fbW9kZSdcclxuXHQgKiBAcmV0dXJucyB7KnxudWxsfVx0XHRcdFx0XHRtaXhlZCB8IG51bGxcclxuXHQgKi9cclxuXHRvYmouY2FsZW5kYXJfX2dldF9wYXJhbV92YWx1ZSA9IGZ1bmN0aW9uKCByZXNvdXJjZV9pZCwgcHJvcF9uYW1lICl7XHJcblxyXG5cdFx0aWYgKFxyXG5cdFx0XHQgICAoIG9iai5jYWxlbmRhcl9faXNfZGVmaW5lZCggcmVzb3VyY2VfaWQgKSApXHJcblx0XHRcdCYmICggJ3VuZGVmaW5lZCcgIT09IHR5cGVvZiAoIHBfY2FsZW5kYXJzWyAnY2FsZW5kYXJfJyArIHJlc291cmNlX2lkIF1bIHByb3BfbmFtZSBdICkgKVxyXG5cdFx0KXtcclxuXHRcdFx0Ly8gRml4SW46IDkuOS4wLjI5LlxyXG5cdFx0XHRpZiAoIG9iai5jYWxlbmRhcl9faXNfcHJvcF9pbnQoIHByb3BfbmFtZSApICl7XHJcblx0XHRcdFx0cF9jYWxlbmRhcnNbICdjYWxlbmRhcl8nICsgcmVzb3VyY2VfaWQgXVsgcHJvcF9uYW1lIF0gPSBwYXJzZUludCggcF9jYWxlbmRhcnNbICdjYWxlbmRhcl8nICsgcmVzb3VyY2VfaWQgXVsgcHJvcF9uYW1lIF0gKTtcclxuXHRcdFx0fVxyXG5cdFx0XHRyZXR1cm4gIHBfY2FsZW5kYXJzWyAnY2FsZW5kYXJfJyArIHJlc291cmNlX2lkIF1bIHByb3BfbmFtZSBdO1xyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBudWxsO1x0XHQvLyBJZiBzb21lIHByb3BlcnR5IG5vdCBkZWZpbmVkLCB0aGVuIG51bGw7XHJcblx0fTtcclxuXHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cclxuXHJcblx0Ly8gQm9va2luZ3MgXHQtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0dmFyIHBfYm9va2luZ3MgPSBvYmouYm9va2luZ3Nfb2JqID0gb2JqLmJvb2tpbmdzX29iaiB8fCB7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gY2FsZW5kYXJfMTogT2JqZWN0IHtcclxuIFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly9cdFx0XHRcdFx0XHQgICBpZDogICAgIDFcclxuIFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly9cdFx0XHRcdFx0XHQgLCBkYXRlczogIE9iamVjdCB7IFwiMjAyMy0wNy0yMVwiOiB74oCmfSwgXCIyMDIzLTA3LTIyXCI6IHvigKZ9LCBcIjIwMjMtMDctMjNcIjoge+KApn0sIOKAplxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vIH1cclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0fTtcclxuXHJcblx0LyoqXHJcblx0ICogIENoZWNrIGlmIGJvb2tpbmdzIGZvciBzcGVjaWZpYyBib29raW5nIHJlc291cmNlIGRlZmluZWQgICA6OiAgIHRydWUgfCBmYWxzZVxyXG5cdCAqXHJcblx0ICogQHBhcmFtIHtzdHJpbmd8aW50fSByZXNvdXJjZV9pZFxyXG5cdCAqIEByZXR1cm5zIHtib29sZWFufVxyXG5cdCAqL1xyXG5cdG9iai5ib29raW5nc19pbl9jYWxlbmRhcl9faXNfZGVmaW5lZCA9IGZ1bmN0aW9uICggcmVzb3VyY2VfaWQgKSB7XHJcblxyXG5cdFx0cmV0dXJuICgndW5kZWZpbmVkJyAhPT0gdHlwZW9mKCBwX2Jvb2tpbmdzWyAnY2FsZW5kYXJfJyArIHJlc291cmNlX2lkIF0gKSApO1xyXG5cdH07XHJcblxyXG5cdC8qKlxyXG5cdCAqIEdldCBib29raW5ncyBjYWxlbmRhciBvYmplY3QgICA6OiAgIHsgaWQ6IDEgLCBkYXRlczogIE9iamVjdCB7IFwiMjAyMy0wNy0yMVwiOiB74oCmfSwgXCIyMDIzLTA3LTIyXCI6IHvigKZ9LCBcIjIwMjMtMDctMjNcIjoge+KApn0sIOKApiB9XHJcblx0ICpcclxuXHQgKiBAcGFyYW0ge3N0cmluZ3xpbnR9IHJlc291cmNlX2lkXHRcdFx0XHQgICcyJ1xyXG5cdCAqIEByZXR1cm5zIHtvYmplY3R8Ym9vbGVhbn1cdFx0XHRcdFx0eyBpZDogMiAsIGRhdGVzOiAgT2JqZWN0IHsgXCIyMDIzLTA3LTIxXCI6IHvigKZ9LCBcIjIwMjMtMDctMjJcIjoge+KApn0sIFwiMjAyMy0wNy0yM1wiOiB74oCmfSwg4oCmIH1cclxuXHQgKi9cclxuXHRvYmouYm9va2luZ3NfaW5fY2FsZW5kYXJfX2dldCA9IGZ1bmN0aW9uKCByZXNvdXJjZV9pZCApe1xyXG5cclxuXHRcdGlmICggb2JqLmJvb2tpbmdzX2luX2NhbGVuZGFyX19pc19kZWZpbmVkKCByZXNvdXJjZV9pZCApICl7XHJcblxyXG5cdFx0XHRyZXR1cm4gcF9ib29raW5nc1sgJ2NhbGVuZGFyXycgKyByZXNvdXJjZV9pZCBdO1xyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0cmV0dXJuIGZhbHNlO1xyXG5cdFx0fVxyXG5cdH07XHJcblxyXG5cdC8qKlxyXG5cdCAqIFNldCBib29raW5ncyBjYWxlbmRhciBvYmplY3QgICA6OiAgIHsgZGF0ZXM6ICBPYmplY3QgeyBcIjIwMjMtMDctMjFcIjoge+KApn0sIFwiMjAyMy0wNy0yMlwiOiB74oCmfSwgXCIyMDIzLTA3LTIzXCI6IHvigKZ9LCDigKYgfVxyXG5cdCAqXHJcblx0ICogaWYgY2FsZW5kYXIgb2JqZWN0ICBub3QgZGVmaW5lZCwgdGhlbiAgaXQncyB3aWxsIGJlIGRlZmluZWQgYW5kIElEIHNldFxyXG5cdCAqIGlmIGNhbGVuZGFyIGV4aXN0LCB0aGVuICBzeXN0ZW0gc2V0ICBhcyBuZXcgb3Igb3ZlcndyaXRlIG9ubHkgcHJvcGVydGllcyBmcm9tIGNhbGVuZGFyX29iaiBwYXJhbWV0ZXIsICBidXQgb3RoZXIgcHJvcGVydGllcyB3aWxsIGJlIGV4aXN0ZWQgYW5kIG5vdCBvdmVyd3JpdGUsIGxpa2UgJ2lkJ1xyXG5cdCAqXHJcblx0ICogQHBhcmFtIHtzdHJpbmd8aW50fSByZXNvdXJjZV9pZFx0XHRcdFx0ICAnMidcclxuXHQgKiBAcGFyYW0ge29iamVjdH0gY2FsZW5kYXJfb2JqXHRcdFx0XHRcdCAgeyAgZGF0ZXM6ICBPYmplY3QgeyBcIjIwMjMtMDctMjFcIjoge+KApn0sIFwiMjAyMy0wNy0yMlwiOiB74oCmfSwgXCIyMDIzLTA3LTIzXCI6IHvigKZ9LCDigKYgfSAgfVxyXG5cdCAqIEByZXR1cm5zIHsqfVxyXG5cdCAqXHJcblx0ICogRXhhbXBsZXM6XHJcblx0ICpcclxuXHQgKiBDb21tb24gdXNhZ2UgaW4gUEhQOlxyXG5cdCAqICAgXHRcdFx0ZWNobyBcIiAgX3dwYmMuYm9va2luZ3NfaW5fY2FsZW5kYXJfX3NldCggIFwiIC5pbnR2YWwoICRyZXNvdXJjZV9pZCApIC4gXCIsIHsgJ2RhdGVzJzogXCIgLiB3cF9qc29uX2VuY29kZSggJGF2YWlsYWJpbGl0eV9wZXJfZGF5c19hcnIgKSAuIFwiIH0gKTtcIjtcclxuXHQgKi9cclxuXHRvYmouYm9va2luZ3NfaW5fY2FsZW5kYXJfX3NldCA9IGZ1bmN0aW9uKCByZXNvdXJjZV9pZCwgY2FsZW5kYXJfb2JqICl7XHJcblxyXG5cdFx0aWYgKCAhIG9iai5ib29raW5nc19pbl9jYWxlbmRhcl9faXNfZGVmaW5lZCggcmVzb3VyY2VfaWQgKSApe1xyXG5cdFx0XHRwX2Jvb2tpbmdzWyAnY2FsZW5kYXJfJyArIHJlc291cmNlX2lkIF0gPSB7fTtcclxuXHRcdFx0cF9ib29raW5nc1sgJ2NhbGVuZGFyXycgKyByZXNvdXJjZV9pZCBdWyAnaWQnIF0gPSByZXNvdXJjZV9pZDtcclxuXHRcdH1cclxuXHJcblx0XHRmb3IgKCB2YXIgcHJvcF9uYW1lIGluIGNhbGVuZGFyX29iaiApe1xyXG5cclxuXHRcdFx0cF9ib29raW5nc1sgJ2NhbGVuZGFyXycgKyByZXNvdXJjZV9pZCBdWyBwcm9wX25hbWUgXSA9IGNhbGVuZGFyX29ialsgcHJvcF9uYW1lIF07XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHBfYm9va2luZ3NbICdjYWxlbmRhcl8nICsgcmVzb3VyY2VfaWQgXTtcclxuXHR9O1xyXG5cclxuXHQvLyBEYXRlc1xyXG5cclxuXHQvKipcclxuXHQgKiAgR2V0IGJvb2tpbmdzIGRhdGEgZm9yIEFMTCBEYXRlcyBpbiBjYWxlbmRhciAgIDo6ICAgZmFsc2UgfCB7IFwiMjAyMy0wNy0yMlwiOiB74oCmfSwgXCIyMDIzLTA3LTIzXCI6IHvigKZ9LCDigKYgfVxyXG5cdCAqXHJcblx0ICogQHBhcmFtIHtzdHJpbmd8aW50fSByZXNvdXJjZV9pZFx0XHRcdCcxJ1xyXG5cdCAqIEByZXR1cm5zIHtvYmplY3R8Ym9vbGVhbn1cdFx0XHRcdGZhbHNlIHwgT2JqZWN0IHtcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcIjIwMjMtMDctMjRcIjogT2JqZWN0IHsgWydzdW1tYXJ5J11bJ3N0YXR1c19mb3JfZGF5J106IFwiYXZhaWxhYmxlXCIsIGRheV9hdmFpbGFiaWxpdHk6IDEsIG1heF9jYXBhY2l0eTogMSwg4oCmIH1cclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcIjIwMjMtMDctMjZcIjogT2JqZWN0IHsgWydzdW1tYXJ5J11bJ3N0YXR1c19mb3JfZGF5J106IFwiZnVsbF9kYXlfYm9va2luZ1wiLCBbJ3N1bW1hcnknXVsnc3RhdHVzX2Zvcl9ib29raW5ncyddOiBcInBlbmRpbmdcIiwgZGF5X2F2YWlsYWJpbGl0eTogMCwg4oCmIH1cclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcIjIwMjMtMDctMjlcIjogT2JqZWN0IHsgWydzdW1tYXJ5J11bJ3N0YXR1c19mb3JfZGF5J106IFwicmVzb3VyY2VfYXZhaWxhYmlsaXR5XCIsIGRheV9hdmFpbGFiaWxpdHk6IDAsIG1heF9jYXBhY2l0eTogMSwg4oCmIH1cclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcIjIwMjMtMDctMzBcIjoge+KApn0sIFwiMjAyMy0wNy0zMVwiOiB74oCmfSwg4oCmXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdH1cclxuXHQgKi9cclxuXHRvYmouYm9va2luZ3NfaW5fY2FsZW5kYXJfX2dldF9kYXRlcyA9IGZ1bmN0aW9uKCByZXNvdXJjZV9pZCl7XHJcblxyXG5cdFx0aWYgKFxyXG5cdFx0XHQgICAoIG9iai5ib29raW5nc19pbl9jYWxlbmRhcl9faXNfZGVmaW5lZCggcmVzb3VyY2VfaWQgKSApXHJcblx0XHRcdCYmICggJ3VuZGVmaW5lZCcgIT09IHR5cGVvZiAoIHBfYm9va2luZ3NbICdjYWxlbmRhcl8nICsgcmVzb3VyY2VfaWQgXVsgJ2RhdGVzJyBdICkgKVxyXG5cdFx0KXtcclxuXHRcdFx0cmV0dXJuICBwX2Jvb2tpbmdzWyAnY2FsZW5kYXJfJyArIHJlc291cmNlX2lkIF1bICdkYXRlcycgXTtcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gZmFsc2U7XHRcdC8vIElmIHNvbWUgcHJvcGVydHkgbm90IGRlZmluZWQsIHRoZW4gZmFsc2U7XHJcblx0fTtcclxuXHJcblx0LyoqXHJcblx0ICogU2V0IGJvb2tpbmdzIGRhdGVzIGluIGNhbGVuZGFyIG9iamVjdCAgIDo6ICAgIHsgXCIyMDIzLTA3LTIxXCI6IHvigKZ9LCBcIjIwMjMtMDctMjJcIjoge+KApn0sIFwiMjAyMy0wNy0yM1wiOiB74oCmfSwg4oCmIH1cclxuXHQgKlxyXG5cdCAqIGlmIGNhbGVuZGFyIG9iamVjdCAgbm90IGRlZmluZWQsIHRoZW4gIGl0J3Mgd2lsbCBiZSBkZWZpbmVkIGFuZCAnaWQnLCAnZGF0ZXMnIHNldFxyXG5cdCAqIGlmIGNhbGVuZGFyIGV4aXN0LCB0aGVuIHN5c3RlbSBhZGQgYSAgbmV3IG9yIG92ZXJ3cml0ZSBvbmx5IGRhdGVzIGZyb20gZGF0ZXNfb2JqIHBhcmFtZXRlcixcclxuXHQgKiBidXQgb3RoZXIgZGF0ZXMgbm90IGZyb20gcGFyYW1ldGVyIGRhdGVzX29iaiB3aWxsIGJlIGV4aXN0ZWQgYW5kIG5vdCBvdmVyd3JpdGUuXHJcblx0ICpcclxuXHQgKiBAcGFyYW0ge3N0cmluZ3xpbnR9IHJlc291cmNlX2lkXHRcdFx0XHQgICcyJ1xyXG5cdCAqIEBwYXJhbSB7b2JqZWN0fSBkYXRlc19vYmpcdFx0XHRcdFx0ICB7IFwiMjAyMy0wNy0yMVwiOiB74oCmfSwgXCIyMDIzLTA3LTIyXCI6IHvigKZ9LCBcIjIwMjMtMDctMjNcIjoge+KApn0sIOKApiB9XHJcblx0ICogQHBhcmFtIHtib29sZWFufSBpc19jb21wbGV0ZV9vdmVyd3JpdGVcdFx0ICBpZiBmYWxzZSwgIHRoZW4gIG9ubHkgb3ZlcndyaXRlIG9yIGFkZCAgZGF0ZXMgZnJvbSBcdGRhdGVzX29ialxyXG5cdCAqIEByZXR1cm5zIHsqfVxyXG5cdCAqXHJcblx0ICogRXhhbXBsZXM6XHJcblx0ICogICBcdFx0XHRfd3BiYy5ib29raW5nc19pbl9jYWxlbmRhcl9fc2V0X2RhdGVzKCByZXNvdXJjZV9pZCwgeyBcIjIwMjMtMDctMjFcIjoge+KApn0sIFwiMjAyMy0wNy0yMlwiOiB74oCmfSwg4oCmIH0gICk7XHRcdDwtICAgb3ZlcndyaXRlIEFMTCBkYXRlc1xyXG5cdCAqICAgXHRcdFx0X3dwYmMuYm9va2luZ3NfaW5fY2FsZW5kYXJfX3NldF9kYXRlcyggcmVzb3VyY2VfaWQsIHsgXCIyMDIzLTA3LTIyXCI6IHvigKZ9IH0sICBmYWxzZSAgKTtcdFx0XHRcdFx0PC0gICBhZGQgb3Igb3ZlcndyaXRlIG9ubHkgIFx0XCIyMDIzLTA3LTIyXCI6IHt9XHJcblx0ICpcclxuXHQgKiBDb21tb24gdXNhZ2UgaW4gUEhQOlxyXG5cdCAqICAgXHRcdFx0ZWNobyBcIiAgX3dwYmMuYm9va2luZ3NfaW5fY2FsZW5kYXJfX3NldF9kYXRlcyggIFwiIC4gaW50dmFsKCAkcmVzb3VyY2VfaWQgKSAuIFwiLCAgXCIgLiB3cF9qc29uX2VuY29kZSggJGF2YWlsYWJpbGl0eV9wZXJfZGF5c19hcnIgKSAuIFwiICApOyAgXCI7XHJcblx0ICovXHJcblx0b2JqLmJvb2tpbmdzX2luX2NhbGVuZGFyX19zZXRfZGF0ZXMgPSBmdW5jdGlvbiggcmVzb3VyY2VfaWQsIGRhdGVzX29iaiAsIGlzX2NvbXBsZXRlX292ZXJ3cml0ZSA9IHRydWUgKXtcclxuXHJcblx0XHRpZiAoICFvYmouYm9va2luZ3NfaW5fY2FsZW5kYXJfX2lzX2RlZmluZWQoIHJlc291cmNlX2lkICkgKXtcclxuXHRcdFx0b2JqLmJvb2tpbmdzX2luX2NhbGVuZGFyX19zZXQoIHJlc291cmNlX2lkLCB7ICdkYXRlcyc6IHt9IH0gKTtcclxuXHRcdH1cclxuXHJcblx0XHRpZiAoICd1bmRlZmluZWQnID09PSB0eXBlb2YgKHBfYm9va2luZ3NbICdjYWxlbmRhcl8nICsgcmVzb3VyY2VfaWQgXVsgJ2RhdGVzJyBdKSApe1xyXG5cdFx0XHRwX2Jvb2tpbmdzWyAnY2FsZW5kYXJfJyArIHJlc291cmNlX2lkIF1bICdkYXRlcycgXSA9IHt9XHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKGlzX2NvbXBsZXRlX292ZXJ3cml0ZSl7XHJcblxyXG5cdFx0XHQvLyBDb21wbGV0ZSBvdmVyd3JpdGUgYWxsICBib29raW5nIGRhdGVzXHJcblx0XHRcdHBfYm9va2luZ3NbICdjYWxlbmRhcl8nICsgcmVzb3VyY2VfaWQgXVsgJ2RhdGVzJyBdID0gZGF0ZXNfb2JqO1xyXG5cdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdC8vIEFkZCBvbmx5ICBuZXcgb3Igb3ZlcndyaXRlIGV4aXN0IGJvb2tpbmcgZGF0ZXMgZnJvbSAgcGFyYW1ldGVyLiBCb29raW5nIGRhdGVzIG5vdCBmcm9tICBwYXJhbWV0ZXIgIHdpbGwgIGJlIHdpdGhvdXQgY2huYW5nZXNcclxuXHRcdFx0Zm9yICggdmFyIHByb3BfbmFtZSBpbiBkYXRlc19vYmogKXtcclxuXHJcblx0XHRcdFx0cF9ib29raW5nc1sgJ2NhbGVuZGFyXycgKyByZXNvdXJjZV9pZCBdWydkYXRlcyddWyBwcm9wX25hbWUgXSA9IGRhdGVzX29ialsgcHJvcF9uYW1lIF07XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gcF9ib29raW5nc1sgJ2NhbGVuZGFyXycgKyByZXNvdXJjZV9pZCBdO1xyXG5cdH07XHJcblxyXG5cclxuXHQvKipcclxuXHQgKiAgR2V0IGJvb2tpbmdzIGRhdGEgZm9yIHNwZWNpZmljIGRhdGUgaW4gY2FsZW5kYXIgICA6OiAgIGZhbHNlIHwgeyBkYXlfYXZhaWxhYmlsaXR5OiAxLCAuLi4gfVxyXG5cdCAqXHJcblx0ICogQHBhcmFtIHtzdHJpbmd8aW50fSByZXNvdXJjZV9pZFx0XHRcdCcxJ1xyXG5cdCAqIEBwYXJhbSB7c3RyaW5nfSBzcWxfY2xhc3NfZGF5XHRcdFx0JzIwMjMtMDctMjEnXHJcblx0ICogQHJldHVybnMge29iamVjdHxib29sZWFufVx0XHRcdFx0ZmFsc2UgfCB7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdGRheV9hdmFpbGFiaWxpdHk6IDRcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0bWF4X2NhcGFjaXR5OiA0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gID49IEJ1c2luZXNzIExhcmdlXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdDI6IE9iamVjdCB7IGlzX2RheV91bmF2YWlsYWJsZTogZmFsc2UsIF9kYXlfc3RhdHVzOiBcImF2YWlsYWJsZVwiIH1cclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0MTA6IE9iamVjdCB7IGlzX2RheV91bmF2YWlsYWJsZTogZmFsc2UsIF9kYXlfc3RhdHVzOiBcImF2YWlsYWJsZVwiIH1cdFx0Ly8gID49IEJ1c2luZXNzIExhcmdlIC4uLlxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQxMTogT2JqZWN0IHsgaXNfZGF5X3VuYXZhaWxhYmxlOiBmYWxzZSwgX2RheV9zdGF0dXM6IFwiYXZhaWxhYmxlXCIgfVxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQxMjogT2JqZWN0IHsgaXNfZGF5X3VuYXZhaWxhYmxlOiBmYWxzZSwgX2RheV9zdGF0dXM6IFwiYXZhaWxhYmxlXCIgfVxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0fVxyXG5cdCAqL1xyXG5cdG9iai5ib29raW5nc19pbl9jYWxlbmRhcl9fZ2V0X2Zvcl9kYXRlID0gZnVuY3Rpb24oIHJlc291cmNlX2lkLCBzcWxfY2xhc3NfZGF5ICl7XHJcblxyXG5cdFx0aWYgKFxyXG5cdFx0XHQgICAoIG9iai5ib29raW5nc19pbl9jYWxlbmRhcl9faXNfZGVmaW5lZCggcmVzb3VyY2VfaWQgKSApXHJcblx0XHRcdCYmICggJ3VuZGVmaW5lZCcgIT09IHR5cGVvZiAoIHBfYm9va2luZ3NbICdjYWxlbmRhcl8nICsgcmVzb3VyY2VfaWQgXVsgJ2RhdGVzJyBdICkgKVxyXG5cdFx0XHQmJiAoICd1bmRlZmluZWQnICE9PSB0eXBlb2YgKCBwX2Jvb2tpbmdzWyAnY2FsZW5kYXJfJyArIHJlc291cmNlX2lkIF1bICdkYXRlcycgXVsgc3FsX2NsYXNzX2RheSBdICkgKVxyXG5cdFx0KXtcclxuXHRcdFx0cmV0dXJuICBwX2Jvb2tpbmdzWyAnY2FsZW5kYXJfJyArIHJlc291cmNlX2lkIF1bICdkYXRlcycgXVsgc3FsX2NsYXNzX2RheSBdO1xyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBmYWxzZTtcdFx0Ly8gSWYgc29tZSBwcm9wZXJ0eSBub3QgZGVmaW5lZCwgdGhlbiBmYWxzZTtcclxuXHR9O1xyXG5cclxuXHJcblx0Ly8gQW55ICBQQVJBTVMgICBpbiBib29raW5nc1xyXG5cclxuXHQvKipcclxuXHQgKiBTZXQgcHJvcGVydHkgIHRvICBib29raW5nXHJcblx0ICogQHBhcmFtIHJlc291cmNlX2lkXHRcIjFcIlxyXG5cdCAqIEBwYXJhbSBwcm9wX25hbWVcdFx0bmFtZSBvZiBwcm9wZXJ0eVxyXG5cdCAqIEBwYXJhbSBwcm9wX3ZhbHVlXHR2YWx1ZSBvZiBwcm9wZXJ0eVxyXG5cdCAqIEByZXR1cm5zIHsqfVx0XHRcdGJvb2tpbmcgb2JqZWN0XHJcblx0ICovXHJcblx0b2JqLmJvb2tpbmdfX3NldF9wYXJhbV92YWx1ZSA9IGZ1bmN0aW9uICggcmVzb3VyY2VfaWQsIHByb3BfbmFtZSwgcHJvcF92YWx1ZSApIHtcclxuXHJcblx0XHRpZiAoICEgb2JqLmJvb2tpbmdzX2luX2NhbGVuZGFyX19pc19kZWZpbmVkKCByZXNvdXJjZV9pZCApICl7XHJcblx0XHRcdHBfYm9va2luZ3NbICdjYWxlbmRhcl8nICsgcmVzb3VyY2VfaWQgXSA9IHt9O1xyXG5cdFx0XHRwX2Jvb2tpbmdzWyAnY2FsZW5kYXJfJyArIHJlc291cmNlX2lkIF1bICdpZCcgXSA9IHJlc291cmNlX2lkO1xyXG5cdFx0fVxyXG5cclxuXHRcdHBfYm9va2luZ3NbICdjYWxlbmRhcl8nICsgcmVzb3VyY2VfaWQgXVsgcHJvcF9uYW1lIF0gPSBwcm9wX3ZhbHVlO1xyXG5cclxuXHRcdHJldHVybiBwX2Jvb2tpbmdzWyAnY2FsZW5kYXJfJyArIHJlc291cmNlX2lkIF07XHJcblx0fTtcclxuXHJcblx0LyoqXHJcblx0ICogIEdldCBib29raW5nIHByb3BlcnR5IHZhbHVlICAgXHQ6OiAgIG1peGVkIHwgbnVsbFxyXG5cdCAqXHJcblx0ICogQHBhcmFtIHtzdHJpbmd8aW50fSAgcmVzb3VyY2VfaWRcdFx0JzEnXHJcblx0ICogQHBhcmFtIHtzdHJpbmd9IHByb3BfbmFtZVx0XHRcdCdzZWxlY3Rpb25fbW9kZSdcclxuXHQgKiBAcmV0dXJucyB7KnxudWxsfVx0XHRcdFx0XHRtaXhlZCB8IG51bGxcclxuXHQgKi9cclxuXHRvYmouYm9va2luZ19fZ2V0X3BhcmFtX3ZhbHVlID0gZnVuY3Rpb24oIHJlc291cmNlX2lkLCBwcm9wX25hbWUgKXtcclxuXHJcblx0XHRpZiAoXHJcblx0XHRcdCAgICggb2JqLmJvb2tpbmdzX2luX2NhbGVuZGFyX19pc19kZWZpbmVkKCByZXNvdXJjZV9pZCApIClcclxuXHRcdFx0JiYgKCAndW5kZWZpbmVkJyAhPT0gdHlwZW9mICggcF9ib29raW5nc1sgJ2NhbGVuZGFyXycgKyByZXNvdXJjZV9pZCBdWyBwcm9wX25hbWUgXSApIClcclxuXHRcdCl7XHJcblx0XHRcdHJldHVybiAgcF9ib29raW5nc1sgJ2NhbGVuZGFyXycgKyByZXNvdXJjZV9pZCBdWyBwcm9wX25hbWUgXTtcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gbnVsbDtcdFx0Ly8gSWYgc29tZSBwcm9wZXJ0eSBub3QgZGVmaW5lZCwgdGhlbiBudWxsO1xyXG5cdH07XHJcblxyXG5cclxuXHJcblxyXG5cdC8qKlxyXG5cdCAqIFNldCBib29raW5ncyBmb3IgYWxsICBjYWxlbmRhcnNcclxuXHQgKlxyXG5cdCAqIEBwYXJhbSB7b2JqZWN0fSBjYWxlbmRhcnNfb2JqXHRcdE9iamVjdCB7IGNhbGVuZGFyXzE6IHsgaWQ6IDEsIGRhdGVzOiBPYmplY3QgeyBcIjIwMjMtMDctMjJcIjoge+KApn0sIFwiMjAyMy0wNy0yM1wiOiB74oCmfSwgXCIyMDIzLTA3LTI0XCI6IHvigKZ9LCDigKYgfSB9XHJcblx0ICogXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0IGNhbGVuZGFyXzM6IHt9LCAuLi4gfVxyXG5cdCAqL1xyXG5cdG9iai5ib29raW5nc19pbl9jYWxlbmRhcnNfX3NldF9hbGwgPSBmdW5jdGlvbiAoIGNhbGVuZGFyc19vYmogKSB7XHJcblx0XHRwX2Jvb2tpbmdzID0gY2FsZW5kYXJzX29iajtcclxuXHR9O1xyXG5cclxuXHQvKipcclxuXHQgKiBHZXQgYm9va2luZ3MgaW4gYWxsIGNhbGVuZGFyc1xyXG5cdCAqXHJcblx0ICogQHJldHVybnMge29iamVjdHx7fX1cclxuXHQgKi9cclxuXHRvYmouYm9va2luZ3NfaW5fY2FsZW5kYXJzX19nZXRfYWxsID0gZnVuY3Rpb24gKCkge1xyXG5cdFx0cmV0dXJuIHBfYm9va2luZ3M7XHJcblx0fTtcclxuXHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cclxuXHJcblxyXG5cclxuXHQvLyBTZWFzb25zIFx0LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdHZhciBwX3NlYXNvbnMgPSBvYmouc2Vhc29uc19vYmogPSBvYmouc2Vhc29uc19vYmogfHwge1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vIGNhbGVuZGFyXzE6IE9iamVjdCB7XHJcbiBcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vXHRcdFx0XHRcdFx0ICAgaWQ6ICAgICAxXHJcbiBcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vXHRcdFx0XHRcdFx0ICwgZGF0ZXM6ICBPYmplY3QgeyBcIjIwMjMtMDctMjFcIjoge+KApn0sIFwiMjAyMy0wNy0yMlwiOiB74oCmfSwgXCIyMDIzLTA3LTIzXCI6IHvigKZ9LCDigKZcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQvLyB9XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdH07XHJcblxyXG5cdC8qKlxyXG5cdCAqIEFkZCBzZWFzb24gbmFtZXMgZm9yIGRhdGVzIGluIGNhbGVuZGFyIG9iamVjdCAgIDo6ICAgIHsgXCIyMDIzLTA3LTIxXCI6IFsgJ3dwYmNfc2Vhc29uX3NlcHRlbWJlcl8yMDIzJywgJ3dwYmNfc2Vhc29uX3NlcHRlbWJlcl8yMDI0JyBdLCBcIjIwMjMtMDctMjJcIjogWy4uLl0sIC4uLiB9XHJcblx0ICpcclxuXHQgKlxyXG5cdCAqIEBwYXJhbSB7c3RyaW5nfGludH0gcmVzb3VyY2VfaWRcdFx0XHRcdCAgJzInXHJcblx0ICogQHBhcmFtIHtvYmplY3R9IGRhdGVzX29ialx0XHRcdFx0XHQgIHsgXCIyMDIzLTA3LTIxXCI6IHvigKZ9LCBcIjIwMjMtMDctMjJcIjoge+KApn0sIFwiMjAyMy0wNy0yM1wiOiB74oCmfSwg4oCmIH1cclxuXHQgKiBAcGFyYW0ge2Jvb2xlYW59IGlzX2NvbXBsZXRlX292ZXJ3cml0ZVx0XHQgIGlmIGZhbHNlLCAgdGhlbiAgb25seSAgYWRkICBkYXRlcyBmcm9tIFx0ZGF0ZXNfb2JqXHJcblx0ICogQHJldHVybnMgeyp9XHJcblx0ICpcclxuXHQgKiBFeGFtcGxlczpcclxuXHQgKiAgIFx0XHRcdF93cGJjLnNlYXNvbnNfX3NldCggcmVzb3VyY2VfaWQsIHsgXCIyMDIzLTA3LTIxXCI6IFsgJ3dwYmNfc2Vhc29uX3NlcHRlbWJlcl8yMDIzJywgJ3dwYmNfc2Vhc29uX3NlcHRlbWJlcl8yMDI0JyBdLCBcIjIwMjMtMDctMjJcIjogWy4uLl0sIC4uLiB9ICApO1xyXG5cdCAqL1xyXG5cdG9iai5zZWFzb25zX19zZXQgPSBmdW5jdGlvbiggcmVzb3VyY2VfaWQsIGRhdGVzX29iaiAsIGlzX2NvbXBsZXRlX292ZXJ3cml0ZSA9IGZhbHNlICl7XHJcblxyXG5cdFx0aWYgKCAndW5kZWZpbmVkJyA9PT0gdHlwZW9mIChwX3NlYXNvbnNbICdjYWxlbmRhcl8nICsgcmVzb3VyY2VfaWQgXSkgKXtcclxuXHRcdFx0cF9zZWFzb25zWyAnY2FsZW5kYXJfJyArIHJlc291cmNlX2lkIF0gPSB7fTtcclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIGlzX2NvbXBsZXRlX292ZXJ3cml0ZSApe1xyXG5cclxuXHRcdFx0Ly8gQ29tcGxldGUgb3ZlcndyaXRlIGFsbCAgc2Vhc29uIGRhdGVzXHJcblx0XHRcdHBfc2Vhc29uc1sgJ2NhbGVuZGFyXycgKyByZXNvdXJjZV9pZCBdID0gZGF0ZXNfb2JqO1xyXG5cclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHQvLyBBZGQgb25seSAgbmV3IG9yIG92ZXJ3cml0ZSBleGlzdCBib29raW5nIGRhdGVzIGZyb20gIHBhcmFtZXRlci4gQm9va2luZyBkYXRlcyBub3QgZnJvbSAgcGFyYW1ldGVyICB3aWxsICBiZSB3aXRob3V0IGNobmFuZ2VzXHJcblx0XHRcdGZvciAoIHZhciBwcm9wX25hbWUgaW4gZGF0ZXNfb2JqICl7XHJcblxyXG5cdFx0XHRcdGlmICggJ3VuZGVmaW5lZCcgPT09IHR5cGVvZiAocF9zZWFzb25zWyAnY2FsZW5kYXJfJyArIHJlc291cmNlX2lkIF1bIHByb3BfbmFtZSBdKSApe1xyXG5cdFx0XHRcdFx0cF9zZWFzb25zWyAnY2FsZW5kYXJfJyArIHJlc291cmNlX2lkIF1bIHByb3BfbmFtZSBdID0gW107XHJcblx0XHRcdFx0fVxyXG5cdFx0XHRcdGZvciAoIHZhciBzZWFzb25fbmFtZV9rZXkgaW4gZGF0ZXNfb2JqWyBwcm9wX25hbWUgXSApe1xyXG5cdFx0XHRcdFx0cF9zZWFzb25zWyAnY2FsZW5kYXJfJyArIHJlc291cmNlX2lkIF1bIHByb3BfbmFtZSBdLnB1c2goIGRhdGVzX29ialsgcHJvcF9uYW1lIF1bIHNlYXNvbl9uYW1lX2tleSBdICk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHBfc2Vhc29uc1sgJ2NhbGVuZGFyXycgKyByZXNvdXJjZV9pZCBdO1xyXG5cdH07XHJcblxyXG5cclxuXHQvKipcclxuXHQgKiAgR2V0IGJvb2tpbmdzIGRhdGEgZm9yIHNwZWNpZmljIGRhdGUgaW4gY2FsZW5kYXIgICA6OiAgIFtdIHwgWyAnd3BiY19zZWFzb25fc2VwdGVtYmVyXzIwMjMnLCAnd3BiY19zZWFzb25fc2VwdGVtYmVyXzIwMjQnIF1cclxuXHQgKlxyXG5cdCAqIEBwYXJhbSB7c3RyaW5nfGludH0gcmVzb3VyY2VfaWRcdFx0XHQnMSdcclxuXHQgKiBAcGFyYW0ge3N0cmluZ30gc3FsX2NsYXNzX2RheVx0XHRcdCcyMDIzLTA3LTIxJ1xyXG5cdCAqIEByZXR1cm5zIHtvYmplY3R8Ym9vbGVhbn1cdFx0XHRcdFtdICB8ICBbICd3cGJjX3NlYXNvbl9zZXB0ZW1iZXJfMjAyMycsICd3cGJjX3NlYXNvbl9zZXB0ZW1iZXJfMjAyNCcgXVxyXG5cdCAqL1xyXG5cdG9iai5zZWFzb25zX19nZXRfZm9yX2RhdGUgPSBmdW5jdGlvbiggcmVzb3VyY2VfaWQsIHNxbF9jbGFzc19kYXkgKXtcclxuXHJcblx0XHRpZiAoXHJcblx0XHRcdCAgICggJ3VuZGVmaW5lZCcgIT09IHR5cGVvZiAoIHBfc2Vhc29uc1sgJ2NhbGVuZGFyXycgKyByZXNvdXJjZV9pZCBdICkgKVxyXG5cdFx0XHQmJiAoICd1bmRlZmluZWQnICE9PSB0eXBlb2YgKCBwX3NlYXNvbnNbICdjYWxlbmRhcl8nICsgcmVzb3VyY2VfaWQgXVsgc3FsX2NsYXNzX2RheSBdICkgKVxyXG5cdFx0KXtcclxuXHRcdFx0cmV0dXJuICBwX3NlYXNvbnNbICdjYWxlbmRhcl8nICsgcmVzb3VyY2VfaWQgXVsgc3FsX2NsYXNzX2RheSBdO1xyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBbXTtcdFx0Ly8gSWYgbm90IGRlZmluZWQsIHRoZW4gW107XHJcblx0fTtcclxuXHJcblxyXG5cdC8vIE90aGVyIHBhcmFtZXRlcnMgXHRcdFx0LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0dmFyIHBfb3RoZXIgPSBvYmoub3RoZXJfb2JqID0gb2JqLm90aGVyX29iaiB8fCB7IH07XHJcblxyXG5cdG9iai5zZXRfb3RoZXJfcGFyYW0gPSBmdW5jdGlvbiAoIHBhcmFtX2tleSwgcGFyYW1fdmFsICkge1xyXG5cdFx0cF9vdGhlclsgcGFyYW1fa2V5IF0gPSBwYXJhbV92YWw7XHJcblx0fTtcclxuXHJcblx0b2JqLmdldF9vdGhlcl9wYXJhbSA9IGZ1bmN0aW9uICggcGFyYW1fa2V5ICkge1xyXG5cdFx0cmV0dXJuIHBfb3RoZXJbIHBhcmFtX2tleSBdO1xyXG5cdH07XHJcblxyXG5cdC8qKlxyXG5cdCAqIEdldCBhbGwgb3RoZXIgcGFyYW1zXHJcblx0ICpcclxuXHQgKiBAcmV0dXJucyB7b2JqZWN0fHt9fVxyXG5cdCAqL1xyXG5cdG9iai5nZXRfb3RoZXJfcGFyYW1fX2FsbCA9IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiBwX290aGVyO1xyXG5cdH07XHJcblxyXG5cdC8vIE1lc3NhZ2VzIFx0XHRcdCAgICAgICAgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0dmFyIHBfbWVzc2FnZXMgPSBvYmoubWVzc2FnZXNfb2JqID0gb2JqLm1lc3NhZ2VzX29iaiB8fCB7IH07XHJcblxyXG5cdG9iai5zZXRfbWVzc2FnZSA9IGZ1bmN0aW9uICggcGFyYW1fa2V5LCBwYXJhbV92YWwgKSB7XHJcblx0XHRwX21lc3NhZ2VzWyBwYXJhbV9rZXkgXSA9IHBhcmFtX3ZhbDtcclxuXHR9O1xyXG5cclxuXHRvYmouZ2V0X21lc3NhZ2UgPSBmdW5jdGlvbiAoIHBhcmFtX2tleSApIHtcclxuXHRcdHJldHVybiBwX21lc3NhZ2VzWyBwYXJhbV9rZXkgXTtcclxuXHR9O1xyXG5cclxuXHQvKipcclxuXHQgKiBHZXQgYWxsIG90aGVyIHBhcmFtc1xyXG5cdCAqXHJcblx0ICogQHJldHVybnMge29iamVjdHx7fX1cclxuXHQgKi9cclxuXHRvYmouZ2V0X21lc3NhZ2VzX19hbGwgPSBmdW5jdGlvbiAoKSB7XHJcblx0XHRyZXR1cm4gcF9tZXNzYWdlcztcclxuXHR9O1xyXG5cclxuXHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cclxuXHRyZXR1cm4gb2JqO1xyXG5cclxufSggX3dwYmMgfHwge30sIGpRdWVyeSApKTtcclxuIiwid2luZG93Ll9fV1BCQ19ERVYgPSB0cnVlO1xyXG5cclxuLyoqXHJcbiAqIEV4dGVuZCBfd3BiYyB3aXRoICBuZXcgbWV0aG9kc1xyXG4gKlxyXG4gKiBAdHlwZSB7Knx7fX1cclxuICogQHByaXZhdGVcclxuICovXHJcbl93cGJjID0gKGZ1bmN0aW9uIChvYmosICQpIHtcclxuXHJcblx0LyoqXHJcblx0ICogRGV2IGxvZ2dlciAobm8tb3AgdW5sZXNzIHdpbmRvdy5fX1dQQkNfREVWID0gdHJ1ZSlcclxuXHQgKlxyXG5cdCAqIEB0eXBlIHsqfHt3YXJuOiAoZnVuY3Rpb24oKiwgKiwgKik6IHZvaWQpLCBlcnJvcjogKGZ1bmN0aW9uKCosICosICopOiB2b2lkKSwgb25jZTogb2JqLmRldi5vbmNlLCB0cnk6ICgoZnVuY3Rpb24oKiwgKiwgKik6ICgqfHVuZGVmaW5lZCkpfCopfX1cclxuXHQgKi9cclxuXHRvYmouZGV2ID0gb2JqLmRldiB8fCAoKCkgPT4ge1xyXG5cdFx0Y29uc3Qgc2VlbiAgICA9IG5ldyBTZXQoKTtcclxuXHRcdGNvbnN0IGVuYWJsZWQgPSAoKSA9PiAhIXdpbmRvdy5fX1dQQkNfREVWO1xyXG5cclxuXHRcdGZ1bmN0aW9uIG91dChsZXZlbCwgY29kZSwgbXNnLCBleHRyYSkge1xyXG5cdFx0XHRpZiAoICFlbmFibGVkKCkgKSByZXR1cm47XHJcblx0XHRcdHRyeSB7XHJcblx0XHRcdFx0KGNvbnNvbGVbbGV2ZWxdIHx8IGNvbnNvbGUud2FybikoIGBbV1BCQ11bJHtjb2RlfV0gJHttc2d9YCwgZXh0cmEgPz8gJycgKTtcclxuXHRcdFx0fSBjYXRjaCB7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4ge1xyXG5cdFx0XHRsb2cgIDogKGNvZGUsIG1zZywgZXh0cmEpID0+IG91dCgnbG9nJywgICBjb2RlLCBtc2csIGV4dHJhKSxcclxuXHRcdFx0ZGVidWc6IChjb2RlLCBtc2csIGV4dHJhKSA9PiBvdXQoJ2RlYnVnJywgY29kZSwgbXNnLCBleHRyYSksXHJcblx0XHRcdHdhcm4gOiAoY29kZSwgbXNnLCBleHRyYSkgPT4gb3V0KCAnd2FybicsIGNvZGUsIG1zZywgZXh0cmEgKSxcclxuXHRcdFx0ZXJyb3I6IChjb2RlLCBlcnJPck1zZywgZXh0cmEpID0+XHJcblx0XHRcdFx0b3V0KCAnZXJyb3InLCBjb2RlLFxyXG5cdFx0XHRcdFx0ZXJyT3JNc2cgaW5zdGFuY2VvZiBFcnJvciA/IGVyck9yTXNnLm1lc3NhZ2UgOiBTdHJpbmcoIGVyck9yTXNnICksXHJcblx0XHRcdFx0XHRlcnJPck1zZyBpbnN0YW5jZW9mIEVycm9yID8gZXJyT3JNc2cgOiBleHRyYSApLFxyXG5cdFx0XHRvbmNlIDogKGNvZGUsIG1zZywgZXh0cmEpID0+IHtcclxuXHRcdFx0XHRpZiAoICFlbmFibGVkKCkgKSByZXR1cm47XHJcblx0XHRcdFx0Y29uc3Qga2V5ID0gYCR7Y29kZX18JHttc2d9YDtcclxuXHRcdFx0XHRpZiAoIHNlZW4uaGFzKCBrZXkgKSApIHJldHVybjtcclxuXHRcdFx0XHRzZWVuLmFkZCgga2V5ICk7XHJcblx0XHRcdFx0b3V0KCAnZXJyb3InLCBjb2RlLCBtc2csIGV4dHJhICk7XHJcblx0XHRcdH0sXHJcblx0XHRcdHRyeSAgOiAoY29kZSwgZm4sIGV4dHJhKSA9PiB7XHJcblx0XHRcdFx0dHJ5IHtcclxuXHRcdFx0XHRcdHJldHVybiBmbigpO1xyXG5cdFx0XHRcdH0gY2F0Y2ggKCBlICkge1xyXG5cdFx0XHRcdFx0b3V0KCAnZXJyb3InLCBjb2RlLCBlLCBleHRyYSApO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fVxyXG5cdFx0fTtcclxuXHR9KSgpO1xyXG5cclxuXHQvLyBPcHRpb25hbDogZ2xvYmFsIHRyYXBzIGluIGRldi5cclxuXHRpZiAoIHdpbmRvdy5fX1dQQkNfREVWICkge1xyXG5cdFx0d2luZG93LmFkZEV2ZW50TGlzdGVuZXIoICdlcnJvcicsIChlKSA9PiB7XHJcblx0XHRcdHRyeSB7IF93cGJjPy5kZXY/LmVycm9yKCAnR0xPQkFMLUVSUk9SJywgZT8uZXJyb3IgfHwgZT8ubWVzc2FnZSwgZSApOyB9IGNhdGNoICggXyApIHt9XHJcblx0XHR9ICk7XHJcblx0XHR3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lciggJ3VuaGFuZGxlZHJlamVjdGlvbicsIChlKSA9PiB7XHJcblx0XHRcdHRyeSB7IF93cGJjPy5kZXY/LmVycm9yKCAnR0xPQkFMLVJFSkVDVElPTicsIGU/LnJlYXNvbiApOyB9IGNhdGNoICggXyApIHt9XHJcblx0XHR9ICk7XHJcblx0fVxyXG5cclxuXHRyZXR1cm4gb2JqO1xyXG5cdH0oIF93cGJjIHx8IHt9LCBqUXVlcnkgKSk7XHJcbiIsIi8qKlxyXG4gKiBFeHRlbmQgX3dwYmMgd2l0aCAgbmV3IG1ldGhvZHMgICAgICAgIC8vIEZpeEluOiA5LjguNi4yLlxyXG4gKlxyXG4gKiBAdHlwZSB7Knx7fX1cclxuICogQHByaXZhdGVcclxuICovXHJcbiBfd3BiYyA9IChmdW5jdGlvbiAoIG9iaiwgJCkge1xyXG5cclxuXHQvLyBMb2FkIEJhbGFuY2VyIFx0LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHJcblx0dmFyIHBfYmFsYW5jZXIgPSBvYmouYmFsYW5jZXJfb2JqID0gb2JqLmJhbGFuY2VyX29iaiB8fCB7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J21heF90aHJlYWRzJzogMixcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnaW5fcHJvY2VzcycgOiBbXSxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnd2FpdCcgICAgICAgOiBbXVxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHR9O1xyXG5cclxuXHQgLyoqXHJcblx0ICAqIFNldCAgbWF4IHBhcmFsbGVsIHJlcXVlc3QgIHRvICBsb2FkXHJcblx0ICAqXHJcblx0ICAqIEBwYXJhbSBtYXhfdGhyZWFkc1xyXG5cdCAgKi9cclxuXHRvYmouYmFsYW5jZXJfX3NldF9tYXhfdGhyZWFkcyA9IGZ1bmN0aW9uICggbWF4X3RocmVhZHMgKXtcclxuXHJcblx0XHRwX2JhbGFuY2VyWyAnbWF4X3RocmVhZHMnIF0gPSBtYXhfdGhyZWFkcztcclxuXHR9O1xyXG5cclxuXHQvKipcclxuXHQgKiAgQ2hlY2sgaWYgYmFsYW5jZXIgZm9yIHNwZWNpZmljIGJvb2tpbmcgcmVzb3VyY2UgZGVmaW5lZCAgIDo6ICAgdHJ1ZSB8IGZhbHNlXHJcblx0ICpcclxuXHQgKiBAcGFyYW0ge3N0cmluZ3xpbnR9IHJlc291cmNlX2lkXHJcblx0ICogQHJldHVybnMge2Jvb2xlYW59XHJcblx0ICovXHJcblx0b2JqLmJhbGFuY2VyX19pc19kZWZpbmVkID0gZnVuY3Rpb24gKCByZXNvdXJjZV9pZCApIHtcclxuXHJcblx0XHRyZXR1cm4gKCd1bmRlZmluZWQnICE9PSB0eXBlb2YoIHBfYmFsYW5jZXJbICdiYWxhbmNlcl8nICsgcmVzb3VyY2VfaWQgXSApICk7XHJcblx0fTtcclxuXHJcblxyXG5cdC8qKlxyXG5cdCAqICBDcmVhdGUgYmFsYW5jZXIgaW5pdGlhbGl6aW5nXHJcblx0ICpcclxuXHQgKiBAcGFyYW0ge3N0cmluZ3xpbnR9IHJlc291cmNlX2lkXHJcblx0ICovXHJcblx0b2JqLmJhbGFuY2VyX19pbml0ID0gZnVuY3Rpb24gKCByZXNvdXJjZV9pZCwgZnVuY3Rpb25fbmFtZSAsIHBhcmFtcyA9e30pIHtcclxuXHJcblx0XHR2YXIgYmFsYW5jZV9vYmogPSB7fTtcclxuXHRcdGJhbGFuY2Vfb2JqWyAncmVzb3VyY2VfaWQnIF0gICA9IHJlc291cmNlX2lkO1xyXG5cdFx0YmFsYW5jZV9vYmpbICdwcmlvcml0eScgXSAgICAgID0gMTtcclxuXHRcdGJhbGFuY2Vfb2JqWyAnZnVuY3Rpb25fbmFtZScgXSA9IGZ1bmN0aW9uX25hbWU7XHJcblx0XHRiYWxhbmNlX29ialsgJ3BhcmFtcycgXSAgICAgICAgPSB3cGJjX2Nsb25lX29iaiggcGFyYW1zICk7XHJcblxyXG5cclxuXHRcdGlmICggb2JqLmJhbGFuY2VyX19pc19hbHJlYWR5X3J1biggcmVzb3VyY2VfaWQsIGZ1bmN0aW9uX25hbWUgKSApe1xyXG5cdFx0XHRyZXR1cm4gJ3J1bic7XHJcblx0XHR9XHJcblx0XHRpZiAoIG9iai5iYWxhbmNlcl9faXNfYWxyZWFkeV93YWl0KCByZXNvdXJjZV9pZCwgZnVuY3Rpb25fbmFtZSApICl7XHJcblx0XHRcdHJldHVybiAnd2FpdCc7XHJcblx0XHR9XHJcblxyXG5cclxuXHRcdGlmICggb2JqLmJhbGFuY2VyX19jYW5faV9ydW4oKSApe1xyXG5cdFx0XHRvYmouYmFsYW5jZXJfX2FkZF90b19fcnVuKCBiYWxhbmNlX29iaiApO1xyXG5cdFx0XHRyZXR1cm4gJ3J1bic7XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHRvYmouYmFsYW5jZXJfX2FkZF90b19fd2FpdCggYmFsYW5jZV9vYmogKTtcclxuXHRcdFx0cmV0dXJuICd3YWl0JztcclxuXHRcdH1cclxuXHR9O1xyXG5cclxuXHQgLyoqXHJcblx0ICAqIENhbiBJIFJ1biA/XHJcblx0ICAqIEByZXR1cm5zIHtib29sZWFufVxyXG5cdCAgKi9cclxuXHRvYmouYmFsYW5jZXJfX2Nhbl9pX3J1biA9IGZ1bmN0aW9uICgpe1xyXG5cdFx0cmV0dXJuICggcF9iYWxhbmNlclsgJ2luX3Byb2Nlc3MnIF0ubGVuZ3RoIDwgcF9iYWxhbmNlclsgJ21heF90aHJlYWRzJyBdICk7XHJcblx0fVxyXG5cclxuXHRcdCAvKipcclxuXHRcdCAgKiBBZGQgdG8gV0FJVFxyXG5cdFx0ICAqIEBwYXJhbSBiYWxhbmNlX29ialxyXG5cdFx0ICAqL1xyXG5cdFx0b2JqLmJhbGFuY2VyX19hZGRfdG9fX3dhaXQgPSBmdW5jdGlvbiAoIGJhbGFuY2Vfb2JqICkge1xyXG5cdFx0XHRwX2JhbGFuY2VyWyd3YWl0J10ucHVzaCggYmFsYW5jZV9vYmogKTtcclxuXHRcdH1cclxuXHJcblx0XHQgLyoqXHJcblx0XHQgICogUmVtb3ZlIGZyb20gV2FpdFxyXG5cdFx0ICAqXHJcblx0XHQgICogQHBhcmFtIHJlc291cmNlX2lkXHJcblx0XHQgICogQHBhcmFtIGZ1bmN0aW9uX25hbWVcclxuXHRcdCAgKiBAcmV0dXJucyB7Knxib29sZWFufVxyXG5cdFx0ICAqL1xyXG5cdFx0b2JqLmJhbGFuY2VyX19yZW1vdmVfZnJvbV9fd2FpdF9saXN0ID0gZnVuY3Rpb24gKCByZXNvdXJjZV9pZCwgZnVuY3Rpb25fbmFtZSApe1xyXG5cclxuXHRcdFx0dmFyIHJlbW92ZWRfZWwgPSBmYWxzZTtcclxuXHJcblx0XHRcdGlmICggcF9iYWxhbmNlclsgJ3dhaXQnIF0ubGVuZ3RoICl7XHRcdFx0XHRcdC8vIEZpeEluOiA5LjguMTAuMS5cclxuXHRcdFx0XHRmb3IgKCB2YXIgaSBpbiBwX2JhbGFuY2VyWyAnd2FpdCcgXSApe1xyXG5cdFx0XHRcdFx0aWYgKFxyXG5cdFx0XHRcdFx0XHQocmVzb3VyY2VfaWQgPT09IHBfYmFsYW5jZXJbICd3YWl0JyBdWyBpIF1bICdyZXNvdXJjZV9pZCcgXSlcclxuXHRcdFx0XHRcdFx0JiYgKGZ1bmN0aW9uX25hbWUgPT09IHBfYmFsYW5jZXJbICd3YWl0JyBdWyBpIF1bICdmdW5jdGlvbl9uYW1lJyBdKVxyXG5cdFx0XHRcdFx0KXtcclxuXHRcdFx0XHRcdFx0cmVtb3ZlZF9lbCA9IHBfYmFsYW5jZXJbICd3YWl0JyBdLnNwbGljZSggaSwgMSApO1xyXG5cdFx0XHRcdFx0XHRyZW1vdmVkX2VsID0gcmVtb3ZlZF9lbC5wb3AoKTtcclxuXHRcdFx0XHRcdFx0cF9iYWxhbmNlclsgJ3dhaXQnIF0gPSBwX2JhbGFuY2VyWyAnd2FpdCcgXS5maWx0ZXIoIGZ1bmN0aW9uICggdiApe1xyXG5cdFx0XHRcdFx0XHRcdHJldHVybiB2O1xyXG5cdFx0XHRcdFx0XHR9ICk7XHRcdFx0XHRcdC8vIFJlaW5kZXggYXJyYXlcclxuXHRcdFx0XHRcdFx0cmV0dXJuIHJlbW92ZWRfZWw7XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblx0XHRcdHJldHVybiByZW1vdmVkX2VsO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8qKlxyXG5cdFx0KiBJcyBhbHJlYWR5IFdBSVRcclxuXHRcdCpcclxuXHRcdCogQHBhcmFtIHJlc291cmNlX2lkXHJcblx0XHQqIEBwYXJhbSBmdW5jdGlvbl9uYW1lXHJcblx0XHQqIEByZXR1cm5zIHtib29sZWFufVxyXG5cdFx0Ki9cclxuXHRcdG9iai5iYWxhbmNlcl9faXNfYWxyZWFkeV93YWl0ID0gZnVuY3Rpb24gKCByZXNvdXJjZV9pZCwgZnVuY3Rpb25fbmFtZSApe1xyXG5cclxuXHRcdFx0aWYgKCBwX2JhbGFuY2VyWyAnd2FpdCcgXS5sZW5ndGggKXtcdFx0XHRcdC8vIEZpeEluOiA5LjguMTAuMS5cclxuXHRcdFx0XHRmb3IgKCB2YXIgaSBpbiBwX2JhbGFuY2VyWyAnd2FpdCcgXSApe1xyXG5cdFx0XHRcdFx0aWYgKFxyXG5cdFx0XHRcdFx0XHQocmVzb3VyY2VfaWQgPT09IHBfYmFsYW5jZXJbICd3YWl0JyBdWyBpIF1bICdyZXNvdXJjZV9pZCcgXSlcclxuXHRcdFx0XHRcdFx0JiYgKGZ1bmN0aW9uX25hbWUgPT09IHBfYmFsYW5jZXJbICd3YWl0JyBdWyBpIF1bICdmdW5jdGlvbl9uYW1lJyBdKVxyXG5cdFx0XHRcdFx0KXtcclxuXHRcdFx0XHRcdFx0cmV0dXJuIHRydWU7XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblx0XHRcdHJldHVybiBmYWxzZTtcclxuXHRcdH1cclxuXHJcblxyXG5cdFx0IC8qKlxyXG5cdFx0ICAqIEFkZCB0byBSVU5cclxuXHRcdCAgKiBAcGFyYW0gYmFsYW5jZV9vYmpcclxuXHRcdCAgKi9cclxuXHRcdG9iai5iYWxhbmNlcl9fYWRkX3RvX19ydW4gPSBmdW5jdGlvbiAoIGJhbGFuY2Vfb2JqICkge1xyXG5cdFx0XHRwX2JhbGFuY2VyWydpbl9wcm9jZXNzJ10ucHVzaCggYmFsYW5jZV9vYmogKTtcclxuXHRcdH1cclxuXHJcblx0XHQvKipcclxuXHRcdCogUmVtb3ZlIGZyb20gUlVOIGxpc3RcclxuXHRcdCpcclxuXHRcdCogQHBhcmFtIHJlc291cmNlX2lkXHJcblx0XHQqIEBwYXJhbSBmdW5jdGlvbl9uYW1lXHJcblx0XHQqIEByZXR1cm5zIHsqfGJvb2xlYW59XHJcblx0XHQqL1xyXG5cdFx0b2JqLmJhbGFuY2VyX19yZW1vdmVfZnJvbV9fcnVuX2xpc3QgPSBmdW5jdGlvbiAoIHJlc291cmNlX2lkLCBmdW5jdGlvbl9uYW1lICl7XHJcblxyXG5cdFx0XHQgdmFyIHJlbW92ZWRfZWwgPSBmYWxzZTtcclxuXHJcblx0XHRcdCBpZiAoIHBfYmFsYW5jZXJbICdpbl9wcm9jZXNzJyBdLmxlbmd0aCApe1x0XHRcdFx0Ly8gRml4SW46IDkuOC4xMC4xLlxyXG5cdFx0XHRcdCBmb3IgKCB2YXIgaSBpbiBwX2JhbGFuY2VyWyAnaW5fcHJvY2VzcycgXSApe1xyXG5cdFx0XHRcdFx0IGlmIChcclxuXHRcdFx0XHRcdFx0IChyZXNvdXJjZV9pZCA9PT0gcF9iYWxhbmNlclsgJ2luX3Byb2Nlc3MnIF1bIGkgXVsgJ3Jlc291cmNlX2lkJyBdKVxyXG5cdFx0XHRcdFx0XHQgJiYgKGZ1bmN0aW9uX25hbWUgPT09IHBfYmFsYW5jZXJbICdpbl9wcm9jZXNzJyBdWyBpIF1bICdmdW5jdGlvbl9uYW1lJyBdKVxyXG5cdFx0XHRcdFx0ICl7XHJcblx0XHRcdFx0XHRcdCByZW1vdmVkX2VsID0gcF9iYWxhbmNlclsgJ2luX3Byb2Nlc3MnIF0uc3BsaWNlKCBpLCAxICk7XHJcblx0XHRcdFx0XHRcdCByZW1vdmVkX2VsID0gcmVtb3ZlZF9lbC5wb3AoKTtcclxuXHRcdFx0XHRcdFx0IHBfYmFsYW5jZXJbICdpbl9wcm9jZXNzJyBdID0gcF9iYWxhbmNlclsgJ2luX3Byb2Nlc3MnIF0uZmlsdGVyKCBmdW5jdGlvbiAoIHYgKXtcclxuXHRcdFx0XHRcdFx0XHQgcmV0dXJuIHY7XHJcblx0XHRcdFx0XHRcdCB9ICk7XHRcdC8vIFJlaW5kZXggYXJyYXlcclxuXHRcdFx0XHRcdFx0IHJldHVybiByZW1vdmVkX2VsO1xyXG5cdFx0XHRcdFx0IH1cclxuXHRcdFx0XHQgfVxyXG5cdFx0XHQgfVxyXG5cdFx0XHQgcmV0dXJuIHJlbW92ZWRfZWw7XHJcblx0XHR9XHJcblxyXG5cdFx0LyoqXHJcblx0XHQqIElzIGFscmVhZHkgUlVOXHJcblx0XHQqXHJcblx0XHQqIEBwYXJhbSByZXNvdXJjZV9pZFxyXG5cdFx0KiBAcGFyYW0gZnVuY3Rpb25fbmFtZVxyXG5cdFx0KiBAcmV0dXJucyB7Ym9vbGVhbn1cclxuXHRcdCovXHJcblx0XHRvYmouYmFsYW5jZXJfX2lzX2FscmVhZHlfcnVuID0gZnVuY3Rpb24gKCByZXNvdXJjZV9pZCwgZnVuY3Rpb25fbmFtZSApe1xyXG5cclxuXHRcdFx0aWYgKCBwX2JhbGFuY2VyWyAnaW5fcHJvY2VzcycgXS5sZW5ndGggKXtcdFx0XHRcdFx0Ly8gRml4SW46IDkuOC4xMC4xLlxyXG5cdFx0XHRcdGZvciAoIHZhciBpIGluIHBfYmFsYW5jZXJbICdpbl9wcm9jZXNzJyBdICl7XHJcblx0XHRcdFx0XHRpZiAoXHJcblx0XHRcdFx0XHRcdChyZXNvdXJjZV9pZCA9PT0gcF9iYWxhbmNlclsgJ2luX3Byb2Nlc3MnIF1bIGkgXVsgJ3Jlc291cmNlX2lkJyBdKVxyXG5cdFx0XHRcdFx0XHQmJiAoZnVuY3Rpb25fbmFtZSA9PT0gcF9iYWxhbmNlclsgJ2luX3Byb2Nlc3MnIF1bIGkgXVsgJ2Z1bmN0aW9uX25hbWUnIF0pXHJcblx0XHRcdFx0XHQpe1xyXG5cdFx0XHRcdFx0XHRyZXR1cm4gdHJ1ZTtcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHRcdFx0cmV0dXJuIGZhbHNlO1xyXG5cdFx0fVxyXG5cclxuXHJcblxyXG5cdG9iai5iYWxhbmNlcl9fcnVuX25leHQgPSBmdW5jdGlvbiAoKXtcclxuXHJcblx0XHQvLyBHZXQgMXN0IGZyb20gIFdhaXQgbGlzdFxyXG5cdFx0dmFyIHJlbW92ZWRfZWwgPSBmYWxzZTtcclxuXHRcdGlmICggcF9iYWxhbmNlclsgJ3dhaXQnIF0ubGVuZ3RoICl7XHRcdFx0XHRcdC8vIEZpeEluOiA5LjguMTAuMS5cclxuXHRcdFx0Zm9yICggdmFyIGkgaW4gcF9iYWxhbmNlclsgJ3dhaXQnIF0gKXtcclxuXHRcdFx0XHRyZW1vdmVkX2VsID0gb2JqLmJhbGFuY2VyX19yZW1vdmVfZnJvbV9fd2FpdF9saXN0KCBwX2JhbGFuY2VyWyAnd2FpdCcgXVsgaSBdWyAncmVzb3VyY2VfaWQnIF0sIHBfYmFsYW5jZXJbICd3YWl0JyBdWyBpIF1bICdmdW5jdGlvbl9uYW1lJyBdICk7XHJcblx0XHRcdFx0YnJlYWs7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIGZhbHNlICE9PSByZW1vdmVkX2VsICl7XHJcblxyXG5cdFx0XHQvLyBSdW5cclxuXHRcdFx0b2JqLmJhbGFuY2VyX19ydW4oIHJlbW92ZWRfZWwgKTtcclxuXHRcdH1cclxuXHR9XHJcblxyXG5cdCAvKipcclxuXHQgICogUnVuXHJcblx0ICAqIEBwYXJhbSBiYWxhbmNlX29ialxyXG5cdCAgKi9cclxuXHRvYmouYmFsYW5jZXJfX3J1biA9IGZ1bmN0aW9uICggYmFsYW5jZV9vYmogKXtcclxuXHJcblx0XHRzd2l0Y2ggKCBiYWxhbmNlX29ialsgJ2Z1bmN0aW9uX25hbWUnIF0gKXtcclxuXHJcblx0XHRcdGNhc2UgJ3dwYmNfY2FsZW5kYXJfX2xvYWRfZGF0YV9fYWp4JzpcclxuXHJcblx0XHRcdFx0Ly8gQWRkIHRvIHJ1biBsaXN0XHJcblx0XHRcdFx0b2JqLmJhbGFuY2VyX19hZGRfdG9fX3J1biggYmFsYW5jZV9vYmogKTtcclxuXHJcblx0XHRcdFx0d3BiY19jYWxlbmRhcl9fbG9hZF9kYXRhX19hangoIGJhbGFuY2Vfb2JqWyAncGFyYW1zJyBdIClcclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGRlZmF1bHQ6XHJcblx0XHR9XHJcblx0fVxyXG5cclxuXHRyZXR1cm4gb2JqO1xyXG5cclxufSggX3dwYmMgfHwge30sIGpRdWVyeSApKTtcclxuXHJcblxyXG4gXHQvKipcclxuIFx0ICogLS0gSGVscCBmdW5jdGlvbnMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdCAqL1xyXG5cclxuXHRmdW5jdGlvbiB3cGJjX2JhbGFuY2VyX19pc193YWl0KCBwYXJhbXMsIGZ1bmN0aW9uX25hbWUgKXtcclxuLy9jb25zb2xlLmxvZygnOjp3cGJjX2JhbGFuY2VyX19pc193YWl0JyxwYXJhbXMgLCBmdW5jdGlvbl9uYW1lICk7XHJcblx0XHRpZiAoICd1bmRlZmluZWQnICE9PSB0eXBlb2YgKHBhcmFtc1sgJ3Jlc291cmNlX2lkJyBdKSApe1xyXG5cclxuXHRcdFx0dmFyIGJhbGFuY2VyX3N0YXR1cyA9IF93cGJjLmJhbGFuY2VyX19pbml0KCBwYXJhbXNbICdyZXNvdXJjZV9pZCcgXSwgZnVuY3Rpb25fbmFtZSwgcGFyYW1zICk7XHJcblxyXG5cdFx0XHRyZXR1cm4gKCAnd2FpdCcgPT09IGJhbGFuY2VyX3N0YXR1cyApO1xyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBmYWxzZTtcclxuXHR9XHJcblxyXG5cclxuXHRmdW5jdGlvbiB3cGJjX2JhbGFuY2VyX19jb21wbGV0ZWQoIHJlc291cmNlX2lkICwgZnVuY3Rpb25fbmFtZSApe1xyXG4vL2NvbnNvbGUubG9nKCc6OndwYmNfYmFsYW5jZXJfX2NvbXBsZXRlZCcscmVzb3VyY2VfaWQgLCBmdW5jdGlvbl9uYW1lICk7XHJcblx0XHRfd3BiYy5iYWxhbmNlcl9fcmVtb3ZlX2Zyb21fX3J1bl9saXN0KCByZXNvdXJjZV9pZCwgZnVuY3Rpb25fbmFtZSApO1xyXG5cdFx0X3dwYmMuYmFsYW5jZXJfX3J1bl9uZXh0KCk7XHJcblx0fSIsIi8qKlxyXG4gKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuICpcdGluY2x1ZGVzL19fanMvY2FsL3dwYmNfY2FsLmpzXHJcbiAqID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG4gKi9cclxuXHJcbi8qKlxyXG4gKiBPcmRlciBvciBjaGlsZCBib29raW5nIHJlc291cmNlcyBzYXZlZCBoZXJlOiAgXHRfd3BiYy5ib29raW5nX19nZXRfcGFyYW1fdmFsdWUoIHJlc291cmNlX2lkLFxyXG4gKiAncmVzb3VyY2VzX2lkX2Fycl9faW5fZGF0ZXMnIClcdFx0WzIsMTAsMTIsMTFdXHJcbiAqL1xyXG5cclxuLyoqXHJcbiAqIEhvdyB0byBjaGVjayAgYm9va2VkIHRpbWVzIG9uICBzcGVjaWZpYyBkYXRlOiA/XHJcbiAqXHJcblx0XHRcdF93cGJjLmJvb2tpbmdzX2luX2NhbGVuZGFyX19nZXRfZm9yX2RhdGUoMiwnMjAyMy0wOC0yMScpO1xyXG5cclxuXHRcdFx0Y29uc29sZS5sb2coXHJcblx0XHRcdFx0XHRcdF93cGJjLmJvb2tpbmdzX2luX2NhbGVuZGFyX19nZXRfZm9yX2RhdGUoMiwnMjAyMy0wOC0yMScpWzJdLmJvb2tlZF90aW1lX3Nsb3RzLm1lcmdlZF9zZWNvbmRzLFxyXG5cdFx0XHRcdFx0XHRfd3BiYy5ib29raW5nc19pbl9jYWxlbmRhcl9fZ2V0X2Zvcl9kYXRlKDIsJzIwMjMtMDgtMjEnKVsxMF0uYm9va2VkX3RpbWVfc2xvdHMubWVyZ2VkX3NlY29uZHMsXHJcblx0XHRcdFx0XHRcdF93cGJjLmJvb2tpbmdzX2luX2NhbGVuZGFyX19nZXRfZm9yX2RhdGUoMiwnMjAyMy0wOC0yMScpWzExXS5ib29rZWRfdGltZV9zbG90cy5tZXJnZWRfc2Vjb25kcyxcclxuXHRcdFx0XHRcdFx0X3dwYmMuYm9va2luZ3NfaW5fY2FsZW5kYXJfX2dldF9mb3JfZGF0ZSgyLCcyMDIzLTA4LTIxJylbMTJdLmJvb2tlZF90aW1lX3Nsb3RzLm1lcmdlZF9zZWNvbmRzXHJcblx0XHRcdFx0XHQpO1xyXG4gKiAgT1JcclxuXHRcdFx0Y29uc29sZS5sb2coXHJcblx0XHRcdFx0XHRcdF93cGJjLmJvb2tpbmdzX2luX2NhbGVuZGFyX19nZXRfZm9yX2RhdGUoMiwnMjAyMy0wOC0yMScpWzJdLmJvb2tlZF90aW1lX3Nsb3RzLm1lcmdlZF9yZWFkYWJsZSxcclxuXHRcdFx0XHRcdFx0X3dwYmMuYm9va2luZ3NfaW5fY2FsZW5kYXJfX2dldF9mb3JfZGF0ZSgyLCcyMDIzLTA4LTIxJylbMTBdLmJvb2tlZF90aW1lX3Nsb3RzLm1lcmdlZF9yZWFkYWJsZSxcclxuXHRcdFx0XHRcdFx0X3dwYmMuYm9va2luZ3NfaW5fY2FsZW5kYXJfX2dldF9mb3JfZGF0ZSgyLCcyMDIzLTA4LTIxJylbMTFdLmJvb2tlZF90aW1lX3Nsb3RzLm1lcmdlZF9yZWFkYWJsZSxcclxuXHRcdFx0XHRcdFx0X3dwYmMuYm9va2luZ3NfaW5fY2FsZW5kYXJfX2dldF9mb3JfZGF0ZSgyLCcyMDIzLTA4LTIxJylbMTJdLmJvb2tlZF90aW1lX3Nsb3RzLm1lcmdlZF9yZWFkYWJsZVxyXG5cdFx0XHRcdFx0KTtcclxuICpcclxuICovXHJcblxyXG4vKipcclxuICogRGF5cyBzZWxlY3Rpb246XHJcbiAqIFx0XHRcdFx0XHR3cGJjX2NhbGVuZGFyX191bnNlbGVjdF9hbGxfZGF0ZXMoIHJlc291cmNlX2lkICk7XHJcbiAqXHJcbiAqXHRcdFx0XHRcdHZhciByZXNvdXJjZV9pZCA9IDE7XHJcbiAqIFx0RXhhbXBsZSAxOlx0XHR2YXIgbnVtX3NlbGVjdGVkX2RheXMgPSB3cGJjX2F1dG9fc2VsZWN0X2RhdGVzX2luX2NhbGVuZGFyKCByZXNvdXJjZV9pZCwgJzIwMjQtMDUtMTUnLFxyXG4gKiAnMjAyNC0wNS0yNScgKTsgRXhhbXBsZSAyOlx0XHR2YXIgbnVtX3NlbGVjdGVkX2RheXMgPSB3cGJjX2F1dG9fc2VsZWN0X2RhdGVzX2luX2NhbGVuZGFyKCByZXNvdXJjZV9pZCxcclxuICogWycyMDI0LTA1LTA5JywnMjAyNC0wNS0xOScsJzIwMjQtMDUtMjUnXSApO1xyXG4gKlxyXG4gKi9cclxuXHJcblxyXG4vKipcclxuICogQyBBIEwgRSBOIEQgQSBSICAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuICovXHJcblxyXG5cclxuLyoqXHJcbiAqICBTaG93IFdQQkMgQ2FsZW5kYXJcclxuICpcclxuICogQHBhcmFtIHJlc291cmNlX2lkXHRcdFx0LSByZXNvdXJjZSBJRFxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn1cclxuICovXHJcbmZ1bmN0aW9uIHdwYmNfY2FsZW5kYXJfc2hvdyggcmVzb3VyY2VfaWQgKXtcclxuXHJcblx0Ly8gSWYgbm8gY2FsZW5kYXIgSFRNTCB0YWcsICB0aGVuICBleGl0XHJcblx0aWYgKCAwID09PSBqUXVlcnkoICcjY2FsZW5kYXJfYm9va2luZycgKyByZXNvdXJjZV9pZCApLmxlbmd0aCApeyByZXR1cm4gZmFsc2U7IH1cclxuXHJcblx0Ly8gSWYgdGhlIGNhbGVuZGFyIHdpdGggdGhlIHNhbWUgQm9va2luZyByZXNvdXJjZSBpcyBhY3RpdmF0ZWQgYWxyZWFkeSwgdGhlbiBleGl0LiBCdXQgaW4gRWxlbWVudG9yIHRoZSBjbGFzcyBjYW4gYmUgc3RhbGUsIHNvIHZlcmlmeSBpbnN0YW5jZS5cclxuXHRpZiAoIGpRdWVyeSggJyNjYWxlbmRhcl9ib29raW5nJyArIHJlc291cmNlX2lkICkuaGFzQ2xhc3MoICdoYXNEYXRlcGljaycgKSApIHtcclxuXHJcblx0XHR2YXIgZXhpc3RpbmdfaW5zdCA9IG51bGw7XHJcblxyXG5cdFx0dHJ5IHtcclxuXHRcdFx0ZXhpc3RpbmdfaW5zdCA9IGpRdWVyeS5kYXRlcGljay5fZ2V0SW5zdCggalF1ZXJ5KCAnI2NhbGVuZGFyX2Jvb2tpbmcnICsgcmVzb3VyY2VfaWQgKS5nZXQoIDAgKSApO1xyXG5cdFx0fSBjYXRjaCAoIGUgKSB7XHJcblx0XHRcdGV4aXN0aW5nX2luc3QgPSBudWxsO1xyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggZXhpc3RpbmdfaW5zdCApIHtcclxuXHRcdFx0cmV0dXJuIGZhbHNlO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8vIFN0YWxlIG1hcmtlcjogcmVtb3ZlIGFuZCBjb250aW51ZSB3aXRoIGluaXQuXHJcblx0XHRqUXVlcnkoICcjY2FsZW5kYXJfYm9va2luZycgKyByZXNvdXJjZV9pZCApLnJlbW92ZUNsYXNzKCAnaGFzRGF0ZXBpY2snICk7XHJcblx0fVxyXG5cclxuXHR3cGJjX3JhbmdlX3NlbGVjdGlvbl9fcHJlcGFyZV9ndWlkYW5jZSggcmVzb3VyY2VfaWQgKTtcclxuXHJcblxyXG5cclxuXHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdC8vIERheXMgc2VsZWN0aW9uXHJcblx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHR2YXIgbG9jYWxfX2lzX3JhbmdlX3NlbGVjdCA9IGZhbHNlO1xyXG5cdHZhciBsb2NhbF9fbXVsdGlfZGF5c19zZWxlY3RfbnVtICAgPSAzNjU7XHRcdFx0XHRcdC8vIG11bHRpcGxlIHwgZml4ZWRcclxuXHRpZiAoICdkeW5hbWljJyA9PT0gX3dwYmMuY2FsZW5kYXJfX2dldF9wYXJhbV92YWx1ZSggcmVzb3VyY2VfaWQsICdkYXlzX3NlbGVjdF9tb2RlJyApICl7XHJcblx0XHRsb2NhbF9faXNfcmFuZ2Vfc2VsZWN0ID0gdHJ1ZTtcclxuXHRcdGxvY2FsX19tdWx0aV9kYXlzX3NlbGVjdF9udW0gPSAwO1xyXG5cdH1cclxuXHRpZiAoICdzaW5nbGUnICA9PT0gX3dwYmMuY2FsZW5kYXJfX2dldF9wYXJhbV92YWx1ZSggcmVzb3VyY2VfaWQsICdkYXlzX3NlbGVjdF9tb2RlJyApICl7XHJcblx0XHRsb2NhbF9fbXVsdGlfZGF5c19zZWxlY3RfbnVtID0gMDtcclxuXHR9XHJcblxyXG5cdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0Ly8gTWluIC0gTWF4IGRheXMgdG8gc2Nyb2xsL3Nob3dcclxuXHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdHZhciBsb2NhbF9fbWluX2RhdGUgPSAwO1xyXG4gXHRsb2NhbF9fbWluX2RhdGUgPSBuZXcgRGF0ZSggX3dwYmMuZ2V0X290aGVyX3BhcmFtKCAndG9kYXlfYXJyJyApWyAwIF0sIChwYXJzZUludCggX3dwYmMuZ2V0X290aGVyX3BhcmFtKCAndG9kYXlfYXJyJyApWyAxIF0gKSAtIDEpLCBfd3BiYy5nZXRfb3RoZXJfcGFyYW0oICd0b2RheV9hcnInIClbIDIgXSwgMCwgMCwgMCApO1x0XHRcdC8vIEZpeEluOiA5LjkuMC4xNy5cclxuLy9jb25zb2xlLmxvZyggbG9jYWxfX21pbl9kYXRlICk7XHJcblx0dmFyIGxvY2FsX19tYXhfZGF0ZSA9IF93cGJjLmNhbGVuZGFyX19nZXRfcGFyYW1fdmFsdWUoIHJlc291cmNlX2lkLCAnYm9va2luZ19tYXhfbW9udGhlc19pbl9jYWxlbmRhcicgKTtcclxuXHQvL2xvY2FsX19tYXhfZGF0ZSA9IG5ldyBEYXRlKDIwMjQsIDUsIDI4KTsgIEl0IGlzIGhlcmUgaXNzdWUgb2Ygbm90IHNlbGVjdGFibGUgZGF0ZXMsIGJ1dCBzb21lIGRhdGVzIHNob3dpbmcgaW4gY2FsZW5kYXIgYXMgYXZhaWxhYmxlLCBidXQgd2UgY2FuIG5vdCBzZWxlY3QgaXQuXHJcblxyXG5cdC8vLy8gRGVmaW5lIGxhc3QgZGF5IGluIGNhbGVuZGFyIChhcyBhIGxhc3QgZGF5IG9mIG1vbnRoIChhbmQgbm90IGRhdGUsIHdoaWNoIGlzIHJlbGF0ZWQgdG8gYWN0dWFsICdUb2RheScgZGF0ZSkuXHJcblx0Ly8vLyBFLmcuIGlmIHRvZGF5IGlzIDIwMjMtMDktMjUsIGFuZCB3ZSBzZXQgJ051bWJlciBvZiBtb250aHMgdG8gc2Nyb2xsJyBhcyA1IG1vbnRocywgdGhlbiBsYXN0IGRheSB3aWxsIGJlIDIwMjQtMDItMjkgYW5kIG5vdCB0aGUgMjAyNC0wMi0yNS5cclxuXHQvLyB2YXIgY2FsX2xhc3RfZGF5X2luX21vbnRoID0galF1ZXJ5LmRhdGVwaWNrLl9kZXRlcm1pbmVEYXRlKCBudWxsLCBsb2NhbF9fbWF4X2RhdGUsIG5ldyBEYXRlKCkgKTtcclxuXHQvLyBjYWxfbGFzdF9kYXlfaW5fbW9udGggPSBuZXcgRGF0ZSggY2FsX2xhc3RfZGF5X2luX21vbnRoLmdldEZ1bGxZZWFyKCksIGNhbF9sYXN0X2RheV9pbl9tb250aC5nZXRNb250aCgpICsgMSwgMCApO1xyXG5cdC8vIGxvY2FsX19tYXhfZGF0ZSA9IGNhbF9sYXN0X2RheV9pbl9tb250aDtcdFx0XHQvLyBGaXhJbjogMTAuMC4wLjI2LlxyXG5cclxuXHQvLyBHZXQgc3RhcnQgLyBlbmQgZGF0ZXMgZnJvbSAgdGhlIEJvb2tpbmcgQ2FsZW5kYXIgc2hvcnRjb2RlLiBFeGFtcGxlOiBbYm9va2luZyBjYWxlbmRhcl9kYXRlc19zdGFydD0nMjAyNi0wMS0wMScgY2FsZW5kYXJfZGF0ZXNfZW5kPScyMDI2LTEyLTMxJyAgcmVzb3VyY2VfaWQ9MV0gLy8gRml4SW46IDEwLjEzLjEuNC5cclxuXHRpZiAoIGZhbHNlICE9PSB3cGJjX2NhbGVuZGFyX19nZXRfZGF0ZXNfc3RhcnQoIHJlc291cmNlX2lkICkgKSB7XHJcblx0XHRsb2NhbF9fbWluX2RhdGUgPSB3cGJjX2NhbGVuZGFyX19nZXRfZGF0ZXNfc3RhcnQoIHJlc291cmNlX2lkICk7ICAvLyBFLmcuIC0gbG9jYWxfX21pbl9kYXRlID0gbmV3IERhdGUoIDIwMjUsIDAsIDEgKTtcclxuXHR9XHJcblx0aWYgKCBmYWxzZSAhPT0gd3BiY19jYWxlbmRhcl9fZ2V0X2RhdGVzX2VuZCggcmVzb3VyY2VfaWQgKSApIHtcclxuXHRcdGxvY2FsX19tYXhfZGF0ZSA9IHdwYmNfY2FsZW5kYXJfX2dldF9kYXRlc19lbmQoIHJlc291cmNlX2lkICk7ICAgIC8vIEUuZy4gLSBsb2NhbF9fbWF4X2RhdGUgPSBuZXcgRGF0ZSggMjAyNSwgMTEsIDMxICk7XHJcblx0fVxyXG5cclxuXHQvLyBJbiBjYXNlIHdlIGVkaXQgYm9va2luZyBpbiBwYXN0IG9yIGhhdmUgc3BlY2lmaWMgcGFyYW1ldGVyIGluIFVSTC5cclxuXHR2YXIgd3BiY19lZGl0X2Jvb2tpbmdfaGFzaCA9IF93cGJjLmdldF9vdGhlcl9wYXJhbSggJ3RoaXNfcGFnZV9ib29raW5nX2hhc2gnICk7XHJcblx0dmFyIHdwYmNfaXNfZWRpdF9ib29raW5nX2NvbnRleHQgPSAoICd1bmRlZmluZWQnICE9PSB0eXBlb2Ygd3BiY19lZGl0X2Jvb2tpbmdfaGFzaCApICYmICggJycgIT09IHdwYmNfZWRpdF9ib29raW5nX2hhc2ggKTtcclxuXHR2YXIgd3BiY19hbGxvd19wYXN0X2NvbnRleHQgPSBfd3BiYy5nZXRfb3RoZXJfcGFyYW0oICd0aGlzX3BhZ2VfYWxsb3dfcGFzdCcgKTtcclxuXHR2YXIgd3BiY19pc19hbGxvd19wYXN0X2NvbnRleHQgPSAoICcxJyA9PT0gU3RyaW5nKCB3cGJjX2FsbG93X3Bhc3RfY29udGV4dCApICkgfHwgKCAxID09PSB3cGJjX2FsbG93X3Bhc3RfY29udGV4dCApIHx8ICggdHJ1ZSA9PT0gd3BiY19hbGxvd19wYXN0X2NvbnRleHQgKTtcclxuXHR2YXIgd3BiY19hbGxvd19wYXN0X2RhdGVfYXJyID0gX3dwYmMuZ2V0X290aGVyX3BhcmFtKCAndGhpc19wYWdlX2FsbG93X3Bhc3RfYXJyJyApO1xyXG5cdHZhciB3cGJjX2lzX2FkZF9ib29raW5nX2FkbWluX3BhZ2UgPSAoIGxvY2F0aW9uLmhyZWYuaW5kZXhPZiggJ3BhZ2U9d3BiYycgKSAhPSAtMSApICYmICggbG9jYXRpb24uaHJlZi5pbmRleE9mKCAndGFiPWFkZC1ib29raW5nJyApICE9IC0xICk7XHJcblx0aWYgKCAgICggd3BiY19pc19hZGRfYm9va2luZ19hZG1pbl9wYWdlIHx8IHdwYmNfaXNfZWRpdF9ib29raW5nX2NvbnRleHQgfHwgd3BiY19pc19hbGxvd19wYXN0X2NvbnRleHQgKVxyXG5cdFx0JiYgKFxyXG5cdFx0XHQgIHdwYmNfaXNfZWRpdF9ib29raW5nX2NvbnRleHRcclxuXHRcdCAgIHx8IHdwYmNfaXNfYWxsb3dfcGFzdF9jb250ZXh0XHJcblx0XHQgICB8fCAoIGxvY2F0aW9uLmhyZWYuaW5kZXhPZignYm9va2luZ19oYXNoJykgIT0gLTEgKSAgICAgICAgICAgICAgICAgIC8vIENvbW1lbnQgdGhpcyBsaW5lIGZvciBhYmlsaXR5IHRvIGFkZCAgYm9va2luZyBpbiBwYXN0IGRheXMgYXQgIEJvb2tpbmcgPiBBZGQgYm9va2luZyBwYWdlLlxyXG5cdFx0ICAgfHwgKCBsb2NhdGlvbi5ocmVmLmluZGV4T2YoJ2FsbG93X3Bhc3QnKSAhPSAtMSApICAgICAgICAgICAgICAgIC8vIEZpeEluOiAxMC43LjEuMi5cclxuXHRcdClcclxuXHQpe1xyXG5cdFx0Ly8gbG9jYWxfX21pbl9kYXRlID0gbnVsbDtcclxuXHRcdC8vIEZpeEluOiAxMC4xNC4xLjQuXHJcblx0XHR2YXIgd3BiY19taW5fZGF0ZV9hcnIgPSAoIHdwYmNfaXNfYWxsb3dfcGFzdF9jb250ZXh0ICYmIHdwYmNfYWxsb3dfcGFzdF9kYXRlX2FyciAmJiAoIDUgPD0gd3BiY19hbGxvd19wYXN0X2RhdGVfYXJyLmxlbmd0aCApICkgPyB3cGJjX2FsbG93X3Bhc3RfZGF0ZV9hcnIgOiBfd3BiYy5nZXRfb3RoZXJfcGFyYW0oICd0aW1lX2xvY2FsX2FycicgKTtcclxuXHRcdGxvY2FsX19taW5fZGF0ZSAgPSBuZXcgRGF0ZSggd3BiY19taW5fZGF0ZV9hcnJbMF0sICggcGFyc2VJbnQoIHdwYmNfbWluX2RhdGVfYXJyWzFdICkgLSAxKSwgd3BiY19taW5fZGF0ZV9hcnJbMl0sIHdwYmNfbWluX2RhdGVfYXJyWzNdLCB3cGJjX21pbl9kYXRlX2Fycls0XSwgMCApO1xyXG5cdFx0bG9jYWxfX21heF9kYXRlID0gbnVsbDtcclxuXHR9XHJcblxyXG5cdHZhciBsb2NhbF9fc3RhcnRfd2Vla2RheSAgICA9IF93cGJjLmNhbGVuZGFyX19nZXRfcGFyYW1fdmFsdWUoIHJlc291cmNlX2lkLCAnYm9va2luZ19zdGFydF9kYXlfd2VlZWsnICk7XHJcblx0dmFyIGxvY2FsX19udW1iZXJfb2ZfbW9udGhzID0gcGFyc2VJbnQoIF93cGJjLmNhbGVuZGFyX19nZXRfcGFyYW1fdmFsdWUoIHJlc291cmNlX2lkLCAnY2FsZW5kYXJfbnVtYmVyX29mX21vbnRocycgKSApO1xyXG5cclxuXHRqUXVlcnkoICcjY2FsZW5kYXJfYm9va2luZycgKyByZXNvdXJjZV9pZCApLnRleHQoICcnICk7XHRcdFx0XHRcdC8vIFJlbW92ZSBhbGwgSFRNTCBpbiBjYWxlbmRhciB0YWdcclxuXHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdC8vIFNob3cgY2FsZW5kYXJcclxuXHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdGpRdWVyeSgnI2NhbGVuZGFyX2Jvb2tpbmcnKyByZXNvdXJjZV9pZCkuZGF0ZXBpY2soXHJcblx0XHRcdHtcblx0XHRcdFx0YmVmb3JlU2VsZWN0RGF5OiBmdW5jdGlvbiAoIGpzX2RhdGUsIGluc3QgKSB7XG5cdFx0XHRcdFx0cmV0dXJuICdmdW5jdGlvbicgPT09IHR5cGVvZiB3cGJjX19jYWxlbmRhcl9fYmVmb3JlX3NlbGVjdF9kYXlzX19ic1xuXHRcdFx0XHRcdFx0PyB3cGJjX19jYWxlbmRhcl9fYmVmb3JlX3NlbGVjdF9kYXlzX19icygganNfZGF0ZSwgcmVzb3VyY2VfaWQsIGluc3QgKSA6IHRydWU7XG5cdFx0XHRcdH0sXG5cdFx0XHRcdGJlZm9yZVNob3dEYXk6IGZ1bmN0aW9uICgganNfZGF0ZSApe1xuXHRcdFx0XHRcdFx0XHRcdFx0cmV0dXJuIHdwYmNfX2NhbGVuZGFyX19hcHBseV9jc3NfdG9fZGF5cygganNfZGF0ZSwgeydyZXNvdXJjZV9pZCc6IHJlc291cmNlX2lkfSwgdGhpcyApO1xyXG5cdFx0XHRcdFx0XHRcdCAgfSxcclxuXHRcdFx0XHRvblNlbGVjdDogZnVuY3Rpb24gKCBzdHJpbmdfZGF0ZXMsIGpzX2RhdGVzX2FyciApeyAgLyoqXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQgKlx0c3RyaW5nX2RhdGVzICAgPSAgICcyMy4wOC4yMDIzIC0gMjYuMDguMjAyMydcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCAqICAgfCAgICAnMjMuMDguMjAyMyAtIDIzLjA4LjIwMjMnICAgIHxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCAqICcxOS4wOS4yMDIzLCAyNC4wOC4yMDIzLCAzMC4wOS4yMDIzJ1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0ICoganNfZGF0ZXNfYXJyICAgPSAgIHJhbmdlOiBbIERhdGUgKEF1ZyAyMyAyMDIzKSxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCAqIERhdGUgKEF1ZyAyNSAyMDIzKV0gICAgIHwgICAgIG11bHRpcGxlOiBbXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQgKiBEYXRlKE9jdCAyNCAyMDIzKSwgRGF0ZShPY3QgMjAgMjAyMyksIERhdGUoT2N0XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQgKiAxNiAyMDIzKSBdXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQgKi9cclxuXHRcdFx0XHRcdFx0XHRcdFx0cmV0dXJuIHdwYmNfX2NhbGVuZGFyX19vbl9zZWxlY3RfZGF5cyggc3RyaW5nX2RhdGVzLCB7J3Jlc291cmNlX2lkJzogcmVzb3VyY2VfaWR9LCB0aGlzICk7XHJcblx0XHRcdFx0XHRcdFx0ICB9LFxyXG5cdFx0XHRcdG9uSG92ZXI6IGZ1bmN0aW9uICggc3RyaW5nX2RhdGUsIGpzX2RhdGUgKXtcclxuXHRcdFx0XHRcdFx0XHRcdFx0cmV0dXJuIHdwYmNfX2NhbGVuZGFyX19vbl9ob3Zlcl9kYXlzKCBzdHJpbmdfZGF0ZSwganNfZGF0ZSwgeydyZXNvdXJjZV9pZCc6IHJlc291cmNlX2lkfSwgdGhpcyApO1xyXG5cdFx0XHRcdFx0XHRcdCAgfSxcclxuXHRcdFx0XHRvbkNoYW5nZU1vbnRoWWVhcjogZnVuY3Rpb24gKCB5ZWFyLCByZWFsX21vbnRoLCBqc19kYXRlX18xc3RfZGF5X2luX21vbnRoICl7IH0sXHJcblx0XHRcdFx0c2hvd09uICAgICAgICA6ICdib3RoJyxcclxuXHRcdFx0XHRudW1iZXJPZk1vbnRoczogbG9jYWxfX251bWJlcl9vZl9tb250aHMsXHJcblx0XHRcdFx0c3RlcE1vbnRocyAgICA6IDEsXHJcblx0XHRcdFx0Ly8gcHJldlRleHQgICAgICA6ICcmbGFxdW87JyxcclxuXHRcdFx0XHQvLyBuZXh0VGV4dCAgICAgIDogJyZyYXF1bzsnLFxyXG5cdFx0XHRcdHByZXZUZXh0ICAgICAgOiAnJmxzYXF1bzsnLFxyXG5cdFx0XHRcdG5leHRUZXh0ICAgICAgOiAnJnJzYXF1bzsnLFxyXG5cdFx0XHRcdGRhdGVGb3JtYXQgICAgOiAnZGQubW0ueXknLFxyXG5cdFx0XHRcdGNoYW5nZU1vbnRoICAgOiBmYWxzZSxcclxuXHRcdFx0XHRjaGFuZ2VZZWFyICAgIDogZmFsc2UsXHJcblx0XHRcdFx0bWluRGF0ZSAgICAgICA6IGxvY2FsX19taW5fZGF0ZSxcclxuXHRcdFx0XHRtYXhEYXRlICAgICAgIDogbG9jYWxfX21heF9kYXRlLCBcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gJzFZJyxcclxuXHRcdFx0XHQvLyBtaW5EYXRlOiBuZXcgRGF0ZSgyMDIwLCAyLCAxKSwgbWF4RGF0ZTogbmV3IERhdGUoMjAyMCwgOSwgMzEpLCAgICAgICAgICAgICBcdC8vIEFiaWxpdHkgdG8gc2V0IGFueSAgc3RhcnQgYW5kIGVuZCBkYXRlIGluIGNhbGVuZGFyXHJcblx0XHRcdFx0c2hvd1N0YXR1cyAgICAgIDogZmFsc2UsXHJcblx0XHRcdFx0bXVsdGlTZXBhcmF0b3IgIDogJywgJyxcclxuXHRcdFx0XHRjbG9zZUF0VG9wICAgICAgOiBmYWxzZSxcclxuXHRcdFx0XHRmaXJzdERheSAgICAgICAgOiBsb2NhbF9fc3RhcnRfd2Vla2RheSxcclxuXHRcdFx0XHRnb3RvQ3VycmVudCAgICAgOiBmYWxzZSxcclxuXHRcdFx0XHRoaWRlSWZOb1ByZXZOZXh0OiB0cnVlLFxyXG5cdFx0XHRcdG11bHRpU2VsZWN0ICAgICA6IGxvY2FsX19tdWx0aV9kYXlzX3NlbGVjdF9udW0sXHJcblx0XHRcdFx0cmFuZ2VTZWxlY3QgICAgIDogbG9jYWxfX2lzX3JhbmdlX3NlbGVjdCxcclxuXHRcdFx0XHQvLyBzaG93V2Vla3M6IHRydWUsXHJcblx0XHRcdFx0dXNlVGhlbWVSb2xsZXI6IGZhbHNlXHJcblx0XHRcdH1cclxuXHQpO1xyXG5cclxuXHJcblxyXG5cdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0Ly8gQ2xlYXIgdG9kYXkgZGF0ZSBoaWdobGlnaHRpbmdcclxuXHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdHNldFRpbWVvdXQoIGZ1bmN0aW9uICgpeyAgd3BiY19jYWxlbmRhcnNfX2NsZWFyX2RheXNfaGlnaGxpZ2h0aW5nKCByZXNvdXJjZV9pZCApOyAgfSwgNTAwICk7ICAgICAgICAgICAgICAgICAgICBcdC8vIEZpeEluOiA3LjEuMi44LlxyXG5cclxuXHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdC8vIFNjcm9sbCBjYWxlbmRhciB0byAgc3BlY2lmaWMgbW9udGhcclxuXHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdHZhciBzdGFydF9ia19tb250aCA9IF93cGJjLmNhbGVuZGFyX19nZXRfcGFyYW1fdmFsdWUoIHJlc291cmNlX2lkLCAnY2FsZW5kYXJfc2Nyb2xsX3RvJyApO1xyXG5cdGlmICggZmFsc2UgIT09IHN0YXJ0X2JrX21vbnRoICl7XHJcblx0XHR3cGJjX2NhbGVuZGFyX19zY3JvbGxfdG8oIHJlc291cmNlX2lkLCBzdGFydF9ia19tb250aFsgMCBdLCBzdGFydF9ia19tb250aFsgMSBdICk7XHJcblx0fVxyXG5cdH1cclxuXHJcblxyXG5cdC8qKlxyXG5cdCAqIEdldCBib29raW5nIHN0YXR1c2VzIGFzIGFycmF5IGZyb20gdGhlIHN0cnVjdHVyZWQgc3VtbWFyeSBmaWVsZCwgd2l0aCBmYWxsYmFjayB0byB0aGUgbGVnYWN5IHN0cmluZyBmaWVsZC5cclxuXHQgKlxyXG5cdCAqIEBwYXJhbSBkYXRlX2Jvb2tpbmdzX29ialxyXG5cdCAqIEByZXR1cm5zIHtbXX1cclxuXHQgKi9cclxuXHRmdW5jdGlvbiB3cGJjX2dldF9ib29raW5nX3N0YXR1c2VzX19hc19hcnIoIGRhdGVfYm9va2luZ3Nfb2JqICl7XHJcblxyXG5cdFx0aWYgKFxyXG5cdFx0XHQgICAoICEgZGF0ZV9ib29raW5nc19vYmogKVxyXG5cdFx0XHR8fCAoICd1bmRlZmluZWQnID09PSB0eXBlb2YgKGRhdGVfYm9va2luZ3Nfb2JqWyAnc3VtbWFyeScgXSkgKVxyXG5cdFx0KXtcclxuXHRcdFx0cmV0dXJuIFtdO1xyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggQXJyYXkuaXNBcnJheSggZGF0ZV9ib29raW5nc19vYmpbICdzdW1tYXJ5JyBdWyAnc3RhdHVzX2Zvcl9ib29raW5nc19hcnInIF0gKSApe1xyXG5cdFx0XHRyZXR1cm4gZGF0ZV9ib29raW5nc19vYmpbICdzdW1tYXJ5JyBdWyAnc3RhdHVzX2Zvcl9ib29raW5nc19hcnInIF0uZmlsdGVyKCBmdW5jdGlvbiAoIGJvb2tpbmdfc3RhdHVzICl7XHJcblx0XHRcdFx0cmV0dXJuICcnICE9PSBib29raW5nX3N0YXR1cztcclxuXHRcdFx0fSApO1xyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggISBkYXRlX2Jvb2tpbmdzX29ialsgJ3N1bW1hcnknIF1bICdzdGF0dXNfZm9yX2Jvb2tpbmdzJyBdICl7XHJcblx0XHRcdHJldHVybiBbXTtcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gZGF0ZV9ib29raW5nc19vYmpbICdzdW1tYXJ5JyBdWyAnc3RhdHVzX2Zvcl9ib29raW5ncycgXS50b1N0cmluZygpLnRyaW0oKS5zcGxpdCggL1xccysvICkuZmlsdGVyKCBmdW5jdGlvbiAoIGJvb2tpbmdfc3RhdHVzICl7XHJcblx0XHRcdHJldHVybiAnJyAhPT0gYm9va2luZ19zdGF0dXM7XHJcblx0XHR9ICk7XHJcblx0fVxyXG5cclxuXHJcblx0LyoqXHJcblx0ICogQ2hlY2sgZXhhY3QgYm9va2luZyBzdGF0dXMgaW4gc3RhdHVzZXMgYXJyYXkuXHJcblx0ICpcclxuXHQgKiBAcGFyYW0ge1tdfSBib29raW5nX3N0YXR1c2VzX2FyclxyXG5cdCAqIEBwYXJhbSB7c3RyaW5nfSBib29raW5nX3N0YXR1c1xyXG5cdCAqIEByZXR1cm5zIHtib29sZWFufVxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdwYmNfYm9va2luZ19zdGF0dXNlc19faGFzKCBib29raW5nX3N0YXR1c2VzX2FyciwgYm9va2luZ19zdGF0dXMgKXtcclxuXHRcdHJldHVybiBib29raW5nX3N0YXR1c2VzX2Fyci5pbmRleE9mKCBib29raW5nX3N0YXR1cyApID4gLTE7XHJcblx0fVxyXG5cclxuXHJcblx0LyoqXHJcblx0ICogQ2hlY2sgYm9va2luZyBzdGF0dXMgcGFydCwgZS5nLiBcInBlbmRpbmdcIiBpbiBcImFwcHJvdmVkX3BlbmRpbmdcIi5cclxuXHQgKlxyXG5cdCAqIEBwYXJhbSB7W119IGJvb2tpbmdfc3RhdHVzZXNfYXJyXHJcblx0ICogQHBhcmFtIHtzdHJpbmd9IGJvb2tpbmdfc3RhdHVzX3BhcnRcclxuXHQgKiBAcmV0dXJucyB7Ym9vbGVhbn1cclxuXHQgKi9cclxuXHRmdW5jdGlvbiB3cGJjX2Jvb2tpbmdfc3RhdHVzZXNfX2hhc19wYXJ0KCBib29raW5nX3N0YXR1c2VzX2FyciwgYm9va2luZ19zdGF0dXNfcGFydCApe1xyXG5cclxuXHRcdGZvciAoIHZhciBpID0gMDsgaSA8IGJvb2tpbmdfc3RhdHVzZXNfYXJyLmxlbmd0aDsgaSsrICl7XHJcblx0XHRcdGlmICggYm9va2luZ19zdGF0dXNlc19hcnJbIGkgXS5zcGxpdCggJ18nICkuaW5kZXhPZiggYm9va2luZ19zdGF0dXNfcGFydCApID4gLTEgKXtcclxuXHRcdFx0XHRyZXR1cm4gdHJ1ZTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBmYWxzZTtcclxuXHR9XG5cblxuXHQvKipcblx0ICogQXBwbHkgb3B0aW9uYWwsIG9uZS13YXkgZGF0ZSBjb25zdHJhaW50cyB0byBhIG5hdGl2ZSBhdmFpbGFiaWxpdHkgcmVzdWx0LlxuXHQgKlxuXHQgKiBMaXN0ZW5lcnMgcmVjZWl2ZSBvbmx5IGEgbmV3IGNvbnN0cmFpbnQgb2JqZWN0LiBObyBib29raW5nLCBhdmFpbGFiaWxpdHksXG5cdCAqIHNlYXNvbiwgb3IgY2FsZW5kYXIgcGFyYW1ldGVyIG9iamVjdHMgYXJlIGV4cG9zZWQuIENvcmUgYXZhaWxhYmlsaXR5IHN0YXlzXG5cdCAqIGF1dGhvcml0YXRpdmUgYmVjYXVzZSB0aGUgcmV0dXJuZWQgc3RhdGUgY2FuIG9ubHkgY2hhbmdlIGZyb20gc2VsZWN0YWJsZSB0b1xuXHQgKiBibG9ja2VkOyBhIGxpc3RlbmVyIGNhbm5vdCByZW9wZW4gYSBuYXRpdmVseSB1bmF2YWlsYWJsZSBkYXRlLlxuXHQgKlxuXHQgKiBFdmVudDogd3BiY19jYWxlbmRhcl9fYXBwbHlfZGF0ZV9jb25zdHJhaW50c1xuXHQgKlxuXHQgKiBDb25zdHJhaW50IG9iamVjdDpcblx0ICoge1xuXHQgKiAgICAgcmVzb3VyY2VfaWQ6IHJlc291cmNlX2lkLFxuXHQgKiAgICAgc3FsX2RhdGU6IHNxbF9kYXRlLFxuXHQgKiAgICAgaXNfYmxvY2tlZDogZmFsc2UsXG5cdCAqICAgICBjc3NfY2xhc3NlczogW11cblx0ICogfVxuXHQgKlxuXHQgKiBMaXN0ZW5lcnMgbWF5IHNldCBpc19ibG9ja2VkIHRvIHRoZSBib29sZWFuIHRydWUgYW5kIGFwcGVuZCBpbmRpdmlkdWFsLFxuXHQgKiB2YWxpZCBDU1MgY2xhc3MgbmFtZXMgdG8gY3NzX2NsYXNzZXMuIENvcmUtb3duZWQgYXZhaWxhYmlsaXR5IGNsYXNzZXMgYXJlXG5cdCAqIGlnbm9yZWQgd2hlbiBzdXBwbGllZCBieSBsaXN0ZW5lcnMuXG5cdCAqXG5cdCAqIEBwYXJhbSB7bnVtYmVyfHN0cmluZ30gcmVzb3VyY2VfaWQgICAgICAgICAgIEJvb2tpbmcgcmVzb3VyY2UgSUQuXG5cdCAqIEBwYXJhbSB7c3RyaW5nfSAgICAgICAgc3FsX2RhdGUgICAgICAgICAgICAgIENhbGVuZGFyIGRhdGUgaW4gWVlZWS1NTS1ERCBmb3JtYXQuXG5cdCAqIEBwYXJhbSB7Ym9vbGVhbn0gICAgICAgaXNfbmF0aXZlbHlfc2VsZWN0YWJsZSBXaGV0aGVyIGNvcmUgbWFya2VkIHRoZSBkYXRlIHNlbGVjdGFibGUuXG5cdCAqIEBwYXJhbSB7c3RyaW5nW119ICAgICAgbmF0aXZlX2Nzc19jbGFzc2VzICAgIENvcmUtZ2VuZXJhdGVkIENTUyBjbGFzc2VzLlxuXHQgKiBAcmV0dXJucyB7e2lzX3NlbGVjdGFibGU6IGJvb2xlYW4sIGNzc19jbGFzc2VzOiBzdHJpbmdbXX19IENvbnN0cmFpbmVkIHJlc3VsdC5cblx0ICovXG5cdGZ1bmN0aW9uIHdwYmNfY2FsZW5kYXJfX2V2YWx1YXRlX2RhdGVfY29uc3RyYWludHMoIHJlc291cmNlX2lkLCBzcWxfZGF0ZSwgaXNfbmF0aXZlbHlfc2VsZWN0YWJsZSwgbmF0aXZlX2Nzc19jbGFzc2VzICkge1xuXG5cdFx0dmFyIGRhdGVfY29uc3RyYWludCA9IHtcblx0XHRcdCdyZXNvdXJjZV9pZCc6IHJlc291cmNlX2lkLFxuXHRcdFx0J3NxbF9kYXRlJzogc3FsX2RhdGUsXG5cdFx0XHQnaXNfYmxvY2tlZCc6IGZhbHNlLFxuXHRcdFx0J2Nzc19jbGFzc2VzJzogW11cblx0XHR9O1xuXHRcdHZhciByZXN1bHRfY3NzX2NsYXNzZXMgPSBBcnJheS5pc0FycmF5KCBuYXRpdmVfY3NzX2NsYXNzZXMgKSA/IG5hdGl2ZV9jc3NfY2xhc3Nlcy5zbGljZSggMCApIDogW107XG5cdFx0dmFyIGNvbnN0cmFpbnRfY2xhc3NfaW5kZXg7XG5cdFx0dmFyIGNvbnN0cmFpbnRfY3NzX2NsYXNzO1xuXG5cdFx0alF1ZXJ5KCAnYm9keScgKS50cmlnZ2VyKCAnd3BiY19jYWxlbmRhcl9fYXBwbHlfZGF0ZV9jb25zdHJhaW50cycsIFsgZGF0ZV9jb25zdHJhaW50IF0gKTtcblxuXHRcdGlmICggdHJ1ZSA9PT0gZGF0ZV9jb25zdHJhaW50LmlzX2Jsb2NrZWQgKSB7XG5cdFx0XHRmb3IgKCBjb25zdHJhaW50X2NsYXNzX2luZGV4ID0gcmVzdWx0X2Nzc19jbGFzc2VzLmxlbmd0aCAtIDE7IGNvbnN0cmFpbnRfY2xhc3NfaW5kZXggPj0gMDsgY29uc3RyYWludF9jbGFzc19pbmRleC0tICkge1xuXHRcdFx0XHRpZiAoICdkYXRlX2F2YWlsYWJsZScgPT09IHJlc3VsdF9jc3NfY2xhc3Nlc1sgY29uc3RyYWludF9jbGFzc19pbmRleCBdICkge1xuXHRcdFx0XHRcdHJlc3VsdF9jc3NfY2xhc3Nlcy5zcGxpY2UoIGNvbnN0cmFpbnRfY2xhc3NfaW5kZXgsIDEgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIC0xID09PSByZXN1bHRfY3NzX2NsYXNzZXMuaW5kZXhPZiggJ2RhdGVfdXNlcl91bmF2YWlsYWJsZScgKSApIHtcblx0XHRcdFx0cmVzdWx0X2Nzc19jbGFzc2VzLnB1c2goICdkYXRlX3VzZXJfdW5hdmFpbGFibGUnICk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0aWYgKCBBcnJheS5pc0FycmF5KCBkYXRlX2NvbnN0cmFpbnQuY3NzX2NsYXNzZXMgKSApIHtcblx0XHRcdGZvciAoIGNvbnN0cmFpbnRfY2xhc3NfaW5kZXggPSAwOyBjb25zdHJhaW50X2NsYXNzX2luZGV4IDwgZGF0ZV9jb25zdHJhaW50LmNzc19jbGFzc2VzLmxlbmd0aDsgY29uc3RyYWludF9jbGFzc19pbmRleCsrICkge1xuXHRcdFx0XHRpZiAoICdzdHJpbmcnICE9PSB0eXBlb2YgZGF0ZV9jb25zdHJhaW50LmNzc19jbGFzc2VzWyBjb25zdHJhaW50X2NsYXNzX2luZGV4IF0gKSB7XG5cdFx0XHRcdFx0Y29udGludWU7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRjb25zdHJhaW50X2Nzc19jbGFzcyA9IGRhdGVfY29uc3RyYWludC5jc3NfY2xhc3Nlc1sgY29uc3RyYWludF9jbGFzc19pbmRleCBdLnRyaW0oKTtcblx0XHRcdFx0aWYgKFxuXHRcdFx0XHRcdCAgICcnID09PSBjb25zdHJhaW50X2Nzc19jbGFzc1xuXHRcdFx0XHRcdHx8ICdkYXRlX2F2YWlsYWJsZScgPT09IGNvbnN0cmFpbnRfY3NzX2NsYXNzXG5cdFx0XHRcdFx0fHwgJ2RhdGVfdXNlcl91bmF2YWlsYWJsZScgPT09IGNvbnN0cmFpbnRfY3NzX2NsYXNzXG5cdFx0XHRcdFx0fHwgISAvXi0/W19hLXpBLVpdK1tfYS16QS1aMC05LV0qJC8udGVzdCggY29uc3RyYWludF9jc3NfY2xhc3MgKVxuXHRcdFx0XHQpIHtcblx0XHRcdFx0XHRjb250aW51ZTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICggLTEgPT09IHJlc3VsdF9jc3NfY2xhc3Nlcy5pbmRleE9mKCBjb25zdHJhaW50X2Nzc19jbGFzcyApICkge1xuXHRcdFx0XHRcdHJlc3VsdF9jc3NfY2xhc3Nlcy5wdXNoKCBjb25zdHJhaW50X2Nzc19jbGFzcyApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHtcblx0XHRcdCdpc19zZWxlY3RhYmxlJzogQm9vbGVhbiggaXNfbmF0aXZlbHlfc2VsZWN0YWJsZSApICYmIHRydWUgIT09IGRhdGVfY29uc3RyYWludC5pc19ibG9ja2VkLFxuXHRcdFx0J2Nzc19jbGFzc2VzJzogcmVzdWx0X2Nzc19jbGFzc2VzXG5cdFx0fTtcblx0fVxuXG5cblx0LyoqXG5cdCAqIEFwcGx5IENTUyB0byBjYWxlbmRhciBkYXRlIGNlbGxzXG5cdCAqXHJcblx0ICogQHBhcmFtIGRhdGVcdFx0XHRcdFx0XHRcdFx0XHRcdC0gIEphdmFTY3JpcHQgRGF0ZSBPYmo6ICBcdFx0TW9uIERlYyAxMSAyMDIzIDAwOjAwOjAwXHJcblx0ICogICAgIEdNVCswMjAwIChFYXN0ZXJuIEV1cm9wZWFuIFN0YW5kYXJkIFRpbWUpXHJcblx0ICogQHBhcmFtIGNhbGVuZGFyX3BhcmFtc19hcnJcdFx0XHRcdFx0XHQtICBDYWxlbmRhciBTZXR0aW5ncyBPYmplY3Q6ICBcdHtcclxuXHQgKlx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0ICBcdFx0XHRcdFx0XHRcInJlc291cmNlX2lkXCI6IDRcclxuXHQgKlx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdH1cclxuXHQgKiBAcGFyYW0gZGF0ZXBpY2tfdGhpc1x0XHRcdFx0XHRcdFx0XHQtIHRoaXMgb2YgZGF0ZXBpY2sgT2JqXHJcblx0ICogQHJldHVybnMgeygqfHN0cmluZylbXXwoYm9vbGVhbnxzdHJpbmcpW119XHRcdC0gWyB7dHJ1ZSAtYXZhaWxhYmxlIHwgZmFsc2UgLSB1bmF2YWlsYWJsZX0sICdDU1MgY2xhc3NlcyBmb3JcclxuXHQgKiAgICAgY2FsZW5kYXIgZGF5IGNlbGwnIF1cclxuXHQgKi9cclxuXHRmdW5jdGlvbiB3cGJjX19jYWxlbmRhcl9fYXBwbHlfY3NzX3RvX2RheXMoIGRhdGUsIGNhbGVuZGFyX3BhcmFtc19hcnIsIGRhdGVwaWNrX3RoaXMgKXtcclxuXHJcblx0XHR2YXIgdG9kYXlfZGF0ZSA9IG5ldyBEYXRlKCBfd3BiYy5nZXRfb3RoZXJfcGFyYW0oICd0b2RheV9hcnInIClbIDAgXSwgKHBhcnNlSW50KCBfd3BiYy5nZXRfb3RoZXJfcGFyYW0oICd0b2RheV9hcnInIClbIDEgXSApIC0gMSksIF93cGJjLmdldF9vdGhlcl9wYXJhbSggJ3RvZGF5X2FycicgKVsgMiBdLCAwLCAwLCAwICk7XHRcdFx0XHRcdFx0XHRcdC8vIFRvZGF5IEpTX0RhdGVfT2JqLlxyXG5cdFx0dmFyIGNsYXNzX2RheSAgICAgPSB3cGJjX19nZXRfX3RkX2NsYXNzX2RhdGUoIGRhdGUgKTtcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQvLyAnMS05LTIwMjMnXHJcblx0XHR2YXIgc3FsX2NsYXNzX2RheSA9IHdwYmNfX2dldF9fc3FsX2NsYXNzX2RhdGUoIGRhdGUgKTtcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQvLyAnMjAyMy0wMS0wOSdcclxuXHRcdHZhciByZXNvdXJjZV9pZCA9ICggJ3VuZGVmaW5lZCcgIT09IHR5cGVvZihjYWxlbmRhcl9wYXJhbXNfYXJyWyAncmVzb3VyY2VfaWQnIF0pICkgPyBjYWxlbmRhcl9wYXJhbXNfYXJyWyAncmVzb3VyY2VfaWQnIF0gOiAnMSc7IFx0XHQvLyAnMSdcclxuXHJcblx0XHQvLyBHZXQgU2VsZWN0ZWQgZGF0ZXMgaW4gY2FsZW5kYXJcclxuXHRcdHZhciBzZWxlY3RlZF9kYXRlc19zcWwgPSB3cGJjX2dldF9fc2VsZWN0ZWRfZGF0ZXNfc3FsX19hc19hcnIoIHJlc291cmNlX2lkICk7XHJcblxyXG5cdFx0Ly8gR2V0IERhdGEgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdHZhciBkYXRlX2Jvb2tpbmdzX29iaiA9IF93cGJjLmJvb2tpbmdzX2luX2NhbGVuZGFyX19nZXRfZm9yX2RhdGUoIHJlc291cmNlX2lkLCBzcWxfY2xhc3NfZGF5ICk7XHJcblxyXG5cclxuXHRcdC8vIEFycmF5IHdpdGggQ1NTIGNsYXNzZXMgZm9yIGRhdGUgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHR2YXIgY3NzX2NsYXNzZXNfX2Zvcl9kYXRlID0gW107XHJcblx0XHRjc3NfY2xhc3Nlc19fZm9yX2RhdGUucHVzaCggJ3NxbF9kYXRlXycgICAgICsgc3FsX2NsYXNzX2RheSApO1x0XHRcdFx0Ly8gICdzcWxfZGF0ZV8yMDIzLTA3LTIxJ1xyXG5cdFx0Y3NzX2NsYXNzZXNfX2Zvcl9kYXRlLnB1c2goICdjYWw0ZGF0ZS0nICAgICArIGNsYXNzX2RheSApO1x0XHRcdFx0XHQvLyAgJ2NhbDRkYXRlLTctMjEtMjAyMydcclxuXHRcdGNzc19jbGFzc2VzX19mb3JfZGF0ZS5wdXNoKCAnd3BiY193ZWVrZGF5XycgKyBkYXRlLmdldERheSgpICk7XHRcdFx0XHQvLyAgJ3dwYmNfd2Vla2RheV80J1xyXG5cclxuXHRcdC8vIERlZmluZSBTZWxlY3RlZCBDaGVjayBJbi9PdXQgZGF0ZXMgaW4gVEQgIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHRpZiAoXHJcblx0XHRcdFx0KCBzZWxlY3RlZF9kYXRlc19zcWwubGVuZ3RoICApXHJcblx0XHRcdC8vJiYgICggc2VsZWN0ZWRfZGF0ZXNfc3FsWyAwIF0gIT09IHNlbGVjdGVkX2RhdGVzX3NxbFsgKHNlbGVjdGVkX2RhdGVzX3NxbC5sZW5ndGggLSAxKSBdIClcclxuXHRcdCl7XHJcblx0XHRcdGlmICggc3FsX2NsYXNzX2RheSA9PT0gc2VsZWN0ZWRfZGF0ZXNfc3FsWyAwIF0gKXtcclxuXHRcdFx0XHRjc3NfY2xhc3Nlc19fZm9yX2RhdGUucHVzaCggJ3NlbGVjdGVkX2NoZWNrX2luJyApO1xyXG5cdFx0XHRcdGNzc19jbGFzc2VzX19mb3JfZGF0ZS5wdXNoKCAnc2VsZWN0ZWRfY2hlY2tfaW5fb3V0JyApO1xyXG5cdFx0XHR9XHJcblx0XHRcdGlmICggICggc2VsZWN0ZWRfZGF0ZXNfc3FsLmxlbmd0aCA+IDEgKSAmJiAoIHNxbF9jbGFzc19kYXkgPT09IHNlbGVjdGVkX2RhdGVzX3NxbFsgKHNlbGVjdGVkX2RhdGVzX3NxbC5sZW5ndGggLSAxKSBdICkgKSB7XHJcblx0XHRcdFx0Y3NzX2NsYXNzZXNfX2Zvcl9kYXRlLnB1c2goICdzZWxlY3RlZF9jaGVja19vdXQnICk7XHJcblx0XHRcdFx0Y3NzX2NsYXNzZXNfX2Zvcl9kYXRlLnB1c2goICdzZWxlY3RlZF9jaGVja19pbl9vdXQnICk7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblxyXG5cdFx0dmFyIGlzX2RheV9zZWxlY3RhYmxlICAgICA9IGZhbHNlO1xuXHRcdHZhciBkYXRlX2NvbnN0cmFpbnRfcmVzdWx0O1xuXHJcblx0XHQvLyBJZiBzb21ldGhpbmcgbm90IGRlZmluZWQsICB0aGVuICB0aGlzIGRhdGUgY2xvc2VkIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAvLyBGaXhJbjogMTAuMTIuNC42LlxyXG5cdFx0aWYgKCAoZmFsc2UgPT09IGRhdGVfYm9va2luZ3Nfb2JqKSB8fCAoJ3VuZGVmaW5lZCcgPT09IHR5cGVvZiAoZGF0ZV9ib29raW5nc19vYmpbcmVzb3VyY2VfaWRdKSkgKSB7XG5cblx0XHRcdGNzc19jbGFzc2VzX19mb3JfZGF0ZS5wdXNoKCAnZGF0ZV91c2VyX3VuYXZhaWxhYmxlJyApO1xuXHRcdFx0ZGF0ZV9jb25zdHJhaW50X3Jlc3VsdCA9IHdwYmNfY2FsZW5kYXJfX2V2YWx1YXRlX2RhdGVfY29uc3RyYWludHMoIHJlc291cmNlX2lkLCBzcWxfY2xhc3NfZGF5LCBpc19kYXlfc2VsZWN0YWJsZSwgY3NzX2NsYXNzZXNfX2Zvcl9kYXRlICk7XG5cblx0XHRcdHJldHVybiBbIGRhdGVfY29uc3RyYWludF9yZXN1bHQuaXNfc2VsZWN0YWJsZSwgZGF0ZV9jb25zdHJhaW50X3Jlc3VsdC5jc3NfY2xhc3Nlcy5qb2luKCAnICcgKSBdO1xuXHRcdH1cclxuXHJcblxyXG5cdFx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdC8vICAgZGF0ZV9ib29raW5nc19vYmogIC0gRGVmaW5lZC4gICAgICAgICAgICBEYXRlcyBjYW4gYmUgc2VsZWN0YWJsZS5cclxuXHRcdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHR2YXIgYm9va2luZ19zdGF0dXNlc19hcnIgPSB3cGJjX2dldF9ib29raW5nX3N0YXR1c2VzX19hc19hcnIoIGRhdGVfYm9va2luZ3Nfb2JqICk7XHJcblxyXG5cdFx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdC8vIEFkZCBzZWFzb24gbmFtZXMgdG8gdGhlIGRheSBDU1MgY2xhc3NlcyAtLSBpdCBpcyByZXF1aXJlZCBmb3IgY29ycmVjdCAgd29yayAgb2YgY29uZGl0aW9uYWwgZmllbGRzIC0tLS0tLS0tLS0tLS0tXHJcblx0XHR2YXIgc2Vhc29uX25hbWVzX2FyciA9IF93cGJjLnNlYXNvbnNfX2dldF9mb3JfZGF0ZSggcmVzb3VyY2VfaWQsIHNxbF9jbGFzc19kYXkgKTtcclxuXHJcblx0XHRmb3IgKCB2YXIgc2Vhc29uX2tleSBpbiBzZWFzb25fbmFtZXNfYXJyICl7XHJcblxyXG5cdFx0XHRjc3NfY2xhc3Nlc19fZm9yX2RhdGUucHVzaCggc2Vhc29uX25hbWVzX2Fyclsgc2Vhc29uX2tleSBdICk7XHRcdFx0XHQvLyAgJ3dwZGV2Ymtfc2Vhc29uX3NlcHRlbWJlcl8yMDIzJ1xyXG5cdFx0fVxyXG5cdFx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHJcblxyXG5cdFx0Ly8gQ29zdCBSYXRlIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdGNzc19jbGFzc2VzX19mb3JfZGF0ZS5wdXNoKCAncmF0ZV8nICsgZGF0ZV9ib29raW5nc19vYmpbIHJlc291cmNlX2lkIF1bICdkYXRlX2Nvc3RfcmF0ZScgXS50b1N0cmluZygpLnJlcGxhY2UoIC9bXFwuXFxzXS9nLCAnXycgKSApO1x0XHRcdFx0XHRcdC8vICAncmF0ZV85OV8wMCcgLT4gOTkuMDBcclxuXHJcblxyXG5cdFx0aWYgKCBwYXJzZUludCggZGF0ZV9ib29raW5nc19vYmpbICdkYXlfYXZhaWxhYmlsaXR5JyBdICkgPiAwICl7XHJcblx0XHRcdGlzX2RheV9zZWxlY3RhYmxlID0gdHJ1ZTtcclxuXHRcdFx0Y3NzX2NsYXNzZXNfX2Zvcl9kYXRlLnB1c2goICdkYXRlX2F2YWlsYWJsZScgKTtcclxuXHRcdFx0Y3NzX2NsYXNzZXNfX2Zvcl9kYXRlLnB1c2goICdyZXNlcnZlZF9kYXlzX2NvdW50JyArIHBhcnNlSW50KCBkYXRlX2Jvb2tpbmdzX29ialsgJ21heF9jYXBhY2l0eScgXSAtIGRhdGVfYm9va2luZ3Nfb2JqWyAnZGF5X2F2YWlsYWJpbGl0eScgXSApICk7XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHRpc19kYXlfc2VsZWN0YWJsZSA9IGZhbHNlO1xyXG5cdFx0XHRjc3NfY2xhc3Nlc19fZm9yX2RhdGUucHVzaCggJ2RhdGVfdXNlcl91bmF2YWlsYWJsZScgKTtcclxuXHRcdH1cclxuXHJcblxyXG5cdFx0c3dpdGNoICggZGF0ZV9ib29raW5nc19vYmpbICdzdW1tYXJ5J11bJ3N0YXR1c19mb3JfZGF5JyBdICl7XHJcblxyXG5cdFx0XHRjYXNlICdhdmFpbGFibGUnOlxyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0Y2FzZSAndGltZV9zbG90c19ib29raW5nJzpcclxuXHRcdFx0XHRjc3NfY2xhc3Nlc19fZm9yX2RhdGUucHVzaCggJ3RpbWVzcGFydGx5JywgJ3RpbWVzX2Nsb2NrJyApO1xyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0Y2FzZSAnZnVsbF9kYXlfYm9va2luZyc6XHJcblx0XHRcdFx0Y3NzX2NsYXNzZXNfX2Zvcl9kYXRlLnB1c2goICdmdWxsX2RheV9ib29raW5nJyApO1xyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0Y2FzZSAnc2Vhc29uX2ZpbHRlcic6XHJcblx0XHRcdFx0Y3NzX2NsYXNzZXNfX2Zvcl9kYXRlLnB1c2goICdkYXRlX3VzZXJfdW5hdmFpbGFibGUnLCAnc2Vhc29uX3VuYXZhaWxhYmxlJyApO1xyXG5cdFx0XHRcdGRhdGVfYm9va2luZ3Nfb2JqWyAnc3VtbWFyeSddWydzdGF0dXNfZm9yX2Jvb2tpbmdzJyBdID0gJyc7XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vIFJlc2V0IGJvb2tpbmcgc3RhdHVzIGNvbG9yIGZvciBwb3NzaWJsZSBvbGQgYm9va2luZ3Mgb24gdGhpcyBkYXRlXHJcblx0XHRcdFx0ZGF0ZV9ib29raW5nc19vYmpbICdzdW1tYXJ5J11bJ3N0YXR1c19mb3JfYm9va2luZ3NfYXJyJyBdID0gW107XHJcblx0XHRcdFx0Ym9va2luZ19zdGF0dXNlc19hcnIgPSBbXTtcclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgJ3Jlc291cmNlX2F2YWlsYWJpbGl0eSc6XHJcblx0XHRcdFx0Y3NzX2NsYXNzZXNfX2Zvcl9kYXRlLnB1c2goICdkYXRlX3VzZXJfdW5hdmFpbGFibGUnLCAncmVzb3VyY2VfdW5hdmFpbGFibGUnICk7XHJcblx0XHRcdFx0ZGF0ZV9ib29raW5nc19vYmpbICdzdW1tYXJ5J11bJ3N0YXR1c19mb3JfYm9va2luZ3MnIF0gPSAnJztcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gUmVzZXQgYm9va2luZyBzdGF0dXMgY29sb3IgZm9yIHBvc3NpYmxlIG9sZCBib29raW5ncyBvbiB0aGlzIGRhdGVcclxuXHRcdFx0XHRkYXRlX2Jvb2tpbmdzX29ialsgJ3N1bW1hcnknXVsnc3RhdHVzX2Zvcl9ib29raW5nc19hcnInIF0gPSBbXTtcclxuXHRcdFx0XHRib29raW5nX3N0YXR1c2VzX2FyciA9IFtdO1xyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0Y2FzZSAnd2Vla2RheV91bmF2YWlsYWJsZSc6XHJcblx0XHRcdFx0Y3NzX2NsYXNzZXNfX2Zvcl9kYXRlLnB1c2goICdkYXRlX3VzZXJfdW5hdmFpbGFibGUnLCAnd2Vla2RheV91bmF2YWlsYWJsZScgKTtcclxuXHRcdFx0XHRkYXRlX2Jvb2tpbmdzX29ialsgJ3N1bW1hcnknXVsnc3RhdHVzX2Zvcl9ib29raW5ncycgXSA9ICcnO1x0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQvLyBSZXNldCBib29raW5nIHN0YXR1cyBjb2xvciBmb3IgcG9zc2libGUgb2xkIGJvb2tpbmdzIG9uIHRoaXMgZGF0ZVxyXG5cdFx0XHRcdGRhdGVfYm9va2luZ3Nfb2JqWyAnc3VtbWFyeSddWydzdGF0dXNfZm9yX2Jvb2tpbmdzX2FycicgXSA9IFtdO1xyXG5cdFx0XHRcdGJvb2tpbmdfc3RhdHVzZXNfYXJyID0gW107XHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdmcm9tX3RvZGF5X3VuYXZhaWxhYmxlJzpcclxuXHRcdFx0XHRjc3NfY2xhc3Nlc19fZm9yX2RhdGUucHVzaCggJ2RhdGVfdXNlcl91bmF2YWlsYWJsZScsICdmcm9tX3RvZGF5X3VuYXZhaWxhYmxlJyApO1xyXG5cdFx0XHRcdGRhdGVfYm9va2luZ3Nfb2JqWyAnc3VtbWFyeSddWydzdGF0dXNfZm9yX2Jvb2tpbmdzJyBdID0gJyc7XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vIFJlc2V0IGJvb2tpbmcgc3RhdHVzIGNvbG9yIGZvciBwb3NzaWJsZSBvbGQgYm9va2luZ3Mgb24gdGhpcyBkYXRlXHJcblx0XHRcdFx0ZGF0ZV9ib29raW5nc19vYmpbICdzdW1tYXJ5J11bJ3N0YXR1c19mb3JfYm9va2luZ3NfYXJyJyBdID0gW107XHJcblx0XHRcdFx0Ym9va2luZ19zdGF0dXNlc19hcnIgPSBbXTtcclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgJ2xpbWl0X2F2YWlsYWJsZV9mcm9tX3RvZGF5JzpcclxuXHRcdFx0XHRjc3NfY2xhc3Nlc19fZm9yX2RhdGUucHVzaCggJ2RhdGVfdXNlcl91bmF2YWlsYWJsZScsICdsaW1pdF9hdmFpbGFibGVfZnJvbV90b2RheScgKTtcclxuXHRcdFx0XHRkYXRlX2Jvb2tpbmdzX29ialsgJ3N1bW1hcnknXVsnc3RhdHVzX2Zvcl9ib29raW5ncycgXSA9ICcnO1x0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQvLyBSZXNldCBib29raW5nIHN0YXR1cyBjb2xvciBmb3IgcG9zc2libGUgb2xkIGJvb2tpbmdzIG9uIHRoaXMgZGF0ZVxyXG5cdFx0XHRcdGRhdGVfYm9va2luZ3Nfb2JqWyAnc3VtbWFyeSddWydzdGF0dXNfZm9yX2Jvb2tpbmdzX2FycicgXSA9IFtdO1xyXG5cdFx0XHRcdGJvb2tpbmdfc3RhdHVzZXNfYXJyID0gW107XHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdjaGFuZ2Vfb3Zlcic6XHJcblx0XHRcdFx0LypcclxuXHRcdFx0XHQgKlxyXG5cdFx0XHRcdC8vICBjaGVja19vdXRfdGltZV9kYXRlMmFwcHJvdmUgXHQgXHRjaGVja19pbl90aW1lX2RhdGUyYXBwcm92ZVxyXG5cdFx0XHRcdC8vICBjaGVja19vdXRfdGltZV9kYXRlMmFwcHJvdmUgXHQgXHRjaGVja19pbl90aW1lX2RhdGVfYXBwcm92ZWRcclxuXHRcdFx0XHQvLyAgY2hlY2tfaW5fdGltZV9kYXRlMmFwcHJvdmUgXHRcdCBcdGNoZWNrX291dF90aW1lX2RhdGVfYXBwcm92ZWRcclxuXHRcdFx0XHQvLyAgY2hlY2tfb3V0X3RpbWVfZGF0ZV9hcHByb3ZlZCBcdCBcdGNoZWNrX2luX3RpbWVfZGF0ZV9hcHByb3ZlZFxyXG5cdFx0XHRcdCAqL1xyXG5cclxuXHRcdFx0XHRjc3NfY2xhc3Nlc19fZm9yX2RhdGUucHVzaCggJ3RpbWVzcGFydGx5JywgJ2NoZWNrX2luX3RpbWUnLCAnY2hlY2tfb3V0X3RpbWUnICk7XHJcblx0XHRcdFx0Ly8gRml4SW46IDEwLjAuMC4yLlxyXG5cdFx0XHRcdGlmICggd3BiY19ib29raW5nX3N0YXR1c2VzX19oYXMoIGJvb2tpbmdfc3RhdHVzZXNfYXJyLCAnYXBwcm92ZWRfcGVuZGluZycgKSApe1xyXG5cdFx0XHRcdFx0Y3NzX2NsYXNzZXNfX2Zvcl9kYXRlLnB1c2goICdjaGVja19vdXRfdGltZV9kYXRlX2FwcHJvdmVkJywgJ2NoZWNrX2luX3RpbWVfZGF0ZTJhcHByb3ZlJyApO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0XHRpZiAoIHdwYmNfYm9va2luZ19zdGF0dXNlc19faGFzKCBib29raW5nX3N0YXR1c2VzX2FyciwgJ3BlbmRpbmdfYXBwcm92ZWQnICkgKXtcclxuXHRcdFx0XHRcdGNzc19jbGFzc2VzX19mb3JfZGF0ZS5wdXNoKCAnY2hlY2tfb3V0X3RpbWVfZGF0ZTJhcHByb3ZlJywgJ2NoZWNrX2luX3RpbWVfZGF0ZV9hcHByb3ZlZCcgKTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdjaGVja19pbic6XHJcblx0XHRcdFx0Y3NzX2NsYXNzZXNfX2Zvcl9kYXRlLnB1c2goICd0aW1lc3BhcnRseScsICdjaGVja19pbl90aW1lJyApO1xyXG5cclxuXHRcdFx0XHQvLyBGaXhJbjogOS45LjAuMzMuXHJcblx0XHRcdFx0aWYgKCB3cGJjX2Jvb2tpbmdfc3RhdHVzZXNfX2hhc19wYXJ0KCBib29raW5nX3N0YXR1c2VzX2FyciwgJ3BlbmRpbmcnICkgKXtcclxuXHRcdFx0XHRcdGNzc19jbGFzc2VzX19mb3JfZGF0ZS5wdXNoKCAnY2hlY2tfaW5fdGltZV9kYXRlMmFwcHJvdmUnICk7XHJcblx0XHRcdFx0fSBlbHNlIGlmICggd3BiY19ib29raW5nX3N0YXR1c2VzX19oYXNfcGFydCggYm9va2luZ19zdGF0dXNlc19hcnIsICdhcHByb3ZlZCcgKSApe1xyXG5cdFx0XHRcdFx0Y3NzX2NsYXNzZXNfX2Zvcl9kYXRlLnB1c2goICdjaGVja19pbl90aW1lX2RhdGVfYXBwcm92ZWQnICk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0Y2FzZSAnY2hlY2tfb3V0JzpcclxuXHRcdFx0XHRjc3NfY2xhc3Nlc19fZm9yX2RhdGUucHVzaCggJ3RpbWVzcGFydGx5JywgJ2NoZWNrX291dF90aW1lJyApO1xyXG5cclxuXHRcdFx0XHQvLyBGaXhJbjogOS45LjAuMzMuXHJcblx0XHRcdFx0aWYgKCB3cGJjX2Jvb2tpbmdfc3RhdHVzZXNfX2hhc19wYXJ0KCBib29raW5nX3N0YXR1c2VzX2FyciwgJ3BlbmRpbmcnICkgKXtcclxuXHRcdFx0XHRcdGNzc19jbGFzc2VzX19mb3JfZGF0ZS5wdXNoKCAnY2hlY2tfb3V0X3RpbWVfZGF0ZTJhcHByb3ZlJyApO1xyXG5cdFx0XHRcdH0gZWxzZSBpZiAoIHdwYmNfYm9va2luZ19zdGF0dXNlc19faGFzX3BhcnQoIGJvb2tpbmdfc3RhdHVzZXNfYXJyLCAnYXBwcm92ZWQnICkgKXtcclxuXHRcdFx0XHRcdGNzc19jbGFzc2VzX19mb3JfZGF0ZS5wdXNoKCAnY2hlY2tfb3V0X3RpbWVfZGF0ZV9hcHByb3ZlZCcgKTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRkZWZhdWx0OlxyXG5cdFx0XHRcdC8vIG1peGVkIHN0YXR1c2VzOiAnY2hhbmdlX292ZXIgY2hlY2tfb3V0JyAuLi4uIHZhcmlhdGlvbnMuLi4uIGNoZWNrIG1vcmUgaW4gXHRcdGZ1bmN0aW9uIHdwYmNfZ2V0X2F2YWlsYWJpbGl0eV9wZXJfZGF5c19hcnIoKVxyXG5cdFx0XHRcdGRhdGVfYm9va2luZ3Nfb2JqWyAnc3VtbWFyeSddWydzdGF0dXNfZm9yX2RheScgXSA9ICdhdmFpbGFibGUnO1xyXG5cdFx0fVxyXG5cclxuXHJcblxyXG5cdFx0aWYgKCAnYXZhaWxhYmxlJyAhPSBkYXRlX2Jvb2tpbmdzX29ialsgJ3N1bW1hcnknXVsnc3RhdHVzX2Zvcl9kYXknIF0gKXtcclxuXHJcblx0XHRcdHZhciBpc19zZXRfcGVuZGluZ19kYXlzX3NlbGVjdGFibGUgPSBfd3BiYy5jYWxlbmRhcl9fZ2V0X3BhcmFtX3ZhbHVlKCByZXNvdXJjZV9pZCwgJ3BlbmRpbmdfZGF5c19zZWxlY3RhYmxlJyApO1x0Ly8gc2V0IHBlbmRpbmcgZGF5cyBzZWxlY3RhYmxlICAgICAgICAgIC8vIEZpeEluOiA4LjYuMS4xOC5cclxuXHJcblx0XHRcdGlmICggd3BiY19ib29raW5nX3N0YXR1c2VzX19oYXMoIGJvb2tpbmdfc3RhdHVzZXNfYXJyLCAncGVuZGluZycgKSApe1xyXG5cdFx0XHRcdGNzc19jbGFzc2VzX19mb3JfZGF0ZS5wdXNoKCAnZGF0ZTJhcHByb3ZlJyApO1xyXG5cdFx0XHRcdGlzX2RheV9zZWxlY3RhYmxlID0gKGlzX2RheV9zZWxlY3RhYmxlKSA/IHRydWUgOiBpc19zZXRfcGVuZGluZ19kYXlzX3NlbGVjdGFibGU7XHJcblx0XHRcdH1cclxuXHRcdFx0aWYgKCB3cGJjX2Jvb2tpbmdfc3RhdHVzZXNfX2hhcyggYm9va2luZ19zdGF0dXNlc19hcnIsICdhcHByb3ZlZCcgKSApe1xyXG5cdFx0XHRcdGNzc19jbGFzc2VzX19mb3JfZGF0ZS5wdXNoKCAnZGF0ZV9hcHByb3ZlZCcgKTtcclxuXHRcdFx0fVxyXG5cdFx0XHRpZiAoIHdwYmNfYm9va2luZ19zdGF0dXNlc19faGFzKCBib29raW5nX3N0YXR1c2VzX2FyciwgJ3BlbmRpbmdfcGVuZGluZycgKSApe1xyXG5cdFx0XHRcdGNzc19jbGFzc2VzX19mb3JfZGF0ZS5wdXNoKCAnY2hlY2tfb3V0X3RpbWVfZGF0ZTJhcHByb3ZlJywgJ2NoZWNrX2luX3RpbWVfZGF0ZTJhcHByb3ZlJyApO1xyXG5cdFx0XHRcdGlzX2RheV9zZWxlY3RhYmxlID0gKGlzX2RheV9zZWxlY3RhYmxlKSA/IHRydWUgOiBpc19zZXRfcGVuZGluZ19kYXlzX3NlbGVjdGFibGU7XHJcblx0XHRcdH1cclxuXHRcdFx0aWYgKCB3cGJjX2Jvb2tpbmdfc3RhdHVzZXNfX2hhcyggYm9va2luZ19zdGF0dXNlc19hcnIsICdwZW5kaW5nX2FwcHJvdmVkJyApICl7XHJcblx0XHRcdFx0Y3NzX2NsYXNzZXNfX2Zvcl9kYXRlLnB1c2goICdjaGVja19vdXRfdGltZV9kYXRlMmFwcHJvdmUnLCAnY2hlY2tfaW5fdGltZV9kYXRlX2FwcHJvdmVkJyApO1xyXG5cdFx0XHRcdGlzX2RheV9zZWxlY3RhYmxlID0gKGlzX2RheV9zZWxlY3RhYmxlKSA/IHRydWUgOiBpc19zZXRfcGVuZGluZ19kYXlzX3NlbGVjdGFibGU7XHJcblx0XHRcdH1cclxuXHRcdFx0aWYgKCB3cGJjX2Jvb2tpbmdfc3RhdHVzZXNfX2hhcyggYm9va2luZ19zdGF0dXNlc19hcnIsICdhcHByb3ZlZF9wZW5kaW5nJyApICl7XHJcblx0XHRcdFx0Y3NzX2NsYXNzZXNfX2Zvcl9kYXRlLnB1c2goICdjaGVja19vdXRfdGltZV9kYXRlX2FwcHJvdmVkJywgJ2NoZWNrX2luX3RpbWVfZGF0ZTJhcHByb3ZlJyApO1xyXG5cdFx0XHRcdGlzX2RheV9zZWxlY3RhYmxlID0gKGlzX2RheV9zZWxlY3RhYmxlKSA/IHRydWUgOiBpc19zZXRfcGVuZGluZ19kYXlzX3NlbGVjdGFibGU7XHJcblx0XHRcdH1cclxuXHRcdFx0aWYgKCB3cGJjX2Jvb2tpbmdfc3RhdHVzZXNfX2hhcyggYm9va2luZ19zdGF0dXNlc19hcnIsICdhcHByb3ZlZF9hcHByb3ZlZCcgKSApe1xyXG5cdFx0XHRcdGNzc19jbGFzc2VzX19mb3JfZGF0ZS5wdXNoKCAnY2hlY2tfb3V0X3RpbWVfZGF0ZV9hcHByb3ZlZCcsICdjaGVja19pbl90aW1lX2RhdGVfYXBwcm92ZWQnICk7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHRkYXRlX2NvbnN0cmFpbnRfcmVzdWx0ID0gd3BiY19jYWxlbmRhcl9fZXZhbHVhdGVfZGF0ZV9jb25zdHJhaW50cyggcmVzb3VyY2VfaWQsIHNxbF9jbGFzc19kYXksIGlzX2RheV9zZWxlY3RhYmxlLCBjc3NfY2xhc3Nlc19fZm9yX2RhdGUgKTtcblxuXHRcdHJldHVybiBbIGRhdGVfY29uc3RyYWludF9yZXN1bHQuaXNfc2VsZWN0YWJsZSwgZGF0ZV9jb25zdHJhaW50X3Jlc3VsdC5jc3NfY2xhc3Nlcy5qb2luKCAnICcgKSBdO1xuXHR9XHJcblxyXG5cclxuXHQvKipcclxuXHQgKiBNb3VzZW92ZXIgY2FsZW5kYXIgZGF0ZSBjZWxsc1xyXG5cdCAqXHJcblx0ICogQHBhcmFtIHN0cmluZ19kYXRlXHJcblx0ICogQHBhcmFtIGRhdGVcdFx0XHRcdFx0XHRcdFx0XHRcdC0gIEphdmFTY3JpcHQgRGF0ZSBPYmo6ICBcdFx0TW9uIERlYyAxMSAyMDIzIDAwOjAwOjAwXHJcblx0ICogICAgIEdNVCswMjAwIChFYXN0ZXJuIEV1cm9wZWFuIFN0YW5kYXJkIFRpbWUpXHJcblx0ICogQHBhcmFtIGNhbGVuZGFyX3BhcmFtc19hcnJcdFx0XHRcdFx0XHQtICBDYWxlbmRhciBTZXR0aW5ncyBPYmplY3Q6ICBcdHtcclxuXHQgKlx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0ICBcdFx0XHRcdFx0XHRcInJlc291cmNlX2lkXCI6IDRcclxuXHQgKlx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdH1cclxuXHQgKiBAcGFyYW0gZGF0ZXBpY2tfdGhpc1x0XHRcdFx0XHRcdFx0XHQtIHRoaXMgb2YgZGF0ZXBpY2sgT2JqXHJcblx0ICogQHJldHVybnMge2Jvb2xlYW59XHJcblx0ICovXHJcblx0ZnVuY3Rpb24gd3BiY19fY2FsZW5kYXJfX29uX2hvdmVyX2RheXMoIHN0cmluZ19kYXRlLCBkYXRlLCBjYWxlbmRhcl9wYXJhbXNfYXJyLCBkYXRlcGlja190aGlzICkge1xyXG5cclxuXHRcdGlmICggbnVsbCA9PT0gZGF0ZSApIHtcclxuXHRcdFx0d3BiY19jYWxlbmRhcnNfX2NsZWFyX2RheXNfaGlnaGxpZ2h0aW5nKCAoJ3VuZGVmaW5lZCcgIT09IHR5cGVvZiAoY2FsZW5kYXJfcGFyYW1zX2FyclsgJ3Jlc291cmNlX2lkJyBdKSkgPyBjYWxlbmRhcl9wYXJhbXNfYXJyWyAncmVzb3VyY2VfaWQnIF0gOiAnMScgKTtcdFx0Ly8gRml4SW46IDEwLjUuMi40LlxyXG5cdFx0XHRyZXR1cm4gZmFsc2U7XHJcblx0XHR9XHJcblxyXG5cdFx0dmFyIGNsYXNzX2RheSAgICAgPSB3cGJjX19nZXRfX3RkX2NsYXNzX2RhdGUoIGRhdGUgKTtcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQvLyAnMS05LTIwMjMnXHJcblx0XHR2YXIgc3FsX2NsYXNzX2RheSA9IHdwYmNfX2dldF9fc3FsX2NsYXNzX2RhdGUoIGRhdGUgKTtcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQvLyAnMjAyMy0wMS0wOSdcclxuXHRcdHZhciByZXNvdXJjZV9pZCA9ICggJ3VuZGVmaW5lZCcgIT09IHR5cGVvZihjYWxlbmRhcl9wYXJhbXNfYXJyWyAncmVzb3VyY2VfaWQnIF0pICkgPyBjYWxlbmRhcl9wYXJhbXNfYXJyWyAncmVzb3VyY2VfaWQnIF0gOiAnMSc7XHRcdC8vICcxJ1xyXG5cclxuXHRcdC8vIEdldCBEYXRhIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHR2YXIgZGF0ZV9ib29raW5nX29iaiA9IF93cGJjLmJvb2tpbmdzX2luX2NhbGVuZGFyX19nZXRfZm9yX2RhdGUoIHJlc291cmNlX2lkLCBzcWxfY2xhc3NfZGF5ICk7XHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vIHsuLi59XHJcblxyXG5cdFx0aWYgKCAhIGRhdGVfYm9va2luZ19vYmogKXsgcmV0dXJuIGZhbHNlOyB9XHJcblxyXG5cclxuXHRcdC8vIFQgbyBvIGwgdCBpIHAgcyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHR2YXIgdG9vbHRpcF90ZXh0ID0gJyc7XHJcblx0XHRpZiAoIGRhdGVfYm9va2luZ19vYmpbICdzdW1tYXJ5J11bJ3Rvb2x0aXBfYXZhaWxhYmlsaXR5JyBdLmxlbmd0aCA+IDAgKXtcclxuXHRcdFx0dG9vbHRpcF90ZXh0ICs9ICBkYXRlX2Jvb2tpbmdfb2JqWyAnc3VtbWFyeSddWyd0b29sdGlwX2F2YWlsYWJpbGl0eScgXTtcclxuXHRcdH1cclxuXHRcdGlmICggZGF0ZV9ib29raW5nX29ialsgJ3N1bW1hcnknXVsndG9vbHRpcF9kYXlfY29zdCcgXS5sZW5ndGggPiAwICl7XHJcblx0XHRcdHRvb2x0aXBfdGV4dCArPSAgZGF0ZV9ib29raW5nX29ialsgJ3N1bW1hcnknXVsndG9vbHRpcF9kYXlfY29zdCcgXTtcclxuXHRcdH1cclxuXHRcdGlmICggZGF0ZV9ib29raW5nX29ialsgJ3N1bW1hcnknXVsndG9vbHRpcF90aW1lcycgXS5sZW5ndGggPiAwICl7XHJcblx0XHRcdHRvb2x0aXBfdGV4dCArPSAgZGF0ZV9ib29raW5nX29ialsgJ3N1bW1hcnknXVsndG9vbHRpcF90aW1lcycgXTtcclxuXHRcdH1cclxuXHRcdGlmICggZGF0ZV9ib29raW5nX29ialsgJ3N1bW1hcnknXVsndG9vbHRpcF9ib29raW5nX2RldGFpbHMnIF0ubGVuZ3RoID4gMCApe1xyXG5cdFx0XHR0b29sdGlwX3RleHQgKz0gIGRhdGVfYm9va2luZ19vYmpbICdzdW1tYXJ5J11bJ3Rvb2x0aXBfYm9va2luZ19kZXRhaWxzJyBdO1xyXG5cdFx0fVxyXG5cdFx0d3BiY19zZXRfdG9vbHRpcF9fX2Zvcl9fY2FsZW5kYXJfZGF0ZSggdG9vbHRpcF90ZXh0LCByZXNvdXJjZV9pZCwgY2xhc3NfZGF5ICk7XHJcblxyXG5cclxuXHJcblx0XHQvLyAgVSBuIGggbyB2IGUgciBpIG4gZyAgICBpbiAgICBVTlNFTEVDVEFCTEVfQ0FMRU5EQVIgIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdFx0dmFyIGlzX3Vuc2VsZWN0YWJsZV9jYWxlbmRhciA9ICggalF1ZXJ5KCAnI2NhbGVuZGFyX2Jvb2tpbmdfdW5zZWxlY3RhYmxlJyArIHJlc291cmNlX2lkICkubGVuZ3RoID4gMCk7XHRcdFx0XHQvLyBGaXhJbjogOC4wLjEuMi5cclxuXHRcdHZhciBpc19ib29raW5nX2Zvcm1fZXhpc3QgICAgPSAoIGpRdWVyeSggJyNib29raW5nX2Zvcm1fZGl2JyArIHJlc291cmNlX2lkICkubGVuZ3RoID4gMCApO1xyXG5cdFx0dmFyIGlzX2FkZF9ib29raW5nX21vZGFsX2NhbGVuZGFyID0gKCBqUXVlcnkoICcjY2FsZW5kYXJfYm9va2luZycgKyByZXNvdXJjZV9pZCApLmNsb3Nlc3QoICcjd3BiY19tb2RhbF9fYWRkX2Jvb2tpbmdfX3NlY3Rpb24nICkubGVuZ3RoID4gMCApO1xyXG5cdFx0dmFyIGlzX2FkbWluX2NhbGVuZGFyX3ByZXZpZXcgPSAoIGpRdWVyeSggJyNjYWxlbmRhcl9ib29raW5nJyArIHJlc291cmNlX2lkICkuY2xvc2VzdCggJ1tkYXRhLXdwYmMtYWRtaW4tY2FsZW5kYXItcHJldmlldz1cIjFcIl0nICkubGVuZ3RoID4gMCApO1xyXG5cclxuXHRcdGlmICggKCBpc191bnNlbGVjdGFibGVfY2FsZW5kYXIgKSAmJiAoICEgaXNfYm9va2luZ19mb3JtX2V4aXN0ICkgKXtcclxuXHJcblx0XHRcdC8qKlxyXG5cdFx0XHQgKiAgVW4gSG92ZXIgYWxsIGRhdGVzIGluIGNhbGVuZGFyICh3aXRob3V0IHRoZSBib29raW5nIGZvcm0pLCBpZiBvbmx5IEF2YWlsYWJpbGl0eSBDYWxlbmRhciBoZXJlIGFuZCB3ZSBkb1xyXG5cdFx0XHQgKiBub3QgaW5zZXJ0IEJvb2tpbmcgZm9ybSBieSBtaXN0YWtlLlxyXG5cdFx0XHQgKi9cclxuXHJcblx0XHRcdHdwYmNfY2FsZW5kYXJzX19jbGVhcl9kYXlzX2hpZ2hsaWdodGluZyggcmVzb3VyY2VfaWQgKTsgXHRcdFx0XHRcdFx0XHQvLyBDbGVhciBkYXlzIGhpZ2hsaWdodGluZ1xyXG5cclxuXHRcdFx0dmFyIGNzc19vZl9jYWxlbmRhciA9ICcud3BiY19vbmx5X2NhbGVuZGFyICNjYWxlbmRhcl9ib29raW5nJyArIHJlc291cmNlX2lkO1xyXG5cdFx0XHRqUXVlcnkoIGNzc19vZl9jYWxlbmRhciArICcgLmRhdGVwaWNrLWRheXMtY2VsbCwgJ1xyXG5cdFx0XHRcdCAgKyBjc3Nfb2ZfY2FsZW5kYXIgKyAnIC5kYXRlcGljay1kYXlzLWNlbGwgYScgKS5jc3MoICdjdXJzb3InLCAnZGVmYXVsdCcgKTtcdC8vIFNldCBjdXJzb3IgdG8gRGVmYXVsdFxyXG5cdFx0XHRyZXR1cm4gZmFsc2U7XHJcblx0XHR9XHJcblxyXG5cclxuXHJcblx0XHQvLyAgRCBhIHkgcyAgICBIIG8gdiBlIHIgaSBuIGcgIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdFx0aWYgKFxyXG5cdFx0XHQgICAoIGxvY2F0aW9uLmhyZWYuaW5kZXhPZiggJ3BhZ2U9d3BiYycgKSA9PSAtMSApXHJcblx0XHRcdHx8ICggKCBsb2NhdGlvbi5ocmVmLmluZGV4T2YoICdwYWdlPXdwYmMnICkgPiAwICkgJiYgKCBsb2NhdGlvbi5ocmVmLmluZGV4T2YoICd0YWI9YWRkLWJvb2tpbmcnICkgPiAwICkgKVxyXG5cdFx0XHR8fCAoIGlzX2FkZF9ib29raW5nX21vZGFsX2NhbGVuZGFyIClcclxuXHRcdFx0fHwgKCBpc19hZG1pbl9jYWxlbmRhcl9wcmV2aWV3IClcclxuXHRcdFx0fHwgKCBsb2NhdGlvbi5ocmVmLmluZGV4T2YoICdwYWdlPXdwYmMtc2V0dXAnICkgPiAwIClcclxuXHRcdFx0fHwgKCBsb2NhdGlvbi5ocmVmLmluZGV4T2YoICdwYWdlPXdwYmMtYXZhaWxhYmlsaXR5JyApID4gMCApXHJcblx0XHRcdHx8ICggICggbG9jYXRpb24uaHJlZi5pbmRleE9mKCAncGFnZT13cGJjLXNldHRpbmdzJyApID4gMCApICAmJlxyXG5cdFx0XHRcdCAgKCBsb2NhdGlvbi5ocmVmLmluZGV4T2YoICd0YWI9YnVpbGRlcl9ib29raW5nX2Zvcm0nICkgPiAwIClcclxuXHRcdFx0ICAgKVxyXG5cdFx0KXtcclxuXHRcdFx0Ly8gVGhlIHNhbWUgYXMgZGF0ZXMgc2VsZWN0aW9uLCAgYnV0IGZvciBkYXlzIGhvdmVyaW5nXHJcblxyXG5cdFx0XHRpZiAoICdmdW5jdGlvbicgPT0gdHlwZW9mKCB3cGJjX19jYWxlbmRhcl9fZG9fZGF5c19oaWdobGlnaHRfX2JzICkgKXtcclxuXHRcdFx0XHR3cGJjX19jYWxlbmRhcl9fZG9fZGF5c19oaWdobGlnaHRfX2JzKCBzcWxfY2xhc3NfZGF5LCBkYXRlLCByZXNvdXJjZV9pZCApO1xyXG5cdFx0XHR9IGVsc2UgaWYgKCAnZHluYW1pYycgPT09IF93cGJjLmNhbGVuZGFyX19nZXRfcGFyYW1fdmFsdWUoIHJlc291cmNlX2lkLCAnZGF5c19zZWxlY3RfbW9kZScgKSApIHtcclxuXHRcdFx0XHR3cGJjX19jYWxlbmRhcl9fZG9fZGF5c19oaWdobGlnaHRfX3VucmVzdHJpY3RlZF9yYW5nZSggc3FsX2NsYXNzX2RheSwgZGF0ZSwgcmVzb3VyY2VfaWQgKTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG5cclxuXHQvKipcclxuXHQgKiBIaWdobGlnaHQgYW4gdW5yZXN0cmljdGVkIHByb3Bvc2VkIHJhbmdlIGFmdGVyIHRoZSBmaXJzdCBjbGljayB3aGVuIEJ1c2luZXNzIFNtYWxsIGlzIG5vdCBsb2FkZWQuXHJcblx0ICpcclxuXHQgKiBAcGFyYW0ge3N0cmluZ30gc3FsX2NsYXNzX2RheSBIb3ZlcmVkIGRhdGUgaW4gU1FMIGZvcm1hdC5cclxuXHQgKiBAcGFyYW0ge0RhdGV9IGRhdGUgSG92ZXJlZCBkYXRlLlxyXG5cdCAqIEBwYXJhbSB7bnVtYmVyfHN0cmluZ30gcmVzb3VyY2VfaWQgQm9va2luZyByZXNvdXJjZSBJRC5cclxuXHQgKiBAcmV0dXJucyB7Ym9vbGVhbn0gVHJ1ZSB3aGVuIHRoZSBjb21wbGV0ZSBwcm9wb3NlZCByYW5nZSBpcyBhdmFpbGFibGUgYW5kIGhpZ2hsaWdodGVkLlxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdwYmNfX2NhbGVuZGFyX19kb19kYXlzX2hpZ2hsaWdodF9fdW5yZXN0cmljdGVkX3JhbmdlKCBzcWxfY2xhc3NfZGF5LCBkYXRlLCByZXNvdXJjZV9pZCApe1xyXG5cclxuXHRcdHZhciBpbnN0ID0gd3BiY19jYWxlbmRhcl9fZ2V0X2luc3QoIHJlc291cmNlX2lkICk7XHJcblx0XHR2YXIgcmFuZ2Vfc3RhcnQ7XHJcblx0XHR2YXIgcmFuZ2VfZW5kO1xyXG5cdFx0dmFyIHdvcmtpbmdfZGF0ZTtcclxuXHRcdHZhciB0ZF9vdmVycyA9IFtdO1xyXG5cclxuXHRcdHdwYmNfY2FsZW5kYXJzX19jbGVhcl9kYXlzX2hpZ2hsaWdodGluZyggcmVzb3VyY2VfaWQgKTtcclxuXHJcblx0XHRpZiAoXHJcblx0XHRcdCAgIG51bGwgPT09IGluc3RcclxuXHRcdFx0fHwgJ2R5bmFtaWMnICE9PSBfd3BiYy5jYWxlbmRhcl9fZ2V0X3BhcmFtX3ZhbHVlKCByZXNvdXJjZV9pZCwgJ2RheXNfc2VsZWN0X21vZGUnIClcclxuXHRcdCkge1xyXG5cdFx0XHRyZXR1cm4gZmFsc2U7XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gQmVmb3JlIGEgcmFuZ2Ugc3RhcnRzLCBvciBhZnRlciBpdCBpcyBjb21wbGV0ZSwgcHJldmlldyB0aGUgaG92ZXJlZCBkYXRlIGFzIHRoZSBwb3NzaWJsZSBmaXJzdCBkYXkuXHJcblx0XHRpZiAoIDEgIT09IGluc3QuZGF0ZXMubGVuZ3RoIHx8ICEgaW5zdC5kYXRlc1sgMCBdICkge1xyXG5cdFx0XHRpZiAoICEgd3BiY19pc190aGlzX2RheV9zZWxlY3RhYmxlKCByZXNvdXJjZV9pZCwgc3FsX2NsYXNzX2RheSApICkge1xyXG5cdFx0XHRcdHJldHVybiBmYWxzZTtcclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0alF1ZXJ5KCAnI2NhbGVuZGFyX2Jvb2tpbmcnICsgcmVzb3VyY2VfaWQgKyAnIC5jYWw0ZGF0ZS0nICsgd3BiY19fZ2V0X190ZF9jbGFzc19kYXRlKCBkYXRlICkgKVxyXG5cdFx0XHRcdC5hZGRDbGFzcyggJ2RhdGVwaWNrLWRheXMtY2VsbC1vdmVyJyApO1xyXG5cdFx0XHRyZXR1cm4gdHJ1ZTtcclxuXHRcdH1cclxuXHJcblx0XHRyYW5nZV9zdGFydCA9IG5ldyBEYXRlKCBpbnN0LmRhdGVzWyAwIF0uZ2V0RnVsbFllYXIoKSwgaW5zdC5kYXRlc1sgMCBdLmdldE1vbnRoKCksIGluc3QuZGF0ZXNbIDAgXS5nZXREYXRlKCksIDAsIDAsIDAgKTtcclxuXHRcdHJhbmdlX2VuZCAgID0gbmV3IERhdGUoIGRhdGUuZ2V0RnVsbFllYXIoKSwgZGF0ZS5nZXRNb250aCgpLCBkYXRlLmdldERhdGUoKSwgMCwgMCwgMCApO1xyXG5cclxuXHRcdC8vIERhdGVwaWNrIG9ubHkgcGVybWl0cyBhIGNoZWNrLW91dCBkYXRlIG9uL2FmdGVyIHRoZSBmaXJzdCBjbGljay4gRG8gbm90IHByZXZpZXcgYSBiYWNrd2FyZCByYW5nZS5cclxuXHRcdGlmICggcmFuZ2VfZW5kLmdldFRpbWUoKSA8IHJhbmdlX3N0YXJ0LmdldFRpbWUoKSApIHtcclxuXHRcdFx0cmV0dXJuIGZhbHNlO1xyXG5cdFx0fVxyXG5cclxuXHRcdHdvcmtpbmdfZGF0ZSA9IG5ldyBEYXRlKCByYW5nZV9zdGFydC5nZXRUaW1lKCkgKTtcclxuXHRcdHdoaWxlICggd29ya2luZ19kYXRlLmdldFRpbWUoKSA8PSByYW5nZV9lbmQuZ2V0VGltZSgpICkge1xyXG5cdFx0XHRzcWxfY2xhc3NfZGF5ID0gd3BiY19fZ2V0X19zcWxfY2xhc3NfZGF0ZSggd29ya2luZ19kYXRlICk7XHJcblx0XHRcdGlmICggISB3cGJjX2lzX3RoaXNfZGF5X3NlbGVjdGFibGUoIHJlc291cmNlX2lkLCBzcWxfY2xhc3NfZGF5ICkgKSB7XHJcblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHR0ZF9vdmVycy5wdXNoKCAnI2NhbGVuZGFyX2Jvb2tpbmcnICsgcmVzb3VyY2VfaWQgKyAnIC5jYWw0ZGF0ZS0nICsgd3BiY19fZ2V0X190ZF9jbGFzc19kYXRlKCB3b3JraW5nX2RhdGUgKSApO1xyXG5cdFx0XHR3b3JraW5nX2RhdGUuc2V0RGF0ZSggd29ya2luZ19kYXRlLmdldERhdGUoKSArIDEgKTtcclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIHRkX292ZXJzLmxlbmd0aCApIHtcclxuXHRcdFx0alF1ZXJ5KCB0ZF9vdmVycy5qb2luKCAnLCcgKSApLmFkZENsYXNzKCAnZGF0ZXBpY2stZGF5cy1jZWxsLW92ZXInICk7XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRydWU7XHJcblx0fVxyXG5cclxuXHJcblx0LyoqXHJcblx0ICogQ29tcGxldGUgYW4gdW5yZXN0cmljdGVkIHR3by1jbGljayByYW5nZSB3aGVuIHRoZSBCdXNpbmVzcyBTbWFsbCByYW5nZSBlbmdpbmUgaXMgbm90IGxvYWRlZC5cclxuXHQgKiBUaGUgaGlkZGVuIGJvb2tpbmcgZmllbGQgbXVzdCBjb250YWluIGV2ZXJ5IGRhdGUgYmVjYXVzZSBGcmVlIHRpbWUvaGludCBoYW5kbGVycyBjb25zdW1lIGEgY29tbWEtc2VwYXJhdGVkIGxpc3QuXHJcblx0ICpcclxuXHQgKiBAcGFyYW0ge3N0cmluZ30gc2VsZWN0ZWRfZGF0ZXMgRGF0ZXBpY2sncyBlbmRwb2ludCBzdHJpbmcuXHJcblx0ICogQHBhcmFtIHtudW1iZXJ8c3RyaW5nfSByZXNvdXJjZV9pZCBCb29raW5nIHJlc291cmNlIElELlxyXG5cdCAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGFmdGVyIGEgY29tcGxldGUgdmFsaWQgcmFuZ2UsIGZhbHNlIHdoaWxlIGluY29tcGxldGUgb3IgaW52YWxpZC5cclxuXHQgKi9cclxuXHRmdW5jdGlvbiB3cGJjX19jYWxlbmRhcl9fZG9fZGF5c19zZWxlY3RfX3VucmVzdHJpY3RlZF9yYW5nZSggc2VsZWN0ZWRfZGF0ZXMsIHJlc291cmNlX2lkICl7XHJcblxyXG5cdFx0dmFyIGluc3QgPSB3cGJjX2NhbGVuZGFyX19nZXRfaW5zdCggcmVzb3VyY2VfaWQgKTtcclxuXHRcdHZhciByYW5nZV9zdGFydDtcclxuXHRcdHZhciByYW5nZV9lbmQ7XHJcblx0XHR2YXIgY3VycmVudF9kYXRlO1xyXG5cdFx0dmFyIHNlbGVjdGVkX3JhbmdlID0gW107XHJcblxyXG5cdFx0aWYgKCBudWxsID09PSBpbnN0ICkge1xyXG5cdFx0XHRyZXR1cm4gZmFsc2U7XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gRGF0ZXBpY2sgd3JpdGVzIFwic3RhcnQgLSBzdGFydFwiIGFmdGVyIGNsaWNrIG9uZS4gS2VlcCBpdHMgaW50ZXJuYWwgZW5kcG9pbnQsIGJ1dCBkbyBub3QgZXhwb3NlIGEgc3VibWl0dGFibGUgcmFuZ2UgeWV0LlxyXG5cdFx0aWYgKCB0cnVlID09PSBpbnN0LnN0YXlPcGVuIHx8IGluc3QuZGF0ZXMubGVuZ3RoIDwgMiB8fCAhIGluc3QuZGF0ZXNbIDAgXSB8fCAhIGluc3QuZGF0ZXNbIDEgXSApIHtcclxuXHRcdFx0alF1ZXJ5KCAnI2RhdGVfYm9va2luZycgKyByZXNvdXJjZV9pZCApLnZhbCggJycgKTtcclxuXHRcdFx0cmV0dXJuIGZhbHNlO1xyXG5cdFx0fVxyXG5cclxuXHRcdHJhbmdlX3N0YXJ0ID0gbmV3IERhdGUoIGluc3QuZGF0ZXNbIDAgXS5nZXRGdWxsWWVhcigpLCBpbnN0LmRhdGVzWyAwIF0uZ2V0TW9udGgoKSwgaW5zdC5kYXRlc1sgMCBdLmdldERhdGUoKSwgMCwgMCwgMCApO1xyXG5cdFx0cmFuZ2VfZW5kICAgPSBuZXcgRGF0ZSggaW5zdC5kYXRlc1sgMSBdLmdldEZ1bGxZZWFyKCksIGluc3QuZGF0ZXNbIDEgXS5nZXRNb250aCgpLCBpbnN0LmRhdGVzWyAxIF0uZ2V0RGF0ZSgpLCAwLCAwLCAwICk7XHJcblxyXG5cdFx0Ly8gRGVmZW5zaXZlIG5vcm1hbGl6YXRpb24uIERhdGVwaWNrIG5vcm1hbGx5IHByZXZlbnRzIGFuIGVuZCBkYXRlIGJlZm9yZSB0aGUgZmlyc3QgZW5kcG9pbnQuXHJcblx0XHRpZiAoIHJhbmdlX2VuZC5nZXRUaW1lKCkgPCByYW5nZV9zdGFydC5nZXRUaW1lKCkgKSB7XHJcblx0XHRcdGN1cnJlbnRfZGF0ZSA9IHJhbmdlX3N0YXJ0O1xyXG5cdFx0XHRyYW5nZV9zdGFydCA9IHJhbmdlX2VuZDtcclxuXHRcdFx0cmFuZ2VfZW5kID0gY3VycmVudF9kYXRlO1xyXG5cdFx0fVxyXG5cclxuXHRcdGN1cnJlbnRfZGF0ZSA9IG5ldyBEYXRlKCByYW5nZV9zdGFydC5nZXRUaW1lKCkgKTtcclxuXHRcdHdoaWxlICggY3VycmVudF9kYXRlLmdldFRpbWUoKSA8PSByYW5nZV9lbmQuZ2V0VGltZSgpICkge1xyXG5cdFx0XHRpZiAoICEgd3BiY19pc190aGlzX2RheV9zZWxlY3RhYmxlKCByZXNvdXJjZV9pZCwgd3BiY19fZ2V0X19zcWxfY2xhc3NfZGF0ZSggY3VycmVudF9kYXRlICkgKSApIHtcclxuXHRcdFx0XHR3cGJjX2NhbGVuZGFyX191bnNlbGVjdF9hbGxfZGF0ZXMoIHJlc291cmNlX2lkICk7XHJcblx0XHRcdFx0aWYgKCAnZnVuY3Rpb24nID09PSB0eXBlb2YgKCB3cGJjX2Zyb250X2VuZF9fc2hvd19tZXNzYWdlX193YXJuaW5nICkgKSB7XHJcblx0XHRcdFx0XHR3cGJjX2Zyb250X2VuZF9fc2hvd19tZXNzYWdlX193YXJuaW5nKFxyXG5cdFx0XHRcdFx0XHQnI2Jvb2tpbmdfZm9ybV9kaXYnICsgcmVzb3VyY2VfaWQgKyAnIC5ia19jYWxlbmRhcl9mcmFtZScsXHJcblx0XHRcdFx0XHRcdF93cGJjLmdldF9tZXNzYWdlKCAnbWVzc2FnZV9yYW5nZV9zZWxlY3Rpb25faGFzX3VuYXZhaWxhYmxlX2RhdGVzJyApLFxyXG5cdFx0XHRcdFx0XHQndGV4dCdcclxuXHRcdFx0XHRcdCk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHRcdHJldHVybiBmYWxzZTtcclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0c2VsZWN0ZWRfcmFuZ2UucHVzaCggalF1ZXJ5LmRhdGVwaWNrLl9mb3JtYXREYXRlKCBpbnN0LCBjdXJyZW50X2RhdGUgKSApO1xyXG5cdFx0XHRjdXJyZW50X2RhdGUuc2V0RGF0ZSggY3VycmVudF9kYXRlLmdldERhdGUoKSArIDEgKTtcclxuXHRcdH1cclxuXHJcblx0XHRqUXVlcnkoICcjZGF0ZV9ib29raW5nJyArIHJlc291cmNlX2lkICkudmFsKCBzZWxlY3RlZF9yYW5nZS5qb2luKCAnLCAnICkgKTtcclxuXHRcdHJldHVybiB0cnVlO1xyXG5cdH1cclxuXHJcblxyXG5cdC8qKlxyXG5cdCAqIFByZXBhcmUgYSBjb2xsYXBzZWQgcmFuZ2Utc2VsZWN0aW9uIGd1aWRhbmNlIG5vdGUgZm9yIG9uZSBjYWxlbmRhci5cclxuXHQgKiBLZWVwaW5nIG9uZSByZXVzYWJsZSBub2RlIGF2b2lkcyByZXBlYXRlZCBpbnNlcnRpb24gd2hpbGUgaW5hY3RpdmUgZ3VpZGFuY2Ugb2NjdXBpZXMgbm8gbGF5b3V0IHNwYWNlLlxyXG5cdCAqXHJcblx0ICogQHBhcmFtIHtudW1iZXJ8c3RyaW5nfSByZXNvdXJjZV9pZCBCb29raW5nIHJlc291cmNlIElELlxyXG5cdCAqIEByZXR1cm5zIHtqUXVlcnl9IFRoZSBwcmVwYXJlZCBub3RlLCBvciBhbiBlbXB0eSBjb2xsZWN0aW9uIHdoZW4gZ3VpZGFuY2UgaXMgdW5hdmFpbGFibGUuXHJcblx0ICovXHJcblx0ZnVuY3Rpb24gd3BiY19yYW5nZV9zZWxlY3Rpb25fX3ByZXBhcmVfZ3VpZGFuY2UoIHJlc291cmNlX2lkICl7XHJcblxyXG5cdFx0dmFyIGlzX2VuYWJsZWQgPSBfd3BiYy5jYWxlbmRhcl9fZ2V0X3BhcmFtX3ZhbHVlKCByZXNvdXJjZV9pZCwgJ3JhbmdlX3NlbGVjdGlvbl9ndWlkYW5jZV9pc19lbmFibGVkJyApO1xyXG5cdFx0dmFyICRib29raW5nX2Zvcm0gPSBqUXVlcnkoICcjYm9va2luZ19mb3JtX2RpdicgKyByZXNvdXJjZV9pZCApO1xyXG5cdFx0dmFyICRjYWxlbmRhcl9mcmFtZTtcclxuXHRcdHZhciAkbm90ZSA9IGpRdWVyeSggJyN3cGJjX3JhbmdlX3NlbGVjdGlvbl9ndWlkYW5jZScgKyByZXNvdXJjZV9pZCApO1xyXG5cclxuXHRcdGlmIChcclxuXHRcdFx0ICAgZmFsc2UgPT09IGlzX2VuYWJsZWRcclxuXHRcdFx0fHwgMCA9PT0gaXNfZW5hYmxlZFxyXG5cdFx0XHR8fCAnMCcgPT09IGlzX2VuYWJsZWRcclxuXHRcdFx0fHwgJ29mZicgPT09IFN0cmluZyggaXNfZW5hYmxlZCApLnRvTG93ZXJDYXNlKClcclxuXHRcdFx0fHwgJ2ZhbHNlJyA9PT0gU3RyaW5nKCBpc19lbmFibGVkICkudG9Mb3dlckNhc2UoKVxyXG5cdFx0XHR8fCAnZHluYW1pYycgIT09IF93cGJjLmNhbGVuZGFyX19nZXRfcGFyYW1fdmFsdWUoIHJlc291cmNlX2lkLCAnZGF5c19zZWxlY3RfbW9kZScgKVxyXG5cdFx0XHR8fCAwID09PSAkYm9va2luZ19mb3JtLmxlbmd0aFxyXG5cdFx0KSB7XHJcblx0XHRcdCRub3RlLnJlbW92ZSgpO1xyXG5cdFx0XHRyZXR1cm4galF1ZXJ5KCk7XHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCAwIDwgJG5vdGUubGVuZ3RoICkge1xyXG5cdFx0XHQkbm90ZS5zdG9wKCB0cnVlLCB0cnVlICkuaGlkZSgpLmF0dHIoICdhcmlhLWhpZGRlbicsICd0cnVlJyApO1xyXG5cdFx0XHRyZXR1cm4gJG5vdGU7XHJcblx0XHR9XHJcblxyXG5cdFx0JGNhbGVuZGFyX2ZyYW1lID0gJGJvb2tpbmdfZm9ybS5maW5kKCAnLmJsb2NrX2hpbnRzLmRhdGVwaWNrJyApLmZpcnN0KCk7XHJcblx0XHRpZiAoIDAgPT09ICRjYWxlbmRhcl9mcmFtZS5sZW5ndGggKSB7XHJcblx0XHRcdCRjYWxlbmRhcl9mcmFtZSA9ICRib29raW5nX2Zvcm0uZmluZCggJy53cGJjX2NhbF9wb3dlcmVkX2J5JyApLmZpcnN0KCk7XHJcblx0XHRcdGlmICggMCA9PT0gJGNhbGVuZGFyX2ZyYW1lLmxlbmd0aCApIHtcclxuXHRcdFx0XHQkY2FsZW5kYXJfZnJhbWUgPSAkYm9va2luZ19mb3JtLmZpbmQoICcuYmtfY2FsZW5kYXJfZnJhbWUnICkuZmlyc3QoKTtcclxuXHRcdFx0XHRpZiAoIDAgPT09ICRjYWxlbmRhcl9mcmFtZS5sZW5ndGggKSB7XHJcblx0XHRcdFx0XHRyZXR1cm4galF1ZXJ5KCk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0JG5vdGUgPSBqUXVlcnkoICc8ZGl2PicsIHtcclxuXHRcdFx0J2lkJzogJ3dwYmNfcmFuZ2Vfc2VsZWN0aW9uX2d1aWRhbmNlJyArIHJlc291cmNlX2lkLFxyXG5cdFx0XHQnY2xhc3MnOiAnd3BiY19yYW5nZV9zZWxlY3Rpb25fZ3VpZGFuY2Ugd3BiY19mcm9udF9lbmRfX21lc3NhZ2Ugd3BiY19mZV9tZXNzYWdlX2luZm8nLFxyXG5cdFx0XHQncm9sZSc6ICdzdGF0dXMnLFxyXG5cdFx0XHQnYXJpYS1saXZlJzogJ3BvbGl0ZScsXHJcblx0XHRcdCdhcmlhLWhpZGRlbic6ICd0cnVlJyxcclxuXHRcdFx0J3N0eWxlJzogJ2Rpc3BsYXk6IG5vbmU7J1xyXG5cdFx0fSApO1xyXG5cdFx0JG5vdGUuYXBwZW5kKCBqUXVlcnkoICc8aT4nLCB7XHJcblx0XHRcdCdjbGFzcyc6ICdtZW51X2ljb24gaWNvbi0xeCB3cGJjX2ljbl9pbmZvX291dGxpbmUnLFxyXG5cdFx0XHQnYXJpYS1oaWRkZW4nOiAndHJ1ZSdcclxuXHRcdH0gKSApO1xyXG5cdFx0JG5vdGUuYXBwZW5kKCBqUXVlcnkoICc8c3Bhbj4nICkudGV4dCggX3dwYmMuZ2V0X21lc3NhZ2UoICdtZXNzYWdlX3JhbmdlX3NlbGVjdGlvbl9jbGlja19sYXN0X2RhdGUnICkgKSApO1xyXG5cdFx0JGNhbGVuZGFyX2ZyYW1lLmFmdGVyKCAkbm90ZSApO1xyXG5cclxuXHRcdHJldHVybiAkbm90ZTtcclxuXHR9XHJcblxyXG5cclxuXHQvKipcclxuXHQgKiBHZXQgdGhlIHJhbmdlLWd1aWRhbmNlIGFuaW1hdGlvbiBkdXJhdGlvbiBmb3IgdGhlIGN1cnJlbnQgbW90aW9uIHByZWZlcmVuY2UuXHJcblx0ICpcclxuXHQgKiBAcmV0dXJucyB7bnVtYmVyfSBBbmltYXRpb24gZHVyYXRpb24gaW4gbWlsbGlzZWNvbmRzLCBvciB6ZXJvIHdoZW4gcmVkdWNlZCBtb3Rpb24gaXMgcHJlZmVycmVkLlxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdwYmNfcmFuZ2Vfc2VsZWN0aW9uX19nZXRfZ3VpZGFuY2VfYW5pbWF0aW9uX2R1cmF0aW9uKCl7XHJcblxyXG5cdFx0aWYgKFxyXG5cdFx0XHQnZnVuY3Rpb24nID09PSB0eXBlb2Ygd2luZG93Lm1hdGNoTWVkaWFcclxuXHRcdFx0JiYgd2luZG93Lm1hdGNoTWVkaWEoICcocHJlZmVycy1yZWR1Y2VkLW1vdGlvbjogcmVkdWNlKScgKS5tYXRjaGVzXHJcblx0XHQpIHtcclxuXHRcdFx0cmV0dXJuIDA7XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIDE2MDtcclxuXHR9XHJcblxyXG5cclxuXHQvKipcclxuXHQgKiBDb2xsYXBzZSB0aGUgcmFuZ2Utc2VsZWN0aW9uIGd1aWRhbmNlIHNvIGl0IGRvZXMgbm90IHJlc2VydmUgZW1wdHkgbGF5b3V0IHNwYWNlLlxyXG5cdCAqXHJcblx0ICogQHBhcmFtIHtudW1iZXJ8c3RyaW5nfSByZXNvdXJjZV9pZCBCb29raW5nIHJlc291cmNlIElELlxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdwYmNfcmFuZ2Vfc2VsZWN0aW9uX19oaWRlX2d1aWRhbmNlKCByZXNvdXJjZV9pZCApe1xyXG5cclxuXHRcdGpRdWVyeSggJyN3cGJjX3JhbmdlX3NlbGVjdGlvbl9ndWlkYW5jZScgKyByZXNvdXJjZV9pZCApXHJcblx0XHRcdC5hdHRyKCAnYXJpYS1oaWRkZW4nLCAndHJ1ZScgKVxyXG5cdFx0XHQuc3RvcCggdHJ1ZSwgdHJ1ZSApXHJcblx0XHRcdC5zbGlkZVVwKCB3cGJjX3JhbmdlX3NlbGVjdGlvbl9fZ2V0X2d1aWRhbmNlX2FuaW1hdGlvbl9kdXJhdGlvbigpICk7XHJcblx0fVxyXG5cclxuXHJcblx0LyoqXHJcblx0ICogU2hvdyB0aGUgcHJlcGFyZWQgaW5mb3JtYXRpb25hbCBub3RlIGFmdGVyIHRoZSBmaXJzdCByYW5nZSBjbGljay5cclxuXHQgKiBUaGUgY2FsZW5kYXIgcGFyYW1ldGVyIGNhbiBiZSBzZXQgdG8gZmFsc2UgYnkgUEhQIG9yIEphdmFTY3JpcHQgdG8gc3VwcHJlc3MgdGhpcyBVSSBwZXIgcmVzb3VyY2UuXHJcblx0ICpcclxuXHQgKiBAcGFyYW0ge251bWJlcnxzdHJpbmd9IHJlc291cmNlX2lkIEJvb2tpbmcgcmVzb3VyY2UgSUQuXHJcblx0ICogQHJldHVybnMge2Jvb2xlYW59IFRydWUgd2hlbiB0aGUgbm90ZSB3YXMgc2hvd24uXHJcblx0ICovXHJcblx0ZnVuY3Rpb24gd3BiY19yYW5nZV9zZWxlY3Rpb25fX3Nob3dfZ3VpZGFuY2UoIHJlc291cmNlX2lkICl7XHJcblxyXG5cdFx0dmFyICRub3RlID0gd3BiY19yYW5nZV9zZWxlY3Rpb25fX3ByZXBhcmVfZ3VpZGFuY2UoIHJlc291cmNlX2lkICk7XHJcblxyXG5cdFx0aWYgKCAwID09PSAkbm90ZS5sZW5ndGggKSB7XHJcblx0XHRcdHJldHVybiBmYWxzZTtcclxuXHRcdH1cclxuXHJcblx0XHQkbm90ZVxyXG5cdFx0XHQuc3RvcCggdHJ1ZSwgdHJ1ZSApXHJcblx0XHRcdC5zbGlkZURvd24oIHdwYmNfcmFuZ2Vfc2VsZWN0aW9uX19nZXRfZ3VpZGFuY2VfYW5pbWF0aW9uX2R1cmF0aW9uKCkgKVxyXG5cdFx0XHQucmVtb3ZlQXR0ciggJ2FyaWEtaGlkZGVuJyApO1xyXG5cdFx0JG5vdGUuZmluZCggJ3NwYW4nICkudGV4dCggX3dwYmMuZ2V0X21lc3NhZ2UoICdtZXNzYWdlX3JhbmdlX3NlbGVjdGlvbl9jbGlja19sYXN0X2RhdGUnICkgKTtcclxuXHJcblx0XHRyZXR1cm4gdHJ1ZTtcclxuXHR9XHJcblxyXG5cclxuXHQvKipcclxuXHQgKiBTeW5jaHJvbml6ZSB0aGUgZ3VpZGFuY2Ugd2l0aCBEYXRlcGljaydzIHR3by1jbGljayByYW5nZSBzdGF0ZS5cclxuXHQgKlxyXG5cdCAqIEBwYXJhbSB7bnVtYmVyfHN0cmluZ30gcmVzb3VyY2VfaWQgQm9va2luZyByZXNvdXJjZSBJRC5cclxuXHQgKi9cclxuXHRmdW5jdGlvbiB3cGJjX3JhbmdlX3NlbGVjdGlvbl9fc3luY19ndWlkYW5jZSggcmVzb3VyY2VfaWQgKXtcclxuXHJcblx0XHR2YXIgaW5zdCA9IHdwYmNfY2FsZW5kYXJfX2dldF9pbnN0KCByZXNvdXJjZV9pZCApO1xyXG5cclxuXHRcdGlmIChcclxuXHRcdFx0ICAgbnVsbCAhPT0gaW5zdFxyXG5cdFx0XHQmJiAnZHluYW1pYycgPT09IF93cGJjLmNhbGVuZGFyX19nZXRfcGFyYW1fdmFsdWUoIHJlc291cmNlX2lkLCAnZGF5c19zZWxlY3RfbW9kZScgKVxyXG5cdFx0XHQmJiB0cnVlID09PSBpbnN0LnN0YXlPcGVuXHJcblx0XHRcdCYmIDEgPT09IGluc3QuZGF0ZXMubGVuZ3RoXHJcblx0XHRcdCYmIGluc3QuZGF0ZXNbIDAgXVxyXG5cdFx0KSB7XHJcblx0XHRcdHdwYmNfcmFuZ2Vfc2VsZWN0aW9uX19zaG93X2d1aWRhbmNlKCByZXNvdXJjZV9pZCApO1xyXG5cdFx0XHRyZXR1cm47XHJcblx0XHR9XHJcblxyXG5cdFx0d3BiY19yYW5nZV9zZWxlY3Rpb25fX2hpZGVfZ3VpZGFuY2UoIHJlc291cmNlX2lkICk7XHJcblx0fVxyXG5cclxuXHJcblx0LyoqXHJcblx0ICogU2VsZWN0IGNhbGVuZGFyIGRhdGUgY2VsbHNcclxuXHQgKlxyXG5cdCAqIEBwYXJhbSBkYXRlXHRcdFx0XHRcdFx0XHRcdFx0XHQtICBKYXZhU2NyaXB0IERhdGUgT2JqOiAgXHRcdE1vbiBEZWMgMTEgMjAyMyAwMDowMDowMFxyXG5cdCAqICAgICBHTVQrMDIwMCAoRWFzdGVybiBFdXJvcGVhbiBTdGFuZGFyZCBUaW1lKVxyXG5cdCAqIEBwYXJhbSBjYWxlbmRhcl9wYXJhbXNfYXJyXHRcdFx0XHRcdFx0LSAgQ2FsZW5kYXIgU2V0dGluZ3MgT2JqZWN0OiAgXHR7XHJcblx0ICpcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCAgXHRcdFx0XHRcdFx0XCJyZXNvdXJjZV9pZFwiOiA0XHJcblx0ICpcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHR9XHJcblx0ICogQHBhcmFtIGRhdGVwaWNrX3RoaXNcdFx0XHRcdFx0XHRcdFx0LSB0aGlzIG9mIGRhdGVwaWNrIE9ialxyXG5cdCAqXHJcblx0ICovXHJcblx0ZnVuY3Rpb24gd3BiY19fY2FsZW5kYXJfX29uX3NlbGVjdF9kYXlzKCBkYXRlLCBjYWxlbmRhcl9wYXJhbXNfYXJyLCBkYXRlcGlja190aGlzICl7XHJcblxyXG5cdFx0dmFyIHJlc291cmNlX2lkID0gKCAndW5kZWZpbmVkJyAhPT0gdHlwZW9mKGNhbGVuZGFyX3BhcmFtc19hcnJbICdyZXNvdXJjZV9pZCcgXSkgKSA/IGNhbGVuZGFyX3BhcmFtc19hcnJbICdyZXNvdXJjZV9pZCcgXSA6ICcxJztcdFx0Ly8gJzEnXHJcblxyXG5cdFx0Ly8gU2V0IHVuc2VsZWN0YWJsZSwgIGlmIG9ubHkgQXZhaWxhYmlsaXR5IENhbGVuZGFyICBoZXJlIChhbmQgd2UgZG8gbm90IGluc2VydCBCb29raW5nIGZvcm0gYnkgbWlzdGFrZSkuXHJcblx0XHR2YXIgaXNfdW5zZWxlY3RhYmxlX2NhbGVuZGFyID0gKCBqUXVlcnkoICcjY2FsZW5kYXJfYm9va2luZ191bnNlbGVjdGFibGUnICsgcmVzb3VyY2VfaWQgKS5sZW5ndGggPiAwKTtcdFx0XHRcdC8vIEZpeEluOiA4LjAuMS4yLlxyXG5cdFx0dmFyIGlzX2Jvb2tpbmdfZm9ybV9leGlzdCAgICA9ICggalF1ZXJ5KCAnI2Jvb2tpbmdfZm9ybV9kaXYnICsgcmVzb3VyY2VfaWQgKS5sZW5ndGggPiAwICk7XHJcblx0XHRpZiAoICggaXNfdW5zZWxlY3RhYmxlX2NhbGVuZGFyICkgJiYgKCAhIGlzX2Jvb2tpbmdfZm9ybV9leGlzdCApICl7XHJcblx0XHRcdHdwYmNfY2FsZW5kYXJfX3Vuc2VsZWN0X2FsbF9kYXRlcyggcmVzb3VyY2VfaWQgKTtcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vIFVuc2VsZWN0IERhdGVzXHJcblx0XHRcdGpRdWVyeSgnLndwYmNfb25seV9jYWxlbmRhciAucG9wb3Zlcl9jYWxlbmRhcl9ob3ZlcicpLnJlbW92ZSgpOyAgICAgICAgICAgICAgICAgICAgICBcdFx0XHRcdFx0XHRcdC8vIEhpZGUgYWxsIG9wZW5lZCBwb3BvdmVyc1xyXG5cdFx0XHRyZXR1cm4gZmFsc2U7XHJcblx0XHR9XHJcblxyXG5cdFx0alF1ZXJ5KCAnI2RhdGVfYm9va2luZycgKyByZXNvdXJjZV9pZCApLnZhbCggZGF0ZSApO1x0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gQWRkIHNlbGVjdGVkIGRhdGVzIHRvICBoaWRkZW4gdGV4dGFyZWFcclxuXHJcblxyXG5cdFx0aWYgKCAnZnVuY3Rpb24nID09PSB0eXBlb2YgKHdwYmNfX2NhbGVuZGFyX19kb19kYXlzX3NlbGVjdF9fYnMpICkge1xyXG5cdFx0XHR3cGJjX19jYWxlbmRhcl9fZG9fZGF5c19zZWxlY3RfX2JzKCBkYXRlLCByZXNvdXJjZV9pZCApO1xyXG5cdFx0fSBlbHNlIGlmICggJ2R5bmFtaWMnID09PSBfd3BiYy5jYWxlbmRhcl9fZ2V0X3BhcmFtX3ZhbHVlKCByZXNvdXJjZV9pZCwgJ2RheXNfc2VsZWN0X21vZGUnICkgKSB7XHJcblx0XHRcdHdwYmNfX2NhbGVuZGFyX19kb19kYXlzX3NlbGVjdF9fdW5yZXN0cmljdGVkX3JhbmdlKCBkYXRlLCByZXNvdXJjZV9pZCApO1xyXG5cdFx0fVxyXG5cclxuXHRcdHdwYmNfcmFuZ2Vfc2VsZWN0aW9uX19zeW5jX2d1aWRhbmNlKCByZXNvdXJjZV9pZCApO1xyXG5cclxuXHRcdHdwYmNfZGlzYWJsZV90aW1lX2ZpZWxkc19pbl9ib29raW5nX2Zvcm0oIHJlc291cmNlX2lkICk7XHJcblxyXG5cdFx0Ly8gSG9vayAtLSB0cmlnZ2VyIGRheSBzZWxlY3Rpb24gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdHZhciBtb3VzZV9jbGlja2VkX2RhdGVzID0gZGF0ZTtcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vIENhbiBiZTogXCIwNS4xMC4yMDIzIC0gMDcuMTAuMjAyM1wiICB8ICBcIjEwLjEwLjIwMjMgLSAxMC4xMC4yMDIzXCIgIHxcclxuXHRcdHZhciBhbGxfc2VsZWN0ZWRfZGF0ZXNfYXJyID0gd3BiY19nZXRfX3NlbGVjdGVkX2RhdGVzX3NxbF9fYXNfYXJyKCByZXNvdXJjZV9pZCApO1x0XHRcdFx0XHRcdFx0XHRcdC8vIENhbiBiZTogWyBcIjIwMjMtMTAtMDVcIiwgXCIyMDIzLTEwLTA2XCIsIFwiMjAyMy0xMC0wN1wiLCDigKYgXVxyXG5cdFx0alF1ZXJ5KCBcIi5ib29raW5nX2Zvcm1fZGl2XCIgKS50cmlnZ2VyKCBcImRhdGVfc2VsZWN0ZWRcIiwgWyByZXNvdXJjZV9pZCwgbW91c2VfY2xpY2tlZF9kYXRlcywgYWxsX3NlbGVjdGVkX2RhdGVzX2FyciBdICk7XHJcblx0fVxyXG5cclxuXHQvLyBNYXJrIG1pZGRsZSBzZWxlY3RlZCBkYXRlcyB3aXRoIDAuNSBvcGFjaXR5XHRcdC8vIEZpeEluOiAxMC4zLjAuOS5cclxuXHRqUXVlcnkoIGRvY3VtZW50ICkucmVhZHkoIGZ1bmN0aW9uICgpe1xyXG5cdFx0alF1ZXJ5KCBcIi5ib29raW5nX2Zvcm1fZGl2XCIgKS5vbiggJ2RhdGVfc2VsZWN0ZWQnLCBmdW5jdGlvbiAoIGV2ZW50LCByZXNvdXJjZV9pZCwgZGF0ZSApe1xyXG5cdFx0XHRcdGlmIChcclxuXHRcdFx0XHRcdCAgICggICdmaXhlZCcgPT09IF93cGJjLmNhbGVuZGFyX19nZXRfcGFyYW1fdmFsdWUoIHJlc291cmNlX2lkLCAnZGF5c19zZWxlY3RfbW9kZScgKSlcclxuXHRcdFx0XHRcdHx8ICgnZHluYW1pYycgPT09IF93cGJjLmNhbGVuZGFyX19nZXRfcGFyYW1fdmFsdWUoIHJlc291cmNlX2lkLCAnZGF5c19zZWxlY3RfbW9kZScgKSlcclxuXHRcdFx0XHQpe1xyXG5cdFx0XHRcdFx0dmFyIGNsb3NlZF90aW1lciA9IHNldFRpbWVvdXQoIGZ1bmN0aW9uICgpe1xyXG5cdFx0XHRcdFx0XHR2YXIgbWlkZGxlX2RheXNfb3BhY2l0eSA9IF93cGJjLmdldF9vdGhlcl9wYXJhbSggJ2NhbGVuZGFyc19fZGF5c19zZWxlY3Rpb25fX21pZGRsZV9kYXlzX29wYWNpdHknICk7XHJcblx0XHRcdFx0XHRcdGpRdWVyeSggJyNjYWxlbmRhcl9ib29raW5nJyArIHJlc291cmNlX2lkICsgJyAuZGF0ZXBpY2stY3VycmVudC1kYXknICkubm90KCBcIi5zZWxlY3RlZF9jaGVja19pbl9vdXRcIiApLmNzcyggJ29wYWNpdHknLCBtaWRkbGVfZGF5c19vcGFjaXR5ICk7XHJcblx0XHRcdFx0XHR9LCAxMCApO1xyXG5cdFx0XHRcdH1cclxuXHRcdH0gKTtcclxuXHR9ICk7XHJcblxyXG5cclxuXHQvKipcclxuXHQgKiAtLSAgVCBpIG0gZSAgICBGIGkgZSBsIGQgcyAgICAgc3RhcnQgIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0ICovXHJcblxyXG5cdC8qKlxyXG5cdCAqIERpc2FibGUgdGltZSBzbG90cyBpbiBib29raW5nIGZvcm0gZGVwZW5kIG9uIHNlbGVjdGVkIGRhdGVzIGFuZCBib29rZWQgZGF0ZXMvdGltZXNcclxuXHQgKlxyXG5cdCAqIEBwYXJhbSByZXNvdXJjZV9pZFxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdwYmNfZGlzYWJsZV90aW1lX2ZpZWxkc19pbl9ib29raW5nX2Zvcm0oIHJlc291cmNlX2lkICl7XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiBcdDEuIEdldCBhbGwgdGltZSBmaWVsZHMgaW4gdGhlIGJvb2tpbmcgZm9ybSBhcyBhcnJheSAgb2Ygb2JqZWN0c1xyXG5cdFx0ICogXHRcdFx0XHRcdFtcclxuXHRcdCAqIFx0XHRcdFx0XHQgXHQgICB7XHRqcXVlcnlfb3B0aW9uOiAgICAgIGpRdWVyeV9PYmplY3Qge31cclxuXHRcdCAqIFx0XHRcdFx0XHRcdFx0XHRuYW1lOiAgICAgICAgICAgICAgICdyYW5nZXRpbWUyW10nXHJcblx0XHQgKiBcdFx0XHRcdFx0XHRcdFx0dGltZXNfYXNfc2Vjb25kczogICBbIDIxNjAwLCAyMzQwMCBdXHJcblx0XHQgKiBcdFx0XHRcdFx0XHRcdFx0dmFsdWVfb3B0aW9uXzI0aDogICAnMDY6MDAgLSAwNjozMCdcclxuXHRcdCAqIFx0XHRcdFx0XHQgICAgIH1cclxuXHRcdCAqIFx0XHRcdFx0XHQgIC4uLlxyXG5cdFx0ICogXHRcdFx0XHRcdFx0ICAge1x0anF1ZXJ5X29wdGlvbjogICAgICBqUXVlcnlfT2JqZWN0IHt9XHJcblx0XHQgKiBcdFx0XHRcdFx0XHRcdFx0bmFtZTogICAgICAgICAgICAgICAnc3RhcnR0aW1lMltdJ1xyXG5cdFx0ICogXHRcdFx0XHRcdFx0XHRcdHRpbWVzX2FzX3NlY29uZHM6ICAgWyAyMTYwMCBdXHJcblx0XHQgKiBcdFx0XHRcdFx0XHRcdFx0dmFsdWVfb3B0aW9uXzI0aDogICAnMDY6MDAnXHJcblx0XHQgKiAgXHRcdFx0XHRcdCAgICB9XHJcblx0XHQgKiBcdFx0XHRcdFx0IF1cclxuXHRcdCAqL1xyXG5cdFx0dmFyIHRpbWVfZmllbGRzX29ial9hcnIgPSB3cGJjX2dldF9fdGltZV9maWVsZHNfX2luX2Jvb2tpbmdfZm9ybV9fYXNfYXJyKCByZXNvdXJjZV9pZCApO1xyXG5cclxuXHRcdC8vIDIuIEdldCBhbGwgc2VsZWN0ZWQgZGF0ZXMgaW4gIFNRTCBmb3JtYXQgIGxpa2UgdGhpcyBbIFwiMjAyMy0wOC0yM1wiLCBcIjIwMjMtMDgtMjRcIiwgXCIyMDIzLTA4LTI1XCIsIC4uLiBdXHJcblx0XHR2YXIgc2VsZWN0ZWRfZGF0ZXNfYXJyID0gd3BiY19nZXRfX3NlbGVjdGVkX2RhdGVzX3NxbF9fYXNfYXJyKCByZXNvdXJjZV9pZCApO1xyXG5cclxuXHRcdC8vIDMuIEdldCBjaGlsZCBib29raW5nIHJlc291cmNlcyAgb3Igc2luZ2xlIGJvb2tpbmcgcmVzb3VyY2UgIHRoYXQgIGV4aXN0ICBpbiBkYXRlc1xyXG5cdFx0dmFyIGNoaWxkX3Jlc291cmNlc19hcnIgPSB3cGJjX2Nsb25lX29iaiggX3dwYmMuYm9va2luZ19fZ2V0X3BhcmFtX3ZhbHVlKCByZXNvdXJjZV9pZCwgJ3Jlc291cmNlc19pZF9hcnJfX2luX2RhdGVzJyApICk7XHJcblxyXG5cdFx0dmFyIHNxbF9kYXRlO1xyXG5cdFx0dmFyIGNoaWxkX3Jlc291cmNlX2lkO1xyXG5cdFx0dmFyIG1lcmdlZF9zZWNvbmRzO1xyXG5cdFx0dmFyIHRpbWVfZmllbGRzX29iajtcclxuXHRcdHZhciBpc19pbnRlcnNlY3Q7XHJcblx0XHR2YXIgaXNfY2hlY2tfaW47XHJcblxyXG5cdFx0dmFyIHRvZGF5X3RpbWVfX3JlYWwgID0gbmV3IERhdGUoIF93cGJjLmdldF9vdGhlcl9wYXJhbSggJ3RpbWVfbG9jYWxfYXJyJyApWzBdLCAoIHBhcnNlSW50KCBfd3BiYy5nZXRfb3RoZXJfcGFyYW0oICd0aW1lX2xvY2FsX2FycicgKVsxXSApIC0gMSksIF93cGJjLmdldF9vdGhlcl9wYXJhbSggJ3RpbWVfbG9jYWxfYXJyJyApWzJdLCBfd3BiYy5nZXRfb3RoZXJfcGFyYW0oICd0aW1lX2xvY2FsX2FycicgKVszXSwgX3dwYmMuZ2V0X290aGVyX3BhcmFtKCAndGltZV9sb2NhbF9hcnInIClbNF0sIDAgKTtcclxuXHRcdHZhciB0b2RheV90aW1lX19zaGlmdCA9IG5ldyBEYXRlKCBfd3BiYy5nZXRfb3RoZXJfcGFyYW0oICd0b2RheV9hcnInICAgICAgKVswXSwgKCBwYXJzZUludCggX3dwYmMuZ2V0X290aGVyX3BhcmFtKCAgICAgICd0b2RheV9hcnInIClbMV0gKSAtIDEpLCBfd3BiYy5nZXRfb3RoZXJfcGFyYW0oICd0b2RheV9hcnInICAgICAgKVsyXSwgX3dwYmMuZ2V0X290aGVyX3BhcmFtKCAndG9kYXlfYXJyJyAgICAgIClbM10sIF93cGJjLmdldF9vdGhlcl9wYXJhbSggJ3RvZGF5X2FycicgICAgICApWzRdLCAwICk7XHJcblx0XHR2YXIgYWxsb3dfcGFzdF9jb250ZXh0ID0gX3dwYmMuZ2V0X290aGVyX3BhcmFtKCAndGhpc19wYWdlX2FsbG93X3Bhc3QnICk7XHJcblx0XHR2YXIgZWRpdF9ib29raW5nX2hhc2hfY29udGV4dCA9IF93cGJjLmdldF9vdGhlcl9wYXJhbSggJ3RoaXNfcGFnZV9ib29raW5nX2hhc2gnICk7XHJcblx0XHR2YXIgaXNfYWxsb3dfcGFzdF9jb250ZXh0ID1cclxuXHRcdFx0ICAgKCAnMScgPT09IFN0cmluZyggYWxsb3dfcGFzdF9jb250ZXh0ICkgKVxyXG5cdFx0XHR8fCAoIDEgPT09IGFsbG93X3Bhc3RfY29udGV4dCApXHJcblx0XHRcdHx8ICggdHJ1ZSA9PT0gYWxsb3dfcGFzdF9jb250ZXh0IClcclxuXHRcdFx0fHwgKCAnJyAhPT0gU3RyaW5nKCBlZGl0X2Jvb2tpbmdfaGFzaF9jb250ZXh0IHx8ICcnICkgKVxyXG5cdFx0XHR8fCAoIGxvY2F0aW9uLmhyZWYuaW5kZXhPZiggJ2Jvb2tpbmdfaGFzaCcgKSA+IC0xIClcclxuXHRcdFx0fHwgKCBsb2NhdGlvbi5ocmVmLmluZGV4T2YoICdhbGxvd19wYXN0JyApID4gLTEgKTtcclxuXHJcblx0XHQvLyA0LiBMb29wICBhbGwgIHRpbWUgRmllbGRzIG9wdGlvbnNcdFx0Ly8gRml4SW46IDEwLjMuMC4yLlxyXG5cdFx0Zm9yICggbGV0IGZpZWxkX2tleSA9IDA7IGZpZWxkX2tleSA8IHRpbWVfZmllbGRzX29ial9hcnIubGVuZ3RoOyBmaWVsZF9rZXkrKyApe1xyXG5cclxuXHRcdFx0dGltZV9maWVsZHNfb2JqX2FyclsgZmllbGRfa2V5IF0uZGlzYWJsZWQgPSAwOyAgICAgICAgICAvLyBCeSBkZWZhdWx0LCB0aGlzIHRpbWUgZmllbGQgaXMgbm90IGRpc2FibGVkLlxyXG5cclxuXHRcdFx0dGltZV9maWVsZHNfb2JqID0gdGltZV9maWVsZHNfb2JqX2FyclsgZmllbGRfa2V5IF07XHRcdC8vIHsgdGltZXNfYXNfc2Vjb25kczogWyAyMTYwMCwgMjM0MDAgXSwgdmFsdWVfb3B0aW9uXzI0aDogJzA2OjAwIC0gMDY6MzAnLCBuYW1lOiAncmFuZ2V0aW1lMltdJywganF1ZXJ5X29wdGlvbjogalF1ZXJ5X09iamVjdCB7fX1cclxuXHJcblx0XHRcdC8vIExvb3AgIGFsbCAgc2VsZWN0ZWQgZGF0ZXMuXHJcblx0XHRcdGZvciAoIHZhciBpID0gMDsgaSA8IHNlbGVjdGVkX2RhdGVzX2Fyci5sZW5ndGg7IGkrKyApIHtcclxuXHJcblx0XHRcdFx0Ly8gR2V0IERhdGU6ICcyMDIzLTA4LTE4Jy5cclxuXHRcdFx0XHRzcWxfZGF0ZSA9IHNlbGVjdGVkX2RhdGVzX2FycltpXTtcclxuXHJcblx0XHRcdFx0dmFyIGlzX3RpbWVfaW5fcGFzdCA9IGlzX2FsbG93X3Bhc3RfY29udGV4dCA/IGZhbHNlIDogd3BiY19jaGVja19pc190aW1lX2luX3Bhc3QoIHRvZGF5X3RpbWVfX3NoaWZ0LCBzcWxfZGF0ZSwgdGltZV9maWVsZHNfb2JqICk7XHJcblx0XHRcdFx0Ly8gRXhjZXB0aW9uICBmb3IgJ0VuZCBUaW1lJyBmaWVsZCwgIHdoZW4gIHNlbGVjdGVkIHNldmVyYWwgZGF0ZXMuIC8vIEZpeEluOiAxMC4xNC4xLjUuXHJcblx0XHRcdFx0aWYgKCAoICEgaXNfYWxsb3dfcGFzdF9jb250ZXh0ICkgJiZcclxuXHRcdFx0XHRcdCgnT24nICE9PSBfd3BiYy5jYWxlbmRhcl9fZ2V0X3BhcmFtX3ZhbHVlKCByZXNvdXJjZV9pZCwgJ2Jvb2tpbmdfcmVjdXJyZW50X3RpbWUnICkpICYmXHJcblx0XHRcdFx0XHQoLTEgIT09IHRpbWVfZmllbGRzX29iai5uYW1lLmluZGV4T2YoICdlbmR0aW1lJyApKSAmJlxyXG5cdFx0XHRcdFx0KHNlbGVjdGVkX2RhdGVzX2Fyci5sZW5ndGggPiAxKVxyXG5cdFx0XHRcdCkge1xyXG5cdFx0XHRcdFx0aXNfdGltZV9pbl9wYXN0ID0gd3BiY19jaGVja19pc190aW1lX2luX3Bhc3QoIHRvZGF5X3RpbWVfX3NoaWZ0LCBzZWxlY3RlZF9kYXRlc19hcnJbKHNlbGVjdGVkX2RhdGVzX2Fyci5sZW5ndGggLSAxKV0sIHRpbWVfZmllbGRzX29iaiApO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0XHRpZiAoIGlzX3RpbWVfaW5fcGFzdCApIHtcclxuXHRcdFx0XHRcdC8vIFRoaXMgdGltZSBmb3Igc2VsZWN0ZWQgZGF0ZSBhbHJlYWR5ICBpbiB0aGUgcGFzdC5cclxuXHRcdFx0XHRcdHRpbWVfZmllbGRzX29ial9hcnJbZmllbGRfa2V5XS5kaXNhYmxlZCA9IDE7XHJcblx0XHRcdFx0XHRicmVhaztcdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gZXhpc3QgIGZyb20gICBEYXRlcyBMT09QLlxyXG5cdFx0XHRcdH1cclxuXHRcdFx0XHQvLyBGaXhJbjogOS45LjAuMzEuXHJcblx0XHRcdFx0aWYgKFxyXG5cdFx0XHRcdFx0ICAgKCAnT2ZmJyA9PT0gX3dwYmMuY2FsZW5kYXJfX2dldF9wYXJhbV92YWx1ZSggcmVzb3VyY2VfaWQsICdib29raW5nX3JlY3VycmVudF90aW1lJyApIClcclxuXHRcdFx0XHRcdCYmICggc2VsZWN0ZWRfZGF0ZXNfYXJyLmxlbmd0aD4xIClcclxuXHRcdFx0XHQpe1xyXG5cdFx0XHRcdFx0Ly9UT0RPOiBza2lwIHNvbWUgZmllbGRzIGNoZWNraW5nIGlmIGl0J3Mgc3RhcnQgLyBlbmQgdGltZSBmb3IgbXVscGxlIGRhdGVzICBzZWxlY3Rpb24gIG1vZGUuXHJcblx0XHRcdFx0XHQvL1RPRE86IHdlIG5lZWQgdG8gZml4IHNpdHVhdGlvbiAgZm9yIGVudGltZXMsICB3aGVuICB1c2VyICBzZWxlY3QgIHNldmVyYWwgIGRhdGVzLCAgYW5kIGluIHN0YXJ0ICB0aW1lIGJvb2tlZCAwMDowMCAtIDE1OjAwICwgYnV0IHN5c3RzbWUgYmxvY2sgdW50aWxsIDE1OjAwIHRoZSBlbmQgdGltZSBhcyB3ZWxsLCAgd2hpY2ggIGlzIHdyb25nLCAgYmVjYXVzZSBpdCAyIG9yIDMgZGF0ZXMgc2VsZWN0aW9uICBhbmQgZW5kIGRhdGUgY2FuIGJlIGZ1bGx1ICBhdmFpbGFibGVcclxuXHJcblx0XHRcdFx0XHRpZiAoICgwID09IGkpICYmICh0aW1lX2ZpZWxkc19vYmpbICduYW1lJyBdLmluZGV4T2YoICdlbmR0aW1lJyApID49IDApICl7XHJcblx0XHRcdFx0XHRcdGJyZWFrO1xyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0aWYgKCAoIChzZWxlY3RlZF9kYXRlc19hcnIubGVuZ3RoLTEpID09IGkgKSAmJiAodGltZV9maWVsZHNfb2JqWyAnbmFtZScgXS5pbmRleE9mKCAnc3RhcnR0aW1lJyApID49IDApICl7XHJcblx0XHRcdFx0XHRcdGJyZWFrO1xyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdH1cclxuXHJcblxyXG5cclxuXHRcdFx0XHR2YXIgaG93X21hbnlfcmVzb3VyY2VzX2ludGVyc2VjdGVkID0gMDtcclxuXHRcdFx0XHQvLyBMb29wIGFsbCByZXNvdXJjZXMgSURcclxuXHRcdFx0XHRcdC8vIGZvciAoIHZhciByZXNfa2V5IGluIGNoaWxkX3Jlc291cmNlc19hcnIgKXtcdCBcdFx0XHRcdFx0XHQvLyBGaXhJbjogMTAuMy4wLjIuXHJcblx0XHRcdFx0aWYgKCBudWxsID09PSBjaGlsZF9yZXNvdXJjZXNfYXJyICkge1xyXG5cdFx0XHRcdFx0Y2hpbGRfcmVzb3VyY2VzX2FyciA9IFtdO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0XHRmb3IgKCBsZXQgcmVzX2tleSA9IDA7IHJlc19rZXkgPCBjaGlsZF9yZXNvdXJjZXNfYXJyLmxlbmd0aDsgcmVzX2tleSsrICl7XHJcblxyXG5cdFx0XHRcdFx0Y2hpbGRfcmVzb3VyY2VfaWQgPSBjaGlsZF9yZXNvdXJjZXNfYXJyWyByZXNfa2V5IF07XHJcblxyXG5cdFx0XHRcdFx0Ly8gX3dwYmMuYm9va2luZ3NfaW5fY2FsZW5kYXJfX2dldF9mb3JfZGF0ZSgyLCcyMDIzLTA4LTIxJylbMTJdLmJvb2tlZF90aW1lX3Nsb3RzLm1lcmdlZF9zZWNvbmRzXHRcdD0gWyBcIjA3OjAwOjExIC0gMDc6MzA6MDJcIiwgXCIxMDowMDoxMSAtIDAwOjAwOjAwXCIgXVxyXG5cdFx0XHRcdFx0Ly8gX3dwYmMuYm9va2luZ3NfaW5fY2FsZW5kYXJfX2dldF9mb3JfZGF0ZSgyLCcyMDIzLTA4LTIxJylbMl0uYm9va2VkX3RpbWVfc2xvdHMubWVyZ2VkX3NlY29uZHNcdFx0XHQ9IFsgIFsgMjUyMTEsIDI3MDAyIF0sIFsgMzYwMTEsIDg2NDAwIF0gIF1cclxuXHJcblx0XHRcdFx0XHRpZiAoIGZhbHNlICE9PSBfd3BiYy5ib29raW5nc19pbl9jYWxlbmRhcl9fZ2V0X2Zvcl9kYXRlKCByZXNvdXJjZV9pZCwgc3FsX2RhdGUgKSApe1xyXG5cdFx0XHRcdFx0XHRtZXJnZWRfc2Vjb25kcyA9IF93cGJjLmJvb2tpbmdzX2luX2NhbGVuZGFyX19nZXRfZm9yX2RhdGUoIHJlc291cmNlX2lkLCBzcWxfZGF0ZSApWyBjaGlsZF9yZXNvdXJjZV9pZCBdLmJvb2tlZF90aW1lX3Nsb3RzLm1lcmdlZF9zZWNvbmRzO1x0XHQvLyBbICBbIDI1MjExLCAyNzAwMiBdLCBbIDM2MDExLCA4NjQwMCBdICBdXHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdFx0XHRtZXJnZWRfc2Vjb25kcyA9IFtdO1xyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0aWYgKCB0aW1lX2ZpZWxkc19vYmoudGltZXNfYXNfc2Vjb25kcy5sZW5ndGggPiAxICl7XHJcblx0XHRcdFx0XHRcdGlzX2ludGVyc2VjdCA9IHdwYmNfaXNfaW50ZXJzZWN0X19yYW5nZV90aW1lX2ludGVydmFsKCAgW1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRbXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0KCBwYXJzZUludCggdGltZV9maWVsZHNfb2JqLnRpbWVzX2FzX3NlY29uZHNbMF0gKSArIDIwICksXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0KCBwYXJzZUludCggdGltZV9maWVsZHNfb2JqLnRpbWVzX2FzX3NlY29uZHNbMV0gKSAtIDIwIClcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XVxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XVxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0LCBtZXJnZWRfc2Vjb25kcyApO1xyXG5cdFx0XHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRcdFx0aXNfY2hlY2tfaW4gPSAoLTEgIT09IHRpbWVfZmllbGRzX29iai5uYW1lLmluZGV4T2YoICdzdGFydCcgKSk7XHJcblx0XHRcdFx0XHRcdGlzX2ludGVyc2VjdCA9IHdwYmNfaXNfaW50ZXJzZWN0X19vbmVfdGltZV9pbnRlcnZhbChcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCggKCBpc19jaGVja19pbiApXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQgID8gcGFyc2VJbnQoIHRpbWVfZmllbGRzX29iai50aW1lc19hc19zZWNvbmRzICkgKyAyMFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0ICA6IHBhcnNlSW50KCB0aW1lX2ZpZWxkc19vYmoudGltZXNfYXNfc2Vjb25kcyApIC0gMjBcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdClcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCwgbWVyZ2VkX3NlY29uZHMgKTtcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdGlmIChpc19pbnRlcnNlY3Qpe1xyXG5cdFx0XHRcdFx0XHRob3dfbWFueV9yZXNvdXJjZXNfaW50ZXJzZWN0ZWQrKztcdFx0XHQvLyBJbmNyZWFzZVxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGlmICggY2hpbGRfcmVzb3VyY2VzX2Fyci5sZW5ndGggPT0gaG93X21hbnlfcmVzb3VyY2VzX2ludGVyc2VjdGVkICkge1xyXG5cdFx0XHRcdFx0Ly8gQWxsIHJlc291cmNlcyBpbnRlcnNlY3RlZCwgIHRoZW4gIGl0J3MgbWVhbnMgdGhhdCB0aGlzIHRpbWUtc2xvdCBvciB0aW1lIG11c3QgIGJlICBEaXNhYmxlZCwgYW5kIHdlIGNhbiAgZXhpc3QgIGZyb20gICBzZWxlY3RlZF9kYXRlc19hcnIgTE9PUFxyXG5cclxuXHRcdFx0XHRcdHRpbWVfZmllbGRzX29ial9hcnJbIGZpZWxkX2tleSBdLmRpc2FibGVkID0gMTtcclxuXHRcdFx0XHRcdGJyZWFrO1x0XHRcdFx0XHRcdFx0XHRcdFx0XHQvLyBleGlzdCAgZnJvbSAgIERhdGVzIExPT1BcclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblxyXG5cdFx0Ly8gNS4gTm93IHdlIGNhbiBkaXNhYmxlIHRpbWUgc2xvdCBpbiBIVE1MIGJ5ICB1c2luZyAgKCBmaWVsZC5kaXNhYmxlZCA9PSAxICkgcHJvcGVydHlcclxuXHRcdHdwYmNfX2h0bWxfX3RpbWVfZmllbGRfb3B0aW9uc19fc2V0X2Rpc2FibGVkKCB0aW1lX2ZpZWxkc19vYmpfYXJyICk7XHJcblxyXG5cdFx0alF1ZXJ5KCBcIi5ib29raW5nX2Zvcm1fZGl2XCIgKS50cmlnZ2VyKCAnd3BiY19ob29rX3RpbWVzbG90c19kaXNhYmxlZCcsIFtyZXNvdXJjZV9pZCwgc2VsZWN0ZWRfZGF0ZXNfYXJyXSApO1x0XHRcdFx0XHQvLyBUcmlnZ2VyIGhvb2sgb24gZGlzYWJsaW5nIHRpbWVzbG90cy5cdFx0VXNhZ2U6IFx0alF1ZXJ5KCBcIi5ib29raW5nX2Zvcm1fZGl2XCIgKS5vbiggJ3dwYmNfaG9va190aW1lc2xvdHNfZGlzYWJsZWQnLCBmdW5jdGlvbiAoIGV2ZW50LCBia190eXBlLCBhbGxfZGF0ZXMgKXsgLi4uIH0gKTtcdFx0Ly8gRml4SW46IDguNy4xMS45LlxyXG5cdH1cclxuXHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiBDaGVjayBpZiBzcGVjaWZpYyB0aW1lKC1zbG90KSBhbHJlYWR5ICBpbiB0aGUgcGFzdCBmb3Igc2VsZWN0ZWQgZGF0ZVxyXG5cdFx0ICpcclxuXHRcdCAqIEBwYXJhbSBqc19jdXJyZW50X3RpbWVfdG9fY2hlY2tcdFx0LSBKUyBEYXRlXHJcblx0XHQgKiBAcGFyYW0gc3FsX2RhdGVcdFx0XHRcdFx0XHQtICcyMDI1LTAxLTI2J1xyXG5cdFx0ICogQHBhcmFtIHRpbWVfZmllbGRzX29ialx0XHRcdFx0LSBPYmplY3RcclxuXHRcdCAqIEByZXR1cm5zIHtib29sZWFufVxyXG5cdFx0ICovXHJcblx0XHRmdW5jdGlvbiB3cGJjX2NoZWNrX2lzX3RpbWVfaW5fcGFzdCgganNfY3VycmVudF90aW1lX3RvX2NoZWNrLCBzcWxfZGF0ZSwgdGltZV9maWVsZHNfb2JqICkge1xyXG5cclxuXHRcdFx0Ly8gRml4SW46IDEwLjkuNi40XHJcblx0XHRcdHZhciBzcWxfZGF0ZV9hcnIgPSBzcWxfZGF0ZS5zcGxpdCggJy0nICk7XHJcblx0XHRcdHZhciBzcWxfZGF0ZV9fbWlkbmlnaHQgPSBuZXcgRGF0ZSggcGFyc2VJbnQoIHNxbF9kYXRlX2FyclswXSApLCAoIHBhcnNlSW50KCBzcWxfZGF0ZV9hcnJbMV0gKSAtIDEgKSwgcGFyc2VJbnQoIHNxbF9kYXRlX2FyclsyXSApLCAwLCAwLCAwICk7XHJcblx0XHRcdHZhciBzcWxfZGF0ZV9fbWlkbmlnaHRfbWlsaXNlY29uZHMgPSBzcWxfZGF0ZV9fbWlkbmlnaHQuZ2V0VGltZSgpO1xyXG5cclxuXHRcdFx0dmFyIGlzX2ludGVyc2VjdCA9IGZhbHNlO1xyXG5cclxuXHRcdFx0aWYgKCB0aW1lX2ZpZWxkc19vYmoudGltZXNfYXNfc2Vjb25kcy5sZW5ndGggPiAxICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIGpzX2N1cnJlbnRfdGltZV90b19jaGVjay5nZXRUaW1lKCkgPiAoc3FsX2RhdGVfX21pZG5pZ2h0X21pbGlzZWNvbmRzICsgKHBhcnNlSW50KCB0aW1lX2ZpZWxkc19vYmoudGltZXNfYXNfc2Vjb25kc1swXSApICsgMjApICogMTAwMCkgKSB7XHJcblx0XHRcdFx0XHRpc19pbnRlcnNlY3QgPSB0cnVlO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0XHRpZiAoIGpzX2N1cnJlbnRfdGltZV90b19jaGVjay5nZXRUaW1lKCkgPiAoc3FsX2RhdGVfX21pZG5pZ2h0X21pbGlzZWNvbmRzICsgKHBhcnNlSW50KCB0aW1lX2ZpZWxkc19vYmoudGltZXNfYXNfc2Vjb25kc1sxXSApIC0gMjApICogMTAwMCkgKSB7XHJcblx0XHRcdFx0XHRpc19pbnRlcnNlY3QgPSB0cnVlO1xyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblx0XHRcdFx0dmFyIGlzX2NoZWNrX2luID0gKC0xICE9PSB0aW1lX2ZpZWxkc19vYmoubmFtZS5pbmRleE9mKCAnc3RhcnQnICkpO1xyXG5cclxuXHRcdFx0XHR2YXIgdGltZXNfYXNfc2Vjb25kc19jaGVjayA9IChpc19jaGVja19pbikgPyBwYXJzZUludCggdGltZV9maWVsZHNfb2JqLnRpbWVzX2FzX3NlY29uZHMgKSArIDIwIDogcGFyc2VJbnQoIHRpbWVfZmllbGRzX29iai50aW1lc19hc19zZWNvbmRzICkgLSAyMDtcclxuXHJcblx0XHRcdFx0dGltZXNfYXNfc2Vjb25kc19jaGVjayA9IHNxbF9kYXRlX19taWRuaWdodF9taWxpc2Vjb25kcyArIHRpbWVzX2FzX3NlY29uZHNfY2hlY2sgKiAxMDAwO1xyXG5cclxuXHRcdFx0XHRpZiAoIGpzX2N1cnJlbnRfdGltZV90b19jaGVjay5nZXRUaW1lKCkgPiB0aW1lc19hc19zZWNvbmRzX2NoZWNrICkge1xyXG5cdFx0XHRcdFx0aXNfaW50ZXJzZWN0ID0gdHJ1ZTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHJldHVybiBpc19pbnRlcnNlY3Q7XHJcblx0XHR9XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiBJcyBudW1iZXIgaW5zaWRlIC9pbnRlcnNlY3QgIG9mIGFycmF5IG9mIGludGVydmFscyA/XHJcblx0XHQgKlxyXG5cdFx0ICogQHBhcmFtIHRpbWVfQVx0XHQgICAgIFx0LSAyNTgwMFxyXG5cdFx0ICogQHBhcmFtIHRpbWVfaW50ZXJ2YWxfQlx0XHQtIFsgIFsgMjUyMTEsIDI3MDAyIF0sIFsgMzYwMTEsIDg2NDAwIF0gIF1cclxuXHRcdCAqIEByZXR1cm5zIHtib29sZWFufVxyXG5cdFx0ICovXHJcblx0XHRmdW5jdGlvbiB3cGJjX2lzX2ludGVyc2VjdF9fb25lX3RpbWVfaW50ZXJ2YWwoIHRpbWVfQSwgdGltZV9pbnRlcnZhbF9CICl7XHJcblxyXG5cdFx0XHRmb3IgKCB2YXIgaiA9IDA7IGogPCB0aW1lX2ludGVydmFsX0IubGVuZ3RoOyBqKysgKXtcclxuXHJcblx0XHRcdFx0aWYgKCAocGFyc2VJbnQoIHRpbWVfQSApID4gcGFyc2VJbnQoIHRpbWVfaW50ZXJ2YWxfQlsgaiBdWyAwIF0gKSkgJiYgKHBhcnNlSW50KCB0aW1lX0EgKSA8IHBhcnNlSW50KCB0aW1lX2ludGVydmFsX0JbIGogXVsgMSBdICkpICl7XHJcblx0XHRcdFx0XHRyZXR1cm4gdHJ1ZVxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Ly8gaWYgKCAoIHBhcnNlSW50KCB0aW1lX0EgKSA9PSBwYXJzZUludCggdGltZV9pbnRlcnZhbF9CWyBqIF1bIDAgXSApICkgfHwgKCBwYXJzZUludCggdGltZV9BICkgPT0gcGFyc2VJbnQoIHRpbWVfaW50ZXJ2YWxfQlsgaiBdWyAxIF0gKSApICkge1xyXG5cdFx0XHRcdC8vIFx0XHRcdC8vIFRpbWUgQSBqdXN0ICBhdCAgdGhlIGJvcmRlciBvZiBpbnRlcnZhbFxyXG5cdFx0XHRcdC8vIH1cclxuXHRcdFx0fVxyXG5cclxuXHRcdCAgICByZXR1cm4gZmFsc2U7XHJcblx0XHR9XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiBJcyB0aGVzZSBhcnJheSBvZiBpbnRlcnZhbHMgaW50ZXJzZWN0ZWQgP1xyXG5cdFx0ICpcclxuXHRcdCAqIEBwYXJhbSB0aW1lX2ludGVydmFsX0FcdFx0LSBbIFsgMjE2MDAsIDIzNDAwIF0gXVxyXG5cdFx0ICogQHBhcmFtIHRpbWVfaW50ZXJ2YWxfQlx0XHQtIFsgIFsgMjUyMTEsIDI3MDAyIF0sIFsgMzYwMTEsIDg2NDAwIF0gIF1cclxuXHRcdCAqIEByZXR1cm5zIHtib29sZWFufVxyXG5cdFx0ICovXHJcblx0XHRmdW5jdGlvbiB3cGJjX2lzX2ludGVyc2VjdF9fcmFuZ2VfdGltZV9pbnRlcnZhbCggdGltZV9pbnRlcnZhbF9BLCB0aW1lX2ludGVydmFsX0IgKXtcclxuXHJcblx0XHRcdHZhciBpc19pbnRlcnNlY3Q7XHJcblxyXG5cdFx0XHRmb3IgKCB2YXIgaSA9IDA7IGkgPCB0aW1lX2ludGVydmFsX0EubGVuZ3RoOyBpKysgKXtcclxuXHJcblx0XHRcdFx0Zm9yICggdmFyIGogPSAwOyBqIDwgdGltZV9pbnRlcnZhbF9CLmxlbmd0aDsgaisrICl7XHJcblxyXG5cdFx0XHRcdFx0aXNfaW50ZXJzZWN0ID0gd3BiY19pbnRlcnZhbHNfX2lzX2ludGVyc2VjdGVkKCB0aW1lX2ludGVydmFsX0FbIGkgXSwgdGltZV9pbnRlcnZhbF9CWyBqIF0gKTtcclxuXHJcblx0XHRcdFx0XHRpZiAoIGlzX2ludGVyc2VjdCApe1xyXG5cdFx0XHRcdFx0XHRyZXR1cm4gdHJ1ZTtcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHJldHVybiBmYWxzZTtcclxuXHRcdH1cclxuXHJcblx0XHQvKipcclxuXHRcdCAqIEdldCBhbGwgdGltZSBmaWVsZHMgaW4gdGhlIGJvb2tpbmcgZm9ybSBhcyBhcnJheSAgb2Ygb2JqZWN0c1xyXG5cdFx0ICpcclxuXHRcdCAqIEBwYXJhbSByZXNvdXJjZV9pZFxyXG5cdFx0ICogQHJldHVybnMgW11cclxuXHRcdCAqXHJcblx0XHQgKiBcdFx0RXhhbXBsZTpcclxuXHRcdCAqIFx0XHRcdFx0XHRbXHJcblx0XHQgKiBcdFx0XHRcdFx0IFx0ICAge1xyXG5cdFx0ICogXHRcdFx0XHRcdFx0XHRcdHZhbHVlX29wdGlvbl8yNGg6ICAgJzA2OjAwIC0gMDY6MzAnXHJcblx0XHQgKiBcdFx0XHRcdFx0XHRcdFx0dGltZXNfYXNfc2Vjb25kczogICBbIDIxNjAwLCAyMzQwMCBdXHJcblx0XHQgKiBcdFx0XHRcdFx0IFx0ICAgXHRcdGpxdWVyeV9vcHRpb246ICAgICAgalF1ZXJ5X09iamVjdCB7fVxyXG5cdFx0ICogXHRcdFx0XHRcdFx0XHRcdG5hbWU6ICAgICAgICAgICAgICAgJ3JhbmdldGltZTJbXSdcclxuXHRcdCAqIFx0XHRcdFx0XHQgICAgIH1cclxuXHRcdCAqIFx0XHRcdFx0XHQgIC4uLlxyXG5cdFx0ICogXHRcdFx0XHRcdFx0ICAge1xyXG5cdFx0ICogXHRcdFx0XHRcdFx0XHRcdHZhbHVlX29wdGlvbl8yNGg6ICAgJzA2OjAwJ1xyXG5cdFx0ICogXHRcdFx0XHRcdFx0XHRcdHRpbWVzX2FzX3NlY29uZHM6ICAgWyAyMTYwMCBdXHJcblx0XHQgKiBcdFx0XHRcdFx0XHQgICBcdFx0anF1ZXJ5X29wdGlvbjogICAgICBqUXVlcnlfT2JqZWN0IHt9XHJcblx0XHQgKiBcdFx0XHRcdFx0XHRcdFx0bmFtZTogICAgICAgICAgICAgICAnc3RhcnR0aW1lMltdJ1xyXG5cdFx0ICogIFx0XHRcdFx0XHQgICAgfVxyXG5cdFx0ICogXHRcdFx0XHRcdCBdXHJcblx0XHQgKi9cclxuXHRcdGZ1bmN0aW9uIHdwYmNfZ2V0X190aW1lX2ZpZWxkc19faW5fYm9va2luZ19mb3JtX19hc19hcnIoIHJlc291cmNlX2lkICl7XHJcblx0XHQgICAgLyoqXHJcblx0XHRcdCAqIEZpZWxkcyB3aXRoICBbXSAgbGlrZSB0aGlzICAgc2VsZWN0W25hbWU9XCJyYW5nZXRpbWUxW11cIl1cclxuXHRcdFx0ICogaXQncyB3aGVuIHdlIGhhdmUgJ211bHRpcGxlJyBpbiBzaG9ydGNvZGU6ICAgW3NlbGVjdCogcmFuZ2V0aW1lIG11bHRpcGxlICBcIjA2OjAwIC0gMDY6MzBcIiAuLi4gXVxyXG5cdFx0XHQgKi9cclxuXHRcdFx0dmFyIHRpbWVfZmllbGRzX2Fycj1bXHJcblx0XHRcdFx0XHRcdFx0XHRcdCdzZWxlY3RbbmFtZT1cInJhbmdldGltZScgKyByZXNvdXJjZV9pZCArICdcIl0nLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHQnc2VsZWN0W25hbWU9XCJyYW5nZXRpbWUnICsgcmVzb3VyY2VfaWQgKyAnW11cIl0nLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHQnc2VsZWN0W25hbWU9XCJzdGFydHRpbWUnICsgcmVzb3VyY2VfaWQgKyAnXCJdJyxcclxuXHRcdFx0XHRcdFx0XHRcdFx0J3NlbGVjdFtuYW1lPVwic3RhcnR0aW1lJyArIHJlc291cmNlX2lkICsgJ1tdXCJdJyxcclxuXHRcdFx0XHRcdFx0XHRcdFx0J3NlbGVjdFtuYW1lPVwiZW5kdGltZScgKyByZXNvdXJjZV9pZCArICdcIl0nLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHQnc2VsZWN0W25hbWU9XCJlbmR0aW1lJyArIHJlc291cmNlX2lkICsgJ1tdXCJdJ1xyXG5cdFx0XHRcdFx0XHRcdFx0XTtcclxuXHJcblx0XHRcdHZhciB0aW1lX2ZpZWxkc19vYmpfYXJyID0gW107XHJcblxyXG5cdFx0XHQvLyBMb29wIGFsbCBUaW1lIEZpZWxkc1xyXG5cdFx0XHRmb3IgKCB2YXIgY3RmPSAwOyBjdGYgPCB0aW1lX2ZpZWxkc19hcnIubGVuZ3RoOyBjdGYrKyApe1xyXG5cclxuXHRcdFx0XHR2YXIgdGltZV9maWVsZCA9IHRpbWVfZmllbGRzX2FyclsgY3RmIF07XHJcblx0XHRcdFx0dmFyIHRpbWVfb3B0aW9uID0galF1ZXJ5KCB0aW1lX2ZpZWxkICsgJyBvcHRpb24nICk7XHJcblxyXG5cdFx0XHRcdC8vIExvb3AgYWxsIG9wdGlvbnMgaW4gdGltZSBmaWVsZFxyXG5cdFx0XHRcdGZvciAoIHZhciBqID0gMDsgaiA8IHRpbWVfb3B0aW9uLmxlbmd0aDsgaisrICl7XHJcblxyXG5cdFx0XHRcdFx0dmFyIGpxdWVyeV9vcHRpb24gPSBqUXVlcnkoIHRpbWVfZmllbGQgKyAnIG9wdGlvbjplcSgnICsgaiArICcpJyApO1xyXG5cdFx0XHRcdFx0dmFyIHZhbHVlX29wdGlvbl9zZWNvbmRzX2FyciA9IGpxdWVyeV9vcHRpb24udmFsKCkuc3BsaXQoICctJyApO1xyXG5cdFx0XHRcdFx0dmFyIHRpbWVzX2FzX3NlY29uZHMgPSBbXTtcclxuXHJcblx0XHRcdFx0XHQvLyBHZXQgdGltZSBhcyBzZWNvbmRzXHJcblx0XHRcdFx0XHRpZiAoIHZhbHVlX29wdGlvbl9zZWNvbmRzX2Fyci5sZW5ndGggKXtcdFx0XHRcdFx0XHRcdFx0XHQvLyBGaXhJbjogOS44LjEwLjEuXHJcblx0XHRcdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHZhbHVlX29wdGlvbl9zZWNvbmRzX2Fyci5sZW5ndGg7IGkrKyApe1x0XHQvLyBGaXhJbjogMTAuMC4wLjU2LlxyXG5cdFx0XHRcdFx0XHRcdC8vIHZhbHVlX29wdGlvbl9zZWNvbmRzX2FycltpXSA9ICcxNDowMCAnICB8ICcgMTY6MDAnICAgKGlmIGZyb20gJ3JhbmdldGltZScpIGFuZCAnMTY6MDAnICBpZiAoc3RhcnQvZW5kIHRpbWUpXHJcblxyXG5cdFx0XHRcdFx0XHRcdHZhciBzdGFydF9lbmRfdGltZXNfYXJyID0gdmFsdWVfb3B0aW9uX3NlY29uZHNfYXJyWyBpIF0udHJpbSgpLnNwbGl0KCAnOicgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0dmFyIHRpbWVfaW5fc2Vjb25kcyA9IHBhcnNlSW50KCBzdGFydF9lbmRfdGltZXNfYXJyWyAwIF0gKSAqIDYwICogNjAgKyBwYXJzZUludCggc3RhcnRfZW5kX3RpbWVzX2FyclsgMSBdICkgKiA2MDtcclxuXHJcblx0XHRcdFx0XHRcdFx0dGltZXNfYXNfc2Vjb25kcy5wdXNoKCB0aW1lX2luX3NlY29uZHMgKTtcclxuXHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdHRpbWVfZmllbGRzX29ial9hcnIucHVzaCgge1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnbmFtZScgICAgICAgICAgICA6IGpRdWVyeSggdGltZV9maWVsZCApLmF0dHIoICduYW1lJyApLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQndmFsdWVfb3B0aW9uXzI0aCc6IGpxdWVyeV9vcHRpb24udmFsKCksXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCdqcXVlcnlfb3B0aW9uJyAgIDoganF1ZXJ5X29wdGlvbixcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J3RpbWVzX2FzX3NlY29uZHMnOiB0aW1lc19hc19zZWNvbmRzXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHR9ICk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZXR1cm4gdGltZV9maWVsZHNfb2JqX2FycjtcclxuXHRcdH1cclxuXHJcblx0XHRcdC8qKlxyXG5cdFx0XHQgKiBEaXNhYmxlIEhUTUwgb3B0aW9ucyBhbmQgYWRkIGJvb2tlZCBDU1MgY2xhc3NcclxuXHRcdFx0ICpcclxuXHRcdFx0ICogQHBhcmFtIHRpbWVfZmllbGRzX29ial9hcnIgICAgICAtIHRoaXMgdmFsdWUgaXMgZnJvbSAgdGhlIGZ1bmM6XHJcblx0XHRcdCAqICAgICBcdHdwYmNfZ2V0X190aW1lX2ZpZWxkc19faW5fYm9va2luZ19mb3JtX19hc19hcnIoIHJlc291cmNlX2lkIClcclxuXHRcdFx0ICogXHRcdFx0XHRcdFtcclxuXHRcdFx0ICogXHRcdFx0XHRcdCBcdCAgIHtcdGpxdWVyeV9vcHRpb246ICAgICAgalF1ZXJ5X09iamVjdCB7fVxyXG5cdFx0XHQgKiBcdFx0XHRcdFx0XHRcdFx0bmFtZTogICAgICAgICAgICAgICAncmFuZ2V0aW1lMltdJ1xyXG5cdFx0XHQgKiBcdFx0XHRcdFx0XHRcdFx0dGltZXNfYXNfc2Vjb25kczogICBbIDIxNjAwLCAyMzQwMCBdXHJcblx0XHRcdCAqIFx0XHRcdFx0XHRcdFx0XHR2YWx1ZV9vcHRpb25fMjRoOiAgICcwNjowMCAtIDA2OjMwJ1xyXG5cdFx0XHQgKiBcdCAgXHRcdFx0XHRcdFx0ICAgIGRpc2FibGVkID0gMVxyXG5cdFx0XHQgKiBcdFx0XHRcdFx0ICAgICB9XHJcblx0XHRcdCAqIFx0XHRcdFx0XHQgIC4uLlxyXG5cdFx0XHQgKiBcdFx0XHRcdFx0XHQgICB7XHRqcXVlcnlfb3B0aW9uOiAgICAgIGpRdWVyeV9PYmplY3Qge31cclxuXHRcdFx0ICogXHRcdFx0XHRcdFx0XHRcdG5hbWU6ICAgICAgICAgICAgICAgJ3N0YXJ0dGltZTJbXSdcclxuXHRcdFx0ICogXHRcdFx0XHRcdFx0XHRcdHRpbWVzX2FzX3NlY29uZHM6ICAgWyAyMTYwMCBdXHJcblx0XHRcdCAqIFx0XHRcdFx0XHRcdFx0XHR2YWx1ZV9vcHRpb25fMjRoOiAgICcwNjowMCdcclxuXHRcdFx0ICogICBcdFx0XHRcdFx0XHRcdGRpc2FibGVkID0gMFxyXG5cdFx0XHQgKiAgXHRcdFx0XHRcdCAgICB9XHJcblx0XHRcdCAqIFx0XHRcdFx0XHQgXVxyXG5cdFx0XHQgKlxyXG5cdFx0XHQgKi9cclxuXHRcdFx0ZnVuY3Rpb24gd3BiY19faHRtbF9fdGltZV9maWVsZF9vcHRpb25zX19zZXRfZGlzYWJsZWQoIHRpbWVfZmllbGRzX29ial9hcnIgKXtcclxuXHJcblx0XHRcdFx0dmFyIGpxdWVyeV9vcHRpb247XHJcblxyXG5cdFx0XHRcdGZvciAoIHZhciBpID0gMDsgaSA8IHRpbWVfZmllbGRzX29ial9hcnIubGVuZ3RoOyBpKysgKXtcclxuXHJcblx0XHRcdFx0XHR2YXIganF1ZXJ5X29wdGlvbiA9IHRpbWVfZmllbGRzX29ial9hcnJbIGkgXS5qcXVlcnlfb3B0aW9uO1xyXG5cclxuXHRcdFx0XHRcdGlmICggMSA9PSB0aW1lX2ZpZWxkc19vYmpfYXJyWyBpIF0uZGlzYWJsZWQgKXtcclxuXHRcdFx0XHRcdFx0anF1ZXJ5X29wdGlvbi5wcm9wKCAnZGlzYWJsZWQnLCB0cnVlICk7IFx0XHQvLyBNYWtlIGRpc2FibGUgc29tZSBvcHRpb25zXHJcblx0XHRcdFx0XHRcdGpxdWVyeV9vcHRpb24uYWRkQ2xhc3MoICdib29rZWQnICk7ICAgICAgICAgICBcdC8vIEFkZCBcImJvb2tlZFwiIENTUyBjbGFzc1xyXG5cclxuXHRcdFx0XHRcdFx0Ly8gaWYgdGhpcyBib29rZWQgZWxlbWVudCBzZWxlY3RlZCAtLT4gdGhlbiBkZXNlbGVjdCAgaXRcclxuXHRcdFx0XHRcdFx0aWYgKCBqcXVlcnlfb3B0aW9uLnByb3AoICdzZWxlY3RlZCcgKSApe1xyXG5cdFx0XHRcdFx0XHRcdGpxdWVyeV9vcHRpb24ucHJvcCggJ3NlbGVjdGVkJywgZmFsc2UgKTtcclxuXHJcblx0XHRcdFx0XHRcdFx0anF1ZXJ5X29wdGlvbi5wYXJlbnQoKS5maW5kKCAnb3B0aW9uOm5vdChbZGlzYWJsZWRdKTpmaXJzdCcgKS5wcm9wKCAnc2VsZWN0ZWQnLCB0cnVlICkudHJpZ2dlciggXCJjaGFuZ2VcIiApO1xyXG5cdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRcdFx0anF1ZXJ5X29wdGlvbi5wcm9wKCAnZGlzYWJsZWQnLCBmYWxzZSApOyAgXHRcdC8vIE1ha2UgYWN0aXZlIGFsbCB0aW1lc1xyXG5cdFx0XHRcdFx0XHRqcXVlcnlfb3B0aW9uLnJlbW92ZUNsYXNzKCAnYm9va2VkJyApOyAgIFx0XHQvLyBSZW1vdmUgY2xhc3MgXCJib29rZWRcIlxyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0LyoqXHJcblx0ICogQ2hlY2sgaWYgdGhpcyB0aW1lX3JhbmdlIHwgVGltZV9TbG90IGlzIEZ1bGwgRGF5ICBib29rZWRcclxuXHQgKlxyXG5cdCAqIEBwYXJhbSB0aW1lc2xvdF9hcnJfaW5fc2Vjb25kc1x0XHQtIFsgMzYwMTEsIDg2NDAwIF1cclxuXHQgKiBAcmV0dXJucyB7Ym9vbGVhbn1cclxuXHQgKi9cclxuXHRmdW5jdGlvbiB3cGJjX2lzX3RoaXNfdGltZXNsb3RfX2Z1bGxfZGF5X2Jvb2tlZCggdGltZXNsb3RfYXJyX2luX3NlY29uZHMgKXtcclxuXHJcblx0XHRpZiAoXHJcblx0XHRcdFx0KCB0aW1lc2xvdF9hcnJfaW5fc2Vjb25kcy5sZW5ndGggPiAxIClcclxuXHRcdFx0JiYgKCBwYXJzZUludCggdGltZXNsb3RfYXJyX2luX3NlY29uZHNbIDAgXSApIDwgMzAgKVxyXG5cdFx0XHQmJiAoIHBhcnNlSW50KCB0aW1lc2xvdF9hcnJfaW5fc2Vjb25kc1sgMSBdICkgPiAgKCAoMjQgKiA2MCAqIDYwKSAtIDMwKSApXHJcblx0XHQpe1xyXG5cdFx0XHRyZXR1cm4gdHJ1ZTtcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gZmFsc2U7XHJcblx0fVxyXG5cclxuXHJcblx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHQvKiAgPT0gIFMgZSBsIGUgYyB0IGUgZCAgICBEIGEgdCBlIHMgIC8gIFQgaSBtIGUgLSBGIGkgZSBsIGQgcyAgPT1cclxuXHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqL1xyXG5cclxuXHQvKipcclxuXHQgKiAgR2V0IGFsbCBzZWxlY3RlZCBkYXRlcyBpbiBTUUwgZm9ybWF0IGxpa2UgdGhpcyBbIFwiMjAyMy0wOC0yM1wiLCBcIjIwMjMtMDgtMjRcIiAsIC4uLiBdXHJcblx0ICpcclxuXHQgKiBAcGFyYW0gcmVzb3VyY2VfaWRcclxuXHQgKiBAcmV0dXJucyB7W119XHRcdFx0WyBcIjIwMjMtMDgtMjNcIiwgXCIyMDIzLTA4LTI0XCIsIFwiMjAyMy0wOC0yNVwiLCBcIjIwMjMtMDgtMjZcIiwgXCIyMDIzLTA4LTI3XCIsIFwiMjAyMy0wOC0yOFwiLFxyXG5cdCAqICAgICBcIjIwMjMtMDgtMjlcIiBdXHJcblx0ICovXHJcblx0ZnVuY3Rpb24gd3BiY19nZXRfX3NlbGVjdGVkX2RhdGVzX3NxbF9fYXNfYXJyKCByZXNvdXJjZV9pZCApe1xyXG5cclxuXHRcdHZhciBzZWxlY3RlZF9kYXRlc19hcnIgPSBbXTtcclxuXHRcdHNlbGVjdGVkX2RhdGVzX2FyciA9IGpRdWVyeSggJyNkYXRlX2Jvb2tpbmcnICsgcmVzb3VyY2VfaWQgKS52YWwoKS5zcGxpdCgnLCcpO1xyXG5cclxuXHRcdGlmICggc2VsZWN0ZWRfZGF0ZXNfYXJyLmxlbmd0aCApe1x0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vIEZpeEluOiA5LjguMTAuMS5cclxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgc2VsZWN0ZWRfZGF0ZXNfYXJyLmxlbmd0aDsgaSsrICl7XHRcdFx0XHRcdFx0Ly8gRml4SW46IDEwLjAuMC41Ni5cclxuXHRcdFx0XHRzZWxlY3RlZF9kYXRlc19hcnJbIGkgXSA9IHNlbGVjdGVkX2RhdGVzX2FyclsgaSBdLnRyaW0oKTtcclxuXHRcdFx0XHRzZWxlY3RlZF9kYXRlc19hcnJbIGkgXSA9IHNlbGVjdGVkX2RhdGVzX2FyclsgaSBdLnNwbGl0KCAnLicgKTtcclxuXHRcdFx0XHRpZiAoIHNlbGVjdGVkX2RhdGVzX2FyclsgaSBdLmxlbmd0aCA+IDEgKXtcclxuXHRcdFx0XHRcdHNlbGVjdGVkX2RhdGVzX2FyclsgaSBdID0gc2VsZWN0ZWRfZGF0ZXNfYXJyWyBpIF1bIDIgXSArICctJyArIHNlbGVjdGVkX2RhdGVzX2FyclsgaSBdWyAxIF0gKyAnLScgKyBzZWxlY3RlZF9kYXRlc19hcnJbIGkgXVsgMCBdO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIFJlbW92ZSBlbXB0eSBlbGVtZW50cyBmcm9tIGFuIGFycmF5XHJcblx0XHRzZWxlY3RlZF9kYXRlc19hcnIgPSBzZWxlY3RlZF9kYXRlc19hcnIuZmlsdGVyKCBmdW5jdGlvbiAoIG4gKXsgcmV0dXJuIHBhcnNlSW50KG4pOyB9ICk7XHJcblxyXG5cdFx0c2VsZWN0ZWRfZGF0ZXNfYXJyLnNvcnQoKTtcclxuXHJcblx0XHRyZXR1cm4gc2VsZWN0ZWRfZGF0ZXNfYXJyO1xyXG5cdH1cclxuXHJcblxyXG5cdC8qKlxyXG5cdCAqIEdldCBhbGwgdGltZSBmaWVsZHMgaW4gdGhlIGJvb2tpbmcgZm9ybSBhcyBhcnJheSAgb2Ygb2JqZWN0c1xyXG5cdCAqXHJcblx0ICogQHBhcmFtIHJlc291cmNlX2lkXHJcblx0ICogQHBhcmFtIGlzX29ubHlfc2VsZWN0ZWRfdGltZVxyXG5cdCAqIEByZXR1cm5zIFtdXHJcblx0ICpcclxuXHQgKiBcdFx0RXhhbXBsZTpcclxuXHQgKiBcdFx0XHRcdFx0W1xyXG5cdCAqIFx0XHRcdFx0XHQgXHQgICB7XHJcblx0ICogXHRcdFx0XHRcdFx0XHRcdHZhbHVlX29wdGlvbl8yNGg6ICAgJzA2OjAwIC0gMDY6MzAnXHJcblx0ICogXHRcdFx0XHRcdFx0XHRcdHRpbWVzX2FzX3NlY29uZHM6ICAgWyAyMTYwMCwgMjM0MDAgXVxyXG5cdCAqIFx0XHRcdFx0XHQgXHQgICBcdFx0anF1ZXJ5X29wdGlvbjogICAgICBqUXVlcnlfT2JqZWN0IHt9XHJcblx0ICogXHRcdFx0XHRcdFx0XHRcdG5hbWU6ICAgICAgICAgICAgICAgJ3JhbmdldGltZTJbXSdcclxuXHQgKiBcdFx0XHRcdFx0ICAgICB9XHJcblx0ICogXHRcdFx0XHRcdCAgLi4uXHJcblx0ICogXHRcdFx0XHRcdFx0ICAge1xyXG5cdCAqIFx0XHRcdFx0XHRcdFx0XHR2YWx1ZV9vcHRpb25fMjRoOiAgICcwNjowMCdcclxuXHQgKiBcdFx0XHRcdFx0XHRcdFx0dGltZXNfYXNfc2Vjb25kczogICBbIDIxNjAwIF1cclxuXHQgKiBcdFx0XHRcdFx0XHQgICBcdFx0anF1ZXJ5X29wdGlvbjogICAgICBqUXVlcnlfT2JqZWN0IHt9XHJcblx0ICogXHRcdFx0XHRcdFx0XHRcdG5hbWU6ICAgICAgICAgICAgICAgJ3N0YXJ0dGltZTJbXSdcclxuXHQgKiAgXHRcdFx0XHRcdCAgICB9XHJcblx0ICogXHRcdFx0XHRcdCBdXHJcblx0ICovXHJcblx0ZnVuY3Rpb24gd3BiY19nZXRfX3NlbGVjdGVkX3RpbWVfZmllbGRzX19pbl9ib29raW5nX2Zvcm1fX2FzX2FyciggcmVzb3VyY2VfaWQsIGlzX29ubHlfc2VsZWN0ZWRfdGltZSA9IHRydWUgKXtcclxuXHRcdC8qKlxyXG5cdFx0ICogRmllbGRzIHdpdGggIFtdICBsaWtlIHRoaXMgICBzZWxlY3RbbmFtZT1cInJhbmdldGltZTFbXVwiXVxyXG5cdFx0ICogaXQncyB3aGVuIHdlIGhhdmUgJ211bHRpcGxlJyBpbiBzaG9ydGNvZGU6ICAgW3NlbGVjdCogcmFuZ2V0aW1lIG11bHRpcGxlICBcIjA2OjAwIC0gMDY6MzBcIiAuLi4gXVxyXG5cdFx0ICovXHJcblx0XHR2YXIgdGltZV9maWVsZHNfYXJyPVtcclxuXHRcdFx0XHRcdFx0XHRcdCdzZWxlY3RbbmFtZT1cInJhbmdldGltZScgKyByZXNvdXJjZV9pZCArICdcIl0nLFxyXG5cdFx0XHRcdFx0XHRcdFx0J3NlbGVjdFtuYW1lPVwicmFuZ2V0aW1lJyArIHJlc291cmNlX2lkICsgJ1tdXCJdJyxcclxuXHRcdFx0XHRcdFx0XHRcdCdzZWxlY3RbbmFtZT1cInN0YXJ0dGltZScgKyByZXNvdXJjZV9pZCArICdcIl0nLFxyXG5cdFx0XHRcdFx0XHRcdFx0J3NlbGVjdFtuYW1lPVwic3RhcnR0aW1lJyArIHJlc291cmNlX2lkICsgJ1tdXCJdJyxcclxuXHRcdFx0XHRcdFx0XHRcdCdzZWxlY3RbbmFtZT1cImVuZHRpbWUnICsgcmVzb3VyY2VfaWQgKyAnXCJdJyxcclxuXHRcdFx0XHRcdFx0XHRcdCdzZWxlY3RbbmFtZT1cImVuZHRpbWUnICsgcmVzb3VyY2VfaWQgKyAnW11cIl0nLFxyXG5cdFx0XHRcdFx0XHRcdFx0J3NlbGVjdFtuYW1lPVwiZHVyYXRpb250aW1lJyArIHJlc291cmNlX2lkICsgJ1wiXScsXHJcblx0XHRcdFx0XHRcdFx0XHQnc2VsZWN0W25hbWU9XCJkdXJhdGlvbnRpbWUnICsgcmVzb3VyY2VfaWQgKyAnW11cIl0nXHJcblx0XHRcdFx0XHRcdFx0XTtcclxuXHJcblx0XHR2YXIgdGltZV9maWVsZHNfb2JqX2FyciA9IFtdO1xyXG5cclxuXHRcdC8vIExvb3AgYWxsIFRpbWUgRmllbGRzXHJcblx0XHRmb3IgKCB2YXIgY3RmPSAwOyBjdGYgPCB0aW1lX2ZpZWxkc19hcnIubGVuZ3RoOyBjdGYrKyApe1xyXG5cclxuXHRcdFx0dmFyIHRpbWVfZmllbGQgPSB0aW1lX2ZpZWxkc19hcnJbIGN0ZiBdO1xyXG5cclxuXHRcdFx0dmFyIHRpbWVfb3B0aW9uO1xyXG5cdFx0XHRpZiAoIGlzX29ubHlfc2VsZWN0ZWRfdGltZSApe1xyXG5cdFx0XHRcdHRpbWVfb3B0aW9uID0galF1ZXJ5KCAnI2Jvb2tpbmdfZm9ybScgKyByZXNvdXJjZV9pZCArICcgJyArIHRpbWVfZmllbGQgKyAnIG9wdGlvbjpzZWxlY3RlZCcgKTtcdFx0XHQvLyBFeGNsdWRlIGNvbmRpdGlvbmFsICBmaWVsZHMsICBiZWNhdXNlIG9mIHVzaW5nICcjYm9va2luZ19mb3JtMyAuLi4nXHJcblx0XHRcdH0gZWxzZSB7XHJcblx0XHRcdFx0dGltZV9vcHRpb24gPSBqUXVlcnkoICcjYm9va2luZ19mb3JtJyArIHJlc291cmNlX2lkICsgJyAnICsgdGltZV9maWVsZCArICcgb3B0aW9uJyApO1x0XHRcdFx0Ly8gQWxsICB0aW1lIGZpZWxkc1xyXG5cdFx0XHR9XHJcblxyXG5cclxuXHRcdFx0Ly8gTG9vcCBhbGwgb3B0aW9ucyBpbiB0aW1lIGZpZWxkXHJcblx0XHRcdGZvciAoIHZhciBqID0gMDsgaiA8IHRpbWVfb3B0aW9uLmxlbmd0aDsgaisrICl7XHJcblxyXG5cdFx0XHRcdHZhciBqcXVlcnlfb3B0aW9uID0galF1ZXJ5KCB0aW1lX29wdGlvblsgaiBdICk7XHRcdC8vIEdldCBvbmx5ICBzZWxlY3RlZCBvcHRpb25zIFx0Ly9qUXVlcnkoIHRpbWVfZmllbGQgKyAnIG9wdGlvbjplcSgnICsgaiArICcpJyApO1xyXG5cdFx0XHRcdHZhciB2YWx1ZV9vcHRpb25fc2Vjb25kc19hcnIgPSBqcXVlcnlfb3B0aW9uLnZhbCgpLnNwbGl0KCAnLScgKTtcclxuXHRcdFx0XHR2YXIgdGltZXNfYXNfc2Vjb25kcyA9IFtdO1xyXG5cclxuXHRcdFx0XHQvLyBHZXQgdGltZSBhcyBzZWNvbmRzXHJcblx0XHRcdFx0aWYgKCB2YWx1ZV9vcHRpb25fc2Vjb25kc19hcnIubGVuZ3RoICl7XHRcdFx0XHQgXHRcdFx0XHRcdFx0XHRcdC8vIEZpeEluOiA5LjguMTAuMS5cclxuXHRcdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHZhbHVlX29wdGlvbl9zZWNvbmRzX2Fyci5sZW5ndGg7IGkrKyApe1x0XHRcdFx0XHQvLyBGaXhJbjogMTAuMC4wLjU2LlxyXG5cdFx0XHRcdFx0XHQvLyB2YWx1ZV9vcHRpb25fc2Vjb25kc19hcnJbaV0gPSAnMTQ6MDAgJyAgfCAnIDE2OjAwJyAgIChpZiBmcm9tICdyYW5nZXRpbWUnKSBhbmQgJzE2OjAwJyAgaWYgKHN0YXJ0L2VuZCB0aW1lKVxyXG5cclxuXHRcdFx0XHRcdFx0dmFyIHN0YXJ0X2VuZF90aW1lc19hcnIgPSB2YWx1ZV9vcHRpb25fc2Vjb25kc19hcnJbIGkgXS50cmltKCkuc3BsaXQoICc6JyApO1xyXG5cclxuXHRcdFx0XHRcdFx0dmFyIHRpbWVfaW5fc2Vjb25kcyA9IHBhcnNlSW50KCBzdGFydF9lbmRfdGltZXNfYXJyWyAwIF0gKSAqIDYwICogNjAgKyBwYXJzZUludCggc3RhcnRfZW5kX3RpbWVzX2FyclsgMSBdICkgKiA2MDtcclxuXHJcblx0XHRcdFx0XHRcdHRpbWVzX2FzX3NlY29uZHMucHVzaCggdGltZV9pbl9zZWNvbmRzICk7XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR0aW1lX2ZpZWxkc19vYmpfYXJyLnB1c2goIHtcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdCduYW1lJyAgICAgICAgICAgIDogalF1ZXJ5KCAnI2Jvb2tpbmdfZm9ybScgKyByZXNvdXJjZV9pZCArICcgJyArIHRpbWVfZmllbGQgKS5hdHRyKCAnbmFtZScgKSxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdCd2YWx1ZV9vcHRpb25fMjRoJzoganF1ZXJ5X29wdGlvbi52YWwoKSxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdCdqcXVlcnlfb3B0aW9uJyAgIDoganF1ZXJ5X29wdGlvbixcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdCd0aW1lc19hc19zZWNvbmRzJzogdGltZXNfYXNfc2Vjb25kc1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdH0gKTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIFRleHQ6ICAgW3N0YXJ0dGltZV0gLSBbZW5kdGltZV0gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHJcblx0XHR2YXIgdGV4dF90aW1lX2ZpZWxkc19hcnI9W1xyXG5cdFx0XHRcdFx0XHRcdFx0XHQnaW5wdXRbbmFtZT1cInN0YXJ0dGltZScgKyByZXNvdXJjZV9pZCArICdcIl0nLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHQnaW5wdXRbbmFtZT1cImVuZHRpbWUnICsgcmVzb3VyY2VfaWQgKyAnXCJdJyxcclxuXHRcdFx0XHRcdFx0XHRcdF07XHJcblx0XHRmb3IgKCB2YXIgdGY9IDA7IHRmIDwgdGV4dF90aW1lX2ZpZWxkc19hcnIubGVuZ3RoOyB0ZisrICl7XHJcblxyXG5cdFx0XHR2YXIgdGV4dF9qcXVlcnkgPSBqUXVlcnkoICcjYm9va2luZ19mb3JtJyArIHJlc291cmNlX2lkICsgJyAnICsgdGV4dF90aW1lX2ZpZWxkc19hcnJbIHRmIF0gKTtcdFx0XHRcdFx0XHRcdFx0Ly8gRXhjbHVkZSBjb25kaXRpb25hbCAgZmllbGRzLCAgYmVjYXVzZSBvZiB1c2luZyAnI2Jvb2tpbmdfZm9ybTMgLi4uJ1xyXG5cdFx0XHRpZiAoIHRleHRfanF1ZXJ5Lmxlbmd0aCA+IDAgKXtcclxuXHJcblx0XHRcdFx0dmFyIHRpbWVfX2hfbV9fYXJyID0gdGV4dF9qcXVlcnkudmFsKCkudHJpbSgpLnNwbGl0KCAnOicgKTtcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gJzE0OjAwJ1xyXG5cdFx0XHRcdGlmICggMCA9PSB0aW1lX19oX21fX2Fyci5sZW5ndGggKXtcclxuXHRcdFx0XHRcdGNvbnRpbnVlO1x0XHRcdFx0XHRcdFx0XHRcdC8vIE5vdCBlbnRlcmVkIHRpbWUgdmFsdWUgaW4gYSBmaWVsZFxyXG5cdFx0XHRcdH1cclxuXHRcdFx0XHRpZiAoIDEgPT0gdGltZV9faF9tX19hcnIubGVuZ3RoICl7XHJcblx0XHRcdFx0XHRpZiAoICcnID09PSB0aW1lX19oX21fX2FyclsgMCBdICl7XHJcblx0XHRcdFx0XHRcdGNvbnRpbnVlO1x0XHRcdFx0XHRcdFx0XHQvLyBOb3QgZW50ZXJlZCB0aW1lIHZhbHVlIGluIGEgZmllbGRcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdHRpbWVfX2hfbV9fYXJyWyAxIF0gPSAwO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0XHR2YXIgdGV4dF90aW1lX2luX3NlY29uZHMgPSBwYXJzZUludCggdGltZV9faF9tX19hcnJbIDAgXSApICogNjAgKiA2MCArIHBhcnNlSW50KCB0aW1lX19oX21fX2FyclsgMSBdICkgKiA2MDtcclxuXHJcblx0XHRcdFx0dmFyIHRleHRfdGltZXNfYXNfc2Vjb25kcyA9IFtdO1xyXG5cdFx0XHRcdHRleHRfdGltZXNfYXNfc2Vjb25kcy5wdXNoKCB0ZXh0X3RpbWVfaW5fc2Vjb25kcyApO1xyXG5cclxuXHRcdFx0XHR0aW1lX2ZpZWxkc19vYmpfYXJyLnB1c2goIHtcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdCduYW1lJyAgICAgICAgICAgIDogdGV4dF9qcXVlcnkuYXR0ciggJ25hbWUnICksXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHQndmFsdWVfb3B0aW9uXzI0aCc6IHRleHRfanF1ZXJ5LnZhbCgpLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0J2pxdWVyeV9vcHRpb24nICAgOiB0ZXh0X2pxdWVyeSxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdCd0aW1lc19hc19zZWNvbmRzJzogdGV4dF90aW1lc19hc19zZWNvbmRzXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0fSApO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRpbWVfZmllbGRzX29ial9hcnI7XHJcblx0fVxyXG5cclxuXHJcblxyXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuLyogID09ICBTIFUgUCBQIE8gUiBUICAgIGZvciAgICBDIEEgTCBFIE4gRCBBIFIgID09XHJcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqL1xyXG5cclxuXHQvKipcclxuXHQgKiBHZXQgQ2FsZW5kYXIgZGF0ZXBpY2sgSW5zdGFuY2UuXHJcblx0ICpcclxuXHQgKiBAcGFyYW0ge2ludHxzdHJpbmd9IHJlc291cmNlX2lkXHJcblx0ICogQHJldHVybnMgeyp8bnVsbH1cclxuXHQgKi9cclxuXHRmdW5jdGlvbiB3cGJjX2NhbGVuZGFyX19nZXRfaW5zdChyZXNvdXJjZV9pZCkge1xyXG5cclxuXHRcdGlmICggJ3VuZGVmaW5lZCcgPT09IHR5cGVvZiAocmVzb3VyY2VfaWQpICkge1xyXG5cdFx0XHRyZXNvdXJjZV9pZCA9ICcxJztcclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIGpRdWVyeSggJyNjYWxlbmRhcl9ib29raW5nJyArIHJlc291cmNlX2lkICkubGVuZ3RoID4gMCApIHtcclxuXHJcblx0XHRcdHRyeSB7XHJcblx0XHRcdFx0dmFyIGluc3QgPSBqUXVlcnkuZGF0ZXBpY2suX2dldEluc3QoIGpRdWVyeSggJyNjYWxlbmRhcl9ib29raW5nJyArIHJlc291cmNlX2lkICkuZ2V0KCAwICkgKTtcclxuXHRcdFx0XHRyZXR1cm4gaW5zdCA/IGluc3QgOiBudWxsO1xyXG5cdFx0XHR9IGNhdGNoICggZSApIHtcclxuXHRcdFx0XHRyZXR1cm4gbnVsbDtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBudWxsO1xyXG5cdH1cclxuXHJcblxyXG5cdC8qKlxyXG5cdCAqIFVuc2VsZWN0ICBhbGwgZGF0ZXMgaW4gY2FsZW5kYXIgYW5kIHZpc3VhbGx5IHVwZGF0ZSB0aGlzIGNhbGVuZGFyXHJcblx0ICpcclxuXHQgKiBAcGFyYW0gcmVzb3VyY2VfaWRcdFx0SUQgb2YgYm9va2luZyByZXNvdXJjZVxyXG5cdCAqIEByZXR1cm5zIHtib29sZWFufVx0XHR0cnVlIG9uIHN1Y2Nlc3MgfCBmYWxzZSwgIGlmIG5vIHN1Y2ggIGNhbGVuZGFyXHJcblx0ICovXHJcblx0ZnVuY3Rpb24gd3BiY19jYWxlbmRhcl9fdW5zZWxlY3RfYWxsX2RhdGVzKCByZXNvdXJjZV9pZCApe1xyXG5cclxuXHRcdGlmICggJ3VuZGVmaW5lZCcgPT09IHR5cGVvZiAocmVzb3VyY2VfaWQpICl7XHJcblx0XHRcdHJlc291cmNlX2lkID0gJzEnO1xyXG5cdFx0fVxyXG5cclxuXHRcdHdwYmNfcmFuZ2Vfc2VsZWN0aW9uX19oaWRlX2d1aWRhbmNlKCByZXNvdXJjZV9pZCApO1xyXG5cclxuXHRcdHZhciBpbnN0ID0gd3BiY19jYWxlbmRhcl9fZ2V0X2luc3QoIHJlc291cmNlX2lkIClcclxuXHJcblx0XHRpZiAoIG51bGwgIT09IGluc3QgKXtcclxuXHJcblx0XHRcdC8vIFVuc2VsZWN0IGFsbCBkYXRlcyBhbmQgc2V0ICBwcm9wZXJ0aWVzIG9mIERhdGVwaWNrXHJcblx0XHRcdGpRdWVyeSggJyNkYXRlX2Jvb2tpbmcnICsgcmVzb3VyY2VfaWQgKS52YWwoICcnICk7ICAgICAgLy9GaXhJbjogNS40LjNcclxuXHRcdFx0aW5zdC5zdGF5T3BlbiA9IGZhbHNlO1xyXG5cdFx0XHRpbnN0LmRhdGVzID0gW107XHJcblx0XHRcdGpRdWVyeS5kYXRlcGljay5fdXBkYXRlRGF0ZXBpY2soIGluc3QgKTtcclxuXHJcblx0XHRcdHJldHVybiB0cnVlXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGZhbHNlO1xyXG5cclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIENsZWFyIGRheXMgaGlnaGxpZ2h0aW5nIGluIEFsbCBvciBzcGVjaWZpYyBDYWxlbmRhcnNcclxuXHQgKlxyXG4gICAgICogQHBhcmFtIHJlc291cmNlX2lkICAtIGNhbiBiZSBza2lwZWQgdG8gIGNsZWFyIGhpZ2hsaWdodGluZyBpbiBhbGwgY2FsZW5kYXJzXHJcbiAgICAgKi9cclxuXHRmdW5jdGlvbiB3cGJjX2NhbGVuZGFyc19fY2xlYXJfZGF5c19oaWdobGlnaHRpbmcoIHJlc291cmNlX2lkICl7XHJcblxyXG5cdFx0aWYgKCAndW5kZWZpbmVkJyAhPT0gdHlwZW9mICggcmVzb3VyY2VfaWQgKSApe1xyXG5cclxuXHRcdFx0alF1ZXJ5KCAnI2NhbGVuZGFyX2Jvb2tpbmcnICsgcmVzb3VyY2VfaWQgKyAnIC5kYXRlcGljay1kYXlzLWNlbGwtb3ZlcicgKS5yZW1vdmVDbGFzcyggJ2RhdGVwaWNrLWRheXMtY2VsbC1vdmVyJyApO1x0XHQvLyBDbGVhciBpbiBzcGVjaWZpYyBjYWxlbmRhclxyXG5cclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdGpRdWVyeSggJy5kYXRlcGljay1kYXlzLWNlbGwtb3ZlcicgKS5yZW1vdmVDbGFzcyggJ2RhdGVwaWNrLWRheXMtY2VsbC1vdmVyJyApO1x0XHRcdFx0XHRcdFx0XHQvLyBDbGVhciBpbiBhbGwgY2FsZW5kYXJzXHJcblx0XHR9XHJcblx0fVxyXG5cclxuXHQvKipcclxuXHQgKiBTY3JvbGwgdG8gc3BlY2lmaWMgbW9udGggaW4gY2FsZW5kYXJcclxuXHQgKlxyXG5cdCAqIEBwYXJhbSByZXNvdXJjZV9pZFx0XHRJRCBvZiByZXNvdXJjZVxyXG5cdCAqIEBwYXJhbSB5ZWFyXHRcdFx0XHQtIHJlYWwgeWVhciAgLSAyMDIzXHJcblx0ICogQHBhcmFtIG1vbnRoXHRcdFx0XHQtIHJlYWwgbW9udGggLSAxMlxyXG5cdCAqIEByZXR1cm5zIHtib29sZWFufVxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdwYmNfY2FsZW5kYXJfX3Njcm9sbF90byggcmVzb3VyY2VfaWQsIHllYXIsIG1vbnRoICl7XHJcblxyXG5cdFx0aWYgKCAndW5kZWZpbmVkJyA9PT0gdHlwZW9mIChyZXNvdXJjZV9pZCkgKXsgcmVzb3VyY2VfaWQgPSAnMSc7IH1cclxuXHRcdHZhciBpbnN0ID0gd3BiY19jYWxlbmRhcl9fZ2V0X2luc3QoIHJlc291cmNlX2lkIClcclxuXHRcdGlmICggbnVsbCAhPT0gaW5zdCApe1xyXG5cclxuXHRcdFx0eWVhciAgPSBwYXJzZUludCggeWVhciApO1xyXG5cdFx0XHRtb250aCA9IHBhcnNlSW50KCBtb250aCApIC0gMTtcdFx0Ly8gSW4gSlMgZGF0ZSwgIG1vbnRoIC0xXHJcblxyXG5cdFx0XHRpbnN0LmN1cnNvckRhdGUgPSBuZXcgRGF0ZSgpO1xyXG5cdFx0XHQvLyBJbiBzb21lIGNhc2VzLCAgdGhlIHNldEZ1bGxZZWFyIGNhbiAgc2V0ICBvbmx5IFllYXIsICBhbmQgbm90IHRoZSBNb250aCBhbmQgZGF5ICAgICAgLy8gRml4SW46IDYuMi4zLjUuXHJcblx0XHRcdGluc3QuY3Vyc29yRGF0ZS5zZXRGdWxsWWVhciggeWVhciwgbW9udGgsIDEgKTtcclxuXHRcdFx0aW5zdC5jdXJzb3JEYXRlLnNldE1vbnRoKCBtb250aCApO1xyXG5cdFx0XHRpbnN0LmN1cnNvckRhdGUuc2V0RGF0ZSggMSApO1xyXG5cclxuXHRcdFx0aW5zdC5kcmF3TW9udGggPSBpbnN0LmN1cnNvckRhdGUuZ2V0TW9udGgoKTtcclxuXHRcdFx0aW5zdC5kcmF3WWVhciA9IGluc3QuY3Vyc29yRGF0ZS5nZXRGdWxsWWVhcigpO1xyXG5cclxuXHRcdFx0alF1ZXJ5LmRhdGVwaWNrLl9ub3RpZnlDaGFuZ2UoIGluc3QgKTtcclxuXHRcdFx0alF1ZXJ5LmRhdGVwaWNrLl9hZGp1c3RJbnN0RGF0ZSggaW5zdCApO1xyXG5cdFx0XHRqUXVlcnkuZGF0ZXBpY2suX3Nob3dEYXRlKCBpbnN0ICk7XHJcblx0XHRcdGpRdWVyeS5kYXRlcGljay5fdXBkYXRlRGF0ZXBpY2soIGluc3QgKTtcclxuXHJcblx0XHRcdHJldHVybiB0cnVlO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIGZhbHNlO1xyXG5cdH1cclxuXHJcblx0LyoqXG5cdCAqIERldGVybWluZSBuYXRpdmUgZGF0ZSBzZWxlY3RhYmlsaXR5IHdpdGhvdXQgb3B0aW9uYWwgZGF0ZSBjb25zdHJhaW50cy5cblx0ICpcblx0ICogVGhpcyBoZWxwZXIgZXhwb3NlcyB0aGUgY2Fub25pY2FsIGNhbGVuZGFyIHJlc3VsdCBmb3IgYWxnb3JpdGhtcywgc3VjaCBhc1xuXHQgKiBnYXAgZGlzY292ZXJ5LCB0aGF0IG11c3Qgbm90IGNvbnN1bWUgdGhlaXIgb3duIGRlcml2ZWQgY29uc3RyYWludHMuIEl0IGRvZXNcblx0ICogbm90IHRyaWdnZXIgd3BiY19jYWxlbmRhcl9fYXBwbHlfZGF0ZV9jb25zdHJhaW50cyBhbmQgbXVzdCByZW1haW4gZnJlZSBvZlxuXHQgKiBvcHRpb25hbC1tb2R1bGUgc3RhdGUuXG5cdCAqXG5cdCAqIEBwYXJhbSB7bnVtYmVyfHN0cmluZ30gcmVzb3VyY2VfaWQgQm9va2luZyByZXNvdXJjZSBJRC5cblx0ICogQHBhcmFtIHtzdHJpbmd9ICAgICAgICBzcWxfZGF0ZSAgICBDYWxlbmRhciBkYXRlIGluIFlZWVktTU0tREQgZm9ybWF0LlxuXHQgKiBAcmV0dXJucyB7Ym9vbGVhbn0gVHJ1ZSB3aGVuIGNvcmUgY2FsZW5kYXIgZGF0YSBtYXJrcyB0aGUgZGF0ZSBzZWxlY3RhYmxlLlxuXHQgKi9cblx0ZnVuY3Rpb24gd3BiY19pc190aGlzX2RheV9zZWxlY3RhYmxlX19yYXcoIHJlc291cmNlX2lkLCBzcWxfZGF0ZSApe1xuXG5cdFx0Ly8gR2V0IERhdGEgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblx0XHR2YXIgZGF0ZV9ib29raW5nc19vYmogPSBfd3BiYy5ib29raW5nc19pbl9jYWxlbmRhcl9fZ2V0X2Zvcl9kYXRlKCByZXNvdXJjZV9pZCwgc3FsX2RhdGUgKTtcblx0XHR2YXIgaXNfZGF5X3NlbGVjdGFibGUgPSBmYWxzZTtcblxuXHRcdGlmICggZGF0ZV9ib29raW5nc19vYmogJiYgJ3VuZGVmaW5lZCcgIT09IHR5cGVvZiAoIGRhdGVfYm9va2luZ3Nfb2JqWyAnZGF5X2F2YWlsYWJpbGl0eScgXSApICkge1xuXHRcdFx0aXNfZGF5X3NlbGVjdGFibGUgPSAoIHBhcnNlSW50KCBkYXRlX2Jvb2tpbmdzX29ialsgJ2RheV9hdmFpbGFiaWxpdHknIF0gKSA+IDAgKTtcblxuXHRcdFx0aWYgKCAndW5kZWZpbmVkJyAhPT0gdHlwZW9mICggZGF0ZV9ib29raW5nc19vYmpbICdzdW1tYXJ5JyBdICkgJiYgJ2F2YWlsYWJsZScgIT0gZGF0ZV9ib29raW5nc19vYmpbICdzdW1tYXJ5J11bJ3N0YXR1c19mb3JfZGF5JyBdICl7XG5cblx0XHRcdFx0dmFyIGlzX3NldF9wZW5kaW5nX2RheXNfc2VsZWN0YWJsZSA9IF93cGJjLmNhbGVuZGFyX19nZXRfcGFyYW1fdmFsdWUoIHJlc291cmNlX2lkLCAncGVuZGluZ19kYXlzX3NlbGVjdGFibGUnICk7XHRcdC8vIHNldCBwZW5kaW5nIGRheXMgc2VsZWN0YWJsZSAgICAgICAgICAvLyBGaXhJbjogOC42LjEuMTguXG5cdFx0XHRcdHZhciBib29raW5nX3N0YXR1c2VzX2FyciA9IHdwYmNfZ2V0X2Jvb2tpbmdfc3RhdHVzZXNfX2FzX2FyciggZGF0ZV9ib29raW5nc19vYmogKTtcblxuXHRcdFx0XHRpZiAoXG5cdFx0XHRcdFx0ICAgKCB3cGJjX2Jvb2tpbmdfc3RhdHVzZXNfX2hhcyggYm9va2luZ19zdGF0dXNlc19hcnIsICdwZW5kaW5nJyApIClcblx0XHRcdFx0XHR8fCAoIHdwYmNfYm9va2luZ19zdGF0dXNlc19faGFzKCBib29raW5nX3N0YXR1c2VzX2FyciwgJ3BlbmRpbmdfcGVuZGluZycgKSApXG5cdFx0XHRcdFx0fHwgKCB3cGJjX2Jvb2tpbmdfc3RhdHVzZXNfX2hhcyggYm9va2luZ19zdGF0dXNlc19hcnIsICdwZW5kaW5nX2FwcHJvdmVkJyApIClcblx0XHRcdFx0XHR8fCAoIHdwYmNfYm9va2luZ19zdGF0dXNlc19faGFzKCBib29raW5nX3N0YXR1c2VzX2FyciwgJ2FwcHJvdmVkX3BlbmRpbmcnICkgKVxuXHRcdFx0XHQpe1xuXHRcdFx0XHRcdGlzX2RheV9zZWxlY3RhYmxlID0gKGlzX2RheV9zZWxlY3RhYmxlKSA/IHRydWUgOiBpc19zZXRfcGVuZGluZ19kYXlzX3NlbGVjdGFibGU7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHRyZXR1cm4gQm9vbGVhbiggaXNfZGF5X3NlbGVjdGFibGUgKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBEZXRlcm1pbmUgZmluYWwgZGF0ZSBzZWxlY3RhYmlsaXR5IGFmdGVyIG5hdGl2ZSBhbmQgb3B0aW9uYWwgY29uc3RyYWludHMuXG5cdCAqXG5cdCAqIE5hdGl2ZSB1bmF2YWlsYWJpbGl0eSByZXR1cm5zIGltbWVkaWF0ZWx5LiBPcHRpb25hbCBtb2R1bGVzIG1heSB0aGVyZWZvcmVcblx0ICogb25seSBibG9jayBhIG5hdGl2ZWx5IHNlbGVjdGFibGUgZGF0ZSBhbmQgY2FuIG5ldmVyIHJlb3BlbiBhIGNvcmUtdW5hdmFpbGFibGVcblx0ICogZGF0ZS5cblx0ICpcblx0ICogQHBhcmFtIHtudW1iZXJ8c3RyaW5nfSByZXNvdXJjZV9pZCBCb29raW5nIHJlc291cmNlIElELlxuXHQgKiBAcGFyYW0ge3N0cmluZ30gICAgICAgIHNxbF9kYXRlICAgIENhbGVuZGFyIGRhdGUgaW4gWVlZWS1NTS1ERCBmb3JtYXQuXG5cdCAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIHdoZW4gdGhlIGRhdGUgcmVtYWlucyBzZWxlY3RhYmxlIGFmdGVyIGNvbnN0cmFpbnRzLlxuXHQgKi9cblx0ZnVuY3Rpb24gd3BiY19pc190aGlzX2RheV9zZWxlY3RhYmxlKCByZXNvdXJjZV9pZCwgc3FsX2RhdGUgKXtcblxuXHRcdHZhciBpc19uYXRpdmVseV9zZWxlY3RhYmxlID0gd3BiY19pc190aGlzX2RheV9zZWxlY3RhYmxlX19yYXcoIHJlc291cmNlX2lkLCBzcWxfZGF0ZSApO1xuXG5cdFx0aWYgKCAhIGlzX25hdGl2ZWx5X3NlbGVjdGFibGUgKSB7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHdwYmNfY2FsZW5kYXJfX2V2YWx1YXRlX2RhdGVfY29uc3RyYWludHMoIHJlc291cmNlX2lkLCBzcWxfZGF0ZSwgaXNfbmF0aXZlbHlfc2VsZWN0YWJsZSwgW10gKS5pc19zZWxlY3RhYmxlO1xuXHR9XG5cclxuXHQvKipcclxuXHQgKiBJcyBkYXRlIHRvIGNoZWNrIElOIGFycmF5IG9mIHNlbGVjdGVkIGRhdGVzXHJcblx0ICpcclxuXHQgKiBAcGFyYW0ge2RhdGV9anNfZGF0ZV90b19jaGVja1x0XHQtIEpTIERhdGVcdFx0XHQtIHNpbXBsZSAgSmF2YVNjcmlwdCBEYXRlIG9iamVjdFxyXG5cdCAqIEBwYXJhbSB7W119IGpzX2RhdGVzX2Fyclx0XHRcdC0gWyBKU0RhdGUsIC4uLiBdICAgLSBhcnJheSAgb2YgSlMgZGF0ZXNcclxuXHQgKiBAcmV0dXJucyB7Ym9vbGVhbn1cclxuXHQgKi9cclxuXHRmdW5jdGlvbiB3cGJjX2lzX3RoaXNfZGF5X2Ftb25nX3NlbGVjdGVkX2RheXMoIGpzX2RhdGVfdG9fY2hlY2ssIGpzX2RhdGVzX2FyciApe1xyXG5cclxuXHRcdGZvciAoIHZhciBkYXRlX2luZGV4ID0gMDsgZGF0ZV9pbmRleCA8IGpzX2RhdGVzX2Fyci5sZW5ndGggOyBkYXRlX2luZGV4KysgKXsgICAgIFx0XHRcdFx0XHRcdFx0XHRcdC8vIEZpeEluOiA4LjQuNS4xNi5cclxuXHRcdFx0aWYgKCAoIGpzX2RhdGVzX2FyclsgZGF0ZV9pbmRleCBdLmdldEZ1bGxZZWFyKCkgPT09IGpzX2RhdGVfdG9fY2hlY2suZ2V0RnVsbFllYXIoKSApICYmXHJcblx0XHRcdFx0ICgganNfZGF0ZXNfYXJyWyBkYXRlX2luZGV4IF0uZ2V0TW9udGgoKSA9PT0ganNfZGF0ZV90b19jaGVjay5nZXRNb250aCgpICkgJiZcclxuXHRcdFx0XHQgKCBqc19kYXRlc19hcnJbIGRhdGVfaW5kZXggXS5nZXREYXRlKCkgPT09IGpzX2RhdGVfdG9fY2hlY2suZ2V0RGF0ZSgpICkgKSB7XHJcblx0XHRcdFx0XHRyZXR1cm4gdHJ1ZTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiAgZmFsc2U7XHJcblx0fVxyXG5cclxuXHQvKipcclxuXHQgKiBHZXQgU1FMIENsYXNzIERhdGUgJzIwMjMtMDgtMDEnIGZyb20gIEpTIERhdGVcclxuXHQgKlxyXG5cdCAqIEBwYXJhbSBkYXRlXHRcdFx0XHRKUyBEYXRlXHJcblx0ICogQHJldHVybnMge3N0cmluZ31cdFx0JzIwMjMtMDgtMTInXHJcblx0ICovXHJcblx0ZnVuY3Rpb24gd3BiY19fZ2V0X19zcWxfY2xhc3NfZGF0ZSggZGF0ZSApe1xyXG5cclxuXHRcdHZhciBzcWxfY2xhc3NfZGF5ID0gZGF0ZS5nZXRGdWxsWWVhcigpICsgJy0nO1xyXG5cdFx0XHRzcWxfY2xhc3NfZGF5ICs9ICggKCBkYXRlLmdldE1vbnRoKCkgKyAxICkgPCAxMCApID8gJzAnIDogJyc7XHJcblx0XHRcdHNxbF9jbGFzc19kYXkgKz0gKCBkYXRlLmdldE1vbnRoKCkgKyAxICkgKyAnLSdcclxuXHRcdFx0c3FsX2NsYXNzX2RheSArPSAoIGRhdGUuZ2V0RGF0ZSgpIDwgMTAgKSA/ICcwJyA6ICcnO1xyXG5cdFx0XHRzcWxfY2xhc3NfZGF5ICs9IGRhdGUuZ2V0RGF0ZSgpO1xyXG5cclxuXHRcdFx0cmV0dXJuIHNxbF9jbGFzc19kYXk7XHJcblx0fVxyXG5cclxuXHQvKipcclxuXHQgKiBHZXQgSlMgRGF0ZSBmcm9tICB0aGUgU1FMIGRhdGUgZm9ybWF0ICcyMDI0LTA1LTE0J1xyXG5cdCAqIEBwYXJhbSBzcWxfY2xhc3NfZGF0ZVxyXG5cdCAqIEByZXR1cm5zIHtEYXRlfVxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdwYmNfX2dldF9fanNfZGF0ZSggc3FsX2NsYXNzX2RhdGUgKXtcclxuXHJcblx0XHR2YXIgc3FsX2NsYXNzX2RhdGVfYXJyID0gc3FsX2NsYXNzX2RhdGUuc3BsaXQoICctJyApO1xyXG5cclxuXHRcdHZhciBkYXRlX2pzID0gbmV3IERhdGUoKTtcclxuXHJcblx0XHRkYXRlX2pzLnNldEZ1bGxZZWFyKCBwYXJzZUludCggc3FsX2NsYXNzX2RhdGVfYXJyWyAwIF0gKSwgKHBhcnNlSW50KCBzcWxfY2xhc3NfZGF0ZV9hcnJbIDEgXSApIC0gMSksIHBhcnNlSW50KCBzcWxfY2xhc3NfZGF0ZV9hcnJbIDIgXSApICk7ICAvLyB5ZWFyLCBtb250aCwgZGF0ZVxyXG5cclxuXHRcdC8vIFdpdGhvdXQgdGhpcyB0aW1lIGFkanVzdCBEYXRlcyBzZWxlY3Rpb24gIGluIERhdGVwaWNrZXIgY2FuIG5vdCB3b3JrISEhXHJcblx0XHRkYXRlX2pzLnNldEhvdXJzKDApO1xyXG5cdFx0ZGF0ZV9qcy5zZXRNaW51dGVzKDApO1xyXG5cdFx0ZGF0ZV9qcy5zZXRTZWNvbmRzKDApO1xyXG5cdFx0ZGF0ZV9qcy5zZXRNaWxsaXNlY29uZHMoMCk7XHJcblxyXG5cdFx0cmV0dXJuIGRhdGVfanM7XHJcblx0fVxyXG5cclxuXHQvKipcclxuXHQgKiBHZXQgVEQgQ2xhc3MgRGF0ZSAnMS0zMS0yMDIzJyBmcm9tICBKUyBEYXRlXHJcblx0ICpcclxuXHQgKiBAcGFyYW0gZGF0ZVx0XHRcdFx0SlMgRGF0ZVxyXG5cdCAqIEByZXR1cm5zIHtzdHJpbmd9XHRcdCcxLTMxLTIwMjMnXHJcblx0ICovXHJcblx0ZnVuY3Rpb24gd3BiY19fZ2V0X190ZF9jbGFzc19kYXRlKCBkYXRlICl7XHJcblxyXG5cdFx0dmFyIHRkX2NsYXNzX2RheSA9IChkYXRlLmdldE1vbnRoKCkgKyAxKSArICctJyArIGRhdGUuZ2V0RGF0ZSgpICsgJy0nICsgZGF0ZS5nZXRGdWxsWWVhcigpO1x0XHRcdFx0XHRcdFx0XHQvLyAnMS05LTIwMjMnXHJcblxyXG5cdFx0cmV0dXJuIHRkX2NsYXNzX2RheTtcclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIEdldCBkYXRlIHBhcmFtcyBmcm9tICBzdHJpbmcgZGF0ZVxyXG5cdCAqXHJcblx0ICogQHBhcmFtIGRhdGVcdFx0XHRzdHJpbmcgZGF0ZSBsaWtlICczMS41LjIwMjMnXHJcblx0ICogQHBhcmFtIHNlcGFyYXRvclx0XHRkZWZhdWx0ICcuJyAgY2FuIGJlIHNraXBwZWQuXHJcblx0ICogQHJldHVybnMgeyAge2RhdGU6IG51bWJlciwgbW9udGg6IG51bWJlciwgeWVhcjogbnVtYmVyfSAgfVxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdwYmNfX2dldF9fZGF0ZV9wYXJhbXNfX2Zyb21fc3RyaW5nX2RhdGUoIGRhdGUgLCBzZXBhcmF0b3Ipe1xyXG5cclxuXHRcdHNlcGFyYXRvciA9ICggJ3VuZGVmaW5lZCcgIT09IHR5cGVvZiAoc2VwYXJhdG9yKSApID8gc2VwYXJhdG9yIDogJy4nO1xyXG5cclxuXHRcdHZhciBkYXRlX2FyciA9IGRhdGUuc3BsaXQoIHNlcGFyYXRvciApO1xyXG5cdFx0dmFyIGRhdGVfb2JqID0ge1xyXG5cdFx0XHQneWVhcicgOiAgcGFyc2VJbnQoIGRhdGVfYXJyWyAyIF0gKSxcclxuXHRcdFx0J21vbnRoJzogKHBhcnNlSW50KCBkYXRlX2FyclsgMSBdICkgLSAxKSxcclxuXHRcdFx0J2RhdGUnIDogIHBhcnNlSW50KCBkYXRlX2FyclsgMCBdIClcclxuXHRcdH07XHJcblx0XHRyZXR1cm4gZGF0ZV9vYmo7XHRcdC8vIGZvciBcdFx0ID0gbmV3IERhdGUoIGRhdGVfb2JqLnllYXIgLCBkYXRlX29iai5tb250aCAsIGRhdGVfb2JqLmRhdGUgKTtcclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIEFkZCBTcGluIExvYWRlciB0byAgY2FsZW5kYXJcclxuXHQgKiBAcGFyYW0gcmVzb3VyY2VfaWRcclxuXHQgKi9cclxuXHRmdW5jdGlvbiB3cGJjX2NhbGVuZGFyX19sb2FkaW5nX19zdGFydCggcmVzb3VyY2VfaWQgKXtcclxuXHRcdGlmICggISBqUXVlcnkoICcjY2FsZW5kYXJfYm9va2luZycgKyByZXNvdXJjZV9pZCApLm5leHQoKS5oYXNDbGFzcyggJ3dwYmNfc3BpbnNfbG9hZGVyX3dyYXBwZXInICkgKXtcclxuXHRcdFx0alF1ZXJ5KCAnI2NhbGVuZGFyX2Jvb2tpbmcnICsgcmVzb3VyY2VfaWQgKS5hZnRlciggJzxkaXYgY2xhc3M9XCJ3cGJjX3NwaW5zX2xvYWRlcl93cmFwcGVyXCI+PGRpdiBjbGFzcz1cIndwYmNfc3Bpbl9sb2FkZXJfb25lX25ld1wiPjwvZGl2PjwvZGl2PicgKTtcclxuXHRcdH1cclxuXHRcdGlmICggISBqUXVlcnkoICcjY2FsZW5kYXJfYm9va2luZycgKyByZXNvdXJjZV9pZCApLmhhc0NsYXNzKCAnd3BiY19jYWxlbmRhcl9ibHVyX3NtYWxsJyApICl7XHJcblx0XHRcdGpRdWVyeSggJyNjYWxlbmRhcl9ib29raW5nJyArIHJlc291cmNlX2lkICkuYWRkQ2xhc3MoICd3cGJjX2NhbGVuZGFyX2JsdXJfc21hbGwnICk7XHJcblx0XHR9XHJcblx0XHR3cGJjX2NhbGVuZGFyX19ibHVyX19zdGFydCggcmVzb3VyY2VfaWQgKTtcclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIFJlbW92ZSBTcGluIExvYWRlciB0byAgY2FsZW5kYXJcclxuXHQgKiBAcGFyYW0gcmVzb3VyY2VfaWRcclxuXHQgKi9cclxuXHRmdW5jdGlvbiB3cGJjX2NhbGVuZGFyX19sb2FkaW5nX19zdG9wKCByZXNvdXJjZV9pZCApe1xyXG5cdFx0alF1ZXJ5KCAnI2NhbGVuZGFyX2Jvb2tpbmcnICsgcmVzb3VyY2VfaWQgKyAnICsgLndwYmNfc3BpbnNfbG9hZGVyX3dyYXBwZXInICkucmVtb3ZlKCk7XHJcblx0XHRqUXVlcnkoICcjY2FsZW5kYXJfYm9va2luZycgKyByZXNvdXJjZV9pZCApLnJlbW92ZUNsYXNzKCAnd3BiY19jYWxlbmRhcl9ibHVyX3NtYWxsJyApO1xyXG5cdFx0d3BiY19jYWxlbmRhcl9fYmx1cl9fc3RvcCggcmVzb3VyY2VfaWQgKTtcclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIEFkZCBCbHVyIHRvICBjYWxlbmRhclxyXG5cdCAqIEBwYXJhbSByZXNvdXJjZV9pZFxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdwYmNfY2FsZW5kYXJfX2JsdXJfX3N0YXJ0KCByZXNvdXJjZV9pZCApe1xyXG5cdFx0aWYgKCAhIGpRdWVyeSggJyNjYWxlbmRhcl9ib29raW5nJyArIHJlc291cmNlX2lkICkuaGFzQ2xhc3MoICd3cGJjX2NhbGVuZGFyX2JsdXInICkgKXtcclxuXHRcdFx0alF1ZXJ5KCAnI2NhbGVuZGFyX2Jvb2tpbmcnICsgcmVzb3VyY2VfaWQgKS5hZGRDbGFzcyggJ3dwYmNfY2FsZW5kYXJfYmx1cicgKTtcclxuXHRcdH1cclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIFJlbW92ZSBCbHVyIGluICBjYWxlbmRhclxyXG5cdCAqIEBwYXJhbSByZXNvdXJjZV9pZFxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdwYmNfY2FsZW5kYXJfX2JsdXJfX3N0b3AoIHJlc291cmNlX2lkICl7XHJcblx0XHRqUXVlcnkoICcjY2FsZW5kYXJfYm9va2luZycgKyByZXNvdXJjZV9pZCApLnJlbW92ZUNsYXNzKCAnd3BiY19jYWxlbmRhcl9ibHVyJyApO1xyXG5cdH1cclxuXHJcblxyXG5cdC8vIC4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uXHJcblx0LyogID09ICBDYWxlbmRhciBVcGRhdGUgIC0gVmlldyAgPT1cclxuXHQvLyAuLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLiAqL1xyXG5cclxuXHQvKipcclxuXHQgKiBVcGRhdGUgbG9vayBvZiBjYWxlbmRhciAoc2FmZSkuXHJcblx0ICpcclxuXHQgKiBJbiBFbGVtZW50b3IgcHJldmlldyB0aGUgRE9NIGNhbiBiZSByZS1yZW5kZXJlZCwgc28gdGhlIGNhbGVuZGFyIGVsZW1lbnQgbWF5IGV4aXN0XHJcblx0ICogd2hpbGUgdGhlIERhdGVwaWNrIGluc3RhbmNlIGlzIG1pc3NpbmcuIEluIHRoYXQgY2FzZSB0cnkgdG8gKHJlKWluaXRpYWxpemUuXHJcblx0ICpcclxuXHQgKiBAcGFyYW0ge2ludHxzdHJpbmd9IHJlc291cmNlX2lkXHJcblx0ICogQHJldHVybiB7Ym9vbGVhbn0gdHJ1ZSBpZiB1cGRhdGVkLCBmYWxzZSBpZiBub3QgcG9zc2libGVcclxuXHQgKi9cclxuXHRmdW5jdGlvbiB3cGJjX2NhbGVuZGFyX191cGRhdGVfbG9vayhyZXNvdXJjZV9pZCkge1xyXG5cclxuXHRcdHZhciBpbnN0ID0gd3BiY19jYWxlbmRhcl9fZ2V0X2luc3QoIHJlc291cmNlX2lkICk7XHJcblxyXG5cdFx0Ly8gSWYgaW5zdGFuY2UgbWlzc2luZywgdHJ5IHRvIHJlLWluaXQgY2FsZW5kYXIgb25jZS5cclxuXHRcdGlmICggbnVsbCA9PT0gaW5zdCApIHtcclxuXHJcblx0XHRcdHZhciBqcV9jYWwgPSBqUXVlcnkoICcjY2FsZW5kYXJfYm9va2luZycgKyByZXNvdXJjZV9pZCApO1xyXG5cclxuXHRcdFx0aWYgKCBqcV9jYWwubGVuZ3RoICYmICgnZnVuY3Rpb24nID09PSB0eXBlb2Ygd3BiY19jYWxlbmRhcl9zaG93KSApIHtcclxuXHJcblx0XHRcdFx0Ly8gRWxlbWVudG9yIHNvbWV0aW1lcyBsZWF2ZXMgc3RhbGUgY2xhc3Mgd2l0aG91dCByZWFsIGluc3RhbmNlLlxyXG5cdFx0XHRcdGlmICgganFfY2FsLmhhc0NsYXNzKCAnaGFzRGF0ZXBpY2snICkgKSB7XHJcblx0XHRcdFx0XHRqcV9jYWwucmVtb3ZlQ2xhc3MoICdoYXNEYXRlcGljaycgKTtcclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdC8vIFRyeSB0byBpbml0IGRhdGVwaWNrIG1hcmt1cCBub3cuXHJcblx0XHRcdFx0d3BiY19jYWxlbmRhcl9zaG93KCByZXNvdXJjZV9pZCApO1xyXG5cclxuXHRcdFx0XHQvLyBUcnkgYWdhaW4uXHJcblx0XHRcdFx0aW5zdCA9IHdwYmNfY2FsZW5kYXJfX2dldF9pbnN0KCByZXNvdXJjZV9pZCApO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gU3RpbGwgbm8gaW5zdGFuY2UgLT4gZG8gbm90IGNyYXNoIHRoZSB3aG9sZSBhamF4IGZsb3cuXHJcblx0XHRpZiAoIG51bGwgPT09IGluc3QgKSB7XHJcblx0XHRcdHJldHVybiBmYWxzZTtcclxuXHRcdH1cclxuXHJcblx0XHRqUXVlcnkuZGF0ZXBpY2suX3VwZGF0ZURhdGVwaWNrKCBpbnN0ICk7XHJcblx0XHRyZXR1cm4gdHJ1ZTtcclxuXHR9XHJcblxyXG5cclxuXHJcblx0LyoqXHJcblx0ICogVXBkYXRlIGR5bmFtaWNhbGx5IE51bWJlciBvZiBNb250aHMgaW4gY2FsZW5kYXJcclxuXHQgKlxyXG5cdCAqIEBwYXJhbSByZXNvdXJjZV9pZCBpbnRcclxuXHQgKiBAcGFyYW0gbW9udGhzX251bWJlciBpbnRcclxuXHQgKi9cclxuXHRmdW5jdGlvbiB3cGJjX2NhbGVuZGFyX191cGRhdGVfbW9udGhzX251bWJlciggcmVzb3VyY2VfaWQsIG1vbnRoc19udW1iZXIgKXtcclxuXHRcdHZhciBpbnN0ID0gd3BiY19jYWxlbmRhcl9fZ2V0X2luc3QoIHJlc291cmNlX2lkICk7XHJcblx0XHRpZiAoIG51bGwgIT09IGluc3QgKXtcclxuXHRcdFx0aW5zdC5zZXR0aW5nc1sgJ251bWJlck9mTW9udGhzJyBdID0gbW9udGhzX251bWJlcjtcclxuXHRcdFx0Ly9fd3BiYy5jYWxlbmRhcl9fc2V0X3BhcmFtX3ZhbHVlKCByZXNvdXJjZV9pZCwgJ2NhbGVuZGFyX251bWJlcl9vZl9tb250aHMnLCBtb250aHNfbnVtYmVyICk7XHJcblx0XHRcdHdwYmNfY2FsZW5kYXJfX3VwZGF0ZV9sb29rKCByZXNvdXJjZV9pZCApO1xyXG5cdFx0fVxyXG5cdH1cclxuXHJcblxyXG5cdC8qKlxyXG5cdCAqIFNob3cgY2FsZW5kYXIgaW4gIGRpZmZlcmVudCBTa2luXHJcblx0ICpcclxuXHQgKiBAcGFyYW0gc2VsZWN0ZWRfc2tpbl91cmxcclxuXHQgKi9cclxuXHRmdW5jdGlvbiB3cGJjX19jYWxlbmRhcl9fY2hhbmdlX3NraW4oIHNlbGVjdGVkX3NraW5fdXJsICl7XHJcblxyXG5cdC8vY29uc29sZS5sb2coICdTS0lOIFNFTEVDVElPTiA6OicsIHNlbGVjdGVkX3NraW5fdXJsICk7XHJcblxyXG5cdFx0Ly8gUmVtb3ZlIENTUyBza2luXHJcblx0XHR2YXIgc3R5bGVzaGVldCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCAnd3BiYy1jYWxlbmRhci1za2luLWNzcycgKTtcclxuXHRcdHN0eWxlc2hlZXQucGFyZW50Tm9kZS5yZW1vdmVDaGlsZCggc3R5bGVzaGVldCApO1xyXG5cclxuXHJcblx0XHQvLyBBZGQgbmV3IENTUyBza2luXHJcblx0XHR2YXIgaGVhZElEID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoIFwiaGVhZFwiIClbIDAgXTtcclxuXHRcdHZhciBjc3NOb2RlID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCggJ2xpbmsnICk7XHJcblx0XHRjc3NOb2RlLnR5cGUgPSAndGV4dC9jc3MnO1xyXG5cdFx0Y3NzTm9kZS5zZXRBdHRyaWJ1dGUoIFwiaWRcIiwgXCJ3cGJjLWNhbGVuZGFyLXNraW4tY3NzXCIgKTtcclxuXHRcdGNzc05vZGUucmVsID0gJ3N0eWxlc2hlZXQnO1xyXG5cdFx0Y3NzTm9kZS5tZWRpYSA9ICdzY3JlZW4nO1xyXG5cdFx0Y3NzTm9kZS5ocmVmID0gc2VsZWN0ZWRfc2tpbl91cmw7XHQvL1wiaHR0cDovL2JldGEvd3AtY29udGVudC9wbHVnaW5zL2Jvb2tpbmcvY3NzL3NraW5zL2dyZWVuLTAxLmNzc1wiO1xyXG5cdFx0aGVhZElELmFwcGVuZENoaWxkKCBjc3NOb2RlICk7XHJcblx0fVxyXG5cclxuXHJcblx0ZnVuY3Rpb24gd3BiY19fY3NzX19jaGFuZ2Vfc2tpbiggc2VsZWN0ZWRfc2tpbl91cmwsIHN0eWxlc2hlZXRfaWQgPSAnd3BiYy10aW1lX3BpY2tlci1za2luLWNzcycgKXtcclxuXHJcblx0XHQvLyBSZW1vdmUgQ1NTIHNraW5cclxuXHRcdHZhciBzdHlsZXNoZWV0ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoIHN0eWxlc2hlZXRfaWQgKTtcclxuXHRcdHN0eWxlc2hlZXQucGFyZW50Tm9kZS5yZW1vdmVDaGlsZCggc3R5bGVzaGVldCApO1xyXG5cclxuXHJcblx0XHQvLyBBZGQgbmV3IENTUyBza2luXHJcblx0XHR2YXIgaGVhZElEID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoIFwiaGVhZFwiIClbIDAgXTtcclxuXHRcdHZhciBjc3NOb2RlID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCggJ2xpbmsnICk7XHJcblx0XHRjc3NOb2RlLnR5cGUgPSAndGV4dC9jc3MnO1xyXG5cdFx0Y3NzTm9kZS5zZXRBdHRyaWJ1dGUoIFwiaWRcIiwgc3R5bGVzaGVldF9pZCApO1xyXG5cdFx0Y3NzTm9kZS5yZWwgPSAnc3R5bGVzaGVldCc7XHJcblx0XHRjc3NOb2RlLm1lZGlhID0gJ3NjcmVlbic7XHJcblx0XHRjc3NOb2RlLmhyZWYgPSBzZWxlY3RlZF9za2luX3VybDtcdC8vXCJodHRwOi8vYmV0YS93cC1jb250ZW50L3BsdWdpbnMvYm9va2luZy9jc3Mvc2tpbnMvZ3JlZW4tMDEuY3NzXCI7XHJcblx0XHRoZWFkSUQuYXBwZW5kQ2hpbGQoIGNzc05vZGUgKTtcclxuXHR9XHJcblxyXG5cclxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcbi8qICA9PSAgUyBVIFAgUCBPIFIgVCAgICBNIEEgVCBIICA9PVxyXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi9cclxuXHJcblx0XHQvKipcclxuXHRcdCAqIE1lcmdlIHNldmVyYWwgIGludGVyc2VjdGVkIGludGVydmFscyBvciByZXR1cm4gbm90IGludGVyc2VjdGVkOlxyXG5cdFx0ICogW1sxLDNdLFsyLDZdLFs4LDEwXSxbMTUsMThdXSAgLT4gICBbWzEsNl0sWzgsMTBdLFsxNSwxOF1dXHJcblx0XHQgKlxyXG5cdFx0ICogQHBhcmFtIFtdIGludGVydmFsc1x0XHRcdCBbIFsxLDNdLFsyLDRdLFs2LDhdLFs5LDEwXSxbMyw3XSBdXHJcblx0XHQgKiBAcmV0dXJucyBbXVx0XHRcdFx0XHQgWyBbMSw4XSxbOSwxMF0gXVxyXG5cdFx0ICpcclxuXHRcdCAqIEV4bWFtcGxlOiB3cGJjX2ludGVydmFsc19fbWVyZ2VfaW5lcnNlY3RlZCggIFsgWzEsM10sWzIsNF0sWzYsOF0sWzksMTBdLFszLDddIF0gICk7XHJcblx0XHQgKi9cclxuXHRcdGZ1bmN0aW9uIHdwYmNfaW50ZXJ2YWxzX19tZXJnZV9pbmVyc2VjdGVkKCBpbnRlcnZhbHMgKXtcclxuXHJcblx0XHRcdGlmICggISBpbnRlcnZhbHMgfHwgaW50ZXJ2YWxzLmxlbmd0aCA9PT0gMCApe1xyXG5cdFx0XHRcdHJldHVybiBbXTtcclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0dmFyIG1lcmdlZCA9IFtdO1xyXG5cdFx0XHRpbnRlcnZhbHMuc29ydCggZnVuY3Rpb24gKCBhLCBiICl7XHJcblx0XHRcdFx0cmV0dXJuIGFbIDAgXSAtIGJbIDAgXTtcclxuXHRcdFx0fSApO1xyXG5cclxuXHRcdFx0dmFyIG1lcmdlZEludGVydmFsID0gaW50ZXJ2YWxzWyAwIF07XHJcblxyXG5cdFx0XHRmb3IgKCB2YXIgaSA9IDE7IGkgPCBpbnRlcnZhbHMubGVuZ3RoOyBpKysgKXtcclxuXHRcdFx0XHR2YXIgaW50ZXJ2YWwgPSBpbnRlcnZhbHNbIGkgXTtcclxuXHJcblx0XHRcdFx0aWYgKCBpbnRlcnZhbFsgMCBdIDw9IG1lcmdlZEludGVydmFsWyAxIF0gKXtcclxuXHRcdFx0XHRcdG1lcmdlZEludGVydmFsWyAxIF0gPSBNYXRoLm1heCggbWVyZ2VkSW50ZXJ2YWxbIDEgXSwgaW50ZXJ2YWxbIDEgXSApO1xyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblx0XHRcdFx0XHRtZXJnZWQucHVzaCggbWVyZ2VkSW50ZXJ2YWwgKTtcclxuXHRcdFx0XHRcdG1lcmdlZEludGVydmFsID0gaW50ZXJ2YWw7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRtZXJnZWQucHVzaCggbWVyZ2VkSW50ZXJ2YWwgKTtcclxuXHRcdFx0cmV0dXJuIG1lcmdlZDtcclxuXHRcdH1cclxuXHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiBJcyAyIGludGVydmFscyBpbnRlcnNlY3RlZDogICAgICAgWzM2MDExLCA4NjM5Ml0gICAgPD0+ICAgIFsxLCA0MzE5Ml0gID0+ICB0cnVlICAgICAgKCBpbnRlcnNlY3RlZCApXHJcblx0XHQgKlxyXG5cdFx0ICogR29vZCBleHBsYW5hdGlvbiAgaGVyZVxyXG5cdFx0ICogaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMzI2OTQzNC93aGF0cy10aGUtbW9zdC1lZmZpY2llbnQtd2F5LXRvLXRlc3QtaWYtdHdvLXJhbmdlcy1vdmVybGFwXHJcblx0XHQgKlxyXG5cdFx0ICogQHBhcmFtICBpbnRlcnZhbF9BICAgLSBbIDM2MDExLCA4NjM5MiBdXHJcblx0XHQgKiBAcGFyYW0gIGludGVydmFsX0IgICAtIFsgICAgIDEsIDQzMTkyIF1cclxuXHRcdCAqXHJcblx0XHQgKiBAcmV0dXJuIGJvb2xcclxuXHRcdCAqL1xyXG5cdFx0ZnVuY3Rpb24gd3BiY19pbnRlcnZhbHNfX2lzX2ludGVyc2VjdGVkKCBpbnRlcnZhbF9BLCBpbnRlcnZhbF9CICkge1xyXG5cclxuXHRcdFx0aWYgKFxyXG5cdFx0XHRcdFx0KCAwID09IGludGVydmFsX0EubGVuZ3RoIClcclxuXHRcdFx0XHQgfHwgKCAwID09IGludGVydmFsX0IubGVuZ3RoIClcclxuXHRcdFx0KXtcclxuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGludGVydmFsX0FbIDAgXSA9IHBhcnNlSW50KCBpbnRlcnZhbF9BWyAwIF0gKTtcclxuXHRcdFx0aW50ZXJ2YWxfQVsgMSBdID0gcGFyc2VJbnQoIGludGVydmFsX0FbIDEgXSApO1xyXG5cdFx0XHRpbnRlcnZhbF9CWyAwIF0gPSBwYXJzZUludCggaW50ZXJ2YWxfQlsgMCBdICk7XHJcblx0XHRcdGludGVydmFsX0JbIDEgXSA9IHBhcnNlSW50KCBpbnRlcnZhbF9CWyAxIF0gKTtcclxuXHJcblx0XHRcdHZhciBpc19pbnRlcnNlY3RlZCA9IE1hdGgubWF4KCBpbnRlcnZhbF9BWyAwIF0sIGludGVydmFsX0JbIDAgXSApIC0gTWF0aC5taW4oIGludGVydmFsX0FbIDEgXSwgaW50ZXJ2YWxfQlsgMSBdICk7XHJcblxyXG5cdFx0XHQvLyBpZiAoIDAgPT0gaXNfaW50ZXJzZWN0ZWQgKSB7XHJcblx0XHRcdC8vXHQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTdWNoIHJhbmdlcyBnb2luZyBvbmUgYWZ0ZXIgb3RoZXIsIGUuZy46IFsgMTIsIDE1IF0gYW5kIFsgMTUsIDIxIF1cclxuXHRcdFx0Ly8gfVxyXG5cclxuXHRcdFx0aWYgKCBpc19pbnRlcnNlY3RlZCA8IDAgKSB7XHJcblx0XHRcdFx0cmV0dXJuIHRydWU7ICAgICAgICAgICAgICAgICAgICAgLy8gSU5URVJTRUNURURcclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cmV0dXJuIGZhbHNlOyAgICAgICAgICAgICAgICAgICAgICAgLy8gTm90IGludGVyc2VjdGVkXHJcblx0XHR9XHJcblxyXG5cclxuXHRcdC8qKlxyXG5cdFx0ICogR2V0IHRoZSBjbG9zZXRzIEFCUyB2YWx1ZSBvZiBlbGVtZW50IGluIGFycmF5IHRvIHRoZSBjdXJyZW50IG15VmFsdWVcclxuXHRcdCAqXHJcblx0XHQgKiBAcGFyYW0gbXlWYWx1ZSBcdC0gaW50IGVsZW1lbnQgdG8gc2VhcmNoIGNsb3NldCBcdFx0XHQ0XHJcblx0XHQgKiBAcGFyYW0gbXlBcnJheVx0LSBhcnJheSBvZiBlbGVtZW50cyB3aGVyZSB0byBzZWFyY2ggXHRbNSw4LDEsN11cclxuXHRcdCAqIEByZXR1cm5zIGludFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdDVcclxuXHRcdCAqL1xyXG5cdFx0ZnVuY3Rpb24gd3BiY19nZXRfYWJzX2Nsb3Nlc3RfdmFsdWVfaW5fYXJyKCBteVZhbHVlLCBteUFycmF5ICl7XHJcblxyXG5cdFx0XHRpZiAoIG15QXJyYXkubGVuZ3RoID09IDAgKXsgXHRcdFx0XHRcdFx0XHRcdC8vIElmIHRoZSBhcnJheSBpcyBlbXB0eSAtPiByZXR1cm4gIHRoZSBteVZhbHVlXHJcblx0XHRcdFx0cmV0dXJuIG15VmFsdWU7XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHZhciBvYmogPSBteUFycmF5WyAwIF07XHJcblx0XHRcdHZhciBkaWZmID0gTWF0aC5hYnMoIG15VmFsdWUgLSBvYmogKTsgICAgICAgICAgICAgXHQvLyBHZXQgZGlzdGFuY2UgYmV0d2VlbiAgMXN0IGVsZW1lbnRcclxuXHRcdFx0dmFyIGNsb3NldFZhbHVlID0gbXlBcnJheVsgMCBdOyAgICAgICAgICAgICAgICAgICBcdFx0XHQvLyBTYXZlIDFzdCBlbGVtZW50XHJcblxyXG5cdFx0XHRmb3IgKCB2YXIgaSA9IDE7IGkgPCBteUFycmF5Lmxlbmd0aDsgaSsrICl7XHJcblx0XHRcdFx0b2JqID0gbXlBcnJheVsgaSBdO1xyXG5cclxuXHRcdFx0XHRpZiAoIE1hdGguYWJzKCBteVZhbHVlIC0gb2JqICkgPCBkaWZmICl7ICAgICBcdFx0XHQvLyB3ZSBmb3VuZCBjbG9zZXIgdmFsdWUgLT4gc2F2ZSBpdFxyXG5cdFx0XHRcdFx0ZGlmZiA9IE1hdGguYWJzKCBteVZhbHVlIC0gb2JqICk7XHJcblx0XHRcdFx0XHRjbG9zZXRWYWx1ZSA9IG9iajtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHJldHVybiBjbG9zZXRWYWx1ZTtcclxuXHRcdH1cclxuXHJcblxyXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuLyogID09ICBUIE8gTyBMIFQgSSBQIFMgID09XHJcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqL1xyXG5cclxuXHQvKipcclxuXHQgKiBEZWZpbmUgdG9vbHRpcCB0byBzaG93LCAgd2hlbiAgbW91c2Ugb3ZlciBEYXRlIGluIENhbGVuZGFyXHJcblx0ICpcclxuXHQgKiBAcGFyYW0gIHRvb2x0aXBfdGV4dFx0XHRcdC0gVGV4dCB0byBzaG93XHRcdFx0XHQnQm9va2VkIHRpbWU6IDEyOjAwIC0gMTM6MDA8YnI+Q29zdDogJDIwLjAwJ1xyXG5cdCAqIEBwYXJhbSAgcmVzb3VyY2VfaWRcdFx0XHQtIElEIG9mIGJvb2tpbmcgcmVzb3VyY2VcdCcxJ1xyXG5cdCAqIEBwYXJhbSAgdGRfY2xhc3NcdFx0XHRcdC0gU1FMIGNsYXNzXHRcdFx0XHRcdCcxLTktMjAyMydcclxuXHQgKiBAcmV0dXJucyB7Ym9vbGVhbn1cdFx0XHRcdFx0LSBkZWZpbmVkIHRvIHNob3cgb3Igbm90XHJcblx0ICovXHJcblx0ZnVuY3Rpb24gd3BiY19zZXRfdG9vbHRpcF9fX2Zvcl9fY2FsZW5kYXJfZGF0ZSggdG9vbHRpcF90ZXh0LCByZXNvdXJjZV9pZCwgdGRfY2xhc3MgKXtcclxuXHJcblx0XHQvL1RPRE86IG1ha2UgZXNjYXBpbmcgb2YgdGV4dCBmb3IgcXVvdCBzeW1ib2xzLCAgYW5kIEpTL0hUTUwuLi5cclxuXHJcblx0XHRqUXVlcnkoICcjY2FsZW5kYXJfYm9va2luZycgKyByZXNvdXJjZV9pZCArICcgdGQuY2FsNGRhdGUtJyArIHRkX2NsYXNzICkuYXR0ciggJ2RhdGEtY29udGVudCcsIHRvb2x0aXBfdGV4dCApO1xyXG5cclxuXHRcdHZhciB0ZF9lbCA9IGpRdWVyeSggJyNjYWxlbmRhcl9ib29raW5nJyArIHJlc291cmNlX2lkICsgJyB0ZC5jYWw0ZGF0ZS0nICsgdGRfY2xhc3MgKS5nZXQoIDAgKTtcdFx0XHRcdFx0Ly8gRml4SW46IDkuMC4xLjEuXHJcblxyXG5cdFx0aWYgKFxyXG5cdFx0XHQgICAoICd1bmRlZmluZWQnICE9PSB0eXBlb2YodGRfZWwpIClcclxuXHRcdFx0JiYgKCB1bmRlZmluZWQgPT0gdGRfZWwuX3RpcHB5IClcclxuXHRcdFx0JiYgKCAnJyAhPT0gdG9vbHRpcF90ZXh0IClcclxuXHRcdCl7XHJcblxyXG5cdFx0XHR3cGJjX3RpcHB5KCB0ZF9lbCAsIHtcclxuXHRcdFx0XHRcdGNvbnRlbnQoIHJlZmVyZW5jZSApe1xyXG5cclxuXHRcdFx0XHRcdFx0dmFyIHBvcG92ZXJfY29udGVudCA9IHJlZmVyZW5jZS5nZXRBdHRyaWJ1dGUoICdkYXRhLWNvbnRlbnQnICk7XHJcblxyXG5cdFx0XHRcdFx0XHRyZXR1cm4gJzxkaXYgY2xhc3M9XCJwb3BvdmVyIHBvcG92ZXJfdGlwcHlcIj4nXHJcblx0XHRcdFx0XHRcdFx0XHRcdCsgJzxkaXYgY2xhc3M9XCJwb3BvdmVyLWNvbnRlbnRcIj4nXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0KyBwb3BvdmVyX2NvbnRlbnRcclxuXHRcdFx0XHRcdFx0XHRcdFx0KyAnPC9kaXY+J1xyXG5cdFx0XHRcdFx0XHRcdCArICc8L2Rpdj4nO1xyXG5cdFx0XHRcdFx0fSxcclxuXHRcdFx0XHRcdGFsbG93SFRNTCAgICAgICAgOiB0cnVlLFxyXG5cdFx0XHRcdFx0dHJpZ2dlclx0XHRcdCA6ICdtb3VzZWVudGVyIGZvY3VzJyxcclxuXHRcdFx0XHRcdGludGVyYWN0aXZlICAgICAgOiBmYWxzZSxcclxuXHRcdFx0XHRcdGhpZGVPbkNsaWNrICAgICAgOiB0cnVlLFxyXG5cdFx0XHRcdFx0aW50ZXJhY3RpdmVCb3JkZXI6IDEwLFxyXG5cdFx0XHRcdFx0bWF4V2lkdGggICAgICAgICA6IDU1MCxcclxuXHRcdFx0XHRcdHRoZW1lICAgICAgICAgICAgOiAnd3BiYy10aXBweS10aW1lcycsXHJcblx0XHRcdFx0XHRwbGFjZW1lbnQgICAgICAgIDogJ3RvcCcsXHJcblx0XHRcdFx0XHRkZWxheVx0XHRcdCA6IFs0MDAsIDBdLFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vIEZpeEluOiA5LjQuMi4yLlxyXG5cdFx0XHRcdFx0Ly9kZWxheVx0XHRcdCA6IFswLCA5OTk5OTk5OTk5XSxcdFx0XHRcdFx0XHQvLyBEZWJ1Z2UgIHRvb2x0aXBcclxuXHRcdFx0XHRcdGlnbm9yZUF0dHJpYnV0ZXMgOiB0cnVlLFxyXG5cdFx0XHRcdFx0dG91Y2hcdFx0XHQgOiB0cnVlLFx0XHRcdFx0XHRcdFx0XHQvL1snaG9sZCcsIDUwMF0sIC8vIDUwMG1zIGRlbGF5XHRcdFx0XHQvLyBGaXhJbjogOS4yLjEuNS5cclxuXHRcdFx0XHRcdGFwcGVuZFRvOiAoKSA9PiBkb2N1bWVudC5ib2R5LFxyXG5cdFx0XHR9KTtcclxuXHJcblx0XHRcdHJldHVybiAgdHJ1ZTtcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gIGZhbHNlO1xyXG5cdH1cclxuXHJcblxyXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuLyogID09ICBEYXRlcyBGdW5jdGlvbnMgID09XHJcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqL1xyXG5cclxuLyoqXHJcbiAqIEdldCBudW1iZXIgb2YgZGF0ZXMgYmV0d2VlbiAyIEpTIERhdGVzXHJcbiAqXHJcbiAqIEBwYXJhbSBkYXRlMVx0XHRKUyBEYXRlXHJcbiAqIEBwYXJhbSBkYXRlMlx0XHRKUyBEYXRlXHJcbiAqIEByZXR1cm5zIHtudW1iZXJ9XHJcbiAqL1xyXG5mdW5jdGlvbiB3cGJjX2RhdGVzX19kYXlzX2JldHdlZW4oZGF0ZTEsIGRhdGUyKSB7XHJcblxyXG4gICAgLy8gVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgaW4gb25lIGRheVxyXG4gICAgdmFyIE9ORV9EQVkgPSAxMDAwICogNjAgKiA2MCAqIDI0O1xyXG5cclxuICAgIC8vIENvbnZlcnQgYm90aCBkYXRlcyB0byBtaWxsaXNlY29uZHNcclxuICAgIHZhciBkYXRlMV9tcyA9IGRhdGUxLmdldFRpbWUoKTtcclxuICAgIHZhciBkYXRlMl9tcyA9IGRhdGUyLmdldFRpbWUoKTtcclxuXHJcbiAgICAvLyBDYWxjdWxhdGUgdGhlIGRpZmZlcmVuY2UgaW4gbWlsbGlzZWNvbmRzXHJcbiAgICB2YXIgZGlmZmVyZW5jZV9tcyA9ICBkYXRlMV9tcyAtIGRhdGUyX21zO1xyXG5cclxuICAgIC8vIENvbnZlcnQgYmFjayB0byBkYXlzIGFuZCByZXR1cm5cclxuICAgIHJldHVybiBNYXRoLnJvdW5kKGRpZmZlcmVuY2VfbXMvT05FX0RBWSk7XHJcbn1cclxuXHJcblxyXG4vKipcclxuICogQ2hlY2sgIGlmIHRoaXMgYXJyYXkgIG9mIGRhdGVzIGlzIGNvbnNlY3V0aXZlIGFycmF5ICBvZiBkYXRlcyBvciBub3QuXHJcbiAqIFx0XHRlLmcuICBbJzIwMjQtMDUtMDknLCcyMDI0LTA1LTE5JywnMjAyNC0wNS0zMCddIC0+IGZhbHNlXHJcbiAqIFx0XHRlLmcuICBbJzIwMjQtMDUtMDknLCcyMDI0LTA1LTEwJywnMjAyNC0wNS0xMSddIC0+IHRydWVcclxuICogQHBhcmFtIHNxbF9kYXRlc19hcnJcdCBhcnJheVx0XHRlLmcuOiBbJzIwMjQtMDUtMDknLCcyMDI0LTA1LTE5JywnMjAyNC0wNS0zMCddXHJcbiAqIEByZXR1cm5zIHtib29sZWFufVxyXG4gKi9cclxuZnVuY3Rpb24gd3BiY19kYXRlc19faXNfY29uc2VjdXRpdmVfZGF0ZXNfYXJyX3JhbmdlKCBzcWxfZGF0ZXNfYXJyICl7XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQvLyBGaXhJbjogMTAuMC4wLjUwLlxyXG5cclxuXHRpZiAoIHNxbF9kYXRlc19hcnIubGVuZ3RoID4gMSApe1xyXG5cdFx0dmFyIHByZXZpb3NfZGF0ZSA9IHdwYmNfX2dldF9fanNfZGF0ZSggc3FsX2RhdGVzX2FyclsgMCBdICk7XHJcblx0XHR2YXIgY3VycmVudF9kYXRlO1xyXG5cclxuXHRcdGZvciAoIHZhciBpID0gMTsgaSA8IHNxbF9kYXRlc19hcnIubGVuZ3RoOyBpKysgKXtcclxuXHRcdFx0Y3VycmVudF9kYXRlID0gd3BiY19fZ2V0X19qc19kYXRlKCBzcWxfZGF0ZXNfYXJyW2ldICk7XHJcblxyXG5cdFx0XHRpZiAoIHdwYmNfZGF0ZXNfX2RheXNfYmV0d2VlbiggY3VycmVudF9kYXRlLCBwcmV2aW9zX2RhdGUgKSAhPSAxICl7XHJcblx0XHRcdFx0cmV0dXJuICBmYWxzZTtcclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cHJldmlvc19kYXRlID0gY3VycmVudF9kYXRlO1xyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0cmV0dXJuIHRydWU7XHJcbn1cclxuXHJcblxyXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuLyogID09ICBBdXRvIERhdGVzIFNlbGVjdGlvbiAgPT1cclxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovXHJcblxyXG4vKipcclxuICogID09IEhvdyB0byAgdXNlID8gPT1cclxuICpcclxuICogIEZvciBEYXRlcyBzZWxlY3Rpb24sIHdlIG5lZWQgdG8gdXNlIHRoaXMgbG9naWMhICAgICBXZSBuZWVkIHNlbGVjdCB0aGUgZGF0ZXMgb25seSBhZnRlciBib29raW5nIGRhdGEgbG9hZGVkIVxyXG4gKlxyXG4gKiAgQ2hlY2sgZXhhbXBsZSBiZWxsb3cuXHJcbiAqXHJcbiAqXHQvLyBGaXJlIG9uIGFsbCBib29raW5nIGRhdGVzIGxvYWRlZFxyXG4gKlx0alF1ZXJ5KCAnYm9keScgKS5vbiggJ3dwYmNfY2FsZW5kYXJfYWp4X19sb2FkZWRfZGF0YScsIGZ1bmN0aW9uICggZXZlbnQsIGxvYWRlZF9yZXNvdXJjZV9pZCApe1xyXG4gKlxyXG4gKlx0XHRpZiAoIGxvYWRlZF9yZXNvdXJjZV9pZCA9PSBzZWxlY3RfZGF0ZXNfaW5fY2FsZW5kYXJfaWQgKXtcclxuICpcdFx0XHR3cGJjX2F1dG9fc2VsZWN0X2RhdGVzX2luX2NhbGVuZGFyKCBzZWxlY3RfZGF0ZXNfaW5fY2FsZW5kYXJfaWQsICcyMDI0LTA1LTE1JywgJzIwMjQtMDUtMjUnICk7XHJcbiAqXHRcdH1cclxuICpcdH0gKTtcclxuICpcclxuICovXHJcblxyXG5cclxuLyoqXHJcbiAqIFRyeSB0byBBdXRvIHNlbGVjdCBkYXRlcyBpbiBzcGVjaWZpYyBjYWxlbmRhciBieSBzaW11bGF0ZWQgY2xpY2tzIGluIGRhdGVwaWNrZXJcclxuICpcclxuICogQHBhcmFtIHJlc291cmNlX2lkXHRcdDFcclxuICogQHBhcmFtIGNoZWNrX2luX3ltZFx0XHQnMjAyNC0wNS0wOSdcdFx0T1IgIFx0WycyMDI0LTA1LTA5JywnMjAyNC0wNS0xOScsJzIwMjQtMDUtMjAnXVxyXG4gKiBAcGFyYW0gY2hlY2tfb3V0X3ltZFx0XHQnMjAyNC0wNS0xNSdcdFx0T3B0aW9uYWxcclxuICpcclxuICogQHJldHVybnMge251bWJlcn1cdFx0bnVtYmVyIG9mIHNlbGVjdGVkIGRhdGVzXHJcbiAqXHJcbiAqIFx0RXhhbXBsZSAxOlx0XHRcdFx0dmFyIG51bV9zZWxlY3RlZF9kYXlzID0gd3BiY19hdXRvX3NlbGVjdF9kYXRlc19pbl9jYWxlbmRhciggMSwgJzIwMjQtMDUtMTUnLFxyXG4gKiAgICAgJzIwMjQtMDUtMjUnICk7IEV4YW1wbGUgMjpcdFx0XHRcdHZhciBudW1fc2VsZWN0ZWRfZGF5cyA9IHdwYmNfYXV0b19zZWxlY3RfZGF0ZXNfaW5fY2FsZW5kYXIoIDEsXHJcbiAqICAgICBbJzIwMjQtMDUtMDknLCcyMDI0LTA1LTE5JywnMjAyNC0wNS0yMCddICk7XHJcbiAqL1xyXG5mdW5jdGlvbiB3cGJjX2F1dG9fc2VsZWN0X2RhdGVzX2luX2NhbGVuZGFyKCByZXNvdXJjZV9pZCwgY2hlY2tfaW5feW1kLCBjaGVja19vdXRfeW1kID0gJycgKXtcdFx0XHRcdFx0XHRcdFx0Ly8gRml4SW46IDEwLjAuMC40Ny5cclxuXHJcblx0Y29uc29sZS5sb2coICdXUEJDX0FVVE9fU0VMRUNUX0RBVEVTX0lOX0NBTEVOREFSKCBSRVNPVVJDRV9JRCwgQ0hFQ0tfSU5fWU1ELCBDSEVDS19PVVRfWU1EICknLCByZXNvdXJjZV9pZCwgY2hlY2tfaW5feW1kLCBjaGVja19vdXRfeW1kICk7XHJcblxyXG5cdGlmIChcclxuXHRcdCAgICggJzIxMDAtMDEtMDEnID09IGNoZWNrX2luX3ltZCApXHJcblx0XHR8fCAoICcyMTAwLTAxLTAxJyA9PSBjaGVja19vdXRfeW1kIClcclxuXHRcdHx8ICggKCAnJyA9PSBjaGVja19pbl95bWQgKSAmJiAoICcnID09IGNoZWNrX291dF95bWQgKSApXHJcblx0KXtcclxuXHRcdHJldHVybiAwO1xyXG5cdH1cclxuXHJcblx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHQvLyBJZiBcdGNoZWNrX2luX3ltZCAgPSAgWyAnMjAyNC0wNS0wOScsJzIwMjQtMDUtMTknLCcyMDI0LTA1LTMwJyBdXHRcdFx0XHRBUlJBWSBvZiBEQVRFU1x0XHRcdFx0XHRcdC8vIEZpeEluOiAxMC4wLjAuNTAuXHJcblx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHR2YXIgZGF0ZXNfdG9fc2VsZWN0X2FyciA9IFtdO1xyXG5cdGlmICggQXJyYXkuaXNBcnJheSggY2hlY2tfaW5feW1kICkgKXtcclxuXHRcdGRhdGVzX3RvX3NlbGVjdF9hcnIgPSB3cGJjX2Nsb25lX29iaiggY2hlY2tfaW5feW1kICk7XHJcblxyXG5cdFx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdFx0Ly8gRXhjZXB0aW9ucyB0byAgc2V0ICBcdE1VTFRJUExFIERBWVMgXHRtb2RlXHJcblx0XHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHQvLyBpZiBkYXRlcyBhcyBOT1QgQ09OU0VDVVRJVkU6IFsnMjAyNC0wNS0wOScsJzIwMjQtMDUtMTknLCcyMDI0LTA1LTMwJ10sIC0+IHNldCBNVUxUSVBMRSBEQVlTIG1vZGVcclxuXHRcdGlmIChcclxuXHRcdFx0ICAgKCBkYXRlc190b19zZWxlY3RfYXJyLmxlbmd0aCA+IDAgKVxyXG5cdFx0XHQmJiAoICcnID09IGNoZWNrX291dF95bWQgKVxyXG5cdFx0XHQmJiAoICEgd3BiY19kYXRlc19faXNfY29uc2VjdXRpdmVfZGF0ZXNfYXJyX3JhbmdlKCBkYXRlc190b19zZWxlY3RfYXJyICkgKVxyXG5cdFx0KXtcclxuXHRcdFx0d3BiY19jYWxfZGF5c19zZWxlY3RfX211bHRpcGxlKCByZXNvdXJjZV9pZCApO1xyXG5cdFx0fVxyXG5cdFx0Ly8gaWYgbXVsdGlwbGUgZGF5cyB0byBzZWxlY3QsIGJ1dCBlbmFibGVkIFNJTkdMRSBkYXkgbW9kZSwgLT4gc2V0IE1VTFRJUExFIERBWVMgbW9kZVxyXG5cdFx0aWYgKFxyXG5cdFx0XHQgICAoIGRhdGVzX3RvX3NlbGVjdF9hcnIubGVuZ3RoID4gMSApXHJcblx0XHRcdCYmICggJycgPT0gY2hlY2tfb3V0X3ltZCApXHJcblx0XHRcdCYmICggJ3NpbmdsZScgPT09IF93cGJjLmNhbGVuZGFyX19nZXRfcGFyYW1fdmFsdWUoIHJlc291cmNlX2lkLCAnZGF5c19zZWxlY3RfbW9kZScgKSApXHJcblx0XHQpe1xyXG5cdFx0XHR3cGJjX2NhbF9kYXlzX3NlbGVjdF9fbXVsdGlwbGUoIHJlc291cmNlX2lkICk7XHJcblx0XHR9XHJcblx0XHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHRjaGVja19pbl95bWQgPSBkYXRlc190b19zZWxlY3RfYXJyWyAwIF07XHJcblx0XHRpZiAoICcnID09IGNoZWNrX291dF95bWQgKXtcclxuXHRcdFx0Y2hlY2tfb3V0X3ltZCA9IGRhdGVzX3RvX3NlbGVjdF9hcnJbIChkYXRlc190b19zZWxlY3RfYXJyLmxlbmd0aC0xKSBdO1xyXG5cdFx0fVxyXG5cdH1cclxuXHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cclxuXHJcblx0aWYgKCAnJyA9PSBjaGVja19pbl95bWQgKXtcclxuXHRcdGNoZWNrX2luX3ltZCA9IGNoZWNrX291dF95bWQ7XHJcblx0fVxyXG5cdGlmICggJycgPT0gY2hlY2tfb3V0X3ltZCApe1xyXG5cdFx0Y2hlY2tfb3V0X3ltZCA9IGNoZWNrX2luX3ltZDtcclxuXHR9XHJcblxyXG5cdGlmICggJ3VuZGVmaW5lZCcgPT09IHR5cGVvZiAocmVzb3VyY2VfaWQpICl7XHJcblx0XHRyZXNvdXJjZV9pZCA9ICcxJztcclxuXHR9XHJcblxyXG5cclxuXHR2YXIgaW5zdCA9IHdwYmNfY2FsZW5kYXJfX2dldF9pbnN0KCByZXNvdXJjZV9pZCApO1xyXG5cclxuXHRpZiAoIG51bGwgIT09IGluc3QgKXtcclxuXHJcblx0XHQvLyBVbnNlbGVjdCBhbGwgZGF0ZXMgYW5kIHNldCAgcHJvcGVydGllcyBvZiBEYXRlcGlja1xyXG5cdFx0alF1ZXJ5KCAnI2RhdGVfYm9va2luZycgKyByZXNvdXJjZV9pZCApLnZhbCggJycgKTsgICAgICBcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly9GaXhJbjogNS40LjNcclxuXHRcdGluc3Quc3RheU9wZW4gPSBmYWxzZTtcclxuXHRcdGluc3QuZGF0ZXMgPSBbXTtcclxuXHRcdHZhciBjaGVja19pbl9qcyA9IHdwYmNfX2dldF9fanNfZGF0ZSggY2hlY2tfaW5feW1kICk7XHJcblx0XHR2YXIgdGRfY2VsbCAgICAgPSB3cGJjX2dldF9jbGlja2VkX3RkKCBpbnN0LmlkLCBjaGVja19pbl9qcyApO1xyXG5cclxuXHRcdC8vIElzIG9tZSB0eXBlIG9mIGVycm9yLCB0aGVuIHNlbGVjdCBtdWx0aXBsZSBkYXlzIHNlbGVjdGlvbiAgbW9kZS5cclxuXHRcdGlmICggJycgPT09IF93cGJjLmNhbGVuZGFyX19nZXRfcGFyYW1fdmFsdWUoIHJlc291cmNlX2lkLCAnZGF5c19zZWxlY3RfbW9kZScgKSApIHtcclxuIFx0XHRcdF93cGJjLmNhbGVuZGFyX19zZXRfcGFyYW1fdmFsdWUoIHJlc291cmNlX2lkLCAnZGF5c19zZWxlY3RfbW9kZScsICdtdWx0aXBsZScgKTtcclxuXHRcdH1cclxuXHJcblxyXG5cdFx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHQvLyAgPT0gRFlOQU1JQyA9PVxyXG5cdFx0aWYgKCAnZHluYW1pYycgPT09IF93cGJjLmNhbGVuZGFyX19nZXRfcGFyYW1fdmFsdWUoIHJlc291cmNlX2lkLCAnZGF5c19zZWxlY3RfbW9kZScgKSApe1xyXG5cdFx0XHQvLyAxLXN0IGNsaWNrXHJcblx0XHRcdGluc3Quc3RheU9wZW4gPSBmYWxzZTtcclxuXHRcdFx0alF1ZXJ5LmRhdGVwaWNrLl9zZWxlY3REYXkoIHRkX2NlbGwsICcjJyArIGluc3QuaWQsIGNoZWNrX2luX2pzLmdldFRpbWUoKSApO1xyXG5cdFx0XHRpZiAoIDAgPT09IGluc3QuZGF0ZXMubGVuZ3RoICl7XHJcblx0XHRcdFx0cmV0dXJuIDA7ICBcdFx0XHRcdFx0XHRcdFx0Ly8gRmlyc3QgY2xpY2sgIHdhcyB1bnN1Y2Nlc3NmdWwsIHNvIHdlIG11c3Qgbm90IG1ha2Ugb3RoZXIgY2xpY2tcclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gMi1uZCBjbGlja1xyXG5cdFx0XHR2YXIgY2hlY2tfb3V0X2pzID0gd3BiY19fZ2V0X19qc19kYXRlKCBjaGVja19vdXRfeW1kICk7XHJcblx0XHRcdHZhciB0ZF9jZWxsX291dCA9IHdwYmNfZ2V0X2NsaWNrZWRfdGQoIGluc3QuaWQsIGNoZWNrX291dF9qcyApO1xyXG5cdFx0XHRpbnN0LnN0YXlPcGVuID0gdHJ1ZTtcclxuXHRcdFx0alF1ZXJ5LmRhdGVwaWNrLl9zZWxlY3REYXkoIHRkX2NlbGxfb3V0LCAnIycgKyBpbnN0LmlkLCBjaGVja19vdXRfanMuZ2V0VGltZSgpICk7XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHQvLyAgPT0gRklYRUQgPT1cclxuXHRcdGlmICggICdmaXhlZCcgPT09IF93cGJjLmNhbGVuZGFyX19nZXRfcGFyYW1fdmFsdWUoIHJlc291cmNlX2lkLCAnZGF5c19zZWxlY3RfbW9kZScgKSkge1xyXG5cdFx0XHRqUXVlcnkuZGF0ZXBpY2suX3NlbGVjdERheSggdGRfY2VsbCwgJyMnICsgaW5zdC5pZCwgY2hlY2tfaW5fanMuZ2V0VGltZSgpICk7XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHQvLyAgPT0gU0lOR0xFID09XHJcblx0XHRpZiAoICdzaW5nbGUnID09PSBfd3BiYy5jYWxlbmRhcl9fZ2V0X3BhcmFtX3ZhbHVlKCByZXNvdXJjZV9pZCwgJ2RheXNfc2VsZWN0X21vZGUnICkgKXtcclxuXHRcdFx0Ly9qUXVlcnkuZGF0ZXBpY2suX3Jlc3RyaWN0TWluTWF4KCBpbnN0LCBqUXVlcnkuZGF0ZXBpY2suX2RldGVybWluZURhdGUoIGluc3QsIGNoZWNrX2luX2pzLCBudWxsICkgKTtcdFx0Ly8gRG8gd2UgbmVlZCB0byBydW4gIHRoaXMgPyBQbGVhc2Ugbm90ZSwgY2hlY2tfaW5fanMgbXVzdCAgaGF2ZSB0aW1lLCAgbWluLCBzZWMgZGVmaW5lZCB0byAwIVxyXG5cdFx0XHRqUXVlcnkuZGF0ZXBpY2suX3NlbGVjdERheSggdGRfY2VsbCwgJyMnICsgaW5zdC5pZCwgY2hlY2tfaW5fanMuZ2V0VGltZSgpICk7XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHQvLyAgPT0gTVVMVElQTEUgPT1cclxuXHRcdGlmICggJ211bHRpcGxlJyA9PT0gX3dwYmMuY2FsZW5kYXJfX2dldF9wYXJhbV92YWx1ZSggcmVzb3VyY2VfaWQsICdkYXlzX3NlbGVjdF9tb2RlJyApICl7XHJcblxyXG5cdFx0XHR2YXIgZGF0ZXNfYXJyO1xyXG5cclxuXHRcdFx0aWYgKCBkYXRlc190b19zZWxlY3RfYXJyLmxlbmd0aCA+IDAgKXtcclxuXHRcdFx0XHQvLyBTaXR1YXRpb24sIHdoZW4gd2UgaGF2ZSBkYXRlcyBhcnJheTogWycyMDI0LTA1LTA5JywnMjAyNC0wNS0xOScsJzIwMjQtMDUtMzAnXS4gIGFuZCBub3QgdGhlIENoZWNrIEluIC8gQ2hlY2sgIG91dCBkYXRlcyBhcyBwYXJhbWV0ZXIgaW4gdGhpcyBmdW5jdGlvblxyXG5cdFx0XHRcdGRhdGVzX2FyciA9IHdwYmNfZ2V0X3NlbGVjdGlvbl9kYXRlc19qc19zdHJfYXJyX19mcm9tX2FyciggZGF0ZXNfdG9fc2VsZWN0X2FyciApO1xyXG5cdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdGRhdGVzX2FyciA9IHdwYmNfZ2V0X3NlbGVjdGlvbl9kYXRlc19qc19zdHJfYXJyX19mcm9tX2NoZWNrX2luX291dCggY2hlY2tfaW5feW1kLCBjaGVja19vdXRfeW1kLCBpbnN0ICk7XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggMCA9PT0gZGF0ZXNfYXJyLmRhdGVzX2pzLmxlbmd0aCApe1xyXG5cdFx0XHRcdHJldHVybiAwO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBGb3IgQ2FsZW5kYXIgRGF5cyBzZWxlY3Rpb25cclxuXHRcdFx0Zm9yICggdmFyIGogPSAwOyBqIDwgZGF0ZXNfYXJyLmRhdGVzX2pzLmxlbmd0aDsgaisrICl7ICAgICAgIC8vIExvb3AgYXJyYXkgb2YgZGF0ZXNcclxuXHJcblx0XHRcdFx0dmFyIHN0cl9kYXRlID0gd3BiY19fZ2V0X19zcWxfY2xhc3NfZGF0ZSggZGF0ZXNfYXJyLmRhdGVzX2pzWyBqIF0gKTtcclxuXHJcblx0XHRcdFx0Ly8gRGF0ZSB1bmF2YWlsYWJsZSAhXHJcblx0XHRcdFx0aWYgKCAwID09IF93cGJjLmJvb2tpbmdzX2luX2NhbGVuZGFyX19nZXRfZm9yX2RhdGUoIHJlc291cmNlX2lkLCBzdHJfZGF0ZSApLmRheV9hdmFpbGFiaWxpdHkgKXtcclxuXHRcdFx0XHRcdHJldHVybiAwO1xyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0aWYgKCBkYXRlc19hcnIuZGF0ZXNfanNbIGogXSAhPSAtMSApIHtcclxuXHRcdFx0XHRcdGluc3QuZGF0ZXMucHVzaCggZGF0ZXNfYXJyLmRhdGVzX2pzWyBqIF0gKTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHZhciBjaGVja19vdXRfZGF0ZSA9IGRhdGVzX2Fyci5kYXRlc19qc1sgKGRhdGVzX2Fyci5kYXRlc19qcy5sZW5ndGggLSAxKSBdO1xyXG5cclxuXHRcdFx0aW5zdC5kYXRlcy5wdXNoKCBjaGVja19vdXRfZGF0ZSApOyBcdFx0XHQvLyBOZWVkIGFkZCBvbmUgYWRkaXRpb25hbCBTQU1FIGRhdGUgZm9yIGNvcnJlY3QgIHdvcmtzIG9mIGRhdGVzIHNlbGVjdGlvbiAhISEhIVxyXG5cclxuXHRcdFx0dmFyIGNoZWNrb3V0X3RpbWVzdGFtcCA9IGNoZWNrX291dF9kYXRlLmdldFRpbWUoKTtcclxuXHRcdFx0dmFyIHRkX2NlbGwgPSB3cGJjX2dldF9jbGlja2VkX3RkKCBpbnN0LmlkLCBjaGVja19vdXRfZGF0ZSApO1xyXG5cclxuXHRcdFx0alF1ZXJ5LmRhdGVwaWNrLl9zZWxlY3REYXkoIHRkX2NlbGwsICcjJyArIGluc3QuaWQsIGNoZWNrb3V0X3RpbWVzdGFtcCApO1xyXG5cdFx0fVxyXG5cclxuXHJcblx0XHRpZiAoIDAgIT09IGluc3QuZGF0ZXMubGVuZ3RoICl7XHJcblx0XHRcdC8vIFNjcm9sbCB0byBzcGVjaWZpYyBtb250aCwgaWYgd2Ugc2V0IGRhdGVzIGluIHNvbWUgZnV0dXJlIG1vbnRoc1xyXG5cdFx0XHR3cGJjX2NhbGVuZGFyX19zY3JvbGxfdG8oIHJlc291cmNlX2lkLCBpbnN0LmRhdGVzWyAwIF0uZ2V0RnVsbFllYXIoKSwgaW5zdC5kYXRlc1sgMCBdLmdldE1vbnRoKCkrMSApO1xyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB3cGJjX2dldF9fc2VsZWN0ZWRfZGF0ZXNfc3FsX19hc19hcnIoIHJlc291cmNlX2lkICkubGVuZ3RoO1xuXHR9XHJcblxyXG5cdHJldHVybiAwO1xyXG59XHJcblxyXG5cdC8qKlxyXG5cdCAqIEdldCBIVE1MIHRkIGVsZW1lbnQgKHdoZXJlIHdhcyBjbGljayBpbiBjYWxlbmRhciAgZGF5ICBjZWxsKVxyXG5cdCAqXHJcblx0ICogQHBhcmFtIGNhbGVuZGFyX2h0bWxfaWRcdFx0XHQnY2FsZW5kYXJfYm9va2luZzEnXHJcblx0ICogQHBhcmFtIGRhdGVfanNcdFx0XHRcdFx0SlMgRGF0ZVxyXG5cdCAqIEByZXR1cm5zIHsqfGpRdWVyeX1cdFx0XHRcdERvbSBIVE1MIHRkIGVsZW1lbnRcclxuXHQgKi9cclxuXHRmdW5jdGlvbiB3cGJjX2dldF9jbGlja2VkX3RkKCBjYWxlbmRhcl9odG1sX2lkLCBkYXRlX2pzICl7XHJcblxyXG5cdCAgICB2YXIgdGRfY2VsbCA9IGpRdWVyeSggJyMnICsgY2FsZW5kYXJfaHRtbF9pZCArICcgLnNxbF9kYXRlXycgKyB3cGJjX19nZXRfX3NxbF9jbGFzc19kYXRlKCBkYXRlX2pzICkgKS5nZXQoIDAgKTtcclxuXHJcblx0XHRyZXR1cm4gdGRfY2VsbDtcclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIEdldCBhcnJheXMgb2YgSlMgYW5kIFNRTCBkYXRlcyBhcyBkYXRlcyBhcnJheVxyXG5cdCAqXHJcblx0ICogQHBhcmFtIGNoZWNrX2luX3ltZFx0XHRcdFx0XHRcdFx0JzIwMjQtMDUtMTUnXHJcblx0ICogQHBhcmFtIGNoZWNrX291dF95bWRcdFx0XHRcdFx0XHRcdCcyMDI0LTA1LTI1J1xyXG5cdCAqIEBwYXJhbSBpbnN0XHRcdFx0XHRcdFx0XHRcdFx0RGF0ZXBpY2sgSW5zdC4gVXNlIHdwYmNfY2FsZW5kYXJfX2dldF9pbnN0KCByZXNvdXJjZV9pZCApO1xyXG5cdCAqIEByZXR1cm5zIHt7ZGF0ZXNfanM6ICpbXSwgZGF0ZXNfc3RyOiAqW119fVxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdwYmNfZ2V0X3NlbGVjdGlvbl9kYXRlc19qc19zdHJfYXJyX19mcm9tX2NoZWNrX2luX291dCggY2hlY2tfaW5feW1kLCBjaGVja19vdXRfeW1kICwgaW5zdCApe1xyXG5cclxuXHRcdHZhciBvcmlnaW5hbF9hcnJheSA9IFtdO1xyXG5cdFx0dmFyIGRhdGU7XHJcblx0XHR2YXIgYmtfZGlzdGluY3RfZGF0ZXMgPSBbXTtcclxuXHJcblx0XHR2YXIgY2hlY2tfaW5fZGF0ZSA9IGNoZWNrX2luX3ltZC5zcGxpdCggJy0nICk7XHJcblx0XHR2YXIgY2hlY2tfb3V0X2RhdGUgPSBjaGVja19vdXRfeW1kLnNwbGl0KCAnLScgKTtcclxuXHJcblx0XHRkYXRlID0gbmV3IERhdGUoKTtcclxuXHRcdGRhdGUuc2V0RnVsbFllYXIoIGNoZWNrX2luX2RhdGVbIDAgXSwgKGNoZWNrX2luX2RhdGVbIDEgXSAtIDEpLCBjaGVja19pbl9kYXRlWyAyIF0gKTsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyB5ZWFyLCBtb250aCwgZGF0ZVxyXG5cdFx0dmFyIG9yaWdpbmFsX2NoZWNrX2luX2RhdGUgPSBkYXRlO1xyXG5cdFx0b3JpZ2luYWxfYXJyYXkucHVzaCggalF1ZXJ5LmRhdGVwaWNrLl9yZXN0cmljdE1pbk1heCggaW5zdCwgalF1ZXJ5LmRhdGVwaWNrLl9kZXRlcm1pbmVEYXRlKCBpbnN0LCBkYXRlLCBudWxsICkgKSApOyAvL2FkZCBkYXRlXHJcblx0XHRpZiAoICEgd3BiY19pbl9hcnJheSggYmtfZGlzdGluY3RfZGF0ZXMsIChjaGVja19pbl9kYXRlWyAyIF0gKyAnLicgKyBjaGVja19pbl9kYXRlWyAxIF0gKyAnLicgKyBjaGVja19pbl9kYXRlWyAwIF0pICkgKXtcclxuXHRcdFx0YmtfZGlzdGluY3RfZGF0ZXMucHVzaCggcGFyc2VJbnQoY2hlY2tfaW5fZGF0ZVsgMiBdKSArICcuJyArIHBhcnNlSW50KGNoZWNrX2luX2RhdGVbIDEgXSkgKyAnLicgKyBjaGVja19pbl9kYXRlWyAwIF0gKTtcclxuXHRcdH1cclxuXHJcblx0XHR2YXIgZGF0ZV9vdXQgPSBuZXcgRGF0ZSgpO1xyXG5cdFx0ZGF0ZV9vdXQuc2V0RnVsbFllYXIoIGNoZWNrX291dF9kYXRlWyAwIF0sIChjaGVja19vdXRfZGF0ZVsgMSBdIC0gMSksIGNoZWNrX291dF9kYXRlWyAyIF0gKTsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyB5ZWFyLCBtb250aCwgZGF0ZVxyXG5cdFx0dmFyIG9yaWdpbmFsX2NoZWNrX291dF9kYXRlID0gZGF0ZV9vdXQ7XHJcblxyXG5cdFx0dmFyIG1ld0RhdGUgPSBuZXcgRGF0ZSggb3JpZ2luYWxfY2hlY2tfaW5fZGF0ZS5nZXRGdWxsWWVhcigpLCBvcmlnaW5hbF9jaGVja19pbl9kYXRlLmdldE1vbnRoKCksIG9yaWdpbmFsX2NoZWNrX2luX2RhdGUuZ2V0RGF0ZSgpICk7XHJcblx0XHRtZXdEYXRlLnNldERhdGUoIG9yaWdpbmFsX2NoZWNrX2luX2RhdGUuZ2V0RGF0ZSgpICsgMSApO1xyXG5cclxuXHRcdHdoaWxlIChcclxuXHRcdFx0KG9yaWdpbmFsX2NoZWNrX291dF9kYXRlID4gZGF0ZSkgJiZcclxuXHRcdFx0KG9yaWdpbmFsX2NoZWNrX2luX2RhdGUgIT0gb3JpZ2luYWxfY2hlY2tfb3V0X2RhdGUpICl7XHJcblx0XHRcdGRhdGUgPSBuZXcgRGF0ZSggbWV3RGF0ZS5nZXRGdWxsWWVhcigpLCBtZXdEYXRlLmdldE1vbnRoKCksIG1ld0RhdGUuZ2V0RGF0ZSgpICk7XHJcblxyXG5cdFx0XHRvcmlnaW5hbF9hcnJheS5wdXNoKCBqUXVlcnkuZGF0ZXBpY2suX3Jlc3RyaWN0TWluTWF4KCBpbnN0LCBqUXVlcnkuZGF0ZXBpY2suX2RldGVybWluZURhdGUoIGluc3QsIGRhdGUsIG51bGwgKSApICk7IC8vYWRkIGRhdGVcclxuXHRcdFx0aWYgKCAhd3BiY19pbl9hcnJheSggYmtfZGlzdGluY3RfZGF0ZXMsIChkYXRlLmdldERhdGUoKSArICcuJyArIHBhcnNlSW50KCBkYXRlLmdldE1vbnRoKCkgKyAxICkgKyAnLicgKyBkYXRlLmdldEZ1bGxZZWFyKCkpICkgKXtcclxuXHRcdFx0XHRia19kaXN0aW5jdF9kYXRlcy5wdXNoKCAocGFyc2VJbnQoZGF0ZS5nZXREYXRlKCkpICsgJy4nICsgcGFyc2VJbnQoIGRhdGUuZ2V0TW9udGgoKSArIDEgKSArICcuJyArIGRhdGUuZ2V0RnVsbFllYXIoKSkgKTtcclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0bWV3RGF0ZSA9IG5ldyBEYXRlKCBkYXRlLmdldEZ1bGxZZWFyKCksIGRhdGUuZ2V0TW9udGgoKSwgZGF0ZS5nZXREYXRlKCkgKTtcclxuXHRcdFx0bWV3RGF0ZS5zZXREYXRlKCBtZXdEYXRlLmdldERhdGUoKSArIDEgKTtcclxuXHRcdH1cclxuXHRcdG9yaWdpbmFsX2FycmF5LnBvcCgpO1xyXG5cdFx0YmtfZGlzdGluY3RfZGF0ZXMucG9wKCk7XHJcblxyXG5cdFx0cmV0dXJuIHsnZGF0ZXNfanMnOiBvcmlnaW5hbF9hcnJheSwgJ2RhdGVzX3N0cic6IGJrX2Rpc3RpbmN0X2RhdGVzfTtcclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIEdldCBhcnJheXMgb2YgSlMgYW5kIFNRTCBkYXRlcyBhcyBkYXRlcyBhcnJheVxyXG5cdCAqXHJcblx0ICogQHBhcmFtIGRhdGVzX3RvX3NlbGVjdF9hcnJcdD0gWycyMDI0LTA1LTA5JywnMjAyNC0wNS0xOScsJzIwMjQtMDUtMzAnXVxyXG5cdCAqXHJcblx0ICogQHJldHVybnMge3tkYXRlc19qczogKltdLCBkYXRlc19zdHI6ICpbXX19XHJcblx0ICovXHJcblx0ZnVuY3Rpb24gd3BiY19nZXRfc2VsZWN0aW9uX2RhdGVzX2pzX3N0cl9hcnJfX2Zyb21fYXJyKCBkYXRlc190b19zZWxlY3RfYXJyICl7XHRcdFx0XHRcdFx0XHRcdFx0XHQvLyBGaXhJbjogMTAuMC4wLjUwLlxyXG5cclxuXHRcdHZhciBvcmlnaW5hbF9hcnJheSAgICA9IFtdO1xyXG5cdFx0dmFyIGJrX2Rpc3RpbmN0X2RhdGVzID0gW107XHJcblx0XHR2YXIgb25lX2RhdGVfc3RyO1xyXG5cclxuXHRcdGZvciAoIHZhciBkID0gMDsgZCA8IGRhdGVzX3RvX3NlbGVjdF9hcnIubGVuZ3RoOyBkKysgKXtcclxuXHJcblx0XHRcdG9yaWdpbmFsX2FycmF5LnB1c2goIHdwYmNfX2dldF9fanNfZGF0ZSggZGF0ZXNfdG9fc2VsZWN0X2FyclsgZCBdICkgKTtcclxuXHJcblx0XHRcdG9uZV9kYXRlX3N0ciA9IGRhdGVzX3RvX3NlbGVjdF9hcnJbIGQgXS5zcGxpdCgnLScpXHJcblx0XHRcdGlmICggISB3cGJjX2luX2FycmF5KCBia19kaXN0aW5jdF9kYXRlcywgKG9uZV9kYXRlX3N0clsgMiBdICsgJy4nICsgb25lX2RhdGVfc3RyWyAxIF0gKyAnLicgKyBvbmVfZGF0ZV9zdHJbIDAgXSkgKSApe1xyXG5cdFx0XHRcdGJrX2Rpc3RpbmN0X2RhdGVzLnB1c2goIHBhcnNlSW50KG9uZV9kYXRlX3N0clsgMiBdKSArICcuJyArIHBhcnNlSW50KG9uZV9kYXRlX3N0clsgMSBdKSArICcuJyArIG9uZV9kYXRlX3N0clsgMCBdICk7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4geydkYXRlc19qcyc6IG9yaWdpbmFsX2FycmF5LCAnZGF0ZXNfc3RyJzogb3JpZ2luYWxfYXJyYXl9O1xyXG5cdH1cclxuXHJcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG4vKiAgPT0gIEF1dG8gRmlsbCBGaWVsZHMgLyBBdXRvIFNlbGVjdCBEYXRlcyAgPT1cclxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09ICovXHJcblxyXG5qUXVlcnkoIGRvY3VtZW50ICkucmVhZHkoIGZ1bmN0aW9uICgpe1xyXG5cclxuXHR2YXIgdXJsX3BhcmFtcyA9IG5ldyBVUkxTZWFyY2hQYXJhbXMoIHdpbmRvdy5sb2NhdGlvbi5zZWFyY2ggKTtcclxuXHJcblx0Ly8gRGlzYWJsZSBkYXlzIHNlbGVjdGlvbiAgaW4gY2FsZW5kYXIsICBhZnRlciAgcmVkaXJlY3Rpb24gIGZyb20gIHRoZSBcIlNlYXJjaCByZXN1bHRzIHBhZ2UsICBhZnRlciAgc2VhcmNoICBhdmFpbGFiaWxpdHlcIiBcdFx0XHQvLyBGaXhJbjogOC44LjIuMy5cclxuXHRpZiAgKCAnT24nICE9IF93cGJjLmdldF9vdGhlcl9wYXJhbSggJ2lzX2VuYWJsZWRfYm9va2luZ19zZWFyY2hfcmVzdWx0c19kYXlzX3NlbGVjdCcgKSApIHtcclxuXHRcdGlmIChcclxuXHRcdFx0KCB1cmxfcGFyYW1zLmhhcyggJ3dwYmNfc2VsZWN0X2NoZWNrX2luJyApICkgJiZcclxuXHRcdFx0KCB1cmxfcGFyYW1zLmhhcyggJ3dwYmNfc2VsZWN0X2NoZWNrX291dCcgKSApICYmXHJcblx0XHRcdCggdXJsX3BhcmFtcy5oYXMoICd3cGJjX3NlbGVjdF9jYWxlbmRhcl9pZCcgKSApXHJcblx0XHQpe1xyXG5cclxuXHRcdFx0dmFyIHNlbGVjdF9kYXRlc19pbl9jYWxlbmRhcl9pZCA9IHBhcnNlSW50KCB1cmxfcGFyYW1zLmdldCggJ3dwYmNfc2VsZWN0X2NhbGVuZGFyX2lkJyApICk7XHJcblxyXG5cdFx0XHQvLyBGaXJlIG9uIGFsbCBib29raW5nIGRhdGVzIGxvYWRlZFxyXG5cdFx0XHRqUXVlcnkoICdib2R5JyApLm9uKCAnd3BiY19jYWxlbmRhcl9hanhfX2xvYWRlZF9kYXRhJywgZnVuY3Rpb24gKCBldmVudCwgbG9hZGVkX3Jlc291cmNlX2lkICl7XHJcblxyXG5cdFx0XHRcdGlmICggbG9hZGVkX3Jlc291cmNlX2lkID09IHNlbGVjdF9kYXRlc19pbl9jYWxlbmRhcl9pZCApe1xyXG5cdFx0XHRcdFx0d3BiY19hdXRvX3NlbGVjdF9kYXRlc19pbl9jYWxlbmRhciggc2VsZWN0X2RhdGVzX2luX2NhbGVuZGFyX2lkLCB1cmxfcGFyYW1zLmdldCggJ3dwYmNfc2VsZWN0X2NoZWNrX2luJyApLCB1cmxfcGFyYW1zLmdldCggJ3dwYmNfc2VsZWN0X2NoZWNrX291dCcgKSApO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fSApO1xyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0aWYgKFxuXHRcdHVybF9wYXJhbXMuaGFzKCAnd3BiY19hdXRvX2ZpbGwnIClcblx0XHQmJiAhIGpRdWVyeSggJ2JvZHknICkuaGFzQ2xhc3MoICd3cC1hZG1pbicgKVxuXHQpe1xuXHJcblx0XHR2YXIgd3BiY19hdXRvX2ZpbGxfdmFsdWUgPSB1cmxfcGFyYW1zLmdldCggJ3dwYmNfYXV0b19maWxsJyApO1xyXG5cclxuXHRcdC8vIENvbnZlcnQgYmFjay4gICAgIFNvbWUgc3lzdGVtcyBkbyBub3QgbGlrZSBzeW1ib2wgJ34nIGluIFVSTCwgc28gIHdlIG5lZWQgdG8gcmVwbGFjZSB0byAgc29tZSBvdGhlciBzeW1ib2xzXHJcblx0XHR3cGJjX2F1dG9fZmlsbF92YWx1ZSA9IHdwYmNfYXV0b19maWxsX3ZhbHVlLnJlcGxhY2VBbGwoICdfXl8nLCAnficgKTtcclxuXHJcblx0XHR3cGJjX2F1dG9fZmlsbF9ib29raW5nX2ZpZWxkcyggd3BiY19hdXRvX2ZpbGxfdmFsdWUgKTtcclxuXHR9XHJcblxyXG59ICk7XHJcblxyXG4vKipcclxuICogQXV0b2ZpbGwgLyBzZWxlY3QgYm9va2luZyBmb3JtICBmaWVsZHMgYnkgIHZhbHVlcyBmcm9tICB0aGUgR0VUIHJlcXVlc3QgIHBhcmFtZXRlcjogP3dwYmNfYXV0b19maWxsPVxyXG4gKlxyXG4gKiBVUkwtcHJvdmlkZWQgZmllbGQgbmFtZXMgYXJlIHJlc29sdmVkIHRocm91Z2ggdGhlIGV4YWN0LW5hbWUgRE9NIEFQSSBzb1xuICogdGhleSBjYW4gbmV2ZXIgYmUgaW50ZXJwcmV0ZWQgYXMgQ1NTIHNlbGVjdG9yIHN5bnRheC5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gYXV0b19maWxsX3N0ciBTZXJpYWxpemVkIGZpZWxkLW5hbWUgYW5kIHZhbHVlIHBhaXJzLlxuICogQHJldHVybiB7dm9pZH1cbiAqL1xyXG5mdW5jdGlvbiB3cGJjX2F1dG9fZmlsbF9ib29raW5nX2ZpZWxkcyggYXV0b19maWxsX3N0ciApe1x0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gRml4SW46IDEwLjAuMC40OC5cclxuXHJcblx0aWYgKCAnJyA9PSBhdXRvX2ZpbGxfc3RyICl7XHJcblx0XHRyZXR1cm47XHJcblx0fVxyXG5cclxuLy8gY29uc29sZS5sb2coICdXUEJDX0FVVE9fRklMTF9CT09LSU5HX0ZJRUxEUyggQVVUT19GSUxMX1NUUiApJywgYXV0b19maWxsX3N0cik7XHJcblxyXG5cdHZhciBmaWVsZHNfYXJyID0gd3BiY19hdXRvX2ZpbGxfYm9va2luZ19maWVsZHNfX3BhcnNlKCBhdXRvX2ZpbGxfc3RyICk7XG5cblx0Zm9yICggbGV0IGkgPSAwOyBpIDwgZmllbGRzX2Fyci5sZW5ndGg7IGkrKyApe1xuXHRcdHZhciBmaWVsZF9uYW1lID0gU3RyaW5nKCBmaWVsZHNfYXJyWyBpIF1bICduYW1lJyBdIHx8ICcnICk7XG5cdFx0aWYgKCAnJyA9PT0gZmllbGRfbmFtZSApIHtcblx0XHRcdGNvbnRpbnVlO1xuXHRcdH1cblxuXHRcdHZhciBmaWVsZF9lbGVtZW50cyA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlOYW1lKCBmaWVsZF9uYW1lICk7XG5cdFx0aWYgKCAwIDwgZmllbGRfZWxlbWVudHMubGVuZ3RoICkge1xuXHRcdFx0alF1ZXJ5KCBmaWVsZF9lbGVtZW50cyApLnZhbCggZmllbGRzX2FyclsgaSBdWyAndmFsdWUnIF0gKTtcblx0XHR9XG5cdH1cbn1cblxyXG5cdC8qKlxyXG5cdCAqIFBhcnNlIGRhdGEgZnJvbSAgZ2V0IHBhcmFtZXRlcjpcdD93cGJjX2F1dG9fZmlsbD12aXNpdG9yczIzMV4yfm1heF9jYXBhY2l0eTIzMV4yXHJcblx0ICpcclxuXHQgKiBAcGFyYW0gZGF0YV9zdHIgICAgICA9ICAgJ3Zpc2l0b3JzMjMxXjJ+bWF4X2NhcGFjaXR5MjMxXjInO1xyXG5cdCAqIEByZXR1cm5zIHsqfVxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdwYmNfYXV0b19maWxsX2Jvb2tpbmdfZmllbGRzX19wYXJzZSggZGF0YV9zdHIgKXtcclxuXHJcblx0XHR2YXIgZmlsdGVyX29wdGlvbnNfYXJyID0gW107XHJcblxyXG5cdFx0dmFyIGRhdGFfYXJyID0gZGF0YV9zdHIuc3BsaXQoICd+JyApO1xyXG5cclxuXHRcdGZvciAoIHZhciBqID0gMDsgaiA8IGRhdGFfYXJyLmxlbmd0aDsgaisrICl7XHJcblxyXG5cdFx0XHR2YXIgbXlfZm9ybV9maWVsZCA9IGRhdGFfYXJyWyBqIF0uc3BsaXQoICdeJyApO1xyXG5cclxuXHRcdFx0dmFyIGZpbHRlcl9uYW1lICA9ICgndW5kZWZpbmVkJyAhPT0gdHlwZW9mIChteV9mb3JtX2ZpZWxkWyAwIF0pKSA/IG15X2Zvcm1fZmllbGRbIDAgXSA6ICcnO1xyXG5cdFx0XHR2YXIgZmlsdGVyX3ZhbHVlID0gKCd1bmRlZmluZWQnICE9PSB0eXBlb2YgKG15X2Zvcm1fZmllbGRbIDEgXSkpID8gbXlfZm9ybV9maWVsZFsgMSBdIDogJyc7XHJcblxyXG5cdFx0XHRmaWx0ZXJfb3B0aW9uc19hcnIucHVzaChcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHR7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnbmFtZScgIDogZmlsdGVyX25hbWUsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHQndmFsdWUnIDogZmlsdGVyX3ZhbHVlXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHRcdFx0ICAgKTtcclxuXHRcdH1cclxuXHRcdHJldHVybiBmaWx0ZXJfb3B0aW9uc19hcnI7XHJcblx0fVxyXG5cclxuXHQvKipcclxuXHQgKiBQYXJzZSBkYXRhIGZyb20gIGdldCBwYXJhbWV0ZXI6XHQ/c2VhcmNoX2dldF9fY3VzdG9tX3BhcmFtcz0uLi5cclxuXHQgKlxyXG5cdCAqIEBwYXJhbSBkYXRhX3N0ciAgICAgID0gICAndGV4dF5zZWFyY2hfZmllbGRfX2Rpc3BsYXlfY2hlY2tfaW5eMjMuMDUuMjAyNH50ZXh0XnNlYXJjaF9maWVsZF9fZGlzcGxheV9jaGVja19vdXReMjYuMDUuMjAyNH5zZWxlY3Rib3gtb25lXnNlYXJjaF9xdWFudGl0eV4yfnNlbGVjdGJveC1vbmVebG9jYXRpb25eU3BhaW5+c2VsZWN0Ym94LW9uZV5tYXhfY2FwYWNpdHleMn5zZWxlY3Rib3gtb25lXmFtZW5pdHlecGFya2luZ35jaGVja2JveF5zZWFyY2hfZmllbGRfX2V4dGVuZF9zZWFyY2hfZGF5c141fnN1Ym1pdF5eU2VhcmNofmhpZGRlbl5zZWFyY2hfZ2V0X19jaGVja19pbl95bWReMjAyNC0wNS0yM35oaWRkZW5ec2VhcmNoX2dldF9fY2hlY2tfb3V0X3ltZF4yMDI0LTA1LTI2fmhpZGRlbl5zZWFyY2hfZ2V0X190aW1lXn5oaWRkZW5ec2VhcmNoX2dldF9fcXVhbnRpdHleMn5oaWRkZW5ec2VhcmNoX2dldF9fZXh0ZW5kXjV+aGlkZGVuXnNlYXJjaF9nZXRfX3VzZXJzX2lkXn5oaWRkZW5ec2VhcmNoX2dldF9fY3VzdG9tX3BhcmFtc15+JztcclxuXHQgKiBAcmV0dXJucyB7Kn1cclxuXHQgKi9cclxuXHRmdW5jdGlvbiB3cGJjX2F1dG9fZmlsbF9zZWFyY2hfZmllbGRzX19wYXJzZSggZGF0YV9zdHIgKXtcclxuXHJcblx0XHR2YXIgZmlsdGVyX29wdGlvbnNfYXJyID0gW107XHJcblxyXG5cdFx0dmFyIGRhdGFfYXJyID0gZGF0YV9zdHIuc3BsaXQoICd+JyApO1xyXG5cclxuXHRcdGZvciAoIHZhciBqID0gMDsgaiA8IGRhdGFfYXJyLmxlbmd0aDsgaisrICl7XHJcblxyXG5cdFx0XHR2YXIgbXlfZm9ybV9maWVsZCA9IGRhdGFfYXJyWyBqIF0uc3BsaXQoICdeJyApO1xyXG5cclxuXHRcdFx0dmFyIGZpbHRlcl90eXBlICA9ICgndW5kZWZpbmVkJyAhPT0gdHlwZW9mIChteV9mb3JtX2ZpZWxkWyAwIF0pKSA/IG15X2Zvcm1fZmllbGRbIDAgXSA6ICcnO1xyXG5cdFx0XHR2YXIgZmlsdGVyX25hbWUgID0gKCd1bmRlZmluZWQnICE9PSB0eXBlb2YgKG15X2Zvcm1fZmllbGRbIDEgXSkpID8gbXlfZm9ybV9maWVsZFsgMSBdIDogJyc7XHJcblx0XHRcdHZhciBmaWx0ZXJfdmFsdWUgPSAoJ3VuZGVmaW5lZCcgIT09IHR5cGVvZiAobXlfZm9ybV9maWVsZFsgMiBdKSkgPyBteV9mb3JtX2ZpZWxkWyAyIF0gOiAnJztcclxuXHJcblx0XHRcdGZpbHRlcl9vcHRpb25zX2Fyci5wdXNoKFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdHtcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdCd0eXBlJyAgOiBmaWx0ZXJfdHlwZSxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdCduYW1lJyAgOiBmaWx0ZXJfbmFtZSxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdCd2YWx1ZScgOiBmaWx0ZXJfdmFsdWVcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHRcdFx0XHQgICApO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIGZpbHRlcl9vcHRpb25zX2FycjtcclxuXHR9XHJcblxyXG5cclxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcbi8qICA9PSAgQXV0byBVcGRhdGUgbnVtYmVyIG9mIG1vbnRocyBpbiBjYWxlbmRhcnMgT04gc2NyZWVuIHNpemUgY2hhbmdlZCAgPT1cclxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovXHJcblxyXG4vKipcclxuICogQXV0byBVcGRhdGUgTnVtYmVyIG9mIE1vbnRocyBpbiBDYWxlbmRhciwgZS5nLjogIFx0XHRpZiAgICAoIFdJTkRPV19XSURUSCA8PSA3ODJweCApICAgPj4+IFx0TU9OVEhTX05VTUJFUiA9IDFcclxuICogICBFTFNFOiAgbnVtYmVyIG9mIG1vbnRocyBkZWZpbmVkIGluIHNob3J0Y29kZS5cclxuICogQHBhcmFtIHJlc291cmNlX2lkIGludFxyXG4gKlxyXG4gKi9cclxuZnVuY3Rpb24gd3BiY19jYWxlbmRhcl9fYXV0b191cGRhdGVfbW9udGhzX251bWJlcl9fb25fcmVzaXplKCByZXNvdXJjZV9pZCApe1xyXG5cclxuXHRpZiAoIHRydWUgPT09IF93cGJjLmdldF9vdGhlcl9wYXJhbSggJ2lzX2FsbG93X3NldmVyYWxfbW9udGhzX29uX21vYmlsZScgKSApIHtcclxuXHRcdHJldHVybiBmYWxzZTtcclxuXHR9XHJcblxyXG5cdHZhciBsb2NhbF9fbnVtYmVyX29mX21vbnRocyA9IHBhcnNlSW50KCBfd3BiYy5jYWxlbmRhcl9fZ2V0X3BhcmFtX3ZhbHVlKCByZXNvdXJjZV9pZCwgJ2NhbGVuZGFyX251bWJlcl9vZl9tb250aHMnICkgKTtcclxuXHJcblx0aWYgKCBsb2NhbF9fbnVtYmVyX29mX21vbnRocyA+IDEgKXtcclxuXHJcblx0XHRpZiAoIGpRdWVyeSggd2luZG93ICkud2lkdGgoKSA8PSA3ODIgKXtcclxuXHRcdFx0d3BiY19jYWxlbmRhcl9fdXBkYXRlX21vbnRoc19udW1iZXIoIHJlc291cmNlX2lkLCAxICk7XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHR3cGJjX2NhbGVuZGFyX191cGRhdGVfbW9udGhzX251bWJlciggcmVzb3VyY2VfaWQsIGxvY2FsX19udW1iZXJfb2ZfbW9udGhzICk7XHJcblx0XHR9XHJcblxyXG5cdH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEF1dG8gVXBkYXRlIE51bWJlciBvZiBNb250aHMgaW4gICBBTEwgICBDYWxlbmRhcnNcclxuICpcclxuICovXHJcbmZ1bmN0aW9uIHdwYmNfY2FsZW5kYXJzX19hdXRvX3VwZGF0ZV9tb250aHNfbnVtYmVyKCl7XHJcblxyXG5cdHZhciBhbGxfY2FsZW5kYXJzX2FyciA9IF93cGJjLmNhbGVuZGFyc19hbGxfX2dldCgpO1xyXG5cclxuXHQvLyBUaGlzIExPT1AgXCJmb3IgaW5cIiBpcyBHT09ELCBiZWNhdXNlIHdlIGNoZWNrICBoZXJlIGtleXMgICAgJ2NhbGVuZGFyXycgPT09IGNhbGVuZGFyX2lkLnNsaWNlKCAwLCA5IClcclxuXHRmb3IgKCB2YXIgY2FsZW5kYXJfaWQgaW4gYWxsX2NhbGVuZGFyc19hcnIgKXtcclxuXHRcdGlmICggJ2NhbGVuZGFyXycgPT09IGNhbGVuZGFyX2lkLnNsaWNlKCAwLCA5ICkgKXtcclxuXHRcdFx0dmFyIHJlc291cmNlX2lkID0gcGFyc2VJbnQoIGNhbGVuZGFyX2lkLnNsaWNlKCA5ICkgKTtcdFx0XHQvLyAgJ2NhbGVuZGFyXzMnIC0+IDNcclxuXHRcdFx0aWYgKCByZXNvdXJjZV9pZCA+IDAgKXtcclxuXHRcdFx0XHR3cGJjX2NhbGVuZGFyX19hdXRvX3VwZGF0ZV9tb250aHNfbnVtYmVyX19vbl9yZXNpemUoIHJlc291cmNlX2lkICk7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHR9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBJZiBicm93c2VyIHdpbmRvdyBjaGFuZ2VkLCAgdGhlbiAgdXBkYXRlIG51bWJlciBvZiBtb250aHMuXHJcbiAqL1xyXG5qUXVlcnkoIHdpbmRvdyApLm9uKCAncmVzaXplJywgZnVuY3Rpb24gKCl7XHJcblx0d3BiY19jYWxlbmRhcnNfX2F1dG9fdXBkYXRlX21vbnRoc19udW1iZXIoKTtcclxufSApO1xyXG5cclxuLyoqXHJcbiAqIEF1dG8gdXBkYXRlIGNhbGVuZGFyIG51bWJlciBvZiBtb250aHMgb24gaW5pdGlhbCBwYWdlIGxvYWRcclxuICovXHJcbmpRdWVyeSggZG9jdW1lbnQgKS5yZWFkeSggZnVuY3Rpb24gKCl7XHJcblx0dmFyIGNsb3NlZF90aW1lciA9IHNldFRpbWVvdXQoIGZ1bmN0aW9uICgpe1xyXG5cdFx0d3BiY19jYWxlbmRhcnNfX2F1dG9fdXBkYXRlX21vbnRoc19udW1iZXIoKTtcclxuXHR9LCAxMDAgKTtcclxufSk7XHJcblxyXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuLyogID09ICBDaGVjazogY2FsZW5kYXJfZGF0ZXNfc3RhcnQ6IFwiMjAyNi0wMS0wMVwiLCBjYWxlbmRhcl9kYXRlc19lbmQ6IFwiMjAyNi0xMi0zMVwiID09ICAvLyBGaXhJbjogMTAuMTMuMS40LlxyXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi9cclxuXHQvKipcclxuXHQgKiBHZXQgU3RhcnQgSlMgRGF0ZSBvZiBzdGFydGluZyBkYXRlcyBpbiBjYWxlbmRhciwgZnJvbSB0aGUgX3dwYmMgb2JqZWN0LlxyXG5cdCAqXHJcblx0ICogQHBhcmFtIGludGVnZXIgcmVzb3VyY2VfaWQgLSByZXNvdXJjZSBJRCwgZS5nLjogMS5cclxuXHQgKi9cclxuXHRmdW5jdGlvbiB3cGJjX2NhbGVuZGFyX19nZXRfZGF0ZXNfc3RhcnQoIHJlc291cmNlX2lkICkge1xyXG5cdFx0cmV0dXJuIHdwYmNfY2FsZW5kYXJfX2dldF9kYXRlX3BhcmFtZXRlciggcmVzb3VyY2VfaWQsICdjYWxlbmRhcl9kYXRlc19zdGFydCcgKTtcclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIEdldCBFbmQgSlMgRGF0ZSBvZiBlbmRpbmcgZGF0ZXMgaW4gY2FsZW5kYXIsIGZyb20gdGhlIF93cGJjIG9iamVjdC5cclxuXHQgKlxyXG5cdCAqIEBwYXJhbSBpbnRlZ2VyIHJlc291cmNlX2lkIC0gcmVzb3VyY2UgSUQsIGUuZy46IDEuXHJcblx0ICovXHJcblx0ZnVuY3Rpb24gd3BiY19jYWxlbmRhcl9fZ2V0X2RhdGVzX2VuZChyZXNvdXJjZV9pZCkge1xyXG5cdFx0cmV0dXJuIHdwYmNfY2FsZW5kYXJfX2dldF9kYXRlX3BhcmFtZXRlciggcmVzb3VyY2VfaWQsICdjYWxlbmRhcl9kYXRlc19lbmQnICk7XHJcblx0fVxyXG5cclxuLyoqXHJcbiAqIEdldCB2YWxpZGF0ZXMgZGF0ZSBwYXJhbWV0ZXIuXHJcbiAqXHJcbiAqIEBwYXJhbSByZXNvdXJjZV9pZCAgIC0gMVxyXG4gKiBAcGFyYW0gcGFyYW1ldGVyX3N0ciAtICdjYWxlbmRhcl9kYXRlc19zdGFydCcgfCAnY2FsZW5kYXJfZGF0ZXNfZW5kJyB8IC4uLlxyXG4gKi9cclxuZnVuY3Rpb24gd3BiY19jYWxlbmRhcl9fZ2V0X2RhdGVfcGFyYW1ldGVyKHJlc291cmNlX2lkLCBwYXJhbWV0ZXJfc3RyKSB7XHJcblxyXG5cdHZhciBkYXRlX2V4cGVjdGVkX3ltZCA9IF93cGJjLmNhbGVuZGFyX19nZXRfcGFyYW1fdmFsdWUoIHJlc291cmNlX2lkLCBwYXJhbWV0ZXJfc3RyICk7XHJcblxyXG5cdGlmICggISBkYXRlX2V4cGVjdGVkX3ltZCApIHtcclxuXHRcdHJldHVybiBmYWxzZTsgICAgICAgICAgICAgLy8gJycgfCAwIHwgbnVsbCB8IHVuZGVmaW5lZCAgLT4gZmFsc2UuXHJcblx0fVxyXG5cclxuXHRpZiAoIC0xICE9PSBkYXRlX2V4cGVjdGVkX3ltZC5pbmRleE9mKCAnLScgKSApIHtcclxuXHJcblx0XHR2YXIgZGF0ZV9leHBlY3RlZF95bWRfYXJyID0gZGF0ZV9leHBlY3RlZF95bWQuc3BsaXQoICctJyApO1x0Ly8gJzIwMjUtMDctMjYnIC0+IFsnMjAyNScsICcwNycsICcyNiddXHJcblxyXG5cdFx0aWYgKCBkYXRlX2V4cGVjdGVkX3ltZF9hcnIubGVuZ3RoID4gMCApIHtcclxuXHRcdFx0dmFyIHllYXIgID0gKGRhdGVfZXhwZWN0ZWRfeW1kX2Fyci5sZW5ndGggPiAwKSA/IHBhcnNlSW50KCBkYXRlX2V4cGVjdGVkX3ltZF9hcnJbMF0gKSA6IG5ldyBEYXRlKCkuZ2V0RnVsbFllYXIoKTtcdC8vIFllYXIuXHJcblx0XHRcdHZhciBtb250aCA9IChkYXRlX2V4cGVjdGVkX3ltZF9hcnIubGVuZ3RoID4gMSkgPyAocGFyc2VJbnQoIGRhdGVfZXhwZWN0ZWRfeW1kX2FyclsxXSApIC0gMSkgOiAwOyAgLy8gKG1vbnRoIC0gMSkgb3IgMCAtIEphbi5cclxuXHRcdFx0dmFyIGRheSAgID0gKGRhdGVfZXhwZWN0ZWRfeW1kX2Fyci5sZW5ndGggPiAyKSA/IHBhcnNlSW50KCBkYXRlX2V4cGVjdGVkX3ltZF9hcnJbMl0gKSA6IDE7ICAvLyBkYXRlIG9yIE90aGVyd2lzZSAxc3Qgb2YgbW9udGhcclxuXHJcblx0XHRcdHZhciBkYXRlX2pzID0gbmV3IERhdGUoIHllYXIsIG1vbnRoLCBkYXksIDAsIDAsIDAsIDAgKTtcclxuXHJcblx0XHRcdHJldHVybiBkYXRlX2pzO1xyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0cmV0dXJuIGZhbHNlOyAgLy8gRmFsbGJhY2ssICBpZiB3ZSBub3QgcGFyc2VkIHRoaXMgcGFyYW1ldGVyICAnY2FsZW5kYXJfZGF0ZXNfc3RhcnQnID0gJzIwMjUtMDctMjYnLCAgZm9yIGV4YW1wbGUgYmVjYXVzZSBvZiAnY2FsZW5kYXJfZGF0ZXNfc3RhcnQnID0gJ3Nmc2RmJy5cclxufVxyXG4iLCIvKipcclxuICogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuICpcdGluY2x1ZGVzL19fanMvY2FsL2RheXNfc2VsZWN0X2N1c3RvbS5qc1xyXG4gKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG4gKi9cclxuXHJcbi8vIEZpeEluOiA5LjguOS4yLlxyXG5cclxuLyoqXHJcbiAqIFJlLUluaXQgQ2FsZW5kYXIgYW5kIFJlLVJlbmRlciBpdC5cclxuICpcclxuICogQHBhcmFtIHJlc291cmNlX2lkXHJcbiAqL1xyXG5mdW5jdGlvbiB3cGJjX2NhbF9fcmVfaW5pdCggcmVzb3VyY2VfaWQgKXtcclxuXHJcblx0Ly8gUmVtb3ZlIENMQVNTICBmb3IgYWJpbGl0eSB0byByZS1yZW5kZXIgYW5kIHJlaW5pdCBjYWxlbmRhci5cclxuXHRqUXVlcnkoICcjY2FsZW5kYXJfYm9va2luZycgKyByZXNvdXJjZV9pZCApLnJlbW92ZUNsYXNzKCAnaGFzRGF0ZXBpY2snICk7XHJcblx0d3BiY19jYWxlbmRhcl9zaG93KCByZXNvdXJjZV9pZCApO1xyXG59XHJcblxyXG5cclxuLyoqXHJcbiAqIFJlLUluaXQgcHJldmlvdXNseSAgc2F2ZWQgZGF5cyBzZWxlY3Rpb24gIHZhcmlhYmxlcy5cclxuICpcclxuICogQHBhcmFtIHJlc291cmNlX2lkXHJcbiAqL1xyXG5mdW5jdGlvbiB3cGJjX2NhbF9kYXlzX3NlbGVjdF9fcmVfaW5pdCggcmVzb3VyY2VfaWQgKXtcclxuXHJcblx0X3dwYmMuY2FsZW5kYXJfX3NldF9wYXJhbV92YWx1ZSggcmVzb3VyY2VfaWQsICdzYXZlZF92YXJpYWJsZV9fX2RheXNfc2VsZWN0X2luaXRpYWwnXHJcblx0XHQsIHtcclxuXHRcdFx0J2R5bmFtaWNfX2RheXNfbWluJyAgICAgICAgOiBfd3BiYy5jYWxlbmRhcl9fZ2V0X3BhcmFtX3ZhbHVlKCByZXNvdXJjZV9pZCwgJ2R5bmFtaWNfX2RheXNfbWluJyApLFxyXG5cdFx0XHQnZHluYW1pY19fZGF5c19tYXgnICAgICAgICA6IF93cGJjLmNhbGVuZGFyX19nZXRfcGFyYW1fdmFsdWUoIHJlc291cmNlX2lkLCAnZHluYW1pY19fZGF5c19tYXgnICksXHJcblx0XHRcdCdkeW5hbWljX19kYXlzX3NwZWNpZmljJyAgIDogX3dwYmMuY2FsZW5kYXJfX2dldF9wYXJhbV92YWx1ZSggcmVzb3VyY2VfaWQsICdkeW5hbWljX19kYXlzX3NwZWNpZmljJyApLFxyXG5cdFx0XHQnZHluYW1pY19fd2Vla19kYXlzX19zdGFydCc6IF93cGJjLmNhbGVuZGFyX19nZXRfcGFyYW1fdmFsdWUoIHJlc291cmNlX2lkLCAnZHluYW1pY19fd2Vla19kYXlzX19zdGFydCcgKSxcclxuXHRcdFx0J2ZpeGVkX19kYXlzX251bScgICAgICAgICAgOiBfd3BiYy5jYWxlbmRhcl9fZ2V0X3BhcmFtX3ZhbHVlKCByZXNvdXJjZV9pZCwgJ2ZpeGVkX19kYXlzX251bScgKSxcclxuXHRcdFx0J2ZpeGVkX193ZWVrX2RheXNfX3N0YXJ0JyAgOiBfd3BiYy5jYWxlbmRhcl9fZ2V0X3BhcmFtX3ZhbHVlKCByZXNvdXJjZV9pZCwgJ2ZpeGVkX193ZWVrX2RheXNfX3N0YXJ0JyApXHJcblx0XHR9XHJcblx0KTtcclxufVxyXG5cclxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblxyXG4vKipcclxuICogU2V0IFNpbmdsZSBEYXkgc2VsZWN0aW9uIC0gYWZ0ZXIgcGFnZSBsb2FkXHJcbiAqXHJcbiAqIEBwYXJhbSByZXNvdXJjZV9pZFx0XHRJRCBvZiBib29raW5nIHJlc291cmNlXHJcbiAqL1xyXG5mdW5jdGlvbiB3cGJjX2NhbF9yZWFkeV9kYXlzX3NlbGVjdF9fc2luZ2xlKCByZXNvdXJjZV9pZCApe1xyXG5cclxuXHQvLyBSZS1kZWZpbmUgc2VsZWN0aW9uLCBvbmx5IGFmdGVyIHBhZ2UgbG9hZGVkIHdpdGggYWxsIGluaXQgdmFyc1xyXG5cdGpRdWVyeShkb2N1bWVudCkucmVhZHkoZnVuY3Rpb24oKXtcclxuXHJcblx0XHQvLyBXYWl0IDEgc2Vjb25kLCBqdXN0IHRvICBiZSBzdXJlLCB0aGF0IGFsbCBpbml0IHZhcnMgZGVmaW5lZFxyXG5cdFx0c2V0VGltZW91dChmdW5jdGlvbigpe1xyXG5cclxuXHRcdFx0d3BiY19jYWxfZGF5c19zZWxlY3RfX3NpbmdsZSggcmVzb3VyY2VfaWQgKTtcclxuXHJcblx0XHR9LCAxMDAwKTtcclxuXHR9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldCBTaW5nbGUgRGF5IHNlbGVjdGlvblxyXG4gKiBDYW4gYmUgcnVuIGF0IGFueSAgdGltZSwgIHdoZW4gIGNhbGVuZGFyIGRlZmluZWQgLSB1c2VmdWwgZm9yIGNvbnNvbGUgcnVuLlxyXG4gKlxyXG4gKiBAcGFyYW0gcmVzb3VyY2VfaWRcdFx0SUQgb2YgYm9va2luZyByZXNvdXJjZVxyXG4gKi9cclxuZnVuY3Rpb24gd3BiY19jYWxfZGF5c19zZWxlY3RfX3NpbmdsZSggcmVzb3VyY2VfaWQgKXtcclxuXHJcblx0X3dwYmMuY2FsZW5kYXJfX3NldF9wYXJhbWV0ZXJzKCByZXNvdXJjZV9pZCwgeydkYXlzX3NlbGVjdF9tb2RlJzogJ3NpbmdsZSd9ICk7XHJcblxyXG5cdHdwYmNfY2FsX2RheXNfc2VsZWN0X19yZV9pbml0KCByZXNvdXJjZV9pZCApO1xyXG5cdHdwYmNfY2FsX19yZV9pbml0KCByZXNvdXJjZV9pZCApO1xyXG59XHJcblxyXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHJcbi8qKlxyXG4gKiBTZXQgTXVsdGlwbGUgRGF5cyBzZWxlY3Rpb24gIC0gYWZ0ZXIgcGFnZSBsb2FkXHJcbiAqXHJcbiAqIEBwYXJhbSByZXNvdXJjZV9pZFx0XHRJRCBvZiBib29raW5nIHJlc291cmNlXHJcbiAqL1xyXG5mdW5jdGlvbiB3cGJjX2NhbF9yZWFkeV9kYXlzX3NlbGVjdF9fbXVsdGlwbGUoIHJlc291cmNlX2lkICl7XHJcblxyXG5cdC8vIFJlLWRlZmluZSBzZWxlY3Rpb24sIG9ubHkgYWZ0ZXIgcGFnZSBsb2FkZWQgd2l0aCBhbGwgaW5pdCB2YXJzXHJcblx0alF1ZXJ5KGRvY3VtZW50KS5yZWFkeShmdW5jdGlvbigpe1xyXG5cclxuXHRcdC8vIFdhaXQgMSBzZWNvbmQsIGp1c3QgdG8gIGJlIHN1cmUsIHRoYXQgYWxsIGluaXQgdmFycyBkZWZpbmVkXHJcblx0XHRzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7XHJcblxyXG5cdFx0XHR3cGJjX2NhbF9kYXlzX3NlbGVjdF9fbXVsdGlwbGUoIHJlc291cmNlX2lkICk7XHJcblxyXG5cdFx0fSwgMTAwMCk7XHJcblx0fSk7XHJcbn1cclxuXHJcblxyXG4vKipcclxuICogU2V0IE11bHRpcGxlIERheXMgc2VsZWN0aW9uXHJcbiAqIENhbiBiZSBydW4gYXQgYW55ICB0aW1lLCAgd2hlbiAgY2FsZW5kYXIgZGVmaW5lZCAtIHVzZWZ1bCBmb3IgY29uc29sZSBydW4uXHJcbiAqXHJcbiAqIEBwYXJhbSByZXNvdXJjZV9pZFx0XHRJRCBvZiBib29raW5nIHJlc291cmNlXHJcbiAqL1xyXG5mdW5jdGlvbiB3cGJjX2NhbF9kYXlzX3NlbGVjdF9fbXVsdGlwbGUoIHJlc291cmNlX2lkICl7XHJcblxyXG5cdF93cGJjLmNhbGVuZGFyX19zZXRfcGFyYW1ldGVycyggcmVzb3VyY2VfaWQsIHsnZGF5c19zZWxlY3RfbW9kZSc6ICdtdWx0aXBsZSd9ICk7XHJcblxyXG5cdHdwYmNfY2FsX2RheXNfc2VsZWN0X19yZV9pbml0KCByZXNvdXJjZV9pZCApO1xyXG5cdHdwYmNfY2FsX19yZV9pbml0KCByZXNvdXJjZV9pZCApO1xyXG59XHJcblxyXG5cclxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblxyXG4vKipcclxuICogU2V0IEZpeGVkIERheXMgc2VsZWN0aW9uIHdpdGggIDEgbW91c2UgY2xpY2sgIC0gYWZ0ZXIgcGFnZSBsb2FkXHJcbiAqXHJcbiAqIEBpbnRlZ2VyIHJlc291cmNlX2lkXHRcdFx0LSAxXHRcdFx0XHQgICAtLSBJRCBvZiBib29raW5nIHJlc291cmNlIChjYWxlbmRhcikgLVxyXG4gKiBAaW50ZWdlciBkYXlzX251bWJlclx0XHRcdC0gM1x0XHRcdFx0ICAgLS0gbnVtYmVyIG9mIGRheXMgdG8gIHNlbGVjdFx0LVxyXG4gKiBAYXJyYXkgd2Vla19kYXlzX19zdGFydFx0LSBbLTFdIHwgWyAxLCA1XSAgIC0tICB7IC0xIC0gQW55IHwgMCAtIFN1LCAgMSAtIE1vLCAgMiAtIFR1LCAzIC0gV2UsIDQgLSBUaCwgNSAtIEZyLCA2IC0gU2F0IH1cclxuICovXHJcbmZ1bmN0aW9uIHdwYmNfY2FsX3JlYWR5X2RheXNfc2VsZWN0X19maXhlZCggcmVzb3VyY2VfaWQsIGRheXNfbnVtYmVyLCB3ZWVrX2RheXNfX3N0YXJ0ID0gWy0xXSApe1xyXG5cclxuXHQvLyBSZS1kZWZpbmUgc2VsZWN0aW9uLCBvbmx5IGFmdGVyIHBhZ2UgbG9hZGVkIHdpdGggYWxsIGluaXQgdmFyc1xyXG5cdGpRdWVyeShkb2N1bWVudCkucmVhZHkoZnVuY3Rpb24oKXtcclxuXHJcblx0XHQvLyBXYWl0IDEgc2Vjb25kLCBqdXN0IHRvICBiZSBzdXJlLCB0aGF0IGFsbCBpbml0IHZhcnMgZGVmaW5lZFxyXG5cdFx0c2V0VGltZW91dChmdW5jdGlvbigpe1xyXG5cclxuXHRcdFx0d3BiY19jYWxfZGF5c19zZWxlY3RfX2ZpeGVkKCByZXNvdXJjZV9pZCwgZGF5c19udW1iZXIsIHdlZWtfZGF5c19fc3RhcnQgKTtcclxuXHJcblx0XHR9LCAxMDAwKTtcclxuXHR9KTtcclxufVxyXG5cclxuXHJcbi8qKlxyXG4gKiBTZXQgRml4ZWQgRGF5cyBzZWxlY3Rpb24gd2l0aCAgMSBtb3VzZSBjbGlja1xyXG4gKiBDYW4gYmUgcnVuIGF0IGFueSAgdGltZSwgIHdoZW4gIGNhbGVuZGFyIGRlZmluZWQgLSB1c2VmdWwgZm9yIGNvbnNvbGUgcnVuLlxyXG4gKlxyXG4gKiBAaW50ZWdlciByZXNvdXJjZV9pZFx0XHRcdC0gMVx0XHRcdFx0ICAgLS0gSUQgb2YgYm9va2luZyByZXNvdXJjZSAoY2FsZW5kYXIpIC1cclxuICogQGludGVnZXIgZGF5c19udW1iZXJcdFx0XHQtIDNcdFx0XHRcdCAgIC0tIG51bWJlciBvZiBkYXlzIHRvICBzZWxlY3RcdC1cclxuICogQGFycmF5IHdlZWtfZGF5c19fc3RhcnRcdC0gWy0xXSB8IFsgMSwgNV0gICAtLSAgeyAtMSAtIEFueSB8IDAgLSBTdSwgIDEgLSBNbywgIDIgLSBUdSwgMyAtIFdlLCA0IC0gVGgsIDUgLSBGciwgNiAtIFNhdCB9XHJcbiAqL1xyXG5mdW5jdGlvbiB3cGJjX2NhbF9kYXlzX3NlbGVjdF9fZml4ZWQoIHJlc291cmNlX2lkLCBkYXlzX251bWJlciwgd2Vla19kYXlzX19zdGFydCA9IFstMV0gKXtcclxuXHJcblx0X3dwYmMuY2FsZW5kYXJfX3NldF9wYXJhbWV0ZXJzKCByZXNvdXJjZV9pZCwgeydkYXlzX3NlbGVjdF9tb2RlJzogJ2ZpeGVkJ30gKTtcclxuXHJcblx0X3dwYmMuY2FsZW5kYXJfX3NldF9wYXJhbWV0ZXJzKCByZXNvdXJjZV9pZCwgeydmaXhlZF9fZGF5c19udW0nOiBwYXJzZUludCggZGF5c19udW1iZXIgKX0gKTtcdFx0XHQvLyBOdW1iZXIgb2YgZGF5cyBzZWxlY3Rpb24gd2l0aCAxIG1vdXNlIGNsaWNrXHJcblx0X3dwYmMuY2FsZW5kYXJfX3NldF9wYXJhbWV0ZXJzKCByZXNvdXJjZV9pZCwgeydmaXhlZF9fd2Vla19kYXlzX19zdGFydCc6IHdlZWtfZGF5c19fc3RhcnR9ICk7IFx0Ly8geyAtMSAtIEFueSB8IDAgLSBTdSwgIDEgLSBNbywgIDIgLSBUdSwgMyAtIFdlLCA0IC0gVGgsIDUgLSBGciwgNiAtIFNhdCB9XHJcblxyXG5cdHdwYmNfY2FsX2RheXNfc2VsZWN0X19yZV9pbml0KCByZXNvdXJjZV9pZCApO1xyXG5cdHdwYmNfY2FsX19yZV9pbml0KCByZXNvdXJjZV9pZCApO1xyXG59XHJcblxyXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuLyoqXG4gKiBTZXQgdGhlIGV4aXN0aW5nIGNhbGVuZGFyIHBhcmFtZXRlcnMgdG8gdHdvLWNsaWNrIHJhbmdlIG1vZGUgYWZ0ZXIgcGFnZSBsb2FkLlxuICogRnJlZSB1c2VzIHRoZSB1bnJlc3RyaWN0ZWQgc2hhcmVkIGhhbmRsZXI7IEJ1c2luZXNzIFNtYWxsKyBrZWVwcyBpdHMgYWxyZWFkeSBpbml0aWFsaXplZCBhZHZhbmNlZCByYW5nZSBydWxlcy5cbiAqXG4gKiBAcGFyYW0gcmVzb3VyY2VfaWQgSUQgb2YgYm9va2luZyByZXNvdXJjZS5cbiAqL1xuZnVuY3Rpb24gd3BiY19jYWxfcmVhZHlfZGF5c19zZWxlY3RfX3JhbmdlX21vZGUoIHJlc291cmNlX2lkICl7XG5cblx0alF1ZXJ5KGRvY3VtZW50KS5yZWFkeShmdW5jdGlvbigpe1xuXHRcdHNldFRpbWVvdXQoZnVuY3Rpb24oKXtcblx0XHRcdHdwYmNfY2FsX2RheXNfc2VsZWN0X19yYW5nZV9tb2RlKCByZXNvdXJjZV9pZCApO1xuXHRcdH0sIDEwMDApO1xuXHR9KTtcbn1cblxuLyoqXG4gKiBTd2l0Y2ggdG8gdHdvLWNsaWNrIHJhbmdlIG1vZGUgd2l0aG91dCBjaGFuZ2luZyBhbnkgYWR2YW5jZWQgcmFuZ2UgcGFyYW1ldGVycy5cbiAqXG4gKiBAcGFyYW0gcmVzb3VyY2VfaWQgSUQgb2YgYm9va2luZyByZXNvdXJjZS5cbiAqL1xuZnVuY3Rpb24gd3BiY19jYWxfZGF5c19zZWxlY3RfX3JhbmdlX21vZGUoIHJlc291cmNlX2lkICl7XG5cblx0X3dwYmMuY2FsZW5kYXJfX3NldF9wYXJhbWV0ZXJzKCByZXNvdXJjZV9pZCwgeydkYXlzX3NlbGVjdF9tb2RlJzogJ2R5bmFtaWMnfSApO1xuXG5cdHdwYmNfY2FsX2RheXNfc2VsZWN0X19yZV9pbml0KCByZXNvdXJjZV9pZCApO1xuXHR3cGJjX2NhbF9fcmVfaW5pdCggcmVzb3VyY2VfaWQgKTtcbn1cblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbi8qKlxuICogU2V0IFJhbmdlIERheXMgc2VsZWN0aW9uICB3aXRoICAyIG1vdXNlIGNsaWNrcyAgLSBhZnRlciBwYWdlIGxvYWRcbiAqXHJcbiAqIEBpbnRlZ2VyIHJlc291cmNlX2lkXHRcdFx0LSAxXHRcdFx0XHQgICBcdFx0LS0gSUQgb2YgYm9va2luZyByZXNvdXJjZSAoY2FsZW5kYXIpXHJcbiAqIEBpbnRlZ2VyIGRheXNfbWluXHRcdFx0LSA3XHRcdFx0XHQgICBcdFx0LS0gTWluIG51bWJlciBvZiBkYXlzIHRvIHNlbGVjdFxyXG4gKiBAaW50ZWdlciBkYXlzX21heFx0XHRcdC0gMzBcdFx0XHQgICBcdFx0LS0gTWF4IG51bWJlciBvZiBkYXlzIHRvIHNlbGVjdFxyXG4gKiBAYXJyYXkgZGF5c19zcGVjaWZpY1x0XHRcdC0gW10gfCBbNywxNCwyMSwyOF1cdFx0LS0gUmVzdHJpY3Rpb24gZm9yIFNwZWNpZmljIG51bWJlciBvZiBkYXlzIHNlbGVjdGlvblxyXG4gKiBAYXJyYXkgd2Vla19kYXlzX19zdGFydFx0XHQtIFstMV0gfCBbIDEsIDVdICAgXHRcdC0tICB7IC0xIC0gQW55IHwgMCAtIFN1LCAgMSAtIE1vLCAgMiAtIFR1LCAzIC0gV2UsIDQgLSBUaCwgNSAtIEZyLCA2IC0gU2F0IH1cclxuICovXHJcbmZ1bmN0aW9uIHdwYmNfY2FsX3JlYWR5X2RheXNfc2VsZWN0X19yYW5nZSggcmVzb3VyY2VfaWQsIGRheXNfbWluLCBkYXlzX21heCwgZGF5c19zcGVjaWZpYyA9IFtdLCB3ZWVrX2RheXNfX3N0YXJ0ID0gWy0xXSApe1xyXG5cclxuXHQvLyBSZS1kZWZpbmUgc2VsZWN0aW9uLCBvbmx5IGFmdGVyIHBhZ2UgbG9hZGVkIHdpdGggYWxsIGluaXQgdmFyc1xyXG5cdGpRdWVyeShkb2N1bWVudCkucmVhZHkoZnVuY3Rpb24oKXtcclxuXHJcblx0XHQvLyBXYWl0IDEgc2Vjb25kLCBqdXN0IHRvICBiZSBzdXJlLCB0aGF0IGFsbCBpbml0IHZhcnMgZGVmaW5lZFxyXG5cdFx0c2V0VGltZW91dChmdW5jdGlvbigpe1xyXG5cclxuXHRcdFx0d3BiY19jYWxfZGF5c19zZWxlY3RfX3JhbmdlKCByZXNvdXJjZV9pZCwgZGF5c19taW4sIGRheXNfbWF4LCBkYXlzX3NwZWNpZmljLCB3ZWVrX2RheXNfX3N0YXJ0ICk7XHJcblx0XHR9LCAxMDAwKTtcclxuXHR9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldCBSYW5nZSBEYXlzIHNlbGVjdGlvbiAgd2l0aCAgMiBtb3VzZSBjbGlja3NcclxuICogQ2FuIGJlIHJ1biBhdCBhbnkgIHRpbWUsICB3aGVuICBjYWxlbmRhciBkZWZpbmVkIC0gdXNlZnVsIGZvciBjb25zb2xlIHJ1bi5cclxuICpcclxuICogQGludGVnZXIgcmVzb3VyY2VfaWRcdFx0XHQtIDFcdFx0XHRcdCAgIFx0XHQtLSBJRCBvZiBib29raW5nIHJlc291cmNlIChjYWxlbmRhcilcclxuICogQGludGVnZXIgZGF5c19taW5cdFx0XHQtIDdcdFx0XHRcdCAgIFx0XHQtLSBNaW4gbnVtYmVyIG9mIGRheXMgdG8gc2VsZWN0XHJcbiAqIEBpbnRlZ2VyIGRheXNfbWF4XHRcdFx0LSAzMFx0XHRcdCAgIFx0XHQtLSBNYXggbnVtYmVyIG9mIGRheXMgdG8gc2VsZWN0XHJcbiAqIEBhcnJheSBkYXlzX3NwZWNpZmljXHRcdFx0LSBbXSB8IFs3LDE0LDIxLDI4XVx0XHQtLSBSZXN0cmljdGlvbiBmb3IgU3BlY2lmaWMgbnVtYmVyIG9mIGRheXMgc2VsZWN0aW9uXHJcbiAqIEBhcnJheSB3ZWVrX2RheXNfX3N0YXJ0XHRcdC0gWy0xXSB8IFsgMSwgNV0gICBcdFx0LS0gIHsgLTEgLSBBbnkgfCAwIC0gU3UsICAxIC0gTW8sICAyIC0gVHUsIDMgLSBXZSwgNCAtIFRoLCA1IC0gRnIsIDYgLSBTYXQgfVxyXG4gKi9cclxuZnVuY3Rpb24gd3BiY19jYWxfZGF5c19zZWxlY3RfX3JhbmdlKCByZXNvdXJjZV9pZCwgZGF5c19taW4sIGRheXNfbWF4LCBkYXlzX3NwZWNpZmljID0gW10sIHdlZWtfZGF5c19fc3RhcnQgPSBbLTFdICl7XHJcblxyXG5cdF93cGJjLmNhbGVuZGFyX19zZXRfcGFyYW1ldGVycyggIHJlc291cmNlX2lkLCB7J2RheXNfc2VsZWN0X21vZGUnOiAnZHluYW1pYyd9ICApO1xyXG5cdF93cGJjLmNhbGVuZGFyX19zZXRfcGFyYW1fdmFsdWUoIHJlc291cmNlX2lkLCAnZHluYW1pY19fZGF5c19taW4nICAgICAgICAgLCBwYXJzZUludCggZGF5c19taW4gKSAgKTsgICAgICAgICAgIFx0XHQvLyBNaW4uIE51bWJlciBvZiBkYXlzIHNlbGVjdGlvbiB3aXRoIDIgbW91c2UgY2xpY2tzXHJcblx0X3dwYmMuY2FsZW5kYXJfX3NldF9wYXJhbV92YWx1ZSggcmVzb3VyY2VfaWQsICdkeW5hbWljX19kYXlzX21heCcgICAgICAgICAsIHBhcnNlSW50KCBkYXlzX21heCApICApOyAgICAgICAgICBcdFx0Ly8gTWF4LiBOdW1iZXIgb2YgZGF5cyBzZWxlY3Rpb24gd2l0aCAyIG1vdXNlIGNsaWNrc1xyXG5cdF93cGJjLmNhbGVuZGFyX19zZXRfcGFyYW1fdmFsdWUoIHJlc291cmNlX2lkLCAnZHluYW1pY19fZGF5c19zcGVjaWZpYycgICAgLCBkYXlzX3NwZWNpZmljICApO1x0ICAgICAgXHRcdFx0XHQvLyBFeGFtcGxlIFs1LDddXHJcblx0X3dwYmMuY2FsZW5kYXJfX3NldF9wYXJhbV92YWx1ZSggcmVzb3VyY2VfaWQsICdkeW5hbWljX193ZWVrX2RheXNfX3N0YXJ0JyAsIHdlZWtfZGF5c19fc3RhcnQgICk7ICBcdFx0XHRcdFx0Ly8geyAtMSAtIEFueSB8IDAgLSBTdSwgIDEgLSBNbywgIDIgLSBUdSwgMyAtIFdlLCA0IC0gVGgsIDUgLSBGciwgNiAtIFNhdCB9XHJcblxyXG5cdHdwYmNfY2FsX2RheXNfc2VsZWN0X19yZV9pbml0KCByZXNvdXJjZV9pZCApO1xyXG5cdHdwYmNfY2FsX19yZV9pbml0KCByZXNvdXJjZV9pZCApO1xyXG59XHJcbiIsIi8qKlxyXG4gKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG4gKlx0aW5jbHVkZXMvX19qcy9jYWxfYWp4X2xvYWQvd3BiY19jYWxfYWp4LmpzXHJcbiAqID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcbiAqL1xyXG5cclxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcbi8vICBBIGogYSB4ICAgIEwgbyBhIGQgICAgQyBhIGwgZSBuIGQgYSByICAgIEQgYSB0IGFcclxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblxyXG5mdW5jdGlvbiB3cGJjX2NhbGVuZGFyX19sb2FkX2RhdGFfX2FqeCggcGFyYW1zICl7XHJcblxyXG5cdC8vIEZpeEluOiA5LjguNi4yLlxyXG5cdHdwYmNfY2FsZW5kYXJfX2xvYWRpbmdfX3N0YXJ0KCBwYXJhbXNbJ3Jlc291cmNlX2lkJ10gKTtcclxuXHJcblx0Ly8gVHJpZ2dlciBldmVudCBmb3IgY2FsZW5kYXIgYmVmb3JlIGxvYWRpbmcgQm9va2luZyBkYXRhLCAgYnV0IGFmdGVyIHNob3dpbmcgQ2FsZW5kYXIuXHJcblx0aWYgKCBqUXVlcnkoICcjY2FsZW5kYXJfYm9va2luZycgKyBwYXJhbXNbJ3Jlc291cmNlX2lkJ10gKS5sZW5ndGggPiAwICl7XHJcblx0XHR2YXIgdGFyZ2V0X2VsbSA9IGpRdWVyeSggJ2JvZHknICkudHJpZ2dlciggXCJ3cGJjX2NhbGVuZGFyX2FqeF9fYmVmb3JlX2xvYWRlZF9kYXRhXCIsIFtwYXJhbXNbJ3Jlc291cmNlX2lkJ11dICk7XHJcblx0XHQgLy9qUXVlcnkoICdib2R5JyApLm9uKCAnd3BiY19jYWxlbmRhcl9hanhfX2JlZm9yZV9sb2FkZWRfZGF0YScsIGZ1bmN0aW9uKCBldmVudCwgcmVzb3VyY2VfaWQgKSB7IC4uLiB9ICk7XHJcblx0fVxyXG5cclxuXHRpZiAoIHdwYmNfYmFsYW5jZXJfX2lzX3dhaXQoIHBhcmFtcyAsICd3cGJjX2NhbGVuZGFyX19sb2FkX2RhdGFfX2FqeCcgKSApe1xyXG5cdFx0cmV0dXJuIGZhbHNlO1xyXG5cdH1cclxuXHJcblx0Ly8gRml4SW46IDkuOC42LjIuXHJcblx0d3BiY19jYWxlbmRhcl9fYmx1cl9fc3RvcCggcGFyYW1zWydyZXNvdXJjZV9pZCddICk7XHJcblxyXG5cdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0Ly8gPT0gR2V0IHN0YXJ0IC8gZW5kIGRhdGVzIGZyb20gIHRoZSBCb29raW5nIENhbGVuZGFyIHNob3J0Y29kZS4gPT1cclxuXHQvLyBFeGFtcGxlOiBbYm9va2luZyBjYWxlbmRhcl9kYXRlc19zdGFydD0nMjAyNi0wMS0wMScgY2FsZW5kYXJfZGF0ZXNfZW5kPScyMDI2LTEyLTMxJyAgcmVzb3VyY2VfaWQ9MV0gICAgICAgICAgICAgIC8vIEZpeEluOiAxMC4xMy4xLjQuXHJcblx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRpZiAoIGZhbHNlICE9PSB3cGJjX2NhbGVuZGFyX19nZXRfZGF0ZXNfc3RhcnQoIHBhcmFtc1sncmVzb3VyY2VfaWQnXSApICkge1xyXG5cdFx0aWYgKCAhIHBhcmFtc1snZGF0ZXNfdG9fY2hlY2snXSApIHsgcGFyYW1zWydkYXRlc190b19jaGVjayddID0gW107IH1cclxuXHRcdHZhciBkYXRlc19zdGFydCA9IHdwYmNfY2FsZW5kYXJfX2dldF9kYXRlc19zdGFydCggcGFyYW1zWydyZXNvdXJjZV9pZCddICk7ICAvLyBFLmcuIC0gbG9jYWxfX21pbl9kYXRlID0gbmV3IERhdGUoIDIwMjUsIDAsIDEgKTtcclxuXHRcdGlmICggZmFsc2UgIT09IGRhdGVzX3N0YXJ0ICl7XHJcblx0XHRcdHBhcmFtc1snZGF0ZXNfdG9fY2hlY2snXVswXSA9IHdwYmNfX2dldF9fc3FsX2NsYXNzX2RhdGUoIGRhdGVzX3N0YXJ0ICk7XHJcblx0XHR9XHJcblx0fVxyXG5cdGlmICggZmFsc2UgIT09IHdwYmNfY2FsZW5kYXJfX2dldF9kYXRlc19lbmQoIHBhcmFtc1sncmVzb3VyY2VfaWQnXSApICkge1xyXG5cdFx0aWYgKCAhcGFyYW1zWydkYXRlc190b19jaGVjayddICkgeyBwYXJhbXNbJ2RhdGVzX3RvX2NoZWNrJ10gPSBbXTsgfVxyXG5cdFx0dmFyIGRhdGVzX2VuZCA9IHdwYmNfY2FsZW5kYXJfX2dldF9kYXRlc19lbmQoIHBhcmFtc1sncmVzb3VyY2VfaWQnXSApOyAgLy8gRS5nLiAtIGxvY2FsX19taW5fZGF0ZSA9IG5ldyBEYXRlKCAyMDI1LCAwLCAxICk7XHJcblx0XHRpZiAoIGZhbHNlICE9PSBkYXRlc19lbmQgKSB7XHJcblx0XHRcdHBhcmFtc1snZGF0ZXNfdG9fY2hlY2snXVsxXSA9IHdwYmNfX2dldF9fc3FsX2NsYXNzX2RhdGUoIGRhdGVzX2VuZCApO1xyXG5cdFx0XHRpZiAoICFwYXJhbXNbJ2RhdGVzX3RvX2NoZWNrJ11bMF0gKSB7XHJcblx0XHRcdFx0cGFyYW1zWydkYXRlc190b19jaGVjayddWzBdID0gd3BiY19fZ2V0X19zcWxfY2xhc3NfZGF0ZSggbmV3IERhdGUoKSApO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblx0fVxyXG5cdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblxyXG4vLyBjb25zb2xlLmdyb3VwRW5kKCk7IGNvbnNvbGUudGltZSgncmVzb3VyY2VfaWRfJyArIHBhcmFtc1sncmVzb3VyY2VfaWQnXSk7XHJcbmNvbnNvbGUuZ3JvdXBDb2xsYXBzZWQoICdXUEJDX0FKWF9DQUxFTkRBUl9MT0FEJyApOyBjb25zb2xlLmxvZyggJyA9PSBCZWZvcmUgQWpheCBTZW5kIC0gY2FsZW5kYXJzX2FsbF9fZ2V0KCkgPT0gJyAsIF93cGJjLmNhbGVuZGFyc19hbGxfX2dldCgpICk7XHJcblx0aWYgKCAnZnVuY3Rpb24nID09PSB0eXBlb2YgKHdwYmNfaG9va19faW5pdF90aW1lc2VsZWN0b3IpICkge1xyXG5cdFx0d3BiY19ob29rX19pbml0X3RpbWVzZWxlY3RvcigpO1xyXG5cdH1cclxuXHJcblx0Ly8gU3RhcnQgQWpheFxyXG5cdGpRdWVyeS5wb3N0KCB3cGJjX3VybF9hamF4LFxyXG5cdFx0XHRcdHtcclxuXHRcdFx0XHRcdGFjdGlvbiAgICAgICAgICA6ICdXUEJDX0FKWF9DQUxFTkRBUl9MT0FEJyxcclxuXHRcdFx0XHRcdHdwYmNfYWp4X3VzZXJfaWQ6IF93cGJjLmdldF9zZWN1cmVfcGFyYW0oICd1c2VyX2lkJyApLFxyXG5cdFx0XHRcdFx0bm9uY2UgICAgICAgICAgIDogX3dwYmMuZ2V0X3NlY3VyZV9wYXJhbSggJ25vbmNlJyApLFxyXG5cdFx0XHRcdFx0d3BiY19hanhfbG9jYWxlIDogX3dwYmMuZ2V0X3NlY3VyZV9wYXJhbSggJ2xvY2FsZScgKSxcclxuXHJcblx0XHRcdFx0XHRjYWxlbmRhcl9yZXF1ZXN0X3BhcmFtcyA6IHBhcmFtcyBcdFx0XHRcdFx0XHQvLyBVc3VhbGx5IGxpa2U6IHsgJ3Jlc291cmNlX2lkJzogMSwgJ21heF9kYXlzX2NvdW50JzogMzY1IH1cclxuXHRcdFx0XHR9LFxyXG5cclxuXHRcdFx0XHQvKipcclxuXHRcdFx0XHQgKiBTIHUgYyBjIGUgcyBzXHJcblx0XHRcdFx0ICpcclxuXHRcdFx0XHQgKiBAcGFyYW0gcmVzcG9uc2VfZGF0YVx0XHQtXHRpdHMgb2JqZWN0IHJldHVybmVkIGZyb20gIEFqYXggLSBjbGFzcy1saXZlLXNlYXJjaC5waHBcclxuXHRcdFx0XHQgKiBAcGFyYW0gdGV4dFN0YXR1c1x0XHQtXHQnc3VjY2VzcydcclxuXHRcdFx0XHQgKiBAcGFyYW0ganFYSFJcdFx0XHRcdC1cdE9iamVjdFxyXG5cdFx0XHRcdCAqL1xyXG5cdFx0XHRcdGZ1bmN0aW9uICggcmVzcG9uc2VfZGF0YSwgdGV4dFN0YXR1cywganFYSFIgKSB7XHJcbi8vIGNvbnNvbGUudGltZUVuZCgncmVzb3VyY2VfaWRfJyArIHJlc3BvbnNlX2RhdGFbJ3Jlc291cmNlX2lkJ10pO1xyXG5jb25zb2xlLmxvZyggJyA9PSBSZXNwb25zZSBXUEJDX0FKWF9DQUxFTkRBUl9MT0FEID09ICcsIHJlc3BvbnNlX2RhdGEgKTsgY29uc29sZS5ncm91cEVuZCgpO1xyXG5cclxuXHRcdFx0XHRcdC8vIEZpeEluOiA5LjguNi4yLlxyXG5cdFx0XHRcdFx0dmFyIGFqeF9wb3N0X2RhdGFfX3Jlc291cmNlX2lkID0gd3BiY19nZXRfcmVzb3VyY2VfaWRfX2Zyb21fYWp4X3Bvc3RfZGF0YV91cmwoIHRoaXMuZGF0YSApO1xyXG5cdFx0XHRcdFx0d3BiY19iYWxhbmNlcl9fY29tcGxldGVkKCBhanhfcG9zdF9kYXRhX19yZXNvdXJjZV9pZCAsICd3cGJjX2NhbGVuZGFyX19sb2FkX2RhdGFfX2FqeCcgKTtcclxuXHJcblx0XHRcdFx0XHR2YXIgaXNfdmFsaWRfcmVzcG9uc2UgPSAoXG5cdFx0XHRcdFx0XHRcdCh0eXBlb2YgcmVzcG9uc2VfZGF0YSA9PT0gJ29iamVjdCcpXG5cdFx0XHRcdFx0XHQgJiYgKHJlc3BvbnNlX2RhdGEgIT09IG51bGwpXG5cdFx0XHRcdFx0XHQgJiYgKCEgQXJyYXkuaXNBcnJheSggcmVzcG9uc2VfZGF0YSApKVxuXHRcdFx0XHRcdFx0ICYmIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCggcmVzcG9uc2VfZGF0YSwgJ3Jlc291cmNlX2lkJyApXG5cdFx0XHRcdFx0XHQgJiYgKHR5cGVvZiByZXNwb25zZV9kYXRhWyAnYWp4X2RhdGEnIF0gPT09ICdvYmplY3QnKVxuXHRcdFx0XHRcdFx0ICYmIChyZXNwb25zZV9kYXRhWyAnYWp4X2RhdGEnIF0gIT09IG51bGwpXG5cdFx0XHRcdFx0XHQgJiYgKCEgQXJyYXkuaXNBcnJheSggcmVzcG9uc2VfZGF0YVsgJ2FqeF9kYXRhJyBdICkpXG5cdFx0XHRcdFx0XHQgJiYgT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKCByZXNwb25zZV9kYXRhWyAnYWp4X2RhdGEnIF0sICdkYXRlcycgKVxuXHRcdFx0XHRcdFx0ICYmIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCggcmVzcG9uc2VfZGF0YVsgJ2FqeF9kYXRhJyBdLCAncmVzb3VyY2VzX2lkX2Fycl9faW5fZGF0ZXMnIClcblx0XHRcdFx0XHRcdCAmJiBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoIHJlc3BvbnNlX2RhdGFbICdhanhfZGF0YScgXSwgJ2FnZ3JlZ2F0ZV9yZXNvdXJjZV9pZF9hcnInIClcblx0XHRcdFx0XHQpO1xuXG5cdFx0XHRcdFx0aWYgKCAhIGlzX3ZhbGlkX3Jlc3BvbnNlICkge1xuXHRcdFx0XHRcdFx0dmFyIGpxX25vZGUgPSB3cGJjX2dldF9jYWxlbmRhcl9fanFfbm9kZV9fZm9yX21lc3NhZ2VzKCB0aGlzLmRhdGEgKTtcblx0XHRcdFx0XHRcdHZhciByZXNwb25zZV9lcnJvcl9tZXNzYWdlID0gX3dwYmMuZ2V0X21lc3NhZ2UoICdtZXNzYWdlX3VuZXhwZWN0ZWRfc2VydmVyX3Jlc3BvbnNlJyApIHx8ICdUaGUgc2VydmVyIHJldHVybmVkIGFuIHVuZXhwZWN0ZWQgcmVzcG9uc2UuIFBsZWFzZSByZWxvYWQgdGhlIHBhZ2UgYW5kIHRyeSBhZ2Fpbi4nO1xuXG5cdFx0XHRcdFx0XHR3cGJjX2Zyb250X2VuZF9fbG9nX3VuZXhwZWN0ZWRfYWpheF9yZXNwb25zZSggJ1dQQkNfQUpYX0NBTEVOREFSX0xPQUQnLCByZXNwb25zZV9kYXRhLCBqcVhIUiwgdGV4dFN0YXR1cywgJ0ludmFsaWQgcmVzcG9uc2Ugc3RydWN0dXJlJyApO1xuXHRcdFx0XHRcdFx0d3BiY19jYWxlbmRhcl9fbG9hZGluZ19fc3RvcCggYWp4X3Bvc3RfZGF0YV9fcmVzb3VyY2VfaWQgKTtcblxuXHRcdFx0XHRcdFx0d3BiY19mcm9udF9lbmRfX3Nob3dfbWVzc2FnZSggcmVzcG9uc2VfZXJyb3JfbWVzc2FnZSwgeyAndHlwZScgICAgICAgIDogJ2Vycm9yJyxcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQgICdzaG93X2hlcmUnICAgOiB7J2pxX25vZGUnOiBqcV9ub2RlLCAnd2hlcmUnOiAnYWZ0ZXInfSxcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQgICdpc19hcHBlbmQnICAgOiB0cnVlLFxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCAgJ3N0eWxlJyAgICAgICA6ICd0ZXh0LWFsaWduOmxlZnQ7Jyxcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQgICdjb250ZW50X21vZGUnOiAndGV4dCcsXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0ICAnZGVsYXknICAgICAgIDogMFxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdH0gKTtcblx0XHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0XHR9XG5cclxuXHRcdFx0XHRcdC8vIFNob3cgQ2FsZW5kYXJcclxuXHRcdFx0XHRcdHdwYmNfY2FsZW5kYXJfX2xvYWRpbmdfX3N0b3AoIHJlc3BvbnNlX2RhdGFbICdyZXNvdXJjZV9pZCcgXSApO1xyXG5cclxuXHRcdFx0XHRcdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdFx0XHRcdC8vIEJvb2tpbmdzIC0gRGF0ZXNcclxuXHRcdFx0XHRcdF93cGJjLmJvb2tpbmdzX2luX2NhbGVuZGFyX19zZXRfZGF0ZXMoICByZXNwb25zZV9kYXRhWyAncmVzb3VyY2VfaWQnIF0sIHJlc3BvbnNlX2RhdGFbICdhanhfZGF0YScgXVsnZGF0ZXMnXSAgKTtcclxuXHJcblx0XHRcdFx0XHQvLyBCb29raW5ncyAtIENoaWxkIG9yIG9ubHkgc2luZ2xlIGJvb2tpbmcgcmVzb3VyY2UgaW4gZGF0ZXNcclxuXHRcdFx0XHRcdF93cGJjLmJvb2tpbmdfX3NldF9wYXJhbV92YWx1ZSggcmVzcG9uc2VfZGF0YVsgJ3Jlc291cmNlX2lkJyBdLCAncmVzb3VyY2VzX2lkX2Fycl9faW5fZGF0ZXMnLCByZXNwb25zZV9kYXRhWyAnYWp4X2RhdGEnIF1bICdyZXNvdXJjZXNfaWRfYXJyX19pbl9kYXRlcycgXSApO1xyXG5cclxuXHRcdFx0XHRcdC8vIEFnZ3JlZ2F0ZSBib29raW5nIHJlc291cmNlcywgIGlmIGFueSA/XHJcblx0XHRcdFx0XHRfd3BiYy5ib29raW5nX19zZXRfcGFyYW1fdmFsdWUoIHJlc3BvbnNlX2RhdGFbICdyZXNvdXJjZV9pZCcgXSwgJ2FnZ3JlZ2F0ZV9yZXNvdXJjZV9pZF9hcnInLCByZXNwb25zZV9kYXRhWyAnYWp4X2RhdGEnIF1bICdhZ2dyZWdhdGVfcmVzb3VyY2VfaWRfYXJyJyBdICk7XG5cdFx0XHRcdFx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdFx0XHRcdFx0LyoqXG5cdFx0XHRcdFx0ICogQWxsb3cgb3B0aW9uYWwgbW9kdWxlcyB0byBjYWxjdWxhdGUgZGVyaXZlZCBjYWxlbmRhciBzdGF0ZSBhZnRlciBjYW5vbmljYWxcblx0XHRcdFx0XHQgKiBBSkFYIGRhdGEgaXMgc3RvcmVkIGFuZCBiZWZvcmUgdGhlIGZpcnN0IHJlZnJlc2hlZCBjYWxlbmRhciByZW5kZXIuXG5cdFx0XHRcdFx0ICpcblx0XHRcdFx0XHQgKiBAcGFyYW0ge251bWJlcnxzdHJpbmd9IHJlc291cmNlX2lkIEJvb2tpbmcgcmVzb3VyY2UgSUQuXG5cdFx0XHRcdFx0ICovXG5cdFx0XHRcdFx0alF1ZXJ5KCAnYm9keScgKS50cmlnZ2VyKCAnd3BiY19jYWxlbmRhcl9hanhfX2JlZm9yZV91cGRhdGVfbG9vaycsIFsgcmVzcG9uc2VfZGF0YVsgJ3Jlc291cmNlX2lkJyBdIF0gKTtcblxuXHRcdFx0XHRcdC8vIFVwZGF0ZSBjYWxlbmRhclxuXHRcdFx0XHRcdHdwYmNfY2FsZW5kYXJfX3VwZGF0ZV9sb29rKCByZXNwb25zZV9kYXRhWyAncmVzb3VyY2VfaWQnIF0gKTtcblxyXG5cdFx0XHRcdFx0aWYgKCAnZnVuY3Rpb24nID09PSB0eXBlb2YgKHdwYmNfaG9va19faW5pdF90aW1lc2VsZWN0b3IpICkge1xyXG5cdFx0XHRcdFx0XHR3cGJjX2hvb2tfX2luaXRfdGltZXNlbGVjdG9yKCk7XHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0aWYgKFxyXG5cdFx0XHRcdFx0XHRcdCggJ3VuZGVmaW5lZCcgIT09IHR5cGVvZiAocmVzcG9uc2VfZGF0YVsgJ2FqeF9kYXRhJyBdWyAnYWp4X2FmdGVyX2FjdGlvbl9tZXNzYWdlJyBdKSApXHJcblx0XHRcdFx0XHRcdCAmJiAoICcnICE9IHJlc3BvbnNlX2RhdGFbICdhanhfZGF0YScgXVsgJ2FqeF9hZnRlcl9hY3Rpb25fbWVzc2FnZScgXS5yZXBsYWNlKCAvXFxuL2csIFwiPGJyIC8+XCIgKSApXHJcblx0XHRcdFx0XHQpe1xyXG5cclxuXHRcdFx0XHRcdFx0dmFyIGpxX25vZGUgID0gd3BiY19nZXRfY2FsZW5kYXJfX2pxX25vZGVfX2Zvcl9tZXNzYWdlcyggdGhpcy5kYXRhICk7XHJcblxyXG5cdFx0XHRcdFx0XHQvLyBTaG93IE1lc3NhZ2VcclxuXHRcdFx0XHRcdFx0d3BiY19mcm9udF9lbmRfX3Nob3dfbWVzc2FnZSggcmVzcG9uc2VfZGF0YVsgJ2FqeF9kYXRhJyBdWyAnYWp4X2FmdGVyX2FjdGlvbl9tZXNzYWdlJyBdLnJlcGxhY2UoIC9cXG4vZywgXCI8YnIgLz5cIiApLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0eyAgICd0eXBlJyAgICAgOiAoICd1bmRlZmluZWQnICE9PSB0eXBlb2YoIHJlc3BvbnNlX2RhdGFbICdhanhfZGF0YScgXVsgJ2FqeF9hZnRlcl9hY3Rpb25fbWVzc2FnZV9zdGF0dXMnIF0gKSApXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCAgPyByZXNwb25zZV9kYXRhWyAnYWp4X2RhdGEnIF1bICdhanhfYWZ0ZXJfYWN0aW9uX21lc3NhZ2Vfc3RhdHVzJyBdIDogJ2luZm8nLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnc2hvd19oZXJlJzogeydqcV9ub2RlJzoganFfbm9kZSwgJ3doZXJlJzogJ2FmdGVyJ30sXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCdpc19hcHBlbmQnOiB0cnVlLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnc3R5bGUnICAgIDogJ3RleHQtYWxpZ246bGVmdDsnLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnZGVsYXknICAgIDogMTAwMDBcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdH0gKTtcclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRpZiAoICdmdW5jdGlvbicgPT09IHR5cGVvZiAod3BiY191cGRhdGVfY2FwYWNpdHlfaGludCkgKSB7XHJcblx0XHRcdFx0XHRcdHdwYmNfdXBkYXRlX2NhcGFjaXR5X2hpbnQoIHJlc3BvbnNlX2RhdGFbJ3Jlc291cmNlX2lkJ10gKTtcclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHQvLyBUcmlnZ2VyIGV2ZW50IHRoYXQgY2FsZW5kYXIgaGFzIGJlZW5cdFx0IC8vIEZpeEluOiAxMC4wLjAuNDQuICAvLyBGaXhJbjogMTAuMTQuMTcuMi5cclxuXHRcdFx0XHRcdGlmICggKGpRdWVyeSggJyNjYWxlbmRhcl9ib29raW5nJyArIHJlc3BvbnNlX2RhdGFbJ3Jlc291cmNlX2lkJ10gKS5sZW5ndGggPiAwKSB8fCAoalF1ZXJ5KCAnI2RhdGVfYm9va2luZycgKyByZXNwb25zZV9kYXRhWydyZXNvdXJjZV9pZCddICkubGVuZ3RoID4gMCkgKSB7XHJcblx0XHRcdFx0XHRcdHZhciB0YXJnZXRfZWxtID0galF1ZXJ5KCAnYm9keScgKS50cmlnZ2VyKCBcIndwYmNfY2FsZW5kYXJfYWp4X19sb2FkZWRfZGF0YVwiLCBbcmVzcG9uc2VfZGF0YVsgJ3Jlc291cmNlX2lkJyBdXSApO1xyXG5cdFx0XHRcdFx0XHQgLy9qUXVlcnkoICdib2R5JyApLm9uKCAnd3BiY19jYWxlbmRhcl9hanhfX2xvYWRlZF9kYXRhJywgZnVuY3Rpb24oIGV2ZW50LCByZXNvdXJjZV9pZCApIHsgLi4uIH0gKTtcclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHQvL2pRdWVyeSggJyNhamF4X3Jlc3BvbmQnICkuaHRtbCggcmVzcG9uc2VfZGF0YSApO1x0XHQvLyBGb3IgYWJpbGl0eSB0byBzaG93IHJlc3BvbnNlLCBhZGQgc3VjaCBESVYgZWxlbWVudCB0byBwYWdlXHJcblx0XHRcdFx0fVxyXG5cdFx0XHQgICkuZmFpbCggZnVuY3Rpb24gKCBqcVhIUiwgdGV4dFN0YXR1cywgZXJyb3JUaHJvd24gKSB7XG5cdFx0XHRcdFx0d3BiY19mcm9udF9lbmRfX2xvZ191bmV4cGVjdGVkX2FqYXhfcmVzcG9uc2UoICdXUEJDX0FKWF9DQUxFTkRBUl9MT0FEJywganFYSFIucmVzcG9uc2VUZXh0IHx8ICcnLCBqcVhIUiwgdGV4dFN0YXR1cywgZXJyb3JUaHJvd24gKTtcblxyXG5cdFx0XHRcdFx0dmFyIGFqeF9wb3N0X2RhdGFfX3Jlc291cmNlX2lkID0gd3BiY19nZXRfcmVzb3VyY2VfaWRfX2Zyb21fYWp4X3Bvc3RfZGF0YV91cmwoIHRoaXMuZGF0YSApO1xuXHRcdFx0XHRcdHdwYmNfYmFsYW5jZXJfX2NvbXBsZXRlZCggYWp4X3Bvc3RfZGF0YV9fcmVzb3VyY2VfaWQgLCAnd3BiY19jYWxlbmRhcl9fbG9hZF9kYXRhX19hangnICk7XG5cdFx0XHRcdFx0d3BiY19jYWxlbmRhcl9fbG9hZGluZ19fc3RvcCggYWp4X3Bvc3RfZGF0YV9fcmVzb3VyY2VfaWQgKTtcblxuXHRcdFx0XHRcdHZhciBmYWxsYmFja19lcnJvcl9tZXNzYWdlID0gX3dwYmMuZ2V0X21lc3NhZ2UoICdtZXNzYWdlX3VuZXhwZWN0ZWRfc2VydmVyX3Jlc3BvbnNlJyApIHx8ICdUaGUgc2VydmVyIHJldHVybmVkIGFuIHVuZXhwZWN0ZWQgcmVzcG9uc2UuIFBsZWFzZSByZWxvYWQgdGhlIHBhZ2UgYW5kIHRyeSBhZ2Fpbi4nO1xuXHRcdFx0XHRcdHZhciBjb25mbGljdF9jYWNoZV9oaW50ICAgID0gX3dwYmMuZ2V0X21lc3NhZ2UoICdtZXNzYWdlX2h0dHBfY29uZmxpY3RfY2FjaGVfaGludCcgKSB8fCAnQSBjYWNoZWQgb3Igb3B0aW1pemVkIHZlcnNpb24gb2YgdGhpcyBwYWdlIG1heSBiZSBvdXRkYXRlZC4gQ2xlYXIgdGhlIGJyb3dzZXIgY2FjaGUgYW5kIHJlbG9hZCB0aGUgcGFnZS4gV2Vic2l0ZSBhZG1pbmlzdHJhdG9ycyBzaG91bGQgYWxzbyBwdXJnZSBwYWdlLCBzZXJ2ZXIsIGFuZCBDRE4gY2FjaGVzIGFuZCByZWdlbmVyYXRlIG1pbmlmaWVkIG9yIG9wdGltaXplZCBmaWxlcy4nO1xuXHRcdFx0XHRcdHZhciBlcnJvcl9tZXNzYWdlICAgICAgICAgID0gd3BiY19mcm9udF9lbmRfX2dldF9hamF4X2Vycm9yX21lc3NhZ2UoIGpxWEhSLCBmYWxsYmFja19lcnJvcl9tZXNzYWdlLCBjb25mbGljdF9jYWNoZV9oaW50ICk7XG5cdFx0XHRcdFx0dmFyIG1lc3NhZ2Vfc2hvd19kZWxheSA9IDMwMDA7XG5cblx0XHRcdFx0XHR2YXIganFfbm9kZSAgPSB3cGJjX2dldF9jYWxlbmRhcl9fanFfbm9kZV9fZm9yX21lc3NhZ2VzKCB0aGlzLmRhdGEgKTtcblxyXG5cdFx0XHRcdFx0LyoqXHJcblx0XHRcdFx0XHQgKiBJZiB3ZSBtYWtlIGZhc3QgY2xpY2tpbmcgb24gZGlmZmVyZW50IHBhZ2VzLFxyXG5cdFx0XHRcdFx0ICogdGhlbiB1bmRlciBjYWxlbmRhciB3aWxsIHNob3cgZXJyb3IgbWVzc2FnZSB3aXRoICBlbXB0eSAgdGV4dCwgYmVjYXVzZSBhamF4IHdhcyBub3QgcmVjZWl2ZWQuXHJcblx0XHRcdFx0XHQgKiBUbyAgbm90IHNob3cgc3VjaCB3YXJuaW5ncyB3ZSBhcmUgc2V0IGRlbGF5ICBpbiAzIHNlY29uZHMuICB2YXIgbWVzc2FnZV9zaG93X2RlbGF5ID0gMzAwMDtcclxuXHRcdFx0XHRcdCAqL1xyXG5cdFx0XHRcdFx0dmFyIGNsb3NlZF90aW1lciA9IHNldFRpbWVvdXQoIGZ1bmN0aW9uICgpe1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQvLyBTaG93IE1lc3NhZ2VcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHR3cGJjX2Zyb250X2VuZF9fc2hvd19tZXNzYWdlKCBlcnJvcl9tZXNzYWdlICwgeyAndHlwZScgICAgIDogJ2Vycm9yJyxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnc2hvd19oZXJlJzogeydqcV9ub2RlJzoganFfbm9kZSwgJ3doZXJlJzogJ2FmdGVyJ30sXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J2lzX2FwcGVuZCc6IHRydWUsXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCdzdHlsZScgICAgOiAndGV4dC1hbGlnbjpsZWZ0OycsXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCdjc3NfY2xhc3MnOid3cGJjX2ZlX21lc3NhZ2VfYWx0Jyxcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J2NvbnRlbnRfbW9kZSc6ICd0ZXh0Jyxcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J2RlbGF5JyAgICA6IDBcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdH0gKTtcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCAgIH0gLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0ICAgcGFyc2VJbnQoIG1lc3NhZ2Vfc2hvd19kZWxheSApICAgKTtcclxuXHJcblx0XHRcdCAgfSlcclxuXHQgICAgICAgICAgLy8gLmRvbmUoICAgZnVuY3Rpb24gKCBkYXRhLCB0ZXh0U3RhdHVzLCBqcVhIUiApIHsgICBpZiAoIHdpbmRvdy5jb25zb2xlICYmIHdpbmRvdy5jb25zb2xlLmxvZyApeyBjb25zb2xlLmxvZyggJ3NlY29uZCBzdWNjZXNzJywgZGF0YSwgdGV4dFN0YXR1cywganFYSFIgKTsgfSAgICB9KVxyXG5cdFx0XHQgIC8vIC5hbHdheXMoIGZ1bmN0aW9uICggZGF0YV9qcVhIUiwgdGV4dFN0YXR1cywganFYSFJfZXJyb3JUaHJvd24gKSB7ICAgaWYgKCB3aW5kb3cuY29uc29sZSAmJiB3aW5kb3cuY29uc29sZS5sb2cgKXsgY29uc29sZS5sb2coICdhbHdheXMgZmluaXNoZWQnLCBkYXRhX2pxWEhSLCB0ZXh0U3RhdHVzLCBqcVhIUl9lcnJvclRocm93biApOyB9ICAgICB9KVxyXG5cdFx0XHQgIDsgIC8vIEVuZCBBamF4XHJcbn1cclxuXHJcblxyXG5cclxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcbi8vIFN1cHBvcnRcclxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblxyXG5cdC8qKlxyXG5cdCAqIEdldCBDYWxlbmRhciBqUXVlcnkgbm9kZSBmb3Igc2hvd2luZyBtZXNzYWdlcyBkdXJpbmcgQWpheFxyXG5cdCAqIFRoaXMgcGFyYW1ldGVyOiAgIGNhbGVuZGFyX3JlcXVlc3RfcGFyYW1zW3Jlc291cmNlX2lkXSAgIHBhcnNlZCBmcm9tIHRoaXMuZGF0YSBBamF4IHBvc3QgIGRhdGFcclxuXHQgKlxyXG5cdCAqIEBwYXJhbSBhanhfcG9zdF9kYXRhX3VybF9wYXJhbXNcdFx0ICdhY3Rpb249V1BCQ19BSlhfQ0FMRU5EQVJfTE9BRC4uLiZjYWxlbmRhcl9yZXF1ZXN0X3BhcmFtcyU1QnJlc291cmNlX2lkJTVEPTImY2FsZW5kYXJfcmVxdWVzdF9wYXJhbXMlNUJib29raW5nX2hhc2glNUQ9JmNhbGVuZGFyX3JlcXVlc3RfcGFyYW1zJ1xyXG5cdCAqIEByZXR1cm5zIHtzdHJpbmd9XHQnJyNjYWxlbmRhcl9ib29raW5nMScgIHwgICAnLmJvb2tpbmdfZm9ybV9kaXYnIC4uLlxyXG5cdCAqXHJcblx0ICogRXhhbXBsZSAgICB2YXIganFfbm9kZSAgPSB3cGJjX2dldF9jYWxlbmRhcl9fanFfbm9kZV9fZm9yX21lc3NhZ2VzKCB0aGlzLmRhdGEgKTtcclxuXHQgKi9cclxuXHRmdW5jdGlvbiB3cGJjX2dldF9jYWxlbmRhcl9fanFfbm9kZV9fZm9yX21lc3NhZ2VzKCBhanhfcG9zdF9kYXRhX3VybF9wYXJhbXMgKXtcclxuXHJcblx0XHR2YXIganFfbm9kZSA9ICcuYm9va2luZ19mb3JtX2Rpdic7XHJcblxyXG5cdFx0dmFyIGNhbGVuZGFyX3Jlc291cmNlX2lkID0gd3BiY19nZXRfcmVzb3VyY2VfaWRfX2Zyb21fYWp4X3Bvc3RfZGF0YV91cmwoIGFqeF9wb3N0X2RhdGFfdXJsX3BhcmFtcyApO1xyXG5cclxuXHRcdGlmICggY2FsZW5kYXJfcmVzb3VyY2VfaWQgPiAwICl7XHJcblx0XHRcdGpxX25vZGUgPSAnI2NhbGVuZGFyX2Jvb2tpbmcnICsgY2FsZW5kYXJfcmVzb3VyY2VfaWQ7XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGpxX25vZGU7XHJcblx0fVxyXG5cclxuXHJcblx0LyoqXHJcblx0ICogR2V0IHJlc291cmNlIElEIGZyb20gYWp4IHBvc3QgZGF0YSB1cmwgICB1c3VhbGx5ICBmcm9tICB0aGlzLmRhdGEgID1cclxuXHQgKiAnYWN0aW9uPVdQQkNfQUpYX0NBTEVOREFSX0xPQUQuLi4mY2FsZW5kYXJfcmVxdWVzdF9wYXJhbXMlNUJyZXNvdXJjZV9pZCU1RD0yJmNhbGVuZGFyX3JlcXVlc3RfcGFyYW1zJTVCYm9va2luZ19oYXNoJTVEPSZjYWxlbmRhcl9yZXF1ZXN0X3BhcmFtcydcclxuXHQgKlxyXG5cdCAqIEBwYXJhbSBhanhfcG9zdF9kYXRhX3VybF9wYXJhbXNcdFx0ICdhY3Rpb249V1BCQ19BSlhfQ0FMRU5EQVJfTE9BRC4uLiZjYWxlbmRhcl9yZXF1ZXN0X3BhcmFtcyU1QnJlc291cmNlX2lkJTVEPTImY2FsZW5kYXJfcmVxdWVzdF9wYXJhbXMlNUJib29raW5nX2hhc2glNUQ9JmNhbGVuZGFyX3JlcXVlc3RfcGFyYW1zJ1xyXG5cdCAqIEByZXR1cm5zIHtpbnR9XHRcdFx0XHRcdFx0IDEgfCAwICAoaWYgZXJycm9yIHRoZW4gIDApXHJcblx0ICpcclxuXHQgKiBFeGFtcGxlICAgIHZhciBqcV9ub2RlICA9IHdwYmNfZ2V0X2NhbGVuZGFyX19qcV9ub2RlX19mb3JfbWVzc2FnZXMoIHRoaXMuZGF0YSApO1xyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdwYmNfZ2V0X3Jlc291cmNlX2lkX19mcm9tX2FqeF9wb3N0X2RhdGFfdXJsKCBhanhfcG9zdF9kYXRhX3VybF9wYXJhbXMgKXtcclxuXHJcblx0XHQvLyBHZXQgYm9va2luZyByZXNvdXJjZSBJRCBmcm9tIEFqYXggUG9zdCBSZXF1ZXN0ICAtPiB0aGlzLmRhdGEgPSAnYWN0aW9uPVdQQkNfQUpYX0NBTEVOREFSX0xPQUQuLi4mY2FsZW5kYXJfcmVxdWVzdF9wYXJhbXMlNUJyZXNvdXJjZV9pZCU1RD0yJmNhbGVuZGFyX3JlcXVlc3RfcGFyYW1zJTVCYm9va2luZ19oYXNoJTVEPSZjYWxlbmRhcl9yZXF1ZXN0X3BhcmFtcydcclxuXHRcdHZhciBjYWxlbmRhcl9yZXNvdXJjZV9pZCA9IHdwYmNfZ2V0X3VyaV9wYXJhbV9ieV9uYW1lKCAnY2FsZW5kYXJfcmVxdWVzdF9wYXJhbXNbcmVzb3VyY2VfaWRdJywgYWp4X3Bvc3RfZGF0YV91cmxfcGFyYW1zICk7XHJcblx0XHRpZiAoIChudWxsICE9PSBjYWxlbmRhcl9yZXNvdXJjZV9pZCkgJiYgKCcnICE9PSBjYWxlbmRhcl9yZXNvdXJjZV9pZCkgKXtcclxuXHRcdFx0Y2FsZW5kYXJfcmVzb3VyY2VfaWQgPSBwYXJzZUludCggY2FsZW5kYXJfcmVzb3VyY2VfaWQgKTtcclxuXHRcdFx0aWYgKCBjYWxlbmRhcl9yZXNvdXJjZV9pZCA+IDAgKXtcclxuXHRcdFx0XHRyZXR1cm4gY2FsZW5kYXJfcmVzb3VyY2VfaWQ7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHRcdHJldHVybiAwO1xyXG5cdH1cclxuXHJcblxyXG5cdC8qKlxyXG5cdCAqIEdldCBwYXJhbWV0ZXIgZnJvbSBVUkwgIC0gIHBhcnNlIFVSTCBwYXJhbWV0ZXJzLCAgbGlrZSB0aGlzOlxyXG5cdCAqIGFjdGlvbj1XUEJDX0FKWF9DQUxFTkRBUl9MT0FELi4uJmNhbGVuZGFyX3JlcXVlc3RfcGFyYW1zJTVCcmVzb3VyY2VfaWQlNUQ9MiZjYWxlbmRhcl9yZXF1ZXN0X3BhcmFtcyU1QmJvb2tpbmdfaGFzaCU1RD0mY2FsZW5kYXJfcmVxdWVzdF9wYXJhbXNcclxuXHQgKiBAcGFyYW0gbmFtZSAgcGFyYW1ldGVyICBuYW1lLCAgbGlrZSAnY2FsZW5kYXJfcmVxdWVzdF9wYXJhbXNbcmVzb3VyY2VfaWRdJ1xyXG5cdCAqIEBwYXJhbSB1cmxcdCdwYXJhbWV0ZXIgIHN0cmluZyBVUkwnXHJcblx0ICogQHJldHVybnMge3N0cmluZ3xudWxsfSAgIHBhcmFtZXRlciB2YWx1ZVxyXG5cdCAqXHJcblx0ICogRXhhbXBsZTogXHRcdHdwYmNfZ2V0X3VyaV9wYXJhbV9ieV9uYW1lKCAnY2FsZW5kYXJfcmVxdWVzdF9wYXJhbXNbcmVzb3VyY2VfaWRdJywgdGhpcy5kYXRhICk7ICAtPiAnMidcclxuXHQgKi9cclxuXHRmdW5jdGlvbiB3cGJjX2dldF91cmlfcGFyYW1fYnlfbmFtZSggbmFtZSwgdXJsICl7XHJcblxyXG5cdFx0dXJsID0gZGVjb2RlVVJJQ29tcG9uZW50KCB1cmwgKTtcclxuXHJcblx0XHRuYW1lID0gbmFtZS5yZXBsYWNlKCAvW1xcW1xcXV0vZywgJ1xcXFwkJicgKTtcclxuXHRcdHZhciByZWdleCA9IG5ldyBSZWdFeHAoICdbPyZdJyArIG5hbWUgKyAnKD0oW14mI10qKXwmfCN8JCknICksXHJcblx0XHRcdHJlc3VsdHMgPSByZWdleC5leGVjKCB1cmwgKTtcclxuXHRcdGlmICggIXJlc3VsdHMgKSByZXR1cm4gbnVsbDtcclxuXHRcdGlmICggIXJlc3VsdHNbIDIgXSApIHJldHVybiAnJztcclxuXHRcdHJldHVybiBkZWNvZGVVUklDb21wb25lbnQoIHJlc3VsdHNbIDIgXS5yZXBsYWNlKCAvXFwrL2csICcgJyApICk7XHJcblx0fVxyXG4iLCIvKipcclxuICogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcbiAqXHRpbmNsdWRlcy9fX2pzL2Zyb250X2VuZF9tZXNzYWdlcy93cGJjX2ZlX21lc3NhZ2VzLmpzXHJcbiAqID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG4gKi9cclxuXHJcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG4vLyBTaG93IE1lc3NhZ2VzIGF0IEZyb250LUVkbiBzaWRlXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuLyoqXG4gKiBFeHRyYWN0IGEgc2FmZSBwbGFpbi10ZXh0IG1lc3NhZ2UgZnJvbSBhIHJlY29nbml6ZWQgSlNPTiBBSkFYIGVycm9yIHJlc3BvbnNlLlxuICpcbiAqIE9ubHkgZG9jdW1lbnRlZCBtZXNzYWdlIHByb3BlcnRpZXMgYXJlIGFjY2VwdGVkLiBDYWxsZXJzIG11c3Qgc3RpbGwgcmVuZGVyIHRoZSByZXR1cm5lZCB2YWx1ZSBpbiB0ZXh0IG1vZGUgc28gYW5cbiAqIHVwc3RyZWFtIHJlc3BvbnNlIGNhbm5vdCBpbmplY3QgbWFya3VwIGludG8gdGhlIHB1YmxpYyBib29raW5nIHBhZ2UuXG4gKlxuICogQHBhcmFtIHtqcVhIUnxudWxsfSBqcV94aHIgalF1ZXJ5IFhIUiBvYmplY3QsIHdoZW4gYXZhaWxhYmxlLlxuICogQHJldHVybiB7c3RyaW5nfSBCb3VuZGVkIHNlcnZlciBtZXNzYWdlLCBvciBhbiBlbXB0eSBzdHJpbmcgd2hlbiB0aGUgcmVzcG9uc2UgaXMgbm90IHJlY29nbml6ZWQuXG4gKi9cbmZ1bmN0aW9uIHdwYmNfZnJvbnRfZW5kX19nZXRfc2FmZV9hamF4X2Vycm9yX21lc3NhZ2UoIGpxX3hociApIHtcblx0aWYgKFxuXHRcdCEganFfeGhyXG5cdFx0fHwgISBqcV94aHIucmVzcG9uc2VKU09OXG5cdFx0fHwgJ29iamVjdCcgIT09IHR5cGVvZiBqcV94aHIucmVzcG9uc2VKU09OXG5cdFx0fHwgQXJyYXkuaXNBcnJheSgganFfeGhyLnJlc3BvbnNlSlNPTiApXG5cdCkge1xuXHRcdHJldHVybiAnJztcblx0fVxuXG5cdHZhciByZXNwb25zZV9qc29uICAgICAgPSBqcV94aHIucmVzcG9uc2VKU09OO1xuXHR2YXIgbWVzc2FnZV9jYW5kaWRhdGVzID0gW107XG5cblx0aWYgKCAnc3RyaW5nJyA9PT0gdHlwZW9mIHJlc3BvbnNlX2pzb24ubWVzc2FnZSApIHtcblx0XHRtZXNzYWdlX2NhbmRpZGF0ZXMucHVzaCggcmVzcG9uc2VfanNvbi5tZXNzYWdlICk7XG5cdH1cblx0aWYgKFxuXHRcdHJlc3BvbnNlX2pzb24uZGF0YVxuXHRcdCYmICdvYmplY3QnID09PSB0eXBlb2YgcmVzcG9uc2VfanNvbi5kYXRhXG5cdFx0JiYgISBBcnJheS5pc0FycmF5KCByZXNwb25zZV9qc29uLmRhdGEgKVxuXHRcdCYmICdzdHJpbmcnID09PSB0eXBlb2YgcmVzcG9uc2VfanNvbi5kYXRhLm1lc3NhZ2Vcblx0KSB7XG5cdFx0bWVzc2FnZV9jYW5kaWRhdGVzLnB1c2goIHJlc3BvbnNlX2pzb24uZGF0YS5tZXNzYWdlICk7XG5cdH1cblxuXHRmb3IgKCB2YXIgY2FuZGlkYXRlX2luZGV4ID0gMDsgY2FuZGlkYXRlX2luZGV4IDwgbWVzc2FnZV9jYW5kaWRhdGVzLmxlbmd0aDsgY2FuZGlkYXRlX2luZGV4KysgKSB7XG5cdFx0dmFyIHNlcnZlcl9tZXNzYWdlID0gbWVzc2FnZV9jYW5kaWRhdGVzWyBjYW5kaWRhdGVfaW5kZXggXS50cmltKCk7XG5cdFx0aWYgKCBzZXJ2ZXJfbWVzc2FnZSApIHtcblx0XHRcdHJldHVybiBzZXJ2ZXJfbWVzc2FnZS5zbGljZSggMCwgMTAwMCApO1xuXHRcdH1cblx0fVxuXG5cdHJldHVybiAnJztcbn1cblxuLyoqXG4gKiBCdWlsZCBhIHB1YmxpYy1zYWZlIEFKQVggZmFpbHVyZSBtZXNzYWdlIHdpdGggb3B0aW9uYWwgSFRUUCA0MDkgY2FjaGUgdHJvdWJsZXNob290aW5nIGd1aWRhbmNlLlxuICpcbiAqIEBwYXJhbSB7anFYSFJ8bnVsbH0ganFfeGhyICAgICAgICAgICAgICAgICAgICBqUXVlcnkgWEhSIG9iamVjdCwgd2hlbiBhdmFpbGFibGUuXG4gKiBAcGFyYW0ge3N0cmluZ30gICAgIGZhbGxiYWNrX21lc3NhZ2UgICAgICAgICAgTG9jYWxpemVkIGZhbGxiYWNrIHNob3duIHdoZW4gbm8gc2FmZSBzZXJ2ZXIgbWVzc2FnZSBleGlzdHMuXG4gKiBAcGFyYW0ge3N0cmluZ30gICAgIGh0dHBfY29uZmxpY3RfY2FjaGVfaGludCAgT3B0aW9uYWwgbG9jYWxpemVkIGNhY2hlIGd1aWRhbmNlIGZvciBIVFRQIDQwOSByZXNwb25zZXMuXG4gKiBAcmV0dXJuIHtzdHJpbmd9IFBsYWluLXRleHQgbWVzc2FnZSBpbmNsdWRpbmcgdGhlIEhUVFAgc3RhdHVzIHdoZW4gYXZhaWxhYmxlLlxuICovXG5mdW5jdGlvbiB3cGJjX2Zyb250X2VuZF9fZ2V0X2FqYXhfZXJyb3JfbWVzc2FnZSgganFfeGhyLCBmYWxsYmFja19tZXNzYWdlLCBodHRwX2NvbmZsaWN0X2NhY2hlX2hpbnQgKSB7XG5cdHZhciBodHRwX3N0YXR1cyAgICAgICAgID0ganFfeGhyICYmIGpxX3hoci5zdGF0dXMgPyBwYXJzZUludCgganFfeGhyLnN0YXR1cywgMTAgKSA6IDA7XG5cdHZhciBzYWZlX3NlcnZlcl9tZXNzYWdlID0gd3BiY19mcm9udF9lbmRfX2dldF9zYWZlX2FqYXhfZXJyb3JfbWVzc2FnZSgganFfeGhyICk7XG5cdHZhciBlcnJvcl9tZXNzYWdlICAgICAgID0gc2FmZV9zZXJ2ZXJfbWVzc2FnZSB8fCBTdHJpbmcoIGZhbGxiYWNrX21lc3NhZ2UgfHwgJycgKS50cmltKCk7XG5cblx0aWYgKCA0MDkgPT09IGh0dHBfc3RhdHVzICYmIGh0dHBfY29uZmxpY3RfY2FjaGVfaGludCApIHtcblx0XHRlcnJvcl9tZXNzYWdlICs9ICggZXJyb3JfbWVzc2FnZSA/ICcgJyA6ICcnICkgKyBTdHJpbmcoIGh0dHBfY29uZmxpY3RfY2FjaGVfaGludCApLnRyaW0oKTtcblx0fVxuXHRpZiAoIGh0dHBfc3RhdHVzICkge1xuXHRcdGVycm9yX21lc3NhZ2UgKz0gJyAoJyArIGh0dHBfc3RhdHVzICsgJyknO1xuXHR9XG5cblx0cmV0dXJuIGVycm9yX21lc3NhZ2U7XG59XG5cbi8qKlxuICogTG9nIGFuIHVuZXhwZWN0ZWQgQUpBWCByZXNwb25zZSBmb3IgYnJvd3Nlci1jb25zb2xlIGRpYWdub3N0aWNzLlxuICpcbiAqIFRoZSByZXNwb25zZSBpcyBpbnRlbnRpb25hbGx5IGtlcHQgb3V0IG9mIGZyb250ZW5kIG5vdGljZXMgYmVjYXVzZSBpdCBjYW4gY29udGFpbiBhIGNvbXBsZXRlIEhUTUwgZXJyb3Igb3IgbG9naW4gcGFnZS5cbiAqIExvZ2dpbmcgaXQgaGVyZSBwcmVzZXJ2ZXMgdGhlIHNlcnZlciBwYXlsb2FkIGFuZCByZXF1ZXN0IGNvbnRleHQgZm9yIHN1cHBvcnQgdHJvdWJsZXNob290aW5nLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSAgICAgIGFqYXhfYWN0aW9uICAgV29yZFByZXNzIEFKQVggYWN0aW9uIHRoYXQgcHJvZHVjZWQgdGhlIHVuZXhwZWN0ZWQgcmVzcG9uc2UuXG4gKiBAcGFyYW0geyp9ICAgICAgICAgICByZXNwb25zZV9kYXRhIFJhdyByZXNwb25zZSBwYXlsb2FkIHJldHVybmVkIGJ5IHRoZSBzZXJ2ZXIuXG4gKiBAcGFyYW0ge2pxWEhSfG51bGx9ICBqcV94aHIgICAgICAgIGpRdWVyeSBYSFIgb2JqZWN0LCB3aGVuIGF2YWlsYWJsZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSAgICAgIHRleHRfc3RhdHVzICAgalF1ZXJ5IHJlcXVlc3Qgc3RhdHVzIG9yIHN1Y2Nlc3Mgc3RhdGUuXG4gKiBAcGFyYW0ge3N0cmluZ3xFcnJvcn0gZXJyb3JfdGhyb3duIEVycm9yIGRlc2NyaXB0aW9uIG9yIGV4Y2VwdGlvbiByZXBvcnRlZCBieSBqUXVlcnkuXG4gKiBAcmV0dXJuIHt2b2lkfVxuICovXG5mdW5jdGlvbiB3cGJjX2Zyb250X2VuZF9fbG9nX3VuZXhwZWN0ZWRfYWpheF9yZXNwb25zZSggYWpheF9hY3Rpb24sIHJlc3BvbnNlX2RhdGEsIGpxX3hociwgdGV4dF9zdGF0dXMsIGVycm9yX3Rocm93biApIHtcblx0aWYgKCAhIHdpbmRvdy5jb25zb2xlIHx8ICdmdW5jdGlvbicgIT09IHR5cGVvZiB3aW5kb3cuY29uc29sZS5lcnJvciApIHtcblx0XHRyZXR1cm47XG5cdH1cblxuXHR0cnkge1xuXHRcdHZhciBjb250ZW50X3R5cGUgICAgICAgPSAnJztcblx0XHR2YXIgcmVzcG9uc2VfdGV4dCAgICAgID0gJ3N0cmluZycgPT09IHR5cGVvZiByZXNwb25zZV9kYXRhID8gcmVzcG9uc2VfZGF0YSA6ICcnO1xuXHRcdHZhciByZXNwb25zZV9sZW5ndGggICAgPSByZXNwb25zZV90ZXh0Lmxlbmd0aDtcblx0XHR2YXIgcmVzcG9uc2VfZm9ybWF0ICAgID0gcmVzcG9uc2VfdGV4dCA/ICd0ZXh0JyA6ICdlbXB0eSc7XG5cdFx0dmFyIGh0dHBfc3RhdHVzICAgICAgICA9IGpxX3hociAmJiBqcV94aHIuc3RhdHVzID8gcGFyc2VJbnQoIGpxX3hoci5zdGF0dXMsIDEwICkgOiAwO1xuXHRcdHZhciBkaWFnbm9zdGljX2FjdGlvbiAgPSBTdHJpbmcoIGFqYXhfYWN0aW9uIHx8ICdBSkFYJyApLnJlcGxhY2UoIC9eV1BCQ19BSlhfLywgJycgKS5yZXBsYWNlKCAvW15BLVphLXowLTldKy9nLCAnLScgKS50b1VwcGVyQ2FzZSgpO1xuXHRcdHZhciBkaWFnbm9zdGljX2NvZGUgICAgPSAnV1BCQy0nICsgZGlhZ25vc3RpY19hY3Rpb24gKyAnLScgKyAoIGh0dHBfc3RhdHVzIHx8ICdORVRXT1JLJyApO1xuXHRcdHZhciByZXNwb25zZV9oZWFkZXJzICAgPSB7fTtcblx0XHRpZiAoIGpxX3hociAmJiAnZnVuY3Rpb24nID09PSB0eXBlb2YganFfeGhyLmdldFJlc3BvbnNlSGVhZGVyICkge1xuXHRcdFx0Y29udGVudF90eXBlID0ganFfeGhyLmdldFJlc3BvbnNlSGVhZGVyKCAnY29udGVudC10eXBlJyApIHx8ICcnO1xuXHRcdFx0cmVzcG9uc2VfaGVhZGVycyA9IHtcblx0XHRcdFx0J3NlcnZlcicgICAgICAgICAgIDoganFfeGhyLmdldFJlc3BvbnNlSGVhZGVyKCAnc2VydmVyJyApIHx8ICcnLFxuXHRcdFx0XHQnY2ZfcmF5JyAgICAgICAgICAgOiBqcV94aHIuZ2V0UmVzcG9uc2VIZWFkZXIoICdjZi1yYXknICkgfHwgJycsXG5cdFx0XHRcdCd4X2NhY2hlJyAgICAgICAgICA6IGpxX3hoci5nZXRSZXNwb25zZUhlYWRlciggJ3gtY2FjaGUnICkgfHwgJycsXG5cdFx0XHRcdCd4X2NhY2hlX3N0YXR1cycgICA6IGpxX3hoci5nZXRSZXNwb25zZUhlYWRlciggJ3gtY2FjaGUtc3RhdHVzJyApIHx8ICcnLFxuXHRcdFx0XHQneF9saXRlc3BlZWRfY2FjaGUnOiBqcV94aHIuZ2V0UmVzcG9uc2VIZWFkZXIoICd4LWxpdGVzcGVlZC1jYWNoZScgKSB8fCAnJyxcblx0XHRcdFx0J3hfcmVxdWVzdF9pZCcgICAgIDoganFfeGhyLmdldFJlc3BvbnNlSGVhZGVyKCAneC1yZXF1ZXN0LWlkJyApIHx8ICcnXG5cdFx0XHR9O1xuXHRcdH1cblx0XHRpZiAoIGpxX3hociAmJiBqcV94aHIucmVzcG9uc2VKU09OICYmICdvYmplY3QnID09PSB0eXBlb2YganFfeGhyLnJlc3BvbnNlSlNPTiApIHtcblx0XHRcdHJlc3BvbnNlX2Zvcm1hdCA9ICdqc29uJztcblx0XHRcdHRyeSB7XG5cdFx0XHRcdHJlc3BvbnNlX2xlbmd0aCA9IEpTT04uc3RyaW5naWZ5KCBqcV94aHIucmVzcG9uc2VKU09OICkubGVuZ3RoO1xuXHRcdFx0fSBjYXRjaCAoIHJlc3BvbnNlX2pzb25fZXJyb3IgKSB7XG5cdFx0XHRcdHJlc3BvbnNlX2xlbmd0aCA9IDA7XG5cdFx0XHR9XG5cdFx0fSBlbHNlIGlmICggLTEgIT09IGNvbnRlbnRfdHlwZS50b0xvd2VyQ2FzZSgpLmluZGV4T2YoICdodG1sJyApIHx8IC9eXFxzKig/OjwhZG9jdHlwZXw8aHRtbCkvaS50ZXN0KCByZXNwb25zZV90ZXh0ICkgKSB7XG5cdFx0XHRyZXNwb25zZV9mb3JtYXQgPSAnaHRtbCc7XG5cdFx0fVxuXG5cdFx0d2luZG93LmNvbnNvbGUuZXJyb3IoICdbV1BCQ11bQUpBWC1VTkVYUEVDVEVELVJFU1BPTlNFXSAnICsgYWpheF9hY3Rpb24sIHtcblx0XHRcdCdhY3Rpb24nICAgICAgICAgIDogYWpheF9hY3Rpb24sXG5cdFx0XHQnZGlhZ25vc3RpY19jb2RlJyA6IGRpYWdub3N0aWNfY29kZSxcblx0XHRcdCdodHRwX3N0YXR1cycgICAgIDogaHR0cF9zdGF0dXMsXG5cdFx0XHQnaHR0cF9zdGF0dXNfdGV4dCc6IGpxX3hociAmJiBqcV94aHIuc3RhdHVzVGV4dCA/IGpxX3hoci5zdGF0dXNUZXh0IDogJycsXG5cdFx0XHQndGV4dF9zdGF0dXMnICAgICA6IHRleHRfc3RhdHVzIHx8ICcnLFxuXHRcdFx0J2Vycm9yJyAgICAgICAgICAgOiBlcnJvcl90aHJvd24gfHwgJycsXG5cdFx0XHQnY29udGVudF90eXBlJyAgICA6IGNvbnRlbnRfdHlwZSxcblx0XHRcdCdyZXNwb25zZV9mb3JtYXQnIDogcmVzcG9uc2VfZm9ybWF0LFxuXHRcdFx0J3Jlc3BvbnNlX2xlbmd0aCcgOiByZXNwb25zZV9sZW5ndGgsXG5cdFx0XHQnc2VydmVyX21lc3NhZ2UnICA6IHdwYmNfZnJvbnRfZW5kX19nZXRfc2FmZV9hamF4X2Vycm9yX21lc3NhZ2UoIGpxX3hociApLFxuXHRcdFx0J3Jlc3BvbnNlX2hlYWRlcnMnOiByZXNwb25zZV9oZWFkZXJzLFxuXHRcdFx0J3Jlc3BvbnNlJyAgICAgICAgOiByZXNwb25zZV9kYXRhXG5cdFx0fSApO1xuXHR9IGNhdGNoICggbG9nZ2luZ19lcnJvciApIHtcblx0XHQvLyBDb25zb2xlIGRpYWdub3N0aWNzIG11c3QgbmV2ZXIgaW50ZXJydXB0IGZyb250ZW5kIGVycm9yIHJlY292ZXJ5LlxuXHR9XG59XG5cbi8qKlxuICogU2hvdyBtZXNzYWdlIGluIGNvbnRlbnRcbiAqXHJcbiAqIEBwYXJhbSBtZXNzYWdlXHRcdFx0XHRNZXNzYWdlIEhUTUxcclxuICogQHBhcmFtIHBhcmFtcyA9IHtcclxuICpcdFx0XHRcdFx0XHRcdFx0J3R5cGUnICAgICA6ICd3YXJuaW5nJyxcdFx0XHRcdFx0XHRcdC8vICdlcnJvcicgfCAnd2FybmluZycgfCAnaW5mbycgfCAnc3VjY2VzcydcclxuICpcdFx0XHRcdFx0XHRcdFx0J3Nob3dfaGVyZScgOiB7XHJcbiAqXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnanFfbm9kZScgOiAnJyxcdFx0XHRcdC8vIGFueSBqUXVlcnkgbm9kZSBkZWZpbml0aW9uXHJcbiAqXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnd2hlcmUnICAgOiAnaW5zaWRlJ1x0XHQvLyAnaW5zaWRlJyB8ICdiZWZvcmUnIHwgJ2FmdGVyJyB8ICdyaWdodCcgfCAnbGVmdCdcclxuICpcdFx0XHRcdFx0XHRcdFx0XHRcdFx0ICB9LFxyXG4gKlx0XHRcdFx0XHRcdFx0XHQnaXNfYXBwZW5kJzogdHJ1ZSxcdFx0XHRcdFx0XHRcdFx0Ly8gQXBwbHkgIG9ubHkgaWYgXHQnd2hlcmUnICAgOiAnaW5zaWRlJ1xyXG4gKlx0XHRcdFx0XHRcdFx0XHQnc3R5bGUnICAgIDogJ3RleHQtYWxpZ246bGVmdDsnLFx0XHRcdFx0Ly8gc3R5bGVzLCBpZiBuZWVkZWRcclxuICpcdFx0XHRcdFx0XHRcdCAgICAnY3NzX2NsYXNzJzogJycsXHRcdFx0XHRcdFx0XHRcdC8vIEZvciBleGFtcGxlIGNhbiAgYmU6ICd3cGJjX2ZlX21lc3NhZ2VfYWx0J1xyXG4gKlx0XHRcdFx0XHRcdFx0XHQnZGVsYXknICAgIDogMCxcdFx0XHRcdFx0XHRcdFx0XHQvLyBob3cgbWFueSBtaWNyb3NlY29uZCB0byAgc2hvdywgIGlmIDAgIHRoZW4gIHNob3cgZm9yZXZlclxyXG4gKlx0XHRcdFx0XHRcdFx0XHQnaWZfdmlzaWJsZV9ub3Rfc2hvdyc6IGZhbHNlXHRcdFx0XHRcdC8vIGlmIHRydWUsICB0aGVuIGRvIG5vdCBzaG93IG1lc3NhZ2UsICBpZiBwcmV2aW9zIG1lc3NhZ2Ugd2FzIG5vdCBoaWRlZCAobm90IGFwcGx5IGlmICd3aGVyZScgICA6ICdpbnNpZGUnIClcclxuICpcdFx0XHRcdH07XHJcbiAqIEV4YW1wbGVzOlxyXG4gKiBcdFx0XHR2YXIgaHRtbF9pZCA9IHdwYmNfZnJvbnRfZW5kX19zaG93X21lc3NhZ2UoICdZb3UgY2FuIHRlc3QgZGF5cyBzZWxlY3Rpb24gaW4gY2FsZW5kYXInLCB7fSApO1xyXG4gKlxyXG4gKlx0XHRcdHZhciBub3RpY2VfbWVzc2FnZV9pZCA9IHdwYmNfZnJvbnRfZW5kX19zaG93X21lc3NhZ2UoIF93cGJjLmdldF9tZXNzYWdlKCAnbWVzc2FnZV9jaGVja19yZXF1aXJlZCcgKSwgeyAndHlwZSc6ICd3YXJuaW5nJywgJ2RlbGF5JzogMTAwMDAsICdpZl92aXNpYmxlX25vdF9zaG93JzogdHJ1ZSxcclxuICpcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCAgJ3Nob3dfaGVyZSc6IHsnd2hlcmUnOiAncmlnaHQnLCAnanFfbm9kZSc6IGVsLH0gfSApO1xyXG4gKlxyXG4gKlx0XHRcdHdwYmNfZnJvbnRfZW5kX19zaG93X21lc3NhZ2UoIHJlc3BvbnNlX2RhdGFbICdhanhfZGF0YScgXVsgJ2FqeF9hZnRlcl9hY3Rpb25fbWVzc2FnZScgXS5yZXBsYWNlKCAvXFxuL2csIFwiPGJyIC8+XCIgKSxcclxuICpcdFx0XHRcdFx0XHRcdFx0XHRcdFx0eyAgICd0eXBlJyAgICAgOiAoICd1bmRlZmluZWQnICE9PSB0eXBlb2YoIHJlc3BvbnNlX2RhdGFbICdhanhfZGF0YScgXVsgJ2FqeF9hZnRlcl9hY3Rpb25fbWVzc2FnZV9zdGF0dXMnIF0gKSApXHJcbiAqXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0ICA/IHJlc3BvbnNlX2RhdGFbICdhanhfZGF0YScgXVsgJ2FqeF9hZnRlcl9hY3Rpb25fbWVzc2FnZV9zdGF0dXMnIF0gOiAnaW5mbycsXHJcbiAqXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J3Nob3dfaGVyZSc6IHsnanFfbm9kZSc6IGpxX25vZGUsICd3aGVyZSc6ICdhZnRlcid9LFxyXG4gKlx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCdjc3NfY2xhc3MnOid3cGJjX2ZlX21lc3NhZ2VfYWx0JyxcclxuICpcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnZGVsYXknICAgIDogMTAwMDBcclxuICpcdFx0XHRcdFx0XHRcdFx0XHRcdFx0fSApO1xyXG4gKlxyXG4gKlxyXG4gKiBAcmV0dXJucyBzdHJpbmcgIC0gSFRNTCBJRFx0XHRvciAwIGlmIG5vdCBzaG93aW5nIGR1cmluZyB0aGlzIHRpbWUuXHJcbiAqL1xyXG5mdW5jdGlvbiB3cGJjX2Zyb250X2VuZF9fc2hvd19tZXNzYWdlKCBtZXNzYWdlLCBwYXJhbXMgPSB7fSApe1xyXG5cclxuXHR2YXIgcGFyYW1zX2RlZmF1bHQgPSB7XHJcblx0XHRcdFx0XHRcdFx0XHQndHlwZScgICAgIDogJ3dhcm5pbmcnLFx0XHRcdFx0XHRcdFx0Ly8gJ2Vycm9yJyB8ICd3YXJuaW5nJyB8ICdpbmZvJyB8ICdzdWNjZXNzJ1xyXG5cdFx0XHRcdFx0XHRcdFx0J3Nob3dfaGVyZScgOiB7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J2pxX25vZGUnIDogJycsXHRcdFx0XHQvLyBhbnkgalF1ZXJ5IG5vZGUgZGVmaW5pdGlvblxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCd3aGVyZScgICA6ICdpbnNpZGUnXHRcdC8vICdpbnNpZGUnIHwgJ2JlZm9yZScgfCAnYWZ0ZXInIHwgJ3JpZ2h0JyB8ICdsZWZ0J1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0ICB9LFxyXG5cdFx0XHRcdFx0XHRcdFx0J2lzX2FwcGVuZCc6IHRydWUsXHRcdFx0XHRcdFx0XHRcdC8vIEFwcGx5ICBvbmx5IGlmIFx0J3doZXJlJyAgIDogJ2luc2lkZSdcclxuXHRcdFx0XHRcdFx0XHRcdCdzdHlsZScgICAgOiAndGV4dC1hbGlnbjpsZWZ0OycsXHRcdFx0XHQvLyBzdHlsZXMsIGlmIG5lZWRlZFxyXG5cdFx0XHRcdFx0XHRcdCAgICAnY3NzX2NsYXNzJzogJycsXHRcdFx0XHRcdFx0XHRcdC8vIEZvciBleGFtcGxlIGNhbiAgYmU6ICd3cGJjX2ZlX21lc3NhZ2VfYWx0J1xyXG5cdFx0XHRcdFx0XHRcdFx0J2RlbGF5JyAgICA6IDAsXHRcdFx0XHRcdFx0XHRcdFx0Ly8gaG93IG1hbnkgbWljcm9zZWNvbmQgdG8gIHNob3csICBpZiAwICB0aGVuICBzaG93IGZvcmV2ZXJcblx0XHRcdFx0XHRcdFx0XHQnaWZfdmlzaWJsZV9ub3Rfc2hvdyc6IGZhbHNlLFx0XHRcdFx0XHQvLyBpZiB0cnVlLCAgdGhlbiBkbyBub3Qgc2hvdyBtZXNzYWdlLCAgaWYgcHJldmlvcyBtZXNzYWdlIHdhcyBub3QgaGlkZWQgKG5vdCBhcHBseSBpZiAnd2hlcmUnICAgOiAnaW5zaWRlJyApXG5cdFx0XHRcdFx0XHRcdFx0J2lzX3Njcm9sbCc6IHRydWUsXHRcdFx0XHRcdFx0XHRcdC8vIGlzIHNjcm9sbCAgdG8gIHRoaXMgZWxlbWVudFxuXHRcdFx0XHRcdFx0XHRcdCdjb250ZW50X21vZGUnOiAnaHRtbCdcdFx0XHRcdFx0XHRcdC8vICdodG1sJyBmb3IgdHJ1c3RlZCBsZWdhY3kgY29udGVudCB8ICd0ZXh0JyBmb3IgZWRpdGFibGUvdXNlciBjb250ZW50XG5cdFx0XHRcdFx0XHR9O1xyXG5cdGZvciAoIHZhciBwX2tleSBpbiBwYXJhbXMgKXtcclxuXHRcdHBhcmFtc19kZWZhdWx0WyBwX2tleSBdID0gcGFyYW1zWyBwX2tleSBdO1xyXG5cdH1cclxuXHRwYXJhbXMgPSBwYXJhbXNfZGVmYXVsdDtcblxuXHRpZiAoICd0ZXh0JyA9PT0gcGFyYW1zWyAnY29udGVudF9tb2RlJyBdICkge1xuXHRcdG1lc3NhZ2UgPSBqUXVlcnkoICc8ZGl2PicgKS50ZXh0KCBudWxsID09PSBtZXNzYWdlIHx8ICd1bmRlZmluZWQnID09PSB0eXBlb2YgbWVzc2FnZSA/ICcnIDogU3RyaW5nKCBtZXNzYWdlICkgKS5odG1sKCkucmVwbGFjZSggL1xcbi9nLCAnPGJyIC8+JyApO1xuXHR9XG5cclxuICAgIHZhciB1bmlxdWVfZGl2X2lkID0gbmV3IERhdGUoKTtcclxuICAgIHVuaXF1ZV9kaXZfaWQgPSAnd3BiY19ub3RpY2VfJyArIHVuaXF1ZV9kaXZfaWQuZ2V0VGltZSgpO1xyXG5cclxuXHRwYXJhbXNbJ2Nzc19jbGFzcyddICs9ICcgd3BiY19mZV9tZXNzYWdlJztcclxuXHRpZiAoIHBhcmFtc1sndHlwZSddID09ICdlcnJvcicgKXtcclxuXHRcdHBhcmFtc1snY3NzX2NsYXNzJ10gKz0gJyB3cGJjX2ZlX21lc3NhZ2VfZXJyb3InO1xyXG5cdFx0bWVzc2FnZSA9ICc8aSBjbGFzcz1cIm1lbnVfaWNvbiBpY29uLTF4IHdwYmNfaWNuX3JlcG9ydF9nbWFpbGVycm9ycmVkXCI+PC9pPicgKyBtZXNzYWdlO1xyXG5cdH1cclxuXHRpZiAoIHBhcmFtc1sndHlwZSddID09ICd3YXJuaW5nJyApe1xyXG5cdFx0cGFyYW1zWydjc3NfY2xhc3MnXSArPSAnIHdwYmNfZmVfbWVzc2FnZV93YXJuaW5nJztcclxuXHRcdG1lc3NhZ2UgPSAnPGkgY2xhc3M9XCJtZW51X2ljb24gaWNvbi0xeCB3cGJjX2ljbl93YXJuaW5nXCI+PC9pPicgKyBtZXNzYWdlO1xyXG5cdH1cclxuXHRpZiAoIHBhcmFtc1sndHlwZSddID09ICdpbmZvJyApe1xyXG5cdFx0cGFyYW1zWydjc3NfY2xhc3MnXSArPSAnIHdwYmNfZmVfbWVzc2FnZV9pbmZvJztcclxuXHR9XHJcblx0aWYgKCBwYXJhbXNbJ3R5cGUnXSA9PSAnc3VjY2VzcycgKXtcclxuXHRcdHBhcmFtc1snY3NzX2NsYXNzJ10gKz0gJyB3cGJjX2ZlX21lc3NhZ2Vfc3VjY2Vzcyc7XHJcblx0XHRtZXNzYWdlID0gJzxpIGNsYXNzPVwibWVudV9pY29uIGljb24tMXggd3BiY19pY25fZG9uZV9vdXRsaW5lXCI+PC9pPicgKyBtZXNzYWdlO1xyXG5cdH1cclxuXHJcblx0dmFyIHNjcm9sbF90b19lbGVtZW50ID0gJzxkaXYgaWQ9XCInICsgdW5pcXVlX2Rpdl9pZCArICdfc2Nyb2xsXCIgc3R5bGU9XCJkaXNwbGF5Om5vbmU7XCI+PC9kaXY+JztcclxuXHRtZXNzYWdlID0gJzxkaXYgaWQ9XCInICsgdW5pcXVlX2Rpdl9pZCArICdcIiBjbGFzcz1cIndwYmNfZnJvbnRfZW5kX19tZXNzYWdlICcgKyBwYXJhbXNbJ2Nzc19jbGFzcyddICsgJ1wiIHN0eWxlPVwiJyArIHBhcmFtc1sgJ3N0eWxlJyBdICsgJ1wiPicgKyBtZXNzYWdlICsgJzwvZGl2Pic7XHJcblxyXG5cclxuXHR2YXIganFfZWxfbWVzc2FnZSA9IGZhbHNlO1xyXG5cdHZhciBpc19zaG93X21lc3NhZ2UgPSB0cnVlO1xyXG5cclxuXHRpZiAoICdpbnNpZGUnID09PSBwYXJhbXNbICdzaG93X2hlcmUnIF1bICd3aGVyZScgXSApe1xyXG5cclxuXHRcdGlmICggcGFyYW1zWyAnaXNfYXBwZW5kJyBdICl7XHJcblx0XHRcdGpRdWVyeSggcGFyYW1zWyAnc2hvd19oZXJlJyBdWyAnanFfbm9kZScgXSApLmFwcGVuZCggc2Nyb2xsX3RvX2VsZW1lbnQgKTtcclxuXHRcdFx0alF1ZXJ5KCBwYXJhbXNbICdzaG93X2hlcmUnIF1bICdqcV9ub2RlJyBdICkuYXBwZW5kKCBtZXNzYWdlICk7XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHRqUXVlcnkoIHBhcmFtc1sgJ3Nob3dfaGVyZScgXVsgJ2pxX25vZGUnIF0gKS5odG1sKCBzY3JvbGxfdG9fZWxlbWVudCArIG1lc3NhZ2UgKTtcclxuXHRcdH1cclxuXHJcblx0fSBlbHNlIGlmICggJ2JlZm9yZScgPT09IHBhcmFtc1sgJ3Nob3dfaGVyZScgXVsgJ3doZXJlJyBdICl7XHJcblxyXG5cdFx0anFfZWxfbWVzc2FnZSA9IGpRdWVyeSggcGFyYW1zWyAnc2hvd19oZXJlJyBdWyAnanFfbm9kZScgXSApLnNpYmxpbmdzKCAnW2lkXj1cIndwYmNfbm90aWNlX1wiXScgKTtcclxuXHRcdGlmICggKHBhcmFtc1sgJ2lmX3Zpc2libGVfbm90X3Nob3cnIF0pICYmIChqcV9lbF9tZXNzYWdlLmlzKCAnOnZpc2libGUnICkpICl7XHJcblx0XHRcdGlzX3Nob3dfbWVzc2FnZSA9IGZhbHNlO1xyXG5cdFx0XHR1bmlxdWVfZGl2X2lkID0galF1ZXJ5KCBqcV9lbF9tZXNzYWdlLmdldCggMCApICkuYXR0ciggJ2lkJyApO1xyXG5cdFx0fVxyXG5cdFx0aWYgKCBpc19zaG93X21lc3NhZ2UgKXtcclxuXHRcdFx0alF1ZXJ5KCBwYXJhbXNbICdzaG93X2hlcmUnIF1bICdqcV9ub2RlJyBdICkuYmVmb3JlKCBzY3JvbGxfdG9fZWxlbWVudCApO1xyXG5cdFx0XHRqUXVlcnkoIHBhcmFtc1sgJ3Nob3dfaGVyZScgXVsgJ2pxX25vZGUnIF0gKS5iZWZvcmUoIG1lc3NhZ2UgKTtcclxuXHRcdH1cclxuXHJcblx0fSBlbHNlIGlmICggJ2FmdGVyJyA9PT0gcGFyYW1zWyAnc2hvd19oZXJlJyBdWyAnd2hlcmUnIF0gKXtcclxuXHJcblx0XHRqcV9lbF9tZXNzYWdlID0galF1ZXJ5KCBwYXJhbXNbICdzaG93X2hlcmUnIF1bICdqcV9ub2RlJyBdICkubmV4dEFsbCggJ1tpZF49XCJ3cGJjX25vdGljZV9cIl0nICk7XHJcblx0XHRpZiAoIChwYXJhbXNbICdpZl92aXNpYmxlX25vdF9zaG93JyBdKSAmJiAoanFfZWxfbWVzc2FnZS5pcyggJzp2aXNpYmxlJyApKSApe1xyXG5cdFx0XHRpc19zaG93X21lc3NhZ2UgPSBmYWxzZTtcclxuXHRcdFx0dW5pcXVlX2Rpdl9pZCA9IGpRdWVyeSgganFfZWxfbWVzc2FnZS5nZXQoIDAgKSApLmF0dHIoICdpZCcgKTtcclxuXHRcdH1cclxuXHRcdGlmICggaXNfc2hvd19tZXNzYWdlICl7XHJcblx0XHRcdGpRdWVyeSggcGFyYW1zWyAnc2hvd19oZXJlJyBdWyAnanFfbm9kZScgXSApLmJlZm9yZSggc2Nyb2xsX3RvX2VsZW1lbnQgKTtcdFx0Ly8gV2UgbmVlZCB0byAgc2V0ICBoZXJlIGJlZm9yZShmb3IgaGFuZHkgc2Nyb2xsKVxyXG5cdFx0XHRqUXVlcnkoIHBhcmFtc1sgJ3Nob3dfaGVyZScgXVsgJ2pxX25vZGUnIF0gKS5hZnRlciggbWVzc2FnZSApO1xyXG5cdFx0fVxyXG5cclxuXHR9IGVsc2UgaWYgKCAncmlnaHQnID09PSBwYXJhbXNbICdzaG93X2hlcmUnIF1bICd3aGVyZScgXSApe1xyXG5cclxuXHRcdGpxX2VsX21lc3NhZ2UgPSBqUXVlcnkoIHBhcmFtc1sgJ3Nob3dfaGVyZScgXVsgJ2pxX25vZGUnIF0gKS5uZXh0QWxsKCAnLndwYmNfZnJvbnRfZW5kX19tZXNzYWdlX2NvbnRhaW5lcl9yaWdodCcgKS5maW5kKCAnW2lkXj1cIndwYmNfbm90aWNlX1wiXScgKTtcclxuXHRcdGlmICggKHBhcmFtc1sgJ2lmX3Zpc2libGVfbm90X3Nob3cnIF0pICYmIChqcV9lbF9tZXNzYWdlLmlzKCAnOnZpc2libGUnICkpICl7XHJcblx0XHRcdGlzX3Nob3dfbWVzc2FnZSA9IGZhbHNlO1xyXG5cdFx0XHR1bmlxdWVfZGl2X2lkID0galF1ZXJ5KCBqcV9lbF9tZXNzYWdlLmdldCggMCApICkuYXR0ciggJ2lkJyApO1xyXG5cdFx0fVxyXG5cdFx0aWYgKCBpc19zaG93X21lc3NhZ2UgKXtcclxuXHRcdFx0alF1ZXJ5KCBwYXJhbXNbICdzaG93X2hlcmUnIF1bICdqcV9ub2RlJyBdICkuYmVmb3JlKCBzY3JvbGxfdG9fZWxlbWVudCApO1x0XHQvLyBXZSBuZWVkIHRvICBzZXQgIGhlcmUgYmVmb3JlKGZvciBoYW5keSBzY3JvbGwpXHJcblx0XHRcdGpRdWVyeSggcGFyYW1zWyAnc2hvd19oZXJlJyBdWyAnanFfbm9kZScgXSApLmFmdGVyKCAnPGRpdiBjbGFzcz1cIndwYmNfZnJvbnRfZW5kX19tZXNzYWdlX2NvbnRhaW5lcl9yaWdodFwiPicgKyBtZXNzYWdlICsgJzwvZGl2PicgKTtcclxuXHRcdH1cclxuXHR9IGVsc2UgaWYgKCAnbGVmdCcgPT09IHBhcmFtc1sgJ3Nob3dfaGVyZScgXVsgJ3doZXJlJyBdICl7XHJcblxyXG5cdFx0anFfZWxfbWVzc2FnZSA9IGpRdWVyeSggcGFyYW1zWyAnc2hvd19oZXJlJyBdWyAnanFfbm9kZScgXSApLnNpYmxpbmdzKCAnLndwYmNfZnJvbnRfZW5kX19tZXNzYWdlX2NvbnRhaW5lcl9sZWZ0JyApLmZpbmQoICdbaWRePVwid3BiY19ub3RpY2VfXCJdJyApO1xyXG5cdFx0aWYgKCAocGFyYW1zWyAnaWZfdmlzaWJsZV9ub3Rfc2hvdycgXSkgJiYgKGpxX2VsX21lc3NhZ2UuaXMoICc6dmlzaWJsZScgKSkgKXtcclxuXHRcdFx0aXNfc2hvd19tZXNzYWdlID0gZmFsc2U7XHJcblx0XHRcdHVuaXF1ZV9kaXZfaWQgPSBqUXVlcnkoIGpxX2VsX21lc3NhZ2UuZ2V0KCAwICkgKS5hdHRyKCAnaWQnICk7XHJcblx0XHR9XHJcblx0XHRpZiAoIGlzX3Nob3dfbWVzc2FnZSApe1xyXG5cdFx0XHRqUXVlcnkoIHBhcmFtc1sgJ3Nob3dfaGVyZScgXVsgJ2pxX25vZGUnIF0gKS5iZWZvcmUoIHNjcm9sbF90b19lbGVtZW50ICk7XHRcdC8vIFdlIG5lZWQgdG8gIHNldCAgaGVyZSBiZWZvcmUoZm9yIGhhbmR5IHNjcm9sbClcclxuXHRcdFx0alF1ZXJ5KCBwYXJhbXNbICdzaG93X2hlcmUnIF1bICdqcV9ub2RlJyBdICkuYmVmb3JlKCAnPGRpdiBjbGFzcz1cIndwYmNfZnJvbnRfZW5kX19tZXNzYWdlX2NvbnRhaW5lcl9sZWZ0XCI+JyArIG1lc3NhZ2UgKyAnPC9kaXY+JyApO1xyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0aWYgKCAgICggaXNfc2hvd19tZXNzYWdlICkgICYmICAoIHBhcnNlSW50KCBwYXJhbXNbICdkZWxheScgXSApID4gMCApICAgKXtcclxuXHRcdHZhciBjbG9zZWRfdGltZXIgPSBzZXRUaW1lb3V0KCBmdW5jdGlvbiAoKXtcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRqUXVlcnkoICcjJyArIHVuaXF1ZV9kaXZfaWQgKS5mYWRlT3V0KCAxNTAwICk7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0fSAsIHBhcnNlSW50KCBwYXJhbXNbICdkZWxheScgXSApICAgKTtcclxuXHJcblx0XHR2YXIgY2xvc2VkX3RpbWVyMiA9IHNldFRpbWVvdXQoIGZ1bmN0aW9uICgpe1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0alF1ZXJ5KCAnIycgKyB1bmlxdWVfZGl2X2lkICkudHJpZ2dlciggJ2hpZGUnICk7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0fSwgKCBwYXJzZUludCggcGFyYW1zWyAnZGVsYXknIF0gKSArIDE1MDEgKSApO1xyXG5cdH1cclxuXHJcblx0Ly8gQ2hlY2sgIGlmIHNob3dlZCBtZXNzYWdlIGluIHNvbWUgaGlkZGVuIHBhcmVudCBzZWN0aW9uIGFuZCBzaG93IGl0LiBCdXQgaXQgbXVzdCAgYmUgbG93ZXIgdGhhbiAnLndwYmNfY29udGFpbmVyJ1xyXG5cdHZhciBwYXJlbnRfZWxzID0galF1ZXJ5KCAnIycgKyB1bmlxdWVfZGl2X2lkICkucGFyZW50cygpLm1hcCggZnVuY3Rpb24gKCl7XHJcblx0XHRpZiAoICghalF1ZXJ5KCB0aGlzICkuaXMoICd2aXNpYmxlJyApKSAmJiAoalF1ZXJ5KCAnLndwYmNfY29udGFpbmVyJyApLmhhcyggdGhpcyApKSApe1xyXG5cdFx0XHRqUXVlcnkoIHRoaXMgKS5zaG93KCk7XHJcblx0XHR9XHJcblx0fSApO1xyXG5cclxuXHRpZiAoIHBhcmFtc1sgJ2lzX3Njcm9sbCcgXSApe1xyXG5cdFx0d3BiY19kb19zY3JvbGwoICcjJyArIHVuaXF1ZV9kaXZfaWQgKyAnX3Njcm9sbCcgKTtcclxuXHR9XHJcblxyXG5cdHJldHVybiB1bmlxdWVfZGl2X2lkO1xyXG59XHJcblxyXG5cclxuXHQvKipcclxuXHQgKiBFcnJvciBtZXNzYWdlLiBcdFByZXNldCBvZiBwYXJhbWV0ZXJzIGZvciByZWFsIG1lc3NhZ2UgZnVuY3Rpb24uXHJcblx0ICpcclxuXHQgKiBAcGFyYW0gZWxcdFx0LSBhbnkgalF1ZXJ5IG5vZGUgZGVmaW5pdGlvblxyXG5cdCAqIEBwYXJhbSBtZXNzYWdlXHQtIE1lc3NhZ2UgSFRNTFxyXG5cdCAqIEByZXR1cm5zIHN0cmluZyAgLSBIVE1MIElEXHRcdG9yIDAgaWYgbm90IHNob3dpbmcgZHVyaW5nIHRoaXMgdGltZS5cclxuXHQgKi9cclxuXHRmdW5jdGlvbiB3cGJjX2Zyb250X2VuZF9fc2hvd19tZXNzYWdlX19lcnJvcigganFfbm9kZSwgbWVzc2FnZSwgY29udGVudF9tb2RlICl7XG5cblx0XHRjb250ZW50X21vZGUgPSAoICd1bmRlZmluZWQnID09PSB0eXBlb2YgY29udGVudF9tb2RlICkgPyAnaHRtbCcgOiBjb250ZW50X21vZGU7XG5cclxuXHRcdHZhciBub3RpY2VfbWVzc2FnZV9pZCA9IHdwYmNfZnJvbnRfZW5kX19zaG93X21lc3NhZ2UoXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0bWVzc2FnZSxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHR7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQndHlwZScgICAgICAgICAgICAgICA6ICdlcnJvcicsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnZGVsYXknICAgICAgICAgICAgICA6IDEwMDAwLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCdpZl92aXNpYmxlX25vdF9zaG93JzogdHJ1ZSxcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J2NvbnRlbnRfbW9kZScgICAgICAgOiBjb250ZW50X21vZGUsXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J3Nob3dfaGVyZScgICAgICAgICAgOiB7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnd2hlcmUnICA6ICdyaWdodCcsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnanFfbm9kZSc6IGpxX25vZGVcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQgICB9XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0KTtcclxuXHRcdHJldHVybiBub3RpY2VfbWVzc2FnZV9pZDtcclxuXHR9XHJcblxyXG5cclxuXHQvKipcclxuXHQgKiBFcnJvciBtZXNzYWdlIFVOREVSIGVsZW1lbnQuIFx0UHJlc2V0IG9mIHBhcmFtZXRlcnMgZm9yIHJlYWwgbWVzc2FnZSBmdW5jdGlvbi5cclxuXHQgKlxyXG5cdCAqIEBwYXJhbSBlbFx0XHQtIGFueSBqUXVlcnkgbm9kZSBkZWZpbml0aW9uXHJcblx0ICogQHBhcmFtIG1lc3NhZ2VcdC0gTWVzc2FnZSBIVE1MXHJcblx0ICogQHJldHVybnMgc3RyaW5nICAtIEhUTUwgSURcdFx0b3IgMCBpZiBub3Qgc2hvd2luZyBkdXJpbmcgdGhpcyB0aW1lLlxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdwYmNfZnJvbnRfZW5kX19zaG93X21lc3NhZ2VfX2Vycm9yX3VuZGVyX2VsZW1lbnQoIGpxX25vZGUsIG1lc3NhZ2UsIG1lc3NhZ2VfZGVsYXksIGNvbnRlbnRfbW9kZSApe1xuXHJcblx0XHRpZiAoICd1bmRlZmluZWQnID09PSB0eXBlb2YgKG1lc3NhZ2VfZGVsYXkpICl7XG5cdFx0XHRtZXNzYWdlX2RlbGF5ID0gMFxuXHRcdH1cblx0XHRjb250ZW50X21vZGUgPSAoICd1bmRlZmluZWQnID09PSB0eXBlb2YgY29udGVudF9tb2RlICkgPyAnaHRtbCcgOiBjb250ZW50X21vZGU7XG5cclxuXHRcdHZhciBub3RpY2VfbWVzc2FnZV9pZCA9IHdwYmNfZnJvbnRfZW5kX19zaG93X21lc3NhZ2UoXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0bWVzc2FnZSxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHR7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQndHlwZScgICAgICAgICAgICAgICA6ICdlcnJvcicsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnZGVsYXknICAgICAgICAgICAgICA6IG1lc3NhZ2VfZGVsYXksXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J2lmX3Zpc2libGVfbm90X3Nob3cnOiB0cnVlLFxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnY29udGVudF9tb2RlJyAgICAgICA6IGNvbnRlbnRfbW9kZSxcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnc2hvd19oZXJlJyAgICAgICAgICA6IHtcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCd3aGVyZScgIDogJ2FmdGVyJyxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCdqcV9ub2RlJzoganFfbm9kZVxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCAgIH1cclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQpO1xyXG5cdFx0cmV0dXJuIG5vdGljZV9tZXNzYWdlX2lkO1xyXG5cdH1cclxuXHJcblxyXG5cdC8qKlxyXG5cdCAqIEVycm9yIG1lc3NhZ2UgVU5ERVIgZWxlbWVudC4gXHRQcmVzZXQgb2YgcGFyYW1ldGVycyBmb3IgcmVhbCBtZXNzYWdlIGZ1bmN0aW9uLlxyXG5cdCAqXHJcblx0ICogQHBhcmFtIGVsXHRcdC0gYW55IGpRdWVyeSBub2RlIGRlZmluaXRpb25cclxuXHQgKiBAcGFyYW0gbWVzc2FnZVx0LSBNZXNzYWdlIEhUTUxcclxuXHQgKiBAcmV0dXJucyBzdHJpbmcgIC0gSFRNTCBJRFx0XHRvciAwIGlmIG5vdCBzaG93aW5nIGR1cmluZyB0aGlzIHRpbWUuXHJcblx0ICovXHJcblx0ZnVuY3Rpb24gd3BiY19mcm9udF9lbmRfX3Nob3dfbWVzc2FnZV9fZXJyb3JfYWJvdmVfZWxlbWVudCgganFfbm9kZSwgbWVzc2FnZSwgbWVzc2FnZV9kZWxheSwgY29udGVudF9tb2RlICl7XG5cclxuXHRcdGlmICggJ3VuZGVmaW5lZCcgPT09IHR5cGVvZiAobWVzc2FnZV9kZWxheSkgKXtcblx0XHRcdG1lc3NhZ2VfZGVsYXkgPSAxMDAwMFxuXHRcdH1cblx0XHRjb250ZW50X21vZGUgPSAoICd1bmRlZmluZWQnID09PSB0eXBlb2YgY29udGVudF9tb2RlICkgPyAnaHRtbCcgOiBjb250ZW50X21vZGU7XG5cclxuXHRcdHZhciBub3RpY2VfbWVzc2FnZV9pZCA9IHdwYmNfZnJvbnRfZW5kX19zaG93X21lc3NhZ2UoXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0bWVzc2FnZSxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHR7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQndHlwZScgICAgICAgICAgICAgICA6ICdlcnJvcicsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnZGVsYXknICAgICAgICAgICAgICA6IG1lc3NhZ2VfZGVsYXksXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J2lmX3Zpc2libGVfbm90X3Nob3cnOiB0cnVlLFxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnY29udGVudF9tb2RlJyAgICAgICA6IGNvbnRlbnRfbW9kZSxcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnc2hvd19oZXJlJyAgICAgICAgICA6IHtcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCd3aGVyZScgIDogJ2JlZm9yZScsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnanFfbm9kZSc6IGpxX25vZGVcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQgICB9XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0KTtcclxuXHRcdHJldHVybiBub3RpY2VfbWVzc2FnZV9pZDtcclxuXHR9XHJcblxyXG5cclxuXHQvKipcclxuXHQgKiBXYXJuaW5nIG1lc3NhZ2UuIFx0UHJlc2V0IG9mIHBhcmFtZXRlcnMgZm9yIHJlYWwgbWVzc2FnZSBmdW5jdGlvbi5cclxuXHQgKlxyXG5cdCAqIEBwYXJhbSBlbFx0XHQtIGFueSBqUXVlcnkgbm9kZSBkZWZpbml0aW9uXHJcblx0ICogQHBhcmFtIG1lc3NhZ2VcdC0gTWVzc2FnZSBIVE1MXHJcblx0ICogQHJldHVybnMgc3RyaW5nICAtIEhUTUwgSURcdFx0b3IgMCBpZiBub3Qgc2hvd2luZyBkdXJpbmcgdGhpcyB0aW1lLlxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdwYmNfZnJvbnRfZW5kX19zaG93X21lc3NhZ2VfX3dhcm5pbmcoIGpxX25vZGUsIG1lc3NhZ2UsIGNvbnRlbnRfbW9kZSApe1xuXG5cdFx0Y29udGVudF9tb2RlID0gKCAndW5kZWZpbmVkJyA9PT0gdHlwZW9mIGNvbnRlbnRfbW9kZSApID8gJ2h0bWwnIDogY29udGVudF9tb2RlO1xuXHJcblx0XHR2YXIgbm90aWNlX21lc3NhZ2VfaWQgPSB3cGJjX2Zyb250X2VuZF9fc2hvd19tZXNzYWdlKFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdG1lc3NhZ2UsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0e1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J3R5cGUnICAgICAgICAgICAgICAgOiAnd2FybmluZycsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnZGVsYXknICAgICAgICAgICAgICA6IDEwMDAwLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCdpZl92aXNpYmxlX25vdF9zaG93JzogdHJ1ZSxcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J2NvbnRlbnRfbW9kZScgICAgICAgOiBjb250ZW50X21vZGUsXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J3Nob3dfaGVyZScgICAgICAgICAgOiB7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnd2hlcmUnICA6ICdyaWdodCcsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnanFfbm9kZSc6IGpxX25vZGVcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQgICB9XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0KTtcclxuXHRcdHdwYmNfaGlnaGxpZ2h0X2Vycm9yX29uX2Zvcm1fZmllbGQoIGpxX25vZGUgKTtcclxuXHRcdHJldHVybiBub3RpY2VfbWVzc2FnZV9pZDtcclxuXHR9XHJcblxyXG5cclxuXHQvKipcclxuXHQgKiBXYXJuaW5nIG1lc3NhZ2UgVU5ERVIgZWxlbWVudC4gXHRQcmVzZXQgb2YgcGFyYW1ldGVycyBmb3IgcmVhbCBtZXNzYWdlIGZ1bmN0aW9uLlxyXG5cdCAqXHJcblx0ICogQHBhcmFtIGVsXHRcdC0gYW55IGpRdWVyeSBub2RlIGRlZmluaXRpb25cclxuXHQgKiBAcGFyYW0gbWVzc2FnZVx0LSBNZXNzYWdlIEhUTUxcclxuXHQgKiBAcmV0dXJucyBzdHJpbmcgIC0gSFRNTCBJRFx0XHRvciAwIGlmIG5vdCBzaG93aW5nIGR1cmluZyB0aGlzIHRpbWUuXHJcblx0ICovXHJcblx0ZnVuY3Rpb24gd3BiY19mcm9udF9lbmRfX3Nob3dfbWVzc2FnZV9fd2FybmluZ191bmRlcl9lbGVtZW50KCBqcV9ub2RlLCBtZXNzYWdlLCBjb250ZW50X21vZGUgKXtcblxuXHRcdGNvbnRlbnRfbW9kZSA9ICggJ3VuZGVmaW5lZCcgPT09IHR5cGVvZiBjb250ZW50X21vZGUgKSA/ICdodG1sJyA6IGNvbnRlbnRfbW9kZTtcblxyXG5cdFx0dmFyIG5vdGljZV9tZXNzYWdlX2lkID0gd3BiY19mcm9udF9lbmRfX3Nob3dfbWVzc2FnZShcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRtZXNzYWdlLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdHtcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCd0eXBlJyAgICAgICAgICAgICAgIDogJ3dhcm5pbmcnLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J2RlbGF5JyAgICAgICAgICAgICAgOiAxMDAwMCxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnaWZfdmlzaWJsZV9ub3Rfc2hvdyc6IHRydWUsXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCdjb250ZW50X21vZGUnICAgICAgIDogY29udGVudF9tb2RlLFxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCdzaG93X2hlcmUnICAgICAgICAgIDoge1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J3doZXJlJyAgOiAnYWZ0ZXInLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J2pxX25vZGUnOiBqcV9ub2RlXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0ICAgfVxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCk7XHJcblx0XHRyZXR1cm4gbm90aWNlX21lc3NhZ2VfaWQ7XHJcblx0fVxyXG5cclxuXHJcblx0LyoqXHJcblx0ICogV2FybmluZyBtZXNzYWdlIEFCT1ZFIGVsZW1lbnQuIFx0UHJlc2V0IG9mIHBhcmFtZXRlcnMgZm9yIHJlYWwgbWVzc2FnZSBmdW5jdGlvbi5cclxuXHQgKlxyXG5cdCAqIEBwYXJhbSBlbFx0XHQtIGFueSBqUXVlcnkgbm9kZSBkZWZpbml0aW9uXHJcblx0ICogQHBhcmFtIG1lc3NhZ2VcdC0gTWVzc2FnZSBIVE1MXHJcblx0ICogQHJldHVybnMgc3RyaW5nICAtIEhUTUwgSURcdFx0b3IgMCBpZiBub3Qgc2hvd2luZyBkdXJpbmcgdGhpcyB0aW1lLlxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdwYmNfZnJvbnRfZW5kX19zaG93X21lc3NhZ2VfX3dhcm5pbmdfYWJvdmVfZWxlbWVudCgganFfbm9kZSwgbWVzc2FnZSwgY29udGVudF9tb2RlICl7XG5cblx0XHRjb250ZW50X21vZGUgPSAoICd1bmRlZmluZWQnID09PSB0eXBlb2YgY29udGVudF9tb2RlICkgPyAnaHRtbCcgOiBjb250ZW50X21vZGU7XG5cclxuXHRcdHZhciBub3RpY2VfbWVzc2FnZV9pZCA9IHdwYmNfZnJvbnRfZW5kX19zaG93X21lc3NhZ2UoXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0bWVzc2FnZSxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHR7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQndHlwZScgICAgICAgICAgICAgICA6ICd3YXJuaW5nJyxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCdkZWxheScgICAgICAgICAgICAgIDogMTAwMDAsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J2lmX3Zpc2libGVfbm90X3Nob3cnOiB0cnVlLFxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnY29udGVudF9tb2RlJyAgICAgICA6IGNvbnRlbnRfbW9kZSxcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnc2hvd19oZXJlJyAgICAgICAgICA6IHtcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCd3aGVyZScgIDogJ2JlZm9yZScsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnanFfbm9kZSc6IGpxX25vZGVcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQgICB9XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0KTtcclxuXHRcdHJldHVybiBub3RpY2VfbWVzc2FnZV9pZDtcclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIEhpZ2hsaWdodCBFcnJvciBpbiBzcGVjaWZpYyBmaWVsZFxyXG5cdCAqXHJcblx0ICogQHBhcmFtIGpxX25vZGVcdFx0XHRcdFx0c3RyaW5nIG9yIGpRdWVyeSBlbGVtZW50LCAgd2hlcmUgc2Nyb2xsICB0b1xyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdwYmNfaGlnaGxpZ2h0X2Vycm9yX29uX2Zvcm1fZmllbGQoIGpxX25vZGUgKXtcclxuXHJcblx0XHRpZiAoICFqUXVlcnkoIGpxX25vZGUgKS5sZW5ndGggKXtcclxuXHRcdFx0cmV0dXJuO1xyXG5cdFx0fVxyXG5cdFx0aWYgKCAhIGpRdWVyeSgganFfbm9kZSApLmlzKCAnOmlucHV0JyApICl7XHJcblx0XHRcdC8vIFNpdHVhdGlvbiB3aXRoICBjaGVja2JveGVzIG9yIHJhZGlvICBidXR0b25zXHJcblx0XHRcdHZhciBqcV9ub2RlX2FyciA9IGpRdWVyeSgganFfbm9kZSApLmZpbmQoICc6aW5wdXQnICk7XHJcblx0XHRcdGlmICggIWpxX25vZGVfYXJyLmxlbmd0aCApe1xyXG5cdFx0XHRcdHJldHVyblxyXG5cdFx0XHR9XHJcblx0XHRcdGpxX25vZGUgPSBqcV9ub2RlX2Fyci5nZXQoIDAgKTtcclxuXHRcdH1cclxuXHRcdHZhciBwYXJhbXMgPSB7fTtcclxuXHRcdHBhcmFtc1sgJ2RlbGF5JyBdID0gMTAwMDA7XHJcblxyXG5cdFx0aWYgKCAhalF1ZXJ5KCBqcV9ub2RlICkuaGFzQ2xhc3MoICd3cGJjX2Zvcm1fZmllbGRfZXJyb3InICkgKXtcclxuXHJcblx0XHRcdGpRdWVyeSgganFfbm9kZSApLmFkZENsYXNzKCAnd3BiY19mb3JtX2ZpZWxkX2Vycm9yJyApXHJcblxyXG5cdFx0XHRpZiAoIHBhcnNlSW50KCBwYXJhbXNbICdkZWxheScgXSApID4gMCApe1xyXG5cdFx0XHRcdHZhciBjbG9zZWRfdGltZXIgPSBzZXRUaW1lb3V0KCBmdW5jdGlvbiAoKXtcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0IGpRdWVyeSgganFfbm9kZSApLnJlbW92ZUNsYXNzKCAnd3BiY19mb3JtX2ZpZWxkX2Vycm9yJyApO1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0ICB9XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHQgICAsIHBhcnNlSW50KCBwYXJhbXNbICdkZWxheScgXSApXHJcblx0XHRcdFx0XHRcdFx0XHRcdCk7XHJcblxyXG5cdFx0XHR9XHJcblx0XHR9XHJcblx0fVxyXG5cclxuLyoqXHJcbiAqIFNjcm9sbCB0byBzcGVjaWZpYyBlbGVtZW50XHJcbiAqXHJcbiAqIEBwYXJhbSBqcV9ub2RlXHRcdFx0XHRcdHN0cmluZyBvciBqUXVlcnkgZWxlbWVudCwgIHdoZXJlIHNjcm9sbCAgdG9cclxuICogQHBhcmFtIGV4dHJhX3NoaWZ0X29mZnNldFx0XHRpbnQgc2hpZnQgb2Zmc2V0IGZyb20gIGpxX25vZGVcclxuICovXHJcbmZ1bmN0aW9uIHdwYmNfZG9fc2Nyb2xsKCBqcV9ub2RlICwgZXh0cmFfc2hpZnRfb2Zmc2V0ID0gMCApe1xyXG5cclxuXHRpZiAoICFqUXVlcnkoIGpxX25vZGUgKS5sZW5ndGggKXtcclxuXHRcdHJldHVybjtcclxuXHR9XHJcblx0dmFyIHRhcmdldE9mZnNldCA9IGpRdWVyeSgganFfbm9kZSApLm9mZnNldCgpLnRvcDtcclxuXHJcblx0aWYgKCB0YXJnZXRPZmZzZXQgPD0gMCApe1xyXG5cdFx0aWYgKCAwICE9IGpRdWVyeSgganFfbm9kZSApLm5leHRBbGwoICc6dmlzaWJsZScgKS5sZW5ndGggKXtcclxuXHRcdFx0dGFyZ2V0T2Zmc2V0ID0galF1ZXJ5KCBqcV9ub2RlICkubmV4dEFsbCggJzp2aXNpYmxlJyApLmZpcnN0KCkub2Zmc2V0KCkudG9wO1xyXG5cdFx0fSBlbHNlIGlmICggMCAhPSBqUXVlcnkoIGpxX25vZGUgKS5wYXJlbnQoKS5uZXh0QWxsKCAnOnZpc2libGUnICkubGVuZ3RoICl7XHJcblx0XHRcdHRhcmdldE9mZnNldCA9IGpRdWVyeSgganFfbm9kZSApLnBhcmVudCgpLm5leHRBbGwoICc6dmlzaWJsZScgKS5maXJzdCgpLm9mZnNldCgpLnRvcDtcclxuXHRcdH1cclxuXHR9XHJcblxyXG5cdGlmICggalF1ZXJ5KCAnI3dwYWRtaW5iYXInICkubGVuZ3RoID4gMCApe1xyXG5cdFx0dGFyZ2V0T2Zmc2V0ID0gdGFyZ2V0T2Zmc2V0IC0gNTAgLSA1MDtcclxuXHR9IGVsc2Uge1xyXG5cdFx0dGFyZ2V0T2Zmc2V0ID0gdGFyZ2V0T2Zmc2V0IC0gMjAgLSA1MDtcclxuXHR9XHJcblx0dGFyZ2V0T2Zmc2V0ICs9IGV4dHJhX3NoaWZ0X29mZnNldDtcclxuXHJcblx0Ly8gU2Nyb2xsIG9ubHkgIGlmIHdlIGRpZCBub3Qgc2Nyb2xsIGJlZm9yZVxyXG5cdGlmICggISBqUXVlcnkoICdodG1sLGJvZHknICkuaXMoICc6YW5pbWF0ZWQnICkgKXtcclxuXHRcdGpRdWVyeSggJ2h0bWwsYm9keScgKS5hbmltYXRlKCB7c2Nyb2xsVG9wOiB0YXJnZXRPZmZzZXR9LCA1MDAgKTtcclxuXHR9XHJcbn1cclxuXHJcbiIsIlxyXG4vLyBGaXhJbjogMTAuMi4wLjQuXHJcbi8qKlxyXG4gKiBEZWZpbmUgUG9wb3ZlcnMgZm9yIFRpbWVsaW5lcyBpbiBXUCBCb29raW5nIENhbGVuZGFyXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd8Ym9vbGVhbn1cclxuICovXHJcbmZ1bmN0aW9uIHdwYmNfZGVmaW5lX3RpcHB5X3BvcG92ZXIoKXtcclxuXHRpZiAoICdmdW5jdGlvbicgIT09IHR5cGVvZiAod3BiY190aXBweSkgKXtcclxuXHRcdGNvbnNvbGUubG9nKCAnV1BCQyBFcnJvci4gd3BiY190aXBweSB3YXMgbm90IGRlZmluZWQuJyApO1xyXG5cdFx0cmV0dXJuIGZhbHNlO1xyXG5cdH1cclxuXHR3cGJjX3RpcHB5KCAnLnBvcG92ZXJfYm90dG9tLnBvcG92ZXJfY2xpY2snLCB7XHJcblx0XHRjb250ZW50KCByZWZlcmVuY2UgKXtcclxuXHRcdFx0dmFyIHBvcG92ZXJfdGl0bGUgPSByZWZlcmVuY2UuZ2V0QXR0cmlidXRlKCAnZGF0YS1vcmlnaW5hbC10aXRsZScgKTtcclxuXHRcdFx0dmFyIHBvcG92ZXJfY29udGVudCA9IHJlZmVyZW5jZS5nZXRBdHRyaWJ1dGUoICdkYXRhLWNvbnRlbnQnICk7XHJcblx0XHRcdHJldHVybiAnPGRpdiBjbGFzcz1cInBvcG92ZXIgcG9wb3Zlcl90aXBweVwiPidcclxuXHRcdFx0XHQrICc8ZGl2IGNsYXNzPVwicG9wb3Zlci1jbG9zZVwiPjxhIGhyZWY9XCJqYXZhc2NyaXB0OnZvaWQoMClcIiBvbmNsaWNrPVwiamF2YXNjcmlwdDp0aGlzLnBhcmVudEVsZW1lbnQucGFyZW50RWxlbWVudC5wYXJlbnRFbGVtZW50LnBhcmVudEVsZW1lbnQucGFyZW50RWxlbWVudC5fdGlwcHkuaGlkZSgpO1wiID4mdGltZXM7PC9hPjwvZGl2PidcclxuXHRcdFx0XHQrIHBvcG92ZXJfY29udGVudFxyXG5cdFx0XHRcdCsgJzwvZGl2Pic7XHJcblx0XHR9LFxyXG5cdFx0YWxsb3dIVE1MICAgICAgICA6IHRydWUsXHJcblx0XHR0cmlnZ2VyICAgICAgICAgIDogJ21hbnVhbCcsXHJcblx0XHRpbnRlcmFjdGl2ZSAgICAgIDogdHJ1ZSxcclxuXHRcdGhpZGVPbkNsaWNrICAgICAgOiBmYWxzZSxcclxuXHRcdGludGVyYWN0aXZlQm9yZGVyOiAxMCxcclxuXHRcdG1heFdpZHRoICAgICAgICAgOiA1NTAsXHJcblx0XHR0aGVtZSAgICAgICAgICAgIDogJ3dwYmMtdGlwcHktcG9wb3ZlcicsXHJcblx0XHRwbGFjZW1lbnQgICAgICAgIDogJ2JvdHRvbS1zdGFydCcsXHJcblx0XHR0b3VjaCAgICAgICAgICAgIDogWydob2xkJywgNTAwXSxcclxuXHR9ICk7XHJcblx0alF1ZXJ5KCAnLnBvcG92ZXJfYm90dG9tLnBvcG92ZXJfY2xpY2snICkub24oICdjbGljaycsIGZ1bmN0aW9uICgpe1xyXG5cdFx0aWYgKCB0aGlzLl90aXBweS5zdGF0ZS5pc1Zpc2libGUgKXtcclxuXHRcdFx0dGhpcy5fdGlwcHkuaGlkZSgpO1xyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0dGhpcy5fdGlwcHkuc2hvdygpO1xyXG5cdFx0fVxyXG5cdH0gKTtcclxuXHR3cGJjX2RlZmluZV9oaWRlX3RpcHB5X29uX3Njcm9sbCgpO1xyXG59XHJcblxyXG5cclxuXHJcbmZ1bmN0aW9uIHdwYmNfZGVmaW5lX2hpZGVfdGlwcHlfb25fc2Nyb2xsKCl7XHJcblx0alF1ZXJ5KCAnLmZsZXhfdGxfX3Njcm9sbGluZ19zZWN0aW9uMiwuZmxleF90bF9fc2Nyb2xsaW5nX3NlY3Rpb25zJyApLm9uKCAnc2Nyb2xsJywgZnVuY3Rpb24gKCBldmVudCApe1xyXG5cdFx0aWYgKCAnZnVuY3Rpb24nID09PSB0eXBlb2YgKHdwYmNfdGlwcHkpICl7XHJcblx0XHRcdHdwYmNfdGlwcHkuaGlkZUFsbCgpO1xyXG5cdFx0fVxyXG5cdH0gKTtcclxufVxyXG4iLCIvKipcclxuICogV1BCQyBjYWxlbmRhciBsb2FkZXIgYm9vdHN0cmFwLlxyXG4gKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcbiAqIC0gRmluZHMgZXZlcnkgLmNhbGVuZGFyX2xvYWRlcl9mcmFtZVtkYXRhLXdwYmMtcmlkXSBvbiB0aGUgcGFnZSAobm93IG9yIGxhdGVyKS5cclxuICogLSBGb3IgZWFjaCBsb2FkZXIgZWxlbWVudCwgd2FpdHMgYSBcImdyYWNlXCIgcGVyaW9kIChkYXRhLXdwYmMtZ3JhY2UsIGRlZmF1bHQgODAwMCBtcyk6XHJcbiAqICAgICAtIElmIHRoZSByZWFsIGNhbGVuZGFyIGFwcGVhcnM6IGRvIG5vdGhpbmcgKGxvYWRlciBuYXR1cmFsbHkgcmVwbGFjZWQpLlxyXG4gKiAgICAgLSBJZiBub3Q6IHNob3cgYSBoZWxwZnVsIG1lc3NhZ2UgKG1pc3NpbmcgalF1ZXJ5L193cGJjL2RhdGVwaWNrKSBvciBhIGR1cGxpY2F0ZSBub3RpY2UuXHJcbiAqIC0gV29ya3Mgd2l0aCBtdWx0aXBsZSBjYWxlbmRhcnMgYW5kIGV2ZW4gZHVwbGljYXRlIFJJRHMgb24gdGhlIHNhbWUgcGFnZS5cclxuICogLSBObyBpbmxpbmUgSlMgbmVlZGVkIGluIHRoZSBzaG9ydGNvZGUvdGVtcGxhdGUgb3V0cHV0LlxyXG4gKlxyXG4gKiBGaWxlOiAgLi4vaW5jbHVkZXMvX19qcy9jbGllbnQvY2FsL3dwYmNfY2FsX2xvYWRlci5qc1xyXG4gKlxyXG4gKiBAc2luY2UgICAgMTAuMTQuNVxyXG4gKiBAbW9kaWZpZWQgMjAyNS0wOS0wNyAxMjoyMVxyXG4gKiBAdmVyc2lvbiAgMS4wLjBcclxuICpcclxuICovXHJcbi8qKlxyXG4gKiBXUEJDIGNhbGVuZGFyIGxvYWRlciBib290c3RyYXAuXHJcbiAqIC0gQXV0by1kZXRlY3RzIC5jYWxlbmRhcl9sb2FkZXJfZnJhbWVbZGF0YS13cGJjLXJpZF0gYmxvY2tzLlxyXG4gKiAtIFdhaXRzIGEgXCJncmFjZVwiIHBlcmlvZCBwZXIgZWxlbWVudCBiZWZvcmUgc2hvd2luZyBhIGhlbHBmdWwgbWVzc2FnZVxyXG4gKiAgIGlmIHRoZSByZWFsIGNhbGVuZGFyIGhhc24ndCByZXBsYWNlZCB0aGUgbG9hZGVyLlxyXG4gKiAtIE11bHRpcGxlIGNhbGVuZGFycyBhbmQgZHVwbGljYXRlIFJJRHMgYXJlIGhhbmRsZWQuXHJcbiAqL1xyXG4oZnVuY3Rpb24gKHcsIGQpIHtcclxuXHQndXNlIHN0cmljdCc7XHJcblxyXG5cdC8qIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdCAqIFNtYWxsIHV0aWxpdGllcyAoc25ha2VfY2FzZSlcclxuXHQgKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi9cclxuXHJcblx0LyoqIFRyYWNrIHByb2Nlc3NlZCBsb2FkZXIgZWxlbWVudHM7IGZhbGxiYWNrIHRvIGRhdGEgZmxhZyBpZiBXZWFrU2V0IG1pc3NpbmcuICovXHJcblx0dmFyIHByb2Nlc3NlZF9zZXQgPSB0eXBlb2YgV2Vha1NldCA9PT0gJ2Z1bmN0aW9uJyA/IG5ldyBXZWFrU2V0KCkgOiBudWxsO1xyXG5cclxuXHQvKiogUmV0dXJuIGZpcnN0IG1hdGNoIGluc2lkZSBvcHRpb25hbCByb290LiAqL1xyXG5cdGZ1bmN0aW9uIHF1ZXJ5X29uZShzZWxlY3Rvciwgcm9vdCkge1xyXG5cdFx0cmV0dXJuIChyb290IHx8IGQpLnF1ZXJ5U2VsZWN0b3IoIHNlbGVjdG9yICk7XHJcblx0fVxyXG5cclxuXHQvKiogUmV0dXJuIE5vZGVMaXN0IG9mIG1hdGNoZXMgaW5zaWRlIG9wdGlvbmFsIHJvb3QuICovXHJcblx0ZnVuY3Rpb24gcXVlcnlfYWxsKHNlbGVjdG9yLCByb290KSB7XHJcblx0XHRyZXR1cm4gKHJvb3QgfHwgZCkucXVlcnlTZWxlY3RvckFsbCggc2VsZWN0b3IgKTtcclxuXHR9XHJcblxyXG5cdC8qKiBSdW4gYSBjYWxsYmFjayB3aGVuIERPTSBpcyByZWFkeS4gKi9cclxuXHRmdW5jdGlvbiBvbl9yZWFkeShmbikge1xyXG5cdFx0aWYgKCBkLnJlYWR5U3RhdGUgPT09ICdsb2FkaW5nJyApIHtcclxuXHRcdFx0ZC5hZGRFdmVudExpc3RlbmVyKCAnRE9NQ29udGVudExvYWRlZCcsIGZuICk7XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHRmbigpO1xyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0LyoqIENsZWFyIGludGVydmFsIHNhZmVseS4gKi9cclxuXHRmdW5jdGlvbiBzYWZlX2NsZWFyKGludGVydmFsX2lkKSB7XHJcblx0XHR0cnkge1xyXG5cdFx0XHR3LmNsZWFySW50ZXJ2YWwoIGludGVydmFsX2lkICk7XHJcblx0XHR9IGNhdGNoICggZSApIHtcclxuXHRcdH1cclxuXHR9XHJcblxyXG5cdC8qKiBNYXJrIGVsZW1lbnQgcHJvY2Vzc2VkIChXZWFrU2V0IG9yIGRhdGEgYXR0cmlidXRlKS4gKi9cclxuXHRmdW5jdGlvbiBtYXJrX3Byb2Nlc3NlZChlbCkge1xyXG5cdFx0aWYgKCBwcm9jZXNzZWRfc2V0ICkge1xyXG5cdFx0XHRwcm9jZXNzZWRfc2V0LmFkZCggZWwgKTtcclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdHRyeSB7XHJcblx0XHRcdFx0ZWwuZGF0YXNldC53cGJjUHJvY2Vzc2VkID0gJzEnO1xyXG5cdFx0XHR9IGNhdGNoICggZSApIHtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0LyoqIENoZWNrIGlmIGVsZW1lbnQgd2FzIHByb2Nlc3NlZC4gKi9cclxuXHRmdW5jdGlvbiBpc19wcm9jZXNzZWQoZWwpIHtcclxuXHRcdHJldHVybiBwcm9jZXNzZWRfc2V0ID8gcHJvY2Vzc2VkX3NldC5oYXMoIGVsICkgOiAoZWwgJiYgZWwuZGF0YXNldCAmJiBlbC5kYXRhc2V0LndwYmNQcm9jZXNzZWQgPT09ICcxJyk7XHJcblx0fVxyXG5cclxuXHQvKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblx0ICogTWVzc2FnZXNcblx0ICogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovXG5cblx0LyoqXG5cdCAqIEJ1aWxkIHZpc2l0b3IgbWVzc2FnZXMgZm9yIGEgcmVzb3VyY2UsIHVzaW5nIGxvY2FsaXplZCBGb3JtIE1lc3NhZ2VzIHdoZW4gYXZhaWxhYmxlLlxuXHQgKiBAcGFyYW0ge3N0cmluZ3xudW1iZXJ9IHJpZFxuXHQgKiBAcmV0dXJuIHt7ZHVwbGljYXRlOnN0cmluZyxpbml0X2ZhaWxlZDpzdHJpbmcsc3VwcG9ydDpzdHJpbmcsbGliX2pxOnN0cmluZyxsaWJfZHA6c3RyaW5nLGxpYl93cGJjOnN0cmluZ319XG5cdCAqL1xuXHRmdW5jdGlvbiBnZXRfbWVzc2FnZXMocmlkKSB7XG5cdFx0dmFyIHJpZF9pbnQgICAgICAgICAgPSBwYXJzZUludCggcmlkLCAxMCApO1xuXHRcdHZhciBkdXBsaWNhdGVfbWVzc2FnZSA9XG5cdFx0XHQnTW9yZSB0aGFuIG9uZSBjYWxlbmRhciBvciBib29raW5nIGZvcm0gZm9yIEJvb2tpbmcgUmVzb3VyY2UgSUQge3Jlc291cmNlX2lkfSBpcyBwcmVzZW50IG9uIHRoaXMgcGFnZS4gJyArXG5cdFx0XHQnQSBoaWRkZW4gY29weSBzdGlsbCBjb25mbGljdHMgd2l0aCB0aGUgdmlzaWJsZSBmb3JtIGFuZCBjYW4gcHJldmVudCBib29raW5nIHN1Ym1pc3Npb24uICcgK1xuXHRcdFx0J1RoZSBzaXRlIGFkbWluaXN0cmF0b3IgbXVzdCBrZWVwIG9ubHkgb25lIGNhbGVuZGFyIG9yIGZvcm0gZm9yIHRoaXMgQm9va2luZyBSZXNvdXJjZS4gJyArXG5cdFx0XHQnQWZ0ZXIgdGhlIHBhZ2UgaXMgY29ycmVjdGVkLCByZWxvYWQgaXQgYW5kIHRyeSBhZ2Fpbi4nO1xuXG5cdFx0aWYgKCB3Ll93cGJjICYmIHR5cGVvZiB3Ll93cGJjLmdldF9tZXNzYWdlID09PSAnZnVuY3Rpb24nICkge1xuXHRcdFx0ZHVwbGljYXRlX21lc3NhZ2UgPSB3Ll93cGJjLmdldF9tZXNzYWdlKCAnbWVzc2FnZV9kdXBsaWNhdGVfYm9va2luZ19yZXNvdXJjZV9vbl9wYWdlJyApIHx8IGR1cGxpY2F0ZV9tZXNzYWdlO1xuXHRcdH1cblx0XHRkdXBsaWNhdGVfbWVzc2FnZSA9IFN0cmluZyggZHVwbGljYXRlX21lc3NhZ2UgKS5yZXBsYWNlKCAvXFx7cmVzb3VyY2VfaWRcXH0vZywgU3RyaW5nKCByaWRfaW50ICkgKTtcblxuXHRcdHJldHVybiB7XG5cdFx0XHRkdXBsaWNhdGUgIDogZHVwbGljYXRlX21lc3NhZ2UsXG5cdFx0XHRpbml0X2ZhaWxlZDpcclxuXHRcdFx0XHQnVGhlIGNhbGVuZGFyIGNvdWxkIG5vdCBiZSBpbml0aWFsaXplZCBvbiB0aGlzIHBhZ2UuJyArICdcXG4nICtcclxuXHRcdFx0XHQnUGxlYXNlIGNoZWNrIHlvdXIgYnJvd3NlciBjb25zb2xlIGZvciBKYXZhU2NyaXB0IGVycm9ycyBhbmQgY29uZmxpY3RzIHdpdGggb3RoZXIgc2NyaXB0cy9wbHVnaW5zLicsXHJcblx0XHRcdHN1cHBvcnQgICAgOiAnJywgLyogJ0NvbnRhY3Qgc3VwcG9ydEB3cGJvb2tpbmdjYWxlbmRhci5jb20gaWYgeW91IGhhdmUgYW55IHF1ZXN0aW9ucy4nLCAqL1xyXG5cdFx0XHRsaWJfanEgICAgIDpcclxuXHRcdFx0XHQnSXQgYXBwZWFycyB0aGF0IHRoZSBcImpRdWVyeVwiIGxpYnJhcnkgaXMgbm90IGxvYWRpbmcgY29ycmVjdGx5LicgKyAnXFxuJyArXHJcblx0XHRcdFx0J0ZvciBtb3JlIGluZm9ybWF0aW9uLCBwbGVhc2UgcmVmZXIgdG8gdGhpcyBwYWdlOiBodHRwczovL3dwYm9va2luZ2NhbGVuZGFyLmNvbS9mYXEvJyxcclxuXHRcdFx0bGliX2RwICAgICA6XHJcblx0XHRcdFx0J0l0IGFwcGVhcnMgdGhhdCB0aGUgXCJqUXVlcnkuZGF0ZXBpY2tcIiBsaWJyYXJ5IGlzIG5vdCBsb2FkaW5nIGNvcnJlY3RseS4nICsgJ1xcbicgK1xyXG5cdFx0XHRcdCdGb3IgbW9yZSBpbmZvcm1hdGlvbiwgcGxlYXNlIHJlZmVyIHRvIHRoaXMgcGFnZTogaHR0cHM6Ly93cGJvb2tpbmdjYWxlbmRhci5jb20vZmFxLycsXHJcblx0XHRcdGxpYl93cGJjICAgOlxyXG5cdFx0XHRcdCdJdCBhcHBlYXJzIHRoYXQgdGhlIFwiX3dwYmNcIiBsaWJyYXJ5IGlzIG5vdCBsb2FkaW5nIGNvcnJlY3RseS4nICsgJ1xcbicgK1xyXG5cdFx0XHRcdCdQbGVhc2UgZW5hYmxlIHRoZSBsb2FkaW5nIG9mIEpTL0NTUyBmaWxlcyBmb3IgdGhpcyBwYWdlIG9uIHRoZSBcIldQIEJvb2tpbmcgQ2FsZW5kYXJcIiAtIFwiU2V0dGluZ3MgR2VuZXJhbFwiIC0gXCJBZHZhbmNlZFwiIHBhZ2UnICsgJ1xcbicgK1xyXG5cdFx0XHRcdCdGb3IgbW9yZSBpbmZvcm1hdGlvbiwgcGxlYXNlIHJlZmVyIHRvIHRoaXMgcGFnZTogaHR0cHM6Ly93cGJvb2tpbmdjYWxlbmRhci5jb20vZmFxLydcclxuXHRcdH07XHJcblx0fVxyXG5cclxuXHQvKipcblx0ICogRXNjYXBlIGEgcGxhaW4tdGV4dCBsb2FkZXIgbWVzc2FnZSBiZWZvcmUgaW5zZXJ0aW5nIGl0cyB3cmFwcGVyIG1hcmt1cC5cblx0ICpcblx0ICogQHBhcmFtIHtzdHJpbmd9IHBsYWluX3RleHQgVmlzaXRvci1mYWNpbmcgcGxhaW4gdGV4dC5cblx0ICogQHJldHVybiB7c3RyaW5nfSBIVE1MLXNhZmUgdGV4dC5cblx0ICovXG5cdGZ1bmN0aW9uIGVzY2FwZV9odG1sKHBsYWluX3RleHQpIHtcblx0XHRyZXR1cm4gU3RyaW5nKCBwbGFpbl90ZXh0IHx8ICcnIClcblx0XHRcdC5yZXBsYWNlKCAvJi9nLCAnJmFtcDsnIClcblx0XHRcdC5yZXBsYWNlKCAvPC9nLCAnJmx0OycgKVxuXHRcdFx0LnJlcGxhY2UoIC8+L2csICcmZ3Q7JyApXG5cdFx0XHQucmVwbGFjZSggL1wiL2csICcmcXVvdDsnIClcblx0XHRcdC5yZXBsYWNlKCAvJy9nLCAnJiMwMzk7JyApO1xuXHR9XG5cblx0LyoqXG5cdCAqIFdyYXAgcGxhaW4gdGV4dCAod2l0aCBuZXdsaW5lcykgaW4gYSBzbWFsbCBIVE1MIGNvbnRhaW5lci5cblx0ICogQHBhcmFtIHtzdHJpbmd9IG1zZ1xuXHQgKiBAcmV0dXJuIHtzdHJpbmd9XG5cdCAqL1xuXHRmdW5jdGlvbiB3cmFwX2h0bWwobXNnKSB7XG5cdFx0cmV0dXJuICc8ZGl2IHN0eWxlPVwiZm9udC1zaXplOjEzcHg7bWFyZ2luOjEwcHg7XCI+JyArIGVzY2FwZV9odG1sKCBtc2cgKS5yZXBsYWNlKCAvXFxuL2csICc8YnI+JyApICsgJzwvZGl2Pic7XG5cdH1cblxyXG5cdC8qKiBMaWJyYXJ5IHByZXNlbmNlIGNoZWNrcyAoZmFzdCAmIGNoZWFwKS4gKi9cclxuXHRmdW5jdGlvbiBoYXNfanEoKSB7XHJcblx0XHRyZXR1cm4gISEody5qUXVlcnkgJiYgalF1ZXJ5LmZuICYmIHR5cGVvZiBqUXVlcnkuZm4ub24gPT09ICdmdW5jdGlvbicpO1xyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gaGFzX2RwKCkge1xyXG5cdFx0cmV0dXJuICEhKHcualF1ZXJ5ICYmIGpRdWVyeS5kYXRlcGljayk7XHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBoYXNfd3BiYygpIHtcclxuXHRcdHJldHVybiAhISh3Ll93cGJjICYmIHR5cGVvZiB3Ll93cGJjLnNldF9vdGhlcl9wYXJhbSA9PT0gJ2Z1bmN0aW9uJyk7XHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBub3JtYWxpemVfcmlkKHJpZCkge1xyXG5cdFx0dmFyIG4gPSBwYXJzZUludCggcmlkLCAxMCApO1xyXG5cdFx0cmV0dXJuIChuID4gMCkgPyBTdHJpbmcoIG4gKSA6ICcnO1xyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gZ2V0X3JpZF9jb3VudHMocmlkKSB7XHJcblx0XHR2YXIgciA9IG5vcm1hbGl6ZV9yaWQoIHJpZCApO1xyXG5cdFx0cmV0dXJuIHtcclxuXHRcdFx0cmlkICAgICAgIDogcixcclxuXHRcdFx0bG9hZGVycyAgIDogciA/IHF1ZXJ5X2FsbCggJy5jYWxlbmRhcl9sb2FkZXJfZnJhbWVbZGF0YS13cGJjLXJpZD1cIicgKyByICsgJ1wiXScgKS5sZW5ndGggOiAwLFxyXG5cdFx0XHRjb250YWluZXJzOiByID8gcXVlcnlfYWxsKCAnI2NhbGVuZGFyX2Jvb2tpbmcnICsgciApLmxlbmd0aCA6IDBcclxuXHRcdH07XHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBpc19kdXBsaWNhdGVfcmlkKHJpZCkge1xyXG5cdFx0dmFyIGMgPSBnZXRfcmlkX2NvdW50cyggcmlkICk7XHJcblx0XHRyZXR1cm4gKGMubG9hZGVycyA+IDEpIHx8IChjLmNvbnRhaW5lcnMgPiAxKTtcclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIERldGVybWluZSBpZiB0aGUgbG9hZGVyIGhhcyBiZWVuIHJlcGxhY2VkIGJ5IHRoZSByZWFsIGNhbGVuZGFyLlxyXG5cdCAqXHJcblx0ICogQHBhcmFtIHtFbGVtZW50fSBlbCAgICAgICBMb2FkZXIgZWxlbWVudFxyXG5cdCAqIEBwYXJhbSB7c3RyaW5nfSByaWQgICAgICAgUmVzb3VyY2UgSURcclxuXHQgKiBAcGFyYW0ge0VsZW1lbnR8bnVsbH0gY29udGFpbmVyIE9wdGlvbmFsICNjYWxlbmRhcl9ib29raW5ne3JpZH0gZWxlbWVudFxyXG5cdCAqIEByZXR1cm4ge2Jvb2xlYW59XHJcblx0ICovXHJcblx0ZnVuY3Rpb24gaXNfcmVwbGFjZWQoZWwsIHJpZCwgY29udGFpbmVyKSB7XHJcblx0XHR2YXIgbG9hZGVyX3N0aWxsX2luX2RvbSA9IGQuYm9keS5jb250YWlucyggZWwgKTtcclxuXHRcdHZhciBjYWxlbmRhcl9leGlzdHMgICAgID0gISFxdWVyeV9vbmUoICcud3BiY19jYWxlbmRhcl9pZF8nICsgcmlkLCBjb250YWluZXIgfHwgZCApO1xyXG5cdFx0cmV0dXJuICghbG9hZGVyX3N0aWxsX2luX2RvbSkgfHwgY2FsZW5kYXJfZXhpc3RzO1xyXG5cdH1cclxuXHJcblx0LyoqXHJcblx0ICogU3RhcnQgd2F0Y2hlciBmb3IgYSBzaW5nbGUgbG9hZGVyIGVsZW1lbnQuXHJcblx0ICogLSBQb2xscyBhbmQgb2JzZXJ2ZXMgdGhlIGNhbGVuZGFyIGNvbnRhaW5lci5cclxuXHQgKiAtIEFmdGVyIGdyYWNlLCBpbmplY3RzIGEgc3VpdGFibGUgbWVzc2FnZSBpZiBub3QgcmVwbGFjZWQuXHJcblx0ICpcclxuXHQgKiBAcGFyYW0ge0VsZW1lbnR9IGVsXHJcblx0ICovXHJcblx0ZnVuY3Rpb24gc3RhcnRfZm9yKGVsKSB7XHJcblx0XHRpZiAoICEgZWwgfHwgaXNfcHJvY2Vzc2VkKCBlbCApICkge1xyXG5cdFx0XHRyZXR1cm47XHJcblx0XHR9XHJcblx0XHRtYXJrX3Byb2Nlc3NlZCggZWwgKTtcclxuXHJcblx0XHR2YXIgcmlkID0gZWwuZGF0YXNldC53cGJjUmlkO1xyXG5cdFx0aWYgKCAhIHJpZCApIHtcclxuXHRcdFx0cmV0dXJuO1xyXG5cdFx0fVxyXG5cclxuXHRcdHZhciBncmFjZV9tcyA9IHBhcnNlSW50KCBlbC5kYXRhc2V0LndwYmNHcmFjZSB8fCAnODAwMCcsIDEwICk7XHJcblx0XHRpZiAoICEgKGdyYWNlX21zID4gMCkgKSB7XHJcblx0XHRcdGdyYWNlX21zID0gODAwMDtcclxuXHRcdH1cclxuXHJcblx0XHR2YXIgY29udGFpbmVyX2lkID0gJ2NhbGVuZGFyX2Jvb2tpbmcnICsgcmlkO1xyXG5cdFx0dmFyIGNvbnRhaW5lciAgICA9IGQuZ2V0RWxlbWVudEJ5SWQoIGNvbnRhaW5lcl9pZCApO1xyXG5cdFx0dmFyIHRleHRfZWwgICAgICA9IHF1ZXJ5X29uZSggJy5jYWxlbmRhcl9sb2FkZXJfdGV4dCcsIGVsICk7XHJcblxyXG5cdFx0ZnVuY3Rpb24gcmVwbGFjZWRfbm93KCkge1xyXG5cdFx0XHRyZXR1cm4gaXNfcmVwbGFjZWQoIGVsLCByaWQsIGNvbnRhaW5lciApO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8vIEFscmVhZHkgcmVwbGFjZWQgLT4gbm90aGluZyB0byBkby5cclxuXHRcdGlmICggcmVwbGFjZWRfbm93KCkgKSB7XHJcblx0XHRcdHJldHVybjtcclxuXHRcdH1cclxuXHJcblx0XHQvLyAxKSBDaGVhcCBwb2xsaW5nLlxyXG5cdFx0dmFyIHBvbGxfaWQgPSB3LnNldEludGVydmFsKCBmdW5jdGlvbiAoKSB7XHJcblx0XHRcdGlmICggcmVwbGFjZWRfbm93KCkgKSB7XHJcblx0XHRcdFx0c2FmZV9jbGVhciggcG9sbF9pZCApO1xyXG5cdFx0XHRcdGlmICggb2JzZXJ2ZXIgKSB7XHJcblx0XHRcdFx0XHR0cnkge1xyXG5cdFx0XHRcdFx0XHRvYnNlcnZlci5kaXNjb25uZWN0KCk7XHJcblx0XHRcdFx0XHR9IGNhdGNoICggZSApIHtcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHRcdH0sIDI1MCApO1xyXG5cclxuXHRcdC8vIDIpIE11dGF0aW9uT2JzZXJ2ZXIgZm9yIGZhc3RlciByZWFjdGlvbi5cclxuXHRcdHZhciBvYnNlcnZlciA9IG51bGw7XHJcblx0XHRpZiAoIGNvbnRhaW5lciAmJiAnTXV0YXRpb25PYnNlcnZlcicgaW4gdyApIHtcclxuXHRcdFx0dHJ5IHtcclxuXHRcdFx0XHRvYnNlcnZlciA9IG5ldyBNdXRhdGlvbk9ic2VydmVyKCBmdW5jdGlvbiAoKSB7XHJcblx0XHRcdFx0XHRpZiAoIHJlcGxhY2VkX25vdygpICkge1xyXG5cdFx0XHRcdFx0XHRzYWZlX2NsZWFyKCBwb2xsX2lkICk7XHJcblx0XHRcdFx0XHRcdHRyeSB7XHJcblx0XHRcdFx0XHRcdFx0b2JzZXJ2ZXIuZGlzY29ubmVjdCgpO1xyXG5cdFx0XHRcdFx0XHR9IGNhdGNoICggZSApIHtcclxuXHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdH0gKTtcclxuXHRcdFx0XHRvYnNlcnZlci5vYnNlcnZlKCBjb250YWluZXIsIHsgY2hpbGRMaXN0OiB0cnVlLCBzdWJ0cmVlOiB0cnVlIH0gKTtcclxuXHRcdFx0fSBjYXRjaCAoIGUgKSB7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHQvLyAzKSBGaW5hbCBkZWNpc2lvbiBhZnRlciBncmFjZSBwZXJpb2QuXHJcblx0XHR3LnNldFRpbWVvdXQoIGZ1bmN0aW9uIGZpbmFsaXplX2FmdGVyX2dyYWNlKCkge1xyXG5cdFx0XHRpZiAoIHJlcGxhY2VkX25vdygpICkge1xyXG5cdFx0XHRcdHNhZmVfY2xlYXIoIHBvbGxfaWQgKTtcclxuXHRcdFx0XHRpZiAoIG9ic2VydmVyICkge1xyXG5cdFx0XHRcdFx0dHJ5IHtcclxuXHRcdFx0XHRcdFx0b2JzZXJ2ZXIuZGlzY29ubmVjdCgpO1xyXG5cdFx0XHRcdFx0fSBjYXRjaCAoIGUgKSB7XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0fVxyXG5cdFx0XHRcdHJldHVybjtcclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0dmFyIE0gPSBnZXRfbWVzc2FnZXMoIHJpZCApO1xyXG5cdFx0XHR2YXIgbXNnO1xyXG5cdFx0XHRpZiAoICEgaGFzX2pxKCkgKSB7XHJcblx0XHRcdFx0bXNnID0gTS5saWJfanE7XHJcblx0XHRcdH0gZWxzZSBpZiAoICEgaGFzX3dwYmMoKSApIHtcclxuXHRcdFx0XHRtc2cgPSBNLmxpYl93cGJjO1xyXG5cdFx0XHR9IGVsc2UgaWYgKCAhIGhhc19kcCgpICkge1xyXG5cdFx0XHRcdG1zZyA9IE0ubGliX2RwO1xyXG5cdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdC8vIExpYnJhcmllcyBhcmUgcHJlc2VudCwgYnV0IGxvYWRlciB3YXNuJ3QgcmVwbGFjZWQgLT4gZGVjaWRlIHdoYXQgaXMgbW9zdCBsaWtlbHkuXHJcblx0XHRcdFx0aWYgKCBpc19kdXBsaWNhdGVfcmlkKCByaWQgKSApIHtcclxuXHRcdFx0XHRcdG1zZyA9IE0uZHVwbGljYXRlICsgJ1xcblxcbicgKyBNLnN1cHBvcnQ7XHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRcdG1zZyA9IE0uaW5pdF9mYWlsZWQgKyAnXFxuXFxuJyArIE0uc3VwcG9ydDtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHRyeSB7XHJcblx0XHRcdFx0aWYgKCB0ZXh0X2VsICkge1xyXG5cdFx0XHRcdFx0dGV4dF9lbC5pbm5lckhUTUwgPSB3cmFwX2h0bWwoIG1zZyApO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fSBjYXRjaCAoIGUgKSB7XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHNhZmVfY2xlYXIoIHBvbGxfaWQgKTtcclxuXHRcdFx0aWYgKCBvYnNlcnZlciApIHtcclxuXHRcdFx0XHR0cnkge1xyXG5cdFx0XHRcdFx0b2JzZXJ2ZXIuZGlzY29ubmVjdCgpO1xyXG5cdFx0XHRcdH0gY2F0Y2ggKCBlICkge1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fVxyXG5cdFx0fSwgZ3JhY2VfbXMgKTtcclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIEluaXRpYWxpemUgd2F0Y2hlcnMgZm9yIGxvYWRlciBlbGVtZW50cyBhbHJlYWR5IGluIHRoZSBET00uXHJcblx0ICovXHJcblx0ZnVuY3Rpb24gYm9vdHN0cmFwX2V4aXN0aW5nKCkge1xyXG5cdFx0cXVlcnlfYWxsKCAnLmNhbGVuZGFyX2xvYWRlcl9mcmFtZVtkYXRhLXdwYmMtcmlkXScgKS5mb3JFYWNoKCBzdGFydF9mb3IgKTtcclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIE9ic2VydmUgdGhlIGRvY3VtZW50IGZvciBhbnkgbmV3IGxvYWRlciBlbGVtZW50cyBpbnNlcnRlZCBsYXRlciAoQUpBWCwgYmxvY2sgcmVuZGVyKS5cclxuXHQgKi9cclxuXHRmdW5jdGlvbiBvYnNlcnZlX25ld19sb2FkZXJzKCkge1xyXG5cdFx0aWYgKCAhICgnTXV0YXRpb25PYnNlcnZlcicgaW4gdykgKSB7XHJcblx0XHRcdHJldHVybjtcclxuXHRcdH1cclxuXHRcdHRyeSB7XHJcblx0XHRcdHZhciBkb2Nfb2JzZXJ2ZXIgPSBuZXcgTXV0YXRpb25PYnNlcnZlciggZnVuY3Rpb24gKG11dGF0aW9ucykge1xyXG5cdFx0XHRcdGZvciAoIHZhciBpID0gMDsgaSA8IG11dGF0aW9ucy5sZW5ndGg7IGkrKyApIHtcclxuXHRcdFx0XHRcdHZhciBub2RlcyA9IG11dGF0aW9uc1tpXS5hZGRlZE5vZGVzIHx8IFtdO1xyXG5cdFx0XHRcdFx0Zm9yICggdmFyIGogPSAwOyBqIDwgbm9kZXMubGVuZ3RoOyBqKysgKSB7XHJcblx0XHRcdFx0XHRcdHZhciBub2RlID0gbm9kZXNbal07XHJcblx0XHRcdFx0XHRcdGlmICggISBub2RlIHx8IG5vZGUubm9kZVR5cGUgIT09IDEgKSB7XHJcblx0XHRcdFx0XHRcdFx0Y29udGludWU7XHJcblx0XHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdFx0aWYgKCBub2RlLm1hdGNoZXMgJiYgbm9kZS5tYXRjaGVzKCAnLmNhbGVuZGFyX2xvYWRlcl9mcmFtZVtkYXRhLXdwYmMtcmlkXScgKSApIHtcclxuXHRcdFx0XHRcdFx0XHRzdGFydF9mb3IoIG5vZGUgKTtcclxuXHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHRpZiAoIG5vZGUucXVlcnlTZWxlY3RvckFsbCApIHtcclxuXHRcdFx0XHRcdFx0XHR2YXIgaW5uZXIgPSBub2RlLnF1ZXJ5U2VsZWN0b3JBbGwoICcuY2FsZW5kYXJfbG9hZGVyX2ZyYW1lW2RhdGEtd3BiYy1yaWRdJyApO1xyXG5cdFx0XHRcdFx0XHRcdGlmICggaW5uZXIgJiYgaW5uZXIubGVuZ3RoICkge1xyXG5cdFx0XHRcdFx0XHRcdFx0aW5uZXIuZm9yRWFjaCggc3RhcnRfZm9yICk7XHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9ICk7XHJcblx0XHRcdGRvY19vYnNlcnZlci5vYnNlcnZlKCBkLmRvY3VtZW50RWxlbWVudCwgeyBjaGlsZExpc3Q6IHRydWUsIHN1YnRyZWU6IHRydWUgfSApO1xyXG5cdFx0fSBjYXRjaCAoIGUgKSB7XHJcblx0XHR9XHJcblx0fVxyXG5cclxuXHQvKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHQgKiBCb290XHJcblx0ICogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovXHJcblx0b25fcmVhZHkoIGZ1bmN0aW9uICgpIHtcclxuXHRcdGJvb3RzdHJhcF9leGlzdGluZygpO1xyXG5cdFx0b2JzZXJ2ZV9uZXdfbG9hZGVycygpO1xyXG5cdH0gKTtcclxuXHJcbn0pKCB3aW5kb3csIGRvY3VtZW50ICk7XHJcbiIsIihmdW5jdGlvbiggdyApIHtcclxuXHJcblx0J3VzZSBzdHJpY3QnO1xyXG5cclxuXHRpZiAoICEgdy5XUEJDX0ZFICkge1xyXG5cdFx0dy5XUEJDX0ZFID0ge307XHJcblx0fVxyXG5cclxuXHQvKipcclxuXHQgKiBBdXRvLWZpbGwgYm9va2luZyBmb3JtIGZpZWxkcyAodGV4dC9lbWFpbCkgYmFzZWQgb24gaW5wdXQgXCJuYW1lXCIgcGF0dGVybnMuXHJcblx0ICpcclxuXHQgKiBGb3JtIElEIGZvcm1hdDogYm9va2luZ19mb3Jte3Jlc291cmNlX2lkfVxyXG5cdCAqIFNraXBzIGRhdGUgZmllbGQ6IGRhdGVfYm9va2luZ3tyZXNvdXJjZV9pZH1cclxuXHQgKlxyXG5cdCAqIEBwYXJhbSB7bnVtYmVyfSByZXNvdXJjZV9pZCBCb29raW5nIHJlc291cmNlIElELlxyXG5cdCAqIEBwYXJhbSB7T2JqZWN0fSBmaWxsX3ZhbHVlcyBWYWx1ZXMgdG8gaW5qZWN0IChzdHJpbmdzKS5cclxuXHQgKlxyXG5cdCAqIEByZXR1cm4ge2Jvb2xlYW59IFRydWUgaWYgZm9ybSBmb3VuZCBhbmQgcHJvY2Vzc2VkLCBmYWxzZSBvdGhlcndpc2UuXHJcblx0ICovXHJcblx0dy5XUEJDX0ZFLmF1dG9maWxsX2Jvb2tpbmdfZm9ybV9maWVsZHMgPSBmdW5jdGlvbiggcmVzb3VyY2VfaWQsIGZpbGxfdmFsdWVzICkge1xyXG5cclxuXHRcdHJlc291cmNlX2lkICA9IHBhcnNlSW50KCByZXNvdXJjZV9pZCwgMTAgKSB8fCAwO1xyXG5cdFx0ZmlsbF92YWx1ZXMgID0gZmlsbF92YWx1ZXMgfHwge307XHJcblxyXG5cdFx0dmFyIGZvcm1faWQgICA9ICdib29raW5nX2Zvcm0nICsgcmVzb3VyY2VfaWQ7XHJcblx0XHR2YXIgZGF0ZV9uYW1lID0gJ2RhdGVfYm9va2luZycgKyByZXNvdXJjZV9pZDtcclxuXHJcblx0XHR2YXIgc3VibWl0X2Zvcm0gPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCggZm9ybV9pZCApO1xyXG5cclxuXHRcdGlmICggISBzdWJtaXRfZm9ybSApIHtcclxuXHRcdFx0LyogZXNsaW50LWRpc2FibGUgbm8tY29uc29sZSAqL1xyXG5cdFx0XHRjb25zb2xlLmVycm9yKCAnV1BCQzogTm8gYm9va2luZyBmb3JtOiAnICsgZm9ybV9pZCApO1xyXG5cdFx0XHQvKiBlc2xpbnQtZW5hYmxlIG5vLWNvbnNvbGUgKi9cclxuXHRcdFx0cmV0dXJuIGZhbHNlO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8vIEtlZXAgc2FtZSByZWdleCBydWxlcyBhbmQgcHJpb3JpdHkgb3JkZXIgYXMgbGVnYWN5IGlubGluZSBKUy5cclxuXHRcdHZhciBydWxlcyA9IGFycmF5X3J1bGVzKCBmaWxsX3ZhbHVlcyApO1xyXG5cclxuXHRcdHZhciBlbGVtZW50cyA9IHN1Ym1pdF9mb3JtLmVsZW1lbnRzIHx8IFtdO1xyXG5cdFx0dmFyIGNvdW50ICAgID0gZWxlbWVudHMubGVuZ3RoO1xyXG5cdFx0dmFyIGVsO1xyXG5cdFx0dmFyIGk7XHJcblx0XHR2YXIgajtcclxuXHJcblx0XHRmb3IgKCBpID0gMDsgaSA8IGNvdW50OyBpKysgKSB7XHJcblxyXG5cdFx0XHRlbCA9IGVsZW1lbnRzWyBpIF07XHJcblxyXG5cdFx0XHRpZiAoICEgZWwgfHwgISBlbC5uYW1lICkge1xyXG5cdFx0XHRcdGNvbnRpbnVlO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBPbmx5IHRleHQvZW1haWwgaW5wdXRzLlxyXG5cdFx0XHRpZiAoICggZWwudHlwZSAhPT0gJ3RleHQnICkgJiYgKCBlbC50eXBlICE9PSAnZW1haWwnICkgKSB7XHJcblx0XHRcdFx0Y29udGludWU7XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIFNraXAgZGF0ZSBmaWVsZC5cclxuXHRcdFx0aWYgKCBlbC5uYW1lID09PSBkYXRlX25hbWUgKSB7XHJcblx0XHRcdFx0Y29udGludWU7XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIEZpbGwgb25seSBlbXB0eSB2YWx1ZXMgKGxlZ2FjeSBiZWhhdmlvcjogPT0gXCJcIikuXHJcblx0XHRcdGlmICggZWwudmFsdWUgIT09ICcnICkge1xyXG5cdFx0XHRcdGNvbnRpbnVlO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRmb3IgKCBqID0gMDsgaiA8IHJ1bGVzLmxlbmd0aDsgaisrICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIHJ1bGVzWyBqIF0ucmUudGVzdCggZWwubmFtZSApICkge1xyXG5cclxuXHRcdFx0XHRcdGlmICggcnVsZXNbIGogXS52YWwgIT09ICcnICkge1xyXG5cdFx0XHRcdFx0XHRlbC52YWx1ZSA9IHJ1bGVzWyBqIF0udmFsO1xyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGJyZWFrOyAvLyBTdG9wIGF0IGZpcnN0IG1hdGNoaW5nIHJ1bGUgKHByaW9yaXR5KS5cclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdHJ1ZTtcclxuXHR9O1xyXG5cclxuXHQvKipcclxuXHQgKiBCdWlsZCBydWxlcyBhcnJheSBmb3IgYXV0b2ZpbGwuXHJcblx0ICpcclxuXHQgKiBAcGFyYW0ge09iamVjdH0gZmlsbF92YWx1ZXMgVmFsdWVzIHRvIGluamVjdC5cclxuXHQgKlxyXG5cdCAqIEByZXR1cm4ge0FycmF5fSBSdWxlcyBsaXN0LlxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIGFycmF5X3J1bGVzKCBmaWxsX3ZhbHVlcyApIHtcclxuXHJcblx0XHQvLyBOb3JtYWxpemUgdG8gc3RyaW5ncyAocHJldmVudCBcInVuZGVmaW5lZFwiIGluIGZpZWxkcykuXHJcblx0XHR2YXIgbmlja25hbWUgID0gKCBmaWxsX3ZhbHVlcy5uaWNrbmFtZSAhPSBudWxsICkgPyBTdHJpbmcoIGZpbGxfdmFsdWVzLm5pY2tuYW1lICkgOiAnJztcclxuXHRcdHZhciBsYXN0X25hbWUgPSAoIGZpbGxfdmFsdWVzLmxhc3RfbmFtZSAhPSBudWxsICkgPyBTdHJpbmcoIGZpbGxfdmFsdWVzLmxhc3RfbmFtZSApIDogJyc7XHJcblx0XHR2YXIgZmlyc3RfbmFtZSA9ICggZmlsbF92YWx1ZXMuZmlyc3RfbmFtZSAhPSBudWxsICkgPyBTdHJpbmcoIGZpbGxfdmFsdWVzLmZpcnN0X25hbWUgKSA6ICcnO1xyXG5cdFx0dmFyIGVtYWlsICAgICA9ICggZmlsbF92YWx1ZXMuZW1haWwgIT0gbnVsbCApID8gU3RyaW5nKCBmaWxsX3ZhbHVlcy5lbWFpbCApIDogJyc7XHJcblx0XHR2YXIgcGhvbmUgICAgID0gKCBmaWxsX3ZhbHVlcy5waG9uZSAhPSBudWxsICkgPyBTdHJpbmcoIGZpbGxfdmFsdWVzLnBob25lICkgOiAnJztcclxuXHRcdHZhciBuYl9lbmZhbnQgPSAoIGZpbGxfdmFsdWVzLm5iX2VuZmFudCAhPSBudWxsICkgPyBTdHJpbmcoIGZpbGxfdmFsdWVzLm5iX2VuZmFudCApIDogJyc7XHJcblx0XHR2YXIgdXJsICAgICAgID0gKCBmaWxsX3ZhbHVlcy51cmwgIT0gbnVsbCApID8gU3RyaW5nKCBmaWxsX3ZhbHVlcy51cmwgKSA6ICcnO1xyXG5cclxuXHRcdHJldHVybiBbXHJcblx0XHRcdHsgcmU6IC9eKFtBLVphLXowLTlfXFwtXFwuXSkqKG5pY2tuYW1lKXsxfShbQS1aYS16MC05X1xcLVxcLl0pKiQvLCB2YWw6IG5pY2tuYW1lIH0sXHJcblx0XHRcdHsgcmU6IC9eKFtBLVphLXowLTlfXFwtXFwuXSkqKGxhc3R8c2Vjb25kKXsxfShbX1xcLVxcLl0pP25hbWUoW0EtWmEtejAtOV9cXC1cXC5dKSokLywgdmFsOiBsYXN0X25hbWUgfSxcclxuXHRcdFx0eyByZTogL15uYW1lKFswLTlfXFwtXFwuXSkqJC8sIHZhbDogZmlyc3RfbmFtZSB9LFxyXG5cdFx0XHR7IHJlOiAvXihbQS1aYS16MC05X1xcLVxcLl0pKihmaXJzdHxteSl7MX0oW19cXC1cXC5dKT9uYW1lKFtBLVphLXowLTlfXFwtXFwuXSkqJC8sIHZhbDogZmlyc3RfbmFtZSB9LFxyXG5cdFx0XHR7IHJlOiAvXihlKT8oW19cXC1cXC5dKT9tYWlsKFswLTlfXFwtXFwuXSopJC8sIHZhbDogZW1haWwgfSxcclxuXHRcdFx0eyByZTogL14oW0EtWmEtejAtOV9cXC1cXC5dKSoocGhvbmV8Zm9uZSl7MX0oW0EtWmEtejAtOV9cXC1cXC5dKSokLywgdmFsOiBwaG9uZSB9LFxyXG5cdFx0XHR7IHJlOiAvXihlKT8oW19cXC1cXC5dKT9uYl9lbmZhbnQoWzAtOV9cXC1cXC5dKikkLywgdmFsOiBuYl9lbmZhbnQgfSxcclxuXHRcdFx0eyByZTogL14oW0EtWmEtejAtOV9cXC1cXC5dKSooVVJMfHNpdGV8d2VifFdFQil7MX0oW0EtWmEtejAtOV9cXC1cXC5dKSokLywgdmFsOiB1cmwgfVxyXG5cdFx0XTtcclxuXHR9XHJcblxyXG59KSggd2luZG93ICk7XHJcbiIsIi8vID09IFN1Ym1pdCBCb29raW5nIERhdGEgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG4vLyBSZWZhY3RvcmVkIChzYWZlKSwgd2l0aCBuZXcgd3BiY18qIG5hbWVzLlxyXG4vLyBCYWNrd2FyZC1jb21wYXRpYmxlIHdyYXBwZXJzIGZvciBsZWdhY3kgZnVuY3Rpb24gbmFtZXMgYXJlIGluY2x1ZGVkIGF0IHRoZSBib3R0b20uXHJcbi8vIEBmaWxlOiBpbmNsdWRlcy9fX2pzL2NsaWVudC9mcm9udF9lbmRfZm9ybS9ib29raW5nX2Zvcm1fc3VibWl0LmpzXHJcblxyXG4vKipcbiAqIENoZWNrIHdoZXRoZXIgYSBmb3JtIGJlbG9uZ3MgdG8gYSByZXF1ZXN0LWxvY2FsIGJvb2tpbmcgcHJldmlldy5cbiAqXG4gKiBTaWduZWQgaWZyYW1lIGFuZCBuZXctd2luZG93IHByZXZpZXdzIGludGVudGlvbmFsbHkgZG8gbm90IHVzZSB0aGlzIG1hcmtlcjtcbiAqIHRoZXkgcmV0YWluIHRoZSBjb21wbGV0ZSBCb29raW5nIENhbGVuZGFyIHByZXZpZXcgbGlmZWN5Y2xlLlxuICpcbiAqIEBwYXJhbSB7SFRNTEZvcm1FbGVtZW50fSBzdWJtaXRfZm9ybSBCb29raW5nIGZvcm0gYmVpbmcgc3VibWl0dGVkLlxuICogQHJldHVybiB7Ym9vbGVhbn0gVHJ1ZSB3aGVuIGZpbmFsIHN1Ym1pc3Npb24gbXVzdCByZW1haW4gbG9jYWwgYW5kIG5vbi1tdXRhdGluZy5cbiAqL1xuZnVuY3Rpb24gd3BiY19ib29raW5nX2Zvcm1fX2lzX2lubGluZV9wcmV2aWV3X3N1Ym1pc3Npb24oIHN1Ym1pdF9mb3JtICkge1xuXHRyZXR1cm4gMCA8IGpRdWVyeSggc3VibWl0X2Zvcm0gKS5jbG9zZXN0KCAnW2RhdGEtd3BiYy1pbmxpbmUtYm9va2luZy1wcmV2aWV3PVwiMVwiXScgKS5sZW5ndGg7XG59XG5cbi8qKlxuICogRXhwbGFpbiBiZWxvdyB0aGUgZm9ybSB3aHkgYSByZXF1ZXN0LWxvY2FsIHByZXZpZXcgY2Fubm90IGNyZWF0ZSBhIGJvb2tpbmcuXG4gKlxuICogQHBhcmFtIHtIVE1MRm9ybUVsZW1lbnR9IHN1Ym1pdF9mb3JtIEJvb2tpbmcgZm9ybSBiZWluZyBzdWJtaXR0ZWQuXG4gKiBAcmV0dXJuIHt2b2lkfVxuICovXG5mdW5jdGlvbiB3cGJjX2Jvb2tpbmdfZm9ybV9fc2hvd19pbmxpbmVfcHJldmlld19zdWJtaXNzaW9uX25vdGljZSggc3VibWl0X2Zvcm0gKSB7XG5cdHdwYmNfZnJvbnRfZW5kX19zaG93X21lc3NhZ2VfX3dhcm5pbmdfdW5kZXJfZWxlbWVudChcblx0XHRzdWJtaXRfZm9ybSxcblx0XHRfd3BiYy5nZXRfbWVzc2FnZSggJ21lc3NhZ2VfaW5saW5lX3ByZXZpZXdfc3VibWlzc2lvbl9kaXNhYmxlZCcgKSxcblx0XHQndGV4dCdcblx0KTtcbn1cblxuLyoqXG4gKiBDaGVjayBmaWVsZHMgYXQgZm9ybSBhbmQgdGhlbiBzZW5kIHJlcXVlc3QgKGxlZ2FjeTogbXlib29raW5nX3N1Ym1pdCkuXG4gKlxyXG4gKiBAcGFyYW0ge0hUTUxGb3JtRWxlbWVudH0gc3VibWl0X2Zvcm1cclxuICogQHBhcmFtIHtudW1iZXJ8c3RyaW5nfSAgIHJlc291cmNlX2lkXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSAgICAgICAgICB3cGRldl9hY3RpdmVfbG9jYWxlXHJcbiAqXHJcbiAqIEByZXR1cm4ge2ZhbHNlfHVuZGVmaW5lZH0gTGVnYWN5IGJlaGF2aW9yOiByZXR1cm5zIGZhbHNlIGluIHNvbWUgY2FzZXMsIG90aGVyd2lzZSB1bmRlZmluZWQuXHJcbiAqL1xyXG5mdW5jdGlvbiB3cGJjX2Jvb2tpbmdfZm9ybV9zdWJtaXQoIHN1Ym1pdF9mb3JtLCByZXNvdXJjZV9pZCwgd3BkZXZfYWN0aXZlX2xvY2FsZSApIHtcclxuXHJcblx0cmVzb3VyY2VfaWQgPSBwYXJzZUludCggcmVzb3VyY2VfaWQsIDEwICk7XHJcblxyXG5cdC8vIFNhZmV0eSBndWFyZCAobGVnYWN5IGNvZGUgYXNzdW1lZCB2YWxpZCBmb3JtKS5cclxuXHRpZiAoICEgc3VibWl0X2Zvcm0gfHwgISBzdWJtaXRfZm9ybS5lbGVtZW50cyApIHtcclxuXHRcdC8qIGVzbGludC1kaXNhYmxlIG5vLWNvbnNvbGUgKi9cclxuXHRcdGNvbnNvbGUuZXJyb3IoICdXUEJDOiBJbnZhbGlkIHN1Ym1pdCBmb3JtIGluIHdwYmNfYm9va2luZ19mb3JtX3N1Ym1pdCgpLicgKTtcclxuXHRcdC8qIGVzbGludC1lbmFibGUgbm8tY29uc29sZSAqL1xyXG5cdFx0cmV0dXJuIGZhbHNlO1xyXG5cdH1cclxuXHJcblx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdC8vIEV4dGVybmFsIGhvb2s6IGFsbG93IHBhdXNlIHN1Ym1pdCBvbiBjb25maXJtYXRpb24vc3VtbWFyeSBzdGVwLlxyXG5cdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHR2YXIgdGFyZ2V0X2VsbSA9IGpRdWVyeSggJy5ib29raW5nX2Zvcm1fZGl2JyApLnRyaWdnZXIoICdib29raW5nX2Zvcm1fc3VibWl0X2NsaWNrJywgWyByZXNvdXJjZV9pZCwgc3VibWl0X2Zvcm0sIHdwZGV2X2FjdGl2ZV9sb2NhbGUgXSApOyAvLyBGaXhJbjogOC44LjMuMTMuXHJcblxyXG5cdGlmIChcclxuXHRcdCggalF1ZXJ5KCB0YXJnZXRfZWxtICkuZmluZCggJ2lucHV0W25hbWU9XCJib29raW5nX2Zvcm1fc2hvd19zdW1tYXJ5XCJdJyApLmxlbmd0aCA+IDAgKSAmJlxyXG5cdFx0KCAncGF1c2Vfc3VibWl0JyA9PT0galF1ZXJ5KCB0YXJnZXRfZWxtICkuZmluZCggJ2lucHV0W25hbWU9XCJib29raW5nX2Zvcm1fc2hvd19zdW1tYXJ5XCJdJyApLnZhbCgpIClcclxuXHQpIHtcblx0XHRyZXR1cm4gZmFsc2U7XG5cdH1cblxuXHRpZiAoIHdwYmNfYm9va2luZ19mb3JtX19pc19pbmxpbmVfcHJldmlld19zdWJtaXNzaW9uKCBzdWJtaXRfZm9ybSApICkge1xuXHRcdHdwYmNfYm9va2luZ19mb3JtX19zaG93X2lubGluZV9wcmV2aWV3X3N1Ym1pc3Npb25fbm90aWNlKCBzdWJtaXRfZm9ybSApO1xuXHRcdHJldHVybiBmYWxzZTtcblx0fVxuXG5cdC8vIEZpeEluOiA4LjQuMC4yLlxuXHR2YXIgaXNfZXJyb3IgPSB3cGJjX2NoZWNrX2Vycm9yc19pbl9ib29raW5nX2Zvcm0oIHJlc291cmNlX2lkICk7XHJcblx0aWYgKCBpc19lcnJvciApIHtcclxuXHRcdHJldHVybiBmYWxzZTtcclxuXHR9XHJcblxyXG5cdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHQvLyBTaG93IG1lc3NhZ2UgaWYgbm8gc2VsZWN0ZWQgZGF5cyBpbiBDYWxlbmRhcihzKS5cclxuXHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0dmFyIGRhdGVfaW5wdXQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCggJ2RhdGVfYm9va2luZycgKyByZXNvdXJjZV9pZCApO1xyXG5cdHZhciBkYXRlX3ZhbHVlID0gKCBkYXRlX2lucHV0ICkgPyBkYXRlX2lucHV0LnZhbHVlIDogJyc7XHJcblxyXG5cdGlmICggJycgPT09IGRhdGVfdmFsdWUgKSB7XHJcblxyXG5cdFx0dmFyIGFycl9vZl9zZWxlY3RlZF9hZGRpdGlvbmFsX2NhbGVuZGFycyA9IHdwYmNfZ2V0X2Fycl9vZl9zZWxlY3RlZF9hZGRpdGlvbmFsX2NhbGVuZGFycyggcmVzb3VyY2VfaWQgKTsgLy8gRml4SW46IDguNS4yLjI2LlxyXG5cclxuXHRcdGlmICggISBhcnJfb2Zfc2VsZWN0ZWRfYWRkaXRpb25hbF9jYWxlbmRhcnMgfHwgKCBhcnJfb2Zfc2VsZWN0ZWRfYWRkaXRpb25hbF9jYWxlbmRhcnMubGVuZ3RoID09PSAwICkgKSB7XHJcblx0XHRcdHdwYmNfZnJvbnRfZW5kX19zaG93X21lc3NhZ2VfX3dhcm5pbmcoXG5cdFx0XHRcdCcjYm9va2luZ19mb3JtX2RpdicgKyByZXNvdXJjZV9pZCArICcgLmJrX2NhbGVuZGFyX2ZyYW1lJyxcblx0XHRcdFx0X3dwYmMuZ2V0X21lc3NhZ2UoICdtZXNzYWdlX2NoZWNrX25vX3NlbGVjdGVkX2RhdGVzJyApLFxuXHRcdFx0XHQndGV4dCdcblx0XHRcdCk7XG5cdFx0XHRyZXR1cm47XHJcblx0XHR9XHJcblx0fVxyXG5cclxuXHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0Ly8gRml4SW46IDYuMS4xLjMuIFRpbWUgc2VsZWN0aW9uIGF2YWlsYWJpbGl0eSBjaGVja3MuXHJcblx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdGlmICggdHlwZW9mIHdwYmNfaXNfdGhpc190aW1lX3NlbGVjdGlvbl9ub3RfYXZhaWxhYmxlID09PSAnZnVuY3Rpb24nICkge1xyXG5cclxuXHRcdGlmICggJycgPT09IGRhdGVfdmFsdWUgKSB7IC8vIFByaW1hcnkgY2FsZW5kYXIgbm90IHNlbGVjdGVkLlxyXG5cclxuXHRcdFx0dmFyIGFkZGl0aW9uYWxfY2FsZW5kYXJzX2VsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoICdhZGRpdGlvbmFsX2NhbGVuZGFycycgKyByZXNvdXJjZV9pZCApO1xyXG5cclxuXHRcdFx0aWYgKCBhZGRpdGlvbmFsX2NhbGVuZGFyc19lbCAhPT0gbnVsbCApIHsgLy8gQ2hlY2tpbmcgYWRkaXRpb25hbCBjYWxlbmRhcnMuXHJcblxyXG5cdFx0XHRcdHZhciBpZF9hZGRpdGlvbmFsX3N0ciA9IGFkZGl0aW9uYWxfY2FsZW5kYXJzX2VsLnZhbHVlO1xyXG5cdFx0XHRcdHZhciBpZF9hZGRpdGlvbmFsX2FyciA9IGlkX2FkZGl0aW9uYWxfc3RyLnNwbGl0KCAnLCcgKTtcclxuXHRcdFx0XHR2YXIgaXNfdGltZXNfZGF0ZXNfb2sgPSBmYWxzZTtcclxuXHJcblx0XHRcdFx0Zm9yICggdmFyIGlhID0gMDsgaWEgPCBpZF9hZGRpdGlvbmFsX2Fyci5sZW5ndGg7IGlhKysgKSB7XHJcblxyXG5cdFx0XHRcdFx0dmFyIGFkZF9pZCA9IGlkX2FkZGl0aW9uYWxfYXJyWyBpYSBdO1xyXG5cclxuXHRcdFx0XHRcdHZhciBhZGRfZGF0ZV9lbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCAnZGF0ZV9ib29raW5nJyArIGFkZF9pZCApO1xyXG5cdFx0XHRcdFx0dmFyIGFkZF9kYXRlX3ZhbCA9ICggYWRkX2RhdGVfZWwgKSA/IGFkZF9kYXRlX2VsLnZhbHVlIDogJyc7XHJcblxyXG5cdFx0XHRcdFx0aWYgKFxyXG5cdFx0XHRcdFx0XHQoICcnICE9PSBhZGRfZGF0ZV92YWwgKSAmJlxyXG5cdFx0XHRcdFx0XHQoICEgd3BiY19pc190aGlzX3RpbWVfc2VsZWN0aW9uX25vdF9hdmFpbGFibGUoIGFkZF9pZCwgc3VibWl0X2Zvcm0uZWxlbWVudHMgKSApXHJcblx0XHRcdFx0XHQpIHtcclxuXHRcdFx0XHRcdFx0aXNfdGltZXNfZGF0ZXNfb2sgPSB0cnVlO1xyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0aWYgKCAhIGlzX3RpbWVzX2RhdGVzX29rICkge1xyXG5cdFx0XHRcdFx0cmV0dXJuO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fVxyXG5cclxuXHRcdH0gZWxzZSB7IC8vIFByaW1hcnkgY2FsZW5kYXIgc2VsZWN0ZWQuXHJcblxyXG5cdFx0XHRpZiAoIHdwYmNfaXNfdGhpc190aW1lX3NlbGVjdGlvbl9ub3RfYXZhaWxhYmxlKCByZXNvdXJjZV9pZCwgc3VibWl0X2Zvcm0uZWxlbWVudHMgKSApIHtcclxuXHRcdFx0XHRyZXR1cm47XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHR9XHJcblxyXG5cdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHQvLyBTZXJpYWxpemUgZm9ybSAobGVnYWN5IGZvcm1hdCkuXHJcblx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdHZhciBjb3VudCAgICA9IHN1Ym1pdF9mb3JtLmVsZW1lbnRzLmxlbmd0aDtcclxuXHR2YXIgZm9ybWRhdGEgPSAnJztcclxuXHR2YXIgaW5wX3ZhbHVlO1xyXG5cdHZhciBpbnBfdGl0bGVfdmFsdWU7XHJcblx0dmFyIGVsZW1lbnQ7XHJcblx0dmFyIGVsX3R5cGU7XHJcblxyXG5cdC8vIEhlbHBlcjogbGVnYWN5IGVzY2FwaW5nIGZvciB0aGUgc2VyaWFsaXplZCB2YWx1ZS5cclxuXHRmdW5jdGlvbiB3cGJjX2VzY2FwZV9zZXJpYWxpemVkX3ZhbHVlKCB2YWwgKSB7XHJcblxyXG5cdFx0dmFsID0gKCB2YWwgPT0gbnVsbCApID8gJycgOiBTdHJpbmcoIHZhbCApO1xyXG5cclxuXHRcdC8vIFJlcGxhY2UgcmVnaXN0ZXJlZCBjaGFyYWN0ZXJzLlxyXG5cdFx0dmFsID0gdmFsLnJlcGxhY2UoIG5ldyBSZWdFeHAoICdcXFxcXicsICdnJyApLCAnJiM5NDsnICk7XHJcblx0XHR2YWwgPSB2YWwucmVwbGFjZSggbmV3IFJlZ0V4cCggJ34nLCAnZycgKSwgJyYjMTI2OycgKTtcclxuXHJcblx0XHQvLyBSZXBsYWNlIHF1b3Rlcy5cclxuXHRcdHZhbCA9IHZhbC5yZXBsYWNlKCAvXCIvZywgJyYjMzQ7JyApO1xyXG5cdFx0dmFsID0gdmFsLnJlcGxhY2UoIC8nL2csICcmIzM5OycgKTtcclxuXHJcblx0XHRyZXR1cm4gdmFsO1xyXG5cdH1cclxuXHJcblx0Ly8gSGVscGVyOiBkZXRlcm1pbmUgVUkgdHlwZSBmb3IgdGl0bGUgZXh0cmFjdGlvbiAobGVnYWN5IGxvZ2ljKS5cclxuXHRmdW5jdGlvbiB3cGJjX2dldF9pbnB1dF9lbGVtZW50X3R5cGUoIGVsICkge1xyXG5cclxuXHRcdGlmICggISBlbCB8fCAhIGVsLnRhZ05hbWUgKSB7XHJcblx0XHRcdHJldHVybiAnJztcclxuXHRcdH1cclxuXHJcblx0XHR2YXIgdGFnID0gU3RyaW5nKCBlbC50YWdOYW1lICkudG9Mb3dlckNhc2UoKTtcclxuXHJcblx0XHRpZiAoICdpbnB1dCcgPT09IHRhZyApIHtcclxuXHRcdFx0cmV0dXJuICggZWwudHlwZSApID8gU3RyaW5nKCBlbC50eXBlICkudG9Mb3dlckNhc2UoKSA6ICd0ZXh0JztcclxuXHRcdH1cclxuXHJcblx0XHQvLyBMZWdhY3kgdXNlZCBcInNlbGVjdFwiIHN0cmluZyBoZXJlLlxyXG5cdFx0aWYgKCAnc2VsZWN0JyA9PT0gdGFnICkge1xyXG5cdFx0XHRyZXR1cm4gJ3NlbGVjdCc7XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRhZztcclxuXHR9XHJcblxyXG5cdGZvciAoIHZhciBpID0gMDsgaSA8IGNvdW50OyBpKysgKSB7IC8vIEZpeEluOiA5LjEuNS4xLlxyXG5cclxuXHRcdGVsZW1lbnQgPSBzdWJtaXRfZm9ybS5lbGVtZW50c1sgaSBdO1xyXG5cclxuXHRcdGlmICggISBlbGVtZW50ICkge1xyXG5cdFx0XHRjb250aW51ZTtcclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIGpRdWVyeSggZWxlbWVudCApLmNsb3Nlc3QoICcuYm9va2luZ19mb3JtX2dhcmJhZ2UnICkubGVuZ3RoICkge1xyXG5cdFx0XHRjb250aW51ZTsgLy8gU2tpcCBlbGVtZW50cyBmcm9tIGdhcmJhZ2UuIEZpeEluOiA3LjEuMi4xNC5cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoICcxJyA9PT0gU3RyaW5nKCBqUXVlcnkoIGVsZW1lbnQgKS5hdHRyKCAnZGF0YS13cGJjLWJvb2tpbmctc3VibWl0LWlnbm9yZScgKSB8fCAnJyApICkge1xyXG5cdFx0XHRjb250aW51ZTtcclxuXHRcdH1cclxuXHJcblx0XHRpZiAoXHJcblx0XHRcdCggZWxlbWVudC50eXBlICE9PSAnYnV0dG9uJyApICYmXHJcblx0XHRcdCggZWxlbWVudC50eXBlICE9PSAnaGlkZGVuJyApICYmXHJcblx0XHRcdCggZWxlbWVudC5uYW1lICE9PSAoICdkYXRlX2Jvb2tpbmcnICsgcmVzb3VyY2VfaWQgKSApXHJcblx0XHRcdC8vICYmICggalF1ZXJ5KCBlbGVtZW50ICkuaXMoICc6dmlzaWJsZScgKSApIC8vRml4SW46IDcuMi4xLjEyLjJcclxuXHRcdCkge1xyXG5cclxuXHRcdFx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdFx0XHQvLyBHZXQgZWxlbWVudCB2YWx1ZS5cclxuXHRcdFx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdFx0XHRpZiAoIGVsZW1lbnQudHlwZSA9PT0gJ2NoZWNrYm94JyApIHtcclxuXHJcblx0XHRcdFx0aWYgKCBlbGVtZW50LnZhbHVlID09PSAnJyApIHtcclxuXHRcdFx0XHRcdGlucF92YWx1ZSA9IGVsZW1lbnQuY2hlY2tlZDtcclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdFx0aW5wX3ZhbHVlID0gKCBlbGVtZW50LmNoZWNrZWQgKSA/IGVsZW1lbnQudmFsdWUgOiAnJztcclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCBlbGVtZW50LnR5cGUgPT09ICdyYWRpbycgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggZWxlbWVudC5jaGVja2VkICkge1xyXG5cdFx0XHRcdFx0aW5wX3ZhbHVlID0gZWxlbWVudC52YWx1ZTtcclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdC8vIFJlcXVpcmVkIHJhZGlvOiBzaG93IHdhcm5pbmcgaWYgbm9uZSBjaGVja2VkLlxyXG5cdFx0XHRcdFx0Ly8gRml4SW46IDcuMC4xLjYyLlxyXG5cdFx0XHRcdFx0aWYgKFxyXG5cdFx0XHRcdFx0XHQoIGVsZW1lbnQuY2xhc3NOYW1lLmluZGV4T2YoICd3cGRldi12YWxpZGF0ZXMtYXMtcmVxdWlyZWQnICkgIT09IC0xICkgJiZcclxuXHRcdFx0XHRcdFx0KCBqUXVlcnkoIGVsZW1lbnQgKS5pcyggJzp2aXNpYmxlJyApICkgJiYgLy8gRml4SW46IDcuMi4xLjEyLjIuXHJcblx0XHRcdFx0XHRcdCggISBqUXVlcnkoICc6cmFkaW9bbmFtZT1cIicgKyBlbGVtZW50Lm5hbWUgKyAnXCJdJywgc3VibWl0X2Zvcm0gKS5pcyggJzpjaGVja2VkJyApIClcclxuXHRcdFx0XHRcdCkge1xyXG5cdFx0XHRcdFx0XHR3cGJjX2Zyb250X2VuZF9fc2hvd19tZXNzYWdlX193YXJuaW5nKCBlbGVtZW50LCBfd3BiYy5nZXRfbWVzc2FnZSggJ21lc3NhZ2VfY2hlY2tfcmVxdWlyZWRfZm9yX3JhZGlvX2JveCcgKSwgJ3RleHQnICk7IC8vIEZpeEluOiA4LjUuMS4zLlxuXHRcdFx0XHRcdFx0cmV0dXJuO1xyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdC8vIFNraXAgc3RvcmluZyBlbXB0eSByYWRpbyBvcHRpb25zLlxyXG5cdFx0XHRcdFx0Y29udGludWU7XHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRpbnBfdmFsdWUgPSBlbGVtZW50LnZhbHVlO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpbnBfdGl0bGVfdmFsdWUgPSAnJztcclxuXHJcblx0XHRcdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdFx0Ly8gR2V0IGh1bWFuLWZyaWVuZGx5IHRpdGxlIHZhbHVlIChsZWdhY3kgYmVoYXZpb3IpLlxyXG5cdFx0XHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHRcdHZhciBpbnB1dF9lbGVtZW50X3R5cGUgPSB3cGJjX2dldF9pbnB1dF9lbGVtZW50X3R5cGUoIGVsZW1lbnQgKTtcclxuXHJcblx0XHRcdHN3aXRjaCAoIGlucHV0X2VsZW1lbnRfdHlwZSApIHtcclxuXHJcblx0XHRcdFx0Y2FzZSAndGV4dCc6XHJcblx0XHRcdFx0Y2FzZSAnZW1haWwnOlxyXG5cdFx0XHRcdFx0aW5wX3RpdGxlX3ZhbHVlID0gaW5wX3ZhbHVlO1xyXG5cdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdGNhc2UgJ3NlbGVjdCc6XHJcblx0XHRcdFx0XHRpbnBfdGl0bGVfdmFsdWUgPSBqUXVlcnkoIGVsZW1lbnQgKS5maW5kKCAnb3B0aW9uOnNlbGVjdGVkJyApLnRleHQoKTtcclxuXHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRjYXNlICdyYWRpbyc6XHJcblx0XHRcdFx0Y2FzZSAnY2hlY2tib3gnOlxyXG5cdFx0XHRcdFx0aWYgKCBqUXVlcnkoIGVsZW1lbnQgKS5pcyggJzpjaGVja2VkJyApICkge1xyXG5cdFx0XHRcdFx0XHR2YXIgbGFiZWxfZWxlbWVudCA9IGpRdWVyeSggZWxlbWVudCApLnBhcmVudHMoICcud3BkZXYtbGlzdC1pdGVtJyApLmZpbmQoICcud3BkZXYtbGlzdC1pdGVtLWxhYmVsJyApO1xyXG5cdFx0XHRcdFx0XHRpZiAoIGxhYmVsX2VsZW1lbnQubGVuZ3RoICkge1xyXG5cdFx0XHRcdFx0XHRcdGlucF90aXRsZV92YWx1ZSA9IGxhYmVsX2VsZW1lbnQuaHRtbCgpO1xyXG5cdFx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0ZGVmYXVsdDpcclxuXHRcdFx0XHRcdGlucF90aXRsZV92YWx1ZSA9IGlucF92YWx1ZTtcclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdFx0XHQvLyBNdWx0aXBsZSBzZWxlY3QgdmFsdWUgZXh0cmFjdGlvbi5cclxuXHRcdFx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdFx0XHRpZiAoICggZWxlbWVudC50eXBlID09PSAnc2VsZWN0Ym94LW11bHRpcGxlJyApIHx8ICggZWxlbWVudC50eXBlID09PSAnc2VsZWN0LW11bHRpcGxlJyApICkge1xyXG5cdFx0XHRcdGlucF92YWx1ZSA9IGpRdWVyeSggJ1tuYW1lPVwiJyArIGVsZW1lbnQubmFtZSArICdcIl0nICkudmFsKCk7XHJcblx0XHRcdFx0aWYgKCAoIGlucF92YWx1ZSA9PT0gbnVsbCApIHx8ICggU3RyaW5nKCBpbnBfdmFsdWUgKSA9PT0gJycgKSApIHtcclxuXHRcdFx0XHRcdGlucF92YWx1ZSA9ICcnO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdFx0XHQvLyBNYWtlIHZhbGlkYXRpb24gb25seSBmb3IgdmlzaWJsZSBlbGVtZW50cy5cclxuXHRcdFx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdFx0XHRpZiAoIGpRdWVyeSggZWxlbWVudCApLmlzKCAnOnZpc2libGUnICkgKSB7IC8vIEZpeEluOiA3LjIuMS4xMi4yLlxyXG5cclxuXHRcdFx0XHQvLyBSZWNoZWNrIG1heCBhdmFpbGFibGUgdmlzaXRvcnMgc2VsZWN0aW9uLlxyXG5cdFx0XHRcdGlmICggdHlwZW9mIHdwYmNfX2lzX2xlc3NfdGhhbl9yZXF1aXJlZF9fb2ZfbWF4X2F2YWlsYWJsZV9zbG90c19fYmwgPT09ICdmdW5jdGlvbicgKSB7XHJcblx0XHRcdFx0XHRpZiAoIHdwYmNfX2lzX2xlc3NfdGhhbl9yZXF1aXJlZF9fb2ZfbWF4X2F2YWlsYWJsZV9zbG90c19fYmwoIHJlc291cmNlX2lkLCBlbGVtZW50ICkgKSB7XHJcblx0XHRcdFx0XHRcdHJldHVybjtcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdC8vIFJlcXVpcmVkIGZpZWxkcy5cclxuXHRcdFx0XHRpZiAoIGVsZW1lbnQuY2xhc3NOYW1lLmluZGV4T2YoICd3cGRldi12YWxpZGF0ZXMtYXMtcmVxdWlyZWQnICkgIT09IC0xICkge1xyXG5cclxuXHRcdFx0XHRcdGlmICggKCBlbGVtZW50LnR5cGUgPT09ICdjaGVja2JveCcgKSAmJiAoIGVsZW1lbnQuY2hlY2tlZCA9PT0gZmFsc2UgKSApIHtcclxuXHJcblx0XHRcdFx0XHRcdGlmICggISBqUXVlcnkoICc6Y2hlY2tib3hbbmFtZT1cIicgKyBlbGVtZW50Lm5hbWUgKyAnXCJdJywgc3VibWl0X2Zvcm0gKS5pcyggJzpjaGVja2VkJyApICkge1xyXG5cdFx0XHRcdFx0XHRcdHdwYmNfZnJvbnRfZW5kX19zaG93X21lc3NhZ2VfX3dhcm5pbmcoIGVsZW1lbnQsIF93cGJjLmdldF9tZXNzYWdlKCAnbWVzc2FnZV9jaGVja19yZXF1aXJlZF9mb3JfY2hlY2tfYm94JyApLCAndGV4dCcgKTsgLy8gRml4SW46IDguNS4xLjMuXG5cdFx0XHRcdFx0XHRcdHJldHVybjtcclxuXHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGlmICggZWxlbWVudC50eXBlID09PSAncmFkaW8nICkge1xyXG5cclxuXHRcdFx0XHRcdFx0aWYgKCAhIGpRdWVyeSggJzpyYWRpb1tuYW1lPVwiJyArIGVsZW1lbnQubmFtZSArICdcIl0nLCBzdWJtaXRfZm9ybSApLmlzKCAnOmNoZWNrZWQnICkgKSB7XHJcblx0XHRcdFx0XHRcdFx0d3BiY19mcm9udF9lbmRfX3Nob3dfbWVzc2FnZV9fd2FybmluZyggZWxlbWVudCwgX3dwYmMuZ2V0X21lc3NhZ2UoICdtZXNzYWdlX2NoZWNrX3JlcXVpcmVkX2Zvcl9yYWRpb19ib3gnICksICd0ZXh0JyApOyAvLyBGaXhJbjogOC41LjEuMy5cblx0XHRcdFx0XHRcdFx0cmV0dXJuO1xyXG5cdFx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0aWYgKCAoIGVsZW1lbnQudHlwZSAhPT0gJ2NoZWNrYm94JyApICYmICggZWxlbWVudC50eXBlICE9PSAncmFkaW8nICkgJiYgKCAnJyA9PT0gd3BiY190cmltKCBpbnBfdmFsdWUgKSApICkge1xyXG5cdFx0XHRcdFx0XHR3cGJjX2Zyb250X2VuZF9fc2hvd19tZXNzYWdlX193YXJuaW5nKCBlbGVtZW50LCBfd3BiYy5nZXRfbWVzc2FnZSggJ21lc3NhZ2VfY2hlY2tfcmVxdWlyZWQnICksICd0ZXh0JyApOyAvLyBGaXhJbjogOC41LjEuMy5cblx0XHRcdFx0XHRcdHJldHVybjtcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdC8vIEVtYWlsIGZvcm1hdCB2YWxpZGF0aW9uLlxyXG5cdFx0XHRcdGlmICggZWxlbWVudC5jbGFzc05hbWUuaW5kZXhPZiggJ3dwZGV2LXZhbGlkYXRlcy1hcy1lbWFpbCcgKSAhPT0gLTEgKSB7XHJcblxyXG5cdFx0XHRcdFx0aW5wX3ZhbHVlID0gU3RyaW5nKCBpbnBfdmFsdWUgKS5yZXBsYWNlKCAvXlxccyt8XFxzKyQvZ20sICcnICk7IC8vIFRyaW0gd2hpdGUgc3BhY2UuIEZpeEluOiA1LjQuNS5cclxuXHRcdFx0XHRcdHZhciByZWdfZW1haWwgPSAvXihbQS1aYS16MC05X1xcLVxcLlxcK10pK1xcQChbQS1aYS16MC05X1xcLVxcLl0pK1xcLihbQS1aYS16XXsyLH0pJC87XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBpbnBfdmFsdWUgIT09ICcnICkge1xyXG5cdFx0XHRcdFx0XHRpZiAoIHJlZ19lbWFpbC50ZXN0KCBpbnBfdmFsdWUgKSA9PT0gZmFsc2UgKSB7XHJcblx0XHRcdFx0XHRcdFx0d3BiY19mcm9udF9lbmRfX3Nob3dfbWVzc2FnZV9fd2FybmluZyggZWxlbWVudCwgX3dwYmMuZ2V0X21lc3NhZ2UoICdtZXNzYWdlX2NoZWNrX2VtYWlsJyApLCAndGV4dCcgKTsgLy8gRml4SW46IDguNS4xLjMuXG5cdFx0XHRcdFx0XHRcdHJldHVybjtcclxuXHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Ly8gU2FtZSBlbWFpbCBmaWVsZCB2YWxpZGF0aW9uICh2ZXJpZmljYXRpb24gZmllbGQpLlxyXG5cdFx0XHRcdGlmICggKCBlbGVtZW50LmNsYXNzTmFtZS5pbmRleE9mKCAnd3BkZXYtdmFsaWRhdGVzLWFzLWVtYWlsJyApICE9PSAtMSApICYmICggZWxlbWVudC5jbGFzc05hbWUuaW5kZXhPZiggJ3NhbWVfYXNfJyApICE9PSAtMSApICkge1xyXG5cclxuXHRcdFx0XHRcdHZhciBwcmltYXJ5X2VtYWlsX25hbWUgPSBlbGVtZW50LmNsYXNzTmFtZS5tYXRjaCggL3NhbWVfYXNfKFteXFxzXSkrL2dpICk7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBwcmltYXJ5X2VtYWlsX25hbWUgIT09IG51bGwgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRwcmltYXJ5X2VtYWlsX25hbWUgPSBwcmltYXJ5X2VtYWlsX25hbWVbIDAgXS5zdWJzdHIoIDggKTtcclxuXHJcblx0XHRcdFx0XHRcdGlmICggalF1ZXJ5KCAnW25hbWU9XCInICsgcHJpbWFyeV9lbWFpbF9uYW1lICsgcmVzb3VyY2VfaWQgKyAnXCJdJyApLmxlbmd0aCA+IDAgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGlmICggalF1ZXJ5KCAnW25hbWU9XCInICsgcHJpbWFyeV9lbWFpbF9uYW1lICsgcmVzb3VyY2VfaWQgKyAnXCJdJyApLnZhbCgpICE9PSBpbnBfdmFsdWUgKSB7XHJcblx0XHRcdFx0XHRcdFx0XHR3cGJjX2Zyb250X2VuZF9fc2hvd19tZXNzYWdlX193YXJuaW5nKCBlbGVtZW50LCBfd3BiYy5nZXRfbWVzc2FnZSggJ21lc3NhZ2VfY2hlY2tfc2FtZV9lbWFpbCcgKSwgJ3RleHQnICk7IC8vIEZpeEluOiA4LjUuMS4zLlxuXHRcdFx0XHRcdFx0XHRcdHJldHVybjtcclxuXHRcdFx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHQvLyBTa2lwIG9uZSBsb29wIGZvciB0aGUgZW1haWwgdmVyaWZpY2F0aW9uIGZpZWxkLlxyXG5cdFx0XHRcdFx0Y29udGludWU7IC8vIEZpeEluOiA4LjEuMi4xNS5cclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdFx0Ly8gR2V0IEZvcm0gRGF0YSAobGVnYWN5IGZvcm1hdCkuXHJcblx0XHRcdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdFx0aWYgKCBlbGVtZW50Lm5hbWUgIT09ICggJ2NhcHRjaGFfaW5wdXQnICsgcmVzb3VyY2VfaWQgKSApIHtcclxuXHJcblx0XHRcdFx0aWYgKCBmb3JtZGF0YSAhPT0gJycgKSB7XHJcblx0XHRcdFx0XHRmb3JtZGF0YSArPSAnfic7XHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRlbF90eXBlID0gZWxlbWVudC50eXBlO1xyXG5cclxuXHRcdFx0XHRpZiAoIGVsZW1lbnQuY2xhc3NOYW1lLmluZGV4T2YoICd3cGRldi12YWxpZGF0ZXMtYXMtZW1haWwnICkgIT09IC0xICkge1xyXG5cdFx0XHRcdFx0ZWxfdHlwZSA9ICdlbWFpbCc7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHRcdGlmICggZWxlbWVudC5jbGFzc05hbWUuaW5kZXhPZiggJ3dwZGV2LXZhbGlkYXRlcy1hcy1jb3Vwb24nICkgIT09IC0xICkge1xyXG5cdFx0XHRcdFx0ZWxfdHlwZSA9ICdjb3Vwb24nO1xyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0aW5wX3ZhbHVlID0gd3BiY19lc2NhcGVfc2VyaWFsaXplZF92YWx1ZSggaW5wX3ZhbHVlICk7XHJcblxyXG5cdFx0XHRcdGlmICggZWxfdHlwZSA9PT0gJ3NlbGVjdC1vbmUnICkge1xyXG5cdFx0XHRcdFx0ZWxfdHlwZSA9ICdzZWxlY3Rib3gtb25lJztcclxuXHRcdFx0XHR9XHJcblx0XHRcdFx0aWYgKCBlbF90eXBlID09PSAnc2VsZWN0LW11bHRpcGxlJyApIHtcclxuXHRcdFx0XHRcdGVsX3R5cGUgPSAnc2VsZWN0Ym94LW11bHRpcGxlJztcclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGZvcm1kYXRhICs9IGVsX3R5cGUgKyAnXicgKyBlbGVtZW50Lm5hbWUgKyAnXicgKyBpbnBfdmFsdWU7XHJcblxyXG5cdFx0XHRcdC8vIEFkZCB0aXRsZS9sYWJlbCB2YWx1ZSAobGVnYWN5KS5cclxuXHRcdFx0XHR2YXIgY2xlYW5fZmllbGRfbmFtZSA9IFN0cmluZyggZWxlbWVudC5uYW1lICk7XHJcblxyXG5cdFx0XHRcdC8vIEJVR0ZJWDogcmVwbGFjZUFsbChSZWdFeHApIGlzIG5vdCBzdXBwb3J0ZWQgaW4gb2xkZXIgYnJvd3NlcnMuXHJcblx0XHRcdFx0Ly8gS2VlcCBsZWdhY3kgaW50ZW50OiByZW1vdmUgW10gc3VmZml4IG9jY3VycmVuY2VzLlxyXG5cdFx0XHRcdGNsZWFuX2ZpZWxkX25hbWUgPSBjbGVhbl9maWVsZF9uYW1lLnJlcGxhY2UoIC9cXFtcXF0vZ2ksICcnICk7XHJcblxyXG5cdFx0XHRcdHZhciByZXNvdXJjZV9pZF9zdHIgPSBTdHJpbmcoIHJlc291cmNlX2lkICk7XHJcblxyXG5cdFx0XHRcdC8vIExlZ2FjeSBhc3N1bWVkIHN1ZmZpeCBlbmRzIHdpdGggcmVzb3VyY2VfaWQsIG1ha2UgaXQgc2FmZS5cclxuXHRcdFx0XHRpZiAoXHJcblx0XHRcdFx0XHQoIGNsZWFuX2ZpZWxkX25hbWUubGVuZ3RoID49IHJlc291cmNlX2lkX3N0ci5sZW5ndGggKSAmJlxyXG5cdFx0XHRcdFx0KCBjbGVhbl9maWVsZF9uYW1lLnN1YnN0ciggY2xlYW5fZmllbGRfbmFtZS5sZW5ndGggLSByZXNvdXJjZV9pZF9zdHIubGVuZ3RoICkgPT09IHJlc291cmNlX2lkX3N0ciApXHJcblx0XHRcdFx0KSB7XHJcblx0XHRcdFx0XHRjbGVhbl9maWVsZF9uYW1lID0gY2xlYW5fZmllbGRfbmFtZS5zdWJzdHIoIDAsIGNsZWFuX2ZpZWxkX25hbWUubGVuZ3RoIC0gcmVzb3VyY2VfaWRfc3RyLmxlbmd0aCApO1xyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Zm9ybWRhdGEgKz0gJ34nICsgZWxfdHlwZSArICdeJyArIGNsZWFuX2ZpZWxkX25hbWUgKyAnX3ZhbCcgKyByZXNvdXJjZV9pZCArICdeJyArIGlucF90aXRsZV92YWx1ZTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0Ly8gVE9ETzogaGVyZSB3YXMgZnVuY3Rpb24gZm9yICdDaGVjayBpZiB2aXNpdG9yIGZpbmlzaCBkYXRlcyBzZWxlY3Rpb24uXHJcblxyXG5cdC8vIENhcHRjaGEgdmVyaWZ5LlxyXG5cdHZhciBjYXB0Y2hhID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoICd3cGRldl9jYXB0Y2hhX2NoYWxsZW5nZV8nICsgcmVzb3VyY2VfaWQgKTtcclxuXHJcblx0aWYgKCBjYXB0Y2hhICE9PSBudWxsICkge1xyXG5cdFx0d3BiY19mb3JtX3N1Ym1pdF9zZW5kKCByZXNvdXJjZV9pZCwgZm9ybWRhdGEsIGNhcHRjaGEudmFsdWUsIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCAnY2FwdGNoYV9pbnB1dCcgKyByZXNvdXJjZV9pZCApLnZhbHVlLCB3cGRldl9hY3RpdmVfbG9jYWxlICk7XHJcblx0fSBlbHNlIHtcclxuXHRcdHdwYmNfZm9ybV9zdWJtaXRfc2VuZCggcmVzb3VyY2VfaWQsIGZvcm1kYXRhLCAnJywgJycsIHdwZGV2X2FjdGl2ZV9sb2NhbGUgKTtcclxuXHR9XHJcblxyXG5cdHJldHVybjtcclxufVxyXG5cclxuXHJcbi8qKlxyXG4gKiBHYXRoZXJpbmcgcGFyYW1zIGZvciBzZW5kaW5nIEFqYXggcmVxdWVzdCBhbmQgdGhlbiBzZW5kIGl0IChsZWdhY3k6IGZvcm1fc3VibWl0X3NlbmQpLlxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcnxzdHJpbmd9IHJlc291cmNlX2lkXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSAgICAgICAgZm9ybWRhdGFcclxuICogQHBhcmFtIHtzdHJpbmd9ICAgICAgICBjYXB0Y2hhX2NoYWxhbmdlXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSAgICAgICAgdXNlcl9jYXB0Y2hhXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSAgICAgICAgd3BkZXZfYWN0aXZlX2xvY2FsZVxyXG4gKlxyXG4gKiBAcmV0dXJuIHt1bmRlZmluZWR9IExlZ2FjeSBiZWhhdmlvci5cclxuICovXHJcbmZ1bmN0aW9uIHdwYmNfZm9ybV9zdWJtaXRfc2VuZCggcmVzb3VyY2VfaWQsIGZvcm1kYXRhLCBjYXB0Y2hhX2NoYWxhbmdlLCB1c2VyX2NhcHRjaGEsIHdwZGV2X2FjdGl2ZV9sb2NhbGUgKSB7XHJcblxyXG5cdHJlc291cmNlX2lkID0gcGFyc2VJbnQoIHJlc291cmNlX2lkLCAxMCApO1xyXG5cclxuXHR2YXIgbXlfYm9va2luZ19mb3JtID0gJyc7XHJcblx0dmFyIGJvb2tpbmdfZm9ybV90eXBlX2VsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoICdib29raW5nX2Zvcm1fdHlwZScgKyByZXNvdXJjZV9pZCApO1xyXG5cdGlmICggYm9va2luZ19mb3JtX3R5cGVfZWwgIT09IG51bGwgKSB7XHJcblx0XHRteV9ib29raW5nX2Zvcm0gPSBib29raW5nX2Zvcm1fdHlwZV9lbC52YWx1ZTtcclxuXHR9XHJcblxyXG5cdHZhciBteV9ib29raW5nX2hhc2ggPSAnJztcclxuXHRpZiAoIF93cGJjLmdldF9vdGhlcl9wYXJhbSggJ3RoaXNfcGFnZV9ib29raW5nX2hhc2gnICkgIT09ICcnICkge1xyXG5cdFx0bXlfYm9va2luZ19oYXNoID0gX3dwYmMuZ2V0X290aGVyX3BhcmFtKCAndGhpc19wYWdlX2Jvb2tpbmdfaGFzaCcgKTtcclxuXHR9XHJcblxyXG5cdHZhciBpc19zZW5kX2VtZWlscyA9IDE7XHJcblx0dmFyICRpc19zZW5kX2VtYWlsX3RvZ2dsZSA9IGpRdWVyeSggJyNpc19zZW5kX2VtYWlsX2Zvcl9wZW5kaW5nJyApO1xyXG5cdHZhciAkbW9kYWxfc2VuZF9lbWFpbF90b2dnbGUgPSBqUXVlcnkoICcjYm9va2luZ19mb3JtJyArIHJlc291cmNlX2lkICkuY2xvc2VzdCggJy53cGJjX21vZGFsX19hZGRfYm9va2luZ19fc2VjdGlvbicgKS5maW5kKCAnW2RhdGEtd3BiYy1hZGQtYm9va2luZy1zZW5kLWVtYWlsc10nICkuZmlyc3QoKTtcclxuXHRpZiAoICRtb2RhbF9zZW5kX2VtYWlsX3RvZ2dsZS5sZW5ndGggKSB7XHJcblx0XHQkaXNfc2VuZF9lbWFpbF90b2dnbGUgPSAkbW9kYWxfc2VuZF9lbWFpbF90b2dnbGU7XHJcblx0fVxyXG5cdGlmICggJGlzX3NlbmRfZW1haWxfdG9nZ2xlLmxlbmd0aCApIHsgLy8gRml4SW46IDguNy45LjUuXHJcblxyXG5cdFx0aXNfc2VuZF9lbWVpbHMgPSAkaXNfc2VuZF9lbWFpbF90b2dnbGUuaXMoICc6Y2hlY2tlZCcgKTtcclxuXHJcblx0XHRpZiAoIGZhbHNlID09PSBpc19zZW5kX2VtZWlscyApIHtcclxuXHRcdFx0aXNfc2VuZF9lbWVpbHMgPSAwO1xyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0aXNfc2VuZF9lbWVpbHMgPSAxO1xyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0dmFyIGRhdGVfZWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCggJ2RhdGVfYm9va2luZycgKyByZXNvdXJjZV9pZCApO1xyXG5cdHZhciBkYXRlX3ZhbHVlID0gKCBkYXRlX2VsICkgPyBkYXRlX2VsLnZhbHVlIDogJyc7XHJcblxyXG5cdGlmICggJycgIT09IGRhdGVfdmFsdWUgKSB7IC8vIEZpeEluOiA2LjEuMS4zLlxyXG5cdFx0d3BiY19zZW5kX2FqYXhfc3VibWl0KCByZXNvdXJjZV9pZCwgZm9ybWRhdGEsIGNhcHRjaGFfY2hhbGFuZ2UsIHVzZXJfY2FwdGNoYSwgaXNfc2VuZF9lbWVpbHMsIG15X2Jvb2tpbmdfaGFzaCwgbXlfYm9va2luZ19mb3JtLCB3cGRldl9hY3RpdmVfbG9jYWxlICk7XHJcblx0fSBlbHNlIHtcclxuXHRcdGpRdWVyeSggJyNib29raW5nX2Zvcm1fZGl2JyArIHJlc291cmNlX2lkICkuaGlkZSgpO1xyXG5cdFx0alF1ZXJ5KCAnI3N1Ym1pdGluZycgKyByZXNvdXJjZV9pZCApLmhpZGUoKTtcclxuXHR9XHJcblxyXG5cdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHQvLyBBZGRpdGlvbmFsIGNhbGVuZGFycyBzdWJtaXQuXHJcblx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdHZhciBhZGRpdGlvbmFsX2NhbGVuZGFyc19lbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCAnYWRkaXRpb25hbF9jYWxlbmRhcnMnICsgcmVzb3VyY2VfaWQgKTtcclxuXHRpZiAoIGFkZGl0aW9uYWxfY2FsZW5kYXJzX2VsID09PSBudWxsICkge1xyXG5cdFx0cmV0dXJuO1xyXG5cdH1cclxuXHJcblx0dmFyIGlkX2FkZGl0aW9uYWxfc3RyID0gYWRkaXRpb25hbF9jYWxlbmRhcnNfZWwudmFsdWU7XHJcblx0dmFyIGlkX2FkZGl0aW9uYWxfYXJyID0gaWRfYWRkaXRpb25hbF9zdHIuc3BsaXQoICcsJyApO1xyXG5cclxuXHQvLyBGaXhJbjogMTAuOS40LjEuXHJcblx0Zm9yICggdmFyIGlhID0gMDsgaWEgPCBpZF9hZGRpdGlvbmFsX2Fyci5sZW5ndGg7IGlhKysgKSB7XHJcblx0XHRpZF9hZGRpdGlvbmFsX2FyclsgaWEgXSA9IHBhcnNlSW50KCBpZF9hZGRpdGlvbmFsX2FyclsgaWEgXSwgMTAgKTtcclxuXHR9XHJcblxyXG5cdGlmICggISBqUXVlcnkoICcjYm9va2luZ19mb3JtX2RpdicgKyByZXNvdXJjZV9pZCApLmlzKCAnOnZpc2libGUnICkgKSB7XHJcblx0XHR3cGJjX2Jvb2tpbmdfZm9ybV9fc3Bpbl9sb2FkZXJfX3Nob3coIHJlc291cmNlX2lkICk7IC8vIFNob3cgU3Bpbm5lclxyXG5cdH1cclxuXHJcblx0Ly8gSGVscGVyOiByZXdyaXRlIGZpZWxkIG5hbWUgc3VmZml4IGZyb20gcmVzb3VyY2VfaWQgLT4gaWRfYWRkaXRpb25hbC5cclxuXHRmdW5jdGlvbiB3cGJjX3Jld3JpdGVfZmllbGRfbmFtZV9zdWZmaXgoIGZpZWxkX25hbWUsIG9sZF9pZCwgbmV3X2lkICkge1xyXG5cclxuXHRcdGZpZWxkX25hbWUgPSBTdHJpbmcoIGZpZWxkX25hbWUgKTtcclxuXHJcblx0XHR2YXIgb2xkX2lkX3N0ciA9IFN0cmluZyggb2xkX2lkICk7XHJcblx0XHR2YXIgbmV3X2lkX3N0ciA9IFN0cmluZyggbmV3X2lkICk7XHJcblxyXG5cdFx0Ly8gSGFuZGxlIGZpZWxkcyB3aXRoIFtdLlxyXG5cdFx0aWYgKFxyXG5cdFx0XHQoIGZpZWxkX25hbWUubGVuZ3RoID49ICggb2xkX2lkX3N0ci5sZW5ndGggKyAyICkgKSAmJlxyXG5cdFx0XHQoIGZpZWxkX25hbWUuc3Vic3RyKCBmaWVsZF9uYW1lLmxlbmd0aCAtICggb2xkX2lkX3N0ci5sZW5ndGggKyAyICkgKSA9PT0gKCBvbGRfaWRfc3RyICsgJ1tdJyApIClcclxuXHRcdCkge1xyXG5cdFx0XHRyZXR1cm4gZmllbGRfbmFtZS5zdWJzdHIoIDAsIGZpZWxkX25hbWUubGVuZ3RoIC0gKCBvbGRfaWRfc3RyLmxlbmd0aCArIDIgKSApICsgbmV3X2lkX3N0ciArICdbXSc7XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gSGFuZGxlIGZpZWxkcyB3aXRob3V0IFtdLlxyXG5cdFx0aWYgKFxyXG5cdFx0XHQoIGZpZWxkX25hbWUubGVuZ3RoID49IG9sZF9pZF9zdHIubGVuZ3RoICkgJiZcclxuXHRcdFx0KCBmaWVsZF9uYW1lLnN1YnN0ciggZmllbGRfbmFtZS5sZW5ndGggLSBvbGRfaWRfc3RyLmxlbmd0aCApID09PSBvbGRfaWRfc3RyIClcclxuXHRcdCkge1xyXG5cdFx0XHRyZXR1cm4gZmllbGRfbmFtZS5zdWJzdHIoIDAsIGZpZWxkX25hbWUubGVuZ3RoIC0gb2xkX2lkX3N0ci5sZW5ndGggKSArIG5ld19pZF9zdHI7XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gRmFsbGJhY2s6IHJldHVybiB1bmNoYW5nZWQgKHNhZmVyIHRoYW4gYnJlYWtpbmcgbmFtZSkuXHJcblx0XHRyZXR1cm4gZmllbGRfbmFtZTtcclxuXHR9XHJcblxyXG5cdGZvciAoIGlhID0gMDsgaWEgPCBpZF9hZGRpdGlvbmFsX2Fyci5sZW5ndGg7IGlhKysgKSB7XHJcblxyXG5cdFx0dmFyIGlkX2FkZGl0aW9uYWwgPSBpZF9hZGRpdGlvbmFsX2FyclsgaWEgXTtcclxuXHJcblx0XHQvLyBGaXhJbjogMTAuOS40LjEuXHJcblx0XHRpZiAoIGlkX2FkZGl0aW9uYWwgPD0gMCApIHtcclxuXHRcdFx0Y29udGludWU7XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gUmVidWlsZCBmb3JtZGF0YSBmb3IgZWFjaCBhZGRpdGlvbmFsIGNhbGVuZGFyIChsZWdhY3kgYmVoYXZpb3IpLlxyXG5cdFx0dmFyIGZvcm1kYXRhX2FkZGl0aW9uYWxfYXJyID0gU3RyaW5nKCBmb3JtZGF0YSApLnNwbGl0KCAnficgKTtcclxuXHRcdHZhciBmb3JtZGF0YV9hZGRpdGlvbmFsID0gJyc7XHJcblxyXG5cdFx0Zm9yICggdmFyIGogPSAwOyBqIDwgZm9ybWRhdGFfYWRkaXRpb25hbF9hcnIubGVuZ3RoOyBqKysgKSB7XHJcblxyXG5cdFx0XHR2YXIgbXlfZm9ybV9maWVsZCA9IGZvcm1kYXRhX2FkZGl0aW9uYWxfYXJyWyBqIF0uc3BsaXQoICdeJyApO1xyXG5cclxuXHRcdFx0aWYgKCBmb3JtZGF0YV9hZGRpdGlvbmFsICE9PSAnJyApIHtcclxuXHRcdFx0XHRmb3JtZGF0YV9hZGRpdGlvbmFsICs9ICd+JztcclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gU2FmZXR5OiBlbnN1cmUgd2UgaGF2ZSBhdCBsZWFzdCB0eXBlIF4gbmFtZSBeIHZhbHVlLlxyXG5cdFx0XHRpZiAoIG15X2Zvcm1fZmllbGQubGVuZ3RoIDwgMyApIHtcclxuXHRcdFx0XHRmb3JtZGF0YV9hZGRpdGlvbmFsICs9IGZvcm1kYXRhX2FkZGl0aW9uYWxfYXJyWyBqIF07XHJcblx0XHRcdFx0Y29udGludWU7XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdG15X2Zvcm1fZmllbGRbIDEgXSA9IHdwYmNfcmV3cml0ZV9maWVsZF9uYW1lX3N1ZmZpeCggbXlfZm9ybV9maWVsZFsgMSBdLCByZXNvdXJjZV9pZCwgaWRfYWRkaXRpb25hbCApO1xyXG5cdFx0XHRmb3JtZGF0YV9hZGRpdGlvbmFsICs9IG15X2Zvcm1fZmllbGRbIDAgXSArICdeJyArIG15X2Zvcm1fZmllbGRbIDEgXSArICdeJyArIG15X2Zvcm1fZmllbGRbIDIgXTtcclxuXHRcdH1cclxuXHJcblx0XHQvLyBJZiBwYXltZW50IGZvcm0gZm9yIG1haW4gYm9va2luZyByZXNvdXJjZSBpcyBzaG93aW5nLCBhcHBlbmQgZm9yIGFkZGl0aW9uYWwgY2FsZW5kYXJzLlxyXG5cdFx0aWYgKCBqUXVlcnkoICcjZ2F0ZXdheV9wYXltZW50X2Zvcm1zJyArIHJlc291cmNlX2lkICkubGVuZ3RoID4gMCApIHtcclxuXHRcdFx0alF1ZXJ5KCAnI2dhdGV3YXlfcGF5bWVudF9mb3JtcycgKyByZXNvdXJjZV9pZCApLmFmdGVyKCAnPGRpdiBpZD1cImdhdGV3YXlfcGF5bWVudF9mb3JtcycgKyBpZF9hZGRpdGlvbmFsICsgJ1wiPjwvZGl2PicgKTtcclxuXHRcdFx0alF1ZXJ5KCAnI2dhdGV3YXlfcGF5bWVudF9mb3JtcycgKyByZXNvdXJjZV9pZCApLmFmdGVyKCAnPGRpdiBpZD1cImFqYXhfcmVzcG9uZF9pbnNlcnQnICsgaWRfYWRkaXRpb25hbCArICdcIiBzdHlsZT1cImRpc3BsYXk6bm9uZTtcIj48L2Rpdj4nICk7XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gRml4SW46IDguNS4yLjE3LlxyXG5cdFx0d3BiY19zZW5kX2FqYXhfc3VibWl0KCBpZF9hZGRpdGlvbmFsLCBmb3JtZGF0YV9hZGRpdGlvbmFsLCBjYXB0Y2hhX2NoYWxhbmdlLCB1c2VyX2NhcHRjaGEsIGlzX3NlbmRfZW1laWxzLCBteV9ib29raW5nX2hhc2gsIG15X2Jvb2tpbmdfZm9ybSwgd3BkZXZfYWN0aXZlX2xvY2FsZSApO1xyXG5cdH1cclxufVxyXG5cclxuXHJcbi8qKlxyXG4gKiBTZW5kIEFqYXggc3VibWl0IChsZWdhY3k6IHNlbmRfYWpheF9zdWJtaXQpLlxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcnxzdHJpbmd9IHJlc291cmNlX2lkXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSAgICAgICAgZm9ybWRhdGFcclxuICogQHBhcmFtIHtzdHJpbmd9ICAgICAgICBjYXB0Y2hhX2NoYWxhbmdlXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSAgICAgICAgdXNlcl9jYXB0Y2hhXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSAgICAgICAgaXNfc2VuZF9lbWVpbHNcclxuICogQHBhcmFtIHtzdHJpbmd9ICAgICAgICBteV9ib29raW5nX2hhc2hcclxuICogQHBhcmFtIHtzdHJpbmd9ICAgICAgICBteV9ib29raW5nX2Zvcm1cclxuICogQHBhcmFtIHtzdHJpbmd9ICAgICAgICB3cGRldl9hY3RpdmVfbG9jYWxlXHJcbiAqXHJcbiAqIEByZXR1cm4ge3VuZGVmaW5lZH0gTGVnYWN5IGJlaGF2aW9yLlxyXG4gKi9cclxuZnVuY3Rpb24gd3BiY19zZW5kX2FqYXhfc3VibWl0KHJlc291cmNlX2lkLCBmb3JtZGF0YSwgY2FwdGNoYV9jaGFsYW5nZSwgdXNlcl9jYXB0Y2hhLCBpc19zZW5kX2VtZWlscywgbXlfYm9va2luZ19oYXNoLCBteV9ib29raW5nX2Zvcm0sIHdwZGV2X2FjdGl2ZV9sb2NhbGUpIHtcclxuXHJcblx0cmVzb3VyY2VfaWQgPSBwYXJzZUludCggcmVzb3VyY2VfaWQsIDEwICk7XHJcblxyXG5cdC8vIERpc2FibGUgU3VibWl0IHwgU2hvdyBzcGluIGxvYWRlci5cclxuXHR3cGJjX2Jvb2tpbmdfZm9ybV9fb25fc3VibWl0X191aV9lbGVtZW50c19kaXNhYmxlKCByZXNvdXJjZV9pZCApO1xyXG5cclxuXHQvLyBGaXhJbjogMjAyNi0wMi0wNSAtIHBhc3MgcHJldmlldyBjb250ZXh0IHRvIGJvb2tpbmcgY3JlYXRlIEFqYXguXHJcblx0dmFyIGZvcm1fc3RhdHVzICA9IHdwYmNfX2dldF9mb3JtX3N0YXR1c19mb3Jfc3VibWl0KCByZXNvdXJjZV9pZCApO1xyXG5cdHZhciBwcmV2aWV3X2FyZ3MgPSAoZm9ybV9zdGF0dXMgPT09ICdwcmV2aWV3JykgPyB3cGJjX19nZXRfYmZiX3ByZXZpZXdfYXJnc19mcm9tX2xvY2F0aW9uKCkgOiBudWxsO1xyXG5cdHZhciAkYWRkX2Jvb2tpbmdfbW9kYWwgPSBqUXVlcnkoICcjYm9va2luZ19mb3JtJyArIHJlc291cmNlX2lkICkuY2xvc2VzdCggJyN3cGJjX21vZGFsX19hZGRfYm9va2luZ19fc2VjdGlvbicgKTtcblx0dmFyIGlzX2FsbG93X3Bhc3QgPSAwO1xuXHR2YXIgY2xhc3NpY19ib29raW5nX2NvbnRleHRfdG9rZW4gPSAnJztcblx0dmFyIGFkbWluX2Jvb2tpbmdfbm9uY2UgPSAnJztcblx0dmFyIGhhc19hZGRfYm9va2luZ19tb2RhbF9jb250ZXh0ID0gKCAkYWRkX2Jvb2tpbmdfbW9kYWwubGVuZ3RoICYmICRhZGRfYm9va2luZ19tb2RhbC5pcyggJzp2aXNpYmxlJyApICk7XG5cdGlmICggJ3VuZGVmaW5lZCcgIT09IHR5cGVvZiBfd3BiYyApIHtcblx0XHRhZG1pbl9ib29raW5nX25vbmNlID0gU3RyaW5nKCBfd3BiYy5nZXRfb3RoZXJfcGFyYW0oICd0aGlzX3BhZ2VfYWRtaW5fYm9va2luZ19ub25jZScgKSB8fCAnJyApO1xuXHR9XG5cclxuXHRpZiAoIGhhc19hZGRfYm9va2luZ19tb2RhbF9jb250ZXh0ICkge1xyXG5cdFx0aXNfYWxsb3dfcGFzdCA9ICRhZGRfYm9va2luZ19tb2RhbC5maW5kKCAnW2RhdGEtd3BiYy1hZGQtYm9va2luZy1hbGxvdy1wYXN0XScgKS5maXJzdCgpLmlzKCAnOmNoZWNrZWQnICkgPyAxIDogMDtcclxuXHRcdGlmICggISBpc19hbGxvd19wYXN0ICkge1xyXG5cdFx0XHRpc19hbGxvd19wYXN0ID0gKCAnMScgPT09IFN0cmluZyggJGFkZF9ib29raW5nX21vZGFsLmF0dHIoICdkYXRhLXdwYmMtYWRkLWJvb2tpbmctYWxsb3ctcGFzdCcgKSB8fCAnMCcgKSApID8gMSA6IDA7XHJcblx0XHR9XHJcblx0fVxyXG5cdGlmICggISBoYXNfYWRkX2Jvb2tpbmdfbW9kYWxfY29udGV4dCAmJiAoICd1bmRlZmluZWQnICE9PSB0eXBlb2YgX3dwYmMgKSApIHtcblx0XHRpc19hbGxvd19wYXN0ID0gKCAnMScgPT09IFN0cmluZyggX3dwYmMuZ2V0X290aGVyX3BhcmFtKCAndGhpc19wYWdlX2FsbG93X3Bhc3QnICkgfHwgJzAnICkgKSA/IDEgOiAwO1xuXHRcdGNsYXNzaWNfYm9va2luZ19jb250ZXh0X3Rva2VuID0gU3RyaW5nKCBfd3BiYy5ib29raW5nX19nZXRfcGFyYW1fdmFsdWUoIHJlc291cmNlX2lkLCAnY2xhc3NpY19ib29raW5nX2NvbnRleHRfdG9rZW4nICkgfHwgJycgKTtcblx0fVxuXHJcblx0dmFyIHJlcXVlc3RfcGFyYW1zID0ge1xyXG5cdFx0J3Jlc291cmNlX2lkJyAgICAgICAgICAgICAgOiByZXNvdXJjZV9pZCxcclxuXHRcdCdkYXRlc19kZG1teXlfY3N2JyAgICAgICAgIDogZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoICdkYXRlX2Jvb2tpbmcnICsgcmVzb3VyY2VfaWQgKS52YWx1ZSxcclxuXHRcdCdmb3JtZGF0YScgICAgICAgICAgICAgICAgIDogZm9ybWRhdGEsXHJcblx0XHQnYm9va2luZ19oYXNoJyAgICAgICAgICAgICA6IG15X2Jvb2tpbmdfaGFzaCxcclxuXHRcdCdjdXN0b21fZm9ybScgICAgICAgICAgICAgIDogbXlfYm9va2luZ19mb3JtLFxyXG5cdFx0J2FnZ3JlZ2F0ZV9yZXNvdXJjZV9pZF9hcnInOiAoICggbnVsbCAhPT0gX3dwYmMuYm9va2luZ19fZ2V0X3BhcmFtX3ZhbHVlKCByZXNvdXJjZV9pZCwgJ2FnZ3JlZ2F0ZV9yZXNvdXJjZV9pZF9hcnInICkgKSA/IF93cGJjLmJvb2tpbmdfX2dldF9wYXJhbV92YWx1ZSggcmVzb3VyY2VfaWQsICdhZ2dyZWdhdGVfcmVzb3VyY2VfaWRfYXJyJyApLmpvaW4oICcsJyApIDogJycgKSxcclxuXHRcdCdjYXB0Y2hhX2NoYWxhbmdlJyAgICAgICAgIDogY2FwdGNoYV9jaGFsYW5nZSxcclxuXHRcdCdjYXB0Y2hhX3VzZXJfaW5wdXQnICAgICAgIDogdXNlcl9jYXB0Y2hhLFxyXG5cdFx0J2lzX2VtYWlsc19zZW5kJyAgICAgICAgICAgOiBpc19zZW5kX2VtZWlscyxcclxuXHRcdCdhY3RpdmVfbG9jYWxlJyAgICAgICAgICAgIDogd3BkZXZfYWN0aXZlX2xvY2FsZSxcclxuXHRcdCdmb3JtX3N0YXR1cycgICAgICAgICAgICAgIDogZm9ybV9zdGF0dXMsXG5cdFx0J2FsbG93X3Bhc3QnICAgICAgICAgICAgICAgOiBpc19hbGxvd19wYXN0LFxuXHRcdCdjbGFzc2ljX2Jvb2tpbmdfY29udGV4dF90b2tlbic6IGNsYXNzaWNfYm9va2luZ19jb250ZXh0X3Rva2VuLFxuXHRcdCd3cGJjX2FkbWluX2Jvb2tpbmdfbm9uY2UnICAgICA6IGFkbWluX2Jvb2tpbmdfbm9uY2Vcblx0fTtcblxyXG5cdHZhciAkdGltZV9vdmVycmlkZV9wYW5lbCA9IGpRdWVyeSggJyNib29raW5nX2Zvcm0nICsgcmVzb3VyY2VfaWQgKS5maW5kKCAnW2RhdGEtd3BiYy1hZGQtYm9va2luZy10aW1lLW92ZXJyaWRlLXBhbmVsXScgKS5maXJzdCgpO1xyXG5cdGlmICggISAkdGltZV9vdmVycmlkZV9wYW5lbC5sZW5ndGggKSB7XHJcblx0XHQkdGltZV9vdmVycmlkZV9wYW5lbCA9IGpRdWVyeSggJyN3cGJjX21vZGFsX19hZGRfYm9va2luZ19fc2VjdGlvbjp2aXNpYmxlJyApLmZpbmQoICdbZGF0YS13cGJjLWFkZC1ib29raW5nLXRpbWUtb3ZlcnJpZGUtcGFuZWxdJyApLmZpcnN0KCk7XHJcblx0fVxyXG5cdGlmIChcclxuXHRcdCAgICR0aW1lX292ZXJyaWRlX3BhbmVsLmxlbmd0aFxyXG5cdFx0JiYgJHRpbWVfb3ZlcnJpZGVfcGFuZWwuZmluZCggJ1tkYXRhLXdwYmMtYWRkLWJvb2tpbmctdGltZS1vdmVycmlkZS1lbmFibGVkXScgKS5maXJzdCgpLmlzKCAnOmNoZWNrZWQnIClcclxuXHQpIHtcclxuXHRcdHJlcXVlc3RfcGFyYW1zWyd3cGJjX3RpbWVfb3ZlcnJpZGVfZW5hYmxlZCddID0gMTtcclxuXHRcdHJlcXVlc3RfcGFyYW1zWyd3cGJjX3RpbWVfb3ZlcnJpZGVfc291cmNlJ10gID0gJHRpbWVfb3ZlcnJpZGVfcGFuZWwuYXR0ciggJ2RhdGEtd3BiYy1hZGQtYm9va2luZy10aW1lLW92ZXJyaWRlLXNvdXJjZScgKSB8fCAnJztcclxuXHRcdHJlcXVlc3RfcGFyYW1zWyd3cGJjX3RpbWVfb3ZlcnJpZGVfc3RhcnQnXSAgID0gJHRpbWVfb3ZlcnJpZGVfcGFuZWwuZmluZCggJ1tkYXRhLXdwYmMtYWRkLWJvb2tpbmctdGltZS1vdmVycmlkZS1maWVsZD1cInN0YXJ0XCJdJyApLmZpcnN0KCkudmFsKCkgfHwgJyc7XHJcblx0XHRyZXF1ZXN0X3BhcmFtc1snd3BiY190aW1lX292ZXJyaWRlX2VuZCddICAgICA9ICR0aW1lX292ZXJyaWRlX3BhbmVsLmZpbmQoICdbZGF0YS13cGJjLWFkZC1ib29raW5nLXRpbWUtb3ZlcnJpZGUtZmllbGQ9XCJlbmRcIl0nICkuZmlyc3QoKS52YWwoKSB8fCAnJztcclxuXHR9XHJcblxyXG5cdHZhciBzZWxlY3RlZF9kYXRlc19jb3VudCA9IFN0cmluZyggcmVxdWVzdF9wYXJhbXNbJ2RhdGVzX2RkbW15eV9jc3YnXSB8fCAnJyApLnNwbGl0KCAnLCcgKS5maWx0ZXIoIGZ1bmN0aW9uKCBkYXRlX3RleHQgKXtcclxuXHRcdHJldHVybiAnJyAhPT0gU3RyaW5nKCBkYXRlX3RleHQgfHwgJycgKS5yZXBsYWNlKCAvXlxccyt8XFxzKyQvZywgJycgKTtcclxuXHR9ICkubGVuZ3RoO1xyXG5cdHZhciBpc190aW1lc19hdmFpbGFiaWxpdHlfb3ZlcnJpZGUgPSAoXHJcblx0XHQgICAoIDEgPT09IHBhcnNlSW50KCByZXF1ZXN0X3BhcmFtc1snd3BiY190aW1lX292ZXJyaWRlX2VuYWJsZWQnXSB8fCAwLCAxMCApIClcclxuXHRcdCYmICggJ3RpbWVzX2F2YWlsYWJpbGl0eScgPT09IFN0cmluZyggcmVxdWVzdF9wYXJhbXNbJ3dwYmNfdGltZV9vdmVycmlkZV9zb3VyY2UnXSB8fCAnJyApIClcclxuXHQpO1xyXG5cdGlmIChcclxuXHRcdCAgIChcclxuXHRcdFx0ICAgaGFzX2FkZF9ib29raW5nX21vZGFsX2NvbnRleHRcclxuXHRcdFx0JiYgJzEnID09PSBTdHJpbmcoICRhZGRfYm9va2luZ19tb2RhbC5hdHRyKCAnZGF0YS13cGJjLWFkZC1ib29raW5nLWZvcmNlLXJlY3VycmVudC10aW1lJyApIHx8ICcwJyApXHJcblx0XHQgICApXHJcblx0XHR8fCAoXHJcblx0XHRcdCAgIGlzX3RpbWVzX2F2YWlsYWJpbGl0eV9vdmVycmlkZVxyXG5cdFx0XHQmJiAoIHNlbGVjdGVkX2RhdGVzX2NvdW50ID4gMSApXHJcblx0XHQgICApXHJcblx0KSB7XHJcblx0XHRyZXF1ZXN0X3BhcmFtc1snaXNfdXNlX2Jvb2tpbmdfcmVjdXJyZW50X3RpbWUnXSA9IDE7XHJcblx0fVxyXG5cclxuXHQvLyBJZiBwcmV2aWV3LCBwYXNzIHNlc3Npb24gaWRlbnRpZmllcnMgc28gUEhQIGNhbiBsb2FkIHRyYW5zaWVudCBzbmFwc2hvdC5cclxuXHRpZiAoIHByZXZpZXdfYXJncyAmJiBwcmV2aWV3X2FyZ3MudG9rZW4gJiYgcHJldmlld19hcmdzLmZvcm1faWQgKSB7XHJcblx0XHRyZXF1ZXN0X3BhcmFtc1snd3BiY19iZmJfcHJldmlldyddICAgICAgICAgPSAxO1xyXG5cdFx0cmVxdWVzdF9wYXJhbXNbJ3dwYmNfYmZiX3ByZXZpZXdfdG9rZW4nXSAgID0gcHJldmlld19hcmdzLnRva2VuO1xyXG5cdFx0cmVxdWVzdF9wYXJhbXNbJ3dwYmNfYmZiX3ByZXZpZXdfZm9ybV9pZCddID0gcHJldmlld19hcmdzLmZvcm1faWQ7XHJcblx0XHRyZXF1ZXN0X3BhcmFtc1snd3BiY19iZmJfcHJldmlld19ub25jZSddICAgPSBwcmV2aWV3X2FyZ3Mubm9uY2U7IC8vIG5vdGU6IFVSTCBwYXJhbSBpcyBgbm9uY2VgLlxyXG5cdH1cclxuXHJcblx0dmFyIGlzX2V4aXQgPSB3cGJjX2FqeF9ib29raW5nX19jcmVhdGUoIHJlcXVlc3RfcGFyYW1zICk7XHJcblxyXG5cdGlmICggdHJ1ZSA9PT0gaXNfZXhpdCApIHtcclxuXHRcdHJldHVybjtcclxuXHR9XHJcbn1cclxuXHJcblxyXG5cclxuLy8gPT0gSGVscGVyIEZ1bmN0aW9ucyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcblxyXG4vKipcclxuICogUGFyc2UgcXVlcnkgc3RyaW5nIGludG8ge2tleTp2YWx1ZX0gKG9sZC1icm93c2VyIHNhZmUpLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcXNcclxuICogQHJldHVybiB7T2JqZWN0fVxyXG4gKi9cclxuZnVuY3Rpb24gd3BiY19fcGFyc2VfcXVlcnlfc3RyaW5nKHFzKSB7XHJcblx0dmFyIG91dCA9IHt9O1xyXG5cdHFzICAgICAgPSAocXMgfHwgJycpO1xyXG5cdHFzICAgICAgPSBxcy5yZXBsYWNlKCAvXlxcPy8sICcnICk7XHJcblx0aWYgKCAhIHFzICkge1xyXG5cdFx0cmV0dXJuIG91dDtcclxuXHR9XHJcblxyXG5cdHZhciBwYXJ0cyA9IHFzLnNwbGl0KCAnJicgKTtcclxuXHRmb3IgKCB2YXIgaSA9IDA7IGkgPCBwYXJ0cy5sZW5ndGg7IGkrKyApIHtcclxuXHRcdHZhciBrdiA9IHBhcnRzW2ldLnNwbGl0KCAnPScgKTtcclxuXHRcdHZhciBrICA9IGRlY29kZVVSSUNvbXBvbmVudCgga3ZbMF0gfHwgJycgKTtcclxuXHRcdGlmICggISBrICkge1xyXG5cdFx0XHRjb250aW51ZTtcclxuXHRcdH1cclxuXHRcdHZhciB2ICA9IGRlY29kZVVSSUNvbXBvbmVudCgga3Yuc2xpY2UoIDEgKS5qb2luKCAnPScgKSB8fCAnJyApO1xyXG5cdFx0b3V0W2tdID0gdjtcclxuXHR9XHJcblx0cmV0dXJuIG91dDtcclxufVxyXG5cclxuLyoqXHJcbiAqIERldGVjdCBwcmV2aWV3IGFyZ3MgZnJvbSBjdXJyZW50IFVSTCAoaWZyYW1lIFVSTCkuXHJcbiAqXHJcbiAqIEByZXR1cm4ge09iamVjdHxudWxsfSB7IHRva2VuLCBmb3JtX2lkLCBub25jZSB9IG9yIG51bGxcclxuICovXHJcbmZ1bmN0aW9uIHdwYmNfX2dldF9iZmJfcHJldmlld19hcmdzX2Zyb21fbG9jYXRpb24oKSB7XHJcblx0dHJ5IHtcclxuXHRcdHZhciBwID0gd3BiY19fcGFyc2VfcXVlcnlfc3RyaW5nKCAod2luZG93LmxvY2F0aW9uICYmIHdpbmRvdy5sb2NhdGlvbi5zZWFyY2gpID8gd2luZG93LmxvY2F0aW9uLnNlYXJjaCA6ICcnICk7XHJcblxyXG5cdFx0aWYgKCAhIHAud3BiY19iZmJfcHJldmlldyB8fCAocC53cGJjX2JmYl9wcmV2aWV3ID09PSAnMCcpICkge1xyXG5cdFx0XHRyZXR1cm4gbnVsbDtcclxuXHRcdH1cclxuXHJcblx0XHRpZiAoICEgcC53cGJjX2JmYl9wcmV2aWV3X3Rva2VuIHx8ICEgcC53cGJjX2JmYl9wcmV2aWV3X2Zvcm1faWQgKSB7XHJcblx0XHRcdHJldHVybiBudWxsO1xyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB7XHJcblx0XHRcdHRva2VuICA6IFN0cmluZyggcC53cGJjX2JmYl9wcmV2aWV3X3Rva2VuICksXHJcblx0XHRcdGZvcm1faWQ6IHBhcnNlSW50KCBwLndwYmNfYmZiX3ByZXZpZXdfZm9ybV9pZCwgMTAgKSB8fCAwLFxyXG5cdFx0XHRub25jZSAgOiAocC5ub25jZSkgPyBTdHJpbmcoIHAubm9uY2UgKSA6ICcnXHJcblx0XHR9O1xyXG5cdH0gY2F0Y2ggKCBlICkge1xyXG5cdFx0cmV0dXJuIG51bGw7XHJcblx0fVxyXG59XHJcblxyXG4vKipcclxuICogUmVzb2x2ZSBmb3JtIHN0YXR1cyBmb3Igc3VibWl0LlxyXG4gKlxyXG4gKiBQcmlvcml0eTpcclxuICogMSkgc2hvcnRjb2RlIHBhcmFtIGV4cG9zZWQgdmlhIF93cGJjLmJvb2tpbmdfX2dldF9wYXJhbV92YWx1ZSguLi4sICdmb3JtX3N0YXR1cycpXHJcbiAqIDIpIGRldGVjdCBwcmV2aWV3IFVSTCBhcmdzXHJcbiAqIDMpIGZhbGxiYWNrOiBwdWJsaXNoZWRcclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IHJlc291cmNlX2lkXHJcbiAqIEByZXR1cm4ge3N0cmluZ30gJ3ByZXZpZXcnfCdwdWJsaXNoZWQnXHJcbiAqL1xyXG5mdW5jdGlvbiB3cGJjX19nZXRfZm9ybV9zdGF0dXNfZm9yX3N1Ym1pdChyZXNvdXJjZV9pZCkge1xyXG5cclxuXHR2YXIgc3RhdHVzID0gJyc7XHJcblxyXG5cdHRyeSB7XHJcblx0XHRpZiAoICh0eXBlb2YgX3dwYmMgIT09ICd1bmRlZmluZWQnKSAmJiBfd3BiYy5ib29raW5nX19nZXRfcGFyYW1fdmFsdWUgKSB7XHJcblx0XHRcdHN0YXR1cyA9IF93cGJjLmJvb2tpbmdfX2dldF9wYXJhbV92YWx1ZSggcmVzb3VyY2VfaWQsICdmb3JtX3N0YXR1cycgKTtcclxuXHRcdH1cclxuXHR9IGNhdGNoICggZSApIHt9XHJcblxyXG5cdHN0YXR1cyA9IChzdGF0dXMgPT0gbnVsbCkgPyAnJyA6IFN0cmluZyggc3RhdHVzICk7XHJcblx0c3RhdHVzID0gc3RhdHVzLnRvTG93ZXJDYXNlKCk7XHJcblxyXG5cdC8vIFVSTC1iYXNlZCBkZXRlY3Rpb24gZm9yIHByZXZpZXcgaWZyYW1lLlxyXG5cdHZhciBwcmV2aWV3X2FyZ3MgPSB3cGJjX19nZXRfYmZiX3ByZXZpZXdfYXJnc19mcm9tX2xvY2F0aW9uKCk7XHJcblx0aWYgKCBwcmV2aWV3X2FyZ3MgKSB7XHJcblx0XHRyZXR1cm4gJ3ByZXZpZXcnO1xyXG5cdH1cclxuXHJcblx0cmV0dXJuIChzdGF0dXMgPT09ICdwcmV2aWV3JykgPyAncHJldmlldycgOiAncHVibGlzaGVkJztcclxufVxyXG5cclxuXHJcblxyXG4vLyA9PSBCYWNrd2FyZC1jb21wYXRpYmxlIHdyYXBwZXJzIChrZWVwIG9sZCBnbG9iYWwgbmFtZXMgd29ya2luZyAxMDAlIGFzIGJlZm9yZSkuID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuZnVuY3Rpb24gbXlib29raW5nX3N1Ym1pdCggc3VibWl0X2Zvcm0sIHJlc291cmNlX2lkLCB3cGRldl9hY3RpdmVfbG9jYWxlICkge1xyXG5cdHJldHVybiB3cGJjX2Jvb2tpbmdfZm9ybV9zdWJtaXQoIHN1Ym1pdF9mb3JtLCByZXNvdXJjZV9pZCwgd3BkZXZfYWN0aXZlX2xvY2FsZSApO1xyXG59XHJcbiIsInRyeSB7XHJcblx0dmFyIGV2ID0gKHR5cGVvZiBDdXN0b21FdmVudCA9PT0gJ2Z1bmN0aW9uJykgPyBuZXcgQ3VzdG9tRXZlbnQoICd3cGJjLXJlYWR5JyApIDogZG9jdW1lbnQuY3JlYXRlRXZlbnQoICdFdmVudCcgKTtcclxuXHRpZiAoIGV2LmluaXRFdmVudCApIHtcclxuXHRcdGV2LmluaXRFdmVudCggJ3dwYmMtcmVhZHknLCB0cnVlLCB0cnVlICk7XHJcblx0fVxyXG5cdGRvY3VtZW50LmRpc3BhdGNoRXZlbnQoIGV2ICk7XHJcblx0Y29uc29sZS5sb2coICd3cGJjLXJlYWR5JyApO1xyXG59IGNhdGNoICggZSApIHtcclxuXHRjb25zb2xlLmVycm9yKCBcIldQQkMgZXZlbnQgJ3dwYmMtcmVhZHknIGZhaWxlZCFcIiwgZSApO1xyXG59XHJcbiJdfQ==
|
| 6090 |
|