"use strict";(self.webpackChunktimetrex=self.webpackChunktimetrex||[]).push([["attendance-map-MapViewController","leaflet-timetrex"],{6638:(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"MapViewController\": () => (/* binding */ MapViewController)\n/* harmony export */ });\n/* harmony import */ var _framework_leaflet_leaflet_timetrex__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6889);\n/* provided dependency */ var _ = __webpack_require__(9050);\n/* provided dependency */ var $ = __webpack_require__(9755);\n/* provided dependency */ var jQuery = __webpack_require__(9755);\n// TODO: This file needs cleaning up of old functions once the Map is known to be stable\n// and that we are certain the old code is no longer needed\n\n\nclass MapViewController extends BaseViewController {\n\tconstructor( options = {} ) {\n\t\t_.defaults( options, {\n\t\t\tel: '#map_view_container',\n\t\t\t// _required_files: {\n\t\t\t// \t15: ['leaflet-timetrex']\n\t\t\t// },\n\t\t\tcolors: [\n\t\t\t\t{ name: 'red', value: '#c0392b' },\n\t\t\t\t{ name: 'orange', value: '#d35400' },\n\t\t\t\t{ name: 'yellow', value: '#f39c12' },\n\t\t\t\t{ name: 'green', value: '#16a085' },\n\t\t\t\t{ name: 'lightblue', value: '#27ae60' },\n\t\t\t\t{ name: 'blue', value: '#2980b9' },\n\t\t\t\t{ name: 'purple', value: '#8e44ad' }\n\t\t\t],\n\t\t\tmoved_unsaved_markers: null, // type object as its an array with named keys\n\t\t\tpunches_dic: {},\n\t\t\tpunch_api: null,\n\t\t\tlayers: null,\n\t\t\tcircle_layers: null,\n\t\t\tdisplay_mode: null,\n\t\t\tgeo_labels: null,\n\t\t\tzoom_changed_timer: null,\n\t\t\tdragend_timer: null,\n\t\t\tpopups: [],\n\t\t\tinfo_panel_dic: {},\n\t\t\tmap_control: null,\n\t\t\tsearch_typing_delay: 0,\n\t\t\tstop_suggestions: false,\n\t\t\tmap_last_bounds: null,\n\t\t\tgeofence_filters: null,\n\t\t\tdistances_grid: null,\n\t\t\tcalculatedRouteData: null,\n\n\t\t\t// General page build section\n\t\t\t// -----------------------------------------------------------------------\n\n\t\t} );\n\n\t\tsuper( options );\n\t}\n\n\tinit() {\n\t\tif ( Global.getProductEdition() >= 15 ) {\n\t\t\tthis.edit_only_mode = true;\n\t\t\tthis.moved_unsaved_markers = {};\n\t\t\t//this._super('initialize' );\n\t\t\tthis.edit_view_tpl = 'MapEditView.html';\n\t\t\tthis.permission_id = 'punch';\n\t\t\tthis.sub_view_mode = true;\n\t\t\tthis.viewId = 'Map';\n\t\t\tthis.script_name = 'MapView';\n\t\t\tthis.context_menu_name = $.i18n._( 'Map' );\n\t\t\tthis.navigation_label = $.i18n._( 'Map' );\n\t\t\t// Including this.api below to avoid issues with references to this.api.key_name in BaseViewController.onContextMenuClick() in connection with onExportClick()\n\t\t\tthis.punch_api = this.api = TTAPI.APIPunch;\n\t\t\tthis.map_last_bounds = new L.LatLngBounds();\n\t\t\tthis.calculatedRouteData = {};\n\n\t\t\t//all product edition checks in this view should be based off the existance of this.geo_fence_api\n\t\t\tif ( Global.getProductEdition() >= 20 ) {\n\t\t\t\tthis.geo_fence_api = TTAPI.APIGEOFence;\n\t\t\t}\n\n\t\t\tthis.user_api = TTAPI.APIUser;\n\n\t\t\tthis.render();\n\t\t\tthis.buildContextMenu();\n\n\t\t\tthis.initData();\n\t\t}\n\t}\n\n\tgetCustomContextMenuModel() {\n\t\tvar context_menu_model = {\n\t\t\texclude: ['default'],\n\t\t\tinclude: [\n\t\t\t\t'save',\n\t\t\t\t'cancel',\n\t\t\t\t'export_excel'\n\t\t\t]\n\t\t};\n\n\t\treturn context_menu_model;\n\t}\n\n\tsetEditMenuSaveIcon( context_btn, pId ) {\n\t\t//#2557 - JavaScript exception - Cannot read property 'editPermissionValidate' of null\n\t\tif ( !this.parent_view_controller || !this.parent_view_controller.editPermissionValidate( 'punch' ) ||\n\t\t\tthis.parent_view_controller.is_mass_editing ||\n\t\t\tthis.display_mode === 'geo_fence' ) {\n\t\t\tContextMenuManager.hideMenuItem( this.determineContextMenuMountAttributes().id, context_btn.id, false )\n\t\t}\n\t\tif ( !this.is_changed || this.parent_view_controller.is_viewing ) {\n\t\t\tContextMenuManager.disableMenuItem( this.determineContextMenuMountAttributes().id, context_btn.id, false );\n\t\t}\n\t}\n\n\tsetDefaultMenuExportIcon( context_btn, grid_selected_length, pId ) {\n\t\t// This function decides whether or not the export icon should be enabled.\n\t\t// Note that it checks for initialized distance grid, and grid stays initialized even when switching tabs,\n\t\t// thus after first click on distance tab, export icon will be enabled on both map and distance tabs.\n\t\tif ( !this.distances_grid ) {\n\t\t\tContextMenuManager.disableMenuItem( this.determineContextMenuMountAttributes().id, context_btn.id, false );\n\t\t}\n\t}\n\n\topenEditView( data ) {\n\t\tthis.incoming_data = data; // dont like using a 'global' variable like this when we dont need to. but we're going inbetween here and base controller.\n\t\tthis.user_generic_data_api = TTAPI.APIUserGenericData;\n\t\tif ( !this.edit_view ) {\n\t\t\tthis.initEditViewUI( this.viewId, this.edit_view_tpl );\n\t\t}\n\t\tthis.initEditView(); // calls to BaseViewController\n\t}\n\n\tbuildEditViewUI() {\n\t\tsuper.buildEditViewUI();\n\n\t\tvar tab_model = {\n\t\t\t'tab_map': {\n\t\t\t\t'label': $.i18n._( 'Map' ),\n\t\t\t\t'init_callback': 'initMapTabView',\n\t\t\t\t'html_template': this.getMapTabHtml()\n\t\t\t},\n\t\t\t'tab_map_distances': {\n\t\t\t\t'label': $.i18n._( 'Distances' ),\n\t\t\t\t'init_callback': 'initDistancesTableTabView',\n\t\t\t\t'html_template': this.getDistancesTabHtml()\n\t\t\t}\n\t\t};\n\n\t\tthis.current_edit_record = {}; // Needed so onTabShow in BaseViewController calls the tab init_callback.\n\t\tthis.setTabModel( tab_model );\n\n\t\t// only trigger map load in specific product editions\n\t\tif ( ( Global.getProductEdition() >= 15 ) ) {\n\t\t\tthis.initLeafletMap();\n\t\t\tthis.populateLeafletMap( this.incoming_data );\n\n\t\t\t// Normally we should avoid accessing the map internal logic directly, but in this case we dont want to hardcode geofence logic into leaflet-timetrex.\n\t\t\t// Note: attach the listener here and not earlier in initLeafletMap, otherwise it gets triggered too often during map set-up.\n\t\t\tthis.map_control._internal._leaflet_map.on( 'moveend', this.callbackMapPanning.bind( this ) );\n\n\t\t\tProgressBar.cancelProgressBar();\n\t\t}\n\t\tthis.setEditViewDataDone();\n\t}\n\n\tinitMapTabView() {\n\t\t// Re-build context menu to update icons after coming from distance tab.\n\t\tthis.buildContextMenu( true );\n\t\tthis.setEditMenu();\n\t}\n\n\tinitDistancesTableTabView() {\n\t\tthis.initDistanceGrid(); // will only init grid if it does not yet exist\n\t\t// Re-build context menu to update icons after coming from distance tab, see setDefaultMenuExportIcon on enabling the export button.\n\t\tthis.buildContextMenu( true );\n\t\tthis.setEditMenu();\n\t}\n\n\tcheckTabPermissions( tab ) {\n\t\tvar retval = true; //Most tabs are shown, so default to true.\n\n\t\tswitch ( tab ) {\n\t\t\t// only show the distances tab if there are routes\n\t\t\tcase 'tab_map_distances':\n\t\t\t\tif ( this.incoming_data\n\t\t\t\t\t&& this.incoming_data.tt_map_data\n\t\t\t\t\t&& this.incoming_data.tt_map_data.tt_routes\n\t\t\t\t\t&& this.incoming_data.tt_map_data.tt_routes.length > 0 ) {\n\t\t\t\t\tretval = true;\n\t\t\t\t} else {\n\t\t\t\t\tretval = false;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\n\t\treturn retval;\n\t}\n\n\tsetEditViewDataDone() {\n\t\tsuper.setEditViewDataDone();\n\t}\n\n\tonSaveClick( ignoreWarning ) {\n\t\t// Parent ViewController handles the actual data save, but callback will come back here after successfull save.\n\t\t// Code note: 'moved_unsaved_markers' is an object, as each marker moved is stored as an attribute on the object. When passed to parent view controller for saving, the data is an array via _.values\n\n\t\tvar this_MapViewController = this; // Reference local scope for callbacks to reference further down in the function. Var name also identifies what 'this' is referring to.\n\t\tif ( this.parent_view_controller.onMapSaveClick ) {\n\t\t\tthis.parent_view_controller.onMapSaveClick( _.values( this.moved_unsaved_markers ), _onSaveClickCallback );\n\t\t} else {\n\t\t\tDebug.Text( 'ERROR: Save function does not exist on parent ViewController. Missing function or marker should not be set to draggable.', 'MapViewController.js', 'MapViewController', 'onSaveClick', 1 );\n\t\t}\n\n\t\tfunction _onSaveClickCallback() {\n\t\t\tthis_MapViewController.is_changed = false;\n\t\t\tthis_MapViewController.moved_unsaved_markers = {};\n\t\t\tthis_MapViewController.removeEditView();\n\t\t\tProgressBar.closeOverlay();\n\t\t}\n\t}\n\n\tonExportClick( method ) {\n\t\t//Debug.Text('Exporting Grid To CSV: '+method, 'MapViewController.js', 'MapViewController', 'onExportClick', 10);\n\n\t\tProgressBar.showOverlay();\n\t\t// if ( method == undefined ) {\n\t\t// \tmethod = this.api['export' + this.api.key_name];\n\t\t// }\n\t\tif ( this.distances_grid ) {\n\t\t\tthis.distances_grid.grid2csv( 'driving_distances' );\n\t\t} else {\n\t\t\tDebug.Text( 'ERROR: Exporting Grid To CSV Failed, grid does not exist.', 'MapViewController.js', 'MapViewController', 'onExportClick', 1 );\n\t\t}\n\t\tProgressBar.closeOverlay();\n\t}\n\n\t// Map initialisation section\n\t// -----------------------------------------------------------------------\n\n\tinitLeafletMap() {\n\t\tvar osm;\n\t\tvar map_layers;\n\n\t\tif ( APIGlobal.pre_login_data.map_provider && APIGlobal.pre_login_data.map_provider == 'mapbox' ) {\n\t\t\tvar osmUrl = 'https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}';\n\t\t\tvar osmAttrib = '© Mapbox © OpenStreetMap Improve this map';\n\n\t\t\tosm = [ L.tileLayer( osmUrl, { attribution: osmAttrib, tileSize: 512, maxZoom: 18, zoomOffset: -1, id: 'mapbox/streets-v11', accessToken: APIGlobal.pre_login_data.map_api_key }), ]; //Street Maps\n\t\t\tmap_layers = { 'Streets': osm[0], 'Satellite': L.tileLayer( osmUrl, { attribution: osmAttrib, tileSize: 512, maxZoom: 18, zoomOffset: -1, id: 'mapbox/satellite-streets-v11', accessToken: APIGlobal.pre_login_data.map_api_key }) };\n\t\t} else {\n\t\t\tvar osmUrl = APIGlobal.pre_login_data.map_tile_url + '/{z}/{x}/{y}.png?tt_key=' + APIGlobal.pre_login_data.registration_key;\n\t\t\tvar osmAttrib = 'Map data by ©OpenStreetMap.';\n\n\t\t\tosm = [ new L.TileLayer( osmUrl, { minZoom: 3, maxZoom: 18, attribution: osmAttrib, noWrap: true } ) ];\n\t\t}\n\n\t\tthis.map_control = new _framework_leaflet_leaflet_timetrex__WEBPACK_IMPORTED_MODULE_0__.TTMap( 'map', {\n\t\t\tautoPan: false,\n\t\t\tmaxBoundsViscosity: 1.0,\n\t\t\tlayers: osm,\n\t\t\tminZoom: 2\n\t\t} );\n\n\t\tif ( map_layers ) { //Add any Street/Satellite layers to the map if they are specified.\n\t\t\tL.control.layers( map_layers ).addTo( this.map_control._internal._leaflet_map );\n\t\t}\n\n\t\t// leaflet-timetrex already sets start view to center of US, lets try to find a better location based on company/employee\n\t\tvar current_map_default_coordinates = this.map_control.getCenter();\n\t\tvar alternative_default_coordinates = this.startMapCoordinates();\n\t\t// check if the calculated defaults are any different than map default (US continent center, zoom 4)\n\t\tif ( current_map_default_coordinates.equals( alternative_default_coordinates ) === false ) {\n\t\t\t// found better default coordinates, use those, and zoom in further (10)\n\t\t\tthis.map_control.setView( alternative_default_coordinates, 10 );\n\t\t}\n\n\t\tthis.initRoutingLogic(); // Must be before markers (and routes) are processed\n\n\t\tvar cluster_layer_options = {\n\t\t\tmaxClusterRadius: 55, // make sure not too big, else clusters cant spiderify, not too small for overlap\n\t\t\tspiderfyDistanceMultiplier: 5, // to prevent overlap, but with clickable tooltips to hide, not so much an issue now\n\t\t\tshowCoverageOnHover: false // with small number of markers close together, the polygon lines for bounds look more messy than helpful\n\t\t};\n\n\t\t// this.map_control.createLayer('markers'); // for normal marker layers vs clustered\n\t\tthis.map_control.createLayer( 'markers', {\n\t\t\ttype: 'marker-cluster',\n\t\t\tcluster_layer_options: cluster_layer_options\n\t\t} );\n\n\t\tthis.map_control.createLayer( 'lines' );\n\t\tthis.map_control.createLayer( 'marker-circles' );\n\t\tthis.map_control.createLayer( 'geofences' );\n\n\t\tthis.initSearchBox();\n\t}\n\n\tinitRoutingLogic() {\n\t\tvar routing_options = {\n\t\t\trouting_url: APIGlobal.pre_login_data.map_routing_url\n\t\t};\n\t\tthis.map_control.createLayer( 'routes' );\n\t\tthis.map_control.initRoutingEngine( routing_options );\n\t}\n\n\tpopulateLeafletMap( data ) {\n\n\t\t// TODO-future: Maybe split geofence logic out and make leaflet-timetrex handle this data? Or are geofences the exception to business data\n\t\t// The idea was that everything coming through in 'data' variable would be in TTMap data format.\n\n\t\t// Check if incoming data is geofences, all other 'data' will be in TTMap format.\n\t\tif ( data.length > 0 && data[0].hasOwnProperty( 'geo_type_id' ) ) {\n\t\t\t// this will be using the old data format which has an array only 1 level deep\n\t\t\t// we can call draw Geofences directly without checking api for geofence feature enabled like in initGeoFences(), because this geo_type_id will\n\t\t\t// only be present if triggered from edit geofence UI, which itself will check for the feature permissions.\n\t\t\tvar geo_bounds = this.drawGeoFences( data );\n\t\t\tthis.extendMapBounds( geo_bounds );\n\t\t\treturn true;\n\t\t\t// end geo-fence logic. Do not continue as we are only wanting to plot geofences.\n\t\t}\n\n\t\t// Trigger the plotting of the organised data onto the map.\n\t\tif ( !data || !data.options || !data.tt_map_data ) {\n\t\t\tDebug.Text( 'Error: TTMapData is in an invalid format. Abort.', 'MapViewController.js', 'MapViewController', 'populateLeafletMap', 1 );\n\t\t\treturn false;\n\t\t}\n\n\t\t// Temp for debug during dev\n\t\twindow.map_control = this.map_control;\n\n\t\t// Options Setting for addTTMap function\n\t\tvar options = {\n\t\t\tcallbackDistanceResults: this.callbackDistanceResults.bind( this )\n\t\t};\n\n\t\t// Marker Processing\n\n\t\tif ( data.options.single_marker_draggable === true // This prevents new marker & save marker on read only views. As of now, only timesheet and punch view can edit/add latlng locations\n\t\t\t&& data.tt_map_data.tt_markers\n\t\t\t&& data.tt_map_data.tt_markers.length === 0\n\t\t) {\n\t\t\t// Initiate new marker UI.\n\t\t\t// No markers found in data, this may be a new punch record being created, or existing punch with no gps.\n\t\t\t// Note, we no longer need to check for id to identify new punch records. Previous code needed to know, as new punches required data to be\n\t\t\t// passed back to parent controller, and existing punch map data would be directly saved by MapViewController.\n\t\t\t// Now, we always pass back, and parent does saving, not MapViewController. So new punches and existing punch without gps will be treated the same.\n\t\t\t// Note, this logic may need to change when mass edit is enabled. As that would also deal with single records.\n\n\t\t\tvar marker_options = {\n\t\t\t\tdraggable: true,\n\t\t\t\tcallbacks: {\n\t\t\t\t\tonMarkerDragend: this.callbackTriggerMarkerMove.bind( this ),\n\t\t\t\t\tonMarkerAddNew: this.callbackTriggerMarkerMove.bind( this )\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tthis.map_control.addMarkerInteractive( marker_options );\n\t\t\tDebug.Text( 'Note: No markers found in data. May be new record/existing with no gps', 'MapViewController.js', 'MapViewController', 'populateLeafletMap', 10 );\n\t\t}\n\n\t\t// Special logic to prep data further when there is only one marker. Related to tracking markers that have been moved.\n\t\tif ( data.tt_map_data.tt_markers && data.tt_map_data.tt_markers.length === 1 ) {\n\t\t\tdata.tt_map_data.tt_markers[0].callbacks = data.tt_map_data.tt_markers[0].callbacks || {};\n\n\t\t\t// check if onMarkerDragend already exists on marker data from parent view controller, add more checks if more callbacks added to 'this.mapCallbacks'\n\t\t\t// TODO-future: Instead of overwriting, add the callbacks in a chain? Requires future refactor.\n\t\t\tif ( data.tt_map_data.tt_markers[0].callbacks.onMarkerDragend ) {\n\t\t\t\tDebug.Text( 'Error: Duplicate onMarkerDragEnd callback found. Overwriting parent view callback.', 'MapViewController.js', 'MapViewController', 'populateLeafletMap', 1 );\n\t\t\t}\n\n\t\t\tdata.tt_map_data.tt_markers[0].callbacks.onMarkerDragend = this.callbackTriggerMarkerMove.bind( this );\n\n\t\t\t// As there is only one marker, center map on marker and zoom in to max -2 zoom (-2 is so we dont just see blank in rural)\n\t\t\t//this.map_control.setView( data.tt_map_data.tt_markers[0].latlng, 16 );\n\t\t\t// don't set specific zoom for single marker. let generateMarkerBounds() handle all that\n\t\t}\n\n\t\tif ( data.tt_map_data.tt_markers && data.tt_map_data.tt_markers.length > 0 ) {\n\t\t\t// Data modifications/checks done, send to TTMap to plot on map\n\t\t\tthis.map_control.addTTMapData( data.tt_map_data, options );\n\t\t} else {\n\t\t\t// No data available for map. Nothing to plot\n\t\t\tDebug.Text( 'Error: No data to plot for map.', 'MapViewController.js', 'MapViewController', 'populateLeafletMap', 1 );\n\t\t}\n\n\t\tvar marker_bounds = this.generateMarkerBounds();\n\t\tthis.extendMapBounds( marker_bounds );\n\n\t\t// Geofence Processing\n\n\t\t// check geofence data is in correct format (object with keys, not an array)\n\t\tif ( data.geofence_filters\n\t\t\t&& Object.keys( data.geofence_filters ).length > 0\n\t\t\t&& data.geofence_filters.length === undefined // means its not an array\n\t\t) {\n\t\t\tthis.geofence_filters = data.geofence_filters;\n\n\t\t\t//1 second later to make sure map is draw, the bounds got value\n\t\t\tvar this_MapViewController = this; // Reference local scope for callbacks to reference further down in the function. Var name also identifies what 'this' is referring to.\n\t\t\t// this setTimeout function was in the old code, but does not seem needed? Test it out for a while.\n\t\t\t// if commented out, it seems to show more bounds, and less bounds if left in.\n\t\t\t// maybe due to viewpoint not including it the marker first? Re-visit after rest of map is done.\n\t\t\tsetTimeout( function() {\n\t\t\t\t// This will load geo fences, then draw, then extend the bounds\n\t\t\t\tthis_MapViewController.initGeoFences( 'initial-map-load' );\n\t\t\t}, 1000 );\n\n\t\t}\n\t}\n\n\tcallbackTriggerMarkerMove( marker, new_position ) {\n\t\tvar this_MapViewController = this; // Reference local scope for callbacks to reference further down in the function. Var name also identifies what 'this' is referring to.\n\t\tthis_MapViewController.is_changed = true;\n\t\tthis_MapViewController.setEditMenu();\n\t\tvar marker_punch_id = marker.options.punch_id;\n\n\t\t// add the info to the array which tracks moved markers. Used later by the save function\n\t\tthis_MapViewController.moved_unsaved_markers[marker_punch_id] = {\n\t\t\tid: marker_punch_id,\n\t\t\tlatitude: new_position.lat.toFixed( 6 ), // database only stores to 6 decimal points. Note potential issues with up/down rounding with toFixed due to binary storage with floats, not too important here though\n\t\t\tlongitude: new_position.lng.toFixed( 6 ), // database only stores to 6 decimal points. Note potential issues with up/down rounding with toFixed, due to binary storage with floats, not too important here though\n\t\t\tposition_accuracy: 0\n\t\t};\n\t\tDebug.Text( 'Marker position change:\\nOriginal: ' + marker.getLatLng().toString() + '\\n=> New: ' + new_position.toString(), 'MapViewController.js', 'MapViewController', 'callbackTriggerMarkerMove', 10 );\n\t}\n\n\t// Callbacks from the map\n\t// -----------------------------------------------------------------------\n\n\tcallbackMapPanning() {\n\t\t// debounce the call so that fast zooming/panning like scroll-zooming does not trigger too many API calls in succession. As well as initial map changes during map load.\n\t\tclearTimeout( this._mapZoomEndTimer );\n\t\tvar this_MapViewController = this; // Reference local scope for callbacks to reference further down in the function. Var name also identifies what 'this' is referring to.\n\t\tthis._mapZoomEndTimer = setTimeout( function() {\n\t\t\tthis_MapViewController.initGeoFences( 'map-panning-end' );\n\t\t}, 500 );\n\t}\n\n\t// When results come in for a specific route, this callback should be called, so that it can track all distances and collate. As some user journeys will share route data.\n\tcallbackDistanceResults( ref_id, route_info ) {\n\t\tthis.calculatedRouteData[ref_id] = route_info;\n\t}\n\n\t// Map search bar section\n\t// -----------------------------------------------------------------------\n\n\tinitSearchBox() {\n\t\tvar this_MapViewController = this; // Reference local scope for callbacks to reference further down in the function. Var name also identifies what 'this' is referring to.\n\t\tvar pac_input = $( '#pac-input' );\n\t\tpac_input.bind( 'focus', function( e ) {\n\t\t\t$( this ).select();\n\t\t} );\n\n\t\tpac_input.bind( 'keyup', function( e ) {\n\t\t\tif ( e.keyCode === 13 ) {\n\t\t\t\t$( '#suggestion-box div' ).first().click();\n\t\t\t} else {\n\t\t\t\tthis_MapViewController.search_key_delay = parseInt( Date.now() );\n\t\t\t\twindow.setTimeout( function() {\n\t\t\t\t\tif ( parseInt( Date.now() ) - this_MapViewController.search_key_delay >= 250 ) {\n\t\t\t\t\t\tthis_MapViewController.stop_suggestions = false;\n\t\t\t\t\t\t_framework_leaflet_leaflet_timetrex__WEBPACK_IMPORTED_MODULE_0__.TTMapHelper.searchSuggest( this_MapViewController, false );\n\t\t\t\t\t}\n\t\t\t\t}, 300 );\n\t\t\t}\n\t\t} );\n\t}\n\n\t// Geo fence section\n\t// -----------------------------------------------------------------------\n\n\tinitGeoFences( trigger ) {\n\t\t// Debug.Text( 'Init GeoFences', 'MapViewController.js', 'MapViewController', '_initGeoFence', 10 );\n\n\t\tif ( this.geo_fence_api && this.geofence_filters ) { //initialize function checks product edition for the inclusion of the geo_fence_api\n\t\t\t// Debug.Text( 'Init GeoFences: Data detected.', 'MapViewController.js', 'MapViewController', '_initGeoFence', 10 );\n\t\t\tvar this_MapViewController = this; // Reference local scope for callbacks to reference further down in the function. Var name also identifies what 'this' is referring to.\n\t\t\tvar leaflet_map_center = this_MapViewController.map_control.getCenter();\n\n\t\t\tvar center_point = {\n\t\t\t\tcenter: [leaflet_map_center.lat, leaflet_map_center.lng],\n\t\t\t\tradius: this.getViewAreaRadius() // TODO!\n\t\t\t};\n\n\t\t\tvar filters_all = this.geofence_filters;\n\t\t\tvar branch = filters_all.branch_id;\n\t\t\tvar department = filters_all.department_id;\n\t\t\tvar job = filters_all.job_id;\n\t\t\tvar job_item = filters_all.job_item_id;\n\t\t\tvar punch_tag = filters_all.punch_tag_id;\n\n\t\t\tthis_MapViewController.geo_fence_api.getGEOFenceByGEOLocationAndBranchAndDepartmentAndJobAndTaskAndPunchTag( center_point, branch, department, job, job_item, punch_tag, {\n\t\t\t\tonResult: function( result ) {\n\t\t\t\t\tvar geo_fences_result = result.getResult();\n\t\t\t\t\tif ( geo_fences_result && geo_fences_result.length > 0 ) {\n\t\t\t\t\t\t// Geofences found, lets draw them on the map\n\t\t\t\t\t\t// TODO: Also clear the old fences first!\n\t\t\t\t\t\tvar geo_bounds = this_MapViewController.drawGeoFences( geo_fences_result ); // don't clean area;\n\n\t\t\t\t\t\t// Decide whether we need to expand the map bounds\n\t\t\t\t\t\tif ( trigger === 'initial-map-load' ) {\n\t\t\t\t\t\t\tthis_MapViewController.extendMapBounds( geo_bounds );\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// do nothing as we only want to edit bounds on load. On panning we just want to re-generate fences for the view area.\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\n\t\t} else {\n\t\t\tDebug.Text( '_InitGeoFence() Denied. Functionality unavailable in this product edition.', 'MapViewController.js', 'MapViewController', '_initGeoFence', 10 );\n\t\t}\n\t}\n\n\tdrawGeoFences( geo_fence_data ) {\n\t\tif ( geo_fence_data && geo_fence_data.length > 0 ) {\n\t\t\tthis.map_control.getLayer( 'geofences' ).clear();\n\t\t\tthis.geo_labels = [];\n\t\t\tvar geofence_bounds = new L.LatLngBounds();\n\t\t\tfor ( var i = 0, m = geo_fence_data.length; i < m; i++ ) {\n\t\t\t\tvar geo_fence = geo_fence_data[i];\n\t\t\t\tif ( geo_fence.geo_type_id == 10 && geo_fence.geo_polygon ) {\n\t\t\t\t\tgeofence_bounds.extend( this.map_control.drawGeoFencePolygon( geo_fence ) );\n\t\t\t\t} else if ( geo_fence.geo_type_id == 20 && geo_fence.geo_circle ) {\n\t\t\t\t\tgeofence_bounds.extend( this.map_control.drawGeoFenceCircle( geo_fence ) );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn geofence_bounds;\n\t\t}\n\t}\n\n\t// Map bounds section\n\t// -----------------------------------------------------------------------\n\n\t/**\n\t * extendMapBounds\n\t * will fit map to specified bounds, by extending blank/existing bounds, or overriding bounds\n\t * @param new_bounds the bounds to existing existing or force\n\t * @param [force] optional boolean to prevent extending, and just overriding with new\n\t */\n\textendMapBounds( new_bounds, force ) {\n\t\tif ( new_bounds === undefined ) {\n\t\t\treturn false;\n\t\t}\n\t\tvar bounds;\n\t\tif ( force ) { // if force true, it means dont extend, override the bounds fresh\n\t\t\tbounds = new L.LatLngBounds();\n\t\t} else {\n\t\t\tbounds = this.map_last_bounds;\n\t\t}\n\t\tbounds.extend( new_bounds );\n\t\tthis.map_last_bounds = bounds;\n\n\t\t// Setting max zoom to 14 for two reasons: -- now 13, to trigger the move to bounds on a test (temp)\n\t\t// 1. to ensure radius for checking nearby geofences is high enough to include them\n\t\t// 2. to reduce chances of markers in the middle of nowhere showing as zoomed in blank maps.\n\t\tthis.map_control.fitBounds( bounds, { padding: [15, 15], maxZoom: 13 } );\n\t\treturn true;\n\t}\n\n\tgenerateMarkerBounds() {\n\t\tvar markers = Object.values( this.map_control.getLayer( 'markers' ).get() );\n\t\tif ( markers.length < 1 ) {\n\t\t\t// no markers to do bounds on. exit function. Not necessarily an error state.\n\t\t\treturn;\n\t\t}\n\n\t\tvar marker_bounds = new L.LatLngBounds();\n\t\t// for each marker, extend the bounds to include it\n\t\tmarkers.map( function( m_layer ) {\n\t\t\tmarker_bounds.extend( m_layer.getLatLng() );\n\t\t} );\n\t\treturn marker_bounds;\n\t}\n\n\tgetViewAreaRadius() {\n\t\tvar bounds = this.map_control.getBounds();\n\t\tif ( !bounds ) {\n\t\t\treturn 0;\n\t\t}\n\t\tvar center = bounds.getCenter();\n\t\tvar ne = bounds.getNorthEast();\n\t\tvar r = 3963.0;\n\t\tvar lat1 = center.lat / 57.2958;\n\t\tvar lon1 = center.lng / 57.2958;\n\t\tvar lat2 = ne.lat / 57.2958;\n\t\tvar lon2 = ne.lng / 57.2958;\n\t\t// distance = circle radius from center to Northeast corner of bounds\n\t\tvar dis = r * Math.acos( Math.sin( lat1 ) * Math.sin( lat2 ) +\n\t\t\tMath.cos( lat1 ) * Math.cos( lat2 ) * Math.cos( lon2 - lon1 ) );\n\t\treturn dis * 1609.344;\n\t}\n\n\t// setDefaultMenuMapIcon: function ( context_btn ) {\n\t// \tif ( Global.getProductEdition() <= 10 ) {\n\t// \t\tcontext_btn.addClass( 'invisible-image' );\n\t// \t}\n\t//\n\t// \tvar show = false;\n\t// \tif ( this.grid ) {\n\t// \t\tvar selected_items = this.getSelectedItems();\n\t// \t\tDebug.Arr( selected_items, 'selected items', 'BaseViewController.js', 'BaseViewController', 'setDefaultMenuMapIcon', 10 );\n\t// \t\tif ( selected_items.length > 0 ) {\n\t// \t\t\tcontext_btn.removeClass( 'disable-image' );\n\t// \t\t} else {\n\t// \t\t\tcontext_btn.addClass( 'disable-image' );\n\t// \t\t}\n\t// \t}\n\t// },\n\n\t// Distance Table Code\n\t// -----------------------------------------------------------------------\n\n\tinitDistanceGrid() {\n\t\t// only init grid if it does not yet exist\n\t\tif ( !this.distances_grid ) {\n\t\t\tvar grid_parent_container = this.edit_view_tab.find( '#tab_map_distances_content_div' );\n\t\t\tthis.distances_grid = this.buildDistancesGrid( 'distance_grid_table' );\n\t\t\tgrid_parent_container.append( this.distances_grid );\n\t\t}\n\t}\n\n\tbuildDistancesGrid( grid_selector ) {\n\t\tvar column_info_array = [];\n\t\tvar column_info_default = {\n\t\t\tname: 'default',\n\t\t\tindex: 'default',\n\t\t\tlabel: $.i18n._( 'Default' ),\n\t\t\t// width: 100,\n\t\t\tsortable: true,\n\t\t\tformatter: 'select',\n\t\t\teditable: false,\n\t\t\ttitle: false,\n\t\t\tedittype: 'select'\n\t\t};\n\n\t\tfunction _addColumn2Grid( field, label, options ) {\n\t\t\tvar column_info = {\n\t\t\t\tname: field,\n\t\t\t\tindex: field,\n\t\t\t\tlabel: label // do not put the $.i18n reference directly in the function, as it will interfere with the extraction of language labels for translation files\n\t\t\t};\n\t\t\tif ( options ) {\n\t\t\t\tjQuery.extend( column_info, options ); // have the flexibility here to add individual column options now that we refactored to a function\n\t\t\t}\n\t\t\tcolumn_info_array.push( jQuery.extend( {}, column_info_default, column_info ) );\n\t\t}\n\n\t\t_addColumn2Grid( 'first_name', $.i18n._( 'First Name' ) );\n\t\t_addColumn2Grid( 'last_name', $.i18n._( 'Last Name' ) );\n\t\t_addColumn2Grid( 'branch', $.i18n._( 'Branch' ) );\n\t\t_addColumn2Grid( 'department', $.i18n._( 'Department' ) );\n\t\t_addColumn2Grid( 'job_manual_id', $.i18n._( 'Job Code' ) );\n\t\t_addColumn2Grid( 'job', $.i18n._( 'Job' ) );\n\t\t_addColumn2Grid( 'job_item_manual_id', $.i18n._( 'Task Code' ) );\n\t\t_addColumn2Grid( 'job_item', $.i18n._( 'Task' ) );\n\t\t_addColumn2Grid( 'in_time_stamp', $.i18n._( 'In Punch' ) );\n\t\t_addColumn2Grid( 'out_time_stamp', $.i18n._( 'Out Punch' ) );\n\t\t_addColumn2Grid( 'total_time', $.i18n._( 'Total Time' ) );\n\t\t_addColumn2Grid( 'duration', $.i18n._( 'Driving Duration' ) );\n\t\t_addColumn2Grid( 'distance', $.i18n._( 'Driving Distance' ) );\n\t\t_addColumn2Grid( 'in_latitude', $.i18n._( 'In Latitude' ) );\n\t\t_addColumn2Grid( 'in_longitude', $.i18n._( 'In Longitude' ) );\n\t\t_addColumn2Grid( 'out_latitude', $.i18n._( 'Out Latitude' ) );\n\t\t_addColumn2Grid( 'out_longitude', $.i18n._( 'Out Longitude' ) );\n\n\t\t// Future option. If implementing, create the function below based off showEmployeeSettingNoResultCover()\n\t\t// if ( data.length < 1 ) {\n\t\t// \tthis.showDistanceTableNoResultCover();\n\t\t// }\n\n\t\tvar this_MapViewController = this; // Reference local scope for callbacks to reference further down in the function. Var name also identifies what 'this' is referring to.\n\t\tvar data = this.getDistancesGridData();\n\n\t\treturn new TTGrid( grid_selector, {\n\t\t\tdata: data,\n\t\t\tgridComplete: function() {\n\t\t\t\tthis_MapViewController.setDistancesTableGridSize();\n\t\t\t},\n\t\t\tmultiselect: false\n\t\t}, column_info_array );\n\t}\n\n\tgetDistancesGridData() {\n\t\tvar this_MapViewController = this; // Reference local scope for callbacks to reference further down in the function. Var name also identifies what 'this' is referring to.\n\t\tvar grid_source = [];\n\t\tvar route_array = this.incoming_data.tt_map_data.tt_routes;\n\n\t\tif ( !route_array || route_array.length < 1 ) {\n\t\t\t// error? there are no calculated routes. No need to error for now, as its likely this will be handled earlier.\n\t\t\treturn false;\n\t\t}\n\n\t\tObject.values( route_array ).map( function( route ) {\n\t\t\tvar in_punch = route.route_markers[0].punch;\n\t\t\tvar out_punch = route.route_markers[1].punch;\n\n\t\t\tif ( in_punch.status !== 'In'\n\t\t\t\t|| out_punch.status !== 'Out' ) {\n\t\t\t\tDebug.Text( 'ERROR: in_punch and out_punch have data mismatch punch In/Out status', 'MapViewController.js', 'MapViewController', 'getDistancesGridData', 1 );\n\t\t\t}\n\n\t\t\t// For some of the data we will only refer to in_punch. Therefore, make sure the data matches.\n\t\t\tif ( in_punch.first_name !== out_punch.first_name\n\t\t\t\t|| in_punch.last_name !== out_punch.last_name\n\t\t\t\t|| in_punch.branch !== out_punch.branch\n\t\t\t\t|| in_punch.department !== out_punch.department\n\t\t\t\t|| in_punch.job !== out_punch.job\n\t\t\t\t|| in_punch.job_item !== out_punch.job_item\n\t\t\t) {\n\t\t\t\tDebug.Text( 'ERROR: in_punch and out_punch have data mismatch.', 'MapViewController.js', 'MapViewController', 'getDistancesGridData', 1 );\n\t\t\t}\n\n\t\t\tvar table_filters = [false, undefined, null, 'false', 'undefined', 'null'];\n\t\t\tvar table_entry = {\n\t\t\t\tfirst_name: Global.filterOutput( in_punch.first_name, table_filters ),\n\t\t\t\tlast_name: Global.filterOutput( in_punch.last_name, table_filters ),\n\t\t\t\tin_time_stamp: Global.filterOutput( in_punch.time_stamp, table_filters ),\n\t\t\t\tin_latitude: Global.filterOutput( in_punch.latitude, table_filters ),\n\t\t\t\tin_longitude: Global.filterOutput( in_punch.longitude, table_filters ),\n\t\t\t\tout_time_stamp: Global.filterOutput( out_punch.time_stamp, table_filters ),\n\t\t\t\tout_latitude: Global.filterOutput( out_punch.latitude, table_filters ),\n\t\t\t\tout_longitude: Global.filterOutput( out_punch.longitude, table_filters ),\n\t\t\t\tdistance: '',\n\t\t\t\tduration: '',\n\t\t\t\tbranch: Global.filterOutput( in_punch.branch, table_filters ),\n\t\t\t\tdepartment: Global.filterOutput( in_punch.department, table_filters ),\n\t\t\t\tjob_manual_id: Global.filterOutput( in_punch.job_manual_id, table_filters ),\n\t\t\t\tjob: Global.filterOutput( in_punch.job, table_filters ),\n\t\t\t\tjob_item_manual_id: Global.filterOutput( in_punch.job_item_manual_id, table_filters ),\n\t\t\t\tjob_item: Global.filterOutput( in_punch.job_item, table_filters ),\n\t\t\t\ttotal_time: Global.filterOutput( Global.getTimeUnit( in_punch.total_time ), table_filters )\n\t\t\t};\n\t\t\tvar row_route_info;\n\t\t\t// if route info exists, set it, else try to acquire it from the main routes\n\t\t\tif ( route.route_distance && route.route_duration ) {\n\t\t\t\trow_route_info = {\n\t\t\t\t\tdistance: _framework_leaflet_leaflet_timetrex__WEBPACK_IMPORTED_MODULE_0__.TTConvertMapData.convertMetersToUserUnits( route.route_distance ).distance_in_user_format,\n\t\t\t\t\tduration: Global.getTimeUnit( route.route_duration )\n\t\t\t\t};\n\t\t\t\tjQuery.extend( table_entry, row_route_info );\n\n\t\t\t\t// check for duplicate route flag, if there is one, look-up the reference for that duplicate route, and request the route info.\n\t\t\t} else if ( route.foundDuplicateLine && this_MapViewController.calculatedRouteData[route.ref_id] ) {\n\t\t\t\tvar existing_route_info = this_MapViewController.calculatedRouteData[route.ref_id];\n\n\t\t\t\trow_route_info = {\n\t\t\t\t\tdistance: _framework_leaflet_leaflet_timetrex__WEBPACK_IMPORTED_MODULE_0__.TTConvertMapData.convertMetersToUserUnits( existing_route_info.route_distance ).distance_in_user_format,\n\t\t\t\t\tduration: Global.getTimeUnit( existing_route_info.route_duration )\n\t\t\t\t};\n\t\t\t\tjQuery.extend( table_entry, row_route_info );\n\t\t\t} else {\n\t\t\t\tDebug.Text( 'Note: No distance data found for entry. Leaving as empty strings', 'MapViewController.js', 'MapViewController', 'getDistancesGridData', 10 );\n\t\t\t}\n\t\t\tgrid_source.push( table_entry );\n\t\t} );\n\n\t\treturn grid_source;\n\t}\n\n\tsetDistancesTableGridSize( grid ) {\n\t\tif ( !grid ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar tab_distances_table = this.edit_view.find( '#tab_map_distances_content_div' );\n\t\tgrid.grid.setGridWidth( tab_distances_table.width() );\n\t\tgrid.grid.setGridHeight( tab_distances_table.height() );\n\t\tgrid.setGridColumnsWidth();\n\t}\n\n\tgetMapTabHtml() {\n\t\treturn `
\n\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t
\n\t\t\t\t
`;\n\t}\n\n\tgetDistancesTabHtml() {\n\t\treturn `\n\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t
\n\t\t\t\t
`;\n\t}\n\n}\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,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QUNBO0FBQ0E7QUFDQTs7QUFFQSIsInNvdXJjZXMiOlsid2VicGFjazovLy8uL2ludGVyZmFjZS9odG1sNS92aWV3cy9hdHRlbmRhbmNlL21hcC9NYXBWaWV3Q29udHJvbGxlci5qcz9kZGU2Il0sInNvdXJjZXNDb250ZW50IjpbIi8vIFRPRE86IFRoaXMgZmlsZSBuZWVkcyBjbGVhbmluZyB1cCBvZiBvbGQgZnVuY3Rpb25zIG9uY2UgdGhlIE1hcCBpcyBrbm93biB0byBiZSBzdGFibGVcbi8vIGFuZCB0aGF0IHdlIGFyZSBjZXJ0YWluIHRoZSBvbGQgY29kZSBpcyBubyBsb25nZXIgbmVlZGVkXG5pbXBvcnQgeyBUVE1hcCwgVFRDb252ZXJ0TWFwRGF0YSwgVFRNYXBIZWxwZXIgfSBmcm9tICdAL2ZyYW1ld29yay9sZWFmbGV0L2xlYWZsZXQtdGltZXRyZXgnO1xuXG5leHBvcnQgY2xhc3MgTWFwVmlld0NvbnRyb2xsZXIgZXh0ZW5kcyBCYXNlVmlld0NvbnRyb2xsZXIge1xuXHRjb25zdHJ1Y3Rvciggb3B0aW9ucyA9IHt9ICkge1xuXHRcdF8uZGVmYXVsdHMoIG9wdGlvbnMsIHtcblx0XHRcdGVsOiAnI21hcF92aWV3X2NvbnRhaW5lcicsXG5cdFx0XHQvLyBfcmVxdWlyZWRfZmlsZXM6IHtcblx0XHRcdC8vIFx0MTU6IFsnbGVhZmxldC10aW1ldHJleCddXG5cdFx0XHQvLyB9LFxuXHRcdFx0Y29sb3JzOiBbXG5cdFx0XHRcdHsgbmFtZTogJ3JlZCcsIHZhbHVlOiAnI2MwMzkyYicgfSxcblx0XHRcdFx0eyBuYW1lOiAnb3JhbmdlJywgdmFsdWU6ICcjZDM1NDAwJyB9LFxuXHRcdFx0XHR7IG5hbWU6ICd5ZWxsb3cnLCB2YWx1ZTogJyNmMzljMTInIH0sXG5cdFx0XHRcdHsgbmFtZTogJ2dyZWVuJywgdmFsdWU6ICcjMTZhMDg1JyB9LFxuXHRcdFx0XHR7IG5hbWU6ICdsaWdodGJsdWUnLCB2YWx1ZTogJyMyN2FlNjAnIH0sXG5cdFx0XHRcdHsgbmFtZTogJ2JsdWUnLCB2YWx1ZTogJyMyOTgwYjknIH0sXG5cdFx0XHRcdHsgbmFtZTogJ3B1cnBsZScsIHZhbHVlOiAnIzhlNDRhZCcgfVxuXHRcdFx0XSxcblx0XHRcdG1vdmVkX3Vuc2F2ZWRfbWFya2VyczogbnVsbCwgLy8gdHlwZSBvYmplY3QgYXMgaXRzIGFuIGFycmF5IHdpdGggbmFtZWQga2V5c1xuXHRcdFx0cHVuY2hlc19kaWM6IHt9LFxuXHRcdFx0cHVuY2hfYXBpOiBudWxsLFxuXHRcdFx0bGF5ZXJzOiBudWxsLFxuXHRcdFx0Y2lyY2xlX2xheWVyczogbnVsbCxcblx0XHRcdGRpc3BsYXlfbW9kZTogbnVsbCxcblx0XHRcdGdlb19sYWJlbHM6IG51bGwsXG5cdFx0XHR6b29tX2NoYW5nZWRfdGltZXI6IG51bGwsXG5cdFx0XHRkcmFnZW5kX3RpbWVyOiBudWxsLFxuXHRcdFx0cG9wdXBzOiBbXSxcblx0XHRcdGluZm9fcGFuZWxfZGljOiB7fSxcblx0XHRcdG1hcF9jb250cm9sOiBudWxsLFxuXHRcdFx0c2VhcmNoX3R5cGluZ19kZWxheTogMCxcblx0XHRcdHN0b3Bfc3VnZ2VzdGlvbnM6IGZhbHNlLFxuXHRcdFx0bWFwX2xhc3RfYm91bmRzOiBudWxsLFxuXHRcdFx0Z2VvZmVuY2VfZmlsdGVyczogbnVsbCxcblx0XHRcdGRpc3RhbmNlc19ncmlkOiBudWxsLFxuXHRcdFx0Y2FsY3VsYXRlZFJvdXRlRGF0YTogbnVsbCxcblxuXHRcdFx0Ly8gR2VuZXJhbCBwYWdlIGJ1aWxkIHNlY3Rpb25cblx0XHRcdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblx0XHR9ICk7XG5cblx0XHRzdXBlciggb3B0aW9ucyApO1xuXHR9XG5cblx0aW5pdCgpIHtcblx0XHRpZiAoIEdsb2JhbC5nZXRQcm9kdWN0RWRpdGlvbigpID49IDE1ICkge1xuXHRcdFx0dGhpcy5lZGl0X29ubHlfbW9kZSA9IHRydWU7XG5cdFx0XHR0aGlzLm1vdmVkX3Vuc2F2ZWRfbWFya2VycyA9IHt9O1xuXHRcdFx0Ly90aGlzLl9zdXBlcignaW5pdGlhbGl6ZScgKTtcblx0XHRcdHRoaXMuZWRpdF92aWV3X3RwbCA9ICdNYXBFZGl0Vmlldy5odG1sJztcblx0XHRcdHRoaXMucGVybWlzc2lvbl9pZCA9ICdwdW5jaCc7XG5cdFx0XHR0aGlzLnN1Yl92aWV3X21vZGUgPSB0cnVlO1xuXHRcdFx0dGhpcy52aWV3SWQgPSAnTWFwJztcblx0XHRcdHRoaXMuc2NyaXB0X25hbWUgPSAnTWFwVmlldyc7XG5cdFx0XHR0aGlzLmNvbnRleHRfbWVudV9uYW1lID0gJC5pMThuLl8oICdNYXAnICk7XG5cdFx0XHR0aGlzLm5hdmlnYXRpb25fbGFiZWwgPSAkLmkxOG4uXyggJ01hcCcgKTtcblx0XHRcdC8vIEluY2x1ZGluZyB0aGlzLmFwaSBiZWxvdyB0byBhdm9pZCBpc3N1ZXMgd2l0aCByZWZlcmVuY2VzIHRvIHRoaXMuYXBpLmtleV9uYW1lIGluIEJhc2VWaWV3Q29udHJvbGxlci5vbkNvbnRleHRNZW51Q2xpY2soKSBpbiBjb25uZWN0aW9uIHdpdGggb25FeHBvcnRDbGljaygpXG5cdFx0XHR0aGlzLnB1bmNoX2FwaSA9IHRoaXMuYXBpID0gVFRBUEkuQVBJUHVuY2g7XG5cdFx0XHR0aGlzLm1hcF9sYXN0X2JvdW5kcyA9IG5ldyBMLkxhdExuZ0JvdW5kcygpO1xuXHRcdFx0dGhpcy5jYWxjdWxhdGVkUm91dGVEYXRhID0ge307XG5cblx0XHRcdC8vYWxsIHByb2R1Y3QgZWRpdGlvbiBjaGVja3MgaW4gdGhpcyB2aWV3IHNob3VsZCBiZSBiYXNlZCBvZmYgdGhlIGV4aXN0YW5jZSBvZiB0aGlzLmdlb19mZW5jZV9hcGlcblx0XHRcdGlmICggR2xvYmFsLmdldFByb2R1Y3RFZGl0aW9uKCkgPj0gMjAgKSB7XG5cdFx0XHRcdHRoaXMuZ2VvX2ZlbmNlX2FwaSA9IFRUQVBJLkFQSUdFT0ZlbmNlO1xuXHRcdFx0fVxuXG5cdFx0XHR0aGlzLnVzZXJfYXBpID0gVFRBUEkuQVBJVXNlcjtcblxuXHRcdFx0dGhpcy5yZW5kZXIoKTtcblx0XHRcdHRoaXMuYnVpbGRDb250ZXh0TWVudSgpO1xuXG5cdFx0XHR0aGlzLmluaXREYXRhKCk7XG5cdFx0fVxuXHR9XG5cblx0Z2V0Q3VzdG9tQ29udGV4dE1lbnVNb2RlbCgpIHtcblx0XHR2YXIgY29udGV4dF9tZW51X21vZGVsID0ge1xuXHRcdFx0ZXhjbHVkZTogWydkZWZhdWx0J10sXG5cdFx0XHRpbmNsdWRlOiBbXG5cdFx0XHRcdCdzYXZlJyxcblx0XHRcdFx0J2NhbmNlbCcsXG5cdFx0XHRcdCdleHBvcnRfZXhjZWwnXG5cdFx0XHRdXG5cdFx0fTtcblxuXHRcdHJldHVybiBjb250ZXh0X21lbnVfbW9kZWw7XG5cdH1cblxuXHRzZXRFZGl0TWVudVNhdmVJY29uKCBjb250ZXh0X2J0biwgcElkICkge1xuXHRcdC8vIzI1NTcgLSBKYXZhU2NyaXB0IGV4Y2VwdGlvbiAtIENhbm5vdCByZWFkIHByb3BlcnR5ICdlZGl0UGVybWlzc2lvblZhbGlkYXRlJyBvZiBudWxsXG5cdFx0aWYgKCAhdGhpcy5wYXJlbnRfdmlld19jb250cm9sbGVyIHx8ICF0aGlzLnBhcmVudF92aWV3X2NvbnRyb2xsZXIuZWRpdFBlcm1pc3Npb25WYWxpZGF0ZSggJ3B1bmNoJyApIHx8XG5cdFx0XHR0aGlzLnBhcmVudF92aWV3X2NvbnRyb2xsZXIuaXNfbWFzc19lZGl0aW5nIHx8XG5cdFx0XHR0aGlzLmRpc3BsYXlfbW9kZSA9PT0gJ2dlb19mZW5jZScgKSB7XG5cdFx0XHRDb250ZXh0TWVudU1hbmFnZXIuaGlkZU1lbnVJdGVtKCB0aGlzLmRldGVybWluZUNvbnRleHRNZW51TW91bnRBdHRyaWJ1dGVzKCkuaWQsIGNvbnRleHRfYnRuLmlkLCBmYWxzZSApXG5cdFx0fVxuXHRcdGlmICggIXRoaXMuaXNfY2hhbmdlZCB8fCB0aGlzLnBhcmVudF92aWV3X2NvbnRyb2xsZXIuaXNfdmlld2luZyApIHtcblx0XHRcdENvbnRleHRNZW51TWFuYWdlci5kaXNhYmxlTWVudUl0ZW0oIHRoaXMuZGV0ZXJtaW5lQ29udGV4dE1lbnVNb3VudEF0dHJpYnV0ZXMoKS5pZCwgY29udGV4dF9idG4uaWQsIGZhbHNlICk7XG5cdFx0fVxuXHR9XG5cblx0c2V0RGVmYXVsdE1lbnVFeHBvcnRJY29uKCBjb250ZXh0X2J0biwgZ3JpZF9zZWxlY3RlZF9sZW5ndGgsIHBJZCApIHtcblx0XHQvLyBUaGlzIGZ1bmN0aW9uIGRlY2lkZXMgd2hldGhlciBvciBub3QgdGhlIGV4cG9ydCBpY29uIHNob3VsZCBiZSBlbmFibGVkLlxuXHRcdC8vIE5vdGUgdGhhdCBpdCBjaGVja3MgZm9yIGluaXRpYWxpemVkIGRpc3RhbmNlIGdyaWQsIGFuZCBncmlkIHN0YXlzIGluaXRpYWxpemVkIGV2ZW4gd2hlbiBzd2l0Y2hpbmcgdGFicyxcblx0XHQvLyB0aHVzIGFmdGVyIGZpcnN0IGNsaWNrIG9uIGRpc3RhbmNlIHRhYiwgZXhwb3J0IGljb24gd2lsbCBiZSBlbmFibGVkIG9uIGJvdGggbWFwIGFuZCBkaXN0YW5jZSB0YWJzLlxuXHRcdGlmICggIXRoaXMuZGlzdGFuY2VzX2dyaWQgKSB7XG5cdFx0XHRDb250ZXh0TWVudU1hbmFnZXIuZGlzYWJsZU1lbnVJdGVtKCB0aGlzLmRldGVybWluZUNvbnRleHRNZW51TW91bnRBdHRyaWJ1dGVzKCkuaWQsIGNvbnRleHRfYnRuLmlkLCBmYWxzZSApO1xuXHRcdH1cblx0fVxuXG5cdG9wZW5FZGl0VmlldyggZGF0YSApIHtcblx0XHR0aGlzLmluY29taW5nX2RhdGEgPSBkYXRhOyAvLyBkb250IGxpa2UgdXNpbmcgYSAnZ2xvYmFsJyB2YXJpYWJsZSBsaWtlIHRoaXMgd2hlbiB3ZSBkb250IG5lZWQgdG8uIGJ1dCB3ZSdyZSBnb2luZyBpbmJldHdlZW4gaGVyZSBhbmQgYmFzZSBjb250cm9sbGVyLlxuXHRcdHRoaXMudXNlcl9nZW5lcmljX2RhdGFfYXBpID0gVFRBUEkuQVBJVXNlckdlbmVyaWNEYXRhO1xuXHRcdGlmICggIXRoaXMuZWRpdF92aWV3ICkge1xuXHRcdFx0dGhpcy5pbml0RWRpdFZpZXdVSSggdGhpcy52aWV3SWQsIHRoaXMuZWRpdF92aWV3X3RwbCApO1xuXHRcdH1cblx0XHR0aGlzLmluaXRFZGl0VmlldygpOyAvLyBjYWxscyB0byBCYXNlVmlld0NvbnRyb2xsZXJcblx0fVxuXG5cdGJ1aWxkRWRpdFZpZXdVSSgpIHtcblx0XHRzdXBlci5idWlsZEVkaXRWaWV3VUkoKTtcblxuXHRcdHZhciB0YWJfbW9kZWwgPSB7XG5cdFx0XHQndGFiX21hcCc6IHtcblx0XHRcdFx0J2xhYmVsJzogJC5pMThuLl8oICdNYXAnICksXG5cdFx0XHRcdCdpbml0X2NhbGxiYWNrJzogJ2luaXRNYXBUYWJWaWV3Jyxcblx0XHRcdFx0J2h0bWxfdGVtcGxhdGUnOiB0aGlzLmdldE1hcFRhYkh0bWwoKVxuXHRcdFx0fSxcblx0XHRcdCd0YWJfbWFwX2Rpc3RhbmNlcyc6IHtcblx0XHRcdFx0J2xhYmVsJzogJC5pMThuLl8oICdEaXN0YW5jZXMnICksXG5cdFx0XHRcdCdpbml0X2NhbGxiYWNrJzogJ2luaXREaXN0YW5jZXNUYWJsZVRhYlZpZXcnLFxuXHRcdFx0XHQnaHRtbF90ZW1wbGF0ZSc6IHRoaXMuZ2V0RGlzdGFuY2VzVGFiSHRtbCgpXG5cdFx0XHR9XG5cdFx0fTtcblxuXHRcdHRoaXMuY3VycmVudF9lZGl0X3JlY29yZCA9IHt9OyAvLyBOZWVkZWQgc28gb25UYWJTaG93IGluIEJhc2VWaWV3Q29udHJvbGxlciBjYWxscyB0aGUgdGFiIGluaXRfY2FsbGJhY2suXG5cdFx0dGhpcy5zZXRUYWJNb2RlbCggdGFiX21vZGVsICk7XG5cblx0XHQvLyBvbmx5IHRyaWdnZXIgbWFwIGxvYWQgaW4gc3BlY2lmaWMgcHJvZHVjdCBlZGl0aW9uc1xuXHRcdGlmICggKCBHbG9iYWwuZ2V0UHJvZHVjdEVkaXRpb24oKSA+PSAxNSApICkge1xuXHRcdFx0dGhpcy5pbml0TGVhZmxldE1hcCgpO1xuXHRcdFx0dGhpcy5wb3B1bGF0ZUxlYWZsZXRNYXAoIHRoaXMuaW5jb21pbmdfZGF0YSApO1xuXG5cdFx0XHQvLyBOb3JtYWxseSB3ZSBzaG91bGQgYXZvaWQgYWNjZXNzaW5nIHRoZSBtYXAgaW50ZXJuYWwgbG9naWMgZGlyZWN0bHksIGJ1dCBpbiB0aGlzIGNhc2Ugd2UgZG9udCB3YW50IHRvIGhhcmRjb2RlIGdlb2ZlbmNlIGxvZ2ljIGludG8gbGVhZmxldC10aW1ldHJleC5cblx0XHRcdC8vIE5vdGU6IGF0dGFjaCB0aGUgbGlzdGVuZXIgaGVyZSBhbmQgbm90IGVhcmxpZXIgaW4gaW5pdExlYWZsZXRNYXAsIG90aGVyd2lzZSBpdCBnZXRzIHRyaWdnZXJlZCB0b28gb2Z0ZW4gZHVyaW5nIG1hcCBzZXQtdXAuXG5cdFx0XHR0aGlzLm1hcF9jb250cm9sLl9pbnRlcm5hbC5fbGVhZmxldF9tYXAub24oICdtb3ZlZW5kJywgdGhpcy5jYWxsYmFja01hcFBhbm5pbmcuYmluZCggdGhpcyApICk7XG5cblx0XHRcdFByb2dyZXNzQmFyLmNhbmNlbFByb2dyZXNzQmFyKCk7XG5cdFx0fVxuXHRcdHRoaXMuc2V0RWRpdFZpZXdEYXRhRG9uZSgpO1xuXHR9XG5cblx0aW5pdE1hcFRhYlZpZXcoKSB7XG5cdFx0Ly8gUmUtYnVpbGQgY29udGV4dCBtZW51IHRvIHVwZGF0ZSBpY29ucyBhZnRlciBjb21pbmcgZnJvbSBkaXN0YW5jZSB0YWIuXG5cdFx0dGhpcy5idWlsZENvbnRleHRNZW51KCB0cnVlICk7XG5cdFx0dGhpcy5zZXRFZGl0TWVudSgpO1xuXHR9XG5cblx0aW5pdERpc3RhbmNlc1RhYmxlVGFiVmlldygpIHtcblx0XHR0aGlzLmluaXREaXN0YW5jZUdyaWQoKTsgLy8gd2lsbCBvbmx5IGluaXQgZ3JpZCBpZiBpdCBkb2VzIG5vdCB5ZXQgZXhpc3Rcblx0XHQvLyBSZS1idWlsZCBjb250ZXh0IG1lbnUgdG8gdXBkYXRlIGljb25zIGFmdGVyIGNvbWluZyBmcm9tIGRpc3RhbmNlIHRhYiwgc2VlIHNldERlZmF1bHRNZW51RXhwb3J0SWNvbiBvbiBlbmFibGluZyB0aGUgZXhwb3J0IGJ1dHRvbi5cblx0XHR0aGlzLmJ1aWxkQ29udGV4dE1lbnUoIHRydWUgKTtcblx0XHR0aGlzLnNldEVkaXRNZW51KCk7XG5cdH1cblxuXHRjaGVja1RhYlBlcm1pc3Npb25zKCB0YWIgKSB7XG5cdFx0dmFyIHJldHZhbCA9IHRydWU7IC8vTW9zdCB0YWJzIGFyZSBzaG93biwgc28gZGVmYXVsdCB0byB0cnVlLlxuXG5cdFx0c3dpdGNoICggdGFiICkge1xuXHRcdFx0Ly8gb25seSBzaG93IHRoZSBkaXN0YW5jZXMgdGFiIGlmIHRoZXJlIGFyZSByb3V0ZXNcblx0XHRcdGNhc2UgJ3RhYl9tYXBfZGlzdGFuY2VzJzpcblx0XHRcdFx0aWYgKCB0aGlzLmluY29taW5nX2RhdGFcblx0XHRcdFx0XHQmJiB0aGlzLmluY29taW5nX2RhdGEudHRfbWFwX2RhdGFcblx0XHRcdFx0XHQmJiB0aGlzLmluY29taW5nX2RhdGEudHRfbWFwX2RhdGEudHRfcm91dGVzXG5cdFx0XHRcdFx0JiYgdGhpcy5pbmNvbWluZ19kYXRhLnR0X21hcF9kYXRhLnR0X3JvdXRlcy5sZW5ndGggPiAwICkge1xuXHRcdFx0XHRcdHJldHZhbCA9IHRydWU7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0cmV0dmFsID0gZmFsc2U7XG5cdFx0XHRcdH1cblx0XHRcdFx0YnJlYWs7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHJldHZhbDtcblx0fVxuXG5cdHNldEVkaXRWaWV3RGF0YURvbmUoKSB7XG5cdFx0c3VwZXIuc2V0RWRpdFZpZXdEYXRhRG9uZSgpO1xuXHR9XG5cblx0b25TYXZlQ2xpY2soIGlnbm9yZVdhcm5pbmcgKSB7XG5cdFx0Ly8gUGFyZW50IFZpZXdDb250cm9sbGVyIGhhbmRsZXMgdGhlIGFjdHVhbCBkYXRhIHNhdmUsIGJ1dCBjYWxsYmFjayB3aWxsIGNvbWUgYmFjayBoZXJlIGFmdGVyIHN1Y2Nlc3NmdWxsIHNhdmUuXG5cdFx0Ly8gQ29kZSBub3RlOiAnbW92ZWRfdW5zYXZlZF9tYXJrZXJzJyBpcyBhbiBvYmplY3QsIGFzIGVhY2ggbWFya2VyIG1vdmVkIGlzIHN0b3JlZCBhcyBhbiBhdHRyaWJ1dGUgb24gdGhlIG9iamVjdC4gV2hlbiBwYXNzZWQgdG8gcGFyZW50IHZpZXcgY29udHJvbGxlciBmb3Igc2F2aW5nLCB0aGUgZGF0YSBpcyBhbiBhcnJheSB2aWEgXy52YWx1ZXNcblxuXHRcdHZhciB0aGlzX01hcFZpZXdDb250cm9sbGVyID0gdGhpczsgLy8gUmVmZXJlbmNlIGxvY2FsIHNjb3BlIGZvciBjYWxsYmFja3MgdG8gcmVmZXJlbmNlIGZ1cnRoZXIgZG93biBpbiB0aGUgZnVuY3Rpb24uIFZhciBuYW1lIGFsc28gaWRlbnRpZmllcyB3aGF0ICd0aGlzJyBpcyByZWZlcnJpbmcgdG8uXG5cdFx0aWYgKCB0aGlzLnBhcmVudF92aWV3X2NvbnRyb2xsZXIub25NYXBTYXZlQ2xpY2sgKSB7XG5cdFx0XHR0aGlzLnBhcmVudF92aWV3X2NvbnRyb2xsZXIub25NYXBTYXZlQ2xpY2soIF8udmFsdWVzKCB0aGlzLm1vdmVkX3Vuc2F2ZWRfbWFya2VycyApLCBfb25TYXZlQ2xpY2tDYWxsYmFjayApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHREZWJ1Zy5UZXh0KCAnRVJST1I6IFNhdmUgZnVuY3Rpb24gZG9lcyBub3QgZXhpc3Qgb24gcGFyZW50IFZpZXdDb250cm9sbGVyLiBNaXNzaW5nIGZ1bmN0aW9uIG9yIG1hcmtlciBzaG91bGQgbm90IGJlIHNldCB0byBkcmFnZ2FibGUuJywgJ01hcFZpZXdDb250cm9sbGVyLmpzJywgJ01hcFZpZXdDb250cm9sbGVyJywgJ29uU2F2ZUNsaWNrJywgMSApO1xuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIF9vblNhdmVDbGlja0NhbGxiYWNrKCkge1xuXHRcdFx0dGhpc19NYXBWaWV3Q29udHJvbGxlci5pc19jaGFuZ2VkID0gZmFsc2U7XG5cdFx0XHR0aGlzX01hcFZpZXdDb250cm9sbGVyLm1vdmVkX3Vuc2F2ZWRfbWFya2VycyA9IHt9O1xuXHRcdFx0dGhpc19NYXBWaWV3Q29udHJvbGxlci5yZW1vdmVFZGl0VmlldygpO1xuXHRcdFx0UHJvZ3Jlc3NCYXIuY2xvc2VPdmVybGF5KCk7XG5cdFx0fVxuXHR9XG5cblx0b25FeHBvcnRDbGljayggbWV0aG9kICkge1xuXHRcdC8vRGVidWcuVGV4dCgnRXhwb3J0aW5nIEdyaWQgVG8gQ1NWOiAnK21ldGhvZCwgJ01hcFZpZXdDb250cm9sbGVyLmpzJywgJ01hcFZpZXdDb250cm9sbGVyJywgJ29uRXhwb3J0Q2xpY2snLCAxMCk7XG5cblx0XHRQcm9ncmVzc0Jhci5zaG93T3ZlcmxheSgpO1xuXHRcdC8vIGlmICggbWV0aG9kID09IHVuZGVmaW5lZCApIHtcblx0XHQvLyBcdG1ldGhvZCA9IHRoaXMuYXBpWydleHBvcnQnICsgdGhpcy5hcGkua2V5X25hbWVdO1xuXHRcdC8vIH1cblx0XHRpZiAoIHRoaXMuZGlzdGFuY2VzX2dyaWQgKSB7XG5cdFx0XHR0aGlzLmRpc3RhbmNlc19ncmlkLmdyaWQyY3N2KCAnZHJpdmluZ19kaXN0YW5jZXMnICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdERlYnVnLlRleHQoICdFUlJPUjogRXhwb3J0aW5nIEdyaWQgVG8gQ1NWIEZhaWxlZCwgZ3JpZCBkb2VzIG5vdCBleGlzdC4nLCAnTWFwVmlld0NvbnRyb2xsZXIuanMnLCAnTWFwVmlld0NvbnRyb2xsZXInLCAnb25FeHBvcnRDbGljaycsIDEgKTtcblx0XHR9XG5cdFx0UHJvZ3Jlc3NCYXIuY2xvc2VPdmVybGF5KCk7XG5cdH1cblxuXHQvLyBNYXAgaW5pdGlhbGlzYXRpb24gc2VjdGlvblxuXHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdGluaXRMZWFmbGV0TWFwKCkge1xuXHRcdHZhciBvc207XG5cdFx0dmFyIG1hcF9sYXllcnM7XG5cblx0XHRpZiAoIEFQSUdsb2JhbC5wcmVfbG9naW5fZGF0YS5tYXBfcHJvdmlkZXIgJiYgQVBJR2xvYmFsLnByZV9sb2dpbl9kYXRhLm1hcF9wcm92aWRlciA9PSAnbWFwYm94JyApIHtcblx0XHRcdHZhciBvc21VcmwgPSAnaHR0cHM6Ly9hcGkubWFwYm94LmNvbS9zdHlsZXMvdjEve2lkfS90aWxlcy97en0ve3h9L3t5fT9hY2Nlc3NfdG9rZW49e2FjY2Vzc1Rva2VufSc7XG5cdFx0XHR2YXIgb3NtQXR0cmliID0gJ8KpIDxhIGhyZWY9XCJodHRwczovL3d3dy5tYXBib3guY29tL2Fib3V0L21hcHMvXCI+TWFwYm94PC9hPiDCqSA8YSBocmVmPVwiaHR0cDovL3d3dy5vcGVuc3RyZWV0bWFwLm9yZy9jb3B5cmlnaHRcIj5PcGVuU3RyZWV0TWFwPC9hPiA8c3Ryb25nPjxhIGhyZWY9XCJodHRwczovL3d3dy5tYXBib3guY29tL21hcC1mZWVkYmFjay9cIiB0YXJnZXQ9XCJfYmxhbmtcIj5JbXByb3ZlIHRoaXMgbWFwPC9hPjwvc3Ryb25nPic7XG5cblx0XHRcdG9zbSA9IFsgTC50aWxlTGF5ZXIoIG9zbVVybCwgeyBhdHRyaWJ1dGlvbjogb3NtQXR0cmliLCB0aWxlU2l6ZTogNTEyLCBtYXhab29tOiAxOCwgem9vbU9mZnNldDogLTEsIGlkOiAnbWFwYm94L3N0cmVldHMtdjExJywgYWNjZXNzVG9rZW46IEFQSUdsb2JhbC5wcmVfbG9naW5fZGF0YS5tYXBfYXBpX2tleSB9KSwgXTsgLy9TdHJlZXQgTWFwc1xuXHRcdFx0bWFwX2xheWVycyA9IHsgJ1N0cmVldHMnOiBvc21bMF0sICdTYXRlbGxpdGUnOiBMLnRpbGVMYXllciggb3NtVXJsLCB7IGF0dHJpYnV0aW9uOiBvc21BdHRyaWIsIHRpbGVTaXplOiA1MTIsIG1heFpvb206IDE4LCB6b29tT2Zmc2V0OiAtMSwgaWQ6ICdtYXBib3gvc2F0ZWxsaXRlLXN0cmVldHMtdjExJywgYWNjZXNzVG9rZW46IEFQSUdsb2JhbC5wcmVfbG9naW5fZGF0YS5tYXBfYXBpX2tleSB9KSB9O1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR2YXIgb3NtVXJsID0gQVBJR2xvYmFsLnByZV9sb2dpbl9kYXRhLm1hcF90aWxlX3VybCArICcve3p9L3t4fS97eX0ucG5nP3R0X2tleT0nICsgQVBJR2xvYmFsLnByZV9sb2dpbl9kYXRhLnJlZ2lzdHJhdGlvbl9rZXk7XG5cdFx0XHR2YXIgb3NtQXR0cmliID0gJ01hcCBkYXRhIGJ5IMKpPGEgaHJlZj1cImh0dHA6Ly93d3cub3BlbnN0cmVldG1hcC5vcmcvY29weXJpZ2h0XCI+T3BlblN0cmVldE1hcDwvYT4uJztcblxuXHRcdFx0b3NtID0gWyBuZXcgTC5UaWxlTGF5ZXIoIG9zbVVybCwgeyBtaW5ab29tOiAzLCBtYXhab29tOiAxOCwgYXR0cmlidXRpb246IG9zbUF0dHJpYiwgbm9XcmFwOiB0cnVlIH0gKSBdO1xuXHRcdH1cblxuXHRcdHRoaXMubWFwX2NvbnRyb2wgPSBuZXcgVFRNYXAoICdtYXAnLCB7XG5cdFx0XHRhdXRvUGFuOiBmYWxzZSxcblx0XHRcdG1heEJvdW5kc1Zpc2Nvc2l0eTogMS4wLFxuXHRcdFx0bGF5ZXJzOiBvc20sXG5cdFx0XHRtaW5ab29tOiAyXG5cdFx0fSApO1xuXG5cdFx0aWYgKCBtYXBfbGF5ZXJzICkgeyAvL0FkZCBhbnkgU3RyZWV0L1NhdGVsbGl0ZSBsYXllcnMgdG8gdGhlIG1hcCBpZiB0aGV5IGFyZSBzcGVjaWZpZWQuXG5cdFx0XHRMLmNvbnRyb2wubGF5ZXJzKCBtYXBfbGF5ZXJzICkuYWRkVG8oIHRoaXMubWFwX2NvbnRyb2wuX2ludGVybmFsLl9sZWFmbGV0X21hcCApO1xuXHRcdH1cblxuXHRcdC8vIGxlYWZsZXQtdGltZXRyZXggYWxyZWFkeSBzZXRzIHN0YXJ0IHZpZXcgdG8gY2VudGVyIG9mIFVTLCBsZXRzIHRyeSB0byBmaW5kIGEgYmV0dGVyIGxvY2F0aW9uIGJhc2VkIG9uIGNvbXBhbnkvZW1wbG95ZWVcblx0XHR2YXIgY3VycmVudF9tYXBfZGVmYXVsdF9jb29yZGluYXRlcyA9IHRoaXMubWFwX2NvbnRyb2wuZ2V0Q2VudGVyKCk7XG5cdFx0dmFyIGFsdGVybmF0aXZlX2RlZmF1bHRfY29vcmRpbmF0ZXMgPSB0aGlzLnN0YXJ0TWFwQ29vcmRpbmF0ZXMoKTtcblx0XHQvLyBjaGVjayBpZiB0aGUgY2FsY3VsYXRlZCBkZWZhdWx0cyBhcmUgYW55IGRpZmZlcmVudCB0aGFuIG1hcCBkZWZhdWx0IChVUyBjb250aW5lbnQgY2VudGVyLCB6b29tIDQpXG5cdFx0aWYgKCBjdXJyZW50X21hcF9kZWZhdWx0X2Nvb3JkaW5hdGVzLmVxdWFscyggYWx0ZXJuYXRpdmVfZGVmYXVsdF9jb29yZGluYXRlcyApID09PSBmYWxzZSApIHtcblx0XHRcdC8vIGZvdW5kIGJldHRlciBkZWZhdWx0IGNvb3JkaW5hdGVzLCB1c2UgdGhvc2UsIGFuZCB6b29tIGluIGZ1cnRoZXIgKDEwKVxuXHRcdFx0dGhpcy5tYXBfY29udHJvbC5zZXRWaWV3KCBhbHRlcm5hdGl2ZV9kZWZhdWx0X2Nvb3JkaW5hdGVzLCAxMCApO1xuXHRcdH1cblxuXHRcdHRoaXMuaW5pdFJvdXRpbmdMb2dpYygpOyAvLyBNdXN0IGJlIGJlZm9yZSBtYXJrZXJzIChhbmQgcm91dGVzKSBhcmUgcHJvY2Vzc2VkXG5cblx0XHR2YXIgY2x1c3Rlcl9sYXllcl9vcHRpb25zID0ge1xuXHRcdFx0bWF4Q2x1c3RlclJhZGl1czogNTUsIC8vIG1ha2Ugc3VyZSBub3QgdG9vIGJpZywgZWxzZSBjbHVzdGVycyBjYW50IHNwaWRlcmlmeSwgbm90IHRvbyBzbWFsbCBmb3Igb3ZlcmxhcFxuXHRcdFx0c3BpZGVyZnlEaXN0YW5jZU11bHRpcGxpZXI6IDUsIC8vIHRvIHByZXZlbnQgb3ZlcmxhcCwgYnV0IHdpdGggY2xpY2thYmxlIHRvb2x0aXBzIHRvIGhpZGUsIG5vdCBzbyBtdWNoIGFuIGlzc3VlIG5vd1xuXHRcdFx0c2hvd0NvdmVyYWdlT25Ib3ZlcjogZmFsc2UgLy8gd2l0aCBzbWFsbCBudW1iZXIgb2YgbWFya2VycyBjbG9zZSB0b2dldGhlciwgdGhlIHBvbHlnb24gbGluZXMgZm9yIGJvdW5kcyBsb29rIG1vcmUgbWVzc3kgdGhhbiBoZWxwZnVsXG5cdFx0fTtcblxuXHRcdC8vIHRoaXMubWFwX2NvbnRyb2wuY3JlYXRlTGF5ZXIoJ21hcmtlcnMnKTsgLy8gZm9yIG5vcm1hbCBtYXJrZXIgbGF5ZXJzIHZzIGNsdXN0ZXJlZFxuXHRcdHRoaXMubWFwX2NvbnRyb2wuY3JlYXRlTGF5ZXIoICdtYXJrZXJzJywge1xuXHRcdFx0dHlwZTogJ21hcmtlci1jbHVzdGVyJyxcblx0XHRcdGNsdXN0ZXJfbGF5ZXJfb3B0aW9uczogY2x1c3Rlcl9sYXllcl9vcHRpb25zXG5cdFx0fSApO1xuXG5cdFx0dGhpcy5tYXBfY29udHJvbC5jcmVhdGVMYXllciggJ2xpbmVzJyApO1xuXHRcdHRoaXMubWFwX2NvbnRyb2wuY3JlYXRlTGF5ZXIoICdtYXJrZXItY2lyY2xlcycgKTtcblx0XHR0aGlzLm1hcF9jb250cm9sLmNyZWF0ZUxheWVyKCAnZ2VvZmVuY2VzJyApO1xuXG5cdFx0dGhpcy5pbml0U2VhcmNoQm94KCk7XG5cdH1cblxuXHRpbml0Um91dGluZ0xvZ2ljKCkge1xuXHRcdHZhciByb3V0aW5nX29wdGlvbnMgPSB7XG5cdFx0XHRyb3V0aW5nX3VybDogQVBJR2xvYmFsLnByZV9sb2dpbl9kYXRhLm1hcF9yb3V0aW5nX3VybFxuXHRcdH07XG5cdFx0dGhpcy5tYXBfY29udHJvbC5jcmVhdGVMYXllciggJ3JvdXRlcycgKTtcblx0XHR0aGlzLm1hcF9jb250cm9sLmluaXRSb3V0aW5nRW5naW5lKCByb3V0aW5nX29wdGlvbnMgKTtcblx0fVxuXG5cdHBvcHVsYXRlTGVhZmxldE1hcCggZGF0YSApIHtcblxuXHRcdC8vIFRPRE8tZnV0dXJlOiBNYXliZSBzcGxpdCBnZW9mZW5jZSBsb2dpYyBvdXQgYW5kIG1ha2UgbGVhZmxldC10aW1ldHJleCBoYW5kbGUgdGhpcyBkYXRhPyBPciBhcmUgZ2VvZmVuY2VzIHRoZSBleGNlcHRpb24gdG8gYnVzaW5lc3MgZGF0YVxuXHRcdC8vIFRoZSBpZGVhIHdhcyB0aGF0IGV2ZXJ5dGhpbmcgY29taW5nIHRocm91Z2ggaW4gJ2RhdGEnIHZhcmlhYmxlIHdvdWxkIGJlIGluIFRUTWFwIGRhdGEgZm9ybWF0LlxuXG5cdFx0Ly8gQ2hlY2sgaWYgaW5jb21pbmcgZGF0YSBpcyBnZW9mZW5jZXMsIGFsbCBvdGhlciAnZGF0YScgd2lsbCBiZSBpbiBUVE1hcCBmb3JtYXQuXG5cdFx0aWYgKCBkYXRhLmxlbmd0aCA+IDAgJiYgZGF0YVswXS5oYXNPd25Qcm9wZXJ0eSggJ2dlb190eXBlX2lkJyApICkge1xuXHRcdFx0Ly8gdGhpcyB3aWxsIGJlIHVzaW5nIHRoZSBvbGQgZGF0YSBmb3JtYXQgd2hpY2ggaGFzIGFuIGFycmF5IG9ubHkgMSBsZXZlbCBkZWVwXG5cdFx0XHQvLyB3ZSBjYW4gY2FsbCBkcmF3IEdlb2ZlbmNlcyBkaXJlY3RseSB3aXRob3V0IGNoZWNraW5nIGFwaSBmb3IgZ2VvZmVuY2UgZmVhdHVyZSBlbmFibGVkIGxpa2UgaW4gaW5pdEdlb0ZlbmNlcygpLCBiZWNhdXNlIHRoaXMgZ2VvX3R5cGVfaWQgd2lsbFxuXHRcdFx0Ly8gb25seSBiZSBwcmVzZW50IGlmIHRyaWdnZXJlZCBmcm9tIGVkaXQgZ2VvZmVuY2UgVUksIHdoaWNoIGl0c2VsZiB3aWxsIGNoZWNrIGZvciB0aGUgZmVhdHVyZSBwZXJtaXNzaW9ucy5cblx0XHRcdHZhciBnZW9fYm91bmRzID0gdGhpcy5kcmF3R2VvRmVuY2VzKCBkYXRhICk7XG5cdFx0XHR0aGlzLmV4dGVuZE1hcEJvdW5kcyggZ2VvX2JvdW5kcyApO1xuXHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0XHQvLyBlbmQgZ2VvLWZlbmNlIGxvZ2ljLiBEbyBub3QgY29udGludWUgYXMgd2UgYXJlIG9ubHkgd2FudGluZyB0byBwbG90IGdlb2ZlbmNlcy5cblx0XHR9XG5cblx0XHQvLyBUcmlnZ2VyIHRoZSBwbG90dGluZyBvZiB0aGUgb3JnYW5pc2VkIGRhdGEgb250byB0aGUgbWFwLlxuXHRcdGlmICggIWRhdGEgfHwgIWRhdGEub3B0aW9ucyB8fCAhZGF0YS50dF9tYXBfZGF0YSApIHtcblx0XHRcdERlYnVnLlRleHQoICdFcnJvcjogVFRNYXBEYXRhIGlzIGluIGFuIGludmFsaWQgZm9ybWF0LiBBYm9ydC4nLCAnTWFwVmlld0NvbnRyb2xsZXIuanMnLCAnTWFwVmlld0NvbnRyb2xsZXInLCAncG9wdWxhdGVMZWFmbGV0TWFwJywgMSApO1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblxuXHRcdC8vIFRlbXAgZm9yIGRlYnVnIGR1cmluZyBkZXZcblx0XHR3aW5kb3cubWFwX2NvbnRyb2wgPSB0aGlzLm1hcF9jb250cm9sO1xuXG5cdFx0Ly8gT3B0aW9ucyBTZXR0aW5nIGZvciBhZGRUVE1hcCBmdW5jdGlvblxuXHRcdHZhciBvcHRpb25zID0ge1xuXHRcdFx0Y2FsbGJhY2tEaXN0YW5jZVJlc3VsdHM6IHRoaXMuY2FsbGJhY2tEaXN0YW5jZVJlc3VsdHMuYmluZCggdGhpcyApXG5cdFx0fTtcblxuXHRcdC8vIE1hcmtlciBQcm9jZXNzaW5nXG5cblx0XHRpZiAoIGRhdGEub3B0aW9ucy5zaW5nbGVfbWFya2VyX2RyYWdnYWJsZSA9PT0gdHJ1ZSAvLyBUaGlzIHByZXZlbnRzIG5ldyBtYXJrZXIgJiBzYXZlIG1hcmtlciBvbiByZWFkIG9ubHkgdmlld3MuIEFzIG9mIG5vdywgb25seSB0aW1lc2hlZXQgYW5kIHB1bmNoIHZpZXcgY2FuIGVkaXQvYWRkIGxhdGxuZyBsb2NhdGlvbnNcblx0XHRcdCYmIGRhdGEudHRfbWFwX2RhdGEudHRfbWFya2Vyc1xuXHRcdFx0JiYgZGF0YS50dF9tYXBfZGF0YS50dF9tYXJrZXJzLmxlbmd0aCA9PT0gMFxuXHRcdCkge1xuXHRcdFx0Ly8gSW5pdGlhdGUgbmV3IG1hcmtlciBVSS5cblx0XHRcdC8vIE5vIG1hcmtlcnMgZm91bmQgaW4gZGF0YSwgdGhpcyBtYXkgYmUgYSBuZXcgcHVuY2ggcmVjb3JkIGJlaW5nIGNyZWF0ZWQsIG9yIGV4aXN0aW5nIHB1bmNoIHdpdGggbm8gZ3BzLlxuXHRcdFx0Ly8gTm90ZSwgd2Ugbm8gbG9uZ2VyIG5lZWQgdG8gY2hlY2sgZm9yIGlkIHRvIGlkZW50aWZ5IG5ldyBwdW5jaCByZWNvcmRzLiBQcmV2aW91cyBjb2RlIG5lZWRlZCB0byBrbm93LCBhcyBuZXcgcHVuY2hlcyByZXF1aXJlZCBkYXRhIHRvIGJlXG5cdFx0XHQvLyBwYXNzZWQgYmFjayB0byBwYXJlbnQgY29udHJvbGxlciwgYW5kIGV4aXN0aW5nIHB1bmNoIG1hcCBkYXRhIHdvdWxkIGJlIGRpcmVjdGx5IHNhdmVkIGJ5IE1hcFZpZXdDb250cm9sbGVyLlxuXHRcdFx0Ly8gTm93LCB3ZSBhbHdheXMgcGFzcyBiYWNrLCBhbmQgcGFyZW50IGRvZXMgc2F2aW5nLCBub3QgTWFwVmlld0NvbnRyb2xsZXIuIFNvIG5ldyBwdW5jaGVzIGFuZCBleGlzdGluZyBwdW5jaCB3aXRob3V0IGdwcyB3aWxsIGJlIHRyZWF0ZWQgdGhlIHNhbWUuXG5cdFx0XHQvLyBOb3RlLCB0aGlzIGxvZ2ljIG1heSBuZWVkIHRvIGNoYW5nZSB3aGVuIG1hc3MgZWRpdCBpcyBlbmFibGVkLiBBcyB0aGF0IHdvdWxkIGFsc28gZGVhbCB3aXRoIHNpbmdsZSByZWNvcmRzLlxuXG5cdFx0XHR2YXIgbWFya2VyX29wdGlvbnMgPSB7XG5cdFx0XHRcdGRyYWdnYWJsZTogdHJ1ZSxcblx0XHRcdFx0Y2FsbGJhY2tzOiB7XG5cdFx0XHRcdFx0b25NYXJrZXJEcmFnZW5kOiB0aGlzLmNhbGxiYWNrVHJpZ2dlck1hcmtlck1vdmUuYmluZCggdGhpcyApLFxuXHRcdFx0XHRcdG9uTWFya2VyQWRkTmV3OiB0aGlzLmNhbGxiYWNrVHJpZ2dlck1hcmtlck1vdmUuYmluZCggdGhpcyApXG5cdFx0XHRcdH1cblx0XHRcdH07XG5cblx0XHRcdHRoaXMubWFwX2NvbnRyb2wuYWRkTWFya2VySW50ZXJhY3RpdmUoIG1hcmtlcl9vcHRpb25zICk7XG5cdFx0XHREZWJ1Zy5UZXh0KCAnTm90ZTogTm8gbWFya2VycyBmb3VuZCBpbiBkYXRhLiBNYXkgYmUgbmV3IHJlY29yZC9leGlzdGluZyB3aXRoIG5vIGdwcycsICdNYXBWaWV3Q29udHJvbGxlci5qcycsICdNYXBWaWV3Q29udHJvbGxlcicsICdwb3B1bGF0ZUxlYWZsZXRNYXAnLCAxMCApO1xuXHRcdH1cblxuXHRcdC8vIFNwZWNpYWwgbG9naWMgdG8gcHJlcCBkYXRhIGZ1cnRoZXIgd2hlbiB0aGVyZSBpcyBvbmx5IG9uZSBtYXJrZXIuIFJlbGF0ZWQgdG8gdHJhY2tpbmcgbWFya2VycyB0aGF0IGhhdmUgYmVlbiBtb3ZlZC5cblx0XHRpZiAoIGRhdGEudHRfbWFwX2RhdGEudHRfbWFya2VycyAmJiBkYXRhLnR0X21hcF9kYXRhLnR0X21hcmtlcnMubGVuZ3RoID09PSAxICkge1xuXHRcdFx0ZGF0YS50dF9tYXBfZGF0YS50dF9tYXJrZXJzWzBdLmNhbGxiYWNrcyA9IGRhdGEudHRfbWFwX2RhdGEudHRfbWFya2Vyc1swXS5jYWxsYmFja3MgfHwge307XG5cblx0XHRcdC8vIGNoZWNrIGlmIG9uTWFya2VyRHJhZ2VuZCBhbHJlYWR5IGV4aXN0cyBvbiBtYXJrZXIgZGF0YSBmcm9tIHBhcmVudCB2aWV3IGNvbnRyb2xsZXIsIGFkZCBtb3JlIGNoZWNrcyBpZiBtb3JlIGNhbGxiYWNrcyBhZGRlZCB0byAndGhpcy5tYXBDYWxsYmFja3MnXG5cdFx0XHQvLyBUT0RPLWZ1dHVyZTogSW5zdGVhZCBvZiBvdmVyd3JpdGluZywgYWRkIHRoZSBjYWxsYmFja3MgaW4gYSBjaGFpbj8gUmVxdWlyZXMgZnV0dXJlIHJlZmFjdG9yLlxuXHRcdFx0aWYgKCBkYXRhLnR0X21hcF9kYXRhLnR0X21hcmtlcnNbMF0uY2FsbGJhY2tzLm9uTWFya2VyRHJhZ2VuZCApIHtcblx0XHRcdFx0RGVidWcuVGV4dCggJ0Vycm9yOiBEdXBsaWNhdGUgb25NYXJrZXJEcmFnRW5kIGNhbGxiYWNrIGZvdW5kLiBPdmVyd3JpdGluZyBwYXJlbnQgdmlldyBjYWxsYmFjay4nLCAnTWFwVmlld0NvbnRyb2xsZXIuanMnLCAnTWFwVmlld0NvbnRyb2xsZXInLCAncG9wdWxhdGVMZWFmbGV0TWFwJywgMSApO1xuXHRcdFx0fVxuXG5cdFx0XHRkYXRhLnR0X21hcF9kYXRhLnR0X21hcmtlcnNbMF0uY2FsbGJhY2tzLm9uTWFya2VyRHJhZ2VuZCA9IHRoaXMuY2FsbGJhY2tUcmlnZ2VyTWFya2VyTW92ZS5iaW5kKCB0aGlzICk7XG5cblx0XHRcdC8vIEFzIHRoZXJlIGlzIG9ubHkgb25lIG1hcmtlciwgY2VudGVyIG1hcCBvbiBtYXJrZXIgYW5kIHpvb20gaW4gdG8gbWF4IC0yIHpvb20gKC0yIGlzIHNvIHdlIGRvbnQganVzdCBzZWUgYmxhbmsgaW4gcnVyYWwpXG5cdFx0XHQvL3RoaXMubWFwX2NvbnRyb2wuc2V0VmlldyggZGF0YS50dF9tYXBfZGF0YS50dF9tYXJrZXJzWzBdLmxhdGxuZywgMTYgKTtcblx0XHRcdC8vIGRvbid0IHNldCBzcGVjaWZpYyB6b29tIGZvciBzaW5nbGUgbWFya2VyLiBsZXQgZ2VuZXJhdGVNYXJrZXJCb3VuZHMoKSBoYW5kbGUgYWxsIHRoYXRcblx0XHR9XG5cblx0XHRpZiAoIGRhdGEudHRfbWFwX2RhdGEudHRfbWFya2VycyAmJiBkYXRhLnR0X21hcF9kYXRhLnR0X21hcmtlcnMubGVuZ3RoID4gMCApIHtcblx0XHRcdC8vIERhdGEgbW9kaWZpY2F0aW9ucy9jaGVja3MgZG9uZSwgc2VuZCB0byBUVE1hcCB0byBwbG90IG9uIG1hcFxuXHRcdFx0dGhpcy5tYXBfY29udHJvbC5hZGRUVE1hcERhdGEoIGRhdGEudHRfbWFwX2RhdGEsIG9wdGlvbnMgKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0Ly8gTm8gZGF0YSBhdmFpbGFibGUgZm9yIG1hcC4gTm90aGluZyB0byBwbG90XG5cdFx0XHREZWJ1Zy5UZXh0KCAnRXJyb3I6IE5vIGRhdGEgdG8gcGxvdCBmb3IgbWFwLicsICdNYXBWaWV3Q29udHJvbGxlci5qcycsICdNYXBWaWV3Q29udHJvbGxlcicsICdwb3B1bGF0ZUxlYWZsZXRNYXAnLCAxICk7XG5cdFx0fVxuXG5cdFx0dmFyIG1hcmtlcl9ib3VuZHMgPSB0aGlzLmdlbmVyYXRlTWFya2VyQm91bmRzKCk7XG5cdFx0dGhpcy5leHRlbmRNYXBCb3VuZHMoIG1hcmtlcl9ib3VuZHMgKTtcblxuXHRcdC8vIEdlb2ZlbmNlIFByb2Nlc3NpbmdcblxuXHRcdC8vIGNoZWNrIGdlb2ZlbmNlIGRhdGEgaXMgaW4gY29ycmVjdCBmb3JtYXQgKG9iamVjdCB3aXRoIGtleXMsIG5vdCBhbiBhcnJheSlcblx0XHRpZiAoIGRhdGEuZ2VvZmVuY2VfZmlsdGVyc1xuXHRcdFx0JiYgT2JqZWN0LmtleXMoIGRhdGEuZ2VvZmVuY2VfZmlsdGVycyApLmxlbmd0aCA+IDBcblx0XHRcdCYmIGRhdGEuZ2VvZmVuY2VfZmlsdGVycy5sZW5ndGggPT09IHVuZGVmaW5lZCAvLyBtZWFucyBpdHMgbm90IGFuIGFycmF5XG5cdFx0KSB7XG5cdFx0XHR0aGlzLmdlb2ZlbmNlX2ZpbHRlcnMgPSBkYXRhLmdlb2ZlbmNlX2ZpbHRlcnM7XG5cblx0XHRcdC8vMSBzZWNvbmQgbGF0ZXIgdG8gbWFrZSBzdXJlIG1hcCBpcyBkcmF3LCB0aGUgYm91bmRzIGdvdCB2YWx1ZVxuXHRcdFx0dmFyIHRoaXNfTWFwVmlld0NvbnRyb2xsZXIgPSB0aGlzOyAvLyBSZWZlcmVuY2UgbG9jYWwgc2NvcGUgZm9yIGNhbGxiYWNrcyB0byByZWZlcmVuY2UgZnVydGhlciBkb3duIGluIHRoZSBmdW5jdGlvbi4gVmFyIG5hbWUgYWxzbyBpZGVudGlmaWVzIHdoYXQgJ3RoaXMnIGlzIHJlZmVycmluZyB0by5cblx0XHRcdC8vIHRoaXMgc2V0VGltZW91dCBmdW5jdGlvbiB3YXMgaW4gdGhlIG9sZCBjb2RlLCBidXQgZG9lcyBub3Qgc2VlbSBuZWVkZWQ/IFRlc3QgaXQgb3V0IGZvciBhIHdoaWxlLlxuXHRcdFx0Ly8gaWYgY29tbWVudGVkIG91dCwgaXQgc2VlbXMgdG8gc2hvdyBtb3JlIGJvdW5kcywgYW5kIGxlc3MgYm91bmRzIGlmIGxlZnQgaW4uXG5cdFx0XHQvLyBtYXliZSBkdWUgdG8gdmlld3BvaW50IG5vdCBpbmNsdWRpbmcgaXQgdGhlIG1hcmtlciBmaXJzdD8gUmUtdmlzaXQgYWZ0ZXIgcmVzdCBvZiBtYXAgaXMgZG9uZS5cblx0XHRcdHNldFRpbWVvdXQoIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHQvLyBUaGlzIHdpbGwgbG9hZCBnZW8gZmVuY2VzLCB0aGVuIGRyYXcsIHRoZW4gZXh0ZW5kIHRoZSBib3VuZHNcblx0XHRcdFx0dGhpc19NYXBWaWV3Q29udHJvbGxlci5pbml0R2VvRmVuY2VzKCAnaW5pdGlhbC1tYXAtbG9hZCcgKTtcblx0XHRcdH0sIDEwMDAgKTtcblxuXHRcdH1cblx0fVxuXG5cdGNhbGxiYWNrVHJpZ2dlck1hcmtlck1vdmUoIG1hcmtlciwgbmV3X3Bvc2l0aW9uICkge1xuXHRcdHZhciB0aGlzX01hcFZpZXdDb250cm9sbGVyID0gdGhpczsgLy8gUmVmZXJlbmNlIGxvY2FsIHNjb3BlIGZvciBjYWxsYmFja3MgdG8gcmVmZXJlbmNlIGZ1cnRoZXIgZG93biBpbiB0aGUgZnVuY3Rpb24uIFZhciBuYW1lIGFsc28gaWRlbnRpZmllcyB3aGF0ICd0aGlzJyBpcyByZWZlcnJpbmcgdG8uXG5cdFx0dGhpc19NYXBWaWV3Q29udHJvbGxlci5pc19jaGFuZ2VkID0gdHJ1ZTtcblx0XHR0aGlzX01hcFZpZXdDb250cm9sbGVyLnNldEVkaXRNZW51KCk7XG5cdFx0dmFyIG1hcmtlcl9wdW5jaF9pZCA9IG1hcmtlci5vcHRpb25zLnB1bmNoX2lkO1xuXG5cdFx0Ly8gYWRkIHRoZSBpbmZvIHRvIHRoZSBhcnJheSB3aGljaCB0cmFja3MgbW92ZWQgbWFya2Vycy4gVXNlZCBsYXRlciBieSB0aGUgc2F2ZSBmdW5jdGlvblxuXHRcdHRoaXNfTWFwVmlld0NvbnRyb2xsZXIubW92ZWRfdW5zYXZlZF9tYXJrZXJzW21hcmtlcl9wdW5jaF9pZF0gPSB7XG5cdFx0XHRpZDogbWFya2VyX3B1bmNoX2lkLFxuXHRcdFx0bGF0aXR1ZGU6IG5ld19wb3NpdGlvbi5sYXQudG9GaXhlZCggNiApLCAvLyBkYXRhYmFzZSBvbmx5IHN0b3JlcyB0byA2IGRlY2ltYWwgcG9pbnRzLiBOb3RlIHBvdGVudGlhbCBpc3N1ZXMgd2l0aCB1cC9kb3duIHJvdW5kaW5nIHdpdGggdG9GaXhlZCBkdWUgdG8gYmluYXJ5IHN0b3JhZ2Ugd2l0aCBmbG9hdHMsIG5vdCB0b28gaW1wb3J0YW50IGhlcmUgdGhvdWdoXG5cdFx0XHRsb25naXR1ZGU6IG5ld19wb3NpdGlvbi5sbmcudG9GaXhlZCggNiApLCAvLyBkYXRhYmFzZSBvbmx5IHN0b3JlcyB0byA2IGRlY2ltYWwgcG9pbnRzLiBOb3RlIHBvdGVudGlhbCBpc3N1ZXMgd2l0aCB1cC9kb3duIHJvdW5kaW5nIHdpdGggdG9GaXhlZCwgZHVlIHRvIGJpbmFyeSBzdG9yYWdlIHdpdGggZmxvYXRzLCBub3QgdG9vIGltcG9ydGFudCBoZXJlIHRob3VnaFxuXHRcdFx0cG9zaXRpb25fYWNjdXJhY3k6IDBcblx0XHR9O1xuXHRcdERlYnVnLlRleHQoICdNYXJrZXIgcG9zaXRpb24gY2hhbmdlOlxcbk9yaWdpbmFsOiAnICsgbWFya2VyLmdldExhdExuZygpLnRvU3RyaW5nKCkgKyAnXFxuPT4gTmV3OiAnICsgbmV3X3Bvc2l0aW9uLnRvU3RyaW5nKCksICdNYXBWaWV3Q29udHJvbGxlci5qcycsICdNYXBWaWV3Q29udHJvbGxlcicsICdjYWxsYmFja1RyaWdnZXJNYXJrZXJNb3ZlJywgMTAgKTtcblx0fVxuXG5cdC8vIENhbGxiYWNrcyBmcm9tIHRoZSBtYXBcblx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXHRjYWxsYmFja01hcFBhbm5pbmcoKSB7XG5cdFx0Ly8gZGVib3VuY2UgdGhlIGNhbGwgc28gdGhhdCBmYXN0IHpvb21pbmcvcGFubmluZyBsaWtlIHNjcm9sbC16b29taW5nIGRvZXMgbm90IHRyaWdnZXIgdG9vIG1hbnkgQVBJIGNhbGxzIGluIHN1Y2Nlc3Npb24uIEFzIHdlbGwgYXMgaW5pdGlhbCBtYXAgY2hhbmdlcyBkdXJpbmcgbWFwIGxvYWQuXG5cdFx0Y2xlYXJUaW1lb3V0KCB0aGlzLl9tYXBab29tRW5kVGltZXIgKTtcblx0XHR2YXIgdGhpc19NYXBWaWV3Q29udHJvbGxlciA9IHRoaXM7IC8vIFJlZmVyZW5jZSBsb2NhbCBzY29wZSBmb3IgY2FsbGJhY2tzIHRvIHJlZmVyZW5jZSBmdXJ0aGVyIGRvd24gaW4gdGhlIGZ1bmN0aW9uLiBWYXIgbmFtZSBhbHNvIGlkZW50aWZpZXMgd2hhdCAndGhpcycgaXMgcmVmZXJyaW5nIHRvLlxuXHRcdHRoaXMuX21hcFpvb21FbmRUaW1lciA9IHNldFRpbWVvdXQoIGZ1bmN0aW9uKCkge1xuXHRcdFx0dGhpc19NYXBWaWV3Q29udHJvbGxlci5pbml0R2VvRmVuY2VzKCAnbWFwLXBhbm5pbmctZW5kJyApO1xuXHRcdH0sIDUwMCApO1xuXHR9XG5cblx0Ly8gV2hlbiByZXN1bHRzIGNvbWUgaW4gZm9yIGEgc3BlY2lmaWMgcm91dGUsIHRoaXMgY2FsbGJhY2sgc2hvdWxkIGJlIGNhbGxlZCwgc28gdGhhdCBpdCBjYW4gdHJhY2sgYWxsIGRpc3RhbmNlcyBhbmQgY29sbGF0ZS4gQXMgc29tZSB1c2VyIGpvdXJuZXlzIHdpbGwgc2hhcmUgcm91dGUgZGF0YS5cblx0Y2FsbGJhY2tEaXN0YW5jZVJlc3VsdHMoIHJlZl9pZCwgcm91dGVfaW5mbyApIHtcblx0XHR0aGlzLmNhbGN1bGF0ZWRSb3V0ZURhdGFbcmVmX2lkXSA9IHJvdXRlX2luZm87XG5cdH1cblxuXHQvLyBNYXAgc2VhcmNoIGJhciBzZWN0aW9uXG5cdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblx0aW5pdFNlYXJjaEJveCgpIHtcblx0XHR2YXIgdGhpc19NYXBWaWV3Q29udHJvbGxlciA9IHRoaXM7IC8vIFJlZmVyZW5jZSBsb2NhbCBzY29wZSBmb3IgY2FsbGJhY2tzIHRvIHJlZmVyZW5jZSBmdXJ0aGVyIGRvd24gaW4gdGhlIGZ1bmN0aW9uLiBWYXIgbmFtZSBhbHNvIGlkZW50aWZpZXMgd2hhdCAndGhpcycgaXMgcmVmZXJyaW5nIHRvLlxuXHRcdHZhciBwYWNfaW5wdXQgPSAkKCAnI3BhYy1pbnB1dCcgKTtcblx0XHRwYWNfaW5wdXQuYmluZCggJ2ZvY3VzJywgZnVuY3Rpb24oIGUgKSB7XG5cdFx0XHQkKCB0aGlzICkuc2VsZWN0KCk7XG5cdFx0fSApO1xuXG5cdFx0cGFjX2lucHV0LmJpbmQoICdrZXl1cCcsIGZ1bmN0aW9uKCBlICkge1xuXHRcdFx0aWYgKCBlLmtleUNvZGUgPT09IDEzICkge1xuXHRcdFx0XHQkKCAnI3N1Z2dlc3Rpb24tYm94IGRpdicgKS5maXJzdCgpLmNsaWNrKCk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHR0aGlzX01hcFZpZXdDb250cm9sbGVyLnNlYXJjaF9rZXlfZGVsYXkgPSBwYXJzZUludCggRGF0ZS5ub3coKSApO1xuXHRcdFx0XHR3aW5kb3cuc2V0VGltZW91dCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0aWYgKCBwYXJzZUludCggRGF0ZS5ub3coKSApIC0gdGhpc19NYXBWaWV3Q29udHJvbGxlci5zZWFyY2hfa2V5X2RlbGF5ID49IDI1MCApIHtcblx0XHRcdFx0XHRcdHRoaXNfTWFwVmlld0NvbnRyb2xsZXIuc3RvcF9zdWdnZXN0aW9ucyA9IGZhbHNlO1xuXHRcdFx0XHRcdFx0VFRNYXBIZWxwZXIuc2VhcmNoU3VnZ2VzdCggdGhpc19NYXBWaWV3Q29udHJvbGxlciwgZmFsc2UgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0sIDMwMCApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0fVxuXG5cdC8vIEdlbyBmZW5jZSBzZWN0aW9uXG5cdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblx0aW5pdEdlb0ZlbmNlcyggdHJpZ2dlciApIHtcblx0XHQvLyBEZWJ1Zy5UZXh0KCAnSW5pdCBHZW9GZW5jZXMnLCAnTWFwVmlld0NvbnRyb2xsZXIuanMnLCAnTWFwVmlld0NvbnRyb2xsZXInLCAnX2luaXRHZW9GZW5jZScsIDEwICk7XG5cblx0XHRpZiAoIHRoaXMuZ2VvX2ZlbmNlX2FwaSAmJiB0aGlzLmdlb2ZlbmNlX2ZpbHRlcnMgKSB7IC8vaW5pdGlhbGl6ZSBmdW5jdGlvbiBjaGVja3MgcHJvZHVjdCBlZGl0aW9uIGZvciB0aGUgaW5jbHVzaW9uIG9mIHRoZSBnZW9fZmVuY2VfYXBpXG5cdFx0XHQvLyBEZWJ1Zy5UZXh0KCAnSW5pdCBHZW9GZW5jZXM6IERhdGEgZGV0ZWN0ZWQuJywgJ01hcFZpZXdDb250cm9sbGVyLmpzJywgJ01hcFZpZXdDb250cm9sbGVyJywgJ19pbml0R2VvRmVuY2UnLCAxMCApO1xuXHRcdFx0dmFyIHRoaXNfTWFwVmlld0NvbnRyb2xsZXIgPSB0aGlzOyAvLyBSZWZlcmVuY2UgbG9jYWwgc2NvcGUgZm9yIGNhbGxiYWNrcyB0byByZWZlcmVuY2UgZnVydGhlciBkb3duIGluIHRoZSBmdW5jdGlvbi4gVmFyIG5hbWUgYWxzbyBpZGVudGlmaWVzIHdoYXQgJ3RoaXMnIGlzIHJlZmVycmluZyB0by5cblx0XHRcdHZhciBsZWFmbGV0X21hcF9jZW50ZXIgPSB0aGlzX01hcFZpZXdDb250cm9sbGVyLm1hcF9jb250cm9sLmdldENlbnRlcigpO1xuXG5cdFx0XHR2YXIgY2VudGVyX3BvaW50ID0ge1xuXHRcdFx0XHRjZW50ZXI6IFtsZWFmbGV0X21hcF9jZW50ZXIubGF0LCBsZWFmbGV0X21hcF9jZW50ZXIubG5nXSxcblx0XHRcdFx0cmFkaXVzOiB0aGlzLmdldFZpZXdBcmVhUmFkaXVzKCkgLy8gVE9ETyFcblx0XHRcdH07XG5cblx0XHRcdHZhciBmaWx0ZXJzX2FsbCA9IHRoaXMuZ2VvZmVuY2VfZmlsdGVycztcblx0XHRcdHZhciBicmFuY2ggPSBmaWx0ZXJzX2FsbC5icmFuY2hfaWQ7XG5cdFx0XHR2YXIgZGVwYXJ0bWVudCA9IGZpbHRlcnNfYWxsLmRlcGFydG1lbnRfaWQ7XG5cdFx0XHR2YXIgam9iID0gZmlsdGVyc19hbGwuam9iX2lkO1xuXHRcdFx0dmFyIGpvYl9pdGVtID0gZmlsdGVyc19hbGwuam9iX2l0ZW1faWQ7XG5cdFx0XHR2YXIgcHVuY2hfdGFnID0gZmlsdGVyc19hbGwucHVuY2hfdGFnX2lkO1xuXG5cdFx0XHR0aGlzX01hcFZpZXdDb250cm9sbGVyLmdlb19mZW5jZV9hcGkuZ2V0R0VPRmVuY2VCeUdFT0xvY2F0aW9uQW5kQnJhbmNoQW5kRGVwYXJ0bWVudEFuZEpvYkFuZFRhc2tBbmRQdW5jaFRhZyggY2VudGVyX3BvaW50LCBicmFuY2gsIGRlcGFydG1lbnQsIGpvYiwgam9iX2l0ZW0sIHB1bmNoX3RhZywge1xuXHRcdFx0XHRvblJlc3VsdDogZnVuY3Rpb24oIHJlc3VsdCApIHtcblx0XHRcdFx0XHR2YXIgZ2VvX2ZlbmNlc19yZXN1bHQgPSByZXN1bHQuZ2V0UmVzdWx0KCk7XG5cdFx0XHRcdFx0aWYgKCBnZW9fZmVuY2VzX3Jlc3VsdCAmJiBnZW9fZmVuY2VzX3Jlc3VsdC5sZW5ndGggPiAwICkge1xuXHRcdFx0XHRcdFx0Ly8gR2VvZmVuY2VzIGZvdW5kLCBsZXRzIGRyYXcgdGhlbSBvbiB0aGUgbWFwXG5cdFx0XHRcdFx0XHQvLyBUT0RPOiBBbHNvIGNsZWFyIHRoZSBvbGQgZmVuY2VzIGZpcnN0IVxuXHRcdFx0XHRcdFx0dmFyIGdlb19ib3VuZHMgPSB0aGlzX01hcFZpZXdDb250cm9sbGVyLmRyYXdHZW9GZW5jZXMoIGdlb19mZW5jZXNfcmVzdWx0ICk7IC8vIGRvbid0IGNsZWFuIGFyZWE7XG5cblx0XHRcdFx0XHRcdC8vIERlY2lkZSB3aGV0aGVyIHdlIG5lZWQgdG8gZXhwYW5kIHRoZSBtYXAgYm91bmRzXG5cdFx0XHRcdFx0XHRpZiAoIHRyaWdnZXIgPT09ICdpbml0aWFsLW1hcC1sb2FkJyApIHtcblx0XHRcdFx0XHRcdFx0dGhpc19NYXBWaWV3Q29udHJvbGxlci5leHRlbmRNYXBCb3VuZHMoIGdlb19ib3VuZHMgKTtcblx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRcdC8vIGRvIG5vdGhpbmcgYXMgd2Ugb25seSB3YW50IHRvIGVkaXQgYm91bmRzIG9uIGxvYWQuIE9uIHBhbm5pbmcgd2UganVzdCB3YW50IHRvIHJlLWdlbmVyYXRlIGZlbmNlcyBmb3IgdGhlIHZpZXcgYXJlYS5cblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH0gKTtcblxuXHRcdH0gZWxzZSB7XG5cdFx0XHREZWJ1Zy5UZXh0KCAnX0luaXRHZW9GZW5jZSgpIERlbmllZC4gRnVuY3Rpb25hbGl0eSB1bmF2YWlsYWJsZSBpbiB0aGlzIHByb2R1Y3QgZWRpdGlvbi4nLCAnTWFwVmlld0NvbnRyb2xsZXIuanMnLCAnTWFwVmlld0NvbnRyb2xsZXInLCAnX2luaXRHZW9GZW5jZScsIDEwICk7XG5cdFx0fVxuXHR9XG5cblx0ZHJhd0dlb0ZlbmNlcyggZ2VvX2ZlbmNlX2RhdGEgKSB7XG5cdFx0aWYgKCBnZW9fZmVuY2VfZGF0YSAmJiBnZW9fZmVuY2VfZGF0YS5sZW5ndGggPiAwICkge1xuXHRcdFx0dGhpcy5tYXBfY29udHJvbC5nZXRMYXllciggJ2dlb2ZlbmNlcycgKS5jbGVhcigpO1xuXHRcdFx0dGhpcy5nZW9fbGFiZWxzID0gW107XG5cdFx0XHR2YXIgZ2VvZmVuY2VfYm91bmRzID0gbmV3IEwuTGF0TG5nQm91bmRzKCk7XG5cdFx0XHRmb3IgKCB2YXIgaSA9IDAsIG0gPSBnZW9fZmVuY2VfZGF0YS5sZW5ndGg7IGkgPCBtOyBpKysgKSB7XG5cdFx0XHRcdHZhciBnZW9fZmVuY2UgPSBnZW9fZmVuY2VfZGF0YVtpXTtcblx0XHRcdFx0aWYgKCBnZW9fZmVuY2UuZ2VvX3R5cGVfaWQgPT0gMTAgJiYgZ2VvX2ZlbmNlLmdlb19wb2x5Z29uICkge1xuXHRcdFx0XHRcdGdlb2ZlbmNlX2JvdW5kcy5leHRlbmQoIHRoaXMubWFwX2NvbnRyb2wuZHJhd0dlb0ZlbmNlUG9seWdvbiggZ2VvX2ZlbmNlICkgKTtcblx0XHRcdFx0fSBlbHNlIGlmICggZ2VvX2ZlbmNlLmdlb190eXBlX2lkID09IDIwICYmIGdlb19mZW5jZS5nZW9fY2lyY2xlICkge1xuXHRcdFx0XHRcdGdlb2ZlbmNlX2JvdW5kcy5leHRlbmQoIHRoaXMubWFwX2NvbnRyb2wuZHJhd0dlb0ZlbmNlQ2lyY2xlKCBnZW9fZmVuY2UgKSApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gZ2VvZmVuY2VfYm91bmRzO1xuXHRcdH1cblx0fVxuXG5cdC8vIE1hcCBib3VuZHMgc2VjdGlvblxuXHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdC8qKlxuXHQgKiBleHRlbmRNYXBCb3VuZHNcblx0ICogd2lsbCBmaXQgbWFwIHRvIHNwZWNpZmllZCBib3VuZHMsIGJ5IGV4dGVuZGluZyBibGFuay9leGlzdGluZyBib3VuZHMsIG9yIG92ZXJyaWRpbmcgYm91bmRzXG5cdCAqIEBwYXJhbSBuZXdfYm91bmRzIHRoZSBib3VuZHMgdG8gZXhpc3RpbmcgZXhpc3Rpbmcgb3IgZm9yY2Vcblx0ICogQHBhcmFtIFtmb3JjZV0gb3B0aW9uYWwgYm9vbGVhbiB0byBwcmV2ZW50IGV4dGVuZGluZywgYW5kIGp1c3Qgb3ZlcnJpZGluZyB3aXRoIG5ld1xuXHQgKi9cblx0ZXh0ZW5kTWFwQm91bmRzKCBuZXdfYm91bmRzLCBmb3JjZSApIHtcblx0XHRpZiAoIG5ld19ib3VuZHMgPT09IHVuZGVmaW5lZCApIHtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cdFx0dmFyIGJvdW5kcztcblx0XHRpZiAoIGZvcmNlICkgeyAvLyBpZiBmb3JjZSB0cnVlLCBpdCBtZWFucyBkb250IGV4dGVuZCwgb3ZlcnJpZGUgdGhlIGJvdW5kcyBmcmVzaFxuXHRcdFx0Ym91bmRzID0gbmV3IEwuTGF0TG5nQm91bmRzKCk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGJvdW5kcyA9IHRoaXMubWFwX2xhc3RfYm91bmRzO1xuXHRcdH1cblx0XHRib3VuZHMuZXh0ZW5kKCBuZXdfYm91bmRzICk7XG5cdFx0dGhpcy5tYXBfbGFzdF9ib3VuZHMgPSBib3VuZHM7XG5cblx0XHQvLyBTZXR0aW5nIG1heCB6b29tIHRvIDE0IGZvciB0d28gcmVhc29uczogLS0gbm93IDEzLCB0byB0cmlnZ2VyIHRoZSBtb3ZlIHRvIGJvdW5kcyBvbiBhIHRlc3QgKHRlbXApXG5cdFx0Ly8gMS4gdG8gZW5zdXJlIHJhZGl1cyBmb3IgY2hlY2tpbmcgbmVhcmJ5IGdlb2ZlbmNlcyBpcyBoaWdoIGVub3VnaCB0byBpbmNsdWRlIHRoZW1cblx0XHQvLyAyLiB0byByZWR1Y2UgY2hhbmNlcyBvZiBtYXJrZXJzIGluIHRoZSBtaWRkbGUgb2Ygbm93aGVyZSBzaG93aW5nIGFzIHpvb21lZCBpbiBibGFuayBtYXBzLlxuXHRcdHRoaXMubWFwX2NvbnRyb2wuZml0Qm91bmRzKCBib3VuZHMsIHsgcGFkZGluZzogWzE1LCAxNV0sIG1heFpvb206IDEzIH0gKTtcblx0XHRyZXR1cm4gdHJ1ZTtcblx0fVxuXG5cdGdlbmVyYXRlTWFya2VyQm91bmRzKCkge1xuXHRcdHZhciBtYXJrZXJzID0gT2JqZWN0LnZhbHVlcyggdGhpcy5tYXBfY29udHJvbC5nZXRMYXllciggJ21hcmtlcnMnICkuZ2V0KCkgKTtcblx0XHRpZiAoIG1hcmtlcnMubGVuZ3RoIDwgMSApIHtcblx0XHRcdC8vIG5vIG1hcmtlcnMgdG8gZG8gYm91bmRzIG9uLiBleGl0IGZ1bmN0aW9uLiBOb3QgbmVjZXNzYXJpbHkgYW4gZXJyb3Igc3RhdGUuXG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0dmFyIG1hcmtlcl9ib3VuZHMgPSBuZXcgTC5MYXRMbmdCb3VuZHMoKTtcblx0XHQvLyBmb3IgZWFjaCBtYXJrZXIsIGV4dGVuZCB0aGUgYm91bmRzIHRvIGluY2x1ZGUgaXRcblx0XHRtYXJrZXJzLm1hcCggZnVuY3Rpb24oIG1fbGF5ZXIgKSB7XG5cdFx0XHRtYXJrZXJfYm91bmRzLmV4dGVuZCggbV9sYXllci5nZXRMYXRMbmcoKSApO1xuXHRcdH0gKTtcblx0XHRyZXR1cm4gbWFya2VyX2JvdW5kcztcblx0fVxuXG5cdGdldFZpZXdBcmVhUmFkaXVzKCkge1xuXHRcdHZhciBib3VuZHMgPSB0aGlzLm1hcF9jb250cm9sLmdldEJvdW5kcygpO1xuXHRcdGlmICggIWJvdW5kcyApIHtcblx0XHRcdHJldHVybiAwO1xuXHRcdH1cblx0XHR2YXIgY2VudGVyID0gYm91bmRzLmdldENlbnRlcigpO1xuXHRcdHZhciBuZSA9IGJvdW5kcy5nZXROb3J0aEVhc3QoKTtcblx0XHR2YXIgciA9IDM5NjMuMDtcblx0XHR2YXIgbGF0MSA9IGNlbnRlci5sYXQgLyA1Ny4yOTU4O1xuXHRcdHZhciBsb24xID0gY2VudGVyLmxuZyAvIDU3LjI5NTg7XG5cdFx0dmFyIGxhdDIgPSBuZS5sYXQgLyA1Ny4yOTU4O1xuXHRcdHZhciBsb24yID0gbmUubG5nIC8gNTcuMjk1ODtcblx0XHQvLyBkaXN0YW5jZSA9IGNpcmNsZSByYWRpdXMgZnJvbSBjZW50ZXIgdG8gTm9ydGhlYXN0IGNvcm5lciBvZiBib3VuZHNcblx0XHR2YXIgZGlzID0gciAqIE1hdGguYWNvcyggTWF0aC5zaW4oIGxhdDEgKSAqIE1hdGguc2luKCBsYXQyICkgK1xuXHRcdFx0TWF0aC5jb3MoIGxhdDEgKSAqIE1hdGguY29zKCBsYXQyICkgKiBNYXRoLmNvcyggbG9uMiAtIGxvbjEgKSApO1xuXHRcdHJldHVybiBkaXMgKiAxNjA5LjM0NDtcblx0fVxuXG5cdC8vIHNldERlZmF1bHRNZW51TWFwSWNvbjogZnVuY3Rpb24gKCBjb250ZXh0X2J0biApIHtcblx0Ly8gXHRpZiAoIEdsb2JhbC5nZXRQcm9kdWN0RWRpdGlvbigpIDw9IDEwICkge1xuXHQvLyBcdFx0Y29udGV4dF9idG4uYWRkQ2xhc3MoICdpbnZpc2libGUtaW1hZ2UnICk7XG5cdC8vIFx0fVxuXHQvL1xuXHQvLyBcdHZhciBzaG93ID0gZmFsc2U7XG5cdC8vIFx0aWYgKCB0aGlzLmdyaWQgKSB7XG5cdC8vIFx0XHR2YXIgc2VsZWN0ZWRfaXRlbXMgPSB0aGlzLmdldFNlbGVjdGVkSXRlbXMoKTtcblx0Ly8gXHRcdERlYnVnLkFyciggc2VsZWN0ZWRfaXRlbXMsICdzZWxlY3RlZCBpdGVtcycsICdCYXNlVmlld0NvbnRyb2xsZXIuanMnLCAnQmFzZVZpZXdDb250cm9sbGVyJywgJ3NldERlZmF1bHRNZW51TWFwSWNvbicsIDEwICk7XG5cdC8vIFx0XHRpZiAoIHNlbGVjdGVkX2l0ZW1zLmxlbmd0aCA+IDAgKSB7XG5cdC8vIFx0XHRcdGNvbnRleHRfYnRuLnJlbW92ZUNsYXNzKCAnZGlzYWJsZS1pbWFnZScgKTtcblx0Ly8gXHRcdH0gZWxzZSB7XG5cdC8vIFx0XHRcdGNvbnRleHRfYnRuLmFkZENsYXNzKCAnZGlzYWJsZS1pbWFnZScgKTtcblx0Ly8gXHRcdH1cblx0Ly8gXHR9XG5cdC8vIH0sXG5cblx0Ly8gRGlzdGFuY2UgVGFibGUgQ29kZVxuXHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdGluaXREaXN0YW5jZUdyaWQoKSB7XG5cdFx0Ly8gb25seSBpbml0IGdyaWQgaWYgaXQgZG9lcyBub3QgeWV0IGV4aXN0XG5cdFx0aWYgKCAhdGhpcy5kaXN0YW5jZXNfZ3JpZCApIHtcblx0XHRcdHZhciBncmlkX3BhcmVudF9jb250YWluZXIgPSB0aGlzLmVkaXRfdmlld190YWIuZmluZCggJyN0YWJfbWFwX2Rpc3RhbmNlc19jb250ZW50X2RpdicgKTtcblx0XHRcdHRoaXMuZGlzdGFuY2VzX2dyaWQgPSB0aGlzLmJ1aWxkRGlzdGFuY2VzR3JpZCggJ2Rpc3RhbmNlX2dyaWRfdGFibGUnICk7XG5cdFx0XHRncmlkX3BhcmVudF9jb250YWluZXIuYXBwZW5kKCB0aGlzLmRpc3RhbmNlc19ncmlkICk7XG5cdFx0fVxuXHR9XG5cblx0YnVpbGREaXN0YW5jZXNHcmlkKCBncmlkX3NlbGVjdG9yICkge1xuXHRcdHZhciBjb2x1bW5faW5mb19hcnJheSA9IFtdO1xuXHRcdHZhciBjb2x1bW5faW5mb19kZWZhdWx0ID0ge1xuXHRcdFx0bmFtZTogJ2RlZmF1bHQnLFxuXHRcdFx0aW5kZXg6ICdkZWZhdWx0Jyxcblx0XHRcdGxhYmVsOiAkLmkxOG4uXyggJ0RlZmF1bHQnICksXG5cdFx0XHQvLyB3aWR0aDogMTAwLFxuXHRcdFx0c29ydGFibGU6IHRydWUsXG5cdFx0XHRmb3JtYXR0ZXI6ICdzZWxlY3QnLFxuXHRcdFx0ZWRpdGFibGU6IGZhbHNlLFxuXHRcdFx0dGl0bGU6IGZhbHNlLFxuXHRcdFx0ZWRpdHR5cGU6ICdzZWxlY3QnXG5cdFx0fTtcblxuXHRcdGZ1bmN0aW9uIF9hZGRDb2x1bW4yR3JpZCggZmllbGQsIGxhYmVsLCBvcHRpb25zICkge1xuXHRcdFx0dmFyIGNvbHVtbl9pbmZvID0ge1xuXHRcdFx0XHRuYW1lOiBmaWVsZCxcblx0XHRcdFx0aW5kZXg6IGZpZWxkLFxuXHRcdFx0XHRsYWJlbDogbGFiZWwgLy8gZG8gbm90IHB1dCB0aGUgJC5pMThuIHJlZmVyZW5jZSBkaXJlY3RseSBpbiB0aGUgZnVuY3Rpb24sIGFzIGl0IHdpbGwgaW50ZXJmZXJlIHdpdGggdGhlIGV4dHJhY3Rpb24gb2YgbGFuZ3VhZ2UgbGFiZWxzIGZvciB0cmFuc2xhdGlvbiBmaWxlc1xuXHRcdFx0fTtcblx0XHRcdGlmICggb3B0aW9ucyApIHtcblx0XHRcdFx0alF1ZXJ5LmV4dGVuZCggY29sdW1uX2luZm8sIG9wdGlvbnMgKTsgLy8gaGF2ZSB0aGUgZmxleGliaWxpdHkgaGVyZSB0byBhZGQgaW5kaXZpZHVhbCBjb2x1bW4gb3B0aW9ucyBub3cgdGhhdCB3ZSByZWZhY3RvcmVkIHRvIGEgZnVuY3Rpb25cblx0XHRcdH1cblx0XHRcdGNvbHVtbl9pbmZvX2FycmF5LnB1c2goIGpRdWVyeS5leHRlbmQoIHt9LCBjb2x1bW5faW5mb19kZWZhdWx0LCBjb2x1bW5faW5mbyApICk7XG5cdFx0fVxuXG5cdFx0X2FkZENvbHVtbjJHcmlkKCAnZmlyc3RfbmFtZScsICQuaTE4bi5fKCAnRmlyc3QgTmFtZScgKSApO1xuXHRcdF9hZGRDb2x1bW4yR3JpZCggJ2xhc3RfbmFtZScsICQuaTE4bi5fKCAnTGFzdCBOYW1lJyApICk7XG5cdFx0X2FkZENvbHVtbjJHcmlkKCAnYnJhbmNoJywgJC5pMThuLl8oICdCcmFuY2gnICkgKTtcblx0XHRfYWRkQ29sdW1uMkdyaWQoICdkZXBhcnRtZW50JywgJC5pMThuLl8oICdEZXBhcnRtZW50JyApICk7XG5cdFx0X2FkZENvbHVtbjJHcmlkKCAnam9iX21hbnVhbF9pZCcsICQuaTE4bi5fKCAnSm9iIENvZGUnICkgKTtcblx0XHRfYWRkQ29sdW1uMkdyaWQoICdqb2InLCAkLmkxOG4uXyggJ0pvYicgKSApO1xuXHRcdF9hZGRDb2x1bW4yR3JpZCggJ2pvYl9pdGVtX21hbnVhbF9pZCcsICQuaTE4bi5fKCAnVGFzayBDb2RlJyApICk7XG5cdFx0X2FkZENvbHVtbjJHcmlkKCAnam9iX2l0ZW0nLCAkLmkxOG4uXyggJ1Rhc2snICkgKTtcblx0XHRfYWRkQ29sdW1uMkdyaWQoICdpbl90aW1lX3N0YW1wJywgJC5pMThuLl8oICdJbiBQdW5jaCcgKSApO1xuXHRcdF9hZGRDb2x1bW4yR3JpZCggJ291dF90aW1lX3N0YW1wJywgJC5pMThuLl8oICdPdXQgUHVuY2gnICkgKTtcblx0XHRfYWRkQ29sdW1uMkdyaWQoICd0b3RhbF90aW1lJywgJC5pMThuLl8oICdUb3RhbCBUaW1lJyApICk7XG5cdFx0X2FkZENvbHVtbjJHcmlkKCAnZHVyYXRpb24nLCAkLmkxOG4uXyggJ0RyaXZpbmcgRHVyYXRpb24nICkgKTtcblx0XHRfYWRkQ29sdW1uMkdyaWQoICdkaXN0YW5jZScsICQuaTE4bi5fKCAnRHJpdmluZyBEaXN0YW5jZScgKSApO1xuXHRcdF9hZGRDb2x1bW4yR3JpZCggJ2luX2xhdGl0dWRlJywgJC5pMThuLl8oICdJbiBMYXRpdHVkZScgKSApO1xuXHRcdF9hZGRDb2x1bW4yR3JpZCggJ2luX2xvbmdpdHVkZScsICQuaTE4bi5fKCAnSW4gTG9uZ2l0dWRlJyApICk7XG5cdFx0X2FkZENvbHVtbjJHcmlkKCAnb3V0X2xhdGl0dWRlJywgJC5pMThuLl8oICdPdXQgTGF0aXR1ZGUnICkgKTtcblx0XHRfYWRkQ29sdW1uMkdyaWQoICdvdXRfbG9uZ2l0dWRlJywgJC5pMThuLl8oICdPdXQgTG9uZ2l0dWRlJyApICk7XG5cblx0XHQvLyBGdXR1cmUgb3B0aW9uLiBJZiBpbXBsZW1lbnRpbmcsIGNyZWF0ZSB0aGUgZnVuY3Rpb24gYmVsb3cgYmFzZWQgb2ZmIHNob3dFbXBsb3llZVNldHRpbmdOb1Jlc3VsdENvdmVyKClcblx0XHQvLyBpZiAoIGRhdGEubGVuZ3RoIDwgMSApIHtcblx0XHQvLyBcdHRoaXMuc2hvd0Rpc3RhbmNlVGFibGVOb1Jlc3VsdENvdmVyKCk7XG5cdFx0Ly8gfVxuXG5cdFx0dmFyIHRoaXNfTWFwVmlld0NvbnRyb2xsZXIgPSB0aGlzOyAvLyBSZWZlcmVuY2UgbG9jYWwgc2NvcGUgZm9yIGNhbGxiYWNrcyB0byByZWZlcmVuY2UgZnVydGhlciBkb3duIGluIHRoZSBmdW5jdGlvbi4gVmFyIG5hbWUgYWxzbyBpZGVudGlmaWVzIHdoYXQgJ3RoaXMnIGlzIHJlZmVycmluZyB0by5cblx0XHR2YXIgZGF0YSA9IHRoaXMuZ2V0RGlzdGFuY2VzR3JpZERhdGEoKTtcblxuXHRcdHJldHVybiBuZXcgVFRHcmlkKCBncmlkX3NlbGVjdG9yLCB7XG5cdFx0XHRkYXRhOiBkYXRhLFxuXHRcdFx0Z3JpZENvbXBsZXRlOiBmdW5jdGlvbigpIHtcblx0XHRcdFx0dGhpc19NYXBWaWV3Q29udHJvbGxlci5zZXREaXN0YW5jZXNUYWJsZUdyaWRTaXplKCk7XG5cdFx0XHR9LFxuXHRcdFx0bXVsdGlzZWxlY3Q6IGZhbHNlXG5cdFx0fSwgY29sdW1uX2luZm9fYXJyYXkgKTtcblx0fVxuXG5cdGdldERpc3RhbmNlc0dyaWREYXRhKCkge1xuXHRcdHZhciB0aGlzX01hcFZpZXdDb250cm9sbGVyID0gdGhpczsgLy8gUmVmZXJlbmNlIGxvY2FsIHNjb3BlIGZvciBjYWxsYmFja3MgdG8gcmVmZXJlbmNlIGZ1cnRoZXIgZG93biBpbiB0aGUgZnVuY3Rpb24uIFZhciBuYW1lIGFsc28gaWRlbnRpZmllcyB3aGF0ICd0aGlzJyBpcyByZWZlcnJpbmcgdG8uXG5cdFx0dmFyIGdyaWRfc291cmNlID0gW107XG5cdFx0dmFyIHJvdXRlX2FycmF5ID0gdGhpcy5pbmNvbWluZ19kYXRhLnR0X21hcF9kYXRhLnR0X3JvdXRlcztcblxuXHRcdGlmICggIXJvdXRlX2FycmF5IHx8IHJvdXRlX2FycmF5Lmxlbmd0aCA8IDEgKSB7XG5cdFx0XHQvLyBlcnJvcj8gdGhlcmUgYXJlIG5vIGNhbGN1bGF0ZWQgcm91dGVzLiBObyBuZWVkIHRvIGVycm9yIGZvciBub3csIGFzIGl0cyBsaWtlbHkgdGhpcyB3aWxsIGJlIGhhbmRsZWQgZWFybGllci5cblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cblx0XHRPYmplY3QudmFsdWVzKCByb3V0ZV9hcnJheSApLm1hcCggZnVuY3Rpb24oIHJvdXRlICkge1xuXHRcdFx0dmFyIGluX3B1bmNoID0gcm91dGUucm91dGVfbWFya2Vyc1swXS5wdW5jaDtcblx0XHRcdHZhciBvdXRfcHVuY2ggPSByb3V0ZS5yb3V0ZV9tYXJrZXJzWzFdLnB1bmNoO1xuXG5cdFx0XHRpZiAoIGluX3B1bmNoLnN0YXR1cyAhPT0gJ0luJ1xuXHRcdFx0XHR8fCBvdXRfcHVuY2guc3RhdHVzICE9PSAnT3V0JyApIHtcblx0XHRcdFx0RGVidWcuVGV4dCggJ0VSUk9SOiBpbl9wdW5jaCBhbmQgb3V0X3B1bmNoIGhhdmUgZGF0YSBtaXNtYXRjaCBwdW5jaCBJbi9PdXQgc3RhdHVzJywgJ01hcFZpZXdDb250cm9sbGVyLmpzJywgJ01hcFZpZXdDb250cm9sbGVyJywgJ2dldERpc3RhbmNlc0dyaWREYXRhJywgMSApO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBGb3Igc29tZSBvZiB0aGUgZGF0YSB3ZSB3aWxsIG9ubHkgcmVmZXIgdG8gaW5fcHVuY2guIFRoZXJlZm9yZSwgbWFrZSBzdXJlIHRoZSBkYXRhIG1hdGNoZXMuXG5cdFx0XHRpZiAoIGluX3B1bmNoLmZpcnN0X25hbWUgIT09IG91dF9wdW5jaC5maXJzdF9uYW1lXG5cdFx0XHRcdHx8IGluX3B1bmNoLmxhc3RfbmFtZSAhPT0gb3V0X3B1bmNoLmxhc3RfbmFtZVxuXHRcdFx0XHR8fCBpbl9wdW5jaC5icmFuY2ggIT09IG91dF9wdW5jaC5icmFuY2hcblx0XHRcdFx0fHwgaW5fcHVuY2guZGVwYXJ0bWVudCAhPT0gb3V0X3B1bmNoLmRlcGFydG1lbnRcblx0XHRcdFx0fHwgaW5fcHVuY2guam9iICE9PSBvdXRfcHVuY2guam9iXG5cdFx0XHRcdHx8IGluX3B1bmNoLmpvYl9pdGVtICE9PSBvdXRfcHVuY2guam9iX2l0ZW1cblx0XHRcdCkge1xuXHRcdFx0XHREZWJ1Zy5UZXh0KCAnRVJST1I6IGluX3B1bmNoIGFuZCBvdXRfcHVuY2ggaGF2ZSBkYXRhIG1pc21hdGNoLicsICdNYXBWaWV3Q29udHJvbGxlci5qcycsICdNYXBWaWV3Q29udHJvbGxlcicsICdnZXREaXN0YW5jZXNHcmlkRGF0YScsIDEgKTtcblx0XHRcdH1cblxuXHRcdFx0dmFyIHRhYmxlX2ZpbHRlcnMgPSBbZmFsc2UsIHVuZGVmaW5lZCwgbnVsbCwgJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJ107XG5cdFx0XHR2YXIgdGFibGVfZW50cnkgPSB7XG5cdFx0XHRcdGZpcnN0X25hbWU6IEdsb2JhbC5maWx0ZXJPdXRwdXQoIGluX3B1bmNoLmZpcnN0X25hbWUsIHRhYmxlX2ZpbHRlcnMgKSxcblx0XHRcdFx0bGFzdF9uYW1lOiBHbG9iYWwuZmlsdGVyT3V0cHV0KCBpbl9wdW5jaC5sYXN0X25hbWUsIHRhYmxlX2ZpbHRlcnMgKSxcblx0XHRcdFx0aW5fdGltZV9zdGFtcDogR2xvYmFsLmZpbHRlck91dHB1dCggaW5fcHVuY2gudGltZV9zdGFtcCwgdGFibGVfZmlsdGVycyApLFxuXHRcdFx0XHRpbl9sYXRpdHVkZTogR2xvYmFsLmZpbHRlck91dHB1dCggaW5fcHVuY2gubGF0aXR1ZGUsIHRhYmxlX2ZpbHRlcnMgKSxcblx0XHRcdFx0aW5fbG9uZ2l0dWRlOiBHbG9iYWwuZmlsdGVyT3V0cHV0KCBpbl9wdW5jaC5sb25naXR1ZGUsIHRhYmxlX2ZpbHRlcnMgKSxcblx0XHRcdFx0b3V0X3RpbWVfc3RhbXA6IEdsb2JhbC5maWx0ZXJPdXRwdXQoIG91dF9wdW5jaC50aW1lX3N0YW1wLCB0YWJsZV9maWx0ZXJzICksXG5cdFx0XHRcdG91dF9sYXRpdHVkZTogR2xvYmFsLmZpbHRlck91dHB1dCggb3V0X3B1bmNoLmxhdGl0dWRlLCB0YWJsZV9maWx0ZXJzICksXG5cdFx0XHRcdG91dF9sb25naXR1ZGU6IEdsb2JhbC5maWx0ZXJPdXRwdXQoIG91dF9wdW5jaC5sb25naXR1ZGUsIHRhYmxlX2ZpbHRlcnMgKSxcblx0XHRcdFx0ZGlzdGFuY2U6ICcnLFxuXHRcdFx0XHRkdXJhdGlvbjogJycsXG5cdFx0XHRcdGJyYW5jaDogR2xvYmFsLmZpbHRlck91dHB1dCggaW5fcHVuY2guYnJhbmNoLCB0YWJsZV9maWx0ZXJzICksXG5cdFx0XHRcdGRlcGFydG1lbnQ6IEdsb2JhbC5maWx0ZXJPdXRwdXQoIGluX3B1bmNoLmRlcGFydG1lbnQsIHRhYmxlX2ZpbHRlcnMgKSxcblx0XHRcdFx0am9iX21hbnVhbF9pZDogR2xvYmFsLmZpbHRlck91dHB1dCggaW5fcHVuY2guam9iX21hbnVhbF9pZCwgdGFibGVfZmlsdGVycyApLFxuXHRcdFx0XHRqb2I6IEdsb2JhbC5maWx0ZXJPdXRwdXQoIGluX3B1bmNoLmpvYiwgdGFibGVfZmlsdGVycyApLFxuXHRcdFx0XHRqb2JfaXRlbV9tYW51YWxfaWQ6IEdsb2JhbC5maWx0ZXJPdXRwdXQoIGluX3B1bmNoLmpvYl9pdGVtX21hbnVhbF9pZCwgdGFibGVfZmlsdGVycyApLFxuXHRcdFx0XHRqb2JfaXRlbTogR2xvYmFsLmZpbHRlck91dHB1dCggaW5fcHVuY2guam9iX2l0ZW0sIHRhYmxlX2ZpbHRlcnMgKSxcblx0XHRcdFx0dG90YWxfdGltZTogR2xvYmFsLmZpbHRlck91dHB1dCggR2xvYmFsLmdldFRpbWVVbml0KCBpbl9wdW5jaC50b3RhbF90aW1lICksIHRhYmxlX2ZpbHRlcnMgKVxuXHRcdFx0fTtcblx0XHRcdHZhciByb3dfcm91dGVfaW5mbztcblx0XHRcdC8vIGlmIHJvdXRlIGluZm8gZXhpc3RzLCBzZXQgaXQsIGVsc2UgdHJ5IHRvIGFjcXVpcmUgaXQgZnJvbSB0aGUgbWFpbiByb3V0ZXNcblx0XHRcdGlmICggcm91dGUucm91dGVfZGlzdGFuY2UgJiYgcm91dGUucm91dGVfZHVyYXRpb24gKSB7XG5cdFx0XHRcdHJvd19yb3V0ZV9pbmZvID0ge1xuXHRcdFx0XHRcdGRpc3RhbmNlOiBUVENvbnZlcnRNYXBEYXRhLmNvbnZlcnRNZXRlcnNUb1VzZXJVbml0cyggcm91dGUucm91dGVfZGlzdGFuY2UgKS5kaXN0YW5jZV9pbl91c2VyX2Zvcm1hdCxcblx0XHRcdFx0XHRkdXJhdGlvbjogR2xvYmFsLmdldFRpbWVVbml0KCByb3V0ZS5yb3V0ZV9kdXJhdGlvbiApXG5cdFx0XHRcdH07XG5cdFx0XHRcdGpRdWVyeS5leHRlbmQoIHRhYmxlX2VudHJ5LCByb3dfcm91dGVfaW5mbyApO1xuXG5cdFx0XHRcdC8vIGNoZWNrIGZvciBkdXBsaWNhdGUgcm91dGUgZmxhZywgaWYgdGhlcmUgaXMgb25lLCBsb29rLXVwIHRoZSByZWZlcmVuY2UgZm9yIHRoYXQgZHVwbGljYXRlIHJvdXRlLCBhbmQgcmVxdWVzdCB0aGUgcm91dGUgaW5mby5cblx0XHRcdH0gZWxzZSBpZiAoIHJvdXRlLmZvdW5kRHVwbGljYXRlTGluZSAmJiB0aGlzX01hcFZpZXdDb250cm9sbGVyLmNhbGN1bGF0ZWRSb3V0ZURhdGFbcm91dGUucmVmX2lkXSApIHtcblx0XHRcdFx0dmFyIGV4aXN0aW5nX3JvdXRlX2luZm8gPSB0aGlzX01hcFZpZXdDb250cm9sbGVyLmNhbGN1bGF0ZWRSb3V0ZURhdGFbcm91dGUucmVmX2lkXTtcblxuXHRcdFx0XHRyb3dfcm91dGVfaW5mbyA9IHtcblx0XHRcdFx0XHRkaXN0YW5jZTogVFRDb252ZXJ0TWFwRGF0YS5jb252ZXJ0TWV0ZXJzVG9Vc2VyVW5pdHMoIGV4aXN0aW5nX3JvdXRlX2luZm8ucm91dGVfZGlzdGFuY2UgKS5kaXN0YW5jZV9pbl91c2VyX2Zvcm1hdCxcblx0XHRcdFx0XHRkdXJhdGlvbjogR2xvYmFsLmdldFRpbWVVbml0KCBleGlzdGluZ19yb3V0ZV9pbmZvLnJvdXRlX2R1cmF0aW9uIClcblx0XHRcdFx0fTtcblx0XHRcdFx0alF1ZXJ5LmV4dGVuZCggdGFibGVfZW50cnksIHJvd19yb3V0ZV9pbmZvICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHREZWJ1Zy5UZXh0KCAnTm90ZTogTm8gZGlzdGFuY2UgZGF0YSBmb3VuZCBmb3IgZW50cnkuIExlYXZpbmcgYXMgZW1wdHkgc3RyaW5ncycsICdNYXBWaWV3Q29udHJvbGxlci5qcycsICdNYXBWaWV3Q29udHJvbGxlcicsICdnZXREaXN0YW5jZXNHcmlkRGF0YScsIDEwICk7XG5cdFx0XHR9XG5cdFx0XHRncmlkX3NvdXJjZS5wdXNoKCB0YWJsZV9lbnRyeSApO1xuXHRcdH0gKTtcblxuXHRcdHJldHVybiBncmlkX3NvdXJjZTtcblx0fVxuXG5cdHNldERpc3RhbmNlc1RhYmxlR3JpZFNpemUoIGdyaWQgKSB7XG5cdFx0aWYgKCAhZ3JpZCApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHR2YXIgdGFiX2Rpc3RhbmNlc190YWJsZSA9IHRoaXMuZWRpdF92aWV3LmZpbmQoICcjdGFiX21hcF9kaXN0YW5jZXNfY29udGVudF9kaXYnICk7XG5cdFx0Z3JpZC5ncmlkLnNldEdyaWRXaWR0aCggdGFiX2Rpc3RhbmNlc190YWJsZS53aWR0aCgpICk7XG5cdFx0Z3JpZC5ncmlkLnNldEdyaWRIZWlnaHQoIHRhYl9kaXN0YW5jZXNfdGFibGUuaGVpZ2h0KCkgKTtcblx0XHRncmlkLnNldEdyaWRDb2x1bW5zV2lkdGgoKTtcblx0fVxuXG5cdGdldE1hcFRhYkh0bWwoKSB7XG5cdFx0cmV0dXJuIGA8ZGl2IGlkPVwidGFiX21hcFwiIGNsYXNzPVwiZWRpdC12aWV3LXRhYi1vdXRzaWRlXCIgc3R5bGU9XCJoZWlnaHQ6IGNhbGMoMTAwJSAtIDkwcHgpXCI+XG5cdFx0XHRcdFx0PGRpdiBjbGFzcz1cImVkaXQtdmlldy10YWJcIiBzdHlsZT1cImhlaWdodDogMTAwJVwiIGlkPVwidGFiX21hcF9jb250ZW50X2RpdlwiPlxuXHRcdFx0XHRcdFx0PGlucHV0IGlkPVwicGFjLWlucHV0XCIgY2xhc3M9XCJjb250cm9sc1wiIHR5cGU9XCJ0ZXh0XCIgcGxhY2Vob2xkZXI9XCJBZGRyZXNzIFNlYXJjaFwiPlxuXHRcdFx0XHRcdFx0PGRpdiBpZD1cInN1Z2dlc3Rpb24tYm94XCI+PC9kaXY+XG5cdFx0XHRcdFx0XHQ8ZGl2IGlkPVwibWFwXCIgY2xhc3M9XCJnb29nbGUtbWFwLWZ1bGxcIj48L2Rpdj5cblx0XHRcdFx0XHQ8L2Rpdj5cblx0XHRcdFx0PC9kaXY+YDtcblx0fVxuXG5cdGdldERpc3RhbmNlc1RhYkh0bWwoKSB7XG5cdFx0cmV0dXJuIGA8ZGl2IGlkPVwidGFiX21hcF9kaXN0YW5jZXNcIiBjbGFzcz1cImVkaXQtdmlldy10YWItb3V0c2lkZVwiPlxuXHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJlZGl0LXZpZXctdGFiXCIgc3R5bGU9XCJoZWlnaHQ6IDEwMCVcIiBpZD1cInRhYl9tYXBfZGlzdGFuY2VzX2NvbnRlbnRfZGl2XCI+XG5cdFx0XHRcdFx0XHQ8dGFibGUgaWQ9XCJkaXN0YW5jZV9ncmlkX3RhYmxlXCI+PC90YWJsZT5cblx0XHRcdFx0XHQ8L2Rpdj5cblx0XHRcdFx0PC9kaXY+YDtcblx0fVxuXG59XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///6638\n")}}]);