PluginProbe
Booking Calendar / 11.0
Booking Calendar v11.0
11.8.4 11.8.3 11.8.2 11.8.1 11.8 11.7 11.6.1 11.6 11.5 11.4.3 11.4.2 11.4.1 11.4 11.3 11.2.1 11.2 11.1 11.0 10.15.7 10.15.6 10.1.3 10.10 10.10.1 10.10.2 10.11 All 204 releases
booking / _dist / all / _src / wpbc_all.js

wpbc_all.js in Booking Calendar 11.0, at _dist/all/_src/wpbc_all.js

5,353 lines 516.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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
1052
1053 // -----------------------------------------------------------------------------------------------------------------
1054 // Days selection
1055 // -----------------------------------------------------------------------------------------------------------------
1056 var local__is_range_select = false;
1057 var local__multi_days_select_num = 365; // multiple | fixed
1058 if ( 'dynamic' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ) ){
1059 local__is_range_select = true;
1060 local__multi_days_select_num = 0;
1061 }
1062 if ( 'single' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ) ){
1063 local__multi_days_select_num = 0;
1064 }
1065
1066 // -----------------------------------------------------------------------------------------------------------------
1067 // Min - Max days to scroll/show
1068 // -----------------------------------------------------------------------------------------------------------------
1069 var local__min_date = 0;
1070 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.
1071 //console.log( local__min_date );
1072 var local__max_date = _wpbc.calendar__get_param_value( resource_id, 'booking_max_monthes_in_calendar' );
1073 //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.
1074
1075 //// Define last day in calendar (as a last day of month (and not date, which is related to actual 'Today' date).
1076 //// 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.
1077 // var cal_last_day_in_month = jQuery.datepick._determineDate( null, local__max_date, new Date() );
1078 // cal_last_day_in_month = new Date( cal_last_day_in_month.getFullYear(), cal_last_day_in_month.getMonth() + 1, 0 );
1079 // local__max_date = cal_last_day_in_month; // FixIn: 10.0.0.26.
1080
1081 // 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.
1082 if ( false !== wpbc_calendar__get_dates_start( resource_id ) ) {
1083 local__min_date = wpbc_calendar__get_dates_start( resource_id ); // E.g. - local__min_date = new Date( 2025, 0, 1 );
1084 }
1085 if ( false !== wpbc_calendar__get_dates_end( resource_id ) ) {
1086 local__max_date = wpbc_calendar__get_dates_end( resource_id ); // E.g. - local__max_date = new Date( 2025, 11, 31 );
1087 }
1088
1089 // In case we edit booking in past or have specific parameter in URL.
1090 var wpbc_edit_booking_hash = _wpbc.get_other_param( 'this_page_booking_hash' );
1091 var wpbc_is_edit_booking_context = ( 'undefined' !== typeof wpbc_edit_booking_hash ) && ( '' !== wpbc_edit_booking_hash );
1092 var wpbc_is_add_booking_admin_page = ( location.href.indexOf( 'page=wpbc' ) != -1 ) && ( location.href.indexOf( 'tab=add-booking' ) != -1 );
1093 if ( ( wpbc_is_add_booking_admin_page || wpbc_is_edit_booking_context )
1094 && (
1095 wpbc_is_edit_booking_context
1096 || ( location.href.indexOf('booking_hash') != -1 ) // Comment this line for ability to add booking in past days at Booking > Add booking page.
1097 || ( location.href.indexOf('allow_past') != -1 ) // FixIn: 10.7.1.2.
1098 )
1099 ){
1100 // local__min_date = null;
1101 // FixIn: 10.14.1.4.
1102 local__min_date = 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 );
1103 local__max_date = null;
1104 }
1105
1106 var local__start_weekday = _wpbc.calendar__get_param_value( resource_id, 'booking_start_day_weeek' );
1107 var local__number_of_months = parseInt( _wpbc.calendar__get_param_value( resource_id, 'calendar_number_of_months' ) );
1108
1109 jQuery( '#calendar_booking' + resource_id ).text( '' ); // Remove all HTML in calendar tag
1110 // -----------------------------------------------------------------------------------------------------------------
1111 // Show calendar
1112 // -----------------------------------------------------------------------------------------------------------------
1113 jQuery('#calendar_booking'+ resource_id).datepick(
1114 {
1115 beforeShowDay: function ( js_date ){
1116 return wpbc__calendar__apply_css_to_days( js_date, {'resource_id': resource_id}, this );
1117 },
1118 onSelect: function ( string_dates, js_dates_arr ){ /**
1119 * string_dates = '23.08.2023 - 26.08.2023'
1120 * | '23.08.2023 - 23.08.2023' |
1121 * '19.09.2023, 24.08.2023, 30.09.2023'
1122 * js_dates_arr = range: [ Date (Aug 23 2023),
1123 * Date (Aug 25 2023)] | multiple: [
1124 * Date(Oct 24 2023), Date(Oct 20 2023), Date(Oct
1125 * 16 2023) ]
1126 */
1127 return wpbc__calendar__on_select_days( string_dates, {'resource_id': resource_id}, this );
1128 },
1129 onHover: function ( string_date, js_date ){
1130 return wpbc__calendar__on_hover_days( string_date, js_date, {'resource_id': resource_id}, this );
1131 },
1132 onChangeMonthYear: function ( year, real_month, js_date__1st_day_in_month ){ },
1133 showOn : 'both',
1134 numberOfMonths: local__number_of_months,
1135 stepMonths : 1,
1136 // prevText : '&laquo;',
1137 // nextText : '&raquo;',
1138 prevText : '&lsaquo;',
1139 nextText : '&rsaquo;',
1140 dateFormat : 'dd.mm.yy',
1141 changeMonth : false,
1142 changeYear : false,
1143 minDate : local__min_date,
1144 maxDate : local__max_date, // '1Y',
1145 // minDate: new Date(2020, 2, 1), maxDate: new Date(2020, 9, 31), // Ability to set any start and end date in calendar
1146 showStatus : false,
1147 multiSeparator : ', ',
1148 closeAtTop : false,
1149 firstDay : local__start_weekday,
1150 gotoCurrent : false,
1151 hideIfNoPrevNext: true,
1152 multiSelect : local__multi_days_select_num,
1153 rangeSelect : local__is_range_select,
1154 // showWeeks: true,
1155 useThemeRoller: false
1156 }
1157 );
1158
1159
1160
1161 // -----------------------------------------------------------------------------------------------------------------
1162 // Clear today date highlighting
1163 // -----------------------------------------------------------------------------------------------------------------
1164 setTimeout( function (){ wpbc_calendars__clear_days_highlighting( resource_id ); }, 500 ); // FixIn: 7.1.2.8.
1165
1166 // -----------------------------------------------------------------------------------------------------------------
1167 // Scroll calendar to specific month
1168 // -----------------------------------------------------------------------------------------------------------------
1169 var start_bk_month = _wpbc.calendar__get_param_value( resource_id, 'calendar_scroll_to' );
1170 if ( false !== start_bk_month ){
1171 wpbc_calendar__scroll_to( resource_id, start_bk_month[ 0 ], start_bk_month[ 1 ] );
1172 }
1173 }
1174
1175
1176 /**
1177 * Get booking statuses as array from the structured summary field, with fallback to the legacy string field.
1178 *
1179 * @param date_bookings_obj
1180 * @returns {[]}
1181 */
1182 function wpbc_get_booking_statuses__as_arr( date_bookings_obj ){
1183
1184 if (
1185 ( ! date_bookings_obj )
1186 || ( 'undefined' === typeof (date_bookings_obj[ 'summary' ]) )
1187 ){
1188 return [];
1189 }
1190
1191 if ( Array.isArray( date_bookings_obj[ 'summary' ][ 'status_for_bookings_arr' ] ) ){
1192 return date_bookings_obj[ 'summary' ][ 'status_for_bookings_arr' ].filter( function ( booking_status ){
1193 return '' !== booking_status;
1194 } );
1195 }
1196
1197 if ( ! date_bookings_obj[ 'summary' ][ 'status_for_bookings' ] ){
1198 return [];
1199 }
1200
1201 return date_bookings_obj[ 'summary' ][ 'status_for_bookings' ].toString().trim().split( /\s+/ ).filter( function ( booking_status ){
1202 return '' !== booking_status;
1203 } );
1204 }
1205
1206
1207 /**
1208 * Check exact booking status in statuses array.
1209 *
1210 * @param {[]} booking_statuses_arr
1211 * @param {string} booking_status
1212 * @returns {boolean}
1213 */
1214 function wpbc_booking_statuses__has( booking_statuses_arr, booking_status ){
1215 return booking_statuses_arr.indexOf( booking_status ) > -1;
1216 }
1217
1218
1219 /**
1220 * Check booking status part, e.g. "pending" in "approved_pending".
1221 *
1222 * @param {[]} booking_statuses_arr
1223 * @param {string} booking_status_part
1224 * @returns {boolean}
1225 */
1226 function wpbc_booking_statuses__has_part( booking_statuses_arr, booking_status_part ){
1227
1228 for ( var i = 0; i < booking_statuses_arr.length; i++ ){
1229 if ( booking_statuses_arr[ i ].split( '_' ).indexOf( booking_status_part ) > -1 ){
1230 return true;
1231 }
1232 }
1233
1234 return false;
1235 }
1236
1237
1238 /**
1239 * Apply CSS to calendar date cells
1240 *
1241 * @param date - JavaScript Date Obj: Mon Dec 11 2023 00:00:00
1242 * GMT+0200 (Eastern European Standard Time)
1243 * @param calendar_params_arr - Calendar Settings Object: {
1244 * "resource_id": 4
1245 * }
1246 * @param datepick_this - this of datepick Obj
1247 * @returns {(*|string)[]|(boolean|string)[]} - [ {true -available | false - unavailable}, 'CSS classes for
1248 * calendar day cell' ]
1249 */
1250 function wpbc__calendar__apply_css_to_days( date, calendar_params_arr, datepick_this ){
1251
1252 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.
1253 var class_day = wpbc__get__td_class_date( date ); // '1-9-2023'
1254 var sql_class_day = wpbc__get__sql_class_date( date ); // '2023-01-09'
1255 var resource_id = ( 'undefined' !== typeof(calendar_params_arr[ 'resource_id' ]) ) ? calendar_params_arr[ 'resource_id' ] : '1'; // '1'
1256
1257 // Get Selected dates in calendar
1258 var selected_dates_sql = wpbc_get__selected_dates_sql__as_arr( resource_id );
1259
1260 // Get Data --------------------------------------------------------------------------------------------------------
1261 var date_bookings_obj = _wpbc.bookings_in_calendar__get_for_date( resource_id, sql_class_day );
1262
1263
1264 // Array with CSS classes for date ---------------------------------------------------------------------------------
1265 var css_classes__for_date = [];
1266 css_classes__for_date.push( 'sql_date_' + sql_class_day ); // 'sql_date_2023-07-21'
1267 css_classes__for_date.push( 'cal4date-' + class_day ); // 'cal4date-7-21-2023'
1268 css_classes__for_date.push( 'wpbc_weekday_' + date.getDay() ); // 'wpbc_weekday_4'
1269
1270 // Define Selected Check In/Out dates in TD -----------------------------------------------------------------------
1271 if (
1272 ( selected_dates_sql.length )
1273 //&& ( selected_dates_sql[ 0 ] !== selected_dates_sql[ (selected_dates_sql.length - 1) ] )
1274 ){
1275 if ( sql_class_day === selected_dates_sql[ 0 ] ){
1276 css_classes__for_date.push( 'selected_check_in' );
1277 css_classes__for_date.push( 'selected_check_in_out' );
1278 }
1279 if ( ( selected_dates_sql.length > 1 ) && ( sql_class_day === selected_dates_sql[ (selected_dates_sql.length - 1) ] ) ) {
1280 css_classes__for_date.push( 'selected_check_out' );
1281 css_classes__for_date.push( 'selected_check_in_out' );
1282 }
1283 }
1284
1285
1286 var is_day_selectable = false;
1287
1288 // If something not defined, then this date closed --------------------------------------------------------------- // FixIn: 10.12.4.6.
1289 if ( (false === date_bookings_obj) || ('undefined' === typeof (date_bookings_obj[resource_id])) ) {
1290
1291 css_classes__for_date.push( 'date_user_unavailable' );
1292
1293 return [ is_day_selectable, css_classes__for_date.join(' ') ];
1294 }
1295
1296
1297 // -----------------------------------------------------------------------------------------------------------------
1298 // date_bookings_obj - Defined. Dates can be selectable.
1299 // -----------------------------------------------------------------------------------------------------------------
1300 var booking_statuses_arr = wpbc_get_booking_statuses__as_arr( date_bookings_obj );
1301
1302 // -----------------------------------------------------------------------------------------------------------------
1303 // Add season names to the day CSS classes -- it is required for correct work of conditional fields --------------
1304 var season_names_arr = _wpbc.seasons__get_for_date( resource_id, sql_class_day );
1305
1306 for ( var season_key in season_names_arr ){
1307
1308 css_classes__for_date.push( season_names_arr[ season_key ] ); // 'wpdevbk_season_september_2023'
1309 }
1310 // -----------------------------------------------------------------------------------------------------------------
1311
1312
1313 // Cost Rate -------------------------------------------------------------------------------------------------------
1314 css_classes__for_date.push( 'rate_' + date_bookings_obj[ resource_id ][ 'date_cost_rate' ].toString().replace( /[\.\s]/g, '_' ) ); // 'rate_99_00' -> 99.00
1315
1316
1317 if ( parseInt( date_bookings_obj[ 'day_availability' ] ) > 0 ){
1318 is_day_selectable = true;
1319 css_classes__for_date.push( 'date_available' );
1320 css_classes__for_date.push( 'reserved_days_count' + parseInt( date_bookings_obj[ 'max_capacity' ] - date_bookings_obj[ 'day_availability' ] ) );
1321 } else {
1322 is_day_selectable = false;
1323 css_classes__for_date.push( 'date_user_unavailable' );
1324 }
1325
1326
1327 switch ( date_bookings_obj[ 'summary']['status_for_day' ] ){
1328
1329 case 'available':
1330 break;
1331
1332 case 'time_slots_booking':
1333 css_classes__for_date.push( 'timespartly', 'times_clock' );
1334 break;
1335
1336 case 'full_day_booking':
1337 css_classes__for_date.push( 'full_day_booking' );
1338 break;
1339
1340 case 'season_filter':
1341 css_classes__for_date.push( 'date_user_unavailable', 'season_unavailable' );
1342 date_bookings_obj[ 'summary']['status_for_bookings' ] = ''; // Reset booking status color for possible old bookings on this date
1343 date_bookings_obj[ 'summary']['status_for_bookings_arr' ] = [];
1344 booking_statuses_arr = [];
1345 break;
1346
1347 case 'resource_availability':
1348 css_classes__for_date.push( 'date_user_unavailable', 'resource_unavailable' );
1349 date_bookings_obj[ 'summary']['status_for_bookings' ] = ''; // Reset booking status color for possible old bookings on this date
1350 date_bookings_obj[ 'summary']['status_for_bookings_arr' ] = [];
1351 booking_statuses_arr = [];
1352 break;
1353
1354 case 'weekday_unavailable':
1355 css_classes__for_date.push( 'date_user_unavailable', 'weekday_unavailable' );
1356 date_bookings_obj[ 'summary']['status_for_bookings' ] = ''; // Reset booking status color for possible old bookings on this date
1357 date_bookings_obj[ 'summary']['status_for_bookings_arr' ] = [];
1358 booking_statuses_arr = [];
1359 break;
1360
1361 case 'from_today_unavailable':
1362 css_classes__for_date.push( 'date_user_unavailable', 'from_today_unavailable' );
1363 date_bookings_obj[ 'summary']['status_for_bookings' ] = ''; // Reset booking status color for possible old bookings on this date
1364 date_bookings_obj[ 'summary']['status_for_bookings_arr' ] = [];
1365 booking_statuses_arr = [];
1366 break;
1367
1368 case 'limit_available_from_today':
1369 css_classes__for_date.push( 'date_user_unavailable', 'limit_available_from_today' );
1370 date_bookings_obj[ 'summary']['status_for_bookings' ] = ''; // Reset booking status color for possible old bookings on this date
1371 date_bookings_obj[ 'summary']['status_for_bookings_arr' ] = [];
1372 booking_statuses_arr = [];
1373 break;
1374
1375 case 'change_over':
1376 /*
1377 *
1378 // check_out_time_date2approve check_in_time_date2approve
1379 // check_out_time_date2approve check_in_time_date_approved
1380 // check_in_time_date2approve check_out_time_date_approved
1381 // check_out_time_date_approved check_in_time_date_approved
1382 */
1383
1384 css_classes__for_date.push( 'timespartly', 'check_in_time', 'check_out_time' );
1385 // FixIn: 10.0.0.2.
1386 if ( wpbc_booking_statuses__has( booking_statuses_arr, 'approved_pending' ) ){
1387 css_classes__for_date.push( 'check_out_time_date_approved', 'check_in_time_date2approve' );
1388 }
1389 if ( wpbc_booking_statuses__has( booking_statuses_arr, 'pending_approved' ) ){
1390 css_classes__for_date.push( 'check_out_time_date2approve', 'check_in_time_date_approved' );
1391 }
1392 break;
1393
1394 case 'check_in':
1395 css_classes__for_date.push( 'timespartly', 'check_in_time' );
1396
1397 // FixIn: 9.9.0.33.
1398 if ( wpbc_booking_statuses__has_part( booking_statuses_arr, 'pending' ) ){
1399 css_classes__for_date.push( 'check_in_time_date2approve' );
1400 } else if ( wpbc_booking_statuses__has_part( booking_statuses_arr, 'approved' ) ){
1401 css_classes__for_date.push( 'check_in_time_date_approved' );
1402 }
1403 break;
1404
1405 case 'check_out':
1406 css_classes__for_date.push( 'timespartly', 'check_out_time' );
1407
1408 // FixIn: 9.9.0.33.
1409 if ( wpbc_booking_statuses__has_part( booking_statuses_arr, 'pending' ) ){
1410 css_classes__for_date.push( 'check_out_time_date2approve' );
1411 } else if ( wpbc_booking_statuses__has_part( booking_statuses_arr, 'approved' ) ){
1412 css_classes__for_date.push( 'check_out_time_date_approved' );
1413 }
1414 break;
1415
1416 default:
1417 // mixed statuses: 'change_over check_out' .... variations.... check more in function wpbc_get_availability_per_days_arr()
1418 date_bookings_obj[ 'summary']['status_for_day' ] = 'available';
1419 }
1420
1421
1422
1423 if ( 'available' != date_bookings_obj[ 'summary']['status_for_day' ] ){
1424
1425 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.
1426
1427 if ( wpbc_booking_statuses__has( booking_statuses_arr, 'pending' ) ){
1428 css_classes__for_date.push( 'date2approve' );
1429 is_day_selectable = (is_day_selectable) ? true : is_set_pending_days_selectable;
1430 }
1431 if ( wpbc_booking_statuses__has( booking_statuses_arr, 'approved' ) ){
1432 css_classes__for_date.push( 'date_approved' );
1433 }
1434 if ( wpbc_booking_statuses__has( booking_statuses_arr, 'pending_pending' ) ){
1435 css_classes__for_date.push( 'check_out_time_date2approve', 'check_in_time_date2approve' );
1436 is_day_selectable = (is_day_selectable) ? true : is_set_pending_days_selectable;
1437 }
1438 if ( wpbc_booking_statuses__has( booking_statuses_arr, 'pending_approved' ) ){
1439 css_classes__for_date.push( 'check_out_time_date2approve', 'check_in_time_date_approved' );
1440 is_day_selectable = (is_day_selectable) ? true : is_set_pending_days_selectable;
1441 }
1442 if ( wpbc_booking_statuses__has( booking_statuses_arr, 'approved_pending' ) ){
1443 css_classes__for_date.push( 'check_out_time_date_approved', 'check_in_time_date2approve' );
1444 is_day_selectable = (is_day_selectable) ? true : is_set_pending_days_selectable;
1445 }
1446 if ( wpbc_booking_statuses__has( booking_statuses_arr, 'approved_approved' ) ){
1447 css_classes__for_date.push( 'check_out_time_date_approved', 'check_in_time_date_approved' );
1448 }
1449 }
1450
1451 return [ is_day_selectable, css_classes__for_date.join( ' ' ) ];
1452 }
1453
1454
1455 /**
1456 * Mouseover calendar date cells
1457 *
1458 * @param string_date
1459 * @param date - JavaScript Date Obj: Mon Dec 11 2023 00:00:00
1460 * GMT+0200 (Eastern European Standard Time)
1461 * @param calendar_params_arr - Calendar Settings Object: {
1462 * "resource_id": 4
1463 * }
1464 * @param datepick_this - this of datepick Obj
1465 * @returns {boolean}
1466 */
1467 function wpbc__calendar__on_hover_days( string_date, date, calendar_params_arr, datepick_this ) {
1468
1469 if ( null === date ) {
1470 wpbc_calendars__clear_days_highlighting( ('undefined' !== typeof (calendar_params_arr[ 'resource_id' ])) ? calendar_params_arr[ 'resource_id' ] : '1' ); // FixIn: 10.5.2.4.
1471 return false;
1472 }
1473
1474 var class_day = wpbc__get__td_class_date( date ); // '1-9-2023'
1475 var sql_class_day = wpbc__get__sql_class_date( date ); // '2023-01-09'
1476 var resource_id = ( 'undefined' !== typeof(calendar_params_arr[ 'resource_id' ]) ) ? calendar_params_arr[ 'resource_id' ] : '1'; // '1'
1477
1478 // Get Data --------------------------------------------------------------------------------------------------------
1479 var date_booking_obj = _wpbc.bookings_in_calendar__get_for_date( resource_id, sql_class_day ); // {...}
1480
1481 if ( ! date_booking_obj ){ return false; }
1482
1483
1484 // T o o l t i p s -------------------------------------------------------------------------------------------------
1485 var tooltip_text = '';
1486 if ( date_booking_obj[ 'summary']['tooltip_availability' ].length > 0 ){
1487 tooltip_text += date_booking_obj[ 'summary']['tooltip_availability' ];
1488 }
1489 if ( date_booking_obj[ 'summary']['tooltip_day_cost' ].length > 0 ){
1490 tooltip_text += date_booking_obj[ 'summary']['tooltip_day_cost' ];
1491 }
1492 if ( date_booking_obj[ 'summary']['tooltip_times' ].length > 0 ){
1493 tooltip_text += date_booking_obj[ 'summary']['tooltip_times' ];
1494 }
1495 if ( date_booking_obj[ 'summary']['tooltip_booking_details' ].length > 0 ){
1496 tooltip_text += date_booking_obj[ 'summary']['tooltip_booking_details' ];
1497 }
1498 wpbc_set_tooltip___for__calendar_date( tooltip_text, resource_id, class_day );
1499
1500
1501
1502 // U n h o v e r i n g in UNSELECTABLE_CALENDAR ------------------------------------------------------------
1503 var is_unselectable_calendar = ( jQuery( '#calendar_booking_unselectable' + resource_id ).length > 0); // FixIn: 8.0.1.2.
1504 var is_booking_form_exist = ( jQuery( '#booking_form_div' + resource_id ).length > 0 );
1505 var is_add_booking_modal_calendar = ( jQuery( '#calendar_booking' + resource_id ).closest( '#wpbc_modal__add_booking__section' ).length > 0 );
1506
1507 if ( ( is_unselectable_calendar ) && ( ! is_booking_form_exist ) ){
1508
1509 /**
1510 * Un Hover all dates in calendar (without the booking form), if only Availability Calendar here and we do
1511 * not insert Booking form by mistake.
1512 */
1513
1514 wpbc_calendars__clear_days_highlighting( resource_id ); // Clear days highlighting
1515
1516 var css_of_calendar = '.wpbc_only_calendar #calendar_booking' + resource_id;
1517 jQuery( css_of_calendar + ' .datepick-days-cell, '
1518 + css_of_calendar + ' .datepick-days-cell a' ).css( 'cursor', 'default' ); // Set cursor to Default
1519 return false;
1520 }
1521
1522
1523
1524 // D a y s H o v e r i n g ------------------------------------------------------------------------------------
1525 if (
1526 ( location.href.indexOf( 'page=wpbc' ) == -1 )
1527 || ( ( location.href.indexOf( 'page=wpbc' ) > 0 ) && ( location.href.indexOf( 'tab=add-booking' ) > 0 ) )
1528 || ( is_add_booking_modal_calendar )
1529 || ( location.href.indexOf( 'page=wpbc-setup' ) > 0 )
1530 || ( location.href.indexOf( 'page=wpbc-availability' ) > 0 )
1531 || ( ( location.href.indexOf( 'page=wpbc-settings' ) > 0 ) &&
1532 ( location.href.indexOf( '&tab=form' ) > 0 )
1533 )
1534 ){
1535 // The same as dates selection, but for days hovering
1536
1537 if ( 'function' == typeof( wpbc__calendar__do_days_highlight__bs ) ){
1538 wpbc__calendar__do_days_highlight__bs( sql_class_day, date, resource_id );
1539 }
1540 }
1541
1542 }
1543
1544
1545 /**
1546 * Select calendar date cells
1547 *
1548 * @param date - JavaScript Date Obj: Mon Dec 11 2023 00:00:00
1549 * GMT+0200 (Eastern European Standard Time)
1550 * @param calendar_params_arr - Calendar Settings Object: {
1551 * "resource_id": 4
1552 * }
1553 * @param datepick_this - this of datepick Obj
1554 *
1555 */
1556 function wpbc__calendar__on_select_days( date, calendar_params_arr, datepick_this ){
1557
1558 var resource_id = ( 'undefined' !== typeof(calendar_params_arr[ 'resource_id' ]) ) ? calendar_params_arr[ 'resource_id' ] : '1'; // '1'
1559
1560 // Set unselectable, if only Availability Calendar here (and we do not insert Booking form by mistake).
1561 var is_unselectable_calendar = ( jQuery( '#calendar_booking_unselectable' + resource_id ).length > 0); // FixIn: 8.0.1.2.
1562 var is_booking_form_exist = ( jQuery( '#booking_form_div' + resource_id ).length > 0 );
1563 if ( ( is_unselectable_calendar ) && ( ! is_booking_form_exist ) ){
1564 wpbc_calendar__unselect_all_dates( resource_id ); // Unselect Dates
1565 jQuery('.wpbc_only_calendar .popover_calendar_hover').remove(); // Hide all opened popovers
1566 return false;
1567 }
1568
1569 jQuery( '#date_booking' + resource_id ).val( date ); // Add selected dates to hidden textarea
1570
1571
1572 if ( 'function' === typeof (wpbc__calendar__do_days_select__bs) ){ wpbc__calendar__do_days_select__bs( date, resource_id ); }
1573
1574 wpbc_disable_time_fields_in_booking_form( resource_id );
1575
1576 // Hook -- trigger day selection -----------------------------------------------------------------------------------
1577 var mouse_clicked_dates = date; // Can be: "05.10.2023 - 07.10.2023" | "10.10.2023 - 10.10.2023" |
1578 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", … ]
1579 jQuery( ".booking_form_div" ).trigger( "date_selected", [ resource_id, mouse_clicked_dates, all_selected_dates_arr ] );
1580 }
1581
1582 // Mark middle selected dates with 0.5 opacity // FixIn: 10.3.0.9.
1583 jQuery( document ).ready( function (){
1584 jQuery( ".booking_form_div" ).on( 'date_selected', function ( event, resource_id, date ){
1585 if (
1586 ( 'fixed' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ))
1587 || ('dynamic' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ))
1588 ){
1589 var closed_timer = setTimeout( function (){
1590 var middle_days_opacity = _wpbc.get_other_param( 'calendars__days_selection__middle_days_opacity' );
1591 jQuery( '#calendar_booking' + resource_id + ' .datepick-current-day' ).not( ".selected_check_in_out" ).css( 'opacity', middle_days_opacity );
1592 }, 10 );
1593 }
1594 } );
1595 } );
1596
1597
1598 /**
1599 * -- T i m e F i e l d s start --------------------------------------------------------------------------
1600 */
1601
1602 /**
1603 * Disable time slots in booking form depend on selected dates and booked dates/times
1604 *
1605 * @param resource_id
1606 */
1607 function wpbc_disable_time_fields_in_booking_form( resource_id ){
1608
1609 /**
1610 * 1. Get all time fields in the booking form as array of objects
1611 * [
1612 * { jquery_option: jQuery_Object {}
1613 * name: 'rangetime2[]'
1614 * times_as_seconds: [ 21600, 23400 ]
1615 * value_option_24h: '06:00 - 06:30'
1616 * }
1617 * ...
1618 * { jquery_option: jQuery_Object {}
1619 * name: 'starttime2[]'
1620 * times_as_seconds: [ 21600 ]
1621 * value_option_24h: '06:00'
1622 * }
1623 * ]
1624 */
1625 var time_fields_obj_arr = wpbc_get__time_fields__in_booking_form__as_arr( resource_id );
1626
1627 // 2. Get all selected dates in SQL format like this [ "2023-08-23", "2023-08-24", "2023-08-25", ... ]
1628 var selected_dates_arr = wpbc_get__selected_dates_sql__as_arr( resource_id );
1629
1630 // 3. Get child booking resources or single booking resource that exist in dates
1631 var child_resources_arr = wpbc_clone_obj( _wpbc.booking__get_param_value( resource_id, 'resources_id_arr__in_dates' ) );
1632
1633 var sql_date;
1634 var child_resource_id;
1635 var merged_seconds;
1636 var time_fields_obj;
1637 var is_intersect;
1638 var is_check_in;
1639
1640 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 );
1641 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 );
1642
1643 // 4. Loop all time Fields options // FixIn: 10.3.0.2.
1644 for ( let field_key = 0; field_key < time_fields_obj_arr.length; field_key++ ){
1645
1646 time_fields_obj_arr[ field_key ].disabled = 0; // By default, this time field is not disabled.
1647
1648 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 {}}
1649
1650 // Loop all selected dates.
1651 for ( var i = 0; i < selected_dates_arr.length; i++ ) {
1652
1653 // Get Date: '2023-08-18'.
1654 sql_date = selected_dates_arr[i];
1655
1656 var is_time_in_past = wpbc_check_is_time_in_past( today_time__shift, sql_date, time_fields_obj );
1657 // Exception for 'End Time' field, when selected several dates. // FixIn: 10.14.1.5.
1658 if ( ('On' !== _wpbc.calendar__get_param_value( resource_id, 'booking_recurrent_time' )) &&
1659 (-1 !== time_fields_obj.name.indexOf( 'endtime' )) &&
1660 (selected_dates_arr.length > 1)
1661 ) {
1662 is_time_in_past = wpbc_check_is_time_in_past( today_time__shift, selected_dates_arr[(selected_dates_arr.length - 1)], time_fields_obj );
1663 }
1664 if ( is_time_in_past ) {
1665 // This time for selected date already in the past.
1666 time_fields_obj_arr[field_key].disabled = 1;
1667 break; // exist from Dates LOOP.
1668 }
1669 // FixIn: 9.9.0.31.
1670 if (
1671 ( 'Off' === _wpbc.calendar__get_param_value( resource_id, 'booking_recurrent_time' ) )
1672 && ( selected_dates_arr.length>1 )
1673 ){
1674 //TODO: skip some fields checking if it's start / end time for mulple dates selection mode.
1675 //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
1676
1677 if ( (0 == i) && (time_fields_obj[ 'name' ].indexOf( 'endtime' ) >= 0) ){
1678 break;
1679 }
1680 if ( ( (selected_dates_arr.length-1) == i ) && (time_fields_obj[ 'name' ].indexOf( 'starttime' ) >= 0) ){
1681 break;
1682 }
1683 }
1684
1685
1686
1687 var how_many_resources_intersected = 0;
1688 // Loop all resources ID
1689 // for ( var res_key in child_resources_arr ){ // FixIn: 10.3.0.2.
1690 if ( null === child_resources_arr ) {
1691 child_resources_arr = [];
1692 }
1693 for ( let res_key = 0; res_key < child_resources_arr.length; res_key++ ){
1694
1695 child_resource_id = child_resources_arr[ res_key ];
1696
1697 // _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" ]
1698 // _wpbc.bookings_in_calendar__get_for_date(2,'2023-08-21')[2].booked_time_slots.merged_seconds = [ [ 25211, 27002 ], [ 36011, 86400 ] ]
1699
1700 if ( false !== _wpbc.bookings_in_calendar__get_for_date( resource_id, sql_date ) ){
1701 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 ] ]
1702 } else {
1703 merged_seconds = [];
1704 }
1705 if ( time_fields_obj.times_as_seconds.length > 1 ){
1706 is_intersect = wpbc_is_intersect__range_time_interval( [
1707 [
1708 ( parseInt( time_fields_obj.times_as_seconds[0] ) + 20 ),
1709 ( parseInt( time_fields_obj.times_as_seconds[1] ) - 20 )
1710 ]
1711 ]
1712 , merged_seconds );
1713 } else {
1714 is_check_in = (-1 !== time_fields_obj.name.indexOf( 'start' ));
1715 is_intersect = wpbc_is_intersect__one_time_interval(
1716 ( ( is_check_in )
1717 ? parseInt( time_fields_obj.times_as_seconds ) + 20
1718 : parseInt( time_fields_obj.times_as_seconds ) - 20
1719 )
1720 , merged_seconds );
1721 }
1722 if (is_intersect){
1723 how_many_resources_intersected++; // Increase
1724 }
1725
1726 }
1727
1728 if ( child_resources_arr.length == how_many_resources_intersected ) {
1729 // 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
1730
1731 time_fields_obj_arr[ field_key ].disabled = 1;
1732 break; // exist from Dates LOOP
1733 }
1734 }
1735 }
1736
1737
1738 // 5. Now we can disable time slot in HTML by using ( field.disabled == 1 ) property
1739 wpbc__html__time_field_options__set_disabled( time_fields_obj_arr );
1740
1741 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.
1742 }
1743
1744
1745 /**
1746 * Check if specific time(-slot) already in the past for selected date
1747 *
1748 * @param js_current_time_to_check - JS Date
1749 * @param sql_date - '2025-01-26'
1750 * @param time_fields_obj - Object
1751 * @returns {boolean}
1752 */
1753 function wpbc_check_is_time_in_past( js_current_time_to_check, sql_date, time_fields_obj ) {
1754
1755 // FixIn: 10.9.6.4
1756 var sql_date_arr = sql_date.split( '-' );
1757 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 );
1758 var sql_date__midnight_miliseconds = sql_date__midnight.getTime();
1759
1760 var is_intersect = false;
1761
1762 if ( time_fields_obj.times_as_seconds.length > 1 ) {
1763
1764 if ( js_current_time_to_check.getTime() > (sql_date__midnight_miliseconds + (parseInt( time_fields_obj.times_as_seconds[0] ) + 20) * 1000) ) {
1765 is_intersect = true;
1766 }
1767 if ( js_current_time_to_check.getTime() > (sql_date__midnight_miliseconds + (parseInt( time_fields_obj.times_as_seconds[1] ) - 20) * 1000) ) {
1768 is_intersect = true;
1769 }
1770
1771 } else {
1772 var is_check_in = (-1 !== time_fields_obj.name.indexOf( 'start' ));
1773
1774 var times_as_seconds_check = (is_check_in) ? parseInt( time_fields_obj.times_as_seconds ) + 20 : parseInt( time_fields_obj.times_as_seconds ) - 20;
1775
1776 times_as_seconds_check = sql_date__midnight_miliseconds + times_as_seconds_check * 1000;
1777
1778 if ( js_current_time_to_check.getTime() > times_as_seconds_check ) {
1779 is_intersect = true;
1780 }
1781 }
1782
1783 return is_intersect;
1784 }
1785
1786 /**
1787 * Is number inside /intersect of array of intervals ?
1788 *
1789 * @param time_A - 25800
1790 * @param time_interval_B - [ [ 25211, 27002 ], [ 36011, 86400 ] ]
1791 * @returns {boolean}
1792 */
1793 function wpbc_is_intersect__one_time_interval( time_A, time_interval_B ){
1794
1795 for ( var j = 0; j < time_interval_B.length; j++ ){
1796
1797 if ( (parseInt( time_A ) > parseInt( time_interval_B[ j ][ 0 ] )) && (parseInt( time_A ) < parseInt( time_interval_B[ j ][ 1 ] )) ){
1798 return true
1799 }
1800
1801 // if ( ( parseInt( time_A ) == parseInt( time_interval_B[ j ][ 0 ] ) ) || ( parseInt( time_A ) == parseInt( time_interval_B[ j ][ 1 ] ) ) ) {
1802 // // Time A just at the border of interval
1803 // }
1804 }
1805
1806 return false;
1807 }
1808
1809 /**
1810 * Is these array of intervals intersected ?
1811 *
1812 * @param time_interval_A - [ [ 21600, 23400 ] ]
1813 * @param time_interval_B - [ [ 25211, 27002 ], [ 36011, 86400 ] ]
1814 * @returns {boolean}
1815 */
1816 function wpbc_is_intersect__range_time_interval( time_interval_A, time_interval_B ){
1817
1818 var is_intersect;
1819
1820 for ( var i = 0; i < time_interval_A.length; i++ ){
1821
1822 for ( var j = 0; j < time_interval_B.length; j++ ){
1823
1824 is_intersect = wpbc_intervals__is_intersected( time_interval_A[ i ], time_interval_B[ j ] );
1825
1826 if ( is_intersect ){
1827 return true;
1828 }
1829 }
1830 }
1831
1832 return false;
1833 }
1834
1835 /**
1836 * Get all time fields in the booking form as array of objects
1837 *
1838 * @param resource_id
1839 * @returns []
1840 *
1841 * Example:
1842 * [
1843 * {
1844 * value_option_24h: '06:00 - 06:30'
1845 * times_as_seconds: [ 21600, 23400 ]
1846 * jquery_option: jQuery_Object {}
1847 * name: 'rangetime2[]'
1848 * }
1849 * ...
1850 * {
1851 * value_option_24h: '06:00'
1852 * times_as_seconds: [ 21600 ]
1853 * jquery_option: jQuery_Object {}
1854 * name: 'starttime2[]'
1855 * }
1856 * ]
1857 */
1858 function wpbc_get__time_fields__in_booking_form__as_arr( resource_id ){
1859 /**
1860 * Fields with [] like this select[name="rangetime1[]"]
1861 * it's when we have 'multiple' in shortcode: [select* rangetime multiple "06:00 - 06:30" ... ]
1862 */
1863 var time_fields_arr=[
1864 'select[name="rangetime' + resource_id + '"]',
1865 'select[name="rangetime' + resource_id + '[]"]',
1866 'select[name="starttime' + resource_id + '"]',
1867 'select[name="starttime' + resource_id + '[]"]',
1868 'select[name="endtime' + resource_id + '"]',
1869 'select[name="endtime' + resource_id + '[]"]'
1870 ];
1871
1872 var time_fields_obj_arr = [];
1873
1874 // Loop all Time Fields
1875 for ( var ctf= 0; ctf < time_fields_arr.length; ctf++ ){
1876
1877 var time_field = time_fields_arr[ ctf ];
1878 var time_option = jQuery( time_field + ' option' );
1879
1880 // Loop all options in time field
1881 for ( var j = 0; j < time_option.length; j++ ){
1882
1883 var jquery_option = jQuery( time_field + ' option:eq(' + j + ')' );
1884 var value_option_seconds_arr = jquery_option.val().split( '-' );
1885 var times_as_seconds = [];
1886
1887 // Get time as seconds
1888 if ( value_option_seconds_arr.length ){ // FixIn: 9.8.10.1.
1889 for ( let i = 0; i < value_option_seconds_arr.length; i++ ){ // FixIn: 10.0.0.56.
1890 // value_option_seconds_arr[i] = '14:00 ' | ' 16:00' (if from 'rangetime') and '16:00' if (start/end time)
1891
1892 var start_end_times_arr = value_option_seconds_arr[ i ].trim().split( ':' );
1893
1894 var time_in_seconds = parseInt( start_end_times_arr[ 0 ] ) * 60 * 60 + parseInt( start_end_times_arr[ 1 ] ) * 60;
1895
1896 times_as_seconds.push( time_in_seconds );
1897 }
1898 }
1899
1900 time_fields_obj_arr.push( {
1901 'name' : jQuery( time_field ).attr( 'name' ),
1902 'value_option_24h': jquery_option.val(),
1903 'jquery_option' : jquery_option,
1904 'times_as_seconds': times_as_seconds
1905 } );
1906 }
1907 }
1908
1909 return time_fields_obj_arr;
1910 }
1911
1912 /**
1913 * Disable HTML options and add booked CSS class
1914 *
1915 * @param time_fields_obj_arr - this value is from the func:
1916 * wpbc_get__time_fields__in_booking_form__as_arr( resource_id )
1917 * [
1918 * { jquery_option: jQuery_Object {}
1919 * name: 'rangetime2[]'
1920 * times_as_seconds: [ 21600, 23400 ]
1921 * value_option_24h: '06:00 - 06:30'
1922 * disabled = 1
1923 * }
1924 * ...
1925 * { jquery_option: jQuery_Object {}
1926 * name: 'starttime2[]'
1927 * times_as_seconds: [ 21600 ]
1928 * value_option_24h: '06:00'
1929 * disabled = 0
1930 * }
1931 * ]
1932 *
1933 */
1934 function wpbc__html__time_field_options__set_disabled( time_fields_obj_arr ){
1935
1936 var jquery_option;
1937
1938 for ( var i = 0; i < time_fields_obj_arr.length; i++ ){
1939
1940 var jquery_option = time_fields_obj_arr[ i ].jquery_option;
1941
1942 if ( 1 == time_fields_obj_arr[ i ].disabled ){
1943 jquery_option.prop( 'disabled', true ); // Make disable some options
1944 jquery_option.addClass( 'booked' ); // Add "booked" CSS class
1945
1946 // if this booked element selected --> then deselect it
1947 if ( jquery_option.prop( 'selected' ) ){
1948 jquery_option.prop( 'selected', false );
1949
1950 jquery_option.parent().find( 'option:not([disabled]):first' ).prop( 'selected', true ).trigger( "change" );
1951 }
1952
1953 } else {
1954 jquery_option.prop( 'disabled', false ); // Make active all times
1955 jquery_option.removeClass( 'booked' ); // Remove class "booked"
1956 }
1957 }
1958
1959 }
1960
1961 /**
1962 * Check if this time_range | Time_Slot is Full Day booked
1963 *
1964 * @param timeslot_arr_in_seconds - [ 36011, 86400 ]
1965 * @returns {boolean}
1966 */
1967 function wpbc_is_this_timeslot__full_day_booked( timeslot_arr_in_seconds ){
1968
1969 if (
1970 ( timeslot_arr_in_seconds.length > 1 )
1971 && ( parseInt( timeslot_arr_in_seconds[ 0 ] ) < 30 )
1972 && ( parseInt( timeslot_arr_in_seconds[ 1 ] ) > ( (24 * 60 * 60) - 30) )
1973 ){
1974 return true;
1975 }
1976
1977 return false;
1978 }
1979
1980
1981 // -----------------------------------------------------------------------------------------------------------------
1982 /* == S e l e c t e d D a t e s / T i m e - F i e l d s ==
1983 // ----------------------------------------------------------------------------------------------------------------- */
1984
1985 /**
1986 * Get all selected dates in SQL format like this [ "2023-08-23", "2023-08-24" , ... ]
1987 *
1988 * @param resource_id
1989 * @returns {[]} [ "2023-08-23", "2023-08-24", "2023-08-25", "2023-08-26", "2023-08-27", "2023-08-28",
1990 * "2023-08-29" ]
1991 */
1992 function wpbc_get__selected_dates_sql__as_arr( resource_id ){
1993
1994 var selected_dates_arr = [];
1995 selected_dates_arr = jQuery( '#date_booking' + resource_id ).val().split(',');
1996
1997 if ( selected_dates_arr.length ){ // FixIn: 9.8.10.1.
1998 for ( let i = 0; i < selected_dates_arr.length; i++ ){ // FixIn: 10.0.0.56.
1999 selected_dates_arr[ i ] = selected_dates_arr[ i ].trim();
2000 selected_dates_arr[ i ] = selected_dates_arr[ i ].split( '.' );
2001 if ( selected_dates_arr[ i ].length > 1 ){
2002 selected_dates_arr[ i ] = selected_dates_arr[ i ][ 2 ] + '-' + selected_dates_arr[ i ][ 1 ] + '-' + selected_dates_arr[ i ][ 0 ];
2003 }
2004 }
2005 }
2006
2007 // Remove empty elements from an array
2008 selected_dates_arr = selected_dates_arr.filter( function ( n ){ return parseInt(n); } );
2009
2010 selected_dates_arr.sort();
2011
2012 return selected_dates_arr;
2013 }
2014
2015
2016 /**
2017 * Get all time fields in the booking form as array of objects
2018 *
2019 * @param resource_id
2020 * @param is_only_selected_time
2021 * @returns []
2022 *
2023 * Example:
2024 * [
2025 * {
2026 * value_option_24h: '06:00 - 06:30'
2027 * times_as_seconds: [ 21600, 23400 ]
2028 * jquery_option: jQuery_Object {}
2029 * name: 'rangetime2[]'
2030 * }
2031 * ...
2032 * {
2033 * value_option_24h: '06:00'
2034 * times_as_seconds: [ 21600 ]
2035 * jquery_option: jQuery_Object {}
2036 * name: 'starttime2[]'
2037 * }
2038 * ]
2039 */
2040 function wpbc_get__selected_time_fields__in_booking_form__as_arr( resource_id, is_only_selected_time = true ){
2041 /**
2042 * Fields with [] like this select[name="rangetime1[]"]
2043 * it's when we have 'multiple' in shortcode: [select* rangetime multiple "06:00 - 06:30" ... ]
2044 */
2045 var time_fields_arr=[
2046 'select[name="rangetime' + resource_id + '"]',
2047 'select[name="rangetime' + resource_id + '[]"]',
2048 'select[name="starttime' + resource_id + '"]',
2049 'select[name="starttime' + resource_id + '[]"]',
2050 'select[name="endtime' + resource_id + '"]',
2051 'select[name="endtime' + resource_id + '[]"]',
2052 'select[name="durationtime' + resource_id + '"]',
2053 'select[name="durationtime' + resource_id + '[]"]'
2054 ];
2055
2056 var time_fields_obj_arr = [];
2057
2058 // Loop all Time Fields
2059 for ( var ctf= 0; ctf < time_fields_arr.length; ctf++ ){
2060
2061 var time_field = time_fields_arr[ ctf ];
2062
2063 var time_option;
2064 if ( is_only_selected_time ){
2065 time_option = jQuery( '#booking_form' + resource_id + ' ' + time_field + ' option:selected' ); // Exclude conditional fields, because of using '#booking_form3 ...'
2066 } else {
2067 time_option = jQuery( '#booking_form' + resource_id + ' ' + time_field + ' option' ); // All time fields
2068 }
2069
2070
2071 // Loop all options in time field
2072 for ( var j = 0; j < time_option.length; j++ ){
2073
2074 var jquery_option = jQuery( time_option[ j ] ); // Get only selected options //jQuery( time_field + ' option:eq(' + j + ')' );
2075 var value_option_seconds_arr = jquery_option.val().split( '-' );
2076 var times_as_seconds = [];
2077
2078 // Get time as seconds
2079 if ( value_option_seconds_arr.length ){ // FixIn: 9.8.10.1.
2080 for ( let i = 0; i < value_option_seconds_arr.length; i++ ){ // FixIn: 10.0.0.56.
2081 // value_option_seconds_arr[i] = '14:00 ' | ' 16:00' (if from 'rangetime') and '16:00' if (start/end time)
2082
2083 var start_end_times_arr = value_option_seconds_arr[ i ].trim().split( ':' );
2084
2085 var time_in_seconds = parseInt( start_end_times_arr[ 0 ] ) * 60 * 60 + parseInt( start_end_times_arr[ 1 ] ) * 60;
2086
2087 times_as_seconds.push( time_in_seconds );
2088 }
2089 }
2090
2091 time_fields_obj_arr.push( {
2092 'name' : jQuery( '#booking_form' + resource_id + ' ' + time_field ).attr( 'name' ),
2093 'value_option_24h': jquery_option.val(),
2094 'jquery_option' : jquery_option,
2095 'times_as_seconds': times_as_seconds
2096 } );
2097 }
2098 }
2099
2100 // Text: [starttime] - [endtime] -----------------------------------------------------------------------------
2101
2102 var text_time_fields_arr=[
2103 'input[name="starttime' + resource_id + '"]',
2104 'input[name="endtime' + resource_id + '"]',
2105 ];
2106 for ( var tf= 0; tf < text_time_fields_arr.length; tf++ ){
2107
2108 var text_jquery = jQuery( '#booking_form' + resource_id + ' ' + text_time_fields_arr[ tf ] ); // Exclude conditional fields, because of using '#booking_form3 ...'
2109 if ( text_jquery.length > 0 ){
2110
2111 var time__h_m__arr = text_jquery.val().trim().split( ':' ); // '14:00'
2112 if ( 0 == time__h_m__arr.length ){
2113 continue; // Not entered time value in a field
2114 }
2115 if ( 1 == time__h_m__arr.length ){
2116 if ( '' === time__h_m__arr[ 0 ] ){
2117 continue; // Not entered time value in a field
2118 }
2119 time__h_m__arr[ 1 ] = 0;
2120 }
2121 var text_time_in_seconds = parseInt( time__h_m__arr[ 0 ] ) * 60 * 60 + parseInt( time__h_m__arr[ 1 ] ) * 60;
2122
2123 var text_times_as_seconds = [];
2124 text_times_as_seconds.push( text_time_in_seconds );
2125
2126 time_fields_obj_arr.push( {
2127 'name' : text_jquery.attr( 'name' ),
2128 'value_option_24h': text_jquery.val(),
2129 'jquery_option' : text_jquery,
2130 'times_as_seconds': text_times_as_seconds
2131 } );
2132 }
2133 }
2134
2135 return time_fields_obj_arr;
2136 }
2137
2138
2139
2140 // ---------------------------------------------------------------------------------------------------------------------
2141 /* == S U P P O R T for C A L E N D A R ==
2142 // --------------------------------------------------------------------------------------------------------------------- */
2143
2144 /**
2145 * Get Calendar datepick Instance.
2146 *
2147 * @param {int|string} resource_id
2148 * @returns {*|null}
2149 */
2150 function wpbc_calendar__get_inst(resource_id) {
2151
2152 if ( 'undefined' === typeof (resource_id) ) {
2153 resource_id = '1';
2154 }
2155
2156 if ( jQuery( '#calendar_booking' + resource_id ).length > 0 ) {
2157
2158 try {
2159 var inst = jQuery.datepick._getInst( jQuery( '#calendar_booking' + resource_id ).get( 0 ) );
2160 return inst ? inst : null;
2161 } catch ( e ) {
2162 return null;
2163 }
2164 }
2165
2166 return null;
2167 }
2168
2169
2170 /**
2171 * Unselect all dates in calendar and visually update this calendar
2172 *
2173 * @param resource_id ID of booking resource
2174 * @returns {boolean} true on success | false, if no such calendar
2175 */
2176 function wpbc_calendar__unselect_all_dates( resource_id ){
2177
2178 if ( 'undefined' === typeof (resource_id) ){
2179 resource_id = '1';
2180 }
2181
2182 var inst = wpbc_calendar__get_inst( resource_id )
2183
2184 if ( null !== inst ){
2185
2186 // Unselect all dates and set properties of Datepick
2187 jQuery( '#date_booking' + resource_id ).val( '' ); //FixIn: 5.4.3
2188 inst.stayOpen = false;
2189 inst.dates = [];
2190 jQuery.datepick._updateDatepick( inst );
2191
2192 return true
2193 }
2194
2195 return false;
2196
2197 }
2198
2199 /**
2200 * Clear days highlighting in All or specific Calendars
2201 *
2202 * @param resource_id - can be skiped to clear highlighting in all calendars
2203 */
2204 function wpbc_calendars__clear_days_highlighting( resource_id ){
2205
2206 if ( 'undefined' !== typeof ( resource_id ) ){
2207
2208 jQuery( '#calendar_booking' + resource_id + ' .datepick-days-cell-over' ).removeClass( 'datepick-days-cell-over' ); // Clear in specific calendar
2209
2210 } else {
2211 jQuery( '.datepick-days-cell-over' ).removeClass( 'datepick-days-cell-over' ); // Clear in all calendars
2212 }
2213 }
2214
2215 /**
2216 * Scroll to specific month in calendar
2217 *
2218 * @param resource_id ID of resource
2219 * @param year - real year - 2023
2220 * @param month - real month - 12
2221 * @returns {boolean}
2222 */
2223 function wpbc_calendar__scroll_to( resource_id, year, month ){
2224
2225 if ( 'undefined' === typeof (resource_id) ){ resource_id = '1'; }
2226 var inst = wpbc_calendar__get_inst( resource_id )
2227 if ( null !== inst ){
2228
2229 year = parseInt( year );
2230 month = parseInt( month ) - 1; // In JS date, month -1
2231
2232 inst.cursorDate = new Date();
2233 // In some cases, the setFullYear can set only Year, and not the Month and day // FixIn: 6.2.3.5.
2234 inst.cursorDate.setFullYear( year, month, 1 );
2235 inst.cursorDate.setMonth( month );
2236 inst.cursorDate.setDate( 1 );
2237
2238 inst.drawMonth = inst.cursorDate.getMonth();
2239 inst.drawYear = inst.cursorDate.getFullYear();
2240
2241 jQuery.datepick._notifyChange( inst );
2242 jQuery.datepick._adjustInstDate( inst );
2243 jQuery.datepick._showDate( inst );
2244 jQuery.datepick._updateDatepick( inst );
2245
2246 return true;
2247 }
2248 return false;
2249 }
2250
2251 /**
2252 * Is this date selectable in calendar (mainly it's means AVAILABLE date)
2253 *
2254 * @param {int|string} resource_id 1
2255 * @param {string} sql_class_day '2023-08-11'
2256 * @returns {boolean} true | false
2257 */
2258 function wpbc_is_this_day_selectable( resource_id, sql_class_day ){
2259
2260 // Get Data --------------------------------------------------------------------------------------------------------
2261 var date_bookings_obj = _wpbc.bookings_in_calendar__get_for_date( resource_id, sql_class_day );
2262
2263 var is_day_selectable = ( parseInt( date_bookings_obj[ 'day_availability' ] ) > 0 );
2264
2265 if ( typeof (date_bookings_obj[ 'summary' ]) === 'undefined' ){
2266 return is_day_selectable;
2267 }
2268
2269 if ( 'available' != date_bookings_obj[ 'summary']['status_for_day' ] ){
2270
2271 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.
2272 var booking_statuses_arr = wpbc_get_booking_statuses__as_arr( date_bookings_obj );
2273
2274 if (
2275 ( wpbc_booking_statuses__has( booking_statuses_arr, 'pending' ) )
2276 || ( wpbc_booking_statuses__has( booking_statuses_arr, 'pending_pending' ) )
2277 || ( wpbc_booking_statuses__has( booking_statuses_arr, 'pending_approved' ) )
2278 || ( wpbc_booking_statuses__has( booking_statuses_arr, 'approved_pending' ) )
2279 ){
2280 is_day_selectable = (is_day_selectable) ? true : is_set_pending_days_selectable;
2281 }
2282 }
2283
2284 return is_day_selectable;
2285 }
2286
2287 /**
2288 * Is date to check IN array of selected dates
2289 *
2290 * @param {date}js_date_to_check - JS Date - simple JavaScript Date object
2291 * @param {[]} js_dates_arr - [ JSDate, ... ] - array of JS dates
2292 * @returns {boolean}
2293 */
2294 function wpbc_is_this_day_among_selected_days( js_date_to_check, js_dates_arr ){
2295
2296 for ( var date_index = 0; date_index < js_dates_arr.length ; date_index++ ){ // FixIn: 8.4.5.16.
2297 if ( ( js_dates_arr[ date_index ].getFullYear() === js_date_to_check.getFullYear() ) &&
2298 ( js_dates_arr[ date_index ].getMonth() === js_date_to_check.getMonth() ) &&
2299 ( js_dates_arr[ date_index ].getDate() === js_date_to_check.getDate() ) ) {
2300 return true;
2301 }
2302 }
2303
2304 return false;
2305 }
2306
2307 /**
2308 * Get SQL Class Date '2023-08-01' from JS Date
2309 *
2310 * @param date JS Date
2311 * @returns {string} '2023-08-12'
2312 */
2313 function wpbc__get__sql_class_date( date ){
2314
2315 var sql_class_day = date.getFullYear() + '-';
2316 sql_class_day += ( ( date.getMonth() + 1 ) < 10 ) ? '0' : '';
2317 sql_class_day += ( date.getMonth() + 1 ) + '-'
2318 sql_class_day += ( date.getDate() < 10 ) ? '0' : '';
2319 sql_class_day += date.getDate();
2320
2321 return sql_class_day;
2322 }
2323
2324 /**
2325 * Get JS Date from the SQL date format '2024-05-14'
2326 * @param sql_class_date
2327 * @returns {Date}
2328 */
2329 function wpbc__get__js_date( sql_class_date ){
2330
2331 var sql_class_date_arr = sql_class_date.split( '-' );
2332
2333 var date_js = new Date();
2334
2335 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
2336
2337 // Without this time adjust Dates selection in Datepicker can not work!!!
2338 date_js.setHours(0);
2339 date_js.setMinutes(0);
2340 date_js.setSeconds(0);
2341 date_js.setMilliseconds(0);
2342
2343 return date_js;
2344 }
2345
2346 /**
2347 * Get TD Class Date '1-31-2023' from JS Date
2348 *
2349 * @param date JS Date
2350 * @returns {string} '1-31-2023'
2351 */
2352 function wpbc__get__td_class_date( date ){
2353
2354 var td_class_day = (date.getMonth() + 1) + '-' + date.getDate() + '-' + date.getFullYear(); // '1-9-2023'
2355
2356 return td_class_day;
2357 }
2358
2359 /**
2360 * Get date params from string date
2361 *
2362 * @param date string date like '31.5.2023'
2363 * @param separator default '.' can be skipped.
2364 * @returns { {date: number, month: number, year: number} }
2365 */
2366 function wpbc__get__date_params__from_string_date( date , separator){
2367
2368 separator = ( 'undefined' !== typeof (separator) ) ? separator : '.';
2369
2370 var date_arr = date.split( separator );
2371 var date_obj = {
2372 'year' : parseInt( date_arr[ 2 ] ),
2373 'month': (parseInt( date_arr[ 1 ] ) - 1),
2374 'date' : parseInt( date_arr[ 0 ] )
2375 };
2376 return date_obj; // for = new Date( date_obj.year , date_obj.month , date_obj.date );
2377 }
2378
2379 /**
2380 * Add Spin Loader to calendar
2381 * @param resource_id
2382 */
2383 function wpbc_calendar__loading__start( resource_id ){
2384 if ( ! jQuery( '#calendar_booking' + resource_id ).next().hasClass( 'wpbc_spins_loader_wrapper' ) ){
2385 jQuery( '#calendar_booking' + resource_id ).after( '<div class="wpbc_spins_loader_wrapper"><div class="wpbc_spin_loader_one_new"></div></div>' );
2386 }
2387 if ( ! jQuery( '#calendar_booking' + resource_id ).hasClass( 'wpbc_calendar_blur_small' ) ){
2388 jQuery( '#calendar_booking' + resource_id ).addClass( 'wpbc_calendar_blur_small' );
2389 }
2390 wpbc_calendar__blur__start( resource_id );
2391 }
2392
2393 /**
2394 * Remove Spin Loader to calendar
2395 * @param resource_id
2396 */
2397 function wpbc_calendar__loading__stop( resource_id ){
2398 jQuery( '#calendar_booking' + resource_id + ' + .wpbc_spins_loader_wrapper' ).remove();
2399 jQuery( '#calendar_booking' + resource_id ).removeClass( 'wpbc_calendar_blur_small' );
2400 wpbc_calendar__blur__stop( resource_id );
2401 }
2402
2403 /**
2404 * Add Blur to calendar
2405 * @param resource_id
2406 */
2407 function wpbc_calendar__blur__start( resource_id ){
2408 if ( ! jQuery( '#calendar_booking' + resource_id ).hasClass( 'wpbc_calendar_blur' ) ){
2409 jQuery( '#calendar_booking' + resource_id ).addClass( 'wpbc_calendar_blur' );
2410 }
2411 }
2412
2413 /**
2414 * Remove Blur in calendar
2415 * @param resource_id
2416 */
2417 function wpbc_calendar__blur__stop( resource_id ){
2418 jQuery( '#calendar_booking' + resource_id ).removeClass( 'wpbc_calendar_blur' );
2419 }
2420
2421
2422 // .................................................................................................................
2423 /* == Calendar Update - View ==
2424 // ................................................................................................................. */
2425
2426 /**
2427 * Update look of calendar (safe).
2428 *
2429 * In Elementor preview the DOM can be re-rendered, so the calendar element may exist
2430 * while the Datepick instance is missing. In that case try to (re)initialize.
2431 *
2432 * @param {int|string} resource_id
2433 * @return {boolean} true if updated, false if not possible
2434 */
2435 function wpbc_calendar__update_look(resource_id) {
2436
2437 var inst = wpbc_calendar__get_inst( resource_id );
2438
2439 // If instance missing, try to re-init calendar once.
2440 if ( null === inst ) {
2441
2442 var jq_cal = jQuery( '#calendar_booking' + resource_id );
2443
2444 if ( jq_cal.length && ('function' === typeof wpbc_calendar_show) ) {
2445
2446 // Elementor sometimes leaves stale class without real instance.
2447 if ( jq_cal.hasClass( 'hasDatepick' ) ) {
2448 jq_cal.removeClass( 'hasDatepick' );
2449 }
2450
2451 // Try to init datepick markup now.
2452 wpbc_calendar_show( resource_id );
2453
2454 // Try again.
2455 inst = wpbc_calendar__get_inst( resource_id );
2456 }
2457 }
2458
2459 // Still no instance -> do not crash the whole ajax flow.
2460 if ( null === inst ) {
2461 return false;
2462 }
2463
2464 jQuery.datepick._updateDatepick( inst );
2465 return true;
2466 }
2467
2468
2469
2470 /**
2471 * Update dynamically Number of Months in calendar
2472 *
2473 * @param resource_id int
2474 * @param months_number int
2475 */
2476 function wpbc_calendar__update_months_number( resource_id, months_number ){
2477 var inst = wpbc_calendar__get_inst( resource_id );
2478 if ( null !== inst ){
2479 inst.settings[ 'numberOfMonths' ] = months_number;
2480 //_wpbc.calendar__set_param_value( resource_id, 'calendar_number_of_months', months_number );
2481 wpbc_calendar__update_look( resource_id );
2482 }
2483 }
2484
2485
2486 /**
2487 * Show calendar in different Skin
2488 *
2489 * @param selected_skin_url
2490 */
2491 function wpbc__calendar__change_skin( selected_skin_url ){
2492
2493 //console.log( 'SKIN SELECTION ::', selected_skin_url );
2494
2495 // Remove CSS skin
2496 var stylesheet = document.getElementById( 'wpbc-calendar-skin-css' );
2497 stylesheet.parentNode.removeChild( stylesheet );
2498
2499
2500 // Add new CSS skin
2501 var headID = document.getElementsByTagName( "head" )[ 0 ];
2502 var cssNode = document.createElement( 'link' );
2503 cssNode.type = 'text/css';
2504 cssNode.setAttribute( "id", "wpbc-calendar-skin-css" );
2505 cssNode.rel = 'stylesheet';
2506 cssNode.media = 'screen';
2507 cssNode.href = selected_skin_url; //"http://beta/wp-content/plugins/booking/css/skins/green-01.css";
2508 headID.appendChild( cssNode );
2509 }
2510
2511
2512 function wpbc__css__change_skin( selected_skin_url, stylesheet_id = 'wpbc-time_picker-skin-css' ){
2513
2514 // Remove CSS skin
2515 var stylesheet = document.getElementById( stylesheet_id );
2516 stylesheet.parentNode.removeChild( stylesheet );
2517
2518
2519 // Add new CSS skin
2520 var headID = document.getElementsByTagName( "head" )[ 0 ];
2521 var cssNode = document.createElement( 'link' );
2522 cssNode.type = 'text/css';
2523 cssNode.setAttribute( "id", stylesheet_id );
2524 cssNode.rel = 'stylesheet';
2525 cssNode.media = 'screen';
2526 cssNode.href = selected_skin_url; //"http://beta/wp-content/plugins/booking/css/skins/green-01.css";
2527 headID.appendChild( cssNode );
2528 }
2529
2530
2531 // ---------------------------------------------------------------------------------------------------------------------
2532 /* == S U P P O R T M A T H ==
2533 // --------------------------------------------------------------------------------------------------------------------- */
2534
2535 /**
2536 * Merge several intersected intervals or return not intersected:
2537 * [[1,3],[2,6],[8,10],[15,18]] -> [[1,6],[8,10],[15,18]]
2538 *
2539 * @param [] intervals [ [1,3],[2,4],[6,8],[9,10],[3,7] ]
2540 * @returns [] [ [1,8],[9,10] ]
2541 *
2542 * Exmample: wpbc_intervals__merge_inersected( [ [1,3],[2,4],[6,8],[9,10],[3,7] ] );
2543 */
2544 function wpbc_intervals__merge_inersected( intervals ){
2545
2546 if ( ! intervals || intervals.length === 0 ){
2547 return [];
2548 }
2549
2550 var merged = [];
2551 intervals.sort( function ( a, b ){
2552 return a[ 0 ] - b[ 0 ];
2553 } );
2554
2555 var mergedInterval = intervals[ 0 ];
2556
2557 for ( var i = 1; i < intervals.length; i++ ){
2558 var interval = intervals[ i ];
2559
2560 if ( interval[ 0 ] <= mergedInterval[ 1 ] ){
2561 mergedInterval[ 1 ] = Math.max( mergedInterval[ 1 ], interval[ 1 ] );
2562 } else {
2563 merged.push( mergedInterval );
2564 mergedInterval = interval;
2565 }
2566 }
2567
2568 merged.push( mergedInterval );
2569 return merged;
2570 }
2571
2572
2573 /**
2574 * Is 2 intervals intersected: [36011, 86392] <=> [1, 43192] => true ( intersected )
2575 *
2576 * Good explanation here
2577 * https://stackoverflow.com/questions/3269434/whats-the-most-efficient-way-to-test-if-two-ranges-overlap
2578 *
2579 * @param interval_A - [ 36011, 86392 ]
2580 * @param interval_B - [ 1, 43192 ]
2581 *
2582 * @return bool
2583 */
2584 function wpbc_intervals__is_intersected( interval_A, interval_B ) {
2585
2586 if (
2587 ( 0 == interval_A.length )
2588 || ( 0 == interval_B.length )
2589 ){
2590 return false;
2591 }
2592
2593 interval_A[ 0 ] = parseInt( interval_A[ 0 ] );
2594 interval_A[ 1 ] = parseInt( interval_A[ 1 ] );
2595 interval_B[ 0 ] = parseInt( interval_B[ 0 ] );
2596 interval_B[ 1 ] = parseInt( interval_B[ 1 ] );
2597
2598 var is_intersected = Math.max( interval_A[ 0 ], interval_B[ 0 ] ) - Math.min( interval_A[ 1 ], interval_B[ 1 ] );
2599
2600 // if ( 0 == is_intersected ) {
2601 // // Such ranges going one after other, e.g.: [ 12, 15 ] and [ 15, 21 ]
2602 // }
2603
2604 if ( is_intersected < 0 ) {
2605 return true; // INTERSECTED
2606 }
2607
2608 return false; // Not intersected
2609 }
2610
2611
2612 /**
2613 * Get the closets ABS value of element in array to the current myValue
2614 *
2615 * @param myValue - int element to search closet 4
2616 * @param myArray - array of elements where to search [5,8,1,7]
2617 * @returns int 5
2618 */
2619 function wpbc_get_abs_closest_value_in_arr( myValue, myArray ){
2620
2621 if ( myArray.length == 0 ){ // If the array is empty -> return the myValue
2622 return myValue;
2623 }
2624
2625 var obj = myArray[ 0 ];
2626 var diff = Math.abs( myValue - obj ); // Get distance between 1st element
2627 var closetValue = myArray[ 0 ]; // Save 1st element
2628
2629 for ( var i = 1; i < myArray.length; i++ ){
2630 obj = myArray[ i ];
2631
2632 if ( Math.abs( myValue - obj ) < diff ){ // we found closer value -> save it
2633 diff = Math.abs( myValue - obj );
2634 closetValue = obj;
2635 }
2636 }
2637
2638 return closetValue;
2639 }
2640
2641
2642 // ---------------------------------------------------------------------------------------------------------------------
2643 /* == T O O L T I P S ==
2644 // --------------------------------------------------------------------------------------------------------------------- */
2645
2646 /**
2647 * Define tooltip to show, when mouse over Date in Calendar
2648 *
2649 * @param tooltip_text - Text to show 'Booked time: 12:00 - 13:00<br>Cost: $20.00'
2650 * @param resource_id - ID of booking resource '1'
2651 * @param td_class - SQL class '1-9-2023'
2652 * @returns {boolean} - defined to show or not
2653 */
2654 function wpbc_set_tooltip___for__calendar_date( tooltip_text, resource_id, td_class ){
2655
2656 //TODO: make escaping of text for quot symbols, and JS/HTML...
2657
2658 jQuery( '#calendar_booking' + resource_id + ' td.cal4date-' + td_class ).attr( 'data-content', tooltip_text );
2659
2660 var td_el = jQuery( '#calendar_booking' + resource_id + ' td.cal4date-' + td_class ).get( 0 ); // FixIn: 9.0.1.1.
2661
2662 if (
2663 ( 'undefined' !== typeof(td_el) )
2664 && ( undefined == td_el._tippy )
2665 && ( '' !== tooltip_text )
2666 ){
2667
2668 wpbc_tippy( td_el , {
2669 content( reference ){
2670
2671 var popover_content = reference.getAttribute( 'data-content' );
2672
2673 return '<div class="popover popover_tippy">'
2674 + '<div class="popover-content">'
2675 + popover_content
2676 + '</div>'
2677 + '</div>';
2678 },
2679 allowHTML : true,
2680 trigger : 'mouseenter focus',
2681 interactive : false,
2682 hideOnClick : true,
2683 interactiveBorder: 10,
2684 maxWidth : 550,
2685 theme : 'wpbc-tippy-times',
2686 placement : 'top',
2687 delay : [400, 0], // FixIn: 9.4.2.2.
2688 //delay : [0, 9999999999], // Debuge tooltip
2689 ignoreAttributes : true,
2690 touch : true, //['hold', 500], // 500ms delay // FixIn: 9.2.1.5.
2691 appendTo: () => document.body,
2692 });
2693
2694 return true;
2695 }
2696
2697 return false;
2698 }
2699
2700
2701 // ---------------------------------------------------------------------------------------------------------------------
2702 /* == Dates Functions ==
2703 // --------------------------------------------------------------------------------------------------------------------- */
2704
2705 /**
2706 * Get number of dates between 2 JS Dates
2707 *
2708 * @param date1 JS Date
2709 * @param date2 JS Date
2710 * @returns {number}
2711 */
2712 function wpbc_dates__days_between(date1, date2) {
2713
2714 // The number of milliseconds in one day
2715 var ONE_DAY = 1000 * 60 * 60 * 24;
2716
2717 // Convert both dates to milliseconds
2718 var date1_ms = date1.getTime();
2719 var date2_ms = date2.getTime();
2720
2721 // Calculate the difference in milliseconds
2722 var difference_ms = date1_ms - date2_ms;
2723
2724 // Convert back to days and return
2725 return Math.round(difference_ms/ONE_DAY);
2726 }
2727
2728
2729 /**
2730 * Check if this array of dates is consecutive array of dates or not.
2731 * e.g. ['2024-05-09','2024-05-19','2024-05-30'] -> false
2732 * e.g. ['2024-05-09','2024-05-10','2024-05-11'] -> true
2733 * @param sql_dates_arr array e.g.: ['2024-05-09','2024-05-19','2024-05-30']
2734 * @returns {boolean}
2735 */
2736 function wpbc_dates__is_consecutive_dates_arr_range( sql_dates_arr ){ // FixIn: 10.0.0.50.
2737
2738 if ( sql_dates_arr.length > 1 ){
2739 var previos_date = wpbc__get__js_date( sql_dates_arr[ 0 ] );
2740 var current_date;
2741
2742 for ( var i = 1; i < sql_dates_arr.length; i++ ){
2743 current_date = wpbc__get__js_date( sql_dates_arr[i] );
2744
2745 if ( wpbc_dates__days_between( current_date, previos_date ) != 1 ){
2746 return false;
2747 }
2748
2749 previos_date = current_date;
2750 }
2751 }
2752
2753 return true;
2754 }
2755
2756
2757 // ---------------------------------------------------------------------------------------------------------------------
2758 /* == Auto Dates Selection ==
2759 // --------------------------------------------------------------------------------------------------------------------- */
2760
2761 /**
2762 * == How to use ? ==
2763 *
2764 * For Dates selection, we need to use this logic! We need select the dates only after booking data loaded!
2765 *
2766 * Check example bellow.
2767 *
2768 * // Fire on all booking dates loaded
2769 * jQuery( 'body' ).on( 'wpbc_calendar_ajx__loaded_data', function ( event, loaded_resource_id ){
2770 *
2771 * if ( loaded_resource_id == select_dates_in_calendar_id ){
2772 * wpbc_auto_select_dates_in_calendar( select_dates_in_calendar_id, '2024-05-15', '2024-05-25' );
2773 * }
2774 * } );
2775 *
2776 */
2777
2778
2779 /**
2780 * Try to Auto select dates in specific calendar by simulated clicks in datepicker
2781 *
2782 * @param resource_id 1
2783 * @param check_in_ymd '2024-05-09' OR ['2024-05-09','2024-05-19','2024-05-20']
2784 * @param check_out_ymd '2024-05-15' Optional
2785 *
2786 * @returns {number} number of selected dates
2787 *
2788 * Example 1: var num_selected_days = wpbc_auto_select_dates_in_calendar( 1, '2024-05-15',
2789 * '2024-05-25' ); Example 2: var num_selected_days = wpbc_auto_select_dates_in_calendar( 1,
2790 * ['2024-05-09','2024-05-19','2024-05-20'] );
2791 */
2792 function wpbc_auto_select_dates_in_calendar( resource_id, check_in_ymd, check_out_ymd = '' ){ // FixIn: 10.0.0.47.
2793
2794 console.log( 'WPBC_AUTO_SELECT_DATES_IN_CALENDAR( RESOURCE_ID, CHECK_IN_YMD, CHECK_OUT_YMD )', resource_id, check_in_ymd, check_out_ymd );
2795
2796 if (
2797 ( '2100-01-01' == check_in_ymd )
2798 || ( '2100-01-01' == check_out_ymd )
2799 || ( ( '' == check_in_ymd ) && ( '' == check_out_ymd ) )
2800 ){
2801 return 0;
2802 }
2803
2804 // -----------------------------------------------------------------------------------------------------------------
2805 // If check_in_ymd = [ '2024-05-09','2024-05-19','2024-05-30' ] ARRAY of DATES // FixIn: 10.0.0.50.
2806 // -----------------------------------------------------------------------------------------------------------------
2807 var dates_to_select_arr = [];
2808 if ( Array.isArray( check_in_ymd ) ){
2809 dates_to_select_arr = wpbc_clone_obj( check_in_ymd );
2810
2811 // -------------------------------------------------------------------------------------------------------------
2812 // Exceptions to set MULTIPLE DAYS mode
2813 // -------------------------------------------------------------------------------------------------------------
2814 // if dates as NOT CONSECUTIVE: ['2024-05-09','2024-05-19','2024-05-30'], -> set MULTIPLE DAYS mode
2815 if (
2816 ( dates_to_select_arr.length > 0 )
2817 && ( '' == check_out_ymd )
2818 && ( ! wpbc_dates__is_consecutive_dates_arr_range( dates_to_select_arr ) )
2819 ){
2820 wpbc_cal_days_select__multiple( resource_id );
2821 }
2822 // if multiple days to select, but enabled SINGLE day mode, -> set MULTIPLE DAYS mode
2823 if (
2824 ( dates_to_select_arr.length > 1 )
2825 && ( '' == check_out_ymd )
2826 && ( 'single' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ) )
2827 ){
2828 wpbc_cal_days_select__multiple( resource_id );
2829 }
2830 // -------------------------------------------------------------------------------------------------------------
2831 check_in_ymd = dates_to_select_arr[ 0 ];
2832 if ( '' == check_out_ymd ){
2833 check_out_ymd = dates_to_select_arr[ (dates_to_select_arr.length-1) ];
2834 }
2835 }
2836 // -----------------------------------------------------------------------------------------------------------------
2837
2838
2839 if ( '' == check_in_ymd ){
2840 check_in_ymd = check_out_ymd;
2841 }
2842 if ( '' == check_out_ymd ){
2843 check_out_ymd = check_in_ymd;
2844 }
2845
2846 if ( 'undefined' === typeof (resource_id) ){
2847 resource_id = '1';
2848 }
2849
2850
2851 var inst = wpbc_calendar__get_inst( resource_id );
2852
2853 if ( null !== inst ){
2854
2855 // Unselect all dates and set properties of Datepick
2856 jQuery( '#date_booking' + resource_id ).val( '' ); //FixIn: 5.4.3
2857 inst.stayOpen = false;
2858 inst.dates = [];
2859 var check_in_js = wpbc__get__js_date( check_in_ymd );
2860 var td_cell = wpbc_get_clicked_td( inst.id, check_in_js );
2861
2862 // Is ome type of error, then select multiple days selection mode.
2863 if ( '' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ) ) {
2864 _wpbc.calendar__set_param_value( resource_id, 'days_select_mode', 'multiple' );
2865 }
2866
2867
2868 // ---------------------------------------------------------------------------------------------------------
2869 // == DYNAMIC ==
2870 if ( 'dynamic' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ) ){
2871 // 1-st click
2872 inst.stayOpen = false;
2873 jQuery.datepick._selectDay( td_cell, '#' + inst.id, check_in_js.getTime() );
2874 if ( 0 === inst.dates.length ){
2875 return 0; // First click was unsuccessful, so we must not make other click
2876 }
2877
2878 // 2-nd click
2879 var check_out_js = wpbc__get__js_date( check_out_ymd );
2880 var td_cell_out = wpbc_get_clicked_td( inst.id, check_out_js );
2881 inst.stayOpen = true;
2882 jQuery.datepick._selectDay( td_cell_out, '#' + inst.id, check_out_js.getTime() );
2883 }
2884
2885 // ---------------------------------------------------------------------------------------------------------
2886 // == FIXED ==
2887 if ( 'fixed' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' )) {
2888 jQuery.datepick._selectDay( td_cell, '#' + inst.id, check_in_js.getTime() );
2889 }
2890
2891 // ---------------------------------------------------------------------------------------------------------
2892 // == SINGLE ==
2893 if ( 'single' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ) ){
2894 //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!
2895 jQuery.datepick._selectDay( td_cell, '#' + inst.id, check_in_js.getTime() );
2896 }
2897
2898 // ---------------------------------------------------------------------------------------------------------
2899 // == MULTIPLE ==
2900 if ( 'multiple' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ) ){
2901
2902 var dates_arr;
2903
2904 if ( dates_to_select_arr.length > 0 ){
2905 // 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
2906 dates_arr = wpbc_get_selection_dates_js_str_arr__from_arr( dates_to_select_arr );
2907 } else {
2908 dates_arr = wpbc_get_selection_dates_js_str_arr__from_check_in_out( check_in_ymd, check_out_ymd, inst );
2909 }
2910
2911 if ( 0 === dates_arr.dates_js.length ){
2912 return 0;
2913 }
2914
2915 // For Calendar Days selection
2916 for ( var j = 0; j < dates_arr.dates_js.length; j++ ){ // Loop array of dates
2917
2918 var str_date = wpbc__get__sql_class_date( dates_arr.dates_js[ j ] );
2919
2920 // Date unavailable !
2921 if ( 0 == _wpbc.bookings_in_calendar__get_for_date( resource_id, str_date ).day_availability ){
2922 return 0;
2923 }
2924
2925 if ( dates_arr.dates_js[ j ] != -1 ) {
2926 inst.dates.push( dates_arr.dates_js[ j ] );
2927 }
2928 }
2929
2930 var check_out_date = dates_arr.dates_js[ (dates_arr.dates_js.length - 1) ];
2931
2932 inst.dates.push( check_out_date ); // Need add one additional SAME date for correct works of dates selection !!!!!
2933
2934 var checkout_timestamp = check_out_date.getTime();
2935 var td_cell = wpbc_get_clicked_td( inst.id, check_out_date );
2936
2937 jQuery.datepick._selectDay( td_cell, '#' + inst.id, checkout_timestamp );
2938 }
2939
2940
2941 if ( 0 !== inst.dates.length ){
2942 // Scroll to specific month, if we set dates in some future months
2943 wpbc_calendar__scroll_to( resource_id, inst.dates[ 0 ].getFullYear(), inst.dates[ 0 ].getMonth()+1 );
2944 }
2945
2946 return inst.dates.length;
2947 }
2948
2949 return 0;
2950 }
2951
2952 /**
2953 * Get HTML td element (where was click in calendar day cell)
2954 *
2955 * @param calendar_html_id 'calendar_booking1'
2956 * @param date_js JS Date
2957 * @returns {*|jQuery} Dom HTML td element
2958 */
2959 function wpbc_get_clicked_td( calendar_html_id, date_js ){
2960
2961 var td_cell = jQuery( '#' + calendar_html_id + ' .sql_date_' + wpbc__get__sql_class_date( date_js ) ).get( 0 );
2962
2963 return td_cell;
2964 }
2965
2966 /**
2967 * Get arrays of JS and SQL dates as dates array
2968 *
2969 * @param check_in_ymd '2024-05-15'
2970 * @param check_out_ymd '2024-05-25'
2971 * @param inst Datepick Inst. Use wpbc_calendar__get_inst( resource_id );
2972 * @returns {{dates_js: *[], dates_str: *[]}}
2973 */
2974 function wpbc_get_selection_dates_js_str_arr__from_check_in_out( check_in_ymd, check_out_ymd , inst ){
2975
2976 var original_array = [];
2977 var date;
2978 var bk_distinct_dates = [];
2979
2980 var check_in_date = check_in_ymd.split( '-' );
2981 var check_out_date = check_out_ymd.split( '-' );
2982
2983 date = new Date();
2984 date.setFullYear( check_in_date[ 0 ], (check_in_date[ 1 ] - 1), check_in_date[ 2 ] ); // year, month, date
2985 var original_check_in_date = date;
2986 original_array.push( jQuery.datepick._restrictMinMax( inst, jQuery.datepick._determineDate( inst, date, null ) ) ); //add date
2987 if ( ! wpbc_in_array( bk_distinct_dates, (check_in_date[ 2 ] + '.' + check_in_date[ 1 ] + '.' + check_in_date[ 0 ]) ) ){
2988 bk_distinct_dates.push( parseInt(check_in_date[ 2 ]) + '.' + parseInt(check_in_date[ 1 ]) + '.' + check_in_date[ 0 ] );
2989 }
2990
2991 var date_out = new Date();
2992 date_out.setFullYear( check_out_date[ 0 ], (check_out_date[ 1 ] - 1), check_out_date[ 2 ] ); // year, month, date
2993 var original_check_out_date = date_out;
2994
2995 var mewDate = new Date( original_check_in_date.getFullYear(), original_check_in_date.getMonth(), original_check_in_date.getDate() );
2996 mewDate.setDate( original_check_in_date.getDate() + 1 );
2997
2998 while (
2999 (original_check_out_date > date) &&
3000 (original_check_in_date != original_check_out_date) ){
3001 date = new Date( mewDate.getFullYear(), mewDate.getMonth(), mewDate.getDate() );
3002
3003 original_array.push( jQuery.datepick._restrictMinMax( inst, jQuery.datepick._determineDate( inst, date, null ) ) ); //add date
3004 if ( !wpbc_in_array( bk_distinct_dates, (date.getDate() + '.' + parseInt( date.getMonth() + 1 ) + '.' + date.getFullYear()) ) ){
3005 bk_distinct_dates.push( (parseInt(date.getDate()) + '.' + parseInt( date.getMonth() + 1 ) + '.' + date.getFullYear()) );
3006 }
3007
3008 mewDate = new Date( date.getFullYear(), date.getMonth(), date.getDate() );
3009 mewDate.setDate( mewDate.getDate() + 1 );
3010 }
3011 original_array.pop();
3012 bk_distinct_dates.pop();
3013
3014 return {'dates_js': original_array, 'dates_str': bk_distinct_dates};
3015 }
3016
3017 /**
3018 * Get arrays of JS and SQL dates as dates array
3019 *
3020 * @param dates_to_select_arr = ['2024-05-09','2024-05-19','2024-05-30']
3021 *
3022 * @returns {{dates_js: *[], dates_str: *[]}}
3023 */
3024 function wpbc_get_selection_dates_js_str_arr__from_arr( dates_to_select_arr ){ // FixIn: 10.0.0.50.
3025
3026 var original_array = [];
3027 var bk_distinct_dates = [];
3028 var one_date_str;
3029
3030 for ( var d = 0; d < dates_to_select_arr.length; d++ ){
3031
3032 original_array.push( wpbc__get__js_date( dates_to_select_arr[ d ] ) );
3033
3034 one_date_str = dates_to_select_arr[ d ].split('-')
3035 if ( ! wpbc_in_array( bk_distinct_dates, (one_date_str[ 2 ] + '.' + one_date_str[ 1 ] + '.' + one_date_str[ 0 ]) ) ){
3036 bk_distinct_dates.push( parseInt(one_date_str[ 2 ]) + '.' + parseInt(one_date_str[ 1 ]) + '.' + one_date_str[ 0 ] );
3037 }
3038 }
3039
3040 return {'dates_js': original_array, 'dates_str': original_array};
3041 }
3042
3043 // =====================================================================================================================
3044 /* == Auto Fill Fields / Auto Select Dates ==
3045 // ===================================================================================================================== */
3046
3047 jQuery( document ).ready( function (){
3048
3049 var url_params = new URLSearchParams( window.location.search );
3050
3051 // Disable days selection in calendar, after redirection from the "Search results page, after search availability" // FixIn: 8.8.2.3.
3052 if ( 'On' != _wpbc.get_other_param( 'is_enabled_booking_search_results_days_select' ) ) {
3053 if (
3054 ( url_params.has( 'wpbc_select_check_in' ) ) &&
3055 ( url_params.has( 'wpbc_select_check_out' ) ) &&
3056 ( url_params.has( 'wpbc_select_calendar_id' ) )
3057 ){
3058
3059 var select_dates_in_calendar_id = parseInt( url_params.get( 'wpbc_select_calendar_id' ) );
3060
3061 // Fire on all booking dates loaded
3062 jQuery( 'body' ).on( 'wpbc_calendar_ajx__loaded_data', function ( event, loaded_resource_id ){
3063
3064 if ( loaded_resource_id == select_dates_in_calendar_id ){
3065 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' ) );
3066 }
3067 } );
3068 }
3069 }
3070
3071 if ( url_params.has( 'wpbc_auto_fill' ) ){
3072
3073 var wpbc_auto_fill_value = url_params.get( 'wpbc_auto_fill' );
3074
3075 // Convert back. Some systems do not like symbol '~' in URL, so we need to replace to some other symbols
3076 wpbc_auto_fill_value = wpbc_auto_fill_value.replaceAll( '_^_', '~' );
3077
3078 wpbc_auto_fill_booking_fields( wpbc_auto_fill_value );
3079 }
3080
3081 } );
3082
3083 /**
3084 * Autofill / select booking form fields by values from the GET request parameter: ?wpbc_auto_fill=
3085 *
3086 * @param auto_fill_str
3087 */
3088 function wpbc_auto_fill_booking_fields( auto_fill_str ){ // FixIn: 10.0.0.48.
3089
3090 if ( '' == auto_fill_str ){
3091 return;
3092 }
3093
3094 // console.log( 'WPBC_AUTO_FILL_BOOKING_FIELDS( AUTO_FILL_STR )', auto_fill_str);
3095
3096 var fields_arr = wpbc_auto_fill_booking_fields__parse( auto_fill_str );
3097
3098 for ( let i = 0; i < fields_arr.length; i++ ){
3099 jQuery( '[name="' + fields_arr[ i ][ 'name' ] + '"]' ).val( fields_arr[ i ][ 'value' ] );
3100 }
3101 }
3102
3103 /**
3104 * Parse data from get parameter: ?wpbc_auto_fill=visitors231^2~max_capacity231^2
3105 *
3106 * @param data_str = 'visitors231^2~max_capacity231^2';
3107 * @returns {*}
3108 */
3109 function wpbc_auto_fill_booking_fields__parse( data_str ){
3110
3111 var filter_options_arr = [];
3112
3113 var data_arr = data_str.split( '~' );
3114
3115 for ( var j = 0; j < data_arr.length; j++ ){
3116
3117 var my_form_field = data_arr[ j ].split( '^' );
3118
3119 var filter_name = ('undefined' !== typeof (my_form_field[ 0 ])) ? my_form_field[ 0 ] : '';
3120 var filter_value = ('undefined' !== typeof (my_form_field[ 1 ])) ? my_form_field[ 1 ] : '';
3121
3122 filter_options_arr.push(
3123 {
3124 'name' : filter_name,
3125 'value' : filter_value
3126 }
3127 );
3128 }
3129 return filter_options_arr;
3130 }
3131
3132 /**
3133 * Parse data from get parameter: ?search_get__custom_params=...
3134 *
3135 * @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^~';
3136 * @returns {*}
3137 */
3138 function wpbc_auto_fill_search_fields__parse( data_str ){
3139
3140 var filter_options_arr = [];
3141
3142 var data_arr = data_str.split( '~' );
3143
3144 for ( var j = 0; j < data_arr.length; j++ ){
3145
3146 var my_form_field = data_arr[ j ].split( '^' );
3147
3148 var filter_type = ('undefined' !== typeof (my_form_field[ 0 ])) ? my_form_field[ 0 ] : '';
3149 var filter_name = ('undefined' !== typeof (my_form_field[ 1 ])) ? my_form_field[ 1 ] : '';
3150 var filter_value = ('undefined' !== typeof (my_form_field[ 2 ])) ? my_form_field[ 2 ] : '';
3151
3152 filter_options_arr.push(
3153 {
3154 'type' : filter_type,
3155 'name' : filter_name,
3156 'value' : filter_value
3157 }
3158 );
3159 }
3160 return filter_options_arr;
3161 }
3162
3163
3164 // ---------------------------------------------------------------------------------------------------------------------
3165 /* == Auto Update number of months in calendars ON screen size changed ==
3166 // --------------------------------------------------------------------------------------------------------------------- */
3167
3168 /**
3169 * Auto Update Number of Months in Calendar, e.g.: if ( WINDOW_WIDTH <= 782px ) >>> MONTHS_NUMBER = 1
3170 * ELSE: number of months defined in shortcode.
3171 * @param resource_id int
3172 *
3173 */
3174 function wpbc_calendar__auto_update_months_number__on_resize( resource_id ){
3175
3176 if ( true === _wpbc.get_other_param( 'is_allow_several_months_on_mobile' ) ) {
3177 return false;
3178 }
3179
3180 var local__number_of_months = parseInt( _wpbc.calendar__get_param_value( resource_id, 'calendar_number_of_months' ) );
3181
3182 if ( local__number_of_months > 1 ){
3183
3184 if ( jQuery( window ).width() <= 782 ){
3185 wpbc_calendar__update_months_number( resource_id, 1 );
3186 } else {
3187 wpbc_calendar__update_months_number( resource_id, local__number_of_months );
3188 }
3189
3190 }
3191 }
3192
3193 /**
3194 * Auto Update Number of Months in ALL Calendars
3195 *
3196 */
3197 function wpbc_calendars__auto_update_months_number(){
3198
3199 var all_calendars_arr = _wpbc.calendars_all__get();
3200
3201 // This LOOP "for in" is GOOD, because we check here keys 'calendar_' === calendar_id.slice( 0, 9 )
3202 for ( var calendar_id in all_calendars_arr ){
3203 if ( 'calendar_' === calendar_id.slice( 0, 9 ) ){
3204 var resource_id = parseInt( calendar_id.slice( 9 ) ); // 'calendar_3' -> 3
3205 if ( resource_id > 0 ){
3206 wpbc_calendar__auto_update_months_number__on_resize( resource_id );
3207 }
3208 }
3209 }
3210 }
3211
3212 /**
3213 * If browser window changed, then update number of months.
3214 */
3215 jQuery( window ).on( 'resize', function (){
3216 wpbc_calendars__auto_update_months_number();
3217 } );
3218
3219 /**
3220 * Auto update calendar number of months on initial page load
3221 */
3222 jQuery( document ).ready( function (){
3223 var closed_timer = setTimeout( function (){
3224 wpbc_calendars__auto_update_months_number();
3225 }, 100 );
3226 });
3227
3228 // ---------------------------------------------------------------------------------------------------------------------
3229 /* == Check: calendar_dates_start: "2026-01-01", calendar_dates_end: "2026-12-31" == // FixIn: 10.13.1.4.
3230 // --------------------------------------------------------------------------------------------------------------------- */
3231 /**
3232 * Get Start JS Date of starting dates in calendar, from the _wpbc object.
3233 *
3234 * @param integer resource_id - resource ID, e.g.: 1.
3235 */
3236 function wpbc_calendar__get_dates_start( resource_id ) {
3237 return wpbc_calendar__get_date_parameter( resource_id, 'calendar_dates_start' );
3238 }
3239
3240 /**
3241 * Get End JS Date of ending dates in calendar, from the _wpbc object.
3242 *
3243 * @param integer resource_id - resource ID, e.g.: 1.
3244 */
3245 function wpbc_calendar__get_dates_end(resource_id) {
3246 return wpbc_calendar__get_date_parameter( resource_id, 'calendar_dates_end' );
3247 }
3248
3249 /**
3250 * Get validates date parameter.
3251 *
3252 * @param resource_id - 1
3253 * @param parameter_str - 'calendar_dates_start' | 'calendar_dates_end' | ...
3254 */
3255 function wpbc_calendar__get_date_parameter(resource_id, parameter_str) {
3256
3257 var date_expected_ymd = _wpbc.calendar__get_param_value( resource_id, parameter_str );
3258
3259 if ( ! date_expected_ymd ) {
3260 return false; // '' | 0 | null | undefined -> false.
3261 }
3262
3263 if ( -1 !== date_expected_ymd.indexOf( '-' ) ) {
3264
3265 var date_expected_ymd_arr = date_expected_ymd.split( '-' ); // '2025-07-26' -> ['2025', '07', '26']
3266
3267 if ( date_expected_ymd_arr.length > 0 ) {
3268 var year = (date_expected_ymd_arr.length > 0) ? parseInt( date_expected_ymd_arr[0] ) : new Date().getFullYear(); // Year.
3269 var month = (date_expected_ymd_arr.length > 1) ? (parseInt( date_expected_ymd_arr[1] ) - 1) : 0; // (month - 1) or 0 - Jan.
3270 var day = (date_expected_ymd_arr.length > 2) ? parseInt( date_expected_ymd_arr[2] ) : 1; // date or Otherwise 1st of month
3271
3272 var date_js = new Date( year, month, day, 0, 0, 0, 0 );
3273
3274 return date_js;
3275 }
3276 }
3277
3278 return false; // Fallback, if we not parsed this parameter 'calendar_dates_start' = '2025-07-26', for example because of 'calendar_dates_start' = 'sfsdf'.
3279 }
3280
3281 /**
3282 * ====================================================================================================================
3283 * includes/__js/cal/days_select_custom.js
3284 * ====================================================================================================================
3285 */
3286
3287 // FixIn: 9.8.9.2.
3288
3289 /**
3290 * Re-Init Calendar and Re-Render it.
3291 *
3292 * @param resource_id
3293 */
3294 function wpbc_cal__re_init( resource_id ){
3295
3296 // Remove CLASS for ability to re-render and reinit calendar.
3297 jQuery( '#calendar_booking' + resource_id ).removeClass( 'hasDatepick' );
3298 wpbc_calendar_show( resource_id );
3299 }
3300
3301
3302 /**
3303 * Re-Init previously saved days selection variables.
3304 *
3305 * @param resource_id
3306 */
3307 function wpbc_cal_days_select__re_init( resource_id ){
3308
3309 _wpbc.calendar__set_param_value( resource_id, 'saved_variable___days_select_initial'
3310 , {
3311 'dynamic__days_min' : _wpbc.calendar__get_param_value( resource_id, 'dynamic__days_min' ),
3312 'dynamic__days_max' : _wpbc.calendar__get_param_value( resource_id, 'dynamic__days_max' ),
3313 'dynamic__days_specific' : _wpbc.calendar__get_param_value( resource_id, 'dynamic__days_specific' ),
3314 'dynamic__week_days__start': _wpbc.calendar__get_param_value( resource_id, 'dynamic__week_days__start' ),
3315 'fixed__days_num' : _wpbc.calendar__get_param_value( resource_id, 'fixed__days_num' ),
3316 'fixed__week_days__start' : _wpbc.calendar__get_param_value( resource_id, 'fixed__week_days__start' )
3317 }
3318 );
3319 }
3320
3321 // ---------------------------------------------------------------------------------------------------------------------
3322
3323 /**
3324 * Set Single Day selection - after page load
3325 *
3326 * @param resource_id ID of booking resource
3327 */
3328 function wpbc_cal_ready_days_select__single( resource_id ){
3329
3330 // Re-define selection, only after page loaded with all init vars
3331 jQuery(document).ready(function(){
3332
3333 // Wait 1 second, just to be sure, that all init vars defined
3334 setTimeout(function(){
3335
3336 wpbc_cal_days_select__single( resource_id );
3337
3338 }, 1000);
3339 });
3340 }
3341
3342 /**
3343 * Set Single Day selection
3344 * Can be run at any time, when calendar defined - useful for console run.
3345 *
3346 * @param resource_id ID of booking resource
3347 */
3348 function wpbc_cal_days_select__single( resource_id ){
3349
3350 _wpbc.calendar__set_parameters( resource_id, {'days_select_mode': 'single'} );
3351
3352 wpbc_cal_days_select__re_init( resource_id );
3353 wpbc_cal__re_init( resource_id );
3354 }
3355
3356 // ---------------------------------------------------------------------------------------------------------------------
3357
3358 /**
3359 * Set Multiple Days selection - after page load
3360 *
3361 * @param resource_id ID of booking resource
3362 */
3363 function wpbc_cal_ready_days_select__multiple( resource_id ){
3364
3365 // Re-define selection, only after page loaded with all init vars
3366 jQuery(document).ready(function(){
3367
3368 // Wait 1 second, just to be sure, that all init vars defined
3369 setTimeout(function(){
3370
3371 wpbc_cal_days_select__multiple( resource_id );
3372
3373 }, 1000);
3374 });
3375 }
3376
3377
3378 /**
3379 * Set Multiple Days selection
3380 * Can be run at any time, when calendar defined - useful for console run.
3381 *
3382 * @param resource_id ID of booking resource
3383 */
3384 function wpbc_cal_days_select__multiple( resource_id ){
3385
3386 _wpbc.calendar__set_parameters( resource_id, {'days_select_mode': 'multiple'} );
3387
3388 wpbc_cal_days_select__re_init( resource_id );
3389 wpbc_cal__re_init( resource_id );
3390 }
3391
3392
3393 // ---------------------------------------------------------------------------------------------------------------------
3394
3395 /**
3396 * Set Fixed Days selection with 1 mouse click - after page load
3397 *
3398 * @integer resource_id - 1 -- ID of booking resource (calendar) -
3399 * @integer days_number - 3 -- number of days to select -
3400 * @array week_days__start - [-1] | [ 1, 5] -- { -1 - Any | 0 - Su, 1 - Mo, 2 - Tu, 3 - We, 4 - Th, 5 - Fr, 6 - Sat }
3401 */
3402 function wpbc_cal_ready_days_select__fixed( resource_id, days_number, week_days__start = [-1] ){
3403
3404 // Re-define selection, only after page loaded with all init vars
3405 jQuery(document).ready(function(){
3406
3407 // Wait 1 second, just to be sure, that all init vars defined
3408 setTimeout(function(){
3409
3410 wpbc_cal_days_select__fixed( resource_id, days_number, week_days__start );
3411
3412 }, 1000);
3413 });
3414 }
3415
3416
3417 /**
3418 * Set Fixed Days selection with 1 mouse click
3419 * Can be run at any time, when calendar defined - useful for console run.
3420 *
3421 * @integer resource_id - 1 -- ID of booking resource (calendar) -
3422 * @integer days_number - 3 -- number of days to select -
3423 * @array week_days__start - [-1] | [ 1, 5] -- { -1 - Any | 0 - Su, 1 - Mo, 2 - Tu, 3 - We, 4 - Th, 5 - Fr, 6 - Sat }
3424 */
3425 function wpbc_cal_days_select__fixed( resource_id, days_number, week_days__start = [-1] ){
3426
3427 _wpbc.calendar__set_parameters( resource_id, {'days_select_mode': 'fixed'} );
3428
3429 _wpbc.calendar__set_parameters( resource_id, {'fixed__days_num': parseInt( days_number )} ); // Number of days selection with 1 mouse click
3430 _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 }
3431
3432 wpbc_cal_days_select__re_init( resource_id );
3433 wpbc_cal__re_init( resource_id );
3434 }
3435
3436 // ---------------------------------------------------------------------------------------------------------------------
3437
3438 /**
3439 * Set Range Days selection with 2 mouse clicks - after page load
3440 *
3441 * @integer resource_id - 1 -- ID of booking resource (calendar)
3442 * @integer days_min - 7 -- Min number of days to select
3443 * @integer days_max - 30 -- Max number of days to select
3444 * @array days_specific - [] | [7,14,21,28] -- Restriction for Specific number of days selection
3445 * @array week_days__start - [-1] | [ 1, 5] -- { -1 - Any | 0 - Su, 1 - Mo, 2 - Tu, 3 - We, 4 - Th, 5 - Fr, 6 - Sat }
3446 */
3447 function wpbc_cal_ready_days_select__range( resource_id, days_min, days_max, days_specific = [], week_days__start = [-1] ){
3448
3449 // Re-define selection, only after page loaded with all init vars
3450 jQuery(document).ready(function(){
3451
3452 // Wait 1 second, just to be sure, that all init vars defined
3453 setTimeout(function(){
3454
3455 wpbc_cal_days_select__range( resource_id, days_min, days_max, days_specific, week_days__start );
3456 }, 1000);
3457 });
3458 }
3459
3460 /**
3461 * Set Range Days selection with 2 mouse clicks
3462 * Can be run at any time, when calendar defined - useful for console run.
3463 *
3464 * @integer resource_id - 1 -- ID of booking resource (calendar)
3465 * @integer days_min - 7 -- Min number of days to select
3466 * @integer days_max - 30 -- Max number of days to select
3467 * @array days_specific - [] | [7,14,21,28] -- Restriction for Specific number of days selection
3468 * @array week_days__start - [-1] | [ 1, 5] -- { -1 - Any | 0 - Su, 1 - Mo, 2 - Tu, 3 - We, 4 - Th, 5 - Fr, 6 - Sat }
3469 */
3470 function wpbc_cal_days_select__range( resource_id, days_min, days_max, days_specific = [], week_days__start = [-1] ){
3471
3472 _wpbc.calendar__set_parameters( resource_id, {'days_select_mode': 'dynamic'} );
3473 _wpbc.calendar__set_param_value( resource_id, 'dynamic__days_min' , parseInt( days_min ) ); // Min. Number of days selection with 2 mouse clicks
3474 _wpbc.calendar__set_param_value( resource_id, 'dynamic__days_max' , parseInt( days_max ) ); // Max. Number of days selection with 2 mouse clicks
3475 _wpbc.calendar__set_param_value( resource_id, 'dynamic__days_specific' , days_specific ); // Example [5,7]
3476 _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 }
3477
3478 wpbc_cal_days_select__re_init( resource_id );
3479 wpbc_cal__re_init( resource_id );
3480 }
3481
3482 /**
3483 * ====================================================================================================================
3484 * includes/__js/cal_ajx_load/wpbc_cal_ajx.js
3485 * ====================================================================================================================
3486 */
3487
3488 // ---------------------------------------------------------------------------------------------------------------------
3489 // A j a x L o a d C a l e n d a r D a t a
3490 // ---------------------------------------------------------------------------------------------------------------------
3491
3492 function wpbc_calendar__load_data__ajx( params ){
3493
3494 // FixIn: 9.8.6.2.
3495 wpbc_calendar__loading__start( params['resource_id'] );
3496
3497 // Trigger event for calendar before loading Booking data, but after showing Calendar.
3498 if ( jQuery( '#calendar_booking' + params['resource_id'] ).length > 0 ){
3499 var target_elm = jQuery( 'body' ).trigger( "wpbc_calendar_ajx__before_loaded_data", [params['resource_id']] );
3500 //jQuery( 'body' ).on( 'wpbc_calendar_ajx__before_loaded_data', function( event, resource_id ) { ... } );
3501 }
3502
3503 if ( wpbc_balancer__is_wait( params , 'wpbc_calendar__load_data__ajx' ) ){
3504 return false;
3505 }
3506
3507 // FixIn: 9.8.6.2.
3508 wpbc_calendar__blur__stop( params['resource_id'] );
3509
3510 // -----------------------------------------------------------------------------------------------------------------
3511 // == Get start / end dates from the Booking Calendar shortcode. ==
3512 // Example: [booking calendar_dates_start='2026-01-01' calendar_dates_end='2026-12-31' resource_id=1] // FixIn: 10.13.1.4.
3513 // -----------------------------------------------------------------------------------------------------------------
3514 if ( false !== wpbc_calendar__get_dates_start( params['resource_id'] ) ) {
3515 if ( ! params['dates_to_check'] ) { params['dates_to_check'] = []; }
3516 var dates_start = wpbc_calendar__get_dates_start( params['resource_id'] ); // E.g. - local__min_date = new Date( 2025, 0, 1 );
3517 if ( false !== dates_start ){
3518 params['dates_to_check'][0] = wpbc__get__sql_class_date( dates_start );
3519 }
3520 }
3521 if ( false !== wpbc_calendar__get_dates_end( params['resource_id'] ) ) {
3522 if ( !params['dates_to_check'] ) { params['dates_to_check'] = []; }
3523 var dates_end = wpbc_calendar__get_dates_end( params['resource_id'] ); // E.g. - local__min_date = new Date( 2025, 0, 1 );
3524 if ( false !== dates_end ) {
3525 params['dates_to_check'][1] = wpbc__get__sql_class_date( dates_end );
3526 if ( !params['dates_to_check'][0] ) {
3527 params['dates_to_check'][0] = wpbc__get__sql_class_date( new Date() );
3528 }
3529 }
3530 }
3531 // -----------------------------------------------------------------------------------------------------------------
3532
3533 // console.groupEnd(); console.time('resource_id_' + params['resource_id']);
3534 console.groupCollapsed( 'WPBC_AJX_CALENDAR_LOAD' ); console.log( ' == Before Ajax Send - calendars_all__get() == ' , _wpbc.calendars_all__get() );
3535 if ( 'function' === typeof (wpbc_hook__init_timeselector) ) {
3536 wpbc_hook__init_timeselector();
3537 }
3538
3539 // Start Ajax
3540 jQuery.post( wpbc_url_ajax,
3541 {
3542 action : 'WPBC_AJX_CALENDAR_LOAD',
3543 wpbc_ajx_user_id: _wpbc.get_secure_param( 'user_id' ),
3544 nonce : _wpbc.get_secure_param( 'nonce' ),
3545 wpbc_ajx_locale : _wpbc.get_secure_param( 'locale' ),
3546
3547 calendar_request_params : params // Usually like: { 'resource_id': 1, 'max_days_count': 365 }
3548 },
3549
3550 /**
3551 * S u c c e s s
3552 *
3553 * @param response_data - its object returned from Ajax - class-live-search.php
3554 * @param textStatus - 'success'
3555 * @param jqXHR - Object
3556 */
3557 function ( response_data, textStatus, jqXHR ) {
3558 // console.timeEnd('resource_id_' + response_data['resource_id']);
3559 console.log( ' == Response WPBC_AJX_CALENDAR_LOAD == ', response_data ); console.groupEnd();
3560
3561 // FixIn: 9.8.6.2.
3562 var ajx_post_data__resource_id = wpbc_get_resource_id__from_ajx_post_data_url( this.data );
3563 wpbc_balancer__completed( ajx_post_data__resource_id , 'wpbc_calendar__load_data__ajx' );
3564
3565 // Probably Error
3566 if ( (typeof response_data !== 'object') || (response_data === null) ){
3567
3568 var jq_node = wpbc_get_calendar__jq_node__for_messages( this.data );
3569 var message_type = 'info';
3570
3571 if ( '' === response_data ){
3572 response_data = 'The server responds with an empty string. The server probably stopped working unexpectedly. <br>Please check your <strong>error.log</strong> in your server configuration for relative errors.';
3573 message_type = 'warning';
3574 }
3575
3576 // Show Message
3577 wpbc_front_end__show_message( response_data , { 'type' : message_type,
3578 'show_here': {'jq_node': jq_node, 'where': 'after'},
3579 'is_append': true,
3580 'style' : 'text-align:left;',
3581 'delay' : 0
3582 } );
3583 return;
3584 }
3585
3586 // Show Calendar
3587 wpbc_calendar__loading__stop( response_data[ 'resource_id' ] );
3588
3589 // -------------------------------------------------------------------------------------------------
3590 // Bookings - Dates
3591 _wpbc.bookings_in_calendar__set_dates( response_data[ 'resource_id' ], response_data[ 'ajx_data' ]['dates'] );
3592
3593 // Bookings - Child or only single booking resource in dates
3594 _wpbc.booking__set_param_value( response_data[ 'resource_id' ], 'resources_id_arr__in_dates', response_data[ 'ajx_data' ][ 'resources_id_arr__in_dates' ] );
3595
3596 // Aggregate booking resources, if any ?
3597 _wpbc.booking__set_param_value( response_data[ 'resource_id' ], 'aggregate_resource_id_arr', response_data[ 'ajx_data' ][ 'aggregate_resource_id_arr' ] );
3598 // -------------------------------------------------------------------------------------------------
3599
3600 // Update calendar
3601 wpbc_calendar__update_look( response_data[ 'resource_id' ] );
3602
3603 if ( 'function' === typeof (wpbc_hook__init_timeselector) ) {
3604 wpbc_hook__init_timeselector();
3605 }
3606
3607 if (
3608 ( 'undefined' !== typeof (response_data[ 'ajx_data' ][ 'ajx_after_action_message' ]) )
3609 && ( '' != response_data[ 'ajx_data' ][ 'ajx_after_action_message' ].replace( /\n/g, "<br />" ) )
3610 ){
3611
3612 var jq_node = wpbc_get_calendar__jq_node__for_messages( this.data );
3613
3614 // Show Message
3615 wpbc_front_end__show_message( response_data[ 'ajx_data' ][ 'ajx_after_action_message' ].replace( /\n/g, "<br />" ),
3616 { 'type' : ( 'undefined' !== typeof( response_data[ 'ajx_data' ][ 'ajx_after_action_message_status' ] ) )
3617 ? response_data[ 'ajx_data' ][ 'ajx_after_action_message_status' ] : 'info',
3618 'show_here': {'jq_node': jq_node, 'where': 'after'},
3619 'is_append': true,
3620 'style' : 'text-align:left;',
3621 'delay' : 10000
3622 } );
3623 }
3624
3625 if ( 'function' === typeof (wpbc_update_capacity_hint) ) {
3626 wpbc_update_capacity_hint( response_data['resource_id'] );
3627 }
3628
3629 // Trigger event that calendar has been // FixIn: 10.0.0.44. // FixIn: 10.14.17.2.
3630 if ( (jQuery( '#calendar_booking' + response_data['resource_id'] ).length > 0) || (jQuery( '#date_booking' + response_data['resource_id'] ).length > 0) ) {
3631 var target_elm = jQuery( 'body' ).trigger( "wpbc_calendar_ajx__loaded_data", [response_data[ 'resource_id' ]] );
3632 //jQuery( 'body' ).on( 'wpbc_calendar_ajx__loaded_data', function( event, resource_id ) { ... } );
3633 }
3634
3635 //jQuery( '#ajax_respond' ).html( response_data ); // For ability to show response, add such DIV element to page
3636 }
3637 ).fail( function ( jqXHR, textStatus, errorThrown ) { if ( window.console && window.console.log ){ console.log( 'Ajax_Error', jqXHR, textStatus, errorThrown ); }
3638
3639 var ajx_post_data__resource_id = wpbc_get_resource_id__from_ajx_post_data_url( this.data );
3640 wpbc_balancer__completed( ajx_post_data__resource_id , 'wpbc_calendar__load_data__ajx' );
3641
3642 // Get Content of Error Message
3643 var error_message = '<strong>' + 'Error!' + '</strong> ' + errorThrown ;
3644 if ( jqXHR.status ){
3645 error_message += ' (<b>' + jqXHR.status + '</b>)';
3646 if (403 == jqXHR.status ){
3647 error_message += '<br> Probably nonce for this page has been expired. Please <a href="javascript:void(0)" onclick="javascript:location.reload();">reload the page</a>.';
3648 error_message += '<br> Otherwise, please check this <a style="font-weight: 600;" href="https://wpbookingcalendar.com/faq/request-do-not-pass-security-check/?after_update=10.1.1">troubleshooting instruction</a>.<br>'
3649 }
3650 }
3651 var message_show_delay = 3000;
3652 if ( jqXHR.responseText ){
3653 error_message += ' ' + jqXHR.responseText;
3654 message_show_delay = 10;
3655 }
3656 error_message = error_message.replace( /\n/g, "<br />" );
3657
3658 var jq_node = wpbc_get_calendar__jq_node__for_messages( this.data );
3659
3660 /**
3661 * If we make fast clicking on different pages,
3662 * then under calendar will show error message with empty text, because ajax was not received.
3663 * To not show such warnings we are set delay in 3 seconds. var message_show_delay = 3000;
3664 */
3665 var closed_timer = setTimeout( function (){
3666
3667 // Show Message
3668 wpbc_front_end__show_message( error_message , { 'type' : 'error',
3669 'show_here': {'jq_node': jq_node, 'where': 'after'},
3670 'is_append': true,
3671 'style' : 'text-align:left;',
3672 'css_class':'wpbc_fe_message_alt',
3673 'delay' : 0
3674 } );
3675 } ,
3676 parseInt( message_show_delay ) );
3677
3678 })
3679 // .done( function ( data, textStatus, jqXHR ) { if ( window.console && window.console.log ){ console.log( 'second success', data, textStatus, jqXHR ); } })
3680 // .always( function ( data_jqXHR, textStatus, jqXHR_errorThrown ) { if ( window.console && window.console.log ){ console.log( 'always finished', data_jqXHR, textStatus, jqXHR_errorThrown ); } })
3681 ; // End Ajax
3682 }
3683
3684
3685
3686 // ---------------------------------------------------------------------------------------------------------------------
3687 // Support
3688 // ---------------------------------------------------------------------------------------------------------------------
3689
3690 /**
3691 * Get Calendar jQuery node for showing messages during Ajax
3692 * This parameter: calendar_request_params[resource_id] parsed from this.data Ajax post data
3693 *
3694 * @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'
3695 * @returns {string} ''#calendar_booking1' | '.booking_form_div' ...
3696 *
3697 * Example var jq_node = wpbc_get_calendar__jq_node__for_messages( this.data );
3698 */
3699 function wpbc_get_calendar__jq_node__for_messages( ajx_post_data_url_params ){
3700
3701 var jq_node = '.booking_form_div';
3702
3703 var calendar_resource_id = wpbc_get_resource_id__from_ajx_post_data_url( ajx_post_data_url_params );
3704
3705 if ( calendar_resource_id > 0 ){
3706 jq_node = '#calendar_booking' + calendar_resource_id;
3707 }
3708
3709 return jq_node;
3710 }
3711
3712
3713 /**
3714 * Get resource ID from ajx post data url usually from this.data =
3715 * 'action=WPBC_AJX_CALENDAR_LOAD...&calendar_request_params%5Bresource_id%5D=2&calendar_request_params%5Bbooking_hash%5D=&calendar_request_params'
3716 *
3717 * @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'
3718 * @returns {int} 1 | 0 (if errror then 0)
3719 *
3720 * Example var jq_node = wpbc_get_calendar__jq_node__for_messages( this.data );
3721 */
3722 function wpbc_get_resource_id__from_ajx_post_data_url( ajx_post_data_url_params ){
3723
3724 // 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'
3725 var calendar_resource_id = wpbc_get_uri_param_by_name( 'calendar_request_params[resource_id]', ajx_post_data_url_params );
3726 if ( (null !== calendar_resource_id) && ('' !== calendar_resource_id) ){
3727 calendar_resource_id = parseInt( calendar_resource_id );
3728 if ( calendar_resource_id > 0 ){
3729 return calendar_resource_id;
3730 }
3731 }
3732 return 0;
3733 }
3734
3735
3736 /**
3737 * Get parameter from URL - parse URL parameters, like this:
3738 * action=WPBC_AJX_CALENDAR_LOAD...&calendar_request_params%5Bresource_id%5D=2&calendar_request_params%5Bbooking_hash%5D=&calendar_request_params
3739 * @param name parameter name, like 'calendar_request_params[resource_id]'
3740 * @param url 'parameter string URL'
3741 * @returns {string|null} parameter value
3742 *
3743 * Example: wpbc_get_uri_param_by_name( 'calendar_request_params[resource_id]', this.data ); -> '2'
3744 */
3745 function wpbc_get_uri_param_by_name( name, url ){
3746
3747 url = decodeURIComponent( url );
3748
3749 name = name.replace( /[\[\]]/g, '\\$&' );
3750 var regex = new RegExp( '[?&]' + name + '(=([^&#]*)|&|#|$)' ),
3751 results = regex.exec( url );
3752 if ( !results ) return null;
3753 if ( !results[ 2 ] ) return '';
3754 return decodeURIComponent( results[ 2 ].replace( /\+/g, ' ' ) );
3755 }
3756
3757 /**
3758 * =====================================================================================================================
3759 * includes/__js/front_end_messages/wpbc_fe_messages.js
3760 * =====================================================================================================================
3761 */
3762
3763 // ---------------------------------------------------------------------------------------------------------------------
3764 // Show Messages at Front-Edn side
3765 // ---------------------------------------------------------------------------------------------------------------------
3766
3767 /**
3768 * Show message in content
3769 *
3770 * @param message Message HTML
3771 * @param params = {
3772 * 'type' : 'warning', // 'error' | 'warning' | 'info' | 'success'
3773 * 'show_here' : {
3774 * 'jq_node' : '', // any jQuery node definition
3775 * 'where' : 'inside' // 'inside' | 'before' | 'after' | 'right' | 'left'
3776 * },
3777 * 'is_append': true, // Apply only if 'where' : 'inside'
3778 * 'style' : 'text-align:left;', // styles, if needed
3779 * 'css_class': '', // For example can be: 'wpbc_fe_message_alt'
3780 * 'delay' : 0, // how many microsecond to show, if 0 then show forever
3781 * 'if_visible_not_show': false // if true, then do not show message, if previos message was not hided (not apply if 'where' : 'inside' )
3782 * };
3783 * Examples:
3784 * var html_id = wpbc_front_end__show_message( 'You can test days selection in calendar', {} );
3785 *
3786 * var notice_message_id = wpbc_front_end__show_message( _wpbc.get_message( 'message_check_required' ), { 'type': 'warning', 'delay': 10000, 'if_visible_not_show': true,
3787 * 'show_here': {'where': 'right', 'jq_node': el,} } );
3788 *
3789 * wpbc_front_end__show_message( response_data[ 'ajx_data' ][ 'ajx_after_action_message' ].replace( /\n/g, "<br />" ),
3790 * { 'type' : ( 'undefined' !== typeof( response_data[ 'ajx_data' ][ 'ajx_after_action_message_status' ] ) )
3791 * ? response_data[ 'ajx_data' ][ 'ajx_after_action_message_status' ] : 'info',
3792 * 'show_here': {'jq_node': jq_node, 'where': 'after'},
3793 * 'css_class':'wpbc_fe_message_alt',
3794 * 'delay' : 10000
3795 * } );
3796 *
3797 *
3798 * @returns string - HTML ID or 0 if not showing during this time.
3799 */
3800 function wpbc_front_end__show_message( message, params = {} ){
3801
3802 var params_default = {
3803 'type' : 'warning', // 'error' | 'warning' | 'info' | 'success'
3804 'show_here' : {
3805 'jq_node' : '', // any jQuery node definition
3806 'where' : 'inside' // 'inside' | 'before' | 'after' | 'right' | 'left'
3807 },
3808 'is_append': true, // Apply only if 'where' : 'inside'
3809 'style' : 'text-align:left;', // styles, if needed
3810 'css_class': '', // For example can be: 'wpbc_fe_message_alt'
3811 'delay' : 0, // how many microsecond to show, if 0 then show forever
3812 'if_visible_not_show': false, // if true, then do not show message, if previos message was not hided (not apply if 'where' : 'inside' )
3813 'is_scroll': true // is scroll to this element
3814 };
3815 for ( var p_key in params ){
3816 params_default[ p_key ] = params[ p_key ];
3817 }
3818 params = params_default;
3819
3820 var unique_div_id = new Date();
3821 unique_div_id = 'wpbc_notice_' + unique_div_id.getTime();
3822
3823 params['css_class'] += ' wpbc_fe_message';
3824 if ( params['type'] == 'error' ){
3825 params['css_class'] += ' wpbc_fe_message_error';
3826 message = '<i class="menu_icon icon-1x wpbc_icn_report_gmailerrorred"></i>' + message;
3827 }
3828 if ( params['type'] == 'warning' ){
3829 params['css_class'] += ' wpbc_fe_message_warning';
3830 message = '<i class="menu_icon icon-1x wpbc_icn_warning"></i>' + message;
3831 }
3832 if ( params['type'] == 'info' ){
3833 params['css_class'] += ' wpbc_fe_message_info';
3834 }
3835 if ( params['type'] == 'success' ){
3836 params['css_class'] += ' wpbc_fe_message_success';
3837 message = '<i class="menu_icon icon-1x wpbc_icn_done_outline"></i>' + message;
3838 }
3839
3840 var scroll_to_element = '<div id="' + unique_div_id + '_scroll" style="display:none;"></div>';
3841 message = '<div id="' + unique_div_id + '" class="wpbc_front_end__message ' + params['css_class'] + '" style="' + params[ 'style' ] + '">' + message + '</div>';
3842
3843
3844 var jq_el_message = false;
3845 var is_show_message = true;
3846
3847 if ( 'inside' === params[ 'show_here' ][ 'where' ] ){
3848
3849 if ( params[ 'is_append' ] ){
3850 jQuery( params[ 'show_here' ][ 'jq_node' ] ).append( scroll_to_element );
3851 jQuery( params[ 'show_here' ][ 'jq_node' ] ).append( message );
3852 } else {
3853 jQuery( params[ 'show_here' ][ 'jq_node' ] ).html( scroll_to_element + message );
3854 }
3855
3856 } else if ( 'before' === params[ 'show_here' ][ 'where' ] ){
3857
3858 jq_el_message = jQuery( params[ 'show_here' ][ 'jq_node' ] ).siblings( '[id^="wpbc_notice_"]' );
3859 if ( (params[ 'if_visible_not_show' ]) && (jq_el_message.is( ':visible' )) ){
3860 is_show_message = false;
3861 unique_div_id = jQuery( jq_el_message.get( 0 ) ).attr( 'id' );
3862 }
3863 if ( is_show_message ){
3864 jQuery( params[ 'show_here' ][ 'jq_node' ] ).before( scroll_to_element );
3865 jQuery( params[ 'show_here' ][ 'jq_node' ] ).before( message );
3866 }
3867
3868 } else if ( 'after' === params[ 'show_here' ][ 'where' ] ){
3869
3870 jq_el_message = jQuery( params[ 'show_here' ][ 'jq_node' ] ).nextAll( '[id^="wpbc_notice_"]' );
3871 if ( (params[ 'if_visible_not_show' ]) && (jq_el_message.is( ':visible' )) ){
3872 is_show_message = false;
3873 unique_div_id = jQuery( jq_el_message.get( 0 ) ).attr( 'id' );
3874 }
3875 if ( is_show_message ){
3876 jQuery( params[ 'show_here' ][ 'jq_node' ] ).before( scroll_to_element ); // We need to set here before(for handy scroll)
3877 jQuery( params[ 'show_here' ][ 'jq_node' ] ).after( message );
3878 }
3879
3880 } else if ( 'right' === params[ 'show_here' ][ 'where' ] ){
3881
3882 jq_el_message = jQuery( params[ 'show_here' ][ 'jq_node' ] ).nextAll( '.wpbc_front_end__message_container_right' ).find( '[id^="wpbc_notice_"]' );
3883 if ( (params[ 'if_visible_not_show' ]) && (jq_el_message.is( ':visible' )) ){
3884 is_show_message = false;
3885 unique_div_id = jQuery( jq_el_message.get( 0 ) ).attr( 'id' );
3886 }
3887 if ( is_show_message ){
3888 jQuery( params[ 'show_here' ][ 'jq_node' ] ).before( scroll_to_element ); // We need to set here before(for handy scroll)
3889 jQuery( params[ 'show_here' ][ 'jq_node' ] ).after( '<div class="wpbc_front_end__message_container_right">' + message + '</div>' );
3890 }
3891 } else if ( 'left' === params[ 'show_here' ][ 'where' ] ){
3892
3893 jq_el_message = jQuery( params[ 'show_here' ][ 'jq_node' ] ).siblings( '.wpbc_front_end__message_container_left' ).find( '[id^="wpbc_notice_"]' );
3894 if ( (params[ 'if_visible_not_show' ]) && (jq_el_message.is( ':visible' )) ){
3895 is_show_message = false;
3896 unique_div_id = jQuery( jq_el_message.get( 0 ) ).attr( 'id' );
3897 }
3898 if ( is_show_message ){
3899 jQuery( params[ 'show_here' ][ 'jq_node' ] ).before( scroll_to_element ); // We need to set here before(for handy scroll)
3900 jQuery( params[ 'show_here' ][ 'jq_node' ] ).before( '<div class="wpbc_front_end__message_container_left">' + message + '</div>' );
3901 }
3902 }
3903
3904 if ( ( is_show_message ) && ( parseInt( params[ 'delay' ] ) > 0 ) ){
3905 var closed_timer = setTimeout( function (){
3906 jQuery( '#' + unique_div_id ).fadeOut( 1500 );
3907 } , parseInt( params[ 'delay' ] ) );
3908
3909 var closed_timer2 = setTimeout( function (){
3910 jQuery( '#' + unique_div_id ).trigger( 'hide' );
3911 }, ( parseInt( params[ 'delay' ] ) + 1501 ) );
3912 }
3913
3914 // Check if showed message in some hidden parent section and show it. But it must be lower than '.wpbc_container'
3915 var parent_els = jQuery( '#' + unique_div_id ).parents().map( function (){
3916 if ( (!jQuery( this ).is( 'visible' )) && (jQuery( '.wpbc_container' ).has( this )) ){
3917 jQuery( this ).show();
3918 }
3919 } );
3920
3921 if ( params[ 'is_scroll' ] ){
3922 wpbc_do_scroll( '#' + unique_div_id + '_scroll' );
3923 }
3924
3925 return unique_div_id;
3926 }
3927
3928
3929 /**
3930 * Error message. Preset of parameters for real message function.
3931 *
3932 * @param el - any jQuery node definition
3933 * @param message - Message HTML
3934 * @returns string - HTML ID or 0 if not showing during this time.
3935 */
3936 function wpbc_front_end__show_message__error( jq_node, message ){
3937
3938 var notice_message_id = wpbc_front_end__show_message(
3939 message,
3940 {
3941 'type' : 'error',
3942 'delay' : 10000,
3943 'if_visible_not_show': true,
3944 'show_here' : {
3945 'where' : 'right',
3946 'jq_node': jq_node
3947 }
3948 }
3949 );
3950 return notice_message_id;
3951 }
3952
3953
3954 /**
3955 * Error message UNDER element. Preset of parameters for real message function.
3956 *
3957 * @param el - any jQuery node definition
3958 * @param message - Message HTML
3959 * @returns string - HTML ID or 0 if not showing during this time.
3960 */
3961 function wpbc_front_end__show_message__error_under_element( jq_node, message, message_delay ){
3962
3963 if ( 'undefined' === typeof (message_delay) ){
3964 message_delay = 0
3965 }
3966
3967 var notice_message_id = wpbc_front_end__show_message(
3968 message,
3969 {
3970 'type' : 'error',
3971 'delay' : message_delay,
3972 'if_visible_not_show': true,
3973 'show_here' : {
3974 'where' : 'after',
3975 'jq_node': jq_node
3976 }
3977 }
3978 );
3979 return notice_message_id;
3980 }
3981
3982
3983 /**
3984 * Error message UNDER element. Preset of parameters for real message function.
3985 *
3986 * @param el - any jQuery node definition
3987 * @param message - Message HTML
3988 * @returns string - HTML ID or 0 if not showing during this time.
3989 */
3990 function wpbc_front_end__show_message__error_above_element( jq_node, message, message_delay ){
3991
3992 if ( 'undefined' === typeof (message_delay) ){
3993 message_delay = 10000
3994 }
3995
3996 var notice_message_id = wpbc_front_end__show_message(
3997 message,
3998 {
3999 'type' : 'error',
4000 'delay' : message_delay,
4001 'if_visible_not_show': true,
4002 'show_here' : {
4003 'where' : 'before',
4004 'jq_node': jq_node
4005 }
4006 }
4007 );
4008 return notice_message_id;
4009 }
4010
4011
4012 /**
4013 * Warning message. Preset of parameters for real message function.
4014 *
4015 * @param el - any jQuery node definition
4016 * @param message - Message HTML
4017 * @returns string - HTML ID or 0 if not showing during this time.
4018 */
4019 function wpbc_front_end__show_message__warning( jq_node, message ){
4020
4021 var notice_message_id = wpbc_front_end__show_message(
4022 message,
4023 {
4024 'type' : 'warning',
4025 'delay' : 10000,
4026 'if_visible_not_show': true,
4027 'show_here' : {
4028 'where' : 'right',
4029 'jq_node': jq_node
4030 }
4031 }
4032 );
4033 wpbc_highlight_error_on_form_field( jq_node );
4034 return notice_message_id;
4035 }
4036
4037
4038 /**
4039 * Warning message UNDER element. Preset of parameters for real message function.
4040 *
4041 * @param el - any jQuery node definition
4042 * @param message - Message HTML
4043 * @returns string - HTML ID or 0 if not showing during this time.
4044 */
4045 function wpbc_front_end__show_message__warning_under_element( jq_node, message ){
4046
4047 var notice_message_id = wpbc_front_end__show_message(
4048 message,
4049 {
4050 'type' : 'warning',
4051 'delay' : 10000,
4052 'if_visible_not_show': true,
4053 'show_here' : {
4054 'where' : 'after',
4055 'jq_node': jq_node
4056 }
4057 }
4058 );
4059 return notice_message_id;
4060 }
4061
4062
4063 /**
4064 * Warning message ABOVE element. Preset of parameters for real message function.
4065 *
4066 * @param el - any jQuery node definition
4067 * @param message - Message HTML
4068 * @returns string - HTML ID or 0 if not showing during this time.
4069 */
4070 function wpbc_front_end__show_message__warning_above_element( jq_node, message ){
4071
4072 var notice_message_id = wpbc_front_end__show_message(
4073 message,
4074 {
4075 'type' : 'warning',
4076 'delay' : 10000,
4077 'if_visible_not_show': true,
4078 'show_here' : {
4079 'where' : 'before',
4080 'jq_node': jq_node
4081 }
4082 }
4083 );
4084 return notice_message_id;
4085 }
4086
4087 /**
4088 * Highlight Error in specific field
4089 *
4090 * @param jq_node string or jQuery element, where scroll to
4091 */
4092 function wpbc_highlight_error_on_form_field( jq_node ){
4093
4094 if ( !jQuery( jq_node ).length ){
4095 return;
4096 }
4097 if ( ! jQuery( jq_node ).is( ':input' ) ){
4098 // Situation with checkboxes or radio buttons
4099 var jq_node_arr = jQuery( jq_node ).find( ':input' );
4100 if ( !jq_node_arr.length ){
4101 return
4102 }
4103 jq_node = jq_node_arr.get( 0 );
4104 }
4105 var params = {};
4106 params[ 'delay' ] = 10000;
4107
4108 if ( !jQuery( jq_node ).hasClass( 'wpbc_form_field_error' ) ){
4109
4110 jQuery( jq_node ).addClass( 'wpbc_form_field_error' )
4111
4112 if ( parseInt( params[ 'delay' ] ) > 0 ){
4113 var closed_timer = setTimeout( function (){
4114 jQuery( jq_node ).removeClass( 'wpbc_form_field_error' );
4115 }
4116 , parseInt( params[ 'delay' ] )
4117 );
4118
4119 }
4120 }
4121 }
4122
4123 /**
4124 * Scroll to specific element
4125 *
4126 * @param jq_node string or jQuery element, where scroll to
4127 * @param extra_shift_offset int shift offset from jq_node
4128 */
4129 function wpbc_do_scroll( jq_node , extra_shift_offset = 0 ){
4130
4131 if ( !jQuery( jq_node ).length ){
4132 return;
4133 }
4134 var targetOffset = jQuery( jq_node ).offset().top;
4135
4136 if ( targetOffset <= 0 ){
4137 if ( 0 != jQuery( jq_node ).nextAll( ':visible' ).length ){
4138 targetOffset = jQuery( jq_node ).nextAll( ':visible' ).first().offset().top;
4139 } else if ( 0 != jQuery( jq_node ).parent().nextAll( ':visible' ).length ){
4140 targetOffset = jQuery( jq_node ).parent().nextAll( ':visible' ).first().offset().top;
4141 }
4142 }
4143
4144 if ( jQuery( '#wpadminbar' ).length > 0 ){
4145 targetOffset = targetOffset - 50 - 50;
4146 } else {
4147 targetOffset = targetOffset - 20 - 50;
4148 }
4149 targetOffset += extra_shift_offset;
4150
4151 // Scroll only if we did not scroll before
4152 if ( ! jQuery( 'html,body' ).is( ':animated' ) ){
4153 jQuery( 'html,body' ).animate( {scrollTop: targetOffset}, 500 );
4154 }
4155 }
4156
4157
4158
4159 // FixIn: 10.2.0.4.
4160 /**
4161 * Define Popovers for Timelines in WP Booking Calendar
4162 *
4163 * @returns {string|boolean}
4164 */
4165 function wpbc_define_tippy_popover(){
4166 if ( 'function' !== typeof (wpbc_tippy) ){
4167 console.log( 'WPBC Error. wpbc_tippy was not defined.' );
4168 return false;
4169 }
4170 wpbc_tippy( '.popover_bottom.popover_click', {
4171 content( reference ){
4172 var popover_title = reference.getAttribute( 'data-original-title' );
4173 var popover_content = reference.getAttribute( 'data-content' );
4174 return '<div class="popover popover_tippy">'
4175 + '<div class="popover-close"><a href="javascript:void(0)" onclick="javascript:this.parentElement.parentElement.parentElement.parentElement.parentElement._tippy.hide();" >&times;</a></div>'
4176 + popover_content
4177 + '</div>';
4178 },
4179 allowHTML : true,
4180 trigger : 'manual',
4181 interactive : true,
4182 hideOnClick : false,
4183 interactiveBorder: 10,
4184 maxWidth : 550,
4185 theme : 'wpbc-tippy-popover',
4186 placement : 'bottom-start',
4187 touch : ['hold', 500],
4188 } );
4189 jQuery( '.popover_bottom.popover_click' ).on( 'click', function (){
4190 if ( this._tippy.state.isVisible ){
4191 this._tippy.hide();
4192 } else {
4193 this._tippy.show();
4194 }
4195 } );
4196 wpbc_define_hide_tippy_on_scroll();
4197 }
4198
4199
4200
4201 function wpbc_define_hide_tippy_on_scroll(){
4202 jQuery( '.flex_tl__scrolling_section2,.flex_tl__scrolling_sections' ).on( 'scroll', function ( event ){
4203 if ( 'function' === typeof (wpbc_tippy) ){
4204 wpbc_tippy.hideAll();
4205 }
4206 } );
4207 }
4208
4209 /**
4210 * WPBC calendar loader bootstrap.
4211 * ==============================================================================================
4212 * - Finds every .calendar_loader_frame[data-wpbc-rid] on the page (now or later).
4213 * - For each loader element, waits a "grace" period (data-wpbc-grace, default 8000 ms):
4214 * - If the real calendar appears: do nothing (loader naturally replaced).
4215 * - If not: show a helpful message (missing jQuery/_wpbc/datepick) or a duplicate notice.
4216 * - Works with multiple calendars and even duplicate RIDs on the same page.
4217 * - No inline JS needed in the shortcode/template output.
4218 *
4219 * File: ../includes/__js/client/cal/wpbc_cal_loader.js
4220 *
4221 * @since 10.14.5
4222 * @modified 2025-09-07 12:21
4223 * @version 1.0.0
4224 *
4225 */
4226 /**
4227 * WPBC calendar loader bootstrap.
4228 * - Auto-detects .calendar_loader_frame[data-wpbc-rid] blocks.
4229 * - Waits a "grace" period per element before showing a helpful message
4230 * if the real calendar hasn't replaced the loader.
4231 * - Multiple calendars and duplicate RIDs are handled.
4232 */
4233 (function (w, d) {
4234 'use strict';
4235
4236 /* ---------------------------------------------------------------------------
4237 * Small utilities (snake_case)
4238 * ------------------------------------------------------------------------ */
4239
4240 /** Track processed loader elements; fallback to data flag if WeakSet missing. */
4241 var processed_set = typeof WeakSet === 'function' ? new WeakSet() : null;
4242
4243 /** Return first match inside optional root. */
4244 function query_one(selector, root) {
4245 return (root || d).querySelector( selector );
4246 }
4247
4248 /** Return NodeList of matches inside optional root. */
4249 function query_all(selector, root) {
4250 return (root || d).querySelectorAll( selector );
4251 }
4252
4253 /** Run a callback when DOM is ready. */
4254 function on_ready(fn) {
4255 if ( d.readyState === 'loading' ) {
4256 d.addEventListener( 'DOMContentLoaded', fn );
4257 } else {
4258 fn();
4259 }
4260 }
4261
4262 /** Clear interval safely. */
4263 function safe_clear(interval_id) {
4264 try {
4265 w.clearInterval( interval_id );
4266 } catch ( e ) {
4267 }
4268 }
4269
4270 /** Mark element processed (WeakSet or data attribute). */
4271 function mark_processed(el) {
4272 if ( processed_set ) {
4273 processed_set.add( el );
4274 } else {
4275 try {
4276 el.dataset.wpbcProcessed = '1';
4277 } catch ( e ) {
4278 }
4279 }
4280 }
4281
4282 /** Check if element was processed. */
4283 function is_processed(el) {
4284 return processed_set ? processed_set.has( el ) : (el && el.dataset && el.dataset.wpbcProcessed === '1');
4285 }
4286
4287 /* ---------------------------------------------------------------------------
4288 * Messages (fixed English strings; no i18n)
4289 * ------------------------------------------------------------------------ */
4290
4291 /**
4292 * Build fixed English messages for a resource.
4293 * @param {string|number} rid
4294 * @return {{duplicate:string,support:string,lib_jq:string,lib_dp:string,lib_wpbc:string}}
4295 */
4296 function get_messages(rid) {
4297 var rid_int = parseInt( rid, 10 );
4298 return {
4299 duplicate :
4300 'You have added the same calendar (ID = ' + rid_int + ') more than once on this page. ' +
4301 'Please keep only one calendar with the same ID on a page to avoid conflicts.',
4302 init_failed:
4303 'The calendar could not be initialized on this page.' + '\n' +
4304 'Please check your browser console for JavaScript errors and conflicts with other scripts/plugins.',
4305 support : '', /* 'Contact support@wpbookingcalendar.com if you have any questions.', */
4306 lib_jq :
4307 'It appears that the "jQuery" library is not loading correctly.' + '\n' +
4308 'For more information, please refer to this page: https://wpbookingcalendar.com/faq/',
4309 lib_dp :
4310 'It appears that the "jQuery.datepick" library is not loading correctly.' + '\n' +
4311 'For more information, please refer to this page: https://wpbookingcalendar.com/faq/',
4312 lib_wpbc :
4313 'It appears that the "_wpbc" library is not loading correctly.' + '\n' +
4314 'Please enable the loading of JS/CSS files for this page on the "WP Booking Calendar" - "Settings General" - "Advanced" page' + '\n' +
4315 'For more information, please refer to this page: https://wpbookingcalendar.com/faq/'
4316 };
4317 }
4318
4319 /**
4320 * Wrap plain text (with newlines) in a small HTML container.
4321 * @param {string} msg
4322 * @return {string}
4323 */
4324 function wrap_html(msg) {
4325 return '<div style="font-size:13px;margin:10px;">' + String( msg || '' ).replace( /\n/g, '<br>' ) + '</div>';
4326 }
4327
4328 /** Library presence checks (fast & cheap). */
4329 function has_jq() {
4330 return !!(w.jQuery && jQuery.fn && typeof jQuery.fn.on === 'function');
4331 }
4332
4333 function has_dp() {
4334 return !!(w.jQuery && jQuery.datepick);
4335 }
4336
4337 function has_wpbc() {
4338 return !!(w._wpbc && typeof w._wpbc.set_other_param === 'function');
4339 }
4340
4341 function normalize_rid(rid) {
4342 var n = parseInt( rid, 10 );
4343 return (n > 0) ? String( n ) : '';
4344 }
4345
4346 function get_rid_counts(rid) {
4347 var r = normalize_rid( rid );
4348 return {
4349 rid : r,
4350 loaders : r ? query_all( '.calendar_loader_frame[data-wpbc-rid="' + r + '"]' ).length : 0,
4351 containers: r ? query_all( '#calendar_booking' + r ).length : 0
4352 };
4353 }
4354
4355 function is_duplicate_rid(rid) {
4356 var c = get_rid_counts( rid );
4357 return (c.loaders > 1) || (c.containers > 1);
4358 }
4359
4360 /**
4361 * Determine if the loader has been replaced by the real calendar.
4362 *
4363 * @param {Element} el Loader element
4364 * @param {string} rid Resource ID
4365 * @param {Element|null} container Optional #calendar_booking{rid} element
4366 * @return {boolean}
4367 */
4368 function is_replaced(el, rid, container) {
4369 var loader_still_in_dom = d.body.contains( el );
4370 var calendar_exists = !!query_one( '.wpbc_calendar_id_' + rid, container || d );
4371 return (!loader_still_in_dom) || calendar_exists;
4372 }
4373
4374 /**
4375 * Start watcher for a single loader element.
4376 * - Polls and observes the calendar container.
4377 * - After grace, injects a suitable message if not replaced.
4378 *
4379 * @param {Element} el
4380 */
4381 function start_for(el) {
4382 if ( ! el || is_processed( el ) ) {
4383 return;
4384 }
4385 mark_processed( el );
4386
4387 var rid = el.dataset.wpbcRid;
4388 if ( ! rid ) {
4389 return;
4390 }
4391
4392 var grace_ms = parseInt( el.dataset.wpbcGrace || '8000', 10 );
4393 if ( ! (grace_ms > 0) ) {
4394 grace_ms = 8000;
4395 }
4396
4397 var container_id = 'calendar_booking' + rid;
4398 var container = d.getElementById( container_id );
4399 var text_el = query_one( '.calendar_loader_text', el );
4400
4401 function replaced_now() {
4402 return is_replaced( el, rid, container );
4403 }
4404
4405 // Already replaced -> nothing to do.
4406 if ( replaced_now() ) {
4407 return;
4408 }
4409
4410 // 1) Cheap polling.
4411 var poll_id = w.setInterval( function () {
4412 if ( replaced_now() ) {
4413 safe_clear( poll_id );
4414 if ( observer ) {
4415 try {
4416 observer.disconnect();
4417 } catch ( e ) {
4418 }
4419 }
4420 }
4421 }, 250 );
4422
4423 // 2) MutationObserver for faster reaction.
4424 var observer = null;
4425 if ( container && 'MutationObserver' in w ) {
4426 try {
4427 observer = new MutationObserver( function () {
4428 if ( replaced_now() ) {
4429 safe_clear( poll_id );
4430 try {
4431 observer.disconnect();
4432 } catch ( e ) {
4433 }
4434 }
4435 } );
4436 observer.observe( container, { childList: true, subtree: true } );
4437 } catch ( e ) {
4438 }
4439 }
4440
4441 // 3) Final decision after grace period.
4442 w.setTimeout( function finalize_after_grace() {
4443 if ( replaced_now() ) {
4444 safe_clear( poll_id );
4445 if ( observer ) {
4446 try {
4447 observer.disconnect();
4448 } catch ( e ) {
4449 }
4450 }
4451 return;
4452 }
4453
4454 var M = get_messages( rid );
4455 var msg;
4456 if ( ! has_jq() ) {
4457 msg = M.lib_jq;
4458 } else if ( ! has_wpbc() ) {
4459 msg = M.lib_wpbc;
4460 } else if ( ! has_dp() ) {
4461 msg = M.lib_dp;
4462 } else {
4463 // Libraries are present, but loader wasn't replaced -> decide what is most likely.
4464 if ( is_duplicate_rid( rid ) ) {
4465 msg = M.duplicate + '\n\n' + M.support;
4466 } else {
4467 msg = M.init_failed + '\n\n' + M.support;
4468 }
4469 }
4470
4471 try {
4472 if ( text_el ) {
4473 text_el.innerHTML = wrap_html( msg );
4474 }
4475 } catch ( e ) {
4476 }
4477
4478 safe_clear( poll_id );
4479 if ( observer ) {
4480 try {
4481 observer.disconnect();
4482 } catch ( e ) {
4483 }
4484 }
4485 }, grace_ms );
4486 }
4487
4488 /**
4489 * Initialize watchers for loader elements already in the DOM.
4490 */
4491 function bootstrap_existing() {
4492 query_all( '.calendar_loader_frame[data-wpbc-rid]' ).forEach( start_for );
4493 }
4494
4495 /**
4496 * Observe the document for any new loader elements inserted later (AJAX, block render).
4497 */
4498 function observe_new_loaders() {
4499 if ( ! ('MutationObserver' in w) ) {
4500 return;
4501 }
4502 try {
4503 var doc_observer = new MutationObserver( function (mutations) {
4504 for ( var i = 0; i < mutations.length; i++ ) {
4505 var nodes = mutations[i].addedNodes || [];
4506 for ( var j = 0; j < nodes.length; j++ ) {
4507 var node = nodes[j];
4508 if ( ! node || node.nodeType !== 1 ) {
4509 continue;
4510 }
4511 if ( node.matches && node.matches( '.calendar_loader_frame[data-wpbc-rid]' ) ) {
4512 start_for( node );
4513 }
4514 if ( node.querySelectorAll ) {
4515 var inner = node.querySelectorAll( '.calendar_loader_frame[data-wpbc-rid]' );
4516 if ( inner && inner.length ) {
4517 inner.forEach( start_for );
4518 }
4519 }
4520 }
4521 }
4522 } );
4523 doc_observer.observe( d.documentElement, { childList: true, subtree: true } );
4524 } catch ( e ) {
4525 }
4526 }
4527
4528 /* ---------------------------------------------------------------------------
4529 * Boot
4530 * ------------------------------------------------------------------------ */
4531 on_ready( function () {
4532 bootstrap_existing();
4533 observe_new_loaders();
4534 } );
4535
4536 })( window, document );
4537
4538 (function( w ) {
4539
4540 'use strict';
4541
4542 if ( ! w.WPBC_FE ) {
4543 w.WPBC_FE = {};
4544 }
4545
4546 /**
4547 * Auto-fill booking form fields (text/email) based on input "name" patterns.
4548 *
4549 * Form ID format: booking_form{resource_id}
4550 * Skips date field: date_booking{resource_id}
4551 *
4552 * @param {number} resource_id Booking resource ID.
4553 * @param {Object} fill_values Values to inject (strings).
4554 *
4555 * @return {boolean} True if form found and processed, false otherwise.
4556 */
4557 w.WPBC_FE.autofill_booking_form_fields = function( resource_id, fill_values ) {
4558
4559 resource_id = parseInt( resource_id, 10 ) || 0;
4560 fill_values = fill_values || {};
4561
4562 var form_id = 'booking_form' + resource_id;
4563 var date_name = 'date_booking' + resource_id;
4564
4565 var submit_form = document.getElementById( form_id );
4566
4567 if ( ! submit_form ) {
4568 /* eslint-disable no-console */
4569 console.error( 'WPBC: No booking form: ' + form_id );
4570 /* eslint-enable no-console */
4571 return false;
4572 }
4573
4574 // Keep same regex rules and priority order as legacy inline JS.
4575 var rules = array_rules( fill_values );
4576
4577 var elements = submit_form.elements || [];
4578 var count = elements.length;
4579 var el;
4580 var i;
4581 var j;
4582
4583 for ( i = 0; i < count; i++ ) {
4584
4585 el = elements[ i ];
4586
4587 if ( ! el || ! el.name ) {
4588 continue;
4589 }
4590
4591 // Only text/email inputs.
4592 if ( ( el.type !== 'text' ) && ( el.type !== 'email' ) ) {
4593 continue;
4594 }
4595
4596 // Skip date field.
4597 if ( el.name === date_name ) {
4598 continue;
4599 }
4600
4601 // Fill only empty values (legacy behavior: == "").
4602 if ( el.value !== '' ) {
4603 continue;
4604 }
4605
4606 for ( j = 0; j < rules.length; j++ ) {
4607
4608 if ( rules[ j ].re.test( el.name ) ) {
4609
4610 if ( rules[ j ].val !== '' ) {
4611 el.value = rules[ j ].val;
4612 }
4613
4614 break; // Stop at first matching rule (priority).
4615 }
4616 }
4617 }
4618
4619 return true;
4620 };
4621
4622 /**
4623 * Build rules array for autofill.
4624 *
4625 * @param {Object} fill_values Values to inject.
4626 *
4627 * @return {Array} Rules list.
4628 */
4629 function array_rules( fill_values ) {
4630
4631 // Normalize to strings (prevent "undefined" in fields).
4632 var nickname = ( fill_values.nickname != null ) ? String( fill_values.nickname ) : '';
4633 var last_name = ( fill_values.last_name != null ) ? String( fill_values.last_name ) : '';
4634 var first_name = ( fill_values.first_name != null ) ? String( fill_values.first_name ) : '';
4635 var email = ( fill_values.email != null ) ? String( fill_values.email ) : '';
4636 var phone = ( fill_values.phone != null ) ? String( fill_values.phone ) : '';
4637 var nb_enfant = ( fill_values.nb_enfant != null ) ? String( fill_values.nb_enfant ) : '';
4638 var url = ( fill_values.url != null ) ? String( fill_values.url ) : '';
4639
4640 return [
4641 { re: /^([A-Za-z0-9_\-\.])*(nickname){1}([A-Za-z0-9_\-\.])*$/, val: nickname },
4642 { re: /^([A-Za-z0-9_\-\.])*(last|second){1}([_\-\.])?name([A-Za-z0-9_\-\.])*$/, val: last_name },
4643 { re: /^name([0-9_\-\.])*$/, val: first_name },
4644 { re: /^([A-Za-z0-9_\-\.])*(first|my){1}([_\-\.])?name([A-Za-z0-9_\-\.])*$/, val: first_name },
4645 { re: /^(e)?([_\-\.])?mail([0-9_\-\.]*)$/, val: email },
4646 { re: /^([A-Za-z0-9_\-\.])*(phone|fone){1}([A-Za-z0-9_\-\.])*$/, val: phone },
4647 { re: /^(e)?([_\-\.])?nb_enfant([0-9_\-\.]*)$/, val: nb_enfant },
4648 { re: /^([A-Za-z0-9_\-\.])*(URL|site|web|WEB){1}([A-Za-z0-9_\-\.])*$/, val: url }
4649 ];
4650 }
4651
4652 })( window );
4653
4654 // == Submit Booking Data ==============================================================================================
4655 // Refactored (safe), with new wpbc_* names.
4656 // Backward-compatible wrappers for legacy function names are included at the bottom.
4657 // @file: includes/__js/client/front_end_form/booking_form_submit.js
4658
4659 /**
4660 * Check fields at form and then send request (legacy: mybooking_submit).
4661 *
4662 * @param {HTMLFormElement} submit_form
4663 * @param {number|string} resource_id
4664 * @param {string} wpdev_active_locale
4665 *
4666 * @return {false|undefined} Legacy behavior: returns false in some cases, otherwise undefined.
4667 */
4668 function wpbc_booking_form_submit( submit_form, resource_id, wpdev_active_locale ) {
4669
4670 resource_id = parseInt( resource_id, 10 );
4671
4672 // Safety guard (legacy code assumed valid form).
4673 if ( ! submit_form || ! submit_form.elements ) {
4674 /* eslint-disable no-console */
4675 console.error( 'WPBC: Invalid submit form in wpbc_booking_form_submit().' );
4676 /* eslint-enable no-console */
4677 return false;
4678 }
4679
4680 // -------------------------------------------------------------------------
4681 // External hook: allow pause submit on confirmation/summary step.
4682 // -------------------------------------------------------------------------
4683 var target_elm = jQuery( '.booking_form_div' ).trigger( 'booking_form_submit_click', [ resource_id, submit_form, wpdev_active_locale ] ); // FixIn: 8.8.3.13.
4684
4685 if (
4686 ( jQuery( target_elm ).find( 'input[name="booking_form_show_summary"]' ).length > 0 ) &&
4687 ( 'pause_submit' === jQuery( target_elm ).find( 'input[name="booking_form_show_summary"]' ).val() )
4688 ) {
4689 return false;
4690 }
4691
4692 // FixIn: 8.4.0.2.
4693 var is_error = wpbc_check_errors_in_booking_form( resource_id );
4694 if ( is_error ) {
4695 return false;
4696 }
4697
4698 // -------------------------------------------------------------------------
4699 // Show message if no selected days in Calendar(s).
4700 // -------------------------------------------------------------------------
4701 var date_input = document.getElementById( 'date_booking' + resource_id );
4702 var date_value = ( date_input ) ? date_input.value : '';
4703
4704 if ( '' === date_value ) {
4705
4706 var arr_of_selected_additional_calendars = wpbc_get_arr_of_selected_additional_calendars( resource_id ); // FixIn: 8.5.2.26.
4707
4708 if ( ! arr_of_selected_additional_calendars || ( arr_of_selected_additional_calendars.length === 0 ) ) {
4709 wpbc_front_end__show_message__error_under_element(
4710 '#booking_form_div' + resource_id + ' .bk_calendar_frame',
4711 _wpbc.get_message( 'message_check_no_selected_dates' ),
4712 3000
4713 );
4714 return;
4715 }
4716 }
4717
4718 // -------------------------------------------------------------------------
4719 // FixIn: 6.1.1.3. Time selection availability checks.
4720 // -------------------------------------------------------------------------
4721 if ( typeof wpbc_is_this_time_selection_not_available === 'function' ) {
4722
4723 if ( '' === date_value ) { // Primary calendar not selected.
4724
4725 var additional_calendars_el = document.getElementById( 'additional_calendars' + resource_id );
4726
4727 if ( additional_calendars_el !== null ) { // Checking additional calendars.
4728
4729 var id_additional_str = additional_calendars_el.value;
4730 var id_additional_arr = id_additional_str.split( ',' );
4731 var is_times_dates_ok = false;
4732
4733 for ( var ia = 0; ia < id_additional_arr.length; ia++ ) {
4734
4735 var add_id = id_additional_arr[ ia ];
4736
4737 var add_date_el = document.getElementById( 'date_booking' + add_id );
4738 var add_date_val = ( add_date_el ) ? add_date_el.value : '';
4739
4740 if (
4741 ( '' !== add_date_val ) &&
4742 ( ! wpbc_is_this_time_selection_not_available( add_id, submit_form.elements ) )
4743 ) {
4744 is_times_dates_ok = true;
4745 }
4746 }
4747
4748 if ( ! is_times_dates_ok ) {
4749 return;
4750 }
4751 }
4752
4753 } else { // Primary calendar selected.
4754
4755 if ( wpbc_is_this_time_selection_not_available( resource_id, submit_form.elements ) ) {
4756 return;
4757 }
4758 }
4759 }
4760
4761 // -------------------------------------------------------------------------
4762 // Serialize form (legacy format).
4763 // -------------------------------------------------------------------------
4764 var count = submit_form.elements.length;
4765 var formdata = '';
4766 var inp_value;
4767 var inp_title_value;
4768 var element;
4769 var el_type;
4770
4771 // Helper: legacy escaping for the serialized value.
4772 function wpbc_escape_serialized_value( val ) {
4773
4774 val = ( val == null ) ? '' : String( val );
4775
4776 // Replace registered characters.
4777 val = val.replace( new RegExp( '\\^', 'g' ), '&#94;' );
4778 val = val.replace( new RegExp( '~', 'g' ), '&#126;' );
4779
4780 // Replace quotes.
4781 val = val.replace( /"/g, '&#34;' );
4782 val = val.replace( /'/g, '&#39;' );
4783
4784 return val;
4785 }
4786
4787 // Helper: determine UI type for title extraction (legacy logic).
4788 function wpbc_get_input_element_type( el ) {
4789
4790 if ( ! el || ! el.tagName ) {
4791 return '';
4792 }
4793
4794 var tag = String( el.tagName ).toLowerCase();
4795
4796 if ( 'input' === tag ) {
4797 return ( el.type ) ? String( el.type ).toLowerCase() : 'text';
4798 }
4799
4800 // Legacy used "select" string here.
4801 if ( 'select' === tag ) {
4802 return 'select';
4803 }
4804
4805 return tag;
4806 }
4807
4808 for ( var i = 0; i < count; i++ ) { // FixIn: 9.1.5.1.
4809
4810 element = submit_form.elements[ i ];
4811
4812 if ( ! element ) {
4813 continue;
4814 }
4815
4816 if ( jQuery( element ).closest( '.booking_form_garbage' ).length ) {
4817 continue; // Skip elements from garbage. FixIn: 7.1.2.14.
4818 }
4819
4820 if (
4821 ( element.type !== 'button' ) &&
4822 ( element.type !== 'hidden' ) &&
4823 ( element.name !== ( 'date_booking' + resource_id ) )
4824 // && ( jQuery( element ).is( ':visible' ) ) //FixIn: 7.2.1.12.2
4825 ) {
4826
4827 // -------------------------------------------------------------
4828 // Get element value.
4829 // -------------------------------------------------------------
4830 if ( element.type === 'checkbox' ) {
4831
4832 if ( element.value === '' ) {
4833 inp_value = element.checked;
4834 } else {
4835 inp_value = ( element.checked ) ? element.value : '';
4836 }
4837
4838 } else if ( element.type === 'radio' ) {
4839
4840 if ( element.checked ) {
4841 inp_value = element.value;
4842 } else {
4843
4844 // Required radio: show warning if none checked.
4845 // FixIn: 7.0.1.62.
4846 if (
4847 ( element.className.indexOf( 'wpdev-validates-as-required' ) !== -1 ) &&
4848 ( jQuery( element ).is( ':visible' ) ) && // FixIn: 7.2.1.12.2.
4849 ( ! jQuery( ':radio[name="' + element.name + '"]', submit_form ).is( ':checked' ) )
4850 ) {
4851 wpbc_front_end__show_message__warning( element, _wpbc.get_message( 'message_check_required_for_radio_box' ) ); // FixIn: 8.5.1.3.
4852 return;
4853 }
4854
4855 // Skip storing empty radio options.
4856 continue;
4857 }
4858
4859 } else {
4860 inp_value = element.value;
4861 }
4862
4863 inp_title_value = '';
4864
4865 // -------------------------------------------------------------
4866 // Get human-friendly title value (legacy behavior).
4867 // -------------------------------------------------------------
4868 var input_element_type = wpbc_get_input_element_type( element );
4869
4870 switch ( input_element_type ) {
4871
4872 case 'text':
4873 case 'email':
4874 inp_title_value = inp_value;
4875 break;
4876
4877 case 'select':
4878 inp_title_value = jQuery( element ).find( 'option:selected' ).text();
4879 break;
4880
4881 case 'radio':
4882 case 'checkbox':
4883 if ( jQuery( element ).is( ':checked' ) ) {
4884 var label_element = jQuery( element ).parents( '.wpdev-list-item' ).find( '.wpdev-list-item-label' );
4885 if ( label_element.length ) {
4886 inp_title_value = label_element.html();
4887 }
4888 }
4889 break;
4890
4891 default:
4892 inp_title_value = inp_value;
4893 }
4894
4895 // -------------------------------------------------------------
4896 // Multiple select value extraction.
4897 // -------------------------------------------------------------
4898 if ( ( element.type === 'selectbox-multiple' ) || ( element.type === 'select-multiple' ) ) {
4899 inp_value = jQuery( '[name="' + element.name + '"]' ).val();
4900 if ( ( inp_value === null ) || ( String( inp_value ) === '' ) ) {
4901 inp_value = '';
4902 }
4903 }
4904
4905 // -------------------------------------------------------------
4906 // Make validation only for visible elements.
4907 // -------------------------------------------------------------
4908 if ( jQuery( element ).is( ':visible' ) ) { // FixIn: 7.2.1.12.2.
4909
4910 // Recheck max available visitors selection.
4911 if ( typeof wpbc__is_less_than_required__of_max_available_slots__bl === 'function' ) {
4912 if ( wpbc__is_less_than_required__of_max_available_slots__bl( resource_id, element ) ) {
4913 return;
4914 }
4915 }
4916
4917 // Required fields.
4918 if ( element.className.indexOf( 'wpdev-validates-as-required' ) !== -1 ) {
4919
4920 if ( ( element.type === 'checkbox' ) && ( element.checked === false ) ) {
4921
4922 if ( ! jQuery( ':checkbox[name="' + element.name + '"]', submit_form ).is( ':checked' ) ) {
4923 wpbc_front_end__show_message__warning( element, _wpbc.get_message( 'message_check_required_for_check_box' ) ); // FixIn: 8.5.1.3.
4924 return;
4925 }
4926 }
4927
4928 if ( element.type === 'radio' ) {
4929
4930 if ( ! jQuery( ':radio[name="' + element.name + '"]', submit_form ).is( ':checked' ) ) {
4931 wpbc_front_end__show_message__warning( element, _wpbc.get_message( 'message_check_required_for_radio_box' ) ); // FixIn: 8.5.1.3.
4932 return;
4933 }
4934 }
4935
4936 if ( ( element.type !== 'checkbox' ) && ( element.type !== 'radio' ) && ( '' === wpbc_trim( inp_value ) ) ) {
4937 wpbc_front_end__show_message__warning( element, _wpbc.get_message( 'message_check_required' ) ); // FixIn: 8.5.1.3.
4938 return;
4939 }
4940 }
4941
4942 // Email format validation.
4943 if ( element.className.indexOf( 'wpdev-validates-as-email' ) !== -1 ) {
4944
4945 inp_value = String( inp_value ).replace( /^\s+|\s+$/gm, '' ); // Trim white space. FixIn: 5.4.5.
4946 var reg_email = /^([A-Za-z0-9_\-\.\+])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,})$/;
4947
4948 if ( inp_value !== '' ) {
4949 if ( reg_email.test( inp_value ) === false ) {
4950 wpbc_front_end__show_message__warning( element, _wpbc.get_message( 'message_check_email' ) ); // FixIn: 8.5.1.3.
4951 return;
4952 }
4953 }
4954 }
4955
4956 // Same email field validation (verification field).
4957 if ( ( element.className.indexOf( 'wpdev-validates-as-email' ) !== -1 ) && ( element.className.indexOf( 'same_as_' ) !== -1 ) ) {
4958
4959 var primary_email_name = element.className.match( /same_as_([^\s])+/gi );
4960
4961 if ( primary_email_name !== null ) {
4962
4963 primary_email_name = primary_email_name[ 0 ].substr( 8 );
4964
4965 if ( jQuery( '[name="' + primary_email_name + resource_id + '"]' ).length > 0 ) {
4966
4967 if ( jQuery( '[name="' + primary_email_name + resource_id + '"]' ).val() !== inp_value ) {
4968 wpbc_front_end__show_message__warning( element, _wpbc.get_message( 'message_check_same_email' ) ); // FixIn: 8.5.1.3.
4969 return;
4970 }
4971 }
4972 }
4973
4974 // Skip one loop for the email verification field.
4975 continue; // FixIn: 8.1.2.15.
4976 }
4977 }
4978
4979 // -------------------------------------------------------------
4980 // Get Form Data (legacy format).
4981 // -------------------------------------------------------------
4982 if ( element.name !== ( 'captcha_input' + resource_id ) ) {
4983
4984 if ( formdata !== '' ) {
4985 formdata += '~';
4986 }
4987
4988 el_type = element.type;
4989
4990 if ( element.className.indexOf( 'wpdev-validates-as-email' ) !== -1 ) {
4991 el_type = 'email';
4992 }
4993 if ( element.className.indexOf( 'wpdev-validates-as-coupon' ) !== -1 ) {
4994 el_type = 'coupon';
4995 }
4996
4997 inp_value = wpbc_escape_serialized_value( inp_value );
4998
4999 if ( el_type === 'select-one' ) {
5000 el_type = 'selectbox-one';
5001 }
5002 if ( el_type === 'select-multiple' ) {
5003 el_type = 'selectbox-multiple';
5004 }
5005
5006 formdata += el_type + '^' + element.name + '^' + inp_value;
5007
5008 // Add title/label value (legacy).
5009 var clean_field_name = String( element.name );
5010
5011 // BUGFIX: replaceAll(RegExp) is not supported in older browsers.
5012 // Keep legacy intent: remove [] suffix occurrences.
5013 clean_field_name = clean_field_name.replace( /\[\]/gi, '' );
5014
5015 var resource_id_str = String( resource_id );
5016
5017 // Legacy assumed suffix ends with resource_id, make it safe.
5018 if (
5019 ( clean_field_name.length >= resource_id_str.length ) &&
5020 ( clean_field_name.substr( clean_field_name.length - resource_id_str.length ) === resource_id_str )
5021 ) {
5022 clean_field_name = clean_field_name.substr( 0, clean_field_name.length - resource_id_str.length );
5023 }
5024
5025 formdata += '~' + el_type + '^' + clean_field_name + '_val' + resource_id + '^' + inp_title_value;
5026 }
5027 }
5028 }
5029
5030 // TODO: here was function for 'Check if visitor finish dates selection.
5031
5032 // Captcha verify.
5033 var captcha = document.getElementById( 'wpdev_captcha_challenge_' + resource_id );
5034
5035 if ( captcha !== null ) {
5036 wpbc_form_submit_send( resource_id, formdata, captcha.value, document.getElementById( 'captcha_input' + resource_id ).value, wpdev_active_locale );
5037 } else {
5038 wpbc_form_submit_send( resource_id, formdata, '', '', wpdev_active_locale );
5039 }
5040
5041 return;
5042 }
5043
5044
5045 /**
5046 * Gathering params for sending Ajax request and then send it (legacy: form_submit_send).
5047 *
5048 * @param {number|string} resource_id
5049 * @param {string} formdata
5050 * @param {string} captcha_chalange
5051 * @param {string} user_captcha
5052 * @param {string} wpdev_active_locale
5053 *
5054 * @return {undefined} Legacy behavior.
5055 */
5056 function wpbc_form_submit_send( resource_id, formdata, captcha_chalange, user_captcha, wpdev_active_locale ) {
5057
5058 resource_id = parseInt( resource_id, 10 );
5059
5060 var my_booking_form = '';
5061 var booking_form_type_el = document.getElementById( 'booking_form_type' + resource_id );
5062 if ( booking_form_type_el !== null ) {
5063 my_booking_form = booking_form_type_el.value;
5064 }
5065
5066 var my_booking_hash = '';
5067 if ( _wpbc.get_other_param( 'this_page_booking_hash' ) !== '' ) {
5068 my_booking_hash = _wpbc.get_other_param( 'this_page_booking_hash' );
5069 }
5070
5071 var is_send_emeils = 1;
5072 var $is_send_email_toggle = jQuery( '#is_send_email_for_pending' );
5073 var $modal_send_email_toggle = jQuery( '#booking_form' + resource_id ).closest( '.wpbc_modal__add_booking__section' ).find( '[data-wpbc-add-booking-send-emails]' ).first();
5074 if ( $modal_send_email_toggle.length ) {
5075 $is_send_email_toggle = $modal_send_email_toggle;
5076 }
5077 if ( $is_send_email_toggle.length ) { // FixIn: 8.7.9.5.
5078
5079 is_send_emeils = $is_send_email_toggle.is( ':checked' );
5080
5081 if ( false === is_send_emeils ) {
5082 is_send_emeils = 0;
5083 } else {
5084 is_send_emeils = 1;
5085 }
5086 }
5087
5088 var date_el = document.getElementById( 'date_booking' + resource_id );
5089 var date_value = ( date_el ) ? date_el.value : '';
5090
5091 if ( '' !== date_value ) { // FixIn: 6.1.1.3.
5092 wpbc_send_ajax_submit( resource_id, formdata, captcha_chalange, user_captcha, is_send_emeils, my_booking_hash, my_booking_form, wpdev_active_locale );
5093 } else {
5094 jQuery( '#booking_form_div' + resource_id ).hide();
5095 jQuery( '#submiting' + resource_id ).hide();
5096 }
5097
5098 // -------------------------------------------------------------------------
5099 // Additional calendars submit.
5100 // -------------------------------------------------------------------------
5101 var additional_calendars_el = document.getElementById( 'additional_calendars' + resource_id );
5102 if ( additional_calendars_el === null ) {
5103 return;
5104 }
5105
5106 var id_additional_str = additional_calendars_el.value;
5107 var id_additional_arr = id_additional_str.split( ',' );
5108
5109 // FixIn: 10.9.4.1.
5110 for ( var ia = 0; ia < id_additional_arr.length; ia++ ) {
5111 id_additional_arr[ ia ] = parseInt( id_additional_arr[ ia ], 10 );
5112 }
5113
5114 if ( ! jQuery( '#booking_form_div' + resource_id ).is( ':visible' ) ) {
5115 wpbc_booking_form__spin_loader__show( resource_id ); // Show Spinner
5116 }
5117
5118 // Helper: rewrite field name suffix from resource_id -> id_additional.
5119 function wpbc_rewrite_field_name_suffix( field_name, old_id, new_id ) {
5120
5121 field_name = String( field_name );
5122
5123 var old_id_str = String( old_id );
5124 var new_id_str = String( new_id );
5125
5126 // Handle fields with [].
5127 if (
5128 ( field_name.length >= ( old_id_str.length + 2 ) ) &&
5129 ( field_name.substr( field_name.length - ( old_id_str.length + 2 ) ) === ( old_id_str + '[]' ) )
5130 ) {
5131 return field_name.substr( 0, field_name.length - ( old_id_str.length + 2 ) ) + new_id_str + '[]';
5132 }
5133
5134 // Handle fields without [].
5135 if (
5136 ( field_name.length >= old_id_str.length ) &&
5137 ( field_name.substr( field_name.length - old_id_str.length ) === old_id_str )
5138 ) {
5139 return field_name.substr( 0, field_name.length - old_id_str.length ) + new_id_str;
5140 }
5141
5142 // Fallback: return unchanged (safer than breaking name).
5143 return field_name;
5144 }
5145
5146 for ( ia = 0; ia < id_additional_arr.length; ia++ ) {
5147
5148 var id_additional = id_additional_arr[ ia ];
5149
5150 // FixIn: 10.9.4.1.
5151 if ( id_additional <= 0 ) {
5152 continue;
5153 }
5154
5155 // Rebuild formdata for each additional calendar (legacy behavior).
5156 var formdata_additional_arr = String( formdata ).split( '~' );
5157 var formdata_additional = '';
5158
5159 for ( var j = 0; j < formdata_additional_arr.length; j++ ) {
5160
5161 var my_form_field = formdata_additional_arr[ j ].split( '^' );
5162
5163 if ( formdata_additional !== '' ) {
5164 formdata_additional += '~';
5165 }
5166
5167 // Safety: ensure we have at least type ^ name ^ value.
5168 if ( my_form_field.length < 3 ) {
5169 formdata_additional += formdata_additional_arr[ j ];
5170 continue;
5171 }
5172
5173 my_form_field[ 1 ] = wpbc_rewrite_field_name_suffix( my_form_field[ 1 ], resource_id, id_additional );
5174 formdata_additional += my_form_field[ 0 ] + '^' + my_form_field[ 1 ] + '^' + my_form_field[ 2 ];
5175 }
5176
5177 // If payment form for main booking resource is showing, append for additional calendars.
5178 if ( jQuery( '#gateway_payment_forms' + resource_id ).length > 0 ) {
5179 jQuery( '#gateway_payment_forms' + resource_id ).after( '<div id="gateway_payment_forms' + id_additional + '"></div>' );
5180 jQuery( '#gateway_payment_forms' + resource_id ).after( '<div id="ajax_respond_insert' + id_additional + '" style="display:none;"></div>' );
5181 }
5182
5183 // FixIn: 8.5.2.17.
5184 wpbc_send_ajax_submit( id_additional, formdata_additional, captcha_chalange, user_captcha, is_send_emeils, my_booking_hash, my_booking_form, wpdev_active_locale );
5185 }
5186 }
5187
5188
5189 /**
5190 * Send Ajax submit (legacy: send_ajax_submit).
5191 *
5192 * @param {number|string} resource_id
5193 * @param {string} formdata
5194 * @param {string} captcha_chalange
5195 * @param {string} user_captcha
5196 * @param {number} is_send_emeils
5197 * @param {string} my_booking_hash
5198 * @param {string} my_booking_form
5199 * @param {string} wpdev_active_locale
5200 *
5201 * @return {undefined} Legacy behavior.
5202 */
5203 function wpbc_send_ajax_submit(resource_id, formdata, captcha_chalange, user_captcha, is_send_emeils, my_booking_hash, my_booking_form, wpdev_active_locale) {
5204
5205 resource_id = parseInt( resource_id, 10 );
5206
5207 // Disable Submit | Show spin loader.
5208 wpbc_booking_form__on_submit__ui_elements_disable( resource_id );
5209
5210 // FixIn: 2026-02-05 - pass preview context to booking create Ajax.
5211 var form_status = wpbc__get_form_status_for_submit( resource_id );
5212 var preview_args = (form_status === 'preview') ? wpbc__get_bfb_preview_args_from_location() : null;
5213
5214 var request_params = {
5215 'resource_id' : resource_id,
5216 'dates_ddmmyy_csv' : document.getElementById( 'date_booking' + resource_id ).value,
5217 'formdata' : formdata,
5218 'booking_hash' : my_booking_hash,
5219 'custom_form' : my_booking_form,
5220 '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( ',' ) : '' ),
5221 'captcha_chalange' : captcha_chalange,
5222 'captcha_user_input' : user_captcha,
5223 'is_emails_send' : is_send_emeils,
5224 'active_locale' : wpdev_active_locale,
5225 'form_status' : form_status
5226 };
5227
5228 // If preview, pass session identifiers so PHP can load transient snapshot.
5229 if ( preview_args && preview_args.token && preview_args.form_id ) {
5230 request_params['wpbc_bfb_preview'] = 1;
5231 request_params['wpbc_bfb_preview_token'] = preview_args.token;
5232 request_params['wpbc_bfb_preview_form_id'] = preview_args.form_id;
5233 request_params['wpbc_bfb_preview_nonce'] = preview_args.nonce; // note: URL param is `nonce`.
5234 }
5235
5236 var is_exit = wpbc_ajx_booking__create( request_params );
5237
5238 if ( true === is_exit ) {
5239 return;
5240 }
5241 }
5242
5243
5244
5245 // == Helper Functions =================================================================================================
5246
5247 /**
5248 * Parse query string into {key:value} (old-browser safe).
5249 *
5250 * @param {string} qs
5251 * @return {Object}
5252 */
5253 function wpbc__parse_query_string(qs) {
5254 var out = {};
5255 qs = (qs || '');
5256 qs = qs.replace( /^\?/, '' );
5257 if ( ! qs ) {
5258 return out;
5259 }
5260
5261 var parts = qs.split( '&' );
5262 for ( var i = 0; i < parts.length; i++ ) {
5263 var kv = parts[i].split( '=' );
5264 var k = decodeURIComponent( kv[0] || '' );
5265 if ( ! k ) {
5266 continue;
5267 }
5268 var v = decodeURIComponent( kv.slice( 1 ).join( '=' ) || '' );
5269 out[k] = v;
5270 }
5271 return out;
5272 }
5273
5274 /**
5275 * Detect preview args from current URL (iframe URL).
5276 *
5277 * @return {Object|null} { token, form_id, nonce } or null
5278 */
5279 function wpbc__get_bfb_preview_args_from_location() {
5280 try {
5281 var p = wpbc__parse_query_string( (window.location && window.location.search) ? window.location.search : '' );
5282
5283 if ( ! p.wpbc_bfb_preview || (p.wpbc_bfb_preview === '0') ) {
5284 return null;
5285 }
5286
5287 if ( ! p.wpbc_bfb_preview_token || ! p.wpbc_bfb_preview_form_id ) {
5288 return null;
5289 }
5290
5291 return {
5292 token : String( p.wpbc_bfb_preview_token ),
5293 form_id: parseInt( p.wpbc_bfb_preview_form_id, 10 ) || 0,
5294 nonce : (p.nonce) ? String( p.nonce ) : ''
5295 };
5296 } catch ( e ) {
5297 return null;
5298 }
5299 }
5300
5301 /**
5302 * Resolve form status for submit.
5303 *
5304 * Priority:
5305 * 1) shortcode param exposed via _wpbc.booking__get_param_value(..., 'form_status')
5306 * 2) detect preview URL args
5307 * 3) fallback: published
5308 *
5309 * @param {number} resource_id
5310 * @return {string} 'preview'|'published'
5311 */
5312 function wpbc__get_form_status_for_submit(resource_id) {
5313
5314 var status = '';
5315
5316 try {
5317 if ( (typeof _wpbc !== 'undefined') && _wpbc.booking__get_param_value ) {
5318 status = _wpbc.booking__get_param_value( resource_id, 'form_status' );
5319 }
5320 } catch ( e ) {}
5321
5322 status = (status == null) ? '' : String( status );
5323 status = status.toLowerCase();
5324
5325 // URL-based detection for preview iframe.
5326 var preview_args = wpbc__get_bfb_preview_args_from_location();
5327 if ( preview_args ) {
5328 return 'preview';
5329 }
5330
5331 return (status === 'preview') ? 'preview' : 'published';
5332 }
5333
5334
5335
5336 // == Backward-compatible wrappers (keep old global names working 100% as before). =====================================
5337 function mybooking_submit( submit_form, resource_id, wpdev_active_locale ) {
5338 return wpbc_booking_form_submit( submit_form, resource_id, wpdev_active_locale );
5339 }
5340
5341 try {
5342 var ev = (typeof CustomEvent === 'function') ? new CustomEvent( 'wpbc-ready' ) : document.createEvent( 'Event' );
5343 if ( ev.initEvent ) {
5344 ev.initEvent( 'wpbc-ready', true, true );
5345 }
5346 document.dispatchEvent( ev );
5347 console.log( 'wpbc-ready' );
5348 } catch ( e ) {
5349 console.error( "WPBC event 'wpbc-ready' failed!", e );
5350 }
5351
5352 //# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndwYmNfdXRpbHMuanMiLCJ3cGJjLmpzIiwiZGV2X2xvZy5qcyIsImFqeF9sb2FkX2JhbGFuY2VyLmpzIiwid3BiY19jYWwuanMiLCJkYXlzX3NlbGVjdF9jdXN0b20uanMiLCJ3cGJjX2NhbF9hanguanMiLCJ3cGJjX2ZlX21lc3NhZ2VzLmpzIiwidGltZWxpbmVfcG9wb3Zlci5qcyIsIndwYmNfY2FsX2xvYWRlci5qcyIsImF1dG9maWxsX2ZpZWxkcy5qcyIsImJvb2tpbmdfZm9ybV9zdWJtaXQuanMiLCJ3cGJjX3JlYWR5X2V2ZW50LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQ2xHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQy9oQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQ2hFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FDdFFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUNwd0VBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQ3hNQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FDbFJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUNoWkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FDbERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUN4VUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQ25IQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUM5cUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJmaWxlIjoid3BiY19hbGwuanMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcclxuICogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcbiAqIEphdmFTY3JpcHQgVXRpbCBGdW5jdGlvbnNcdFx0Li4vaW5jbHVkZXMvX19qcy91dGlscy93cGJjX3V0aWxzLmpzXHJcbiAqID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG4gKi9cclxuXHJcbi8qKlxyXG4gKiBUcmltICBzdHJpbmdzIGFuZCBhcnJheSBqb2luZWQgd2l0aCAgKCwpXHJcbiAqXHJcbiAqIEBwYXJhbSBzdHJpbmdfdG9fdHJpbSAgIHN0cmluZyAvIGFycmF5XHJcbiAqIEByZXR1cm5zIHN0cmluZ1xyXG4gKi9cclxuZnVuY3Rpb24gd3BiY190cmltKHN0cmluZ190b190cmltKSB7XHJcblxyXG5cdGlmICggQXJyYXkuaXNBcnJheSggc3RyaW5nX3RvX3RyaW0gKSApIHtcclxuXHRcdHN0cmluZ190b190cmltID0gc3RyaW5nX3RvX3RyaW0uam9pbiggJywnICk7XHJcblx0fVxyXG5cclxuXHRpZiAoICdzdHJpbmcnID09IHR5cGVvZiAoc3RyaW5nX3RvX3RyaW0pICkge1xyXG5cdFx0c3RyaW5nX3RvX3RyaW0gPSBzdHJpbmdfdG9fdHJpbS50cmltKCk7XHJcblx0fVxyXG5cclxuXHRyZXR1cm4gc3RyaW5nX3RvX3RyaW07XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDaGVjayBpZiBlbGVtZW50IGluIGFycmF5XHJcbiAqXHJcbiAqIEBwYXJhbSBhcnJheV9oZXJlXHRcdGFycmF5XHJcbiAqIEBwYXJhbSBwX3ZhbFx0XHRcdFx0ZWxlbWVudCB0byAgY2hlY2tcclxuICogQHJldHVybnMge2Jvb2xlYW59XHJcbiAqL1xyXG5mdW5jdGlvbiB3cGJjX2luX2FycmF5KGFycmF5X2hlcmUsIHBfdmFsKSB7XHJcblx0Zm9yICggdmFyIGkgPSAwLCBsID0gYXJyYXlfaGVyZS5sZW5ndGg7IGkgPCBsOyBpKysgKSB7XHJcblx0XHRpZiAoIGFycmF5X2hlcmVbaV0gPT0gcF92YWwgKSB7XHJcblx0XHRcdHJldHVybiB0cnVlO1xyXG5cdFx0fVxyXG5cdH1cclxuXHRyZXR1cm4gZmFsc2U7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBQcmV2ZW50IG9wZW5pbmcgYmxhbmsgd2luZG93cyBvbiBXb3JkUHJlc3MgcGxheWdyb3VuZCBmb3IgcHNldWRvIGxpbmtzIGxpa2UgdGhpczogPGEgaHJlZj1cImphdmFzY3JpcHQ6dm9pZCgwKVwiPiBvciAjIHRvIHN0YXkgaW4gdGhlIHNhbWUgdGFiLlxyXG4gKi9cclxuKGZ1bmN0aW9uICgpIHtcclxuXHQndXNlIHN0cmljdCc7XHJcblxyXG5cdGZ1bmN0aW9uIGlzX3BsYXlncm91bmRfb3JpZ2luKCkge1xyXG5cdFx0cmV0dXJuIGxvY2F0aW9uLm9yaWdpbiA9PT0gJ2h0dHBzOi8vcGxheWdyb3VuZC53b3JkcHJlc3MubmV0JztcclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIGlzX3BzZXVkb19saW5rKGEpIHtcclxuXHRcdGlmICggIWEgfHwgIWEuZ2V0QXR0cmlidXRlICkgcmV0dXJuIHRydWU7XHJcblx0XHR2YXIgaHJlZiA9IChhLmdldEF0dHJpYnV0ZSggJ2hyZWYnICkgfHwgJycpLnRyaW0oKS50b0xvd2VyQ2FzZSgpO1xyXG5cdFx0cmV0dXJuIChcclxuXHRcdFx0IWhyZWYgfHxcclxuXHRcdFx0aHJlZiA9PT0gJyMnIHx8XHJcblx0XHRcdGhyZWYuaW5kZXhPZiggJyMnICkgPT09IDAgfHxcclxuXHRcdFx0aHJlZi5pbmRleE9mKCAnamF2YXNjcmlwdDonICkgPT09IDAgfHxcclxuXHRcdFx0aHJlZi5pbmRleE9mKCAnbWFpbHRvOicgKSA9PT0gMCB8fFxyXG5cdFx0XHRocmVmLmluZGV4T2YoICd0ZWw6JyApID09PSAwXHJcblx0XHQpO1xyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gZml4X3RhcmdldChhKSB7XHJcblx0XHRpZiAoICEgYSApIHJldHVybjtcclxuXHRcdGlmICggaXNfcHNldWRvX2xpbmsoIGEgKSB8fCBhLmhhc0F0dHJpYnV0ZSggJ2RhdGEtd3Atbm8tYmxhbmsnICkgKSB7XHJcblx0XHRcdGEudGFyZ2V0ID0gJ19zZWxmJztcclxuXHRcdH1cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIGluaXRfZml4KCkge1xyXG5cdFx0Ly8gT3B0aW9uYWw6IGNsZWFuIHVwIGN1cnJlbnQgRE9NIChoYXJtbGVzc+KAlGFmZmVjdHMgb25seSBwc2V1ZG8vZGF0YW1hcmtlZCBsaW5rcykuXHJcblx0XHR2YXIgbm9kZXMgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCAnYVtocmVmXScgKTtcclxuXHRcdGZvciAoIHZhciBpID0gMDsgaSA8IG5vZGVzLmxlbmd0aDsgaSsrICkgZml4X3RhcmdldCggbm9kZXNbaV0gKTtcclxuXHJcblx0XHQvLyBMYXRlIGJ1YmJsZS1waGFzZSBsaXN0ZW5lcnMgKHJ1biBhZnRlciBQbGF5Z3JvdW5kJ3MgaGFuZGxlcnMpXHJcblx0XHRkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCAnY2xpY2snLCBmdW5jdGlvbiAoZSkge1xyXG5cdFx0XHR2YXIgYSA9IGUudGFyZ2V0ICYmIGUudGFyZ2V0LmNsb3Nlc3QgPyBlLnRhcmdldC5jbG9zZXN0KCAnYVtocmVmXScgKSA6IG51bGw7XHJcblx0XHRcdGlmICggYSApIGZpeF90YXJnZXQoIGEgKTtcclxuXHRcdH0sIGZhbHNlICk7XHJcblxyXG5cdFx0ZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lciggJ2ZvY3VzaW4nLCBmdW5jdGlvbiAoZSkge1xyXG5cdFx0XHR2YXIgYSA9IGUudGFyZ2V0ICYmIGUudGFyZ2V0LmNsb3Nlc3QgPyBlLnRhcmdldC5jbG9zZXN0KCAnYVtocmVmXScgKSA6IG51bGw7XHJcblx0XHRcdGlmICggYSApIGZpeF90YXJnZXQoIGEgKTtcclxuXHRcdH0gKTtcclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHNjaGVkdWxlX2luaXQoKSB7XHJcblx0XHRpZiAoICFpc19wbGF5Z3JvdW5kX29yaWdpbigpICkgcmV0dXJuO1xyXG5cdFx0c2V0VGltZW91dCggaW5pdF9maXgsIDEwMDAgKTsgLy8gZW5zdXJlIHdlIGF0dGFjaCBhZnRlciBQbGF5Z3JvdW5kJ3Mgc2NyaXB0LlxyXG5cdH1cclxuXHJcblx0aWYgKCBkb2N1bWVudC5yZWFkeVN0YXRlID09PSAnbG9hZGluZycgKSB7XHJcblx0XHRkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCAnRE9NQ29udGVudExvYWRlZCcsIHNjaGVkdWxlX2luaXQgKTtcclxuXHR9IGVsc2Uge1xyXG5cdFx0c2NoZWR1bGVfaW5pdCgpO1xyXG5cdH1cclxufSkoKTsiLCJcInVzZSBzdHJpY3RcIjtcclxuLyoqXHJcbiAqID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG4gKlx0aW5jbHVkZXMvX19qcy93cGJjL3dwYmMuanNcclxuICogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcbiAqL1xyXG5cclxuLyoqXHJcbiAqIERlZXAgQ2xvbmUgb2Ygb2JqZWN0IG9yIGFycmF5XHJcbiAqXHJcbiAqIEBwYXJhbSBvYmpcclxuICogQHJldHVybnMge2FueX1cclxuICovXHJcbmZ1bmN0aW9uIHdwYmNfY2xvbmVfb2JqKCBvYmogKXtcclxuXHJcblx0cmV0dXJuIEpTT04ucGFyc2UoIEpTT04uc3RyaW5naWZ5KCBvYmogKSApO1xyXG59XHJcblxyXG5cclxuXHJcbi8qKlxyXG4gKiBNYWluIF93cGJjIEpTIG9iamVjdFxyXG4gKi9cclxuXHJcbnZhciBfd3BiYyA9IChmdW5jdGlvbiAoIG9iaiwgJCkge1xyXG5cclxuXHQvLyBTZWN1cmUgcGFyYW1ldGVycyBmb3IgQWpheFx0LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0dmFyIHBfc2VjdXJlID0gb2JqLnNlY3VyaXR5X29iaiA9IG9iai5zZWN1cml0eV9vYmogfHwge1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHR1c2VyX2lkOiAwLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRub25jZSAgOiAnJyxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0bG9jYWxlIDogJydcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCAgfTtcclxuXHRvYmouc2V0X3NlY3VyZV9wYXJhbSA9IGZ1bmN0aW9uICggcGFyYW1fa2V5LCBwYXJhbV92YWwgKSB7XHJcblx0XHRwX3NlY3VyZVsgcGFyYW1fa2V5IF0gPSBwYXJhbV92YWw7XHJcblx0fTtcclxuXHJcblx0b2JqLmdldF9zZWN1cmVfcGFyYW0gPSBmdW5jdGlvbiAoIHBhcmFtX2tleSApIHtcclxuXHRcdHJldHVybiBwX3NlY3VyZVsgcGFyYW1fa2V5IF07XHJcblx0fTtcclxuXHJcblxyXG5cdC8vIENhbGVuZGFycyBcdC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHR2YXIgcF9jYWxlbmRhcnMgPSBvYmouY2FsZW5kYXJzX29iaiA9IG9iai5jYWxlbmRhcnNfb2JqIHx8IHtcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gc29ydCAgICAgICAgICAgIDogXCJib29raW5nX2lkXCIsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vIHNvcnRfdHlwZSAgICAgICA6IFwiREVTQ1wiLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQvLyBwYWdlX251bSAgICAgICAgOiAxLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQvLyBwYWdlX2l0ZW1zX2NvdW50OiAxMCxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gY3JlYXRlX2RhdGUgICAgIDogXCJcIixcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8ga2V5d29yZCAgICAgICAgIDogXCJcIixcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gc291cmNlICAgICAgICAgIDogXCJcIlxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdH07XHJcblxyXG5cdC8qKlxyXG5cdCAqICBDaGVjayBpZiBjYWxlbmRhciBmb3Igc3BlY2lmaWMgYm9va2luZyByZXNvdXJjZSBkZWZpbmVkICAgOjogICB0cnVlIHwgZmFsc2VcclxuXHQgKlxyXG5cdCAqIEBwYXJhbSB7c3RyaW5nfGludH0gcmVzb3VyY2VfaWRcclxuXHQgKiBAcmV0dXJucyB7Ym9vbGVhbn1cclxuXHQgKi9cclxuXHRvYmouY2FsZW5kYXJfX2lzX2RlZmluZWQgPSBmdW5jdGlvbiAoIHJlc291cmNlX2lkICkge1xyXG5cclxuXHRcdHJldHVybiAoJ3VuZGVmaW5lZCcgIT09IHR5cGVvZiggcF9jYWxlbmRhcnNbICdjYWxlbmRhcl8nICsgcmVzb3VyY2VfaWQgXSApICk7XHJcblx0fTtcclxuXHJcblx0LyoqXHJcblx0ICogIENyZWF0ZSBDYWxlbmRhciBpbml0aWFsaXppbmdcclxuXHQgKlxyXG5cdCAqIEBwYXJhbSB7c3RyaW5nfGludH0gcmVzb3VyY2VfaWRcclxuXHQgKi9cclxuXHRvYmouY2FsZW5kYXJfX2luaXQgPSBmdW5jdGlvbiAoIHJlc291cmNlX2lkICkge1xyXG5cclxuXHRcdHBfY2FsZW5kYXJzWyAnY2FsZW5kYXJfJyArIHJlc291cmNlX2lkIF0gPSB7fTtcclxuXHRcdHBfY2FsZW5kYXJzWyAnY2FsZW5kYXJfJyArIHJlc291cmNlX2lkIF1bICdpZCcgXSA9IHJlc291cmNlX2lkO1xyXG5cdFx0cF9jYWxlbmRhcnNbICdjYWxlbmRhcl8nICsgcmVzb3VyY2VfaWQgXVsgJ3BlbmRpbmdfZGF5c19zZWxlY3RhYmxlJyBdID0gZmFsc2U7XHJcblxyXG5cdH07XHJcblxyXG5cdC8qKlxyXG5cdCAqIENoZWNrICBpZiB0aGUgdHlwZSBvZiB0aGlzIHByb3BlcnR5ICBpcyBJTlRcclxuXHQgKiBAcGFyYW0gcHJvcGVydHlfbmFtZVxyXG5cdCAqIEByZXR1cm5zIHtib29sZWFufVxyXG5cdCAqL1xyXG5cdG9iai5jYWxlbmRhcl9faXNfcHJvcF9pbnQgPSBmdW5jdGlvbiAoIHByb3BlcnR5X25hbWUgKSB7XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQvLyBGaXhJbjogOS45LjAuMjkuXHJcblxyXG5cdFx0dmFyIHBfY2FsZW5kYXJfaW50X3Byb3BlcnRpZXMgPSBbJ2R5bmFtaWNfX2RheXNfbWluJywgJ2R5bmFtaWNfX2RheXNfbWF4JywgJ2ZpeGVkX19kYXlzX251bSddO1xyXG5cclxuXHRcdHZhciBpc19pbmNsdWRlID0gcF9jYWxlbmRhcl9pbnRfcHJvcGVydGllcy5pbmNsdWRlcyggcHJvcGVydHlfbmFtZSApO1xyXG5cclxuXHRcdHJldHVybiBpc19pbmNsdWRlO1xyXG5cdH07XHJcblxyXG5cclxuXHQvKipcclxuXHQgKiBTZXQgcGFyYW1zIGZvciBhbGwgIGNhbGVuZGFyc1xyXG5cdCAqXHJcblx0ICogQHBhcmFtIHtvYmplY3R9IGNhbGVuZGFyc19vYmpcdFx0T2JqZWN0IHsgY2FsZW5kYXJfMToge30gfVxyXG5cdCAqIFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCBjYWxlbmRhcl8zOiB7fSwgLi4uIH1cclxuXHQgKi9cclxuXHRvYmouY2FsZW5kYXJzX2FsbF9fc2V0ID0gZnVuY3Rpb24gKCBjYWxlbmRhcnNfb2JqICkge1xyXG5cdFx0cF9jYWxlbmRhcnMgPSBjYWxlbmRhcnNfb2JqO1xyXG5cdH07XHJcblxyXG5cdC8qKlxyXG5cdCAqIEdldCBib29raW5ncyBpbiBhbGwgY2FsZW5kYXJzXHJcblx0ICpcclxuXHQgKiBAcmV0dXJucyB7b2JqZWN0fHt9fVxyXG5cdCAqL1xyXG5cdG9iai5jYWxlbmRhcnNfYWxsX19nZXQgPSBmdW5jdGlvbiAoKSB7XHJcblx0XHRyZXR1cm4gcF9jYWxlbmRhcnM7XHJcblx0fTtcclxuXHJcblx0LyoqXHJcblx0ICogR2V0IGNhbGVuZGFyIG9iamVjdCAgIDo6ICAgeyBpZDogMSwg4oCmIH1cclxuXHQgKlxyXG5cdCAqIEBwYXJhbSB7c3RyaW5nfGludH0gcmVzb3VyY2VfaWRcdFx0XHRcdCAgJzInXHJcblx0ICogQHJldHVybnMge29iamVjdHxib29sZWFufVx0XHRcdFx0XHR7IGlkOiAyICzigKYgfVxyXG5cdCAqL1xyXG5cdG9iai5jYWxlbmRhcl9fZ2V0X3BhcmFtZXRlcnMgPSBmdW5jdGlvbiAoIHJlc291cmNlX2lkICkge1xyXG5cclxuXHRcdGlmICggb2JqLmNhbGVuZGFyX19pc19kZWZpbmVkKCByZXNvdXJjZV9pZCApICl7XHJcblxyXG5cdFx0XHRyZXR1cm4gcF9jYWxlbmRhcnNbICdjYWxlbmRhcl8nICsgcmVzb3VyY2VfaWQgXTtcclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdHJldHVybiBmYWxzZTtcclxuXHRcdH1cclxuXHR9O1xyXG5cclxuXHQvKipcclxuXHQgKiBTZXQgY2FsZW5kYXIgb2JqZWN0ICAgOjogICB7IGRhdGVzOiAgT2JqZWN0IHsgXCIyMDIzLTA3LTIxXCI6IHvigKZ9LCBcIjIwMjMtMDctMjJcIjoge+KApn0sIFwiMjAyMy0wNy0yM1wiOiB74oCmfSwg4oCmIH1cclxuXHQgKlxyXG5cdCAqIGlmIGNhbGVuZGFyIG9iamVjdCAgbm90IGRlZmluZWQsIHRoZW4gIGl0J3Mgd2lsbCBiZSBkZWZpbmVkIGFuZCBJRCBzZXRcclxuXHQgKiBpZiBjYWxlbmRhciBleGlzdCwgdGhlbiAgc3lzdGVtIHNldCAgYXMgbmV3IG9yIG92ZXJ3cml0ZSBvbmx5IHByb3BlcnRpZXMgZnJvbSBjYWxlbmRhcl9wcm9wZXJ0eV9vYmogcGFyYW1ldGVyLCAgYnV0IG90aGVyIHByb3BlcnRpZXMgd2lsbCBiZSBleGlzdGVkIGFuZCBub3Qgb3ZlcndyaXRlLCBsaWtlICdpZCdcclxuXHQgKlxyXG5cdCAqIEBwYXJhbSB7c3RyaW5nfGludH0gcmVzb3VyY2VfaWRcdFx0XHRcdCAgJzInXHJcblx0ICogQHBhcmFtIHtvYmplY3R9IGNhbGVuZGFyX3Byb3BlcnR5X29ialx0XHRcdFx0XHQgIHsgIGRhdGVzOiAgT2JqZWN0IHsgXCIyMDIzLTA3LTIxXCI6IHvigKZ9LCBcIjIwMjMtMDctMjJcIjoge+KApn0sIFwiMjAyMy0wNy0yM1wiOiB74oCmfSwg4oCmIH0gIH1cclxuXHQgKiBAcGFyYW0ge2Jvb2xlYW59IGlzX2NvbXBsZXRlX292ZXJ3cml0ZVx0XHQgIGlmICd0cnVlJyAoZGVmYXVsdDogJ2ZhbHNlJyksICB0aGVuICBvbmx5IG92ZXJ3cml0ZSBvciBhZGQgIG5ldyBwcm9wZXJ0aWVzIGluICBjYWxlbmRhcl9wcm9wZXJ0eV9vYmpcclxuXHQgKiBAcmV0dXJucyB7Kn1cclxuXHQgKlxyXG5cdCAqIEV4YW1wbGVzOlxyXG5cdCAqXHJcblx0ICogQ29tbW9uIHVzYWdlIGluIFBIUDpcclxuXHQgKiAgIFx0XHRcdGVjaG8gXCIgIF93cGJjLmNhbGVuZGFyX19zZXQoICBcIiAuaW50dmFsKCAkcmVzb3VyY2VfaWQgKSAuIFwiLCB7ICdkYXRlcyc6IFwiIC4gd3BfanNvbl9lbmNvZGUoICRhdmFpbGFiaWxpdHlfcGVyX2RheXNfYXJyICkgLiBcIiB9ICk7XCI7XHJcblx0ICovXHJcblx0b2JqLmNhbGVuZGFyX19zZXRfcGFyYW1ldGVycyA9IGZ1bmN0aW9uICggcmVzb3VyY2VfaWQsIGNhbGVuZGFyX3Byb3BlcnR5X29iaiwgaXNfY29tcGxldGVfb3ZlcndyaXRlID0gZmFsc2UgICkge1xyXG5cclxuXHRcdGlmICggKCFvYmouY2FsZW5kYXJfX2lzX2RlZmluZWQoIHJlc291cmNlX2lkICkpIHx8ICh0cnVlID09PSBpc19jb21wbGV0ZV9vdmVyd3JpdGUpICl7XHJcblx0XHRcdG9iai5jYWxlbmRhcl9faW5pdCggcmVzb3VyY2VfaWQgKTtcclxuXHRcdH1cclxuXHJcblx0XHRmb3IgKCB2YXIgcHJvcF9uYW1lIGluIGNhbGVuZGFyX3Byb3BlcnR5X29iaiApe1xyXG5cclxuXHRcdFx0cF9jYWxlbmRhcnNbICdjYWxlbmRhcl8nICsgcmVzb3VyY2VfaWQgXVsgcHJvcF9uYW1lIF0gPSBjYWxlbmRhcl9wcm9wZXJ0eV9vYmpbIHByb3BfbmFtZSBdO1xyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBwX2NhbGVuZGFyc1sgJ2NhbGVuZGFyXycgKyByZXNvdXJjZV9pZCBdO1xyXG5cdH07XHJcblxyXG5cdC8qKlxyXG5cdCAqIFNldCBwcm9wZXJ0eSAgdG8gIGNhbGVuZGFyXHJcblx0ICogQHBhcmFtIHJlc291cmNlX2lkXHRcIjFcIlxyXG5cdCAqIEBwYXJhbSBwcm9wX25hbWVcdFx0bmFtZSBvZiBwcm9wZXJ0eVxyXG5cdCAqIEBwYXJhbSBwcm9wX3ZhbHVlXHR2YWx1ZSBvZiBwcm9wZXJ0eVxyXG5cdCAqIEByZXR1cm5zIHsqfVx0XHRcdGNhbGVuZGFyIG9iamVjdFxyXG5cdCAqL1xyXG5cdG9iai5jYWxlbmRhcl9fc2V0X3BhcmFtX3ZhbHVlID0gZnVuY3Rpb24gKCByZXNvdXJjZV9pZCwgcHJvcF9uYW1lLCBwcm9wX3ZhbHVlICkge1xyXG5cclxuXHRcdGlmICggKCFvYmouY2FsZW5kYXJfX2lzX2RlZmluZWQoIHJlc291cmNlX2lkICkpICl7XHJcblx0XHRcdG9iai5jYWxlbmRhcl9faW5pdCggcmVzb3VyY2VfaWQgKTtcclxuXHRcdH1cclxuXHJcblx0XHRwX2NhbGVuZGFyc1sgJ2NhbGVuZGFyXycgKyByZXNvdXJjZV9pZCBdWyBwcm9wX25hbWUgXSA9IHByb3BfdmFsdWU7XHJcblxyXG5cdFx0cmV0dXJuIHBfY2FsZW5kYXJzWyAnY2FsZW5kYXJfJyArIHJlc291cmNlX2lkIF07XHJcblx0fTtcclxuXHJcblx0LyoqXHJcblx0ICogIEdldCBjYWxlbmRhciBwcm9wZXJ0eSB2YWx1ZSAgIFx0OjogICBtaXhlZCB8IG51bGxcclxuXHQgKlxyXG5cdCAqIEBwYXJhbSB7c3RyaW5nfGludH0gIHJlc291cmNlX2lkXHRcdCcxJ1xyXG5cdCAqIEBwYXJhbSB7c3RyaW5nfSBwcm9wX25hbWVcdFx0XHQnc2VsZWN0aW9uX21vZGUnXHJcblx0ICogQHJldHVybnMgeyp8bnVsbH1cdFx0XHRcdFx0bWl4ZWQgfCBudWxsXHJcblx0ICovXHJcblx0b2JqLmNhbGVuZGFyX19nZXRfcGFyYW1fdmFsdWUgPSBmdW5jdGlvbiggcmVzb3VyY2VfaWQsIHByb3BfbmFtZSApe1xyXG5cclxuXHRcdGlmIChcclxuXHRcdFx0ICAgKCBvYmouY2FsZW5kYXJfX2lzX2RlZmluZWQoIHJlc291cmNlX2lkICkgKVxyXG5cdFx0XHQmJiAoICd1bmRlZmluZWQnICE9PSB0eXBlb2YgKCBwX2NhbGVuZGFyc1sgJ2NhbGVuZGFyXycgKyByZXNvdXJjZV9pZCBdWyBwcm9wX25hbWUgXSApIClcclxuXHRcdCl7XHJcblx0XHRcdC8vIEZpeEluOiA5LjkuMC4yOS5cclxuXHRcdFx0aWYgKCBvYmouY2FsZW5kYXJfX2lzX3Byb3BfaW50KCBwcm9wX25hbWUgKSApe1xyXG5cdFx0XHRcdHBfY2FsZW5kYXJzWyAnY2FsZW5kYXJfJyArIHJlc291cmNlX2lkIF1bIHByb3BfbmFtZSBdID0gcGFyc2VJbnQoIHBfY2FsZW5kYXJzWyAnY2FsZW5kYXJfJyArIHJlc291cmNlX2lkIF1bIHByb3BfbmFtZSBdICk7XHJcblx0XHRcdH1cclxuXHRcdFx0cmV0dXJuICBwX2NhbGVuZGFyc1sgJ2NhbGVuZGFyXycgKyByZXNvdXJjZV9pZCBdWyBwcm9wX25hbWUgXTtcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gbnVsbDtcdFx0Ly8gSWYgc29tZSBwcm9wZXJ0eSBub3QgZGVmaW5lZCwgdGhlbiBudWxsO1xyXG5cdH07XHJcblx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHJcblxyXG5cdC8vIEJvb2tpbmdzIFx0LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdHZhciBwX2Jvb2tpbmdzID0gb2JqLmJvb2tpbmdzX29iaiA9IG9iai5ib29raW5nc19vYmogfHwge1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vIGNhbGVuZGFyXzE6IE9iamVjdCB7XHJcbiBcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vXHRcdFx0XHRcdFx0ICAgaWQ6ICAgICAxXHJcbiBcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vXHRcdFx0XHRcdFx0ICwgZGF0ZXM6ICBPYmplY3QgeyBcIjIwMjMtMDctMjFcIjoge+KApn0sIFwiMjAyMy0wNy0yMlwiOiB74oCmfSwgXCIyMDIzLTA3LTIzXCI6IHvigKZ9LCDigKZcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQvLyB9XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdH07XHJcblxyXG5cdC8qKlxyXG5cdCAqICBDaGVjayBpZiBib29raW5ncyBmb3Igc3BlY2lmaWMgYm9va2luZyByZXNvdXJjZSBkZWZpbmVkICAgOjogICB0cnVlIHwgZmFsc2VcclxuXHQgKlxyXG5cdCAqIEBwYXJhbSB7c3RyaW5nfGludH0gcmVzb3VyY2VfaWRcclxuXHQgKiBAcmV0dXJucyB7Ym9vbGVhbn1cclxuXHQgKi9cclxuXHRvYmouYm9va2luZ3NfaW5fY2FsZW5kYXJfX2lzX2RlZmluZWQgPSBmdW5jdGlvbiAoIHJlc291cmNlX2lkICkge1xyXG5cclxuXHRcdHJldHVybiAoJ3VuZGVmaW5lZCcgIT09IHR5cGVvZiggcF9ib29raW5nc1sgJ2NhbGVuZGFyXycgKyByZXNvdXJjZV9pZCBdICkgKTtcclxuXHR9O1xyXG5cclxuXHQvKipcclxuXHQgKiBHZXQgYm9va2luZ3MgY2FsZW5kYXIgb2JqZWN0ICAgOjogICB7IGlkOiAxICwgZGF0ZXM6ICBPYmplY3QgeyBcIjIwMjMtMDctMjFcIjoge+KApn0sIFwiMjAyMy0wNy0yMlwiOiB74oCmfSwgXCIyMDIzLTA3LTIzXCI6IHvigKZ9LCDigKYgfVxyXG5cdCAqXHJcblx0ICogQHBhcmFtIHtzdHJpbmd8aW50fSByZXNvdXJjZV9pZFx0XHRcdFx0ICAnMidcclxuXHQgKiBAcmV0dXJucyB7b2JqZWN0fGJvb2xlYW59XHRcdFx0XHRcdHsgaWQ6IDIgLCBkYXRlczogIE9iamVjdCB7IFwiMjAyMy0wNy0yMVwiOiB74oCmfSwgXCIyMDIzLTA3LTIyXCI6IHvigKZ9LCBcIjIwMjMtMDctMjNcIjoge+KApn0sIOKApiB9XHJcblx0ICovXHJcblx0b2JqLmJvb2tpbmdzX2luX2NhbGVuZGFyX19nZXQgPSBmdW5jdGlvbiggcmVzb3VyY2VfaWQgKXtcclxuXHJcblx0XHRpZiAoIG9iai5ib29raW5nc19pbl9jYWxlbmRhcl9faXNfZGVmaW5lZCggcmVzb3VyY2VfaWQgKSApe1xyXG5cclxuXHRcdFx0cmV0dXJuIHBfYm9va2luZ3NbICdjYWxlbmRhcl8nICsgcmVzb3VyY2VfaWQgXTtcclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdHJldHVybiBmYWxzZTtcclxuXHRcdH1cclxuXHR9O1xyXG5cclxuXHQvKipcclxuXHQgKiBTZXQgYm9va2luZ3MgY2FsZW5kYXIgb2JqZWN0ICAgOjogICB7IGRhdGVzOiAgT2JqZWN0IHsgXCIyMDIzLTA3LTIxXCI6IHvigKZ9LCBcIjIwMjMtMDctMjJcIjoge+KApn0sIFwiMjAyMy0wNy0yM1wiOiB74oCmfSwg4oCmIH1cclxuXHQgKlxyXG5cdCAqIGlmIGNhbGVuZGFyIG9iamVjdCAgbm90IGRlZmluZWQsIHRoZW4gIGl0J3Mgd2lsbCBiZSBkZWZpbmVkIGFuZCBJRCBzZXRcclxuXHQgKiBpZiBjYWxlbmRhciBleGlzdCwgdGhlbiAgc3lzdGVtIHNldCAgYXMgbmV3IG9yIG92ZXJ3cml0ZSBvbmx5IHByb3BlcnRpZXMgZnJvbSBjYWxlbmRhcl9vYmogcGFyYW1ldGVyLCAgYnV0IG90aGVyIHByb3BlcnRpZXMgd2lsbCBiZSBleGlzdGVkIGFuZCBub3Qgb3ZlcndyaXRlLCBsaWtlICdpZCdcclxuXHQgKlxyXG5cdCAqIEBwYXJhbSB7c3RyaW5nfGludH0gcmVzb3VyY2VfaWRcdFx0XHRcdCAgJzInXHJcblx0ICogQHBhcmFtIHtvYmplY3R9IGNhbGVuZGFyX29ialx0XHRcdFx0XHQgIHsgIGRhdGVzOiAgT2JqZWN0IHsgXCIyMDIzLTA3LTIxXCI6IHvigKZ9LCBcIjIwMjMtMDctMjJcIjoge+KApn0sIFwiMjAyMy0wNy0yM1wiOiB74oCmfSwg4oCmIH0gIH1cclxuXHQgKiBAcmV0dXJucyB7Kn1cclxuXHQgKlxyXG5cdCAqIEV4YW1wbGVzOlxyXG5cdCAqXHJcblx0ICogQ29tbW9uIHVzYWdlIGluIFBIUDpcclxuXHQgKiAgIFx0XHRcdGVjaG8gXCIgIF93cGJjLmJvb2tpbmdzX2luX2NhbGVuZGFyX19zZXQoICBcIiAuaW50dmFsKCAkcmVzb3VyY2VfaWQgKSAuIFwiLCB7ICdkYXRlcyc6IFwiIC4gd3BfanNvbl9lbmNvZGUoICRhdmFpbGFiaWxpdHlfcGVyX2RheXNfYXJyICkgLiBcIiB9ICk7XCI7XHJcblx0ICovXHJcblx0b2JqLmJvb2tpbmdzX2luX2NhbGVuZGFyX19zZXQgPSBmdW5jdGlvbiggcmVzb3VyY2VfaWQsIGNhbGVuZGFyX29iaiApe1xyXG5cclxuXHRcdGlmICggISBvYmouYm9va2luZ3NfaW5fY2FsZW5kYXJfX2lzX2RlZmluZWQoIHJlc291cmNlX2lkICkgKXtcclxuXHRcdFx0cF9ib29raW5nc1sgJ2NhbGVuZGFyXycgKyByZXNvdXJjZV9pZCBdID0ge307XHJcblx0XHRcdHBfYm9va2luZ3NbICdjYWxlbmRhcl8nICsgcmVzb3VyY2VfaWQgXVsgJ2lkJyBdID0gcmVzb3VyY2VfaWQ7XHJcblx0XHR9XHJcblxyXG5cdFx0Zm9yICggdmFyIHByb3BfbmFtZSBpbiBjYWxlbmRhcl9vYmogKXtcclxuXHJcblx0XHRcdHBfYm9va2luZ3NbICdjYWxlbmRhcl8nICsgcmVzb3VyY2VfaWQgXVsgcHJvcF9uYW1lIF0gPSBjYWxlbmRhcl9vYmpbIHByb3BfbmFtZSBdO1xyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBwX2Jvb2tpbmdzWyAnY2FsZW5kYXJfJyArIHJlc291cmNlX2lkIF07XHJcblx0fTtcclxuXHJcblx0Ly8gRGF0ZXNcclxuXHJcblx0LyoqXHJcblx0ICogIEdldCBib29raW5ncyBkYXRhIGZvciBBTEwgRGF0ZXMgaW4gY2FsZW5kYXIgICA6OiAgIGZhbHNlIHwgeyBcIjIwMjMtMDctMjJcIjoge+KApn0sIFwiMjAyMy0wNy0yM1wiOiB74oCmfSwg4oCmIH1cclxuXHQgKlxyXG5cdCAqIEBwYXJhbSB7c3RyaW5nfGludH0gcmVzb3VyY2VfaWRcdFx0XHQnMSdcclxuXHQgKiBAcmV0dXJucyB7b2JqZWN0fGJvb2xlYW59XHRcdFx0XHRmYWxzZSB8IE9iamVjdCB7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XCIyMDIzLTA3LTI0XCI6IE9iamVjdCB7IFsnc3VtbWFyeSddWydzdGF0dXNfZm9yX2RheSddOiBcImF2YWlsYWJsZVwiLCBkYXlfYXZhaWxhYmlsaXR5OiAxLCBtYXhfY2FwYWNpdHk6IDEsIOKApiB9XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XCIyMDIzLTA3LTI2XCI6IE9iamVjdCB7IFsnc3VtbWFyeSddWydzdGF0dXNfZm9yX2RheSddOiBcImZ1bGxfZGF5X2Jvb2tpbmdcIiwgWydzdW1tYXJ5J11bJ3N0YXR1c19mb3JfYm9va2luZ3MnXTogXCJwZW5kaW5nXCIsIGRheV9hdmFpbGFiaWxpdHk6IDAsIOKApiB9XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XCIyMDIzLTA3LTI5XCI6IE9iamVjdCB7IFsnc3VtbWFyeSddWydzdGF0dXNfZm9yX2RheSddOiBcInJlc291cmNlX2F2YWlsYWJpbGl0eVwiLCBkYXlfYXZhaWxhYmlsaXR5OiAwLCBtYXhfY2FwYWNpdHk6IDEsIOKApiB9XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XCIyMDIzLTA3LTMwXCI6IHvigKZ9LCBcIjIwMjMtMDctMzFcIjoge+KApn0sIOKAplxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHR9XHJcblx0ICovXHJcblx0b2JqLmJvb2tpbmdzX2luX2NhbGVuZGFyX19nZXRfZGF0ZXMgPSBmdW5jdGlvbiggcmVzb3VyY2VfaWQpe1xyXG5cclxuXHRcdGlmIChcclxuXHRcdFx0ICAgKCBvYmouYm9va2luZ3NfaW5fY2FsZW5kYXJfX2lzX2RlZmluZWQoIHJlc291cmNlX2lkICkgKVxyXG5cdFx0XHQmJiAoICd1bmRlZmluZWQnICE9PSB0eXBlb2YgKCBwX2Jvb2tpbmdzWyAnY2FsZW5kYXJfJyArIHJlc291cmNlX2lkIF1bICdkYXRlcycgXSApIClcclxuXHRcdCl7XHJcblx0XHRcdHJldHVybiAgcF9ib29raW5nc1sgJ2NhbGVuZGFyXycgKyByZXNvdXJjZV9pZCBdWyAnZGF0ZXMnIF07XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGZhbHNlO1x0XHQvLyBJZiBzb21lIHByb3BlcnR5IG5vdCBkZWZpbmVkLCB0aGVuIGZhbHNlO1xyXG5cdH07XHJcblxyXG5cdC8qKlxyXG5cdCAqIFNldCBib29raW5ncyBkYXRlcyBpbiBjYWxlbmRhciBvYmplY3QgICA6OiAgICB7IFwiMjAyMy0wNy0yMVwiOiB74oCmfSwgXCIyMDIzLTA3LTIyXCI6IHvigKZ9LCBcIjIwMjMtMDctMjNcIjoge+KApn0sIOKApiB9XHJcblx0ICpcclxuXHQgKiBpZiBjYWxlbmRhciBvYmplY3QgIG5vdCBkZWZpbmVkLCB0aGVuICBpdCdzIHdpbGwgYmUgZGVmaW5lZCBhbmQgJ2lkJywgJ2RhdGVzJyBzZXRcclxuXHQgKiBpZiBjYWxlbmRhciBleGlzdCwgdGhlbiBzeXN0ZW0gYWRkIGEgIG5ldyBvciBvdmVyd3JpdGUgb25seSBkYXRlcyBmcm9tIGRhdGVzX29iaiBwYXJhbWV0ZXIsXHJcblx0ICogYnV0IG90aGVyIGRhdGVzIG5vdCBmcm9tIHBhcmFtZXRlciBkYXRlc19vYmogd2lsbCBiZSBleGlzdGVkIGFuZCBub3Qgb3ZlcndyaXRlLlxyXG5cdCAqXHJcblx0ICogQHBhcmFtIHtzdHJpbmd8aW50fSByZXNvdXJjZV9pZFx0XHRcdFx0ICAnMidcclxuXHQgKiBAcGFyYW0ge29iamVjdH0gZGF0ZXNfb2JqXHRcdFx0XHRcdCAgeyBcIjIwMjMtMDctMjFcIjoge+KApn0sIFwiMjAyMy0wNy0yMlwiOiB74oCmfSwgXCIyMDIzLTA3LTIzXCI6IHvigKZ9LCDigKYgfVxyXG5cdCAqIEBwYXJhbSB7Ym9vbGVhbn0gaXNfY29tcGxldGVfb3ZlcndyaXRlXHRcdCAgaWYgZmFsc2UsICB0aGVuICBvbmx5IG92ZXJ3cml0ZSBvciBhZGQgIGRhdGVzIGZyb20gXHRkYXRlc19vYmpcclxuXHQgKiBAcmV0dXJucyB7Kn1cclxuXHQgKlxyXG5cdCAqIEV4YW1wbGVzOlxyXG5cdCAqICAgXHRcdFx0X3dwYmMuYm9va2luZ3NfaW5fY2FsZW5kYXJfX3NldF9kYXRlcyggcmVzb3VyY2VfaWQsIHsgXCIyMDIzLTA3LTIxXCI6IHvigKZ9LCBcIjIwMjMtMDctMjJcIjoge+KApn0sIOKApiB9ICApO1x0XHQ8LSAgIG92ZXJ3cml0ZSBBTEwgZGF0ZXNcclxuXHQgKiAgIFx0XHRcdF93cGJjLmJvb2tpbmdzX2luX2NhbGVuZGFyX19zZXRfZGF0ZXMoIHJlc291cmNlX2lkLCB7IFwiMjAyMy0wNy0yMlwiOiB74oCmfSB9LCAgZmFsc2UgICk7XHRcdFx0XHRcdDwtICAgYWRkIG9yIG92ZXJ3cml0ZSBvbmx5ICBcdFwiMjAyMy0wNy0yMlwiOiB7fVxyXG5cdCAqXHJcblx0ICogQ29tbW9uIHVzYWdlIGluIFBIUDpcclxuXHQgKiAgIFx0XHRcdGVjaG8gXCIgIF93cGJjLmJvb2tpbmdzX2luX2NhbGVuZGFyX19zZXRfZGF0ZXMoICBcIiAuIGludHZhbCggJHJlc291cmNlX2lkICkgLiBcIiwgIFwiIC4gd3BfanNvbl9lbmNvZGUoICRhdmFpbGFiaWxpdHlfcGVyX2RheXNfYXJyICkgLiBcIiAgKTsgIFwiO1xyXG5cdCAqL1xyXG5cdG9iai5ib29raW5nc19pbl9jYWxlbmRhcl9fc2V0X2RhdGVzID0gZnVuY3Rpb24oIHJlc291cmNlX2lkLCBkYXRlc19vYmogLCBpc19jb21wbGV0ZV9vdmVyd3JpdGUgPSB0cnVlICl7XHJcblxyXG5cdFx0aWYgKCAhb2JqLmJvb2tpbmdzX2luX2NhbGVuZGFyX19pc19kZWZpbmVkKCByZXNvdXJjZV9pZCApICl7XHJcblx0XHRcdG9iai5ib29raW5nc19pbl9jYWxlbmRhcl9fc2V0KCByZXNvdXJjZV9pZCwgeyAnZGF0ZXMnOiB7fSB9ICk7XHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCAndW5kZWZpbmVkJyA9PT0gdHlwZW9mIChwX2Jvb2tpbmdzWyAnY2FsZW5kYXJfJyArIHJlc291cmNlX2lkIF1bICdkYXRlcycgXSkgKXtcclxuXHRcdFx0cF9ib29raW5nc1sgJ2NhbGVuZGFyXycgKyByZXNvdXJjZV9pZCBdWyAnZGF0ZXMnIF0gPSB7fVxyXG5cdFx0fVxyXG5cclxuXHRcdGlmIChpc19jb21wbGV0ZV9vdmVyd3JpdGUpe1xyXG5cclxuXHRcdFx0Ly8gQ29tcGxldGUgb3ZlcndyaXRlIGFsbCAgYm9va2luZyBkYXRlc1xyXG5cdFx0XHRwX2Jvb2tpbmdzWyAnY2FsZW5kYXJfJyArIHJlc291cmNlX2lkIF1bICdkYXRlcycgXSA9IGRhdGVzX29iajtcclxuXHRcdH0gZWxzZSB7XHJcblxyXG5cdFx0XHQvLyBBZGQgb25seSAgbmV3IG9yIG92ZXJ3cml0ZSBleGlzdCBib29raW5nIGRhdGVzIGZyb20gIHBhcmFtZXRlci4gQm9va2luZyBkYXRlcyBub3QgZnJvbSAgcGFyYW1ldGVyICB3aWxsICBiZSB3aXRob3V0IGNobmFuZ2VzXHJcblx0XHRcdGZvciAoIHZhciBwcm9wX25hbWUgaW4gZGF0ZXNfb2JqICl7XHJcblxyXG5cdFx0XHRcdHBfYm9va2luZ3NbICdjYWxlbmRhcl8nICsgcmVzb3VyY2VfaWQgXVsnZGF0ZXMnXVsgcHJvcF9uYW1lIF0gPSBkYXRlc19vYmpbIHByb3BfbmFtZSBdO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHBfYm9va2luZ3NbICdjYWxlbmRhcl8nICsgcmVzb3VyY2VfaWQgXTtcclxuXHR9O1xyXG5cclxuXHJcblx0LyoqXHJcblx0ICogIEdldCBib29raW5ncyBkYXRhIGZvciBzcGVjaWZpYyBkYXRlIGluIGNhbGVuZGFyICAgOjogICBmYWxzZSB8IHsgZGF5X2F2YWlsYWJpbGl0eTogMSwgLi4uIH1cclxuXHQgKlxyXG5cdCAqIEBwYXJhbSB7c3RyaW5nfGludH0gcmVzb3VyY2VfaWRcdFx0XHQnMSdcclxuXHQgKiBAcGFyYW0ge3N0cmluZ30gc3FsX2NsYXNzX2RheVx0XHRcdCcyMDIzLTA3LTIxJ1xyXG5cdCAqIEByZXR1cm5zIHtvYmplY3R8Ym9vbGVhbn1cdFx0XHRcdGZhbHNlIHwge1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRkYXlfYXZhaWxhYmlsaXR5OiA0XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdG1heF9jYXBhY2l0eTogNFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vICA+PSBCdXNpbmVzcyBMYXJnZVxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQyOiBPYmplY3QgeyBpc19kYXlfdW5hdmFpbGFibGU6IGZhbHNlLCBfZGF5X3N0YXR1czogXCJhdmFpbGFibGVcIiB9XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdDEwOiBPYmplY3QgeyBpc19kYXlfdW5hdmFpbGFibGU6IGZhbHNlLCBfZGF5X3N0YXR1czogXCJhdmFpbGFibGVcIiB9XHRcdC8vICA+PSBCdXNpbmVzcyBMYXJnZSAuLi5cclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0MTE6IE9iamVjdCB7IGlzX2RheV91bmF2YWlsYWJsZTogZmFsc2UsIF9kYXlfc3RhdHVzOiBcImF2YWlsYWJsZVwiIH1cclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0MTI6IE9iamVjdCB7IGlzX2RheV91bmF2YWlsYWJsZTogZmFsc2UsIF9kYXlfc3RhdHVzOiBcImF2YWlsYWJsZVwiIH1cclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdH1cclxuXHQgKi9cclxuXHRvYmouYm9va2luZ3NfaW5fY2FsZW5kYXJfX2dldF9mb3JfZGF0ZSA9IGZ1bmN0aW9uKCByZXNvdXJjZV9pZCwgc3FsX2NsYXNzX2RheSApe1xyXG5cclxuXHRcdGlmIChcclxuXHRcdFx0ICAgKCBvYmouYm9va2luZ3NfaW5fY2FsZW5kYXJfX2lzX2RlZmluZWQoIHJlc291cmNlX2lkICkgKVxyXG5cdFx0XHQmJiAoICd1bmRlZmluZWQnICE9PSB0eXBlb2YgKCBwX2Jvb2tpbmdzWyAnY2FsZW5kYXJfJyArIHJlc291cmNlX2lkIF1bICdkYXRlcycgXSApIClcclxuXHRcdFx0JiYgKCAndW5kZWZpbmVkJyAhPT0gdHlwZW9mICggcF9ib29raW5nc1sgJ2NhbGVuZGFyXycgKyByZXNvdXJjZV9pZCBdWyAnZGF0ZXMnIF1bIHNxbF9jbGFzc19kYXkgXSApIClcclxuXHRcdCl7XHJcblx0XHRcdHJldHVybiAgcF9ib29raW5nc1sgJ2NhbGVuZGFyXycgKyByZXNvdXJjZV9pZCBdWyAnZGF0ZXMnIF1bIHNxbF9jbGFzc19kYXkgXTtcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gZmFsc2U7XHRcdC8vIElmIHNvbWUgcHJvcGVydHkgbm90IGRlZmluZWQsIHRoZW4gZmFsc2U7XHJcblx0fTtcclxuXHJcblxyXG5cdC8vIEFueSAgUEFSQU1TICAgaW4gYm9va2luZ3NcclxuXHJcblx0LyoqXHJcblx0ICogU2V0IHByb3BlcnR5ICB0byAgYm9va2luZ1xyXG5cdCAqIEBwYXJhbSByZXNvdXJjZV9pZFx0XCIxXCJcclxuXHQgKiBAcGFyYW0gcHJvcF9uYW1lXHRcdG5hbWUgb2YgcHJvcGVydHlcclxuXHQgKiBAcGFyYW0gcHJvcF92YWx1ZVx0dmFsdWUgb2YgcHJvcGVydHlcclxuXHQgKiBAcmV0dXJucyB7Kn1cdFx0XHRib29raW5nIG9iamVjdFxyXG5cdCAqL1xyXG5cdG9iai5ib29raW5nX19zZXRfcGFyYW1fdmFsdWUgPSBmdW5jdGlvbiAoIHJlc291cmNlX2lkLCBwcm9wX25hbWUsIHByb3BfdmFsdWUgKSB7XHJcblxyXG5cdFx0aWYgKCAhIG9iai5ib29raW5nc19pbl9jYWxlbmRhcl9faXNfZGVmaW5lZCggcmVzb3VyY2VfaWQgKSApe1xyXG5cdFx0XHRwX2Jvb2tpbmdzWyAnY2FsZW5kYXJfJyArIHJlc291cmNlX2lkIF0gPSB7fTtcclxuXHRcdFx0cF9ib29raW5nc1sgJ2NhbGVuZGFyXycgKyByZXNvdXJjZV9pZCBdWyAnaWQnIF0gPSByZXNvdXJjZV9pZDtcclxuXHRcdH1cclxuXHJcblx0XHRwX2Jvb2tpbmdzWyAnY2FsZW5kYXJfJyArIHJlc291cmNlX2lkIF1bIHByb3BfbmFtZSBdID0gcHJvcF92YWx1ZTtcclxuXHJcblx0XHRyZXR1cm4gcF9ib29raW5nc1sgJ2NhbGVuZGFyXycgKyByZXNvdXJjZV9pZCBdO1xyXG5cdH07XHJcblxyXG5cdC8qKlxyXG5cdCAqICBHZXQgYm9va2luZyBwcm9wZXJ0eSB2YWx1ZSAgIFx0OjogICBtaXhlZCB8IG51bGxcclxuXHQgKlxyXG5cdCAqIEBwYXJhbSB7c3RyaW5nfGludH0gIHJlc291cmNlX2lkXHRcdCcxJ1xyXG5cdCAqIEBwYXJhbSB7c3RyaW5nfSBwcm9wX25hbWVcdFx0XHQnc2VsZWN0aW9uX21vZGUnXHJcblx0ICogQHJldHVybnMgeyp8bnVsbH1cdFx0XHRcdFx0bWl4ZWQgfCBudWxsXHJcblx0ICovXHJcblx0b2JqLmJvb2tpbmdfX2dldF9wYXJhbV92YWx1ZSA9IGZ1bmN0aW9uKCByZXNvdXJjZV9pZCwgcHJvcF9uYW1lICl7XHJcblxyXG5cdFx0aWYgKFxyXG5cdFx0XHQgICAoIG9iai5ib29raW5nc19pbl9jYWxlbmRhcl9faXNfZGVmaW5lZCggcmVzb3VyY2VfaWQgKSApXHJcblx0XHRcdCYmICggJ3VuZGVmaW5lZCcgIT09IHR5cGVvZiAoIHBfYm9va2luZ3NbICdjYWxlbmRhcl8nICsgcmVzb3VyY2VfaWQgXVsgcHJvcF9uYW1lIF0gKSApXHJcblx0XHQpe1xyXG5cdFx0XHRyZXR1cm4gIHBfYm9va2luZ3NbICdjYWxlbmRhcl8nICsgcmVzb3VyY2VfaWQgXVsgcHJvcF9uYW1lIF07XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIG51bGw7XHRcdC8vIElmIHNvbWUgcHJvcGVydHkgbm90IGRlZmluZWQsIHRoZW4gbnVsbDtcclxuXHR9O1xyXG5cclxuXHJcblxyXG5cclxuXHQvKipcclxuXHQgKiBTZXQgYm9va2luZ3MgZm9yIGFsbCAgY2FsZW5kYXJzXHJcblx0ICpcclxuXHQgKiBAcGFyYW0ge29iamVjdH0gY2FsZW5kYXJzX29ialx0XHRPYmplY3QgeyBjYWxlbmRhcl8xOiB7IGlkOiAxLCBkYXRlczogT2JqZWN0IHsgXCIyMDIzLTA3LTIyXCI6IHvigKZ9LCBcIjIwMjMtMDctMjNcIjoge+KApn0sIFwiMjAyMy0wNy0yNFwiOiB74oCmfSwg4oCmIH0gfVxyXG5cdCAqIFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCBjYWxlbmRhcl8zOiB7fSwgLi4uIH1cclxuXHQgKi9cclxuXHRvYmouYm9va2luZ3NfaW5fY2FsZW5kYXJzX19zZXRfYWxsID0gZnVuY3Rpb24gKCBjYWxlbmRhcnNfb2JqICkge1xyXG5cdFx0cF9ib29raW5ncyA9IGNhbGVuZGFyc19vYmo7XHJcblx0fTtcclxuXHJcblx0LyoqXHJcblx0ICogR2V0IGJvb2tpbmdzIGluIGFsbCBjYWxlbmRhcnNcclxuXHQgKlxyXG5cdCAqIEByZXR1cm5zIHtvYmplY3R8e319XHJcblx0ICovXHJcblx0b2JqLmJvb2tpbmdzX2luX2NhbGVuZGFyc19fZ2V0X2FsbCA9IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiBwX2Jvb2tpbmdzO1xyXG5cdH07XHJcblx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHJcblxyXG5cclxuXHJcblx0Ly8gU2Vhc29ucyBcdC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHR2YXIgcF9zZWFzb25zID0gb2JqLnNlYXNvbnNfb2JqID0gb2JqLnNlYXNvbnNfb2JqIHx8IHtcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQvLyBjYWxlbmRhcl8xOiBPYmplY3Qge1xyXG4gXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQvL1x0XHRcdFx0XHRcdCAgIGlkOiAgICAgMVxyXG4gXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQvL1x0XHRcdFx0XHRcdCAsIGRhdGVzOiAgT2JqZWN0IHsgXCIyMDIzLTA3LTIxXCI6IHvigKZ9LCBcIjIwMjMtMDctMjJcIjoge+KApn0sIFwiMjAyMy0wNy0yM1wiOiB74oCmfSwg4oCmXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gfVxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHR9O1xyXG5cclxuXHQvKipcclxuXHQgKiBBZGQgc2Vhc29uIG5hbWVzIGZvciBkYXRlcyBpbiBjYWxlbmRhciBvYmplY3QgICA6OiAgICB7IFwiMjAyMy0wNy0yMVwiOiBbICd3cGJjX3NlYXNvbl9zZXB0ZW1iZXJfMjAyMycsICd3cGJjX3NlYXNvbl9zZXB0ZW1iZXJfMjAyNCcgXSwgXCIyMDIzLTA3LTIyXCI6IFsuLi5dLCAuLi4gfVxyXG5cdCAqXHJcblx0ICpcclxuXHQgKiBAcGFyYW0ge3N0cmluZ3xpbnR9IHJlc291cmNlX2lkXHRcdFx0XHQgICcyJ1xyXG5cdCAqIEBwYXJhbSB7b2JqZWN0fSBkYXRlc19vYmpcdFx0XHRcdFx0ICB7IFwiMjAyMy0wNy0yMVwiOiB74oCmfSwgXCIyMDIzLTA3LTIyXCI6IHvigKZ9LCBcIjIwMjMtMDctMjNcIjoge+KApn0sIOKApiB9XHJcblx0ICogQHBhcmFtIHtib29sZWFufSBpc19jb21wbGV0ZV9vdmVyd3JpdGVcdFx0ICBpZiBmYWxzZSwgIHRoZW4gIG9ubHkgIGFkZCAgZGF0ZXMgZnJvbSBcdGRhdGVzX29ialxyXG5cdCAqIEByZXR1cm5zIHsqfVxyXG5cdCAqXHJcblx0ICogRXhhbXBsZXM6XHJcblx0ICogICBcdFx0XHRfd3BiYy5zZWFzb25zX19zZXQoIHJlc291cmNlX2lkLCB7IFwiMjAyMy0wNy0yMVwiOiBbICd3cGJjX3NlYXNvbl9zZXB0ZW1iZXJfMjAyMycsICd3cGJjX3NlYXNvbl9zZXB0ZW1iZXJfMjAyNCcgXSwgXCIyMDIzLTA3LTIyXCI6IFsuLi5dLCAuLi4gfSAgKTtcclxuXHQgKi9cclxuXHRvYmouc2Vhc29uc19fc2V0ID0gZnVuY3Rpb24oIHJlc291cmNlX2lkLCBkYXRlc19vYmogLCBpc19jb21wbGV0ZV9vdmVyd3JpdGUgPSBmYWxzZSApe1xyXG5cclxuXHRcdGlmICggJ3VuZGVmaW5lZCcgPT09IHR5cGVvZiAocF9zZWFzb25zWyAnY2FsZW5kYXJfJyArIHJlc291cmNlX2lkIF0pICl7XHJcblx0XHRcdHBfc2Vhc29uc1sgJ2NhbGVuZGFyXycgKyByZXNvdXJjZV9pZCBdID0ge307XHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBpc19jb21wbGV0ZV9vdmVyd3JpdGUgKXtcclxuXHJcblx0XHRcdC8vIENvbXBsZXRlIG92ZXJ3cml0ZSBhbGwgIHNlYXNvbiBkYXRlc1xyXG5cdFx0XHRwX3NlYXNvbnNbICdjYWxlbmRhcl8nICsgcmVzb3VyY2VfaWQgXSA9IGRhdGVzX29iajtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0Ly8gQWRkIG9ubHkgIG5ldyBvciBvdmVyd3JpdGUgZXhpc3QgYm9va2luZyBkYXRlcyBmcm9tICBwYXJhbWV0ZXIuIEJvb2tpbmcgZGF0ZXMgbm90IGZyb20gIHBhcmFtZXRlciAgd2lsbCAgYmUgd2l0aG91dCBjaG5hbmdlc1xyXG5cdFx0XHRmb3IgKCB2YXIgcHJvcF9uYW1lIGluIGRhdGVzX29iaiApe1xyXG5cclxuXHRcdFx0XHRpZiAoICd1bmRlZmluZWQnID09PSB0eXBlb2YgKHBfc2Vhc29uc1sgJ2NhbGVuZGFyXycgKyByZXNvdXJjZV9pZCBdWyBwcm9wX25hbWUgXSkgKXtcclxuXHRcdFx0XHRcdHBfc2Vhc29uc1sgJ2NhbGVuZGFyXycgKyByZXNvdXJjZV9pZCBdWyBwcm9wX25hbWUgXSA9IFtdO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0XHRmb3IgKCB2YXIgc2Vhc29uX25hbWVfa2V5IGluIGRhdGVzX29ialsgcHJvcF9uYW1lIF0gKXtcclxuXHRcdFx0XHRcdHBfc2Vhc29uc1sgJ2NhbGVuZGFyXycgKyByZXNvdXJjZV9pZCBdWyBwcm9wX25hbWUgXS5wdXNoKCBkYXRlc19vYmpbIHByb3BfbmFtZSBdWyBzZWFzb25fbmFtZV9rZXkgXSApO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBwX3NlYXNvbnNbICdjYWxlbmRhcl8nICsgcmVzb3VyY2VfaWQgXTtcclxuXHR9O1xyXG5cclxuXHJcblx0LyoqXHJcblx0ICogIEdldCBib29raW5ncyBkYXRhIGZvciBzcGVjaWZpYyBkYXRlIGluIGNhbGVuZGFyICAgOjogICBbXSB8IFsgJ3dwYmNfc2Vhc29uX3NlcHRlbWJlcl8yMDIzJywgJ3dwYmNfc2Vhc29uX3NlcHRlbWJlcl8yMDI0JyBdXHJcblx0ICpcclxuXHQgKiBAcGFyYW0ge3N0cmluZ3xpbnR9IHJlc291cmNlX2lkXHRcdFx0JzEnXHJcblx0ICogQHBhcmFtIHtzdHJpbmd9IHNxbF9jbGFzc19kYXlcdFx0XHQnMjAyMy0wNy0yMSdcclxuXHQgKiBAcmV0dXJucyB7b2JqZWN0fGJvb2xlYW59XHRcdFx0XHRbXSAgfCAgWyAnd3BiY19zZWFzb25fc2VwdGVtYmVyXzIwMjMnLCAnd3BiY19zZWFzb25fc2VwdGVtYmVyXzIwMjQnIF1cclxuXHQgKi9cclxuXHRvYmouc2Vhc29uc19fZ2V0X2Zvcl9kYXRlID0gZnVuY3Rpb24oIHJlc291cmNlX2lkLCBzcWxfY2xhc3NfZGF5ICl7XHJcblxyXG5cdFx0aWYgKFxyXG5cdFx0XHQgICAoICd1bmRlZmluZWQnICE9PSB0eXBlb2YgKCBwX3NlYXNvbnNbICdjYWxlbmRhcl8nICsgcmVzb3VyY2VfaWQgXSApIClcclxuXHRcdFx0JiYgKCAndW5kZWZpbmVkJyAhPT0gdHlwZW9mICggcF9zZWFzb25zWyAnY2FsZW5kYXJfJyArIHJlc291cmNlX2lkIF1bIHNxbF9jbGFzc19kYXkgXSApIClcclxuXHRcdCl7XHJcblx0XHRcdHJldHVybiAgcF9zZWFzb25zWyAnY2FsZW5kYXJfJyArIHJlc291cmNlX2lkIF1bIHNxbF9jbGFzc19kYXkgXTtcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gW107XHRcdC8vIElmIG5vdCBkZWZpbmVkLCB0aGVuIFtdO1xyXG5cdH07XHJcblxyXG5cclxuXHQvLyBPdGhlciBwYXJhbWV0ZXJzIFx0XHRcdC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdHZhciBwX290aGVyID0gb2JqLm90aGVyX29iaiA9IG9iai5vdGhlcl9vYmogfHwgeyB9O1xyXG5cclxuXHRvYmouc2V0X290aGVyX3BhcmFtID0gZnVuY3Rpb24gKCBwYXJhbV9rZXksIHBhcmFtX3ZhbCApIHtcclxuXHRcdHBfb3RoZXJbIHBhcmFtX2tleSBdID0gcGFyYW1fdmFsO1xyXG5cdH07XHJcblxyXG5cdG9iai5nZXRfb3RoZXJfcGFyYW0gPSBmdW5jdGlvbiAoIHBhcmFtX2tleSApIHtcclxuXHRcdHJldHVybiBwX290aGVyWyBwYXJhbV9rZXkgXTtcclxuXHR9O1xyXG5cclxuXHQvKipcclxuXHQgKiBHZXQgYWxsIG90aGVyIHBhcmFtc1xyXG5cdCAqXHJcblx0ICogQHJldHVybnMge29iamVjdHx7fX1cclxuXHQgKi9cclxuXHRvYmouZ2V0X290aGVyX3BhcmFtX19hbGwgPSBmdW5jdGlvbiAoKSB7XHJcblx0XHRyZXR1cm4gcF9vdGhlcjtcclxuXHR9O1xyXG5cclxuXHQvLyBNZXNzYWdlcyBcdFx0XHQgICAgICAgIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdHZhciBwX21lc3NhZ2VzID0gb2JqLm1lc3NhZ2VzX29iaiA9IG9iai5tZXNzYWdlc19vYmogfHwgeyB9O1xyXG5cclxuXHRvYmouc2V0X21lc3NhZ2UgPSBmdW5jdGlvbiAoIHBhcmFtX2tleSwgcGFyYW1fdmFsICkge1xyXG5cdFx0cF9tZXNzYWdlc1sgcGFyYW1fa2V5IF0gPSBwYXJhbV92YWw7XHJcblx0fTtcclxuXHJcblx0b2JqLmdldF9tZXNzYWdlID0gZnVuY3Rpb24gKCBwYXJhbV9rZXkgKSB7XHJcblx0XHRyZXR1cm4gcF9tZXNzYWdlc1sgcGFyYW1fa2V5IF07XHJcblx0fTtcclxuXHJcblx0LyoqXHJcblx0ICogR2V0IGFsbCBvdGhlciBwYXJhbXNcclxuXHQgKlxyXG5cdCAqIEByZXR1cm5zIHtvYmplY3R8e319XHJcblx0ICovXHJcblx0b2JqLmdldF9tZXNzYWdlc19fYWxsID0gZnVuY3Rpb24gKCkge1xyXG5cdFx0cmV0dXJuIHBfbWVzc2FnZXM7XHJcblx0fTtcclxuXHJcblx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHJcblx0cmV0dXJuIG9iajtcclxuXHJcbn0oIF93cGJjIHx8IHt9LCBqUXVlcnkgKSk7XHJcbiIsIndpbmRvdy5fX1dQQkNfREVWID0gdHJ1ZTtcclxuXHJcbi8qKlxyXG4gKiBFeHRlbmQgX3dwYmMgd2l0aCAgbmV3IG1ldGhvZHNcclxuICpcclxuICogQHR5cGUgeyp8e319XHJcbiAqIEBwcml2YXRlXHJcbiAqL1xyXG5fd3BiYyA9IChmdW5jdGlvbiAob2JqLCAkKSB7XHJcblxyXG5cdC8qKlxyXG5cdCAqIERldiBsb2dnZXIgKG5vLW9wIHVubGVzcyB3aW5kb3cuX19XUEJDX0RFViA9IHRydWUpXHJcblx0ICpcclxuXHQgKiBAdHlwZSB7Knx7d2FybjogKGZ1bmN0aW9uKCosICosICopOiB2b2lkKSwgZXJyb3I6IChmdW5jdGlvbigqLCAqLCAqKTogdm9pZCksIG9uY2U6IG9iai5kZXYub25jZSwgdHJ5OiAoKGZ1bmN0aW9uKCosICosICopOiAoKnx1bmRlZmluZWQpKXwqKX19XHJcblx0ICovXHJcblx0b2JqLmRldiA9IG9iai5kZXYgfHwgKCgpID0+IHtcclxuXHRcdGNvbnN0IHNlZW4gICAgPSBuZXcgU2V0KCk7XHJcblx0XHRjb25zdCBlbmFibGVkID0gKCkgPT4gISF3aW5kb3cuX19XUEJDX0RFVjtcclxuXHJcblx0XHRmdW5jdGlvbiBvdXQobGV2ZWwsIGNvZGUsIG1zZywgZXh0cmEpIHtcclxuXHRcdFx0aWYgKCAhZW5hYmxlZCgpICkgcmV0dXJuO1xyXG5cdFx0XHR0cnkge1xyXG5cdFx0XHRcdChjb25zb2xlW2xldmVsXSB8fCBjb25zb2xlLndhcm4pKCBgW1dQQkNdWyR7Y29kZX1dICR7bXNnfWAsIGV4dHJhID8/ICcnICk7XHJcblx0XHRcdH0gY2F0Y2gge1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHtcclxuXHRcdFx0bG9nICA6IChjb2RlLCBtc2csIGV4dHJhKSA9PiBvdXQoJ2xvZycsICAgY29kZSwgbXNnLCBleHRyYSksXHJcblx0XHRcdGRlYnVnOiAoY29kZSwgbXNnLCBleHRyYSkgPT4gb3V0KCdkZWJ1ZycsIGNvZGUsIG1zZywgZXh0cmEpLFxyXG5cdFx0XHR3YXJuIDogKGNvZGUsIG1zZywgZXh0cmEpID0+IG91dCggJ3dhcm4nLCBjb2RlLCBtc2csIGV4dHJhICksXHJcblx0XHRcdGVycm9yOiAoY29kZSwgZXJyT3JNc2csIGV4dHJhKSA9PlxyXG5cdFx0XHRcdG91dCggJ2Vycm9yJywgY29kZSxcclxuXHRcdFx0XHRcdGVyck9yTXNnIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJPck1zZy5tZXNzYWdlIDogU3RyaW5nKCBlcnJPck1zZyApLFxyXG5cdFx0XHRcdFx0ZXJyT3JNc2cgaW5zdGFuY2VvZiBFcnJvciA/IGVyck9yTXNnIDogZXh0cmEgKSxcclxuXHRcdFx0b25jZSA6IChjb2RlLCBtc2csIGV4dHJhKSA9PiB7XHJcblx0XHRcdFx0aWYgKCAhZW5hYmxlZCgpICkgcmV0dXJuO1xyXG5cdFx0XHRcdGNvbnN0IGtleSA9IGAke2NvZGV9fCR7bXNnfWA7XHJcblx0XHRcdFx0aWYgKCBzZWVuLmhhcygga2V5ICkgKSByZXR1cm47XHJcblx0XHRcdFx0c2Vlbi5hZGQoIGtleSApO1xyXG5cdFx0XHRcdG91dCggJ2Vycm9yJywgY29kZSwgbXNnLCBleHRyYSApO1xyXG5cdFx0XHR9LFxyXG5cdFx0XHR0cnkgIDogKGNvZGUsIGZuLCBleHRyYSkgPT4ge1xyXG5cdFx0XHRcdHRyeSB7XHJcblx0XHRcdFx0XHRyZXR1cm4gZm4oKTtcclxuXHRcdFx0XHR9IGNhdGNoICggZSApIHtcclxuXHRcdFx0XHRcdG91dCggJ2Vycm9yJywgY29kZSwgZSwgZXh0cmEgKTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHRcdH07XHJcblx0fSkoKTtcclxuXHJcblx0Ly8gT3B0aW9uYWw6IGdsb2JhbCB0cmFwcyBpbiBkZXYuXHJcblx0aWYgKCB3aW5kb3cuX19XUEJDX0RFViApIHtcclxuXHRcdHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCAnZXJyb3InLCAoZSkgPT4ge1xyXG5cdFx0XHR0cnkgeyBfd3BiYz8uZGV2Py5lcnJvciggJ0dMT0JBTC1FUlJPUicsIGU/LmVycm9yIHx8IGU/Lm1lc3NhZ2UsIGUgKTsgfSBjYXRjaCAoIF8gKSB7fVxyXG5cdFx0fSApO1xyXG5cdFx0d2luZG93LmFkZEV2ZW50TGlzdGVuZXIoICd1bmhhbmRsZWRyZWplY3Rpb24nLCAoZSkgPT4ge1xyXG5cdFx0XHR0cnkgeyBfd3BiYz8uZGV2Py5lcnJvciggJ0dMT0JBTC1SRUpFQ1RJT04nLCBlPy5yZWFzb24gKTsgfSBjYXRjaCAoIF8gKSB7fVxyXG5cdFx0fSApO1xyXG5cdH1cclxuXHJcblx0cmV0dXJuIG9iajtcclxuXHR9KCBfd3BiYyB8fCB7fSwgalF1ZXJ5ICkpO1xyXG4iLCIvKipcclxuICogRXh0ZW5kIF93cGJjIHdpdGggIG5ldyBtZXRob2RzICAgICAgICAvLyBGaXhJbjogOS44LjYuMi5cclxuICpcclxuICogQHR5cGUgeyp8e319XHJcbiAqIEBwcml2YXRlXHJcbiAqL1xyXG4gX3dwYmMgPSAoZnVuY3Rpb24gKCBvYmosICQpIHtcclxuXHJcblx0Ly8gTG9hZCBCYWxhbmNlciBcdC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblxyXG5cdHZhciBwX2JhbGFuY2VyID0gb2JqLmJhbGFuY2VyX29iaiA9IG9iai5iYWxhbmNlcl9vYmogfHwge1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCdtYXhfdGhyZWFkcyc6IDIsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J2luX3Byb2Nlc3MnIDogW10sXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J3dhaXQnICAgICAgIDogW11cclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0fTtcclxuXHJcblx0IC8qKlxyXG5cdCAgKiBTZXQgIG1heCBwYXJhbGxlbCByZXF1ZXN0ICB0byAgbG9hZFxyXG5cdCAgKlxyXG5cdCAgKiBAcGFyYW0gbWF4X3RocmVhZHNcclxuXHQgICovXHJcblx0b2JqLmJhbGFuY2VyX19zZXRfbWF4X3RocmVhZHMgPSBmdW5jdGlvbiAoIG1heF90aHJlYWRzICl7XHJcblxyXG5cdFx0cF9iYWxhbmNlclsgJ21heF90aHJlYWRzJyBdID0gbWF4X3RocmVhZHM7XHJcblx0fTtcclxuXHJcblx0LyoqXHJcblx0ICogIENoZWNrIGlmIGJhbGFuY2VyIGZvciBzcGVjaWZpYyBib29raW5nIHJlc291cmNlIGRlZmluZWQgICA6OiAgIHRydWUgfCBmYWxzZVxyXG5cdCAqXHJcblx0ICogQHBhcmFtIHtzdHJpbmd8aW50fSByZXNvdXJjZV9pZFxyXG5cdCAqIEByZXR1cm5zIHtib29sZWFufVxyXG5cdCAqL1xyXG5cdG9iai5iYWxhbmNlcl9faXNfZGVmaW5lZCA9IGZ1bmN0aW9uICggcmVzb3VyY2VfaWQgKSB7XHJcblxyXG5cdFx0cmV0dXJuICgndW5kZWZpbmVkJyAhPT0gdHlwZW9mKCBwX2JhbGFuY2VyWyAnYmFsYW5jZXJfJyArIHJlc291cmNlX2lkIF0gKSApO1xyXG5cdH07XHJcblxyXG5cclxuXHQvKipcclxuXHQgKiAgQ3JlYXRlIGJhbGFuY2VyIGluaXRpYWxpemluZ1xyXG5cdCAqXHJcblx0ICogQHBhcmFtIHtzdHJpbmd8aW50fSByZXNvdXJjZV9pZFxyXG5cdCAqL1xyXG5cdG9iai5iYWxhbmNlcl9faW5pdCA9IGZ1bmN0aW9uICggcmVzb3VyY2VfaWQsIGZ1bmN0aW9uX25hbWUgLCBwYXJhbXMgPXt9KSB7XHJcblxyXG5cdFx0dmFyIGJhbGFuY2Vfb2JqID0ge307XHJcblx0XHRiYWxhbmNlX29ialsgJ3Jlc291cmNlX2lkJyBdICAgPSByZXNvdXJjZV9pZDtcclxuXHRcdGJhbGFuY2Vfb2JqWyAncHJpb3JpdHknIF0gICAgICA9IDE7XHJcblx0XHRiYWxhbmNlX29ialsgJ2Z1bmN0aW9uX25hbWUnIF0gPSBmdW5jdGlvbl9uYW1lO1xyXG5cdFx0YmFsYW5jZV9vYmpbICdwYXJhbXMnIF0gICAgICAgID0gd3BiY19jbG9uZV9vYmooIHBhcmFtcyApO1xyXG5cclxuXHJcblx0XHRpZiAoIG9iai5iYWxhbmNlcl9faXNfYWxyZWFkeV9ydW4oIHJlc291cmNlX2lkLCBmdW5jdGlvbl9uYW1lICkgKXtcclxuXHRcdFx0cmV0dXJuICdydW4nO1xyXG5cdFx0fVxyXG5cdFx0aWYgKCBvYmouYmFsYW5jZXJfX2lzX2FscmVhZHlfd2FpdCggcmVzb3VyY2VfaWQsIGZ1bmN0aW9uX25hbWUgKSApe1xyXG5cdFx0XHRyZXR1cm4gJ3dhaXQnO1xyXG5cdFx0fVxyXG5cclxuXHJcblx0XHRpZiAoIG9iai5iYWxhbmNlcl9fY2FuX2lfcnVuKCkgKXtcclxuXHRcdFx0b2JqLmJhbGFuY2VyX19hZGRfdG9fX3J1biggYmFsYW5jZV9vYmogKTtcclxuXHRcdFx0cmV0dXJuICdydW4nO1xyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0b2JqLmJhbGFuY2VyX19hZGRfdG9fX3dhaXQoIGJhbGFuY2Vfb2JqICk7XHJcblx0XHRcdHJldHVybiAnd2FpdCc7XHJcblx0XHR9XHJcblx0fTtcclxuXHJcblx0IC8qKlxyXG5cdCAgKiBDYW4gSSBSdW4gP1xyXG5cdCAgKiBAcmV0dXJucyB7Ym9vbGVhbn1cclxuXHQgICovXHJcblx0b2JqLmJhbGFuY2VyX19jYW5faV9ydW4gPSBmdW5jdGlvbiAoKXtcclxuXHRcdHJldHVybiAoIHBfYmFsYW5jZXJbICdpbl9wcm9jZXNzJyBdLmxlbmd0aCA8IHBfYmFsYW5jZXJbICdtYXhfdGhyZWFkcycgXSApO1xyXG5cdH1cclxuXHJcblx0XHQgLyoqXHJcblx0XHQgICogQWRkIHRvIFdBSVRcclxuXHRcdCAgKiBAcGFyYW0gYmFsYW5jZV9vYmpcclxuXHRcdCAgKi9cclxuXHRcdG9iai5iYWxhbmNlcl9fYWRkX3RvX193YWl0ID0gZnVuY3Rpb24gKCBiYWxhbmNlX29iaiApIHtcclxuXHRcdFx0cF9iYWxhbmNlclsnd2FpdCddLnB1c2goIGJhbGFuY2Vfb2JqICk7XHJcblx0XHR9XHJcblxyXG5cdFx0IC8qKlxyXG5cdFx0ICAqIFJlbW92ZSBmcm9tIFdhaXRcclxuXHRcdCAgKlxyXG5cdFx0ICAqIEBwYXJhbSByZXNvdXJjZV9pZFxyXG5cdFx0ICAqIEBwYXJhbSBmdW5jdGlvbl9uYW1lXHJcblx0XHQgICogQHJldHVybnMgeyp8Ym9vbGVhbn1cclxuXHRcdCAgKi9cclxuXHRcdG9iai5iYWxhbmNlcl9fcmVtb3ZlX2Zyb21fX3dhaXRfbGlzdCA9IGZ1bmN0aW9uICggcmVzb3VyY2VfaWQsIGZ1bmN0aW9uX25hbWUgKXtcclxuXHJcblx0XHRcdHZhciByZW1vdmVkX2VsID0gZmFsc2U7XHJcblxyXG5cdFx0XHRpZiAoIHBfYmFsYW5jZXJbICd3YWl0JyBdLmxlbmd0aCApe1x0XHRcdFx0XHQvLyBGaXhJbjogOS44LjEwLjEuXHJcblx0XHRcdFx0Zm9yICggdmFyIGkgaW4gcF9iYWxhbmNlclsgJ3dhaXQnIF0gKXtcclxuXHRcdFx0XHRcdGlmIChcclxuXHRcdFx0XHRcdFx0KHJlc291cmNlX2lkID09PSBwX2JhbGFuY2VyWyAnd2FpdCcgXVsgaSBdWyAncmVzb3VyY2VfaWQnIF0pXHJcblx0XHRcdFx0XHRcdCYmIChmdW5jdGlvbl9uYW1lID09PSBwX2JhbGFuY2VyWyAnd2FpdCcgXVsgaSBdWyAnZnVuY3Rpb25fbmFtZScgXSlcclxuXHRcdFx0XHRcdCl7XHJcblx0XHRcdFx0XHRcdHJlbW92ZWRfZWwgPSBwX2JhbGFuY2VyWyAnd2FpdCcgXS5zcGxpY2UoIGksIDEgKTtcclxuXHRcdFx0XHRcdFx0cmVtb3ZlZF9lbCA9IHJlbW92ZWRfZWwucG9wKCk7XHJcblx0XHRcdFx0XHRcdHBfYmFsYW5jZXJbICd3YWl0JyBdID0gcF9iYWxhbmNlclsgJ3dhaXQnIF0uZmlsdGVyKCBmdW5jdGlvbiAoIHYgKXtcclxuXHRcdFx0XHRcdFx0XHRyZXR1cm4gdjtcclxuXHRcdFx0XHRcdFx0fSApO1x0XHRcdFx0XHQvLyBSZWluZGV4IGFycmF5XHJcblx0XHRcdFx0XHRcdHJldHVybiByZW1vdmVkX2VsO1xyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdH1cclxuXHRcdFx0fVxyXG5cdFx0XHRyZXR1cm4gcmVtb3ZlZF9lbDtcclxuXHRcdH1cclxuXHJcblx0XHQvKipcclxuXHRcdCogSXMgYWxyZWFkeSBXQUlUXHJcblx0XHQqXHJcblx0XHQqIEBwYXJhbSByZXNvdXJjZV9pZFxyXG5cdFx0KiBAcGFyYW0gZnVuY3Rpb25fbmFtZVxyXG5cdFx0KiBAcmV0dXJucyB7Ym9vbGVhbn1cclxuXHRcdCovXHJcblx0XHRvYmouYmFsYW5jZXJfX2lzX2FscmVhZHlfd2FpdCA9IGZ1bmN0aW9uICggcmVzb3VyY2VfaWQsIGZ1bmN0aW9uX25hbWUgKXtcclxuXHJcblx0XHRcdGlmICggcF9iYWxhbmNlclsgJ3dhaXQnIF0ubGVuZ3RoICl7XHRcdFx0XHQvLyBGaXhJbjogOS44LjEwLjEuXHJcblx0XHRcdFx0Zm9yICggdmFyIGkgaW4gcF9iYWxhbmNlclsgJ3dhaXQnIF0gKXtcclxuXHRcdFx0XHRcdGlmIChcclxuXHRcdFx0XHRcdFx0KHJlc291cmNlX2lkID09PSBwX2JhbGFuY2VyWyAnd2FpdCcgXVsgaSBdWyAncmVzb3VyY2VfaWQnIF0pXHJcblx0XHRcdFx0XHRcdCYmIChmdW5jdGlvbl9uYW1lID09PSBwX2JhbGFuY2VyWyAnd2FpdCcgXVsgaSBdWyAnZnVuY3Rpb25fbmFtZScgXSlcclxuXHRcdFx0XHRcdCl7XHJcblx0XHRcdFx0XHRcdHJldHVybiB0cnVlO1xyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdH1cclxuXHRcdFx0fVxyXG5cdFx0XHRyZXR1cm4gZmFsc2U7XHJcblx0XHR9XHJcblxyXG5cclxuXHRcdCAvKipcclxuXHRcdCAgKiBBZGQgdG8gUlVOXHJcblx0XHQgICogQHBhcmFtIGJhbGFuY2Vfb2JqXHJcblx0XHQgICovXHJcblx0XHRvYmouYmFsYW5jZXJfX2FkZF90b19fcnVuID0gZnVuY3Rpb24gKCBiYWxhbmNlX29iaiApIHtcclxuXHRcdFx0cF9iYWxhbmNlclsnaW5fcHJvY2VzcyddLnB1c2goIGJhbGFuY2Vfb2JqICk7XHJcblx0XHR9XHJcblxyXG5cdFx0LyoqXHJcblx0XHQqIFJlbW92ZSBmcm9tIFJVTiBsaXN0XHJcblx0XHQqXHJcblx0XHQqIEBwYXJhbSByZXNvdXJjZV9pZFxyXG5cdFx0KiBAcGFyYW0gZnVuY3Rpb25fbmFtZVxyXG5cdFx0KiBAcmV0dXJucyB7Knxib29sZWFufVxyXG5cdFx0Ki9cclxuXHRcdG9iai5iYWxhbmNlcl9fcmVtb3ZlX2Zyb21fX3J1bl9saXN0ID0gZnVuY3Rpb24gKCByZXNvdXJjZV9pZCwgZnVuY3Rpb25fbmFtZSApe1xyXG5cclxuXHRcdFx0IHZhciByZW1vdmVkX2VsID0gZmFsc2U7XHJcblxyXG5cdFx0XHQgaWYgKCBwX2JhbGFuY2VyWyAnaW5fcHJvY2VzcycgXS5sZW5ndGggKXtcdFx0XHRcdC8vIEZpeEluOiA5LjguMTAuMS5cclxuXHRcdFx0XHQgZm9yICggdmFyIGkgaW4gcF9iYWxhbmNlclsgJ2luX3Byb2Nlc3MnIF0gKXtcclxuXHRcdFx0XHRcdCBpZiAoXHJcblx0XHRcdFx0XHRcdCAocmVzb3VyY2VfaWQgPT09IHBfYmFsYW5jZXJbICdpbl9wcm9jZXNzJyBdWyBpIF1bICdyZXNvdXJjZV9pZCcgXSlcclxuXHRcdFx0XHRcdFx0ICYmIChmdW5jdGlvbl9uYW1lID09PSBwX2JhbGFuY2VyWyAnaW5fcHJvY2VzcycgXVsgaSBdWyAnZnVuY3Rpb25fbmFtZScgXSlcclxuXHRcdFx0XHRcdCApe1xyXG5cdFx0XHRcdFx0XHQgcmVtb3ZlZF9lbCA9IHBfYmFsYW5jZXJbICdpbl9wcm9jZXNzJyBdLnNwbGljZSggaSwgMSApO1xyXG5cdFx0XHRcdFx0XHQgcmVtb3ZlZF9lbCA9IHJlbW92ZWRfZWwucG9wKCk7XHJcblx0XHRcdFx0XHRcdCBwX2JhbGFuY2VyWyAnaW5fcHJvY2VzcycgXSA9IHBfYmFsYW5jZXJbICdpbl9wcm9jZXNzJyBdLmZpbHRlciggZnVuY3Rpb24gKCB2ICl7XHJcblx0XHRcdFx0XHRcdFx0IHJldHVybiB2O1xyXG5cdFx0XHRcdFx0XHQgfSApO1x0XHQvLyBSZWluZGV4IGFycmF5XHJcblx0XHRcdFx0XHRcdCByZXR1cm4gcmVtb3ZlZF9lbDtcclxuXHRcdFx0XHRcdCB9XHJcblx0XHRcdFx0IH1cclxuXHRcdFx0IH1cclxuXHRcdFx0IHJldHVybiByZW1vdmVkX2VsO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8qKlxyXG5cdFx0KiBJcyBhbHJlYWR5IFJVTlxyXG5cdFx0KlxyXG5cdFx0KiBAcGFyYW0gcmVzb3VyY2VfaWRcclxuXHRcdCogQHBhcmFtIGZ1bmN0aW9uX25hbWVcclxuXHRcdCogQHJldHVybnMge2Jvb2xlYW59XHJcblx0XHQqL1xyXG5cdFx0b2JqLmJhbGFuY2VyX19pc19hbHJlYWR5X3J1biA9IGZ1bmN0aW9uICggcmVzb3VyY2VfaWQsIGZ1bmN0aW9uX25hbWUgKXtcclxuXHJcblx0XHRcdGlmICggcF9iYWxhbmNlclsgJ2luX3Byb2Nlc3MnIF0ubGVuZ3RoICl7XHRcdFx0XHRcdC8vIEZpeEluOiA5LjguMTAuMS5cclxuXHRcdFx0XHRmb3IgKCB2YXIgaSBpbiBwX2JhbGFuY2VyWyAnaW5fcHJvY2VzcycgXSApe1xyXG5cdFx0XHRcdFx0aWYgKFxyXG5cdFx0XHRcdFx0XHQocmVzb3VyY2VfaWQgPT09IHBfYmFsYW5jZXJbICdpbl9wcm9jZXNzJyBdWyBpIF1bICdyZXNvdXJjZV9pZCcgXSlcclxuXHRcdFx0XHRcdFx0JiYgKGZ1bmN0aW9uX25hbWUgPT09IHBfYmFsYW5jZXJbICdpbl9wcm9jZXNzJyBdWyBpIF1bICdmdW5jdGlvbl9uYW1lJyBdKVxyXG5cdFx0XHRcdFx0KXtcclxuXHRcdFx0XHRcdFx0cmV0dXJuIHRydWU7XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblx0XHRcdHJldHVybiBmYWxzZTtcclxuXHRcdH1cclxuXHJcblxyXG5cclxuXHRvYmouYmFsYW5jZXJfX3J1bl9uZXh0ID0gZnVuY3Rpb24gKCl7XHJcblxyXG5cdFx0Ly8gR2V0IDFzdCBmcm9tICBXYWl0IGxpc3RcclxuXHRcdHZhciByZW1vdmVkX2VsID0gZmFsc2U7XHJcblx0XHRpZiAoIHBfYmFsYW5jZXJbICd3YWl0JyBdLmxlbmd0aCApe1x0XHRcdFx0XHQvLyBGaXhJbjogOS44LjEwLjEuXHJcblx0XHRcdGZvciAoIHZhciBpIGluIHBfYmFsYW5jZXJbICd3YWl0JyBdICl7XHJcblx0XHRcdFx0cmVtb3ZlZF9lbCA9IG9iai5iYWxhbmNlcl9fcmVtb3ZlX2Zyb21fX3dhaXRfbGlzdCggcF9iYWxhbmNlclsgJ3dhaXQnIF1bIGkgXVsgJ3Jlc291cmNlX2lkJyBdLCBwX2JhbGFuY2VyWyAnd2FpdCcgXVsgaSBdWyAnZnVuY3Rpb25fbmFtZScgXSApO1xyXG5cdFx0XHRcdGJyZWFrO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBmYWxzZSAhPT0gcmVtb3ZlZF9lbCApe1xyXG5cclxuXHRcdFx0Ly8gUnVuXHJcblx0XHRcdG9iai5iYWxhbmNlcl9fcnVuKCByZW1vdmVkX2VsICk7XHJcblx0XHR9XHJcblx0fVxyXG5cclxuXHQgLyoqXHJcblx0ICAqIFJ1blxyXG5cdCAgKiBAcGFyYW0gYmFsYW5jZV9vYmpcclxuXHQgICovXHJcblx0b2JqLmJhbGFuY2VyX19ydW4gPSBmdW5jdGlvbiAoIGJhbGFuY2Vfb2JqICl7XHJcblxyXG5cdFx0c3dpdGNoICggYmFsYW5jZV9vYmpbICdmdW5jdGlvbl9uYW1lJyBdICl7XHJcblxyXG5cdFx0XHRjYXNlICd3cGJjX2NhbGVuZGFyX19sb2FkX2RhdGFfX2FqeCc6XHJcblxyXG5cdFx0XHRcdC8vIEFkZCB0byBydW4gbGlzdFxyXG5cdFx0XHRcdG9iai5iYWxhbmNlcl9fYWRkX3RvX19ydW4oIGJhbGFuY2Vfb2JqICk7XHJcblxyXG5cdFx0XHRcdHdwYmNfY2FsZW5kYXJfX2xvYWRfZGF0YV9fYWp4KCBiYWxhbmNlX29ialsgJ3BhcmFtcycgXSApXHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRkZWZhdWx0OlxyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0cmV0dXJuIG9iajtcclxuXHJcbn0oIF93cGJjIHx8IHt9LCBqUXVlcnkgKSk7XHJcblxyXG5cclxuIFx0LyoqXHJcbiBcdCAqIC0tIEhlbHAgZnVuY3Rpb25zIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHQgKi9cclxuXHJcblx0ZnVuY3Rpb24gd3BiY19iYWxhbmNlcl9faXNfd2FpdCggcGFyYW1zLCBmdW5jdGlvbl9uYW1lICl7XHJcbi8vY29uc29sZS5sb2coJzo6d3BiY19iYWxhbmNlcl9faXNfd2FpdCcscGFyYW1zICwgZnVuY3Rpb25fbmFtZSApO1xyXG5cdFx0aWYgKCAndW5kZWZpbmVkJyAhPT0gdHlwZW9mIChwYXJhbXNbICdyZXNvdXJjZV9pZCcgXSkgKXtcclxuXHJcblx0XHRcdHZhciBiYWxhbmNlcl9zdGF0dXMgPSBfd3BiYy5iYWxhbmNlcl9faW5pdCggcGFyYW1zWyAncmVzb3VyY2VfaWQnIF0sIGZ1bmN0aW9uX25hbWUsIHBhcmFtcyApO1xyXG5cclxuXHRcdFx0cmV0dXJuICggJ3dhaXQnID09PSBiYWxhbmNlcl9zdGF0dXMgKTtcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gZmFsc2U7XHJcblx0fVxyXG5cclxuXHJcblx0ZnVuY3Rpb24gd3BiY19iYWxhbmNlcl9fY29tcGxldGVkKCByZXNvdXJjZV9pZCAsIGZ1bmN0aW9uX25hbWUgKXtcclxuLy9jb25zb2xlLmxvZygnOjp3cGJjX2JhbGFuY2VyX19jb21wbGV0ZWQnLHJlc291cmNlX2lkICwgZnVuY3Rpb25fbmFtZSApO1xyXG5cdFx0X3dwYmMuYmFsYW5jZXJfX3JlbW92ZV9mcm9tX19ydW5fbGlzdCggcmVzb3VyY2VfaWQsIGZ1bmN0aW9uX25hbWUgKTtcclxuXHRcdF93cGJjLmJhbGFuY2VyX19ydW5fbmV4dCgpO1xyXG5cdH0iLCIvKipcclxuICogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcbiAqXHRpbmNsdWRlcy9fX2pzL2NhbC93cGJjX2NhbC5qc1xyXG4gKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuICovXHJcblxyXG4vKipcclxuICogT3JkZXIgb3IgY2hpbGQgYm9va2luZyByZXNvdXJjZXMgc2F2ZWQgaGVyZTogIFx0X3dwYmMuYm9va2luZ19fZ2V0X3BhcmFtX3ZhbHVlKCByZXNvdXJjZV9pZCxcclxuICogJ3Jlc291cmNlc19pZF9hcnJfX2luX2RhdGVzJyApXHRcdFsyLDEwLDEyLDExXVxyXG4gKi9cclxuXHJcbi8qKlxyXG4gKiBIb3cgdG8gY2hlY2sgIGJvb2tlZCB0aW1lcyBvbiAgc3BlY2lmaWMgZGF0ZTogP1xyXG4gKlxyXG5cdFx0XHRfd3BiYy5ib29raW5nc19pbl9jYWxlbmRhcl9fZ2V0X2Zvcl9kYXRlKDIsJzIwMjMtMDgtMjEnKTtcclxuXHJcblx0XHRcdGNvbnNvbGUubG9nKFxyXG5cdFx0XHRcdFx0XHRfd3BiYy5ib29raW5nc19pbl9jYWxlbmRhcl9fZ2V0X2Zvcl9kYXRlKDIsJzIwMjMtMDgtMjEnKVsyXS5ib29rZWRfdGltZV9zbG90cy5tZXJnZWRfc2Vjb25kcyxcclxuXHRcdFx0XHRcdFx0X3dwYmMuYm9va2luZ3NfaW5fY2FsZW5kYXJfX2dldF9mb3JfZGF0ZSgyLCcyMDIzLTA4LTIxJylbMTBdLmJvb2tlZF90aW1lX3Nsb3RzLm1lcmdlZF9zZWNvbmRzLFxyXG5cdFx0XHRcdFx0XHRfd3BiYy5ib29raW5nc19pbl9jYWxlbmRhcl9fZ2V0X2Zvcl9kYXRlKDIsJzIwMjMtMDgtMjEnKVsxMV0uYm9va2VkX3RpbWVfc2xvdHMubWVyZ2VkX3NlY29uZHMsXHJcblx0XHRcdFx0XHRcdF93cGJjLmJvb2tpbmdzX2luX2NhbGVuZGFyX19nZXRfZm9yX2RhdGUoMiwnMjAyMy0wOC0yMScpWzEyXS5ib29rZWRfdGltZV9zbG90cy5tZXJnZWRfc2Vjb25kc1xyXG5cdFx0XHRcdFx0KTtcclxuICogIE9SXHJcblx0XHRcdGNvbnNvbGUubG9nKFxyXG5cdFx0XHRcdFx0XHRfd3BiYy5ib29raW5nc19pbl9jYWxlbmRhcl9fZ2V0X2Zvcl9kYXRlKDIsJzIwMjMtMDgtMjEnKVsyXS5ib29rZWRfdGltZV9zbG90cy5tZXJnZWRfcmVhZGFibGUsXHJcblx0XHRcdFx0XHRcdF93cGJjLmJvb2tpbmdzX2luX2NhbGVuZGFyX19nZXRfZm9yX2RhdGUoMiwnMjAyMy0wOC0yMScpWzEwXS5ib29rZWRfdGltZV9zbG90cy5tZXJnZWRfcmVhZGFibGUsXHJcblx0XHRcdFx0XHRcdF93cGJjLmJvb2tpbmdzX2luX2NhbGVuZGFyX19nZXRfZm9yX2RhdGUoMiwnMjAyMy0wOC0yMScpWzExXS5ib29rZWRfdGltZV9zbG90cy5tZXJnZWRfcmVhZGFibGUsXHJcblx0XHRcdFx0XHRcdF93cGJjLmJvb2tpbmdzX2luX2NhbGVuZGFyX19nZXRfZm9yX2RhdGUoMiwnMjAyMy0wOC0yMScpWzEyXS5ib29rZWRfdGltZV9zbG90cy5tZXJnZWRfcmVhZGFibGVcclxuXHRcdFx0XHRcdCk7XHJcbiAqXHJcbiAqL1xyXG5cclxuLyoqXHJcbiAqIERheXMgc2VsZWN0aW9uOlxyXG4gKiBcdFx0XHRcdFx0d3BiY19jYWxlbmRhcl9fdW5zZWxlY3RfYWxsX2RhdGVzKCByZXNvdXJjZV9pZCApO1xyXG4gKlxyXG4gKlx0XHRcdFx0XHR2YXIgcmVzb3VyY2VfaWQgPSAxO1xyXG4gKiBcdEV4YW1wbGUgMTpcdFx0dmFyIG51bV9zZWxlY3RlZF9kYXlzID0gd3BiY19hdXRvX3NlbGVjdF9kYXRlc19pbl9jYWxlbmRhciggcmVzb3VyY2VfaWQsICcyMDI0LTA1LTE1JyxcclxuICogJzIwMjQtMDUtMjUnICk7IEV4YW1wbGUgMjpcdFx0dmFyIG51bV9zZWxlY3RlZF9kYXlzID0gd3BiY19hdXRvX3NlbGVjdF9kYXRlc19pbl9jYWxlbmRhciggcmVzb3VyY2VfaWQsXHJcbiAqIFsnMjAyNC0wNS0wOScsJzIwMjQtMDUtMTknLCcyMDI0LTA1LTI1J10gKTtcclxuICpcclxuICovXHJcblxyXG5cclxuLyoqXHJcbiAqIEMgQSBMIEUgTiBEIEEgUiAgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcbiAqL1xyXG5cclxuXHJcbi8qKlxyXG4gKiAgU2hvdyBXUEJDIENhbGVuZGFyXHJcbiAqXHJcbiAqIEBwYXJhbSByZXNvdXJjZV9pZFx0XHRcdC0gcmVzb3VyY2UgSURcclxuICogQHJldHVybnMge2Jvb2xlYW59XHJcbiAqL1xyXG5mdW5jdGlvbiB3cGJjX2NhbGVuZGFyX3Nob3coIHJlc291cmNlX2lkICl7XHJcblxyXG5cdC8vIElmIG5vIGNhbGVuZGFyIEhUTUwgdGFnLCAgdGhlbiAgZXhpdFxyXG5cdGlmICggMCA9PT0galF1ZXJ5KCAnI2NhbGVuZGFyX2Jvb2tpbmcnICsgcmVzb3VyY2VfaWQgKS5sZW5ndGggKXsgcmV0dXJuIGZhbHNlOyB9XHJcblxyXG5cdC8vIElmIHRoZSBjYWxlbmRhciB3aXRoIHRoZSBzYW1lIEJvb2tpbmcgcmVzb3VyY2UgaXMgYWN0aXZhdGVkIGFscmVhZHksIHRoZW4gZXhpdC4gQnV0IGluIEVsZW1lbnRvciB0aGUgY2xhc3MgY2FuIGJlIHN0YWxlLCBzbyB2ZXJpZnkgaW5zdGFuY2UuXHJcblx0aWYgKCBqUXVlcnkoICcjY2FsZW5kYXJfYm9va2luZycgKyByZXNvdXJjZV9pZCApLmhhc0NsYXNzKCAnaGFzRGF0ZXBpY2snICkgKSB7XHJcblxyXG5cdFx0dmFyIGV4aXN0aW5nX2luc3QgPSBudWxsO1xyXG5cclxuXHRcdHRyeSB7XHJcblx0XHRcdGV4aXN0aW5nX2luc3QgPSBqUXVlcnkuZGF0ZXBpY2suX2dldEluc3QoIGpRdWVyeSggJyNjYWxlbmRhcl9ib29raW5nJyArIHJlc291cmNlX2lkICkuZ2V0KCAwICkgKTtcclxuXHRcdH0gY2F0Y2ggKCBlICkge1xyXG5cdFx0XHRleGlzdGluZ19pbnN0ID0gbnVsbDtcclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIGV4aXN0aW5nX2luc3QgKSB7XHJcblx0XHRcdHJldHVybiBmYWxzZTtcclxuXHRcdH1cclxuXHJcblx0XHQvLyBTdGFsZSBtYXJrZXI6IHJlbW92ZSBhbmQgY29udGludWUgd2l0aCBpbml0LlxyXG5cdFx0alF1ZXJ5KCAnI2NhbGVuZGFyX2Jvb2tpbmcnICsgcmVzb3VyY2VfaWQgKS5yZW1vdmVDbGFzcyggJ2hhc0RhdGVwaWNrJyApO1xyXG5cdH1cclxuXHJcblxyXG5cclxuXHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdC8vIERheXMgc2VsZWN0aW9uXHJcblx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHR2YXIgbG9jYWxfX2lzX3JhbmdlX3NlbGVjdCA9IGZhbHNlO1xyXG5cdHZhciBsb2NhbF9fbXVsdGlfZGF5c19zZWxlY3RfbnVtICAgPSAzNjU7XHRcdFx0XHRcdC8vIG11bHRpcGxlIHwgZml4ZWRcclxuXHRpZiAoICdkeW5hbWljJyA9PT0gX3dwYmMuY2FsZW5kYXJfX2dldF9wYXJhbV92YWx1ZSggcmVzb3VyY2VfaWQsICdkYXlzX3NlbGVjdF9tb2RlJyApICl7XHJcblx0XHRsb2NhbF9faXNfcmFuZ2Vfc2VsZWN0ID0gdHJ1ZTtcclxuXHRcdGxvY2FsX19tdWx0aV9kYXlzX3NlbGVjdF9udW0gPSAwO1xyXG5cdH1cclxuXHRpZiAoICdzaW5nbGUnICA9PT0gX3dwYmMuY2FsZW5kYXJfX2dldF9wYXJhbV92YWx1ZSggcmVzb3VyY2VfaWQsICdkYXlzX3NlbGVjdF9tb2RlJyApICl7XHJcblx0XHRsb2NhbF9fbXVsdGlfZGF5c19zZWxlY3RfbnVtID0gMDtcclxuXHR9XHJcblxyXG5cdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0Ly8gTWluIC0gTWF4IGRheXMgdG8gc2Nyb2xsL3Nob3dcclxuXHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdHZhciBsb2NhbF9fbWluX2RhdGUgPSAwO1xyXG4gXHRsb2NhbF9fbWluX2RhdGUgPSBuZXcgRGF0ZSggX3dwYmMuZ2V0X290aGVyX3BhcmFtKCAndG9kYXlfYXJyJyApWyAwIF0sIChwYXJzZUludCggX3dwYmMuZ2V0X290aGVyX3BhcmFtKCAndG9kYXlfYXJyJyApWyAxIF0gKSAtIDEpLCBfd3BiYy5nZXRfb3RoZXJfcGFyYW0oICd0b2RheV9hcnInIClbIDIgXSwgMCwgMCwgMCApO1x0XHRcdC8vIEZpeEluOiA5LjkuMC4xNy5cclxuLy9jb25zb2xlLmxvZyggbG9jYWxfX21pbl9kYXRlICk7XHJcblx0dmFyIGxvY2FsX19tYXhfZGF0ZSA9IF93cGJjLmNhbGVuZGFyX19nZXRfcGFyYW1fdmFsdWUoIHJlc291cmNlX2lkLCAnYm9va2luZ19tYXhfbW9udGhlc19pbl9jYWxlbmRhcicgKTtcclxuXHQvL2xvY2FsX19tYXhfZGF0ZSA9IG5ldyBEYXRlKDIwMjQsIDUsIDI4KTsgIEl0IGlzIGhlcmUgaXNzdWUgb2Ygbm90IHNlbGVjdGFibGUgZGF0ZXMsIGJ1dCBzb21lIGRhdGVzIHNob3dpbmcgaW4gY2FsZW5kYXIgYXMgYXZhaWxhYmxlLCBidXQgd2UgY2FuIG5vdCBzZWxlY3QgaXQuXHJcblxyXG5cdC8vLy8gRGVmaW5lIGxhc3QgZGF5IGluIGNhbGVuZGFyIChhcyBhIGxhc3QgZGF5IG9mIG1vbnRoIChhbmQgbm90IGRhdGUsIHdoaWNoIGlzIHJlbGF0ZWQgdG8gYWN0dWFsICdUb2RheScgZGF0ZSkuXHJcblx0Ly8vLyBFLmcuIGlmIHRvZGF5IGlzIDIwMjMtMDktMjUsIGFuZCB3ZSBzZXQgJ051bWJlciBvZiBtb250aHMgdG8gc2Nyb2xsJyBhcyA1IG1vbnRocywgdGhlbiBsYXN0IGRheSB3aWxsIGJlIDIwMjQtMDItMjkgYW5kIG5vdCB0aGUgMjAyNC0wMi0yNS5cclxuXHQvLyB2YXIgY2FsX2xhc3RfZGF5X2luX21vbnRoID0galF1ZXJ5LmRhdGVwaWNrLl9kZXRlcm1pbmVEYXRlKCBudWxsLCBsb2NhbF9fbWF4X2RhdGUsIG5ldyBEYXRlKCkgKTtcclxuXHQvLyBjYWxfbGFzdF9kYXlfaW5fbW9udGggPSBuZXcgRGF0ZSggY2FsX2xhc3RfZGF5X2luX21vbnRoLmdldEZ1bGxZZWFyKCksIGNhbF9sYXN0X2RheV9pbl9tb250aC5nZXRNb250aCgpICsgMSwgMCApO1xyXG5cdC8vIGxvY2FsX19tYXhfZGF0ZSA9IGNhbF9sYXN0X2RheV9pbl9tb250aDtcdFx0XHQvLyBGaXhJbjogMTAuMC4wLjI2LlxyXG5cclxuXHQvLyBHZXQgc3RhcnQgLyBlbmQgZGF0ZXMgZnJvbSAgdGhlIEJvb2tpbmcgQ2FsZW5kYXIgc2hvcnRjb2RlLiBFeGFtcGxlOiBbYm9va2luZyBjYWxlbmRhcl9kYXRlc19zdGFydD0nMjAyNi0wMS0wMScgY2FsZW5kYXJfZGF0ZXNfZW5kPScyMDI2LTEyLTMxJyAgcmVzb3VyY2VfaWQ9MV0gLy8gRml4SW46IDEwLjEzLjEuNC5cclxuXHRpZiAoIGZhbHNlICE9PSB3cGJjX2NhbGVuZGFyX19nZXRfZGF0ZXNfc3RhcnQoIHJlc291cmNlX2lkICkgKSB7XHJcblx0XHRsb2NhbF9fbWluX2RhdGUgPSB3cGJjX2NhbGVuZGFyX19nZXRfZGF0ZXNfc3RhcnQoIHJlc291cmNlX2lkICk7ICAvLyBFLmcuIC0gbG9jYWxfX21pbl9kYXRlID0gbmV3IERhdGUoIDIwMjUsIDAsIDEgKTtcclxuXHR9XHJcblx0aWYgKCBmYWxzZSAhPT0gd3BiY19jYWxlbmRhcl9fZ2V0X2RhdGVzX2VuZCggcmVzb3VyY2VfaWQgKSApIHtcclxuXHRcdGxvY2FsX19tYXhfZGF0ZSA9IHdwYmNfY2FsZW5kYXJfX2dldF9kYXRlc19lbmQoIHJlc291cmNlX2lkICk7ICAgIC8vIEUuZy4gLSBsb2NhbF9fbWF4X2RhdGUgPSBuZXcgRGF0ZSggMjAyNSwgMTEsIDMxICk7XHJcblx0fVxyXG5cclxuXHQvLyBJbiBjYXNlIHdlIGVkaXQgYm9va2luZyBpbiBwYXN0IG9yIGhhdmUgc3BlY2lmaWMgcGFyYW1ldGVyIGluIFVSTC5cclxuXHR2YXIgd3BiY19lZGl0X2Jvb2tpbmdfaGFzaCA9IF93cGJjLmdldF9vdGhlcl9wYXJhbSggJ3RoaXNfcGFnZV9ib29raW5nX2hhc2gnICk7XHJcblx0dmFyIHdwYmNfaXNfZWRpdF9ib29raW5nX2NvbnRleHQgPSAoICd1bmRlZmluZWQnICE9PSB0eXBlb2Ygd3BiY19lZGl0X2Jvb2tpbmdfaGFzaCApICYmICggJycgIT09IHdwYmNfZWRpdF9ib29raW5nX2hhc2ggKTtcclxuXHR2YXIgd3BiY19pc19hZGRfYm9va2luZ19hZG1pbl9wYWdlID0gKCBsb2NhdGlvbi5ocmVmLmluZGV4T2YoICdwYWdlPXdwYmMnICkgIT0gLTEgKSAmJiAoIGxvY2F0aW9uLmhyZWYuaW5kZXhPZiggJ3RhYj1hZGQtYm9va2luZycgKSAhPSAtMSApO1xyXG5cdGlmICggICAoIHdwYmNfaXNfYWRkX2Jvb2tpbmdfYWRtaW5fcGFnZSB8fCB3cGJjX2lzX2VkaXRfYm9va2luZ19jb250ZXh0IClcclxuXHRcdCYmIChcclxuXHRcdFx0ICB3cGJjX2lzX2VkaXRfYm9va2luZ19jb250ZXh0XHJcblx0XHQgICB8fCAoIGxvY2F0aW9uLmhyZWYuaW5kZXhPZignYm9va2luZ19oYXNoJykgIT0gLTEgKSAgICAgICAgICAgICAgICAgIC8vIENvbW1lbnQgdGhpcyBsaW5lIGZvciBhYmlsaXR5IHRvIGFkZCAgYm9va2luZyBpbiBwYXN0IGRheXMgYXQgIEJvb2tpbmcgPiBBZGQgYm9va2luZyBwYWdlLlxyXG5cdFx0ICAgfHwgKCBsb2NhdGlvbi5ocmVmLmluZGV4T2YoJ2FsbG93X3Bhc3QnKSAhPSAtMSApICAgICAgICAgICAgICAgIC8vIEZpeEluOiAxMC43LjEuMi5cclxuXHRcdClcclxuXHQpe1xyXG5cdFx0Ly8gbG9jYWxfX21pbl9kYXRlID0gbnVsbDtcclxuXHRcdC8vIEZpeEluOiAxMC4xNC4xLjQuXHJcblx0XHRsb2NhbF9fbWluX2RhdGUgID0gbmV3IERhdGUoIF93cGJjLmdldF9vdGhlcl9wYXJhbSggJ3RpbWVfbG9jYWxfYXJyJyApWzBdLCAoIHBhcnNlSW50KCBfd3BiYy5nZXRfb3RoZXJfcGFyYW0oICd0aW1lX2xvY2FsX2FycicgKVsxXSApIC0gMSksIF93cGJjLmdldF9vdGhlcl9wYXJhbSggJ3RpbWVfbG9jYWxfYXJyJyApWzJdLCBfd3BiYy5nZXRfb3RoZXJfcGFyYW0oICd0aW1lX2xvY2FsX2FycicgKVszXSwgX3dwYmMuZ2V0X290aGVyX3BhcmFtKCAndGltZV9sb2NhbF9hcnInIClbNF0sIDAgKTtcclxuXHRcdGxvY2FsX19tYXhfZGF0ZSA9IG51bGw7XHJcblx0fVxyXG5cclxuXHR2YXIgbG9jYWxfX3N0YXJ0X3dlZWtkYXkgICAgPSBfd3BiYy5jYWxlbmRhcl9fZ2V0X3BhcmFtX3ZhbHVlKCByZXNvdXJjZV9pZCwgJ2Jvb2tpbmdfc3RhcnRfZGF5X3dlZWVrJyApO1xyXG5cdHZhciBsb2NhbF9fbnVtYmVyX29mX21vbnRocyA9IHBhcnNlSW50KCBfd3BiYy5jYWxlbmRhcl9fZ2V0X3BhcmFtX3ZhbHVlKCByZXNvdXJjZV9pZCwgJ2NhbGVuZGFyX251bWJlcl9vZl9tb250aHMnICkgKTtcclxuXHJcblx0alF1ZXJ5KCAnI2NhbGVuZGFyX2Jvb2tpbmcnICsgcmVzb3VyY2VfaWQgKS50ZXh0KCAnJyApO1x0XHRcdFx0XHQvLyBSZW1vdmUgYWxsIEhUTUwgaW4gY2FsZW5kYXIgdGFnXHJcblx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHQvLyBTaG93IGNhbGVuZGFyXHJcblx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRqUXVlcnkoJyNjYWxlbmRhcl9ib29raW5nJysgcmVzb3VyY2VfaWQpLmRhdGVwaWNrKFxyXG5cdFx0XHR7XHJcblx0XHRcdFx0YmVmb3JlU2hvd0RheTogZnVuY3Rpb24gKCBqc19kYXRlICl7XHJcblx0XHRcdFx0XHRcdFx0XHRcdHJldHVybiB3cGJjX19jYWxlbmRhcl9fYXBwbHlfY3NzX3RvX2RheXMoIGpzX2RhdGUsIHsncmVzb3VyY2VfaWQnOiByZXNvdXJjZV9pZH0sIHRoaXMgKTtcclxuXHRcdFx0XHRcdFx0XHQgIH0sXHJcblx0XHRcdFx0b25TZWxlY3Q6IGZ1bmN0aW9uICggc3RyaW5nX2RhdGVzLCBqc19kYXRlc19hcnIgKXsgIC8qKlxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0ICpcdHN0cmluZ19kYXRlcyAgID0gICAnMjMuMDguMjAyMyAtIDI2LjA4LjIwMjMnXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQgKiAgIHwgICAgJzIzLjA4LjIwMjMgLSAyMy4wOC4yMDIzJyAgICB8XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQgKiAnMTkuMDkuMjAyMywgMjQuMDguMjAyMywgMzAuMDkuMjAyMydcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCAqIGpzX2RhdGVzX2FyciAgID0gICByYW5nZTogWyBEYXRlIChBdWcgMjMgMjAyMyksXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQgKiBEYXRlIChBdWcgMjUgMjAyMyldICAgICB8ICAgICBtdWx0aXBsZTogW1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0ICogRGF0ZShPY3QgMjQgMjAyMyksIERhdGUoT2N0IDIwIDIwMjMpLCBEYXRlKE9jdFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0ICogMTYgMjAyMykgXVxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0ICovXHJcblx0XHRcdFx0XHRcdFx0XHRcdHJldHVybiB3cGJjX19jYWxlbmRhcl9fb25fc2VsZWN0X2RheXMoIHN0cmluZ19kYXRlcywgeydyZXNvdXJjZV9pZCc6IHJlc291cmNlX2lkfSwgdGhpcyApO1xyXG5cdFx0XHRcdFx0XHRcdCAgfSxcclxuXHRcdFx0XHRvbkhvdmVyOiBmdW5jdGlvbiAoIHN0cmluZ19kYXRlLCBqc19kYXRlICl7XHJcblx0XHRcdFx0XHRcdFx0XHRcdHJldHVybiB3cGJjX19jYWxlbmRhcl9fb25faG92ZXJfZGF5cyggc3RyaW5nX2RhdGUsIGpzX2RhdGUsIHsncmVzb3VyY2VfaWQnOiByZXNvdXJjZV9pZH0sIHRoaXMgKTtcclxuXHRcdFx0XHRcdFx0XHQgIH0sXHJcblx0XHRcdFx0b25DaGFuZ2VNb250aFllYXI6IGZ1bmN0aW9uICggeWVhciwgcmVhbF9tb250aCwganNfZGF0ZV9fMXN0X2RheV9pbl9tb250aCApeyB9LFxyXG5cdFx0XHRcdHNob3dPbiAgICAgICAgOiAnYm90aCcsXHJcblx0XHRcdFx0bnVtYmVyT2ZNb250aHM6IGxvY2FsX19udW1iZXJfb2ZfbW9udGhzLFxyXG5cdFx0XHRcdHN0ZXBNb250aHMgICAgOiAxLFxyXG5cdFx0XHRcdC8vIHByZXZUZXh0ICAgICAgOiAnJmxhcXVvOycsXHJcblx0XHRcdFx0Ly8gbmV4dFRleHQgICAgICA6ICcmcmFxdW87JyxcclxuXHRcdFx0XHRwcmV2VGV4dCAgICAgIDogJyZsc2FxdW87JyxcclxuXHRcdFx0XHRuZXh0VGV4dCAgICAgIDogJyZyc2FxdW87JyxcclxuXHRcdFx0XHRkYXRlRm9ybWF0ICAgIDogJ2RkLm1tLnl5JyxcclxuXHRcdFx0XHRjaGFuZ2VNb250aCAgIDogZmFsc2UsXHJcblx0XHRcdFx0Y2hhbmdlWWVhciAgICA6IGZhbHNlLFxyXG5cdFx0XHRcdG1pbkRhdGUgICAgICAgOiBsb2NhbF9fbWluX2RhdGUsXHJcblx0XHRcdFx0bWF4RGF0ZSAgICAgICA6IGxvY2FsX19tYXhfZGF0ZSwgXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vICcxWScsXHJcblx0XHRcdFx0Ly8gbWluRGF0ZTogbmV3IERhdGUoMjAyMCwgMiwgMSksIG1heERhdGU6IG5ldyBEYXRlKDIwMjAsIDksIDMxKSwgICAgICAgICAgICAgXHQvLyBBYmlsaXR5IHRvIHNldCBhbnkgIHN0YXJ0IGFuZCBlbmQgZGF0ZSBpbiBjYWxlbmRhclxyXG5cdFx0XHRcdHNob3dTdGF0dXMgICAgICA6IGZhbHNlLFxyXG5cdFx0XHRcdG11bHRpU2VwYXJhdG9yICA6ICcsICcsXHJcblx0XHRcdFx0Y2xvc2VBdFRvcCAgICAgIDogZmFsc2UsXHJcblx0XHRcdFx0Zmlyc3REYXkgICAgICAgIDogbG9jYWxfX3N0YXJ0X3dlZWtkYXksXHJcblx0XHRcdFx0Z290b0N1cnJlbnQgICAgIDogZmFsc2UsXHJcblx0XHRcdFx0aGlkZUlmTm9QcmV2TmV4dDogdHJ1ZSxcclxuXHRcdFx0XHRtdWx0aVNlbGVjdCAgICAgOiBsb2NhbF9fbXVsdGlfZGF5c19zZWxlY3RfbnVtLFxyXG5cdFx0XHRcdHJhbmdlU2VsZWN0ICAgICA6IGxvY2FsX19pc19yYW5nZV9zZWxlY3QsXHJcblx0XHRcdFx0Ly8gc2hvd1dlZWtzOiB0cnVlLFxyXG5cdFx0XHRcdHVzZVRoZW1lUm9sbGVyOiBmYWxzZVxyXG5cdFx0XHR9XHJcblx0KTtcclxuXHJcblxyXG5cclxuXHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdC8vIENsZWFyIHRvZGF5IGRhdGUgaGlnaGxpZ2h0aW5nXHJcblx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRzZXRUaW1lb3V0KCBmdW5jdGlvbiAoKXsgIHdwYmNfY2FsZW5kYXJzX19jbGVhcl9kYXlzX2hpZ2hsaWdodGluZyggcmVzb3VyY2VfaWQgKTsgIH0sIDUwMCApOyAgICAgICAgICAgICAgICAgICAgXHQvLyBGaXhJbjogNy4xLjIuOC5cclxuXHJcblx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHQvLyBTY3JvbGwgY2FsZW5kYXIgdG8gIHNwZWNpZmljIG1vbnRoXHJcblx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHR2YXIgc3RhcnRfYmtfbW9udGggPSBfd3BiYy5jYWxlbmRhcl9fZ2V0X3BhcmFtX3ZhbHVlKCByZXNvdXJjZV9pZCwgJ2NhbGVuZGFyX3Njcm9sbF90bycgKTtcclxuXHRpZiAoIGZhbHNlICE9PSBzdGFydF9ia19tb250aCApe1xyXG5cdFx0d3BiY19jYWxlbmRhcl9fc2Nyb2xsX3RvKCByZXNvdXJjZV9pZCwgc3RhcnRfYmtfbW9udGhbIDAgXSwgc3RhcnRfYmtfbW9udGhbIDEgXSApO1xyXG5cdH1cclxuXHR9XHJcblxyXG5cclxuXHQvKipcclxuXHQgKiBHZXQgYm9va2luZyBzdGF0dXNlcyBhcyBhcnJheSBmcm9tIHRoZSBzdHJ1Y3R1cmVkIHN1bW1hcnkgZmllbGQsIHdpdGggZmFsbGJhY2sgdG8gdGhlIGxlZ2FjeSBzdHJpbmcgZmllbGQuXHJcblx0ICpcclxuXHQgKiBAcGFyYW0gZGF0ZV9ib29raW5nc19vYmpcclxuXHQgKiBAcmV0dXJucyB7W119XHJcblx0ICovXHJcblx0ZnVuY3Rpb24gd3BiY19nZXRfYm9va2luZ19zdGF0dXNlc19fYXNfYXJyKCBkYXRlX2Jvb2tpbmdzX29iaiApe1xyXG5cclxuXHRcdGlmIChcclxuXHRcdFx0ICAgKCAhIGRhdGVfYm9va2luZ3Nfb2JqIClcclxuXHRcdFx0fHwgKCAndW5kZWZpbmVkJyA9PT0gdHlwZW9mIChkYXRlX2Jvb2tpbmdzX29ialsgJ3N1bW1hcnknIF0pIClcclxuXHRcdCl7XHJcblx0XHRcdHJldHVybiBbXTtcclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIGRhdGVfYm9va2luZ3Nfb2JqWyAnc3VtbWFyeScgXVsgJ3N0YXR1c19mb3JfYm9va2luZ3NfYXJyJyBdICkgKXtcclxuXHRcdFx0cmV0dXJuIGRhdGVfYm9va2luZ3Nfb2JqWyAnc3VtbWFyeScgXVsgJ3N0YXR1c19mb3JfYm9va2luZ3NfYXJyJyBdLmZpbHRlciggZnVuY3Rpb24gKCBib29raW5nX3N0YXR1cyApe1xyXG5cdFx0XHRcdHJldHVybiAnJyAhPT0gYm9va2luZ19zdGF0dXM7XHJcblx0XHRcdH0gKTtcclxuXHRcdH1cclxuXHJcblx0XHRpZiAoICEgZGF0ZV9ib29raW5nc19vYmpbICdzdW1tYXJ5JyBdWyAnc3RhdHVzX2Zvcl9ib29raW5ncycgXSApe1xyXG5cdFx0XHRyZXR1cm4gW107XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGRhdGVfYm9va2luZ3Nfb2JqWyAnc3VtbWFyeScgXVsgJ3N0YXR1c19mb3JfYm9va2luZ3MnIF0udG9TdHJpbmcoKS50cmltKCkuc3BsaXQoIC9cXHMrLyApLmZpbHRlciggZnVuY3Rpb24gKCBib29raW5nX3N0YXR1cyApe1xyXG5cdFx0XHRyZXR1cm4gJycgIT09IGJvb2tpbmdfc3RhdHVzO1xyXG5cdFx0fSApO1xyXG5cdH1cclxuXHJcblxyXG5cdC8qKlxyXG5cdCAqIENoZWNrIGV4YWN0IGJvb2tpbmcgc3RhdHVzIGluIHN0YXR1c2VzIGFycmF5LlxyXG5cdCAqXHJcblx0ICogQHBhcmFtIHtbXX0gYm9va2luZ19zdGF0dXNlc19hcnJcclxuXHQgKiBAcGFyYW0ge3N0cmluZ30gYm9va2luZ19zdGF0dXNcclxuXHQgKiBAcmV0dXJucyB7Ym9vbGVhbn1cclxuXHQgKi9cclxuXHRmdW5jdGlvbiB3cGJjX2Jvb2tpbmdfc3RhdHVzZXNfX2hhcyggYm9va2luZ19zdGF0dXNlc19hcnIsIGJvb2tpbmdfc3RhdHVzICl7XHJcblx0XHRyZXR1cm4gYm9va2luZ19zdGF0dXNlc19hcnIuaW5kZXhPZiggYm9va2luZ19zdGF0dXMgKSA+IC0xO1xyXG5cdH1cclxuXHJcblxyXG5cdC8qKlxyXG5cdCAqIENoZWNrIGJvb2tpbmcgc3RhdHVzIHBhcnQsIGUuZy4gXCJwZW5kaW5nXCIgaW4gXCJhcHByb3ZlZF9wZW5kaW5nXCIuXHJcblx0ICpcclxuXHQgKiBAcGFyYW0ge1tdfSBib29raW5nX3N0YXR1c2VzX2FyclxyXG5cdCAqIEBwYXJhbSB7c3RyaW5nfSBib29raW5nX3N0YXR1c19wYXJ0XHJcblx0ICogQHJldHVybnMge2Jvb2xlYW59XHJcblx0ICovXHJcblx0ZnVuY3Rpb24gd3BiY19ib29raW5nX3N0YXR1c2VzX19oYXNfcGFydCggYm9va2luZ19zdGF0dXNlc19hcnIsIGJvb2tpbmdfc3RhdHVzX3BhcnQgKXtcclxuXHJcblx0XHRmb3IgKCB2YXIgaSA9IDA7IGkgPCBib29raW5nX3N0YXR1c2VzX2Fyci5sZW5ndGg7IGkrKyApe1xyXG5cdFx0XHRpZiAoIGJvb2tpbmdfc3RhdHVzZXNfYXJyWyBpIF0uc3BsaXQoICdfJyApLmluZGV4T2YoIGJvb2tpbmdfc3RhdHVzX3BhcnQgKSA+IC0xICl7XHJcblx0XHRcdFx0cmV0dXJuIHRydWU7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gZmFsc2U7XHJcblx0fVxyXG5cclxuXHJcblx0LyoqXHJcblx0ICogQXBwbHkgQ1NTIHRvIGNhbGVuZGFyIGRhdGUgY2VsbHNcclxuXHQgKlxyXG5cdCAqIEBwYXJhbSBkYXRlXHRcdFx0XHRcdFx0XHRcdFx0XHQtICBKYXZhU2NyaXB0IERhdGUgT2JqOiAgXHRcdE1vbiBEZWMgMTEgMjAyMyAwMDowMDowMFxyXG5cdCAqICAgICBHTVQrMDIwMCAoRWFzdGVybiBFdXJvcGVhbiBTdGFuZGFyZCBUaW1lKVxyXG5cdCAqIEBwYXJhbSBjYWxlbmRhcl9wYXJhbXNfYXJyXHRcdFx0XHRcdFx0LSAgQ2FsZW5kYXIgU2V0dGluZ3MgT2JqZWN0OiAgXHR7XHJcblx0ICpcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCAgXHRcdFx0XHRcdFx0XCJyZXNvdXJjZV9pZFwiOiA0XHJcblx0ICpcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHR9XHJcblx0ICogQHBhcmFtIGRhdGVwaWNrX3RoaXNcdFx0XHRcdFx0XHRcdFx0LSB0aGlzIG9mIGRhdGVwaWNrIE9ialxyXG5cdCAqIEByZXR1cm5zIHsoKnxzdHJpbmcpW118KGJvb2xlYW58c3RyaW5nKVtdfVx0XHQtIFsge3RydWUgLWF2YWlsYWJsZSB8IGZhbHNlIC0gdW5hdmFpbGFibGV9LCAnQ1NTIGNsYXNzZXMgZm9yXHJcblx0ICogICAgIGNhbGVuZGFyIGRheSBjZWxsJyBdXHJcblx0ICovXHJcblx0ZnVuY3Rpb24gd3BiY19fY2FsZW5kYXJfX2FwcGx5X2Nzc190b19kYXlzKCBkYXRlLCBjYWxlbmRhcl9wYXJhbXNfYXJyLCBkYXRlcGlja190aGlzICl7XHJcblxyXG5cdFx0dmFyIHRvZGF5X2RhdGUgPSBuZXcgRGF0ZSggX3dwYmMuZ2V0X290aGVyX3BhcmFtKCAndG9kYXlfYXJyJyApWyAwIF0sIChwYXJzZUludCggX3dwYmMuZ2V0X290aGVyX3BhcmFtKCAndG9kYXlfYXJyJyApWyAxIF0gKSAtIDEpLCBfd3BiYy5nZXRfb3RoZXJfcGFyYW0oICd0b2RheV9hcnInIClbIDIgXSwgMCwgMCwgMCApO1x0XHRcdFx0XHRcdFx0XHQvLyBUb2RheSBKU19EYXRlX09iai5cclxuXHRcdHZhciBjbGFzc19kYXkgICAgID0gd3BiY19fZ2V0X190ZF9jbGFzc19kYXRlKCBkYXRlICk7XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gJzEtOS0yMDIzJ1xyXG5cdFx0dmFyIHNxbF9jbGFzc19kYXkgPSB3cGJjX19nZXRfX3NxbF9jbGFzc19kYXRlKCBkYXRlICk7XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gJzIwMjMtMDEtMDknXHJcblx0XHR2YXIgcmVzb3VyY2VfaWQgPSAoICd1bmRlZmluZWQnICE9PSB0eXBlb2YoY2FsZW5kYXJfcGFyYW1zX2FyclsgJ3Jlc291cmNlX2lkJyBdKSApID8gY2FsZW5kYXJfcGFyYW1zX2FyclsgJ3Jlc291cmNlX2lkJyBdIDogJzEnOyBcdFx0Ly8gJzEnXHJcblxyXG5cdFx0Ly8gR2V0IFNlbGVjdGVkIGRhdGVzIGluIGNhbGVuZGFyXHJcblx0XHR2YXIgc2VsZWN0ZWRfZGF0ZXNfc3FsID0gd3BiY19nZXRfX3NlbGVjdGVkX2RhdGVzX3NxbF9fYXNfYXJyKCByZXNvdXJjZV9pZCApO1xyXG5cclxuXHRcdC8vIEdldCBEYXRhIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHR2YXIgZGF0ZV9ib29raW5nc19vYmogPSBfd3BiYy5ib29raW5nc19pbl9jYWxlbmRhcl9fZ2V0X2Zvcl9kYXRlKCByZXNvdXJjZV9pZCwgc3FsX2NsYXNzX2RheSApO1xyXG5cclxuXHJcblx0XHQvLyBBcnJheSB3aXRoIENTUyBjbGFzc2VzIGZvciBkYXRlIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdFx0dmFyIGNzc19jbGFzc2VzX19mb3JfZGF0ZSA9IFtdO1xyXG5cdFx0Y3NzX2NsYXNzZXNfX2Zvcl9kYXRlLnB1c2goICdzcWxfZGF0ZV8nICAgICArIHNxbF9jbGFzc19kYXkgKTtcdFx0XHRcdC8vICAnc3FsX2RhdGVfMjAyMy0wNy0yMSdcclxuXHRcdGNzc19jbGFzc2VzX19mb3JfZGF0ZS5wdXNoKCAnY2FsNGRhdGUtJyAgICAgKyBjbGFzc19kYXkgKTtcdFx0XHRcdFx0Ly8gICdjYWw0ZGF0ZS03LTIxLTIwMjMnXHJcblx0XHRjc3NfY2xhc3Nlc19fZm9yX2RhdGUucHVzaCggJ3dwYmNfd2Vla2RheV8nICsgZGF0ZS5nZXREYXkoKSApO1x0XHRcdFx0Ly8gICd3cGJjX3dlZWtkYXlfNCdcclxuXHJcblx0XHQvLyBEZWZpbmUgU2VsZWN0ZWQgQ2hlY2sgSW4vT3V0IGRhdGVzIGluIFREICAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdFx0aWYgKFxyXG5cdFx0XHRcdCggc2VsZWN0ZWRfZGF0ZXNfc3FsLmxlbmd0aCAgKVxyXG5cdFx0XHQvLyYmICAoIHNlbGVjdGVkX2RhdGVzX3NxbFsgMCBdICE9PSBzZWxlY3RlZF9kYXRlc19zcWxbIChzZWxlY3RlZF9kYXRlc19zcWwubGVuZ3RoIC0gMSkgXSApXHJcblx0XHQpe1xyXG5cdFx0XHRpZiAoIHNxbF9jbGFzc19kYXkgPT09IHNlbGVjdGVkX2RhdGVzX3NxbFsgMCBdICl7XHJcblx0XHRcdFx0Y3NzX2NsYXNzZXNfX2Zvcl9kYXRlLnB1c2goICdzZWxlY3RlZF9jaGVja19pbicgKTtcclxuXHRcdFx0XHRjc3NfY2xhc3Nlc19fZm9yX2RhdGUucHVzaCggJ3NlbGVjdGVkX2NoZWNrX2luX291dCcgKTtcclxuXHRcdFx0fVxyXG5cdFx0XHRpZiAoICAoIHNlbGVjdGVkX2RhdGVzX3NxbC5sZW5ndGggPiAxICkgJiYgKCBzcWxfY2xhc3NfZGF5ID09PSBzZWxlY3RlZF9kYXRlc19zcWxbIChzZWxlY3RlZF9kYXRlc19zcWwubGVuZ3RoIC0gMSkgXSApICkge1xyXG5cdFx0XHRcdGNzc19jbGFzc2VzX19mb3JfZGF0ZS5wdXNoKCAnc2VsZWN0ZWRfY2hlY2tfb3V0JyApO1xyXG5cdFx0XHRcdGNzc19jbGFzc2VzX19mb3JfZGF0ZS5wdXNoKCAnc2VsZWN0ZWRfY2hlY2tfaW5fb3V0JyApO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cclxuXHRcdHZhciBpc19kYXlfc2VsZWN0YWJsZSA9IGZhbHNlO1xyXG5cclxuXHRcdC8vIElmIHNvbWV0aGluZyBub3QgZGVmaW5lZCwgIHRoZW4gIHRoaXMgZGF0ZSBjbG9zZWQgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIC8vIEZpeEluOiAxMC4xMi40LjYuXHJcblx0XHRpZiAoIChmYWxzZSA9PT0gZGF0ZV9ib29raW5nc19vYmopIHx8ICgndW5kZWZpbmVkJyA9PT0gdHlwZW9mIChkYXRlX2Jvb2tpbmdzX29ialtyZXNvdXJjZV9pZF0pKSApIHtcclxuXHJcblx0XHRcdGNzc19jbGFzc2VzX19mb3JfZGF0ZS5wdXNoKCAnZGF0ZV91c2VyX3VuYXZhaWxhYmxlJyApO1xyXG5cclxuXHRcdFx0cmV0dXJuIFsgaXNfZGF5X3NlbGVjdGFibGUsIGNzc19jbGFzc2VzX19mb3JfZGF0ZS5qb2luKCcgJykgIF07XHJcblx0XHR9XHJcblxyXG5cclxuXHRcdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHQvLyAgIGRhdGVfYm9va2luZ3Nfb2JqICAtIERlZmluZWQuICAgICAgICAgICAgRGF0ZXMgY2FuIGJlIHNlbGVjdGFibGUuXHJcblx0XHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdFx0dmFyIGJvb2tpbmdfc3RhdHVzZXNfYXJyID0gd3BiY19nZXRfYm9va2luZ19zdGF0dXNlc19fYXNfYXJyKCBkYXRlX2Jvb2tpbmdzX29iaiApO1xyXG5cclxuXHRcdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHQvLyBBZGQgc2Vhc29uIG5hbWVzIHRvIHRoZSBkYXkgQ1NTIGNsYXNzZXMgLS0gaXQgaXMgcmVxdWlyZWQgZm9yIGNvcnJlY3QgIHdvcmsgIG9mIGNvbmRpdGlvbmFsIGZpZWxkcyAtLS0tLS0tLS0tLS0tLVxyXG5cdFx0dmFyIHNlYXNvbl9uYW1lc19hcnIgPSBfd3BiYy5zZWFzb25zX19nZXRfZm9yX2RhdGUoIHJlc291cmNlX2lkLCBzcWxfY2xhc3NfZGF5ICk7XHJcblxyXG5cdFx0Zm9yICggdmFyIHNlYXNvbl9rZXkgaW4gc2Vhc29uX25hbWVzX2FyciApe1xyXG5cclxuXHRcdFx0Y3NzX2NsYXNzZXNfX2Zvcl9kYXRlLnB1c2goIHNlYXNvbl9uYW1lc19hcnJbIHNlYXNvbl9rZXkgXSApO1x0XHRcdFx0Ly8gICd3cGRldmJrX3NlYXNvbl9zZXB0ZW1iZXJfMjAyMydcclxuXHRcdH1cclxuXHRcdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblxyXG5cclxuXHRcdC8vIENvc3QgUmF0ZSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHRjc3NfY2xhc3Nlc19fZm9yX2RhdGUucHVzaCggJ3JhdGVfJyArIGRhdGVfYm9va2luZ3Nfb2JqWyByZXNvdXJjZV9pZCBdWyAnZGF0ZV9jb3N0X3JhdGUnIF0udG9TdHJpbmcoKS5yZXBsYWNlKCAvW1xcLlxcc10vZywgJ18nICkgKTtcdFx0XHRcdFx0XHQvLyAgJ3JhdGVfOTlfMDAnIC0+IDk5LjAwXHJcblxyXG5cclxuXHRcdGlmICggcGFyc2VJbnQoIGRhdGVfYm9va2luZ3Nfb2JqWyAnZGF5X2F2YWlsYWJpbGl0eScgXSApID4gMCApe1xyXG5cdFx0XHRpc19kYXlfc2VsZWN0YWJsZSA9IHRydWU7XHJcblx0XHRcdGNzc19jbGFzc2VzX19mb3JfZGF0ZS5wdXNoKCAnZGF0ZV9hdmFpbGFibGUnICk7XHJcblx0XHRcdGNzc19jbGFzc2VzX19mb3JfZGF0ZS5wdXNoKCAncmVzZXJ2ZWRfZGF5c19jb3VudCcgKyBwYXJzZUludCggZGF0ZV9ib29raW5nc19vYmpbICdtYXhfY2FwYWNpdHknIF0gLSBkYXRlX2Jvb2tpbmdzX29ialsgJ2RheV9hdmFpbGFiaWxpdHknIF0gKSApO1xyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0aXNfZGF5X3NlbGVjdGFibGUgPSBmYWxzZTtcclxuXHRcdFx0Y3NzX2NsYXNzZXNfX2Zvcl9kYXRlLnB1c2goICdkYXRlX3VzZXJfdW5hdmFpbGFibGUnICk7XHJcblx0XHR9XHJcblxyXG5cclxuXHRcdHN3aXRjaCAoIGRhdGVfYm9va2luZ3Nfb2JqWyAnc3VtbWFyeSddWydzdGF0dXNfZm9yX2RheScgXSApe1xyXG5cclxuXHRcdFx0Y2FzZSAnYXZhaWxhYmxlJzpcclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgJ3RpbWVfc2xvdHNfYm9va2luZyc6XHJcblx0XHRcdFx0Y3NzX2NsYXNzZXNfX2Zvcl9kYXRlLnB1c2goICd0aW1lc3BhcnRseScsICd0aW1lc19jbG9jaycgKTtcclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgJ2Z1bGxfZGF5X2Jvb2tpbmcnOlxyXG5cdFx0XHRcdGNzc19jbGFzc2VzX19mb3JfZGF0ZS5wdXNoKCAnZnVsbF9kYXlfYm9va2luZycgKTtcclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgJ3NlYXNvbl9maWx0ZXInOlxyXG5cdFx0XHRcdGNzc19jbGFzc2VzX19mb3JfZGF0ZS5wdXNoKCAnZGF0ZV91c2VyX3VuYXZhaWxhYmxlJywgJ3NlYXNvbl91bmF2YWlsYWJsZScgKTtcclxuXHRcdFx0XHRkYXRlX2Jvb2tpbmdzX29ialsgJ3N1bW1hcnknXVsnc3RhdHVzX2Zvcl9ib29raW5ncycgXSA9ICcnO1x0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQvLyBSZXNldCBib29raW5nIHN0YXR1cyBjb2xvciBmb3IgcG9zc2libGUgb2xkIGJvb2tpbmdzIG9uIHRoaXMgZGF0ZVxyXG5cdFx0XHRcdGRhdGVfYm9va2luZ3Nfb2JqWyAnc3VtbWFyeSddWydzdGF0dXNfZm9yX2Jvb2tpbmdzX2FycicgXSA9IFtdO1xyXG5cdFx0XHRcdGJvb2tpbmdfc3RhdHVzZXNfYXJyID0gW107XHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdyZXNvdXJjZV9hdmFpbGFiaWxpdHknOlxyXG5cdFx0XHRcdGNzc19jbGFzc2VzX19mb3JfZGF0ZS5wdXNoKCAnZGF0ZV91c2VyX3VuYXZhaWxhYmxlJywgJ3Jlc291cmNlX3VuYXZhaWxhYmxlJyApO1xyXG5cdFx0XHRcdGRhdGVfYm9va2luZ3Nfb2JqWyAnc3VtbWFyeSddWydzdGF0dXNfZm9yX2Jvb2tpbmdzJyBdID0gJyc7XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vIFJlc2V0IGJvb2tpbmcgc3RhdHVzIGNvbG9yIGZvciBwb3NzaWJsZSBvbGQgYm9va2luZ3Mgb24gdGhpcyBkYXRlXHJcblx0XHRcdFx0ZGF0ZV9ib29raW5nc19vYmpbICdzdW1tYXJ5J11bJ3N0YXR1c19mb3JfYm9va2luZ3NfYXJyJyBdID0gW107XHJcblx0XHRcdFx0Ym9va2luZ19zdGF0dXNlc19hcnIgPSBbXTtcclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgJ3dlZWtkYXlfdW5hdmFpbGFibGUnOlxyXG5cdFx0XHRcdGNzc19jbGFzc2VzX19mb3JfZGF0ZS5wdXNoKCAnZGF0ZV91c2VyX3VuYXZhaWxhYmxlJywgJ3dlZWtkYXlfdW5hdmFpbGFibGUnICk7XHJcblx0XHRcdFx0ZGF0ZV9ib29raW5nc19vYmpbICdzdW1tYXJ5J11bJ3N0YXR1c19mb3JfYm9va2luZ3MnIF0gPSAnJztcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gUmVzZXQgYm9va2luZyBzdGF0dXMgY29sb3IgZm9yIHBvc3NpYmxlIG9sZCBib29raW5ncyBvbiB0aGlzIGRhdGVcclxuXHRcdFx0XHRkYXRlX2Jvb2tpbmdzX29ialsgJ3N1bW1hcnknXVsnc3RhdHVzX2Zvcl9ib29raW5nc19hcnInIF0gPSBbXTtcclxuXHRcdFx0XHRib29raW5nX3N0YXR1c2VzX2FyciA9IFtdO1xyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0Y2FzZSAnZnJvbV90b2RheV91bmF2YWlsYWJsZSc6XHJcblx0XHRcdFx0Y3NzX2NsYXNzZXNfX2Zvcl9kYXRlLnB1c2goICdkYXRlX3VzZXJfdW5hdmFpbGFibGUnLCAnZnJvbV90b2RheV91bmF2YWlsYWJsZScgKTtcclxuXHRcdFx0XHRkYXRlX2Jvb2tpbmdzX29ialsgJ3N1bW1hcnknXVsnc3RhdHVzX2Zvcl9ib29raW5ncycgXSA9ICcnO1x0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQvLyBSZXNldCBib29raW5nIHN0YXR1cyBjb2xvciBmb3IgcG9zc2libGUgb2xkIGJvb2tpbmdzIG9uIHRoaXMgZGF0ZVxyXG5cdFx0XHRcdGRhdGVfYm9va2luZ3Nfb2JqWyAnc3VtbWFyeSddWydzdGF0dXNfZm9yX2Jvb2tpbmdzX2FycicgXSA9IFtdO1xyXG5cdFx0XHRcdGJvb2tpbmdfc3RhdHVzZXNfYXJyID0gW107XHJcblx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRjYXNlICdsaW1pdF9hdmFpbGFibGVfZnJvbV90b2RheSc6XHJcblx0XHRcdFx0Y3NzX2NsYXNzZXNfX2Zvcl9kYXRlLnB1c2goICdkYXRlX3VzZXJfdW5hdmFpbGFibGUnLCAnbGltaXRfYXZhaWxhYmxlX2Zyb21fdG9kYXknICk7XHJcblx0XHRcdFx0ZGF0ZV9ib29raW5nc19vYmpbICdzdW1tYXJ5J11bJ3N0YXR1c19mb3JfYm9va2luZ3MnIF0gPSAnJztcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gUmVzZXQgYm9va2luZyBzdGF0dXMgY29sb3IgZm9yIHBvc3NpYmxlIG9sZCBib29raW5ncyBvbiB0aGlzIGRhdGVcclxuXHRcdFx0XHRkYXRlX2Jvb2tpbmdzX29ialsgJ3N1bW1hcnknXVsnc3RhdHVzX2Zvcl9ib29raW5nc19hcnInIF0gPSBbXTtcclxuXHRcdFx0XHRib29raW5nX3N0YXR1c2VzX2FyciA9IFtdO1xyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0Y2FzZSAnY2hhbmdlX292ZXInOlxyXG5cdFx0XHRcdC8qXHJcblx0XHRcdFx0ICpcclxuXHRcdFx0XHQvLyAgY2hlY2tfb3V0X3RpbWVfZGF0ZTJhcHByb3ZlIFx0IFx0Y2hlY2tfaW5fdGltZV9kYXRlMmFwcHJvdmVcclxuXHRcdFx0XHQvLyAgY2hlY2tfb3V0X3RpbWVfZGF0ZTJhcHByb3ZlIFx0IFx0Y2hlY2tfaW5fdGltZV9kYXRlX2FwcHJvdmVkXHJcblx0XHRcdFx0Ly8gIGNoZWNrX2luX3RpbWVfZGF0ZTJhcHByb3ZlIFx0XHQgXHRjaGVja19vdXRfdGltZV9kYXRlX2FwcHJvdmVkXHJcblx0XHRcdFx0Ly8gIGNoZWNrX291dF90aW1lX2RhdGVfYXBwcm92ZWQgXHQgXHRjaGVja19pbl90aW1lX2RhdGVfYXBwcm92ZWRcclxuXHRcdFx0XHQgKi9cclxuXHJcblx0XHRcdFx0Y3NzX2NsYXNzZXNfX2Zvcl9kYXRlLnB1c2goICd0aW1lc3BhcnRseScsICdjaGVja19pbl90aW1lJywgJ2NoZWNrX291dF90aW1lJyApO1xyXG5cdFx0XHRcdC8vIEZpeEluOiAxMC4wLjAuMi5cclxuXHRcdFx0XHRpZiAoIHdwYmNfYm9va2luZ19zdGF0dXNlc19faGFzKCBib29raW5nX3N0YXR1c2VzX2FyciwgJ2FwcHJvdmVkX3BlbmRpbmcnICkgKXtcclxuXHRcdFx0XHRcdGNzc19jbGFzc2VzX19mb3JfZGF0ZS5wdXNoKCAnY2hlY2tfb3V0X3RpbWVfZGF0ZV9hcHByb3ZlZCcsICdjaGVja19pbl90aW1lX2RhdGUyYXBwcm92ZScgKTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdFx0aWYgKCB3cGJjX2Jvb2tpbmdfc3RhdHVzZXNfX2hhcyggYm9va2luZ19zdGF0dXNlc19hcnIsICdwZW5kaW5nX2FwcHJvdmVkJyApICl7XHJcblx0XHRcdFx0XHRjc3NfY2xhc3Nlc19fZm9yX2RhdGUucHVzaCggJ2NoZWNrX291dF90aW1lX2RhdGUyYXBwcm92ZScsICdjaGVja19pbl90aW1lX2RhdGVfYXBwcm92ZWQnICk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0Y2FzZSAnY2hlY2tfaW4nOlxyXG5cdFx0XHRcdGNzc19jbGFzc2VzX19mb3JfZGF0ZS5wdXNoKCAndGltZXNwYXJ0bHknLCAnY2hlY2tfaW5fdGltZScgKTtcclxuXHJcblx0XHRcdFx0Ly8gRml4SW46IDkuOS4wLjMzLlxyXG5cdFx0XHRcdGlmICggd3BiY19ib29raW5nX3N0YXR1c2VzX19oYXNfcGFydCggYm9va2luZ19zdGF0dXNlc19hcnIsICdwZW5kaW5nJyApICl7XHJcblx0XHRcdFx0XHRjc3NfY2xhc3Nlc19fZm9yX2RhdGUucHVzaCggJ2NoZWNrX2luX3RpbWVfZGF0ZTJhcHByb3ZlJyApO1xyXG5cdFx0XHRcdH0gZWxzZSBpZiAoIHdwYmNfYm9va2luZ19zdGF0dXNlc19faGFzX3BhcnQoIGJvb2tpbmdfc3RhdHVzZXNfYXJyLCAnYXBwcm92ZWQnICkgKXtcclxuXHRcdFx0XHRcdGNzc19jbGFzc2VzX19mb3JfZGF0ZS5wdXNoKCAnY2hlY2tfaW5fdGltZV9kYXRlX2FwcHJvdmVkJyApO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdGNhc2UgJ2NoZWNrX291dCc6XHJcblx0XHRcdFx0Y3NzX2NsYXNzZXNfX2Zvcl9kYXRlLnB1c2goICd0aW1lc3BhcnRseScsICdjaGVja19vdXRfdGltZScgKTtcclxuXHJcblx0XHRcdFx0Ly8gRml4SW46IDkuOS4wLjMzLlxyXG5cdFx0XHRcdGlmICggd3BiY19ib29raW5nX3N0YXR1c2VzX19oYXNfcGFydCggYm9va2luZ19zdGF0dXNlc19hcnIsICdwZW5kaW5nJyApICl7XHJcblx0XHRcdFx0XHRjc3NfY2xhc3Nlc19fZm9yX2RhdGUucHVzaCggJ2NoZWNrX291dF90aW1lX2RhdGUyYXBwcm92ZScgKTtcclxuXHRcdFx0XHR9IGVsc2UgaWYgKCB3cGJjX2Jvb2tpbmdfc3RhdHVzZXNfX2hhc19wYXJ0KCBib29raW5nX3N0YXR1c2VzX2FyciwgJ2FwcHJvdmVkJyApICl7XHJcblx0XHRcdFx0XHRjc3NfY2xhc3Nlc19fZm9yX2RhdGUucHVzaCggJ2NoZWNrX291dF90aW1lX2RhdGVfYXBwcm92ZWQnICk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0ZGVmYXVsdDpcclxuXHRcdFx0XHQvLyBtaXhlZCBzdGF0dXNlczogJ2NoYW5nZV9vdmVyIGNoZWNrX291dCcgLi4uLiB2YXJpYXRpb25zLi4uLiBjaGVjayBtb3JlIGluIFx0XHRmdW5jdGlvbiB3cGJjX2dldF9hdmFpbGFiaWxpdHlfcGVyX2RheXNfYXJyKClcclxuXHRcdFx0XHRkYXRlX2Jvb2tpbmdzX29ialsgJ3N1bW1hcnknXVsnc3RhdHVzX2Zvcl9kYXknIF0gPSAnYXZhaWxhYmxlJztcclxuXHRcdH1cclxuXHJcblxyXG5cclxuXHRcdGlmICggJ2F2YWlsYWJsZScgIT0gZGF0ZV9ib29raW5nc19vYmpbICdzdW1tYXJ5J11bJ3N0YXR1c19mb3JfZGF5JyBdICl7XHJcblxyXG5cdFx0XHR2YXIgaXNfc2V0X3BlbmRpbmdfZGF5c19zZWxlY3RhYmxlID0gX3dwYmMuY2FsZW5kYXJfX2dldF9wYXJhbV92YWx1ZSggcmVzb3VyY2VfaWQsICdwZW5kaW5nX2RheXNfc2VsZWN0YWJsZScgKTtcdC8vIHNldCBwZW5kaW5nIGRheXMgc2VsZWN0YWJsZSAgICAgICAgICAvLyBGaXhJbjogOC42LjEuMTguXHJcblxyXG5cdFx0XHRpZiAoIHdwYmNfYm9va2luZ19zdGF0dXNlc19faGFzKCBib29raW5nX3N0YXR1c2VzX2FyciwgJ3BlbmRpbmcnICkgKXtcclxuXHRcdFx0XHRjc3NfY2xhc3Nlc19fZm9yX2RhdGUucHVzaCggJ2RhdGUyYXBwcm92ZScgKTtcclxuXHRcdFx0XHRpc19kYXlfc2VsZWN0YWJsZSA9IChpc19kYXlfc2VsZWN0YWJsZSkgPyB0cnVlIDogaXNfc2V0X3BlbmRpbmdfZGF5c19zZWxlY3RhYmxlO1xyXG5cdFx0XHR9XHJcblx0XHRcdGlmICggd3BiY19ib29raW5nX3N0YXR1c2VzX19oYXMoIGJvb2tpbmdfc3RhdHVzZXNfYXJyLCAnYXBwcm92ZWQnICkgKXtcclxuXHRcdFx0XHRjc3NfY2xhc3Nlc19fZm9yX2RhdGUucHVzaCggJ2RhdGVfYXBwcm92ZWQnICk7XHJcblx0XHRcdH1cclxuXHRcdFx0aWYgKCB3cGJjX2Jvb2tpbmdfc3RhdHVzZXNfX2hhcyggYm9va2luZ19zdGF0dXNlc19hcnIsICdwZW5kaW5nX3BlbmRpbmcnICkgKXtcclxuXHRcdFx0XHRjc3NfY2xhc3Nlc19fZm9yX2RhdGUucHVzaCggJ2NoZWNrX291dF90aW1lX2RhdGUyYXBwcm92ZScsICdjaGVja19pbl90aW1lX2RhdGUyYXBwcm92ZScgKTtcclxuXHRcdFx0XHRpc19kYXlfc2VsZWN0YWJsZSA9IChpc19kYXlfc2VsZWN0YWJsZSkgPyB0cnVlIDogaXNfc2V0X3BlbmRpbmdfZGF5c19zZWxlY3RhYmxlO1xyXG5cdFx0XHR9XHJcblx0XHRcdGlmICggd3BiY19ib29raW5nX3N0YXR1c2VzX19oYXMoIGJvb2tpbmdfc3RhdHVzZXNfYXJyLCAncGVuZGluZ19hcHByb3ZlZCcgKSApe1xyXG5cdFx0XHRcdGNzc19jbGFzc2VzX19mb3JfZGF0ZS5wdXNoKCAnY2hlY2tfb3V0X3RpbWVfZGF0ZTJhcHByb3ZlJywgJ2NoZWNrX2luX3RpbWVfZGF0ZV9hcHByb3ZlZCcgKTtcclxuXHRcdFx0XHRpc19kYXlfc2VsZWN0YWJsZSA9IChpc19kYXlfc2VsZWN0YWJsZSkgPyB0cnVlIDogaXNfc2V0X3BlbmRpbmdfZGF5c19zZWxlY3RhYmxlO1xyXG5cdFx0XHR9XHJcblx0XHRcdGlmICggd3BiY19ib29raW5nX3N0YXR1c2VzX19oYXMoIGJvb2tpbmdfc3RhdHVzZXNfYXJyLCAnYXBwcm92ZWRfcGVuZGluZycgKSApe1xyXG5cdFx0XHRcdGNzc19jbGFzc2VzX19mb3JfZGF0ZS5wdXNoKCAnY2hlY2tfb3V0X3RpbWVfZGF0ZV9hcHByb3ZlZCcsICdjaGVja19pbl90aW1lX2RhdGUyYXBwcm92ZScgKTtcclxuXHRcdFx0XHRpc19kYXlfc2VsZWN0YWJsZSA9IChpc19kYXlfc2VsZWN0YWJsZSkgPyB0cnVlIDogaXNfc2V0X3BlbmRpbmdfZGF5c19zZWxlY3RhYmxlO1xyXG5cdFx0XHR9XHJcblx0XHRcdGlmICggd3BiY19ib29raW5nX3N0YXR1c2VzX19oYXMoIGJvb2tpbmdfc3RhdHVzZXNfYXJyLCAnYXBwcm92ZWRfYXBwcm92ZWQnICkgKXtcclxuXHRcdFx0XHRjc3NfY2xhc3Nlc19fZm9yX2RhdGUucHVzaCggJ2NoZWNrX291dF90aW1lX2RhdGVfYXBwcm92ZWQnLCAnY2hlY2tfaW5fdGltZV9kYXRlX2FwcHJvdmVkJyApO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIFsgaXNfZGF5X3NlbGVjdGFibGUsIGNzc19jbGFzc2VzX19mb3JfZGF0ZS5qb2luKCAnICcgKSBdO1xyXG5cdH1cclxuXHJcblxyXG5cdC8qKlxyXG5cdCAqIE1vdXNlb3ZlciBjYWxlbmRhciBkYXRlIGNlbGxzXHJcblx0ICpcclxuXHQgKiBAcGFyYW0gc3RyaW5nX2RhdGVcclxuXHQgKiBAcGFyYW0gZGF0ZVx0XHRcdFx0XHRcdFx0XHRcdFx0LSAgSmF2YVNjcmlwdCBEYXRlIE9iajogIFx0XHRNb24gRGVjIDExIDIwMjMgMDA6MDA6MDBcclxuXHQgKiAgICAgR01UKzAyMDAgKEVhc3Rlcm4gRXVyb3BlYW4gU3RhbmRhcmQgVGltZSlcclxuXHQgKiBAcGFyYW0gY2FsZW5kYXJfcGFyYW1zX2Fyclx0XHRcdFx0XHRcdC0gIENhbGVuZGFyIFNldHRpbmdzIE9iamVjdDogIFx0e1xyXG5cdCAqXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQgIFx0XHRcdFx0XHRcdFwicmVzb3VyY2VfaWRcIjogNFxyXG5cdCAqXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0fVxyXG5cdCAqIEBwYXJhbSBkYXRlcGlja190aGlzXHRcdFx0XHRcdFx0XHRcdC0gdGhpcyBvZiBkYXRlcGljayBPYmpcclxuXHQgKiBAcmV0dXJucyB7Ym9vbGVhbn1cclxuXHQgKi9cclxuXHRmdW5jdGlvbiB3cGJjX19jYWxlbmRhcl9fb25faG92ZXJfZGF5cyggc3RyaW5nX2RhdGUsIGRhdGUsIGNhbGVuZGFyX3BhcmFtc19hcnIsIGRhdGVwaWNrX3RoaXMgKSB7XHJcblxyXG5cdFx0aWYgKCBudWxsID09PSBkYXRlICkge1xyXG5cdFx0XHR3cGJjX2NhbGVuZGFyc19fY2xlYXJfZGF5c19oaWdobGlnaHRpbmcoICgndW5kZWZpbmVkJyAhPT0gdHlwZW9mIChjYWxlbmRhcl9wYXJhbXNfYXJyWyAncmVzb3VyY2VfaWQnIF0pKSA/IGNhbGVuZGFyX3BhcmFtc19hcnJbICdyZXNvdXJjZV9pZCcgXSA6ICcxJyApO1x0XHQvLyBGaXhJbjogMTAuNS4yLjQuXHJcblx0XHRcdHJldHVybiBmYWxzZTtcclxuXHRcdH1cclxuXHJcblx0XHR2YXIgY2xhc3NfZGF5ICAgICA9IHdwYmNfX2dldF9fdGRfY2xhc3NfZGF0ZSggZGF0ZSApO1x0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vICcxLTktMjAyMydcclxuXHRcdHZhciBzcWxfY2xhc3NfZGF5ID0gd3BiY19fZ2V0X19zcWxfY2xhc3NfZGF0ZSggZGF0ZSApO1x0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vICcyMDIzLTAxLTA5J1xyXG5cdFx0dmFyIHJlc291cmNlX2lkID0gKCAndW5kZWZpbmVkJyAhPT0gdHlwZW9mKGNhbGVuZGFyX3BhcmFtc19hcnJbICdyZXNvdXJjZV9pZCcgXSkgKSA/IGNhbGVuZGFyX3BhcmFtc19hcnJbICdyZXNvdXJjZV9pZCcgXSA6ICcxJztcdFx0Ly8gJzEnXHJcblxyXG5cdFx0Ly8gR2V0IERhdGEgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdHZhciBkYXRlX2Jvb2tpbmdfb2JqID0gX3dwYmMuYm9va2luZ3NfaW5fY2FsZW5kYXJfX2dldF9mb3JfZGF0ZSggcmVzb3VyY2VfaWQsIHNxbF9jbGFzc19kYXkgKTtcdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gey4uLn1cclxuXHJcblx0XHRpZiAoICEgZGF0ZV9ib29raW5nX29iaiApeyByZXR1cm4gZmFsc2U7IH1cclxuXHJcblxyXG5cdFx0Ly8gVCBvIG8gbCB0IGkgcCBzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdHZhciB0b29sdGlwX3RleHQgPSAnJztcclxuXHRcdGlmICggZGF0ZV9ib29raW5nX29ialsgJ3N1bW1hcnknXVsndG9vbHRpcF9hdmFpbGFiaWxpdHknIF0ubGVuZ3RoID4gMCApe1xyXG5cdFx0XHR0b29sdGlwX3RleHQgKz0gIGRhdGVfYm9va2luZ19vYmpbICdzdW1tYXJ5J11bJ3Rvb2x0aXBfYXZhaWxhYmlsaXR5JyBdO1xyXG5cdFx0fVxyXG5cdFx0aWYgKCBkYXRlX2Jvb2tpbmdfb2JqWyAnc3VtbWFyeSddWyd0b29sdGlwX2RheV9jb3N0JyBdLmxlbmd0aCA+IDAgKXtcclxuXHRcdFx0dG9vbHRpcF90ZXh0ICs9ICBkYXRlX2Jvb2tpbmdfb2JqWyAnc3VtbWFyeSddWyd0b29sdGlwX2RheV9jb3N0JyBdO1xyXG5cdFx0fVxyXG5cdFx0aWYgKCBkYXRlX2Jvb2tpbmdfb2JqWyAnc3VtbWFyeSddWyd0b29sdGlwX3RpbWVzJyBdLmxlbmd0aCA+IDAgKXtcclxuXHRcdFx0dG9vbHRpcF90ZXh0ICs9ICBkYXRlX2Jvb2tpbmdfb2JqWyAnc3VtbWFyeSddWyd0b29sdGlwX3RpbWVzJyBdO1xyXG5cdFx0fVxyXG5cdFx0aWYgKCBkYXRlX2Jvb2tpbmdfb2JqWyAnc3VtbWFyeSddWyd0b29sdGlwX2Jvb2tpbmdfZGV0YWlscycgXS5sZW5ndGggPiAwICl7XHJcblx0XHRcdHRvb2x0aXBfdGV4dCArPSAgZGF0ZV9ib29raW5nX29ialsgJ3N1bW1hcnknXVsndG9vbHRpcF9ib29raW5nX2RldGFpbHMnIF07XHJcblx0XHR9XHJcblx0XHR3cGJjX3NldF90b29sdGlwX19fZm9yX19jYWxlbmRhcl9kYXRlKCB0b29sdGlwX3RleHQsIHJlc291cmNlX2lkLCBjbGFzc19kYXkgKTtcclxuXHJcblxyXG5cclxuXHRcdC8vICBVIG4gaCBvIHYgZSByIGkgbiBnICAgIGluICAgIFVOU0VMRUNUQUJMRV9DQUxFTkRBUiAgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHR2YXIgaXNfdW5zZWxlY3RhYmxlX2NhbGVuZGFyID0gKCBqUXVlcnkoICcjY2FsZW5kYXJfYm9va2luZ191bnNlbGVjdGFibGUnICsgcmVzb3VyY2VfaWQgKS5sZW5ndGggPiAwKTtcdFx0XHRcdC8vIEZpeEluOiA4LjAuMS4yLlxyXG5cdFx0dmFyIGlzX2Jvb2tpbmdfZm9ybV9leGlzdCAgICA9ICggalF1ZXJ5KCAnI2Jvb2tpbmdfZm9ybV9kaXYnICsgcmVzb3VyY2VfaWQgKS5sZW5ndGggPiAwICk7XHJcblx0XHR2YXIgaXNfYWRkX2Jvb2tpbmdfbW9kYWxfY2FsZW5kYXIgPSAoIGpRdWVyeSggJyNjYWxlbmRhcl9ib29raW5nJyArIHJlc291cmNlX2lkICkuY2xvc2VzdCggJyN3cGJjX21vZGFsX19hZGRfYm9va2luZ19fc2VjdGlvbicgKS5sZW5ndGggPiAwICk7XHJcblxyXG5cdFx0aWYgKCAoIGlzX3Vuc2VsZWN0YWJsZV9jYWxlbmRhciApICYmICggISBpc19ib29raW5nX2Zvcm1fZXhpc3QgKSApe1xyXG5cclxuXHRcdFx0LyoqXHJcblx0XHRcdCAqICBVbiBIb3ZlciBhbGwgZGF0ZXMgaW4gY2FsZW5kYXIgKHdpdGhvdXQgdGhlIGJvb2tpbmcgZm9ybSksIGlmIG9ubHkgQXZhaWxhYmlsaXR5IENhbGVuZGFyIGhlcmUgYW5kIHdlIGRvXHJcblx0XHRcdCAqIG5vdCBpbnNlcnQgQm9va2luZyBmb3JtIGJ5IG1pc3Rha2UuXHJcblx0XHRcdCAqL1xyXG5cclxuXHRcdFx0d3BiY19jYWxlbmRhcnNfX2NsZWFyX2RheXNfaGlnaGxpZ2h0aW5nKCByZXNvdXJjZV9pZCApOyBcdFx0XHRcdFx0XHRcdC8vIENsZWFyIGRheXMgaGlnaGxpZ2h0aW5nXHJcblxyXG5cdFx0XHR2YXIgY3NzX29mX2NhbGVuZGFyID0gJy53cGJjX29ubHlfY2FsZW5kYXIgI2NhbGVuZGFyX2Jvb2tpbmcnICsgcmVzb3VyY2VfaWQ7XHJcblx0XHRcdGpRdWVyeSggY3NzX29mX2NhbGVuZGFyICsgJyAuZGF0ZXBpY2stZGF5cy1jZWxsLCAnXHJcblx0XHRcdFx0ICArIGNzc19vZl9jYWxlbmRhciArICcgLmRhdGVwaWNrLWRheXMtY2VsbCBhJyApLmNzcyggJ2N1cnNvcicsICdkZWZhdWx0JyApO1x0Ly8gU2V0IGN1cnNvciB0byBEZWZhdWx0XHJcblx0XHRcdHJldHVybiBmYWxzZTtcclxuXHRcdH1cclxuXHJcblxyXG5cclxuXHRcdC8vICBEIGEgeSBzICAgIEggbyB2IGUgciBpIG4gZyAgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHRpZiAoXHJcblx0XHRcdCAgICggbG9jYXRpb24uaHJlZi5pbmRleE9mKCAncGFnZT13cGJjJyApID09IC0xIClcclxuXHRcdFx0fHwgKCAoIGxvY2F0aW9uLmhyZWYuaW5kZXhPZiggJ3BhZ2U9d3BiYycgKSA+IDAgKSAmJiAoIGxvY2F0aW9uLmhyZWYuaW5kZXhPZiggJ3RhYj1hZGQtYm9va2luZycgKSA+IDAgKSApXHJcblx0XHRcdHx8ICggaXNfYWRkX2Jvb2tpbmdfbW9kYWxfY2FsZW5kYXIgKVxyXG5cdFx0XHR8fCAoIGxvY2F0aW9uLmhyZWYuaW5kZXhPZiggJ3BhZ2U9d3BiYy1zZXR1cCcgKSA+IDAgKVxyXG5cdFx0XHR8fCAoIGxvY2F0aW9uLmhyZWYuaW5kZXhPZiggJ3BhZ2U9d3BiYy1hdmFpbGFiaWxpdHknICkgPiAwIClcclxuXHRcdFx0fHwgKCAgKCBsb2NhdGlvbi5ocmVmLmluZGV4T2YoICdwYWdlPXdwYmMtc2V0dGluZ3MnICkgPiAwICkgICYmXHJcblx0XHRcdFx0ICAoIGxvY2F0aW9uLmhyZWYuaW5kZXhPZiggJyZ0YWI9Zm9ybScgKSA+IDAgKVxyXG5cdFx0XHQgICApXHJcblx0XHQpe1xyXG5cdFx0XHQvLyBUaGUgc2FtZSBhcyBkYXRlcyBzZWxlY3Rpb24sICBidXQgZm9yIGRheXMgaG92ZXJpbmdcclxuXHJcblx0XHRcdGlmICggJ2Z1bmN0aW9uJyA9PSB0eXBlb2YoIHdwYmNfX2NhbGVuZGFyX19kb19kYXlzX2hpZ2hsaWdodF9fYnMgKSApe1xyXG5cdFx0XHRcdHdwYmNfX2NhbGVuZGFyX19kb19kYXlzX2hpZ2hsaWdodF9fYnMoIHNxbF9jbGFzc19kYXksIGRhdGUsIHJlc291cmNlX2lkICk7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0fVxyXG5cclxuXHJcblx0LyoqXHJcblx0ICogU2VsZWN0IGNhbGVuZGFyIGRhdGUgY2VsbHNcclxuXHQgKlxyXG5cdCAqIEBwYXJhbSBkYXRlXHRcdFx0XHRcdFx0XHRcdFx0XHQtICBKYXZhU2NyaXB0IERhdGUgT2JqOiAgXHRcdE1vbiBEZWMgMTEgMjAyMyAwMDowMDowMFxyXG5cdCAqICAgICBHTVQrMDIwMCAoRWFzdGVybiBFdXJvcGVhbiBTdGFuZGFyZCBUaW1lKVxyXG5cdCAqIEBwYXJhbSBjYWxlbmRhcl9wYXJhbXNfYXJyXHRcdFx0XHRcdFx0LSAgQ2FsZW5kYXIgU2V0dGluZ3MgT2JqZWN0OiAgXHR7XHJcblx0ICpcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCAgXHRcdFx0XHRcdFx0XCJyZXNvdXJjZV9pZFwiOiA0XHJcblx0ICpcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHR9XHJcblx0ICogQHBhcmFtIGRhdGVwaWNrX3RoaXNcdFx0XHRcdFx0XHRcdFx0LSB0aGlzIG9mIGRhdGVwaWNrIE9ialxyXG5cdCAqXHJcblx0ICovXHJcblx0ZnVuY3Rpb24gd3BiY19fY2FsZW5kYXJfX29uX3NlbGVjdF9kYXlzKCBkYXRlLCBjYWxlbmRhcl9wYXJhbXNfYXJyLCBkYXRlcGlja190aGlzICl7XHJcblxyXG5cdFx0dmFyIHJlc291cmNlX2lkID0gKCAndW5kZWZpbmVkJyAhPT0gdHlwZW9mKGNhbGVuZGFyX3BhcmFtc19hcnJbICdyZXNvdXJjZV9pZCcgXSkgKSA/IGNhbGVuZGFyX3BhcmFtc19hcnJbICdyZXNvdXJjZV9pZCcgXSA6ICcxJztcdFx0Ly8gJzEnXHJcblxyXG5cdFx0Ly8gU2V0IHVuc2VsZWN0YWJsZSwgIGlmIG9ubHkgQXZhaWxhYmlsaXR5IENhbGVuZGFyICBoZXJlIChhbmQgd2UgZG8gbm90IGluc2VydCBCb29raW5nIGZvcm0gYnkgbWlzdGFrZSkuXHJcblx0XHR2YXIgaXNfdW5zZWxlY3RhYmxlX2NhbGVuZGFyID0gKCBqUXVlcnkoICcjY2FsZW5kYXJfYm9va2luZ191bnNlbGVjdGFibGUnICsgcmVzb3VyY2VfaWQgKS5sZW5ndGggPiAwKTtcdFx0XHRcdC8vIEZpeEluOiA4LjAuMS4yLlxyXG5cdFx0dmFyIGlzX2Jvb2tpbmdfZm9ybV9leGlzdCAgICA9ICggalF1ZXJ5KCAnI2Jvb2tpbmdfZm9ybV9kaXYnICsgcmVzb3VyY2VfaWQgKS5sZW5ndGggPiAwICk7XHJcblx0XHRpZiAoICggaXNfdW5zZWxlY3RhYmxlX2NhbGVuZGFyICkgJiYgKCAhIGlzX2Jvb2tpbmdfZm9ybV9leGlzdCApICl7XHJcblx0XHRcdHdwYmNfY2FsZW5kYXJfX3Vuc2VsZWN0X2FsbF9kYXRlcyggcmVzb3VyY2VfaWQgKTtcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vIFVuc2VsZWN0IERhdGVzXHJcblx0XHRcdGpRdWVyeSgnLndwYmNfb25seV9jYWxlbmRhciAucG9wb3Zlcl9jYWxlbmRhcl9ob3ZlcicpLnJlbW92ZSgpOyAgICAgICAgICAgICAgICAgICAgICBcdFx0XHRcdFx0XHRcdC8vIEhpZGUgYWxsIG9wZW5lZCBwb3BvdmVyc1xyXG5cdFx0XHRyZXR1cm4gZmFsc2U7XHJcblx0XHR9XHJcblxyXG5cdFx0alF1ZXJ5KCAnI2RhdGVfYm9va2luZycgKyByZXNvdXJjZV9pZCApLnZhbCggZGF0ZSApO1x0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gQWRkIHNlbGVjdGVkIGRhdGVzIHRvICBoaWRkZW4gdGV4dGFyZWFcclxuXHJcblxyXG5cdFx0aWYgKCAnZnVuY3Rpb24nID09PSB0eXBlb2YgKHdwYmNfX2NhbGVuZGFyX19kb19kYXlzX3NlbGVjdF9fYnMpICl7IHdwYmNfX2NhbGVuZGFyX19kb19kYXlzX3NlbGVjdF9fYnMoIGRhdGUsIHJlc291cmNlX2lkICk7IH1cclxuXHJcblx0XHR3cGJjX2Rpc2FibGVfdGltZV9maWVsZHNfaW5fYm9va2luZ19mb3JtKCByZXNvdXJjZV9pZCApO1xyXG5cclxuXHRcdC8vIEhvb2sgLS0gdHJpZ2dlciBkYXkgc2VsZWN0aW9uIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHR2YXIgbW91c2VfY2xpY2tlZF9kYXRlcyA9IGRhdGU7XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQvLyBDYW4gYmU6IFwiMDUuMTAuMjAyMyAtIDA3LjEwLjIwMjNcIiAgfCAgXCIxMC4xMC4yMDIzIC0gMTAuMTAuMjAyM1wiICB8XHJcblx0XHR2YXIgYWxsX3NlbGVjdGVkX2RhdGVzX2FyciA9IHdwYmNfZ2V0X19zZWxlY3RlZF9kYXRlc19zcWxfX2FzX2FyciggcmVzb3VyY2VfaWQgKTtcdFx0XHRcdFx0XHRcdFx0XHQvLyBDYW4gYmU6IFsgXCIyMDIzLTEwLTA1XCIsIFwiMjAyMy0xMC0wNlwiLCBcIjIwMjMtMTAtMDdcIiwg4oCmIF1cclxuXHRcdGpRdWVyeSggXCIuYm9va2luZ19mb3JtX2RpdlwiICkudHJpZ2dlciggXCJkYXRlX3NlbGVjdGVkXCIsIFsgcmVzb3VyY2VfaWQsIG1vdXNlX2NsaWNrZWRfZGF0ZXMsIGFsbF9zZWxlY3RlZF9kYXRlc19hcnIgXSApO1xyXG5cdH1cclxuXHJcblx0Ly8gTWFyayBtaWRkbGUgc2VsZWN0ZWQgZGF0ZXMgd2l0aCAwLjUgb3BhY2l0eVx0XHQvLyBGaXhJbjogMTAuMy4wLjkuXHJcblx0alF1ZXJ5KCBkb2N1bWVudCApLnJlYWR5KCBmdW5jdGlvbiAoKXtcclxuXHRcdGpRdWVyeSggXCIuYm9va2luZ19mb3JtX2RpdlwiICkub24oICdkYXRlX3NlbGVjdGVkJywgZnVuY3Rpb24gKCBldmVudCwgcmVzb3VyY2VfaWQsIGRhdGUgKXtcclxuXHRcdFx0XHRpZiAoXHJcblx0XHRcdFx0XHQgICAoICAnZml4ZWQnID09PSBfd3BiYy5jYWxlbmRhcl9fZ2V0X3BhcmFtX3ZhbHVlKCByZXNvdXJjZV9pZCwgJ2RheXNfc2VsZWN0X21vZGUnICkpXHJcblx0XHRcdFx0XHR8fCAoJ2R5bmFtaWMnID09PSBfd3BiYy5jYWxlbmRhcl9fZ2V0X3BhcmFtX3ZhbHVlKCByZXNvdXJjZV9pZCwgJ2RheXNfc2VsZWN0X21vZGUnICkpXHJcblx0XHRcdFx0KXtcclxuXHRcdFx0XHRcdHZhciBjbG9zZWRfdGltZXIgPSBzZXRUaW1lb3V0KCBmdW5jdGlvbiAoKXtcclxuXHRcdFx0XHRcdFx0dmFyIG1pZGRsZV9kYXlzX29wYWNpdHkgPSBfd3BiYy5nZXRfb3RoZXJfcGFyYW0oICdjYWxlbmRhcnNfX2RheXNfc2VsZWN0aW9uX19taWRkbGVfZGF5c19vcGFjaXR5JyApO1xyXG5cdFx0XHRcdFx0XHRqUXVlcnkoICcjY2FsZW5kYXJfYm9va2luZycgKyByZXNvdXJjZV9pZCArICcgLmRhdGVwaWNrLWN1cnJlbnQtZGF5JyApLm5vdCggXCIuc2VsZWN0ZWRfY2hlY2tfaW5fb3V0XCIgKS5jc3MoICdvcGFjaXR5JywgbWlkZGxlX2RheXNfb3BhY2l0eSApO1xyXG5cdFx0XHRcdFx0fSwgMTAgKTtcclxuXHRcdFx0XHR9XHJcblx0XHR9ICk7XHJcblx0fSApO1xyXG5cclxuXHJcblx0LyoqXHJcblx0ICogLS0gIFQgaSBtIGUgICAgRiBpIGUgbCBkIHMgICAgIHN0YXJ0ICAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdCAqL1xyXG5cclxuXHQvKipcclxuXHQgKiBEaXNhYmxlIHRpbWUgc2xvdHMgaW4gYm9va2luZyBmb3JtIGRlcGVuZCBvbiBzZWxlY3RlZCBkYXRlcyBhbmQgYm9va2VkIGRhdGVzL3RpbWVzXHJcblx0ICpcclxuXHQgKiBAcGFyYW0gcmVzb3VyY2VfaWRcclxuXHQgKi9cclxuXHRmdW5jdGlvbiB3cGJjX2Rpc2FibGVfdGltZV9maWVsZHNfaW5fYm9va2luZ19mb3JtKCByZXNvdXJjZV9pZCApe1xyXG5cclxuXHRcdC8qKlxyXG5cdFx0ICogXHQxLiBHZXQgYWxsIHRpbWUgZmllbGRzIGluIHRoZSBib29raW5nIGZvcm0gYXMgYXJyYXkgIG9mIG9iamVjdHNcclxuXHRcdCAqIFx0XHRcdFx0XHRbXHJcblx0XHQgKiBcdFx0XHRcdFx0IFx0ICAge1x0anF1ZXJ5X29wdGlvbjogICAgICBqUXVlcnlfT2JqZWN0IHt9XHJcblx0XHQgKiBcdFx0XHRcdFx0XHRcdFx0bmFtZTogICAgICAgICAgICAgICAncmFuZ2V0aW1lMltdJ1xyXG5cdFx0ICogXHRcdFx0XHRcdFx0XHRcdHRpbWVzX2FzX3NlY29uZHM6ICAgWyAyMTYwMCwgMjM0MDAgXVxyXG5cdFx0ICogXHRcdFx0XHRcdFx0XHRcdHZhbHVlX29wdGlvbl8yNGg6ICAgJzA2OjAwIC0gMDY6MzAnXHJcblx0XHQgKiBcdFx0XHRcdFx0ICAgICB9XHJcblx0XHQgKiBcdFx0XHRcdFx0ICAuLi5cclxuXHRcdCAqIFx0XHRcdFx0XHRcdCAgIHtcdGpxdWVyeV9vcHRpb246ICAgICAgalF1ZXJ5X09iamVjdCB7fVxyXG5cdFx0ICogXHRcdFx0XHRcdFx0XHRcdG5hbWU6ICAgICAgICAgICAgICAgJ3N0YXJ0dGltZTJbXSdcclxuXHRcdCAqIFx0XHRcdFx0XHRcdFx0XHR0aW1lc19hc19zZWNvbmRzOiAgIFsgMjE2MDAgXVxyXG5cdFx0ICogXHRcdFx0XHRcdFx0XHRcdHZhbHVlX29wdGlvbl8yNGg6ICAgJzA2OjAwJ1xyXG5cdFx0ICogIFx0XHRcdFx0XHQgICAgfVxyXG5cdFx0ICogXHRcdFx0XHRcdCBdXHJcblx0XHQgKi9cclxuXHRcdHZhciB0aW1lX2ZpZWxkc19vYmpfYXJyID0gd3BiY19nZXRfX3RpbWVfZmllbGRzX19pbl9ib29raW5nX2Zvcm1fX2FzX2FyciggcmVzb3VyY2VfaWQgKTtcclxuXHJcblx0XHQvLyAyLiBHZXQgYWxsIHNlbGVjdGVkIGRhdGVzIGluICBTUUwgZm9ybWF0ICBsaWtlIHRoaXMgWyBcIjIwMjMtMDgtMjNcIiwgXCIyMDIzLTA4LTI0XCIsIFwiMjAyMy0wOC0yNVwiLCAuLi4gXVxyXG5cdFx0dmFyIHNlbGVjdGVkX2RhdGVzX2FyciA9IHdwYmNfZ2V0X19zZWxlY3RlZF9kYXRlc19zcWxfX2FzX2FyciggcmVzb3VyY2VfaWQgKTtcclxuXHJcblx0XHQvLyAzLiBHZXQgY2hpbGQgYm9va2luZyByZXNvdXJjZXMgIG9yIHNpbmdsZSBib29raW5nIHJlc291cmNlICB0aGF0ICBleGlzdCAgaW4gZGF0ZXNcclxuXHRcdHZhciBjaGlsZF9yZXNvdXJjZXNfYXJyID0gd3BiY19jbG9uZV9vYmooIF93cGJjLmJvb2tpbmdfX2dldF9wYXJhbV92YWx1ZSggcmVzb3VyY2VfaWQsICdyZXNvdXJjZXNfaWRfYXJyX19pbl9kYXRlcycgKSApO1xyXG5cclxuXHRcdHZhciBzcWxfZGF0ZTtcclxuXHRcdHZhciBjaGlsZF9yZXNvdXJjZV9pZDtcclxuXHRcdHZhciBtZXJnZWRfc2Vjb25kcztcclxuXHRcdHZhciB0aW1lX2ZpZWxkc19vYmo7XHJcblx0XHR2YXIgaXNfaW50ZXJzZWN0O1xyXG5cdFx0dmFyIGlzX2NoZWNrX2luO1xyXG5cclxuXHRcdHZhciB0b2RheV90aW1lX19yZWFsICA9IG5ldyBEYXRlKCBfd3BiYy5nZXRfb3RoZXJfcGFyYW0oICd0aW1lX2xvY2FsX2FycicgKVswXSwgKCBwYXJzZUludCggX3dwYmMuZ2V0X290aGVyX3BhcmFtKCAndGltZV9sb2NhbF9hcnInIClbMV0gKSAtIDEpLCBfd3BiYy5nZXRfb3RoZXJfcGFyYW0oICd0aW1lX2xvY2FsX2FycicgKVsyXSwgX3dwYmMuZ2V0X290aGVyX3BhcmFtKCAndGltZV9sb2NhbF9hcnInIClbM10sIF93cGJjLmdldF9vdGhlcl9wYXJhbSggJ3RpbWVfbG9jYWxfYXJyJyApWzRdLCAwICk7XHJcblx0XHR2YXIgdG9kYXlfdGltZV9fc2hpZnQgPSBuZXcgRGF0ZSggX3dwYmMuZ2V0X290aGVyX3BhcmFtKCAndG9kYXlfYXJyJyAgICAgIClbMF0sICggcGFyc2VJbnQoIF93cGJjLmdldF9vdGhlcl9wYXJhbSggICAgICAndG9kYXlfYXJyJyApWzFdICkgLSAxKSwgX3dwYmMuZ2V0X290aGVyX3BhcmFtKCAndG9kYXlfYXJyJyAgICAgIClbMl0sIF93cGJjLmdldF9vdGhlcl9wYXJhbSggJ3RvZGF5X2FycicgICAgICApWzNdLCBfd3BiYy5nZXRfb3RoZXJfcGFyYW0oICd0b2RheV9hcnInICAgICAgKVs0XSwgMCApO1xyXG5cclxuXHRcdC8vIDQuIExvb3AgIGFsbCAgdGltZSBGaWVsZHMgb3B0aW9uc1x0XHQvLyBGaXhJbjogMTAuMy4wLjIuXHJcblx0XHRmb3IgKCBsZXQgZmllbGRfa2V5ID0gMDsgZmllbGRfa2V5IDwgdGltZV9maWVsZHNfb2JqX2Fyci5sZW5ndGg7IGZpZWxkX2tleSsrICl7XHJcblxyXG5cdFx0XHR0aW1lX2ZpZWxkc19vYmpfYXJyWyBmaWVsZF9rZXkgXS5kaXNhYmxlZCA9IDA7ICAgICAgICAgIC8vIEJ5IGRlZmF1bHQsIHRoaXMgdGltZSBmaWVsZCBpcyBub3QgZGlzYWJsZWQuXHJcblxyXG5cdFx0XHR0aW1lX2ZpZWxkc19vYmogPSB0aW1lX2ZpZWxkc19vYmpfYXJyWyBmaWVsZF9rZXkgXTtcdFx0Ly8geyB0aW1lc19hc19zZWNvbmRzOiBbIDIxNjAwLCAyMzQwMCBdLCB2YWx1ZV9vcHRpb25fMjRoOiAnMDY6MDAgLSAwNjozMCcsIG5hbWU6ICdyYW5nZXRpbWUyW10nLCBqcXVlcnlfb3B0aW9uOiBqUXVlcnlfT2JqZWN0IHt9fVxyXG5cclxuXHRcdFx0Ly8gTG9vcCAgYWxsICBzZWxlY3RlZCBkYXRlcy5cclxuXHRcdFx0Zm9yICggdmFyIGkgPSAwOyBpIDwgc2VsZWN0ZWRfZGF0ZXNfYXJyLmxlbmd0aDsgaSsrICkge1xyXG5cclxuXHRcdFx0XHQvLyBHZXQgRGF0ZTogJzIwMjMtMDgtMTgnLlxyXG5cdFx0XHRcdHNxbF9kYXRlID0gc2VsZWN0ZWRfZGF0ZXNfYXJyW2ldO1xyXG5cclxuXHRcdFx0XHR2YXIgaXNfdGltZV9pbl9wYXN0ID0gd3BiY19jaGVja19pc190aW1lX2luX3Bhc3QoIHRvZGF5X3RpbWVfX3NoaWZ0LCBzcWxfZGF0ZSwgdGltZV9maWVsZHNfb2JqICk7XHJcblx0XHRcdFx0Ly8gRXhjZXB0aW9uICBmb3IgJ0VuZCBUaW1lJyBmaWVsZCwgIHdoZW4gIHNlbGVjdGVkIHNldmVyYWwgZGF0ZXMuIC8vIEZpeEluOiAxMC4xNC4xLjUuXHJcblx0XHRcdFx0aWYgKCAoJ09uJyAhPT0gX3dwYmMuY2FsZW5kYXJfX2dldF9wYXJhbV92YWx1ZSggcmVzb3VyY2VfaWQsICdib29raW5nX3JlY3VycmVudF90aW1lJyApKSAmJlxyXG5cdFx0XHRcdFx0KC0xICE9PSB0aW1lX2ZpZWxkc19vYmoubmFtZS5pbmRleE9mKCAnZW5kdGltZScgKSkgJiZcclxuXHRcdFx0XHRcdChzZWxlY3RlZF9kYXRlc19hcnIubGVuZ3RoID4gMSlcclxuXHRcdFx0XHQpIHtcclxuXHRcdFx0XHRcdGlzX3RpbWVfaW5fcGFzdCA9IHdwYmNfY2hlY2tfaXNfdGltZV9pbl9wYXN0KCB0b2RheV90aW1lX19zaGlmdCwgc2VsZWN0ZWRfZGF0ZXNfYXJyWyhzZWxlY3RlZF9kYXRlc19hcnIubGVuZ3RoIC0gMSldLCB0aW1lX2ZpZWxkc19vYmogKTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdFx0aWYgKCBpc190aW1lX2luX3Bhc3QgKSB7XHJcblx0XHRcdFx0XHQvLyBUaGlzIHRpbWUgZm9yIHNlbGVjdGVkIGRhdGUgYWxyZWFkeSAgaW4gdGhlIHBhc3QuXHJcblx0XHRcdFx0XHR0aW1lX2ZpZWxkc19vYmpfYXJyW2ZpZWxkX2tleV0uZGlzYWJsZWQgPSAxO1xyXG5cdFx0XHRcdFx0YnJlYWs7XHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vIGV4aXN0ICBmcm9tICAgRGF0ZXMgTE9PUC5cclxuXHRcdFx0XHR9XHJcblx0XHRcdFx0Ly8gRml4SW46IDkuOS4wLjMxLlxyXG5cdFx0XHRcdGlmIChcclxuXHRcdFx0XHRcdCAgICggJ09mZicgPT09IF93cGJjLmNhbGVuZGFyX19nZXRfcGFyYW1fdmFsdWUoIHJlc291cmNlX2lkLCAnYm9va2luZ19yZWN1cnJlbnRfdGltZScgKSApXHJcblx0XHRcdFx0XHQmJiAoIHNlbGVjdGVkX2RhdGVzX2Fyci5sZW5ndGg+MSApXHJcblx0XHRcdFx0KXtcclxuXHRcdFx0XHRcdC8vVE9ETzogc2tpcCBzb21lIGZpZWxkcyBjaGVja2luZyBpZiBpdCdzIHN0YXJ0IC8gZW5kIHRpbWUgZm9yIG11bHBsZSBkYXRlcyAgc2VsZWN0aW9uICBtb2RlLlxyXG5cdFx0XHRcdFx0Ly9UT0RPOiB3ZSBuZWVkIHRvIGZpeCBzaXR1YXRpb24gIGZvciBlbnRpbWVzLCAgd2hlbiAgdXNlciAgc2VsZWN0ICBzZXZlcmFsICBkYXRlcywgIGFuZCBpbiBzdGFydCAgdGltZSBib29rZWQgMDA6MDAgLSAxNTowMCAsIGJ1dCBzeXN0c21lIGJsb2NrIHVudGlsbCAxNTowMCB0aGUgZW5kIHRpbWUgYXMgd2VsbCwgIHdoaWNoICBpcyB3cm9uZywgIGJlY2F1c2UgaXQgMiBvciAzIGRhdGVzIHNlbGVjdGlvbiAgYW5kIGVuZCBkYXRlIGNhbiBiZSBmdWxsdSAgYXZhaWxhYmxlXHJcblxyXG5cdFx0XHRcdFx0aWYgKCAoMCA9PSBpKSAmJiAodGltZV9maWVsZHNfb2JqWyAnbmFtZScgXS5pbmRleE9mKCAnZW5kdGltZScgKSA+PSAwKSApe1xyXG5cdFx0XHRcdFx0XHRicmVhaztcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdGlmICggKCAoc2VsZWN0ZWRfZGF0ZXNfYXJyLmxlbmd0aC0xKSA9PSBpICkgJiYgKHRpbWVfZmllbGRzX29ialsgJ25hbWUnIF0uaW5kZXhPZiggJ3N0YXJ0dGltZScgKSA+PSAwKSApe1xyXG5cdFx0XHRcdFx0XHRicmVhaztcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9XHJcblxyXG5cclxuXHJcblx0XHRcdFx0dmFyIGhvd19tYW55X3Jlc291cmNlc19pbnRlcnNlY3RlZCA9IDA7XHJcblx0XHRcdFx0Ly8gTG9vcCBhbGwgcmVzb3VyY2VzIElEXHJcblx0XHRcdFx0XHQvLyBmb3IgKCB2YXIgcmVzX2tleSBpbiBjaGlsZF9yZXNvdXJjZXNfYXJyICl7XHQgXHRcdFx0XHRcdFx0Ly8gRml4SW46IDEwLjMuMC4yLlxyXG5cdFx0XHRcdGlmICggbnVsbCA9PT0gY2hpbGRfcmVzb3VyY2VzX2FyciApIHtcclxuXHRcdFx0XHRcdGNoaWxkX3Jlc291cmNlc19hcnIgPSBbXTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdFx0Zm9yICggbGV0IHJlc19rZXkgPSAwOyByZXNfa2V5IDwgY2hpbGRfcmVzb3VyY2VzX2Fyci5sZW5ndGg7IHJlc19rZXkrKyApe1xyXG5cclxuXHRcdFx0XHRcdGNoaWxkX3Jlc291cmNlX2lkID0gY2hpbGRfcmVzb3VyY2VzX2FyclsgcmVzX2tleSBdO1xyXG5cclxuXHRcdFx0XHRcdC8vIF93cGJjLmJvb2tpbmdzX2luX2NhbGVuZGFyX19nZXRfZm9yX2RhdGUoMiwnMjAyMy0wOC0yMScpWzEyXS5ib29rZWRfdGltZV9zbG90cy5tZXJnZWRfc2Vjb25kc1x0XHQ9IFsgXCIwNzowMDoxMSAtIDA3OjMwOjAyXCIsIFwiMTA6MDA6MTEgLSAwMDowMDowMFwiIF1cclxuXHRcdFx0XHRcdC8vIF93cGJjLmJvb2tpbmdzX2luX2NhbGVuZGFyX19nZXRfZm9yX2RhdGUoMiwnMjAyMy0wOC0yMScpWzJdLmJvb2tlZF90aW1lX3Nsb3RzLm1lcmdlZF9zZWNvbmRzXHRcdFx0PSBbICBbIDI1MjExLCAyNzAwMiBdLCBbIDM2MDExLCA4NjQwMCBdICBdXHJcblxyXG5cdFx0XHRcdFx0aWYgKCBmYWxzZSAhPT0gX3dwYmMuYm9va2luZ3NfaW5fY2FsZW5kYXJfX2dldF9mb3JfZGF0ZSggcmVzb3VyY2VfaWQsIHNxbF9kYXRlICkgKXtcclxuXHRcdFx0XHRcdFx0bWVyZ2VkX3NlY29uZHMgPSBfd3BiYy5ib29raW5nc19pbl9jYWxlbmRhcl9fZ2V0X2Zvcl9kYXRlKCByZXNvdXJjZV9pZCwgc3FsX2RhdGUgKVsgY2hpbGRfcmVzb3VyY2VfaWQgXS5ib29rZWRfdGltZV9zbG90cy5tZXJnZWRfc2Vjb25kcztcdFx0Ly8gWyAgWyAyNTIxMSwgMjcwMDIgXSwgWyAzNjAxMSwgODY0MDAgXSAgXVxyXG5cdFx0XHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRcdFx0bWVyZ2VkX3NlY29uZHMgPSBbXTtcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdGlmICggdGltZV9maWVsZHNfb2JqLnRpbWVzX2FzX3NlY29uZHMubGVuZ3RoID4gMSApe1xyXG5cdFx0XHRcdFx0XHRpc19pbnRlcnNlY3QgPSB3cGJjX2lzX2ludGVyc2VjdF9fcmFuZ2VfdGltZV9pbnRlcnZhbCggIFtcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0W1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCggcGFyc2VJbnQoIHRpbWVfZmllbGRzX29iai50aW1lc19hc19zZWNvbmRzWzBdICkgKyAyMCApLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCggcGFyc2VJbnQoIHRpbWVfZmllbGRzX29iai50aW1lc19hc19zZWNvbmRzWzFdICkgLSAyMCApXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdF1cclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdF1cclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCwgbWVyZ2VkX3NlY29uZHMgKTtcclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblx0XHRcdFx0XHRcdGlzX2NoZWNrX2luID0gKC0xICE9PSB0aW1lX2ZpZWxkc19vYmoubmFtZS5pbmRleE9mKCAnc3RhcnQnICkpO1xyXG5cdFx0XHRcdFx0XHRpc19pbnRlcnNlY3QgPSB3cGJjX2lzX2ludGVyc2VjdF9fb25lX3RpbWVfaW50ZXJ2YWwoXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQoICggaXNfY2hlY2tfaW4gKVxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0ICA/IHBhcnNlSW50KCB0aW1lX2ZpZWxkc19vYmoudGltZXNfYXNfc2Vjb25kcyApICsgMjBcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCAgOiBwYXJzZUludCggdGltZV9maWVsZHNfb2JqLnRpbWVzX2FzX3NlY29uZHMgKSAtIDIwXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQpXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQsIG1lcmdlZF9zZWNvbmRzICk7XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHRpZiAoaXNfaW50ZXJzZWN0KXtcclxuXHRcdFx0XHRcdFx0aG93X21hbnlfcmVzb3VyY2VzX2ludGVyc2VjdGVkKys7XHRcdFx0Ly8gSW5jcmVhc2VcclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRpZiAoIGNoaWxkX3Jlc291cmNlc19hcnIubGVuZ3RoID09IGhvd19tYW55X3Jlc291cmNlc19pbnRlcnNlY3RlZCApIHtcclxuXHRcdFx0XHRcdC8vIEFsbCByZXNvdXJjZXMgaW50ZXJzZWN0ZWQsICB0aGVuICBpdCdzIG1lYW5zIHRoYXQgdGhpcyB0aW1lLXNsb3Qgb3IgdGltZSBtdXN0ICBiZSAgRGlzYWJsZWQsIGFuZCB3ZSBjYW4gIGV4aXN0ICBmcm9tICAgc2VsZWN0ZWRfZGF0ZXNfYXJyIExPT1BcclxuXHJcblx0XHRcdFx0XHR0aW1lX2ZpZWxkc19vYmpfYXJyWyBmaWVsZF9rZXkgXS5kaXNhYmxlZCA9IDE7XHJcblx0XHRcdFx0XHRicmVhaztcdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gZXhpc3QgIGZyb20gICBEYXRlcyBMT09QXHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cclxuXHRcdC8vIDUuIE5vdyB3ZSBjYW4gZGlzYWJsZSB0aW1lIHNsb3QgaW4gSFRNTCBieSAgdXNpbmcgICggZmllbGQuZGlzYWJsZWQgPT0gMSApIHByb3BlcnR5XHJcblx0XHR3cGJjX19odG1sX190aW1lX2ZpZWxkX29wdGlvbnNfX3NldF9kaXNhYmxlZCggdGltZV9maWVsZHNfb2JqX2FyciApO1xyXG5cclxuXHRcdGpRdWVyeSggXCIuYm9va2luZ19mb3JtX2RpdlwiICkudHJpZ2dlciggJ3dwYmNfaG9va190aW1lc2xvdHNfZGlzYWJsZWQnLCBbcmVzb3VyY2VfaWQsIHNlbGVjdGVkX2RhdGVzX2Fycl0gKTtcdFx0XHRcdFx0Ly8gVHJpZ2dlciBob29rIG9uIGRpc2FibGluZyB0aW1lc2xvdHMuXHRcdFVzYWdlOiBcdGpRdWVyeSggXCIuYm9va2luZ19mb3JtX2RpdlwiICkub24oICd3cGJjX2hvb2tfdGltZXNsb3RzX2Rpc2FibGVkJywgZnVuY3Rpb24gKCBldmVudCwgYmtfdHlwZSwgYWxsX2RhdGVzICl7IC4uLiB9ICk7XHRcdC8vIEZpeEluOiA4LjcuMTEuOS5cclxuXHR9XHJcblxyXG5cclxuXHRcdC8qKlxyXG5cdFx0ICogQ2hlY2sgaWYgc3BlY2lmaWMgdGltZSgtc2xvdCkgYWxyZWFkeSAgaW4gdGhlIHBhc3QgZm9yIHNlbGVjdGVkIGRhdGVcclxuXHRcdCAqXHJcblx0XHQgKiBAcGFyYW0ganNfY3VycmVudF90aW1lX3RvX2NoZWNrXHRcdC0gSlMgRGF0ZVxyXG5cdFx0ICogQHBhcmFtIHNxbF9kYXRlXHRcdFx0XHRcdFx0LSAnMjAyNS0wMS0yNidcclxuXHRcdCAqIEBwYXJhbSB0aW1lX2ZpZWxkc19vYmpcdFx0XHRcdC0gT2JqZWN0XHJcblx0XHQgKiBAcmV0dXJucyB7Ym9vbGVhbn1cclxuXHRcdCAqL1xyXG5cdFx0ZnVuY3Rpb24gd3BiY19jaGVja19pc190aW1lX2luX3Bhc3QoIGpzX2N1cnJlbnRfdGltZV90b19jaGVjaywgc3FsX2RhdGUsIHRpbWVfZmllbGRzX29iaiApIHtcclxuXHJcblx0XHRcdC8vIEZpeEluOiAxMC45LjYuNFxyXG5cdFx0XHR2YXIgc3FsX2RhdGVfYXJyID0gc3FsX2RhdGUuc3BsaXQoICctJyApO1xyXG5cdFx0XHR2YXIgc3FsX2RhdGVfX21pZG5pZ2h0ID0gbmV3IERhdGUoIHBhcnNlSW50KCBzcWxfZGF0ZV9hcnJbMF0gKSwgKCBwYXJzZUludCggc3FsX2RhdGVfYXJyWzFdICkgLSAxICksIHBhcnNlSW50KCBzcWxfZGF0ZV9hcnJbMl0gKSwgMCwgMCwgMCApO1xyXG5cdFx0XHR2YXIgc3FsX2RhdGVfX21pZG5pZ2h0X21pbGlzZWNvbmRzID0gc3FsX2RhdGVfX21pZG5pZ2h0LmdldFRpbWUoKTtcclxuXHJcblx0XHRcdHZhciBpc19pbnRlcnNlY3QgPSBmYWxzZTtcclxuXHJcblx0XHRcdGlmICggdGltZV9maWVsZHNfb2JqLnRpbWVzX2FzX3NlY29uZHMubGVuZ3RoID4gMSApIHtcclxuXHJcblx0XHRcdFx0aWYgKCBqc19jdXJyZW50X3RpbWVfdG9fY2hlY2suZ2V0VGltZSgpID4gKHNxbF9kYXRlX19taWRuaWdodF9taWxpc2Vjb25kcyArIChwYXJzZUludCggdGltZV9maWVsZHNfb2JqLnRpbWVzX2FzX3NlY29uZHNbMF0gKSArIDIwKSAqIDEwMDApICkge1xyXG5cdFx0XHRcdFx0aXNfaW50ZXJzZWN0ID0gdHJ1ZTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdFx0aWYgKCBqc19jdXJyZW50X3RpbWVfdG9fY2hlY2suZ2V0VGltZSgpID4gKHNxbF9kYXRlX19taWRuaWdodF9taWxpc2Vjb25kcyArIChwYXJzZUludCggdGltZV9maWVsZHNfb2JqLnRpbWVzX2FzX3NlY29uZHNbMV0gKSAtIDIwKSAqIDEwMDApICkge1xyXG5cdFx0XHRcdFx0aXNfaW50ZXJzZWN0ID0gdHJ1ZTtcclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdHZhciBpc19jaGVja19pbiA9ICgtMSAhPT0gdGltZV9maWVsZHNfb2JqLm5hbWUuaW5kZXhPZiggJ3N0YXJ0JyApKTtcclxuXHJcblx0XHRcdFx0dmFyIHRpbWVzX2FzX3NlY29uZHNfY2hlY2sgPSAoaXNfY2hlY2tfaW4pID8gcGFyc2VJbnQoIHRpbWVfZmllbGRzX29iai50aW1lc19hc19zZWNvbmRzICkgKyAyMCA6IHBhcnNlSW50KCB0aW1lX2ZpZWxkc19vYmoudGltZXNfYXNfc2Vjb25kcyApIC0gMjA7XHJcblxyXG5cdFx0XHRcdHRpbWVzX2FzX3NlY29uZHNfY2hlY2sgPSBzcWxfZGF0ZV9fbWlkbmlnaHRfbWlsaXNlY29uZHMgKyB0aW1lc19hc19zZWNvbmRzX2NoZWNrICogMTAwMDtcclxuXHJcblx0XHRcdFx0aWYgKCBqc19jdXJyZW50X3RpbWVfdG9fY2hlY2suZ2V0VGltZSgpID4gdGltZXNfYXNfc2Vjb25kc19jaGVjayApIHtcclxuXHRcdFx0XHRcdGlzX2ludGVyc2VjdCA9IHRydWU7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZXR1cm4gaXNfaW50ZXJzZWN0O1xyXG5cdFx0fVxyXG5cclxuXHRcdC8qKlxyXG5cdFx0ICogSXMgbnVtYmVyIGluc2lkZSAvaW50ZXJzZWN0ICBvZiBhcnJheSBvZiBpbnRlcnZhbHMgP1xyXG5cdFx0ICpcclxuXHRcdCAqIEBwYXJhbSB0aW1lX0FcdFx0ICAgICBcdC0gMjU4MDBcclxuXHRcdCAqIEBwYXJhbSB0aW1lX2ludGVydmFsX0JcdFx0LSBbICBbIDI1MjExLCAyNzAwMiBdLCBbIDM2MDExLCA4NjQwMCBdICBdXHJcblx0XHQgKiBAcmV0dXJucyB7Ym9vbGVhbn1cclxuXHRcdCAqL1xyXG5cdFx0ZnVuY3Rpb24gd3BiY19pc19pbnRlcnNlY3RfX29uZV90aW1lX2ludGVydmFsKCB0aW1lX0EsIHRpbWVfaW50ZXJ2YWxfQiApe1xyXG5cclxuXHRcdFx0Zm9yICggdmFyIGogPSAwOyBqIDwgdGltZV9pbnRlcnZhbF9CLmxlbmd0aDsgaisrICl7XHJcblxyXG5cdFx0XHRcdGlmICggKHBhcnNlSW50KCB0aW1lX0EgKSA+IHBhcnNlSW50KCB0aW1lX2ludGVydmFsX0JbIGogXVsgMCBdICkpICYmIChwYXJzZUludCggdGltZV9BICkgPCBwYXJzZUludCggdGltZV9pbnRlcnZhbF9CWyBqIF1bIDEgXSApKSApe1xyXG5cdFx0XHRcdFx0cmV0dXJuIHRydWVcclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdC8vIGlmICggKCBwYXJzZUludCggdGltZV9BICkgPT0gcGFyc2VJbnQoIHRpbWVfaW50ZXJ2YWxfQlsgaiBdWyAwIF0gKSApIHx8ICggcGFyc2VJbnQoIHRpbWVfQSApID09IHBhcnNlSW50KCB0aW1lX2ludGVydmFsX0JbIGogXVsgMSBdICkgKSApIHtcclxuXHRcdFx0XHQvLyBcdFx0XHQvLyBUaW1lIEEganVzdCAgYXQgIHRoZSBib3JkZXIgb2YgaW50ZXJ2YWxcclxuXHRcdFx0XHQvLyB9XHJcblx0XHRcdH1cclxuXHJcblx0XHQgICAgcmV0dXJuIGZhbHNlO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8qKlxyXG5cdFx0ICogSXMgdGhlc2UgYXJyYXkgb2YgaW50ZXJ2YWxzIGludGVyc2VjdGVkID9cclxuXHRcdCAqXHJcblx0XHQgKiBAcGFyYW0gdGltZV9pbnRlcnZhbF9BXHRcdC0gWyBbIDIxNjAwLCAyMzQwMCBdIF1cclxuXHRcdCAqIEBwYXJhbSB0aW1lX2ludGVydmFsX0JcdFx0LSBbICBbIDI1MjExLCAyNzAwMiBdLCBbIDM2MDExLCA4NjQwMCBdICBdXHJcblx0XHQgKiBAcmV0dXJucyB7Ym9vbGVhbn1cclxuXHRcdCAqL1xyXG5cdFx0ZnVuY3Rpb24gd3BiY19pc19pbnRlcnNlY3RfX3JhbmdlX3RpbWVfaW50ZXJ2YWwoIHRpbWVfaW50ZXJ2YWxfQSwgdGltZV9pbnRlcnZhbF9CICl7XHJcblxyXG5cdFx0XHR2YXIgaXNfaW50ZXJzZWN0O1xyXG5cclxuXHRcdFx0Zm9yICggdmFyIGkgPSAwOyBpIDwgdGltZV9pbnRlcnZhbF9BLmxlbmd0aDsgaSsrICl7XHJcblxyXG5cdFx0XHRcdGZvciAoIHZhciBqID0gMDsgaiA8IHRpbWVfaW50ZXJ2YWxfQi5sZW5ndGg7IGorKyApe1xyXG5cclxuXHRcdFx0XHRcdGlzX2ludGVyc2VjdCA9IHdwYmNfaW50ZXJ2YWxzX19pc19pbnRlcnNlY3RlZCggdGltZV9pbnRlcnZhbF9BWyBpIF0sIHRpbWVfaW50ZXJ2YWxfQlsgaiBdICk7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCBpc19pbnRlcnNlY3QgKXtcclxuXHRcdFx0XHRcdFx0cmV0dXJuIHRydWU7XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZXR1cm4gZmFsc2U7XHJcblx0XHR9XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiBHZXQgYWxsIHRpbWUgZmllbGRzIGluIHRoZSBib29raW5nIGZvcm0gYXMgYXJyYXkgIG9mIG9iamVjdHNcclxuXHRcdCAqXHJcblx0XHQgKiBAcGFyYW0gcmVzb3VyY2VfaWRcclxuXHRcdCAqIEByZXR1cm5zIFtdXHJcblx0XHQgKlxyXG5cdFx0ICogXHRcdEV4YW1wbGU6XHJcblx0XHQgKiBcdFx0XHRcdFx0W1xyXG5cdFx0ICogXHRcdFx0XHRcdCBcdCAgIHtcclxuXHRcdCAqIFx0XHRcdFx0XHRcdFx0XHR2YWx1ZV9vcHRpb25fMjRoOiAgICcwNjowMCAtIDA2OjMwJ1xyXG5cdFx0ICogXHRcdFx0XHRcdFx0XHRcdHRpbWVzX2FzX3NlY29uZHM6ICAgWyAyMTYwMCwgMjM0MDAgXVxyXG5cdFx0ICogXHRcdFx0XHRcdCBcdCAgIFx0XHRqcXVlcnlfb3B0aW9uOiAgICAgIGpRdWVyeV9PYmplY3Qge31cclxuXHRcdCAqIFx0XHRcdFx0XHRcdFx0XHRuYW1lOiAgICAgICAgICAgICAgICdyYW5nZXRpbWUyW10nXHJcblx0XHQgKiBcdFx0XHRcdFx0ICAgICB9XHJcblx0XHQgKiBcdFx0XHRcdFx0ICAuLi5cclxuXHRcdCAqIFx0XHRcdFx0XHRcdCAgIHtcclxuXHRcdCAqIFx0XHRcdFx0XHRcdFx0XHR2YWx1ZV9vcHRpb25fMjRoOiAgICcwNjowMCdcclxuXHRcdCAqIFx0XHRcdFx0XHRcdFx0XHR0aW1lc19hc19zZWNvbmRzOiAgIFsgMjE2MDAgXVxyXG5cdFx0ICogXHRcdFx0XHRcdFx0ICAgXHRcdGpxdWVyeV9vcHRpb246ICAgICAgalF1ZXJ5X09iamVjdCB7fVxyXG5cdFx0ICogXHRcdFx0XHRcdFx0XHRcdG5hbWU6ICAgICAgICAgICAgICAgJ3N0YXJ0dGltZTJbXSdcclxuXHRcdCAqICBcdFx0XHRcdFx0ICAgIH1cclxuXHRcdCAqIFx0XHRcdFx0XHQgXVxyXG5cdFx0ICovXHJcblx0XHRmdW5jdGlvbiB3cGJjX2dldF9fdGltZV9maWVsZHNfX2luX2Jvb2tpbmdfZm9ybV9fYXNfYXJyKCByZXNvdXJjZV9pZCApe1xyXG5cdFx0ICAgIC8qKlxyXG5cdFx0XHQgKiBGaWVsZHMgd2l0aCAgW10gIGxpa2UgdGhpcyAgIHNlbGVjdFtuYW1lPVwicmFuZ2V0aW1lMVtdXCJdXHJcblx0XHRcdCAqIGl0J3Mgd2hlbiB3ZSBoYXZlICdtdWx0aXBsZScgaW4gc2hvcnRjb2RlOiAgIFtzZWxlY3QqIHJhbmdldGltZSBtdWx0aXBsZSAgXCIwNjowMCAtIDA2OjMwXCIgLi4uIF1cclxuXHRcdFx0ICovXHJcblx0XHRcdHZhciB0aW1lX2ZpZWxkc19hcnI9W1xyXG5cdFx0XHRcdFx0XHRcdFx0XHQnc2VsZWN0W25hbWU9XCJyYW5nZXRpbWUnICsgcmVzb3VyY2VfaWQgKyAnXCJdJyxcclxuXHRcdFx0XHRcdFx0XHRcdFx0J3NlbGVjdFtuYW1lPVwicmFuZ2V0aW1lJyArIHJlc291cmNlX2lkICsgJ1tdXCJdJyxcclxuXHRcdFx0XHRcdFx0XHRcdFx0J3NlbGVjdFtuYW1lPVwic3RhcnR0aW1lJyArIHJlc291cmNlX2lkICsgJ1wiXScsXHJcblx0XHRcdFx0XHRcdFx0XHRcdCdzZWxlY3RbbmFtZT1cInN0YXJ0dGltZScgKyByZXNvdXJjZV9pZCArICdbXVwiXScsXHJcblx0XHRcdFx0XHRcdFx0XHRcdCdzZWxlY3RbbmFtZT1cImVuZHRpbWUnICsgcmVzb3VyY2VfaWQgKyAnXCJdJyxcclxuXHRcdFx0XHRcdFx0XHRcdFx0J3NlbGVjdFtuYW1lPVwiZW5kdGltZScgKyByZXNvdXJjZV9pZCArICdbXVwiXSdcclxuXHRcdFx0XHRcdFx0XHRcdF07XHJcblxyXG5cdFx0XHR2YXIgdGltZV9maWVsZHNfb2JqX2FyciA9IFtdO1xyXG5cclxuXHRcdFx0Ly8gTG9vcCBhbGwgVGltZSBGaWVsZHNcclxuXHRcdFx0Zm9yICggdmFyIGN0Zj0gMDsgY3RmIDwgdGltZV9maWVsZHNfYXJyLmxlbmd0aDsgY3RmKysgKXtcclxuXHJcblx0XHRcdFx0dmFyIHRpbWVfZmllbGQgPSB0aW1lX2ZpZWxkc19hcnJbIGN0ZiBdO1xyXG5cdFx0XHRcdHZhciB0aW1lX29wdGlvbiA9IGpRdWVyeSggdGltZV9maWVsZCArICcgb3B0aW9uJyApO1xyXG5cclxuXHRcdFx0XHQvLyBMb29wIGFsbCBvcHRpb25zIGluIHRpbWUgZmllbGRcclxuXHRcdFx0XHRmb3IgKCB2YXIgaiA9IDA7IGogPCB0aW1lX29wdGlvbi5sZW5ndGg7IGorKyApe1xyXG5cclxuXHRcdFx0XHRcdHZhciBqcXVlcnlfb3B0aW9uID0galF1ZXJ5KCB0aW1lX2ZpZWxkICsgJyBvcHRpb246ZXEoJyArIGogKyAnKScgKTtcclxuXHRcdFx0XHRcdHZhciB2YWx1ZV9vcHRpb25fc2Vjb25kc19hcnIgPSBqcXVlcnlfb3B0aW9uLnZhbCgpLnNwbGl0KCAnLScgKTtcclxuXHRcdFx0XHRcdHZhciB0aW1lc19hc19zZWNvbmRzID0gW107XHJcblxyXG5cdFx0XHRcdFx0Ly8gR2V0IHRpbWUgYXMgc2Vjb25kc1xyXG5cdFx0XHRcdFx0aWYgKCB2YWx1ZV9vcHRpb25fc2Vjb25kc19hcnIubGVuZ3RoICl7XHRcdFx0XHRcdFx0XHRcdFx0Ly8gRml4SW46IDkuOC4xMC4xLlxyXG5cdFx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB2YWx1ZV9vcHRpb25fc2Vjb25kc19hcnIubGVuZ3RoOyBpKysgKXtcdFx0Ly8gRml4SW46IDEwLjAuMC41Ni5cclxuXHRcdFx0XHRcdFx0XHQvLyB2YWx1ZV9vcHRpb25fc2Vjb25kc19hcnJbaV0gPSAnMTQ6MDAgJyAgfCAnIDE2OjAwJyAgIChpZiBmcm9tICdyYW5nZXRpbWUnKSBhbmQgJzE2OjAwJyAgaWYgKHN0YXJ0L2VuZCB0aW1lKVxyXG5cclxuXHRcdFx0XHRcdFx0XHR2YXIgc3RhcnRfZW5kX3RpbWVzX2FyciA9IHZhbHVlX29wdGlvbl9zZWNvbmRzX2FyclsgaSBdLnRyaW0oKS5zcGxpdCggJzonICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdHZhciB0aW1lX2luX3NlY29uZHMgPSBwYXJzZUludCggc3RhcnRfZW5kX3RpbWVzX2FyclsgMCBdICkgKiA2MCAqIDYwICsgcGFyc2VJbnQoIHN0YXJ0X2VuZF90aW1lc19hcnJbIDEgXSApICogNjA7XHJcblxyXG5cdFx0XHRcdFx0XHRcdHRpbWVzX2FzX3NlY29uZHMucHVzaCggdGltZV9pbl9zZWNvbmRzICk7XHJcblx0XHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHR0aW1lX2ZpZWxkc19vYmpfYXJyLnB1c2goIHtcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J25hbWUnICAgICAgICAgICAgOiBqUXVlcnkoIHRpbWVfZmllbGQgKS5hdHRyKCAnbmFtZScgKSxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J3ZhbHVlX29wdGlvbl8yNGgnOiBqcXVlcnlfb3B0aW9uLnZhbCgpLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnanF1ZXJ5X29wdGlvbicgICA6IGpxdWVyeV9vcHRpb24sXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCd0aW1lc19hc19zZWNvbmRzJzogdGltZXNfYXNfc2Vjb25kc1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0fSApO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cmV0dXJuIHRpbWVfZmllbGRzX29ial9hcnI7XHJcblx0XHR9XHJcblxyXG5cdFx0XHQvKipcclxuXHRcdFx0ICogRGlzYWJsZSBIVE1MIG9wdGlvbnMgYW5kIGFkZCBib29rZWQgQ1NTIGNsYXNzXHJcblx0XHRcdCAqXHJcblx0XHRcdCAqIEBwYXJhbSB0aW1lX2ZpZWxkc19vYmpfYXJyICAgICAgLSB0aGlzIHZhbHVlIGlzIGZyb20gIHRoZSBmdW5jOlxyXG5cdFx0XHQgKiAgICAgXHR3cGJjX2dldF9fdGltZV9maWVsZHNfX2luX2Jvb2tpbmdfZm9ybV9fYXNfYXJyKCByZXNvdXJjZV9pZCApXHJcblx0XHRcdCAqIFx0XHRcdFx0XHRbXHJcblx0XHRcdCAqIFx0XHRcdFx0XHQgXHQgICB7XHRqcXVlcnlfb3B0aW9uOiAgICAgIGpRdWVyeV9PYmplY3Qge31cclxuXHRcdFx0ICogXHRcdFx0XHRcdFx0XHRcdG5hbWU6ICAgICAgICAgICAgICAgJ3JhbmdldGltZTJbXSdcclxuXHRcdFx0ICogXHRcdFx0XHRcdFx0XHRcdHRpbWVzX2FzX3NlY29uZHM6ICAgWyAyMTYwMCwgMjM0MDAgXVxyXG5cdFx0XHQgKiBcdFx0XHRcdFx0XHRcdFx0dmFsdWVfb3B0aW9uXzI0aDogICAnMDY6MDAgLSAwNjozMCdcclxuXHRcdFx0ICogXHQgIFx0XHRcdFx0XHRcdCAgICBkaXNhYmxlZCA9IDFcclxuXHRcdFx0ICogXHRcdFx0XHRcdCAgICAgfVxyXG5cdFx0XHQgKiBcdFx0XHRcdFx0ICAuLi5cclxuXHRcdFx0ICogXHRcdFx0XHRcdFx0ICAge1x0anF1ZXJ5X29wdGlvbjogICAgICBqUXVlcnlfT2JqZWN0IHt9XHJcblx0XHRcdCAqIFx0XHRcdFx0XHRcdFx0XHRuYW1lOiAgICAgICAgICAgICAgICdzdGFydHRpbWUyW10nXHJcblx0XHRcdCAqIFx0XHRcdFx0XHRcdFx0XHR0aW1lc19hc19zZWNvbmRzOiAgIFsgMjE2MDAgXVxyXG5cdFx0XHQgKiBcdFx0XHRcdFx0XHRcdFx0dmFsdWVfb3B0aW9uXzI0aDogICAnMDY6MDAnXHJcblx0XHRcdCAqICAgXHRcdFx0XHRcdFx0XHRkaXNhYmxlZCA9IDBcclxuXHRcdFx0ICogIFx0XHRcdFx0XHQgICAgfVxyXG5cdFx0XHQgKiBcdFx0XHRcdFx0IF1cclxuXHRcdFx0ICpcclxuXHRcdFx0ICovXHJcblx0XHRcdGZ1bmN0aW9uIHdwYmNfX2h0bWxfX3RpbWVfZmllbGRfb3B0aW9uc19fc2V0X2Rpc2FibGVkKCB0aW1lX2ZpZWxkc19vYmpfYXJyICl7XHJcblxyXG5cdFx0XHRcdHZhciBqcXVlcnlfb3B0aW9uO1xyXG5cclxuXHRcdFx0XHRmb3IgKCB2YXIgaSA9IDA7IGkgPCB0aW1lX2ZpZWxkc19vYmpfYXJyLmxlbmd0aDsgaSsrICl7XHJcblxyXG5cdFx0XHRcdFx0dmFyIGpxdWVyeV9vcHRpb24gPSB0aW1lX2ZpZWxkc19vYmpfYXJyWyBpIF0uanF1ZXJ5X29wdGlvbjtcclxuXHJcblx0XHRcdFx0XHRpZiAoIDEgPT0gdGltZV9maWVsZHNfb2JqX2FyclsgaSBdLmRpc2FibGVkICl7XHJcblx0XHRcdFx0XHRcdGpxdWVyeV9vcHRpb24ucHJvcCggJ2Rpc2FibGVkJywgdHJ1ZSApOyBcdFx0Ly8gTWFrZSBkaXNhYmxlIHNvbWUgb3B0aW9uc1xyXG5cdFx0XHRcdFx0XHRqcXVlcnlfb3B0aW9uLmFkZENsYXNzKCAnYm9va2VkJyApOyAgICAgICAgICAgXHQvLyBBZGQgXCJib29rZWRcIiBDU1MgY2xhc3NcclxuXHJcblx0XHRcdFx0XHRcdC8vIGlmIHRoaXMgYm9va2VkIGVsZW1lbnQgc2VsZWN0ZWQgLS0+IHRoZW4gZGVzZWxlY3QgIGl0XHJcblx0XHRcdFx0XHRcdGlmICgganF1ZXJ5X29wdGlvbi5wcm9wKCAnc2VsZWN0ZWQnICkgKXtcclxuXHRcdFx0XHRcdFx0XHRqcXVlcnlfb3B0aW9uLnByb3AoICdzZWxlY3RlZCcsIGZhbHNlICk7XHJcblxyXG5cdFx0XHRcdFx0XHRcdGpxdWVyeV9vcHRpb24ucGFyZW50KCkuZmluZCggJ29wdGlvbjpub3QoW2Rpc2FibGVkXSk6Zmlyc3QnICkucHJvcCggJ3NlbGVjdGVkJywgdHJ1ZSApLnRyaWdnZXIoIFwiY2hhbmdlXCIgKTtcclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblx0XHRcdFx0XHRcdGpxdWVyeV9vcHRpb24ucHJvcCggJ2Rpc2FibGVkJywgZmFsc2UgKTsgIFx0XHQvLyBNYWtlIGFjdGl2ZSBhbGwgdGltZXNcclxuXHRcdFx0XHRcdFx0anF1ZXJ5X29wdGlvbi5yZW1vdmVDbGFzcyggJ2Jvb2tlZCcgKTsgICBcdFx0Ly8gUmVtb3ZlIGNsYXNzIFwiYm9va2VkXCJcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIENoZWNrIGlmIHRoaXMgdGltZV9yYW5nZSB8IFRpbWVfU2xvdCBpcyBGdWxsIERheSAgYm9va2VkXHJcblx0ICpcclxuXHQgKiBAcGFyYW0gdGltZXNsb3RfYXJyX2luX3NlY29uZHNcdFx0LSBbIDM2MDExLCA4NjQwMCBdXHJcblx0ICogQHJldHVybnMge2Jvb2xlYW59XHJcblx0ICovXHJcblx0ZnVuY3Rpb24gd3BiY19pc190aGlzX3RpbWVzbG90X19mdWxsX2RheV9ib29rZWQoIHRpbWVzbG90X2Fycl9pbl9zZWNvbmRzICl7XHJcblxyXG5cdFx0aWYgKFxyXG5cdFx0XHRcdCggdGltZXNsb3RfYXJyX2luX3NlY29uZHMubGVuZ3RoID4gMSApXHJcblx0XHRcdCYmICggcGFyc2VJbnQoIHRpbWVzbG90X2Fycl9pbl9zZWNvbmRzWyAwIF0gKSA8IDMwIClcclxuXHRcdFx0JiYgKCBwYXJzZUludCggdGltZXNsb3RfYXJyX2luX3NlY29uZHNbIDEgXSApID4gICggKDI0ICogNjAgKiA2MCkgLSAzMCkgKVxyXG5cdFx0KXtcclxuXHRcdFx0cmV0dXJuIHRydWU7XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGZhbHNlO1xyXG5cdH1cclxuXHJcblxyXG5cdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0LyogID09ICBTIGUgbCBlIGMgdCBlIGQgICAgRCBhIHQgZSBzICAvICBUIGkgbSBlIC0gRiBpIGUgbCBkIHMgID09XHJcblx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi9cclxuXHJcblx0LyoqXHJcblx0ICogIEdldCBhbGwgc2VsZWN0ZWQgZGF0ZXMgaW4gU1FMIGZvcm1hdCBsaWtlIHRoaXMgWyBcIjIwMjMtMDgtMjNcIiwgXCIyMDIzLTA4LTI0XCIgLCAuLi4gXVxyXG5cdCAqXHJcblx0ICogQHBhcmFtIHJlc291cmNlX2lkXHJcblx0ICogQHJldHVybnMge1tdfVx0XHRcdFsgXCIyMDIzLTA4LTIzXCIsIFwiMjAyMy0wOC0yNFwiLCBcIjIwMjMtMDgtMjVcIiwgXCIyMDIzLTA4LTI2XCIsIFwiMjAyMy0wOC0yN1wiLCBcIjIwMjMtMDgtMjhcIixcclxuXHQgKiAgICAgXCIyMDIzLTA4LTI5XCIgXVxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdwYmNfZ2V0X19zZWxlY3RlZF9kYXRlc19zcWxfX2FzX2FyciggcmVzb3VyY2VfaWQgKXtcclxuXHJcblx0XHR2YXIgc2VsZWN0ZWRfZGF0ZXNfYXJyID0gW107XHJcblx0XHRzZWxlY3RlZF9kYXRlc19hcnIgPSBqUXVlcnkoICcjZGF0ZV9ib29raW5nJyArIHJlc291cmNlX2lkICkudmFsKCkuc3BsaXQoJywnKTtcclxuXHJcblx0XHRpZiAoIHNlbGVjdGVkX2RhdGVzX2Fyci5sZW5ndGggKXtcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQvLyBGaXhJbjogOS44LjEwLjEuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHNlbGVjdGVkX2RhdGVzX2Fyci5sZW5ndGg7IGkrKyApe1x0XHRcdFx0XHRcdC8vIEZpeEluOiAxMC4wLjAuNTYuXHJcblx0XHRcdFx0c2VsZWN0ZWRfZGF0ZXNfYXJyWyBpIF0gPSBzZWxlY3RlZF9kYXRlc19hcnJbIGkgXS50cmltKCk7XHJcblx0XHRcdFx0c2VsZWN0ZWRfZGF0ZXNfYXJyWyBpIF0gPSBzZWxlY3RlZF9kYXRlc19hcnJbIGkgXS5zcGxpdCggJy4nICk7XHJcblx0XHRcdFx0aWYgKCBzZWxlY3RlZF9kYXRlc19hcnJbIGkgXS5sZW5ndGggPiAxICl7XHJcblx0XHRcdFx0XHRzZWxlY3RlZF9kYXRlc19hcnJbIGkgXSA9IHNlbGVjdGVkX2RhdGVzX2FyclsgaSBdWyAyIF0gKyAnLScgKyBzZWxlY3RlZF9kYXRlc19hcnJbIGkgXVsgMSBdICsgJy0nICsgc2VsZWN0ZWRfZGF0ZXNfYXJyWyBpIF1bIDAgXTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHQvLyBSZW1vdmUgZW1wdHkgZWxlbWVudHMgZnJvbSBhbiBhcnJheVxyXG5cdFx0c2VsZWN0ZWRfZGF0ZXNfYXJyID0gc2VsZWN0ZWRfZGF0ZXNfYXJyLmZpbHRlciggZnVuY3Rpb24gKCBuICl7IHJldHVybiBwYXJzZUludChuKTsgfSApO1xyXG5cclxuXHRcdHNlbGVjdGVkX2RhdGVzX2Fyci5zb3J0KCk7XHJcblxyXG5cdFx0cmV0dXJuIHNlbGVjdGVkX2RhdGVzX2FycjtcclxuXHR9XHJcblxyXG5cclxuXHQvKipcclxuXHQgKiBHZXQgYWxsIHRpbWUgZmllbGRzIGluIHRoZSBib29raW5nIGZvcm0gYXMgYXJyYXkgIG9mIG9iamVjdHNcclxuXHQgKlxyXG5cdCAqIEBwYXJhbSByZXNvdXJjZV9pZFxyXG5cdCAqIEBwYXJhbSBpc19vbmx5X3NlbGVjdGVkX3RpbWVcclxuXHQgKiBAcmV0dXJucyBbXVxyXG5cdCAqXHJcblx0ICogXHRcdEV4YW1wbGU6XHJcblx0ICogXHRcdFx0XHRcdFtcclxuXHQgKiBcdFx0XHRcdFx0IFx0ICAge1xyXG5cdCAqIFx0XHRcdFx0XHRcdFx0XHR2YWx1ZV9vcHRpb25fMjRoOiAgICcwNjowMCAtIDA2OjMwJ1xyXG5cdCAqIFx0XHRcdFx0XHRcdFx0XHR0aW1lc19hc19zZWNvbmRzOiAgIFsgMjE2MDAsIDIzNDAwIF1cclxuXHQgKiBcdFx0XHRcdFx0IFx0ICAgXHRcdGpxdWVyeV9vcHRpb246ICAgICAgalF1ZXJ5X09iamVjdCB7fVxyXG5cdCAqIFx0XHRcdFx0XHRcdFx0XHRuYW1lOiAgICAgICAgICAgICAgICdyYW5nZXRpbWUyW10nXHJcblx0ICogXHRcdFx0XHRcdCAgICAgfVxyXG5cdCAqIFx0XHRcdFx0XHQgIC4uLlxyXG5cdCAqIFx0XHRcdFx0XHRcdCAgIHtcclxuXHQgKiBcdFx0XHRcdFx0XHRcdFx0dmFsdWVfb3B0aW9uXzI0aDogICAnMDY6MDAnXHJcblx0ICogXHRcdFx0XHRcdFx0XHRcdHRpbWVzX2FzX3NlY29uZHM6ICAgWyAyMTYwMCBdXHJcblx0ICogXHRcdFx0XHRcdFx0ICAgXHRcdGpxdWVyeV9vcHRpb246ICAgICAgalF1ZXJ5X09iamVjdCB7fVxyXG5cdCAqIFx0XHRcdFx0XHRcdFx0XHRuYW1lOiAgICAgICAgICAgICAgICdzdGFydHRpbWUyW10nXHJcblx0ICogIFx0XHRcdFx0XHQgICAgfVxyXG5cdCAqIFx0XHRcdFx0XHQgXVxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdwYmNfZ2V0X19zZWxlY3RlZF90aW1lX2ZpZWxkc19faW5fYm9va2luZ19mb3JtX19hc19hcnIoIHJlc291cmNlX2lkLCBpc19vbmx5X3NlbGVjdGVkX3RpbWUgPSB0cnVlICl7XHJcblx0XHQvKipcclxuXHRcdCAqIEZpZWxkcyB3aXRoICBbXSAgbGlrZSB0aGlzICAgc2VsZWN0W25hbWU9XCJyYW5nZXRpbWUxW11cIl1cclxuXHRcdCAqIGl0J3Mgd2hlbiB3ZSBoYXZlICdtdWx0aXBsZScgaW4gc2hvcnRjb2RlOiAgIFtzZWxlY3QqIHJhbmdldGltZSBtdWx0aXBsZSAgXCIwNjowMCAtIDA2OjMwXCIgLi4uIF1cclxuXHRcdCAqL1xyXG5cdFx0dmFyIHRpbWVfZmllbGRzX2Fycj1bXHJcblx0XHRcdFx0XHRcdFx0XHQnc2VsZWN0W25hbWU9XCJyYW5nZXRpbWUnICsgcmVzb3VyY2VfaWQgKyAnXCJdJyxcclxuXHRcdFx0XHRcdFx0XHRcdCdzZWxlY3RbbmFtZT1cInJhbmdldGltZScgKyByZXNvdXJjZV9pZCArICdbXVwiXScsXHJcblx0XHRcdFx0XHRcdFx0XHQnc2VsZWN0W25hbWU9XCJzdGFydHRpbWUnICsgcmVzb3VyY2VfaWQgKyAnXCJdJyxcclxuXHRcdFx0XHRcdFx0XHRcdCdzZWxlY3RbbmFtZT1cInN0YXJ0dGltZScgKyByZXNvdXJjZV9pZCArICdbXVwiXScsXHJcblx0XHRcdFx0XHRcdFx0XHQnc2VsZWN0W25hbWU9XCJlbmR0aW1lJyArIHJlc291cmNlX2lkICsgJ1wiXScsXHJcblx0XHRcdFx0XHRcdFx0XHQnc2VsZWN0W25hbWU9XCJlbmR0aW1lJyArIHJlc291cmNlX2lkICsgJ1tdXCJdJyxcclxuXHRcdFx0XHRcdFx0XHRcdCdzZWxlY3RbbmFtZT1cImR1cmF0aW9udGltZScgKyByZXNvdXJjZV9pZCArICdcIl0nLFxyXG5cdFx0XHRcdFx0XHRcdFx0J3NlbGVjdFtuYW1lPVwiZHVyYXRpb250aW1lJyArIHJlc291cmNlX2lkICsgJ1tdXCJdJ1xyXG5cdFx0XHRcdFx0XHRcdF07XHJcblxyXG5cdFx0dmFyIHRpbWVfZmllbGRzX29ial9hcnIgPSBbXTtcclxuXHJcblx0XHQvLyBMb29wIGFsbCBUaW1lIEZpZWxkc1xyXG5cdFx0Zm9yICggdmFyIGN0Zj0gMDsgY3RmIDwgdGltZV9maWVsZHNfYXJyLmxlbmd0aDsgY3RmKysgKXtcclxuXHJcblx0XHRcdHZhciB0aW1lX2ZpZWxkID0gdGltZV9maWVsZHNfYXJyWyBjdGYgXTtcclxuXHJcblx0XHRcdHZhciB0aW1lX29wdGlvbjtcclxuXHRcdFx0aWYgKCBpc19vbmx5X3NlbGVjdGVkX3RpbWUgKXtcclxuXHRcdFx0XHR0aW1lX29wdGlvbiA9IGpRdWVyeSggJyNib29raW5nX2Zvcm0nICsgcmVzb3VyY2VfaWQgKyAnICcgKyB0aW1lX2ZpZWxkICsgJyBvcHRpb246c2VsZWN0ZWQnICk7XHRcdFx0Ly8gRXhjbHVkZSBjb25kaXRpb25hbCAgZmllbGRzLCAgYmVjYXVzZSBvZiB1c2luZyAnI2Jvb2tpbmdfZm9ybTMgLi4uJ1xyXG5cdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdHRpbWVfb3B0aW9uID0galF1ZXJ5KCAnI2Jvb2tpbmdfZm9ybScgKyByZXNvdXJjZV9pZCArICcgJyArIHRpbWVfZmllbGQgKyAnIG9wdGlvbicgKTtcdFx0XHRcdC8vIEFsbCAgdGltZSBmaWVsZHNcclxuXHRcdFx0fVxyXG5cclxuXHJcblx0XHRcdC8vIExvb3AgYWxsIG9wdGlvbnMgaW4gdGltZSBmaWVsZFxyXG5cdFx0XHRmb3IgKCB2YXIgaiA9IDA7IGogPCB0aW1lX29wdGlvbi5sZW5ndGg7IGorKyApe1xyXG5cclxuXHRcdFx0XHR2YXIganF1ZXJ5X29wdGlvbiA9IGpRdWVyeSggdGltZV9vcHRpb25bIGogXSApO1x0XHQvLyBHZXQgb25seSAgc2VsZWN0ZWQgb3B0aW9ucyBcdC8valF1ZXJ5KCB0aW1lX2ZpZWxkICsgJyBvcHRpb246ZXEoJyArIGogKyAnKScgKTtcclxuXHRcdFx0XHR2YXIgdmFsdWVfb3B0aW9uX3NlY29uZHNfYXJyID0ganF1ZXJ5X29wdGlvbi52YWwoKS5zcGxpdCggJy0nICk7XHJcblx0XHRcdFx0dmFyIHRpbWVzX2FzX3NlY29uZHMgPSBbXTtcclxuXHJcblx0XHRcdFx0Ly8gR2V0IHRpbWUgYXMgc2Vjb25kc1xyXG5cdFx0XHRcdGlmICggdmFsdWVfb3B0aW9uX3NlY29uZHNfYXJyLmxlbmd0aCApe1x0XHRcdFx0IFx0XHRcdFx0XHRcdFx0XHQvLyBGaXhJbjogOS44LjEwLjEuXHJcblx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB2YWx1ZV9vcHRpb25fc2Vjb25kc19hcnIubGVuZ3RoOyBpKysgKXtcdFx0XHRcdFx0Ly8gRml4SW46IDEwLjAuMC41Ni5cclxuXHRcdFx0XHRcdFx0Ly8gdmFsdWVfb3B0aW9uX3NlY29uZHNfYXJyW2ldID0gJzE0OjAwICcgIHwgJyAxNjowMCcgICAoaWYgZnJvbSAncmFuZ2V0aW1lJykgYW5kICcxNjowMCcgIGlmIChzdGFydC9lbmQgdGltZSlcclxuXHJcblx0XHRcdFx0XHRcdHZhciBzdGFydF9lbmRfdGltZXNfYXJyID0gdmFsdWVfb3B0aW9uX3NlY29uZHNfYXJyWyBpIF0udHJpbSgpLnNwbGl0KCAnOicgKTtcclxuXHJcblx0XHRcdFx0XHRcdHZhciB0aW1lX2luX3NlY29uZHMgPSBwYXJzZUludCggc3RhcnRfZW5kX3RpbWVzX2FyclsgMCBdICkgKiA2MCAqIDYwICsgcGFyc2VJbnQoIHN0YXJ0X2VuZF90aW1lc19hcnJbIDEgXSApICogNjA7XHJcblxyXG5cdFx0XHRcdFx0XHR0aW1lc19hc19zZWNvbmRzLnB1c2goIHRpbWVfaW5fc2Vjb25kcyApO1xyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0dGltZV9maWVsZHNfb2JqX2Fyci5wdXNoKCB7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnbmFtZScgICAgICAgICAgICA6IGpRdWVyeSggJyNib29raW5nX2Zvcm0nICsgcmVzb3VyY2VfaWQgKyAnICcgKyB0aW1lX2ZpZWxkICkuYXR0ciggJ25hbWUnICksXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHQndmFsdWVfb3B0aW9uXzI0aCc6IGpxdWVyeV9vcHRpb24udmFsKCksXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnanF1ZXJ5X29wdGlvbicgICA6IGpxdWVyeV9vcHRpb24sXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHQndGltZXNfYXNfc2Vjb25kcyc6IHRpbWVzX2FzX3NlY29uZHNcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHR9ICk7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHQvLyBUZXh0OiAgIFtzdGFydHRpbWVdIC0gW2VuZHRpbWVdIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblxyXG5cdFx0dmFyIHRleHRfdGltZV9maWVsZHNfYXJyPVtcclxuXHRcdFx0XHRcdFx0XHRcdFx0J2lucHV0W25hbWU9XCJzdGFydHRpbWUnICsgcmVzb3VyY2VfaWQgKyAnXCJdJyxcclxuXHRcdFx0XHRcdFx0XHRcdFx0J2lucHV0W25hbWU9XCJlbmR0aW1lJyArIHJlc291cmNlX2lkICsgJ1wiXScsXHJcblx0XHRcdFx0XHRcdFx0XHRdO1xyXG5cdFx0Zm9yICggdmFyIHRmPSAwOyB0ZiA8IHRleHRfdGltZV9maWVsZHNfYXJyLmxlbmd0aDsgdGYrKyApe1xyXG5cclxuXHRcdFx0dmFyIHRleHRfanF1ZXJ5ID0galF1ZXJ5KCAnI2Jvb2tpbmdfZm9ybScgKyByZXNvdXJjZV9pZCArICcgJyArIHRleHRfdGltZV9maWVsZHNfYXJyWyB0ZiBdICk7XHRcdFx0XHRcdFx0XHRcdC8vIEV4Y2x1ZGUgY29uZGl0aW9uYWwgIGZpZWxkcywgIGJlY2F1c2Ugb2YgdXNpbmcgJyNib29raW5nX2Zvcm0zIC4uLidcclxuXHRcdFx0aWYgKCB0ZXh0X2pxdWVyeS5sZW5ndGggPiAwICl7XHJcblxyXG5cdFx0XHRcdHZhciB0aW1lX19oX21fX2FyciA9IHRleHRfanF1ZXJ5LnZhbCgpLnRyaW0oKS5zcGxpdCggJzonICk7XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vICcxNDowMCdcclxuXHRcdFx0XHRpZiAoIDAgPT0gdGltZV9faF9tX19hcnIubGVuZ3RoICl7XHJcblx0XHRcdFx0XHRjb250aW51ZTtcdFx0XHRcdFx0XHRcdFx0XHQvLyBOb3QgZW50ZXJlZCB0aW1lIHZhbHVlIGluIGEgZmllbGRcclxuXHRcdFx0XHR9XHJcblx0XHRcdFx0aWYgKCAxID09IHRpbWVfX2hfbV9fYXJyLmxlbmd0aCApe1xyXG5cdFx0XHRcdFx0aWYgKCAnJyA9PT0gdGltZV9faF9tX19hcnJbIDAgXSApe1xyXG5cdFx0XHRcdFx0XHRjb250aW51ZTtcdFx0XHRcdFx0XHRcdFx0Ly8gTm90IGVudGVyZWQgdGltZSB2YWx1ZSBpbiBhIGZpZWxkXHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHR0aW1lX19oX21fX2FyclsgMSBdID0gMDtcclxuXHRcdFx0XHR9XHJcblx0XHRcdFx0dmFyIHRleHRfdGltZV9pbl9zZWNvbmRzID0gcGFyc2VJbnQoIHRpbWVfX2hfbV9fYXJyWyAwIF0gKSAqIDYwICogNjAgKyBwYXJzZUludCggdGltZV9faF9tX19hcnJbIDEgXSApICogNjA7XHJcblxyXG5cdFx0XHRcdHZhciB0ZXh0X3RpbWVzX2FzX3NlY29uZHMgPSBbXTtcclxuXHRcdFx0XHR0ZXh0X3RpbWVzX2FzX3NlY29uZHMucHVzaCggdGV4dF90aW1lX2luX3NlY29uZHMgKTtcclxuXHJcblx0XHRcdFx0dGltZV9maWVsZHNfb2JqX2Fyci5wdXNoKCB7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnbmFtZScgICAgICAgICAgICA6IHRleHRfanF1ZXJ5LmF0dHIoICduYW1lJyApLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0J3ZhbHVlX29wdGlvbl8yNGgnOiB0ZXh0X2pxdWVyeS52YWwoKSxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdCdqcXVlcnlfb3B0aW9uJyAgIDogdGV4dF9qcXVlcnksXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHQndGltZXNfYXNfc2Vjb25kcyc6IHRleHRfdGltZXNfYXNfc2Vjb25kc1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdH0gKTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aW1lX2ZpZWxkc19vYmpfYXJyO1xyXG5cdH1cclxuXHJcblxyXG5cclxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcbi8qICA9PSAgUyBVIFAgUCBPIFIgVCAgICBmb3IgICAgQyBBIEwgRSBOIEQgQSBSICA9PVxyXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi9cclxuXHJcblx0LyoqXHJcblx0ICogR2V0IENhbGVuZGFyIGRhdGVwaWNrIEluc3RhbmNlLlxyXG5cdCAqXHJcblx0ICogQHBhcmFtIHtpbnR8c3RyaW5nfSByZXNvdXJjZV9pZFxyXG5cdCAqIEByZXR1cm5zIHsqfG51bGx9XHJcblx0ICovXHJcblx0ZnVuY3Rpb24gd3BiY19jYWxlbmRhcl9fZ2V0X2luc3QocmVzb3VyY2VfaWQpIHtcclxuXHJcblx0XHRpZiAoICd1bmRlZmluZWQnID09PSB0eXBlb2YgKHJlc291cmNlX2lkKSApIHtcclxuXHRcdFx0cmVzb3VyY2VfaWQgPSAnMSc7XHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBqUXVlcnkoICcjY2FsZW5kYXJfYm9va2luZycgKyByZXNvdXJjZV9pZCApLmxlbmd0aCA+IDAgKSB7XHJcblxyXG5cdFx0XHR0cnkge1xyXG5cdFx0XHRcdHZhciBpbnN0ID0galF1ZXJ5LmRhdGVwaWNrLl9nZXRJbnN0KCBqUXVlcnkoICcjY2FsZW5kYXJfYm9va2luZycgKyByZXNvdXJjZV9pZCApLmdldCggMCApICk7XHJcblx0XHRcdFx0cmV0dXJuIGluc3QgPyBpbnN0IDogbnVsbDtcclxuXHRcdFx0fSBjYXRjaCAoIGUgKSB7XHJcblx0XHRcdFx0cmV0dXJuIG51bGw7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gbnVsbDtcclxuXHR9XHJcblxyXG5cclxuXHQvKipcclxuXHQgKiBVbnNlbGVjdCAgYWxsIGRhdGVzIGluIGNhbGVuZGFyIGFuZCB2aXN1YWxseSB1cGRhdGUgdGhpcyBjYWxlbmRhclxyXG5cdCAqXHJcblx0ICogQHBhcmFtIHJlc291cmNlX2lkXHRcdElEIG9mIGJvb2tpbmcgcmVzb3VyY2VcclxuXHQgKiBAcmV0dXJucyB7Ym9vbGVhbn1cdFx0dHJ1ZSBvbiBzdWNjZXNzIHwgZmFsc2UsICBpZiBubyBzdWNoICBjYWxlbmRhclxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdwYmNfY2FsZW5kYXJfX3Vuc2VsZWN0X2FsbF9kYXRlcyggcmVzb3VyY2VfaWQgKXtcclxuXHJcblx0XHRpZiAoICd1bmRlZmluZWQnID09PSB0eXBlb2YgKHJlc291cmNlX2lkKSApe1xyXG5cdFx0XHRyZXNvdXJjZV9pZCA9ICcxJztcclxuXHRcdH1cclxuXHJcblx0XHR2YXIgaW5zdCA9IHdwYmNfY2FsZW5kYXJfX2dldF9pbnN0KCByZXNvdXJjZV9pZCApXHJcblxyXG5cdFx0aWYgKCBudWxsICE9PSBpbnN0ICl7XHJcblxyXG5cdFx0XHQvLyBVbnNlbGVjdCBhbGwgZGF0ZXMgYW5kIHNldCAgcHJvcGVydGllcyBvZiBEYXRlcGlja1xyXG5cdFx0XHRqUXVlcnkoICcjZGF0ZV9ib29raW5nJyArIHJlc291cmNlX2lkICkudmFsKCAnJyApOyAgICAgIC8vRml4SW46IDUuNC4zXHJcblx0XHRcdGluc3Quc3RheU9wZW4gPSBmYWxzZTtcclxuXHRcdFx0aW5zdC5kYXRlcyA9IFtdO1xyXG5cdFx0XHRqUXVlcnkuZGF0ZXBpY2suX3VwZGF0ZURhdGVwaWNrKCBpbnN0ICk7XHJcblxyXG5cdFx0XHRyZXR1cm4gdHJ1ZVxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBmYWxzZTtcclxuXHJcblx0fVxyXG5cclxuXHQvKipcclxuXHQgKiBDbGVhciBkYXlzIGhpZ2hsaWdodGluZyBpbiBBbGwgb3Igc3BlY2lmaWMgQ2FsZW5kYXJzXHJcblx0ICpcclxuICAgICAqIEBwYXJhbSByZXNvdXJjZV9pZCAgLSBjYW4gYmUgc2tpcGVkIHRvICBjbGVhciBoaWdobGlnaHRpbmcgaW4gYWxsIGNhbGVuZGFyc1xyXG4gICAgICovXHJcblx0ZnVuY3Rpb24gd3BiY19jYWxlbmRhcnNfX2NsZWFyX2RheXNfaGlnaGxpZ2h0aW5nKCByZXNvdXJjZV9pZCApe1xyXG5cclxuXHRcdGlmICggJ3VuZGVmaW5lZCcgIT09IHR5cGVvZiAoIHJlc291cmNlX2lkICkgKXtcclxuXHJcblx0XHRcdGpRdWVyeSggJyNjYWxlbmRhcl9ib29raW5nJyArIHJlc291cmNlX2lkICsgJyAuZGF0ZXBpY2stZGF5cy1jZWxsLW92ZXInICkucmVtb3ZlQ2xhc3MoICdkYXRlcGljay1kYXlzLWNlbGwtb3ZlcicgKTtcdFx0Ly8gQ2xlYXIgaW4gc3BlY2lmaWMgY2FsZW5kYXJcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHRqUXVlcnkoICcuZGF0ZXBpY2stZGF5cy1jZWxsLW92ZXInICkucmVtb3ZlQ2xhc3MoICdkYXRlcGljay1kYXlzLWNlbGwtb3ZlcicgKTtcdFx0XHRcdFx0XHRcdFx0Ly8gQ2xlYXIgaW4gYWxsIGNhbGVuZGFyc1xyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0LyoqXHJcblx0ICogU2Nyb2xsIHRvIHNwZWNpZmljIG1vbnRoIGluIGNhbGVuZGFyXHJcblx0ICpcclxuXHQgKiBAcGFyYW0gcmVzb3VyY2VfaWRcdFx0SUQgb2YgcmVzb3VyY2VcclxuXHQgKiBAcGFyYW0geWVhclx0XHRcdFx0LSByZWFsIHllYXIgIC0gMjAyM1xyXG5cdCAqIEBwYXJhbSBtb250aFx0XHRcdFx0LSByZWFsIG1vbnRoIC0gMTJcclxuXHQgKiBAcmV0dXJucyB7Ym9vbGVhbn1cclxuXHQgKi9cclxuXHRmdW5jdGlvbiB3cGJjX2NhbGVuZGFyX19zY3JvbGxfdG8oIHJlc291cmNlX2lkLCB5ZWFyLCBtb250aCApe1xyXG5cclxuXHRcdGlmICggJ3VuZGVmaW5lZCcgPT09IHR5cGVvZiAocmVzb3VyY2VfaWQpICl7IHJlc291cmNlX2lkID0gJzEnOyB9XHJcblx0XHR2YXIgaW5zdCA9IHdwYmNfY2FsZW5kYXJfX2dldF9pbnN0KCByZXNvdXJjZV9pZCApXHJcblx0XHRpZiAoIG51bGwgIT09IGluc3QgKXtcclxuXHJcblx0XHRcdHllYXIgID0gcGFyc2VJbnQoIHllYXIgKTtcclxuXHRcdFx0bW9udGggPSBwYXJzZUludCggbW9udGggKSAtIDE7XHRcdC8vIEluIEpTIGRhdGUsICBtb250aCAtMVxyXG5cclxuXHRcdFx0aW5zdC5jdXJzb3JEYXRlID0gbmV3IERhdGUoKTtcclxuXHRcdFx0Ly8gSW4gc29tZSBjYXNlcywgIHRoZSBzZXRGdWxsWWVhciBjYW4gIHNldCAgb25seSBZZWFyLCAgYW5kIG5vdCB0aGUgTW9udGggYW5kIGRheSAgICAgIC8vIEZpeEluOiA2LjIuMy41LlxyXG5cdFx0XHRpbnN0LmN1cnNvckRhdGUuc2V0RnVsbFllYXIoIHllYXIsIG1vbnRoLCAxICk7XHJcblx0XHRcdGluc3QuY3Vyc29yRGF0ZS5zZXRNb250aCggbW9udGggKTtcclxuXHRcdFx0aW5zdC5jdXJzb3JEYXRlLnNldERhdGUoIDEgKTtcclxuXHJcblx0XHRcdGluc3QuZHJhd01vbnRoID0gaW5zdC5jdXJzb3JEYXRlLmdldE1vbnRoKCk7XHJcblx0XHRcdGluc3QuZHJhd1llYXIgPSBpbnN0LmN1cnNvckRhdGUuZ2V0RnVsbFllYXIoKTtcclxuXHJcblx0XHRcdGpRdWVyeS5kYXRlcGljay5fbm90aWZ5Q2hhbmdlKCBpbnN0ICk7XHJcblx0XHRcdGpRdWVyeS5kYXRlcGljay5fYWRqdXN0SW5zdERhdGUoIGluc3QgKTtcclxuXHRcdFx0alF1ZXJ5LmRhdGVwaWNrLl9zaG93RGF0ZSggaW5zdCApO1xyXG5cdFx0XHRqUXVlcnkuZGF0ZXBpY2suX3VwZGF0ZURhdGVwaWNrKCBpbnN0ICk7XHJcblxyXG5cdFx0XHRyZXR1cm4gdHJ1ZTtcclxuXHRcdH1cclxuXHRcdHJldHVybiBmYWxzZTtcclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIElzIHRoaXMgZGF0ZSBzZWxlY3RhYmxlIGluIGNhbGVuZGFyIChtYWlubHkgaXQncyBtZWFucyBBVkFJTEFCTEUgZGF0ZSlcclxuXHQgKlxyXG5cdCAqIEBwYXJhbSB7aW50fHN0cmluZ30gcmVzb3VyY2VfaWRcdFx0MVxyXG5cdCAqIEBwYXJhbSB7c3RyaW5nfSBzcWxfY2xhc3NfZGF5XHRcdCcyMDIzLTA4LTExJ1xyXG5cdCAqIEByZXR1cm5zIHtib29sZWFufVx0XHRcdFx0XHR0cnVlIHwgZmFsc2VcclxuXHQgKi9cclxuXHRmdW5jdGlvbiB3cGJjX2lzX3RoaXNfZGF5X3NlbGVjdGFibGUoIHJlc291cmNlX2lkLCBzcWxfY2xhc3NfZGF5ICl7XHJcblxyXG5cdFx0Ly8gR2V0IERhdGEgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdHZhciBkYXRlX2Jvb2tpbmdzX29iaiA9IF93cGJjLmJvb2tpbmdzX2luX2NhbGVuZGFyX19nZXRfZm9yX2RhdGUoIHJlc291cmNlX2lkLCBzcWxfY2xhc3NfZGF5ICk7XHJcblxyXG5cdFx0dmFyIGlzX2RheV9zZWxlY3RhYmxlID0gKCBwYXJzZUludCggZGF0ZV9ib29raW5nc19vYmpbICdkYXlfYXZhaWxhYmlsaXR5JyBdICkgPiAwICk7XHJcblxyXG5cdFx0aWYgKCB0eXBlb2YgKGRhdGVfYm9va2luZ3Nfb2JqWyAnc3VtbWFyeScgXSkgPT09ICd1bmRlZmluZWQnICl7XHJcblx0XHRcdHJldHVybiBpc19kYXlfc2VsZWN0YWJsZTtcclxuXHRcdH1cclxuXHJcblx0XHRpZiAoICdhdmFpbGFibGUnICE9IGRhdGVfYm9va2luZ3Nfb2JqWyAnc3VtbWFyeSddWydzdGF0dXNfZm9yX2RheScgXSApe1xyXG5cclxuXHRcdFx0dmFyIGlzX3NldF9wZW5kaW5nX2RheXNfc2VsZWN0YWJsZSA9IF93cGJjLmNhbGVuZGFyX19nZXRfcGFyYW1fdmFsdWUoIHJlc291cmNlX2lkLCAncGVuZGluZ19kYXlzX3NlbGVjdGFibGUnICk7XHRcdC8vIHNldCBwZW5kaW5nIGRheXMgc2VsZWN0YWJsZSAgICAgICAgICAvLyBGaXhJbjogOC42LjEuMTguXHJcblx0XHRcdHZhciBib29raW5nX3N0YXR1c2VzX2FyciA9IHdwYmNfZ2V0X2Jvb2tpbmdfc3RhdHVzZXNfX2FzX2FyciggZGF0ZV9ib29raW5nc19vYmogKTtcclxuXHJcblx0XHRcdGlmIChcclxuXHRcdFx0XHQgICAoIHdwYmNfYm9va2luZ19zdGF0dXNlc19faGFzKCBib29raW5nX3N0YXR1c2VzX2FyciwgJ3BlbmRpbmcnICkgKVxyXG5cdFx0XHRcdHx8ICggd3BiY19ib29raW5nX3N0YXR1c2VzX19oYXMoIGJvb2tpbmdfc3RhdHVzZXNfYXJyLCAncGVuZGluZ19wZW5kaW5nJyApIClcclxuXHRcdFx0XHR8fCAoIHdwYmNfYm9va2luZ19zdGF0dXNlc19faGFzKCBib29raW5nX3N0YXR1c2VzX2FyciwgJ3BlbmRpbmdfYXBwcm92ZWQnICkgKVxyXG5cdFx0XHRcdHx8ICggd3BiY19ib29raW5nX3N0YXR1c2VzX19oYXMoIGJvb2tpbmdfc3RhdHVzZXNfYXJyLCAnYXBwcm92ZWRfcGVuZGluZycgKSApXHJcblx0XHRcdCl7XHJcblx0XHRcdFx0aXNfZGF5X3NlbGVjdGFibGUgPSAoaXNfZGF5X3NlbGVjdGFibGUpID8gdHJ1ZSA6IGlzX3NldF9wZW5kaW5nX2RheXNfc2VsZWN0YWJsZTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBpc19kYXlfc2VsZWN0YWJsZTtcclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIElzIGRhdGUgdG8gY2hlY2sgSU4gYXJyYXkgb2Ygc2VsZWN0ZWQgZGF0ZXNcclxuXHQgKlxyXG5cdCAqIEBwYXJhbSB7ZGF0ZX1qc19kYXRlX3RvX2NoZWNrXHRcdC0gSlMgRGF0ZVx0XHRcdC0gc2ltcGxlICBKYXZhU2NyaXB0IERhdGUgb2JqZWN0XHJcblx0ICogQHBhcmFtIHtbXX0ganNfZGF0ZXNfYXJyXHRcdFx0LSBbIEpTRGF0ZSwgLi4uIF0gICAtIGFycmF5ICBvZiBKUyBkYXRlc1xyXG5cdCAqIEByZXR1cm5zIHtib29sZWFufVxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdwYmNfaXNfdGhpc19kYXlfYW1vbmdfc2VsZWN0ZWRfZGF5cygganNfZGF0ZV90b19jaGVjaywganNfZGF0ZXNfYXJyICl7XHJcblxyXG5cdFx0Zm9yICggdmFyIGRhdGVfaW5kZXggPSAwOyBkYXRlX2luZGV4IDwganNfZGF0ZXNfYXJyLmxlbmd0aCA7IGRhdGVfaW5kZXgrKyApeyAgICAgXHRcdFx0XHRcdFx0XHRcdFx0Ly8gRml4SW46IDguNC41LjE2LlxyXG5cdFx0XHRpZiAoICgganNfZGF0ZXNfYXJyWyBkYXRlX2luZGV4IF0uZ2V0RnVsbFllYXIoKSA9PT0ganNfZGF0ZV90b19jaGVjay5nZXRGdWxsWWVhcigpICkgJiZcclxuXHRcdFx0XHQgKCBqc19kYXRlc19hcnJbIGRhdGVfaW5kZXggXS5nZXRNb250aCgpID09PSBqc19kYXRlX3RvX2NoZWNrLmdldE1vbnRoKCkgKSAmJlxyXG5cdFx0XHRcdCAoIGpzX2RhdGVzX2FyclsgZGF0ZV9pbmRleCBdLmdldERhdGUoKSA9PT0ganNfZGF0ZV90b19jaGVjay5nZXREYXRlKCkgKSApIHtcclxuXHRcdFx0XHRcdHJldHVybiB0cnVlO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuICBmYWxzZTtcclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIEdldCBTUUwgQ2xhc3MgRGF0ZSAnMjAyMy0wOC0wMScgZnJvbSAgSlMgRGF0ZVxyXG5cdCAqXHJcblx0ICogQHBhcmFtIGRhdGVcdFx0XHRcdEpTIERhdGVcclxuXHQgKiBAcmV0dXJucyB7c3RyaW5nfVx0XHQnMjAyMy0wOC0xMidcclxuXHQgKi9cclxuXHRmdW5jdGlvbiB3cGJjX19nZXRfX3NxbF9jbGFzc19kYXRlKCBkYXRlICl7XHJcblxyXG5cdFx0dmFyIHNxbF9jbGFzc19kYXkgPSBkYXRlLmdldEZ1bGxZZWFyKCkgKyAnLSc7XHJcblx0XHRcdHNxbF9jbGFzc19kYXkgKz0gKCAoIGRhdGUuZ2V0TW9udGgoKSArIDEgKSA8IDEwICkgPyAnMCcgOiAnJztcclxuXHRcdFx0c3FsX2NsYXNzX2RheSArPSAoIGRhdGUuZ2V0TW9udGgoKSArIDEgKSArICctJ1xyXG5cdFx0XHRzcWxfY2xhc3NfZGF5ICs9ICggZGF0ZS5nZXREYXRlKCkgPCAxMCApID8gJzAnIDogJyc7XHJcblx0XHRcdHNxbF9jbGFzc19kYXkgKz0gZGF0ZS5nZXREYXRlKCk7XHJcblxyXG5cdFx0XHRyZXR1cm4gc3FsX2NsYXNzX2RheTtcclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIEdldCBKUyBEYXRlIGZyb20gIHRoZSBTUUwgZGF0ZSBmb3JtYXQgJzIwMjQtMDUtMTQnXHJcblx0ICogQHBhcmFtIHNxbF9jbGFzc19kYXRlXHJcblx0ICogQHJldHVybnMge0RhdGV9XHJcblx0ICovXHJcblx0ZnVuY3Rpb24gd3BiY19fZ2V0X19qc19kYXRlKCBzcWxfY2xhc3NfZGF0ZSApe1xyXG5cclxuXHRcdHZhciBzcWxfY2xhc3NfZGF0ZV9hcnIgPSBzcWxfY2xhc3NfZGF0ZS5zcGxpdCggJy0nICk7XHJcblxyXG5cdFx0dmFyIGRhdGVfanMgPSBuZXcgRGF0ZSgpO1xyXG5cclxuXHRcdGRhdGVfanMuc2V0RnVsbFllYXIoIHBhcnNlSW50KCBzcWxfY2xhc3NfZGF0ZV9hcnJbIDAgXSApLCAocGFyc2VJbnQoIHNxbF9jbGFzc19kYXRlX2FyclsgMSBdICkgLSAxKSwgcGFyc2VJbnQoIHNxbF9jbGFzc19kYXRlX2FyclsgMiBdICkgKTsgIC8vIHllYXIsIG1vbnRoLCBkYXRlXHJcblxyXG5cdFx0Ly8gV2l0aG91dCB0aGlzIHRpbWUgYWRqdXN0IERhdGVzIHNlbGVjdGlvbiAgaW4gRGF0ZXBpY2tlciBjYW4gbm90IHdvcmshISFcclxuXHRcdGRhdGVfanMuc2V0SG91cnMoMCk7XHJcblx0XHRkYXRlX2pzLnNldE1pbnV0ZXMoMCk7XHJcblx0XHRkYXRlX2pzLnNldFNlY29uZHMoMCk7XHJcblx0XHRkYXRlX2pzLnNldE1pbGxpc2Vjb25kcygwKTtcclxuXHJcblx0XHRyZXR1cm4gZGF0ZV9qcztcclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIEdldCBURCBDbGFzcyBEYXRlICcxLTMxLTIwMjMnIGZyb20gIEpTIERhdGVcclxuXHQgKlxyXG5cdCAqIEBwYXJhbSBkYXRlXHRcdFx0XHRKUyBEYXRlXHJcblx0ICogQHJldHVybnMge3N0cmluZ31cdFx0JzEtMzEtMjAyMydcclxuXHQgKi9cclxuXHRmdW5jdGlvbiB3cGJjX19nZXRfX3RkX2NsYXNzX2RhdGUoIGRhdGUgKXtcclxuXHJcblx0XHR2YXIgdGRfY2xhc3NfZGF5ID0gKGRhdGUuZ2V0TW9udGgoKSArIDEpICsgJy0nICsgZGF0ZS5nZXREYXRlKCkgKyAnLScgKyBkYXRlLmdldEZ1bGxZZWFyKCk7XHRcdFx0XHRcdFx0XHRcdC8vICcxLTktMjAyMydcclxuXHJcblx0XHRyZXR1cm4gdGRfY2xhc3NfZGF5O1xyXG5cdH1cclxuXHJcblx0LyoqXHJcblx0ICogR2V0IGRhdGUgcGFyYW1zIGZyb20gIHN0cmluZyBkYXRlXHJcblx0ICpcclxuXHQgKiBAcGFyYW0gZGF0ZVx0XHRcdHN0cmluZyBkYXRlIGxpa2UgJzMxLjUuMjAyMydcclxuXHQgKiBAcGFyYW0gc2VwYXJhdG9yXHRcdGRlZmF1bHQgJy4nICBjYW4gYmUgc2tpcHBlZC5cclxuXHQgKiBAcmV0dXJucyB7ICB7ZGF0ZTogbnVtYmVyLCBtb250aDogbnVtYmVyLCB5ZWFyOiBudW1iZXJ9ICB9XHJcblx0ICovXHJcblx0ZnVuY3Rpb24gd3BiY19fZ2V0X19kYXRlX3BhcmFtc19fZnJvbV9zdHJpbmdfZGF0ZSggZGF0ZSAsIHNlcGFyYXRvcil7XHJcblxyXG5cdFx0c2VwYXJhdG9yID0gKCAndW5kZWZpbmVkJyAhPT0gdHlwZW9mIChzZXBhcmF0b3IpICkgPyBzZXBhcmF0b3IgOiAnLic7XHJcblxyXG5cdFx0dmFyIGRhdGVfYXJyID0gZGF0ZS5zcGxpdCggc2VwYXJhdG9yICk7XHJcblx0XHR2YXIgZGF0ZV9vYmogPSB7XHJcblx0XHRcdCd5ZWFyJyA6ICBwYXJzZUludCggZGF0ZV9hcnJbIDIgXSApLFxyXG5cdFx0XHQnbW9udGgnOiAocGFyc2VJbnQoIGRhdGVfYXJyWyAxIF0gKSAtIDEpLFxyXG5cdFx0XHQnZGF0ZScgOiAgcGFyc2VJbnQoIGRhdGVfYXJyWyAwIF0gKVxyXG5cdFx0fTtcclxuXHRcdHJldHVybiBkYXRlX29iajtcdFx0Ly8gZm9yIFx0XHQgPSBuZXcgRGF0ZSggZGF0ZV9vYmoueWVhciAsIGRhdGVfb2JqLm1vbnRoICwgZGF0ZV9vYmouZGF0ZSApO1xyXG5cdH1cclxuXHJcblx0LyoqXHJcblx0ICogQWRkIFNwaW4gTG9hZGVyIHRvICBjYWxlbmRhclxyXG5cdCAqIEBwYXJhbSByZXNvdXJjZV9pZFxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdwYmNfY2FsZW5kYXJfX2xvYWRpbmdfX3N0YXJ0KCByZXNvdXJjZV9pZCApe1xyXG5cdFx0aWYgKCAhIGpRdWVyeSggJyNjYWxlbmRhcl9ib29raW5nJyArIHJlc291cmNlX2lkICkubmV4dCgpLmhhc0NsYXNzKCAnd3BiY19zcGluc19sb2FkZXJfd3JhcHBlcicgKSApe1xyXG5cdFx0XHRqUXVlcnkoICcjY2FsZW5kYXJfYm9va2luZycgKyByZXNvdXJjZV9pZCApLmFmdGVyKCAnPGRpdiBjbGFzcz1cIndwYmNfc3BpbnNfbG9hZGVyX3dyYXBwZXJcIj48ZGl2IGNsYXNzPVwid3BiY19zcGluX2xvYWRlcl9vbmVfbmV3XCI+PC9kaXY+PC9kaXY+JyApO1xyXG5cdFx0fVxyXG5cdFx0aWYgKCAhIGpRdWVyeSggJyNjYWxlbmRhcl9ib29raW5nJyArIHJlc291cmNlX2lkICkuaGFzQ2xhc3MoICd3cGJjX2NhbGVuZGFyX2JsdXJfc21hbGwnICkgKXtcclxuXHRcdFx0alF1ZXJ5KCAnI2NhbGVuZGFyX2Jvb2tpbmcnICsgcmVzb3VyY2VfaWQgKS5hZGRDbGFzcyggJ3dwYmNfY2FsZW5kYXJfYmx1cl9zbWFsbCcgKTtcclxuXHRcdH1cclxuXHRcdHdwYmNfY2FsZW5kYXJfX2JsdXJfX3N0YXJ0KCByZXNvdXJjZV9pZCApO1xyXG5cdH1cclxuXHJcblx0LyoqXHJcblx0ICogUmVtb3ZlIFNwaW4gTG9hZGVyIHRvICBjYWxlbmRhclxyXG5cdCAqIEBwYXJhbSByZXNvdXJjZV9pZFxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdwYmNfY2FsZW5kYXJfX2xvYWRpbmdfX3N0b3AoIHJlc291cmNlX2lkICl7XHJcblx0XHRqUXVlcnkoICcjY2FsZW5kYXJfYm9va2luZycgKyByZXNvdXJjZV9pZCArICcgKyAud3BiY19zcGluc19sb2FkZXJfd3JhcHBlcicgKS5yZW1vdmUoKTtcclxuXHRcdGpRdWVyeSggJyNjYWxlbmRhcl9ib29raW5nJyArIHJlc291cmNlX2lkICkucmVtb3ZlQ2xhc3MoICd3cGJjX2NhbGVuZGFyX2JsdXJfc21hbGwnICk7XHJcblx0XHR3cGJjX2NhbGVuZGFyX19ibHVyX19zdG9wKCByZXNvdXJjZV9pZCApO1xyXG5cdH1cclxuXHJcblx0LyoqXHJcblx0ICogQWRkIEJsdXIgdG8gIGNhbGVuZGFyXHJcblx0ICogQHBhcmFtIHJlc291cmNlX2lkXHJcblx0ICovXHJcblx0ZnVuY3Rpb24gd3BiY19jYWxlbmRhcl9fYmx1cl9fc3RhcnQoIHJlc291cmNlX2lkICl7XHJcblx0XHRpZiAoICEgalF1ZXJ5KCAnI2NhbGVuZGFyX2Jvb2tpbmcnICsgcmVzb3VyY2VfaWQgKS5oYXNDbGFzcyggJ3dwYmNfY2FsZW5kYXJfYmx1cicgKSApe1xyXG5cdFx0XHRqUXVlcnkoICcjY2FsZW5kYXJfYm9va2luZycgKyByZXNvdXJjZV9pZCApLmFkZENsYXNzKCAnd3BiY19jYWxlbmRhcl9ibHVyJyApO1xyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0LyoqXHJcblx0ICogUmVtb3ZlIEJsdXIgaW4gIGNhbGVuZGFyXHJcblx0ICogQHBhcmFtIHJlc291cmNlX2lkXHJcblx0ICovXHJcblx0ZnVuY3Rpb24gd3BiY19jYWxlbmRhcl9fYmx1cl9fc3RvcCggcmVzb3VyY2VfaWQgKXtcclxuXHRcdGpRdWVyeSggJyNjYWxlbmRhcl9ib29raW5nJyArIHJlc291cmNlX2lkICkucmVtb3ZlQ2xhc3MoICd3cGJjX2NhbGVuZGFyX2JsdXInICk7XHJcblx0fVxyXG5cclxuXHJcblx0Ly8gLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi5cclxuXHQvKiAgPT0gIENhbGVuZGFyIFVwZGF0ZSAgLSBWaWV3ICA9PVxyXG5cdC8vIC4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uICovXHJcblxyXG5cdC8qKlxyXG5cdCAqIFVwZGF0ZSBsb29rIG9mIGNhbGVuZGFyIChzYWZlKS5cclxuXHQgKlxyXG5cdCAqIEluIEVsZW1lbnRvciBwcmV2aWV3IHRoZSBET00gY2FuIGJlIHJlLXJlbmRlcmVkLCBzbyB0aGUgY2FsZW5kYXIgZWxlbWVudCBtYXkgZXhpc3RcclxuXHQgKiB3aGlsZSB0aGUgRGF0ZXBpY2sgaW5zdGFuY2UgaXMgbWlzc2luZy4gSW4gdGhhdCBjYXNlIHRyeSB0byAocmUpaW5pdGlhbGl6ZS5cclxuXHQgKlxyXG5cdCAqIEBwYXJhbSB7aW50fHN0cmluZ30gcmVzb3VyY2VfaWRcclxuXHQgKiBAcmV0dXJuIHtib29sZWFufSB0cnVlIGlmIHVwZGF0ZWQsIGZhbHNlIGlmIG5vdCBwb3NzaWJsZVxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdwYmNfY2FsZW5kYXJfX3VwZGF0ZV9sb29rKHJlc291cmNlX2lkKSB7XHJcblxyXG5cdFx0dmFyIGluc3QgPSB3cGJjX2NhbGVuZGFyX19nZXRfaW5zdCggcmVzb3VyY2VfaWQgKTtcclxuXHJcblx0XHQvLyBJZiBpbnN0YW5jZSBtaXNzaW5nLCB0cnkgdG8gcmUtaW5pdCBjYWxlbmRhciBvbmNlLlxyXG5cdFx0aWYgKCBudWxsID09PSBpbnN0ICkge1xyXG5cclxuXHRcdFx0dmFyIGpxX2NhbCA9IGpRdWVyeSggJyNjYWxlbmRhcl9ib29raW5nJyArIHJlc291cmNlX2lkICk7XHJcblxyXG5cdFx0XHRpZiAoIGpxX2NhbC5sZW5ndGggJiYgKCdmdW5jdGlvbicgPT09IHR5cGVvZiB3cGJjX2NhbGVuZGFyX3Nob3cpICkge1xyXG5cclxuXHRcdFx0XHQvLyBFbGVtZW50b3Igc29tZXRpbWVzIGxlYXZlcyBzdGFsZSBjbGFzcyB3aXRob3V0IHJlYWwgaW5zdGFuY2UuXHJcblx0XHRcdFx0aWYgKCBqcV9jYWwuaGFzQ2xhc3MoICdoYXNEYXRlcGljaycgKSApIHtcclxuXHRcdFx0XHRcdGpxX2NhbC5yZW1vdmVDbGFzcyggJ2hhc0RhdGVwaWNrJyApO1xyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Ly8gVHJ5IHRvIGluaXQgZGF0ZXBpY2sgbWFya3VwIG5vdy5cclxuXHRcdFx0XHR3cGJjX2NhbGVuZGFyX3Nob3coIHJlc291cmNlX2lkICk7XHJcblxyXG5cdFx0XHRcdC8vIFRyeSBhZ2Fpbi5cclxuXHRcdFx0XHRpbnN0ID0gd3BiY19jYWxlbmRhcl9fZ2V0X2luc3QoIHJlc291cmNlX2lkICk7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHQvLyBTdGlsbCBubyBpbnN0YW5jZSAtPiBkbyBub3QgY3Jhc2ggdGhlIHdob2xlIGFqYXggZmxvdy5cclxuXHRcdGlmICggbnVsbCA9PT0gaW5zdCApIHtcclxuXHRcdFx0cmV0dXJuIGZhbHNlO1xyXG5cdFx0fVxyXG5cclxuXHRcdGpRdWVyeS5kYXRlcGljay5fdXBkYXRlRGF0ZXBpY2soIGluc3QgKTtcclxuXHRcdHJldHVybiB0cnVlO1xyXG5cdH1cclxuXHJcblxyXG5cclxuXHQvKipcclxuXHQgKiBVcGRhdGUgZHluYW1pY2FsbHkgTnVtYmVyIG9mIE1vbnRocyBpbiBjYWxlbmRhclxyXG5cdCAqXHJcblx0ICogQHBhcmFtIHJlc291cmNlX2lkIGludFxyXG5cdCAqIEBwYXJhbSBtb250aHNfbnVtYmVyIGludFxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdwYmNfY2FsZW5kYXJfX3VwZGF0ZV9tb250aHNfbnVtYmVyKCByZXNvdXJjZV9pZCwgbW9udGhzX251bWJlciApe1xyXG5cdFx0dmFyIGluc3QgPSB3cGJjX2NhbGVuZGFyX19nZXRfaW5zdCggcmVzb3VyY2VfaWQgKTtcclxuXHRcdGlmICggbnVsbCAhPT0gaW5zdCApe1xyXG5cdFx0XHRpbnN0LnNldHRpbmdzWyAnbnVtYmVyT2ZNb250aHMnIF0gPSBtb250aHNfbnVtYmVyO1xyXG5cdFx0XHQvL193cGJjLmNhbGVuZGFyX19zZXRfcGFyYW1fdmFsdWUoIHJlc291cmNlX2lkLCAnY2FsZW5kYXJfbnVtYmVyX29mX21vbnRocycsIG1vbnRoc19udW1iZXIgKTtcclxuXHRcdFx0d3BiY19jYWxlbmRhcl9fdXBkYXRlX2xvb2soIHJlc291cmNlX2lkICk7XHJcblx0XHR9XHJcblx0fVxyXG5cclxuXHJcblx0LyoqXHJcblx0ICogU2hvdyBjYWxlbmRhciBpbiAgZGlmZmVyZW50IFNraW5cclxuXHQgKlxyXG5cdCAqIEBwYXJhbSBzZWxlY3RlZF9za2luX3VybFxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdwYmNfX2NhbGVuZGFyX19jaGFuZ2Vfc2tpbiggc2VsZWN0ZWRfc2tpbl91cmwgKXtcclxuXHJcblx0Ly9jb25zb2xlLmxvZyggJ1NLSU4gU0VMRUNUSU9OIDo6Jywgc2VsZWN0ZWRfc2tpbl91cmwgKTtcclxuXHJcblx0XHQvLyBSZW1vdmUgQ1NTIHNraW5cclxuXHRcdHZhciBzdHlsZXNoZWV0ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoICd3cGJjLWNhbGVuZGFyLXNraW4tY3NzJyApO1xyXG5cdFx0c3R5bGVzaGVldC5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKCBzdHlsZXNoZWV0ICk7XHJcblxyXG5cclxuXHRcdC8vIEFkZCBuZXcgQ1NTIHNraW5cclxuXHRcdHZhciBoZWFkSUQgPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSggXCJoZWFkXCIgKVsgMCBdO1xyXG5cdFx0dmFyIGNzc05vZGUgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCAnbGluaycgKTtcclxuXHRcdGNzc05vZGUudHlwZSA9ICd0ZXh0L2Nzcyc7XHJcblx0XHRjc3NOb2RlLnNldEF0dHJpYnV0ZSggXCJpZFwiLCBcIndwYmMtY2FsZW5kYXItc2tpbi1jc3NcIiApO1xyXG5cdFx0Y3NzTm9kZS5yZWwgPSAnc3R5bGVzaGVldCc7XHJcblx0XHRjc3NOb2RlLm1lZGlhID0gJ3NjcmVlbic7XHJcblx0XHRjc3NOb2RlLmhyZWYgPSBzZWxlY3RlZF9za2luX3VybDtcdC8vXCJodHRwOi8vYmV0YS93cC1jb250ZW50L3BsdWdpbnMvYm9va2luZy9jc3Mvc2tpbnMvZ3JlZW4tMDEuY3NzXCI7XHJcblx0XHRoZWFkSUQuYXBwZW5kQ2hpbGQoIGNzc05vZGUgKTtcclxuXHR9XHJcblxyXG5cclxuXHRmdW5jdGlvbiB3cGJjX19jc3NfX2NoYW5nZV9za2luKCBzZWxlY3RlZF9za2luX3VybCwgc3R5bGVzaGVldF9pZCA9ICd3cGJjLXRpbWVfcGlja2VyLXNraW4tY3NzJyApe1xyXG5cclxuXHRcdC8vIFJlbW92ZSBDU1Mgc2tpblxyXG5cdFx0dmFyIHN0eWxlc2hlZXQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCggc3R5bGVzaGVldF9pZCApO1xyXG5cdFx0c3R5bGVzaGVldC5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKCBzdHlsZXNoZWV0ICk7XHJcblxyXG5cclxuXHRcdC8vIEFkZCBuZXcgQ1NTIHNraW5cclxuXHRcdHZhciBoZWFkSUQgPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSggXCJoZWFkXCIgKVsgMCBdO1xyXG5cdFx0dmFyIGNzc05vZGUgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCAnbGluaycgKTtcclxuXHRcdGNzc05vZGUudHlwZSA9ICd0ZXh0L2Nzcyc7XHJcblx0XHRjc3NOb2RlLnNldEF0dHJpYnV0ZSggXCJpZFwiLCBzdHlsZXNoZWV0X2lkICk7XHJcblx0XHRjc3NOb2RlLnJlbCA9ICdzdHlsZXNoZWV0JztcclxuXHRcdGNzc05vZGUubWVkaWEgPSAnc2NyZWVuJztcclxuXHRcdGNzc05vZGUuaHJlZiA9IHNlbGVjdGVkX3NraW5fdXJsO1x0Ly9cImh0dHA6Ly9iZXRhL3dwLWNvbnRlbnQvcGx1Z2lucy9ib29raW5nL2Nzcy9za2lucy9ncmVlbi0wMS5jc3NcIjtcclxuXHRcdGhlYWRJRC5hcHBlbmRDaGlsZCggY3NzTm9kZSApO1xyXG5cdH1cclxuXHJcblxyXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuLyogID09ICBTIFUgUCBQIE8gUiBUICAgIE0gQSBUIEggID09XHJcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqL1xyXG5cclxuXHRcdC8qKlxyXG5cdFx0ICogTWVyZ2Ugc2V2ZXJhbCAgaW50ZXJzZWN0ZWQgaW50ZXJ2YWxzIG9yIHJldHVybiBub3QgaW50ZXJzZWN0ZWQ6XHJcblx0XHQgKiBbWzEsM10sWzIsNl0sWzgsMTBdLFsxNSwxOF1dICAtPiAgIFtbMSw2XSxbOCwxMF0sWzE1LDE4XV1cclxuXHRcdCAqXHJcblx0XHQgKiBAcGFyYW0gW10gaW50ZXJ2YWxzXHRcdFx0IFsgWzEsM10sWzIsNF0sWzYsOF0sWzksMTBdLFszLDddIF1cclxuXHRcdCAqIEByZXR1cm5zIFtdXHRcdFx0XHRcdCBbIFsxLDhdLFs5LDEwXSBdXHJcblx0XHQgKlxyXG5cdFx0ICogRXhtYW1wbGU6IHdwYmNfaW50ZXJ2YWxzX19tZXJnZV9pbmVyc2VjdGVkKCAgWyBbMSwzXSxbMiw0XSxbNiw4XSxbOSwxMF0sWzMsN10gXSAgKTtcclxuXHRcdCAqL1xyXG5cdFx0ZnVuY3Rpb24gd3BiY19pbnRlcnZhbHNfX21lcmdlX2luZXJzZWN0ZWQoIGludGVydmFscyApe1xyXG5cclxuXHRcdFx0aWYgKCAhIGludGVydmFscyB8fCBpbnRlcnZhbHMubGVuZ3RoID09PSAwICl7XHJcblx0XHRcdFx0cmV0dXJuIFtdO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHR2YXIgbWVyZ2VkID0gW107XHJcblx0XHRcdGludGVydmFscy5zb3J0KCBmdW5jdGlvbiAoIGEsIGIgKXtcclxuXHRcdFx0XHRyZXR1cm4gYVsgMCBdIC0gYlsgMCBdO1xyXG5cdFx0XHR9ICk7XHJcblxyXG5cdFx0XHR2YXIgbWVyZ2VkSW50ZXJ2YWwgPSBpbnRlcnZhbHNbIDAgXTtcclxuXHJcblx0XHRcdGZvciAoIHZhciBpID0gMTsgaSA8IGludGVydmFscy5sZW5ndGg7IGkrKyApe1xyXG5cdFx0XHRcdHZhciBpbnRlcnZhbCA9IGludGVydmFsc1sgaSBdO1xyXG5cclxuXHRcdFx0XHRpZiAoIGludGVydmFsWyAwIF0gPD0gbWVyZ2VkSW50ZXJ2YWxbIDEgXSApe1xyXG5cdFx0XHRcdFx0bWVyZ2VkSW50ZXJ2YWxbIDEgXSA9IE1hdGgubWF4KCBtZXJnZWRJbnRlcnZhbFsgMSBdLCBpbnRlcnZhbFsgMSBdICk7XHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRcdG1lcmdlZC5wdXNoKCBtZXJnZWRJbnRlcnZhbCApO1xyXG5cdFx0XHRcdFx0bWVyZ2VkSW50ZXJ2YWwgPSBpbnRlcnZhbDtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdG1lcmdlZC5wdXNoKCBtZXJnZWRJbnRlcnZhbCApO1xyXG5cdFx0XHRyZXR1cm4gbWVyZ2VkO1xyXG5cdFx0fVxyXG5cclxuXHJcblx0XHQvKipcclxuXHRcdCAqIElzIDIgaW50ZXJ2YWxzIGludGVyc2VjdGVkOiAgICAgICBbMzYwMTEsIDg2MzkyXSAgICA8PT4gICAgWzEsIDQzMTkyXSAgPT4gIHRydWUgICAgICAoIGludGVyc2VjdGVkIClcclxuXHRcdCAqXHJcblx0XHQgKiBHb29kIGV4cGxhbmF0aW9uICBoZXJlXHJcblx0XHQgKiBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy8zMjY5NDM0L3doYXRzLXRoZS1tb3N0LWVmZmljaWVudC13YXktdG8tdGVzdC1pZi10d28tcmFuZ2VzLW92ZXJsYXBcclxuXHRcdCAqXHJcblx0XHQgKiBAcGFyYW0gIGludGVydmFsX0EgICAtIFsgMzYwMTEsIDg2MzkyIF1cclxuXHRcdCAqIEBwYXJhbSAgaW50ZXJ2YWxfQiAgIC0gWyAgICAgMSwgNDMxOTIgXVxyXG5cdFx0ICpcclxuXHRcdCAqIEByZXR1cm4gYm9vbFxyXG5cdFx0ICovXHJcblx0XHRmdW5jdGlvbiB3cGJjX2ludGVydmFsc19faXNfaW50ZXJzZWN0ZWQoIGludGVydmFsX0EsIGludGVydmFsX0IgKSB7XHJcblxyXG5cdFx0XHRpZiAoXHJcblx0XHRcdFx0XHQoIDAgPT0gaW50ZXJ2YWxfQS5sZW5ndGggKVxyXG5cdFx0XHRcdCB8fCAoIDAgPT0gaW50ZXJ2YWxfQi5sZW5ndGggKVxyXG5cdFx0XHQpe1xyXG5cdFx0XHRcdHJldHVybiBmYWxzZTtcclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aW50ZXJ2YWxfQVsgMCBdID0gcGFyc2VJbnQoIGludGVydmFsX0FbIDAgXSApO1xyXG5cdFx0XHRpbnRlcnZhbF9BWyAxIF0gPSBwYXJzZUludCggaW50ZXJ2YWxfQVsgMSBdICk7XHJcblx0XHRcdGludGVydmFsX0JbIDAgXSA9IHBhcnNlSW50KCBpbnRlcnZhbF9CWyAwIF0gKTtcclxuXHRcdFx0aW50ZXJ2YWxfQlsgMSBdID0gcGFyc2VJbnQoIGludGVydmFsX0JbIDEgXSApO1xyXG5cclxuXHRcdFx0dmFyIGlzX2ludGVyc2VjdGVkID0gTWF0aC5tYXgoIGludGVydmFsX0FbIDAgXSwgaW50ZXJ2YWxfQlsgMCBdICkgLSBNYXRoLm1pbiggaW50ZXJ2YWxfQVsgMSBdLCBpbnRlcnZhbF9CWyAxIF0gKTtcclxuXHJcblx0XHRcdC8vIGlmICggMCA9PSBpc19pbnRlcnNlY3RlZCApIHtcclxuXHRcdFx0Ly9cdCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFN1Y2ggcmFuZ2VzIGdvaW5nIG9uZSBhZnRlciBvdGhlciwgZS5nLjogWyAxMiwgMTUgXSBhbmQgWyAxNSwgMjEgXVxyXG5cdFx0XHQvLyB9XHJcblxyXG5cdFx0XHRpZiAoIGlzX2ludGVyc2VjdGVkIDwgMCApIHtcclxuXHRcdFx0XHRyZXR1cm4gdHJ1ZTsgICAgICAgICAgICAgICAgICAgICAvLyBJTlRFUlNFQ1RFRFxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRyZXR1cm4gZmFsc2U7ICAgICAgICAgICAgICAgICAgICAgICAvLyBOb3QgaW50ZXJzZWN0ZWRcclxuXHRcdH1cclxuXHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiBHZXQgdGhlIGNsb3NldHMgQUJTIHZhbHVlIG9mIGVsZW1lbnQgaW4gYXJyYXkgdG8gdGhlIGN1cnJlbnQgbXlWYWx1ZVxyXG5cdFx0ICpcclxuXHRcdCAqIEBwYXJhbSBteVZhbHVlIFx0LSBpbnQgZWxlbWVudCB0byBzZWFyY2ggY2xvc2V0IFx0XHRcdDRcclxuXHRcdCAqIEBwYXJhbSBteUFycmF5XHQtIGFycmF5IG9mIGVsZW1lbnRzIHdoZXJlIHRvIHNlYXJjaCBcdFs1LDgsMSw3XVxyXG5cdFx0ICogQHJldHVybnMgaW50XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0NVxyXG5cdFx0ICovXHJcblx0XHRmdW5jdGlvbiB3cGJjX2dldF9hYnNfY2xvc2VzdF92YWx1ZV9pbl9hcnIoIG15VmFsdWUsIG15QXJyYXkgKXtcclxuXHJcblx0XHRcdGlmICggbXlBcnJheS5sZW5ndGggPT0gMCApeyBcdFx0XHRcdFx0XHRcdFx0Ly8gSWYgdGhlIGFycmF5IGlzIGVtcHR5IC0+IHJldHVybiAgdGhlIG15VmFsdWVcclxuXHRcdFx0XHRyZXR1cm4gbXlWYWx1ZTtcclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0dmFyIG9iaiA9IG15QXJyYXlbIDAgXTtcclxuXHRcdFx0dmFyIGRpZmYgPSBNYXRoLmFicyggbXlWYWx1ZSAtIG9iaiApOyAgICAgICAgICAgICBcdC8vIEdldCBkaXN0YW5jZSBiZXR3ZWVuICAxc3QgZWxlbWVudFxyXG5cdFx0XHR2YXIgY2xvc2V0VmFsdWUgPSBteUFycmF5WyAwIF07ICAgICAgICAgICAgICAgICAgIFx0XHRcdC8vIFNhdmUgMXN0IGVsZW1lbnRcclxuXHJcblx0XHRcdGZvciAoIHZhciBpID0gMTsgaSA8IG15QXJyYXkubGVuZ3RoOyBpKysgKXtcclxuXHRcdFx0XHRvYmogPSBteUFycmF5WyBpIF07XHJcblxyXG5cdFx0XHRcdGlmICggTWF0aC5hYnMoIG15VmFsdWUgLSBvYmogKSA8IGRpZmYgKXsgICAgIFx0XHRcdC8vIHdlIGZvdW5kIGNsb3NlciB2YWx1ZSAtPiBzYXZlIGl0XHJcblx0XHRcdFx0XHRkaWZmID0gTWF0aC5hYnMoIG15VmFsdWUgLSBvYmogKTtcclxuXHRcdFx0XHRcdGNsb3NldFZhbHVlID0gb2JqO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0cmV0dXJuIGNsb3NldFZhbHVlO1xyXG5cdFx0fVxyXG5cclxuXHJcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG4vKiAgPT0gIFQgTyBPIEwgVCBJIFAgUyAgPT1cclxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovXHJcblxyXG5cdC8qKlxyXG5cdCAqIERlZmluZSB0b29sdGlwIHRvIHNob3csICB3aGVuICBtb3VzZSBvdmVyIERhdGUgaW4gQ2FsZW5kYXJcclxuXHQgKlxyXG5cdCAqIEBwYXJhbSAgdG9vbHRpcF90ZXh0XHRcdFx0LSBUZXh0IHRvIHNob3dcdFx0XHRcdCdCb29rZWQgdGltZTogMTI6MDAgLSAxMzowMDxicj5Db3N0OiAkMjAuMDAnXHJcblx0ICogQHBhcmFtICByZXNvdXJjZV9pZFx0XHRcdC0gSUQgb2YgYm9va2luZyByZXNvdXJjZVx0JzEnXHJcblx0ICogQHBhcmFtICB0ZF9jbGFzc1x0XHRcdFx0LSBTUUwgY2xhc3NcdFx0XHRcdFx0JzEtOS0yMDIzJ1xyXG5cdCAqIEByZXR1cm5zIHtib29sZWFufVx0XHRcdFx0XHQtIGRlZmluZWQgdG8gc2hvdyBvciBub3RcclxuXHQgKi9cclxuXHRmdW5jdGlvbiB3cGJjX3NldF90b29sdGlwX19fZm9yX19jYWxlbmRhcl9kYXRlKCB0b29sdGlwX3RleHQsIHJlc291cmNlX2lkLCB0ZF9jbGFzcyApe1xyXG5cclxuXHRcdC8vVE9ETzogbWFrZSBlc2NhcGluZyBvZiB0ZXh0IGZvciBxdW90IHN5bWJvbHMsICBhbmQgSlMvSFRNTC4uLlxyXG5cclxuXHRcdGpRdWVyeSggJyNjYWxlbmRhcl9ib29raW5nJyArIHJlc291cmNlX2lkICsgJyB0ZC5jYWw0ZGF0ZS0nICsgdGRfY2xhc3MgKS5hdHRyKCAnZGF0YS1jb250ZW50JywgdG9vbHRpcF90ZXh0ICk7XHJcblxyXG5cdFx0dmFyIHRkX2VsID0galF1ZXJ5KCAnI2NhbGVuZGFyX2Jvb2tpbmcnICsgcmVzb3VyY2VfaWQgKyAnIHRkLmNhbDRkYXRlLScgKyB0ZF9jbGFzcyApLmdldCggMCApO1x0XHRcdFx0XHQvLyBGaXhJbjogOS4wLjEuMS5cclxuXHJcblx0XHRpZiAoXHJcblx0XHRcdCAgICggJ3VuZGVmaW5lZCcgIT09IHR5cGVvZih0ZF9lbCkgKVxyXG5cdFx0XHQmJiAoIHVuZGVmaW5lZCA9PSB0ZF9lbC5fdGlwcHkgKVxyXG5cdFx0XHQmJiAoICcnICE9PSB0b29sdGlwX3RleHQgKVxyXG5cdFx0KXtcclxuXHJcblx0XHRcdHdwYmNfdGlwcHkoIHRkX2VsICwge1xyXG5cdFx0XHRcdFx0Y29udGVudCggcmVmZXJlbmNlICl7XHJcblxyXG5cdFx0XHRcdFx0XHR2YXIgcG9wb3Zlcl9jb250ZW50ID0gcmVmZXJlbmNlLmdldEF0dHJpYnV0ZSggJ2RhdGEtY29udGVudCcgKTtcclxuXHJcblx0XHRcdFx0XHRcdHJldHVybiAnPGRpdiBjbGFzcz1cInBvcG92ZXIgcG9wb3Zlcl90aXBweVwiPidcclxuXHRcdFx0XHRcdFx0XHRcdFx0KyAnPGRpdiBjbGFzcz1cInBvcG92ZXItY29udGVudFwiPidcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHQrIHBvcG92ZXJfY29udGVudFxyXG5cdFx0XHRcdFx0XHRcdFx0XHQrICc8L2Rpdj4nXHJcblx0XHRcdFx0XHRcdFx0ICsgJzwvZGl2Pic7XHJcblx0XHRcdFx0XHR9LFxyXG5cdFx0XHRcdFx0YWxsb3dIVE1MICAgICAgICA6IHRydWUsXHJcblx0XHRcdFx0XHR0cmlnZ2VyXHRcdFx0IDogJ21vdXNlZW50ZXIgZm9jdXMnLFxyXG5cdFx0XHRcdFx0aW50ZXJhY3RpdmUgICAgICA6IGZhbHNlLFxyXG5cdFx0XHRcdFx0aGlkZU9uQ2xpY2sgICAgICA6IHRydWUsXHJcblx0XHRcdFx0XHRpbnRlcmFjdGl2ZUJvcmRlcjogMTAsXHJcblx0XHRcdFx0XHRtYXhXaWR0aCAgICAgICAgIDogNTUwLFxyXG5cdFx0XHRcdFx0dGhlbWUgICAgICAgICAgICA6ICd3cGJjLXRpcHB5LXRpbWVzJyxcclxuXHRcdFx0XHRcdHBsYWNlbWVudCAgICAgICAgOiAndG9wJyxcclxuXHRcdFx0XHRcdGRlbGF5XHRcdFx0IDogWzQwMCwgMF0sXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gRml4SW46IDkuNC4yLjIuXHJcblx0XHRcdFx0XHQvL2RlbGF5XHRcdFx0IDogWzAsIDk5OTk5OTk5OTldLFx0XHRcdFx0XHRcdC8vIERlYnVnZSAgdG9vbHRpcFxyXG5cdFx0XHRcdFx0aWdub3JlQXR0cmlidXRlcyA6IHRydWUsXHJcblx0XHRcdFx0XHR0b3VjaFx0XHRcdCA6IHRydWUsXHRcdFx0XHRcdFx0XHRcdC8vWydob2xkJywgNTAwXSwgLy8gNTAwbXMgZGVsYXlcdFx0XHRcdC8vIEZpeEluOiA5LjIuMS41LlxyXG5cdFx0XHRcdFx0YXBwZW5kVG86ICgpID0+IGRvY3VtZW50LmJvZHksXHJcblx0XHRcdH0pO1xyXG5cclxuXHRcdFx0cmV0dXJuICB0cnVlO1xyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiAgZmFsc2U7XHJcblx0fVxyXG5cclxuXHJcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG4vKiAgPT0gIERhdGVzIEZ1bmN0aW9ucyAgPT1cclxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovXHJcblxyXG4vKipcclxuICogR2V0IG51bWJlciBvZiBkYXRlcyBiZXR3ZWVuIDIgSlMgRGF0ZXNcclxuICpcclxuICogQHBhcmFtIGRhdGUxXHRcdEpTIERhdGVcclxuICogQHBhcmFtIGRhdGUyXHRcdEpTIERhdGVcclxuICogQHJldHVybnMge251bWJlcn1cclxuICovXHJcbmZ1bmN0aW9uIHdwYmNfZGF0ZXNfX2RheXNfYmV0d2VlbihkYXRlMSwgZGF0ZTIpIHtcclxuXHJcbiAgICAvLyBUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyBpbiBvbmUgZGF5XHJcbiAgICB2YXIgT05FX0RBWSA9IDEwMDAgKiA2MCAqIDYwICogMjQ7XHJcblxyXG4gICAgLy8gQ29udmVydCBib3RoIGRhdGVzIHRvIG1pbGxpc2Vjb25kc1xyXG4gICAgdmFyIGRhdGUxX21zID0gZGF0ZTEuZ2V0VGltZSgpO1xyXG4gICAgdmFyIGRhdGUyX21zID0gZGF0ZTIuZ2V0VGltZSgpO1xyXG5cclxuICAgIC8vIENhbGN1bGF0ZSB0aGUgZGlmZmVyZW5jZSBpbiBtaWxsaXNlY29uZHNcclxuICAgIHZhciBkaWZmZXJlbmNlX21zID0gIGRhdGUxX21zIC0gZGF0ZTJfbXM7XHJcblxyXG4gICAgLy8gQ29udmVydCBiYWNrIHRvIGRheXMgYW5kIHJldHVyblxyXG4gICAgcmV0dXJuIE1hdGgucm91bmQoZGlmZmVyZW5jZV9tcy9PTkVfREFZKTtcclxufVxyXG5cclxuXHJcbi8qKlxyXG4gKiBDaGVjayAgaWYgdGhpcyBhcnJheSAgb2YgZGF0ZXMgaXMgY29uc2VjdXRpdmUgYXJyYXkgIG9mIGRhdGVzIG9yIG5vdC5cclxuICogXHRcdGUuZy4gIFsnMjAyNC0wNS0wOScsJzIwMjQtMDUtMTknLCcyMDI0LTA1LTMwJ10gLT4gZmFsc2VcclxuICogXHRcdGUuZy4gIFsnMjAyNC0wNS0wOScsJzIwMjQtMDUtMTAnLCcyMDI0LTA1LTExJ10gLT4gdHJ1ZVxyXG4gKiBAcGFyYW0gc3FsX2RhdGVzX2Fyclx0IGFycmF5XHRcdGUuZy46IFsnMjAyNC0wNS0wOScsJzIwMjQtMDUtMTknLCcyMDI0LTA1LTMwJ11cclxuICogQHJldHVybnMge2Jvb2xlYW59XHJcbiAqL1xyXG5mdW5jdGlvbiB3cGJjX2RhdGVzX19pc19jb25zZWN1dGl2ZV9kYXRlc19hcnJfcmFuZ2UoIHNxbF9kYXRlc19hcnIgKXtcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vIEZpeEluOiAxMC4wLjAuNTAuXHJcblxyXG5cdGlmICggc3FsX2RhdGVzX2Fyci5sZW5ndGggPiAxICl7XHJcblx0XHR2YXIgcHJldmlvc19kYXRlID0gd3BiY19fZ2V0X19qc19kYXRlKCBzcWxfZGF0ZXNfYXJyWyAwIF0gKTtcclxuXHRcdHZhciBjdXJyZW50X2RhdGU7XHJcblxyXG5cdFx0Zm9yICggdmFyIGkgPSAxOyBpIDwgc3FsX2RhdGVzX2Fyci5sZW5ndGg7IGkrKyApe1xyXG5cdFx0XHRjdXJyZW50X2RhdGUgPSB3cGJjX19nZXRfX2pzX2RhdGUoIHNxbF9kYXRlc19hcnJbaV0gKTtcclxuXHJcblx0XHRcdGlmICggd3BiY19kYXRlc19fZGF5c19iZXR3ZWVuKCBjdXJyZW50X2RhdGUsIHByZXZpb3NfZGF0ZSApICE9IDEgKXtcclxuXHRcdFx0XHRyZXR1cm4gIGZhbHNlO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRwcmV2aW9zX2RhdGUgPSBjdXJyZW50X2RhdGU7XHJcblx0XHR9XHJcblx0fVxyXG5cclxuXHRyZXR1cm4gdHJ1ZTtcclxufVxyXG5cclxuXHJcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG4vKiAgPT0gIEF1dG8gRGF0ZXMgU2VsZWN0aW9uICA9PVxyXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi9cclxuXHJcbi8qKlxyXG4gKiAgPT0gSG93IHRvICB1c2UgPyA9PVxyXG4gKlxyXG4gKiAgRm9yIERhdGVzIHNlbGVjdGlvbiwgd2UgbmVlZCB0byB1c2UgdGhpcyBsb2dpYyEgICAgIFdlIG5lZWQgc2VsZWN0IHRoZSBkYXRlcyBvbmx5IGFmdGVyIGJvb2tpbmcgZGF0YSBsb2FkZWQhXHJcbiAqXHJcbiAqICBDaGVjayBleGFtcGxlIGJlbGxvdy5cclxuICpcclxuICpcdC8vIEZpcmUgb24gYWxsIGJvb2tpbmcgZGF0ZXMgbG9hZGVkXHJcbiAqXHRqUXVlcnkoICdib2R5JyApLm9uKCAnd3BiY19jYWxlbmRhcl9hanhfX2xvYWRlZF9kYXRhJywgZnVuY3Rpb24gKCBldmVudCwgbG9hZGVkX3Jlc291cmNlX2lkICl7XHJcbiAqXHJcbiAqXHRcdGlmICggbG9hZGVkX3Jlc291cmNlX2lkID09IHNlbGVjdF9kYXRlc19pbl9jYWxlbmRhcl9pZCApe1xyXG4gKlx0XHRcdHdwYmNfYXV0b19zZWxlY3RfZGF0ZXNfaW5fY2FsZW5kYXIoIHNlbGVjdF9kYXRlc19pbl9jYWxlbmRhcl9pZCwgJzIwMjQtMDUtMTUnLCAnMjAyNC0wNS0yNScgKTtcclxuICpcdFx0fVxyXG4gKlx0fSApO1xyXG4gKlxyXG4gKi9cclxuXHJcblxyXG4vKipcclxuICogVHJ5IHRvIEF1dG8gc2VsZWN0IGRhdGVzIGluIHNwZWNpZmljIGNhbGVuZGFyIGJ5IHNpbXVsYXRlZCBjbGlja3MgaW4gZGF0ZXBpY2tlclxyXG4gKlxyXG4gKiBAcGFyYW0gcmVzb3VyY2VfaWRcdFx0MVxyXG4gKiBAcGFyYW0gY2hlY2tfaW5feW1kXHRcdCcyMDI0LTA1LTA5J1x0XHRPUiAgXHRbJzIwMjQtMDUtMDknLCcyMDI0LTA1LTE5JywnMjAyNC0wNS0yMCddXHJcbiAqIEBwYXJhbSBjaGVja19vdXRfeW1kXHRcdCcyMDI0LTA1LTE1J1x0XHRPcHRpb25hbFxyXG4gKlxyXG4gKiBAcmV0dXJucyB7bnVtYmVyfVx0XHRudW1iZXIgb2Ygc2VsZWN0ZWQgZGF0ZXNcclxuICpcclxuICogXHRFeGFtcGxlIDE6XHRcdFx0XHR2YXIgbnVtX3NlbGVjdGVkX2RheXMgPSB3cGJjX2F1dG9fc2VsZWN0X2RhdGVzX2luX2NhbGVuZGFyKCAxLCAnMjAyNC0wNS0xNScsXHJcbiAqICAgICAnMjAyNC0wNS0yNScgKTsgRXhhbXBsZSAyOlx0XHRcdFx0dmFyIG51bV9zZWxlY3RlZF9kYXlzID0gd3BiY19hdXRvX3NlbGVjdF9kYXRlc19pbl9jYWxlbmRhciggMSxcclxuICogICAgIFsnMjAyNC0wNS0wOScsJzIwMjQtMDUtMTknLCcyMDI0LTA1LTIwJ10gKTtcclxuICovXHJcbmZ1bmN0aW9uIHdwYmNfYXV0b19zZWxlY3RfZGF0ZXNfaW5fY2FsZW5kYXIoIHJlc291cmNlX2lkLCBjaGVja19pbl95bWQsIGNoZWNrX291dF95bWQgPSAnJyApe1x0XHRcdFx0XHRcdFx0XHQvLyBGaXhJbjogMTAuMC4wLjQ3LlxyXG5cclxuXHRjb25zb2xlLmxvZyggJ1dQQkNfQVVUT19TRUxFQ1RfREFURVNfSU5fQ0FMRU5EQVIoIFJFU09VUkNFX0lELCBDSEVDS19JTl9ZTUQsIENIRUNLX09VVF9ZTUQgKScsIHJlc291cmNlX2lkLCBjaGVja19pbl95bWQsIGNoZWNrX291dF95bWQgKTtcclxuXHJcblx0aWYgKFxyXG5cdFx0ICAgKCAnMjEwMC0wMS0wMScgPT0gY2hlY2tfaW5feW1kIClcclxuXHRcdHx8ICggJzIxMDAtMDEtMDEnID09IGNoZWNrX291dF95bWQgKVxyXG5cdFx0fHwgKCAoICcnID09IGNoZWNrX2luX3ltZCApICYmICggJycgPT0gY2hlY2tfb3V0X3ltZCApIClcclxuXHQpe1xyXG5cdFx0cmV0dXJuIDA7XHJcblx0fVxyXG5cclxuXHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdC8vIElmIFx0Y2hlY2tfaW5feW1kICA9ICBbICcyMDI0LTA1LTA5JywnMjAyNC0wNS0xOScsJzIwMjQtMDUtMzAnIF1cdFx0XHRcdEFSUkFZIG9mIERBVEVTXHRcdFx0XHRcdFx0Ly8gRml4SW46IDEwLjAuMC41MC5cclxuXHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdHZhciBkYXRlc190b19zZWxlY3RfYXJyID0gW107XHJcblx0aWYgKCBBcnJheS5pc0FycmF5KCBjaGVja19pbl95bWQgKSApe1xyXG5cdFx0ZGF0ZXNfdG9fc2VsZWN0X2FyciA9IHdwYmNfY2xvbmVfb2JqKCBjaGVja19pbl95bWQgKTtcclxuXHJcblx0XHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHQvLyBFeGNlcHRpb25zIHRvICBzZXQgIFx0TVVMVElQTEUgREFZUyBcdG1vZGVcclxuXHRcdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdC8vIGlmIGRhdGVzIGFzIE5PVCBDT05TRUNVVElWRTogWycyMDI0LTA1LTA5JywnMjAyNC0wNS0xOScsJzIwMjQtMDUtMzAnXSwgLT4gc2V0IE1VTFRJUExFIERBWVMgbW9kZVxyXG5cdFx0aWYgKFxyXG5cdFx0XHQgICAoIGRhdGVzX3RvX3NlbGVjdF9hcnIubGVuZ3RoID4gMCApXHJcblx0XHRcdCYmICggJycgPT0gY2hlY2tfb3V0X3ltZCApXHJcblx0XHRcdCYmICggISB3cGJjX2RhdGVzX19pc19jb25zZWN1dGl2ZV9kYXRlc19hcnJfcmFuZ2UoIGRhdGVzX3RvX3NlbGVjdF9hcnIgKSApXHJcblx0XHQpe1xyXG5cdFx0XHR3cGJjX2NhbF9kYXlzX3NlbGVjdF9fbXVsdGlwbGUoIHJlc291cmNlX2lkICk7XHJcblx0XHR9XHJcblx0XHQvLyBpZiBtdWx0aXBsZSBkYXlzIHRvIHNlbGVjdCwgYnV0IGVuYWJsZWQgU0lOR0xFIGRheSBtb2RlLCAtPiBzZXQgTVVMVElQTEUgREFZUyBtb2RlXHJcblx0XHRpZiAoXHJcblx0XHRcdCAgICggZGF0ZXNfdG9fc2VsZWN0X2Fyci5sZW5ndGggPiAxIClcclxuXHRcdFx0JiYgKCAnJyA9PSBjaGVja19vdXRfeW1kIClcclxuXHRcdFx0JiYgKCAnc2luZ2xlJyA9PT0gX3dwYmMuY2FsZW5kYXJfX2dldF9wYXJhbV92YWx1ZSggcmVzb3VyY2VfaWQsICdkYXlzX3NlbGVjdF9tb2RlJyApIClcclxuXHRcdCl7XHJcblx0XHRcdHdwYmNfY2FsX2RheXNfc2VsZWN0X19tdWx0aXBsZSggcmVzb3VyY2VfaWQgKTtcclxuXHRcdH1cclxuXHRcdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdGNoZWNrX2luX3ltZCA9IGRhdGVzX3RvX3NlbGVjdF9hcnJbIDAgXTtcclxuXHRcdGlmICggJycgPT0gY2hlY2tfb3V0X3ltZCApe1xyXG5cdFx0XHRjaGVja19vdXRfeW1kID0gZGF0ZXNfdG9fc2VsZWN0X2FyclsgKGRhdGVzX3RvX3NlbGVjdF9hcnIubGVuZ3RoLTEpIF07XHJcblx0XHR9XHJcblx0fVxyXG5cdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblxyXG5cclxuXHRpZiAoICcnID09IGNoZWNrX2luX3ltZCApe1xyXG5cdFx0Y2hlY2tfaW5feW1kID0gY2hlY2tfb3V0X3ltZDtcclxuXHR9XHJcblx0aWYgKCAnJyA9PSBjaGVja19vdXRfeW1kICl7XHJcblx0XHRjaGVja19vdXRfeW1kID0gY2hlY2tfaW5feW1kO1xyXG5cdH1cclxuXHJcblx0aWYgKCAndW5kZWZpbmVkJyA9PT0gdHlwZW9mIChyZXNvdXJjZV9pZCkgKXtcclxuXHRcdHJlc291cmNlX2lkID0gJzEnO1xyXG5cdH1cclxuXHJcblxyXG5cdHZhciBpbnN0ID0gd3BiY19jYWxlbmRhcl9fZ2V0X2luc3QoIHJlc291cmNlX2lkICk7XHJcblxyXG5cdGlmICggbnVsbCAhPT0gaW5zdCApe1xyXG5cclxuXHRcdC8vIFVuc2VsZWN0IGFsbCBkYXRlcyBhbmQgc2V0ICBwcm9wZXJ0aWVzIG9mIERhdGVwaWNrXHJcblx0XHRqUXVlcnkoICcjZGF0ZV9ib29raW5nJyArIHJlc291cmNlX2lkICkudmFsKCAnJyApOyAgICAgIFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQvL0ZpeEluOiA1LjQuM1xyXG5cdFx0aW5zdC5zdGF5T3BlbiA9IGZhbHNlO1xyXG5cdFx0aW5zdC5kYXRlcyA9IFtdO1xyXG5cdFx0dmFyIGNoZWNrX2luX2pzID0gd3BiY19fZ2V0X19qc19kYXRlKCBjaGVja19pbl95bWQgKTtcclxuXHRcdHZhciB0ZF9jZWxsICAgICA9IHdwYmNfZ2V0X2NsaWNrZWRfdGQoIGluc3QuaWQsIGNoZWNrX2luX2pzICk7XHJcblxyXG5cdFx0Ly8gSXMgb21lIHR5cGUgb2YgZXJyb3IsIHRoZW4gc2VsZWN0IG11bHRpcGxlIGRheXMgc2VsZWN0aW9uICBtb2RlLlxyXG5cdFx0aWYgKCAnJyA9PT0gX3dwYmMuY2FsZW5kYXJfX2dldF9wYXJhbV92YWx1ZSggcmVzb3VyY2VfaWQsICdkYXlzX3NlbGVjdF9tb2RlJyApICkge1xyXG4gXHRcdFx0X3dwYmMuY2FsZW5kYXJfX3NldF9wYXJhbV92YWx1ZSggcmVzb3VyY2VfaWQsICdkYXlzX3NlbGVjdF9tb2RlJywgJ211bHRpcGxlJyApO1xyXG5cdFx0fVxyXG5cclxuXHJcblx0XHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdC8vICA9PSBEWU5BTUlDID09XHJcblx0XHRpZiAoICdkeW5hbWljJyA9PT0gX3dwYmMuY2FsZW5kYXJfX2dldF9wYXJhbV92YWx1ZSggcmVzb3VyY2VfaWQsICdkYXlzX3NlbGVjdF9tb2RlJyApICl7XHJcblx0XHRcdC8vIDEtc3QgY2xpY2tcclxuXHRcdFx0aW5zdC5zdGF5T3BlbiA9IGZhbHNlO1xyXG5cdFx0XHRqUXVlcnkuZGF0ZXBpY2suX3NlbGVjdERheSggdGRfY2VsbCwgJyMnICsgaW5zdC5pZCwgY2hlY2tfaW5fanMuZ2V0VGltZSgpICk7XHJcblx0XHRcdGlmICggMCA9PT0gaW5zdC5kYXRlcy5sZW5ndGggKXtcclxuXHRcdFx0XHRyZXR1cm4gMDsgIFx0XHRcdFx0XHRcdFx0XHQvLyBGaXJzdCBjbGljayAgd2FzIHVuc3VjY2Vzc2Z1bCwgc28gd2UgbXVzdCBub3QgbWFrZSBvdGhlciBjbGlja1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyAyLW5kIGNsaWNrXHJcblx0XHRcdHZhciBjaGVja19vdXRfanMgPSB3cGJjX19nZXRfX2pzX2RhdGUoIGNoZWNrX291dF95bWQgKTtcclxuXHRcdFx0dmFyIHRkX2NlbGxfb3V0ID0gd3BiY19nZXRfY2xpY2tlZF90ZCggaW5zdC5pZCwgY2hlY2tfb3V0X2pzICk7XHJcblx0XHRcdGluc3Quc3RheU9wZW4gPSB0cnVlO1xyXG5cdFx0XHRqUXVlcnkuZGF0ZXBpY2suX3NlbGVjdERheSggdGRfY2VsbF9vdXQsICcjJyArIGluc3QuaWQsIGNoZWNrX291dF9qcy5nZXRUaW1lKCkgKTtcclxuXHRcdH1cclxuXHJcblx0XHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdC8vICA9PSBGSVhFRCA9PVxyXG5cdFx0aWYgKCAgJ2ZpeGVkJyA9PT0gX3dwYmMuY2FsZW5kYXJfX2dldF9wYXJhbV92YWx1ZSggcmVzb3VyY2VfaWQsICdkYXlzX3NlbGVjdF9tb2RlJyApKSB7XHJcblx0XHRcdGpRdWVyeS5kYXRlcGljay5fc2VsZWN0RGF5KCB0ZF9jZWxsLCAnIycgKyBpbnN0LmlkLCBjaGVja19pbl9qcy5nZXRUaW1lKCkgKTtcclxuXHRcdH1cclxuXHJcblx0XHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdC8vICA9PSBTSU5HTEUgPT1cclxuXHRcdGlmICggJ3NpbmdsZScgPT09IF93cGJjLmNhbGVuZGFyX19nZXRfcGFyYW1fdmFsdWUoIHJlc291cmNlX2lkLCAnZGF5c19zZWxlY3RfbW9kZScgKSApe1xyXG5cdFx0XHQvL2pRdWVyeS5kYXRlcGljay5fcmVzdHJpY3RNaW5NYXgoIGluc3QsIGpRdWVyeS5kYXRlcGljay5fZGV0ZXJtaW5lRGF0ZSggaW5zdCwgY2hlY2tfaW5fanMsIG51bGwgKSApO1x0XHQvLyBEbyB3ZSBuZWVkIHRvIHJ1biAgdGhpcyA/IFBsZWFzZSBub3RlLCBjaGVja19pbl9qcyBtdXN0ICBoYXZlIHRpbWUsICBtaW4sIHNlYyBkZWZpbmVkIHRvIDAhXHJcblx0XHRcdGpRdWVyeS5kYXRlcGljay5fc2VsZWN0RGF5KCB0ZF9jZWxsLCAnIycgKyBpbnN0LmlkLCBjaGVja19pbl9qcy5nZXRUaW1lKCkgKTtcclxuXHRcdH1cclxuXHJcblx0XHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdC8vICA9PSBNVUxUSVBMRSA9PVxyXG5cdFx0aWYgKCAnbXVsdGlwbGUnID09PSBfd3BiYy5jYWxlbmRhcl9fZ2V0X3BhcmFtX3ZhbHVlKCByZXNvdXJjZV9pZCwgJ2RheXNfc2VsZWN0X21vZGUnICkgKXtcclxuXHJcblx0XHRcdHZhciBkYXRlc19hcnI7XHJcblxyXG5cdFx0XHRpZiAoIGRhdGVzX3RvX3NlbGVjdF9hcnIubGVuZ3RoID4gMCApe1xyXG5cdFx0XHRcdC8vIFNpdHVhdGlvbiwgd2hlbiB3ZSBoYXZlIGRhdGVzIGFycmF5OiBbJzIwMjQtMDUtMDknLCcyMDI0LTA1LTE5JywnMjAyNC0wNS0zMCddLiAgYW5kIG5vdCB0aGUgQ2hlY2sgSW4gLyBDaGVjayAgb3V0IGRhdGVzIGFzIHBhcmFtZXRlciBpbiB0aGlzIGZ1bmN0aW9uXHJcblx0XHRcdFx0ZGF0ZXNfYXJyID0gd3BiY19nZXRfc2VsZWN0aW9uX2RhdGVzX2pzX3N0cl9hcnJfX2Zyb21fYXJyKCBkYXRlc190b19zZWxlY3RfYXJyICk7XHJcblx0XHRcdH0gZWxzZSB7XHJcblx0XHRcdFx0ZGF0ZXNfYXJyID0gd3BiY19nZXRfc2VsZWN0aW9uX2RhdGVzX2pzX3N0cl9hcnJfX2Zyb21fY2hlY2tfaW5fb3V0KCBjaGVja19pbl95bWQsIGNoZWNrX291dF95bWQsIGluc3QgKTtcclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCAwID09PSBkYXRlc19hcnIuZGF0ZXNfanMubGVuZ3RoICl7XHJcblx0XHRcdFx0cmV0dXJuIDA7XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIEZvciBDYWxlbmRhciBEYXlzIHNlbGVjdGlvblxyXG5cdFx0XHRmb3IgKCB2YXIgaiA9IDA7IGogPCBkYXRlc19hcnIuZGF0ZXNfanMubGVuZ3RoOyBqKysgKXsgICAgICAgLy8gTG9vcCBhcnJheSBvZiBkYXRlc1xyXG5cclxuXHRcdFx0XHR2YXIgc3RyX2RhdGUgPSB3cGJjX19nZXRfX3NxbF9jbGFzc19kYXRlKCBkYXRlc19hcnIuZGF0ZXNfanNbIGogXSApO1xyXG5cclxuXHRcdFx0XHQvLyBEYXRlIHVuYXZhaWxhYmxlICFcclxuXHRcdFx0XHRpZiAoIDAgPT0gX3dwYmMuYm9va2luZ3NfaW5fY2FsZW5kYXJfX2dldF9mb3JfZGF0ZSggcmVzb3VyY2VfaWQsIHN0cl9kYXRlICkuZGF5X2F2YWlsYWJpbGl0eSApe1xyXG5cdFx0XHRcdFx0cmV0dXJuIDA7XHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRpZiAoIGRhdGVzX2Fyci5kYXRlc19qc1sgaiBdICE9IC0xICkge1xyXG5cdFx0XHRcdFx0aW5zdC5kYXRlcy5wdXNoKCBkYXRlc19hcnIuZGF0ZXNfanNbIGogXSApO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0dmFyIGNoZWNrX291dF9kYXRlID0gZGF0ZXNfYXJyLmRhdGVzX2pzWyAoZGF0ZXNfYXJyLmRhdGVzX2pzLmxlbmd0aCAtIDEpIF07XHJcblxyXG5cdFx0XHRpbnN0LmRhdGVzLnB1c2goIGNoZWNrX291dF9kYXRlICk7IFx0XHRcdC8vIE5lZWQgYWRkIG9uZSBhZGRpdGlvbmFsIFNBTUUgZGF0ZSBmb3IgY29ycmVjdCAgd29ya3Mgb2YgZGF0ZXMgc2VsZWN0aW9uICEhISEhXHJcblxyXG5cdFx0XHR2YXIgY2hlY2tvdXRfdGltZXN0YW1wID0gY2hlY2tfb3V0X2RhdGUuZ2V0VGltZSgpO1xyXG5cdFx0XHR2YXIgdGRfY2VsbCA9IHdwYmNfZ2V0X2NsaWNrZWRfdGQoIGluc3QuaWQsIGNoZWNrX291dF9kYXRlICk7XHJcblxyXG5cdFx0XHRqUXVlcnkuZGF0ZXBpY2suX3NlbGVjdERheSggdGRfY2VsbCwgJyMnICsgaW5zdC5pZCwgY2hlY2tvdXRfdGltZXN0YW1wICk7XHJcblx0XHR9XHJcblxyXG5cclxuXHRcdGlmICggMCAhPT0gaW5zdC5kYXRlcy5sZW5ndGggKXtcclxuXHRcdFx0Ly8gU2Nyb2xsIHRvIHNwZWNpZmljIG1vbnRoLCBpZiB3ZSBzZXQgZGF0ZXMgaW4gc29tZSBmdXR1cmUgbW9udGhzXHJcblx0XHRcdHdwYmNfY2FsZW5kYXJfX3Njcm9sbF90byggcmVzb3VyY2VfaWQsIGluc3QuZGF0ZXNbIDAgXS5nZXRGdWxsWWVhcigpLCBpbnN0LmRhdGVzWyAwIF0uZ2V0TW9udGgoKSsxICk7XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGluc3QuZGF0ZXMubGVuZ3RoO1xyXG5cdH1cclxuXHJcblx0cmV0dXJuIDA7XHJcbn1cclxuXHJcblx0LyoqXHJcblx0ICogR2V0IEhUTUwgdGQgZWxlbWVudCAod2hlcmUgd2FzIGNsaWNrIGluIGNhbGVuZGFyICBkYXkgIGNlbGwpXHJcblx0ICpcclxuXHQgKiBAcGFyYW0gY2FsZW5kYXJfaHRtbF9pZFx0XHRcdCdjYWxlbmRhcl9ib29raW5nMSdcclxuXHQgKiBAcGFyYW0gZGF0ZV9qc1x0XHRcdFx0XHRKUyBEYXRlXHJcblx0ICogQHJldHVybnMgeyp8alF1ZXJ5fVx0XHRcdFx0RG9tIEhUTUwgdGQgZWxlbWVudFxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdwYmNfZ2V0X2NsaWNrZWRfdGQoIGNhbGVuZGFyX2h0bWxfaWQsIGRhdGVfanMgKXtcclxuXHJcblx0ICAgIHZhciB0ZF9jZWxsID0galF1ZXJ5KCAnIycgKyBjYWxlbmRhcl9odG1sX2lkICsgJyAuc3FsX2RhdGVfJyArIHdwYmNfX2dldF9fc3FsX2NsYXNzX2RhdGUoIGRhdGVfanMgKSApLmdldCggMCApO1xyXG5cclxuXHRcdHJldHVybiB0ZF9jZWxsO1xyXG5cdH1cclxuXHJcblx0LyoqXHJcblx0ICogR2V0IGFycmF5cyBvZiBKUyBhbmQgU1FMIGRhdGVzIGFzIGRhdGVzIGFycmF5XHJcblx0ICpcclxuXHQgKiBAcGFyYW0gY2hlY2tfaW5feW1kXHRcdFx0XHRcdFx0XHQnMjAyNC0wNS0xNSdcclxuXHQgKiBAcGFyYW0gY2hlY2tfb3V0X3ltZFx0XHRcdFx0XHRcdFx0JzIwMjQtMDUtMjUnXHJcblx0ICogQHBhcmFtIGluc3RcdFx0XHRcdFx0XHRcdFx0XHREYXRlcGljayBJbnN0LiBVc2Ugd3BiY19jYWxlbmRhcl9fZ2V0X2luc3QoIHJlc291cmNlX2lkICk7XHJcblx0ICogQHJldHVybnMge3tkYXRlc19qczogKltdLCBkYXRlc19zdHI6ICpbXX19XHJcblx0ICovXHJcblx0ZnVuY3Rpb24gd3BiY19nZXRfc2VsZWN0aW9uX2RhdGVzX2pzX3N0cl9hcnJfX2Zyb21fY2hlY2tfaW5fb3V0KCBjaGVja19pbl95bWQsIGNoZWNrX291dF95bWQgLCBpbnN0ICl7XHJcblxyXG5cdFx0dmFyIG9yaWdpbmFsX2FycmF5ID0gW107XHJcblx0XHR2YXIgZGF0ZTtcclxuXHRcdHZhciBia19kaXN0aW5jdF9kYXRlcyA9IFtdO1xyXG5cclxuXHRcdHZhciBjaGVja19pbl9kYXRlID0gY2hlY2tfaW5feW1kLnNwbGl0KCAnLScgKTtcclxuXHRcdHZhciBjaGVja19vdXRfZGF0ZSA9IGNoZWNrX291dF95bWQuc3BsaXQoICctJyApO1xyXG5cclxuXHRcdGRhdGUgPSBuZXcgRGF0ZSgpO1xyXG5cdFx0ZGF0ZS5zZXRGdWxsWWVhciggY2hlY2tfaW5fZGF0ZVsgMCBdLCAoY2hlY2tfaW5fZGF0ZVsgMSBdIC0gMSksIGNoZWNrX2luX2RhdGVbIDIgXSApOyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHllYXIsIG1vbnRoLCBkYXRlXHJcblx0XHR2YXIgb3JpZ2luYWxfY2hlY2tfaW5fZGF0ZSA9IGRhdGU7XHJcblx0XHRvcmlnaW5hbF9hcnJheS5wdXNoKCBqUXVlcnkuZGF0ZXBpY2suX3Jlc3RyaWN0TWluTWF4KCBpbnN0LCBqUXVlcnkuZGF0ZXBpY2suX2RldGVybWluZURhdGUoIGluc3QsIGRhdGUsIG51bGwgKSApICk7IC8vYWRkIGRhdGVcclxuXHRcdGlmICggISB3cGJjX2luX2FycmF5KCBia19kaXN0aW5jdF9kYXRlcywgKGNoZWNrX2luX2RhdGVbIDIgXSArICcuJyArIGNoZWNrX2luX2RhdGVbIDEgXSArICcuJyArIGNoZWNrX2luX2RhdGVbIDAgXSkgKSApe1xyXG5cdFx0XHRia19kaXN0aW5jdF9kYXRlcy5wdXNoKCBwYXJzZUludChjaGVja19pbl9kYXRlWyAyIF0pICsgJy4nICsgcGFyc2VJbnQoY2hlY2tfaW5fZGF0ZVsgMSBdKSArICcuJyArIGNoZWNrX2luX2RhdGVbIDAgXSApO1xyXG5cdFx0fVxyXG5cclxuXHRcdHZhciBkYXRlX291dCA9IG5ldyBEYXRlKCk7XHJcblx0XHRkYXRlX291dC5zZXRGdWxsWWVhciggY2hlY2tfb3V0X2RhdGVbIDAgXSwgKGNoZWNrX291dF9kYXRlWyAxIF0gLSAxKSwgY2hlY2tfb3V0X2RhdGVbIDIgXSApOyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHllYXIsIG1vbnRoLCBkYXRlXHJcblx0XHR2YXIgb3JpZ2luYWxfY2hlY2tfb3V0X2RhdGUgPSBkYXRlX291dDtcclxuXHJcblx0XHR2YXIgbWV3RGF0ZSA9IG5ldyBEYXRlKCBvcmlnaW5hbF9jaGVja19pbl9kYXRlLmdldEZ1bGxZZWFyKCksIG9yaWdpbmFsX2NoZWNrX2luX2RhdGUuZ2V0TW9udGgoKSwgb3JpZ2luYWxfY2hlY2tfaW5fZGF0ZS5nZXREYXRlKCkgKTtcclxuXHRcdG1ld0RhdGUuc2V0RGF0ZSggb3JpZ2luYWxfY2hlY2tfaW5fZGF0ZS5nZXREYXRlKCkgKyAxICk7XHJcblxyXG5cdFx0d2hpbGUgKFxyXG5cdFx0XHQob3JpZ2luYWxfY2hlY2tfb3V0X2RhdGUgPiBkYXRlKSAmJlxyXG5cdFx0XHQob3JpZ2luYWxfY2hlY2tfaW5fZGF0ZSAhPSBvcmlnaW5hbF9jaGVja19vdXRfZGF0ZSkgKXtcclxuXHRcdFx0ZGF0ZSA9IG5ldyBEYXRlKCBtZXdEYXRlLmdldEZ1bGxZZWFyKCksIG1ld0RhdGUuZ2V0TW9udGgoKSwgbWV3RGF0ZS5nZXREYXRlKCkgKTtcclxuXHJcblx0XHRcdG9yaWdpbmFsX2FycmF5LnB1c2goIGpRdWVyeS5kYXRlcGljay5fcmVzdHJpY3RNaW5NYXgoIGluc3QsIGpRdWVyeS5kYXRlcGljay5fZGV0ZXJtaW5lRGF0ZSggaW5zdCwgZGF0ZSwgbnVsbCApICkgKTsgLy9hZGQgZGF0ZVxyXG5cdFx0XHRpZiAoICF3cGJjX2luX2FycmF5KCBia19kaXN0aW5jdF9kYXRlcywgKGRhdGUuZ2V0RGF0ZSgpICsgJy4nICsgcGFyc2VJbnQoIGRhdGUuZ2V0TW9udGgoKSArIDEgKSArICcuJyArIGRhdGUuZ2V0RnVsbFllYXIoKSkgKSApe1xyXG5cdFx0XHRcdGJrX2Rpc3RpbmN0X2RhdGVzLnB1c2goIChwYXJzZUludChkYXRlLmdldERhdGUoKSkgKyAnLicgKyBwYXJzZUludCggZGF0ZS5nZXRNb250aCgpICsgMSApICsgJy4nICsgZGF0ZS5nZXRGdWxsWWVhcigpKSApO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRtZXdEYXRlID0gbmV3IERhdGUoIGRhdGUuZ2V0RnVsbFllYXIoKSwgZGF0ZS5nZXRNb250aCgpLCBkYXRlLmdldERhdGUoKSApO1xyXG5cdFx0XHRtZXdEYXRlLnNldERhdGUoIG1ld0RhdGUuZ2V0RGF0ZSgpICsgMSApO1xyXG5cdFx0fVxyXG5cdFx0b3JpZ2luYWxfYXJyYXkucG9wKCk7XHJcblx0XHRia19kaXN0aW5jdF9kYXRlcy5wb3AoKTtcclxuXHJcblx0XHRyZXR1cm4geydkYXRlc19qcyc6IG9yaWdpbmFsX2FycmF5LCAnZGF0ZXNfc3RyJzogYmtfZGlzdGluY3RfZGF0ZXN9O1xyXG5cdH1cclxuXHJcblx0LyoqXHJcblx0ICogR2V0IGFycmF5cyBvZiBKUyBhbmQgU1FMIGRhdGVzIGFzIGRhdGVzIGFycmF5XHJcblx0ICpcclxuXHQgKiBAcGFyYW0gZGF0ZXNfdG9fc2VsZWN0X2Fyclx0PSBbJzIwMjQtMDUtMDknLCcyMDI0LTA1LTE5JywnMjAyNC0wNS0zMCddXHJcblx0ICpcclxuXHQgKiBAcmV0dXJucyB7e2RhdGVzX2pzOiAqW10sIGRhdGVzX3N0cjogKltdfX1cclxuXHQgKi9cclxuXHRmdW5jdGlvbiB3cGJjX2dldF9zZWxlY3Rpb25fZGF0ZXNfanNfc3RyX2Fycl9fZnJvbV9hcnIoIGRhdGVzX3RvX3NlbGVjdF9hcnIgKXtcdFx0XHRcdFx0XHRcdFx0XHRcdC8vIEZpeEluOiAxMC4wLjAuNTAuXHJcblxyXG5cdFx0dmFyIG9yaWdpbmFsX2FycmF5ICAgID0gW107XHJcblx0XHR2YXIgYmtfZGlzdGluY3RfZGF0ZXMgPSBbXTtcclxuXHRcdHZhciBvbmVfZGF0ZV9zdHI7XHJcblxyXG5cdFx0Zm9yICggdmFyIGQgPSAwOyBkIDwgZGF0ZXNfdG9fc2VsZWN0X2Fyci5sZW5ndGg7IGQrKyApe1xyXG5cclxuXHRcdFx0b3JpZ2luYWxfYXJyYXkucHVzaCggd3BiY19fZ2V0X19qc19kYXRlKCBkYXRlc190b19zZWxlY3RfYXJyWyBkIF0gKSApO1xyXG5cclxuXHRcdFx0b25lX2RhdGVfc3RyID0gZGF0ZXNfdG9fc2VsZWN0X2FyclsgZCBdLnNwbGl0KCctJylcclxuXHRcdFx0aWYgKCAhIHdwYmNfaW5fYXJyYXkoIGJrX2Rpc3RpbmN0X2RhdGVzLCAob25lX2RhdGVfc3RyWyAyIF0gKyAnLicgKyBvbmVfZGF0ZV9zdHJbIDEgXSArICcuJyArIG9uZV9kYXRlX3N0clsgMCBdKSApICl7XHJcblx0XHRcdFx0YmtfZGlzdGluY3RfZGF0ZXMucHVzaCggcGFyc2VJbnQob25lX2RhdGVfc3RyWyAyIF0pICsgJy4nICsgcGFyc2VJbnQob25lX2RhdGVfc3RyWyAxIF0pICsgJy4nICsgb25lX2RhdGVfc3RyWyAwIF0gKTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB7J2RhdGVzX2pzJzogb3JpZ2luYWxfYXJyYXksICdkYXRlc19zdHInOiBvcmlnaW5hbF9hcnJheX07XHJcblx0fVxyXG5cclxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcbi8qICA9PSAgQXV0byBGaWxsIEZpZWxkcyAvIEF1dG8gU2VsZWN0IERhdGVzICA9PVxyXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0gKi9cclxuXHJcbmpRdWVyeSggZG9jdW1lbnQgKS5yZWFkeSggZnVuY3Rpb24gKCl7XHJcblxyXG5cdHZhciB1cmxfcGFyYW1zID0gbmV3IFVSTFNlYXJjaFBhcmFtcyggd2luZG93LmxvY2F0aW9uLnNlYXJjaCApO1xyXG5cclxuXHQvLyBEaXNhYmxlIGRheXMgc2VsZWN0aW9uICBpbiBjYWxlbmRhciwgIGFmdGVyICByZWRpcmVjdGlvbiAgZnJvbSAgdGhlIFwiU2VhcmNoIHJlc3VsdHMgcGFnZSwgIGFmdGVyICBzZWFyY2ggIGF2YWlsYWJpbGl0eVwiIFx0XHRcdC8vIEZpeEluOiA4LjguMi4zLlxyXG5cdGlmICAoICdPbicgIT0gX3dwYmMuZ2V0X290aGVyX3BhcmFtKCAnaXNfZW5hYmxlZF9ib29raW5nX3NlYXJjaF9yZXN1bHRzX2RheXNfc2VsZWN0JyApICkge1xyXG5cdFx0aWYgKFxyXG5cdFx0XHQoIHVybF9wYXJhbXMuaGFzKCAnd3BiY19zZWxlY3RfY2hlY2tfaW4nICkgKSAmJlxyXG5cdFx0XHQoIHVybF9wYXJhbXMuaGFzKCAnd3BiY19zZWxlY3RfY2hlY2tfb3V0JyApICkgJiZcclxuXHRcdFx0KCB1cmxfcGFyYW1zLmhhcyggJ3dwYmNfc2VsZWN0X2NhbGVuZGFyX2lkJyApIClcclxuXHRcdCl7XHJcblxyXG5cdFx0XHR2YXIgc2VsZWN0X2RhdGVzX2luX2NhbGVuZGFyX2lkID0gcGFyc2VJbnQoIHVybF9wYXJhbXMuZ2V0KCAnd3BiY19zZWxlY3RfY2FsZW5kYXJfaWQnICkgKTtcclxuXHJcblx0XHRcdC8vIEZpcmUgb24gYWxsIGJvb2tpbmcgZGF0ZXMgbG9hZGVkXHJcblx0XHRcdGpRdWVyeSggJ2JvZHknICkub24oICd3cGJjX2NhbGVuZGFyX2FqeF9fbG9hZGVkX2RhdGEnLCBmdW5jdGlvbiAoIGV2ZW50LCBsb2FkZWRfcmVzb3VyY2VfaWQgKXtcclxuXHJcblx0XHRcdFx0aWYgKCBsb2FkZWRfcmVzb3VyY2VfaWQgPT0gc2VsZWN0X2RhdGVzX2luX2NhbGVuZGFyX2lkICl7XHJcblx0XHRcdFx0XHR3cGJjX2F1dG9fc2VsZWN0X2RhdGVzX2luX2NhbGVuZGFyKCBzZWxlY3RfZGF0ZXNfaW5fY2FsZW5kYXJfaWQsIHVybF9wYXJhbXMuZ2V0KCAnd3BiY19zZWxlY3RfY2hlY2tfaW4nICksIHVybF9wYXJhbXMuZ2V0KCAnd3BiY19zZWxlY3RfY2hlY2tfb3V0JyApICk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9ICk7XHJcblx0XHR9XHJcblx0fVxyXG5cclxuXHRpZiAoIHVybF9wYXJhbXMuaGFzKCAnd3BiY19hdXRvX2ZpbGwnICkgKXtcclxuXHJcblx0XHR2YXIgd3BiY19hdXRvX2ZpbGxfdmFsdWUgPSB1cmxfcGFyYW1zLmdldCggJ3dwYmNfYXV0b19maWxsJyApO1xyXG5cclxuXHRcdC8vIENvbnZlcnQgYmFjay4gICAgIFNvbWUgc3lzdGVtcyBkbyBub3QgbGlrZSBzeW1ib2wgJ34nIGluIFVSTCwgc28gIHdlIG5lZWQgdG8gcmVwbGFjZSB0byAgc29tZSBvdGhlciBzeW1ib2xzXHJcblx0XHR3cGJjX2F1dG9fZmlsbF92YWx1ZSA9IHdwYmNfYXV0b19maWxsX3ZhbHVlLnJlcGxhY2VBbGwoICdfXl8nLCAnficgKTtcclxuXHJcblx0XHR3cGJjX2F1dG9fZmlsbF9ib29raW5nX2ZpZWxkcyggd3BiY19hdXRvX2ZpbGxfdmFsdWUgKTtcclxuXHR9XHJcblxyXG59ICk7XHJcblxyXG4vKipcclxuICogQXV0b2ZpbGwgLyBzZWxlY3QgYm9va2luZyBmb3JtICBmaWVsZHMgYnkgIHZhbHVlcyBmcm9tICB0aGUgR0VUIHJlcXVlc3QgIHBhcmFtZXRlcjogP3dwYmNfYXV0b19maWxsPVxyXG4gKlxyXG4gKiBAcGFyYW0gYXV0b19maWxsX3N0clxyXG4gKi9cclxuZnVuY3Rpb24gd3BiY19hdXRvX2ZpbGxfYm9va2luZ19maWVsZHMoIGF1dG9fZmlsbF9zdHIgKXtcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vIEZpeEluOiAxMC4wLjAuNDguXHJcblxyXG5cdGlmICggJycgPT0gYXV0b19maWxsX3N0ciApe1xyXG5cdFx0cmV0dXJuO1xyXG5cdH1cclxuXHJcbi8vIGNvbnNvbGUubG9nKCAnV1BCQ19BVVRPX0ZJTExfQk9PS0lOR19GSUVMRFMoIEFVVE9fRklMTF9TVFIgKScsIGF1dG9fZmlsbF9zdHIpO1xyXG5cclxuXHR2YXIgZmllbGRzX2FyciA9IHdwYmNfYXV0b19maWxsX2Jvb2tpbmdfZmllbGRzX19wYXJzZSggYXV0b19maWxsX3N0ciApO1xyXG5cclxuXHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBmaWVsZHNfYXJyLmxlbmd0aDsgaSsrICl7XHJcblx0XHRqUXVlcnkoICdbbmFtZT1cIicgKyBmaWVsZHNfYXJyWyBpIF1bICduYW1lJyBdICsgJ1wiXScgKS52YWwoIGZpZWxkc19hcnJbIGkgXVsgJ3ZhbHVlJyBdICk7XHJcblx0fVxyXG59XHJcblxyXG5cdC8qKlxyXG5cdCAqIFBhcnNlIGRhdGEgZnJvbSAgZ2V0IHBhcmFtZXRlcjpcdD93cGJjX2F1dG9fZmlsbD12aXNpdG9yczIzMV4yfm1heF9jYXBhY2l0eTIzMV4yXHJcblx0ICpcclxuXHQgKiBAcGFyYW0gZGF0YV9zdHIgICAgICA9ICAgJ3Zpc2l0b3JzMjMxXjJ+bWF4X2NhcGFjaXR5MjMxXjInO1xyXG5cdCAqIEByZXR1cm5zIHsqfVxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdwYmNfYXV0b19maWxsX2Jvb2tpbmdfZmllbGRzX19wYXJzZSggZGF0YV9zdHIgKXtcclxuXHJcblx0XHR2YXIgZmlsdGVyX29wdGlvbnNfYXJyID0gW107XHJcblxyXG5cdFx0dmFyIGRhdGFfYXJyID0gZGF0YV9zdHIuc3BsaXQoICd+JyApO1xyXG5cclxuXHRcdGZvciAoIHZhciBqID0gMDsgaiA8IGRhdGFfYXJyLmxlbmd0aDsgaisrICl7XHJcblxyXG5cdFx0XHR2YXIgbXlfZm9ybV9maWVsZCA9IGRhdGFfYXJyWyBqIF0uc3BsaXQoICdeJyApO1xyXG5cclxuXHRcdFx0dmFyIGZpbHRlcl9uYW1lICA9ICgndW5kZWZpbmVkJyAhPT0gdHlwZW9mIChteV9mb3JtX2ZpZWxkWyAwIF0pKSA/IG15X2Zvcm1fZmllbGRbIDAgXSA6ICcnO1xyXG5cdFx0XHR2YXIgZmlsdGVyX3ZhbHVlID0gKCd1bmRlZmluZWQnICE9PSB0eXBlb2YgKG15X2Zvcm1fZmllbGRbIDEgXSkpID8gbXlfZm9ybV9maWVsZFsgMSBdIDogJyc7XHJcblxyXG5cdFx0XHRmaWx0ZXJfb3B0aW9uc19hcnIucHVzaChcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHR7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnbmFtZScgIDogZmlsdGVyX25hbWUsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHQndmFsdWUnIDogZmlsdGVyX3ZhbHVlXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHRcdFx0ICAgKTtcclxuXHRcdH1cclxuXHRcdHJldHVybiBmaWx0ZXJfb3B0aW9uc19hcnI7XHJcblx0fVxyXG5cclxuXHQvKipcclxuXHQgKiBQYXJzZSBkYXRhIGZyb20gIGdldCBwYXJhbWV0ZXI6XHQ/c2VhcmNoX2dldF9fY3VzdG9tX3BhcmFtcz0uLi5cclxuXHQgKlxyXG5cdCAqIEBwYXJhbSBkYXRhX3N0ciAgICAgID0gICAndGV4dF5zZWFyY2hfZmllbGRfX2Rpc3BsYXlfY2hlY2tfaW5eMjMuMDUuMjAyNH50ZXh0XnNlYXJjaF9maWVsZF9fZGlzcGxheV9jaGVja19vdXReMjYuMDUuMjAyNH5zZWxlY3Rib3gtb25lXnNlYXJjaF9xdWFudGl0eV4yfnNlbGVjdGJveC1vbmVebG9jYXRpb25eU3BhaW5+c2VsZWN0Ym94LW9uZV5tYXhfY2FwYWNpdHleMn5zZWxlY3Rib3gtb25lXmFtZW5pdHlecGFya2luZ35jaGVja2JveF5zZWFyY2hfZmllbGRfX2V4dGVuZF9zZWFyY2hfZGF5c141fnN1Ym1pdF5eU2VhcmNofmhpZGRlbl5zZWFyY2hfZ2V0X19jaGVja19pbl95bWReMjAyNC0wNS0yM35oaWRkZW5ec2VhcmNoX2dldF9fY2hlY2tfb3V0X3ltZF4yMDI0LTA1LTI2fmhpZGRlbl5zZWFyY2hfZ2V0X190aW1lXn5oaWRkZW5ec2VhcmNoX2dldF9fcXVhbnRpdHleMn5oaWRkZW5ec2VhcmNoX2dldF9fZXh0ZW5kXjV+aGlkZGVuXnNlYXJjaF9nZXRfX3VzZXJzX2lkXn5oaWRkZW5ec2VhcmNoX2dldF9fY3VzdG9tX3BhcmFtc15+JztcclxuXHQgKiBAcmV0dXJucyB7Kn1cclxuXHQgKi9cclxuXHRmdW5jdGlvbiB3cGJjX2F1dG9fZmlsbF9zZWFyY2hfZmllbGRzX19wYXJzZSggZGF0YV9zdHIgKXtcclxuXHJcblx0XHR2YXIgZmlsdGVyX29wdGlvbnNfYXJyID0gW107XHJcblxyXG5cdFx0dmFyIGRhdGFfYXJyID0gZGF0YV9zdHIuc3BsaXQoICd+JyApO1xyXG5cclxuXHRcdGZvciAoIHZhciBqID0gMDsgaiA8IGRhdGFfYXJyLmxlbmd0aDsgaisrICl7XHJcblxyXG5cdFx0XHR2YXIgbXlfZm9ybV9maWVsZCA9IGRhdGFfYXJyWyBqIF0uc3BsaXQoICdeJyApO1xyXG5cclxuXHRcdFx0dmFyIGZpbHRlcl90eXBlICA9ICgndW5kZWZpbmVkJyAhPT0gdHlwZW9mIChteV9mb3JtX2ZpZWxkWyAwIF0pKSA/IG15X2Zvcm1fZmllbGRbIDAgXSA6ICcnO1xyXG5cdFx0XHR2YXIgZmlsdGVyX25hbWUgID0gKCd1bmRlZmluZWQnICE9PSB0eXBlb2YgKG15X2Zvcm1fZmllbGRbIDEgXSkpID8gbXlfZm9ybV9maWVsZFsgMSBdIDogJyc7XHJcblx0XHRcdHZhciBmaWx0ZXJfdmFsdWUgPSAoJ3VuZGVmaW5lZCcgIT09IHR5cGVvZiAobXlfZm9ybV9maWVsZFsgMiBdKSkgPyBteV9mb3JtX2ZpZWxkWyAyIF0gOiAnJztcclxuXHJcblx0XHRcdGZpbHRlcl9vcHRpb25zX2Fyci5wdXNoKFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdHtcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdCd0eXBlJyAgOiBmaWx0ZXJfdHlwZSxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdCduYW1lJyAgOiBmaWx0ZXJfbmFtZSxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdCd2YWx1ZScgOiBmaWx0ZXJfdmFsdWVcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHRcdFx0XHQgICApO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIGZpbHRlcl9vcHRpb25zX2FycjtcclxuXHR9XHJcblxyXG5cclxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcbi8qICA9PSAgQXV0byBVcGRhdGUgbnVtYmVyIG9mIG1vbnRocyBpbiBjYWxlbmRhcnMgT04gc2NyZWVuIHNpemUgY2hhbmdlZCAgPT1cclxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovXHJcblxyXG4vKipcclxuICogQXV0byBVcGRhdGUgTnVtYmVyIG9mIE1vbnRocyBpbiBDYWxlbmRhciwgZS5nLjogIFx0XHRpZiAgICAoIFdJTkRPV19XSURUSCA8PSA3ODJweCApICAgPj4+IFx0TU9OVEhTX05VTUJFUiA9IDFcclxuICogICBFTFNFOiAgbnVtYmVyIG9mIG1vbnRocyBkZWZpbmVkIGluIHNob3J0Y29kZS5cclxuICogQHBhcmFtIHJlc291cmNlX2lkIGludFxyXG4gKlxyXG4gKi9cclxuZnVuY3Rpb24gd3BiY19jYWxlbmRhcl9fYXV0b191cGRhdGVfbW9udGhzX251bWJlcl9fb25fcmVzaXplKCByZXNvdXJjZV9pZCApe1xyXG5cclxuXHRpZiAoIHRydWUgPT09IF93cGJjLmdldF9vdGhlcl9wYXJhbSggJ2lzX2FsbG93X3NldmVyYWxfbW9udGhzX29uX21vYmlsZScgKSApIHtcclxuXHRcdHJldHVybiBmYWxzZTtcclxuXHR9XHJcblxyXG5cdHZhciBsb2NhbF9fbnVtYmVyX29mX21vbnRocyA9IHBhcnNlSW50KCBfd3BiYy5jYWxlbmRhcl9fZ2V0X3BhcmFtX3ZhbHVlKCByZXNvdXJjZV9pZCwgJ2NhbGVuZGFyX251bWJlcl9vZl9tb250aHMnICkgKTtcclxuXHJcblx0aWYgKCBsb2NhbF9fbnVtYmVyX29mX21vbnRocyA+IDEgKXtcclxuXHJcblx0XHRpZiAoIGpRdWVyeSggd2luZG93ICkud2lkdGgoKSA8PSA3ODIgKXtcclxuXHRcdFx0d3BiY19jYWxlbmRhcl9fdXBkYXRlX21vbnRoc19udW1iZXIoIHJlc291cmNlX2lkLCAxICk7XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHR3cGJjX2NhbGVuZGFyX191cGRhdGVfbW9udGhzX251bWJlciggcmVzb3VyY2VfaWQsIGxvY2FsX19udW1iZXJfb2ZfbW9udGhzICk7XHJcblx0XHR9XHJcblxyXG5cdH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEF1dG8gVXBkYXRlIE51bWJlciBvZiBNb250aHMgaW4gICBBTEwgICBDYWxlbmRhcnNcclxuICpcclxuICovXHJcbmZ1bmN0aW9uIHdwYmNfY2FsZW5kYXJzX19hdXRvX3VwZGF0ZV9tb250aHNfbnVtYmVyKCl7XHJcblxyXG5cdHZhciBhbGxfY2FsZW5kYXJzX2FyciA9IF93cGJjLmNhbGVuZGFyc19hbGxfX2dldCgpO1xyXG5cclxuXHQvLyBUaGlzIExPT1AgXCJmb3IgaW5cIiBpcyBHT09ELCBiZWNhdXNlIHdlIGNoZWNrICBoZXJlIGtleXMgICAgJ2NhbGVuZGFyXycgPT09IGNhbGVuZGFyX2lkLnNsaWNlKCAwLCA5IClcclxuXHRmb3IgKCB2YXIgY2FsZW5kYXJfaWQgaW4gYWxsX2NhbGVuZGFyc19hcnIgKXtcclxuXHRcdGlmICggJ2NhbGVuZGFyXycgPT09IGNhbGVuZGFyX2lkLnNsaWNlKCAwLCA5ICkgKXtcclxuXHRcdFx0dmFyIHJlc291cmNlX2lkID0gcGFyc2VJbnQoIGNhbGVuZGFyX2lkLnNsaWNlKCA5ICkgKTtcdFx0XHQvLyAgJ2NhbGVuZGFyXzMnIC0+IDNcclxuXHRcdFx0aWYgKCByZXNvdXJjZV9pZCA+IDAgKXtcclxuXHRcdFx0XHR3cGJjX2NhbGVuZGFyX19hdXRvX3VwZGF0ZV9tb250aHNfbnVtYmVyX19vbl9yZXNpemUoIHJlc291cmNlX2lkICk7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHR9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBJZiBicm93c2VyIHdpbmRvdyBjaGFuZ2VkLCAgdGhlbiAgdXBkYXRlIG51bWJlciBvZiBtb250aHMuXHJcbiAqL1xyXG5qUXVlcnkoIHdpbmRvdyApLm9uKCAncmVzaXplJywgZnVuY3Rpb24gKCl7XHJcblx0d3BiY19jYWxlbmRhcnNfX2F1dG9fdXBkYXRlX21vbnRoc19udW1iZXIoKTtcclxufSApO1xyXG5cclxuLyoqXHJcbiAqIEF1dG8gdXBkYXRlIGNhbGVuZGFyIG51bWJlciBvZiBtb250aHMgb24gaW5pdGlhbCBwYWdlIGxvYWRcclxuICovXHJcbmpRdWVyeSggZG9jdW1lbnQgKS5yZWFkeSggZnVuY3Rpb24gKCl7XHJcblx0dmFyIGNsb3NlZF90aW1lciA9IHNldFRpbWVvdXQoIGZ1bmN0aW9uICgpe1xyXG5cdFx0d3BiY19jYWxlbmRhcnNfX2F1dG9fdXBkYXRlX21vbnRoc19udW1iZXIoKTtcclxuXHR9LCAxMDAgKTtcclxufSk7XHJcblxyXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuLyogID09ICBDaGVjazogY2FsZW5kYXJfZGF0ZXNfc3RhcnQ6IFwiMjAyNi0wMS0wMVwiLCBjYWxlbmRhcl9kYXRlc19lbmQ6IFwiMjAyNi0xMi0zMVwiID09ICAvLyBGaXhJbjogMTAuMTMuMS40LlxyXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi9cclxuXHQvKipcclxuXHQgKiBHZXQgU3RhcnQgSlMgRGF0ZSBvZiBzdGFydGluZyBkYXRlcyBpbiBjYWxlbmRhciwgZnJvbSB0aGUgX3dwYmMgb2JqZWN0LlxyXG5cdCAqXHJcblx0ICogQHBhcmFtIGludGVnZXIgcmVzb3VyY2VfaWQgLSByZXNvdXJjZSBJRCwgZS5nLjogMS5cclxuXHQgKi9cclxuXHRmdW5jdGlvbiB3cGJjX2NhbGVuZGFyX19nZXRfZGF0ZXNfc3RhcnQoIHJlc291cmNlX2lkICkge1xyXG5cdFx0cmV0dXJuIHdwYmNfY2FsZW5kYXJfX2dldF9kYXRlX3BhcmFtZXRlciggcmVzb3VyY2VfaWQsICdjYWxlbmRhcl9kYXRlc19zdGFydCcgKTtcclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIEdldCBFbmQgSlMgRGF0ZSBvZiBlbmRpbmcgZGF0ZXMgaW4gY2FsZW5kYXIsIGZyb20gdGhlIF93cGJjIG9iamVjdC5cclxuXHQgKlxyXG5cdCAqIEBwYXJhbSBpbnRlZ2VyIHJlc291cmNlX2lkIC0gcmVzb3VyY2UgSUQsIGUuZy46IDEuXHJcblx0ICovXHJcblx0ZnVuY3Rpb24gd3BiY19jYWxlbmRhcl9fZ2V0X2RhdGVzX2VuZChyZXNvdXJjZV9pZCkge1xyXG5cdFx0cmV0dXJuIHdwYmNfY2FsZW5kYXJfX2dldF9kYXRlX3BhcmFtZXRlciggcmVzb3VyY2VfaWQsICdjYWxlbmRhcl9kYXRlc19lbmQnICk7XHJcblx0fVxyXG5cclxuLyoqXHJcbiAqIEdldCB2YWxpZGF0ZXMgZGF0ZSBwYXJhbWV0ZXIuXHJcbiAqXHJcbiAqIEBwYXJhbSByZXNvdXJjZV9pZCAgIC0gMVxyXG4gKiBAcGFyYW0gcGFyYW1ldGVyX3N0ciAtICdjYWxlbmRhcl9kYXRlc19zdGFydCcgfCAnY2FsZW5kYXJfZGF0ZXNfZW5kJyB8IC4uLlxyXG4gKi9cclxuZnVuY3Rpb24gd3BiY19jYWxlbmRhcl9fZ2V0X2RhdGVfcGFyYW1ldGVyKHJlc291cmNlX2lkLCBwYXJhbWV0ZXJfc3RyKSB7XHJcblxyXG5cdHZhciBkYXRlX2V4cGVjdGVkX3ltZCA9IF93cGJjLmNhbGVuZGFyX19nZXRfcGFyYW1fdmFsdWUoIHJlc291cmNlX2lkLCBwYXJhbWV0ZXJfc3RyICk7XHJcblxyXG5cdGlmICggISBkYXRlX2V4cGVjdGVkX3ltZCApIHtcclxuXHRcdHJldHVybiBmYWxzZTsgICAgICAgICAgICAgLy8gJycgfCAwIHwgbnVsbCB8IHVuZGVmaW5lZCAgLT4gZmFsc2UuXHJcblx0fVxyXG5cclxuXHRpZiAoIC0xICE9PSBkYXRlX2V4cGVjdGVkX3ltZC5pbmRleE9mKCAnLScgKSApIHtcclxuXHJcblx0XHR2YXIgZGF0ZV9leHBlY3RlZF95bWRfYXJyID0gZGF0ZV9leHBlY3RlZF95bWQuc3BsaXQoICctJyApO1x0Ly8gJzIwMjUtMDctMjYnIC0+IFsnMjAyNScsICcwNycsICcyNiddXHJcblxyXG5cdFx0aWYgKCBkYXRlX2V4cGVjdGVkX3ltZF9hcnIubGVuZ3RoID4gMCApIHtcclxuXHRcdFx0dmFyIHllYXIgID0gKGRhdGVfZXhwZWN0ZWRfeW1kX2Fyci5sZW5ndGggPiAwKSA/IHBhcnNlSW50KCBkYXRlX2V4cGVjdGVkX3ltZF9hcnJbMF0gKSA6IG5ldyBEYXRlKCkuZ2V0RnVsbFllYXIoKTtcdC8vIFllYXIuXHJcblx0XHRcdHZhciBtb250aCA9IChkYXRlX2V4cGVjdGVkX3ltZF9hcnIubGVuZ3RoID4gMSkgPyAocGFyc2VJbnQoIGRhdGVfZXhwZWN0ZWRfeW1kX2FyclsxXSApIC0gMSkgOiAwOyAgLy8gKG1vbnRoIC0gMSkgb3IgMCAtIEphbi5cclxuXHRcdFx0dmFyIGRheSAgID0gKGRhdGVfZXhwZWN0ZWRfeW1kX2Fyci5sZW5ndGggPiAyKSA/IHBhcnNlSW50KCBkYXRlX2V4cGVjdGVkX3ltZF9hcnJbMl0gKSA6IDE7ICAvLyBkYXRlIG9yIE90aGVyd2lzZSAxc3Qgb2YgbW9udGhcclxuXHJcblx0XHRcdHZhciBkYXRlX2pzID0gbmV3IERhdGUoIHllYXIsIG1vbnRoLCBkYXksIDAsIDAsIDAsIDAgKTtcclxuXHJcblx0XHRcdHJldHVybiBkYXRlX2pzO1xyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0cmV0dXJuIGZhbHNlOyAgLy8gRmFsbGJhY2ssICBpZiB3ZSBub3QgcGFyc2VkIHRoaXMgcGFyYW1ldGVyICAnY2FsZW5kYXJfZGF0ZXNfc3RhcnQnID0gJzIwMjUtMDctMjYnLCAgZm9yIGV4YW1wbGUgYmVjYXVzZSBvZiAnY2FsZW5kYXJfZGF0ZXNfc3RhcnQnID0gJ3Nmc2RmJy5cclxufVxyXG4iLCIvKipcclxuICogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuICpcdGluY2x1ZGVzL19fanMvY2FsL2RheXNfc2VsZWN0X2N1c3RvbS5qc1xyXG4gKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG4gKi9cclxuXHJcbi8vIEZpeEluOiA5LjguOS4yLlxyXG5cclxuLyoqXHJcbiAqIFJlLUluaXQgQ2FsZW5kYXIgYW5kIFJlLVJlbmRlciBpdC5cclxuICpcclxuICogQHBhcmFtIHJlc291cmNlX2lkXHJcbiAqL1xyXG5mdW5jdGlvbiB3cGJjX2NhbF9fcmVfaW5pdCggcmVzb3VyY2VfaWQgKXtcclxuXHJcblx0Ly8gUmVtb3ZlIENMQVNTICBmb3IgYWJpbGl0eSB0byByZS1yZW5kZXIgYW5kIHJlaW5pdCBjYWxlbmRhci5cclxuXHRqUXVlcnkoICcjY2FsZW5kYXJfYm9va2luZycgKyByZXNvdXJjZV9pZCApLnJlbW92ZUNsYXNzKCAnaGFzRGF0ZXBpY2snICk7XHJcblx0d3BiY19jYWxlbmRhcl9zaG93KCByZXNvdXJjZV9pZCApO1xyXG59XHJcblxyXG5cclxuLyoqXHJcbiAqIFJlLUluaXQgcHJldmlvdXNseSAgc2F2ZWQgZGF5cyBzZWxlY3Rpb24gIHZhcmlhYmxlcy5cclxuICpcclxuICogQHBhcmFtIHJlc291cmNlX2lkXHJcbiAqL1xyXG5mdW5jdGlvbiB3cGJjX2NhbF9kYXlzX3NlbGVjdF9fcmVfaW5pdCggcmVzb3VyY2VfaWQgKXtcclxuXHJcblx0X3dwYmMuY2FsZW5kYXJfX3NldF9wYXJhbV92YWx1ZSggcmVzb3VyY2VfaWQsICdzYXZlZF92YXJpYWJsZV9fX2RheXNfc2VsZWN0X2luaXRpYWwnXHJcblx0XHQsIHtcclxuXHRcdFx0J2R5bmFtaWNfX2RheXNfbWluJyAgICAgICAgOiBfd3BiYy5jYWxlbmRhcl9fZ2V0X3BhcmFtX3ZhbHVlKCByZXNvdXJjZV9pZCwgJ2R5bmFtaWNfX2RheXNfbWluJyApLFxyXG5cdFx0XHQnZHluYW1pY19fZGF5c19tYXgnICAgICAgICA6IF93cGJjLmNhbGVuZGFyX19nZXRfcGFyYW1fdmFsdWUoIHJlc291cmNlX2lkLCAnZHluYW1pY19fZGF5c19tYXgnICksXHJcblx0XHRcdCdkeW5hbWljX19kYXlzX3NwZWNpZmljJyAgIDogX3dwYmMuY2FsZW5kYXJfX2dldF9wYXJhbV92YWx1ZSggcmVzb3VyY2VfaWQsICdkeW5hbWljX19kYXlzX3NwZWNpZmljJyApLFxyXG5cdFx0XHQnZHluYW1pY19fd2Vla19kYXlzX19zdGFydCc6IF93cGJjLmNhbGVuZGFyX19nZXRfcGFyYW1fdmFsdWUoIHJlc291cmNlX2lkLCAnZHluYW1pY19fd2Vla19kYXlzX19zdGFydCcgKSxcclxuXHRcdFx0J2ZpeGVkX19kYXlzX251bScgICAgICAgICAgOiBfd3BiYy5jYWxlbmRhcl9fZ2V0X3BhcmFtX3ZhbHVlKCByZXNvdXJjZV9pZCwgJ2ZpeGVkX19kYXlzX251bScgKSxcclxuXHRcdFx0J2ZpeGVkX193ZWVrX2RheXNfX3N0YXJ0JyAgOiBfd3BiYy5jYWxlbmRhcl9fZ2V0X3BhcmFtX3ZhbHVlKCByZXNvdXJjZV9pZCwgJ2ZpeGVkX193ZWVrX2RheXNfX3N0YXJ0JyApXHJcblx0XHR9XHJcblx0KTtcclxufVxyXG5cclxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblxyXG4vKipcclxuICogU2V0IFNpbmdsZSBEYXkgc2VsZWN0aW9uIC0gYWZ0ZXIgcGFnZSBsb2FkXHJcbiAqXHJcbiAqIEBwYXJhbSByZXNvdXJjZV9pZFx0XHRJRCBvZiBib29raW5nIHJlc291cmNlXHJcbiAqL1xyXG5mdW5jdGlvbiB3cGJjX2NhbF9yZWFkeV9kYXlzX3NlbGVjdF9fc2luZ2xlKCByZXNvdXJjZV9pZCApe1xyXG5cclxuXHQvLyBSZS1kZWZpbmUgc2VsZWN0aW9uLCBvbmx5IGFmdGVyIHBhZ2UgbG9hZGVkIHdpdGggYWxsIGluaXQgdmFyc1xyXG5cdGpRdWVyeShkb2N1bWVudCkucmVhZHkoZnVuY3Rpb24oKXtcclxuXHJcblx0XHQvLyBXYWl0IDEgc2Vjb25kLCBqdXN0IHRvICBiZSBzdXJlLCB0aGF0IGFsbCBpbml0IHZhcnMgZGVmaW5lZFxyXG5cdFx0c2V0VGltZW91dChmdW5jdGlvbigpe1xyXG5cclxuXHRcdFx0d3BiY19jYWxfZGF5c19zZWxlY3RfX3NpbmdsZSggcmVzb3VyY2VfaWQgKTtcclxuXHJcblx0XHR9LCAxMDAwKTtcclxuXHR9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldCBTaW5nbGUgRGF5IHNlbGVjdGlvblxyXG4gKiBDYW4gYmUgcnVuIGF0IGFueSAgdGltZSwgIHdoZW4gIGNhbGVuZGFyIGRlZmluZWQgLSB1c2VmdWwgZm9yIGNvbnNvbGUgcnVuLlxyXG4gKlxyXG4gKiBAcGFyYW0gcmVzb3VyY2VfaWRcdFx0SUQgb2YgYm9va2luZyByZXNvdXJjZVxyXG4gKi9cclxuZnVuY3Rpb24gd3BiY19jYWxfZGF5c19zZWxlY3RfX3NpbmdsZSggcmVzb3VyY2VfaWQgKXtcclxuXHJcblx0X3dwYmMuY2FsZW5kYXJfX3NldF9wYXJhbWV0ZXJzKCByZXNvdXJjZV9pZCwgeydkYXlzX3NlbGVjdF9tb2RlJzogJ3NpbmdsZSd9ICk7XHJcblxyXG5cdHdwYmNfY2FsX2RheXNfc2VsZWN0X19yZV9pbml0KCByZXNvdXJjZV9pZCApO1xyXG5cdHdwYmNfY2FsX19yZV9pbml0KCByZXNvdXJjZV9pZCApO1xyXG59XHJcblxyXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHJcbi8qKlxyXG4gKiBTZXQgTXVsdGlwbGUgRGF5cyBzZWxlY3Rpb24gIC0gYWZ0ZXIgcGFnZSBsb2FkXHJcbiAqXHJcbiAqIEBwYXJhbSByZXNvdXJjZV9pZFx0XHRJRCBvZiBib29raW5nIHJlc291cmNlXHJcbiAqL1xyXG5mdW5jdGlvbiB3cGJjX2NhbF9yZWFkeV9kYXlzX3NlbGVjdF9fbXVsdGlwbGUoIHJlc291cmNlX2lkICl7XHJcblxyXG5cdC8vIFJlLWRlZmluZSBzZWxlY3Rpb24sIG9ubHkgYWZ0ZXIgcGFnZSBsb2FkZWQgd2l0aCBhbGwgaW5pdCB2YXJzXHJcblx0alF1ZXJ5KGRvY3VtZW50KS5yZWFkeShmdW5jdGlvbigpe1xyXG5cclxuXHRcdC8vIFdhaXQgMSBzZWNvbmQsIGp1c3QgdG8gIGJlIHN1cmUsIHRoYXQgYWxsIGluaXQgdmFycyBkZWZpbmVkXHJcblx0XHRzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7XHJcblxyXG5cdFx0XHR3cGJjX2NhbF9kYXlzX3NlbGVjdF9fbXVsdGlwbGUoIHJlc291cmNlX2lkICk7XHJcblxyXG5cdFx0fSwgMTAwMCk7XHJcblx0fSk7XHJcbn1cclxuXHJcblxyXG4vKipcclxuICogU2V0IE11bHRpcGxlIERheXMgc2VsZWN0aW9uXHJcbiAqIENhbiBiZSBydW4gYXQgYW55ICB0aW1lLCAgd2hlbiAgY2FsZW5kYXIgZGVmaW5lZCAtIHVzZWZ1bCBmb3IgY29uc29sZSBydW4uXHJcbiAqXHJcbiAqIEBwYXJhbSByZXNvdXJjZV9pZFx0XHRJRCBvZiBib29raW5nIHJlc291cmNlXHJcbiAqL1xyXG5mdW5jdGlvbiB3cGJjX2NhbF9kYXlzX3NlbGVjdF9fbXVsdGlwbGUoIHJlc291cmNlX2lkICl7XHJcblxyXG5cdF93cGJjLmNhbGVuZGFyX19zZXRfcGFyYW1ldGVycyggcmVzb3VyY2VfaWQsIHsnZGF5c19zZWxlY3RfbW9kZSc6ICdtdWx0aXBsZSd9ICk7XHJcblxyXG5cdHdwYmNfY2FsX2RheXNfc2VsZWN0X19yZV9pbml0KCByZXNvdXJjZV9pZCApO1xyXG5cdHdwYmNfY2FsX19yZV9pbml0KCByZXNvdXJjZV9pZCApO1xyXG59XHJcblxyXG5cclxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblxyXG4vKipcclxuICogU2V0IEZpeGVkIERheXMgc2VsZWN0aW9uIHdpdGggIDEgbW91c2UgY2xpY2sgIC0gYWZ0ZXIgcGFnZSBsb2FkXHJcbiAqXHJcbiAqIEBpbnRlZ2VyIHJlc291cmNlX2lkXHRcdFx0LSAxXHRcdFx0XHQgICAtLSBJRCBvZiBib29raW5nIHJlc291cmNlIChjYWxlbmRhcikgLVxyXG4gKiBAaW50ZWdlciBkYXlzX251bWJlclx0XHRcdC0gM1x0XHRcdFx0ICAgLS0gbnVtYmVyIG9mIGRheXMgdG8gIHNlbGVjdFx0LVxyXG4gKiBAYXJyYXkgd2Vla19kYXlzX19zdGFydFx0LSBbLTFdIHwgWyAxLCA1XSAgIC0tICB7IC0xIC0gQW55IHwgMCAtIFN1LCAgMSAtIE1vLCAgMiAtIFR1LCAzIC0gV2UsIDQgLSBUaCwgNSAtIEZyLCA2IC0gU2F0IH1cclxuICovXHJcbmZ1bmN0aW9uIHdwYmNfY2FsX3JlYWR5X2RheXNfc2VsZWN0X19maXhlZCggcmVzb3VyY2VfaWQsIGRheXNfbnVtYmVyLCB3ZWVrX2RheXNfX3N0YXJ0ID0gWy0xXSApe1xyXG5cclxuXHQvLyBSZS1kZWZpbmUgc2VsZWN0aW9uLCBvbmx5IGFmdGVyIHBhZ2UgbG9hZGVkIHdpdGggYWxsIGluaXQgdmFyc1xyXG5cdGpRdWVyeShkb2N1bWVudCkucmVhZHkoZnVuY3Rpb24oKXtcclxuXHJcblx0XHQvLyBXYWl0IDEgc2Vjb25kLCBqdXN0IHRvICBiZSBzdXJlLCB0aGF0IGFsbCBpbml0IHZhcnMgZGVmaW5lZFxyXG5cdFx0c2V0VGltZW91dChmdW5jdGlvbigpe1xyXG5cclxuXHRcdFx0d3BiY19jYWxfZGF5c19zZWxlY3RfX2ZpeGVkKCByZXNvdXJjZV9pZCwgZGF5c19udW1iZXIsIHdlZWtfZGF5c19fc3RhcnQgKTtcclxuXHJcblx0XHR9LCAxMDAwKTtcclxuXHR9KTtcclxufVxyXG5cclxuXHJcbi8qKlxyXG4gKiBTZXQgRml4ZWQgRGF5cyBzZWxlY3Rpb24gd2l0aCAgMSBtb3VzZSBjbGlja1xyXG4gKiBDYW4gYmUgcnVuIGF0IGFueSAgdGltZSwgIHdoZW4gIGNhbGVuZGFyIGRlZmluZWQgLSB1c2VmdWwgZm9yIGNvbnNvbGUgcnVuLlxyXG4gKlxyXG4gKiBAaW50ZWdlciByZXNvdXJjZV9pZFx0XHRcdC0gMVx0XHRcdFx0ICAgLS0gSUQgb2YgYm9va2luZyByZXNvdXJjZSAoY2FsZW5kYXIpIC1cclxuICogQGludGVnZXIgZGF5c19udW1iZXJcdFx0XHQtIDNcdFx0XHRcdCAgIC0tIG51bWJlciBvZiBkYXlzIHRvICBzZWxlY3RcdC1cclxuICogQGFycmF5IHdlZWtfZGF5c19fc3RhcnRcdC0gWy0xXSB8IFsgMSwgNV0gICAtLSAgeyAtMSAtIEFueSB8IDAgLSBTdSwgIDEgLSBNbywgIDIgLSBUdSwgMyAtIFdlLCA0IC0gVGgsIDUgLSBGciwgNiAtIFNhdCB9XHJcbiAqL1xyXG5mdW5jdGlvbiB3cGJjX2NhbF9kYXlzX3NlbGVjdF9fZml4ZWQoIHJlc291cmNlX2lkLCBkYXlzX251bWJlciwgd2Vla19kYXlzX19zdGFydCA9IFstMV0gKXtcclxuXHJcblx0X3dwYmMuY2FsZW5kYXJfX3NldF9wYXJhbWV0ZXJzKCByZXNvdXJjZV9pZCwgeydkYXlzX3NlbGVjdF9tb2RlJzogJ2ZpeGVkJ30gKTtcclxuXHJcblx0X3dwYmMuY2FsZW5kYXJfX3NldF9wYXJhbWV0ZXJzKCByZXNvdXJjZV9pZCwgeydmaXhlZF9fZGF5c19udW0nOiBwYXJzZUludCggZGF5c19udW1iZXIgKX0gKTtcdFx0XHQvLyBOdW1iZXIgb2YgZGF5cyBzZWxlY3Rpb24gd2l0aCAxIG1vdXNlIGNsaWNrXHJcblx0X3dwYmMuY2FsZW5kYXJfX3NldF9wYXJhbWV0ZXJzKCByZXNvdXJjZV9pZCwgeydmaXhlZF9fd2Vla19kYXlzX19zdGFydCc6IHdlZWtfZGF5c19fc3RhcnR9ICk7IFx0Ly8geyAtMSAtIEFueSB8IDAgLSBTdSwgIDEgLSBNbywgIDIgLSBUdSwgMyAtIFdlLCA0IC0gVGgsIDUgLSBGciwgNiAtIFNhdCB9XHJcblxyXG5cdHdwYmNfY2FsX2RheXNfc2VsZWN0X19yZV9pbml0KCByZXNvdXJjZV9pZCApO1xyXG5cdHdwYmNfY2FsX19yZV9pbml0KCByZXNvdXJjZV9pZCApO1xyXG59XHJcblxyXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHJcbi8qKlxyXG4gKiBTZXQgUmFuZ2UgRGF5cyBzZWxlY3Rpb24gIHdpdGggIDIgbW91c2UgY2xpY2tzICAtIGFmdGVyIHBhZ2UgbG9hZFxyXG4gKlxyXG4gKiBAaW50ZWdlciByZXNvdXJjZV9pZFx0XHRcdC0gMVx0XHRcdFx0ICAgXHRcdC0tIElEIG9mIGJvb2tpbmcgcmVzb3VyY2UgKGNhbGVuZGFyKVxyXG4gKiBAaW50ZWdlciBkYXlzX21pblx0XHRcdC0gN1x0XHRcdFx0ICAgXHRcdC0tIE1pbiBudW1iZXIgb2YgZGF5cyB0byBzZWxlY3RcclxuICogQGludGVnZXIgZGF5c19tYXhcdFx0XHQtIDMwXHRcdFx0ICAgXHRcdC0tIE1heCBudW1iZXIgb2YgZGF5cyB0byBzZWxlY3RcclxuICogQGFycmF5IGRheXNfc3BlY2lmaWNcdFx0XHQtIFtdIHwgWzcsMTQsMjEsMjhdXHRcdC0tIFJlc3RyaWN0aW9uIGZvciBTcGVjaWZpYyBudW1iZXIgb2YgZGF5cyBzZWxlY3Rpb25cclxuICogQGFycmF5IHdlZWtfZGF5c19fc3RhcnRcdFx0LSBbLTFdIHwgWyAxLCA1XSAgIFx0XHQtLSAgeyAtMSAtIEFueSB8IDAgLSBTdSwgIDEgLSBNbywgIDIgLSBUdSwgMyAtIFdlLCA0IC0gVGgsIDUgLSBGciwgNiAtIFNhdCB9XHJcbiAqL1xyXG5mdW5jdGlvbiB3cGJjX2NhbF9yZWFkeV9kYXlzX3NlbGVjdF9fcmFuZ2UoIHJlc291cmNlX2lkLCBkYXlzX21pbiwgZGF5c19tYXgsIGRheXNfc3BlY2lmaWMgPSBbXSwgd2Vla19kYXlzX19zdGFydCA9IFstMV0gKXtcclxuXHJcblx0Ly8gUmUtZGVmaW5lIHNlbGVjdGlvbiwgb25seSBhZnRlciBwYWdlIGxvYWRlZCB3aXRoIGFsbCBpbml0IHZhcnNcclxuXHRqUXVlcnkoZG9jdW1lbnQpLnJlYWR5KGZ1bmN0aW9uKCl7XHJcblxyXG5cdFx0Ly8gV2FpdCAxIHNlY29uZCwganVzdCB0byAgYmUgc3VyZSwgdGhhdCBhbGwgaW5pdCB2YXJzIGRlZmluZWRcclxuXHRcdHNldFRpbWVvdXQoZnVuY3Rpb24oKXtcclxuXHJcblx0XHRcdHdwYmNfY2FsX2RheXNfc2VsZWN0X19yYW5nZSggcmVzb3VyY2VfaWQsIGRheXNfbWluLCBkYXlzX21heCwgZGF5c19zcGVjaWZpYywgd2Vla19kYXlzX19zdGFydCApO1xyXG5cdFx0fSwgMTAwMCk7XHJcblx0fSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXQgUmFuZ2UgRGF5cyBzZWxlY3Rpb24gIHdpdGggIDIgbW91c2UgY2xpY2tzXHJcbiAqIENhbiBiZSBydW4gYXQgYW55ICB0aW1lLCAgd2hlbiAgY2FsZW5kYXIgZGVmaW5lZCAtIHVzZWZ1bCBmb3IgY29uc29sZSBydW4uXHJcbiAqXHJcbiAqIEBpbnRlZ2VyIHJlc291cmNlX2lkXHRcdFx0LSAxXHRcdFx0XHQgICBcdFx0LS0gSUQgb2YgYm9va2luZyByZXNvdXJjZSAoY2FsZW5kYXIpXHJcbiAqIEBpbnRlZ2VyIGRheXNfbWluXHRcdFx0LSA3XHRcdFx0XHQgICBcdFx0LS0gTWluIG51bWJlciBvZiBkYXlzIHRvIHNlbGVjdFxyXG4gKiBAaW50ZWdlciBkYXlzX21heFx0XHRcdC0gMzBcdFx0XHQgICBcdFx0LS0gTWF4IG51bWJlciBvZiBkYXlzIHRvIHNlbGVjdFxyXG4gKiBAYXJyYXkgZGF5c19zcGVjaWZpY1x0XHRcdC0gW10gfCBbNywxNCwyMSwyOF1cdFx0LS0gUmVzdHJpY3Rpb24gZm9yIFNwZWNpZmljIG51bWJlciBvZiBkYXlzIHNlbGVjdGlvblxyXG4gKiBAYXJyYXkgd2Vla19kYXlzX19zdGFydFx0XHQtIFstMV0gfCBbIDEsIDVdICAgXHRcdC0tICB7IC0xIC0gQW55IHwgMCAtIFN1LCAgMSAtIE1vLCAgMiAtIFR1LCAzIC0gV2UsIDQgLSBUaCwgNSAtIEZyLCA2IC0gU2F0IH1cclxuICovXHJcbmZ1bmN0aW9uIHdwYmNfY2FsX2RheXNfc2VsZWN0X19yYW5nZSggcmVzb3VyY2VfaWQsIGRheXNfbWluLCBkYXlzX21heCwgZGF5c19zcGVjaWZpYyA9IFtdLCB3ZWVrX2RheXNfX3N0YXJ0ID0gWy0xXSApe1xyXG5cclxuXHRfd3BiYy5jYWxlbmRhcl9fc2V0X3BhcmFtZXRlcnMoICByZXNvdXJjZV9pZCwgeydkYXlzX3NlbGVjdF9tb2RlJzogJ2R5bmFtaWMnfSAgKTtcclxuXHRfd3BiYy5jYWxlbmRhcl9fc2V0X3BhcmFtX3ZhbHVlKCByZXNvdXJjZV9pZCwgJ2R5bmFtaWNfX2RheXNfbWluJyAgICAgICAgICwgcGFyc2VJbnQoIGRheXNfbWluICkgICk7ICAgICAgICAgICBcdFx0Ly8gTWluLiBOdW1iZXIgb2YgZGF5cyBzZWxlY3Rpb24gd2l0aCAyIG1vdXNlIGNsaWNrc1xyXG5cdF93cGJjLmNhbGVuZGFyX19zZXRfcGFyYW1fdmFsdWUoIHJlc291cmNlX2lkLCAnZHluYW1pY19fZGF5c19tYXgnICAgICAgICAgLCBwYXJzZUludCggZGF5c19tYXggKSAgKTsgICAgICAgICAgXHRcdC8vIE1heC4gTnVtYmVyIG9mIGRheXMgc2VsZWN0aW9uIHdpdGggMiBtb3VzZSBjbGlja3NcclxuXHRfd3BiYy5jYWxlbmRhcl9fc2V0X3BhcmFtX3ZhbHVlKCByZXNvdXJjZV9pZCwgJ2R5bmFtaWNfX2RheXNfc3BlY2lmaWMnICAgICwgZGF5c19zcGVjaWZpYyAgKTtcdCAgICAgIFx0XHRcdFx0Ly8gRXhhbXBsZSBbNSw3XVxyXG5cdF93cGJjLmNhbGVuZGFyX19zZXRfcGFyYW1fdmFsdWUoIHJlc291cmNlX2lkLCAnZHluYW1pY19fd2Vla19kYXlzX19zdGFydCcgLCB3ZWVrX2RheXNfX3N0YXJ0ICApOyAgXHRcdFx0XHRcdC8vIHsgLTEgLSBBbnkgfCAwIC0gU3UsICAxIC0gTW8sICAyIC0gVHUsIDMgLSBXZSwgNCAtIFRoLCA1IC0gRnIsIDYgLSBTYXQgfVxyXG5cclxuXHR3cGJjX2NhbF9kYXlzX3NlbGVjdF9fcmVfaW5pdCggcmVzb3VyY2VfaWQgKTtcclxuXHR3cGJjX2NhbF9fcmVfaW5pdCggcmVzb3VyY2VfaWQgKTtcclxufVxyXG4iLCIvKipcclxuICogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuICpcdGluY2x1ZGVzL19fanMvY2FsX2FqeF9sb2FkL3dwYmNfY2FsX2FqeC5qc1xyXG4gKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG4gKi9cclxuXHJcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG4vLyAgQSBqIGEgeCAgICBMIG8gYSBkICAgIEMgYSBsIGUgbiBkIGEgciAgICBEIGEgdCBhXHJcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cclxuZnVuY3Rpb24gd3BiY19jYWxlbmRhcl9fbG9hZF9kYXRhX19hangoIHBhcmFtcyApe1xyXG5cclxuXHQvLyBGaXhJbjogOS44LjYuMi5cclxuXHR3cGJjX2NhbGVuZGFyX19sb2FkaW5nX19zdGFydCggcGFyYW1zWydyZXNvdXJjZV9pZCddICk7XHJcblxyXG5cdC8vIFRyaWdnZXIgZXZlbnQgZm9yIGNhbGVuZGFyIGJlZm9yZSBsb2FkaW5nIEJvb2tpbmcgZGF0YSwgIGJ1dCBhZnRlciBzaG93aW5nIENhbGVuZGFyLlxyXG5cdGlmICggalF1ZXJ5KCAnI2NhbGVuZGFyX2Jvb2tpbmcnICsgcGFyYW1zWydyZXNvdXJjZV9pZCddICkubGVuZ3RoID4gMCApe1xyXG5cdFx0dmFyIHRhcmdldF9lbG0gPSBqUXVlcnkoICdib2R5JyApLnRyaWdnZXIoIFwid3BiY19jYWxlbmRhcl9hanhfX2JlZm9yZV9sb2FkZWRfZGF0YVwiLCBbcGFyYW1zWydyZXNvdXJjZV9pZCddXSApO1xyXG5cdFx0IC8valF1ZXJ5KCAnYm9keScgKS5vbiggJ3dwYmNfY2FsZW5kYXJfYWp4X19iZWZvcmVfbG9hZGVkX2RhdGEnLCBmdW5jdGlvbiggZXZlbnQsIHJlc291cmNlX2lkICkgeyAuLi4gfSApO1xyXG5cdH1cclxuXHJcblx0aWYgKCB3cGJjX2JhbGFuY2VyX19pc193YWl0KCBwYXJhbXMgLCAnd3BiY19jYWxlbmRhcl9fbG9hZF9kYXRhX19hangnICkgKXtcclxuXHRcdHJldHVybiBmYWxzZTtcclxuXHR9XHJcblxyXG5cdC8vIEZpeEluOiA5LjguNi4yLlxyXG5cdHdwYmNfY2FsZW5kYXJfX2JsdXJfX3N0b3AoIHBhcmFtc1sncmVzb3VyY2VfaWQnXSApO1xyXG5cclxuXHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdC8vID09IEdldCBzdGFydCAvIGVuZCBkYXRlcyBmcm9tICB0aGUgQm9va2luZyBDYWxlbmRhciBzaG9ydGNvZGUuID09XHJcblx0Ly8gRXhhbXBsZTogW2Jvb2tpbmcgY2FsZW5kYXJfZGF0ZXNfc3RhcnQ9JzIwMjYtMDEtMDEnIGNhbGVuZGFyX2RhdGVzX2VuZD0nMjAyNi0xMi0zMScgIHJlc291cmNlX2lkPTFdICAgICAgICAgICAgICAvLyBGaXhJbjogMTAuMTMuMS40LlxyXG5cdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0aWYgKCBmYWxzZSAhPT0gd3BiY19jYWxlbmRhcl9fZ2V0X2RhdGVzX3N0YXJ0KCBwYXJhbXNbJ3Jlc291cmNlX2lkJ10gKSApIHtcclxuXHRcdGlmICggISBwYXJhbXNbJ2RhdGVzX3RvX2NoZWNrJ10gKSB7IHBhcmFtc1snZGF0ZXNfdG9fY2hlY2snXSA9IFtdOyB9XHJcblx0XHR2YXIgZGF0ZXNfc3RhcnQgPSB3cGJjX2NhbGVuZGFyX19nZXRfZGF0ZXNfc3RhcnQoIHBhcmFtc1sncmVzb3VyY2VfaWQnXSApOyAgLy8gRS5nLiAtIGxvY2FsX19taW5fZGF0ZSA9IG5ldyBEYXRlKCAyMDI1LCAwLCAxICk7XHJcblx0XHRpZiAoIGZhbHNlICE9PSBkYXRlc19zdGFydCApe1xyXG5cdFx0XHRwYXJhbXNbJ2RhdGVzX3RvX2NoZWNrJ11bMF0gPSB3cGJjX19nZXRfX3NxbF9jbGFzc19kYXRlKCBkYXRlc19zdGFydCApO1xyXG5cdFx0fVxyXG5cdH1cclxuXHRpZiAoIGZhbHNlICE9PSB3cGJjX2NhbGVuZGFyX19nZXRfZGF0ZXNfZW5kKCBwYXJhbXNbJ3Jlc291cmNlX2lkJ10gKSApIHtcclxuXHRcdGlmICggIXBhcmFtc1snZGF0ZXNfdG9fY2hlY2snXSApIHsgcGFyYW1zWydkYXRlc190b19jaGVjayddID0gW107IH1cclxuXHRcdHZhciBkYXRlc19lbmQgPSB3cGJjX2NhbGVuZGFyX19nZXRfZGF0ZXNfZW5kKCBwYXJhbXNbJ3Jlc291cmNlX2lkJ10gKTsgIC8vIEUuZy4gLSBsb2NhbF9fbWluX2RhdGUgPSBuZXcgRGF0ZSggMjAyNSwgMCwgMSApO1xyXG5cdFx0aWYgKCBmYWxzZSAhPT0gZGF0ZXNfZW5kICkge1xyXG5cdFx0XHRwYXJhbXNbJ2RhdGVzX3RvX2NoZWNrJ11bMV0gPSB3cGJjX19nZXRfX3NxbF9jbGFzc19kYXRlKCBkYXRlc19lbmQgKTtcclxuXHRcdFx0aWYgKCAhcGFyYW1zWydkYXRlc190b19jaGVjayddWzBdICkge1xyXG5cdFx0XHRcdHBhcmFtc1snZGF0ZXNfdG9fY2hlY2snXVswXSA9IHdwYmNfX2dldF9fc3FsX2NsYXNzX2RhdGUoIG5ldyBEYXRlKCkgKTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cdH1cclxuXHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cclxuLy8gY29uc29sZS5ncm91cEVuZCgpOyBjb25zb2xlLnRpbWUoJ3Jlc291cmNlX2lkXycgKyBwYXJhbXNbJ3Jlc291cmNlX2lkJ10pO1xyXG5jb25zb2xlLmdyb3VwQ29sbGFwc2VkKCAnV1BCQ19BSlhfQ0FMRU5EQVJfTE9BRCcgKTsgY29uc29sZS5sb2coICcgPT0gQmVmb3JlIEFqYXggU2VuZCAtIGNhbGVuZGFyc19hbGxfX2dldCgpID09ICcgLCBfd3BiYy5jYWxlbmRhcnNfYWxsX19nZXQoKSApO1xyXG5cdGlmICggJ2Z1bmN0aW9uJyA9PT0gdHlwZW9mICh3cGJjX2hvb2tfX2luaXRfdGltZXNlbGVjdG9yKSApIHtcclxuXHRcdHdwYmNfaG9va19faW5pdF90aW1lc2VsZWN0b3IoKTtcclxuXHR9XHJcblxyXG5cdC8vIFN0YXJ0IEFqYXhcclxuXHRqUXVlcnkucG9zdCggd3BiY191cmxfYWpheCxcclxuXHRcdFx0XHR7XHJcblx0XHRcdFx0XHRhY3Rpb24gICAgICAgICAgOiAnV1BCQ19BSlhfQ0FMRU5EQVJfTE9BRCcsXHJcblx0XHRcdFx0XHR3cGJjX2FqeF91c2VyX2lkOiBfd3BiYy5nZXRfc2VjdXJlX3BhcmFtKCAndXNlcl9pZCcgKSxcclxuXHRcdFx0XHRcdG5vbmNlICAgICAgICAgICA6IF93cGJjLmdldF9zZWN1cmVfcGFyYW0oICdub25jZScgKSxcclxuXHRcdFx0XHRcdHdwYmNfYWp4X2xvY2FsZSA6IF93cGJjLmdldF9zZWN1cmVfcGFyYW0oICdsb2NhbGUnICksXHJcblxyXG5cdFx0XHRcdFx0Y2FsZW5kYXJfcmVxdWVzdF9wYXJhbXMgOiBwYXJhbXMgXHRcdFx0XHRcdFx0Ly8gVXN1YWxseSBsaWtlOiB7ICdyZXNvdXJjZV9pZCc6IDEsICdtYXhfZGF5c19jb3VudCc6IDM2NSB9XHJcblx0XHRcdFx0fSxcclxuXHJcblx0XHRcdFx0LyoqXHJcblx0XHRcdFx0ICogUyB1IGMgYyBlIHMgc1xyXG5cdFx0XHRcdCAqXHJcblx0XHRcdFx0ICogQHBhcmFtIHJlc3BvbnNlX2RhdGFcdFx0LVx0aXRzIG9iamVjdCByZXR1cm5lZCBmcm9tICBBamF4IC0gY2xhc3MtbGl2ZS1zZWFyY2gucGhwXHJcblx0XHRcdFx0ICogQHBhcmFtIHRleHRTdGF0dXNcdFx0LVx0J3N1Y2Nlc3MnXHJcblx0XHRcdFx0ICogQHBhcmFtIGpxWEhSXHRcdFx0XHQtXHRPYmplY3RcclxuXHRcdFx0XHQgKi9cclxuXHRcdFx0XHRmdW5jdGlvbiAoIHJlc3BvbnNlX2RhdGEsIHRleHRTdGF0dXMsIGpxWEhSICkge1xyXG4vLyBjb25zb2xlLnRpbWVFbmQoJ3Jlc291cmNlX2lkXycgKyByZXNwb25zZV9kYXRhWydyZXNvdXJjZV9pZCddKTtcclxuY29uc29sZS5sb2coICcgPT0gUmVzcG9uc2UgV1BCQ19BSlhfQ0FMRU5EQVJfTE9BRCA9PSAnLCByZXNwb25zZV9kYXRhICk7IGNvbnNvbGUuZ3JvdXBFbmQoKTtcclxuXHJcblx0XHRcdFx0XHQvLyBGaXhJbjogOS44LjYuMi5cclxuXHRcdFx0XHRcdHZhciBhanhfcG9zdF9kYXRhX19yZXNvdXJjZV9pZCA9IHdwYmNfZ2V0X3Jlc291cmNlX2lkX19mcm9tX2FqeF9wb3N0X2RhdGFfdXJsKCB0aGlzLmRhdGEgKTtcclxuXHRcdFx0XHRcdHdwYmNfYmFsYW5jZXJfX2NvbXBsZXRlZCggYWp4X3Bvc3RfZGF0YV9fcmVzb3VyY2VfaWQgLCAnd3BiY19jYWxlbmRhcl9fbG9hZF9kYXRhX19hangnICk7XHJcblxyXG5cdFx0XHRcdFx0Ly8gUHJvYmFibHkgRXJyb3JcclxuXHRcdFx0XHRcdGlmICggKHR5cGVvZiByZXNwb25zZV9kYXRhICE9PSAnb2JqZWN0JykgfHwgKHJlc3BvbnNlX2RhdGEgPT09IG51bGwpICl7XHJcblxyXG5cdFx0XHRcdFx0XHR2YXIganFfbm9kZSAgPSB3cGJjX2dldF9jYWxlbmRhcl9fanFfbm9kZV9fZm9yX21lc3NhZ2VzKCB0aGlzLmRhdGEgKTtcclxuXHRcdFx0XHRcdFx0dmFyIG1lc3NhZ2VfdHlwZSA9ICdpbmZvJztcclxuXHJcblx0XHRcdFx0XHRcdGlmICggJycgPT09IHJlc3BvbnNlX2RhdGEgKXtcclxuXHRcdFx0XHRcdFx0XHRyZXNwb25zZV9kYXRhID0gJ1RoZSBzZXJ2ZXIgcmVzcG9uZHMgd2l0aCBhbiBlbXB0eSBzdHJpbmcuIFRoZSBzZXJ2ZXIgcHJvYmFibHkgc3RvcHBlZCB3b3JraW5nIHVuZXhwZWN0ZWRseS4gPGJyPlBsZWFzZSBjaGVjayB5b3VyIDxzdHJvbmc+ZXJyb3IubG9nPC9zdHJvbmc+IGluIHlvdXIgc2VydmVyIGNvbmZpZ3VyYXRpb24gZm9yIHJlbGF0aXZlIGVycm9ycy4nO1xyXG5cdFx0XHRcdFx0XHRcdG1lc3NhZ2VfdHlwZSA9ICd3YXJuaW5nJztcclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0Ly8gU2hvdyBNZXNzYWdlXHJcblx0XHRcdFx0XHRcdHdwYmNfZnJvbnRfZW5kX19zaG93X21lc3NhZ2UoIHJlc3BvbnNlX2RhdGEgLCB7ICd0eXBlJyAgICAgOiBtZXNzYWdlX3R5cGUsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCdzaG93X2hlcmUnOiB7J2pxX25vZGUnOiBqcV9ub2RlLCAnd2hlcmUnOiAnYWZ0ZXInfSxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J2lzX2FwcGVuZCc6IHRydWUsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCdzdHlsZScgICAgOiAndGV4dC1hbGlnbjpsZWZ0OycsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCdkZWxheScgICAgOiAwXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHR9ICk7XHJcblx0XHRcdFx0XHRcdHJldHVybjtcclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHQvLyBTaG93IENhbGVuZGFyXHJcblx0XHRcdFx0XHR3cGJjX2NhbGVuZGFyX19sb2FkaW5nX19zdG9wKCByZXNwb25zZV9kYXRhWyAncmVzb3VyY2VfaWQnIF0gKTtcclxuXHJcblx0XHRcdFx0XHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHRcdFx0XHQvLyBCb29raW5ncyAtIERhdGVzXHJcblx0XHRcdFx0XHRfd3BiYy5ib29raW5nc19pbl9jYWxlbmRhcl9fc2V0X2RhdGVzKCAgcmVzcG9uc2VfZGF0YVsgJ3Jlc291cmNlX2lkJyBdLCByZXNwb25zZV9kYXRhWyAnYWp4X2RhdGEnIF1bJ2RhdGVzJ10gICk7XHJcblxyXG5cdFx0XHRcdFx0Ly8gQm9va2luZ3MgLSBDaGlsZCBvciBvbmx5IHNpbmdsZSBib29raW5nIHJlc291cmNlIGluIGRhdGVzXHJcblx0XHRcdFx0XHRfd3BiYy5ib29raW5nX19zZXRfcGFyYW1fdmFsdWUoIHJlc3BvbnNlX2RhdGFbICdyZXNvdXJjZV9pZCcgXSwgJ3Jlc291cmNlc19pZF9hcnJfX2luX2RhdGVzJywgcmVzcG9uc2VfZGF0YVsgJ2FqeF9kYXRhJyBdWyAncmVzb3VyY2VzX2lkX2Fycl9faW5fZGF0ZXMnIF0gKTtcclxuXHJcblx0XHRcdFx0XHQvLyBBZ2dyZWdhdGUgYm9va2luZyByZXNvdXJjZXMsICBpZiBhbnkgP1xyXG5cdFx0XHRcdFx0X3dwYmMuYm9va2luZ19fc2V0X3BhcmFtX3ZhbHVlKCByZXNwb25zZV9kYXRhWyAncmVzb3VyY2VfaWQnIF0sICdhZ2dyZWdhdGVfcmVzb3VyY2VfaWRfYXJyJywgcmVzcG9uc2VfZGF0YVsgJ2FqeF9kYXRhJyBdWyAnYWdncmVnYXRlX3Jlc291cmNlX2lkX2FycicgXSApO1xyXG5cdFx0XHRcdFx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cclxuXHRcdFx0XHRcdC8vIFVwZGF0ZSBjYWxlbmRhclxyXG5cdFx0XHRcdFx0d3BiY19jYWxlbmRhcl9fdXBkYXRlX2xvb2soIHJlc3BvbnNlX2RhdGFbICdyZXNvdXJjZV9pZCcgXSApO1xyXG5cclxuXHRcdFx0XHRcdGlmICggJ2Z1bmN0aW9uJyA9PT0gdHlwZW9mICh3cGJjX2hvb2tfX2luaXRfdGltZXNlbGVjdG9yKSApIHtcclxuXHRcdFx0XHRcdFx0d3BiY19ob29rX19pbml0X3RpbWVzZWxlY3RvcigpO1xyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGlmIChcclxuXHRcdFx0XHRcdFx0XHQoICd1bmRlZmluZWQnICE9PSB0eXBlb2YgKHJlc3BvbnNlX2RhdGFbICdhanhfZGF0YScgXVsgJ2FqeF9hZnRlcl9hY3Rpb25fbWVzc2FnZScgXSkgKVxyXG5cdFx0XHRcdFx0XHQgJiYgKCAnJyAhPSByZXNwb25zZV9kYXRhWyAnYWp4X2RhdGEnIF1bICdhanhfYWZ0ZXJfYWN0aW9uX21lc3NhZ2UnIF0ucmVwbGFjZSggL1xcbi9nLCBcIjxiciAvPlwiICkgKVxyXG5cdFx0XHRcdFx0KXtcclxuXHJcblx0XHRcdFx0XHRcdHZhciBqcV9ub2RlICA9IHdwYmNfZ2V0X2NhbGVuZGFyX19qcV9ub2RlX19mb3JfbWVzc2FnZXMoIHRoaXMuZGF0YSApO1xyXG5cclxuXHRcdFx0XHRcdFx0Ly8gU2hvdyBNZXNzYWdlXHJcblx0XHRcdFx0XHRcdHdwYmNfZnJvbnRfZW5kX19zaG93X21lc3NhZ2UoIHJlc3BvbnNlX2RhdGFbICdhanhfZGF0YScgXVsgJ2FqeF9hZnRlcl9hY3Rpb25fbWVzc2FnZScgXS5yZXBsYWNlKCAvXFxuL2csIFwiPGJyIC8+XCIgKSxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdHsgICAndHlwZScgICAgIDogKCAndW5kZWZpbmVkJyAhPT0gdHlwZW9mKCByZXNwb25zZV9kYXRhWyAnYWp4X2RhdGEnIF1bICdhanhfYWZ0ZXJfYWN0aW9uX21lc3NhZ2Vfc3RhdHVzJyBdICkgKVxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQgID8gcmVzcG9uc2VfZGF0YVsgJ2FqeF9kYXRhJyBdWyAnYWp4X2FmdGVyX2FjdGlvbl9tZXNzYWdlX3N0YXR1cycgXSA6ICdpbmZvJyxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J3Nob3dfaGVyZSc6IHsnanFfbm9kZSc6IGpxX25vZGUsICd3aGVyZSc6ICdhZnRlcid9LFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnaXNfYXBwZW5kJzogdHJ1ZSxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J3N0eWxlJyAgICA6ICd0ZXh0LWFsaWduOmxlZnQ7JyxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J2RlbGF5JyAgICA6IDEwMDAwXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHR9ICk7XHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0aWYgKCAnZnVuY3Rpb24nID09PSB0eXBlb2YgKHdwYmNfdXBkYXRlX2NhcGFjaXR5X2hpbnQpICkge1xyXG5cdFx0XHRcdFx0XHR3cGJjX3VwZGF0ZV9jYXBhY2l0eV9oaW50KCByZXNwb25zZV9kYXRhWydyZXNvdXJjZV9pZCddICk7XHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0Ly8gVHJpZ2dlciBldmVudCB0aGF0IGNhbGVuZGFyIGhhcyBiZWVuXHRcdCAvLyBGaXhJbjogMTAuMC4wLjQ0LiAgLy8gRml4SW46IDEwLjE0LjE3LjIuXHJcblx0XHRcdFx0XHRpZiAoIChqUXVlcnkoICcjY2FsZW5kYXJfYm9va2luZycgKyByZXNwb25zZV9kYXRhWydyZXNvdXJjZV9pZCddICkubGVuZ3RoID4gMCkgfHwgKGpRdWVyeSggJyNkYXRlX2Jvb2tpbmcnICsgcmVzcG9uc2VfZGF0YVsncmVzb3VyY2VfaWQnXSApLmxlbmd0aCA+IDApICkge1xyXG5cdFx0XHRcdFx0XHR2YXIgdGFyZ2V0X2VsbSA9IGpRdWVyeSggJ2JvZHknICkudHJpZ2dlciggXCJ3cGJjX2NhbGVuZGFyX2FqeF9fbG9hZGVkX2RhdGFcIiwgW3Jlc3BvbnNlX2RhdGFbICdyZXNvdXJjZV9pZCcgXV0gKTtcclxuXHRcdFx0XHRcdFx0IC8valF1ZXJ5KCAnYm9keScgKS5vbiggJ3dwYmNfY2FsZW5kYXJfYWp4X19sb2FkZWRfZGF0YScsIGZ1bmN0aW9uKCBldmVudCwgcmVzb3VyY2VfaWQgKSB7IC4uLiB9ICk7XHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0Ly9qUXVlcnkoICcjYWpheF9yZXNwb25kJyApLmh0bWwoIHJlc3BvbnNlX2RhdGEgKTtcdFx0Ly8gRm9yIGFiaWxpdHkgdG8gc2hvdyByZXNwb25zZSwgYWRkIHN1Y2ggRElWIGVsZW1lbnQgdG8gcGFnZVxyXG5cdFx0XHRcdH1cclxuXHRcdFx0ICApLmZhaWwoIGZ1bmN0aW9uICgganFYSFIsIHRleHRTdGF0dXMsIGVycm9yVGhyb3duICkgeyAgICBpZiAoIHdpbmRvdy5jb25zb2xlICYmIHdpbmRvdy5jb25zb2xlLmxvZyApeyBjb25zb2xlLmxvZyggJ0FqYXhfRXJyb3InLCBqcVhIUiwgdGV4dFN0YXR1cywgZXJyb3JUaHJvd24gKTsgfVxyXG5cclxuXHRcdFx0XHRcdHZhciBhanhfcG9zdF9kYXRhX19yZXNvdXJjZV9pZCA9IHdwYmNfZ2V0X3Jlc291cmNlX2lkX19mcm9tX2FqeF9wb3N0X2RhdGFfdXJsKCB0aGlzLmRhdGEgKTtcclxuXHRcdFx0XHRcdHdwYmNfYmFsYW5jZXJfX2NvbXBsZXRlZCggYWp4X3Bvc3RfZGF0YV9fcmVzb3VyY2VfaWQgLCAnd3BiY19jYWxlbmRhcl9fbG9hZF9kYXRhX19hangnICk7XHJcblxyXG5cdFx0XHRcdFx0Ly8gR2V0IENvbnRlbnQgb2YgRXJyb3IgTWVzc2FnZVxyXG5cdFx0XHRcdFx0dmFyIGVycm9yX21lc3NhZ2UgPSAnPHN0cm9uZz4nICsgJ0Vycm9yIScgKyAnPC9zdHJvbmc+ICcgKyBlcnJvclRocm93biA7XHJcblx0XHRcdFx0XHRpZiAoIGpxWEhSLnN0YXR1cyApe1xyXG5cdFx0XHRcdFx0XHRlcnJvcl9tZXNzYWdlICs9ICcgKDxiPicgKyBqcVhIUi5zdGF0dXMgKyAnPC9iPiknO1xyXG5cdFx0XHRcdFx0XHRpZiAoNDAzID09IGpxWEhSLnN0YXR1cyApe1xyXG5cdFx0XHRcdFx0XHRcdGVycm9yX21lc3NhZ2UgKz0gJzxicj4gUHJvYmFibHkgbm9uY2UgZm9yIHRoaXMgcGFnZSBoYXMgYmVlbiBleHBpcmVkLiBQbGVhc2UgPGEgaHJlZj1cImphdmFzY3JpcHQ6dm9pZCgwKVwiIG9uY2xpY2s9XCJqYXZhc2NyaXB0OmxvY2F0aW9uLnJlbG9hZCgpO1wiPnJlbG9hZCB0aGUgcGFnZTwvYT4uJztcclxuXHRcdFx0XHRcdFx0XHRlcnJvcl9tZXNzYWdlICs9ICc8YnI+IE90aGVyd2lzZSwgcGxlYXNlIGNoZWNrIHRoaXMgPGEgc3R5bGU9XCJmb250LXdlaWdodDogNjAwO1wiIGhyZWY9XCJodHRwczovL3dwYm9va2luZ2NhbGVuZGFyLmNvbS9mYXEvcmVxdWVzdC1kby1ub3QtcGFzcy1zZWN1cml0eS1jaGVjay8/YWZ0ZXJfdXBkYXRlPTEwLjEuMVwiPnRyb3VibGVzaG9vdGluZyBpbnN0cnVjdGlvbjwvYT4uPGJyPidcclxuXHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0dmFyIG1lc3NhZ2Vfc2hvd19kZWxheSA9IDMwMDA7XHJcblx0XHRcdFx0XHRpZiAoIGpxWEhSLnJlc3BvbnNlVGV4dCApe1xyXG5cdFx0XHRcdFx0XHRlcnJvcl9tZXNzYWdlICs9ICcgJyArIGpxWEhSLnJlc3BvbnNlVGV4dDtcclxuXHRcdFx0XHRcdFx0bWVzc2FnZV9zaG93X2RlbGF5ID0gMTA7XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHRlcnJvcl9tZXNzYWdlID0gZXJyb3JfbWVzc2FnZS5yZXBsYWNlKCAvXFxuL2csIFwiPGJyIC8+XCIgKTtcclxuXHJcblx0XHRcdFx0XHR2YXIganFfbm9kZSAgPSB3cGJjX2dldF9jYWxlbmRhcl9fanFfbm9kZV9fZm9yX21lc3NhZ2VzKCB0aGlzLmRhdGEgKTtcclxuXHJcblx0XHRcdFx0XHQvKipcclxuXHRcdFx0XHRcdCAqIElmIHdlIG1ha2UgZmFzdCBjbGlja2luZyBvbiBkaWZmZXJlbnQgcGFnZXMsXHJcblx0XHRcdFx0XHQgKiB0aGVuIHVuZGVyIGNhbGVuZGFyIHdpbGwgc2hvdyBlcnJvciBtZXNzYWdlIHdpdGggIGVtcHR5ICB0ZXh0LCBiZWNhdXNlIGFqYXggd2FzIG5vdCByZWNlaXZlZC5cclxuXHRcdFx0XHRcdCAqIFRvICBub3Qgc2hvdyBzdWNoIHdhcm5pbmdzIHdlIGFyZSBzZXQgZGVsYXkgIGluIDMgc2Vjb25kcy4gIHZhciBtZXNzYWdlX3Nob3dfZGVsYXkgPSAzMDAwO1xyXG5cdFx0XHRcdFx0ICovXHJcblx0XHRcdFx0XHR2YXIgY2xvc2VkX3RpbWVyID0gc2V0VGltZW91dCggZnVuY3Rpb24gKCl7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vIFNob3cgTWVzc2FnZVxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdHdwYmNfZnJvbnRfZW5kX19zaG93X21lc3NhZ2UoIGVycm9yX21lc3NhZ2UgLCB7ICd0eXBlJyAgICAgOiAnZXJyb3InLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCdzaG93X2hlcmUnOiB7J2pxX25vZGUnOiBqcV9ub2RlLCAnd2hlcmUnOiAnYWZ0ZXInfSxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnaXNfYXBwZW5kJzogdHJ1ZSxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnc3R5bGUnICAgIDogJ3RleHQtYWxpZ246bGVmdDsnLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCdjc3NfY2xhc3MnOid3cGJjX2ZlX21lc3NhZ2VfYWx0JyxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnZGVsYXknICAgIDogMFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHR9ICk7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQgICB9ICxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCAgIHBhcnNlSW50KCBtZXNzYWdlX3Nob3dfZGVsYXkgKSAgICk7XHJcblxyXG5cdFx0XHQgIH0pXHJcblx0ICAgICAgICAgIC8vIC5kb25lKCAgIGZ1bmN0aW9uICggZGF0YSwgdGV4dFN0YXR1cywganFYSFIgKSB7ICAgaWYgKCB3aW5kb3cuY29uc29sZSAmJiB3aW5kb3cuY29uc29sZS5sb2cgKXsgY29uc29sZS5sb2coICdzZWNvbmQgc3VjY2VzcycsIGRhdGEsIHRleHRTdGF0dXMsIGpxWEhSICk7IH0gICAgfSlcclxuXHRcdFx0ICAvLyAuYWx3YXlzKCBmdW5jdGlvbiAoIGRhdGFfanFYSFIsIHRleHRTdGF0dXMsIGpxWEhSX2Vycm9yVGhyb3duICkgeyAgIGlmICggd2luZG93LmNvbnNvbGUgJiYgd2luZG93LmNvbnNvbGUubG9nICl7IGNvbnNvbGUubG9nKCAnYWx3YXlzIGZpbmlzaGVkJywgZGF0YV9qcVhIUiwgdGV4dFN0YXR1cywganFYSFJfZXJyb3JUaHJvd24gKTsgfSAgICAgfSlcclxuXHRcdFx0ICA7ICAvLyBFbmQgQWpheFxyXG59XHJcblxyXG5cclxuXHJcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG4vLyBTdXBwb3J0XHJcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cclxuXHQvKipcclxuXHQgKiBHZXQgQ2FsZW5kYXIgalF1ZXJ5IG5vZGUgZm9yIHNob3dpbmcgbWVzc2FnZXMgZHVyaW5nIEFqYXhcclxuXHQgKiBUaGlzIHBhcmFtZXRlcjogICBjYWxlbmRhcl9yZXF1ZXN0X3BhcmFtc1tyZXNvdXJjZV9pZF0gICBwYXJzZWQgZnJvbSB0aGlzLmRhdGEgQWpheCBwb3N0ICBkYXRhXHJcblx0ICpcclxuXHQgKiBAcGFyYW0gYWp4X3Bvc3RfZGF0YV91cmxfcGFyYW1zXHRcdCAnYWN0aW9uPVdQQkNfQUpYX0NBTEVOREFSX0xPQUQuLi4mY2FsZW5kYXJfcmVxdWVzdF9wYXJhbXMlNUJyZXNvdXJjZV9pZCU1RD0yJmNhbGVuZGFyX3JlcXVlc3RfcGFyYW1zJTVCYm9va2luZ19oYXNoJTVEPSZjYWxlbmRhcl9yZXF1ZXN0X3BhcmFtcydcclxuXHQgKiBAcmV0dXJucyB7c3RyaW5nfVx0JycjY2FsZW5kYXJfYm9va2luZzEnICB8ICAgJy5ib29raW5nX2Zvcm1fZGl2JyAuLi5cclxuXHQgKlxyXG5cdCAqIEV4YW1wbGUgICAgdmFyIGpxX25vZGUgID0gd3BiY19nZXRfY2FsZW5kYXJfX2pxX25vZGVfX2Zvcl9tZXNzYWdlcyggdGhpcy5kYXRhICk7XHJcblx0ICovXHJcblx0ZnVuY3Rpb24gd3BiY19nZXRfY2FsZW5kYXJfX2pxX25vZGVfX2Zvcl9tZXNzYWdlcyggYWp4X3Bvc3RfZGF0YV91cmxfcGFyYW1zICl7XHJcblxyXG5cdFx0dmFyIGpxX25vZGUgPSAnLmJvb2tpbmdfZm9ybV9kaXYnO1xyXG5cclxuXHRcdHZhciBjYWxlbmRhcl9yZXNvdXJjZV9pZCA9IHdwYmNfZ2V0X3Jlc291cmNlX2lkX19mcm9tX2FqeF9wb3N0X2RhdGFfdXJsKCBhanhfcG9zdF9kYXRhX3VybF9wYXJhbXMgKTtcclxuXHJcblx0XHRpZiAoIGNhbGVuZGFyX3Jlc291cmNlX2lkID4gMCApe1xyXG5cdFx0XHRqcV9ub2RlID0gJyNjYWxlbmRhcl9ib29raW5nJyArIGNhbGVuZGFyX3Jlc291cmNlX2lkO1xyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBqcV9ub2RlO1xyXG5cdH1cclxuXHJcblxyXG5cdC8qKlxyXG5cdCAqIEdldCByZXNvdXJjZSBJRCBmcm9tIGFqeCBwb3N0IGRhdGEgdXJsICAgdXN1YWxseSAgZnJvbSAgdGhpcy5kYXRhICA9XHJcblx0ICogJ2FjdGlvbj1XUEJDX0FKWF9DQUxFTkRBUl9MT0FELi4uJmNhbGVuZGFyX3JlcXVlc3RfcGFyYW1zJTVCcmVzb3VyY2VfaWQlNUQ9MiZjYWxlbmRhcl9yZXF1ZXN0X3BhcmFtcyU1QmJvb2tpbmdfaGFzaCU1RD0mY2FsZW5kYXJfcmVxdWVzdF9wYXJhbXMnXHJcblx0ICpcclxuXHQgKiBAcGFyYW0gYWp4X3Bvc3RfZGF0YV91cmxfcGFyYW1zXHRcdCAnYWN0aW9uPVdQQkNfQUpYX0NBTEVOREFSX0xPQUQuLi4mY2FsZW5kYXJfcmVxdWVzdF9wYXJhbXMlNUJyZXNvdXJjZV9pZCU1RD0yJmNhbGVuZGFyX3JlcXVlc3RfcGFyYW1zJTVCYm9va2luZ19oYXNoJTVEPSZjYWxlbmRhcl9yZXF1ZXN0X3BhcmFtcydcclxuXHQgKiBAcmV0dXJucyB7aW50fVx0XHRcdFx0XHRcdCAxIHwgMCAgKGlmIGVycnJvciB0aGVuICAwKVxyXG5cdCAqXHJcblx0ICogRXhhbXBsZSAgICB2YXIganFfbm9kZSAgPSB3cGJjX2dldF9jYWxlbmRhcl9fanFfbm9kZV9fZm9yX21lc3NhZ2VzKCB0aGlzLmRhdGEgKTtcclxuXHQgKi9cclxuXHRmdW5jdGlvbiB3cGJjX2dldF9yZXNvdXJjZV9pZF9fZnJvbV9hanhfcG9zdF9kYXRhX3VybCggYWp4X3Bvc3RfZGF0YV91cmxfcGFyYW1zICl7XHJcblxyXG5cdFx0Ly8gR2V0IGJvb2tpbmcgcmVzb3VyY2UgSUQgZnJvbSBBamF4IFBvc3QgUmVxdWVzdCAgLT4gdGhpcy5kYXRhID0gJ2FjdGlvbj1XUEJDX0FKWF9DQUxFTkRBUl9MT0FELi4uJmNhbGVuZGFyX3JlcXVlc3RfcGFyYW1zJTVCcmVzb3VyY2VfaWQlNUQ9MiZjYWxlbmRhcl9yZXF1ZXN0X3BhcmFtcyU1QmJvb2tpbmdfaGFzaCU1RD0mY2FsZW5kYXJfcmVxdWVzdF9wYXJhbXMnXHJcblx0XHR2YXIgY2FsZW5kYXJfcmVzb3VyY2VfaWQgPSB3cGJjX2dldF91cmlfcGFyYW1fYnlfbmFtZSggJ2NhbGVuZGFyX3JlcXVlc3RfcGFyYW1zW3Jlc291cmNlX2lkXScsIGFqeF9wb3N0X2RhdGFfdXJsX3BhcmFtcyApO1xyXG5cdFx0aWYgKCAobnVsbCAhPT0gY2FsZW5kYXJfcmVzb3VyY2VfaWQpICYmICgnJyAhPT0gY2FsZW5kYXJfcmVzb3VyY2VfaWQpICl7XHJcblx0XHRcdGNhbGVuZGFyX3Jlc291cmNlX2lkID0gcGFyc2VJbnQoIGNhbGVuZGFyX3Jlc291cmNlX2lkICk7XHJcblx0XHRcdGlmICggY2FsZW5kYXJfcmVzb3VyY2VfaWQgPiAwICl7XHJcblx0XHRcdFx0cmV0dXJuIGNhbGVuZGFyX3Jlc291cmNlX2lkO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gMDtcclxuXHR9XHJcblxyXG5cclxuXHQvKipcclxuXHQgKiBHZXQgcGFyYW1ldGVyIGZyb20gVVJMICAtICBwYXJzZSBVUkwgcGFyYW1ldGVycywgIGxpa2UgdGhpczpcclxuXHQgKiBhY3Rpb249V1BCQ19BSlhfQ0FMRU5EQVJfTE9BRC4uLiZjYWxlbmRhcl9yZXF1ZXN0X3BhcmFtcyU1QnJlc291cmNlX2lkJTVEPTImY2FsZW5kYXJfcmVxdWVzdF9wYXJhbXMlNUJib29raW5nX2hhc2glNUQ9JmNhbGVuZGFyX3JlcXVlc3RfcGFyYW1zXHJcblx0ICogQHBhcmFtIG5hbWUgIHBhcmFtZXRlciAgbmFtZSwgIGxpa2UgJ2NhbGVuZGFyX3JlcXVlc3RfcGFyYW1zW3Jlc291cmNlX2lkXSdcclxuXHQgKiBAcGFyYW0gdXJsXHQncGFyYW1ldGVyICBzdHJpbmcgVVJMJ1xyXG5cdCAqIEByZXR1cm5zIHtzdHJpbmd8bnVsbH0gICBwYXJhbWV0ZXIgdmFsdWVcclxuXHQgKlxyXG5cdCAqIEV4YW1wbGU6IFx0XHR3cGJjX2dldF91cmlfcGFyYW1fYnlfbmFtZSggJ2NhbGVuZGFyX3JlcXVlc3RfcGFyYW1zW3Jlc291cmNlX2lkXScsIHRoaXMuZGF0YSApOyAgLT4gJzInXHJcblx0ICovXHJcblx0ZnVuY3Rpb24gd3BiY19nZXRfdXJpX3BhcmFtX2J5X25hbWUoIG5hbWUsIHVybCApe1xyXG5cclxuXHRcdHVybCA9IGRlY29kZVVSSUNvbXBvbmVudCggdXJsICk7XHJcblxyXG5cdFx0bmFtZSA9IG5hbWUucmVwbGFjZSggL1tcXFtcXF1dL2csICdcXFxcJCYnICk7XHJcblx0XHR2YXIgcmVnZXggPSBuZXcgUmVnRXhwKCAnWz8mXScgKyBuYW1lICsgJyg9KFteJiNdKil8JnwjfCQpJyApLFxyXG5cdFx0XHRyZXN1bHRzID0gcmVnZXguZXhlYyggdXJsICk7XHJcblx0XHRpZiAoICFyZXN1bHRzICkgcmV0dXJuIG51bGw7XHJcblx0XHRpZiAoICFyZXN1bHRzWyAyIF0gKSByZXR1cm4gJyc7XHJcblx0XHRyZXR1cm4gZGVjb2RlVVJJQ29tcG9uZW50KCByZXN1bHRzWyAyIF0ucmVwbGFjZSggL1xcKy9nLCAnICcgKSApO1xyXG5cdH1cclxuIiwiLyoqXHJcbiAqID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG4gKlx0aW5jbHVkZXMvX19qcy9mcm9udF9lbmRfbWVzc2FnZXMvd3BiY19mZV9tZXNzYWdlcy5qc1xyXG4gKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuICovXHJcblxyXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuLy8gU2hvdyBNZXNzYWdlcyBhdCBGcm9udC1FZG4gc2lkZVxyXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHJcbi8qKlxyXG4gKiBTaG93IG1lc3NhZ2UgaW4gY29udGVudFxyXG4gKlxyXG4gKiBAcGFyYW0gbWVzc2FnZVx0XHRcdFx0TWVzc2FnZSBIVE1MXHJcbiAqIEBwYXJhbSBwYXJhbXMgPSB7XHJcbiAqXHRcdFx0XHRcdFx0XHRcdCd0eXBlJyAgICAgOiAnd2FybmluZycsXHRcdFx0XHRcdFx0XHQvLyAnZXJyb3InIHwgJ3dhcm5pbmcnIHwgJ2luZm8nIHwgJ3N1Y2Nlc3MnXHJcbiAqXHRcdFx0XHRcdFx0XHRcdCdzaG93X2hlcmUnIDoge1xyXG4gKlx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J2pxX25vZGUnIDogJycsXHRcdFx0XHQvLyBhbnkgalF1ZXJ5IG5vZGUgZGVmaW5pdGlvblxyXG4gKlx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J3doZXJlJyAgIDogJ2luc2lkZSdcdFx0Ly8gJ2luc2lkZScgfCAnYmVmb3JlJyB8ICdhZnRlcicgfCAncmlnaHQnIHwgJ2xlZnQnXHJcbiAqXHRcdFx0XHRcdFx0XHRcdFx0XHRcdCAgfSxcclxuICpcdFx0XHRcdFx0XHRcdFx0J2lzX2FwcGVuZCc6IHRydWUsXHRcdFx0XHRcdFx0XHRcdC8vIEFwcGx5ICBvbmx5IGlmIFx0J3doZXJlJyAgIDogJ2luc2lkZSdcclxuICpcdFx0XHRcdFx0XHRcdFx0J3N0eWxlJyAgICA6ICd0ZXh0LWFsaWduOmxlZnQ7JyxcdFx0XHRcdC8vIHN0eWxlcywgaWYgbmVlZGVkXHJcbiAqXHRcdFx0XHRcdFx0XHQgICAgJ2Nzc19jbGFzcyc6ICcnLFx0XHRcdFx0XHRcdFx0XHQvLyBGb3IgZXhhbXBsZSBjYW4gIGJlOiAnd3BiY19mZV9tZXNzYWdlX2FsdCdcclxuICpcdFx0XHRcdFx0XHRcdFx0J2RlbGF5JyAgICA6IDAsXHRcdFx0XHRcdFx0XHRcdFx0Ly8gaG93IG1hbnkgbWljcm9zZWNvbmQgdG8gIHNob3csICBpZiAwICB0aGVuICBzaG93IGZvcmV2ZXJcclxuICpcdFx0XHRcdFx0XHRcdFx0J2lmX3Zpc2libGVfbm90X3Nob3cnOiBmYWxzZVx0XHRcdFx0XHQvLyBpZiB0cnVlLCAgdGhlbiBkbyBub3Qgc2hvdyBtZXNzYWdlLCAgaWYgcHJldmlvcyBtZXNzYWdlIHdhcyBub3QgaGlkZWQgKG5vdCBhcHBseSBpZiAnd2hlcmUnICAgOiAnaW5zaWRlJyApXHJcbiAqXHRcdFx0XHR9O1xyXG4gKiBFeGFtcGxlczpcclxuICogXHRcdFx0dmFyIGh0bWxfaWQgPSB3cGJjX2Zyb250X2VuZF9fc2hvd19tZXNzYWdlKCAnWW91IGNhbiB0ZXN0IGRheXMgc2VsZWN0aW9uIGluIGNhbGVuZGFyJywge30gKTtcclxuICpcclxuICpcdFx0XHR2YXIgbm90aWNlX21lc3NhZ2VfaWQgPSB3cGJjX2Zyb250X2VuZF9fc2hvd19tZXNzYWdlKCBfd3BiYy5nZXRfbWVzc2FnZSggJ21lc3NhZ2VfY2hlY2tfcmVxdWlyZWQnICksIHsgJ3R5cGUnOiAnd2FybmluZycsICdkZWxheSc6IDEwMDAwLCAnaWZfdmlzaWJsZV9ub3Rfc2hvdyc6IHRydWUsXHJcbiAqXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQgICdzaG93X2hlcmUnOiB7J3doZXJlJzogJ3JpZ2h0JywgJ2pxX25vZGUnOiBlbCx9IH0gKTtcclxuICpcclxuICpcdFx0XHR3cGJjX2Zyb250X2VuZF9fc2hvd19tZXNzYWdlKCByZXNwb25zZV9kYXRhWyAnYWp4X2RhdGEnIF1bICdhanhfYWZ0ZXJfYWN0aW9uX21lc3NhZ2UnIF0ucmVwbGFjZSggL1xcbi9nLCBcIjxiciAvPlwiICksXHJcbiAqXHRcdFx0XHRcdFx0XHRcdFx0XHRcdHsgICAndHlwZScgICAgIDogKCAndW5kZWZpbmVkJyAhPT0gdHlwZW9mKCByZXNwb25zZV9kYXRhWyAnYWp4X2RhdGEnIF1bICdhanhfYWZ0ZXJfYWN0aW9uX21lc3NhZ2Vfc3RhdHVzJyBdICkgKVxyXG4gKlx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCAgPyByZXNwb25zZV9kYXRhWyAnYWp4X2RhdGEnIF1bICdhanhfYWZ0ZXJfYWN0aW9uX21lc3NhZ2Vfc3RhdHVzJyBdIDogJ2luZm8nLFxyXG4gKlx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCdzaG93X2hlcmUnOiB7J2pxX25vZGUnOiBqcV9ub2RlLCAnd2hlcmUnOiAnYWZ0ZXInfSxcclxuICpcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnY3NzX2NsYXNzJzond3BiY19mZV9tZXNzYWdlX2FsdCcsXHJcbiAqXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J2RlbGF5JyAgICA6IDEwMDAwXHJcbiAqXHRcdFx0XHRcdFx0XHRcdFx0XHRcdH0gKTtcclxuICpcclxuICpcclxuICogQHJldHVybnMgc3RyaW5nICAtIEhUTUwgSURcdFx0b3IgMCBpZiBub3Qgc2hvd2luZyBkdXJpbmcgdGhpcyB0aW1lLlxyXG4gKi9cclxuZnVuY3Rpb24gd3BiY19mcm9udF9lbmRfX3Nob3dfbWVzc2FnZSggbWVzc2FnZSwgcGFyYW1zID0ge30gKXtcclxuXHJcblx0dmFyIHBhcmFtc19kZWZhdWx0ID0ge1xyXG5cdFx0XHRcdFx0XHRcdFx0J3R5cGUnICAgICA6ICd3YXJuaW5nJyxcdFx0XHRcdFx0XHRcdC8vICdlcnJvcicgfCAnd2FybmluZycgfCAnaW5mbycgfCAnc3VjY2VzcydcclxuXHRcdFx0XHRcdFx0XHRcdCdzaG93X2hlcmUnIDoge1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCdqcV9ub2RlJyA6ICcnLFx0XHRcdFx0Ly8gYW55IGpRdWVyeSBub2RlIGRlZmluaXRpb25cclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnd2hlcmUnICAgOiAnaW5zaWRlJ1x0XHQvLyAnaW5zaWRlJyB8ICdiZWZvcmUnIHwgJ2FmdGVyJyB8ICdyaWdodCcgfCAnbGVmdCdcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdCAgfSxcclxuXHRcdFx0XHRcdFx0XHRcdCdpc19hcHBlbmQnOiB0cnVlLFx0XHRcdFx0XHRcdFx0XHQvLyBBcHBseSAgb25seSBpZiBcdCd3aGVyZScgICA6ICdpbnNpZGUnXHJcblx0XHRcdFx0XHRcdFx0XHQnc3R5bGUnICAgIDogJ3RleHQtYWxpZ246bGVmdDsnLFx0XHRcdFx0Ly8gc3R5bGVzLCBpZiBuZWVkZWRcclxuXHRcdFx0XHRcdFx0XHQgICAgJ2Nzc19jbGFzcyc6ICcnLFx0XHRcdFx0XHRcdFx0XHQvLyBGb3IgZXhhbXBsZSBjYW4gIGJlOiAnd3BiY19mZV9tZXNzYWdlX2FsdCdcclxuXHRcdFx0XHRcdFx0XHRcdCdkZWxheScgICAgOiAwLFx0XHRcdFx0XHRcdFx0XHRcdC8vIGhvdyBtYW55IG1pY3Jvc2Vjb25kIHRvICBzaG93LCAgaWYgMCAgdGhlbiAgc2hvdyBmb3JldmVyXHJcblx0XHRcdFx0XHRcdFx0XHQnaWZfdmlzaWJsZV9ub3Rfc2hvdyc6IGZhbHNlLFx0XHRcdFx0XHQvLyBpZiB0cnVlLCAgdGhlbiBkbyBub3Qgc2hvdyBtZXNzYWdlLCAgaWYgcHJldmlvcyBtZXNzYWdlIHdhcyBub3QgaGlkZWQgKG5vdCBhcHBseSBpZiAnd2hlcmUnICAgOiAnaW5zaWRlJyApXHJcblx0XHRcdFx0XHRcdFx0XHQnaXNfc2Nyb2xsJzogdHJ1ZVx0XHRcdFx0XHRcdFx0XHQvLyBpcyBzY3JvbGwgIHRvICB0aGlzIGVsZW1lbnRcclxuXHRcdFx0XHRcdFx0fTtcclxuXHRmb3IgKCB2YXIgcF9rZXkgaW4gcGFyYW1zICl7XHJcblx0XHRwYXJhbXNfZGVmYXVsdFsgcF9rZXkgXSA9IHBhcmFtc1sgcF9rZXkgXTtcclxuXHR9XHJcblx0cGFyYW1zID0gcGFyYW1zX2RlZmF1bHQ7XHJcblxyXG4gICAgdmFyIHVuaXF1ZV9kaXZfaWQgPSBuZXcgRGF0ZSgpO1xyXG4gICAgdW5pcXVlX2Rpdl9pZCA9ICd3cGJjX25vdGljZV8nICsgdW5pcXVlX2Rpdl9pZC5nZXRUaW1lKCk7XHJcblxyXG5cdHBhcmFtc1snY3NzX2NsYXNzJ10gKz0gJyB3cGJjX2ZlX21lc3NhZ2UnO1xyXG5cdGlmICggcGFyYW1zWyd0eXBlJ10gPT0gJ2Vycm9yJyApe1xyXG5cdFx0cGFyYW1zWydjc3NfY2xhc3MnXSArPSAnIHdwYmNfZmVfbWVzc2FnZV9lcnJvcic7XHJcblx0XHRtZXNzYWdlID0gJzxpIGNsYXNzPVwibWVudV9pY29uIGljb24tMXggd3BiY19pY25fcmVwb3J0X2dtYWlsZXJyb3JyZWRcIj48L2k+JyArIG1lc3NhZ2U7XHJcblx0fVxyXG5cdGlmICggcGFyYW1zWyd0eXBlJ10gPT0gJ3dhcm5pbmcnICl7XHJcblx0XHRwYXJhbXNbJ2Nzc19jbGFzcyddICs9ICcgd3BiY19mZV9tZXNzYWdlX3dhcm5pbmcnO1xyXG5cdFx0bWVzc2FnZSA9ICc8aSBjbGFzcz1cIm1lbnVfaWNvbiBpY29uLTF4IHdwYmNfaWNuX3dhcm5pbmdcIj48L2k+JyArIG1lc3NhZ2U7XHJcblx0fVxyXG5cdGlmICggcGFyYW1zWyd0eXBlJ10gPT0gJ2luZm8nICl7XHJcblx0XHRwYXJhbXNbJ2Nzc19jbGFzcyddICs9ICcgd3BiY19mZV9tZXNzYWdlX2luZm8nO1xyXG5cdH1cclxuXHRpZiAoIHBhcmFtc1sndHlwZSddID09ICdzdWNjZXNzJyApe1xyXG5cdFx0cGFyYW1zWydjc3NfY2xhc3MnXSArPSAnIHdwYmNfZmVfbWVzc2FnZV9zdWNjZXNzJztcclxuXHRcdG1lc3NhZ2UgPSAnPGkgY2xhc3M9XCJtZW51X2ljb24gaWNvbi0xeCB3cGJjX2ljbl9kb25lX291dGxpbmVcIj48L2k+JyArIG1lc3NhZ2U7XHJcblx0fVxyXG5cclxuXHR2YXIgc2Nyb2xsX3RvX2VsZW1lbnQgPSAnPGRpdiBpZD1cIicgKyB1bmlxdWVfZGl2X2lkICsgJ19zY3JvbGxcIiBzdHlsZT1cImRpc3BsYXk6bm9uZTtcIj48L2Rpdj4nO1xyXG5cdG1lc3NhZ2UgPSAnPGRpdiBpZD1cIicgKyB1bmlxdWVfZGl2X2lkICsgJ1wiIGNsYXNzPVwid3BiY19mcm9udF9lbmRfX21lc3NhZ2UgJyArIHBhcmFtc1snY3NzX2NsYXNzJ10gKyAnXCIgc3R5bGU9XCInICsgcGFyYW1zWyAnc3R5bGUnIF0gKyAnXCI+JyArIG1lc3NhZ2UgKyAnPC9kaXY+JztcclxuXHJcblxyXG5cdHZhciBqcV9lbF9tZXNzYWdlID0gZmFsc2U7XHJcblx0dmFyIGlzX3Nob3dfbWVzc2FnZSA9IHRydWU7XHJcblxyXG5cdGlmICggJ2luc2lkZScgPT09IHBhcmFtc1sgJ3Nob3dfaGVyZScgXVsgJ3doZXJlJyBdICl7XHJcblxyXG5cdFx0aWYgKCBwYXJhbXNbICdpc19hcHBlbmQnIF0gKXtcclxuXHRcdFx0alF1ZXJ5KCBwYXJhbXNbICdzaG93X2hlcmUnIF1bICdqcV9ub2RlJyBdICkuYXBwZW5kKCBzY3JvbGxfdG9fZWxlbWVudCApO1xyXG5cdFx0XHRqUXVlcnkoIHBhcmFtc1sgJ3Nob3dfaGVyZScgXVsgJ2pxX25vZGUnIF0gKS5hcHBlbmQoIG1lc3NhZ2UgKTtcclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdGpRdWVyeSggcGFyYW1zWyAnc2hvd19oZXJlJyBdWyAnanFfbm9kZScgXSApLmh0bWwoIHNjcm9sbF90b19lbGVtZW50ICsgbWVzc2FnZSApO1xyXG5cdFx0fVxyXG5cclxuXHR9IGVsc2UgaWYgKCAnYmVmb3JlJyA9PT0gcGFyYW1zWyAnc2hvd19oZXJlJyBdWyAnd2hlcmUnIF0gKXtcclxuXHJcblx0XHRqcV9lbF9tZXNzYWdlID0galF1ZXJ5KCBwYXJhbXNbICdzaG93X2hlcmUnIF1bICdqcV9ub2RlJyBdICkuc2libGluZ3MoICdbaWRePVwid3BiY19ub3RpY2VfXCJdJyApO1xyXG5cdFx0aWYgKCAocGFyYW1zWyAnaWZfdmlzaWJsZV9ub3Rfc2hvdycgXSkgJiYgKGpxX2VsX21lc3NhZ2UuaXMoICc6dmlzaWJsZScgKSkgKXtcclxuXHRcdFx0aXNfc2hvd19tZXNzYWdlID0gZmFsc2U7XHJcblx0XHRcdHVuaXF1ZV9kaXZfaWQgPSBqUXVlcnkoIGpxX2VsX21lc3NhZ2UuZ2V0KCAwICkgKS5hdHRyKCAnaWQnICk7XHJcblx0XHR9XHJcblx0XHRpZiAoIGlzX3Nob3dfbWVzc2FnZSApe1xyXG5cdFx0XHRqUXVlcnkoIHBhcmFtc1sgJ3Nob3dfaGVyZScgXVsgJ2pxX25vZGUnIF0gKS5iZWZvcmUoIHNjcm9sbF90b19lbGVtZW50ICk7XHJcblx0XHRcdGpRdWVyeSggcGFyYW1zWyAnc2hvd19oZXJlJyBdWyAnanFfbm9kZScgXSApLmJlZm9yZSggbWVzc2FnZSApO1xyXG5cdFx0fVxyXG5cclxuXHR9IGVsc2UgaWYgKCAnYWZ0ZXInID09PSBwYXJhbXNbICdzaG93X2hlcmUnIF1bICd3aGVyZScgXSApe1xyXG5cclxuXHRcdGpxX2VsX21lc3NhZ2UgPSBqUXVlcnkoIHBhcmFtc1sgJ3Nob3dfaGVyZScgXVsgJ2pxX25vZGUnIF0gKS5uZXh0QWxsKCAnW2lkXj1cIndwYmNfbm90aWNlX1wiXScgKTtcclxuXHRcdGlmICggKHBhcmFtc1sgJ2lmX3Zpc2libGVfbm90X3Nob3cnIF0pICYmIChqcV9lbF9tZXNzYWdlLmlzKCAnOnZpc2libGUnICkpICl7XHJcblx0XHRcdGlzX3Nob3dfbWVzc2FnZSA9IGZhbHNlO1xyXG5cdFx0XHR1bmlxdWVfZGl2X2lkID0galF1ZXJ5KCBqcV9lbF9tZXNzYWdlLmdldCggMCApICkuYXR0ciggJ2lkJyApO1xyXG5cdFx0fVxyXG5cdFx0aWYgKCBpc19zaG93X21lc3NhZ2UgKXtcclxuXHRcdFx0alF1ZXJ5KCBwYXJhbXNbICdzaG93X2hlcmUnIF1bICdqcV9ub2RlJyBdICkuYmVmb3JlKCBzY3JvbGxfdG9fZWxlbWVudCApO1x0XHQvLyBXZSBuZWVkIHRvICBzZXQgIGhlcmUgYmVmb3JlKGZvciBoYW5keSBzY3JvbGwpXHJcblx0XHRcdGpRdWVyeSggcGFyYW1zWyAnc2hvd19oZXJlJyBdWyAnanFfbm9kZScgXSApLmFmdGVyKCBtZXNzYWdlICk7XHJcblx0XHR9XHJcblxyXG5cdH0gZWxzZSBpZiAoICdyaWdodCcgPT09IHBhcmFtc1sgJ3Nob3dfaGVyZScgXVsgJ3doZXJlJyBdICl7XHJcblxyXG5cdFx0anFfZWxfbWVzc2FnZSA9IGpRdWVyeSggcGFyYW1zWyAnc2hvd19oZXJlJyBdWyAnanFfbm9kZScgXSApLm5leHRBbGwoICcud3BiY19mcm9udF9lbmRfX21lc3NhZ2VfY29udGFpbmVyX3JpZ2h0JyApLmZpbmQoICdbaWRePVwid3BiY19ub3RpY2VfXCJdJyApO1xyXG5cdFx0aWYgKCAocGFyYW1zWyAnaWZfdmlzaWJsZV9ub3Rfc2hvdycgXSkgJiYgKGpxX2VsX21lc3NhZ2UuaXMoICc6dmlzaWJsZScgKSkgKXtcclxuXHRcdFx0aXNfc2hvd19tZXNzYWdlID0gZmFsc2U7XHJcblx0XHRcdHVuaXF1ZV9kaXZfaWQgPSBqUXVlcnkoIGpxX2VsX21lc3NhZ2UuZ2V0KCAwICkgKS5hdHRyKCAnaWQnICk7XHJcblx0XHR9XHJcblx0XHRpZiAoIGlzX3Nob3dfbWVzc2FnZSApe1xyXG5cdFx0XHRqUXVlcnkoIHBhcmFtc1sgJ3Nob3dfaGVyZScgXVsgJ2pxX25vZGUnIF0gKS5iZWZvcmUoIHNjcm9sbF90b19lbGVtZW50ICk7XHRcdC8vIFdlIG5lZWQgdG8gIHNldCAgaGVyZSBiZWZvcmUoZm9yIGhhbmR5IHNjcm9sbClcclxuXHRcdFx0alF1ZXJ5KCBwYXJhbXNbICdzaG93X2hlcmUnIF1bICdqcV9ub2RlJyBdICkuYWZ0ZXIoICc8ZGl2IGNsYXNzPVwid3BiY19mcm9udF9lbmRfX21lc3NhZ2VfY29udGFpbmVyX3JpZ2h0XCI+JyArIG1lc3NhZ2UgKyAnPC9kaXY+JyApO1xyXG5cdFx0fVxyXG5cdH0gZWxzZSBpZiAoICdsZWZ0JyA9PT0gcGFyYW1zWyAnc2hvd19oZXJlJyBdWyAnd2hlcmUnIF0gKXtcclxuXHJcblx0XHRqcV9lbF9tZXNzYWdlID0galF1ZXJ5KCBwYXJhbXNbICdzaG93X2hlcmUnIF1bICdqcV9ub2RlJyBdICkuc2libGluZ3MoICcud3BiY19mcm9udF9lbmRfX21lc3NhZ2VfY29udGFpbmVyX2xlZnQnICkuZmluZCggJ1tpZF49XCJ3cGJjX25vdGljZV9cIl0nICk7XHJcblx0XHRpZiAoIChwYXJhbXNbICdpZl92aXNpYmxlX25vdF9zaG93JyBdKSAmJiAoanFfZWxfbWVzc2FnZS5pcyggJzp2aXNpYmxlJyApKSApe1xyXG5cdFx0XHRpc19zaG93X21lc3NhZ2UgPSBmYWxzZTtcclxuXHRcdFx0dW5pcXVlX2Rpdl9pZCA9IGpRdWVyeSgganFfZWxfbWVzc2FnZS5nZXQoIDAgKSApLmF0dHIoICdpZCcgKTtcclxuXHRcdH1cclxuXHRcdGlmICggaXNfc2hvd19tZXNzYWdlICl7XHJcblx0XHRcdGpRdWVyeSggcGFyYW1zWyAnc2hvd19oZXJlJyBdWyAnanFfbm9kZScgXSApLmJlZm9yZSggc2Nyb2xsX3RvX2VsZW1lbnQgKTtcdFx0Ly8gV2UgbmVlZCB0byAgc2V0ICBoZXJlIGJlZm9yZShmb3IgaGFuZHkgc2Nyb2xsKVxyXG5cdFx0XHRqUXVlcnkoIHBhcmFtc1sgJ3Nob3dfaGVyZScgXVsgJ2pxX25vZGUnIF0gKS5iZWZvcmUoICc8ZGl2IGNsYXNzPVwid3BiY19mcm9udF9lbmRfX21lc3NhZ2VfY29udGFpbmVyX2xlZnRcIj4nICsgbWVzc2FnZSArICc8L2Rpdj4nICk7XHJcblx0XHR9XHJcblx0fVxyXG5cclxuXHRpZiAoICAgKCBpc19zaG93X21lc3NhZ2UgKSAgJiYgICggcGFyc2VJbnQoIHBhcmFtc1sgJ2RlbGF5JyBdICkgPiAwICkgICApe1xyXG5cdFx0dmFyIGNsb3NlZF90aW1lciA9IHNldFRpbWVvdXQoIGZ1bmN0aW9uICgpe1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdGpRdWVyeSggJyMnICsgdW5pcXVlX2Rpdl9pZCApLmZhZGVPdXQoIDE1MDAgKTtcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHR9ICwgcGFyc2VJbnQoIHBhcmFtc1sgJ2RlbGF5JyBdICkgICApO1xyXG5cclxuXHRcdHZhciBjbG9zZWRfdGltZXIyID0gc2V0VGltZW91dCggZnVuY3Rpb24gKCl7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRqUXVlcnkoICcjJyArIHVuaXF1ZV9kaXZfaWQgKS50cmlnZ2VyKCAnaGlkZScgKTtcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHR9LCAoIHBhcnNlSW50KCBwYXJhbXNbICdkZWxheScgXSApICsgMTUwMSApICk7XHJcblx0fVxyXG5cclxuXHQvLyBDaGVjayAgaWYgc2hvd2VkIG1lc3NhZ2UgaW4gc29tZSBoaWRkZW4gcGFyZW50IHNlY3Rpb24gYW5kIHNob3cgaXQuIEJ1dCBpdCBtdXN0ICBiZSBsb3dlciB0aGFuICcud3BiY19jb250YWluZXInXHJcblx0dmFyIHBhcmVudF9lbHMgPSBqUXVlcnkoICcjJyArIHVuaXF1ZV9kaXZfaWQgKS5wYXJlbnRzKCkubWFwKCBmdW5jdGlvbiAoKXtcclxuXHRcdGlmICggKCFqUXVlcnkoIHRoaXMgKS5pcyggJ3Zpc2libGUnICkpICYmIChqUXVlcnkoICcud3BiY19jb250YWluZXInICkuaGFzKCB0aGlzICkpICl7XHJcblx0XHRcdGpRdWVyeSggdGhpcyApLnNob3coKTtcclxuXHRcdH1cclxuXHR9ICk7XHJcblxyXG5cdGlmICggcGFyYW1zWyAnaXNfc2Nyb2xsJyBdICl7XHJcblx0XHR3cGJjX2RvX3Njcm9sbCggJyMnICsgdW5pcXVlX2Rpdl9pZCArICdfc2Nyb2xsJyApO1xyXG5cdH1cclxuXHJcblx0cmV0dXJuIHVuaXF1ZV9kaXZfaWQ7XHJcbn1cclxuXHJcblxyXG5cdC8qKlxyXG5cdCAqIEVycm9yIG1lc3NhZ2UuIFx0UHJlc2V0IG9mIHBhcmFtZXRlcnMgZm9yIHJlYWwgbWVzc2FnZSBmdW5jdGlvbi5cclxuXHQgKlxyXG5cdCAqIEBwYXJhbSBlbFx0XHQtIGFueSBqUXVlcnkgbm9kZSBkZWZpbml0aW9uXHJcblx0ICogQHBhcmFtIG1lc3NhZ2VcdC0gTWVzc2FnZSBIVE1MXHJcblx0ICogQHJldHVybnMgc3RyaW5nICAtIEhUTUwgSURcdFx0b3IgMCBpZiBub3Qgc2hvd2luZyBkdXJpbmcgdGhpcyB0aW1lLlxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdwYmNfZnJvbnRfZW5kX19zaG93X21lc3NhZ2VfX2Vycm9yKCBqcV9ub2RlLCBtZXNzYWdlICl7XHJcblxyXG5cdFx0dmFyIG5vdGljZV9tZXNzYWdlX2lkID0gd3BiY19mcm9udF9lbmRfX3Nob3dfbWVzc2FnZShcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRtZXNzYWdlLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdHtcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCd0eXBlJyAgICAgICAgICAgICAgIDogJ2Vycm9yJyxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCdkZWxheScgICAgICAgICAgICAgIDogMTAwMDAsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnaWZfdmlzaWJsZV9ub3Rfc2hvdyc6IHRydWUsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnc2hvd19oZXJlJyAgICAgICAgICA6IHtcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCd3aGVyZScgIDogJ3JpZ2h0JyxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCdqcV9ub2RlJzoganFfbm9kZVxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCAgIH1cclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQpO1xyXG5cdFx0cmV0dXJuIG5vdGljZV9tZXNzYWdlX2lkO1xyXG5cdH1cclxuXHJcblxyXG5cdC8qKlxyXG5cdCAqIEVycm9yIG1lc3NhZ2UgVU5ERVIgZWxlbWVudC4gXHRQcmVzZXQgb2YgcGFyYW1ldGVycyBmb3IgcmVhbCBtZXNzYWdlIGZ1bmN0aW9uLlxyXG5cdCAqXHJcblx0ICogQHBhcmFtIGVsXHRcdC0gYW55IGpRdWVyeSBub2RlIGRlZmluaXRpb25cclxuXHQgKiBAcGFyYW0gbWVzc2FnZVx0LSBNZXNzYWdlIEhUTUxcclxuXHQgKiBAcmV0dXJucyBzdHJpbmcgIC0gSFRNTCBJRFx0XHRvciAwIGlmIG5vdCBzaG93aW5nIGR1cmluZyB0aGlzIHRpbWUuXHJcblx0ICovXHJcblx0ZnVuY3Rpb24gd3BiY19mcm9udF9lbmRfX3Nob3dfbWVzc2FnZV9fZXJyb3JfdW5kZXJfZWxlbWVudCgganFfbm9kZSwgbWVzc2FnZSwgbWVzc2FnZV9kZWxheSApe1xyXG5cclxuXHRcdGlmICggJ3VuZGVmaW5lZCcgPT09IHR5cGVvZiAobWVzc2FnZV9kZWxheSkgKXtcclxuXHRcdFx0bWVzc2FnZV9kZWxheSA9IDBcclxuXHRcdH1cclxuXHJcblx0XHR2YXIgbm90aWNlX21lc3NhZ2VfaWQgPSB3cGJjX2Zyb250X2VuZF9fc2hvd19tZXNzYWdlKFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdG1lc3NhZ2UsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0e1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J3R5cGUnICAgICAgICAgICAgICAgOiAnZXJyb3InLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J2RlbGF5JyAgICAgICAgICAgICAgOiBtZXNzYWdlX2RlbGF5LFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J2lmX3Zpc2libGVfbm90X3Nob3cnOiB0cnVlLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J3Nob3dfaGVyZScgICAgICAgICAgOiB7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnd2hlcmUnICA6ICdhZnRlcicsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnanFfbm9kZSc6IGpxX25vZGVcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQgICB9XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0KTtcclxuXHRcdHJldHVybiBub3RpY2VfbWVzc2FnZV9pZDtcclxuXHR9XHJcblxyXG5cclxuXHQvKipcclxuXHQgKiBFcnJvciBtZXNzYWdlIFVOREVSIGVsZW1lbnQuIFx0UHJlc2V0IG9mIHBhcmFtZXRlcnMgZm9yIHJlYWwgbWVzc2FnZSBmdW5jdGlvbi5cclxuXHQgKlxyXG5cdCAqIEBwYXJhbSBlbFx0XHQtIGFueSBqUXVlcnkgbm9kZSBkZWZpbml0aW9uXHJcblx0ICogQHBhcmFtIG1lc3NhZ2VcdC0gTWVzc2FnZSBIVE1MXHJcblx0ICogQHJldHVybnMgc3RyaW5nICAtIEhUTUwgSURcdFx0b3IgMCBpZiBub3Qgc2hvd2luZyBkdXJpbmcgdGhpcyB0aW1lLlxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdwYmNfZnJvbnRfZW5kX19zaG93X21lc3NhZ2VfX2Vycm9yX2Fib3ZlX2VsZW1lbnQoIGpxX25vZGUsIG1lc3NhZ2UsIG1lc3NhZ2VfZGVsYXkgKXtcclxuXHJcblx0XHRpZiAoICd1bmRlZmluZWQnID09PSB0eXBlb2YgKG1lc3NhZ2VfZGVsYXkpICl7XHJcblx0XHRcdG1lc3NhZ2VfZGVsYXkgPSAxMDAwMFxyXG5cdFx0fVxyXG5cclxuXHRcdHZhciBub3RpY2VfbWVzc2FnZV9pZCA9IHdwYmNfZnJvbnRfZW5kX19zaG93X21lc3NhZ2UoXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0bWVzc2FnZSxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHR7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQndHlwZScgICAgICAgICAgICAgICA6ICdlcnJvcicsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnZGVsYXknICAgICAgICAgICAgICA6IG1lc3NhZ2VfZGVsYXksXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnaWZfdmlzaWJsZV9ub3Rfc2hvdyc6IHRydWUsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnc2hvd19oZXJlJyAgICAgICAgICA6IHtcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCd3aGVyZScgIDogJ2JlZm9yZScsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnanFfbm9kZSc6IGpxX25vZGVcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQgICB9XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0KTtcclxuXHRcdHJldHVybiBub3RpY2VfbWVzc2FnZV9pZDtcclxuXHR9XHJcblxyXG5cclxuXHQvKipcclxuXHQgKiBXYXJuaW5nIG1lc3NhZ2UuIFx0UHJlc2V0IG9mIHBhcmFtZXRlcnMgZm9yIHJlYWwgbWVzc2FnZSBmdW5jdGlvbi5cclxuXHQgKlxyXG5cdCAqIEBwYXJhbSBlbFx0XHQtIGFueSBqUXVlcnkgbm9kZSBkZWZpbml0aW9uXHJcblx0ICogQHBhcmFtIG1lc3NhZ2VcdC0gTWVzc2FnZSBIVE1MXHJcblx0ICogQHJldHVybnMgc3RyaW5nICAtIEhUTUwgSURcdFx0b3IgMCBpZiBub3Qgc2hvd2luZyBkdXJpbmcgdGhpcyB0aW1lLlxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdwYmNfZnJvbnRfZW5kX19zaG93X21lc3NhZ2VfX3dhcm5pbmcoIGpxX25vZGUsIG1lc3NhZ2UgKXtcclxuXHJcblx0XHR2YXIgbm90aWNlX21lc3NhZ2VfaWQgPSB3cGJjX2Zyb250X2VuZF9fc2hvd19tZXNzYWdlKFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdG1lc3NhZ2UsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0e1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J3R5cGUnICAgICAgICAgICAgICAgOiAnd2FybmluZycsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnZGVsYXknICAgICAgICAgICAgICA6IDEwMDAwLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J2lmX3Zpc2libGVfbm90X3Nob3cnOiB0cnVlLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J3Nob3dfaGVyZScgICAgICAgICAgOiB7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnd2hlcmUnICA6ICdyaWdodCcsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnanFfbm9kZSc6IGpxX25vZGVcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQgICB9XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0KTtcclxuXHRcdHdwYmNfaGlnaGxpZ2h0X2Vycm9yX29uX2Zvcm1fZmllbGQoIGpxX25vZGUgKTtcclxuXHRcdHJldHVybiBub3RpY2VfbWVzc2FnZV9pZDtcclxuXHR9XHJcblxyXG5cclxuXHQvKipcclxuXHQgKiBXYXJuaW5nIG1lc3NhZ2UgVU5ERVIgZWxlbWVudC4gXHRQcmVzZXQgb2YgcGFyYW1ldGVycyBmb3IgcmVhbCBtZXNzYWdlIGZ1bmN0aW9uLlxyXG5cdCAqXHJcblx0ICogQHBhcmFtIGVsXHRcdC0gYW55IGpRdWVyeSBub2RlIGRlZmluaXRpb25cclxuXHQgKiBAcGFyYW0gbWVzc2FnZVx0LSBNZXNzYWdlIEhUTUxcclxuXHQgKiBAcmV0dXJucyBzdHJpbmcgIC0gSFRNTCBJRFx0XHRvciAwIGlmIG5vdCBzaG93aW5nIGR1cmluZyB0aGlzIHRpbWUuXHJcblx0ICovXHJcblx0ZnVuY3Rpb24gd3BiY19mcm9udF9lbmRfX3Nob3dfbWVzc2FnZV9fd2FybmluZ191bmRlcl9lbGVtZW50KCBqcV9ub2RlLCBtZXNzYWdlICl7XHJcblxyXG5cdFx0dmFyIG5vdGljZV9tZXNzYWdlX2lkID0gd3BiY19mcm9udF9lbmRfX3Nob3dfbWVzc2FnZShcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRtZXNzYWdlLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdHtcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCd0eXBlJyAgICAgICAgICAgICAgIDogJ3dhcm5pbmcnLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J2RlbGF5JyAgICAgICAgICAgICAgOiAxMDAwMCxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCdpZl92aXNpYmxlX25vdF9zaG93JzogdHJ1ZSxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCdzaG93X2hlcmUnICAgICAgICAgIDoge1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J3doZXJlJyAgOiAnYWZ0ZXInLFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0J2pxX25vZGUnOiBqcV9ub2RlXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0ICAgfVxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCk7XHJcblx0XHRyZXR1cm4gbm90aWNlX21lc3NhZ2VfaWQ7XHJcblx0fVxyXG5cclxuXHJcblx0LyoqXHJcblx0ICogV2FybmluZyBtZXNzYWdlIEFCT1ZFIGVsZW1lbnQuIFx0UHJlc2V0IG9mIHBhcmFtZXRlcnMgZm9yIHJlYWwgbWVzc2FnZSBmdW5jdGlvbi5cclxuXHQgKlxyXG5cdCAqIEBwYXJhbSBlbFx0XHQtIGFueSBqUXVlcnkgbm9kZSBkZWZpbml0aW9uXHJcblx0ICogQHBhcmFtIG1lc3NhZ2VcdC0gTWVzc2FnZSBIVE1MXHJcblx0ICogQHJldHVybnMgc3RyaW5nICAtIEhUTUwgSURcdFx0b3IgMCBpZiBub3Qgc2hvd2luZyBkdXJpbmcgdGhpcyB0aW1lLlxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdwYmNfZnJvbnRfZW5kX19zaG93X21lc3NhZ2VfX3dhcm5pbmdfYWJvdmVfZWxlbWVudCgganFfbm9kZSwgbWVzc2FnZSApe1xyXG5cclxuXHRcdHZhciBub3RpY2VfbWVzc2FnZV9pZCA9IHdwYmNfZnJvbnRfZW5kX19zaG93X21lc3NhZ2UoXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0bWVzc2FnZSxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHR7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQndHlwZScgICAgICAgICAgICAgICA6ICd3YXJuaW5nJyxcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCdkZWxheScgICAgICAgICAgICAgIDogMTAwMDAsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnaWZfdmlzaWJsZV9ub3Rfc2hvdyc6IHRydWUsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnc2hvd19oZXJlJyAgICAgICAgICA6IHtcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCd3aGVyZScgIDogJ2JlZm9yZScsXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnanFfbm9kZSc6IGpxX25vZGVcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQgICB9XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0KTtcclxuXHRcdHJldHVybiBub3RpY2VfbWVzc2FnZV9pZDtcclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIEhpZ2hsaWdodCBFcnJvciBpbiBzcGVjaWZpYyBmaWVsZFxyXG5cdCAqXHJcblx0ICogQHBhcmFtIGpxX25vZGVcdFx0XHRcdFx0c3RyaW5nIG9yIGpRdWVyeSBlbGVtZW50LCAgd2hlcmUgc2Nyb2xsICB0b1xyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdwYmNfaGlnaGxpZ2h0X2Vycm9yX29uX2Zvcm1fZmllbGQoIGpxX25vZGUgKXtcclxuXHJcblx0XHRpZiAoICFqUXVlcnkoIGpxX25vZGUgKS5sZW5ndGggKXtcclxuXHRcdFx0cmV0dXJuO1xyXG5cdFx0fVxyXG5cdFx0aWYgKCAhIGpRdWVyeSgganFfbm9kZSApLmlzKCAnOmlucHV0JyApICl7XHJcblx0XHRcdC8vIFNpdHVhdGlvbiB3aXRoICBjaGVja2JveGVzIG9yIHJhZGlvICBidXR0b25zXHJcblx0XHRcdHZhciBqcV9ub2RlX2FyciA9IGpRdWVyeSgganFfbm9kZSApLmZpbmQoICc6aW5wdXQnICk7XHJcblx0XHRcdGlmICggIWpxX25vZGVfYXJyLmxlbmd0aCApe1xyXG5cdFx0XHRcdHJldHVyblxyXG5cdFx0XHR9XHJcblx0XHRcdGpxX25vZGUgPSBqcV9ub2RlX2Fyci5nZXQoIDAgKTtcclxuXHRcdH1cclxuXHRcdHZhciBwYXJhbXMgPSB7fTtcclxuXHRcdHBhcmFtc1sgJ2RlbGF5JyBdID0gMTAwMDA7XHJcblxyXG5cdFx0aWYgKCAhalF1ZXJ5KCBqcV9ub2RlICkuaGFzQ2xhc3MoICd3cGJjX2Zvcm1fZmllbGRfZXJyb3InICkgKXtcclxuXHJcblx0XHRcdGpRdWVyeSgganFfbm9kZSApLmFkZENsYXNzKCAnd3BiY19mb3JtX2ZpZWxkX2Vycm9yJyApXHJcblxyXG5cdFx0XHRpZiAoIHBhcnNlSW50KCBwYXJhbXNbICdkZWxheScgXSApID4gMCApe1xyXG5cdFx0XHRcdHZhciBjbG9zZWRfdGltZXIgPSBzZXRUaW1lb3V0KCBmdW5jdGlvbiAoKXtcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0IGpRdWVyeSgganFfbm9kZSApLnJlbW92ZUNsYXNzKCAnd3BiY19mb3JtX2ZpZWxkX2Vycm9yJyApO1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0ICB9XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHQgICAsIHBhcnNlSW50KCBwYXJhbXNbICdkZWxheScgXSApXHJcblx0XHRcdFx0XHRcdFx0XHRcdCk7XHJcblxyXG5cdFx0XHR9XHJcblx0XHR9XHJcblx0fVxyXG5cclxuLyoqXHJcbiAqIFNjcm9sbCB0byBzcGVjaWZpYyBlbGVtZW50XHJcbiAqXHJcbiAqIEBwYXJhbSBqcV9ub2RlXHRcdFx0XHRcdHN0cmluZyBvciBqUXVlcnkgZWxlbWVudCwgIHdoZXJlIHNjcm9sbCAgdG9cclxuICogQHBhcmFtIGV4dHJhX3NoaWZ0X29mZnNldFx0XHRpbnQgc2hpZnQgb2Zmc2V0IGZyb20gIGpxX25vZGVcclxuICovXHJcbmZ1bmN0aW9uIHdwYmNfZG9fc2Nyb2xsKCBqcV9ub2RlICwgZXh0cmFfc2hpZnRfb2Zmc2V0ID0gMCApe1xyXG5cclxuXHRpZiAoICFqUXVlcnkoIGpxX25vZGUgKS5sZW5ndGggKXtcclxuXHRcdHJldHVybjtcclxuXHR9XHJcblx0dmFyIHRhcmdldE9mZnNldCA9IGpRdWVyeSgganFfbm9kZSApLm9mZnNldCgpLnRvcDtcclxuXHJcblx0aWYgKCB0YXJnZXRPZmZzZXQgPD0gMCApe1xyXG5cdFx0aWYgKCAwICE9IGpRdWVyeSgganFfbm9kZSApLm5leHRBbGwoICc6dmlzaWJsZScgKS5sZW5ndGggKXtcclxuXHRcdFx0dGFyZ2V0T2Zmc2V0ID0galF1ZXJ5KCBqcV9ub2RlICkubmV4dEFsbCggJzp2aXNpYmxlJyApLmZpcnN0KCkub2Zmc2V0KCkudG9wO1xyXG5cdFx0fSBlbHNlIGlmICggMCAhPSBqUXVlcnkoIGpxX25vZGUgKS5wYXJlbnQoKS5uZXh0QWxsKCAnOnZpc2libGUnICkubGVuZ3RoICl7XHJcblx0XHRcdHRhcmdldE9mZnNldCA9IGpRdWVyeSgganFfbm9kZSApLnBhcmVudCgpLm5leHRBbGwoICc6dmlzaWJsZScgKS5maXJzdCgpLm9mZnNldCgpLnRvcDtcclxuXHRcdH1cclxuXHR9XHJcblxyXG5cdGlmICggalF1ZXJ5KCAnI3dwYWRtaW5iYXInICkubGVuZ3RoID4gMCApe1xyXG5cdFx0dGFyZ2V0T2Zmc2V0ID0gdGFyZ2V0T2Zmc2V0IC0gNTAgLSA1MDtcclxuXHR9IGVsc2Uge1xyXG5cdFx0dGFyZ2V0T2Zmc2V0ID0gdGFyZ2V0T2Zmc2V0IC0gMjAgLSA1MDtcclxuXHR9XHJcblx0dGFyZ2V0T2Zmc2V0ICs9IGV4dHJhX3NoaWZ0X29mZnNldDtcclxuXHJcblx0Ly8gU2Nyb2xsIG9ubHkgIGlmIHdlIGRpZCBub3Qgc2Nyb2xsIGJlZm9yZVxyXG5cdGlmICggISBqUXVlcnkoICdodG1sLGJvZHknICkuaXMoICc6YW5pbWF0ZWQnICkgKXtcclxuXHRcdGpRdWVyeSggJ2h0bWwsYm9keScgKS5hbmltYXRlKCB7c2Nyb2xsVG9wOiB0YXJnZXRPZmZzZXR9LCA1MDAgKTtcclxuXHR9XHJcbn1cclxuXHJcbiIsIlxyXG4vLyBGaXhJbjogMTAuMi4wLjQuXHJcbi8qKlxyXG4gKiBEZWZpbmUgUG9wb3ZlcnMgZm9yIFRpbWVsaW5lcyBpbiBXUCBCb29raW5nIENhbGVuZGFyXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd8Ym9vbGVhbn1cclxuICovXHJcbmZ1bmN0aW9uIHdwYmNfZGVmaW5lX3RpcHB5X3BvcG92ZXIoKXtcclxuXHRpZiAoICdmdW5jdGlvbicgIT09IHR5cGVvZiAod3BiY190aXBweSkgKXtcclxuXHRcdGNvbnNvbGUubG9nKCAnV1BCQyBFcnJvci4gd3BiY190aXBweSB3YXMgbm90IGRlZmluZWQuJyApO1xyXG5cdFx0cmV0dXJuIGZhbHNlO1xyXG5cdH1cclxuXHR3cGJjX3RpcHB5KCAnLnBvcG92ZXJfYm90dG9tLnBvcG92ZXJfY2xpY2snLCB7XHJcblx0XHRjb250ZW50KCByZWZlcmVuY2UgKXtcclxuXHRcdFx0dmFyIHBvcG92ZXJfdGl0bGUgPSByZWZlcmVuY2UuZ2V0QXR0cmlidXRlKCAnZGF0YS1vcmlnaW5hbC10aXRsZScgKTtcclxuXHRcdFx0dmFyIHBvcG92ZXJfY29udGVudCA9IHJlZmVyZW5jZS5nZXRBdHRyaWJ1dGUoICdkYXRhLWNvbnRlbnQnICk7XHJcblx0XHRcdHJldHVybiAnPGRpdiBjbGFzcz1cInBvcG92ZXIgcG9wb3Zlcl90aXBweVwiPidcclxuXHRcdFx0XHQrICc8ZGl2IGNsYXNzPVwicG9wb3Zlci1jbG9zZVwiPjxhIGhyZWY9XCJqYXZhc2NyaXB0OnZvaWQoMClcIiBvbmNsaWNrPVwiamF2YXNjcmlwdDp0aGlzLnBhcmVudEVsZW1lbnQucGFyZW50RWxlbWVudC5wYXJlbnRFbGVtZW50LnBhcmVudEVsZW1lbnQucGFyZW50RWxlbWVudC5fdGlwcHkuaGlkZSgpO1wiID4mdGltZXM7PC9hPjwvZGl2PidcclxuXHRcdFx0XHQrIHBvcG92ZXJfY29udGVudFxyXG5cdFx0XHRcdCsgJzwvZGl2Pic7XHJcblx0XHR9LFxyXG5cdFx0YWxsb3dIVE1MICAgICAgICA6IHRydWUsXHJcblx0XHR0cmlnZ2VyICAgICAgICAgIDogJ21hbnVhbCcsXHJcblx0XHRpbnRlcmFjdGl2ZSAgICAgIDogdHJ1ZSxcclxuXHRcdGhpZGVPbkNsaWNrICAgICAgOiBmYWxzZSxcclxuXHRcdGludGVyYWN0aXZlQm9yZGVyOiAxMCxcclxuXHRcdG1heFdpZHRoICAgICAgICAgOiA1NTAsXHJcblx0XHR0aGVtZSAgICAgICAgICAgIDogJ3dwYmMtdGlwcHktcG9wb3ZlcicsXHJcblx0XHRwbGFjZW1lbnQgICAgICAgIDogJ2JvdHRvbS1zdGFydCcsXHJcblx0XHR0b3VjaCAgICAgICAgICAgIDogWydob2xkJywgNTAwXSxcclxuXHR9ICk7XHJcblx0alF1ZXJ5KCAnLnBvcG92ZXJfYm90dG9tLnBvcG92ZXJfY2xpY2snICkub24oICdjbGljaycsIGZ1bmN0aW9uICgpe1xyXG5cdFx0aWYgKCB0aGlzLl90aXBweS5zdGF0ZS5pc1Zpc2libGUgKXtcclxuXHRcdFx0dGhpcy5fdGlwcHkuaGlkZSgpO1xyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0dGhpcy5fdGlwcHkuc2hvdygpO1xyXG5cdFx0fVxyXG5cdH0gKTtcclxuXHR3cGJjX2RlZmluZV9oaWRlX3RpcHB5X29uX3Njcm9sbCgpO1xyXG59XHJcblxyXG5cclxuXHJcbmZ1bmN0aW9uIHdwYmNfZGVmaW5lX2hpZGVfdGlwcHlfb25fc2Nyb2xsKCl7XHJcblx0alF1ZXJ5KCAnLmZsZXhfdGxfX3Njcm9sbGluZ19zZWN0aW9uMiwuZmxleF90bF9fc2Nyb2xsaW5nX3NlY3Rpb25zJyApLm9uKCAnc2Nyb2xsJywgZnVuY3Rpb24gKCBldmVudCApe1xyXG5cdFx0aWYgKCAnZnVuY3Rpb24nID09PSB0eXBlb2YgKHdwYmNfdGlwcHkpICl7XHJcblx0XHRcdHdwYmNfdGlwcHkuaGlkZUFsbCgpO1xyXG5cdFx0fVxyXG5cdH0gKTtcclxufVxyXG4iLCIvKipcclxuICogV1BCQyBjYWxlbmRhciBsb2FkZXIgYm9vdHN0cmFwLlxyXG4gKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcbiAqIC0gRmluZHMgZXZlcnkgLmNhbGVuZGFyX2xvYWRlcl9mcmFtZVtkYXRhLXdwYmMtcmlkXSBvbiB0aGUgcGFnZSAobm93IG9yIGxhdGVyKS5cclxuICogLSBGb3IgZWFjaCBsb2FkZXIgZWxlbWVudCwgd2FpdHMgYSBcImdyYWNlXCIgcGVyaW9kIChkYXRhLXdwYmMtZ3JhY2UsIGRlZmF1bHQgODAwMCBtcyk6XHJcbiAqICAgICAtIElmIHRoZSByZWFsIGNhbGVuZGFyIGFwcGVhcnM6IGRvIG5vdGhpbmcgKGxvYWRlciBuYXR1cmFsbHkgcmVwbGFjZWQpLlxyXG4gKiAgICAgLSBJZiBub3Q6IHNob3cgYSBoZWxwZnVsIG1lc3NhZ2UgKG1pc3NpbmcgalF1ZXJ5L193cGJjL2RhdGVwaWNrKSBvciBhIGR1cGxpY2F0ZSBub3RpY2UuXHJcbiAqIC0gV29ya3Mgd2l0aCBtdWx0aXBsZSBjYWxlbmRhcnMgYW5kIGV2ZW4gZHVwbGljYXRlIFJJRHMgb24gdGhlIHNhbWUgcGFnZS5cclxuICogLSBObyBpbmxpbmUgSlMgbmVlZGVkIGluIHRoZSBzaG9ydGNvZGUvdGVtcGxhdGUgb3V0cHV0LlxyXG4gKlxyXG4gKiBGaWxlOiAgLi4vaW5jbHVkZXMvX19qcy9jbGllbnQvY2FsL3dwYmNfY2FsX2xvYWRlci5qc1xyXG4gKlxyXG4gKiBAc2luY2UgICAgMTAuMTQuNVxyXG4gKiBAbW9kaWZpZWQgMjAyNS0wOS0wNyAxMjoyMVxyXG4gKiBAdmVyc2lvbiAgMS4wLjBcclxuICpcclxuICovXHJcbi8qKlxyXG4gKiBXUEJDIGNhbGVuZGFyIGxvYWRlciBib290c3RyYXAuXHJcbiAqIC0gQXV0by1kZXRlY3RzIC5jYWxlbmRhcl9sb2FkZXJfZnJhbWVbZGF0YS13cGJjLXJpZF0gYmxvY2tzLlxyXG4gKiAtIFdhaXRzIGEgXCJncmFjZVwiIHBlcmlvZCBwZXIgZWxlbWVudCBiZWZvcmUgc2hvd2luZyBhIGhlbHBmdWwgbWVzc2FnZVxyXG4gKiAgIGlmIHRoZSByZWFsIGNhbGVuZGFyIGhhc24ndCByZXBsYWNlZCB0aGUgbG9hZGVyLlxyXG4gKiAtIE11bHRpcGxlIGNhbGVuZGFycyBhbmQgZHVwbGljYXRlIFJJRHMgYXJlIGhhbmRsZWQuXHJcbiAqL1xyXG4oZnVuY3Rpb24gKHcsIGQpIHtcclxuXHQndXNlIHN0cmljdCc7XHJcblxyXG5cdC8qIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdCAqIFNtYWxsIHV0aWxpdGllcyAoc25ha2VfY2FzZSlcclxuXHQgKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi9cclxuXHJcblx0LyoqIFRyYWNrIHByb2Nlc3NlZCBsb2FkZXIgZWxlbWVudHM7IGZhbGxiYWNrIHRvIGRhdGEgZmxhZyBpZiBXZWFrU2V0IG1pc3NpbmcuICovXHJcblx0dmFyIHByb2Nlc3NlZF9zZXQgPSB0eXBlb2YgV2Vha1NldCA9PT0gJ2Z1bmN0aW9uJyA/IG5ldyBXZWFrU2V0KCkgOiBudWxsO1xyXG5cclxuXHQvKiogUmV0dXJuIGZpcnN0IG1hdGNoIGluc2lkZSBvcHRpb25hbCByb290LiAqL1xyXG5cdGZ1bmN0aW9uIHF1ZXJ5X29uZShzZWxlY3Rvciwgcm9vdCkge1xyXG5cdFx0cmV0dXJuIChyb290IHx8IGQpLnF1ZXJ5U2VsZWN0b3IoIHNlbGVjdG9yICk7XHJcblx0fVxyXG5cclxuXHQvKiogUmV0dXJuIE5vZGVMaXN0IG9mIG1hdGNoZXMgaW5zaWRlIG9wdGlvbmFsIHJvb3QuICovXHJcblx0ZnVuY3Rpb24gcXVlcnlfYWxsKHNlbGVjdG9yLCByb290KSB7XHJcblx0XHRyZXR1cm4gKHJvb3QgfHwgZCkucXVlcnlTZWxlY3RvckFsbCggc2VsZWN0b3IgKTtcclxuXHR9XHJcblxyXG5cdC8qKiBSdW4gYSBjYWxsYmFjayB3aGVuIERPTSBpcyByZWFkeS4gKi9cclxuXHRmdW5jdGlvbiBvbl9yZWFkeShmbikge1xyXG5cdFx0aWYgKCBkLnJlYWR5U3RhdGUgPT09ICdsb2FkaW5nJyApIHtcclxuXHRcdFx0ZC5hZGRFdmVudExpc3RlbmVyKCAnRE9NQ29udGVudExvYWRlZCcsIGZuICk7XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHRmbigpO1xyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0LyoqIENsZWFyIGludGVydmFsIHNhZmVseS4gKi9cclxuXHRmdW5jdGlvbiBzYWZlX2NsZWFyKGludGVydmFsX2lkKSB7XHJcblx0XHR0cnkge1xyXG5cdFx0XHR3LmNsZWFySW50ZXJ2YWwoIGludGVydmFsX2lkICk7XHJcblx0XHR9IGNhdGNoICggZSApIHtcclxuXHRcdH1cclxuXHR9XHJcblxyXG5cdC8qKiBNYXJrIGVsZW1lbnQgcHJvY2Vzc2VkIChXZWFrU2V0IG9yIGRhdGEgYXR0cmlidXRlKS4gKi9cclxuXHRmdW5jdGlvbiBtYXJrX3Byb2Nlc3NlZChlbCkge1xyXG5cdFx0aWYgKCBwcm9jZXNzZWRfc2V0ICkge1xyXG5cdFx0XHRwcm9jZXNzZWRfc2V0LmFkZCggZWwgKTtcclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdHRyeSB7XHJcblx0XHRcdFx0ZWwuZGF0YXNldC53cGJjUHJvY2Vzc2VkID0gJzEnO1xyXG5cdFx0XHR9IGNhdGNoICggZSApIHtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0LyoqIENoZWNrIGlmIGVsZW1lbnQgd2FzIHByb2Nlc3NlZC4gKi9cclxuXHRmdW5jdGlvbiBpc19wcm9jZXNzZWQoZWwpIHtcclxuXHRcdHJldHVybiBwcm9jZXNzZWRfc2V0ID8gcHJvY2Vzc2VkX3NldC5oYXMoIGVsICkgOiAoZWwgJiYgZWwuZGF0YXNldCAmJiBlbC5kYXRhc2V0LndwYmNQcm9jZXNzZWQgPT09ICcxJyk7XHJcblx0fVxyXG5cclxuXHQvKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHQgKiBNZXNzYWdlcyAoZml4ZWQgRW5nbGlzaCBzdHJpbmdzOyBubyBpMThuKVxyXG5cdCAqIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqL1xyXG5cclxuXHQvKipcclxuXHQgKiBCdWlsZCBmaXhlZCBFbmdsaXNoIG1lc3NhZ2VzIGZvciBhIHJlc291cmNlLlxyXG5cdCAqIEBwYXJhbSB7c3RyaW5nfG51bWJlcn0gcmlkXHJcblx0ICogQHJldHVybiB7e2R1cGxpY2F0ZTpzdHJpbmcsc3VwcG9ydDpzdHJpbmcsbGliX2pxOnN0cmluZyxsaWJfZHA6c3RyaW5nLGxpYl93cGJjOnN0cmluZ319XHJcblx0ICovXHJcblx0ZnVuY3Rpb24gZ2V0X21lc3NhZ2VzKHJpZCkge1xyXG5cdFx0dmFyIHJpZF9pbnQgPSBwYXJzZUludCggcmlkLCAxMCApO1xyXG5cdFx0cmV0dXJuIHtcclxuXHRcdFx0ZHVwbGljYXRlICA6XHJcblx0XHRcdFx0J1lvdSBoYXZlIGFkZGVkIHRoZSBzYW1lIGNhbGVuZGFyIChJRCA9ICcgKyByaWRfaW50ICsgJykgbW9yZSB0aGFuIG9uY2Ugb24gdGhpcyBwYWdlLiAnICtcclxuXHRcdFx0XHQnUGxlYXNlIGtlZXAgb25seSBvbmUgY2FsZW5kYXIgd2l0aCB0aGUgc2FtZSBJRCBvbiBhIHBhZ2UgdG8gYXZvaWQgY29uZmxpY3RzLicsXHJcblx0XHRcdGluaXRfZmFpbGVkOlxyXG5cdFx0XHRcdCdUaGUgY2FsZW5kYXIgY291bGQgbm90IGJlIGluaXRpYWxpemVkIG9uIHRoaXMgcGFnZS4nICsgJ1xcbicgK1xyXG5cdFx0XHRcdCdQbGVhc2UgY2hlY2sgeW91ciBicm93c2VyIGNvbnNvbGUgZm9yIEphdmFTY3JpcHQgZXJyb3JzIGFuZCBjb25mbGljdHMgd2l0aCBvdGhlciBzY3JpcHRzL3BsdWdpbnMuJyxcclxuXHRcdFx0c3VwcG9ydCAgICA6ICcnLCAvKiAnQ29udGFjdCBzdXBwb3J0QHdwYm9va2luZ2NhbGVuZGFyLmNvbSBpZiB5b3UgaGF2ZSBhbnkgcXVlc3Rpb25zLicsICovXHJcblx0XHRcdGxpYl9qcSAgICAgOlxyXG5cdFx0XHRcdCdJdCBhcHBlYXJzIHRoYXQgdGhlIFwialF1ZXJ5XCIgbGlicmFyeSBpcyBub3QgbG9hZGluZyBjb3JyZWN0bHkuJyArICdcXG4nICtcclxuXHRcdFx0XHQnRm9yIG1vcmUgaW5mb3JtYXRpb24sIHBsZWFzZSByZWZlciB0byB0aGlzIHBhZ2U6IGh0dHBzOi8vd3Bib29raW5nY2FsZW5kYXIuY29tL2ZhcS8nLFxyXG5cdFx0XHRsaWJfZHAgICAgIDpcclxuXHRcdFx0XHQnSXQgYXBwZWFycyB0aGF0IHRoZSBcImpRdWVyeS5kYXRlcGlja1wiIGxpYnJhcnkgaXMgbm90IGxvYWRpbmcgY29ycmVjdGx5LicgKyAnXFxuJyArXHJcblx0XHRcdFx0J0ZvciBtb3JlIGluZm9ybWF0aW9uLCBwbGVhc2UgcmVmZXIgdG8gdGhpcyBwYWdlOiBodHRwczovL3dwYm9va2luZ2NhbGVuZGFyLmNvbS9mYXEvJyxcclxuXHRcdFx0bGliX3dwYmMgICA6XHJcblx0XHRcdFx0J0l0IGFwcGVhcnMgdGhhdCB0aGUgXCJfd3BiY1wiIGxpYnJhcnkgaXMgbm90IGxvYWRpbmcgY29ycmVjdGx5LicgKyAnXFxuJyArXHJcblx0XHRcdFx0J1BsZWFzZSBlbmFibGUgdGhlIGxvYWRpbmcgb2YgSlMvQ1NTIGZpbGVzIGZvciB0aGlzIHBhZ2Ugb24gdGhlIFwiV1AgQm9va2luZyBDYWxlbmRhclwiIC0gXCJTZXR0aW5ncyBHZW5lcmFsXCIgLSBcIkFkdmFuY2VkXCIgcGFnZScgKyAnXFxuJyArXHJcblx0XHRcdFx0J0ZvciBtb3JlIGluZm9ybWF0aW9uLCBwbGVhc2UgcmVmZXIgdG8gdGhpcyBwYWdlOiBodHRwczovL3dwYm9va2luZ2NhbGVuZGFyLmNvbS9mYXEvJ1xyXG5cdFx0fTtcclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIFdyYXAgcGxhaW4gdGV4dCAod2l0aCBuZXdsaW5lcykgaW4gYSBzbWFsbCBIVE1MIGNvbnRhaW5lci5cclxuXHQgKiBAcGFyYW0ge3N0cmluZ30gbXNnXHJcblx0ICogQHJldHVybiB7c3RyaW5nfVxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdyYXBfaHRtbChtc2cpIHtcclxuXHRcdHJldHVybiAnPGRpdiBzdHlsZT1cImZvbnQtc2l6ZToxM3B4O21hcmdpbjoxMHB4O1wiPicgKyBTdHJpbmcoIG1zZyB8fCAnJyApLnJlcGxhY2UoIC9cXG4vZywgJzxicj4nICkgKyAnPC9kaXY+JztcclxuXHR9XHJcblxyXG5cdC8qKiBMaWJyYXJ5IHByZXNlbmNlIGNoZWNrcyAoZmFzdCAmIGNoZWFwKS4gKi9cclxuXHRmdW5jdGlvbiBoYXNfanEoKSB7XHJcblx0XHRyZXR1cm4gISEody5qUXVlcnkgJiYgalF1ZXJ5LmZuICYmIHR5cGVvZiBqUXVlcnkuZm4ub24gPT09ICdmdW5jdGlvbicpO1xyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gaGFzX2RwKCkge1xyXG5cdFx0cmV0dXJuICEhKHcualF1ZXJ5ICYmIGpRdWVyeS5kYXRlcGljayk7XHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBoYXNfd3BiYygpIHtcclxuXHRcdHJldHVybiAhISh3Ll93cGJjICYmIHR5cGVvZiB3Ll93cGJjLnNldF9vdGhlcl9wYXJhbSA9PT0gJ2Z1bmN0aW9uJyk7XHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBub3JtYWxpemVfcmlkKHJpZCkge1xyXG5cdFx0dmFyIG4gPSBwYXJzZUludCggcmlkLCAxMCApO1xyXG5cdFx0cmV0dXJuIChuID4gMCkgPyBTdHJpbmcoIG4gKSA6ICcnO1xyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gZ2V0X3JpZF9jb3VudHMocmlkKSB7XHJcblx0XHR2YXIgciA9IG5vcm1hbGl6ZV9yaWQoIHJpZCApO1xyXG5cdFx0cmV0dXJuIHtcclxuXHRcdFx0cmlkICAgICAgIDogcixcclxuXHRcdFx0bG9hZGVycyAgIDogciA/IHF1ZXJ5X2FsbCggJy5jYWxlbmRhcl9sb2FkZXJfZnJhbWVbZGF0YS13cGJjLXJpZD1cIicgKyByICsgJ1wiXScgKS5sZW5ndGggOiAwLFxyXG5cdFx0XHRjb250YWluZXJzOiByID8gcXVlcnlfYWxsKCAnI2NhbGVuZGFyX2Jvb2tpbmcnICsgciApLmxlbmd0aCA6IDBcclxuXHRcdH07XHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBpc19kdXBsaWNhdGVfcmlkKHJpZCkge1xyXG5cdFx0dmFyIGMgPSBnZXRfcmlkX2NvdW50cyggcmlkICk7XHJcblx0XHRyZXR1cm4gKGMubG9hZGVycyA+IDEpIHx8IChjLmNvbnRhaW5lcnMgPiAxKTtcclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIERldGVybWluZSBpZiB0aGUgbG9hZGVyIGhhcyBiZWVuIHJlcGxhY2VkIGJ5IHRoZSByZWFsIGNhbGVuZGFyLlxyXG5cdCAqXHJcblx0ICogQHBhcmFtIHtFbGVtZW50fSBlbCAgICAgICBMb2FkZXIgZWxlbWVudFxyXG5cdCAqIEBwYXJhbSB7c3RyaW5nfSByaWQgICAgICAgUmVzb3VyY2UgSURcclxuXHQgKiBAcGFyYW0ge0VsZW1lbnR8bnVsbH0gY29udGFpbmVyIE9wdGlvbmFsICNjYWxlbmRhcl9ib29raW5ne3JpZH0gZWxlbWVudFxyXG5cdCAqIEByZXR1cm4ge2Jvb2xlYW59XHJcblx0ICovXHJcblx0ZnVuY3Rpb24gaXNfcmVwbGFjZWQoZWwsIHJpZCwgY29udGFpbmVyKSB7XHJcblx0XHR2YXIgbG9hZGVyX3N0aWxsX2luX2RvbSA9IGQuYm9keS5jb250YWlucyggZWwgKTtcclxuXHRcdHZhciBjYWxlbmRhcl9leGlzdHMgICAgID0gISFxdWVyeV9vbmUoICcud3BiY19jYWxlbmRhcl9pZF8nICsgcmlkLCBjb250YWluZXIgfHwgZCApO1xyXG5cdFx0cmV0dXJuICghbG9hZGVyX3N0aWxsX2luX2RvbSkgfHwgY2FsZW5kYXJfZXhpc3RzO1xyXG5cdH1cclxuXHJcblx0LyoqXHJcblx0ICogU3RhcnQgd2F0Y2hlciBmb3IgYSBzaW5nbGUgbG9hZGVyIGVsZW1lbnQuXHJcblx0ICogLSBQb2xscyBhbmQgb2JzZXJ2ZXMgdGhlIGNhbGVuZGFyIGNvbnRhaW5lci5cclxuXHQgKiAtIEFmdGVyIGdyYWNlLCBpbmplY3RzIGEgc3VpdGFibGUgbWVzc2FnZSBpZiBub3QgcmVwbGFjZWQuXHJcblx0ICpcclxuXHQgKiBAcGFyYW0ge0VsZW1lbnR9IGVsXHJcblx0ICovXHJcblx0ZnVuY3Rpb24gc3RhcnRfZm9yKGVsKSB7XHJcblx0XHRpZiAoICEgZWwgfHwgaXNfcHJvY2Vzc2VkKCBlbCApICkge1xyXG5cdFx0XHRyZXR1cm47XHJcblx0XHR9XHJcblx0XHRtYXJrX3Byb2Nlc3NlZCggZWwgKTtcclxuXHJcblx0XHR2YXIgcmlkID0gZWwuZGF0YXNldC53cGJjUmlkO1xyXG5cdFx0aWYgKCAhIHJpZCApIHtcclxuXHRcdFx0cmV0dXJuO1xyXG5cdFx0fVxyXG5cclxuXHRcdHZhciBncmFjZV9tcyA9IHBhcnNlSW50KCBlbC5kYXRhc2V0LndwYmNHcmFjZSB8fCAnODAwMCcsIDEwICk7XHJcblx0XHRpZiAoICEgKGdyYWNlX21zID4gMCkgKSB7XHJcblx0XHRcdGdyYWNlX21zID0gODAwMDtcclxuXHRcdH1cclxuXHJcblx0XHR2YXIgY29udGFpbmVyX2lkID0gJ2NhbGVuZGFyX2Jvb2tpbmcnICsgcmlkO1xyXG5cdFx0dmFyIGNvbnRhaW5lciAgICA9IGQuZ2V0RWxlbWVudEJ5SWQoIGNvbnRhaW5lcl9pZCApO1xyXG5cdFx0dmFyIHRleHRfZWwgICAgICA9IHF1ZXJ5X29uZSggJy5jYWxlbmRhcl9sb2FkZXJfdGV4dCcsIGVsICk7XHJcblxyXG5cdFx0ZnVuY3Rpb24gcmVwbGFjZWRfbm93KCkge1xyXG5cdFx0XHRyZXR1cm4gaXNfcmVwbGFjZWQoIGVsLCByaWQsIGNvbnRhaW5lciApO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8vIEFscmVhZHkgcmVwbGFjZWQgLT4gbm90aGluZyB0byBkby5cclxuXHRcdGlmICggcmVwbGFjZWRfbm93KCkgKSB7XHJcblx0XHRcdHJldHVybjtcclxuXHRcdH1cclxuXHJcblx0XHQvLyAxKSBDaGVhcCBwb2xsaW5nLlxyXG5cdFx0dmFyIHBvbGxfaWQgPSB3LnNldEludGVydmFsKCBmdW5jdGlvbiAoKSB7XHJcblx0XHRcdGlmICggcmVwbGFjZWRfbm93KCkgKSB7XHJcblx0XHRcdFx0c2FmZV9jbGVhciggcG9sbF9pZCApO1xyXG5cdFx0XHRcdGlmICggb2JzZXJ2ZXIgKSB7XHJcblx0XHRcdFx0XHR0cnkge1xyXG5cdFx0XHRcdFx0XHRvYnNlcnZlci5kaXNjb25uZWN0KCk7XHJcblx0XHRcdFx0XHR9IGNhdGNoICggZSApIHtcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHRcdH0sIDI1MCApO1xyXG5cclxuXHRcdC8vIDIpIE11dGF0aW9uT2JzZXJ2ZXIgZm9yIGZhc3RlciByZWFjdGlvbi5cclxuXHRcdHZhciBvYnNlcnZlciA9IG51bGw7XHJcblx0XHRpZiAoIGNvbnRhaW5lciAmJiAnTXV0YXRpb25PYnNlcnZlcicgaW4gdyApIHtcclxuXHRcdFx0dHJ5IHtcclxuXHRcdFx0XHRvYnNlcnZlciA9IG5ldyBNdXRhdGlvbk9ic2VydmVyKCBmdW5jdGlvbiAoKSB7XHJcblx0XHRcdFx0XHRpZiAoIHJlcGxhY2VkX25vdygpICkge1xyXG5cdFx0XHRcdFx0XHRzYWZlX2NsZWFyKCBwb2xsX2lkICk7XHJcblx0XHRcdFx0XHRcdHRyeSB7XHJcblx0XHRcdFx0XHRcdFx0b2JzZXJ2ZXIuZGlzY29ubmVjdCgpO1xyXG5cdFx0XHRcdFx0XHR9IGNhdGNoICggZSApIHtcclxuXHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdH0gKTtcclxuXHRcdFx0XHRvYnNlcnZlci5vYnNlcnZlKCBjb250YWluZXIsIHsgY2hpbGRMaXN0OiB0cnVlLCBzdWJ0cmVlOiB0cnVlIH0gKTtcclxuXHRcdFx0fSBjYXRjaCAoIGUgKSB7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHQvLyAzKSBGaW5hbCBkZWNpc2lvbiBhZnRlciBncmFjZSBwZXJpb2QuXHJcblx0XHR3LnNldFRpbWVvdXQoIGZ1bmN0aW9uIGZpbmFsaXplX2FmdGVyX2dyYWNlKCkge1xyXG5cdFx0XHRpZiAoIHJlcGxhY2VkX25vdygpICkge1xyXG5cdFx0XHRcdHNhZmVfY2xlYXIoIHBvbGxfaWQgKTtcclxuXHRcdFx0XHRpZiAoIG9ic2VydmVyICkge1xyXG5cdFx0XHRcdFx0dHJ5IHtcclxuXHRcdFx0XHRcdFx0b2JzZXJ2ZXIuZGlzY29ubmVjdCgpO1xyXG5cdFx0XHRcdFx0fSBjYXRjaCAoIGUgKSB7XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0fVxyXG5cdFx0XHRcdHJldHVybjtcclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0dmFyIE0gPSBnZXRfbWVzc2FnZXMoIHJpZCApO1xyXG5cdFx0XHR2YXIgbXNnO1xyXG5cdFx0XHRpZiAoICEgaGFzX2pxKCkgKSB7XHJcblx0XHRcdFx0bXNnID0gTS5saWJfanE7XHJcblx0XHRcdH0gZWxzZSBpZiAoICEgaGFzX3dwYmMoKSApIHtcclxuXHRcdFx0XHRtc2cgPSBNLmxpYl93cGJjO1xyXG5cdFx0XHR9IGVsc2UgaWYgKCAhIGhhc19kcCgpICkge1xyXG5cdFx0XHRcdG1zZyA9IE0ubGliX2RwO1xyXG5cdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdC8vIExpYnJhcmllcyBhcmUgcHJlc2VudCwgYnV0IGxvYWRlciB3YXNuJ3QgcmVwbGFjZWQgLT4gZGVjaWRlIHdoYXQgaXMgbW9zdCBsaWtlbHkuXHJcblx0XHRcdFx0aWYgKCBpc19kdXBsaWNhdGVfcmlkKCByaWQgKSApIHtcclxuXHRcdFx0XHRcdG1zZyA9IE0uZHVwbGljYXRlICsgJ1xcblxcbicgKyBNLnN1cHBvcnQ7XHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRcdG1zZyA9IE0uaW5pdF9mYWlsZWQgKyAnXFxuXFxuJyArIE0uc3VwcG9ydDtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHRyeSB7XHJcblx0XHRcdFx0aWYgKCB0ZXh0X2VsICkge1xyXG5cdFx0XHRcdFx0dGV4dF9lbC5pbm5lckhUTUwgPSB3cmFwX2h0bWwoIG1zZyApO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fSBjYXRjaCAoIGUgKSB7XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHNhZmVfY2xlYXIoIHBvbGxfaWQgKTtcclxuXHRcdFx0aWYgKCBvYnNlcnZlciApIHtcclxuXHRcdFx0XHR0cnkge1xyXG5cdFx0XHRcdFx0b2JzZXJ2ZXIuZGlzY29ubmVjdCgpO1xyXG5cdFx0XHRcdH0gY2F0Y2ggKCBlICkge1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fVxyXG5cdFx0fSwgZ3JhY2VfbXMgKTtcclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIEluaXRpYWxpemUgd2F0Y2hlcnMgZm9yIGxvYWRlciBlbGVtZW50cyBhbHJlYWR5IGluIHRoZSBET00uXHJcblx0ICovXHJcblx0ZnVuY3Rpb24gYm9vdHN0cmFwX2V4aXN0aW5nKCkge1xyXG5cdFx0cXVlcnlfYWxsKCAnLmNhbGVuZGFyX2xvYWRlcl9mcmFtZVtkYXRhLXdwYmMtcmlkXScgKS5mb3JFYWNoKCBzdGFydF9mb3IgKTtcclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIE9ic2VydmUgdGhlIGRvY3VtZW50IGZvciBhbnkgbmV3IGxvYWRlciBlbGVtZW50cyBpbnNlcnRlZCBsYXRlciAoQUpBWCwgYmxvY2sgcmVuZGVyKS5cclxuXHQgKi9cclxuXHRmdW5jdGlvbiBvYnNlcnZlX25ld19sb2FkZXJzKCkge1xyXG5cdFx0aWYgKCAhICgnTXV0YXRpb25PYnNlcnZlcicgaW4gdykgKSB7XHJcblx0XHRcdHJldHVybjtcclxuXHRcdH1cclxuXHRcdHRyeSB7XHJcblx0XHRcdHZhciBkb2Nfb2JzZXJ2ZXIgPSBuZXcgTXV0YXRpb25PYnNlcnZlciggZnVuY3Rpb24gKG11dGF0aW9ucykge1xyXG5cdFx0XHRcdGZvciAoIHZhciBpID0gMDsgaSA8IG11dGF0aW9ucy5sZW5ndGg7IGkrKyApIHtcclxuXHRcdFx0XHRcdHZhciBub2RlcyA9IG11dGF0aW9uc1tpXS5hZGRlZE5vZGVzIHx8IFtdO1xyXG5cdFx0XHRcdFx0Zm9yICggdmFyIGogPSAwOyBqIDwgbm9kZXMubGVuZ3RoOyBqKysgKSB7XHJcblx0XHRcdFx0XHRcdHZhciBub2RlID0gbm9kZXNbal07XHJcblx0XHRcdFx0XHRcdGlmICggISBub2RlIHx8IG5vZGUubm9kZVR5cGUgIT09IDEgKSB7XHJcblx0XHRcdFx0XHRcdFx0Y29udGludWU7XHJcblx0XHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdFx0aWYgKCBub2RlLm1hdGNoZXMgJiYgbm9kZS5tYXRjaGVzKCAnLmNhbGVuZGFyX2xvYWRlcl9mcmFtZVtkYXRhLXdwYmMtcmlkXScgKSApIHtcclxuXHRcdFx0XHRcdFx0XHRzdGFydF9mb3IoIG5vZGUgKTtcclxuXHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHRpZiAoIG5vZGUucXVlcnlTZWxlY3RvckFsbCApIHtcclxuXHRcdFx0XHRcdFx0XHR2YXIgaW5uZXIgPSBub2RlLnF1ZXJ5U2VsZWN0b3JBbGwoICcuY2FsZW5kYXJfbG9hZGVyX2ZyYW1lW2RhdGEtd3BiYy1yaWRdJyApO1xyXG5cdFx0XHRcdFx0XHRcdGlmICggaW5uZXIgJiYgaW5uZXIubGVuZ3RoICkge1xyXG5cdFx0XHRcdFx0XHRcdFx0aW5uZXIuZm9yRWFjaCggc3RhcnRfZm9yICk7XHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9ICk7XHJcblx0XHRcdGRvY19vYnNlcnZlci5vYnNlcnZlKCBkLmRvY3VtZW50RWxlbWVudCwgeyBjaGlsZExpc3Q6IHRydWUsIHN1YnRyZWU6IHRydWUgfSApO1xyXG5cdFx0fSBjYXRjaCAoIGUgKSB7XHJcblx0XHR9XHJcblx0fVxyXG5cclxuXHQvKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHQgKiBCb290XHJcblx0ICogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovXHJcblx0b25fcmVhZHkoIGZ1bmN0aW9uICgpIHtcclxuXHRcdGJvb3RzdHJhcF9leGlzdGluZygpO1xyXG5cdFx0b2JzZXJ2ZV9uZXdfbG9hZGVycygpO1xyXG5cdH0gKTtcclxuXHJcbn0pKCB3aW5kb3csIGRvY3VtZW50ICk7XHJcbiIsIihmdW5jdGlvbiggdyApIHtcclxuXHJcblx0J3VzZSBzdHJpY3QnO1xyXG5cclxuXHRpZiAoICEgdy5XUEJDX0ZFICkge1xyXG5cdFx0dy5XUEJDX0ZFID0ge307XHJcblx0fVxyXG5cclxuXHQvKipcclxuXHQgKiBBdXRvLWZpbGwgYm9va2luZyBmb3JtIGZpZWxkcyAodGV4dC9lbWFpbCkgYmFzZWQgb24gaW5wdXQgXCJuYW1lXCIgcGF0dGVybnMuXHJcblx0ICpcclxuXHQgKiBGb3JtIElEIGZvcm1hdDogYm9va2luZ19mb3Jte3Jlc291cmNlX2lkfVxyXG5cdCAqIFNraXBzIGRhdGUgZmllbGQ6IGRhdGVfYm9va2luZ3tyZXNvdXJjZV9pZH1cclxuXHQgKlxyXG5cdCAqIEBwYXJhbSB7bnVtYmVyfSByZXNvdXJjZV9pZCBCb29raW5nIHJlc291cmNlIElELlxyXG5cdCAqIEBwYXJhbSB7T2JqZWN0fSBmaWxsX3ZhbHVlcyBWYWx1ZXMgdG8gaW5qZWN0IChzdHJpbmdzKS5cclxuXHQgKlxyXG5cdCAqIEByZXR1cm4ge2Jvb2xlYW59IFRydWUgaWYgZm9ybSBmb3VuZCBhbmQgcHJvY2Vzc2VkLCBmYWxzZSBvdGhlcndpc2UuXHJcblx0ICovXHJcblx0dy5XUEJDX0ZFLmF1dG9maWxsX2Jvb2tpbmdfZm9ybV9maWVsZHMgPSBmdW5jdGlvbiggcmVzb3VyY2VfaWQsIGZpbGxfdmFsdWVzICkge1xyXG5cclxuXHRcdHJlc291cmNlX2lkICA9IHBhcnNlSW50KCByZXNvdXJjZV9pZCwgMTAgKSB8fCAwO1xyXG5cdFx0ZmlsbF92YWx1ZXMgID0gZmlsbF92YWx1ZXMgfHwge307XHJcblxyXG5cdFx0dmFyIGZvcm1faWQgICA9ICdib29raW5nX2Zvcm0nICsgcmVzb3VyY2VfaWQ7XHJcblx0XHR2YXIgZGF0ZV9uYW1lID0gJ2RhdGVfYm9va2luZycgKyByZXNvdXJjZV9pZDtcclxuXHJcblx0XHR2YXIgc3VibWl0X2Zvcm0gPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCggZm9ybV9pZCApO1xyXG5cclxuXHRcdGlmICggISBzdWJtaXRfZm9ybSApIHtcclxuXHRcdFx0LyogZXNsaW50LWRpc2FibGUgbm8tY29uc29sZSAqL1xyXG5cdFx0XHRjb25zb2xlLmVycm9yKCAnV1BCQzogTm8gYm9va2luZyBmb3JtOiAnICsgZm9ybV9pZCApO1xyXG5cdFx0XHQvKiBlc2xpbnQtZW5hYmxlIG5vLWNvbnNvbGUgKi9cclxuXHRcdFx0cmV0dXJuIGZhbHNlO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8vIEtlZXAgc2FtZSByZWdleCBydWxlcyBhbmQgcHJpb3JpdHkgb3JkZXIgYXMgbGVnYWN5IGlubGluZSBKUy5cclxuXHRcdHZhciBydWxlcyA9IGFycmF5X3J1bGVzKCBmaWxsX3ZhbHVlcyApO1xyXG5cclxuXHRcdHZhciBlbGVtZW50cyA9IHN1Ym1pdF9mb3JtLmVsZW1lbnRzIHx8IFtdO1xyXG5cdFx0dmFyIGNvdW50ICAgID0gZWxlbWVudHMubGVuZ3RoO1xyXG5cdFx0dmFyIGVsO1xyXG5cdFx0dmFyIGk7XHJcblx0XHR2YXIgajtcclxuXHJcblx0XHRmb3IgKCBpID0gMDsgaSA8IGNvdW50OyBpKysgKSB7XHJcblxyXG5cdFx0XHRlbCA9IGVsZW1lbnRzWyBpIF07XHJcblxyXG5cdFx0XHRpZiAoICEgZWwgfHwgISBlbC5uYW1lICkge1xyXG5cdFx0XHRcdGNvbnRpbnVlO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBPbmx5IHRleHQvZW1haWwgaW5wdXRzLlxyXG5cdFx0XHRpZiAoICggZWwudHlwZSAhPT0gJ3RleHQnICkgJiYgKCBlbC50eXBlICE9PSAnZW1haWwnICkgKSB7XHJcblx0XHRcdFx0Y29udGludWU7XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIFNraXAgZGF0ZSBmaWVsZC5cclxuXHRcdFx0aWYgKCBlbC5uYW1lID09PSBkYXRlX25hbWUgKSB7XHJcblx0XHRcdFx0Y29udGludWU7XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIEZpbGwgb25seSBlbXB0eSB2YWx1ZXMgKGxlZ2FjeSBiZWhhdmlvcjogPT0gXCJcIikuXHJcblx0XHRcdGlmICggZWwudmFsdWUgIT09ICcnICkge1xyXG5cdFx0XHRcdGNvbnRpbnVlO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRmb3IgKCBqID0gMDsgaiA8IHJ1bGVzLmxlbmd0aDsgaisrICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIHJ1bGVzWyBqIF0ucmUudGVzdCggZWwubmFtZSApICkge1xyXG5cclxuXHRcdFx0XHRcdGlmICggcnVsZXNbIGogXS52YWwgIT09ICcnICkge1xyXG5cdFx0XHRcdFx0XHRlbC52YWx1ZSA9IHJ1bGVzWyBqIF0udmFsO1xyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGJyZWFrOyAvLyBTdG9wIGF0IGZpcnN0IG1hdGNoaW5nIHJ1bGUgKHByaW9yaXR5KS5cclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdHJ1ZTtcclxuXHR9O1xyXG5cclxuXHQvKipcclxuXHQgKiBCdWlsZCBydWxlcyBhcnJheSBmb3IgYXV0b2ZpbGwuXHJcblx0ICpcclxuXHQgKiBAcGFyYW0ge09iamVjdH0gZmlsbF92YWx1ZXMgVmFsdWVzIHRvIGluamVjdC5cclxuXHQgKlxyXG5cdCAqIEByZXR1cm4ge0FycmF5fSBSdWxlcyBsaXN0LlxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIGFycmF5X3J1bGVzKCBmaWxsX3ZhbHVlcyApIHtcclxuXHJcblx0XHQvLyBOb3JtYWxpemUgdG8gc3RyaW5ncyAocHJldmVudCBcInVuZGVmaW5lZFwiIGluIGZpZWxkcykuXHJcblx0XHR2YXIgbmlja25hbWUgID0gKCBmaWxsX3ZhbHVlcy5uaWNrbmFtZSAhPSBudWxsICkgPyBTdHJpbmcoIGZpbGxfdmFsdWVzLm5pY2tuYW1lICkgOiAnJztcclxuXHRcdHZhciBsYXN0X25hbWUgPSAoIGZpbGxfdmFsdWVzLmxhc3RfbmFtZSAhPSBudWxsICkgPyBTdHJpbmcoIGZpbGxfdmFsdWVzLmxhc3RfbmFtZSApIDogJyc7XHJcblx0XHR2YXIgZmlyc3RfbmFtZSA9ICggZmlsbF92YWx1ZXMuZmlyc3RfbmFtZSAhPSBudWxsICkgPyBTdHJpbmcoIGZpbGxfdmFsdWVzLmZpcnN0X25hbWUgKSA6ICcnO1xyXG5cdFx0dmFyIGVtYWlsICAgICA9ICggZmlsbF92YWx1ZXMuZW1haWwgIT0gbnVsbCApID8gU3RyaW5nKCBmaWxsX3ZhbHVlcy5lbWFpbCApIDogJyc7XHJcblx0XHR2YXIgcGhvbmUgICAgID0gKCBmaWxsX3ZhbHVlcy5waG9uZSAhPSBudWxsICkgPyBTdHJpbmcoIGZpbGxfdmFsdWVzLnBob25lICkgOiAnJztcclxuXHRcdHZhciBuYl9lbmZhbnQgPSAoIGZpbGxfdmFsdWVzLm5iX2VuZmFudCAhPSBudWxsICkgPyBTdHJpbmcoIGZpbGxfdmFsdWVzLm5iX2VuZmFudCApIDogJyc7XHJcblx0XHR2YXIgdXJsICAgICAgID0gKCBmaWxsX3ZhbHVlcy51cmwgIT0gbnVsbCApID8gU3RyaW5nKCBmaWxsX3ZhbHVlcy51cmwgKSA6ICcnO1xyXG5cclxuXHRcdHJldHVybiBbXHJcblx0XHRcdHsgcmU6IC9eKFtBLVphLXowLTlfXFwtXFwuXSkqKG5pY2tuYW1lKXsxfShbQS1aYS16MC05X1xcLVxcLl0pKiQvLCB2YWw6IG5pY2tuYW1lIH0sXHJcblx0XHRcdHsgcmU6IC9eKFtBLVphLXowLTlfXFwtXFwuXSkqKGxhc3R8c2Vjb25kKXsxfShbX1xcLVxcLl0pP25hbWUoW0EtWmEtejAtOV9cXC1cXC5dKSokLywgdmFsOiBsYXN0X25hbWUgfSxcclxuXHRcdFx0eyByZTogL15uYW1lKFswLTlfXFwtXFwuXSkqJC8sIHZhbDogZmlyc3RfbmFtZSB9LFxyXG5cdFx0XHR7IHJlOiAvXihbQS1aYS16MC05X1xcLVxcLl0pKihmaXJzdHxteSl7MX0oW19cXC1cXC5dKT9uYW1lKFtBLVphLXowLTlfXFwtXFwuXSkqJC8sIHZhbDogZmlyc3RfbmFtZSB9LFxyXG5cdFx0XHR7IHJlOiAvXihlKT8oW19cXC1cXC5dKT9tYWlsKFswLTlfXFwtXFwuXSopJC8sIHZhbDogZW1haWwgfSxcclxuXHRcdFx0eyByZTogL14oW0EtWmEtejAtOV9cXC1cXC5dKSoocGhvbmV8Zm9uZSl7MX0oW0EtWmEtejAtOV9cXC1cXC5dKSokLywgdmFsOiBwaG9uZSB9LFxyXG5cdFx0XHR7IHJlOiAvXihlKT8oW19cXC1cXC5dKT9uYl9lbmZhbnQoWzAtOV9cXC1cXC5dKikkLywgdmFsOiBuYl9lbmZhbnQgfSxcclxuXHRcdFx0eyByZTogL14oW0EtWmEtejAtOV9cXC1cXC5dKSooVVJMfHNpdGV8d2VifFdFQil7MX0oW0EtWmEtejAtOV9cXC1cXC5dKSokLywgdmFsOiB1cmwgfVxyXG5cdFx0XTtcclxuXHR9XHJcblxyXG59KSggd2luZG93ICk7XHJcbiIsIi8vID09IFN1Ym1pdCBCb29raW5nIERhdGEgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG4vLyBSZWZhY3RvcmVkIChzYWZlKSwgd2l0aCBuZXcgd3BiY18qIG5hbWVzLlxyXG4vLyBCYWNrd2FyZC1jb21wYXRpYmxlIHdyYXBwZXJzIGZvciBsZWdhY3kgZnVuY3Rpb24gbmFtZXMgYXJlIGluY2x1ZGVkIGF0IHRoZSBib3R0b20uXHJcbi8vIEBmaWxlOiBpbmNsdWRlcy9fX2pzL2NsaWVudC9mcm9udF9lbmRfZm9ybS9ib29raW5nX2Zvcm1fc3VibWl0LmpzXHJcblxyXG4vKipcclxuICogQ2hlY2sgZmllbGRzIGF0IGZvcm0gYW5kIHRoZW4gc2VuZCByZXF1ZXN0IChsZWdhY3k6IG15Ym9va2luZ19zdWJtaXQpLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0hUTUxGb3JtRWxlbWVudH0gc3VibWl0X2Zvcm1cclxuICogQHBhcmFtIHtudW1iZXJ8c3RyaW5nfSAgIHJlc291cmNlX2lkXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSAgICAgICAgICB3cGRldl9hY3RpdmVfbG9jYWxlXHJcbiAqXHJcbiAqIEByZXR1cm4ge2ZhbHNlfHVuZGVmaW5lZH0gTGVnYWN5IGJlaGF2aW9yOiByZXR1cm5zIGZhbHNlIGluIHNvbWUgY2FzZXMsIG90aGVyd2lzZSB1bmRlZmluZWQuXHJcbiAqL1xyXG5mdW5jdGlvbiB3cGJjX2Jvb2tpbmdfZm9ybV9zdWJtaXQoIHN1Ym1pdF9mb3JtLCByZXNvdXJjZV9pZCwgd3BkZXZfYWN0aXZlX2xvY2FsZSApIHtcclxuXHJcblx0cmVzb3VyY2VfaWQgPSBwYXJzZUludCggcmVzb3VyY2VfaWQsIDEwICk7XHJcblxyXG5cdC8vIFNhZmV0eSBndWFyZCAobGVnYWN5IGNvZGUgYXNzdW1lZCB2YWxpZCBmb3JtKS5cclxuXHRpZiAoICEgc3VibWl0X2Zvcm0gfHwgISBzdWJtaXRfZm9ybS5lbGVtZW50cyApIHtcclxuXHRcdC8qIGVzbGludC1kaXNhYmxlIG5vLWNvbnNvbGUgKi9cclxuXHRcdGNvbnNvbGUuZXJyb3IoICdXUEJDOiBJbnZhbGlkIHN1Ym1pdCBmb3JtIGluIHdwYmNfYm9va2luZ19mb3JtX3N1Ym1pdCgpLicgKTtcclxuXHRcdC8qIGVzbGludC1lbmFibGUgbm8tY29uc29sZSAqL1xyXG5cdFx0cmV0dXJuIGZhbHNlO1xyXG5cdH1cclxuXHJcblx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdC8vIEV4dGVybmFsIGhvb2s6IGFsbG93IHBhdXNlIHN1Ym1pdCBvbiBjb25maXJtYXRpb24vc3VtbWFyeSBzdGVwLlxyXG5cdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHR2YXIgdGFyZ2V0X2VsbSA9IGpRdWVyeSggJy5ib29raW5nX2Zvcm1fZGl2JyApLnRyaWdnZXIoICdib29raW5nX2Zvcm1fc3VibWl0X2NsaWNrJywgWyByZXNvdXJjZV9pZCwgc3VibWl0X2Zvcm0sIHdwZGV2X2FjdGl2ZV9sb2NhbGUgXSApOyAvLyBGaXhJbjogOC44LjMuMTMuXHJcblxyXG5cdGlmIChcclxuXHRcdCggalF1ZXJ5KCB0YXJnZXRfZWxtICkuZmluZCggJ2lucHV0W25hbWU9XCJib29raW5nX2Zvcm1fc2hvd19zdW1tYXJ5XCJdJyApLmxlbmd0aCA+IDAgKSAmJlxyXG5cdFx0KCAncGF1c2Vfc3VibWl0JyA9PT0galF1ZXJ5KCB0YXJnZXRfZWxtICkuZmluZCggJ2lucHV0W25hbWU9XCJib29raW5nX2Zvcm1fc2hvd19zdW1tYXJ5XCJdJyApLnZhbCgpIClcclxuXHQpIHtcclxuXHRcdHJldHVybiBmYWxzZTtcclxuXHR9XHJcblxyXG5cdC8vIEZpeEluOiA4LjQuMC4yLlxyXG5cdHZhciBpc19lcnJvciA9IHdwYmNfY2hlY2tfZXJyb3JzX2luX2Jvb2tpbmdfZm9ybSggcmVzb3VyY2VfaWQgKTtcclxuXHRpZiAoIGlzX2Vycm9yICkge1xyXG5cdFx0cmV0dXJuIGZhbHNlO1xyXG5cdH1cclxuXHJcblx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdC8vIFNob3cgbWVzc2FnZSBpZiBubyBzZWxlY3RlZCBkYXlzIGluIENhbGVuZGFyKHMpLlxyXG5cdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHR2YXIgZGF0ZV9pbnB1dCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCAnZGF0ZV9ib29raW5nJyArIHJlc291cmNlX2lkICk7XHJcblx0dmFyIGRhdGVfdmFsdWUgPSAoIGRhdGVfaW5wdXQgKSA/IGRhdGVfaW5wdXQudmFsdWUgOiAnJztcclxuXHJcblx0aWYgKCAnJyA9PT0gZGF0ZV92YWx1ZSApIHtcclxuXHJcblx0XHR2YXIgYXJyX29mX3NlbGVjdGVkX2FkZGl0aW9uYWxfY2FsZW5kYXJzID0gd3BiY19nZXRfYXJyX29mX3NlbGVjdGVkX2FkZGl0aW9uYWxfY2FsZW5kYXJzKCByZXNvdXJjZV9pZCApOyAvLyBGaXhJbjogOC41LjIuMjYuXHJcblxyXG5cdFx0aWYgKCAhIGFycl9vZl9zZWxlY3RlZF9hZGRpdGlvbmFsX2NhbGVuZGFycyB8fCAoIGFycl9vZl9zZWxlY3RlZF9hZGRpdGlvbmFsX2NhbGVuZGFycy5sZW5ndGggPT09IDAgKSApIHtcclxuXHRcdFx0d3BiY19mcm9udF9lbmRfX3Nob3dfbWVzc2FnZV9fZXJyb3JfdW5kZXJfZWxlbWVudChcclxuXHRcdFx0XHQnI2Jvb2tpbmdfZm9ybV9kaXYnICsgcmVzb3VyY2VfaWQgKyAnIC5ia19jYWxlbmRhcl9mcmFtZScsXHJcblx0XHRcdFx0X3dwYmMuZ2V0X21lc3NhZ2UoICdtZXNzYWdlX2NoZWNrX25vX3NlbGVjdGVkX2RhdGVzJyApLFxyXG5cdFx0XHRcdDMwMDBcclxuXHRcdFx0KTtcclxuXHRcdFx0cmV0dXJuO1xyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdC8vIEZpeEluOiA2LjEuMS4zLiBUaW1lIHNlbGVjdGlvbiBhdmFpbGFiaWxpdHkgY2hlY2tzLlxyXG5cdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRpZiAoIHR5cGVvZiB3cGJjX2lzX3RoaXNfdGltZV9zZWxlY3Rpb25fbm90X2F2YWlsYWJsZSA9PT0gJ2Z1bmN0aW9uJyApIHtcclxuXHJcblx0XHRpZiAoICcnID09PSBkYXRlX3ZhbHVlICkgeyAvLyBQcmltYXJ5IGNhbGVuZGFyIG5vdCBzZWxlY3RlZC5cclxuXHJcblx0XHRcdHZhciBhZGRpdGlvbmFsX2NhbGVuZGFyc19lbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCAnYWRkaXRpb25hbF9jYWxlbmRhcnMnICsgcmVzb3VyY2VfaWQgKTtcclxuXHJcblx0XHRcdGlmICggYWRkaXRpb25hbF9jYWxlbmRhcnNfZWwgIT09IG51bGwgKSB7IC8vIENoZWNraW5nIGFkZGl0aW9uYWwgY2FsZW5kYXJzLlxyXG5cclxuXHRcdFx0XHR2YXIgaWRfYWRkaXRpb25hbF9zdHIgPSBhZGRpdGlvbmFsX2NhbGVuZGFyc19lbC52YWx1ZTtcclxuXHRcdFx0XHR2YXIgaWRfYWRkaXRpb25hbF9hcnIgPSBpZF9hZGRpdGlvbmFsX3N0ci5zcGxpdCggJywnICk7XHJcblx0XHRcdFx0dmFyIGlzX3RpbWVzX2RhdGVzX29rID0gZmFsc2U7XHJcblxyXG5cdFx0XHRcdGZvciAoIHZhciBpYSA9IDA7IGlhIDwgaWRfYWRkaXRpb25hbF9hcnIubGVuZ3RoOyBpYSsrICkge1xyXG5cclxuXHRcdFx0XHRcdHZhciBhZGRfaWQgPSBpZF9hZGRpdGlvbmFsX2FyclsgaWEgXTtcclxuXHJcblx0XHRcdFx0XHR2YXIgYWRkX2RhdGVfZWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCggJ2RhdGVfYm9va2luZycgKyBhZGRfaWQgKTtcclxuXHRcdFx0XHRcdHZhciBhZGRfZGF0ZV92YWwgPSAoIGFkZF9kYXRlX2VsICkgPyBhZGRfZGF0ZV9lbC52YWx1ZSA6ICcnO1xyXG5cclxuXHRcdFx0XHRcdGlmIChcclxuXHRcdFx0XHRcdFx0KCAnJyAhPT0gYWRkX2RhdGVfdmFsICkgJiZcclxuXHRcdFx0XHRcdFx0KCAhIHdwYmNfaXNfdGhpc190aW1lX3NlbGVjdGlvbl9ub3RfYXZhaWxhYmxlKCBhZGRfaWQsIHN1Ym1pdF9mb3JtLmVsZW1lbnRzICkgKVxyXG5cdFx0XHRcdFx0KSB7XHJcblx0XHRcdFx0XHRcdGlzX3RpbWVzX2RhdGVzX29rID0gdHJ1ZTtcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGlmICggISBpc190aW1lc19kYXRlc19vayApIHtcclxuXHRcdFx0XHRcdHJldHVybjtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHJcblx0XHR9IGVsc2UgeyAvLyBQcmltYXJ5IGNhbGVuZGFyIHNlbGVjdGVkLlxyXG5cclxuXHRcdFx0aWYgKCB3cGJjX2lzX3RoaXNfdGltZV9zZWxlY3Rpb25fbm90X2F2YWlsYWJsZSggcmVzb3VyY2VfaWQsIHN1Ym1pdF9mb3JtLmVsZW1lbnRzICkgKSB7XHJcblx0XHRcdFx0cmV0dXJuO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblx0fVxyXG5cclxuXHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0Ly8gU2VyaWFsaXplIGZvcm0gKGxlZ2FjeSBmb3JtYXQpLlxyXG5cdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHR2YXIgY291bnQgICAgPSBzdWJtaXRfZm9ybS5lbGVtZW50cy5sZW5ndGg7XHJcblx0dmFyIGZvcm1kYXRhID0gJyc7XHJcblx0dmFyIGlucF92YWx1ZTtcclxuXHR2YXIgaW5wX3RpdGxlX3ZhbHVlO1xyXG5cdHZhciBlbGVtZW50O1xyXG5cdHZhciBlbF90eXBlO1xyXG5cclxuXHQvLyBIZWxwZXI6IGxlZ2FjeSBlc2NhcGluZyBmb3IgdGhlIHNlcmlhbGl6ZWQgdmFsdWUuXHJcblx0ZnVuY3Rpb24gd3BiY19lc2NhcGVfc2VyaWFsaXplZF92YWx1ZSggdmFsICkge1xyXG5cclxuXHRcdHZhbCA9ICggdmFsID09IG51bGwgKSA/ICcnIDogU3RyaW5nKCB2YWwgKTtcclxuXHJcblx0XHQvLyBSZXBsYWNlIHJlZ2lzdGVyZWQgY2hhcmFjdGVycy5cclxuXHRcdHZhbCA9IHZhbC5yZXBsYWNlKCBuZXcgUmVnRXhwKCAnXFxcXF4nLCAnZycgKSwgJyYjOTQ7JyApO1xyXG5cdFx0dmFsID0gdmFsLnJlcGxhY2UoIG5ldyBSZWdFeHAoICd+JywgJ2cnICksICcmIzEyNjsnICk7XHJcblxyXG5cdFx0Ly8gUmVwbGFjZSBxdW90ZXMuXHJcblx0XHR2YWwgPSB2YWwucmVwbGFjZSggL1wiL2csICcmIzM0OycgKTtcclxuXHRcdHZhbCA9IHZhbC5yZXBsYWNlKCAvJy9nLCAnJiMzOTsnICk7XHJcblxyXG5cdFx0cmV0dXJuIHZhbDtcclxuXHR9XHJcblxyXG5cdC8vIEhlbHBlcjogZGV0ZXJtaW5lIFVJIHR5cGUgZm9yIHRpdGxlIGV4dHJhY3Rpb24gKGxlZ2FjeSBsb2dpYykuXHJcblx0ZnVuY3Rpb24gd3BiY19nZXRfaW5wdXRfZWxlbWVudF90eXBlKCBlbCApIHtcclxuXHJcblx0XHRpZiAoICEgZWwgfHwgISBlbC50YWdOYW1lICkge1xyXG5cdFx0XHRyZXR1cm4gJyc7XHJcblx0XHR9XHJcblxyXG5cdFx0dmFyIHRhZyA9IFN0cmluZyggZWwudGFnTmFtZSApLnRvTG93ZXJDYXNlKCk7XHJcblxyXG5cdFx0aWYgKCAnaW5wdXQnID09PSB0YWcgKSB7XHJcblx0XHRcdHJldHVybiAoIGVsLnR5cGUgKSA/IFN0cmluZyggZWwudHlwZSApLnRvTG93ZXJDYXNlKCkgOiAndGV4dCc7XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gTGVnYWN5IHVzZWQgXCJzZWxlY3RcIiBzdHJpbmcgaGVyZS5cclxuXHRcdGlmICggJ3NlbGVjdCcgPT09IHRhZyApIHtcclxuXHRcdFx0cmV0dXJuICdzZWxlY3QnO1xyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0YWc7XHJcblx0fVxyXG5cclxuXHRmb3IgKCB2YXIgaSA9IDA7IGkgPCBjb3VudDsgaSsrICkgeyAvLyBGaXhJbjogOS4xLjUuMS5cclxuXHJcblx0XHRlbGVtZW50ID0gc3VibWl0X2Zvcm0uZWxlbWVudHNbIGkgXTtcclxuXHJcblx0XHRpZiAoICEgZWxlbWVudCApIHtcclxuXHRcdFx0Y29udGludWU7XHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCBqUXVlcnkoIGVsZW1lbnQgKS5jbG9zZXN0KCAnLmJvb2tpbmdfZm9ybV9nYXJiYWdlJyApLmxlbmd0aCApIHtcclxuXHRcdFx0Y29udGludWU7IC8vIFNraXAgZWxlbWVudHMgZnJvbSBnYXJiYWdlLiBGaXhJbjogNy4xLjIuMTQuXHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKFxyXG5cdFx0XHQoIGVsZW1lbnQudHlwZSAhPT0gJ2J1dHRvbicgKSAmJlxyXG5cdFx0XHQoIGVsZW1lbnQudHlwZSAhPT0gJ2hpZGRlbicgKSAmJlxyXG5cdFx0XHQoIGVsZW1lbnQubmFtZSAhPT0gKCAnZGF0ZV9ib29raW5nJyArIHJlc291cmNlX2lkICkgKVxyXG5cdFx0XHQvLyAmJiAoIGpRdWVyeSggZWxlbWVudCApLmlzKCAnOnZpc2libGUnICkgKSAvL0ZpeEluOiA3LjIuMS4xMi4yXHJcblx0XHQpIHtcclxuXHJcblx0XHRcdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdFx0Ly8gR2V0IGVsZW1lbnQgdmFsdWUuXHJcblx0XHRcdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdFx0aWYgKCBlbGVtZW50LnR5cGUgPT09ICdjaGVja2JveCcgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggZWxlbWVudC52YWx1ZSA9PT0gJycgKSB7XHJcblx0XHRcdFx0XHRpbnBfdmFsdWUgPSBlbGVtZW50LmNoZWNrZWQ7XHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRcdGlucF92YWx1ZSA9ICggZWxlbWVudC5jaGVja2VkICkgPyBlbGVtZW50LnZhbHVlIDogJyc7XHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIGlmICggZWxlbWVudC50eXBlID09PSAncmFkaW8nICkge1xyXG5cclxuXHRcdFx0XHRpZiAoIGVsZW1lbnQuY2hlY2tlZCApIHtcclxuXHRcdFx0XHRcdGlucF92YWx1ZSA9IGVsZW1lbnQudmFsdWU7XHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0XHQvLyBSZXF1aXJlZCByYWRpbzogc2hvdyB3YXJuaW5nIGlmIG5vbmUgY2hlY2tlZC5cclxuXHRcdFx0XHRcdC8vIEZpeEluOiA3LjAuMS42Mi5cclxuXHRcdFx0XHRcdGlmIChcclxuXHRcdFx0XHRcdFx0KCBlbGVtZW50LmNsYXNzTmFtZS5pbmRleE9mKCAnd3BkZXYtdmFsaWRhdGVzLWFzLXJlcXVpcmVkJyApICE9PSAtMSApICYmXHJcblx0XHRcdFx0XHRcdCggalF1ZXJ5KCBlbGVtZW50ICkuaXMoICc6dmlzaWJsZScgKSApICYmIC8vIEZpeEluOiA3LjIuMS4xMi4yLlxyXG5cdFx0XHRcdFx0XHQoICEgalF1ZXJ5KCAnOnJhZGlvW25hbWU9XCInICsgZWxlbWVudC5uYW1lICsgJ1wiXScsIHN1Ym1pdF9mb3JtICkuaXMoICc6Y2hlY2tlZCcgKSApXHJcblx0XHRcdFx0XHQpIHtcclxuXHRcdFx0XHRcdFx0d3BiY19mcm9udF9lbmRfX3Nob3dfbWVzc2FnZV9fd2FybmluZyggZWxlbWVudCwgX3dwYmMuZ2V0X21lc3NhZ2UoICdtZXNzYWdlX2NoZWNrX3JlcXVpcmVkX2Zvcl9yYWRpb19ib3gnICkgKTsgLy8gRml4SW46IDguNS4xLjMuXHJcblx0XHRcdFx0XHRcdHJldHVybjtcclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHQvLyBTa2lwIHN0b3JpbmcgZW1wdHkgcmFkaW8gb3B0aW9ucy5cclxuXHRcdFx0XHRcdGNvbnRpbnVlO1xyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH0gZWxzZSB7XHJcblx0XHRcdFx0aW5wX3ZhbHVlID0gZWxlbWVudC52YWx1ZTtcclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aW5wX3RpdGxlX3ZhbHVlID0gJyc7XHJcblxyXG5cdFx0XHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHRcdC8vIEdldCBodW1hbi1mcmllbmRseSB0aXRsZSB2YWx1ZSAobGVnYWN5IGJlaGF2aW9yKS5cclxuXHRcdFx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdFx0XHR2YXIgaW5wdXRfZWxlbWVudF90eXBlID0gd3BiY19nZXRfaW5wdXRfZWxlbWVudF90eXBlKCBlbGVtZW50ICk7XHJcblxyXG5cdFx0XHRzd2l0Y2ggKCBpbnB1dF9lbGVtZW50X3R5cGUgKSB7XHJcblxyXG5cdFx0XHRcdGNhc2UgJ3RleHQnOlxyXG5cdFx0XHRcdGNhc2UgJ2VtYWlsJzpcclxuXHRcdFx0XHRcdGlucF90aXRsZV92YWx1ZSA9IGlucF92YWx1ZTtcclxuXHRcdFx0XHRcdGJyZWFrO1xyXG5cclxuXHRcdFx0XHRjYXNlICdzZWxlY3QnOlxyXG5cdFx0XHRcdFx0aW5wX3RpdGxlX3ZhbHVlID0galF1ZXJ5KCBlbGVtZW50ICkuZmluZCggJ29wdGlvbjpzZWxlY3RlZCcgKS50ZXh0KCk7XHJcblx0XHRcdFx0XHRicmVhaztcclxuXHJcblx0XHRcdFx0Y2FzZSAncmFkaW8nOlxyXG5cdFx0XHRcdGNhc2UgJ2NoZWNrYm94JzpcclxuXHRcdFx0XHRcdGlmICggalF1ZXJ5KCBlbGVtZW50ICkuaXMoICc6Y2hlY2tlZCcgKSApIHtcclxuXHRcdFx0XHRcdFx0dmFyIGxhYmVsX2VsZW1lbnQgPSBqUXVlcnkoIGVsZW1lbnQgKS5wYXJlbnRzKCAnLndwZGV2LWxpc3QtaXRlbScgKS5maW5kKCAnLndwZGV2LWxpc3QtaXRlbS1sYWJlbCcgKTtcclxuXHRcdFx0XHRcdFx0aWYgKCBsYWJlbF9lbGVtZW50Lmxlbmd0aCApIHtcclxuXHRcdFx0XHRcdFx0XHRpbnBfdGl0bGVfdmFsdWUgPSBsYWJlbF9lbGVtZW50Lmh0bWwoKTtcclxuXHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdGRlZmF1bHQ6XHJcblx0XHRcdFx0XHRpbnBfdGl0bGVfdmFsdWUgPSBpbnBfdmFsdWU7XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdFx0Ly8gTXVsdGlwbGUgc2VsZWN0IHZhbHVlIGV4dHJhY3Rpb24uXHJcblx0XHRcdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdFx0aWYgKCAoIGVsZW1lbnQudHlwZSA9PT0gJ3NlbGVjdGJveC1tdWx0aXBsZScgKSB8fCAoIGVsZW1lbnQudHlwZSA9PT0gJ3NlbGVjdC1tdWx0aXBsZScgKSApIHtcclxuXHRcdFx0XHRpbnBfdmFsdWUgPSBqUXVlcnkoICdbbmFtZT1cIicgKyBlbGVtZW50Lm5hbWUgKyAnXCJdJyApLnZhbCgpO1xyXG5cdFx0XHRcdGlmICggKCBpbnBfdmFsdWUgPT09IG51bGwgKSB8fCAoIFN0cmluZyggaW5wX3ZhbHVlICkgPT09ICcnICkgKSB7XHJcblx0XHRcdFx0XHRpbnBfdmFsdWUgPSAnJztcclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdFx0Ly8gTWFrZSB2YWxpZGF0aW9uIG9ubHkgZm9yIHZpc2libGUgZWxlbWVudHMuXHJcblx0XHRcdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdFx0aWYgKCBqUXVlcnkoIGVsZW1lbnQgKS5pcyggJzp2aXNpYmxlJyApICkgeyAvLyBGaXhJbjogNy4yLjEuMTIuMi5cclxuXHJcblx0XHRcdFx0Ly8gUmVjaGVjayBtYXggYXZhaWxhYmxlIHZpc2l0b3JzIHNlbGVjdGlvbi5cclxuXHRcdFx0XHRpZiAoIHR5cGVvZiB3cGJjX19pc19sZXNzX3RoYW5fcmVxdWlyZWRfX29mX21heF9hdmFpbGFibGVfc2xvdHNfX2JsID09PSAnZnVuY3Rpb24nICkge1xyXG5cdFx0XHRcdFx0aWYgKCB3cGJjX19pc19sZXNzX3RoYW5fcmVxdWlyZWRfX29mX21heF9hdmFpbGFibGVfc2xvdHNfX2JsKCByZXNvdXJjZV9pZCwgZWxlbWVudCApICkge1xyXG5cdFx0XHRcdFx0XHRyZXR1cm47XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHQvLyBSZXF1aXJlZCBmaWVsZHMuXHJcblx0XHRcdFx0aWYgKCBlbGVtZW50LmNsYXNzTmFtZS5pbmRleE9mKCAnd3BkZXYtdmFsaWRhdGVzLWFzLXJlcXVpcmVkJyApICE9PSAtMSApIHtcclxuXHJcblx0XHRcdFx0XHRpZiAoICggZWxlbWVudC50eXBlID09PSAnY2hlY2tib3gnICkgJiYgKCBlbGVtZW50LmNoZWNrZWQgPT09IGZhbHNlICkgKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRpZiAoICEgalF1ZXJ5KCAnOmNoZWNrYm94W25hbWU9XCInICsgZWxlbWVudC5uYW1lICsgJ1wiXScsIHN1Ym1pdF9mb3JtICkuaXMoICc6Y2hlY2tlZCcgKSApIHtcclxuXHRcdFx0XHRcdFx0XHR3cGJjX2Zyb250X2VuZF9fc2hvd19tZXNzYWdlX193YXJuaW5nKCBlbGVtZW50LCBfd3BiYy5nZXRfbWVzc2FnZSggJ21lc3NhZ2VfY2hlY2tfcmVxdWlyZWRfZm9yX2NoZWNrX2JveCcgKSApOyAvLyBGaXhJbjogOC41LjEuMy5cclxuXHRcdFx0XHRcdFx0XHRyZXR1cm47XHJcblx0XHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRpZiAoIGVsZW1lbnQudHlwZSA9PT0gJ3JhZGlvJyApIHtcclxuXHJcblx0XHRcdFx0XHRcdGlmICggISBqUXVlcnkoICc6cmFkaW9bbmFtZT1cIicgKyBlbGVtZW50Lm5hbWUgKyAnXCJdJywgc3VibWl0X2Zvcm0gKS5pcyggJzpjaGVja2VkJyApICkge1xyXG5cdFx0XHRcdFx0XHRcdHdwYmNfZnJvbnRfZW5kX19zaG93X21lc3NhZ2VfX3dhcm5pbmcoIGVsZW1lbnQsIF93cGJjLmdldF9tZXNzYWdlKCAnbWVzc2FnZV9jaGVja19yZXF1aXJlZF9mb3JfcmFkaW9fYm94JyApICk7IC8vIEZpeEluOiA4LjUuMS4zLlxyXG5cdFx0XHRcdFx0XHRcdHJldHVybjtcclxuXHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdGlmICggKCBlbGVtZW50LnR5cGUgIT09ICdjaGVja2JveCcgKSAmJiAoIGVsZW1lbnQudHlwZSAhPT0gJ3JhZGlvJyApICYmICggJycgPT09IHdwYmNfdHJpbSggaW5wX3ZhbHVlICkgKSApIHtcclxuXHRcdFx0XHRcdFx0d3BiY19mcm9udF9lbmRfX3Nob3dfbWVzc2FnZV9fd2FybmluZyggZWxlbWVudCwgX3dwYmMuZ2V0X21lc3NhZ2UoICdtZXNzYWdlX2NoZWNrX3JlcXVpcmVkJyApICk7IC8vIEZpeEluOiA4LjUuMS4zLlxyXG5cdFx0XHRcdFx0XHRyZXR1cm47XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHQvLyBFbWFpbCBmb3JtYXQgdmFsaWRhdGlvbi5cclxuXHRcdFx0XHRpZiAoIGVsZW1lbnQuY2xhc3NOYW1lLmluZGV4T2YoICd3cGRldi12YWxpZGF0ZXMtYXMtZW1haWwnICkgIT09IC0xICkge1xyXG5cclxuXHRcdFx0XHRcdGlucF92YWx1ZSA9IFN0cmluZyggaW5wX3ZhbHVlICkucmVwbGFjZSggL15cXHMrfFxccyskL2dtLCAnJyApOyAvLyBUcmltIHdoaXRlIHNwYWNlLiBGaXhJbjogNS40LjUuXHJcblx0XHRcdFx0XHR2YXIgcmVnX2VtYWlsID0gL14oW0EtWmEtejAtOV9cXC1cXC5cXCtdKStcXEAoW0EtWmEtejAtOV9cXC1cXC5dKStcXC4oW0EtWmEtel17Mix9KSQvO1xyXG5cclxuXHRcdFx0XHRcdGlmICggaW5wX3ZhbHVlICE9PSAnJyApIHtcclxuXHRcdFx0XHRcdFx0aWYgKCByZWdfZW1haWwudGVzdCggaW5wX3ZhbHVlICkgPT09IGZhbHNlICkge1xyXG5cdFx0XHRcdFx0XHRcdHdwYmNfZnJvbnRfZW5kX19zaG93X21lc3NhZ2VfX3dhcm5pbmcoIGVsZW1lbnQsIF93cGJjLmdldF9tZXNzYWdlKCAnbWVzc2FnZV9jaGVja19lbWFpbCcgKSApOyAvLyBGaXhJbjogOC41LjEuMy5cclxuXHRcdFx0XHRcdFx0XHRyZXR1cm47XHJcblx0XHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdC8vIFNhbWUgZW1haWwgZmllbGQgdmFsaWRhdGlvbiAodmVyaWZpY2F0aW9uIGZpZWxkKS5cclxuXHRcdFx0XHRpZiAoICggZWxlbWVudC5jbGFzc05hbWUuaW5kZXhPZiggJ3dwZGV2LXZhbGlkYXRlcy1hcy1lbWFpbCcgKSAhPT0gLTEgKSAmJiAoIGVsZW1lbnQuY2xhc3NOYW1lLmluZGV4T2YoICdzYW1lX2FzXycgKSAhPT0gLTEgKSApIHtcclxuXHJcblx0XHRcdFx0XHR2YXIgcHJpbWFyeV9lbWFpbF9uYW1lID0gZWxlbWVudC5jbGFzc05hbWUubWF0Y2goIC9zYW1lX2FzXyhbXlxcc10pKy9naSApO1xyXG5cclxuXHRcdFx0XHRcdGlmICggcHJpbWFyeV9lbWFpbF9uYW1lICE9PSBudWxsICkge1xyXG5cclxuXHRcdFx0XHRcdFx0cHJpbWFyeV9lbWFpbF9uYW1lID0gcHJpbWFyeV9lbWFpbF9uYW1lWyAwIF0uc3Vic3RyKCA4ICk7XHJcblxyXG5cdFx0XHRcdFx0XHRpZiAoIGpRdWVyeSggJ1tuYW1lPVwiJyArIHByaW1hcnlfZW1haWxfbmFtZSArIHJlc291cmNlX2lkICsgJ1wiXScgKS5sZW5ndGggPiAwICkge1xyXG5cclxuXHRcdFx0XHRcdFx0XHRpZiAoIGpRdWVyeSggJ1tuYW1lPVwiJyArIHByaW1hcnlfZW1haWxfbmFtZSArIHJlc291cmNlX2lkICsgJ1wiXScgKS52YWwoKSAhPT0gaW5wX3ZhbHVlICkge1xyXG5cdFx0XHRcdFx0XHRcdFx0d3BiY19mcm9udF9lbmRfX3Nob3dfbWVzc2FnZV9fd2FybmluZyggZWxlbWVudCwgX3dwYmMuZ2V0X21lc3NhZ2UoICdtZXNzYWdlX2NoZWNrX3NhbWVfZW1haWwnICkgKTsgLy8gRml4SW46IDguNS4xLjMuXHJcblx0XHRcdFx0XHRcdFx0XHRyZXR1cm47XHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0Ly8gU2tpcCBvbmUgbG9vcCBmb3IgdGhlIGVtYWlsIHZlcmlmaWNhdGlvbiBmaWVsZC5cclxuXHRcdFx0XHRcdGNvbnRpbnVlOyAvLyBGaXhJbjogOC4xLjIuMTUuXHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHRcdC8vIEdldCBGb3JtIERhdGEgKGxlZ2FjeSBmb3JtYXQpLlxyXG5cdFx0XHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHRcdGlmICggZWxlbWVudC5uYW1lICE9PSAoICdjYXB0Y2hhX2lucHV0JyArIHJlc291cmNlX2lkICkgKSB7XHJcblxyXG5cdFx0XHRcdGlmICggZm9ybWRhdGEgIT09ICcnICkge1xyXG5cdFx0XHRcdFx0Zm9ybWRhdGEgKz0gJ34nO1xyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0ZWxfdHlwZSA9IGVsZW1lbnQudHlwZTtcclxuXHJcblx0XHRcdFx0aWYgKCBlbGVtZW50LmNsYXNzTmFtZS5pbmRleE9mKCAnd3BkZXYtdmFsaWRhdGVzLWFzLWVtYWlsJyApICE9PSAtMSApIHtcclxuXHRcdFx0XHRcdGVsX3R5cGUgPSAnZW1haWwnO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0XHRpZiAoIGVsZW1lbnQuY2xhc3NOYW1lLmluZGV4T2YoICd3cGRldi12YWxpZGF0ZXMtYXMtY291cG9uJyApICE9PSAtMSApIHtcclxuXHRcdFx0XHRcdGVsX3R5cGUgPSAnY291cG9uJztcclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGlucF92YWx1ZSA9IHdwYmNfZXNjYXBlX3NlcmlhbGl6ZWRfdmFsdWUoIGlucF92YWx1ZSApO1xyXG5cclxuXHRcdFx0XHRpZiAoIGVsX3R5cGUgPT09ICdzZWxlY3Qtb25lJyApIHtcclxuXHRcdFx0XHRcdGVsX3R5cGUgPSAnc2VsZWN0Ym94LW9uZSc7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHRcdGlmICggZWxfdHlwZSA9PT0gJ3NlbGVjdC1tdWx0aXBsZScgKSB7XHJcblx0XHRcdFx0XHRlbF90eXBlID0gJ3NlbGVjdGJveC1tdWx0aXBsZSc7XHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRmb3JtZGF0YSArPSBlbF90eXBlICsgJ14nICsgZWxlbWVudC5uYW1lICsgJ14nICsgaW5wX3ZhbHVlO1xyXG5cclxuXHRcdFx0XHQvLyBBZGQgdGl0bGUvbGFiZWwgdmFsdWUgKGxlZ2FjeSkuXHJcblx0XHRcdFx0dmFyIGNsZWFuX2ZpZWxkX25hbWUgPSBTdHJpbmcoIGVsZW1lbnQubmFtZSApO1xyXG5cclxuXHRcdFx0XHQvLyBCVUdGSVg6IHJlcGxhY2VBbGwoUmVnRXhwKSBpcyBub3Qgc3VwcG9ydGVkIGluIG9sZGVyIGJyb3dzZXJzLlxyXG5cdFx0XHRcdC8vIEtlZXAgbGVnYWN5IGludGVudDogcmVtb3ZlIFtdIHN1ZmZpeCBvY2N1cnJlbmNlcy5cclxuXHRcdFx0XHRjbGVhbl9maWVsZF9uYW1lID0gY2xlYW5fZmllbGRfbmFtZS5yZXBsYWNlKCAvXFxbXFxdL2dpLCAnJyApO1xyXG5cclxuXHRcdFx0XHR2YXIgcmVzb3VyY2VfaWRfc3RyID0gU3RyaW5nKCByZXNvdXJjZV9pZCApO1xyXG5cclxuXHRcdFx0XHQvLyBMZWdhY3kgYXNzdW1lZCBzdWZmaXggZW5kcyB3aXRoIHJlc291cmNlX2lkLCBtYWtlIGl0IHNhZmUuXHJcblx0XHRcdFx0aWYgKFxyXG5cdFx0XHRcdFx0KCBjbGVhbl9maWVsZF9uYW1lLmxlbmd0aCA+PSByZXNvdXJjZV9pZF9zdHIubGVuZ3RoICkgJiZcclxuXHRcdFx0XHRcdCggY2xlYW5fZmllbGRfbmFtZS5zdWJzdHIoIGNsZWFuX2ZpZWxkX25hbWUubGVuZ3RoIC0gcmVzb3VyY2VfaWRfc3RyLmxlbmd0aCApID09PSByZXNvdXJjZV9pZF9zdHIgKVxyXG5cdFx0XHRcdCkge1xyXG5cdFx0XHRcdFx0Y2xlYW5fZmllbGRfbmFtZSA9IGNsZWFuX2ZpZWxkX25hbWUuc3Vic3RyKCAwLCBjbGVhbl9maWVsZF9uYW1lLmxlbmd0aCAtIHJlc291cmNlX2lkX3N0ci5sZW5ndGggKTtcclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdGZvcm1kYXRhICs9ICd+JyArIGVsX3R5cGUgKyAnXicgKyBjbGVhbl9maWVsZF9uYW1lICsgJ192YWwnICsgcmVzb3VyY2VfaWQgKyAnXicgKyBpbnBfdGl0bGVfdmFsdWU7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHR9XHJcblxyXG5cdC8vIFRPRE86IGhlcmUgd2FzIGZ1bmN0aW9uIGZvciAnQ2hlY2sgaWYgdmlzaXRvciBmaW5pc2ggZGF0ZXMgc2VsZWN0aW9uLlxyXG5cclxuXHQvLyBDYXB0Y2hhIHZlcmlmeS5cclxuXHR2YXIgY2FwdGNoYSA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCAnd3BkZXZfY2FwdGNoYV9jaGFsbGVuZ2VfJyArIHJlc291cmNlX2lkICk7XHJcblxyXG5cdGlmICggY2FwdGNoYSAhPT0gbnVsbCApIHtcclxuXHRcdHdwYmNfZm9ybV9zdWJtaXRfc2VuZCggcmVzb3VyY2VfaWQsIGZvcm1kYXRhLCBjYXB0Y2hhLnZhbHVlLCBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCggJ2NhcHRjaGFfaW5wdXQnICsgcmVzb3VyY2VfaWQgKS52YWx1ZSwgd3BkZXZfYWN0aXZlX2xvY2FsZSApO1xyXG5cdH0gZWxzZSB7XHJcblx0XHR3cGJjX2Zvcm1fc3VibWl0X3NlbmQoIHJlc291cmNlX2lkLCBmb3JtZGF0YSwgJycsICcnLCB3cGRldl9hY3RpdmVfbG9jYWxlICk7XHJcblx0fVxyXG5cclxuXHRyZXR1cm47XHJcbn1cclxuXHJcblxyXG4vKipcclxuICogR2F0aGVyaW5nIHBhcmFtcyBmb3Igc2VuZGluZyBBamF4IHJlcXVlc3QgYW5kIHRoZW4gc2VuZCBpdCAobGVnYWN5OiBmb3JtX3N1Ym1pdF9zZW5kKS5cclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ8c3RyaW5nfSByZXNvdXJjZV9pZFxyXG4gKiBAcGFyYW0ge3N0cmluZ30gICAgICAgIGZvcm1kYXRhXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSAgICAgICAgY2FwdGNoYV9jaGFsYW5nZVxyXG4gKiBAcGFyYW0ge3N0cmluZ30gICAgICAgIHVzZXJfY2FwdGNoYVxyXG4gKiBAcGFyYW0ge3N0cmluZ30gICAgICAgIHdwZGV2X2FjdGl2ZV9sb2NhbGVcclxuICpcclxuICogQHJldHVybiB7dW5kZWZpbmVkfSBMZWdhY3kgYmVoYXZpb3IuXHJcbiAqL1xyXG5mdW5jdGlvbiB3cGJjX2Zvcm1fc3VibWl0X3NlbmQoIHJlc291cmNlX2lkLCBmb3JtZGF0YSwgY2FwdGNoYV9jaGFsYW5nZSwgdXNlcl9jYXB0Y2hhLCB3cGRldl9hY3RpdmVfbG9jYWxlICkge1xyXG5cclxuXHRyZXNvdXJjZV9pZCA9IHBhcnNlSW50KCByZXNvdXJjZV9pZCwgMTAgKTtcclxuXHJcblx0dmFyIG15X2Jvb2tpbmdfZm9ybSA9ICcnO1xyXG5cdHZhciBib29raW5nX2Zvcm1fdHlwZV9lbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCAnYm9va2luZ19mb3JtX3R5cGUnICsgcmVzb3VyY2VfaWQgKTtcclxuXHRpZiAoIGJvb2tpbmdfZm9ybV90eXBlX2VsICE9PSBudWxsICkge1xyXG5cdFx0bXlfYm9va2luZ19mb3JtID0gYm9va2luZ19mb3JtX3R5cGVfZWwudmFsdWU7XHJcblx0fVxyXG5cclxuXHR2YXIgbXlfYm9va2luZ19oYXNoID0gJyc7XHJcblx0aWYgKCBfd3BiYy5nZXRfb3RoZXJfcGFyYW0oICd0aGlzX3BhZ2VfYm9va2luZ19oYXNoJyApICE9PSAnJyApIHtcclxuXHRcdG15X2Jvb2tpbmdfaGFzaCA9IF93cGJjLmdldF9vdGhlcl9wYXJhbSggJ3RoaXNfcGFnZV9ib29raW5nX2hhc2gnICk7XHJcblx0fVxyXG5cclxuXHR2YXIgaXNfc2VuZF9lbWVpbHMgPSAxO1xyXG5cdHZhciAkaXNfc2VuZF9lbWFpbF90b2dnbGUgPSBqUXVlcnkoICcjaXNfc2VuZF9lbWFpbF9mb3JfcGVuZGluZycgKTtcclxuXHR2YXIgJG1vZGFsX3NlbmRfZW1haWxfdG9nZ2xlID0galF1ZXJ5KCAnI2Jvb2tpbmdfZm9ybScgKyByZXNvdXJjZV9pZCApLmNsb3Nlc3QoICcud3BiY19tb2RhbF9fYWRkX2Jvb2tpbmdfX3NlY3Rpb24nICkuZmluZCggJ1tkYXRhLXdwYmMtYWRkLWJvb2tpbmctc2VuZC1lbWFpbHNdJyApLmZpcnN0KCk7XHJcblx0aWYgKCAkbW9kYWxfc2VuZF9lbWFpbF90b2dnbGUubGVuZ3RoICkge1xyXG5cdFx0JGlzX3NlbmRfZW1haWxfdG9nZ2xlID0gJG1vZGFsX3NlbmRfZW1haWxfdG9nZ2xlO1xyXG5cdH1cclxuXHRpZiAoICRpc19zZW5kX2VtYWlsX3RvZ2dsZS5sZW5ndGggKSB7IC8vIEZpeEluOiA4LjcuOS41LlxyXG5cclxuXHRcdGlzX3NlbmRfZW1laWxzID0gJGlzX3NlbmRfZW1haWxfdG9nZ2xlLmlzKCAnOmNoZWNrZWQnICk7XHJcblxyXG5cdFx0aWYgKCBmYWxzZSA9PT0gaXNfc2VuZF9lbWVpbHMgKSB7XHJcblx0XHRcdGlzX3NlbmRfZW1laWxzID0gMDtcclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdGlzX3NlbmRfZW1laWxzID0gMTtcclxuXHRcdH1cclxuXHR9XHJcblxyXG5cdHZhciBkYXRlX2VsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoICdkYXRlX2Jvb2tpbmcnICsgcmVzb3VyY2VfaWQgKTtcclxuXHR2YXIgZGF0ZV92YWx1ZSA9ICggZGF0ZV9lbCApID8gZGF0ZV9lbC52YWx1ZSA6ICcnO1xyXG5cclxuXHRpZiAoICcnICE9PSBkYXRlX3ZhbHVlICkgeyAvLyBGaXhJbjogNi4xLjEuMy5cclxuXHRcdHdwYmNfc2VuZF9hamF4X3N1Ym1pdCggcmVzb3VyY2VfaWQsIGZvcm1kYXRhLCBjYXB0Y2hhX2NoYWxhbmdlLCB1c2VyX2NhcHRjaGEsIGlzX3NlbmRfZW1laWxzLCBteV9ib29raW5nX2hhc2gsIG15X2Jvb2tpbmdfZm9ybSwgd3BkZXZfYWN0aXZlX2xvY2FsZSApO1xyXG5cdH0gZWxzZSB7XHJcblx0XHRqUXVlcnkoICcjYm9va2luZ19mb3JtX2RpdicgKyByZXNvdXJjZV9pZCApLmhpZGUoKTtcclxuXHRcdGpRdWVyeSggJyNzdWJtaXRpbmcnICsgcmVzb3VyY2VfaWQgKS5oaWRlKCk7XHJcblx0fVxyXG5cclxuXHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0Ly8gQWRkaXRpb25hbCBjYWxlbmRhcnMgc3VibWl0LlxyXG5cdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHR2YXIgYWRkaXRpb25hbF9jYWxlbmRhcnNfZWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCggJ2FkZGl0aW9uYWxfY2FsZW5kYXJzJyArIHJlc291cmNlX2lkICk7XHJcblx0aWYgKCBhZGRpdGlvbmFsX2NhbGVuZGFyc19lbCA9PT0gbnVsbCApIHtcclxuXHRcdHJldHVybjtcclxuXHR9XHJcblxyXG5cdHZhciBpZF9hZGRpdGlvbmFsX3N0ciA9IGFkZGl0aW9uYWxfY2FsZW5kYXJzX2VsLnZhbHVlO1xyXG5cdHZhciBpZF9hZGRpdGlvbmFsX2FyciA9IGlkX2FkZGl0aW9uYWxfc3RyLnNwbGl0KCAnLCcgKTtcclxuXHJcblx0Ly8gRml4SW46IDEwLjkuNC4xLlxyXG5cdGZvciAoIHZhciBpYSA9IDA7IGlhIDwgaWRfYWRkaXRpb25hbF9hcnIubGVuZ3RoOyBpYSsrICkge1xyXG5cdFx0aWRfYWRkaXRpb25hbF9hcnJbIGlhIF0gPSBwYXJzZUludCggaWRfYWRkaXRpb25hbF9hcnJbIGlhIF0sIDEwICk7XHJcblx0fVxyXG5cclxuXHRpZiAoICEgalF1ZXJ5KCAnI2Jvb2tpbmdfZm9ybV9kaXYnICsgcmVzb3VyY2VfaWQgKS5pcyggJzp2aXNpYmxlJyApICkge1xyXG5cdFx0d3BiY19ib29raW5nX2Zvcm1fX3NwaW5fbG9hZGVyX19zaG93KCByZXNvdXJjZV9pZCApOyAvLyBTaG93IFNwaW5uZXJcclxuXHR9XHJcblxyXG5cdC8vIEhlbHBlcjogcmV3cml0ZSBmaWVsZCBuYW1lIHN1ZmZpeCBmcm9tIHJlc291cmNlX2lkIC0+IGlkX2FkZGl0aW9uYWwuXHJcblx0ZnVuY3Rpb24gd3BiY19yZXdyaXRlX2ZpZWxkX25hbWVfc3VmZml4KCBmaWVsZF9uYW1lLCBvbGRfaWQsIG5ld19pZCApIHtcclxuXHJcblx0XHRmaWVsZF9uYW1lID0gU3RyaW5nKCBmaWVsZF9uYW1lICk7XHJcblxyXG5cdFx0dmFyIG9sZF9pZF9zdHIgPSBTdHJpbmcoIG9sZF9pZCApO1xyXG5cdFx0dmFyIG5ld19pZF9zdHIgPSBTdHJpbmcoIG5ld19pZCApO1xyXG5cclxuXHRcdC8vIEhhbmRsZSBmaWVsZHMgd2l0aCBbXS5cclxuXHRcdGlmIChcclxuXHRcdFx0KCBmaWVsZF9uYW1lLmxlbmd0aCA+PSAoIG9sZF9pZF9zdHIubGVuZ3RoICsgMiApICkgJiZcclxuXHRcdFx0KCBmaWVsZF9uYW1lLnN1YnN0ciggZmllbGRfbmFtZS5sZW5ndGggLSAoIG9sZF9pZF9zdHIubGVuZ3RoICsgMiApICkgPT09ICggb2xkX2lkX3N0ciArICdbXScgKSApXHJcblx0XHQpIHtcclxuXHRcdFx0cmV0dXJuIGZpZWxkX25hbWUuc3Vic3RyKCAwLCBmaWVsZF9uYW1lLmxlbmd0aCAtICggb2xkX2lkX3N0ci5sZW5ndGggKyAyICkgKSArIG5ld19pZF9zdHIgKyAnW10nO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8vIEhhbmRsZSBmaWVsZHMgd2l0aG91dCBbXS5cclxuXHRcdGlmIChcclxuXHRcdFx0KCBmaWVsZF9uYW1lLmxlbmd0aCA+PSBvbGRfaWRfc3RyLmxlbmd0aCApICYmXHJcblx0XHRcdCggZmllbGRfbmFtZS5zdWJzdHIoIGZpZWxkX25hbWUubGVuZ3RoIC0gb2xkX2lkX3N0ci5sZW5ndGggKSA9PT0gb2xkX2lkX3N0ciApXHJcblx0XHQpIHtcclxuXHRcdFx0cmV0dXJuIGZpZWxkX25hbWUuc3Vic3RyKCAwLCBmaWVsZF9uYW1lLmxlbmd0aCAtIG9sZF9pZF9zdHIubGVuZ3RoICkgKyBuZXdfaWRfc3RyO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8vIEZhbGxiYWNrOiByZXR1cm4gdW5jaGFuZ2VkIChzYWZlciB0aGFuIGJyZWFraW5nIG5hbWUpLlxyXG5cdFx0cmV0dXJuIGZpZWxkX25hbWU7XHJcblx0fVxyXG5cclxuXHRmb3IgKCBpYSA9IDA7IGlhIDwgaWRfYWRkaXRpb25hbF9hcnIubGVuZ3RoOyBpYSsrICkge1xyXG5cclxuXHRcdHZhciBpZF9hZGRpdGlvbmFsID0gaWRfYWRkaXRpb25hbF9hcnJbIGlhIF07XHJcblxyXG5cdFx0Ly8gRml4SW46IDEwLjkuNC4xLlxyXG5cdFx0aWYgKCBpZF9hZGRpdGlvbmFsIDw9IDAgKSB7XHJcblx0XHRcdGNvbnRpbnVlO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8vIFJlYnVpbGQgZm9ybWRhdGEgZm9yIGVhY2ggYWRkaXRpb25hbCBjYWxlbmRhciAobGVnYWN5IGJlaGF2aW9yKS5cclxuXHRcdHZhciBmb3JtZGF0YV9hZGRpdGlvbmFsX2FyciA9IFN0cmluZyggZm9ybWRhdGEgKS5zcGxpdCggJ34nICk7XHJcblx0XHR2YXIgZm9ybWRhdGFfYWRkaXRpb25hbCA9ICcnO1xyXG5cclxuXHRcdGZvciAoIHZhciBqID0gMDsgaiA8IGZvcm1kYXRhX2FkZGl0aW9uYWxfYXJyLmxlbmd0aDsgaisrICkge1xyXG5cclxuXHRcdFx0dmFyIG15X2Zvcm1fZmllbGQgPSBmb3JtZGF0YV9hZGRpdGlvbmFsX2FyclsgaiBdLnNwbGl0KCAnXicgKTtcclxuXHJcblx0XHRcdGlmICggZm9ybWRhdGFfYWRkaXRpb25hbCAhPT0gJycgKSB7XHJcblx0XHRcdFx0Zm9ybWRhdGFfYWRkaXRpb25hbCArPSAnfic7XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIFNhZmV0eTogZW5zdXJlIHdlIGhhdmUgYXQgbGVhc3QgdHlwZSBeIG5hbWUgXiB2YWx1ZS5cclxuXHRcdFx0aWYgKCBteV9mb3JtX2ZpZWxkLmxlbmd0aCA8IDMgKSB7XHJcblx0XHRcdFx0Zm9ybWRhdGFfYWRkaXRpb25hbCArPSBmb3JtZGF0YV9hZGRpdGlvbmFsX2FyclsgaiBdO1xyXG5cdFx0XHRcdGNvbnRpbnVlO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRteV9mb3JtX2ZpZWxkWyAxIF0gPSB3cGJjX3Jld3JpdGVfZmllbGRfbmFtZV9zdWZmaXgoIG15X2Zvcm1fZmllbGRbIDEgXSwgcmVzb3VyY2VfaWQsIGlkX2FkZGl0aW9uYWwgKTtcclxuXHRcdFx0Zm9ybWRhdGFfYWRkaXRpb25hbCArPSBteV9mb3JtX2ZpZWxkWyAwIF0gKyAnXicgKyBteV9mb3JtX2ZpZWxkWyAxIF0gKyAnXicgKyBteV9mb3JtX2ZpZWxkWyAyIF07XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gSWYgcGF5bWVudCBmb3JtIGZvciBtYWluIGJvb2tpbmcgcmVzb3VyY2UgaXMgc2hvd2luZywgYXBwZW5kIGZvciBhZGRpdGlvbmFsIGNhbGVuZGFycy5cclxuXHRcdGlmICggalF1ZXJ5KCAnI2dhdGV3YXlfcGF5bWVudF9mb3JtcycgKyByZXNvdXJjZV9pZCApLmxlbmd0aCA+IDAgKSB7XHJcblx0XHRcdGpRdWVyeSggJyNnYXRld2F5X3BheW1lbnRfZm9ybXMnICsgcmVzb3VyY2VfaWQgKS5hZnRlciggJzxkaXYgaWQ9XCJnYXRld2F5X3BheW1lbnRfZm9ybXMnICsgaWRfYWRkaXRpb25hbCArICdcIj48L2Rpdj4nICk7XHJcblx0XHRcdGpRdWVyeSggJyNnYXRld2F5X3BheW1lbnRfZm9ybXMnICsgcmVzb3VyY2VfaWQgKS5hZnRlciggJzxkaXYgaWQ9XCJhamF4X3Jlc3BvbmRfaW5zZXJ0JyArIGlkX2FkZGl0aW9uYWwgKyAnXCIgc3R5bGU9XCJkaXNwbGF5Om5vbmU7XCI+PC9kaXY+JyApO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8vIEZpeEluOiA4LjUuMi4xNy5cclxuXHRcdHdwYmNfc2VuZF9hamF4X3N1Ym1pdCggaWRfYWRkaXRpb25hbCwgZm9ybWRhdGFfYWRkaXRpb25hbCwgY2FwdGNoYV9jaGFsYW5nZSwgdXNlcl9jYXB0Y2hhLCBpc19zZW5kX2VtZWlscywgbXlfYm9va2luZ19oYXNoLCBteV9ib29raW5nX2Zvcm0sIHdwZGV2X2FjdGl2ZV9sb2NhbGUgKTtcclxuXHR9XHJcbn1cclxuXHJcblxyXG4vKipcclxuICogU2VuZCBBamF4IHN1Ym1pdCAobGVnYWN5OiBzZW5kX2FqYXhfc3VibWl0KS5cclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ8c3RyaW5nfSByZXNvdXJjZV9pZFxyXG4gKiBAcGFyYW0ge3N0cmluZ30gICAgICAgIGZvcm1kYXRhXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSAgICAgICAgY2FwdGNoYV9jaGFsYW5nZVxyXG4gKiBAcGFyYW0ge3N0cmluZ30gICAgICAgIHVzZXJfY2FwdGNoYVxyXG4gKiBAcGFyYW0ge251bWJlcn0gICAgICAgIGlzX3NlbmRfZW1laWxzXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSAgICAgICAgbXlfYm9va2luZ19oYXNoXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSAgICAgICAgbXlfYm9va2luZ19mb3JtXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSAgICAgICAgd3BkZXZfYWN0aXZlX2xvY2FsZVxyXG4gKlxyXG4gKiBAcmV0dXJuIHt1bmRlZmluZWR9IExlZ2FjeSBiZWhhdmlvci5cclxuICovXHJcbmZ1bmN0aW9uIHdwYmNfc2VuZF9hamF4X3N1Ym1pdChyZXNvdXJjZV9pZCwgZm9ybWRhdGEsIGNhcHRjaGFfY2hhbGFuZ2UsIHVzZXJfY2FwdGNoYSwgaXNfc2VuZF9lbWVpbHMsIG15X2Jvb2tpbmdfaGFzaCwgbXlfYm9va2luZ19mb3JtLCB3cGRldl9hY3RpdmVfbG9jYWxlKSB7XHJcblxyXG5cdHJlc291cmNlX2lkID0gcGFyc2VJbnQoIHJlc291cmNlX2lkLCAxMCApO1xyXG5cclxuXHQvLyBEaXNhYmxlIFN1Ym1pdCB8IFNob3cgc3BpbiBsb2FkZXIuXHJcblx0d3BiY19ib29raW5nX2Zvcm1fX29uX3N1Ym1pdF9fdWlfZWxlbWVudHNfZGlzYWJsZSggcmVzb3VyY2VfaWQgKTtcclxuXHJcblx0Ly8gRml4SW46IDIwMjYtMDItMDUgLSBwYXNzIHByZXZpZXcgY29udGV4dCB0byBib29raW5nIGNyZWF0ZSBBamF4LlxyXG5cdHZhciBmb3JtX3N0YXR1cyAgPSB3cGJjX19nZXRfZm9ybV9zdGF0dXNfZm9yX3N1Ym1pdCggcmVzb3VyY2VfaWQgKTtcclxuXHR2YXIgcHJldmlld19hcmdzID0gKGZvcm1fc3RhdHVzID09PSAncHJldmlldycpID8gd3BiY19fZ2V0X2JmYl9wcmV2aWV3X2FyZ3NfZnJvbV9sb2NhdGlvbigpIDogbnVsbDtcclxuXHJcblx0dmFyIHJlcXVlc3RfcGFyYW1zID0ge1xyXG5cdFx0J3Jlc291cmNlX2lkJyAgICAgICAgICAgICAgOiByZXNvdXJjZV9pZCxcclxuXHRcdCdkYXRlc19kZG1teXlfY3N2JyAgICAgICAgIDogZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoICdkYXRlX2Jvb2tpbmcnICsgcmVzb3VyY2VfaWQgKS52YWx1ZSxcclxuXHRcdCdmb3JtZGF0YScgICAgICAgICAgICAgICAgIDogZm9ybWRhdGEsXHJcblx0XHQnYm9va2luZ19oYXNoJyAgICAgICAgICAgICA6IG15X2Jvb2tpbmdfaGFzaCxcclxuXHRcdCdjdXN0b21fZm9ybScgICAgICAgICAgICAgIDogbXlfYm9va2luZ19mb3JtLFxyXG5cdFx0J2FnZ3JlZ2F0ZV9yZXNvdXJjZV9pZF9hcnInOiAoICggbnVsbCAhPT0gX3dwYmMuYm9va2luZ19fZ2V0X3BhcmFtX3ZhbHVlKCByZXNvdXJjZV9pZCwgJ2FnZ3JlZ2F0ZV9yZXNvdXJjZV9pZF9hcnInICkgKSA/IF93cGJjLmJvb2tpbmdfX2dldF9wYXJhbV92YWx1ZSggcmVzb3VyY2VfaWQsICdhZ2dyZWdhdGVfcmVzb3VyY2VfaWRfYXJyJyApLmpvaW4oICcsJyApIDogJycgKSxcclxuXHRcdCdjYXB0Y2hhX2NoYWxhbmdlJyAgICAgICAgIDogY2FwdGNoYV9jaGFsYW5nZSxcclxuXHRcdCdjYXB0Y2hhX3VzZXJfaW5wdXQnICAgICAgIDogdXNlcl9jYXB0Y2hhLFxyXG5cdFx0J2lzX2VtYWlsc19zZW5kJyAgICAgICAgICAgOiBpc19zZW5kX2VtZWlscyxcclxuXHRcdCdhY3RpdmVfbG9jYWxlJyAgICAgICAgICAgIDogd3BkZXZfYWN0aXZlX2xvY2FsZSxcclxuXHRcdCdmb3JtX3N0YXR1cycgICAgICAgICAgICAgIDogZm9ybV9zdGF0dXNcclxuXHR9O1xyXG5cclxuXHQvLyBJZiBwcmV2aWV3LCBwYXNzIHNlc3Npb24gaWRlbnRpZmllcnMgc28gUEhQIGNhbiBsb2FkIHRyYW5zaWVudCBzbmFwc2hvdC5cclxuXHRpZiAoIHByZXZpZXdfYXJncyAmJiBwcmV2aWV3X2FyZ3MudG9rZW4gJiYgcHJldmlld19hcmdzLmZvcm1faWQgKSB7XHJcblx0XHRyZXF1ZXN0X3BhcmFtc1snd3BiY19iZmJfcHJldmlldyddICAgICAgICAgPSAxO1xyXG5cdFx0cmVxdWVzdF9wYXJhbXNbJ3dwYmNfYmZiX3ByZXZpZXdfdG9rZW4nXSAgID0gcHJldmlld19hcmdzLnRva2VuO1xyXG5cdFx0cmVxdWVzdF9wYXJhbXNbJ3dwYmNfYmZiX3ByZXZpZXdfZm9ybV9pZCddID0gcHJldmlld19hcmdzLmZvcm1faWQ7XHJcblx0XHRyZXF1ZXN0X3BhcmFtc1snd3BiY19iZmJfcHJldmlld19ub25jZSddICAgPSBwcmV2aWV3X2FyZ3Mubm9uY2U7IC8vIG5vdGU6IFVSTCBwYXJhbSBpcyBgbm9uY2VgLlxyXG5cdH1cclxuXHJcblx0dmFyIGlzX2V4aXQgPSB3cGJjX2FqeF9ib29raW5nX19jcmVhdGUoIHJlcXVlc3RfcGFyYW1zICk7XHJcblxyXG5cdGlmICggdHJ1ZSA9PT0gaXNfZXhpdCApIHtcclxuXHRcdHJldHVybjtcclxuXHR9XHJcbn1cclxuXHJcblxyXG5cclxuLy8gPT0gSGVscGVyIEZ1bmN0aW9ucyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcblxyXG4vKipcclxuICogUGFyc2UgcXVlcnkgc3RyaW5nIGludG8ge2tleTp2YWx1ZX0gKG9sZC1icm93c2VyIHNhZmUpLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcXNcclxuICogQHJldHVybiB7T2JqZWN0fVxyXG4gKi9cclxuZnVuY3Rpb24gd3BiY19fcGFyc2VfcXVlcnlfc3RyaW5nKHFzKSB7XHJcblx0dmFyIG91dCA9IHt9O1xyXG5cdHFzICAgICAgPSAocXMgfHwgJycpO1xyXG5cdHFzICAgICAgPSBxcy5yZXBsYWNlKCAvXlxcPy8sICcnICk7XHJcblx0aWYgKCAhIHFzICkge1xyXG5cdFx0cmV0dXJuIG91dDtcclxuXHR9XHJcblxyXG5cdHZhciBwYXJ0cyA9IHFzLnNwbGl0KCAnJicgKTtcclxuXHRmb3IgKCB2YXIgaSA9IDA7IGkgPCBwYXJ0cy5sZW5ndGg7IGkrKyApIHtcclxuXHRcdHZhciBrdiA9IHBhcnRzW2ldLnNwbGl0KCAnPScgKTtcclxuXHRcdHZhciBrICA9IGRlY29kZVVSSUNvbXBvbmVudCgga3ZbMF0gfHwgJycgKTtcclxuXHRcdGlmICggISBrICkge1xyXG5cdFx0XHRjb250aW51ZTtcclxuXHRcdH1cclxuXHRcdHZhciB2ICA9IGRlY29kZVVSSUNvbXBvbmVudCgga3Yuc2xpY2UoIDEgKS5qb2luKCAnPScgKSB8fCAnJyApO1xyXG5cdFx0b3V0W2tdID0gdjtcclxuXHR9XHJcblx0cmV0dXJuIG91dDtcclxufVxyXG5cclxuLyoqXHJcbiAqIERldGVjdCBwcmV2aWV3IGFyZ3MgZnJvbSBjdXJyZW50IFVSTCAoaWZyYW1lIFVSTCkuXHJcbiAqXHJcbiAqIEByZXR1cm4ge09iamVjdHxudWxsfSB7IHRva2VuLCBmb3JtX2lkLCBub25jZSB9IG9yIG51bGxcclxuICovXHJcbmZ1bmN0aW9uIHdwYmNfX2dldF9iZmJfcHJldmlld19hcmdzX2Zyb21fbG9jYXRpb24oKSB7XHJcblx0dHJ5IHtcclxuXHRcdHZhciBwID0gd3BiY19fcGFyc2VfcXVlcnlfc3RyaW5nKCAod2luZG93LmxvY2F0aW9uICYmIHdpbmRvdy5sb2NhdGlvbi5zZWFyY2gpID8gd2luZG93LmxvY2F0aW9uLnNlYXJjaCA6ICcnICk7XHJcblxyXG5cdFx0aWYgKCAhIHAud3BiY19iZmJfcHJldmlldyB8fCAocC53cGJjX2JmYl9wcmV2aWV3ID09PSAnMCcpICkge1xyXG5cdFx0XHRyZXR1cm4gbnVsbDtcclxuXHRcdH1cclxuXHJcblx0XHRpZiAoICEgcC53cGJjX2JmYl9wcmV2aWV3X3Rva2VuIHx8ICEgcC53cGJjX2JmYl9wcmV2aWV3X2Zvcm1faWQgKSB7XHJcblx0XHRcdHJldHVybiBudWxsO1xyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB7XHJcblx0XHRcdHRva2VuICA6IFN0cmluZyggcC53cGJjX2JmYl9wcmV2aWV3X3Rva2VuICksXHJcblx0XHRcdGZvcm1faWQ6IHBhcnNlSW50KCBwLndwYmNfYmZiX3ByZXZpZXdfZm9ybV9pZCwgMTAgKSB8fCAwLFxyXG5cdFx0XHRub25jZSAgOiAocC5ub25jZSkgPyBTdHJpbmcoIHAubm9uY2UgKSA6ICcnXHJcblx0XHR9O1xyXG5cdH0gY2F0Y2ggKCBlICkge1xyXG5cdFx0cmV0dXJuIG51bGw7XHJcblx0fVxyXG59XHJcblxyXG4vKipcclxuICogUmVzb2x2ZSBmb3JtIHN0YXR1cyBmb3Igc3VibWl0LlxyXG4gKlxyXG4gKiBQcmlvcml0eTpcclxuICogMSkgc2hvcnRjb2RlIHBhcmFtIGV4cG9zZWQgdmlhIF93cGJjLmJvb2tpbmdfX2dldF9wYXJhbV92YWx1ZSguLi4sICdmb3JtX3N0YXR1cycpXHJcbiAqIDIpIGRldGVjdCBwcmV2aWV3IFVSTCBhcmdzXHJcbiAqIDMpIGZhbGxiYWNrOiBwdWJsaXNoZWRcclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IHJlc291cmNlX2lkXHJcbiAqIEByZXR1cm4ge3N0cmluZ30gJ3ByZXZpZXcnfCdwdWJsaXNoZWQnXHJcbiAqL1xyXG5mdW5jdGlvbiB3cGJjX19nZXRfZm9ybV9zdGF0dXNfZm9yX3N1Ym1pdChyZXNvdXJjZV9pZCkge1xyXG5cclxuXHR2YXIgc3RhdHVzID0gJyc7XHJcblxyXG5cdHRyeSB7XHJcblx0XHRpZiAoICh0eXBlb2YgX3dwYmMgIT09ICd1bmRlZmluZWQnKSAmJiBfd3BiYy5ib29raW5nX19nZXRfcGFyYW1fdmFsdWUgKSB7XHJcblx0XHRcdHN0YXR1cyA9IF93cGJjLmJvb2tpbmdfX2dldF9wYXJhbV92YWx1ZSggcmVzb3VyY2VfaWQsICdmb3JtX3N0YXR1cycgKTtcclxuXHRcdH1cclxuXHR9IGNhdGNoICggZSApIHt9XHJcblxyXG5cdHN0YXR1cyA9IChzdGF0dXMgPT0gbnVsbCkgPyAnJyA6IFN0cmluZyggc3RhdHVzICk7XHJcblx0c3RhdHVzID0gc3RhdHVzLnRvTG93ZXJDYXNlKCk7XHJcblxyXG5cdC8vIFVSTC1iYXNlZCBkZXRlY3Rpb24gZm9yIHByZXZpZXcgaWZyYW1lLlxyXG5cdHZhciBwcmV2aWV3X2FyZ3MgPSB3cGJjX19nZXRfYmZiX3ByZXZpZXdfYXJnc19mcm9tX2xvY2F0aW9uKCk7XHJcblx0aWYgKCBwcmV2aWV3X2FyZ3MgKSB7XHJcblx0XHRyZXR1cm4gJ3ByZXZpZXcnO1xyXG5cdH1cclxuXHJcblx0cmV0dXJuIChzdGF0dXMgPT09ICdwcmV2aWV3JykgPyAncHJldmlldycgOiAncHVibGlzaGVkJztcclxufVxyXG5cclxuXHJcblxyXG4vLyA9PSBCYWNrd2FyZC1jb21wYXRpYmxlIHdyYXBwZXJzIChrZWVwIG9sZCBnbG9iYWwgbmFtZXMgd29ya2luZyAxMDAlIGFzIGJlZm9yZSkuID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuZnVuY3Rpb24gbXlib29raW5nX3N1Ym1pdCggc3VibWl0X2Zvcm0sIHJlc291cmNlX2lkLCB3cGRldl9hY3RpdmVfbG9jYWxlICkge1xyXG5cdHJldHVybiB3cGJjX2Jvb2tpbmdfZm9ybV9zdWJtaXQoIHN1Ym1pdF9mb3JtLCByZXNvdXJjZV9pZCwgd3BkZXZfYWN0aXZlX2xvY2FsZSApO1xyXG59XHJcbiIsInRyeSB7XHJcblx0dmFyIGV2ID0gKHR5cGVvZiBDdXN0b21FdmVudCA9PT0gJ2Z1bmN0aW9uJykgPyBuZXcgQ3VzdG9tRXZlbnQoICd3cGJjLXJlYWR5JyApIDogZG9jdW1lbnQuY3JlYXRlRXZlbnQoICdFdmVudCcgKTtcclxuXHRpZiAoIGV2LmluaXRFdmVudCApIHtcclxuXHRcdGV2LmluaXRFdmVudCggJ3dwYmMtcmVhZHknLCB0cnVlLCB0cnVlICk7XHJcblx0fVxyXG5cdGRvY3VtZW50LmRpc3BhdGNoRXZlbnQoIGV2ICk7XHJcblx0Y29uc29sZS5sb2coICd3cGJjLXJlYWR5JyApO1xyXG59IGNhdGNoICggZSApIHtcclxuXHRjb25zb2xlLmVycm9yKCBcIldQQkMgZXZlbnQgJ3dwYmMtcmVhZHknIGZhaWxlZCFcIiwgZSApO1xyXG59XHJcbiJdfQ==
5353