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_admin.js

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

2,240 lines 197.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1
2 /**
3 * Blink specific HTML element to set attention to this element.
4 *
5 * @param {string} element_to_blink - class or id of element: '.wpbc_widget_available_unavailable'
6 * @param {int} how_many_times - 4
7 * @param {int} how_long_to_blink - 350
8 */
9 function wpbc_blink_element( element_to_blink, how_many_times = 4, how_long_to_blink = 350 ){
10
11 for ( let i = 0; i < how_many_times; i++ ){
12 jQuery( element_to_blink ).fadeOut( how_long_to_blink ).fadeIn( how_long_to_blink );
13 }
14 jQuery( element_to_blink ).animate( {opacity: 1}, 500 );
15 }
16
17 /**
18 * Support Functions - Spin Icon in Buttons ------------------------------------------------------------------ */
19
20 /**
21 * Remove spin icon from button and Enable this button.
22 *
23 * @param button_clicked_element_id - HTML ID attribute of this button
24 * @return string - CSS classes that was previously in button icon
25 */
26 function wpbc_button__remove_spin(button_clicked_element_id) {
27
28 var previos_classes = '';
29 if (
30 (undefined != button_clicked_element_id)
31 && ('' != button_clicked_element_id)
32 ) {
33 var jElement = jQuery( '#' + button_clicked_element_id );
34 if ( jElement.length ) {
35 previos_classes = wpbc_button_disable_loading_icon( jElement.get( 0 ) );
36 }
37 }
38
39 return previos_classes;
40 }
41
42
43 /**
44 * Show Loading (rotating arrow) icon for button that has been clicked
45 *
46 * @param this_button - this object of specific button
47 * @return string - CSS classes that was previously in button icon
48 */
49 function wpbc_button_enable_loading_icon(this_button) {
50
51 var jButton = jQuery( this_button );
52 var jIcon = jButton.find( 'i' );
53 var previos_classes = jIcon.attr( 'class' );
54
55 jIcon.removeClass().addClass( 'menu_icon icon-1x wpbc_icn_rotate_right wpbc_spin' ); // Set Rotate icon.
56 // jIcon.addClass( 'wpbc_animation_pause' ); // Pause animation.
57 // jIcon.addClass( 'wpbc_ui_red' ); // Set icon color red.
58
59 jIcon.attr( 'wpbc_previous_class', previos_classes )
60
61 jButton.addClass( 'disabled' ); // Disable button
62 // We need to set here attr instead of prop, because for A elements, attribute 'disabled' do not added with jButton.prop( "disabled", true );.
63
64 jButton.attr( 'wpbc_previous_onclick', jButton.attr( 'onclick' ) ); // Save this value.
65 jButton.attr( 'onclick', '' ); // Disable actions "on click".
66
67 return previos_classes;
68 }
69
70
71 /**
72 * Hide Loading (rotating arrow) icon for button that was clicked and show previous icon and enable button
73 *
74 * @param this_button - this object of specific button
75 * @return string - CSS classes that was previously in button icon
76 */
77 function wpbc_button_disable_loading_icon(this_button) {
78
79 var jButton = jQuery( this_button );
80 var jIcon = jButton.find( 'i' );
81
82 var previos_classes = jIcon.attr( 'wpbc_previous_class' );
83 if (
84 (undefined != previos_classes)
85 && ('' != previos_classes)
86 ) {
87 jIcon.removeClass().addClass( previos_classes );
88 }
89
90 jButton.removeClass( 'disabled' ); // Remove Disable button.
91
92 var previous_onclick = jButton.attr( 'wpbc_previous_onclick' )
93 if (
94 (undefined != previous_onclick)
95 && ('' != previous_onclick)
96 ) {
97 jButton.attr( 'onclick', previous_onclick );
98 }
99
100 return previos_classes;
101 }
102
103 /**
104 * On selection of radio button, adjust attributes of radio container
105 *
106 * @param _this
107 */
108 function wpbc_ui_el__radio_container_selection(_this) {
109
110 if ( jQuery( _this ).is( ':checked' ) ) {
111 jQuery( _this ).parents( '.wpbc_ui_radio_section' ).find( '.wpbc_ui_radio_container' ).removeAttr( 'data-selected' );
112 jQuery( _this ).parents( '.wpbc_ui_radio_container:not(.disabled)' ).attr( 'data-selected', true );
113 }
114
115 if ( jQuery( _this ).is( ':disabled' ) ) {
116 jQuery( _this ).parents( '.wpbc_ui_radio_container' ).addClass( 'disabled' );
117 }
118 }
119
120 /**
121 * On click on Radio Container, we will select the radio button and then adjust attributes of radio container
122 *
123 * @param _this
124 */
125 function wpbc_ui_el__radio_container_click(_this) {
126
127 if ( jQuery( _this ).hasClass( 'disabled' ) ) {
128 return false;
129 }
130
131 var j_radio = jQuery( _this ).find( 'input[type=radio]:not(.wpbc-form-radio-internal)' );
132 if ( j_radio.length ) {
133 j_radio.prop( 'checked', true ).trigger( 'change' );
134 }
135
136 }
137 "use strict";
138 // =====================================================================================================================
139 // == Full Screen - support functions ==
140 // =====================================================================================================================
141
142 /**
143 * Check Full screen mode, by removing top tab
144 */
145 function wpbc_check_full_screen_mode(){
146 if ( jQuery( 'body' ).hasClass( 'wpbc_admin_full_screen' ) ) {
147 jQuery( 'html' ).removeClass( 'wp-toolbar' );
148 } else {
149 jQuery( 'html' ).addClass( 'wp-toolbar' );
150 }
151 wpbc_check_buttons_max_min_in_full_screen_mode();
152 }
153
154 function wpbc_check_buttons_max_min_in_full_screen_mode() {
155 if ( jQuery( 'body' ).hasClass( 'wpbc_admin_full_screen' ) ) {
156 jQuery( '.wpbc_ui__top_nav__btn_full_screen' ).addClass( 'wpbc_ui__hide' );
157 jQuery( '.wpbc_ui__top_nav__btn_normal_screen' ).removeClass( 'wpbc_ui__hide' );
158 } else {
159 jQuery( '.wpbc_ui__top_nav__btn_full_screen' ).removeClass( 'wpbc_ui__hide' );
160 jQuery( '.wpbc_ui__top_nav__btn_normal_screen' ).addClass( 'wpbc_ui__hide' );
161 }
162 }
163
164 jQuery( document ).ready( function () {
165 wpbc_check_full_screen_mode();
166 } );
167 /**
168 * Checkbox Selection functions for Listing.
169 */
170
171 /**
172 * Selections of several checkboxes like in gMail with shift :)
173 * Need to have this structure:
174 * .wpbc_selectable_table
175 * .wpbc_selectable_head
176 * .check-column
177 * :checkbox
178 * .wpbc_selectable_body
179 * .wpbc_row
180 * .check-column
181 * :checkbox
182 * .wpbc_selectable_foot
183 * .check-column
184 * :checkbox
185 */
186 function wpbc_define_gmail_checkbox_selection( $ ){
187
188 var checks, first, last, checked, sliced, lastClicked = false;
189
190 // Check all checkboxes.
191 $( '.wpbc_selectable_body' ).find( '.check-column' ).find( ':checkbox' ).on(
192 'click',
193 function (e) {
194 if ( 'undefined' == e.shiftKey ) {
195 return true;
196 }
197 if ( e.shiftKey ) {
198 if ( ! lastClicked ) {
199 return true;
200 }
201 checks = $( lastClicked ).closest( '.wpbc_selectable_body' ).find( ':checkbox' ).filter( ':visible:enabled' );
202 first = checks.index( lastClicked );
203 last = checks.index( this );
204 checked = $( this ).prop( 'checked' );
205 if ( 0 < first && 0 < last && first != last ) {
206 sliced = (last > first) ? checks.slice( first, last ) : checks.slice( last, first );
207 sliced.prop(
208 'checked',
209 function () {
210 if ( $( this ).closest( '.wpbc_row' ).is( ':visible' ) ) {
211 return checked;
212 }
213 return false;
214 }
215 ).trigger( 'change' );
216 }
217 }
218 lastClicked = this;
219
220 // toggle "check all" checkboxes.
221 var unchecked = $( this ).closest( '.wpbc_selectable_body' ).find( ':checkbox' ).filter( ':visible:enabled' ).not( ':checked' );
222 $( this ).closest( '.wpbc_selectable_table' ).children( '.wpbc_selectable_head, .wpbc_selectable_foot' ).find( ':checkbox' ).prop(
223 'checked',
224 function () {
225 return (0 === unchecked.length);
226 }
227 ).trigger( 'change' );
228
229 return true;
230 }
231 );
232
233 // Head || Foot clicking to select / deselect ALL.
234 $( '.wpbc_selectable_head, .wpbc_selectable_foot' ).find( '.check-column :checkbox' ).on(
235 'click',
236 function (event) {
237 var $this = $( this ),
238 $table = $this.closest( '.wpbc_selectable_table' ),
239 controlChecked = $this.prop( 'checked' ),
240 toggle = event.shiftKey || $this.data( 'wp-toggle' );
241
242 $table.children( '.wpbc_selectable_body' ).filter( ':visible' )
243 .find( '.check-column' ).find( ':checkbox' )
244 .prop(
245 'checked',
246 function () {
247 if ( $( this ).is( ':hidden,:disabled' ) ) {
248 return false;
249 }
250 if ( toggle ) {
251 return ! $( this ).prop( 'checked' );
252 } else if ( controlChecked ) {
253 return true;
254 }
255 return false;
256 }
257 ).trigger( 'change' );
258
259 $table.children( '.wpbc_selectable_head, .wpbc_selectable_foot' ).filter( ':visible' )
260 .find( '.check-column' ).find( ':checkbox' )
261 .prop(
262 'checked',
263 function () {
264 if ( toggle ) {
265 return false;
266 } else if ( controlChecked ) {
267 return true;
268 }
269 return false;
270 }
271 );
272 }
273 );
274
275
276 // Visually show selected border.
277 $( '.wpbc_selectable_body' ).find( '.check-column :checkbox' ).on(
278 'change',
279 function (event) {
280 if ( jQuery( this ).is( ':checked' ) ) {
281 jQuery( this ).closest( '.wpbc_list_row' ).addClass( 'row_selected_color' );
282 } else {
283 jQuery( this ).closest( '.wpbc_list_row' ).removeClass( 'row_selected_color' );
284 }
285
286 // Disable text selection while pressing 'shift'.
287 document.getSelection().removeAllRanges();
288
289 // Show or hide buttons on Actions toolbar at Booking Listing page, if we have some selected bookings.
290 wpbc_show_hide_action_buttons_for_selected_bookings();
291 }
292 );
293
294 wpbc_show_hide_action_buttons_for_selected_bookings();
295 }
296
297
298 /**
299 * Get ID array of selected elements
300 */
301 function wpbc_get_selected_row_id() {
302
303 var $table = jQuery( '.wpbc__wrap__booking_listing .wpbc_selectable_table' );
304 var checkboxes = $table.children( '.wpbc_selectable_body' ).filter( ':visible' ).find( '.check-column' ).find( ':checkbox' );
305 var selected_id = [];
306
307 jQuery.each(
308 checkboxes,
309 function (key, checkbox) {
310 if ( jQuery( checkbox ).is( ':checked' ) ) {
311 var element_id = wpbc_get_row_id_from_element( checkbox );
312 selected_id.push( element_id );
313 }
314 }
315 );
316
317 return selected_id;
318 }
319
320
321 /**
322 * Get ID of row, based on clciked element
323 *
324 * @param this_inbound_element - ususlly this
325 * @returns {number}
326 */
327 function wpbc_get_row_id_from_element(this_inbound_element) {
328
329 var element_id = jQuery( this_inbound_element ).closest( '.wpbc_listing_usual_row' ).attr( 'id' );
330
331 element_id = parseInt( element_id.replace( 'row_id_', '' ) );
332
333 return element_id;
334 }
335
336
337 /**
338 * == Booking Listing == Show or hide buttons on Actions toolbar at page, if we have some selected bookings.
339 */
340 function wpbc_show_hide_action_buttons_for_selected_bookings(){
341
342 var selected_rows_arr = wpbc_get_selected_row_id();
343
344 if ( selected_rows_arr.length > 0 ) {
345 jQuery( '.hide_button_if_no_selection' ).show();
346 } else {
347 jQuery( '.hide_button_if_no_selection' ).hide();
348 }
349 }
350 "use strict";
351 // =====================================================================================================================
352 // == Left Bar - expand / colapse functions ==
353 // =====================================================================================================================
354
355 /**
356 * Expand Vertical Left Bar.
357 */
358 function wpbc_admin_ui__sidebar_left__do_max() {
359 jQuery( '.wpbc_settings_page_wrapper' ).removeClass( 'min max compact none' );
360 jQuery( '.wpbc_settings_page_wrapper' ).addClass( 'max' );
361 jQuery( '.wpbc_ui__top_nav__btn_open_left_vertical_nav' ).addClass( 'wpbc_ui__hide' );
362 jQuery( '.wpbc_ui__top_nav__btn_hide_left_vertical_nav' ).removeClass( 'wpbc_ui__hide' );
363
364 jQuery( '.wp-admin' ).removeClass( 'wpbc_page_wrapper_left_min wpbc_page_wrapper_left_max wpbc_page_wrapper_left_compact wpbc_page_wrapper_left_none' );
365 jQuery( '.wp-admin' ).addClass( 'wpbc_page_wrapper_left_max' );
366 }
367
368 /**
369 * Hide Vertical Left Bar.
370 */
371 function wpbc_admin_ui__sidebar_left__do_min() {
372 jQuery( '.wpbc_settings_page_wrapper' ).removeClass( 'min max compact none' );
373 jQuery( '.wpbc_settings_page_wrapper' ).addClass( 'min' );
374 jQuery( '.wpbc_ui__top_nav__btn_open_left_vertical_nav' ).removeClass( 'wpbc_ui__hide' );
375 jQuery( '.wpbc_ui__top_nav__btn_hide_left_vertical_nav' ).addClass( 'wpbc_ui__hide' );
376
377 jQuery( '.wp-admin' ).removeClass( 'wpbc_page_wrapper_left_min wpbc_page_wrapper_left_max wpbc_page_wrapper_left_compact wpbc_page_wrapper_left_none' );
378 jQuery( '.wp-admin' ).addClass( 'wpbc_page_wrapper_left_min' );
379 }
380
381 /**
382 * Colapse Vertical Left Bar.
383 */
384 function wpbc_admin_ui__sidebar_left__do_compact() {
385 jQuery( '.wpbc_settings_page_wrapper' ).removeClass( 'min max compact none' );
386 jQuery( '.wpbc_settings_page_wrapper' ).addClass( 'compact' );
387 jQuery( '.wpbc_ui__top_nav__btn_open_left_vertical_nav' ).removeClass( 'wpbc_ui__hide' );
388 jQuery( '.wpbc_ui__top_nav__btn_hide_left_vertical_nav' ).addClass( 'wpbc_ui__hide' );
389
390 jQuery( '.wp-admin' ).removeClass( 'wpbc_page_wrapper_left_min wpbc_page_wrapper_left_max wpbc_page_wrapper_left_compact wpbc_page_wrapper_left_none' );
391 jQuery( '.wp-admin' ).addClass( 'wpbc_page_wrapper_left_compact' );
392 }
393
394 /**
395 * Completely Hide Vertical Left Bar.
396 */
397 function wpbc_admin_ui__sidebar_left__do_hide() {
398 jQuery( '.wpbc_settings_page_wrapper' ).removeClass( 'min max compact none' );
399 jQuery( '.wpbc_settings_page_wrapper' ).addClass( 'none' );
400 jQuery( '.wpbc_ui__top_nav__btn_open_left_vertical_nav' ).removeClass( 'wpbc_ui__hide' );
401 jQuery( '.wpbc_ui__top_nav__btn_hide_left_vertical_nav' ).addClass( 'wpbc_ui__hide' );
402 // Hide top "Menu" button with divider.
403 jQuery( '.wpbc_ui__top_nav__btn_show_left_vertical_nav,.wpbc_ui__top_nav__btn_show_left_vertical_nav_divider' ).addClass( 'wpbc_ui__hide' );
404
405 jQuery( '.wp-admin' ).removeClass( 'wpbc_page_wrapper_left_min wpbc_page_wrapper_left_max wpbc_page_wrapper_left_compact wpbc_page_wrapper_left_none' );
406 jQuery( '.wp-admin' ).addClass( 'wpbc_page_wrapper_left_none' );
407 }
408
409 /**
410 * Action on click "Go Back" - show root menu
411 * or some other section in left sidebar.
412 *
413 * @param string menu_to_show - menu slug.
414 */
415 function wpbc_admin_ui__sidebar_left__show_section( menu_to_show ) {
416 jQuery( '.wpbc_ui_el__vert_left_bar__section' ).addClass( 'wpbc_ui__hide' )
417 jQuery( '.wpbc_ui_el__vert_left_bar__section_' + menu_to_show ).removeClass( 'wpbc_ui__hide' );
418 }
419
420 // =====================================================================================================================
421 // == Right Side Bar - expand / colapse functions ==
422 // =====================================================================================================================
423
424 /**
425 * Expand Vertical Right Bar.
426 */
427 function wpbc_admin_ui__sidebar_right__do_max() {
428 jQuery( '.wpbc_settings_page_wrapper' ).removeClass( 'min_right max_right compact_right none_right' );
429 jQuery( '.wpbc_settings_page_wrapper' ).addClass( 'max_right' );
430 jQuery( '.wpbc_ui__top_nav__btn_open_right_vertical_nav' ).addClass( 'wpbc_ui__hide' );
431 jQuery( '.wpbc_ui__top_nav__btn_hide_right_vertical_nav' ).removeClass( 'wpbc_ui__hide' );
432 }
433
434 /**
435 * Hide Vertical Right Bar.
436 */
437 function wpbc_admin_ui__sidebar_right__do_min() {
438 jQuery( '.wpbc_settings_page_wrapper' ).removeClass( 'min_right max_right compact_right none_right' );
439 jQuery( '.wpbc_settings_page_wrapper' ).addClass( 'min_right' );
440 jQuery( '.wpbc_ui__top_nav__btn_open_right_vertical_nav' ).removeClass( 'wpbc_ui__hide' );
441 jQuery( '.wpbc_ui__top_nav__btn_hide_right_vertical_nav' ).addClass( 'wpbc_ui__hide' );
442 }
443
444 /**
445 * Colapse Vertical Right Bar.
446 */
447 function wpbc_admin_ui__sidebar_right__do_compact() {
448 jQuery( '.wpbc_settings_page_wrapper' ).removeClass( 'min_right max_right compact_right none_right' );
449 jQuery( '.wpbc_settings_page_wrapper' ).addClass( 'compact_right' );
450 jQuery( '.wpbc_ui__top_nav__btn_open_right_vertical_nav' ).removeClass( 'wpbc_ui__hide' );
451 jQuery( '.wpbc_ui__top_nav__btn_hide_right_vertical_nav' ).addClass( 'wpbc_ui__hide' );
452 }
453
454 /**
455 * Completely Hide Vertical Right Bar.
456 */
457 function wpbc_admin_ui__sidebar_right__do_hide() {
458 jQuery( '.wpbc_settings_page_wrapper' ).removeClass( 'min_right max_right compact_right none_right' );
459 jQuery( '.wpbc_settings_page_wrapper' ).addClass( 'none_right' );
460 jQuery( '.wpbc_ui__top_nav__btn_open_right_vertical_nav' ).removeClass( 'wpbc_ui__hide' );
461 jQuery( '.wpbc_ui__top_nav__btn_hide_right_vertical_nav' ).addClass( 'wpbc_ui__hide' );
462 // Hide top "Menu" button with divider.
463 jQuery( '.wpbc_ui__top_nav__btn_show_right_vertical_nav,.wpbc_ui__top_nav__btn_show_right_vertical_nav_divider' ).addClass( 'wpbc_ui__hide' );
464 }
465
466 /**
467 * Action on click "Go Back" - show root menu
468 * or some other section in right sidebar.
469 *
470 * @param string menu_to_show - menu slug.
471 */
472 function wpbc_admin_ui__sidebar_right__show_section( menu_to_show ) {
473 jQuery( '.wpbc_ui_el__vert_right_bar__section' ).addClass( 'wpbc_ui__hide' )
474 jQuery( '.wpbc_ui_el__vert_right_bar__section_' + menu_to_show ).removeClass( 'wpbc_ui__hide' );
475 }
476
477 // =====================================================================================================================
478 // == End Right Side Bar section ==
479 // =====================================================================================================================
480
481 /**
482 * Get anchor(s) array from URL.
483 * Doc: https://developer.mozilla.org/en-US/docs/Web/API/Location
484 *
485 * @returns {*[]}
486 */
487 function wpbc_url_get_anchors_arr() {
488 var hashes = window.location.hash.replace( '%23', '#' );
489 var hashes_arr = hashes.split( '#' );
490 var result = [];
491 var hashes_arr_length = hashes_arr.length;
492
493 for ( var i = 0; i < hashes_arr_length; i++ ) {
494 if ( hashes_arr[i].length > 0 ) {
495 result.push( hashes_arr[i] );
496 }
497 }
498 return result;
499 }
500
501 /**
502 * Auto Expand Settings section based on URL anchor, after page loaded.
503 */
504 jQuery( document ).ready( function () { wpbc_admin_ui__redirect_legacy_general_availability_url(); } );
505 jQuery( document ).ready( function () { wpbc_admin_ui__do_expand_section(); setTimeout( 'wpbc_admin_ui__do_expand_section', 10 ); } );
506 jQuery( document ).ready( function () { wpbc_admin_ui__do_expand_section(); setTimeout( 'wpbc_admin_ui__do_expand_section', 150 ); } );
507
508 /**
509 * Redirect old Settings > Availability anchors to the dedicated General Availability page.
510 */
511 function wpbc_admin_ui__redirect_legacy_general_availability_url() {
512
513 if (
514 ( window.location.href.indexOf( 'page=wpbc-settings' ) > -1 )
515 && (
516 ( window.location.hash.indexOf( 'wpbc_general_settings_availability_metabox' ) > -1 )
517 || ( window.location.hash.indexOf( 'wpbc_general_settings_availability_tab' ) > -1 )
518 )
519 ) {
520 window.location.replace( window.location.href.split( '?' )[0] + '?page=wpbc-availability&tab=general_availability' );
521 }
522 }
523
524 /**
525 * Expand section in General Settings page and select Menu item.
526 */
527 function wpbc_admin_ui__do_expand_section() {
528
529 // window.location.hash = #section_id / doc: https://developer.mozilla.org/en-US/docs/Web/API/Location .
530 var anchors_arr = wpbc_url_get_anchors_arr();
531 var anchors_arr_length = anchors_arr.length;
532
533 if ( anchors_arr_length > 0 ) {
534 var one_anchor_prop_value = anchors_arr[0].split( 'do_expand__' );
535 if ( one_anchor_prop_value.length > 1 ) {
536
537 // 'wpbc_general_settings_calendar_metabox'
538 var section_to_show = one_anchor_prop_value[1];
539 var section_id_to_show = '#' + section_to_show;
540
541
542 // -- Remove selected background in all left menu items ---------------------------------------------------
543 jQuery( '.wpbc_ui_el__vert_nav_item ' ).removeClass( 'active' );
544 // Set left menu selected.
545 jQuery( '.do_expand__' + section_to_show + '_link' ).addClass( 'active' );
546 var selected_title = jQuery( '.do_expand__' + section_to_show + '_link a .wpbc_ui_el__vert_nav_title ' ).text();
547
548 // Expand section, if it colapsed.
549 if ( ! jQuery( '.do_expand__' + section_to_show + '_link' ).parents( '.wpbc_ui_el__level__folder' ).hasClass( 'expanded' ) ) {
550 jQuery( '.wpbc_ui_el__level__folder' ).removeClass( 'expanded' );
551 jQuery( '.do_expand__' + section_to_show + '_link' ).parents( '.wpbc_ui_el__level__folder' ).addClass( 'expanded' );
552 }
553
554 // -- Expand section ---------------------------------------------------------------------------------------
555 var container_to_hide_class = '.postbox';
556 // Hide sections '.postbox' in admin page and show specific one.
557 jQuery( '.wpbc_admin_page ' + container_to_hide_class ).hide();
558 jQuery( '.wpbc_container_always_hide__on_left_nav_click' ).hide();
559 jQuery( section_id_to_show ).show();
560
561 // Show all other sections, if provided in URL: ..?page=wpbc-settings#do_expand__wpbc_general_settings_capacity_metabox#wpbc_general_settings_capacity_upgrade_metabox .
562 for ( let i = 1; i < anchors_arr_length; i++ ) {
563 jQuery( '#' + anchors_arr[i] ).show();
564 }
565
566 if ( false ) {
567 var targetOffset = wpbc_scroll_to( section_id_to_show );
568 }
569
570 // -- Set Value to Input about selected Nav element --------------------------------------------------------------- // FixIn: 9.8.6.1.
571 var section_id_tab = section_id_to_show.substring( 0, section_id_to_show.length - 8 ) + '_tab';
572 if ( container_to_hide_class == section_id_to_show ) {
573 section_id_tab = '#wpbc_general_settings_all_tab'
574 }
575 if ( '#wpbc_general_settings_capacity_metabox,#wpbc_general_settings_capacity_upgrade_metabox' == section_id_to_show ) {
576 section_id_tab = '#wpbc_general_settings_capacity_tab'
577 }
578 jQuery( '#form_visible_section' ).val( section_id_tab );
579 }
580
581 // Like blinking some elements.
582 wpbc_admin_ui__do__anchor__another_actions();
583 }
584 }
585
586 function wpbc_admin_ui__is_in_mobile_screen_size() {
587 return wpbc_admin_ui__is_in_this_screen_size( 605 );
588 }
589
590 function wpbc_admin_ui__is_in_this_screen_size(size) {
591 return (window.screen.width <= size);
592 }
593
594 /**
595 * Open settings page | Expand section | Select Menu item.
596 */
597 function wpbc_admin_ui__do__open_url__expand_section(url, section_id) {
598
599 // window.location.href = url + '&do_expand=' + section_id + '#do_expand__' + section_id; //.
600 window.location.href = url + '#do_expand__' + section_id;
601
602 if ( wpbc_admin_ui__is_in_mobile_screen_size() ) {
603 wpbc_admin_ui__sidebar_left__do_min();
604 }
605
606 wpbc_admin_ui__do_expand_section();
607 }
608
609
610 /**
611 * Check for Other actions: Like blinking some elements in settings page. E.g. Days selection or change-over days.
612 */
613 function wpbc_admin_ui__do__anchor__another_actions() {
614
615 var anchors_arr = wpbc_url_get_anchors_arr();
616 var anchors_arr_length = anchors_arr.length;
617
618 // Other actions: Like blinking some elements.
619 for ( var i = 0; i < anchors_arr_length; i++ ) {
620
621 var this_anchor = anchors_arr[i];
622
623 var this_anchor_prop_value = this_anchor.split( 'do_other_actions__' );
624
625 if ( this_anchor_prop_value.length > 1 ) {
626
627 var section_action = this_anchor_prop_value[1];
628
629 switch ( section_action ) {
630
631 case 'blink_day_selections':
632 // wpbc_ui_settings__panel__click( '#wpbc_general_settings_calendar_tab a', '#wpbc_general_settings_calendar_metabox', 'Days Selection' );.
633 wpbc_blink_element( '.wpbc_tr_set_gen_booking_type_of_day_selections', 4, 350 );
634 wpbc_scroll_to( '.wpbc_tr_set_gen_booking_type_of_day_selections' );
635 break;
636
637 case 'blink_change_over_days':
638 // wpbc_ui_settings__panel__click( '#wpbc_general_settings_calendar_tab a', '#wpbc_general_settings_calendar_metabox', 'Changeover Days' );.
639 wpbc_blink_element( '.wpbc_tr_set_gen_booking_range_selection_time_is_active', 4, 350 );
640 wpbc_scroll_to( '.wpbc_tr_set_gen_booking_range_selection_time_is_active' );
641 break;
642
643 case 'blink_captcha':
644 wpbc_blink_element( '.wpbc_tr_set_gen_booking_is_use_captcha', 4, 350 );
645 wpbc_scroll_to( '.wpbc_tr_set_gen_booking_is_use_captcha' );
646 break;
647
648 default:
649 }
650 }
651 }
652 }
653
654 /**
655 * Copy txt to clipbrd from Text fields.
656 *
657 * @param html_element_id - e.g. 'data_field'
658 * @returns {boolean}
659 */
660 function wpbc_copy_text_to_clipbrd_from_element( html_element_id ) {
661 // Get the text field.
662 var copyText = document.getElementById( html_element_id );
663
664 // Select the text field.
665 copyText.select();
666 copyText.setSelectionRange( 0, 99999 ); // For mobile devices.
667
668 // Copy the text inside the text field.
669 var is_copied = wpbc_copy_text_to_clipbrd( copyText.value );
670 if ( ! is_copied ) {
671 console.error( 'Oops, unable to copy', copyText.value );
672 }
673 return is_copied;
674 }
675
676 /**
677 * Copy txt to clipbrd.
678 *
679 * @param text
680 * @returns {boolean}
681 */
682 function wpbc_copy_text_to_clipbrd(text) {
683
684 if ( ! navigator.clipboard ) {
685 return wpbc_fallback_copy_text_to_clipbrd( text );
686 }
687
688 navigator.clipboard.writeText( text ).then(
689 function () {
690 // console.log( 'Async: Copying to clipboard was successful!' );.
691 return true;
692 },
693 function (err) {
694 // console.error( 'Async: Could not copy text: ', err );.
695 return false;
696 }
697 );
698 }
699
700 /**
701 * Copy txt to clipbrd - depricated method.
702 *
703 * @param text
704 * @returns {boolean}
705 */
706 function wpbc_fallback_copy_text_to_clipbrd( text ) {
707
708 // -----------------------------------------------------------------------------------------------------------------
709 // var textArea = document.createElement( "textarea" );
710 // textArea.value = text;
711 //
712 // // Avoid scrolling to bottom.
713 // textArea.style.top = "0";
714 // textArea.style.left = "0";
715 // textArea.style.position = "fixed";
716 // textArea.style.zIndex = "999999999";
717 // document.body.appendChild( textArea );
718 // textArea.focus();
719 // textArea.select();
720
721 // -----------------------------------------------------------------------------------------------------------------
722 // Now get it as HTML (original here https://stackoverflow.com/questions/34191780/javascript-copy-string-to-clipboard-as-text-html ).
723
724 // [1] - Create container for the HTML.
725 var container = document.createElement( 'div' );
726 container.innerHTML = text;
727
728 // [2] - Hide element.
729 container.style.position = 'fixed';
730 container.style.pointerEvents = 'none';
731 container.style.opacity = 0;
732
733 // Detect all style sheets of the page.
734 var activeSheets = Array.prototype.slice.call( document.styleSheets ).filter(
735 function (sheet) {
736 return ! sheet.disabled;
737 }
738 );
739
740 // [3] - Mount the container to the DOM to make `contentWindow` available.
741 document.body.appendChild( container );
742
743 // [4] - Copy to clipboard.
744 window.getSelection().removeAllRanges();
745
746 var range = document.createRange();
747 range.selectNode( container );
748 window.getSelection().addRange( range );
749 // -----------------------------------------------------------------------------------------------------------------
750
751 var result = false;
752
753 try {
754 result = document.execCommand( 'copy' );
755 // console.log( 'Fallback: Copying text command was ' + msg ); //.
756 } catch ( err ) {
757 // console.error( 'Fallback: Oops, unable to copy', err ); //.
758 }
759 // document.body.removeChild( textArea ); //.
760
761 // [5.4] - Enable CSS.
762 var activeSheets_length = activeSheets.length;
763 for ( var i = 0; i < activeSheets_length; i++ ) {
764 activeSheets[i].disabled = false;
765 }
766
767 // [6] - Remove the container
768 document.body.removeChild( container );
769
770 return result;
771 }
772 /**
773 * WPBC Collapsible Groups
774 *
775 * Universal, dependency-free controller for expanding/collapsing grouped sections in right-side panels (Inspector/Library/Form Settings, or any other WPBC page).
776 *
777 * === How to use it (quick) ? ===
778 *
779 * -- 1. Markup (independent mode: multiple open allowed) --
780 * <div class="wpbc_collapsible">
781 * <section class="wpbc_ui__collapsible_group is-open">
782 * <button type="button" class="group__header"><h3>General</h3></button>
783 * <div class="group__fields">…</div>
784 * </section>
785 * <section class="wpbc_ui__collapsible_group">
786 * <button type="button" class="group__header"><h3>Advanced</h3></button>
787 * <div class="group__fields">…</div>
788 * </section>
789 * </div>
790 *
791 * -- 2. Exclusive/accordion mode (one open at a time) --
792 * <div class="wpbc_collapsible wpbc_collapsible--exclusive">…</div>
793 *
794 * -- 3. Auto-init --
795 * The script auto-initializes on DOMContentLoaded. No extra code needed.
796 *
797 * -- 4. Programmatic control (optional)
798 * const root = document.querySelector('#wpbc_bfb__inspector');
799 * const api = root.__wpbc_collapsible_instance; // set by auto-init
800 *
801 * api.open_by_heading('Validation'); // open by heading text
802 * api.open_by_index(0); // open the first group
803 *
804 * -- 5.Listen to events (e.g., to persist “open group” state) --
805 * root.addEventListener('wpbc:collapsible:open', (e) => { console.log( e.detail.group ); });
806 * root.addEventListener('wpbc:collapsible:close', (e) => { console.log( e.detail.group ); });
807 *
808 *
809 *
810 * Markup expectations (minimal):
811 * <div class="wpbc_collapsible [wpbc_collapsible--exclusive]">
812 * <section class="wpbc_ui__collapsible_group [is-open]">
813 * <button type="button" class="group__header"> ... </button>
814 * <div class="group__fields"> ... </div>
815 * </section>
816 * ... more <section> ...
817 * </div>
818 *
819 * Notes:
820 * - Add `is-open` to any section you want initially expanded.
821 * - Add `wpbc_collapsible--exclusive` to the container for "open one at a time" behavior.
822 * - Works with your existing BFB markup (classes used there are the defaults).
823 *
824 * Accessibility:
825 * - Sets aria-expanded on .group__header
826 * - Sets aria-hidden + [hidden] on .group__fields
827 * - ArrowUp/ArrowDown move focus between headers; Enter/Space toggles
828 *
829 * Events (bubbles from the <section>):
830 * - 'wpbc:collapsible:open' (detail: { group, root, instance })
831 * - 'wpbc:collapsible:close' (detail: { group, root, instance })
832 *
833 * Public API (instance methods):
834 * - init(), destroy(), refresh()
835 * - expand(group, [exclusive]), collapse(group), toggle(group)
836 * - open_by_index(index), open_by_heading(text)
837 * - is_exclusive(), is_open(group)
838 *
839 * @version 2025-08-26
840 * @since 2025-08-26
841 */
842 // ---------------------------------------------------------------------------------------------------------------------
843 // == File /collapsible_groups.js == Time point: 2025-08-26 14:13
844 // ---------------------------------------------------------------------------------------------------------------------
845 (function (w, d) {
846 'use strict';
847
848 class WPBC_Collapsible_Groups {
849
850 /**
851 * Create a collapsible controller for a container.
852 *
853 * @param {HTMLElement|string} root_el
854 * The container element (or CSS selector) that wraps collapsible groups.
855 * The container usually has the class `.wpbc_collapsible`.
856 * @param {Object} [opts={}]
857 * @param {string} [opts.group_selector='.wpbc_ui__collapsible_group']
858 * Selector for each collapsible group inside the container.
859 * @param {string} [opts.header_selector='.group__header']
860 * Selector for the clickable header inside a group.
861 * @param {string} [opts.fields_selector='.group__fields']
862 * Selector for the content/panel element inside a group.
863 * @param {string} [opts.open_class='is-open']
864 * Class name that indicates the group is open.
865 * @param {boolean} [opts.exclusive=false]
866 * If true, only one group can be open at a time in this container.
867 *
868 * @constructor
869 * @since 2025-08-26
870 */
871 constructor(root_el, opts = {}) {
872 this.root = (typeof root_el === 'string') ? d.querySelector( root_el ) : root_el;
873 this.opts = Object.assign( {
874 group_selector : '.wpbc_ui__collapsible_group',
875 header_selector: '.group__header',
876 fields_selector: '.group__fields,.group__content',
877 open_class : 'is-open',
878 exclusive : false
879 }, opts );
880
881 // Bound handlers (for add/removeEventListener symmetry).
882 /** @private */
883 this._on_click = this._on_click.bind( this );
884 /** @private */
885 this._on_keydown = this._on_keydown.bind( this );
886
887 /** @type {HTMLElement[]} @private */
888 this._groups = [];
889 /** @type {MutationObserver|null} @private */
890 this._observer = null;
891 }
892
893 /**
894 * Initialize the controller: cache groups, attach listeners, set ARIA,
895 * and start observing DOM changes inside the container.
896 *
897 * @returns {WPBC_Collapsible_Groups} The instance (chainable).
898 * @listens click
899 * @listens keydown
900 * @since 2025-08-26
901 */
902 init() {
903 if ( !this.root ) {
904 return this;
905 }
906 this._groups = Array.prototype.slice.call(
907 this.root.querySelectorAll( this.opts.group_selector )
908 );
909 this.root.addEventListener( 'click', this._on_click, false );
910 this.root.addEventListener( 'keydown', this._on_keydown, false );
911
912 // Observe dynamic inserts/removals (Inspector re-renders).
913 this._observer = new MutationObserver( () => {
914 this.refresh();
915 } );
916 this._observer.observe( this.root, { childList: true, subtree: true } );
917
918 this._sync_all_aria();
919 return this;
920 }
921
922 /**
923 * Tear down the controller: detach listeners, stop the observer,
924 * and drop internal references.
925 *
926 * @returns {void}
927 * @since 2025-08-26
928 */
929 destroy() {
930 if ( !this.root ) {
931 return;
932 }
933 this.root.removeEventListener( 'click', this._on_click, false );
934 this.root.removeEventListener( 'keydown', this._on_keydown, false );
935 if ( this._observer ) {
936 this._observer.disconnect();
937 this._observer = null;
938 }
939 this._groups = [];
940 }
941
942 /**
943 * Re-scan the DOM for current groups and re-apply ARIA to all of them.
944 * Useful after dynamic (re)renders.
945 *
946 * @returns {void}
947 * @since 2025-08-26
948 */
949 refresh() {
950 if ( !this.root ) {
951 return;
952 }
953 this._groups = Array.prototype.slice.call(
954 this.root.querySelectorAll( this.opts.group_selector )
955 );
956 this._sync_all_aria();
957 }
958
959 /**
960 * Check whether the container is in exclusive (accordion) mode.
961 *
962 * Order of precedence:
963 * 1) Explicit option `opts.exclusive`
964 * 2) Container has class `.wpbc_collapsible--exclusive`
965 * 3) Container matches `[data-wpbc-accordion="exclusive"]`
966 *
967 * @returns {boolean} True if exclusive mode is active.
968 * @since 2025-08-26
969 */
970 is_exclusive() {
971 return !!(
972 this.opts.exclusive ||
973 this.root.classList.contains( 'wpbc_collapsible--exclusive' ) ||
974 this.root.matches( '[data-wpbc-accordion="exclusive"]' )
975 );
976 }
977
978 /**
979 * Determine whether a specific group is open.
980 *
981 * @param {HTMLElement} group The group element to test.
982 * @returns {boolean} True if the group is currently open.
983 * @since 2025-08-26
984 */
985 is_open(group) {
986 return group.classList.contains( this.opts.open_class );
987 }
988
989 /**
990 * Open a group. Honors exclusive mode by collapsing all sibling groups
991 * (queried from the live DOM at call-time).
992 *
993 * @param {HTMLElement} group The group element to open.
994 * @param {boolean} [exclusive]
995 * If provided, overrides container mode for this action only.
996 * @returns {void}
997 * @fires CustomEvent#wpbc:collapsible:open
998 * @since 2025-08-26
999 */
1000 expand(group, exclusive) {
1001 if ( !group ) {
1002 return;
1003 }
1004 const do_exclusive = (typeof exclusive === 'boolean') ? exclusive : this.is_exclusive();
1005 if ( do_exclusive ) {
1006 // Always use the live DOM, not the cached list.
1007 Array.prototype.forEach.call(
1008 this.root.querySelectorAll( this.opts.group_selector ),
1009 (g) => {
1010 if ( g !== group ) {
1011 this._set_open( g, false );
1012 }
1013 }
1014 );
1015 }
1016 this._set_open( group, true );
1017 }
1018
1019 /**
1020 * Close a group.
1021 *
1022 * @param {HTMLElement} group The group element to close.
1023 * @returns {void}
1024 * @fires CustomEvent#wpbc:collapsible:close
1025 * @since 2025-08-26
1026 */
1027 collapse(group) {
1028 if ( !group ) {
1029 return;
1030 }
1031 this._set_open( group, false );
1032 }
1033
1034 /**
1035 * Toggle a group's open/closed state.
1036 *
1037 * @param {HTMLElement} group The group element to toggle.
1038 * @returns {void}
1039 * @since 2025-08-26
1040 */
1041 toggle(group) {
1042 if ( !group ) {
1043 return;
1044 }
1045 this[this.is_open( group ) ? 'collapse' : 'expand']( group );
1046 }
1047
1048 /**
1049 * Open a group by its index within the container (0-based).
1050 *
1051 * @param {number} index Zero-based index of the group.
1052 * @returns {void}
1053 * @since 2025-08-26
1054 */
1055 open_by_index(index) {
1056 const group = this._groups[index];
1057 if ( group ) {
1058 this.expand( group );
1059 }
1060 }
1061
1062 /**
1063 * Open a group by matching text contained within the <h3> inside the header.
1064 * The comparison is case-insensitive and substring-based.
1065 *
1066 * @param {string} text Text to match against the heading contents.
1067 * @returns {void}
1068 * @since 2025-08-26
1069 */
1070 open_by_heading(text) {
1071 if ( !text ) {
1072 return;
1073 }
1074 const t = String( text ).toLowerCase();
1075 const match = this._groups.find( (g) => {
1076 const h = g.querySelector( this.opts.header_selector + ' h3' );
1077 return h && h.textContent.toLowerCase().indexOf( t ) !== -1;
1078 } );
1079 if ( match ) {
1080 this.expand( match );
1081 }
1082 }
1083
1084 // -------------------------------------------------------------------------------------------------------------
1085 // Internal
1086 // -------------------------------------------------------------------------------------------------------------
1087
1088 /**
1089 * Delegated click handler for headers.
1090 *
1091 * @private
1092 * @param {MouseEvent} ev The click event.
1093 * @returns {void}
1094 * @since 2025-08-26
1095 */
1096 _on_click(ev) {
1097 const btn = ev.target.closest( this.opts.header_selector );
1098 if ( !btn || !this.root.contains( btn ) ) {
1099 return;
1100 }
1101 ev.preventDefault();
1102 ev.stopPropagation();
1103 const group = btn.closest( this.opts.group_selector );
1104 if ( group ) {
1105 this.toggle( group );
1106 }
1107 }
1108
1109 /**
1110 * Keyboard handler for header interactions and roving focus:
1111 * - Enter/Space toggles the active group.
1112 * - ArrowUp/ArrowDown moves focus between group headers.
1113 *
1114 * @private
1115 * @param {KeyboardEvent} ev The keyboard event.
1116 * @returns {void}
1117 * @since 2025-08-26
1118 */
1119 _on_keydown(ev) {
1120 const btn = ev.target.closest( this.opts.header_selector );
1121 if ( !btn ) {
1122 return;
1123 }
1124
1125 const key = ev.key;
1126
1127 // Toggle on Enter / Space.
1128 if ( key === 'Enter' || key === ' ' ) {
1129 ev.preventDefault();
1130 const group = btn.closest( this.opts.group_selector );
1131 if ( group ) {
1132 this.toggle( group );
1133 }
1134 return;
1135 }
1136
1137 // Move focus with ArrowUp/ArrowDown between headers in this container.
1138 if ( key === 'ArrowUp' || key === 'ArrowDown' ) {
1139 ev.preventDefault();
1140 const headers = Array.prototype.map.call(
1141 this.root.querySelectorAll( this.opts.group_selector ),
1142 (g) => g.querySelector( this.opts.header_selector )
1143 ).filter( Boolean );
1144 const idx = headers.indexOf( btn );
1145 if ( idx !== -1 ) {
1146 const next_idx = (key === 'ArrowDown')
1147 ? Math.min( headers.length - 1, idx + 1 )
1148 : Math.max( 0, idx - 1 );
1149 headers[next_idx].focus();
1150 }
1151 }
1152 }
1153
1154 /**
1155 * Apply ARIA synchronization to all known groups based on their open state.
1156 *
1157 * @private
1158 * @returns {void}
1159 * @since 2025-08-26
1160 */
1161 _sync_all_aria() {
1162 this._groups.forEach( (g) => this._sync_group_aria( g ) );
1163 }
1164
1165 /**
1166 * Sync ARIA attributes and visibility on a single group.
1167 *
1168 * @private
1169 * @param {HTMLElement} group The group element to sync.
1170 * @returns {void}
1171 * @since 2025-08-26
1172 */
1173 _sync_group_aria(group) {
1174 const is_open = this.is_open( group );
1175 const header = group.querySelector( this.opts.header_selector );
1176 // Only direct children that match.
1177 const panels = Array.prototype.filter.call( group.children, (el) => el.matches( this.opts.fields_selector ) );
1178
1179 // Header ARIA.
1180 if ( header ) {
1181 header.setAttribute( 'role', 'button' );
1182 header.setAttribute( 'aria-expanded', is_open ? 'true' : 'false' );
1183
1184 if ( panels.length ) {
1185 // Ensure each panel has an id; then wire aria-controls with space-separated ids.
1186 const ids = panels.map( (p) => {
1187 if ( !p.id ) p.id = this._generate_id( 'wpbc_collapsible_panel' );
1188 return p.id;
1189 } );
1190 header.setAttribute( 'aria-controls', ids.join( ' ' ) );
1191 }
1192 }
1193
1194 // (3) Panels ARIA + visibility.
1195 panels.forEach( (p) => {
1196 p.hidden = !is_open; // actual visibility.
1197 p.setAttribute( 'aria-hidden', is_open ? 'false' : 'true' ); // ARIA.
1198 } );
1199 }
1200
1201 /**
1202 * Internal state change: set a group's open/closed state, sync ARIA,
1203 * manage focus on collapse, and emit a custom event.
1204 *
1205 * @private
1206 * @param {HTMLElement} group The group element to mutate.
1207 * @param {boolean} open Whether the group should be open.
1208 * @returns {void}
1209 * @fires CustomEvent#wpbc:collapsible:open
1210 * @fires CustomEvent#wpbc:collapsible:close
1211 * @since 2025-08-26
1212 */
1213 _set_open(group, open) {
1214 if ( !open && group.contains( document.activeElement ) ) {
1215 const header = group.querySelector( this.opts.header_selector );
1216 header && header.focus();
1217 }
1218 group.classList.toggle( this.opts.open_class, open );
1219 this._sync_group_aria( group );
1220 const ev_name = open ? 'wpbc:collapsible:open' : 'wpbc:collapsible:close';
1221 group.dispatchEvent( new CustomEvent( ev_name, {
1222 bubbles: true,
1223 detail : { group, root: this.root, instance: this }
1224 } ) );
1225 }
1226
1227 /**
1228 * Generate a unique DOM id with the specified prefix.
1229 *
1230 * @private
1231 * @param {string} prefix The id prefix to use.
1232 * @returns {string} A unique element id not present in the document.
1233 * @since 2025-08-26
1234 */
1235 _generate_id(prefix) {
1236 let i = 1;
1237 let id;
1238 do {
1239 id = prefix + '_' + (i++);
1240 }
1241 while ( d.getElementById( id ) );
1242 return id;
1243 }
1244 }
1245
1246 /**
1247 * Auto-initialize collapsible controllers on the page.
1248 * Finds top-level `.wpbc_collapsible` containers (ignoring nested ones),
1249 * and instantiates {@link WPBC_Collapsible_Groups} on each.
1250 *
1251 * @function WPBC_Collapsible_AutoInit
1252 * @returns {void}
1253 * @since 2025-08-26
1254 * @example
1255 * // Runs automatically on DOMContentLoaded; can also be called manually:
1256 * WPBC_Collapsible_AutoInit();
1257 */
1258 function wpbc_collapsible__auto_init() {
1259 var ROOT = '.wpbc_collapsible';
1260 var nodes = Array.prototype.slice.call( d.querySelectorAll( ROOT ) )
1261 .filter( function (n) {
1262 return !n.parentElement || !n.parentElement.closest( ROOT );
1263 } );
1264
1265 nodes.forEach( function (node) {
1266 if ( node.__wpbc_collapsible_instance ) {
1267 return;
1268 }
1269 var exclusive = node.classList.contains( 'wpbc_collapsible--exclusive' ) || node.matches( '[data-wpbc-accordion="exclusive"]' );
1270
1271 node.__wpbc_collapsible_instance = new WPBC_Collapsible_Groups( node, { exclusive } ).init();
1272 } );
1273 }
1274
1275 // Export to global for manual control if needed.
1276 w.WPBC_Collapsible_Groups = WPBC_Collapsible_Groups;
1277 w.WPBC_Collapsible_AutoInit = wpbc_collapsible__auto_init;
1278
1279 // DOM-ready auto init.
1280 if ( d.readyState === 'loading' ) {
1281 d.addEventListener( 'DOMContentLoaded', wpbc_collapsible__auto_init, { once: true } );
1282 } else {
1283 wpbc_collapsible__auto_init();
1284 }
1285 })( window, document );
1286
1287 /* globals window, document */
1288 /**
1289 * WPBC Slider Length Groups
1290 *
1291 * Universal, dependency-free controller that keeps a "length" control in sync:
1292 * - number input (data-wpbc_slider_len_value)
1293 * - unit select (data-wpbc_slider_len_unit)
1294 * - range slider (data-wpbc_slider_len_range)
1295 * - writer input (data-wpbc_slider_len_writer) [optional but recommended]
1296 *
1297 * The "writer" stores the combined value like: "100%", "420px", "12.5rem".
1298 * When number/unit/slider change -> writer updates and emits 'input' (bubbles).
1299 * When writer is changed externally (apply-from-JSON, etc) -> UI updates.
1300 *
1301 * Markup expectations (minimal):
1302 * <div class="wpbc_slider_len_group"
1303 * data-wpbc_slider_len_bounds_map='{"%":{"min":30,"max":100,"step":1},"px":{"min":300,"max":2000,"step":10}}'
1304 * data-wpbc_slider_len_default_unit="%">
1305 * <input type="number" data-wpbc_slider_len_value>
1306 * <select data-wpbc_slider_len_unit>...</select>
1307 * <input type="range" data-wpbc_slider_len_range>
1308 * <input type="text" data-wpbc_slider_len_writer style="display:none;">
1309 * </div>
1310 *
1311 * Performance notes:
1312 * - MutationObserver is DISABLED by default (prevents performance issues).
1313 * - If your UI re-renders and inserts new groups dynamically, call:
1314 * WPBC_Slider_Len_AutoInit(); OR instance.refresh();
1315 * Or enable observer via: new WPBC_Slider_Len_Groups(root, { enable_observer:true }).init();
1316 *
1317 * Public API (instance methods):
1318 * - init(), destroy(), refresh()
1319 *
1320 * @version 2026-01-25
1321 * @since 2026-01-25
1322 * @file ../includes/__js/admin/slider_groups/wpbc_len_groups.js
1323 */
1324 (function (w, d) {
1325 'use strict';
1326
1327 // -------------------------------------------------------------------------------------------------
1328 // Helpers
1329 // -------------------------------------------------------------------------------------------------
1330 function clamp_num(v, min, max) {
1331 if (typeof min === 'number' && !isNaN(min)) v = Math.max(min, v);
1332 if (typeof max === 'number' && !isNaN(max)) v = Math.min(max, v);
1333 return v;
1334 }
1335
1336 function parse_float(v) {
1337 var n = parseFloat(v);
1338 return isNaN(n) ? null : n;
1339 }
1340
1341 function safe_json_parse(str) {
1342 try {
1343 return JSON.parse(str);
1344 } catch (e) {
1345 return null;
1346 }
1347 }
1348
1349 function parse_len_combined(raw, default_unit) {
1350 var s = (raw == null) ? '' : String(raw).trim();
1351 if (!s) return { num: '', unit: default_unit || '%' };
1352
1353 var m = s.match(/^\s*([\-]?\d+(?:\.\d+)?)\s*([a-z%]*)\s*$/i);
1354 if (!m) {
1355 // If it's not parseable, treat as number and keep default unit.
1356 return { num: s, unit: default_unit || '%' };
1357 }
1358
1359 var num = m[1] ? String(m[1]) : '';
1360 var unit = m[2] ? String(m[2]) : '';
1361 if (!unit) unit = default_unit || '%';
1362
1363 return { num: num, unit: unit };
1364 }
1365
1366 function build_combined(num, unit) {
1367 if (num == null || String(num).trim() === '') return '';
1368 return String(num) + String(unit || '');
1369 }
1370
1371 function emit_input(el) {
1372 if (!el) return;
1373 el.dispatchEvent(new Event('input', { bubbles: true }));
1374 }
1375
1376 // -------------------------------------------------------------------------------------------------
1377 // Controller
1378 // -------------------------------------------------------------------------------------------------
1379 class WPBC_Slider_Len_Groups {
1380
1381 /**
1382 * @param {HTMLElement|string} root_el Container (or selector). If omitted, uses document.
1383 * @param {Object} [opts={}]
1384 */
1385 constructor(root_el, opts) {
1386 this.root = root_el
1387 ? ((typeof root_el === 'string') ? d.querySelector(root_el) : root_el)
1388 : d;
1389
1390 this.opts = Object.assign({
1391 // Strict selectors (NO backward compatibility).
1392 group_selector : '.wpbc_slider_len_group',
1393 value_selector : '[data-wpbc_slider_len_value]',
1394 unit_selector : '[data-wpbc_slider_len_unit]',
1395 range_selector : '[data-wpbc_slider_len_range]',
1396 writer_selector : '[data-wpbc_slider_len_writer]',
1397
1398 default_unit : '%',
1399
1400 fallback_bounds : {
1401 'px' : { min: 0, max: 512, step: 1 },
1402 '%' : { min: 0, max: 100, step: 1 },
1403 'rem': { min: 0, max: 10, step: 0.1 },
1404 'em' : { min: 0, max: 10, step: 0.1 }
1405 },
1406
1407 // Disabled by default for performance.
1408 enable_observer : false,
1409 observer_debounce_ms: 150
1410 }, opts || {});
1411
1412 this._on_input = this._on_input.bind(this);
1413 this._on_change = this._on_change.bind(this);
1414
1415 this._bounds_cache = new WeakMap(); // group -> bounds_map_object
1416 this._observer = null;
1417 this._refresh_tmr = null;
1418 }
1419
1420 init() {
1421 if (!this.root) return this;
1422
1423 this.root.addEventListener('input', this._on_input, true);
1424 this.root.addEventListener('change', this._on_change, true);
1425
1426 if (this.opts.enable_observer && w.MutationObserver) {
1427 this._observer = new MutationObserver(() => { this._debounced_refresh(); });
1428 this._observer.observe(this.root === d ? d.documentElement : this.root, { childList: true, subtree: true });
1429 }
1430
1431 this.refresh();
1432 return this;
1433 }
1434
1435 destroy() {
1436 if (!this.root) return;
1437
1438 this.root.removeEventListener('input', this._on_input, true);
1439 this.root.removeEventListener('change', this._on_change, true);
1440
1441 if (this._observer) {
1442 this._observer.disconnect();
1443 this._observer = null;
1444 }
1445
1446 if (this._refresh_tmr) {
1447 clearTimeout(this._refresh_tmr);
1448 this._refresh_tmr = null;
1449 }
1450 }
1451
1452 refresh() {
1453 if (!this.root) return;
1454
1455 var scope = (this.root === d ? d : this.root);
1456 var groups = Array.prototype.slice.call(scope.querySelectorAll(this.opts.group_selector));
1457
1458 for (var i = 0; i < groups.length; i++) {
1459 this._sync_group_from_writer(groups[i]);
1460 this._apply_bounds_for_current_unit(groups[i]);
1461 }
1462 }
1463
1464 // -------------------------------------------------------------------------------------------------
1465 // Internal
1466 // -------------------------------------------------------------------------------------------------
1467 _debounced_refresh() {
1468 if (this._refresh_tmr) clearTimeout(this._refresh_tmr);
1469 this._refresh_tmr = setTimeout(() => {
1470 this._refresh_tmr = null;
1471 this.refresh();
1472 }, Number(this.opts.observer_debounce_ms) || 0);
1473 }
1474
1475 _find_group(el) {
1476 return (el && el.closest) ? el.closest(this.opts.group_selector) : null;
1477 }
1478
1479 _get_parts(group) {
1480 if (!group) return null;
1481 return {
1482 group : group,
1483 num : group.querySelector(this.opts.value_selector),
1484 unit : group.querySelector(this.opts.unit_selector),
1485 range : group.querySelector(this.opts.range_selector),
1486 writer: group.querySelector(this.opts.writer_selector)
1487 };
1488 }
1489
1490 _get_default_unit(group) {
1491 var du = (group && group.getAttribute)
1492 ? group.getAttribute('data-wpbc_slider_len_default_unit')
1493 : '';
1494 return du ? String(du) : this.opts.default_unit;
1495 }
1496
1497 _get_bounds_map(group) {
1498 if (!group) return null;
1499 if (this._bounds_cache.has(group)) {
1500 return this._bounds_cache.get(group);
1501 }
1502
1503 var raw = group.getAttribute('data-wpbc_slider_len_bounds_map');
1504 var map = raw ? safe_json_parse(raw) : null;
1505 if (!map || typeof map !== 'object') map = null;
1506
1507 this._bounds_cache.set(group, map);
1508 return map;
1509 }
1510
1511 _get_bounds_for_unit(group, unit) {
1512 var map = this._get_bounds_map(group);
1513 if (map && unit && map[unit]) {
1514 return map[unit];
1515 }
1516 return this.opts.fallback_bounds[unit] || this.opts.fallback_bounds['px'];
1517 }
1518
1519 _apply_bounds(parts, bounds) {
1520 if (!parts || !bounds) return;
1521
1522 var min = (bounds.min != null) ? Number(bounds.min) : null;
1523 var max = (bounds.max != null) ? Number(bounds.max) : null;
1524 var step = (bounds.step != null) ? Number(bounds.step) : null;
1525
1526 if (parts.range) {
1527 if (!isNaN(min)) parts.range.min = String(min);
1528 if (!isNaN(max)) parts.range.max = String(max);
1529 if (!isNaN(step)) parts.range.step = String(step);
1530 }
1531 if (parts.num) {
1532 if (!isNaN(min)) parts.num.min = String(min);
1533 if (!isNaN(max)) parts.num.max = String(max);
1534 if (!isNaN(step)) parts.num.step = String(step);
1535 }
1536 }
1537
1538 _apply_bounds_for_current_unit(group) {
1539 var parts = this._get_parts(group);
1540 if (!parts || !parts.unit) return;
1541
1542 var unit = parts.unit.value || this._get_default_unit(group);
1543 var b = this._get_bounds_for_unit(group, unit);
1544
1545 this._apply_bounds(parts, b);
1546
1547 // Clamp current value to new bounds.
1548 var v = parse_float(parts.num && parts.num.value ? parts.num.value : (parts.range ? parts.range.value : ''));
1549 if (v == null) return;
1550
1551 var min = (b && b.min != null) ? Number(b.min) : null;
1552 var max = (b && b.max != null) ? Number(b.max) : null;
1553 v = clamp_num(v, isNaN(min) ? null : min, isNaN(max) ? null : max);
1554
1555 if (parts.num) parts.num.value = String(v);
1556 if (parts.range) parts.range.value = String(v);
1557
1558 this._write_combined(parts, String(v), unit, /*emit*/ false);
1559 }
1560
1561 _write_combined(parts, num, unit, emit) {
1562 if (!parts) return;
1563
1564 var combined = build_combined(num, unit);
1565
1566 if (parts.writer) {
1567 // Avoid recursion: mark as internal write.
1568 parts.writer.__wpbc_slider_len_internal = true;
1569 parts.writer.value = combined;
1570 if (emit) emit_input(parts.writer);
1571 parts.writer.__wpbc_slider_len_internal = false;
1572 } else if (parts.num) {
1573 // If writer is missing, at least notify via number input.
1574 if (emit) emit_input(parts.num);
1575 }
1576 }
1577
1578 _sync_group_from_writer(group) {
1579 var parts = this._get_parts(group);
1580 if (!parts || !parts.writer) return;
1581
1582 var raw = String(parts.writer.value || '').trim();
1583 if (!raw) return;
1584
1585 var du = this._get_default_unit(group);
1586 var p = parse_len_combined(raw, du);
1587
1588 if (parts.unit) parts.unit.value = p.unit;
1589 if (parts.num) parts.num.value = p.num;
1590 if (parts.range) parts.range.value = p.num;
1591 }
1592
1593 _on_input(ev) {
1594 var t = ev.target;
1595 if (!t) return;
1596
1597 var group = this._find_group(t);
1598 if (!group) return;
1599
1600 var parts = this._get_parts(group);
1601 if (!parts) return;
1602
1603 // Writer changed externally -> update UI.
1604 if (parts.writer && t === parts.writer) {
1605 if (t.__wpbc_slider_len_internal) return;
1606 this._sync_group_from_writer(group);
1607 this._apply_bounds_for_current_unit(group);
1608 return;
1609 }
1610
1611 // Slider moved -> update number + writer.
1612 if (t.matches && t.matches(this.opts.range_selector)) {
1613 if (parts.num) parts.num.value = t.value;
1614
1615 var unit = (parts.unit && parts.unit.value) ? parts.unit.value : this._get_default_unit(group);
1616 this._write_combined(parts, t.value, unit, /*emit*/ true);
1617 return;
1618 }
1619
1620 // Number typed -> update slider + writer (clamp if slider has bounds).
1621 if (t.matches && t.matches(this.opts.value_selector)) {
1622 var v = parse_float(t.value);
1623
1624 if (v != null && parts.range) {
1625 var rmin = Number(parts.range.min);
1626 var rmax = Number(parts.range.max);
1627 v = clamp_num(v, isNaN(rmin) ? null : rmin, isNaN(rmax) ? null : rmax);
1628
1629 parts.range.value = String(v);
1630 if (String(v) !== t.value) t.value = String(v);
1631 }
1632
1633 var unit2 = (parts.unit && parts.unit.value) ? parts.unit.value : this._get_default_unit(group);
1634 this._write_combined(parts, t.value, unit2, /*emit*/ true);
1635 }
1636 }
1637
1638 _on_change(ev) {
1639 var t = ev.target;
1640 if (!t) return;
1641
1642 var group = this._find_group(t);
1643 if (!group) return;
1644
1645 var parts = this._get_parts(group);
1646 if (!parts) return;
1647
1648 // Unit changed -> update bounds + writer.
1649 if (t.matches && t.matches(this.opts.unit_selector)) {
1650 this._apply_bounds_for_current_unit(group);
1651
1652 var num = parts.num ? parts.num.value : (parts.range ? parts.range.value : '');
1653 var unit = t.value || this._get_default_unit(group);
1654 this._write_combined(parts, num, unit, /*emit*/ true);
1655 }
1656 }
1657 }
1658
1659 // -------------------------------------------------------------------------------------------------
1660 // Auto-init
1661 // -------------------------------------------------------------------------------------------------
1662 function wpbc_slider_len_groups__auto_init() {
1663 var ROOT = '.wpbc_slider_len_groups';
1664 var nodes = Array.prototype.slice.call(d.querySelectorAll(ROOT))
1665 .filter(function (n) { return !n.parentElement || !n.parentElement.closest(ROOT); });
1666
1667 // If no explicit containers, install a single document-root instance.
1668 if (!nodes.length) {
1669 if (!d.__wpbc_slider_len_groups_global_instance) {
1670 d.__wpbc_slider_len_groups_global_instance = new WPBC_Slider_Len_Groups(d).init();
1671 }
1672 return;
1673 }
1674
1675 nodes.forEach(function (node) {
1676 if (node.__wpbc_slider_len_groups_instance) return;
1677 node.__wpbc_slider_len_groups_instance = new WPBC_Slider_Len_Groups(node).init();
1678 });
1679 }
1680
1681 // Export globals (manual control if needed).
1682 w.WPBC_Slider_Len_Groups = WPBC_Slider_Len_Groups;
1683 w.WPBC_Slider_Len_AutoInit = wpbc_slider_len_groups__auto_init;
1684
1685 // DOM-ready auto init.
1686 if (d.readyState === 'loading') {
1687 d.addEventListener('DOMContentLoaded', wpbc_slider_len_groups__auto_init, { once: true });
1688 } else {
1689 wpbc_slider_len_groups__auto_init();
1690 }
1691
1692 })(window, document);
1693
1694 /* globals window, document */
1695 /**
1696 * WPBC Slider Range Groups
1697 *
1698 * Universal, dependency-free controller that keeps a "range + number" pair in sync:
1699 * - number input (data-wpbc_slider_range_value)
1700 * - range slider (data-wpbc_slider_range_range)
1701 * - writer input (data-wpbc_slider_range_writer) [optional]
1702 *
1703 * If writer exists: number/slider update writer and emit 'input' on writer (bubbles).
1704 * If writer is missing: emits 'input' on the number input.
1705 * If writer changes externally: updates number/slider.
1706 *
1707 * Markup expectations (minimal):
1708 * <div class="wpbc_slider_range_group">
1709 * <input type="number" data-wpbc_slider_range_value>
1710 * <input type="range" data-wpbc_slider_range_range>
1711 * <!-- optional -->
1712 * <input type="text" data-wpbc_slider_range_writer style="display:none;">
1713 * </div>
1714 *
1715 * Performance notes:
1716 * - MutationObserver is DISABLED by default.
1717 * - If your UI re-renders and inserts new groups dynamically, call:
1718 * WPBC_Slider_Range_AutoInit(); OR instance.refresh();
1719 * Or enable observer via: new WPBC_Slider_Range_Groups(root, { enable_observer:true }).init();
1720 *
1721 * Public API (instance methods):
1722 * - init(), destroy(), refresh()
1723 *
1724 * @version 2026-01-25
1725 * @since 2026-01-25
1726 * @file ../includes/__js/admin/slider_groups/wpbc_range_groups.js
1727 */
1728 (function (w, d) {
1729 'use strict';
1730
1731 // -------------------------------------------------------------------------------------------------
1732 // Helpers
1733 // -------------------------------------------------------------------------------------------------
1734 function clamp_num(v, min, max) {
1735 if (typeof min === 'number' && !isNaN(min)) v = Math.max(min, v);
1736 if (typeof max === 'number' && !isNaN(max)) v = Math.min(max, v);
1737 return v;
1738 }
1739
1740 function parse_float(v) {
1741 var n = parseFloat(v);
1742 return isNaN(n) ? null : n;
1743 }
1744
1745 function emit_input(el) {
1746 if (!el) return;
1747 el.dispatchEvent(new Event('input', { bubbles: true }));
1748 }
1749
1750 // -------------------------------------------------------------------------------------------------
1751 // Controller
1752 // -------------------------------------------------------------------------------------------------
1753 class WPBC_Slider_Range_Groups {
1754
1755 /**
1756 * @param {HTMLElement|string} root_el Container (or selector). If omitted, uses document.
1757 * @param {Object} [opts={}]
1758 */
1759 constructor(root_el, opts) {
1760 this.root = root_el
1761 ? ((typeof root_el === 'string') ? d.querySelector(root_el) : root_el)
1762 : d;
1763
1764 this.opts = Object.assign({
1765 // Strict selectors (NO backward compatibility).
1766 group_selector : '.wpbc_slider_range_group',
1767 value_selector : '[data-wpbc_slider_range_value]',
1768 range_selector : '[data-wpbc_slider_range_range]',
1769 writer_selector : '[data-wpbc_slider_range_writer]',
1770
1771 // Disabled by default for performance.
1772 enable_observer : false,
1773 observer_debounce_ms: 150
1774 }, opts || {});
1775
1776 this._on_input = this._on_input.bind(this);
1777 this._on_change = this._on_change.bind(this);
1778
1779 this._observer = null;
1780 this._refresh_tmr = null;
1781 }
1782
1783 init() {
1784 if (!this.root) return this;
1785
1786 this.root.addEventListener('input', this._on_input, true);
1787 this.root.addEventListener('change', this._on_change, true);
1788
1789 if (this.opts.enable_observer && w.MutationObserver) {
1790 this._observer = new MutationObserver(() => { this._debounced_refresh(); });
1791 this._observer.observe(this.root === d ? d.documentElement : this.root, { childList: true, subtree: true });
1792 }
1793
1794 this.refresh();
1795 return this;
1796 }
1797
1798 destroy() {
1799 if (!this.root) return;
1800
1801 this.root.removeEventListener('input', this._on_input, true);
1802 this.root.removeEventListener('change', this._on_change, true);
1803
1804 if (this._observer) {
1805 this._observer.disconnect();
1806 this._observer = null;
1807 }
1808
1809 if (this._refresh_tmr) {
1810 clearTimeout(this._refresh_tmr);
1811 this._refresh_tmr = null;
1812 }
1813 }
1814
1815 refresh() {
1816 if (!this.root) return;
1817
1818 var scope = (this.root === d ? d : this.root);
1819 var groups = Array.prototype.slice.call(scope.querySelectorAll(this.opts.group_selector));
1820
1821 for (var i = 0; i < groups.length; i++) {
1822 this._sync_from_writer(groups[i]);
1823 this._clamp_to_range(groups[i]);
1824 }
1825 }
1826
1827 // -------------------------------------------------------------------------------------------------
1828 // Internal
1829 // -------------------------------------------------------------------------------------------------
1830 _debounced_refresh() {
1831 if (this._refresh_tmr) clearTimeout(this._refresh_tmr);
1832 this._refresh_tmr = setTimeout(() => {
1833 this._refresh_tmr = null;
1834 this.refresh();
1835 }, Number(this.opts.observer_debounce_ms) || 0);
1836 }
1837
1838 _find_group(el) {
1839 return (el && el.closest) ? el.closest(this.opts.group_selector) : null;
1840 }
1841
1842 _get_parts(group) {
1843 if (!group) return null;
1844 return {
1845 group : group,
1846 num : group.querySelector(this.opts.value_selector),
1847 range : group.querySelector(this.opts.range_selector),
1848 writer: group.querySelector(this.opts.writer_selector)
1849 };
1850 }
1851
1852 _write(parts, value, emit) {
1853 if (!parts) return;
1854
1855 if (parts.writer) {
1856 parts.writer.__wpbc_slider_range_internal = true;
1857 parts.writer.value = String(value);
1858 if (emit) emit_input(parts.writer);
1859 parts.writer.__wpbc_slider_range_internal = false;
1860 } else if (parts.num) {
1861 // If writer is missing, at least notify via number input.
1862 if (emit) emit_input(parts.num);
1863 }
1864 }
1865
1866 _sync_from_writer(group) {
1867 var parts = this._get_parts(group);
1868 if (!parts || !parts.writer) return;
1869
1870 var raw = String(parts.writer.value || '').trim();
1871 if (!raw) return;
1872
1873 if (parts.num) parts.num.value = raw;
1874 if (parts.range) parts.range.value = raw;
1875 }
1876
1877 _clamp_to_range(group) {
1878 var parts = this._get_parts(group);
1879 if (!parts || !parts.range || !parts.num) return;
1880
1881 var v = parse_float(parts.num.value);
1882 if (v == null) return;
1883
1884 var min = Number(parts.range.min);
1885 var max = Number(parts.range.max);
1886 var vv = clamp_num(v, isNaN(min) ? null : min, isNaN(max) ? null : max);
1887
1888 if (String(vv) !== parts.num.value) parts.num.value = String(vv);
1889 parts.range.value = String(vv);
1890 }
1891
1892 _on_input(ev) {
1893 var t = ev.target;
1894 if (!t) return;
1895
1896 var group = this._find_group(t);
1897 if (!group) return;
1898
1899 var parts = this._get_parts(group);
1900 if (!parts) return;
1901
1902 // Writer changed externally -> update UI.
1903 if (parts.writer && t === parts.writer) {
1904 if (t.__wpbc_slider_range_internal) return;
1905 this._sync_from_writer(group);
1906 this._clamp_to_range(group);
1907 return;
1908 }
1909
1910 // Range moved -> update number + writer.
1911 if (t.matches && t.matches(this.opts.range_selector)) {
1912 if (parts.num) parts.num.value = t.value;
1913 this._write(parts, t.value, /*emit*/ true);
1914 return;
1915 }
1916
1917 // Number typed -> update range + writer (clamp by slider bounds).
1918 if (t.matches && t.matches(this.opts.value_selector)) {
1919 if (parts.range) {
1920 var v = parse_float(t.value);
1921 if (v != null) {
1922 var min = Number(parts.range.min);
1923 var max = Number(parts.range.max);
1924 v = clamp_num(v, isNaN(min) ? null : min, isNaN(max) ? null : max);
1925
1926 parts.range.value = String(v);
1927 if (String(v) !== t.value) t.value = String(v);
1928 }
1929 }
1930 this._write(parts, t.value, /*emit*/ true);
1931 }
1932 }
1933
1934 _on_change(ev) {
1935 // No special "change" handling needed currently; kept for symmetry/future.
1936 }
1937 }
1938
1939 // -------------------------------------------------------------------------------------------------
1940 // Auto-init
1941 // -------------------------------------------------------------------------------------------------
1942 function wpbc_slider_range_groups__auto_init() {
1943 var ROOT = '.wpbc_slider_range_groups';
1944 var nodes = Array.prototype.slice.call(d.querySelectorAll(ROOT))
1945 .filter(function (n) { return !n.parentElement || !n.parentElement.closest(ROOT); });
1946
1947 if (!nodes.length) {
1948 if (!d.__wpbc_slider_range_groups_global_instance) {
1949 d.__wpbc_slider_range_groups_global_instance = new WPBC_Slider_Range_Groups(d).init();
1950 }
1951 return;
1952 }
1953
1954 nodes.forEach(function (node) {
1955 if (node.__wpbc_slider_range_groups_instance) return;
1956 node.__wpbc_slider_range_groups_instance = new WPBC_Slider_Range_Groups(node).init();
1957 });
1958 }
1959
1960 // Export globals.
1961 w.WPBC_Slider_Range_Groups = WPBC_Slider_Range_Groups;
1962 w.WPBC_Slider_Range_AutoInit = wpbc_slider_range_groups__auto_init;
1963
1964 if (d.readyState === 'loading') {
1965 d.addEventListener('DOMContentLoaded', wpbc_slider_range_groups__auto_init, { once: true });
1966 } else {
1967 wpbc_slider_range_groups__auto_init();
1968 }
1969
1970 })(window, document);
1971
1972 /**
1973 * Booking Calendar — Generic UI Tabs Utility (JS)
1974 *
1975 * Purpose: Lightweight, dependency-free tabs controller for any small tab group in admin UIs.
1976 * - Auto-initializes groups marked with data-wpbc-tabs.
1977 * - Assigns ARIA roles and toggles aria-selected/aria-hidden/tabindex.
1978 * - Supports keyboard navigation (Left/Right/Home/End).
1979 * - Public API: window.wpbc_ui_tabs.{init_on, init_group, set_active}
1980 * - Emits 'wpbc:tabs:change' on the group root when the active tab changes.
1981 *
1982 * Markup contract:
1983 * - Root: [data-wpbc-tabs]
1984 * - Tabs: [data-wpbc-tab-key="K"]
1985 * - Panels: [data-wpbc-tab-panel="K"]
1986 *
1987 * @package Booking Calendar
1988 * @subpackage Admin\UI
1989 * @since 11.0.0
1990 * @version 1.0.0
1991 * @see /includes/__js/admin/ui_tabs/ui_tabs.js
1992 *
1993 *
1994 * How it works:
1995 * - Root node must have [data-wpbc-tabs] attribute (any value).
1996 * - Tab buttons must carry [data-wpbc-tab-key="..."] (unique per group).
1997 * - Panels must carry [data-wpbc-tab-panel="..."] with matching keys.
1998 * - Adds WAI-ARIA roles and aria-selected/hidden wiring.
1999 *
2000 * <div data-wpbc-tabs="column-styles" data-wpbc-tab-active="1" class="wpbc_ui_tabs_root" >
2001 * <!-- Top Tabs -->
2002 * <div data-wpbc-tablist="" role="tablist" class=" wpbc_ui_el__horis_top_bar__wrapper" >
2003 * <div class="wpbc_ui_el__horis_top_bar__content">
2004 * <h2 class="wpbc_ui_el__horis_nav_label">Column:</h2>
2005 *
2006 * <div class="wpbc_ui_el__horis_nav_item wpbc_ui_el__horis_nav_item__1">
2007 * <a
2008 * data-wpbc-tab-key="1"
2009 * aria-selected="true" role="tab" tabindex="0" aria-controls="wpbc_tab_panel_col_1"
2010 *
2011 * href="javascript:void(0);"
2012 * class="wpbc_ui_el__horis_nav_item__a wpbc_ui_el__horis_nav_item__single"
2013 * id="wpbc_tab_col_1"
2014 * title="Column 1"
2015 * ><span class="wpbc_ui_el__horis_nav_title">Title 1</span></a>
2016 * </div>
2017 * ...
2018 * </div>
2019 * </div>
2020 * <!-- Tabs Content -->
2021 * <div class="wpbc_tab__panel group__fields" data-wpbc-tab-panel="1" id="wpbc_tab_panel_col_1" role="tabpanel" aria-labelledby="wpbc_tab_col_1">
2022 * ...
2023 * </div>
2024 * ...
2025 * </div>
2026 *
2027 * Public API:
2028 * - wpbc_ui_tabs.init_on(root_or_selector) // find and init groups within a container
2029 * - wpbc_ui_tabs.init_group(root_el) // init a single group root
2030 * - wpbc_ui_tabs.set_active(root_el, key) // programmatically change active tab
2031 *
2032 * Events:
2033 * - Dispatches CustomEvent 'wpbc:tabs:change' on root when tab changes:
2034 * detail: { active_key: '2', prev_key: '1' }
2035 *
2036 * Switch a local (generic) tabs group to tab 3: var group = document.querySelector('[data-wpbc-tabs="column-styles"]'); if ( group ) { wpbc_ui_tabs.set_active(group, '3'); }
2037 */
2038 (function ( w ) {
2039 'use strict';
2040
2041 if ( w.wpbc_ui_tabs ) {
2042 return;
2043 }
2044
2045 /**
2046 * Internal: toggle active state.
2047 *
2048 * @param {HTMLElement} root_el
2049 * @param {string} key
2050 * @param {boolean} should_emit
2051 */
2052 function set_active_internal( root_el, key, should_emit ) {
2053 var tab_btns = root_el.querySelectorAll( '[data-wpbc-tab-key]' );
2054 var panels = root_el.querySelectorAll( '[data-wpbc-tab-panel]' );
2055
2056 var prev_key = root_el.getAttribute( 'data-wpbc-tab-active' ) || null;
2057 if ( String( prev_key ) === String( key ) ) {
2058 return;
2059 }
2060
2061 // Buttons: aria + class
2062 for ( var i = 0; i < tab_btns.length; i++ ) {
2063 var btn = tab_btns[i];
2064 var b_key = btn.getAttribute( 'data-wpbc-tab-key' );
2065 var is_on = String( b_key ) === String( key );
2066
2067 btn.setAttribute( 'role', 'tab' );
2068 btn.setAttribute( 'aria-selected', is_on ? 'true' : 'false' );
2069 btn.setAttribute( 'tabindex', is_on ? '0' : '-1' );
2070
2071 if ( is_on ) {
2072 btn.classList.add( 'active' );
2073 } else {
2074 btn.classList.remove( 'active' );
2075 }
2076 }
2077
2078 // Panels: aria + visibility
2079 for ( var j = 0; j < panels.length; j++ ) {
2080 var pn = panels[j];
2081 var pkey = pn.getAttribute( 'data-wpbc-tab-panel' );
2082 var show = String( pkey ) === String( key );
2083
2084 pn.setAttribute( 'role', 'tabpanel' );
2085 pn.setAttribute( 'aria-hidden', show ? 'false' : 'true' );
2086 if ( show ) {
2087 pn.removeAttribute( 'hidden' );
2088 } else {
2089 pn.setAttribute( 'hidden', '' );
2090 }
2091 }
2092
2093 root_el.setAttribute( 'data-wpbc-tab-active', String( key ) );
2094
2095 if ( should_emit ) {
2096 try {
2097 var ev = new w.CustomEvent( 'wpbc:tabs:change', {
2098 bubbles : true,
2099 detail : { active_key : String( key ), prev_key : prev_key }
2100 } );
2101 root_el.dispatchEvent( ev );
2102 } catch ( _e ) {}
2103 }
2104 }
2105
2106 /**
2107 * Internal: get ordered keys from buttons.
2108 *
2109 * @param {HTMLElement} root_el
2110 * @returns {string[]}
2111 */
2112 function get_keys( root_el ) {
2113 var list = [];
2114 var btns = root_el.querySelectorAll( '[data-wpbc-tab-key]' );
2115 for ( var i = 0; i < btns.length; i++ ) {
2116 var k = btns[i].getAttribute( 'data-wpbc-tab-key' );
2117 if ( k != null && k !== '' ) {
2118 list.push( String( k ) );
2119 }
2120 }
2121 return list;
2122 }
2123
2124 /**
2125 * Internal: move focus between tabs using keyboard.
2126 *
2127 * @param {HTMLElement} root_el
2128 * @param {number} dir +1 (next) / -1 (prev)
2129 */
2130 function focus_relative( root_el, dir ) {
2131 var keys = get_keys( root_el );
2132 var current = root_el.getAttribute( 'data-wpbc-tab-active' ) || keys[0] || null;
2133 var idx = Math.max( 0, keys.indexOf( String( current ) ) );
2134 var next = keys[ ( idx + ( dir > 0 ? 1 : keys.length - 1 ) ) % keys.length ];
2135
2136 var next_btn = root_el.querySelector( '[data-wpbc-tab-key="' + next + '"]' );
2137 if ( next_btn ) {
2138 next_btn.focus();
2139 set_active_internal( root_el, next, true );
2140 }
2141 }
2142
2143 /**
2144 * Initialize a single tabs group root.
2145 *
2146 * @param {HTMLElement} root_el
2147 */
2148 function init_group( root_el ) {
2149 if ( ! root_el || root_el.__wpbc_tabs_inited ) {
2150 return;
2151 }
2152 root_el.__wpbc_tabs_inited = true;
2153
2154 // Roles
2155 var tablist = root_el.querySelector( '[data-wpbc-tablist]' ) || root_el;
2156 tablist.setAttribute( 'role', 'tablist' );
2157
2158 // Default active: from attribute or first button
2159 var keys = get_keys( root_el );
2160 var def = root_el.getAttribute( 'data-wpbc-tab-active' ) || ( keys[0] || '1' );
2161 set_active_internal( root_el, def, false );
2162
2163 // Clicks
2164 root_el.addEventListener( 'click', function ( e ) {
2165 var btn = e.target.closest ? e.target.closest( '[data-wpbc-tab-key]' ) : null;
2166 if ( ! btn || ! root_el.contains( btn ) ) {
2167 return;
2168 }
2169 e.preventDefault();
2170 var key = btn.getAttribute( 'data-wpbc-tab-key' );
2171 if ( key != null ) {
2172 set_active_internal( root_el, key, true );
2173 }
2174 }, true );
2175
2176 // Keyboard (Left/Right/Home/End)
2177 root_el.addEventListener( 'keydown', function ( e ) {
2178 var tgt = e.target;
2179 if ( ! tgt || ! tgt.hasAttribute || ! tgt.hasAttribute( 'data-wpbc-tab-key' ) ) {
2180 return;
2181 }
2182 switch ( e.key ) {
2183 case 'ArrowLeft':
2184 e.preventDefault(); focus_relative( root_el, -1 ); break;
2185 case 'ArrowRight':
2186 e.preventDefault(); focus_relative( root_el, +1 ); break;
2187 case 'Home':
2188 e.preventDefault(); set_active_internal( root_el, ( get_keys( root_el )[0] || '1' ), true ); break;
2189 case 'End':
2190 e.preventDefault(); var ks = get_keys( root_el ); set_active_internal( root_el, ( ks[ ks.length - 1 ] || '1' ), true ); break;
2191 }
2192 }, true );
2193 }
2194
2195 /**
2196 * Initialize all groups within a container (or document).
2197 *
2198 * @param {HTMLElement|string|null} container
2199 */
2200 function init_on( container ) {
2201 var ctx = container ? ( typeof container === 'string' ? document.querySelector( container ) : container ) : document;
2202 if ( ! ctx ) {
2203 return;
2204 }
2205 var groups = ctx.querySelectorAll( '[data-wpbc-tabs]' );
2206 for ( var i = 0; i < groups.length; i++ ) {
2207 init_group( groups[i] );
2208 }
2209 }
2210
2211 /**
2212 * Programmatically set active tab by key.
2213 *
2214 * @param {HTMLElement} root_el
2215 * @param {string|number} key
2216 */
2217 function set_active( root_el, key ) {
2218 if ( root_el && root_el.hasAttribute && root_el.hasAttribute( 'data-wpbc-tabs' ) ) {
2219 set_active_internal( root_el, String( key ), true );
2220 }
2221 }
2222
2223 // Public API (snake_case)
2224 w.wpbc_ui_tabs = {
2225 init_on : init_on,
2226 init_group : init_group,
2227 set_active : set_active
2228 };
2229
2230 // Auto-init on DOM ready
2231 if ( document.readyState === 'loading' ) {
2232 document.addEventListener( 'DOMContentLoaded', function () { init_on( document ); } );
2233 } else {
2234 init_on( document );
2235 }
2236
2237 })( window );
2238
2239 //# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInVpX2VsZW1lbnRzLmpzIiwidWlfbG9hZGluZ19zcGluLmpzIiwidWlfcmFkaW9fY29udGFpbmVyLmpzIiwidWlfZnVsbF9zY3JlZW5fbW9kZS5qcyIsImdtYWlsX2NoZWNrYm94X3NlbGVjdGlvbi5qcyIsImJvb2tpbmdzX2NoZWNrYm94X3NlbGVjdGlvbi5qcyIsInVpX3NpZGViYXJfbGVmdF9fYWN0aW9ucy5qcyIsImNvcHlfdGV4dF90b19jbGlwYnJkLmpzIiwiY29sbGFwc2libGVfZ3JvdXBzLmpzIiwid3BiY19sZW5fZ3JvdXBzLmpzIiwid3BiY19yYW5nZV9ncm91cHMuanMiLCJ1aV90YWJzLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FDZkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQ3JGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQ2pDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUM3QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUNqSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQ3BEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQy9TQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQ3JIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FDbGdCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FDdFpBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUNyUkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6IndwYmNfYWxsX2FkbWluLmpzIiwic291cmNlc0NvbnRlbnQiOlsiXHJcbi8qKlxyXG4gKiBCbGluayBzcGVjaWZpYyBIVE1MIGVsZW1lbnQgdG8gc2V0IGF0dGVudGlvbiB0byB0aGlzIGVsZW1lbnQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBlbGVtZW50X3RvX2JsaW5rXHRcdCAgLSBjbGFzcyBvciBpZCBvZiBlbGVtZW50OiAnLndwYmNfd2lkZ2V0X2F2YWlsYWJsZV91bmF2YWlsYWJsZSdcclxuICogQHBhcmFtIHtpbnR9IGhvd19tYW55X3RpbWVzXHRcdFx0ICAtIDRcclxuICogQHBhcmFtIHtpbnR9IGhvd19sb25nX3RvX2JsaW5rXHRcdCAgLSAzNTBcclxuICovXHJcbmZ1bmN0aW9uIHdwYmNfYmxpbmtfZWxlbWVudCggZWxlbWVudF90b19ibGluaywgaG93X21hbnlfdGltZXMgPSA0LCBob3dfbG9uZ190b19ibGluayA9IDM1MCApe1xyXG5cclxuXHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBob3dfbWFueV90aW1lczsgaSsrICl7XHJcblx0XHRqUXVlcnkoIGVsZW1lbnRfdG9fYmxpbmsgKS5mYWRlT3V0KCBob3dfbG9uZ190b19ibGluayApLmZhZGVJbiggaG93X2xvbmdfdG9fYmxpbmsgKTtcclxuXHR9XHJcbiAgICBqUXVlcnkoIGVsZW1lbnRfdG9fYmxpbmsgKS5hbmltYXRlKCB7b3BhY2l0eTogMX0sIDUwMCApO1xyXG59XHJcbiIsIi8qKlxyXG4gKiAgIFN1cHBvcnQgRnVuY3Rpb25zIC0gU3BpbiBJY29uIGluIEJ1dHRvbnMgIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqL1xyXG5cclxuLyoqXHJcbiAqIFJlbW92ZSBzcGluIGljb24gZnJvbSAgYnV0dG9uIGFuZCBFbmFibGUgdGhpcyBidXR0b24uXHJcbiAqXHJcbiAqIEBwYXJhbSBidXR0b25fY2xpY2tlZF9lbGVtZW50X2lkXHRcdC0gSFRNTCBJRCBhdHRyaWJ1dGUgb2YgdGhpcyBidXR0b25cclxuICogQHJldHVybiBzdHJpbmdcdFx0XHRcdFx0XHQtIENTUyBjbGFzc2VzIHRoYXQgd2FzIHByZXZpb3VzbHkgaW4gYnV0dG9uIGljb25cclxuICovXHJcbmZ1bmN0aW9uIHdwYmNfYnV0dG9uX19yZW1vdmVfc3BpbihidXR0b25fY2xpY2tlZF9lbGVtZW50X2lkKSB7XHJcblxyXG5cdHZhciBwcmV2aW9zX2NsYXNzZXMgPSAnJztcclxuXHRpZiAoXHJcblx0XHQodW5kZWZpbmVkICE9IGJ1dHRvbl9jbGlja2VkX2VsZW1lbnRfaWQpXHJcblx0XHQmJiAoJycgIT0gYnV0dG9uX2NsaWNrZWRfZWxlbWVudF9pZClcclxuXHQpIHtcclxuXHRcdHZhciBqRWxlbWVudCA9IGpRdWVyeSggJyMnICsgYnV0dG9uX2NsaWNrZWRfZWxlbWVudF9pZCApO1xyXG5cdFx0aWYgKCBqRWxlbWVudC5sZW5ndGggKSB7XHJcblx0XHRcdHByZXZpb3NfY2xhc3NlcyA9IHdwYmNfYnV0dG9uX2Rpc2FibGVfbG9hZGluZ19pY29uKCBqRWxlbWVudC5nZXQoIDAgKSApO1xyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0cmV0dXJuIHByZXZpb3NfY2xhc3NlcztcclxufVxyXG5cclxuXHJcbi8qKlxyXG4gKiBTaG93IExvYWRpbmcgKHJvdGF0aW5nIGFycm93KSBpY29uIGZvciBidXR0b24gdGhhdCBoYXMgYmVlbiBjbGlja2VkXHJcbiAqXHJcbiAqIEBwYXJhbSB0aGlzX2J1dHRvblx0XHQtIHRoaXMgb2JqZWN0IG9mIHNwZWNpZmljIGJ1dHRvblxyXG4gKiBAcmV0dXJuIHN0cmluZ1x0XHRcdC0gQ1NTIGNsYXNzZXMgdGhhdCB3YXMgcHJldmlvdXNseSBpbiBidXR0b24gaWNvblxyXG4gKi9cclxuZnVuY3Rpb24gd3BiY19idXR0b25fZW5hYmxlX2xvYWRpbmdfaWNvbih0aGlzX2J1dHRvbikge1xyXG5cclxuXHR2YXIgakJ1dHRvbiAgICAgICAgID0galF1ZXJ5KCB0aGlzX2J1dHRvbiApO1xyXG5cdHZhciBqSWNvbiAgICAgICAgICAgPSBqQnV0dG9uLmZpbmQoICdpJyApO1xyXG5cdHZhciBwcmV2aW9zX2NsYXNzZXMgPSBqSWNvbi5hdHRyKCAnY2xhc3MnICk7XHJcblxyXG5cdGpJY29uLnJlbW92ZUNsYXNzKCkuYWRkQ2xhc3MoICdtZW51X2ljb24gaWNvbi0xeCB3cGJjX2ljbl9yb3RhdGVfcmlnaHQgd3BiY19zcGluJyApO1x0Ly8gU2V0IFJvdGF0ZSBpY29uLlxyXG5cdC8vIGpJY29uLmFkZENsYXNzKCAnd3BiY19hbmltYXRpb25fcGF1c2UnICk7XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gUGF1c2UgYW5pbWF0aW9uLlxyXG5cdC8vIGpJY29uLmFkZENsYXNzKCAnd3BiY191aV9yZWQnICk7XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vIFNldCBpY29uIGNvbG9yIHJlZC5cclxuXHJcblx0akljb24uYXR0ciggJ3dwYmNfcHJldmlvdXNfY2xhc3MnLCBwcmV2aW9zX2NsYXNzZXMgKVxyXG5cclxuXHRqQnV0dG9uLmFkZENsYXNzKCAnZGlzYWJsZWQnICk7XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gRGlzYWJsZSBidXR0b25cclxuXHQvLyBXZSBuZWVkIHRvICBzZXQgIGhlcmUgYXR0ciBpbnN0ZWFkIG9mIHByb3AsIGJlY2F1c2UgZm9yIEEgZWxlbWVudHMsICBhdHRyaWJ1dGUgJ2Rpc2FibGVkJyBkbyAgbm90IGFkZGVkIHdpdGggakJ1dHRvbi5wcm9wKCBcImRpc2FibGVkXCIsIHRydWUgKTsuXHJcblxyXG5cdGpCdXR0b24uYXR0ciggJ3dwYmNfcHJldmlvdXNfb25jbGljaycsIGpCdXR0b24uYXR0ciggJ29uY2xpY2snICkgKTtcdFx0Ly8gU2F2ZSB0aGlzIHZhbHVlLlxyXG5cdGpCdXR0b24uYXR0ciggJ29uY2xpY2snLCAnJyApO1x0XHRcdFx0XHRcdFx0XHRcdFx0XHQvLyBEaXNhYmxlIGFjdGlvbnMgXCJvbiBjbGlja1wiLlxyXG5cclxuXHRyZXR1cm4gcHJldmlvc19jbGFzc2VzO1xyXG59XHJcblxyXG5cclxuLyoqXHJcbiAqIEhpZGUgTG9hZGluZyAocm90YXRpbmcgYXJyb3cpIGljb24gZm9yIGJ1dHRvbiB0aGF0IHdhcyBjbGlja2VkIGFuZCBzaG93IHByZXZpb3VzIGljb24gYW5kIGVuYWJsZSBidXR0b25cclxuICpcclxuICogQHBhcmFtIHRoaXNfYnV0dG9uXHRcdC0gdGhpcyBvYmplY3Qgb2Ygc3BlY2lmaWMgYnV0dG9uXHJcbiAqIEByZXR1cm4gc3RyaW5nXHRcdFx0LSBDU1MgY2xhc3NlcyB0aGF0IHdhcyBwcmV2aW91c2x5IGluIGJ1dHRvbiBpY29uXHJcbiAqL1xyXG5mdW5jdGlvbiB3cGJjX2J1dHRvbl9kaXNhYmxlX2xvYWRpbmdfaWNvbih0aGlzX2J1dHRvbikge1xyXG5cclxuXHR2YXIgakJ1dHRvbiA9IGpRdWVyeSggdGhpc19idXR0b24gKTtcclxuXHR2YXIgakljb24gICA9IGpCdXR0b24uZmluZCggJ2knICk7XHJcblxyXG5cdHZhciBwcmV2aW9zX2NsYXNzZXMgPSBqSWNvbi5hdHRyKCAnd3BiY19wcmV2aW91c19jbGFzcycgKTtcclxuXHRpZiAoXHJcblx0XHQodW5kZWZpbmVkICE9IHByZXZpb3NfY2xhc3NlcylcclxuXHRcdCYmICgnJyAhPSBwcmV2aW9zX2NsYXNzZXMpXHJcblx0KSB7XHJcblx0XHRqSWNvbi5yZW1vdmVDbGFzcygpLmFkZENsYXNzKCBwcmV2aW9zX2NsYXNzZXMgKTtcclxuXHR9XHJcblxyXG5cdGpCdXR0b24ucmVtb3ZlQ2xhc3MoICdkaXNhYmxlZCcgKTtcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQvLyBSZW1vdmUgRGlzYWJsZSBidXR0b24uXHJcblxyXG5cdHZhciBwcmV2aW91c19vbmNsaWNrID0gakJ1dHRvbi5hdHRyKCAnd3BiY19wcmV2aW91c19vbmNsaWNrJyApXHJcblx0aWYgKFxyXG5cdFx0KHVuZGVmaW5lZCAhPSBwcmV2aW91c19vbmNsaWNrKVxyXG5cdFx0JiYgKCcnICE9IHByZXZpb3VzX29uY2xpY2spXHJcblx0KSB7XHJcblx0XHRqQnV0dG9uLmF0dHIoICdvbmNsaWNrJywgcHJldmlvdXNfb25jbGljayApO1xyXG5cdH1cclxuXHJcblx0cmV0dXJuIHByZXZpb3NfY2xhc3NlcztcclxufVxyXG4iLCIvKipcclxuICogT24gc2VsZWN0aW9uICBvZiByYWRpbyBidXR0b24sIGFkanVzdCBhdHRyaWJ1dGVzIG9mIHJhZGlvIGNvbnRhaW5lclxyXG4gKlxyXG4gKiBAcGFyYW0gX3RoaXNcclxuICovXHJcbmZ1bmN0aW9uIHdwYmNfdWlfZWxfX3JhZGlvX2NvbnRhaW5lcl9zZWxlY3Rpb24oX3RoaXMpIHtcclxuXHJcblx0aWYgKCBqUXVlcnkoIF90aGlzICkuaXMoICc6Y2hlY2tlZCcgKSApIHtcclxuXHRcdGpRdWVyeSggX3RoaXMgKS5wYXJlbnRzKCAnLndwYmNfdWlfcmFkaW9fc2VjdGlvbicgKS5maW5kKCAnLndwYmNfdWlfcmFkaW9fY29udGFpbmVyJyApLnJlbW92ZUF0dHIoICdkYXRhLXNlbGVjdGVkJyApO1xyXG5cdFx0alF1ZXJ5KCBfdGhpcyApLnBhcmVudHMoICcud3BiY191aV9yYWRpb19jb250YWluZXI6bm90KC5kaXNhYmxlZCknICkuYXR0ciggJ2RhdGEtc2VsZWN0ZWQnLCB0cnVlICk7XHJcblx0fVxyXG5cclxuXHRpZiAoIGpRdWVyeSggX3RoaXMgKS5pcyggJzpkaXNhYmxlZCcgKSApIHtcclxuXHRcdGpRdWVyeSggX3RoaXMgKS5wYXJlbnRzKCAnLndwYmNfdWlfcmFkaW9fY29udGFpbmVyJyApLmFkZENsYXNzKCAnZGlzYWJsZWQnICk7XHJcblx0fVxyXG59XHJcblxyXG4vKipcclxuICogT24gY2xpY2sgb24gUmFkaW8gQ29udGFpbmVyLCB3ZSB3aWxsICBzZWxlY3QgIHRoZSAgcmFkaW8gYnV0dG9uICAgIGFuZCB0aGVuIGFkanVzdCBhdHRyaWJ1dGVzIG9mIHJhZGlvIGNvbnRhaW5lclxyXG4gKlxyXG4gKiBAcGFyYW0gX3RoaXNcclxuICovXHJcbmZ1bmN0aW9uIHdwYmNfdWlfZWxfX3JhZGlvX2NvbnRhaW5lcl9jbGljayhfdGhpcykge1xyXG5cclxuXHRpZiAoIGpRdWVyeSggX3RoaXMgKS5oYXNDbGFzcyggJ2Rpc2FibGVkJyApICkge1xyXG5cdFx0cmV0dXJuIGZhbHNlO1xyXG5cdH1cclxuXHJcblx0dmFyIGpfcmFkaW8gPSBqUXVlcnkoIF90aGlzICkuZmluZCggJ2lucHV0W3R5cGU9cmFkaW9dOm5vdCgud3BiYy1mb3JtLXJhZGlvLWludGVybmFsKScgKTtcclxuXHRpZiAoIGpfcmFkaW8ubGVuZ3RoICkge1xyXG5cdFx0al9yYWRpby5wcm9wKCAnY2hlY2tlZCcsIHRydWUgKS50cmlnZ2VyKCAnY2hhbmdlJyApO1xyXG5cdH1cclxuXHJcbn0iLCJcInVzZSBzdHJpY3RcIjtcclxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcbi8vID09IEZ1bGwgU2NyZWVuICAtICBzdXBwb3J0IGZ1bmN0aW9ucyAgID09XHJcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG5cclxuLyoqXHJcbiAqIENoZWNrIEZ1bGwgIHNjcmVlbiBtb2RlLCAgYnkgIHJlbW92aW5nIHRvcCB0YWJcclxuICovXHJcbmZ1bmN0aW9uIHdwYmNfY2hlY2tfZnVsbF9zY3JlZW5fbW9kZSgpe1xyXG5cdGlmICggalF1ZXJ5KCAnYm9keScgKS5oYXNDbGFzcyggJ3dwYmNfYWRtaW5fZnVsbF9zY3JlZW4nICkgKSB7XHJcblx0XHRqUXVlcnkoICdodG1sJyApLnJlbW92ZUNsYXNzKCAnd3AtdG9vbGJhcicgKTtcclxuXHR9IGVsc2Uge1xyXG5cdFx0alF1ZXJ5KCAnaHRtbCcgKS5hZGRDbGFzcyggJ3dwLXRvb2xiYXInICk7XHJcblx0fVxyXG5cdHdwYmNfY2hlY2tfYnV0dG9uc19tYXhfbWluX2luX2Z1bGxfc2NyZWVuX21vZGUoKTtcclxufVxyXG5cclxuZnVuY3Rpb24gd3BiY19jaGVja19idXR0b25zX21heF9taW5faW5fZnVsbF9zY3JlZW5fbW9kZSgpIHtcclxuXHRpZiAoIGpRdWVyeSggJ2JvZHknICkuaGFzQ2xhc3MoICd3cGJjX2FkbWluX2Z1bGxfc2NyZWVuJyApICkge1xyXG5cdFx0alF1ZXJ5KCAnLndwYmNfdWlfX3RvcF9uYXZfX2J0bl9mdWxsX3NjcmVlbicgICApLmFkZENsYXNzKCAgICAnd3BiY191aV9faGlkZScgKTtcclxuXHRcdGpRdWVyeSggJy53cGJjX3VpX190b3BfbmF2X19idG5fbm9ybWFsX3NjcmVlbicgKS5yZW1vdmVDbGFzcyggJ3dwYmNfdWlfX2hpZGUnICk7XHJcblx0fSBlbHNlIHtcclxuXHRcdGpRdWVyeSggJy53cGJjX3VpX190b3BfbmF2X19idG5fZnVsbF9zY3JlZW4nICAgKS5yZW1vdmVDbGFzcyggJ3dwYmNfdWlfX2hpZGUnICk7XHJcblx0XHRqUXVlcnkoICcud3BiY191aV9fdG9wX25hdl9fYnRuX25vcm1hbF9zY3JlZW4nICkuYWRkQ2xhc3MoICAgICd3cGJjX3VpX19oaWRlJyApO1xyXG5cdH1cclxufVxyXG5cclxualF1ZXJ5KCBkb2N1bWVudCApLnJlYWR5KCBmdW5jdGlvbiAoKSB7XHJcblx0d3BiY19jaGVja19mdWxsX3NjcmVlbl9tb2RlKCk7XHJcbn0gKTsiLCIvKipcclxuICogQ2hlY2tib3ggU2VsZWN0aW9uIGZ1bmN0aW9ucyBmb3IgTGlzdGluZy5cclxuICovXHJcblxyXG4vKipcclxuICogU2VsZWN0aW9ucyBvZiBzZXZlcmFsICBjaGVja2JveGVzIGxpa2UgaW4gZ01haWwgd2l0aCBzaGlmdCA6KVxyXG4gKiBOZWVkIHRvICBoYXZlIHRoaXMgc3RydWN0dXJlOlxyXG4gKiAud3BiY19zZWxlY3RhYmxlX3RhYmxlXHJcbiAqICAgICAgLndwYmNfc2VsZWN0YWJsZV9oZWFkXHJcbiAqICAgICAgICAgICAgICAuY2hlY2stY29sdW1uXHJcbiAqICAgICAgICAgICAgICAgICAgOmNoZWNrYm94XHJcbiAqICAgICAgLndwYmNfc2VsZWN0YWJsZV9ib2R5XHJcbiAqICAgICAgICAgIC53cGJjX3Jvd1xyXG4gKiAgICAgICAgICAgICAgLmNoZWNrLWNvbHVtblxyXG4gKiAgICAgICAgICAgICAgICAgIDpjaGVja2JveFxyXG4gKiAgICAgIC53cGJjX3NlbGVjdGFibGVfZm9vdFxyXG4gKiAgICAgICAgICAgICAgLmNoZWNrLWNvbHVtblxyXG4gKiAgICAgICAgICAgICAgICAgIDpjaGVja2JveFxyXG4gKi9cclxuZnVuY3Rpb24gd3BiY19kZWZpbmVfZ21haWxfY2hlY2tib3hfc2VsZWN0aW9uKCAkICl7XHJcblxyXG5cdHZhciBjaGVja3MsIGZpcnN0LCBsYXN0LCBjaGVja2VkLCBzbGljZWQsIGxhc3RDbGlja2VkID0gZmFsc2U7XHJcblxyXG5cdC8vIENoZWNrIGFsbCBjaGVja2JveGVzLlxyXG5cdCQoICcud3BiY19zZWxlY3RhYmxlX2JvZHknICkuZmluZCggJy5jaGVjay1jb2x1bW4nICkuZmluZCggJzpjaGVja2JveCcgKS5vbihcclxuXHRcdCdjbGljaycsXHJcblx0XHRmdW5jdGlvbiAoZSkge1xyXG5cdFx0XHRpZiAoICd1bmRlZmluZWQnID09IGUuc2hpZnRLZXkgKSB7XHJcblx0XHRcdFx0cmV0dXJuIHRydWU7XHJcblx0XHRcdH1cclxuXHRcdFx0aWYgKCBlLnNoaWZ0S2V5ICkge1xyXG5cdFx0XHRcdGlmICggISBsYXN0Q2xpY2tlZCApIHtcclxuXHRcdFx0XHRcdHJldHVybiB0cnVlO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0XHRjaGVja3MgID0gJCggbGFzdENsaWNrZWQgKS5jbG9zZXN0KCAnLndwYmNfc2VsZWN0YWJsZV9ib2R5JyApLmZpbmQoICc6Y2hlY2tib3gnICkuZmlsdGVyKCAnOnZpc2libGU6ZW5hYmxlZCcgKTtcclxuXHRcdFx0XHRmaXJzdCAgID0gY2hlY2tzLmluZGV4KCBsYXN0Q2xpY2tlZCApO1xyXG5cdFx0XHRcdGxhc3QgICAgPSBjaGVja3MuaW5kZXgoIHRoaXMgKTtcclxuXHRcdFx0XHRjaGVja2VkID0gJCggdGhpcyApLnByb3AoICdjaGVja2VkJyApO1xyXG5cdFx0XHRcdGlmICggMCA8IGZpcnN0ICYmIDAgPCBsYXN0ICYmIGZpcnN0ICE9IGxhc3QgKSB7XHJcblx0XHRcdFx0XHRzbGljZWQgPSAobGFzdCA+IGZpcnN0KSA/IGNoZWNrcy5zbGljZSggZmlyc3QsIGxhc3QgKSA6IGNoZWNrcy5zbGljZSggbGFzdCwgZmlyc3QgKTtcclxuXHRcdFx0XHRcdHNsaWNlZC5wcm9wKFxyXG5cdFx0XHRcdFx0XHQnY2hlY2tlZCcsXHJcblx0XHRcdFx0XHRcdGZ1bmN0aW9uICgpIHtcclxuXHRcdFx0XHRcdFx0XHRpZiAoICQoIHRoaXMgKS5jbG9zZXN0KCAnLndwYmNfcm93JyApLmlzKCAnOnZpc2libGUnICkgKSB7XHJcblx0XHRcdFx0XHRcdFx0XHRyZXR1cm4gY2hlY2tlZDtcclxuXHRcdFx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHRcdFx0cmV0dXJuIGZhbHNlO1xyXG5cdFx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHQpLnRyaWdnZXIoICdjaGFuZ2UnICk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblx0XHRcdGxhc3RDbGlja2VkID0gdGhpcztcclxuXHJcblx0XHRcdC8vIHRvZ2dsZSBcImNoZWNrIGFsbFwiIGNoZWNrYm94ZXMuXHJcblx0XHRcdHZhciB1bmNoZWNrZWQgPSAkKCB0aGlzICkuY2xvc2VzdCggJy53cGJjX3NlbGVjdGFibGVfYm9keScgKS5maW5kKCAnOmNoZWNrYm94JyApLmZpbHRlciggJzp2aXNpYmxlOmVuYWJsZWQnICkubm90KCAnOmNoZWNrZWQnICk7XHJcblx0XHRcdCQoIHRoaXMgKS5jbG9zZXN0KCAnLndwYmNfc2VsZWN0YWJsZV90YWJsZScgKS5jaGlsZHJlbiggJy53cGJjX3NlbGVjdGFibGVfaGVhZCwgLndwYmNfc2VsZWN0YWJsZV9mb290JyApLmZpbmQoICc6Y2hlY2tib3gnICkucHJvcChcclxuXHRcdFx0XHQnY2hlY2tlZCcsXHJcblx0XHRcdFx0ZnVuY3Rpb24gKCkge1xyXG5cdFx0XHRcdFx0cmV0dXJuICgwID09PSB1bmNoZWNrZWQubGVuZ3RoKTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdCkudHJpZ2dlciggJ2NoYW5nZScgKTtcclxuXHJcblx0XHRcdHJldHVybiB0cnVlO1xyXG5cdFx0fVxyXG5cdCk7XHJcblxyXG5cdC8vIEhlYWQgfHwgRm9vdCBjbGlja2luZyB0byAgc2VsZWN0IC8gZGVzZWxlY3QgQUxMLlxyXG5cdCQoICcud3BiY19zZWxlY3RhYmxlX2hlYWQsIC53cGJjX3NlbGVjdGFibGVfZm9vdCcgKS5maW5kKCAnLmNoZWNrLWNvbHVtbiA6Y2hlY2tib3gnICkub24oXHJcblx0XHQnY2xpY2snLFxyXG5cdFx0ZnVuY3Rpb24gKGV2ZW50KSB7XHJcblx0XHRcdHZhciAkdGhpcyAgICAgICAgICA9ICQoIHRoaXMgKSxcclxuXHRcdFx0XHQkdGFibGUgICAgICAgICA9ICR0aGlzLmNsb3Nlc3QoICcud3BiY19zZWxlY3RhYmxlX3RhYmxlJyApLFxyXG5cdFx0XHRcdGNvbnRyb2xDaGVja2VkID0gJHRoaXMucHJvcCggJ2NoZWNrZWQnICksXHJcblx0XHRcdFx0dG9nZ2xlICAgICAgICAgPSBldmVudC5zaGlmdEtleSB8fCAkdGhpcy5kYXRhKCAnd3AtdG9nZ2xlJyApO1xyXG5cclxuXHRcdFx0JHRhYmxlLmNoaWxkcmVuKCAnLndwYmNfc2VsZWN0YWJsZV9ib2R5JyApLmZpbHRlciggJzp2aXNpYmxlJyApXHJcblx0XHRcdFx0LmZpbmQoICcuY2hlY2stY29sdW1uJyApLmZpbmQoICc6Y2hlY2tib3gnIClcclxuXHRcdFx0XHQucHJvcChcclxuXHRcdFx0XHRcdCdjaGVja2VkJyxcclxuXHRcdFx0XHRcdGZ1bmN0aW9uICgpIHtcclxuXHRcdFx0XHRcdFx0aWYgKCAkKCB0aGlzICkuaXMoICc6aGlkZGVuLDpkaXNhYmxlZCcgKSApIHtcclxuXHRcdFx0XHRcdFx0XHRyZXR1cm4gZmFsc2U7XHJcblx0XHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdFx0aWYgKCB0b2dnbGUgKSB7XHJcblx0XHRcdFx0XHRcdFx0cmV0dXJuICEgJCggdGhpcyApLnByb3AoICdjaGVja2VkJyApO1xyXG5cdFx0XHRcdFx0XHR9IGVsc2UgaWYgKCBjb250cm9sQ2hlY2tlZCApIHtcclxuXHRcdFx0XHRcdFx0XHRyZXR1cm4gdHJ1ZTtcclxuXHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHRyZXR1cm4gZmFsc2U7XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0KS50cmlnZ2VyKCAnY2hhbmdlJyApO1xyXG5cclxuXHRcdFx0JHRhYmxlLmNoaWxkcmVuKCAnLndwYmNfc2VsZWN0YWJsZV9oZWFkLCAgLndwYmNfc2VsZWN0YWJsZV9mb290JyApLmZpbHRlciggJzp2aXNpYmxlJyApXHJcblx0XHRcdFx0LmZpbmQoICcuY2hlY2stY29sdW1uJyApLmZpbmQoICc6Y2hlY2tib3gnIClcclxuXHRcdFx0XHQucHJvcChcclxuXHRcdFx0XHRcdCdjaGVja2VkJyxcclxuXHRcdFx0XHRcdGZ1bmN0aW9uICgpIHtcclxuXHRcdFx0XHRcdFx0aWYgKCB0b2dnbGUgKSB7XHJcblx0XHRcdFx0XHRcdFx0cmV0dXJuIGZhbHNlO1xyXG5cdFx0XHRcdFx0XHR9IGVsc2UgaWYgKCBjb250cm9sQ2hlY2tlZCApIHtcclxuXHRcdFx0XHRcdFx0XHRyZXR1cm4gdHJ1ZTtcclxuXHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHRyZXR1cm4gZmFsc2U7XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0KTtcclxuXHRcdH1cclxuXHQpO1xyXG5cclxuXHJcblx0Ly8gVmlzdWFsbHkgIHNob3cgc2VsZWN0ZWQgYm9yZGVyLlxyXG5cdCQoICcud3BiY19zZWxlY3RhYmxlX2JvZHknICkuZmluZCggJy5jaGVjay1jb2x1bW4gOmNoZWNrYm94JyApLm9uKFxyXG5cdFx0J2NoYW5nZScsXHJcblx0XHRmdW5jdGlvbiAoZXZlbnQpIHtcclxuXHRcdFx0aWYgKCBqUXVlcnkoIHRoaXMgKS5pcyggJzpjaGVja2VkJyApICkge1xyXG5cdFx0XHRcdGpRdWVyeSggdGhpcyApLmNsb3Nlc3QoICcud3BiY19saXN0X3JvdycgKS5hZGRDbGFzcyggJ3Jvd19zZWxlY3RlZF9jb2xvcicgKTtcclxuXHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRqUXVlcnkoIHRoaXMgKS5jbG9zZXN0KCAnLndwYmNfbGlzdF9yb3cnICkucmVtb3ZlQ2xhc3MoICdyb3dfc2VsZWN0ZWRfY29sb3InICk7XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIERpc2FibGUgdGV4dCBzZWxlY3Rpb24gd2hpbGUgcHJlc3NpbmcgJ3NoaWZ0Jy5cclxuXHRcdFx0ZG9jdW1lbnQuZ2V0U2VsZWN0aW9uKCkucmVtb3ZlQWxsUmFuZ2VzKCk7XHJcblxyXG5cdFx0XHQvLyBTaG93IG9yIGhpZGUgYnV0dG9ucyBvbiBBY3Rpb25zIHRvb2xiYXIgIGF0ICBCb29raW5nIExpc3RpbmcgIHBhZ2UsICBpZiB3ZSBoYXZlIHNvbWUgc2VsZWN0ZWQgYm9va2luZ3MuXHJcblx0XHRcdHdwYmNfc2hvd19oaWRlX2FjdGlvbl9idXR0b25zX2Zvcl9zZWxlY3RlZF9ib29raW5ncygpO1xyXG5cdFx0fVxyXG5cdCk7XHJcblxyXG5cdHdwYmNfc2hvd19oaWRlX2FjdGlvbl9idXR0b25zX2Zvcl9zZWxlY3RlZF9ib29raW5ncygpO1xyXG59XHJcbiIsIlxyXG4vKipcclxuICogR2V0IElEIGFycmF5ICBvZiBzZWxlY3RlZCBlbGVtZW50c1xyXG4gKi9cclxuZnVuY3Rpb24gd3BiY19nZXRfc2VsZWN0ZWRfcm93X2lkKCkge1xyXG5cclxuXHR2YXIgJHRhYmxlICAgICAgPSBqUXVlcnkoICcud3BiY19fd3JhcF9fYm9va2luZ19saXN0aW5nIC53cGJjX3NlbGVjdGFibGVfdGFibGUnICk7XHJcblx0dmFyIGNoZWNrYm94ZXMgID0gJHRhYmxlLmNoaWxkcmVuKCAnLndwYmNfc2VsZWN0YWJsZV9ib2R5JyApLmZpbHRlciggJzp2aXNpYmxlJyApLmZpbmQoICcuY2hlY2stY29sdW1uJyApLmZpbmQoICc6Y2hlY2tib3gnICk7XHJcblx0dmFyIHNlbGVjdGVkX2lkID0gW107XHJcblxyXG5cdGpRdWVyeS5lYWNoKFxyXG5cdFx0Y2hlY2tib3hlcyxcclxuXHRcdGZ1bmN0aW9uIChrZXksIGNoZWNrYm94KSB7XHJcblx0XHRcdGlmICggalF1ZXJ5KCBjaGVja2JveCApLmlzKCAnOmNoZWNrZWQnICkgKSB7XHJcblx0XHRcdFx0dmFyIGVsZW1lbnRfaWQgPSB3cGJjX2dldF9yb3dfaWRfZnJvbV9lbGVtZW50KCBjaGVja2JveCApO1xyXG5cdFx0XHRcdHNlbGVjdGVkX2lkLnB1c2goIGVsZW1lbnRfaWQgKTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cdCk7XHJcblxyXG5cdHJldHVybiBzZWxlY3RlZF9pZDtcclxufVxyXG5cclxuXHJcbi8qKlxyXG4gKiBHZXQgSUQgb2Ygcm93LCAgYmFzZWQgb24gY2xjaWtlZCBlbGVtZW50XHJcbiAqXHJcbiAqIEBwYXJhbSB0aGlzX2luYm91bmRfZWxlbWVudCAgLSB1c3VzbGx5ICB0aGlzXHJcbiAqIEByZXR1cm5zIHtudW1iZXJ9XHJcbiAqL1xyXG5mdW5jdGlvbiB3cGJjX2dldF9yb3dfaWRfZnJvbV9lbGVtZW50KHRoaXNfaW5ib3VuZF9lbGVtZW50KSB7XHJcblxyXG5cdHZhciBlbGVtZW50X2lkID0galF1ZXJ5KCB0aGlzX2luYm91bmRfZWxlbWVudCApLmNsb3Nlc3QoICcud3BiY19saXN0aW5nX3VzdWFsX3JvdycgKS5hdHRyKCAnaWQnICk7XHJcblxyXG5cdGVsZW1lbnRfaWQgPSBwYXJzZUludCggZWxlbWVudF9pZC5yZXBsYWNlKCAncm93X2lkXycsICcnICkgKTtcclxuXHJcblx0cmV0dXJuIGVsZW1lbnRfaWQ7XHJcbn1cclxuXHJcblxyXG4vKipcclxuICogPT0gQm9va2luZyBMaXN0aW5nID09IFNob3cgb3IgaGlkZSBidXR0b25zIG9uIEFjdGlvbnMgdG9vbGJhciAgYXQgICAgcGFnZSwgIGlmIHdlIGhhdmUgc29tZSBzZWxlY3RlZCBib29raW5ncy5cclxuICovXHJcbmZ1bmN0aW9uIHdwYmNfc2hvd19oaWRlX2FjdGlvbl9idXR0b25zX2Zvcl9zZWxlY3RlZF9ib29raW5ncygpe1xyXG5cclxuXHR2YXIgc2VsZWN0ZWRfcm93c19hcnIgPSB3cGJjX2dldF9zZWxlY3RlZF9yb3dfaWQoKTtcclxuXHJcblx0aWYgKCBzZWxlY3RlZF9yb3dzX2Fyci5sZW5ndGggPiAwICkge1xyXG5cdFx0alF1ZXJ5KCAnLmhpZGVfYnV0dG9uX2lmX25vX3NlbGVjdGlvbicgKS5zaG93KCk7XHJcblx0fSBlbHNlIHtcclxuXHRcdGpRdWVyeSggJy5oaWRlX2J1dHRvbl9pZl9ub19zZWxlY3Rpb24nICkuaGlkZSgpO1xyXG5cdH1cclxufSIsIlwidXNlIHN0cmljdFwiO1xyXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuLy8gPT0gTGVmdCBCYXIgIC0gIGV4cGFuZCAvIGNvbGFwc2UgZnVuY3Rpb25zICAgPT1cclxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcblxyXG4vKipcclxuICogRXhwYW5kIFZlcnRpY2FsIExlZnQgQmFyLlxyXG4gKi9cclxuZnVuY3Rpb24gd3BiY19hZG1pbl91aV9fc2lkZWJhcl9sZWZ0X19kb19tYXgoKSB7XHJcblx0alF1ZXJ5KCAnLndwYmNfc2V0dGluZ3NfcGFnZV93cmFwcGVyJyApLnJlbW92ZUNsYXNzKCAnbWluIG1heCBjb21wYWN0IG5vbmUnICk7XHJcblx0alF1ZXJ5KCAnLndwYmNfc2V0dGluZ3NfcGFnZV93cmFwcGVyJyApLmFkZENsYXNzKCAnbWF4JyApO1xyXG5cdGpRdWVyeSggJy53cGJjX3VpX190b3BfbmF2X19idG5fb3Blbl9sZWZ0X3ZlcnRpY2FsX25hdicgKS5hZGRDbGFzcyggJ3dwYmNfdWlfX2hpZGUnICk7XHJcblx0alF1ZXJ5KCAnLndwYmNfdWlfX3RvcF9uYXZfX2J0bl9oaWRlX2xlZnRfdmVydGljYWxfbmF2JyApLnJlbW92ZUNsYXNzKCAnd3BiY191aV9faGlkZScgKTtcclxuXHJcblx0alF1ZXJ5KCAnLndwLWFkbWluJyApLnJlbW92ZUNsYXNzKCAnd3BiY19wYWdlX3dyYXBwZXJfbGVmdF9taW4gd3BiY19wYWdlX3dyYXBwZXJfbGVmdF9tYXggd3BiY19wYWdlX3dyYXBwZXJfbGVmdF9jb21wYWN0IHdwYmNfcGFnZV93cmFwcGVyX2xlZnRfbm9uZScgKTtcclxuXHRqUXVlcnkoICcud3AtYWRtaW4nICkuYWRkQ2xhc3MoICd3cGJjX3BhZ2Vfd3JhcHBlcl9sZWZ0X21heCcgKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEhpZGUgVmVydGljYWwgTGVmdCBCYXIuXHJcbiAqL1xyXG5mdW5jdGlvbiB3cGJjX2FkbWluX3VpX19zaWRlYmFyX2xlZnRfX2RvX21pbigpIHtcclxuXHRqUXVlcnkoICcud3BiY19zZXR0aW5nc19wYWdlX3dyYXBwZXInICkucmVtb3ZlQ2xhc3MoICdtaW4gbWF4IGNvbXBhY3Qgbm9uZScgKTtcclxuXHRqUXVlcnkoICcud3BiY19zZXR0aW5nc19wYWdlX3dyYXBwZXInICkuYWRkQ2xhc3MoICdtaW4nICk7XHJcblx0alF1ZXJ5KCAnLndwYmNfdWlfX3RvcF9uYXZfX2J0bl9vcGVuX2xlZnRfdmVydGljYWxfbmF2JyApLnJlbW92ZUNsYXNzKCAnd3BiY191aV9faGlkZScgKTtcclxuXHRqUXVlcnkoICcud3BiY191aV9fdG9wX25hdl9fYnRuX2hpZGVfbGVmdF92ZXJ0aWNhbF9uYXYnICkuYWRkQ2xhc3MoICd3cGJjX3VpX19oaWRlJyApO1xyXG5cclxuXHRqUXVlcnkoICcud3AtYWRtaW4nICkucmVtb3ZlQ2xhc3MoICd3cGJjX3BhZ2Vfd3JhcHBlcl9sZWZ0X21pbiB3cGJjX3BhZ2Vfd3JhcHBlcl9sZWZ0X21heCB3cGJjX3BhZ2Vfd3JhcHBlcl9sZWZ0X2NvbXBhY3Qgd3BiY19wYWdlX3dyYXBwZXJfbGVmdF9ub25lJyApO1xyXG5cdGpRdWVyeSggJy53cC1hZG1pbicgKS5hZGRDbGFzcyggJ3dwYmNfcGFnZV93cmFwcGVyX2xlZnRfbWluJyApO1xyXG59XHJcblxyXG4vKipcclxuICogQ29sYXBzZSBWZXJ0aWNhbCBMZWZ0IEJhci5cclxuICovXHJcbmZ1bmN0aW9uIHdwYmNfYWRtaW5fdWlfX3NpZGViYXJfbGVmdF9fZG9fY29tcGFjdCgpIHtcclxuXHRqUXVlcnkoICcud3BiY19zZXR0aW5nc19wYWdlX3dyYXBwZXInICkucmVtb3ZlQ2xhc3MoICdtaW4gbWF4IGNvbXBhY3Qgbm9uZScgKTtcclxuXHRqUXVlcnkoICcud3BiY19zZXR0aW5nc19wYWdlX3dyYXBwZXInICkuYWRkQ2xhc3MoICdjb21wYWN0JyApO1xyXG5cdGpRdWVyeSggJy53cGJjX3VpX190b3BfbmF2X19idG5fb3Blbl9sZWZ0X3ZlcnRpY2FsX25hdicgKS5yZW1vdmVDbGFzcyggJ3dwYmNfdWlfX2hpZGUnICk7XHJcblx0alF1ZXJ5KCAnLndwYmNfdWlfX3RvcF9uYXZfX2J0bl9oaWRlX2xlZnRfdmVydGljYWxfbmF2JyApLmFkZENsYXNzKCAnd3BiY191aV9faGlkZScgKTtcclxuXHJcblx0alF1ZXJ5KCAnLndwLWFkbWluJyApLnJlbW92ZUNsYXNzKCAnd3BiY19wYWdlX3dyYXBwZXJfbGVmdF9taW4gd3BiY19wYWdlX3dyYXBwZXJfbGVmdF9tYXggd3BiY19wYWdlX3dyYXBwZXJfbGVmdF9jb21wYWN0IHdwYmNfcGFnZV93cmFwcGVyX2xlZnRfbm9uZScgKTtcclxuXHRqUXVlcnkoICcud3AtYWRtaW4nICkuYWRkQ2xhc3MoICd3cGJjX3BhZ2Vfd3JhcHBlcl9sZWZ0X2NvbXBhY3QnICk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDb21wbGV0ZWx5IEhpZGUgVmVydGljYWwgTGVmdCBCYXIuXHJcbiAqL1xyXG5mdW5jdGlvbiB3cGJjX2FkbWluX3VpX19zaWRlYmFyX2xlZnRfX2RvX2hpZGUoKSB7XHJcblx0alF1ZXJ5KCAnLndwYmNfc2V0dGluZ3NfcGFnZV93cmFwcGVyJyApLnJlbW92ZUNsYXNzKCAnbWluIG1heCBjb21wYWN0IG5vbmUnICk7XHJcblx0alF1ZXJ5KCAnLndwYmNfc2V0dGluZ3NfcGFnZV93cmFwcGVyJyApLmFkZENsYXNzKCAnbm9uZScgKTtcclxuXHRqUXVlcnkoICcud3BiY191aV9fdG9wX25hdl9fYnRuX29wZW5fbGVmdF92ZXJ0aWNhbF9uYXYnICkucmVtb3ZlQ2xhc3MoICd3cGJjX3VpX19oaWRlJyApO1xyXG5cdGpRdWVyeSggJy53cGJjX3VpX190b3BfbmF2X19idG5faGlkZV9sZWZ0X3ZlcnRpY2FsX25hdicgKS5hZGRDbGFzcyggJ3dwYmNfdWlfX2hpZGUnICk7XHJcblx0Ly8gSGlkZSB0b3AgXCJNZW51XCIgYnV0dG9uIHdpdGggZGl2aWRlci5cclxuXHRqUXVlcnkoICcud3BiY191aV9fdG9wX25hdl9fYnRuX3Nob3dfbGVmdF92ZXJ0aWNhbF9uYXYsLndwYmNfdWlfX3RvcF9uYXZfX2J0bl9zaG93X2xlZnRfdmVydGljYWxfbmF2X2RpdmlkZXInICkuYWRkQ2xhc3MoICd3cGJjX3VpX19oaWRlJyApO1xyXG5cclxuXHRqUXVlcnkoICcud3AtYWRtaW4nICkucmVtb3ZlQ2xhc3MoICd3cGJjX3BhZ2Vfd3JhcHBlcl9sZWZ0X21pbiB3cGJjX3BhZ2Vfd3JhcHBlcl9sZWZ0X21heCB3cGJjX3BhZ2Vfd3JhcHBlcl9sZWZ0X2NvbXBhY3Qgd3BiY19wYWdlX3dyYXBwZXJfbGVmdF9ub25lJyApO1xyXG5cdGpRdWVyeSggJy53cC1hZG1pbicgKS5hZGRDbGFzcyggJ3dwYmNfcGFnZV93cmFwcGVyX2xlZnRfbm9uZScgKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEFjdGlvbiBvbiBjbGljayBcIkdvIEJhY2tcIiAtIHNob3cgcm9vdCBtZW51XHJcbiAqIG9yIHNvbWUgb3RoZXIgc2VjdGlvbiBpbiBsZWZ0IHNpZGViYXIuXHJcbiAqXHJcbiAqIEBwYXJhbSBzdHJpbmcgbWVudV90b19zaG93IC0gbWVudSBzbHVnLlxyXG4gKi9cclxuZnVuY3Rpb24gd3BiY19hZG1pbl91aV9fc2lkZWJhcl9sZWZ0X19zaG93X3NlY3Rpb24oIG1lbnVfdG9fc2hvdyApIHtcclxuXHRqUXVlcnkoICcud3BiY191aV9lbF9fdmVydF9sZWZ0X2Jhcl9fc2VjdGlvbicgKS5hZGRDbGFzcyggJ3dwYmNfdWlfX2hpZGUnIClcclxuXHRqUXVlcnkoICcud3BiY191aV9lbF9fdmVydF9sZWZ0X2Jhcl9fc2VjdGlvbl8nICsgbWVudV90b19zaG93ICkucmVtb3ZlQ2xhc3MoICd3cGJjX3VpX19oaWRlJyApO1xyXG59XHJcblxyXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuLy8gPT0gUmlnaHQgU2lkZSBCYXIgIC0gIGV4cGFuZCAvIGNvbGFwc2UgZnVuY3Rpb25zICAgPT1cclxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcblxyXG4vKipcclxuICogRXhwYW5kIFZlcnRpY2FsIFJpZ2h0IEJhci5cclxuICovXHJcbmZ1bmN0aW9uIHdwYmNfYWRtaW5fdWlfX3NpZGViYXJfcmlnaHRfX2RvX21heCgpIHtcclxuXHRqUXVlcnkoICcud3BiY19zZXR0aW5nc19wYWdlX3dyYXBwZXInICkucmVtb3ZlQ2xhc3MoICdtaW5fcmlnaHQgbWF4X3JpZ2h0IGNvbXBhY3RfcmlnaHQgbm9uZV9yaWdodCcgKTtcclxuXHRqUXVlcnkoICcud3BiY19zZXR0aW5nc19wYWdlX3dyYXBwZXInICkuYWRkQ2xhc3MoICdtYXhfcmlnaHQnICk7XHJcblx0alF1ZXJ5KCAnLndwYmNfdWlfX3RvcF9uYXZfX2J0bl9vcGVuX3JpZ2h0X3ZlcnRpY2FsX25hdicgKS5hZGRDbGFzcyggJ3dwYmNfdWlfX2hpZGUnICk7XHJcblx0alF1ZXJ5KCAnLndwYmNfdWlfX3RvcF9uYXZfX2J0bl9oaWRlX3JpZ2h0X3ZlcnRpY2FsX25hdicgKS5yZW1vdmVDbGFzcyggJ3dwYmNfdWlfX2hpZGUnICk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBIaWRlIFZlcnRpY2FsIFJpZ2h0IEJhci5cclxuICovXHJcbmZ1bmN0aW9uIHdwYmNfYWRtaW5fdWlfX3NpZGViYXJfcmlnaHRfX2RvX21pbigpIHtcclxuXHRqUXVlcnkoICcud3BiY19zZXR0aW5nc19wYWdlX3dyYXBwZXInICkucmVtb3ZlQ2xhc3MoICdtaW5fcmlnaHQgbWF4X3JpZ2h0IGNvbXBhY3RfcmlnaHQgbm9uZV9yaWdodCcgKTtcclxuXHRqUXVlcnkoICcud3BiY19zZXR0aW5nc19wYWdlX3dyYXBwZXInICkuYWRkQ2xhc3MoICdtaW5fcmlnaHQnICk7XHJcblx0alF1ZXJ5KCAnLndwYmNfdWlfX3RvcF9uYXZfX2J0bl9vcGVuX3JpZ2h0X3ZlcnRpY2FsX25hdicgKS5yZW1vdmVDbGFzcyggJ3dwYmNfdWlfX2hpZGUnICk7XHJcblx0alF1ZXJ5KCAnLndwYmNfdWlfX3RvcF9uYXZfX2J0bl9oaWRlX3JpZ2h0X3ZlcnRpY2FsX25hdicgKS5hZGRDbGFzcyggJ3dwYmNfdWlfX2hpZGUnICk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDb2xhcHNlIFZlcnRpY2FsIFJpZ2h0IEJhci5cclxuICovXHJcbmZ1bmN0aW9uIHdwYmNfYWRtaW5fdWlfX3NpZGViYXJfcmlnaHRfX2RvX2NvbXBhY3QoKSB7XHJcblx0alF1ZXJ5KCAnLndwYmNfc2V0dGluZ3NfcGFnZV93cmFwcGVyJyApLnJlbW92ZUNsYXNzKCAnbWluX3JpZ2h0IG1heF9yaWdodCBjb21wYWN0X3JpZ2h0IG5vbmVfcmlnaHQnICk7XHJcblx0alF1ZXJ5KCAnLndwYmNfc2V0dGluZ3NfcGFnZV93cmFwcGVyJyApLmFkZENsYXNzKCAnY29tcGFjdF9yaWdodCcgKTtcclxuXHRqUXVlcnkoICcud3BiY191aV9fdG9wX25hdl9fYnRuX29wZW5fcmlnaHRfdmVydGljYWxfbmF2JyApLnJlbW92ZUNsYXNzKCAnd3BiY191aV9faGlkZScgKTtcclxuXHRqUXVlcnkoICcud3BiY191aV9fdG9wX25hdl9fYnRuX2hpZGVfcmlnaHRfdmVydGljYWxfbmF2JyApLmFkZENsYXNzKCAnd3BiY191aV9faGlkZScgKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENvbXBsZXRlbHkgSGlkZSBWZXJ0aWNhbCBSaWdodCBCYXIuXHJcbiAqL1xyXG5mdW5jdGlvbiB3cGJjX2FkbWluX3VpX19zaWRlYmFyX3JpZ2h0X19kb19oaWRlKCkge1xyXG5cdGpRdWVyeSggJy53cGJjX3NldHRpbmdzX3BhZ2Vfd3JhcHBlcicgKS5yZW1vdmVDbGFzcyggJ21pbl9yaWdodCBtYXhfcmlnaHQgY29tcGFjdF9yaWdodCBub25lX3JpZ2h0JyApO1xyXG5cdGpRdWVyeSggJy53cGJjX3NldHRpbmdzX3BhZ2Vfd3JhcHBlcicgKS5hZGRDbGFzcyggJ25vbmVfcmlnaHQnICk7XHJcblx0alF1ZXJ5KCAnLndwYmNfdWlfX3RvcF9uYXZfX2J0bl9vcGVuX3JpZ2h0X3ZlcnRpY2FsX25hdicgKS5yZW1vdmVDbGFzcyggJ3dwYmNfdWlfX2hpZGUnICk7XHJcblx0alF1ZXJ5KCAnLndwYmNfdWlfX3RvcF9uYXZfX2J0bl9oaWRlX3JpZ2h0X3ZlcnRpY2FsX25hdicgKS5hZGRDbGFzcyggJ3dwYmNfdWlfX2hpZGUnICk7XHJcblx0Ly8gSGlkZSB0b3AgXCJNZW51XCIgYnV0dG9uIHdpdGggZGl2aWRlci5cclxuXHRqUXVlcnkoICcud3BiY191aV9fdG9wX25hdl9fYnRuX3Nob3dfcmlnaHRfdmVydGljYWxfbmF2LC53cGJjX3VpX190b3BfbmF2X19idG5fc2hvd19yaWdodF92ZXJ0aWNhbF9uYXZfZGl2aWRlcicgKS5hZGRDbGFzcyggJ3dwYmNfdWlfX2hpZGUnICk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBY3Rpb24gb24gY2xpY2sgXCJHbyBCYWNrXCIgLSBzaG93IHJvb3QgbWVudVxyXG4gKiBvciBzb21lIG90aGVyIHNlY3Rpb24gaW4gcmlnaHQgc2lkZWJhci5cclxuICpcclxuICogQHBhcmFtIHN0cmluZyBtZW51X3RvX3Nob3cgLSBtZW51IHNsdWcuXHJcbiAqL1xyXG5mdW5jdGlvbiB3cGJjX2FkbWluX3VpX19zaWRlYmFyX3JpZ2h0X19zaG93X3NlY3Rpb24oIG1lbnVfdG9fc2hvdyApIHtcclxuXHRqUXVlcnkoICcud3BiY191aV9lbF9fdmVydF9yaWdodF9iYXJfX3NlY3Rpb24nICkuYWRkQ2xhc3MoICd3cGJjX3VpX19oaWRlJyApXHJcblx0alF1ZXJ5KCAnLndwYmNfdWlfZWxfX3ZlcnRfcmlnaHRfYmFyX19zZWN0aW9uXycgKyBtZW51X3RvX3Nob3cgKS5yZW1vdmVDbGFzcyggJ3dwYmNfdWlfX2hpZGUnICk7XHJcbn1cclxuXHJcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG4vLyA9PSBFbmQgUmlnaHQgU2lkZSBCYXIgIHNlY3Rpb24gICA9PVxyXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuXHJcbi8qKlxyXG4gKiBHZXQgYW5jaG9yKHMpIGFycmF5ICBmcm9tICBVUkwuXHJcbiAqIERvYzogaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvQVBJL0xvY2F0aW9uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsqW119XHJcbiAqL1xyXG5mdW5jdGlvbiB3cGJjX3VybF9nZXRfYW5jaG9yc19hcnIoKSB7XHJcblx0dmFyIGhhc2hlcyAgICAgICAgICAgID0gd2luZG93LmxvY2F0aW9uLmhhc2gucmVwbGFjZSggJyUyMycsICcjJyApO1xyXG5cdHZhciBoYXNoZXNfYXJyICAgICAgICA9IGhhc2hlcy5zcGxpdCggJyMnICk7XHJcblx0dmFyIHJlc3VsdCAgICAgICAgICAgID0gW107XHJcblx0dmFyIGhhc2hlc19hcnJfbGVuZ3RoID0gaGFzaGVzX2Fyci5sZW5ndGg7XHJcblxyXG5cdGZvciAoIHZhciBpID0gMDsgaSA8IGhhc2hlc19hcnJfbGVuZ3RoOyBpKysgKSB7XHJcblx0XHRpZiAoIGhhc2hlc19hcnJbaV0ubGVuZ3RoID4gMCApIHtcclxuXHRcdFx0cmVzdWx0LnB1c2goIGhhc2hlc19hcnJbaV0gKTtcclxuXHRcdH1cclxuXHR9XHJcblx0cmV0dXJuIHJlc3VsdDtcclxufVxyXG5cclxuLyoqXHJcbiAqIEF1dG8gRXhwYW5kIFNldHRpbmdzIHNlY3Rpb24gYmFzZWQgb24gVVJMIGFuY2hvciwgYWZ0ZXIgIHBhZ2UgbG9hZGVkLlxyXG4gKi9cclxualF1ZXJ5KCBkb2N1bWVudCApLnJlYWR5KCBmdW5jdGlvbiAoKSB7IHdwYmNfYWRtaW5fdWlfX3JlZGlyZWN0X2xlZ2FjeV9nZW5lcmFsX2F2YWlsYWJpbGl0eV91cmwoKTsgfSApO1xyXG5qUXVlcnkoIGRvY3VtZW50ICkucmVhZHkoIGZ1bmN0aW9uICgpIHsgd3BiY19hZG1pbl91aV9fZG9fZXhwYW5kX3NlY3Rpb24oKTsgc2V0VGltZW91dCggJ3dwYmNfYWRtaW5fdWlfX2RvX2V4cGFuZF9zZWN0aW9uJywgMTAgKTsgfSApO1xyXG5qUXVlcnkoIGRvY3VtZW50ICkucmVhZHkoIGZ1bmN0aW9uICgpIHsgd3BiY19hZG1pbl91aV9fZG9fZXhwYW5kX3NlY3Rpb24oKTsgc2V0VGltZW91dCggJ3dwYmNfYWRtaW5fdWlfX2RvX2V4cGFuZF9zZWN0aW9uJywgMTUwICk7IH0gKTtcclxuXHJcbi8qKlxyXG4gKiBSZWRpcmVjdCBvbGQgU2V0dGluZ3MgPiBBdmFpbGFiaWxpdHkgYW5jaG9ycyB0byB0aGUgZGVkaWNhdGVkIEdlbmVyYWwgQXZhaWxhYmlsaXR5IHBhZ2UuXHJcbiAqL1xyXG5mdW5jdGlvbiB3cGJjX2FkbWluX3VpX19yZWRpcmVjdF9sZWdhY3lfZ2VuZXJhbF9hdmFpbGFiaWxpdHlfdXJsKCkge1xyXG5cclxuXHRpZiAoXHJcblx0XHQgICAoIHdpbmRvdy5sb2NhdGlvbi5ocmVmLmluZGV4T2YoICdwYWdlPXdwYmMtc2V0dGluZ3MnICkgPiAtMSApXHJcblx0XHQmJiAoXHJcblx0XHRcdCAgICggd2luZG93LmxvY2F0aW9uLmhhc2guaW5kZXhPZiggJ3dwYmNfZ2VuZXJhbF9zZXR0aW5nc19hdmFpbGFiaWxpdHlfbWV0YWJveCcgKSA+IC0xIClcclxuXHRcdFx0fHwgKCB3aW5kb3cubG9jYXRpb24uaGFzaC5pbmRleE9mKCAnd3BiY19nZW5lcmFsX3NldHRpbmdzX2F2YWlsYWJpbGl0eV90YWInICkgPiAtMSApXHJcblx0XHQpXHJcblx0KSB7XHJcblx0XHR3aW5kb3cubG9jYXRpb24ucmVwbGFjZSggd2luZG93LmxvY2F0aW9uLmhyZWYuc3BsaXQoICc/JyApWzBdICsgJz9wYWdlPXdwYmMtYXZhaWxhYmlsaXR5JnRhYj1nZW5lcmFsX2F2YWlsYWJpbGl0eScgKTtcclxuXHR9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFeHBhbmQgc2VjdGlvbiBpbiAgR2VuZXJhbCBTZXR0aW5ncyBwYWdlIGFuZCBzZWxlY3QgTWVudSBpdGVtLlxyXG4gKi9cclxuZnVuY3Rpb24gd3BiY19hZG1pbl91aV9fZG9fZXhwYW5kX3NlY3Rpb24oKSB7XHJcblxyXG5cdC8vIHdpbmRvdy5sb2NhdGlvbi5oYXNoICA9ICNzZWN0aW9uX2lkICAvICBkb2M6IGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0FQSS9Mb2NhdGlvbiAuXHJcblx0dmFyIGFuY2hvcnNfYXJyICAgICAgICA9IHdwYmNfdXJsX2dldF9hbmNob3JzX2FycigpO1xyXG5cdHZhciBhbmNob3JzX2Fycl9sZW5ndGggPSBhbmNob3JzX2Fyci5sZW5ndGg7XHJcblxyXG5cdGlmICggYW5jaG9yc19hcnJfbGVuZ3RoID4gMCApIHtcclxuXHRcdHZhciBvbmVfYW5jaG9yX3Byb3BfdmFsdWUgPSBhbmNob3JzX2FyclswXS5zcGxpdCggJ2RvX2V4cGFuZF9fJyApO1xyXG5cdFx0aWYgKCBvbmVfYW5jaG9yX3Byb3BfdmFsdWUubGVuZ3RoID4gMSApIHtcclxuXHJcblx0XHRcdC8vICd3cGJjX2dlbmVyYWxfc2V0dGluZ3NfY2FsZW5kYXJfbWV0YWJveCdcclxuXHRcdFx0dmFyIHNlY3Rpb25fdG9fc2hvdyAgICA9IG9uZV9hbmNob3JfcHJvcF92YWx1ZVsxXTtcclxuXHRcdFx0dmFyIHNlY3Rpb25faWRfdG9fc2hvdyA9ICcjJyArIHNlY3Rpb25fdG9fc2hvdztcclxuXHJcblxyXG5cdFx0XHQvLyAtLSBSZW1vdmUgc2VsZWN0ZWQgYmFja2dyb3VuZCBpbiBhbGwgbGVmdCAgbWVudSAgaXRlbXMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHRcdGpRdWVyeSggJy53cGJjX3VpX2VsX192ZXJ0X25hdl9pdGVtICcgKS5yZW1vdmVDbGFzcyggJ2FjdGl2ZScgKTtcclxuXHRcdFx0Ly8gU2V0IGxlZnQgbWVudSBzZWxlY3RlZC5cclxuXHRcdFx0alF1ZXJ5KCAnLmRvX2V4cGFuZF9fJyArIHNlY3Rpb25fdG9fc2hvdyArICdfbGluaycgKS5hZGRDbGFzcyggJ2FjdGl2ZScgKTtcclxuXHRcdFx0dmFyIHNlbGVjdGVkX3RpdGxlID0galF1ZXJ5KCAnLmRvX2V4cGFuZF9fJyArIHNlY3Rpb25fdG9fc2hvdyArICdfbGluayBhIC53cGJjX3VpX2VsX192ZXJ0X25hdl90aXRsZSAnICkudGV4dCgpO1xyXG5cclxuXHRcdFx0Ly8gRXhwYW5kIHNlY3Rpb24sIGlmIGl0IGNvbGFwc2VkLlxyXG5cdFx0XHRpZiAoICEgalF1ZXJ5KCAnLmRvX2V4cGFuZF9fJyArIHNlY3Rpb25fdG9fc2hvdyArICdfbGluaycgKS5wYXJlbnRzKCAnLndwYmNfdWlfZWxfX2xldmVsX19mb2xkZXInICkuaGFzQ2xhc3MoICdleHBhbmRlZCcgKSApIHtcclxuXHRcdFx0XHRqUXVlcnkoICcud3BiY191aV9lbF9fbGV2ZWxfX2ZvbGRlcicgKS5yZW1vdmVDbGFzcyggJ2V4cGFuZGVkJyApO1xyXG5cdFx0XHRcdGpRdWVyeSggJy5kb19leHBhbmRfXycgKyBzZWN0aW9uX3RvX3Nob3cgKyAnX2xpbmsnICkucGFyZW50cyggJy53cGJjX3VpX2VsX19sZXZlbF9fZm9sZGVyJyApLmFkZENsYXNzKCAnZXhwYW5kZWQnICk7XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIC0tIEV4cGFuZCBzZWN0aW9uIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdFx0XHR2YXIgY29udGFpbmVyX3RvX2hpZGVfY2xhc3MgPSAnLnBvc3Rib3gnO1xyXG5cdFx0XHQvLyBIaWRlIHNlY3Rpb25zICcucG9zdGJveCcgaW4gYWRtaW4gcGFnZSBhbmQgc2hvdyBzcGVjaWZpYyBvbmUuXHJcblx0XHRcdGpRdWVyeSggJy53cGJjX2FkbWluX3BhZ2UgJyArIGNvbnRhaW5lcl90b19oaWRlX2NsYXNzICkuaGlkZSgpO1xyXG5cdFx0XHRqUXVlcnkoICcud3BiY19jb250YWluZXJfYWx3YXlzX2hpZGVfX29uX2xlZnRfbmF2X2NsaWNrJyApLmhpZGUoKTtcclxuXHRcdFx0alF1ZXJ5KCBzZWN0aW9uX2lkX3RvX3Nob3cgKS5zaG93KCk7XHJcblxyXG5cdFx0XHQvLyBTaG93IGFsbCBvdGhlciBzZWN0aW9ucywgIGlmIHByb3ZpZGVkIGluIFVSTDogLi4/cGFnZT13cGJjLXNldHRpbmdzI2RvX2V4cGFuZF9fd3BiY19nZW5lcmFsX3NldHRpbmdzX2NhcGFjaXR5X21ldGFib3gjd3BiY19nZW5lcmFsX3NldHRpbmdzX2NhcGFjaXR5X3VwZ3JhZGVfbWV0YWJveCAuXHJcblx0XHRcdGZvciAoIGxldCBpID0gMTsgaSA8IGFuY2hvcnNfYXJyX2xlbmd0aDsgaSsrICkge1xyXG5cdFx0XHRcdGpRdWVyeSggJyMnICsgYW5jaG9yc19hcnJbaV0gKS5zaG93KCk7XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICggZmFsc2UgKSB7XHJcblx0XHRcdFx0dmFyIHRhcmdldE9mZnNldCA9IHdwYmNfc2Nyb2xsX3RvKCBzZWN0aW9uX2lkX3RvX3Nob3cgKTtcclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gLS0gU2V0IFZhbHVlIHRvIElucHV0IGFib3V0IHNlbGVjdGVkIE5hdiBlbGVtZW50ICAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gICAgICAgLy8gRml4SW46IDkuOC42LjEuXHJcblx0XHRcdHZhciBzZWN0aW9uX2lkX3RhYiA9IHNlY3Rpb25faWRfdG9fc2hvdy5zdWJzdHJpbmcoIDAsIHNlY3Rpb25faWRfdG9fc2hvdy5sZW5ndGggLSA4ICkgKyAnX3RhYic7XHJcblx0XHRcdGlmICggY29udGFpbmVyX3RvX2hpZGVfY2xhc3MgPT0gc2VjdGlvbl9pZF90b19zaG93ICkge1xyXG5cdFx0XHRcdHNlY3Rpb25faWRfdGFiID0gJyN3cGJjX2dlbmVyYWxfc2V0dGluZ3NfYWxsX3RhYidcclxuXHRcdFx0fVxyXG5cdFx0XHRpZiAoICcjd3BiY19nZW5lcmFsX3NldHRpbmdzX2NhcGFjaXR5X21ldGFib3gsI3dwYmNfZ2VuZXJhbF9zZXR0aW5nc19jYXBhY2l0eV91cGdyYWRlX21ldGFib3gnID09IHNlY3Rpb25faWRfdG9fc2hvdyApIHtcclxuXHRcdFx0XHRzZWN0aW9uX2lkX3RhYiA9ICcjd3BiY19nZW5lcmFsX3NldHRpbmdzX2NhcGFjaXR5X3RhYidcclxuXHRcdFx0fVxyXG5cdFx0XHRqUXVlcnkoICcjZm9ybV92aXNpYmxlX3NlY3Rpb24nICkudmFsKCBzZWN0aW9uX2lkX3RhYiApO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8vIExpa2UgYmxpbmtpbmcgc29tZSBlbGVtZW50cy5cclxuXHRcdHdwYmNfYWRtaW5fdWlfX2RvX19hbmNob3JfX2Fub3RoZXJfYWN0aW9ucygpO1xyXG5cdH1cclxufVxyXG5cclxuZnVuY3Rpb24gd3BiY19hZG1pbl91aV9faXNfaW5fbW9iaWxlX3NjcmVlbl9zaXplKCkge1xyXG5cdHJldHVybiB3cGJjX2FkbWluX3VpX19pc19pbl90aGlzX3NjcmVlbl9zaXplKCA2MDUgKTtcclxufVxyXG5cclxuZnVuY3Rpb24gd3BiY19hZG1pbl91aV9faXNfaW5fdGhpc19zY3JlZW5fc2l6ZShzaXplKSB7XHJcblx0cmV0dXJuICh3aW5kb3cuc2NyZWVuLndpZHRoIDw9IHNpemUpO1xyXG59XHJcblxyXG4vKipcclxuICogT3BlbiBzZXR0aW5ncyBwYWdlICB8ICBFeHBhbmQgc2VjdGlvbiAgfCAgU2VsZWN0IE1lbnUgaXRlbS5cclxuICovXHJcbmZ1bmN0aW9uIHdwYmNfYWRtaW5fdWlfX2RvX19vcGVuX3VybF9fZXhwYW5kX3NlY3Rpb24odXJsLCBzZWN0aW9uX2lkKSB7XHJcblxyXG5cdC8vIHdpbmRvdy5sb2NhdGlvbi5ocmVmID0gdXJsICsgJyZkb19leHBhbmQ9JyArIHNlY3Rpb25faWQgKyAnI2RvX2V4cGFuZF9fJyArIHNlY3Rpb25faWQ7IC8vLlxyXG5cdHdpbmRvdy5sb2NhdGlvbi5ocmVmID0gdXJsICsgJyNkb19leHBhbmRfXycgKyBzZWN0aW9uX2lkO1xyXG5cclxuXHRpZiAoIHdwYmNfYWRtaW5fdWlfX2lzX2luX21vYmlsZV9zY3JlZW5fc2l6ZSgpICkge1xyXG5cdFx0d3BiY19hZG1pbl91aV9fc2lkZWJhcl9sZWZ0X19kb19taW4oKTtcclxuXHR9XHJcblxyXG5cdHdwYmNfYWRtaW5fdWlfX2RvX2V4cGFuZF9zZWN0aW9uKCk7XHJcbn1cclxuXHJcblxyXG4vKipcclxuICogQ2hlY2sgIGZvciBPdGhlciBhY3Rpb25zOiAgTGlrZSBibGlua2luZyBzb21lIGVsZW1lbnRzIGluIHNldHRpbmdzIHBhZ2UuIEUuZy4gRGF5cyBzZWxlY3Rpb24gIG9yICBjaGFuZ2Utb3ZlciBkYXlzLlxyXG4gKi9cclxuZnVuY3Rpb24gd3BiY19hZG1pbl91aV9fZG9fX2FuY2hvcl9fYW5vdGhlcl9hY3Rpb25zKCkge1xyXG5cclxuXHR2YXIgYW5jaG9yc19hcnIgICAgICAgID0gd3BiY191cmxfZ2V0X2FuY2hvcnNfYXJyKCk7XHJcblx0dmFyIGFuY2hvcnNfYXJyX2xlbmd0aCA9IGFuY2hvcnNfYXJyLmxlbmd0aDtcclxuXHJcblx0Ly8gT3RoZXIgYWN0aW9uczogIExpa2UgYmxpbmtpbmcgc29tZSBlbGVtZW50cy5cclxuXHRmb3IgKCB2YXIgaSA9IDA7IGkgPCBhbmNob3JzX2Fycl9sZW5ndGg7IGkrKyApIHtcclxuXHJcblx0XHR2YXIgdGhpc19hbmNob3IgPSBhbmNob3JzX2FycltpXTtcclxuXHJcblx0XHR2YXIgdGhpc19hbmNob3JfcHJvcF92YWx1ZSA9IHRoaXNfYW5jaG9yLnNwbGl0KCAnZG9fb3RoZXJfYWN0aW9uc19fJyApO1xyXG5cclxuXHRcdGlmICggdGhpc19hbmNob3JfcHJvcF92YWx1ZS5sZW5ndGggPiAxICkge1xyXG5cclxuXHRcdFx0dmFyIHNlY3Rpb25fYWN0aW9uID0gdGhpc19hbmNob3JfcHJvcF92YWx1ZVsxXTtcclxuXHJcblx0XHRcdHN3aXRjaCAoIHNlY3Rpb25fYWN0aW9uICkge1xyXG5cclxuXHRcdFx0XHRjYXNlICdibGlua19kYXlfc2VsZWN0aW9ucyc6XHJcblx0XHRcdFx0XHQvLyB3cGJjX3VpX3NldHRpbmdzX19wYW5lbF9fY2xpY2soICcjd3BiY19nZW5lcmFsX3NldHRpbmdzX2NhbGVuZGFyX3RhYiBhJywgJyN3cGJjX2dlbmVyYWxfc2V0dGluZ3NfY2FsZW5kYXJfbWV0YWJveCcsICdEYXlzIFNlbGVjdGlvbicgKTsuXHJcblx0XHRcdFx0XHR3cGJjX2JsaW5rX2VsZW1lbnQoICcud3BiY190cl9zZXRfZ2VuX2Jvb2tpbmdfdHlwZV9vZl9kYXlfc2VsZWN0aW9ucycsIDQsIDM1MCApO1xyXG5cdFx0XHRcdFx0XHR3cGJjX3Njcm9sbF90byggJy53cGJjX3RyX3NldF9nZW5fYm9va2luZ190eXBlX29mX2RheV9zZWxlY3Rpb25zJyApO1xyXG5cdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdGNhc2UgJ2JsaW5rX2NoYW5nZV9vdmVyX2RheXMnOlxyXG5cdFx0XHRcdFx0Ly8gd3BiY191aV9zZXR0aW5nc19fcGFuZWxfX2NsaWNrKCAnI3dwYmNfZ2VuZXJhbF9zZXR0aW5nc19jYWxlbmRhcl90YWIgYScsICcjd3BiY19nZW5lcmFsX3NldHRpbmdzX2NhbGVuZGFyX21ldGFib3gnLCAnQ2hhbmdlb3ZlciBEYXlzJyApOy5cclxuXHRcdFx0XHRcdHdwYmNfYmxpbmtfZWxlbWVudCggJy53cGJjX3RyX3NldF9nZW5fYm9va2luZ19yYW5nZV9zZWxlY3Rpb25fdGltZV9pc19hY3RpdmUnLCA0LCAzNTAgKTtcclxuXHRcdFx0XHRcdFx0d3BiY19zY3JvbGxfdG8oICcud3BiY190cl9zZXRfZ2VuX2Jvb2tpbmdfcmFuZ2Vfc2VsZWN0aW9uX3RpbWVfaXNfYWN0aXZlJyApO1xyXG5cdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdGNhc2UgJ2JsaW5rX2NhcHRjaGEnOlxyXG5cdFx0XHRcdFx0d3BiY19ibGlua19lbGVtZW50KCAnLndwYmNfdHJfc2V0X2dlbl9ib29raW5nX2lzX3VzZV9jYXB0Y2hhJywgNCwgMzUwICk7XHJcblx0XHRcdFx0XHRcdHdwYmNfc2Nyb2xsX3RvKCAnLndwYmNfdHJfc2V0X2dlbl9ib29raW5nX2lzX3VzZV9jYXB0Y2hhJyApO1xyXG5cdFx0XHRcdFx0YnJlYWs7XHJcblxyXG5cdFx0XHRcdGRlZmF1bHQ6XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHR9XHJcbn1cclxuIiwiLyoqXHJcbiAqIENvcHkgdHh0IHRvIGNsaXBicmQgZnJvbSBUZXh0IGZpZWxkcy5cclxuICpcclxuICogQHBhcmFtIGh0bWxfZWxlbWVudF9pZCAgLSBlLmcuICdkYXRhX2ZpZWxkJ1xyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn1cclxuICovXHJcbmZ1bmN0aW9uIHdwYmNfY29weV90ZXh0X3RvX2NsaXBicmRfZnJvbV9lbGVtZW50KCBodG1sX2VsZW1lbnRfaWQgKSB7XHJcblx0Ly8gR2V0IHRoZSB0ZXh0IGZpZWxkLlxyXG5cdHZhciBjb3B5VGV4dCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCBodG1sX2VsZW1lbnRfaWQgKTtcclxuXHJcblx0Ly8gU2VsZWN0IHRoZSB0ZXh0IGZpZWxkLlxyXG5cdGNvcHlUZXh0LnNlbGVjdCgpO1xyXG5cdGNvcHlUZXh0LnNldFNlbGVjdGlvblJhbmdlKCAwLCA5OTk5OSApOyAvLyBGb3IgbW9iaWxlIGRldmljZXMuXHJcblxyXG5cdC8vIENvcHkgdGhlIHRleHQgaW5zaWRlIHRoZSB0ZXh0IGZpZWxkLlxyXG5cdHZhciBpc19jb3BpZWQgPSB3cGJjX2NvcHlfdGV4dF90b19jbGlwYnJkKCBjb3B5VGV4dC52YWx1ZSApO1xyXG5cdGlmICggISBpc19jb3BpZWQgKSB7XHJcblx0XHRjb25zb2xlLmVycm9yKCAnT29wcywgdW5hYmxlIHRvIGNvcHknLCBjb3B5VGV4dC52YWx1ZSApO1xyXG5cdH1cclxuXHRyZXR1cm4gaXNfY29waWVkO1xyXG59XHJcblxyXG4vKipcclxuICogQ29weSB0eHQgdG8gY2xpcGJyZC5cclxuICpcclxuICogQHBhcmFtIHRleHRcclxuICogQHJldHVybnMge2Jvb2xlYW59XHJcbiAqL1xyXG5mdW5jdGlvbiB3cGJjX2NvcHlfdGV4dF90b19jbGlwYnJkKHRleHQpIHtcclxuXHJcblx0aWYgKCAhIG5hdmlnYXRvci5jbGlwYm9hcmQgKSB7XHJcblx0XHRyZXR1cm4gd3BiY19mYWxsYmFja19jb3B5X3RleHRfdG9fY2xpcGJyZCggdGV4dCApO1xyXG5cdH1cclxuXHJcblx0bmF2aWdhdG9yLmNsaXBib2FyZC53cml0ZVRleHQoIHRleHQgKS50aGVuKFxyXG5cdFx0ZnVuY3Rpb24gKCkge1xyXG5cdFx0XHQvLyBjb25zb2xlLmxvZyggJ0FzeW5jOiBDb3B5aW5nIHRvIGNsaXBib2FyZCB3YXMgc3VjY2Vzc2Z1bCEnICk7LlxyXG5cdFx0XHRyZXR1cm4gIHRydWU7XHJcblx0XHR9LFxyXG5cdFx0ZnVuY3Rpb24gKGVycikge1xyXG5cdFx0XHQvLyBjb25zb2xlLmVycm9yKCAnQXN5bmM6IENvdWxkIG5vdCBjb3B5IHRleHQ6ICcsIGVyciApOy5cclxuXHRcdFx0cmV0dXJuICBmYWxzZTtcclxuXHRcdH1cclxuXHQpO1xyXG59XHJcblxyXG4vKipcclxuICogQ29weSB0eHQgdG8gY2xpcGJyZCAtIGRlcHJpY2F0ZWQgbWV0aG9kLlxyXG4gKlxyXG4gKiBAcGFyYW0gdGV4dFxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn1cclxuICovXHJcbmZ1bmN0aW9uIHdwYmNfZmFsbGJhY2tfY29weV90ZXh0X3RvX2NsaXBicmQoIHRleHQgKSB7XHJcblxyXG5cdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0Ly8gdmFyIHRleHRBcmVhICAgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCBcInRleHRhcmVhXCIgKTtcclxuXHQvLyB0ZXh0QXJlYS52YWx1ZSA9IHRleHQ7XHJcblx0Ly9cclxuXHQvLyAvLyBBdm9pZCBzY3JvbGxpbmcgdG8gYm90dG9tLlxyXG5cdC8vIHRleHRBcmVhLnN0eWxlLnRvcCAgICAgID0gXCIwXCI7XHJcblx0Ly8gdGV4dEFyZWEuc3R5bGUubGVmdCAgICAgPSBcIjBcIjtcclxuXHQvLyB0ZXh0QXJlYS5zdHlsZS5wb3NpdGlvbiA9IFwiZml4ZWRcIjtcclxuXHQvLyB0ZXh0QXJlYS5zdHlsZS56SW5kZXggICA9IFwiOTk5OTk5OTk5XCI7XHJcblx0Ly8gZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZCggdGV4dEFyZWEgKTtcclxuXHQvLyB0ZXh0QXJlYS5mb2N1cygpO1xyXG5cdC8vIHRleHRBcmVhLnNlbGVjdCgpO1xyXG5cclxuXHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdC8vIE5vdyBnZXQgaXQgYXMgSFRNTCAgKG9yaWdpbmFsIGhlcmUgaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMzQxOTE3ODAvamF2YXNjcmlwdC1jb3B5LXN0cmluZy10by1jbGlwYm9hcmQtYXMtdGV4dC1odG1sICkuXHJcblxyXG5cdC8vIFsxXSAtIENyZWF0ZSBjb250YWluZXIgZm9yIHRoZSBIVE1MLlxyXG5cdHZhciBjb250YWluZXIgICAgICAgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCAnZGl2JyApO1xyXG5cdGNvbnRhaW5lci5pbm5lckhUTUwgPSB0ZXh0O1xyXG5cclxuXHQvLyBbMl0gLSBIaWRlIGVsZW1lbnQuXHJcblx0Y29udGFpbmVyLnN0eWxlLnBvc2l0aW9uICAgICAgPSAnZml4ZWQnO1xyXG5cdGNvbnRhaW5lci5zdHlsZS5wb2ludGVyRXZlbnRzID0gJ25vbmUnO1xyXG5cdGNvbnRhaW5lci5zdHlsZS5vcGFjaXR5ICAgICAgID0gMDtcclxuXHJcblx0Ly8gRGV0ZWN0IGFsbCBzdHlsZSBzaGVldHMgb2YgdGhlIHBhZ2UuXHJcblx0dmFyIGFjdGl2ZVNoZWV0cyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKCBkb2N1bWVudC5zdHlsZVNoZWV0cyApLmZpbHRlcihcclxuXHRcdGZ1bmN0aW9uIChzaGVldCkge1xyXG5cdFx0XHRyZXR1cm4gISBzaGVldC5kaXNhYmxlZDtcclxuXHRcdH1cclxuXHQpO1xyXG5cclxuXHQvLyBbM10gLSBNb3VudCB0aGUgY29udGFpbmVyIHRvIHRoZSBET00gdG8gbWFrZSBgY29udGVudFdpbmRvd2AgYXZhaWxhYmxlLlxyXG5cdGRvY3VtZW50LmJvZHkuYXBwZW5kQ2hpbGQoIGNvbnRhaW5lciApO1xyXG5cclxuXHQvLyBbNF0gLSBDb3B5IHRvIGNsaXBib2FyZC5cclxuXHR3aW5kb3cuZ2V0U2VsZWN0aW9uKCkucmVtb3ZlQWxsUmFuZ2VzKCk7XHJcblxyXG5cdHZhciByYW5nZSA9IGRvY3VtZW50LmNyZWF0ZVJhbmdlKCk7XHJcblx0cmFuZ2Uuc2VsZWN0Tm9kZSggY29udGFpbmVyICk7XHJcblx0d2luZG93LmdldFNlbGVjdGlvbigpLmFkZFJhbmdlKCByYW5nZSApO1xyXG5cdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblxyXG5cdHZhciByZXN1bHQgPSBmYWxzZTtcclxuXHJcblx0dHJ5IHtcclxuXHRcdHJlc3VsdCA9IGRvY3VtZW50LmV4ZWNDb21tYW5kKCAnY29weScgKTtcclxuXHRcdC8vIGNvbnNvbGUubG9nKCAnRmFsbGJhY2s6IENvcHlpbmcgdGV4dCBjb21tYW5kIHdhcyAnICsgbXNnICk7IC8vLlxyXG5cdH0gY2F0Y2ggKCBlcnIgKSB7XHJcblx0XHQvLyBjb25zb2xlLmVycm9yKCAnRmFsbGJhY2s6IE9vcHMsIHVuYWJsZSB0byBjb3B5JywgZXJyICk7IC8vLlxyXG5cdH1cclxuXHQvLyBkb2N1bWVudC5ib2R5LnJlbW92ZUNoaWxkKCB0ZXh0QXJlYSApOyAvLy5cclxuXHJcblx0Ly8gWzUuNF0gLSBFbmFibGUgQ1NTLlxyXG5cdHZhciBhY3RpdmVTaGVldHNfbGVuZ3RoID0gYWN0aXZlU2hlZXRzLmxlbmd0aDtcclxuXHRmb3IgKCB2YXIgaSA9IDA7IGkgPCBhY3RpdmVTaGVldHNfbGVuZ3RoOyBpKysgKSB7XHJcblx0XHRhY3RpdmVTaGVldHNbaV0uZGlzYWJsZWQgPSBmYWxzZTtcclxuXHR9XHJcblxyXG5cdC8vIFs2XSAtIFJlbW92ZSB0aGUgY29udGFpbmVyXHJcblx0ZG9jdW1lbnQuYm9keS5yZW1vdmVDaGlsZCggY29udGFpbmVyICk7XHJcblxyXG5cdHJldHVybiAgcmVzdWx0O1xyXG59IiwiLyoqXHJcbiAqIFdQQkMgQ29sbGFwc2libGUgR3JvdXBzXHJcbiAqXHJcbiAqIFVuaXZlcnNhbCwgZGVwZW5kZW5jeS1mcmVlIGNvbnRyb2xsZXIgZm9yIGV4cGFuZGluZy9jb2xsYXBzaW5nIGdyb3VwZWQgc2VjdGlvbnMgaW4gcmlnaHQtc2lkZSBwYW5lbHMgKEluc3BlY3Rvci9MaWJyYXJ5L0Zvcm0gU2V0dGluZ3MsIG9yIGFueSBvdGhlciBXUEJDIHBhZ2UpLlxyXG4gKlxyXG4gKiBcdFx0PT09IEhvdyB0byB1c2UgaXQgKHF1aWNrKSA/ID09PVxyXG4gKlxyXG4gKlx0XHQtLSAxLiBNYXJrdXAgKGluZGVwZW5kZW50IG1vZGU6IG11bHRpcGxlIG9wZW4gYWxsb3dlZCkgLS1cclxuICpcdFx0XHQ8ZGl2IGNsYXNzPVwid3BiY19jb2xsYXBzaWJsZVwiPlxyXG4gKlx0XHRcdCAgPHNlY3Rpb24gY2xhc3M9XCJ3cGJjX3VpX19jb2xsYXBzaWJsZV9ncm91cCBpcy1vcGVuXCI+XHJcbiAqXHRcdFx0XHQ8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cImdyb3VwX19oZWFkZXJcIj48aDM+R2VuZXJhbDwvaDM+PC9idXR0b24+XHJcbiAqXHRcdFx0XHQ8ZGl2IGNsYXNzPVwiZ3JvdXBfX2ZpZWxkc1wiPuKApjwvZGl2PlxyXG4gKlx0XHRcdCAgPC9zZWN0aW9uPlxyXG4gKlx0XHRcdCAgPHNlY3Rpb24gY2xhc3M9XCJ3cGJjX3VpX19jb2xsYXBzaWJsZV9ncm91cFwiPlxyXG4gKlx0XHRcdFx0PGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJncm91cF9faGVhZGVyXCI+PGgzPkFkdmFuY2VkPC9oMz48L2J1dHRvbj5cclxuICpcdFx0XHRcdDxkaXYgY2xhc3M9XCJncm91cF9fZmllbGRzXCI+4oCmPC9kaXY+XHJcbiAqXHRcdFx0ICA8L3NlY3Rpb24+XHJcbiAqXHRcdFx0PC9kaXY+XHJcbiAqXHJcbiAqXHRcdC0tIDIuIEV4Y2x1c2l2ZS9hY2NvcmRpb24gbW9kZSAob25lIG9wZW4gYXQgYSB0aW1lKSAtLVxyXG4gKlx0XHRcdDxkaXYgY2xhc3M9XCJ3cGJjX2NvbGxhcHNpYmxlIHdwYmNfY29sbGFwc2libGUtLWV4Y2x1c2l2ZVwiPuKApjwvZGl2PlxyXG4gKlxyXG4gKlx0XHQtLSAzLiBBdXRvLWluaXQgLS1cclxuICpcdFx0XHRUaGUgc2NyaXB0IGF1dG8taW5pdGlhbGl6ZXMgb24gRE9NQ29udGVudExvYWRlZC4gTm8gZXh0cmEgY29kZSBuZWVkZWQuXHJcbiAqXHJcbiAqXHRcdC0tIDQuIFByb2dyYW1tYXRpYyBjb250cm9sIChvcHRpb25hbClcclxuICpcdFx0XHRjb25zdCByb290ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI3dwYmNfYmZiX19pbnNwZWN0b3InKTtcclxuICpcdFx0XHRjb25zdCBhcGkgID0gcm9vdC5fX3dwYmNfY29sbGFwc2libGVfaW5zdGFuY2U7IC8vIHNldCBieSBhdXRvLWluaXRcclxuICpcclxuICpcdFx0XHRhcGkub3Blbl9ieV9oZWFkaW5nKCdWYWxpZGF0aW9uJyk7IC8vIG9wZW4gYnkgaGVhZGluZyB0ZXh0XHJcbiAqXHRcdFx0YXBpLm9wZW5fYnlfaW5kZXgoMCk7ICAgICAgICAgICAgICAvLyBvcGVuIHRoZSBmaXJzdCBncm91cFxyXG4gKlxyXG4gKlx0XHQtLSA1Lkxpc3RlbiB0byBldmVudHMgKGUuZy4sIHRvIHBlcnNpc3Qg4oCcb3BlbiBncm91cOKAnSBzdGF0ZSkgLS1cclxuICpcdFx0XHRyb290LmFkZEV2ZW50TGlzdGVuZXIoJ3dwYmM6Y29sbGFwc2libGU6b3BlbicsICAoZSkgPT4geyBjb25zb2xlLmxvZyggIGUuZGV0YWlsLmdyb3VwICk7IH0pO1xyXG4gKlx0XHRcdHJvb3QuYWRkRXZlbnRMaXN0ZW5lcignd3BiYzpjb2xsYXBzaWJsZTpjbG9zZScsIChlKSA9PiB7IGNvbnNvbGUubG9nKCAgZS5kZXRhaWwuZ3JvdXAgKTsgfSk7XHJcbiAqXHJcbiAqXHJcbiAqXHJcbiAqIE1hcmt1cCBleHBlY3RhdGlvbnMgKG1pbmltYWwpOlxyXG4gKiAgPGRpdiBjbGFzcz1cIndwYmNfY29sbGFwc2libGUgW3dwYmNfY29sbGFwc2libGUtLWV4Y2x1c2l2ZV1cIj5cclxuICogICAgPHNlY3Rpb24gY2xhc3M9XCJ3cGJjX3VpX19jb2xsYXBzaWJsZV9ncm91cCBbaXMtb3Blbl1cIj5cclxuICogICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cImdyb3VwX19oZWFkZXJcIj4gLi4uIDwvYnV0dG9uPlxyXG4gKiAgICAgIDxkaXYgY2xhc3M9XCJncm91cF9fZmllbGRzXCI+IC4uLiA8L2Rpdj5cclxuICogICAgPC9zZWN0aW9uPlxyXG4gKiAgICAuLi4gbW9yZSA8c2VjdGlvbj4gLi4uXHJcbiAqICA8L2Rpdj5cclxuICpcclxuICogTm90ZXM6XHJcbiAqICAtIEFkZCBgaXMtb3BlbmAgdG8gYW55IHNlY3Rpb24geW91IHdhbnQgaW5pdGlhbGx5IGV4cGFuZGVkLlxyXG4gKiAgLSBBZGQgYHdwYmNfY29sbGFwc2libGUtLWV4Y2x1c2l2ZWAgdG8gdGhlIGNvbnRhaW5lciBmb3IgXCJvcGVuIG9uZSBhdCBhIHRpbWVcIiBiZWhhdmlvci5cclxuICogIC0gV29ya3Mgd2l0aCB5b3VyIGV4aXN0aW5nIEJGQiBtYXJrdXAgKGNsYXNzZXMgdXNlZCB0aGVyZSBhcmUgdGhlIGRlZmF1bHRzKS5cclxuICpcclxuICogQWNjZXNzaWJpbGl0eTpcclxuICogIC0gU2V0cyBhcmlhLWV4cGFuZGVkIG9uIC5ncm91cF9faGVhZGVyXHJcbiAqICAtIFNldHMgYXJpYS1oaWRkZW4gKyBbaGlkZGVuXSBvbiAuZ3JvdXBfX2ZpZWxkc1xyXG4gKiAgLSBBcnJvd1VwL0Fycm93RG93biBtb3ZlIGZvY3VzIGJldHdlZW4gaGVhZGVyczsgRW50ZXIvU3BhY2UgdG9nZ2xlc1xyXG4gKlxyXG4gKiBFdmVudHMgKGJ1YmJsZXMgZnJvbSB0aGUgPHNlY3Rpb24+KTpcclxuICogIC0gJ3dwYmM6Y29sbGFwc2libGU6b3BlbicgIChkZXRhaWw6IHsgZ3JvdXAsIHJvb3QsIGluc3RhbmNlIH0pXHJcbiAqICAtICd3cGJjOmNvbGxhcHNpYmxlOmNsb3NlJyAoZGV0YWlsOiB7IGdyb3VwLCByb290LCBpbnN0YW5jZSB9KVxyXG4gKlxyXG4gKiBQdWJsaWMgQVBJIChpbnN0YW5jZSBtZXRob2RzKTpcclxuICogIC0gaW5pdCgpLCBkZXN0cm95KCksIHJlZnJlc2goKVxyXG4gKiAgLSBleHBhbmQoZ3JvdXAsIFtleGNsdXNpdmVdKSwgY29sbGFwc2UoZ3JvdXApLCB0b2dnbGUoZ3JvdXApXHJcbiAqICAtIG9wZW5fYnlfaW5kZXgoaW5kZXgpLCBvcGVuX2J5X2hlYWRpbmcodGV4dClcclxuICogIC0gaXNfZXhjbHVzaXZlKCksIGlzX29wZW4oZ3JvdXApXHJcbiAqXHJcbiAqIEB2ZXJzaW9uIDIwMjUtMDgtMjZcclxuICogQHNpbmNlIDIwMjUtMDgtMjZcclxuICovXHJcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG4vLyA9PSBGaWxlICAvY29sbGFwc2libGVfZ3JvdXBzLmpzID09IFRpbWUgcG9pbnQ6IDIwMjUtMDgtMjYgMTQ6MTNcclxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcbihmdW5jdGlvbiAodywgZCkge1xyXG5cdCd1c2Ugc3RyaWN0JztcclxuXHJcblx0Y2xhc3MgV1BCQ19Db2xsYXBzaWJsZV9Hcm91cHMge1xyXG5cclxuXHRcdC8qKlxyXG5cdFx0ICogQ3JlYXRlIGEgY29sbGFwc2libGUgY29udHJvbGxlciBmb3IgYSBjb250YWluZXIuXHJcblx0XHQgKlxyXG5cdFx0ICogQHBhcmFtIHtIVE1MRWxlbWVudHxzdHJpbmd9IHJvb3RfZWxcclxuXHRcdCAqICAgICAgICBUaGUgY29udGFpbmVyIGVsZW1lbnQgKG9yIENTUyBzZWxlY3RvcikgdGhhdCB3cmFwcyBjb2xsYXBzaWJsZSBncm91cHMuXHJcblx0XHQgKiAgICAgICAgVGhlIGNvbnRhaW5lciB1c3VhbGx5IGhhcyB0aGUgY2xhc3MgYC53cGJjX2NvbGxhcHNpYmxlYC5cclxuXHRcdCAqIEBwYXJhbSB7T2JqZWN0fSBbb3B0cz17fV1cclxuXHRcdCAqIEBwYXJhbSB7c3RyaW5nfSAgW29wdHMuZ3JvdXBfc2VsZWN0b3I9Jy53cGJjX3VpX19jb2xsYXBzaWJsZV9ncm91cCddXHJcblx0XHQgKiAgICAgICAgU2VsZWN0b3IgZm9yIGVhY2ggY29sbGFwc2libGUgZ3JvdXAgaW5zaWRlIHRoZSBjb250YWluZXIuXHJcblx0XHQgKiBAcGFyYW0ge3N0cmluZ30gIFtvcHRzLmhlYWRlcl9zZWxlY3Rvcj0nLmdyb3VwX19oZWFkZXInXVxyXG5cdFx0ICogICAgICAgIFNlbGVjdG9yIGZvciB0aGUgY2xpY2thYmxlIGhlYWRlciBpbnNpZGUgYSBncm91cC5cclxuXHRcdCAqIEBwYXJhbSB7c3RyaW5nfSAgW29wdHMuZmllbGRzX3NlbGVjdG9yPScuZ3JvdXBfX2ZpZWxkcyddXHJcblx0XHQgKiAgICAgICAgU2VsZWN0b3IgZm9yIHRoZSBjb250ZW50L3BhbmVsIGVsZW1lbnQgaW5zaWRlIGEgZ3JvdXAuXHJcblx0XHQgKiBAcGFyYW0ge3N0cmluZ30gIFtvcHRzLm9wZW5fY2xhc3M9J2lzLW9wZW4nXVxyXG5cdFx0ICogICAgICAgIENsYXNzIG5hbWUgdGhhdCBpbmRpY2F0ZXMgdGhlIGdyb3VwIGlzIG9wZW4uXHJcblx0XHQgKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRzLmV4Y2x1c2l2ZT1mYWxzZV1cclxuXHRcdCAqICAgICAgICBJZiB0cnVlLCBvbmx5IG9uZSBncm91cCBjYW4gYmUgb3BlbiBhdCBhIHRpbWUgaW4gdGhpcyBjb250YWluZXIuXHJcblx0XHQgKlxyXG5cdFx0ICogQGNvbnN0cnVjdG9yXHJcblx0XHQgKiBAc2luY2UgMjAyNS0wOC0yNlxyXG5cdFx0ICovXHJcblx0XHRjb25zdHJ1Y3Rvcihyb290X2VsLCBvcHRzID0ge30pIHtcclxuXHRcdFx0dGhpcy5yb290ID0gKHR5cGVvZiByb290X2VsID09PSAnc3RyaW5nJykgPyBkLnF1ZXJ5U2VsZWN0b3IoIHJvb3RfZWwgKSA6IHJvb3RfZWw7XHJcblx0XHRcdHRoaXMub3B0cyA9IE9iamVjdC5hc3NpZ24oIHtcclxuXHRcdFx0XHRncm91cF9zZWxlY3RvciA6ICcud3BiY191aV9fY29sbGFwc2libGVfZ3JvdXAnLFxyXG5cdFx0XHRcdGhlYWRlcl9zZWxlY3RvcjogJy5ncm91cF9faGVhZGVyJyxcclxuXHRcdFx0XHRmaWVsZHNfc2VsZWN0b3I6ICcuZ3JvdXBfX2ZpZWxkcywuZ3JvdXBfX2NvbnRlbnQnLFxyXG5cdFx0XHRcdG9wZW5fY2xhc3MgICAgIDogJ2lzLW9wZW4nLFxyXG5cdFx0XHRcdGV4Y2x1c2l2ZSAgICAgIDogZmFsc2VcclxuXHRcdFx0fSwgb3B0cyApO1xyXG5cclxuXHRcdFx0Ly8gQm91bmQgaGFuZGxlcnMgKGZvciBhZGQvcmVtb3ZlRXZlbnRMaXN0ZW5lciBzeW1tZXRyeSkuXHJcblx0XHRcdC8qKiBAcHJpdmF0ZSAqL1xyXG5cdFx0XHR0aGlzLl9vbl9jbGljayA9IHRoaXMuX29uX2NsaWNrLmJpbmQoIHRoaXMgKTtcclxuXHRcdFx0LyoqIEBwcml2YXRlICovXHJcblx0XHRcdHRoaXMuX29uX2tleWRvd24gPSB0aGlzLl9vbl9rZXlkb3duLmJpbmQoIHRoaXMgKTtcclxuXHJcblx0XHRcdC8qKiBAdHlwZSB7SFRNTEVsZW1lbnRbXX0gQHByaXZhdGUgKi9cclxuXHRcdFx0dGhpcy5fZ3JvdXBzID0gW107XHJcblx0XHRcdC8qKiBAdHlwZSB7TXV0YXRpb25PYnNlcnZlcnxudWxsfSBAcHJpdmF0ZSAqL1xyXG5cdFx0XHR0aGlzLl9vYnNlcnZlciA9IG51bGw7XHJcblx0XHR9XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiBJbml0aWFsaXplIHRoZSBjb250cm9sbGVyOiBjYWNoZSBncm91cHMsIGF0dGFjaCBsaXN0ZW5lcnMsIHNldCBBUklBLFxyXG5cdFx0ICogYW5kIHN0YXJ0IG9ic2VydmluZyBET00gY2hhbmdlcyBpbnNpZGUgdGhlIGNvbnRhaW5lci5cclxuXHRcdCAqXHJcblx0XHQgKiBAcmV0dXJucyB7V1BCQ19Db2xsYXBzaWJsZV9Hcm91cHN9IFRoZSBpbnN0YW5jZSAoY2hhaW5hYmxlKS5cclxuXHRcdCAqIEBsaXN0ZW5zIGNsaWNrXHJcblx0XHQgKiBAbGlzdGVucyBrZXlkb3duXHJcblx0XHQgKiBAc2luY2UgMjAyNS0wOC0yNlxyXG5cdFx0ICovXHJcblx0XHRpbml0KCkge1xyXG5cdFx0XHRpZiAoICF0aGlzLnJvb3QgKSB7XHJcblx0XHRcdFx0cmV0dXJuIHRoaXM7XHJcblx0XHRcdH1cclxuXHRcdFx0dGhpcy5fZ3JvdXBzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoXHJcblx0XHRcdFx0dGhpcy5yb290LnF1ZXJ5U2VsZWN0b3JBbGwoIHRoaXMub3B0cy5ncm91cF9zZWxlY3RvciApXHJcblx0XHRcdCk7XHJcblx0XHRcdHRoaXMucm9vdC5hZGRFdmVudExpc3RlbmVyKCAnY2xpY2snLCB0aGlzLl9vbl9jbGljaywgZmFsc2UgKTtcclxuXHRcdFx0dGhpcy5yb290LmFkZEV2ZW50TGlzdGVuZXIoICdrZXlkb3duJywgdGhpcy5fb25fa2V5ZG93biwgZmFsc2UgKTtcclxuXHJcblx0XHRcdC8vIE9ic2VydmUgZHluYW1pYyBpbnNlcnRzL3JlbW92YWxzIChJbnNwZWN0b3IgcmUtcmVuZGVycykuXHJcblx0XHRcdHRoaXMuX29ic2VydmVyID0gbmV3IE11dGF0aW9uT2JzZXJ2ZXIoICgpID0+IHtcclxuXHRcdFx0XHR0aGlzLnJlZnJlc2goKTtcclxuXHRcdFx0fSApO1xyXG5cdFx0XHR0aGlzLl9vYnNlcnZlci5vYnNlcnZlKCB0aGlzLnJvb3QsIHsgY2hpbGRMaXN0OiB0cnVlLCBzdWJ0cmVlOiB0cnVlIH0gKTtcclxuXHJcblx0XHRcdHRoaXMuX3N5bmNfYWxsX2FyaWEoKTtcclxuXHRcdFx0cmV0dXJuIHRoaXM7XHJcblx0XHR9XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiBUZWFyIGRvd24gdGhlIGNvbnRyb2xsZXI6IGRldGFjaCBsaXN0ZW5lcnMsIHN0b3AgdGhlIG9ic2VydmVyLFxyXG5cdFx0ICogYW5kIGRyb3AgaW50ZXJuYWwgcmVmZXJlbmNlcy5cclxuXHRcdCAqXHJcblx0XHQgKiBAcmV0dXJucyB7dm9pZH1cclxuXHRcdCAqIEBzaW5jZSAyMDI1LTA4LTI2XHJcblx0XHQgKi9cclxuXHRcdGRlc3Ryb3koKSB7XHJcblx0XHRcdGlmICggIXRoaXMucm9vdCApIHtcclxuXHRcdFx0XHRyZXR1cm47XHJcblx0XHRcdH1cclxuXHRcdFx0dGhpcy5yb290LnJlbW92ZUV2ZW50TGlzdGVuZXIoICdjbGljaycsIHRoaXMuX29uX2NsaWNrLCBmYWxzZSApO1xyXG5cdFx0XHR0aGlzLnJvb3QucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ2tleWRvd24nLCB0aGlzLl9vbl9rZXlkb3duLCBmYWxzZSApO1xyXG5cdFx0XHRpZiAoIHRoaXMuX29ic2VydmVyICkge1xyXG5cdFx0XHRcdHRoaXMuX29ic2VydmVyLmRpc2Nvbm5lY3QoKTtcclxuXHRcdFx0XHR0aGlzLl9vYnNlcnZlciA9IG51bGw7XHJcblx0XHRcdH1cclxuXHRcdFx0dGhpcy5fZ3JvdXBzID0gW107XHJcblx0XHR9XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiBSZS1zY2FuIHRoZSBET00gZm9yIGN1cnJlbnQgZ3JvdXBzIGFuZCByZS1hcHBseSBBUklBIHRvIGFsbCBvZiB0aGVtLlxyXG5cdFx0ICogVXNlZnVsIGFmdGVyIGR5bmFtaWMgKHJlKXJlbmRlcnMuXHJcblx0XHQgKlxyXG5cdFx0ICogQHJldHVybnMge3ZvaWR9XHJcblx0XHQgKiBAc2luY2UgMjAyNS0wOC0yNlxyXG5cdFx0ICovXHJcblx0XHRyZWZyZXNoKCkge1xyXG5cdFx0XHRpZiAoICF0aGlzLnJvb3QgKSB7XHJcblx0XHRcdFx0cmV0dXJuO1xyXG5cdFx0XHR9XHJcblx0XHRcdHRoaXMuX2dyb3VwcyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKFxyXG5cdFx0XHRcdHRoaXMucm9vdC5xdWVyeVNlbGVjdG9yQWxsKCB0aGlzLm9wdHMuZ3JvdXBfc2VsZWN0b3IgKVxyXG5cdFx0XHQpO1xyXG5cdFx0XHR0aGlzLl9zeW5jX2FsbF9hcmlhKCk7XHJcblx0XHR9XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiBDaGVjayB3aGV0aGVyIHRoZSBjb250YWluZXIgaXMgaW4gZXhjbHVzaXZlIChhY2NvcmRpb24pIG1vZGUuXHJcblx0XHQgKlxyXG5cdFx0ICogT3JkZXIgb2YgcHJlY2VkZW5jZTpcclxuXHRcdCAqICAxKSBFeHBsaWNpdCBvcHRpb24gYG9wdHMuZXhjbHVzaXZlYFxyXG5cdFx0ICogIDIpIENvbnRhaW5lciBoYXMgY2xhc3MgYC53cGJjX2NvbGxhcHNpYmxlLS1leGNsdXNpdmVgXHJcblx0XHQgKiAgMykgQ29udGFpbmVyIG1hdGNoZXMgYFtkYXRhLXdwYmMtYWNjb3JkaW9uPVwiZXhjbHVzaXZlXCJdYFxyXG5cdFx0ICpcclxuXHRcdCAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIGV4Y2x1c2l2ZSBtb2RlIGlzIGFjdGl2ZS5cclxuXHRcdCAqIEBzaW5jZSAyMDI1LTA4LTI2XHJcblx0XHQgKi9cclxuXHRcdGlzX2V4Y2x1c2l2ZSgpIHtcclxuXHRcdFx0cmV0dXJuICEhKFxyXG5cdFx0XHRcdHRoaXMub3B0cy5leGNsdXNpdmUgfHxcclxuXHRcdFx0XHR0aGlzLnJvb3QuY2xhc3NMaXN0LmNvbnRhaW5zKCAnd3BiY19jb2xsYXBzaWJsZS0tZXhjbHVzaXZlJyApIHx8XHJcblx0XHRcdFx0dGhpcy5yb290Lm1hdGNoZXMoICdbZGF0YS13cGJjLWFjY29yZGlvbj1cImV4Y2x1c2l2ZVwiXScgKVxyXG5cdFx0XHQpO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8qKlxyXG5cdFx0ICogRGV0ZXJtaW5lIHdoZXRoZXIgYSBzcGVjaWZpYyBncm91cCBpcyBvcGVuLlxyXG5cdFx0ICpcclxuXHRcdCAqIEBwYXJhbSB7SFRNTEVsZW1lbnR9IGdyb3VwIFRoZSBncm91cCBlbGVtZW50IHRvIHRlc3QuXHJcblx0XHQgKiBAcmV0dXJucyB7Ym9vbGVhbn0gVHJ1ZSBpZiB0aGUgZ3JvdXAgaXMgY3VycmVudGx5IG9wZW4uXHJcblx0XHQgKiBAc2luY2UgMjAyNS0wOC0yNlxyXG5cdFx0ICovXHJcblx0XHRpc19vcGVuKGdyb3VwKSB7XHJcblx0XHRcdHJldHVybiBncm91cC5jbGFzc0xpc3QuY29udGFpbnMoIHRoaXMub3B0cy5vcGVuX2NsYXNzICk7XHJcblx0XHR9XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiBPcGVuIGEgZ3JvdXAuIEhvbm9ycyBleGNsdXNpdmUgbW9kZSBieSBjb2xsYXBzaW5nIGFsbCBzaWJsaW5nIGdyb3Vwc1xyXG5cdFx0ICogKHF1ZXJpZWQgZnJvbSB0aGUgbGl2ZSBET00gYXQgY2FsbC10aW1lKS5cclxuXHRcdCAqXHJcblx0XHQgKiBAcGFyYW0ge0hUTUxFbGVtZW50fSBncm91cCBUaGUgZ3JvdXAgZWxlbWVudCB0byBvcGVuLlxyXG5cdFx0ICogQHBhcmFtIHtib29sZWFufSBbZXhjbHVzaXZlXVxyXG5cdFx0ICogICAgICAgIElmIHByb3ZpZGVkLCBvdmVycmlkZXMgY29udGFpbmVyIG1vZGUgZm9yIHRoaXMgYWN0aW9uIG9ubHkuXHJcblx0XHQgKiBAcmV0dXJucyB7dm9pZH1cclxuXHRcdCAqIEBmaXJlcyBDdXN0b21FdmVudCN3cGJjOmNvbGxhcHNpYmxlOm9wZW5cclxuXHRcdCAqIEBzaW5jZSAyMDI1LTA4LTI2XHJcblx0XHQgKi9cclxuXHRcdGV4cGFuZChncm91cCwgZXhjbHVzaXZlKSB7XHJcblx0XHRcdGlmICggIWdyb3VwICkge1xyXG5cdFx0XHRcdHJldHVybjtcclxuXHRcdFx0fVxyXG5cdFx0XHRjb25zdCBkb19leGNsdXNpdmUgPSAodHlwZW9mIGV4Y2x1c2l2ZSA9PT0gJ2Jvb2xlYW4nKSA/IGV4Y2x1c2l2ZSA6IHRoaXMuaXNfZXhjbHVzaXZlKCk7XHJcblx0XHRcdGlmICggZG9fZXhjbHVzaXZlICkge1xyXG5cdFx0XHRcdC8vIEFsd2F5cyB1c2UgdGhlIGxpdmUgRE9NLCBub3QgdGhlIGNhY2hlZCBsaXN0LlxyXG5cdFx0XHRcdEFycmF5LnByb3RvdHlwZS5mb3JFYWNoLmNhbGwoXHJcblx0XHRcdFx0XHR0aGlzLnJvb3QucXVlcnlTZWxlY3RvckFsbCggdGhpcy5vcHRzLmdyb3VwX3NlbGVjdG9yICksXHJcblx0XHRcdFx0XHQoZykgPT4ge1xyXG5cdFx0XHRcdFx0XHRpZiAoIGcgIT09IGdyb3VwICkge1xyXG5cdFx0XHRcdFx0XHRcdHRoaXMuX3NldF9vcGVuKCBnLCBmYWxzZSApO1xyXG5cdFx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0KTtcclxuXHRcdFx0fVxyXG5cdFx0XHR0aGlzLl9zZXRfb3BlbiggZ3JvdXAsIHRydWUgKTtcclxuXHRcdH1cclxuXHJcblx0XHQvKipcclxuXHRcdCAqIENsb3NlIGEgZ3JvdXAuXHJcblx0XHQgKlxyXG5cdFx0ICogQHBhcmFtIHtIVE1MRWxlbWVudH0gZ3JvdXAgVGhlIGdyb3VwIGVsZW1lbnQgdG8gY2xvc2UuXHJcblx0XHQgKiBAcmV0dXJucyB7dm9pZH1cclxuXHRcdCAqIEBmaXJlcyBDdXN0b21FdmVudCN3cGJjOmNvbGxhcHNpYmxlOmNsb3NlXHJcblx0XHQgKiBAc2luY2UgMjAyNS0wOC0yNlxyXG5cdFx0ICovXHJcblx0XHRjb2xsYXBzZShncm91cCkge1xyXG5cdFx0XHRpZiAoICFncm91cCApIHtcclxuXHRcdFx0XHRyZXR1cm47XHJcblx0XHRcdH1cclxuXHRcdFx0dGhpcy5fc2V0X29wZW4oIGdyb3VwLCBmYWxzZSApO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8qKlxyXG5cdFx0ICogVG9nZ2xlIGEgZ3JvdXAncyBvcGVuL2Nsb3NlZCBzdGF0ZS5cclxuXHRcdCAqXHJcblx0XHQgKiBAcGFyYW0ge0hUTUxFbGVtZW50fSBncm91cCBUaGUgZ3JvdXAgZWxlbWVudCB0byB0b2dnbGUuXHJcblx0XHQgKiBAcmV0dXJucyB7dm9pZH1cclxuXHRcdCAqIEBzaW5jZSAyMDI1LTA4LTI2XHJcblx0XHQgKi9cclxuXHRcdHRvZ2dsZShncm91cCkge1xyXG5cdFx0XHRpZiAoICFncm91cCApIHtcclxuXHRcdFx0XHRyZXR1cm47XHJcblx0XHRcdH1cclxuXHRcdFx0dGhpc1t0aGlzLmlzX29wZW4oIGdyb3VwICkgPyAnY29sbGFwc2UnIDogJ2V4cGFuZCddKCBncm91cCApO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8qKlxyXG5cdFx0ICogT3BlbiBhIGdyb3VwIGJ5IGl0cyBpbmRleCB3aXRoaW4gdGhlIGNvbnRhaW5lciAoMC1iYXNlZCkuXHJcblx0XHQgKlxyXG5cdFx0ICogQHBhcmFtIHtudW1iZXJ9IGluZGV4IFplcm8tYmFzZWQgaW5kZXggb2YgdGhlIGdyb3VwLlxyXG5cdFx0ICogQHJldHVybnMge3ZvaWR9XHJcblx0XHQgKiBAc2luY2UgMjAyNS0wOC0yNlxyXG5cdFx0ICovXHJcblx0XHRvcGVuX2J5X2luZGV4KGluZGV4KSB7XHJcblx0XHRcdGNvbnN0IGdyb3VwID0gdGhpcy5fZ3JvdXBzW2luZGV4XTtcclxuXHRcdFx0aWYgKCBncm91cCApIHtcclxuXHRcdFx0XHR0aGlzLmV4cGFuZCggZ3JvdXAgKTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cclxuXHRcdC8qKlxyXG5cdFx0ICogT3BlbiBhIGdyb3VwIGJ5IG1hdGNoaW5nIHRleHQgY29udGFpbmVkIHdpdGhpbiB0aGUgPGgzPiBpbnNpZGUgdGhlIGhlYWRlci5cclxuXHRcdCAqIFRoZSBjb21wYXJpc29uIGlzIGNhc2UtaW5zZW5zaXRpdmUgYW5kIHN1YnN0cmluZy1iYXNlZC5cclxuXHRcdCAqXHJcblx0XHQgKiBAcGFyYW0ge3N0cmluZ30gdGV4dCBUZXh0IHRvIG1hdGNoIGFnYWluc3QgdGhlIGhlYWRpbmcgY29udGVudHMuXHJcblx0XHQgKiBAcmV0dXJucyB7dm9pZH1cclxuXHRcdCAqIEBzaW5jZSAyMDI1LTA4LTI2XHJcblx0XHQgKi9cclxuXHRcdG9wZW5fYnlfaGVhZGluZyh0ZXh0KSB7XHJcblx0XHRcdGlmICggIXRleHQgKSB7XHJcblx0XHRcdFx0cmV0dXJuO1xyXG5cdFx0XHR9XHJcblx0XHRcdGNvbnN0IHQgICAgID0gU3RyaW5nKCB0ZXh0ICkudG9Mb3dlckNhc2UoKTtcclxuXHRcdFx0Y29uc3QgbWF0Y2ggPSB0aGlzLl9ncm91cHMuZmluZCggKGcpID0+IHtcclxuXHRcdFx0XHRjb25zdCBoID0gZy5xdWVyeVNlbGVjdG9yKCB0aGlzLm9wdHMuaGVhZGVyX3NlbGVjdG9yICsgJyBoMycgKTtcclxuXHRcdFx0XHRyZXR1cm4gaCAmJiBoLnRleHRDb250ZW50LnRvTG93ZXJDYXNlKCkuaW5kZXhPZiggdCApICE9PSAtMTtcclxuXHRcdFx0fSApO1xyXG5cdFx0XHRpZiAoIG1hdGNoICkge1xyXG5cdFx0XHRcdHRoaXMuZXhwYW5kKCBtYXRjaCApO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdFx0Ly8gSW50ZXJuYWxcclxuXHRcdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHJcblx0XHQvKipcclxuXHRcdCAqIERlbGVnYXRlZCBjbGljayBoYW5kbGVyIGZvciBoZWFkZXJzLlxyXG5cdFx0ICpcclxuXHRcdCAqIEBwcml2YXRlXHJcblx0XHQgKiBAcGFyYW0ge01vdXNlRXZlbnR9IGV2IFRoZSBjbGljayBldmVudC5cclxuXHRcdCAqIEByZXR1cm5zIHt2b2lkfVxyXG5cdFx0ICogQHNpbmNlIDIwMjUtMDgtMjZcclxuXHRcdCAqL1xyXG5cdFx0X29uX2NsaWNrKGV2KSB7XHJcblx0XHRcdGNvbnN0IGJ0biA9IGV2LnRhcmdldC5jbG9zZXN0KCB0aGlzLm9wdHMuaGVhZGVyX3NlbGVjdG9yICk7XHJcblx0XHRcdGlmICggIWJ0biB8fCAhdGhpcy5yb290LmNvbnRhaW5zKCBidG4gKSApIHtcclxuXHRcdFx0XHRyZXR1cm47XHJcblx0XHRcdH1cclxuXHRcdFx0ZXYucHJldmVudERlZmF1bHQoKTtcclxuXHRcdFx0ZXYuc3RvcFByb3BhZ2F0aW9uKCk7XHJcblx0XHRcdGNvbnN0IGdyb3VwID0gYnRuLmNsb3Nlc3QoIHRoaXMub3B0cy5ncm91cF9zZWxlY3RvciApO1xyXG5cdFx0XHRpZiAoIGdyb3VwICkge1xyXG5cdFx0XHRcdHRoaXMudG9nZ2xlKCBncm91cCApO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiBLZXlib2FyZCBoYW5kbGVyIGZvciBoZWFkZXIgaW50ZXJhY3Rpb25zIGFuZCByb3ZpbmcgZm9jdXM6XHJcblx0XHQgKiAgLSBFbnRlci9TcGFjZSB0b2dnbGVzIHRoZSBhY3RpdmUgZ3JvdXAuXHJcblx0XHQgKiAgLSBBcnJvd1VwL0Fycm93RG93biBtb3ZlcyBmb2N1cyBiZXR3ZWVuIGdyb3VwIGhlYWRlcnMuXHJcblx0XHQgKlxyXG5cdFx0ICogQHByaXZhdGVcclxuXHRcdCAqIEBwYXJhbSB7S2V5Ym9hcmRFdmVudH0gZXYgVGhlIGtleWJvYXJkIGV2ZW50LlxyXG5cdFx0ICogQHJldHVybnMge3ZvaWR9XHJcblx0XHQgKiBAc2luY2UgMjAyNS0wOC0yNlxyXG5cdFx0ICovXHJcblx0XHRfb25fa2V5ZG93bihldikge1xyXG5cdFx0XHRjb25zdCBidG4gPSBldi50YXJnZXQuY2xvc2VzdCggdGhpcy5vcHRzLmhlYWRlcl9zZWxlY3RvciApO1xyXG5cdFx0XHRpZiAoICFidG4gKSB7XHJcblx0XHRcdFx0cmV0dXJuO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRjb25zdCBrZXkgPSBldi5rZXk7XHJcblxyXG5cdFx0XHQvLyBUb2dnbGUgb24gRW50ZXIgLyBTcGFjZS5cclxuXHRcdFx0aWYgKCBrZXkgPT09ICdFbnRlcicgfHwga2V5ID09PSAnICcgKSB7XHJcblx0XHRcdFx0ZXYucHJldmVudERlZmF1bHQoKTtcclxuXHRcdFx0XHRjb25zdCBncm91cCA9IGJ0bi5jbG9zZXN0KCB0aGlzLm9wdHMuZ3JvdXBfc2VsZWN0b3IgKTtcclxuXHRcdFx0XHRpZiAoIGdyb3VwICkge1xyXG5cdFx0XHRcdFx0dGhpcy50b2dnbGUoIGdyb3VwICk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHRcdHJldHVybjtcclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gTW92ZSBmb2N1cyB3aXRoIEFycm93VXAvQXJyb3dEb3duIGJldHdlZW4gaGVhZGVycyBpbiB0aGlzIGNvbnRhaW5lci5cclxuXHRcdFx0aWYgKCBrZXkgPT09ICdBcnJvd1VwJyB8fCBrZXkgPT09ICdBcnJvd0Rvd24nICkge1xyXG5cdFx0XHRcdGV2LnByZXZlbnREZWZhdWx0KCk7XHJcblx0XHRcdFx0Y29uc3QgaGVhZGVycyA9IEFycmF5LnByb3RvdHlwZS5tYXAuY2FsbChcclxuXHRcdFx0XHRcdHRoaXMucm9vdC5xdWVyeVNlbGVjdG9yQWxsKCB0aGlzLm9wdHMuZ3JvdXBfc2VsZWN0b3IgKSxcclxuXHRcdFx0XHRcdChnKSA9PiBnLnF1ZXJ5U2VsZWN0b3IoIHRoaXMub3B0cy5oZWFkZXJfc2VsZWN0b3IgKVxyXG5cdFx0XHRcdCkuZmlsdGVyKCBCb29sZWFuICk7XHJcblx0XHRcdFx0Y29uc3QgaWR4ICAgICA9IGhlYWRlcnMuaW5kZXhPZiggYnRuICk7XHJcblx0XHRcdFx0aWYgKCBpZHggIT09IC0xICkge1xyXG5cdFx0XHRcdFx0Y29uc3QgbmV4dF9pZHggPSAoa2V5ID09PSAnQXJyb3dEb3duJylcclxuXHRcdFx0XHRcdFx0PyBNYXRoLm1pbiggaGVhZGVycy5sZW5ndGggLSAxLCBpZHggKyAxIClcclxuXHRcdFx0XHRcdFx0OiBNYXRoLm1heCggMCwgaWR4IC0gMSApO1xyXG5cdFx0XHRcdFx0aGVhZGVyc1tuZXh0X2lkeF0uZm9jdXMoKTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHQvKipcclxuXHRcdCAqIEFwcGx5IEFSSUEgc3luY2hyb25pemF0aW9uIHRvIGFsbCBrbm93biBncm91cHMgYmFzZWQgb24gdGhlaXIgb3BlbiBzdGF0ZS5cclxuXHRcdCAqXHJcblx0XHQgKiBAcHJpdmF0ZVxyXG5cdFx0ICogQHJldHVybnMge3ZvaWR9XHJcblx0XHQgKiBAc2luY2UgMjAyNS0wOC0yNlxyXG5cdFx0ICovXHJcblx0XHRfc3luY19hbGxfYXJpYSgpIHtcclxuXHRcdFx0dGhpcy5fZ3JvdXBzLmZvckVhY2goIChnKSA9PiB0aGlzLl9zeW5jX2dyb3VwX2FyaWEoIGcgKSApO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8qKlxyXG5cdFx0ICogU3luYyBBUklBIGF0dHJpYnV0ZXMgYW5kIHZpc2liaWxpdHkgb24gYSBzaW5nbGUgZ3JvdXAuXHJcblx0XHQgKlxyXG5cdFx0ICogQHByaXZhdGVcclxuXHRcdCAqIEBwYXJhbSB7SFRNTEVsZW1lbnR9IGdyb3VwIFRoZSBncm91cCBlbGVtZW50IHRvIHN5bmMuXHJcblx0XHQgKiBAcmV0dXJucyB7dm9pZH1cclxuXHRcdCAqIEBzaW5jZSAyMDI1LTA4LTI2XHJcblx0XHQgKi9cclxuXHRcdF9zeW5jX2dyb3VwX2FyaWEoZ3JvdXApIHtcclxuXHRcdFx0Y29uc3QgaXNfb3BlbiA9IHRoaXMuaXNfb3BlbiggZ3JvdXAgKTtcclxuXHRcdFx0Y29uc3QgaGVhZGVyICA9IGdyb3VwLnF1ZXJ5U2VsZWN0b3IoIHRoaXMub3B0cy5oZWFkZXJfc2VsZWN0b3IgKTtcclxuXHRcdFx0Ly8gT25seSBkaXJlY3QgY2hpbGRyZW4gdGhhdCBtYXRjaC5cclxuXHRcdFx0Y29uc3QgcGFuZWxzID0gQXJyYXkucHJvdG90eXBlLmZpbHRlci5jYWxsKCBncm91cC5jaGlsZHJlbiwgKGVsKSA9PiBlbC5tYXRjaGVzKCB0aGlzLm9wdHMuZmllbGRzX3NlbGVjdG9yICkgKTtcclxuXHJcblx0XHRcdC8vIEhlYWRlciBBUklBLlxyXG5cdFx0XHRpZiAoIGhlYWRlciApIHtcclxuXHRcdFx0XHRoZWFkZXIuc2V0QXR0cmlidXRlKCAncm9sZScsICdidXR0b24nICk7XHJcblx0XHRcdFx0aGVhZGVyLnNldEF0dHJpYnV0ZSggJ2FyaWEtZXhwYW5kZWQnLCBpc19vcGVuID8gJ3RydWUnIDogJ2ZhbHNlJyApO1xyXG5cclxuXHRcdFx0XHRpZiAoIHBhbmVscy5sZW5ndGggKSB7XHJcblx0XHRcdFx0XHQvLyBFbnN1cmUgZWFjaCBwYW5lbCBoYXMgYW4gaWQ7IHRoZW4gd2lyZSBhcmlhLWNvbnRyb2xzIHdpdGggc3BhY2Utc2VwYXJhdGVkIGlkcy5cclxuXHRcdFx0XHRcdGNvbnN0IGlkcyA9IHBhbmVscy5tYXAoIChwKSA9PiB7XHJcblx0XHRcdFx0XHRcdGlmICggIXAuaWQgKSBwLmlkID0gdGhpcy5fZ2VuZXJhdGVfaWQoICd3cGJjX2NvbGxhcHNpYmxlX3BhbmVsJyApO1xyXG5cdFx0XHRcdFx0XHRyZXR1cm4gcC5pZDtcclxuXHRcdFx0XHRcdH0gKTtcclxuXHRcdFx0XHRcdGhlYWRlci5zZXRBdHRyaWJ1dGUoICdhcmlhLWNvbnRyb2xzJywgaWRzLmpvaW4oICcgJyApICk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyAoMykgUGFuZWxzIEFSSUEgKyB2aXNpYmlsaXR5LlxyXG5cdFx0XHRwYW5lbHMuZm9yRWFjaCggKHApID0+IHtcclxuXHRcdFx0XHRwLmhpZGRlbiA9ICFpc19vcGVuOyAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBhY3R1YWwgdmlzaWJpbGl0eS5cclxuXHRcdFx0XHRwLnNldEF0dHJpYnV0ZSggJ2FyaWEtaGlkZGVuJywgaXNfb3BlbiA/ICdmYWxzZScgOiAndHJ1ZScgKTsgLy8gQVJJQS5cclxuXHRcdFx0fSApO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8qKlxyXG5cdFx0ICogSW50ZXJuYWwgc3RhdGUgY2hhbmdlOiBzZXQgYSBncm91cCdzIG9wZW4vY2xvc2VkIHN0YXRlLCBzeW5jIEFSSUEsXHJcblx0XHQgKiBtYW5hZ2UgZm9jdXMgb24gY29sbGFwc2UsIGFuZCBlbWl0IGEgY3VzdG9tIGV2ZW50LlxyXG5cdFx0ICpcclxuXHRcdCAqIEBwcml2YXRlXHJcblx0XHQgKiBAcGFyYW0ge0hUTUxFbGVtZW50fSBncm91cCBUaGUgZ3JvdXAgZWxlbWVudCB0byBtdXRhdGUuXHJcblx0XHQgKiBAcGFyYW0ge2Jvb2xlYW59IG9wZW4gV2hldGhlciB0aGUgZ3JvdXAgc2hvdWxkIGJlIG9wZW4uXHJcblx0XHQgKiBAcmV0dXJucyB7dm9pZH1cclxuXHRcdCAqIEBmaXJlcyBDdXN0b21FdmVudCN3cGJjOmNvbGxhcHNpYmxlOm9wZW5cclxuXHRcdCAqIEBmaXJlcyBDdXN0b21FdmVudCN3cGJjOmNvbGxhcHNpYmxlOmNsb3NlXHJcblx0XHQgKiBAc2luY2UgMjAyNS0wOC0yNlxyXG5cdFx0ICovXHJcblx0XHRfc2V0X29wZW4oZ3JvdXAsIG9wZW4pIHtcclxuXHRcdFx0aWYgKCAhb3BlbiAmJiBncm91cC5jb250YWlucyggZG9jdW1lbnQuYWN0aXZlRWxlbWVudCApICkge1xyXG5cdFx0XHRcdGNvbnN0IGhlYWRlciA9IGdyb3VwLnF1ZXJ5U2VsZWN0b3IoIHRoaXMub3B0cy5oZWFkZXJfc2VsZWN0b3IgKTtcclxuXHRcdFx0XHRoZWFkZXIgJiYgaGVhZGVyLmZvY3VzKCk7XHJcblx0XHRcdH1cclxuXHRcdFx0Z3JvdXAuY2xhc3NMaXN0LnRvZ2dsZSggdGhpcy5vcHRzLm9wZW5fY2xhc3MsIG9wZW4gKTtcclxuXHRcdFx0dGhpcy5fc3luY19ncm91cF9hcmlhKCBncm91cCApO1xyXG5cdFx0XHRjb25zdCBldl9uYW1lID0gb3BlbiA/ICd3cGJjOmNvbGxhcHNpYmxlOm9wZW4nIDogJ3dwYmM6Y29sbGFwc2libGU6Y2xvc2UnO1xyXG5cdFx0XHRncm91cC5kaXNwYXRjaEV2ZW50KCBuZXcgQ3VzdG9tRXZlbnQoIGV2X25hbWUsIHtcclxuXHRcdFx0XHRidWJibGVzOiB0cnVlLFxyXG5cdFx0XHRcdGRldGFpbCA6IHsgZ3JvdXAsIHJvb3Q6IHRoaXMucm9vdCwgaW5zdGFuY2U6IHRoaXMgfVxyXG5cdFx0XHR9ICkgKTtcclxuXHRcdH1cclxuXHJcblx0XHQvKipcclxuXHRcdCAqIEdlbmVyYXRlIGEgdW5pcXVlIERPTSBpZCB3aXRoIHRoZSBzcGVjaWZpZWQgcHJlZml4LlxyXG5cdFx0ICpcclxuXHRcdCAqIEBwcml2YXRlXHJcblx0XHQgKiBAcGFyYW0ge3N0cmluZ30gcHJlZml4IFRoZSBpZCBwcmVmaXggdG8gdXNlLlxyXG5cdFx0ICogQHJldHVybnMge3N0cmluZ30gQSB1bmlxdWUgZWxlbWVudCBpZCBub3QgcHJlc2VudCBpbiB0aGUgZG9jdW1lbnQuXHJcblx0XHQgKiBAc2luY2UgMjAyNS0wOC0yNlxyXG5cdFx0ICovXHJcblx0XHRfZ2VuZXJhdGVfaWQocHJlZml4KSB7XHJcblx0XHRcdGxldCBpID0gMTtcclxuXHRcdFx0bGV0IGlkO1xyXG5cdFx0XHRkbyB7XHJcblx0XHRcdFx0aWQgPSBwcmVmaXggKyAnXycgKyAoaSsrKTtcclxuXHRcdFx0fVxyXG5cdFx0XHR3aGlsZSAoIGQuZ2V0RWxlbWVudEJ5SWQoIGlkICkgKTtcclxuXHRcdFx0cmV0dXJuIGlkO1xyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0LyoqXHJcblx0ICogQXV0by1pbml0aWFsaXplIGNvbGxhcHNpYmxlIGNvbnRyb2xsZXJzIG9uIHRoZSBwYWdlLlxyXG5cdCAqIEZpbmRzIHRvcC1sZXZlbCBgLndwYmNfY29sbGFwc2libGVgIGNvbnRhaW5lcnMgKGlnbm9yaW5nIG5lc3RlZCBvbmVzKSxcclxuXHQgKiBhbmQgaW5zdGFudGlhdGVzIHtAbGluayBXUEJDX0NvbGxhcHNpYmxlX0dyb3Vwc30gb24gZWFjaC5cclxuXHQgKlxyXG5cdCAqIEBmdW5jdGlvbiBXUEJDX0NvbGxhcHNpYmxlX0F1dG9Jbml0XHJcblx0ICogQHJldHVybnMge3ZvaWR9XHJcblx0ICogQHNpbmNlIDIwMjUtMDgtMjZcclxuXHQgKiBAZXhhbXBsZVxyXG5cdCAqIC8vIFJ1bnMgYXV0b21hdGljYWxseSBvbiBET01Db250ZW50TG9hZGVkOyBjYW4gYWxzbyBiZSBjYWxsZWQgbWFudWFsbHk6XHJcblx0ICogV1BCQ19Db2xsYXBzaWJsZV9BdXRvSW5pdCgpO1xyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHdwYmNfY29sbGFwc2libGVfX2F1dG9faW5pdCgpIHtcclxuXHRcdHZhciBST09UICA9ICcud3BiY19jb2xsYXBzaWJsZSc7XHJcblx0XHR2YXIgbm9kZXMgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbCggZC5xdWVyeVNlbGVjdG9yQWxsKCBST09UICkgKVxyXG5cdFx0XHQuZmlsdGVyKCBmdW5jdGlvbiAobikge1xyXG5cdFx0XHRcdHJldHVybiAhbi5wYXJlbnRFbGVtZW50IHx8ICFuLnBhcmVudEVsZW1lbnQuY2xvc2VzdCggUk9PVCApO1xyXG5cdFx0XHR9ICk7XHJcblxyXG5cdFx0bm9kZXMuZm9yRWFjaCggZnVuY3Rpb24gKG5vZGUpIHtcclxuXHRcdFx0aWYgKCBub2RlLl9fd3BiY19jb2xsYXBzaWJsZV9pbnN0YW5jZSApIHtcclxuXHRcdFx0XHRyZXR1cm47XHJcblx0XHRcdH1cclxuXHRcdFx0dmFyIGV4Y2x1c2l2ZSA9IG5vZGUuY2xhc3NMaXN0LmNvbnRhaW5zKCAnd3BiY19jb2xsYXBzaWJsZS0tZXhjbHVzaXZlJyApIHx8IG5vZGUubWF0Y2hlcyggJ1tkYXRhLXdwYmMtYWNjb3JkaW9uPVwiZXhjbHVzaXZlXCJdJyApO1xyXG5cclxuXHRcdFx0bm9kZS5fX3dwYmNfY29sbGFwc2libGVfaW5zdGFuY2UgPSBuZXcgV1BCQ19Db2xsYXBzaWJsZV9Hcm91cHMoIG5vZGUsIHsgZXhjbHVzaXZlIH0gKS5pbml0KCk7XHJcblx0XHR9ICk7XHJcblx0fVxyXG5cclxuXHQvLyBFeHBvcnQgdG8gZ2xvYmFsIGZvciBtYW51YWwgY29udHJvbCBpZiBuZWVkZWQuXHJcblx0dy5XUEJDX0NvbGxhcHNpYmxlX0dyb3VwcyAgID0gV1BCQ19Db2xsYXBzaWJsZV9Hcm91cHM7XHJcblx0dy5XUEJDX0NvbGxhcHNpYmxlX0F1dG9Jbml0ID0gd3BiY19jb2xsYXBzaWJsZV9fYXV0b19pbml0O1xyXG5cclxuXHQvLyBET00tcmVhZHkgYXV0byBpbml0LlxyXG5cdGlmICggZC5yZWFkeVN0YXRlID09PSAnbG9hZGluZycgKSB7XHJcblx0XHRkLmFkZEV2ZW50TGlzdGVuZXIoICdET01Db250ZW50TG9hZGVkJywgd3BiY19jb2xsYXBzaWJsZV9fYXV0b19pbml0LCB7IG9uY2U6IHRydWUgfSApO1xyXG5cdH0gZWxzZSB7XHJcblx0XHR3cGJjX2NvbGxhcHNpYmxlX19hdXRvX2luaXQoKTtcclxuXHR9XHJcbn0pKCB3aW5kb3csIGRvY3VtZW50ICk7XHJcbiIsIi8qIGdsb2JhbHMgd2luZG93LCBkb2N1bWVudCAqL1xyXG4vKipcclxuICogV1BCQyBTbGlkZXIgTGVuZ3RoIEdyb3Vwc1xyXG4gKlxyXG4gKiBVbml2ZXJzYWwsIGRlcGVuZGVuY3ktZnJlZSBjb250cm9sbGVyIHRoYXQga2VlcHMgYSBcImxlbmd0aFwiIGNvbnRyb2wgaW4gc3luYzpcclxuICogIC0gbnVtYmVyIGlucHV0ICAoZGF0YS13cGJjX3NsaWRlcl9sZW5fdmFsdWUpXHJcbiAqICAtIHVuaXQgc2VsZWN0ICAgKGRhdGEtd3BiY19zbGlkZXJfbGVuX3VuaXQpXHJcbiAqICAtIHJhbmdlIHNsaWRlciAgKGRhdGEtd3BiY19zbGlkZXJfbGVuX3JhbmdlKVxyXG4gKiAgLSB3cml0ZXIgaW5wdXQgIChkYXRhLXdwYmNfc2xpZGVyX2xlbl93cml0ZXIpICBbb3B0aW9uYWwgYnV0IHJlY29tbWVuZGVkXVxyXG4gKlxyXG4gKiBUaGUgXCJ3cml0ZXJcIiBzdG9yZXMgdGhlIGNvbWJpbmVkIHZhbHVlIGxpa2U6IFwiMTAwJVwiLCBcIjQyMHB4XCIsIFwiMTIuNXJlbVwiLlxyXG4gKiBXaGVuIG51bWJlci91bml0L3NsaWRlciBjaGFuZ2UgLT4gd3JpdGVyIHVwZGF0ZXMgYW5kIGVtaXRzICdpbnB1dCcgKGJ1YmJsZXMpLlxyXG4gKiBXaGVuIHdyaXRlciBpcyBjaGFuZ2VkIGV4dGVybmFsbHkgKGFwcGx5LWZyb20tSlNPTiwgZXRjKSAtPiBVSSB1cGRhdGVzLlxyXG4gKlxyXG4gKiBNYXJrdXAgZXhwZWN0YXRpb25zIChtaW5pbWFsKTpcclxuICogIDxkaXYgY2xhc3M9XCJ3cGJjX3NsaWRlcl9sZW5fZ3JvdXBcIlxyXG4gKiAgICAgICBkYXRhLXdwYmNfc2xpZGVyX2xlbl9ib3VuZHNfbWFwPSd7XCIlXCI6e1wibWluXCI6MzAsXCJtYXhcIjoxMDAsXCJzdGVwXCI6MX0sXCJweFwiOntcIm1pblwiOjMwMCxcIm1heFwiOjIwMDAsXCJzdGVwXCI6MTB9fSdcclxuICogICAgICAgZGF0YS13cGJjX3NsaWRlcl9sZW5fZGVmYXVsdF91bml0PVwiJVwiPlxyXG4gKiAgICA8aW5wdXQgdHlwZT1cIm51bWJlclwiIGRhdGEtd3BiY19zbGlkZXJfbGVuX3ZhbHVlPlxyXG4gKiAgICA8c2VsZWN0IGRhdGEtd3BiY19zbGlkZXJfbGVuX3VuaXQ+Li4uPC9zZWxlY3Q+XHJcbiAqICAgIDxpbnB1dCB0eXBlPVwicmFuZ2VcIiBkYXRhLXdwYmNfc2xpZGVyX2xlbl9yYW5nZT5cclxuICogICAgPGlucHV0IHR5cGU9XCJ0ZXh0XCIgZGF0YS13cGJjX3NsaWRlcl9sZW5fd3JpdGVyIHN0eWxlPVwiZGlzcGxheTpub25lO1wiPlxyXG4gKiAgPC9kaXY+XHJcbiAqXHJcbiAqIFBlcmZvcm1hbmNlIG5vdGVzOlxyXG4gKiAtIE11dGF0aW9uT2JzZXJ2ZXIgaXMgRElTQUJMRUQgYnkgZGVmYXVsdCAocHJldmVudHMgcGVyZm9ybWFuY2UgaXNzdWVzKS5cclxuICogLSBJZiB5b3VyIFVJIHJlLXJlbmRlcnMgYW5kIGluc2VydHMgbmV3IGdyb3VwcyBkeW5hbWljYWxseSwgY2FsbDpcclxuICogICAgIFdQQkNfU2xpZGVyX0xlbl9BdXRvSW5pdCgpOyAgT1IgaW5zdGFuY2UucmVmcmVzaCgpO1xyXG4gKiAgIE9yIGVuYWJsZSBvYnNlcnZlciB2aWE6IG5ldyBXUEJDX1NsaWRlcl9MZW5fR3JvdXBzKHJvb3QsIHsgZW5hYmxlX29ic2VydmVyOnRydWUgfSkuaW5pdCgpO1xyXG4gKlxyXG4gKiBQdWJsaWMgQVBJIChpbnN0YW5jZSBtZXRob2RzKTpcclxuICogIC0gaW5pdCgpLCBkZXN0cm95KCksIHJlZnJlc2goKVxyXG4gKlxyXG4gKiBAdmVyc2lvbiAyMDI2LTAxLTI1XHJcbiAqIEBzaW5jZSAgIDIwMjYtMDEtMjVcclxuICogQGZpbGUgICAgLi4vaW5jbHVkZXMvX19qcy9hZG1pbi9zbGlkZXJfZ3JvdXBzL3dwYmNfbGVuX2dyb3Vwcy5qc1xyXG4gKi9cclxuKGZ1bmN0aW9uICh3LCBkKSB7XHJcblx0J3VzZSBzdHJpY3QnO1xyXG5cclxuXHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0Ly8gSGVscGVyc1xyXG5cdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRmdW5jdGlvbiBjbGFtcF9udW0odiwgbWluLCBtYXgpIHtcclxuXHRcdGlmICh0eXBlb2YgbWluID09PSAnbnVtYmVyJyAmJiAhaXNOYU4obWluKSkgdiA9IE1hdGgubWF4KG1pbiwgdik7XHJcblx0XHRpZiAodHlwZW9mIG1heCA9PT0gJ251bWJlcicgJiYgIWlzTmFOKG1heCkpIHYgPSBNYXRoLm1pbihtYXgsIHYpO1xyXG5cdFx0cmV0dXJuIHY7XHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBwYXJzZV9mbG9hdCh2KSB7XHJcblx0XHR2YXIgbiA9IHBhcnNlRmxvYXQodik7XHJcblx0XHRyZXR1cm4gaXNOYU4obikgPyBudWxsIDogbjtcclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHNhZmVfanNvbl9wYXJzZShzdHIpIHtcclxuXHRcdHRyeSB7XHJcblx0XHRcdHJldHVybiBKU09OLnBhcnNlKHN0cik7XHJcblx0XHR9IGNhdGNoIChlKSB7XHJcblx0XHRcdHJldHVybiBudWxsO1xyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gcGFyc2VfbGVuX2NvbWJpbmVkKHJhdywgZGVmYXVsdF91bml0KSB7XHJcblx0XHR2YXIgcyA9IChyYXcgPT0gbnVsbCkgPyAnJyA6IFN0cmluZyhyYXcpLnRyaW0oKTtcclxuXHRcdGlmICghcykgcmV0dXJuIHsgbnVtOiAnJywgdW5pdDogZGVmYXVsdF91bml0IHx8ICclJyB9O1xyXG5cclxuXHRcdHZhciBtID0gcy5tYXRjaCgvXlxccyooW1xcLV0/XFxkKyg/OlxcLlxcZCspPylcXHMqKFthLXolXSopXFxzKiQvaSk7XHJcblx0XHRpZiAoIW0pIHtcclxuXHRcdFx0Ly8gSWYgaXQncyBub3QgcGFyc2VhYmxlLCB0cmVhdCBhcyBudW1iZXIgYW5kIGtlZXAgZGVmYXVsdCB1bml0LlxyXG5cdFx0XHRyZXR1cm4geyBudW06IHMsIHVuaXQ6IGRlZmF1bHRfdW5pdCB8fCAnJScgfTtcclxuXHRcdH1cclxuXHJcblx0XHR2YXIgbnVtICA9IG1bMV0gPyBTdHJpbmcobVsxXSkgOiAnJztcclxuXHRcdHZhciB1bml0ID0gbVsyXSA/IFN0cmluZyhtWzJdKSA6ICcnO1xyXG5cdFx0aWYgKCF1bml0KSB1bml0ID0gZGVmYXVsdF91bml0IHx8ICclJztcclxuXHJcblx0XHRyZXR1cm4geyBudW06IG51bSwgdW5pdDogdW5pdCB9O1xyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gYnVpbGRfY29tYmluZWQobnVtLCB1bml0KSB7XHJcblx0XHRpZiAobnVtID09IG51bGwgfHwgU3RyaW5nKG51bSkudHJpbSgpID09PSAnJykgcmV0dXJuICcnO1xyXG5cdFx0cmV0dXJuIFN0cmluZyhudW0pICsgU3RyaW5nKHVuaXQgfHwgJycpO1xyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gZW1pdF9pbnB1dChlbCkge1xyXG5cdFx0aWYgKCFlbCkgcmV0dXJuO1xyXG5cdFx0ZWwuZGlzcGF0Y2hFdmVudChuZXcgRXZlbnQoJ2lucHV0JywgeyBidWJibGVzOiB0cnVlIH0pKTtcclxuXHR9XHJcblxyXG5cdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHQvLyBDb250cm9sbGVyXHJcblx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdGNsYXNzIFdQQkNfU2xpZGVyX0xlbl9Hcm91cHMge1xyXG5cclxuXHRcdC8qKlxyXG5cdFx0ICogQHBhcmFtIHtIVE1MRWxlbWVudHxzdHJpbmd9IHJvb3RfZWwgQ29udGFpbmVyIChvciBzZWxlY3RvcikuIElmIG9taXR0ZWQsIHVzZXMgZG9jdW1lbnQuXHJcblx0XHQgKiBAcGFyYW0ge09iamVjdH0gW29wdHM9e31dXHJcblx0XHQgKi9cclxuXHRcdGNvbnN0cnVjdG9yKHJvb3RfZWwsIG9wdHMpIHtcclxuXHRcdFx0dGhpcy5yb290ID0gcm9vdF9lbFxyXG5cdFx0XHRcdD8gKCh0eXBlb2Ygcm9vdF9lbCA9PT0gJ3N0cmluZycpID8gZC5xdWVyeVNlbGVjdG9yKHJvb3RfZWwpIDogcm9vdF9lbClcclxuXHRcdFx0XHQ6IGQ7XHJcblxyXG5cdFx0XHR0aGlzLm9wdHMgPSBPYmplY3QuYXNzaWduKHtcclxuXHRcdFx0XHQvLyBTdHJpY3Qgc2VsZWN0b3JzIChOTyBiYWNrd2FyZCBjb21wYXRpYmlsaXR5KS5cclxuXHRcdFx0XHRncm91cF9zZWxlY3RvciAgOiAnLndwYmNfc2xpZGVyX2xlbl9ncm91cCcsXHJcblx0XHRcdFx0dmFsdWVfc2VsZWN0b3IgIDogJ1tkYXRhLXdwYmNfc2xpZGVyX2xlbl92YWx1ZV0nLFxyXG5cdFx0XHRcdHVuaXRfc2VsZWN0b3IgICA6ICdbZGF0YS13cGJjX3NsaWRlcl9sZW5fdW5pdF0nLFxyXG5cdFx0XHRcdHJhbmdlX3NlbGVjdG9yICA6ICdbZGF0YS13cGJjX3NsaWRlcl9sZW5fcmFuZ2VdJyxcclxuXHRcdFx0XHR3cml0ZXJfc2VsZWN0b3IgOiAnW2RhdGEtd3BiY19zbGlkZXJfbGVuX3dyaXRlcl0nLFxyXG5cclxuXHRcdFx0XHRkZWZhdWx0X3VuaXQgICAgOiAnJScsXHJcblxyXG5cdFx0XHRcdGZhbGxiYWNrX2JvdW5kcyA6IHtcclxuXHRcdFx0XHRcdCdweCcgOiB7IG1pbjogMCwgICBtYXg6IDUxMiwgIHN0ZXA6IDEgICB9LFxyXG5cdFx0XHRcdFx0JyUnICA6IHsgbWluOiAwLCAgIG1heDogMTAwLCAgc3RlcDogMSAgIH0sXHJcblx0XHRcdFx0XHQncmVtJzogeyBtaW46IDAsICAgbWF4OiAxMCwgICBzdGVwOiAwLjEgfSxcclxuXHRcdFx0XHRcdCdlbScgOiB7IG1pbjogMCwgICBtYXg6IDEwLCAgIHN0ZXA6IDAuMSB9XHJcblx0XHRcdFx0fSxcclxuXHJcblx0XHRcdFx0Ly8gRGlzYWJsZWQgYnkgZGVmYXVsdCBmb3IgcGVyZm9ybWFuY2UuXHJcblx0XHRcdFx0ZW5hYmxlX29ic2VydmVyICAgICA6IGZhbHNlLFxyXG5cdFx0XHRcdG9ic2VydmVyX2RlYm91bmNlX21zOiAxNTBcclxuXHRcdFx0fSwgb3B0cyB8fCB7fSk7XHJcblxyXG5cdFx0XHR0aGlzLl9vbl9pbnB1dCAgPSB0aGlzLl9vbl9pbnB1dC5iaW5kKHRoaXMpO1xyXG5cdFx0XHR0aGlzLl9vbl9jaGFuZ2UgPSB0aGlzLl9vbl9jaGFuZ2UuYmluZCh0aGlzKTtcclxuXHJcblx0XHRcdHRoaXMuX2JvdW5kc19jYWNoZSA9IG5ldyBXZWFrTWFwKCk7IC8vIGdyb3VwIC0+IGJvdW5kc19tYXBfb2JqZWN0XHJcblx0XHRcdHRoaXMuX29ic2VydmVyICAgICA9IG51bGw7XHJcblx0XHRcdHRoaXMuX3JlZnJlc2hfdG1yICA9IG51bGw7XHJcblx0XHR9XHJcblxyXG5cdFx0aW5pdCgpIHtcclxuXHRcdFx0aWYgKCF0aGlzLnJvb3QpIHJldHVybiB0aGlzO1xyXG5cclxuXHRcdFx0dGhpcy5yb290LmFkZEV2ZW50TGlzdGVuZXIoJ2lucHV0JywgIHRoaXMuX29uX2lucHV0LCAgdHJ1ZSk7XHJcblx0XHRcdHRoaXMucm9vdC5hZGRFdmVudExpc3RlbmVyKCdjaGFuZ2UnLCB0aGlzLl9vbl9jaGFuZ2UsIHRydWUpO1xyXG5cclxuXHRcdFx0aWYgKHRoaXMub3B0cy5lbmFibGVfb2JzZXJ2ZXIgJiYgdy5NdXRhdGlvbk9ic2VydmVyKSB7XHJcblx0XHRcdFx0dGhpcy5fb2JzZXJ2ZXIgPSBuZXcgTXV0YXRpb25PYnNlcnZlcigoKSA9PiB7IHRoaXMuX2RlYm91bmNlZF9yZWZyZXNoKCk7IH0pO1xyXG5cdFx0XHRcdHRoaXMuX29ic2VydmVyLm9ic2VydmUodGhpcy5yb290ID09PSBkID8gZC5kb2N1bWVudEVsZW1lbnQgOiB0aGlzLnJvb3QsIHsgY2hpbGRMaXN0OiB0cnVlLCBzdWJ0cmVlOiB0cnVlIH0pO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHR0aGlzLnJlZnJlc2goKTtcclxuXHRcdFx0cmV0dXJuIHRoaXM7XHJcblx0XHR9XHJcblxyXG5cdFx0ZGVzdHJveSgpIHtcclxuXHRcdFx0aWYgKCF0aGlzLnJvb3QpIHJldHVybjtcclxuXHJcblx0XHRcdHRoaXMucm9vdC5yZW1vdmVFdmVudExpc3RlbmVyKCdpbnB1dCcsICB0aGlzLl9vbl9pbnB1dCwgIHRydWUpO1xyXG5cdFx0XHR0aGlzLnJvb3QucmVtb3ZlRXZlbnRMaXN0ZW5lcignY2hhbmdlJywgdGhpcy5fb25fY2hhbmdlLCB0cnVlKTtcclxuXHJcblx0XHRcdGlmICh0aGlzLl9vYnNlcnZlcikge1xyXG5cdFx0XHRcdHRoaXMuX29ic2VydmVyLmRpc2Nvbm5lY3QoKTtcclxuXHRcdFx0XHR0aGlzLl9vYnNlcnZlciA9IG51bGw7XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdGlmICh0aGlzLl9yZWZyZXNoX3Rtcikge1xyXG5cdFx0XHRcdGNsZWFyVGltZW91dCh0aGlzLl9yZWZyZXNoX3Rtcik7XHJcblx0XHRcdFx0dGhpcy5fcmVmcmVzaF90bXIgPSBudWxsO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0cmVmcmVzaCgpIHtcclxuXHRcdFx0aWYgKCF0aGlzLnJvb3QpIHJldHVybjtcclxuXHJcblx0XHRcdHZhciBzY29wZSAgPSAodGhpcy5yb290ID09PSBkID8gZCA6IHRoaXMucm9vdCk7XHJcblx0XHRcdHZhciBncm91cHMgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChzY29wZS5xdWVyeVNlbGVjdG9yQWxsKHRoaXMub3B0cy5ncm91cF9zZWxlY3RvcikpO1xyXG5cclxuXHRcdFx0Zm9yICh2YXIgaSA9IDA7IGkgPCBncm91cHMubGVuZ3RoOyBpKyspIHtcclxuXHRcdFx0XHR0aGlzLl9zeW5jX2dyb3VwX2Zyb21fd3JpdGVyKGdyb3Vwc1tpXSk7XHJcblx0XHRcdFx0dGhpcy5fYXBwbHlfYm91bmRzX2Zvcl9jdXJyZW50X3VuaXQoZ3JvdXBzW2ldKTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRcdC8vIEludGVybmFsXHJcblx0XHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHRfZGVib3VuY2VkX3JlZnJlc2goKSB7XHJcblx0XHRcdGlmICh0aGlzLl9yZWZyZXNoX3RtcikgY2xlYXJUaW1lb3V0KHRoaXMuX3JlZnJlc2hfdG1yKTtcclxuXHRcdFx0dGhpcy5fcmVmcmVzaF90bXIgPSBzZXRUaW1lb3V0KCgpID0+IHtcclxuXHRcdFx0XHR0aGlzLl9yZWZyZXNoX3RtciA9IG51bGw7XHJcblx0XHRcdFx0dGhpcy5yZWZyZXNoKCk7XHJcblx0XHRcdH0sIE51bWJlcih0aGlzLm9wdHMub2JzZXJ2ZXJfZGVib3VuY2VfbXMpIHx8IDApO1xyXG5cdFx0fVxyXG5cclxuXHRcdF9maW5kX2dyb3VwKGVsKSB7XHJcblx0XHRcdHJldHVybiAoZWwgJiYgZWwuY2xvc2VzdCkgPyBlbC5jbG9zZXN0KHRoaXMub3B0cy5ncm91cF9zZWxlY3RvcikgOiBudWxsO1xyXG5cdFx0fVxyXG5cclxuXHRcdF9nZXRfcGFydHMoZ3JvdXApIHtcclxuXHRcdFx0aWYgKCFncm91cCkgcmV0dXJuIG51bGw7XHJcblx0XHRcdHJldHVybiB7XHJcblx0XHRcdFx0Z3JvdXAgOiBncm91cCxcclxuXHRcdFx0XHRudW0gICA6IGdyb3VwLnF1ZXJ5U2VsZWN0b3IodGhpcy5vcHRzLnZhbHVlX3NlbGVjdG9yKSxcclxuXHRcdFx0XHR1bml0ICA6IGdyb3VwLnF1ZXJ5U2VsZWN0b3IodGhpcy5vcHRzLnVuaXRfc2VsZWN0b3IpLFxyXG5cdFx0XHRcdHJhbmdlIDogZ3JvdXAucXVlcnlTZWxlY3Rvcih0aGlzLm9wdHMucmFuZ2Vfc2VsZWN0b3IpLFxyXG5cdFx0XHRcdHdyaXRlcjogZ3JvdXAucXVlcnlTZWxlY3Rvcih0aGlzLm9wdHMud3JpdGVyX3NlbGVjdG9yKVxyXG5cdFx0XHR9O1xyXG5cdFx0fVxyXG5cclxuXHRcdF9nZXRfZGVmYXVsdF91bml0KGdyb3VwKSB7XHJcblx0XHRcdHZhciBkdSA9IChncm91cCAmJiBncm91cC5nZXRBdHRyaWJ1dGUpXHJcblx0XHRcdFx0PyBncm91cC5nZXRBdHRyaWJ1dGUoJ2RhdGEtd3BiY19zbGlkZXJfbGVuX2RlZmF1bHRfdW5pdCcpXHJcblx0XHRcdFx0OiAnJztcclxuXHRcdFx0cmV0dXJuIGR1ID8gU3RyaW5nKGR1KSA6IHRoaXMub3B0cy5kZWZhdWx0X3VuaXQ7XHJcblx0XHR9XHJcblxyXG5cdFx0X2dldF9ib3VuZHNfbWFwKGdyb3VwKSB7XHJcblx0XHRcdGlmICghZ3JvdXApIHJldHVybiBudWxsO1xyXG5cdFx0XHRpZiAodGhpcy5fYm91bmRzX2NhY2hlLmhhcyhncm91cCkpIHtcclxuXHRcdFx0XHRyZXR1cm4gdGhpcy5fYm91bmRzX2NhY2hlLmdldChncm91cCk7XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHZhciByYXcgPSBncm91cC5nZXRBdHRyaWJ1dGUoJ2RhdGEtd3BiY19zbGlkZXJfbGVuX2JvdW5kc19tYXAnKTtcclxuXHRcdFx0dmFyIG1hcCA9IHJhdyA/IHNhZmVfanNvbl9wYXJzZShyYXcpIDogbnVsbDtcclxuXHRcdFx0aWYgKCFtYXAgfHwgdHlwZW9mIG1hcCAhPT0gJ29iamVjdCcpIG1hcCA9IG51bGw7XHJcblxyXG5cdFx0XHR0aGlzLl9ib3VuZHNfY2FjaGUuc2V0KGdyb3VwLCBtYXApO1xyXG5cdFx0XHRyZXR1cm4gbWFwO1xyXG5cdFx0fVxyXG5cclxuXHRcdF9nZXRfYm91bmRzX2Zvcl91bml0KGdyb3VwLCB1bml0KSB7XHJcblx0XHRcdHZhciBtYXAgPSB0aGlzLl9nZXRfYm91bmRzX21hcChncm91cCk7XHJcblx0XHRcdGlmIChtYXAgJiYgdW5pdCAmJiBtYXBbdW5pdF0pIHtcclxuXHRcdFx0XHRyZXR1cm4gbWFwW3VuaXRdO1xyXG5cdFx0XHR9XHJcblx0XHRcdHJldHVybiB0aGlzLm9wdHMuZmFsbGJhY2tfYm91bmRzW3VuaXRdIHx8IHRoaXMub3B0cy5mYWxsYmFja19ib3VuZHNbJ3B4J107XHJcblx0XHR9XHJcblxyXG5cdFx0X2FwcGx5X2JvdW5kcyhwYXJ0cywgYm91bmRzKSB7XHJcblx0XHRcdGlmICghcGFydHMgfHwgIWJvdW5kcykgcmV0dXJuO1xyXG5cclxuXHRcdFx0dmFyIG1pbiAgPSAoYm91bmRzLm1pbiAgIT0gbnVsbCkgPyBOdW1iZXIoYm91bmRzLm1pbikgIDogbnVsbDtcclxuXHRcdFx0dmFyIG1heCAgPSAoYm91bmRzLm1heCAgIT0gbnVsbCkgPyBOdW1iZXIoYm91bmRzLm1heCkgIDogbnVsbDtcclxuXHRcdFx0dmFyIHN0ZXAgPSAoYm91bmRzLnN0ZXAgIT0gbnVsbCkgPyBOdW1iZXIoYm91bmRzLnN0ZXApIDogbnVsbDtcclxuXHJcblx0XHRcdGlmIChwYXJ0cy5yYW5nZSkge1xyXG5cdFx0XHRcdGlmICghaXNOYU4obWluKSkgIHBhcnRzLnJhbmdlLm1pbiAgPSBTdHJpbmcobWluKTtcclxuXHRcdFx0XHRpZiAoIWlzTmFOKG1heCkpICBwYXJ0cy5yYW5nZS5tYXggID0gU3RyaW5nKG1heCk7XHJcblx0XHRcdFx0aWYgKCFpc05hTihzdGVwKSkgcGFydHMucmFuZ2Uuc3RlcCA9IFN0cmluZyhzdGVwKTtcclxuXHRcdFx0fVxyXG5cdFx0XHRpZiAocGFydHMubnVtKSB7XHJcblx0XHRcdFx0aWYgKCFpc05hTihtaW4pKSAgcGFydHMubnVtLm1pbiAgPSBTdHJpbmcobWluKTtcclxuXHRcdFx0XHRpZiAoIWlzTmFOKG1heCkpICBwYXJ0cy5udW0ubWF4ICA9IFN0cmluZyhtYXgpO1xyXG5cdFx0XHRcdGlmICghaXNOYU4oc3RlcCkpIHBhcnRzLm51bS5zdGVwID0gU3RyaW5nKHN0ZXApO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0X2FwcGx5X2JvdW5kc19mb3JfY3VycmVudF91bml0KGdyb3VwKSB7XHJcblx0XHRcdHZhciBwYXJ0cyA9IHRoaXMuX2dldF9wYXJ0cyhncm91cCk7XHJcblx0XHRcdGlmICghcGFydHMgfHwgIXBhcnRzLnVuaXQpIHJldHVybjtcclxuXHJcblx0XHRcdHZhciB1bml0ID0gcGFydHMudW5pdC52YWx1ZSB8fCB0aGlzLl9nZXRfZGVmYXVsdF91bml0KGdyb3VwKTtcclxuXHRcdFx0dmFyIGIgICAgPSB0aGlzLl9nZXRfYm91bmRzX2Zvcl91bml0KGdyb3VwLCB1bml0KTtcclxuXHJcblx0XHRcdHRoaXMuX2FwcGx5X2JvdW5kcyhwYXJ0cywgYik7XHJcblxyXG5cdFx0XHQvLyBDbGFtcCBjdXJyZW50IHZhbHVlIHRvIG5ldyBib3VuZHMuXHJcblx0XHRcdHZhciB2ID0gcGFyc2VfZmxvYXQocGFydHMubnVtICYmIHBhcnRzLm51bS52YWx1ZSA/IHBhcnRzLm51bS52YWx1ZSA6IChwYXJ0cy5yYW5nZSA/IHBhcnRzLnJhbmdlLnZhbHVlIDogJycpKTtcclxuXHRcdFx0aWYgKHYgPT0gbnVsbCkgcmV0dXJuO1xyXG5cclxuXHRcdFx0dmFyIG1pbiA9IChiICYmIGIubWluICE9IG51bGwpID8gTnVtYmVyKGIubWluKSA6IG51bGw7XHJcblx0XHRcdHZhciBtYXggPSAoYiAmJiBiLm1heCAhPSBudWxsKSA/IE51bWJlcihiLm1heCkgOiBudWxsO1xyXG5cdFx0XHR2ID0gY2xhbXBfbnVtKHYsIGlzTmFOKG1pbikgPyBudWxsIDogbWluLCBpc05hTihtYXgpID8gbnVsbCA6IG1heCk7XHJcblxyXG5cdFx0XHRpZiAocGFydHMubnVtKSAgIHBhcnRzLm51bS52YWx1ZSAgID0gU3RyaW5nKHYpO1xyXG5cdFx0XHRpZiAocGFydHMucmFuZ2UpIHBhcnRzLnJhbmdlLnZhbHVlID0gU3RyaW5nKHYpO1xyXG5cclxuXHRcdFx0dGhpcy5fd3JpdGVfY29tYmluZWQocGFydHMsIFN0cmluZyh2KSwgdW5pdCwgLyplbWl0Ki8gZmFsc2UpO1xyXG5cdFx0fVxyXG5cclxuXHRcdF93cml0ZV9jb21iaW5lZChwYXJ0cywgbnVtLCB1bml0LCBlbWl0KSB7XHJcblx0XHRcdGlmICghcGFydHMpIHJldHVybjtcclxuXHJcblx0XHRcdHZhciBjb21iaW5lZCA9IGJ1aWxkX2NvbWJpbmVkKG51bSwgdW5pdCk7XHJcblxyXG5cdFx0XHRpZiAocGFydHMud3JpdGVyKSB7XHJcblx0XHRcdFx0Ly8gQXZvaWQgcmVjdXJzaW9uOiBtYXJrIGFzIGludGVybmFsIHdyaXRlLlxyXG5cdFx0XHRcdHBhcnRzLndyaXRlci5fX3dwYmNfc2xpZGVyX2xlbl9pbnRlcm5hbCA9IHRydWU7XHJcblx0XHRcdFx0cGFydHMud3JpdGVyLnZhbHVlID0gY29tYmluZWQ7XHJcblx0XHRcdFx0aWYgKGVtaXQpIGVtaXRfaW5wdXQocGFydHMud3JpdGVyKTtcclxuXHRcdFx0XHRwYXJ0cy53cml0ZXIuX193cGJjX3NsaWRlcl9sZW5faW50ZXJuYWwgPSBmYWxzZTtcclxuXHRcdFx0fSBlbHNlIGlmIChwYXJ0cy5udW0pIHtcclxuXHRcdFx0XHQvLyBJZiB3cml0ZXIgaXMgbWlzc2luZywgYXQgbGVhc3Qgbm90aWZ5IHZpYSBudW1iZXIgaW5wdXQuXHJcblx0XHRcdFx0aWYgKGVtaXQpIGVtaXRfaW5wdXQocGFydHMubnVtKTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cclxuXHRcdF9zeW5jX2dyb3VwX2Zyb21fd3JpdGVyKGdyb3VwKSB7XHJcblx0XHRcdHZhciBwYXJ0cyA9IHRoaXMuX2dldF9wYXJ0cyhncm91cCk7XHJcblx0XHRcdGlmICghcGFydHMgfHwgIXBhcnRzLndyaXRlcikgcmV0dXJuO1xyXG5cclxuXHRcdFx0dmFyIHJhdyA9IFN0cmluZyhwYXJ0cy53cml0ZXIudmFsdWUgfHwgJycpLnRyaW0oKTtcclxuXHRcdFx0aWYgKCFyYXcpIHJldHVybjtcclxuXHJcblx0XHRcdHZhciBkdSA9IHRoaXMuX2dldF9kZWZhdWx0X3VuaXQoZ3JvdXApO1xyXG5cdFx0XHR2YXIgcCAgPSBwYXJzZV9sZW5fY29tYmluZWQocmF3LCBkdSk7XHJcblxyXG5cdFx0XHRpZiAocGFydHMudW5pdCkgIHBhcnRzLnVuaXQudmFsdWUgID0gcC51bml0O1xyXG5cdFx0XHRpZiAocGFydHMubnVtKSAgIHBhcnRzLm51bS52YWx1ZSAgID0gcC5udW07XHJcblx0XHRcdGlmIChwYXJ0cy5yYW5nZSkgcGFydHMucmFuZ2UudmFsdWUgPSBwLm51bTtcclxuXHRcdH1cclxuXHJcblx0XHRfb25faW5wdXQoZXYpIHtcclxuXHRcdFx0dmFyIHQgPSBldi50YXJnZXQ7XHJcblx0XHRcdGlmICghdCkgcmV0dXJuO1xyXG5cclxuXHRcdFx0dmFyIGdyb3VwID0gdGhpcy5fZmluZF9ncm91cCh0KTtcclxuXHRcdFx0aWYgKCFncm91cCkgcmV0dXJuO1xyXG5cclxuXHRcdFx0dmFyIHBhcnRzID0gdGhpcy5fZ2V0X3BhcnRzKGdyb3VwKTtcclxuXHRcdFx0aWYgKCFwYXJ0cykgcmV0dXJuO1xyXG5cclxuXHRcdFx0Ly8gV3JpdGVyIGNoYW5nZWQgZXh0ZXJuYWxseSAtPiB1cGRhdGUgVUkuXHJcblx0XHRcdGlmIChwYXJ0cy53cml0ZXIgJiYgdCA9PT0gcGFydHMud3JpdGVyKSB7XHJcblx0XHRcdFx0aWYgKHQuX193cGJjX3NsaWRlcl9sZW5faW50ZXJuYWwpIHJldHVybjtcclxuXHRcdFx0XHR0aGlzLl9zeW5jX2dyb3VwX2Zyb21fd3JpdGVyKGdyb3VwKTtcclxuXHRcdFx0XHR0aGlzLl9hcHBseV9ib3VuZHNfZm9yX2N1cnJlbnRfdW5pdChncm91cCk7XHJcblx0XHRcdFx0cmV0dXJuO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBTbGlkZXIgbW92ZWQgLT4gdXBkYXRlIG51bWJlciArIHdyaXRlci5cclxuXHRcdFx0aWYgKHQubWF0Y2hlcyAmJiB0Lm1hdGNoZXModGhpcy5vcHRzLnJhbmdlX3NlbGVjdG9yKSkge1xyXG5cdFx0XHRcdGlmIChwYXJ0cy5udW0pIHBhcnRzLm51bS52YWx1ZSA9IHQudmFsdWU7XHJcblxyXG5cdFx0XHRcdHZhciB1bml0ID0gKHBhcnRzLnVuaXQgJiYgcGFydHMudW5pdC52YWx1ZSkgPyBwYXJ0cy51bml0LnZhbHVlIDogdGhpcy5fZ2V0X2RlZmF1bHRfdW5pdChncm91cCk7XHJcblx0XHRcdFx0dGhpcy5fd3JpdGVfY29tYmluZWQocGFydHMsIHQudmFsdWUsIHVuaXQsIC8qZW1pdCovIHRydWUpO1xyXG5cdFx0XHRcdHJldHVybjtcclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gTnVtYmVyIHR5cGVkIC0+IHVwZGF0ZSBzbGlkZXIgKyB3cml0ZXIgKGNsYW1wIGlmIHNsaWRlciBoYXMgYm91bmRzKS5cclxuXHRcdFx0aWYgKHQubWF0Y2hlcyAmJiB0Lm1hdGNoZXModGhpcy5vcHRzLnZhbHVlX3NlbGVjdG9yKSkge1xyXG5cdFx0XHRcdHZhciB2ID0gcGFyc2VfZmxvYXQodC52YWx1ZSk7XHJcblxyXG5cdFx0XHRcdGlmICh2ICE9IG51bGwgJiYgcGFydHMucmFuZ2UpIHtcclxuXHRcdFx0XHRcdHZhciBybWluID0gTnVtYmVyKHBhcnRzLnJhbmdlLm1pbik7XHJcblx0XHRcdFx0XHR2YXIgcm1heCA9IE51bWJlcihwYXJ0cy5yYW5nZS5tYXgpO1xyXG5cdFx0XHRcdFx0diA9IGNsYW1wX251bSh2LCBpc05hTihybWluKSA/IG51bGwgOiBybWluLCBpc05hTihybWF4KSA/IG51bGwgOiBybWF4KTtcclxuXHJcblx0XHRcdFx0XHRwYXJ0cy5yYW5nZS52YWx1ZSA9IFN0cmluZyh2KTtcclxuXHRcdFx0XHRcdGlmIChTdHJpbmcodikgIT09IHQudmFsdWUpIHQudmFsdWUgPSBTdHJpbmcodik7XHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR2YXIgdW5pdDIgPSAocGFydHMudW5pdCAmJiBwYXJ0cy51bml0LnZhbHVlKSA/IHBhcnRzLnVuaXQudmFsdWUgOiB0aGlzLl9nZXRfZGVmYXVsdF91bml0KGdyb3VwKTtcclxuXHRcdFx0XHR0aGlzLl93cml0ZV9jb21iaW5lZChwYXJ0cywgdC52YWx1ZSwgdW5pdDIsIC8qZW1pdCovIHRydWUpO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0X29uX2NoYW5nZShldikge1xyXG5cdFx0XHR2YXIgdCA9IGV2LnRhcmdldDtcclxuXHRcdFx0aWYgKCF0KSByZXR1cm47XHJcblxyXG5cdFx0XHR2YXIgZ3JvdXAgPSB0aGlzLl9maW5kX2dyb3VwKHQpO1xyXG5cdFx0XHRpZiAoIWdyb3VwKSByZXR1cm47XHJcblxyXG5cdFx0XHR2YXIgcGFydHMgPSB0aGlzLl9nZXRfcGFydHMoZ3JvdXApO1xyXG5cdFx0XHRpZiAoIXBhcnRzKSByZXR1cm47XHJcblxyXG5cdFx0XHQvLyBVbml0IGNoYW5nZWQgLT4gdXBkYXRlIGJvdW5kcyArIHdyaXRlci5cclxuXHRcdFx0aWYgKHQubWF0Y2hlcyAmJiB0Lm1hdGNoZXModGhpcy5vcHRzLnVuaXRfc2VsZWN0b3IpKSB7XHJcblx0XHRcdFx0dGhpcy5fYXBwbHlfYm91bmRzX2Zvcl9jdXJyZW50X3VuaXQoZ3JvdXApO1xyXG5cclxuXHRcdFx0XHR2YXIgbnVtICA9IHBhcnRzLm51bSA/IHBhcnRzLm51bS52YWx1ZSA6IChwYXJ0cy5yYW5nZSA/IHBhcnRzLnJhbmdlLnZhbHVlIDogJycpO1xyXG5cdFx0XHRcdHZhciB1bml0ID0gdC52YWx1ZSB8fCB0aGlzLl9nZXRfZGVmYXVsdF91bml0KGdyb3VwKTtcclxuXHRcdFx0XHR0aGlzLl93cml0ZV9jb21iaW5lZChwYXJ0cywgbnVtLCB1bml0LCAvKmVtaXQqLyB0cnVlKTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdC8vIEF1dG8taW5pdFxyXG5cdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRmdW5jdGlvbiB3cGJjX3NsaWRlcl9sZW5fZ3JvdXBzX19hdXRvX2luaXQoKSB7XHJcblx0XHR2YXIgUk9PVCAgPSAnLndwYmNfc2xpZGVyX2xlbl9ncm91cHMnO1xyXG5cdFx0dmFyIG5vZGVzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoZC5xdWVyeVNlbGVjdG9yQWxsKFJPT1QpKVxyXG5cdFx0XHQuZmlsdGVyKGZ1bmN0aW9uIChuKSB7IHJldHVybiAhbi5wYXJlbnRFbGVtZW50IHx8ICFuLnBhcmVudEVsZW1lbnQuY2xvc2VzdChST09UKTsgfSk7XHJcblxyXG5cdFx0Ly8gSWYgbm8gZXhwbGljaXQgY29udGFpbmVycywgaW5zdGFsbCBhIHNpbmdsZSBkb2N1bWVudC1yb290IGluc3RhbmNlLlxyXG5cdFx0aWYgKCFub2Rlcy5sZW5ndGgpIHtcclxuXHRcdFx0aWYgKCFkLl9fd3BiY19zbGlkZXJfbGVuX2dyb3Vwc19nbG9iYWxfaW5zdGFuY2UpIHtcclxuXHRcdFx0XHRkLl9fd3BiY19zbGlkZXJfbGVuX2dyb3Vwc19nbG9iYWxfaW5zdGFuY2UgPSBuZXcgV1BCQ19TbGlkZXJfTGVuX0dyb3VwcyhkKS5pbml0KCk7XHJcblx0XHRcdH1cclxuXHRcdFx0cmV0dXJuO1xyXG5cdFx0fVxyXG5cclxuXHRcdG5vZGVzLmZvckVhY2goZnVuY3Rpb24gKG5vZGUpIHtcclxuXHRcdFx0aWYgKG5vZGUuX193cGJjX3NsaWRlcl9sZW5fZ3JvdXBzX2luc3RhbmNlKSByZXR1cm47XHJcblx0XHRcdG5vZGUuX193cGJjX3NsaWRlcl9sZW5fZ3JvdXBzX2luc3RhbmNlID0gbmV3IFdQQkNfU2xpZGVyX0xlbl9Hcm91cHMobm9kZSkuaW5pdCgpO1xyXG5cdFx0fSk7XHJcblx0fVxyXG5cclxuXHQvLyBFeHBvcnQgZ2xvYmFscyAobWFudWFsIGNvbnRyb2wgaWYgbmVlZGVkKS5cclxuXHR3LldQQkNfU2xpZGVyX0xlbl9Hcm91cHMgICA9IFdQQkNfU2xpZGVyX0xlbl9Hcm91cHM7XHJcblx0dy5XUEJDX1NsaWRlcl9MZW5fQXV0b0luaXQgPSB3cGJjX3NsaWRlcl9sZW5fZ3JvdXBzX19hdXRvX2luaXQ7XHJcblxyXG5cdC8vIERPTS1yZWFkeSBhdXRvIGluaXQuXHJcblx0aWYgKGQucmVhZHlTdGF0ZSA9PT0gJ2xvYWRpbmcnKSB7XHJcblx0XHRkLmFkZEV2ZW50TGlzdGVuZXIoJ0RPTUNvbnRlbnRMb2FkZWQnLCB3cGJjX3NsaWRlcl9sZW5fZ3JvdXBzX19hdXRvX2luaXQsIHsgb25jZTogdHJ1ZSB9KTtcclxuXHR9IGVsc2Uge1xyXG5cdFx0d3BiY19zbGlkZXJfbGVuX2dyb3Vwc19fYXV0b19pbml0KCk7XHJcblx0fVxyXG5cclxufSkod2luZG93LCBkb2N1bWVudCk7XHJcbiIsIi8qIGdsb2JhbHMgd2luZG93LCBkb2N1bWVudCAqL1xyXG4vKipcclxuICogV1BCQyBTbGlkZXIgUmFuZ2UgR3JvdXBzXHJcbiAqXHJcbiAqIFVuaXZlcnNhbCwgZGVwZW5kZW5jeS1mcmVlIGNvbnRyb2xsZXIgdGhhdCBrZWVwcyBhIFwicmFuZ2UgKyBudW1iZXJcIiBwYWlyIGluIHN5bmM6XHJcbiAqICAtIG51bWJlciBpbnB1dCAgKGRhdGEtd3BiY19zbGlkZXJfcmFuZ2VfdmFsdWUpXHJcbiAqICAtIHJhbmdlIHNsaWRlciAgKGRhdGEtd3BiY19zbGlkZXJfcmFuZ2VfcmFuZ2UpXHJcbiAqICAtIHdyaXRlciBpbnB1dCAgKGRhdGEtd3BiY19zbGlkZXJfcmFuZ2Vfd3JpdGVyKSBbb3B0aW9uYWxdXHJcbiAqXHJcbiAqIElmIHdyaXRlciBleGlzdHM6IG51bWJlci9zbGlkZXIgdXBkYXRlIHdyaXRlciBhbmQgZW1pdCAnaW5wdXQnIG9uIHdyaXRlciAoYnViYmxlcykuXHJcbiAqIElmIHdyaXRlciBpcyBtaXNzaW5nOiBlbWl0cyAnaW5wdXQnIG9uIHRoZSBudW1iZXIgaW5wdXQuXHJcbiAqIElmIHdyaXRlciBjaGFuZ2VzIGV4dGVybmFsbHk6IHVwZGF0ZXMgbnVtYmVyL3NsaWRlci5cclxuICpcclxuICogTWFya3VwIGV4cGVjdGF0aW9ucyAobWluaW1hbCk6XHJcbiAqICA8ZGl2IGNsYXNzPVwid3BiY19zbGlkZXJfcmFuZ2VfZ3JvdXBcIj5cclxuICogICAgPGlucHV0IHR5cGU9XCJudW1iZXJcIiBkYXRhLXdwYmNfc2xpZGVyX3JhbmdlX3ZhbHVlPlxyXG4gKiAgICA8aW5wdXQgdHlwZT1cInJhbmdlXCIgIGRhdGEtd3BiY19zbGlkZXJfcmFuZ2VfcmFuZ2U+XHJcbiAqICAgIDwhLS0gb3B0aW9uYWwgLS0+XHJcbiAqICAgIDxpbnB1dCB0eXBlPVwidGV4dFwiIGRhdGEtd3BiY19zbGlkZXJfcmFuZ2Vfd3JpdGVyIHN0eWxlPVwiZGlzcGxheTpub25lO1wiPlxyXG4gKiAgPC9kaXY+XHJcbiAqXHJcbiAqIFBlcmZvcm1hbmNlIG5vdGVzOlxyXG4gKiAtIE11dGF0aW9uT2JzZXJ2ZXIgaXMgRElTQUJMRUQgYnkgZGVmYXVsdC5cclxuICogLSBJZiB5b3VyIFVJIHJlLXJlbmRlcnMgYW5kIGluc2VydHMgbmV3IGdyb3VwcyBkeW5hbWljYWxseSwgY2FsbDpcclxuICogICAgIFdQQkNfU2xpZGVyX1JhbmdlX0F1dG9Jbml0KCk7IE9SIGluc3RhbmNlLnJlZnJlc2goKTtcclxuICogICBPciBlbmFibGUgb2JzZXJ2ZXIgdmlhOiBuZXcgV1BCQ19TbGlkZXJfUmFuZ2VfR3JvdXBzKHJvb3QsIHsgZW5hYmxlX29ic2VydmVyOnRydWUgfSkuaW5pdCgpO1xyXG4gKlxyXG4gKiBQdWJsaWMgQVBJIChpbnN0YW5jZSBtZXRob2RzKTpcclxuICogIC0gaW5pdCgpLCBkZXN0cm95KCksIHJlZnJlc2goKVxyXG4gKlxyXG4gKiBAdmVyc2lvbiAyMDI2LTAxLTI1XHJcbiAqIEBzaW5jZSAgIDIwMjYtMDEtMjVcclxuICogQGZpbGUgICAgLi4vaW5jbHVkZXMvX19qcy9hZG1pbi9zbGlkZXJfZ3JvdXBzL3dwYmNfcmFuZ2VfZ3JvdXBzLmpzXHJcbiAqL1xyXG4oZnVuY3Rpb24gKHcsIGQpIHtcclxuXHQndXNlIHN0cmljdCc7XHJcblxyXG5cdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHQvLyBIZWxwZXJzXHJcblx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdGZ1bmN0aW9uIGNsYW1wX251bSh2LCBtaW4sIG1heCkge1xyXG5cdFx0aWYgKHR5cGVvZiBtaW4gPT09ICdudW1iZXInICYmICFpc05hTihtaW4pKSB2ID0gTWF0aC5tYXgobWluLCB2KTtcclxuXHRcdGlmICh0eXBlb2YgbWF4ID09PSAnbnVtYmVyJyAmJiAhaXNOYU4obWF4KSkgdiA9IE1hdGgubWluKG1heCwgdik7XHJcblx0XHRyZXR1cm4gdjtcclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIHBhcnNlX2Zsb2F0KHYpIHtcclxuXHRcdHZhciBuID0gcGFyc2VGbG9hdCh2KTtcclxuXHRcdHJldHVybiBpc05hTihuKSA/IG51bGwgOiBuO1xyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gZW1pdF9pbnB1dChlbCkge1xyXG5cdFx0aWYgKCFlbCkgcmV0dXJuO1xyXG5cdFx0ZWwuZGlzcGF0Y2hFdmVudChuZXcgRXZlbnQoJ2lucHV0JywgeyBidWJibGVzOiB0cnVlIH0pKTtcclxuXHR9XHJcblxyXG5cdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHQvLyBDb250cm9sbGVyXHJcblx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdGNsYXNzIFdQQkNfU2xpZGVyX1JhbmdlX0dyb3VwcyB7XHJcblxyXG5cdFx0LyoqXHJcblx0XHQgKiBAcGFyYW0ge0hUTUxFbGVtZW50fHN0cmluZ30gcm9vdF9lbCBDb250YWluZXIgKG9yIHNlbGVjdG9yKS4gSWYgb21pdHRlZCwgdXNlcyBkb2N1bWVudC5cclxuXHRcdCAqIEBwYXJhbSB7T2JqZWN0fSBbb3B0cz17fV1cclxuXHRcdCAqL1xyXG5cdFx0Y29uc3RydWN0b3Iocm9vdF9lbCwgb3B0cykge1xyXG5cdFx0XHR0aGlzLnJvb3QgPSByb290X2VsXHJcblx0XHRcdFx0PyAoKHR5cGVvZiByb290X2VsID09PSAnc3RyaW5nJykgPyBkLnF1ZXJ5U2VsZWN0b3Iocm9vdF9lbCkgOiByb290X2VsKVxyXG5cdFx0XHRcdDogZDtcclxuXHJcblx0XHRcdHRoaXMub3B0cyA9IE9iamVjdC5hc3NpZ24oe1xyXG5cdFx0XHRcdC8vIFN0cmljdCBzZWxlY3RvcnMgKE5PIGJhY2t3YXJkIGNvbXBhdGliaWxpdHkpLlxyXG5cdFx0XHRcdGdyb3VwX3NlbGVjdG9yICA6ICcud3BiY19zbGlkZXJfcmFuZ2VfZ3JvdXAnLFxyXG5cdFx0XHRcdHZhbHVlX3NlbGVjdG9yICA6ICdbZGF0YS13cGJjX3NsaWRlcl9yYW5nZV92YWx1ZV0nLFxyXG5cdFx0XHRcdHJhbmdlX3NlbGVjdG9yICA6ICdbZGF0YS13cGJjX3NsaWRlcl9yYW5nZV9yYW5nZV0nLFxyXG5cdFx0XHRcdHdyaXRlcl9zZWxlY3RvciA6ICdbZGF0YS13cGJjX3NsaWRlcl9yYW5nZV93cml0ZXJdJyxcclxuXHJcblx0XHRcdFx0Ly8gRGlzYWJsZWQgYnkgZGVmYXVsdCBmb3IgcGVyZm9ybWFuY2UuXHJcblx0XHRcdFx0ZW5hYmxlX29ic2VydmVyICAgICA6IGZhbHNlLFxyXG5cdFx0XHRcdG9ic2VydmVyX2RlYm91bmNlX21zOiAxNTBcclxuXHRcdFx0fSwgb3B0cyB8fCB7fSk7XHJcblxyXG5cdFx0XHR0aGlzLl9vbl9pbnB1dCAgPSB0aGlzLl9vbl9pbnB1dC5iaW5kKHRoaXMpO1xyXG5cdFx0XHR0aGlzLl9vbl9jaGFuZ2UgPSB0aGlzLl9vbl9jaGFuZ2UuYmluZCh0aGlzKTtcclxuXHJcblx0XHRcdHRoaXMuX29ic2VydmVyICAgID0gbnVsbDtcclxuXHRcdFx0dGhpcy5fcmVmcmVzaF90bXIgPSBudWxsO1xyXG5cdFx0fVxyXG5cclxuXHRcdGluaXQoKSB7XHJcblx0XHRcdGlmICghdGhpcy5yb290KSByZXR1cm4gdGhpcztcclxuXHJcblx0XHRcdHRoaXMucm9vdC5hZGRFdmVudExpc3RlbmVyKCdpbnB1dCcsICB0aGlzLl9vbl9pbnB1dCwgIHRydWUpO1xyXG5cdFx0XHR0aGlzLnJvb3QuYWRkRXZlbnRMaXN0ZW5lcignY2hhbmdlJywgdGhpcy5fb25fY2hhbmdlLCB0cnVlKTtcclxuXHJcblx0XHRcdGlmICh0aGlzLm9wdHMuZW5hYmxlX29ic2VydmVyICYmIHcuTXV0YXRpb25PYnNlcnZlcikge1xyXG5cdFx0XHRcdHRoaXMuX29ic2VydmVyID0gbmV3IE11dGF0aW9uT2JzZXJ2ZXIoKCkgPT4geyB0aGlzLl9kZWJvdW5jZWRfcmVmcmVzaCgpOyB9KTtcclxuXHRcdFx0XHR0aGlzLl9vYnNlcnZlci5vYnNlcnZlKHRoaXMucm9vdCA9PT0gZCA/IGQuZG9jdW1lbnRFbGVtZW50IDogdGhpcy5yb290LCB7IGNoaWxkTGlzdDogdHJ1ZSwgc3VidHJlZTogdHJ1ZSB9KTtcclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0dGhpcy5yZWZyZXNoKCk7XHJcblx0XHRcdHJldHVybiB0aGlzO1xyXG5cdFx0fVxyXG5cclxuXHRcdGRlc3Ryb3koKSB7XHJcblx0XHRcdGlmICghdGhpcy5yb290KSByZXR1cm47XHJcblxyXG5cdFx0XHR0aGlzLnJvb3QucmVtb3ZlRXZlbnRMaXN0ZW5lcignaW5wdXQnLCAgdGhpcy5fb25faW5wdXQsICB0cnVlKTtcclxuXHRcdFx0dGhpcy5yb290LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ2NoYW5nZScsIHRoaXMuX29uX2NoYW5nZSwgdHJ1ZSk7XHJcblxyXG5cdFx0XHRpZiAodGhpcy5fb2JzZXJ2ZXIpIHtcclxuXHRcdFx0XHR0aGlzLl9vYnNlcnZlci5kaXNjb25uZWN0KCk7XHJcblx0XHRcdFx0dGhpcy5fb2JzZXJ2ZXIgPSBudWxsO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpZiAodGhpcy5fcmVmcmVzaF90bXIpIHtcclxuXHRcdFx0XHRjbGVhclRpbWVvdXQodGhpcy5fcmVmcmVzaF90bXIpO1xyXG5cdFx0XHRcdHRoaXMuX3JlZnJlc2hfdG1yID0gbnVsbDtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cclxuXHRcdHJlZnJlc2goKSB7XHJcblx0XHRcdGlmICghdGhpcy5yb290KSByZXR1cm47XHJcblxyXG5cdFx0XHR2YXIgc2NvcGUgID0gKHRoaXMucm9vdCA9PT0gZCA/IGQgOiB0aGlzLnJvb3QpO1xyXG5cdFx0XHR2YXIgZ3JvdXBzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoc2NvcGUucXVlcnlTZWxlY3RvckFsbCh0aGlzLm9wdHMuZ3JvdXBfc2VsZWN0b3IpKTtcclxuXHJcblx0XHRcdGZvciAodmFyIGkgPSAwOyBpIDwgZ3JvdXBzLmxlbmd0aDsgaSsrKSB7XHJcblx0XHRcdFx0dGhpcy5fc3luY19mcm9tX3dyaXRlcihncm91cHNbaV0pO1xyXG5cdFx0XHRcdHRoaXMuX2NsYW1wX3RvX3JhbmdlKGdyb3Vwc1tpXSk7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHQvLyBJbnRlcm5hbFxyXG5cdFx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdFx0X2RlYm91bmNlZF9yZWZyZXNoKCkge1xyXG5cdFx0XHRpZiAodGhpcy5fcmVmcmVzaF90bXIpIGNsZWFyVGltZW91dCh0aGlzLl9yZWZyZXNoX3Rtcik7XHJcblx0XHRcdHRoaXMuX3JlZnJlc2hfdG1yID0gc2V0VGltZW91dCgoKSA9PiB7XHJcblx0XHRcdFx0dGhpcy5fcmVmcmVzaF90bXIgPSBudWxsO1xyXG5cdFx0XHRcdHRoaXMucmVmcmVzaCgpO1xyXG5cdFx0XHR9LCBOdW1iZXIodGhpcy5vcHRzLm9ic2VydmVyX2RlYm91bmNlX21zKSB8fCAwKTtcclxuXHRcdH1cclxuXHJcblx0XHRfZmluZF9ncm91cChlbCkge1xyXG5cdFx0XHRyZXR1cm4gKGVsICYmIGVsLmNsb3Nlc3QpID8gZWwuY2xvc2VzdCh0aGlzLm9wdHMuZ3JvdXBfc2VsZWN0b3IpIDogbnVsbDtcclxuXHRcdH1cclxuXHJcblx0XHRfZ2V0X3BhcnRzKGdyb3VwKSB7XHJcblx0XHRcdGlmICghZ3JvdXApIHJldHVybiBudWxsO1xyXG5cdFx0XHRyZXR1cm4ge1xyXG5cdFx0XHRcdGdyb3VwIDogZ3JvdXAsXHJcblx0XHRcdFx0bnVtICAgOiBncm91cC5xdWVyeVNlbGVjdG9yKHRoaXMub3B0cy52YWx1ZV9zZWxlY3RvciksXHJcblx0XHRcdFx0cmFuZ2UgOiBncm91cC5xdWVyeVNlbGVjdG9yKHRoaXMub3B0cy5yYW5nZV9zZWxlY3RvciksXHJcblx0XHRcdFx0d3JpdGVyOiBncm91cC5xdWVyeVNlbGVjdG9yKHRoaXMub3B0cy53cml0ZXJfc2VsZWN0b3IpXHJcblx0XHRcdH07XHJcblx0XHR9XHJcblxyXG5cdFx0X3dyaXRlKHBhcnRzLCB2YWx1ZSwgZW1pdCkge1xyXG5cdFx0XHRpZiAoIXBhcnRzKSByZXR1cm47XHJcblxyXG5cdFx0XHRpZiAocGFydHMud3JpdGVyKSB7XHJcblx0XHRcdFx0cGFydHMud3JpdGVyLl9fd3BiY19zbGlkZXJfcmFuZ2VfaW50ZXJuYWwgPSB0cnVlO1xyXG5cdFx0XHRcdHBhcnRzLndyaXRlci52YWx1ZSA9IFN0cmluZyh2YWx1ZSk7XHJcblx0XHRcdFx0aWYgKGVtaXQpIGVtaXRfaW5wdXQocGFydHMud3JpdGVyKTtcclxuXHRcdFx0XHRwYXJ0cy53cml0ZXIuX193cGJjX3NsaWRlcl9yYW5nZV9pbnRlcm5hbCA9IGZhbHNlO1xyXG5cdFx0XHR9IGVsc2UgaWYgKHBhcnRzLm51bSkge1xyXG5cdFx0XHRcdC8vIElmIHdyaXRlciBpcyBtaXNzaW5nLCBhdCBsZWFzdCBub3RpZnkgdmlhIG51bWJlciBpbnB1dC5cclxuXHRcdFx0XHRpZiAoZW1pdCkgZW1pdF9pbnB1dChwYXJ0cy5udW0pO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0X3N5bmNfZnJvbV93cml0ZXIoZ3JvdXApIHtcclxuXHRcdFx0dmFyIHBhcnRzID0gdGhpcy5fZ2V0X3BhcnRzKGdyb3VwKTtcclxuXHRcdFx0aWYgKCFwYXJ0cyB8fCAhcGFydHMud3JpdGVyKSByZXR1cm47XHJcblxyXG5cdFx0XHR2YXIgcmF3ID0gU3RyaW5nKHBhcnRzLndyaXRlci52YWx1ZSB8fCAnJykudHJpbSgpO1xyXG5cdFx0XHRpZiAoIXJhdykgcmV0dXJuO1xyXG5cclxuXHRcdFx0aWYgKHBhcnRzLm51bSkgICBwYXJ0cy5udW0udmFsdWUgICA9IHJhdztcclxuXHRcdFx0aWYgKHBhcnRzLnJhbmdlKSBwYXJ0cy5yYW5nZS52YWx1ZSA9IHJhdztcclxuXHRcdH1cclxuXHJcblx0XHRfY2xhbXBfdG9fcmFuZ2UoZ3JvdXApIHtcclxuXHRcdFx0dmFyIHBhcnRzID0gdGhpcy5fZ2V0X3BhcnRzKGdyb3VwKTtcclxuXHRcdFx0aWYgKCFwYXJ0cyB8fCAhcGFydHMucmFuZ2UgfHwgIXBhcnRzLm51bSkgcmV0dXJuO1xyXG5cclxuXHRcdFx0dmFyIHYgPSBwYXJzZV9mbG9hdChwYXJ0cy5udW0udmFsdWUpO1xyXG5cdFx0XHRpZiAodiA9PSBudWxsKSByZXR1cm47XHJcblxyXG5cdFx0XHR2YXIgbWluID0gTnVtYmVyKHBhcnRzLnJhbmdlLm1pbik7XHJcblx0XHRcdHZhciBtYXggPSBOdW1iZXIocGFydHMucmFuZ2UubWF4KTtcclxuXHRcdFx0dmFyIHZ2ICA9IGNsYW1wX251bSh2LCBpc05hTihtaW4pID8gbnVsbCA6IG1pbiwgaXNOYU4obWF4KSA/IG51bGwgOiBtYXgpO1xyXG5cclxuXHRcdFx0aWYgKFN0cmluZyh2dikgIT09IHBhcnRzLm51bS52YWx1ZSkgcGFydHMubnVtLnZhbHVlID0gU3RyaW5nKHZ2KTtcclxuXHRcdFx0cGFydHMucmFuZ2UudmFsdWUgPSBTdHJpbmcodnYpO1xyXG5cdFx0fVxyXG5cclxuXHRcdF9vbl9pbnB1dChldikge1xyXG5cdFx0XHR2YXIgdCA9IGV2LnRhcmdldDtcclxuXHRcdFx0aWYgKCF0KSByZXR1cm47XHJcblxyXG5cdFx0XHR2YXIgZ3JvdXAgPSB0aGlzLl9maW5kX2dyb3VwKHQpO1xyXG5cdFx0XHRpZiAoIWdyb3VwKSByZXR1cm47XHJcblxyXG5cdFx0XHR2YXIgcGFydHMgPSB0aGlzLl9nZXRfcGFydHMoZ3JvdXApO1xyXG5cdFx0XHRpZiAoIXBhcnRzKSByZXR1cm47XHJcblxyXG5cdFx0XHQvLyBXcml0ZXIgY2hhbmdlZCBleHRlcm5hbGx5IC0+IHVwZGF0ZSBVSS5cclxuXHRcdFx0aWYgKHBhcnRzLndyaXRlciAmJiB0ID09PSBwYXJ0cy53cml0ZXIpIHtcclxuXHRcdFx0XHRpZiAodC5fX3dwYmNfc2xpZGVyX3JhbmdlX2ludGVybmFsKSByZXR1cm47XHJcblx0XHRcdFx0dGhpcy5fc3luY19mcm9tX3dyaXRlcihncm91cCk7XHJcblx0XHRcdFx0dGhpcy5fY2xhbXBfdG9fcmFuZ2UoZ3JvdXApO1xyXG5cdFx0XHRcdHJldHVybjtcclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gUmFuZ2UgbW92ZWQgLT4gdXBkYXRlIG51bWJlciArIHdyaXRlci5cclxuXHRcdFx0aWYgKHQubWF0Y2hlcyAmJiB0Lm1hdGNoZXModGhpcy5vcHRzLnJhbmdlX3NlbGVjdG9yKSkge1xyXG5cdFx0XHRcdGlmIChwYXJ0cy5udW0pIHBhcnRzLm51bS52YWx1ZSA9IHQudmFsdWU7XHJcblx0XHRcdFx0dGhpcy5fd3JpdGUocGFydHMsIHQudmFsdWUsIC8qZW1pdCovIHRydWUpO1xyXG5cdFx0XHRcdHJldHVybjtcclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gTnVtYmVyIHR5cGVkIC0+IHVwZGF0ZSByYW5nZSArIHdyaXRlciAoY2xhbXAgYnkgc2xpZGVyIGJvdW5kcykuXHJcblx0XHRcdGlmICh0Lm1hdGNoZXMgJiYgdC5tYXRjaGVzKHRoaXMub3B0cy52YWx1ZV9zZWxlY3RvcikpIHtcclxuXHRcdFx0XHRpZiAocGFydHMucmFuZ2UpIHtcclxuXHRcdFx0XHRcdHZhciB2ID0gcGFyc2VfZmxvYXQodC52YWx1ZSk7XHJcblx0XHRcdFx0XHRpZiAodiAhPSBudWxsKSB7XHJcblx0XHRcdFx0XHRcdHZhciBtaW4gPSBOdW1iZXIocGFydHMucmFuZ2UubWluKTtcclxuXHRcdFx0XHRcdFx0dmFyIG1heCA9IE51bWJlcihwYXJ0cy5yYW5nZS5tYXgpO1xyXG5cdFx0XHRcdFx0XHR2ID0gY2xhbXBfbnVtKHYsIGlzTmFOKG1pbikgPyBudWxsIDogbWluLCBpc05hTihtYXgpID8gbnVsbCA6IG1heCk7XHJcblxyXG5cdFx0XHRcdFx0XHRwYXJ0cy5yYW5nZS52YWx1ZSA9IFN0cmluZyh2KTtcclxuXHRcdFx0XHRcdFx0aWYgKFN0cmluZyh2KSAhPT0gdC52YWx1ZSkgdC52YWx1ZSA9IFN0cmluZyh2KTtcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9XHJcblx0XHRcdFx0dGhpcy5fd3JpdGUocGFydHMsIHQudmFsdWUsIC8qZW1pdCovIHRydWUpO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0X29uX2NoYW5nZShldikge1xyXG5cdFx0XHQvLyBObyBzcGVjaWFsIFwiY2hhbmdlXCIgaGFuZGxpbmcgbmVlZGVkIGN1cnJlbnRseTsga2VwdCBmb3Igc3ltbWV0cnkvZnV0dXJlLlxyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cdC8vIEF1dG8taW5pdFxyXG5cdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHRmdW5jdGlvbiB3cGJjX3NsaWRlcl9yYW5nZV9ncm91cHNfX2F1dG9faW5pdCgpIHtcclxuXHRcdHZhciBST09UICA9ICcud3BiY19zbGlkZXJfcmFuZ2VfZ3JvdXBzJztcclxuXHRcdHZhciBub2RlcyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGQucXVlcnlTZWxlY3RvckFsbChST09UKSlcclxuXHRcdFx0LmZpbHRlcihmdW5jdGlvbiAobikgeyByZXR1cm4gIW4ucGFyZW50RWxlbWVudCB8fCAhbi5wYXJlbnRFbGVtZW50LmNsb3Nlc3QoUk9PVCk7IH0pO1xyXG5cclxuXHRcdGlmICghbm9kZXMubGVuZ3RoKSB7XHJcblx0XHRcdGlmICghZC5fX3dwYmNfc2xpZGVyX3JhbmdlX2dyb3Vwc19nbG9iYWxfaW5zdGFuY2UpIHtcclxuXHRcdFx0XHRkLl9fd3BiY19zbGlkZXJfcmFuZ2VfZ3JvdXBzX2dsb2JhbF9pbnN0YW5jZSA9IG5ldyBXUEJDX1NsaWRlcl9SYW5nZV9Hcm91cHMoZCkuaW5pdCgpO1xyXG5cdFx0XHR9XHJcblx0XHRcdHJldHVybjtcclxuXHRcdH1cclxuXHJcblx0XHRub2Rlcy5mb3JFYWNoKGZ1bmN0aW9uIChub2RlKSB7XHJcblx0XHRcdGlmIChub2RlLl9fd3BiY19zbGlkZXJfcmFuZ2VfZ3JvdXBzX2luc3RhbmNlKSByZXR1cm47XHJcblx0XHRcdG5vZGUuX193cGJjX3NsaWRlcl9yYW5nZV9ncm91cHNfaW5zdGFuY2UgPSBuZXcgV1BCQ19TbGlkZXJfUmFuZ2VfR3JvdXBzKG5vZGUpLmluaXQoKTtcclxuXHRcdH0pO1xyXG5cdH1cclxuXHJcblx0Ly8gRXhwb3J0IGdsb2JhbHMuXHJcblx0dy5XUEJDX1NsaWRlcl9SYW5nZV9Hcm91cHMgICA9IFdQQkNfU2xpZGVyX1JhbmdlX0dyb3VwcztcclxuXHR3LldQQkNfU2xpZGVyX1JhbmdlX0F1dG9Jbml0ID0gd3BiY19zbGlkZXJfcmFuZ2VfZ3JvdXBzX19hdXRvX2luaXQ7XHJcblxyXG5cdGlmIChkLnJlYWR5U3RhdGUgPT09ICdsb2FkaW5nJykge1xyXG5cdFx0ZC5hZGRFdmVudExpc3RlbmVyKCdET01Db250ZW50TG9hZGVkJywgd3BiY19zbGlkZXJfcmFuZ2VfZ3JvdXBzX19hdXRvX2luaXQsIHsgb25jZTogdHJ1ZSB9KTtcclxuXHR9IGVsc2Uge1xyXG5cdFx0d3BiY19zbGlkZXJfcmFuZ2VfZ3JvdXBzX19hdXRvX2luaXQoKTtcclxuXHR9XHJcblxyXG59KSh3aW5kb3csIGRvY3VtZW50KTtcclxuIiwiLyoqXHJcbiAqIEJvb2tpbmcgQ2FsZW5kYXIg4oCUIEdlbmVyaWMgVUkgVGFicyBVdGlsaXR5IChKUylcclxuICpcclxuICogUHVycG9zZTogTGlnaHR3ZWlnaHQsIGRlcGVuZGVuY3ktZnJlZSB0YWJzIGNvbnRyb2xsZXIgZm9yIGFueSBzbWFsbCB0YWIgZ3JvdXAgaW4gYWRtaW4gVUlzLlxyXG4gKiAtIEF1dG8taW5pdGlhbGl6ZXMgZ3JvdXBzIG1hcmtlZCB3aXRoIGRhdGEtd3BiYy10YWJzLlxyXG4gKiAtIEFzc2lnbnMgQVJJQSByb2xlcyBhbmQgdG9nZ2xlcyBhcmlhLXNlbGVjdGVkL2FyaWEtaGlkZGVuL3RhYmluZGV4LlxyXG4gKiAtIFN1cHBvcnRzIGtleWJvYXJkIG5hdmlnYXRpb24gKExlZnQvUmlnaHQvSG9tZS9FbmQpLlxyXG4gKiAtIFB1YmxpYyBBUEk6IHdpbmRvdy53cGJjX3VpX3RhYnMue2luaXRfb24sIGluaXRfZ3JvdXAsIHNldF9hY3RpdmV9XHJcbiAqIC0gRW1pdHMgJ3dwYmM6dGFiczpjaGFuZ2UnIG9uIHRoZSBncm91cCByb290IHdoZW4gdGhlIGFjdGl2ZSB0YWIgY2hhbmdlcy5cclxuICpcclxuICogTWFya3VwIGNvbnRyYWN0OlxyXG4gKiAtIFJvb3Q6ICAgW2RhdGEtd3BiYy10YWJzXVxyXG4gKiAtIFRhYnM6ICAgW2RhdGEtd3BiYy10YWIta2V5PVwiS1wiXVxyXG4gKiAtIFBhbmVsczogW2RhdGEtd3BiYy10YWItcGFuZWw9XCJLXCJdXHJcbiAqXHJcbiAqIEBwYWNrYWdlICAgQm9va2luZyBDYWxlbmRhclxyXG4gKiBAc3VicGFja2FnZSBBZG1pblxcVUlcclxuICogQHNpbmNlICAgICAxMS4wLjBcclxuICogQHZlcnNpb24gICAxLjAuMFxyXG4gKiBAc2VlICAgICAgIC9pbmNsdWRlcy9fX2pzL2FkbWluL3VpX3RhYnMvdWlfdGFicy5qc1xyXG4gKlxyXG4gKlxyXG4gKiBIb3cgaXQgd29ya3M6XHJcbiAqIC0gUm9vdCBub2RlIG11c3QgaGF2ZSBbZGF0YS13cGJjLXRhYnNdIGF0dHJpYnV0ZSAoYW55IHZhbHVlKS5cclxuICogLSBUYWIgYnV0dG9ucyBtdXN0IGNhcnJ5IFtkYXRhLXdwYmMtdGFiLWtleT1cIi4uLlwiXSAodW5pcXVlIHBlciBncm91cCkuXHJcbiAqIC0gUGFuZWxzIG11c3QgY2FycnkgW2RhdGEtd3BiYy10YWItcGFuZWw9XCIuLi5cIl0gd2l0aCBtYXRjaGluZyBrZXlzLlxyXG4gKiAtIEFkZHMgV0FJLUFSSUEgcm9sZXMgYW5kIGFyaWEtc2VsZWN0ZWQvaGlkZGVuIHdpcmluZy5cclxuICpcclxuICogPGRpdiBkYXRhLXdwYmMtdGFicz1cImNvbHVtbi1zdHlsZXNcIiBkYXRhLXdwYmMtdGFiLWFjdGl2ZT1cIjFcIiAgICBjbGFzcz1cIndwYmNfdWlfdGFic19yb290XCIgPlxyXG4gKiAgICA8IS0tIFRvcCBUYWJzIC0tPlxyXG4gKiAgICA8ZGl2IGRhdGEtd3BiYy10YWJsaXN0PVwiXCIgcm9sZT1cInRhYmxpc3RcIiAgICAgICAgICAgICAgICAgICAgY2xhc3M9XCIgd3BiY191aV9lbF9faG9yaXNfdG9wX2Jhcl9fd3JhcHBlclwiID5cclxuICogICAgICAgIDxkaXYgY2xhc3M9XCJ3cGJjX3VpX2VsX19ob3Jpc190b3BfYmFyX19jb250ZW50XCI+XHJcbiAqICAgICAgICAgICAgPGgyIGNsYXNzPVwid3BiY191aV9lbF9faG9yaXNfbmF2X2xhYmVsXCI+Q29sdW1uOjwvaDI+XHJcbiAqXHJcbiAqICAgICAgICAgICAgPGRpdiBjbGFzcz1cIndwYmNfdWlfZWxfX2hvcmlzX25hdl9pdGVtIHdwYmNfdWlfZWxfX2hvcmlzX25hdl9pdGVtX18xXCI+XHJcbiAqICAgICAgICAgICAgICAgIDxhXHJcbiAqICAgICAgICAgICAgICAgICAgICBkYXRhLXdwYmMtdGFiLWtleT1cIjFcIlxyXG4gKiAgICAgICAgICAgICAgICAgICAgYXJpYS1zZWxlY3RlZD1cInRydWVcIiByb2xlPVwidGFiXCIgdGFiaW5kZXg9XCIwXCIgYXJpYS1jb250cm9scz1cIndwYmNfdGFiX3BhbmVsX2NvbF8xXCJcclxuICpcclxuICogICAgICAgICAgICAgICAgICAgICAgICBocmVmPVwiamF2YXNjcmlwdDp2b2lkKDApO1wiXHJcbiAqICAgICAgICAgICAgICAgICAgICAgICAgY2xhc3M9XCJ3cGJjX3VpX2VsX19ob3Jpc19uYXZfaXRlbV9fYSB3cGJjX3VpX2VsX19ob3Jpc19uYXZfaXRlbV9fc2luZ2xlXCJcclxuICogICAgICAgICAgICAgICAgICAgICAgICBpZD1cIndwYmNfdGFiX2NvbF8xXCJcclxuICogICAgICAgICAgICAgICAgICAgICAgICB0aXRsZT1cIkNvbHVtbiAxXCJcclxuICogICAgICAgICAgICAgICAgPjxzcGFuIGNsYXNzPVwid3BiY191aV9lbF9faG9yaXNfbmF2X3RpdGxlXCI+VGl0bGUgMTwvc3Bhbj48L2E+XHJcbiAqICAgICAgICAgICAgPC9kaXY+XHJcbiAqICAgICAgICAgICAgLi4uXHJcbiAqICAgICAgICA8L2Rpdj5cclxuICogICAgPC9kaXY+XHJcbiAqICAgIDwhLS0gVGFicyBDb250ZW50IC0tPlxyXG4gKiAgICA8ZGl2IGNsYXNzPVwid3BiY190YWJfX3BhbmVsIGdyb3VwX19maWVsZHNcIiBkYXRhLXdwYmMtdGFiLXBhbmVsPVwiMVwiIGlkPVwid3BiY190YWJfcGFuZWxfY29sXzFcIiByb2xlPVwidGFicGFuZWxcIiBhcmlhLWxhYmVsbGVkYnk9XCJ3cGJjX3RhYl9jb2xfMVwiPlxyXG4gKiAgICAgICAgLi4uXHJcbiAqICAgIDwvZGl2PlxyXG4gKiAgICAuLi5cclxuICogPC9kaXY+XHJcbiAqXHJcbiAqIFB1YmxpYyBBUEk6XHJcbiAqICAgLSB3cGJjX3VpX3RhYnMuaW5pdF9vbihyb290X29yX3NlbGVjdG9yKSAgIC8vIGZpbmQgYW5kIGluaXQgZ3JvdXBzIHdpdGhpbiBhIGNvbnRhaW5lclxyXG4gKiAgIC0gd3BiY191aV90YWJzLmluaXRfZ3JvdXAocm9vdF9lbCkgICAgICAgICAvLyBpbml0IGEgc2luZ2xlIGdyb3VwIHJvb3RcclxuICogICAtIHdwYmNfdWlfdGFicy5zZXRfYWN0aXZlKHJvb3RfZWwsIGtleSkgICAgLy8gcHJvZ3JhbW1hdGljYWxseSBjaGFuZ2UgYWN0aXZlIHRhYlxyXG4gKlxyXG4gKiBFdmVudHM6XHJcbiAqICAgLSBEaXNwYXRjaGVzIEN1c3RvbUV2ZW50ICd3cGJjOnRhYnM6Y2hhbmdlJyBvbiByb290IHdoZW4gdGFiIGNoYW5nZXM6XHJcbiAqICAgICAgIGRldGFpbDogeyBhY3RpdmVfa2V5OiAnMicsIHByZXZfa2V5OiAnMScgfVxyXG4gKlxyXG4gKiBTd2l0Y2ggYSBsb2NhbCAoZ2VuZXJpYykgdGFicyBncm91cCB0byB0YWIgMzogICAgIHZhciBncm91cCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJ1tkYXRhLXdwYmMtdGFicz1cImNvbHVtbi1zdHlsZXNcIl0nKTsgaWYgKCBncm91cCApIHsgd3BiY191aV90YWJzLnNldF9hY3RpdmUoZ3JvdXAsICczJyk7IH1cclxuICovXHJcbihmdW5jdGlvbiAoIHcgKSB7XHJcblx0J3VzZSBzdHJpY3QnO1xyXG5cclxuXHRpZiAoIHcud3BiY191aV90YWJzICkge1xyXG5cdFx0cmV0dXJuO1xyXG5cdH1cclxuXHJcblx0LyoqXHJcblx0ICogSW50ZXJuYWw6IHRvZ2dsZSBhY3RpdmUgc3RhdGUuXHJcblx0ICpcclxuXHQgKiBAcGFyYW0ge0hUTUxFbGVtZW50fSByb290X2VsXHJcblx0ICogQHBhcmFtIHtzdHJpbmd9ICAgICAga2V5XHJcblx0ICogQHBhcmFtIHtib29sZWFufSAgICAgc2hvdWxkX2VtaXRcclxuXHQgKi9cclxuXHRmdW5jdGlvbiBzZXRfYWN0aXZlX2ludGVybmFsKCByb290X2VsLCBrZXksIHNob3VsZF9lbWl0ICkge1xyXG5cdFx0dmFyIHRhYl9idG5zID0gcm9vdF9lbC5xdWVyeVNlbGVjdG9yQWxsKCAnW2RhdGEtd3BiYy10YWIta2V5XScgKTtcclxuXHRcdHZhciBwYW5lbHMgICA9IHJvb3RfZWwucXVlcnlTZWxlY3RvckFsbCggJ1tkYXRhLXdwYmMtdGFiLXBhbmVsXScgKTtcclxuXHJcblx0XHR2YXIgcHJldl9rZXkgPSByb290X2VsLmdldEF0dHJpYnV0ZSggJ2RhdGEtd3BiYy10YWItYWN0aXZlJyApIHx8IG51bGw7XHJcblx0XHRpZiAoIFN0cmluZyggcHJldl9rZXkgKSA9PT0gU3RyaW5nKCBrZXkgKSApIHtcclxuXHRcdFx0cmV0dXJuO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8vIEJ1dHRvbnM6IGFyaWEgKyBjbGFzc1xyXG5cdFx0Zm9yICggdmFyIGkgPSAwOyBpIDwgdGFiX2J0bnMubGVuZ3RoOyBpKysgKSB7XHJcblx0XHRcdHZhciBidG4gICA9IHRhYl9idG5zW2ldO1xyXG5cdFx0XHR2YXIgYl9rZXkgPSBidG4uZ2V0QXR0cmlidXRlKCAnZGF0YS13cGJjLXRhYi1rZXknICk7XHJcblx0XHRcdHZhciBpc19vbiA9IFN0cmluZyggYl9rZXkgKSA9PT0gU3RyaW5nKCBrZXkgKTtcclxuXHJcblx0XHRcdGJ0bi5zZXRBdHRyaWJ1dGUoICdyb2xlJywgJ3RhYicgKTtcclxuXHRcdFx0YnRuLnNldEF0dHJpYnV0ZSggJ2FyaWEtc2VsZWN0ZWQnLCBpc19vbiA/ICd0cnVlJyA6ICdmYWxzZScgKTtcclxuXHRcdFx0YnRuLnNldEF0dHJpYnV0ZSggJ3RhYmluZGV4JywgaXNfb24gPyAnMCcgOiAnLTEnICk7XHJcblxyXG5cdFx0XHRpZiAoIGlzX29uICkge1xyXG5cdFx0XHRcdGJ0bi5jbGFzc0xpc3QuYWRkKCAnYWN0aXZlJyApO1xyXG5cdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdGJ0bi5jbGFzc0xpc3QucmVtb3ZlKCAnYWN0aXZlJyApO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gUGFuZWxzOiBhcmlhICsgdmlzaWJpbGl0eVxyXG5cdFx0Zm9yICggdmFyIGogPSAwOyBqIDwgcGFuZWxzLmxlbmd0aDsgaisrICkge1xyXG5cdFx0XHR2YXIgcG4gICA9IHBhbmVsc1tqXTtcclxuXHRcdFx0dmFyIHBrZXkgPSBwbi5nZXRBdHRyaWJ1dGUoICdkYXRhLXdwYmMtdGFiLXBhbmVsJyApO1xyXG5cdFx0XHR2YXIgc2hvdyA9IFN0cmluZyggcGtleSApID09PSBTdHJpbmcoIGtleSApO1xyXG5cclxuXHRcdFx0cG4uc2V0QXR0cmlidXRlKCAncm9sZScsICd0YWJwYW5lbCcgKTtcclxuXHRcdFx0cG4uc2V0QXR0cmlidXRlKCAnYXJpYS1oaWRkZW4nLCBzaG93ID8gJ2ZhbHNlJyA6ICd0cnVlJyApO1xyXG5cdFx0XHRpZiAoIHNob3cgKSB7XHJcblx0XHRcdFx0cG4ucmVtb3ZlQXR0cmlidXRlKCAnaGlkZGVuJyApO1xyXG5cdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdHBuLnNldEF0dHJpYnV0ZSggJ2hpZGRlbicsICcnICk7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHRyb290X2VsLnNldEF0dHJpYnV0ZSggJ2RhdGEtd3BiYy10YWItYWN0aXZlJywgU3RyaW5nKCBrZXkgKSApO1xyXG5cclxuXHRcdGlmICggc2hvdWxkX2VtaXQgKSB7XHJcblx0XHRcdHRyeSB7XHJcblx0XHRcdFx0dmFyIGV2ID0gbmV3IHcuQ3VzdG9tRXZlbnQoICd3cGJjOnRhYnM6Y2hhbmdlJywge1xyXG5cdFx0XHRcdFx0YnViYmxlcyA6IHRydWUsXHJcblx0XHRcdFx0XHRkZXRhaWwgIDogeyBhY3RpdmVfa2V5IDogU3RyaW5nKCBrZXkgKSwgcHJldl9rZXkgOiBwcmV2X2tleSB9XHJcblx0XHRcdFx0fSApO1xyXG5cdFx0XHRcdHJvb3RfZWwuZGlzcGF0Y2hFdmVudCggZXYgKTtcclxuXHRcdFx0fSBjYXRjaCAoIF9lICkge31cclxuXHRcdH1cclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIEludGVybmFsOiBnZXQgb3JkZXJlZCBrZXlzIGZyb20gYnV0dG9ucy5cclxuXHQgKlxyXG5cdCAqIEBwYXJhbSB7SFRNTEVsZW1lbnR9IHJvb3RfZWxcclxuXHQgKiBAcmV0dXJucyB7c3RyaW5nW119XHJcblx0ICovXHJcblx0ZnVuY3Rpb24gZ2V0X2tleXMoIHJvb3RfZWwgKSB7XHJcblx0XHR2YXIgbGlzdCA9IFtdO1xyXG5cdFx0dmFyIGJ0bnMgPSByb290X2VsLnF1ZXJ5U2VsZWN0b3JBbGwoICdbZGF0YS13cGJjLXRhYi1rZXldJyApO1xyXG5cdFx0Zm9yICggdmFyIGkgPSAwOyBpIDwgYnRucy5sZW5ndGg7IGkrKyApIHtcclxuXHRcdFx0dmFyIGsgPSBidG5zW2ldLmdldEF0dHJpYnV0ZSggJ2RhdGEtd3BiYy10YWIta2V5JyApO1xyXG5cdFx0XHRpZiAoIGsgIT0gbnVsbCAmJiBrICE9PSAnJyApIHtcclxuXHRcdFx0XHRsaXN0LnB1c2goIFN0cmluZyggayApICk7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHRcdHJldHVybiBsaXN0O1xyXG5cdH1cclxuXHJcblx0LyoqXHJcblx0ICogSW50ZXJuYWw6IG1vdmUgZm9jdXMgYmV0d2VlbiB0YWJzIHVzaW5nIGtleWJvYXJkLlxyXG5cdCAqXHJcblx0ICogQHBhcmFtIHtIVE1MRWxlbWVudH0gcm9vdF9lbFxyXG5cdCAqIEBwYXJhbSB7bnVtYmVyfSAgICAgIGRpciAgKzEgKG5leHQpIC8gLTEgKHByZXYpXHJcblx0ICovXHJcblx0ZnVuY3Rpb24gZm9jdXNfcmVsYXRpdmUoIHJvb3RfZWwsIGRpciApIHtcclxuXHRcdHZhciBrZXlzICAgID0gZ2V0X2tleXMoIHJvb3RfZWwgKTtcclxuXHRcdHZhciBjdXJyZW50ID0gcm9vdF9lbC5nZXRBdHRyaWJ1dGUoICdkYXRhLXdwYmMtdGFiLWFjdGl2ZScgKSB8fCBrZXlzWzBdIHx8IG51bGw7XHJcblx0XHR2YXIgaWR4ICAgICA9IE1hdGgubWF4KCAwLCBrZXlzLmluZGV4T2YoIFN0cmluZyggY3VycmVudCApICkgKTtcclxuXHRcdHZhciBuZXh0ICAgID0ga2V5c1sgKCBpZHggKyAoIGRpciA+IDAgPyAxIDoga2V5cy5sZW5ndGggLSAxICkgKSAlIGtleXMubGVuZ3RoIF07XHJcblxyXG5cdFx0dmFyIG5leHRfYnRuID0gcm9vdF9lbC5xdWVyeVNlbGVjdG9yKCAnW2RhdGEtd3BiYy10YWIta2V5PVwiJyArIG5leHQgKyAnXCJdJyApO1xyXG5cdFx0aWYgKCBuZXh0X2J0biApIHtcclxuXHRcdFx0bmV4dF9idG4uZm9jdXMoKTtcclxuXHRcdFx0c2V0X2FjdGl2ZV9pbnRlcm5hbCggcm9vdF9lbCwgbmV4dCwgdHJ1ZSApO1xyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0LyoqXHJcblx0ICogSW5pdGlhbGl6ZSBhIHNpbmdsZSB0YWJzIGdyb3VwIHJvb3QuXHJcblx0ICpcclxuXHQgKiBAcGFyYW0ge0hUTUxFbGVtZW50fSByb290X2VsXHJcblx0ICovXHJcblx0ZnVuY3Rpb24gaW5pdF9ncm91cCggcm9vdF9lbCApIHtcclxuXHRcdGlmICggISByb290X2VsIHx8IHJvb3RfZWwuX193cGJjX3RhYnNfaW5pdGVkICkge1xyXG5cdFx0XHRyZXR1cm47XHJcblx0XHR9XHJcblx0XHRyb290X2VsLl9fd3BiY190YWJzX2luaXRlZCA9IHRydWU7XHJcblxyXG5cdFx0Ly8gUm9sZXNcclxuXHRcdHZhciB0YWJsaXN0ID0gcm9vdF9lbC5xdWVyeVNlbGVjdG9yKCAnW2RhdGEtd3BiYy10YWJsaXN0XScgKSB8fCByb290X2VsO1xyXG5cdFx0dGFibGlzdC5zZXRBdHRyaWJ1dGUoICdyb2xlJywgJ3RhYmxpc3QnICk7XHJcblxyXG5cdFx0Ly8gRGVmYXVsdCBhY3RpdmU6IGZyb20gYXR0cmlidXRlIG9yIGZpcnN0IGJ1dHRvblxyXG5cdFx0dmFyIGtleXMgPSBnZXRfa2V5cyggcm9vdF9lbCApO1xyXG5cdFx0dmFyIGRlZiAgPSByb290X2VsLmdldEF0dHJpYnV0ZSggJ2RhdGEtd3BiYy10YWItYWN0aXZlJyApIHx8ICgga2V5c1swXSB8fCAnMScgKTtcclxuXHRcdHNldF9hY3RpdmVfaW50ZXJuYWwoIHJvb3RfZWwsIGRlZiwgZmFsc2UgKTtcclxuXHJcblx0XHQvLyBDbGlja3NcclxuXHRcdHJvb3RfZWwuYWRkRXZlbnRMaXN0ZW5lciggJ2NsaWNrJywgZnVuY3Rpb24gKCBlICkge1xyXG5cdFx0XHR2YXIgYnRuID0gZS50YXJnZXQuY2xvc2VzdCA/IGUudGFyZ2V0LmNsb3Nlc3QoICdbZGF0YS13cGJjLXRhYi1rZXldJyApIDogbnVsbDtcclxuXHRcdFx0aWYgKCAhIGJ0biB8fCAhIHJvb3RfZWwuY29udGFpbnMoIGJ0biApICkge1xyXG5cdFx0XHRcdHJldHVybjtcclxuXHRcdFx0fVxyXG5cdFx0XHRlLnByZXZlbnREZWZhdWx0KCk7XHJcblx0XHRcdHZhciBrZXkgPSBidG4uZ2V0QXR0cmlidXRlKCAnZGF0YS13cGJjLXRhYi1rZXknICk7XHJcblx0XHRcdGlmICgga2V5ICE9IG51bGwgKSB7XHJcblx0XHRcdFx0c2V0X2FjdGl2ZV9pbnRlcm5hbCggcm9vdF9lbCwga2V5LCB0cnVlICk7XHJcblx0XHRcdH1cclxuXHRcdH0sIHRydWUgKTtcclxuXHJcblx0XHQvLyBLZXlib2FyZCAoTGVmdC9SaWdodC9Ib21lL0VuZClcclxuXHRcdHJvb3RfZWwuYWRkRXZlbnRMaXN0ZW5lciggJ2tleWRvd24nLCBmdW5jdGlvbiAoIGUgKSB7XHJcblx0XHRcdHZhciB0Z3QgPSBlLnRhcmdldDtcclxuXHRcdFx0aWYgKCAhIHRndCB8fCAhIHRndC5oYXNBdHRyaWJ1dGUgfHwgISB0Z3QuaGFzQXR0cmlidXRlKCAnZGF0YS13cGJjLXRhYi1rZXknICkgKSB7XHJcblx0XHRcdFx0cmV0dXJuO1xyXG5cdFx0XHR9XHJcblx0XHRcdHN3aXRjaCAoIGUua2V5ICkge1xyXG5cdFx0XHRjYXNlICdBcnJvd0xlZnQnOlxyXG5cdFx0XHRcdGUucHJldmVudERlZmF1bHQoKTsgZm9jdXNfcmVsYXRpdmUoIHJvb3RfZWwsIC0xICk7IGJyZWFrO1xyXG5cdFx0XHRjYXNlICdBcnJvd1JpZ2h0JzpcclxuXHRcdFx0XHRlLnByZXZlbnREZWZhdWx0KCk7IGZvY3VzX3JlbGF0aXZlKCByb290X2VsLCArMSApOyBicmVhaztcclxuXHRcdFx0Y2FzZSAnSG9tZSc6XHJcblx0XHRcdFx0ZS5wcmV2ZW50RGVmYXVsdCgpOyBzZXRfYWN0aXZlX2ludGVybmFsKCByb290X2VsLCAoIGdldF9rZXlzKCByb290X2VsIClbMF0gfHwgJzEnICksIHRydWUgKTsgYnJlYWs7XHJcblx0XHRcdGNhc2UgJ0VuZCc6XHJcblx0XHRcdFx0ZS5wcmV2ZW50RGVmYXVsdCgpOyB2YXIga3MgPSBnZXRfa2V5cyggcm9vdF9lbCApOyBzZXRfYWN0aXZlX2ludGVybmFsKCByb290X2VsLCAoIGtzWyBrcy5sZW5ndGggLSAxIF0gfHwgJzEnICksIHRydWUgKTsgYnJlYWs7XHJcblx0XHRcdH1cclxuXHRcdH0sIHRydWUgKTtcclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIEluaXRpYWxpemUgYWxsIGdyb3VwcyB3aXRoaW4gYSBjb250YWluZXIgKG9yIGRvY3VtZW50KS5cclxuXHQgKlxyXG5cdCAqIEBwYXJhbSB7SFRNTEVsZW1lbnR8c3RyaW5nfG51bGx9IGNvbnRhaW5lclxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIGluaXRfb24oIGNvbnRhaW5lciApIHtcclxuXHRcdHZhciBjdHggPSBjb250YWluZXIgPyAoIHR5cGVvZiBjb250YWluZXIgPT09ICdzdHJpbmcnID8gZG9jdW1lbnQucXVlcnlTZWxlY3RvciggY29udGFpbmVyICkgOiBjb250YWluZXIgKSA6IGRvY3VtZW50O1xyXG5cdFx0aWYgKCAhIGN0eCApIHtcclxuXHRcdFx0cmV0dXJuO1xyXG5cdFx0fVxyXG5cdFx0dmFyIGdyb3VwcyA9IGN0eC5xdWVyeVNlbGVjdG9yQWxsKCAnW2RhdGEtd3BiYy10YWJzXScgKTtcclxuXHRcdGZvciAoIHZhciBpID0gMDsgaSA8IGdyb3Vwcy5sZW5ndGg7IGkrKyApIHtcclxuXHRcdFx0aW5pdF9ncm91cCggZ3JvdXBzW2ldICk7XHJcblx0XHR9XHJcblx0fVxyXG5cclxuXHQvKipcclxuXHQgKiBQcm9ncmFtbWF0aWNhbGx5IHNldCBhY3RpdmUgdGFiIGJ5IGtleS5cclxuXHQgKlxyXG5cdCAqIEBwYXJhbSB7SFRNTEVsZW1lbnR9IHJvb3RfZWxcclxuXHQgKiBAcGFyYW0ge3N0cmluZ3xudW1iZXJ9IGtleVxyXG5cdCAqL1xyXG5cdGZ1bmN0aW9uIHNldF9hY3RpdmUoIHJvb3RfZWwsIGtleSApIHtcclxuXHRcdGlmICggcm9vdF9lbCAmJiByb290X2VsLmhhc0F0dHJpYnV0ZSAmJiByb290X2VsLmhhc0F0dHJpYnV0ZSggJ2RhdGEtd3BiYy10YWJzJyApICkge1xyXG5cdFx0XHRzZXRfYWN0aXZlX2ludGVybmFsKCByb290X2VsLCBTdHJpbmcoIGtleSApLCB0cnVlICk7XHJcblx0XHR9XHJcblx0fVxyXG5cclxuXHQvLyBQdWJsaWMgQVBJIChzbmFrZV9jYXNlKVxyXG5cdHcud3BiY191aV90YWJzID0ge1xyXG5cdFx0aW5pdF9vbiAgICA6IGluaXRfb24sXHJcblx0XHRpbml0X2dyb3VwIDogaW5pdF9ncm91cCxcclxuXHRcdHNldF9hY3RpdmUgOiBzZXRfYWN0aXZlXHJcblx0fTtcclxuXHJcblx0Ly8gQXV0by1pbml0IG9uIERPTSByZWFkeVxyXG5cdGlmICggZG9jdW1lbnQucmVhZHlTdGF0ZSA9PT0gJ2xvYWRpbmcnICkge1xyXG5cdFx0ZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lciggJ0RPTUNvbnRlbnRMb2FkZWQnLCBmdW5jdGlvbiAoKSB7IGluaXRfb24oIGRvY3VtZW50ICk7IH0gKTtcclxuXHR9IGVsc2Uge1xyXG5cdFx0aW5pdF9vbiggZG9jdW1lbnQgKTtcclxuXHR9XHJcblxyXG59KSggd2luZG93ICk7XHJcbiJdfQ==
2240