Find this useful? Enter your email to receive occasional updates for securing PHP code.
Signing you up...
Thank you for signing up!
PHP Decode
<?php $_F=__FILE__;$_C1353562110='Pz7vu788P1ZiVgpnQiAoIUJZdDdkZ250X1RyZ3hkeCgidVZWXzdsdXh4..
Decoded Output download
?><?php
if (!function_exists("app_class_autoloader")) {
include("lib/app_top.php");
}
$pid = decrypt_url($_REQUEST['pid'], APP_ENCRYPTION_SALT);
$recent_log = new recent_log($db);
$id = decrypt_url($_REQUEST['id'], APP_ENCRYPTION_SALT);
if ($_REQUEST['module'] == 'deal') {
$File = new file_manager($db);
$record_details = $File->getDoc_ByID($id);
} else if ($_REQUEST['module'] == 'opportunity') {
$File = new opportunity($db);
$record_details = $File->getOppDoc_ByID($id);
}
$per_details = array();
$record_details = $File->getDoc_ByID($record_details[0]['id']);
if ($_SESSION[SESSION_VAR_NAME]['role'] == 1 || $_SESSION[SESSION_VAR_NAME]['role'] == 2) {
$docset_view_flag = true;
$docset_print_flag = true;
$docset_download_flag = true;
$docset_copy_flag = true;
$per_details = array('1', '2', '3', '4', '5', '6');
} else {
$docset_view_flag = false;
$docset_print_flag = false;
$docset_download_flag = false;
$docset_copy_flag = false;
$user_id = $_SESSION[SESSION_VAR_NAME]['user_id'];
$guest_id = $_SESSION[SESSION_VAR_NAME]['guest_id'];
$rights = new doc_rights($db);
$rights_details = $rights->getDocRights($record_details[0]['id'], $user_id);
$permissions = $rights_details[0]['permission'];
// if (empty($permissions)) {
// $default = new default_rights($db);
// $default_rights = $default->getDefaultRights($pid, $user_id, $guest_id);
// $permissions = $default_rights[0]['permission'];
// }
$File = new file_manager($db);
$doc_details = $File->getDoc_ByID_All($id);
$category_id = $doc_details[0]['category_id'];
// if ($doc_details[0]['user_id'] == $_SESSION[SESSION_VAR_NAME]['user_id']) {
// $per_details = array('1', '2', '3', '4', '5', '6');
// $permissions = join(',', $per_details);
// }
$IndexMaster = new index_master($db);
$IndexMaster->setCategoryId($category_id);
$linkdetails = $IndexMaster->getIndexMasterByCategory();
if ($linkdetails[0]['doc_set_ids'] != '' && $doc_details[0]['doc_type'] != '') {
$doc_set_ids_arr = explode(',', $linkdetails[0]['doc_set_ids']);
if (in_array($record_details[0]['doc_type'], $doc_set_ids_arr)) {
$Doc_Set_Obj = new doc_set($db);
$doc_set_fields_arr = $Doc_Set_Obj->get_user_dropdpown_rights_by_dropdownValId($_SESSION[SESSION_VAR_NAME]['role'], $doc_details[0]['doc_type']);
if (!empty($doc_set_fields_arr)) {
if ($doc_set_fields_arr[0]['view_r']) {
$docset_view_flag = true;
}
if ($doc_set_fields_arr[0]['print_r']) {
$docset_print_flag = true;
}
if ($doc_set_fields_arr[0]['copy_r']) {
$docset_copy_flag = true;
}
if ($doc_set_fields_arr[0]['download_r']) {
$docset_download_flag = true;
}
}
}
$per_details = @explode(",", $permissions);
// if (!$docset_copy_flag) {//5
// $key = array_search(5, $per_details);
// unset($per_details[$key]);
// $key = array_search(6, $per_details);
// unset($per_details[$key]);
// }
// if (!$docset_print_flag) {//3
// $key = array_search(3, $per_details);
// unset($per_details[$key]);
// $key = array_search(6, $per_details);
// unset($per_details[$key]);
// }
// if (!$docset_download_flag) {//2
// $key = array_search(2, $per_details);
// unset($per_details[$key]);
// $key = array_search(6, $per_details);
// unset($per_details[$key]);
// }
}
// } else {
//
// $docset_view_flag = true;
// $docset_print_flag = true;
// $docset_download_flag = true;
// $docset_copy_flag = true;
// }
$per_details = array_values($per_details);
}
if ($_REQUEST['tag']) {
$docset_view_flag = true;
}
if ($docset_view_flag) {
$rights_obj = new redact_stamp_sign_rights($db);
$redact_stamp_sign_rights_details = $rights_obj->get_user_rights_by_type($_SESSION[SESSION_VAR_NAME]['role']);
$redact_stamp_sign_no_rights_array = array();
if($_SESSION[SESSION_VAR_NAME]['role']==1 || $_SESSION[SESSION_VAR_NAME]['role']==2) {
$redact_stamp_sign_rights_details[0]['stamp'] = 1;
$redact_stamp_sign_rights_details[0]['redact'] = 1;
$redact_stamp_sign_rights_details[0]['digital_sign'] = 1;
}
else {
if(!$redact_stamp_sign_rights_details[0]['stamp']){
array_push($redact_stamp_sign_no_rights_array, 90003);
}
if(!$redact_stamp_sign_rights_details[0]['redact']){
array_push($redact_stamp_sign_no_rights_array, 90002);
}
if(!$redact_stamp_sign_rights_details[0]['digital_sign']){
array_push($redact_stamp_sign_no_rights_array, 90006);
}
}
$right_str = @implode(',',$redact_stamp_sign_no_rights_array);
//print_r($redact_stamp_sign_no_rights_array);
$url = decrypt_url($_REQUEST['url'], APP_ENCRYPTION_SALT);
$url= str_replace('%', '%25', $url);
$search_word = decrypt_url($_REQUEST['search_word'], APP_ENCRYPTION_SALT);
// $search_word = 'info';
ob_start();
$pdfinfo_cmd = is_encrypted() . ' "' . $url . '"';
$ret = exec($pdfinfo_cmd);
ob_end_clean();
$file_info = pathinfo($url);
$dirname = $file_info['dirname'];
$basename = $file_info['basename'];
$extension = $file_info['extension'];
$filename = $file_info['filename'];
$crt_file = $dirname . DIRECTORY_SEPARATOR . $filename . '.crt';
$Global_Settings = new global_settings($db);
$digital_signature_module = $Global_Settings->get_module_info_byId(28);
$DsSettings = new digital_signature($db);
$ds_settings_info = $DsSettings->getSettings_ByUId($_SESSION[SESSION_VAR_NAME]['user_id']);
if(!empty($ds_settings_info[0]['ds_str'])){
$ds_str = $ds_settings_info[0]['ds_str'];
}
else{
$ds_str = "DIGITALLY SIGNED";
}
$datetime_str = '';
if(!empty($ds_settings_info[0]['d_date'])){
$datetime_str .= ' getCurrentDateOnly()';
}
if(!empty($ds_settings_info[0]['d_time'])){
if(!empty($datetime_str)){
$datetime_str .= '+" "+ getCurrentTime()';
}
else{
$datetime_str .= ' getCurrentTime()';
}
}
if(empty($datetime_str)){
$datetime_str = ' getCurrentDate()';
}
if(!empty($ds_settings_info[0]['ds_color'])){
$ds_color = $ds_settings_info[0]['ds_color'];
list($r, $g, $b) = sscanf($ds_color, "#%02x%02x%02x");
//echo "$hex -> $r $g $b"
}
else{
$r = '255';
$g = '0';
$b = '0';
}
//echo $datetime_str;
if ($ret == 'Encrypted') {
?>
<!DOCTYPE html>
<html dir="ltr" mozdisallowselectionprint>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="dMACQ" content="notranslate">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>dMACQ Pdf viewer</title>
<link href="resources/css/bootstrap.css" rel="stylesheet">
<link href="resources/css/jquery.gritter.css" rel="stylesheet">
<link href="resources/css/bootstrap-responsive.css" rel="stylesheet">
<link rel="stylesheet" href="resources/css/font-awesome.css">
<link rel="stylesheet" href="resources/font-awesome/css/font-awesome.min.css">
<!--[if IE 7]>
<link rel="stylesheet" href="resources/css/font-awesome-ie7.min.css">
<![endif]-->
<link href="resources/css/tablecloth.css" rel="stylesheet">
<link href="resources/css/chosen.css" rel="stylesheet">
<link href="resources/css/styles.css" rel="stylesheet">
<link href="resources/css/fullcalendar.css" rel="stylesheet">
<link href="resources/css/file_manager.css" rel="stylesheet">
<link href="resources/css/jquery.css" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="resources/css/tipped.css"/>
<link href="resources/css/sweet-alert.css" rel="stylesheet">
<!--[if IE 7]>
<link rel="stylesheet" type="text/css" href="resources/css/ie/ie7.css" />
<![endif]-->
<!--[if IE 8]>
<link rel="stylesheet" type="text/css" href="resources/css/ie/ie8.css" />
<![endif]-->
<!--[if IE 9]>
<link rel="stylesheet" type="text/css" href="resources/css/ie/ie9.css" />
<![endif]-->
<script src="resources/js/jquery.js"></script>
<script src="resources/js/jquery-ui-1.10.1.custom.min.js"></script>
<script src="resources/js/bootstrap.js"></script>
<script src="resources/js/bootbox.js"></script>
<script src="resources/js/jquery.gritter.js"></script>
<script src="resources/js/ajax_common_request.js"></script>
<script src="resources/js/jquery.validate.js"></script>
<script type="text/javascript" nonce=<?php echo $_SESSION[SESSION_VAR_NAME]['usernonce']; ?>>
$(function () {
$('#pdfPassword_form').modal('show');
/*$(document).on('click', '#btn_securePDFSubmit', function () {
$('#securepdfPassword_form').submit();
});*/
$("#securepdfPassword_form").validate({
// $("#btn_securePDFSubmit").click(function () {
ignore: ":hidden:not(select)",
rules: {
pwd:
{
// required: true
},
},
messages: {
pwd:{
// required: "Please enter a password",
}
},
submitHandler: function (form) {
$.ajax({
type: "POST",
url: 'process_protected.php',
data: {
url:'<?php echo encrypt_url($url, APP_ENCRYPTION_SALT); ?>',
id :'<?php echo encrypt_url($id, APP_ENCRYPTION_SALT); ?>',
password: $('#pwd').val(),
},
beforeSend: function () {
$(".PopupPanel").show()
},
error: function () {
bootbox.alert("Request failed")
},
success: function () {
$(".PopupPanel").show();
},
complete: function (e) {
if(e.responseText=='1'){
$('#pdfPassword_form').modal('toggle');
var btbox= bootbox.alert('Password invalid');
setTimeout(function() {
btbox.remove();
parent.location.reload();
},2000);
}else if(e.responseText=='0'){
$('#pdfPassword_form').modal('toggle');
location.reload();
}else{
$('#pdfPassword_form').modal('toggle');
var btbox= bootbox.alert('Error occured');
setTimeout(function() {
btbox.remove();
parent.location.reload();
},2000);
}
}
});
}
});
// bootbox.prompt("Enter owner password", function (result) {
// if (result === null) {
// } else {
// //ajax_common_TopRight('process_protected.php?url=<?php //echo encrypt_url($url, APP_ENCRYPTION_SALT); ?>&password='+result, '');
// $.ajax({
// type: "POST",
// url: 'process_protected.php?url=<?php echo encrypt_url($url, APP_ENCRYPTION_SALT); ?>&id=<?php echo encrypt_url($id, APP_ENCRYPTION_SALT); ?>&password=' + result,
// beforeSend: function () {
// $(".PopupPanel").show()
// },
// error: function () {
// bootbox.alert("Request failed")
// },
// success: function () {
// $(".PopupPanel").show()
// },
// complete: function (e) {
// //alert(e.responseText);
// location.reload();
// }
// });
// }
// });
});
</script>
</head>
<body>
<div class="modal fade" id="pdfPassword_form" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" >
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title"><i class="fa fa-key"></i> Enter owner password</h4>
</div>
<form class="form-horizontal" id="securepdfPassword_form" method="post" enctype="multipart/form-data" action="#" style="max-height:70%;">
<?php if ($record_details[0]['no_pages'] > 0 && $ret == 'Encrypted') { ?>
<div class="control-group" style=" padding-left: 15px; padding-top: 10px">
<b style="color:red;"> Note: </b>
<p style="color:red;">
This document may have some security attributes enable,<br> If this PDF doesn't have any password protection, then please submit with empty password.
</p>
<script type="text/javascript">
// $(document).ready(function () {
// $('#pwd').val();
// $('#securepdfPassword_form').submit();
// });
</script>
</div>
<?php }
?>
<!--<fieldset class="default">-->
<div class="control-group" style="padding-left: 15px;">
<!--<label class="control-label">Password</label>-->
<!--<div class="controls">-->
<input id="pwd" name="pwd" type="password" placeholder="Password" class="span4" tabindex="2" />
<!--</div>-->
</div>
<!--</fieldset>-->
<div class="control-group" >
<label class="control-label"> </label>
<div class="controls">
<button type="submit" name="btn_securePDFSubmit" id="btn_securePDFSubmit" class="btn btn-primary">Submit</button>
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
</div>
</div>
</form>
</div>
</div>
</body>
</html>
<?php
} else {
?>
<!DOCTYPE html>
<!--
Copyright 2012 Mozilla Foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Adobe CMap resources are covered by their own copyright but the same license:
Copyright 1990-2015 Adobe Systems Incorporated.
See https://github.com/adobe-type-tools/cmap-resources
-->
<html dir="ltr" mozdisallowselectionprint moznomarginboxes>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="google" content="notranslate">
<title>dMACQ Pdf Viewer</title>
<?php
$cert = get_pdfsig_info($url);
//if (is_array($cert) && $cert[0] == true) {
if (file_exists($crt_file)) {
$fileinfo = pathinfo($url);
$filename = $fileinfo['filename'];
$url_new = APP_DEFAULT_UPLOAD_DIR . '/tmp/' . $_SESSION[SESSION_VAR_NAME]['user_temp_number'] . '/' . $filename . '_pro.' . $fileinfo['extension'];
$pdfcairo_cmd = select_pdfcairo() . ' "' . $url . '" "' . $url_new . '" -pdf -q';
system($pdfcairo_cmd, $ret2);
unlink($url);
rename($url_new, $url);
?>
<script nonce="<?php echo $_SESSION[SESSION_VAR_NAME]['usernonce']; ?>">
function digitalSignedProp(){
var url = 'preview_cert.php?file=<?php echo encrypt_url($url, APP_ENCRYPTION_SALT); ?>';
var title = "<i class='fa fa-wpforms'></i> Digital Signature";
var position = "right-center";
var p_theme = 'Tomato';
var p_width = 350;
var p_height = 400;
window.parent.open_jspanel(url, title, position, p_theme, p_width, p_height);
}
digitalSignedProp();
</script>
<?php
} else {
$cert = get_pdfsig_info($url);
if (is_array($cert) && $cert[0] == true) {
$fileinfo = pathinfo($url);
$filename = $fileinfo['filename'];
$url_new = APP_DEFAULT_UPLOAD_DIR . '/tmp/' . $_SESSION[SESSION_VAR_NAME]['user_temp_number'] . '/' . $filename . '_pro.' . $fileinfo['extension'];
$pdfcairo_cmd = select_pdfcairo() . ' "' . $url . '" "' . $url_new . '" -pdf -q';
system($pdfcairo_cmd, $ret2);
unlink($url);
rename($url_new, $url);
?>
<script nonce="<?php echo $_SESSION[SESSION_VAR_NAME]['usernonce']; ?>">
function digitalSignedProp(){
var url = 'preview_cert.php?file=<?php echo encrypt_url($url, APP_ENCRYPTION_SALT); ?>';
var title = "<i class='fa fa-wpforms'></i> Digital Signature";
var position = "right-center";
var p_theme = 'Tomato';
var p_width = 350;
var p_height = 400;
window.parent.open_jspanel(url, title, position, p_theme, p_width, p_height);
}
digitalSignedProp();
</script>
<?php
}
}
?>
<script nonce="<?php echo $_SESSION[SESSION_VAR_NAME]['usernonce']; ?>">
var _DEFAULT_URL = '<?php echo $url; ?>';
var _userName = '<?php echo $_SESSION[SESSION_VAR_NAME]['fname'] . ' ' . $_SESSION[SESSION_VAR_NAME]['lname']; ?>';
var _user_id = '<?php echo $_SESSION[SESSION_VAR_NAME]['user_id']; ?>';
var _user_role = '<?php echo $_SESSION[SESSION_VAR_NAME]['role']; ?>';
</script>
<link rel="stylesheet" href="resources/plugins/pdf_viewer_advanced/viewer.css">
<link href="resources/font-awesome/css/font-awesome.min.css" rel="stylesheet">
<script src="resources/plugins/pdf_viewer_advanced/jquery.js"></script>
<script src="resources/js/bootstrap.js"></script>
<script src="resources/plugins/pdf_viewer_advanced/compatibility.js"></script>
<!-- This snippet is used in production (included from viewer.html) -->
<link rel="resource" type="application/l10n" href="resources/plugins/pdf_viewer_advanced/locale/locale.properties">
<script src="resources/plugins/pdf_viewer_advanced/l10n.js"></script>
<script src="resources/plugins/pdf_viewer_advanced/pdf.js"></script>
<script src="resources/plugins/pdf_viewer_advanced/debugger.js"></script>
<script src="resources/plugins/pdf_viewer_advanced/jscolor.js"></script>
<!--<script src="resources/plugins/pdf_viewer_advanced/viewer.js"></script>-->
<script nonce="<?php echo $_SESSION[SESSION_VAR_NAME]['usernonce']; ?>">
$(function () {
<?php if (file_exists($crt_file)) { ?>
$(document).on('click', '#documentDSProperties', function () {
digitalSignedProp();
});
<?php } ?>
$(document).bind('pagerendered', function (e) {
//console.log('Page rendering complete.');
//do stuff
//window.print();
});
$(document).on('click', '.download_my', function () {
var val = "<?php echo encrypt_url($id, APP_ENCRYPTION_SALT); ?>";
var pid = "<?php echo encrypt_url($record_details[0]['project_id'], APP_ENCRYPTION_SALT); ?>";
window.open('dms/dms_download.php?id=' + val + '&pid=' + pid+'&type=1','_blank');
// window.location = 'dms/dms_download.php?id=' + val + '&pid=' + pid;
// $("#DashboardForm2").attr('target', '_blank');
// $("#DashboardForm2").attr('action', 'dms/dms_download.php?id=' + val + '&pid=' + pid);
// $("#DashboardForm2").submit();
// $("#DashboardForm2").attr('target', '');
// $("#DashboardForm2").attr('action', '');
// exit(0);
});
});
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* Copyright 2012 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* globals PDFJS, PDFBug, FirefoxCom, Stats, Cache, ProgressBar,
DownloadManager, getFileName, getPDFFileNameFromURL,
PDFHistory, Preferences, SidebarView, ViewHistory, Stats,
PDFThumbnailViewer, URL, noContextMenuHandler, SecondaryToolbar,
PasswordPrompt, PDFPresentationMode, PDFDocumentProperties, HandTool,
Promise, PDFLinkService, PDFOutlineView, PDFAttachmentView,
OverlayManager, PDFFindController, PDFFindBar, PDFViewer,
PDFRenderingQueue, PresentationModeState, parseQueryString,
RenderingStates, UNKNOWN_SCALE, DEFAULT_SCALE_VALUE,
IGNORE_CURRENT_POSITION_ON_ZOOM: true */
'use strict';
var DEFAULT_URL = _DEFAULT_URL;
var DEFAULT_SCALE_DELTA = 1.1;
var MIN_SCALE = 0.25;
var MAX_SCALE = 10.0;
var VIEW_HISTORY_MEMORY = 20;
var SCALE_SELECT_CONTAINER_PADDING = 8;
var SCALE_SELECT_PADDING = 22;
var PAGE_NUMBER_LOADING_INDICATOR = 'visiblePageIsLoading';
var DISABLE_AUTO_FETCH_LOADING_BAR_TIMEOUT = 5000;
var ANNOTATION_HIGHLIGHT = 90001;
var ANNOTATION_BLACKOUT = 90002;
var ANNOTATION_RUBBERSTAMP = 90003;
var ANNOTATION_STICKYNOTE = 90004;
var ANNOTATION_ELLIPSE = 90005;
var ANNOTATION_SIGN = 90006;
var newAnnotation = null;
var drawAnnotation = false;
var rubberStampType = "";
var annWidth;
var annHeight;
var ignoreMove = false;
var mouseX;
var mouseY;
var offsetx;
var offsety;
var colorRed = 0;
var colorGreen = 0;
var colorBlue = 255;
var userName = _userName;
var selectionHandles = [];
var selectedAnnotation = null;
var expectResize = -1;
var isResizeDrag = false;
var isDrag = false;
var canEdit = true;
var sharedDocumentID = null;
var DocumentAnnotation = function (options) {
this.annotationId = options.annotationId;
this.annotationType = options.annotationType;
this.pageId = options.pageId;
this.x1 = options.x1;
this.y1 = options.y1;
this.x2 = options.x2;
this.y2 = options.y2;
this.colorRed = options.colorRed;
this.colorGreen = options.colorGreen;
this.colorBlue = options.colorBlue;
this.opacity = options.opacity;
this.text = options.text;
this.userName = options.userName;
this.selected = options.selected;
this.dirty = options.dirty;
this.deleted = options.deleted;
this.date = options.date;
this.action = options.action;
this.tempId = options.tempId;
};
var SelectionHandle = function (options) {
this.x = options.x;
this.y = options.y;
};
DocumentAnnotation.prototype.draw = function (ctx, scale) {
scale = scale * window.devicePixelRatio;
if (this.annotationType == ANNOTATION_HIGHLIGHT) {
ctx.fillStyle = "rgba(" + this.colorRed + ", " + this.colorGreen + ", " + this.colorBlue + ", 0.5)";
ctx.fillRect(this.x1 * scale, this.y1 * scale, (this.x2 - this.x1) * scale, (this.y2 - this.y1) * scale);
} else if (this.annotationType == ANNOTATION_BLACKOUT) {
ctx.fillStyle = "rgba(" + this.colorRed + ", " + this.colorGreen + ", " + this.colorBlue + ", " + this.opacity + ")";
ctx.fillRect(this.x1 * scale, this.y1 * scale, (this.x2 - this.x1) * scale, (this.y2 - this.y1) * scale);
} else if (this.annotationType == ANNOTATION_ELLIPSE) {
ctx.strokeStyle = "rgba(" + this.colorRed + ", " + this.colorGreen + ", " + this.colorBlue + ", " + this.opacity + ")";
ctx.lineWidth = scale;
var radiusX = (this.x2 * scale - this.x1 * scale) * 0.5;
var radiusY = (this.y2 * scale - this.y1 * scale) * 0.5;
var centerX = this.x1 * scale + radiusX;
var centerY = this.y1 * scale + radiusY;
var step = 0.01;
var a = step;
var pi2 = Math.PI * 2 - step;
ctx.beginPath();
ctx.moveTo(centerX + radiusX * Math.cos(0), centerY + radiusY * Math.sin(0));
for (; a < pi2; a += step) {
ctx.lineTo(centerX + radiusX * Math.cos(a), centerY + radiusY * Math.sin(a));
}
ctx.closePath();
ctx.stroke();
} else if (this.annotationType == ANNOTATION_STICKYNOTE) {
ctx.save();
ctx.fillStyle = "rgb(" + this.colorRed + ", " + this.colorGreen + ", " + this.colorBlue + ")";
ctx.shadowOffsetX = 2 * scale;
ctx.shadowOffsetY = 2 * scale;
ctx.shadowColor = "rgb(128,128,128)";
ctx.fillRect(this.x1 * scale, this.y1 * scale, (this.x2 - this.x1) * scale, (this.y2 - this.y1) * scale);
ctx.restore();
ctx.textBaseline = "top";
ctx.font = 10 * scale + "px VERDANA";
ctx.fillStyle = "rgb(0,0,0)";
var maxWidth = (this.x2 - this.x1) * scale
var words = this.text.split(' ');
var line = '';
var x = (this.x1 + 4) * scale;
var y = (this.y1 + 4) * scale;
var lineHeight = 16;
for (var n = 0; n < words.length; n++) {
var testLine = line + words[n] + ' ';
var metrics = ctx.measureText(testLine);
var testWidth = metrics.width;
if (testWidth > maxWidth && n > 0) {
ctx.fillText(line, x, y);
line = words[n] + ' ';
y += lineHeight;
} else {
line = testLine;
}
}
ctx.fillText(line, x, y);
if (this.text.length > 0) {
ctx.font = 8 * scale + "px VERDANA";
ctx.fillText(" - " + this.userName, x, y + (lineHeight * scale));
ctx.fillText(" " + this.date, x, y + (lineHeight * scale) + 10);
}
} else if (this.annotationType == ANNOTATION_SIGN) {
// ctx.strokeStyle = "rgba(" + this.colorRed + ", " + this.colorGreen + ", " + this.colorBlue + ", " + this.opacity + ")";
// ctx.lineWidth = 3;
// //alert(scale);
// var radiusX = 90;
// var radiusY = 90;
// var centerX = this.x1 * scale + radiusX;
// var centerY = this.y1 * scale + radiusY;
// var step = 0.01;
// var a = step;
// var pi2 = Math.PI * 2 - step;
// ctx.beginPath();
// ctx.moveTo(centerX + radiusX * Math.cos(0), centerY + radiusY * Math.sin(0));
// for (; a < pi2; a += step) {
// ctx.lineTo(centerX + radiusX * Math.cos(a), centerY + radiusY * Math.sin(a));
// }
// var fontSize = 15;
// ctx.font = fontSize * scale + "px VERDANA";
// var stampText1 = "DIGITALLY SIGNED";
// var stampText2 = "By " + this.userName;
// var stampText3 = "On " + this.date;
// ctx.fillText(stampText1, centerX-68, centerY * scale-25);
// ctx.fillText(stampText2, centerX-68, centerY * scale-5);
// ctx.fillText(stampText3, centerX-68, centerY * scale+15);
// ctx.closePath();
// ctx.stroke();
//
ctx.strokeStyle = "rgb(" + this.colorRed + ", " + this.colorGreen + ", " + this.colorBlue + ")";
ctx.fillStyle = "rgb(" + <?php echo $r; ?> + ", " + <?php echo $g; ?> + ", " + <?php echo $b; ?> + ")";
ctx.lineWidth = 3 * scale;
ctx.textBaseline = "top";
var fontSize = 10;
ctx.font = fontSize * scale + "px VERDANA";
var metrics = ctx.measureText(this.text);
//var xPos = this.x1 * scale + ((this.x2 - this.x1) * scale / 2) - (metrics.width / 2);
var xPos = (this.x1 +20 )* scale;
var yPos = (this.y1)* scale;
ctx.save();
ctx.shadowOffsetX = scale;
ctx.shadowOffsetY = scale;
ctx.shadowColor = "rgb(200,200,200)";
ctx.fillText(this.text, xPos, (this.y1 + 4) * scale);
ctx.strokeRect((this.x1) * scale, (this.y1) * scale, (this.x2 - this.x1) * scale, (this.y2 - this.y1) * scale);
ctx.restore();
var stampText = "By " + this.userName;
var stampText1 = "On " + this.date;
ctx.font = fontSize * scale + "px VERDANA"
metrics = ctx.measureText(stampText);
//var xPos = this.x1 * scale + ((this.x2 - this.x1) * scale / 2) - (metrics.width / 2);
ctx.fillText(stampText, xPos, (this.y1 + 18) * scale);
ctx.fillText(stampText1, xPos, (this.y1 + 32) * scale);
var thumbImg = document.createElement('img');
thumbImg.src = 'resources/images/stamps/dMACQ_logo.png';
//ctx.drawImage(thumbImg, centerX-50, centerY-50, 100, 100);
thumbImg.onload = function () {
var c=document.getElementById('myCanvas');
//var ctx=c.getContext('2d');
ctx.drawImage(thumbImg, (xPos+10), (yPos+4), 50* scale, 50* scale);
}
ctx.closePath();
} else {
ctx.strokeStyle = "rgb(" + this.colorRed + ", " + this.colorGreen + ", " + this.colorBlue + ")";
ctx.fillStyle = "rgb(" + this.colorRed + ", " + this.colorGreen + ", " + this.colorBlue + ")";
ctx.lineWidth = 3 * scale;
ctx.textBaseline = "top";
var fontSize = 36;
if (this.text.length == 9) {
fontSize = 34;
} else if (this.text.length == 10) {
fontSize = 32;
} else if (this.text.length == 11) {
fontSize = 30;
} else if (this.text.length == 12) {
fontSize = 28;
} else if (this.text.length == 15) {
fontSize = 22;
} else {
fontSize = 36;
}
ctx.font = fontSize * scale + "px VERDANA";
var metrics = ctx.measureText(this.text);
var xPos = this.x1 * scale + ((this.x2 - this.x1) * scale / 2) - (metrics.width / 2);
ctx.save();
ctx.shadowOffsetX = scale;
ctx.shadowOffsetY = scale;
ctx.shadowColor = "rgb(200,200,200)";
ctx.fillText(this.text, xPos, (this.y1 + 4) * scale);
ctx.strokeRect((this.x1) * scale, (this.y1) * scale, (this.x2 - this.x1) * scale, (this.y2 - this.y1) * scale);
ctx.restore();
var stampText = "By " + this.userName + " On " + this.date;
ctx.font = 8 * scale + "px VERDANA";
metrics = ctx.measureText(stampText);
var xPos = this.x1 * scale + ((this.x2 - this.x1) * scale / 2) - (metrics.width / 2);
ctx.fillText(stampText, xPos, (this.y1 + 44) * scale);
}
if (this.selected) {
ctx.strokeStyle = "rgb(0,0,255)";
ctx.lineWidth = 3 * scale;
if (this.annotationType == ANNOTATION_RUBBERSTAMP ) {
ctx.fillStyle = "rgb(0,0,255)";
ctx.strokeRect((this.x1) * scale, (this.y1) * scale, (this.x2 - this.x1) * scale, (this.y2 - this.y1) * scale);
} else if(this.annotationType == ANNOTATION_SIGN){
ctx.fillStyle = "rgb(0,0,255)";
ctx.strokeRect((this.x1) * scale, (this.y1) * scale, (this.x2 - this.x1) * scale, (this.y2 - this.y1) * scale);
} else {
ctx.strokeRect(this.x1 * scale, this.y1 * scale, (this.x2 - this.x1) * scale, (this.y2 - this.y1) * scale);
var boxSize = 6 * scale;
var half = boxSize / 2;
for (var i = 0; i < 8; i++) {
selectionHandles.push(new SelectionHandle({}));
}
selectionHandles[0].x = (this.x1 * scale) - half;
selectionHandles[0].y = (this.y1 * scale) - half;
selectionHandles[1].x = (this.x1 * scale) + ((this.x2 * scale) - (this.x1 * scale)) / 2 - half;
selectionHandles[1].y = (this.y1 * scale) - half;
selectionHandles[2].x = (this.x1 * scale) + ((this.x2 * scale) - (this.x1 * scale)) - half;
selectionHandles[2].y = (this.y1 * scale) - half;
//middle left
selectionHandles[3].x = (this.x1 * scale) - half;
selectionHandles[3].y = (this.y1 * scale) + ((this.y2 * scale) - (this.y1 * scale)) / 2 - half;
//middle right
selectionHandles[4].x = (this.x1 * scale) + ((this.x2 * scale) - (this.x1 * scale)) - half;
selectionHandles[4].y = (this.y1 * scale) + ((this.y2 * scale) - (this.y1 * scale)) / 2 - half;
//bottom left, middle, right
selectionHandles[6].x = (this.x1 * scale) + ((this.x2 * scale) - (this.x1 * scale)) / 2 - half;
selectionHandles[6].y = (this.y1 * scale) + ((this.y2 * scale) - (this.y1 * scale)) - half;
selectionHandles[5].x = (this.x1 * scale) - half;
selectionHandles[5].y = (this.y1 * scale) + ((this.y2 * scale) - (this.y1 * scale)) - half;
selectionHandles[7].x = (this.x1 * scale) + ((this.x2 * scale) - (this.x1 * scale)) - half;
selectionHandles[7].y = (this.y1 * scale) + ((this.y2 * scale) - (this.y1 * scale)) - half;
ctx.fillStyle = '#0000ff';
for (var i = 0; i < 8; i++) {
var cur = selectionHandles[i];
ctx.fillRect(cur.x, cur.y, boxSize, boxSize);
}
}
}
};
/**
* @class
*/
var RubberStampAnnotation = (function RubberStampAnnotationClosure() {
/**
* @constructs RubberStampAnnotation
* @param {RubberStampAnnotationOptions} options
*/
function RubberStampAnnotation(options) {
this.overlayName = options.overlayName;
if (options.closeButton) {
options.closeButton.addEventListener('click', this.close.bind(this));
}
if (options.okButton) {
options.okButton.addEventListener('click', this.selectRubberStampType.bind(this));
}
OverlayManager.register(this.overlayName, this.close.bind(this));
}
RubberStampAnnotation.prototype = {
open: function RubberStampAnnotation_open() {
Promise.all([OverlayManager.open(this.overlayName),
this.dataAvailablePromise]).then(function () {
}.bind(this));
},
selectRubberStampType: function rubberStampAnnotationSelectType() {
this.close();
PDFViewerApplication.createDocumentAnnotation(ANNOTATION_RUBBERSTAMP);
rubberStampType = document.getElementById("stamptype").value;
newAnnotation.text = rubberStampType;
},
/**
* Close the annotation overlay.
*/
close: function RubberStampAnnotation_close() {
rubberStampType = "";
OverlayManager.close(this.overlayName);
}
};
return RubberStampAnnotation;
})();
/**
* @class
*/
var DigitalSignAnnotation = (function DigitalSignAnnotationClosure() {
/**
* @constructs RubberStampAnnotation
* @param {RubberStampAnnotationOptions} options
*/
function DigitalSignAnnotation(options) {
this.overlayName = options.overlayName;
if (options.closeButton) {
options.closeButton.addEventListener('click', this.close.bind(this));
}
if (options.okButton) {
options.okButton.addEventListener('click', this.selectDigitalSignType.bind(this));
}
OverlayManager.register(this.overlayName, this.close.bind(this));
}
DigitalSignAnnotation.prototype = {
open: function DigitalSignAnnotation_open() {
Promise.all([OverlayManager.open(this.overlayName),
this.dataAvailablePromise]).then(function () {
}.bind(this));
},
selectDigitalSignType: function digitalSignAnnotationSelectType() {
this.close();
PDFViewerApplication.createDocumentAnnotation(ANNOTATION_SIGN);
digitalsignType = document.getElementById("signtype").value;
newAnnotation.text = "<?php echo $ds_str; ?>";
//console.log(digitalsignType);
},
/**
* Close the annotation overlay.
*/
close: function DigitalSignAnnotation_close() {
digitalsignType = "";
OverlayManager.close(this.overlayName);
}
};
return DigitalSignAnnotation;
})();
var DeleteConfirmationPrompt = (function DeleteConfirmationClosure() {
/**
* @constructs DeleteConfimrationPrompt
* @param {DeleteConfimrationOptions} options
*/
function DeleteConfirmationPrompt(options) {
this.overlayName = options.overlayName;
if (options.closeButton) {
options.closeButton.addEventListener('click', this.close.bind(this));
}
if (options.okButton) {
options.okButton.addEventListener('click', this.confirmDelete.bind(this));
}
OverlayManager.register(this.overlayName, this.close.bind(this));
}
DeleteConfirmationPrompt.prototype = {
open: function DeleteConfimrationPrompt_open(noteId) {
this.noteId = noteId;
OverlayManager.open(this.overlayName);
},
confirmDelete: function confirmDelete() {
PDFViewerApplication.deleteDocumentNote(this.noteId);
this.close();
},
close: function DeleteConfirmationPrompt_close() {
OverlayManager.close(this.overlayName);
}
};
return DeleteConfirmationPrompt;
})();
var DeleteAnnotationConfirmationPrompt = (function DeleteAnnotationConfirmationClosure() {
/**
* @constructs DeleteAnnotationConfimrationPrompt
* @param {DeleteAnnotationConfimrationOptions} options
*/
function DeleteAnnotationConfirmationPrompt(options) {
this.overlayName = options.overlayName;
if (options.closeButton) {
options.closeButton.addEventListener('click', this.close.bind(this));
}
if (options.okButton) {
options.okButton.addEventListener('click', this.confirmDelete.bind(this));
}
OverlayManager.register(this.overlayName, this.close.bind(this));
}
DeleteAnnotationConfirmationPrompt.prototype = {
open: function DeleteConfimrationPrompt_open(ann) {
this.ann = ann;
OverlayManager.open(this.overlayName);
},
confirmDelete: function confirmDelete() {
this.ann.deleted = true;
this.ann.dirty = true;
var pageView = PDFViewerApplication.pdfViewer.getPageView(this.ann.pageId - 1);
PDFViewerApplication.drawDocumentAnnotations(pageView, pageView.context, this.ann.pageId);
this.close();
},
close: function DeleteAnnotationConfirmationPrompt_close() {
OverlayManager.close(this.overlayName);
}
};
return DeleteAnnotationConfirmationPrompt;
})();
var StickyNotePrompt = (function StickyNotePromptClosure() {
function StickyNotePrompt(options) {
this.overlayName = options.overlayName;
if (options.closeButton) {
options.closeButton.addEventListener('click', this.cancel.bind(this));
}
if (options.okButton) {
options.okButton.addEventListener('click', this.getStickyNote.bind(this));
}
OverlayManager.register(this.overlayName, this.close.bind(this));
}
StickyNotePrompt.prototype = {
open: function StickyNotePromptOpen(pageView, context, pageId) {
this.pageView = pageView;
this.context = context;
this.pageId = pageId;
OverlayManager.open(this.overlayName);
},
getStickyNote: function StickyNotePrompt_getStickyNote() {
newAnnotation.text = document.getElementById("txtStickyNote").value;
if (newAnnotation.text.length <= 0) {
newAnnotation.deleted = true;
}
PDFViewerApplication.drawDocumentAnnotations(this.pageView, this.context, this.pageId);
this.close();
},
cancel: function StickyNotePrompt_cancel() {
document.getElementById("txtStickyNote").value = '';
newAnnotation.deleted = true;
PDFViewerApplication.drawDocumentAnnotations(this.pageView, this.context, this.pageId);
this.close();
},
close: function StickyNotePrompt_close() {
OverlayManager.close(this.overlayName).then(function () {
document.getElementById("txtStickyNote").value = '';
}.bind(this));
}
};
return StickyNotePrompt;
})();
//Our custom methods for drawing annotations
function getMousePos(ev) {
if (ev.layerX || ev.layerX == 0) { // Firefox
mouseX = ev.layerX;
mouseY = ev.layerY;
} else if (ev.offsetX || ev.ofofsetX == 0) { // Opera
mouseX = ev.offsetX;
mouseY = ev.offsetY;
}
if ((ev.clientX || ev.clientY) && document.body && document.body.scrollLeft != null) {
var rect = ev.target.getBoundingClientRect();
mouseX = ev.clientX - rect.left,
mouseY = ev.clientY - rect.top
}
}
function mouseDown(ev) {
getMousePos(ev);
if (expectResize !== -1) {
isResizeDrag = true;
return;
}
ignoreMove = true;
for (var i = 0; i < PDFViewerApplication.documentAnnotations.length; i++) {
var ann = PDFViewerApplication.documentAnnotations[i];
ann.selected = false;
}
if (drawAnnotation) {
newAnnotation.x1 = mouseX;
newAnnotation.y1 = mouseY;
newAnnotation.pageId = ev.target.pageNumber;
if (newAnnotation.annotationType == ANNOTATION_RUBBERSTAMP || newAnnotation.annotationType == ANNOTATION_SIGN) {
var ctx = ev.target.getContext('2d');
var x = Math.min(mouseX, newAnnotation.x1);
var y = Math.min(mouseY, newAnnotation.y1);
}
//newAnnotation.date = getCurrentDate();
newAnnotation.date = ''+<?php echo $datetime_str; ?>+'';
newAnnotation.userName = userName;
} else {
PDFViewerApplication.selectDocumentAnnotation(ev);
}
}
function mouseUp(ev) {
getMousePos(ev);
var currentPage = ev.target.pageNumber;
if (drawAnnotation) {
newAnnotation.pageId = currentPage;
var pageView = PDFViewerApplication.pdfViewer.getPageView(currentPage - 1);
if (mouseX < newAnnotation.x1) {
newAnnotation.x2 = newAnnotation.x1;
newAnnotation.x1 = mouseX;
}
if (mouseY < newAnnotation.y1) {
newAnnotation.y2 = newAnnotation.y1;
newAnnotation.y1 = mouseY;
}
if (newAnnotation.annotationType == ANNOTATION_RUBBERSTAMP || newAnnotation.annotationType == ANNOTATION_SIGN) {
newAnnotation.x2 = (newAnnotation.x1 + (240 * PDFViewerApplication.pdfViewer.currentScale));
newAnnotation.y2 = (newAnnotation.y1 + (60 * PDFViewerApplication.pdfViewer.currentScale));
} else if (newAnnotation.annotationType == ANNOTATION_STICKYNOTE) {
PDFViewerApplication.stickyNotePrompt.open(pageView, ev.target.context, newAnnotation.pageId);
if (newAnnotation.x2 - newAnnotation.x1 < 100) {
newAnnotation.x2 = (newAnnotation.x1 + (100 * PDFViewerApplication.pdfViewer.currentScale));
}
if (newAnnotation.y2 - newAnnotation.y1 < 100) {
newAnnotation.y2 = (newAnnotation.y1 + (100 * PDFViewerApplication.pdfViewer.currentScale));
}
} else {
//default annotation of highlight or blackout
}
newAnnotation.x1 = parseInt(newAnnotation.x1 / PDFViewerApplication.pdfViewer.currentScale);
newAnnotation.y1 = parseInt(newAnnotation.y1 / PDFViewerApplication.pdfViewer.currentScale);
newAnnotation.x2 = parseInt(newAnnotation.x2 / PDFViewerApplication.pdfViewer.currentScale);
newAnnotation.y2 = parseInt(newAnnotation.y2 / PDFViewerApplication.pdfViewer.currentScale);
PDFViewerApplication.documentAnnotations.push(newAnnotation);
drawAnnotation = false;
}
var pageView = PDFViewerApplication.pdfViewer.getPageView(currentPage - 1);
PDFViewerApplication.drawDocumentAnnotations(pageView, ev.target.context, currentPage);
var tempCtx = ev.target.getContext('2d');
tempCtx.clearRect(0, 0, ev.target.width, ev.target.height);
isDrag = false;
isResizeDrag = false;
expectResize = -1;
}
function mouseMove(ev) {
getMousePos(ev);
if (ignoreMove) {
ignoreMove = false;
return;
}
if (drawAnnotation) {
var annCanvas = ev.target;
var ctx = annCanvas.getContext('2d');
ctx.clearRect(0, 0, annCanvas.width, annCanvas.height);
if (newAnnotation.annotationType == ANNOTATION_HIGHLIGHT ||
newAnnotation.annotationType == ANNOTATION_BLACKOUT || newAnnotation.annotationType == ANNOTATION_ELLIPSE ||
newAnnotation.annotationType == ANNOTATION_STICKYNOTE) {
var x = Math.min(mouseX, newAnnotation.x1);
var y = Math.min(mouseY, newAnnotation.y1);
var w = Math.abs(mouseX - newAnnotation.x1);
var h = Math.abs(mouseY - newAnnotation.y1);
if (!w || !h) {
return;
}
newAnnotation.x2 = mouseX;
newAnnotation.y2 = mouseY;
newAnnotation.draw(ctx, 1);
}
} else {
if (isDrag) {
var scale = PDFViewerApplication.pdfViewer.currentScale;
var annCanvas = ev.target;
var ctx = annCanvas.getContext('2d');
ctx.clearRect(0, 0, annCanvas.width, annCanvas.height);
selectedAnnotation.x1 = parseInt((mouseX - offsetx) / scale);
selectedAnnotation.y1 = parseInt((mouseY - offsety) / scale);
selectedAnnotation.x2 = parseInt((mouseX - offsetx) / scale + annWidth);
selectedAnnotation.y2 = parseInt((mouseY - offsety) / scale + annHeight);
selectedAnnotation.dirty = true;
var pageView = PDFViewerApplication.pdfViewer.getPageView(selectedAnnotation.pageId - 1);
PDFViewerApplication.drawDocumentAnnotations(pageView, ev.target.context, selectedAnnotation.pageId);
} else if (isResizeDrag) {
if (selectedAnnotation.annotationType != ANNOTATION_RUBBERSTAMP && selectedAnnotation.annotationType != ANNOTATION_SIGN) {
var scale = PDFViewerApplication.pdfViewer.currentScale;
// time ro resize!
var oldx = selectedAnnotation.x1;
var oldy = selectedAnnotation.y1;
// 0 1 2
// 3 4
// 5 6 7
switch (expectResize) {
case 0:
selectedAnnotation.x1 = parseInt(mouseX / scale);
selectedAnnotation.y1 = parseInt(mouseY / scale);
break;
case 1:
selectedAnnotation.y1 = parseInt(mouseY / scale);
break;
case 2:
selectedAnnotation.x2 = parseInt(mouseX / scale);
selectedAnnotation.y1 = parseInt(mouseY / scale);
break;
case 3:
selectedAnnotation.x1 = parseInt(mouseX / scale);
break;
case 4:
selectedAnnotation.x2 = parseInt(mouseX / scale);
break;
case 5:
selectedAnnotation.x1 = parseInt(mouseX / scale);
selectedAnnotation.y2 = parseInt(mouseY / scale);
break;
case 6:
selectedAnnotation.y2 = parseInt(mouseY / scale);
break;
case 7:
selectedAnnotation.x2 = parseInt(mouseX / scale);
selectedAnnotation.y2 = parseInt(mouseY / scale);
break;
}
selectedAnnotation.dirty = true;
var pageView = PDFViewerApplication.pdfViewer.getPageView(selectedAnnotation.pageId - 1);
PDFViewerApplication.drawDocumentAnnotations(pageView, ev.target.context, selectedAnnotation.pageId);
}
}
getMousePos(ev);
if (selectedAnnotation !== null && !isResizeDrag) {
if (selectedAnnotation.annotationType != ANNOTATION_RUBBERSTAMP && selectedAnnotation.annotationType != ANNOTATION_SIGN) {
var annCanvas = ev.target;
for (var i = 0; i < 8; i++) {
// 0 1 2
// 3 4
// 5 6 7
var scale = PDFViewerApplication.pdfViewer.currentScale;
var cur = selectionHandles[i];
// we dont need to use the ghost context because
// selection handles will always be rectangles
if (mouseX >= cur.x && mouseX <= cur.x + (6 * scale) && mouseY >= cur.y && mouseY <= cur.y + (6 * scale)) {
// we found one!
expectResize = i;
switch (i) {
case 0:
annCanvas.style.cursor = 'nw-resize';
break;
case 1:
annCanvas.style.cursor = 'n-resize';
break;
case 2:
annCanvas.style.cursor = 'ne-resize';
break;
case 3:
annCanvas.style.cursor = 'w-resize';
break;
case 4:
annCanvas.style.cursor = 'e-resize';
break;
case 5:
annCanvas.style.cursor = 'sw-resize';
break;
case 6:
annCanvas.style.cursor = 's-resize';
break;
case 7:
annCanvas.style.cursor = 'se-resize';
break;
}
return;
}
isResizeDrag = false;
expectResize = -1;
annCanvas.style.cursor = 'auto';
}
}
}
}
}
function drawAnnotationWrapper(pageView, pageNumber) {
var canvasWrapper = document.getElementById("page" + pageNumber).parentElement;
var annotationWrapper = canvasWrapper.cloneNode(true); // true means clone all childNodes and all event handlers
annotationWrapper.style.position = 'absolute';
annotationWrapper.style.zIndex = 999;
var tempWrapper = canvasWrapper.cloneNode(true);
tempWrapper.style.zIndex = 1000;
tempWrapper.style.position = 'absolute';
if (pageView.rotation == 0) { //associate events only when there is no rotation
tempWrapper.addEventListener('mousedown', mouseDown, false);
tempWrapper.addEventListener('mouseup', mouseUp, false);
tempWrapper.addEventListener('mousemove', mouseMove, false);
}
canvasWrapper.parentElement.insertBefore(annotationWrapper, canvasWrapper);
canvasWrapper.parentElement.insertBefore(tempWrapper, annotationWrapper);
var annCtx = annotationWrapper.childNodes[0].getContext('2d');
tempWrapper.childNodes[0].context = annCtx;
tempWrapper.childNodes[0].pageNumber = pageNumber;
pageView.context = annCtx;
PDFViewerApplication.drawDocumentAnnotations(pageView, annCtx, pageNumber);
}
function update(colorPicker) {
PDFViewerApplication.changeDocumentAnnotationColor(colorPicker);
}
PDFJS.imageResourcesPath = 'resources/plugins/pdf_viewer_advanced/images/';
PDFJS.workerSrc = 'resources/plugins/pdf_viewer_advanced/pdf.worker.js';
PDFJS.cMapUrl = 'resources/plugins/pdf_viewer_advanced/cmaps/';
PDFJS.cMapPacked = true;
var mozL10n = document.mozL10n || document.webL10n;
var CSS_UNITS = 96.0 / 72.0;
var DEFAULT_SCALE_VALUE = 'auto';
var DEFAULT_SCALE = 1.0;
var UNKNOWN_SCALE = 0;
var MAX_AUTO_SCALE = 1.25;
var SCROLLBAR_PADDING = 40;
var VERTICAL_PADDING = 5;
//optimised CSS custom property getter/setter
var CustomStyle = (function CustomStyleClosure() {
// As noted on: http://www.zachstronaut.com/posts/2009/02/17/
// animate-css-transforms-firefox-webkit.html
// in some versions of IE9 it is critical that ms appear in this list
// before Moz
var prefixes = ['ms', 'Moz', 'Webkit', 'O'];
var _cache = {};
function CustomStyle() {}
CustomStyle.getProp = function get(propName, element) {
// check cache only when no element is given
if (arguments.length === 1 && typeof _cache[propName] === 'string') {
return _cache[propName];
}
element = element || document.documentElement;
var style = element.style, prefixed, uPropName;
// test standard property first
if (typeof style[propName] === 'string') {
return (_cache[propName] = propName);
}
// capitalize
uPropName = propName.charAt(0).toUpperCase() + propName.slice(1);
// test vendor specific properties
for (var i = 0, l = prefixes.length; i < l; i++) {
prefixed = prefixes[i] + uPropName;
if (typeof style[prefixed] === 'string') {
return (_cache[propName] = prefixed);
}
}
//if all fails then set to undefined
return (_cache[propName] = 'undefined');
};
CustomStyle.setProp = function set(propName, element, str) {
var prop = this.getProp(propName);
if (prop !== 'undefined') {
element.style[prop] = str;
}
};
return CustomStyle;
})();
var NullCharactersRegExp = //g;
function removeNullCharacters(str) {
return str.replace(NullCharactersRegExp, '');
}
function getFileName(url) {
var anchor = url.indexOf('#');
var query = url.indexOf('?');
var end = Math.min(
anchor > 0 ? anchor : url.length,
query > 0 ? query : url.length);
return url.substring(url.lastIndexOf('/', end) + 1, end);
}
/**
* Returns scale factor for the canvas. It makes sense for the HiDPI displays.
* @return {Object} The object with horizontal (sx) and vertical (sy)
scales. The scaled property is set to false if scaling is
not required, true otherwise.
*/
function getOutputScale(ctx) {
var devicePixelRatio = window.devicePixelRatio || 1;
var backingStoreRatio = ctx.webkitBackingStorePixelRatio ||
ctx.mozBackingStorePixelRatio ||
ctx.msBackingStorePixelRatio ||
ctx.oBackingStorePixelRatio ||
ctx.backingStorePixelRatio || 1;
var pixelRatio = devicePixelRatio / backingStoreRatio;
return {
sx: pixelRatio,
sy: pixelRatio,
scaled: pixelRatio !== 1
};
}
/**
* Scrolls specified element into view of its parent.
* element {Object} The element to be visible.
* spot {Object} An object with optional top and left properties,
* specifying the offset from the top left edge.
*/
function scrollIntoView(element, spot) {
// Assuming offsetParent is available (it's not available when viewer is in
// hidden iframe or object). We have to scroll: if the offsetParent is not set
// producing the error. See also animationStartedClosure.
var parent = element.offsetParent;
var offsetY = element.offsetTop + element.clientTop;
var offsetX = element.offsetLeft + element.clientLeft;
if (!parent) {
console.error('offsetParent is not set -- cannot scroll');
return;
}
while (parent.clientHeight === parent.scrollHeight) {
if (parent.dataset._scaleY) {
offsetY /= parent.dataset._scaleY;
offsetX /= parent.dataset._scaleX;
}
offsetY += parent.offsetTop;
offsetX += parent.offsetLeft;
parent = parent.offsetParent;
if (!parent) {
return; // no need to scroll
}
}
if (spot) {
if (spot.top !== undefined) {
offsetY += spot.top;
}
if (spot.left !== undefined) {
offsetX += spot.left;
parent.scrollLeft = offsetX;
}
}
parent.scrollTop = offsetY;
}
/**
* Helper function to start monitoring the scroll event and converting them into
* PDF.js friendly one: with scroll debounce and scroll direction.
*/
function watchScroll(viewAreaElement, callback) {
var debounceScroll = function debounceScroll(evt) {
if (rAF) {
return;
}
// schedule an invocation of scroll for next animation frame.
rAF = window.requestAnimationFrame(function viewAreaElementScrolled() {
rAF = null;
var currentY = viewAreaElement.scrollTop;
var lastY = state.lastY;
if (currentY !== lastY) {
state.down = currentY > lastY;
}
state.lastY = currentY;
callback(state);
});
};
var state = {
down: true,
lastY: viewAreaElement.scrollTop,
_eventHandler: debounceScroll
};
var rAF = null;
viewAreaElement.addEventListener('scroll', debounceScroll, true);
return state;
}
/**
* Helper function to parse query string (e.g. ?param1=value&parm2=...).
*/
function parseQueryString(query) {
var parts = query.split('&');
var params = {};
for (var i = 0, ii = parts.length; i < ii; ++i) {
var param = parts[i].split('=');
var key = param[0].toLowerCase();
var value = param.length > 1 ? param[1] : null;
params[decodeURIComponent(key)] = decodeURIComponent(value);
}
return params;
}
/**
* Use binary search to find the index of the first item in a given array which
* passes a given condition. The items are expected to be sorted in the sense
* that if the condition is true for one item in the array, then it is also true
* for all following items.
*
* @returns {Number} Index of the first array element to pass the test,
* or |items.length| if no such element exists.
*/
function binarySearchFirstItem(items, condition) {
var minIndex = 0;
var maxIndex = items.length - 1;
if (items.length === 0 || !condition(items[maxIndex])) {
return items.length;
}
if (condition(items[minIndex])) {
return minIndex;
}
while (minIndex < maxIndex) {
var currentIndex = (minIndex + maxIndex) >> 1;
var currentItem = items[currentIndex];
if (condition(currentItem)) {
maxIndex = currentIndex;
} else {
minIndex = currentIndex + 1;
}
}
return minIndex; /* === maxIndex */
}
/**
* Generic helper to find out what elements are visible within a scroll pane.
*/
function getVisibleElements(scrollEl, views, sortByVisibility) {
var top = scrollEl.scrollTop, bottom = top + scrollEl.clientHeight;
var left = scrollEl.scrollLeft, right = left + scrollEl.clientWidth;
function isElementBottomBelowViewTop(view) {
var element = view.div;
var elementBottom =
element.offsetTop + element.clientTop + element.clientHeight;
return elementBottom > top;
}
var visible = [], view, element;
var currentHeight, viewHeight, hiddenHeight, percentHeight;
var currentWidth, viewWidth;
var firstVisibleElementInd = (views.length === 0) ? 0 :
binarySearchFirstItem(views, isElementBottomBelowViewTop);
for (var i = firstVisibleElementInd, ii = views.length; i < ii; i++) {
view = views[i];
element = view.div;
currentHeight = element.offsetTop + element.clientTop;
viewHeight = element.clientHeight;
if (currentHeight > bottom) {
break;
}
currentWidth = element.offsetLeft + element.clientLeft;
viewWidth = element.clientWidth;
if (currentWidth + viewWidth < left || currentWidth > right) {
continue;
}
hiddenHeight = Math.max(0, top - currentHeight) +
Math.max(0, currentHeight + viewHeight - bottom);
percentHeight = ((viewHeight - hiddenHeight) * 100 / viewHeight) | 0;
visible.push({
id: view.id,
x: currentWidth,
y: currentHeight,
view: view,
percent: percentHeight
});
}
var first = visible[0];
var last = visible[visible.length - 1];
if (sortByVisibility) {
visible.sort(function (a, b) {
var pc = a.percent - b.percent;
if (Math.abs(pc) > 0.001) {
return -pc;
}
return a.id - b.id; // ensure stability
});
}
return {first: first, last: last, views: visible};
}
/**
* Event handler to suppress context menu.
*/
function noContextMenuHandler(e) {
e.preventDefault();
}
/**
* Returns the filename or guessed filename from the url (see issue 3455).
* url {String} The original PDF location.
* @return {String} Guessed PDF file name.
*/
function getPDFFileNameFromURL(url) {
var reURI = /^(?:([^:]+:)?\/\/[^\/]+)?([^?#]*)(\?[^#]*)?(#.*)?$/;
// SCHEME HOST 1.PATH 2.QUERY 3.REF
// Pattern to get last matching NAME.pdf
var reFilename = /[^\/?#=]+\.pdf(?!.*\.pdf)/i;
var splitURI = reURI.exec(url);
var suggestedFilename = reFilename.exec(splitURI[1]) ||
reFilename.exec(splitURI[2]) ||
reFilename.exec(splitURI[3]);
if (suggestedFilename) {
suggestedFilename = suggestedFilename[0];
if (suggestedFilename.indexOf('%') !== -1) {
// URL-encoded %2Fpath%2Fto%2Ffile.pdf should be file.pdf
try {
suggestedFilename =
reFilename.exec(decodeURIComponent(suggestedFilename))[0];
} catch (e) { // Possible (extremely rare) errors:
// URIError "Malformed URI", e.g. for "%AA.pdf"
// TypeError "null has no properties", e.g. for "%2F.pdf"
}
}
}
return suggestedFilename || 'document.pdf';
}
var ProgressBar = (function ProgressBarClosure() {
function clamp(v, min, max) {
return Math.min(Math.max(v, min), max);
}
function ProgressBar(id, opts) {
this.visible = true;
// Fetch the sub-elements for later.
this.div = document.querySelector(id + ' .progress');
// Get the loading bar element, so it can be resized to fit the viewer.
this.bar = this.div.parentNode;
// Get options, with sensible defaults.
this.height = opts.height || 100;
this.width = opts.width || 100;
this.units = opts.units || '%';
// Initialize heights.
this.div.style.height = this.height + this.units;
this.percent = 0;
}
ProgressBar.prototype = {
updateBar: function ProgressBar_updateBar() {
if (this._indeterminate) {
this.div.classList.add('indeterminate');
this.div.style.width = this.width + this.units;
return;
}
this.div.classList.remove('indeterminate');
var progressSize = this.width * this._percent / 100;
this.div.style.width = progressSize + this.units;
},
get percent() {
return this._percent;
},
set percent(val) {
this._indeterminate = isNaN(val);
this._percent = clamp(val, 0, 100);
this.updateBar();
},
setWidth: function ProgressBar_setWidth(viewer) {
if (viewer) {
var container = viewer.parentNode;
var scrollbarWidth = container.offsetWidth - viewer.offsetWidth;
if (scrollbarWidth > 0) {
this.bar.setAttribute('style', 'width: calc(100% - ' +
scrollbarWidth + 'px);');
}
}
},
hide: function ProgressBar_hide() {
if (!this.visible) {
return;
}
this.visible = false;
this.bar.classList.add('hidden');
document.body.classList.remove('loadingInProgress');
},
show: function ProgressBar_show() {
if (this.visible) {
return;
}
this.visible = true;
document.body.classList.add('loadingInProgress');
this.bar.classList.remove('hidden');
}
};
return ProgressBar;
})();
var DEFAULT_PREFERENCES = {
showPreviousViewOnLoad: true,
defaultZoomValue: '',
sidebarViewOnLoad: 0,
enableHandToolOnLoad: false,
enableWebGL: false,
pdfBugEnabled: false,
disableRange: false,
disableStream: false,
disableAutoFetch: false,
disableFontFace: false,
disableTextLayer: false,
useOnlyCssZoom: false
};
var SidebarView = {
NONE: 0,
THUMBS: 1,
OUTLINE: 2,
ATTACHMENTS: 3
};
/**
* Preferences - Utility for storing persistent settings.
* Used for settings that should be applied to all opened documents,
* or every time the viewer is loaded.
*/
var Preferences = {
prefs: Object.create(DEFAULT_PREFERENCES),
isInitializedPromiseResolved: false,
initializedPromise: null,
/**
* Initialize and fetch the current preference values from storage.
* @return {Promise} A promise that is resolved when the preferences
* have been initialized.
*/
initialize: function preferencesInitialize() {
return this.initializedPromise =
this._readFromStorage(DEFAULT_PREFERENCES).then(function (prefObj) {
this.isInitializedPromiseResolved = true;
if (prefObj) {
this.prefs = prefObj;
}
}.bind(this));
},
/**
* Stub function for writing preferences to storage.
* NOTE: This should be overridden by a build-specific function defined below.
* @param {Object} prefObj The preferences that should be written to storage.
* @return {Promise} A promise that is resolved when the preference values
* have been written.
*/
_writeToStorage: function preferences_writeToStorage(prefObj) {
return Promise.resolve();
},
/**
* Stub function for reading preferences from storage.
* NOTE: This should be overridden by a build-specific function defined below.
* @param {Object} prefObj The preferences that should be read from storage.
* @return {Promise} A promise that is resolved with an {Object} containing
* the preferences that have been read.
*/
_readFromStorage: function preferences_readFromStorage(prefObj) {
return Promise.resolve();
},
/**
* Reset the preferences to their default values and update storage.
* @return {Promise} A promise that is resolved when the preference values
* have been reset.
*/
reset: function preferencesReset() {
return this.initializedPromise.then(function () {
this.prefs = Object.create(DEFAULT_PREFERENCES);
return this._writeToStorage(DEFAULT_PREFERENCES);
}.bind(this));
},
/**
* Replace the current preference values with the ones from storage.
* @return {Promise} A promise that is resolved when the preference values
* have been updated.
*/
reload: function preferencesReload() {
return this.initializedPromise.then(function () {
this._readFromStorage(DEFAULT_PREFERENCES).then(function (prefObj) {
if (prefObj) {
this.prefs = prefObj;
}
}.bind(this));
}.bind(this));
},
/**
* Set the value of a preference.
* @param {string} name The name of the preference that should be changed.
* @param {boolean|number|string} value The new value of the preference.
* @return {Promise} A promise that is resolved when the value has been set,
* provided that the preference exists and the types match.
*/
set: function preferencesSet(name, value) {
return this.initializedPromise.then(function () {
if (DEFAULT_PREFERENCES[name] === undefined) {
throw new Error('preferencesSet: \'' + name + '\' is undefined.');
} else if (value === undefined) {
throw new Error('preferencesSet: no value is specified.');
}
var valueType = typeof value;
var defaultType = typeof DEFAULT_PREFERENCES[name];
if (valueType !== defaultType) {
if (valueType === 'number' && defaultType === 'string') {
value = value.toString();
} else {
throw new Error('Preferences_set: \'' + value + '\' is a \"' +
valueType + '\", expected \"' + defaultType + '\".');
}
} else {
if (valueType === 'number' && (value | 0) !== value) {
throw new Error('Preferences_set: \'' + value +
'\' must be an \"integer\".');
}
}
this.prefs[name] = value;
return this._writeToStorage(this.prefs);
}.bind(this));
},
/**
* Get the value of a preference.
* @param {string} name The name of the preference whose value is requested.
* @return {Promise} A promise that is resolved with a {boolean|number|string}
* containing the value of the preference.
*/
get: function preferencesGet(name) {
return this.initializedPromise.then(function () {
var defaultValue = DEFAULT_PREFERENCES[name];
if (defaultValue === undefined) {
throw new Error('preferencesGet: \'' + name + '\' is undefined.');
} else {
var prefValue = this.prefs[name];
if (prefValue !== undefined) {
return prefValue;
}
}
return defaultValue;
}.bind(this));
}
};
Preferences._writeToStorage = function (prefObj) {
return new Promise(function (resolve) {
localStorage.setItem('pdfjs.preferences', JSON.stringify(prefObj));
resolve();
});
};
Preferences._readFromStorage = function (prefObj) {
return new Promise(function (resolve) {
var readPrefs = JSON.parse(localStorage.getItem('pdfjs.preferences'));
resolve(readPrefs);
});
};
$(function() {
$('#print').click(function(){
var mediaQueryList = window.matchMedia('print');
mediaQueryList.addListener(function(mql) {
if (mql.matches) {
console.log('before print dialog open');
} else {
console.log('after print dialog closed');
window.location.reload();
}
});
});
});
(function mozPrintCallbackPolyfillClosure() {
if ('mozPrintCallback' in document.createElement('canvas')) {
return;
}
// Cause positive result on feature-detection:
HTMLCanvasElement.prototype.mozPrintCallback = undefined;
var canvases; // During print task: non-live NodeList of <canvas> elements
var index; // Index of <canvas> element that is being processed
var print = window.print;
window.print = function print() {
if (canvases) {
console.warn('Ignored window.print() because of a pending print job.');
return;
}
try {
dispatchEvent('beforeprint');
} finally {
canvases = document.querySelectorAll('canvas');
index = -1;
next();
}
};
function dispatchEvent(eventType) {
var event = document.createEvent('CustomEvent');
event.initCustomEvent(eventType, false, false, 'custom');
window.dispatchEvent(event);
}
function next() {
if (!canvases) {
return; // Print task cancelled by user (state reset in abort())
}
renderProgress();
if (++index < canvases.length) {
var canvas = canvases[index];
if (typeof canvas.mozPrintCallback === 'function') {
canvas.mozPrintCallback({
context: canvas.getContext('2d'),
abort: abort,
done: next
});
} else {
next();
}
} else {
renderProgress();
print.call(window);
setTimeout(abort, 20); // Tidy-up
}
}
function abort() {
if (canvases) {
canvases = null;
renderProgress();
dispatchEvent('afterprint');
}
}
function renderProgress() {
var progressContainer = document.getElementById('mozPrintCallback-shim');
if (canvases && canvases.length) {
var progress = Math.round(100 * index / canvases.length);
var progressBar = progressContainer.querySelector('progress');
var progressPerc = progressContainer.querySelector('.relative-progress');
progressBar.value = progress;
progressPerc.textContent = progress + '%';
progressContainer.removeAttribute('hidden');
progressContainer.onclick = abort;
} else {
progressContainer.setAttribute('hidden', '');
}
}
var hasAttachEvent = !!document.attachEvent;
window.addEventListener('keydown', function (event) {
// Intercept Cmd/Ctrl + P in all browsers.
// Also intercept Cmd/Ctrl + Shift + P in Chrome and Opera
if (event.keyCode === 80/*P*/ && (event.ctrlKey || event.metaKey) &&
!event.altKey && (!event.shiftKey || window.chrome || window.opera)) {
//window.print();
if (hasAttachEvent) {
// Only attachEvent can cancel Ctrl + P dialog in IE <=10
// attachEvent is gone in IE11, so the dialog will re-appear in IE11.
return;
}
event.preventDefault();
if (event.stopImmediatePropagation) {
event.stopImmediatePropagation();
} else {
event.stopPropagation();
}
return;
}
if (event.keyCode === 27 && canvases) { // Esc
abort();
}
}, true);
if (hasAttachEvent) {
document.attachEvent('onkeydown', function (event) {
event = event || window.event;
if (event.keyCode === 80/*P*/ && event.ctrlKey) {
event.keyCode = 0;
return false;
}
});
}
if ('onbeforeprint' in window) {
// Do not propagate before/afterprint events when they are not triggered
// from within this polyfill. (FF/IE).
var stopPropagationIfNeeded = function (event) {
if (event.detail !== 'custom' && event.stopImmediatePropagation) {
event.stopImmediatePropagation();
}
};
window.addEventListener('beforeprint', stopPropagationIfNeeded, false);
window.addEventListener('afterprint', stopPropagationIfNeeded, false);
}
})();
var DownloadManager = (function DownloadManagerClosure() {
/*function download(blobUrl, filename) {
var a = document.createElement('a');
if (a.click) {
// Use a.click() if available. Otherwise, Chrome might show
// "Unsafe JavaScript attempt to initiate a navigation change
// for frame with URL" and not open the PDF at all.
// Supported by (not mentioned = untested):
// - Firefox 6 - 19 (4- does not support a.click, 5 ignores a.click)
// - Chrome 19 - 26 (18- does not support a.click)
// - Opera 9 - 12.15
// - Internet Explorer 6 - 10
// - Safari 6 (5.1- does not support a.click)
a.href = blobUrl;
a.target = '_parent';
// Use a.download if available. This increases the likelihood that
// the file is downloaded instead of opened by another PDF plugin.
if ('download' in a) {
a.download = filename;
}
// <a> must be in the document for IE and recent Firefox versions.
// (otherwise .click() is ignored)
(document.body || document.documentElement).appendChild(a);
a.click();
a.parentNode.removeChild(a);
} else {
if (window.top === window &&
blobUrl.split('#')[0] === window.location.href.split('#')[0]) {
// If _parent == self, then opening an identical URL with different
// location hash will only cause a navigation, not a download.
var padCharacter = blobUrl.indexOf('?') === -1 ? '?' : '&';
blobUrl = blobUrl.replace(/#|$/, padCharacter + '$&');
}
window.open(blobUrl, '_parent');
}
}*/
function DownloadManager() {}
/*DownloadManager.prototype = {
downloadUrl: function DownloadManager_downloadUrl(url, filename) {
if (!PDFJS.isValidUrl(url, true)) {
return; // restricted/invalid URL
}
download(url + '#pdfjs.action=download', filename);
},
downloadData: function DownloadManager_downloadData(data, filename,
contentType) {
if (navigator.msSaveBlob) { // IE10 and above
return navigator.msSaveBlob(new Blob([data], {type: contentType}),
filename);
}
var blobUrl = PDFJS.createObjectURL(data, contentType);
download(blobUrl, filename);
},
download: function DownloadManager_download(blob, url, filename) {
if (!URL) {
// URL.createObjectURL is not supported
this.downloadUrl(url, filename);
return;
}
if (navigator.msSaveBlob) {
// IE10 / IE11
if (!navigator.msSaveBlob(blob, filename)) {
this.downloadUrl(url, filename);
}
return;
}
var blobUrl = URL.createObjectURL(blob);
download(blobUrl, filename);
}
};
return DownloadManager; */
})();
/**
* View History - This is a utility for saving various view parameters for
* recently opened files.
*
* The way that the view parameters are stored depends on how PDF.js is built,
* for 'node make <flag>' the following cases exist:
* - FIREFOX or MOZCENTRAL - uses sessionStorage.
* - GENERIC or CHROME - uses localStorage, if it is available.
*/
var ViewHistory = (function ViewHistoryClosure() {
function ViewHistory(fingerprint) {
this.fingerprint = fingerprint;
this.isInitializedPromiseResolved = false;
this.initializedPromise =
this._readFromStorage().then(function (databaseStr) {
this.isInitializedPromiseResolved = true;
var database = JSON.parse(databaseStr || '{}');
if (!('files' in database)) {
database.files = [];
}
if (database.files.length >= VIEW_HISTORY_MEMORY) {
database.files.shift();
}
var index;
for (var i = 0, length = database.files.length; i < length; i++) {
var branch = database.files[i];
if (branch.fingerprint === this.fingerprint) {
index = i;
break;
}
}
if (typeof index !== 'number') {
index = database.files.push({fingerprint: this.fingerprint}) - 1;
}
this.file = database.files[index];
this.database = database;
}.bind(this));
}
ViewHistory.prototype = {
_writeToStorage: function ViewHistory_writeToStorage() {
return new Promise(function (resolve) {
var databaseStr = JSON.stringify(this.database);
localStorage.setItem('database', databaseStr);
resolve();
}.bind(this));
},
_readFromStorage: function ViewHistory_readFromStorage() {
return new Promise(function (resolve) {
resolve(localStorage.getItem('database'));
});
},
set: function ViewHistory_set(name, val) {
if (!this.isInitializedPromiseResolved) {
return;
}
this.file[name] = val;
return this._writeToStorage();
},
setMultiple: function ViewHistory_setMultiple(properties) {
if (!this.isInitializedPromiseResolved) {
return;
}
for (var name in properties) {
this.file[name] = properties[name];
}
return this._writeToStorage();
},
get: function ViewHistory_get(name, defaultValue) {
if (!this.isInitializedPromiseResolved) {
return defaultValue;
}
return this.file[name] || defaultValue;
}
};
return ViewHistory;
})();
/**
* Creates a "search bar" given a set of DOM elements that act as controls
* for searching or for setting search preferences in the UI. This object
* also sets up the appropriate events for the controls. Actual searching
* is done by PDFFindController.
*/
var PDFFindBar = (function PDFFindBarClosure() {
function PDFFindBar(options) {
this.opened = false;
this.bar = options.bar || null;
this.toggleButton = options.toggleButton || null;
this.findField = options.findField || null;
this.findField.value = '<?php echo addslashes($search_word); ?>';
this.highlightAll = options.highlightAllCheckbox || null;
this.caseSensitive = options.caseSensitiveCheckbox || null;
this.findMsg = options.findMsg || null;
this.findStatusIcon = options.findStatusIcon || null;
this.findPreviousButton = options.findPreviousButton || null;
this.findNextButton = options.findNextButton || null;
this.findController = options.findController || null;
if (this.findController === null) {
throw new Error('PDFFindBar cannot be used without a ' +
'PDFFindController instance.');
}
// Add event listeners to the DOM elements.
var self = this;
this.toggleButton.addEventListener('click', function () {
self.toggle();
});
this.findField.addEventListener('input', function () {
self.dispatchEvent('');
});
this.bar.addEventListener('keydown', function (evt) {
switch (evt.keyCode) {
case 13: // Enter
if (evt.target === self.findField) {
self.dispatchEvent('again', evt.shiftKey);
}
break;
case 27: // Escape
self.close();
break;
}
});
this.findPreviousButton.addEventListener('click', function () {
self.dispatchEvent('again', true);
});
this.findNextButton.addEventListener('click', function () {
self.dispatchEvent('again', false);
});
this.highlightAll.addEventListener('click', function () {
self.dispatchEvent('highlightallchange');
});
this.caseSensitive.addEventListener('click', function () {
self.dispatchEvent('casesensitivitychange');
});
}
PDFFindBar.prototype = {
dispatchEvent: function PDFFindBar_dispatchEvent(type, findPrev) {
var event = document.createEvent('CustomEvent');
event.initCustomEvent('find' + type, true, true, {
query: this.findField.value,
caseSensitive: this.caseSensitive.checked,
highlightAll: this.highlightAll.checked,
findPrevious: findPrev
});
return window.dispatchEvent(event);
},
updateUIState: function PDFFindBar_updateUIState(state, previous) {
var notFound = false;
var findMsg = '';
var status = '';
switch (state) {
case FindStates.FIND_FOUND:
break;
case FindStates.FIND_PENDING:
status = 'pending';
break;
case FindStates.FIND_NOTFOUND:
findMsg = mozL10n.get('find_not_found', null, 'Phrase not found');
notFound = true;
break;
case FindStates.FIND_WRAPPED:
if (previous) {
findMsg = mozL10n.get('find_reached_top', null,
'Reached top of document, continued from bottom');
} else {
findMsg = mozL10n.get('find_reached_bottom', null,
'Reached end of document, continued from top');
}
break;
}
if (notFound) {
this.findField.classList.add('notFound');
} else {
this.findField.classList.remove('notFound');
}
this.findField.setAttribute('data-status', status);
this.findMsg.textContent = findMsg;
},
open: function PDFFindBar_open() {
if (!this.opened) {
this.opened = true;
this.toggleButton.classList.add('toggled');
this.bar.classList.remove('hidden');
}
this.findField.select();
this.findField.focus();
},
close: function PDFFindBar_close() {
if (!this.opened) {
return;
}
this.opened = false;
this.toggleButton.classList.remove('toggled');
this.bar.classList.add('hidden');
this.findController.active = false;
},
toggle: function PDFFindBar_toggle() {
if (this.opened) {
this.close();
} else {
this.open();
}
}
};
return PDFFindBar;
})();
var FindStates = {
FIND_FOUND: 0,
FIND_NOTFOUND: 1,
FIND_WRAPPED: 2,
FIND_PENDING: 3
};
var FIND_SCROLL_OFFSET_TOP = -50;
var FIND_SCROLL_OFFSET_LEFT = -400;
/**
* Provides "search" or "find" functionality for the PDF.
* This object actually performs the search for a given string.
*/
var PDFFindController = (function PDFFindControllerClosure() {
function PDFFindController(options) {
this.startedTextExtraction = false;
this.extractTextPromises = [];
this.pendingFindMatches = {};
this.active = false; // If active, find results will be highlighted.
this.pageContents = []; // Stores the text for each page.
this.pageMatches = [];
this.selected = {// Currently selected match.
pageIdx: -1,
matchIdx: -1
};
this.offset = {// Where the find algorithm currently is in the document.
pageIdx: null,
matchIdx: null
};
this.pagesToSearch = null;
this.resumePageIdx = null;
this.state = null;
this.dirtyMatch = false;
this.findTimeout = null;
this.pdfViewer = options.pdfViewer || null;
this.integratedFind = options.integratedFind || false;
this.charactersToNormalize = {
'': '\'', // Left single quotation mark
'': '\'', // Right single quotation mark
'': '\'', // Single low-9 quotation mark
'': '\'', // Single high-reversed-9 quotation mark
'': '"', // Left double quotation mark
'': '"', // Right double quotation mark
'': '"', // Double low-9 quotation mark
'': '"', // Double high-reversed-9 quotation mark
'': '1/4', // Vulgar fraction one quarter
'': '1/2', // Vulgar fraction one half
'': '3/4', // Vulgar fraction three quarters
'': ' ' // No-break space
};
this.findBar = options.findBar || null;
// Compile the regular expression for text normalization once
var replace = Object.keys(this.charactersToNormalize).join('');
this.normalizationRegex = new RegExp('[' + replace + ']', 'g');
var events = [
'find',
'findagain',
'findhighlightallchange',
'findcasesensitivitychange'
];
this.firstPagePromise = new Promise(function (resolve) {
this.resolveFirstPage = resolve;
}.bind(this));
this.handleEvent = this.handleEvent.bind(this);
for (var i = 0, len = events.length; i < len; i++) {
window.addEventListener(events[i], this.handleEvent);
}
}
PDFFindController.prototype = {
setFindBar: function PDFFindController_setFindBar(findBar) {
this.findBar = findBar;
},
reset: function PDFFindController_reset() {
this.startedTextExtraction = false;
this.extractTextPromises = [];
this.active = false;
},
normalize: function PDFFindController_normalize(text) {
var self = this;
return text.replace(this.normalizationRegex, function (ch) {
return self.charactersToNormalize[ch];
});
},
calcFindMatch: function PDFFindController_calcFindMatch(pageIndex) {
var pageContent = this.normalize(this.pageContents[pageIndex]);
var query = this.normalize(this.state.query);
var caseSensitive = this.state.caseSensitive;
var queryLen = query.length;
if (queryLen === 0) {
return; // Do nothing: the matches should be wiped out already.
}
if (!caseSensitive) {
pageContent = pageContent.toLowerCase();
query = query.toLowerCase();
}
var matches = [];
var matchIdx = -queryLen;
while (true) {
matchIdx = pageContent.indexOf(query, matchIdx + queryLen);
if (matchIdx === -1) {
break;
}
matches.push(matchIdx);
}
this.pageMatches[pageIndex] = matches;
this.updatePage(pageIndex);
if (this.resumePageIdx === pageIndex) {
this.resumePageIdx = null;
this.nextPageMatch();
}
},
extractText: function PDFFindController_extractText() {
if (this.startedTextExtraction) {
return;
}
this.startedTextExtraction = true;
this.pageContents = [];
var extractTextPromisesResolves = [];
var numPages = this.pdfViewer.pagesCount;
for (var i = 0; i < numPages; i++) {
this.extractTextPromises.push(new Promise(function (resolve) {
extractTextPromisesResolves.push(resolve);
}));
}
var self = this;
function extractPageText(pageIndex) {
self.pdfViewer.getPageTextContent(pageIndex).then(
function textContentResolved(textContent) {
var textItems = textContent.items;
var str = [];
for (var i = 0, len = textItems.length; i < len; i++) {
str.push(textItems[i].str);
}
// Store the pageContent as a string.
self.pageContents.push(str.join(''));
extractTextPromisesResolves[pageIndex](pageIndex);
if ((pageIndex + 1) < self.pdfViewer.pagesCount) {
extractPageText(pageIndex + 1);
}
}
);
}
extractPageText(0);
},
handleEvent: function PDFFindController_handleEvent(e) {
if (this.state === null || e.type !== 'findagain') {
this.dirtyMatch = true;
}
this.state = e.detail;
this.updateUIState(FindStates.FIND_PENDING);
this.firstPagePromise.then(function () {
this.extractText();
clearTimeout(this.findTimeout);
if (e.type === 'find') {
// Only trigger the find action after 250ms of silence.
this.findTimeout = setTimeout(this.nextMatch.bind(this), 250);
} else {
this.nextMatch();
}
}.bind(this));
},
updatePage: function PDFFindController_updatePage(index) {
if (this.selected.pageIdx === index) {
// If the page is selected, scroll the page into view, which triggers
// rendering the page, which adds the textLayer. Once the textLayer is
// build, it will scroll onto the selected match.
this.pdfViewer.scrollPageIntoView(index + 1);
}
var page = this.pdfViewer.getPageView(index);
if (page.textLayer) {
page.textLayer.updateMatches();
}
},
nextMatch: function PDFFindController_nextMatch() {
var previous = this.state.findPrevious;
var currentPageIndex = this.pdfViewer.currentPageNumber - 1;
var numPages = this.pdfViewer.pagesCount;
this.active = true;
if (this.dirtyMatch) {
// Need to recalculate the matches, reset everything.
this.dirtyMatch = false;
this.selected.pageIdx = this.selected.matchIdx = -1;
this.offset.pageIdx = currentPageIndex;
this.offset.matchIdx = null;
this.hadMatch = false;
this.resumePageIdx = null;
this.pageMatches = [];
var self = this;
for (var i = 0; i < numPages; i++) {
// Wipe out any previous highlighted matches.
this.updatePage(i);
// As soon as the text is extracted start finding the matches.
if (!(i in this.pendingFindMatches)) {
this.pendingFindMatches[i] = true;
this.extractTextPromises[i].then(function (pageIdx) {
delete self.pendingFindMatches[pageIdx];
self.calcFindMatch(pageIdx);
});
}
}
}
// If there's no query there's no point in searching.
if (this.state.query === '') {
this.updateUIState(FindStates.FIND_FOUND);
return;
}
// If we're waiting on a page, we return since we can't do anything else.
if (this.resumePageIdx) {
return;
}
var offset = this.offset;
// Keep track of how many pages we should maximally iterate through.
this.pagesToSearch = numPages;
// If there's already a matchIdx that means we are iterating through a
// page's matches.
if (offset.matchIdx !== null) {
var numPageMatches = this.pageMatches[offset.pageIdx].length;
if ((!previous && offset.matchIdx + 1 < numPageMatches) ||
(previous && offset.matchIdx > 0)) {
// The simple case; we just have advance the matchIdx to select
// the next match on the page.
this.hadMatch = true;
offset.matchIdx = (previous ? offset.matchIdx - 1 :
offset.matchIdx + 1);
this.updateMatch(true);
return;
}
// We went beyond the current page's matches, so we advance to
// the next page.
this.advanceOffsetPage(previous);
}
// Start searching through the page.
this.nextPageMatch();
},
matchesReady: function PDFFindController_matchesReady(matches) {
var offset = this.offset;
var numMatches = matches.length;
var previous = this.state.findPrevious;
if (numMatches) {
// There were matches for the page, so initialize the matchIdx.
this.hadMatch = true;
offset.matchIdx = (previous ? numMatches - 1 : 0);
this.updateMatch(true);
return true;
} else {
// No matches, so attempt to search the next page.
this.advanceOffsetPage(previous);
if (offset.wrapped) {
offset.matchIdx = null;
if (this.pagesToSearch < 0) {
// No point in wrapping again, there were no matches.
this.updateMatch(false);
// while matches were not found, searching for a page
// with matches should nevertheless halt.
return true;
}
}
// Matches were not found (and searching is not done).
return false;
}
},
/**
* The method is called back from the text layer when match presentation
* is updated.
* @param {number} pageIndex - page index.
* @param {number} index - match index.
* @param {Array} elements - text layer div elements array.
* @param {number} beginIdx - start index of the div array for the match.
* @param {number} endIdx - end index of the div array for the match.
*/
updateMatchPosition: function PDFFindController_updateMatchPosition(
pageIndex, index, elements, beginIdx, endIdx) {
if (this.selected.matchIdx === index &&
this.selected.pageIdx === pageIndex) {
scrollIntoView(elements[beginIdx], {
top: FIND_SCROLL_OFFSET_TOP,
left: FIND_SCROLL_OFFSET_LEFT
});
}
},
nextPageMatch: function PDFFindController_nextPageMatch() {
if (this.resumePageIdx !== null) {
console.error('There can only be one pending page.');
}
do {
var pageIdx = this.offset.pageIdx;
var matches = this.pageMatches[pageIdx];
if (!matches) {
// The matches don't exist yet for processing by "matchesReady",
// so set a resume point for when they do exist.
this.resumePageIdx = pageIdx;
break;
}
} while (!this.matchesReady(matches));
},
advanceOffsetPage: function PDFFindController_advanceOffsetPage(previous) {
var offset = this.offset;
var numPages = this.extractTextPromises.length;
offset.pageIdx = (previous ? offset.pageIdx - 1 : offset.pageIdx + 1);
offset.matchIdx = null;
this.pagesToSearch--;
if (offset.pageIdx >= numPages || offset.pageIdx < 0) {
offset.pageIdx = (previous ? numPages - 1 : 0);
offset.wrapped = true;
}
},
updateMatch: function PDFFindController_updateMatch(found) {
var state = FindStates.FIND_NOTFOUND;
var wrapped = this.offset.wrapped;
this.offset.wrapped = false;
if (found) {
var previousPage = this.selected.pageIdx;
this.selected.pageIdx = this.offset.pageIdx;
this.selected.matchIdx = this.offset.matchIdx;
state = (wrapped ? FindStates.FIND_WRAPPED : FindStates.FIND_FOUND);
// Update the currently selected page to wipe out any selected matches.
if (previousPage !== -1 && previousPage !== this.selected.pageIdx) {
this.updatePage(previousPage);
}
}
this.updateUIState(state, this.state.findPrevious);
if (this.selected.pageIdx !== -1) {
this.updatePage(this.selected.pageIdx);
}
},
updateUIState: function PDFFindController_updateUIState(state, previous) {
if (this.integratedFind) {
FirefoxCom.request('updateFindControlState',
{result: state, findPrevious: previous});
return;
}
if (this.findBar === null) {
throw new Error('PDFFindController is not initialized with a ' +
'PDFFindBar instance.');
}
this.findBar.updateUIState(state, previous);
}
};
return PDFFindController;
})();
/**
* Performs navigation functions inside PDF, such as opening specified page,
* or destination.
* @class
* @implements {IPDFLinkService}
*/
var PDFLinkService = (function () {
/**
* @constructs PDFLinkService
*/
function PDFLinkService() {
this.baseUrl = null;
this.pdfDocument = null;
this.pdfViewer = null;
this.pdfHistory = null;
this._pagesRefCache = null;
}
PDFLinkService.prototype = {
setDocument: function PDFLinkService_setDocument(pdfDocument, baseUrl) {
this.baseUrl = baseUrl;
this.pdfDocument = pdfDocument;
this._pagesRefCache = Object.create(null);
},
setViewer: function PDFLinkService_setViewer(pdfViewer) {
this.pdfViewer = pdfViewer;
},
setHistory: function PDFLinkService_setHistory(pdfHistory) {
this.pdfHistory = pdfHistory;
},
/**
* @returns {number}
*/
get pagesCount() {
return this.pdfDocument.numPages;
},
/**
* @returns {number}
*/
get page() {
return this.pdfViewer.currentPageNumber;
},
/**
* @param {number} value
*/
set page(value) {
this.pdfViewer.currentPageNumber = value;
},
/**
* @param dest - The PDF destination object.
*/
navigateTo: function PDFLinkService_navigateTo(dest) {
var destString = '';
var self = this;
var goToDestination = function (destRef) {
// dest array looks like that: <page-ref> </XYZ|FitXXX> <args..>
var pageNumber = destRef instanceof Object ?
self._pagesRefCache[destRef.num + ' ' + destRef.gen + ' R'] :
(destRef + 1);
if (pageNumber) {
if (pageNumber > self.pagesCount) {
pageNumber = self.pagesCount;
}
self.pdfViewer.scrollPageIntoView(pageNumber, dest);
if (self.pdfHistory) {
// Update the browsing history.
self.pdfHistory.push({
dest: dest,
hash: destString,
page: pageNumber
});
}
} else {
self.pdfDocument.getPageIndex(destRef).then(function (pageIndex) {
var pageNum = pageIndex + 1;
var cacheKey = destRef.num + ' ' + destRef.gen + ' R';
self._pagesRefCache[cacheKey] = pageNum;
goToDestination(destRef);
});
}
};
var destinationPromise;
if (typeof dest === 'string') {
destString = dest;
destinationPromise = this.pdfDocument.getDestination(dest);
} else {
destinationPromise = Promise.resolve(dest);
}
destinationPromise.then(function (destination) {
dest = destination;
if (!(destination instanceof Array)) {
return; // invalid destination
}
goToDestination(destination[0]);
});
},
/**
* @param dest - The PDF destination object.
* @returns {string} The hyperlink to the PDF object.
*/
getDestinationHash: function PDFLinkService_getDestinationHash(dest) {
if (typeof dest === 'string') {
return this.getAnchorUrl('#' + escape(dest));
}
if (dest instanceof Array) {
var destRef = dest[0]; // see navigateTo method for dest format
var pageNumber = destRef instanceof Object ?
this._pagesRefCache[destRef.num + ' ' + destRef.gen + ' R'] :
(destRef + 1);
if (pageNumber) {
var pdfOpenParams = this.getAnchorUrl('#page=' + pageNumber);
var destKind = dest[1];
if (typeof destKind === 'object' && 'name' in destKind &&
destKind.name === 'XYZ') {
var scale = (dest[4] || this.pdfViewer.currentScaleValue);
var scaleNumber = parseFloat(scale);
if (scaleNumber) {
scale = scaleNumber * 100;
}
pdfOpenParams += '&zoom=' + scale;
if (dest[2] || dest[3]) {
pdfOpenParams += ',' + (dest[2] || 0) + ',' + (dest[3] || 0);
}
}
return pdfOpenParams;
}
}
return '';
},
/**
* Prefix the full url on anchor links to make sure that links are resolved
* relative to the current URL instead of the one defined in <base href>.
* @param {String} anchor The anchor hash, including the #.
* @returns {string} The hyperlink to the PDF object.
*/
getAnchorUrl: function PDFLinkService_getAnchorUrl(anchor) {
return (this.baseUrl || '') + anchor;
},
/**
* @param {string} hash
*/
setHash: function PDFLinkService_setHash(hash) {
if (hash.indexOf('=') >= 0) {
var params = parseQueryString(hash);
// borrowing syntax from "Parameters for Opening PDF Files"
if ('nameddest' in params) {
if (this.pdfHistory) {
this.pdfHistory.updateNextHashParam(params.nameddest);
}
this.navigateTo(params.nameddest);
return;
}
var pageNumber, dest;
if ('page' in params) {
pageNumber = (params.page | 0) || 1;
}
//Customization added by Sri Krishnan for Annotations
if ('documentid' in params) {
document.getElementById("documentid").value = params.documentid;
}
if ('revisionid' in params) {
document.getElementById("revisionid").value = params.revisionid;
}
if ('username' in params) {
document.getElementById("username").value = params.username;
userName = params.username;
}
if ('print' in params) {
if (params.print == 'false') {
document.getElementById('print').classList.add('hidden');
document.getElementById('secondaryPrint').classList.add('hidden');
} else {
document.getElementById('print').classList.remove('hidden');
document.getElementById('secondaryPrint').classList.remove('hidden');
}
}
if ('download' in params) {
if (params.download == 'false') {
document.getElementById('download').classList.add('hidden');
document.getElementById('secondaryDownload').classList.add('hidden');
} else {
document.getElementById('download').classList.remove('hidden');
document.getElementById('secondaryDownload').classList.remove('hidden');
}
}
if ('edit' in params) {
if (params.edit == 'false') {
document.getElementById('saveAnnotations').disabled = true;
document.getElementById('deleteAnnotation').disabled = true;
document.getElementById('background').disabled = true;
document.getElementById('highlight').disabled = true;
document.getElementById('blackout').disabled = true;
document.getElementById('ellipse').disabled = true;
document.getElementById('stickynote').disabled = true;
document.getElementById('rubberstamp').disabled = true;
document.getElementById('digitalsign').disabled = true;
canEdit = false;
} else {
document.getElementById('saveAnnotations').disabled = false;
document.getElementById('deleteAnnotation').disabled = false;
document.getElementById('background').disabled = false;
document.getElementById('highlight').disabled = false;
document.getElementById('blackout').disabled = false;
document.getElementById('ellipse').disabled = false;
document.getElementById('stickynote').disabled = false;
document.getElementById('rubberstamp').disabled = false;
document.getElementById('digitalsign').disabled = false;
canEdit = true;
}
}
if ('shareddocumentid' in params) {
sharedDocumentID = params.shareddocumentid;
}
if ('zoom' in params) {
// Build the destination array.
var zoomArgs = params.zoom.split(','); // scale,left,top
var zoomArg = zoomArgs[0];
var zoomArgNumber = parseFloat(zoomArg);
if (zoomArg.indexOf('Fit') === -1) {
// If the zoomArg is a number, it has to get divided by 100. If it's
// a string, it should stay as it is.
dest = [null, {name: 'XYZ'},
zoomArgs.length > 1 ? (zoomArgs[1] | 0) : null,
zoomArgs.length > 2 ? (zoomArgs[2] | 0) : null,
(zoomArgNumber ? zoomArgNumber / 100 : zoomArg)];
} else {
if (zoomArg === 'Fit' || zoomArg === 'FitB') {
dest = [null, {name: zoomArg}];
} else if ((zoomArg === 'FitH' || zoomArg === 'FitBH') ||
(zoomArg === 'FitV' || zoomArg === 'FitBV')) {
dest = [null, {name: zoomArg},
zoomArgs.length > 1 ? (zoomArgs[1] | 0) : null];
} else if (zoomArg === 'FitR') {
if (zoomArgs.length !== 5) {
console.error('PDFLinkService_setHash: ' +
'Not enough parameters for \'FitR\'.');
} else {
dest = [null, {name: zoomArg},
(zoomArgs[1] | 0), (zoomArgs[2] | 0),
(zoomArgs[3] | 0), (zoomArgs[4] | 0)];
}
} else {
console.error('PDFLinkService_setHash: \'' + zoomArg +
'\' is not a valid zoom value.');
}
}
}
if (dest) {
this.pdfViewer.scrollPageIntoView(pageNumber || this.page, dest);
} else if (pageNumber) {
this.page = pageNumber; // simple page
}
if ('pagemode' in params) {
var event = document.createEvent('CustomEvent');
event.initCustomEvent('pagemode', true, true, {
mode: params.pagemode,
});
this.pdfViewer.container.dispatchEvent(event);
}
} else if (/^\d+$/.test(hash)) { // page number
this.page = hash;
} else { // named destination
if (this.pdfHistory) {
this.pdfHistory.updateNextHashParam(unescape(hash));
}
this.navigateTo(unescape(hash));
}
},
/**
* @param {string} action
*/
executeNamedAction: function PDFLinkService_executeNamedAction(action) {
// See PDF reference, table 8.45 - Named action
switch (action) {
case 'GoBack':
if (this.pdfHistory) {
this.pdfHistory.back();
}
break;
case 'GoForward':
if (this.pdfHistory) {
this.pdfHistory.forward();
}
break;
case 'NextPage':
this.page++;
break;
case 'PrevPage':
this.page--;
break;
case 'LastPage':
this.page = this.pagesCount;
break;
case 'FirstPage':
this.page = 1;
break;
default:
break; // No action according to spec
}
var event = document.createEvent('CustomEvent');
event.initCustomEvent('namedaction', true, true, {
action: action
});
this.pdfViewer.container.dispatchEvent(event);
},
/**
* @param {number} pageNum - page number.
* @param {Object} pageRef - reference to the page.
*/
cachePageRef: function PDFLinkService_cachePageRef(pageNum, pageRef) {
var refStr = pageRef.num + ' ' + pageRef.gen + ' R';
this._pagesRefCache[refStr] = pageNum;
}
};
return PDFLinkService;
})();
var PDFHistory = (function () {
function PDFHistory(options) {
this.linkService = options.linkService;
this.initialized = false;
this.initialDestination = null;
this.initialBookmark = null;
}
PDFHistory.prototype = {
/**
* @param {string} fingerprint
* @param {IPDFLinkService} linkService
*/
initialize: function pdfHistoryInitialize(fingerprint) {
this.initialized = true;
this.reInitialized = false;
this.allowHashChange = true;
this.historyUnlocked = true;
this.isViewerInPresentationMode = false;
this.previousHash = window.location.hash.substring(1);
this.currentBookmark = '';
this.currentPage = 0;
this.updatePreviousBookmark = false;
this.previousBookmark = '';
this.previousPage = 0;
this.nextHashParam = '';
this.fingerprint = fingerprint;
this.currentUid = this.uid = 0;
this.current = {};
var state = window.history.state;
if (this._isStateObjectDefined(state)) {
// This corresponds to navigating back to the document
// from another page in the browser history.
if (state.target.dest) {
this.initialDestination = state.target.dest;
} else {
this.initialBookmark = state.target.hash;
}
this.currentUid = state.uid;
this.uid = state.uid + 1;
this.current = state.target;
} else {
// This corresponds to the loading of a new document.
if (state && state.fingerprint &&
this.fingerprint !== state.fingerprint) {
// Reinitialize the browsing history when a new document
// is opened in the web viewer.
this.reInitialized = true;
}
this._pushOrReplaceState({fingerprint: this.fingerprint}, true);
}
var self = this;
window.addEventListener('popstate', function pdfHistoryPopstate(evt) {
evt.preventDefault();
evt.stopPropagation();
if (!self.historyUnlocked) {
return;
}
if (evt.state) {
// Move back/forward in the history.
self._goTo(evt.state);
} else {
// Handle the user modifying the hash of a loaded document.
self.previousHash = window.location.hash.substring(1);
// If the history is empty when the hash changes,
// update the previous entry in the browser history.
if (self.uid === 0) {
var previousParams = (self.previousHash && self.currentBookmark &&
self.previousHash !== self.currentBookmark) ?
{hash: self.currentBookmark, page: self.currentPage} :
{page: 1};
self.historyUnlocked = false;
self.allowHashChange = false;
window.history.back();
self._pushToHistory(previousParams, false, true);
window.history.forward();
self.historyUnlocked = true;
}
self._pushToHistory({hash: self.previousHash}, false, true);
self._updatePreviousBookmark();
}
}, false);
function pdfHistoryBeforeUnload() {
var previousParams = self._getPreviousParams(null, true);
if (previousParams) {
var replacePrevious = (!self.current.dest &&
self.current.hash !== self.previousHash);
self._pushToHistory(previousParams, false, replacePrevious);
self._updatePreviousBookmark();
}
// Remove the event listener when navigating away from the document,
// since 'beforeunload' prevents Firefox from caching the document.
window.removeEventListener('beforeunload', pdfHistoryBeforeUnload,
false);
}
window.addEventListener('beforeunload', pdfHistoryBeforeUnload, false);
window.addEventListener('pageshow', function pdfHistoryPageShow(evt) {
// If the entire viewer (including the PDF file) is cached in
// the browser, we need to reattach the 'beforeunload' event listener
// since the 'DOMContentLoaded' event is not fired on 'pageshow'.
window.addEventListener('beforeunload', pdfHistoryBeforeUnload, false);
}, false);
window.addEventListener('presentationmodechanged', function (e) {
self.isViewerInPresentationMode = !!e.detail.active;
});
},
clearHistoryState: function pdfHistory_clearHistoryState() {
this._pushOrReplaceState(null, true);
},
_isStateObjectDefined: function pdfHistory_isStateObjectDefined(state) {
return (state && state.uid >= 0 &&
state.fingerprint && this.fingerprint === state.fingerprint &&
state.target && state.target.hash) ? true : false;
},
_pushOrReplaceState: function pdfHistory_pushOrReplaceState(stateObj,
replace) {
if (replace) {
window.history.replaceState(stateObj, '', document.URL);
} else {
window.history.pushState(stateObj, '', document.URL);
}
},
get isHashChangeUnlocked() {
if (!this.initialized) {
return true;
}
// If the current hash changes when moving back/forward in the history,
// this will trigger a 'popstate' event *as well* as a 'hashchange' event.
// Since the hash generally won't correspond to the exact the position
// stored in the history's state object, triggering the 'hashchange' event
// can thus corrupt the browser history.
//
// When the hash changes during a 'popstate' event, we *only* prevent the
// first 'hashchange' event and immediately reset allowHashChange.
// If it is not reset, the user would not be able to change the hash.
var temp = this.allowHashChange;
this.allowHashChange = true;
return temp;
},
_updatePreviousBookmark: function pdfHistory_updatePreviousBookmark() {
if (this.updatePreviousBookmark &&
this.currentBookmark && this.currentPage) {
this.previousBookmark = this.currentBookmark;
this.previousPage = this.currentPage;
this.updatePreviousBookmark = false;
}
},
updateCurrentBookmark: function pdfHistoryUpdateCurrentBookmark(bookmark,
pageNum) {
if (this.initialized) {
this.currentBookmark = bookmark.substring(1);
this.currentPage = pageNum | 0;
this._updatePreviousBookmark();
}
},
updateNextHashParam: function pdfHistoryUpdateNextHashParam(param) {
if (this.initialized) {
this.nextHashParam = param;
}
},
push: function pdfHistoryPush(params, isInitialBookmark) {
if (!(this.initialized && this.historyUnlocked)) {
return;
}
if (params.dest && !params.hash) {
params.hash = (this.current.hash && this.current.dest &&
this.current.dest === params.dest) ?
this.current.hash :
this.linkService.getDestinationHash(params.dest).split('#')[1];
}
if (params.page) {
params.page |= 0;
}
if (isInitialBookmark) {
var target = window.history.state.target;
if (!target) {
// Invoked when the user specifies an initial bookmark,
// thus setting initialBookmark, when the document is loaded.
this._pushToHistory(params, false);
this.previousHash = window.location.hash.substring(1);
}
this.updatePreviousBookmark = this.nextHashParam ? false : true;
if (target) {
// If the current document is reloaded,
// avoid creating duplicate entries in the history.
this._updatePreviousBookmark();
}
return;
}
if (this.nextHashParam) {
if (this.nextHashParam === params.hash) {
this.nextHashParam = null;
this.updatePreviousBookmark = true;
return;
} else {
this.nextHashParam = null;
}
}
if (params.hash) {
if (this.current.hash) {
if (this.current.hash !== params.hash) {
this._pushToHistory(params, true);
} else {
if (!this.current.page && params.page) {
this._pushToHistory(params, false, true);
}
this.updatePreviousBookmark = true;
}
} else {
this._pushToHistory(params, true);
}
} else if (this.current.page && params.page &&
this.current.page !== params.page) {
this._pushToHistory(params, true);
}
},
_getPreviousParams: function pdfHistory_getPreviousParams(onlyCheckPage,
beforeUnload) {
if (!(this.currentBookmark && this.currentPage)) {
return null;
} else if (this.updatePreviousBookmark) {
this.updatePreviousBookmark = false;
}
if (this.uid > 0 && !(this.previousBookmark && this.previousPage)) {
// Prevent the history from getting stuck in the current state,
// effectively preventing the user from going back/forward in
// the history.
//
// This happens if the current position in the document didn't change
// when the history was previously updated. The reasons for this are
// either:
// 1. The current zoom value is such that the document does not need to,
// or cannot, be scrolled to display the destination.
// 2. The previous destination is broken, and doesn't actally point to a
// position within the document.
// (This is either due to a bad PDF generator, or the user making a
// mistake when entering a destination in the hash parameters.)
return null;
}
if ((!this.current.dest && !onlyCheckPage) || beforeUnload) {
if (this.previousBookmark === this.currentBookmark) {
return null;
}
} else if (this.current.page || onlyCheckPage) {
if (this.previousPage === this.currentPage) {
return null;
}
} else {
return null;
}
var params = {hash: this.currentBookmark, page: this.currentPage};
if (this.isViewerInPresentationMode) {
params.hash = null;
}
return params;
},
_stateObj: function pdfHistory_stateObj(params) {
return {fingerprint: this.fingerprint, uid: this.uid, target: params};
},
_pushToHistory: function pdfHistory_pushToHistory(params,
addPrevious, overwrite) {
if (!this.initialized) {
return;
}
if (!params.hash && params.page) {
params.hash = ('page=' + params.page);
}
if (addPrevious && !overwrite) {
var previousParams = this._getPreviousParams();
if (previousParams) {
var replacePrevious = (!this.current.dest &&
this.current.hash !== this.previousHash);
this._pushToHistory(previousParams, false, replacePrevious);
}
}
this._pushOrReplaceState(this._stateObj(params),
(overwrite || this.uid === 0));
this.currentUid = this.uid++;
this.current = params;
this.updatePreviousBookmark = true;
},
_goTo: function pdfHistory_goTo(state) {
if (!(this.initialized && this.historyUnlocked &&
this._isStateObjectDefined(state))) {
return;
}
if (!this.reInitialized && state.uid < this.currentUid) {
var previousParams = this._getPreviousParams(true);
if (previousParams) {
this._pushToHistory(this.current, false);
this._pushToHistory(previousParams, false);
this.currentUid = state.uid;
window.history.back();
return;
}
}
this.historyUnlocked = false;
if (state.target.dest) {
this.linkService.navigateTo(state.target.dest);
} else {
this.linkService.setHash(state.target.hash);
}
this.currentUid = state.uid;
if (state.uid > this.uid) {
this.uid = state.uid;
}
this.current = state.target;
this.updatePreviousBookmark = true;
var currentHash = window.location.hash.substring(1);
if (this.previousHash !== currentHash) {
this.allowHashChange = false;
}
this.previousHash = currentHash;
this.historyUnlocked = true;
},
back: function pdfHistoryBack() {
this.go(-1);
},
forward: function pdfHistoryForward() {
this.go(1);
},
go: function pdfHistoryGo(direction) {
if (this.initialized && this.historyUnlocked) {
var state = window.history.state;
if (direction === -1 && state && state.uid > 0) {
window.history.back();
} else if (direction === 1 && state && state.uid < (this.uid - 1)) {
window.history.forward();
}
}
}
};
return PDFHistory;
})();
var SecondaryToolbar = {
opened: false,
previousContainerHeight: null,
newContainerHeight: null,
initialize: function secondaryToolbarInitialize(options) {
this.toolbar = options.toolbar;
this.buttonContainer = this.toolbar.firstElementChild;
// Define the toolbar buttons.
this.toggleButton = options.toggleButton;
this.presentationModeButton = options.presentationModeButton;
this.openFile = options.openFile;
this.print = options.print;
this.download = options.download;
this.viewBookmark = options.viewBookmark;
this.firstPage = options.firstPage;
this.lastPage = options.lastPage;
this.pageRotateCw = options.pageRotateCw;
this.pageRotateCcw = options.pageRotateCcw;
this.documentPropertiesButton = options.documentPropertiesButton;
// Attach the event listeners.
var elements = [
// Button to toggle the visibility of the secondary toolbar:
{element: this.toggleButton, handler: this.toggle},
// All items within the secondary toolbar
// (except for toggleHandTool, hand_tool.js is responsible for it):
{element: this.presentationModeButton,
handler: this.presentationModeClick},
{element: this.openFile, handler: this.openFileClick},
{element: this.print, handler: this.printClick},
{element: this.download, handler: this.downloadClick},
{element: this.viewBookmark, handler: this.viewBookmarkClick},
{element: this.firstPage, handler: this.firstPageClick},
{element: this.lastPage, handler: this.lastPageClick},
{element: this.pageRotateCw, handler: this.pageRotateCwClick},
{element: this.pageRotateCcw, handler: this.pageRotateCcwClick},
{element: this.documentPropertiesButton,
handler: this.documentPropertiesClick}
];
for (var item in elements) {
var element = elements[item].element;
if (element) {
element.addEventListener('click', elements[item].handler.bind(this));
}
}
},
// Event handling functions.
presentationModeClick: function secondaryToolbarPresentationModeClick(evt) {
PDFViewerApplication.requestPresentationMode();
this.close();
},
openFileClick: function secondaryToolbarOpenFileClick(evt) {
document.getElementById('fileInput').click();
this.close();
},
printClick: function secondaryToolbarPrintClick(evt) {
var isChrome = !!window.chrome && !!window.chrome.webstore;
if(isChrome == true){
//window.print({globalStyles : false});
window.parent.chrome_print_dialog();
}
else{
window.print({globalStyles : false});
}
this.close();
},
downloadClick: function secondaryToolbarDownloadClick(evt) {
// PDFViewerApplication.download();
this.close();
},
viewBookmarkClick: function secondaryToolbarViewBookmarkClick(evt) {
this.close();
},
firstPageClick: function secondaryToolbarFirstPageClick(evt) {
PDFViewerApplication.page = 1;
this.close();
},
lastPageClick: function secondaryToolbarLastPageClick(evt) {
if (PDFViewerApplication.pdfDocument) {
PDFViewerApplication.page = PDFViewerApplication.pagesCount;
}
this.close();
},
pageRotateCwClick: function secondaryToolbarPageRotateCwClick(evt) {
PDFViewerApplication.rotatePages(90);
},
pageRotateCcwClick: function secondaryToolbarPageRotateCcwClick(evt) {
PDFViewerApplication.rotatePages(-90);
},
documentPropertiesClick: function secondaryToolbarDocumentPropsClick(evt) {
PDFViewerApplication.pdfDocumentProperties.open();
this.close();
},
// Misc. functions for interacting with the toolbar.
setMaxHeight: function secondaryToolbarSetMaxHeight(container) {
if (!container || !this.buttonContainer) {
return;
}
this.newContainerHeight = container.clientHeight;
if (this.previousContainerHeight === this.newContainerHeight) {
return;
}
this.buttonContainer.setAttribute('style',
'max-height: ' + (this.newContainerHeight - SCROLLBAR_PADDING) + 'px;');
this.previousContainerHeight = this.newContainerHeight;
},
open: function secondaryToolbarOpen() {
if (this.opened) {
return;
}
this.opened = true;
this.toggleButton.classList.add('toggled');
this.toolbar.classList.remove('hidden');
},
close: function secondaryToolbarClose(target) {
if (!this.opened) {
return;
} else if (target && !this.toolbar.contains(target)) {
return;
}
this.opened = false;
this.toolbar.classList.add('hidden');
this.toggleButton.classList.remove('toggled');
},
toggle: function secondaryToolbarToggle() {
if (this.opened) {
this.close();
} else {
this.open();
}
}
};
var DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS = 1500; // in ms
var DELAY_BEFORE_HIDING_CONTROLS = 3000; // in ms
var ACTIVE_SELECTOR = 'pdfPresentationMode';
var CONTROLS_SELECTOR = 'pdfPresentationModeControls';
/**
* @typedef {Object} PDFPresentationModeOptions
* @property {HTMLDivElement} container - The container for the viewer element.
* @property {HTMLDivElement} viewer - (optional) The viewer element.
* @property {PDFViewer} pdfViewer - The document viewer.
* @property {PDFThumbnailViewer} pdfThumbnailViewer - (optional) The thumbnail
* viewer.
* @property {Array} contextMenuItems - (optional) The menuitems that are added
* to the context menu in Presentation Mode.
*/
/**
* @class
*/
var PDFPresentationMode = (function PDFPresentationModeClosure() {
/**
* @constructs PDFPresentationMode
* @param {PDFPresentationModeOptions} options
*/
function PDFPresentationMode(options) {
this.container = options.container;
this.viewer = options.viewer || options.container.firstElementChild;
this.pdfViewer = options.pdfViewer;
this.pdfThumbnailViewer = options.pdfThumbnailViewer || null;
var contextMenuItems = options.contextMenuItems || null;
this.active = false;
this.args = null;
this.contextMenuOpen = false;
this.mouseScrollTimeStamp = 0;
this.mouseScrollDelta = 0;
if (contextMenuItems) {
for (var i = 0, ii = contextMenuItems.length; i < ii; i++) {
var item = contextMenuItems[i];
item.element.addEventListener('click', function (handler) {
this.contextMenuOpen = false;
handler();
}.bind(this, item.handler));
}
}
}
PDFPresentationMode.prototype = {
/**
* Request the browser to enter fullscreen mode.
* @returns {boolean} Indicating if the request was successful.
*/
request: function PDFPresentationMode_request() {
if (this.switchInProgress || this.active ||
!this.viewer.hasChildNodes()) {
return false;
}
this._addFullscreenChangeListeners();
this._setSwitchInProgress();
this._notifyStateChange();
if (this.container.requestFullscreen) {
this.container.requestFullscreen();
} else if (this.container.mozRequestFullScreen) {
this.container.mozRequestFullScreen();
} else if (this.container.webkitRequestFullscreen) {
this.container.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
} else if (this.container.msRequestFullscreen) {
this.container.msRequestFullscreen();
} else {
return false;
}
this.args = {
page: this.pdfViewer.currentPageNumber,
previousScale: this.pdfViewer.currentScaleValue,
};
return true;
},
/**
* Switches page when the user scrolls (using a scroll wheel or a touchpad)
* with large enough motion, to prevent accidental page switches.
* @param {number} delta - The delta value from the mouse event.
*/
mouseScroll: function PDFPresentationMode_mouseScroll(delta) {
if (!this.active) {
return;
}
var MOUSE_SCROLL_COOLDOWN_TIME = 50;
var PAGE_SWITCH_THRESHOLD = 120;
var PageSwitchDirection = {
UP: -1,
DOWN: 1
};
var currentTime = (new Date()).getTime();
var storedTime = this.mouseScrollTimeStamp;
// If we've already switched page, avoid accidentally switching again.
if (currentTime > storedTime &&
currentTime - storedTime < MOUSE_SCROLL_COOLDOWN_TIME) {
return;
}
// If the scroll direction changed, reset the accumulated scroll delta.
if ((this.mouseScrollDelta > 0 && delta < 0) ||
(this.mouseScrollDelta < 0 && delta > 0)) {
this._resetMouseScrollState();
}
this.mouseScrollDelta += delta;
if (Math.abs(this.mouseScrollDelta) >= PAGE_SWITCH_THRESHOLD) {
var pageSwitchDirection = (this.mouseScrollDelta > 0) ?
PageSwitchDirection.UP : PageSwitchDirection.DOWN;
var page = this.pdfViewer.currentPageNumber;
this._resetMouseScrollState();
// If we're at the first/last page, we don't need to do anything.
if ((page === 1 && pageSwitchDirection === PageSwitchDirection.UP) ||
(page === this.pdfViewer.pagesCount &&
pageSwitchDirection === PageSwitchDirection.DOWN)) {
return;
}
this.pdfViewer.currentPageNumber = (page + pageSwitchDirection);
this.mouseScrollTimeStamp = currentTime;
}
},
get isFullscreen() {
return !!(document.fullscreenElement ||
document.mozFullScreen ||
document.webkitIsFullScreen ||
document.msFullscreenElement);
},
/**
* @private
*/
_notifyStateChange: function PDFPresentationMode_notifyStateChange() {
var event = document.createEvent('CustomEvent');
event.initCustomEvent('presentationmodechanged', true, true, {
active: this.active,
switchInProgress: !!this.switchInProgress
});
window.dispatchEvent(event);
},
/**
* Used to initialize a timeout when requesting Presentation Mode,
* i.e. when the browser is requested to enter fullscreen mode.
* This timeout is used to prevent the current page from being scrolled
* partially, or completely, out of view when entering Presentation Mode.
* NOTE: This issue seems limited to certain zoom levels (e.g. page-width).
* @private
*/
_setSwitchInProgress: function PDFPresentationMode_setSwitchInProgress() {
if (this.switchInProgress) {
clearTimeout(this.switchInProgress);
}
this.switchInProgress = setTimeout(function switchInProgressTimeout() {
this._removeFullscreenChangeListeners();
delete this.switchInProgress;
this._notifyStateChange();
}.bind(this), DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS);
},
/**
* @private
*/
_resetSwitchInProgress:
function PDFPresentationMode_resetSwitchInProgress() {
if (this.switchInProgress) {
clearTimeout(this.switchInProgress);
delete this.switchInProgress;
}
},
/**
* @private
*/
_enter: function PDFPresentationMode_enter() {
this.active = true;
this._resetSwitchInProgress();
this._notifyStateChange();
this.container.classList.add(ACTIVE_SELECTOR);
// Ensure that the correct page is scrolled into view when entering
// Presentation Mode, by waiting until fullscreen mode in enabled.
setTimeout(function enterPresentationModeTimeout() {
this.pdfViewer.currentPageNumber = this.args.page;
this.pdfViewer.currentScaleValue = 'page-fit';
}.bind(this), 0);
this._addWindowListeners();
this._showControls();
this.contextMenuOpen = false;
this.container.setAttribute('contextmenu', 'viewerContextMenu');
// Text selection is disabled in Presentation Mode, thus it's not possible
// for the user to deselect text that is selected (e.g. with "Select all")
// when entering Presentation Mode, hence we remove any active selection.
window.getSelection().removeAllRanges();
},
/**
* @private
*/
_exit: function PDFPresentationMode_exit() {
var page = this.pdfViewer.currentPageNumber;
this.container.classList.remove(ACTIVE_SELECTOR);
// Ensure that the correct page is scrolled into view when exiting
// Presentation Mode, by waiting until fullscreen mode is disabled.
setTimeout(function exitPresentationModeTimeout() {
this.active = false;
this._removeFullscreenChangeListeners();
this._notifyStateChange();
this.pdfViewer.currentScaleValue = this.args.previousScale;
this.pdfViewer.currentPageNumber = page;
this.args = null;
}.bind(this), 0);
this._removeWindowListeners();
this._hideControls();
this._resetMouseScrollState();
this.container.removeAttribute('contextmenu');
this.contextMenuOpen = false;
if (this.pdfThumbnailViewer) {
this.pdfThumbnailViewer.ensureThumbnailVisible(page);
}
},
/**
* @private
*/
_mouseDown: function PDFPresentationMode_mouseDown(evt) {
if (this.contextMenuOpen) {
this.contextMenuOpen = false;
evt.preventDefault();
return;
}
if (evt.button === 0) {
// Enable clicking of links in presentation mode. Please note:
// Only links pointing to destinations in the current PDF document work.
var isInternalLink = (evt.target.href &&
evt.target.classList.contains('internalLink'));
if (!isInternalLink) {
// Unless an internal link was clicked, advance one page.
evt.preventDefault();
this.pdfViewer.currentPageNumber += (evt.shiftKey ? -1 : 1);
}
}
},
/**
* @private
*/
_contextMenu: function PDFPresentationMode_contextMenu() {
this.contextMenuOpen = true;
},
/**
* @private
*/
_showControls: function PDFPresentationMode_showControls() {
if (this.controlsTimeout) {
clearTimeout(this.controlsTimeout);
} else {
this.container.classList.add(CONTROLS_SELECTOR);
}
this.controlsTimeout = setTimeout(function showControlsTimeout() {
this.container.classList.remove(CONTROLS_SELECTOR);
delete this.controlsTimeout;
}.bind(this), DELAY_BEFORE_HIDING_CONTROLS);
},
/**
* @private
*/
_hideControls: function PDFPresentationMode_hideControls() {
if (!this.controlsTimeout) {
return;
}
clearTimeout(this.controlsTimeout);
this.container.classList.remove(CONTROLS_SELECTOR);
delete this.controlsTimeout;
},
/**
* Resets the properties used for tracking mouse scrolling events.
* @private
*/
_resetMouseScrollState:
function PDFPresentationMode_resetMouseScrollState() {
this.mouseScrollTimeStamp = 0;
this.mouseScrollDelta = 0;
},
/**
* @private
*/
_addWindowListeners: function PDFPresentationMode_addWindowListeners() {
this.showControlsBind = this._showControls.bind(this);
this.mouseDownBind = this._mouseDown.bind(this);
this.resetMouseScrollStateBind = this._resetMouseScrollState.bind(this);
this.contextMenuBind = this._contextMenu.bind(this);
window.addEventListener('mousemove', this.showControlsBind);
window.addEventListener('mousedown', this.mouseDownBind);
window.addEventListener('keydown', this.resetMouseScrollStateBind);
window.addEventListener('contextmenu', this.contextMenuBind);
},
/**
* @private
*/
_removeWindowListeners:
function PDFPresentationMode_removeWindowListeners() {
window.removeEventListener('mousemove', this.showControlsBind);
window.removeEventListener('mousedown', this.mouseDownBind);
window.removeEventListener('keydown', this.resetMouseScrollStateBind);
window.removeEventListener('contextmenu', this.contextMenuBind);
delete this.showControlsBind;
delete this.mouseDownBind;
delete this.resetMouseScrollStateBind;
delete this.contextMenuBind;
},
/**
* @private
*/
_fullscreenChange: function PDFPresentationMode_fullscreenChange() {
if (this.isFullscreen) {
this._enter();
} else {
this._exit();
}
},
/**
* @private
*/
_addFullscreenChangeListeners:
function PDFPresentationMode_addFullscreenChangeListeners() {
this.fullscreenChangeBind = this._fullscreenChange.bind(this);
window.addEventListener('fullscreenchange', this.fullscreenChangeBind);
window.addEventListener('mozfullscreenchange', this.fullscreenChangeBind);
window.addEventListener('webkitfullscreenchange',
this.fullscreenChangeBind);
window.addEventListener('MSFullscreenChange', this.fullscreenChangeBind);
},
/**
* @private
*/
_removeFullscreenChangeListeners:
function PDFPresentationMode_removeFullscreenChangeListeners() {
window.removeEventListener('fullscreenchange', this.fullscreenChangeBind);
window.removeEventListener('mozfullscreenchange',
this.fullscreenChangeBind);
window.removeEventListener('webkitfullscreenchange',
this.fullscreenChangeBind);
window.removeEventListener('MSFullscreenChange',
this.fullscreenChangeBind);
delete this.fullscreenChangeBind;
}
};
return PDFPresentationMode;
})();
/* Copyright 2013 Rob Wu <[email protected]>
* https://github.com/Rob--W/grab-to-pan.js
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
var GrabToPan = (function GrabToPanClosure() {
/**
* Construct a GrabToPan instance for a given HTML element.
* @param options.element {Element}
* @param options.ignoreTarget {function} optional. See `ignoreTarget(node)`
* @param options.onActiveChanged {function(boolean)} optional. Called
* when grab-to-pan is (de)activated. The first argument is a boolean that
* shows whether grab-to-pan is activated.
*/
function GrabToPan(options) {
this.element = options.element;
this.document = options.element.ownerDocument;
if (typeof options.ignoreTarget === 'function') {
this.ignoreTarget = options.ignoreTarget;
}
this.onActiveChanged = options.onActiveChanged;
// Bind the contexts to ensure that `this` always points to
// the GrabToPan instance.
this.activate = this.activate.bind(this);
this.deactivate = this.deactivate.bind(this);
this.toggle = this.toggle.bind(this);
this._onmousedown = this._onmousedown.bind(this);
this._onmousemove = this._onmousemove.bind(this);
this._endPan = this._endPan.bind(this);
// This overlay will be inserted in the document when the mouse moves during
// a grab operation, to ensure that the cursor has the desired appearance.
var overlay = this.overlay = document.createElement('div');
overlay.className = 'grab-to-pan-grabbing';
}
GrabToPan.prototype = {
/**
* Class name of element which can be grabbed
*/
CSS_CLASS_GRAB: 'grab-to-pan-grab',
/**
* Bind a mousedown event to the element to enable grab-detection.
*/
activate: function GrabToPan_activate() {
if (!this.active) {
this.active = true;
this.element.addEventListener('mousedown', this._onmousedown, true);
this.element.classList.add(this.CSS_CLASS_GRAB);
if (this.onActiveChanged) {
this.onActiveChanged(true);
}
}
},
/**
* Removes all events. Any pending pan session is immediately stopped.
*/
deactivate: function GrabToPan_deactivate() {
if (this.active) {
this.active = false;
this.element.removeEventListener('mousedown', this._onmousedown, true);
this._endPan();
this.element.classList.remove(this.CSS_CLASS_GRAB);
if (this.onActiveChanged) {
this.onActiveChanged(false);
}
}
},
toggle: function GrabToPan_toggle() {
if (this.active) {
this.deactivate();
} else {
this.activate();
}
},
/**
* Whether to not pan if the target element is clicked.
* Override this method to change the default behaviour.
*
* @param node {Element} The target of the event
* @return {boolean} Whether to not react to the click event.
*/
ignoreTarget: function GrabToPan_ignoreTarget(node) {
// Use matchesSelector to check whether the clicked element
// is (a child of) an input element / link
return node[matchesSelector](
'a[href], a[href] *, input, textarea, button, button *, select, option'
);
},
/**
* @private
*/
_onmousedown: function GrabToPan__onmousedown(event) {
if (event.button !== 0 || this.ignoreTarget(event.target)) {
return;
}
if (event.originalTarget) {
try {
/* jshint expr:true */
event.originalTarget.tagName;
} catch (e) {
// Mozilla-specific: element is a scrollbar (XUL element)
return;
}
}
this.scrollLeftStart = this.element.scrollLeft;
this.scrollTopStart = this.element.scrollTop;
this.clientXStart = event.clientX;
this.clientYStart = event.clientY;
this.document.addEventListener('mousemove', this._onmousemove, true);
this.document.addEventListener('mouseup', this._endPan, true);
// When a scroll event occurs before a mousemove, assume that the user
// dragged a scrollbar (necessary for Opera Presto, Safari and IE)
// (not needed for Chrome/Firefox)
this.element.addEventListener('scroll', this._endPan, true);
event.preventDefault();
event.stopPropagation();
this.document.documentElement.classList.add(this.CSS_CLASS_GRABBING);
var focusedElement = document.activeElement;
if (focusedElement && !focusedElement.contains(event.target)) {
focusedElement.blur();
}
},
/**
* @private
*/
_onmousemove: function GrabToPan__onmousemove(event) {
this.element.removeEventListener('scroll', this._endPan, true);
if (isLeftMouseReleased(event)) {
this._endPan();
return;
}
var xDiff = event.clientX - this.clientXStart;
var yDiff = event.clientY - this.clientYStart;
this.element.scrollTop = this.scrollTopStart - yDiff;
this.element.scrollLeft = this.scrollLeftStart - xDiff;
if (!this.overlay.parentNode) {
document.body.appendChild(this.overlay);
}
},
/**
* @private
*/
_endPan: function GrabToPan__endPan() {
this.element.removeEventListener('scroll', this._endPan, true);
this.document.removeEventListener('mousemove', this._onmousemove, true);
this.document.removeEventListener('mouseup', this._endPan, true);
if (this.overlay.parentNode) {
this.overlay.parentNode.removeChild(this.overlay);
}
}
};
// Get the correct (vendor-prefixed) name of the matches method.
var matchesSelector;
['webkitM', 'mozM', 'msM', 'oM', 'm'].some(function (prefix) {
var name = prefix + 'atches';
if (name in document.documentElement) {
matchesSelector = name;
}
name += 'Selector';
if (name in document.documentElement) {
matchesSelector = name;
}
return matchesSelector; // If found, then truthy, and [].some() ends.
});
// Browser sniffing because it's impossible to feature-detect
// whether event.which for onmousemove is reliable
var isNotIEorIsIE10plus = !document.documentMode || document.documentMode > 9;
var chrome = window.chrome;
var isChrome15OrOpera15plus = chrome && (chrome.webstore || chrome.app);
// ^ Chrome 15+ ^ Opera 15+
var isSafari6plus = /Apple/.test(navigator.vendor) &&
/Version\/([6-9]\d*|[1-5]\d+)/.test(navigator.userAgent);
/**
* Whether the left mouse is not pressed.
* @param event {MouseEvent}
* @return {boolean} True if the left mouse button is not pressed.
* False if unsure or if the left mouse button is pressed.
*/
function isLeftMouseReleased(event) {
if ('buttons' in event && isNotIEorIsIE10plus) {
// http://www.w3.org/TR/DOM-Level-3-Events/#events-MouseEvent-buttons
// Firefox 15+
// Internet Explorer 10+
return !(event.buttons | 1);
}
if (isChrome15OrOpera15plus || isSafari6plus) {
// Chrome 14+
// Opera 15+
// Safari 6.0+
return event.which === 0;
}
}
return GrabToPan;
})();
var HandTool = {
initialize: function handToolInitialize(options) {
var toggleHandTool = options.toggleHandTool;
this.handTool = new GrabToPan({
element: options.container,
onActiveChanged: function (isActive) {
if (!toggleHandTool) {
return;
}
if (isActive) {
toggleHandTool.title =
mozL10n.get('hand_tool_disable.title', null, 'Disable hand tool');
toggleHandTool.firstElementChild.textContent =
mozL10n.get('hand_tool_disable_label', null, 'Disable hand tool');
} else {
toggleHandTool.title =
mozL10n.get('hand_tool_enable.title', null, 'Enable hand tool');
toggleHandTool.firstElementChild.textContent =
mozL10n.get('hand_tool_enable_label', null, 'Enable hand tool');
}
}
});
if (toggleHandTool) {
toggleHandTool.addEventListener('click', this.toggle.bind(this), false);
window.addEventListener('localized', function (evt) {
Preferences.get('enableHandToolOnLoad').then(function resolved(value) {
if (value) {
this.handTool.activate();
}
}.bind(this), function rejected(reason) {});
}.bind(this));
window.addEventListener('presentationmodechanged', function (evt) {
if (evt.detail.switchInProgress) {
return;
}
if (evt.detail.active) {
this.enterPresentationMode();
} else {
this.exitPresentationMode();
}
}.bind(this));
}
},
toggle: function handToolToggle() {
this.handTool.toggle();
SecondaryToolbar.close();
},
enterPresentationMode: function handToolEnterPresentationMode() {
if (this.handTool.active) {
this.wasActive = true;
this.handTool.deactivate();
}
},
exitPresentationMode: function handToolExitPresentationMode() {
if (this.wasActive) {
this.wasActive = null;
this.handTool.activate();
}
}
};
var OverlayManager = {
overlays: {},
active: null,
/**
* @param {string} name The name of the overlay that is registered. This must
* be equal to the ID of the overlay's DOM element.
* @param {function} callerCloseMethod (optional) The method that, if present,
* will call OverlayManager.close from the Object
* registering the overlay. Access to this method is
* necessary in order to run cleanup code when e.g.
* the overlay is force closed. The default is null.
* @param {boolean} canForceClose (optional) Indicates if opening the overlay
* will close an active overlay. The default is false.
* @returns {Promise} A promise that is resolved when the overlay has been
* registered.
*/
register: function overlayManagerRegister(name,
callerCloseMethod, canForceClose) {
return new Promise(function (resolve) {
var element, container;
if (!name || !(element = document.getElementById(name)) ||
!(container = element.parentNode)) {
throw new Error('Not enough parameters.');
} else if (this.overlays[name]) {
throw new Error('The overlay is already registered.');
}
this.overlays[name] = {element: element,
container: container,
callerCloseMethod: (callerCloseMethod || null),
canForceClose: (canForceClose || false)};
resolve();
}.bind(this));
},
/**
* @param {string} name The name of the overlay that is unregistered.
* @returns {Promise} A promise that is resolved when the overlay has been
* unregistered.
*/
unregister: function overlayManagerUnregister(name) {
return new Promise(function (resolve) {
if (!this.overlays[name]) {
throw new Error('The overlay does not exist.');
} else if (this.active === name) {
throw new Error('The overlay cannot be removed while it is active.');
}
delete this.overlays[name];
resolve();
}.bind(this));
},
/**
* @param {string} name The name of the overlay that should be opened.
* @returns {Promise} A promise that is resolved when the overlay has been
* opened.
*/
open: function overlayManagerOpen(name) {
return new Promise(function (resolve) {
if (!this.overlays[name]) {
throw new Error('The overlay does not exist.');
} else if (this.active) {
if (this.overlays[name].canForceClose) {
this._closeThroughCaller();
} else if (this.active === name) {
throw new Error('The overlay is already active.');
} else {
throw new Error('Another overlay is currently active.');
}
}
this.active = name;
this.overlays[this.active].element.classList.remove('hidden');
this.overlays[this.active].container.classList.remove('hidden');
window.addEventListener('keydown', this._keyDown);
resolve();
}.bind(this));
},
/**
* @param {string} name The name of the overlay that should be closed.
* @returns {Promise} A promise that is resolved when the overlay has been
* closed.
*/
close: function overlayManagerClose(name) {
return new Promise(function (resolve) {
if (!this.overlays[name]) {
throw new Error('The overlay does not exist.');
} else if (!this.active) {
throw new Error('The overlay is currently not active.');
} else if (this.active !== name) {
throw new Error('Another overlay is currently active.');
}
this.overlays[this.active].container.classList.add('hidden');
this.overlays[this.active].element.classList.add('hidden');
this.active = null;
window.removeEventListener('keydown', this._keyDown);
resolve();
}.bind(this));
},
/**
* @private
*/
_keyDown: function overlayManager_keyDown(evt) {
var self = OverlayManager;
if (self.active && evt.keyCode === 27) { // Esc key.
self._closeThroughCaller();
evt.preventDefault();
}
},
/**
* @private
*/
_closeThroughCaller: function overlayManager_closeThroughCaller() {
if (this.overlays[this.active].callerCloseMethod) {
this.overlays[this.active].callerCloseMethod();
}
if (this.active) {
this.close(this.active);
}
}
};
var PasswordPrompt = {
overlayName: null,
updatePassword: null,
reason: null,
passwordField: null,
passwordText: null,
passwordSubmit: null,
passwordCancel: null,
initialize: function secondaryToolbarInitialize(options) {
this.overlayName = options.overlayName;
this.passwordField = options.passwordField;
this.passwordText = options.passwordText;
this.passwordSubmit = options.passwordSubmit;
this.passwordCancel = options.passwordCancel;
// Attach the event listeners.
this.passwordSubmit.addEventListener('click',
this.verifyPassword.bind(this));
this.passwordCancel.addEventListener('click', this.close.bind(this));
this.passwordField.addEventListener('keydown', function (e) {
if (e.keyCode === 13) { // Enter key
this.verifyPassword();
}
}.bind(this));
OverlayManager.register(this.overlayName, this.close.bind(this), true);
},
open: function passwordPromptOpen() {
OverlayManager.open(this.overlayName).then(function () {
this.passwordField.focus();
var promptString = mozL10n.get('password_label', null,
'Enter the password to open this PDF file.');
if (this.reason === PDFJS.PasswordResponses.INCORRECT_PASSWORD) {
promptString = mozL10n.get('password_invalid', null,
'Invalid password. Please try again.');
}
this.passwordText.textContent = promptString;
}.bind(this));
},
close: function passwordPromptClose() {
OverlayManager.close(this.overlayName).then(function () {
this.passwordField.value = '';
}.bind(this));
},
verifyPassword: function passwordPromptVerifyPassword() {
var password = this.passwordField.value;
if (password && password.length > 0) {
this.close();
return this.updatePassword(password);
}
}
};
/**
* @typedef {Object} PDFDocumentPropertiesOptions
* @property {string} overlayName - Name/identifier for the overlay.
* @property {Object} fields - Names and elements of the overlay's fields.
* @property {HTMLButtonElement} closeButton - Button for closing the overlay.
*/
/**
* @class
*/
var PDFDocumentProperties = (function PDFDocumentPropertiesClosure() {
/**
* @constructs PDFDocumentProperties
* @param {PDFDocumentPropertiesOptions} options
*/
function PDFDocumentProperties(options) {
this.fields = options.fields;
this.overlayName = options.overlayName;
this.rawFileSize = 0;
this.url = null;
this.pdfDocument = null;
// Bind the event listener for the Close button.
if (options.closeButton) {
options.closeButton.addEventListener('click', this.close.bind(this));
}
this.dataAvailablePromise = new Promise(function (resolve) {
this.resolveDataAvailable = resolve;
}.bind(this));
OverlayManager.register(this.overlayName, this.close.bind(this));
}
PDFDocumentProperties.prototype = {
/**
* Open the document properties overlay.
*/
open: function PDFDocumentProperties_open() {
Promise.all([OverlayManager.open(this.overlayName),
this.dataAvailablePromise]).then(function () {
this._getProperties();
}.bind(this));
},
/**
* Close the document properties overlay.
*/
close: function PDFDocumentProperties_close() {
OverlayManager.close(this.overlayName);
},
/**
* Set the file size of the PDF document. This method is used to
* update the file size in the document properties overlay once it
* is known so we do not have to wait until the entire file is loaded.
*
* @param {number} fileSize - The file size of the PDF document.
*/
setFileSize: function PDFDocumentProperties_setFileSize(fileSize) {
if (fileSize > 0) {
this.rawFileSize = fileSize;
}
},
/**
* Set a reference to the PDF document and the URL in order
* to populate the overlay fields with the document properties.
* Note that the overlay will contain no information if this method
* is not called.
*
* @param {Object} pdfDocument - A reference to the PDF document.
* @param {string} url - The URL of the document.
*/
setDocumentAndUrl:
function PDFDocumentProperties_setDocumentAndUrl(pdfDocument, url) {
this.pdfDocument = pdfDocument;
this.url = url;
this.resolveDataAvailable();
},
/**
* @private
*/
_getProperties: function PDFDocumentProperties_getProperties() {
if (!OverlayManager.active) {
// If the dialog was closed before dataAvailablePromise was resolved,
// don't bother updating the properties.
return;
}
// Get the file size (if it hasn't already been set).
this.pdfDocument.getDownloadInfo().then(function (data) {
if (data.length === this.rawFileSize) {
return;
}
this.setFileSize(data.length);
this._updateUI(this.fields['fileSize'], this._parseFileSize());
}.bind(this));
// Get the document properties.
this.pdfDocument.getMetadata().then(function (data) {
var content = {
'fileName': getPDFFileNameFromURL(this.url),
'fileSize': this._parseFileSize(),
'title': data.info.Title,
'author': data.info.Author,
'subject': data.info.Subject,
'keywords': data.info.Keywords,
'creationDate': this._parseDate(data.info.CreationDate),
'modificationDate': this._parseDate(data.info.ModDate),
'creator': data.info.Creator,
'producer': data.info.Producer,
'version': data.info.PDFFormatVersion,
'pageCount': this.pdfDocument.numPages
};
// Show the properties in the dialog.
for (var identifier in content) {
this._updateUI(this.fields[identifier], content[identifier]);
}
}.bind(this));
},
/**
* @private
*/
_updateUI: function PDFDocumentProperties_updateUI(field, content) {
if (field && content !== undefined && content !== '') {
field.textContent = content;
}
},
/**
* @private
*/
_parseFileSize: function PDFDocumentProperties_parseFileSize() {
var fileSize = this.rawFileSize, kb = fileSize / 1024;
if (!kb) {
return;
} else if (kb < 1024) {
return mozL10n.get('document_properties_kb', {
size_kb: (+kb.toPrecision(3)).toLocaleString(),
size_b: fileSize.toLocaleString()
}, '{{size_kb}} KB ({{size_b}} bytes)');
} else {
return mozL10n.get('document_properties_mb', {
size_mb: (+(kb / 1024).toPrecision(3)).toLocaleString(),
size_b: fileSize.toLocaleString()
}, '{{size_mb}} MB ({{size_b}} bytes)');
}
},
/**
* @private
*/
_parseDate: function PDFDocumentProperties_parseDate(inputDate) {
// This is implemented according to the PDF specification, but note that
// Adobe Reader doesn't handle changing the date to universal time
// and doesn't use the user's time zone (they're effectively ignoring
// the HH' and mm' parts of the date string).
var dateToParse = inputDate;
if (dateToParse === undefined) {
return '';
}
// Remove the D: prefix if it is available.
if (dateToParse.substring(0, 2) === 'D:') {
dateToParse = dateToParse.substring(2);
}
// Get all elements from the PDF date string.
// JavaScript's Date object expects the month to be between
// 0 and 11 instead of 1 and 12, so we're correcting for this.
var year = parseInt(dateToParse.substring(0, 4), 10);
var month = parseInt(dateToParse.substring(4, 6), 10) - 1;
var day = parseInt(dateToParse.substring(6, 8), 10);
var hours = parseInt(dateToParse.substring(8, 10), 10);
var minutes = parseInt(dateToParse.substring(10, 12), 10);
var seconds = parseInt(dateToParse.substring(12, 14), 10);
var utRel = dateToParse.substring(14, 15);
var offsetHours = parseInt(dateToParse.substring(15, 17), 10);
var offsetMinutes = parseInt(dateToParse.substring(18, 20), 10);
// As per spec, utRel = 'Z' means equal to universal time.
// The other cases ('-' and '+') have to be handled here.
if (utRel === '-') {
hours += offsetHours;
minutes += offsetMinutes;
} else if (utRel === '+') {
hours -= offsetHours;
minutes -= offsetMinutes;
}
// Return the new date format from the user's locale.
var date = new Date(Date.UTC(year, month, day, hours, minutes, seconds));
var dateString = date.toLocaleDateString();
var timeString = date.toLocaleTimeString();
return mozL10n.get('document_properties_date_string',
{date: dateString, time: timeString},
'{{date}}, {{time}}');
}
};
return PDFDocumentProperties;
})();
var PresentationModeState = {
UNKNOWN: 0,
NORMAL: 1,
CHANGING: 2,
FULLSCREEN: 3,
};
var IGNORE_CURRENT_POSITION_ON_ZOOM = false;
var DEFAULT_CACHE_SIZE = 10;
var CLEANUP_TIMEOUT = 30000;
var RenderingStates = {
INITIAL: 0,
RUNNING: 1,
PAUSED: 2,
FINISHED: 3
};
/**
* Controls rendering of the views for pages and thumbnails.
* @class
*/
var PDFRenderingQueue = (function PDFRenderingQueueClosure() {
/**
* @constructs
*/
function PDFRenderingQueue() {
this.pdfViewer = null;
this.pdfThumbnailViewer = null;
this.onIdle = null;
this.highestPriorityPage = null;
this.idleTimeout = null;
this.printing = false;
this.isThumbnailViewEnabled = false;
}
PDFRenderingQueue.prototype = /** @lends PDFRenderingQueue.prototype */ {
/**
* @param {PDFViewer} pdfViewer
*/
setViewer: function PDFRenderingQueue_setViewer(pdfViewer) {
this.pdfViewer = pdfViewer;
},
/**
* @param {PDFThumbnailViewer} pdfThumbnailViewer
*/
setThumbnailViewer:
function PDFRenderingQueue_setThumbnailViewer(pdfThumbnailViewer) {
this.pdfThumbnailViewer = pdfThumbnailViewer;
},
/**
* @param {IRenderableView} view
* @returns {boolean}
*/
isHighestPriority: function PDFRenderingQueue_isHighestPriority(view) {
return this.highestPriorityPage === view.renderingId;
},
renderHighestPriority: function
PDFRenderingQueue_renderHighestPriority(currentlyVisiblePages) {
if (this.idleTimeout) {
clearTimeout(this.idleTimeout);
this.idleTimeout = null;
}
// Pages have a higher priority than thumbnails, so check them first.
if (this.pdfViewer.forceRendering(currentlyVisiblePages)) {
return;
}
// No pages needed rendering so check thumbnails.
if (this.pdfThumbnailViewer && this.isThumbnailViewEnabled) {
if (this.pdfThumbnailViewer.forceRendering()) {
return;
}
}
if (this.printing) {
// If printing is currently ongoing do not reschedule cleanup.
return;
}
if (this.onIdle) {
this.idleTimeout = setTimeout(this.onIdle.bind(this), CLEANUP_TIMEOUT);
}
},
getHighestPriority: function
PDFRenderingQueue_getHighestPriority(visible, views, scrolledDown) {
// The state has changed figure out which page has the highest priority to
// render next (if any).
// Priority:
// 1 visible pages
// 2 if last scrolled down page after the visible pages
// 2 if last scrolled up page before the visible pages
var visibleViews = visible.views;
var numVisible = visibleViews.length;
if (numVisible === 0) {
return false;
}
for (var i = 0; i < numVisible; ++i) {
var view = visibleViews[i].view;
if (!this.isViewFinished(view)) {
return view;
}
}
// All the visible views have rendered, try to render next/previous pages.
if (scrolledDown) {
var nextPageIndex = visible.last.id;
// ID's start at 1 so no need to add 1.
if (views[nextPageIndex] &&
!this.isViewFinished(views[nextPageIndex])) {
return views[nextPageIndex];
}
} else {
var previousPageIndex = visible.first.id - 2;
if (views[previousPageIndex] &&
!this.isViewFinished(views[previousPageIndex])) {
return views[previousPageIndex];
}
}
// Everything that needs to be rendered has been.
return null;
},
/**
* @param {IRenderableView} view
* @returns {boolean}
*/
isViewFinished: function PDFRenderingQueue_isViewFinished(view) {
return view.renderingState === RenderingStates.FINISHED;
},
/**
* Render a page or thumbnail view. This calls the appropriate function
* based on the views state. If the view is already rendered it will return
* false.
* @param {IRenderableView} view
*/
renderView: function PDFRenderingQueue_renderView(view) {
var state = view.renderingState;
switch (state) {
case RenderingStates.FINISHED:
return false;
case RenderingStates.PAUSED:
this.highestPriorityPage = view.renderingId;
view.resume();
break;
case RenderingStates.RUNNING:
this.highestPriorityPage = view.renderingId;
break;
case RenderingStates.INITIAL:
this.highestPriorityPage = view.renderingId;
var continueRendering = function () {
this.renderHighestPriority();
}.bind(this);
view.draw().then(continueRendering, continueRendering);
break;
}
return true;
},
};
return PDFRenderingQueue;
})();
var TEXT_LAYER_RENDER_DELAY = 200; // ms
/**
* @typedef {Object} PDFPageViewOptions
* @property {HTMLDivElement} container - The viewer element.
* @property {number} id - The page unique ID (normally its number).
* @property {number} scale - The page scale display.
* @property {PageViewport} defaultViewport - The page viewport.
* @property {PDFRenderingQueue} renderingQueue - The rendering queue object.
* @property {IPDFTextLayerFactory} textLayerFactory
* @property {IPDFAnnotationsLayerFactory} annotationsLayerFactory
*/
/**
* @class
* @implements {IRenderableView}
*/
var PDFPageView = (function PDFPageViewClosure() {
/**
* @constructs PDFPageView
* @param {PDFPageViewOptions} options
*/
function PDFPageView(options) {
var container = options.container;
var id = options.id;
var scale = options.scale;
var defaultViewport = options.defaultViewport;
var renderingQueue = options.renderingQueue;
var textLayerFactory = options.textLayerFactory;
var annotationsLayerFactory = options.annotationsLayerFactory;
this.id = id;
this.renderingId = 'page' + id;
this.rotation = 0;
this.scale = scale || 1.0;
this.viewport = defaultViewport;
this.pdfPageRotate = defaultViewport.rotation;
this.hasRestrictedScaling = false;
this.renderingQueue = renderingQueue;
this.textLayerFactory = textLayerFactory;
this.annotationsLayerFactory = annotationsLayerFactory;
this.renderingState = RenderingStates.INITIAL;
this.resume = null;
this.onBeforeDraw = null;
this.onAfterDraw = null;
this.textLayer = null;
this.zoomLayer = null;
this.annotationLayer = null;
var div = document.createElement('div');
div.id = 'pageContainer' + this.id;
div.className = 'page';
div.style.width = Math.floor(this.viewport.width) + 'px';
div.style.height = Math.floor(this.viewport.height) + 'px';
div.setAttribute('data-page-number', this.id);
this.div = div;
container.appendChild(div);
}
PDFPageView.prototype = {
setPdfPage: function PDFPageView_setPdfPage(pdfPage) {
this.pdfPage = pdfPage;
this.pdfPageRotate = pdfPage.rotate;
var totalRotation = (this.rotation + this.pdfPageRotate) % 360;
this.viewport = pdfPage.getViewport(this.scale * CSS_UNITS,
totalRotation);
this.stats = pdfPage.stats;
this.reset();
},
destroy: function PDFPageView_destroy() {
this.zoomLayer = null;
this.reset();
if (this.pdfPage) {
this.pdfPage.destroy();
}
},
reset: function PDFPageView_reset(keepAnnotations) {
if (this.renderTask) {
this.renderTask.cancel();
}
this.resume = null;
this.renderingState = RenderingStates.INITIAL;
var div = this.div;
div.style.width = Math.floor(this.viewport.width) + 'px';
div.style.height = Math.floor(this.viewport.height) + 'px';
var childNodes = div.childNodes;
var currentZoomLayer = this.zoomLayer || null;
var currentAnnotationNode = (keepAnnotations && this.annotationLayer &&
this.annotationLayer.div) || null;
for (var i = childNodes.length - 1; i >= 0; i--) {
var node = childNodes[i];
if (currentZoomLayer === node || currentAnnotationNode === node) {
continue;
}
div.removeChild(node);
}
div.removeAttribute('data-loaded');
if (keepAnnotations) {
if (this.annotationLayer) {
// Hide annotationLayer until all elements are resized
// so they are not displayed on the already-resized page
this.annotationLayer.hide();
}
} else {
this.annotationLayer = null;
}
if (this.canvas) {
// Zeroing the width and height causes Firefox to release graphics
// resources immediately, which can greatly reduce memory consumption.
this.canvas.width = 0;
this.canvas.height = 0;
delete this.canvas;
}
this.loadingIconDiv = document.createElement('div');
this.loadingIconDiv.className = 'loadingIcon';
div.appendChild(this.loadingIconDiv);
},
update: function PDFPageView_update(scale, rotation) {
this.scale = scale || this.scale;
if (typeof rotation !== 'undefined') {
this.rotation = rotation;
}
var totalRotation = (this.rotation + this.pdfPageRotate) % 360;
this.viewport = this.viewport.clone({
scale: this.scale * CSS_UNITS,
rotation: totalRotation
});
var isScalingRestricted = false;
if (this.canvas && PDFJS.maxCanvasPixels > 0) {
var ctx = this.canvas.getContext('2d');
var outputScale = getOutputScale(ctx);
var pixelsInViewport = this.viewport.width * this.viewport.height;
var maxScale = Math.sqrt(PDFJS.maxCanvasPixels / pixelsInViewport);
if (((Math.floor(this.viewport.width) * outputScale.sx) | 0) *
((Math.floor(this.viewport.height) * outputScale.sy) | 0) >
PDFJS.maxCanvasPixels) {
isScalingRestricted = true;
}
}
if (this.canvas &&
(PDFJS.useOnlyCssZoom ||
(this.hasRestrictedScaling && isScalingRestricted))) {
this.cssTransform(this.canvas, true);
return;
} else if (this.canvas && !this.zoomLayer) {
this.zoomLayer = this.canvas.parentNode;
this.zoomLayer.style.position = 'absolute';
}
if (this.zoomLayer) {
this.cssTransform(this.zoomLayer.firstChild);
}
this.reset(true);
},
/**
* Called when moved in the parent's container.
*/
updatePosition: function PDFPageView_updatePosition() {
if (this.textLayer) {
this.textLayer.render(TEXT_LAYER_RENDER_DELAY);
}
},
cssTransform: function PDFPageView_transform(canvas, redrawAnnotations) {
// Scale canvas, canvas wrapper, and page container.
var width = this.viewport.width;
var height = this.viewport.height;
var div = this.div;
canvas.style.width = canvas.parentNode.style.width = div.style.width =
Math.floor(width) + 'px';
canvas.style.height = canvas.parentNode.style.height = div.style.height =
Math.floor(height) + 'px';
// The canvas may have been originally rotated, rotate relative to that.
var relativeRotation = this.viewport.rotation - canvas._viewport.rotation;
var absRotation = Math.abs(relativeRotation);
var scaleX = 1, scaleY = 1;
if (absRotation === 90 || absRotation === 270) {
// Scale x and y because of the rotation.
scaleX = height / width;
scaleY = width / height;
}
var cssTransform = 'rotate(' + relativeRotation + 'deg) ' +
'scale(' + scaleX + ',' + scaleY + ')';
CustomStyle.setProp('transform', canvas, cssTransform);
if (this.textLayer) {
// Rotating the text layer is more complicated since the divs inside the
// the text layer are rotated.
// TODO: This could probably be simplified by drawing the text layer in
// one orientation then rotating overall.
var textLayerViewport = this.textLayer.viewport;
var textRelativeRotation = this.viewport.rotation -
textLayerViewport.rotation;
var textAbsRotation = Math.abs(textRelativeRotation);
var scale = width / textLayerViewport.width;
if (textAbsRotation === 90 || textAbsRotation === 270) {
scale = width / textLayerViewport.height;
}
var textLayerDiv = this.textLayer.textLayerDiv;
var transX, transY;
switch (textAbsRotation) {
case 0:
transX = transY = 0;
break;
case 90:
transX = 0;
transY = '-' + textLayerDiv.style.height;
break;
case 180:
transX = '-' + textLayerDiv.style.width;
transY = '-' + textLayerDiv.style.height;
break;
case 270:
transX = '-' + textLayerDiv.style.width;
transY = 0;
break;
default:
console.error('Bad rotation value.');
break;
}
CustomStyle.setProp('transform', textLayerDiv,
'rotate(' + textAbsRotation + 'deg) ' +
'scale(' + scale + ', ' + scale + ') ' +
'translate(' + transX + ', ' + transY + ')');
CustomStyle.setProp('transformOrigin', textLayerDiv, '0% 0%');
}
if (redrawAnnotations && this.annotationLayer) {
this.annotationLayer.setupAnnotations(this.viewport);
}
},
get width() {
return this.viewport.width;
},
get height() {
return this.viewport.height;
},
getPagePoint: function PDFPageView_getPagePoint(x, y) {
return this.viewport.convertToPdfPoint(x, y);
},
draw: function PDFPageView_draw() {
if (this.renderingState !== RenderingStates.INITIAL) {
console.error('Must be in new state before drawing');
}
this.renderingState = RenderingStates.RUNNING;
var pdfPage = this.pdfPage;
var viewport = this.viewport;
var div = this.div;
// Wrap the canvas so if it has a css transform for highdpi the overflow
// will be hidden in FF.
var canvasWrapper = document.createElement('div');
canvasWrapper.style.width = div.style.width;
canvasWrapper.style.height = div.style.height;
canvasWrapper.classList.add('canvasWrapper');
var canvas = document.createElement('canvas');
canvas.pageNumber = this.id;
canvas.id = 'page' + this.id;
canvasWrapper.appendChild(canvas);
if (this.annotationLayer) {
// annotationLayer needs to stay on top
div.insertBefore(canvasWrapper, this.annotationLayer.div);
} else {
div.appendChild(canvasWrapper);
}
this.canvas = canvas;
var ctx = canvas.getContext('2d');
var outputScale = getOutputScale(ctx);
if (PDFJS.useOnlyCssZoom) {
var actualSizeViewport = viewport.clone({scale: CSS_UNITS});
// Use a scale that will make the canvas be the original intended size
// of the page.
outputScale.sx *= actualSizeViewport.width / viewport.width;
outputScale.sy *= actualSizeViewport.height / viewport.height;
outputScale.scaled = true;
}
if (PDFJS.maxCanvasPixels > 0) {
var pixelsInViewport = viewport.width * viewport.height;
var maxScale = Math.sqrt(PDFJS.maxCanvasPixels / pixelsInViewport);
if (outputScale.sx > maxScale || outputScale.sy > maxScale) {
outputScale.sx = maxScale;
outputScale.sy = maxScale;
outputScale.scaled = true;
this.hasRestrictedScaling = true;
} else {
this.hasRestrictedScaling = false;
}
}
canvas.width = (Math.floor(viewport.width) * outputScale.sx) | 0;
canvas.height = (Math.floor(viewport.height) * outputScale.sy) | 0;
canvas.style.width = Math.floor(viewport.width) + 'px';
canvas.style.height = Math.floor(viewport.height) + 'px';
// Add the viewport so it's known what it was originally drawn with.
canvas._viewport = viewport;
var textLayerDiv = null;
var textLayer = null;
if (this.textLayerFactory) {
textLayerDiv = document.createElement('div');
textLayerDiv.className = 'textLayer';
textLayerDiv.style.width = canvas.style.width;
textLayerDiv.style.height = canvas.style.height;
if (this.annotationLayer) {
// annotationLayer needs to stay on top
div.insertBefore(textLayerDiv, this.annotationLayer.div);
} else {
div.appendChild(textLayerDiv);
}
textLayer = this.textLayerFactory.createTextLayerBuilder(textLayerDiv,
this.id - 1,
this.viewport);
}
this.textLayer = textLayer;
if (outputScale.scaled) {
// Used by the mozCurrentTransform polyfill in src/display/canvas.js.
ctx._transformMatrix = [outputScale.sx, 0, 0, outputScale.sy, 0, 0];
ctx.scale(outputScale.sx, outputScale.sy);
}
var resolveRenderPromise, rejectRenderPromise;
var promise = new Promise(function (resolve, reject) {
resolveRenderPromise = resolve;
rejectRenderPromise = reject;
});
// Rendering area
var self = this;
function pageViewDrawCallback(error) {
// The renderTask may have been replaced by a new one, so only remove
// the reference to the renderTask if it matches the one that is
// triggering this callback.
if (renderTask === self.renderTask) {
self.renderTask = null;
}
if (error === 'cancelled') {
rejectRenderPromise(error);
return;
}
self.renderingState = RenderingStates.FINISHED;
if (self.loadingIconDiv) {
div.removeChild(self.loadingIconDiv);
delete self.loadingIconDiv;
}
if (self.zoomLayer) {
div.removeChild(self.zoomLayer);
self.zoomLayer = null;
}
self.error = error;
self.stats = pdfPage.stats;
if (self.onAfterDraw) {
self.onAfterDraw();
}
var event = document.createEvent('CustomEvent');
event.initCustomEvent('pagerendered', true, true, {
pageNumber: self.id
});
div.dispatchEvent(event);
// This custom event is deprecated, and will be removed in the future,
// please use the |pagerendered| event instead.
var deprecatedEvent = document.createEvent('CustomEvent');
deprecatedEvent.initCustomEvent('pagerender', true, true, {
pageNumber: pdfPage.pageNumber
});
div.dispatchEvent(deprecatedEvent);
if (!error) {
resolveRenderPromise(undefined);
} else {
rejectRenderPromise(error);
}
}
var renderContinueCallback = null;
if (this.renderingQueue) {
renderContinueCallback = function renderContinueCallback(cont) {
if (!self.renderingQueue.isHighestPriority(self)) {
self.renderingState = RenderingStates.PAUSED;
self.resume = function resumeCallback() {
self.renderingState = RenderingStates.RUNNING;
cont();
};
return;
}
cont();
};
}
var renderContext = {
canvasContext: ctx,
viewport: this.viewport,
// intent: 'default', // === 'display'
continueCallback: renderContinueCallback
};
var renderTask = this.renderTask = this.pdfPage.render(renderContext);
this.renderTask.promise.then(
function pdfPageRenderCallback() {
pageViewDrawCallback(null);
if (textLayer) {
self.pdfPage.getTextContent().then(
function textContentResolved(textContent) {
textLayer.setTextContent(textContent);
textLayer.render(TEXT_LAYER_RENDER_DELAY);
}
);
}
},
function pdfPageRenderError(error) {
pageViewDrawCallback(error);
}
);
if (this.annotationsLayerFactory) {
if (!this.annotationLayer) {
this.annotationLayer = this.annotationsLayerFactory.
createAnnotationsLayerBuilder(div, this.pdfPage);
}
this.annotationLayer.setupAnnotations(this.viewport);
}
div.setAttribute('data-loaded', true);
if (self.onBeforeDraw) {
self.onBeforeDraw();
}
return promise;
},
beforePrint: function PDFPageView_beforePrint() {
var pdfPage = this.pdfPage;
var viewport = pdfPage.getViewport(1);
// Use the same hack we use for high dpi displays for printing to get
// better output until bug 811002 is fixed in FF.
var PRINT_OUTPUT_SCALE = 2;
var canvas = document.createElement('canvas');
// The logical size of the canvas.
canvas.width = Math.floor(viewport.width) * PRINT_OUTPUT_SCALE;
canvas.height = Math.floor(viewport.height) * PRINT_OUTPUT_SCALE;
// The rendered size of the canvas, relative to the size of canvasWrapper.
canvas.style.width = (PRINT_OUTPUT_SCALE * 100) + '%';
canvas.style.height = (PRINT_OUTPUT_SCALE * 100) + '%';
var cssScale = 'scale(' + (1 / PRINT_OUTPUT_SCALE) + ', ' +
(1 / PRINT_OUTPUT_SCALE) + ')';
CustomStyle.setProp('transform', canvas, cssScale);
CustomStyle.setProp('transformOrigin', canvas, '0% 0%');
var printContainer = document.getElementById('printContainer');
var canvasWrapper = document.createElement('div');
canvasWrapper.style.width = viewport.width + 'pt';
canvasWrapper.style.height = viewport.height + 'pt';
canvasWrapper.appendChild(canvas);
printContainer.appendChild(canvasWrapper);
canvas.mozPrintCallback = function (obj) {
var ctx = obj.context;
ctx.save();
ctx.fillStyle = 'rgb(255, 255, 255)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.restore();
// Used by the mozCurrentTransform polyfill in src/display/canvas.js.
ctx._transformMatrix =
[PRINT_OUTPUT_SCALE, 0, 0, PRINT_OUTPUT_SCALE, 0, 0];
ctx.scale(PRINT_OUTPUT_SCALE, PRINT_OUTPUT_SCALE);
var renderContext = {
canvasContext: ctx,
viewport: viewport,
intent: 'print'
};
pdfPage.render(renderContext).promise.then(function () {
for (var i = 0; i < PDFViewerApplication.documentAnnotations.length; i++) {
var ann = PDFViewerApplication.documentAnnotations[i];
var documentAnnotation = new DocumentAnnotation(ann);
if (pdfPage.pageNumber == documentAnnotation.pageId) {
if (!documentAnnotation.deleted) {
documentAnnotation.draw(ctx, 0.75);
}
}
}
// Tell the printEngine that rendering this canvas/page has finished.
obj.done();
}, function (error) {
console.error(error);
// Tell the printEngine that rendering this canvas/page has failed.
// This will make the print proces stop.
if ('abort' in obj) {
obj.abort();
} else {
obj.done();
}
});
};
},
};
return PDFPageView;
})();
var MAX_TEXT_DIVS_TO_RENDER = 100000;
var NonWhitespaceRegexp = /\S/;
function isAllWhitespace(str) {
return !NonWhitespaceRegexp.test(str);
}
/**
* @typedef {Object} TextLayerBuilderOptions
* @property {HTMLDivElement} textLayerDiv - The text layer container.
* @property {number} pageIndex - The page index.
* @property {PageViewport} viewport - The viewport of the text layer.
* @property {PDFFindController} findController
*/
/**
* TextLayerBuilder provides text-selection functionality for the PDF.
* It does this by creating overlay divs over the PDF text. These divs
* contain text that matches the PDF text they are overlaying. This object
* also provides a way to highlight text that is being searched for.
* @class
*/
var TextLayerBuilder = (function TextLayerBuilderClosure() {
function TextLayerBuilder(options) {
this.textLayerDiv = options.textLayerDiv;
this.renderingDone = false;
this.divContentDone = false;
this.pageIdx = options.pageIndex;
this.pageNumber = this.pageIdx + 1;
this.matches = [];
this.viewport = options.viewport;
this.textDivs = [];
this.findController = options.findController || null;
}
TextLayerBuilder.prototype = {
_finishRendering: function TextLayerBuilder_finishRendering() {
this.renderingDone = true;
var event = document.createEvent('CustomEvent');
event.initCustomEvent('textlayerrendered', true, true, {
pageNumber: this.pageNumber
});
this.textLayerDiv.dispatchEvent(event);
},
renderLayer: function TextLayerBuilder_renderLayer() {
var textLayerFrag = document.createDocumentFragment();
var textDivs = this.textDivs;
var textDivsLength = textDivs.length;
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
// No point in rendering many divs as it would make the browser
// unusable even after the divs are rendered.
if (textDivsLength > MAX_TEXT_DIVS_TO_RENDER) {
this._finishRendering();
return;
}
var lastFontSize;
var lastFontFamily;
for (var i = 0; i < textDivsLength; i++) {
var textDiv = textDivs[i];
if (textDiv.dataset.isWhitespace !== undefined) {
continue;
}
var fontSize = textDiv.style.fontSize;
var fontFamily = textDiv.style.fontFamily;
// Only build font string and set to context if different from last.
if (fontSize !== lastFontSize || fontFamily !== lastFontFamily) {
ctx.font = fontSize + ' ' + fontFamily;
lastFontSize = fontSize;
lastFontFamily = fontFamily;
}
var width = ctx.measureText(textDiv.textContent).width;
if (width > 0) {
textLayerFrag.appendChild(textDiv);
var transform;
if (textDiv.dataset.canvasWidth !== undefined) {
// Dataset values come of type string.
var textScale = textDiv.dataset.canvasWidth / width;
transform = 'scaleX(' + textScale + ')';
} else {
transform = '';
}
var rotation = textDiv.dataset.angle;
if (rotation) {
transform = 'rotate(' + rotation + 'deg) ' + transform;
}
if (transform) {
CustomStyle.setProp('transform', textDiv, transform);
}
}
}
this.textLayerDiv.appendChild(textLayerFrag);
this._finishRendering();
this.updateMatches();
},
/**
* Renders the text layer.
* @param {number} timeout (optional) if specified, the rendering waits
* for specified amount of ms.
*/
render: function TextLayerBuilder_render(timeout) {
if (!this.divContentDone || this.renderingDone) {
return;
}
if (this.renderTimer) {
clearTimeout(this.renderTimer);
this.renderTimer = null;
}
if (!timeout) { // Render right away
this.renderLayer();
} else { // Schedule
var self = this;
this.renderTimer = setTimeout(function () {
self.renderLayer();
self.renderTimer = null;
}, timeout);
}
},
appendText: function TextLayerBuilder_appendText(geom, styles) {
var style = styles[geom.fontName];
var textDiv = document.createElement('div');
this.textDivs.push(textDiv);
if (isAllWhitespace(geom.str)) {
textDiv.dataset.isWhitespace = true;
return;
}
var tx = PDFJS.Util.transform(this.viewport.transform, geom.transform);
var angle = Math.atan2(tx[1], tx[0]);
if (style.vertical) {
angle += Math.PI / 2;
}
var fontHeight = Math.sqrt((tx[2] * tx[2]) + (tx[3] * tx[3]));
var fontAscent = fontHeight;
if (style.ascent) {
fontAscent = style.ascent * fontAscent;
} else if (style.descent) {
fontAscent = (1 + style.descent) * fontAscent;
}
var left;
var top;
if (angle === 0) {
left = tx[4];
top = tx[5] - fontAscent;
} else {
left = tx[4] + (fontAscent * Math.sin(angle));
top = tx[5] - (fontAscent * Math.cos(angle));
}
textDiv.style.left = left + 'px';
textDiv.style.top = top + 'px';
textDiv.style.fontSize = fontHeight + 'px';
textDiv.style.fontFamily = style.fontFamily;
textDiv.textContent = geom.str;
// |fontName| is only used by the Font Inspector. This test will succeed
// when e.g. the Font Inspector is off but the Stepper is on, but it's
// not worth the effort to do a more accurate test.
if (PDFJS.pdfBug) {
textDiv.dataset.fontName = geom.fontName;
}
// Storing into dataset will convert number into string.
if (angle !== 0) {
textDiv.dataset.angle = angle * (180 / Math.PI);
}
// We don't bother scaling single-char text divs, because it has very
// little effect on text highlighting. This makes scrolling on docs with
// lots of such divs a lot faster.
if (geom.str.length > 1) {
if (style.vertical) {
textDiv.dataset.canvasWidth = geom.height * this.viewport.scale;
} else {
textDiv.dataset.canvasWidth = geom.width * this.viewport.scale;
}
}
},
setTextContent: function TextLayerBuilder_setTextContent(textContent) {
this.textContent = textContent;
var textItems = textContent.items;
for (var i = 0, len = textItems.length; i < len; i++) {
this.appendText(textItems[i], textContent.styles);
}
this.divContentDone = true;
},
convertMatches: function TextLayerBuilder_convertMatches(matches) {
var i = 0;
var iIndex = 0;
var bidiTexts = this.textContent.items;
var end = bidiTexts.length - 1;
var queryLen = (this.findController === null ?
0 : this.findController.state.query.length);
var ret = [];
for (var m = 0, len = matches.length; m < len; m++) {
// Calculate the start position.
var matchIdx = matches[m];
// Loop over the divIdxs.
while (i !== end && matchIdx >= (iIndex + bidiTexts[i].str.length)) {
iIndex += bidiTexts[i].str.length;
i++;
}
if (i === bidiTexts.length) {
console.error('Could not find a matching mapping');
}
var match = {
begin: {
divIdx: i,
offset: matchIdx - iIndex
}
};
// Calculate the end position.
matchIdx += queryLen;
// Somewhat the same array as above, but use > instead of >= to get
// the end position right.
while (i !== end && matchIdx > (iIndex + bidiTexts[i].str.length)) {
iIndex += bidiTexts[i].str.length;
i++;
}
match.end = {
divIdx: i,
offset: matchIdx - iIndex
};
ret.push(match);
}
return ret;
},
renderMatches: function TextLayerBuilder_renderMatches(matches) {
// Early exit if there is nothing to render.
if (matches.length === 0) {
return;
}
var bidiTexts = this.textContent.items;
var textDivs = this.textDivs;
var prevEnd = null;
var pageIdx = this.pageIdx;
var isSelectedPage = (this.findController === null ?
false : (pageIdx === this.findController.selected.pageIdx));
var selectedMatchIdx = (this.findController === null ?
-1 : this.findController.selected.matchIdx);
var highlightAll = (this.findController === null ?
false : this.findController.state.highlightAll);
var infinity = {
divIdx: -1,
offset: undefined
};
function beginText(begin, className) {
var divIdx = begin.divIdx;
textDivs[divIdx].textContent = '';
appendTextToDiv(divIdx, 0, begin.offset, className);
}
function appendTextToDiv(divIdx, fromOffset, toOffset, className) {
var div = textDivs[divIdx];
var content = bidiTexts[divIdx].str.substring(fromOffset, toOffset);
var node = document.createTextNode(content);
if (className) {
var span = document.createElement('span');
span.className = className;
span.appendChild(node);
div.appendChild(span);
return;
}
div.appendChild(node);
}
var i0 = selectedMatchIdx, i1 = i0 + 1;
if (highlightAll) {
i0 = 0;
i1 = matches.length;
} else if (!isSelectedPage) {
// Not highlighting all and this isn't the selected page, so do nothing.
return;
}
for (var i = i0; i < i1; i++) {
var match = matches[i];
var begin = match.begin;
var end = match.end;
var isSelected = (isSelectedPage && i === selectedMatchIdx);
var highlightSuffix = (isSelected ? ' selected' : '');
if (this.findController) {
this.findController.updateMatchPosition(pageIdx, i, textDivs,
begin.divIdx, end.divIdx);
}
// Match inside new div.
if (!prevEnd || begin.divIdx !== prevEnd.divIdx) {
// If there was a previous div, then add the text at the end.
if (prevEnd !== null) {
appendTextToDiv(prevEnd.divIdx, prevEnd.offset, infinity.offset);
}
// Clear the divs and set the content until the starting point.
beginText(begin);
} else {
appendTextToDiv(prevEnd.divIdx, prevEnd.offset, begin.offset);
}
if (begin.divIdx === end.divIdx) {
appendTextToDiv(begin.divIdx, begin.offset, end.offset,
'highlight' + highlightSuffix);
} else {
appendTextToDiv(begin.divIdx, begin.offset, infinity.offset,
'highlight begin' + highlightSuffix);
for (var n0 = begin.divIdx + 1, n1 = end.divIdx; n0 < n1; n0++) {
textDivs[n0].className = 'highlight middle' + highlightSuffix;
}
beginText(end, 'highlight end' + highlightSuffix);
}
prevEnd = end;
}
if (prevEnd) {
appendTextToDiv(prevEnd.divIdx, prevEnd.offset, infinity.offset);
}
},
updateMatches: function TextLayerBuilder_updateMatches() {
// Only show matches when all rendering is done.
if (!this.renderingDone) {
return;
}
// Clear all matches.
var matches = this.matches;
var textDivs = this.textDivs;
var bidiTexts = this.textContent.items;
var clearedUntilDivIdx = -1;
// Clear all current matches.
for (var i = 0, len = matches.length; i < len; i++) {
var match = matches[i];
var begin = Math.max(clearedUntilDivIdx, match.begin.divIdx);
for (var n = begin, end = match.end.divIdx; n <= end; n++) {
var div = textDivs[n];
div.textContent = bidiTexts[n].str;
div.className = '';
}
clearedUntilDivIdx = match.end.divIdx + 1;
}
if (this.findController === null || !this.findController.active) {
return;
}
// Convert the matches on the page controller into the match format
// used for the textLayer.
this.matches = this.convertMatches(this.findController === null ?
[] : (this.findController.pageMatches[this.pageIdx] || []));
this.renderMatches(this.matches);
}
};
return TextLayerBuilder;
})();
/**
* @constructor
* @implements IPDFTextLayerFactory
*/
function DefaultTextLayerFactory() {}
DefaultTextLayerFactory.prototype = {
/**
* @param {HTMLDivElement} textLayerDiv
* @param {number} pageIndex
* @param {PageViewport} viewport
* @returns {TextLayerBuilder}
*/
createTextLayerBuilder: function (textLayerDiv, pageIndex, viewport) {
return new TextLayerBuilder({
textLayerDiv: textLayerDiv,
pageIndex: pageIndex,
viewport: viewport
});
}
};
/**
* @typedef {Object} AnnotationsLayerBuilderOptions
* @property {HTMLDivElement} pageDiv
* @property {PDFPage} pdfPage
* @property {IPDFLinkService} linkService
*/
/**
* @class
*/
var AnnotationsLayerBuilder = (function AnnotationsLayerBuilderClosure() {
/**
* @param {AnnotationsLayerBuilderOptions} options
* @constructs AnnotationsLayerBuilder
*/
function AnnotationsLayerBuilder(options) {
this.pageDiv = options.pageDiv;
this.pdfPage = options.pdfPage;
this.linkService = options.linkService;
this.div = null;
}
AnnotationsLayerBuilder.prototype =
/** @lends AnnotationsLayerBuilder.prototype */ {
/**
* @param {PageViewport} viewport
*/
setupAnnotations:
function AnnotationsLayerBuilder_setupAnnotations(viewport) {
function bindLink(link, dest) {
link.href = linkService.getDestinationHash(dest);
link.onclick = function annotationsLayerBuilderLinksOnclick() {
if (dest) {
linkService.navigateTo(dest);
}
return false;
};
if (dest) {
link.className = 'internalLink';
}
}
function bindNamedAction(link, action) {
link.href = linkService.getAnchorUrl('');
link.onclick = function annotationsLayerBuilderNamedActionOnClick() {
linkService.executeNamedAction(action);
return false;
};
link.className = 'internalLink';
}
var linkService = this.linkService;
var pdfPage = this.pdfPage;
var self = this;
pdfPage.getAnnotations().then(function (annotationsData) {
viewport = viewport.clone({dontFlip: true});
var transform = viewport.transform;
var transformStr = 'matrix(' + transform.join(',') + ')';
var data, element, i, ii;
if (self.div) {
// If an annotationLayer already exists, refresh its children's
// transformation matrices
for (i = 0, ii = annotationsData.length; i < ii; i++) {
data = annotationsData[i];
element = self.div.querySelector(
'[data-annotation-id="' + data.id + '"]');
if (element) {
CustomStyle.setProp('transform', element, transformStr);
}
}
// See PDFPageView.reset()
self.div.removeAttribute('hidden');
} else {
for (i = 0, ii = annotationsData.length; i < ii; i++) {
data = annotationsData[i];
if (!data || !data.hasHtml) {
continue;
}
element = PDFJS.AnnotationUtils.getHtmlElement(data,
pdfPage.commonObjs);
element.setAttribute('data-annotation-id', data.id);
if (typeof mozL10n !== 'undefined') {
mozL10n.translate(element);
}
var rect = data.rect;
var view = pdfPage.view;
rect = PDFJS.Util.normalizeRect([
rect[0],
view[3] - rect[1] + view[1],
rect[2],
view[3] - rect[3] + view[1]
]);
element.style.left = rect[0] + 'px';
element.style.top = rect[1] + 'px';
element.style.position = 'absolute';
CustomStyle.setProp('transform', element, transformStr);
var transformOriginStr = -rect[0] + 'px ' + -rect[1] + 'px';
CustomStyle.setProp('transformOrigin', element, transformOriginStr);
if (data.subtype === 'Link' && !data.url) {
var link = element.getElementsByTagName('a')[0];
if (link) {
if (data.action) {
bindNamedAction(link, data.action);
} else {
bindLink(link, ('dest' in data) ? data.dest : null);
}
}
}
if (!self.div) {
var annotationLayerDiv = document.createElement('div');
annotationLayerDiv.className = 'annotationLayer';
self.pageDiv.appendChild(annotationLayerDiv);
self.div = annotationLayerDiv;
}
self.div.appendChild(element);
}
}
});
},
hide: function () {
if (!this.div) {
return;
}
this.div.setAttribute('hidden', 'true');
}
};
return AnnotationsLayerBuilder;
})();
/**
* @constructor
* @implements IPDFAnnotationsLayerFactory
*/
function DefaultAnnotationsLayerFactory() {}
DefaultAnnotationsLayerFactory.prototype = {
/**
* @param {HTMLDivElement} pageDiv
* @param {PDFPage} pdfPage
* @returns {AnnotationsLayerBuilder}
*/
createAnnotationsLayerBuilder: function (pageDiv, pdfPage) {
return new AnnotationsLayerBuilder({
pageDiv: pageDiv,
pdfPage: pdfPage,
linkService: new SimpleLinkService(),
});
}
};
/**
* @typedef {Object} PDFViewerOptions
* @property {HTMLDivElement} container - The container for the viewer element.
* @property {HTMLDivElement} viewer - (optional) The viewer element.
* @property {IPDFLinkService} linkService - The navigation/linking service.
* @property {PDFRenderingQueue} renderingQueue - (optional) The rendering
* queue object.
* @property {boolean} removePageBorders - (optional) Removes the border shadow
* around the pages. The default is false.
*/
/**
* Simple viewer control to display PDF content/pages.
* @class
* @implements {IRenderableView}
*/
var PDFViewer = (function pdfViewer() {
function PDFPageViewBuffer(size) {
var data = [];
this.push = function cachePush(view) {
var i = data.indexOf(view);
if (i >= 0) {
data.splice(i, 1);
}
data.push(view);
if (data.length > size) {
data.shift().destroy();
}
};
this.resize = function (newSize) {
size = newSize;
while (data.length > size) {
data.shift().destroy();
}
};
}
function isSameScale(oldScale, newScale) {
if (newScale === oldScale) {
return true;
}
if (Math.abs(newScale - oldScale) < 1e-15) {
// Prevent unnecessary re-rendering of all pages when the scale
// changes only because of limited numerical precision.
return true;
}
return false;
}
/**
* @constructs PDFViewer
* @param {PDFViewerOptions} options
*/
function PDFViewer(options) {
this.container = options.container;
this.viewer = options.viewer || options.container.firstElementChild;
this.linkService = options.linkService || new SimpleLinkService();
this.removePageBorders = options.removePageBorders || false;
this.defaultRenderingQueue = !options.renderingQueue;
if (this.defaultRenderingQueue) {
// Custom rendering queue is not specified, using default one
this.renderingQueue = new PDFRenderingQueue();
this.renderingQueue.setViewer(this);
} else {
this.renderingQueue = options.renderingQueue;
}
this.scroll = watchScroll(this.container, this._scrollUpdate.bind(this));
this.updateInProgress = false;
this.presentationModeState = PresentationModeState.UNKNOWN;
this._resetView();
if (this.removePageBorders) {
this.viewer.classList.add('removePageBorders');
}
}
PDFViewer.prototype = /** @lends PDFViewer.prototype */{
get pagesCount() {
return this._pages.length;
},
getPageView: function (index) {
return this._pages[index];
},
get currentPageNumber() {
return this._currentPageNumber;
},
set currentPageNumber(val) {
if (!this.pdfDocument) {
this._currentPageNumber = val;
return;
}
var event = document.createEvent('UIEvents');
event.initUIEvent('pagechange', true, true, window, 0);
event.updateInProgress = this.updateInProgress;
if (!(0 < val && val <= this.pagesCount)) {
event.pageNumber = this._currentPageNumber;
event.previousPageNumber = val;
this.container.dispatchEvent(event);
return;
}
event.previousPageNumber = this._currentPageNumber;
this._currentPageNumber = val;
event.pageNumber = val;
this.container.dispatchEvent(event);
// Check if the caller is `PDFViewer_update`, to avoid breaking scrolling.
if (this.updateInProgress) {
return;
}
this.scrollPageIntoView(val);
},
/**
* @returns {number}
*/
get currentScale() {
return this._currentScale !== UNKNOWN_SCALE ? this._currentScale :
DEFAULT_SCALE;
},
/**
* @param {number} val - Scale of the pages in percents.
*/
set currentScale(val) {
if (isNaN(val)) {
throw new Error('Invalid numeric scale');
}
if (!this.pdfDocument) {
this._currentScale = val;
this._currentScaleValue = val !== UNKNOWN_SCALE ? val.toString() : null;
return;
}
this._setScale(val, false);
},
/**
* @returns {string}
*/
get currentScaleValue() {
return this._currentScaleValue;
},
/**
* @param val - The scale of the pages (in percent or predefined value).
*/
set currentScaleValue(val) {
if (!this.pdfDocument) {
this._currentScale = isNaN(val) ? UNKNOWN_SCALE : val;
this._currentScaleValue = val;
return;
}
this._setScale(val, false);
},
/**
* @returns {number}
*/
get pagesRotation() {
return this._pagesRotation;
},
/**
* @param {number} rotation - The rotation of the pages (0, 90, 180, 270).
*/
set pagesRotation(rotation) {
this._pagesRotation = rotation;
for (var i = 0, l = this._pages.length; i < l; i++) {
var pageView = this._pages[i];
pageView.update(pageView.scale, rotation);
}
this._setScale(this._currentScaleValue, true);
if (this.defaultRenderingQueue) {
this.update();
}
},
/**
* @param pdfDocument {PDFDocument}
*/
setDocument: function (pdfDocument) {
if (this.pdfDocument) {
this._resetView();
}
this.pdfDocument = pdfDocument;
if (!pdfDocument) {
return;
}
var pagesCount = pdfDocument.numPages;
var self = this;
var resolvePagesPromise;
var pagesPromise = new Promise(function (resolve) {
resolvePagesPromise = resolve;
});
this.pagesPromise = pagesPromise;
pagesPromise.then(function () {
var event = document.createEvent('CustomEvent');
event.initCustomEvent('pagesloaded', true, true, {
pagesCount: pagesCount
});
self.container.dispatchEvent(event);
});
var isOnePageRenderedResolved = false;
var resolveOnePageRendered = null;
var onePageRendered = new Promise(function (resolve) {
resolveOnePageRendered = resolve;
});
this.onePageRendered = onePageRendered;
var bindOnAfterAndBeforeDraw = function (pageView) {
pageView.onBeforeDraw = function pdfViewLoadOnBeforeDraw() {
// Add the page to the buffer at the start of drawing. That way it can
// be evicted from the buffer and destroyed even if we pause its
// rendering.
self._buffer.push(this);
};
// when page is painted, using the image as thumbnail base
pageView.onAfterDraw = function pdfViewLoadOnAfterDraw() {
if (!isOnePageRenderedResolved) {
isOnePageRenderedResolved = true;
resolveOnePageRendered();
}
};
};
var firstPagePromise = pdfDocument.getPage(1);
this.firstPagePromise = firstPagePromise;
// Fetch a single page so we can get a viewport that will be the default
// viewport for all pages
return firstPagePromise.then(function (pdfPage) {
var scale = this.currentScale;
var viewport = pdfPage.getViewport(scale * CSS_UNITS);
for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) {
var textLayerFactory = null;
if (!PDFJS.disableTextLayer) {
textLayerFactory = this;
}
var pageView = new PDFPageView({
container: this.viewer,
id: pageNum,
scale: scale,
defaultViewport: viewport.clone(),
renderingQueue: this.renderingQueue,
textLayerFactory: textLayerFactory,
annotationsLayerFactory: this
});
bindOnAfterAndBeforeDraw(pageView);
this._pages.push(pageView);
}
var linkService = this.linkService;
// Fetch all the pages since the viewport is needed before printing
// starts to create the correct size canvas. Wait until one page is
// rendered so we don't tie up too many resources early on.
onePageRendered.then(function () {
if (!PDFJS.disableAutoFetch) {
var getPagesLeft = pagesCount;
for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) {
pdfDocument.getPage(pageNum).then(function (pageNum, pdfPage) {
var pageView = self._pages[pageNum - 1];
if (!pageView.pdfPage) {
pageView.setPdfPage(pdfPage);
}
linkService.cachePageRef(pageNum, pdfPage.ref);
getPagesLeft--;
if (!getPagesLeft) {
resolvePagesPromise();
}
}.bind(null, pageNum));
}
} else {
// XXX: Printing is semi-broken with auto fetch disabled.
resolvePagesPromise();
}
});
var event = document.createEvent('CustomEvent');
event.initCustomEvent('pagesinit', true, true, null);
self.container.dispatchEvent(event);
if (this.defaultRenderingQueue) {
this.update();
}
if (this.findController) {
this.findController.resolveFirstPage();
}
}.bind(this));
},
_resetView: function () {
this._pages = [];
this._currentPageNumber = 1;
this._currentScale = UNKNOWN_SCALE;
this._currentScaleValue = null;
this._buffer = new PDFPageViewBuffer(DEFAULT_CACHE_SIZE);
this._location = null;
this._pagesRotation = 0;
this._pagesRequests = [];
var container = this.viewer;
while (container.hasChildNodes()) {
container.removeChild(container.lastChild);
}
},
_scrollUpdate: function PDFViewer_scrollUpdate() {
if (this.pagesCount === 0) {
return;
}
this.update();
for (var i = 0, ii = this._pages.length; i < ii; i++) {
this._pages[i].updatePosition();
}
},
_setScaleDispatchEvent: function pdfViewer_setScaleDispatchEvent(
newScale, newValue, preset) {
var event = document.createEvent('UIEvents');
event.initUIEvent('scalechange', true, true, window, 0);
event.scale = newScale;
if (preset) {
event.presetValue = newValue;
}
this.container.dispatchEvent(event);
},
_setScaleUpdatePages: function pdfViewer_setScaleUpdatePages(
newScale, newValue, noScroll, preset) {
this._currentScaleValue = newValue;
if (isSameScale(this._currentScale, newScale)) {
if (preset) {
this._setScaleDispatchEvent(newScale, newValue, true);
}
return;
}
for (var i = 0, ii = this._pages.length; i < ii; i++) {
this._pages[i].update(newScale);
}
this._currentScale = newScale;
if (!noScroll) {
var page = this._currentPageNumber, dest;
if (this._location && !IGNORE_CURRENT_POSITION_ON_ZOOM &&
!(this.isInPresentationMode || this.isChangingPresentationMode)) {
page = this._location.pageNumber;
dest = [null, {name: 'XYZ'}, this._location.left,
this._location.top, null];
}
this.scrollPageIntoView(page, dest);
}
this._setScaleDispatchEvent(newScale, newValue, preset);
if (this.defaultRenderingQueue) {
this.update();
}
},
_setScale: function pdfViewer_setScale(value, noScroll) {
var scale = parseFloat(value);
if (scale > 0) {
this._setScaleUpdatePages(scale, value, noScroll, false);
} else {
var currentPage = this._pages[this._currentPageNumber - 1];
if (!currentPage) {
return;
}
var hPadding = (this.isInPresentationMode || this.removePageBorders) ?
0 : SCROLLBAR_PADDING;
var vPadding = (this.isInPresentationMode || this.removePageBorders) ?
0 : VERTICAL_PADDING;
var pageWidthScale = (this.container.clientWidth - hPadding) /
currentPage.width * currentPage.scale;
var pageHeightScale = (this.container.clientHeight - vPadding) /
currentPage.height * currentPage.scale;
switch (value) {
case 'page-actual':
scale = 1;
break;
case 'page-width':
scale = pageWidthScale;
break;
case 'page-height':
scale = pageHeightScale;
break;
case 'page-fit':
scale = Math.min(pageWidthScale, pageHeightScale);
break;
case 'auto':
var isLandscape = (currentPage.width > currentPage.height);
// For pages in landscape mode, fit the page height to the viewer
// *unless* the page would thus become too wide to fit horizontally.
var horizontalScale = isLandscape ?
Math.min(pageHeightScale, pageWidthScale) : pageWidthScale;
scale = Math.min(MAX_AUTO_SCALE, horizontalScale);
break;
default:
console.error('pdfViewSetScale: \'' + value +
'\' is an unknown zoom value.');
return;
}
this._setScaleUpdatePages(scale, value, noScroll, true);
}
},
/**
* Scrolls page into view.
* @param {number} pageNumber
* @param {Array} dest - (optional) original PDF destination array:
* <page-ref> </XYZ|FitXXX> <args..>
*/
scrollPageIntoView: function PDFViewer_scrollPageIntoView(pageNumber,
dest) {
var pageView = this._pages[pageNumber - 1];
if (this.isInPresentationMode) {
if (this._currentPageNumber !== pageView.id) {
// Avoid breaking getVisiblePages in presentation mode.
this.currentPageNumber = pageView.id;
return;
}
dest = null;
// Fixes the case when PDF has different page sizes.
this._setScale(this._currentScaleValue, true);
}
if (!dest) {
scrollIntoView(pageView.div);
return;
}
var x = 0, y = 0;
var width = 0, height = 0, widthScale, heightScale;
var changeOrientation = (pageView.rotation % 180 === 0 ? false : true);
var pageWidth = (changeOrientation ? pageView.height : pageView.width) /
pageView.scale / CSS_UNITS;
var pageHeight = (changeOrientation ? pageView.width : pageView.height) /
pageView.scale / CSS_UNITS;
var scale = 0;
switch (dest[1].name) {
case 'XYZ':
x = dest[2];
y = dest[3];
scale = dest[4];
// If x and/or y coordinates are not supplied, default to
// _top_ left of the page (not the obvious bottom left,
// since aligning the bottom of the intended page with the
// top of the window is rarely helpful).
x = x !== null ? x : 0;
y = y !== null ? y : pageHeight;
break;
case 'Fit':
case 'FitB':
scale = 'page-fit';
break;
case 'FitH':
case 'FitBH':
y = dest[2];
scale = 'page-width';
break;
case 'FitV':
case 'FitBV':
x = dest[2];
width = pageWidth;
height = pageHeight;
scale = 'page-height';
break;
case 'FitR':
x = dest[2];
y = dest[3];
width = dest[4] - x;
height = dest[5] - y;
var hPadding = this.removePageBorders ? 0 : SCROLLBAR_PADDING;
var vPadding = this.removePageBorders ? 0 : VERTICAL_PADDING;
widthScale = (this.container.clientWidth - hPadding) /
width / CSS_UNITS;
heightScale = (this.container.clientHeight - vPadding) /
height / CSS_UNITS;
scale = Math.min(Math.abs(widthScale), Math.abs(heightScale));
break;
default:
return;
}
if (scale && scale !== this._currentScale) {
this.currentScaleValue = scale;
} else if (this._currentScale === UNKNOWN_SCALE) {
this.currentScaleValue = DEFAULT_SCALE_VALUE;
}
if (scale === 'page-fit' && !dest[4]) {
scrollIntoView(pageView.div);
return;
}
var boundingRect = [
pageView.viewport.convertToViewportPoint(x, y),
pageView.viewport.convertToViewportPoint(x + width, y + height)
];
var left = Math.min(boundingRect[0][0], boundingRect[1][0]);
var top = Math.min(boundingRect[0][1], boundingRect[1][1]);
scrollIntoView(pageView.div, {left: left, top: top});
},
_updateLocation: function (firstPage) {
var currentScale = this._currentScale;
var currentScaleValue = this._currentScaleValue;
var normalizedScaleValue =
parseFloat(currentScaleValue) === currentScale ?
Math.round(currentScale * 10000) / 100 : currentScaleValue;
var pageNumber = firstPage.id;
var pdfOpenParams = '#page=' + pageNumber;
pdfOpenParams += '&zoom=' + normalizedScaleValue;
var currentPageView = this._pages[pageNumber - 1];
var container = this.container;
var topLeft = currentPageView.getPagePoint(
(container.scrollLeft - firstPage.x),
(container.scrollTop - firstPage.y));
var intLeft = Math.round(topLeft[0]);
var intTop = Math.round(topLeft[1]);
pdfOpenParams += ',' + intLeft + ',' + intTop;
this._location = {
pageNumber: pageNumber,
scale: normalizedScaleValue,
top: intTop,
left: intLeft,
pdfOpenParams: pdfOpenParams
};
},
update: function PDFViewer_update() {
var visible = this._getVisiblePages();
var visiblePages = visible.views;
if (visiblePages.length === 0) {
return;
}
this.updateInProgress = true;
var suggestedCacheSize = Math.max(DEFAULT_CACHE_SIZE,
2 * visiblePages.length + 1);
this._buffer.resize(suggestedCacheSize);
this.renderingQueue.renderHighestPriority(visible);
var currentId = this._currentPageNumber;
var firstPage = visible.first;
for (var i = 0, ii = visiblePages.length, stillFullyVisible = false;
i < ii; ++i) {
var page = visiblePages[i];
if (page.percent < 100) {
break;
}
if (page.id === currentId) {
stillFullyVisible = true;
break;
}
}
if (!stillFullyVisible) {
currentId = visiblePages[0].id;
}
if (!this.isInPresentationMode) {
this.currentPageNumber = currentId;
}
this._updateLocation(firstPage);
this.updateInProgress = false;
var event = document.createEvent('UIEvents');
event.initUIEvent('updateviewarea', true, true, window, 0);
event.location = this._location;
this.container.dispatchEvent(event);
},
containsElement: function (element) {
return this.container.contains(element);
},
focus: function () {
this.container.focus();
},
get isInPresentationMode() {
return this.presentationModeState === PresentationModeState.FULLSCREEN;
},
get isChangingPresentationMode() {
return this.PresentationModeState === PresentationModeState.CHANGING;
},
get isHorizontalScrollbarEnabled() {
return (this.isInPresentationMode ?
false : (this.container.scrollWidth > this.container.clientWidth));
},
_getVisiblePages: function () {
if (!this.isInPresentationMode) {
return getVisibleElements(this.container, this._pages, true);
} else {
// The algorithm in getVisibleElements doesn't work in all browsers and
// configurations when presentation mode is active.
var visible = [];
var currentPage = this._pages[this._currentPageNumber - 1];
visible.push({id: currentPage.id, view: currentPage});
return {first: currentPage, last: currentPage, views: visible};
}
},
cleanup: function () {
for (var i = 0, ii = this._pages.length; i < ii; i++) {
if (this._pages[i] &&
this._pages[i].renderingState !== RenderingStates.FINISHED) {
this._pages[i].reset();
}
}
},
/**
* @param {PDFPageView} pageView
* @returns {PDFPage}
* @private
*/
_ensurePdfPageLoaded: function (pageView) {
if (pageView.pdfPage) {
return Promise.resolve(pageView.pdfPage);
}
var pageNumber = pageView.id;
if (this._pagesRequests[pageNumber]) {
return this._pagesRequests[pageNumber];
}
var promise = this.pdfDocument.getPage(pageNumber).then(
function (pdfPage) {
pageView.setPdfPage(pdfPage);
this._pagesRequests[pageNumber] = null;
return pdfPage;
}.bind(this));
this._pagesRequests[pageNumber] = promise;
return promise;
},
forceRendering: function (currentlyVisiblePages) {
var visiblePages = currentlyVisiblePages || this._getVisiblePages();
var pageView = this.renderingQueue.getHighestPriority(visiblePages,
this._pages,
this.scroll.down);
if (pageView) {
this._ensurePdfPageLoaded(pageView).then(function () {
this.renderingQueue.renderView(pageView);
}.bind(this));
return true;
}
return false;
},
getPageTextContent: function (pageIndex) {
return this.pdfDocument.getPage(pageIndex + 1).then(function (page) {
return page.getTextContent();
});
},
/**
* @param {HTMLDivElement} textLayerDiv
* @param {number} pageIndex
* @param {PageViewport} viewport
* @returns {TextLayerBuilder}
*/
createTextLayerBuilder: function (textLayerDiv, pageIndex, viewport) {
return new TextLayerBuilder({
textLayerDiv: textLayerDiv,
pageIndex: pageIndex,
viewport: viewport,
findController: this.isInPresentationMode ? null : this.findController
});
},
/**
* @param {HTMLDivElement} pageDiv
* @param {PDFPage} pdfPage
* @returns {AnnotationsLayerBuilder}
*/
createAnnotationsLayerBuilder: function (pageDiv, pdfPage) {
return new AnnotationsLayerBuilder({
pageDiv: pageDiv,
pdfPage: pdfPage,
linkService: this.linkService
});
},
setFindController: function (findController) {
this.findController = findController;
},
};
return PDFViewer;
})();
var SimpleLinkService = (function SimpleLinkServiceClosure() {
function SimpleLinkService() {}
SimpleLinkService.prototype = {
/**
* @returns {number}
*/
get page() {
return 0;
},
/**
* @param {number} value
*/
set page(value) {},
/**
* @param dest - The PDF destination object.
*/
navigateTo: function (dest) {},
/**
* @param dest - The PDF destination object.
* @returns {string} The hyperlink to the PDF object.
*/
getDestinationHash: function (dest) {
return '#';
},
/**
* @param hash - The PDF parameters/hash.
* @returns {string} The hyperlink to the PDF object.
*/
getAnchorUrl: function (hash) {
return '#';
},
/**
* @param {string} hash
*/
setHash: function (hash) {},
/**
* @param {string} action
*/
executeNamedAction: function (action) {},
/**
* @param {number} pageNum - page number.
* @param {Object} pageRef - reference to the page.
*/
cachePageRef: function (pageNum, pageRef) {}
};
return SimpleLinkService;
})();
var THUMBNAIL_SCROLL_MARGIN = -19;
var THUMBNAIL_WIDTH = 98; // px
var THUMBNAIL_CANVAS_BORDER_WIDTH = 1; // px
/**
* @typedef {Object} PDFThumbnailViewOptions
* @property {HTMLDivElement} container - The viewer element.
* @property {number} id - The thumbnail's unique ID (normally its number).
* @property {PageViewport} defaultViewport - The page viewport.
* @property {IPDFLinkService} linkService - The navigation/linking service.
* @property {PDFRenderingQueue} renderingQueue - The rendering queue object.
*/
/**
* @class
* @implements {IRenderableView}
*/
var PDFThumbnailView = (function PDFThumbnailViewClosure() {
function getTempCanvas(width, height) {
var tempCanvas = PDFThumbnailView.tempImageCache;
if (!tempCanvas) {
tempCanvas = document.createElement('canvas');
PDFThumbnailView.tempImageCache = tempCanvas;
}
tempCanvas.width = width;
tempCanvas.height = height;
// Since this is a temporary canvas, we need to fill the canvas with a white
// background ourselves. |_getPageDrawContext| uses CSS rules for this.
var ctx = tempCanvas.getContext('2d');
ctx.save();
ctx.fillStyle = 'rgb(255, 255, 255)';
ctx.fillRect(0, 0, width, height);
ctx.restore();
return tempCanvas;
}
/**
* @constructs PDFThumbnailView
* @param {PDFThumbnailViewOptions} options
*/
function PDFThumbnailView(options) {
var container = options.container;
var id = options.id;
var defaultViewport = options.defaultViewport;
var linkService = options.linkService;
var renderingQueue = options.renderingQueue;
this.id = id;
this.renderingId = 'thumbnail' + id;
this.pdfPage = null;
this.rotation = 0;
this.viewport = defaultViewport;
this.pdfPageRotate = defaultViewport.rotation;
this.linkService = linkService;
this.renderingQueue = renderingQueue;
this.hasImage = false;
this.resume = null;
this.renderingState = RenderingStates.INITIAL;
this.pageWidth = this.viewport.width;
this.pageHeight = this.viewport.height;
this.pageRatio = this.pageWidth / this.pageHeight;
this.canvasWidth = THUMBNAIL_WIDTH;
this.canvasHeight = (this.canvasWidth / this.pageRatio) | 0;
this.scale = this.canvasWidth / this.pageWidth;
var anchor = document.createElement('a');
anchor.href = linkService.getAnchorUrl('#page=' + id);
anchor.title = mozL10n.get('thumb_page_title', {page: id}, 'Page {{page}}');
anchor.onclick = function stopNavigation() {
linkService.page = id;
return false;
};
var div = document.createElement('div');
div.id = 'thumbnailContainer' + id;
div.className = 'thumbnail';
this.div = div;
if (id === 1) {
// Highlight the thumbnail of the first page when no page number is
// specified (or exists in cache) when the document is loaded.
div.classList.add('selected');
}
var ring = document.createElement('div');
ring.className = 'thumbnailSelectionRing';
var borderAdjustment = 2 * THUMBNAIL_CANVAS_BORDER_WIDTH;
ring.style.width = this.canvasWidth + borderAdjustment + 'px';
ring.style.height = this.canvasHeight + borderAdjustment + 'px';
this.ring = ring;
div.appendChild(ring);
anchor.appendChild(div);
container.appendChild(anchor);
}
PDFThumbnailView.prototype = {
setPdfPage: function PDFThumbnailView_setPdfPage(pdfPage) {
this.pdfPage = pdfPage;
this.pdfPageRotate = pdfPage.rotate;
var totalRotation = (this.rotation + this.pdfPageRotate) % 360;
this.viewport = pdfPage.getViewport(1, totalRotation);
this.reset();
},
reset: function PDFThumbnailView_reset() {
if (this.renderTask) {
this.renderTask.cancel();
}
this.hasImage = false;
this.resume = null;
this.renderingState = RenderingStates.INITIAL;
this.pageWidth = this.viewport.width;
this.pageHeight = this.viewport.height;
this.pageRatio = this.pageWidth / this.pageHeight;
this.canvasHeight = (this.canvasWidth / this.pageRatio) | 0;
this.scale = (this.canvasWidth / this.pageWidth);
this.div.removeAttribute('data-loaded');
var ring = this.ring;
var childNodes = ring.childNodes;
for (var i = childNodes.length - 1; i >= 0; i--) {
ring.removeChild(childNodes[i]);
}
var borderAdjustment = 2 * THUMBNAIL_CANVAS_BORDER_WIDTH;
ring.style.width = this.canvasWidth + borderAdjustment + 'px';
ring.style.height = this.canvasHeight + borderAdjustment + 'px';
if (this.canvas) {
// Zeroing the width and height causes Firefox to release graphics
// resources immediately, which can greatly reduce memory consumption.
this.canvas.width = 0;
this.canvas.height = 0;
delete this.canvas;
}
if (this.image) {
this.image.removeAttribute('src');
delete this.image;
}
},
update: function PDFThumbnailView_update(rotation) {
if (typeof rotation !== 'undefined') {
this.rotation = rotation;
}
var totalRotation = (this.rotation + this.pdfPageRotate) % 360;
this.viewport = this.viewport.clone({
scale: 1,
rotation: totalRotation
});
this.reset();
},
/**
* @private
*/
_getPageDrawContext:
function PDFThumbnailView_getPageDrawContext(noCtxScale) {
var canvas = document.createElement('canvas');
this.canvas = canvas;
var ctx = canvas.getContext('2d');
var outputScale = getOutputScale(ctx);
canvas.width = (this.canvasWidth * outputScale.sx) | 0;
canvas.height = (this.canvasHeight * outputScale.sy) | 0;
canvas.style.width = this.canvasWidth + 'px';
canvas.style.height = this.canvasHeight + 'px';
if (!noCtxScale && outputScale.scaled) {
ctx.scale(outputScale.sx, outputScale.sy);
}
var image = document.createElement('img');
this.image = image;
image.id = this.renderingId;
image.className = 'thumbnailImage';
image.setAttribute('aria-label', mozL10n.get('thumb_page_canvas',
{page: this.id}, 'Thumbnail of Page {{page}}'));
image.style.width = canvas.style.width;
image.style.height = canvas.style.height;
return ctx;
},
/**
* @private
*/
_convertCanvasToImage: function PDFThumbnailView_convertCanvasToImage() {
if (!this.canvas) {
return;
}
this.image.src = this.canvas.toDataURL();
this.div.setAttribute('data-loaded', true);
this.ring.appendChild(this.image);
// Zeroing the width and height causes Firefox to release graphics
// resources immediately, which can greatly reduce memory consumption.
this.canvas.width = 0;
this.canvas.height = 0;
delete this.canvas;
},
draw: function PDFThumbnailView_draw() {
if (this.renderingState !== RenderingStates.INITIAL) {
console.error('Must be in new state before drawing');
}
if (this.hasImage) {
return Promise.resolve(undefined);
}
this.hasImage = true;
this.renderingState = RenderingStates.RUNNING;
var resolveRenderPromise, rejectRenderPromise;
var promise = new Promise(function (resolve, reject) {
resolveRenderPromise = resolve;
rejectRenderPromise = reject;
});
var self = this;
function thumbnailDrawCallback(error) {
// The renderTask may have been replaced by a new one, so only remove
// the reference to the renderTask if it matches the one that is
// triggering this callback.
if (renderTask === self.renderTask) {
self.renderTask = null;
}
if (error === 'cancelled') {
rejectRenderPromise(error);
return;
}
self.renderingState = RenderingStates.FINISHED;
self._convertCanvasToImage();
if (!error) {
resolveRenderPromise(undefined);
} else {
rejectRenderPromise(error);
}
}
var ctx = this._getPageDrawContext();
var drawViewport = this.viewport.clone({scale: this.scale});
var renderContinueCallback = function renderContinueCallback(cont) {
if (!self.renderingQueue.isHighestPriority(self)) {
self.renderingState = RenderingStates.PAUSED;
self.resume = function resumeCallback() {
self.renderingState = RenderingStates.RUNNING;
cont();
};
return;
}
cont();
};
var renderContext = {
canvasContext: ctx,
viewport: drawViewport,
continueCallback: renderContinueCallback
};
var renderTask = this.renderTask = this.pdfPage.render(renderContext);
renderTask.promise.then(
function pdfPageRenderCallback() {
thumbnailDrawCallback(null);
},
function pdfPageRenderError(error) {
thumbnailDrawCallback(error);
}
);
return promise;
},
setImage: function PDFThumbnailView_setImage(pageView) {
var img = pageView.canvas;
if (this.hasImage || !img) {
return;
}
if (!this.pdfPage) {
this.setPdfPage(pageView.pdfPage);
}
this.hasImage = true;
this.renderingState = RenderingStates.FINISHED;
var ctx = this._getPageDrawContext(true);
var canvas = ctx.canvas;
if (img.width <= 2 * canvas.width) {
ctx.drawImage(img, 0, 0, img.width, img.height,
0, 0, canvas.width, canvas.height);
this._convertCanvasToImage();
return;
}
// drawImage does an awful job of rescaling the image, doing it gradually.
var MAX_NUM_SCALING_STEPS = 3;
var reducedWidth = canvas.width << MAX_NUM_SCALING_STEPS;
var reducedHeight = canvas.height << MAX_NUM_SCALING_STEPS;
var reducedImage = getTempCanvas(reducedWidth, reducedHeight);
var reducedImageCtx = reducedImage.getContext('2d');
while (reducedWidth > img.width || reducedHeight > img.height) {
reducedWidth >>= 1;
reducedHeight >>= 1;
}
reducedImageCtx.drawImage(img, 0, 0, img.width, img.height,
0, 0, reducedWidth, reducedHeight);
while (reducedWidth > 2 * canvas.width) {
reducedImageCtx.drawImage(reducedImage,
0, 0, reducedWidth, reducedHeight,
0, 0, reducedWidth >> 1, reducedHeight >> 1);
reducedWidth >>= 1;
reducedHeight >>= 1;
}
ctx.drawImage(reducedImage, 0, 0, reducedWidth, reducedHeight,
0, 0, canvas.width, canvas.height);
this._convertCanvasToImage();
}
};
return PDFThumbnailView;
})();
PDFThumbnailView.tempImageCache = null;
/**
* @typedef {Object} PDFThumbnailViewerOptions
* @property {HTMLDivElement} container - The container for the thumbnail
* elements.
* @property {IPDFLinkService} linkService - The navigation/linking service.
* @property {PDFRenderingQueue} renderingQueue - The rendering queue object.
*/
/**
* Simple viewer control to display thumbnails for pages.
* @class
* @implements {IRenderableView}
*/
var PDFThumbnailViewer = (function PDFThumbnailViewerClosure() {
/**
* @constructs PDFThumbnailViewer
* @param {PDFThumbnailViewerOptions} options
*/
function PDFThumbnailViewer(options) {
this.container = options.container;
this.renderingQueue = options.renderingQueue;
this.linkService = options.linkService;
this.scroll = watchScroll(this.container, this._scrollUpdated.bind(this));
this._resetView();
}
PDFThumbnailViewer.prototype = {
/**
* @private
*/
_scrollUpdated: function PDFThumbnailViewer_scrollUpdated() {
this.renderingQueue.renderHighestPriority();
},
getThumbnail: function PDFThumbnailViewer_getThumbnail(index) {
return this.thumbnails[index];
},
/**
* @private
*/
_getVisibleThumbs: function PDFThumbnailViewer_getVisibleThumbs() {
return getVisibleElements(this.container, this.thumbnails);
},
scrollThumbnailIntoView:
function PDFThumbnailViewer_scrollThumbnailIntoView(page) {
var selected = document.querySelector('.thumbnail.selected');
if (selected) {
selected.classList.remove('selected');
}
var thumbnail = document.getElementById('thumbnailContainer' + page);
if (thumbnail) {
thumbnail.classList.add('selected');
}
var visibleThumbs = this._getVisibleThumbs();
var numVisibleThumbs = visibleThumbs.views.length;
// If the thumbnail isn't currently visible, scroll it into view.
if (numVisibleThumbs > 0) {
var first = visibleThumbs.first.id;
// Account for only one thumbnail being visible.
var last = (numVisibleThumbs > 1 ? visibleThumbs.last.id : first);
if (page <= first || page >= last) {
scrollIntoView(thumbnail, {top: THUMBNAIL_SCROLL_MARGIN});
}
}
},
get pagesRotation() {
return this._pagesRotation;
},
set pagesRotation(rotation) {
this._pagesRotation = rotation;
for (var i = 0, l = this.thumbnails.length; i < l; i++) {
var thumb = this.thumbnails[i];
thumb.update(rotation);
}
},
cleanup: function PDFThumbnailViewer_cleanup() {
var tempCanvas = PDFThumbnailView.tempImageCache;
if (tempCanvas) {
// Zeroing the width and height causes Firefox to release graphics
// resources immediately, which can greatly reduce memory consumption.
tempCanvas.width = 0;
tempCanvas.height = 0;
}
PDFThumbnailView.tempImageCache = null;
},
/**
* @private
*/
_resetView: function PDFThumbnailViewer_resetView() {
this.thumbnails = [];
this._pagesRotation = 0;
this._pagesRequests = [];
},
setDocument: function PDFThumbnailViewer_setDocument(pdfDocument) {
if (this.pdfDocument) {
// cleanup of the elements and views
var thumbsView = this.container;
while (thumbsView.hasChildNodes()) {
thumbsView.removeChild(thumbsView.lastChild);
}
this._resetView();
}
this.pdfDocument = pdfDocument;
if (!pdfDocument) {
return Promise.resolve();
}
return pdfDocument.getPage(1).then(function (firstPage) {
var pagesCount = pdfDocument.numPages;
var viewport = firstPage.getViewport(1.0);
for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) {
var thumbnail = new PDFThumbnailView({
container: this.container,
id: pageNum,
defaultViewport: viewport.clone(),
linkService: this.linkService,
renderingQueue: this.renderingQueue
});
this.thumbnails.push(thumbnail);
}
}.bind(this));
},
/**
* @param {PDFPageView} pageView
* @returns {PDFPage}
* @private
*/
_ensurePdfPageLoaded:
function PDFThumbnailViewer_ensurePdfPageLoaded(thumbView) {
if (thumbView.pdfPage) {
return Promise.resolve(thumbView.pdfPage);
}
var pageNumber = thumbView.id;
if (this._pagesRequests[pageNumber]) {
return this._pagesRequests[pageNumber];
}
var promise = this.pdfDocument.getPage(pageNumber).then(
function (pdfPage) {
thumbView.setPdfPage(pdfPage);
this._pagesRequests[pageNumber] = null;
return pdfPage;
}.bind(this));
this._pagesRequests[pageNumber] = promise;
return promise;
},
ensureThumbnailVisible:
function PDFThumbnailViewer_ensureThumbnailVisible(page) {
// Ensure that the thumbnail of the current page is visible
// when switching from another view.
scrollIntoView(document.getElementById('thumbnailContainer' + page));
},
forceRendering: function () {
var visibleThumbs = this._getVisibleThumbs();
var thumbView = this.renderingQueue.getHighestPriority(visibleThumbs,
this.thumbnails,
this.scroll.down);
if (thumbView) {
this._ensurePdfPageLoaded(thumbView).then(function () {
this.renderingQueue.renderView(thumbView);
}.bind(this));
return true;
}
return false;
}
};
return PDFThumbnailViewer;
})();
/**
* @typedef {Object} PDFOutlineViewOptions
* @property {HTMLDivElement} container - The viewer element.
* @property {Array} outline - An array of outline objects.
* @property {IPDFLinkService} linkService - The navigation/linking service.
*/
/**
* @class
*/
var PDFOutlineView = (function PDFOutlineViewClosure() {
/**
* @constructs PDFOutlineView
* @param {PDFOutlineViewOptions} options
*/
function PDFOutlineView(options) {
this.container = options.container;
this.outline = options.outline;
this.linkService = options.linkService;
this.lastToggleIsShow = true;
}
PDFOutlineView.prototype = {
reset: function PDFOutlineView_reset() {
var container = this.container;
while (container.firstChild) {
container.removeChild(container.firstChild);
}
this.lastToggleIsShow = true;
},
/**
* @private
*/
_dispatchEvent: function PDFOutlineView_dispatchEvent(outlineCount) {
var event = document.createEvent('CustomEvent');
event.initCustomEvent('outlineloaded', true, true, {
outlineCount: outlineCount
});
this.container.dispatchEvent(event);
},
/**
* @private
*/
_bindLink: function PDFOutlineView_bindLink(element, item) {
var linkService = this.linkService;
element.href = linkService.getDestinationHash(item.dest);
element.onclick = function goToDestination(e) {
linkService.navigateTo(item.dest);
return false;
};
},
/**
* Prepend a button before an outline item which allows the user to toggle
* the visibility of all outline items at that level.
*
* @private
*/
_addToggleButton: function PDFOutlineView_addToggleButton(div) {
var toggler = document.createElement('div');
toggler.className = 'outlineItemToggler';
toggler.onclick = function (event) {
event.stopPropagation();
toggler.classList.toggle('outlineItemsHidden');
if (event.shiftKey) {
var shouldShowAll = !toggler.classList.contains('outlineItemsHidden');
this._toggleOutlineItem(div, shouldShowAll);
}
}.bind(this);
div.insertBefore(toggler, div.firstChild);
},
/**
* Toggle the visibility of the subtree of an outline item.
*
* @param {Element} root - the root of the outline (sub)tree.
* @param {boolean} state - whether to show the outline (sub)tree. If false,
* the outline subtree rooted at |root| will be collapsed.
*
* @private
*/
_toggleOutlineItem: function PDFOutlineView_toggleOutlineItem(root, show) {
this.lastToggleIsShow = show;
var togglers = root.querySelectorAll('.outlineItemToggler');
for (var i = 0, ii = togglers.length; i < ii; ++i) {
togglers[i].classList[show ? 'remove' : 'add']('outlineItemsHidden');
}
},
/**
* Collapse or expand all subtrees of the outline.
*/
toggleOutlineTree: function PDFOutlineView_toggleOutlineTree() {
this._toggleOutlineItem(this.container, !this.lastToggleIsShow);
},
render: function PDFOutlineView_render() {
var outline = this.outline;
var outlineCount = 0;
this.reset();
if (!outline) {
this._dispatchEvent(outlineCount);
return;
}
var fragment = document.createDocumentFragment();
var queue = [{parent: fragment, items: this.outline}];
var hasAnyNesting = false;
while (queue.length > 0) {
var levelData = queue.shift();
for (var i = 0, len = levelData.items.length; i < len; i++) {
var item = levelData.items[i];
var div = document.createElement('div');
div.className = 'outlineItem';
var element = document.createElement('a');
this._bindLink(element, item);
element.textContent = removeNullCharacters(item.title);
div.appendChild(element);
if (item.items.length > 0) {
hasAnyNesting = true;
this._addToggleButton(div);
var itemsDiv = document.createElement('div');
itemsDiv.className = 'outlineItems';
div.appendChild(itemsDiv);
queue.push({parent: itemsDiv, items: item.items});
}
levelData.parent.appendChild(div);
outlineCount++;
}
}
if (hasAnyNesting) {
this.container.classList.add('outlineWithDeepNesting');
}
this.container.appendChild(fragment);
this._dispatchEvent(outlineCount);
}
};
return PDFOutlineView;
})();
/**
* @typedef {Object} PDFAttachmentViewOptions
* @property {HTMLDivElement} container - The viewer element.
* @property {Array} attachments - An array of attachment objects.
* @property {DownloadManager} downloadManager - The download manager.
*/
/**
* @class
*/
var PDFAttachmentView = (function PDFAttachmentViewClosure() {
/**
* @constructs PDFAttachmentView
* @param {PDFAttachmentViewOptions} options
*/
function PDFAttachmentView(options) {
this.container = options.container;
this.attachments = options.attachments;
this.downloadManager = options.downloadManager;
}
PDFAttachmentView.prototype = {
reset: function PDFAttachmentView_reset() {
var container = this.container;
while (container.firstChild) {
container.removeChild(container.firstChild);
}
},
/**
* @private
*/
_dispatchEvent: function PDFAttachmentView_dispatchEvent(attachmentsCount) {
var event = document.createEvent('CustomEvent');
event.initCustomEvent('attachmentsloaded', true, true, {
attachmentsCount: attachmentsCount
});
this.container.dispatchEvent(event);
},
/**
* @private
*/
_bindLink: function PDFAttachmentView_bindLink(button, content, filename) {
button.onclick = function downloadFile(e) {
this.downloadManager.downloadData(content, filename, '');
return false;
}.bind(this);
},
render: function PDFAttachmentView_render() {
var attachments = this.attachments;
var attachmentsCount = 0;
this.reset();
if (!attachments) {
this._dispatchEvent(attachmentsCount);
return;
}
var names = Object.keys(attachments).sort(function (a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
});
attachmentsCount = names.length;
for (var i = 0; i < attachmentsCount; i++) {
var item = attachments[names[i]];
var filename = getFileName(item.filename);
var div = document.createElement('div');
div.className = 'attachmentsItem';
var button = document.createElement('button');
this._bindLink(button, item.content, filename);
button.textContent = removeNullCharacters(filename);
div.appendChild(button);
this.container.appendChild(div);
}
this._dispatchEvent(attachmentsCount);
}
};
return PDFAttachmentView;
})();
var PDFViewerApplication = {
initialBookmark: document.location.hash.substring(1),
initialDestination: null,
initialized: false,
fellback: false,
pdfDocument: null,
sidebarOpen: false,
printing: false,
/** @type {PDFViewer} */
pdfViewer: null,
/** @type {PDFThumbnailViewer} */
pdfThumbnailViewer: null,
/** @type {PDFRenderingQueue} */
pdfRenderingQueue: null,
/** @type {PDFPresentationMode} */
pdfPresentationMode: null,
/** @type {PDFDocumentProperties} */
pdfDocumentProperties: null,
/** @type {PDFLinkService} */
pdfLinkService: null,
/** @type {PDFHistory} */
pdfHistory: null,
pageRotation: 0,
isInitialViewSet: false,
animationStartedPromise: null,
preferenceSidebarViewOnLoad: SidebarView.NONE,
preferencePdfBugEnabled: false,
preferenceShowPreviousViewOnLoad: true,
preferenceDefaultZoomValue: '',
isViewerEmbedded: (window.parent !== window),
url: '',
documentAnnotations: null, //Added by Sri Krishnan
documentNotes: null, //Added by Sri Krishnan
rubberStampAnnotation: null, //Added by Sri Krishnan
deleteConfirmationPrompt: null, //Added by Sri Krishnan
stickyNotePrompt: null, //Added by Sri Krishnan
deleteAnnotationConfirmationPrompt: null, //Add by Sri Krishnan on 8th March 2017
digitalsignAnnotation: null,
// called once when the document is loaded
initialize: function pdfViewInitialize() {
var pdfRenderingQueue = new PDFRenderingQueue();
pdfRenderingQueue.onIdle = this.cleanup.bind(this);
this.pdfRenderingQueue = pdfRenderingQueue;
var pdfLinkService = new PDFLinkService();
this.pdfLinkService = pdfLinkService;
var container = document.getElementById('viewerContainer');
var viewer = document.getElementById('viewer');
this.pdfViewer = new PDFViewer({
container: container,
viewer: viewer,
renderingQueue: pdfRenderingQueue,
linkService: pdfLinkService
});
pdfRenderingQueue.setViewer(this.pdfViewer);
pdfLinkService.setViewer(this.pdfViewer);
var thumbnailContainer = document.getElementById('thumbnailView');
this.pdfThumbnailViewer = new PDFThumbnailViewer({
container: thumbnailContainer,
renderingQueue: pdfRenderingQueue,
linkService: pdfLinkService
});
pdfRenderingQueue.setThumbnailViewer(this.pdfThumbnailViewer);
Preferences.initialize();
this.pdfHistory = new PDFHistory({
linkService: pdfLinkService
});
pdfLinkService.setHistory(this.pdfHistory);
this.findController = new PDFFindController({
pdfViewer: this.pdfViewer,
integratedFind: this.supportsIntegratedFind
});
this.pdfViewer.setFindController(this.findController);
this.findBar = new PDFFindBar({
bar: document.getElementById('findbar'),
toggleButton: document.getElementById('viewFind'),
findField: document.getElementById('findInput'),
highlightAllCheckbox: document.getElementById('findHighlightAll'),
caseSensitiveCheckbox: document.getElementById('findMatchCase'),
findMsg: document.getElementById('findMsg'),
findStatusIcon: document.getElementById('findStatusIcon'),
findPreviousButton: document.getElementById('findPrevious'),
findNextButton: document.getElementById('findNext'),
findController: this.findController
});
this.findController.setFindBar(this.findBar);
HandTool.initialize({
container: container,
toggleHandTool: document.getElementById('toggleHandTool')
});
this.pdfDocumentProperties = new PDFDocumentProperties({
overlayName: 'documentPropertiesOverlay',
closeButton: document.getElementById('documentPropertiesClose'),
fields: {
'fileName': document.getElementById('fileNameField'),
'fileSize': document.getElementById('fileSizeField'),
'title': document.getElementById('titleField'),
'author': document.getElementById('authorField'),
'subject': document.getElementById('subjectField'),
'keywords': document.getElementById('keywordsField'),
'creationDate': document.getElementById('creationDateField'),
'modificationDate': document.getElementById('modificationDateField'),
'creator': document.getElementById('creatorField'),
'producer': document.getElementById('producerField'),
'version': document.getElementById('versionField'),
'pageCount': document.getElementById('pageCountField')
}
});
this.rubberStampAnnotation = new RubberStampAnnotation({overlayName: 'rubberStampOverlay',
closeButton: document.getElementById('rubberStampOverlayCancel'),
okButton: document.getElementById('rubberStampOverlayOK'),
});
this.digitalsignAnnotation = new DigitalSignAnnotation({overlayName: 'digitalsignOverlay',
closeButton: document.getElementById('digitalsignOverlayCancel'),
okButton: document.getElementById('digitalsignOverlayOK'),
});
this.deleteConfirmationPrompt = new DeleteConfirmationPrompt({overlayName: 'confirmDeleteOverlay',
closeButton: document.getElementById('deleteCancel'),
okButton: document.getElementById('deleteSubmit'),
});
this.deleteAnnotationConfirmationPrompt = new DeleteAnnotationConfirmationPrompt({overlayName: 'confirmDeleteAnnotationOverlay',
closeButton: document.getElementById('deleteNo'),
okButton: document.getElementById('deleteYes'),
});
this.stickyNotePrompt = new StickyNotePrompt({overlayName: 'stickyNoteOverlay',
closeButton: document.getElementById('stickyNoteCancel'),
okButton: document.getElementById('stickyNoteSubmit'),
});
SecondaryToolbar.initialize({
toolbar: document.getElementById('secondaryToolbar'),
toggleButton: document.getElementById('secondaryToolbarToggle'),
presentationModeButton:
document.getElementById('secondaryPresentationMode'),
openFile: document.getElementById('secondaryOpenFile'),
print: document.getElementById('secondaryPrint'),
download: document.getElementById('secondaryDownload'),
viewBookmark: document.getElementById('secondaryViewBookmark'),
firstPage: document.getElementById('firstPage'),
lastPage: document.getElementById('lastPage'),
pageRotateCw: document.getElementById('pageRotateCw'),
pageRotateCcw: document.getElementById('pageRotateCcw'),
documentPropertiesButton: document.getElementById('documentProperties')
});
if (this.supportsFullscreen) {
var toolbar = SecondaryToolbar;
this.pdfPresentationMode = new PDFPresentationMode({
container: container,
viewer: viewer,
pdfViewer: this.pdfViewer,
pdfThumbnailViewer: this.pdfThumbnailViewer,
contextMenuItems: [
{element: document.getElementById('contextFirstPage'),
handler: toolbar.firstPageClick.bind(toolbar)},
{element: document.getElementById('contextLastPage'),
handler: toolbar.lastPageClick.bind(toolbar)},
{element: document.getElementById('contextPageRotateCw'),
handler: toolbar.pageRotateCwClick.bind(toolbar)},
{element: document.getElementById('contextPageRotateCcw'),
handler: toolbar.pageRotateCcwClick.bind(toolbar)}
]
});
}
PasswordPrompt.initialize({
overlayName: 'passwordOverlay',
passwordField: document.getElementById('password'),
passwordText: document.getElementById('passwordText'),
passwordSubmit: document.getElementById('passwordSubmit'),
passwordCancel: document.getElementById('passwordCancel')
});
var self = this;
var initializedPromise = Promise.all([
Preferences.get('enableWebGL').then(function resolved(value) {
PDFJS.disableWebGL = !value;
}),
Preferences.get('sidebarViewOnLoad').then(function resolved(value) {
self.preferenceSidebarViewOnLoad = value;
}),
Preferences.get('pdfBugEnabled').then(function resolved(value) {
self.preferencePdfBugEnabled = value;
}),
Preferences.get('showPreviousViewOnLoad').then(function resolved(value) {
self.preferenceShowPreviousViewOnLoad = value;
}),
Preferences.get('defaultZoomValue').then(function resolved(value) {
self.preferenceDefaultZoomValue = value;
}),
Preferences.get('disableTextLayer').then(function resolved(value) {
if (PDFJS.disableTextLayer === true) {
return;
}
PDFJS.disableTextLayer = value;
}),
Preferences.get('disableRange').then(function resolved(value) {
if (PDFJS.disableRange === true) {
return;
}
PDFJS.disableRange = value;
}),
Preferences.get('disableStream').then(function resolved(value) {
if (PDFJS.disableStream === true) {
return;
}
PDFJS.disableStream = value;
}),
Preferences.get('disableAutoFetch').then(function resolved(value) {
PDFJS.disableAutoFetch = value;
}),
Preferences.get('disableFontFace').then(function resolved(value) {
if (PDFJS.disableFontFace === true) {
return;
}
PDFJS.disableFontFace = value;
}),
Preferences.get('useOnlyCssZoom').then(function resolved(value) {
PDFJS.useOnlyCssZoom = value;
})
// TODO move more preferences and other async stuff here
]).catch(function (reason) { });
return initializedPromise.then(function () {
PDFViewerApplication.initialized = true;
});
},
zoomIn: function pdfViewZoomIn(ticks) {
var newScale = this.pdfViewer.currentScale;
do {
newScale = (newScale * DEFAULT_SCALE_DELTA).toFixed(2);
newScale = Math.ceil(newScale * 10) / 10;
newScale = Math.min(MAX_SCALE, newScale);
} while (--ticks > 0 && newScale < MAX_SCALE);
this.pdfViewer.currentScaleValue = newScale;
},
zoomOut: function pdfViewZoomOut(ticks) {
var newScale = this.pdfViewer.currentScale;
do {
newScale = (newScale / DEFAULT_SCALE_DELTA).toFixed(2);
newScale = Math.floor(newScale * 10) / 10;
newScale = Math.max(MIN_SCALE, newScale);
} while (--ticks > 0 && newScale > MIN_SCALE);
this.pdfViewer.currentScaleValue = newScale;
},
get pagesCount() {
return this.pdfDocument.numPages;
},
set page(val) {
this.pdfLinkService.page = val;
},
get page() { // TODO remove
return this.pdfLinkService.page;
},
get supportsPrinting() {
var canvas = document.createElement('canvas');
var value = 'mozPrintCallback' in canvas;
return PDFJS.shadow(this, 'supportsPrinting', value);
},
get supportsFullscreen() {
var doc = document.documentElement;
var support = !!(doc.requestFullscreen || doc.mozRequestFullScreen ||
doc.webkitRequestFullScreen || doc.msRequestFullscreen);
if (document.fullscreenEnabled === false ||
document.mozFullScreenEnabled === false ||
document.webkitFullscreenEnabled === false ||
document.msFullscreenEnabled === false) {
support = false;
}
if (support && PDFJS.disableFullscreen === true) {
support = false;
}
return PDFJS.shadow(this, 'supportsFullscreen', support);
},
get supportsIntegratedFind() {
var support = false;
return PDFJS.shadow(this, 'supportsIntegratedFind', support);
},
get supportsDocumentFonts() {
var support = true;
return PDFJS.shadow(this, 'supportsDocumentFonts', support);
},
get supportsDocumentColors() {
var support = true;
return PDFJS.shadow(this, 'supportsDocumentColors', support);
},
get loadingBar() {
var bar = new ProgressBar('#loadingBar', {});
return PDFJS.shadow(this, 'loadingBar', bar);
},
setTitleUsingUrl: function pdfViewSetTitleUsingUrl(url) {
this.url = url;
try {
this.setTitle(decodeURIComponent(getFileName(url)) || url);
} catch (e) {
// decodeURIComponent may throw URIError,
// fall back to using the unprocessed url in that case
this.setTitle(url);
}
},
setTitle: function pdfViewSetTitle(title) {
if (this.isViewerEmbedded) {
// Embedded PDF viewers should not be changing their parent page's title.
return;
}
document.title = title;
},
close: function pdfViewClose() {
var errorWrapper = document.getElementById('errorWrapper');
errorWrapper.setAttribute('hidden', 'true');
if (!this.pdfDocument) {
return;
}
this.pdfDocument.destroy();
this.pdfDocument = null;
this.pdfThumbnailViewer.setDocument(null);
this.pdfViewer.setDocument(null);
this.pdfLinkService.setDocument(null, null);
if (typeof PDFBug !== 'undefined') {
PDFBug.cleanup();
}
},
// TODO(mack): This function signature should really be pdfViewOpen(url, args)
open: function pdfViewOpen(file, scale, password,
pdfDataRangeTransport, args) {
if (this.pdfDocument) {
// Reload the preferences if a document was previously opened.
Preferences.reload();
}
this.close();
var parameters = {password: password};
if (typeof file === 'string') { // URL
this.setTitleUsingUrl(file);
parameters.url = file;
} else if (file && 'byteLength' in file) { // ArrayBuffer
parameters.data = file;
} else if (file.url && file.originalUrl) {
this.setTitleUsingUrl(file.originalUrl);
parameters.url = file.url;
}
if (args) {
for (var prop in args) {
parameters[prop] = args[prop];
}
}
var self = this;
self.downloadComplete = false;
var passwordNeeded = function passwordNeeded(updatePassword, reason) {
PasswordPrompt.updatePassword = updatePassword;
PasswordPrompt.reason = reason;
PasswordPrompt.open();
};
function getDocumentProgress(progressData) {
self.progress(progressData.loaded / progressData.total);
}
PDFJS.getDocument(parameters, pdfDataRangeTransport, passwordNeeded,
getDocumentProgress).then(
function getDocumentCallback(pdfDocument) {
self.load(pdfDocument, scale);
},
function getDocumentError(exception) {
var message = exception && exception.message;
var loadingErrorMessage = mozL10n.get('loading_error', null,
'An error occurred while loading the PDF.');
if (exception instanceof PDFJS.InvalidPDFException) {
// change error message also for other builds
loadingErrorMessage = mozL10n.get('invalid_file_error', null,
'Invalid or corrupted PDF file.');
} else if (exception instanceof PDFJS.MissingPDFException) {
// special message for missing PDF's
loadingErrorMessage = mozL10n.get('missing_file_error', null,
'Missing PDF file.');
} else if (exception instanceof PDFJS.UnexpectedResponseException) {
loadingErrorMessage = mozL10n.get('unexpected_response_error', null,
'Unexpected server response.');
}
var moreInfo = {
message: message
};
self.error(loadingErrorMessage, moreInfo);
}
);
if (args && args.length) {
PDFViewerApplication.pdfDocumentProperties.setFileSize(args.length);
}
},
download: function pdfViewDownload() {
function downloadByUrl() {
downloadManager.downloadUrl(url, filename);
}
var url = this.url.split('#')[0];
var filename = getPDFFileNameFromURL(url);
var downloadManager = new DownloadManager();
downloadManager.onerror = function (err) {
// This error won't really be helpful because it's likely the
// fallback won't work either (or is already open).
PDFViewerApplication.error('PDF failed to download.');
};
if (!this.pdfDocument) { // the PDF is not ready yet
downloadByUrl();
return;
}
if (!this.downloadComplete) { // the PDF is still downloading
downloadByUrl();
return;
}
this.pdfDocument.getData().then(
function getDataSuccess(data) {
var blob = PDFJS.createBlob(data, 'application/pdf');
downloadManager.download(blob, url, filename);
},
downloadByUrl // Error occurred try downloading with just the url.
).then(null, downloadByUrl);
},
fallback: function pdfViewFallback(featureId) {
},
/**
* Show the error box.
* @param {String} message A message that is human readable.
* @param {Object} moreInfo (optional) Further information about the error
* that is more technical. Should have a 'message'
* and optionally a 'stack' property.
*/
error: function pdfViewError(message, moreInfo) {
var moreInfoText = mozL10n.get('error_version_info',
{version: PDFJS.version || '?', build: PDFJS.build || '?'},
'PDF.js v{{version}} (build: {{build}})') + '
';
if (moreInfo) {
moreInfoText +=
mozL10n.get('error_message', {message: moreInfo.message},
'Message: {{message}}');
if (moreInfo.stack) {
moreInfoText += '
' +
mozL10n.get('error_stack', {stack: moreInfo.stack},
'Stack: {{stack}}');
} else {
if (moreInfo.filename) {
moreInfoText += '
' +
mozL10n.get('error_file', {file: moreInfo.filename},
'File: {{file}}');
}
if (moreInfo.lineNumber) {
moreInfoText += '
' +
mozL10n.get('error_line', {line: moreInfo.lineNumber},
'Line: {{line}}');
}
}
}
var errorWrapper = document.getElementById('errorWrapper');
errorWrapper.removeAttribute('hidden');
var errorMessage = document.getElementById('errorMessage');
errorMessage.textContent = message;
var closeButton = document.getElementById('errorClose');
closeButton.onclick = function () {
errorWrapper.setAttribute('hidden', 'true');
};
var errorMoreInfo = document.getElementById('errorMoreInfo');
var moreInfoButton = document.getElementById('errorShowMore');
var lessInfoButton = document.getElementById('errorShowLess');
moreInfoButton.onclick = function () {
errorMoreInfo.removeAttribute('hidden');
moreInfoButton.setAttribute('hidden', 'true');
lessInfoButton.removeAttribute('hidden');
errorMoreInfo.style.height = errorMoreInfo.scrollHeight + 'px';
};
lessInfoButton.onclick = function () {
errorMoreInfo.setAttribute('hidden', 'true');
moreInfoButton.removeAttribute('hidden');
lessInfoButton.setAttribute('hidden', 'true');
};
moreInfoButton.oncontextmenu = noContextMenuHandler;
lessInfoButton.oncontextmenu = noContextMenuHandler;
closeButton.oncontextmenu = noContextMenuHandler;
moreInfoButton.removeAttribute('hidden');
lessInfoButton.setAttribute('hidden', 'true');
errorMoreInfo.value = moreInfoText;
},
progress: function pdfViewProgress(level) {
var percent = Math.round(level * 100);
// When we transition from full request to range requests, it's possible
// that we discard some of the loaded data. This can cause the loading
// bar to move backwards. So prevent this by only updating the bar if it
// increases.
if (percent > this.loadingBar.percent || isNaN(percent)) {
this.loadingBar.percent = percent;
// When disableAutoFetch is enabled, it's not uncommon for the entire file
// to never be fetched (depends on e.g. the file structure). In this case
// the loading bar will not be completely filled, nor will it be hidden.
// To prevent displaying a partially filled loading bar permanently, we
// hide it when no data has been loaded during a certain amount of time.
if (PDFJS.disableAutoFetch && percent) {
if (this.disableAutoFetchLoadingBarTimeout) {
clearTimeout(this.disableAutoFetchLoadingBarTimeout);
this.disableAutoFetchLoadingBarTimeout = null;
}
this.loadingBar.show();
this.disableAutoFetchLoadingBarTimeout = setTimeout(function () {
this.loadingBar.hide();
this.disableAutoFetchLoadingBarTimeout = null;
}.bind(this), DISABLE_AUTO_FETCH_LOADING_BAR_TIMEOUT);
}
}
},
load: function pdfViewLoad(pdfDocument, scale) {
var self = this;
scale = scale || UNKNOWN_SCALE;
this.findController.reset();
this.pdfDocument = pdfDocument;
this.pdfDocumentProperties.setDocumentAndUrl(pdfDocument, this.url);
var downloadedPromise = pdfDocument.getDownloadInfo().then(function () {
self.downloadComplete = true;
self.loadingBar.hide();
});
var pagesCount = pdfDocument.numPages;
document.getElementById('numPages').textContent =
mozL10n.get('page_of', {pageCount: pagesCount}, 'of {{pageCount}}');
document.getElementById('pageNumber').max = pagesCount;
var id = this.documentFingerprint = pdfDocument.fingerprint;
var store = this.store = new ViewHistory(id);
var baseDocumentUrl = null;
this.pdfLinkService.setDocument(pdfDocument, baseDocumentUrl);
var pdfViewer = this.pdfViewer;
pdfViewer.currentScale = scale;
pdfViewer.setDocument(pdfDocument);
var firstPagePromise = pdfViewer.firstPagePromise;
var pagesPromise = pdfViewer.pagesPromise;
var onePageRendered = pdfViewer.onePageRendered;
this.pageRotation = 0;
this.isInitialViewSet = false;
this.pdfThumbnailViewer.setDocument(pdfDocument);
firstPagePromise.then(function (pdfPage) {
downloadedPromise.then(function () {
var event = document.createEvent('CustomEvent');
event.initCustomEvent('documentload', true, true, {});
window.dispatchEvent(event);
});
self.loadingBar.setWidth(document.getElementById('viewer'));
if (!PDFJS.disableHistory && !self.isViewerEmbedded) {
// The browsing history is only enabled when the viewer is standalone,
// i.e. not when it is embedded in a web page.
if (!self.preferenceShowPreviousViewOnLoad) {
self.pdfHistory.clearHistoryState();
}
self.pdfHistory.initialize(self.documentFingerprint);
if (self.pdfHistory.initialDestination) {
self.initialDestination = self.pdfHistory.initialDestination;
} else if (self.pdfHistory.initialBookmark) {
self.initialBookmark = self.pdfHistory.initialBookmark;
}
}
store.initializedPromise.then(function resolved() {
var storedHash = null;
if (self.preferenceShowPreviousViewOnLoad &&
store.get('exists', false)) {
var pageNum = store.get('page', '1');
var zoom = self.preferenceDefaultZoomValue ||
store.get('zoom', DEFAULT_SCALE_VALUE);
var left = store.get('scrollLeft', '0');
var top = store.get('scrollTop', '0');
storedHash = 'page=' + pageNum + '&zoom=' + zoom + ',' +
left + ',' + top;
} else if (self.preferenceDefaultZoomValue) {
storedHash = 'page=1&zoom=' + self.preferenceDefaultZoomValue;
}
self.setInitialView(storedHash, scale);
// Make all navigation keys work on document load,
// unless the viewer is embedded in a web page.
if (!self.isViewerEmbedded) {
self.pdfViewer.focus();
}
}, function rejected(reason) {
console.error(reason);
self.setInitialView(null, scale);
});
});
pagesPromise.then(function () {
if (self.supportsPrinting) {
pdfDocument.getJavaScript().then(function (javaScript) {
if (javaScript.length) {
console.warn('Warning: JavaScript is not supported');
self.fallback(PDFJS.UNSUPPORTED_FEATURES.javaScript);
}
// Hack to support auto printing.
var regex = /print\s*\(/;
for (var i = 0, ii = javaScript.length; i < ii; i++) {
var js = javaScript[i];
if (js && regex.test(js)) {
setTimeout(function () {
window.print();
});
return;
}
}
});
}
});
// outline depends on pagesRefMap
var promises = [pagesPromise, this.animationStartedPromise];
Promise.all(promises).then(function () {
pdfDocument.getOutline().then(function (outline) {
var container = document.getElementById('outlineView');
self.outline = new PDFOutlineView({
container: container,
outline: outline,
linkService: self.pdfLinkService
});
self.outline.render();
document.getElementById('viewOutline').disabled = !outline;
if (!outline && !container.classList.contains('hidden')) {
self.switchSidebarView('thumbs');
}
if (outline &&
self.preferenceSidebarViewOnLoad === SidebarView.OUTLINE) {
self.switchSidebarView('outline', true);
}
});
pdfDocument.getAttachments().then(function (attachments) {
var container = document.getElementById('attachmentsView');
self.attachments = new PDFAttachmentView({
container: container,
attachments: attachments,
// downloadManager: new DownloadManager()
});
self.attachments.render();
document.getElementById('viewAttachments').disabled = !attachments;
if (!attachments && !container.classList.contains('hidden')) {
self.switchSidebarView('thumbs');
}
if (attachments &&
self.preferenceSidebarViewOnLoad === SidebarView.ATTACHMENTS) {
self.switchSidebarView('attachments', true);
}
});
});
if (self.preferenceSidebarViewOnLoad === SidebarView.THUMBS) {
Promise.all([firstPagePromise, onePageRendered]).then(function () {
self.switchSidebarView('thumbs', true);
});
}
pdfDocument.getMetadata().then(function (data) {
var info = data.info, metadata = data.metadata;
self.documentInfo = info;
self.metadata = metadata;
// Provides some basic debug information
console.log('PDF ' + pdfDocument.fingerprint + ' [' +
info.PDFFormatVersion + ' ' + (info.Producer || '-').trim() +
' / ' + (info.Creator || '-').trim() + ']' +
' (PDF.js: ' + (PDFJS.version || '-') +
(!PDFJS.disableWebGL ? ' [WebGL]' : '') + ')');
var pdfTitle;
if (metadata && metadata.has('dc:title')) {
var title = metadata.get('dc:title');
// Ghostscript sometimes return 'Untitled', sets the title to 'Untitled'
if (title !== 'Untitled') {
pdfTitle = title;
}
}
if (!pdfTitle && info && info['Title']) {
pdfTitle = info['Title'];
}
if (pdfTitle) {
self.setTitle(pdfTitle + ' - ' + document.title);
}
if (info.IsAcroFormPresent) {
console.warn('Warning: AcroForm/XFA is not supported');
self.fallback(PDFJS.UNSUPPORTED_FEATURES.forms);
}
});
},
setInitialView: function pdfViewSetInitialView(storedHash, scale) {
this.isInitialViewSet = true;
// When opening a new file, when one is already loaded in the viewer,
// ensure that the 'pageNumber' element displays the correct value.
document.getElementById('pageNumber').value = this.pdfViewer.currentPageNumber;
if (this.initialDestination) {
this.pdfLinkService.navigateTo(this.initialDestination);
this.initialDestination = null;
} else if (this.initialBookmark) {
this.pdfLinkService.setHash(this.initialBookmark);
this.pdfHistory.push({hash: this.initialBookmark}, true);
this.initialBookmark = null;
} else if (storedHash) {
this.pdfLinkService.setHash(storedHash);
} else if (scale) {
this.pdfViewer.currentScaleValue = scale;
this.page = 1;
}
//load document notes now.
PDFViewerApplication.loadDocumentNotes(); //Sri Krishnan
//load document annotations now
PDFViewerApplication.loadDocumentAnnotations(); //Sri Krishnan
if (!this.pdfViewer.currentScaleValue) {
// Scale was not initialized: invalid bookmark or scale was not specified.
// Setting the default one.
this.pdfViewer.currentScaleValue = DEFAULT_SCALE_VALUE;
}
},
cleanup: function pdfViewCleanup() {
this.pdfViewer.cleanup();
this.pdfThumbnailViewer.cleanup();
this.pdfDocument.cleanup();
},
forceRendering: function pdfViewForceRendering() {
this.pdfRenderingQueue.printing = this.printing;
this.pdfRenderingQueue.isThumbnailViewEnabled = this.sidebarOpen;
this.pdfRenderingQueue.renderHighestPriority();
},
refreshThumbnailViewer: function pdfViewRefreshThumbnailViewer() {
var pdfViewer = this.pdfViewer;
var thumbnailViewer = this.pdfThumbnailViewer;
// set thumbnail images of rendered pages
var pagesCount = pdfViewer.pagesCount;
for (var pageIndex = 0; pageIndex < pagesCount; pageIndex++) {
var pageView = pdfViewer.getPageView(pageIndex);
if (pageView && pageView.renderingState === RenderingStates.FINISHED) {
var thumbnailView = thumbnailViewer.getThumbnail(pageIndex);
thumbnailView.setImage(pageView);
}
}
thumbnailViewer.scrollThumbnailIntoView(this.page);
},
//Added by Sri Krishnan
saveAndLoadDocumentNotes: function pdfSaveAndLoadDocumentNotes() {
var txtNote = document.getElementById("txtNote").value;
var noteField = document.getElementById("txtNote");
noteField.classList.remove('error');
if ($.trim(txtNote).length == 0) {
noteField.classList.add('error');
return;
}
$.ajax({
type: "POST",
url: $("#frmNotes").attr("action"),
data: $("#frmNotes").serialize(),
success: function (response) {
$("#frmNotes")[0].reset();
PDFViewerApplication.loadDocumentNotes();
},
error: function (jqXHR, exception) {
$("#resultNotes").html("Unable to load notes");
}
});
},
deleteDocumentNote: function pdfDeleteNote(noteId) {
var documentid = document.getElementById("documentid").value;
$.ajax({
async: false,
type: "GET",
url: "dms/documentnotes.php?documentid=" + documentid + "¬eid=" + noteId,
success: function (response) {
PDFViewerApplication.loadDocumentNotes();
},
error: function (jqXHR, exception) {
$("#resultNotes").html("Unable to load notes");
}
});
},
loadDocumentNotes: function pdfLoadDocumentNotes() {
var documentid = document.getElementById("documentid").value;
var username = document.getElementById("username").value;
$.ajax({
type: "GET",
url: "dms/documentnotes.php?documentid=" + documentid,
success: function (response) {
PDFViewerApplication.documentNotes = JSON.parse(response);
$("#resultNotes").empty();
for (var i = 0; i < PDFViewerApplication.documentNotes.length; i++) {
var documentNote = PDFViewerApplication.documentNotes[i];
var noteContainer = document.createElement("div");
if ("P" === documentNote.noteType) {
noteContainer.classList.add("documentnote");
} else {
noteContainer.classList.add("documentnoteprivate");
}
var html = "";
html += "<div class='username'>" + documentNote.userName + "</div>";
if (username === documentNote.userName) {
html += "<div class='deleteicon'><a href='javascript:void(0);' class='overlayButton deletenote' noteid='" + documentNote.noteId + "'><i class='fa fa-trash-o' aria-hidden='true'></i></a></div>";
}
html += "<div style='clear:both'></div><hr/>";
html += "<div class='notedata'>" + documentNote.noteData + "</div>";
html += "<p class='notedate'> - " + documentNote.friendlyDate + "</p>";
$(noteContainer).html(html);
$("#resultNotes").append(noteContainer);
}
},
error: function (jqXHR, exception) {
$("#resultNotes").html("Unable to load notes");
}
});
},
loadDocumentAnnotations: function pdfLoadDocumentAnnotations() {
var documentid = document.getElementById("documentid").value;
var revisionid = document.getElementById("revisionid").value;
PDFViewerApplication.documentAnnotations = new Array();
var annotationUrl = "dms/documentannotations.php?documentid=" + documentid + "&revisionid=" + revisionid;
if (sharedDocumentID) {
annotationUrl = "/shareddocument?MODE=ANN&ID=" + sharedDocumentID;
}
$.ajax({
async: false,
type: "GET",
url: annotationUrl,
success: function (response) {
PDFViewerApplication.documentAnnotations = JSON.parse(response);
},
error: function (jqXHR, exception) {
PDFViewerApplication.documentAnnotations = new Array();
}
});
for (var i = 0; i < PDFViewerApplication.documentAnnotations.length; i++) {
var annotation = PDFViewerApplication.documentAnnotations[i];
annotation.tempId = annotation.annotationId;
}
},
saveAndLoadDocumentAnnotations: function pdfSaveAndLoadDocumentAnnotations() {
var documentid = document.getElementById("documentid").value;
var revisionid = document.getElementById("revisionid").value;
var finalAnnotations = new Array();
for (var i = 0; i < PDFViewerApplication.documentAnnotations.length; i++) {
var annotation = PDFViewerApplication.documentAnnotations[i];
if (annotation.annotationId == -1) { //newly created annotation so check if it is deleted or not
if (annotation.deleted) {
continue; //dont add this to final annotations to be posted to database.
}
}
if (annotation.deleted) {
annotation.action = 2; //indicates that existing annotation is deleted
}
if (annotation.dirty) {
finalAnnotations.push(annotation);
}
}
var annotations = JSON.stringify(finalAnnotations);
$.ajax({
async: false,
type: "GET",
url: "dms/documentannotations.php?documentid=" + documentid + "&revisionid=" + revisionid + "&annotations=" + annotations,
success: function (response) {
PDFViewerApplication.documentAnnotations = JSON.parse(response);
},
error: function (jqXHR, exception) {
PDFViewerApplication.documentAnnotations = new Array();
}
});
for (var i = 0; i < PDFViewerApplication.documentAnnotations.length; i++) {
var annotation = PDFViewerApplication.documentAnnotations[i];
annotation.tempId = annotation.annotationId;
}
//alert(annotation.tempId);
},
createDocumentAnnotation: function pdfCreateNewAnnotation(annotationType) {
if (PDFViewerApplication.pdfViewer._pagesRotation == 0) {
drawAnnotation = true;
newAnnotation = new DocumentAnnotation({});
newAnnotation.annotationId = "-1";
newAnnotation.tempId = new Date().getTime();
newAnnotation.opacity = 1;
newAnnotation.dirty = true;
newAnnotation.annotationType = annotationType;
if (annotationType == ANNOTATION_HIGHLIGHT) {
newAnnotation.colorRed = 255;
newAnnotation.colorGreen = 255;
newAnnotation.colorBlue = 128;
} else if (annotationType == ANNOTATION_BLACKOUT) {
newAnnotation.colorRed = 255;
newAnnotation.colorGreen = 255;
newAnnotation.colorBlue = 255;
} else if (annotationType == ANNOTATION_ELLIPSE) {
newAnnotation.colorRed = 255;
newAnnotation.colorGreen = 0;
newAnnotation.colorBlue = 0;
} else if (annotationType == ANNOTATION_STICKYNOTE) {
newAnnotation.colorRed = 255;
newAnnotation.colorGreen = 255;
newAnnotation.colorBlue = 128;
newAnnotation.text = "";
} else {
newAnnotation.colorRed = 255;
newAnnotation.colorGreen = 0;
newAnnotation.colorBlue = 0;
}
}
},
drawDocumentAnnotations: function pdfDrawDocumentAnnotations(pageView, annCtx, pageNumber) {
document.getElementById("viewer").classList.add("hidden");
annCtx.clearRect(0, 0, pageView.width * window.devicePixelRatio, pageView.height * window.devicePixelRatio);
if (pageView.rotation == 90) {
annCtx.translate(pageView.width, 0);
} else if (pageView.rotation == 180) {
annCtx.translate(pageView.width, pageView.height);
} else if (pageView.rotation == 270) {
annCtx.translate(0, pageView.height);
} else {
annCtx.translate(0, 0);
}
annCtx.rotate(pageView.rotation * Math.PI / 180);
for (var i = 0; i < PDFViewerApplication.documentAnnotations.length; i++) {
var ann = PDFViewerApplication.documentAnnotations[i];
var documentAnnotation = new DocumentAnnotation(ann);
if (pageNumber == documentAnnotation.pageId) {
if (!documentAnnotation.deleted) {
documentAnnotation.draw(annCtx, pageView.scale);
}
}
}
$("#annotationsView").empty();
var annotationsCount = 0;
for (var i = 0; i < PDFViewerApplication.documentAnnotations.length; i++) {
var documentAnnotation = PDFViewerApplication.documentAnnotations[i];
var annContainer = document.createElement("div");
if (!documentAnnotation.deleted) {
var html = "";
html += "<a href='javascript:void(0);' tempannotationid='" + documentAnnotation.tempId + "' class='annselector'>";
html += "<div class='documentannotation'>";
html += "<div class='username'>" + documentAnnotation.userName + "</div>";
if (documentAnnotation.annotationType === ANNOTATION_HIGHLIGHT) {
html += "<div class='annotation annotation-highlight'></div>";
} else if (documentAnnotation.annotationType === ANNOTATION_BLACKOUT) {
html += "<div class='annotation annotation-blackout'></div>";
} else if (documentAnnotation.annotationType === ANNOTATION_ELLIPSE) {
html += "<div class='annotation annotation-ellipse'></div>";
} else if (documentAnnotation.annotationType === ANNOTATION_STICKYNOTE) {
html += "<div class='annotation annotation-note'></div>";
} else if (documentAnnotation.annotationType === ANNOTATION_SIGN) {
html += "<div class='annotation annotation-sign'></div>";
} else {
html += "<div class='annotation annotation-rubberstamp'></div>";
}
html += "</div>";
html += "</a>";
$(annContainer).html(html);
$("#annotationsView").append(annContainer);
annotationsCount++;
}
}
if (annotationsCount <= 0) {
var annContainer = document.createElement("div");
var html = "<div class='documentannotation'>No annotations found</div>";
$(annContainer).html(html);
$("#annotationsView").append(annContainer);
}
document.getElementById("viewer").classList.remove("hidden");
},
deleteDocumentAnnotation: function pdfDeleteDocumentAnnotation() {
var str_rights ="<?php echo $right_str; ?>";
var res_rights = str_rights.split(",");
// alert(str_rights);
// console.log(res_rights);
for (var i = 0; i < PDFViewerApplication.documentAnnotations.length; i++) {
var ann = PDFViewerApplication.documentAnnotations[i];
// alert(jQuery.inArray("90002", res_rights ));
var ann_str = ann.annotationType;
// alert( str_rights.search(ann_str));
if(str_rights.search(ann_str)==-1){
if (ann.selected) {
//if( (ann.userName === userName || userName === 'ADMINISTRATOR' ) && canEdit ){
PDFViewerApplication.deleteAnnotationConfirmationPrompt.open(ann);
break;
//}
}
}
}
},
selectDocumentAnnotation: function pdfSelectDocumentAnnotation(ev) {
var str_rights ="<?php echo $right_str; ?>";
var scale = PDFViewerApplication.pdfViewer.currentScale;
var ctx = ev.target.getContext('2d');
isDrag = false;
ctx.clearRect(0, 0, ev.target.width, ev.target.height);
for (var i = 0; i < PDFViewerApplication.documentAnnotations.length; i++) {
var ann = PDFViewerApplication.documentAnnotations[i];
//console.log(ann);
var ann_str = ann.annotationType;
var ann_user_id = ann.user_id;
//alert(ann_user_id);
isDrag = false;
var temp = 0;
if (ann.x2 < ann.x1) {
temp = ann.x2;
ann.x2 = ann.x1;
ann.x1 = temp;
}
if (ann.y2 < ann.y1) {
temp = ann.y2;
ann.y2 = ann.y1;
ann.y1 = temp;
}
if (ann.pageId == ev.target.pageNumber) {
if (mouseX >= ann.x1 * scale && mouseX <= ann.x2 * scale && mouseY >= ann.y1 * scale && mouseY <= ann.y2 * scale) {
if (!ann.deleted) {
//if( (ann.userName === userName || userName === 'ADMINISTRATOR' ) && canEdit ){ //Check if the user is creator of annotation
ann.selected = true;
annWidth = (ann.x2 - ann.x1);
annHeight = (ann.y2 - ann.y1);
selectedAnnotation = ann;
offsetx = parseInt(mouseX - (ann.x1 * scale));
offsety = parseInt(mouseY - (ann.y1 * scale));
if(str_rights.search(ann_str)==-1){
isDrag = true;
if(ann_str==ANNOTATION_SIGN){
//alert(ann_user_id);
if(ann_user_id == _user_id || ann_user_id ==undefined)
{
isDrag = true;
}else if( _user_role == 1 || _user_role == 2){
isDrag = true;
}else{
isDrag = false;
}
}
}else{
isDrag = false;
}
break;
//}
}
}
}
}
if (!isDrag) { //no annotation are selected so make all annotations as un selected
selectedAnnotation = null;
ctx.clearRect(0, 0, ev.target.width, ev.target.height);
for (var i = 0; i < PDFViewerApplication.documentAnnotations.length; i++) {
var ann = PDFViewerApplication.documentAnnotations[i];
ann.selected = false;
}
}
},
changeDocumentAnnotationColor: function pdfChangeDocumentAnnotationColor(colorPicker) {
colorRed = Math.round(colorPicker.rgb[0]);
colorGreen = Math.round(colorPicker.rgb[1]);
colorBlue = Math.round(colorPicker.rgb[2]);
for (var i = 0; i < PDFViewerApplication.documentAnnotations.length; i++) {
var ann = PDFViewerApplication.documentAnnotations[i];
if (ann.selected == true) {
ann.colorRed = colorRed;
ann.colorGreen = colorGreen;
ann.colorBlue = colorBlue;
ann.dirty = true;
var pageView = PDFViewerApplication.pdfViewer.getPageView(ann.pageId - 1);
PDFViewerApplication.drawDocumentAnnotations(pageView, pageView.context, ann.pageId);
break;
}
}
},
//Added till here by Sri Krishnan
switchSidebarView: function pdfViewSwitchSidebarView(view, openSidebar) {
if (openSidebar && !this.sidebarOpen) {
document.getElementById('sidebarToggle').click();
}
var thumbsView = document.getElementById('thumbnailView');
var outlineView = document.getElementById('outlineView');
var attachmentsView = document.getElementById('attachmentsView');
var notesView = document.getElementById('notesView');//Sri Krishnan
var annotationsView = document.getElementById('annotationsView');//Sri Krishnan
var thumbsButton = document.getElementById('viewThumbnail');
var outlineButton = document.getElementById('viewOutline');
var attachmentsButton = document.getElementById('viewAttachments');
var notesButton = document.getElementById('viewNotes'); //Sri Krishnan
var annotationsButton = document.getElementById('viewAnnotations'); //Sri Krishnan
switch (view) {
case 'thumbs':
var wasAnotherViewVisible = thumbsView.classList.contains('hidden');
thumbsButton.classList.add('toggled');
outlineButton.classList.remove('toggled');
attachmentsButton.classList.remove('toggled');
notesButton.classList.remove('toggled');//Sri Krishnan
annotationsButton.classList.remove('toggled'); //Sri Krishnan
thumbsView.classList.remove('hidden');
outlineView.classList.add('hidden');
attachmentsView.classList.add('hidden');
notesView.classList.add('hidden'); //Sri Krishnan
annotationsView.classList.add('hidden'); //Sri Krishnan
this.forceRendering();
if (wasAnotherViewVisible) {
this.pdfThumbnailViewer.ensureThumbnailVisible(this.page);
}
break;
case 'outline':
if (outlineButton.disabled) {
return;
}
thumbsButton.classList.remove('toggled');
outlineButton.classList.add('toggled');
attachmentsButton.classList.remove('toggled');
notesButton.classList.remove('toggled');//Sri Krishnan
annotationsButton.classList.remove('toggled'); //Sri Krishnan
thumbsView.classList.add('hidden');
outlineView.classList.remove('hidden');
attachmentsView.classList.add('hidden');
notesView.classList.add('hidden'); //Sri Krishnan
annotationsView.classList.add('hidden'); //Sri Krishnan
break;
case 'attachments':
if (attachmentsButton.disabled) {
return;
}
thumbsButton.classList.remove('toggled');
outlineButton.classList.remove('toggled');
attachmentsButton.classList.add('toggled');
notesButton.classList.remove('toggled');//Sri Krishnan
annotationsButton.classList.remove('toggled'); //Sri Krishnan
thumbsView.classList.add('hidden');
outlineView.classList.add('hidden');
attachmentsView.classList.remove('hidden');
notesView.classList.add('hidden'); //Sri Krishnan
annotationsView.classList.add('hidden'); //Sri Krishnan
break;
//Added by Sri Krishnan for notes button
case 'notes':
thumbsButton.classList.remove('toggled');
outlineButton.classList.remove('toggled');
attachmentsButton.classList.remove('toggled');
notesButton.classList.add('toggled');//Sri Krishnan
annotationsButton.classList.remove('toggled'); //Sri Krishnan
thumbsView.classList.add('hidden');
outlineView.classList.add('hidden');
attachmentsView.classList.add('hidden');
notesView.classList.remove('hidden'); //Sri Krishnan
annotationsView.classList.add('hidden'); //Sri Krishnan
break;
case 'annotations':
thumbsButton.classList.remove('toggled');
outlineButton.classList.remove('toggled');
attachmentsButton.classList.remove('toggled');
notesButton.classList.remove('toggled');//Sri Krishnan
annotationsButton.classList.add('toggled');//Sri Krishnan
thumbsView.classList.add('hidden');
outlineView.classList.add('hidden');
attachmentsView.classList.add('hidden');
notesView.classList.add('hidden'); //Sri Krishnan
annotationsView.classList.remove('hidden'); //Sri Krishnan
break;
}
},
beforePrint: function pdfViewSetupBeforePrint() {
if (!this.supportsPrinting) {
var printMessage = mozL10n.get('printing_not_supported', null,
'Warning: Printing is not fully supported by this browser.');
this.error(printMessage);
return;
}
var alertNotReady = false;
var i, ii;
if (!this.pdfDocument || !this.pagesCount) {
alertNotReady = true;
} else {
for (i = 0, ii = this.pagesCount; i < ii; ++i) {
if (!this.pdfViewer.getPageView(i).pdfPage) {
alertNotReady = true;
break;
}
}
}
if (alertNotReady) {
var notReadyMessage = mozL10n.get('printing_not_ready', null,
'Warning: The PDF is not fully loaded for printing.');
window.alert(notReadyMessage);
return;
}
this.printing = true;
this.forceRendering();
var body = document.querySelector('body');
body.setAttribute('data-mozPrintCallback', true);
if (!this.hasEqualPageSizes) {
console.warn('Not all pages have the same size. The printed result ' +
'may be incorrect!');
}
// Insert a @page + size rule to make sure that the page size is correctly
// set. Note that we assume that all pages have the same size, because
// variable-size pages are not supported yet (at least in Chrome & Firefox).
// TODO(robwu): Use named pages when size calculation bugs get resolved
// (e.g. https://crbug.com/355116) AND when support for named pages is
// added (http://www.w3.org/TR/css3-page/#using-named-pages).
// In browsers where @page + size is not supported (such as Firefox,
// https://bugzil.la/851441), the next stylesheet will be ignored and the
// user has to select the correct paper size in the UI if wanted.
this.pageStyleSheet = document.createElement('style');
var pageSize = this.pdfViewer.getPageView(0).pdfPage.getViewport(1);
this.pageStyleSheet.textContent =
// "size:<width> <height>" is what we need. But also add "A4" because
// Firefox incorrectly reports support for the other value.
'@supports ((size:A4) and (size:1pt 1pt)) {' +
'@page { size: ' + pageSize.width + 'pt ' + pageSize.height + 'pt;}' +
// The canvas and each ancestor node must have a height of 100% to make
// sure that each canvas is printed on exactly one page.
'#printContainer {height:100%}' +
'#printContainer > div {width:100% !important;height:100% !important;}' +
'}';
body.appendChild(this.pageStyleSheet);
for (i = 0, ii = this.pagesCount; i < ii; ++i) {
this.pdfViewer.getPageView(i).beforePrint();
}
},
// Whether all pages of the PDF have the same width and height.
get hasEqualPageSizes() {
var firstPage = this.pdfViewer.getPageView(0);
for (var i = 1, ii = this.pagesCount; i < ii; ++i) {
var pageView = this.pdfViewer.getPageView(i);
if (pageView.width !== firstPage.width ||
pageView.height !== firstPage.height) {
return false;
}
}
return true;
},
afterPrint: function pdfViewSetupAfterPrint() {
var div = document.getElementById('printContainer');
while (div.hasChildNodes()) {
div.removeChild(div.lastChild);
}
if (this.pageStyleSheet && this.pageStyleSheet.parentNode) {
this.pageStyleSheet.parentNode.removeChild(this.pageStyleSheet);
this.pageStyleSheet = null;
}
this.printing = false;
this.forceRendering();
},
rotatePages: function pdfViewRotatePages(delta) {
var pageNumber = this.page;
this.pageRotation = (this.pageRotation + 360 + delta) % 360;
this.pdfViewer.pagesRotation = this.pageRotation;
this.pdfThumbnailViewer.pagesRotation = this.pageRotation;
this.forceRendering();
this.pdfViewer.scrollPageIntoView(pageNumber);
},
requestPresentationMode: function pdfViewRequestPresentationMode() {
if (!this.pdfPresentationMode) {
return;
}
this.pdfPresentationMode.request();
},
/**
* @param {number} delta - The delta value from the mouse event.
*/
scrollPresentationMode: function pdfViewScrollPresentationMode(delta) {
if (!this.pdfPresentationMode) {
return;
}
this.pdfPresentationMode.mouseScroll(delta);
}
};
window.PDFView = PDFViewerApplication; // obsolete name, using it as an alias
function webViewerLoad(evt) {
PDFViewerApplication.initialize().then(webViewerInitialized);
document.getElementById('findNext').click();
}
function webViewerInitialized() {
var queryString = document.location.search.substring(1);
var params = parseQueryString(queryString);
var file = 'file' in params ? params.file : DEFAULT_URL;
var fileInput = document.createElement('input');
fileInput.id = 'fileInput';
fileInput.className = 'fileInput';
fileInput.setAttribute('type', 'file');
fileInput.oncontextmenu = noContextMenuHandler;
document.body.appendChild(fileInput);
if (!window.File || !window.FileReader || !window.FileList || !window.Blob) {
document.getElementById('openFile').setAttribute('hidden', 'true');
document.getElementById('secondaryOpenFile').setAttribute('hidden', 'true');
} else {
document.getElementById('fileInput').value = null;
}
var locale = PDFJS.locale || navigator.language;
if (PDFViewerApplication.preferencePdfBugEnabled) {
// Special debugging flags in the hash section of the URL.
var hash = document.location.hash.substring(1);
var hashParams = parseQueryString(hash);
if ('disableworker' in hashParams) {
PDFJS.disableWorker = (hashParams['disableworker'] === 'true');
}
if ('disablerange' in hashParams) {
PDFJS.disableRange = (hashParams['disablerange'] === 'true');
}
if ('disablestream' in hashParams) {
PDFJS.disableStream = (hashParams['disablestream'] === 'true');
}
if ('disableautofetch' in hashParams) {
PDFJS.disableAutoFetch = (hashParams['disableautofetch'] === 'true');
}
if ('disablefontface' in hashParams) {
PDFJS.disableFontFace = (hashParams['disablefontface'] === 'true');
}
if ('disablehistory' in hashParams) {
PDFJS.disableHistory = (hashParams['disablehistory'] === 'true');
}
if ('webgl' in hashParams) {
PDFJS.disableWebGL = (hashParams['webgl'] !== 'true');
}
if ('useonlycsszoom' in hashParams) {
PDFJS.useOnlyCssZoom = (hashParams['useonlycsszoom'] === 'true');
}
if ('verbosity' in hashParams) {
PDFJS.verbosity = hashParams['verbosity'] | 0;
}
if ('ignorecurrentpositiononzoom' in hashParams) {
IGNORE_CURRENT_POSITION_ON_ZOOM =
(hashParams['ignorecurrentpositiononzoom'] === 'true');
}
if ('locale' in hashParams) {
locale = hashParams['locale'];
}
if ('textlayer' in hashParams) {
switch (hashParams['textlayer']) {
case 'off':
PDFJS.disableTextLayer = true;
break;
case 'visible':
case 'shadow':
case 'hover':
var viewer = document.getElementById('viewer');
viewer.classList.add('textLayer-' + hashParams['textlayer']);
break;
}
}
if ('pdfbug' in hashParams) {
PDFJS.pdfBug = true;
var pdfBug = hashParams['pdfbug'];
var enabled = pdfBug.split(',');
PDFBug.enable(enabled);
PDFBug.init();
}
}
mozL10n.setLanguage(locale);
if (!PDFViewerApplication.supportsPrinting) {
document.getElementById('print').classList.add('hidden');
document.getElementById('secondaryPrint').classList.add('hidden');
}
if (!PDFViewerApplication.supportsFullscreen) {
document.getElementById('presentationMode').classList.add('hidden');
document.getElementById('secondaryPresentationMode').
classList.add('hidden');
}
if (PDFViewerApplication.supportsIntegratedFind) {
document.getElementById('viewFind').classList.add('hidden');
}
// Listen for unsupported features to trigger the fallback UI.
PDFJS.UnsupportedManager.listen(PDFViewerApplication.fallback.bind(PDFViewerApplication));
// Suppress context menus for some controls
document.getElementById('scaleSelect').oncontextmenu = noContextMenuHandler;
var mainContainer = document.getElementById('mainContainer');
var outerContainer = document.getElementById('outerContainer');
mainContainer.addEventListener('transitionend', function (e) {
if (e.target === mainContainer) {
var event = document.createEvent('UIEvents');
event.initUIEvent('resize', false, false, window, 0);
window.dispatchEvent(event);
outerContainer.classList.remove('sidebarMoving');
}
}, true);
document.getElementById('sidebarToggle').addEventListener('click',
function () {
this.classList.toggle('toggled');
outerContainer.classList.add('sidebarMoving');
outerContainer.classList.toggle('sidebarOpen');
PDFViewerApplication.sidebarOpen =
outerContainer.classList.contains('sidebarOpen');
if (PDFViewerApplication.sidebarOpen) {
PDFViewerApplication.refreshThumbnailViewer();
}
PDFViewerApplication.forceRendering();
});
document.getElementById('viewThumbnail').addEventListener('click', function () {
PDFViewerApplication.switchSidebarView('thumbs');
});
document.getElementById('viewOutline').addEventListener('click', function () {
PDFViewerApplication.switchSidebarView('outline');
});
document.getElementById('viewOutline').addEventListener('dblclick', function () {
PDFViewerApplication.outline.toggleOutlineTree();
});
document.getElementById('viewAttachments').addEventListener('click', function () {
PDFViewerApplication.switchSidebarView('attachments');
});
document.getElementById('previous').addEventListener('click', function () {
PDFViewerApplication.page--;
});
document.getElementById('next').addEventListener('click', function () {
PDFViewerApplication.page++;
});
document.getElementById('zoomIn').addEventListener('click', function () {
PDFViewerApplication.zoomIn();
});
document.getElementById('zoomOut').addEventListener('click', function () {
PDFViewerApplication.zoomOut();
});
document.getElementById('pageNumber').addEventListener('click', function () {
this.select();
});
document.getElementById('pageNumber').addEventListener('change', function () {
// Handle the user inputting a floating point number.
PDFViewerApplication.page = (this.value | 0);
if (this.value !== (this.value | 0).toString()) {
this.value = PDFViewerApplication.page;
}
});
document.getElementById('scaleSelect').addEventListener('change', function () {
if (this.value === 'custom') {
return;
}
PDFViewerApplication.pdfViewer.currentScaleValue = this.value;
});
document.getElementById('presentationMode').addEventListener('click', SecondaryToolbar.presentationModeClick.bind(SecondaryToolbar));
document.getElementById('openFile').addEventListener('click', SecondaryToolbar.openFileClick.bind(SecondaryToolbar));
<?php
if (in_array('3', $per_details) || in_array('6', $per_details) || $docset_print_flag) {
?>
document.getElementById('print').addEventListener('click', SecondaryToolbar.printClick.bind(SecondaryToolbar));
<?php
}
?>
<?php
if (in_array('2', $per_details) || in_array('6', $per_details) || $docset_download_flag) {
?>
document.getElementById('download').addEventListener('click', SecondaryToolbar.downloadClick.bind(SecondaryToolbar));
<?php }
?>
// Added by Sri Krishnan
document.getElementById('viewNotes').addEventListener('click', function () {
PDFViewerApplication.switchSidebarView('notes');
});
document.getElementById('viewAnnotations').addEventListener('click', function () {
PDFViewerApplication.switchSidebarView('annotations');
});
document.getElementById('savenote').addEventListener('click', function (e) {
e.preventDefault();
PDFViewerApplication.saveAndLoadDocumentNotes();
});
document.getElementById('saveAnnotations').addEventListener('click', function () {
PDFViewerApplication.saveAndLoadDocumentAnnotations();
PDFViewerApplication.rotatePages(0);
});
document.getElementById('deleteAnnotation').addEventListener('click', function () {
PDFViewerApplication.deleteDocumentAnnotation();
});
document.getElementById('highlight').addEventListener('click', function () {
PDFViewerApplication.createDocumentAnnotation(ANNOTATION_HIGHLIGHT);
});
<?php if($redact_stamp_sign_rights_details[0]['redact']){ ?>
document.getElementById('blackout').addEventListener('click', function () {
PDFViewerApplication.createDocumentAnnotation(ANNOTATION_BLACKOUT);
});
<?php }?>
document.getElementById('ellipse').addEventListener('click', function () {
PDFViewerApplication.createDocumentAnnotation(ANNOTATION_ELLIPSE);
});
document.getElementById('stickynote').addEventListener('click', function () {
PDFViewerApplication.createDocumentAnnotation(ANNOTATION_STICKYNOTE);
});
<?php if($redact_stamp_sign_rights_details[0]['stamp']){ ?>
document.getElementById('rubberstamp').addEventListener('click', function () {
if (PDFViewerApplication.pdfViewer._pagesRotation == 0) {
PDFViewerApplication.rubberStampAnnotation.open();
}
});
<?php }?>
<?php if($redact_stamp_sign_rights_details[0]['digital_sign'] && $digital_signature_module[0]['status'] == 1){ ?>
document.getElementById('digitalsign').addEventListener('click', function () {
if (PDFViewerApplication.pdfViewer._pagesRotation == 0) {
PDFViewerApplication.digitalsignAnnotation.open();
}
});
<?php }?>
if (file && file.lastIndexOf('file:', 0) === 0) {
// file:-scheme. Load the contents in the main thread because QtWebKit
// cannot load file:-URLs in a Web Worker. file:-URLs are usually loaded
// very quickly, so there is no need to set up progress event listeners.
PDFViewerApplication.setTitleUsingUrl(file);
var xhr = new XMLHttpRequest();
xhr.onload = function () {
PDFViewerApplication.open(new Uint8Array(xhr.response), 0);
};
try {
xhr.open('GET', file);
xhr.responseType = 'arraybuffer';
xhr.send();
} catch (e) {
PDFViewerApplication.error(mozL10n.get('loading_error', null,
'An error occurred while loading the PDF.'), e);
}
return;
}
if (file) {
PDFViewerApplication.open(file, 0);
}
}
document.addEventListener('DOMContentLoaded', webViewerLoad, true);
document.addEventListener('pagerendered', function (e) {
var pageNumber = e.detail.pageNumber;
var pageIndex = pageNumber - 1;
var pageView = PDFViewerApplication.pdfViewer.getPageView(pageIndex);
//Added by Sri Krishnan for drawing custom annotations
drawAnnotationWrapper(pageView, pageNumber);
//Added till here Sri Krishnan for drawing custom annotations
if (PDFViewerApplication.sidebarOpen) {
var thumbnailView = PDFViewerApplication.pdfThumbnailViewer.getThumbnail(pageIndex);
thumbnailView.setImage(pageView);
}
if (PDFJS.pdfBug && Stats.enabled && pageView.stats) {
Stats.add(pageNumber, pageView.stats);
}
if (pageView.error) {
PDFViewerApplication.error(mozL10n.get('rendering_error', null, 'An error occurred while rendering the page.'), pageView.error);
}
// If the page is still visible when it has finished rendering,
// ensure that the page number input loading indicator is hidden.
if (pageNumber === PDFViewerApplication.page) {
var pageNumberInput = document.getElementById('pageNumber');
pageNumberInput.classList.remove(PAGE_NUMBER_LOADING_INDICATOR);
}
}, true);
document.addEventListener('textlayerrendered', function (e) {
var pageIndex = e.detail.pageNumber - 1;
var pageView = PDFViewerApplication.pdfViewer.getPageView(pageIndex);
}, true);
document.addEventListener('pagemode', function (evt) {
if (!PDFViewerApplication.initialized) {
return;
}
// Handle the 'pagemode' hash parameter, see also `PDFLinkService_setHash`.
var mode = evt.detail.mode;
switch (mode) {
case 'bookmarks':
// Note: Our code calls this property 'outline', even though the
// Open Parameter specification calls it 'bookmarks'.
mode = 'outline';
/* falls through */
case 'thumbs':
case 'attachments':
PDFViewerApplication.switchSidebarView(mode, true);
break;
case 'none':
if (PDFViewerApplication.sidebarOpen) {
document.getElementById('sidebarToggle').click();
}
break;
}
}, true);
document.addEventListener('namedaction', function (e) {
if (!PDFViewerApplication.initialized) {
return;
}
// Processing couple of named actions that might be useful.
// See also PDFLinkService.executeNamedAction
var action = e.detail.action;
switch (action) {
case 'GoToPage':
document.getElementById('pageNumber').focus();
break;
case 'Find':
if (!PDFViewerApplication.supportsIntegratedFind) {
PDFViewerApplication.findBar.toggle();
}
break;
}
}, true);
window.addEventListener('presentationmodechanged', function (e) {
var active = e.detail.active;
var switchInProgress = e.detail.switchInProgress;
PDFViewerApplication.pdfViewer.presentationModeState =
switchInProgress ? PresentationModeState.CHANGING :
active ? PresentationModeState.FULLSCREEN : PresentationModeState.NORMAL;
});
window.addEventListener('updateviewarea', function (evt) {
if (!PDFViewerApplication.initialized) {
return;
}
var location = evt.location;
PDFViewerApplication.store.initializedPromise.then(function () {
PDFViewerApplication.store.setMultiple({
'exists': true,
'page': location.pageNumber,
'zoom': location.scale,
'scrollLeft': location.left,
'scrollTop': location.top
}).catch(function () {
// unable to write to storage
});
});
var href =
PDFViewerApplication.pdfLinkService.getAnchorUrl(location.pdfOpenParams);
document.getElementById('viewBookmark').href = href;
document.getElementById('secondaryViewBookmark').href = href;
// Update the current bookmark in the browsing history.
PDFViewerApplication.pdfHistory.updateCurrentBookmark(location.pdfOpenParams,
location.pageNumber);
// Show/hide the loading indicator in the page number input element.
var pageNumberInput = document.getElementById('pageNumber');
var currentPage =
PDFViewerApplication.pdfViewer.getPageView(PDFViewerApplication.page - 1);
if (currentPage.renderingState === RenderingStates.FINISHED) {
pageNumberInput.classList.remove(PAGE_NUMBER_LOADING_INDICATOR);
} else {
pageNumberInput.classList.add(PAGE_NUMBER_LOADING_INDICATOR);
}
}, true);
window.addEventListener('resize', function webViewerResize(evt) {
if (PDFViewerApplication.initialized) {
var currentScaleValue = PDFViewerApplication.pdfViewer.currentScaleValue;
if (currentScaleValue === 'auto' ||
currentScaleValue === 'page-fit' ||
currentScaleValue === 'page-width') {
// Note: the scale is constant for 'page-actual'.
PDFViewerApplication.pdfViewer.currentScaleValue = currentScaleValue;
} else if (!currentScaleValue) {
// Normally this shouldn't happen, but if the scale wasn't initialized
// we set it to the default value in order to prevent any issues.
// (E.g. the document being rendered with the wrong scale on load.)
PDFViewerApplication.pdfViewer.currentScaleValue = DEFAULT_SCALE_VALUE;
}
PDFViewerApplication.pdfViewer.update();
}
// Set the 'max-height' CSS property of the secondary toolbar.
SecondaryToolbar.setMaxHeight(document.getElementById('viewerContainer'));
});
window.addEventListener('hashchange', function webViewerHashchange(evt) {
if (PDFViewerApplication.pdfHistory.isHashChangeUnlocked) {
var hash = document.location.hash.substring(1);
if (!hash) {
return;
}
if (!PDFViewerApplication.isInitialViewSet) {
PDFViewerApplication.initialBookmark = hash;
} else {
PDFViewerApplication.pdfLinkService.setHash(hash);
}
}
});
window.addEventListener('change', function webViewerChange(evt) {
var files = evt.target.files;
if (!files || files.length === 0) {
return;
}
var file = files[0];
if (!PDFJS.disableCreateObjectURL &&
typeof URL !== 'undefined' && URL.createObjectURL) {
PDFViewerApplication.open(URL.createObjectURL(file), 0);
} else {
// Read the local file into a Uint8Array.
var fileReader = new FileReader();
fileReader.onload = function webViewerChangeFileReaderOnload(evt) {
var buffer = evt.target.result;
var uint8Array = new Uint8Array(buffer);
PDFViewerApplication.open(uint8Array, 0);
};
fileReader.readAsArrayBuffer(file);
}
PDFViewerApplication.setTitleUsingUrl(file.name);
// URL does not reflect proper document location - hiding some icons.
document.getElementById('viewBookmark').setAttribute('hidden', 'true');
document.getElementById('secondaryViewBookmark').
setAttribute('hidden', 'true');
document.getElementById('download').setAttribute('hidden', 'true');
document.getElementById('secondaryDownload').setAttribute('hidden', 'true');
}, true);
function selectScaleOption(value) {
var options = document.getElementById('scaleSelect').options;
var predefinedValueFound = false;
for (var i = 0, ii = options.length; i < ii; i++) {
var option = options[i];
if (option.value !== value) {
option.selected = false;
continue;
}
option.selected = true;
predefinedValueFound = true;
}
return predefinedValueFound;
}
window.addEventListener('localized', function localized(evt) {
document.getElementsByTagName('html')[0].dir = mozL10n.getDirection();
PDFViewerApplication.animationStartedPromise.then(function () {
// Adjust the width of the zoom box to fit the content.
// Note: If the window is narrow enough that the zoom box is not visible,
// we temporarily show it to be able to adjust its width.
var container = document.getElementById('scaleSelectContainer');
if (container.clientWidth === 0) {
container.setAttribute('style', 'display: inherit;');
}
if (container.clientWidth > 0) {
var select = document.getElementById('scaleSelect');
select.setAttribute('style', 'min-width: inherit;');
var width = select.clientWidth + SCALE_SELECT_CONTAINER_PADDING;
select.setAttribute('style', 'min-width: ' +
(width + SCALE_SELECT_PADDING) + 'px;');
container.setAttribute('style', 'min-width: ' + width + 'px; ' +
'max-width: ' + width + 'px;');
}
// Set the 'max-height' CSS property of the secondary toolbar.
SecondaryToolbar.setMaxHeight(document.getElementById('viewerContainer'));
});
}, true);
window.addEventListener('scalechange', function scalechange(evt) {
document.getElementById('zoomOut').disabled = (evt.scale === MIN_SCALE);
document.getElementById('zoomIn').disabled = (evt.scale === MAX_SCALE);
// Update the 'scaleSelect' DOM element.
var predefinedValueFound = selectScaleOption(evt.presetValue ||
'' + evt.scale);
if (!predefinedValueFound) {
var customScaleOption = document.getElementById('customScaleOption');
var customScale = Math.round(evt.scale * 10000) / 100;
customScaleOption.textContent =
mozL10n.get('page_scale_percent', {scale: customScale}, '{{scale}}%');
customScaleOption.selected = true;
}
if (!PDFViewerApplication.initialized) {
return;
}
PDFViewerApplication.pdfViewer.update();
}, true);
window.addEventListener('pagechange', function pagechange(evt) {
var page = evt.pageNumber;
if (evt.previousPageNumber !== page) {
document.getElementById('pageNumber').value = page;
if (PDFViewerApplication.sidebarOpen) {
PDFViewerApplication.pdfThumbnailViewer.scrollThumbnailIntoView(page);
}
}
var numPages = PDFViewerApplication.pagesCount;
document.getElementById('previous').disabled = (page <= 1);
document.getElementById('next').disabled = (page >= numPages);
document.getElementById('firstPage').disabled = (page <= 1);
document.getElementById('lastPage').disabled = (page >= numPages);
// we need to update stats
if (PDFJS.pdfBug && Stats.enabled) {
var pageView = PDFViewerApplication.pdfViewer.getPageView(page - 1);
if (pageView.stats) {
Stats.add(page, pageView.stats);
}
}
}, true);
function handleMouseWheel(evt) {
var MOUSE_WHEEL_DELTA_FACTOR = 40;
var ticks = (evt.type === 'DOMMouseScroll') ? -evt.detail :
evt.wheelDelta / MOUSE_WHEEL_DELTA_FACTOR;
var direction = (ticks < 0) ? 'zoomOut' : 'zoomIn';
var pdfViewer = PDFViewerApplication.pdfViewer;
if (pdfViewer.isInPresentationMode) {
evt.preventDefault();
PDFViewerApplication.scrollPresentationMode(ticks *
MOUSE_WHEEL_DELTA_FACTOR);
} else if (evt.ctrlKey || evt.metaKey) {
// Only zoom the pages, not the entire viewer.
evt.preventDefault();
var previousScale = pdfViewer.currentScale;
PDFViewerApplication[direction](Math.abs(ticks));
var currentScale = pdfViewer.currentScale;
if (previousScale !== currentScale) {
// After scaling the page via zoomIn/zoomOut, the position of the upper-
// left corner is restored. When the mouse wheel is used, the position
// under the cursor should be restored instead.
var scaleCorrectionFactor = currentScale / previousScale - 1;
var rect = pdfViewer.container.getBoundingClientRect();
var dx = evt.clientX - rect.left;
var dy = evt.clientY - rect.top;
pdfViewer.container.scrollLeft += dx * scaleCorrectionFactor;
pdfViewer.container.scrollTop += dy * scaleCorrectionFactor;
}
}
}
window.addEventListener('DOMMouseScroll', handleMouseWheel);
window.addEventListener('mousewheel', handleMouseWheel);
window.addEventListener('click', function click(evt) {
if (SecondaryToolbar.opened &&
PDFViewerApplication.pdfViewer.containsElement(evt.target)) {
SecondaryToolbar.close();
}
}, false);
window.addEventListener('keydown', function keydown(evt) {
if (OverlayManager.active) {
return;
}
var handled = false;
var cmd = (evt.ctrlKey ? 1 : 0) |
(evt.altKey ? 2 : 0) |
(evt.shiftKey ? 4 : 0) |
(evt.metaKey ? 8 : 0);
var pdfViewer = PDFViewerApplication.pdfViewer;
var isViewerInPresentationMode = pdfViewer && pdfViewer.isInPresentationMode;
// First, handle the key bindings that are independent whether an input
// control is selected or not.
if (cmd === 1 || cmd === 8 || cmd === 5 || cmd === 12) {
// either CTRL or META key with optional SHIFT.
switch (evt.keyCode) {
case 70: // f
if (!PDFViewerApplication.supportsIntegratedFind) {
PDFViewerApplication.findBar.open();
handled = true;
}
break;
case 71: // g
if (!PDFViewerApplication.supportsIntegratedFind) {
PDFViewerApplication.findBar.dispatchEvent('again',
cmd === 5 || cmd === 12);
handled = true;
}
break;
case 61: // FF/Mac '='
case 107: // FF '+' and '='
case 187: // Chrome '+'
case 171: // FF with German keyboard
if (!isViewerInPresentationMode) {
PDFViewerApplication.zoomIn();
}
handled = true;
break;
case 173: // FF/Mac '-'
case 109: // FF '-'
case 189: // Chrome '-'
if (!isViewerInPresentationMode) {
PDFViewerApplication.zoomOut();
}
handled = true;
break;
case 48: // '0'
case 96: // '0' on Numpad of Swedish keyboard
if (!isViewerInPresentationMode) {
// keeping it unhandled (to restore page zoom to 100%)
setTimeout(function () {
// ... and resetting the scale after browser adjusts its scale
pdfViewer.currentScaleValue = DEFAULT_SCALE_VALUE;
});
handled = false;
}
break;
}
}
// CTRL or META without shift
if (cmd === 1 || cmd === 8) {
switch (evt.keyCode) {
case 83: // s
//PDFViewerApplication.download();
handled = true;
break;
}
}
// CTRL+ALT or Option+Command
if (cmd === 3 || cmd === 10) {
switch (evt.keyCode) {
case 80: // p
PDFViewerApplication.requestPresentationMode();
handled = true;
break;
case 71: // g
// focuses input#pageNumber field
document.getElementById('pageNumber').select();
handled = true;
break;
}
}
if (handled) {
evt.preventDefault();
return;
}
// Some shortcuts should not get handled if a control/input element
// is selected.
var curElement = document.activeElement || document.querySelector(':focus');
var curElementTagName = curElement && curElement.tagName.toUpperCase();
if (curElementTagName === 'INPUT' ||
curElementTagName === 'TEXTAREA' ||
curElementTagName === 'SELECT') {
// Make sure that the secondary toolbar is closed when Escape is pressed.
if (evt.keyCode !== 27) { // 'Esc'
return;
}
}
var ensureViewerFocused = false;
if (cmd === 0) { // no control key pressed at all.
switch (evt.keyCode) {
case 38: // up arrow
case 33: // pg up
case 8: // backspace
if (!isViewerInPresentationMode &&
pdfViewer.currentScaleValue !== 'page-fit') {
break;
}
/* in presentation mode */
/* falls through */
case 37: // left arrow
// horizontal scrolling using arrow keys
if (pdfViewer.isHorizontalScrollbarEnabled) {
break;
}
/* falls through */
case 75: // 'k'
case 80: // 'p'
PDFViewerApplication.page--;
handled = true;
break;
case 27: // esc key
if (SecondaryToolbar.opened) {
SecondaryToolbar.close();
handled = true;
}
if (!PDFViewerApplication.supportsIntegratedFind &&
PDFViewerApplication.findBar.opened) {
PDFViewerApplication.findBar.close();
handled = true;
}
break;
case 40: // down arrow
case 34: // pg down
case 32: // spacebar
if (!isViewerInPresentationMode &&
pdfViewer.currentScaleValue !== 'page-fit') {
break;
}
/* falls through */
case 39: // right arrow
// horizontal scrolling using arrow keys
if (pdfViewer.isHorizontalScrollbarEnabled) {
break;
}
/* falls through */
case 74: // 'j'
case 78: // 'n'
PDFViewerApplication.page++;
handled = true;
break;
case 36: // home
if (isViewerInPresentationMode || PDFViewerApplication.page > 1) {
PDFViewerApplication.page = 1;
handled = true;
ensureViewerFocused = true;
}
break;
case 35: // end
if (isViewerInPresentationMode || (PDFViewerApplication.pdfDocument &&
PDFViewerApplication.page < PDFViewerApplication.pagesCount)) {
PDFViewerApplication.page = PDFViewerApplication.pagesCount;
handled = true;
ensureViewerFocused = true;
}
break;
case 72: // 'h'
if (!isViewerInPresentationMode) {
HandTool.toggle();
}
break;
case 82: // 'r'
PDFViewerApplication.rotatePages(90);
break;
case 46 :
PDFViewerApplication.deleteDocumentAnnotation();
break;
}
}
if (cmd === 4) { // shift-key
switch (evt.keyCode) {
case 32: // spacebar
if (!isViewerInPresentationMode &&
pdfViewer.currentScaleValue !== 'page-fit') {
break;
}
PDFViewerApplication.page--;
handled = true;
break;
case 82: // 'r'
PDFViewerApplication.rotatePages(-90);
break;
}
}
if (!handled && !isViewerInPresentationMode) {
// 33=Page Up 34=Page Down 35=End 36=Home
// 37=Left 38=Up 39=Right 40=Down
// 32=Spacebar
if ((evt.keyCode >= 33 && evt.keyCode <= 40) ||
(evt.keyCode === 32 && curElementTagName !== 'BUTTON')) {
ensureViewerFocused = true;
}
}
if (cmd === 2) { // alt-key
switch (evt.keyCode) {
case 37: // left arrow
if (isViewerInPresentationMode) {
PDFViewerApplication.pdfHistory.back();
handled = true;
}
break;
case 39: // right arrow
if (isViewerInPresentationMode) {
PDFViewerApplication.pdfHistory.forward();
handled = true;
}
break;
}
}
if (ensureViewerFocused && !pdfViewer.containsElement(curElement)) {
// The page container is not focused, but a page navigation key has been
// pressed. Change the focus to the viewer container to make sure that
// navigation by keyboard works as expected.
pdfViewer.focus();
}
if (handled) {
evt.preventDefault();
}
});
window.addEventListener('beforeprint', function beforePrint(evt) {
PDFViewerApplication.beforePrint();
$.ajax({
async: false,
type: "POST",
url: "dms/printLog.php?documentid=<?php echo $record_details[0]['id']; ?>&pid=<?php echo $pid; ?>&cat_id=<?php echo $record_details[0]['category_id']; ?>&docname=<?php echo $record_details[0]['title']; ?>",
success: function (response) {
PDFViewerApplication.loadDocumentNotes();
// console.log(response);
//alert(response);
},
error: function (jqXHR, exception) {
console.log("No print");
//$("#resultNotes").html("Unable to load notes");
}
});
});
window.addEventListener('afterprint', function afterPrint(evt) {
PDFViewerApplication.afterPrint();
});
(function animationStartedClosure() {
// The offsetParent is not set until the pdf.js iframe or object is visible.
// Waiting for first animation.
PDFViewerApplication.animationStartedPromise = new Promise(
function (resolve) {
window.requestAnimationFrame(resolve);
});
})();
$(document).on("click", '.deletenote', function (event) {
var noteId = $(this).attr('noteid');
PDFViewerApplication.deleteConfirmationPrompt.open(noteId);
});
$(document).on("click", '.annselector', function (event) {
//unselect all annotations first
for (var i = 0; i < PDFViewerApplication.documentAnnotations.length; i++) {
var ann = PDFViewerApplication.documentAnnotations[i];
ann.selected = false;
}
var tempAnnotationId = $(this).attr('tempannotationid');
for (var i = 0; i < PDFViewerApplication.documentAnnotations.length; i++) {
var ann = PDFViewerApplication.documentAnnotations[i];
if (tempAnnotationId == ann.tempId) {
ann.selected = true;
PDFViewerApplication.pdfViewer.scrollPageIntoView(ann.pageId);
break;
}
}
for (var pageNumber = 0; pageNumber < PDFViewerApplication.pdfViewer.pagesCount; pageNumber++) {
var pageView = PDFViewerApplication.pdfViewer.getPageView(pageNumber);
PDFViewerApplication.drawDocumentAnnotations(pageView, pageView.context, pageNumber + 1);
}
});
function getCurrentDate() {
var m_names = new Array("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
var d = new Date();
var curr_date = d.getDate();
var curr_month = d.getMonth();
var curr_year = d.getFullYear();
var curr_hour = d.getHours();
var curr_minutes = d.getMinutes();
var currentDate = curr_date + "-" + m_names[curr_month] + "-" + curr_year + " " + curr_hour + ":" + curr_minutes;
return currentDate;
}
function getCurrentDateOnly() {
var m_names = new Array("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
var d = new Date();
var curr_date = d.getDate();
var curr_month = d.getMonth();
var curr_year = d.getFullYear();
var curr_hour = d.getHours();
var curr_minutes = d.getMinutes();
var currentDate = curr_date + "-" + m_names[curr_month] + "-" + curr_year;
return currentDate;
}
function getCurrentTime() {
var m_names = new Array("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
var d = new Date();
var curr_date = d.getDate();
var curr_month = d.getMonth();
var curr_year = d.getFullYear();
var curr_hour = d.getHours();
var curr_minutes = d.getMinutes();
var currentTime = curr_hour + ":" + curr_minutes;
return currentTime;
}
function log(ann) {
console.log("X1 : " + ann.x1 + " Y1 : " + ann.y1 + " X2 : " + ann.x2 + " Y2 : " + ann.y2);
}
$(document).ready(function () {
//Disable cut copy paste
/*$('body').bind('cut copy paste', function (e) {
e.preventDefault();
});*/
//Disable mouse right click
$("body").on("contextmenu", function (e) {
return false;
});
});
$(document).ready(function () {
$("body").css("-webkit-user-select", "none");
$("body").css("-moz-user-select", "none");
$("body").css("-ms-user-select", "none");
$("body").css("-o-user-select", "none");
$("body").css("user-select", "none");
document.addEventListener('DOMContentLoaded', function() {
document.getElementById('findNextButton').click();
}, false);
});
</script>
</head>
<body tabindex="1" class="loadingInProgress">
<div id="outerContainer" >
<div id="sidebarContainer">
<div id="toolbarSidebar">
<div class="splitToolbarButton toggled">
<button id="viewThumbnail" class="toolbarButton group toggled"
title="Show Thumbnails" tabindex="2" data-l10n-id="thumbs">
<span data-l10n-id="thumbs_label">Thumbnails</span>
</button>
<button id="viewNotes" class="toolbarButton group"
title="Show Document Notes" tabindex="3" >
<span>Document Notes</span>
</button>
<button id="viewAnnotations" class="toolbarButton group"
title="Document Annotations" tabindex="4" >
<span>Document Annotations</span>
</button>
<button id="viewOutline" class="toolbarButton group"
title="Show Document Outline" tabindex="5" data-l10n-id="outline">
<span data-l10n-id="outline_label">Document Outline</span>
</button>
<button id="viewAttachments" class="toolbarButton group"
title="Show Attachments" tabindex="6" data-l10n-id="attachments">
<span data-l10n-id="attachments_label">Attachments</span>
</button>
</div>
</div>
<div id="sidebarContent">
<div id="thumbnailView"></div>
<div id="notesView" class="hidden">
<div id="notesForm">
<form action="dms/documentnotes.php" id="frmNotes" method="post">
<input type="radio" name="radNoteType" value="P" checked/><span class="toolbarLabel" >Public </span>
<input type="radio" name="radNoteType" value="U"/><span class="toolbarLabel">Private</span>
<textarea rows="5" name="txtNote" id="txtNote" class="toolbarField" placeholder="Enter note / comment"></textarea><br/>
<input type="hidden" name="documentid" id="documentid" value="<?php echo $id; ?>"/>
<input type="hidden" name="revisionid" id="revisionid" value=""/>
<input type="hidden" name="user_id" id="user_id" value="<?php echo $_SESSION[SESSION_VAR_NAME]['user_id']; ?>"/>
<input type="hidden" name="username" id="username" value="<?php echo $_SESSION[SESSION_VAR_NAME]['fname'] . ' ' . $_SESSION[SESSION_VAR_NAME]['mname'] . ' ' . $_SESSION[SESSION_VAR_NAME]['lname']; ?>"/>
<input type="submit" class="overlayButton" id="savenote" value="Save Note">
</form>
</div>
<div id="resultNotes"></div>
</div>
<div id="annotationsView" class="hidden"></div>
<div id="outlineView" class="hidden"></div>
<div id="attachmentsView" class="hidden"></div>
</div>
</div>
<!-- sidebarContainer -->
<div id="mainContainer">
<div class="findbar hidden doorHanger hiddenSmallView" id="findbar">
<label for="findInput" class="toolbarLabel" data-l10n-id="find_label">Find:</label>
<input id="findInput" class="toolbarField" tabindex="91" value="ffff">
<div class="splitToolbarButton">
<button class="toolbarButton findPrevious" title=""
id="findPrevious" tabindex="92" data-l10n-id="find_previous">
<span data-l10n-id="find_previous_label">Previous</span>
</button>
<div class="splitToolbarButtonSeparator"></div>
<button class="toolbarButton findNext" title="" id="findNext"
tabindex="93" data-l10n-id="find_next">
<span data-l10n-id="find_next_label">Next</span>
</button>
</div>
<input type="checkbox" id="findHighlightAll" class="toolbarField" checked
tabindex="94"> <label for="findHighlightAll"
class="toolbarLabel" data-l10n-id="find_highlight">Highlight
all</label> <input type="checkbox" id="findMatchCase" class="toolbarField"
tabindex="95"> <label for="findMatchCase"
class="toolbarLabel" data-l10n-id="find_match_case_label">Match
case</label> <span id="findMsg" class="toolbarLabel"></span>
</div>
<!-- findbar -->
<div id="secondaryToolbar"
class="secondaryToolbar hidden doorHangerRight">
<div id="secondaryToolbarButtonContainer">
<button id="secondaryPresentationMode"
class="secondaryToolbarButton presentationMode visibleLargeView"
title="Switch to Presentation Mode" tabindex="51"
data-l10n-id="presentation_mode">
<span data-l10n-id="presentation_mode_label">Presentation
Mode</span>
</button>
<button id="secondaryOpenFile"
class="secondaryToolbarButton openFile visibleLargeView "
title="Open File" tabindex="52" data-l10n-id="open_file">
<span data-l10n-id="open_file_label">Open</span>
</button>
<?php
if (in_array('3', $per_details) || in_array('6', $per_details) || $docset_print_flag) {
?>
<button id="secondaryPrint"
class="secondaryToolbarButton print visibleMediumView "
title="Print" tabindex="53" data-l10n-id="print">
<span data-l10n-id="print_label">Print</span>
</button>
<?php
}
?>
<?php
if (in_array('2', $per_details) || in_array('6', $per_details) || $docset_download_flag) {
?>
<button id="secondaryDownload"
class="secondaryToolbarButton download visibleMediumView download_my"
title="Download" tabindex="54" data-l10n-id="download">
<span data-l10n-id="download_label">Download</span>
</button>
<?php
}
?>
<a href="#" id="secondaryViewBookmark"
class="secondaryToolbarButton bookmark visibleSmallView "
title="Current view (copy or open in new window)" tabindex="55"
data-l10n-id="bookmark"> <span data-l10n-id="bookmark_label">Current
View</span>
</a>
<div class="horizontalToolbarSeparator visibleLargeView"></div>
<button id="firstPage" class="secondaryToolbarButton firstPage"
title="Go to First Page" tabindex="56" data-l10n-id="first_page">
<span data-l10n-id="first_page_label">Go to First Page</span>
</button>
<button id="lastPage" class="secondaryToolbarButton lastPage"
title="Go to Last Page" tabindex="57" data-l10n-id="last_page">
<span data-l10n-id="last_page_label">Go to Last Page</span>
</button>
<div class="horizontalToolbarSeparator"></div>
<button id="pageRotateCw" class="secondaryToolbarButton rotateCw"
title="Rotate Clockwise" tabindex="58"
data-l10n-id="page_rotate_cw">
<span data-l10n-id="page_rotate_cw_label">Rotate Clockwise</span>
</button>
<button id="pageRotateCcw" class="secondaryToolbarButton rotateCcw"
title="Rotate Counterclockwise" tabindex="59"
data-l10n-id="page_rotate_ccw">
<span data-l10n-id="page_rotate_ccw_label">Rotate
Counterclockwise</span>
</button>
<div class="horizontalToolbarSeparator"></div>
<button id="toggleHandTool" class="secondaryToolbarButton handTool"
title="Enable hand tool" tabindex="60"
data-l10n-id="hand_tool_enable">
<span data-l10n-id="hand_tool_enable_label">Enable hand
tool</span>
</button>
<div class="horizontalToolbarSeparator"></div>
<button id="documentProperties"
class="secondaryToolbarButton documentProperties"
title="Document Properties" tabindex="61"
data-l10n-id="document_properties">
<span data-l10n-id="document_properties_label">Document
Properties</span>
</button>
<?php if (file_exists($crt_file)) {?>
<button id="documentDSProperties"
class="secondaryToolbarButton fa fa-wpforms"
title="Digital Signed Properties" tabindex="62"
>
<span>
Digital Signed Properties</span>
</button>
<?php } ?>
</div>
</div>
<!-- secondaryToolbar -->
<div class="toolbar">
<div id="toolbarContainer">
<div id="toolbarViewer">
<div id="toolbarViewerLeft">
<button id="sidebarToggle" class="toolbarButton"
title="Toggle Sidebar" tabindex="11"
data-l10n-id="toggle_sidebar">
<span data-l10n-id="toggle_sidebar_label">Toggle Sidebar</span>
</button>
<div class="toolbarButtonSpacer"></div>
<button id="viewFind" class="toolbarButton group hiddenSmallView"
title="Find in Document" tabindex="12" data-l10n-id="findbar">
<span data-l10n-id="findbar_label">Find</span>
</button>
<div class="splitToolbarButton">
<button class="toolbarButton pageUp" title="Previous Page"
id="previous" tabindex="13" data-l10n-id="previous">
<span data-l10n-id="previous_label">Previous</span>
</button>
<div class="splitToolbarButtonSeparator"></div>
<button class="toolbarButton pageDown" title="Next Page"
id="next" tabindex="14" data-l10n-id="next">
<span data-l10n-id="next_label">Next</span>
</button>
</div>
<label id="pageNumberLabel" class="toolbarLabel" for="pageNumber"
data-l10n-id="page_label">Page: </label> <input type="number"
id="pageNumber" class="toolbarField pageNumber" value="1"
size="4" min="1" tabindex="15"> <span id="numPages"
class="toolbarLabel"></span>
</div>
<div id="toolbarViewerRight" >
<button id="presentationMode"
class="toolbarButton presentationMode hiddenLargeView"
title="Switch to Presentation Mode" tabindex="31"
data-l10n-id="presentation_mode">
<span data-l10n-id="presentation_mode_label">Presentation
Mode</span>
</button>
<button id="openFile"
class="toolbarButton openFile hiddenLargeView hidden" title="Open File"
tabindex="32" data-l10n-id="open_file">
<span data-l10n-id="open_file_label">Open</span>
</button>
<?php
if (in_array('3', $per_details) || in_array('6', $per_details) || $docset_print_flag) {
?>
<button id="print" class="toolbarButton print hiddenMediumView "
title="Print" tabindex="33" data-l10n-id="print">
<span data-l10n-id="print_label">Print</span>
</button>
<?php
}
?>
<?php
if (in_array('2', $per_details) || in_array('6', $per_details) || $docset_download_flag) {
?>
<button id="download"
class="toolbarButton download hiddenMediumView download_my" title="Download"
tabindex="34" data-l10n-id="download">
<span data-l10n-id="download_label">Download</span>
</button>
<?php
}
?>
<a href="#" id="viewBookmark"
class="toolbarButton bookmark hiddenSmallView "
title="Current view (copy or open in new window)" tabindex="35"
data-l10n-id="bookmark"> <span data-l10n-id="bookmark_label">Current
View</span>
</a>
<div class="verticalToolbarSeparator hiddenSmallView"></div>
<button id="secondaryToolbarToggle" class="toolbarButton"
title="Tools" tabindex="36" data-l10n-id="tools">
<span data-l10n-id="tools_label">Tools</span>
</button>
</div>
<div class="outerCenter">
<div class="innerCenter" id="toolbarViewerMiddle">
<div class="splitToolbarButton">
<button id="zoomOut" class="toolbarButton zoomOut"
title="Zoom Out" tabindex="21" data-l10n-id="zoom_out">
<span data-l10n-id="zoom_out_label">Zoom Out</span>
</button>
<div class="splitToolbarButtonSeparator"></div>
<button id="zoomIn" class="toolbarButton zoomIn"
title="Zoom In" tabindex="22" data-l10n-id="zoom_in">
<span data-l10n-id="zoom_in_label">Zoom In</span>
</button>
</div>
<span id="scaleSelectContainer" class="dropdownToolbarButton">
<select id="scaleSelect" title="Zoom" tabindex="23"
data-l10n-id="zoom">
<option id="pageAutoOption" title="" value="auto"
selected="selected" data-l10n-id="page_scale_auto">Automatic
Zoom</option>
<option id="pageActualOption" title="" value="page-actual"
data-l10n-id="page_scale_actual">Actual Size</option>
<option id="pageFitOption" title="" value="page-fit"
data-l10n-id="page_scale_fit">Fit Page</option>
<option id="pageWidthOption" title="" value="page-width"
data-l10n-id="page_scale_width">Full Width</option>
<option id="customScaleOption" title="" value="custom"></option>
<option title="" value="0.5" data-l10n-id="page_scale_percent"
data-l10n-args='{ "scale": 50 }'>50%</option>
<option title="" value="0.75"
data-l10n-id="page_scale_percent"
data-l10n-args='{ "scale": 75 }'>75%</option>
<option title="" value="1" data-l10n-id="page_scale_percent"
data-l10n-args='{ "scale": 100 }'>100%</option>
<option title="" value="1.25"
data-l10n-id="page_scale_percent"
data-l10n-args='{ "scale": 125 }'>125%</option>
<option title="" value="1.5" data-l10n-id="page_scale_percent"
data-l10n-args='{ "scale": 150 }'>150%</option>
<option title="" value="2" data-l10n-id="page_scale_percent"
data-l10n-args='{ "scale": 200 }'>200%</option>
<option title="" value="3" data-l10n-id="page_scale_percent"
data-l10n-args='{ "scale": 300 }'>300%</option>
<option title="" value="4" data-l10n-id="page_scale_percent"
data-l10n-args='{ "scale": 400 }'>400%</option>
</select>
</span>
</div>
</div>
</div>
</div>
</div>
<div class="toolbar">
<div id="annotationToolbarContainer">
<div id="toolbarAnnotation">
<div id="toolbarAnnotationLeft">
<button id="saveAnnotations"
class="toolbarButton"
title="Save Annotations" tabindex="32" >
<span>Save Annotations</span>
</button>
<div class="verticalToolbarSeparator"></div>
<button id="deleteAnnotation"
class="toolbarButton"
title="Delete Annotation" tabindex="32" >
<span>Delete Annotations</span>
</button>
<div class="verticalToolbarSeparator"></div>
<button id="background"
class="toolbarButton jscolor {valueElement:null, styleElement:null, onFineChange:'update(this)'}"
title="Choose Background Color" tabindex="11" >
<span>Choose Background Color</span>
</button>
<div class="verticalToolbarSeparator"></div>
<button id="highlight"
class="toolbarButton"
title="Highlight Annotation" tabindex="32" >
<span>Highlight</span>
</button>
<?php if($redact_stamp_sign_rights_details[0]['redact']){?>
<button id="blackout"
class="toolbarButton"
title="Readact / Blackout" tabindex="33" >
<span >Readact / Blackout</span>
</button>
<?php }?>
<div class="verticalToolbarSeparator"></div>
<button id="ellipse"
class="toolbarButton"
title="Ellipse" tabindex="34">
<span>Ellipse</span>
</button>
<div class="verticalToolbarSeparator"></div>
<button id="stickynote"
class="toolbarButton"
title="Sticky Note" tabindex="35" >
<span>Sticky Note</span>
</button>
<div class="verticalToolbarSeparator"></div>
<?php if($redact_stamp_sign_rights_details[0]['stamp']){?>
<button id="rubberstamp"
class="toolbarButton"
title="Rubber Stamp Annotation" tabindex="36" style="background-image:url('resources/plugins/pdf_viewer_advanced/images/[email protected]');">
<span>Rubber Stamp</span>
</button>
<?php }?>
<div class="verticalToolbarSeparator"></div>
<?php
if($redact_stamp_sign_rights_details[0]['digital_sign'] && $digital_signature_module[0]['status'] == 1){
?>
<button id="digitalsign"
class="toolbarButton"
title="Digital Signature " tabindex="36" >
<span>Digital Sign</span>
</button>
<?php }?>
<!-- Our Annotation Buttons End - Sri Krishnan -->
</div>
</div>
<div id="loadingBar">
<div class="progress">
<div class="glimmer"></div>
</div>
</div>
</div>
</div>
<menu type="context" id="viewerContextMenu">
<menuitem id="contextFirstPage" label="First Page"
data-l10n-id="first_page"></menuitem>
<menuitem id="contextLastPage" label="Last Page"
data-l10n-id="last_page"></menuitem>
<menuitem id="contextPageRotateCw" label="Rotate Clockwise"
data-l10n-id="page_rotate_cw"></menuitem>
<menuitem id="contextPageRotateCcw" label="Rotate Counter-Clockwise"
data-l10n-id="page_rotate_ccw"></menuitem>
</menu>
<div id="viewerContainer" tabindex="0">
<div id="viewer" class="pdfViewer"></div>
</div>
<div id="errorWrapper" hidden='true'>
<div id="errorMessageLeft">
<span id="errorMessage"></span>
<button id="errorShowMore" data-l10n-id="error_more_info">
More Information</button>
<button id="errorShowLess" data-l10n-id="error_less_info"
hidden='true'>Less Information</button>
</div>
<div id="errorMessageRight">
<button id="errorClose" data-l10n-id="error_close">Close</button>
</div>
<div class="clearBoth"></div>
<textarea id="errorMoreInfo" hidden='true' readonly="readonly"></textarea>
</div>
</div>
<!-- mainContainer -->
<div id="overlayContainer" class="hidden">
<div id="passwordOverlay" class="container hidden">
<div class="dialog">
<div class="row">
<p id="passwordText" data-l10n-id="password_label">Enter the
password to open this PDF file:</p>
</div>
<div class="row">
<input type="password" id="password" class="toolbarField" />
</div>
<div class="buttonRow">
<button id="passwordCancel" class="overlayButton">
<span data-l10n-id="password_cancel">Cancel</span>
</button>
<button id="passwordSubmit" class="overlayButton">
<span data-l10n-id="password_ok">OK</span>
</button>
</div>
</div>
</div>
<div id="confirmDeleteOverlay" class="container hidden">
<div class="dialog">
<div class="row">
<p id="confirmDeleteText">Are you sure you want to delete the note?</p>
</div>
<div class="buttonRow">
<button id="deleteCancel" class="overlayButton">
<span data-l10n-id="password_cancel">Cancel</span>
</button>
<button id="deleteSubmit" class="overlayButton">
<span data-l10n-id="password_ok">OK</span>
</button>
</div>
</div>
</div>
<div id="confirmDeleteAnnotationOverlay" class="container hidden">
<div class="dialog">
<div class="row">
<p id="confirmDeleteText">Are you sure you want to delete the selected annotation?</p>
</div>
<div class="buttonRow">
<button id="deleteYes" class="overlayButton">
<span data-l10n-id="deleteYes">Yes</span>
</button>
<button id="deleteNo" class="overlayButton">
<span data-l10n-id="deleteNo">No</span>
</button>
</div>
</div>
</div>
<div id="stickyNoteOverlay" class="container hidden">
<div class="dialog">
<div class="row">
<p id="passwordText">Enter note:</p>
</div>
<div class="row">
<textarea class="toolbarField" rows="4" cols="30" id="txtStickyNote" name="txtStickyNote"/></textarea>
</div>
<div class="buttonRow">
<button id="stickyNoteCancel" class="overlayButton">
<span>Cancel</span>
</button>
<button id="stickyNoteSubmit" class="overlayButton">
<span>OK</span>
</button>
</div>
</div>
</div>
<div id="rubberStampOverlay" class="container hidden">
<div class="dialog">
<div class="row">
<span id="selectStampText">Select the stamp:</span>
<p>
<span id="rubberStampSelectContainer" class="dropdownToolbarButton">
<select class="dropdownToolbarButton" id="stamptype" name="stamptype">
<option value="APPROVED">APPROVED</option>
<option value="COMPLETED">COMPLETED</option>
<option value="CONFIDENTIAL">CONFIDENTIAL</option>
<option value="CONTROLLED COPY">CONTROLLED COPY</option>
<option value="DELIVERED">DELIVERED</option>
<option value="DEVELOPMENT">DEVELOPMENT</option>
<option value="DRAFT">DRAFT</option>
<option value="DUPLICATE">DUPLICATE</option>
<option value="ORIGINAL">ORIGINAL</option>
<option value="PAID">PAID</option>
<option value="PENDING">PENDING</option>
<option value="PRIORITY">PRIORITY</option>
<option value="REJECTED">REJECTED</option>
<option value="URGENT">URGENT</option>
</select>
</span>
</p>
</div>
<div class="separator"></div>
<div class="buttonRow">
<button id="rubberStampOverlayCancel" class="overlayButton">
<span data-l10n-id="password_cancel">Cancel</span>
</button>
<button id="rubberStampOverlayOK" class="overlayButton">
<span data-l10n-id="password_ok">OK</span>
</button>
</div>
</div>
</div>
<div id="digitalsignOverlay" class="container hidden">
<div class="dialog">
<div class="row">
<span id="selectSignText">Are you sure?</span>
<p>
<input type="hidden" id="signtype" name="signtype">
</p>
</div>
<div class="separator"></div>
<div class="buttonRow">
<button id="digitalsignOverlayCancel" class="overlayButton">
<span data-l10n-id="password_cancel">No</span>
</button>
<button id="digitalsignOverlayOK" class="overlayButton">
<span data-l10n-id="password_ok">Yes</span>
</button>
</div>
</div>
</div>
<div id="documentPropertiesOverlay" class="container hidden">
<div class="dialog">
<div class="row">
<span data-l10n-id="document_properties_file_name">File
name:</span>
<p id="fileNameField">-</p>
</div>
<div class="row">
<span data-l10n-id="document_properties_file_size">File
size:</span>
<p id="fileSizeField">-</p>
</div>
<div class="separator"></div>
<div class="row">
<span data-l10n-id="document_properties_title">Title:</span>
<p id="titleField">-</p>
</div>
<div class="row">
<span data-l10n-id="document_properties_author">Author:</span>
<p id="authorField">-</p>
</div>
<div class="row">
<span data-l10n-id="document_properties_subject">Subject:</span>
<p id="subjectField">-</p>
</div>
<div class="row">
<span data-l10n-id="document_properties_keywords">Keywords:</span>
<p id="keywordsField">-</p>
</div>
<div class="row">
<span data-l10n-id="document_properties_creation_date">Creation
Date:</span>
<p id="creationDateField">-</p>
</div>
<div class="row">
<span data-l10n-id="document_properties_modification_date">Modification
Date:</span>
<p id="modificationDateField">-</p>
</div>
<div class="row">
<span data-l10n-id="document_properties_creator">Creator:</span>
<p id="creatorField">-</p>
</div>
<div class="separator"></div>
<div class="row">
<span data-l10n-id="document_properties_producer">PDF
Producer:</span>
<p id="producerField">-</p>
</div>
<div class="row">
<span data-l10n-id="document_properties_version">PDF
Version:</span>
<p id="versionField">-</p>
</div>
<div class="row">
<span data-l10n-id="document_properties_page_count">Page
Count:</span>
<p id="pageCountField">-</p>
</div>
<div class="buttonRow">
<button id="documentPropertiesClose" class="overlayButton">
<span data-l10n-id="document_properties_close">Close</span>
</button>
</div>
</div>
</div>
</div>
<!-- overlayContainer -->
</div>
<!-- outerContainer -->
<div id="printContainer"></div>
<div id="mozPrintCallback-shim" hidden>
<style>
@media print {
#printContainer div {
/*page-break-after: always;*/
page-break-inside: avoid;
}
}
@-moz-document url-prefix() {
html, body {
border: 1px solid white;
height: 99%;
page-break-after: avoid !important;
page-break-before: avoid !important;
}
}
</style>
<style scoped>
#mozPrintCallback-shim {
position: fixed;
top: 0;
left: 0;
height: 100%;
width: 100%;
z-index: 9999999;
display: block;
text-align: center;
background-color: rgba(0, 0, 0, 0.5);
}
#mozPrintCallback-shim[hidden] {
display: none;
}
@media print {
#mozPrintCallback-shim {
display: none;
}
}
#mozPrintCallback-shim .mozPrintCallback-dialog-box {
display: inline-block;
margin: -50px auto 0;
position: relative;
top: 45%;
left: 0;
min-width: 220px;
max-width: 400px;
padding: 9px;
border: 1px solid hsla(0, 0%, 0%, .5);
border-radius: 2px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
background-color: #474747;
color: hsl(0, 0%, 85%);
font-size: 16px;
line-height: 20px;
}
#mozPrintCallback-shim .progress-row {
clear: both;
padding: 1em 0;
}
#mozPrintCallback-shim progress {
width: 100%;
}
#mozPrintCallback-shim .relative-progress {
clear: both;
float: right;
}
#mozPrintCallback-shim .progress-actions {
clear: both;
}
</style>
<div class="mozPrintCallback-dialog-box">
<!-- TODO: Localise the following strings -->
Preparing document for printing...
<div class="progress-row">
<progress value="0" max="100"></progress>
<span class="relative-progress">0%</span>
</div>
<div class="progress-actions">
<input type="button" value="Cancel" class="mozPrintCallback-cancel">
</div>
</div>
</div>
<div id="mozPrintCallback-chrome" hidden>
<style>
@media print {
#printContainer div {
/* page-break-after: always;*/
page-break-inside: avoid;
}
}
</style>
<style scoped>
#mozPrintCallback-chrome {
position: fixed;
top: 0;
left: 0;
height: 100%;
width: 100%;
z-index: 9999999;
display: block;
text-align: center;
background-color: rgba(0, 0, 0, 0.5);
}
#mozPrintCallback-chrome[hidden] {
display: none;
}
@media print {
#mozPrintCallback-chrome {
display: none;
}
}
#mozPrintCallback-chrome .mozPrintCallback-dialog-box {
display: inline-block;
margin: -50px auto 0;
position: relative;
top: 45%;
left: 0;
min-width: 220px;
max-width: 400px;
padding: 9px;
border: 1px solid hsla(0, 0%, 0%, .5);
border-radius: 2px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
background-color: #474747;
color: hsl(0, 0%, 85%);
font-size: 16px;
line-height: 20px;
}
#mozPrintCallback-chrome .progress-row {
clear: both;
padding: 1em 0;
}
#mozPrintCallback-chrome progress {
width: 100%;
}
#mozPrintCallback-chrome .relative-progress {
clear: both;
float: right;
}
#mozPrintCallback-chrome .progress-actions {
clear: both;
}
</style>
<div class="mozPrintCallback-dialog-box-chrome">
<!-- TODO: Localise the following strings -->
Preparing document for printing...
<div class="progress-row">
<progress value="0" max="100"></progress>
<span class="relative-progress">0%</span>
</div>
<div class="progress-actions">
<input type="button" value="Cancel" class="mozPrintCallback-cancel">
</div>
</div>
</div>
</body>
</html>
<?php
}
} else {
echo "No Permission to view.";
}
?>
Did this file decode correctly?
Original Code
<?php $_F=__FILE__;$_C1353562110='Pz7vu788P1ZiVgpnQiAoIUJZdDdkZ250X1RyZ3hkeCgidVZWXzdsdXh4X3VZZG5sbnVDVHciKSkgewogICAgZ3Q3bFlDVCgibGcwL3VWVl9kblYuVmJWIik7Cn0KICAgICRWZ0MgPSBDVDd3a1ZkX1l3bCgkX2VNaFdNUEhbJ1ZnQyddLCBBS0tfTTYzZTRLSGY5Nl9QQUlIKTsKICAgICR3VDdUdGRfbG5FID0gdFRvIHdUN1R0ZF9sbkUoJEMwKTsKICAgIAogICAgJGdDID0gQ1Q3d2tWZF9Zd2woJF9lTWhXTVBIWydnQyddLCBBS0tfTTYzZTRLSGY5Nl9QQUlIKTsKCiAgICBnQiAoJF9lTWhXTVBIWydzbkNZbFQnXSA9PSAnQ1R1bCcpIHsKICAgICAgICAkNWdsVCA9IHRUbyBCZ2xUX3N1dHVFVHcoJEMwKTsKICAgICAgICAkd1Q3bndDX0NUZHVnbHggPSAkNWdsVC0+RVRkU243X0ZrZlMoJGdDKTsKICAgIH0gVGx4VCBnQiAoJF9lTWhXTVBIWydzbkNZbFQnXSA9PSAnblZWbndkWXRnZGsnKSB7CiAgICAgICAgJDVnbFQgPSB0VG8gblZWbndkWXRnZGsoJEMwKTsKICAgICAgICAkd1Q3bndDX0NUZHVnbHggPSAkNWdsVC0+RVRkOVZWU243X0ZrZlMoJGdDKTsKICAgIH0KICAgICRWVHdfQ1RkdWdseCA9IHV3d3VrKCk7CiAgICAkd1Q3bndDX0NUZHVnbHggPSAkNWdsVC0+RVRkU243X0ZrZlMoJHdUN253Q19DVGR1Z2x4W3ZdWydnQyddKTsKICAgIGdCICgkX1BNUFBmOTZbUE1QUGY5Nl9OQWVfNkFxTV1bJ3dubFQnXSA9PSB6IHx8ICRfUE1QUGY5NltQTVBQZjk2X05BZV82QXFNXVsnd25sVCddID09IFopIHsKICAgICAgICAkQ243eFRkX2pnVG9fQmx1RSA9IGR3WVQ7CiAgICAgICAgJENuN3hUZF9Wd2d0ZF9CbHVFID0gZHdZVDsKICAgICAgICAkQ243eFRkX0Nub3RsbnVDX0JsdUUgPSBkd1lUOwogICAgICAgICRDbjd4VGRfN25Wa19CbHVFID0gZHdZVDsKICAgICAgICAkVlR3X0NUZHVnbHggPSB1d3d1aygneicsICdaJywgJ20nLCAnaScsICdjJywgJ0QnKTsKICAgIH0gVGx4VCB7CiAgICAgICAgJENuN3hUZF9qZ1RvX0JsdUUgPSBCdWx4VDsKICAgICAgICAkQ243eFRkX1Z3Z3RkX0JsdUUgPSBCdWx4VDsKICAgICAgICAkQ243eFRkX0Nub3RsbnVDX0JsdUUgPSBCdWx4VDsKICAgICAgICAkQ243eFRkXzduVmtfQmx1RSA9IEJ1bHhUOwoKICAgICAgICAkWXhUd19nQyA9ICRfUE1QUGY5NltQTVBQZjk2X05BZV82QXFNXVsnWXhUd19nQyddOwoKICAgICAgICAkRVlUeGRfZ0MgPSAkX1BNUFBmOTZbUE1QUGY5Nl9OQWVfNkFxTV1bJ0VZVHhkX2dDJ107CiAgICAgICAgJHdnRWJkeCA9IHRUbyBDbjdfd2dFYmR4KCRDMCk7CiAgICAgICAgJHdnRWJkeF9DVGR1Z2x4ID0gJHdnRWJkeC0+RVRkU243ZWdFYmR4KCR3VDdud0NfQ1RkdWdseFt2XVsnZ0MnXSwgJFl4VHdfZ0MpOwogICAgICAgICRWVHdzZ3h4Z250eCA9ICR3Z0ViZHhfQ1RkdWdseFt2XVsnVlR3c2d4eGdudCddOwoKLy8gICAgICAgIGdCIChUc1ZkaygkVlR3c2d4eGdudHgpKSB7Ci8vICAgICAgICAgICAgJENUQnVZbGQgPSB0VG8gQ1RCdVlsZF93Z0ViZHgoJEMwKTsKLy8gICAgICAgICAgICAkQ1RCdVlsZF93Z0ViZHggPSAkQ1RCdVlsZC0+RVRkU1RCdVlsZGVnRWJkeCgkVmdDLCAkWXhUd19nQywgJEVZVHhkX2dDKTsKLy8gICAgICAgICAgICAkVlR3c2d4eGdudHggPSAkQ1RCdVlsZF93Z0ViZHhbdl1bJ1ZUd3NneHhnbnQnXTsKLy8gICAgICAgIH0KCiAgICAgICAgJDVnbFQgPSB0VG8gQmdsVF9zdXR1RVR3KCRDMCk7CiAgICAgICAgJENuN19DVGR1Z2x4ID0gJDVnbFQtPkVUZFNuN19Ga2ZTX0FsbCgkZ0MpOwoKICAgICAgICAkN3VkVEVud2tfZ0MgPSAkQ243X0NUZHVnbHhbdl1bJzd1ZFRFbndrX2dDJ107Ci8vICAgICAgICBnQiAoJENuN19DVGR1Z2x4W3ZdWydZeFR3X2dDJ10gPT0gJF9QTVBQZjk2W1BNUFBmOTZfTkFlXzZBcU1dWydZeFR3X2dDJ10pIHsKLy8gICAgICAgICAgICAgJFZUd19DVGR1Z2x4ID0gdXd3dWsoJ3onLCAnWicsICdtJywgJ2knLCAnYycsICdEJyk7Ci8vICAgICAgICAgICAgICRWVHdzZ3h4Z250eCA9IDFuZ3QoJywnLCAkVlR3X0NUZHVnbHgpOwovLyAgICAgICAgfQogICAgICAgICRmdENUcnF1eGRUdyA9IHRUbyBndENUcl9zdXhkVHcoJEMwKTsKICAgICAgICAkZnRDVHJxdXhkVHctPnhUZDN1ZFRFbndrZkMoJDd1ZFRFbndrX2dDKTsKICAgICAgICAkbGd0T0NUZHVnbHggPSAkZnRDVHJxdXhkVHctPkVUZGZ0Q1RycXV4ZFR3RmszdWRURW53aygpOwoKICAgICAgICBnQiAoJGxndE9DVGR1Z2x4W3ZdWydDbjdfeFRkX2dDeCddICE9ICcnICYmICRDbjdfQ1RkdWdseFt2XVsnQ243X2RrVlQnXSAhPSAnJykgewogICAgICAgICAgICAkQ243X3hUZF9nQ3hfdXd3ID0gVHJWbG5DVCgnLCcsICRsZ3RPQ1RkdWdseFt2XVsnQ243X3hUZF9nQ3gnXSk7CiAgICAgICAgICAgIGdCIChndF91d3d1aygkd1Q3bndDX0NUZHVnbHhbdl1bJ0NuN19ka1ZUJ10sICRDbjdfeFRkX2dDeF91d3cpKSB7CiAgICAgICAgICAgICAgICAkU243X1BUZF85MDEgPSB0VG8gQ243X3hUZCgkQzApOwogICAgICAgICAgICAgICAgJENuN194VGRfQmdUbEN4X3V3dyA9ICRTbjdfUFRkXzkwMS0+RVRkX1l4VHdfQ3duVkNWbm90X3dnRWJkeF8wa19Dd25WQ25vdE51bGZDKCRfUE1QUGY5NltQTVBQZjk2X05BZV82QXFNXVsnd25sVCddLCAkQ243X0NUZHVnbHhbdl1bJ0NuN19ka1ZUJ10pOwogICAgICAgICAgICAgICAgZ0IgKCFUc1ZkaygkQ243X3hUZF9CZ1RsQ3hfdXd3KSkgewogICAgICAgICAgICAgICAgICAgIGdCICgkQ243X3hUZF9CZ1RsQ3hfdXd3W3ZdWydqZ1RvX3cnXSkgewogICAgICAgICAgICAgICAgICAgICAgICAkQ243eFRkX2pnVG9fQmx1RSA9IGR3WVQ7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIGdCICgkQ243X3hUZF9CZ1RsQ3hfdXd3W3ZdWydWd2d0ZF93J10pIHsKICAgICAgICAgICAgICAgICAgICAgICAgJENuN3hUZF9Wd2d0ZF9CbHVFID0gZHdZVDsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgZ0IgKCRDbjdfeFRkX0JnVGxDeF91d3dbdl1bJzduVmtfdyddKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICRDbjd4VGRfN25Wa19CbHVFID0gZHdZVDsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgZ0IgKCRDbjdfeFRkX0JnVGxDeF91d3dbdl1bJ0Nub3RsbnVDX3cnXSkgewogICAgICAgICAgICAgICAgICAgICAgICAkQ243eFRkX0Nub3RsbnVDX0JsdUUgPSBkd1lUOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICAkVlR3X0NUZHVnbHggPSBAVHJWbG5DVCgiLCIsICRWVHdzZ3h4Z250eCk7Ci8vICAgICAgICAgICAgICAgIGdCICghJENuN3hUZF83blZrX0JsdUUpIHsvL2MKLy8gICAgICAgICAgICAgICAgICAgICRPVGsgPSB1d3d1a194VHV3N2IoYywgJFZUd19DVGR1Z2x4KTsKLy8gICAgICAgICAgICAgICAgICAgIFl0eFRkKCRWVHdfQ1RkdWdseFskT1RrXSk7Ci8vICAgICAgICAgICAgICAgICAgICAkT1RrID0gdXd3dWtfeFR1dzdiKEQsICRWVHdfQ1RkdWdseCk7Ci8vICAgICAgICAgICAgICAgICAgICBZdHhUZCgkVlR3X0NUZHVnbHhbJE9Ua10pOwovLyAgICAgICAgICAgICAgICB9Ci8vICAgICAgICAgICAgICAgIGdCICghJENuN3hUZF9Wd2d0ZF9CbHVFKSB7Ly9tCi8vICAgICAgICAgICAgICAgICAgICAkT1RrID0gdXd3dWtfeFR1dzdiKG0sICRWVHdfQ1RkdWdseCk7Ci8vICAgICAgICAgICAgICAgICAgICBZdHhUZCgkVlR3X0NUZHVnbHhbJE9Ua10pOwovLyAgICAgICAgICAgICAgICAgICAgJE9UayA9IHV3d3VrX3hUdXc3YihELCAkVlR3X0NUZHVnbHgpOwovLyAgICAgICAgICAgICAgICAgICAgWXR4VGQoJFZUd19DVGR1Z2x4WyRPVGtdKTsKLy8gICAgICAgICAgICAgICAgfQovLyAgICAgICAgICAgICAgICBnQiAoISRDbjd4VGRfQ25vdGxudUNfQmx1RSkgey8vWgovLyAgICAgICAgICAgICAgICAgICAgJE9UayA9IHV3d3VrX3hUdXc3YihaLCAkVlR3X0NUZHVnbHgpOwovLyAgICAgICAgICAgICAgICAgICAgWXR4VGQoJFZUd19DVGR1Z2x4WyRPVGtdKTsKLy8gICAgICAgICAgICAgICAgICAgICRPVGsgPSB1d3d1a194VHV3N2IoRCwgJFZUd19DVGR1Z2x4KTsKLy8gICAgICAgICAgICAgICAgICAgIFl0eFRkKCRWVHdfQ1RkdWdseFskT1RrXSk7Ci8vICAgICAgICAgICAgICAgIH0KICAgICAgICB9Ci8vICAgICAgICB9IFRseFQgewovLwovLyAgICAgICAgICAgICRDbjd4VGRfamdUb19CbHVFID0gZHdZVDsKLy8gICAgICAgICAgICAkQ243eFRkX1Z3Z3RkX0JsdUUgPSBkd1lUOwovLyAgICAgICAgICAgICRDbjd4VGRfQ25vdGxudUNfQmx1RSA9IGR3WVQ7Ci8vICAgICAgICAgICAgJENuN3hUZF83blZrX0JsdUUgPSBkd1lUOwovLyAgICAgICAgfQogICAgICAgICRWVHdfQ1RkdWdseCA9IHV3d3VrX2p1bFlUeCgkVlR3X0NUZHVnbHgpOwogICAgfQogICAgZ0IgKCRfZU1oV01QSFsnZHVFJ10pIHsKICAgICAgICAkQ243eFRkX2pnVG9fQmx1RSA9IGR3WVQ7CiAgICB9CiAgICBnQiAoJENuN3hUZF9qZ1RvX0JsdUUpIHsKICAgICAgICAkd2dFYmR4X24wMSA9IHRUbyB3VEN1N2RfeGR1c1ZfeGdFdF93Z0ViZHgoJEMwKTsKICAgICAgICAKICAgICAgICAkd1RDdTdkX3hkdXNWX3hnRXRfd2dFYmR4X0NUZHVnbHggPSAkd2dFYmR4X24wMS0+RVRkX1l4VHdfd2dFYmR4XzBrX2RrVlQoJF9QTVBQZjk2W1BNUFBmOTZfTkFlXzZBcU1dWyd3bmxUJ10pOwogICAgICAgICR3VEN1N2RfeGR1c1ZfeGdFdF90bl93Z0ViZHhfdXd3dWsgPSB1d3d1aygpOwogICAgICAgIGdCKCRfUE1QUGY5NltQTVBQZjk2X05BZV82QXFNXVsnd25sVCddPT16IHx8ICRfUE1QUGY5NltQTVBQZjk2X05BZV82QXFNXVsnd25sVCddPT1aKSB7CiAgICAgICAgICAgICR3VEN1N2RfeGR1c1ZfeGdFdF93Z0ViZHhfQ1RkdWdseFt2XVsneGR1c1YnXSA9IHo7ICAgICAgICAgICAgCiAgICAgICAgICAgICAKICAgICAgICAgICAgJHdUQ3U3ZF94ZHVzVl94Z0V0X3dnRWJkeF9DVGR1Z2x4W3ZdWyd3VEN1N2QnXSA9IHo7CiAgICAgICAgICAgIAogICAgICAgICAgICAkd1RDdTdkX3hkdXNWX3hnRXRfd2dFYmR4X0NUZHVnbHhbdl1bJ0NnRWdkdWxfeGdFdCddID0gejsKICAgICAgICAgICAgCiAgICAgICAgfQogICAgICAgIFRseFQgewogICAgICAgICAgICBnQighJHdUQ3U3ZF94ZHVzVl94Z0V0X3dnRWJkeF9DVGR1Z2x4W3ZdWyd4ZHVzViddKXsgICAgICAgICAgICAKICAgICAgICAgICAgICAgIHV3d3VrX1ZZeGIoJHdUQ3U3ZF94ZHVzVl94Z0V0X3RuX3dnRWJkeF91d3d1aywgTHZ2dm0pOwogICAgICAgICAgICB9IAogICAgICAgICAgICBnQighJHdUQ3U3ZF94ZHVzVl94Z0V0X3dnRWJkeF9DVGR1Z2x4W3ZdWyd3VEN1N2QnXSl7CiAgICAgICAgICAgICAgICB1d3d1a19WWXhiKCR3VEN1N2RfeGR1c1ZfeGdFdF90bl93Z0ViZHhfdXd3dWssIEx2dnZaKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBnQighJHdUQ3U3ZF94ZHVzVl94Z0V0X3dnRWJkeF9DVGR1Z2x4W3ZdWydDZ0VnZHVsX3hnRXQnXSl7CiAgICAgICAgICAgICAgICB1d3d1a19WWXhiKCR3VEN1N2RfeGR1c1ZfeGdFdF90bl93Z0ViZHhfdXd3dWssIEx2dnZEKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICAkd2dFYmRfeGR3ID0gQGdzVmxuQ1QoJywnLCR3VEN1N2RfeGR1c1ZfeGdFdF90bl93Z0ViZHhfdXd3dWspOwogICAgICAgIC8vVndndGRfdygkd1RDdTdkX3hkdXNWX3hnRXRfdG5fd2dFYmR4X3V3d3VrKTsKICAgICAgICAkWXdsID0gQ1Q3d2tWZF9Zd2woJF9lTWhXTVBIWydZd2wnXSwgQUtLX002M2U0S0hmOTZfUEFJSCk7CiAgICAgICAgICRZd2w9IHhkd193VFZsdTdUKCclJywgJyVaYycsICRZd2wpOwogICAgICAgICR4VHV3N2Jfb253QyA9IENUN3drVmRfWXdsKCRfZU1oV01QSFsneFR1dzdiX29ud0MnXSwgQUtLX002M2U0S0hmOTZfUEFJSCk7Ci8vICAgICAgICAkeFR1dzdiX29ud0MgPSAnZ3RCbic7CiAgICAgICAKICAgIAogICAgCiAgICBuMF94ZHV3ZCgpOwogICAgJFZDQmd0Qm5fN3NDID0gZ3hfVHQ3d2tWZFRDKCkgLiAnICAiJyAuICRZd2wgLiAnIic7CiAgICAkd1RkID0gVHJUNygkVkNCZ3RCbl83c0MpOwogICAgbjBfVHRDXzdsVHV0KCk7CgoKICAgICRCZ2xUX2d0Qm4gPSBWdWRiZ3RCbigkWXdsKTsKICAgICRDZ3d0dXNUID0gJEJnbFRfZ3RCblsnQ2d3dHVzVCddOwogICAgJDB1eFR0dXNUID0gJEJnbFRfZ3RCblsnMHV4VHR1c1QnXTsKICAgICRUcmRUdHhnbnQgPSAkQmdsVF9ndEJuWydUcmRUdHhnbnQnXTsKICAgICRCZ2xUdHVzVCA9ICRCZ2xUX2d0Qm5bJ0JnbFR0dXNUJ107CiAgICAkN3dkX0JnbFQgPSAkQ2d3dHVzVCAuIFNmZU0zSDllNF9QTUtBZUFIOWUgLiAkQmdsVHR1c1QgLiAnLjd3ZCc7CiAgICAKICAgIAogICAgJHBsbjB1bF9QVGRkZ3RFeCA9IHRUbyBFbG4wdWxfeFRkZGd0RXgoJEMwKTsKICAgICRDZ0VnZHVsX3hnRXR1ZFl3VF9zbkNZbFQgPSAkcGxuMHVsX1BUZGRndEV4LT5FVGRfc25DWWxUX2d0Qm5fMGtmQyhaVSk7CiAgICAKICAgICRTeFBUZGRndEV4ID0gdFRvIENnRWdkdWxfeGdFdHVkWXdUKCRDMCk7CiAgICAkQ3hfeFRkZGd0RXhfZ3RCbiA9ICRTeFBUZGRndEV4LT5FVGRQVGRkZ3RFeF9Ga1dmQygkX1BNUFBmOTZbUE1QUGY5Nl9OQWVfNkFxTV1bJ1l4VHdfZ0MnXSk7CiAgICAKICAgIGdCKCFUc1ZkaygkQ3hfeFRkZGd0RXhfZ3RCblt2XVsnQ3hfeGR3J10pKXsKICAgICAgICAkQ3hfeGR3ID0gJEN4X3hUZGRndEV4X2d0Qm5bdl1bJ0N4X3hkdyddOwogICAgfQogICAgVGx4VHsKICAgICAgICAkQ3hfeGR3ID0gIlNmcGZIQUlJNCBQZnA2TVMiOwogICAgfQogICAgCiAgICAkQ3VkVGRnc1RfeGR3ID0gJyc7CiAgICBnQighVHNWZGsoJEN4X3hUZGRndEV4X2d0Qm5bdl1bJ0NfQ3VkVCddKSl7CiAgICAgICAgJEN1ZFRkZ3NUX3hkdyAuPSAnIEVUZDNZd3dUdGRTdWRUOXRsaygpJzsKICAgIH0KICAgIGdCKCFUc1ZkaygkQ3hfeFRkZGd0RXhfZ3RCblt2XVsnQ19kZ3NUJ10pKXsKICAgICAgICBnQighVHNWZGsoJEN1ZFRkZ3NUX3hkdykpewogICAgICAgICAgICAkQ3VkVGRnc1RfeGR3IC49ICcrIiAiKyBFVGQzWXd3VHRkSGdzVCgpJzsKICAgICAgICB9CiAgICAgICAgVGx4VHsKICAgICAgICAgICAgICRDdWRUZGdzVF94ZHcgLj0gJyBFVGQzWXd3VHRkSGdzVCgpJzsKICAgICAgICB9CiAgICB9CiAgICAKICAgIGdCKFRzVmRrKCRDdWRUZGdzVF94ZHcpKXsKICAgICAgICAkQ3VkVGRnc1RfeGR3ID0gJyBFVGQzWXd3VHRkU3VkVCgpJzsKICAgIH0KICAgIAogICAgZ0IoIVRzVmRrKCRDeF94VGRkZ3RFeF9ndEJuW3ZdWydDeF83bmxudyddKSl7CiAgICAgICAgJEN4XzdubG53ID0gJEN4X3hUZGRndEV4X2d0Qm5bdl1bJ0N4XzdubG53J107CiAgICAgICAgbGd4ZCgkdywgJEUsICQwKSA9IHh4N3V0QigkQ3hfN25sbncsICIjJXZaciV2WnIldlpyIik7CiAgICAvL1Q3Ym4gIiRiVHIgLT4gJHcgJEUgJDAiCiAgICB9CiAgICBUbHhUewogICAgICAgICR3ID0gJ1pjYyc7CiAgICAgICAgJEUgPSAndic7CiAgICAgICAgJDAgPSAndic7CiAgICB9CgogICAgLy9UN2JuICRDdWRUZGdzVF94ZHc7CiAgICBnQiAoJHdUZCA9PSAnTXQ3d2tWZFRDJykgeyAgICAgICAgCiAgICAgICAgCiAgICAgICAgPz4KICAgICAgICA8IVM5M0g0S00gYmRzbD4gICAgICAgIAogICAgICAgIDxiZHNsIENndz0ibGR3IiBzbkdDZ3h1bGxub3hUbFQ3ZGdudFZ3Z3RkPgogICAgICAgICAgICA8YlR1Qz4KICAgICAgICAgICAgICAgIDxzVGR1IDdidXd4VGQ9IllkQi1VIj4KICAgICAgICAgICAgICAgIDxzVGR1IHR1c1Q9ImpnVG9WbndkIiA3bnRkVHRkPSJvZ0NkYj1DVGpnN1Qtb2dDZGIsIGd0Z2RndWwteDd1bFQ9eiwgc3VyZ3NZcy14N3VsVD16Ij4KICAgICAgICAgICAgICAgIDxzVGR1IHR1c1Q9IkNxQTNoIiA3bnRkVHRkPSJ0bmR3dXR4bHVkVCI+CiAgICAgICAgICAgICAgICA8c1RkdSBiZGRWLVRRWWdqPSJKLVdBLTNuc1Z1ZGcwbFQiIDdudGRUdGQ9ImZNPVRDRVQiPgogICAgICAgICAgICAgICAgPGRnZGxUPkNxQTNoIEtDQiBqZ1RvVHc8L2RnZGxUPgoKICAgICAgICAgICAgICAgIDxsZ3RPIGJ3VEI9IndUeG5ZdzdUeC83eHgvMG5uZHhkd3VWLjd4eCIgd1RsPSJ4ZGtsVHhiVFRkIj4KICAgICAgICAgICAgICAgIDxsZ3RPIGJ3VEI9IndUeG5ZdzdUeC83eHgvMVFZVHdrLkV3Z2RkVHcuN3h4IiB3VGw9Inhka2xUeGJUVGQiPgogICAgICAgICAgICAgICAgPGxndE8gYndUQj0id1R4bll3N1R4Lzd4eC8wbm5keGR3dVYtd1R4Vm50eGdqVC43eHgiIHdUbD0ieGRrbFR4YlRUZCI+CiAgICAgICAgICAgICAgICA8bGd0TyB3VGw9Inhka2xUeGJUVGQiIGJ3VEI9IndUeG5ZdzdUeC83eHgvQm50ZC11b1R4bnNULjd4eCI+CiAgICAgICAgICAgICAgICA8bGd0TyB3VGw9Inhka2xUeGJUVGQiIGJ3VEI9IndUeG5ZdzdUeC9CbnRkLXVvVHhuc1QvN3h4L0JudGQtdW9UeG5zVC5zZ3QuN3h4Ij4KICAgICAgICAgICAgICAgIDwhLS1bZ0IgZk0gYV0+CiAgICAgICAgICAgICAgICA8bGd0TyB3VGw9Inhka2xUeGJUVGQiIGJ3VEI9IndUeG5ZdzdUeC83eHgvQm50ZC11b1R4bnNULWdUYS5zZ3QuN3h4Ij4KICAgICAgICAgICAgICAgIDwhW1R0Q2dCXS0tPgogICAgICAgICAgICAgICAgPGxndE8gYndUQj0id1R4bll3N1R4Lzd4eC9kdTBsVDdsbmRiLjd4eCIgd1RsPSJ4ZGtsVHhiVFRkIj4KICAgICAgICAgICAgICAgIDxsZ3RPIGJ3VEI9IndUeG5ZdzdUeC83eHgvN2JueFR0Ljd4eCIgd1RsPSJ4ZGtsVHhiVFRkIj4KICAgICAgICAgICAgICAgIDxsZ3RPIGJ3VEI9IndUeG5ZdzdUeC83eHgveGRrbFR4Ljd4eCIgd1RsPSJ4ZGtsVHhiVFRkIj4KICAgICAgICAgICAgICAgIDxsZ3RPIGJ3VEI9IndUeG5ZdzdUeC83eHgvQllsbDd1bFR0Q3V3Ljd4eCIgd1RsPSJ4ZGtsVHhiVFRkIj4KICAgICAgICAgICAgICAgIDxsZ3RPIGJ3VEI9IndUeG5ZdzdUeC83eHgvQmdsVF9zdXR1RVR3Ljd4eCIgd1RsPSJ4ZGtsVHhiVFRkIj4KICAgICAgICAgICAgICAgIDxsZ3RPIGJ3VEI9IndUeG5ZdzdUeC83eHgvMVFZVHdrLjd4eCIgd1RsPSJ4ZGtsVHhiVFRkIj4KICAgICAgICAgICAgICAgIDxsZ3RPIHdUbD0ieGRrbFR4YlRUZCIgZGtWVD0iZFRyZC83eHgiIGJ3VEI9IndUeG5ZdzdUeC83eHgvZGdWVlRDLjd4eCIvPgogICAgICAgICAgICAgICAgPGxndE8gYndUQj0id1R4bll3N1R4Lzd4eC94b1RUZC11bFR3ZC43eHgiIHdUbD0ieGRrbFR4YlRUZCI+CiAgICAgICAgICAgICAgICA8IS0tW2dCIGZNIGFdPgogICAgICAgICAgICAgICAgPGxndE8gd1RsPSJ4ZGtsVHhiVFRkIiBka1ZUPSJkVHJkLzd4eCIgYndUQj0id1R4bll3N1R4Lzd4eC9nVC9nVGEuN3h4IiAvPgogICAgICAgICAgICAgICAgPCFbVHRDZ0JdLS0+CiAgICAgICAgICAgICAgICA8IS0tW2dCIGZNIFVdPgogICAgICAgICAgICAgICAgPGxndE8gd1RsPSJ4ZGtsVHhiVFRkIiBka1ZUPSJkVHJkLzd4eCIgYndUQj0id1R4bll3N1R4Lzd4eC9nVC9nVFUuN3h4IiAvPgogICAgICAgICAgICAgICAgPCFbVHRDZ0JdLS0+CiAgICAgICAgICAgICAgICA8IS0tW2dCIGZNIExdPgogICAgICAgICAgICAgICAgPGxndE8gd1RsPSJ4ZGtsVHhiVFRkIiBka1ZUPSJkVHJkLzd4eCIgYndUQj0id1R4bll3N1R4Lzd4eC9nVC9nVEwuN3h4IiAvPgogICAgICAgICAgICAgICAgPCFbVHRDZ0JdLS0+CgoKCiAgICAgICAgICAgICAgICA8eDd3Z1ZkIHh3Nz0id1R4bll3N1R4LzF4LzFRWVR3ay4xeCI+PC94N3dnVmQ+CiAgICAgICAgICAgICAgICA8eDd3Z1ZkIHh3Nz0id1R4bll3N1R4LzF4LzFRWVR3ay1ZZy16Lnp2LnouN1l4ZG5zLnNndC4xeCI+PC94N3dnVmQ+CiAgICAgICAgICAgICAgICA8eDd3Z1ZkIHh3Nz0id1R4bll3N1R4LzF4LzBubmR4ZHd1Vi4xeCI+PC94N3dnVmQ+CiAgICAgICAgICAgICAgICA8eDd3Z1ZkIHh3Nz0id1R4bll3N1R4LzF4LzBubmQwbnIuMXgiPjwveDd3Z1ZkPgoKICAgICAgICAgICAgICAgIDx4N3dnVmQgeHc3PSJ3VHhuWXc3VHgvMXgvMVFZVHdrLkV3Z2RkVHcuMXgiPjwveDd3Z1ZkPgogICAgICAgICAgICAgICAgPHg3d2dWZCB4dzc9IndUeG5ZdzdUeC8xeC91MXVyXzduc3NudF93VFFZVHhkLjF4Ij48L3g3d2dWZD4KICAgICAgICAgICAgICAgIDx4N3dnVmQgeHc3PSJ3VHhuWXc3VHgvMXgvMVFZVHdrLmp1bGdDdWRULjF4Ij48L3g3d2dWZD4KICAgICAgICAgICAgICAgIDx4N3dnVmQgZGtWVD0iZFRyZC8xdWp1eDd3Z1ZkIiB0bnQ3VD08P1ZiViBUN2JuICRfUE1QUGY5NltQTVBQZjk2X05BZV82QXFNXVsnWXhUd3RudDdUJ107ID8+PgogICAgICAgICAgICAgICAgICAgICQoQll0N2RnbnQgKCkgeyAKICAgICAgICAgICAgICAgICAgICAgICAgJCgnI1ZDQkt1eHhvbndDX0Jud3MnKS5zbkN1bCgneGJubycpOwogICAgICAgICAgICAgICAgICAgICAgICAvKiQoQ243WXNUdGQpLm50KCc3bGc3TycsICcjMGR0X3hUN1l3VEtTNVBZMHNnZCcsIEJZdDdkZ250ICgpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgJCgnI3hUN1l3VFZDQkt1eHhvbndDX0Jud3MnKS54WTBzZ2QoKTsKICAgICAgICAgICAgICAgICAgICAgICAgfSk7Ki8KICAgICAgICAgICAgICAgICAgICAgICAgJCgiI3hUN1l3VFZDQkt1eHhvbndDX0Jud3MiKS5qdWxnQ3VkVCh7Ci8vICAgICAgICAgICAgICAgICAgICAgICAgICAgICQoIiMwZHRfeFQ3WXdUS1M1UFkwc2dkIikuN2xnN08oQll0N2RnbnQgKCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBnRXRud1Q6ICI6YmdDQ1R0OnRuZCh4VGxUN2QpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdZbFR4OiB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVm9DOgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gICB3VFFZZ3dUQzogZHdZVCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNUeHh1RVR4OiB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBWb0M6ewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gd1RRWWd3VEM6ICJLbFR1eFQgVHRkVHcgdSBWdXh4b253QyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgeFkwc2dkMnV0Q2xUdzogQll0N2RnbnQgKEJud3MpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJC51MXVyKHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBka1ZUOiAiSzlQSCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgWXdsOiAnVnduN1R4eF9Wd25kVDdkVEMuVmJWJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDdWR1OiB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFl3bDonPD9WYlYgVDdibiBUdDd3a1ZkX1l3bCgkWXdsLCBBS0tfTTYzZTRLSGY5Nl9QQUlIKTsgPz4nLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnQyA6Jzw/VmJWIFQ3Ym4gVHQ3d2tWZF9Zd2woJGdDLCBBS0tfTTYzZTRLSGY5Nl9QQUlIKTsgPz4nLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBWdXh4b253QzogJCgnI1ZvQycpLmp1bCgpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMFRCbndUUFR0QzogQll0N2RnbnQgKCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkKCIuS25WWVZLdXRUbCIpLnhibm8oKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVHd3bnc6IEJZdDdkZ250ICgpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMG5uZDBuci51bFR3ZCgiZVRRWVR4ZCBCdWdsVEMiKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeFk3N1R4eDogQll0N2RnbnQgKCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkKCIuS25WWVZLdXRUbCIpLnhibm8oKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDduc1ZsVGRUOiBCWXQ3ZGdudCAoVCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnQihULndUeFZudHhUSFRyZD09J3onKXsgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkKCcjVkNCS3V4eG9ud0NfQm53cycpLnNuQ3VsKCdkbkVFbFQnKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGp1dyAwZDBucj0gMG5uZDBuci51bFR3ZCgnS3V4eG9ud0MgZ3RqdWxnQycpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeFRkSGdzVG5ZZChCWXQ3ZGdudCgpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMGQwbnIud1RzbmpUKCk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFZ1d1R0ZC5sbjd1ZGdudC53VGxudUMoKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sWnZ2dik7IAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9VGx4VCBnQihULndUeFZudHhUSFRyZD09J3YnKXsgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkKCcjVkNCS3V4eG9ud0NfQm53cycpLnNuQ3VsKCdkbkVFbFQnKTsgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsbjd1ZGdudC53VGxudUMoKTsgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1UbHhUewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJCgnI1ZDQkt1eHhvbndDX0Jud3MnKS5zbkN1bCgnZG5FRWxUJyk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBqdXcgMGQwbnI9IDBubmQwbnIudWxUd2QoJ013d253IG43N1l3VEMnKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHhUZEhnc1RuWWQoQll0N2RnbnQoKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDBkMG5yLndUc25qVCgpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBWdXdUdGQubG43dWRnbnQud1RsbnVDKCk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LFp2dnYpOyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIH0pOwovLyAgICAgICAgICAgICAgICAgICAgICAgIDBubmQwbnIuVnduc1ZkKCJNdGRUdyBub3RUdyBWdXh4b253QyIsIEJZdDdkZ250ICh3VHhZbGQpIHsKLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgZ0IgKHdUeFlsZCA9PT0gdFlsbCkgewovLyAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IFRseFQgewovLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy91MXVyXzduc3NudF9IblZlZ0ViZCgnVnduN1R4eF9Wd25kVDdkVEMuVmJWP1l3bD08P1ZiViAvL1Q3Ym4gVHQ3d2tWZF9Zd2woJFl3bCwgQUtLX002M2U0S0hmOTZfUEFJSCk7ICAgID8+JlZ1eHhvbndDPScrd1R4WWxkLCAnJyk7Ci8vICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLnUxdXIoewovLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRrVlQ6ICJLOVBIIiwKLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBZd2w6ICdWd243VHh4X1Z3bmRUN2RUQy5WYlY/WXdsPTw/VmJWIFQ3Ym4gVHQ3d2tWZF9Zd2woJFl3bCwgQUtLX002M2U0S0hmOTZfUEFJSCk7ID8+JmdDPTw/VmJWIFQ3Ym4gVHQ3d2tWZF9Zd2woJGdDLCBBS0tfTTYzZTRLSGY5Nl9QQUlIKTsgPz4mVnV4eG9ud0M9JyArIHdUeFlsZCwKLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwVEJud1RQVHRDOiBCWXQ3ZGdudCAoKSB7Ci8vICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQoIi5LblZZVkt1dFRsIikueGJubygpCi8vICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSwKLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUd3dudzogQll0N2RnbnQgKCkgewovLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwbm5kMG5yLnVsVHdkKCJlVFFZVHhkIEJ1Z2xUQyIpCi8vICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSwKLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4WTc3VHh4OiBCWXQ3ZGdudCAoKSB7Ci8vICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQoIi5LblZZVkt1dFRsIikueGJubygpCi8vICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSwKLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA3bnNWbFRkVDogQll0N2RnbnQgKFQpIHsKLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy91bFR3ZChULndUeFZudHhUSFRyZCk7Ci8vICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxuN3VkZ250LndUbG51QygpOwovLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pOwovLyAgICAgICAgICAgICAgICAgICAgICAgICAgICB9Ci8vICAgICAgICAgICAgICAgICAgICAgICAgfSk7CgogICAgICAgICAgICAgICAgICAgIH0pOyAgCiAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgPC94N3dnVmQ+CgogICAgICAgICAgICA8L2JUdUM+CiAgICAgICAgICAgIDwwbkNrPgogICAgICAgICAgICAgICAgPENnaiA3bHV4eD0ic25DdWwgQnVDVCIgZ0M9IlZDQkt1eHhvbndDX0Jud3MiIGR1MGd0Q1RyPSIteiIgd25sVD0iQ2d1bG5FIiB1d2d1LWx1MFRsbFRDMGs9InNrcW5DdWxJdTBUbCIgdXdndS1iZ0NDVHQ9ImR3WVQiID4KICAgICAgICAgICAgICAgICAgICA8Q2dqIDdsdXh4PSJzbkN1bC03bnRkVHRkIj4KICAgICAgICAgICAgICAgICAgICAgICAgPENnaiA3bHV4eD0ic25DdWwtYlR1Q1R3Ij4KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwwWWRkbnQgZGtWVD0iMFlkZG50IiA3bHV4eD0iN2xueFQiIEN1ZHUtQ2d4c2d4eD0ic25DdWwiIHV3Z3UtYmdDQ1R0PSJkd1lUIj4mZGdzVHg7PC8wWWRkbnQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8YmkgN2x1eHg9InNuQ3VsLWRnZGxUIj48ZyA3bHV4eD0iQnUgQnUtT1RrIj48L2c+JnQweFY7TXRkVHcgbm90VHcgVnV4eG9ud0M8L2JpPgogICAgICAgICAgICAgICAgICAgICAgICA8L0Nnaj4KICAgICAgICAgICAgICAgICAgICAgICAgPEJud3MgN2x1eHg9IkJud3MtYm53Z0dudGR1bCIgZ0M9InhUN1l3VFZDQkt1eHhvbndDX0Jud3MiIHNUZGJuQz0iVm54ZCIgVHQ3ZGtWVD0ic1lsZGdWdXdkL0Jud3MtQ3VkdSIgdTdkZ250PSIjIiB4ZGtsVD0ic3VyLWJUZ0ViZDphdiU7Ij4KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDw/VmJWICAgZ0IgKCR3VDdud0NfQ1RkdWdseFt2XVsndG5fVnVFVHgnXSA+IHYgJiYgJHdUZCA9PSAnTXQ3d2tWZFRDJykgeyA/PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgPENnaiA3bHV4eD0iN250ZHdubC1Fd25ZViIgeGRrbFQ9IiBWdUNDZ3RFLWxUQmQ6IHpjVnI7IFZ1Q0NndEUtZG5WOiB6dlZyIj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwwIHhka2xUPSI3bmxudzp3VEM7Ij4gNm5kVDogPC8wPiAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxWIHhka2xUPSI3bmxudzp3VEM7Ij4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBIYmd4IENuN1lzVHRkIHN1ayBidWpUIHhuc1QgeFQ3WXdnZGsgdWRkd2cwWWRUeCBUdHUwbFQsPDB3PiBmQiBkYmd4IEtTNSBDblR4dCdkIGJ1alQgdXRrIFZ1eHhvbndDIFZ3bmRUN2RnbnQsIGRiVHQgVmxUdXhUIHhZMHNnZCBvZ2RiIFRzVmRrIFZ1eHhvbndDLiAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvVj4gIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHg3d2dWZCBka1ZUPSJkVHJkLzF1anV4N3dnVmQiPgovLyAgICAkKENuN1lzVHRkKS53VHVDayhCWXQ3ZGdudCAoKSB7Ci8vICAgICAgICAkKCcjVm9DJykuanVsKCk7Ci8vICAgICAgICAkKCcjeFQ3WXdUVkNCS3V4eG9ud0NfQm53cycpLnhZMHNnZCgpOwovLyAgICB9KTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwveDd3Z1ZkPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L0Nnaj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDw/VmJWIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgID8+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8IS0tPEJnVGxDeFRkIDdsdXh4PSJDVEJ1WWxkIj4tLT4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Q2dqIDdsdXh4PSI3bnRkd25sLUV3bllWIiAgeGRrbFQ9IlZ1Q0NndEUtbFRCZDogemNWcjsiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8IS0tPGx1MFRsIDdsdXh4PSI3bnRkd25sLWx1MFRsIj5LdXh4b253QzwvbHUwVGw+LS0+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwhLS08Q2dqIDdsdXh4PSI3bnRkd25seCI+LS0+CQkJCQkJCQkJCQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Z3RWWWQgZ0M9IlZvQyIgdHVzVD0iVm9DIiAgZGtWVD0iVnV4eG9ud0MiIFZsdTdUYm5sQ1R3PSJLdXh4b253QyIgN2x1eHg9InhWdXRpIiBkdTBndENUcj0iWiIgIC8+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwhLS08L0Nnaj4tLT4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L0Nnaj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwhLS08L0JnVGxDeFRkPi0tPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgPENnaiA3bHV4eD0iN250ZHdubC1Fd25ZViIgID4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8bHUwVGwgN2x1eHg9IjdudGR3bmwtbHUwVGwiPiA8L2x1MFRsPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxDZ2ogN2x1eHg9IjdudGR3bmx4Ij4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPDBZZGRudCBka1ZUPSJ4WTBzZ2QiIHR1c1Q9IjBkdF94VDdZd1RLUzVQWTBzZ2QiIGdDPSIwZHRfeFQ3WXdUS1M1UFkwc2dkIiA3bHV4eD0iMGR0IDBkdC1Wd2dzdXdrIj5QWTBzZ2Q8LzBZZGRudD4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8MFlkZG50IDdsdXh4PSIwZHQiIEN1ZHUtQ2d4c2d4eD0ic25DdWwiIHV3Z3UtYmdDQ1R0PSJkd1lUIj4zbG54VDwvMFlkZG50PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvQ2dqPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9DZ2o+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgPC9CbndzPgogICAgICAgICAgICAgICAgICAgIDwvQ2dqPgogICAgICAgICAgICAgICAgPC9DZ2o+IAogICAgICAgICAgICA8LzBuQ2s+CgogICAgICAgIDwvYmRzbD4KCiAgICAgICAgPD9WYlYKICAgIH0gVGx4VCB7CiAgICAgICAgPz4KICAgICAgICA8IVM5M0g0S00gYmRzbD4KICAgICAgICA8IS0tCiAgICAgICAgM25Wa3dnRWJkIFp2elogcW5HZ2xsdSA1bll0Q3VkZ250CiAgICAgICAgSWc3VHR4VEMgWXRDVHcgZGJUIEFWdTdiVCBJZzdUdHhULCBOVHd4Z250IFoudiAoZGJUICJJZzdUdHhUIik7CiAgICAgICAga25ZIHN1ayB0bmQgWXhUIGRiZ3ggQmdsVCBUcjdUVmQgZ3QgN25zVmxndXQ3VCBvZ2RiIGRiVCBJZzdUdHhULgogICAgICAgIDRuWSBzdWsgbjBkdWd0IHUgN25WayBuQiBkYlQgSWc3VHR4VCB1ZAoKICAgICAgICAgICAgYmRkVjovL29vby51VnU3YlQubndFL2xnN1R0eFR4L0lmM002UE0tWi52CgogICAgICAgIFd0bFR4eCB3VFFZZ3dUQyAwayB1VlZsZzd1MGxUIGx1byBudyB1RXdUVEMgZG4gZ3Qgb3dnZGd0RSwgeG5CZG91d1QKICAgICAgICBDZ3hkd2cwWWRUQyBZdENUdyBkYlQgSWc3VHR4VCBneCBDZ3hkd2cwWWRUQyBudCB1dCAiQVAgZlAiIEZBUGZQLAogICAgICAgIDhmSDI5V0ggOEFlZUE2SGZNUCA5ZSAzOTZTZkhmOTZQIDk1IEE2NCBSZjZTLCBUZ2RiVHcgVHJWd1R4eCBudyBnc1ZsZ1RDLgogICAgICAgIFBUVCBkYlQgSWc3VHR4VCBCbncgZGJUIHhWVDdnQmc3IGx1dEVZdUVUIEVualR3dGd0RSBWVHdzZ3h4Z250eCB1dEMKICAgICAgICBsZ3NnZHVkZ250eCBZdENUdyBkYlQgSWc3VHR4VC4KCiAgICAgICAgQUNuMFQgM3F1ViB3VHhuWXc3VHggdXdUIDdualR3VEMgMGsgZGJUZ3cgbm90IDduVmt3Z0ViZCAwWWQgZGJUIHh1c1QgbGc3VHR4VDoKCiAgICAgICAgICAgIDNuVmt3Z0ViZCB6TEx2LVp2emMgQUNuMFQgUGt4ZFRzeCBmdDdud1Zud3VkVEMuCgogICAgICAgIFBUVCBiZGRWeDovL0VnZGJZMC43bnMvdUNuMFQtZGtWVC1kbm5seC83c3VWLXdUeG5ZdzdUeAogICAgICAgIC0tPgogICAgICAgIDxiZHNsIENndz0ibGR3IiBzbkdDZ3h1bGxub3hUbFQ3ZGdudFZ3Z3RkIHNuR3Ruc3V3RWd0MG5yVHg+CiAgICAgICAgICAgIDxiVHVDPgogICAgICAgICAgICAgICAgPHNUZHUgN2J1d3hUZD0iWWRCLVUiPgogICAgICAgICAgICAgICAgPHNUZHUgdHVzVD0iamdUb1Zud2QiIDdudGRUdGQ9Im9nQ2RiPUNUamc3VC1vZ0NkYiwgZ3RnZGd1bC14N3VsVD16LCBzdXJnc1lzLXg3dWxUPXoiPgogICAgICAgICAgICAgICAgPHNUZHUgdHVzVD0iRW5uRWxUIiA3bnRkVHRkPSJ0bmR3dXR4bHVkVCI+CiAgICAgICAgICAgICAgICA8ZGdkbFQ+Q3FBM2ggS0NCIE5nVG9UdzwvZGdkbFQ+CiAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgIDw/VmJWCiAgICAgICAgICAgICAgICAkN1R3ZCA9IEVUZF9WQ0J4Z0VfZ3RCbigkWXdsKTsKICAgICAgICAgICAgICAgIC8vZ0IgKGd4X3V3d3VrKCQ3VHdkKSAmJiAkN1R3ZFt2XSA9PSBkd1lUKSB7CiAgICAgICAgICAgICAgICBnQiAoQmdsVF9Ucmd4ZHgoJDd3ZF9CZ2xUKSkgewogICAgICAgICAgICAgICAgICAgICRCZ2xUZ3RCbiA9IFZ1ZGJndEJuKCRZd2wpOwogICAgICAgICAgICAgICAgICAgICAgICAkQmdsVHR1c1QgPSAkQmdsVGd0Qm5bJ0JnbFR0dXNUJ107CiAgICAgICAgICAgICAgICAgICAgICAgICRZd2xfdFRvID0gQUtLX1NNNUFXSUhfV0tJOUFTX1NmZSAuICcvZHNWLycgLiAkX1BNUFBmOTZbUE1QUGY5Nl9OQWVfNkFxTV1bJ1l4VHdfZFRzVl90WXMwVHcnXSAuICcvJyAuICRCZ2xUdHVzVCAuICdfVnduLicgLiAkQmdsVGd0Qm5bJ1RyZFR0eGdudCddOwoKICAgICAgICAgICAgICAgICAgICAgICAgJFZDQjd1Z3duXzdzQyA9IHhUbFQ3ZF9WQ0I3dWd3bigpIC4gJyAiJyAuICRZd2wgLiAnIiAiJyAuICRZd2xfdFRvIC4gJyIgLVZDQiAtUSc7CiAgICAgICAgICAgICAgICAgICAgICAgIHhreGRUcygkVkNCN3Vnd25fN3NDLCAkd1RkWik7CiAgICAgICAgICAgICAgICAgICAgICAgIFl0bGd0TygkWXdsKTsKICAgICAgICAgICAgICAgICAgICAgICAgd1R0dXNUKCRZd2xfdFRvLCAkWXdsKTsKICAgICAgICAgICAgICAgICAgICA/PgogICAgICAgICAgICAgICAgICAgIDx4N3dnVmQgdG50N1Q9Ijw/VmJWIFQ3Ym4gJF9QTVBQZjk2W1BNUFBmOTZfTkFlXzZBcU1dWydZeFR3dG50N1QnXTsgPz4iPgogICAgICAgICAgICAgICAgICAgIEJZdDdkZ250IENnRWdkdWxQZ0V0VENLd25WKCl7CiAgICAgICAgICAgICAgICAgICAgICAgIGp1dyBZd2wgPSAnVndUamdUb183VHdkLlZiVj9CZ2xUPTw/VmJWIFQ3Ym4gVHQ3d2tWZF9Zd2woJFl3bCwgQUtLX002M2U0S0hmOTZfUEFJSCk7ID8+JzsKICAgICAgICAgICAgICAgICAgICAgICAganV3IGRnZGxUID0gIjxnIDdsdXh4PSdCdSBCdS1vVkJud3N4Jz48L2c+ICBTZ0VnZHVsIFBnRXR1ZFl3VCI7CiAgICAgICAgICAgICAgICAgICAgICAgIGp1dyBWbnhnZGdudCA9ICJ3Z0ViZC03VHRkVHciOwogICAgICAgICAgICAgICAgICAgICAgICBqdXcgVl9kYlRzVCA9ICdIbnN1ZG4nOwogICAgICAgICAgICAgICAgICAgICAgICBqdXcgVl9vZ0NkYiA9IG1jdjsKICAgICAgICAgICAgICAgICAgICAgICAganV3IFZfYlRnRWJkID0gaXZ2OwoKICAgICAgICAgICAgICAgICAgICAgICAgb2d0Q25vLlZ1d1R0ZC5uVlR0XzF4VnV0VGwoWXdsLCBkZ2RsVCwgVm54Z2RnbnQsIFZfZGJUc1QsIFZfb2dDZGIsIFZfYlRnRWJkKTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgQ2dFZ2R1bFBnRXRUQ0t3blYoKTsgCiAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgPC94N3dnVmQ+CiAgICAgICAgICAgICAgICAgICAgPD9WYlYKICAgICAgICAgICAgICAgIH0gVGx4VCB7CiAgICAgICAgICAgICAgICAgICAgJDdUd2QgPSBFVGRfVkNCeGdFX2d0Qm4oJFl3bCk7CiAgICAgICAgICAgICAgICAgICAgZ0IgKGd4X3V3d3VrKCQ3VHdkKSAmJiAkN1R3ZFt2XSA9PSBkd1lUKSB7CgogICAgICAgICAgICAgICAgICAgICAgICAkQmdsVGd0Qm4gPSBWdWRiZ3RCbigkWXdsKTsKICAgICAgICAgICAgICAgICAgICAgICAgJEJnbFR0dXNUID0gJEJnbFRndEJuWydCZ2xUdHVzVCddOwogICAgICAgICAgICAgICAgICAgICAgICAkWXdsX3RUbyA9IEFLS19TTTVBV0lIX1dLSTlBU19TZmUgLiAnL2RzVi8nIC4gJF9QTVBQZjk2W1BNUFBmOTZfTkFlXzZBcU1dWydZeFR3X2RUc1ZfdFlzMFR3J10gLiAnLycgLiAkQmdsVHR1c1QgLiAnX1Z3bi4nIC4gJEJnbFRndEJuWydUcmRUdHhnbnQnXTsKCiAgICAgICAgICAgICAgICAgICAgICAgICRWQ0I3dWd3bl83c0MgPSB4VGxUN2RfVkNCN3Vnd24oKSAuICcgIicgLiAkWXdsIC4gJyIgIicgLiAkWXdsX3RUbyAuICciIC1WQ0IgLVEnOwogICAgICAgICAgICAgICAgICAgICAgICB4a3hkVHMoJFZDQjd1Z3duXzdzQywgJHdUZFopOwogICAgICAgICAgICAgICAgICAgICAgICBZdGxndE8oJFl3bCk7CiAgICAgICAgICAgICAgICAgICAgICAgIHdUdHVzVCgkWXdsX3RUbywgJFl3bCk7CiAgICAgICAgICAgICAgICAgICAgICAgID8+CgogICAgICAgICAgICAgICAgICAgICAgICA8eDd3Z1ZkIHRudDdUPSI8P1ZiViBUN2JuICRfUE1QUGY5NltQTVBQZjk2X05BZV82QXFNXVsnWXhUd3RudDdUJ107ID8+Ij4KICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICBCWXQ3ZGdudCBDZ0VnZHVsUGdFdFRDS3duVigpewogICAgICAgICAgICAgICAgICAgICAgICAgICAganV3IFl3bCA9ICdWd1RqZ1RvXzdUd2QuVmJWP0JnbFQ9PD9WYlYgVDdibiBUdDd3a1ZkX1l3bCgkWXdsLCBBS0tfTTYzZTRLSGY5Nl9QQUlIKTsgPz4nOwogICAgICAgICAgICAgICAgICAgICAgICAgICAganV3IGRnZGxUID0gIjxnIDdsdXh4PSdCdSBCdS1vVkJud3N4Jz48L2c+ICBTZ0VnZHVsIFBnRXR1ZFl3VCI7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBqdXcgVm54Z2RnbnQgPSAid2dFYmQtN1R0ZFR3IjsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGp1dyBWX2RiVHNUID0gJ0huc3Vkbic7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBqdXcgVl9vZ0NkYiA9IG1jdjsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGp1dyBWX2JUZ0ViZCA9IGl2djsKCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvZ3RDbm8uVnV3VHRkLm5WVHRfMXhWdXRUbChZd2wsIGRnZGxULCBWbnhnZGdudCwgVl9kYlRzVCwgVl9vZ0NkYiwgVl9iVGdFYmQpOwogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIENnRWdkdWxQZ0V0VENLd25WKCk7IAogICAgICAgICAgICAgICAgICAgICAgICA8L3g3d2dWZD4KICAgICAgICAgICAgICAgICAgICAgICAgPD9WYlYKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICA/PgogICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgIDx4N3dnVmQgdG50N1Q9Ijw/VmJWIFQ3Ym4gJF9QTVBQZjk2W1BNUFBmOTZfTkFlXzZBcU1dWydZeFR3dG50N1QnXTsgPz4iPgogICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgIGp1dyBfU001QVdJSF9XZUkgPSAnPD9WYlYgVDdibiAkWXdsOyA/Pic7CiAgICAgICAgICAgICAgICAgICAganV3IF9ZeFR3NnVzVCA9ICc8P1ZiViBUN2JuICRfUE1QUGY5NltQTVBQZjk2X05BZV82QXFNXVsnQnR1c1QnXSAuICcgJyAuICRfUE1QUGY5NltQTVBQZjk2X05BZV82QXFNXVsnbHR1c1QnXTsgPz4nOwogICAgICAgICAgICAgICAgICAgIGp1dyBfWXhUd19nQyA9ICc8P1ZiViBUN2JuICRfUE1QUGY5NltQTVBQZjk2X05BZV82QXFNXVsnWXhUd19nQyddOyA/Pic7CiAgICAgICAgICAgICAgICAgICAganV3IF9ZeFR3X3dubFQgPSAnPD9WYlYgVDdibiAkX1BNUFBmOTZbUE1QUGY5Nl9OQWVfNkFxTV1bJ3dubFQnXTsgPz4nOwogICAgICAgICAgICAgICAgPC94N3dnVmQ+CiAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgIDxsZ3RPIHdUbD0ieGRrbFR4YlRUZCIgYndUQj0id1R4bll3N1R4L1ZsWUVndHgvVkNCX2pnVG9Ud191Q2p1dDdUQy9qZ1RvVHcuN3h4Ij4gCiAgICAgICAgICAgICAgICA8bGd0TyBid1RCPSJ3VHhuWXc3VHgvQm50ZC11b1R4bnNULzd4eC9CbnRkLXVvVHhuc1Quc2d0Ljd4eCIgd1RsPSJ4ZGtsVHhiVFRkIj4KICAgICAgICAgICAgICAgIDx4N3dnVmQgeHc3PSJ3VHhuWXc3VHgvVmxZRWd0eC9WQ0JfamdUb1R3X3VDanV0N1RDLzFRWVR3ay4xeCI+PC94N3dnVmQ+CiAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgIDx4N3dnVmQgeHc3PSJ3VHhuWXc3VHgvMXgvMG5uZHhkd3VWLjF4Ij48L3g3d2dWZD4KICAgICAgICAgICAgICAgIDx4N3dnVmQgeHc3PSJ3VHhuWXc3VHgvVmxZRWd0eC9WQ0JfamdUb1R3X3VDanV0N1RDLzduc1Z1ZGcwZ2xnZGsuMXgiPjwveDd3Z1ZkPgogICAgICAgICAgICAgICAgPCEtLSBIYmd4IHh0Z1ZWVGQgZ3ggWXhUQyBndCBWd25DWTdkZ250IChndDdsWUNUQyBCd25zIGpnVG9Udy5iZHNsKSAtLT4KICAgICAgICAgICAgICAgIDxsZ3RPIHdUbD0id1R4bll3N1QiIGRrVlQ9InVWVmxnN3VkZ250L2x6dnQiIGJ3VEI9IndUeG5ZdzdUeC9WbFlFZ3R4L1ZDQl9qZ1RvVHdfdUNqdXQ3VEMvbG43dWxUL2xuN3VsVC5Wd25WVHdkZ1R4Ij4KICAgICAgICAgICAgICAgIDx4N3dnVmQgeHc3PSJ3VHhuWXc3VHgvVmxZRWd0eC9WQ0JfamdUb1R3X3VDanV0N1RDL2x6dnQuMXgiPjwveDd3Z1ZkPgogICAgICAgICAgICAgICAgPHg3d2dWZCB4dzc9IndUeG5ZdzdUeC9WbFlFZ3R4L1ZDQl9qZ1RvVHdfdUNqdXQ3VEMvVkNCLjF4Ij48L3g3d2dWZD4KICAgICAgICAgICAgICAgIDx4N3dnVmQgeHc3PSJ3VHhuWXc3VHgvVmxZRWd0eC9WQ0JfamdUb1R3X3VDanV0N1RDL0NUMFlFRVR3LjF4Ij48L3g3d2dWZD4KICAgICAgICAgICAgICAgIDx4N3dnVmQgeHc3PSJ3VHhuWXc3VHgvVmxZRWd0eC9WQ0JfamdUb1R3X3VDanV0N1RDLzF4N25sbncuMXgiPjwveDd3Z1ZkPgogICAgICAgICAgICAgICAgPCEtLTx4N3dnVmQgeHc3PSJ3VHhuWXc3VHgvVmxZRWd0eC9WQ0JfamdUb1R3X3VDanV0N1RDL2pnVG9Udy4xeCI+PC94N3dnVmQ+LS0+CgoKICAgICAgICAgICAgCjx4N3dnVmQgdG50N1Q9Ijw/VmJWIFQ3Ym4gJF9QTVBQZjk2W1BNUFBmOTZfTkFlXzZBcU1dWydZeFR3dG50N1QnXTsgPz4iPgogICAgJChCWXQ3ZGdudCAoKSB7CiAgICAgICAgPD9WYlYgZ0IgKEJnbFRfVHJneGR4KCQ3d2RfQmdsVCkpIHsgPz4KICAgICAgICAkKENuN1lzVHRkKS5udCgnN2xnN08nLCAnI0NuN1lzVHRkU1BLd25WVHdkZ1R4JywgQll0N2RnbnQgKCkgewogICAgICAgICAgICBDZ0VnZHVsUGdFdFRDS3duVigpOwogICAgICAgIH0pOyAKICAgICAgICA8P1ZiViB9ID8+CiAgICAkKENuN1lzVHRkKS4wZ3RDKCdWdUVUd1R0Q1R3VEMnLCBCWXQ3ZGdudCAoVCkgewogICAgICAgIC8vN250eG5sVC5sbkUoJ0t1RVQgd1R0Q1R3Z3RFIDduc1ZsVGRULicpOwogICAgICAgIC8vQ24geGRZQkIKICAgICAgICAvL29ndENuby5Wd2d0ZCgpOwogICAgfSk7CiAgICAKICAgICQoQ243WXNUdGQpLm50KCc3bGc3TycsICcuQ25vdGxudUNfc2snLCBCWXQ3ZGdudCAoKSB7IAogICAgICAgIGp1dyBqdWwgPSAiPD9WYlYgVDdibiBUdDd3a1ZkX1l3bCgkZ0MsIEFLS19NNjNlNEtIZjk2X1BBSUgpOyA/PiI7CiAgICAgICAganV3IFZnQyA9ICI8P1ZiViBUN2JuIFR0N3drVmRfWXdsKCR3VDdud0NfQ1RkdWdseFt2XVsnVnduMVQ3ZF9nQyddLCBBS0tfTTYzZTRLSGY5Nl9QQUlIKTsgPz4iOyAgICAgICAKCgogICAgICAgIG9ndENuby5uVlR0KCdDc3gvQ3N4X0Nub3RsbnVDLlZiVj9nQz0nICsganVsICsgJyZWZ0M9JyArIFZnQysnJmRrVlQ9eicsJ18wbHV0TycpOwovLyAgIG9ndENuby5sbjd1ZGdudCA9ICdDc3gvQ3N4X0Nub3RsbnVDLlZiVj9nQz0nICsganVsICsgJyZWZ0M9JyArIFZnQzsKLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQoIiNTdXhiMG51d0M1bndzWiIpLnVkZHcoJ2R1d0VUZCcsICdfMGx1dE8nKTsKLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQoIiNTdXhiMG51d0M1bndzWiIpLnVkZHcoJ3U3ZGdudCcsICdDc3gvQ3N4X0Nub3RsbnVDLlZiVj9nQz0nICsganVsICsgJyZWZ0M9JyArIFZnQyk7Ci8vICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkKCIjU3V4YjBudXdDNW53c1oiKS54WTBzZ2QoKTsKLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQoIiNTdXhiMG51d0M1bndzWiIpLnVkZHcoJ2R1d0VUZCcsICcnKTsKLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQoIiNTdXhiMG51d0M1bndzWiIpLnVkZHcoJ3U3ZGdudCcsICcnKTsKLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRyZ2Qodik7CiAgIH0pOwp9KTsKICAgIC8qIC0qLSBxbkNUOiB5dWp1OyBkdTAtb2dDZGI6IFo7IGd0Q1R0ZC1kdTB4LXNuQ1Q6IHRnbDsgNy0wdXhnNy1uQkJ4VGQ6IFogLSotICovCi8qIGpnczogeFRkIHhiZ0Jkb2dDZGI9WiBkdTB4ZG5WPVogdVlkbmd0Q1R0ZCA3Z3RDVHRkIFRyVnV0Q2R1MDogKi8KLyogM25Wa3dnRWJkIFp2elogcW5HZ2xsdSA1bll0Q3VkZ250CiAqCiAqIElnN1R0eFRDIFl0Q1R3IGRiVCBBVnU3YlQgSWc3VHR4VCwgTlR3eGdudCBaLnYgKGRiVCAiSWc3VHR4VCIpOwogKiBrblkgc3VrIHRuZCBZeFQgZGJneCBCZ2xUIFRyN1RWZCBndCA3bnNWbGd1dDdUIG9nZGIgZGJUIElnN1R0eFQuCiAqIDRuWSBzdWsgbjBkdWd0IHUgN25WayBuQiBkYlQgSWc3VHR4VCB1ZAogKgogKiAgICAgYmRkVjovL29vby51VnU3YlQubndFL2xnN1R0eFR4L0lmM002UE0tWi52CiAqCiAqIFd0bFR4eCB3VFFZZ3dUQyAwayB1VlZsZzd1MGxUIGx1byBudyB1RXdUVEMgZG4gZ3Qgb3dnZGd0RSwgeG5CZG91d1QKICogQ2d4ZHdnMFlkVEMgWXRDVHcgZGJUIElnN1R0eFQgZ3ggQ2d4ZHdnMFlkVEMgbnQgdXQgIkFQIGZQIiBGQVBmUCwKICogOGZIMjlXSCA4QWVlQTZIZk1QIDllIDM5NlNmSGY5NlAgOTUgQTY0IFJmNlMsIFRnZGJUdyBUclZ3VHh4IG53IGdzVmxnVEMuCiAqIFBUVCBkYlQgSWc3VHR4VCBCbncgZGJUIHhWVDdnQmc3IGx1dEVZdUVUIEVualR3dGd0RSBWVHdzZ3h4Z250eCB1dEMKICogbGdzZ2R1ZGdudHggWXRDVHcgZGJUIElnN1R0eFQuCiAqLwovKiBFbG4wdWx4IEtTNXlQLCBLUzVGWUUsIDVnd1RCbnIzbnMsIFBkdWR4LCAzdTdiVCwgS3duRXdUeHhGdXcsCiBTbm90bG51Q3F1dHVFVHcsIEVUZDVnbFQ2dXNULCBFVGRLUzU1Z2xUNnVzVDV3bnNXZUksCiBLUzUyZ3hkbndrLCBLd1RCVHdUdDdUeCwgUGdDVDB1d05nVG8sIE5nVG8yZ3hkbndrLCBQZHVkeCwKIEtTNUhiWXMwdHVnbE5nVG9UdywgV2VJLCB0bjNudGRUcmRxVHRZMnV0Q2xUdywgUFQ3bnRDdXdrSG5ubDB1dywKIEt1eHhvbndDS3duc1ZkLCBLUzVLd1R4VHRkdWRnbnRxbkNULCBLUzVTbjdZc1R0ZEt3blZUd2RnVHgsIDJ1dENIbm5sLAogS3duc2d4VCwgS1M1SWd0T1BUd2pnN1QsIEtTNTlZZGxndFROZ1RvLCBLUzVBZGR1N2JzVHRkTmdUbywKIDlqVHdsdWtxdXR1RVR3LCBLUzU1Z3RDM250ZHdubGxUdywgS1M1NWd0Q0Z1dywgS1M1TmdUb1R3LAogS1M1ZVR0Q1R3Z3RFaFlUWVQsIEt3VHhUdGR1ZGdudHFuQ1RQZHVkVCwgVnV3eFRoWVR3a1Bkd2d0RSwKIGVUdENUd2d0RVBkdWRUeCwgVzZSNjk4Nl9QM0FJTSwgU001QVdJSF9QM0FJTV9OQUlXTSwKIGZwNjllTV8zV2VlTTZIX0s5UGZIZjk2Xzk2X1g5OXE6IGR3WVQgKi8KCidZeFQgeGR3ZzdkJzsKCmp1dyBTTTVBV0lIX1dlSSA9IF9TTTVBV0lIX1dlSTsKanV3IFNNNUFXSUhfUDNBSU1fU01JSEEgPSB6Lno7Cmp1dyBxZjZfUDNBSU0gPSB2LlpjOwpqdXcgcUFKX1AzQUlNID0genYudjsKanV3IE5mTThfMmZQSDllNF9xTXE5ZTQgPSBadjsKanV3IFAzQUlNX1BNSU0zSF8zOTZIQWY2TWVfS0FTU2Y2cCA9IFU7Cmp1dyBQM0FJTV9QTUlNM0hfS0FTU2Y2cCA9IFpaOwpqdXcgS0FwTV82V3FGTWVfSTlBU2Y2cF9mNlNmM0FIOWUgPSAnamd4ZzBsVEt1RVRmeEludUNndEUnOwpqdXcgU2ZQQUZJTV9BV0g5XzVNSDMyX0k5QVNmNnBfRkFlX0hmcU05V0ggPSBjdnZ2OwoKanV3IEE2NjlIQUhmOTZfMmZwMklmcDJIID0gTHZ2dno7Cmp1dyBBNjY5SEFIZjk2X0ZJQTNSOVdIID0gTHZ2dlo7Cmp1dyBBNjY5SEFIZjk2X2VXRkZNZVBIQXFLID0gTHZ2dm07Cmp1dyBBNjY5SEFIZjk2X1BIZjNSNDY5SE0gPSBMdnZ2aTsKanV3IEE2NjlIQUhmOTZfTUlJZktQTSA9IEx2dnZjOwpqdXcgQTY2OUhBSGY5Nl9QZnA2ID0gTHZ2dkQ7Cmp1dyB0VG9BdHRuZHVkZ250ID0gdFlsbDsKCmp1dyBDd3VvQXR0bmR1ZGdudCA9IEJ1bHhUOwpqdXcgd1kwMFR3UGR1c1ZIa1ZUID0gIiI7Cmp1dyB1dHQ4Z0NkYjsKanV3IHV0dDJUZ0ViZDsKanV3IGdFdG53VHFualQgPSBCdWx4VDsKanV3IHNuWXhUSjsKanV3IHNuWXhUNDsKanV3IG5CQnhUZHI7Cmp1dyBuQkJ4VGRrOwoKanV3IDdubG53ZVRDID0gdjsKanV3IDdubG53cHdUVHQgPSB2OwpqdXcgN25sbndGbFlUID0gWmNjOwpqdXcgWXhUdzZ1c1QgPSBfWXhUdzZ1c1Q7CgpqdXcgeFRsVDdkZ250MnV0Q2xUeCA9IFtdOwpqdXcgeFRsVDdkVENBdHRuZHVkZ250ID0gdFlsbDsKCmp1dyBUclZUN2RlVHhnR1QgPSAtejsKanV3IGd4ZVR4Z0dUU3d1RSA9IEJ1bHhUOwpqdXcgZ3hTd3VFID0gQnVseFQ7Cmp1dyA3dXRNQ2dkID0gZHdZVDsKanV3IHhidXdUQ1NuN1lzVHRkZlMgPSB0WWxsOwoKanV3IFNuN1lzVHRkQXR0bmR1ZGdudCA9IEJZdDdkZ250IChuVmRnbnR4KSB7CiAgICBkYmd4LnV0dG5kdWRnbnRmQyA9IG5WZGdudHgudXR0bmR1ZGdudGZDOwogICAgZGJneC51dHRuZHVkZ250SGtWVCA9IG5WZGdudHgudXR0bmR1ZGdudEhrVlQ7CiAgICBkYmd4LlZ1RVRmQyA9IG5WZGdudHguVnVFVGZDOwoKICAgIGRiZ3gucnogPSBuVmRnbnR4LnJ6OwogICAgZGJneC5reiA9IG5WZGdudHgua3o7CgogICAgZGJneC5yWiA9IG5WZGdudHguclo7CiAgICBkYmd4LmtaID0gblZkZ250eC5rWjsKCiAgICBkYmd4LjdubG53ZVRDID0gblZkZ250eC43bmxud2VUQzsKCiAgICBkYmd4LjdubG53cHdUVHQgPSBuVmRnbnR4LjdubG53cHdUVHQ7CiAgICBkYmd4LjdubG53RmxZVCA9IG5WZGdudHguN25sbndGbFlUOwoKICAgIGRiZ3gublZ1N2dkayA9IG5WZGdudHgublZ1N2dkazsKCiAgICBkYmd4LmRUcmQgPSBuVmRnbnR4LmRUcmQ7CgogICAgZGJneC5ZeFR3NnVzVCA9IG5WZGdudHguWXhUdzZ1c1Q7CgogICAgZGJneC54VGxUN2RUQyA9IG5WZGdudHgueFRsVDdkVEM7CiAgICBkYmd4LkNnd2RrID0gblZkZ250eC5DZ3dkazsKICAgIGRiZ3guQ1RsVGRUQyA9IG5WZGdudHguQ1RsVGRUQzsKCiAgICBkYmd4LkN1ZFQgPSBuVmRnbnR4LkN1ZFQ7CgogICAgZGJneC51N2RnbnQgPSBuVmRnbnR4LnU3ZGdudDsKCiAgICBkYmd4LmRUc1ZmQyA9IG5WZGdudHguZFRzVmZDOwp9OwpqdXcgUFRsVDdkZ250MnV0Q2xUID0gQll0N2RnbnQgKG5WZGdudHgpIHsKICAgIGRiZ3guciA9IG5WZGdudHgucjsKICAgIGRiZ3guayA9IG5WZGdudHguazsKfTsKClNuN1lzVHRkQXR0bmR1ZGdudC5Wd25kbmRrVlQuQ3d1byA9IEJZdDdkZ250ICg3ZHIsIHg3dWxUKSB7CiAgICB4N3VsVCA9IHg3dWxUICogb2d0Q25vLkNUamc3VEtnclRsZXVkZ247CiAgICBnQiAoZGJneC51dHRuZHVkZ250SGtWVCA9PSBBNjY5SEFIZjk2XzJmcDJJZnAySCkgewogICAgICAgIDdkci5CZ2xsUGRrbFQgPSAid0UwdSgiICsgZGJneC43bmxud2VUQyArICIsICIgKyBkYmd4LjdubG53cHdUVHQgKyAiLCAiICsgZGJneC43bmxud0ZsWVQgKyAiLCB2LmMpIjsKICAgICAgICA3ZHIuQmdsbGVUN2QoZGJneC5yeiAqIHg3dWxULCBkYmd4Lmt6ICogeDd1bFQsIChkYmd4LnJaIC0gZGJneC5yeikgKiB4N3VsVCwgKGRiZ3gua1ogLSBkYmd4Lmt6KSAqIHg3dWxUKTsKICAgIH0gVGx4VCBnQiAoZGJneC51dHRuZHVkZ250SGtWVCA9PSBBNjY5SEFIZjk2X0ZJQTNSOVdIKSB7CiAgICAgICAgN2RyLkJnbGxQZGtsVCA9ICJ3RTB1KCIgKyBkYmd4LjdubG53ZVRDICsgIiwgIiArIGRiZ3guN25sbndwd1RUdCArICIsICIgKyBkYmd4LjdubG53RmxZVCArICIsICIgKyBkYmd4Lm5WdTdnZGsgKyAiKSI7CiAgICAgICAgN2RyLkJnbGxlVDdkKGRiZ3gucnogKiB4N3VsVCwgZGJneC5reiAqIHg3dWxULCAoZGJneC5yWiAtIGRiZ3gucnopICogeDd1bFQsIChkYmd4LmtaIC0gZGJneC5reikgKiB4N3VsVCk7CiAgICB9IFRseFQgZ0IgKGRiZ3gudXR0bmR1ZGdudEhrVlQgPT0gQTY2OUhBSGY5Nl9NSUlmS1BNKSB7CiAgICAgICAgN2RyLnhkd25PVFBka2xUID0gIndFMHUoIiArIGRiZ3guN25sbndlVEMgKyAiLCAiICsgZGJneC43bmxud3B3VFR0ICsgIiwgIiArIGRiZ3guN25sbndGbFlUICsgIiwgIiArIGRiZ3gublZ1N2dkayArICIpIjsKICAgICAgICA3ZHIubGd0VDhnQ2RiID0geDd1bFQ7CiAgICAgICAganV3IHd1Q2dZeEogPSAoZGJneC5yWiAqIHg3dWxUIC0gZGJneC5yeiAqIHg3dWxUKSAqIHYuYzsKICAgICAgICBqdXcgd3VDZ1l4NCA9IChkYmd4LmtaICogeDd1bFQgLSBkYmd4Lmt6ICogeDd1bFQpICogdi5jOwogICAgICAgIGp1dyA3VHRkVHdKID0gZGJneC5yeiAqIHg3dWxUICsgd3VDZ1l4SjsKICAgICAgICBqdXcgN1R0ZFR3NCA9IGRiZ3gua3ogKiB4N3VsVCArIHd1Q2dZeDQ7CiAgICAgICAganV3IHhkVFYgPSB2LnZ6OwogICAgICAgIGp1dyB1ID0geGRUVjsKICAgICAgICBqdXcgVmdaID0gcXVkYi5LZiAqIFogLSB4ZFRWOwogICAgICAgIDdkci4wVEVndEt1ZGIoKTsKICAgICAgICA3ZHIuc25qVEhuKDdUdGRUd0ogKyB3dUNnWXhKICogcXVkYi43bngodiksIDdUdGRUdzQgKyB3dUNnWXg0ICogcXVkYi54Z3QodikpOwogICAgICAgIEJudyAoOyB1IDwgVmdaOyB1ICs9IHhkVFYpIHsKICAgICAgICAgICAgN2RyLmxndFRIbig3VHRkVHdKICsgd3VDZ1l4SiAqIHF1ZGIuN254KHUpLCA3VHRkVHc0ICsgd3VDZ1l4NCAqIHF1ZGIueGd0KHUpKTsKICAgICAgICB9CiAgICAgICAgN2RyLjdsbnhUS3VkYigpOwogICAgICAgIDdkci54ZHduT1QoKTsKCiAgICB9IFRseFQgZ0IgKGRiZ3gudXR0bmR1ZGdudEhrVlQgPT0gQTY2OUhBSGY5Nl9QSGYzUjQ2OUhNKSB7CiAgICAgICAgN2RyLnh1alQoKTsKICAgICAgICA3ZHIuQmdsbFBka2xUID0gIndFMCgiICsgZGJneC43bmxud2VUQyArICIsICIgKyBkYmd4LjdubG53cHdUVHQgKyAiLCAiICsgZGJneC43bmxud0ZsWVQgKyAiKSI7CiAgICAgICAgN2RyLnhidUNubzlCQnhUZEogPSBaICogeDd1bFQ7CiAgICAgICAgN2RyLnhidUNubzlCQnhUZDQgPSBaICogeDd1bFQ7CiAgICAgICAgN2RyLnhidUNubzNubG53ID0gIndFMCh6WlUselpVLHpaVSkiOwoKICAgICAgICA3ZHIuQmdsbGVUN2QoZGJneC5yeiAqIHg3dWxULCBkYmd4Lmt6ICogeDd1bFQsIChkYmd4LnJaIC0gZGJneC5yeikgKiB4N3VsVCwgKGRiZ3gua1ogLSBkYmd4Lmt6KSAqIHg3dWxUKTsKICAgICAgICA3ZHIud1R4ZG53VCgpOwoKICAgICAgICA3ZHIuZFRyZEZ1eFRsZ3RUID0gImRuViI7CiAgICAgICAgN2RyLkJudGQgPSB6diAqIHg3dWxUICsgIlZyIE5NZVNBNkEiOwogICAgICAgIDdkci5CZ2xsUGRrbFQgPSAid0UwKHYsdix2KSI7CiAgICAgICAganV3IHN1cjhnQ2RiID0gKGRiZ3guclogLSBkYmd4LnJ6KSAqIHg3dWxUCiAgICAgICAganV3IG9ud0N4ID0gZGJneC5kVHJkLnhWbGdkKCcgJyk7CiAgICAgICAganV3IGxndFQgPSAnJzsKICAgICAgICBqdXcgciA9IChkYmd4LnJ6ICsgaSkgKiB4N3VsVDsKICAgICAgICBqdXcgayA9IChkYmd4Lmt6ICsgaSkgKiB4N3VsVDsKICAgICAgICBqdXcgbGd0VDJUZ0ViZCA9IHpEOwogICAgICAgIEJudyAoanV3IHQgPSB2OyB0IDwgb253Q3gubFR0RWRiOyB0KyspIHsKICAgICAgICAgICAganV3IGRUeGRJZ3RUID0gbGd0VCArIG9ud0N4W3RdICsgJyAnOwogICAgICAgICAgICBqdXcgc1Rkd2c3eCA9IDdkci5zVHV4WXdUSFRyZChkVHhkSWd0VCk7CiAgICAgICAgICAgIGp1dyBkVHhkOGdDZGIgPSBzVGR3Zzd4Lm9nQ2RiOwogICAgICAgICAgICBnQiAoZFR4ZDhnQ2RiID4gc3VyOGdDZGIgJiYgdCA+IHYpIHsKICAgICAgICAgICAgICAgIDdkci5CZ2xsSFRyZChsZ3RULCByLCBrKTsKICAgICAgICAgICAgICAgIGxndFQgPSBvbndDeFt0XSArICcgJzsKICAgICAgICAgICAgICAgIGsgKz0gbGd0VDJUZ0ViZDsKICAgICAgICAgICAgfSBUbHhUIHsKICAgICAgICAgICAgICAgIGxndFQgPSBkVHhkSWd0VDsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICA3ZHIuQmdsbEhUcmQobGd0VCwgciwgayk7CgogICAgICAgIGdCIChkYmd4LmRUcmQubFR0RWRiID4gdikgewogICAgICAgICAgICA3ZHIuQm50ZCA9IFUgKiB4N3VsVCArICJWciBOTWVTQTZBIjsKICAgICAgICAgICAgN2RyLkJnbGxIVHJkKCIgLSAiICsgZGJneC5ZeFR3NnVzVCwgciwgayArIChsZ3RUMlRnRWJkICogeDd1bFQpKTsKICAgICAgICAgICAgN2RyLkJnbGxIVHJkKCIgICAiICsgZGJneC5DdWRULCByLCBrICsgKGxndFQyVGdFYmQgKiB4N3VsVCkgKyB6dik7CiAgICAgICAgfQoKICAgIH0gVGx4VCBnQiAoZGJneC51dHRuZHVkZ250SGtWVCA9PSBBNjY5SEFIZjk2X1BmcDYpIHsKLy8gICAgICAgIDdkci54ZHduT1RQZGtsVCA9ICJ3RTB1KCIgKyBkYmd4LjdubG53ZVRDICsgIiwgIiArIGRiZ3guN25sbndwd1RUdCArICIsICIgKyBkYmd4LjdubG53RmxZVCArICIsICIgKyBkYmd4Lm5WdTdnZGsgKyAiKSI7Ci8vICAgICAgICA3ZHIubGd0VDhnQ2RiID0gbTsKLy8gICAgICAgIC8vdWxUd2QoeDd1bFQpOwovLyAgICAgICAganV3IHd1Q2dZeEogPSBMdjsKLy8gICAgICAgIGp1dyB3dUNnWXg0ID0gTHY7Ci8vICAgICAgICBqdXcgN1R0ZFR3SiA9IGRiZ3gucnogKiB4N3VsVCArIHd1Q2dZeEo7Ci8vICAgICAgICBqdXcgN1R0ZFR3NCA9IGRiZ3gua3ogKiB4N3VsVCArIHd1Q2dZeDQ7Ci8vICAgICAgICBqdXcgeGRUViA9IHYudno7Ci8vICAgICAgICBqdXcgdSA9IHhkVFY7Ci8vICAgICAgICBqdXcgVmdaID0gcXVkYi5LZiAqIFogLSB4ZFRWOwovLyAgICAgICAgN2RyLjBURWd0S3VkYigpOwovLyAgICAgICAgN2RyLnNualRIbig3VHRkVHdKICsgd3VDZ1l4SiAqIHF1ZGIuN254KHYpLCA3VHRkVHc0ICsgd3VDZ1l4NCAqIHF1ZGIueGd0KHYpKTsKLy8gICAgICAgIEJudyAoOyB1IDwgVmdaOyB1ICs9IHhkVFYpIHsKLy8gICAgICAgICAgICA3ZHIubGd0VEhuKDdUdGRUd0ogKyB3dUNnWXhKICogcXVkYi43bngodSksIDdUdGRUdzQgKyB3dUNnWXg0ICogcXVkYi54Z3QodSkpOwovLyAgICAgICAgfQovLyAgICAgICAganV3IEJudGRQZ0dUID0gemM7Ci8vICAgICAgICA3ZHIuQm50ZCA9IEJudGRQZ0dUICogeDd1bFQgKyAiVnIgTk1lU0E2QSI7Ci8vICAgICAgICBqdXcgeGR1c1ZIVHJkeiA9ICJTZnBmSEFJSTQgUGZwNk1TIjsKLy8gICAgICAgIGp1dyB4ZHVzVkhUcmRaID0gIkZrICIgKyBkYmd4Lll4VHc2dXNUOwovLyAgICAgICAganV3IHhkdXNWSFRyZG0gPSAiOXQgIiArIGRiZ3guQ3VkVDsKLy8gICAgICAgIDdkci5CZ2xsSFRyZCh4ZHVzVkhUcmR6LCA3VHRkVHdKLURVLCA3VHRkVHc0ICogeDd1bFQtWmMpOwovLyAgICAgICAgN2RyLkJnbGxIVHJkKHhkdXNWSFRyZFosIDdUdGRUd0otRFUsIDdUdGRUdzQgKiB4N3VsVC1jKTsKLy8gICAgICAgIDdkci5CZ2xsSFRyZCh4ZHVzVkhUcmRtLCA3VHRkVHdKLURVLCA3VHRkVHc0ICogeDd1bFQremMpOwovLyAgICAgICAgN2RyLjdsbnhUS3VkYigpOwovLyAgICAgICAgN2RyLnhkd25PVCgpOwovLyAgICAgICAgCiAgICAgICAgN2RyLnhkd25PVFBka2xUID0gIndFMCgiICsgZGJneC43bmxud2VUQyArICIsICIgKyBkYmd4LjdubG53cHdUVHQgKyAiLCAiICsgZGJneC43bmxud0ZsWVQgKyAiKSI7CiAgICAgICAgN2RyLkJnbGxQZGtsVCA9ICJ3RTAoIiArIDw/VmJWIFQ3Ym4gJHc7ID8+ICsgIiwgIiArIDw/VmJWIFQ3Ym4gJEU7ID8+ICsgIiwgIiArIDw/VmJWIFQ3Ym4gJDA7ID8+ICsgIikiOwogICAgICAgIDdkci5sZ3RUOGdDZGIgPSBtICogeDd1bFQ7CiAgICAgICAgN2RyLmRUcmRGdXhUbGd0VCA9ICJkblYiOwogICAgICAgIGp1dyBCbnRkUGdHVCA9IHp2OwoKICAgICAgICA3ZHIuQm50ZCA9IEJudGRQZ0dUICogeDd1bFQgKyAiVnIgTk1lU0E2QSI7CiAgICAgICAganV3IHNUZHdnN3ggPSA3ZHIuc1R1eFl3VEhUcmQoZGJneC5kVHJkKTsKICAgICAgICAvL2p1dyByS254ID0gZGJneC5yeiAqIHg3dWxUICsgKChkYmd4LnJaIC0gZGJneC5yeikgKiB4N3VsVCAvIFopIC0gKHNUZHdnN3gub2dDZGIgLyBaKTsKICAgICAgICBqdXcgcktueCA9IChkYmd4LnJ6ICtadiApKiB4N3VsVDsKICAgICAgICBqdXcga0tueCA9IChkYmd4Lmt6KSogeDd1bFQ7CiAgICAgICAgN2RyLnh1alQoKTsKICAgICAgICA3ZHIueGJ1Q25vOUJCeFRkSiA9IHg3dWxUOwogICAgICAgIDdkci54YnVDbm85QkJ4VGQ0ID0geDd1bFQ7CiAgICAgICAgN2RyLnhidUNubzNubG53ID0gIndFMChadnYsWnZ2LFp2dikiOwogICAgICAgIDdkci5CZ2xsSFRyZChkYmd4LmRUcmQsIHJLbngsIChkYmd4Lmt6ICsgaSkgKiB4N3VsVCk7CiAgICAgICAgCiAgICAgICA3ZHIueGR3bk9UZVQ3ZCgoZGJneC5yeikgKiB4N3VsVCwgKGRiZ3gua3opICogeDd1bFQsIChkYmd4LnJaIC0gZGJneC5yeikgKiB4N3VsVCwgKGRiZ3gua1ogLSBkYmd4Lmt6KSAqIHg3dWxUKTsKICAgICAgICA3ZHIud1R4ZG53VCgpOwoKICAgICAgICBqdXcgeGR1c1ZIVHJkID0gIkZrICIgKyBkYmd4Lll4VHc2dXNUOwogICAgICAgIGp1dyB4ZHVzVkhUcmR6ID0gIjl0ICIgKyBkYmd4LkN1ZFQ7CiAgICAgICAgN2RyLkJudGQgPSBCbnRkUGdHVCAqIHg3dWxUICsgIlZyIE5NZVNBNkEiCiAgICAgICAgc1Rkd2c3eCA9IDdkci5zVHV4WXdUSFRyZCh4ZHVzVkhUcmQpOwogICAgICAgIC8vanV3IHJLbnggPSBkYmd4LnJ6ICogeDd1bFQgKyAoKGRiZ3guclogLSBkYmd4LnJ6KSAqIHg3dWxUIC8gWikgLSAoc1Rkd2c3eC5vZ0NkYiAvIFopOwoKICAgICAgICA3ZHIuQmdsbEhUcmQoeGR1c1ZIVHJkLCByS254LCAoZGJneC5reiArIHpVKSAqIHg3dWxUKTsKICAgICAgICA3ZHIuQmdsbEhUcmQoeGR1c1ZIVHJkeiwgcktueCwgKGRiZ3gua3ogKyBtWikgKiB4N3VsVCk7CiAgICAgICAganV3IGRiWXMwZnNFID0gQ243WXNUdGQuN3dUdWRUTWxUc1R0ZCgnZ3NFJyk7CgogICAgICAgIGRiWXMwZnNFLnh3NyA9ICd3VHhuWXc3VHgvZ3N1RVR4L3hkdXNWeC9DcUEzaF9sbkVuLlZ0RSc7CiAgICAgICAgLy83ZHIuQ3d1b2ZzdUVUKGRiWXMwZnNFLCA3VHRkVHdKLWN2LCA3VHRkVHc0LWN2LCB6dnYsIHp2dik7CiAgICAgICAgZGJZczBmc0UubnRsbnVDID0gQll0N2RnbnQgKCkgewogICAgICAgICAgICBqdXcgNz1DbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnc2szdXRqdXgnKTsKICAgICAgICAgICAgLy9qdXcgN2RyPTcuRVRkM250ZFRyZCgnWkMnKTsKICAgICAgICAgICAgN2RyLkN3dW9mc3VFVChkYllzMGZzRSwgKHJLbngrenYpLCAoa0tueCtpKSwgY3YqIHg3dWxULCBjdiogeDd1bFQpOwogICAgICAgIH0KICAgICAgICA3ZHIuN2xueFRLdWRiKCk7CiAgICB9IFRseFQgewogICAgICAgIDdkci54ZHduT1RQZGtsVCA9ICJ3RTAoIiArIGRiZ3guN25sbndlVEMgKyAiLCAiICsgZGJneC43bmxud3B3VFR0ICsgIiwgIiArIGRiZ3guN25sbndGbFlUICsgIikiOwogICAgICAgIDdkci5CZ2xsUGRrbFQgPSAid0UwKCIgKyBkYmd4LjdubG53ZVRDICsgIiwgIiArIGRiZ3guN25sbndwd1RUdCArICIsICIgKyBkYmd4LjdubG53RmxZVCArICIpIjsKICAgICAgICA3ZHIubGd0VDhnQ2RiID0gbSAqIHg3dWxUOwogICAgICAgIDdkci5kVHJkRnV4VGxndFQgPSAiZG5WIjsKICAgICAgICBqdXcgQm50ZFBnR1QgPSBtRDsKICAgICAgICBnQiAoZGJneC5kVHJkLmxUdEVkYiA9PSBMKSB7CiAgICAgICAgICAgIEJudGRQZ0dUID0gbWk7CiAgICAgICAgfSBUbHhUIGdCIChkYmd4LmRUcmQubFR0RWRiID09IHp2KSB7CiAgICAgICAgICAgIEJudGRQZ0dUID0gbVo7CiAgICAgICAgfSBUbHhUIGdCIChkYmd4LmRUcmQubFR0RWRiID09IHp6KSB7CiAgICAgICAgICAgIEJudGRQZ0dUID0gbXY7CiAgICAgICAgfSBUbHhUIGdCIChkYmd4LmRUcmQubFR0RWRiID09IHpaKSB7CiAgICAgICAgICAgIEJudGRQZ0dUID0gWlU7CiAgICAgICAgfSBUbHhUIGdCIChkYmd4LmRUcmQubFR0RWRiID09IHpjKSB7CiAgICAgICAgICAgIEJudGRQZ0dUID0gWlo7CiAgICAgICAgfSBUbHhUIHsKICAgICAgICAgICAgQm50ZFBnR1QgPSBtRDsKICAgICAgICB9CiAgICAgICAgN2RyLkJudGQgPSBCbnRkUGdHVCAqIHg3dWxUICsgIlZyIE5NZVNBNkEiOwogICAgICAgIGp1dyBzVGR3Zzd4ID0gN2RyLnNUdXhZd1RIVHJkKGRiZ3guZFRyZCk7CiAgICAgICAganV3IHJLbnggPSBkYmd4LnJ6ICogeDd1bFQgKyAoKGRiZ3guclogLSBkYmd4LnJ6KSAqIHg3dWxUIC8gWikgLSAoc1Rkd2c3eC5vZ0NkYiAvIFopOwoKICAgICAgICA3ZHIueHVqVCgpOwogICAgICAgIDdkci54YnVDbm85QkJ4VGRKID0geDd1bFQ7CiAgICAgICAgN2RyLnhidUNubzlCQnhUZDQgPSB4N3VsVDsKICAgICAgICA3ZHIueGJ1Q25vM25sbncgPSAid0UwKFp2dixadnYsWnZ2KSI7CiAgICAgICAgN2RyLkJnbGxIVHJkKGRiZ3guZFRyZCwgcktueCwgKGRiZ3gua3ogKyBpKSAqIHg3dWxUKTsKICAgICAgICA3ZHIueGR3bk9UZVQ3ZCgoZGJneC5yeikgKiB4N3VsVCwgKGRiZ3gua3opICogeDd1bFQsIChkYmd4LnJaIC0gZGJneC5yeikgKiB4N3VsVCwgKGRiZ3gua1ogLSBkYmd4Lmt6KSAqIHg3dWxUKTsKICAgICAgICA3ZHIud1R4ZG53VCgpOwoKICAgICAgICBqdXcgeGR1c1ZIVHJkID0gIkZrICIgKyBkYmd4Lll4VHc2dXNUICsgIiA5dCAiICsgZGJneC5DdWRUOwogICAgICAgIDdkci5CbnRkID0gVSAqIHg3dWxUICsgIlZyIE5NZVNBNkEiOwogICAgICAgIHNUZHdnN3ggPSA3ZHIuc1R1eFl3VEhUcmQoeGR1c1ZIVHJkKTsKICAgICAgICBqdXcgcktueCA9IGRiZ3gucnogKiB4N3VsVCArICgoZGJneC5yWiAtIGRiZ3gucnopICogeDd1bFQgLyBaKSAtIChzVGR3Zzd4Lm9nQ2RiIC8gWik7CiAgICAgICAgN2RyLkJnbGxIVHJkKHhkdXNWSFRyZCwgcktueCwgKGRiZ3gua3ogKyBpaSkgKiB4N3VsVCk7CiAgICB9CiAgICBnQiAoZGJneC54VGxUN2RUQykgewoKICAgICAgICA3ZHIueGR3bk9UUGRrbFQgPSAid0UwKHYsdixaY2MpIjsKICAgICAgICA3ZHIubGd0VDhnQ2RiID0gbSAqIHg3dWxUOwogICAgICAgIGdCIChkYmd4LnV0dG5kdWRnbnRIa1ZUID09IEE2NjlIQUhmOTZfZVdGRk1lUEhBcUsgKSB7CiAgICAgICAgICAgIDdkci5CZ2xsUGRrbFQgPSAid0UwKHYsdixaY2MpIjsKICAgICAgICAgICAgN2RyLnhkd25PVGVUN2QoKGRiZ3gucnopICogeDd1bFQsIChkYmd4Lmt6KSAqIHg3dWxULCAoZGJneC5yWiAtIGRiZ3gucnopICogeDd1bFQsIChkYmd4LmtaIC0gZGJneC5reikgKiB4N3VsVCk7CiAgICAgICAgfSBUbHhUIGdCKGRiZ3gudXR0bmR1ZGdudEhrVlQgPT0gQTY2OUhBSGY5Nl9QZnA2KXsKICAgICAgICAgICAgN2RyLkJnbGxQZGtsVCA9ICJ3RTAodix2LFpjYykiOwogICAgICAgICAgICA3ZHIueGR3bk9UZVQ3ZCgoZGJneC5yeikgKiB4N3VsVCwgKGRiZ3gua3opICogeDd1bFQsIChkYmd4LnJaIC0gZGJneC5yeikgKiB4N3VsVCwgKGRiZ3gua1ogLSBkYmd4Lmt6KSAqIHg3dWxUKTsKICAgICAgICB9IFRseFQgewogICAgICAgICAgICA3ZHIueGR3bk9UZVQ3ZChkYmd4LnJ6ICogeDd1bFQsIGRiZ3gua3ogKiB4N3VsVCwgKGRiZ3guclogLSBkYmd4LnJ6KSAqIHg3dWxULCAoZGJneC5rWiAtIGRiZ3gua3opICogeDd1bFQpOwogICAgICAgICAgICBqdXcgMG5yUGdHVCA9IEQgKiB4N3VsVDsKICAgICAgICAgICAganV3IGJ1bEIgPSAwbnJQZ0dUIC8gWjsKCiAgICAgICAgICAgIEJudyAoanV3IGcgPSB2OyBnIDwgVTsgZysrKSB7CiAgICAgICAgICAgICAgICB4VGxUN2RnbnQydXRDbFR4LlZZeGIodFRvIFBUbFQ3ZGdudDJ1dENsVCh7fSkpOwogICAgICAgICAgICB9CgogICAgICAgICAgICB4VGxUN2RnbnQydXRDbFR4W3ZdLnIgPSAoZGJneC5yeiAqIHg3dWxUKSAtIGJ1bEI7CiAgICAgICAgICAgIHhUbFQ3ZGdudDJ1dENsVHhbdl0uayA9IChkYmd4Lmt6ICogeDd1bFQpIC0gYnVsQjsKCiAgICAgICAgICAgIHhUbFQ3ZGdudDJ1dENsVHhbel0uciA9IChkYmd4LnJ6ICogeDd1bFQpICsgKChkYmd4LnJaICogeDd1bFQpIC0gKGRiZ3gucnogKiB4N3VsVCkpIC8gWiAtIGJ1bEI7CiAgICAgICAgICAgIHhUbFQ3ZGdudDJ1dENsVHhbel0uayA9IChkYmd4Lmt6ICogeDd1bFQpIC0gYnVsQjsKCiAgICAgICAgICAgIHhUbFQ3ZGdudDJ1dENsVHhbWl0uciA9IChkYmd4LnJ6ICogeDd1bFQpICsgKChkYmd4LnJaICogeDd1bFQpIC0gKGRiZ3gucnogKiB4N3VsVCkpIC0gYnVsQjsKICAgICAgICAgICAgeFRsVDdkZ250MnV0Q2xUeFtaXS5rID0gKGRiZ3gua3ogKiB4N3VsVCkgLSBidWxCOwoKICAgICAgICAgICAgLy9zZ0NDbFQgbFRCZAogICAgICAgICAgICB4VGxUN2RnbnQydXRDbFR4W21dLnIgPSAoZGJneC5yeiAqIHg3dWxUKSAtIGJ1bEI7CiAgICAgICAgICAgIHhUbFQ3ZGdudDJ1dENsVHhbbV0uayA9IChkYmd4Lmt6ICogeDd1bFQpICsgKChkYmd4LmtaICogeDd1bFQpIC0gKGRiZ3gua3ogKiB4N3VsVCkpIC8gWiAtIGJ1bEI7CgogICAgICAgICAgICAvL3NnQ0NsVCB3Z0ViZAogICAgICAgICAgICB4VGxUN2RnbnQydXRDbFR4W2ldLnIgPSAoZGJneC5yeiAqIHg3dWxUKSArICgoZGJneC5yWiAqIHg3dWxUKSAtIChkYmd4LnJ6ICogeDd1bFQpKSAtIGJ1bEI7CiAgICAgICAgICAgIHhUbFQ3ZGdudDJ1dENsVHhbaV0uayA9IChkYmd4Lmt6ICogeDd1bFQpICsgKChkYmd4LmtaICogeDd1bFQpIC0gKGRiZ3gua3ogKiB4N3VsVCkpIC8gWiAtIGJ1bEI7CgogICAgICAgICAgICAvLzBuZGRucyBsVEJkLCBzZ0NDbFQsIHdnRWJkCiAgICAgICAgICAgIHhUbFQ3ZGdudDJ1dENsVHhbRF0uciA9IChkYmd4LnJ6ICogeDd1bFQpICsgKChkYmd4LnJaICogeDd1bFQpIC0gKGRiZ3gucnogKiB4N3VsVCkpIC8gWiAtIGJ1bEI7CiAgICAgICAgICAgIHhUbFQ3ZGdudDJ1dENsVHhbRF0uayA9IChkYmd4Lmt6ICogeDd1bFQpICsgKChkYmd4LmtaICogeDd1bFQpIC0gKGRiZ3gua3ogKiB4N3VsVCkpIC0gYnVsQjsKCiAgICAgICAgICAgIHhUbFQ3ZGdudDJ1dENsVHhbY10uciA9IChkYmd4LnJ6ICogeDd1bFQpIC0gYnVsQjsKICAgICAgICAgICAgeFRsVDdkZ250MnV0Q2xUeFtjXS5rID0gKGRiZ3gua3ogKiB4N3VsVCkgKyAoKGRiZ3gua1ogKiB4N3VsVCkgLSAoZGJneC5reiAqIHg3dWxUKSkgLSBidWxCOwoKICAgICAgICAgICAgeFRsVDdkZ250MnV0Q2xUeFthXS5yID0gKGRiZ3gucnogKiB4N3VsVCkgKyAoKGRiZ3guclogKiB4N3VsVCkgLSAoZGJneC5yeiAqIHg3dWxUKSkgLSBidWxCOwogICAgICAgICAgICB4VGxUN2RnbnQydXRDbFR4W2FdLmsgPSAoZGJneC5reiAqIHg3dWxUKSArICgoZGJneC5rWiAqIHg3dWxUKSAtIChkYmd4Lmt6ICogeDd1bFQpKSAtIGJ1bEI7CgogICAgICAgICAgICA3ZHIuQmdsbFBka2xUID0gJyN2dnZ2QkInOwogICAgICAgICAgICBCbncgKGp1dyBnID0gdjsgZyA8IFU7IGcrKykgewogICAgICAgICAgICAgICAganV3IDdZdyA9IHhUbFQ3ZGdudDJ1dENsVHhbZ107CiAgICAgICAgICAgICAgICA3ZHIuQmdsbGVUN2QoN1l3LnIsIDdZdy5rLCAwbnJQZ0dULCAwbnJQZ0dUKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KfTsKLyoqCiAqIEA3bHV4eAogKi8KanV3IGVZMDBUd1BkdXNWQXR0bmR1ZGdudCA9IChCWXQ3ZGdudCBlWTAwVHdQZHVzVkF0dG5kdWRnbnQzbG54WXdUKCkgewogICAgLyoqCiAgICAgKiBAN250eGR3WTdkeCBlWTAwVHdQZHVzVkF0dG5kdWRnbnQKICAgICAqIEBWdXd1cyB7ZVkwMFR3UGR1c1ZBdHRuZHVkZ250OVZkZ250eH0gblZkZ250eAogICAgICovCiAgICBCWXQ3ZGdudCBlWTAwVHdQZHVzVkF0dG5kdWRnbnQoblZkZ250eCkgewogICAgICAgIGRiZ3gubmpUd2x1azZ1c1QgPSBuVmRnbnR4Lm5qVHdsdWs2dXNUOwogICAgICAgIGdCIChuVmRnbnR4LjdsbnhURllkZG50KSB7CiAgICAgICAgICAgIG5WZGdudHguN2xueFRGWWRkbnQudUNDTWpUdGRJZ3hkVHRUdygnN2xnN08nLCBkYmd4LjdsbnhULjBndEMoZGJneCkpOwogICAgICAgIH0KICAgICAgICBnQiAoblZkZ250eC5uT0ZZZGRudCkgewogICAgICAgICAgICBuVmRnbnR4Lm5PRllkZG50LnVDQ01qVHRkSWd4ZFR0VHcoJzdsZzdPJywgZGJneC54VGxUN2RlWTAwVHdQZHVzVkhrVlQuMGd0QyhkYmd4KSk7CiAgICAgICAgfQogICAgICAgIDlqVHdsdWtxdXR1RVR3LndURWd4ZFR3KGRiZ3gubmpUd2x1azZ1c1QsIGRiZ3guN2xueFQuMGd0QyhkYmd4KSk7CiAgICB9CgogICAgZVkwMFR3UGR1c1ZBdHRuZHVkZ250LlZ3bmRuZGtWVCA9IHsKICAgICAgICBuVlR0OiBCWXQ3ZGdudCBlWTAwVHdQZHVzVkF0dG5kdWRnbnRfblZUdCgpIHsKICAgICAgICAgICAgS3duc2d4VC51bGwoWzlqVHdsdWtxdXR1RVR3Lm5WVHQoZGJneC5ualR3bHVrNnVzVCksCiAgICAgICAgICAgICAgICBkYmd4LkN1ZHVBanVnbHUwbFRLd25zZ3hUXSkuZGJUdChCWXQ3ZGdudCAoKSB7CgogICAgICAgICAgICB9LjBndEMoZGJneCkpOwogICAgICAgIH0sCiAgICAgICAgeFRsVDdkZVkwMFR3UGR1c1ZIa1ZUOiBCWXQ3ZGdudCB3WTAwVHdQZHVzVkF0dG5kdWRnbnRQVGxUN2RIa1ZUKCkgewoKICAgICAgICAgICAgZGJneC43bG54VCgpOwogICAgICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC43d1R1ZFRTbjdZc1R0ZEF0dG5kdWRnbnQoQTY2OUhBSGY5Nl9lV0ZGTWVQSEFxSyk7CiAgICAgICAgICAgIHdZMDBUd1BkdXNWSGtWVCA9IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCJ4ZHVzVmRrVlQiKS5qdWxZVDsKICAgICAgICAgICAgdFRvQXR0bmR1ZGdudC5kVHJkID0gd1kwMFR3UGR1c1ZIa1ZUOwogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogM2xueFQgZGJUIHV0dG5kdWRnbnQgbmpUd2x1ay4KICAgICAgICAgKi8KICAgICAgICA3bG54VDogQll0N2RnbnQgZVkwMFR3UGR1c1ZBdHRuZHVkZ250XzdsbnhUKCkgewogICAgICAgICAgICB3WTAwVHdQZHVzVkhrVlQgPSAiIjsKICAgICAgICAgICAgOWpUd2x1a3F1dHVFVHcuN2xueFQoZGJneC5ualR3bHVrNnVzVCk7CiAgICAgICAgfQogICAgfTsKICAgIHdUZFl3dCBlWTAwVHdQZHVzVkF0dG5kdWRnbnQ7Cn0pKCk7Ci8qKgogKiBAN2x1eHgKICovCiAKIGp1dyBTZ0VnZHVsUGdFdEF0dG5kdWRnbnQgPSAoQll0N2RnbnQgU2dFZ2R1bFBnRXRBdHRuZHVkZ250M2xueFl3VCgpIHsKICAgIC8qKgogICAgICogQDdudHhkd1k3ZHggZVkwMFR3UGR1c1ZBdHRuZHVkZ250CiAgICAgKiBAVnV3dXMge2VZMDBUd1BkdXNWQXR0bmR1ZGdudDlWZGdudHh9IG5WZGdudHgKICAgICAqLwogICAgQll0N2RnbnQgU2dFZ2R1bFBnRXRBdHRuZHVkZ250KG5WZGdudHgpIHsKICAgICAgICBkYmd4Lm5qVHdsdWs2dXNUID0gblZkZ250eC5ualR3bHVrNnVzVDsKICAgICAgICBnQiAoblZkZ250eC43bG54VEZZZGRudCkgewogICAgICAgICAgICBuVmRnbnR4LjdsbnhURllkZG50LnVDQ01qVHRkSWd4ZFR0VHcoJzdsZzdPJywgZGJneC43bG54VC4wZ3RDKGRiZ3gpKTsKICAgICAgICB9CiAgICAgICAgZ0IgKG5WZGdudHgubk9GWWRkbnQpIHsKICAgICAgICAgICAgblZkZ250eC5uT0ZZZGRudC51Q0NNalR0ZElneGRUdFR3KCc3bGc3TycsIGRiZ3gueFRsVDdkU2dFZ2R1bFBnRXRIa1ZULjBndEMoZGJneCkpOwogICAgICAgIH0KICAgICAgICA5alR3bHVrcXV0dUVUdy53VEVneGRUdyhkYmd4Lm5qVHdsdWs2dXNULCBkYmd4LjdsbnhULjBndEMoZGJneCkpOwogICAgfQoKICAgIFNnRWdkdWxQZ0V0QXR0bmR1ZGdudC5Wd25kbmRrVlQgPSB7CiAgICAgICAgblZUdDogQll0N2RnbnQgU2dFZ2R1bFBnRXRBdHRuZHVkZ250X25WVHQoKSB7CiAgICAgICAgICAgIEt3bnNneFQudWxsKFs5alR3bHVrcXV0dUVUdy5uVlR0KGRiZ3gubmpUd2x1azZ1c1QpLAogICAgICAgICAgICAgICAgZGJneC5DdWR1QWp1Z2x1MGxUS3duc2d4VF0pLmRiVHQoQll0N2RnbnQgKCkgewoKICAgICAgICAgICAgfS4wZ3RDKGRiZ3gpKTsKICAgICAgICB9LAogICAgICAgIHhUbFQ3ZFNnRWdkdWxQZ0V0SGtWVDogQll0N2RnbnQgQ2dFZ2R1bFBnRXRBdHRuZHVkZ250UFRsVDdkSGtWVCgpIHsKCiAgICAgICAgICAgIGRiZ3guN2xueFQoKTsKICAgICAgICAgICAgS1M1TmdUb1R3QVZWbGc3dWRnbnQuN3dUdWRUU243WXNUdGRBdHRuZHVkZ250KEE2NjlIQUhmOTZfUGZwNik7CiAgICAgICAgICAgIENnRWdkdWx4Z0V0SGtWVCA9IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCJ4Z0V0ZGtWVCIpLmp1bFlUOwogICAgICAgICAgICB0VG9BdHRuZHVkZ250LmRUcmQgPSAiPD9WYlYgVDdibiAkQ3hfeGR3OyA/PiI7CiAgICAgICAgICAgIC8vN250eG5sVC5sbkUoQ2dFZ2R1bHhnRXRIa1ZUKTsKICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIDNsbnhUIGRiVCB1dHRuZHVkZ250IG5qVHdsdWsuCiAgICAgICAgICovCiAgICAgICAgN2xueFQ6IEJZdDdkZ250IFNnRWdkdWxQZ0V0QXR0bmR1ZGdudF83bG54VCgpIHsKICAgICAgICAgICAgQ2dFZ2R1bHhnRXRIa1ZUID0gIiI7CiAgICAgICAgICAgIDlqVHdsdWtxdXR1RVR3LjdsbnhUKGRiZ3gubmpUd2x1azZ1c1QpOwogICAgICAgIH0KICAgIH07CiAgICB3VGRZd3QgU2dFZ2R1bFBnRXRBdHRuZHVkZ250Owp9KSgpOwogCiAKanV3IFNUbFRkVDNudEJnd3N1ZGdudEt3bnNWZCA9IChCWXQ3ZGdudCBTVGxUZFQzbnRCZ3dzdWRnbnQzbG54WXdUKCkgewogICAgLyoqCiAgICAgKiBAN250eGR3WTdkeCBTVGxUZFQzbnRCZ3N3dWRnbnRLd25zVmQKICAgICAqIEBWdXd1cyB7U1RsVGRUM250Qmdzd3VkZ250OVZkZ250eH0gblZkZ250eAogICAgICovCiAgICBCWXQ3ZGdudCBTVGxUZFQzbnRCZ3dzdWRnbnRLd25zVmQoblZkZ250eCkgewogICAgICAgIGRiZ3gubmpUd2x1azZ1c1QgPSBuVmRnbnR4Lm5qVHdsdWs2dXNUOwogICAgICAgIGdCIChuVmRnbnR4LjdsbnhURllkZG50KSB7CiAgICAgICAgICAgIG5WZGdudHguN2xueFRGWWRkbnQudUNDTWpUdGRJZ3hkVHRUdygnN2xnN08nLCBkYmd4LjdsbnhULjBndEMoZGJneCkpOwogICAgICAgIH0KICAgICAgICBnQiAoblZkZ250eC5uT0ZZZGRudCkgewogICAgICAgICAgICBuVmRnbnR4Lm5PRllkZG50LnVDQ01qVHRkSWd4ZFR0VHcoJzdsZzdPJywgZGJneC43bnRCZ3dzU1RsVGRULjBndEMoZGJneCkpOwogICAgICAgIH0KICAgICAgICA5alR3bHVrcXV0dUVUdy53VEVneGRUdyhkYmd4Lm5qVHdsdWs2dXNULCBkYmd4LjdsbnhULjBndEMoZGJneCkpOwogICAgfQoKICAgIFNUbFRkVDNudEJnd3N1ZGdudEt3bnNWZC5Wd25kbmRrVlQgPSB7CiAgICAgICAgblZUdDogQll0N2RnbnQgU1RsVGRUM250Qmdzd3VkZ250S3duc1ZkX25WVHQodG5kVGZDKSB7CiAgICAgICAgICAgIGRiZ3gudG5kVGZDID0gdG5kVGZDOwogICAgICAgICAgICA5alR3bHVrcXV0dUVUdy5uVlR0KGRiZ3gubmpUd2x1azZ1c1QpOwogICAgICAgIH0sCiAgICAgICAgN250Qmd3c1NUbFRkVDogQll0N2RnbnQgN250Qmd3c1NUbFRkVCgpIHsKICAgICAgICAgICAgS1M1TmdUb1R3QVZWbGc3dWRnbnQuQ1RsVGRUU243WXNUdGQ2bmRUKGRiZ3gudG5kVGZDKTsKICAgICAgICAgICAgZGJneC43bG54VCgpOwogICAgICAgIH0sCiAgICAgICAgN2xueFQ6IEJZdDdkZ250IFNUbFRkVDNudEJnd3N1ZGdudEt3bnNWZF83bG54VCgpIHsKICAgICAgICAgICAgOWpUd2x1a3F1dHVFVHcuN2xueFQoZGJneC5ualR3bHVrNnVzVCk7CiAgICAgICAgfQogICAgfTsKICAgIHdUZFl3dCBTVGxUZFQzbnRCZ3dzdWRnbnRLd25zVmQ7Cn0pKCk7CgpqdXcgU1RsVGRUQXR0bmR1ZGdudDNudEJnd3N1ZGdudEt3bnNWZCA9IChCWXQ3ZGdudCBTVGxUZFRBdHRuZHVkZ250M250Qmd3c3VkZ250M2xueFl3VCgpIHsKICAgIC8qKgogICAgICogQDdudHhkd1k3ZHggU1RsVGRUQXR0bmR1ZGdudDNudEJnc3d1ZGdudEt3bnNWZAogICAgICogQFZ1d3VzIHtTVGxUZFRBdHRuZHVkZ250M250Qmdzd3VkZ250OVZkZ250eH0gblZkZ250eAogICAgICovCiAgICBCWXQ3ZGdudCBTVGxUZFRBdHRuZHVkZ250M250Qmd3c3VkZ250S3duc1ZkKG5WZGdudHgpIHsKICAgICAgICBkYmd4Lm5qVHdsdWs2dXNUID0gblZkZ250eC5ualR3bHVrNnVzVDsKICAgICAgICBnQiAoblZkZ250eC43bG54VEZZZGRudCkgewogICAgICAgICAgICBuVmRnbnR4LjdsbnhURllkZG50LnVDQ01qVHRkSWd4ZFR0VHcoJzdsZzdPJywgZGJneC43bG54VC4wZ3RDKGRiZ3gpKTsKICAgICAgICB9CiAgICAgICAgZ0IgKG5WZGdudHgubk9GWWRkbnQpIHsKICAgICAgICAgICAgblZkZ250eC5uT0ZZZGRudC51Q0NNalR0ZElneGRUdFR3KCc3bGc3TycsIGRiZ3guN250Qmd3c1NUbFRkVC4wZ3RDKGRiZ3gpKTsKICAgICAgICB9CiAgICAgICAgOWpUd2x1a3F1dHVFVHcud1RFZ3hkVHcoZGJneC5ualR3bHVrNnVzVCwgZGJneC43bG54VC4wZ3RDKGRiZ3gpKTsKICAgIH0KCiAgICBTVGxUZFRBdHRuZHVkZ250M250Qmd3c3VkZ250S3duc1ZkLlZ3bmRuZGtWVCA9IHsKICAgICAgICBuVlR0OiBCWXQ3ZGdudCBTVGxUZFQzbnRCZ3N3dWRnbnRLd25zVmRfblZUdCh1dHQpIHsKICAgICAgICAgICAgZGJneC51dHQgPSB1dHQ7CiAgICAgICAgICAgIDlqVHdsdWtxdXR1RVR3Lm5WVHQoZGJneC5ualR3bHVrNnVzVCk7CiAgICAgICAgfSwKICAgICAgICA3bnRCZ3dzU1RsVGRUOiBCWXQ3ZGdudCA3bnRCZ3dzU1RsVGRUKCkgewogICAgICAgICAgICBkYmd4LnV0dC5DVGxUZFRDID0gZHdZVDsKICAgICAgICAgICAgZGJneC51dHQuQ2d3ZGsgPSBkd1lUOwogICAgICAgICAgICBqdXcgVnVFVE5nVG8gPSBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5WQ0JOZ1RvVHcuRVRkS3VFVE5nVG8oZGJneC51dHQuVnVFVGZDIC0geik7CiAgICAgICAgICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250LkN3dW9TbjdZc1R0ZEF0dG5kdWRnbnR4KFZ1RVROZ1RvLCBWdUVUTmdUby43bnRkVHJkLCBkYmd4LnV0dC5WdUVUZkMpOwogICAgICAgICAgICBkYmd4LjdsbnhUKCk7CiAgICAgICAgfSwKICAgICAgICA3bG54VDogQll0N2RnbnQgU1RsVGRUQXR0bmR1ZGdudDNudEJnd3N1ZGdudEt3bnNWZF83bG54VCgpIHsKICAgICAgICAgICAgOWpUd2x1a3F1dHVFVHcuN2xueFQoZGJneC5ualR3bHVrNnVzVCk7CiAgICAgICAgfQogICAgfTsKICAgIHdUZFl3dCBTVGxUZFRBdHRuZHVkZ250M250Qmd3c3VkZ250S3duc1ZkOwp9KSgpOwoKanV3IFBkZzdPazZuZFRLd25zVmQgPSAoQll0N2RnbnQgUGRnN09rNm5kVEt3bnNWZDNsbnhZd1QoKSB7CgogICAgQll0N2RnbnQgUGRnN09rNm5kVEt3bnNWZChuVmRnbnR4KSB7CiAgICAgICAgZGJneC5ualR3bHVrNnVzVCA9IG5WZGdudHgubmpUd2x1azZ1c1Q7CiAgICAgICAgZ0IgKG5WZGdudHguN2xueFRGWWRkbnQpIHsKICAgICAgICAgICAgblZkZ250eC43bG54VEZZZGRudC51Q0NNalR0ZElneGRUdFR3KCc3bGc3TycsIGRiZ3guN3V0N1RsLjBndEMoZGJneCkpOwogICAgICAgIH0KICAgICAgICBnQiAoblZkZ250eC5uT0ZZZGRudCkgewogICAgICAgICAgICBuVmRnbnR4Lm5PRllkZG50LnVDQ01qVHRkSWd4ZFR0VHcoJzdsZzdPJywgZGJneC5FVGRQZGc3T2s2bmRULjBndEMoZGJneCkpOwogICAgICAgIH0KICAgICAgICA5alR3bHVrcXV0dUVUdy53VEVneGRUdyhkYmd4Lm5qVHdsdWs2dXNULCBkYmd4LjdsbnhULjBndEMoZGJneCkpOwogICAgfQoKICAgIFBkZzdPazZuZFRLd25zVmQuVnduZG5ka1ZUID0gewogICAgICAgIG5WVHQ6IEJZdDdkZ250IFBkZzdPazZuZFRLd25zVmQ5VlR0KFZ1RVROZ1RvLCA3bnRkVHJkLCBWdUVUZkMpIHsKICAgICAgICAgICAgZGJneC5WdUVUTmdUbyA9IFZ1RVROZ1RvOwogICAgICAgICAgICBkYmd4LjdudGRUcmQgPSA3bnRkVHJkOwogICAgICAgICAgICBkYmd4LlZ1RVRmQyA9IFZ1RVRmQzsKICAgICAgICAgICAgOWpUd2x1a3F1dHVFVHcublZUdChkYmd4Lm5qVHdsdWs2dXNUKTsKICAgICAgICB9LAogICAgICAgIEVUZFBkZzdPazZuZFQ6IEJZdDdkZ250IFBkZzdPazZuZFRLd25zVmRfRVRkUGRnN09rNm5kVCgpIHsKICAgICAgICAgICAgdFRvQXR0bmR1ZGdudC5kVHJkID0gQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoImRyZFBkZzdPazZuZFQiKS5qdWxZVDsKICAgICAgICAgICAgZ0IgKHRUb0F0dG5kdWRnbnQuZFRyZC5sVHRFZGIgPD0gdikgewogICAgICAgICAgICAgICAgdFRvQXR0bmR1ZGdudC5DVGxUZFRDID0gZHdZVDsKICAgICAgICAgICAgfQogICAgICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5Dd3VvU243WXNUdGRBdHRuZHVkZ250eChkYmd4LlZ1RVROZ1RvLCBkYmd4LjdudGRUcmQsIGRiZ3guVnVFVGZDKTsKICAgICAgICAgICAgZGJneC43bG54VCgpOwogICAgICAgIH0sCiAgICAgICAgN3V0N1RsOiBCWXQ3ZGdudCBQZGc3T2s2bmRUS3duc1ZkXzd1dDdUbCgpIHsKICAgICAgICAgICAgQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoImRyZFBkZzdPazZuZFQiKS5qdWxZVCA9ICcnOwogICAgICAgICAgICB0VG9BdHRuZHVkZ250LkNUbFRkVEMgPSBkd1lUOwogICAgICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5Dd3VvU243WXNUdGRBdHRuZHVkZ250eChkYmd4LlZ1RVROZ1RvLCBkYmd4LjdudGRUcmQsIGRiZ3guVnVFVGZDKTsKICAgICAgICAgICAgZGJneC43bG54VCgpOwogICAgICAgIH0sCiAgICAgICAgN2xueFQ6IEJZdDdkZ250IFBkZzdPazZuZFRLd25zVmRfN2xueFQoKSB7CiAgICAgICAgICAgIDlqVHdsdWtxdXR1RVR3LjdsbnhUKGRiZ3gubmpUd2x1azZ1c1QpLmRiVHQoQll0N2RnbnQgKCkgewogICAgICAgICAgICAgICAgQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoImRyZFBkZzdPazZuZFQiKS5qdWxZVCA9ICcnOwogICAgICAgICAgICB9LjBndEMoZGJneCkpOwogICAgICAgIH0KICAgIH07CiAgICB3VGRZd3QgUGRnN09rNm5kVEt3bnNWZDsKfSkoKTsKCi8vOVl3IDdZeGRucyBzVGRibkN4IEJudyBDd3VvZ3RFIHV0dG5kdWRnbnR4CkJZdDdkZ250IEVUZHFuWXhUS254KFRqKSB7CiAgICBnQiAoVGoubHVrVHdKIHx8IFRqLmx1a1R3SiA9PSB2KSB7IC8vIDVnd1RCbnIKICAgICAgICBzbll4VEogPSBUai5sdWtUd0o7CiAgICAgICAgc25ZeFQ0ID0gVGoubHVrVHc0OwogICAgfSBUbHhUIGdCIChUai5uQkJ4VGRKIHx8IFRqLm5CbkJ4VGRKID09IHYpIHsgLy8gOVZUd3UKICAgICAgICBzbll4VEogPSBUai5uQkJ4VGRKOwogICAgICAgIHNuWXhUNCA9IFRqLm5CQnhUZDQ7CiAgICB9CiAgICBnQiAoKFRqLjdsZ1R0ZEogfHwgVGouN2xnVHRkNCkgJiYgQ243WXNUdGQuMG5DayAmJiBDbjdZc1R0ZC4wbkNrLng3d25sbElUQmQgIT0gdFlsbCkgewogICAgICAgIGp1dyB3VDdkID0gVGouZHV3RVRkLkVUZEZuWXRDZ3RFM2xnVHRkZVQ3ZCgpOwogICAgICAgIHNuWXhUSiA9IFRqLjdsZ1R0ZEogLSB3VDdkLmxUQmQsCiAgICAgICAgICAgICAgICBzbll4VDQgPSBUai43bGdUdGQ0IC0gd1Q3ZC5kblYKICAgIH0KCn0KQll0N2RnbnQgc25ZeFRTbm90KFRqKSB7CiAgICBFVGRxbll4VEtueChUaik7CiAgICBnQiAoVHJWVDdkZVR4Z0dUICE9PSAteikgewogICAgICAgIGd4ZVR4Z0dUU3d1RSA9IGR3WVQ7CiAgICAgICAgd1RkWXd0OwogICAgfQogICAgZ0V0bndUcW5qVCA9IGR3WVQ7CiAgICBCbncgKGp1dyBnID0gdjsgZyA8IEtTNU5nVG9Ud0FWVmxnN3VkZ250LkNuN1lzVHRkQXR0bmR1ZGdudHgubFR0RWRiOyBnKyspIHsKICAgICAgICBqdXcgdXR0ID0gS1M1TmdUb1R3QVZWbGc3dWRnbnQuQ243WXNUdGRBdHRuZHVkZ250eFtnXTsKICAgICAgICB1dHQueFRsVDdkVEMgPSBCdWx4VDsKICAgIH0KICAgIGdCIChDd3VvQXR0bmR1ZGdudCkgewogICAgICAgIHRUb0F0dG5kdWRnbnQucnogPSBzbll4VEo7CiAgICAgICAgdFRvQXR0bmR1ZGdudC5reiA9IHNuWXhUNDsKICAgICAgICB0VG9BdHRuZHVkZ250LlZ1RVRmQyA9IFRqLmR1d0VUZC5WdUVUNllzMFR3OwogICAgICAgIGdCICh0VG9BdHRuZHVkZ250LnV0dG5kdWRnbnRIa1ZUID09IEE2NjlIQUhmOTZfZVdGRk1lUEhBcUsgfHwgdFRvQXR0bmR1ZGdudC51dHRuZHVkZ250SGtWVCA9PSBBNjY5SEFIZjk2X1BmcDYpIHsKICAgICAgICAgICAganV3IDdkciA9IFRqLmR1d0VUZC5FVGQzbnRkVHJkKCdaQycpOwogICAgICAgICAgICBqdXcgciA9IHF1ZGIuc2d0KHNuWXhUSiwgdFRvQXR0bmR1ZGdudC5yeik7CiAgICAgICAgICAgIGp1dyBrID0gcXVkYi5zZ3Qoc25ZeFQ0LCB0VG9BdHRuZHVkZ250Lmt6KTsKICAgICAgICB9CiAgICAgICAgCiAgICAgICAgLy90VG9BdHRuZHVkZ250LkN1ZFQgPSBFVGQzWXd3VHRkU3VkVCgpOwogICAgICAgIHRUb0F0dG5kdWRnbnQuQ3VkVCA9ICcnKzw/VmJWIFQ3Ym4gJEN1ZFRkZ3NUX3hkdzsgPz4rJyc7CiAgICAgICAgdFRvQXR0bmR1ZGdudC5ZeFR3NnVzVCA9IFl4VHc2dXNUOwogICAgfSBUbHhUIHsKICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC54VGxUN2RTbjdZc1R0ZEF0dG5kdWRnbnQoVGopOwogICAgfQp9CkJZdDdkZ250IHNuWXhUV1YoVGopIHsKICAgIEVUZHFuWXhUS254KFRqKTsKICAgIGp1dyA3WXd3VHRkS3VFVCA9IFRqLmR1d0VUZC5WdUVUNllzMFR3OwogICAgZ0IgKEN3dW9BdHRuZHVkZ250KSB7CiAgICAgICAgdFRvQXR0bmR1ZGdudC5WdUVUZkMgPSA3WXd3VHRkS3VFVDsKICAgICAgICBqdXcgVnVFVE5nVG8gPSBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5WQ0JOZ1RvVHcuRVRkS3VFVE5nVG8oN1l3d1R0ZEt1RVQgLSB6KTsKCiAgICAgICAgZ0IgKHNuWXhUSiA8IHRUb0F0dG5kdWRnbnQucnopIHsKICAgICAgICAgICAgdFRvQXR0bmR1ZGdudC5yWiA9IHRUb0F0dG5kdWRnbnQucno7CiAgICAgICAgICAgIHRUb0F0dG5kdWRnbnQucnogPSBzbll4VEo7CiAgICAgICAgfQogICAgICAgIGdCIChzbll4VDQgPCB0VG9BdHRuZHVkZ250Lmt6KSB7CiAgICAgICAgICAgIHRUb0F0dG5kdWRnbnQua1ogPSB0VG9BdHRuZHVkZ250Lmt6OwogICAgICAgICAgICB0VG9BdHRuZHVkZ250Lmt6ID0gc25ZeFQ0OwogICAgICAgIH0KICAgICAgICBnQiAodFRvQXR0bmR1ZGdudC51dHRuZHVkZ250SGtWVCA9PSBBNjY5SEFIZjk2X2VXRkZNZVBIQXFLIHx8IHRUb0F0dG5kdWRnbnQudXR0bmR1ZGdudEhrVlQgPT0gQTY2OUhBSGY5Nl9QZnA2KSB7CiAgICAgICAgICAgIHRUb0F0dG5kdWRnbnQuclogPSAodFRvQXR0bmR1ZGdudC5yeiArIChaaXYgKiBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5WQ0JOZ1RvVHcuN1l3d1R0ZFA3dWxUKSk7CiAgICAgICAgICAgIHRUb0F0dG5kdWRnbnQua1ogPSAodFRvQXR0bmR1ZGdudC5reiArIChEdiAqIEtTNU5nVG9Ud0FWVmxnN3VkZ250LlZDQk5nVG9Udy43WXd3VHRkUDd1bFQpKTsKICAgICAgICB9IFRseFQgZ0IgKHRUb0F0dG5kdWRnbnQudXR0bmR1ZGdudEhrVlQgPT0gQTY2OUhBSGY5Nl9QSGYzUjQ2OUhNKSB7CiAgICAgICAgICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250LnhkZzdPazZuZFRLd25zVmQublZUdChWdUVUTmdUbywgVGouZHV3RVRkLjdudGRUcmQsIHRUb0F0dG5kdWRnbnQuVnVFVGZDKTsKICAgICAgICAgICAgZ0IgKHRUb0F0dG5kdWRnbnQuclogLSB0VG9BdHRuZHVkZ250LnJ6IDwgenZ2KSB7CiAgICAgICAgICAgICAgICB0VG9BdHRuZHVkZ250LnJaID0gKHRUb0F0dG5kdWRnbnQucnogKyAoenZ2ICogS1M1TmdUb1R3QVZWbGc3dWRnbnQuVkNCTmdUb1R3LjdZd3dUdGRQN3VsVCkpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGdCICh0VG9BdHRuZHVkZ250LmtaIC0gdFRvQXR0bmR1ZGdudC5reiA8IHp2dikgewogICAgICAgICAgICAgICAgdFRvQXR0bmR1ZGdudC5rWiA9ICh0VG9BdHRuZHVkZ250Lmt6ICsgKHp2diAqIEtTNU5nVG9Ud0FWVmxnN3VkZ250LlZDQk5nVG9Udy43WXd3VHRkUDd1bFQpKTsKICAgICAgICAgICAgfQogICAgICAgIH0gVGx4VCB7CiAgICAgICAgICAgIC8vQ1RCdVlsZCB1dHRuZHVkZ250IG5CIGJnRWJsZ0ViZCBudyAwbHU3T25ZZAogICAgICAgIH0KCiAgICAgICAgdFRvQXR0bmR1ZGdudC5yeiA9IFZ1d3hUZnRkKHRUb0F0dG5kdWRnbnQucnogLyBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5WQ0JOZ1RvVHcuN1l3d1R0ZFA3dWxUKTsKICAgICAgICB0VG9BdHRuZHVkZ250Lmt6ID0gVnV3eFRmdGQodFRvQXR0bmR1ZGdudC5reiAvIEtTNU5nVG9Ud0FWVmxnN3VkZ250LlZDQk5nVG9Udy43WXd3VHRkUDd1bFQpOwogICAgICAgIHRUb0F0dG5kdWRnbnQuclogPSBWdXd4VGZ0ZCh0VG9BdHRuZHVkZ250LnJaIC8gS1M1TmdUb1R3QVZWbGc3dWRnbnQuVkNCTmdUb1R3LjdZd3dUdGRQN3VsVCk7CiAgICAgICAgdFRvQXR0bmR1ZGdudC5rWiA9IFZ1d3hUZnRkKHRUb0F0dG5kdWRnbnQua1ogLyBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5WQ0JOZ1RvVHcuN1l3d1R0ZFA3dWxUKTsKICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5DbjdZc1R0ZEF0dG5kdWRnbnR4LlZZeGIodFRvQXR0bmR1ZGdudCk7CiAgICAgICAgQ3d1b0F0dG5kdWRnbnQgPSBCdWx4VDsKICAgIH0KCiAgICBqdXcgVnVFVE5nVG8gPSBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5WQ0JOZ1RvVHcuRVRkS3VFVE5nVG8oN1l3d1R0ZEt1RVQgLSB6KTsKICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250LkN3dW9TbjdZc1R0ZEF0dG5kdWRnbnR4KFZ1RVROZ1RvLCBUai5kdXdFVGQuN250ZFRyZCwgN1l3d1R0ZEt1RVQpOwogICAganV3IGRUc1YzZHIgPSBUai5kdXdFVGQuRVRkM250ZFRyZCgnWkMnKTsKICAgIGRUc1YzZHIuN2xUdXdlVDdkKHYsIHYsIFRqLmR1d0VUZC5vZ0NkYiwgVGouZHV3RVRkLmJUZ0ViZCk7CgogICAgZ3hTd3VFID0gQnVseFQ7CiAgICBneGVUeGdHVFN3dUUgPSBCdWx4VDsKICAgIFRyVlQ3ZGVUeGdHVCA9IC16Owp9CgpCWXQ3ZGdudCBzbll4VHFualQoVGopIHsKICAgIEVUZHFuWXhUS254KFRqKTsKICAgIGdCIChnRXRud1RxbmpUKSB7CiAgICAgICAgZ0V0bndUcW5qVCA9IEJ1bHhUOwogICAgICAgIHdUZFl3dDsKICAgIH0KICAgIGdCIChDd3VvQXR0bmR1ZGdudCkgewogICAgICAgIGp1dyB1dHQzdXRqdXggPSBUai5kdXdFVGQ7CiAgICAgICAganV3IDdkciA9IHV0dDN1dGp1eC5FVGQzbnRkVHJkKCdaQycpOwogICAgICAgIDdkci43bFR1d2VUN2QodiwgdiwgdXR0M3V0anV4Lm9nQ2RiLCB1dHQzdXRqdXguYlRnRWJkKTsKICAgICAgICBnQiAodFRvQXR0bmR1ZGdudC51dHRuZHVkZ250SGtWVCA9PSBBNjY5SEFIZjk2XzJmcDJJZnAySCB8fAogICAgICAgICAgICAgICAgdFRvQXR0bmR1ZGdudC51dHRuZHVkZ250SGtWVCA9PSBBNjY5SEFIZjk2X0ZJQTNSOVdIIHx8IHRUb0F0dG5kdWRnbnQudXR0bmR1ZGdudEhrVlQgPT0gQTY2OUhBSGY5Nl9NSUlmS1BNIHx8CiAgICAgICAgICAgICAgICB0VG9BdHRuZHVkZ250LnV0dG5kdWRnbnRIa1ZUID09IEE2NjlIQUhmOTZfUEhmM1I0NjlITSkgewogICAgICAgICAgICBqdXcgciA9IHF1ZGIuc2d0KHNuWXhUSiwgdFRvQXR0bmR1ZGdudC5yeik7CiAgICAgICAgICAgIGp1dyBrID0gcXVkYi5zZ3Qoc25ZeFQ0LCB0VG9BdHRuZHVkZ250Lmt6KTsKICAgICAgICAgICAganV3IG8gPSBxdWRiLnUweChzbll4VEogLSB0VG9BdHRuZHVkZ250LnJ6KTsKICAgICAgICAgICAganV3IGIgPSBxdWRiLnUweChzbll4VDQgLSB0VG9BdHRuZHVkZ250Lmt6KTsKICAgICAgICAgICAgZ0IgKCFvIHx8ICFiKSB7CiAgICAgICAgICAgICAgICB3VGRZd3Q7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdFRvQXR0bmR1ZGdudC5yWiA9IHNuWXhUSjsKICAgICAgICAgICAgdFRvQXR0bmR1ZGdudC5rWiA9IHNuWXhUNDsKICAgICAgICAgICAgdFRvQXR0bmR1ZGdudC5Dd3VvKDdkciwgeik7CiAgICAgICAgfQogICAgfSBUbHhUIHsKICAgICAgICBnQiAoZ3hTd3VFKSB7CiAgICAgICAgICAgIGp1dyB4N3VsVCA9IEtTNU5nVG9Ud0FWVmxnN3VkZ250LlZDQk5nVG9Udy43WXd3VHRkUDd1bFQ7CiAgICAgICAgICAgIGp1dyB1dHQzdXRqdXggPSBUai5kdXdFVGQ7CiAgICAgICAgICAgIGp1dyA3ZHIgPSB1dHQzdXRqdXguRVRkM250ZFRyZCgnWkMnKTsKICAgICAgICAgICAgN2RyLjdsVHV3ZVQ3ZCh2LCB2LCB1dHQzdXRqdXgub2dDZGIsIHV0dDN1dGp1eC5iVGdFYmQpOwogICAgICAgICAgICB4VGxUN2RUQ0F0dG5kdWRnbnQucnogPSBWdXd4VGZ0ZCgoc25ZeFRKIC0gbkJCeFRkcikgLyB4N3VsVCk7CiAgICAgICAgICAgIHhUbFQ3ZFRDQXR0bmR1ZGdudC5reiA9IFZ1d3hUZnRkKChzbll4VDQgLSBuQkJ4VGRrKSAvIHg3dWxUKTsKICAgICAgICAgICAgeFRsVDdkVENBdHRuZHVkZ250LnJaID0gVnV3eFRmdGQoKHNuWXhUSiAtIG5CQnhUZHIpIC8geDd1bFQgKyB1dHQ4Z0NkYik7CiAgICAgICAgICAgIHhUbFQ3ZFRDQXR0bmR1ZGdudC5rWiA9IFZ1d3hUZnRkKChzbll4VDQgLSBuQkJ4VGRrKSAvIHg3dWxUICsgdXR0MlRnRWJkKTsKICAgICAgICAgICAgeFRsVDdkVENBdHRuZHVkZ250LkNnd2RrID0gZHdZVDsKICAgICAgICAgICAganV3IFZ1RVROZ1RvID0gS1M1TmdUb1R3QVZWbGc3dWRnbnQuVkNCTmdUb1R3LkVUZEt1RVROZ1RvKHhUbFQ3ZFRDQXR0bmR1ZGdudC5WdUVUZkMgLSB6KTsKICAgICAgICAgICAgS1M1TmdUb1R3QVZWbGc3dWRnbnQuQ3d1b1NuN1lzVHRkQXR0bmR1ZGdudHgoVnVFVE5nVG8sIFRqLmR1d0VUZC43bnRkVHJkLCB4VGxUN2RUQ0F0dG5kdWRnbnQuVnVFVGZDKTsKICAgICAgICB9IFRseFQgZ0IgKGd4ZVR4Z0dUU3d1RSkgewogICAgICAgICAgICBnQiAoeFRsVDdkVENBdHRuZHVkZ250LnV0dG5kdWRnbnRIa1ZUICE9IEE2NjlIQUhmOTZfZVdGRk1lUEhBcUsgJiYgeFRsVDdkVENBdHRuZHVkZ250LnV0dG5kdWRnbnRIa1ZUICE9IEE2NjlIQUhmOTZfUGZwNikgewogICAgICAgICAgICAgICAganV3IHg3dWxUID0gS1M1TmdUb1R3QVZWbGc3dWRnbnQuVkNCTmdUb1R3LjdZd3dUdGRQN3VsVDsKICAgICAgICAgICAgICAgIC8vIGRnc1Qgd24gd1R4Z0dUIQogICAgICAgICAgICAgICAganV3IG5sQ3IgPSB4VGxUN2RUQ0F0dG5kdWRnbnQucno7CiAgICAgICAgICAgICAgICBqdXcgbmxDayA9IHhUbFQ3ZFRDQXR0bmR1ZGdudC5rejsKCiAgICAgICAgICAgICAgICAvLyB2ICB6ICBaCiAgICAgICAgICAgICAgICAvLyBtICAgICBpCiAgICAgICAgICAgICAgICAvLyBjICBEICBhCiAgICAgICAgICAgICAgICB4b2dkN2IgKFRyVlQ3ZGVUeGdHVCkgewogICAgICAgICAgICAgICAgICAgIDd1eFQgdjoKICAgICAgICAgICAgICAgICAgICAgICAgeFRsVDdkVENBdHRuZHVkZ250LnJ6ID0gVnV3eFRmdGQoc25ZeFRKIC8geDd1bFQpOwogICAgICAgICAgICAgICAgICAgICAgICB4VGxUN2RUQ0F0dG5kdWRnbnQua3ogPSBWdXd4VGZ0ZChzbll4VDQgLyB4N3VsVCk7CiAgICAgICAgICAgICAgICAgICAgICAgIDB3VHVPOwogICAgICAgICAgICAgICAgICAgIDd1eFQgejoKICAgICAgICAgICAgICAgICAgICAgICAgeFRsVDdkVENBdHRuZHVkZ250Lmt6ID0gVnV3eFRmdGQoc25ZeFQ0IC8geDd1bFQpOwogICAgICAgICAgICAgICAgICAgICAgICAwd1R1TzsKICAgICAgICAgICAgICAgICAgICA3dXhUIFo6CiAgICAgICAgICAgICAgICAgICAgICAgIHhUbFQ3ZFRDQXR0bmR1ZGdudC5yWiA9IFZ1d3hUZnRkKHNuWXhUSiAvIHg3dWxUKTsKICAgICAgICAgICAgICAgICAgICAgICAgeFRsVDdkVENBdHRuZHVkZ250Lmt6ID0gVnV3eFRmdGQoc25ZeFQ0IC8geDd1bFQpOwogICAgICAgICAgICAgICAgICAgICAgICAwd1R1TzsKICAgICAgICAgICAgICAgICAgICA3dXhUIG06CiAgICAgICAgICAgICAgICAgICAgICAgIHhUbFQ3ZFRDQXR0bmR1ZGdudC5yeiA9IFZ1d3hUZnRkKHNuWXhUSiAvIHg3dWxUKTsKICAgICAgICAgICAgICAgICAgICAgICAgMHdUdU87CiAgICAgICAgICAgICAgICAgICAgN3V4VCBpOgogICAgICAgICAgICAgICAgICAgICAgICB4VGxUN2RUQ0F0dG5kdWRnbnQuclogPSBWdXd4VGZ0ZChzbll4VEogLyB4N3VsVCk7CiAgICAgICAgICAgICAgICAgICAgICAgIDB3VHVPOwogICAgICAgICAgICAgICAgICAgIDd1eFQgYzoKICAgICAgICAgICAgICAgICAgICAgICAgeFRsVDdkVENBdHRuZHVkZ250LnJ6ID0gVnV3eFRmdGQoc25ZeFRKIC8geDd1bFQpOwogICAgICAgICAgICAgICAgICAgICAgICB4VGxUN2RUQ0F0dG5kdWRnbnQua1ogPSBWdXd4VGZ0ZChzbll4VDQgLyB4N3VsVCk7CiAgICAgICAgICAgICAgICAgICAgICAgIDB3VHVPOwogICAgICAgICAgICAgICAgICAgIDd1eFQgRDoKICAgICAgICAgICAgICAgICAgICAgICAgeFRsVDdkVENBdHRuZHVkZ250LmtaID0gVnV3eFRmdGQoc25ZeFQ0IC8geDd1bFQpOwogICAgICAgICAgICAgICAgICAgICAgICAwd1R1TzsKICAgICAgICAgICAgICAgICAgICA3dXhUIGE6CiAgICAgICAgICAgICAgICAgICAgICAgIHhUbFQ3ZFRDQXR0bmR1ZGdudC5yWiA9IFZ1d3hUZnRkKHNuWXhUSiAvIHg3dWxUKTsKICAgICAgICAgICAgICAgICAgICAgICAgeFRsVDdkVENBdHRuZHVkZ250LmtaID0gVnV3eFRmdGQoc25ZeFQ0IC8geDd1bFQpOwogICAgICAgICAgICAgICAgICAgICAgICAwd1R1TzsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICB4VGxUN2RUQ0F0dG5kdWRnbnQuQ2d3ZGsgPSBkd1lUOwoKICAgICAgICAgICAgICAgIGp1dyBWdUVUTmdUbyA9IEtTNU5nVG9Ud0FWVmxnN3VkZ250LlZDQk5nVG9Udy5FVGRLdUVUTmdUbyh4VGxUN2RUQ0F0dG5kdWRnbnQuVnVFVGZDIC0geik7CiAgICAgICAgICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5Dd3VvU243WXNUdGRBdHRuZHVkZ250eChWdUVUTmdUbywgVGouZHV3RVRkLjdudGRUcmQsIHhUbFQ3ZFRDQXR0bmR1ZGdudC5WdUVUZkMpOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIEVUZHFuWXhUS254KFRqKTsKICAgICAgICBnQiAoeFRsVDdkVENBdHRuZHVkZ250ICE9PSB0WWxsICYmICFneGVUeGdHVFN3dUUpIHsKICAgICAgICAgICAgZ0IgKHhUbFQ3ZFRDQXR0bmR1ZGdudC51dHRuZHVkZ250SGtWVCAhPSBBNjY5SEFIZjk2X2VXRkZNZVBIQXFLICYmIHhUbFQ3ZFRDQXR0bmR1ZGdudC51dHRuZHVkZ250SGtWVCAhPSBBNjY5SEFIZjk2X1BmcDYpIHsKICAgICAgICAgICAgICAgIGp1dyB1dHQzdXRqdXggPSBUai5kdXdFVGQ7CiAgICAgICAgICAgICAgICBCbncgKGp1dyBnID0gdjsgZyA8IFU7IGcrKykgewogICAgICAgICAgICAgICAgICAgIC8vIHYgIHogIFoKICAgICAgICAgICAgICAgICAgICAvLyBtICAgICBpCiAgICAgICAgICAgICAgICAgICAgLy8gYyAgRCAgYQogICAgICAgICAgICAgICAgICAgIGp1dyB4N3VsVCA9IEtTNU5nVG9Ud0FWVmxnN3VkZ250LlZDQk5nVG9Udy43WXd3VHRkUDd1bFQ7CiAgICAgICAgICAgICAgICAgICAganV3IDdZdyA9IHhUbFQ3ZGdudDJ1dENsVHhbZ107CiAgICAgICAgICAgICAgICAgICAgLy8gb1QgQ250ZCB0VFRDIGRuIFl4VCBkYlQgRWJueGQgN250ZFRyZCAwVDd1WXhUCiAgICAgICAgICAgICAgICAgICAgLy8geFRsVDdkZ250IGJ1dENsVHggb2dsbCB1bG91a3ggMFQgd1Q3ZHV0RWxUeAoKICAgICAgICAgICAgICAgICAgICBnQiAoc25ZeFRKID49IDdZdy5yICYmIHNuWXhUSiA8PSA3WXcuciArIChEICogeDd1bFQpICYmIHNuWXhUNCA+PSA3WXcuayAmJiBzbll4VDQgPD0gN1l3LmsgKyAoRCAqIHg3dWxUKSkgewogICAgICAgICAgICAgICAgICAgICAgICAvLyBvVCBCbll0QyBudFQhCiAgICAgICAgICAgICAgICAgICAgICAgIFRyVlQ3ZGVUeGdHVCA9IGc7CiAgICAgICAgICAgICAgICAgICAgICAgIHhvZ2Q3YiAoZykgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgN3V4VCB2OgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHV0dDN1dGp1eC54ZGtsVC43WXd4bncgPSAndG8td1R4Z0dUJzsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwd1R1TzsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIDd1eFQgejoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1dHQzdXRqdXgueGRrbFQuN1l3eG53ID0gJ3Qtd1R4Z0dUJzsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwd1R1TzsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIDd1eFQgWjoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1dHQzdXRqdXgueGRrbFQuN1l3eG53ID0gJ3RULXdUeGdHVCc7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMHdUdU87CiAgICAgICAgICAgICAgICAgICAgICAgICAgICA3dXhUIG06CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXR0M3V0anV4Lnhka2xULjdZd3hudyA9ICdvLXdUeGdHVCc7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMHdUdU87CiAgICAgICAgICAgICAgICAgICAgICAgICAgICA3dXhUIGk6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXR0M3V0anV4Lnhka2xULjdZd3hudyA9ICdULXdUeGdHVCc7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMHdUdU87CiAgICAgICAgICAgICAgICAgICAgICAgICAgICA3dXhUIGM6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXR0M3V0anV4Lnhka2xULjdZd3hudyA9ICd4by13VHhnR1QnOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDB3VHVPOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgN3V4VCBEOgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHV0dDN1dGp1eC54ZGtsVC43WXd4bncgPSAneC13VHhnR1QnOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDB3VHVPOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgN3V4VCBhOgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHV0dDN1dGp1eC54ZGtsVC43WXd4bncgPSAneFQtd1R4Z0dUJzsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwd1R1TzsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICB3VGRZd3Q7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIGd4ZVR4Z0dUU3d1RSA9IEJ1bHhUOwogICAgICAgICAgICAgICAgICAgIFRyVlQ3ZGVUeGdHVCA9IC16OwogICAgICAgICAgICAgICAgICAgIHV0dDN1dGp1eC54ZGtsVC43WXd4bncgPSAndVlkbic7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9Cn0KCkJZdDdkZ250IEN3dW9BdHRuZHVkZ250OHd1VlZUdyhWdUVUTmdUbywgVnVFVDZZczBUdykgewogICAganV3IDd1dGp1eDh3dVZWVHcgPSBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygiVnVFVCIgKyBWdUVUNllzMFR3KS5WdXdUdGRNbFRzVHRkOwogICAganV3IHV0dG5kdWRnbnQ4d3VWVlR3ID0gN3V0anV4OHd1VlZUdy43bG50VDZuQ1QoZHdZVCk7IC8vIGR3WVQgc1R1dHggN2xudFQgdWxsIDdiZ2xDNm5DVHggdXRDIHVsbCBUalR0ZCBidXRDbFR3eAogICAgdXR0bmR1ZGdudDh3dVZWVHcueGRrbFQuVm54Z2RnbnQgPSAndTB4bmxZZFQnOwogICAgdXR0bmR1ZGdudDh3dVZWVHcueGRrbFQuR2Z0Q1RyID0gTExMOwogICAganV3IGRUc1Y4d3VWVlR3ID0gN3V0anV4OHd1VlZUdy43bG50VDZuQ1QoZHdZVCk7CiAgICBkVHNWOHd1VlZUdy54ZGtsVC5HZnRDVHIgPSB6dnZ2OwogICAgZFRzVjh3dVZWVHcueGRrbFQuVm54Z2RnbnQgPSAndTB4bmxZZFQnOwoKICAgIGdCIChWdUVUTmdUby53bmR1ZGdudCA9PSB2KSB7IC8vdXh4bjdndWRUIFRqVHRkeCBudGxrIG9iVHQgZGJUd1QgZ3ggdG4gd25kdWRnbnQKICAgICAgICBkVHNWOHd1VlZUdy51Q0NNalR0ZElneGRUdFR3KCdzbll4VENub3QnLCBzbll4VFNub3QsIEJ1bHhUKTsKICAgICAgICBkVHNWOHd1VlZUdy51Q0NNalR0ZElneGRUdFR3KCdzbll4VFlWJywgc25ZeFRXViwgQnVseFQpOwogICAgICAgIGRUc1Y4d3VWVlR3LnVDQ01qVHRkSWd4ZFR0VHcoJ3NuWXhUc25qVCcsIHNuWXhUcW5qVCwgQnVseFQpOwogICAgfQoKICAgIDd1dGp1eDh3dVZWVHcuVnV3VHRkTWxUc1R0ZC5ndHhUd2RGVEJud1QodXR0bmR1ZGdudDh3dVZWVHcsIDd1dGp1eDh3dVZWVHcpOwogICAgN3V0anV4OHd1VlZUdy5WdXdUdGRNbFRzVHRkLmd0eFR3ZEZUQm53VChkVHNWOHd1VlZUdywgdXR0bmR1ZGdudDh3dVZWVHcpOwoKICAgIGp1dyB1dHQzZHIgPSB1dHRuZHVkZ250OHd1VlZUdy43YmdsQzZuQ1R4W3ZdLkVUZDNudGRUcmQoJ1pDJyk7CiAgICBkVHNWOHd1VlZUdy43YmdsQzZuQ1R4W3ZdLjdudGRUcmQgPSB1dHQzZHI7CiAgICBkVHNWOHd1VlZUdy43YmdsQzZuQ1R4W3ZdLlZ1RVQ2WXMwVHcgPSBWdUVUNllzMFR3OwogICAgVnVFVE5nVG8uN250ZFRyZCA9IHV0dDNkcjsKICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250LkN3dW9TbjdZc1R0ZEF0dG5kdWRnbnR4KFZ1RVROZ1RvLCB1dHQzZHIsIFZ1RVQ2WXMwVHcpOwoKfQoKQll0N2RnbnQgWVZDdWRUKDdubG53S2c3T1R3KSB7CgogICAgS1M1TmdUb1R3QVZWbGc3dWRnbnQuN2J1dEVUU243WXNUdGRBdHRuZHVkZ250M25sbncoN25sbndLZzdPVHcpOwp9CgpLUzV5UC5nc3VFVGVUeG5ZdzdUeEt1ZGIgPSAnd1R4bll3N1R4L1ZsWUVndHgvVkNCX2pnVG9Ud191Q2p1dDdUQy9nc3VFVHgvJzsKS1M1eVAub253T1R3UHc3ID0gJ3dUeG5ZdzdUeC9WbFlFZ3R4L1ZDQl9qZ1RvVHdfdUNqdXQ3VEMvVkNCLm9ud09Udy4xeCc7CktTNXlQLjdxdVZXd2wgPSAnd1R4bll3N1R4L1ZsWUVndHgvVkNCX2pnVG9Ud191Q2p1dDdUQy83c3VWeC8nOwpLUzV5UC43cXVWS3U3T1RDID0gZHdZVDsKCmp1dyBzbkdJenZ0ID0gQ243WXNUdGQuc25HSXp2dCB8fCBDbjdZc1R0ZC5vVDBJenZ0OwoKanV3IDNQUF9XNmZIUCA9IExELnYgLyBhWi52OwpqdXcgU001QVdJSF9QM0FJTV9OQUlXTSA9ICd1WWRuJzsKanV3IFNNNUFXSUhfUDNBSU0gPSB6LnY7Cmp1dyBXNlI2OTg2X1AzQUlNID0gdjsKanV3IHFBSl9BV0g5X1AzQUlNID0gei5aYzsKanV3IFAzZTlJSUZBZV9LQVNTZjZwID0gaXY7Cmp1dyBOTWVIZjNBSV9LQVNTZjZwID0gYzsKCi8vblZkZ3NneFRDIDNQUCA3WXhkbnMgVnduVlR3ZGsgRVRkZFR3L3hUZGRUdwpqdXcgM1l4ZG5zUGRrbFQgPSAoQll0N2RnbnQgM1l4ZG5zUGRrbFQzbG54WXdUKCkgewoKICAgIC8vIEF4IHRuZFRDIG50OiBiZGRWOi8vb29vLkd1N2J4ZHdudHVZZC43bnMvVm54ZHgvWnZ2TC92Wi96YS8KICAgIC8vICAgICAgICAgICAgICB1dGdzdWRULTd4eC1kd3V0eEJud3N4LUJnd1RCbnItb1QwT2dkLmJkc2wKICAgIC8vIGd0IHhuc1QgalR3eGdudHggbkIgZk1MIGdkIGd4IDd3Z2RnN3VsIGRidWQgc3ggdVZWVHV3IGd0IGRiZ3ggbGd4ZAogICAgLy8gMFRCbndUIHFuRwogICAganV3IFZ3VEJnclR4ID0gWydzeCcsICdxbkcnLCAnOFQwT2dkJywgJzknXTsKICAgIGp1dyBfN3U3YlQgPSB7fTsKCiAgICBCWXQ3ZGdudCAzWXhkbnNQZGtsVCgpIHt9CgogICAgM1l4ZG5zUGRrbFQuRVRkS3duViA9IEJZdDdkZ250IEVUZChWd25WNnVzVCwgVGxUc1R0ZCkgewogICAgICAgIC8vIDdiVDdPIDd1N2JUIG50bGsgb2JUdCB0biBUbFRzVHRkIGd4IEVnalR0CiAgICAgICAgZ0IgKHV3RVlzVHRkeC5sVHRFZGIgPT09IHogJiYgZGtWVG5CIF83dTdiVFtWd25WNnVzVF0gPT09ICd4ZHdndEUnKSB7CiAgICAgICAgICAgIHdUZFl3dCBfN3U3YlRbVnduVjZ1c1RdOwogICAgICAgIH0KCiAgICAgICAgVGxUc1R0ZCA9IFRsVHNUdGQgfHwgQ243WXNUdGQuQ243WXNUdGRNbFRzVHRkOwogICAgICAgIGp1dyB4ZGtsVCA9IFRsVHNUdGQueGRrbFQsIFZ3VEJnclRDLCBZS3duVjZ1c1Q7CgogICAgICAgIC8vIGRUeGQgeGR1dEN1d0MgVnduVlR3ZGsgQmd3eGQKICAgICAgICBnQiAoZGtWVG5CIHhka2xUW1Z3blY2dXNUXSA9PT0gJ3hkd2d0RScpIHsKICAgICAgICAgICAgd1RkWXd0IChfN3U3YlRbVnduVjZ1c1RdID0gVnduVjZ1c1QpOwogICAgICAgIH0KCiAgICAgICAgLy8gN3VWZ2R1bGdHVAogICAgICAgIFlLd25WNnVzVCA9IFZ3blY2dXNULjdidXdBZCh2KS5kbldWVlR3M3V4VCgpICsgVnduVjZ1c1QueGxnN1Qoeik7CgogICAgICAgIC8vIGRUeGQgalR0Q253IHhWVDdnQmc3IFZ3blZUd2RnVHgKICAgICAgICBCbncgKGp1dyBnID0gdiwgbCA9IFZ3VEJnclR4LmxUdEVkYjsgZyA8IGw7IGcrKykgewogICAgICAgICAgICBWd1RCZ3JUQyA9IFZ3VEJnclR4W2ddICsgWUt3blY2dXNUOwogICAgICAgICAgICBnQiAoZGtWVG5CIHhka2xUW1Z3VEJnclRDXSA9PT0gJ3hkd2d0RScpIHsKICAgICAgICAgICAgICAgIHdUZFl3dCAoXzd1N2JUW1Z3blY2dXNUXSA9IFZ3VEJnclRDKTsKICAgICAgICAgICAgfQogICAgICAgIH0KCiAgICAgICAgLy9nQiB1bGwgQnVnbHggZGJUdCB4VGQgZG4gWXRDVEJndFRDCiAgICAgICAgd1RkWXd0IChfN3U3YlRbVnduVjZ1c1RdID0gJ1l0Q1RCZ3RUQycpOwogICAgfTsKCiAgICAzWXhkbnNQZGtsVC54VGRLd25WID0gQll0N2RnbnQgeFRkKFZ3blY2dXNULCBUbFRzVHRkLCB4ZHcpIHsKICAgICAgICBqdXcgVnduViA9IGRiZ3guRVRkS3duVihWd25WNnVzVCk7CiAgICAgICAgZ0IgKFZ3blYgIT09ICdZdENUQmd0VEMnKSB7CiAgICAgICAgICAgIFRsVHNUdGQueGRrbFRbVnduVl0gPSB4ZHc7CiAgICAgICAgfQogICAgfTsKCiAgICB3VGRZd3QgM1l4ZG5zUGRrbFQ7Cn0pKCk7CgpqdXcgNllsbDNidXd1N2RUd3hlVEVNclYgPSAvXHJ2di9FOwoKQll0N2RnbnQgd1RzbmpUNllsbDNidXd1N2RUd3goeGR3KSB7CiAgICB3VGRZd3QgeGR3LndUVmx1N1QoNllsbDNidXd1N2RUd3hlVEVNclYsICcnKTsKfQoKQll0N2RnbnQgRVRkNWdsVDZ1c1QoWXdsKSB7CiAgICBqdXcgdXQ3Ym53ID0gWXdsLmd0Q1RyOUIoJyMnKTsKICAgIGp1dyBRWVR3ayA9IFl3bC5ndENUcjlCKCc/Jyk7CiAgICBqdXcgVHRDID0gcXVkYi5zZ3QoCiAgICAgICAgICAgIHV0N2JudyA+IHYgPyB1dDdibncgOiBZd2wubFR0RWRiLAogICAgICAgICAgICBRWVR3ayA+IHYgPyBRWVR3ayA6IFl3bC5sVHRFZGIpOwogICAgd1RkWXd0IFl3bC54WTB4ZHdndEUoWXdsLmx1eGRmdENUcjlCKCcvJywgVHRDKSArIHosIFR0Qyk7Cn0KCi8qKgogKiBlVGRZd3R4IHg3dWxUIEJ1N2RudyBCbncgZGJUIDd1dGp1eC4gZmQgc3VPVHggeFR0eFQgQm53IGRiVCAyZ1NLZiBDZ3hWbHVreC4KICogQHdUZFl3dCB7OTAxVDdkfSBIYlQgbjAxVDdkIG9nZGIgYm53Z0dudGR1bCAoeHIpIHV0QyBqVHdkZzd1bCAoeGspCiB4N3VsVHguIEhiVCB4N3VsVEMgVnduVlR3ZGsgZ3ggeFRkIGRuIEJ1bHhUIGdCIHg3dWxndEUgZ3gKIHRuZCB3VFFZZ3dUQywgZHdZVCBuZGJUd29neFQuCiAqLwpCWXQ3ZGdudCBFVGQ5WWRWWWRQN3VsVCg3ZHIpIHsKICAgIGp1dyBDVGpnN1RLZ3JUbGV1ZGduID0gb2d0Q25vLkNUamc3VEtnclRsZXVkZ24gfHwgejsKICAgIGp1dyAwdTdPZ3RFUGRud1RldWRnbiA9IDdkci5vVDBPZ2RGdTdPZ3RFUGRud1RLZ3JUbGV1ZGduIHx8CiAgICAgICAgICAgIDdkci5zbkdGdTdPZ3RFUGRud1RLZ3JUbGV1ZGduIHx8CiAgICAgICAgICAgIDdkci5zeEZ1N09ndEVQZG53VEtnclRsZXVkZ24gfHwKICAgICAgICAgICAgN2RyLm5GdTdPZ3RFUGRud1RLZ3JUbGV1ZGduIHx8CiAgICAgICAgICAgIDdkci4wdTdPZ3RFUGRud1RLZ3JUbGV1ZGduIHx8IHo7CiAgICBqdXcgVmdyVGxldWRnbiA9IENUamc3VEtnclRsZXVkZ24gLyAwdTdPZ3RFUGRud1RldWRnbjsKICAgIHdUZFl3dCB7CiAgICAgICAgeHI6IFZnclRsZXVkZ24sCiAgICAgICAgeGs6IFZnclRsZXVkZ24sCiAgICAgICAgeDd1bFRDOiBWZ3JUbGV1ZGduICE9PSB6CiAgICB9Owp9CgovKioKICogUDd3bmxseCB4VlQ3Z0JnVEMgVGxUc1R0ZCBndGRuIGpnVG8gbkIgZ2R4IFZ1d1R0ZC4KICogVGxUc1R0ZCB7OTAxVDdkfSBIYlQgVGxUc1R0ZCBkbiAwVCBqZ3hnMGxULgogKiB4Vm5kIHs5MDFUN2R9IEF0IG4wMVQ3ZCBvZ2RiIG5WZGdudHVsIGRuViB1dEMgbFRCZCBWd25WVHdkZ1R4LAogKiAgICAgICAgICAgICAgIHhWVDdnQmtndEUgZGJUIG5CQnhUZCBCd25zIGRiVCBkblYgbFRCZCBUQ0VULgogKi8KQll0N2RnbnQgeDd3bmxsZnRkbk5nVG8oVGxUc1R0ZCwgeFZuZCkgewogICAgLy8gQXh4WXNndEUgbkJCeFRkS3V3VHRkIGd4IHVqdWdsdTBsVCAoZ2QneCB0bmQgdWp1Z2x1MGxUIG9iVHQgamdUb1R3IGd4IGd0CiAgICAvLyBiZ0NDVHQgZ0J3dXNUIG53IG4wMVQ3ZCkuIDhUIGJ1alQgZG4geDd3bmxsOiBnQiBkYlQgbkJCeFRkS3V3VHRkIGd4IHRuZCB4VGQKICAgIC8vIFZ3bkNZN2d0RSBkYlQgVHd3bncuIFBUVCB1bHhuIHV0Z3N1ZGdudFBkdXdkVEMzbG54WXdULgogICAganV3IFZ1d1R0ZCA9IFRsVHNUdGQubkJCeFRkS3V3VHRkOwogICAganV3IG5CQnhUZDQgPSBUbFRzVHRkLm5CQnhUZEhuViArIFRsVHNUdGQuN2xnVHRkSG5WOwogICAganV3IG5CQnhUZEogPSBUbFRzVHRkLm5CQnhUZElUQmQgKyBUbFRzVHRkLjdsZ1R0ZElUQmQ7CiAgICBnQiAoIVZ1d1R0ZCkgewogICAgICAgIDdudHhubFQuVHd3bncoJ25CQnhUZEt1d1R0ZCBneCB0bmQgeFRkIC0tIDd1dHRuZCB4N3dubGwnKTsKICAgICAgICB3VGRZd3Q7CiAgICB9CiAgICBvYmdsVCAoVnV3VHRkLjdsZ1R0ZDJUZ0ViZCA9PT0gVnV3VHRkLng3d25sbDJUZ0ViZCkgewogICAgICAgIGdCIChWdXdUdGQuQ3VkdXhUZC5feDd1bFQ0KSB7CiAgICAgICAgICAgIG5CQnhUZDQgLz0gVnV3VHRkLkN1ZHV4VGQuX3g3dWxUNDsKICAgICAgICAgICAgbkJCeFRkSiAvPSBWdXdUdGQuQ3VkdXhUZC5feDd1bFRKOwogICAgICAgIH0KICAgICAgICBuQkJ4VGQ0ICs9IFZ1d1R0ZC5uQkJ4VGRIblY7CiAgICAgICAgbkJCeFRkSiArPSBWdXdUdGQubkJCeFRkSVRCZDsKICAgICAgICBWdXdUdGQgPSBWdXdUdGQubkJCeFRkS3V3VHRkOwogICAgICAgIGdCICghVnV3VHRkKSB7CiAgICAgICAgICAgIHdUZFl3dDsgLy8gdG4gdFRUQyBkbiB4N3dubGwKICAgICAgICB9CiAgICB9CiAgICBnQiAoeFZuZCkgewogICAgICAgIGdCICh4Vm5kLmRuViAhPT0gWXRDVEJndFRDKSB7CiAgICAgICAgICAgIG5CQnhUZDQgKz0geFZuZC5kblY7CiAgICAgICAgfQogICAgICAgIGdCICh4Vm5kLmxUQmQgIT09IFl0Q1RCZ3RUQykgewogICAgICAgICAgICBuQkJ4VGRKICs9IHhWbmQubFRCZDsKICAgICAgICAgICAgVnV3VHRkLng3d25sbElUQmQgPSBuQkJ4VGRKOwogICAgICAgIH0KICAgIH0KICAgIFZ1d1R0ZC54N3dubGxIblYgPSBuQkJ4VGQ0Owp9CgovKioKICogMlRsVlR3IEJZdDdkZ250IGRuIHhkdXdkIHNudGdkbndndEUgZGJUIHg3d25sbCBUalR0ZCB1dEMgN250alR3ZGd0RSBkYlRzIGd0ZG4KICogS1M1LjF4IEJ3Z1R0Q2xrIG50VDogb2dkYiB4N3dubGwgQ1Qwbll0N1QgdXRDIHg3d25sbCBDZ3dUN2RnbnQuCiAqLwpCWXQ3ZGdudCBvdWQ3YlA3d25sbChqZ1RvQXdUdU1sVHNUdGQsIDd1bGwwdTdPKSB7CiAgICBqdXcgQ1Qwbll0N1RQN3dubGwgPSBCWXQ3ZGdudCBDVDBuWXQ3VFA3d25sbChUamQpIHsKICAgICAgICBnQiAod0E1KSB7CiAgICAgICAgICAgIHdUZFl3dDsKICAgICAgICB9CiAgICAgICAgLy8geDdiVENZbFQgdXQgZ3Rqbjd1ZGdudCBuQiB4N3dubGwgQm53IHRUcmQgdXRnc3VkZ250IEJ3dXNULgogICAgICAgIHdBNSA9IG9ndENuby53VFFZVHhkQXRnc3VkZ250NXd1c1QoQll0N2RnbnQgamdUb0F3VHVNbFRzVHRkUDd3bmxsVEMoKSB7CiAgICAgICAgICAgIHdBNSA9IHRZbGw7CgogICAgICAgICAgICBqdXcgN1l3d1R0ZDQgPSBqZ1RvQXdUdU1sVHNUdGQueDd3bmxsSG5WOwogICAgICAgICAgICBqdXcgbHV4ZDQgPSB4ZHVkVC5sdXhkNDsKICAgICAgICAgICAgZ0IgKDdZd3dUdGQ0ICE9PSBsdXhkNCkgewogICAgICAgICAgICAgICAgeGR1ZFQuQ25vdCA9IDdZd3dUdGQ0ID4gbHV4ZDQ7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgeGR1ZFQubHV4ZDQgPSA3WXd3VHRkNDsKICAgICAgICAgICAgN3VsbDB1N08oeGR1ZFQpOwogICAgICAgIH0pOwogICAgfTsKCiAgICBqdXcgeGR1ZFQgPSB7CiAgICAgICAgQ25vdDogZHdZVCwKICAgICAgICBsdXhkNDogamdUb0F3VHVNbFRzVHRkLng3d25sbEhuViwKICAgICAgICBfVGpUdGQydXRDbFR3OiBDVDBuWXQ3VFA3d25sbAogICAgfTsKCiAgICBqdXcgd0E1ID0gdFlsbDsKICAgIGpnVG9Bd1R1TWxUc1R0ZC51Q0NNalR0ZElneGRUdFR3KCd4N3dubGwnLCBDVDBuWXQ3VFA3d25sbCwgZHdZVCk7CiAgICB3VGRZd3QgeGR1ZFQ7Cn0KCi8qKgogKiAyVGxWVHcgQll0N2RnbnQgZG4gVnV3eFQgUVlUd2sgeGR3Z3RFIChULkUuID9WdXd1c3o9anVsWVQmVnV3c1o9Li4uKS4KICovCkJZdDdkZ250IFZ1d3hUaFlUd2tQZHdndEUoUVlUd2spIHsKICAgIGp1dyBWdXdkeCA9IFFZVHdrLnhWbGdkKCcmJyk7CiAgICBqdXcgVnV3dXN4ID0ge307CiAgICBCbncgKGp1dyBnID0gdiwgZ2cgPSBWdXdkeC5sVHRFZGI7IGcgPCBnZzsgKytnKSB7CiAgICAgICAganV3IFZ1d3VzID0gVnV3ZHhbZ10ueFZsZ2QoJz0nKTsKICAgICAgICBqdXcgT1RrID0gVnV3dXNbdl0uZG5Jbm9UdzN1eFQoKTsKICAgICAgICBqdXcganVsWVQgPSBWdXd1cy5sVHRFZGIgPiB6ID8gVnV3dXNbel0gOiB0WWxsOwogICAgICAgIFZ1d3VzeFtDVDduQ1RXZWYzbnNWbnRUdGQoT1RrKV0gPSBDVDduQ1RXZWYzbnNWbnRUdGQoanVsWVQpOwogICAgfQogICAgd1RkWXd0IFZ1d3VzeDsKfQoKLyoqCiAqIFd4VCAwZ3R1d2sgeFR1dzdiIGRuIEJndEMgZGJUIGd0Q1RyIG5CIGRiVCBCZ3d4ZCBnZFRzIGd0IHUgRWdqVHQgdXd3dWsgb2JnN2IKICogVnV4eFR4IHUgRWdqVHQgN250Q2dkZ250LiBIYlQgZ2RUc3ggdXdUIFRyVlQ3ZFRDIGRuIDBUIHhud2RUQyBndCBkYlQgeFR0eFQKICogZGJ1ZCBnQiBkYlQgN250Q2dkZ250IGd4IGR3WVQgQm53IG50VCBnZFRzIGd0IGRiVCB1d3d1aywgZGJUdCBnZCBneCB1bHhuIGR3WVQKICogQm53IHVsbCBCbmxsbm9ndEUgZ2RUc3guCiAqCiAqIEB3VGRZd3R4IHs2WXMwVHd9IGZ0Q1RyIG5CIGRiVCBCZ3d4ZCB1d3d1ayBUbFRzVHRkIGRuIFZ1eHggZGJUIGRUeGQsCiAqICAgICAgICAgICAgICAgICAgIG53IHxnZFRzeC5sVHRFZGJ8IGdCIHRuIHhZN2IgVGxUc1R0ZCBUcmd4ZHguCiAqLwpCWXQ3ZGdudCAwZ3R1d2tQVHV3N2I1Z3d4ZGZkVHMoZ2RUc3gsIDdudENnZGdudCkgewogICAganV3IHNndGZ0Q1RyID0gdjsKICAgIGp1dyBzdXJmdENUciA9IGdkVHN4LmxUdEVkYiAtIHo7CgogICAgZ0IgKGdkVHN4LmxUdEVkYiA9PT0gdiB8fCAhN250Q2dkZ250KGdkVHN4W3N1cmZ0Q1RyXSkpIHsKICAgICAgICB3VGRZd3QgZ2RUc3gubFR0RWRiOwogICAgfQogICAgZ0IgKDdudENnZGdudChnZFRzeFtzZ3RmdENUcl0pKSB7CiAgICAgICAgd1RkWXd0IHNndGZ0Q1RyOwogICAgfQoKICAgIG9iZ2xUIChzZ3RmdENUciA8IHN1cmZ0Q1RyKSB7CiAgICAgICAganV3IDdZd3dUdGRmdENUciA9IChzZ3RmdENUciArIHN1cmZ0Q1RyKSA+PiB6OwogICAgICAgIGp1dyA3WXd3VHRkZmRUcyA9IGdkVHN4WzdZd3dUdGRmdENUcl07CiAgICAgICAgZ0IgKDdudENnZGdudCg3WXd3VHRkZmRUcykpIHsKICAgICAgICAgICAgc3VyZnRDVHIgPSA3WXd3VHRkZnRDVHI7CiAgICAgICAgfSBUbHhUIHsKICAgICAgICAgICAgc2d0ZnRDVHIgPSA3WXd3VHRkZnRDVHIgKyB6OwogICAgICAgIH0KICAgIH0KICAgIHdUZFl3dCBzZ3RmdENUcjsgLyogPT09IHN1cmZ0Q1RyICovCn0KCi8qKgogKiBwVHRUd2c3IGJUbFZUdyBkbiBCZ3RDIG5ZZCBvYnVkIFRsVHNUdGR4IHV3VCBqZ3hnMGxUIG9nZGJndCB1IHg3d25sbCBWdXRULgogKi8KQll0N2RnbnQgRVRkTmd4ZzBsVE1sVHNUdGR4KHg3d25sbE1sLCBqZ1RveCwgeG53ZEZrTmd4ZzBnbGdkaykgewogICAganV3IGRuViA9IHg3d25sbE1sLng3d25sbEhuViwgMG5kZG5zID0gZG5WICsgeDd3bmxsTWwuN2xnVHRkMlRnRWJkOwogICAganV3IGxUQmQgPSB4N3dubGxNbC54N3dubGxJVEJkLCB3Z0ViZCA9IGxUQmQgKyB4N3dubGxNbC43bGdUdGQ4Z0NkYjsKCiAgICBCWXQ3ZGdudCBneE1sVHNUdGRGbmRkbnNGVGxub05nVG9IblYoamdUbykgewogICAgICAgIGp1dyBUbFRzVHRkID0gamdUby5DZ2o7CiAgICAgICAganV3IFRsVHNUdGRGbmRkbnMgPQogICAgICAgICAgICAgICAgVGxUc1R0ZC5uQkJ4VGRIblYgKyBUbFRzVHRkLjdsZ1R0ZEhuViArIFRsVHNUdGQuN2xnVHRkMlRnRWJkOwogICAgICAgIHdUZFl3dCBUbFRzVHRkRm5kZG5zID4gZG5WOwogICAgfQoKICAgIGp1dyBqZ3hnMGxUID0gW10sIGpnVG8sIFRsVHNUdGQ7CiAgICBqdXcgN1l3d1R0ZDJUZ0ViZCwgamdUbzJUZ0ViZCwgYmdDQ1R0MlRnRWJkLCBWVHc3VHRkMlRnRWJkOwogICAganV3IDdZd3dUdGQ4Z0NkYiwgamdUbzhnQ2RiOwogICAganV3IEJnd3hkTmd4ZzBsVE1sVHNUdGRmdEMgPSAoamdUb3gubFR0RWRiID09PSB2KSA/IHYgOgogICAgICAgICAgICAwZ3R1d2tQVHV3N2I1Z3d4ZGZkVHMoamdUb3gsIGd4TWxUc1R0ZEZuZGRuc0ZUbG5vTmdUb0huVik7CgogICAgQm53IChqdXcgZyA9IEJnd3hkTmd4ZzBsVE1sVHNUdGRmdEMsIGdnID0gamdUb3gubFR0RWRiOyBnIDwgZ2c7IGcrKykgewogICAgICAgIGpnVG8gPSBqZ1RveFtnXTsKICAgICAgICBUbFRzVHRkID0gamdUby5DZ2o7CiAgICAgICAgN1l3d1R0ZDJUZ0ViZCA9IFRsVHNUdGQubkJCeFRkSG5WICsgVGxUc1R0ZC43bGdUdGRIblY7CiAgICAgICAgamdUbzJUZ0ViZCA9IFRsVHNUdGQuN2xnVHRkMlRnRWJkOwoKICAgICAgICBnQiAoN1l3d1R0ZDJUZ0ViZCA+IDBuZGRucykgewogICAgICAgICAgICAwd1R1TzsKICAgICAgICB9CgogICAgICAgIDdZd3dUdGQ4Z0NkYiA9IFRsVHNUdGQubkJCeFRkSVRCZCArIFRsVHNUdGQuN2xnVHRkSVRCZDsKICAgICAgICBqZ1RvOGdDZGIgPSBUbFRzVHRkLjdsZ1R0ZDhnQ2RiOwogICAgICAgIGdCICg3WXd3VHRkOGdDZGIgKyBqZ1RvOGdDZGIgPCBsVEJkIHx8IDdZd3dUdGQ4Z0NkYiA+IHdnRWJkKSB7CiAgICAgICAgICAgIDdudGRndFlUOwogICAgICAgIH0KICAgICAgICBiZ0NDVHQyVGdFYmQgPSBxdWRiLnN1cih2LCBkblYgLSA3WXd3VHRkMlRnRWJkKSArCiAgICAgICAgICAgICAgICBxdWRiLnN1cih2LCA3WXd3VHRkMlRnRWJkICsgamdUbzJUZ0ViZCAtIDBuZGRucyk7CiAgICAgICAgVlR3N1R0ZDJUZ0ViZCA9ICgoamdUbzJUZ0ViZCAtIGJnQ0NUdDJUZ0ViZCkgKiB6dnYgLyBqZ1RvMlRnRWJkKSB8IHY7CgogICAgICAgIGpneGcwbFQuVll4Yih7CiAgICAgICAgICAgIGdDOiBqZ1RvLmdDLAogICAgICAgICAgICByOiA3WXd3VHRkOGdDZGIsCiAgICAgICAgICAgIGs6IDdZd3dUdGQyVGdFYmQsCiAgICAgICAgICAgIGpnVG86IGpnVG8sCiAgICAgICAgICAgIFZUdzdUdGQ6IFZUdzdUdGQyVGdFYmQKICAgICAgICB9KTsKICAgIH0KCiAgICBqdXcgQmd3eGQgPSBqZ3hnMGxUW3ZdOwogICAganV3IGx1eGQgPSBqZ3hnMGxUW2pneGcwbFQubFR0RWRiIC0gel07CgogICAgZ0IgKHhud2RGa05neGcwZ2xnZGspIHsKICAgICAgICBqZ3hnMGxULnhud2QoQll0N2RnbnQgKHUsIDApIHsKICAgICAgICAgICAganV3IFY3ID0gdS5WVHc3VHRkIC0gMC5WVHc3VHRkOwogICAgICAgICAgICBnQiAocXVkYi51MHgoVjcpID4gdi52dnopIHsKICAgICAgICAgICAgICAgIHdUZFl3dCAtVjc7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgd1RkWXd0IHUuZ0MgLSAwLmdDOyAvLyBUdHhZd1QgeGR1MGdsZ2RrCiAgICAgICAgfSk7CiAgICB9CiAgICB3VGRZd3Qge0Jnd3hkOiBCZ3d4ZCwgbHV4ZDogbHV4ZCwgamdUb3g6IGpneGcwbFR9Owp9CgovKioKICogTWpUdGQgYnV0Q2xUdyBkbiB4WVZWd1R4eCA3bnRkVHJkIHNUdFkuCiAqLwpCWXQ3ZGdudCB0bjNudGRUcmRxVHRZMnV0Q2xUdyhUKSB7CiAgICBULlZ3VGpUdGRTVEJ1WWxkKCk7Cn0KCi8qKgogKiBlVGRZd3R4IGRiVCBCZ2xUdHVzVCBudyBFWVR4eFRDIEJnbFR0dXNUIEJ3bnMgZGJUIFl3bCAoeFRUIGd4eFlUIG1pY2MpLgogKiBZd2wge1Bkd2d0RX0gSGJUIG53Z0VndHVsIEtTNSBsbjd1ZGdudC4KICogQHdUZFl3dCB7UGR3Z3RFfSBwWVR4eFRDIEtTNSBCZ2xUIHR1c1QuCiAqLwpCWXQ3ZGdudCBFVGRLUzU1Z2xUNnVzVDV3bnNXZUkoWXdsKSB7CiAgICBqdXcgd1RXZWYgPSAvXig/OihbXjpdKzopP1wvXC9bXlwvXSspPyhbXj8jXSopKFw/W14jXSopPygjLiopPyQvOwogICAgLy8gICAgICAgICAgICBQMzJNcU0gICAgICAyOVBIICAgICAgICAgei5LQUgyICBaLmhXTWU0ICAgbS5lTTUKICAgIC8vIEt1ZGRUd3QgZG4gRVRkIGx1eGQgc3VkN2JndEUgNkFxTS5WQ0IKICAgIGp1dyB3VDVnbFR0dXNUID0gL1teXC8/Iz1dK1wuVkNCXDAoPyEuKlwuVkNCXDApL2c7CiAgICBqdXcgeFZsZ2RXZWYgPSB3VFdlZi5UclQ3KFl3bCk7CiAgICBqdXcgeFlFRVR4ZFRDNWdsVHR1c1QgPSB3VDVnbFR0dXNULlRyVDcoeFZsZ2RXZWZbel0pIHx8CiAgICAgICAgICAgIHdUNWdsVHR1c1QuVHJUNyh4VmxnZFdlZltaXSkgfHwKICAgICAgICAgICAgd1Q1Z2xUdHVzVC5UclQ3KHhWbGdkV2VmW21dKTsKICAgIGdCICh4WUVFVHhkVEM1Z2xUdHVzVCkgewogICAgICAgIHhZRUVUeGRUQzVnbFR0dXNUID0geFlFRVR4ZFRDNWdsVHR1c1Rbdl07CiAgICAgICAgZ0IgKHhZRUVUeGRUQzVnbFR0dXNULmd0Q1RyOUIoJyUnKSAhPT0gLXopIHsKICAgICAgICAgICAgLy8gV2VJLVR0N25DVEMgJVo1VnVkYiVaNWRuJVo1QmdsVC5WQ0IgeGJuWWxDIDBUIEJnbFQuVkNCCiAgICAgICAgICAgIGR3ayB7CiAgICAgICAgICAgICAgICB4WUVFVHhkVEM1Z2xUdHVzVCA9CiAgICAgICAgICAgICAgICAgICAgICAgIHdUNWdsVHR1c1QuVHJUNyhDVDduQ1RXZWYzbnNWbnRUdGQoeFlFRVR4ZFRDNWdsVHR1c1QpKVt2XTsKICAgICAgICAgICAgfSA3dWQ3YiAoVCkgeyAvLyBLbnh4ZzBsVCAoVHJkd1RzVGxrIHd1d1QpIFR3d253eDoKICAgICAgICAgICAgICAgIC8vIFdlZk13d253ICJxdWxCbndzVEMgV2VmIiwgVC5FLiBCbncgIiVBQS5WQ0IiCiAgICAgICAgICAgICAgICAvLyBIa1ZUTXd3bncgInRZbGwgYnV4IHRuIFZ3blZUd2RnVHgiLCBULkUuIEJudyAiJVo1LlZDQiIKICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KICAgIHdUZFl3dCB4WUVFVHhkVEM1Z2xUdHVzVCB8fCAnQ243WXNUdGQuVkNCJzsKfQoKanV3IEt3bkV3VHh4RnV3ID0gKEJZdDdkZ250IEt3bkV3VHh4RnV3M2xueFl3VCgpIHsKCiAgICBCWXQ3ZGdudCA3bHVzVihqLCBzZ3QsIHN1cikgewogICAgICAgIHdUZFl3dCBxdWRiLnNndChxdWRiLnN1cihqLCBzZ3QpLCBzdXIpOwogICAgfQoKICAgIEJZdDdkZ250IEt3bkV3VHh4RnV3KGdDLCBuVmR4KSB7CiAgICAgICAgZGJneC5qZ3hnMGxUID0gZHdZVDsKCiAgICAgICAgLy8gNVRkN2IgZGJUIHhZMC1UbFRzVHRkeCBCbncgbHVkVHcuCiAgICAgICAgZGJneC5DZ2ogPSBDbjdZc1R0ZC5RWVR3a1BUbFQ3ZG53KGdDICsgJyAuVnduRXdUeHgnKTsKCiAgICAgICAgLy8gcFRkIGRiVCBsbnVDZ3RFIDB1dyBUbFRzVHRkLCB4biBnZCA3dXQgMFQgd1R4Z0dUQyBkbiBCZ2QgZGJUIGpnVG9Udy4KICAgICAgICBkYmd4LjB1dyA9IGRiZ3guQ2dqLlZ1d1R0ZDZuQ1Q7CgogICAgICAgIC8vIHBUZCBuVmRnbnR4LCBvZ2RiIHhUdHhnMGxUIENUQnVZbGR4LgogICAgICAgIGRiZ3guYlRnRWJkID0gblZkeC5iVGdFYmQgfHwgenZ2OwogICAgICAgIGRiZ3gub2dDZGIgPSBuVmR4Lm9nQ2RiIHx8IHp2djsKICAgICAgICBkYmd4Lll0Z2R4ID0gblZkeC5ZdGdkeCB8fCAnJSc7CgogICAgICAgIC8vIGZ0Z2RndWxnR1QgYlRnRWJkeC4KICAgICAgICBkYmd4LkNnai54ZGtsVC5iVGdFYmQgPSBkYmd4LmJUZ0ViZCArIGRiZ3guWXRnZHg7CiAgICAgICAgZGJneC5WVHc3VHRkID0gdjsKICAgIH0KCiAgICBLd25Fd1R4eEZ1dy5Wd25kbmRrVlQgPSB7CiAgICAgICAgWVZDdWRURnV3OiBCWXQ3ZGdudCBLd25Fd1R4eEZ1d19ZVkN1ZFRGdXcoKSB7CiAgICAgICAgICAgIGdCIChkYmd4Ll9ndENUZFR3c2d0dWRUKSB7CiAgICAgICAgICAgICAgICBkYmd4LkNnai43bHV4eElneGQudUNDKCdndENUZFR3c2d0dWRUJyk7CiAgICAgICAgICAgICAgICBkYmd4LkNnai54ZGtsVC5vZ0NkYiA9IGRiZ3gub2dDZGIgKyBkYmd4Lll0Z2R4OwogICAgICAgICAgICAgICAgd1RkWXd0OwogICAgICAgICAgICB9CgogICAgICAgICAgICBkYmd4LkNnai43bHV4eElneGQud1RzbmpUKCdndENUZFR3c2d0dWRUJyk7CiAgICAgICAgICAgIGp1dyBWd25Fd1R4eFBnR1QgPSBkYmd4Lm9nQ2RiICogZGJneC5fVlR3N1R0ZCAvIHp2djsKICAgICAgICAgICAgZGJneC5DZ2oueGRrbFQub2dDZGIgPSBWd25Fd1R4eFBnR1QgKyBkYmd4Lll0Z2R4OwogICAgICAgIH0sCiAgICAgICAgRVRkIFZUdzdUdGQoKSB7CiAgICAgICAgICAgIHdUZFl3dCBkYmd4Ll9WVHc3VHRkOwogICAgICAgIH0sCiAgICAgICAgeFRkIFZUdzdUdGQoanVsKSB7CiAgICAgICAgICAgIGRiZ3guX2d0Q1RkVHdzZ3R1ZFQgPSBneDZ1NihqdWwpOwogICAgICAgICAgICBkYmd4Ll9WVHc3VHRkID0gN2x1c1YoanVsLCB2LCB6dnYpOwogICAgICAgICAgICBkYmd4LllWQ3VkVEZ1dygpOwogICAgICAgIH0sCiAgICAgICAgeFRkOGdDZGI6IEJZdDdkZ250IEt3bkV3VHh4RnV3X3hUZDhnQ2RiKGpnVG9UdykgewogICAgICAgICAgICBnQiAoamdUb1R3KSB7CiAgICAgICAgICAgICAgICBqdXcgN250ZHVndFR3ID0gamdUb1R3LlZ1d1R0ZDZuQ1Q7CiAgICAgICAgICAgICAgICBqdXcgeDd3bmxsMHV3OGdDZGIgPSA3bnRkdWd0VHcubkJCeFRkOGdDZGIgLSBqZ1RvVHcubkJCeFRkOGdDZGI7CiAgICAgICAgICAgICAgICBnQiAoeDd3bmxsMHV3OGdDZGIgPiB2KSB7CiAgICAgICAgICAgICAgICAgICAgZGJneC4wdXcueFRkQWRkd2cwWWRUKCd4ZGtsVCcsICdvZ0NkYjogN3VsNyh6dnYlIC0gJyArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB4N3dubGwwdXc4Z0NkYiArICdWcik7Jyk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIGJnQ1Q6IEJZdDdkZ250IEt3bkV3VHh4RnV3X2JnQ1QoKSB7CiAgICAgICAgICAgIGdCICghZGJneC5qZ3hnMGxUKSB7CiAgICAgICAgICAgICAgICB3VGRZd3Q7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZGJneC5qZ3hnMGxUID0gQnVseFQ7CiAgICAgICAgICAgIGRiZ3guMHV3LjdsdXh4SWd4ZC51Q0MoJ2JnQ0NUdCcpOwogICAgICAgICAgICBDbjdZc1R0ZC4wbkNrLjdsdXh4SWd4ZC53VHNualQoJ2xudUNndEVmdEt3bkV3VHh4Jyk7CiAgICAgICAgfSwKICAgICAgICB4Ym5vOiBCWXQ3ZGdudCBLd25Fd1R4eEZ1d194Ym5vKCkgewogICAgICAgICAgICBnQiAoZGJneC5qZ3hnMGxUKSB7CiAgICAgICAgICAgICAgICB3VGRZd3Q7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZGJneC5qZ3hnMGxUID0gZHdZVDsKICAgICAgICAgICAgQ243WXNUdGQuMG5Day43bHV4eElneGQudUNDKCdsbnVDZ3RFZnRLd25Fd1R4eCcpOwogICAgICAgICAgICBkYmd4LjB1dy43bHV4eElneGQud1RzbmpUKCdiZ0NDVHQnKTsKICAgICAgICB9CiAgICB9OwoKICAgIHdUZFl3dCBLd25Fd1R4eEZ1dzsKfSkoKTsKCmp1dyBTTTVBV0lIX0tlTTVNZU02M01QID0gewogICAgeGJub0t3VGpnbll4TmdUbzl0SW51QzogZHdZVCwKICAgIENUQnVZbGRYbm5zTnVsWVQ6ICcnLAogICAgeGdDVDB1d05nVG85dEludUM6IHYsCiAgICBUdHUwbFQydXRDSG5ubDl0SW51QzogQnVseFQsCiAgICBUdHUwbFQ4VDBwSTogQnVseFQsCiAgICBWQ0JGWUVNdHUwbFRDOiBCdWx4VCwKICAgIENneHUwbFRldXRFVDogQnVseFQsCiAgICBDZ3h1MGxUUGR3VHVzOiBCdWx4VCwKICAgIENneHUwbFRBWWRuNVRkN2I6IEJ1bHhULAogICAgQ2d4dTBsVDVudGQ1dTdUOiBCdWx4VCwKICAgIENneHUwbFRIVHJkSXVrVHc6IEJ1bHhULAogICAgWXhUOXRsazN4eFhubnM6IEJ1bHhUCn07CgpqdXcgUGdDVDB1d05nVG8gPSB7CiAgICA2OTZNOiB2LAogICAgSDJXcUZQOiB6LAogICAgOVdISWY2TTogWiwKICAgIEFISEEzMnFNNkhQOiBtCn07CgovKioKICogS3dUQlR3VHQ3VHggLSBXZGdsZ2RrIEJudyB4ZG53Z3RFIFZUd3hneGRUdGQgeFRkZGd0RXguCiAqICAgV3hUQyBCbncgeFRkZGd0RXggZGJ1ZCB4Ym5ZbEMgMFQgdVZWbGdUQyBkbiB1bGwgblZUdFRDIENuN1lzVHRkeCwKICogICBudyBUalR3ayBkZ3NUIGRiVCBqZ1RvVHcgZ3ggbG51Q1RDLgogKi8KanV3IEt3VEJUd1R0N1R4ID0gewogICAgVndUQng6IDkwMVQ3ZC43d1R1ZFQoU001QVdJSF9LZU01TWVNNjNNUCksCiAgICBneGZ0Z2RndWxnR1RDS3duc2d4VGVUeG5salRDOiBCdWx4VCwKICAgIGd0Z2RndWxnR1RDS3duc2d4VDogdFlsbCwKICAgIC8qKgogICAgICogZnRnZGd1bGdHVCB1dEMgQlRkN2IgZGJUIDdZd3dUdGQgVndUQlR3VHQ3VCBqdWxZVHggQnducyB4ZG53dUVULgogICAgICogQHdUZFl3dCB7S3duc2d4VH0gQSBWd25zZ3hUIGRidWQgZ3ggd1R4bmxqVEMgb2JUdCBkYlQgVndUQlR3VHQ3VHgKICAgICAqICAgICAgICAgICAgICAgICAgIGJ1alQgMFRUdCBndGdkZ3VsZ0dUQy4KICAgICAqLwogICAgZ3RnZGd1bGdHVDogQll0N2RnbnQgVndUQlR3VHQ3VHhmdGdkZ3VsZ0dUKCkgewogICAgICAgIHdUZFl3dCBkYmd4Lmd0Z2RndWxnR1RDS3duc2d4VCA9CiAgICAgICAgICAgICAgICBkYmd4Ll93VHVDNXduc1Bkbnd1RVQoU001QVdJSF9LZU01TWVNNjNNUCkuZGJUdChCWXQ3ZGdudCAoVndUQjkwMSkgewogICAgICAgICAgICBkYmd4Lmd4ZnRnZGd1bGdHVENLd25zZ3hUZVR4bmxqVEMgPSBkd1lUOwogICAgICAgICAgICBnQiAoVndUQjkwMSkgewogICAgICAgICAgICAgICAgZGJneC5Wd1RCeCA9IFZ3VEI5MDE7CiAgICAgICAgICAgIH0KICAgICAgICB9LjBndEMoZGJneCkpOwogICAgfSwKICAgIC8qKgogICAgICogUGRZMCBCWXQ3ZGdudCBCbncgb3dnZGd0RSBWd1RCVHdUdDdUeCBkbiB4ZG53dUVULgogICAgICogNjlITTogSGJneCB4Ym5ZbEMgMFQgbmpUd3dnQ0NUdCAwayB1IDBZZ2xDLXhWVDdnQmc3IEJZdDdkZ250IENUQmd0VEMgMFRsbm8uCiAgICAgKiBAVnV3dXMgezkwMVQ3ZH0gVndUQjkwMSBIYlQgVndUQlR3VHQ3VHggZGJ1ZCB4Ym5ZbEMgMFQgb3dnZGRUdCBkbiB4ZG53dUVULgogICAgICogQHdUZFl3dCB7S3duc2d4VH0gQSBWd25zZ3hUIGRidWQgZ3ggd1R4bmxqVEMgb2JUdCBkYlQgVndUQlR3VHQ3VCBqdWxZVHgKICAgICAqICAgICAgICAgICAgICAgICAgIGJ1alQgMFRUdCBvd2dkZFR0LgogICAgICovCiAgICBfb3dnZFRIblBkbnd1RVQ6IEJZdDdkZ250IFZ3VEJUd1R0N1R4X293Z2RUSG5QZG53dUVUKFZ3VEI5MDEpIHsKICAgICAgICB3VGRZd3QgS3duc2d4VC53VHhubGpUKCk7CiAgICB9LAogICAgLyoqCiAgICAgKiBQZFkwIEJZdDdkZ250IEJudyB3VHVDZ3RFIFZ3VEJUd1R0N1R4IEJ3bnMgeGRud3VFVC4KICAgICAqIDY5SE06IEhiZ3ggeGJuWWxDIDBUIG5qVHd3Z0NDVHQgMGsgdSAwWWdsQy14VlQ3Z0JnNyBCWXQ3ZGdudCBDVEJndFRDIDBUbG5vLgogICAgICogQFZ1d3VzIHs5MDFUN2R9IFZ3VEI5MDEgSGJUIFZ3VEJUd1R0N1R4IGRidWQgeGJuWWxDIDBUIHdUdUMgQnducyB4ZG53dUVULgogICAgICogQHdUZFl3dCB7S3duc2d4VH0gQSBWd25zZ3hUIGRidWQgZ3ggd1R4bmxqVEMgb2dkYiB1dCB7OTAxVDdkfSA3bnRkdWd0Z3RFCiAgICAgKiAgICAgICAgICAgICAgICAgICBkYlQgVndUQlR3VHQ3VHggZGJ1ZCBidWpUIDBUVHQgd1R1Qy4KICAgICAqLwogICAgX3dUdUM1d25zUGRud3VFVDogQll0N2RnbnQgVndUQlR3VHQ3VHhfd1R1QzV3bnNQZG53dUVUKFZ3VEI5MDEpIHsKICAgICAgICB3VGRZd3QgS3duc2d4VC53VHhubGpUKCk7CiAgICB9LAogICAgLyoqCiAgICAgKiBlVHhUZCBkYlQgVndUQlR3VHQ3VHggZG4gZGJUZ3cgQ1RCdVlsZCBqdWxZVHggdXRDIFlWQ3VkVCB4ZG53dUVULgogICAgICogQHdUZFl3dCB7S3duc2d4VH0gQSBWd25zZ3hUIGRidWQgZ3ggd1R4bmxqVEMgb2JUdCBkYlQgVndUQlR3VHQ3VCBqdWxZVHgKICAgICAqICAgICAgICAgICAgICAgICAgIGJ1alQgMFRUdCB3VHhUZC4KICAgICAqLwogICAgd1R4VGQ6IEJZdDdkZ250IFZ3VEJUd1R0N1R4ZVR4VGQoKSB7CiAgICAgICAgd1RkWXd0IGRiZ3guZ3RnZGd1bGdHVENLd25zZ3hULmRiVHQoQll0N2RnbnQgKCkgewogICAgICAgICAgICBkYmd4LlZ3VEJ4ID0gOTAxVDdkLjd3VHVkVChTTTVBV0lIX0tlTTVNZU02M01QKTsKICAgICAgICAgICAgd1RkWXd0IGRiZ3guX293Z2RUSG5QZG53dUVUKFNNNUFXSUhfS2VNNU1lTTYzTVApOwogICAgICAgIH0uMGd0QyhkYmd4KSk7CiAgICB9LAogICAgLyoqCiAgICAgKiBlVFZsdTdUIGRiVCA3WXd3VHRkIFZ3VEJUd1R0N1QganVsWVR4IG9nZGIgZGJUIG50VHggQnducyB4ZG53dUVULgogICAgICogQHdUZFl3dCB7S3duc2d4VH0gQSBWd25zZ3hUIGRidWQgZ3ggd1R4bmxqVEMgb2JUdCBkYlQgVndUQlR3VHQ3VCBqdWxZVHgKICAgICAqICAgICAgICAgICAgICAgICAgIGJ1alQgMFRUdCBZVkN1ZFRDLgogICAgICovCiAgICB3VGxudUM6IEJZdDdkZ250IFZ3VEJUd1R0N1R4ZVRsbnVDKCkgewogICAgICAgIHdUZFl3dCBkYmd4Lmd0Z2RndWxnR1RDS3duc2d4VC5kYlR0KEJZdDdkZ250ICgpIHsKICAgICAgICAgICAgZGJneC5fd1R1QzV3bnNQZG53dUVUKFNNNUFXSUhfS2VNNU1lTTYzTVApLmRiVHQoQll0N2RnbnQgKFZ3VEI5MDEpIHsKICAgICAgICAgICAgICAgIGdCIChWd1RCOTAxKSB7CiAgICAgICAgICAgICAgICAgICAgZGJneC5Wd1RCeCA9IFZ3VEI5MDE7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0uMGd0QyhkYmd4KSk7CiAgICAgICAgfS4wZ3RDKGRiZ3gpKTsKICAgIH0sCiAgICAvKioKICAgICAqIFBUZCBkYlQganVsWVQgbkIgdSBWd1RCVHdUdDdULgogICAgICogQFZ1d3VzIHt4ZHdndEV9IHR1c1QgSGJUIHR1c1QgbkIgZGJUIFZ3VEJUd1R0N1QgZGJ1ZCB4Ym5ZbEMgMFQgN2J1dEVUQy4KICAgICAqIEBWdXd1cyB7MG5ubFR1dHx0WXMwVHd8eGR3Z3RFfSBqdWxZVCBIYlQgdFRvIGp1bFlUIG5CIGRiVCBWd1RCVHdUdDdULgogICAgICogQHdUZFl3dCB7S3duc2d4VH0gQSBWd25zZ3hUIGRidWQgZ3ggd1R4bmxqVEMgb2JUdCBkYlQganVsWVQgYnV4IDBUVHQgeFRkLAogICAgICogICAgICAgICAgICAgICAgICAgVnduamdDVEMgZGJ1ZCBkYlQgVndUQlR3VHQ3VCBUcmd4ZHggdXRDIGRiVCBka1ZUeCBzdWQ3Yi4KICAgICAqLwogICAgeFRkOiBCWXQ3ZGdudCBWd1RCVHdUdDdUeFBUZCh0dXNULCBqdWxZVCkgewogICAgICAgIHdUZFl3dCBkYmd4Lmd0Z2RndWxnR1RDS3duc2d4VC5kYlR0KEJZdDdkZ250ICgpIHsKICAgICAgICAgICAgZ0IgKFNNNUFXSUhfS2VNNU1lTTYzTVBbdHVzVF0gPT09IFl0Q1RCZ3RUQykgewogICAgICAgICAgICAgICAgZGJ3bm8gdFRvIE13d253KCdWd1RCVHdUdDdUeFBUZDogXCcnICsgdHVzVCArICdcJyBneCBZdENUQmd0VEMuJyk7CiAgICAgICAgICAgIH0gVGx4VCBnQiAoanVsWVQgPT09IFl0Q1RCZ3RUQykgewogICAgICAgICAgICAgICAgZGJ3bm8gdFRvIE13d253KCdWd1RCVHdUdDdUeFBUZDogdG4ganVsWVQgZ3ggeFZUN2dCZ1RDLicpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGp1dyBqdWxZVEhrVlQgPSBka1ZUbkIganVsWVQ7CiAgICAgICAgICAgIGp1dyBDVEJ1WWxkSGtWVCA9IGRrVlRuQiBTTTVBV0lIX0tlTTVNZU02M01QW3R1c1RdOwoKICAgICAgICAgICAgZ0IgKGp1bFlUSGtWVCAhPT0gQ1RCdVlsZEhrVlQpIHsKICAgICAgICAgICAgICAgIGdCIChqdWxZVEhrVlQgPT09ICd0WXMwVHcnICYmIENUQnVZbGRIa1ZUID09PSAneGR3Z3RFJykgewogICAgICAgICAgICAgICAgICAgIGp1bFlUID0ganVsWVQuZG5QZHdndEUoKTsKICAgICAgICAgICAgICAgIH0gVGx4VCB7CiAgICAgICAgICAgICAgICAgICAgZGJ3bm8gdFRvIE13d253KCdLd1RCVHdUdDdUeF94VGQ6IFwnJyArIGp1bFlUICsgJ1wnIGd4IHUgXCInICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGp1bFlUSGtWVCArICdcIiwgVHJWVDdkVEMgXCInICsgQ1RCdVlsZEhrVlQgKyAnXCIuJyk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0gVGx4VCB7CiAgICAgICAgICAgICAgICBnQiAoanVsWVRIa1ZUID09PSAndFlzMFR3JyAmJiAoanVsWVQgfCB2KSAhPT0ganVsWVQpIHsKICAgICAgICAgICAgICAgICAgICBkYndubyB0VG8gTXd3bncoJ0t3VEJUd1R0N1R4X3hUZDogXCcnICsganVsWVQgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1wnIHNZeGQgMFQgdXQgXCJndGRURVR3XCIuJyk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZGJneC5Wd1RCeFt0dXNUXSA9IGp1bFlUOwogICAgICAgICAgICB3VGRZd3QgZGJneC5fb3dnZFRIblBkbnd1RVQoZGJneC5Wd1RCeCk7CiAgICAgICAgfS4wZ3RDKGRiZ3gpKTsKICAgIH0sCiAgICAvKioKICAgICAqIHBUZCBkYlQganVsWVQgbkIgdSBWd1RCVHdUdDdULgogICAgICogQFZ1d3VzIHt4ZHdndEV9IHR1c1QgSGJUIHR1c1QgbkIgZGJUIFZ3VEJUd1R0N1Qgb2JueFQganVsWVQgZ3ggd1RRWVR4ZFRDLgogICAgICogQHdUZFl3dCB7S3duc2d4VH0gQSBWd25zZ3hUIGRidWQgZ3ggd1R4bmxqVEMgb2dkYiB1IHswbm5sVHV0fHRZczBUd3x4ZHdndEV9CiAgICAgKiAgICAgICAgICAgICAgICAgICA3bnRkdWd0Z3RFIGRiVCBqdWxZVCBuQiBkYlQgVndUQlR3VHQ3VC4KICAgICAqLwogICAgRVRkOiBCWXQ3ZGdudCBWd1RCVHdUdDdUeHBUZCh0dXNUKSB7CiAgICAgICAgd1RkWXd0IGRiZ3guZ3RnZGd1bGdHVENLd25zZ3hULmRiVHQoQll0N2RnbnQgKCkgewogICAgICAgICAgICBqdXcgQ1RCdVlsZE51bFlUID0gU001QVdJSF9LZU01TWVNNjNNUFt0dXNUXTsKCiAgICAgICAgICAgIGdCIChDVEJ1WWxkTnVsWVQgPT09IFl0Q1RCZ3RUQykgewogICAgICAgICAgICAgICAgZGJ3bm8gdFRvIE13d253KCdWd1RCVHdUdDdUeHBUZDogXCcnICsgdHVzVCArICdcJyBneCBZdENUQmd0VEMuJyk7CiAgICAgICAgICAgIH0gVGx4VCB7CiAgICAgICAgICAgICAgICBqdXcgVndUQk51bFlUID0gZGJneC5Wd1RCeFt0dXNUXTsKCiAgICAgICAgICAgICAgICBnQiAoVndUQk51bFlUICE9PSBZdENUQmd0VEMpIHsKICAgICAgICAgICAgICAgICAgICB3VGRZd3QgVndUQk51bFlUOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIHdUZFl3dCBDVEJ1WWxkTnVsWVQ7CiAgICAgICAgfS4wZ3RDKGRiZ3gpKTsKICAgIH0KfTsKCkt3VEJUd1R0N1R4Ll9vd2dkVEhuUGRud3VFVCA9IEJZdDdkZ250IChWd1RCOTAxKSB7CiAgICB3VGRZd3QgdFRvIEt3bnNneFQoQll0N2RnbnQgKHdUeG5salQpIHsKICAgICAgICBsbjd1bFBkbnd1RVQueFRkZmRUcygnVkNCMXguVndUQlR3VHQ3VHgnLCB5UDk2Lnhkd2d0RWdCayhWd1RCOTAxKSk7CiAgICAgICAgd1R4bmxqVCgpOwogICAgfSk7Cn07CgpLd1RCVHdUdDdUeC5fd1R1QzV3bnNQZG53dUVUID0gQll0N2RnbnQgKFZ3VEI5MDEpIHsKICAgIHdUZFl3dCB0VG8gS3duc2d4VChCWXQ3ZGdudCAod1R4bmxqVCkgewogICAgICAgIGp1dyB3VHVDS3dUQnggPSB5UDk2LlZ1d3hUKGxuN3VsUGRud3VFVC5FVGRmZFRzKCdWQ0IxeC5Wd1RCVHdUdDdUeCcpKTsKICAgICAgICB3VHhubGpUKHdUdUNLd1RCeCk7CiAgICB9KTsKfTsKCiAgICAgICAgJChCWXQ3ZGdudCgpIHsgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQoJyNWd2d0ZCcpLjdsZzdPKEJZdDdkZ250KCl7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBqdXcgc1RDZ3VoWVR3a0lneGQgPSBvZ3RDbm8uc3VkN2JxVENndSgnVndndGQnKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNUQ2d1aFlUd2tJZ3hkLnVDQ0lneGRUdFR3KEJZdDdkZ250KHNRbCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdCIChzUWwuc3VkN2JUeCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA3bnR4bmxULmxuRSgnMFRCbndUIFZ3Z3RkIENndWxuRSBuVlR0Jyk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSBUbHhUIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDdudHhubFQubG5FKCd1QmRUdyBWd2d0ZCBDZ3VsbkUgN2xueFRDJyk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ndENuby5sbjd1ZGdudC53VGxudUMoKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7IAogICAgICAgICAgICAgICAgICAgICAgICB9KTsKKEJZdDdkZ250IHNuR0t3Z3RkM3VsbDB1N09LbmxrQmdsbDNsbnhZd1QoKSB7CiAgICBnQiAoJ3NuR0t3Z3RkM3VsbDB1N08nIGd0IENuN1lzVHRkLjd3VHVkVE1sVHNUdGQoJzd1dGp1eCcpKSB7CiAgICAgICAgd1RkWXd0OwogICAgfQogICAgLy8gM3VZeFQgVm54Z2RnalQgd1R4WWxkIG50IEJUdWRZd1QtQ1RkVDdkZ250OgogICAgMkhxSTN1dGp1eE1sVHNUdGQuVnduZG5ka1ZULnNuR0t3Z3RkM3VsbDB1N08gPSBZdENUQmd0VEM7CgogICAganV3IDd1dGp1eFR4OyAgIC8vIFNZd2d0RSBWd2d0ZCBkdXhPOiB0bnQtbGdqVCA2bkNUSWd4ZCBuQiA8N3V0anV4PiBUbFRzVHRkeAogICAganV3IGd0Q1RyOyAgICAgIC8vIGZ0Q1RyIG5CIDw3dXRqdXg+IFRsVHNUdGQgZGJ1ZCBneCAwVGd0RSBWd243VHh4VEMKCiAgICBqdXcgVndndGQgPSBvZ3RDbm8uVndndGQ7CiAgICBvZ3RDbm8uVndndGQgPSBCWXQ3ZGdudCBWd2d0ZCgpIHsKICAgICAgIAogICAgICAgIGdCICg3dXRqdXhUeCkgewogICAgICAgICAgICA3bnR4bmxULm91d3QoJ2ZFdG53VEMgb2d0Q25vLlZ3Z3RkKCkgMFQ3dVl4VCBuQiB1IFZUdENndEUgVndndGQgMW4wLicpOwogICAgICAgICAgICB3VGRZd3Q7CiAgICAgICAgfQogICAgICAgIGR3ayB7CiAgICAgICAgICAgIENneFZ1ZDdiTWpUdGQoJzBUQm53VFZ3Z3RkJyk7CiAgICAgICAgfSBCZ3R1bGxrIHsKICAgICAgICAgICAgN3V0anV4VHggPSBDbjdZc1R0ZC5RWVR3a1BUbFQ3ZG53QWxsKCc3dXRqdXgnKTsKICAgICAgICAgICAgZ3RDVHIgPSAtejsKICAgICAgICAgICAgdFRyZCgpOwogICAgICAgIH0KICAgIH07CgogICAgQll0N2RnbnQgQ2d4VnVkN2JNalR0ZChUalR0ZEhrVlQpIHsKICAgICAgICBqdXcgVGpUdGQgPSBDbjdZc1R0ZC43d1R1ZFRNalR0ZCgnM1l4ZG5zTWpUdGQnKTsKICAgICAgICBUalR0ZC5ndGdkM1l4ZG5zTWpUdGQoVGpUdGRIa1ZULCBCdWx4VCwgQnVseFQsICc3WXhkbnMnKTsKICAgICAgICBvZ3RDbm8uQ2d4VnVkN2JNalR0ZChUalR0ZCk7CiAgICB9CgogICAgQll0N2RnbnQgdFRyZCgpIHsKICAgICAgICBnQiAoITd1dGp1eFR4KSB7CiAgICAgICAgICAgIHdUZFl3dDsgLy8gS3dndGQgZHV4TyA3dXQ3VGxsVEMgMGsgWXhUdyAoeGR1ZFQgd1R4VGQgZ3QgdTBud2QoKSkKICAgICAgICB9CgogICAgICAgIHdUdENUd0t3bkV3VHh4KCk7CiAgICAgICAgZ0IgKCsrZ3RDVHIgPCA3dXRqdXhUeC5sVHRFZGIpIHsKICAgICAgICAgICAganV3IDd1dGp1eCA9IDd1dGp1eFR4W2d0Q1RyXTsKICAgICAgICAgICAgZ0IgKGRrVlRuQiA3dXRqdXguc25HS3dndGQzdWxsMHU3TyA9PT0gJ0JZdDdkZ250JykgewogICAgICAgICAgICAgICAgN3V0anV4LnNuR0t3Z3RkM3VsbDB1N08oewogICAgICAgICAgICAgICAgICAgIDdudGRUcmQ6IDd1dGp1eC5FVGQzbnRkVHJkKCdaQycpLAogICAgICAgICAgICAgICAgICAgIHUwbndkOiB1MG53ZCwKICAgICAgICAgICAgICAgICAgICBDbnRUOiB0VHJkCiAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgfSBUbHhUIHsKICAgICAgICAgICAgICAgIHRUcmQoKTsKICAgICAgICAgICAgfQogICAgICAgIH0gVGx4VCB7CiAgICAgICAgICAgIHdUdENUd0t3bkV3VHh4KCk7CiAgICAgICAgICAgIFZ3Z3RkLjd1bGwob2d0Q25vKTsKICAgICAgICAgICAgeFRkSGdzVG5ZZCh1MG53ZCwgWnYpOyAvLyBIZ0NrLVlWCiAgICAgICAgfQogICAgfQoKICAgIEJZdDdkZ250IHUwbndkKCkgewogICAgICAgIGdCICg3dXRqdXhUeCkgewogICAgICAgICAgICA3dXRqdXhUeCA9IHRZbGw7CiAgICAgICAgICAgIHdUdENUd0t3bkV3VHh4KCk7CiAgICAgICAgICAgIENneFZ1ZDdiTWpUdGQoJ3VCZFR3VndndGQnKTsKICAgICAgICB9CiAgICB9CgogICAgQll0N2RnbnQgd1R0Q1R3S3duRXdUeHgoKSB7CiAgICAgICAganV3IFZ3bkV3VHh4M250ZHVndFR3ID0gQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ3NuR0t3Z3RkM3VsbDB1N08teGJncycpOwogICAgICAgIGdCICg3dXRqdXhUeCAmJiA3dXRqdXhUeC5sVHRFZGIpIHsKICAgICAgICAgICAganV3IFZ3bkV3VHh4ID0gcXVkYi53bll0Qyh6dnYgKiBndENUciAvIDd1dGp1eFR4LmxUdEVkYik7CiAgICAgICAgICAgIGp1dyBWd25Fd1R4eEZ1dyA9IFZ3bkV3VHh4M250ZHVndFR3LlFZVHdrUFRsVDdkbncoJ1Z3bkV3VHh4Jyk7CiAgICAgICAgICAgIGp1dyBWd25Fd1R4eEtUdzcgPSBWd25Fd1R4eDNudGR1Z3RUdy5RWVR3a1BUbFQ3ZG53KCcud1RsdWRnalQtVnduRXdUeHgnKTsKICAgICAgICAgICAgVnduRXdUeHhGdXcuanVsWVQgPSBWd25Fd1R4eDsKICAgICAgICAgICAgVnduRXdUeHhLVHc3LmRUcmQzbnRkVHRkID0gVnduRXdUeHggKyAnJSc7CiAgICAgICAgICAgIFZ3bkV3VHh4M250ZHVndFR3LndUc25qVEFkZHdnMFlkVCgnYmdDQ1R0Jyk7CiAgICAgICAgICAgIFZ3bkV3VHh4M250ZHVndFR3Lm50N2xnN08gPSB1MG53ZDsKICAgICAgICB9IFRseFQgewogICAgICAgICAgICBWd25Fd1R4eDNudGR1Z3RUdy54VGRBZGR3ZzBZZFQoJ2JnQ0NUdCcsICcnKTsKICAgICAgICB9CiAgICB9CgogICAganV3IGJ1eEFkZHU3Yk1qVHRkID0gISFDbjdZc1R0ZC51ZGR1N2JNalR0ZDsKCiAgICBvZ3RDbm8udUNDTWpUdGRJZ3hkVHRUdygnT1RrQ25vdCcsIEJZdDdkZ250IChUalR0ZCkgewogICAgICAgIC8vIGZ0ZFR3N1RWZCAzc0MvM2R3bCArIEsgZ3QgdWxsIDB3bm94VHd4LgogICAgICAgIC8vIEFseG4gZ3RkVHc3VFZkIDNzQy8zZHdsICsgUGJnQmQgKyBLIGd0IDNid25zVCB1dEMgOVZUd3UKICAgICAgICBnQiAoVGpUdGQuT1RrM25DVCA9PT0gVXYvKksqLyAmJiAoVGpUdGQuN2R3bFJUayB8fCBUalR0ZC5zVGR1UlRrKSAmJgogICAgICAgICAgICAgICAgIVRqVHRkLnVsZFJUayAmJiAoIVRqVHRkLnhiZ0JkUlRrIHx8IG9ndENuby43Ynduc1QgfHwgb2d0Q25vLm5WVHd1KSkgewogICAgICAgICAgICAvL29ndENuby5Wd2d0ZCgpOwogICAgICAgICAgICBnQiAoYnV4QWRkdTdiTWpUdGQpIHsKICAgICAgICAgICAgICAgIC8vIDl0bGsgdWRkdTdiTWpUdGQgN3V0IDd1dDdUbCAzZHdsICsgSyBDZ3VsbkUgZ3QgZk0gPD16dgogICAgICAgICAgICAgICAgLy8gdWRkdTdiTWpUdGQgZ3ggRW50VCBndCBmTXp6LCB4biBkYlQgQ2d1bG5FIG9nbGwgd1QtdVZWVHV3IGd0IGZNenouCiAgICAgICAgICAgICAgICB3VGRZd3Q7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgVGpUdGQuVndUalR0ZFNUQnVZbGQoKTsKICAgICAgICAgICAgZ0IgKFRqVHRkLnhkblZmc3NUQ2d1ZFRLd25WdUV1ZGdudCkgewogICAgICAgICAgICAgICAgVGpUdGQueGRuVmZzc1RDZ3VkVEt3blZ1RXVkZ250KCk7CiAgICAgICAgICAgIH0gVGx4VCB7CiAgICAgICAgICAgICAgICBUalR0ZC54ZG5WS3duVnVFdWRnbnQoKTsKICAgICAgICAgICAgfQogICAgICAgICAgICB3VGRZd3Q7CiAgICAgICAgfQogICAgICAgIGdCIChUalR0ZC5PVGszbkNUID09PSBaYSAmJiA3dXRqdXhUeCkgeyAvLyBNeDcKICAgICAgICAgICAgdTBud2QoKTsKICAgICAgICB9CiAgICB9LCBkd1lUKTsKICAgIGdCIChidXhBZGR1N2JNalR0ZCkgewogICAgICAgIENuN1lzVHRkLnVkZHU3Yk1qVHRkKCdudE9Ua0Nub3QnLCBCWXQ3ZGdudCAoVGpUdGQpIHsKICAgICAgICAgICAgVGpUdGQgPSBUalR0ZCB8fCBvZ3RDbm8uVGpUdGQ7CiAgICAgICAgICAgIGdCIChUalR0ZC5PVGszbkNUID09PSBVdi8qSyovICYmIFRqVHRkLjdkd2xSVGspIHsKICAgICAgICAgICAgICAgIFRqVHRkLk9UazNuQ1QgPSB2OwogICAgICAgICAgICAgICAgd1RkWXd0IEJ1bHhUOwogICAgICAgICAgICB9CiAgICAgICAgfSk7CiAgICB9CgogICAgZ0IgKCdudDBUQm53VFZ3Z3RkJyBndCBvZ3RDbm8pIHsKICAgICAgICAvLyBTbiB0bmQgVnduVnVFdWRUIDBUQm53VC91QmRUd1Z3Z3RkIFRqVHRkeCBvYlR0IGRiVGsgdXdUIHRuZCBkd2dFRVR3VEMKICAgICAgICAvLyBCd25zIG9nZGJndCBkYmd4IFZubGtCZ2xsLiAoNTUvZk0pLgogICAgICAgIGp1dyB4ZG5WS3duVnVFdWRnbnRmQjZUVENUQyA9IEJZdDdkZ250IChUalR0ZCkgewogICAgICAgICAgICBnQiAoVGpUdGQuQ1RkdWdsICE9PSAnN1l4ZG5zJyAmJiBUalR0ZC54ZG5WZnNzVENndWRUS3duVnVFdWRnbnQpIHsKICAgICAgICAgICAgICAgIFRqVHRkLnhkblZmc3NUQ2d1ZFRLd25WdUV1ZGdudCgpOwogICAgICAgICAgICB9CiAgICAgICAgfTsKICAgICAgICBvZ3RDbm8udUNDTWpUdGRJZ3hkVHRUdygnMFRCbndUVndndGQnLCB4ZG5WS3duVnVFdWRnbnRmQjZUVENUQywgQnVseFQpOwogICAgICAgIG9ndENuby51Q0NNalR0ZElneGRUdFR3KCd1QmRUd1Z3Z3RkJywgeGRuVkt3blZ1RXVkZ250ZkI2VFRDVEMsIEJ1bHhUKTsKICAgIH0KfSkoKTsKCmp1dyBTbm90bG51Q3F1dHVFVHcgPSAoQll0N2RnbnQgU25vdGxudUNxdXR1RVR3M2xueFl3VCgpIHsKCiAgICAvKkJZdDdkZ250IENub3RsbnVDKDBsbjBXd2wsIEJnbFR0dXNUKSB7CiAgICAgICAganV3IHUgPSBDbjdZc1R0ZC43d1R1ZFRNbFRzVHRkKCd1Jyk7CiAgICAgICAgZ0IgKHUuN2xnN08pIHsKICAgICAgICAgICAgLy8gV3hUIHUuN2xnN08oKSBnQiB1anVnbHUwbFQuIDlkYlR3b2d4VCwgM2J3bnNUIHNnRWJkIHhibm8KICAgICAgICAgICAgLy8gIld0eHVCVCB5dWp1UDd3Z1ZkIHVkZFRzVmQgZG4gZ3RnZGd1ZFQgdSB0dWpnRXVkZ250IDdidXRFVAogICAgICAgICAgICAvLyAgQm53IEJ3dXNUIG9nZGIgV2VJIiB1dEMgdG5kIG5WVHQgZGJUIEtTNSB1ZCB1bGwuCiAgICAgICAgICAgIC8vIFBZVlZud2RUQyAwayAodG5kIHNUdGRnbnRUQyA9IFl0ZFR4ZFRDKToKICAgICAgICAgICAgLy8gLSA1Z3dUQm5yIEQgLSB6TCAoaS0gQ25UeCB0bmQgeFlWVm53ZCB1LjdsZzdPLCBjIGdFdG53VHggdS43bGc3TykKICAgICAgICAgICAgLy8gLSAzYnduc1QgekwgLSBaRCAoelUtIENuVHggdG5kIHhZVlZud2QgdS43bGc3TykKICAgICAgICAgICAgLy8gLSA5VlR3dSBMIC0gelouemMKICAgICAgICAgICAgLy8gLSBmdGRUd3RUZCBNclZsbndUdyBEIC0genYKICAgICAgICAgICAgLy8gLSBQdUJ1d2cgRCAoYy56LSBDblR4IHRuZCB4WVZWbndkIHUuN2xnN08pCiAgICAgICAgICAgIHUuYndUQiA9IDBsbjBXd2w7CiAgICAgICAgICAgIHUuZHV3RVRkID0gJ19WdXdUdGQnOwogICAgICAgICAgICAvLyBXeFQgdS5Dbm90bG51QyBnQiB1anVnbHUwbFQuIEhiZ3ggZ3Q3d1R1eFR4IGRiVCBsZ09UbGdibm5DIGRidWQKICAgICAgICAgICAgLy8gZGJUIEJnbFQgZ3ggQ25vdGxudUNUQyBndHhkVHVDIG5CIG5WVHRUQyAwayB1dG5kYlR3IEtTNSBWbFlFZ3QuCiAgICAgICAgICAgIGdCICgnQ25vdGxudUMnIGd0IHUpIHsKICAgICAgICAgICAgICAgIHUuQ25vdGxudUMgPSBCZ2xUdHVzVDsKICAgICAgICAgICAgfQogICAgICAgICAgICAvLyA8dT4gc1l4ZCAwVCBndCBkYlQgQ243WXNUdGQgQm53IGZNIHV0QyB3VDdUdGQgNWd3VEJuciBqVHd4Z250eC4KICAgICAgICAgICAgLy8gKG5kYlR3b2d4VCAuN2xnN08oKSBneCBnRXRud1RDKQogICAgICAgICAgICAoQ243WXNUdGQuMG5DayB8fCBDbjdZc1R0ZC5DbjdZc1R0ZE1sVHNUdGQpLnVWVlR0QzNiZ2xDKHUpOwogICAgICAgICAgICB1LjdsZzdPKCk7CiAgICAgICAgICAgIHUuVnV3VHRkNm5DVC53VHNualQzYmdsQyh1KTsKICAgICAgICB9IFRseFQgewogICAgICAgICAgICBnQiAob2d0Q25vLmRuViA9PT0gb2d0Q25vICYmCiAgICAgICAgICAgICAgICAgICAgMGxuMFd3bC54VmxnZCgnIycpW3ZdID09PSBvZ3RDbm8ubG43dWRnbnQuYndUQi54VmxnZCgnIycpW3ZdKSB7CiAgICAgICAgICAgICAgICAvLyBmQiBfVnV3VHRkID09IHhUbEIsIGRiVHQgblZUdGd0RSB1dCBnQ1R0ZGc3dWwgV2VJIG9nZGIgQ2dCQlR3VHRkCiAgICAgICAgICAgICAgICAvLyBsbjd1ZGdudCBidXhiIG9nbGwgbnRsayA3dVl4VCB1IHR1amdFdWRnbnQsIHRuZCB1IENub3RsbnVDLgogICAgICAgICAgICAgICAganV3IFZ1QzNidXd1N2RUdyA9IDBsbjBXd2wuZ3RDVHI5QignPycpID09PSAteiA/ICc/JyA6ICcmJzsKICAgICAgICAgICAgICAgIDBsbjBXd2wgPSAwbG4wV3dsLndUVmx1N1QoLyN8JC8sIFZ1QzNidXd1N2RUdyArICckJicpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIG9ndENuby5uVlR0KDBsbjBXd2wsICdfVnV3VHRkJyk7CiAgICAgICAgfQogICAgfSovCgogICAgQll0N2RnbnQgU25vdGxudUNxdXR1RVR3KCkge30KCiAgICAvKlNub3RsbnVDcXV0dUVUdy5Wd25kbmRrVlQgPSB7CiAgICAgICAgQ25vdGxudUNXd2w6IEJZdDdkZ250IFNub3RsbnVDcXV0dUVUd19Dbm90bG51Q1d3bChZd2wsIEJnbFR0dXNUKSB7CiAgICAgICAgICAgIGdCICghS1M1eVAuZ3hOdWxnQ1d3bChZd2wsIGR3WVQpKSB7CiAgICAgICAgICAgICAgICB3VGRZd3Q7IC8vIHdUeGR3ZzdkVEMvZ3RqdWxnQyBXZUkKICAgICAgICAgICAgfQoKICAgICAgICAgICAgQ25vdGxudUMoWXdsICsgJyNWQ0IxeC51N2RnbnQ9Q25vdGxudUMnLCBCZ2xUdHVzVCk7CiAgICAgICAgfSwKICAgICAgICBDbm90bG51Q1N1ZHU6IEJZdDdkZ250IFNub3RsbnVDcXV0dUVUd19Dbm90bG51Q1N1ZHUoQ3VkdSwgQmdsVHR1c1QsCiAgICAgICAgICAgICAgICA3bnRkVHRkSGtWVCkgewogICAgICAgICAgICBnQiAodHVqZ0V1ZG53LnN4UHVqVEZsbjApIHsgLy8gZk16diB1dEMgdTBualQKICAgICAgICAgICAgICAgIHdUZFl3dCB0dWpnRXVkbncuc3hQdWpURmxuMCh0VG8gRmxuMChbQ3VkdV0sIHtka1ZUOiA3bnRkVHRkSGtWVH0pLAogICAgICAgICAgICAgICAgICAgICAgICBCZ2xUdHVzVCk7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGp1dyAwbG4wV3dsID0gS1M1eVAuN3dUdWRUOTAxVDdkV2VJKEN1ZHUsIDdudGRUdGRIa1ZUKTsKICAgICAgICAgICAgQ25vdGxudUMoMGxuMFd3bCwgQmdsVHR1c1QpOwogICAgICAgIH0sCiAgICAgICAgQ25vdGxudUM6IEJZdDdkZ250IFNub3RsbnVDcXV0dUVUd19Dbm90bG51QygwbG4wLCBZd2wsIEJnbFR0dXNUKSB7CgogICAgICAgICAgICBnQiAoIVdlSSkgewogICAgICAgICAgICAgICAgLy8gV2VJLjd3VHVkVDkwMVQ3ZFdlSSBneCB0bmQgeFlWVm53ZFRDCiAgICAgICAgICAgICAgICBkYmd4LkNub3RsbnVDV3dsKFl3bCwgQmdsVHR1c1QpOwogICAgICAgICAgICAgICAgd1RkWXd0OwogICAgICAgICAgICB9CgogICAgICAgICAgICBnQiAodHVqZ0V1ZG53LnN4UHVqVEZsbjApIHsKICAgICAgICAgICAgICAgIC8vIGZNenYgLyBmTXp6CiAgICAgICAgICAgICAgICBnQiAoIXR1amdFdWRudy5zeFB1alRGbG4wKDBsbjAsIEJnbFR0dXNUKSkgewogICAgICAgICAgICAgICAgICAgIGRiZ3guQ25vdGxudUNXd2woWXdsLCBCZ2xUdHVzVCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB3VGRZd3Q7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGp1dyAwbG4wV3dsID0gV2VJLjd3VHVkVDkwMVQ3ZFdlSSgwbG4wKTsKICAgICAgICAgICAgQ25vdGxudUMoMGxuMFd3bCwgQmdsVHR1c1QpOwogICAgICAgIH0KICAgIH07CgogICAgd1RkWXd0IFNub3RsbnVDcXV0dUVUdzsgKi8KfSkoKTsKCi8qKgogKiBOZ1RvIDJneGRud2sgLSBIYmd4IGd4IHUgWWRnbGdkayBCbncgeHVqZ3RFIGp1d2duWXggamdUbyBWdXd1c1RkVHd4IEJudwogKiAgICAgICAgICAgICAgICB3VDdUdGRsayBuVlR0VEMgQmdsVHguCiAqCiAqIEhiVCBvdWsgZGJ1ZCBkYlQgamdUbyBWdXd1c1RkVHd4IHV3VCB4ZG53VEMgQ1RWVHRDeCBudCBibm8gS1M1LjF4IGd4IDBZZ2xkLAogKiBCbncgJ3RuQ1Qgc3VPVCA8Qmx1RT4nIGRiVCBCbmxsbm9ndEUgN3V4VHggVHJneGQ6CiAqICAtIDVmZU01OUogbncgcTlYM002SGVBSSAtIFl4VHggeFR4eGdudFBkbnd1RVQuCiAqICAtIHBNNk1lZjMgbncgMzJlOXFNICAgICAtIFl4VHggbG43dWxQZG53dUVULCBnQiBnZCBneCB1anVnbHUwbFQuCiAqLwpqdXcgTmdUbzJneGRud2sgPSAoQll0N2RnbnQgTmdUbzJneGRud2szbG54WXdUKCkgewogICAgQll0N2RnbnQgTmdUbzJneGRud2soQmd0RVR3VndndGQpIHsKICAgICAgICBkYmd4LkJndEVUd1Z3Z3RkID0gQmd0RVR3VndndGQ7CiAgICAgICAgZGJneC5neGZ0Z2RndWxnR1RDS3duc2d4VGVUeG5salRDID0gQnVseFQ7CiAgICAgICAgZGJneC5ndGdkZ3VsZ0dUQ0t3bnNneFQgPQogICAgICAgICAgICAgICAgZGJneC5fd1R1QzV3bnNQZG53dUVUKCkuZGJUdChCWXQ3ZGdudCAoQ3VkdTB1eFRQZHcpIHsKICAgICAgICAgICAgZGJneC5neGZ0Z2RndWxnR1RDS3duc2d4VGVUeG5salRDID0gZHdZVDsKCiAgICAgICAgICAgIGp1dyBDdWR1MHV4VCA9IHlQOTYuVnV3eFQoQ3VkdTB1eFRQZHcgfHwgJ3t9Jyk7CiAgICAgICAgICAgIGdCICghKCdCZ2xUeCcgZ3QgQ3VkdTB1eFQpKSB7CiAgICAgICAgICAgICAgICBDdWR1MHV4VC5CZ2xUeCA9IFtdOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGdCIChDdWR1MHV4VC5CZ2xUeC5sVHRFZGIgPj0gTmZNOF8yZlBIOWU0X3FNcTllNCkgewogICAgICAgICAgICAgICAgQ3VkdTB1eFQuQmdsVHgueGJnQmQoKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBqdXcgZ3RDVHI7CiAgICAgICAgICAgIEJudyAoanV3IGcgPSB2LCBsVHRFZGIgPSBDdWR1MHV4VC5CZ2xUeC5sVHRFZGI7IGcgPCBsVHRFZGI7IGcrKykgewogICAgICAgICAgICAgICAganV3IDB3dXQ3YiA9IEN1ZHUwdXhULkJnbFR4W2ddOwogICAgICAgICAgICAgICAgZ0IgKDB3dXQ3Yi5CZ3RFVHdWd2d0ZCA9PT0gZGJneC5CZ3RFVHdWd2d0ZCkgewogICAgICAgICAgICAgICAgICAgIGd0Q1RyID0gZzsKICAgICAgICAgICAgICAgICAgICAwd1R1TzsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBnQiAoZGtWVG5CIGd0Q1RyICE9PSAndFlzMFR3JykgewogICAgICAgICAgICAgICAgZ3RDVHIgPSBDdWR1MHV4VC5CZ2xUeC5WWXhiKHtCZ3RFVHdWd2d0ZDogZGJneC5CZ3RFVHdWd2d0ZH0pIC0gejsKICAgICAgICAgICAgfQogICAgICAgICAgICBkYmd4LkJnbFQgPSBDdWR1MHV4VC5CZ2xUeFtndENUcl07CiAgICAgICAgICAgIGRiZ3guQ3VkdTB1eFQgPSBDdWR1MHV4VDsKICAgICAgICB9LjBndEMoZGJneCkpOwogICAgfQoKICAgIE5nVG8yZ3hkbndrLlZ3bmRuZGtWVCA9IHsKICAgICAgICBfb3dnZFRIblBkbnd1RVQ6IEJZdDdkZ250IE5nVG8yZ3hkbndrX293Z2RUSG5QZG53dUVUKCkgewogICAgICAgICAgICB3VGRZd3QgdFRvIEt3bnNneFQoQll0N2RnbnQgKHdUeG5salQpIHsKICAgICAgICAgICAgICAgIGp1dyBDdWR1MHV4VFBkdyA9IHlQOTYueGR3Z3RFZ0JrKGRiZ3guQ3VkdTB1eFQpOwoKCiAgICAgICAgICAgICAgICBsbjd1bFBkbnd1RVQueFRkZmRUcygnQ3VkdTB1eFQnLCBDdWR1MHV4VFBkdyk7CiAgICAgICAgICAgICAgICB3VHhubGpUKCk7CiAgICAgICAgICAgIH0uMGd0QyhkYmd4KSk7CiAgICAgICAgfSwKICAgICAgICBfd1R1QzV3bnNQZG53dUVUOiBCWXQ3ZGdudCBOZ1RvMmd4ZG53a193VHVDNXduc1Bkbnd1RVQoKSB7CiAgICAgICAgICAgIHdUZFl3dCB0VG8gS3duc2d4VChCWXQ3ZGdudCAod1R4bmxqVCkgewoKICAgICAgICAgICAgICAgIHdUeG5salQobG43dWxQZG53dUVULkVUZGZkVHMoJ0N1ZHUwdXhUJykpOwogICAgICAgICAgICB9KTsKICAgICAgICB9LAogICAgICAgIHhUZDogQll0N2RnbnQgTmdUbzJneGRud2tfeFRkKHR1c1QsIGp1bCkgewogICAgICAgICAgICBnQiAoIWRiZ3guZ3hmdGdkZ3VsZ0dUQ0t3bnNneFRlVHhubGpUQykgewogICAgICAgICAgICAgICAgd1RkWXd0OwogICAgICAgICAgICB9CiAgICAgICAgICAgIGRiZ3guQmdsVFt0dXNUXSA9IGp1bDsKICAgICAgICAgICAgd1RkWXd0IGRiZ3guX293Z2RUSG5QZG53dUVUKCk7CiAgICAgICAgfSwKICAgICAgICB4VGRxWWxkZ1ZsVDogQll0N2RnbnQgTmdUbzJneGRud2tfeFRkcVlsZGdWbFQoVnduVlR3ZGdUeCkgewogICAgICAgICAgICBnQiAoIWRiZ3guZ3hmdGdkZ3VsZ0dUQ0t3bnNneFRlVHhubGpUQykgewogICAgICAgICAgICAgICAgd1RkWXd0OwogICAgICAgICAgICB9CiAgICAgICAgICAgIEJudyAoanV3IHR1c1QgZ3QgVnduVlR3ZGdUeCkgewogICAgICAgICAgICAgICAgZGJneC5CZ2xUW3R1c1RdID0gVnduVlR3ZGdUeFt0dXNUXTsKICAgICAgICAgICAgfQogICAgICAgICAgICB3VGRZd3QgZGJneC5fb3dnZFRIblBkbnd1RVQoKTsKICAgICAgICB9LAogICAgICAgIEVUZDogQll0N2RnbnQgTmdUbzJneGRud2tfRVRkKHR1c1QsIENUQnVZbGROdWxZVCkgewogICAgICAgICAgICBnQiAoIWRiZ3guZ3hmdGdkZ3VsZ0dUQ0t3bnNneFRlVHhubGpUQykgewogICAgICAgICAgICAgICAgd1RkWXd0IENUQnVZbGROdWxZVDsKICAgICAgICAgICAgfQogICAgICAgICAgICB3VGRZd3QgZGJneC5CZ2xUW3R1c1RdIHx8IENUQnVZbGROdWxZVDsKICAgICAgICB9CiAgICB9OwoKICAgIHdUZFl3dCBOZ1RvMmd4ZG53azsKfSkoKTsKCi8qKgogKiAzd1R1ZFR4IHUgInhUdXc3YiAwdXciIEVnalR0IHUgeFRkIG5CIFM5cSBUbFRzVHRkeCBkYnVkIHU3ZCB1eCA3bnRkd25seAogKiBCbncgeFR1dzdiZ3RFIG53IEJudyB4VGRkZ3RFIHhUdXc3YiBWd1RCVHdUdDdUeCBndCBkYlQgV2YuIEhiZ3ggbjAxVDdkCiAqIHVseG4geFRkeCBZViBkYlQgdVZWd25Wd2d1ZFQgVGpUdGR4IEJudyBkYlQgN250ZHdubHguIEE3ZFl1bCB4VHV3N2JndEUKICogZ3ggQ250VCAwayBLUzU1Z3RDM250ZHdubGxUdy4KICovCmp1dyBLUzU1Z3RDRnV3ID0gKEJZdDdkZ250IEtTNTVndENGdXczbG54WXdUKCkgewogICAgQll0N2RnbnQgS1M1NWd0Q0Z1dyhuVmRnbnR4KSB7CiAgICAgICAgZGJneC5uVlR0VEMgPSBCdWx4VDsKICAgICAgICBkYmd4LjB1dyA9IG5WZGdudHguMHV3IHx8IHRZbGw7CiAgICAgICAgZGJneC5kbkVFbFRGWWRkbnQgPSBuVmRnbnR4LmRuRUVsVEZZZGRudCB8fCB0WWxsOwogICAgICAgIGRiZ3guQmd0QzVnVGxDID0gblZkZ250eC5CZ3RDNWdUbEMgfHwgdFlsbDsKICAgICAgICBkYmd4LkJndEM1Z1RsQy5qdWxZVCA9ICc8P1ZiViBUN2JuIHVDQ3hsdXhiVHgoJHhUdXc3Yl9vbndDKTsgPz4nOwogICAgICAgIGRiZ3guYmdFYmxnRWJkQWxsID0gblZkZ250eC5iZ0VibGdFYmRBbGwzYlQ3TzBuciB8fCB0WWxsOwogICAgICAgIGRiZ3guN3V4VFBUdHhnZGdqVCA9IG5WZGdudHguN3V4VFBUdHhnZGdqVDNiVDdPMG5yIHx8IHRZbGw7CiAgICAgICAgZGJneC5CZ3RDcXhFID0gblZkZ250eC5CZ3RDcXhFIHx8IHRZbGw7CiAgICAgICAgZGJneC5CZ3RDUGR1ZFl4ZjdudCA9IG5WZGdudHguQmd0Q1BkdWRZeGY3bnQgfHwgdFlsbDsKICAgICAgICBkYmd4LkJndENLd1RqZ25ZeEZZZGRudCA9IG5WZGdudHguQmd0Q0t3VGpnbll4RllkZG50IHx8IHRZbGw7CiAgICAgICAgZGJneC5CZ3RDNlRyZEZZZGRudCA9IG5WZGdudHguQmd0QzZUcmRGWWRkbnQgfHwgdFlsbDsKICAgICAgICBkYmd4LkJndEMzbnRkd25sbFR3ID0gblZkZ250eC5CZ3RDM250ZHdubGxUdyB8fCB0WWxsOwoKICAgICAgICBnQiAoZGJneC5CZ3RDM250ZHdubGxUdyA9PT0gdFlsbCkgewogICAgICAgICAgICBkYndubyB0VG8gTXd3bncoJ0tTNTVndENGdXcgN3V0dG5kIDBUIFl4VEMgb2dkYm5ZZCB1ICcgKwogICAgICAgICAgICAgICAgICAgICdLUzU1Z3RDM250ZHdubGxUdyBndHhkdXQ3VC4nKTsKICAgICAgICB9CgogICAgICAgIC8vIEFDQyBUalR0ZCBsZ3hkVHRUd3ggZG4gZGJUIFM5cSBUbFRzVHRkeC4KICAgICAgICBqdXcgeFRsQiA9IGRiZ3g7CiAgICAgICAgZGJneC5kbkVFbFRGWWRkbnQudUNDTWpUdGRJZ3hkVHRUdygnN2xnN08nLCBCWXQ3ZGdudCAoKSB7CiAgICAgICAgICAgIHhUbEIuZG5FRWxUKCk7CiAgICAgICAgfSk7CgogICAgICAgIGRiZ3guQmd0QzVnVGxDLnVDQ01qVHRkSWd4ZFR0VHcoJ2d0VllkJywgQll0N2RnbnQgKCkgewogICAgICAgICAgICB4VGxCLkNneFZ1ZDdiTWpUdGQoJycpOwogICAgICAgIH0pOwoKICAgICAgICBkYmd4LjB1dy51Q0NNalR0ZElneGRUdFR3KCdPVGtDbm90JywgQll0N2RnbnQgKFRqZCkgewogICAgICAgICAgICB4b2dkN2IgKFRqZC5PVGszbkNUKSB7CiAgICAgICAgICAgICAgICA3dXhUIHptOiAvLyBNdGRUdwogICAgICAgICAgICAgICAgICAgIGdCIChUamQuZHV3RVRkID09PSB4VGxCLkJndEM1Z1RsQykgewogICAgICAgICAgICAgICAgICAgICAgICB4VGxCLkNneFZ1ZDdiTWpUdGQoJ3VFdWd0JywgVGpkLnhiZ0JkUlRrKTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgMHdUdU87CiAgICAgICAgICAgICAgICA3dXhUIFphOiAvLyBNeDd1VlQKICAgICAgICAgICAgICAgICAgICB4VGxCLjdsbnhUKCk7CiAgICAgICAgICAgICAgICAgICAgMHdUdU87CiAgICAgICAgICAgIH0KICAgICAgICB9KTsKCiAgICAgICAgZGJneC5CZ3RDS3dUamduWXhGWWRkbnQudUNDTWpUdGRJZ3hkVHRUdygnN2xnN08nLCBCWXQ3ZGdudCAoKSB7CiAgICAgICAgICAgIHhUbEIuQ2d4VnVkN2JNalR0ZCgndUV1Z3QnLCBkd1lUKTsKICAgICAgICB9KTsKCiAgICAgICAgZGJneC5CZ3RDNlRyZEZZZGRudC51Q0NNalR0ZElneGRUdFR3KCc3bGc3TycsIEJZdDdkZ250ICgpIHsKICAgICAgICAgICAgeFRsQi5DZ3hWdWQ3Yk1qVHRkKCd1RXVndCcsIEJ1bHhUKTsKICAgICAgICB9KTsKCiAgICAgICAgZGJneC5iZ0VibGdFYmRBbGwudUNDTWpUdGRJZ3hkVHRUdygnN2xnN08nLCBCWXQ3ZGdudCAoKSB7CiAgICAgICAgICAgIHhUbEIuQ2d4VnVkN2JNalR0ZCgnYmdFYmxnRWJkdWxsN2J1dEVUJyk7CiAgICAgICAgfSk7CgogICAgICAgIGRiZ3guN3V4VFBUdHhnZGdqVC51Q0NNalR0ZElneGRUdFR3KCc3bGc3TycsIEJZdDdkZ250ICgpIHsKICAgICAgICAgICAgeFRsQi5DZ3hWdWQ3Yk1qVHRkKCc3dXhUeFR0eGdkZ2pnZGs3YnV0RVQnKTsKICAgICAgICB9KTsKICAgIH0KCiAgICBLUzU1Z3RDRnV3LlZ3bmRuZGtWVCA9IHsKICAgICAgICBDZ3hWdWQ3Yk1qVHRkOiBCWXQ3ZGdudCBLUzU1Z3RDRnV3X0NneFZ1ZDdiTWpUdGQoZGtWVCwgQmd0Q0t3VGopIHsKICAgICAgICAgICAganV3IFRqVHRkID0gQ243WXNUdGQuN3dUdWRUTWpUdGQoJzNZeGRuc01qVHRkJyk7CiAgICAgICAgICAgIFRqVHRkLmd0Z2QzWXhkbnNNalR0ZCgnQmd0QycgKyBka1ZULCBkd1lULCBkd1lULCB7CiAgICAgICAgICAgICAgICBRWVR3azogZGJneC5CZ3RDNWdUbEMuanVsWVQsCiAgICAgICAgICAgICAgICA3dXhUUFR0eGdkZ2pUOiBkYmd4Ljd1eFRQVHR4Z2RnalQuN2JUN09UQywKICAgICAgICAgICAgICAgIGJnRWJsZ0ViZEFsbDogZGJneC5iZ0VibGdFYmRBbGwuN2JUN09UQywKICAgICAgICAgICAgICAgIEJndENLd1RqZ25ZeDogQmd0Q0t3VGoKICAgICAgICAgICAgfSk7CiAgICAgICAgICAgIHdUZFl3dCBvZ3RDbm8uQ2d4VnVkN2JNalR0ZChUalR0ZCk7CiAgICAgICAgfSwKICAgICAgICBZVkN1ZFRXZlBkdWRUOiBCWXQ3ZGdudCBLUzU1Z3RDRnV3X1lWQ3VkVFdmUGR1ZFQoeGR1ZFQsIFZ3VGpnbll4KSB7CgogICAgICAgICAgICBqdXcgdG5kNW5ZdEMgPSBCdWx4VDsKICAgICAgICAgICAganV3IEJndENxeEUgPSAnJzsKICAgICAgICAgICAganV3IHhkdWRZeCA9ICcnOwoKICAgICAgICAgICAgeG9nZDdiICh4ZHVkVCkgewogICAgICAgICAgICAgICAgN3V4VCA1Z3RDUGR1ZFR4LjVmNlNfNTlXNlM6CiAgICAgICAgICAgICAgICAgICAgMHdUdU87CgogICAgICAgICAgICAgICAgN3V4VCA1Z3RDUGR1ZFR4LjVmNlNfS002U2Y2cDoKICAgICAgICAgICAgICAgICAgICB4ZHVkWXggPSAnVlR0Q2d0RSc7CiAgICAgICAgICAgICAgICAgICAgMHdUdU87CgogICAgICAgICAgICAgICAgN3V4VCA1Z3RDUGR1ZFR4LjVmNlNfNjlINTlXNlM6CiAgICAgICAgICAgICAgICAgICAgQmd0Q3F4RSA9IHNuR0l6dnQuRVRkKCdCZ3RDX3RuZF9Cbll0QycsIHRZbGwsICdLYnd1eFQgdG5kIEJuWXRDJyk7CiAgICAgICAgICAgICAgICAgICAgdG5kNW5ZdEMgPSBkd1lUOwogICAgICAgICAgICAgICAgICAgIDB3VHVPOwoKICAgICAgICAgICAgICAgIDd1eFQgNWd0Q1BkdWRUeC41ZjZTXzhlQUtLTVM6CiAgICAgICAgICAgICAgICAgICAgZ0IgKFZ3VGpnbll4KSB7CiAgICAgICAgICAgICAgICAgICAgICAgIEJndENxeEUgPSBzbkdJenZ0LkVUZCgnQmd0Q193VHU3YlRDX2RuVicsIHRZbGwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ2VUdTdiVEMgZG5WIG5CIENuN1lzVHRkLCA3bnRkZ3RZVEMgQnducyAwbmRkbnMnKTsKICAgICAgICAgICAgICAgICAgICB9IFRseFQgewogICAgICAgICAgICAgICAgICAgICAgICBCZ3RDcXhFID0gc25HSXp2dC5FVGQoJ0JndENfd1R1N2JUQ18wbmRkbnMnLCB0WWxsLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdlVHU3YlRDIFR0QyBuQiBDbjdZc1R0ZCwgN250ZGd0WVRDIEJ3bnMgZG5WJyk7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIDB3VHVPOwogICAgICAgICAgICB9CgogICAgICAgICAgICBnQiAodG5kNW5ZdEMpIHsKICAgICAgICAgICAgICAgIGRiZ3guQmd0QzVnVGxDLjdsdXh4SWd4ZC51Q0MoJ3RuZDVuWXRDJyk7CiAgICAgICAgICAgIH0gVGx4VCB7CiAgICAgICAgICAgICAgICBkYmd4LkJndEM1Z1RsQy43bHV4eElneGQud1RzbmpUKCd0bmQ1bll0QycpOwogICAgICAgICAgICB9CgogICAgICAgICAgICBkYmd4LkJndEM1Z1RsQy54VGRBZGR3ZzBZZFQoJ0N1ZHUteGR1ZFl4JywgeGR1ZFl4KTsKICAgICAgICAgICAgZGJneC5CZ3RDcXhFLmRUcmQzbnRkVHRkID0gQmd0Q3F4RTsKICAgICAgICB9LAogICAgICAgIG5WVHQ6IEJZdDdkZ250IEtTNTVndENGdXdfblZUdCgpIHsKICAgICAgICAgICAgCiAgICAgICAgICAgIGdCICghZGJneC5uVlR0VEMpIHsKICAgICAgICAgICAgICAgIGRiZ3gublZUdFRDID0gZHdZVDsKICAgICAgICAgICAgICAgIGRiZ3guZG5FRWxURllkZG50LjdsdXh4SWd4ZC51Q0MoJ2RuRUVsVEMnKTsKICAgICAgICAgICAgICAgIGRiZ3guMHV3LjdsdXh4SWd4ZC53VHNualQoJ2JnQ0NUdCcpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGRiZ3guQmd0QzVnVGxDLnhUbFQ3ZCgpOwogICAgICAgICAgICBkYmd4LkJndEM1Z1RsQy5CbjdZeCgpOwogICAgICAgIH0sCiAgICAgICAgN2xueFQ6IEJZdDdkZ250IEtTNTVndENGdXdfN2xueFQoKSB7CiAgICAgICAgICAgIGdCICghZGJneC5uVlR0VEMpIHsKICAgICAgICAgICAgICAgIHdUZFl3dDsKICAgICAgICAgICAgfQogICAgICAgICAgICBkYmd4Lm5WVHRUQyA9IEJ1bHhUOwogICAgICAgICAgICBkYmd4LmRuRUVsVEZZZGRudC43bHV4eElneGQud1RzbmpUKCdkbkVFbFRDJyk7CiAgICAgICAgICAgIGRiZ3guMHV3LjdsdXh4SWd4ZC51Q0MoJ2JnQ0NUdCcpOwogICAgICAgICAgICBkYmd4LkJndEMzbnRkd25sbFR3LnU3ZGdqVCA9IEJ1bHhUOwogICAgICAgIH0sCiAgICAgICAgZG5FRWxUOiBCWXQ3ZGdudCBLUzU1Z3RDRnV3X2RuRUVsVCgpIHsKICAgICAgICAgICAgZ0IgKGRiZ3gublZUdFRDKSB7CiAgICAgICAgICAgICAgICBkYmd4LjdsbnhUKCk7CiAgICAgICAgICAgIH0gVGx4VCB7CiAgICAgICAgICAgICAgICBkYmd4Lm5WVHQoKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH07CiAgICB3VGRZd3QgS1M1NWd0Q0Z1dzsKfSkoKTsKCmp1dyA1Z3RDUGR1ZFR4ID0gewogICAgNWY2U181OVc2UzogdiwKICAgIDVmNlNfNjlINTlXNlM6IHosCiAgICA1ZjZTXzhlQUtLTVM6IFosCiAgICA1ZjZTX0tNNlNmNnA6IG0KfTsKCmp1dyA1ZjZTX1AzZTlJSV85NTVQTUhfSDlLID0gLWN2OwpqdXcgNWY2U19QM2U5SUlfOTU1UE1IX0lNNUggPSAtaXZ2OwoKLyoqCiAqIEt3bmpnQ1R4ICJ4VHV3N2IiIG53ICJCZ3RDIiBCWXQ3ZGdudHVsZ2RrIEJudyBkYlQgS1M1LgogKiBIYmd4IG4wMVQ3ZCB1N2RZdWxsayBWVHdCbndzeCBkYlQgeFR1dzdiIEJudyB1IEVnalR0IHhkd2d0RS4KICovCmp1dyBLUzU1Z3RDM250ZHdubGxUdyA9IChCWXQ3ZGdudCBLUzU1Z3RDM250ZHdubGxUdzNsbnhZd1QoKSB7CiAgICBCWXQ3ZGdudCBLUzU1Z3RDM250ZHdubGxUdyhuVmRnbnR4KSB7CiAgICAgICAgZGJneC54ZHV3ZFRDSFRyZE1yZHd1N2RnbnQgPSBCdWx4VDsKICAgICAgICBkYmd4LlRyZHd1N2RIVHJkS3duc2d4VHggPSBbXTsKICAgICAgICBkYmd4LlZUdENndEU1Z3RDcXVkN2JUeCA9IHt9OwogICAgICAgIGRiZ3gudTdkZ2pUID0gQnVseFQ7IC8vIGZCIHU3ZGdqVCwgQmd0QyB3VHhZbGR4IG9nbGwgMFQgYmdFYmxnRWJkVEMuCiAgICAgICAgZGJneC5WdUVUM250ZFR0ZHggPSBbXTsgLy8gUGRud1R4IGRiVCBkVHJkIEJudyBUdTdiIFZ1RVQuCiAgICAgICAgZGJneC5WdUVUcXVkN2JUeCA9IFtdOwogICAgICAgIGRiZ3gueFRsVDdkVEMgPSB7Ly8gM1l3d1R0ZGxrIHhUbFQ3ZFRDIHN1ZDdiLgogICAgICAgICAgICBWdUVUZkNyOiAteiwKICAgICAgICAgICAgc3VkN2JmQ3I6IC16CiAgICAgICAgfTsKICAgICAgICBkYmd4Lm5CQnhUZCA9IHsvLyA4YlR3VCBkYlQgQmd0QyB1bEVud2dkYnMgN1l3d1R0ZGxrIGd4IGd0IGRiVCBDbjdZc1R0ZC4KICAgICAgICAgICAgVnVFVGZDcjogdFlsbCwKICAgICAgICAgICAgc3VkN2JmQ3I6IHRZbGwKICAgICAgICB9OwogICAgICAgIGRiZ3guVnVFVHhIblBUdXc3YiA9IHRZbGw7CiAgICAgICAgZGJneC53VHhZc1RLdUVUZkNyID0gdFlsbDsKICAgICAgICBkYmd4LnhkdWRUID0gdFlsbDsKICAgICAgICBkYmd4LkNnd2RrcXVkN2IgPSBCdWx4VDsKICAgICAgICBkYmd4LkJndENIZ3NUbllkID0gdFlsbDsKICAgICAgICBkYmd4LlZDQk5nVG9UdyA9IG5WZGdudHguVkNCTmdUb1R3IHx8IHRZbGw7CiAgICAgICAgZGJneC5ndGRURXd1ZFRDNWd0QyA9IG5WZGdudHguZ3RkVEV3dWRUQzVndEMgfHwgQnVseFQ7CiAgICAgICAgZGJneC43YnV3dTdkVHd4SG42bndzdWxnR1QgPSB7CiAgICAgICAgICAgICdcWVp2elUnOiAnXCcnLCAvLyBJVEJkIHhndEVsVCBRWW5kdWRnbnQgc3V3TwogICAgICAgICAgICAnXFladnpMJzogJ1wnJywgLy8gZWdFYmQgeGd0RWxUIFFZbmR1ZGdudCBzdXdPCiAgICAgICAgICAgICdcWVp2ekEnOiAnXCcnLCAvLyBQZ3RFbFQgbG5vLUwgUVluZHVkZ250IHN1d08KICAgICAgICAgICAgJ1xZWnZ6Ric6ICdcJycsIC8vIFBndEVsVCBiZ0ViLXdUalR3eFRDLUwgUVluZHVkZ250IHN1d08KICAgICAgICAgICAgJ1xZWnZ6Myc6ICciJywgLy8gSVRCZCBDblkwbFQgUVluZHVkZ250IHN1d08KICAgICAgICAgICAgJ1xZWnZ6Uyc6ICciJywgLy8gZWdFYmQgQ25ZMGxUIFFZbmR1ZGdudCBzdXdPCiAgICAgICAgICAgICdcWVp2ek0nOiAnIicsIC8vIFNuWTBsVCBsbm8tTCBRWW5kdWRnbnQgc3V3TwogICAgICAgICAgICAnXFladno1JzogJyInLCAvLyBTblkwbFQgYmdFYi13VGpUd3hUQy1MIFFZbmR1ZGdudCBzdXdPCiAgICAgICAgICAgICdcWXZ2RjMnOiAnei9pJywgLy8gTllsRXV3IEJ3dTdkZ250IG50VCBRWXV3ZFR3CiAgICAgICAgICAgICdcWXZ2RlMnOiAnei9aJywgLy8gTllsRXV3IEJ3dTdkZ250IG50VCBidWxCCiAgICAgICAgICAgICdcWXZ2Rk0nOiAnbS9pJywgLy8gTllsRXV3IEJ3dTdkZ250IGRid1RUIFFZdXdkVHd4CiAgICAgICAgICAgICdcWXZ2QXYnOiAnICcgLy8gNm4tMHdUdU8geFZ1N1QKICAgICAgICB9OwogICAgICAgIGRiZ3guQmd0Q0Z1dyA9IG5WZGdudHguQmd0Q0Z1dyB8fCB0WWxsOwoKICAgICAgICAvLyAzbnNWZ2xUIGRiVCB3VEVZbHV3IFRyVndUeHhnbnQgQm53IGRUcmQgdG53c3VsZ0d1ZGdudCBudDdUCiAgICAgICAganV3IHdUVmx1N1QgPSA5MDFUN2QuT1RreChkYmd4LjdidXd1N2RUd3hIbjZud3N1bGdHVCkuMW5ndCgnJyk7CiAgICAgICAgZGJneC50bndzdWxnR3VkZ250ZVRFVHIgPSB0VG8gZVRFTXJWKCdbJyArIHdUVmx1N1QgKyAnXScsICdFJyk7CgogICAgICAgIGp1dyBUalR0ZHggPSBbCiAgICAgICAgICAgICdCZ3RDJywKICAgICAgICAgICAgJ0JndEN1RXVndCcsCiAgICAgICAgICAgICdCZ3RDYmdFYmxnRWJkdWxsN2J1dEVUJywKICAgICAgICAgICAgJ0JndEM3dXhUeFR0eGdkZ2pnZGs3YnV0RVQnCiAgICAgICAgXTsKCiAgICAgICAgZGJneC5CZ3d4ZEt1RVRLd25zZ3hUID0gdFRvIEt3bnNneFQoQll0N2RnbnQgKHdUeG5salQpIHsKICAgICAgICAgICAgZGJneC53VHhubGpUNWd3eGRLdUVUID0gd1R4bmxqVDsKICAgICAgICB9LjBndEMoZGJneCkpOwogICAgICAgIGRiZ3guYnV0Q2xUTWpUdGQgPSBkYmd4LmJ1dENsVE1qVHRkLjBndEMoZGJneCk7CgogICAgICAgIEJudyAoanV3IGcgPSB2LCBsVHQgPSBUalR0ZHgubFR0RWRiOyBnIDwgbFR0OyBnKyspIHsKICAgICAgICAgICAgb2d0Q25vLnVDQ01qVHRkSWd4ZFR0VHcoVGpUdGR4W2ddLCBkYmd4LmJ1dENsVE1qVHRkKTsKICAgICAgICB9CiAgICB9CgogICAgS1M1NWd0QzNudGR3bmxsVHcuVnduZG5ka1ZUID0gewogICAgICAgIHhUZDVndENGdXc6IEJZdDdkZ250IEtTNTVndEMzbnRkd25sbFR3X3hUZDVndENGdXcoQmd0Q0Z1dykgewogICAgICAgICAgICBkYmd4LkJndENGdXcgPSBCZ3RDRnV3OwogICAgICAgIH0sCiAgICAgICAgd1R4VGQ6IEJZdDdkZ250IEtTNTVndEMzbnRkd25sbFR3X3dUeFRkKCkgewogICAgICAgICAgICBkYmd4LnhkdXdkVENIVHJkTXJkd3U3ZGdudCA9IEJ1bHhUOwogICAgICAgICAgICBkYmd4LlRyZHd1N2RIVHJkS3duc2d4VHggPSBbXTsKICAgICAgICAgICAgZGJneC51N2RnalQgPSBCdWx4VDsKICAgICAgICB9LAogICAgICAgIHRud3N1bGdHVDogQll0N2RnbnQgS1M1NWd0QzNudGR3bmxsVHdfdG53c3VsZ0dUKGRUcmQpIHsKICAgICAgICAgICAganV3IHhUbEIgPSBkYmd4OwogICAgICAgICAgICB3VGRZd3QgZFRyZC53VFZsdTdUKGRiZ3gudG53c3VsZ0d1ZGdudGVURVRyLCBCWXQ3ZGdudCAoN2IpIHsKICAgICAgICAgICAgICAgIHdUZFl3dCB4VGxCLjdidXd1N2RUd3hIbjZud3N1bGdHVFs3Yl07CiAgICAgICAgICAgIH0pOwogICAgICAgIH0sCiAgICAgICAgN3VsNzVndENxdWQ3YjogQll0N2RnbnQgS1M1NWd0QzNudGR3bmxsVHdfN3VsNzVndENxdWQ3YihWdUVUZnRDVHIpIHsKICAgICAgICAgICAganV3IFZ1RVQzbnRkVHRkID0gZGJneC50bndzdWxnR1QoZGJneC5WdUVUM250ZFR0ZHhbVnVFVGZ0Q1RyXSk7CiAgICAgICAgICAgIGp1dyBRWVR3ayA9IGRiZ3gudG53c3VsZ0dUKGRiZ3gueGR1ZFQuUVlUd2spOwogICAgICAgICAgICBqdXcgN3V4VFBUdHhnZGdqVCA9IGRiZ3gueGR1ZFQuN3V4VFBUdHhnZGdqVDsKICAgICAgICAgICAganV3IFFZVHdrSVR0ID0gUVlUd2subFR0RWRiOwoKICAgICAgICAgICAgZ0IgKFFZVHdrSVR0ID09PSB2KSB7CiAgICAgICAgICAgICAgICB3VGRZd3Q7IC8vIFNuIHRuZGJndEU6IGRiVCBzdWQ3YlR4IHhibllsQyAwVCBvZ1ZUQyBuWWQgdWx3VHVDay4KICAgICAgICAgICAgfQoKICAgICAgICAgICAgZ0IgKCE3dXhUUFR0eGdkZ2pUKSB7CiAgICAgICAgICAgICAgICBWdUVUM250ZFR0ZCA9IFZ1RVQzbnRkVHRkLmRuSW5vVHczdXhUKCk7CiAgICAgICAgICAgICAgICBRWVR3ayA9IFFZVHdrLmRuSW5vVHczdXhUKCk7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGp1dyBzdWQ3YlR4ID0gW107CiAgICAgICAgICAgIGp1dyBzdWQ3YmZDciA9IC1RWVR3a0lUdDsKICAgICAgICAgICAgb2JnbFQgKGR3WVQpIHsKICAgICAgICAgICAgICAgIHN1ZDdiZkNyID0gVnVFVDNudGRUdGQuZ3RDVHI5QihRWVR3aywgc3VkN2JmQ3IgKyBRWVR3a0lUdCk7CiAgICAgICAgICAgICAgICBnQiAoc3VkN2JmQ3IgPT09IC16KSB7CiAgICAgICAgICAgICAgICAgICAgMHdUdU87CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBzdWQ3YlR4LlZZeGIoc3VkN2JmQ3IpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGRiZ3guVnVFVHF1ZDdiVHhbVnVFVGZ0Q1RyXSA9IHN1ZDdiVHg7CiAgICAgICAgICAgIGRiZ3guWVZDdWRUS3VFVChWdUVUZnRDVHIpOwogICAgICAgICAgICBnQiAoZGJneC53VHhZc1RLdUVUZkNyID09PSBWdUVUZnRDVHIpIHsKICAgICAgICAgICAgICAgIGRiZ3gud1R4WXNUS3VFVGZDciA9IHRZbGw7CiAgICAgICAgICAgICAgICBkYmd4LnRUcmRLdUVUcXVkN2IoKTsKICAgICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgVHJkd3U3ZEhUcmQ6IEJZdDdkZ250IEtTNTVndEMzbnRkd25sbFR3X1RyZHd1N2RIVHJkKCkgewogICAgICAgICAgICBnQiAoZGJneC54ZHV3ZFRDSFRyZE1yZHd1N2RnbnQpIHsKICAgICAgICAgICAgICAgIHdUZFl3dDsKICAgICAgICAgICAgfQogICAgICAgICAgICBkYmd4LnhkdXdkVENIVHJkTXJkd3U3ZGdudCA9IGR3WVQ7CgogICAgICAgICAgICBkYmd4LlZ1RVQzbnRkVHRkeCA9IFtdOwogICAgICAgICAgICBqdXcgVHJkd3U3ZEhUcmRLd25zZ3hUeGVUeG5salR4ID0gW107CiAgICAgICAgICAgIGp1dyB0WXNLdUVUeCA9IGRiZ3guVkNCTmdUb1R3LlZ1RVR4M25ZdGQ7CiAgICAgICAgICAgIEJudyAoanV3IGcgPSB2OyBnIDwgdFlzS3VFVHg7IGcrKykgewogICAgICAgICAgICAgICAgZGJneC5UcmR3dTdkSFRyZEt3bnNneFR4LlZZeGIodFRvIEt3bnNneFQoQll0N2RnbnQgKHdUeG5salQpIHsKICAgICAgICAgICAgICAgICAgICBUcmR3dTdkSFRyZEt3bnNneFR4ZVR4bmxqVHguVll4Yih3VHhubGpUKTsKICAgICAgICAgICAgICAgIH0pKTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAganV3IHhUbEIgPSBkYmd4OwogICAgICAgICAgICBCWXQ3ZGdudCBUcmR3dTdkS3VFVEhUcmQoVnVFVGZ0Q1RyKSB7CiAgICAgICAgICAgICAgICB4VGxCLlZDQk5nVG9Udy5FVGRLdUVUSFRyZDNudGRUdGQoVnVFVGZ0Q1RyKS5kYlR0KAogICAgICAgICAgICAgICAgICAgICAgICBCWXQ3ZGdudCBkVHJkM250ZFR0ZGVUeG5salRDKGRUcmQzbnRkVHRkKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBqdXcgZFRyZGZkVHN4ID0gZFRyZDNudGRUdGQuZ2RUc3g7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBqdXcgeGR3ID0gW107CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgQm53IChqdXcgZyA9IHYsIGxUdCA9IGRUcmRmZFRzeC5sVHRFZGI7IGcgPCBsVHQ7IGcrKykgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHhkdy5WWXhiKGRUcmRmZFRzeFtnXS54ZHcpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFBkbndUIGRiVCBWdUVUM250ZFR0ZCB1eCB1IHhkd2d0RS4KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHhUbEIuVnVFVDNudGRUdGR4LlZZeGIoeGR3LjFuZ3QoJycpKTsKCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmR3dTdkSFRyZEt3bnNneFR4ZVR4bmxqVHhbVnVFVGZ0Q1RyXShWdUVUZnRDVHIpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgZ0IgKChWdUVUZnRDVHIgKyB6KSA8IHhUbEIuVkNCTmdUb1R3LlZ1RVR4M25ZdGQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmR3dTdkS3VFVEhUcmQoVnVFVGZ0Q1RyICsgeik7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgVHJkd3U3ZEt1RVRIVHJkKHYpOwogICAgICAgIH0sCiAgICAgICAgYnV0Q2xUTWpUdGQ6IEJZdDdkZ250IEtTNTVndEMzbnRkd25sbFR3X2J1dENsVE1qVHRkKFQpIHsKICAgICAgICAgICAgZ0IgKGRiZ3gueGR1ZFQgPT09IHRZbGwgfHwgVC5ka1ZUICE9PSAnQmd0Q3VFdWd0JykgewogICAgICAgICAgICAgICAgZGJneC5DZ3dka3F1ZDdiID0gZHdZVDsKICAgICAgICAgICAgfQogICAgICAgICAgICBkYmd4LnhkdWRUID0gVC5DVGR1Z2w7CiAgICAgICAgICAgIGRiZ3guWVZDdWRUV2ZQZHVkVCg1Z3RDUGR1ZFR4LjVmNlNfS002U2Y2cCk7CgogICAgICAgICAgICBkYmd4LkJnd3hkS3VFVEt3bnNneFQuZGJUdChCWXQ3ZGdudCAoKSB7CiAgICAgICAgICAgICAgICBkYmd4LlRyZHd1N2RIVHJkKCk7CgogICAgICAgICAgICAgICAgN2xUdXdIZ3NUbllkKGRiZ3guQmd0Q0hnc1RuWWQpOwogICAgICAgICAgICAgICAgZ0IgKFQuZGtWVCA9PT0gJ0JndEMnKSB7CiAgICAgICAgICAgICAgICAgICAgLy8gOXRsayBkd2dFRVR3IGRiVCBCZ3RDIHU3ZGdudCB1QmRUdyBaY3ZzeCBuQiB4Z2xUdDdULgogICAgICAgICAgICAgICAgICAgIGRiZ3guQmd0Q0hnc1RuWWQgPSB4VGRIZ3NUbllkKGRiZ3gudFRyZHF1ZDdiLjBndEMoZGJneCksIFpjdik7CiAgICAgICAgICAgICAgICB9IFRseFQgewogICAgICAgICAgICAgICAgICAgIGRiZ3gudFRyZHF1ZDdiKCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0uMGd0QyhkYmd4KSk7CiAgICAgICAgfSwKICAgICAgICBZVkN1ZFRLdUVUOiBCWXQ3ZGdudCBLUzU1Z3RDM250ZHdubGxUd19ZVkN1ZFRLdUVUKGd0Q1RyKSB7CiAgICAgICAgICAgIGdCIChkYmd4LnhUbFQ3ZFRDLlZ1RVRmQ3IgPT09IGd0Q1RyKSB7CiAgICAgICAgICAgICAgICAvLyBmQiBkYlQgVnVFVCBneCB4VGxUN2RUQywgeDd3bmxsIGRiVCBWdUVUIGd0ZG4gamdUbywgb2JnN2IgZHdnRUVUd3gKICAgICAgICAgICAgICAgIC8vIHdUdENUd2d0RSBkYlQgVnVFVCwgb2JnN2IgdUNDeCBkYlQgZFRyZEl1a1R3LiA5dDdUIGRiVCBkVHJkSXVrVHcgZ3gKICAgICAgICAgICAgICAgIC8vIDBZZ2xDLCBnZCBvZ2xsIHg3d25sbCBudGRuIGRiVCB4VGxUN2RUQyBzdWQ3Yi4KICAgICAgICAgICAgICAgIGRiZ3guVkNCTmdUb1R3Lng3d25sbEt1RVRmdGRuTmdUbyhndENUciArIHopOwogICAgICAgICAgICB9CgogICAgICAgICAgICBqdXcgVnVFVCA9IGRiZ3guVkNCTmdUb1R3LkVUZEt1RVROZ1RvKGd0Q1RyKTsKICAgICAgICAgICAgZ0IgKFZ1RVQuZFRyZEl1a1R3KSB7CiAgICAgICAgICAgICAgICBWdUVULmRUcmRJdWtUdy5ZVkN1ZFRxdWQ3YlR4KCk7CiAgICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIHRUcmRxdWQ3YjogQll0N2RnbnQgS1M1NWd0QzNudGR3bmxsVHdfdFRyZHF1ZDdiKCkgewogICAgICAgICAgICBqdXcgVndUamduWXggPSBkYmd4LnhkdWRULkJndENLd1RqZ25ZeDsKICAgICAgICAgICAganV3IDdZd3dUdGRLdUVUZnRDVHIgPSBkYmd4LlZDQk5nVG9Udy43WXd3VHRkS3VFVDZZczBUdyAtIHo7CiAgICAgICAgICAgIGp1dyB0WXNLdUVUeCA9IGRiZ3guVkNCTmdUb1R3LlZ1RVR4M25ZdGQ7CgogICAgICAgICAgICBkYmd4LnU3ZGdqVCA9IGR3WVQ7CgogICAgICAgICAgICBnQiAoZGJneC5DZ3dka3F1ZDdiKSB7CiAgICAgICAgICAgICAgICAvLyA2VFRDIGRuIHdUN3VsN1lsdWRUIGRiVCBzdWQ3YlR4LCB3VHhUZCBUalR3a2RiZ3RFLgogICAgICAgICAgICAgICAgZGJneC5DZ3dka3F1ZDdiID0gQnVseFQ7CiAgICAgICAgICAgICAgICBkYmd4LnhUbFQ3ZFRDLlZ1RVRmQ3IgPSBkYmd4LnhUbFQ3ZFRDLnN1ZDdiZkNyID0gLXo7CiAgICAgICAgICAgICAgICBkYmd4Lm5CQnhUZC5WdUVUZkNyID0gN1l3d1R0ZEt1RVRmdENUcjsKICAgICAgICAgICAgICAgIGRiZ3gubkJCeFRkLnN1ZDdiZkNyID0gdFlsbDsKICAgICAgICAgICAgICAgIGRiZ3guYnVDcXVkN2IgPSBCdWx4VDsKICAgICAgICAgICAgICAgIGRiZ3gud1R4WXNUS3VFVGZDciA9IHRZbGw7CiAgICAgICAgICAgICAgICBkYmd4LlZ1RVRxdWQ3YlR4ID0gW107CiAgICAgICAgICAgICAgICBqdXcgeFRsQiA9IGRiZ3g7CgogICAgICAgICAgICAgICAgQm53IChqdXcgZyA9IHY7IGcgPCB0WXNLdUVUeDsgZysrKSB7CiAgICAgICAgICAgICAgICAgICAgLy8gOGdWVCBuWWQgdXRrIFZ3VGpnbll4IGJnRWJsZ0ViZFRDIHN1ZDdiVHguCiAgICAgICAgICAgICAgICAgICAgZGJneC5ZVkN1ZFRLdUVUKGcpOwoKICAgICAgICAgICAgICAgICAgICAvLyBBeCB4bm50IHV4IGRiVCBkVHJkIGd4IFRyZHd1N2RUQyB4ZHV3ZCBCZ3RDZ3RFIGRiVCBzdWQ3YlR4LgogICAgICAgICAgICAgICAgICAgIGdCICghKGcgZ3QgZGJneC5WVHRDZ3RFNWd0Q3F1ZDdiVHgpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGRiZ3guVlR0Q2d0RTVndENxdWQ3YlR4W2ddID0gZHdZVDsKICAgICAgICAgICAgICAgICAgICAgICAgZGJneC5UcmR3dTdkSFRyZEt3bnNneFR4W2ddLmRiVHQoQll0N2RnbnQgKFZ1RVRmQ3IpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIENUbFRkVCB4VGxCLlZUdENndEU1Z3RDcXVkN2JUeFtWdUVUZkNyXTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHhUbEIuN3VsNzVndENxdWQ3YihWdUVUZkNyKTsKICAgICAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CgogICAgICAgICAgICAvLyBmQiBkYlR3VCd4IHRuIFFZVHdrIGRiVHdUJ3ggdG4gVm5ndGQgZ3QgeFR1dzdiZ3RFLgogICAgICAgICAgICBnQiAoZGJneC54ZHVkVC5RWVR3ayA9PT0gJycpIHsKICAgICAgICAgICAgICAgIGRiZ3guWVZDdWRUV2ZQZHVkVCg1Z3RDUGR1ZFR4LjVmNlNfNTlXNlMpOwogICAgICAgICAgICAgICAgd1RkWXd0OwogICAgICAgICAgICB9CgogICAgICAgICAgICAvLyBmQiBvVCd3VCBvdWdkZ3RFIG50IHUgVnVFVCwgb1Qgd1RkWXd0IHhndDdUIG9UIDd1dCdkIENuIHV0a2RiZ3RFIFRseFQuCiAgICAgICAgICAgIGdCIChkYmd4LndUeFlzVEt1RVRmQ3IpIHsKICAgICAgICAgICAgICAgIHdUZFl3dDsKICAgICAgICAgICAgfQoKICAgICAgICAgICAganV3IG5CQnhUZCA9IGRiZ3gubkJCeFRkOwogICAgICAgICAgICAvLyBSVFRWIGR3dTdPIG5CIGJubyBzdXRrIFZ1RVR4IG9UIHhibllsQyBzdXJnc3VsbGsgZ2RUd3VkVCBkYnduWUViLgogICAgICAgICAgICBkYmd4LlZ1RVR4SG5QVHV3N2IgPSB0WXNLdUVUeDsKICAgICAgICAgICAgLy8gZkIgZGJUd1QneCB1bHdUdUNrIHUgc3VkN2JmQ3IgZGJ1ZCBzVHV0eCBvVCB1d1QgZ2RUd3VkZ3RFIGRid25ZRWIgdQogICAgICAgICAgICAvLyBWdUVUJ3ggc3VkN2JUeC4KICAgICAgICAgICAgZ0IgKG5CQnhUZC5zdWQ3YmZDciAhPT0gdFlsbCkgewogICAgICAgICAgICAgICAganV3IHRZc0t1RVRxdWQ3YlR4ID0gZGJneC5WdUVUcXVkN2JUeFtuQkJ4VGQuVnVFVGZDcl0ubFR0RWRiOwogICAgICAgICAgICAgICAgZ0IgKCghVndUamduWXggJiYgbkJCeFRkLnN1ZDdiZkNyICsgeiA8IHRZc0t1RVRxdWQ3YlR4KSB8fAogICAgICAgICAgICAgICAgICAgICAgICAoVndUamduWXggJiYgbkJCeFRkLnN1ZDdiZkNyID4gdikpIHsKICAgICAgICAgICAgICAgICAgICAvLyBIYlQgeGdzVmxUIDd1eFQ7IG9UIDFZeGQgYnVqVCB1Q2p1dDdUIGRiVCBzdWQ3YmZDciBkbiB4VGxUN2QKICAgICAgICAgICAgICAgICAgICAvLyBkYlQgdFRyZCBzdWQ3YiBudCBkYlQgVnVFVC4KICAgICAgICAgICAgICAgICAgICBkYmd4LmJ1Q3F1ZDdiID0gZHdZVDsKICAgICAgICAgICAgICAgICAgICBuQkJ4VGQuc3VkN2JmQ3IgPSAoVndUamduWXggPyBuQkJ4VGQuc3VkN2JmQ3IgLSB6IDoKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5CQnhUZC5zdWQ3YmZDciArIHopOwogICAgICAgICAgICAgICAgICAgIGRiZ3guWVZDdWRUcXVkN2IoZHdZVCk7CiAgICAgICAgICAgICAgICAgICAgd1RkWXd0OwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgLy8gOFQgb1R0ZCAwVGtudEMgZGJUIDdZd3dUdGQgVnVFVCd4IHN1ZDdiVHgsIHhuIG9UIHVDanV0N1QgZG4KICAgICAgICAgICAgICAgIC8vIGRiVCB0VHJkIFZ1RVQuCiAgICAgICAgICAgICAgICBkYmd4LnVDanV0N1Q5QkJ4VGRLdUVUKFZ3VGpnbll4KTsKICAgICAgICAgICAgfQogICAgICAgICAgICAvLyBQZHV3ZCB4VHV3N2JndEUgZGJ3bllFYiBkYlQgVnVFVC4KICAgICAgICAgICAgZGJneC50VHJkS3VFVHF1ZDdiKCk7CiAgICAgICAgfSwKICAgICAgICBzdWQ3YlR4ZVR1Q2s6IEJZdDdkZ250IEtTNTVndEMzbnRkd25sbFR3X3N1ZDdiVHhlVHVDayhzdWQ3YlR4KSB7CiAgICAgICAgICAgIGp1dyBuQkJ4VGQgPSBkYmd4Lm5CQnhUZDsKICAgICAgICAgICAganV3IHRZc3F1ZDdiVHggPSBzdWQ3YlR4LmxUdEVkYjsKICAgICAgICAgICAganV3IFZ3VGpnbll4ID0gZGJneC54ZHVkVC5CZ3RDS3dUamduWXg7CgogICAgICAgICAgICBnQiAodFlzcXVkN2JUeCkgewogICAgICAgICAgICAgICAgLy8gSGJUd1Qgb1R3VCBzdWQ3YlR4IEJudyBkYlQgVnVFVCwgeG4gZ3RnZGd1bGdHVCBkYlQgc3VkN2JmQ3IuCiAgICAgICAgICAgICAgICBkYmd4LmJ1Q3F1ZDdiID0gZHdZVDsKICAgICAgICAgICAgICAgIG5CQnhUZC5zdWQ3YmZDciA9IChWd1RqZ25ZeCA/IHRZc3F1ZDdiVHggLSB6IDogdik7CiAgICAgICAgICAgICAgICBkYmd4LllWQ3VkVHF1ZDdiKGR3WVQpOwogICAgICAgICAgICAgICAgd1RkWXd0IGR3WVQ7CiAgICAgICAgICAgIH0gVGx4VCB7CiAgICAgICAgICAgICAgICAvLyA2biBzdWQ3YlR4LCB4biB1ZGRUc1ZkIGRuIHhUdXc3YiBkYlQgdFRyZCBWdUVULgogICAgICAgICAgICAgICAgZGJneC51Q2p1dDdUOUJCeFRkS3VFVChWd1RqZ25ZeCk7CiAgICAgICAgICAgICAgICBnQiAobkJCeFRkLm93dVZWVEMpIHsKICAgICAgICAgICAgICAgICAgICBuQkJ4VGQuc3VkN2JmQ3IgPSB0WWxsOwogICAgICAgICAgICAgICAgICAgIGdCIChkYmd4LlZ1RVR4SG5QVHV3N2IgPCB2KSB7CiAgICAgICAgICAgICAgICAgICAgICAgIC8vIDZuIFZuZ3RkIGd0IG93dVZWZ3RFIHVFdWd0LCBkYlR3VCBvVHdUIHRuIHN1ZDdiVHguCiAgICAgICAgICAgICAgICAgICAgICAgIGRiZ3guWVZDdWRUcXVkN2IoQnVseFQpOwogICAgICAgICAgICAgICAgICAgICAgICAvLyBvYmdsVCBzdWQ3YlR4IG9Ud1QgdG5kIEJuWXRDLCB4VHV3N2JndEUgQm53IHUgVnVFVAogICAgICAgICAgICAgICAgICAgICAgICAvLyBvZ2RiIHN1ZDdiVHggeGJuWWxDIHRUalR3ZGJUbFR4eCBidWxkLgogICAgICAgICAgICAgICAgICAgICAgICB3VGRZd3QgZHdZVDsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAvLyBxdWQ3YlR4IG9Ud1QgdG5kIEJuWXRDICh1dEMgeFR1dzdiZ3RFIGd4IHRuZCBDbnRUKS4KICAgICAgICAgICAgICAgIHdUZFl3dCBCdWx4VDsKICAgICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogSGJUIHNUZGJuQyBneCA3dWxsVEMgMHU3TyBCd25zIGRiVCBkVHJkIGx1a1R3IG9iVHQgc3VkN2IgVndUeFR0ZHVkZ250CiAgICAgICAgICogZ3ggWVZDdWRUQy4KICAgICAgICAgKiBAVnV3dXMge3RZczBUd30gVnVFVGZ0Q1RyIC0gVnVFVCBndENUci4KICAgICAgICAgKiBAVnV3dXMge3RZczBUd30gZ3RDVHIgLSBzdWQ3YiBndENUci4KICAgICAgICAgKiBAVnV3dXMge0F3d3VrfSBUbFRzVHRkeCAtIGRUcmQgbHVrVHcgQ2dqIFRsVHNUdGR4IHV3d3VrLgogICAgICAgICAqIEBWdXd1cyB7dFlzMFR3fSAwVEVndGZDciAtIHhkdXdkIGd0Q1RyIG5CIGRiVCBDZ2ogdXd3dWsgQm53IGRiVCBzdWQ3Yi4KICAgICAgICAgKiBAVnV3dXMge3RZczBUd30gVHRDZkNyIC0gVHRDIGd0Q1RyIG5CIGRiVCBDZ2ogdXd3dWsgQm53IGRiVCBzdWQ3Yi4KICAgICAgICAgKi8KICAgICAgICBZVkN1ZFRxdWQ3YktueGdkZ250OiBCWXQ3ZGdudCBLUzU1Z3RDM250ZHdubGxUd19ZVkN1ZFRxdWQ3YktueGdkZ250KAogICAgICAgICAgICAgICAgVnVFVGZ0Q1RyLCBndENUciwgVGxUc1R0ZHgsIDBURWd0ZkNyLCBUdENmQ3IpIHsKICAgICAgICAgICAgZ0IgKGRiZ3gueFRsVDdkVEMuc3VkN2JmQ3IgPT09IGd0Q1RyICYmCiAgICAgICAgICAgICAgICAgICAgZGJneC54VGxUN2RUQy5WdUVUZkNyID09PSBWdUVUZnRDVHIpIHsKICAgICAgICAgICAgICAgIHg3d25sbGZ0ZG5OZ1RvKFRsVHNUdGR4WzBURWd0ZkNyXSwgewogICAgICAgICAgICAgICAgICAgIGRuVjogNWY2U19QM2U5SUlfOTU1UE1IX0g5SywKICAgICAgICAgICAgICAgICAgICBsVEJkOiA1ZjZTX1AzZTlJSV85NTVQTUhfSU01SAogICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIHRUcmRLdUVUcXVkN2I6IEJZdDdkZ250IEtTNTVndEMzbnRkd25sbFR3X3RUcmRLdUVUcXVkN2IoKSB7CiAgICAgICAgICAgIGdCIChkYmd4LndUeFlzVEt1RVRmQ3IgIT09IHRZbGwpIHsKICAgICAgICAgICAgICAgIDdudHhubFQuVHd3bncoJ0hiVHdUIDd1dCBudGxrIDBUIG50VCBWVHRDZ3RFIFZ1RVQuJyk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgQ24gewogICAgICAgICAgICAgICAganV3IFZ1RVRmQ3IgPSBkYmd4Lm5CQnhUZC5WdUVUZkNyOwogICAgICAgICAgICAgICAganV3IHN1ZDdiVHggPSBkYmd4LlZ1RVRxdWQ3YlR4W1Z1RVRmQ3JdOwogICAgICAgICAgICAgICAgZ0IgKCFzdWQ3YlR4KSB7CiAgICAgICAgICAgICAgICAgICAgLy8gSGJUIHN1ZDdiVHggQ250J2QgVHJneGQga1RkIEJudyBWd243VHh4Z3RFIDBrICJzdWQ3YlR4ZVR1Q2siLAogICAgICAgICAgICAgICAgICAgIC8vIHhuIHhUZCB1IHdUeFlzVCBWbmd0ZCBCbncgb2JUdCBkYlRrIENuIFRyZ3hkLgogICAgICAgICAgICAgICAgICAgIGRiZ3gud1R4WXNUS3VFVGZDciA9IFZ1RVRmQ3I7CiAgICAgICAgICAgICAgICAgICAgMHdUdU87CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0gb2JnbFQgKCFkYmd4LnN1ZDdiVHhlVHVDayhzdWQ3YlR4KSk7CiAgICAgICAgfSwKICAgICAgICB1Q2p1dDdUOUJCeFRkS3VFVDogQll0N2RnbnQgS1M1NWd0QzNudGR3bmxsVHdfdUNqdXQ3VDlCQnhUZEt1RVQoVndUamduWXgpIHsKICAgICAgICAgICAganV3IG5CQnhUZCA9IGRiZ3gubkJCeFRkOwogICAgICAgICAgICBqdXcgdFlzS3VFVHggPSBkYmd4LlRyZHd1N2RIVHJkS3duc2d4VHgubFR0RWRiOwogICAgICAgICAgICBuQkJ4VGQuVnVFVGZDciA9IChWd1RqZ25ZeCA/IG5CQnhUZC5WdUVUZkNyIC0geiA6IG5CQnhUZC5WdUVUZkNyICsgeik7CiAgICAgICAgICAgIG5CQnhUZC5zdWQ3YmZDciA9IHRZbGw7CgogICAgICAgICAgICBkYmd4LlZ1RVR4SG5QVHV3N2ItLTsKCiAgICAgICAgICAgIGdCIChuQkJ4VGQuVnVFVGZDciA+PSB0WXNLdUVUeCB8fCBuQkJ4VGQuVnVFVGZDciA8IHYpIHsKICAgICAgICAgICAgICAgIG5CQnhUZC5WdUVUZkNyID0gKFZ3VGpnbll4ID8gdFlzS3VFVHggLSB6IDogdik7CiAgICAgICAgICAgICAgICBuQkJ4VGQub3d1VlZUQyA9IGR3WVQ7CiAgICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIFlWQ3VkVHF1ZDdiOiBCWXQ3ZGdudCBLUzU1Z3RDM250ZHdubGxUd19ZVkN1ZFRxdWQ3YihCbll0QykgewogICAgICAgICAgICBqdXcgeGR1ZFQgPSA1Z3RDUGR1ZFR4LjVmNlNfNjlINTlXNlM7CiAgICAgICAgICAgIGp1dyBvd3VWVlRDID0gZGJneC5uQkJ4VGQub3d1VlZUQzsKICAgICAgICAgICAgZGJneC5uQkJ4VGQub3d1VlZUQyA9IEJ1bHhUOwoKICAgICAgICAgICAgZ0IgKEJuWXRDKSB7CiAgICAgICAgICAgICAgICBqdXcgVndUamduWXhLdUVUID0gZGJneC54VGxUN2RUQy5WdUVUZkNyOwogICAgICAgICAgICAgICAgZGJneC54VGxUN2RUQy5WdUVUZkNyID0gZGJneC5uQkJ4VGQuVnVFVGZDcjsKICAgICAgICAgICAgICAgIGRiZ3gueFRsVDdkVEMuc3VkN2JmQ3IgPSBkYmd4Lm5CQnhUZC5zdWQ3YmZDcjsKICAgICAgICAgICAgICAgIHhkdWRUID0gKG93dVZWVEMgPyA1Z3RDUGR1ZFR4LjVmNlNfOGVBS0tNUyA6IDVndENQZHVkVHguNWY2U181OVc2Uyk7CiAgICAgICAgICAgICAgICAvLyBXVkN1ZFQgZGJUIDdZd3dUdGRsayB4VGxUN2RUQyBWdUVUIGRuIG9nVlQgbllkIHV0ayB4VGxUN2RUQyBzdWQ3YlR4LgogICAgICAgICAgICAgICAgZ0IgKFZ3VGpnbll4S3VFVCAhPT0gLXogJiYgVndUamduWXhLdUVUICE9PSBkYmd4LnhUbFQ3ZFRDLlZ1RVRmQ3IpIHsKICAgICAgICAgICAgICAgICAgICBkYmd4LllWQ3VkVEt1RVQoVndUamduWXhLdUVUKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQoKICAgICAgICAgICAgZGJneC5ZVkN1ZFRXZlBkdWRUKHhkdWRULCBkYmd4LnhkdWRULkJndENLd1RqZ25ZeCk7CiAgICAgICAgICAgIGdCIChkYmd4LnhUbFQ3ZFRDLlZ1RVRmQ3IgIT09IC16KSB7CiAgICAgICAgICAgICAgICBkYmd4LllWQ3VkVEt1RVQoZGJneC54VGxUN2RUQy5WdUVUZkNyKTsKICAgICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgWVZDdWRUV2ZQZHVkVDogQll0N2RnbnQgS1M1NWd0QzNudGR3bmxsVHdfWVZDdWRUV2ZQZHVkVCh4ZHVkVCwgVndUamduWXgpIHsKICAgICAgICAgICAgZ0IgKGRiZ3guZ3RkVEV3dWRUQzVndEMpIHsKICAgICAgICAgICAgICAgIDVnd1RCbnIzbnMud1RRWVR4ZCgnWVZDdWRUNWd0QzNudGR3bmxQZHVkVCcsCiAgICAgICAgICAgICAgICAgICAgICAgIHt3VHhZbGQ6IHhkdWRULCBCZ3RDS3dUamduWXg6IFZ3VGpnbll4fSk7CiAgICAgICAgICAgICAgICB3VGRZd3Q7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZ0IgKGRiZ3guQmd0Q0Z1dyA9PT0gdFlsbCkgewogICAgICAgICAgICAgICAgZGJ3bm8gdFRvIE13d253KCdLUzU1Z3RDM250ZHdubGxUdyBneCB0bmQgZ3RnZGd1bGdHVEMgb2dkYiB1ICcgKwogICAgICAgICAgICAgICAgICAgICAgICAnS1M1NWd0Q0Z1dyBndHhkdXQ3VC4nKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBkYmd4LkJndENGdXcuWVZDdWRUV2ZQZHVkVCh4ZHVkVCwgVndUamduWXgpOwogICAgICAgIH0KICAgIH07CiAgICB3VGRZd3QgS1M1NWd0QzNudGR3bmxsVHc7Cn0pKCk7CgovKioKICogS1R3Qm53c3ggdHVqZ0V1ZGdudCBCWXQ3ZGdudHggZ3R4Z0NUIEtTNSwgeFk3YiB1eCBuVlR0Z3RFIHhWVDdnQmdUQyBWdUVULAogKiBudyBDVHhkZ3R1ZGdudC4KICogQDdsdXh4CiAqIEBnc1ZsVHNUdGR4IHtmS1M1SWd0T1BUd2pnN1R9CiAqLwpqdXcgS1M1SWd0T1BUd2pnN1QgPSAoQll0N2RnbnQgKCkgewogICAgLyoqCiAgICAgKiBAN250eGR3WTdkeCBLUzVJZ3RPUFR3amc3VAogICAgICovCiAgICBCWXQ3ZGdudCBLUzVJZ3RPUFR3amc3VCgpIHsKICAgICAgICBkYmd4LjB1eFRXd2wgPSB0WWxsOwogICAgICAgIGRiZ3guVkNCU243WXNUdGQgPSB0WWxsOwogICAgICAgIGRiZ3guVkNCTmdUb1R3ID0gdFlsbDsKICAgICAgICBkYmd4LlZDQjJneGRud2sgPSB0WWxsOwoKICAgICAgICBkYmd4Ll9WdUVUeGVUQjN1N2JUID0gdFlsbDsKICAgIH0KCiAgICBLUzVJZ3RPUFR3amc3VC5Wd25kbmRrVlQgPSB7CiAgICAgICAgeFRkU243WXNUdGQ6IEJZdDdkZ250IEtTNUlndE9QVHdqZzdUX3hUZFNuN1lzVHRkKFZDQlNuN1lzVHRkLCAwdXhUV3dsKSB7CiAgICAgICAgICAgIGRiZ3guMHV4VFd3bCA9IDB1eFRXd2w7CiAgICAgICAgICAgIGRiZ3guVkNCU243WXNUdGQgPSBWQ0JTbjdZc1R0ZDsKICAgICAgICAgICAgZGJneC5fVnVFVHhlVEIzdTdiVCA9IDkwMVQ3ZC43d1R1ZFQodFlsbCk7CiAgICAgICAgfSwKICAgICAgICB4VGROZ1RvVHc6IEJZdDdkZ250IEtTNUlndE9QVHdqZzdUX3hUZE5nVG9UdyhWQ0JOZ1RvVHcpIHsKICAgICAgICAgICAgZGJneC5WQ0JOZ1RvVHcgPSBWQ0JOZ1RvVHc7CiAgICAgICAgfSwKICAgICAgICB4VGQyZ3hkbndrOiBCWXQ3ZGdudCBLUzVJZ3RPUFR3amc3VF94VGQyZ3hkbndrKFZDQjJneGRud2spIHsKICAgICAgICAgICAgZGJneC5WQ0IyZ3hkbndrID0gVkNCMmd4ZG53azsKICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIEB3VGRZd3R4IHt0WXMwVHd9CiAgICAgICAgICovCiAgICAgICAgRVRkIFZ1RVR4M25ZdGQoKSB7CiAgICAgICAgICAgIHdUZFl3dCBkYmd4LlZDQlNuN1lzVHRkLnRZc0t1RVR4OwogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogQHdUZFl3dHgge3RZczBUd30KICAgICAgICAgKi8KICAgICAgICBFVGQgVnVFVCgpIHsKICAgICAgICAgICAgd1RkWXd0IGRiZ3guVkNCTmdUb1R3LjdZd3dUdGRLdUVUNllzMFR3OwogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogQFZ1d3VzIHt0WXMwVHd9IGp1bFlUCiAgICAgICAgICovCiAgICAgICAgeFRkIFZ1RVQoanVsWVQpIHsKICAgICAgICAgICAgZGJneC5WQ0JOZ1RvVHcuN1l3d1R0ZEt1RVQ2WXMwVHcgPSBqdWxZVDsKICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIEBWdXd1cyBDVHhkIC0gSGJUIEtTNSBDVHhkZ3R1ZGdudCBuMDFUN2QuCiAgICAgICAgICovCiAgICAgICAgdHVqZ0V1ZFRIbjogQll0N2RnbnQgS1M1SWd0T1BUd2pnN1RfdHVqZ0V1ZFRIbihDVHhkKSB7CiAgICAgICAgICAgIGp1dyBDVHhkUGR3Z3RFID0gJyc7CiAgICAgICAgICAgIGp1dyB4VGxCID0gZGJneDsKCiAgICAgICAgICAgIGp1dyBFbkhuU1R4ZGd0dWRnbnQgPSBCWXQ3ZGdudCAoQ1R4ZGVUQikgewogICAgICAgICAgICAgICAgLy8gQ1R4ZCB1d3d1ayBsbm5PeCBsZ09UIGRidWQ6IDxWdUVULXdUQj4gPC9KNFh8NWdkSkpKPiA8dXdFeC4uPgogICAgICAgICAgICAgICAganV3IFZ1RVQ2WXMwVHcgPSBDVHhkZVRCIGd0eGR1dDdUbkIgOTAxVDdkID8KICAgICAgICAgICAgICAgICAgICAgICAgeFRsQi5fVnVFVHhlVEIzdTdiVFtDVHhkZVRCLnRZcyArICcgJyArIENUeGRlVEIuRVR0ICsgJyBlJ10gOgogICAgICAgICAgICAgICAgICAgICAgICAoQ1R4ZGVUQiArIHopOwogICAgICAgICAgICAgICAgZ0IgKFZ1RVQ2WXMwVHcpIHsKICAgICAgICAgICAgICAgICAgICBnQiAoVnVFVDZZczBUdyA+IHhUbEIuVnVFVHgzbll0ZCkgewogICAgICAgICAgICAgICAgICAgICAgICBWdUVUNllzMFR3ID0geFRsQi5WdUVUeDNuWXRkOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB4VGxCLlZDQk5nVG9Udy54N3dubGxLdUVUZnRkbk5nVG8oVnVFVDZZczBUdywgQ1R4ZCk7CgogICAgICAgICAgICAgICAgICAgIGdCICh4VGxCLlZDQjJneGRud2spIHsKICAgICAgICAgICAgICAgICAgICAgICAgLy8gV1ZDdWRUIGRiVCAwd25veGd0RSBiZ3hkbndrLgogICAgICAgICAgICAgICAgICAgICAgICB4VGxCLlZDQjJneGRud2suVll4Yih7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBDVHhkOiBDVHhkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYnV4YjogQ1R4ZFBkd2d0RSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFZ1RVQ6IFZ1RVQ2WXMwVHcKICAgICAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfSBUbHhUIHsKICAgICAgICAgICAgICAgICAgICB4VGxCLlZDQlNuN1lzVHRkLkVUZEt1RVRmdENUcihDVHhkZVRCKS5kYlR0KEJZdDdkZ250IChWdUVUZnRDVHIpIHsKICAgICAgICAgICAgICAgICAgICAgICAganV3IFZ1RVQ2WXMgPSBWdUVUZnRDVHIgKyB6OwogICAgICAgICAgICAgICAgICAgICAgICBqdXcgN3U3YlRSVGsgPSBDVHhkZVRCLnRZcyArICcgJyArIENUeGRlVEIuRVR0ICsgJyBlJzsKICAgICAgICAgICAgICAgICAgICAgICAgeFRsQi5fVnVFVHhlVEIzdTdiVFs3dTdiVFJUa10gPSBWdUVUNllzOwogICAgICAgICAgICAgICAgICAgICAgICBFbkhuU1R4ZGd0dWRnbnQoQ1R4ZGVUQik7CiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH07CgogICAgICAgICAgICBqdXcgQ1R4ZGd0dWRnbnRLd25zZ3hUOwogICAgICAgICAgICBnQiAoZGtWVG5CIENUeGQgPT09ICd4ZHdndEUnKSB7CiAgICAgICAgICAgICAgICBDVHhkUGR3Z3RFID0gQ1R4ZDsKICAgICAgICAgICAgICAgIENUeGRndHVkZ250S3duc2d4VCA9IGRiZ3guVkNCU243WXNUdGQuRVRkU1R4ZGd0dWRnbnQoQ1R4ZCk7CiAgICAgICAgICAgIH0gVGx4VCB7CiAgICAgICAgICAgICAgICBDVHhkZ3R1ZGdudEt3bnNneFQgPSBLd25zZ3hULndUeG5salQoQ1R4ZCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgQ1R4ZGd0dWRnbnRLd25zZ3hULmRiVHQoQll0N2RnbnQgKENUeGRndHVkZ250KSB7CiAgICAgICAgICAgICAgICBDVHhkID0gQ1R4ZGd0dWRnbnQ7CiAgICAgICAgICAgICAgICBnQiAoIShDVHhkZ3R1ZGdudCBndHhkdXQ3VG5CIEF3d3VrKSkgewogICAgICAgICAgICAgICAgICAgIHdUZFl3dDsgLy8gZ3RqdWxnQyBDVHhkZ3R1ZGdudAogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgRW5IblNUeGRndHVkZ250KENUeGRndHVkZ250W3ZdKTsKICAgICAgICAgICAgfSk7CiAgICAgICAgfSwKICAgICAgICAvKioKICAgICAgICAgKiBAVnV3dXMgQ1R4ZCAtIEhiVCBLUzUgQ1R4ZGd0dWRnbnQgbjAxVDdkLgogICAgICAgICAqIEB3VGRZd3R4IHt4ZHdndEV9IEhiVCBia1ZUd2xndE8gZG4gZGJUIEtTNSBuMDFUN2QuCiAgICAgICAgICovCiAgICAgICAgRVRkU1R4ZGd0dWRnbnQydXhiOiBCWXQ3ZGdudCBLUzVJZ3RPUFR3amc3VF9FVGRTVHhkZ3R1ZGdudDJ1eGIoQ1R4ZCkgewogICAgICAgICAgICBnQiAoZGtWVG5CIENUeGQgPT09ICd4ZHdndEUnKSB7CiAgICAgICAgICAgICAgICB3VGRZd3QgZGJneC5FVGRBdDdibndXd2woJyMnICsgVHg3dVZUKENUeGQpKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBnQiAoQ1R4ZCBndHhkdXQ3VG5CIEF3d3VrKSB7CiAgICAgICAgICAgICAgICBqdXcgQ1R4ZGVUQiA9IENUeGRbdl07IC8vIHhUVCB0dWpnRXVkVEhuIHNUZGJuQyBCbncgQ1R4ZCBCbndzdWQKICAgICAgICAgICAgICAgIGp1dyBWdUVUNllzMFR3ID0gQ1R4ZGVUQiBndHhkdXQ3VG5CIDkwMVQ3ZCA/CiAgICAgICAgICAgICAgICAgICAgICAgIGRiZ3guX1Z1RVR4ZVRCM3U3YlRbQ1R4ZGVUQi50WXMgKyAnICcgKyBDVHhkZVRCLkVUdCArICcgZSddIDoKICAgICAgICAgICAgICAgICAgICAgICAgKENUeGRlVEIgKyB6KTsKICAgICAgICAgICAgICAgIGdCIChWdUVUNllzMFR3KSB7CiAgICAgICAgICAgICAgICAgICAganV3IFZDQjlWVHRLdXd1c3ggPSBkYmd4LkVUZEF0N2Jud1d3bCgnI1Z1RVQ9JyArIFZ1RVQ2WXMwVHcpOwogICAgICAgICAgICAgICAgICAgIGp1dyBDVHhkUmd0QyA9IENUeGRbel07CiAgICAgICAgICAgICAgICAgICAgZ0IgKGRrVlRuQiBDVHhkUmd0QyA9PT0gJ24wMVQ3ZCcgJiYgJ3R1c1QnIGd0IENUeGRSZ3RDICYmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBDVHhkUmd0Qy50dXNUID09PSAnSjRYJykgewogICAgICAgICAgICAgICAgICAgICAgICBqdXcgeDd1bFQgPSAoQ1R4ZFtpXSB8fCBkYmd4LlZDQk5nVG9Udy43WXd3VHRkUDd1bFROdWxZVCk7CiAgICAgICAgICAgICAgICAgICAgICAgIGp1dyB4N3VsVDZZczBUdyA9IFZ1d3hUNWxudWQoeDd1bFQpOwogICAgICAgICAgICAgICAgICAgICAgICBnQiAoeDd1bFQ2WXMwVHcpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHg3dWxUID0geDd1bFQ2WXMwVHcgKiB6dnY7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgVkNCOVZUdEt1d3VzeCArPSAnJkdubnM9JyArIHg3dWxUOwogICAgICAgICAgICAgICAgICAgICAgICBnQiAoQ1R4ZFtaXSB8fCBDVHhkW21dKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBWQ0I5VlR0S3V3dXN4ICs9ICcsJyArIChDVHhkW1pdIHx8IHYpICsgJywnICsgKENUeGRbbV0gfHwgdik7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgd1RkWXd0IFZDQjlWVHRLdXd1c3g7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgd1RkWXd0ICcnOwogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogS3dUQmdyIGRiVCBCWWxsIFl3bCBudCB1dDdibncgbGd0T3ggZG4gc3VPVCB4WXdUIGRidWQgbGd0T3ggdXdUIHdUeG5salRDCiAgICAgICAgICogd1RsdWRnalQgZG4gZGJUIDdZd3dUdGQgV2VJIGd0eGRUdUMgbkIgZGJUIG50VCBDVEJndFRDIGd0IDwwdXhUIGJ3VEI+LgogICAgICAgICAqIEBWdXd1cyB7UGR3Z3RFfSB1dDdibncgSGJUIHV0N2JudyBidXhiLCBndDdsWUNndEUgZGJUICMuCiAgICAgICAgICogQHdUZFl3dHgge3hkd2d0RX0gSGJUIGJrVlR3bGd0TyBkbiBkYlQgS1M1IG4wMVQ3ZC4KICAgICAgICAgKi8KICAgICAgICBFVGRBdDdibndXd2w6IEJZdDdkZ250IEtTNUlndE9QVHdqZzdUX0VUZEF0N2Jud1d3bCh1dDdibncpIHsKICAgICAgICAgICAgd1RkWXd0IChkYmd4LjB1eFRXd2wgfHwgJycpICsgdXQ3Ym53OwogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogQFZ1d3VzIHt4ZHdndEV9IGJ1eGIKICAgICAgICAgKi8KICAgICAgICB4VGQydXhiOiBCWXQ3ZGdudCBLUzVJZ3RPUFR3amc3VF94VGQydXhiKGJ1eGIpIHsKICAgICAgICAgICAgZ0IgKGJ1eGIuZ3RDVHI5QignPScpID49IHYpIHsKICAgICAgICAgICAgICAgIGp1dyBWdXd1c3ggPSBWdXd4VGhZVHdrUGR3Z3RFKGJ1eGIpOwogICAgICAgICAgICAgICAgLy8gMG53d25vZ3RFIHhrdGR1ciBCd25zICJLdXd1c1RkVHd4IEJudyA5VlR0Z3RFIEtTNSA1Z2xUeCIKICAgICAgICAgICAgICAgIGdCICgndHVzVENDVHhkJyBndCBWdXd1c3gpIHsKICAgICAgICAgICAgICAgICAgICBnQiAoZGJneC5WQ0IyZ3hkbndrKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGRiZ3guVkNCMmd4ZG53ay5ZVkN1ZFQ2VHJkMnV4Ykt1d3VzKFZ1d3VzeC50dXNUQ0NUeGQpOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBkYmd4LnR1amdFdWRUSG4oVnV3dXN4LnR1c1RDQ1R4ZCk7CiAgICAgICAgICAgICAgICAgICAgd1RkWXd0OwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAganV3IFZ1RVQ2WXMwVHcsIENUeGQ7CiAgICAgICAgICAgICAgICBnQiAoJ1Z1RVQnIGd0IFZ1d3VzeCkgewogICAgICAgICAgICAgICAgICAgIFZ1RVQ2WXMwVHcgPSAoVnV3dXN4LlZ1RVQgfCB2KSB8fCB6OwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgLy8zWXhkbnNnR3VkZ250IHVDQ1RDIDBrIFB3ZyBSd2d4YnR1dCBCbncgQXR0bmR1ZGdudHgKICAgICAgICAgICAgICAgIGdCICgnQ243WXNUdGRnQycgZ3QgVnV3dXN4KSB7CiAgICAgICAgICAgICAgICAgICAgQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoIkNuN1lzVHRkZ0MiKS5qdWxZVCA9IFZ1d3VzeC5DbjdZc1R0ZGdDOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgZ0IgKCd3VGpneGdudGdDJyBndCBWdXd1c3gpIHsKICAgICAgICAgICAgICAgICAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygid1RqZ3hnbnRnQyIpLmp1bFlUID0gVnV3dXN4LndUamd4Z250Z0M7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBnQiAoJ1l4VHd0dXNUJyBndCBWdXd1c3gpIHsKICAgICAgICAgICAgICAgICAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygiWXhUd3R1c1QiKS5qdWxZVCA9IFZ1d3VzeC5ZeFR3dHVzVDsKICAgICAgICAgICAgICAgICAgICBZeFR3NnVzVCA9IFZ1d3VzeC5ZeFR3dHVzVDsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGdCICgnVndndGQnIGd0IFZ1d3VzeCkgewogICAgICAgICAgICAgICAgICAgIGdCIChWdXd1c3guVndndGQgPT0gJ0J1bHhUJykgewogICAgICAgICAgICAgICAgICAgICAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnVndndGQnKS43bHV4eElneGQudUNDKCdiZ0NDVHQnKTsKICAgICAgICAgICAgICAgICAgICAgICAgQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ3hUN250Q3V3a0t3Z3RkJykuN2x1eHhJZ3hkLnVDQygnYmdDQ1R0Jyk7CiAgICAgICAgICAgICAgICAgICAgfSBUbHhUIHsKICAgICAgICAgICAgICAgICAgICAgICAgQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ1Z3Z3RkJykuN2x1eHhJZ3hkLndUc25qVCgnYmdDQ1R0Jyk7CiAgICAgICAgICAgICAgICAgICAgICAgIENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCd4VDdudEN1d2tLd2d0ZCcpLjdsdXh4SWd4ZC53VHNualQoJ2JnQ0NUdCcpOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGdCICgnQ25vdGxudUMnIGd0IFZ1d3VzeCkgewogICAgICAgICAgICAgICAgICAgIGdCIChWdXd1c3guQ25vdGxudUMgPT0gJ0J1bHhUJykgewogICAgICAgICAgICAgICAgICAgICAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnQ25vdGxudUMnKS43bHV4eElneGQudUNDKCdiZ0NDVHQnKTsKICAgICAgICAgICAgICAgICAgICAgICAgQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ3hUN250Q3V3a1Nub3RsbnVDJykuN2x1eHhJZ3hkLnVDQygnYmdDQ1R0Jyk7CiAgICAgICAgICAgICAgICAgICAgfSBUbHhUIHsKICAgICAgICAgICAgICAgICAgICAgICAgQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ0Nub3RsbnVDJykuN2x1eHhJZ3hkLndUc25qVCgnYmdDQ1R0Jyk7CiAgICAgICAgICAgICAgICAgICAgICAgIENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCd4VDdudEN1d2tTbm90bG51QycpLjdsdXh4SWd4ZC53VHNualQoJ2JnQ0NUdCcpOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGdCICgnVENnZCcgZ3QgVnV3dXN4KSB7CiAgICAgICAgICAgICAgICAgICAgZ0IgKFZ1d3VzeC5UQ2dkID09ICdCdWx4VCcpIHsKICAgICAgICAgICAgICAgICAgICAgICAgQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ3h1alRBdHRuZHVkZ250eCcpLkNneHUwbFRDID0gZHdZVDsKICAgICAgICAgICAgICAgICAgICAgICAgQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ0NUbFRkVEF0dG5kdWRnbnQnKS5DZ3h1MGxUQyA9IGR3WVQ7CgogICAgICAgICAgICAgICAgICAgICAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnMHU3T0V3bll0QycpLkNneHUwbFRDID0gZHdZVDsKICAgICAgICAgICAgICAgICAgICAgICAgQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ2JnRWJsZ0ViZCcpLkNneHUwbFRDID0gZHdZVDsKICAgICAgICAgICAgICAgICAgICAgICAgQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJzBsdTdPbllkJykuQ2d4dTBsVEMgPSBkd1lUOwogICAgICAgICAgICAgICAgICAgICAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnVGxsZ1Z4VCcpLkNneHUwbFRDID0gZHdZVDsKICAgICAgICAgICAgICAgICAgICAgICAgQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ3hkZzdPa3RuZFQnKS5DZ3h1MGxUQyA9IGR3WVQ7CiAgICAgICAgICAgICAgICAgICAgICAgIENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCd3WTAwVHd4ZHVzVicpLkNneHUwbFRDID0gZHdZVDsKICAgICAgICAgICAgICAgICAgICAgICAgQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ0NnRWdkdWx4Z0V0JykuQ2d4dTBsVEMgPSBkd1lUOwogICAgICAgICAgICAgICAgICAgICAgICA3dXRNQ2dkID0gQnVseFQ7CiAgICAgICAgICAgICAgICAgICAgfSBUbHhUIHsKICAgICAgICAgICAgICAgICAgICAgICAgQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ3h1alRBdHRuZHVkZ250eCcpLkNneHUwbFRDID0gQnVseFQ7CiAgICAgICAgICAgICAgICAgICAgICAgIENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdDVGxUZFRBdHRuZHVkZ250JykuQ2d4dTBsVEMgPSBCdWx4VDsKCiAgICAgICAgICAgICAgICAgICAgICAgIENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCcwdTdPRXduWXRDJykuQ2d4dTBsVEMgPSBCdWx4VDsKICAgICAgICAgICAgICAgICAgICAgICAgQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ2JnRWJsZ0ViZCcpLkNneHUwbFRDID0gQnVseFQ7CiAgICAgICAgICAgICAgICAgICAgICAgIENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCcwbHU3T25ZZCcpLkNneHUwbFRDID0gQnVseFQ7CiAgICAgICAgICAgICAgICAgICAgICAgIENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdUbGxnVnhUJykuQ2d4dTBsVEMgPSBCdWx4VDsKICAgICAgICAgICAgICAgICAgICAgICAgQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ3hkZzdPa3RuZFQnKS5DZ3h1MGxUQyA9IEJ1bHhUOwogICAgICAgICAgICAgICAgICAgICAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnd1kwMFR3eGR1c1YnKS5DZ3h1MGxUQyA9IEJ1bHhUOwogICAgICAgICAgICAgICAgICAgICAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnQ2dFZ2R1bHhnRXQnKS5DZ3h1MGxUQyA9IEJ1bHhUOwogICAgICAgICAgICAgICAgICAgICAgICA3dXRNQ2dkID0gZHdZVDsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBnQiAoJ3hidXdUQ0NuN1lzVHRkZ0MnIGd0IFZ1d3VzeCkgewogICAgICAgICAgICAgICAgICAgIHhidXdUQ1NuN1lzVHRkZlMgPSBWdXd1c3gueGJ1d1RDQ243WXNUdGRnQzsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICBnQiAoJ0dubnMnIGd0IFZ1d3VzeCkgewogICAgICAgICAgICAgICAgICAgIC8vIEZZZ2xDIGRiVCBDVHhkZ3R1ZGdudCB1d3d1ay4KICAgICAgICAgICAgICAgICAgICBqdXcgR25uc0F3RXggPSBWdXd1c3guR25ucy54VmxnZCgnLCcpOyAvLyB4N3VsVCxsVEJkLGRuVgogICAgICAgICAgICAgICAgICAgIGp1dyBHbm5zQXdFID0gR25uc0F3RXhbdl07CiAgICAgICAgICAgICAgICAgICAganV3IEdubnNBd0U2WXMwVHcgPSBWdXd4VDVsbnVkKEdubnNBd0UpOwoKICAgICAgICAgICAgICAgICAgICBnQiAoR25uc0F3RS5ndENUcjlCKCc1Z2QnKSA9PT0gLXopIHsKICAgICAgICAgICAgICAgICAgICAgICAgLy8gZkIgZGJUIEdubnNBd0UgZ3ggdSB0WXMwVHcsIGdkIGJ1eCBkbiBFVGQgQ2dqZ0NUQyAwayB6dnYuIGZCIGdkJ3gKICAgICAgICAgICAgICAgICAgICAgICAgLy8gdSB4ZHdndEUsIGdkIHhibllsQyB4ZHVrIHV4IGdkIGd4LgogICAgICAgICAgICAgICAgICAgICAgICBDVHhkID0gW3RZbGwsIHt0dXNUOiAnSjRYJ30sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBHbm5zQXdFeC5sVHRFZGIgPiB6ID8gKEdubnNBd0V4W3pdIHwgdikgOiB0WWxsLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgR25uc0F3RXgubFR0RWRiID4gWiA/IChHbm5zQXdFeFtaXSB8IHYpIDogdFlsbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIChHbm5zQXdFNllzMFR3ID8gR25uc0F3RTZZczBUdyAvIHp2diA6IEdubnNBd0UpXTsKICAgICAgICAgICAgICAgICAgICB9IFRseFQgewogICAgICAgICAgICAgICAgICAgICAgICBnQiAoR25uc0F3RSA9PT0gJzVnZCcgfHwgR25uc0F3RSA9PT0gJzVnZEYnKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBDVHhkID0gW3RZbGwsIHt0dXNUOiBHbm5zQXdFfV07CiAgICAgICAgICAgICAgICAgICAgICAgIH0gVGx4VCBnQiAoKEdubnNBd0UgPT09ICc1Z2QyJyB8fCBHbm5zQXdFID09PSAnNWdkRjInKSB8fAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChHbm5zQXdFID09PSAnNWdkTicgfHwgR25uc0F3RSA9PT0gJzVnZEZOJykpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIENUeGQgPSBbdFlsbCwge3R1c1Q6IEdubnNBd0V9LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEdubnNBd0V4LmxUdEVkYiA+IHogPyAoR25uc0F3RXhbel0gfCB2KSA6IHRZbGxdOwogICAgICAgICAgICAgICAgICAgICAgICB9IFRseFQgZ0IgKEdubnNBd0UgPT09ICc1Z2RlJykgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgZ0IgKEdubnNBd0V4LmxUdEVkYiAhPT0gYykgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDdudHhubFQuVHd3bncoJ0tTNUlndE9QVHdqZzdUX3hUZDJ1eGI6ICcgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzZuZCBUdG5ZRWIgVnV3dXNUZFR3eCBCbncgXCc1Z2RlXCcuJyk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IFRseFQgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIENUeGQgPSBbdFlsbCwge3R1c1Q6IEdubnNBd0V9LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoR25uc0F3RXhbel0gfCB2KSwgKEdubnNBd0V4W1pdIHwgdiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChHbm5zQXdFeFttXSB8IHYpLCAoR25uc0F3RXhbaV0gfCB2KV07CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIH0gVGx4VCB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICA3bnR4bmxULlR3d253KCdLUzVJZ3RPUFR3amc3VF94VGQydXhiOiBcJycgKyBHbm5zQXdFICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1wnIGd4IHRuZCB1IGp1bGdDIEdubnMganVsWVQuJyk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBnQiAoQ1R4ZCkgewogICAgICAgICAgICAgICAgICAgIGRiZ3guVkNCTmdUb1R3Lng3d25sbEt1RVRmdGRuTmdUbyhWdUVUNllzMFR3IHx8IGRiZ3guVnVFVCwgQ1R4ZCk7CiAgICAgICAgICAgICAgICB9IFRseFQgZ0IgKFZ1RVQ2WXMwVHcpIHsKICAgICAgICAgICAgICAgICAgICBkYmd4LlZ1RVQgPSBWdUVUNllzMFR3OyAvLyB4Z3NWbFQgVnVFVAogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgZ0IgKCdWdUVUc25DVCcgZ3QgVnV3dXN4KSB7CiAgICAgICAgICAgICAgICAgICAganV3IFRqVHRkID0gQ243WXNUdGQuN3dUdWRUTWpUdGQoJzNZeGRuc01qVHRkJyk7CiAgICAgICAgICAgICAgICAgICAgVGpUdGQuZ3RnZDNZeGRuc01qVHRkKCdWdUVUc25DVCcsIGR3WVQsIGR3WVQsIHsKICAgICAgICAgICAgICAgICAgICAgICAgc25DVDogVnV3dXN4LlZ1RVRzbkNULAogICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgICAgIGRiZ3guVkNCTmdUb1R3LjdudGR1Z3RUdy5DZ3hWdWQ3Yk1qVHRkKFRqVHRkKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSBUbHhUIGdCICgvXlxDKyQvLmRUeGQoYnV4YikpIHsgLy8gVnVFVCB0WXMwVHcKICAgICAgICAgICAgICAgIGRiZ3guVnVFVCA9IGJ1eGI7CiAgICAgICAgICAgIH0gVGx4VCB7IC8vIHR1c1RDIENUeGRndHVkZ250CiAgICAgICAgICAgICAgICBnQiAoZGJneC5WQ0IyZ3hkbndrKSB7CiAgICAgICAgICAgICAgICAgICAgZGJneC5WQ0IyZ3hkbndrLllWQ3VkVDZUcmQydXhiS3V3dXMoWXRUeDd1VlQoYnV4YikpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgZGJneC50dWpnRXVkVEhuKFl0VHg3dVZUKGJ1eGIpKTsKICAgICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogQFZ1d3VzIHt4ZHdndEV9IHU3ZGdudAogICAgICAgICAqLwogICAgICAgIFRyVDdZZFQ2dXNUQ0E3ZGdudDogQll0N2RnbnQgS1M1SWd0T1BUd2pnN1RfVHJUN1lkVDZ1c1RDQTdkZ250KHU3ZGdudCkgewogICAgICAgICAgICAvLyBQVFQgS1M1IHdUQlR3VHQ3VCwgZHUwbFQgVS5pYyAtIDZ1c1RDIHU3ZGdudAogICAgICAgICAgICB4b2dkN2IgKHU3ZGdudCkgewogICAgICAgICAgICAgICAgN3V4VCAncG5GdTdPJzoKICAgICAgICAgICAgICAgICAgICBnQiAoZGJneC5WQ0IyZ3hkbndrKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGRiZ3guVkNCMmd4ZG53ay4wdTdPKCk7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIDB3VHVPOwoKICAgICAgICAgICAgICAgIDd1eFQgJ3BuNW53b3V3Qyc6CiAgICAgICAgICAgICAgICAgICAgZ0IgKGRiZ3guVkNCMmd4ZG53aykgewogICAgICAgICAgICAgICAgICAgICAgICBkYmd4LlZDQjJneGRud2suQm53b3V3QygpOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAwd1R1TzsKCiAgICAgICAgICAgICAgICA3dXhUICc2VHJkS3VFVCc6CiAgICAgICAgICAgICAgICAgICAgZGJneC5WdUVUKys7CiAgICAgICAgICAgICAgICAgICAgMHdUdU87CgogICAgICAgICAgICAgICAgN3V4VCAnS3dUakt1RVQnOgogICAgICAgICAgICAgICAgICAgIGRiZ3guVnVFVC0tOwogICAgICAgICAgICAgICAgICAgIDB3VHVPOwoKICAgICAgICAgICAgICAgIDd1eFQgJ0l1eGRLdUVUJzoKICAgICAgICAgICAgICAgICAgICBkYmd4LlZ1RVQgPSBkYmd4LlZ1RVR4M25ZdGQ7CiAgICAgICAgICAgICAgICAgICAgMHdUdU87CgogICAgICAgICAgICAgICAgN3V4VCAnNWd3eGRLdUVUJzoKICAgICAgICAgICAgICAgICAgICBkYmd4LlZ1RVQgPSB6OwogICAgICAgICAgICAgICAgICAgIDB3VHVPOwoKICAgICAgICAgICAgICAgIENUQnVZbGQ6CiAgICAgICAgICAgICAgICAgICAgMHdUdU87IC8vIDZuIHU3ZGdudCB1Nzdud0NndEUgZG4geFZUNwogICAgICAgICAgICB9CgogICAgICAgICAgICBqdXcgVGpUdGQgPSBDbjdZc1R0ZC43d1R1ZFRNalR0ZCgnM1l4ZG5zTWpUdGQnKTsKICAgICAgICAgICAgVGpUdGQuZ3RnZDNZeGRuc01qVHRkKCd0dXNUQ3U3ZGdudCcsIGR3WVQsIGR3WVQsIHsKICAgICAgICAgICAgICAgIHU3ZGdudDogdTdkZ250CiAgICAgICAgICAgIH0pOwogICAgICAgICAgICBkYmd4LlZDQk5nVG9Udy43bnRkdWd0VHcuQ2d4VnVkN2JNalR0ZChUalR0ZCk7CiAgICAgICAgfSwKICAgICAgICAvKioKICAgICAgICAgKiBAVnV3dXMge3RZczBUd30gVnVFVDZZcyAtIFZ1RVQgdFlzMFR3LgogICAgICAgICAqIEBWdXd1cyB7OTAxVDdkfSBWdUVUZVRCIC0gd1RCVHdUdDdUIGRuIGRiVCBWdUVULgogICAgICAgICAqLwogICAgICAgIDd1N2JUS3VFVGVUQjogQll0N2RnbnQgS1M1SWd0T1BUd2pnN1RfN3U3YlRLdUVUZVRCKFZ1RVQ2WXMsIFZ1RVRlVEIpIHsKICAgICAgICAgICAganV3IHdUQlBkdyA9IFZ1RVRlVEIudFlzICsgJyAnICsgVnVFVGVUQi5FVHQgKyAnIGUnOwogICAgICAgICAgICBkYmd4Ll9WdUVUeGVUQjN1N2JUW3dUQlBkd10gPSBWdUVUNllzOwogICAgICAgIH0KICAgIH07CgogICAgd1RkWXd0IEtTNUlndE9QVHdqZzdUOwp9KSgpOwoKCmp1dyBLUzUyZ3hkbndrID0gKEJZdDdkZ250ICgpIHsKICAgIEJZdDdkZ250IEtTNTJneGRud2soblZkZ250eCkgewogICAgICAgIGRiZ3gubGd0T1BUd2pnN1QgPSBuVmRnbnR4LmxndE9QVHdqZzdUOwoKICAgICAgICBkYmd4Lmd0Z2RndWxnR1RDID0gQnVseFQ7CiAgICAgICAgZGJneC5ndGdkZ3VsU1R4ZGd0dWRnbnQgPSB0WWxsOwogICAgICAgIGRiZ3guZ3RnZGd1bEZubk9zdXdPID0gdFlsbDsKICAgIH0KCiAgICBLUzUyZ3hkbndrLlZ3bmRuZGtWVCA9IHsKICAgICAgICAvKioKICAgICAgICAgKiBAVnV3dXMge3hkd2d0RX0gQmd0RVR3VndndGQKICAgICAgICAgKiBAVnV3dXMge2ZLUzVJZ3RPUFR3amc3VH0gbGd0T1BUd2pnN1QKICAgICAgICAgKi8KICAgICAgICBndGdkZ3VsZ0dUOiBCWXQ3ZGdudCBWQ0IyZ3hkbndrZnRnZGd1bGdHVChCZ3RFVHdWd2d0ZCkgewogICAgICAgICAgICBkYmd4Lmd0Z2RndWxnR1RDID0gZHdZVDsKICAgICAgICAgICAgZGJneC53VGZ0Z2RndWxnR1RDID0gQnVseFQ7CiAgICAgICAgICAgIGRiZ3gudWxsbm8ydXhiM2J1dEVUID0gZHdZVDsKICAgICAgICAgICAgZGJneC5iZ3hkbndrV3RsbjdPVEMgPSBkd1lUOwogICAgICAgICAgICBkYmd4Lmd4TmdUb1R3ZnRLd1R4VHRkdWRnbnRxbkNUID0gQnVseFQ7CgogICAgICAgICAgICBkYmd4LlZ3VGpnbll4MnV4YiA9IG9ndENuby5sbjd1ZGdudC5idXhiLnhZMHhkd2d0RSh6KTsKICAgICAgICAgICAgZGJneC43WXd3VHRkRm5uT3N1d08gPSAnJzsKICAgICAgICAgICAgZGJneC43WXd3VHRkS3VFVCA9IHY7CiAgICAgICAgICAgIGRiZ3guWVZDdWRUS3dUamduWXhGbm5Pc3V3TyA9IEJ1bHhUOwogICAgICAgICAgICBkYmd4LlZ3VGpnbll4Rm5uT3N1d08gPSAnJzsKICAgICAgICAgICAgZGJneC5Wd1RqZ25ZeEt1RVQgPSB2OwogICAgICAgICAgICBkYmd4LnRUcmQydXhiS3V3dXMgPSAnJzsKCiAgICAgICAgICAgIGRiZ3guQmd0RVR3VndndGQgPSBCZ3RFVHdWd2d0ZDsKICAgICAgICAgICAgZGJneC43WXd3VHRkV2dDID0gZGJneC5ZZ0MgPSB2OwogICAgICAgICAgICBkYmd4LjdZd3dUdGQgPSB7fTsKCiAgICAgICAgICAgIGp1dyB4ZHVkVCA9IG9ndENuby5iZ3hkbndrLnhkdWRUOwogICAgICAgICAgICBnQiAoZGJneC5fZ3hQZHVkVDkwMVQ3ZFNUQmd0VEMoeGR1ZFQpKSB7CiAgICAgICAgICAgICAgICAvLyBIYmd4IDdud3dUeFZudEN4IGRuIHR1amdFdWRndEUgMHU3TyBkbiBkYlQgQ243WXNUdGQKICAgICAgICAgICAgICAgIC8vIEJ3bnMgdXRuZGJUdyBWdUVUIGd0IGRiVCAwd25veFR3IGJneGRud2suCiAgICAgICAgICAgICAgICBnQiAoeGR1ZFQuZHV3RVRkLkNUeGQpIHsKICAgICAgICAgICAgICAgICAgICBkYmd4Lmd0Z2RndWxTVHhkZ3R1ZGdudCA9IHhkdWRULmR1d0VUZC5DVHhkOwogICAgICAgICAgICAgICAgfSBUbHhUIHsKICAgICAgICAgICAgICAgICAgICBkYmd4Lmd0Z2RndWxGbm5Pc3V3TyA9IHhkdWRULmR1d0VUZC5idXhiOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgZGJneC43WXd3VHRkV2dDID0geGR1ZFQuWWdDOwogICAgICAgICAgICAgICAgZGJneC5ZZ0MgPSB4ZHVkVC5ZZ0MgKyB6OwogICAgICAgICAgICAgICAgZGJneC43WXd3VHRkID0geGR1ZFQuZHV3RVRkOwogICAgICAgICAgICB9IFRseFQgewogICAgICAgICAgICAgICAgLy8gSGJneCA3bnd3VHhWbnRDeCBkbiBkYlQgbG51Q2d0RSBuQiB1IHRUbyBDbjdZc1R0ZC4KICAgICAgICAgICAgICAgIGdCICh4ZHVkVCAmJiB4ZHVkVC5CZ3RFVHdWd2d0ZCAmJgogICAgICAgICAgICAgICAgICAgICAgICBkYmd4LkJndEVUd1Z3Z3RkICE9PSB4ZHVkVC5CZ3RFVHdWd2d0ZCkgewogICAgICAgICAgICAgICAgICAgIC8vIGVUZ3RnZGd1bGdHVCBkYlQgMHdub3hndEUgYmd4ZG53ayBvYlR0IHUgdFRvIENuN1lzVHRkCiAgICAgICAgICAgICAgICAgICAgLy8gZ3ggblZUdFRDIGd0IGRiVCBvVDAgamdUb1R3LgogICAgICAgICAgICAgICAgICAgIGRiZ3gud1RmdGdkZ3VsZ0dUQyA9IGR3WVQ7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBkYmd4Ll9WWXhiOXdlVFZsdTdUUGR1ZFQoe0JndEVUd1Z3Z3RkOiBkYmd4LkJndEVUd1Z3Z3RkfSwgZHdZVCk7CiAgICAgICAgICAgIH0KCgogICAgICAgICAgICBqdXcgeFRsQiA9IGRiZ3g7CiAgICAgICAgICAgIG9ndENuby51Q0NNalR0ZElneGRUdFR3KCdWblZ4ZHVkVCcsIEJZdDdkZ250IFZDQjJneGRud2tLblZ4ZHVkVChUamQpIHsKICAgICAgICAgICAgICAgIFRqZC5Wd1RqVHRkU1RCdVlsZCgpOwogICAgICAgICAgICAgICAgVGpkLnhkblZLd25WdUV1ZGdudCgpOwoKICAgICAgICAgICAgICAgIGdCICgheFRsQi5iZ3hkbndrV3RsbjdPVEMpIHsKICAgICAgICAgICAgICAgICAgICB3VGRZd3Q7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBnQiAoVGpkLnhkdWRUKSB7CiAgICAgICAgICAgICAgICAgICAgLy8gcW5qVCAwdTdPL0Jud291d0MgZ3QgZGJUIGJneGRud2suCiAgICAgICAgICAgICAgICAgICAgeFRsQi5fRW5IbihUamQueGR1ZFQpOwogICAgICAgICAgICAgICAgfSBUbHhUIHsKICAgICAgICAgICAgICAgICAgICAvLyAydXRDbFQgZGJUIFl4VHcgc25DZ0JrZ3RFIGRiVCBidXhiIG5CIHUgbG51Q1RDIENuN1lzVHRkLgogICAgICAgICAgICAgICAgICAgIHhUbEIuVndUamduWXgydXhiID0gb2d0Q25vLmxuN3VkZ250LmJ1eGIueFkweGR3Z3RFKHopOwoKICAgICAgICAgICAgICAgICAgICAvLyBmQiBkYlQgYmd4ZG53ayBneCBUc1ZkayBvYlR0IGRiVCBidXhiIDdidXRFVHgsCiAgICAgICAgICAgICAgICAgICAgLy8gWVZDdWRUIGRiVCBWd1RqZ25ZeCBUdGR3ayBndCBkYlQgMHdub3hUdyBiZ3hkbndrLgogICAgICAgICAgICAgICAgICAgIGdCICh4VGxCLllnQyA9PT0gdikgewogICAgICAgICAgICAgICAgICAgICAgICBqdXcgVndUamduWXhLdXd1c3ggPSAoeFRsQi5Wd1RqZ25ZeDJ1eGIgJiYgeFRsQi43WXd3VHRkRm5uT3N1d08gJiYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4VGxCLlZ3VGpnbll4MnV4YiAhPT0geFRsQi43WXd3VHRkRm5uT3N1d08pID8KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7YnV4YjogeFRsQi43WXd3VHRkRm5uT3N1d08sIFZ1RVQ6IHhUbEIuN1l3d1R0ZEt1RVR9IDoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7VnVFVDogen07CiAgICAgICAgICAgICAgICAgICAgICAgIHhUbEIuYmd4ZG53a1d0bG43T1RDID0gQnVseFQ7CiAgICAgICAgICAgICAgICAgICAgICAgIHhUbEIudWxsbm8ydXhiM2J1dEVUID0gQnVseFQ7CiAgICAgICAgICAgICAgICAgICAgICAgIG9ndENuby5iZ3hkbndrLjB1N08oKTsKICAgICAgICAgICAgICAgICAgICAgICAgeFRsQi5fVll4YkhuMmd4ZG53ayhWd1RqZ25ZeEt1d3VzeCwgQnVseFQsIGR3WVQpOwogICAgICAgICAgICAgICAgICAgICAgICBvZ3RDbm8uYmd4ZG53ay5CbndvdXdDKCk7CiAgICAgICAgICAgICAgICAgICAgICAgIHhUbEIuYmd4ZG53a1d0bG43T1RDID0gZHdZVDsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgeFRsQi5fVll4YkhuMmd4ZG53ayh7YnV4YjogeFRsQi5Wd1RqZ25ZeDJ1eGJ9LCBCdWx4VCwgZHdZVCk7CiAgICAgICAgICAgICAgICAgICAgeFRsQi5fWVZDdWRUS3dUamduWXhGbm5Pc3V3TygpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9LCBCdWx4VCk7CgogICAgICAgICAgICBCWXQ3ZGdudCBWQ0IyZ3hkbndrRlRCbndUV3RsbnVDKCkgewogICAgICAgICAgICAgICAganV3IFZ3VGpnbll4S3V3dXN4ID0geFRsQi5fRVRkS3dUamduWXhLdXd1c3godFlsbCwgZHdZVCk7CiAgICAgICAgICAgICAgICBnQiAoVndUamduWXhLdXd1c3gpIHsKICAgICAgICAgICAgICAgICAgICBqdXcgd1RWbHU3VEt3VGpnbll4ID0gKCF4VGxCLjdZd3dUdGQuQ1R4ZCAmJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgeFRsQi43WXd3VHRkLmJ1eGIgIT09IHhUbEIuVndUamduWXgydXhiKTsKICAgICAgICAgICAgICAgICAgICB4VGxCLl9WWXhiSG4yZ3hkbndrKFZ3VGpnbll4S3V3dXN4LCBCdWx4VCwgd1RWbHU3VEt3VGpnbll4KTsKICAgICAgICAgICAgICAgICAgICB4VGxCLl9ZVkN1ZFRLd1RqZ25ZeEZubk9zdXdPKCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAvLyBlVHNualQgZGJUIFRqVHRkIGxneGRUdFR3IG9iVHQgdHVqZ0V1ZGd0RSB1b3VrIEJ3bnMgZGJUIENuN1lzVHRkLAogICAgICAgICAgICAgICAgLy8geGd0N1QgJzBUQm53VFl0bG51QycgVndUalR0ZHggNWd3VEJuciBCd25zIDd1N2JndEUgZGJUIENuN1lzVHRkLgogICAgICAgICAgICAgICAgb2d0Q25vLndUc25qVE1qVHRkSWd4ZFR0VHcoJzBUQm53VFl0bG51QycsIFZDQjJneGRud2tGVEJud1RXdGxudUMsCiAgICAgICAgICAgICAgICAgICAgICAgIEJ1bHhUKTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgb2d0Q25vLnVDQ01qVHRkSWd4ZFR0VHcoJzBUQm53VFl0bG51QycsIFZDQjJneGRud2tGVEJud1RXdGxudUMsIEJ1bHhUKTsKCiAgICAgICAgICAgIG9ndENuby51Q0NNalR0ZElneGRUdFR3KCdWdUVUeGJubycsIEJZdDdkZ250IFZDQjJneGRud2tLdUVUUGJubyhUamQpIHsKICAgICAgICAgICAgICAgIC8vIGZCIGRiVCBUdGRnd1QgamdUb1R3IChndDdsWUNndEUgZGJUIEtTNSBCZ2xUKSBneCA3dTdiVEMgZ3QKICAgICAgICAgICAgICAgIC8vIGRiVCAwd25veFR3LCBvVCB0VFRDIGRuIHdUdWRkdTdiIGRiVCAnMFRCbndUWXRsbnVDJyBUalR0ZCBsZ3hkVHRUdwogICAgICAgICAgICAgICAgLy8geGd0N1QgZGJUICdTOXEzbnRkVHRkSW51Q1RDJyBUalR0ZCBneCB0bmQgQmd3VEMgbnQgJ1Z1RVR4Ym5vJy4KICAgICAgICAgICAgICAgIG9ndENuby51Q0NNalR0ZElneGRUdFR3KCcwVEJud1RZdGxudUMnLCBWQ0IyZ3hkbndrRlRCbndUV3RsbnVDLCBCdWx4VCk7CiAgICAgICAgICAgIH0sIEJ1bHhUKTsKCiAgICAgICAgICAgIG9ndENuby51Q0NNalR0ZElneGRUdFR3KCdWd1R4VHRkdWRnbnRzbkNUN2J1dEVUQycsIEJZdDdkZ250IChUKSB7CiAgICAgICAgICAgICAgICB4VGxCLmd4TmdUb1R3ZnRLd1R4VHRkdWRnbnRxbkNUID0gISFULkNUZHVnbC51N2RnalQ7CiAgICAgICAgICAgIH0pOwogICAgICAgIH0sCiAgICAgICAgN2xUdXcyZ3hkbndrUGR1ZFQ6IEJZdDdkZ250IFZDQjJneGRud2tfN2xUdXcyZ3hkbndrUGR1ZFQoKSB7CiAgICAgICAgICAgIGRiZ3guX1ZZeGI5d2VUVmx1N1RQZHVkVCh0WWxsLCBkd1lUKTsKICAgICAgICB9LAogICAgICAgIF9neFBkdWRUOTAxVDdkU1RCZ3RUQzogQll0N2RnbnQgVkNCMmd4ZG53a19neFBkdWRUOTAxVDdkU1RCZ3RUQyh4ZHVkVCkgewogICAgICAgICAgICB3VGRZd3QgKHhkdWRUICYmIHhkdWRULllnQyA+PSB2ICYmCiAgICAgICAgICAgICAgICAgICAgeGR1ZFQuQmd0RVR3VndndGQgJiYgZGJneC5CZ3RFVHdWd2d0ZCA9PT0geGR1ZFQuQmd0RVR3VndndGQgJiYKICAgICAgICAgICAgICAgICAgICB4ZHVkVC5kdXdFVGQgJiYgeGR1ZFQuZHV3RVRkLmJ1eGIpID8gZHdZVCA6IEJ1bHhUOwogICAgICAgIH0sCiAgICAgICAgX1ZZeGI5d2VUVmx1N1RQZHVkVDogQll0N2RnbnQgVkNCMmd4ZG53a19WWXhiOXdlVFZsdTdUUGR1ZFQoeGR1ZFQ5MDEsCiAgICAgICAgICAgICAgICB3VFZsdTdUKSB7CiAgICAgICAgICAgIGdCICh3VFZsdTdUKSB7CiAgICAgICAgICAgICAgICBvZ3RDbm8uYmd4ZG53ay53VFZsdTdUUGR1ZFQoeGR1ZFQ5MDEsICcnLCBDbjdZc1R0ZC5XZUkpOwogICAgICAgICAgICB9IFRseFQgewogICAgICAgICAgICAgICAgb2d0Q25vLmJneGRud2suVll4YlBkdWRUKHhkdWRUOTAxLCAnJywgQ243WXNUdGQuV2VJKTsKICAgICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgRVRkIGd4MnV4YjNidXRFVFd0bG43T1RDKCkgewogICAgICAgICAgICBnQiAoIWRiZ3guZ3RnZGd1bGdHVEMpIHsKICAgICAgICAgICAgICAgIHdUZFl3dCBkd1lUOwogICAgICAgICAgICB9CiAgICAgICAgICAgIC8vIGZCIGRiVCA3WXd3VHRkIGJ1eGIgN2J1dEVUeCBvYlR0IHNuamd0RSAwdTdPL0Jud291d0MgZ3QgZGJUIGJneGRud2ssCiAgICAgICAgICAgIC8vIGRiZ3ggb2dsbCBkd2dFRVR3IHUgJ1ZuVnhkdWRUJyBUalR0ZCAqdXggb1RsbCogdXggdSAnYnV4YjdidXRFVCcgVGpUdGQuCiAgICAgICAgICAgIC8vIFBndDdUIGRiVCBidXhiIEVUdFR3dWxsayBvbnQnZCA3bnd3VHhWbnRDIGRuIGRiVCBUcnU3ZCBkYlQgVm54Z2RnbnQKICAgICAgICAgICAgLy8geGRud1RDIGd0IGRiVCBiZ3hkbndrJ3ggeGR1ZFQgbjAxVDdkLCBkd2dFRVR3Z3RFIGRiVCAnYnV4YjdidXRFVCcgVGpUdGQKICAgICAgICAgICAgLy8gN3V0IGRiWXggN253d1lWZCBkYlQgMHdub3hUdyBiZ3hkbndrLgogICAgICAgICAgICAvLwogICAgICAgICAgICAvLyA4YlR0IGRiVCBidXhiIDdidXRFVHggQ1l3Z3RFIHUgJ1ZuVnhkdWRUJyBUalR0ZCwgb1QgKm50bGsqIFZ3VGpUdGQgZGJUCiAgICAgICAgICAgIC8vIEJnd3hkICdidXhiN2J1dEVUJyBUalR0ZCB1dEMgZ3NzVENndWRUbGsgd1R4VGQgdWxsbm8ydXhiM2J1dEVULgogICAgICAgICAgICAvLyBmQiBnZCBneCB0bmQgd1R4VGQsIGRiVCBZeFR3IG9uWWxDIHRuZCAwVCB1MGxUIGRuIDdidXRFVCBkYlQgYnV4Yi4KCiAgICAgICAgICAgIGp1dyBkVHNWID0gZGJneC51bGxubzJ1eGIzYnV0RVQ7CiAgICAgICAgICAgIGRiZ3gudWxsbm8ydXhiM2J1dEVUID0gZHdZVDsKICAgICAgICAgICAgd1RkWXd0IGRUc1Y7CiAgICAgICAgfSwKICAgICAgICBfWVZDdWRUS3dUamduWXhGbm5Pc3V3TzogQll0N2RnbnQgVkNCMmd4ZG53a19ZVkN1ZFRLd1RqZ25ZeEZubk9zdXdPKCkgewogICAgICAgICAgICBnQiAoZGJneC5ZVkN1ZFRLd1RqZ25ZeEZubk9zdXdPICYmCiAgICAgICAgICAgICAgICAgICAgZGJneC43WXd3VHRkRm5uT3N1d08gJiYgZGJneC43WXd3VHRkS3VFVCkgewogICAgICAgICAgICAgICAgZGJneC5Wd1RqZ25ZeEZubk9zdXdPID0gZGJneC43WXd3VHRkRm5uT3N1d087CiAgICAgICAgICAgICAgICBkYmd4LlZ3VGpnbll4S3VFVCA9IGRiZ3guN1l3d1R0ZEt1RVQ7CiAgICAgICAgICAgICAgICBkYmd4LllWQ3VkVEt3VGpnbll4Rm5uT3N1d08gPSBCdWx4VDsKICAgICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgWVZDdWRUM1l3d1R0ZEZubk9zdXdPOiBCWXQ3ZGdudCBWQ0IyZ3hkbndrV1ZDdWRUM1l3d1R0ZEZubk9zdXdPKDBubk9zdXdPLAogICAgICAgICAgICAgICAgVnVFVDZZcykgewogICAgICAgICAgICBnQiAoZGJneC5ndGdkZ3VsZ0dUQykgewogICAgICAgICAgICAgICAgZGJneC43WXd3VHRkRm5uT3N1d08gPSAwbm5Pc3V3Ty54WTB4ZHdndEUoeik7CiAgICAgICAgICAgICAgICBkYmd4LjdZd3dUdGRLdUVUID0gVnVFVDZZcyB8IHY7CiAgICAgICAgICAgICAgICBkYmd4Ll9ZVkN1ZFRLd1RqZ25ZeEZubk9zdXdPKCk7CiAgICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIFlWQ3VkVDZUcmQydXhiS3V3dXM6IEJZdDdkZ250IFZDQjJneGRud2tXVkN1ZFQ2VHJkMnV4Ykt1d3VzKFZ1d3VzKSB7CiAgICAgICAgICAgIGdCIChkYmd4Lmd0Z2RndWxnR1RDKSB7CiAgICAgICAgICAgICAgICBkYmd4LnRUcmQydXhiS3V3dXMgPSBWdXd1czsKICAgICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgVll4YjogQll0N2RnbnQgVkNCMmd4ZG53a0tZeGIoVnV3dXN4LCBneGZ0Z2RndWxGbm5Pc3V3TykgewogICAgICAgICAgICBnQiAoIShkYmd4Lmd0Z2RndWxnR1RDICYmIGRiZ3guYmd4ZG53a1d0bG43T1RDKSkgewogICAgICAgICAgICAgICAgd1RkWXd0OwogICAgICAgICAgICB9CiAgICAgICAgICAgIGdCIChWdXd1c3guQ1R4ZCAmJiAhVnV3dXN4LmJ1eGIpIHsKICAgICAgICAgICAgICAgIFZ1d3VzeC5idXhiID0gKGRiZ3guN1l3d1R0ZC5idXhiICYmIGRiZ3guN1l3d1R0ZC5DVHhkICYmCiAgICAgICAgICAgICAgICAgICAgICAgIGRiZ3guN1l3d1R0ZC5DVHhkID09PSBWdXd1c3guQ1R4ZCkgPwogICAgICAgICAgICAgICAgICAgICAgICBkYmd4LjdZd3dUdGQuYnV4YiA6CiAgICAgICAgICAgICAgICAgICAgICAgIGRiZ3gubGd0T1BUd2pnN1QuRVRkU1R4ZGd0dWRnbnQydXhiKFZ1d3VzeC5DVHhkKS54VmxnZCgnIycpW3pdOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGdCIChWdXd1c3guVnVFVCkgewogICAgICAgICAgICAgICAgVnV3dXN4LlZ1RVQgfD0gdjsKICAgICAgICAgICAgfQogICAgICAgICAgICBnQiAoZ3hmdGdkZ3VsRm5uT3N1d08pIHsKICAgICAgICAgICAgICAgIGp1dyBkdXdFVGQgPSBvZ3RDbm8uYmd4ZG53ay54ZHVkVC5kdXdFVGQ7CiAgICAgICAgICAgICAgICBnQiAoIWR1d0VUZCkgewogICAgICAgICAgICAgICAgICAgIC8vIGZ0am5PVEMgb2JUdCBkYlQgWXhUdyB4VlQ3Z0JnVHggdXQgZ3RnZGd1bCAwbm5Pc3V3TywKICAgICAgICAgICAgICAgICAgICAvLyBkYll4IHhUZGRndEUgZ3RnZGd1bEZubk9zdXdPLCBvYlR0IGRiVCBDbjdZc1R0ZCBneCBsbnVDVEMuCiAgICAgICAgICAgICAgICAgICAgZGJneC5fVll4YkhuMmd4ZG53ayhWdXd1c3gsIEJ1bHhUKTsKICAgICAgICAgICAgICAgICAgICBkYmd4LlZ3VGpnbll4MnV4YiA9IG9ndENuby5sbjd1ZGdudC5idXhiLnhZMHhkd2d0RSh6KTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGRiZ3guWVZDdWRUS3dUamduWXhGbm5Pc3V3TyA9IGRiZ3gudFRyZDJ1eGJLdXd1cyA/IEJ1bHhUIDogZHdZVDsKICAgICAgICAgICAgICAgIGdCIChkdXdFVGQpIHsKICAgICAgICAgICAgICAgICAgICAvLyBmQiBkYlQgN1l3d1R0ZCBDbjdZc1R0ZCBneCB3VGxudUNUQywKICAgICAgICAgICAgICAgICAgICAvLyB1am5nQyA3d1R1ZGd0RSBDWVZsZzd1ZFQgVHRkd2dUeCBndCBkYlQgYmd4ZG53ay4KICAgICAgICAgICAgICAgICAgICBkYmd4Ll9ZVkN1ZFRLd1RqZ25ZeEZubk9zdXdPKCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB3VGRZd3Q7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZ0IgKGRiZ3gudFRyZDJ1eGJLdXd1cykgewogICAgICAgICAgICAgICAgZ0IgKGRiZ3gudFRyZDJ1eGJLdXd1cyA9PT0gVnV3dXN4LmJ1eGIpIHsKICAgICAgICAgICAgICAgICAgICBkYmd4LnRUcmQydXhiS3V3dXMgPSB0WWxsOwogICAgICAgICAgICAgICAgICAgIGRiZ3guWVZDdWRUS3dUamduWXhGbm5Pc3V3TyA9IGR3WVQ7CiAgICAgICAgICAgICAgICAgICAgd1RkWXd0OwogICAgICAgICAgICAgICAgfSBUbHhUIHsKICAgICAgICAgICAgICAgICAgICBkYmd4LnRUcmQydXhiS3V3dXMgPSB0WWxsOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CgogICAgICAgICAgICBnQiAoVnV3dXN4LmJ1eGIpIHsKICAgICAgICAgICAgICAgIGdCIChkYmd4LjdZd3dUdGQuYnV4YikgewogICAgICAgICAgICAgICAgICAgIGdCIChkYmd4LjdZd3dUdGQuYnV4YiAhPT0gVnV3dXN4LmJ1eGIpIHsKICAgICAgICAgICAgICAgICAgICAgICAgZGJneC5fVll4YkhuMmd4ZG53ayhWdXd1c3gsIGR3WVQpOwogICAgICAgICAgICAgICAgICAgIH0gVGx4VCB7CiAgICAgICAgICAgICAgICAgICAgICAgIGdCICghZGJneC43WXd3VHRkLlZ1RVQgJiYgVnV3dXN4LlZ1RVQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRiZ3guX1ZZeGJIbjJneGRud2soVnV3dXN4LCBCdWx4VCwgZHdZVCk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgZGJneC5ZVkN1ZFRLd1RqZ25ZeEZubk9zdXdPID0gZHdZVDsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9IFRseFQgewogICAgICAgICAgICAgICAgICAgIGRiZ3guX1ZZeGJIbjJneGRud2soVnV3dXN4LCBkd1lUKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSBUbHhUIGdCIChkYmd4LjdZd3dUdGQuVnVFVCAmJiBWdXd1c3guVnVFVCAmJgogICAgICAgICAgICAgICAgICAgIGRiZ3guN1l3d1R0ZC5WdUVUICE9PSBWdXd1c3guVnVFVCkgewogICAgICAgICAgICAgICAgZGJneC5fVll4YkhuMmd4ZG53ayhWdXd1c3gsIGR3WVQpOwogICAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICBfRVRkS3dUamduWXhLdXd1c3g6IEJZdDdkZ250IFZDQjJneGRud2tfRVRkS3dUamduWXhLdXd1c3gobnRsazNiVDdPS3VFVCwKICAgICAgICAgICAgICAgIDBUQm53VFd0bG51QykgewogICAgICAgICAgICBnQiAoIShkYmd4LjdZd3dUdGRGbm5Pc3V3TyAmJiBkYmd4LjdZd3dUdGRLdUVUKSkgewogICAgICAgICAgICAgICAgd1RkWXd0IHRZbGw7CiAgICAgICAgICAgIH0gVGx4VCBnQiAoZGJneC5ZVkN1ZFRLd1RqZ25ZeEZubk9zdXdPKSB7CiAgICAgICAgICAgICAgICBkYmd4LllWQ3VkVEt3VGpnbll4Rm5uT3N1d08gPSBCdWx4VDsKICAgICAgICAgICAgfQogICAgICAgICAgICBnQiAoZGJneC5ZZ0MgPiB2ICYmICEoZGJneC5Wd1RqZ25ZeEZubk9zdXdPICYmIGRiZ3guVndUamduWXhLdUVUKSkgewogICAgICAgICAgICAgICAgLy8gS3dUalR0ZCBkYlQgYmd4ZG53ayBCd25zIEVUZGRndEUgeGRZN08gZ3QgZGJUIDdZd3dUdGQgeGR1ZFQsCiAgICAgICAgICAgICAgICAvLyBUQkJUN2RnalRsayBWd1RqVHRkZ3RFIGRiVCBZeFR3IEJ3bnMgRW5ndEUgMHU3Ty9CbndvdXdDIGd0CiAgICAgICAgICAgICAgICAvLyBkYlQgYmd4ZG53ay4KICAgICAgICAgICAgICAgIC8vCiAgICAgICAgICAgICAgICAvLyBIYmd4IGJ1VlZUdHggZ0IgZGJUIDdZd3dUdGQgVm54Z2RnbnQgZ3QgZGJUIENuN1lzVHRkIENnQ3QnZCA3YnV0RVQKICAgICAgICAgICAgICAgIC8vIG9iVHQgZGJUIGJneGRud2sgb3V4IFZ3VGpnbll4bGsgWVZDdWRUQy4gSGJUIHdUdXhudHggQm53IGRiZ3ggdXdUCiAgICAgICAgICAgICAgICAvLyBUZ2RiVHc6CiAgICAgICAgICAgICAgICAvLyB6LiBIYlQgN1l3d1R0ZCBHbm5zIGp1bFlUIGd4IHhZN2IgZGJ1ZCBkYlQgQ243WXNUdGQgQ25UeCB0bmQgdFRUQyBkbiwKICAgICAgICAgICAgICAgIC8vICAgIG53IDd1dHRuZCwgMFQgeDd3bmxsVEMgZG4gQ2d4Vmx1ayBkYlQgQ1R4ZGd0dWRnbnQuCiAgICAgICAgICAgICAgICAvLyBaLiBIYlQgVndUamduWXggQ1R4ZGd0dWRnbnQgZ3ggMHduT1R0LCB1dEMgQ25UeHQnZCB1N2R1bGxrIFZuZ3RkIGRuIHUKICAgICAgICAgICAgICAgIC8vICAgIFZueGdkZ250IG9nZGJndCBkYlQgQ243WXNUdGQuCiAgICAgICAgICAgICAgICAvLyAgICAoSGJneCBneCBUZ2RiVHcgQ1lUIGRuIHUgMHVDIEtTNSBFVHRUd3VkbncsIG53IGRiVCBZeFR3IHN1T2d0RSB1CiAgICAgICAgICAgICAgICAvLyAgICAgc2d4ZHVPVCBvYlR0IFR0ZFR3Z3RFIHUgQ1R4ZGd0dWRnbnQgZ3QgZGJUIGJ1eGIgVnV3dXNUZFR3eC4pCiAgICAgICAgICAgICAgICB3VGRZd3QgdFlsbDsKICAgICAgICAgICAgfQogICAgICAgICAgICBnQiAoKCFkYmd4LjdZd3dUdGQuQ1R4ZCAmJiAhbnRsazNiVDdPS3VFVCkgfHwgMFRCbndUV3RsbnVDKSB7CiAgICAgICAgICAgICAgICBnQiAoZGJneC5Wd1RqZ25ZeEZubk9zdXdPID09PSBkYmd4LjdZd3dUdGRGbm5Pc3V3TykgewogICAgICAgICAgICAgICAgICAgIHdUZFl3dCB0WWxsOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9IFRseFQgZ0IgKGRiZ3guN1l3d1R0ZC5WdUVUIHx8IG50bGszYlQ3T0t1RVQpIHsKICAgICAgICAgICAgICAgIGdCIChkYmd4LlZ3VGpnbll4S3VFVCA9PT0gZGJneC43WXd3VHRkS3VFVCkgewogICAgICAgICAgICAgICAgICAgIHdUZFl3dCB0WWxsOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9IFRseFQgewogICAgICAgICAgICAgICAgd1RkWXd0IHRZbGw7CiAgICAgICAgICAgIH0KICAgICAgICAgICAganV3IFZ1d3VzeCA9IHtidXhiOiBkYmd4LjdZd3dUdGRGbm5Pc3V3TywgVnVFVDogZGJneC43WXd3VHRkS3VFVH07CiAgICAgICAgICAgIGdCIChkYmd4Lmd4TmdUb1R3ZnRLd1R4VHRkdWRnbnRxbkNUKSB7CiAgICAgICAgICAgICAgICBWdXd1c3guYnV4YiA9IHRZbGw7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgd1RkWXd0IFZ1d3VzeDsKICAgICAgICB9LAogICAgICAgIF94ZHVkVDkwMTogQll0N2RnbnQgVkNCMmd4ZG53a194ZHVkVDkwMShWdXd1c3gpIHsKICAgICAgICAgICAgd1RkWXd0IHtCZ3RFVHdWd2d0ZDogZGJneC5CZ3RFVHdWd2d0ZCwgWWdDOiBkYmd4LllnQywgZHV3RVRkOiBWdXd1c3h9OwogICAgICAgIH0sCiAgICAgICAgX1ZZeGJIbjJneGRud2s6IEJZdDdkZ250IFZDQjJneGRud2tfVll4YkhuMmd4ZG53ayhWdXd1c3gsCiAgICAgICAgICAgICAgICB1Q0NLd1RqZ25ZeCwgbmpUd293Z2RUKSB7CiAgICAgICAgICAgIGdCICghZGJneC5ndGdkZ3VsZ0dUQykgewogICAgICAgICAgICAgICAgd1RkWXd0OwogICAgICAgICAgICB9CiAgICAgICAgICAgIGdCICghVnV3dXN4LmJ1eGIgJiYgVnV3dXN4LlZ1RVQpIHsKICAgICAgICAgICAgICAgIFZ1d3VzeC5idXhiID0gKCdWdUVUPScgKyBWdXd1c3guVnVFVCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZ0IgKHVDQ0t3VGpnbll4ICYmICFualR3b3dnZFQpIHsKICAgICAgICAgICAgICAgIGp1dyBWd1RqZ25ZeEt1d3VzeCA9IGRiZ3guX0VUZEt3VGpnbll4S3V3dXN4KCk7CiAgICAgICAgICAgICAgICBnQiAoVndUamduWXhLdXd1c3gpIHsKICAgICAgICAgICAgICAgICAgICBqdXcgd1RWbHU3VEt3VGpnbll4ID0gKCFkYmd4LjdZd3dUdGQuQ1R4ZCAmJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGJneC43WXd3VHRkLmJ1eGIgIT09IGRiZ3guVndUamduWXgydXhiKTsKICAgICAgICAgICAgICAgICAgICBkYmd4Ll9WWXhiSG4yZ3hkbndrKFZ3VGpnbll4S3V3dXN4LCBCdWx4VCwgd1RWbHU3VEt3VGpnbll4KTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBkYmd4Ll9WWXhiOXdlVFZsdTdUUGR1ZFQoZGJneC5feGR1ZFQ5MDEoVnV3dXN4KSwKICAgICAgICAgICAgICAgICAgICAobmpUd293Z2RUIHx8IGRiZ3guWWdDID09PSB2KSk7CiAgICAgICAgICAgIGRiZ3guN1l3d1R0ZFdnQyA9IGRiZ3guWWdDKys7CiAgICAgICAgICAgIGRiZ3guN1l3d1R0ZCA9IFZ1d3VzeDsKICAgICAgICAgICAgZGJneC5ZVkN1ZFRLd1RqZ25ZeEZubk9zdXdPID0gZHdZVDsKICAgICAgICB9LAogICAgICAgIF9FbkhuOiBCWXQ3ZGdudCBWQ0IyZ3hkbndrX0VuSG4oeGR1ZFQpIHsKICAgICAgICAgICAgZ0IgKCEoZGJneC5ndGdkZ3VsZ0dUQyAmJiBkYmd4LmJneGRud2tXdGxuN09UQyAmJgogICAgICAgICAgICAgICAgICAgIGRiZ3guX2d4UGR1ZFQ5MDFUN2RTVEJndFRDKHhkdWRUKSkpIHsKICAgICAgICAgICAgICAgIHdUZFl3dDsKICAgICAgICAgICAgfQogICAgICAgICAgICBnQiAoIWRiZ3gud1RmdGdkZ3VsZ0dUQyAmJiB4ZHVkVC5ZZ0MgPCBkYmd4LjdZd3dUdGRXZ0MpIHsKICAgICAgICAgICAgICAgIGp1dyBWd1RqZ25ZeEt1d3VzeCA9IGRiZ3guX0VUZEt3VGpnbll4S3V3dXN4KGR3WVQpOwogICAgICAgICAgICAgICAgZ0IgKFZ3VGpnbll4S3V3dXN4KSB7CiAgICAgICAgICAgICAgICAgICAgZGJneC5fVll4YkhuMmd4ZG53ayhkYmd4LjdZd3dUdGQsIEJ1bHhUKTsKICAgICAgICAgICAgICAgICAgICBkYmd4Ll9WWXhiSG4yZ3hkbndrKFZ3VGpnbll4S3V3dXN4LCBCdWx4VCk7CiAgICAgICAgICAgICAgICAgICAgZGJneC43WXd3VHRkV2dDID0geGR1ZFQuWWdDOwogICAgICAgICAgICAgICAgICAgIG9ndENuby5iZ3hkbndrLjB1N08oKTsKICAgICAgICAgICAgICAgICAgICB3VGRZd3Q7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZGJneC5iZ3hkbndrV3RsbjdPVEMgPSBCdWx4VDsKCiAgICAgICAgICAgIGdCICh4ZHVkVC5kdXdFVGQuQ1R4ZCkgewogICAgICAgICAgICAgICAgZGJneC5sZ3RPUFR3amc3VC50dWpnRXVkVEhuKHhkdWRULmR1d0VUZC5DVHhkKTsKICAgICAgICAgICAgfSBUbHhUIHsKICAgICAgICAgICAgICAgIGRiZ3gubGd0T1BUd2pnN1QueFRkMnV4Yih4ZHVkVC5kdXdFVGQuYnV4Yik7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZGJneC43WXd3VHRkV2dDID0geGR1ZFQuWWdDOwogICAgICAgICAgICBnQiAoeGR1ZFQuWWdDID4gZGJneC5ZZ0MpIHsKICAgICAgICAgICAgICAgIGRiZ3guWWdDID0geGR1ZFQuWWdDOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGRiZ3guN1l3d1R0ZCA9IHhkdWRULmR1d0VUZDsKICAgICAgICAgICAgZGJneC5ZVkN1ZFRLd1RqZ25ZeEZubk9zdXdPID0gZHdZVDsKCiAgICAgICAgICAgIGp1dyA3WXd3VHRkMnV4YiA9IG9ndENuby5sbjd1ZGdudC5idXhiLnhZMHhkd2d0RSh6KTsKICAgICAgICAgICAgZ0IgKGRiZ3guVndUamduWXgydXhiICE9PSA3WXd3VHRkMnV4YikgewogICAgICAgICAgICAgICAgZGJneC51bGxubzJ1eGIzYnV0RVQgPSBCdWx4VDsKICAgICAgICAgICAgfQogICAgICAgICAgICBkYmd4LlZ3VGpnbll4MnV4YiA9IDdZd3dUdGQydXhiOwoKICAgICAgICAgICAgZGJneC5iZ3hkbndrV3RsbjdPVEMgPSBkd1lUOwogICAgICAgIH0sCiAgICAgICAgMHU3TzogQll0N2RnbnQgVkNCMmd4ZG53a0Z1N08oKSB7CiAgICAgICAgICAgIGRiZ3guRW4oLXopOwogICAgICAgIH0sCiAgICAgICAgQm53b3V3QzogQll0N2RnbnQgVkNCMmd4ZG53azVud291d0MoKSB7CiAgICAgICAgICAgIGRiZ3guRW4oeik7CiAgICAgICAgfSwKICAgICAgICBFbjogQll0N2RnbnQgVkNCMmd4ZG53a3BuKENnd1Q3ZGdudCkgewogICAgICAgICAgICBnQiAoZGJneC5ndGdkZ3VsZ0dUQyAmJiBkYmd4LmJneGRud2tXdGxuN09UQykgewogICAgICAgICAgICAgICAganV3IHhkdWRUID0gb2d0Q25vLmJneGRud2sueGR1ZFQ7CiAgICAgICAgICAgICAgICBnQiAoQ2d3VDdkZ250ID09PSAteiAmJiB4ZHVkVCAmJiB4ZHVkVC5ZZ0MgPiB2KSB7CiAgICAgICAgICAgICAgICAgICAgb2d0Q25vLmJneGRud2suMHU3TygpOwogICAgICAgICAgICAgICAgfSBUbHhUIGdCIChDZ3dUN2RnbnQgPT09IHogJiYgeGR1ZFQgJiYgeGR1ZFQuWWdDIDwgKGRiZ3guWWdDIC0geikpIHsKICAgICAgICAgICAgICAgICAgICBvZ3RDbm8uYmd4ZG53ay5CbndvdXdDKCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9OwoKICAgIHdUZFl3dCBLUzUyZ3hkbndrOwp9KSgpOwoKCmp1dyBQVDdudEN1d2tIbm5sMHV3ID0gewogICAgblZUdFRDOiBCdWx4VCwKICAgIFZ3VGpnbll4M250ZHVndFR3MlRnRWJkOiB0WWxsLAogICAgdFRvM250ZHVndFR3MlRnRWJkOiB0WWxsLAogICAgZ3RnZGd1bGdHVDogQll0N2RnbnQgeFQ3bnRDdXdrSG5ubDB1d2Z0Z2RndWxnR1QoblZkZ250eCkgewogICAgICAgIGRiZ3guZG5ubDB1dyA9IG5WZGdudHguZG5ubDB1dzsKICAgICAgICBkYmd4LjBZZGRudDNudGR1Z3RUdyA9IGRiZ3guZG5ubDB1dy5CZ3d4ZE1sVHNUdGQzYmdsQzsKCiAgICAgICAgLy8gU1RCZ3RUIGRiVCBkbm5sMHV3IDBZZGRudHguCiAgICAgICAgZGJneC5kbkVFbFRGWWRkbnQgPSBuVmRnbnR4LmRuRUVsVEZZZGRudDsKICAgICAgICBkYmd4LlZ3VHhUdGR1ZGdudHFuQ1RGWWRkbnQgPSBuVmRnbnR4LlZ3VHhUdGR1ZGdudHFuQ1RGWWRkbnQ7CiAgICAgICAgZGJneC5uVlR0NWdsVCA9IG5WZGdudHgublZUdDVnbFQ7CiAgICAgICAgZGJneC5Wd2d0ZCA9IG5WZGdudHguVndndGQ7CiAgICAgICAgZGJneC5Dbm90bG51QyA9IG5WZGdudHguQ25vdGxudUM7CiAgICAgICAgZGJneC5qZ1RvRm5uT3N1d08gPSBuVmRnbnR4LmpnVG9Gbm5Pc3V3TzsKICAgICAgICBkYmd4LkJnd3hkS3VFVCA9IG5WZGdudHguQmd3eGRLdUVUOwogICAgICAgIGRiZ3gubHV4ZEt1RVQgPSBuVmRnbnR4Lmx1eGRLdUVUOwogICAgICAgIGRiZ3guVnVFVGVuZHVkVDNvID0gblZkZ250eC5WdUVUZW5kdWRUM287CiAgICAgICAgZGJneC5WdUVUZW5kdWRUMzdvID0gblZkZ250eC5WdUVUZW5kdWRUMzdvOwogICAgICAgIGRiZ3guQ243WXNUdGRLd25WVHdkZ1R4RllkZG50ID0gblZkZ250eC5DbjdZc1R0ZEt3blZUd2RnVHhGWWRkbnQ7CgogICAgICAgIC8vIEFkZHU3YiBkYlQgVGpUdGQgbGd4ZFR0VHd4LgogICAgICAgIGp1dyBUbFRzVHRkeCA9IFsKICAgICAgICAgICAgLy8gRllkZG50IGRuIGRuRUVsVCBkYlQgamd4ZzBnbGdkayBuQiBkYlQgeFQ3bnRDdXdrIGRubmwwdXc6CiAgICAgICAgICAgIHtUbFRzVHRkOiBkYmd4LmRuRUVsVEZZZGRudCwgYnV0Q2xUdzogZGJneC5kbkVFbFR9LAogICAgICAgICAgICAvLyBBbGwgZ2RUc3ggb2dkYmd0IGRiVCB4VDdudEN1d2sgZG5ubDB1dwogICAgICAgICAgICAvLyAoVHI3VFZkIEJudyBkbkVFbFQydXRDSG5ubCwgYnV0Q19kbm5sLjF4IGd4IHdUeFZudHhnMGxUIEJudyBnZCk6CiAgICAgICAgICAgIHtUbFRzVHRkOiBkYmd4LlZ3VHhUdGR1ZGdudHFuQ1RGWWRkbnQsCiAgICAgICAgICAgICAgICBidXRDbFR3OiBkYmd4LlZ3VHhUdGR1ZGdudHFuQ1QzbGc3T30sCiAgICAgICAgICAgIHtUbFRzVHRkOiBkYmd4Lm5WVHQ1Z2xULCBidXRDbFR3OiBkYmd4Lm5WVHQ1Z2xUM2xnN099LAogICAgICAgICAgICB7VGxUc1R0ZDogZGJneC5Wd2d0ZCwgYnV0Q2xUdzogZGJneC5Wd2d0ZDNsZzdPfSwKICAgICAgICAgICAge1RsVHNUdGQ6IGRiZ3guQ25vdGxudUMsIGJ1dENsVHc6IGRiZ3guQ25vdGxudUMzbGc3T30sCiAgICAgICAgICAgIHtUbFRzVHRkOiBkYmd4LmpnVG9Gbm5Pc3V3TywgYnV0Q2xUdzogZGJneC5qZ1RvRm5uT3N1d08zbGc3T30sCiAgICAgICAgICAgIHtUbFRzVHRkOiBkYmd4LkJnd3hkS3VFVCwgYnV0Q2xUdzogZGJneC5CZ3d4ZEt1RVQzbGc3T30sCiAgICAgICAgICAgIHtUbFRzVHRkOiBkYmd4Lmx1eGRLdUVULCBidXRDbFR3OiBkYmd4Lmx1eGRLdUVUM2xnN099LAogICAgICAgICAgICB7VGxUc1R0ZDogZGJneC5WdUVUZW5kdWRUM28sIGJ1dENsVHc6IGRiZ3guVnVFVGVuZHVkVDNvM2xnN099LAogICAgICAgICAgICB7VGxUc1R0ZDogZGJneC5WdUVUZW5kdWRUMzdvLCBidXRDbFR3OiBkYmd4LlZ1RVRlbmR1ZFQzN28zbGc3T30sCiAgICAgICAgICAgIHtUbFRzVHRkOiBkYmd4LkNuN1lzVHRkS3duVlR3ZGdUeEZZZGRudCwKICAgICAgICAgICAgICAgIGJ1dENsVHc6IGRiZ3guQ243WXNUdGRLd25WVHdkZ1R4M2xnN099CiAgICAgICAgXTsKCiAgICAgICAgQm53IChqdXcgZ2RUcyBndCBUbFRzVHRkeCkgewogICAgICAgICAgICBqdXcgVGxUc1R0ZCA9IFRsVHNUdGR4W2dkVHNdLlRsVHNUdGQ7CiAgICAgICAgICAgIGdCIChUbFRzVHRkKSB7CiAgICAgICAgICAgICAgICBUbFRzVHRkLnVDQ01qVHRkSWd4ZFR0VHcoJzdsZzdPJywgVGxUc1R0ZHhbZ2RUc10uYnV0Q2xUdy4wZ3RDKGRiZ3gpKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0sCiAgICAvLyBNalR0ZCBidXRDbGd0RSBCWXQ3ZGdudHguCiAgICBWd1R4VHRkdWRnbnRxbkNUM2xnN086IEJZdDdkZ250IHhUN250Q3V3a0hubmwwdXdLd1R4VHRkdWRnbnRxbkNUM2xnN08oVGpkKSB7CiAgICAgICAgS1M1TmdUb1R3QVZWbGc3dWRnbnQud1RRWVR4ZEt3VHhUdGR1ZGdudHFuQ1QoKTsKICAgICAgICBkYmd4LjdsbnhUKCk7CiAgICB9LAogICAgblZUdDVnbFQzbGc3TzogQll0N2RnbnQgeFQ3bnRDdXdrSG5ubDB1dzlWVHQ1Z2xUM2xnN08oVGpkKSB7CiAgICAgICAgQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ0JnbFRmdFZZZCcpLjdsZzdPKCk7CiAgICAgICAgZGJneC43bG54VCgpOwogICAgfSwKICAgIFZ3Z3RkM2xnN086IEJZdDdkZ250IHhUN250Q3V3a0hubmwwdXdLd2d0ZDNsZzdPKFRqZCkgewogICAgICAgIGp1dyBneDNid25zVCA9ICEhb2d0Q25vLjdid25zVCAmJiAhIW9ndENuby43Ynduc1Qub1QweGRud1Q7CiAgICAgICAgZ0IoZ3gzYnduc1QgPT0gZHdZVCl7CiAgICAgICAgICAgCiAgICAgICAgICAvL29ndENuby5Wd2d0ZCh7RWxuMHVsUGRrbFR4IDogQnVseFR9KTsgICAgICAgICAKICAgICAgICAgIAogICAgICAgICAgICBvZ3RDbm8uVnV3VHRkLjdid25zVF9Wd2d0ZF9DZ3VsbkUoKTsKICAgICAgICB9CiAgICAgICAgVGx4VHsKICAgICAgICAgICAgb2d0Q25vLlZ3Z3RkKHtFbG4wdWxQZGtsVHggOiBCdWx4VH0pOwogICAgICAgIH0KICAgICAKICAgICAgIAogICAgICAgICAgICAgICAgICAgCiAgICAgICAgZGJneC43bG54VCgpOwogICAgfSwKICAgIENub3RsbnVDM2xnN086IEJZdDdkZ250IHhUN250Q3V3a0hubmwwdXdTbm90bG51QzNsZzdPKFRqZCkgewogICAgICAvLyAgS1M1TmdUb1R3QVZWbGc3dWRnbnQuQ25vdGxudUMoKTsKICAgICAgICBkYmd4LjdsbnhUKCk7CiAgICB9LAogICAgamdUb0Zubk9zdXdPM2xnN086IEJZdDdkZ250IHhUN250Q3V3a0hubmwwdXdOZ1RvRm5uT3N1d08zbGc3TyhUamQpIHsKICAgICAgICBkYmd4LjdsbnhUKCk7CiAgICB9LAogICAgQmd3eGRLdUVUM2xnN086IEJZdDdkZ250IHhUN250Q3V3a0hubmwwdXc1Z3d4ZEt1RVQzbGc3TyhUamQpIHsKICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5WdUVUID0gejsKICAgICAgICBkYmd4LjdsbnhUKCk7CiAgICB9LAogICAgbHV4ZEt1RVQzbGc3TzogQll0N2RnbnQgeFQ3bnRDdXdrSG5ubDB1d0l1eGRLdUVUM2xnN08oVGpkKSB7CiAgICAgICAgZ0IgKEtTNU5nVG9Ud0FWVmxnN3VkZ250LlZDQlNuN1lzVHRkKSB7CiAgICAgICAgICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250LlZ1RVQgPSBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5WdUVUeDNuWXRkOwogICAgICAgIH0KICAgICAgICBkYmd4LjdsbnhUKCk7CiAgICB9LAogICAgVnVFVGVuZHVkVDNvM2xnN086IEJZdDdkZ250IHhUN250Q3V3a0hubmwwdXdLdUVUZW5kdWRUM28zbGc3TyhUamQpIHsKICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC53bmR1ZFRLdUVUeChMdik7CiAgICB9LAogICAgVnVFVGVuZHVkVDM3bzNsZzdPOiBCWXQ3ZGdudCB4VDdudEN1d2tIbm5sMHV3S3VFVGVuZHVkVDM3bzNsZzdPKFRqZCkgewogICAgICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250LnduZHVkVEt1RVR4KC1Mdik7CiAgICB9LAogICAgQ243WXNUdGRLd25WVHdkZ1R4M2xnN086IEJZdDdkZ250IHhUN250Q3V3a0hubmwwdXdTbjdZc1R0ZEt3blZ4M2xnN08oVGpkKSB7CiAgICAgICAgS1M1TmdUb1R3QVZWbGc3dWRnbnQuVkNCU243WXNUdGRLd25WVHdkZ1R4Lm5WVHQoKTsKICAgICAgICBkYmd4LjdsbnhUKCk7CiAgICB9LAogICAgLy8gcWd4Ny4gQll0N2RnbnR4IEJudyBndGRUd3U3ZGd0RSBvZ2RiIGRiVCBkbm5sMHV3LgogICAgeFRkcXVyMlRnRWJkOiBCWXQ3ZGdudCB4VDdudEN1d2tIbm5sMHV3UFRkcXVyMlRnRWJkKDdudGR1Z3RUdykgewogICAgICAgIGdCICghN250ZHVndFR3IHx8ICFkYmd4LjBZZGRudDNudGR1Z3RUdykgewogICAgICAgICAgICB3VGRZd3Q7CiAgICAgICAgfQogICAgICAgIGRiZ3gudFRvM250ZHVndFR3MlRnRWJkID0gN250ZHVndFR3LjdsZ1R0ZDJUZ0ViZDsKICAgICAgICBnQiAoZGJneC5Wd1RqZ25ZeDNudGR1Z3RUdzJUZ0ViZCA9PT0gZGJneC50VG8zbnRkdWd0VHcyVGdFYmQpIHsKICAgICAgICAgICAgd1RkWXd0OwogICAgICAgIH0KICAgICAgICBkYmd4LjBZZGRudDNudGR1Z3RUdy54VGRBZGR3ZzBZZFQoJ3hka2xUJywKICAgICAgICAgICAgICAgICdzdXItYlRnRWJkOiAnICsgKGRiZ3gudFRvM250ZHVndFR3MlRnRWJkIC0gUDNlOUlJRkFlX0tBU1NmNnApICsgJ1ZyOycpOwogICAgICAgIGRiZ3guVndUamduWXgzbnRkdWd0VHcyVGdFYmQgPSBkYmd4LnRUbzNudGR1Z3RUdzJUZ0ViZDsKICAgIH0sCiAgICBuVlR0OiBCWXQ3ZGdudCB4VDdudEN1d2tIbm5sMHV3OVZUdCgpIHsKICAgICAgICBnQiAoZGJneC5uVlR0VEMpIHsKICAgICAgICAgICAgd1RkWXd0OwogICAgICAgIH0KICAgICAgICBkYmd4Lm5WVHRUQyA9IGR3WVQ7CiAgICAgICAgZGJneC5kbkVFbFRGWWRkbnQuN2x1eHhJZ3hkLnVDQygnZG5FRWxUQycpOwogICAgICAgIGRiZ3guZG5ubDB1dy43bHV4eElneGQud1RzbmpUKCdiZ0NDVHQnKTsKICAgIH0sCiAgICA3bG54VDogQll0N2RnbnQgeFQ3bnRDdXdrSG5ubDB1dzNsbnhUKGR1d0VUZCkgewogICAgICAgIGdCICghZGJneC5uVlR0VEMpIHsKICAgICAgICAgICAgd1RkWXd0OwogICAgICAgIH0gVGx4VCBnQiAoZHV3RVRkICYmICFkYmd4LmRubmwwdXcuN250ZHVndHgoZHV3RVRkKSkgewogICAgICAgICAgICB3VGRZd3Q7CiAgICAgICAgfQogICAgICAgIGRiZ3gublZUdFRDID0gQnVseFQ7CiAgICAgICAgZGJneC5kbm5sMHV3LjdsdXh4SWd4ZC51Q0MoJ2JnQ0NUdCcpOwogICAgICAgIGRiZ3guZG5FRWxURllkZG50LjdsdXh4SWd4ZC53VHNualQoJ2RuRUVsVEMnKTsKICAgIH0sCiAgICBkbkVFbFQ6IEJZdDdkZ250IHhUN250Q3V3a0hubmwwdXdIbkVFbFQoKSB7CiAgICAgICAgZ0IgKGRiZ3gublZUdFRDKSB7CiAgICAgICAgICAgIGRiZ3guN2xueFQoKTsKICAgICAgICB9IFRseFQgewogICAgICAgICAgICBkYmd4Lm5WVHQoKTsKICAgICAgICB9CiAgICB9Cn07CgoKanV3IFNNSUE0X0ZNNTllTV9lTVBNSEhmNnBfUDhmSDMyX2Y2X0tlOXBlTVBQID0gemN2djsgLy8gZ3Qgc3gKanV3IFNNSUE0X0ZNNTllTV8yZlNmNnBfMzk2SGU5SVAgPSBtdnZ2OyAvLyBndCBzeApqdXcgQTNIZk5NX1BNSU0zSDllID0gJ1ZDQkt3VHhUdGR1ZGdudHFuQ1QnOwpqdXcgMzk2SGU5SVBfUE1JTTNIOWUgPSAnVkNCS3dUeFR0ZHVkZ250cW5DVDNudGR3bmx4JzsKCi8qKgogKiBAZGtWVENUQiB7OTAxVDdkfSBLUzVLd1R4VHRkdWRnbnRxbkNUOVZkZ250eAogKiBAVnduVlR3ZGsgezJIcUlTZ2pNbFRzVHRkfSA3bnRkdWd0VHcgLSBIYlQgN250ZHVndFR3IEJudyBkYlQgamdUb1R3IFRsVHNUdGQuCiAqIEBWd25WVHdkayB7MkhxSVNnak1sVHNUdGR9IGpnVG9UdyAtIChuVmRnbnR1bCkgSGJUIGpnVG9UdyBUbFRzVHRkLgogKiBAVnduVlR3ZGsge0tTNU5nVG9Ud30gVkNCTmdUb1R3IC0gSGJUIENuN1lzVHRkIGpnVG9Udy4KICogQFZ3blZUd2RrIHtLUzVIYllzMHR1Z2xOZ1RvVHd9IFZDQkhiWXMwdHVnbE5nVG9UdyAtIChuVmRnbnR1bCkgSGJUIGRiWXMwdHVnbAogKiAgIGpnVG9Udy4KICogQFZ3blZUd2RrIHtBd3d1a30gN250ZFRyZHFUdFlmZFRzeCAtIChuVmRnbnR1bCkgSGJUIHNUdFlnZFRzeCBkYnVkIHV3VCB1Q0NUQwogKiAgIGRuIGRiVCA3bnRkVHJkIHNUdFkgZ3QgS3dUeFR0ZHVkZ250IHFuQ1QuCiAqLwoKLyoqCiAqIEA3bHV4eAogKi8KanV3IEtTNUt3VHhUdGR1ZGdudHFuQ1QgPSAoQll0N2RnbnQgS1M1S3dUeFR0ZHVkZ250cW5DVDNsbnhZd1QoKSB7CiAgICAvKioKICAgICAqIEA3bnR4ZHdZN2R4IEtTNUt3VHhUdGR1ZGdudHFuQ1QKICAgICAqIEBWdXd1cyB7S1M1S3dUeFR0ZHVkZ250cW5DVDlWZGdudHh9IG5WZGdudHgKICAgICAqLwogICAgQll0N2RnbnQgS1M1S3dUeFR0ZHVkZ250cW5DVChuVmRnbnR4KSB7CiAgICAgICAgZGJneC43bnRkdWd0VHcgPSBuVmRnbnR4LjdudGR1Z3RUdzsKICAgICAgICBkYmd4LmpnVG9UdyA9IG5WZGdudHguamdUb1R3IHx8IG5WZGdudHguN250ZHVndFR3LkJnd3hkTWxUc1R0ZDNiZ2xDOwogICAgICAgIGRiZ3guVkNCTmdUb1R3ID0gblZkZ250eC5WQ0JOZ1RvVHc7CiAgICAgICAgZGJneC5WQ0JIYllzMHR1Z2xOZ1RvVHcgPSBuVmRnbnR4LlZDQkhiWXMwdHVnbE5nVG9UdyB8fCB0WWxsOwogICAgICAgIGp1dyA3bnRkVHJkcVR0WWZkVHN4ID0gblZkZ250eC43bnRkVHJkcVR0WWZkVHN4IHx8IHRZbGw7CgogICAgICAgIGRiZ3gudTdkZ2pUID0gQnVseFQ7CiAgICAgICAgZGJneC51d0V4ID0gdFlsbDsKICAgICAgICBkYmd4LjdudGRUcmRxVHRZOVZUdCA9IEJ1bHhUOwogICAgICAgIGRiZ3guc25ZeFRQN3dubGxIZ3NUUGR1c1YgPSB2OwogICAgICAgIGRiZ3guc25ZeFRQN3dubGxTVGxkdSA9IHY7CgogICAgICAgIGdCICg3bnRkVHJkcVR0WWZkVHN4KSB7CiAgICAgICAgICAgIEJudyAoanV3IGcgPSB2LCBnZyA9IDdudGRUcmRxVHRZZmRUc3gubFR0RWRiOyBnIDwgZ2c7IGcrKykgewogICAgICAgICAgICAgICAganV3IGdkVHMgPSA3bnRkVHJkcVR0WWZkVHN4W2ddOwogICAgICAgICAgICAgICAgZ2RUcy5UbFRzVHRkLnVDQ01qVHRkSWd4ZFR0VHcoJzdsZzdPJywgQll0N2RnbnQgKGJ1dENsVHcpIHsKICAgICAgICAgICAgICAgICAgICBkYmd4LjdudGRUcmRxVHRZOVZUdCA9IEJ1bHhUOwogICAgICAgICAgICAgICAgICAgIGJ1dENsVHcoKTsKICAgICAgICAgICAgICAgIH0uMGd0QyhkYmd4LCBnZFRzLmJ1dENsVHcpKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KCiAgICBLUzVLd1R4VHRkdWRnbnRxbkNULlZ3bmRuZGtWVCA9IHsKICAgICAgICAvKioKICAgICAgICAgKiBlVFFZVHhkIGRiVCAwd25veFR3IGRuIFR0ZFR3IEJZbGx4N3dUVHQgc25DVC4KICAgICAgICAgKiBAd1RkWXd0eCB7MG5ubFR1dH0gZnRDZzd1ZGd0RSBnQiBkYlQgd1RRWVR4ZCBvdXggeFk3N1R4eEJZbC4KICAgICAgICAgKi8KICAgICAgICB3VFFZVHhkOiBCWXQ3ZGdudCBLUzVLd1R4VHRkdWRnbnRxbkNUX3dUUVlUeGQoKSB7CiAgICAgICAgICAgIGdCIChkYmd4LnhvZ2Q3YmZ0S3duRXdUeHggfHwgZGJneC51N2RnalQgfHwKICAgICAgICAgICAgICAgICAgICAhZGJneC5qZ1RvVHcuYnV4M2JnbEM2bkNUeCgpKSB7CiAgICAgICAgICAgICAgICB3VGRZd3QgQnVseFQ7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZGJneC5fdUNDNVlsbHg3d1RUdDNidXRFVElneGRUdFR3eCgpOwogICAgICAgICAgICBkYmd4Ll94VGRQb2dkN2JmdEt3bkV3VHh4KCk7CiAgICAgICAgICAgIGRiZ3guX3RuZGdCa1BkdWRUM2J1dEVUKCk7CgogICAgICAgICAgICBnQiAoZGJneC43bnRkdWd0VHcud1RRWVR4ZDVZbGx4N3dUVHQpIHsKICAgICAgICAgICAgICAgIGRiZ3guN250ZHVndFR3LndUUVlUeGQ1WWxseDd3VFR0KCk7CiAgICAgICAgICAgIH0gVGx4VCBnQiAoZGJneC43bnRkdWd0VHcuc25HZVRRWVR4ZDVZbGxQN3dUVHQpIHsKICAgICAgICAgICAgICAgIGRiZ3guN250ZHVndFR3LnNuR2VUUVlUeGQ1WWxsUDd3VFR0KCk7CiAgICAgICAgICAgIH0gVGx4VCBnQiAoZGJneC43bnRkdWd0VHcub1QwT2dkZVRRWVR4ZDVZbGx4N3dUVHQpIHsKICAgICAgICAgICAgICAgIGRiZ3guN250ZHVndFR3Lm9UME9nZGVUUVlUeGQ1WWxseDd3VFR0KE1sVHNUdGQuQUlJOThfUk00RjlBZVNfZjZLV0gpOwogICAgICAgICAgICB9IFRseFQgZ0IgKGRiZ3guN250ZHVndFR3LnN4ZVRRWVR4ZDVZbGx4N3dUVHQpIHsKICAgICAgICAgICAgICAgIGRiZ3guN250ZHVndFR3LnN4ZVRRWVR4ZDVZbGx4N3dUVHQoKTsKICAgICAgICAgICAgfSBUbHhUIHsKICAgICAgICAgICAgICAgIHdUZFl3dCBCdWx4VDsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgZGJneC51d0V4ID0gewogICAgICAgICAgICAgICAgVnVFVDogZGJneC5WQ0JOZ1RvVHcuN1l3d1R0ZEt1RVQ2WXMwVHcsCiAgICAgICAgICAgICAgICBWd1RqZ25ZeFA3dWxUOiBkYmd4LlZDQk5nVG9Udy43WXd3VHRkUDd1bFROdWxZVCwKICAgICAgICAgICAgfTsKCiAgICAgICAgICAgIHdUZFl3dCBkd1lUOwogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogUG9nZDdiVHggVnVFVCBvYlR0IGRiVCBZeFR3IHg3d25sbHggKFl4Z3RFIHUgeDd3bmxsIG9iVFRsIG53IHUgZG5ZN2JWdUMpCiAgICAgICAgICogb2dkYiBsdXdFVCBUdG5ZRWIgc25kZ250LCBkbiBWd1RqVHRkIHU3N2dDVHRkdWwgVnVFVCB4b2dkN2JUeC4KICAgICAgICAgKiBAVnV3dXMge3RZczBUd30gQ1RsZHUgLSBIYlQgQ1RsZHUganVsWVQgQnducyBkYlQgc25ZeFQgVGpUdGQuCiAgICAgICAgICovCiAgICAgICAgc25ZeFRQN3dubGw6IEJZdDdkZ250IEtTNUt3VHhUdGR1ZGdudHFuQ1Rfc25ZeFRQN3dubGwoQ1RsZHUpIHsKICAgICAgICAgICAgZ0IgKCFkYmd4LnU3ZGdqVCkgewogICAgICAgICAgICAgICAgd1RkWXd0OwogICAgICAgICAgICB9CiAgICAgICAgICAgIGp1dyBxOVdQTV9QM2U5SUlfMzk5SVM5ODZfSGZxTSA9IGN2OwogICAgICAgICAgICBqdXcgS0FwTV9QOGZIMzJfSDJlTVAyOUlTID0gelp2OwogICAgICAgICAgICBqdXcgS3VFVFBvZ2Q3YlNnd1Q3ZGdudCA9IHsKICAgICAgICAgICAgICAgIFdLOiAteiwKICAgICAgICAgICAgICAgIFM5ODY6IHoKICAgICAgICAgICAgfTsKCiAgICAgICAgICAgIGp1dyA3WXd3VHRkSGdzVCA9ICh0VG8gU3VkVCgpKS5FVGRIZ3NUKCk7CiAgICAgICAgICAgIGp1dyB4ZG53VENIZ3NUID0gZGJneC5zbll4VFA3d25sbEhnc1RQZHVzVjsKCiAgICAgICAgICAgIC8vIGZCIG9UJ2pUIHVsd1R1Q2sgeG9nZDdiVEMgVnVFVCwgdWpuZ0MgdTc3Z0NUdGR1bGxrIHhvZ2Q3Ymd0RSB1RXVndC4KICAgICAgICAgICAgZ0IgKDdZd3dUdGRIZ3NUID4geGRud1RDSGdzVCAmJgogICAgICAgICAgICAgICAgICAgIDdZd3dUdGRIZ3NUIC0geGRud1RDSGdzVCA8IHE5V1BNX1AzZTlJSV8zOTlJUzk4Nl9IZnFNKSB7CiAgICAgICAgICAgICAgICB3VGRZd3Q7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLy8gZkIgZGJUIHg3d25sbCBDZ3dUN2RnbnQgN2J1dEVUQywgd1R4VGQgZGJUIHU3N1lzWWx1ZFRDIHg3d25sbCBDVGxkdS4KICAgICAgICAgICAgZ0IgKChkYmd4LnNuWXhUUDd3bmxsU1RsZHUgPiB2ICYmIENUbGR1IDwgdikgfHwKICAgICAgICAgICAgICAgICAgICAoZGJneC5zbll4VFA3d25sbFNUbGR1IDwgdiAmJiBDVGxkdSA+IHYpKSB7CiAgICAgICAgICAgICAgICBkYmd4Ll93VHhUZHFuWXhUUDd3bmxsUGR1ZFQoKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBkYmd4LnNuWXhUUDd3bmxsU1RsZHUgKz0gQ1RsZHU7CgogICAgICAgICAgICBnQiAocXVkYi51MHgoZGJneC5zbll4VFA3d25sbFNUbGR1KSA+PSBLQXBNX1A4ZkgzMl9IMmVNUDI5SVMpIHsKICAgICAgICAgICAgICAgIGp1dyBWdUVUUG9nZDdiU2d3VDdkZ250ID0gKGRiZ3guc25ZeFRQN3dubGxTVGxkdSA+IHYpID8KICAgICAgICAgICAgICAgICAgICAgICAgS3VFVFBvZ2Q3YlNnd1Q3ZGdudC5XSyA6IEt1RVRQb2dkN2JTZ3dUN2RnbnQuUzk4NjsKICAgICAgICAgICAgICAgIGp1dyBWdUVUID0gZGJneC5WQ0JOZ1RvVHcuN1l3d1R0ZEt1RVQ2WXMwVHc7CiAgICAgICAgICAgICAgICBkYmd4Ll93VHhUZHFuWXhUUDd3bmxsUGR1ZFQoKTsKCiAgICAgICAgICAgICAgICAvLyBmQiBvVCd3VCB1ZCBkYlQgQmd3eGQvbHV4ZCBWdUVULCBvVCBDbnQnZCB0VFRDIGRuIENuIHV0a2RiZ3RFLgogICAgICAgICAgICAgICAgZ0IgKChWdUVUID09PSB6ICYmIFZ1RVRQb2dkN2JTZ3dUN2RnbnQgPT09IEt1RVRQb2dkN2JTZ3dUN2RnbnQuV0spIHx8CiAgICAgICAgICAgICAgICAgICAgICAgIChWdUVUID09PSBkYmd4LlZDQk5nVG9Udy5WdUVUeDNuWXRkICYmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVnVFVFBvZ2Q3YlNnd1Q3ZGdudCA9PT0gS3VFVFBvZ2Q3YlNnd1Q3ZGdudC5TOTg2KSkgewogICAgICAgICAgICAgICAgICAgIHdUZFl3dDsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGRiZ3guVkNCTmdUb1R3LjdZd3dUdGRLdUVUNllzMFR3ID0gKFZ1RVQgKyBWdUVUUG9nZDdiU2d3VDdkZ250KTsKICAgICAgICAgICAgICAgIGRiZ3guc25ZeFRQN3dubGxIZ3NUUGR1c1YgPSA3WXd3VHRkSGdzVDsKICAgICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgRVRkIGd4NVlsbHg3d1RUdCgpIHsKICAgICAgICAgICAgd1RkWXd0ICEhKENuN1lzVHRkLkJZbGx4N3dUVHRNbFRzVHRkIHx8CiAgICAgICAgICAgICAgICAgICAgQ243WXNUdGQuc25HNVlsbFA3d1RUdCB8fAogICAgICAgICAgICAgICAgICAgIENuN1lzVHRkLm9UME9nZGZ4NVlsbFA3d1RUdCB8fAogICAgICAgICAgICAgICAgICAgIENuN1lzVHRkLnN4NVlsbHg3d1RUdE1sVHNUdGQpOwogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogQFZ3Z2p1ZFQKICAgICAgICAgKi8KICAgICAgICBfdG5kZ0JrUGR1ZFQzYnV0RVQ6IEJZdDdkZ250IEtTNUt3VHhUdGR1ZGdudHFuQ1RfdG5kZ0JrUGR1ZFQzYnV0RVQoKSB7CiAgICAgICAgICAgIGp1dyBUalR0ZCA9IENuN1lzVHRkLjd3VHVkVE1qVHRkKCczWXhkbnNNalR0ZCcpOwogICAgICAgICAgICBUalR0ZC5ndGdkM1l4ZG5zTWpUdGQoJ1Z3VHhUdGR1ZGdudHNuQ1Q3YnV0RVRDJywgZHdZVCwgZHdZVCwgewogICAgICAgICAgICAgICAgdTdkZ2pUOiBkYmd4LnU3ZGdqVCwKICAgICAgICAgICAgICAgIHhvZ2Q3YmZ0S3duRXdUeHg6ICEhZGJneC54b2dkN2JmdEt3bkV3VHh4CiAgICAgICAgICAgIH0pOwogICAgICAgICAgICBvZ3RDbm8uQ2d4VnVkN2JNalR0ZChUalR0ZCk7CiAgICAgICAgfSwKICAgICAgICAvKioKICAgICAgICAgKiBXeFRDIGRuIGd0Z2RndWxnR1QgdSBkZ3NUbllkIG9iVHQgd1RRWVR4ZGd0RSBLd1R4VHRkdWRnbnQgcW5DVCwKICAgICAgICAgKiBnLlQuIG9iVHQgZGJUIDB3bm94VHcgZ3ggd1RRWVR4ZFRDIGRuIFR0ZFR3IEJZbGx4N3dUVHQgc25DVC4KICAgICAgICAgKiBIYmd4IGRnc1RuWWQgZ3ggWXhUQyBkbiBWd1RqVHRkIGRiVCA3WXd3VHRkIFZ1RVQgQnducyAwVGd0RSB4N3dubGxUQwogICAgICAgICAqIFZ1d2RndWxsaywgbncgN25zVmxUZFRsaywgbllkIG5CIGpnVG8gb2JUdCBUdGRUd2d0RSBLd1R4VHRkdWRnbnQgcW5DVC4KICAgICAgICAgKiA2OUhNOiBIYmd4IGd4eFlUIHhUVHN4IGxnc2dkVEMgZG4gN1R3ZHVndCBHbm5zIGxUalRseCAoVC5FLiBWdUVULW9nQ2RiKS4KICAgICAgICAgKiBAVndnanVkVAogICAgICAgICAqLwogICAgICAgIF94VGRQb2dkN2JmdEt3bkV3VHh4OiBCWXQ3ZGdudCBLUzVLd1R4VHRkdWRnbnRxbkNUX3hUZFBvZ2Q3YmZ0S3duRXdUeHgoKSB7CiAgICAgICAgICAgIGdCIChkYmd4LnhvZ2Q3YmZ0S3duRXdUeHgpIHsKICAgICAgICAgICAgICAgIDdsVHV3SGdzVG5ZZChkYmd4LnhvZ2Q3YmZ0S3duRXdUeHgpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGRiZ3gueG9nZDdiZnRLd25Fd1R4eCA9IHhUZEhnc1RuWWQoQll0N2RnbnQgeG9nZDdiZnRLd25Fd1R4eEhnc1RuWWQoKSB7CiAgICAgICAgICAgICAgICBkYmd4Ll93VHNualQ1WWxseDd3VFR0M2J1dEVUSWd4ZFR0VHd4KCk7CiAgICAgICAgICAgICAgICBDVGxUZFQgZGJneC54b2dkN2JmdEt3bkV3VHh4OwogICAgICAgICAgICAgICAgZGJneC5fdG5kZ0JrUGR1ZFQzYnV0RVQoKTsKICAgICAgICAgICAgfS4wZ3RDKGRiZ3gpLCBTTUlBNF9GTTU5ZU1fZU1QTUhIZjZwX1A4ZkgzMl9mNl9LZTlwZU1QUCk7CiAgICAgICAgfSwKICAgICAgICAvKioKICAgICAgICAgKiBAVndnanVkVAogICAgICAgICAqLwogICAgICAgIF93VHhUZFBvZ2Q3YmZ0S3duRXdUeHg6CiAgICAgICAgICAgICAgICBCWXQ3ZGdudCBLUzVLd1R4VHRkdWRnbnRxbkNUX3dUeFRkUG9nZDdiZnRLd25Fd1R4eCgpIHsKICAgICAgICAgICAgICAgICAgICBnQiAoZGJneC54b2dkN2JmdEt3bkV3VHh4KSB7CiAgICAgICAgICAgICAgICAgICAgICAgIDdsVHV3SGdzVG5ZZChkYmd4LnhvZ2Q3YmZ0S3duRXdUeHgpOwogICAgICAgICAgICAgICAgICAgICAgICBDVGxUZFQgZGJneC54b2dkN2JmdEt3bkV3VHh4OwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogQFZ3Z2p1ZFQKICAgICAgICAgKi8KICAgICAgICBfVHRkVHc6IEJZdDdkZ250IEtTNUt3VHhUdGR1ZGdudHFuQ1RfVHRkVHcoKSB7CiAgICAgICAgICAgIGRiZ3gudTdkZ2pUID0gZHdZVDsKICAgICAgICAgICAgZGJneC5fd1R4VGRQb2dkN2JmdEt3bkV3VHh4KCk7CiAgICAgICAgICAgIGRiZ3guX3RuZGdCa1BkdWRUM2J1dEVUKCk7CiAgICAgICAgICAgIGRiZ3guN250ZHVndFR3LjdsdXh4SWd4ZC51Q0MoQTNIZk5NX1BNSU0zSDllKTsKCiAgICAgICAgICAgIC8vIE10eFl3VCBkYnVkIGRiVCA3bnd3VDdkIFZ1RVQgZ3ggeDd3bmxsVEMgZ3RkbiBqZ1RvIG9iVHQgVHRkVHdndEUKICAgICAgICAgICAgLy8gS3dUeFR0ZHVkZ250IHFuQ1QsIDBrIG91Z2RndEUgWXRkZ2wgQllsbHg3d1RUdCBzbkNUIGd0IFR0dTBsVEMuCiAgICAgICAgICAgIHhUZEhnc1RuWWQoQll0N2RnbnQgVHRkVHdLd1R4VHRkdWRnbnRxbkNUSGdzVG5ZZCgpIHsKICAgICAgICAgICAgICAgIGRiZ3guVkNCTmdUb1R3LjdZd3dUdGRLdUVUNllzMFR3ID0gZGJneC51d0V4LlZ1RVQ7CiAgICAgICAgICAgICAgICBkYmd4LlZDQk5nVG9Udy43WXd3VHRkUDd1bFROdWxZVCA9ICdWdUVULUJnZCc7CiAgICAgICAgICAgIH0uMGd0QyhkYmd4KSwgdik7CgogICAgICAgICAgICBkYmd4Ll91Q0M4Z3RDbm9JZ3hkVHRUd3goKTsKICAgICAgICAgICAgZGJneC5feGJubzNudGR3bmx4KCk7CiAgICAgICAgICAgIGRiZ3guN250ZFRyZHFUdFk5VlR0ID0gQnVseFQ7CiAgICAgICAgICAgIGRiZ3guN250ZHVndFR3LnhUZEFkZHdnMFlkVCgnN250ZFRyZHNUdFknLCAnamdUb1R3M250ZFRyZHFUdFknKTsKCiAgICAgICAgICAgIC8vIEhUcmQgeFRsVDdkZ250IGd4IENneHUwbFRDIGd0IEt3VHhUdGR1ZGdudCBxbkNULCBkYll4IGdkJ3ggdG5kIFZueHhnMGxUCiAgICAgICAgICAgIC8vIEJudyBkYlQgWXhUdyBkbiBDVHhUbFQ3ZCBkVHJkIGRidWQgZ3ggeFRsVDdkVEMgKFQuRS4gb2dkYiAiUFRsVDdkIHVsbCIpCiAgICAgICAgICAgIC8vIG9iVHQgVHRkVHdndEUgS3dUeFR0ZHVkZ250IHFuQ1QsIGJUdDdUIG9UIHdUc25qVCB1dGsgdTdkZ2pUIHhUbFQ3ZGdudC4KICAgICAgICAgICAgb2d0Q25vLkVUZFBUbFQ3ZGdudCgpLndUc25qVEFsbGV1dEVUeCgpOwogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogQFZ3Z2p1ZFQKICAgICAgICAgKi8KICAgICAgICBfVHJnZDogQll0N2RnbnQgS1M1S3dUeFR0ZHVkZ250cW5DVF9UcmdkKCkgewogICAgICAgICAgICBqdXcgVnVFVCA9IGRiZ3guVkNCTmdUb1R3LjdZd3dUdGRLdUVUNllzMFR3OwogICAgICAgICAgICBkYmd4LjdudGR1Z3RUdy43bHV4eElneGQud1RzbmpUKEEzSGZOTV9QTUlNM0g5ZSk7CgogICAgICAgICAgICAvLyBNdHhZd1QgZGJ1ZCBkYlQgN253d1Q3ZCBWdUVUIGd4IHg3d25sbFRDIGd0ZG4gamdUbyBvYlR0IFRyZ2RndEUKICAgICAgICAgICAgLy8gS3dUeFR0ZHVkZ250IHFuQ1QsIDBrIG91Z2RndEUgWXRkZ2wgQllsbHg3d1RUdCBzbkNUIGd4IENneHUwbFRDLgogICAgICAgICAgICB4VGRIZ3NUbllkKEJZdDdkZ250IFRyZ2RLd1R4VHRkdWRnbnRxbkNUSGdzVG5ZZCgpIHsKICAgICAgICAgICAgICAgIGRiZ3gudTdkZ2pUID0gQnVseFQ7CiAgICAgICAgICAgICAgICBkYmd4Ll93VHNualQ1WWxseDd3VFR0M2J1dEVUSWd4ZFR0VHd4KCk7CiAgICAgICAgICAgICAgICBkYmd4Ll90bmRnQmtQZHVkVDNidXRFVCgpOwoKICAgICAgICAgICAgICAgIGRiZ3guVkNCTmdUb1R3LjdZd3dUdGRQN3VsVE51bFlUID0gZGJneC51d0V4LlZ3VGpnbll4UDd1bFQ7CiAgICAgICAgICAgICAgICBkYmd4LlZDQk5nVG9Udy43WXd3VHRkS3VFVDZZczBUdyA9IFZ1RVQ7CiAgICAgICAgICAgICAgICBkYmd4LnV3RXggPSB0WWxsOwogICAgICAgICAgICB9LjBndEMoZGJneCksIHYpOwoKICAgICAgICAgICAgZGJneC5fd1RzbmpUOGd0Q25vSWd4ZFR0VHd4KCk7CiAgICAgICAgICAgIGRiZ3guX2JnQ1QzbnRkd25seCgpOwogICAgICAgICAgICBkYmd4Ll93VHhUZHFuWXhUUDd3bmxsUGR1ZFQoKTsKICAgICAgICAgICAgZGJneC43bnRkdWd0VHcud1RzbmpUQWRkd2cwWWRUKCc3bnRkVHJkc1R0WScpOwogICAgICAgICAgICBkYmd4LjdudGRUcmRxVHRZOVZUdCA9IEJ1bHhUOwoKICAgICAgICAgICAgZ0IgKGRiZ3guVkNCSGJZczB0dWdsTmdUb1R3KSB7CiAgICAgICAgICAgICAgICBkYmd4LlZDQkhiWXMwdHVnbE5nVG9Udy5UdHhZd1RIYllzMHR1Z2xOZ3hnMGxUKFZ1RVQpOwogICAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICAvKioKICAgICAgICAgKiBAVndnanVkVAogICAgICAgICAqLwogICAgICAgIF9zbll4VFNub3Q6IEJZdDdkZ250IEtTNUt3VHhUdGR1ZGdudHFuQ1Rfc25ZeFRTbm90KFRqZCkgewogICAgICAgICAgICBnQiAoZGJneC43bnRkVHJkcVR0WTlWVHQpIHsKICAgICAgICAgICAgICAgIGRiZ3guN250ZFRyZHFUdFk5VlR0ID0gQnVseFQ7CiAgICAgICAgICAgICAgICBUamQuVndUalR0ZFNUQnVZbGQoKTsKICAgICAgICAgICAgICAgIHdUZFl3dDsKICAgICAgICAgICAgfQogICAgICAgICAgICBnQiAoVGpkLjBZZGRudCA9PT0gdikgewogICAgICAgICAgICAgICAgLy8gTXR1MGxUIDdsZzdPZ3RFIG5CIGxndE94IGd0IFZ3VHhUdGR1ZGdudCBzbkNULiBLbFR1eFQgdG5kVDoKICAgICAgICAgICAgICAgIC8vIDl0bGsgbGd0T3ggVm5ndGRndEUgZG4gQ1R4ZGd0dWRnbnR4IGd0IGRiVCA3WXd3VHRkIEtTNSBDbjdZc1R0ZCBvbndPLgogICAgICAgICAgICAgICAganV3IGd4ZnRkVHd0dWxJZ3RPID0gKFRqZC5kdXdFVGQuYndUQiAmJgogICAgICAgICAgICAgICAgICAgICAgICBUamQuZHV3RVRkLjdsdXh4SWd4ZC43bnRkdWd0eCgnZ3RkVHd0dWxJZ3RPJykpOwogICAgICAgICAgICAgICAgZ0IgKCFneGZ0ZFR3dHVsSWd0TykgewogICAgICAgICAgICAgICAgICAgIC8vIFd0bFR4eCB1dCBndGRUd3R1bCBsZ3RPIG91eCA3bGc3T1RDLCB1Q2p1dDdUIG50VCBWdUVULgogICAgICAgICAgICAgICAgICAgIFRqZC5Wd1RqVHRkU1RCdVlsZCgpOwogICAgICAgICAgICAgICAgICAgIGRiZ3guVkNCTmdUb1R3LjdZd3dUdGRLdUVUNllzMFR3ICs9IChUamQueGJnQmRSVGsgPyAteiA6IHopOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICAvKioKICAgICAgICAgKiBAVndnanVkVAogICAgICAgICAqLwogICAgICAgIF83bnRkVHJkcVR0WTogQll0N2RnbnQgS1M1S3dUeFR0ZHVkZ250cW5DVF83bnRkVHJkcVR0WSgpIHsKICAgICAgICAgICAgZGJneC43bnRkVHJkcVR0WTlWVHQgPSBkd1lUOwogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogQFZ3Z2p1ZFQKICAgICAgICAgKi8KICAgICAgICBfeGJubzNudGR3bmx4OiBCWXQ3ZGdudCBLUzVLd1R4VHRkdWRnbnRxbkNUX3hibm8zbnRkd25seCgpIHsKICAgICAgICAgICAgZ0IgKGRiZ3guN250ZHdubHhIZ3NUbllkKSB7CiAgICAgICAgICAgICAgICA3bFR1d0hnc1RuWWQoZGJneC43bnRkd25seEhnc1RuWWQpOwogICAgICAgICAgICB9IFRseFQgewogICAgICAgICAgICAgICAgZGJneC43bnRkdWd0VHcuN2x1eHhJZ3hkLnVDQygzOTZIZTlJUF9QTUlNM0g5ZSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZGJneC43bnRkd25seEhnc1RuWWQgPSB4VGRIZ3NUbllkKEJZdDdkZ250IHhibm8zbnRkd25seEhnc1RuWWQoKSB7CiAgICAgICAgICAgICAgICBkYmd4LjdudGR1Z3RUdy43bHV4eElneGQud1RzbmpUKDM5NkhlOUlQX1BNSU0zSDllKTsKICAgICAgICAgICAgICAgIENUbFRkVCBkYmd4LjdudGR3bmx4SGdzVG5ZZDsKICAgICAgICAgICAgfS4wZ3RDKGRiZ3gpLCBTTUlBNF9GTTU5ZU1fMmZTZjZwXzM5NkhlOUlQKTsKICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIEBWd2dqdWRUCiAgICAgICAgICovCiAgICAgICAgX2JnQ1QzbnRkd25seDogQll0N2RnbnQgS1M1S3dUeFR0ZHVkZ250cW5DVF9iZ0NUM250ZHdubHgoKSB7CiAgICAgICAgICAgIGdCICghZGJneC43bnRkd25seEhnc1RuWWQpIHsKICAgICAgICAgICAgICAgIHdUZFl3dDsKICAgICAgICAgICAgfQogICAgICAgICAgICA3bFR1d0hnc1RuWWQoZGJneC43bnRkd25seEhnc1RuWWQpOwogICAgICAgICAgICBkYmd4LjdudGR1Z3RUdy43bHV4eElneGQud1RzbmpUKDM5NkhlOUlQX1BNSU0zSDllKTsKICAgICAgICAgICAgQ1RsVGRUIGRiZ3guN250ZHdubHhIZ3NUbllkOwogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogZVR4VGR4IGRiVCBWd25WVHdkZ1R4IFl4VEMgQm53IGR3dTdPZ3RFIHNuWXhUIHg3d25sbGd0RSBUalR0ZHguCiAgICAgICAgICogQFZ3Z2p1ZFQKICAgICAgICAgKi8KICAgICAgICBfd1R4VGRxbll4VFA3d25sbFBkdWRUOgogICAgICAgICAgICAgICAgQll0N2RnbnQgS1M1S3dUeFR0ZHVkZ250cW5DVF93VHhUZHFuWXhUUDd3bmxsUGR1ZFQoKSB7CiAgICAgICAgICAgICAgICAgICAgZGJneC5zbll4VFA3d25sbEhnc1RQZHVzViA9IHY7CiAgICAgICAgICAgICAgICAgICAgZGJneC5zbll4VFA3d25sbFNUbGR1ID0gdjsKICAgICAgICAgICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogQFZ3Z2p1ZFQKICAgICAgICAgKi8KICAgICAgICBfdUNDOGd0Q25vSWd4ZFR0VHd4OiBCWXQ3ZGdudCBLUzVLd1R4VHRkdWRnbnRxbkNUX3VDQzhndENub0lneGRUdFR3eCgpIHsKICAgICAgICAgICAgZGJneC54Ym5vM250ZHdubHhGZ3RDID0gZGJneC5feGJubzNudGR3bmx4LjBndEMoZGJneCk7CiAgICAgICAgICAgIGRiZ3guc25ZeFRTbm90Rmd0QyA9IGRiZ3guX3NuWXhUU25vdC4wZ3RDKGRiZ3gpOwogICAgICAgICAgICBkYmd4LndUeFRkcW5ZeFRQN3dubGxQZHVkVEZndEMgPSBkYmd4Ll93VHhUZHFuWXhUUDd3bmxsUGR1ZFQuMGd0QyhkYmd4KTsKICAgICAgICAgICAgZGJneC43bnRkVHJkcVR0WUZndEMgPSBkYmd4Ll83bnRkVHJkcVR0WS4wZ3RDKGRiZ3gpOwoKICAgICAgICAgICAgb2d0Q25vLnVDQ01qVHRkSWd4ZFR0VHcoJ3NuWXhUc25qVCcsIGRiZ3gueGJubzNudGR3bmx4Rmd0Qyk7CiAgICAgICAgICAgIG9ndENuby51Q0NNalR0ZElneGRUdFR3KCdzbll4VENub3QnLCBkYmd4LnNuWXhUU25vdEZndEMpOwogICAgICAgICAgICBvZ3RDbm8udUNDTWpUdGRJZ3hkVHRUdygnT1RrQ25vdCcsIGRiZ3gud1R4VGRxbll4VFA3d25sbFBkdWRURmd0Qyk7CiAgICAgICAgICAgIG9ndENuby51Q0NNalR0ZElneGRUdFR3KCc3bnRkVHJkc1R0WScsIGRiZ3guN250ZFRyZHFUdFlGZ3RDKTsKICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIEBWd2dqdWRUCiAgICAgICAgICovCiAgICAgICAgX3dUc25qVDhndENub0lneGRUdFR3eDoKICAgICAgICAgICAgICAgIEJZdDdkZ250IEtTNUt3VHhUdGR1ZGdudHFuQ1Rfd1RzbmpUOGd0Q25vSWd4ZFR0VHd4KCkgewogICAgICAgICAgICAgICAgICAgIG9ndENuby53VHNualRNalR0ZElneGRUdFR3KCdzbll4VHNualQnLCBkYmd4Lnhibm8zbnRkd25seEZndEMpOwogICAgICAgICAgICAgICAgICAgIG9ndENuby53VHNualRNalR0ZElneGRUdFR3KCdzbll4VENub3QnLCBkYmd4LnNuWXhUU25vdEZndEMpOwogICAgICAgICAgICAgICAgICAgIG9ndENuby53VHNualRNalR0ZElneGRUdFR3KCdPVGtDbm90JywgZGJneC53VHhUZHFuWXhUUDd3bmxsUGR1ZFRGZ3RDKTsKICAgICAgICAgICAgICAgICAgICBvZ3RDbm8ud1RzbmpUTWpUdGRJZ3hkVHRUdygnN250ZFRyZHNUdFknLCBkYmd4LjdudGRUcmRxVHRZRmd0Qyk7CgogICAgICAgICAgICAgICAgICAgIENUbFRkVCBkYmd4Lnhibm8zbnRkd25seEZndEM7CiAgICAgICAgICAgICAgICAgICAgQ1RsVGRUIGRiZ3guc25ZeFRTbm90Rmd0QzsKICAgICAgICAgICAgICAgICAgICBDVGxUZFQgZGJneC53VHhUZHFuWXhUUDd3bmxsUGR1ZFRGZ3RDOwogICAgICAgICAgICAgICAgICAgIENUbFRkVCBkYmd4LjdudGRUcmRxVHRZRmd0QzsKICAgICAgICAgICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogQFZ3Z2p1ZFQKICAgICAgICAgKi8KICAgICAgICBfQllsbHg3d1RUdDNidXRFVDogQll0N2RnbnQgS1M1S3dUeFR0ZHVkZ250cW5DVF9CWWxseDd3VFR0M2J1dEVUKCkgewogICAgICAgICAgICBnQiAoZGJneC5neDVZbGx4N3dUVHQpIHsKICAgICAgICAgICAgICAgIGRiZ3guX1R0ZFR3KCk7CiAgICAgICAgICAgIH0gVGx4VCB7CiAgICAgICAgICAgICAgICBkYmd4Ll9UcmdkKCk7CiAgICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIEBWd2dqdWRUCiAgICAgICAgICovCiAgICAgICAgX3VDQzVZbGx4N3dUVHQzYnV0RVRJZ3hkVHRUd3g6CiAgICAgICAgICAgICAgICBCWXQ3ZGdudCBLUzVLd1R4VHRkdWRnbnRxbkNUX3VDQzVZbGx4N3dUVHQzYnV0RVRJZ3hkVHRUd3goKSB7CiAgICAgICAgICAgICAgICAgICAgZGJneC5CWWxseDd3VFR0M2J1dEVURmd0QyA9IGRiZ3guX0JZbGx4N3dUVHQzYnV0RVQuMGd0QyhkYmd4KTsKCiAgICAgICAgICAgICAgICAgICAgb2d0Q25vLnVDQ01qVHRkSWd4ZFR0VHcoJ0JZbGx4N3dUVHQ3YnV0RVQnLCBkYmd4LkJZbGx4N3dUVHQzYnV0RVRGZ3RDKTsKICAgICAgICAgICAgICAgICAgICBvZ3RDbm8udUNDTWpUdGRJZ3hkVHRUdygnc25HQllsbHg3d1RUdDdidXRFVCcsIGRiZ3guQllsbHg3d1RUdDNidXRFVEZndEMpOwogICAgICAgICAgICAgICAgICAgIG9ndENuby51Q0NNalR0ZElneGRUdFR3KCdvVDBPZ2RCWWxseDd3VFR0N2J1dEVUJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRiZ3guQllsbHg3d1RUdDNidXRFVEZndEMpOwogICAgICAgICAgICAgICAgICAgIG9ndENuby51Q0NNalR0ZElneGRUdFR3KCdxUDVZbGx4N3dUVHQzYnV0RVQnLCBkYmd4LkJZbGx4N3dUVHQzYnV0RVRGZ3RDKTsKICAgICAgICAgICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogQFZ3Z2p1ZFQKICAgICAgICAgKi8KICAgICAgICBfd1RzbmpUNVlsbHg3d1RUdDNidXRFVElneGRUdFR3eDoKICAgICAgICAgICAgICAgIEJZdDdkZ250IEtTNUt3VHhUdGR1ZGdudHFuQ1Rfd1RzbmpUNVlsbHg3d1RUdDNidXRFVElneGRUdFR3eCgpIHsKICAgICAgICAgICAgICAgICAgICBvZ3RDbm8ud1RzbmpUTWpUdGRJZ3hkVHRUdygnQllsbHg3d1RUdDdidXRFVCcsIGRiZ3guQllsbHg3d1RUdDNidXRFVEZndEMpOwogICAgICAgICAgICAgICAgICAgIG9ndENuby53VHNualRNalR0ZElneGRUdFR3KCdzbkdCWWxseDd3VFR0N2J1dEVUJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRiZ3guQllsbHg3d1RUdDNidXRFVEZndEMpOwogICAgICAgICAgICAgICAgICAgIG9ndENuby53VHNualRNalR0ZElneGRUdFR3KCdvVDBPZ2RCWWxseDd3VFR0N2J1dEVUJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRiZ3guQllsbHg3d1RUdDNidXRFVEZndEMpOwogICAgICAgICAgICAgICAgICAgIG9ndENuby53VHNualRNalR0ZElneGRUdFR3KCdxUDVZbGx4N3dUVHQzYnV0RVQnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGJneC5CWWxseDd3VFR0M2J1dEVURmd0Qyk7CgogICAgICAgICAgICAgICAgICAgIENUbFRkVCBkYmd4LkJZbGx4N3dUVHQzYnV0RVRGZ3RDOwogICAgICAgICAgICAgICAgfQogICAgfTsKCiAgICB3VGRZd3QgS1M1S3dUeFR0ZHVkZ250cW5DVDsKfSkoKTsKCgovKiAzblZrd2dFYmQgWnZ6bSBlbjAgOFkgPEVvdGVuMEBFc3VnbC43bnM+CiAqIGJkZFZ4Oi8vRWdkYlkwLjducy9lbjAtLTgvRXd1MC1kbi1WdXQuMXgKICoKICogSWc3VHR4VEMgWXRDVHcgZGJUIEFWdTdiVCBJZzdUdHhULCBOVHd4Z250IFoudiAoZGJUICJJZzdUdHhUIik7CiAqIGtuWSBzdWsgdG5kIFl4VCBkYmd4IEJnbFQgVHI3VFZkIGd0IDduc1ZsZ3V0N1Qgb2dkYiBkYlQgSWc3VHR4VC4KICogNG5ZIHN1ayBuMGR1Z3QgdSA3blZrIG5CIGRiVCBJZzdUdHhUIHVkCiAqCiAqICAgICBiZGRWOi8vb29vLnVWdTdiVC5ud0UvbGc3VHR4VHgvSWYzTTZQTS1aLnYKICoKICogV3RsVHh4IHdUUVlnd1RDIDBrIHVWVmxnN3UwbFQgbHVvIG53IHVFd1RUQyBkbiBndCBvd2dkZ3RFLCB4bkJkb3V3VAogKiBDZ3hkd2cwWWRUQyBZdENUdyBkYlQgSWc3VHR4VCBneCBDZ3hkd2cwWWRUQyBudCB1dCAiQVAgZlAiIEZBUGZQLAogKiA4ZkgyOVdIIDhBZWVBNkhmTVAgOWUgMzk2U2ZIZjk2UCA5NSBBNjQgUmY2UywgVGdkYlR3IFRyVndUeHggbncgZ3NWbGdUQy4KICogUFRUIGRiVCBJZzdUdHhUIEJudyBkYlQgeFZUN2dCZzcgbHV0RVl1RVQgRW5qVHd0Z3RFIFZUd3NneHhnbnR4IHV0QwogKiBsZ3NnZHVkZ250eCBZdENUdyBkYlQgSWc3VHR4VC4KICovCgonWXhUIHhkd2c3ZCc7CgpqdXcgcHd1MEhuS3V0ID0gKEJZdDdkZ250IHB3dTBIbkt1dDNsbnhZd1QoKSB7CiAgICAvKioKICAgICAqIDNudHhkd1k3ZCB1IHB3dTBIbkt1dCBndHhkdXQ3VCBCbncgdSBFZ2pUdCAySHFJIFRsVHNUdGQuCiAgICAgKiBAVnV3dXMgblZkZ250eC5UbFRzVHRkIHtNbFRzVHRkfQogICAgICogQFZ1d3VzIG5WZGdudHguZ0V0bndUSHV3RVRkIHtCWXQ3ZGdudH0gblZkZ250dWwuIFBUVCBgZ0V0bndUSHV3RVRkKHRuQ1QpYAogICAgICogQFZ1d3VzIG5WZGdudHgubnRBN2RnalQzYnV0RVRDIHtCWXQ3ZGdudCgwbm5sVHV0KX0gblZkZ250dWwuIDN1bGxUQwogICAgICogIG9iVHQgRXd1MC1kbi1WdXQgZ3ggKENUKXU3ZGdqdWRUQy4gSGJUIEJnd3hkIHV3RVlzVHRkIGd4IHUgMG5ubFR1dCBkYnVkCiAgICAgKiAgeGJub3ggb2JUZGJUdyBFd3UwLWRuLVZ1dCBneCB1N2RnanVkVEMuCiAgICAgKi8KICAgIEJZdDdkZ250IHB3dTBIbkt1dChuVmRnbnR4KSB7CiAgICAgICAgZGJneC5UbFRzVHRkID0gblZkZ250eC5UbFRzVHRkOwogICAgICAgIGRiZ3guQ243WXNUdGQgPSBuVmRnbnR4LlRsVHNUdGQubm90VHdTbjdZc1R0ZDsKICAgICAgICBnQiAoZGtWVG5CIG5WZGdudHguZ0V0bndUSHV3RVRkID09PSAnQll0N2RnbnQnKSB7CiAgICAgICAgICAgIGRiZ3guZ0V0bndUSHV3RVRkID0gblZkZ250eC5nRXRud1RIdXdFVGQ7CiAgICAgICAgfQogICAgICAgIGRiZ3gubnRBN2RnalQzYnV0RVRDID0gblZkZ250eC5udEE3ZGdqVDNidXRFVEM7CgogICAgICAgIC8vIEZndEMgZGJUIDdudGRUcmR4IGRuIFR0eFl3VCBkYnVkIGBkYmd4YCB1bG91a3ggVm5ndGR4IGRuCiAgICAgICAgLy8gZGJUIHB3dTBIbkt1dCBndHhkdXQ3VC4KICAgICAgICBkYmd4LnU3ZGdqdWRUID0gZGJneC51N2RnanVkVC4wZ3RDKGRiZ3gpOwogICAgICAgIGRiZ3guQ1R1N2RnanVkVCA9IGRiZ3guQ1R1N2RnanVkVC4wZ3RDKGRiZ3gpOwogICAgICAgIGRiZ3guZG5FRWxUID0gZGJneC5kbkVFbFQuMGd0QyhkYmd4KTsKICAgICAgICBkYmd4Ll9udHNuWXhUQ25vdCA9IGRiZ3guX250c25ZeFRDbm90LjBndEMoZGJneCk7CiAgICAgICAgZGJneC5fbnRzbll4VHNualQgPSBkYmd4Ll9udHNuWXhUc25qVC4wZ3RDKGRiZ3gpOwogICAgICAgIGRiZ3guX1R0Q0t1dCA9IGRiZ3guX1R0Q0t1dC4wZ3RDKGRiZ3gpOwoKICAgICAgICAvLyBIYmd4IG5qVHdsdWsgb2dsbCAwVCBndHhUd2RUQyBndCBkYlQgQ243WXNUdGQgb2JUdCBkYlQgc25ZeFQgc25qVHggQ1l3Z3RFCiAgICAgICAgLy8gdSBFd3UwIG5WVHd1ZGdudCwgZG4gVHR4WXdUIGRidWQgZGJUIDdZd3hudyBidXggZGJUIENUeGd3VEMgdVZWVHV3dXQ3VC4KICAgICAgICBqdXcgbmpUd2x1ayA9IGRiZ3gubmpUd2x1ayA9IENuN1lzVHRkLjd3VHVkVE1sVHNUdGQoJ0NnaicpOwogICAgICAgIG5qVHdsdWsuN2x1eHg2dXNUID0gJ0V3dTAtZG4tVnV0LUV3dTAwZ3RFJzsKICAgIH0KICAgIHB3dTBIbkt1dC5Wd25kbmRrVlQgPSB7CiAgICAgICAgLyoqCiAgICAgICAgICogM2x1eHggdHVzVCBuQiBUbFRzVHRkIG9iZzdiIDd1dCAwVCBFd3UwMFRDCiAgICAgICAgICovCiAgICAgICAgM1BQXzNJQVBQX3BlQUY6ICdFd3UwLWRuLVZ1dC1Fd3UwJywKICAgICAgICAvKioKICAgICAgICAgKiBGZ3RDIHUgc25ZeFRDbm90IFRqVHRkIGRuIGRiVCBUbFRzVHRkIGRuIFR0dTBsVCBFd3UwLUNUZFQ3ZGdudC4KICAgICAgICAgKi8KICAgICAgICB1N2RnanVkVDogQll0N2RnbnQgcHd1MEhuS3V0X3U3ZGdqdWRUKCkgewogICAgICAgICAgICBnQiAoIWRiZ3gudTdkZ2pUKSB7CiAgICAgICAgICAgICAgICBkYmd4LnU3ZGdqVCA9IGR3WVQ7CiAgICAgICAgICAgICAgICBkYmd4LlRsVHNUdGQudUNDTWpUdGRJZ3hkVHRUdygnc25ZeFRDbm90JywgZGJneC5fbnRzbll4VENub3QsIGR3WVQpOwogICAgICAgICAgICAgICAgZGJneC5UbFRzVHRkLjdsdXh4SWd4ZC51Q0MoZGJneC4zUFBfM0lBUFBfcGVBRik7CiAgICAgICAgICAgICAgICBnQiAoZGJneC5udEE3ZGdqVDNidXRFVEMpIHsKICAgICAgICAgICAgICAgICAgICBkYmd4Lm50QTdkZ2pUM2J1dEVUQyhkd1lUKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogZVRzbmpUeCB1bGwgVGpUdGR4LiBBdGsgVlR0Q2d0RSBWdXQgeFR4eGdudCBneCBnc3NUQ2d1ZFRsayB4ZG5WVlRDLgogICAgICAgICAqLwogICAgICAgIENUdTdkZ2p1ZFQ6IEJZdDdkZ250IHB3dTBIbkt1dF9DVHU3ZGdqdWRUKCkgewogICAgICAgICAgICBnQiAoZGJneC51N2RnalQpIHsKICAgICAgICAgICAgICAgIGRiZ3gudTdkZ2pUID0gQnVseFQ7CiAgICAgICAgICAgICAgICBkYmd4LlRsVHNUdGQud1RzbmpUTWpUdGRJZ3hkVHRUdygnc25ZeFRDbm90JywgZGJneC5fbnRzbll4VENub3QsIGR3WVQpOwogICAgICAgICAgICAgICAgZGJneC5fVHRDS3V0KCk7CiAgICAgICAgICAgICAgICBkYmd4LlRsVHNUdGQuN2x1eHhJZ3hkLndUc25qVChkYmd4LjNQUF8zSUFQUF9wZUFGKTsKICAgICAgICAgICAgICAgIGdCIChkYmd4Lm50QTdkZ2pUM2J1dEVUQykgewogICAgICAgICAgICAgICAgICAgIGRiZ3gubnRBN2RnalQzYnV0RVRDKEJ1bHhUKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgZG5FRWxUOiBCWXQ3ZGdudCBwd3UwSG5LdXRfZG5FRWxUKCkgewogICAgICAgICAgICBnQiAoZGJneC51N2RnalQpIHsKICAgICAgICAgICAgICAgIGRiZ3guQ1R1N2RnanVkVCgpOwogICAgICAgICAgICB9IFRseFQgewogICAgICAgICAgICAgICAgZGJneC51N2RnanVkVCgpOwogICAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICAvKioKICAgICAgICAgKiA4YlRkYlR3IGRuIHRuZCBWdXQgZ0IgZGJUIGR1d0VUZCBUbFRzVHRkIGd4IDdsZzdPVEMuCiAgICAgICAgICogOWpUd3dnQ1QgZGJneCBzVGRibkMgZG4gN2J1dEVUIGRiVCBDVEJ1WWxkIDBUYnVqZ25Zdy4KICAgICAgICAgKgogICAgICAgICAqIEBWdXd1cyB0bkNUIHtNbFRzVHRkfSBIYlQgZHV3RVRkIG5CIGRiVCBUalR0ZAogICAgICAgICAqIEB3VGRZd3QgezBubmxUdXR9IDhiVGRiVHcgZG4gdG5kIHdUdTdkIGRuIGRiVCA3bGc3TyBUalR0ZC4KICAgICAgICAgKi8KICAgICAgICBnRXRud1RIdXdFVGQ6IEJZdDdkZ250IHB3dTBIbkt1dF9nRXRud1RIdXdFVGQodG5DVCkgewogICAgICAgICAgICAvLyBXeFQgc3VkN2JUeFBUbFQ3ZG53IGRuIDdiVDdPIG9iVGRiVHcgZGJUIDdsZzdPVEMgVGxUc1R0ZAogICAgICAgICAgICAvLyBneCAodSA3YmdsQyBuQikgdXQgZ3RWWWQgVGxUc1R0ZCAvIGxndE8KICAgICAgICAgICAgd1RkWXd0IHRuQ1Rbc3VkN2JUeFBUbFQ3ZG53XSgKICAgICAgICAgICAgICAgICAgICAndVtid1RCXSwgdVtid1RCXSAqLCBndFZZZCwgZFRyZHV3VHUsIDBZZGRudCwgMFlkZG50ICosIHhUbFQ3ZCwgblZkZ250JwogICAgICAgICAgICAgICAgICAgICk7CiAgICAgICAgfSwKICAgICAgICAvKioKICAgICAgICAgKiBAVndnanVkVAogICAgICAgICAqLwogICAgICAgIF9udHNuWXhUQ25vdDogQll0N2RnbnQgcHd1MEhuS3V0X19udHNuWXhUQ25vdChUalR0ZCkgewogICAgICAgICAgICBnQiAoVGpUdGQuMFlkZG50ICE9PSB2IHx8IGRiZ3guZ0V0bndUSHV3RVRkKFRqVHRkLmR1d0VUZCkpIHsKICAgICAgICAgICAgICAgIHdUZFl3dDsKICAgICAgICAgICAgfQogICAgICAgICAgICBnQiAoVGpUdGQubndnRWd0dWxIdXdFVGQpIHsKICAgICAgICAgICAgICAgIGR3ayB7CiAgICAgICAgICAgICAgICAgICAgLyogMXhiZ3RkIFRyVnc6ZHdZVCAqLwogICAgICAgICAgICAgICAgICAgIFRqVHRkLm53Z0VndHVsSHV3RVRkLmR1RTZ1c1Q7CiAgICAgICAgICAgICAgICB9IDd1ZDdiIChUKSB7CiAgICAgICAgICAgICAgICAgICAgLy8gcW5HZ2xsdS14VlQ3Z0JnNzogVGxUc1R0ZCBneCB1IHg3d25sbDB1dyAoSldJIFRsVHNUdGQpCiAgICAgICAgICAgICAgICAgICAgd1RkWXd0OwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CgogICAgICAgICAgICBkYmd4Lng3d25sbElUQmRQZHV3ZCA9IGRiZ3guVGxUc1R0ZC54N3dubGxJVEJkOwogICAgICAgICAgICBkYmd4Lng3d25sbEhuVlBkdXdkID0gZGJneC5UbFRzVHRkLng3d25sbEhuVjsKICAgICAgICAgICAgZGJneC43bGdUdGRKUGR1d2QgPSBUalR0ZC43bGdUdGRKOwogICAgICAgICAgICBkYmd4LjdsZ1R0ZDRQZHV3ZCA9IFRqVHRkLjdsZ1R0ZDQ7CiAgICAgICAgICAgIGRiZ3guQ243WXNUdGQudUNDTWpUdGRJZ3hkVHRUdygnc25ZeFRzbmpUJywgZGJneC5fbnRzbll4VHNualQsIGR3WVQpOwogICAgICAgICAgICBkYmd4LkNuN1lzVHRkLnVDQ01qVHRkSWd4ZFR0VHcoJ3NuWXhUWVYnLCBkYmd4Ll9UdENLdXQsIGR3WVQpOwogICAgICAgICAgICAvLyA4YlR0IHUgeDd3bmxsIFRqVHRkIG43N1l3eCAwVEJud1QgdSBzbll4VHNualQsIHV4eFlzVCBkYnVkIGRiVCBZeFR3CiAgICAgICAgICAgIC8vIEN3dUVFVEMgdSB4N3dubGwwdXcgKHRUN1R4eHV3ayBCbncgOVZUd3UgS3dUeGRuLCBQdUJ1d2cgdXRDIGZNKQogICAgICAgICAgICAvLyAodG5kIHRUVENUQyBCbncgM2J3bnNULzVnd1RCbnIpCiAgICAgICAgICAgIGRiZ3guVGxUc1R0ZC51Q0NNalR0ZElneGRUdFR3KCd4N3dubGwnLCBkYmd4Ll9UdENLdXQsIGR3WVQpOwogICAgICAgICAgICBUalR0ZC5Wd1RqVHRkU1RCdVlsZCgpOwogICAgICAgICAgICBUalR0ZC54ZG5WS3duVnVFdWRnbnQoKTsKICAgICAgICAgICAgZGJneC5DbjdZc1R0ZC5DbjdZc1R0ZE1sVHNUdGQuN2x1eHhJZ3hkLnVDQyhkYmd4LjNQUF8zSUFQUF9wZUFGRmY2cCk7CgogICAgICAgICAgICBqdXcgQm43WXhUQ01sVHNUdGQgPSBDbjdZc1R0ZC51N2RnalRNbFRzVHRkOwogICAgICAgICAgICBnQiAoQm43WXhUQ01sVHNUdGQgJiYgIUJuN1l4VENNbFRzVHRkLjdudGR1Z3R4KFRqVHRkLmR1d0VUZCkpIHsKICAgICAgICAgICAgICAgIEJuN1l4VENNbFRzVHRkLjBsWXcoKTsKICAgICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogQFZ3Z2p1ZFQKICAgICAgICAgKi8KICAgICAgICBfbnRzbll4VHNualQ6IEJZdDdkZ250IHB3dTBIbkt1dF9fbnRzbll4VHNualQoVGpUdGQpIHsKICAgICAgICAgICAgZGJneC5UbFRzVHRkLndUc25qVE1qVHRkSWd4ZFR0VHcoJ3g3d25sbCcsIGRiZ3guX1R0Q0t1dCwgZHdZVCk7CiAgICAgICAgICAgIGdCIChneElUQmRxbll4VGVUbFR1eFRDKFRqVHRkKSkgewogICAgICAgICAgICAgICAgZGJneC5fVHRDS3V0KCk7CiAgICAgICAgICAgICAgICB3VGRZd3Q7CiAgICAgICAgICAgIH0KICAgICAgICAgICAganV3IHJTZ0JCID0gVGpUdGQuN2xnVHRkSiAtIGRiZ3guN2xnVHRkSlBkdXdkOwogICAgICAgICAgICBqdXcga1NnQkIgPSBUalR0ZC43bGdUdGQ0IC0gZGJneC43bGdUdGQ0UGR1d2Q7CiAgICAgICAgICAgIGRiZ3guVGxUc1R0ZC54N3dubGxIblYgPSBkYmd4Lng3d25sbEhuVlBkdXdkIC0ga1NnQkI7CiAgICAgICAgICAgIGRiZ3guVGxUc1R0ZC54N3dubGxJVEJkID0gZGJneC54N3dubGxJVEJkUGR1d2QgLSByU2dCQjsKICAgICAgICAgICAgZ0IgKCFkYmd4Lm5qVHdsdWsuVnV3VHRkNm5DVCkgewogICAgICAgICAgICAgICAgQ243WXNUdGQuMG5Day51VlZUdEMzYmdsQyhkYmd4Lm5qVHdsdWspOwogICAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICAvKioKICAgICAgICAgKiBAVndnanVkVAogICAgICAgICAqLwogICAgICAgIF9UdENLdXQ6IEJZdDdkZ250IHB3dTBIbkt1dF9fVHRDS3V0KCkgewogICAgICAgICAgICBkYmd4LlRsVHNUdGQud1RzbmpUTWpUdGRJZ3hkVHRUdygneDd3bmxsJywgZGJneC5fVHRDS3V0LCBkd1lUKTsKICAgICAgICAgICAgZGJneC5DbjdZc1R0ZC53VHNualRNalR0ZElneGRUdFR3KCdzbll4VHNualQnLCBkYmd4Ll9udHNuWXhUc25qVCwgZHdZVCk7CiAgICAgICAgICAgIGRiZ3guQ243WXNUdGQud1RzbmpUTWpUdGRJZ3hkVHRUdygnc25ZeFRZVicsIGRiZ3guX1R0Q0t1dCwgZHdZVCk7CiAgICAgICAgICAgIGdCIChkYmd4Lm5qVHdsdWsuVnV3VHRkNm5DVCkgewogICAgICAgICAgICAgICAgZGJneC5ualR3bHVrLlZ1d1R0ZDZuQ1Qud1RzbmpUM2JnbEMoZGJneC5ualR3bHVrKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH07CgogICAgLy8gcFRkIGRiVCA3bnd3VDdkIChqVHRDbnctVndUQmdyVEMpIHR1c1QgbkIgZGJUIHN1ZDdiVHggc1RkYm5DLgogICAganV3IHN1ZDdiVHhQVGxUN2RudzsKICAgIFsnb1QwT2dkcScsICdzbkdxJywgJ3N4cScsICducScsICdzJ10ueG5zVChCWXQ3ZGdudCAoVndUQmdyKSB7CiAgICAgICAganV3IHR1c1QgPSBWd1RCZ3IgKyAndWQ3YlR4JzsKICAgICAgICBnQiAodHVzVCBndCBDbjdZc1R0ZC5DbjdZc1R0ZE1sVHNUdGQpIHsKICAgICAgICAgICAgc3VkN2JUeFBUbFQ3ZG53ID0gdHVzVDsKICAgICAgICB9CiAgICAgICAgdHVzVCArPSAnUFRsVDdkbncnOwogICAgICAgIGdCICh0dXNUIGd0IENuN1lzVHRkLkNuN1lzVHRkTWxUc1R0ZCkgewogICAgICAgICAgICBzdWQ3YlR4UFRsVDdkbncgPSB0dXNUOwogICAgICAgIH0KICAgICAgICB3VGRZd3Qgc3VkN2JUeFBUbFQ3ZG53OyAvLyBmQiBCbll0QywgZGJUdCBkd1lkYmssIHV0QyBbXS54bnNUKCkgVHRDeC4KICAgIH0pOwoKICAgIC8vIEZ3bm94VHcgeHRnQkJndEUgMFQ3dVl4VCBnZCd4IGdzVm54eGcwbFQgZG4gQlR1ZFl3VC1DVGRUN2QKICAgIC8vIG9iVGRiVHcgVGpUdGQub2JnN2IgQm53IG50c25ZeFRzbmpUIGd4IHdUbGd1MGxUCiAgICBqdXcgZ3g2bmRmTW53ZnhmTXp2VmxZeCA9ICFDbjdZc1R0ZC5DbjdZc1R0ZHFuQ1QgfHwgQ243WXNUdGQuQ243WXNUdGRxbkNUID4gTDsKICAgIGp1dyA3Ynduc1QgPSBvZ3RDbm8uN2J3bnNUOwogICAganV3IGd4M2J3bnNUemM5dzlWVHd1emNWbFl4ID0gN2J3bnNUICYmICg3Ynduc1Qub1QweGRud1QgfHwgN2J3bnNULnVWVik7CiAgICAvLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIF4gM2J3bnNUIHpjKyAgICAgICBeIDlWVHd1IHpjKwogICAganV3IGd4UHVCdXdnRFZsWXggPSAvQVZWbFQvLmRUeGQodHVqZ0V1ZG53LmpUdENudykgJiYKICAgICAgICAgICAgL05Ud3hnbnRcLyhbRC1MXVxDKnxbei1jXVxDKykvLmRUeGQodHVqZ0V1ZG53Lll4VHdBRVR0ZCk7CgogICAgLyoqCiAgICAgKiA4YlRkYlR3IGRiVCBsVEJkIHNuWXhUIGd4IHRuZCBWd1R4eFRDLgogICAgICogQFZ1d3VzIFRqVHRkIHtxbll4VE1qVHRkfQogICAgICogQHdUZFl3dCB7MG5ubFR1dH0gSHdZVCBnQiBkYlQgbFRCZCBzbll4VCAwWWRkbnQgZ3ggdG5kIFZ3VHh4VEMuCiAgICAgKiAgICAgICAgICAgICAgICAgICA1dWx4VCBnQiBZdHhZd1QgbncgZ0IgZGJUIGxUQmQgc25ZeFQgMFlkZG50IGd4IFZ3VHh4VEMuCiAgICAgKi8KICAgIEJZdDdkZ250IGd4SVRCZHFuWXhUZVRsVHV4VEMoVGpUdGQpIHsKICAgICAgICBnQiAoJzBZZGRudHgnIGd0IFRqVHRkICYmIGd4Nm5kZk1ud2Z4Zk16dlZsWXgpIHsKICAgICAgICAgICAgLy8gYmRkVjovL29vby5vbS5ud0UvSGUvUzlxLUlUalRsLW0tTWpUdGR4LyNUalR0ZHgtcW5ZeFRNalR0ZC0wWWRkbnR4CiAgICAgICAgICAgIC8vIDVnd1RCbnIgemMrCiAgICAgICAgICAgIC8vIGZ0ZFR3dFRkIE1yVmxud1R3IHp2KwogICAgICAgICAgICB3VGRZd3QgIShUalR0ZC4wWWRkbnR4IHwgeik7CiAgICAgICAgfQogICAgICAgIGdCIChneDNid25zVHpjOXc5VlR3dXpjVmxZeCB8fCBneFB1QnV3Z0RWbFl4KSB7CiAgICAgICAgICAgIC8vIDNid25zVCB6aSsKICAgICAgICAgICAgLy8gOVZUd3UgemMrCiAgICAgICAgICAgIC8vIFB1QnV3ZyBELnYrCiAgICAgICAgICAgIHdUZFl3dCBUalR0ZC5vYmc3YiA9PT0gdjsKICAgICAgICB9CiAgICB9CgogICAgd1RkWXd0IHB3dTBIbkt1dDsKfSkoKTsKCmp1dyAydXRDSG5ubCA9IHsKICAgIGd0Z2RndWxnR1Q6IEJZdDdkZ250IGJ1dENIbm5sZnRnZGd1bGdHVChuVmRnbnR4KSB7CiAgICAgICAganV3IGRuRUVsVDJ1dENIbm5sID0gblZkZ250eC5kbkVFbFQydXRDSG5ubDsKICAgICAgICBkYmd4LmJ1dENIbm5sID0gdFRvIHB3dTBIbkt1dCh7CiAgICAgICAgICAgIFRsVHNUdGQ6IG5WZGdudHguN250ZHVndFR3LAogICAgICAgICAgICBudEE3ZGdqVDNidXRFVEM6IEJZdDdkZ250IChneEE3ZGdqVCkgewogICAgICAgICAgICAgICAgZ0IgKCFkbkVFbFQydXRDSG5ubCkgewogICAgICAgICAgICAgICAgICAgIHdUZFl3dDsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGdCIChneEE3ZGdqVCkgewogICAgICAgICAgICAgICAgICAgIGRuRUVsVDJ1dENIbm5sLmRnZGxUID0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNuR0l6dnQuRVRkKCdidXRDX2RubmxfQ2d4dTBsVC5kZ2RsVCcsIHRZbGwsICdTZ3h1MGxUIGJ1dEMgZG5ubCcpOwogICAgICAgICAgICAgICAgICAgIGRuRUVsVDJ1dENIbm5sLkJnd3hkTWxUc1R0ZDNiZ2xDLmRUcmQzbnRkVHRkID0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNuR0l6dnQuRVRkKCdidXRDX2RubmxfQ2d4dTBsVF9sdTBUbCcsIHRZbGwsICdTZ3h1MGxUIGJ1dEMgZG5ubCcpOwogICAgICAgICAgICAgICAgfSBUbHhUIHsKICAgICAgICAgICAgICAgICAgICBkbkVFbFQydXRDSG5ubC5kZ2RsVCA9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzbkdJenZ0LkVUZCgnYnV0Q19kbm5sX1R0dTBsVC5kZ2RsVCcsIHRZbGwsICdNdHUwbFQgYnV0QyBkbm5sJyk7CiAgICAgICAgICAgICAgICAgICAgZG5FRWxUMnV0Q0hubmwuQmd3eGRNbFRzVHRkM2JnbEMuZFRyZDNudGRUdGQgPQogICAgICAgICAgICAgICAgICAgICAgICAgICAgc25HSXp2dC5FVGQoJ2J1dENfZG5ubF9UdHUwbFRfbHUwVGwnLCB0WWxsLCAnTXR1MGxUIGJ1dEMgZG5ubCcpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfSk7CiAgICAgICAgZ0IgKGRuRUVsVDJ1dENIbm5sKSB7CiAgICAgICAgICAgIGRuRUVsVDJ1dENIbm5sLnVDQ01qVHRkSWd4ZFR0VHcoJzdsZzdPJywgZGJneC5kbkVFbFQuMGd0QyhkYmd4KSwgQnVseFQpOwoKICAgICAgICAgICAgb2d0Q25vLnVDQ01qVHRkSWd4ZFR0VHcoJ2xuN3VsZ0dUQycsIEJZdDdkZ250IChUamQpIHsKICAgICAgICAgICAgICAgIEt3VEJUd1R0N1R4LkVUZCgnVHR1MGxUMnV0Q0hubmw5dEludUMnKS5kYlR0KEJZdDdkZ250IHdUeG5salRDKGp1bFlUKSB7CiAgICAgICAgICAgICAgICAgICAgZ0IgKGp1bFlUKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGRiZ3guYnV0Q0hubmwudTdkZ2p1ZFQoKTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9LjBndEMoZGJneCksIEJZdDdkZ250IHdUMVQ3ZFRDKHdUdXhudCkge30pOwogICAgICAgICAgICB9LjBndEMoZGJneCkpOwoKICAgICAgICAgICAgb2d0Q25vLnVDQ01qVHRkSWd4ZFR0VHcoJ1Z3VHhUdGR1ZGdudHNuQ1Q3YnV0RVRDJywgQll0N2RnbnQgKFRqZCkgewogICAgICAgICAgICAgICAgZ0IgKFRqZC5DVGR1Z2wueG9nZDdiZnRLd25Fd1R4eCkgewogICAgICAgICAgICAgICAgICAgIHdUZFl3dDsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGdCIChUamQuQ1RkdWdsLnU3ZGdqVCkgewogICAgICAgICAgICAgICAgICAgIGRiZ3guVHRkVHdLd1R4VHRkdWRnbnRxbkNUKCk7CiAgICAgICAgICAgICAgICB9IFRseFQgewogICAgICAgICAgICAgICAgICAgIGRiZ3guVHJnZEt3VHhUdGR1ZGdudHFuQ1QoKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfS4wZ3RDKGRiZ3gpKTsKICAgICAgICB9CiAgICB9LAogICAgZG5FRWxUOiBCWXQ3ZGdudCBidXRDSG5ubEhuRUVsVCgpIHsKICAgICAgICBkYmd4LmJ1dENIbm5sLmRuRUVsVCgpOwogICAgICAgIFBUN250Q3V3a0hubmwwdXcuN2xueFQoKTsKICAgIH0sCiAgICBUdGRUd0t3VHhUdGR1ZGdudHFuQ1Q6IEJZdDdkZ250IGJ1dENIbm5sTXRkVHdLd1R4VHRkdWRnbnRxbkNUKCkgewogICAgICAgIGdCIChkYmd4LmJ1dENIbm5sLnU3ZGdqVCkgewogICAgICAgICAgICBkYmd4Lm91eEE3ZGdqVCA9IGR3WVQ7CiAgICAgICAgICAgIGRiZ3guYnV0Q0hubmwuQ1R1N2RnanVkVCgpOwogICAgICAgIH0KICAgIH0sCiAgICBUcmdkS3dUeFR0ZHVkZ250cW5DVDogQll0N2RnbnQgYnV0Q0hubmxNcmdkS3dUeFR0ZHVkZ250cW5DVCgpIHsKICAgICAgICBnQiAoZGJneC5vdXhBN2RnalQpIHsKICAgICAgICAgICAgZGJneC5vdXhBN2RnalQgPSB0WWxsOwogICAgICAgICAgICBkYmd4LmJ1dENIbm5sLnU3ZGdqdWRUKCk7CiAgICAgICAgfQogICAgfQp9OwoKanV3IDlqVHdsdWtxdXR1RVR3ID0gewogICAgbmpUd2x1a3g6IHt9LAogICAgdTdkZ2pUOiB0WWxsLAogICAgLyoqCiAgICAgKiBAVnV3dXMge3hkd2d0RX0gdHVzVCBIYlQgdHVzVCBuQiBkYlQgbmpUd2x1ayBkYnVkIGd4IHdURWd4ZFR3VEMuIEhiZ3ggc1l4ZAogICAgICogICAgICAgICAgICAgICAgIDBUIFRRWXVsIGRuIGRiVCBmUyBuQiBkYlQgbmpUd2x1ayd4IFM5cSBUbFRzVHRkLgogICAgICogQFZ1d3VzIHtCWXQ3ZGdudH0gN3VsbFR3M2xueFRxVGRibkMgKG5WZGdudHVsKSBIYlQgc1RkYm5DIGRidWQsIGdCIFZ3VHhUdGQsCiAgICAgKiAgICAgICAgICAgICAgICAgICBvZ2xsIDd1bGwgOWpUd2x1a3F1dHVFVHcuN2xueFQgQnducyBkYlQgOTAxVDdkCiAgICAgKiAgICAgICAgICAgICAgICAgICB3VEVneGRUd2d0RSBkYlQgbmpUd2x1ay4gQTc3VHh4IGRuIGRiZ3ggc1RkYm5DIGd4CiAgICAgKiAgICAgICAgICAgICAgICAgICB0VDdUeHh1d2sgZ3QgbndDVHcgZG4gd1l0IDdsVHV0WVYgN25DVCBvYlR0IFQuRS4KICAgICAqICAgICAgICAgICAgICAgICAgIGRiVCBualR3bHVrIGd4IEJudzdUIDdsbnhUQy4gSGJUIENUQnVZbGQgZ3ggdFlsbC4KICAgICAqIEBWdXd1cyB7MG5ubFR1dH0gN3V0NW53N1QzbG54VCAoblZkZ250dWwpIGZ0Q2c3dWRUeCBnQiBuVlR0Z3RFIGRiVCBualR3bHVrCiAgICAgKiAgICAgICAgICAgICAgICAgIG9nbGwgN2xueFQgdXQgdTdkZ2pUIG5qVHdsdWsuIEhiVCBDVEJ1WWxkIGd4IEJ1bHhULgogICAgICogQHdUZFl3dHgge0t3bnNneFR9IEEgVnduc2d4VCBkYnVkIGd4IHdUeG5salRDIG9iVHQgZGJUIG5qVHdsdWsgYnV4IDBUVHQKICAgICAqICAgICAgICAgICAgICAgICAgICB3VEVneGRUd1RDLgogICAgICovCiAgICB3VEVneGRUdzogQll0N2RnbnQgbmpUd2x1a3F1dHVFVHdlVEVneGRUdyh0dXNULAogICAgICAgICAgICA3dWxsVHczbG54VHFUZGJuQywgN3V0NW53N1QzbG54VCkgewogICAgICAgIHdUZFl3dCB0VG8gS3duc2d4VChCWXQ3ZGdudCAod1R4bmxqVCkgewogICAgICAgICAgICBqdXcgVGxUc1R0ZCwgN250ZHVndFR3OwogICAgICAgICAgICBnQiAoIXR1c1QgfHwgIShUbFRzVHRkID0gQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkModHVzVCkpIHx8CiAgICAgICAgICAgICAgICAgICAgISg3bnRkdWd0VHcgPSBUbFRzVHRkLlZ1d1R0ZDZuQ1QpKSB7CiAgICAgICAgICAgICAgICBkYndubyB0VG8gTXd3bncoJzZuZCBUdG5ZRWIgVnV3dXNUZFR3eC4nKTsKICAgICAgICAgICAgfSBUbHhUIGdCIChkYmd4Lm5qVHdsdWt4W3R1c1RdKSB7CiAgICAgICAgICAgICAgICBkYndubyB0VG8gTXd3bncoJ0hiVCBualR3bHVrIGd4IHVsd1R1Q2sgd1RFZ3hkVHdUQy4nKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBkYmd4Lm5qVHdsdWt4W3R1c1RdID0ge1RsVHNUdGQ6IFRsVHNUdGQsCiAgICAgICAgICAgICAgICA3bnRkdWd0VHc6IDdudGR1Z3RUdywKICAgICAgICAgICAgICAgIDd1bGxUdzNsbnhUcVRkYm5DOiAoN3VsbFR3M2xueFRxVGRibkMgfHwgdFlsbCksCiAgICAgICAgICAgICAgICA3dXQ1bnc3VDNsbnhUOiAoN3V0NW53N1QzbG54VCB8fCBCdWx4VCl9OwogICAgICAgICAgICB3VHhubGpUKCk7CiAgICAgICAgfS4wZ3RDKGRiZ3gpKTsKICAgIH0sCiAgICAvKioKICAgICAqIEBWdXd1cyB7eGR3Z3RFfSB0dXNUIEhiVCB0dXNUIG5CIGRiVCBualR3bHVrIGRidWQgZ3ggWXR3VEVneGRUd1RDLgogICAgICogQHdUZFl3dHgge0t3bnNneFR9IEEgVnduc2d4VCBkYnVkIGd4IHdUeG5salRDIG9iVHQgZGJUIG5qVHdsdWsgYnV4IDBUVHQKICAgICAqICAgICAgICAgICAgICAgICAgICBZdHdURWd4ZFR3VEMuCiAgICAgKi8KICAgIFl0d1RFZ3hkVHc6IEJZdDdkZ250IG5qVHdsdWtxdXR1RVR3V3R3VEVneGRUdyh0dXNUKSB7CiAgICAgICAgd1RkWXd0IHRUbyBLd25zZ3hUKEJZdDdkZ250ICh3VHhubGpUKSB7CiAgICAgICAgICAgIGdCICghZGJneC5ualR3bHVreFt0dXNUXSkgewogICAgICAgICAgICAgICAgZGJ3bm8gdFRvIE13d253KCdIYlQgbmpUd2x1ayBDblR4IHRuZCBUcmd4ZC4nKTsKICAgICAgICAgICAgfSBUbHhUIGdCIChkYmd4LnU3ZGdqVCA9PT0gdHVzVCkgewogICAgICAgICAgICAgICAgZGJ3bm8gdFRvIE13d253KCdIYlQgbmpUd2x1ayA3dXR0bmQgMFQgd1RzbmpUQyBvYmdsVCBnZCBneCB1N2RnalQuJyk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgQ1RsVGRUIGRiZ3gubmpUd2x1a3hbdHVzVF07CgogICAgICAgICAgICB3VHhubGpUKCk7CiAgICAgICAgfS4wZ3RDKGRiZ3gpKTsKICAgIH0sCiAgICAvKioKICAgICAqIEBWdXd1cyB7eGR3Z3RFfSB0dXNUIEhiVCB0dXNUIG5CIGRiVCBualR3bHVrIGRidWQgeGJuWWxDIDBUIG5WVHRUQy4KICAgICAqIEB3VGRZd3R4IHtLd25zZ3hUfSBBIFZ3bnNneFQgZGJ1ZCBneCB3VHhubGpUQyBvYlR0IGRiVCBualR3bHVrIGJ1eCAwVFR0CiAgICAgKiAgICAgICAgICAgICAgICAgICAgblZUdFRDLgogICAgICovCiAgICBuVlR0OiBCWXQ3ZGdudCBualR3bHVrcXV0dUVUdzlWVHQodHVzVCkgewogICAgICAgIHdUZFl3dCB0VG8gS3duc2d4VChCWXQ3ZGdudCAod1R4bmxqVCkgewogICAgICAgICAgICBnQiAoIWRiZ3gubmpUd2x1a3hbdHVzVF0pIHsKICAgICAgICAgICAgICAgIGRid25vIHRUbyBNd3dudygnSGJUIG5qVHdsdWsgQ25UeCB0bmQgVHJneGQuJyk7CiAgICAgICAgICAgIH0gVGx4VCBnQiAoZGJneC51N2RnalQpIHsKICAgICAgICAgICAgICAgIGdCIChkYmd4Lm5qVHdsdWt4W3R1c1RdLjd1dDVudzdUM2xueFQpIHsKICAgICAgICAgICAgICAgICAgICBkYmd4Ll83bG54VEhid25ZRWIzdWxsVHcoKTsKICAgICAgICAgICAgICAgIH0gVGx4VCBnQiAoZGJneC51N2RnalQgPT09IHR1c1QpIHsKICAgICAgICAgICAgICAgICAgICBkYndubyB0VG8gTXd3bncoJ0hiVCBualR3bHVrIGd4IHVsd1R1Q2sgdTdkZ2pULicpOwogICAgICAgICAgICAgICAgfSBUbHhUIHsKICAgICAgICAgICAgICAgICAgICBkYndubyB0VG8gTXd3bncoJ0F0bmRiVHcgbmpUd2x1ayBneCA3WXd3VHRkbGsgdTdkZ2pULicpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIGRiZ3gudTdkZ2pUID0gdHVzVDsKICAgICAgICAgICAgZGJneC5ualR3bHVreFtkYmd4LnU3ZGdqVF0uVGxUc1R0ZC43bHV4eElneGQud1RzbmpUKCdiZ0NDVHQnKTsKICAgICAgICAgICAgZGJneC5ualR3bHVreFtkYmd4LnU3ZGdqVF0uN250ZHVndFR3LjdsdXh4SWd4ZC53VHNualQoJ2JnQ0NUdCcpOwoKICAgICAgICAgICAgb2d0Q25vLnVDQ01qVHRkSWd4ZFR0VHcoJ09Ua0Nub3QnLCBkYmd4Ll9PVGtTbm90KTsKICAgICAgICAgICAgd1R4bmxqVCgpOwogICAgICAgIH0uMGd0QyhkYmd4KSk7CiAgICB9LAogICAgLyoqCiAgICAgKiBAVnV3dXMge3hkd2d0RX0gdHVzVCBIYlQgdHVzVCBuQiBkYlQgbmpUd2x1ayBkYnVkIHhibllsQyAwVCA3bG54VEMuCiAgICAgKiBAd1RkWXd0eCB7S3duc2d4VH0gQSBWd25zZ3hUIGRidWQgZ3ggd1R4bmxqVEMgb2JUdCBkYlQgbmpUd2x1ayBidXggMFRUdAogICAgICogICAgICAgICAgICAgICAgICAgIDdsbnhUQy4KICAgICAqLwogICAgN2xueFQ6IEJZdDdkZ250IG5qVHdsdWtxdXR1RVR3M2xueFQodHVzVCkgewogICAgICAgIHdUZFl3dCB0VG8gS3duc2d4VChCWXQ3ZGdudCAod1R4bmxqVCkgewogICAgICAgICAgICBnQiAoIWRiZ3gubmpUd2x1a3hbdHVzVF0pIHsKICAgICAgICAgICAgICAgIGRid25vIHRUbyBNd3dudygnSGJUIG5qVHdsdWsgQ25UeCB0bmQgVHJneGQuJyk7CiAgICAgICAgICAgIH0gVGx4VCBnQiAoIWRiZ3gudTdkZ2pUKSB7CiAgICAgICAgICAgICAgICBkYndubyB0VG8gTXd3bncoJ0hiVCBualR3bHVrIGd4IDdZd3dUdGRsayB0bmQgdTdkZ2pULicpOwogICAgICAgICAgICB9IFRseFQgZ0IgKGRiZ3gudTdkZ2pUICE9PSB0dXNUKSB7CiAgICAgICAgICAgICAgICBkYndubyB0VG8gTXd3bncoJ0F0bmRiVHcgbmpUd2x1ayBneCA3WXd3VHRkbGsgdTdkZ2pULicpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGRiZ3gubmpUd2x1a3hbZGJneC51N2RnalRdLjdudGR1Z3RUdy43bHV4eElneGQudUNDKCdiZ0NDVHQnKTsKICAgICAgICAgICAgZGJneC5ualR3bHVreFtkYmd4LnU3ZGdqVF0uVGxUc1R0ZC43bHV4eElneGQudUNDKCdiZ0NDVHQnKTsKICAgICAgICAgICAgZGJneC51N2RnalQgPSB0WWxsOwoKICAgICAgICAgICAgb2d0Q25vLndUc25qVE1qVHRkSWd4ZFR0VHcoJ09Ua0Nub3QnLCBkYmd4Ll9PVGtTbm90KTsKICAgICAgICAgICAgd1R4bmxqVCgpOwogICAgICAgIH0uMGd0QyhkYmd4KSk7CiAgICB9LAogICAgLyoqCiAgICAgKiBAVndnanVkVAogICAgICovCiAgICBfT1RrU25vdDogQll0N2RnbnQgbmpUd2x1a3F1dHVFVHdfT1RrU25vdChUamQpIHsKICAgICAgICBqdXcgeFRsQiA9IDlqVHdsdWtxdXR1RVR3OwogICAgICAgIGdCICh4VGxCLnU3ZGdqVCAmJiBUamQuT1RrM25DVCA9PT0gWmEpIHsgLy8gTXg3IE9Uay4KICAgICAgICAgICAgeFRsQi5fN2xueFRIYnduWUViM3VsbFR3KCk7CiAgICAgICAgICAgIFRqZC5Wd1RqVHRkU1RCdVlsZCgpOwogICAgICAgIH0KICAgIH0sCiAgICAvKioKICAgICAqIEBWd2dqdWRUCiAgICAgKi8KICAgIF83bG54VEhid25ZRWIzdWxsVHc6IEJZdDdkZ250IG5qVHdsdWtxdXR1RVR3XzdsbnhUSGJ3bllFYjN1bGxUdygpIHsKICAgICAgICBnQiAoZGJneC5ualR3bHVreFtkYmd4LnU3ZGdqVF0uN3VsbFR3M2xueFRxVGRibkMpIHsKICAgICAgICAgICAgZGJneC5ualR3bHVreFtkYmd4LnU3ZGdqVF0uN3VsbFR3M2xueFRxVGRibkMoKTsKICAgICAgICB9CiAgICAgICAgZ0IgKGRiZ3gudTdkZ2pUKSB7CiAgICAgICAgICAgIGRiZ3guN2xueFQoZGJneC51N2RnalQpOwogICAgICAgIH0KICAgIH0KfTsKCmp1dyBLdXh4b253Q0t3bnNWZCA9IHsKICAgIG5qVHdsdWs2dXNUOiB0WWxsLAogICAgWVZDdWRUS3V4eG9ud0M6IHRZbGwsCiAgICB3VHV4bnQ6IHRZbGwsCiAgICBWdXh4b253QzVnVGxDOiB0WWxsLAogICAgVnV4eG9ud0NIVHJkOiB0WWxsLAogICAgVnV4eG9ud0NQWTBzZ2Q6IHRZbGwsCiAgICBWdXh4b253QzN1dDdUbDogdFlsbCwKICAgIGd0Z2RndWxnR1Q6IEJZdDdkZ250IHhUN250Q3V3a0hubmwwdXdmdGdkZ3VsZ0dUKG5WZGdudHgpIHsKICAgICAgICBkYmd4Lm5qVHdsdWs2dXNUID0gblZkZ250eC5ualR3bHVrNnVzVDsKICAgICAgICBkYmd4LlZ1eHhvbndDNWdUbEMgPSBuVmRnbnR4LlZ1eHhvbndDNWdUbEM7CiAgICAgICAgZGJneC5WdXh4b253Q0hUcmQgPSBuVmRnbnR4LlZ1eHhvbndDSFRyZDsKICAgICAgICBkYmd4LlZ1eHhvbndDUFkwc2dkID0gblZkZ250eC5WdXh4b253Q1BZMHNnZDsKICAgICAgICBkYmd4LlZ1eHhvbndDM3V0N1RsID0gblZkZ250eC5WdXh4b253QzN1dDdUbDsKCiAgICAgICAgLy8gQWRkdTdiIGRiVCBUalR0ZCBsZ3hkVHRUd3guCiAgICAgICAgZGJneC5WdXh4b253Q1BZMHNnZC51Q0NNalR0ZElneGRUdFR3KCc3bGc3TycsCiAgICAgICAgICAgICAgICBkYmd4LmpUd2dCa0t1eHhvbndDLjBndEMoZGJneCkpOwoKICAgICAgICBkYmd4LlZ1eHhvbndDM3V0N1RsLnVDQ01qVHRkSWd4ZFR0VHcoJzdsZzdPJywgZGJneC43bG54VC4wZ3RDKGRiZ3gpKTsKCiAgICAgICAgZGJneC5WdXh4b253QzVnVGxDLnVDQ01qVHRkSWd4ZFR0VHcoJ09Ua0Nub3QnLCBCWXQ3ZGdudCAoVCkgewogICAgICAgICAgICBnQiAoVC5PVGszbkNUID09PSB6bSkgeyAvLyBNdGRUdyBPVGsKICAgICAgICAgICAgICAgIGRiZ3gualR3Z0JrS3V4eG9ud0MoKTsKICAgICAgICAgICAgfQogICAgICAgIH0uMGd0QyhkYmd4KSk7CgogICAgICAgIDlqVHdsdWtxdXR1RVR3LndURWd4ZFR3KGRiZ3gubmpUd2x1azZ1c1QsIGRiZ3guN2xueFQuMGd0QyhkYmd4KSwgZHdZVCk7CiAgICB9LAogICAgblZUdDogQll0N2RnbnQgVnV4eG9ud0NLd25zVmQ5VlR0KCkgewogICAgICAgIDlqVHdsdWtxdXR1RVR3Lm5WVHQoZGJneC5ualR3bHVrNnVzVCkuZGJUdChCWXQ3ZGdudCAoKSB7CiAgICAgICAgICAgIGRiZ3guVnV4eG9ud0M1Z1RsQy5CbjdZeCgpOwoKICAgICAgICAgICAganV3IFZ3bnNWZFBkd2d0RSA9IHNuR0l6dnQuRVRkKCdWdXh4b253Q19sdTBUbCcsIHRZbGwsCiAgICAgICAgICAgICAgICAgICAgJ010ZFR3IGRiVCBWdXh4b253QyBkbiBuVlR0IGRiZ3ggS1M1IEJnbFQuJyk7CgogICAgICAgICAgICBnQiAoZGJneC53VHV4bnQgPT09IEtTNXlQLkt1eHhvbndDZVR4Vm50eFR4LmY2MzllZU0zSF9LQVBQODllUykgewogICAgICAgICAgICAgICAgVnduc1ZkUGR3Z3RFID0gc25HSXp2dC5FVGQoJ1Z1eHhvbndDX2d0anVsZ0MnLCB0WWxsLAogICAgICAgICAgICAgICAgICAgICAgICAnZnRqdWxnQyBWdXh4b253Qy4gS2xUdXhUIGR3ayB1RXVndC4nKTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgZGJneC5WdXh4b253Q0hUcmQuZFRyZDNudGRUdGQgPSBWd25zVmRQZHdndEU7CiAgICAgICAgfS4wZ3RDKGRiZ3gpKTsKICAgIH0sCiAgICA3bG54VDogQll0N2RnbnQgVnV4eG9ud0NLd25zVmQzbG54VCgpIHsKICAgICAgICA5alR3bHVrcXV0dUVUdy43bG54VChkYmd4Lm5qVHdsdWs2dXNUKS5kYlR0KEJZdDdkZ250ICgpIHsKICAgICAgICAgICAgZGJneC5WdXh4b253QzVnVGxDLmp1bFlUID0gJyc7CiAgICAgICAgfS4wZ3RDKGRiZ3gpKTsKICAgIH0sCiAgICBqVHdnQmtLdXh4b253QzogQll0N2RnbnQgVnV4eG9ud0NLd25zVmROVHdnQmtLdXh4b253QygpIHsKICAgICAgICBqdXcgVnV4eG9ud0MgPSBkYmd4LlZ1eHhvbndDNWdUbEMuanVsWVQ7CiAgICAgICAgZ0IgKFZ1eHhvbndDICYmIFZ1eHhvbndDLmxUdEVkYiA+IHYpIHsKICAgICAgICAgICAgZGJneC43bG54VCgpOwogICAgICAgICAgICB3VGRZd3QgZGJneC5ZVkN1ZFRLdXh4b253QyhWdXh4b253Qyk7CiAgICAgICAgfQogICAgfQp9OwoKLyoqCiAqIEBka1ZUQ1RCIHs5MDFUN2R9IEtTNVNuN1lzVHRkS3duVlR3ZGdUeDlWZGdudHgKICogQFZ3blZUd2RrIHt4ZHdndEV9IG5qVHdsdWs2dXNUIC0gNnVzVC9nQ1R0ZGdCZ1R3IEJudyBkYlQgbmpUd2x1ay4KICogQFZ3blZUd2RrIHs5MDFUN2R9IEJnVGxDeCAtIDZ1c1R4IHV0QyBUbFRzVHRkeCBuQiBkYlQgbmpUd2x1ayd4IEJnVGxDeC4KICogQFZ3blZUd2RrIHsySHFJRllkZG50TWxUc1R0ZH0gN2xueFRGWWRkbnQgLSBGWWRkbnQgQm53IDdsbnhndEUgZGJUIG5qVHdsdWsuCiAqLwoKLyoqCiAqIEA3bHV4eAogKi8KanV3IEtTNVNuN1lzVHRkS3duVlR3ZGdUeCA9IChCWXQ3ZGdudCBLUzVTbjdZc1R0ZEt3blZUd2RnVHgzbG54WXdUKCkgewogICAgLyoqCiAgICAgKiBAN250eGR3WTdkeCBLUzVTbjdZc1R0ZEt3blZUd2RnVHgKICAgICAqIEBWdXd1cyB7S1M1U243WXNUdGRLd25WVHdkZ1R4OVZkZ250eH0gblZkZ250eAogICAgICovCiAgICBCWXQ3ZGdudCBLUzVTbjdZc1R0ZEt3blZUd2RnVHgoblZkZ250eCkgewogICAgICAgIGRiZ3guQmdUbEN4ID0gblZkZ250eC5CZ1RsQ3g7CiAgICAgICAgZGJneC5ualR3bHVrNnVzVCA9IG5WZGdudHgubmpUd2x1azZ1c1Q7CgogICAgICAgIGRiZ3gud3VvNWdsVFBnR1QgPSB2OwogICAgICAgIGRiZ3guWXdsID0gdFlsbDsKICAgICAgICBkYmd4LlZDQlNuN1lzVHRkID0gdFlsbDsKCiAgICAgICAgLy8gRmd0QyBkYlQgVGpUdGQgbGd4ZFR0VHcgQm53IGRiVCAzbG54VCAwWWRkbnQuCiAgICAgICAgZ0IgKG5WZGdudHguN2xueFRGWWRkbnQpIHsKICAgICAgICAgICAgblZkZ250eC43bG54VEZZZGRudC51Q0NNalR0ZElneGRUdFR3KCc3bGc3TycsIGRiZ3guN2xueFQuMGd0QyhkYmd4KSk7CiAgICAgICAgfQoKICAgICAgICBkYmd4LkN1ZHVBanVnbHUwbFRLd25zZ3hUID0gdFRvIEt3bnNneFQoQll0N2RnbnQgKHdUeG5salQpIHsKICAgICAgICAgICAgZGJneC53VHhubGpUU3VkdUFqdWdsdTBsVCA9IHdUeG5salQ7CiAgICAgICAgfS4wZ3RDKGRiZ3gpKTsKCiAgICAgICAgOWpUd2x1a3F1dHVFVHcud1RFZ3hkVHcoZGJneC5ualR3bHVrNnVzVCwgZGJneC43bG54VC4wZ3RDKGRiZ3gpKTsKICAgIH0KCiAgICBLUzVTbjdZc1R0ZEt3blZUd2RnVHguVnduZG5ka1ZUID0gewogICAgICAgIC8qKgogICAgICAgICAqIDlWVHQgZGJUIENuN1lzVHRkIFZ3blZUd2RnVHggbmpUd2x1ay4KICAgICAgICAgKi8KICAgICAgICBuVlR0OiBCWXQ3ZGdudCBLUzVTbjdZc1R0ZEt3blZUd2RnVHhfblZUdCgpIHsKICAgICAgICAgICAgS3duc2d4VC51bGwoWzlqVHdsdWtxdXR1RVR3Lm5WVHQoZGJneC5ualR3bHVrNnVzVCksCiAgICAgICAgICAgICAgICBkYmd4LkN1ZHVBanVnbHUwbFRLd25zZ3hUXSkuZGJUdChCWXQ3ZGdudCAoKSB7CiAgICAgICAgICAgICAgICBkYmd4Ll9FVGRLd25WVHdkZ1R4KCk7CiAgICAgICAgICAgIH0uMGd0QyhkYmd4KSk7CiAgICAgICAgfSwKICAgICAgICAvKioKICAgICAgICAgKiAzbG54VCBkYlQgQ243WXNUdGQgVnduVlR3ZGdUeCBualR3bHVrLgogICAgICAgICAqLwogICAgICAgIDdsbnhUOiBCWXQ3ZGdudCBLUzVTbjdZc1R0ZEt3blZUd2RnVHhfN2xueFQoKSB7CiAgICAgICAgICAgIDlqVHdsdWtxdXR1RVR3LjdsbnhUKGRiZ3gubmpUd2x1azZ1c1QpOwogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogUFRkIGRiVCBCZ2xUIHhnR1QgbkIgZGJUIEtTNSBDbjdZc1R0ZC4gSGJneCBzVGRibkMgZ3ggWXhUQyBkbgogICAgICAgICAqIFlWQ3VkVCBkYlQgQmdsVCB4Z0dUIGd0IGRiVCBDbjdZc1R0ZCBWd25WVHdkZ1R4IG5qVHdsdWsgbnQ3VCBnZAogICAgICAgICAqIGd4IE90bm90IHhuIG9UIENuIHRuZCBidWpUIGRuIG91Z2QgWXRkZ2wgZGJUIFR0ZGd3VCBCZ2xUIGd4IGxudUNUQy4KICAgICAgICAgKgogICAgICAgICAqIEBWdXd1cyB7dFlzMFR3fSBCZ2xUUGdHVCAtIEhiVCBCZ2xUIHhnR1QgbkIgZGJUIEtTNSBDbjdZc1R0ZC4KICAgICAgICAgKi8KICAgICAgICB4VGQ1Z2xUUGdHVDogQll0N2RnbnQgS1M1U243WXNUdGRLd25WVHdkZ1R4X3hUZDVnbFRQZ0dUKEJnbFRQZ0dUKSB7CiAgICAgICAgICAgIGdCIChCZ2xUUGdHVCA+IHYpIHsKICAgICAgICAgICAgICAgIGRiZ3gud3VvNWdsVFBnR1QgPSBCZ2xUUGdHVDsKICAgICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogUFRkIHUgd1RCVHdUdDdUIGRuIGRiVCBLUzUgQ243WXNUdGQgdXRDIGRiVCBXZUkgZ3QgbndDVHcKICAgICAgICAgKiBkbiBWblZZbHVkVCBkYlQgbmpUd2x1ayBCZ1RsQ3ggb2dkYiBkYlQgQ243WXNUdGQgVnduVlR3ZGdUeC4KICAgICAgICAgKiA2bmRUIGRidWQgZGJUIG5qVHdsdWsgb2dsbCA3bnRkdWd0IHRuIGd0Qm53c3VkZ250IGdCIGRiZ3ggc1RkYm5DCiAgICAgICAgICogZ3ggdG5kIDd1bGxUQy4KICAgICAgICAgKgogICAgICAgICAqIEBWdXd1cyB7OTAxVDdkfSBWQ0JTbjdZc1R0ZCAtIEEgd1RCVHdUdDdUIGRuIGRiVCBLUzUgQ243WXNUdGQuCiAgICAgICAgICogQFZ1d3VzIHt4ZHdndEV9IFl3bCAtIEhiVCBXZUkgbkIgZGJUIENuN1lzVHRkLgogICAgICAgICAqLwogICAgICAgIHhUZFNuN1lzVHRkQXRDV3dsOgogICAgICAgICAgICAgICAgQll0N2RnbnQgS1M1U243WXNUdGRLd25WVHdkZ1R4X3hUZFNuN1lzVHRkQXRDV3dsKFZDQlNuN1lzVHRkLCBZd2wpIHsKICAgICAgICAgICAgICAgICAgICBkYmd4LlZDQlNuN1lzVHRkID0gVkNCU243WXNUdGQ7CiAgICAgICAgICAgICAgICAgICAgZGJneC5Zd2wgPSBZd2w7CiAgICAgICAgICAgICAgICAgICAgZGJneC53VHhubGpUU3VkdUFqdWdsdTBsVCgpOwogICAgICAgICAgICAgICAgfSwKICAgICAgICAvKioKICAgICAgICAgKiBAVndnanVkVAogICAgICAgICAqLwogICAgICAgIF9FVGRLd25WVHdkZ1R4OiBCWXQ3ZGdudCBLUzVTbjdZc1R0ZEt3blZUd2RnVHhfRVRkS3duVlR3ZGdUeCgpIHsKICAgICAgICAgICAgZ0IgKCE5alR3bHVrcXV0dUVUdy51N2RnalQpIHsKICAgICAgICAgICAgICAgIC8vIGZCIGRiVCBDZ3VsbkUgb3V4IDdsbnhUQyAwVEJud1QgQ3VkdUFqdWdsdTBsVEt3bnNneFQgb3V4IHdUeG5salRDLAogICAgICAgICAgICAgICAgLy8gQ250J2QgMG5kYlR3IFlWQ3VkZ3RFIGRiVCBWd25WVHdkZ1R4LgogICAgICAgICAgICAgICAgd1RkWXd0OwogICAgICAgICAgICB9CiAgICAgICAgICAgIC8vIHBUZCBkYlQgQmdsVCB4Z0dUIChnQiBnZCBidXh0J2QgdWx3VHVDayAwVFR0IHhUZCkuCiAgICAgICAgICAgIGRiZ3guVkNCU243WXNUdGQuRVRkU25vdGxudUNmdEJuKCkuZGJUdChCWXQ3ZGdudCAoQ3VkdSkgewogICAgICAgICAgICAgICAgZ0IgKEN1ZHUubFR0RWRiID09PSBkYmd4Lnd1bzVnbFRQZ0dUKSB7CiAgICAgICAgICAgICAgICAgICAgd1RkWXd0OwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgZGJneC54VGQ1Z2xUUGdHVChDdWR1LmxUdEVkYik7CiAgICAgICAgICAgICAgICBkYmd4Ll9ZVkN1ZFRXZihkYmd4LkJnVGxDeFsnQmdsVFBnR1QnXSwgZGJneC5fVnV3eFQ1Z2xUUGdHVCgpKTsKICAgICAgICAgICAgfS4wZ3RDKGRiZ3gpKTsKCiAgICAgICAgICAgIC8vIHBUZCBkYlQgQ243WXNUdGQgVnduVlR3ZGdUeC4KICAgICAgICAgICAgZGJneC5WQ0JTbjdZc1R0ZC5FVGRxVGR1Q3VkdSgpLmRiVHQoQll0N2RnbnQgKEN1ZHUpIHsKICAgICAgICAgICAgICAgIGp1dyA3bnRkVHRkID0gewogICAgICAgICAgICAgICAgICAgICdCZ2xUNnVzVCc6IEVUZEtTNTVnbFQ2dXNUNXduc1dlSShkYmd4Lll3bCksCiAgICAgICAgICAgICAgICAgICAgJ0JnbFRQZ0dUJzogZGJneC5fVnV3eFQ1Z2xUUGdHVCgpLAogICAgICAgICAgICAgICAgICAgICdkZ2RsVCc6IEN1ZHUuZ3RCbi5IZ2RsVCwKICAgICAgICAgICAgICAgICAgICAndVlkYm53JzogQ3VkdS5ndEJuLkFZZGJudywKICAgICAgICAgICAgICAgICAgICAneFkwMVQ3ZCc6IEN1ZHUuZ3RCbi5QWTAxVDdkLAogICAgICAgICAgICAgICAgICAgICdPVGtvbndDeCc6IEN1ZHUuZ3RCbi5SVGtvbndDeCwKICAgICAgICAgICAgICAgICAgICAnN3dUdWRnbnRTdWRUJzogZGJneC5fVnV3eFRTdWRUKEN1ZHUuZ3RCbi4zd1R1ZGdudFN1ZFQpLAogICAgICAgICAgICAgICAgICAgICdzbkNnQmc3dWRnbnRTdWRUJzogZGJneC5fVnV3eFRTdWRUKEN1ZHUuZ3RCbi5xbkNTdWRUKSwKICAgICAgICAgICAgICAgICAgICAnN3dUdWRudyc6IEN1ZHUuZ3RCbi4zd1R1ZG53LAogICAgICAgICAgICAgICAgICAgICdWd25DWTdUdyc6IEN1ZHUuZ3RCbi5Ld25DWTdUdywKICAgICAgICAgICAgICAgICAgICAnalR3eGdudCc6IEN1ZHUuZ3RCbi5LUzU1bndzdWROVHd4Z250LAogICAgICAgICAgICAgICAgICAgICdWdUVUM25ZdGQnOiBkYmd4LlZDQlNuN1lzVHRkLnRZc0t1RVR4CiAgICAgICAgICAgICAgICB9OwoKICAgICAgICAgICAgICAgIC8vIFBibm8gZGJUIFZ3blZUd2RnVHggZ3QgZGJUIENndWxuRS4KICAgICAgICAgICAgICAgIEJudyAoanV3IGdDVHRkZ0JnVHcgZ3QgN250ZFR0ZCkgewogICAgICAgICAgICAgICAgICAgIGRiZ3guX1lWQ3VkVFdmKGRiZ3guQmdUbEN4W2dDVHRkZ0JnVHddLCA3bnRkVHRkW2dDVHRkZ0JnVHddKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfS4wZ3RDKGRiZ3gpKTsKICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIEBWd2dqdWRUCiAgICAgICAgICovCiAgICAgICAgX1lWQ3VkVFdmOiBCWXQ3ZGdudCBLUzVTbjdZc1R0ZEt3blZUd2RnVHhfWVZDdWRUV2YoQmdUbEMsIDdudGRUdGQpIHsKICAgICAgICAgICAgZ0IgKEJnVGxDICYmIDdudGRUdGQgIT09IFl0Q1RCZ3RUQyAmJiA3bnRkVHRkICE9PSAnJykgewogICAgICAgICAgICAgICAgQmdUbEMuZFRyZDNudGRUdGQgPSA3bnRkVHRkOwogICAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICAvKioKICAgICAgICAgKiBAVndnanVkVAogICAgICAgICAqLwogICAgICAgIF9WdXd4VDVnbFRQZ0dUOiBCWXQ3ZGdudCBLUzVTbjdZc1R0ZEt3blZUd2RnVHhfVnV3eFQ1Z2xUUGdHVCgpIHsKICAgICAgICAgICAganV3IEJnbFRQZ0dUID0gZGJneC53dW81Z2xUUGdHVCwgTzAgPSBCZ2xUUGdHVCAvIHp2Wmk7CiAgICAgICAgICAgIGdCICghTzApIHsKICAgICAgICAgICAgICAgIHdUZFl3dDsKICAgICAgICAgICAgfSBUbHhUIGdCIChPMCA8IHp2WmkpIHsKICAgICAgICAgICAgICAgIHdUZFl3dCBzbkdJenZ0LkVUZCgnQ243WXNUdGRfVnduVlR3ZGdUeF9PMCcsIHsKICAgICAgICAgICAgICAgICAgICB4Z0dUX08wOiAoK08wLmRuS3dUN2d4Z250KG0pKS5kbkluN3VsVFBkd2d0RSgpLAogICAgICAgICAgICAgICAgICAgIHhnR1RfMDogQmdsVFBnR1QuZG5Jbjd1bFRQZHdndEUoKQogICAgICAgICAgICAgICAgfSwgJ3t7eGdHVF9PMH19IFJGICh7e3hnR1RfMH19IDBrZFR4KScpOwogICAgICAgICAgICB9IFRseFQgewogICAgICAgICAgICAgICAgd1RkWXd0IHNuR0l6dnQuRVRkKCdDbjdZc1R0ZF9Wd25WVHdkZ1R4X3MwJywgewogICAgICAgICAgICAgICAgICAgIHhnR1RfczA6ICgrKE8wIC8genZaaSkuZG5Ld1Q3Z3hnbnQobSkpLmRuSW43dWxUUGR3Z3RFKCksCiAgICAgICAgICAgICAgICAgICAgeGdHVF8wOiBCZ2xUUGdHVC5kbkluN3VsVFBkd2d0RSgpCiAgICAgICAgICAgICAgICB9LCAne3t4Z0dUX3MwfX0gcUYgKHt7eGdHVF8wfX0gMGtkVHgpJyk7CiAgICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIEBWd2dqdWRUCiAgICAgICAgICovCiAgICAgICAgX1Z1d3hUU3VkVDogQll0N2RnbnQgS1M1U243WXNUdGRLd25WVHdkZ1R4X1Z1d3hUU3VkVChndFZZZFN1ZFQpIHsKICAgICAgICAgICAgLy8gSGJneCBneCBnc1ZsVHNUdGRUQyB1Nzdud0NndEUgZG4gZGJUIEtTNSB4VlQ3Z0JnN3VkZ250LCAwWWQgdG5kVCBkYnVkCiAgICAgICAgICAgIC8vIEFDbjBUIGVUdUNUdyBDblR4dCdkIGJ1dENsVCA3YnV0RWd0RSBkYlQgQ3VkVCBkbiBZdGdqVHd4dWwgZGdzVAogICAgICAgICAgICAvLyB1dEMgQ25UeHQnZCBZeFQgZGJUIFl4VHcneCBkZ3NUIEdudFQgKGRiVGsnd1QgVEJCVDdkZ2pUbGsgZ0V0bndndEUKICAgICAgICAgICAgLy8gZGJUIDIyJyB1dEMgc3MnIFZ1d2R4IG5CIGRiVCBDdWRUIHhkd2d0RSkuCiAgICAgICAgICAgIGp1dyBDdWRUSG5LdXd4VCA9IGd0VllkU3VkVDsKICAgICAgICAgICAgZ0IgKEN1ZFRIbkt1d3hUID09PSBZdENUQmd0VEMpIHsKICAgICAgICAgICAgICAgIHdUZFl3dCAnJzsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgLy8gZVRzbmpUIGRiVCBTOiBWd1RCZ3IgZ0IgZ2QgZ3ggdWp1Z2x1MGxULgogICAgICAgICAgICBnQiAoQ3VkVEhuS3V3eFQueFkweGR3Z3RFKHYsIFopID09PSAnUzonKSB7CiAgICAgICAgICAgICAgICBDdWRUSG5LdXd4VCA9IEN1ZFRIbkt1d3hULnhZMHhkd2d0RShaKTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgLy8gcFRkIHVsbCBUbFRzVHRkeCBCd25zIGRiVCBLUzUgQ3VkVCB4ZHdndEUuCiAgICAgICAgICAgIC8vIHl1anVQN3dnVmQneCBTdWRUIG4wMVQ3ZCBUclZUN2R4IGRiVCBzbnRkYiBkbiAwVCAwVGRvVFR0CiAgICAgICAgICAgIC8vIHYgdXRDIHp6IGd0eGRUdUMgbkIgeiB1dEMgelosIHhuIG9UJ3dUIDdud3dUN2RndEUgQm53IGRiZ3guCiAgICAgICAgICAgIGp1dyBrVHV3ID0gVnV3eFRmdGQoQ3VkVEhuS3V3eFQueFkweGR3Z3RFKHYsIGkpLCB6dik7CiAgICAgICAgICAgIGp1dyBzbnRkYiA9IFZ1d3hUZnRkKEN1ZFRIbkt1d3hULnhZMHhkd2d0RShpLCBEKSwgenYpIC0gejsKICAgICAgICAgICAganV3IEN1ayA9IFZ1d3hUZnRkKEN1ZFRIbkt1d3hULnhZMHhkd2d0RShELCBVKSwgenYpOwogICAgICAgICAgICBqdXcgYm5Zd3ggPSBWdXd4VGZ0ZChDdWRUSG5LdXd4VC54WTB4ZHdndEUoVSwgenYpLCB6dik7CiAgICAgICAgICAgIGp1dyBzZ3RZZFR4ID0gVnV3eFRmdGQoQ3VkVEhuS3V3eFQueFkweGR3Z3RFKHp2LCB6WiksIHp2KTsKICAgICAgICAgICAganV3IHhUN250Q3ggPSBWdXd4VGZ0ZChDdWRUSG5LdXd4VC54WTB4ZHdndEUoelosIHppKSwgenYpOwogICAgICAgICAgICBqdXcgWWRlVGwgPSBDdWRUSG5LdXd4VC54WTB4ZHdndEUoemksIHpjKTsKICAgICAgICAgICAganV3IG5CQnhUZDJuWXd4ID0gVnV3eFRmdGQoQ3VkVEhuS3V3eFQueFkweGR3Z3RFKHpjLCB6YSksIHp2KTsKICAgICAgICAgICAganV3IG5CQnhUZHFndFlkVHggPSBWdXd4VGZ0ZChDdWRUSG5LdXd4VC54WTB4ZHdndEUoelUsIFp2KSwgenYpOwoKICAgICAgICAgICAgLy8gQXggVlR3IHhWVDcsIFlkZVRsID0gJ1gnIHNUdXR4IFRRWXVsIGRuIFl0Z2pUd3h1bCBkZ3NULgogICAgICAgICAgICAvLyBIYlQgbmRiVHcgN3V4VHggKCctJyB1dEMgJysnKSBidWpUIGRuIDBUIGJ1dENsVEMgYlR3VC4KICAgICAgICAgICAgZ0IgKFlkZVRsID09PSAnLScpIHsKICAgICAgICAgICAgICAgIGJuWXd4ICs9IG5CQnhUZDJuWXd4OwogICAgICAgICAgICAgICAgc2d0WWRUeCArPSBuQkJ4VGRxZ3RZZFR4OwogICAgICAgICAgICB9IFRseFQgZ0IgKFlkZVRsID09PSAnKycpIHsKICAgICAgICAgICAgICAgIGJuWXd4IC09IG5CQnhUZDJuWXd4OwogICAgICAgICAgICAgICAgc2d0WWRUeCAtPSBuQkJ4VGRxZ3RZZFR4OwogICAgICAgICAgICB9CgogICAgICAgICAgICAvLyBlVGRZd3QgZGJUIHRUbyBDdWRUIEJud3N1ZCBCd25zIGRiVCBZeFR3J3ggbG43dWxULgogICAgICAgICAgICBqdXcgQ3VkVCA9IHRUbyBTdWRUKFN1ZFQuV0gzKGtUdXcsIHNudGRiLCBDdWssIGJuWXd4LCBzZ3RZZFR4LCB4VDdudEN4KSk7CiAgICAgICAgICAgIGp1dyBDdWRUUGR3Z3RFID0gQ3VkVC5kbkluN3VsVFN1ZFRQZHdndEUoKTsKICAgICAgICAgICAganV3IGRnc1RQZHdndEUgPSBDdWRULmRuSW43dWxUSGdzVFBkd2d0RSgpOwogICAgICAgICAgICB3VGRZd3Qgc25HSXp2dC5FVGQoJ0NuN1lzVHRkX1Z3blZUd2RnVHhfQ3VkVF94ZHdndEUnLAogICAgICAgICAgICAgICAgICAgIHtDdWRUOiBDdWRUUGR3Z3RFLCBkZ3NUOiBkZ3NUUGR3Z3RFfSwKICAgICAgICAgICAgICAgICAgICAne3tDdWRUfX0sIHt7ZGdzVH19Jyk7CiAgICAgICAgfQogICAgfTsKCiAgICB3VGRZd3QgS1M1U243WXNUdGRLd25WVHdkZ1R4Owp9KSgpOwoKanV3IEt3VHhUdGR1ZGdudHFuQ1RQZHVkVCA9IHsKICAgIFc2UjY5ODY6IHYsCiAgICA2OWVxQUk6IHosCiAgICAzMkE2cGY2cDogWiwKICAgIDVXSUlQM2VNTTY6IG0sCn07CgpqdXcgZnA2OWVNXzNXZWVNNkhfSzlQZkhmOTZfOTZfWDk5cSA9IEJ1bHhUOwpqdXcgU001QVdJSF8zQTMyTV9QZlhNID0genY7CgpqdXcgM0lNQTZXS19IZnFNOVdIID0gbXZ2dnY7CgpqdXcgZVR0Q1R3Z3RFUGR1ZFR4ID0gewogICAgZjZmSGZBSTogdiwKICAgIGVXNjZmNnA6IHosCiAgICBLQVdQTVM6IFosCiAgICA1ZjZmUDJNUzogbQp9OwoKLyoqCiAqIDNudGR3bmx4IHdUdENUd2d0RSBuQiBkYlQgamdUb3ggQm53IFZ1RVR4IHV0QyBkYllzMHR1Z2x4LgogKiBAN2x1eHgKICovCmp1dyBLUzVlVHRDVHdndEVoWVRZVCA9IChCWXQ3ZGdudCBLUzVlVHRDVHdndEVoWVRZVDNsbnhZd1QoKSB7CiAgICAvKioKICAgICAqIEA3bnR4ZHdZN2R4CiAgICAgKi8KICAgIEJZdDdkZ250IEtTNWVUdENUd2d0RWhZVFlUKCkgewogICAgICAgIGRiZ3guVkNCTmdUb1R3ID0gdFlsbDsKICAgICAgICBkYmd4LlZDQkhiWXMwdHVnbE5nVG9UdyA9IHRZbGw7CiAgICAgICAgZGJneC5udGZDbFQgPSB0WWxsOwoKICAgICAgICBkYmd4LmJnRWJUeGRLd2dud2dka0t1RVQgPSB0WWxsOwogICAgICAgIGRiZ3guZ0NsVEhnc1RuWWQgPSB0WWxsOwogICAgICAgIGRiZ3guVndndGRndEUgPSBCdWx4VDsKICAgICAgICBkYmd4Lmd4SGJZczB0dWdsTmdUb010dTBsVEMgPSBCdWx4VDsKICAgIH0KCiAgICBLUzVlVHRDVHdndEVoWVRZVC5Wd25kbmRrVlQgPSAvKiogQGxUdEN4IEtTNWVUdENUd2d0RWhZVFlULlZ3bmRuZGtWVCAqLyB7CiAgICAgICAgLyoqCiAgICAgICAgICogQFZ1d3VzIHtLUzVOZ1RvVHd9IFZDQk5nVG9UdwogICAgICAgICAqLwogICAgICAgIHhUZE5nVG9UdzogQll0N2RnbnQgS1M1ZVR0Q1R3Z3RFaFlUWVRfeFRkTmdUb1R3KFZDQk5nVG9UdykgewogICAgICAgICAgICBkYmd4LlZDQk5nVG9UdyA9IFZDQk5nVG9UdzsKICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIEBWdXd1cyB7S1M1SGJZczB0dWdsTmdUb1R3fSBWQ0JIYllzMHR1Z2xOZ1RvVHcKICAgICAgICAgKi8KICAgICAgICB4VGRIYllzMHR1Z2xOZ1RvVHc6CiAgICAgICAgICAgICAgICBCWXQ3ZGdudCBLUzVlVHRDVHdndEVoWVRZVF94VGRIYllzMHR1Z2xOZ1RvVHcoVkNCSGJZczB0dWdsTmdUb1R3KSB7CiAgICAgICAgICAgICAgICAgICAgZGJneC5WQ0JIYllzMHR1Z2xOZ1RvVHcgPSBWQ0JIYllzMHR1Z2xOZ1RvVHc7CiAgICAgICAgICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIEBWdXd1cyB7ZmVUdENUd3UwbFROZ1RvfSBqZ1RvCiAgICAgICAgICogQHdUZFl3dHggezBubmxUdXR9CiAgICAgICAgICovCiAgICAgICAgZ3gyZ0ViVHhkS3dnbndnZGs6IEJZdDdkZ250IEtTNWVUdENUd2d0RWhZVFlUX2d4MmdFYlR4ZEt3Z253Z2RrKGpnVG8pIHsKICAgICAgICAgICAgd1RkWXd0IGRiZ3guYmdFYlR4ZEt3Z253Z2RrS3VFVCA9PT0gamdUby53VHRDVHdndEVmQzsKICAgICAgICB9LAogICAgICAgIHdUdENUdzJnRWJUeGRLd2dud2dkazogQll0N2RnbnQKICAgICAgICAgICAgICAgIEtTNWVUdENUd2d0RWhZVFlUX3dUdENUdzJnRWJUeGRLd2dud2dkayg3WXd3VHRkbGtOZ3hnMGxUS3VFVHgpIHsKICAgICAgICAgICAgZ0IgKGRiZ3guZ0NsVEhnc1RuWWQpIHsKICAgICAgICAgICAgICAgIDdsVHV3SGdzVG5ZZChkYmd4LmdDbFRIZ3NUbllkKTsKICAgICAgICAgICAgICAgIGRiZ3guZ0NsVEhnc1RuWWQgPSB0WWxsOwogICAgICAgICAgICB9CgogICAgICAgICAgICAvLyBLdUVUeCBidWpUIHUgYmdFYlR3IFZ3Z253Z2RrIGRidXQgZGJZczB0dWdseCwgeG4gN2JUN08gZGJUcyBCZ3d4ZC4KICAgICAgICAgICAgZ0IgKGRiZ3guVkNCTmdUb1R3LkJudzdUZVR0Q1R3Z3RFKDdZd3dUdGRsa05neGcwbFRLdUVUeCkpIHsKICAgICAgICAgICAgICAgIHdUZFl3dDsKICAgICAgICAgICAgfQogICAgICAgICAgICAvLyA2biBWdUVUeCB0VFRDVEMgd1R0Q1R3Z3RFIHhuIDdiVDdPIGRiWXMwdHVnbHguCiAgICAgICAgICAgIGdCIChkYmd4LlZDQkhiWXMwdHVnbE5nVG9UdyAmJiBkYmd4Lmd4SGJZczB0dWdsTmdUb010dTBsVEMpIHsKICAgICAgICAgICAgICAgIGdCIChkYmd4LlZDQkhiWXMwdHVnbE5nVG9Udy5Cbnc3VGVUdENUd2d0RSgpKSB7CiAgICAgICAgICAgICAgICAgICAgd1RkWXd0OwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CgogICAgICAgICAgICBnQiAoZGJneC5Wd2d0ZGd0RSkgewogICAgICAgICAgICAgICAgLy8gZkIgVndndGRndEUgZ3ggN1l3d1R0ZGxrIG50RW5ndEUgQ24gdG5kIHdUeDdiVENZbFQgN2xUdXRZVi4KICAgICAgICAgICAgICAgIHdUZFl3dDsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgZ0IgKGRiZ3gubnRmQ2xUKSB7CiAgICAgICAgICAgICAgICBkYmd4LmdDbFRIZ3NUbllkID0geFRkSGdzVG5ZZChkYmd4Lm50ZkNsVC4wZ3RDKGRiZ3gpLCAzSU1BNldLX0hmcU05V0gpOwogICAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICBFVGQyZ0ViVHhkS3dnbndnZGs6IEJZdDdkZ250CiAgICAgICAgICAgICAgICBLUzVlVHRDVHdndEVoWVRZVF9FVGQyZ0ViVHhkS3dnbndnZGsoamd4ZzBsVCwgamdUb3gsIHg3d25sbFRDU25vdCkgewogICAgICAgICAgICAvLyBIYlQgeGR1ZFQgYnV4IDdidXRFVEMgQmdFWXdUIG5ZZCBvYmc3YiBWdUVUIGJ1eCBkYlQgYmdFYlR4ZCBWd2dud2dkayBkbgogICAgICAgICAgICAvLyB3VHRDVHcgdFRyZCAoZ0IgdXRrKS4KICAgICAgICAgICAgLy8gS3dnbndnZGs6CiAgICAgICAgICAgIC8vIHogamd4ZzBsVCBWdUVUeAogICAgICAgICAgICAvLyBaIGdCIGx1eGQgeDd3bmxsVEMgQ25vdCBWdUVUIHVCZFR3IGRiVCBqZ3hnMGxUIFZ1RVR4CiAgICAgICAgICAgIC8vIFogZ0IgbHV4ZCB4N3dubGxUQyBZViBWdUVUIDBUQm53VCBkYlQgamd4ZzBsVCBWdUVUeAogICAgICAgICAgICBqdXcgamd4ZzBsVE5nVG94ID0gamd4ZzBsVC5qZ1RveDsKCiAgICAgICAgICAgIGp1dyB0WXNOZ3hnMGxUID0gamd4ZzBsVE5nVG94LmxUdEVkYjsKICAgICAgICAgICAgZ0IgKHRZc05neGcwbFQgPT09IHYpIHsKICAgICAgICAgICAgICAgIHdUZFl3dCBCdWx4VDsKICAgICAgICAgICAgfQogICAgICAgICAgICBCbncgKGp1dyBnID0gdjsgZyA8IHRZc05neGcwbFQ7ICsrZykgewogICAgICAgICAgICAgICAganV3IGpnVG8gPSBqZ3hnMGxUTmdUb3hbZ10uamdUbzsKICAgICAgICAgICAgICAgIGdCICghZGJneC5neE5nVG81Z3RneGJUQyhqZ1RvKSkgewogICAgICAgICAgICAgICAgICAgIHdUZFl3dCBqZ1RvOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CgogICAgICAgICAgICAvLyBBbGwgZGJUIGpneGcwbFQgamdUb3ggYnVqVCB3VHRDVHdUQywgZHdrIGRuIHdUdENUdyB0VHJkL1Z3VGpnbll4IFZ1RVR4LgogICAgICAgICAgICBnQiAoeDd3bmxsVENTbm90KSB7CiAgICAgICAgICAgICAgICBqdXcgdFRyZEt1RVRmdENUciA9IGpneGcwbFQubHV4ZC5nQzsKICAgICAgICAgICAgICAgIC8vIGZTJ3ggeGR1d2QgdWQgeiB4biB0biB0VFRDIGRuIHVDQyB6LgogICAgICAgICAgICAgICAgZ0IgKGpnVG94W3RUcmRLdUVUZnRDVHJdICYmCiAgICAgICAgICAgICAgICAgICAgICAgICFkYmd4Lmd4TmdUbzVndGd4YlRDKGpnVG94W3RUcmRLdUVUZnRDVHJdKSkgewogICAgICAgICAgICAgICAgICAgIHdUZFl3dCBqZ1RveFt0VHJkS3VFVGZ0Q1RyXTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSBUbHhUIHsKICAgICAgICAgICAgICAgIGp1dyBWd1RqZ25ZeEt1RVRmdENUciA9IGpneGcwbFQuQmd3eGQuZ0MgLSBaOwogICAgICAgICAgICAgICAgZ0IgKGpnVG94W1Z3VGpnbll4S3VFVGZ0Q1RyXSAmJgogICAgICAgICAgICAgICAgICAgICAgICAhZGJneC5neE5nVG81Z3RneGJUQyhqZ1RveFtWd1RqZ25ZeEt1RVRmdENUcl0pKSB7CiAgICAgICAgICAgICAgICAgICAgd1RkWXd0IGpnVG94W1Z3VGpnbll4S3VFVGZ0Q1RyXTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICAvLyBNalR3a2RiZ3RFIGRidWQgdFRUQ3ggZG4gMFQgd1R0Q1R3VEMgYnV4IDBUVHQuCiAgICAgICAgICAgIHdUZFl3dCB0WWxsOwogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogQFZ1d3VzIHtmZVR0Q1R3dTBsVE5nVG99IGpnVG8KICAgICAgICAgKiBAd1RkWXd0eCB7MG5ubFR1dH0KICAgICAgICAgKi8KICAgICAgICBneE5nVG81Z3RneGJUQzogQll0N2RnbnQgS1M1ZVR0Q1R3Z3RFaFlUWVRfZ3hOZ1RvNWd0Z3hiVEMoamdUbykgewogICAgICAgICAgICB3VGRZd3QgamdUby53VHRDVHdndEVQZHVkVCA9PT0gZVR0Q1R3Z3RFUGR1ZFR4LjVmNmZQMk1TOwogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogZVR0Q1R3IHUgVnVFVCBudyBkYllzMHR1Z2wgamdUby4gSGJneCA3dWxseCBkYlQgdVZWd25Wd2d1ZFQgQll0N2RnbnQKICAgICAgICAgKiAwdXhUQyBudCBkYlQgamdUb3ggeGR1ZFQuIGZCIGRiVCBqZ1RvIGd4IHVsd1R1Q2sgd1R0Q1R3VEMgZ2Qgb2dsbCB3VGRZd3QKICAgICAgICAgKiBCdWx4VC4KICAgICAgICAgKiBAVnV3dXMge2ZlVHRDVHd1MGxUTmdUb30gamdUbwogICAgICAgICAqLwogICAgICAgIHdUdENUd05nVG86IEJZdDdkZ250IEtTNWVUdENUd2d0RWhZVFlUX3dUdENUd05nVG8oamdUbykgewogICAgICAgICAgICBqdXcgeGR1ZFQgPSBqZ1RvLndUdENUd2d0RVBkdWRUOwogICAgICAgICAgICB4b2dkN2IgKHhkdWRUKSB7CiAgICAgICAgICAgICAgICA3dXhUIGVUdENUd2d0RVBkdWRUeC41ZjZmUDJNUzoKICAgICAgICAgICAgICAgICAgICB3VGRZd3QgQnVseFQ7CiAgICAgICAgICAgICAgICA3dXhUIGVUdENUd2d0RVBkdWRUeC5LQVdQTVM6CiAgICAgICAgICAgICAgICAgICAgZGJneC5iZ0ViVHhkS3dnbndnZGtLdUVUID0gamdUby53VHRDVHdndEVmQzsKICAgICAgICAgICAgICAgICAgICBqZ1RvLndUeFlzVCgpOwogICAgICAgICAgICAgICAgICAgIDB3VHVPOwogICAgICAgICAgICAgICAgN3V4VCBlVHRDVHdndEVQZHVkVHguZVc2NmY2cDoKICAgICAgICAgICAgICAgICAgICBkYmd4LmJnRWJUeGRLd2dud2dka0t1RVQgPSBqZ1RvLndUdENUd2d0RWZDOwogICAgICAgICAgICAgICAgICAgIDB3VHVPOwogICAgICAgICAgICAgICAgN3V4VCBlVHRDVHdndEVQZHVkVHguZjZmSGZBSToKICAgICAgICAgICAgICAgICAgICBkYmd4LmJnRWJUeGRLd2dud2dka0t1RVQgPSBqZ1RvLndUdENUd2d0RWZDOwogICAgICAgICAgICAgICAgICAgIGp1dyA3bnRkZ3RZVGVUdENUd2d0RSA9IEJZdDdkZ250ICgpIHsKICAgICAgICAgICAgICAgICAgICAgICAgZGJneC53VHRDVHcyZ0ViVHhkS3dnbndnZGsoKTsKICAgICAgICAgICAgICAgICAgICB9LjBndEMoZGJneCk7CiAgICAgICAgICAgICAgICAgICAgamdUby5Dd3VvKCkuZGJUdCg3bnRkZ3RZVGVUdENUd2d0RSwgN250ZGd0WVRlVHRDVHdndEUpOwogICAgICAgICAgICAgICAgICAgIDB3VHVPOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHdUZFl3dCBkd1lUOwogICAgICAgIH0sCiAgICB9OwoKICAgIHdUZFl3dCBLUzVlVHRDVHdndEVoWVRZVDsKfSkoKTsKCgpqdXcgSE1KSF9JQTRNZV9lTTZTTWVfU01JQTQgPSBadnY7IC8vIHN4CgovKioKICogQGRrVlRDVEIgezkwMVQ3ZH0gS1M1S3VFVE5nVG85VmRnbnR4CiAqIEBWd25WVHdkayB7MkhxSVNnak1sVHNUdGR9IDdudGR1Z3RUdyAtIEhiVCBqZ1RvVHcgVGxUc1R0ZC4KICogQFZ3blZUd2RrIHt0WXMwVHd9IGdDIC0gSGJUIFZ1RVQgWXRnUVlUIGZTICh0bndzdWxsayBnZHggdFlzMFR3KS4KICogQFZ3blZUd2RrIHt0WXMwVHd9IHg3dWxUIC0gSGJUIFZ1RVQgeDd1bFQgQ2d4Vmx1ay4KICogQFZ3blZUd2RrIHtLdUVUTmdUb1Zud2R9IENUQnVZbGROZ1RvVm53ZCAtIEhiVCBWdUVUIGpnVG9WbndkLgogKiBAVnduVlR3ZGsge0tTNWVUdENUd2d0RWhZVFlUfSB3VHRDVHdndEVoWVRZVCAtIEhiVCB3VHRDVHdndEUgUVlUWVQgbjAxVDdkLgogKiBAVnduVlR3ZGsge2ZLUzVIVHJkSXVrVHc1dTdkbndrfSBkVHJkSXVrVHc1dTdkbndrCiAqIEBWd25WVHdkayB7ZktTNUF0dG5kdWRnbnR4SXVrVHc1dTdkbndrfSB1dHRuZHVkZ250eEl1a1R3NXU3ZG53awogKi8KCi8qKgogKiBAN2x1eHgKICogQGdzVmxUc1R0ZHgge2ZlVHRDVHd1MGxUTmdUb30KICovCmp1dyBLUzVLdUVUTmdUbyA9IChCWXQ3ZGdudCBLUzVLdUVUTmdUbzNsbnhZd1QoKSB7CiAgICAvKioKICAgICAqIEA3bnR4ZHdZN2R4IEtTNUt1RVROZ1RvCiAgICAgKiBAVnV3dXMge0tTNUt1RVROZ1RvOVZkZ250eH0gblZkZ250eAogICAgICovCiAgICBCWXQ3ZGdudCBLUzVLdUVUTmdUbyhuVmRnbnR4KSB7CiAgICAgICAganV3IDdudGR1Z3RUdyA9IG5WZGdudHguN250ZHVndFR3OwogICAgICAgIGp1dyBnQyA9IG5WZGdudHguZ0M7CiAgICAgICAganV3IHg3dWxUID0gblZkZ250eC54N3VsVDsKICAgICAgICBqdXcgQ1RCdVlsZE5nVG9WbndkID0gblZkZ250eC5DVEJ1WWxkTmdUb1Zud2Q7CiAgICAgICAganV3IHdUdENUd2d0RWhZVFlUID0gblZkZ250eC53VHRDVHdndEVoWVRZVDsKICAgICAgICBqdXcgZFRyZEl1a1R3NXU3ZG53ayA9IG5WZGdudHguZFRyZEl1a1R3NXU3ZG53azsKICAgICAgICBqdXcgdXR0bmR1ZGdudHhJdWtUdzV1N2Rud2sgPSBuVmRnbnR4LnV0dG5kdWRnbnR4SXVrVHc1dTdkbndrOwoKICAgICAgICBkYmd4LmdDID0gZ0M7CiAgICAgICAgZGJneC53VHRDVHdndEVmQyA9ICdWdUVUJyArIGdDOwoKICAgICAgICBkYmd4LnduZHVkZ250ID0gdjsKICAgICAgICBkYmd4Lng3dWxUID0geDd1bFQgfHwgei52OwogICAgICAgIGRiZ3guamdUb1Zud2QgPSBDVEJ1WWxkTmdUb1Zud2Q7CiAgICAgICAgZGJneC5WQ0JLdUVUZW5kdWRUID0gQ1RCdVlsZE5nVG9WbndkLnduZHVkZ250OwogICAgICAgIGRiZ3guYnV4ZVR4ZHdnN2RUQ1A3dWxndEUgPSBCdWx4VDsKCiAgICAgICAgZGJneC53VHRDVHdndEVoWVRZVCA9IHdUdENUd2d0RWhZVFlUOwogICAgICAgIGRiZ3guZFRyZEl1a1R3NXU3ZG53ayA9IGRUcmRJdWtUdzV1N2Rud2s7CiAgICAgICAgZGJneC51dHRuZHVkZ250eEl1a1R3NXU3ZG53ayA9IHV0dG5kdWRnbnR4SXVrVHc1dTdkbndrOwoKICAgICAgICBkYmd4LndUdENUd2d0RVBkdWRUID0gZVR0Q1R3Z3RFUGR1ZFR4LmY2ZkhmQUk7CiAgICAgICAgZGJneC53VHhZc1QgPSB0WWxsOwoKICAgICAgICBkYmd4Lm50RlRCbndUU3d1byA9IHRZbGw7CiAgICAgICAgZGJneC5udEFCZFR3U3d1byA9IHRZbGw7CgogICAgICAgIGRiZ3guZFRyZEl1a1R3ID0gdFlsbDsKCiAgICAgICAgZGJneC5Hbm5zSXVrVHcgPSB0WWxsOwoKICAgICAgICBkYmd4LnV0dG5kdWRnbnRJdWtUdyA9IHRZbGw7CgogICAgICAgIGp1dyBDZ2ogPSBDbjdZc1R0ZC43d1R1ZFRNbFRzVHRkKCdDZ2onKTsKICAgICAgICBDZ2ouZ0MgPSAnVnVFVDNudGR1Z3RUdycgKyBkYmd4LmdDOwogICAgICAgIENnai43bHV4eDZ1c1QgPSAnVnVFVCc7CiAgICAgICAgQ2dqLnhka2xULm9nQ2RiID0gcXVkYi5CbG5udyhkYmd4LmpnVG9WbndkLm9nQ2RiKSArICdWcic7CiAgICAgICAgQ2dqLnhka2xULmJUZ0ViZCA9IHF1ZGIuQmxubncoZGJneC5qZ1RvVm53ZC5iVGdFYmQpICsgJ1ZyJzsKICAgICAgICBDZ2oueFRkQWRkd2cwWWRUKCdDdWR1LVZ1RVQtdFlzMFR3JywgZGJneC5nQyk7CiAgICAgICAgZGJneC5DZ2ogPSBDZ2o7CgogICAgICAgIDdudGR1Z3RUdy51VlZUdEMzYmdsQyhDZ2opOwogICAgfQoKICAgIEtTNUt1RVROZ1RvLlZ3bmRuZGtWVCA9IHsKICAgICAgICB4VGRLQ0JLdUVUOiBCWXQ3ZGdudCBLUzVLdUVUTmdUb194VGRLQ0JLdUVUKFZDQkt1RVQpIHsKICAgICAgICAgICAgZGJneC5WQ0JLdUVUID0gVkNCS3VFVDsKICAgICAgICAgICAgZGJneC5WQ0JLdUVUZW5kdWRUID0gVkNCS3VFVC53bmR1ZFQ7CiAgICAgICAgICAgIGp1dyBkbmR1bGVuZHVkZ250ID0gKGRiZ3gud25kdWRnbnQgKyBkYmd4LlZDQkt1RVRlbmR1ZFQpICUgbUR2OwogICAgICAgICAgICBkYmd4LmpnVG9WbndkID0gVkNCS3VFVC5FVGROZ1RvVm53ZChkYmd4Lng3dWxUICogM1BQX1c2ZkhQLAogICAgICAgICAgICAgICAgICAgIGRuZHVsZW5kdWRnbnQpOwogICAgICAgICAgICBkYmd4LnhkdWR4ID0gVkNCS3VFVC54ZHVkeDsKICAgICAgICAgICAgZGJneC53VHhUZCgpOwogICAgICAgIH0sCiAgICAgICAgQ1R4ZHduazogQll0N2RnbnQgS1M1S3VFVE5nVG9fQ1R4ZHduaygpIHsKICAgICAgICAgICAgZGJneC5Hbm5zSXVrVHcgPSB0WWxsOwogICAgICAgICAgICBkYmd4LndUeFRkKCk7CiAgICAgICAgICAgIGdCIChkYmd4LlZDQkt1RVQpIHsKICAgICAgICAgICAgICAgIGRiZ3guVkNCS3VFVC5DVHhkd25rKCk7CiAgICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIHdUeFRkOiBCWXQ3ZGdudCBLUzVLdUVUTmdUb193VHhUZChPVFRWQXR0bmR1ZGdudHgpIHsKICAgICAgICAgICAgZ0IgKGRiZ3gud1R0Q1R3SHV4TykgewogICAgICAgICAgICAgICAgZGJneC53VHRDVHdIdXhPLjd1dDdUbCgpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGRiZ3gud1R4WXNUID0gdFlsbDsKICAgICAgICAgICAgZGJneC53VHRDVHdndEVQZHVkVCA9IGVUdENUd2d0RVBkdWRUeC5mNmZIZkFJOwoKICAgICAgICAgICAganV3IENnaiA9IGRiZ3guQ2dqOwogICAgICAgICAgICBDZ2oueGRrbFQub2dDZGIgPSBxdWRiLkJsbm53KGRiZ3guamdUb1Zud2Qub2dDZGIpICsgJ1ZyJzsKICAgICAgICAgICAgQ2dqLnhka2xULmJUZ0ViZCA9IHF1ZGIuQmxubncoZGJneC5qZ1RvVm53ZC5iVGdFYmQpICsgJ1ZyJzsKCiAgICAgICAgICAgIGp1dyA3YmdsQzZuQ1R4ID0gQ2dqLjdiZ2xDNm5DVHg7CiAgICAgICAgICAgIGp1dyA3WXd3VHRkWG5uc0l1a1R3ID0gZGJneC5Hbm5zSXVrVHcgfHwgdFlsbDsKICAgICAgICAgICAganV3IDdZd3dUdGRBdHRuZHVkZ250Nm5DVCA9IChPVFRWQXR0bmR1ZGdudHggJiYgZGJneC51dHRuZHVkZ250SXVrVHcgJiYKICAgICAgICAgICAgICAgICAgICBkYmd4LnV0dG5kdWRnbnRJdWtUdy5DZ2opIHx8IHRZbGw7CiAgICAgICAgICAgIEJudyAoanV3IGcgPSA3YmdsQzZuQ1R4LmxUdEVkYiAtIHo7IGcgPj0gdjsgZy0tKSB7CiAgICAgICAgICAgICAgICBqdXcgdG5DVCA9IDdiZ2xDNm5DVHhbZ107CiAgICAgICAgICAgICAgICBnQiAoN1l3d1R0ZFhubnNJdWtUdyA9PT0gdG5DVCB8fCA3WXd3VHRkQXR0bmR1ZGdudDZuQ1QgPT09IHRuQ1QpIHsKICAgICAgICAgICAgICAgICAgICA3bnRkZ3RZVDsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIENnai53VHNualQzYmdsQyh0bkNUKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBDZ2oud1RzbmpUQWRkd2cwWWRUKCdDdWR1LWxudUNUQycpOwoKICAgICAgICAgICAgZ0IgKE9UVFZBdHRuZHVkZ250eCkgewogICAgICAgICAgICAgICAgZ0IgKGRiZ3gudXR0bmR1ZGdudEl1a1R3KSB7CiAgICAgICAgICAgICAgICAgICAgLy8gMmdDVCB1dHRuZHVkZ250SXVrVHcgWXRkZ2wgdWxsIFRsVHNUdGR4IHV3VCB3VHhnR1RDCiAgICAgICAgICAgICAgICAgICAgLy8geG4gZGJUayB1d1QgdG5kIENneFZsdWtUQyBudCBkYlQgdWx3VHVDay13VHhnR1RDIFZ1RVQKICAgICAgICAgICAgICAgICAgICBkYmd4LnV0dG5kdWRnbnRJdWtUdy5iZ0NUKCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0gVGx4VCB7CiAgICAgICAgICAgICAgICBkYmd4LnV0dG5kdWRnbnRJdWtUdyA9IHRZbGw7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGdCIChkYmd4Ljd1dGp1eCkgewogICAgICAgICAgICAgICAgLy8gWFR3bmd0RSBkYlQgb2dDZGIgdXRDIGJUZ0ViZCA3dVl4VHggNWd3VEJuciBkbiB3VGxUdXhUIEV3dVZiZzd4CiAgICAgICAgICAgICAgICAvLyB3VHhuWXc3VHggZ3NzVENndWRUbGssIG9iZzdiIDd1dCBFd1R1ZGxrIHdUQ1k3VCBzVHNud2sgN250eFlzVmRnbnQuCiAgICAgICAgICAgICAgICBkYmd4Ljd1dGp1eC5vZ0NkYiA9IHY7CiAgICAgICAgICAgICAgICBkYmd4Ljd1dGp1eC5iVGdFYmQgPSB2OwogICAgICAgICAgICAgICAgQ1RsVGRUIGRiZ3guN3V0anV4OwogICAgICAgICAgICB9CgogICAgICAgICAgICBkYmd4LmxudUNndEVmN250U2dqID0gQ243WXNUdGQuN3dUdWRUTWxUc1R0ZCgnQ2dqJyk7CiAgICAgICAgICAgIGRiZ3gubG51Q2d0RWY3bnRTZ2ouN2x1eHg2dXNUID0gJ2xudUNndEVmN250JzsKICAgICAgICAgICAgQ2dqLnVWVlR0QzNiZ2xDKGRiZ3gubG51Q2d0RWY3bnRTZ2opOwogICAgICAgIH0sCiAgICAgICAgWVZDdWRUOiBCWXQ3ZGdudCBLUzVLdUVUTmdUb19ZVkN1ZFQoeDd1bFQsIHduZHVkZ250KSB7CiAgICAgICAgICAgIGRiZ3gueDd1bFQgPSB4N3VsVCB8fCBkYmd4Lng3dWxUOwoKICAgICAgICAgICAgZ0IgKGRrVlRuQiB3bmR1ZGdudCAhPT0gJ1l0Q1RCZ3RUQycpIHsKICAgICAgICAgICAgICAgIGRiZ3gud25kdWRnbnQgPSB3bmR1ZGdudDsKICAgICAgICAgICAgfQoKICAgICAgICAgICAganV3IGRuZHVsZW5kdWRnbnQgPSAoZGJneC53bmR1ZGdudCArIGRiZ3guVkNCS3VFVGVuZHVkVCkgJSBtRHY7CiAgICAgICAgICAgIGRiZ3guamdUb1Zud2QgPSBkYmd4LmpnVG9WbndkLjdsbnRUKHsKICAgICAgICAgICAgICAgIHg3dWxUOiBkYmd4Lng3dWxUICogM1BQX1c2ZkhQLAogICAgICAgICAgICAgICAgd25kdWRnbnQ6IGRuZHVsZW5kdWRnbnQKICAgICAgICAgICAgfSk7CgogICAgICAgICAgICBqdXcgZ3hQN3VsZ3RFZVR4ZHdnN2RUQyA9IEJ1bHhUOwogICAgICAgICAgICBnQiAoZGJneC43dXRqdXggJiYgS1M1eVAuc3VyM3V0anV4S2dyVGx4ID4gdikgewogICAgICAgICAgICAgICAganV3IDdkciA9IGRiZ3guN3V0anV4LkVUZDNudGRUcmQoJ1pDJyk7CiAgICAgICAgICAgICAgICBqdXcgbllkVllkUDd1bFQgPSBFVGQ5WWRWWWRQN3VsVCg3ZHIpOwogICAgICAgICAgICAgICAganV3IFZnclRseGZ0TmdUb1Zud2QgPSBkYmd4LmpnVG9WbndkLm9nQ2RiICogZGJneC5qZ1RvVm53ZC5iVGdFYmQ7CiAgICAgICAgICAgICAgICBqdXcgc3VyUDd1bFQgPSBxdWRiLnhRd2QoS1M1eVAuc3VyM3V0anV4S2dyVGx4IC8gVmdyVGx4ZnROZ1RvVm53ZCk7CiAgICAgICAgICAgICAgICBnQiAoKChxdWRiLkJsbm53KGRiZ3guamdUb1Zud2Qub2dDZGIpICogbllkVllkUDd1bFQueHIpIHwgdikgKgogICAgICAgICAgICAgICAgICAgICAgICAoKHF1ZGIuQmxubncoZGJneC5qZ1RvVm53ZC5iVGdFYmQpICogbllkVllkUDd1bFQueGspIHwgdikgPgogICAgICAgICAgICAgICAgICAgICAgICBLUzV5UC5zdXIzdXRqdXhLZ3JUbHgpIHsKICAgICAgICAgICAgICAgICAgICBneFA3dWxndEVlVHhkd2c3ZFRDID0gZHdZVDsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQoKICAgICAgICAgICAgZ0IgKGRiZ3guN3V0anV4ICYmCiAgICAgICAgICAgICAgICAgICAgKEtTNXlQLll4VDl0bGszeHhYbm5zIHx8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAoZGJneC5idXhlVHhkd2c3ZFRDUDd1bGd0RSAmJiBneFA3dWxndEVlVHhkd2c3ZFRDKSkpIHsKICAgICAgICAgICAgICAgIGRiZ3guN3h4SHd1dHhCbndzKGRiZ3guN3V0anV4LCBkd1lUKTsKICAgICAgICAgICAgICAgIHdUZFl3dDsKICAgICAgICAgICAgfSBUbHhUIGdCIChkYmd4Ljd1dGp1eCAmJiAhZGJneC5Hbm5zSXVrVHcpIHsKICAgICAgICAgICAgICAgIGRiZ3guR25uc0l1a1R3ID0gZGJneC43dXRqdXguVnV3VHRkNm5DVDsKICAgICAgICAgICAgICAgIGRiZ3guR25uc0l1a1R3Lnhka2xULlZueGdkZ250ID0gJ3UweG5sWWRUJzsKICAgICAgICAgICAgfQogICAgICAgICAgICBnQiAoZGJneC5Hbm5zSXVrVHcpIHsKICAgICAgICAgICAgICAgIGRiZ3guN3h4SHd1dHhCbndzKGRiZ3guR25uc0l1a1R3LkJnd3hkM2JnbEMpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGRiZ3gud1R4VGQoZHdZVCk7CiAgICAgICAgfSwKICAgICAgICAvKioKICAgICAgICAgKiAzdWxsVEMgb2JUdCBzbmpUQyBndCBkYlQgVnV3VHRkJ3ggN250ZHVndFR3LgogICAgICAgICAqLwogICAgICAgIFlWQ3VkVEtueGdkZ250OiBCWXQ3ZGdudCBLUzVLdUVUTmdUb19ZVkN1ZFRLbnhnZGdudCgpIHsKICAgICAgICAgICAgZ0IgKGRiZ3guZFRyZEl1a1R3KSB7CiAgICAgICAgICAgICAgICBkYmd4LmRUcmRJdWtUdy53VHRDVHcoSE1KSF9JQTRNZV9lTTZTTWVfU01JQTQpOwogICAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICA3eHhId3V0eEJud3M6IEJZdDdkZ250IEtTNUt1RVROZ1RvX2R3dXR4Qm53cyg3dXRqdXgsIHdUQ3d1b0F0dG5kdWRnbnR4KSB7CiAgICAgICAgICAgIC8vIFA3dWxUIDd1dGp1eCwgN3V0anV4IG93dVZWVHcsIHV0QyBWdUVUIDdudGR1Z3RUdy4KICAgICAgICAgICAganV3IG9nQ2RiID0gZGJneC5qZ1RvVm53ZC5vZ0NkYjsKICAgICAgICAgICAganV3IGJUZ0ViZCA9IGRiZ3guamdUb1Zud2QuYlRnRWJkOwogICAgICAgICAgICBqdXcgQ2dqID0gZGJneC5DZ2o7CiAgICAgICAgICAgIDd1dGp1eC54ZGtsVC5vZ0NkYiA9IDd1dGp1eC5WdXdUdGQ2bkNULnhka2xULm9nQ2RiID0gQ2dqLnhka2xULm9nQ2RiID0KICAgICAgICAgICAgICAgICAgICBxdWRiLkJsbm53KG9nQ2RiKSArICdWcic7CiAgICAgICAgICAgIDd1dGp1eC54ZGtsVC5iVGdFYmQgPSA3dXRqdXguVnV3VHRkNm5DVC54ZGtsVC5iVGdFYmQgPSBDZ2oueGRrbFQuYlRnRWJkID0KICAgICAgICAgICAgICAgICAgICBxdWRiLkJsbm53KGJUZ0ViZCkgKyAnVnInOwogICAgICAgICAgICAvLyBIYlQgN3V0anV4IHN1ayBidWpUIDBUVHQgbndnRWd0dWxsayB3bmR1ZFRDLCB3bmR1ZFQgd1RsdWRnalQgZG4gZGJ1ZC4KICAgICAgICAgICAganV3IHdUbHVkZ2pUZW5kdWRnbnQgPSBkYmd4LmpnVG9WbndkLnduZHVkZ250IC0gN3V0anV4Ll9qZ1RvVm53ZC53bmR1ZGdudDsKICAgICAgICAgICAganV3IHUweGVuZHVkZ250ID0gcXVkYi51MHgod1RsdWRnalRlbmR1ZGdudCk7CiAgICAgICAgICAgIGp1dyB4N3VsVEogPSB6LCB4N3VsVDQgPSB6OwogICAgICAgICAgICBnQiAodTB4ZW5kdWRnbnQgPT09IEx2IHx8IHUweGVuZHVkZ250ID09PSBaYXYpIHsKICAgICAgICAgICAgICAgIC8vIFA3dWxUIHIgdXRDIGsgMFQ3dVl4VCBuQiBkYlQgd25kdWRnbnQuCiAgICAgICAgICAgICAgICB4N3VsVEogPSBiVGdFYmQgLyBvZ0NkYjsKICAgICAgICAgICAgICAgIHg3dWxUNCA9IG9nQ2RiIC8gYlRnRWJkOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGp1dyA3eHhId3V0eEJud3MgPSAnd25kdWRUKCcgKyB3VGx1ZGdqVGVuZHVkZ250ICsgJ0NURSkgJyArCiAgICAgICAgICAgICAgICAgICAgJ3g3dWxUKCcgKyB4N3VsVEogKyAnLCcgKyB4N3VsVDQgKyAnKSc7CiAgICAgICAgICAgIDNZeGRuc1Bka2xULnhUZEt3blYoJ2R3dXR4Qm53cycsIDd1dGp1eCwgN3h4SHd1dHhCbndzKTsKCiAgICAgICAgICAgIGdCIChkYmd4LmRUcmRJdWtUdykgewogICAgICAgICAgICAgICAgLy8gZW5kdWRndEUgZGJUIGRUcmQgbHVrVHcgZ3ggc253VCA3bnNWbGc3dWRUQyB4Z3Q3VCBkYlQgQ2dqeCBndHhnQ1QgZGJUCiAgICAgICAgICAgICAgICAvLyBkYlQgZFRyZCBsdWtUdyB1d1Qgd25kdWRUQy4KICAgICAgICAgICAgICAgIC8vIEg5Uzk6IEhiZ3ggN25ZbEMgVnduMHUwbGsgMFQgeGdzVmxnQmdUQyAwayBDd3VvZ3RFIGRiVCBkVHJkIGx1a1R3IGd0CiAgICAgICAgICAgICAgICAvLyBudFQgbndnVHRkdWRnbnQgZGJUdCB3bmR1ZGd0RSBualR3dWxsLgogICAgICAgICAgICAgICAganV3IGRUcmRJdWtUd05nVG9WbndkID0gZGJneC5kVHJkSXVrVHcuamdUb1Zud2Q7CiAgICAgICAgICAgICAgICBqdXcgZFRyZGVUbHVkZ2pUZW5kdWRnbnQgPSBkYmd4LmpnVG9WbndkLnduZHVkZ250IC0KICAgICAgICAgICAgICAgICAgICAgICAgZFRyZEl1a1R3TmdUb1Zud2Qud25kdWRnbnQ7CiAgICAgICAgICAgICAgICBqdXcgZFRyZEEweGVuZHVkZ250ID0gcXVkYi51MHgoZFRyZGVUbHVkZ2pUZW5kdWRnbnQpOwogICAgICAgICAgICAgICAganV3IHg3dWxUID0gb2dDZGIgLyBkVHJkSXVrVHdOZ1RvVm53ZC5vZ0NkYjsKICAgICAgICAgICAgICAgIGdCIChkVHJkQTB4ZW5kdWRnbnQgPT09IEx2IHx8IGRUcmRBMHhlbmR1ZGdudCA9PT0gWmF2KSB7CiAgICAgICAgICAgICAgICAgICAgeDd1bFQgPSBvZ0NkYiAvIGRUcmRJdWtUd05nVG9WbndkLmJUZ0ViZDsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGp1dyBkVHJkSXVrVHdTZ2ogPSBkYmd4LmRUcmRJdWtUdy5kVHJkSXVrVHdTZ2o7CiAgICAgICAgICAgICAgICBqdXcgZHd1dHhKLCBkd3V0eDQ7CiAgICAgICAgICAgICAgICB4b2dkN2IgKGRUcmRBMHhlbmR1ZGdudCkgewogICAgICAgICAgICAgICAgICAgIDd1eFQgdjoKICAgICAgICAgICAgICAgICAgICAgICAgZHd1dHhKID0gZHd1dHg0ID0gdjsKICAgICAgICAgICAgICAgICAgICAgICAgMHdUdU87CiAgICAgICAgICAgICAgICAgICAgN3V4VCBMdjoKICAgICAgICAgICAgICAgICAgICAgICAgZHd1dHhKID0gdjsKICAgICAgICAgICAgICAgICAgICAgICAgZHd1dHg0ID0gJy0nICsgZFRyZEl1a1R3U2dqLnhka2xULmJUZ0ViZDsKICAgICAgICAgICAgICAgICAgICAgICAgMHdUdU87CiAgICAgICAgICAgICAgICAgICAgN3V4VCB6VXY6CiAgICAgICAgICAgICAgICAgICAgICAgIGR3dXR4SiA9ICctJyArIGRUcmRJdWtUd1Nnai54ZGtsVC5vZ0NkYjsKICAgICAgICAgICAgICAgICAgICAgICAgZHd1dHg0ID0gJy0nICsgZFRyZEl1a1R3U2dqLnhka2xULmJUZ0ViZDsKICAgICAgICAgICAgICAgICAgICAgICAgMHdUdU87CiAgICAgICAgICAgICAgICAgICAgN3V4VCBaYXY6CiAgICAgICAgICAgICAgICAgICAgICAgIGR3dXR4SiA9ICctJyArIGRUcmRJdWtUd1Nnai54ZGtsVC5vZ0NkYjsKICAgICAgICAgICAgICAgICAgICAgICAgZHd1dHg0ID0gdjsKICAgICAgICAgICAgICAgICAgICAgICAgMHdUdU87CiAgICAgICAgICAgICAgICAgICAgQ1RCdVlsZDoKICAgICAgICAgICAgICAgICAgICAgICAgN250eG5sVC5Ud3dudygnRnVDIHduZHVkZ250IGp1bFlULicpOwogICAgICAgICAgICAgICAgICAgICAgICAwd1R1TzsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIDNZeGRuc1Bka2xULnhUZEt3blYoJ2R3dXR4Qm53cycsIGRUcmRJdWtUd1NnaiwKICAgICAgICAgICAgICAgICAgICAgICAgJ3duZHVkVCgnICsgZFRyZEEweGVuZHVkZ250ICsgJ0NURSkgJyArCiAgICAgICAgICAgICAgICAgICAgICAgICd4N3VsVCgnICsgeDd1bFQgKyAnLCAnICsgeDd1bFQgKyAnKSAnICsKICAgICAgICAgICAgICAgICAgICAgICAgJ2R3dXR4bHVkVCgnICsgZHd1dHhKICsgJywgJyArIGR3dXR4NCArICcpJyk7CiAgICAgICAgICAgICAgICAzWXhkbnNQZGtsVC54VGRLd25WKCdkd3V0eEJud3M5d2dFZ3QnLCBkVHJkSXVrVHdTZ2osICd2JSB2JScpOwogICAgICAgICAgICB9CgogICAgICAgICAgICBnQiAod1RDd3VvQXR0bmR1ZGdudHggJiYgZGJneC51dHRuZHVkZ250SXVrVHcpIHsKICAgICAgICAgICAgICAgIGRiZ3gudXR0bmR1ZGdudEl1a1R3LnhUZFlWQXR0bmR1ZGdudHgoZGJneC5qZ1RvVm53ZCk7CiAgICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIEVUZCBvZ0NkYigpIHsKICAgICAgICAgICAgd1RkWXd0IGRiZ3guamdUb1Zud2Qub2dDZGI7CiAgICAgICAgfSwKICAgICAgICBFVGQgYlRnRWJkKCkgewogICAgICAgICAgICB3VGRZd3QgZGJneC5qZ1RvVm53ZC5iVGdFYmQ7CiAgICAgICAgfSwKICAgICAgICBFVGRLdUVUS25ndGQ6IEJZdDdkZ250IEtTNUt1RVROZ1RvX0VUZEt1RVRLbmd0ZChyLCBrKSB7CiAgICAgICAgICAgIHdUZFl3dCBkYmd4LmpnVG9WbndkLjdudGpUd2RIbktDQktuZ3RkKHIsIGspOwogICAgICAgIH0sCiAgICAgICAgQ3d1bzogQll0N2RnbnQgS1M1S3VFVE5nVG9fQ3d1bygpIHsKICAgICAgICAgICAgZ0IgKGRiZ3gud1R0Q1R3Z3RFUGR1ZFQgIT09IGVUdENUd2d0RVBkdWRUeC5mNmZIZkFJKSB7CiAgICAgICAgICAgICAgICA3bnR4bmxULlR3d253KCdxWXhkIDBUIGd0IHRUbyB4ZHVkVCAwVEJud1QgQ3d1b2d0RScpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGRiZ3gud1R0Q1R3Z3RFUGR1ZFQgPSBlVHRDVHdndEVQZHVkVHguZVc2NmY2cDsKCiAgICAgICAgICAgIGp1dyBWQ0JLdUVUID0gZGJneC5WQ0JLdUVUOwogICAgICAgICAgICBqdXcgamdUb1Zud2QgPSBkYmd4LmpnVG9WbndkOwogICAgICAgICAgICBqdXcgQ2dqID0gZGJneC5DZ2o7CiAgICAgICAgICAgIC8vIDh3dVYgZGJUIDd1dGp1eCB4biBnQiBnZCBidXggdSA3eHggZHd1dHhCbndzIEJudyBiZ0ViQ1ZnIGRiVCBualR3QmxubwogICAgICAgICAgICAvLyBvZ2xsIDBUIGJnQ0NUdCBndCA1NS4KICAgICAgICAgICAganV3IDd1dGp1eDh3dVZWVHcgPSBDbjdZc1R0ZC43d1R1ZFRNbFRzVHRkKCdDZ2onKTsKICAgICAgICAgICAgN3V0anV4OHd1VlZUdy54ZGtsVC5vZ0NkYiA9IENnai54ZGtsVC5vZ0NkYjsKICAgICAgICAgICAgN3V0anV4OHd1VlZUdy54ZGtsVC5iVGdFYmQgPSBDZ2oueGRrbFQuYlRnRWJkOwogICAgICAgICAgICA3dXRqdXg4d3VWVlR3LjdsdXh4SWd4ZC51Q0MoJzd1dGp1eDh3dVZWVHcnKTsKCgogICAgICAgICAgICBqdXcgN3V0anV4ID0gQ243WXNUdGQuN3dUdWRUTWxUc1R0ZCgnN3V0anV4Jyk7CgoKICAgICAgICAgICAgN3V0anV4LlZ1RVQ2WXMwVHcgPSBkYmd4LmdDOwogICAgICAgICAgICA3dXRqdXguZ0MgPSAnVnVFVCcgKyBkYmd4LmdDOwoKCiAgICAgICAgICAgIDd1dGp1eDh3dVZWVHcudVZWVHRDM2JnbEMoN3V0anV4KTsKCiAgICAgICAgICAgIGdCIChkYmd4LnV0dG5kdWRnbnRJdWtUdykgewogICAgICAgICAgICAgICAgLy8gdXR0bmR1ZGdudEl1a1R3IHRUVEN4IGRuIHhkdWsgbnQgZG5WCiAgICAgICAgICAgICAgICBDZ2ouZ3R4VHdkRlRCbndUKDd1dGp1eDh3dVZWVHcsIGRiZ3gudXR0bmR1ZGdudEl1a1R3LkNnaik7CiAgICAgICAgICAgIH0gVGx4VCB7CiAgICAgICAgICAgICAgICBDZ2oudVZWVHRDM2JnbEMoN3V0anV4OHd1VlZUdyk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZGJneC43dXRqdXggPSA3dXRqdXg7CgogICAgICAgICAgICBqdXcgN2RyID0gN3V0anV4LkVUZDNudGRUcmQoJ1pDJyk7CiAgICAgICAgICAgIGp1dyBuWWRWWWRQN3VsVCA9IEVUZDlZZFZZZFA3dWxUKDdkcik7CgogICAgICAgICAgICBnQiAoS1M1eVAuWXhUOXRsazN4eFhubnMpIHsKICAgICAgICAgICAgICAgIGp1dyB1N2RZdWxQZ0dUTmdUb1Zud2QgPSBqZ1RvVm53ZC43bG50VCh7eDd1bFQ6IDNQUF9XNmZIUH0pOwogICAgICAgICAgICAgICAgLy8gV3hUIHUgeDd1bFQgZGJ1ZCBvZ2xsIHN1T1QgZGJUIDd1dGp1eCAwVCBkYlQgbndnRWd0dWwgZ3RkVHRDVEMgeGdHVAogICAgICAgICAgICAgICAgLy8gbkIgZGJUIFZ1RVQuCiAgICAgICAgICAgICAgICBuWWRWWWRQN3VsVC54ciAqPSB1N2RZdWxQZ0dUTmdUb1Zud2Qub2dDZGIgLyBqZ1RvVm53ZC5vZ0NkYjsKICAgICAgICAgICAgICAgIG5ZZFZZZFA3dWxULnhrICo9IHU3ZFl1bFBnR1ROZ1RvVm53ZC5iVGdFYmQgLyBqZ1RvVm53ZC5iVGdFYmQ7CiAgICAgICAgICAgICAgICBuWWRWWWRQN3VsVC54N3VsVEMgPSBkd1lUOwogICAgICAgICAgICB9CgogICAgICAgICAgICBnQiAoS1M1eVAuc3VyM3V0anV4S2dyVGx4ID4gdikgewogICAgICAgICAgICAgICAganV3IFZnclRseGZ0TmdUb1Zud2QgPSBqZ1RvVm53ZC5vZ0NkYiAqIGpnVG9WbndkLmJUZ0ViZDsKICAgICAgICAgICAgICAgIGp1dyBzdXJQN3VsVCA9IHF1ZGIueFF3ZChLUzV5UC5zdXIzdXRqdXhLZ3JUbHggLyBWZ3JUbHhmdE5nVG9WbndkKTsKICAgICAgICAgICAgICAgIGdCIChuWWRWWWRQN3VsVC54ciA+IHN1clA3dWxUIHx8IG5ZZFZZZFA3dWxULnhrID4gc3VyUDd1bFQpIHsKICAgICAgICAgICAgICAgICAgICBuWWRWWWRQN3VsVC54ciA9IHN1clA3dWxUOwogICAgICAgICAgICAgICAgICAgIG5ZZFZZZFA3dWxULnhrID0gc3VyUDd1bFQ7CiAgICAgICAgICAgICAgICAgICAgbllkVllkUDd1bFQueDd1bFRDID0gZHdZVDsKICAgICAgICAgICAgICAgICAgICBkYmd4LmJ1eGVUeGR3ZzdkVENQN3VsZ3RFID0gZHdZVDsKICAgICAgICAgICAgICAgIH0gVGx4VCB7CiAgICAgICAgICAgICAgICAgICAgZGJneC5idXhlVHhkd2c3ZFRDUDd1bGd0RSA9IEJ1bHhUOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIDd1dGp1eC5vZ0NkYiA9IChxdWRiLkJsbm53KGpnVG9WbndkLm9nQ2RiKSAqIG5ZZFZZZFA3dWxULnhyKSB8IHY7CiAgICAgICAgICAgIDd1dGp1eC5iVGdFYmQgPSAocXVkYi5CbG5udyhqZ1RvVm53ZC5iVGdFYmQpICogbllkVllkUDd1bFQueGspIHwgdjsKICAgICAgICAgICAgN3V0anV4Lnhka2xULm9nQ2RiID0gcXVkYi5CbG5udyhqZ1RvVm53ZC5vZ0NkYikgKyAnVnInOwogICAgICAgICAgICA3dXRqdXgueGRrbFQuYlRnRWJkID0gcXVkYi5CbG5udyhqZ1RvVm53ZC5iVGdFYmQpICsgJ1ZyJzsKCiAgICAgICAgICAgIC8vIEFDQyBkYlQgamdUb1Zud2QgeG4gZ2QneCBPdG5vdCBvYnVkIGdkIG91eCBud2dFZ3R1bGxrIEN3dW90IG9nZGIuCiAgICAgICAgICAgIDd1dGp1eC5famdUb1Zud2QgPSBqZ1RvVm53ZDsKCiAgICAgICAgICAgIGp1dyBkVHJkSXVrVHdTZ2ogPSB0WWxsOwogICAgICAgICAgICBqdXcgZFRyZEl1a1R3ID0gdFlsbDsKICAgICAgICAgICAgZ0IgKGRiZ3guZFRyZEl1a1R3NXU3ZG53aykgewogICAgICAgICAgICAgICAgZFRyZEl1a1R3U2dqID0gQ243WXNUdGQuN3dUdWRUTWxUc1R0ZCgnQ2dqJyk7CiAgICAgICAgICAgICAgICBkVHJkSXVrVHdTZ2ouN2x1eHg2dXNUID0gJ2RUcmRJdWtUdyc7CiAgICAgICAgICAgICAgICBkVHJkSXVrVHdTZ2oueGRrbFQub2dDZGIgPSA3dXRqdXgueGRrbFQub2dDZGI7CiAgICAgICAgICAgICAgICBkVHJkSXVrVHdTZ2oueGRrbFQuYlRnRWJkID0gN3V0anV4Lnhka2xULmJUZ0ViZDsKICAgICAgICAgICAgICAgIGdCIChkYmd4LnV0dG5kdWRnbnRJdWtUdykgewogICAgICAgICAgICAgICAgICAgIC8vIHV0dG5kdWRnbnRJdWtUdyB0VFRDeCBkbiB4ZHVrIG50IGRuVgogICAgICAgICAgICAgICAgICAgIENnai5ndHhUd2RGVEJud1QoZFRyZEl1a1R3U2dqLCBkYmd4LnV0dG5kdWRnbnRJdWtUdy5DZ2opOwogICAgICAgICAgICAgICAgfSBUbHhUIHsKICAgICAgICAgICAgICAgICAgICBDZ2oudVZWVHRDM2JnbEMoZFRyZEl1a1R3U2dqKTsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICBkVHJkSXVrVHcgPSBkYmd4LmRUcmRJdWtUdzV1N2Rud2suN3dUdWRUSFRyZEl1a1R3RllnbENUdyhkVHJkSXVrVHdTZ2osCiAgICAgICAgICAgICAgICAgICAgICAgIGRiZ3guZ0MgLSB6LAogICAgICAgICAgICAgICAgICAgICAgICBkYmd4LmpnVG9WbndkKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBkYmd4LmRUcmRJdWtUdyA9IGRUcmRJdWtUdzsKCiAgICAgICAgICAgIGdCIChuWWRWWWRQN3VsVC54N3VsVEMpIHsKICAgICAgICAgICAgICAgIC8vIFd4VEMgMGsgZGJUIHNuRzNZd3dUdGRId3V0eEJud3MgVm5sa0JnbGwgZ3QgeHc3L0NneFZsdWsvN3V0anV4LjF4LgogICAgICAgICAgICAgICAgN2RyLl9kd3V0eEJud3NxdWR3Z3IgPSBbbllkVllkUDd1bFQueHIsIHYsIHYsIG5ZZFZZZFA3dWxULnhrLCB2LCB2XTsKICAgICAgICAgICAgICAgIDdkci54N3VsVChuWWRWWWRQN3VsVC54ciwgbllkVllkUDd1bFQueGspOwogICAgICAgICAgICB9CgogICAgICAgICAgICBqdXcgd1R4bmxqVGVUdENUd0t3bnNneFQsIHdUMVQ3ZGVUdENUd0t3bnNneFQ7CiAgICAgICAgICAgIGp1dyBWd25zZ3hUID0gdFRvIEt3bnNneFQoQll0N2RnbnQgKHdUeG5salQsIHdUMVQ3ZCkgewogICAgICAgICAgICAgICAgd1R4bmxqVGVUdENUd0t3bnNneFQgPSB3VHhubGpUOwogICAgICAgICAgICAgICAgd1QxVDdkZVR0Q1R3S3duc2d4VCA9IHdUMVQ3ZDsKICAgICAgICAgICAgfSk7CgogICAgICAgICAgICAvLyBlVHRDVHdndEUgdXdUdQoKICAgICAgICAgICAganV3IHhUbEIgPSBkYmd4OwogICAgICAgICAgICBCWXQ3ZGdudCBWdUVUTmdUb1N3dW8zdWxsMHU3TyhUd3dudykgewogICAgICAgICAgICAgICAgLy8gSGJUIHdUdENUd0h1eE8gc3VrIGJ1alQgMFRUdCB3VFZsdTdUQyAwayB1IHRUbyBudFQsIHhuIG50bGsgd1RzbmpUCiAgICAgICAgICAgICAgICAvLyBkYlQgd1RCVHdUdDdUIGRuIGRiVCB3VHRDVHdIdXhPIGdCIGdkIHN1ZDdiVHggZGJUIG50VCBkYnVkIGd4CiAgICAgICAgICAgICAgICAvLyBkd2dFRVR3Z3RFIGRiZ3ggN3VsbDB1N08uCiAgICAgICAgICAgICAgICBnQiAod1R0Q1R3SHV4TyA9PT0geFRsQi53VHRDVHdIdXhPKSB7CiAgICAgICAgICAgICAgICAgICAgeFRsQi53VHRDVHdIdXhPID0gdFlsbDsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICBnQiAoVHd3bncgPT09ICc3dXQ3VGxsVEMnKSB7CiAgICAgICAgICAgICAgICAgICAgd1QxVDdkZVR0Q1R3S3duc2d4VChUd3dudyk7CiAgICAgICAgICAgICAgICAgICAgd1RkWXd0OwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgeFRsQi53VHRDVHdndEVQZHVkVCA9IGVUdENUd2d0RVBkdWRUeC41ZjZmUDJNUzsKCiAgICAgICAgICAgICAgICBnQiAoeFRsQi5sbnVDZ3RFZjdudFNnaikgewogICAgICAgICAgICAgICAgICAgIENnai53VHNualQzYmdsQyh4VGxCLmxudUNndEVmN250U2dqKTsKICAgICAgICAgICAgICAgICAgICBDVGxUZFQgeFRsQi5sbnVDZ3RFZjdudFNnajsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICBnQiAoeFRsQi5Hbm5zSXVrVHcpIHsKICAgICAgICAgICAgICAgICAgICBDZ2oud1RzbmpUM2JnbEMoeFRsQi5Hbm5zSXVrVHcpOwogICAgICAgICAgICAgICAgICAgIHhUbEIuR25uc0l1a1R3ID0gdFlsbDsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICB4VGxCLlR3d253ID0gVHd3bnc7CiAgICAgICAgICAgICAgICB4VGxCLnhkdWR4ID0gVkNCS3VFVC54ZHVkeDsKICAgICAgICAgICAgICAgIGdCICh4VGxCLm50QUJkVHdTd3VvKSB7CiAgICAgICAgICAgICAgICAgICAgeFRsQi5udEFCZFR3U3d1bygpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAganV3IFRqVHRkID0gQ243WXNUdGQuN3dUdWRUTWpUdGQoJzNZeGRuc01qVHRkJyk7CiAgICAgICAgICAgICAgICBUalR0ZC5ndGdkM1l4ZG5zTWpUdGQoJ1Z1RVR3VHRDVHdUQycsIGR3WVQsIGR3WVQsIHsKICAgICAgICAgICAgICAgICAgICBWdUVUNllzMFR3OiB4VGxCLmdDCiAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIENnai5DZ3hWdWQ3Yk1qVHRkKFRqVHRkKTsKICAgICAgICAgICAgICAgIC8vIEhiZ3ggN1l4ZG5zIFRqVHRkIGd4IENUVndUN3VkVEMsIHV0QyBvZ2xsIDBUIHdUc25qVEMgZ3QgZGJUIEJZZFl3VCwKICAgICAgICAgICAgICAgIC8vIFZsVHV4VCBZeFQgZGJUIHxWdUVUd1R0Q1R3VEN8IFRqVHRkIGd0eGRUdUMuCiAgICAgICAgICAgICAgICBqdXcgQ1RWd1Q3dWRUQ01qVHRkID0gQ243WXNUdGQuN3dUdWRUTWpUdGQoJzNZeGRuc01qVHRkJyk7CiAgICAgICAgICAgICAgICBDVFZ3VDd1ZFRDTWpUdGQuZ3RnZDNZeGRuc01qVHRkKCdWdUVUd1R0Q1R3JywgZHdZVCwgZHdZVCwgewogICAgICAgICAgICAgICAgICAgIFZ1RVQ2WXMwVHc6IFZDQkt1RVQuVnVFVDZZczBUdwogICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICBDZ2ouQ2d4VnVkN2JNalR0ZChDVFZ3VDd1ZFRDTWpUdGQpOwoKICAgICAgICAgICAgICAgIGdCICghVHd3bncpIHsKICAgICAgICAgICAgICAgICAgICB3VHhubGpUZVR0Q1R3S3duc2d4VChZdENUQmd0VEMpOwogICAgICAgICAgICAgICAgfSBUbHhUIHsKICAgICAgICAgICAgICAgICAgICB3VDFUN2RlVHRDVHdLd25zZ3hUKFR3d253KTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQoKICAgICAgICAgICAganV3IHdUdENUdzNudGRndFlUM3VsbDB1N08gPSB0WWxsOwogICAgICAgICAgICBnQiAoZGJneC53VHRDVHdndEVoWVRZVCkgewogICAgICAgICAgICAgICAgd1R0Q1R3M250ZGd0WVQzdWxsMHU3TyA9IEJZdDdkZ250IHdUdENUdzNudGRndFlUM3VsbDB1N08oN250ZCkgewogICAgICAgICAgICAgICAgICAgIGdCICgheFRsQi53VHRDVHdndEVoWVRZVC5neDJnRWJUeGRLd2dud2dkayh4VGxCKSkgewogICAgICAgICAgICAgICAgICAgICAgICB4VGxCLndUdENUd2d0RVBkdWRUID0gZVR0Q1R3Z3RFUGR1ZFR4LktBV1BNUzsKICAgICAgICAgICAgICAgICAgICAgICAgeFRsQi53VHhZc1QgPSBCWXQ3ZGdudCB3VHhZc1QzdWxsMHU3TygpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHhUbEIud1R0Q1R3Z3RFUGR1ZFQgPSBlVHRDVHdndEVQZHVkVHguZVc2NmY2cDsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIDdudGQoKTsKICAgICAgICAgICAgICAgICAgICAgICAgfTsKICAgICAgICAgICAgICAgICAgICAgICAgd1RkWXd0OwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICA3bnRkKCk7CiAgICAgICAgICAgICAgICB9OwogICAgICAgICAgICB9CgogICAgICAgICAgICBqdXcgd1R0Q1R3M250ZFRyZCA9IHsKICAgICAgICAgICAgICAgIDd1dGp1eDNudGRUcmQ6IDdkciwKICAgICAgICAgICAgICAgIGpnVG9WbndkOiBkYmd4LmpnVG9WbndkLAogICAgICAgICAgICAgICAgLy8gZ3RkVHRkOiAnQ1RCdVlsZCcsIC8vID09PSAnQ2d4Vmx1aycKICAgICAgICAgICAgICAgIDdudGRndFlUM3VsbDB1N086IHdUdENUdzNudGRndFlUM3VsbDB1N08KICAgICAgICAgICAgfTsKICAgICAgICAgICAganV3IHdUdENUd0h1eE8gPSBkYmd4LndUdENUd0h1eE8gPSBkYmd4LlZDQkt1RVQud1R0Q1R3KHdUdENUdzNudGRUcmQpOwoKICAgICAgICAgICAgZGJneC53VHRDVHdIdXhPLlZ3bnNneFQuZGJUdCgKICAgICAgICAgICAgICAgICAgICBCWXQ3ZGdudCBWQ0JLdUVUZVR0Q1R3M3VsbDB1N08oKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIFZ1RVROZ1RvU3d1bzN1bGwwdTdPKHRZbGwpOwogICAgICAgICAgICAgICAgICAgICAgICBnQiAoZFRyZEl1a1R3KSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB4VGxCLlZDQkt1RVQuRVRkSFRyZDNudGRUdGQoKS5kYlR0KAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBCWXQ3ZGdudCBkVHJkM250ZFR0ZGVUeG5salRDKGRUcmQzbnRkVHRkKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkVHJkSXVrVHcueFRkSFRyZDNudGRUdGQoZFRyZDNudGRUdGQpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZFRyZEl1a1R3LndUdENUdyhITUpIX0lBNE1lX2VNNlNNZV9TTUlBNCk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAgICAgIEJZdDdkZ250IFZDQkt1RVRlVHRDVHdNd3dudyhUd3dudykgewogICAgICAgICAgICAgICAgICAgICAgICBWdUVUTmdUb1N3dW8zdWxsMHU3TyhUd3dudyk7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICApOwoKICAgICAgICAgICAgZ0IgKGRiZ3gudXR0bmR1ZGdudHhJdWtUdzV1N2Rud2spIHsKICAgICAgICAgICAgICAgIGdCICghZGJneC51dHRuZHVkZ250SXVrVHcpIHsKICAgICAgICAgICAgICAgICAgICBkYmd4LnV0dG5kdWRnbnRJdWtUdyA9IGRiZ3gudXR0bmR1ZGdudHhJdWtUdzV1N2Rud2suCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA3d1R1ZFRBdHRuZHVkZ250eEl1a1R3RllnbENUdyhDZ2osIGRiZ3guVkNCS3VFVCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBkYmd4LnV0dG5kdWRnbnRJdWtUdy54VGRZVkF0dG5kdWRnbnR4KGRiZ3guamdUb1Zud2QpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIENnai54VGRBZGR3ZzBZZFQoJ0N1ZHUtbG51Q1RDJywgZHdZVCk7CgogICAgICAgICAgICBnQiAoeFRsQi5udEZUQm53VFN3dW8pIHsKICAgICAgICAgICAgICAgIHhUbEIubnRGVEJud1RTd3VvKCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgd1RkWXd0IFZ3bnNneFQ7CiAgICAgICAgfSwKICAgICAgICAwVEJud1RLd2d0ZDogQll0N2RnbnQgS1M1S3VFVE5nVG9fMFRCbndUS3dndGQoKSB7CiAgICAgICAgICAgIGp1dyBWQ0JLdUVUID0gZGJneC5WQ0JLdUVUOwoKICAgICAgICAgICAganV3IGpnVG9WbndkID0gVkNCS3VFVC5FVGROZ1RvVm53ZCh6KTsKICAgICAgICAgICAgLy8gV3hUIGRiVCB4dXNUIGJ1N08gb1QgWXhUIEJudyBiZ0ViIENWZyBDZ3hWbHVreCBCbncgVndndGRndEUgZG4gRVRkCiAgICAgICAgICAgIC8vIDBUZGRUdyBuWWRWWWQgWXRkZ2wgMFlFIFV6enZ2WiBneCBCZ3JUQyBndCA1NS4KICAgICAgICAgICAganV3IEtlZjZIXzlXSEtXSF9QM0FJTSA9IFo7CiAgICAgICAgICAgIGp1dyA3dXRqdXggPSBDbjdZc1R0ZC43d1R1ZFRNbFRzVHRkKCc3dXRqdXgnKTsKCiAgICAgICAgICAgIC8vIEhiVCBsbkVnN3VsIHhnR1QgbkIgZGJUIDd1dGp1eC4KICAgICAgICAgICAgN3V0anV4Lm9nQ2RiID0gcXVkYi5CbG5udyhqZ1RvVm53ZC5vZ0NkYikgKiBLZWY2SF85V0hLV0hfUDNBSU07CiAgICAgICAgICAgIDd1dGp1eC5iVGdFYmQgPSBxdWRiLkJsbm53KGpnVG9WbndkLmJUZ0ViZCkgKiBLZWY2SF85V0hLV0hfUDNBSU07CgogICAgICAgICAgICAvLyBIYlQgd1R0Q1R3VEMgeGdHVCBuQiBkYlQgN3V0anV4LCB3VGx1ZGdqVCBkbiBkYlQgeGdHVCBuQiA3dXRqdXg4d3VWVlR3LgogICAgICAgICAgICA3dXRqdXgueGRrbFQub2dDZGIgPSAoS2VmNkhfOVdIS1dIX1AzQUlNICogenZ2KSArICclJzsKICAgICAgICAgICAgN3V0anV4Lnhka2xULmJUZ0ViZCA9IChLZWY2SF85V0hLV0hfUDNBSU0gKiB6dnYpICsgJyUnOwoKICAgICAgICAgICAganV3IDd4eFA3dWxUID0gJ3g3dWxUKCcgKyAoeiAvIEtlZjZIXzlXSEtXSF9QM0FJTSkgKyAnLCAnICsKICAgICAgICAgICAgICAgICAgICAoeiAvIEtlZjZIXzlXSEtXSF9QM0FJTSkgKyAnKSc7CiAgICAgICAgICAgIDNZeGRuc1Bka2xULnhUZEt3blYoJ2R3dXR4Qm53cycsIDd1dGp1eCwgN3h4UDd1bFQpOwogICAgICAgICAgICAzWXhkbnNQZGtsVC54VGRLd25WKCdkd3V0eEJud3M5d2dFZ3QnLCA3dXRqdXgsICd2JSB2JScpOwoKICAgICAgICAgICAganV3IFZ3Z3RkM250ZHVndFR3ID0gQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ1Z3Z3RkM250ZHVndFR3Jyk7CiAgICAgICAgICAgIGp1dyA3dXRqdXg4d3VWVlR3ID0gQ243WXNUdGQuN3dUdWRUTWxUc1R0ZCgnQ2dqJyk7CiAgICAgICAgICAgIDd1dGp1eDh3dVZWVHcueGRrbFQub2dDZGIgPSBqZ1RvVm53ZC5vZ0NkYiArICdWZCc7CiAgICAgICAgICAgIDd1dGp1eDh3dVZWVHcueGRrbFQuYlRnRWJkID0gamdUb1Zud2QuYlRnRWJkICsgJ1ZkJzsKICAgICAgICAgICAgN3V0anV4OHd1VlZUdy51VlZUdEMzYmdsQyg3dXRqdXgpOwogICAgICAgICAgICBWd2d0ZDNudGR1Z3RUdy51VlZUdEMzYmdsQyg3dXRqdXg4d3VWVlR3KTsKCiAgICAgICAgICAgIDd1dGp1eC5zbkdLd2d0ZDN1bGwwdTdPID0gQll0N2RnbnQgKG4wMSkgewogICAgICAgICAgICAgICAganV3IDdkciA9IG4wMS43bnRkVHJkOwoKICAgICAgICAgICAgICAgIDdkci54dWpUKCk7CiAgICAgICAgICAgICAgICA3ZHIuQmdsbFBka2xUID0gJ3dFMChaY2MsIFpjYywgWmNjKSc7CiAgICAgICAgICAgICAgICA3ZHIuQmdsbGVUN2QodiwgdiwgN3V0anV4Lm9nQ2RiLCA3dXRqdXguYlRnRWJkKTsKICAgICAgICAgICAgICAgIDdkci53VHhkbndUKCk7CiAgICAgICAgICAgICAgICAvLyBXeFRDIDBrIGRiVCBzbkczWXd3VHRkSHd1dHhCbndzIFZubGtCZ2xsIGd0IHh3Ny9DZ3hWbHVrLzd1dGp1eC4xeC4KICAgICAgICAgICAgICAgIDdkci5fZHd1dHhCbndzcXVkd2dyID0KICAgICAgICAgICAgICAgICAgICAgICAgW0tlZjZIXzlXSEtXSF9QM0FJTSwgdiwgdiwgS2VmNkhfOVdIS1dIX1AzQUlNLCB2LCB2XTsKICAgICAgICAgICAgICAgIDdkci54N3VsVChLZWY2SF85V0hLV0hfUDNBSU0sIEtlZjZIXzlXSEtXSF9QM0FJTSk7CgogICAgICAgICAgICAgICAganV3IHdUdENUdzNudGRUcmQgPSB7CiAgICAgICAgICAgICAgICAgICAgN3V0anV4M250ZFRyZDogN2RyLAogICAgICAgICAgICAgICAgICAgIGpnVG9WbndkOiBqZ1RvVm53ZCwKICAgICAgICAgICAgICAgICAgICBndGRUdGQ6ICdWd2d0ZCcKICAgICAgICAgICAgICAgIH07CgogICAgICAgICAgICAgICAgVkNCS3VFVC53VHRDVHcod1R0Q1R3M250ZFRyZCkuVnduc2d4VC5kYlR0KEJZdDdkZ250ICgpIHsKICAgICAgICAgICAgICAgICAgICBCbncgKGp1dyBnID0gdjsgZyA8IEtTNU5nVG9Ud0FWVmxnN3VkZ250LkNuN1lzVHRkQXR0bmR1ZGdudHgubFR0RWRiOyBnKyspIHsKICAgICAgICAgICAgICAgICAgICAgICAganV3IHV0dCA9IEtTNU5nVG9Ud0FWVmxnN3VkZ250LkNuN1lzVHRkQXR0bmR1ZGdudHhbZ107CiAgICAgICAgICAgICAgICAgICAgICAgIGp1dyBDbjdZc1R0ZEF0dG5kdWRnbnQgPSB0VG8gU243WXNUdGRBdHRuZHVkZ250KHV0dCk7CiAgICAgICAgICAgICAgICAgICAgICAgIGdCIChWQ0JLdUVULlZ1RVQ2WXMwVHcgPT0gQ243WXNUdGRBdHRuZHVkZ250LlZ1RVRmQykgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgZ0IgKCFDbjdZc1R0ZEF0dG5kdWRnbnQuQ1RsVGRUQykgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIENuN1lzVHRkQXR0bmR1ZGdudC5Dd3VvKDdkciwgdi5hYyk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgLy8gSFRsbCBkYlQgVndndGRNdEVndFQgZGJ1ZCB3VHRDVHdndEUgZGJneCA3dXRqdXgvVnVFVCBidXggQmd0Z3hiVEMuCiAgICAgICAgICAgICAgICAgICAgbjAxLkNudFQoKTsKCgogICAgICAgICAgICAgICAgfSwgQll0N2RnbnQgKFR3d253KSB7CiAgICAgICAgICAgICAgICAgICAgN250eG5sVC5Ud3dudyhUd3dudyk7CiAgICAgICAgICAgICAgICAgICAgLy8gSFRsbCBkYlQgVndndGRNdEVndFQgZGJ1ZCB3VHRDVHdndEUgZGJneCA3dXRqdXgvVnVFVCBidXggQnVnbFRDLgogICAgICAgICAgICAgICAgICAgIC8vIEhiZ3ggb2dsbCBzdU9UIGRiVCBWd2d0ZCBWd243VHggeGRuVi4KICAgICAgICAgICAgICAgICAgICBnQiAoJ3UwbndkJyBndCBuMDEpIHsKICAgICAgICAgICAgICAgICAgICAgICAgbjAxLnUwbndkKCk7CiAgICAgICAgICAgICAgICAgICAgfSBUbHhUIHsKICAgICAgICAgICAgICAgICAgICAgICAgbjAxLkNudFQoKTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgfTsKICAgICAgICB9LAogICAgfTsKCiAgICB3VGRZd3QgS1M1S3VFVE5nVG87Cn0pKCk7CgoKanV3IHFBSl9ITUpIX1NmTlBfSDlfZU02U01lID0genZ2dnZ2OwoKanV3IDZudDhiZ2RUeFZ1N1RlVEVUclYgPSAvXFAvOwoKQll0N2RnbnQgZ3hBbGw4YmdkVHhWdTdUKHhkdykgewogICAgd1RkWXd0ICE2bnQ4YmdkVHhWdTdUZVRFVHJWLmRUeGQoeGR3KTsKfQoKLyoqCiAqIEBka1ZUQ1RCIHs5MDFUN2R9IEhUcmRJdWtUd0ZZZ2xDVHc5VmRnbnR4CiAqIEBWd25WVHdkayB7MkhxSVNnak1sVHNUdGR9IGRUcmRJdWtUd1NnaiAtIEhiVCBkVHJkIGx1a1R3IDdudGR1Z3RUdy4KICogQFZ3blZUd2RrIHt0WXMwVHd9IFZ1RVRmdENUciAtIEhiVCBWdUVUIGd0Q1RyLgogKiBAVnduVlR3ZGsge0t1RVROZ1RvVm53ZH0gamdUb1Zud2QgLSBIYlQgamdUb1Zud2QgbkIgZGJUIGRUcmQgbHVrVHcuCiAqIEBWd25WVHdkayB7S1M1NWd0QzNudGR3bmxsVHd9IEJndEMzbnRkd25sbFR3CiAqLwoKLyoqCiAqIEhUcmRJdWtUd0ZZZ2xDVHcgVnduamdDVHggZFRyZC14VGxUN2RnbnQgQll0N2RnbnR1bGdkayBCbncgZGJUIEtTNS4KICogZmQgQ25UeCBkYmd4IDBrIDd3VHVkZ3RFIG5qVHdsdWsgQ2dqeCBualR3IGRiVCBLUzUgZFRyZC4gSGJUeFQgQ2dqeAogKiA3bnRkdWd0IGRUcmQgZGJ1ZCBzdWQ3YlR4IGRiVCBLUzUgZFRyZCBkYlRrIHV3VCBualR3bHVrZ3RFLiBIYmd4IG4wMVQ3ZAogKiB1bHhuIFZ3bmpnQ1R4IHUgb3VrIGRuIGJnRWJsZ0ViZCBkVHJkIGRidWQgZ3ggMFRndEUgeFR1dzdiVEMgQm53LgogKiBAN2x1eHgKICovCmp1dyBIVHJkSXVrVHdGWWdsQ1R3ID0gKEJZdDdkZ250IEhUcmRJdWtUd0ZZZ2xDVHczbG54WXdUKCkgewogICAgQll0N2RnbnQgSFRyZEl1a1R3RllnbENUdyhuVmRnbnR4KSB7CiAgICAgICAgZGJneC5kVHJkSXVrVHdTZ2ogPSBuVmRnbnR4LmRUcmRJdWtUd1NnajsKICAgICAgICBkYmd4LndUdENUd2d0RVNudFQgPSBCdWx4VDsKICAgICAgICBkYmd4LkNnajNudGRUdGRTbnRUID0gQnVseFQ7CiAgICAgICAgZGJneC5WdUVUZkNyID0gblZkZ250eC5WdUVUZnRDVHI7CiAgICAgICAgZGJneC5WdUVUNllzMFR3ID0gZGJneC5WdUVUZkNyICsgejsKICAgICAgICBkYmd4LnN1ZDdiVHggPSBbXTsKICAgICAgICBkYmd4LmpnVG9WbndkID0gblZkZ250eC5qZ1RvVm53ZDsKICAgICAgICBkYmd4LmRUcmRTZ2p4ID0gW107CiAgICAgICAgZGJneC5CZ3RDM250ZHdubGxUdyA9IG5WZGdudHguQmd0QzNudGR3bmxsVHcgfHwgdFlsbDsKICAgIH0KCiAgICBIVHJkSXVrVHdGWWdsQ1R3LlZ3bmRuZGtWVCA9IHsKICAgICAgICBfQmd0Z3hiZVR0Q1R3Z3RFOiBCWXQ3ZGdudCBIVHJkSXVrVHdGWWdsQ1R3X0JndGd4YmVUdENUd2d0RSgpIHsKICAgICAgICAgICAgZGJneC53VHRDVHdndEVTbnRUID0gZHdZVDsKCiAgICAgICAgICAgIGp1dyBUalR0ZCA9IENuN1lzVHRkLjd3VHVkVE1qVHRkKCczWXhkbnNNalR0ZCcpOwogICAgICAgICAgICBUalR0ZC5ndGdkM1l4ZG5zTWpUdGQoJ2RUcmRsdWtUd3dUdENUd1RDJywgZHdZVCwgZHdZVCwgewogICAgICAgICAgICAgICAgVnVFVDZZczBUdzogZGJneC5WdUVUNllzMFR3CiAgICAgICAgICAgIH0pOwogICAgICAgICAgICBkYmd4LmRUcmRJdWtUd1Nnai5DZ3hWdWQ3Yk1qVHRkKFRqVHRkKTsKICAgICAgICB9LAogICAgICAgIHdUdENUd0l1a1R3OiBCWXQ3ZGdudCBIVHJkSXVrVHdGWWdsQ1R3X3dUdENUd0l1a1R3KCkgewogICAgICAgICAgICBqdXcgZFRyZEl1a1R3NXd1RSA9IENuN1lzVHRkLjd3VHVkVFNuN1lzVHRkNXd1RXNUdGQoKTsKICAgICAgICAgICAganV3IGRUcmRTZ2p4ID0gZGJneC5kVHJkU2dqeDsKICAgICAgICAgICAganV3IGRUcmRTZ2p4SVR0RWRiID0gZFRyZFNnangubFR0RWRiOwogICAgICAgICAgICBqdXcgN3V0anV4ID0gQ243WXNUdGQuN3dUdWRUTWxUc1R0ZCgnN3V0anV4Jyk7CiAgICAgICAgICAgIGp1dyA3ZHIgPSA3dXRqdXguRVRkM250ZFRyZCgnWkMnKTsKCiAgICAgICAgICAgIC8vIDZuIFZuZ3RkIGd0IHdUdENUd2d0RSBzdXRrIENnanggdXggZ2Qgb25ZbEMgc3VPVCBkYlQgMHdub3hUdwogICAgICAgICAgICAvLyBZdFl4dTBsVCBUalR0IHVCZFR3IGRiVCBDZ2p4IHV3VCB3VHRDVHdUQy4KICAgICAgICAgICAgZ0IgKGRUcmRTZ2p4SVR0RWRiID4gcUFKX0hNSkhfU2ZOUF9IOV9lTTZTTWUpIHsKICAgICAgICAgICAgICAgIGRiZ3guX0JndGd4YmVUdENUd2d0RSgpOwogICAgICAgICAgICAgICAgd1RkWXd0OwogICAgICAgICAgICB9CgogICAgICAgICAgICBqdXcgbHV4ZDVudGRQZ0dUOwogICAgICAgICAgICBqdXcgbHV4ZDVudGQ1dXNnbGs7CiAgICAgICAgICAgIEJudyAoanV3IGcgPSB2OyBnIDwgZFRyZFNnanhJVHRFZGI7IGcrKykgewogICAgICAgICAgICAgICAganV3IGRUcmRTZ2ogPSBkVHJkU2dqeFtnXTsKICAgICAgICAgICAgICAgIGdCIChkVHJkU2dqLkN1ZHV4VGQuZ3g4YmdkVHhWdTdUICE9PSBZdENUQmd0VEMpIHsKICAgICAgICAgICAgICAgICAgICA3bnRkZ3RZVDsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICBqdXcgQm50ZFBnR1QgPSBkVHJkU2dqLnhka2xULkJudGRQZ0dUOwogICAgICAgICAgICAgICAganV3IEJudGQ1dXNnbGsgPSBkVHJkU2dqLnhka2xULkJudGQ1dXNnbGs7CgogICAgICAgICAgICAgICAgLy8gOXRsayAwWWdsQyBCbnRkIHhkd2d0RSB1dEMgeFRkIGRuIDdudGRUcmQgZ0IgQ2dCQlR3VHRkIEJ3bnMgbHV4ZC4KICAgICAgICAgICAgICAgIGdCIChCbnRkUGdHVCAhPT0gbHV4ZDVudGRQZ0dUIHx8IEJudGQ1dXNnbGsgIT09IGx1eGQ1bnRkNXVzZ2xrKSB7CiAgICAgICAgICAgICAgICAgICAgN2RyLkJudGQgPSBCbnRkUGdHVCArICcgJyArIEJudGQ1dXNnbGs7CiAgICAgICAgICAgICAgICAgICAgbHV4ZDVudGRQZ0dUID0gQm50ZFBnR1Q7CiAgICAgICAgICAgICAgICAgICAgbHV4ZDVudGQ1dXNnbGsgPSBCbnRkNXVzZ2xrOwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIGp1dyBvZ0NkYiA9IDdkci5zVHV4WXdUSFRyZChkVHJkU2dqLmRUcmQzbnRkVHRkKS5vZ0NkYjsKICAgICAgICAgICAgICAgIGdCIChvZ0NkYiA+IHYpIHsKICAgICAgICAgICAgICAgICAgICBkVHJkSXVrVHc1d3VFLnVWVlR0QzNiZ2xDKGRUcmRTZ2opOwogICAgICAgICAgICAgICAgICAgIGp1dyBkd3V0eEJud3M7CiAgICAgICAgICAgICAgICAgICAgZ0IgKGRUcmRTZ2ouQ3VkdXhUZC43dXRqdXg4Z0NkYiAhPT0gWXRDVEJndFRDKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFN1ZHV4VGQganVsWVR4IDduc1QgbkIgZGtWVCB4ZHdndEUuCiAgICAgICAgICAgICAgICAgICAgICAgIGp1dyBkVHJkUDd1bFQgPSBkVHJkU2dqLkN1ZHV4VGQuN3V0anV4OGdDZGIgLyBvZ0NkYjsKICAgICAgICAgICAgICAgICAgICAgICAgZHd1dHhCbndzID0gJ3g3dWxUSignICsgZFRyZFA3dWxUICsgJyknOwogICAgICAgICAgICAgICAgICAgIH0gVGx4VCB7CiAgICAgICAgICAgICAgICAgICAgICAgIGR3dXR4Qm53cyA9ICcnOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBqdXcgd25kdWRnbnQgPSBkVHJkU2dqLkN1ZHV4VGQudXRFbFQ7CiAgICAgICAgICAgICAgICAgICAgZ0IgKHduZHVkZ250KSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGR3dXR4Qm53cyA9ICd3bmR1ZFQoJyArIHduZHVkZ250ICsgJ0NURSkgJyArIGR3dXR4Qm53czsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgZ0IgKGR3dXR4Qm53cykgewogICAgICAgICAgICAgICAgICAgICAgICAzWXhkbnNQZGtsVC54VGRLd25WKCdkd3V0eEJud3MnLCBkVHJkU2dqLCBkd3V0eEJud3MpOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQoKICAgICAgICAgICAgZGJneC5kVHJkSXVrVHdTZ2oudVZWVHRDM2JnbEMoZFRyZEl1a1R3NXd1RSk7CiAgICAgICAgICAgIGRiZ3guX0JndGd4YmVUdENUd2d0RSgpOwogICAgICAgICAgICBkYmd4LllWQ3VkVHF1ZDdiVHgoKTsKICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIGVUdENUd3ggZGJUIGRUcmQgbHVrVHcuCiAgICAgICAgICogQFZ1d3VzIHt0WXMwVHd9IGRnc1RuWWQgKG5WZGdudHVsKSBnQiB4VlQ3Z0JnVEMsIGRiVCB3VHRDVHdndEUgb3VnZHgKICAgICAgICAgKiAgIEJudyB4VlQ3Z0JnVEMgdXNuWXRkIG5CIHN4LgogICAgICAgICAqLwogICAgICAgIHdUdENUdzogQll0N2RnbnQgSFRyZEl1a1R3RllnbENUd193VHRDVHcoZGdzVG5ZZCkgewogICAgICAgICAgICBnQiAoIWRiZ3guQ2dqM250ZFR0ZFNudFQgfHwgZGJneC53VHRDVHdndEVTbnRUKSB7CiAgICAgICAgICAgICAgICB3VGRZd3Q7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGdCIChkYmd4LndUdENUd0hnc1R3KSB7CiAgICAgICAgICAgICAgICA3bFR1d0hnc1RuWWQoZGJneC53VHRDVHdIZ3NUdyk7CiAgICAgICAgICAgICAgICBkYmd4LndUdENUd0hnc1R3ID0gdFlsbDsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgZ0IgKCFkZ3NUbllkKSB7IC8vIGVUdENUdyB3Z0ViZCB1b3VrCiAgICAgICAgICAgICAgICBkYmd4LndUdENUd0l1a1R3KCk7CiAgICAgICAgICAgIH0gVGx4VCB7IC8vIFA3YlRDWWxUCiAgICAgICAgICAgICAgICBqdXcgeFRsQiA9IGRiZ3g7CiAgICAgICAgICAgICAgICBkYmd4LndUdENUd0hnc1R3ID0geFRkSGdzVG5ZZChCWXQ3ZGdudCAoKSB7CiAgICAgICAgICAgICAgICAgICAgeFRsQi53VHRDVHdJdWtUdygpOwogICAgICAgICAgICAgICAgICAgIHhUbEIud1R0Q1R3SGdzVHcgPSB0WWxsOwogICAgICAgICAgICAgICAgfSwgZGdzVG5ZZCk7CiAgICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIHVWVlR0Q0hUcmQ6IEJZdDdkZ250IEhUcmRJdWtUd0ZZZ2xDVHdfdVZWVHRDSFRyZChFVG5zLCB4ZGtsVHgpIHsKICAgICAgICAgICAganV3IHhka2xUID0geGRrbFR4W0VUbnMuQm50ZDZ1c1RdOwogICAgICAgICAgICBqdXcgZFRyZFNnaiA9IENuN1lzVHRkLjd3VHVkVE1sVHNUdGQoJ0NnaicpOwogICAgICAgICAgICBkYmd4LmRUcmRTZ2p4LlZZeGIoZFRyZFNnaik7CiAgICAgICAgICAgIGdCIChneEFsbDhiZ2RUeFZ1N1QoRVRucy54ZHcpKSB7CiAgICAgICAgICAgICAgICBkVHJkU2dqLkN1ZHV4VGQuZ3g4YmdkVHhWdTdUID0gZHdZVDsKICAgICAgICAgICAgICAgIHdUZFl3dDsKICAgICAgICAgICAgfQogICAgICAgICAgICBqdXcgZHIgPSBLUzV5UC5XZGdsLmR3dXR4Qm53cyhkYmd4LmpnVG9WbndkLmR3dXR4Qm53cywgRVRucy5kd3V0eEJud3MpOwogICAgICAgICAgICBqdXcgdXRFbFQgPSBxdWRiLnVkdXRaKGRyW3pdLCBkclt2XSk7CiAgICAgICAgICAgIGdCICh4ZGtsVC5qVHdkZzd1bCkgewogICAgICAgICAgICAgICAgdXRFbFQgKz0gcXVkYi5LZiAvIFo7CiAgICAgICAgICAgIH0KICAgICAgICAgICAganV3IEJudGQyVGdFYmQgPSBxdWRiLnhRd2QoKGRyW1pdICogZHJbWl0pICsgKGRyW21dICogZHJbbV0pKTsKICAgICAgICAgICAganV3IEJudGRBeDdUdGQgPSBCbnRkMlRnRWJkOwogICAgICAgICAgICBnQiAoeGRrbFQudXg3VHRkKSB7CiAgICAgICAgICAgICAgICBCbnRkQXg3VHRkID0geGRrbFQudXg3VHRkICogQm50ZEF4N1R0ZDsKICAgICAgICAgICAgfSBUbHhUIGdCICh4ZGtsVC5DVHg3VHRkKSB7CiAgICAgICAgICAgICAgICBCbnRkQXg3VHRkID0gKHogKyB4ZGtsVC5DVHg3VHRkKSAqIEJudGRBeDdUdGQ7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGp1dyBsVEJkOwogICAgICAgICAgICBqdXcgZG5WOwogICAgICAgICAgICBnQiAodXRFbFQgPT09IHYpIHsKICAgICAgICAgICAgICAgIGxUQmQgPSBkcltpXTsKICAgICAgICAgICAgICAgIGRuViA9IGRyW2NdIC0gQm50ZEF4N1R0ZDsKICAgICAgICAgICAgfSBUbHhUIHsKICAgICAgICAgICAgICAgIGxUQmQgPSBkcltpXSArIChCbnRkQXg3VHRkICogcXVkYi54Z3QodXRFbFQpKTsKICAgICAgICAgICAgICAgIGRuViA9IGRyW2NdIC0gKEJudGRBeDdUdGQgKiBxdWRiLjdueCh1dEVsVCkpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGRUcmRTZ2oueGRrbFQubFRCZCA9IGxUQmQgKyAnVnInOwogICAgICAgICAgICBkVHJkU2dqLnhka2xULmRuViA9IGRuViArICdWcic7CiAgICAgICAgICAgIGRUcmRTZ2oueGRrbFQuQm50ZFBnR1QgPSBCbnRkMlRnRWJkICsgJ1ZyJzsKICAgICAgICAgICAgZFRyZFNnai54ZGtsVC5CbnRkNXVzZ2xrID0geGRrbFQuQm50ZDV1c2dsazsKCiAgICAgICAgICAgIGRUcmRTZ2ouZFRyZDNudGRUdGQgPSBFVG5zLnhkdzsKICAgICAgICAgICAgLy8gfEJudGQ2dXNUfCBneCBudGxrIFl4VEMgMGsgZGJUIDVudGQgZnR4VlQ3ZG53LiBIYmd4IGRUeGQgb2dsbCB4WTc3VFRDCiAgICAgICAgICAgIC8vIG9iVHQgVC5FLiBkYlQgNW50ZCBmdHhWVDdkbncgZ3ggbkJCIDBZZCBkYlQgUGRUVlZUdyBneCBudCwgMFlkIGdkJ3gKICAgICAgICAgICAgLy8gdG5kIG9ud2RiIGRiVCBUQkJud2QgZG4gQ24gdSBzbndUIHU3N1l3dWRUIGRUeGQuCiAgICAgICAgICAgIGdCIChLUzV5UC5WQ0JGWUUpIHsKICAgICAgICAgICAgICAgIGRUcmRTZ2ouQ3VkdXhUZC5CbnRkNnVzVCA9IEVUbnMuQm50ZDZ1c1Q7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLy8gUGRud2d0RSBndGRuIEN1ZHV4VGQgb2dsbCA3bnRqVHdkIHRZczBUdyBndGRuIHhkd2d0RS4KICAgICAgICAgICAgZ0IgKHV0RWxUICE9PSB2KSB7CiAgICAgICAgICAgICAgICBkVHJkU2dqLkN1ZHV4VGQudXRFbFQgPSB1dEVsVCAqICh6VXYgLyBxdWRiLktmKTsKICAgICAgICAgICAgfQogICAgICAgICAgICAvLyA4VCBDbnQnZCAwbmRiVHcgeDd1bGd0RSB4Z3RFbFQtN2J1dyBkVHJkIENnangsIDBUN3VZeFQgZ2QgYnV4IGpUd2sKICAgICAgICAgICAgLy8gbGdkZGxUIFRCQlQ3ZCBudCBkVHJkIGJnRWJsZ0ViZGd0RS4gSGJneCBzdU9UeCB4N3dubGxndEUgbnQgQ243eCBvZ2RiCiAgICAgICAgICAgIC8vIGxuZHggbkIgeFk3YiBDZ2p4IHUgbG5kIEJ1eGRUdy4KICAgICAgICAgICAgZ0IgKEVUbnMueGR3LmxUdEVkYiA+IHopIHsKICAgICAgICAgICAgICAgIGdCICh4ZGtsVC5qVHdkZzd1bCkgewogICAgICAgICAgICAgICAgICAgIGRUcmRTZ2ouQ3VkdXhUZC43dXRqdXg4Z0NkYiA9IEVUbnMuYlRnRWJkICogZGJneC5qZ1RvVm53ZC54N3VsVDsKICAgICAgICAgICAgICAgIH0gVGx4VCB7CiAgICAgICAgICAgICAgICAgICAgZFRyZFNnai5DdWR1eFRkLjd1dGp1eDhnQ2RiID0gRVRucy5vZ0NkYiAqIGRiZ3guamdUb1Zud2QueDd1bFQ7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIHhUZEhUcmQzbnRkVHRkOiBCWXQ3ZGdudCBIVHJkSXVrVHdGWWdsQ1R3X3hUZEhUcmQzbnRkVHRkKGRUcmQzbnRkVHRkKSB7CiAgICAgICAgICAgIGRiZ3guZFRyZDNudGRUdGQgPSBkVHJkM250ZFR0ZDsKCiAgICAgICAgICAgIGp1dyBkVHJkZmRUc3ggPSBkVHJkM250ZFR0ZC5nZFRzeDsKICAgICAgICAgICAgQm53IChqdXcgZyA9IHYsIGxUdCA9IGRUcmRmZFRzeC5sVHRFZGI7IGcgPCBsVHQ7IGcrKykgewogICAgICAgICAgICAgICAgZGJneC51VlZUdENIVHJkKGRUcmRmZFRzeFtnXSwgZFRyZDNudGRUdGQueGRrbFR4KTsKICAgICAgICAgICAgfQogICAgICAgICAgICBkYmd4LkNnajNudGRUdGRTbnRUID0gZHdZVDsKICAgICAgICB9LAogICAgICAgIDdudGpUd2RxdWQ3YlR4OiBCWXQ3ZGdudCBIVHJkSXVrVHdGWWdsQ1R3XzdudGpUd2RxdWQ3YlR4KHN1ZDdiVHgpIHsKICAgICAgICAgICAganV3IGcgPSB2OwogICAgICAgICAgICBqdXcgZ2Z0Q1RyID0gdjsKICAgICAgICAgICAganV3IDBnQ2dIVHJkeCA9IGRiZ3guZFRyZDNudGRUdGQuZ2RUc3g7CiAgICAgICAgICAgIGp1dyBUdEMgPSAwZ0NnSFRyZHgubFR0RWRiIC0gejsKICAgICAgICAgICAganV3IFFZVHdrSVR0ID0gKGRiZ3guQmd0QzNudGR3bmxsVHcgPT09IHRZbGwgPwogICAgICAgICAgICAgICAgICAgIHYgOiBkYmd4LkJndEMzbnRkd25sbFR3LnhkdWRULlFZVHdrLmxUdEVkYik7CiAgICAgICAgICAgIGp1dyB3VGQgPSBbXTsKCiAgICAgICAgICAgIEJudyAoanV3IHMgPSB2LCBsVHQgPSBzdWQ3YlR4LmxUdEVkYjsgcyA8IGxUdDsgcysrKSB7CiAgICAgICAgICAgICAgICAvLyAzdWw3WWx1ZFQgZGJUIHhkdXdkIFZueGdkZ250LgogICAgICAgICAgICAgICAganV3IHN1ZDdiZkNyID0gc3VkN2JUeFtzXTsKCiAgICAgICAgICAgICAgICAvLyBJbm5WIG5qVHcgZGJUIENnamZDcnguCiAgICAgICAgICAgICAgICBvYmdsVCAoZyAhPT0gVHRDICYmIHN1ZDdiZkNyID49IChnZnRDVHIgKyAwZ0NnSFRyZHhbZ10ueGR3LmxUdEVkYikpIHsKICAgICAgICAgICAgICAgICAgICBnZnRDVHIgKz0gMGdDZ0hUcmR4W2ddLnhkdy5sVHRFZGI7CiAgICAgICAgICAgICAgICAgICAgZysrOwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIGdCIChnID09PSAwZ0NnSFRyZHgubFR0RWRiKSB7CiAgICAgICAgICAgICAgICAgICAgN250eG5sVC5Ud3dudygnM25ZbEMgdG5kIEJndEMgdSBzdWQ3Ymd0RSBzdVZWZ3RFJyk7CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAganV3IHN1ZDdiID0gewogICAgICAgICAgICAgICAgICAgIDBURWd0OiB7CiAgICAgICAgICAgICAgICAgICAgICAgIENnamZDcjogZywKICAgICAgICAgICAgICAgICAgICAgICAgbkJCeFRkOiBzdWQ3YmZDciAtIGdmdENUcgogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH07CgogICAgICAgICAgICAgICAgLy8gM3VsN1lsdWRUIGRiVCBUdEMgVm54Z2RnbnQuCiAgICAgICAgICAgICAgICBzdWQ3YmZDciArPSBRWVR3a0lUdDsKCiAgICAgICAgICAgICAgICAvLyBQbnNUb2J1ZCBkYlQgeHVzVCB1d3d1ayB1eCB1MG5qVCwgMFlkIFl4VCA+IGd0eGRUdUMgbkIgPj0gZG4gRVRkCiAgICAgICAgICAgICAgICAvLyBkYlQgVHRDIFZueGdkZ250IHdnRWJkLgogICAgICAgICAgICAgICAgb2JnbFQgKGcgIT09IFR0QyAmJiBzdWQ3YmZDciA+IChnZnRDVHIgKyAwZ0NnSFRyZHhbZ10ueGR3LmxUdEVkYikpIHsKICAgICAgICAgICAgICAgICAgICBnZnRDVHIgKz0gMGdDZ0hUcmR4W2ddLnhkdy5sVHRFZGI7CiAgICAgICAgICAgICAgICAgICAgZysrOwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIHN1ZDdiLlR0QyA9IHsKICAgICAgICAgICAgICAgICAgICBDZ2pmQ3I6IGcsCiAgICAgICAgICAgICAgICAgICAgbkJCeFRkOiBzdWQ3YmZDciAtIGdmdENUcgogICAgICAgICAgICAgICAgfTsKICAgICAgICAgICAgICAgIHdUZC5WWXhiKHN1ZDdiKTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgd1RkWXd0IHdUZDsKICAgICAgICB9LAogICAgICAgIHdUdENUd3F1ZDdiVHg6IEJZdDdkZ250IEhUcmRJdWtUd0ZZZ2xDVHdfd1R0Q1R3cXVkN2JUeChzdWQ3YlR4KSB7CiAgICAgICAgICAgIC8vIE11d2xrIFRyZ2QgZ0IgZGJUd1QgZ3ggdG5kYmd0RSBkbiB3VHRDVHcuCiAgICAgICAgICAgIGdCIChzdWQ3YlR4LmxUdEVkYiA9PT0gdikgewogICAgICAgICAgICAgICAgd1RkWXd0OwogICAgICAgICAgICB9CgogICAgICAgICAgICBqdXcgMGdDZ0hUcmR4ID0gZGJneC5kVHJkM250ZFR0ZC5nZFRzeDsKICAgICAgICAgICAganV3IGRUcmRTZ2p4ID0gZGJneC5kVHJkU2dqeDsKICAgICAgICAgICAganV3IFZ3VGpNdEMgPSB0WWxsOwogICAgICAgICAgICBqdXcgVnVFVGZDciA9IGRiZ3guVnVFVGZDcjsKICAgICAgICAgICAganV3IGd4UFRsVDdkVENLdUVUID0gKGRiZ3guQmd0QzNudGR3bmxsVHcgPT09IHRZbGwgPwogICAgICAgICAgICAgICAgICAgIEJ1bHhUIDogKFZ1RVRmQ3IgPT09IGRiZ3guQmd0QzNudGR3bmxsVHcueFRsVDdkVEMuVnVFVGZDcikpOwogICAgICAgICAgICBqdXcgeFRsVDdkVENxdWQ3YmZDciA9IChkYmd4LkJndEMzbnRkd25sbFR3ID09PSB0WWxsID8KICAgICAgICAgICAgICAgICAgICAteiA6IGRiZ3guQmd0QzNudGR3bmxsVHcueFRsVDdkVEMuc3VkN2JmQ3IpOwogICAgICAgICAgICBqdXcgYmdFYmxnRWJkQWxsID0gKGRiZ3guQmd0QzNudGR3bmxsVHcgPT09IHRZbGwgPwogICAgICAgICAgICAgICAgICAgIEJ1bHhUIDogZGJneC5CZ3RDM250ZHdubGxUdy54ZHVkVC5iZ0VibGdFYmRBbGwpOwogICAgICAgICAgICBqdXcgZ3RCZ3RnZGsgPSB7CiAgICAgICAgICAgICAgICBDZ2pmQ3I6IC16LAogICAgICAgICAgICAgICAgbkJCeFRkOiBZdENUQmd0VEMKICAgICAgICAgICAgfTsKCiAgICAgICAgICAgIEJZdDdkZ250IDBURWd0SFRyZCgwVEVndCwgN2x1eHg2dXNUKSB7CiAgICAgICAgICAgICAgICBqdXcgQ2dqZkNyID0gMFRFZ3QuQ2dqZkNyOwogICAgICAgICAgICAgICAgZFRyZFNnanhbQ2dqZkNyXS5kVHJkM250ZFR0ZCA9ICcnOwogICAgICAgICAgICAgICAgdVZWVHRDSFRyZEhuU2dqKENnamZDciwgdiwgMFRFZ3QubkJCeFRkLCA3bHV4eDZ1c1QpOwogICAgICAgICAgICB9CgogICAgICAgICAgICBCWXQ3ZGdudCB1VlZUdENIVHJkSG5TZ2ooQ2dqZkNyLCBCd25zOUJCeFRkLCBkbjlCQnhUZCwgN2x1eHg2dXNUKSB7CiAgICAgICAgICAgICAgICBqdXcgQ2dqID0gZFRyZFNnanhbQ2dqZkNyXTsKICAgICAgICAgICAgICAgIGp1dyA3bnRkVHRkID0gMGdDZ0hUcmR4W0NnamZDcl0ueGR3LnhZMHhkd2d0RShCd25zOUJCeFRkLCBkbjlCQnhUZCk7CiAgICAgICAgICAgICAgICBqdXcgdG5DVCA9IENuN1lzVHRkLjd3VHVkVEhUcmQ2bkNUKDdudGRUdGQpOwogICAgICAgICAgICAgICAgZ0IgKDdsdXh4NnVzVCkgewogICAgICAgICAgICAgICAgICAgIGp1dyB4VnV0ID0gQ243WXNUdGQuN3dUdWRUTWxUc1R0ZCgneFZ1dCcpOwogICAgICAgICAgICAgICAgICAgIHhWdXQuN2x1eHg2dXNUID0gN2x1eHg2dXNUOwogICAgICAgICAgICAgICAgICAgIHhWdXQudVZWVHRDM2JnbEModG5DVCk7CiAgICAgICAgICAgICAgICAgICAgQ2dqLnVWVlR0QzNiZ2xDKHhWdXQpOwogICAgICAgICAgICAgICAgICAgIHdUZFl3dDsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIENnai51VlZUdEMzYmdsQyh0bkNUKTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAganV3IGd2ID0geFRsVDdkVENxdWQ3YmZDciwgZ3ogPSBndiArIHo7CiAgICAgICAgICAgIGdCIChiZ0VibGdFYmRBbGwpIHsKICAgICAgICAgICAgICAgIGd2ID0gdjsKICAgICAgICAgICAgICAgIGd6ID0gc3VkN2JUeC5sVHRFZGI7CiAgICAgICAgICAgIH0gVGx4VCBnQiAoIWd4UFRsVDdkVENLdUVUKSB7CiAgICAgICAgICAgICAgICAvLyA2bmQgYmdFYmxnRWJkZ3RFIHVsbCB1dEMgZGJneCBneHQnZCBkYlQgeFRsVDdkVEMgVnVFVCwgeG4gQ24gdG5kYmd0RS4KICAgICAgICAgICAgICAgIHdUZFl3dDsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgQm53IChqdXcgZyA9IGd2OyBnIDwgZ3o7IGcrKykgewogICAgICAgICAgICAgICAganV3IHN1ZDdiID0gc3VkN2JUeFtnXTsKICAgICAgICAgICAgICAgIGp1dyAwVEVndCA9IHN1ZDdiLjBURWd0OwogICAgICAgICAgICAgICAganV3IFR0QyA9IHN1ZDdiLlR0QzsKICAgICAgICAgICAgICAgIGp1dyBneFBUbFQ3ZFRDID0gKGd4UFRsVDdkVENLdUVUICYmIGcgPT09IHhUbFQ3ZFRDcXVkN2JmQ3IpOwogICAgICAgICAgICAgICAganV3IGJnRWJsZ0ViZFBZQkJnciA9IChneFBUbFQ3ZFRDID8gJyB4VGxUN2RUQycgOiAnJyk7CgogICAgICAgICAgICAgICAgZ0IgKGRiZ3guQmd0QzNudGR3bmxsVHcpIHsKICAgICAgICAgICAgICAgICAgICBkYmd4LkJndEMzbnRkd25sbFR3LllWQ3VkVHF1ZDdiS254Z2RnbnQoVnVFVGZDciwgZywgZFRyZFNnangsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAwVEVndC5DZ2pmQ3IsIFR0Qy5DZ2pmQ3IpOwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIC8vIHF1ZDdiIGd0eGdDVCB0VG8gQ2dqLgogICAgICAgICAgICAgICAgZ0IgKCFWd1RqTXRDIHx8IDBURWd0LkNnamZDciAhPT0gVndUak10Qy5DZ2pmQ3IpIHsKICAgICAgICAgICAgICAgICAgICAvLyBmQiBkYlR3VCBvdXggdSBWd1RqZ25ZeCBDZ2osIGRiVHQgdUNDIGRiVCBkVHJkIHVkIGRiVCBUdEMuCiAgICAgICAgICAgICAgICAgICAgZ0IgKFZ3VGpNdEMgIT09IHRZbGwpIHsKICAgICAgICAgICAgICAgICAgICAgICAgdVZWVHRDSFRyZEhuU2dqKFZ3VGpNdEMuQ2dqZkNyLCBWd1RqTXRDLm5CQnhUZCwgZ3RCZ3RnZGsubkJCeFRkKTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgLy8gM2xUdXcgZGJUIENnanggdXRDIHhUZCBkYlQgN250ZFR0ZCBZdGRnbCBkYlQgeGR1d2RndEUgVm5ndGQuCiAgICAgICAgICAgICAgICAgICAgMFRFZ3RIVHJkKDBURWd0KTsKICAgICAgICAgICAgICAgIH0gVGx4VCB7CiAgICAgICAgICAgICAgICAgICAgdVZWVHRDSFRyZEhuU2dqKFZ3VGpNdEMuQ2dqZkNyLCBWd1RqTXRDLm5CQnhUZCwgMFRFZ3QubkJCeFRkKTsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICBnQiAoMFRFZ3QuQ2dqZkNyID09PSBUdEMuQ2dqZkNyKSB7CiAgICAgICAgICAgICAgICAgICAgdVZWVHRDSFRyZEhuU2dqKDBURWd0LkNnamZDciwgMFRFZ3QubkJCeFRkLCBUdEMubkJCeFRkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgJ2JnRWJsZ0ViZCcgKyBiZ0VibGdFYmRQWUJCZ3IpOwogICAgICAgICAgICAgICAgfSBUbHhUIHsKICAgICAgICAgICAgICAgICAgICB1VlZUdENIVHJkSG5TZ2ooMFRFZ3QuQ2dqZkNyLCAwVEVndC5uQkJ4VGQsIGd0Qmd0Z2RrLm5CQnhUZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICdiZ0VibGdFYmQgMFRFZ3QnICsgYmdFYmxnRWJkUFlCQmdyKTsKICAgICAgICAgICAgICAgICAgICBCbncgKGp1dyB0diA9IDBURWd0LkNnamZDciArIHosIHR6ID0gVHRDLkNnamZDcjsgdHYgPCB0ejsgdHYrKykgewogICAgICAgICAgICAgICAgICAgICAgICBkVHJkU2dqeFt0dl0uN2x1eHg2dXNUID0gJ2JnRWJsZ0ViZCBzZ0NDbFQnICsgYmdFYmxnRWJkUFlCQmdyOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAwVEVndEhUcmQoVHRDLCAnYmdFYmxnRWJkIFR0QycgKyBiZ0VibGdFYmRQWUJCZ3IpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgVndUak10QyA9IFR0QzsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgZ0IgKFZ3VGpNdEMpIHsKICAgICAgICAgICAgICAgIHVWVlR0Q0hUcmRIblNnaihWd1RqTXRDLkNnamZDciwgVndUak10Qy5uQkJ4VGQsIGd0Qmd0Z2RrLm5CQnhUZCk7CiAgICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIFlWQ3VkVHF1ZDdiVHg6IEJZdDdkZ250IEhUcmRJdWtUd0ZZZ2xDVHdfWVZDdWRUcXVkN2JUeCgpIHsKICAgICAgICAgICAgLy8gOXRsayB4Ym5vIHN1ZDdiVHggb2JUdCB1bGwgd1R0Q1R3Z3RFIGd4IENudFQuCiAgICAgICAgICAgIGdCICghZGJneC53VHRDVHdndEVTbnRUKSB7CiAgICAgICAgICAgICAgICB3VGRZd3Q7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIC8vIDNsVHV3IHVsbCBzdWQ3YlR4LgogICAgICAgICAgICBqdXcgc3VkN2JUeCA9IGRiZ3guc3VkN2JUeDsKICAgICAgICAgICAganV3IGRUcmRTZ2p4ID0gZGJneC5kVHJkU2dqeDsKICAgICAgICAgICAganV3IDBnQ2dIVHJkeCA9IGRiZ3guZFRyZDNudGRUdGQuZ2RUc3g7CiAgICAgICAgICAgIGp1dyA3bFR1d1RDV3RkZ2xTZ2pmQ3IgPSAtejsKCiAgICAgICAgICAgIC8vIDNsVHV3IHVsbCA3WXd3VHRkIHN1ZDdiVHguCiAgICAgICAgICAgIEJudyAoanV3IGcgPSB2LCBsVHQgPSBzdWQ3YlR4LmxUdEVkYjsgZyA8IGxUdDsgZysrKSB7CiAgICAgICAgICAgICAgICBqdXcgc3VkN2IgPSBzdWQ3YlR4W2ddOwogICAgICAgICAgICAgICAganV3IDBURWd0ID0gcXVkYi5zdXIoN2xUdXdUQ1d0ZGdsU2dqZkNyLCBzdWQ3Yi4wVEVndC5DZ2pmQ3IpOwogICAgICAgICAgICAgICAgQm53IChqdXcgdCA9IDBURWd0LCBUdEMgPSBzdWQ3Yi5UdEMuQ2dqZkNyOyB0IDw9IFR0QzsgdCsrKSB7CiAgICAgICAgICAgICAgICAgICAganV3IENnaiA9IGRUcmRTZ2p4W3RdOwogICAgICAgICAgICAgICAgICAgIENnai5kVHJkM250ZFR0ZCA9IDBnQ2dIVHJkeFt0XS54ZHc7CiAgICAgICAgICAgICAgICAgICAgQ2dqLjdsdXh4NnVzVCA9ICcnOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgN2xUdXdUQ1d0ZGdsU2dqZkNyID0gc3VkN2IuVHRDLkNnamZDciArIHo7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGdCIChkYmd4LkJndEMzbnRkd25sbFR3ID09PSB0WWxsIHx8ICFkYmd4LkJndEMzbnRkd25sbFR3LnU3ZGdqVCkgewogICAgICAgICAgICAgICAgd1RkWXd0OwogICAgICAgICAgICB9CgogICAgICAgICAgICAvLyAzbnRqVHdkIGRiVCBzdWQ3YlR4IG50IGRiVCBWdUVUIDdudGR3bmxsVHcgZ3RkbiBkYlQgc3VkN2IgQm53c3VkCiAgICAgICAgICAgIC8vIFl4VEMgQm53IGRiVCBkVHJkSXVrVHcuCiAgICAgICAgICAgIGRiZ3guc3VkN2JUeCA9IGRiZ3guN250alR3ZHF1ZDdiVHgoZGJneC5CZ3RDM250ZHdubGxUdyA9PT0gdFlsbCA/CiAgICAgICAgICAgICAgICAgICAgW10gOiAoZGJneC5CZ3RDM250ZHdubGxUdy5WdUVUcXVkN2JUeFtkYmd4LlZ1RVRmQ3JdIHx8IFtdKSk7CiAgICAgICAgICAgIGRiZ3gud1R0Q1R3cXVkN2JUeChkYmd4LnN1ZDdiVHgpOwogICAgICAgIH0KICAgIH07CiAgICB3VGRZd3QgSFRyZEl1a1R3RllnbENUdzsKfSkoKTsKCi8qKgogKiBAN250eGR3WTdkbncKICogQGdzVmxUc1R0ZHggZktTNUhUcmRJdWtUdzV1N2Rud2sKICovCkJZdDdkZ250IFNUQnVZbGRIVHJkSXVrVHc1dTdkbndrKCkge30KU1RCdVlsZEhUcmRJdWtUdzV1N2Rud2suVnduZG5ka1ZUID0gewogICAgLyoqCiAgICAgKiBAVnV3dXMgezJIcUlTZ2pNbFRzVHRkfSBkVHJkSXVrVHdTZ2oKICAgICAqIEBWdXd1cyB7dFlzMFR3fSBWdUVUZnRDVHIKICAgICAqIEBWdXd1cyB7S3VFVE5nVG9WbndkfSBqZ1RvVm53ZAogICAgICogQHdUZFl3dHgge0hUcmRJdWtUd0ZZZ2xDVHd9CiAgICAgKi8KICAgIDd3VHVkVEhUcmRJdWtUd0ZZZ2xDVHc6IEJZdDdkZ250IChkVHJkSXVrVHdTZ2osIFZ1RVRmdENUciwgamdUb1Zud2QpIHsKICAgICAgICB3VGRZd3QgdFRvIEhUcmRJdWtUd0ZZZ2xDVHcoewogICAgICAgICAgICBkVHJkSXVrVHdTZ2o6IGRUcmRJdWtUd1NnaiwKICAgICAgICAgICAgVnVFVGZ0Q1RyOiBWdUVUZnRDVHIsCiAgICAgICAgICAgIGpnVG9WbndkOiBqZ1RvVm53ZAogICAgICAgIH0pOwogICAgfQp9OwoKCi8qKgogKiBAZGtWVENUQiB7OTAxVDdkfSBBdHRuZHVkZ250eEl1a1R3RllnbENUdzlWZGdudHgKICogQFZ3blZUd2RrIHsySHFJU2dqTWxUc1R0ZH0gVnVFVFNnagogKiBAVnduVlR3ZGsge0tTNUt1RVR9IFZDQkt1RVQKICogQFZ3blZUd2RrIHtmS1M1SWd0T1BUd2pnN1R9IGxndE9QVHdqZzdUCiAqLwoKLyoqCiAqIEA3bHV4eAogKi8KanV3IEF0dG5kdWRnbnR4SXVrVHdGWWdsQ1R3ID0gKEJZdDdkZ250IEF0dG5kdWRnbnR4SXVrVHdGWWdsQ1R3M2xueFl3VCgpIHsKICAgIC8qKgogICAgICogQFZ1d3VzIHtBdHRuZHVkZ250eEl1a1R3RllnbENUdzlWZGdudHh9IG5WZGdudHgKICAgICAqIEA3bnR4ZHdZN2R4IEF0dG5kdWRnbnR4SXVrVHdGWWdsQ1R3CiAgICAgKi8KICAgIEJZdDdkZ250IEF0dG5kdWRnbnR4SXVrVHdGWWdsQ1R3KG5WZGdudHgpIHsKICAgICAgICBkYmd4LlZ1RVRTZ2ogPSBuVmRnbnR4LlZ1RVRTZ2o7CiAgICAgICAgZGJneC5WQ0JLdUVUID0gblZkZ250eC5WQ0JLdUVUOwogICAgICAgIGRiZ3gubGd0T1BUd2pnN1QgPSBuVmRnbnR4LmxndE9QVHdqZzdUOwoKICAgICAgICBkYmd4LkNnaiA9IHRZbGw7CiAgICB9CiAgICBBdHRuZHVkZ250eEl1a1R3RllnbENUdy5Wd25kbmRrVlQgPQogICAgICAgICAgICAvKiogQGxUdEN4IEF0dG5kdWRnbnR4SXVrVHdGWWdsQ1R3LlZ3bmRuZGtWVCAqLyB7CiAgICAgICAgICAgICAgICAvKioKICAgICAgICAgICAgICAgICAqIEBWdXd1cyB7S3VFVE5nVG9WbndkfSBqZ1RvVm53ZAogICAgICAgICAgICAgICAgICovCiAgICAgICAgICAgICAgICB4VGRZVkF0dG5kdWRnbnR4OgogICAgICAgICAgICAgICAgICAgICAgICBCWXQ3ZGdudCBBdHRuZHVkZ250eEl1a1R3RllnbENUd194VGRZVkF0dG5kdWRnbnR4KGpnVG9WbndkKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBCWXQ3ZGdudCAwZ3RDSWd0TyhsZ3RPLCBDVHhkKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGd0Ty5id1RCID0gbGd0T1BUd2pnN1QuRVRkU1R4ZGd0dWRnbnQydXhiKENUeGQpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxndE8ubnQ3bGc3TyA9IEJZdDdkZ250IHV0dG5kdWRnbnR4SXVrVHdGWWdsQ1R3SWd0T3g5dDdsZzdPKCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnQiAoQ1R4ZCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGd0T1BUd2pnN1QudHVqZ0V1ZFRIbihDVHhkKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3VGRZd3QgQnVseFQ7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnQiAoQ1R4ZCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZ3RPLjdsdXh4NnVzVCA9ICdndGRUd3R1bElndE8nOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBCWXQ3ZGdudCAwZ3RDNnVzVENBN2RnbnQobGd0TywgdTdkZ250KSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGd0Ty5id1RCID0gbGd0T1BUd2pnN1QuRVRkQXQ3Ym53V3dsKCcnKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZ3RPLm50N2xnN08gPSBCWXQ3ZGdudCB1dHRuZHVkZ250eEl1a1R3RllnbENUdzZ1c1RDQTdkZ250OXQzbGc3TygpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGd0T1BUd2pnN1QuVHJUN1lkVDZ1c1RDQTdkZ250KHU3ZGdudCk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdUZFl3dCBCdWx4VDsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9OwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxndE8uN2x1eHg2dXNUID0gJ2d0ZFR3dHVsSWd0Tyc7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICAgICAganV3IGxndE9QVHdqZzdUID0gZGJneC5sZ3RPUFR3amc3VDsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGp1dyBWQ0JLdUVUID0gZGJneC5WQ0JLdUVUOwogICAgICAgICAgICAgICAgICAgICAgICAgICAganV3IHhUbEIgPSBkYmd4OwoKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFZDQkt1RVQuRVRkQXR0bmR1ZGdudHgoKS5kYlR0KEJZdDdkZ250ICh1dHRuZHVkZ250eFN1ZHUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBqZ1RvVm53ZCA9IGpnVG9WbndkLjdsbnRUKHtDbnRkNWxnVjogZHdZVH0pOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGp1dyBkd3V0eEJud3MgPSBqZ1RvVm53ZC5kd3V0eEJud3M7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAganV3IGR3dXR4Qm53c1BkdyA9ICdzdWR3Z3IoJyArIGR3dXR4Qm53cy4xbmd0KCcsJykgKyAnKSc7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAganV3IEN1ZHUsIFRsVHNUdGQsIGcsIGdnOwoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnQiAoeFRsQi5DZ2opIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gZkIgdXQgdXR0bmR1ZGdudEl1a1R3IHVsd1R1Q2sgVHJneGR4LCB3VEJ3VHhiIGdkeCA3YmdsQ3dUdCd4CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGR3dXR4Qm53c3VkZ250IHN1ZHdnN1R4CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEJudyAoZyA9IHYsIGdnID0gdXR0bmR1ZGdudHhTdWR1LmxUdEVkYjsgZyA8IGdnOyBnKyspIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEN1ZHUgPSB1dHRuZHVkZ250eFN1ZHVbZ107CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUbFRzVHRkID0geFRsQi5DZ2ouUVlUd2tQVGxUN2RudygKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1tDdWR1LXV0dG5kdWRnbnQtZ0M9IicgKyBDdWR1LmdDICsgJyJdJyk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnQiAoVGxUc1R0ZCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDNZeGRuc1Bka2xULnhUZEt3blYoJ2R3dXR4Qm53cycsIFRsVHNUdGQsIGR3dXR4Qm53c1Bkdyk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gUFRUIEtTNUt1RVROZ1RvLndUeFRkKCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeFRsQi5DZ2oud1RzbmpUQWRkd2cwWWRUKCdiZ0NDVHQnKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IFRseFQgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBCbncgKGcgPSB2LCBnZyA9IHV0dG5kdWRnbnR4U3VkdS5sVHRFZGI7IGcgPCBnZzsgZysrKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDdWR1ID0gdXR0bmR1ZGdudHhTdWR1W2ddOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ0IgKCFDdWR1IHx8ICFDdWR1LmJ1eDJkc2wpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA3bnRkZ3RZVDsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUbFRzVHRkID0gS1M1eVAuQXR0bmR1ZGdudFdkZ2x4LkVUZDJkc2xNbFRzVHRkKEN1ZHUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFZDQkt1RVQuN25zc250OTAxeCk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUbFRzVHRkLnhUZEFkZHdnMFlkVCgnQ3VkdS11dHRuZHVkZ250LWdDJywgQ3VkdS5nQyk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnQiAoZGtWVG5CIHNuR0l6dnQgIT09ICdZdENUQmd0VEMnKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc25HSXp2dC5kd3V0eGx1ZFQoVGxUc1R0ZCk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAganV3IHdUN2QgPSBDdWR1LndUN2Q7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBqdXcgamdUbyA9IFZDQkt1RVQuamdUbzsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdUN2QgPSBLUzV5UC5XZGdsLnRud3N1bGdHVGVUN2QoWwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdUN2Rbdl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgamdUb1ttXSAtIHdUN2Rbel0gKyBqZ1RvW3pdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdUN2RbWl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgamdUb1ttXSAtIHdUN2RbbV0gKyBqZ1RvW3pdCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBdKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRsVHNUdGQueGRrbFQubFRCZCA9IHdUN2Rbdl0gKyAnVnInOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVGxUc1R0ZC54ZGtsVC5kblYgPSB3VDdkW3pdICsgJ1ZyJzsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRsVHNUdGQueGRrbFQuVm54Z2RnbnQgPSAndTB4bmxZZFQnOwoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDNZeGRuc1Bka2xULnhUZEt3blYoJ2R3dXR4Qm53cycsIFRsVHNUdGQsIGR3dXR4Qm53c1Bkdyk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBqdXcgZHd1dHhCbndzOXdnRWd0UGR3ID0gLXdUN2Rbdl0gKyAnVnIgJyArIC13VDdkW3pdICsgJ1ZyJzsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDNZeGRuc1Bka2xULnhUZEt3blYoJ2R3dXR4Qm53czl3Z0VndCcsIFRsVHNUdGQsIGR3dXR4Qm53czl3Z0VndFBkdyk7CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ0IgKEN1ZHUueFkwZGtWVCA9PT0gJ0lndE8nICYmICFDdWR1Lll3bCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGp1dyBsZ3RPID0gVGxUc1R0ZC5FVGRNbFRzVHRkeEZrSHVFNnVzVCgndScpW3ZdOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdCIChsZ3RPKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdCIChDdWR1LnU3ZGdudCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMGd0QzZ1c1RDQTdkZ250KGxndE8sIEN1ZHUudTdkZ250KTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSBUbHhUIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDBndENJZ3RPKGxndE8sICgnQ1R4ZCcgZ3QgQ3VkdSkgPyBDdWR1LkNUeGQgOiB0WWxsKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnQiAoIXhUbEIuQ2dqKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAganV3IHV0dG5kdWRnbnRJdWtUd1NnaiA9IENuN1lzVHRkLjd3VHVkVE1sVHNUdGQoJ0NnaicpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHV0dG5kdWRnbnRJdWtUd1Nnai43bHV4eDZ1c1QgPSAndXR0bmR1ZGdudEl1a1R3JzsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4VGxCLlZ1RVRTZ2oudVZWVHRDM2JnbEModXR0bmR1ZGdudEl1a1R3U2dqKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4VGxCLkNnaiA9IHV0dG5kdWRnbnRJdWtUd1NnajsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4VGxCLkNnai51VlZUdEMzYmdsQyhUbFRzVHRkKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAgYmdDVDogQll0N2RnbnQgKCkgewogICAgICAgICAgICAgICAgICAgIGdCICghZGJneC5DZ2opIHsKICAgICAgICAgICAgICAgICAgICAgICAgd1RkWXd0OwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBkYmd4LkNnai54VGRBZGR3ZzBZZFQoJ2JnQ0NUdCcsICdkd1lUJyk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH07CiAgICB3VGRZd3QgQXR0bmR1ZGdudHhJdWtUd0ZZZ2xDVHc7Cn0pKCk7CgovKioKICogQDdudHhkd1k3ZG53CiAqIEBnc1ZsVHNUdGR4IGZLUzVBdHRuZHVkZ250eEl1a1R3NXU3ZG53awogKi8KQll0N2RnbnQgU1RCdVlsZEF0dG5kdWRnbnR4SXVrVHc1dTdkbndrKCkge30KU1RCdVlsZEF0dG5kdWRnbnR4SXVrVHc1dTdkbndrLlZ3bmRuZGtWVCA9IHsKICAgIC8qKgogICAgICogQFZ1d3VzIHsySHFJU2dqTWxUc1R0ZH0gVnVFVFNnagogICAgICogQFZ1d3VzIHtLUzVLdUVUfSBWQ0JLdUVUCiAgICAgKiBAd1RkWXd0eCB7QXR0bmR1ZGdudHhJdWtUd0ZZZ2xDVHd9CiAgICAgKi8KICAgIDd3VHVkVEF0dG5kdWRnbnR4SXVrVHdGWWdsQ1R3OiBCWXQ3ZGdudCAoVnVFVFNnaiwgVkNCS3VFVCkgewogICAgICAgIHdUZFl3dCB0VG8gQXR0bmR1ZGdudHhJdWtUd0ZZZ2xDVHcoewogICAgICAgICAgICBWdUVUU2dqOiBWdUVUU2dqLAogICAgICAgICAgICBWQ0JLdUVUOiBWQ0JLdUVULAogICAgICAgICAgICBsZ3RPUFR3amc3VDogdFRvIFBnc1ZsVElndE9QVHdqZzdUKCksCiAgICAgICAgfSk7CiAgICB9Cn07CgoKLyoqCiAqIEBka1ZUQ1RCIHs5MDFUN2R9IEtTNU5nVG9UdzlWZGdudHgKICogQFZ3blZUd2RrIHsySHFJU2dqTWxUc1R0ZH0gN250ZHVndFR3IC0gSGJUIDdudGR1Z3RUdyBCbncgZGJUIGpnVG9UdyBUbFRzVHRkLgogKiBAVnduVlR3ZGsgezJIcUlTZ2pNbFRzVHRkfSBqZ1RvVHcgLSAoblZkZ250dWwpIEhiVCBqZ1RvVHcgVGxUc1R0ZC4KICogQFZ3blZUd2RrIHtmS1M1SWd0T1BUd2pnN1R9IGxndE9QVHdqZzdUIC0gSGJUIHR1amdFdWRnbnQvbGd0T2d0RSB4VHdqZzdULgogKiBAVnduVlR3ZGsge0tTNWVUdENUd2d0RWhZVFlUfSB3VHRDVHdndEVoWVRZVCAtIChuVmRnbnR1bCkgSGJUIHdUdENUd2d0RQogKiAgIFFZVFlUIG4wMVQ3ZC4KICogQFZ3blZUd2RrIHswbm5sVHV0fSB3VHNualRLdUVURm53Q1R3eCAtIChuVmRnbnR1bCkgZVRzbmpUeCBkYlQgMG53Q1R3IHhidUNubwogKiAgIHV3bll0QyBkYlQgVnVFVHguIEhiVCBDVEJ1WWxkIGd4IEJ1bHhULgogKi8KCi8qKgogKiBQZ3NWbFQgamdUb1R3IDdudGR3bmwgZG4gQ2d4Vmx1ayBLUzUgN250ZFR0ZC9WdUVUeC4KICogQDdsdXh4CiAqIEBnc1ZsVHNUdGR4IHtmZVR0Q1R3dTBsVE5nVG99CiAqLwpqdXcgS1M1TmdUb1R3ID0gKEJZdDdkZ250IFZDQk5nVG9UdygpIHsKICAgIEJZdDdkZ250IEtTNUt1RVROZ1RvRllCQlR3KHhnR1QpIHsKICAgICAgICBqdXcgQ3VkdSA9IFtdOwogICAgICAgIGRiZ3guVll4YiA9IEJZdDdkZ250IDd1N2JUS1l4YihqZ1RvKSB7CiAgICAgICAgICAgIGp1dyBnID0gQ3VkdS5ndENUcjlCKGpnVG8pOwogICAgICAgICAgICBnQiAoZyA+PSB2KSB7CiAgICAgICAgICAgICAgICBDdWR1LnhWbGc3VChnLCB6KTsKICAgICAgICAgICAgfQogICAgICAgICAgICBDdWR1LlZZeGIoamdUbyk7CiAgICAgICAgICAgIGdCIChDdWR1LmxUdEVkYiA+IHhnR1QpIHsKICAgICAgICAgICAgICAgIEN1ZHUueGJnQmQoKS5DVHhkd25rKCk7CiAgICAgICAgICAgIH0KICAgICAgICB9OwogICAgICAgIGRiZ3gud1R4Z0dUID0gQll0N2RnbnQgKHRUb1BnR1QpIHsKICAgICAgICAgICAgeGdHVCA9IHRUb1BnR1Q7CiAgICAgICAgICAgIG9iZ2xUIChDdWR1LmxUdEVkYiA+IHhnR1QpIHsKICAgICAgICAgICAgICAgIEN1ZHUueGJnQmQoKS5DVHhkd25rKCk7CiAgICAgICAgICAgIH0KICAgICAgICB9OwogICAgfQoKICAgIEJZdDdkZ250IGd4UHVzVFA3dWxUKG5sQ1A3dWxULCB0VG9QN3VsVCkgewogICAgICAgIGdCICh0VG9QN3VsVCA9PT0gbmxDUDd1bFQpIHsKICAgICAgICAgICAgd1RkWXd0IGR3WVQ7CiAgICAgICAgfQogICAgICAgIGdCIChxdWRiLnUweCh0VG9QN3VsVCAtIG5sQ1A3dWxUKSA8IHpULXpjKSB7CiAgICAgICAgICAgIC8vIEt3VGpUdGQgWXR0VDdUeHh1d2sgd1Qtd1R0Q1R3Z3RFIG5CIHVsbCBWdUVUeCBvYlR0IGRiVCB4N3VsVAogICAgICAgICAgICAvLyA3YnV0RVR4IG50bGsgMFQ3dVl4VCBuQiBsZ3NnZFRDIHRZc1R3Zzd1bCBWd1Q3Z3hnbnQuCiAgICAgICAgICAgIHdUZFl3dCBkd1lUOwogICAgICAgIH0KICAgICAgICB3VGRZd3QgQnVseFQ7CiAgICB9CgogICAgLyoqCiAgICAgKiBAN250eGR3WTdkeCBLUzVOZ1RvVHcKICAgICAqIEBWdXd1cyB7S1M1TmdUb1R3OVZkZ250eH0gblZkZ250eAogICAgICovCiAgICBCWXQ3ZGdudCBLUzVOZ1RvVHcoblZkZ250eCkgewogICAgICAgIGRiZ3guN250ZHVndFR3ID0gblZkZ250eC43bnRkdWd0VHc7CiAgICAgICAgZGJneC5qZ1RvVHcgPSBuVmRnbnR4LmpnVG9UdyB8fCBuVmRnbnR4LjdudGR1Z3RUdy5CZ3d4ZE1sVHNUdGQzYmdsQzsKICAgICAgICBkYmd4LmxndE9QVHdqZzdUID0gblZkZ250eC5sZ3RPUFR3amc3VCB8fCB0VG8gUGdzVmxUSWd0T1BUd2pnN1QoKTsKICAgICAgICBkYmd4LndUc25qVEt1RVRGbndDVHd4ID0gblZkZ250eC53VHNualRLdUVURm53Q1R3eCB8fCBCdWx4VDsKICAgICAgICBkYmd4LkNUQnVZbGRlVHRDVHdndEVoWVRZVCA9ICFuVmRnbnR4LndUdENUd2d0RWhZVFlUOwogICAgICAgIGdCIChkYmd4LkNUQnVZbGRlVHRDVHdndEVoWVRZVCkgewogICAgICAgICAgICAvLyAzWXhkbnMgd1R0Q1R3Z3RFIFFZVFlUIGd4IHRuZCB4VlQ3Z0JnVEMsIFl4Z3RFIENUQnVZbGQgbnRUCiAgICAgICAgICAgIGRiZ3gud1R0Q1R3Z3RFaFlUWVQgPSB0VG8gS1M1ZVR0Q1R3Z3RFaFlUWVQoKTsKICAgICAgICAgICAgZGJneC53VHRDVHdndEVoWVRZVC54VGROZ1RvVHcoZGJneCk7CiAgICAgICAgfSBUbHhUIHsKICAgICAgICAgICAgZGJneC53VHRDVHdndEVoWVRZVCA9IG5WZGdudHgud1R0Q1R3Z3RFaFlUWVQ7CiAgICAgICAgfQoKICAgICAgICBkYmd4Lng3d25sbCA9IG91ZDdiUDd3bmxsKGRiZ3guN250ZHVndFR3LCBkYmd4Ll94N3dubGxXVkN1ZFQuMGd0QyhkYmd4KSk7CiAgICAgICAgZGJneC5ZVkN1ZFRmdEt3bkV3VHh4ID0gQnVseFQ7CiAgICAgICAgZGJneC5Wd1R4VHRkdWRnbnRxbkNUUGR1ZFQgPSBLd1R4VHRkdWRnbnRxbkNUUGR1ZFQuVzZSNjk4NjsKICAgICAgICBkYmd4Ll93VHhUZE5nVG8oKTsKCiAgICAgICAgZ0IgKGRiZ3gud1RzbmpUS3VFVEZud0NUd3gpIHsKICAgICAgICAgICAgZGJneC5qZ1RvVHcuN2x1eHhJZ3hkLnVDQygnd1RzbmpUS3VFVEZud0NUd3gnKTsKICAgICAgICB9CiAgICB9CgogICAgS1M1TmdUb1R3LlZ3bmRuZGtWVCA9IC8qKiBAbFR0Q3ggS1M1TmdUb1R3LlZ3bmRuZGtWVCAqL3sKICAgICAgICBFVGQgVnVFVHgzbll0ZCgpIHsKICAgICAgICAgICAgd1RkWXd0IGRiZ3guX1Z1RVR4LmxUdEVkYjsKICAgICAgICB9LAogICAgICAgIEVUZEt1RVROZ1RvOiBCWXQ3ZGdudCAoZ3RDVHIpIHsKICAgICAgICAgICAgd1RkWXd0IGRiZ3guX1Z1RVR4W2d0Q1RyXTsKICAgICAgICB9LAogICAgICAgIEVUZCA3WXd3VHRkS3VFVDZZczBUdygpIHsKICAgICAgICAgICAgd1RkWXd0IGRiZ3guXzdZd3dUdGRLdUVUNllzMFR3OwogICAgICAgIH0sCiAgICAgICAgeFRkIDdZd3dUdGRLdUVUNllzMFR3KGp1bCkgewogICAgICAgICAgICBnQiAoIWRiZ3guVkNCU243WXNUdGQpIHsKICAgICAgICAgICAgICAgIGRiZ3guXzdZd3dUdGRLdUVUNllzMFR3ID0ganVsOwogICAgICAgICAgICAgICAgd1RkWXd0OwogICAgICAgICAgICB9CgogICAgICAgICAgICBqdXcgVGpUdGQgPSBDbjdZc1R0ZC43d1R1ZFRNalR0ZCgnV2ZNalR0ZHgnKTsKICAgICAgICAgICAgVGpUdGQuZ3RnZFdmTWpUdGQoJ1Z1RVQ3YnV0RVQnLCBkd1lULCBkd1lULCBvZ3RDbm8sIHYpOwogICAgICAgICAgICBUalR0ZC5ZVkN1ZFRmdEt3bkV3VHh4ID0gZGJneC5ZVkN1ZFRmdEt3bkV3VHh4OwoKICAgICAgICAgICAgZ0IgKCEodiA8IGp1bCAmJiBqdWwgPD0gZGJneC5WdUVUeDNuWXRkKSkgewogICAgICAgICAgICAgICAgVGpUdGQuVnVFVDZZczBUdyA9IGRiZ3guXzdZd3dUdGRLdUVUNllzMFR3OwogICAgICAgICAgICAgICAgVGpUdGQuVndUamduWXhLdUVUNllzMFR3ID0ganVsOwogICAgICAgICAgICAgICAgZGJneC43bnRkdWd0VHcuQ2d4VnVkN2JNalR0ZChUalR0ZCk7CiAgICAgICAgICAgICAgICB3VGRZd3Q7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIFRqVHRkLlZ3VGpnbll4S3VFVDZZczBUdyA9IGRiZ3guXzdZd3dUdGRLdUVUNllzMFR3OwogICAgICAgICAgICBkYmd4Ll83WXd3VHRkS3VFVDZZczBUdyA9IGp1bDsKICAgICAgICAgICAgVGpUdGQuVnVFVDZZczBUdyA9IGp1bDsKICAgICAgICAgICAgZGJneC43bnRkdWd0VHcuQ2d4VnVkN2JNalR0ZChUalR0ZCk7CgogICAgICAgICAgICAvLyAzYlQ3TyBnQiBkYlQgN3VsbFR3IGd4IGBLUzVOZ1RvVHdfWVZDdWRUYCwgZG4gdWpuZ0MgMHdUdU9ndEUgeDd3bmxsZ3RFLgogICAgICAgICAgICBnQiAoZGJneC5ZVkN1ZFRmdEt3bkV3VHh4KSB7CiAgICAgICAgICAgICAgICB3VGRZd3Q7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZGJneC54N3dubGxLdUVUZnRkbk5nVG8oanVsKTsKICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIEB3VGRZd3R4IHt0WXMwVHd9CiAgICAgICAgICovCiAgICAgICAgRVRkIDdZd3dUdGRQN3VsVCgpIHsKICAgICAgICAgICAgd1RkWXd0IGRiZ3guXzdZd3dUdGRQN3VsVCAhPT0gVzZSNjk4Nl9QM0FJTSA/IGRiZ3guXzdZd3dUdGRQN3VsVCA6CiAgICAgICAgICAgICAgICAgICAgU001QVdJSF9QM0FJTTsKICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIEBWdXd1cyB7dFlzMFR3fSBqdWwgLSBQN3VsVCBuQiBkYlQgVnVFVHggZ3QgVlR3N1R0ZHguCiAgICAgICAgICovCiAgICAgICAgeFRkIDdZd3dUdGRQN3VsVChqdWwpIHsKICAgICAgICAgICAgZ0IgKGd4NnU2KGp1bCkpIHsKICAgICAgICAgICAgICAgIGRid25vIHRUbyBNd3dudygnZnRqdWxnQyB0WXNUd2c3IHg3dWxUJyk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZ0IgKCFkYmd4LlZDQlNuN1lzVHRkKSB7CiAgICAgICAgICAgICAgICBkYmd4Ll83WXd3VHRkUDd1bFQgPSBqdWw7CiAgICAgICAgICAgICAgICBkYmd4Ll83WXd3VHRkUDd1bFROdWxZVCA9IGp1bCAhPT0gVzZSNjk4Nl9QM0FJTSA/IGp1bC5kblBkd2d0RSgpIDogdFlsbDsKICAgICAgICAgICAgICAgIHdUZFl3dDsKICAgICAgICAgICAgfQogICAgICAgICAgICBkYmd4Ll94VGRQN3VsVChqdWwsIEJ1bHhUKTsKICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIEB3VGRZd3R4IHt4ZHdndEV9CiAgICAgICAgICovCiAgICAgICAgRVRkIDdZd3dUdGRQN3VsVE51bFlUKCkgewogICAgICAgICAgICB3VGRZd3QgZGJneC5fN1l3d1R0ZFA3dWxUTnVsWVQ7CiAgICAgICAgfSwKICAgICAgICAvKioKICAgICAgICAgKiBAVnV3dXMganVsIC0gSGJUIHg3dWxUIG5CIGRiVCBWdUVUeCAoZ3QgVlR3N1R0ZCBudyBWd1RDVEJndFRDIGp1bFlUKS4KICAgICAgICAgKi8KICAgICAgICB4VGQgN1l3d1R0ZFA3dWxUTnVsWVQoanVsKSB7CiAgICAgICAgICAgIGdCICghZGJneC5WQ0JTbjdZc1R0ZCkgewogICAgICAgICAgICAgICAgZGJneC5fN1l3d1R0ZFA3dWxUID0gZ3g2dTYoanVsKSA/IFc2UjY5ODZfUDNBSU0gOiBqdWw7CiAgICAgICAgICAgICAgICBkYmd4Ll83WXd3VHRkUDd1bFROdWxZVCA9IGp1bDsKICAgICAgICAgICAgICAgIHdUZFl3dDsKICAgICAgICAgICAgfQogICAgICAgICAgICBkYmd4Ll94VGRQN3VsVChqdWwsIEJ1bHhUKTsKICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIEB3VGRZd3R4IHt0WXMwVHd9CiAgICAgICAgICovCiAgICAgICAgRVRkIFZ1RVR4ZW5kdWRnbnQoKSB7CiAgICAgICAgICAgIHdUZFl3dCBkYmd4Ll9WdUVUeGVuZHVkZ250OwogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogQFZ1d3VzIHt0WXMwVHd9IHduZHVkZ250IC0gSGJUIHduZHVkZ250IG5CIGRiVCBWdUVUeCAodiwgTHYsIHpVdiwgWmF2KS4KICAgICAgICAgKi8KICAgICAgICB4VGQgVnVFVHhlbmR1ZGdudCh3bmR1ZGdudCkgewogICAgICAgICAgICBkYmd4Ll9WdUVUeGVuZHVkZ250ID0gd25kdWRnbnQ7CgogICAgICAgICAgICBCbncgKGp1dyBnID0gdiwgbCA9IGRiZ3guX1Z1RVR4LmxUdEVkYjsgZyA8IGw7IGcrKykgewogICAgICAgICAgICAgICAganV3IFZ1RVROZ1RvID0gZGJneC5fVnVFVHhbZ107CiAgICAgICAgICAgICAgICBWdUVUTmdUby5ZVkN1ZFQoVnVFVE5nVG8ueDd1bFQsIHduZHVkZ250KTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgZGJneC5feFRkUDd1bFQoZGJneC5fN1l3d1R0ZFA3dWxUTnVsWVQsIGR3WVQpOwoKICAgICAgICAgICAgZ0IgKGRiZ3guQ1RCdVlsZGVUdENUd2d0RWhZVFlUKSB7CiAgICAgICAgICAgICAgICBkYmd4LllWQ3VkVCgpOwogICAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICAvKioKICAgICAgICAgKiBAVnV3dXMgVkNCU243WXNUdGQge0tTNVNuN1lzVHRkfQogICAgICAgICAqLwogICAgICAgIHhUZFNuN1lzVHRkOiBCWXQ3ZGdudCAoVkNCU243WXNUdGQpIHsKICAgICAgICAgICAgZ0IgKGRiZ3guVkNCU243WXNUdGQpIHsKICAgICAgICAgICAgICAgIGRiZ3guX3dUeFRkTmdUbygpOwogICAgICAgICAgICB9CgogICAgICAgICAgICBkYmd4LlZDQlNuN1lzVHRkID0gVkNCU243WXNUdGQ7CiAgICAgICAgICAgIGdCICghVkNCU243WXNUdGQpIHsKICAgICAgICAgICAgICAgIHdUZFl3dDsKICAgICAgICAgICAgfQoKICAgICAgICAgICAganV3IFZ1RVR4M25ZdGQgPSBWQ0JTbjdZc1R0ZC50WXNLdUVUeDsKICAgICAgICAgICAganV3IHhUbEIgPSBkYmd4OwoKICAgICAgICAgICAganV3IHdUeG5salRLdUVUeEt3bnNneFQ7CiAgICAgICAgICAgIGp1dyBWdUVUeEt3bnNneFQgPSB0VG8gS3duc2d4VChCWXQ3ZGdudCAod1R4bmxqVCkgewogICAgICAgICAgICAgICAgd1R4bmxqVEt1RVR4S3duc2d4VCA9IHdUeG5salQ7CiAgICAgICAgICAgIH0pOwogICAgICAgICAgICBkYmd4LlZ1RVR4S3duc2d4VCA9IFZ1RVR4S3duc2d4VDsKICAgICAgICAgICAgVnVFVHhLd25zZ3hULmRiVHQoQll0N2RnbnQgKCkgewogICAgICAgICAgICAgICAganV3IFRqVHRkID0gQ243WXNUdGQuN3dUdWRUTWpUdGQoJzNZeGRuc01qVHRkJyk7CiAgICAgICAgICAgICAgICBUalR0ZC5ndGdkM1l4ZG5zTWpUdGQoJ1Z1RVR4bG51Q1RDJywgZHdZVCwgZHdZVCwgewogICAgICAgICAgICAgICAgICAgIFZ1RVR4M25ZdGQ6IFZ1RVR4M25ZdGQKICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgeFRsQi43bnRkdWd0VHcuQ2d4VnVkN2JNalR0ZChUalR0ZCk7CiAgICAgICAgICAgIH0pOwoKICAgICAgICAgICAganV3IGd4OXRUS3VFVGVUdENUd1RDZVR4bmxqVEMgPSBCdWx4VDsKICAgICAgICAgICAganV3IHdUeG5salQ5dFRLdUVUZVR0Q1R3VEMgPSB0WWxsOwogICAgICAgICAgICBqdXcgbnRUS3VFVGVUdENUd1RDID0gdFRvIEt3bnNneFQoQll0N2RnbnQgKHdUeG5salQpIHsKICAgICAgICAgICAgICAgIHdUeG5salQ5dFRLdUVUZVR0Q1R3VEMgPSB3VHhubGpUOwogICAgICAgICAgICB9KTsKICAgICAgICAgICAgZGJneC5udFRLdUVUZVR0Q1R3VEMgPSBudFRLdUVUZVR0Q1R3VEM7CgogICAgICAgICAgICBqdXcgMGd0Qzl0QUJkVHdBdENGVEJud1RTd3VvID0gQll0N2RnbnQgKFZ1RVROZ1RvKSB7CiAgICAgICAgICAgICAgICBWdUVUTmdUby5udEZUQm53VFN3dW8gPSBCWXQ3ZGdudCBWQ0JOZ1RvSW51Qzl0RlRCbndUU3d1bygpIHsKICAgICAgICAgICAgICAgICAgICAvLyBBQ0MgZGJUIFZ1RVQgZG4gZGJUIDBZQkJUdyB1ZCBkYlQgeGR1d2QgbkIgQ3d1b2d0RS4gSGJ1ZCBvdWsgZ2QgN3V0CiAgICAgICAgICAgICAgICAgICAgLy8gMFQgVGpnN2RUQyBCd25zIGRiVCAwWUJCVHcgdXRDIENUeGR3bmtUQyBUalR0IGdCIG9UIFZ1WXhUIGdkeAogICAgICAgICAgICAgICAgICAgIC8vIHdUdENUd2d0RS4KICAgICAgICAgICAgICAgICAgICB4VGxCLl8wWUJCVHcuVll4YihkYmd4KTsKICAgICAgICAgICAgICAgIH07CiAgICAgICAgICAgICAgICAvLyBvYlR0IFZ1RVQgZ3ggVnVndGRUQywgWXhndEUgZGJUIGdzdUVUIHV4IGRiWXMwdHVnbCAwdXhUCiAgICAgICAgICAgICAgICBWdUVUTmdUby5udEFCZFR3U3d1byA9IEJZdDdkZ250IFZDQk5nVG9JbnVDOXRBQmRUd1N3dW8oKSB7CiAgICAgICAgICAgICAgICAgICAgZ0IgKCFneDl0VEt1RVRlVHRDVHdUQ2VUeG5salRDKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGd4OXRUS3VFVGVUdENUd1RDZVR4bmxqVEMgPSBkd1lUOwogICAgICAgICAgICAgICAgICAgICAgICB3VHhubGpUOXRUS3VFVGVUdENUd1RDKCk7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfTsKICAgICAgICAgICAgfTsKCiAgICAgICAgICAgIGp1dyBCZ3d4ZEt1RVRLd25zZ3hUID0gVkNCU243WXNUdGQuRVRkS3VFVCh6KTsKICAgICAgICAgICAgZGJneC5CZ3d4ZEt1RVRLd25zZ3hUID0gQmd3eGRLdUVUS3duc2d4VDsKCiAgICAgICAgICAgIC8vIDVUZDdiIHUgeGd0RWxUIFZ1RVQgeG4gb1QgN3V0IEVUZCB1IGpnVG9WbndkIGRidWQgb2dsbCAwVCBkYlQgQ1RCdVlsZAogICAgICAgICAgICAvLyBqZ1RvVm53ZCBCbncgdWxsIFZ1RVR4CiAgICAgICAgICAgIHdUZFl3dCBCZ3d4ZEt1RVRLd25zZ3hULmRiVHQoQll0N2RnbnQgKFZDQkt1RVQpIHsKICAgICAgICAgICAgICAgIGp1dyB4N3VsVCA9IGRiZ3guN1l3d1R0ZFA3dWxUOwogICAgICAgICAgICAgICAganV3IGpnVG9WbndkID0gVkNCS3VFVC5FVGROZ1RvVm53ZCh4N3VsVCAqIDNQUF9XNmZIUCk7CiAgICAgICAgICAgICAgICBCbncgKGp1dyBWdUVUNllzID0gejsgVnVFVDZZcyA8PSBWdUVUeDNuWXRkOyArK1Z1RVQ2WXMpIHsKICAgICAgICAgICAgICAgICAgICBqdXcgZFRyZEl1a1R3NXU3ZG53ayA9IHRZbGw7CiAgICAgICAgICAgICAgICAgICAgZ0IgKCFLUzV5UC5DZ3h1MGxUSFRyZEl1a1R3KSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGRUcmRJdWtUdzV1N2Rud2sgPSBkYmd4OwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBqdXcgVnVFVE5nVG8gPSB0VG8gS1M1S3VFVE5nVG8oewogICAgICAgICAgICAgICAgICAgICAgICA3bnRkdWd0VHc6IGRiZ3guamdUb1R3LAogICAgICAgICAgICAgICAgICAgICAgICBnQzogVnVFVDZZcywKICAgICAgICAgICAgICAgICAgICAgICAgeDd1bFQ6IHg3dWxULAogICAgICAgICAgICAgICAgICAgICAgICBDVEJ1WWxkTmdUb1Zud2Q6IGpnVG9WbndkLjdsbnRUKCksCiAgICAgICAgICAgICAgICAgICAgICAgIHdUdENUd2d0RWhZVFlUOiBkYmd4LndUdENUd2d0RWhZVFlULAogICAgICAgICAgICAgICAgICAgICAgICBkVHJkSXVrVHc1dTdkbndrOiBkVHJkSXVrVHc1dTdkbndrLAogICAgICAgICAgICAgICAgICAgICAgICB1dHRuZHVkZ250eEl1a1R3NXU3ZG53azogZGJneAogICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgICAgIDBndEM5dEFCZFR3QXRDRlRCbndUU3d1byhWdUVUTmdUbyk7CiAgICAgICAgICAgICAgICAgICAgZGJneC5fVnVFVHguVll4YihWdUVUTmdUbyk7CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAganV3IGxndE9QVHdqZzdUID0gZGJneC5sZ3RPUFR3amc3VDsKCiAgICAgICAgICAgICAgICAvLyA1VGQ3YiB1bGwgZGJUIFZ1RVR4IHhndDdUIGRiVCBqZ1RvVm53ZCBneCB0VFRDVEMgMFRCbndUIFZ3Z3RkZ3RFCiAgICAgICAgICAgICAgICAvLyB4ZHV3ZHggZG4gN3dUdWRUIGRiVCA3bnd3VDdkIHhnR1QgN3V0anV4LiA4dWdkIFl0ZGdsIG50VCBWdUVUIGd4CiAgICAgICAgICAgICAgICAvLyB3VHRDVHdUQyB4biBvVCBDbnQnZCBkZ1QgWVYgZG5uIHN1dGsgd1R4bll3N1R4IFR1d2xrIG50LgogICAgICAgICAgICAgICAgbnRUS3VFVGVUdENUd1RDLmRiVHQoQll0N2RnbnQgKCkgewogICAgICAgICAgICAgICAgICAgIGdCICghS1M1eVAuQ2d4dTBsVEFZZG41VGQ3YikgewogICAgICAgICAgICAgICAgICAgICAgICBqdXcgRVRkS3VFVHhJVEJkID0gVnVFVHgzbll0ZDsKICAgICAgICAgICAgICAgICAgICAgICAgQm53IChqdXcgVnVFVDZZcyA9IHo7IFZ1RVQ2WXMgPD0gVnVFVHgzbll0ZDsgKytWdUVUNllzKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBWQ0JTbjdZc1R0ZC5FVGRLdUVUKFZ1RVQ2WXMpLmRiVHQoQll0N2RnbnQgKFZ1RVQ2WXMsIFZDQkt1RVQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBqdXcgVnVFVE5nVG8gPSB4VGxCLl9WdUVUeFtWdUVUNllzIC0gel07CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ0IgKCFWdUVUTmdUby5WQ0JLdUVUKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFZ1RVROZ1RvLnhUZEtDQkt1RVQoVkNCS3VFVCk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxndE9QVHdqZzdULjd1N2JUS3VFVGVUQihWdUVUNllzLCBWQ0JLdUVULndUQik7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRVRkS3VFVHhJVEJkLS07CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ0IgKCFFVGRLdUVUeElUQmQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd1R4bmxqVEt1RVR4S3duc2d4VCgpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0uMGd0Qyh0WWxsLCBWdUVUNllzKSk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9IFRseFQgewogICAgICAgICAgICAgICAgICAgICAgICAvLyBKSko6IEt3Z3RkZ3RFIGd4IHhUc2ctMHduT1R0IG9nZGIgdVlkbiBCVGQ3YiBDZ3h1MGxUQy4KICAgICAgICAgICAgICAgICAgICAgICAgd1R4bmxqVEt1RVR4S3duc2d4VCgpOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0pOwoKICAgICAgICAgICAgICAgIGp1dyBUalR0ZCA9IENuN1lzVHRkLjd3VHVkVE1qVHRkKCczWXhkbnNNalR0ZCcpOwogICAgICAgICAgICAgICAgVGpUdGQuZ3RnZDNZeGRuc01qVHRkKCdWdUVUeGd0Z2QnLCBkd1lULCBkd1lULCB0WWxsKTsKICAgICAgICAgICAgICAgIHhUbEIuN250ZHVndFR3LkNneFZ1ZDdiTWpUdGQoVGpUdGQpOwoKICAgICAgICAgICAgICAgIGdCIChkYmd4LkNUQnVZbGRlVHRDVHdndEVoWVRZVCkgewogICAgICAgICAgICAgICAgICAgIGRiZ3guWVZDdWRUKCk7CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgZ0IgKGRiZ3guQmd0QzNudGR3bmxsVHcpIHsKICAgICAgICAgICAgICAgICAgICBkYmd4LkJndEMzbnRkd25sbFR3LndUeG5salQ1Z3d4ZEt1RVQoKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfS4wZ3RDKGRiZ3gpKTsKICAgICAgICB9LAogICAgICAgIF93VHhUZE5nVG86IEJZdDdkZ250ICgpIHsKICAgICAgICAgICAgZGJneC5fVnVFVHggPSBbXTsKICAgICAgICAgICAgZGJneC5fN1l3d1R0ZEt1RVQ2WXMwVHcgPSB6OwogICAgICAgICAgICBkYmd4Ll83WXd3VHRkUDd1bFQgPSBXNlI2OTg2X1AzQUlNOwogICAgICAgICAgICBkYmd4Ll83WXd3VHRkUDd1bFROdWxZVCA9IHRZbGw7CiAgICAgICAgICAgIGRiZ3guXzBZQkJUdyA9IHRUbyBLUzVLdUVUTmdUb0ZZQkJUdyhTTTVBV0lIXzNBMzJNX1BmWE0pOwogICAgICAgICAgICBkYmd4Ll9sbjd1ZGdudCA9IHRZbGw7CiAgICAgICAgICAgIGRiZ3guX1Z1RVR4ZW5kdWRnbnQgPSB2OwogICAgICAgICAgICBkYmd4Ll9WdUVUeGVUUVlUeGR4ID0gW107CgogICAgICAgICAgICBqdXcgN250ZHVndFR3ID0gZGJneC5qZ1RvVHc7CiAgICAgICAgICAgIG9iZ2xUICg3bnRkdWd0VHcuYnV4M2JnbEM2bkNUeCgpKSB7CiAgICAgICAgICAgICAgICA3bnRkdWd0VHcud1RzbmpUM2JnbEMoN250ZHVndFR3Lmx1eGQzYmdsQyk7CiAgICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIF94N3dubGxXVkN1ZFQ6IEJZdDdkZ250IEtTNU5nVG9Ud194N3dubGxXVkN1ZFQoKSB7CiAgICAgICAgICAgIGdCIChkYmd4LlZ1RVR4M25ZdGQgPT09IHYpIHsKICAgICAgICAgICAgICAgIHdUZFl3dDsKICAgICAgICAgICAgfQogICAgICAgICAgICBkYmd4LllWQ3VkVCgpOwogICAgICAgICAgICBCbncgKGp1dyBnID0gdiwgZ2cgPSBkYmd4Ll9WdUVUeC5sVHRFZGI7IGcgPCBnZzsgZysrKSB7CiAgICAgICAgICAgICAgICBkYmd4Ll9WdUVUeFtnXS5ZVkN1ZFRLbnhnZGdudCgpOwogICAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICBfeFRkUDd1bFRTZ3hWdWQ3Yk1qVHRkOiBCWXQ3ZGdudCBWQ0JOZ1RvVHdfeFRkUDd1bFRTZ3hWdWQ3Yk1qVHRkKAogICAgICAgICAgICAgICAgdFRvUDd1bFQsIHRUb051bFlULCBWd1R4VGQpIHsKICAgICAgICAgICAganV3IFRqVHRkID0gQ243WXNUdGQuN3dUdWRUTWpUdGQoJ1dmTWpUdGR4Jyk7CiAgICAgICAgICAgIFRqVHRkLmd0Z2RXZk1qVHRkKCd4N3VsVDdidXRFVCcsIGR3WVQsIGR3WVQsIG9ndENubywgdik7CiAgICAgICAgICAgIFRqVHRkLng3dWxUID0gdFRvUDd1bFQ7CiAgICAgICAgICAgIGdCIChWd1R4VGQpIHsKICAgICAgICAgICAgICAgIFRqVHRkLlZ3VHhUZE51bFlUID0gdFRvTnVsWVQ7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZGJneC43bnRkdWd0VHcuQ2d4VnVkN2JNalR0ZChUalR0ZCk7CiAgICAgICAgfSwKICAgICAgICBfeFRkUDd1bFRXVkN1ZFRLdUVUeDogQll0N2RnbnQgVkNCTmdUb1R3X3hUZFA3dWxUV1ZDdWRUS3VFVHgoCiAgICAgICAgICAgICAgICB0VG9QN3VsVCwgdFRvTnVsWVQsIHRuUDd3bmxsLCBWd1R4VGQpIHsKICAgICAgICAgICAgZGJneC5fN1l3d1R0ZFA3dWxUTnVsWVQgPSB0VG9OdWxZVDsKCiAgICAgICAgICAgIGdCIChneFB1c1RQN3VsVChkYmd4Ll83WXd3VHRkUDd1bFQsIHRUb1A3dWxUKSkgewogICAgICAgICAgICAgICAgZ0IgKFZ3VHhUZCkgewogICAgICAgICAgICAgICAgICAgIGRiZ3guX3hUZFA3dWxUU2d4VnVkN2JNalR0ZCh0VG9QN3VsVCwgdFRvTnVsWVQsIGR3WVQpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgd1RkWXd0OwogICAgICAgICAgICB9CgogICAgICAgICAgICBCbncgKGp1dyBnID0gdiwgZ2cgPSBkYmd4Ll9WdUVUeC5sVHRFZGI7IGcgPCBnZzsgZysrKSB7CiAgICAgICAgICAgICAgICBkYmd4Ll9WdUVUeFtnXS5ZVkN1ZFQodFRvUDd1bFQpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGRiZ3guXzdZd3dUdGRQN3VsVCA9IHRUb1A3dWxUOwoKICAgICAgICAgICAgZ0IgKCF0blA3d25sbCkgewogICAgICAgICAgICAgICAganV3IFZ1RVQgPSBkYmd4Ll83WXd3VHRkS3VFVDZZczBUdywgQ1R4ZDsKICAgICAgICAgICAgICAgIGdCIChkYmd4Ll9sbjd1ZGdudCAmJiAhZnA2OWVNXzNXZWVNNkhfSzlQZkhmOTZfOTZfWDk5cSAmJgogICAgICAgICAgICAgICAgICAgICAgICAhKGRiZ3guZ3hmdEt3VHhUdGR1ZGdudHFuQ1QgfHwgZGJneC5neDNidXRFZ3RFS3dUeFR0ZHVkZ250cW5DVCkpIHsKICAgICAgICAgICAgICAgICAgICBWdUVUID0gZGJneC5fbG43dWRnbnQuVnVFVDZZczBUdzsKICAgICAgICAgICAgICAgICAgICBDVHhkID0gW3RZbGwsIHt0dXNUOiAnSjRYJ30sIGRiZ3guX2xuN3VkZ250LmxUQmQsCiAgICAgICAgICAgICAgICAgICAgICAgIGRiZ3guX2xuN3VkZ250LmRuViwgdFlsbF07CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBkYmd4Lng3d25sbEt1RVRmdGRuTmdUbyhWdUVULCBDVHhkKTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgZGJneC5feFRkUDd1bFRTZ3hWdWQ3Yk1qVHRkKHRUb1A3dWxULCB0VG9OdWxZVCwgVndUeFRkKTsKCiAgICAgICAgICAgIGdCIChkYmd4LkNUQnVZbGRlVHRDVHdndEVoWVRZVCkgewogICAgICAgICAgICAgICAgZGJneC5ZVkN1ZFQoKTsKICAgICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgX3hUZFA3dWxUOiBCWXQ3ZGdudCBWQ0JOZ1RvVHdfeFRkUDd1bFQoanVsWVQsIHRuUDd3bmxsKSB7CiAgICAgICAgICAgIGp1dyB4N3VsVCA9IFZ1d3hUNWxudWQoanVsWVQpOwoKICAgICAgICAgICAgZ0IgKHg3dWxUID4gdikgewogICAgICAgICAgICAgICAgZGJneC5feFRkUDd1bFRXVkN1ZFRLdUVUeCh4N3VsVCwganVsWVQsIHRuUDd3bmxsLCBCdWx4VCk7CiAgICAgICAgICAgIH0gVGx4VCB7CiAgICAgICAgICAgICAgICBqdXcgN1l3d1R0ZEt1RVQgPSBkYmd4Ll9WdUVUeFtkYmd4Ll83WXd3VHRkS3VFVDZZczBUdyAtIHpdOwogICAgICAgICAgICAgICAgZ0IgKCE3WXd3VHRkS3VFVCkgewogICAgICAgICAgICAgICAgICAgIHdUZFl3dDsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGp1dyBiS3VDQ2d0RSA9IChkYmd4Lmd4ZnRLd1R4VHRkdWRnbnRxbkNUIHx8IGRiZ3gud1RzbmpUS3VFVEZud0NUd3gpID8KICAgICAgICAgICAgICAgICAgICAgICAgdiA6IFAzZTlJSUZBZV9LQVNTZjZwOwogICAgICAgICAgICAgICAganV3IGpLdUNDZ3RFID0gKGRiZ3guZ3hmdEt3VHhUdGR1ZGdudHFuQ1QgfHwgZGJneC53VHNualRLdUVURm53Q1R3eCkgPwogICAgICAgICAgICAgICAgICAgICAgICB2IDogTk1lSGYzQUlfS0FTU2Y2cDsKICAgICAgICAgICAgICAgIGp1dyBWdUVUOGdDZGJQN3VsVCA9IChkYmd4LjdudGR1Z3RUdy43bGdUdGQ4Z0NkYiAtIGJLdUNDZ3RFKSAvCiAgICAgICAgICAgICAgICAgICAgICAgIDdZd3dUdGRLdUVULm9nQ2RiICogN1l3d1R0ZEt1RVQueDd1bFQ7CiAgICAgICAgICAgICAgICBqdXcgVnVFVDJUZ0ViZFA3dWxUID0gKGRiZ3guN250ZHVndFR3LjdsZ1R0ZDJUZ0ViZCAtIGpLdUNDZ3RFKSAvCiAgICAgICAgICAgICAgICAgICAgICAgIDdZd3dUdGRLdUVULmJUZ0ViZCAqIDdZd3dUdGRLdUVULng3dWxUOwogICAgICAgICAgICAgICAgeG9nZDdiIChqdWxZVCkgewogICAgICAgICAgICAgICAgICAgIDd1eFQgJ1Z1RVQtdTdkWXVsJzoKICAgICAgICAgICAgICAgICAgICAgICAgeDd1bFQgPSB6OwogICAgICAgICAgICAgICAgICAgICAgICAwd1R1TzsKICAgICAgICAgICAgICAgICAgICA3dXhUICdWdUVULW9nQ2RiJzoKICAgICAgICAgICAgICAgICAgICAgICAgeDd1bFQgPSBWdUVUOGdDZGJQN3VsVDsKICAgICAgICAgICAgICAgICAgICAgICAgMHdUdU87CiAgICAgICAgICAgICAgICAgICAgN3V4VCAnVnVFVC1iVGdFYmQnOgogICAgICAgICAgICAgICAgICAgICAgICB4N3VsVCA9IFZ1RVQyVGdFYmRQN3VsVDsKICAgICAgICAgICAgICAgICAgICAgICAgMHdUdU87CiAgICAgICAgICAgICAgICAgICAgN3V4VCAnVnVFVC1CZ2QnOgogICAgICAgICAgICAgICAgICAgICAgICB4N3VsVCA9IHF1ZGIuc2d0KFZ1RVQ4Z0NkYlA3dWxULCBWdUVUMlRnRWJkUDd1bFQpOwogICAgICAgICAgICAgICAgICAgICAgICAwd1R1TzsKICAgICAgICAgICAgICAgICAgICA3dXhUICd1WWRuJzoKICAgICAgICAgICAgICAgICAgICAgICAganV3IGd4SXV0Q3g3dVZUID0gKDdZd3dUdGRLdUVULm9nQ2RiID4gN1l3d1R0ZEt1RVQuYlRnRWJkKTsKICAgICAgICAgICAgICAgICAgICAgICAgLy8gNW53IFZ1RVR4IGd0IGx1dEN4N3VWVCBzbkNULCBCZ2QgZGJUIFZ1RVQgYlRnRWJkIGRuIGRiVCBqZ1RvVHcKICAgICAgICAgICAgICAgICAgICAgICAgLy8gKll0bFR4eCogZGJUIFZ1RVQgb25ZbEMgZGJZeCAwVDduc1QgZG5uIG9nQ1QgZG4gQmdkIGJud2dHbnRkdWxsay4KICAgICAgICAgICAgICAgICAgICAgICAganV3IGJud2dHbnRkdWxQN3VsVCA9IGd4SXV0Q3g3dVZUID8KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBxdWRiLnNndChWdUVUMlRnRWJkUDd1bFQsIFZ1RVQ4Z0NkYlA3dWxUKSA6IFZ1RVQ4Z0NkYlA3dWxUOwogICAgICAgICAgICAgICAgICAgICAgICB4N3VsVCA9IHF1ZGIuc2d0KHFBSl9BV0g5X1AzQUlNLCBibndnR250ZHVsUDd1bFQpOwogICAgICAgICAgICAgICAgICAgICAgICAwd1R1TzsKICAgICAgICAgICAgICAgICAgICBDVEJ1WWxkOgogICAgICAgICAgICAgICAgICAgICAgICA3bnR4bmxULlR3d253KCdWQ0JOZ1RvUFRkUDd1bFQ6IFwnJyArIGp1bFlUICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnXCcgZ3ggdXQgWXRPdG5vdCBHbm5zIGp1bFlULicpOwogICAgICAgICAgICAgICAgICAgICAgICB3VGRZd3Q7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBkYmd4Ll94VGRQN3VsVFdWQ3VkVEt1RVR4KHg3dWxULCBqdWxZVCwgdG5QN3dubGwsIGR3WVQpOwogICAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICAvKioKICAgICAgICAgKiBQN3dubGx4IFZ1RVQgZ3RkbiBqZ1RvLgogICAgICAgICAqIEBWdXd1cyB7dFlzMFR3fSBWdUVUNllzMFR3CiAgICAgICAgICogQFZ1d3VzIHtBd3d1a30gQ1R4ZCAtIChuVmRnbnR1bCkgbndnRWd0dWwgS1M1IENUeGRndHVkZ250IHV3d3VrOgogICAgICAgICAqICAgPFZ1RVQtd1RCPiA8L0o0WHw1Z2RKSko+IDx1d0V4Li4+CiAgICAgICAgICovCiAgICAgICAgeDd3bmxsS3VFVGZ0ZG5OZ1RvOiBCWXQ3ZGdudCBLUzVOZ1RvVHdfeDd3bmxsS3VFVGZ0ZG5OZ1RvKFZ1RVQ2WXMwVHcsCiAgICAgICAgICAgICAgICBDVHhkKSB7CiAgICAgICAgICAgIGp1dyBWdUVUTmdUbyA9IGRiZ3guX1Z1RVR4W1Z1RVQ2WXMwVHcgLSB6XTsKCiAgICAgICAgICAgIGdCIChkYmd4Lmd4ZnRLd1R4VHRkdWRnbnRxbkNUKSB7CiAgICAgICAgICAgICAgICBnQiAoZGJneC5fN1l3d1R0ZEt1RVQ2WXMwVHcgIT09IFZ1RVROZ1RvLmdDKSB7CiAgICAgICAgICAgICAgICAgICAgLy8gQWpuZ0MgMHdUdU9ndEUgRVRkTmd4ZzBsVEt1RVR4IGd0IFZ3VHhUdGR1ZGdudCBzbkNULgogICAgICAgICAgICAgICAgICAgIGRiZ3guN1l3d1R0ZEt1RVQ2WXMwVHcgPSBWdUVUTmdUby5nQzsKICAgICAgICAgICAgICAgICAgICB3VGRZd3Q7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBDVHhkID0gdFlsbDsKICAgICAgICAgICAgICAgIC8vIDVnclR4IGRiVCA3dXhUIG9iVHQgS1M1IGJ1eCBDZ0JCVHdUdGQgVnVFVCB4Z0dUeC4KICAgICAgICAgICAgICAgIGRiZ3guX3hUZFA3dWxUKGRiZ3guXzdZd3dUdGRQN3VsVE51bFlULCBkd1lUKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBnQiAoIUNUeGQpIHsKICAgICAgICAgICAgICAgIHg3d25sbGZ0ZG5OZ1RvKFZ1RVROZ1RvLkNnaik7CiAgICAgICAgICAgICAgICB3VGRZd3Q7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGp1dyByID0gdiwgayA9IHY7CiAgICAgICAgICAgIGp1dyBvZ0NkYiA9IHYsIGJUZ0ViZCA9IHYsIG9nQ2RiUDd1bFQsIGJUZ0ViZFA3dWxUOwogICAgICAgICAgICBqdXcgN2J1dEVUOXdnVHRkdWRnbnQgPSAoVnVFVE5nVG8ud25kdWRnbnQgJSB6VXYgPT09IHYgPyBCdWx4VCA6IGR3WVQpOwogICAgICAgICAgICBqdXcgVnVFVDhnQ2RiID0gKDdidXRFVDl3Z1R0ZHVkZ250ID8gVnVFVE5nVG8uYlRnRWJkIDogVnVFVE5nVG8ub2dDZGIpIC8KICAgICAgICAgICAgICAgICAgICBWdUVUTmdUby54N3VsVCAvIDNQUF9XNmZIUDsKICAgICAgICAgICAganV3IFZ1RVQyVGdFYmQgPSAoN2J1dEVUOXdnVHRkdWRnbnQgPyBWdUVUTmdUby5vZ0NkYiA6IFZ1RVROZ1RvLmJUZ0ViZCkgLwogICAgICAgICAgICAgICAgICAgIFZ1RVROZ1RvLng3dWxUIC8gM1BQX1c2ZkhQOwogICAgICAgICAgICBqdXcgeDd1bFQgPSB2OwogICAgICAgICAgICB4b2dkN2IgKENUeGRbel0udHVzVCkgewogICAgICAgICAgICAgICAgN3V4VCAnSjRYJzoKICAgICAgICAgICAgICAgICAgICByID0gQ1R4ZFtaXTsKICAgICAgICAgICAgICAgICAgICBrID0gQ1R4ZFttXTsKICAgICAgICAgICAgICAgICAgICB4N3VsVCA9IENUeGRbaV07CiAgICAgICAgICAgICAgICAgICAgLy8gZkIgciB1dEMvbncgayA3bm53Q2d0dWRUeCB1d1QgdG5kIHhZVlZsZ1RDLCBDVEJ1WWxkIGRuCiAgICAgICAgICAgICAgICAgICAgLy8gX2RuVl8gbFRCZCBuQiBkYlQgVnVFVCAodG5kIGRiVCBuMGpnbll4IDBuZGRucyBsVEJkLAogICAgICAgICAgICAgICAgICAgIC8vIHhndDdUIHVsZ0V0Z3RFIGRiVCAwbmRkbnMgbkIgZGJUIGd0ZFR0Q1RDIFZ1RVQgb2dkYiBkYlQKICAgICAgICAgICAgICAgICAgICAvLyBkblYgbkIgZGJUIG9ndENubyBneCB3dXdUbGsgYlRsVkJZbCkuCiAgICAgICAgICAgICAgICAgICAgciA9IHIgIT09IHRZbGwgPyByIDogdjsKICAgICAgICAgICAgICAgICAgICBrID0gayAhPT0gdFlsbCA/IGsgOiBWdUVUMlRnRWJkOwogICAgICAgICAgICAgICAgICAgIDB3VHVPOwogICAgICAgICAgICAgICAgN3V4VCAnNWdkJzoKICAgICAgICAgICAgICAgIDd1eFQgJzVnZEYnOgogICAgICAgICAgICAgICAgICAgIHg3dWxUID0gJ1Z1RVQtQmdkJzsKICAgICAgICAgICAgICAgICAgICAwd1R1TzsKICAgICAgICAgICAgICAgIDd1eFQgJzVnZDInOgogICAgICAgICAgICAgICAgN3V4VCAnNWdkRjInOgogICAgICAgICAgICAgICAgICAgIGsgPSBDVHhkW1pdOwogICAgICAgICAgICAgICAgICAgIHg3dWxUID0gJ1Z1RVQtb2dDZGInOwogICAgICAgICAgICAgICAgICAgIDB3VHVPOwogICAgICAgICAgICAgICAgN3V4VCAnNWdkTic6CiAgICAgICAgICAgICAgICA3dXhUICc1Z2RGTic6CiAgICAgICAgICAgICAgICAgICAgciA9IENUeGRbWl07CiAgICAgICAgICAgICAgICAgICAgb2dDZGIgPSBWdUVUOGdDZGI7CiAgICAgICAgICAgICAgICAgICAgYlRnRWJkID0gVnVFVDJUZ0ViZDsKICAgICAgICAgICAgICAgICAgICB4N3VsVCA9ICdWdUVULWJUZ0ViZCc7CiAgICAgICAgICAgICAgICAgICAgMHdUdU87CiAgICAgICAgICAgICAgICA3dXhUICc1Z2RlJzoKICAgICAgICAgICAgICAgICAgICByID0gQ1R4ZFtaXTsKICAgICAgICAgICAgICAgICAgICBrID0gQ1R4ZFttXTsKICAgICAgICAgICAgICAgICAgICBvZ0NkYiA9IENUeGRbaV0gLSByOwogICAgICAgICAgICAgICAgICAgIGJUZ0ViZCA9IENUeGRbY10gLSBrOwogICAgICAgICAgICAgICAgICAgIGp1dyBiS3VDQ2d0RSA9IGRiZ3gud1RzbmpUS3VFVEZud0NUd3ggPyB2IDogUDNlOUlJRkFlX0tBU1NmNnA7CiAgICAgICAgICAgICAgICAgICAganV3IGpLdUNDZ3RFID0gZGJneC53VHNualRLdUVURm53Q1R3eCA/IHYgOiBOTWVIZjNBSV9LQVNTZjZwOwoKICAgICAgICAgICAgICAgICAgICBvZ0NkYlA3dWxUID0gKGRiZ3guN250ZHVndFR3LjdsZ1R0ZDhnQ2RiIC0gYkt1Q0NndEUpIC8KICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9nQ2RiIC8gM1BQX1c2ZkhQOwogICAgICAgICAgICAgICAgICAgIGJUZ0ViZFA3dWxUID0gKGRiZ3guN250ZHVndFR3LjdsZ1R0ZDJUZ0ViZCAtIGpLdUNDZ3RFKSAvCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBiVGdFYmQgLyAzUFBfVzZmSFA7CiAgICAgICAgICAgICAgICAgICAgeDd1bFQgPSBxdWRiLnNndChxdWRiLnUweChvZ0NkYlA3dWxUKSwgcXVkYi51MHgoYlRnRWJkUDd1bFQpKTsKICAgICAgICAgICAgICAgICAgICAwd1R1TzsKICAgICAgICAgICAgICAgIENUQnVZbGQ6CiAgICAgICAgICAgICAgICAgICAgd1RkWXd0OwogICAgICAgICAgICB9CgogICAgICAgICAgICBnQiAoeDd1bFQgJiYgeDd1bFQgIT09IGRiZ3guXzdZd3dUdGRQN3VsVCkgewogICAgICAgICAgICAgICAgZGJneC43WXd3VHRkUDd1bFROdWxZVCA9IHg3dWxUOwogICAgICAgICAgICB9IFRseFQgZ0IgKGRiZ3guXzdZd3dUdGRQN3VsVCA9PT0gVzZSNjk4Nl9QM0FJTSkgewogICAgICAgICAgICAgICAgZGJneC43WXd3VHRkUDd1bFROdWxZVCA9IFNNNUFXSUhfUDNBSU1fTkFJV007CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGdCICh4N3VsVCA9PT0gJ1Z1RVQtQmdkJyAmJiAhQ1R4ZFtpXSkgewogICAgICAgICAgICAgICAgeDd3bmxsZnRkbk5nVG8oVnVFVE5nVG8uQ2dqKTsKICAgICAgICAgICAgICAgIHdUZFl3dDsKICAgICAgICAgICAgfQoKICAgICAgICAgICAganV3IDBuWXRDZ3RFZVQ3ZCA9IFsKICAgICAgICAgICAgICAgIFZ1RVROZ1RvLmpnVG9WbndkLjdudGpUd2RIbk5nVG9WbndkS25ndGQociwgayksCiAgICAgICAgICAgICAgICBWdUVUTmdUby5qZ1RvVm53ZC43bnRqVHdkSG5OZ1RvVm53ZEtuZ3RkKHIgKyBvZ0NkYiwgayArIGJUZ0ViZCkKICAgICAgICAgICAgXTsKICAgICAgICAgICAganV3IGxUQmQgPSBxdWRiLnNndCgwbll0Q2d0RWVUN2Rbdl1bdl0sIDBuWXRDZ3RFZVQ3ZFt6XVt2XSk7CiAgICAgICAgICAgIGp1dyBkblYgPSBxdWRiLnNndCgwbll0Q2d0RWVUN2Rbdl1bel0sIDBuWXRDZ3RFZVQ3ZFt6XVt6XSk7CgogICAgICAgICAgICB4N3dubGxmdGRuTmdUbyhWdUVUTmdUby5DZ2osIHtsVEJkOiBsVEJkLCBkblY6IGRuVn0pOwogICAgICAgIH0sCiAgICAgICAgX1lWQ3VkVEluN3VkZ250OiBCWXQ3ZGdudCAoQmd3eGRLdUVUKSB7CiAgICAgICAgICAgIGp1dyA3WXd3VHRkUDd1bFQgPSBkYmd4Ll83WXd3VHRkUDd1bFQ7CiAgICAgICAgICAgIGp1dyA3WXd3VHRkUDd1bFROdWxZVCA9IGRiZ3guXzdZd3dUdGRQN3VsVE51bFlUOwogICAgICAgICAgICBqdXcgdG53c3VsZ0dUQ1A3dWxUTnVsWVQgPQogICAgICAgICAgICAgICAgICAgIFZ1d3hUNWxudWQoN1l3d1R0ZFA3dWxUTnVsWVQpID09PSA3WXd3VHRkUDd1bFQgPwogICAgICAgICAgICAgICAgICAgIHF1ZGIud25ZdEMoN1l3d1R0ZFA3dWxUICogenZ2dnYpIC8genZ2IDogN1l3d1R0ZFA3dWxUTnVsWVQ7CgogICAgICAgICAgICBqdXcgVnVFVDZZczBUdyA9IEJnd3hkS3VFVC5nQzsKICAgICAgICAgICAganV3IFZDQjlWVHRLdXd1c3ggPSAnI1Z1RVQ9JyArIFZ1RVQ2WXMwVHc7CiAgICAgICAgICAgIFZDQjlWVHRLdXd1c3ggKz0gJyZHbm5zPScgKyB0bndzdWxnR1RDUDd1bFROdWxZVDsKICAgICAgICAgICAganV3IDdZd3dUdGRLdUVUTmdUbyA9IGRiZ3guX1Z1RVR4W1Z1RVQ2WXMwVHcgLSB6XTsKICAgICAgICAgICAganV3IDdudGR1Z3RUdyA9IGRiZ3guN250ZHVndFR3OwogICAgICAgICAgICBqdXcgZG5WSVRCZCA9IDdZd3dUdGRLdUVUTmdUby5FVGRLdUVUS25ndGQoCiAgICAgICAgICAgICAgICAgICAgKDdudGR1Z3RUdy54N3dubGxJVEJkIC0gQmd3eGRLdUVULnIpLAogICAgICAgICAgICAgICAgICAgICg3bnRkdWd0VHcueDd3bmxsSG5WIC0gQmd3eGRLdUVULmspKTsKICAgICAgICAgICAganV3IGd0ZElUQmQgPSBxdWRiLnduWXRDKGRuVklUQmRbdl0pOwogICAgICAgICAgICBqdXcgZ3RkSG5WID0gcXVkYi53bll0QyhkblZJVEJkW3pdKTsKICAgICAgICAgICAgVkNCOVZUdEt1d3VzeCArPSAnLCcgKyBndGRJVEJkICsgJywnICsgZ3RkSG5WOwoKICAgICAgICAgICAgZGJneC5fbG43dWRnbnQgPSB7CiAgICAgICAgICAgICAgICBWdUVUNllzMFR3OiBWdUVUNllzMFR3LAogICAgICAgICAgICAgICAgeDd1bFQ6IHRud3N1bGdHVENQN3VsVE51bFlULAogICAgICAgICAgICAgICAgZG5WOiBndGRIblYsCiAgICAgICAgICAgICAgICBsVEJkOiBndGRJVEJkLAogICAgICAgICAgICAgICAgVkNCOVZUdEt1d3VzeDogVkNCOVZUdEt1d3VzeAogICAgICAgICAgICB9OwogICAgICAgIH0sCiAgICAgICAgWVZDdWRUOiBCWXQ3ZGdudCBLUzVOZ1RvVHdfWVZDdWRUKCkgewogICAgICAgICAgICBqdXcgamd4ZzBsVCA9IGRiZ3guX0VUZE5neGcwbFRLdUVUeCgpOwogICAgICAgICAgICBqdXcgamd4ZzBsVEt1RVR4ID0gamd4ZzBsVC5qZ1RveDsKICAgICAgICAgICAgZ0IgKGpneGcwbFRLdUVUeC5sVHRFZGIgPT09IHYpIHsKICAgICAgICAgICAgICAgIHdUZFl3dDsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgZGJneC5ZVkN1ZFRmdEt3bkV3VHh4ID0gZHdZVDsKCiAgICAgICAgICAgIGp1dyB4WUVFVHhkVEMzdTdiVFBnR1QgPSBxdWRiLnN1cihTTTVBV0lIXzNBMzJNX1BmWE0sCiAgICAgICAgICAgICAgICAgICAgWiAqIGpneGcwbFRLdUVUeC5sVHRFZGIgKyB6KTsKICAgICAgICAgICAgZGJneC5fMFlCQlR3LndUeGdHVCh4WUVFVHhkVEMzdTdiVFBnR1QpOwoKICAgICAgICAgICAgZGJneC53VHRDVHdndEVoWVRZVC53VHRDVHcyZ0ViVHhkS3dnbndnZGsoamd4ZzBsVCk7CgogICAgICAgICAgICBqdXcgN1l3d1R0ZGZDID0gZGJneC5fN1l3d1R0ZEt1RVQ2WXMwVHc7CiAgICAgICAgICAgIGp1dyBCZ3d4ZEt1RVQgPSBqZ3hnMGxULkJnd3hkOwoKICAgICAgICAgICAgQm53IChqdXcgZyA9IHYsIGdnID0gamd4ZzBsVEt1RVR4LmxUdEVkYiwgeGRnbGw1WWxsa05neGcwbFQgPSBCdWx4VDsKICAgICAgICAgICAgICAgICAgICBnIDwgZ2c7ICsrZykgewogICAgICAgICAgICAgICAganV3IFZ1RVQgPSBqZ3hnMGxUS3VFVHhbZ107CgogICAgICAgICAgICAgICAgZ0IgKFZ1RVQuVlR3N1R0ZCA8IHp2dikgewogICAgICAgICAgICAgICAgICAgIDB3VHVPOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgZ0IgKFZ1RVQuZ0MgPT09IDdZd3dUdGRmQykgewogICAgICAgICAgICAgICAgICAgIHhkZ2xsNVlsbGtOZ3hnMGxUID0gZHdZVDsKICAgICAgICAgICAgICAgICAgICAwd1R1TzsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQoKICAgICAgICAgICAgZ0IgKCF4ZGdsbDVZbGxrTmd4ZzBsVCkgewogICAgICAgICAgICAgICAgN1l3d1R0ZGZDID0gamd4ZzBsVEt1RVR4W3ZdLmdDOwogICAgICAgICAgICB9CgogICAgICAgICAgICBnQiAoIWRiZ3guZ3hmdEt3VHhUdGR1ZGdudHFuQ1QpIHsKICAgICAgICAgICAgICAgIGRiZ3guN1l3d1R0ZEt1RVQ2WXMwVHcgPSA3WXd3VHRkZkM7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGRiZ3guX1lWQ3VkVEluN3VkZ250KEJnd3hkS3VFVCk7CgogICAgICAgICAgICBkYmd4LllWQ3VkVGZ0S3duRXdUeHggPSBCdWx4VDsKCiAgICAgICAgICAgIGp1dyBUalR0ZCA9IENuN1lzVHRkLjd3VHVkVE1qVHRkKCdXZk1qVHRkeCcpOwogICAgICAgICAgICBUalR0ZC5ndGdkV2ZNalR0ZCgnWVZDdWRUamdUb3V3VHUnLCBkd1lULCBkd1lULCBvZ3RDbm8sIHYpOwogICAgICAgICAgICBUalR0ZC5sbjd1ZGdudCA9IGRiZ3guX2xuN3VkZ250OwogICAgICAgICAgICBkYmd4LjdudGR1Z3RUdy5DZ3hWdWQ3Yk1qVHRkKFRqVHRkKTsKICAgICAgICB9LAogICAgICAgIDdudGR1Z3R4TWxUc1R0ZDogQll0N2RnbnQgKFRsVHNUdGQpIHsKICAgICAgICAgICAgd1RkWXd0IGRiZ3guN250ZHVndFR3LjdudGR1Z3R4KFRsVHNUdGQpOwogICAgICAgIH0sCiAgICAgICAgQm43WXg6IEJZdDdkZ250ICgpIHsKICAgICAgICAgICAgZGJneC43bnRkdWd0VHcuQm43WXgoKTsKICAgICAgICB9LAogICAgICAgIEVUZCBneGZ0S3dUeFR0ZHVkZ250cW5DVCgpIHsKICAgICAgICAgICAgd1RkWXd0IGRiZ3guVndUeFR0ZHVkZ250cW5DVFBkdWRUID09PSBLd1R4VHRkdWRnbnRxbkNUUGR1ZFQuNVdJSVAzZU1NNjsKICAgICAgICB9LAogICAgICAgIEVUZCBneDNidXRFZ3RFS3dUeFR0ZHVkZ250cW5DVCgpIHsKICAgICAgICAgICAgd1RkWXd0IGRiZ3guS3dUeFR0ZHVkZ250cW5DVFBkdWRUID09PSBLd1R4VHRkdWRnbnRxbkNUUGR1ZFQuMzJBNnBmNnA7CiAgICAgICAgfSwKICAgICAgICBFVGQgZ3gybndnR250ZHVsUDd3bmxsMHV3TXR1MGxUQygpIHsKICAgICAgICAgICAgd1RkWXd0IChkYmd4Lmd4ZnRLd1R4VHRkdWRnbnRxbkNUID8KICAgICAgICAgICAgICAgICAgICBCdWx4VCA6IChkYmd4LjdudGR1Z3RUdy54N3dubGw4Z0NkYiA+IGRiZ3guN250ZHVndFR3LjdsZ1R0ZDhnQ2RiKSk7CiAgICAgICAgfSwKICAgICAgICBfRVRkTmd4ZzBsVEt1RVR4OiBCWXQ3ZGdudCAoKSB7CiAgICAgICAgICAgIGdCICghZGJneC5neGZ0S3dUeFR0ZHVkZ250cW5DVCkgewogICAgICAgICAgICAgICAgd1RkWXd0IEVUZE5neGcwbFRNbFRzVHRkeChkYmd4LjdudGR1Z3RUdywgZGJneC5fVnVFVHgsIGR3WVQpOwogICAgICAgICAgICB9IFRseFQgewogICAgICAgICAgICAgICAgLy8gSGJUIHVsRW53Z2RicyBndCBFVGROZ3hnMGxUTWxUc1R0ZHggQ25UeHQnZCBvbndPIGd0IHVsbCAwd25veFR3eCB1dEMKICAgICAgICAgICAgICAgIC8vIDdudEJnRVl3dWRnbnR4IG9iVHQgVndUeFR0ZHVkZ250IHNuQ1QgZ3ggdTdkZ2pULgogICAgICAgICAgICAgICAganV3IGpneGcwbFQgPSBbXTsKICAgICAgICAgICAgICAgIGp1dyA3WXd3VHRkS3VFVCA9IGRiZ3guX1Z1RVR4W2RiZ3guXzdZd3dUdGRLdUVUNllzMFR3IC0gel07CiAgICAgICAgICAgICAgICBqZ3hnMGxULlZZeGIoe2dDOiA3WXd3VHRkS3VFVC5nQywgamdUbzogN1l3d1R0ZEt1RVR9KTsKICAgICAgICAgICAgICAgIHdUZFl3dCB7Qmd3eGQ6IDdZd3dUdGRLdUVULCBsdXhkOiA3WXd3VHRkS3VFVCwgamdUb3g6IGpneGcwbFR9OwogICAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICA3bFR1dFlWOiBCWXQ3ZGdudCAoKSB7CiAgICAgICAgICAgIEJudyAoanV3IGcgPSB2LCBnZyA9IGRiZ3guX1Z1RVR4LmxUdEVkYjsgZyA8IGdnOyBnKyspIHsKICAgICAgICAgICAgICAgIGdCIChkYmd4Ll9WdUVUeFtnXSAmJgogICAgICAgICAgICAgICAgICAgICAgICBkYmd4Ll9WdUVUeFtnXS53VHRDVHdndEVQZHVkVCAhPT0gZVR0Q1R3Z3RFUGR1ZFR4LjVmNmZQMk1TKSB7CiAgICAgICAgICAgICAgICAgICAgZGJneC5fVnVFVHhbZ10ud1R4VGQoKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogQFZ1d3VzIHtLUzVLdUVUTmdUb30gVnVFVE5nVG8KICAgICAgICAgKiBAd1RkWXd0eCB7S1M1S3VFVH0KICAgICAgICAgKiBAVndnanVkVAogICAgICAgICAqLwogICAgICAgIF9UdHhZd1RLQ0JLdUVUSW51Q1RDOiBCWXQ3ZGdudCAoVnVFVE5nVG8pIHsKICAgICAgICAgICAgZ0IgKFZ1RVROZ1RvLlZDQkt1RVQpIHsKICAgICAgICAgICAgICAgIHdUZFl3dCBLd25zZ3hULndUeG5salQoVnVFVE5nVG8uVkNCS3VFVCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAganV3IFZ1RVQ2WXMwVHcgPSBWdUVUTmdUby5nQzsKICAgICAgICAgICAgZ0IgKGRiZ3guX1Z1RVR4ZVRRWVR4ZHhbVnVFVDZZczBUd10pIHsKICAgICAgICAgICAgICAgIHdUZFl3dCBkYmd4Ll9WdUVUeGVUUVlUeGR4W1Z1RVQ2WXMwVHddOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGp1dyBWd25zZ3hUID0gZGJneC5WQ0JTbjdZc1R0ZC5FVGRLdUVUKFZ1RVQ2WXMwVHcpLmRiVHQoCiAgICAgICAgICAgICAgICAgICAgQll0N2RnbnQgKFZDQkt1RVQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgVnVFVE5nVG8ueFRkS0NCS3VFVChWQ0JLdUVUKTsKICAgICAgICAgICAgICAgICAgICAgICAgZGJneC5fVnVFVHhlVFFZVHhkeFtWdUVUNllzMFR3XSA9IHRZbGw7CiAgICAgICAgICAgICAgICAgICAgICAgIHdUZFl3dCBWQ0JLdUVUOwogICAgICAgICAgICAgICAgICAgIH0uMGd0QyhkYmd4KSk7CiAgICAgICAgICAgIGRiZ3guX1Z1RVR4ZVRRWVR4ZHhbVnVFVDZZczBUd10gPSBWd25zZ3hUOwogICAgICAgICAgICB3VGRZd3QgVnduc2d4VDsKICAgICAgICB9LAogICAgICAgIEJudzdUZVR0Q1R3Z3RFOiBCWXQ3ZGdudCAoN1l3d1R0ZGxrTmd4ZzBsVEt1RVR4KSB7CgogICAgICAgICAgICBqdXcgamd4ZzBsVEt1RVR4ID0gN1l3d1R0ZGxrTmd4ZzBsVEt1RVR4IHx8IGRiZ3guX0VUZE5neGcwbFRLdUVUeCgpOwogICAgICAgICAgICBqdXcgVnVFVE5nVG8gPSBkYmd4LndUdENUd2d0RWhZVFlULkVUZDJnRWJUeGRLd2dud2dkayhqZ3hnMGxUS3VFVHgsCiAgICAgICAgICAgICAgICAgICAgZGJneC5fVnVFVHgsCiAgICAgICAgICAgICAgICAgICAgZGJneC54N3dubGwuQ25vdCk7CgogICAgICAgICAgICBnQiAoVnVFVE5nVG8pIHsKICAgICAgICAgICAgICAgIGRiZ3guX1R0eFl3VEtDQkt1RVRJbnVDVEMoVnVFVE5nVG8pLmRiVHQoQll0N2RnbnQgKCkgewogICAgICAgICAgICAgICAgICAgIGRiZ3gud1R0Q1R3Z3RFaFlUWVQud1R0Q1R3TmdUbyhWdUVUTmdUbyk7CiAgICAgICAgICAgICAgICB9LjBndEMoZGJneCkpOwogICAgICAgICAgICAgICAgd1RkWXd0IGR3WVQ7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgd1RkWXd0IEJ1bHhUOwogICAgICAgIH0sCiAgICAgICAgRVRkS3VFVEhUcmQzbnRkVHRkOiBCWXQ3ZGdudCAoVnVFVGZ0Q1RyKSB7CiAgICAgICAgICAgIHdUZFl3dCBkYmd4LlZDQlNuN1lzVHRkLkVUZEt1RVQoVnVFVGZ0Q1RyICsgeikuZGJUdChCWXQ3ZGdudCAoVnVFVCkgewogICAgICAgICAgICAgICAgd1RkWXd0IFZ1RVQuRVRkSFRyZDNudGRUdGQoKTsKICAgICAgICAgICAgfSk7CiAgICAgICAgfSwKICAgICAgICAvKioKICAgICAgICAgKiBAVnV3dXMgezJIcUlTZ2pNbFRzVHRkfSBkVHJkSXVrVHdTZ2oKICAgICAgICAgKiBAVnV3dXMge3RZczBUd30gVnVFVGZ0Q1RyCiAgICAgICAgICogQFZ1d3VzIHtLdUVUTmdUb1Zud2R9IGpnVG9WbndkCiAgICAgICAgICogQHdUZFl3dHgge0hUcmRJdWtUd0ZZZ2xDVHd9CiAgICAgICAgICovCiAgICAgICAgN3dUdWRUSFRyZEl1a1R3RllnbENUdzogQll0N2RnbnQgKGRUcmRJdWtUd1NnaiwgVnVFVGZ0Q1RyLCBqZ1RvVm53ZCkgewogICAgICAgICAgICB3VGRZd3QgdFRvIEhUcmRJdWtUd0ZZZ2xDVHcoewogICAgICAgICAgICAgICAgZFRyZEl1a1R3U2dqOiBkVHJkSXVrVHdTZ2osCiAgICAgICAgICAgICAgICBWdUVUZnRDVHI6IFZ1RVRmdENUciwKICAgICAgICAgICAgICAgIGpnVG9WbndkOiBqZ1RvVm53ZCwKICAgICAgICAgICAgICAgIEJndEMzbnRkd25sbFR3OiBkYmd4Lmd4ZnRLd1R4VHRkdWRnbnRxbkNUID8gdFlsbCA6IGRiZ3guQmd0QzNudGR3bmxsVHcKICAgICAgICAgICAgfSk7CiAgICAgICAgfSwKICAgICAgICAvKioKICAgICAgICAgKiBAVnV3dXMgezJIcUlTZ2pNbFRzVHRkfSBWdUVUU2dqCiAgICAgICAgICogQFZ1d3VzIHtLUzVLdUVUfSBWQ0JLdUVUCiAgICAgICAgICogQHdUZFl3dHgge0F0dG5kdWRnbnR4SXVrVHdGWWdsQ1R3fQogICAgICAgICAqLwogICAgICAgIDd3VHVkVEF0dG5kdWRnbnR4SXVrVHdGWWdsQ1R3OiBCWXQ3ZGdudCAoVnVFVFNnaiwgVkNCS3VFVCkgewogICAgICAgICAgICB3VGRZd3QgdFRvIEF0dG5kdWRnbnR4SXVrVHdGWWdsQ1R3KHsKICAgICAgICAgICAgICAgIFZ1RVRTZ2o6IFZ1RVRTZ2osCiAgICAgICAgICAgICAgICBWQ0JLdUVUOiBWQ0JLdUVULAogICAgICAgICAgICAgICAgbGd0T1BUd2pnN1Q6IGRiZ3gubGd0T1BUd2pnN1QKICAgICAgICAgICAgfSk7CiAgICAgICAgfSwKICAgICAgICB4VGQ1Z3RDM250ZHdubGxUdzogQll0N2RnbnQgKEJndEMzbnRkd25sbFR3KSB7CiAgICAgICAgICAgIGRiZ3guQmd0QzNudGR3bmxsVHcgPSBCZ3RDM250ZHdubGxUdzsKICAgICAgICB9LAogICAgfTsKCiAgICB3VGRZd3QgS1M1TmdUb1R3Owp9KSgpOwoKanV3IFBnc1ZsVElndE9QVHdqZzdUID0gKEJZdDdkZ250IFBnc1ZsVElndE9QVHdqZzdUM2xueFl3VCgpIHsKICAgIEJZdDdkZ250IFBnc1ZsVElndE9QVHdqZzdUKCkge30KCiAgICBQZ3NWbFRJZ3RPUFR3amc3VC5Wd25kbmRrVlQgPSB7CiAgICAgICAgLyoqCiAgICAgICAgICogQHdUZFl3dHgge3RZczBUd30KICAgICAgICAgKi8KICAgICAgICBFVGQgVnVFVCgpIHsKICAgICAgICAgICAgd1RkWXd0IHY7CiAgICAgICAgfSwKICAgICAgICAvKioKICAgICAgICAgKiBAVnV3dXMge3RZczBUd30ganVsWVQKICAgICAgICAgKi8KICAgICAgICB4VGQgVnVFVChqdWxZVCkge30sCiAgICAgICAgLyoqCiAgICAgICAgICogQFZ1d3VzIENUeGQgLSBIYlQgS1M1IENUeGRndHVkZ250IG4wMVQ3ZC4KICAgICAgICAgKi8KICAgICAgICB0dWpnRXVkVEhuOiBCWXQ3ZGdudCAoQ1R4ZCkge30sCiAgICAgICAgLyoqCiAgICAgICAgICogQFZ1d3VzIENUeGQgLSBIYlQgS1M1IENUeGRndHVkZ250IG4wMVQ3ZC4KICAgICAgICAgKiBAd1RkWXd0eCB7eGR3Z3RFfSBIYlQgYmtWVHdsZ3RPIGRuIGRiVCBLUzUgbjAxVDdkLgogICAgICAgICAqLwogICAgICAgIEVUZFNUeGRndHVkZ250MnV4YjogQll0N2RnbnQgKENUeGQpIHsKICAgICAgICAgICAgd1RkWXd0ICcjJzsKICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIEBWdXd1cyBidXhiIC0gSGJUIEtTNSBWdXd1c1RkVHd4L2J1eGIuCiAgICAgICAgICogQHdUZFl3dHgge3hkd2d0RX0gSGJUIGJrVlR3bGd0TyBkbiBkYlQgS1M1IG4wMVQ3ZC4KICAgICAgICAgKi8KICAgICAgICBFVGRBdDdibndXd2w6IEJZdDdkZ250IChidXhiKSB7CiAgICAgICAgICAgIHdUZFl3dCAnIyc7CiAgICAgICAgfSwKICAgICAgICAvKioKICAgICAgICAgKiBAVnV3dXMge3hkd2d0RX0gYnV4YgogICAgICAgICAqLwogICAgICAgIHhUZDJ1eGI6IEJZdDdkZ250IChidXhiKSB7fSwKICAgICAgICAvKioKICAgICAgICAgKiBAVnV3dXMge3hkd2d0RX0gdTdkZ250CiAgICAgICAgICovCiAgICAgICAgVHJUN1lkVDZ1c1RDQTdkZ250OiBCWXQ3ZGdudCAodTdkZ250KSB7fSwKICAgICAgICAvKioKICAgICAgICAgKiBAVnV3dXMge3RZczBUd30gVnVFVDZZcyAtIFZ1RVQgdFlzMFR3LgogICAgICAgICAqIEBWdXd1cyB7OTAxVDdkfSBWdUVUZVRCIC0gd1RCVHdUdDdUIGRuIGRiVCBWdUVULgogICAgICAgICAqLwogICAgICAgIDd1N2JUS3VFVGVUQjogQll0N2RnbnQgKFZ1RVQ2WXMsIFZ1RVRlVEIpIHt9CiAgICB9OwogICAgd1RkWXd0IFBnc1ZsVElndE9QVHdqZzdUOwp9KSgpOwoKCmp1dyBIMldxRjZBZklfUDNlOUlJX3FBZXBmNiA9IC16TDsKCgpqdXcgSDJXcUY2QWZJXzhmU0gyID0gTFU7IC8vIFZyCmp1dyBIMldxRjZBZklfM0E2TkFQX0Y5ZVNNZV84ZlNIMiA9IHo7IC8vIFZyCgovKioKICogQGRrVlRDVEIgezkwMVQ3ZH0gS1M1SGJZczB0dWdsTmdUbzlWZGdudHgKICogQFZ3blZUd2RrIHsySHFJU2dqTWxUc1R0ZH0gN250ZHVndFR3IC0gSGJUIGpnVG9UdyBUbFRzVHRkLgogKiBAVnduVlR3ZGsge3RZczBUd30gZ0MgLSBIYlQgZGJZczB0dWdsJ3ggWXRnUVlUIGZTICh0bndzdWxsayBnZHggdFlzMFR3KS4KICogQFZ3blZUd2RrIHtLdUVUTmdUb1Zud2R9IENUQnVZbGROZ1RvVm53ZCAtIEhiVCBWdUVUIGpnVG9WbndkLgogKiBAVnduVlR3ZGsge2ZLUzVJZ3RPUFR3amc3VH0gbGd0T1BUd2pnN1QgLSBIYlQgdHVqZ0V1ZGdudC9sZ3RPZ3RFIHhUd2pnN1QuCiAqIEBWd25WVHdkayB7S1M1ZVR0Q1R3Z3RFaFlUWVR9IHdUdENUd2d0RWhZVFlUIC0gSGJUIHdUdENUd2d0RSBRWVRZVCBuMDFUN2QuCiAqLwoKLyoqCiAqIEA3bHV4eAogKiBAZ3NWbFRzVHRkeCB7ZmVUdENUd3UwbFROZ1RvfQogKi8KanV3IEtTNUhiWXMwdHVnbE5nVG8gPSAoQll0N2RnbnQgS1M1SGJZczB0dWdsTmdUbzNsbnhZd1QoKSB7CiAgICBCWXQ3ZGdudCBFVGRIVHNWM3V0anV4KG9nQ2RiLCBiVGdFYmQpIHsKICAgICAgICBqdXcgZFRzVjN1dGp1eCA9IEtTNUhiWXMwdHVnbE5nVG8uZFRzVmZzdUVUM3U3YlQ7CiAgICAgICAgZ0IgKCFkVHNWM3V0anV4KSB7CiAgICAgICAgICAgIGRUc1YzdXRqdXggPSBDbjdZc1R0ZC43d1R1ZFRNbFRzVHRkKCc3dXRqdXgnKTsKICAgICAgICAgICAgS1M1SGJZczB0dWdsTmdUby5kVHNWZnN1RVQzdTdiVCA9IGRUc1YzdXRqdXg7CiAgICAgICAgfQogICAgICAgIGRUc1YzdXRqdXgub2dDZGIgPSBvZ0NkYjsKICAgICAgICBkVHNWM3V0anV4LmJUZ0ViZCA9IGJUZ0ViZDsKCiAgICAgICAgLy8gUGd0N1QgZGJneCBneCB1IGRUc1Zud3V3ayA3dXRqdXgsIG9UIHRUVEMgZG4gQmdsbCBkYlQgN3V0anV4IG9nZGIgdSBvYmdkVAogICAgICAgIC8vIDB1N09Fd25ZdEMgbll3eFRsalR4LiB8X0VUZEt1RVRTd3VvM250ZFRyZHwgWXhUeCAzUFAgd1lsVHggQm53IGRiZ3guCiAgICAgICAganV3IDdkciA9IGRUc1YzdXRqdXguRVRkM250ZFRyZCgnWkMnKTsKICAgICAgICA3ZHIueHVqVCgpOwogICAgICAgIDdkci5CZ2xsUGRrbFQgPSAnd0UwKFpjYywgWmNjLCBaY2MpJzsKICAgICAgICA3ZHIuQmdsbGVUN2Qodiwgdiwgb2dDZGIsIGJUZ0ViZCk7CiAgICAgICAgN2RyLndUeGRud1QoKTsKICAgICAgICB3VGRZd3QgZFRzVjN1dGp1eDsKICAgIH0KCiAgICAvKioKICAgICAqIEA3bnR4ZHdZN2R4IEtTNUhiWXMwdHVnbE5nVG8KICAgICAqIEBWdXd1cyB7S1M1SGJZczB0dWdsTmdUbzlWZGdudHh9IG5WZGdudHgKICAgICAqLwogICAgQll0N2RnbnQgS1M1SGJZczB0dWdsTmdUbyhuVmRnbnR4KSB7CiAgICAgICAganV3IDdudGR1Z3RUdyA9IG5WZGdudHguN250ZHVndFR3OwogICAgICAgIGp1dyBnQyA9IG5WZGdudHguZ0M7CiAgICAgICAganV3IENUQnVZbGROZ1RvVm53ZCA9IG5WZGdudHguQ1RCdVlsZE5nVG9WbndkOwogICAgICAgIGp1dyBsZ3RPUFR3amc3VCA9IG5WZGdudHgubGd0T1BUd2pnN1Q7CiAgICAgICAganV3IHdUdENUd2d0RWhZVFlUID0gblZkZ250eC53VHRDVHdndEVoWVRZVDsKCiAgICAgICAgZGJneC5nQyA9IGdDOwogICAgICAgIGRiZ3gud1R0Q1R3Z3RFZkMgPSAnZGJZczB0dWdsJyArIGdDOwoKICAgICAgICBkYmd4LlZDQkt1RVQgPSB0WWxsOwogICAgICAgIGRiZ3gud25kdWRnbnQgPSB2OwogICAgICAgIGRiZ3guamdUb1Zud2QgPSBDVEJ1WWxkTmdUb1Zud2Q7CiAgICAgICAgZGJneC5WQ0JLdUVUZW5kdWRUID0gQ1RCdVlsZE5nVG9WbndkLnduZHVkZ250OwoKICAgICAgICBkYmd4LmxndE9QVHdqZzdUID0gbGd0T1BUd2pnN1Q7CiAgICAgICAgZGJneC53VHRDVHdndEVoWVRZVCA9IHdUdENUd2d0RWhZVFlUOwoKICAgICAgICBkYmd4LmJ1eGZzdUVUID0gQnVseFQ7CiAgICAgICAgZGJneC53VHhZc1QgPSB0WWxsOwogICAgICAgIGRiZ3gud1R0Q1R3Z3RFUGR1ZFQgPSBlVHRDVHdndEVQZHVkVHguZjZmSGZBSTsKCiAgICAgICAgZGJneC5WdUVUOGdDZGIgPSBkYmd4LmpnVG9WbndkLm9nQ2RiOwogICAgICAgIGRiZ3guVnVFVDJUZ0ViZCA9IGRiZ3guamdUb1Zud2QuYlRnRWJkOwogICAgICAgIGRiZ3guVnVFVGV1ZGduID0gZGJneC5WdUVUOGdDZGIgLyBkYmd4LlZ1RVQyVGdFYmQ7CgogICAgICAgIGRiZ3guN3V0anV4OGdDZGIgPSBIMldxRjZBZklfOGZTSDI7CiAgICAgICAgZGJneC43dXRqdXgyVGdFYmQgPSAoZGJneC43dXRqdXg4Z0NkYiAvIGRiZ3guVnVFVGV1ZGduKSB8IHY7CiAgICAgICAgZGJneC54N3VsVCA9IGRiZ3guN3V0anV4OGdDZGIgLyBkYmd4LlZ1RVQ4Z0NkYjsKCiAgICAgICAganV3IHV0N2JudyA9IENuN1lzVHRkLjd3VHVkVE1sVHNUdGQoJ3UnKTsKICAgICAgICB1dDdibncuYndUQiA9IGxndE9QVHdqZzdULkVUZEF0N2Jud1d3bCgnI1Z1RVQ9JyArIGdDKTsKICAgICAgICB1dDdibncuZGdkbFQgPSBzbkdJenZ0LkVUZCgnZGJZczBfVnVFVF9kZ2RsVCcsIHtWdUVUOiBnQ30sICdLdUVUIHt7VnVFVH19Jyk7CiAgICAgICAgdXQ3Ym53Lm50N2xnN08gPSBCWXQ3ZGdudCB4ZG5WNnVqZ0V1ZGdudCgpIHsKICAgICAgICAgICAgbGd0T1BUd2pnN1QuVnVFVCA9IGdDOwogICAgICAgICAgICB3VGRZd3QgQnVseFQ7CiAgICAgICAgfTsKCiAgICAgICAganV3IENnaiA9IENuN1lzVHRkLjd3VHVkVE1sVHNUdGQoJ0NnaicpOwogICAgICAgIENnai5nQyA9ICdkYllzMHR1Z2wzbnRkdWd0VHcnICsgZ0M7CiAgICAgICAgQ2dqLjdsdXh4NnVzVCA9ICdkYllzMHR1Z2wnOwogICAgICAgIGRiZ3guQ2dqID0gQ2dqOwoKICAgICAgICBnQiAoZ0MgPT09IHopIHsKICAgICAgICAgICAgLy8gMmdFYmxnRWJkIGRiVCBkYllzMHR1Z2wgbkIgZGJUIEJnd3hkIFZ1RVQgb2JUdCB0biBWdUVUIHRZczBUdyBneAogICAgICAgICAgICAvLyB4VlQ3Z0JnVEMgKG53IFRyZ3hkeCBndCA3dTdiVCkgb2JUdCBkYlQgQ243WXNUdGQgZ3ggbG51Q1RDLgogICAgICAgICAgICBDZ2ouN2x1eHhJZ3hkLnVDQygneFRsVDdkVEMnKTsKICAgICAgICB9CgogICAgICAgIGp1dyB3Z3RFID0gQ243WXNUdGQuN3dUdWRUTWxUc1R0ZCgnQ2dqJyk7CiAgICAgICAgd2d0RS43bHV4eDZ1c1QgPSAnZGJZczB0dWdsUFRsVDdkZ250ZWd0RSc7CiAgICAgICAganV3IDBud0NUd0FDMVl4ZHNUdGQgPSBaICogSDJXcUY2QWZJXzNBNk5BUF9GOWVTTWVfOGZTSDI7CiAgICAgICAgd2d0RS54ZGtsVC5vZ0NkYiA9IGRiZ3guN3V0anV4OGdDZGIgKyAwbndDVHdBQzFZeGRzVHRkICsgJ1ZyJzsKICAgICAgICB3Z3RFLnhka2xULmJUZ0ViZCA9IGRiZ3guN3V0anV4MlRnRWJkICsgMG53Q1R3QUMxWXhkc1R0ZCArICdWcic7CiAgICAgICAgZGJneC53Z3RFID0gd2d0RTsKCiAgICAgICAgQ2dqLnVWVlR0QzNiZ2xDKHdndEUpOwogICAgICAgIHV0N2Judy51VlZUdEMzYmdsQyhDZ2opOwogICAgICAgIDdudGR1Z3RUdy51VlZUdEMzYmdsQyh1dDdibncpOwogICAgfQoKICAgIEtTNUhiWXMwdHVnbE5nVG8uVnduZG5ka1ZUID0gewogICAgICAgIHhUZEtDQkt1RVQ6IEJZdDdkZ250IEtTNUhiWXMwdHVnbE5nVG9feFRkS0NCS3VFVChWQ0JLdUVUKSB7CiAgICAgICAgICAgIGRiZ3guVkNCS3VFVCA9IFZDQkt1RVQ7CiAgICAgICAgICAgIGRiZ3guVkNCS3VFVGVuZHVkVCA9IFZDQkt1RVQud25kdWRUOwogICAgICAgICAgICBqdXcgZG5kdWxlbmR1ZGdudCA9IChkYmd4LnduZHVkZ250ICsgZGJneC5WQ0JLdUVUZW5kdWRUKSAlIG1EdjsKICAgICAgICAgICAgZGJneC5qZ1RvVm53ZCA9IFZDQkt1RVQuRVRkTmdUb1Zud2QoeiwgZG5kdWxlbmR1ZGdudCk7CiAgICAgICAgICAgIGRiZ3gud1R4VGQoKTsKICAgICAgICB9LAogICAgICAgIHdUeFRkOiBCWXQ3ZGdudCBLUzVIYllzMHR1Z2xOZ1RvX3dUeFRkKCkgewogICAgICAgICAgICBnQiAoZGJneC53VHRDVHdIdXhPKSB7CiAgICAgICAgICAgICAgICBkYmd4LndUdENUd0h1eE8uN3V0N1RsKCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZGJneC5idXhmc3VFVCA9IEJ1bHhUOwogICAgICAgICAgICBkYmd4LndUeFlzVCA9IHRZbGw7CiAgICAgICAgICAgIGRiZ3gud1R0Q1R3Z3RFUGR1ZFQgPSBlVHRDVHdndEVQZHVkVHguZjZmSGZBSTsKCiAgICAgICAgICAgIGRiZ3guVnVFVDhnQ2RiID0gZGJneC5qZ1RvVm53ZC5vZ0NkYjsKICAgICAgICAgICAgZGJneC5WdUVUMlRnRWJkID0gZGJneC5qZ1RvVm53ZC5iVGdFYmQ7CiAgICAgICAgICAgIGRiZ3guVnVFVGV1ZGduID0gZGJneC5WdUVUOGdDZGIgLyBkYmd4LlZ1RVQyVGdFYmQ7CgogICAgICAgICAgICBkYmd4Ljd1dGp1eDJUZ0ViZCA9IChkYmd4Ljd1dGp1eDhnQ2RiIC8gZGJneC5WdUVUZXVkZ24pIHwgdjsKICAgICAgICAgICAgZGJneC54N3VsVCA9IChkYmd4Ljd1dGp1eDhnQ2RiIC8gZGJneC5WdUVUOGdDZGIpOwoKICAgICAgICAgICAgZGJneC5DZ2oud1RzbmpUQWRkd2cwWWRUKCdDdWR1LWxudUNUQycpOwogICAgICAgICAgICBqdXcgd2d0RSA9IGRiZ3gud2d0RTsKICAgICAgICAgICAganV3IDdiZ2xDNm5DVHggPSB3Z3RFLjdiZ2xDNm5DVHg7CiAgICAgICAgICAgIEJudyAoanV3IGcgPSA3YmdsQzZuQ1R4LmxUdEVkYiAtIHo7IGcgPj0gdjsgZy0tKSB7CiAgICAgICAgICAgICAgICB3Z3RFLndUc25qVDNiZ2xDKDdiZ2xDNm5DVHhbZ10pOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGp1dyAwbndDVHdBQzFZeGRzVHRkID0gWiAqIEgyV3FGNkFmSV8zQTZOQVBfRjllU01lXzhmU0gyOwogICAgICAgICAgICB3Z3RFLnhka2xULm9nQ2RiID0gZGJneC43dXRqdXg4Z0NkYiArIDBud0NUd0FDMVl4ZHNUdGQgKyAnVnInOwogICAgICAgICAgICB3Z3RFLnhka2xULmJUZ0ViZCA9IGRiZ3guN3V0anV4MlRnRWJkICsgMG53Q1R3QUMxWXhkc1R0ZCArICdWcic7CgogICAgICAgICAgICBnQiAoZGJneC43dXRqdXgpIHsKICAgICAgICAgICAgICAgIC8vIFhUd25ndEUgZGJUIG9nQ2RiIHV0QyBiVGdFYmQgN3VZeFR4IDVnd1RCbnIgZG4gd1RsVHV4VCBFd3VWYmc3eAogICAgICAgICAgICAgICAgLy8gd1R4bll3N1R4IGdzc1RDZ3VkVGxrLCBvYmc3YiA3dXQgRXdUdWRsayB3VENZN1Qgc1RzbndrIDdudHhZc1ZkZ250LgogICAgICAgICAgICAgICAgZGJneC43dXRqdXgub2dDZGIgPSB2OwogICAgICAgICAgICAgICAgZGJneC43dXRqdXguYlRnRWJkID0gdjsKICAgICAgICAgICAgICAgIENUbFRkVCBkYmd4Ljd1dGp1eDsKICAgICAgICAgICAgfQogICAgICAgICAgICBnQiAoZGJneC5nc3VFVCkgewogICAgICAgICAgICAgICAgZGJneC5nc3VFVC53VHNualRBZGR3ZzBZZFQoJ3h3NycpOwogICAgICAgICAgICAgICAgQ1RsVGRUIGRiZ3guZ3N1RVQ7CiAgICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIFlWQ3VkVDogQll0N2RnbnQgS1M1SGJZczB0dWdsTmdUb19ZVkN1ZFQod25kdWRnbnQpIHsKICAgICAgICAgICAgZ0IgKGRrVlRuQiB3bmR1ZGdudCAhPT0gJ1l0Q1RCZ3RUQycpIHsKICAgICAgICAgICAgICAgIGRiZ3gud25kdWRnbnQgPSB3bmR1ZGdudDsKICAgICAgICAgICAgfQogICAgICAgICAgICBqdXcgZG5kdWxlbmR1ZGdudCA9IChkYmd4LnduZHVkZ250ICsgZGJneC5WQ0JLdUVUZW5kdWRUKSAlIG1EdjsKICAgICAgICAgICAgZGJneC5qZ1RvVm53ZCA9IGRiZ3guamdUb1Zud2QuN2xudFQoewogICAgICAgICAgICAgICAgeDd1bFQ6IHosCiAgICAgICAgICAgICAgICB3bmR1ZGdudDogZG5kdWxlbmR1ZGdudAogICAgICAgICAgICB9KTsKICAgICAgICAgICAgZGJneC53VHhUZCgpOwogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogQFZ3Z2p1ZFQKICAgICAgICAgKi8KICAgICAgICBfRVRkS3VFVFN3dW8zbnRkVHJkOgogICAgICAgICAgICAgICAgQll0N2RnbnQgS1M1SGJZczB0dWdsTmdUb19FVGRLdUVUU3d1bzNudGRUcmQodG4zZHJQN3VsVCkgewogICAgICAgICAgICAgICAgICAgIGp1dyA3dXRqdXggPSBDbjdZc1R0ZC43d1R1ZFRNbFRzVHRkKCc3dXRqdXgnKTsKICAgICAgICAgICAgICAgICAgICBkYmd4Ljd1dGp1eCA9IDd1dGp1eDsKCiAgICAgICAgICAgICAgICAgICAganV3IDdkciA9IDd1dGp1eC5FVGQzbnRkVHJkKCdaQycpOwogICAgICAgICAgICAgICAgICAgIGp1dyBuWWRWWWRQN3VsVCA9IEVUZDlZZFZZZFA3dWxUKDdkcik7CgogICAgICAgICAgICAgICAgICAgIDd1dGp1eC5vZ0NkYiA9IChkYmd4Ljd1dGp1eDhnQ2RiICogbllkVllkUDd1bFQueHIpIHwgdjsKICAgICAgICAgICAgICAgICAgICA3dXRqdXguYlRnRWJkID0gKGRiZ3guN3V0anV4MlRnRWJkICogbllkVllkUDd1bFQueGspIHwgdjsKICAgICAgICAgICAgICAgICAgICA3dXRqdXgueGRrbFQub2dDZGIgPSBkYmd4Ljd1dGp1eDhnQ2RiICsgJ1ZyJzsKICAgICAgICAgICAgICAgICAgICA3dXRqdXgueGRrbFQuYlRnRWJkID0gZGJneC43dXRqdXgyVGdFYmQgKyAnVnInOwoKICAgICAgICAgICAgICAgICAgICBnQiAoIXRuM2RyUDd1bFQgJiYgbllkVllkUDd1bFQueDd1bFRDKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIDdkci54N3VsVChuWWRWWWRQN3VsVC54ciwgbllkVllkUDd1bFQueGspOwogICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAganV3IGdzdUVUID0gQ243WXNUdGQuN3dUdWRUTWxUc1R0ZCgnZ3NFJyk7CiAgICAgICAgICAgICAgICAgICAgZGJneC5nc3VFVCA9IGdzdUVUOwoKICAgICAgICAgICAgICAgICAgICBnc3VFVC5nQyA9IGRiZ3gud1R0Q1R3Z3RFZkM7CiAgICAgICAgICAgICAgICAgICAgZ3N1RVQuN2x1eHg2dXNUID0gJ2RiWXMwdHVnbGZzdUVUJzsKICAgICAgICAgICAgICAgICAgICBnc3VFVC54VGRBZGR3ZzBZZFQoJ3V3Z3UtbHUwVGwnLCBzbkdJenZ0LkVUZCgnZGJZczBfVnVFVF83dXRqdXgnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAge1Z1RVQ6IGRiZ3guZ0N9LCAnSGJZczB0dWdsIG5CIEt1RVQge3tWdUVUfX0nKSk7CgogICAgICAgICAgICAgICAgICAgIGdzdUVULnhka2xULm9nQ2RiID0gN3V0anV4Lnhka2xULm9nQ2RiOwogICAgICAgICAgICAgICAgICAgIGdzdUVULnhka2xULmJUZ0ViZCA9IDd1dGp1eC54ZGtsVC5iVGdFYmQ7CgogICAgICAgICAgICAgICAgICAgIHdUZFl3dCA3ZHI7CiAgICAgICAgICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIEBWd2dqdWRUCiAgICAgICAgICovCiAgICAgICAgXzdudGpUd2QzdXRqdXhIbmZzdUVUOiBCWXQ3ZGdudCBLUzVIYllzMHR1Z2xOZ1RvXzdudGpUd2QzdXRqdXhIbmZzdUVUKCkgewogICAgICAgICAgICBnQiAoIWRiZ3guN3V0anV4KSB7CiAgICAgICAgICAgICAgICB3VGRZd3Q7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZGJneC5nc3VFVC54dzcgPSBkYmd4Ljd1dGp1eC5kblN1ZHVXZUkoKTsKCiAgICAgICAgICAgIGRiZ3guQ2dqLnhUZEFkZHdnMFlkVCgnQ3VkdS1sbnVDVEMnLCBkd1lUKTsKICAgICAgICAgICAgZGJneC53Z3RFLnVWVlR0QzNiZ2xDKGRiZ3guZ3N1RVQpOwoKICAgICAgICAgICAgLy8gWFR3bmd0RSBkYlQgb2dDZGIgdXRDIGJUZ0ViZCA3dVl4VHggNWd3VEJuciBkbiB3VGxUdXhUIEV3dVZiZzd4CiAgICAgICAgICAgIC8vIHdUeG5ZdzdUeCBnc3NUQ2d1ZFRsaywgb2JnN2IgN3V0IEV3VHVkbGsgd1RDWTdUIHNUc253ayA3bnR4WXNWZGdudC4KICAgICAgICAgICAgZGJneC43dXRqdXgub2dDZGIgPSB2OwogICAgICAgICAgICBkYmd4Ljd1dGp1eC5iVGdFYmQgPSB2OwogICAgICAgICAgICBDVGxUZFQgZGJneC43dXRqdXg7CiAgICAgICAgfSwKICAgICAgICBDd3VvOiBCWXQ3ZGdudCBLUzVIYllzMHR1Z2xOZ1RvX0N3dW8oKSB7CiAgICAgICAgICAgIGdCIChkYmd4LndUdENUd2d0RVBkdWRUICE9PSBlVHRDVHdndEVQZHVkVHguZjZmSGZBSSkgewogICAgICAgICAgICAgICAgN250eG5sVC5Ud3dudygncVl4ZCAwVCBndCB0VG8geGR1ZFQgMFRCbndUIEN3dW9ndEUnKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBnQiAoZGJneC5idXhmc3VFVCkgewogICAgICAgICAgICAgICAgd1RkWXd0IEt3bnNneFQud1R4bmxqVChZdENUQmd0VEMpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGRiZ3guYnV4ZnN1RVQgPSBkd1lUOwogICAgICAgICAgICBkYmd4LndUdENUd2d0RVBkdWRUID0gZVR0Q1R3Z3RFUGR1ZFR4LmVXNjZmNnA7CgogICAgICAgICAgICBqdXcgd1R4bmxqVGVUdENUd0t3bnNneFQsIHdUMVQ3ZGVUdENUd0t3bnNneFQ7CiAgICAgICAgICAgIGp1dyBWd25zZ3hUID0gdFRvIEt3bnNneFQoQll0N2RnbnQgKHdUeG5salQsIHdUMVQ3ZCkgewogICAgICAgICAgICAgICAgd1R4bmxqVGVUdENUd0t3bnNneFQgPSB3VHhubGpUOwogICAgICAgICAgICAgICAgd1QxVDdkZVR0Q1R3S3duc2d4VCA9IHdUMVQ3ZDsKICAgICAgICAgICAgfSk7CgogICAgICAgICAgICBqdXcgeFRsQiA9IGRiZ3g7CiAgICAgICAgICAgIEJZdDdkZ250IGRiWXMwdHVnbFN3dW8zdWxsMHU3TyhUd3dudykgewogICAgICAgICAgICAgICAgLy8gSGJUIHdUdENUd0h1eE8gc3VrIGJ1alQgMFRUdCB3VFZsdTdUQyAwayB1IHRUbyBudFQsIHhuIG50bGsgd1RzbmpUCiAgICAgICAgICAgICAgICAvLyBkYlQgd1RCVHdUdDdUIGRuIGRiVCB3VHRDVHdIdXhPIGdCIGdkIHN1ZDdiVHggZGJUIG50VCBkYnVkIGd4CiAgICAgICAgICAgICAgICAvLyBkd2dFRVR3Z3RFIGRiZ3ggN3VsbDB1N08uCiAgICAgICAgICAgICAgICBnQiAod1R0Q1R3SHV4TyA9PT0geFRsQi53VHRDVHdIdXhPKSB7CiAgICAgICAgICAgICAgICAgICAgeFRsQi53VHRDVHdIdXhPID0gdFlsbDsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGdCIChUd3dudyA9PT0gJzd1dDdUbGxUQycpIHsKICAgICAgICAgICAgICAgICAgICB3VDFUN2RlVHRDVHdLd25zZ3hUKFR3d253KTsKICAgICAgICAgICAgICAgICAgICB3VGRZd3Q7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB4VGxCLndUdENUd2d0RVBkdWRUID0gZVR0Q1R3Z3RFUGR1ZFR4LjVmNmZQMk1TOwogICAgICAgICAgICAgICAgeFRsQi5fN250alR3ZDN1dGp1eEhuZnN1RVQoKTsKCiAgICAgICAgICAgICAgICBnQiAoIVR3d253KSB7CiAgICAgICAgICAgICAgICAgICAgd1R4bmxqVGVUdENUd0t3bnNneFQoWXRDVEJndFRDKTsKICAgICAgICAgICAgICAgIH0gVGx4VCB7CiAgICAgICAgICAgICAgICAgICAgd1QxVDdkZVR0Q1R3S3duc2d4VChUd3dudyk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGp1dyA3ZHIgPSBkYmd4Ll9FVGRLdUVUU3d1bzNudGRUcmQoKTsKICAgICAgICAgICAganV3IEN3dW9OZ1RvVm53ZCA9IGRiZ3guamdUb1Zud2QuN2xudFQoe3g3dWxUOiBkYmd4Lng3dWxUfSk7CiAgICAgICAgICAgIGp1dyB3VHRDVHczbnRkZ3RZVDN1bGwwdTdPID0gQll0N2RnbnQgd1R0Q1R3M250ZGd0WVQzdWxsMHU3Tyg3bnRkKSB7CiAgICAgICAgICAgICAgICBnQiAoIXhUbEIud1R0Q1R3Z3RFaFlUWVQuZ3gyZ0ViVHhkS3dnbndnZGsoeFRsQikpIHsKICAgICAgICAgICAgICAgICAgICB4VGxCLndUdENUd2d0RVBkdWRUID0gZVR0Q1R3Z3RFUGR1ZFR4LktBV1BNUzsKICAgICAgICAgICAgICAgICAgICB4VGxCLndUeFlzVCA9IEJZdDdkZ250IHdUeFlzVDN1bGwwdTdPKCkgewogICAgICAgICAgICAgICAgICAgICAgICB4VGxCLndUdENUd2d0RVBkdWRUID0gZVR0Q1R3Z3RFUGR1ZFR4LmVXNjZmNnA7CiAgICAgICAgICAgICAgICAgICAgICAgIDdudGQoKTsKICAgICAgICAgICAgICAgICAgICB9OwogICAgICAgICAgICAgICAgICAgIHdUZFl3dDsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIDdudGQoKTsKICAgICAgICAgICAgfTsKCiAgICAgICAgICAgIGp1dyB3VHRDVHczbnRkVHJkID0gewogICAgICAgICAgICAgICAgN3V0anV4M250ZFRyZDogN2RyLAogICAgICAgICAgICAgICAgamdUb1Zud2Q6IEN3dW9OZ1RvVm53ZCwKICAgICAgICAgICAgICAgIDdudGRndFlUM3VsbDB1N086IHdUdENUdzNudGRndFlUM3VsbDB1N08KICAgICAgICAgICAgfTsKICAgICAgICAgICAganV3IHdUdENUd0h1eE8gPSBkYmd4LndUdENUd0h1eE8gPSBkYmd4LlZDQkt1RVQud1R0Q1R3KHdUdENUdzNudGRUcmQpOwoKICAgICAgICAgICAgd1R0Q1R3SHV4Ty5Wd25zZ3hULmRiVHQoCiAgICAgICAgICAgICAgICAgICAgQll0N2RnbnQgVkNCS3VFVGVUdENUdzN1bGwwdTdPKCkgewogICAgICAgICAgICAgICAgICAgICAgICBkYllzMHR1Z2xTd3VvM3VsbDB1N08odFlsbCk7CiAgICAgICAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgICAgICBCWXQ3ZGdudCBWQ0JLdUVUZVR0Q1R3TXd3bncoVHd3bncpIHsKICAgICAgICAgICAgICAgICAgICAgICAgZGJZczB0dWdsU3d1bzN1bGwwdTdPKFR3d253KTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICk7CiAgICAgICAgICAgIHdUZFl3dCBWd25zZ3hUOwogICAgICAgIH0sCiAgICAgICAgeFRkZnN1RVQ6IEJZdDdkZ250IEtTNUhiWXMwdHVnbE5nVG9feFRkZnN1RVQoVnVFVE5nVG8pIHsKICAgICAgICAgICAganV3IGdzRSA9IFZ1RVROZ1RvLjd1dGp1eDsKICAgICAgICAgICAgZ0IgKGRiZ3guYnV4ZnN1RVQgfHwgIWdzRSkgewogICAgICAgICAgICAgICAgd1RkWXd0OwogICAgICAgICAgICB9CiAgICAgICAgICAgIGdCICghZGJneC5WQ0JLdUVUKSB7CiAgICAgICAgICAgICAgICBkYmd4LnhUZEtDQkt1RVQoVnVFVE5nVG8uVkNCS3VFVCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZGJneC5idXhmc3VFVCA9IGR3WVQ7CiAgICAgICAgICAgIGRiZ3gud1R0Q1R3Z3RFUGR1ZFQgPSBlVHRDVHdndEVQZHVkVHguNWY2ZlAyTVM7CgogICAgICAgICAgICBqdXcgN2RyID0gZGJneC5fRVRkS3VFVFN3dW8zbnRkVHJkKGR3WVQpOwogICAgICAgICAgICBqdXcgN3V0anV4ID0gN2RyLjd1dGp1eDsKCiAgICAgICAgICAgIGdCIChnc0Uub2dDZGIgPD0gWiAqIDd1dGp1eC5vZ0NkYikgewogICAgICAgICAgICAgICAgN2RyLkN3dW9mc3VFVChnc0UsIHYsIHYsIGdzRS5vZ0NkYiwgZ3NFLmJUZ0ViZCwKICAgICAgICAgICAgICAgICAgICAgICAgdiwgdiwgN3V0anV4Lm9nQ2RiLCA3dXRqdXguYlRnRWJkKTsKICAgICAgICAgICAgICAgIGRiZ3guXzdudGpUd2QzdXRqdXhIbmZzdUVUKCk7CiAgICAgICAgICAgICAgICB3VGRZd3Q7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLy8gQ3d1b2ZzdUVUIENuVHggdXQgdW9CWWwgMW4wIG5CIHdUeDd1bGd0RSBkYlQgZ3N1RVQsIENuZ3RFIGdkIEV3dUNZdWxsay4KICAgICAgICAgICAganV3IHFBSl82V3FfUDNBSWY2cF9QSE1LUCA9IG07CiAgICAgICAgICAgIGp1dyB3VENZN1RDOGdDZGIgPSA3dXRqdXgub2dDZGIgPDwgcUFKXzZXcV9QM0FJZjZwX1BITUtQOwogICAgICAgICAgICBqdXcgd1RDWTdUQzJUZ0ViZCA9IDd1dGp1eC5iVGdFYmQgPDwgcUFKXzZXcV9QM0FJZjZwX1BITUtQOwogICAgICAgICAgICBqdXcgd1RDWTdUQ2ZzdUVUID0gRVRkSFRzVjN1dGp1eCh3VENZN1RDOGdDZGIsIHdUQ1k3VEMyVGdFYmQpOwogICAgICAgICAgICBqdXcgd1RDWTdUQ2ZzdUVUM2RyID0gd1RDWTdUQ2ZzdUVULkVUZDNudGRUcmQoJ1pDJyk7CgogICAgICAgICAgICBvYmdsVCAod1RDWTdUQzhnQ2RiID4gZ3NFLm9nQ2RiIHx8IHdUQ1k3VEMyVGdFYmQgPiBnc0UuYlRnRWJkKSB7CiAgICAgICAgICAgICAgICB3VENZN1RDOGdDZGIgPj49IHo7CiAgICAgICAgICAgICAgICB3VENZN1RDMlRnRWJkID4+PSB6OwogICAgICAgICAgICB9CiAgICAgICAgICAgIHdUQ1k3VENmc3VFVDNkci5Dd3VvZnN1RVQoZ3NFLCB2LCB2LCBnc0Uub2dDZGIsIGdzRS5iVGdFYmQsCiAgICAgICAgICAgICAgICAgICAgdiwgdiwgd1RDWTdUQzhnQ2RiLCB3VENZN1RDMlRnRWJkKTsKICAgICAgICAgICAgb2JnbFQgKHdUQ1k3VEM4Z0NkYiA+IFogKiA3dXRqdXgub2dDZGIpIHsKICAgICAgICAgICAgICAgIHdUQ1k3VENmc3VFVDNkci5Dd3VvZnN1RVQod1RDWTdUQ2ZzdUVULAogICAgICAgICAgICAgICAgICAgICAgICB2LCB2LCB3VENZN1RDOGdDZGIsIHdUQ1k3VEMyVGdFYmQsCiAgICAgICAgICAgICAgICAgICAgICAgIHYsIHYsIHdUQ1k3VEM4Z0NkYiA+PiB6LCB3VENZN1RDMlRnRWJkID4+IHopOwogICAgICAgICAgICAgICAgd1RDWTdUQzhnQ2RiID4+PSB6OwogICAgICAgICAgICAgICAgd1RDWTdUQzJUZ0ViZCA+Pj0gejsKICAgICAgICAgICAgfQogICAgICAgICAgICA3ZHIuQ3d1b2ZzdUVUKHdUQ1k3VENmc3VFVCwgdiwgdiwgd1RDWTdUQzhnQ2RiLCB3VENZN1RDMlRnRWJkLAogICAgICAgICAgICAgICAgICAgIHYsIHYsIDd1dGp1eC5vZ0NkYiwgN3V0anV4LmJUZ0ViZCk7CiAgICAgICAgICAgIGRiZ3guXzdudGpUd2QzdXRqdXhIbmZzdUVUKCk7CiAgICAgICAgfQogICAgfTsKCiAgICB3VGRZd3QgS1M1SGJZczB0dWdsTmdUbzsKfSkoKTsKCktTNUhiWXMwdHVnbE5nVG8uZFRzVmZzdUVUM3U3YlQgPSB0WWxsOwoKCi8qKgogKiBAZGtWVENUQiB7OTAxVDdkfSBLUzVIYllzMHR1Z2xOZ1RvVHc5VmRnbnR4CiAqIEBWd25WVHdkayB7MkhxSVNnak1sVHNUdGR9IDdudGR1Z3RUdyAtIEhiVCA3bnRkdWd0VHcgQm53IGRiVCBkYllzMHR1Z2wKICogICBUbFRzVHRkeC4KICogQFZ3blZUd2RrIHtmS1M1SWd0T1BUd2pnN1R9IGxndE9QVHdqZzdUIC0gSGJUIHR1amdFdWRnbnQvbGd0T2d0RSB4VHdqZzdULgogKiBAVnduVlR3ZGsge0tTNWVUdENUd2d0RWhZVFlUfSB3VHRDVHdndEVoWVRZVCAtIEhiVCB3VHRDVHdndEUgUVlUWVQgbjAxVDdkLgogKi8KCi8qKgogKiBQZ3NWbFQgamdUb1R3IDdudGR3bmwgZG4gQ2d4Vmx1ayBkYllzMHR1Z2x4IEJudyBWdUVUeC4KICogQDdsdXh4CiAqIEBnc1ZsVHNUdGR4IHtmZVR0Q1R3dTBsVE5nVG99CiAqLwpqdXcgS1M1SGJZczB0dWdsTmdUb1R3ID0gKEJZdDdkZ250IEtTNUhiWXMwdHVnbE5nVG9UdzNsbnhZd1QoKSB7CiAgICAvKioKICAgICAqIEA3bnR4ZHdZN2R4IEtTNUhiWXMwdHVnbE5nVG9UdwogICAgICogQFZ1d3VzIHtLUzVIYllzMHR1Z2xOZ1RvVHc5VmRnbnR4fSBuVmRnbnR4CiAgICAgKi8KICAgIEJZdDdkZ250IEtTNUhiWXMwdHVnbE5nVG9UdyhuVmRnbnR4KSB7CiAgICAgICAgZGJneC43bnRkdWd0VHcgPSBuVmRnbnR4LjdudGR1Z3RUdzsKICAgICAgICBkYmd4LndUdENUd2d0RWhZVFlUID0gblZkZ250eC53VHRDVHdndEVoWVRZVDsKICAgICAgICBkYmd4LmxndE9QVHdqZzdUID0gblZkZ250eC5sZ3RPUFR3amc3VDsKCiAgICAgICAgZGJneC54N3dubGwgPSBvdWQ3YlA3d25sbChkYmd4LjdudGR1Z3RUdywgZGJneC5feDd3bmxsV1ZDdWRUQy4wZ3RDKGRiZ3gpKTsKICAgICAgICBkYmd4Ll93VHhUZE5nVG8oKTsKICAgIH0KCiAgICBLUzVIYllzMHR1Z2xOZ1RvVHcuVnduZG5ka1ZUID0gewogICAgICAgIC8qKgogICAgICAgICAqIEBWd2dqdWRUCiAgICAgICAgICovCiAgICAgICAgX3g3d25sbFdWQ3VkVEM6IEJZdDdkZ250IEtTNUhiWXMwdHVnbE5nVG9Ud194N3dubGxXVkN1ZFRDKCkgewogICAgICAgICAgICBkYmd4LndUdENUd2d0RWhZVFlULndUdENUdzJnRWJUeGRLd2dud2dkaygpOwogICAgICAgIH0sCiAgICAgICAgRVRkSGJZczB0dWdsOiBCWXQ3ZGdudCBLUzVIYllzMHR1Z2xOZ1RvVHdfRVRkSGJZczB0dWdsKGd0Q1RyKSB7CiAgICAgICAgICAgIHdUZFl3dCBkYmd4LmRiWXMwdHVnbHhbZ3RDVHJdOwogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogQFZ3Z2p1ZFQKICAgICAgICAgKi8KICAgICAgICBfRVRkTmd4ZzBsVEhiWXMweDogQll0N2RnbnQgS1M1SGJZczB0dWdsTmdUb1R3X0VUZE5neGcwbFRIYllzMHgoKSB7CiAgICAgICAgICAgIHdUZFl3dCBFVGROZ3hnMGxUTWxUc1R0ZHgoZGJneC43bnRkdWd0VHcsIGRiZ3guZGJZczB0dWdseCk7CiAgICAgICAgfSwKICAgICAgICB4N3dubGxIYllzMHR1Z2xmdGRuTmdUbzoKICAgICAgICAgICAgICAgIEJZdDdkZ250IEtTNUhiWXMwdHVnbE5nVG9Ud194N3dubGxIYllzMHR1Z2xmdGRuTmdUbyhWdUVUKSB7CiAgICAgICAgICAgICAgICAgICAganV3IHhUbFQ3ZFRDID0gQ243WXNUdGQuUVlUd2tQVGxUN2RudygnLmRiWXMwdHVnbC54VGxUN2RUQycpOwogICAgICAgICAgICAgICAgICAgIGdCICh4VGxUN2RUQykgewogICAgICAgICAgICAgICAgICAgICAgICB4VGxUN2RUQy43bHV4eElneGQud1RzbmpUKCd4VGxUN2RUQycpOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBqdXcgZGJZczB0dWdsID0gQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ2RiWXMwdHVnbDNudGR1Z3RUdycgKyBWdUVUKTsKICAgICAgICAgICAgICAgICAgICBnQiAoZGJZczB0dWdsKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGRiWXMwdHVnbC43bHV4eElneGQudUNDKCd4VGxUN2RUQycpOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBqdXcgamd4ZzBsVEhiWXMweCA9IGRiZ3guX0VUZE5neGcwbFRIYllzMHgoKTsKICAgICAgICAgICAgICAgICAgICBqdXcgdFlzTmd4ZzBsVEhiWXMweCA9IGpneGcwbFRIYllzMHguamdUb3gubFR0RWRiOwoKICAgICAgICAgICAgICAgICAgICAvLyBmQiBkYlQgZGJZczB0dWdsIGd4dCdkIDdZd3dUdGRsayBqZ3hnMGxULCB4N3dubGwgZ2QgZ3RkbiBqZ1RvLgogICAgICAgICAgICAgICAgICAgIGdCICh0WXNOZ3hnMGxUSGJZczB4ID4gdikgewogICAgICAgICAgICAgICAgICAgICAgICBqdXcgQmd3eGQgPSBqZ3hnMGxUSGJZczB4LkJnd3hkLmdDOwogICAgICAgICAgICAgICAgICAgICAgICAvLyBBNzduWXRkIEJudyBudGxrIG50VCBkYllzMHR1Z2wgMFRndEUgamd4ZzBsVC4KICAgICAgICAgICAgICAgICAgICAgICAganV3IGx1eGQgPSAodFlzTmd4ZzBsVEhiWXMweCA+IHogPyBqZ3hnMGxUSGJZczB4Lmx1eGQuZ0MgOiBCZ3d4ZCk7CiAgICAgICAgICAgICAgICAgICAgICAgIGdCIChWdUVUIDw9IEJnd3hkIHx8IFZ1RVQgPj0gbHV4ZCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgeDd3bmxsZnRkbk5nVG8oZGJZczB0dWdsLCB7ZG5WOiBIMldxRjZBZklfUDNlOUlJX3FBZXBmNn0pOwogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfSwKICAgICAgICBFVGQgVnVFVHhlbmR1ZGdudCgpIHsKICAgICAgICAgICAgd1RkWXd0IGRiZ3guX1Z1RVR4ZW5kdWRnbnQ7CiAgICAgICAgfSwKICAgICAgICB4VGQgVnVFVHhlbmR1ZGdudCh3bmR1ZGdudCkgewogICAgICAgICAgICBkYmd4Ll9WdUVUeGVuZHVkZ250ID0gd25kdWRnbnQ7CiAgICAgICAgICAgIEJudyAoanV3IGcgPSB2LCBsID0gZGJneC5kYllzMHR1Z2x4LmxUdEVkYjsgZyA8IGw7IGcrKykgewogICAgICAgICAgICAgICAganV3IGRiWXMwID0gZGJneC5kYllzMHR1Z2x4W2ddOwogICAgICAgICAgICAgICAgZGJZczAuWVZDdWRUKHduZHVkZ250KTsKICAgICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgN2xUdXRZVjogQll0N2RnbnQgS1M1SGJZczB0dWdsTmdUb1R3XzdsVHV0WVYoKSB7CiAgICAgICAgICAgIGp1dyBkVHNWM3V0anV4ID0gS1M1SGJZczB0dWdsTmdUby5kVHNWZnN1RVQzdTdiVDsKICAgICAgICAgICAgZ0IgKGRUc1YzdXRqdXgpIHsKICAgICAgICAgICAgICAgIC8vIFhUd25ndEUgZGJUIG9nQ2RiIHV0QyBiVGdFYmQgN3VZeFR4IDVnd1RCbnIgZG4gd1RsVHV4VCBFd3VWYmc3eAogICAgICAgICAgICAgICAgLy8gd1R4bll3N1R4IGdzc1RDZ3VkVGxrLCBvYmc3YiA3dXQgRXdUdWRsayB3VENZN1Qgc1RzbndrIDdudHhZc1ZkZ250LgogICAgICAgICAgICAgICAgZFRzVjN1dGp1eC5vZ0NkYiA9IHY7CiAgICAgICAgICAgICAgICBkVHNWM3V0anV4LmJUZ0ViZCA9IHY7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgS1M1SGJZczB0dWdsTmdUby5kVHNWZnN1RVQzdTdiVCA9IHRZbGw7CiAgICAgICAgfSwKICAgICAgICAvKioKICAgICAgICAgKiBAVndnanVkVAogICAgICAgICAqLwogICAgICAgIF93VHhUZE5nVG86IEJZdDdkZ250IEtTNUhiWXMwdHVnbE5nVG9Ud193VHhUZE5nVG8oKSB7CiAgICAgICAgICAgIGRiZ3guZGJZczB0dWdseCA9IFtdOwogICAgICAgICAgICBkYmd4Ll9WdUVUeGVuZHVkZ250ID0gdjsKICAgICAgICAgICAgZGJneC5fVnVFVHhlVFFZVHhkeCA9IFtdOwogICAgICAgIH0sCiAgICAgICAgeFRkU243WXNUdGQ6IEJZdDdkZ250IEtTNUhiWXMwdHVnbE5nVG9Ud194VGRTbjdZc1R0ZChWQ0JTbjdZc1R0ZCkgewogICAgICAgICAgICBnQiAoZGJneC5WQ0JTbjdZc1R0ZCkgewogICAgICAgICAgICAgICAgLy8gN2xUdXRZViBuQiBkYlQgVGxUc1R0ZHggdXRDIGpnVG94CiAgICAgICAgICAgICAgICBqdXcgZGJZczB4TmdUbyA9IGRiZ3guN250ZHVndFR3OwogICAgICAgICAgICAgICAgb2JnbFQgKGRiWXMweE5nVG8uYnV4M2JnbEM2bkNUeCgpKSB7CiAgICAgICAgICAgICAgICAgICAgZGJZczB4TmdUby53VHNualQzYmdsQyhkYllzMHhOZ1RvLmx1eGQzYmdsQyk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBkYmd4Ll93VHhUZE5nVG8oKTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgZGJneC5WQ0JTbjdZc1R0ZCA9IFZDQlNuN1lzVHRkOwogICAgICAgICAgICBnQiAoIVZDQlNuN1lzVHRkKSB7CiAgICAgICAgICAgICAgICB3VGRZd3QgS3duc2d4VC53VHhubGpUKCk7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIHdUZFl3dCBWQ0JTbjdZc1R0ZC5FVGRLdUVUKHopLmRiVHQoQll0N2RnbnQgKEJnd3hkS3VFVCkgewogICAgICAgICAgICAgICAganV3IFZ1RVR4M25ZdGQgPSBWQ0JTbjdZc1R0ZC50WXNLdUVUeDsKICAgICAgICAgICAgICAgIGp1dyBqZ1RvVm53ZCA9IEJnd3hkS3VFVC5FVGROZ1RvVm53ZCh6LnYpOwogICAgICAgICAgICAgICAgQm53IChqdXcgVnVFVDZZcyA9IHo7IFZ1RVQ2WXMgPD0gVnVFVHgzbll0ZDsgKytWdUVUNllzKSB7CiAgICAgICAgICAgICAgICAgICAganV3IGRiWXMwdHVnbCA9IHRUbyBLUzVIYllzMHR1Z2xOZ1RvKHsKICAgICAgICAgICAgICAgICAgICAgICAgN250ZHVndFR3OiBkYmd4LjdudGR1Z3RUdywKICAgICAgICAgICAgICAgICAgICAgICAgZ0M6IFZ1RVQ2WXMsCiAgICAgICAgICAgICAgICAgICAgICAgIENUQnVZbGROZ1RvVm53ZDogamdUb1Zud2QuN2xudFQoKSwKICAgICAgICAgICAgICAgICAgICAgICAgbGd0T1BUd2pnN1Q6IGRiZ3gubGd0T1BUd2pnN1QsCiAgICAgICAgICAgICAgICAgICAgICAgIHdUdENUd2d0RWhZVFlUOiBkYmd4LndUdENUd2d0RWhZVFlUCiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICAgICAgZGJneC5kYllzMHR1Z2x4LlZZeGIoZGJZczB0dWdsKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfS4wZ3RDKGRiZ3gpKTsKICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIEBWdXd1cyB7S1M1S3VFVE5nVG99IFZ1RVROZ1RvCiAgICAgICAgICogQHdUZFl3dHgge0tTNUt1RVR9CiAgICAgICAgICogQFZ3Z2p1ZFQKICAgICAgICAgKi8KICAgICAgICBfVHR4WXdUS0NCS3VFVEludUNUQzoKICAgICAgICAgICAgICAgIEJZdDdkZ250IEtTNUhiWXMwdHVnbE5nVG9Ud19UdHhZd1RLQ0JLdUVUSW51Q1RDKGRiWXMwTmdUbykgewogICAgICAgICAgICAgICAgICAgIGdCIChkYllzME5nVG8uVkNCS3VFVCkgewogICAgICAgICAgICAgICAgICAgICAgICB3VGRZd3QgS3duc2d4VC53VHhubGpUKGRiWXMwTmdUby5WQ0JLdUVUKTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAganV3IFZ1RVQ2WXMwVHcgPSBkYllzME5nVG8uZ0M7CiAgICAgICAgICAgICAgICAgICAgZ0IgKGRiZ3guX1Z1RVR4ZVRRWVR4ZHhbVnVFVDZZczBUd10pIHsKICAgICAgICAgICAgICAgICAgICAgICAgd1RkWXd0IGRiZ3guX1Z1RVR4ZVRRWVR4ZHhbVnVFVDZZczBUd107CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIGp1dyBWd25zZ3hUID0gZGJneC5WQ0JTbjdZc1R0ZC5FVGRLdUVUKFZ1RVQ2WXMwVHcpLmRiVHQoCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBCWXQ3ZGdudCAoVkNCS3VFVCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRiWXMwTmdUby54VGRLQ0JLdUVUKFZDQkt1RVQpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRiZ3guX1Z1RVR4ZVRRWVR4ZHhbVnVFVDZZczBUd10gPSB0WWxsOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdUZFl3dCBWQ0JLdUVUOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgfS4wZ3RDKGRiZ3gpKTsKICAgICAgICAgICAgICAgICAgICBkYmd4Ll9WdUVUeGVUUVlUeGR4W1Z1RVQ2WXMwVHddID0gVnduc2d4VDsKICAgICAgICAgICAgICAgICAgICB3VGRZd3QgVnduc2d4VDsKICAgICAgICAgICAgICAgIH0sCiAgICAgICAgVHR4WXdUSGJZczB0dWdsTmd4ZzBsVDoKICAgICAgICAgICAgICAgIEJZdDdkZ250IEtTNUhiWXMwdHVnbE5nVG9Ud19UdHhZd1RIYllzMHR1Z2xOZ3hnMGxUKFZ1RVQpIHsKICAgICAgICAgICAgICAgICAgICAvLyBNdHhZd1QgZGJ1ZCBkYlQgZGJZczB0dWdsIG5CIGRiVCA3WXd3VHRkIFZ1RVQgZ3ggamd4ZzBsVAogICAgICAgICAgICAgICAgICAgIC8vIG9iVHQgeG9nZDdiZ3RFIEJ3bnMgdXRuZGJUdyBqZ1RvLgogICAgICAgICAgICAgICAgICAgIHg3d25sbGZ0ZG5OZ1RvKENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdkYllzMHR1Z2wzbnRkdWd0VHcnICsgVnVFVCkpOwogICAgICAgICAgICAgICAgfSwKICAgICAgICBCbnc3VGVUdENUd2d0RTogQll0N2RnbnQgKCkgewogICAgICAgICAgICBqdXcgamd4ZzBsVEhiWXMweCA9IGRiZ3guX0VUZE5neGcwbFRIYllzMHgoKTsKICAgICAgICAgICAganV3IGRiWXMwTmdUbyA9IGRiZ3gud1R0Q1R3Z3RFaFlUWVQuRVRkMmdFYlR4ZEt3Z253Z2RrKGpneGcwbFRIYllzMHgsCiAgICAgICAgICAgICAgICAgICAgZGJneC5kYllzMHR1Z2x4LAogICAgICAgICAgICAgICAgICAgIGRiZ3gueDd3bmxsLkNub3QpOwogICAgICAgICAgICBnQiAoZGJZczBOZ1RvKSB7CiAgICAgICAgICAgICAgICBkYmd4Ll9UdHhZd1RLQ0JLdUVUSW51Q1RDKGRiWXMwTmdUbykuZGJUdChCWXQ3ZGdudCAoKSB7CiAgICAgICAgICAgICAgICAgICAgZGJneC53VHRDVHdndEVoWVRZVC53VHRDVHdOZ1RvKGRiWXMwTmdUbyk7CiAgICAgICAgICAgICAgICB9LjBndEMoZGJneCkpOwogICAgICAgICAgICAgICAgd1RkWXd0IGR3WVQ7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgd1RkWXd0IEJ1bHhUOwogICAgICAgIH0KICAgIH07CgogICAgd1RkWXd0IEtTNUhiWXMwdHVnbE5nVG9UdzsKfSkoKTsKCgovKioKICogQGRrVlRDVEIgezkwMVQ3ZH0gS1M1OVlkbGd0VE5nVG85VmRnbnR4CiAqIEBWd25WVHdkayB7MkhxSVNnak1sVHNUdGR9IDdudGR1Z3RUdyAtIEhiVCBqZ1RvVHcgVGxUc1R0ZC4KICogQFZ3blZUd2RrIHtBd3d1a30gbllkbGd0VCAtIEF0IHV3d3VrIG5CIG5ZZGxndFQgbjAxVDdkeC4KICogQFZ3blZUd2RrIHtmS1M1SWd0T1BUd2pnN1R9IGxndE9QVHdqZzdUIC0gSGJUIHR1amdFdWRnbnQvbGd0T2d0RSB4VHdqZzdULgogKi8KCi8qKgogKiBAN2x1eHgKICovCmp1dyBLUzU5WWRsZ3RUTmdUbyA9IChCWXQ3ZGdudCBLUzU5WWRsZ3RUTmdUbzNsbnhZd1QoKSB7CiAgICAvKioKICAgICAqIEA3bnR4ZHdZN2R4IEtTNTlZZGxndFROZ1RvCiAgICAgKiBAVnV3dXMge0tTNTlZZGxndFROZ1RvOVZkZ250eH0gblZkZ250eAogICAgICovCiAgICBCWXQ3ZGdudCBLUzU5WWRsZ3RUTmdUbyhuVmRnbnR4KSB7CiAgICAgICAgZGJneC43bnRkdWd0VHcgPSBuVmRnbnR4LjdudGR1Z3RUdzsKICAgICAgICBkYmd4Lm5ZZGxndFQgPSBuVmRnbnR4Lm5ZZGxndFQ7CiAgICAgICAgZGJneC5sZ3RPUFR3amc3VCA9IG5WZGdudHgubGd0T1BUd2pnN1Q7CiAgICAgICAgZGJneC5sdXhkSG5FRWxUZnhQYm5vID0gZHdZVDsKICAgIH0KCiAgICBLUzU5WWRsZ3RUTmdUby5Wd25kbmRrVlQgPSB7CiAgICAgICAgd1R4VGQ6IEJZdDdkZ250IEtTNTlZZGxndFROZ1RvX3dUeFRkKCkgewogICAgICAgICAgICBqdXcgN250ZHVndFR3ID0gZGJneC43bnRkdWd0VHc7CiAgICAgICAgICAgIG9iZ2xUICg3bnRkdWd0VHcuQmd3eGQzYmdsQykgewogICAgICAgICAgICAgICAgN250ZHVndFR3LndUc25qVDNiZ2xDKDdudGR1Z3RUdy5CZ3d4ZDNiZ2xDKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBkYmd4Lmx1eGRIbkVFbFRmeFBibm8gPSBkd1lUOwogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogQFZ3Z2p1ZFQKICAgICAgICAgKi8KICAgICAgICBfQ2d4VnVkN2JNalR0ZDogQll0N2RnbnQgS1M1OVlkbGd0VE5nVG9fQ2d4VnVkN2JNalR0ZChuWWRsZ3RUM25ZdGQpIHsKICAgICAgICAgICAganV3IFRqVHRkID0gQ243WXNUdGQuN3dUdWRUTWpUdGQoJzNZeGRuc01qVHRkJyk7CiAgICAgICAgICAgIFRqVHRkLmd0Z2QzWXhkbnNNalR0ZCgnbllkbGd0VGxudUNUQycsIGR3WVQsIGR3WVQsIHsKICAgICAgICAgICAgICAgIG5ZZGxndFQzbll0ZDogbllkbGd0VDNuWXRkCiAgICAgICAgICAgIH0pOwogICAgICAgICAgICBkYmd4LjdudGR1Z3RUdy5DZ3hWdWQ3Yk1qVHRkKFRqVHRkKTsKICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIEBWd2dqdWRUCiAgICAgICAgICovCiAgICAgICAgXzBndENJZ3RPOiBCWXQ3ZGdudCBLUzU5WWRsZ3RUTmdUb18wZ3RDSWd0TyhUbFRzVHRkLCBnZFRzKSB7CiAgICAgICAgICAgIGp1dyBsZ3RPUFR3amc3VCA9IGRiZ3gubGd0T1BUd2pnN1Q7CiAgICAgICAgICAgIFRsVHNUdGQuYndUQiA9IGxndE9QVHdqZzdULkVUZFNUeGRndHVkZ250MnV4YihnZFRzLkNUeGQpOwogICAgICAgICAgICBUbFRzVHRkLm50N2xnN08gPSBCWXQ3ZGdudCBFbkhuU1R4ZGd0dWRnbnQoVCkgewogICAgICAgICAgICAgICAgbGd0T1BUd2pnN1QudHVqZ0V1ZFRIbihnZFRzLkNUeGQpOwogICAgICAgICAgICAgICAgd1RkWXd0IEJ1bHhUOwogICAgICAgICAgICB9OwogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogS3dUVlR0QyB1IDBZZGRudCAwVEJud1QgdXQgbllkbGd0VCBnZFRzIG9iZzdiIHVsbG5veCBkYlQgWXhUdyBkbiBkbkVFbFQKICAgICAgICAgKiBkYlQgamd4ZzBnbGdkayBuQiB1bGwgbllkbGd0VCBnZFRzeCB1ZCBkYnVkIGxUalRsLgogICAgICAgICAqCiAgICAgICAgICogQFZ3Z2p1ZFQKICAgICAgICAgKi8KICAgICAgICBfdUNDSG5FRWxURllkZG50OiBCWXQ3ZGdudCBLUzU5WWRsZ3RUTmdUb191Q0NIbkVFbFRGWWRkbnQoQ2dqKSB7CiAgICAgICAgICAgIGp1dyBkbkVFbFR3ID0gQ243WXNUdGQuN3dUdWRUTWxUc1R0ZCgnQ2dqJyk7CiAgICAgICAgICAgIGRuRUVsVHcuN2x1eHg2dXNUID0gJ25ZZGxndFRmZFRzSG5FRWxUdyc7CiAgICAgICAgICAgIGRuRUVsVHcubnQ3bGc3TyA9IEJZdDdkZ250IChUalR0ZCkgewogICAgICAgICAgICAgICAgVGpUdGQueGRuVkt3blZ1RXVkZ250KCk7CiAgICAgICAgICAgICAgICBkbkVFbFR3LjdsdXh4SWd4ZC5kbkVFbFQoJ25ZZGxndFRmZFRzeDJnQ0NUdCcpOwoKICAgICAgICAgICAgICAgIGdCIChUalR0ZC54YmdCZFJUaykgewogICAgICAgICAgICAgICAgICAgIGp1dyB4Ym5ZbENQYm5vQWxsID0gIWRuRUVsVHcuN2x1eHhJZ3hkLjdudGR1Z3R4KCduWWRsZ3RUZmRUc3gyZ0NDVHQnKTsKICAgICAgICAgICAgICAgICAgICBkYmd4Ll9kbkVFbFQ5WWRsZ3RUZmRUcyhDZ2osIHhibllsQ1Bibm9BbGwpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9LjBndEMoZGJneCk7CiAgICAgICAgICAgIENnai5ndHhUd2RGVEJud1QoZG5FRWxUdywgQ2dqLkJnd3hkM2JnbEMpOwogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogSG5FRWxUIGRiVCBqZ3hnMGdsZ2RrIG5CIGRiVCB4WTBkd1RUIG5CIHV0IG5ZZGxndFQgZ2RUcy4KICAgICAgICAgKgogICAgICAgICAqIEBWdXd1cyB7TWxUc1R0ZH0gd25uZCAtIGRiVCB3bm5kIG5CIGRiVCBuWWRsZ3RUICh4WTApZHdUVC4KICAgICAgICAgKiBAVnV3dXMgezBubmxUdXR9IHhkdWRUIC0gb2JUZGJUdyBkbiB4Ym5vIGRiVCBuWWRsZ3RUICh4WTApZHdUVC4gZkIgQnVseFQsCiAgICAgICAgICogICBkYlQgbllkbGd0VCB4WTBkd1RUIHdubmRUQyB1ZCB8d25uZHwgb2dsbCAwVCA3bmxsdVZ4VEMuCiAgICAgICAgICoKICAgICAgICAgKiBAVndnanVkVAogICAgICAgICAqLwogICAgICAgIF9kbkVFbFQ5WWRsZ3RUZmRUczogQll0N2RnbnQgS1M1OVlkbGd0VE5nVG9fZG5FRWxUOVlkbGd0VGZkVHMod25uZCwgeGJubykgewogICAgICAgICAgICBkYmd4Lmx1eGRIbkVFbFRmeFBibm8gPSB4Ym5vOwogICAgICAgICAgICBqdXcgZG5FRWxUd3ggPSB3bm5kLlFZVHdrUFRsVDdkbndBbGwoJy5uWWRsZ3RUZmRUc0huRUVsVHcnKTsKICAgICAgICAgICAgQm53IChqdXcgZyA9IHYsIGdnID0gZG5FRWxUd3gubFR0RWRiOyBnIDwgZ2c7ICsrZykgewogICAgICAgICAgICAgICAgZG5FRWxUd3hbZ10uN2x1eHhJZ3hkW3hibm8gPyAnd1RzbmpUJyA6ICd1Q0MnXSgnbllkbGd0VGZkVHN4MmdDQ1R0Jyk7CiAgICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIDNubGx1VnhUIG53IFRyVnV0QyB1bGwgeFkwZHdUVHggbkIgZGJUIG5ZZGxndFQuCiAgICAgICAgICovCiAgICAgICAgZG5FRWxUOVlkbGd0VEh3VFQ6IEJZdDdkZ250IEtTNTlZZGxndFROZ1RvX2RuRUVsVDlZZGxndFRId1RUKCkgewogICAgICAgICAgICBkYmd4Ll9kbkVFbFQ5WWRsZ3RUZmRUcyhkYmd4LjdudGR1Z3RUdywgIWRiZ3gubHV4ZEhuRUVsVGZ4UGJubyk7CiAgICAgICAgfSwKICAgICAgICB3VHRDVHc6IEJZdDdkZ250IEtTNTlZZGxndFROZ1RvX3dUdENUdygpIHsKICAgICAgICAgICAganV3IG5ZZGxndFQgPSBkYmd4Lm5ZZGxndFQ7CiAgICAgICAgICAgIGp1dyBuWWRsZ3RUM25ZdGQgPSB2OwoKICAgICAgICAgICAgZGJneC53VHhUZCgpOwoKICAgICAgICAgICAgZ0IgKCFuWWRsZ3RUKSB7CiAgICAgICAgICAgICAgICBkYmd4Ll9DZ3hWdWQ3Yk1qVHRkKG5ZZGxndFQzbll0ZCk7CiAgICAgICAgICAgICAgICB3VGRZd3Q7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGp1dyBCd3VFc1R0ZCA9IENuN1lzVHRkLjd3VHVkVFNuN1lzVHRkNXd1RXNUdGQoKTsKICAgICAgICAgICAganV3IFFZVFlUID0gW3tWdXdUdGQ6IEJ3dUVzVHRkLCBnZFRzeDogZGJneC5uWWRsZ3RUfV07CiAgICAgICAgICAgIGp1dyBidXhBdGs2VHhkZ3RFID0gQnVseFQ7CiAgICAgICAgICAgIG9iZ2xUIChRWVRZVC5sVHRFZGIgPiB2KSB7CiAgICAgICAgICAgICAgICBqdXcgbFRqVGxTdWR1ID0gUVlUWVQueGJnQmQoKTsKICAgICAgICAgICAgICAgIEJudyAoanV3IGcgPSB2LCBsVHQgPSBsVGpUbFN1ZHUuZ2RUc3gubFR0RWRiOyBnIDwgbFR0OyBnKyspIHsKICAgICAgICAgICAgICAgICAgICBqdXcgZ2RUcyA9IGxUalRsU3VkdS5nZFRzeFtnXTsKICAgICAgICAgICAgICAgICAgICBqdXcgQ2dqID0gQ243WXNUdGQuN3dUdWRUTWxUc1R0ZCgnQ2dqJyk7CiAgICAgICAgICAgICAgICAgICAgQ2dqLjdsdXh4NnVzVCA9ICduWWRsZ3RUZmRUcyc7CiAgICAgICAgICAgICAgICAgICAganV3IFRsVHNUdGQgPSBDbjdZc1R0ZC43d1R1ZFRNbFRzVHRkKCd1Jyk7CiAgICAgICAgICAgICAgICAgICAgZGJneC5fMGd0Q0lndE8oVGxUc1R0ZCwgZ2RUcyk7CiAgICAgICAgICAgICAgICAgICAgVGxUc1R0ZC5kVHJkM250ZFR0ZCA9IHdUc25qVDZZbGwzYnV3dTdkVHd4KGdkVHMuZGdkbFQpOwogICAgICAgICAgICAgICAgICAgIENnai51VlZUdEMzYmdsQyhUbFRzVHRkKTsKCiAgICAgICAgICAgICAgICAgICAgZ0IgKGdkVHMuZ2RUc3gubFR0RWRiID4gdikgewogICAgICAgICAgICAgICAgICAgICAgICBidXhBdGs2VHhkZ3RFID0gZHdZVDsKICAgICAgICAgICAgICAgICAgICAgICAgZGJneC5fdUNDSG5FRWxURllkZG50KENnaik7CgogICAgICAgICAgICAgICAgICAgICAgICBqdXcgZ2RUc3hTZ2ogPSBDbjdZc1R0ZC43d1R1ZFRNbFRzVHRkKCdDZ2onKTsKICAgICAgICAgICAgICAgICAgICAgICAgZ2RUc3hTZ2ouN2x1eHg2dXNUID0gJ25ZZGxndFRmZFRzeCc7CiAgICAgICAgICAgICAgICAgICAgICAgIENnai51VlZUdEMzYmdsQyhnZFRzeFNnaik7CiAgICAgICAgICAgICAgICAgICAgICAgIFFZVFlULlZZeGIoe1Z1d1R0ZDogZ2RUc3hTZ2osIGdkVHN4OiBnZFRzLmdkVHN4fSk7CiAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICBsVGpUbFN1ZHUuVnV3VHRkLnVWVlR0QzNiZ2xDKENnaik7CiAgICAgICAgICAgICAgICAgICAgbllkbGd0VDNuWXRkKys7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZ0IgKGJ1eEF0azZUeGRndEUpIHsKICAgICAgICAgICAgICAgIGRiZ3guN250ZHVndFR3LjdsdXh4SWd4ZC51Q0MoJ25ZZGxndFQ4Z2RiU1RUVjZUeGRndEUnKTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgZGJneC43bnRkdWd0VHcudVZWVHRDM2JnbEMoQnd1RXNUdGQpOwoKICAgICAgICAgICAgZGJneC5fQ2d4VnVkN2JNalR0ZChuWWRsZ3RUM25ZdGQpOwogICAgICAgIH0KICAgIH07CgogICAgd1RkWXd0IEtTNTlZZGxndFROZ1RvOwp9KSgpOwoKCi8qKgogKiBAZGtWVENUQiB7OTAxVDdkfSBLUzVBZGR1N2JzVHRkTmdUbzlWZGdudHgKICogQFZ3blZUd2RrIHsySHFJU2dqTWxUc1R0ZH0gN250ZHVndFR3IC0gSGJUIGpnVG9UdyBUbFRzVHRkLgogKiBAVnduVlR3ZGsge0F3d3VrfSB1ZGR1N2JzVHRkeCAtIEF0IHV3d3VrIG5CIHVkZHU3YnNUdGQgbjAxVDdkeC4KICogQFZ3blZUd2RrIHtTbm90bG51Q3F1dHVFVHd9IENub3RsbnVDcXV0dUVUdyAtIEhiVCBDbm90bG51QyBzdXR1RVR3LgogKi8KCi8qKgogKiBAN2x1eHgKICovCmp1dyBLUzVBZGR1N2JzVHRkTmdUbyA9IChCWXQ3ZGdudCBLUzVBZGR1N2JzVHRkTmdUbzNsbnhZd1QoKSB7CiAgICAvKioKICAgICAqIEA3bnR4ZHdZN2R4IEtTNUFkZHU3YnNUdGROZ1RvCiAgICAgKiBAVnV3dXMge0tTNUFkZHU3YnNUdGROZ1RvOVZkZ250eH0gblZkZ250eAogICAgICovCiAgICBCWXQ3ZGdudCBLUzVBZGR1N2JzVHRkTmdUbyhuVmRnbnR4KSB7CiAgICAgICAgZGJneC43bnRkdWd0VHcgPSBuVmRnbnR4LjdudGR1Z3RUdzsKICAgICAgICBkYmd4LnVkZHU3YnNUdGR4ID0gblZkZ250eC51ZGR1N2JzVHRkeDsKICAgICAgICBkYmd4LkNub3RsbnVDcXV0dUVUdyA9IG5WZGdudHguQ25vdGxudUNxdXR1RVR3OwogICAgfQoKICAgIEtTNUFkZHU3YnNUdGROZ1RvLlZ3bmRuZGtWVCA9IHsKICAgICAgICB3VHhUZDogQll0N2RnbnQgS1M1QWRkdTdic1R0ZE5nVG9fd1R4VGQoKSB7CiAgICAgICAgICAgIGp1dyA3bnRkdWd0VHcgPSBkYmd4LjdudGR1Z3RUdzsKICAgICAgICAgICAgb2JnbFQgKDdudGR1Z3RUdy5CZ3d4ZDNiZ2xDKSB7CiAgICAgICAgICAgICAgICA3bnRkdWd0VHcud1RzbmpUM2JnbEMoN250ZHVndFR3LkJnd3hkM2JnbEMpOwogICAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICAvKioKICAgICAgICAgKiBAVndnanVkVAogICAgICAgICAqLwogICAgICAgIF9DZ3hWdWQ3Yk1qVHRkOiBCWXQ3ZGdudCBLUzVBZGR1N2JzVHRkTmdUb19DZ3hWdWQ3Yk1qVHRkKHVkZHU3YnNUdGR4M25ZdGQpIHsKICAgICAgICAgICAganV3IFRqVHRkID0gQ243WXNUdGQuN3dUdWRUTWpUdGQoJzNZeGRuc01qVHRkJyk7CiAgICAgICAgICAgIFRqVHRkLmd0Z2QzWXhkbnNNalR0ZCgndWRkdTdic1R0ZHhsbnVDVEMnLCBkd1lULCBkd1lULCB7CiAgICAgICAgICAgICAgICB1ZGR1N2JzVHRkeDNuWXRkOiB1ZGR1N2JzVHRkeDNuWXRkCiAgICAgICAgICAgIH0pOwogICAgICAgICAgICBkYmd4LjdudGR1Z3RUdy5DZ3hWdWQ3Yk1qVHRkKFRqVHRkKTsKICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIEBWd2dqdWRUCiAgICAgICAgICovCiAgICAgICAgXzBndENJZ3RPOiBCWXQ3ZGdudCBLUzVBZGR1N2JzVHRkTmdUb18wZ3RDSWd0TygwWWRkbnQsIDdudGRUdGQsIEJnbFR0dXNUKSB7CiAgICAgICAgICAgIDBZZGRudC5udDdsZzdPID0gQll0N2RnbnQgQ25vdGxudUM1Z2xUKFQpIHsKICAgICAgICAgICAgICAgIGRiZ3guQ25vdGxudUNxdXR1RVR3LkNub3RsbnVDU3VkdSg3bnRkVHRkLCBCZ2xUdHVzVCwgJycpOwogICAgICAgICAgICAgICAgd1RkWXd0IEJ1bHhUOwogICAgICAgICAgICB9LjBndEMoZGJneCk7CiAgICAgICAgfSwKICAgICAgICB3VHRDVHc6IEJZdDdkZ250IEtTNUFkZHU3YnNUdGROZ1RvX3dUdENUdygpIHsKICAgICAgICAgICAganV3IHVkZHU3YnNUdGR4ID0gZGJneC51ZGR1N2JzVHRkeDsKICAgICAgICAgICAganV3IHVkZHU3YnNUdGR4M25ZdGQgPSB2OwoKICAgICAgICAgICAgZGJneC53VHhUZCgpOwoKICAgICAgICAgICAgZ0IgKCF1ZGR1N2JzVHRkeCkgewogICAgICAgICAgICAgICAgZGJneC5fQ2d4VnVkN2JNalR0ZCh1ZGR1N2JzVHRkeDNuWXRkKTsKICAgICAgICAgICAgICAgIHdUZFl3dDsKICAgICAgICAgICAgfQoKICAgICAgICAgICAganV3IHR1c1R4ID0gOTAxVDdkLk9Ua3godWRkdTdic1R0ZHgpLnhud2QoQll0N2RnbnQgKHUsIDApIHsKICAgICAgICAgICAgICAgIHdUZFl3dCB1LmRuSW5vVHczdXhUKCkubG43dWxUM25zVnV3VCgwLmRuSW5vVHczdXhUKCkpOwogICAgICAgICAgICB9KTsKICAgICAgICAgICAgdWRkdTdic1R0ZHgzbll0ZCA9IHR1c1R4LmxUdEVkYjsKCiAgICAgICAgICAgIEJudyAoanV3IGcgPSB2OyBnIDwgdWRkdTdic1R0ZHgzbll0ZDsgZysrKSB7CiAgICAgICAgICAgICAgICBqdXcgZ2RUcyA9IHVkZHU3YnNUdGR4W3R1c1R4W2ddXTsKICAgICAgICAgICAgICAgIGp1dyBCZ2xUdHVzVCA9IEVUZDVnbFQ2dXNUKGdkVHMuQmdsVHR1c1QpOwogICAgICAgICAgICAgICAganV3IENnaiA9IENuN1lzVHRkLjd3VHVkVE1sVHNUdGQoJ0NnaicpOwogICAgICAgICAgICAgICAgQ2dqLjdsdXh4NnVzVCA9ICd1ZGR1N2JzVHRkeGZkVHMnOwogICAgICAgICAgICAgICAganV3IDBZZGRudCA9IENuN1lzVHRkLjd3VHVkVE1sVHNUdGQoJzBZZGRudCcpOwogICAgICAgICAgICAgICAgZGJneC5fMGd0Q0lndE8oMFlkZG50LCBnZFRzLjdudGRUdGQsIEJnbFR0dXNUKTsKICAgICAgICAgICAgICAgIDBZZGRudC5kVHJkM250ZFR0ZCA9IHdUc25qVDZZbGwzYnV3dTdkVHd4KEJnbFR0dXNUKTsKICAgICAgICAgICAgICAgIENnai51VlZUdEMzYmdsQygwWWRkbnQpOwogICAgICAgICAgICAgICAgZGJneC43bnRkdWd0VHcudVZWVHRDM2JnbEMoQ2dqKTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgZGJneC5fQ2d4VnVkN2JNalR0ZCh1ZGR1N2JzVHRkeDNuWXRkKTsKICAgICAgICB9CiAgICB9OwoKICAgIHdUZFl3dCBLUzVBZGR1N2JzVHRkTmdUbzsKfSkoKTsKCgpqdXcgS1M1TmdUb1R3QVZWbGc3dWRnbnQgPSB7CiAgICBndGdkZ3VsRm5uT3N1d086IENuN1lzVHRkLmxuN3VkZ250LmJ1eGIueFkweGR3Z3RFKHopLAogICAgZ3RnZGd1bFNUeGRndHVkZ250OiB0WWxsLAogICAgZ3RnZGd1bGdHVEM6IEJ1bHhULAogICAgQlRsbDB1N086IEJ1bHhULAogICAgVkNCU243WXNUdGQ6IHRZbGwsCiAgICB4Z0NUMHV3OVZUdDogQnVseFQsCiAgICBWd2d0ZGd0RTogQnVseFQsCiAgICAvKiogQGRrVlQge0tTNU5nVG9Ud30gKi8KICAgIFZDQk5nVG9UdzogdFlsbCwKICAgIC8qKiBAZGtWVCB7S1M1SGJZczB0dWdsTmdUb1R3fSAqLwogICAgVkNCSGJZczB0dWdsTmdUb1R3OiB0WWxsLAogICAgLyoqIEBka1ZUIHtLUzVlVHRDVHdndEVoWVRZVH0gKi8KICAgIFZDQmVUdENUd2d0RWhZVFlUOiB0WWxsLAogICAgLyoqIEBka1ZUIHtLUzVLd1R4VHRkdWRnbnRxbkNUfSAqLwogICAgVkNCS3dUeFR0ZHVkZ250cW5DVDogdFlsbCwKICAgIC8qKiBAZGtWVCB7S1M1U243WXNUdGRLd25WVHdkZ1R4fSAqLwogICAgVkNCU243WXNUdGRLd25WVHdkZ1R4OiB0WWxsLAogICAgLyoqIEBka1ZUIHtLUzVJZ3RPUFR3amc3VH0gKi8KICAgIFZDQklndE9QVHdqZzdUOiB0WWxsLAogICAgLyoqIEBka1ZUIHtLUzUyZ3hkbndrfSAqLwogICAgVkNCMmd4ZG53azogdFlsbCwKICAgIFZ1RVRlbmR1ZGdudDogdiwKICAgIGd4ZnRnZGd1bE5nVG9QVGQ6IEJ1bHhULAogICAgdXRnc3VkZ250UGR1d2RUQ0t3bnNneFQ6IHRZbGwsCiAgICBWd1RCVHdUdDdUUGdDVDB1d05nVG85dEludUM6IFBnQ1QwdXdOZ1RvLjY5Nk0sCiAgICBWd1RCVHdUdDdUS0NCRllFTXR1MGxUQzogQnVseFQsCiAgICBWd1RCVHdUdDdUUGJub0t3VGpnbll4TmdUbzl0SW51QzogZHdZVCwKICAgIFZ3VEJUd1R0N1RTVEJ1WWxkWG5uc051bFlUOiAnJywKICAgIGd4TmdUb1R3TXMwVENDVEM6IChvZ3RDbm8uVnV3VHRkICE9PSBvZ3RDbm8pLAogICAgWXdsOiAnJywKICAgIENuN1lzVHRkQXR0bmR1ZGdudHg6IHRZbGwsIC8vQUNDVEMgMGsgUHdnIFJ3Z3hidHV0CiAgICBDbjdZc1R0ZDZuZFR4OiB0WWxsLCAvL0FDQ1RDIDBrIFB3ZyBSd2d4YnR1dAogICAgd1kwMFR3UGR1c1ZBdHRuZHVkZ250OiB0WWxsLCAvL0FDQ1RDIDBrIFB3ZyBSd2d4YnR1dAogICAgQ1RsVGRUM250Qmd3c3VkZ250S3duc1ZkOiB0WWxsLCAvL0FDQ1RDIDBrIFB3ZyBSd2d4YnR1dAogICAgeGRnN09rNm5kVEt3bnNWZDogdFlsbCwgLy9BQ0NUQyAwayBQd2cgUndneGJ0dXQKICAgIENUbFRkVEF0dG5kdWRnbnQzbnRCZ3dzdWRnbnRLd25zVmQ6IHRZbGwsIC8vQUNDIDBrIFB3ZyBSd2d4YnR1dCBudCBVZGIgcXV3N2IgWnZ6YQogICAgQ2dFZ2R1bHhnRXRBdHRuZHVkZ250OiB0WWxsLAogICAgLy8gN3VsbFRDIG50N1Qgb2JUdCBkYlQgQ243WXNUdGQgZ3ggbG51Q1RDCiAgICBndGdkZ3VsZ0dUOiBCWXQ3ZGdudCBWQ0JOZ1RvZnRnZGd1bGdHVCgpIHsKICAgICAgICBqdXcgVkNCZVR0Q1R3Z3RFaFlUWVQgPSB0VG8gS1M1ZVR0Q1R3Z3RFaFlUWVQoKTsKICAgICAgICBWQ0JlVHRDVHdndEVoWVRZVC5udGZDbFQgPSBkYmd4LjdsVHV0WVYuMGd0QyhkYmd4KTsKICAgICAgICBkYmd4LlZDQmVUdENUd2d0RWhZVFlUID0gVkNCZVR0Q1R3Z3RFaFlUWVQ7CgogICAgICAgIGp1dyBWQ0JJZ3RPUFR3amc3VCA9IHRUbyBLUzVJZ3RPUFR3amc3VCgpOwogICAgICAgIGRiZ3guVkNCSWd0T1BUd2pnN1QgPSBWQ0JJZ3RPUFR3amc3VDsKCiAgICAgICAganV3IDdudGR1Z3RUdyA9IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdqZ1RvVHczbnRkdWd0VHcnKTsKICAgICAgICBqdXcgamdUb1R3ID0gQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ2pnVG9UdycpOwoKICAgICAgICBkYmd4LlZDQk5nVG9UdyA9IHRUbyBLUzVOZ1RvVHcoewogICAgICAgICAgICA3bnRkdWd0VHc6IDdudGR1Z3RUdywKICAgICAgICAgICAgamdUb1R3OiBqZ1RvVHcsCiAgICAgICAgICAgIHdUdENUd2d0RWhZVFlUOiBWQ0JlVHRDVHdndEVoWVRZVCwKICAgICAgICAgICAgbGd0T1BUd2pnN1Q6IFZDQklndE9QVHdqZzdUCiAgICAgICAgfSk7CiAgICAgICAgVkNCZVR0Q1R3Z3RFaFlUWVQueFRkTmdUb1R3KGRiZ3guVkNCTmdUb1R3KTsKICAgICAgICBWQ0JJZ3RPUFR3amc3VC54VGROZ1RvVHcoZGJneC5WQ0JOZ1RvVHcpOwoKICAgICAgICBqdXcgZGJZczB0dWdsM250ZHVndFR3ID0gQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ2RiWXMwdHVnbE5nVG8nKTsKICAgICAgICBkYmd4LlZDQkhiWXMwdHVnbE5nVG9UdyA9IHRUbyBLUzVIYllzMHR1Z2xOZ1RvVHcoewogICAgICAgICAgICA3bnRkdWd0VHc6IGRiWXMwdHVnbDNudGR1Z3RUdywKICAgICAgICAgICAgd1R0Q1R3Z3RFaFlUWVQ6IFZDQmVUdENUd2d0RWhZVFlULAogICAgICAgICAgICBsZ3RPUFR3amc3VDogVkNCSWd0T1BUd2pnN1QKICAgICAgICB9KTsKICAgICAgICBWQ0JlVHRDVHdndEVoWVRZVC54VGRIYllzMHR1Z2xOZ1RvVHcoZGJneC5WQ0JIYllzMHR1Z2xOZ1RvVHcpOwoKICAgICAgICBLd1RCVHdUdDdUeC5ndGdkZ3VsZ0dUKCk7CgogICAgICAgIGRiZ3guVkNCMmd4ZG53ayA9IHRUbyBLUzUyZ3hkbndrKHsKICAgICAgICAgICAgbGd0T1BUd2pnN1Q6IFZDQklndE9QVHdqZzdUCiAgICAgICAgfSk7CiAgICAgICAgVkNCSWd0T1BUd2pnN1QueFRkMmd4ZG53ayhkYmd4LlZDQjJneGRud2spOwoKICAgICAgICBkYmd4LkJndEMzbnRkd25sbFR3ID0gdFRvIEtTNTVndEMzbnRkd25sbFR3KHsKICAgICAgICAgICAgVkNCTmdUb1R3OiBkYmd4LlZDQk5nVG9UdywKICAgICAgICAgICAgZ3RkVEV3dWRUQzVndEM6IGRiZ3gueFlWVm53ZHhmdGRURXd1ZFRDNWd0QwogICAgICAgIH0pOwogICAgICAgIGRiZ3guVkNCTmdUb1R3LnhUZDVndEMzbnRkd25sbFR3KGRiZ3guQmd0QzNudGR3bmxsVHcpOwoKICAgICAgICBkYmd4LkJndENGdXcgPSB0VG8gS1M1NWd0Q0Z1dyh7CiAgICAgICAgICAgIDB1dzogQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ0JndEMwdXcnKSwKICAgICAgICAgICAgZG5FRWxURllkZG50OiBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnamdUbzVndEMnKSwKICAgICAgICAgICAgQmd0QzVnVGxDOiBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnQmd0Q2Z0VllkJyksCiAgICAgICAgICAgIGJnRWJsZ0ViZEFsbDNiVDdPMG5yOiBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnQmd0QzJnRWJsZ0ViZEFsbCcpLAogICAgICAgICAgICA3dXhUUFR0eGdkZ2pUM2JUN08wbnI6IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdCZ3RDcXVkN2IzdXhUJyksCiAgICAgICAgICAgIEJndENxeEU6IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdCZ3RDcXhFJyksCiAgICAgICAgICAgIEJndENQZHVkWXhmN250OiBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnQmd0Q1BkdWRZeGY3bnQnKSwKICAgICAgICAgICAgQmd0Q0t3VGpnbll4RllkZG50OiBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnQmd0Q0t3VGpnbll4JyksCiAgICAgICAgICAgIEJndEM2VHJkRllkZG50OiBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnQmd0QzZUcmQnKSwKICAgICAgICAgICAgQmd0QzNudGR3bmxsVHc6IGRiZ3guQmd0QzNudGR3bmxsVHcKICAgICAgICB9KTsKICAgICAgICAKCiAgICAgICAgZGJneC5CZ3RDM250ZHdubGxUdy54VGQ1Z3RDRnV3KGRiZ3guQmd0Q0Z1dyk7CgogICAgICAgIDJ1dENIbm5sLmd0Z2RndWxnR1QoewogICAgICAgICAgICA3bnRkdWd0VHc6IDdudGR1Z3RUdywKICAgICAgICAgICAgZG5FRWxUMnV0Q0hubmw6IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdkbkVFbFQydXRDSG5ubCcpCiAgICAgICAgfSk7CgogICAgICAgIGRiZ3guVkNCU243WXNUdGRLd25WVHdkZ1R4ID0gdFRvIEtTNVNuN1lzVHRkS3duVlR3ZGdUeCh7CiAgICAgICAgICAgIG5qVHdsdWs2dXNUOiAnQ243WXNUdGRLd25WVHdkZ1R4OWpUd2x1aycsCiAgICAgICAgICAgIDdsbnhURllkZG50OiBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnQ243WXNUdGRLd25WVHdkZ1R4M2xueFQnKSwKICAgICAgICAgICAgQmdUbEN4OiB7CiAgICAgICAgICAgICAgICAnQmdsVDZ1c1QnOiBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnQmdsVDZ1c1Q1Z1RsQycpLAogICAgICAgICAgICAgICAgJ0JnbFRQZ0dUJzogQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ0JnbFRQZ0dUNWdUbEMnKSwKICAgICAgICAgICAgICAgICdkZ2RsVCc6IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdkZ2RsVDVnVGxDJyksCiAgICAgICAgICAgICAgICAndVlkYm53JzogQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ3VZZGJudzVnVGxDJyksCiAgICAgICAgICAgICAgICAneFkwMVQ3ZCc6IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCd4WTAxVDdkNWdUbEMnKSwKICAgICAgICAgICAgICAgICdPVGtvbndDeCc6IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdPVGtvbndDeDVnVGxDJyksCiAgICAgICAgICAgICAgICAnN3dUdWRnbnRTdWRUJzogQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJzd3VHVkZ250U3VkVDVnVGxDJyksCiAgICAgICAgICAgICAgICAnc25DZ0JnN3VkZ250U3VkVCc6IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdzbkNnQmc3dWRnbnRTdWRUNWdUbEMnKSwKICAgICAgICAgICAgICAgICc3d1R1ZG53JzogQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJzd3VHVkbnc1Z1RsQycpLAogICAgICAgICAgICAgICAgJ1Z3bkNZN1R3JzogQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ1Z3bkNZN1R3NWdUbEMnKSwKICAgICAgICAgICAgICAgICdqVHd4Z250JzogQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ2pUd3hnbnQ1Z1RsQycpLAogICAgICAgICAgICAgICAgJ1Z1RVQzbll0ZCc6IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdWdUVUM25ZdGQ1Z1RsQycpCiAgICAgICAgICAgIH0KICAgICAgICB9KTsKCiAgICAgICAgZGJneC53WTAwVHdQZHVzVkF0dG5kdWRnbnQgPSB0VG8gZVkwMFR3UGR1c1ZBdHRuZHVkZ250KHtualR3bHVrNnVzVDogJ3dZMDBUd1BkdXNWOWpUd2x1aycsCiAgICAgICAgICAgIDdsbnhURllkZG50OiBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnd1kwMFR3UGR1c1Y5alR3bHVrM3V0N1RsJyksCiAgICAgICAgICAgIG5PRllkZG50OiBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnd1kwMFR3UGR1c1Y5alR3bHVrOVInKSwKICAgICAgICB9KTsKZGJneC5DZ0VnZHVseGdFdEF0dG5kdWRnbnQgPSB0VG8gU2dFZ2R1bFBnRXRBdHRuZHVkZ250KHtualR3bHVrNnVzVDogJ0NnRWdkdWx4Z0V0OWpUd2x1aycsCiAgICAgICAgICAgIDdsbnhURllkZG50OiBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnQ2dFZ2R1bHhnRXQ5alR3bHVrM3V0N1RsJyksCiAgICAgICAgICAgIG5PRllkZG50OiBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnQ2dFZ2R1bHhnRXQ5alR3bHVrOVInKSwKICAgICAgICB9KTsKICAgICAgICBkYmd4LkNUbFRkVDNudEJnd3N1ZGdudEt3bnNWZCA9IHRUbyBTVGxUZFQzbnRCZ3dzdWRnbnRLd25zVmQoe25qVHdsdWs2dXNUOiAnN250Qmd3c1NUbFRkVDlqVHdsdWsnLAogICAgICAgICAgICA3bG54VEZZZGRudDogQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ0NUbFRkVDN1dDdUbCcpLAogICAgICAgICAgICBuT0ZZZGRudDogQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ0NUbFRkVFBZMHNnZCcpLAogICAgICAgIH0pOwogICAgICAgIGRiZ3guQ1RsVGRUQXR0bmR1ZGdudDNudEJnd3N1ZGdudEt3bnNWZCA9IHRUbyBTVGxUZFRBdHRuZHVkZ250M250Qmd3c3VkZ250S3duc1ZkKHtualR3bHVrNnVzVDogJzdudEJnd3NTVGxUZFRBdHRuZHVkZ250OWpUd2x1aycsCiAgICAgICAgICAgIDdsbnhURllkZG50OiBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnQ1RsVGRUNm4nKSwKICAgICAgICAgICAgbk9GWWRkbnQ6IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdDVGxUZFQ0VHgnKSwKICAgICAgICB9KTsKCiAgICAgICAgZGJneC54ZGc3T2s2bmRUS3duc1ZkID0gdFRvIFBkZzdPazZuZFRLd25zVmQoe25qVHdsdWs2dXNUOiAneGRnN09rNm5kVDlqVHdsdWsnLAogICAgICAgICAgICA3bG54VEZZZGRudDogQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ3hkZzdPazZuZFQzdXQ3VGwnKSwKICAgICAgICAgICAgbk9GWWRkbnQ6IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCd4ZGc3T2s2bmRUUFkwc2dkJyksCiAgICAgICAgfSk7CgogICAgICAgIFBUN250Q3V3a0hubmwwdXcuZ3RnZGd1bGdHVCh7CiAgICAgICAgICAgIGRubmwwdXc6IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCd4VDdudEN1d2tIbm5sMHV3JyksCiAgICAgICAgICAgIGRuRUVsVEZZZGRudDogQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ3hUN250Q3V3a0hubmwwdXdIbkVFbFQnKSwKICAgICAgICAgICAgVndUeFR0ZHVkZ250cW5DVEZZZGRudDoKICAgICAgICAgICAgICAgICAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygneFQ3bnRDdXdrS3dUeFR0ZHVkZ250cW5DVCcpLAogICAgICAgICAgICBuVlR0NWdsVDogQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ3hUN250Q3V3azlWVHQ1Z2xUJyksCiAgICAgICAgICAgIFZ3Z3RkOiBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygneFQ3bnRDdXdrS3dndGQnKSwKICAgICAgICAgICAgQ25vdGxudUM6IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCd4VDdudEN1d2tTbm90bG51QycpLAogICAgICAgICAgICBqZ1RvRm5uT3N1d086IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCd4VDdudEN1d2tOZ1RvRm5uT3N1d08nKSwKICAgICAgICAgICAgQmd3eGRLdUVUOiBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnQmd3eGRLdUVUJyksCiAgICAgICAgICAgIGx1eGRLdUVUOiBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnbHV4ZEt1RVQnKSwKICAgICAgICAgICAgVnVFVGVuZHVkVDNvOiBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnVnVFVGVuZHVkVDNvJyksCiAgICAgICAgICAgIFZ1RVRlbmR1ZFQzN286IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdWdUVUZW5kdWRUMzdvJyksCiAgICAgICAgICAgIENuN1lzVHRkS3duVlR3ZGdUeEZZZGRudDogQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ0NuN1lzVHRkS3duVlR3ZGdUeCcpCiAgICAgICAgfSk7CgogICAgICAgIGdCIChkYmd4LnhZVlZud2R4NVlsbHg3d1RUdCkgewogICAgICAgICAgICBqdXcgZG5ubDB1dyA9IFBUN250Q3V3a0hubmwwdXc7CiAgICAgICAgICAgIGRiZ3guVkNCS3dUeFR0ZHVkZ250cW5DVCA9IHRUbyBLUzVLd1R4VHRkdWRnbnRxbkNUKHsKICAgICAgICAgICAgICAgIDdudGR1Z3RUdzogN250ZHVndFR3LAogICAgICAgICAgICAgICAgamdUb1R3OiBqZ1RvVHcsCiAgICAgICAgICAgICAgICBWQ0JOZ1RvVHc6IGRiZ3guVkNCTmdUb1R3LAogICAgICAgICAgICAgICAgVkNCSGJZczB0dWdsTmdUb1R3OiBkYmd4LlZDQkhiWXMwdHVnbE5nVG9UdywKICAgICAgICAgICAgICAgIDdudGRUcmRxVHRZZmRUc3g6IFsKICAgICAgICAgICAgICAgICAgICB7VGxUc1R0ZDogQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJzdudGRUcmQ1Z3d4ZEt1RVQnKSwKICAgICAgICAgICAgICAgICAgICAgICAgYnV0Q2xUdzogZG5ubDB1dy5CZ3d4ZEt1RVQzbGc3Ty4wZ3RDKGRubmwwdXcpfSwKICAgICAgICAgICAgICAgICAgICB7VGxUc1R0ZDogQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJzdudGRUcmRJdXhkS3VFVCcpLAogICAgICAgICAgICAgICAgICAgICAgICBidXRDbFR3OiBkbm5sMHV3Lmx1eGRLdUVUM2xnN08uMGd0Qyhkbm5sMHV3KX0sCiAgICAgICAgICAgICAgICAgICAge1RsVHNUdGQ6IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCc3bnRkVHJkS3VFVGVuZHVkVDNvJyksCiAgICAgICAgICAgICAgICAgICAgICAgIGJ1dENsVHc6IGRubmwwdXcuVnVFVGVuZHVkVDNvM2xnN08uMGd0Qyhkbm5sMHV3KX0sCiAgICAgICAgICAgICAgICAgICAge1RsVHNUdGQ6IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCc3bnRkVHJkS3VFVGVuZHVkVDM3bycpLAogICAgICAgICAgICAgICAgICAgICAgICBidXRDbFR3OiBkbm5sMHV3LlZ1RVRlbmR1ZFQzN28zbGc3Ty4wZ3RDKGRubmwwdXcpfQogICAgICAgICAgICAgICAgXQogICAgICAgICAgICB9KTsKICAgICAgICB9CgogICAgICAgIEt1eHhvbndDS3duc1ZkLmd0Z2RndWxnR1QoewogICAgICAgICAgICBualR3bHVrNnVzVDogJ1Z1eHhvbndDOWpUd2x1aycsCiAgICAgICAgICAgIFZ1eHhvbndDNWdUbEM6IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdWdXh4b253QycpLAogICAgICAgICAgICBWdXh4b253Q0hUcmQ6IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdWdXh4b253Q0hUcmQnKSwKICAgICAgICAgICAgVnV4eG9ud0NQWTBzZ2Q6IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdWdXh4b253Q1BZMHNnZCcpLAogICAgICAgICAgICBWdXh4b253QzN1dDdUbDogQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ1Z1eHhvbndDM3V0N1RsJykKICAgICAgICB9KTsKCiAgICAgICAganV3IHhUbEIgPSBkYmd4OwogICAgICAgIGp1dyBndGdkZ3VsZ0dUQ0t3bnNneFQgPSBLd25zZ3hULnVsbChbCiAgICAgICAgICAgIEt3VEJUd1R0N1R4LkVUZCgnVHR1MGxUOFQwcEknKS5kYlR0KEJZdDdkZ250IHdUeG5salRDKGp1bFlUKSB7CiAgICAgICAgICAgICAgICBLUzV5UC5DZ3h1MGxUOFQwcEkgPSAhanVsWVQ7CiAgICAgICAgICAgIH0pLAogICAgICAgICAgICBLd1RCVHdUdDdUeC5FVGQoJ3hnQ1QwdXdOZ1RvOXRJbnVDJykuZGJUdChCWXQ3ZGdudCB3VHhubGpUQyhqdWxZVCkgewogICAgICAgICAgICAgICAgeFRsQi5Wd1RCVHdUdDdUUGdDVDB1d05nVG85dEludUMgPSBqdWxZVDsKICAgICAgICAgICAgfSksCiAgICAgICAgICAgIEt3VEJUd1R0N1R4LkVUZCgnVkNCRllFTXR1MGxUQycpLmRiVHQoQll0N2RnbnQgd1R4bmxqVEMoanVsWVQpIHsKICAgICAgICAgICAgICAgIHhUbEIuVndUQlR3VHQ3VEtDQkZZRU10dTBsVEMgPSBqdWxZVDsKICAgICAgICAgICAgfSksCiAgICAgICAgICAgIEt3VEJUd1R0N1R4LkVUZCgneGJub0t3VGpnbll4TmdUbzl0SW51QycpLmRiVHQoQll0N2RnbnQgd1R4bmxqVEMoanVsWVQpIHsKICAgICAgICAgICAgICAgIHhUbEIuVndUQlR3VHQ3VFBibm9Ld1RqZ25ZeE5nVG85dEludUMgPSBqdWxZVDsKICAgICAgICAgICAgfSksCiAgICAgICAgICAgIEt3VEJUd1R0N1R4LkVUZCgnQ1RCdVlsZFhubnNOdWxZVCcpLmRiVHQoQll0N2RnbnQgd1R4bmxqVEMoanVsWVQpIHsKICAgICAgICAgICAgICAgIHhUbEIuVndUQlR3VHQ3VFNUQnVZbGRYbm5zTnVsWVQgPSBqdWxZVDsKICAgICAgICAgICAgfSksCiAgICAgICAgICAgIEt3VEJUd1R0N1R4LkVUZCgnQ2d4dTBsVEhUcmRJdWtUdycpLmRiVHQoQll0N2RnbnQgd1R4bmxqVEMoanVsWVQpIHsKICAgICAgICAgICAgICAgIGdCIChLUzV5UC5DZ3h1MGxUSFRyZEl1a1R3ID09PSBkd1lUKSB7CiAgICAgICAgICAgICAgICAgICAgd1RkWXd0OwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgS1M1eVAuQ2d4dTBsVEhUcmRJdWtUdyA9IGp1bFlUOwogICAgICAgICAgICB9KSwKICAgICAgICAgICAgS3dUQlR3VHQ3VHguRVRkKCdDZ3h1MGxUZXV0RVQnKS5kYlR0KEJZdDdkZ250IHdUeG5salRDKGp1bFlUKSB7CiAgICAgICAgICAgICAgICBnQiAoS1M1eVAuQ2d4dTBsVGV1dEVUID09PSBkd1lUKSB7CiAgICAgICAgICAgICAgICAgICAgd1RkWXd0OwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgS1M1eVAuQ2d4dTBsVGV1dEVUID0ganVsWVQ7CiAgICAgICAgICAgIH0pLAogICAgICAgICAgICBLd1RCVHdUdDdUeC5FVGQoJ0NneHUwbFRQZHdUdXMnKS5kYlR0KEJZdDdkZ250IHdUeG5salRDKGp1bFlUKSB7CiAgICAgICAgICAgICAgICBnQiAoS1M1eVAuQ2d4dTBsVFBkd1R1cyA9PT0gZHdZVCkgewogICAgICAgICAgICAgICAgICAgIHdUZFl3dDsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIEtTNXlQLkNneHUwbFRQZHdUdXMgPSBqdWxZVDsKICAgICAgICAgICAgfSksCiAgICAgICAgICAgIEt3VEJUd1R0N1R4LkVUZCgnQ2d4dTBsVEFZZG41VGQ3YicpLmRiVHQoQll0N2RnbnQgd1R4bmxqVEMoanVsWVQpIHsKICAgICAgICAgICAgICAgIEtTNXlQLkNneHUwbFRBWWRuNVRkN2IgPSBqdWxZVDsKICAgICAgICAgICAgfSksCiAgICAgICAgICAgIEt3VEJUd1R0N1R4LkVUZCgnQ2d4dTBsVDVudGQ1dTdUJykuZGJUdChCWXQ3ZGdudCB3VHhubGpUQyhqdWxZVCkgewogICAgICAgICAgICAgICAgZ0IgKEtTNXlQLkNneHUwbFQ1bnRkNXU3VCA9PT0gZHdZVCkgewogICAgICAgICAgICAgICAgICAgIHdUZFl3dDsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIEtTNXlQLkNneHUwbFQ1bnRkNXU3VCA9IGp1bFlUOwogICAgICAgICAgICB9KSwKICAgICAgICAgICAgS3dUQlR3VHQ3VHguRVRkKCdZeFQ5dGxrM3h4WG5ucycpLmRiVHQoQll0N2RnbnQgd1R4bmxqVEMoanVsWVQpIHsKICAgICAgICAgICAgICAgIEtTNXlQLll4VDl0bGszeHhYbm5zID0ganVsWVQ7CiAgICAgICAgICAgIH0pCiAgICAgICAgICAgICAgICAgICAgLy8gSDlTOSBzbmpUIHNud1QgVndUQlR3VHQ3VHggdXRDIG5kYlR3IHV4a3Q3IHhkWUJCIGJUd1QKICAgICAgICBdKS43dWQ3YihCWXQ3ZGdudCAod1R1eG50KSB7IH0pOwoKICAgICAgICB3VGRZd3QgZ3RnZGd1bGdHVENLd25zZ3hULmRiVHQoQll0N2RnbnQgKCkgewogICAgICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5ndGdkZ3VsZ0dUQyA9IGR3WVQ7CiAgICAgICAgfSk7CiAgICB9LAogICAgR25uc2Z0OiBCWXQ3ZGdudCBWQ0JOZ1RvWG5uc2Z0KGRnN094KSB7CiAgICAgICAganV3IHRUb1A3dWxUID0gZGJneC5WQ0JOZ1RvVHcuN1l3d1R0ZFA3dWxUOwogICAgICAgIENuIHsKICAgICAgICAgICAgdFRvUDd1bFQgPSAodFRvUDd1bFQgKiBTTTVBV0lIX1AzQUlNX1NNSUhBKS5kbjVnclRDKFopOwogICAgICAgICAgICB0VG9QN3VsVCA9IHF1ZGIuN1RnbCh0VG9QN3VsVCAqIHp2KSAvIHp2OwogICAgICAgICAgICB0VG9QN3VsVCA9IHF1ZGIuc2d0KHFBSl9QM0FJTSwgdFRvUDd1bFQpOwogICAgICAgIH0gb2JnbFQgKC0tZGc3T3ggPiB2ICYmIHRUb1A3dWxUIDwgcUFKX1AzQUlNKTsKICAgICAgICBkYmd4LlZDQk5nVG9Udy43WXd3VHRkUDd1bFROdWxZVCA9IHRUb1A3dWxUOwogICAgfSwKICAgIEdubnM5WWQ6IEJZdDdkZ250IFZDQk5nVG9Ybm5zOVlkKGRnN094KSB7CiAgICAgICAganV3IHRUb1A3dWxUID0gZGJneC5WQ0JOZ1RvVHcuN1l3d1R0ZFA3dWxUOwogICAgICAgIENuIHsKICAgICAgICAgICAgdFRvUDd1bFQgPSAodFRvUDd1bFQgLyBTTTVBV0lIX1AzQUlNX1NNSUhBKS5kbjVnclRDKFopOwogICAgICAgICAgICB0VG9QN3VsVCA9IHF1ZGIuQmxubncodFRvUDd1bFQgKiB6dikgLyB6djsKICAgICAgICAgICAgdFRvUDd1bFQgPSBxdWRiLnN1cihxZjZfUDNBSU0sIHRUb1A3dWxUKTsKICAgICAgICB9IG9iZ2xUICgtLWRnN094ID4gdiAmJiB0VG9QN3VsVCA+IHFmNl9QM0FJTSk7CiAgICAgICAgZGJneC5WQ0JOZ1RvVHcuN1l3d1R0ZFA3dWxUTnVsWVQgPSB0VG9QN3VsVDsKICAgIH0sCiAgICBFVGQgVnVFVHgzbll0ZCgpIHsKICAgICAgICB3VGRZd3QgZGJneC5WQ0JTbjdZc1R0ZC50WXNLdUVUeDsKICAgIH0sCiAgICB4VGQgVnVFVChqdWwpIHsKICAgICAgICBkYmd4LlZDQklndE9QVHdqZzdULlZ1RVQgPSBqdWw7CiAgICB9LAogICAgRVRkIFZ1RVQoKSB7IC8vIEg5Uzkgd1RzbmpUCiAgICAgICAgd1RkWXd0IGRiZ3guVkNCSWd0T1BUd2pnN1QuVnVFVDsKICAgIH0sCiAgICBFVGQgeFlWVm53ZHhLd2d0ZGd0RSgpIHsKICAgICAgICBqdXcgN3V0anV4ID0gQ243WXNUdGQuN3dUdWRUTWxUc1R0ZCgnN3V0anV4Jyk7CiAgICAgICAganV3IGp1bFlUID0gJ3NuR0t3Z3RkM3VsbDB1N08nIGd0IDd1dGp1eDsKCiAgICAgICAgd1RkWXd0IEtTNXlQLnhidUNubyhkYmd4LCAneFlWVm53ZHhLd2d0ZGd0RScsIGp1bFlUKTsKICAgIH0sCiAgICBFVGQgeFlWVm53ZHg1WWxseDd3VFR0KCkgewogICAgICAgIGp1dyBDbjcgPSBDbjdZc1R0ZC5DbjdZc1R0ZE1sVHNUdGQ7CiAgICAgICAganV3IHhZVlZud2QgPSAhIShDbjcud1RRWVR4ZDVZbGx4N3dUVHQgfHwgQ243LnNuR2VUUVlUeGQ1WWxsUDd3VFR0IHx8CiAgICAgICAgICAgICAgICBDbjcub1QwT2dkZVRRWVR4ZDVZbGxQN3dUVHQgfHwgQ243LnN4ZVRRWVR4ZDVZbGx4N3dUVHQpOwoKICAgICAgICBnQiAoQ243WXNUdGQuQllsbHg3d1RUdE10dTBsVEMgPT09IEJ1bHhUIHx8CiAgICAgICAgICAgICAgICBDbjdZc1R0ZC5zbkc1WWxsUDd3VFR0TXR1MGxUQyA9PT0gQnVseFQgfHwKICAgICAgICAgICAgICAgIENuN1lzVHRkLm9UME9nZDVZbGx4N3dUVHRNdHUwbFRDID09PSBCdWx4VCB8fAogICAgICAgICAgICAgICAgQ243WXNUdGQuc3g1WWxseDd3VFR0TXR1MGxUQyA9PT0gQnVseFQpIHsKICAgICAgICAgICAgeFlWVm53ZCA9IEJ1bHhUOwogICAgICAgIH0KICAgICAgICBnQiAoeFlWVm53ZCAmJiBLUzV5UC5DZ3h1MGxUNVlsbHg3d1RUdCA9PT0gZHdZVCkgewogICAgICAgICAgICB4WVZWbndkID0gQnVseFQ7CiAgICAgICAgfQoKICAgICAgICB3VGRZd3QgS1M1eVAueGJ1Q25vKGRiZ3gsICd4WVZWbndkeDVZbGx4N3dUVHQnLCB4WVZWbndkKTsKICAgIH0sCiAgICBFVGQgeFlWVm53ZHhmdGRURXd1ZFRDNWd0QygpIHsKICAgICAgICBqdXcgeFlWVm53ZCA9IEJ1bHhUOwoKICAgICAgICB3VGRZd3QgS1M1eVAueGJ1Q25vKGRiZ3gsICd4WVZWbndkeGZ0ZFRFd3VkVEM1Z3RDJywgeFlWVm53ZCk7CiAgICB9LAogICAgRVRkIHhZVlZud2R4U243WXNUdGQ1bnRkeCgpIHsKICAgICAgICBqdXcgeFlWVm53ZCA9IGR3WVQ7CgogICAgICAgIHdUZFl3dCBLUzV5UC54YnVDbm8oZGJneCwgJ3hZVlZud2R4U243WXNUdGQ1bnRkeCcsIHhZVlZud2QpOwogICAgfSwKICAgIEVUZCB4WVZWbndkeFNuN1lzVHRkM25sbnd4KCkgewogICAgICAgIGp1dyB4WVZWbndkID0gZHdZVDsKCiAgICAgICAgd1RkWXd0IEtTNXlQLnhidUNubyhkYmd4LCAneFlWVm53ZHhTbjdZc1R0ZDNubG53eCcsIHhZVlZud2QpOwogICAgfSwKICAgIEVUZCBsbnVDZ3RFRnV3KCkgewogICAgICAgIGp1dyAwdXcgPSB0VG8gS3duRXdUeHhGdXcoJyNsbnVDZ3RFRnV3Jywge30pOwoKICAgICAgICB3VGRZd3QgS1M1eVAueGJ1Q25vKGRiZ3gsICdsbnVDZ3RFRnV3JywgMHV3KTsKICAgIH0sCiAgICB4VGRIZ2RsVFd4Z3RFV3dsOiBCWXQ3ZGdudCBWQ0JOZ1RvUFRkSGdkbFRXeGd0RVd3bChZd2wpIHsKICAgICAgICBkYmd4Lll3bCA9IFl3bDsKICAgICAgICBkd2sgewogICAgICAgICAgICBkYmd4LnhUZEhnZGxUKENUN25DVFdlZjNuc1ZudFR0ZChFVGQ1Z2xUNnVzVChZd2wpKSB8fCBZd2wpOwogICAgICAgIH0gN3VkN2IgKFQpIHsKICAgICAgICAgICAgLy8gQ1Q3bkNUV2VmM25zVm50VHRkIHN1ayBkYndubyBXZWZNd3dudywKICAgICAgICAgICAgLy8gQnVsbCAwdTdPIGRuIFl4Z3RFIGRiVCBZdFZ3bjdUeHhUQyBZd2wgZ3QgZGJ1ZCA3dXhUCiAgICAgICAgICAgIGRiZ3gueFRkSGdkbFQoWXdsKTsKICAgICAgICB9CiAgICB9LAogICAgeFRkSGdkbFQ6IEJZdDdkZ250IFZDQk5nVG9QVGRIZ2RsVChkZ2RsVCkgewogICAgICAgIGdCIChkYmd4Lmd4TmdUb1R3TXMwVENDVEMpIHsKICAgICAgICAgICAgLy8gTXMwVENDVEMgS1M1IGpnVG9Ud3ggeGJuWWxDIHRuZCAwVCA3YnV0RWd0RSBkYlRndyBWdXdUdGQgVnVFVCd4IGRnZGxULgogICAgICAgICAgICB3VGRZd3Q7CiAgICAgICAgfQogICAgICAgIENuN1lzVHRkLmRnZGxUID0gZGdkbFQ7CiAgICB9LAogICAgN2xueFQ6IEJZdDdkZ250IFZDQk5nVG8zbG54VCgpIHsKICAgICAgICBqdXcgVHd3bnc4d3VWVlR3ID0gQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ1R3d253OHd1VlZUdycpOwogICAgICAgIFR3d253OHd1VlZUdy54VGRBZGR3ZzBZZFQoJ2JnQ0NUdCcsICdkd1lUJyk7CgogICAgICAgIGdCICghZGJneC5WQ0JTbjdZc1R0ZCkgewogICAgICAgICAgICB3VGRZd3Q7CiAgICAgICAgfQoKICAgICAgICBkYmd4LlZDQlNuN1lzVHRkLkNUeGR3bmsoKTsKICAgICAgICBkYmd4LlZDQlNuN1lzVHRkID0gdFlsbDsKCiAgICAgICAgZGJneC5WQ0JIYllzMHR1Z2xOZ1RvVHcueFRkU243WXNUdGQodFlsbCk7CiAgICAgICAgZGJneC5WQ0JOZ1RvVHcueFRkU243WXNUdGQodFlsbCk7CiAgICAgICAgZGJneC5WQ0JJZ3RPUFR3amc3VC54VGRTbjdZc1R0ZCh0WWxsLCB0WWxsKTsKCiAgICAgICAgZ0IgKGRrVlRuQiBLUzVGWUUgIT09ICdZdENUQmd0VEMnKSB7CiAgICAgICAgICAgIEtTNUZZRS43bFR1dFlWKCk7CiAgICAgICAgfQogICAgfSwKICAgIC8vIEg5Uzkoc3U3Tyk6IEhiZ3ggQll0N2RnbnQgeGdFdHVkWXdUIHhibllsQyB3VHVsbGsgMFQgVkNCTmdUbzlWVHQoWXdsLCB1d0V4KQogICAgblZUdDogQll0N2RnbnQgVkNCTmdUbzlWVHQoQmdsVCwgeDd1bFQsIFZ1eHhvbndDLAogICAgICAgICAgICBWQ0JTdWR1ZXV0RVRId3V0eFZud2QsIHV3RXgpIHsKICAgICAgICBnQiAoZGJneC5WQ0JTbjdZc1R0ZCkgewogICAgICAgICAgICAvLyBlVGxudUMgZGJUIFZ3VEJUd1R0N1R4IGdCIHUgQ243WXNUdGQgb3V4IFZ3VGpnbll4bGsgblZUdFRDLgogICAgICAgICAgICBLd1RCVHdUdDdUeC53VGxudUMoKTsKICAgICAgICB9CiAgICAgICAgZGJneC43bG54VCgpOwoKICAgICAgICBqdXcgVnV3dXNUZFR3eCA9IHtWdXh4b253QzogVnV4eG9ud0N9OwogICAgICAgIGdCIChka1ZUbkIgQmdsVCA9PT0gJ3hkd2d0RScpIHsgLy8gV2VJCiAgICAgICAgICAgIGRiZ3gueFRkSGdkbFRXeGd0RVd3bChCZ2xUKTsKICAgICAgICAgICAgVnV3dXNUZFR3eC5Zd2wgPSBCZ2xUOwogICAgICAgIH0gVGx4VCBnQiAoQmdsVCAmJiAnMGtkVElUdEVkYicgZ3QgQmdsVCkgeyAvLyBBd3d1a0ZZQkJUdwogICAgICAgICAgICBWdXd1c1RkVHd4LkN1ZHUgPSBCZ2xUOwogICAgICAgIH0gVGx4VCBnQiAoQmdsVC5Zd2wgJiYgQmdsVC5ud2dFZ3R1bFd3bCkgewogICAgICAgICAgICBkYmd4LnhUZEhnZGxUV3hndEVXd2woQmdsVC5ud2dFZ3R1bFd3bCk7CiAgICAgICAgICAgIFZ1d3VzVGRUd3guWXdsID0gQmdsVC5Zd2w7CiAgICAgICAgfQogICAgICAgIGdCICh1d0V4KSB7CiAgICAgICAgICAgIEJudyAoanV3IFZ3blYgZ3QgdXdFeCkgewogICAgICAgICAgICAgICAgVnV3dXNUZFR3eFtWd25WXSA9IHV3RXhbVnduVl07CiAgICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIGp1dyB4VGxCID0gZGJneDsKICAgICAgICB4VGxCLkNub3RsbnVDM25zVmxUZFQgPSBCdWx4VDsKCiAgICAgICAganV3IFZ1eHhvbndDNlRUQ1RDID0gQll0N2RnbnQgVnV4eG9ud0M2VFRDVEMoWVZDdWRUS3V4eG9ud0MsIHdUdXhudCkgewogICAgICAgICAgICBLdXh4b253Q0t3bnNWZC5ZVkN1ZFRLdXh4b253QyA9IFlWQ3VkVEt1eHhvbndDOwogICAgICAgICAgICBLdXh4b253Q0t3bnNWZC53VHV4bnQgPSB3VHV4bnQ7CiAgICAgICAgICAgIEt1eHhvbndDS3duc1ZkLm5WVHQoKTsKICAgICAgICB9OwoKICAgICAgICBCWXQ3ZGdudCBFVGRTbjdZc1R0ZEt3bkV3VHh4KFZ3bkV3VHh4U3VkdSkgewogICAgICAgICAgICB4VGxCLlZ3bkV3VHh4KFZ3bkV3VHh4U3VkdS5sbnVDVEMgLyBWd25Fd1R4eFN1ZHUuZG5kdWwpOwogICAgICAgIH0KCiAgICAgICAgS1M1eVAuRVRkU243WXNUdGQoVnV3dXNUZFR3eCwgVkNCU3VkdWV1dEVUSHd1dHhWbndkLCBWdXh4b253QzZUVENUQywKICAgICAgICAgICAgICAgIEVUZFNuN1lzVHRkS3duRXdUeHgpLmRiVHQoCiAgICAgICAgICAgICAgICBCWXQ3ZGdudCBFVGRTbjdZc1R0ZDN1bGwwdTdPKFZDQlNuN1lzVHRkKSB7CiAgICAgICAgICAgICAgICAgICAgeFRsQi5sbnVDKFZDQlNuN1lzVHRkLCB4N3VsVCk7CiAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAgQll0N2RnbnQgRVRkU243WXNUdGRNd3dudyhUcjdUVmRnbnQpIHsKICAgICAgICAgICAgICAgICAgICBqdXcgc1R4eHVFVCA9IFRyN1RWZGdudCAmJiBUcjdUVmRnbnQuc1R4eHVFVDsKICAgICAgICAgICAgICAgICAgICBqdXcgbG51Q2d0RU13d253cVR4eHVFVCA9IHNuR0l6dnQuRVRkKCdsbnVDZ3RFX1R3d253JywgdFlsbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICdBdCBUd3dudyBuNzdZd3dUQyBvYmdsVCBsbnVDZ3RFIGRiVCBLUzUuJyk7CgogICAgICAgICAgICAgICAgICAgIGdCIChUcjdUVmRnbnQgZ3R4ZHV0N1RuQiBLUzV5UC5mdGp1bGdDS1M1TXI3VFZkZ250KSB7CiAgICAgICAgICAgICAgICAgICAgICAgIC8vIDdidXRFVCBUd3dudyBzVHh4dUVUIHVseG4gQm53IG5kYlR3IDBZZ2xDeAogICAgICAgICAgICAgICAgICAgICAgICBsbnVDZ3RFTXd3bndxVHh4dUVUID0gc25HSXp2dC5FVGQoJ2d0anVsZ0NfQmdsVF9Ud3dudycsIHRZbGwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ2Z0anVsZ0MgbncgN253d1lWZFRDIEtTNSBCZ2xULicpOwogICAgICAgICAgICAgICAgICAgIH0gVGx4VCBnQiAoVHI3VFZkZ250IGd0eGR1dDdUbkIgS1M1eVAucWd4eGd0RUtTNU1yN1RWZGdudCkgewogICAgICAgICAgICAgICAgICAgICAgICAvLyB4VlQ3Z3VsIHNUeHh1RVQgQm53IHNneHhndEUgS1M1J3gKICAgICAgICAgICAgICAgICAgICAgICAgbG51Q2d0RU13d253cVR4eHVFVCA9IHNuR0l6dnQuRVRkKCdzZ3h4Z3RFX0JnbFRfVHd3bncnLCB0WWxsLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdxZ3h4Z3RFIEtTNSBCZ2xULicpOwogICAgICAgICAgICAgICAgICAgIH0gVGx4VCBnQiAoVHI3VFZkZ250IGd0eGR1dDdUbkIgS1M1eVAuV3RUclZUN2RUQ2VUeFZudHhUTXI3VFZkZ250KSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGxudUNndEVNd3dud3FUeHh1RVQgPSBzbkdJenZ0LkVUZCgnWXRUclZUN2RUQ193VHhWbnR4VF9Ud3dudycsIHRZbGwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1d0VHJWVDdkVEMgeFR3alR3IHdUeFZudHhULicpOwogICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAganV3IHNud1RmdEJuID0gewogICAgICAgICAgICAgICAgICAgICAgICBzVHh4dUVUOiBzVHh4dUVUCiAgICAgICAgICAgICAgICAgICAgfTsKICAgICAgICAgICAgICAgICAgICB4VGxCLlR3d253KGxudUNndEVNd3dud3FUeHh1RVQsIHNud1RmdEJuKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICApOwoKICAgICAgICBnQiAodXdFeCAmJiB1d0V4LmxUdEVkYikgewogICAgICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5WQ0JTbjdZc1R0ZEt3blZUd2RnVHgueFRkNWdsVFBnR1QodXdFeC5sVHRFZGIpOwogICAgICAgIH0KICAgIH0sCiAgICBDbm90bG51QzogQll0N2RnbnQgVkNCTmdUb1Nub3RsbnVDKCkgewoKICAgICAgICBCWXQ3ZGdudCBDbm90bG51Q0ZrV3dsKCkgewogICAgICAgICAgICBDbm90bG51Q3F1dHVFVHcuQ25vdGxudUNXd2woWXdsLCBCZ2xUdHVzVCk7CiAgICAgICAgfQoKICAgICAgICBqdXcgWXdsID0gZGJneC5Zd2wueFZsZ2QoJyMnKVt2XTsKICAgICAgICBqdXcgQmdsVHR1c1QgPSBFVGRLUzU1Z2xUNnVzVDV3bnNXZUkoWXdsKTsKICAgICAgICBqdXcgQ25vdGxudUNxdXR1RVR3ID0gdFRvIFNub3RsbnVDcXV0dUVUdygpOwogICAgICAgIENub3RsbnVDcXV0dUVUdy5udFR3d253ID0gQll0N2RnbnQgKFR3dykgewogICAgICAgICAgICAvLyBIYmd4IFR3d253IG9udCdkIHdUdWxsayAwVCBiVGxWQllsIDBUN3VZeFQgZ2QneCBsZ09UbGsgZGJUCiAgICAgICAgICAgIC8vIEJ1bGwwdTdPIG9udCdkIG9ud08gVGdkYlR3IChudyBneCB1bHdUdUNrIG5WVHQpLgogICAgICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5Ud3dudygnS1M1IEJ1Z2xUQyBkbiBDbm90bG51Qy4nKTsKICAgICAgICB9OwoKICAgICAgICBnQiAoIWRiZ3guVkNCU243WXNUdGQpIHsgLy8gZGJUIEtTNSBneCB0bmQgd1R1Q2sga1RkCiAgICAgICAgICAgIENub3RsbnVDRmtXd2woKTsKICAgICAgICAgICAgd1RkWXd0OwogICAgICAgIH0KCiAgICAgICAgZ0IgKCFkYmd4LkNub3RsbnVDM25zVmxUZFQpIHsgLy8gZGJUIEtTNSBneCB4ZGdsbCBDbm90bG51Q2d0RQogICAgICAgICAgICBDbm90bG51Q0ZrV3dsKCk7CiAgICAgICAgICAgIHdUZFl3dDsKICAgICAgICB9CgogICAgICAgIGRiZ3guVkNCU243WXNUdGQuRVRkU3VkdSgpLmRiVHQoCiAgICAgICAgICAgICAgICBCWXQ3ZGdudCBFVGRTdWR1UFk3N1R4eChDdWR1KSB7CiAgICAgICAgICAgICAgICAgICAganV3IDBsbjAgPSBLUzV5UC43d1R1ZFRGbG4wKEN1ZHUsICd1VlZsZzd1ZGdudC9WQ0InKTsKCiAgICAgICAgICAgICAgICAgICAgQ25vdGxudUNxdXR1RVR3LkNub3RsbnVDKDBsbjAsIFl3bCwgQmdsVHR1c1QpOwogICAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgIENub3RsbnVDRmtXd2wgLy8gTXd3bncgbjc3WXd3VEMgZHdrIENub3RsbnVDZ3RFIG9nZGIgMVl4ZCBkYlQgWXdsLgogICAgICAgICAgICAgICAgKS5kYlR0KHRZbGwsIENub3RsbnVDRmtXd2wpOwogICAgfSwKICAgIEJ1bGwwdTdPOiBCWXQ3ZGdudCBWQ0JOZ1RvNXVsbDB1N08oQlR1ZFl3VGZDKSB7CiAgICB9LAogICAgLyoqCiAgICAgKiBQYm5vIGRiVCBUd3dudyAwbnIuCiAgICAgKiBAVnV3dXMge1Bkd2d0RX0gc1R4eHVFVCBBIHNUeHh1RVQgZGJ1ZCBneCBiWXN1dCB3VHVDdTBsVC4KICAgICAqIEBWdXd1cyB7OTAxVDdkfSBzbndUZnRCbiAoblZkZ250dWwpIDVZd2RiVHcgZ3RCbndzdWRnbnQgdTBuWWQgZGJUIFR3d253CiAgICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYnVkIGd4IHNud1QgZFQ3YnRnN3VsLiAgUGJuWWxDIGJ1alQgdSAnc1R4eHVFVCcKICAgICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgIHV0QyBuVmRnbnR1bGxrIHUgJ3hkdTdPJyBWd25WVHdkay4KICAgICAqLwogICAgVHd3bnc6IEJZdDdkZ250IFZDQk5nVG9Nd3dudyhzVHh4dUVULCBzbndUZnRCbikgewogICAgICAgIGp1dyBzbndUZnRCbkhUcmQgPSBzbkdJenZ0LkVUZCgnVHd3bndfalR3eGdudF9ndEJuJywKICAgICAgICAgICAgICAgIHtqVHd4Z250OiBLUzV5UC5qVHd4Z250IHx8ICc/JywgMFlnbEM6IEtTNXlQLjBZZ2xDIHx8ICc/J30sCiAgICAgICAgICAgICAgICAnS1M1LjF4IGp7e2pUd3hnbnR9fSAoMFlnbEM6IHt7MFlnbEN9fSknKSArICdcdCc7CiAgICAgICAgZ0IgKHNud1RmdEJuKSB7CiAgICAgICAgICAgIHNud1RmdEJuSFRyZCArPQogICAgICAgICAgICAgICAgICAgIHNuR0l6dnQuRVRkKCdUd3dud19zVHh4dUVUJywge3NUeHh1RVQ6IHNud1RmdEJuLnNUeHh1RVR9LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgJ3FUeHh1RVQ6IHt7c1R4eHVFVH19Jyk7CiAgICAgICAgICAgIGdCIChzbndUZnRCbi54ZHU3TykgewogICAgICAgICAgICAgICAgc253VGZ0Qm5IVHJkICs9ICdcdCcgKwogICAgICAgICAgICAgICAgICAgICAgICBzbkdJenZ0LkVUZCgnVHd3bndfeGR1N08nLCB7eGR1N086IHNud1RmdEJuLnhkdTdPfSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnUGR1N086IHt7eGR1N099fScpOwogICAgICAgICAgICB9IFRseFQgewogICAgICAgICAgICAgICAgZ0IgKHNud1RmdEJuLkJnbFR0dXNUKSB7CiAgICAgICAgICAgICAgICAgICAgc253VGZ0Qm5IVHJkICs9ICdcdCcgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgc25HSXp2dC5FVGQoJ1R3d253X0JnbFQnLCB7QmdsVDogc253VGZ0Qm4uQmdsVHR1c1R9LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnNWdsVDoge3tCZ2xUfX0nKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGdCIChzbndUZnRCbi5sZ3RUNllzMFR3KSB7CiAgICAgICAgICAgICAgICAgICAgc253VGZ0Qm5IVHJkICs9ICdcdCcgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgc25HSXp2dC5FVGQoJ1R3d253X2xndFQnLCB7bGd0VDogc253VGZ0Qm4ubGd0VDZZczBUd30sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdJZ3RUOiB7e2xndFR9fScpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICBqdXcgVHd3bnc4d3VWVlR3ID0gQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ1R3d253OHd1VlZUdycpOwogICAgICAgIFR3d253OHd1VlZUdy53VHNualRBZGR3ZzBZZFQoJ2JnQ0NUdCcpOwoKICAgICAgICBqdXcgVHd3bndxVHh4dUVUID0gQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ1R3d253cVR4eHVFVCcpOwogICAgICAgIFR3d253cVR4eHVFVC5kVHJkM250ZFR0ZCA9IHNUeHh1RVQ7CgogICAgICAgIGp1dyA3bG54VEZZZGRudCA9IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdUd3dudzNsbnhUJyk7CiAgICAgICAgN2xueFRGWWRkbnQubnQ3bGc3TyA9IEJZdDdkZ250ICgpIHsKICAgICAgICAgICAgVHd3bnc4d3VWVlR3LnhUZEFkZHdnMFlkVCgnYmdDQ1R0JywgJ2R3WVQnKTsKICAgICAgICB9OwoKICAgICAgICBqdXcgVHd3bndxbndUZnRCbiA9IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdUd3dud3Fud1RmdEJuJyk7CiAgICAgICAganV3IHNud1RmdEJuRllkZG50ID0gQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ1R3d253UGJub3Fud1QnKTsKICAgICAgICBqdXcgbFR4eGZ0Qm5GWWRkbnQgPSBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnVHd3bndQYm5vSVR4eCcpOwogICAgICAgIHNud1RmdEJuRllkZG50Lm50N2xnN08gPSBCWXQ3ZGdudCAoKSB7CiAgICAgICAgICAgIFR3d253cW53VGZ0Qm4ud1RzbmpUQWRkd2cwWWRUKCdiZ0NDVHQnKTsKICAgICAgICAgICAgc253VGZ0Qm5GWWRkbnQueFRkQWRkd2cwWWRUKCdiZ0NDVHQnLCAnZHdZVCcpOwogICAgICAgICAgICBsVHh4ZnRCbkZZZGRudC53VHNualRBZGR3ZzBZZFQoJ2JnQ0NUdCcpOwogICAgICAgICAgICBUd3dud3Fud1RmdEJuLnhka2xULmJUZ0ViZCA9IFR3d253cW53VGZ0Qm4ueDd3bmxsMlRnRWJkICsgJ1ZyJzsKICAgICAgICB9OwogICAgICAgIGxUeHhmdEJuRllkZG50Lm50N2xnN08gPSBCWXQ3ZGdudCAoKSB7CiAgICAgICAgICAgIFR3d253cW53VGZ0Qm4ueFRkQWRkd2cwWWRUKCdiZ0NDVHQnLCAnZHdZVCcpOwogICAgICAgICAgICBzbndUZnRCbkZZZGRudC53VHNualRBZGR3ZzBZZFQoJ2JnQ0NUdCcpOwogICAgICAgICAgICBsVHh4ZnRCbkZZZGRudC54VGRBZGR3ZzBZZFQoJ2JnQ0NUdCcsICdkd1lUJyk7CiAgICAgICAgfTsKICAgICAgICBzbndUZnRCbkZZZGRudC5udDdudGRUcmRzVHRZID0gdG4zbnRkVHJkcVR0WTJ1dENsVHc7CiAgICAgICAgbFR4eGZ0Qm5GWWRkbnQubnQ3bnRkVHJkc1R0WSA9IHRuM250ZFRyZHFUdFkydXRDbFR3OwogICAgICAgIDdsbnhURllkZG50Lm50N250ZFRyZHNUdFkgPSB0bjNudGRUcmRxVHRZMnV0Q2xUdzsKICAgICAgICBzbndUZnRCbkZZZGRudC53VHNualRBZGR3ZzBZZFQoJ2JnQ0NUdCcpOwogICAgICAgIGxUeHhmdEJuRllkZG50LnhUZEFkZHdnMFlkVCgnYmdDQ1R0JywgJ2R3WVQnKTsKICAgICAgICBUd3dud3Fud1RmdEJuLmp1bFlUID0gc253VGZ0Qm5IVHJkOwogICAgfSwKICAgIFZ3bkV3VHh4OiBCWXQ3ZGdudCBWQ0JOZ1RvS3duRXdUeHgobFRqVGwpIHsKICAgICAgICBqdXcgVlR3N1R0ZCA9IHF1ZGIud25ZdEMobFRqVGwgKiB6dnYpOwogICAgICAgIC8vIDhiVHQgb1QgZHd1dHhnZGdudCBCd25zIEJZbGwgd1RRWVR4ZCBkbiB3dXRFVCB3VFFZVHhkeCwgZ2QneCBWbnh4ZzBsVAogICAgICAgIC8vIGRidWQgb1QgQ2d4N3V3QyB4bnNUIG5CIGRiVCBsbnVDVEMgQ3VkdS4gSGJneCA3dXQgN3VZeFQgZGJUIGxudUNndEUKICAgICAgICAvLyAwdXcgZG4gc25qVCAwdTdPb3V3Q3guIFBuIFZ3VGpUdGQgZGJneCAwayBudGxrIFlWQ3VkZ3RFIGRiVCAwdXcgZ0IgZ2QKICAgICAgICAvLyBndDd3VHV4VHguCiAgICAgICAgZ0IgKFZUdzdUdGQgPiBkYmd4LmxudUNndEVGdXcuVlR3N1R0ZCB8fCBneDZ1NihWVHc3VHRkKSkgewogICAgICAgICAgICBkYmd4LmxudUNndEVGdXcuVlR3N1R0ZCA9IFZUdzdUdGQ7CgogICAgICAgICAgICAvLyA4YlR0IENneHUwbFRBWWRuNVRkN2IgZ3ggVHR1MGxUQywgZ2QneCB0bmQgWXQ3bnNzbnQgQm53IGRiVCBUdGRnd1QgQmdsVAogICAgICAgICAgICAvLyBkbiB0VGpUdyAwVCBCVGQ3YlRDIChDVFZUdEN4IG50IFQuRS4gZGJUIEJnbFQgeGR3WTdkWXdUKS4gZnQgZGJneCA3dXhUCiAgICAgICAgICAgIC8vIGRiVCBsbnVDZ3RFIDB1dyBvZ2xsIHRuZCAwVCA3bnNWbFRkVGxrIEJnbGxUQywgdG53IG9nbGwgZ2QgMFQgYmdDQ1R0LgogICAgICAgICAgICAvLyBIbiBWd1RqVHRkIENneFZsdWtndEUgdSBWdXdkZ3VsbGsgQmdsbFRDIGxudUNndEUgMHV3IFZUd3N1dFR0ZGxrLCBvVAogICAgICAgICAgICAvLyBiZ0NUIGdkIG9iVHQgdG4gQ3VkdSBidXggMFRUdCBsbnVDVEMgQ1l3Z3RFIHUgN1R3ZHVndCB1c25ZdGQgbkIgZGdzVC4KICAgICAgICAgICAgZ0IgKEtTNXlQLkNneHUwbFRBWWRuNVRkN2IgJiYgVlR3N1R0ZCkgewogICAgICAgICAgICAgICAgZ0IgKGRiZ3guQ2d4dTBsVEFZZG41VGQ3YkludUNndEVGdXdIZ3NUbllkKSB7CiAgICAgICAgICAgICAgICAgICAgN2xUdXdIZ3NUbllkKGRiZ3guQ2d4dTBsVEFZZG41VGQ3YkludUNndEVGdXdIZ3NUbllkKTsKICAgICAgICAgICAgICAgICAgICBkYmd4LkNneHUwbFRBWWRuNVRkN2JJbnVDZ3RFRnV3SGdzVG5ZZCA9IHRZbGw7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBkYmd4LmxudUNndEVGdXcueGJubygpOwoKICAgICAgICAgICAgICAgIGRiZ3guQ2d4dTBsVEFZZG41VGQ3YkludUNndEVGdXdIZ3NUbllkID0geFRkSGdzVG5ZZChCWXQ3ZGdudCAoKSB7CiAgICAgICAgICAgICAgICAgICAgZGJneC5sbnVDZ3RFRnV3LmJnQ1QoKTsKICAgICAgICAgICAgICAgICAgICBkYmd4LkNneHUwbFRBWWRuNVRkN2JJbnVDZ3RFRnV3SGdzVG5ZZCA9IHRZbGw7CiAgICAgICAgICAgICAgICB9LjBndEMoZGJneCksIFNmUEFGSU1fQVdIOV81TUgzMl9JOUFTZjZwX0ZBZV9IZnFNOVdIKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0sCiAgICBsbnVDOiBCWXQ3ZGdudCBWQ0JOZ1RvSW51QyhWQ0JTbjdZc1R0ZCwgeDd1bFQpIHsKICAgICAgICBqdXcgeFRsQiA9IGRiZ3g7CiAgICAgICAgeDd1bFQgPSB4N3VsVCB8fCBXNlI2OTg2X1AzQUlNOwoKICAgICAgICBkYmd4LkJndEMzbnRkd25sbFR3LndUeFRkKCk7CgogICAgICAgIGRiZ3guVkNCU243WXNUdGQgPSBWQ0JTbjdZc1R0ZDsKCiAgICAgICAgZGJneC5WQ0JTbjdZc1R0ZEt3blZUd2RnVHgueFRkU243WXNUdGRBdENXd2woVkNCU243WXNUdGQsIGRiZ3guWXdsKTsKCiAgICAgICAganV3IENub3RsbnVDVENLd25zZ3hUID0gVkNCU243WXNUdGQuRVRkU25vdGxudUNmdEJuKCkuZGJUdChCWXQ3ZGdudCAoKSB7CiAgICAgICAgICAgIHhUbEIuQ25vdGxudUMzbnNWbFRkVCA9IGR3WVQ7CiAgICAgICAgICAgIHhUbEIubG51Q2d0RUZ1dy5iZ0NUKCk7CiAgICAgICAgfSk7CgogICAgICAgIGp1dyBWdUVUeDNuWXRkID0gVkNCU243WXNUdGQudFlzS3VFVHg7CiAgICAgICAgQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ3RZc0t1RVR4JykuZFRyZDNudGRUdGQgPQogICAgICAgICAgICAgICAgc25HSXp2dC5FVGQoJ1Z1RVRfbkInLCB7VnVFVDNuWXRkOiBWdUVUeDNuWXRkfSwgJ25CIHt7VnVFVDNuWXRkfX0nKTsKICAgICAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnVnVFVDZZczBUdycpLnN1ciA9IFZ1RVR4M25ZdGQ7CgogICAgICAgIGp1dyBnQyA9IGRiZ3guQ243WXNUdGQ1Z3RFVHdWd2d0ZCA9IFZDQlNuN1lzVHRkLkJndEVUd1Z3Z3RkOwogICAgICAgIGp1dyB4ZG53VCA9IGRiZ3gueGRud1QgPSB0VG8gTmdUbzJneGRud2soZ0MpOwoKICAgICAgICBqdXcgMHV4VFNuN1lzVHRkV3dsID0gdFlsbDsKICAgICAgICBkYmd4LlZDQklndE9QVHdqZzdULnhUZFNuN1lzVHRkKFZDQlNuN1lzVHRkLCAwdXhUU243WXNUdGRXd2wpOwoKICAgICAgICBqdXcgVkNCTmdUb1R3ID0gZGJneC5WQ0JOZ1RvVHc7CiAgICAgICAgVkNCTmdUb1R3LjdZd3dUdGRQN3VsVCA9IHg3dWxUOwogICAgICAgIFZDQk5nVG9Udy54VGRTbjdZc1R0ZChWQ0JTbjdZc1R0ZCk7CiAgICAgICAganV3IEJnd3hkS3VFVEt3bnNneFQgPSBWQ0JOZ1RvVHcuQmd3eGRLdUVUS3duc2d4VDsKICAgICAgICBqdXcgVnVFVHhLd25zZ3hUID0gVkNCTmdUb1R3LlZ1RVR4S3duc2d4VDsKICAgICAgICBqdXcgbnRUS3VFVGVUdENUd1RDID0gVkNCTmdUb1R3Lm50VEt1RVRlVHRDVHdUQzsKCiAgICAgICAgZGJneC5WdUVUZW5kdWRnbnQgPSB2OwogICAgICAgIGRiZ3guZ3hmdGdkZ3VsTmdUb1BUZCA9IEJ1bHhUOwoKICAgICAgICBkYmd4LlZDQkhiWXMwdHVnbE5nVG9Udy54VGRTbjdZc1R0ZChWQ0JTbjdZc1R0ZCk7CgogICAgICAgIEJnd3hkS3VFVEt3bnNneFQuZGJUdChCWXQ3ZGdudCAoVkNCS3VFVCkgewogICAgICAgICAgICBDbm90bG51Q1RDS3duc2d4VC5kYlR0KEJZdDdkZ250ICgpIHsKICAgICAgICAgICAgICAgIGp1dyBUalR0ZCA9IENuN1lzVHRkLjd3VHVkVE1qVHRkKCczWXhkbnNNalR0ZCcpOwogICAgICAgICAgICAgICAgVGpUdGQuZ3RnZDNZeGRuc01qVHRkKCdDbjdZc1R0ZGxudUMnLCBkd1lULCBkd1lULCB7fSk7CiAgICAgICAgICAgICAgICBvZ3RDbm8uQ2d4VnVkN2JNalR0ZChUalR0ZCk7CiAgICAgICAgICAgIH0pOwoKICAgICAgICAgICAgeFRsQi5sbnVDZ3RFRnV3LnhUZDhnQ2RiKENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdqZ1RvVHcnKSk7CgogICAgICAgICAgICBnQiAoIUtTNXlQLkNneHUwbFQyZ3hkbndrICYmICF4VGxCLmd4TmdUb1R3TXMwVENDVEMpIHsKICAgICAgICAgICAgICAgIC8vIEhiVCAwd25veGd0RSBiZ3hkbndrIGd4IG50bGsgVHR1MGxUQyBvYlR0IGRiVCBqZ1RvVHcgZ3ggeGR1dEN1bG50VCwKICAgICAgICAgICAgICAgIC8vIGcuVC4gdG5kIG9iVHQgZ2QgZ3ggVHMwVENDVEMgZ3QgdSBvVDAgVnVFVC4KICAgICAgICAgICAgICAgIGdCICgheFRsQi5Wd1RCVHdUdDdUUGJub0t3VGpnbll4TmdUbzl0SW51QykgewogICAgICAgICAgICAgICAgICAgIHhUbEIuVkNCMmd4ZG53ay43bFR1dzJneGRud2tQZHVkVCgpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgeFRsQi5WQ0IyZ3hkbndrLmd0Z2RndWxnR1QoeFRsQi5DbjdZc1R0ZDVndEVUd1Z3Z3RkKTsKCiAgICAgICAgICAgICAgICBnQiAoeFRsQi5WQ0IyZ3hkbndrLmd0Z2RndWxTVHhkZ3R1ZGdudCkgewogICAgICAgICAgICAgICAgICAgIHhUbEIuZ3RnZGd1bFNUeGRndHVkZ250ID0geFRsQi5WQ0IyZ3hkbndrLmd0Z2RndWxTVHhkZ3R1ZGdudDsKICAgICAgICAgICAgICAgIH0gVGx4VCBnQiAoeFRsQi5WQ0IyZ3hkbndrLmd0Z2RndWxGbm5Pc3V3TykgewogICAgICAgICAgICAgICAgICAgIHhUbEIuZ3RnZGd1bEZubk9zdXdPID0geFRsQi5WQ0IyZ3hkbndrLmd0Z2RndWxGbm5Pc3V3TzsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQoKICAgICAgICAgICAgeGRud1QuZ3RnZGd1bGdHVENLd25zZ3hULmRiVHQoQll0N2RnbnQgd1R4bmxqVEMoKSB7CiAgICAgICAgICAgICAgICBqdXcgeGRud1RDMnV4YiA9IHRZbGw7CiAgICAgICAgICAgICAgICBnQiAoeFRsQi5Wd1RCVHdUdDdUUGJub0t3VGpnbll4TmdUbzl0SW51QyAmJgogICAgICAgICAgICAgICAgICAgICAgICB4ZG53VC5FVGQoJ1RyZ3hkeCcsIEJ1bHhUKSkgewogICAgICAgICAgICAgICAgICAgIGp1dyBWdUVUNllzID0geGRud1QuRVRkKCdWdUVUJywgJ3onKTsKICAgICAgICAgICAgICAgICAgICBqdXcgR25ucyA9IHhUbEIuVndUQlR3VHQ3VFNUQnVZbGRYbm5zTnVsWVQgfHwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHhkbndULkVUZCgnR25ucycsIFNNNUFXSUhfUDNBSU1fTkFJV00pOwogICAgICAgICAgICAgICAgICAgIGp1dyBsVEJkID0geGRud1QuRVRkKCd4N3dubGxJVEJkJywgJ3YnKTsKICAgICAgICAgICAgICAgICAgICBqdXcgZG5WID0geGRud1QuRVRkKCd4N3dubGxIblYnLCAndicpOwoKICAgICAgICAgICAgICAgICAgICB4ZG53VEMydXhiID0gJ1Z1RVQ9JyArIFZ1RVQ2WXMgKyAnJkdubnM9JyArIEdubnMgKyAnLCcgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgbFRCZCArICcsJyArIGRuVjsKICAgICAgICAgICAgICAgIH0gVGx4VCBnQiAoeFRsQi5Wd1RCVHdUdDdUU1RCdVlsZFhubnNOdWxZVCkgewogICAgICAgICAgICAgICAgICAgIHhkbndUQzJ1eGIgPSAnVnVFVD16JkdubnM9JyArIHhUbEIuVndUQlR3VHQ3VFNUQnVZbGRYbm5zTnVsWVQ7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB4VGxCLnhUZGZ0Z2RndWxOZ1RvKHhkbndUQzJ1eGIsIHg3dWxUKTsKCiAgICAgICAgICAgICAgICAvLyBxdU9UIHVsbCB0dWpnRXVkZ250IE9Ua3ggb253TyBudCBDbjdZc1R0ZCBsbnVDLAogICAgICAgICAgICAgICAgLy8gWXRsVHh4IGRiVCBqZ1RvVHcgZ3ggVHMwVENDVEMgZ3QgdSBvVDAgVnVFVC4KICAgICAgICAgICAgICAgIGdCICgheFRsQi5neE5nVG9Ud01zMFRDQ1RDKSB7CiAgICAgICAgICAgICAgICAgICAgeFRsQi5WQ0JOZ1RvVHcuQm43WXgoKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwgQll0N2RnbnQgd1QxVDdkVEMod1R1eG50KSB7CiAgICAgICAgICAgICAgICA3bnR4bmxULlR3d253KHdUdXhudCk7CiAgICAgICAgICAgICAgICB4VGxCLnhUZGZ0Z2RndWxOZ1RvKHRZbGwsIHg3dWxUKTsKICAgICAgICAgICAgfSk7CiAgICAgICAgfSk7CgogICAgICAgIFZ1RVR4S3duc2d4VC5kYlR0KEJZdDdkZ250ICgpIHsKICAgICAgICAgICAgZ0IgKHhUbEIueFlWVm53ZHhLd2d0ZGd0RSkgewogICAgICAgICAgICAgICAgVkNCU243WXNUdGQuRVRkeXVqdVA3d2dWZCgpLmRiVHQoQll0N2RnbnQgKDF1anVQN3dnVmQpIHsKICAgICAgICAgICAgICAgICAgICBnQiAoMXVqdVA3d2dWZC5sVHRFZGIpIHsKICAgICAgICAgICAgICAgICAgICAgICAgN250eG5sVC5vdXd0KCc4dXd0Z3RFOiB5dWp1UDd3Z1ZkIGd4IHRuZCB4WVZWbndkVEMnKTsKICAgICAgICAgICAgICAgICAgICAgICAgeFRsQi5CdWxsMHU3TyhLUzV5UC5XNlBXS0s5ZUhNU181TUFIV2VNUC4xdWp1UDd3Z1ZkKTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgLy8gMnU3TyBkbiB4WVZWbndkIHVZZG4gVndndGRndEUuCiAgICAgICAgICAgICAgICAgICAganV3IHdURVRyID0gL1wwVndndGRceCpcKC87CiAgICAgICAgICAgICAgICAgICAgQm53IChqdXcgZyA9IHYsIGdnID0gMXVqdVA3d2dWZC5sVHRFZGI7IGcgPCBnZzsgZysrKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGp1dyAxeCA9IDF1anVQN3dnVmRbZ107CiAgICAgICAgICAgICAgICAgICAgICAgIGdCICgxeCAmJiB3VEVUci5kVHhkKDF4KSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgeFRkSGdzVG5ZZChCWXQ3ZGdudCAoKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2d0Q25vLlZ3Z3RkKCk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdUZFl3dDsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICB9CiAgICAgICAgfSk7CgogICAgICAgIC8vIG5ZZGxndFQgQ1RWVHRDeCBudCBWdUVUeGVUQnF1VgogICAgICAgIGp1dyBWd25zZ3hUeCA9IFtWdUVUeEt3bnNneFQsIGRiZ3gudXRnc3VkZ250UGR1d2RUQ0t3bnNneFRdOwogICAgICAgIEt3bnNneFQudWxsKFZ3bnNneFR4KS5kYlR0KEJZdDdkZ250ICgpIHsKICAgICAgICAgICAgVkNCU243WXNUdGQuRVRkOVlkbGd0VCgpLmRiVHQoQll0N2RnbnQgKG5ZZGxndFQpIHsKICAgICAgICAgICAgICAgIGp1dyA3bnRkdWd0VHcgPSBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnbllkbGd0VE5nVG8nKTsKICAgICAgICAgICAgICAgIHhUbEIubllkbGd0VCA9IHRUbyBLUzU5WWRsZ3RUTmdUbyh7CiAgICAgICAgICAgICAgICAgICAgN250ZHVndFR3OiA3bnRkdWd0VHcsCiAgICAgICAgICAgICAgICAgICAgbllkbGd0VDogbllkbGd0VCwKICAgICAgICAgICAgICAgICAgICBsZ3RPUFR3amc3VDogeFRsQi5WQ0JJZ3RPUFR3amc3VAogICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICB4VGxCLm5ZZGxndFQud1R0Q1R3KCk7CiAgICAgICAgICAgICAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnamdUbzlZZGxndFQnKS5DZ3h1MGxUQyA9ICFuWWRsZ3RUOwoKICAgICAgICAgICAgICAgIGdCICghbllkbGd0VCAmJiAhN250ZHVndFR3LjdsdXh4SWd4ZC43bnRkdWd0eCgnYmdDQ1R0JykpIHsKICAgICAgICAgICAgICAgICAgICB4VGxCLnhvZ2Q3YlBnQ1QwdXdOZ1RvKCdkYllzMHgnKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGdCIChuWWRsZ3RUICYmCiAgICAgICAgICAgICAgICAgICAgICAgIHhUbEIuVndUQlR3VHQ3VFBnQ1QwdXdOZ1RvOXRJbnVDID09PSBQZ0NUMHV3TmdUby45V0hJZjZNKSB7CiAgICAgICAgICAgICAgICAgICAgeFRsQi54b2dkN2JQZ0NUMHV3TmdUbygnbllkbGd0VCcsIGR3WVQpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9KTsKICAgICAgICAgICAgVkNCU243WXNUdGQuRVRkQWRkdTdic1R0ZHgoKS5kYlR0KEJZdDdkZ250ICh1ZGR1N2JzVHRkeCkgewogICAgICAgICAgICAgICAganV3IDdudGR1Z3RUdyA9IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCd1ZGR1N2JzVHRkeE5nVG8nKTsKICAgICAgICAgICAgICAgIHhUbEIudWRkdTdic1R0ZHggPSB0VG8gS1M1QWRkdTdic1R0ZE5nVG8oewogICAgICAgICAgICAgICAgICAgIDdudGR1Z3RUdzogN250ZHVndFR3LAogICAgICAgICAgICAgICAgICAgIHVkZHU3YnNUdGR4OiB1ZGR1N2JzVHRkeCwKICAgICAgICAgICAgICAgICAgLy8gIENub3RsbnVDcXV0dUVUdzogdFRvIFNub3RsbnVDcXV0dUVUdygpCiAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIHhUbEIudWRkdTdic1R0ZHgud1R0Q1R3KCk7CiAgICAgICAgICAgICAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnamdUb0FkZHU3YnNUdGR4JykuQ2d4dTBsVEMgPSAhdWRkdTdic1R0ZHg7CgogICAgICAgICAgICAgICAgZ0IgKCF1ZGR1N2JzVHRkeCAmJiAhN250ZHVndFR3LjdsdXh4SWd4ZC43bnRkdWd0eCgnYmdDQ1R0JykpIHsKICAgICAgICAgICAgICAgICAgICB4VGxCLnhvZ2Q3YlBnQ1QwdXdOZ1RvKCdkYllzMHgnKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGdCICh1ZGR1N2JzVHRkeCAmJgogICAgICAgICAgICAgICAgICAgICAgICB4VGxCLlZ3VEJUd1R0N1RQZ0NUMHV3TmdUbzl0SW51QyA9PT0gUGdDVDB1d05nVG8uQUhIQTMycU02SFApIHsKICAgICAgICAgICAgICAgICAgICB4VGxCLnhvZ2Q3YlBnQ1QwdXdOZ1RvKCd1ZGR1N2JzVHRkeCcsIGR3WVQpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9KTsKICAgICAgICB9KTsKCiAgICAgICAgZ0IgKHhUbEIuVndUQlR3VHQ3VFBnQ1QwdXdOZ1RvOXRJbnVDID09PSBQZ0NUMHV3TmdUby5IMldxRlApIHsKICAgICAgICAgICAgS3duc2d4VC51bGwoW0Jnd3hkS3VFVEt3bnNneFQsIG50VEt1RVRlVHRDVHdUQ10pLmRiVHQoQll0N2RnbnQgKCkgewogICAgICAgICAgICAgICAgeFRsQi54b2dkN2JQZ0NUMHV3TmdUbygnZGJZczB4JywgZHdZVCk7CiAgICAgICAgICAgIH0pOwogICAgICAgIH0KCiAgICAgICAgVkNCU243WXNUdGQuRVRkcVRkdUN1ZHUoKS5kYlR0KEJZdDdkZ250IChDdWR1KSB7CiAgICAgICAgICAgIGp1dyBndEJuID0gQ3VkdS5ndEJuLCBzVGR1Q3VkdSA9IEN1ZHUuc1RkdUN1ZHU7CiAgICAgICAgICAgIHhUbEIuQ243WXNUdGRmdEJuID0gZ3RCbjsKICAgICAgICAgICAgeFRsQi5zVGR1Q3VkdSA9IHNUZHVDdWR1OwoKICAgICAgICAgICAgLy8gS3duamdDVHggeG5zVCAwdXhnNyBDVDBZRSBndEJud3N1ZGdudAogICAgICAgICAgICA3bnR4bmxULmxuRSgnS1M1ICcgKyBWQ0JTbjdZc1R0ZC5CZ3RFVHdWd2d0ZCArICcgWycgKwogICAgICAgICAgICAgICAgICAgIGd0Qm4uS1M1NW53c3VkTlR3eGdudCArICcgJyArIChndEJuLkt3bkNZN1R3IHx8ICctJykuZHdncygpICsKICAgICAgICAgICAgICAgICAgICAnIC8gJyArIChndEJuLjN3VHVkbncgfHwgJy0nKS5kd2dzKCkgKyAnXScgKwogICAgICAgICAgICAgICAgICAgICcgKEtTNS4xeDogJyArIChLUzV5UC5qVHd4Z250IHx8ICctJykgKwogICAgICAgICAgICAgICAgICAgICghS1M1eVAuQ2d4dTBsVDhUMHBJID8gJyBbOFQwcEldJyA6ICcnKSArICcpJyk7CgogICAgICAgICAgICBqdXcgVkNCSGdkbFQ7CiAgICAgICAgICAgIGdCIChzVGR1Q3VkdSAmJiBzVGR1Q3VkdS5idXgoJ0M3OmRnZGxUJykpIHsKICAgICAgICAgICAgICAgIGp1dyBkZ2RsVCA9IHNUZHVDdWR1LkVUZCgnQzc6ZGdkbFQnKTsKICAgICAgICAgICAgICAgIC8vIHBibnhkeDd3Z1ZkIHhuc1RkZ3NUeCB3VGRZd3QgJ1d0ZGdkbFRDJywgeFRkeCBkYlQgZGdkbFQgZG4gJ1d0ZGdkbFRDJwogICAgICAgICAgICAgICAgZ0IgKGRnZGxUICE9PSAnV3RkZ2RsVEMnKSB7CiAgICAgICAgICAgICAgICAgICAgVkNCSGdkbFQgPSBkZ2RsVDsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQoKICAgICAgICAgICAgZ0IgKCFWQ0JIZ2RsVCAmJiBndEJuICYmIGd0Qm5bJ0hnZGxUJ10pIHsKICAgICAgICAgICAgICAgIFZDQkhnZGxUID0gZ3RCblsnSGdkbFQnXTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgZ0IgKFZDQkhnZGxUKSB7CiAgICAgICAgICAgICAgICB4VGxCLnhUZEhnZGxUKFZDQkhnZGxUICsgJyAtICcgKyBDbjdZc1R0ZC5kZ2RsVCk7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGdCIChndEJuLmZ4QTd3bjVud3NLd1R4VHRkKSB7CiAgICAgICAgICAgICAgICA3bnR4bmxULm91d3QoJzh1d3RndEU6IEE3d241bndzL0o1QSBneCB0bmQgeFlWVm53ZFRDJyk7CiAgICAgICAgICAgICAgICB4VGxCLkJ1bGwwdTdPKEtTNXlQLlc2UFdLSzllSE1TXzVNQUhXZU1QLkJud3N4KTsKICAgICAgICAgICAgfQoKICAgICAgICB9KTsKICAgIH0sCiAgICB4VGRmdGdkZ3VsTmdUbzogQll0N2RnbnQgVkNCTmdUb1BUZGZ0Z2RndWxOZ1RvKHhkbndUQzJ1eGIsIHg3dWxUKSB7CiAgICAgICAgZGJneC5neGZ0Z2RndWxOZ1RvUFRkID0gZHdZVDsKCiAgICAgICAgLy8gOGJUdCBuVlR0Z3RFIHUgdFRvIEJnbFQsIG9iVHQgbnRUIGd4IHVsd1R1Q2sgbG51Q1RDIGd0IGRiVCBqZ1RvVHcsCiAgICAgICAgLy8gVHR4WXdUIGRidWQgZGJUICdWdUVUNllzMFR3JyBUbFRzVHRkIENneFZsdWt4IGRiVCA3bnd3VDdkIGp1bFlULgogICAgICAgIENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdWdUVUNllzMFR3JykuanVsWVQgPSBkYmd4LlZDQk5nVG9Udy43WXd3VHRkS3VFVDZZczBUdzsKCiAgICAgICAgZ0IgKGRiZ3guZ3RnZGd1bFNUeGRndHVkZ250KSB7CiAgICAgICAgICAgIGRiZ3guVkNCSWd0T1BUd2pnN1QudHVqZ0V1ZFRIbihkYmd4Lmd0Z2RndWxTVHhkZ3R1ZGdudCk7CiAgICAgICAgICAgIGRiZ3guZ3RnZGd1bFNUeGRndHVkZ250ID0gdFlsbDsKICAgICAgICB9IFRseFQgZ0IgKGRiZ3guZ3RnZGd1bEZubk9zdXdPKSB7CiAgICAgICAgICAgIGRiZ3guVkNCSWd0T1BUd2pnN1QueFRkMnV4YihkYmd4Lmd0Z2RndWxGbm5Pc3V3Tyk7CiAgICAgICAgICAgIGRiZ3guVkNCMmd4ZG53ay5WWXhiKHtidXhiOiBkYmd4Lmd0Z2RndWxGbm5Pc3V3T30sIGR3WVQpOwogICAgICAgICAgICBkYmd4Lmd0Z2RndWxGbm5Pc3V3TyA9IHRZbGw7CiAgICAgICAgfSBUbHhUIGdCICh4ZG53VEMydXhiKSB7CiAgICAgICAgICAgIGRiZ3guVkNCSWd0T1BUd2pnN1QueFRkMnV4Yih4ZG53VEMydXhiKTsKICAgICAgICB9IFRseFQgZ0IgKHg3dWxUKSB7CiAgICAgICAgICAgIGRiZ3guVkNCTmdUb1R3LjdZd3dUdGRQN3VsVE51bFlUID0geDd1bFQ7CiAgICAgICAgICAgIGRiZ3guVnVFVCA9IHo7CiAgICAgICAgfQogICAgICAgIC8vbG51QyBDbjdZc1R0ZCB0bmRUeCB0bm8uCiAgICAgICAgS1M1TmdUb1R3QVZWbGc3dWRnbnQubG51Q1NuN1lzVHRkNm5kVHgoKTsgLy9Qd2cgUndneGJ0dXQKICAgICAgICAvL2xudUMgQ243WXNUdGQgdXR0bmR1ZGdudHggdG5vIAogICAgICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250LmxudUNTbjdZc1R0ZEF0dG5kdWRnbnR4KCk7IC8vUHdnIFJ3Z3hidHV0CgogICAgICAgIGdCICghZGJneC5WQ0JOZ1RvVHcuN1l3d1R0ZFA3dWxUTnVsWVQpIHsKICAgICAgICAgICAgLy8gUDd1bFQgb3V4IHRuZCBndGdkZ3VsZ0dUQzogZ3RqdWxnQyAwbm5Pc3V3TyBudyB4N3VsVCBvdXggdG5kIHhWVDdnQmdUQy4KICAgICAgICAgICAgLy8gUFRkZGd0RSBkYlQgQ1RCdVlsZCBudFQuCiAgICAgICAgICAgIGRiZ3guVkNCTmdUb1R3LjdZd3dUdGRQN3VsVE51bFlUID0gU001QVdJSF9QM0FJTV9OQUlXTTsKICAgICAgICB9CiAgICB9LAogICAgN2xUdXRZVjogQll0N2RnbnQgVkNCTmdUbzNsVHV0WVYoKSB7CiAgICAgICAgZGJneC5WQ0JOZ1RvVHcuN2xUdXRZVigpOwogICAgICAgIGRiZ3guVkNCSGJZczB0dWdsTmdUb1R3LjdsVHV0WVYoKTsKICAgICAgICBkYmd4LlZDQlNuN1lzVHRkLjdsVHV0WVYoKTsKICAgIH0sCiAgICBCbnc3VGVUdENUd2d0RTogQll0N2RnbnQgVkNCTmdUbzVudzdUZVR0Q1R3Z3RFKCkgewogICAgICAgIGRiZ3guVkNCZVR0Q1R3Z3RFaFlUWVQuVndndGRndEUgPSBkYmd4LlZ3Z3RkZ3RFOwogICAgICAgIGRiZ3guVkNCZVR0Q1R3Z3RFaFlUWVQuZ3hIYllzMHR1Z2xOZ1RvTXR1MGxUQyA9IGRiZ3gueGdDVDB1dzlWVHQ7CiAgICAgICAgZGJneC5WQ0JlVHRDVHdndEVoWVRZVC53VHRDVHcyZ0ViVHhkS3dnbndnZGsoKTsKICAgIH0sCiAgICB3VEJ3VHhiSGJZczB0dWdsTmdUb1R3OiBCWXQ3ZGdudCBWQ0JOZ1RvZVRCd1R4YkhiWXMwdHVnbE5nVG9UdygpIHsKICAgICAgICBqdXcgVkNCTmdUb1R3ID0gZGJneC5WQ0JOZ1RvVHc7CiAgICAgICAganV3IGRiWXMwdHVnbE5nVG9UdyA9IGRiZ3guVkNCSGJZczB0dWdsTmdUb1R3OwoKICAgICAgICAvLyB4VGQgZGJZczB0dWdsIGdzdUVUeCBuQiB3VHRDVHdUQyBWdUVUeAogICAgICAgIGp1dyBWdUVUeDNuWXRkID0gVkNCTmdUb1R3LlZ1RVR4M25ZdGQ7CiAgICAgICAgQm53IChqdXcgVnVFVGZ0Q1RyID0gdjsgVnVFVGZ0Q1RyIDwgVnVFVHgzbll0ZDsgVnVFVGZ0Q1RyKyspIHsKICAgICAgICAgICAganV3IFZ1RVROZ1RvID0gVkNCTmdUb1R3LkVUZEt1RVROZ1RvKFZ1RVRmdENUcik7CiAgICAgICAgICAgIGdCIChWdUVUTmdUbyAmJiBWdUVUTmdUby53VHRDVHdndEVQZHVkVCA9PT0gZVR0Q1R3Z3RFUGR1ZFR4LjVmNmZQMk1TKSB7CiAgICAgICAgICAgICAgICBqdXcgZGJZczB0dWdsTmdUbyA9IGRiWXMwdHVnbE5nVG9Udy5FVGRIYllzMHR1Z2woVnVFVGZ0Q1RyKTsKICAgICAgICAgICAgICAgIGRiWXMwdHVnbE5nVG8ueFRkZnN1RVQoVnVFVE5nVG8pOwogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICBkYllzMHR1Z2xOZ1RvVHcueDd3bmxsSGJZczB0dWdsZnRkbk5nVG8oZGJneC5WdUVUKTsKICAgIH0sCiAgICAvL0FDQ1RDIDBrIFB3ZyBSd2d4YnR1dAoKICAgIHh1alRBdENJbnVDU243WXNUdGQ2bmRUeDogQll0N2RnbnQgVkNCUHVqVEF0Q0ludUNTbjdZc1R0ZDZuZFR4KCkgewogICAgICAgIGp1dyBkcmQ2bmRUID0gQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoImRyZDZuZFQiKS5qdWxZVDsKICAgICAgICBqdXcgdG5kVDVnVGxDID0gQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoImRyZDZuZFQiKTsKICAgICAgICB0bmRUNWdUbEMuN2x1eHhJZ3hkLndUc25qVCgnVHd3bncnKTsKICAgICAgICBnQiAoJC5kd2dzKGRyZDZuZFQpLmxUdEVkYiA9PSB2KSB7CiAgICAgICAgICAgIHRuZFQ1Z1RsQy43bHV4eElneGQudUNDKCdUd3dudycpOwogICAgICAgICAgICB3VGRZd3Q7CiAgICAgICAgfQogICAgICAgICQudTF1cih7CiAgICAgICAgICAgIGRrVlQ6ICJLOVBIIiwKICAgICAgICAgICAgWXdsOiAkKCIjQndzNm5kVHgiKS51ZGR3KCJ1N2RnbnQiKSwKICAgICAgICAgICAgQ3VkdTogJCgiI0J3czZuZFR4IikueFR3Z3VsZ0dUKCksCiAgICAgICAgICAgIHhZNzdUeHg6IEJZdDdkZ250ICh3VHhWbnR4VCkgewogICAgICAgICAgICAgICAgJCgiI0J3czZuZFR4Iilbdl0ud1R4VGQoKTsKICAgICAgICAgICAgICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250LmxudUNTbjdZc1R0ZDZuZFR4KCk7CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIFR3d253OiBCWXQ3ZGdudCAoMVFKMmUsIFRyN1RWZGdudCkgewogICAgICAgICAgICAgICAgJCgiI3dUeFlsZDZuZFR4IikuYmRzbCgiV3R1MGxUIGRuIGxudUMgdG5kVHgiKTsKICAgICAgICAgICAgfQogICAgICAgIH0pOwoKICAgIH0sCiAgICBDVGxUZFRTbjdZc1R0ZDZuZFQ6IEJZdDdkZ250IFZDQlNUbFRkVDZuZFQodG5kVGZDKSB7CiAgICAgICAganV3IENuN1lzVHRkZ0MgPSBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygiQ243WXNUdGRnQyIpLmp1bFlUOwogICAgICAgICQudTF1cih7CiAgICAgICAgICAgIHV4a3Q3OiBCdWx4VCwKICAgICAgICAgICAgZGtWVDogInBNSCIsCiAgICAgICAgICAgIFl3bDogIkNzeC9DbjdZc1R0ZHRuZFR4LlZiVj9DbjdZc1R0ZGdDPSIgKyBDbjdZc1R0ZGdDICsgIiZ0bmRUZ0M9IiArIHRuZFRmQywKICAgICAgICAgICAgeFk3N1R4eDogQll0N2RnbnQgKHdUeFZudHhUKSB7CiAgICAgICAgICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5sbnVDU243WXNUdGQ2bmRUeCgpOwogICAgICAgICAgICB9LAogICAgICAgICAgICBUd3dudzogQll0N2RnbnQgKDFRSjJlLCBUcjdUVmRnbnQpIHsKICAgICAgICAgICAgICAgICQoIiN3VHhZbGQ2bmRUeCIpLmJkc2woIld0dTBsVCBkbiBsbnVDIHRuZFR4Iik7CiAgICAgICAgICAgIH0KICAgICAgICB9KTsKCiAgICB9LAogICAgbG51Q1NuN1lzVHRkNm5kVHg6IEJZdDdkZ250IFZDQkludUNTbjdZc1R0ZDZuZFR4KCkgewogICAgICAgIGp1dyBDbjdZc1R0ZGdDID0gQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoIkNuN1lzVHRkZ0MiKS5qdWxZVDsKICAgICAgICBqdXcgWXhUd3R1c1QgPSBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygiWXhUd3R1c1QiKS5qdWxZVDsKCiAgICAgICAgJC51MXVyKHsKICAgICAgICAgICAgZGtWVDogInBNSCIsCiAgICAgICAgICAgIFl3bDogIkNzeC9DbjdZc1R0ZHRuZFR4LlZiVj9DbjdZc1R0ZGdDPSIgKyBDbjdZc1R0ZGdDLAogICAgICAgICAgICB4WTc3VHh4OiBCWXQ3ZGdudCAod1R4Vm50eFQpIHsKICAgICAgICAgICAgICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250LkNuN1lzVHRkNm5kVHggPSB5UDk2LlZ1d3hUKHdUeFZudHhUKTsKICAgICAgICAgICAgICAgICQoIiN3VHhZbGQ2bmRUeCIpLlRzVmRrKCk7CiAgICAgICAgICAgICAgICBCbncgKGp1dyBnID0gdjsgZyA8IEtTNU5nVG9Ud0FWVmxnN3VkZ250LkNuN1lzVHRkNm5kVHgubFR0RWRiOyBnKyspIHsKICAgICAgICAgICAgICAgICAgICBqdXcgQ243WXNUdGQ2bmRUID0gS1M1TmdUb1R3QVZWbGc3dWRnbnQuQ243WXNUdGQ2bmRUeFtnXTsKICAgICAgICAgICAgICAgICAgICBqdXcgdG5kVDNudGR1Z3RUdyA9IENuN1lzVHRkLjd3VHVkVE1sVHNUdGQoIkNnaiIpOwogICAgICAgICAgICAgICAgICAgIGdCICgiSyIgPT09IENuN1lzVHRkNm5kVC50bmRUSGtWVCkgewogICAgICAgICAgICAgICAgICAgICAgICB0bmRUM250ZHVndFR3LjdsdXh4SWd4ZC51Q0MoIkNuN1lzVHRkdG5kVCIpOwogICAgICAgICAgICAgICAgICAgIH0gVGx4VCB7CiAgICAgICAgICAgICAgICAgICAgICAgIHRuZFQzbnRkdWd0VHcuN2x1eHhJZ3hkLnVDQygiQ243WXNUdGR0bmRUVndnanVkVCIpOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBqdXcgYmRzbCA9ICIiOwogICAgICAgICAgICAgICAgICAgIGJkc2wgKz0gIjxDZ2ogN2x1eHg9J1l4VHd0dXNUJz4iICsgQ243WXNUdGQ2bmRULll4VHc2dXNUICsgIjwvQ2dqPiI7CiAgICAgICAgICAgICAgICAgICAgZ0IgKFl4VHd0dXNUID09PSBDbjdZc1R0ZDZuZFQuWXhUdzZ1c1QpIHsKICAgICAgICAgICAgICAgICAgICAgICAgYmRzbCArPSAiPENnaiA3bHV4eD0nQ1RsVGRUZzdudCc+PHUgYndUQj0nMXVqdXg3d2dWZDpqbmdDKHYpOycgN2x1eHg9J25qVHdsdWtGWWRkbnQgQ1RsVGRUdG5kVCcgdG5kVGdDPSciICsgQ243WXNUdGQ2bmRULnRuZFRmQyArICInPjxnIDdsdXh4PSdCdSBCdS1kd3V4Yi1uJyB1d2d1LWJnQ0NUdD0nZHdZVCc+PC9nPjwvdT48L0Nnaj4iOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBiZHNsICs9ICI8Q2dqIHhka2xUPSc3bFR1dzowbmRiJz48L0Nnaj48YncvPiI7CiAgICAgICAgICAgICAgICAgICAgYmRzbCArPSAiPENnaiA3bHV4eD0ndG5kVEN1ZHUnPiIgKyBDbjdZc1R0ZDZuZFQudG5kVFN1ZHUgKyAiPC9DZ2o+IjsKICAgICAgICAgICAgICAgICAgICBiZHNsICs9ICI8ViA3bHV4eD0ndG5kVEN1ZFQnPiAtICIgKyBDbjdZc1R0ZDZuZFQuQndnVHRDbGtTdWRUICsgIjwvVj4iOwogICAgICAgICAgICAgICAgICAgICQodG5kVDNudGR1Z3RUdykuYmRzbChiZHNsKTsKICAgICAgICAgICAgICAgICAgICAkKCIjd1R4WWxkNm5kVHgiKS51VlZUdEModG5kVDNudGR1Z3RUdyk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIFR3d253OiBCWXQ3ZGdudCAoMVFKMmUsIFRyN1RWZGdudCkgewogICAgICAgICAgICAgICAgJCgiI3dUeFlsZDZuZFR4IikuYmRzbCgiV3R1MGxUIGRuIGxudUMgdG5kVHgiKTsKICAgICAgICAgICAgfQogICAgICAgIH0pOwogICAgfSwKICAgIGxudUNTbjdZc1R0ZEF0dG5kdWRnbnR4OiBCWXQ3ZGdudCBWQ0JJbnVDU243WXNUdGRBdHRuZHVkZ250eCgpIHsKICAgICAgICBqdXcgQ243WXNUdGRnQyA9IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCJDbjdZc1R0ZGdDIikuanVsWVQ7CiAgICAgICAganV3IHdUamd4Z250Z0MgPSBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygid1RqZ3hnbnRnQyIpLmp1bFlUOwogICAgICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250LkNuN1lzVHRkQXR0bmR1ZGdudHggPSB0VG8gQXd3dWsoKTsKICAgICAgICBqdXcgdXR0bmR1ZGdudFd3bCA9ICJDc3gvQ243WXNUdGR1dHRuZHVkZ250eC5WYlY/Q243WXNUdGRnQz0iICsgQ243WXNUdGRnQyArICImd1RqZ3hnbnRnQz0iICsgd1RqZ3hnbnRnQzsKICAgICAgICBnQiAoeGJ1d1RDU243WXNUdGRmUykgewogICAgICAgICAgICB1dHRuZHVkZ250V3dsID0gIi94YnV3VENDbjdZc1R0ZD9xOVNNPUE2NiZmUz0iICsgeGJ1d1RDU243WXNUdGRmUzsKICAgICAgICB9CgogICAgICAgICQudTF1cih7CiAgICAgICAgICAgIHV4a3Q3OiBCdWx4VCwKICAgICAgICAgICAgZGtWVDogInBNSCIsCiAgICAgICAgICAgIFl3bDogdXR0bmR1ZGdudFd3bCwKICAgICAgICAgICAgeFk3N1R4eDogQll0N2RnbnQgKHdUeFZudHhUKSB7CiAgICAgICAgICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5DbjdZc1R0ZEF0dG5kdWRnbnR4ID0geVA5Ni5WdXd4VCh3VHhWbnR4VCk7CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIFR3d253OiBCWXQ3ZGdudCAoMVFKMmUsIFRyN1RWZGdudCkgewogICAgICAgICAgICAgICAgS1M1TmdUb1R3QVZWbGc3dWRnbnQuQ243WXNUdGRBdHRuZHVkZ250eCA9IHRUbyBBd3d1aygpOwogICAgICAgICAgICB9CiAgICAgICAgfSk7CiAgICAgICAgQm53IChqdXcgZyA9IHY7IGcgPCBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5DbjdZc1R0ZEF0dG5kdWRnbnR4LmxUdEVkYjsgZysrKSB7CiAgICAgICAgICAgIGp1dyB1dHRuZHVkZ250ID0gS1M1TmdUb1R3QVZWbGc3dWRnbnQuQ243WXNUdGRBdHRuZHVkZ250eFtnXTsKICAgICAgICAgICAgdXR0bmR1ZGdudC5kVHNWZkMgPSB1dHRuZHVkZ250LnV0dG5kdWRnbnRmQzsKICAgICAgICB9CiAgICB9LAogICAgeHVqVEF0Q0ludUNTbjdZc1R0ZEF0dG5kdWRnbnR4OiBCWXQ3ZGdudCBWQ0JQdWpUQXRDSW51Q1NuN1lzVHRkQXR0bmR1ZGdudHgoKSB7CiAgICAgICAganV3IENuN1lzVHRkZ0MgPSBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygiQ243WXNUdGRnQyIpLmp1bFlUOwogICAgICAgIGp1dyB3VGpneGdudGdDID0gQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoIndUamd4Z250Z0MiKS5qdWxZVDsKICAgICAgICBqdXcgQmd0dWxBdHRuZHVkZ250eCA9IHRUbyBBd3d1aygpOwogICAgICAgIEJudyAoanV3IGcgPSB2OyBnIDwgS1M1TmdUb1R3QVZWbGc3dWRnbnQuQ243WXNUdGRBdHRuZHVkZ250eC5sVHRFZGI7IGcrKykgewogICAgICAgICAgICBqdXcgdXR0bmR1ZGdudCA9IEtTNU5nVG9Ud0FWVmxnN3VkZ250LkNuN1lzVHRkQXR0bmR1ZGdudHhbZ107CiAgICAgICAgICAgIGdCICh1dHRuZHVkZ250LnV0dG5kdWRnbnRmQyA9PSAteikgeyAvL3RUb2xrIDd3VHVkVEMgdXR0bmR1ZGdudCB4biA3YlQ3TyBnQiBnZCBneCBDVGxUZFRDIG53IHRuZAogICAgICAgICAgICAgICAgZ0IgKHV0dG5kdWRnbnQuQ1RsVGRUQykgewogICAgICAgICAgICAgICAgICAgIDdudGRndFlUOyAvL0NudGQgdUNDIGRiZ3ggZG4gQmd0dWwgdXR0bmR1ZGdudHggZG4gMFQgVm54ZFRDIGRuIEN1ZHUwdXhULgogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIGdCICh1dHRuZHVkZ250LkNUbFRkVEMpIHsKICAgICAgICAgICAgICAgIHV0dG5kdWRnbnQudTdkZ250ID0gWjsgLy9ndENnN3VkVHggZGJ1ZCBUcmd4ZGd0RSB1dHRuZHVkZ250IGd4IENUbFRkVEMgCiAgICAgICAgICAgIH0KICAgICAgICAgICAgZ0IgKHV0dG5kdWRnbnQuQ2d3ZGspIHsKICAgICAgICAgICAgICAgIEJndHVsQXR0bmR1ZGdudHguVll4Yih1dHRuZHVkZ250KTsKICAgICAgICAgICAgfQoKICAgICAgICB9CiAgICAgICAganV3IHV0dG5kdWRnbnR4ID0geVA5Ni54ZHdndEVnQmsoQmd0dWxBdHRuZHVkZ250eCk7CiAgICAgICAgJC51MXVyKHsKICAgICAgICAgICAgdXhrdDc6IEJ1bHhULAogICAgICAgICAgICBka1ZUOiAicE1IIiwKICAgICAgICAgICAgWXdsOiAiQ3N4L0NuN1lzVHRkdXR0bmR1ZGdudHguVmJWP0NuN1lzVHRkZ0M9IiArIENuN1lzVHRkZ0MgKyAiJndUamd4Z250Z0M9IiArIHdUamd4Z250Z0MgKyAiJnV0dG5kdWRnbnR4PSIgKyB1dHRuZHVkZ250eCwKICAgICAgICAgICAgeFk3N1R4eDogQll0N2RnbnQgKHdUeFZudHhUKSB7CiAgICAgICAgICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5DbjdZc1R0ZEF0dG5kdWRnbnR4ID0geVA5Ni5WdXd4VCh3VHhWbnR4VCk7CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIFR3d253OiBCWXQ3ZGdudCAoMVFKMmUsIFRyN1RWZGdudCkgewogICAgICAgICAgICAgICAgS1M1TmdUb1R3QVZWbGc3dWRnbnQuQ243WXNUdGRBdHRuZHVkZ250eCA9IHRUbyBBd3d1aygpOwogICAgICAgICAgICB9CiAgICAgICAgfSk7CiAgICAgICAgQm53IChqdXcgZyA9IHY7IGcgPCBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5DbjdZc1R0ZEF0dG5kdWRnbnR4LmxUdEVkYjsgZysrKSB7CiAgICAgICAgICAgIGp1dyB1dHRuZHVkZ250ID0gS1M1TmdUb1R3QVZWbGc3dWRnbnQuQ243WXNUdGRBdHRuZHVkZ250eFtnXTsKICAgICAgICAgICAgdXR0bmR1ZGdudC5kVHNWZkMgPSB1dHRuZHVkZ250LnV0dG5kdWRnbnRmQzsKICAgICAgICB9CiAgICAgICAgLy91bFR3ZCh1dHRuZHVkZ250LmRUc1ZmQyk7CiAgICB9LAogICAgN3dUdWRUU243WXNUdGRBdHRuZHVkZ250OiBCWXQ3ZGdudCBWQ0Izd1R1ZFQ2VG9BdHRuZHVkZ250KHV0dG5kdWRnbnRIa1ZUKSB7CiAgICAgICAgZ0IgKEtTNU5nVG9Ud0FWVmxnN3VkZ250LlZDQk5nVG9Udy5fVnVFVHhlbmR1ZGdudCA9PSB2KSB7CiAgICAgICAgICAgIEN3dW9BdHRuZHVkZ250ID0gZHdZVDsKICAgICAgICAgICAgdFRvQXR0bmR1ZGdudCA9IHRUbyBTbjdZc1R0ZEF0dG5kdWRnbnQoe30pOwogICAgICAgICAgICB0VG9BdHRuZHVkZ250LnV0dG5kdWRnbnRmQyA9ICIteiI7CiAgICAgICAgICAgIHRUb0F0dG5kdWRnbnQuZFRzVmZDID0gdFRvIFN1ZFQoKS5FVGRIZ3NUKCk7CgogICAgICAgICAgICB0VG9BdHRuZHVkZ250Lm5WdTdnZGsgPSB6OwogICAgICAgICAgICB0VG9BdHRuZHVkZ250LkNnd2RrID0gZHdZVDsKICAgICAgICAgICAgdFRvQXR0bmR1ZGdudC51dHRuZHVkZ250SGtWVCA9IHV0dG5kdWRnbnRIa1ZUOwogICAgICAgICAgICBnQiAodXR0bmR1ZGdudEhrVlQgPT0gQTY2OUhBSGY5Nl8yZnAySWZwMkgpIHsKICAgICAgICAgICAgICAgIHRUb0F0dG5kdWRnbnQuN25sbndlVEMgPSBaY2M7CiAgICAgICAgICAgICAgICB0VG9BdHRuZHVkZ250LjdubG53cHdUVHQgPSBaY2M7CiAgICAgICAgICAgICAgICB0VG9BdHRuZHVkZ250LjdubG53RmxZVCA9IHpaVTsKICAgICAgICAgICAgfSBUbHhUIGdCICh1dHRuZHVkZ250SGtWVCA9PSBBNjY5SEFIZjk2X0ZJQTNSOVdIKSB7CiAgICAgICAgICAgICAgICB0VG9BdHRuZHVkZ250LjdubG53ZVRDID0gWmNjOwogICAgICAgICAgICAgICAgdFRvQXR0bmR1ZGdudC43bmxud3B3VFR0ID0gWmNjOwogICAgICAgICAgICAgICAgdFRvQXR0bmR1ZGdudC43bmxud0ZsWVQgPSBaY2M7CiAgICAgICAgICAgIH0gVGx4VCBnQiAodXR0bmR1ZGdudEhrVlQgPT0gQTY2OUhBSGY5Nl9NSUlmS1BNKSB7CiAgICAgICAgICAgICAgICB0VG9BdHRuZHVkZ250LjdubG53ZVRDID0gWmNjOwogICAgICAgICAgICAgICAgdFRvQXR0bmR1ZGdudC43bmxud3B3VFR0ID0gdjsKICAgICAgICAgICAgICAgIHRUb0F0dG5kdWRnbnQuN25sbndGbFlUID0gdjsKICAgICAgICAgICAgfSBUbHhUIGdCICh1dHRuZHVkZ250SGtWVCA9PSBBNjY5SEFIZjk2X1BIZjNSNDY5SE0pIHsKICAgICAgICAgICAgICAgIHRUb0F0dG5kdWRnbnQuN25sbndlVEMgPSBaY2M7CiAgICAgICAgICAgICAgICB0VG9BdHRuZHVkZ250LjdubG53cHdUVHQgPSBaY2M7CiAgICAgICAgICAgICAgICB0VG9BdHRuZHVkZ250LjdubG53RmxZVCA9IHpaVTsKICAgICAgICAgICAgICAgIHRUb0F0dG5kdWRnbnQuZFRyZCA9ICIiOwogICAgICAgICAgICB9IFRseFQgewogICAgICAgICAgICAgICAgdFRvQXR0bmR1ZGdudC43bmxud2VUQyA9IFpjYzsKICAgICAgICAgICAgICAgIHRUb0F0dG5kdWRnbnQuN25sbndwd1RUdCA9IHY7CiAgICAgICAgICAgICAgICB0VG9BdHRuZHVkZ250LjdubG53RmxZVCA9IHY7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9LAogICAgQ3d1b1NuN1lzVHRkQXR0bmR1ZGdudHg6IEJZdDdkZ250IFZDQlN3dW9TbjdZc1R0ZEF0dG5kdWRnbnR4KFZ1RVROZ1RvLCB1dHQzZHIsIFZ1RVQ2WXMwVHcpIHsKICAgICAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygiamdUb1R3IikuN2x1eHhJZ3hkLnVDQygiYmdDQ1R0Iik7CiAgICAgICAgdXR0M2RyLjdsVHV3ZVQ3ZCh2LCB2LCBWdUVUTmdUby5vZ0NkYiAqIG9ndENuby5DVGpnN1RLZ3JUbGV1ZGduLCBWdUVUTmdUby5iVGdFYmQgKiBvZ3RDbm8uQ1RqZzdUS2dyVGxldWRnbik7CiAgICAgICAgZ0IgKFZ1RVROZ1RvLnduZHVkZ250ID09IEx2KSB7CiAgICAgICAgICAgIHV0dDNkci5kd3V0eGx1ZFQoVnVFVE5nVG8ub2dDZGIsIHYpOwogICAgICAgIH0gVGx4VCBnQiAoVnVFVE5nVG8ud25kdWRnbnQgPT0gelV2KSB7CiAgICAgICAgICAgIHV0dDNkci5kd3V0eGx1ZFQoVnVFVE5nVG8ub2dDZGIsIFZ1RVROZ1RvLmJUZ0ViZCk7CiAgICAgICAgfSBUbHhUIGdCIChWdUVUTmdUby53bmR1ZGdudCA9PSBaYXYpIHsKICAgICAgICAgICAgdXR0M2RyLmR3dXR4bHVkVCh2LCBWdUVUTmdUby5iVGdFYmQpOwogICAgICAgIH0gVGx4VCB7CiAgICAgICAgICAgIHV0dDNkci5kd3V0eGx1ZFQodiwgdik7CiAgICAgICAgfQogICAgICAgIHV0dDNkci53bmR1ZFQoVnVFVE5nVG8ud25kdWRnbnQgKiBxdWRiLktmIC8gelV2KTsKICAgICAgICBCbncgKGp1dyBnID0gdjsgZyA8IEtTNU5nVG9Ud0FWVmxnN3VkZ250LkNuN1lzVHRkQXR0bmR1ZGdudHgubFR0RWRiOyBnKyspIHsKICAgICAgICAgICAganV3IHV0dCA9IEtTNU5nVG9Ud0FWVmxnN3VkZ250LkNuN1lzVHRkQXR0bmR1ZGdudHhbZ107CiAgICAgICAgICAgIGp1dyBDbjdZc1R0ZEF0dG5kdWRnbnQgPSB0VG8gU243WXNUdGRBdHRuZHVkZ250KHV0dCk7CiAgICAgICAgICAgIGdCIChWdUVUNllzMFR3ID09IENuN1lzVHRkQXR0bmR1ZGdudC5WdUVUZkMpIHsKICAgICAgICAgICAgICAgIGdCICghQ243WXNUdGRBdHRuZHVkZ250LkNUbFRkVEMpIHsKICAgICAgICAgICAgICAgICAgICBDbjdZc1R0ZEF0dG5kdWRnbnQuQ3d1byh1dHQzZHIsIFZ1RVROZ1RvLng3dWxUKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICAkKCIjdXR0bmR1ZGdudHhOZ1RvIikuVHNWZGsoKTsKICAgICAgICBqdXcgdXR0bmR1ZGdudHgzbll0ZCA9IHY7CiAgICAgICAgQm53IChqdXcgZyA9IHY7IGcgPCBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5DbjdZc1R0ZEF0dG5kdWRnbnR4LmxUdEVkYjsgZysrKSB7CiAgICAgICAgICAgIGp1dyBDbjdZc1R0ZEF0dG5kdWRnbnQgPSBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5DbjdZc1R0ZEF0dG5kdWRnbnR4W2ddOwogICAgICAgICAgICBqdXcgdXR0M250ZHVndFR3ID0gQ243WXNUdGQuN3dUdWRUTWxUc1R0ZCgiQ2dqIik7CiAgICAgICAgICAgIGdCICghQ243WXNUdGRBdHRuZHVkZ250LkNUbFRkVEMpIHsKICAgICAgICAgICAgICAgIGp1dyBiZHNsID0gIiI7CiAgICAgICAgICAgICAgICBiZHNsICs9ICI8dSBid1RCPScxdWp1eDd3Z1ZkOmpuZ0Modik7JyBkVHNWdXR0bmR1ZGdudGdDPSciICsgQ243WXNUdGRBdHRuZHVkZ250LmRUc1ZmQyArICInIDdsdXh4PSd1dHR4VGxUN2Rudyc+IjsKICAgICAgICAgICAgICAgIGJkc2wgKz0gIjxDZ2ogIDdsdXh4PSdDbjdZc1R0ZHV0dG5kdWRnbnQnPiI7CiAgICAgICAgICAgICAgICBiZHNsICs9ICI8Q2dqIDdsdXh4PSdZeFR3dHVzVCc+IiArIENuN1lzVHRkQXR0bmR1ZGdudC5ZeFR3NnVzVCArICI8L0Nnaj4iOwogICAgICAgICAgICAgICAgZ0IgKENuN1lzVHRkQXR0bmR1ZGdudC51dHRuZHVkZ250SGtWVCA9PT0gQTY2OUhBSGY5Nl8yZnAySWZwMkgpIHsKICAgICAgICAgICAgICAgICAgICBiZHNsICs9ICI8Q2dqIDdsdXh4PSd1dHRuZHVkZ250IHV0dG5kdWRnbnQtYmdFYmxnRWJkJz48L0Nnaj4iOwogICAgICAgICAgICAgICAgfSBUbHhUIGdCIChDbjdZc1R0ZEF0dG5kdWRnbnQudXR0bmR1ZGdudEhrVlQgPT09IEE2NjlIQUhmOTZfRklBM1I5V0gpIHsKICAgICAgICAgICAgICAgICAgICBiZHNsICs9ICI8Q2dqIDdsdXh4PSd1dHRuZHVkZ250IHV0dG5kdWRnbnQtMGx1N09uWWQnPjwvQ2dqPiI7CiAgICAgICAgICAgICAgICB9IFRseFQgZ0IgKENuN1lzVHRkQXR0bmR1ZGdudC51dHRuZHVkZ250SGtWVCA9PT0gQTY2OUhBSGY5Nl9NSUlmS1BNKSB7CiAgICAgICAgICAgICAgICAgICAgYmRzbCArPSAiPENnaiA3bHV4eD0ndXR0bmR1ZGdudCB1dHRuZHVkZ250LVRsbGdWeFQnPjwvQ2dqPiI7CiAgICAgICAgICAgICAgICB9IFRseFQgZ0IgKENuN1lzVHRkQXR0bmR1ZGdudC51dHRuZHVkZ250SGtWVCA9PT0gQTY2OUhBSGY5Nl9QSGYzUjQ2OUhNKSB7CiAgICAgICAgICAgICAgICAgICAgYmRzbCArPSAiPENnaiA3bHV4eD0ndXR0bmR1ZGdudCB1dHRuZHVkZ250LXRuZFQnPjwvQ2dqPiI7CiAgICAgICAgICAgICAgICB9IFRseFQgZ0IgKENuN1lzVHRkQXR0bmR1ZGdudC51dHRuZHVkZ250SGtWVCA9PT0gQTY2OUhBSGY5Nl9QZnA2KSB7CiAgICAgICAgICAgICAgICAgICAgYmRzbCArPSAiPENnaiA3bHV4eD0ndXR0bmR1ZGdudCB1dHRuZHVkZ250LXhnRXQnPjwvQ2dqPiI7CiAgICAgICAgICAgICAgICB9IFRseFQgewogICAgICAgICAgICAgICAgICAgIGJkc2wgKz0gIjxDZ2ogN2x1eHg9J3V0dG5kdWRnbnQgdXR0bmR1ZGdudC13WTAwVHd4ZHVzVic+PC9DZ2o+IjsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGJkc2wgKz0gIjwvQ2dqPiI7CiAgICAgICAgICAgICAgICBiZHNsICs9ICI8L3U+IjsKICAgICAgICAgICAgICAgICQodXR0M250ZHVndFR3KS5iZHNsKGJkc2wpOwogICAgICAgICAgICAgICAgJCgiI3V0dG5kdWRnbnR4TmdUbyIpLnVWVlR0Qyh1dHQzbnRkdWd0VHcpOwogICAgICAgICAgICAgICAgdXR0bmR1ZGdudHgzbll0ZCsrOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGdCICh1dHRuZHVkZ250eDNuWXRkIDw9IHYpIHsKICAgICAgICAgICAganV3IHV0dDNudGR1Z3RUdyA9IENuN1lzVHRkLjd3VHVkVE1sVHNUdGQoIkNnaiIpOwogICAgICAgICAgICBqdXcgYmRzbCA9ICI8Q2dqICA3bHV4eD0nQ243WXNUdGR1dHRuZHVkZ250Jz42biB1dHRuZHVkZ250eCBCbll0QzwvQ2dqPiI7CiAgICAgICAgICAgICQodXR0M250ZHVndFR3KS5iZHNsKGJkc2wpOwogICAgICAgICAgICAkKCIjdXR0bmR1ZGdudHhOZ1RvIikudVZWVHRDKHV0dDNudGR1Z3RUdyk7CiAgICAgICAgfQogICAgICAgIENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCJqZ1RvVHciKS43bHV4eElneGQud1RzbmpUKCJiZ0NDVHQiKTsKICAgIH0sCiAgICBDVGxUZFRTbjdZc1R0ZEF0dG5kdWRnbnQ6IEJZdDdkZ250IFZDQlNUbFRkVFNuN1lzVHRkQXR0bmR1ZGdudCgpIHsKICAgICAgICBqdXcgeGR3X3dnRWJkeCA9Ijw/VmJWIFQ3Ym4gJHdnRWJkX3hkdzsgPz4iOwogICAgICAgIGp1dyB3VHhfd2dFYmR4ID0geGR3X3dnRWJkeC54VmxnZCgiLCIpOwogICAgICAgIC8vIHVsVHdkKHhkd193Z0ViZHgpOwogICAgICAgICAKICAgICAgICAvLyA3bnR4bmxULmxuRSh3VHhfd2dFYmR4KTsKICAgICAgICBCbncgKGp1dyBnID0gdjsgZyA8IEtTNU5nVG9Ud0FWVmxnN3VkZ250LkNuN1lzVHRkQXR0bmR1ZGdudHgubFR0RWRiOyBnKyspIHsKICAgICAgICAgICAganV3IHV0dCA9IEtTNU5nVG9Ud0FWVmxnN3VkZ250LkNuN1lzVHRkQXR0bmR1ZGdudHhbZ107CiAgICAgICAgICAvLyB1bFR3ZCgxaFlUd2suZ3RBd3d1aygiTHZ2dloiLCB3VHhfd2dFYmR4ICkpOwogICAgICAgICAgIGp1dyB1dHRfeGR3ID0gdXR0LnV0dG5kdWRnbnRIa1ZUOwogICAgICAgICAgLy8gdWxUd2QoIHhkd193Z0ViZHgueFR1dzdiKHV0dF94ZHcpKTsKICAgICAgICAgICAgZ0IoeGR3X3dnRWJkeC54VHV3N2IodXR0X3hkdyk9PS16KXsKICAgICAgICAgICAgIGdCICh1dHQueFRsVDdkVEMpIHsKICAgICAgICAgICAgICAgIC8vZ0IoICh1dHQuWXhUdzZ1c1QgPT09ICBZeFR3NnVzVCB8fCBZeFR3NnVzVCA9PT0gJ0FTcWY2ZlBIZUFIOWUnICkgJiYgN3V0TUNnZCApeyAKICAgICAgICAgICAgICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250LkNUbFRkVEF0dG5kdWRnbnQzbnRCZ3dzdWRnbnRLd25zVmQublZUdCh1dHQpOwogICAgICAgICAgICAgICAgMHdUdU87CiAgICAgICAgICAgICAgICAvL30KICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICB9CiAgICB9LAogICAgeFRsVDdkU243WXNUdGRBdHRuZHVkZ250OiBCWXQ3ZGdudCBWQ0JQVGxUN2RTbjdZc1R0ZEF0dG5kdWRnbnQoVGopIHsKICAgIGp1dyB4ZHdfd2dFYmR4ID0iPD9WYlYgVDdibiAkd2dFYmRfeGR3OyA/PiI7CiAgICAgICAgCiAgICAgICAganV3IHg3dWxUID0gS1M1TmdUb1R3QVZWbGc3dWRnbnQuVkNCTmdUb1R3LjdZd3dUdGRQN3VsVDsKICAgICAgICBqdXcgN2RyID0gVGouZHV3RVRkLkVUZDNudGRUcmQoJ1pDJyk7CiAgICAgICAgZ3hTd3VFID0gQnVseFQ7CiAgICAgICAgN2RyLjdsVHV3ZVQ3ZCh2LCB2LCBUai5kdXdFVGQub2dDZGIsIFRqLmR1d0VUZC5iVGdFYmQpOwogICAgICAgIEJudyAoanV3IGcgPSB2OyBnIDwgS1M1TmdUb1R3QVZWbGc3dWRnbnQuQ243WXNUdGRBdHRuZHVkZ250eC5sVHRFZGI7IGcrKykgewogICAgICAgICAgICBqdXcgdXR0ID0gS1M1TmdUb1R3QVZWbGc3dWRnbnQuQ243WXNUdGRBdHRuZHVkZ250eFtnXTsKICAgICAgICAgICAgLy83bnR4bmxULmxuRSh1dHQpOwogICAgICAgICAgICBqdXcgdXR0X3hkdyA9IHV0dC51dHRuZHVkZ250SGtWVDsKICAgICAgICAgICAganV3IHV0dF9ZeFR3X2dDID0gdXR0Lll4VHdfZ0M7CiAgICAgICAgICAgIC8vdWxUd2QodXR0X1l4VHdfZ0MpOwogICAgICAgICAgICBneFN3dUUgPSBCdWx4VDsKICAgICAgICAgICAganV3IGRUc1YgPSB2OwogICAgICAgICAgICBnQiAodXR0LnJaIDwgdXR0LnJ6KSB7CiAgICAgICAgICAgICAgICBkVHNWID0gdXR0LnJaOwogICAgICAgICAgICAgICAgdXR0LnJaID0gdXR0LnJ6OwogICAgICAgICAgICAgICAgdXR0LnJ6ID0gZFRzVjsKICAgICAgICAgICAgfQogICAgICAgICAgICBnQiAodXR0LmtaIDwgdXR0Lmt6KSB7CiAgICAgICAgICAgICAgICBkVHNWID0gdXR0LmtaOwogICAgICAgICAgICAgICAgdXR0LmtaID0gdXR0Lmt6OwogICAgICAgICAgICAgICAgdXR0Lmt6ID0gZFRzVjsKICAgICAgICAgICAgfQogICAgICAgICAgICBnQiAodXR0LlZ1RVRmQyA9PSBUai5kdXdFVGQuVnVFVDZZczBUdykgewogICAgICAgICAgICAgICAgZ0IgKHNuWXhUSiA+PSB1dHQucnogKiB4N3VsVCAmJiBzbll4VEogPD0gdXR0LnJaICogeDd1bFQgJiYgc25ZeFQ0ID49IHV0dC5reiAqIHg3dWxUICYmIHNuWXhUNCA8PSB1dHQua1ogKiB4N3VsVCkgewogICAgICAgICAgICAgICAgICAgIGdCICghdXR0LkNUbFRkVEMpIHsKICAgICAgICAgICAgICAgICAgICAgICAgLy9nQiggKHV0dC5ZeFR3NnVzVCA9PT0gIFl4VHc2dXNUIHx8IFl4VHc2dXNUID09PSAnQVNxZjZmUEhlQUg5ZScgKSAmJiA3dXRNQ2dkICl7IC8vM2JUN08gZ0IgZGJUIFl4VHcgZ3ggN3dUdWRudyBuQiB1dHRuZHVkZ250CiAgICAgICAgICAgICAgICAgICAgICAgIHV0dC54VGxUN2RUQyA9IGR3WVQ7CiAgICAgICAgICAgICAgICAgICAgICAgIHV0dDhnQ2RiID0gKHV0dC5yWiAtIHV0dC5yeik7CiAgICAgICAgICAgICAgICAgICAgICAgIHV0dDJUZ0ViZCA9ICh1dHQua1ogLSB1dHQua3opOwogICAgICAgICAgICAgICAgICAgICAgICB4VGxUN2RUQ0F0dG5kdWRnbnQgPSB1dHQ7CgogICAgICAgICAgICAgICAgICAgICAgICBuQkJ4VGRyID0gVnV3eFRmdGQoc25ZeFRKIC0gKHV0dC5yeiAqIHg3dWxUKSk7CiAgICAgICAgICAgICAgICAgICAgICAgIG5CQnhUZGsgPSBWdXd4VGZ0ZChzbll4VDQgLSAodXR0Lmt6ICogeDd1bFQpKTsKICAgICAgICAgICAgICAgICAgICBnQih4ZHdfd2dFYmR4LnhUdXc3Yih1dHRfeGR3KT09LXopewogICAgICAgICAgICAgICAgICAgICAgICBneFN3dUUgPSBkd1lUOwogICAgICAgICAgICAgICAgICAgICAgICBnQih1dHRfeGR3PT1BNjY5SEFIZjk2X1BmcDYpewogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy91bFR3ZCh1dHRfWXhUd19nQyk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBnQih1dHRfWXhUd19nQyA9PSBfWXhUd19nQyB8fCB1dHRfWXhUd19nQyA9PVl0Q1RCZ3RUQykKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBneFN3dUUgPSBkd1lUOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgfVRseFQgZ0IoIF9ZeFR3X3dubFQgPT0geiB8fCBfWXhUd193bmxUID09IFopewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGd4U3d1RSA9IGR3WVQ7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9VGx4VHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBneFN3dUUgPSBCdWx4VDsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIH1UbHhUewogICAgICAgICAgICAgICAgICAgICAgICAgZ3hTd3VFID0gQnVseFQ7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAwd1R1TzsKICAgICAgICAgICAgICAgICAgICAgICAgLy99CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGdCICghZ3hTd3VFKSB7IC8vdG4gdXR0bmR1ZGdudCB1d1QgeFRsVDdkVEMgeG4gc3VPVCB1bGwgdXR0bmR1ZGdudHggdXggWXQgeFRsVDdkVEMKICAgICAgICAgICAgeFRsVDdkVENBdHRuZHVkZ250ID0gdFlsbDsKICAgICAgICAgICAgN2RyLjdsVHV3ZVQ3ZCh2LCB2LCBUai5kdXdFVGQub2dDZGIsIFRqLmR1d0VUZC5iVGdFYmQpOwogICAgICAgICAgICBCbncgKGp1dyBnID0gdjsgZyA8IEtTNU5nVG9Ud0FWVmxnN3VkZ250LkNuN1lzVHRkQXR0bmR1ZGdudHgubFR0RWRiOyBnKyspIHsKICAgICAgICAgICAgICAgIGp1dyB1dHQgPSBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5DbjdZc1R0ZEF0dG5kdWRnbnR4W2ddOwogICAgICAgICAgICAgICAgdXR0LnhUbFQ3ZFRDID0gQnVseFQ7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9LAogICAgN2J1dEVUU243WXNUdGRBdHRuZHVkZ250M25sbnc6IEJZdDdkZ250IFZDQjNidXRFVFNuN1lzVHRkQXR0bmR1ZGdudDNubG53KDdubG53S2c3T1R3KSB7CiAgICAgICAgN25sbndlVEMgPSBxdWRiLnduWXRDKDdubG53S2c3T1R3LndFMFt2XSk7CiAgICAgICAgN25sbndwd1RUdCA9IHF1ZGIud25ZdEMoN25sbndLZzdPVHcud0UwW3pdKTsKICAgICAgICA3bmxud0ZsWVQgPSBxdWRiLnduWXRDKDdubG53S2c3T1R3LndFMFtaXSk7CgogICAgICAgIEJudyAoanV3IGcgPSB2OyBnIDwgS1M1TmdUb1R3QVZWbGc3dWRnbnQuQ243WXNUdGRBdHRuZHVkZ250eC5sVHRFZGI7IGcrKykgewogICAgICAgICAgICBqdXcgdXR0ID0gS1M1TmdUb1R3QVZWbGc3dWRnbnQuQ243WXNUdGRBdHRuZHVkZ250eFtnXTsKICAgICAgICAgICAgZ0IgKHV0dC54VGxUN2RUQyA9PSBkd1lUKSB7CiAgICAgICAgICAgICAgICB1dHQuN25sbndlVEMgPSA3bmxud2VUQzsKICAgICAgICAgICAgICAgIHV0dC43bmxud3B3VFR0ID0gN25sbndwd1RUdDsKICAgICAgICAgICAgICAgIHV0dC43bmxud0ZsWVQgPSA3bmxud0ZsWVQ7CiAgICAgICAgICAgICAgICB1dHQuQ2d3ZGsgPSBkd1lUOwogICAgICAgICAgICAgICAganV3IFZ1RVROZ1RvID0gS1M1TmdUb1R3QVZWbGc3dWRnbnQuVkNCTmdUb1R3LkVUZEt1RVROZ1RvKHV0dC5WdUVUZkMgLSB6KTsKICAgICAgICAgICAgICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250LkN3dW9TbjdZc1R0ZEF0dG5kdWRnbnR4KFZ1RVROZ1RvLCBWdUVUTmdUby43bnRkVHJkLCB1dHQuVnVFVGZDKTsKICAgICAgICAgICAgICAgIDB3VHVPOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfSwKICAgIC8vQUNDVEMgZGdsbCBiVHdUIDBrIFB3ZyBSd2d4YnR1dAoKICAgIHhvZ2Q3YlBnQ1QwdXdOZ1RvOiBCWXQ3ZGdudCBWQ0JOZ1RvUG9nZDdiUGdDVDB1d05nVG8oamdUbywgblZUdFBnQ1QwdXcpIHsKICAgICAgICBnQiAoblZUdFBnQ1QwdXcgJiYgIWRiZ3gueGdDVDB1dzlWVHQpIHsKICAgICAgICAgICAgQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ3hnQ1QwdXdIbkVFbFQnKS43bGc3TygpOwogICAgICAgIH0KICAgICAgICBqdXcgZGJZczB4TmdUbyA9IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdkYllzMHR1Z2xOZ1RvJyk7CiAgICAgICAganV3IG5ZZGxndFROZ1RvID0gQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ25ZZGxndFROZ1RvJyk7CiAgICAgICAganV3IHVkZHU3YnNUdGR4TmdUbyA9IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCd1ZGR1N2JzVHRkeE5nVG8nKTsKICAgICAgICBqdXcgdG5kVHhOZ1RvID0gQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ3RuZFR4TmdUbycpOy8vUHdnIFJ3Z3hidHV0CiAgICAgICAganV3IHV0dG5kdWRnbnR4TmdUbyA9IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCd1dHRuZHVkZ250eE5nVG8nKTsvL1B3ZyBSd2d4YnR1dAoKICAgICAgICBqdXcgZGJZczB4RllkZG50ID0gQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ2pnVG9IYllzMHR1Z2wnKTsKICAgICAgICBqdXcgbllkbGd0VEZZZGRudCA9IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdqZ1RvOVlkbGd0VCcpOwogICAgICAgIGp1dyB1ZGR1N2JzVHRkeEZZZGRudCA9IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdqZ1RvQWRkdTdic1R0ZHgnKTsKICAgICAgICBqdXcgdG5kVHhGWWRkbnQgPSBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnamdUbzZuZFR4Jyk7IC8vUHdnIFJ3Z3hidHV0CiAgICAgICAganV3IHV0dG5kdWRnbnR4RllkZG50ID0gQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ2pnVG9BdHRuZHVkZ250eCcpOyAvL1B3ZyBSd2d4YnR1dAoKICAgICAgICB4b2dkN2IgKGpnVG8pIHsKICAgICAgICAgICAgN3V4VCAnZGJZczB4JzoKICAgICAgICAgICAgICAgIGp1dyBvdXhBdG5kYlR3TmdUb05neGcwbFQgPSBkYllzMHhOZ1RvLjdsdXh4SWd4ZC43bnRkdWd0eCgnYmdDQ1R0Jyk7CgogICAgICAgICAgICAgICAgZGJZczB4RllkZG50LjdsdXh4SWd4ZC51Q0MoJ2RuRUVsVEMnKTsKICAgICAgICAgICAgICAgIG5ZZGxndFRGWWRkbnQuN2x1eHhJZ3hkLndUc25qVCgnZG5FRWxUQycpOwogICAgICAgICAgICAgICAgdWRkdTdic1R0ZHhGWWRkbnQuN2x1eHhJZ3hkLndUc25qVCgnZG5FRWxUQycpOwogICAgICAgICAgICAgICAgdG5kVHhGWWRkbnQuN2x1eHhJZ3hkLndUc25qVCgnZG5FRWxUQycpOy8vUHdnIFJ3Z3hidHV0CiAgICAgICAgICAgICAgICB1dHRuZHVkZ250eEZZZGRudC43bHV4eElneGQud1RzbmpUKCdkbkVFbFRDJyk7IC8vUHdnIFJ3Z3hidHV0CgogICAgICAgICAgICAgICAgZGJZczB4TmdUby43bHV4eElneGQud1RzbmpUKCdiZ0NDVHQnKTsKICAgICAgICAgICAgICAgIG5ZZGxndFROZ1RvLjdsdXh4SWd4ZC51Q0MoJ2JnQ0NUdCcpOwogICAgICAgICAgICAgICAgdWRkdTdic1R0ZHhOZ1RvLjdsdXh4SWd4ZC51Q0MoJ2JnQ0NUdCcpOwogICAgICAgICAgICAgICAgdG5kVHhOZ1RvLjdsdXh4SWd4ZC51Q0MoJ2JnQ0NUdCcpOyAvL1B3ZyBSd2d4YnR1dAogICAgICAgICAgICAgICAgdXR0bmR1ZGdudHhOZ1RvLjdsdXh4SWd4ZC51Q0MoJ2JnQ0NUdCcpOyAvL1B3ZyBSd2d4YnR1dAogICAgICAgICAgICAgICAgZGJneC5Cbnc3VGVUdENUd2d0RSgpOwoKICAgICAgICAgICAgICAgIGdCIChvdXhBdG5kYlR3TmdUb05neGcwbFQpIHsKICAgICAgICAgICAgICAgICAgICBkYmd4LlZDQkhiWXMwdHVnbE5nVG9Udy5UdHhZd1RIYllzMHR1Z2xOZ3hnMGxUKGRiZ3guVnVFVCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAwd1R1TzsKCiAgICAgICAgICAgIDd1eFQgJ25ZZGxndFQnOgogICAgICAgICAgICAgICAgZ0IgKG5ZZGxndFRGWWRkbnQuQ2d4dTBsVEMpIHsKICAgICAgICAgICAgICAgICAgICB3VGRZd3Q7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBkYllzMHhGWWRkbnQuN2x1eHhJZ3hkLndUc25qVCgnZG5FRWxUQycpOwogICAgICAgICAgICAgICAgbllkbGd0VEZZZGRudC43bHV4eElneGQudUNDKCdkbkVFbFRDJyk7CiAgICAgICAgICAgICAgICB1ZGR1N2JzVHRkeEZZZGRudC43bHV4eElneGQud1RzbmpUKCdkbkVFbFRDJyk7CiAgICAgICAgICAgICAgICB0bmRUeEZZZGRudC43bHV4eElneGQud1RzbmpUKCdkbkVFbFRDJyk7Ly9Qd2cgUndneGJ0dXQKICAgICAgICAgICAgICAgIHV0dG5kdWRnbnR4RllkZG50LjdsdXh4SWd4ZC53VHNualQoJ2RuRUVsVEMnKTsgLy9Qd2cgUndneGJ0dXQKCiAgICAgICAgICAgICAgICBkYllzMHhOZ1RvLjdsdXh4SWd4ZC51Q0MoJ2JnQ0NUdCcpOwogICAgICAgICAgICAgICAgbllkbGd0VE5nVG8uN2x1eHhJZ3hkLndUc25qVCgnYmdDQ1R0Jyk7CiAgICAgICAgICAgICAgICB1ZGR1N2JzVHRkeE5nVG8uN2x1eHhJZ3hkLnVDQygnYmdDQ1R0Jyk7CiAgICAgICAgICAgICAgICB0bmRUeE5nVG8uN2x1eHhJZ3hkLnVDQygnYmdDQ1R0Jyk7IC8vUHdnIFJ3Z3hidHV0CiAgICAgICAgICAgICAgICB1dHRuZHVkZ250eE5nVG8uN2x1eHhJZ3hkLnVDQygnYmdDQ1R0Jyk7IC8vUHdnIFJ3Z3hidHV0CiAgICAgICAgICAgICAgICAwd1R1TzsKCiAgICAgICAgICAgIDd1eFQgJ3VkZHU3YnNUdGR4JzoKICAgICAgICAgICAgICAgIGdCICh1ZGR1N2JzVHRkeEZZZGRudC5DZ3h1MGxUQykgewogICAgICAgICAgICAgICAgICAgIHdUZFl3dDsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGRiWXMweEZZZGRudC43bHV4eElneGQud1RzbmpUKCdkbkVFbFRDJyk7CiAgICAgICAgICAgICAgICBuWWRsZ3RURllkZG50LjdsdXh4SWd4ZC53VHNualQoJ2RuRUVsVEMnKTsKICAgICAgICAgICAgICAgIHVkZHU3YnNUdGR4RllkZG50LjdsdXh4SWd4ZC51Q0MoJ2RuRUVsVEMnKTsKICAgICAgICAgICAgICAgIHRuZFR4RllkZG50LjdsdXh4SWd4ZC53VHNualQoJ2RuRUVsVEMnKTsvL1B3ZyBSd2d4YnR1dAogICAgICAgICAgICAgICAgdXR0bmR1ZGdudHhGWWRkbnQuN2x1eHhJZ3hkLndUc25qVCgnZG5FRWxUQycpOyAvL1B3ZyBSd2d4YnR1dAoKICAgICAgICAgICAgICAgIGRiWXMweE5nVG8uN2x1eHhJZ3hkLnVDQygnYmdDQ1R0Jyk7CiAgICAgICAgICAgICAgICBuWWRsZ3RUTmdUby43bHV4eElneGQudUNDKCdiZ0NDVHQnKTsKICAgICAgICAgICAgICAgIHVkZHU3YnNUdGR4TmdUby43bHV4eElneGQud1RzbmpUKCdiZ0NDVHQnKTsKCiAgICAgICAgICAgICAgICB0bmRUeE5nVG8uN2x1eHhJZ3hkLnVDQygnYmdDQ1R0Jyk7IC8vUHdnIFJ3Z3hidHV0CiAgICAgICAgICAgICAgICB1dHRuZHVkZ250eE5nVG8uN2x1eHhJZ3hkLnVDQygnYmdDQ1R0Jyk7IC8vUHdnIFJ3Z3hidHV0CiAgICAgICAgICAgICAgICAwd1R1TzsKICAgICAgICAgICAgICAgIC8vQUNDVEMgMGsgUHdnIFJ3Z3hidHV0IEJudyB0bmRUeCAwWWRkbnQKICAgICAgICAgICAgN3V4VCAndG5kVHgnOgogICAgICAgICAgICAgICAgZGJZczB4RllkZG50LjdsdXh4SWd4ZC53VHNualQoJ2RuRUVsVEMnKTsKICAgICAgICAgICAgICAgIG5ZZGxndFRGWWRkbnQuN2x1eHhJZ3hkLndUc25qVCgnZG5FRWxUQycpOwogICAgICAgICAgICAgICAgdWRkdTdic1R0ZHhGWWRkbnQuN2x1eHhJZ3hkLndUc25qVCgnZG5FRWxUQycpOwogICAgICAgICAgICAgICAgdG5kVHhGWWRkbnQuN2x1eHhJZ3hkLnVDQygnZG5FRWxUQycpOy8vUHdnIFJ3Z3hidHV0CiAgICAgICAgICAgICAgICB1dHRuZHVkZ250eEZZZGRudC43bHV4eElneGQud1RzbmpUKCdkbkVFbFRDJyk7IC8vUHdnIFJ3Z3hidHV0CgogICAgICAgICAgICAgICAgZGJZczB4TmdUby43bHV4eElneGQudUNDKCdiZ0NDVHQnKTsKICAgICAgICAgICAgICAgIG5ZZGxndFROZ1RvLjdsdXh4SWd4ZC51Q0MoJ2JnQ0NUdCcpOwogICAgICAgICAgICAgICAgdWRkdTdic1R0ZHhOZ1RvLjdsdXh4SWd4ZC51Q0MoJ2JnQ0NUdCcpOwogICAgICAgICAgICAgICAgdG5kVHhOZ1RvLjdsdXh4SWd4ZC53VHNualQoJ2JnQ0NUdCcpOyAvL1B3ZyBSd2d4YnR1dAogICAgICAgICAgICAgICAgdXR0bmR1ZGdudHhOZ1RvLjdsdXh4SWd4ZC51Q0MoJ2JnQ0NUdCcpOyAvL1B3ZyBSd2d4YnR1dAogICAgICAgICAgICAgICAgMHdUdU87CgogICAgICAgICAgICA3dXhUICd1dHRuZHVkZ250eCc6CiAgICAgICAgICAgICAgICBkYllzMHhGWWRkbnQuN2x1eHhJZ3hkLndUc25qVCgnZG5FRWxUQycpOwogICAgICAgICAgICAgICAgbllkbGd0VEZZZGRudC43bHV4eElneGQud1RzbmpUKCdkbkVFbFRDJyk7CiAgICAgICAgICAgICAgICB1ZGR1N2JzVHRkeEZZZGRudC43bHV4eElneGQud1RzbmpUKCdkbkVFbFRDJyk7CiAgICAgICAgICAgICAgICB0bmRUeEZZZGRudC43bHV4eElneGQud1RzbmpUKCdkbkVFbFRDJyk7Ly9Qd2cgUndneGJ0dXQKICAgICAgICAgICAgICAgIHV0dG5kdWRnbnR4RllkZG50LjdsdXh4SWd4ZC51Q0MoJ2RuRUVsVEMnKTsvL1B3ZyBSd2d4YnR1dAoKICAgICAgICAgICAgICAgIGRiWXMweE5nVG8uN2x1eHhJZ3hkLnVDQygnYmdDQ1R0Jyk7CiAgICAgICAgICAgICAgICBuWWRsZ3RUTmdUby43bHV4eElneGQudUNDKCdiZ0NDVHQnKTsKICAgICAgICAgICAgICAgIHVkZHU3YnNUdGR4TmdUby43bHV4eElneGQudUNDKCdiZ0NDVHQnKTsKICAgICAgICAgICAgICAgIHRuZFR4TmdUby43bHV4eElneGQudUNDKCdiZ0NDVHQnKTsgLy9Qd2cgUndneGJ0dXQKICAgICAgICAgICAgICAgIHV0dG5kdWRnbnR4TmdUby43bHV4eElneGQud1RzbmpUKCdiZ0NDVHQnKTsgLy9Qd2cgUndneGJ0dXQKICAgICAgICAgICAgICAgIDB3VHVPOwogICAgICAgIH0KICAgIH0sCiAgICAwVEJud1RLd2d0ZDogQll0N2RnbnQgVkNCTmdUb1BUZFlWRlRCbndUS3dndGQoKSB7CiAgICAgICAgZ0IgKCFkYmd4LnhZVlZud2R4S3dndGRndEUpIHsKICAgICAgICAgICAganV3IFZ3Z3RkcVR4eHVFVCA9IHNuR0l6dnQuRVRkKCdWd2d0ZGd0RV90bmRfeFlWVm53ZFRDJywgdFlsbCwKICAgICAgICAgICAgICAgICAgICAnOHV3dGd0RTogS3dndGRndEUgZ3ggdG5kIEJZbGxrIHhZVlZud2RUQyAwayBkYmd4IDB3bm94VHcuJyk7CiAgICAgICAgICAgIGRiZ3guVHd3bncoVndndGRxVHh4dUVUKTsKICAgICAgICAgICAgd1RkWXd0OwogICAgICAgIH0KCiAgICAgICAganV3IHVsVHdkNm5kZVR1Q2sgPSBCdWx4VDsKICAgICAgICBqdXcgZywgZ2c7CiAgICAgICAgZ0IgKCFkYmd4LlZDQlNuN1lzVHRkIHx8ICFkYmd4LlZ1RVR4M25ZdGQpIHsKICAgICAgICAgICAgdWxUd2Q2bmRlVHVDayA9IGR3WVQ7CiAgICAgICAgfSBUbHhUIHsKICAgICAgICAgICAgQm53IChnID0gdiwgZ2cgPSBkYmd4LlZ1RVR4M25ZdGQ7IGcgPCBnZzsgKytnKSB7CiAgICAgICAgICAgICAgICBnQiAoIWRiZ3guVkNCTmdUb1R3LkVUZEt1RVROZ1RvKGcpLlZDQkt1RVQpIHsKICAgICAgICAgICAgICAgICAgICB1bFR3ZDZuZGVUdUNrID0gZHdZVDsKICAgICAgICAgICAgICAgICAgICAwd1R1TzsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBnQiAodWxUd2Q2bmRlVHVDaykgewogICAgICAgICAgICBqdXcgdG5kZVR1Q2txVHh4dUVUID0gc25HSXp2dC5FVGQoJ1Z3Z3RkZ3RFX3RuZF93VHVDaycsIHRZbGwsCiAgICAgICAgICAgICAgICAgICAgJzh1d3RndEU6IEhiVCBLUzUgZ3ggdG5kIEJZbGxrIGxudUNUQyBCbncgVndndGRndEUuJyk7CiAgICAgICAgICAgIG9ndENuby51bFR3ZCh0bmRlVHVDa3FUeHh1RVQpOwogICAgICAgICAgICB3VGRZd3Q7CiAgICAgICAgfQoKICAgICAgICBkYmd4LlZ3Z3RkZ3RFID0gZHdZVDsKICAgICAgICBkYmd4LkJudzdUZVR0Q1R3Z3RFKCk7CgogICAgICAgIGp1dyAwbkNrID0gQ243WXNUdGQuUVlUd2tQVGxUN2RudygnMG5DaycpOwogICAgICAgIDBuQ2sueFRkQWRkd2cwWWRUKCdDdWR1LXNuR0t3Z3RkM3VsbDB1N08nLCBkd1lUKTsKCiAgICAgICAgZ0IgKCFkYmd4LmJ1eE1RWXVsS3VFVFBnR1R4KSB7CiAgICAgICAgICAgIDdudHhubFQub3V3dCgnNm5kIHVsbCBWdUVUeCBidWpUIGRiVCB4dXNUIHhnR1QuIEhiVCBWd2d0ZFRDIHdUeFlsZCAnICsKICAgICAgICAgICAgICAgICAgICAnc3VrIDBUIGd0N253d1Q3ZCEnKTsKICAgICAgICB9CgogICAgICAgIC8vIGZ0eFR3ZCB1IEBWdUVUICsgeGdHVCB3WWxUIGRuIHN1T1QgeFl3VCBkYnVkIGRiVCBWdUVUIHhnR1QgZ3ggN253d1Q3ZGxrCiAgICAgICAgLy8geFRkLiA2bmRUIGRidWQgb1QgdXh4WXNUIGRidWQgdWxsIFZ1RVR4IGJ1alQgZGJUIHh1c1QgeGdHVCwgMFQ3dVl4VAogICAgICAgIC8vIGp1d2d1MGxULXhnR1QgVnVFVHggdXdUIHRuZCB4WVZWbndkVEMga1RkICh1ZCBsVHV4ZCBndCAzYnduc1QgJiA1Z3dUQm5yKS4KICAgICAgICAvLyBIOVM5KHduMG9ZKTogV3hUIHR1c1RDIFZ1RVR4IG9iVHQgeGdHVCA3dWw3WWx1ZGdudCAwWUV4IEVUZCB3VHhubGpUQwogICAgICAgIC8vIChULkUuIGJkZFZ4Oi8vN3cwWUUuN25zL21jY3p6RCkgQTZTIG9iVHQgeFlWVm53ZCBCbncgdHVzVEMgVnVFVHggZ3gKICAgICAgICAvLyB1Q0NUQyAoYmRkVjovL29vby5vbS5ud0UvSGUvN3h4bS1WdUVULyNZeGd0RS10dXNUQy1WdUVUeCkuCiAgICAgICAgLy8gZnQgMHdub3hUd3ggb2JUd1QgQFZ1RVQgKyB4Z0dUIGd4IHRuZCB4WVZWbndkVEMgKHhZN2IgdXggNWd3VEJuciwKICAgICAgICAvLyBiZGRWeDovLzBZRUdnbC5sdS9VY3ppaXopLCBkYlQgdFRyZCB4ZGtsVHhiVFRkIG9nbGwgMFQgZ0V0bndUQyB1dEMgZGJUCiAgICAgICAgLy8gWXhUdyBidXggZG4geFRsVDdkIGRiVCA3bnd3VDdkIFZ1VlR3IHhnR1QgZ3QgZGJUIFdmIGdCIG91dGRUQy4KICAgICAgICBkYmd4LlZ1RVRQZGtsVFBiVFRkID0gQ243WXNUdGQuN3dUdWRUTWxUc1R0ZCgneGRrbFQnKTsKICAgICAgICBqdXcgVnVFVFBnR1QgPSBkYmd4LlZDQk5nVG9Udy5FVGRLdUVUTmdUbyh2KS5WQ0JLdUVULkVUZE5nVG9WbndkKHopOwogICAgICAgIGRiZ3guVnVFVFBka2xUUGJUVGQuZFRyZDNudGRUdGQgPQogICAgICAgICAgICAgICAgLy8gInhnR1Q6PG9nQ2RiPiA8YlRnRWJkPiIgZ3ggb2J1ZCBvVCB0VFRDLiBGWWQgdWx4biB1Q0MgIkFpIiAwVDd1WXhUCiAgICAgICAgICAgICAgICAvLyA1Z3dUQm5yIGd0N253d1Q3ZGxrIHdUVm53ZHggeFlWVm53ZCBCbncgZGJUIG5kYlR3IGp1bFlULgogICAgICAgICAgICAgICAgJ0B4WVZWbndkeCAoKHhnR1Q6QWkpIHV0QyAoeGdHVDp6VmQgelZkKSkgeycgKwogICAgICAgICAgICAgICAgJ0BWdUVUIHsgeGdHVDogJyArIFZ1RVRQZ0dULm9nQ2RiICsgJ1ZkICcgKyBWdUVUUGdHVC5iVGdFYmQgKyAnVmQ7fScgKwogICAgICAgICAgICAgICAgLy8gSGJUIDd1dGp1eCB1dEMgVHU3YiB1dDdUeGRudyB0bkNUIHNZeGQgYnVqVCB1IGJUZ0ViZCBuQiB6dnYlIGRuIHN1T1QKICAgICAgICAgICAgICAgIC8vIHhZd1QgZGJ1ZCBUdTdiIDd1dGp1eCBneCBWd2d0ZFRDIG50IFRydTdkbGsgbnRUIFZ1RVQuCiAgICAgICAgICAgICAgICAnI1Z3Z3RkM250ZHVndFR3IHtiVGdFYmQ6enZ2JX0nICsKICAgICAgICAgICAgICAgICcjVndndGQzbnRkdWd0VHcgPiBDZ2oge29nQ2RiOnp2diUgIWdzVm53ZHV0ZDtiVGdFYmQ6enZ2JSAhZ3NWbndkdXRkO30nICsKICAgICAgICAgICAgICAgICd9JzsKICAgICAgICAwbkNrLnVWVlR0QzNiZ2xDKGRiZ3guVnVFVFBka2xUUGJUVGQpOwoKICAgICAgICBCbncgKGcgPSB2LCBnZyA9IGRiZ3guVnVFVHgzbll0ZDsgZyA8IGdnOyArK2cpIHsKICAgICAgICAgICAgZGJneC5WQ0JOZ1RvVHcuRVRkS3VFVE5nVG8oZykuMFRCbndUS3dndGQoKTsKICAgICAgICB9CgogICAgfSwKICAgIC8vIDhiVGRiVHcgdWxsIFZ1RVR4IG5CIGRiVCBLUzUgYnVqVCBkYlQgeHVzVCBvZ0NkYiB1dEMgYlRnRWJkLgogICAgRVRkIGJ1eE1RWXVsS3VFVFBnR1R4KCkgewogICAgICAgIGp1dyBCZ3d4ZEt1RVQgPSBkYmd4LlZDQk5nVG9Udy5FVGRLdUVUTmdUbyh2KTsKICAgICAgICBCbncgKGp1dyBnID0geiwgZ2cgPSBkYmd4LlZ1RVR4M25ZdGQ7IGcgPCBnZzsgKytnKSB7CiAgICAgICAgICAgIGp1dyBWdUVUTmdUbyA9IGRiZ3guVkNCTmdUb1R3LkVUZEt1RVROZ1RvKGcpOwogICAgICAgICAgICBnQiAoVnVFVE5nVG8ub2dDZGIgIT09IEJnd3hkS3VFVC5vZ0NkYiB8fAogICAgICAgICAgICAgICAgICAgIFZ1RVROZ1RvLmJUZ0ViZCAhPT0gQmd3eGRLdUVULmJUZ0ViZCkgewogICAgICAgICAgICAgICAgd1RkWXd0IEJ1bHhUOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHdUZFl3dCBkd1lUOwogICAgfSwKICAgIHVCZFR3S3dndGQ6IEJZdDdkZ250IFZDQk5nVG9QVGRZVkFCZFR3S3dndGQoKSB7CiAgICAgICAganV3IENnaiA9IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdWd2d0ZDNudGR1Z3RUdycpOwogICAgICAgIG9iZ2xUIChDZ2ouYnV4M2JnbEM2bkNUeCgpKSB7CiAgICAgICAgICAgIENnai53VHNualQzYmdsQyhDZ2oubHV4ZDNiZ2xDKTsKICAgICAgICB9CgogICAgICAgIGdCIChkYmd4LlZ1RVRQZGtsVFBiVFRkICYmIGRiZ3guVnVFVFBka2xUUGJUVGQuVnV3VHRkNm5DVCkgewogICAgICAgICAgICBkYmd4LlZ1RVRQZGtsVFBiVFRkLlZ1d1R0ZDZuQ1Qud1RzbmpUM2JnbEMoZGJneC5WdUVUUGRrbFRQYlRUZCk7CiAgICAgICAgICAgIGRiZ3guVnVFVFBka2xUUGJUVGQgPSB0WWxsOwogICAgICAgIH0KCiAgICAgICAgZGJneC5Wd2d0ZGd0RSA9IEJ1bHhUOwogICAgICAgIGRiZ3guQm53N1RlVHRDVHdndEUoKTsKICAgIH0sCiAgICB3bmR1ZFRLdUVUeDogQll0N2RnbnQgVkNCTmdUb2VuZHVkVEt1RVR4KENUbGR1KSB7CiAgICAgICAganV3IFZ1RVQ2WXMwVHcgPSBkYmd4LlZ1RVQ7CiAgICAgICAgZGJneC5WdUVUZW5kdWRnbnQgPSAoZGJneC5WdUVUZW5kdWRnbnQgKyBtRHYgKyBDVGxkdSkgJSBtRHY7CiAgICAgICAgZGJneC5WQ0JOZ1RvVHcuVnVFVHhlbmR1ZGdudCA9IGRiZ3guVnVFVGVuZHVkZ250OwogICAgICAgIGRiZ3guVkNCSGJZczB0dWdsTmdUb1R3LlZ1RVR4ZW5kdWRnbnQgPSBkYmd4LlZ1RVRlbmR1ZGdudDsKCiAgICAgICAgZGJneC5Cbnc3VGVUdENUd2d0RSgpOwoKICAgICAgICBkYmd4LlZDQk5nVG9Udy54N3dubGxLdUVUZnRkbk5nVG8oVnVFVDZZczBUdyk7CiAgICB9LAogICAgd1RRWVR4ZEt3VHhUdGR1ZGdudHFuQ1Q6IEJZdDdkZ250IFZDQk5nVG9lVFFZVHhkS3dUeFR0ZHVkZ250cW5DVCgpIHsKICAgICAgICBnQiAoIWRiZ3guVkNCS3dUeFR0ZHVkZ250cW5DVCkgewogICAgICAgICAgICB3VGRZd3Q7CiAgICAgICAgfQogICAgICAgIGRiZ3guVkNCS3dUeFR0ZHVkZ250cW5DVC53VFFZVHhkKCk7CiAgICB9LAogICAgLyoqCiAgICAgKiBAVnV3dXMge3RZczBUd30gQ1RsZHUgLSBIYlQgQ1RsZHUganVsWVQgQnducyBkYlQgc25ZeFQgVGpUdGQuCiAgICAgKi8KICAgIHg3d25sbEt3VHhUdGR1ZGdudHFuQ1Q6IEJZdDdkZ250IFZDQk5nVG9QN3dubGxLd1R4VHRkdWRnbnRxbkNUKENUbGR1KSB7CiAgICAgICAgZ0IgKCFkYmd4LlZDQkt3VHhUdGR1ZGdudHFuQ1QpIHsKICAgICAgICAgICAgd1RkWXd0OwogICAgICAgIH0KICAgICAgICBkYmd4LlZDQkt3VHhUdGR1ZGdudHFuQ1Quc25ZeFRQN3dubGwoQ1RsZHUpOwogICAgfQp9OwpvZ3RDbm8uS1M1TmdUbyA9IEtTNU5nVG9Ud0FWVmxnN3VkZ250OyAvLyBuMHhubFRkVCB0dXNULCBZeGd0RSBnZCB1eCB1dCB1bGd1eAoKCkJZdDdkZ250IG9UME5nVG9Ud0ludUMoVGpkKSB7CiAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5ndGdkZ3VsZ0dUKCkuZGJUdChvVDBOZ1RvVHdmdGdkZ3VsZ0dUQyk7CiAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnQmd0QzZUcmQnKS43bGc3TygpOwp9CgpCWXQ3ZGdudCBvVDBOZ1RvVHdmdGdkZ3VsZ0dUQygpIHsKICAgIGp1dyBRWVR3a1Bkd2d0RSA9IENuN1lzVHRkLmxuN3VkZ250LnhUdXc3Yi54WTB4ZHdndEUoeik7CiAgICBqdXcgVnV3dXN4ID0gVnV3eFRoWVR3a1Bkd2d0RShRWVR3a1Bkd2d0RSk7CiAgICBqdXcgQmdsVCA9ICdCZ2xUJyBndCBWdXd1c3ggPyBWdXd1c3guQmdsVCA6IFNNNUFXSUhfV2VJOwoKICAgIGp1dyBCZ2xUZnRWWWQgPSBDbjdZc1R0ZC43d1R1ZFRNbFRzVHRkKCdndFZZZCcpOwogICAgQmdsVGZ0VllkLmdDID0gJ0JnbFRmdFZZZCc7CiAgICBCZ2xUZnRWWWQuN2x1eHg2dXNUID0gJ0JnbFRmdFZZZCc7CiAgICBCZ2xUZnRWWWQueFRkQWRkd2cwWWRUKCdka1ZUJywgJ0JnbFQnKTsKICAgIEJnbFRmdFZZZC5udDdudGRUcmRzVHRZID0gdG4zbnRkVHJkcVR0WTJ1dENsVHc7CiAgICBDbjdZc1R0ZC4wbkNrLnVWVlR0QzNiZ2xDKEJnbFRmdFZZZCk7CgogICAgZ0IgKCFvZ3RDbm8uNWdsVCB8fCAhb2d0Q25vLjVnbFRlVHVDVHcgfHwgIW9ndENuby41Z2xUSWd4ZCB8fCAhb2d0Q25vLkZsbjApIHsKICAgICAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnblZUdDVnbFQnKS54VGRBZGR3ZzBZZFQoJ2JnQ0NUdCcsICdkd1lUJyk7CiAgICAgICAgQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ3hUN250Q3V3azlWVHQ1Z2xUJykueFRkQWRkd2cwWWRUKCdiZ0NDVHQnLCAnZHdZVCcpOwogICAgfSBUbHhUIHsKICAgICAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnQmdsVGZ0VllkJykuanVsWVQgPSB0WWxsOwogICAgfQoKCgogICAganV3IGxuN3VsVCA9IEtTNXlQLmxuN3VsVCB8fCB0dWpnRXVkbncubHV0RVl1RVQ7CgogICAgZ0IgKEtTNU5nVG9Ud0FWVmxnN3VkZ250LlZ3VEJUd1R0N1RLQ0JGWUVNdHUwbFRDKSB7CiAgICAgICAgLy8gUFZUN2d1bCBDVDBZRUVndEUgQmx1RXggZ3QgZGJUIGJ1eGIgeFQ3ZGdudCBuQiBkYlQgV2VJLgogICAgICAgIGp1dyBidXhiID0gQ243WXNUdGQubG43dWRnbnQuYnV4Yi54WTB4ZHdndEUoeik7CiAgICAgICAganV3IGJ1eGJLdXd1c3ggPSBWdXd4VGhZVHdrUGR3Z3RFKGJ1eGIpOwoKICAgICAgICBnQiAoJ0NneHUwbFRvbndPVHcnIGd0IGJ1eGJLdXd1c3gpIHsKICAgICAgICAgICAgS1M1eVAuQ2d4dTBsVDhud09UdyA9IChidXhiS3V3dXN4WydDZ3h1MGxUb253T1R3J10gPT09ICdkd1lUJyk7CiAgICAgICAgfQogICAgICAgIGdCICgnQ2d4dTBsVHd1dEVUJyBndCBidXhiS3V3dXN4KSB7CiAgICAgICAgICAgIEtTNXlQLkNneHUwbFRldXRFVCA9IChidXhiS3V3dXN4WydDZ3h1MGxUd3V0RVQnXSA9PT0gJ2R3WVQnKTsKICAgICAgICB9CiAgICAgICAgZ0IgKCdDZ3h1MGxUeGR3VHVzJyBndCBidXhiS3V3dXN4KSB7CiAgICAgICAgICAgIEtTNXlQLkNneHUwbFRQZHdUdXMgPSAoYnV4Ykt1d3VzeFsnQ2d4dTBsVHhkd1R1cyddID09PSAnZHdZVCcpOwogICAgICAgIH0KICAgICAgICBnQiAoJ0NneHUwbFR1WWRuQlRkN2InIGd0IGJ1eGJLdXd1c3gpIHsKICAgICAgICAgICAgS1M1eVAuQ2d4dTBsVEFZZG41VGQ3YiA9IChidXhiS3V3dXN4WydDZ3h1MGxUdVlkbkJUZDdiJ10gPT09ICdkd1lUJyk7CiAgICAgICAgfQogICAgICAgIGdCICgnQ2d4dTBsVEJudGRCdTdUJyBndCBidXhiS3V3dXN4KSB7CiAgICAgICAgICAgIEtTNXlQLkNneHUwbFQ1bnRkNXU3VCA9IChidXhiS3V3dXN4WydDZ3h1MGxUQm50ZEJ1N1QnXSA9PT0gJ2R3WVQnKTsKICAgICAgICB9CiAgICAgICAgZ0IgKCdDZ3h1MGxUYmd4ZG53aycgZ3QgYnV4Ykt1d3VzeCkgewogICAgICAgICAgICBLUzV5UC5DZ3h1MGxUMmd4ZG53ayA9IChidXhiS3V3dXN4WydDZ3h1MGxUYmd4ZG53ayddID09PSAnZHdZVCcpOwogICAgICAgIH0KICAgICAgICBnQiAoJ29UMEVsJyBndCBidXhiS3V3dXN4KSB7CiAgICAgICAgICAgIEtTNXlQLkNneHUwbFQ4VDBwSSA9IChidXhiS3V3dXN4WydvVDBFbCddICE9PSAnZHdZVCcpOwogICAgICAgIH0KICAgICAgICBnQiAoJ1l4VG50bGs3eHhHbm5zJyBndCBidXhiS3V3dXN4KSB7CiAgICAgICAgICAgIEtTNXlQLll4VDl0bGszeHhYbm5zID0gKGJ1eGJLdXd1c3hbJ1l4VG50bGs3eHhHbm5zJ10gPT09ICdkd1lUJyk7CiAgICAgICAgfQogICAgICAgIGdCICgnalR3MG54Z2RrJyBndCBidXhiS3V3dXN4KSB7CiAgICAgICAgICAgIEtTNXlQLmpUdzBueGdkayA9IGJ1eGJLdXd1c3hbJ2pUdzBueGdkayddIHwgdjsKICAgICAgICB9CiAgICAgICAgZ0IgKCdnRXRud1Q3WXd3VHRkVm54Z2RnbnRudEdubnMnIGd0IGJ1eGJLdXd1c3gpIHsKICAgICAgICAgICAgZnA2OWVNXzNXZWVNNkhfSzlQZkhmOTZfOTZfWDk5cSA9CiAgICAgICAgICAgICAgICAgICAgKGJ1eGJLdXd1c3hbJ2dFdG53VDdZd3dUdGRWbnhnZGdudG50R25ucyddID09PSAnZHdZVCcpOwogICAgICAgIH0KICAgICAgICBnQiAoJ2xuN3VsVCcgZ3QgYnV4Ykt1d3VzeCkgewogICAgICAgICAgICBsbjd1bFQgPSBidXhiS3V3dXN4Wydsbjd1bFQnXTsKICAgICAgICB9CiAgICAgICAgZ0IgKCdkVHJkbHVrVHcnIGd0IGJ1eGJLdXd1c3gpIHsKICAgICAgICAgICAgeG9nZDdiIChidXhiS3V3dXN4WydkVHJkbHVrVHcnXSkgewogICAgICAgICAgICAgICAgN3V4VCAnbkJCJzoKICAgICAgICAgICAgICAgICAgICBLUzV5UC5DZ3h1MGxUSFRyZEl1a1R3ID0gZHdZVDsKICAgICAgICAgICAgICAgICAgICAwd1R1TzsKICAgICAgICAgICAgICAgIDd1eFQgJ2pneGcwbFQnOgogICAgICAgICAgICAgICAgN3V4VCAneGJ1Q25vJzoKICAgICAgICAgICAgICAgIDd1eFQgJ2JualR3JzoKICAgICAgICAgICAgICAgICAgICBqdXcgamdUb1R3ID0gQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ2pnVG9UdycpOwogICAgICAgICAgICAgICAgICAgIGpnVG9Udy43bHV4eElneGQudUNDKCdkVHJkSXVrVHctJyArIGJ1eGJLdXd1c3hbJ2RUcmRsdWtUdyddKTsKICAgICAgICAgICAgICAgICAgICAwd1R1TzsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBnQiAoJ1ZDQjBZRScgZ3QgYnV4Ykt1d3VzeCkgewogICAgICAgICAgICBLUzV5UC5WQ0JGWUUgPSBkd1lUOwogICAgICAgICAgICBqdXcgVkNCRllFID0gYnV4Ykt1d3VzeFsnVkNCMFlFJ107CiAgICAgICAgICAgIGp1dyBUdHUwbFRDID0gVkNCRllFLnhWbGdkKCcsJyk7CiAgICAgICAgICAgIEtTNUZZRS5UdHUwbFQoVHR1MGxUQyk7CiAgICAgICAgICAgIEtTNUZZRS5ndGdkKCk7CiAgICAgICAgfQogICAgfQoKICAgIHNuR0l6dnQueFRkSXV0RVl1RVQobG43dWxUKTsKCiAgICBnQiAoIUtTNU5nVG9Ud0FWVmxnN3VkZ250LnhZVlZud2R4S3dndGRndEUpIHsKICAgICAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnVndndGQnKS43bHV4eElneGQudUNDKCdiZ0NDVHQnKTsKICAgICAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygneFQ3bnRDdXdrS3dndGQnKS43bHV4eElneGQudUNDKCdiZ0NDVHQnKTsKICAgIH0KCiAgICBnQiAoIUtTNU5nVG9Ud0FWVmxnN3VkZ250LnhZVlZud2R4NVlsbHg3d1RUdCkgewogICAgICAgIENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdWd1R4VHRkdWRnbnRxbkNUJykuN2x1eHhJZ3hkLnVDQygnYmdDQ1R0Jyk7CiAgICAgICAgQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ3hUN250Q3V3a0t3VHhUdGR1ZGdudHFuQ1QnKS4KICAgICAgICAgICAgICAgIDdsdXh4SWd4ZC51Q0MoJ2JnQ0NUdCcpOwogICAgfQoKICAgIGdCIChLUzVOZ1RvVHdBVlZsZzd1ZGdudC54WVZWbndkeGZ0ZFRFd3VkVEM1Z3RDKSB7CiAgICAgICAgQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ2pnVG81Z3RDJykuN2x1eHhJZ3hkLnVDQygnYmdDQ1R0Jyk7CiAgICB9CgogICAgLy8gSWd4ZFR0IEJudyBZdHhZVlZud2RUQyBCVHVkWXdUeCBkbiBkd2dFRVR3IGRiVCBCdWxsMHU3TyBXZi4KICAgIEtTNXlQLld0eFlWVm53ZFRDcXV0dUVUdy5sZ3hkVHQoS1M1TmdUb1R3QVZWbGc3dWRnbnQuQnVsbDB1N08uMGd0QyhLUzVOZ1RvVHdBVlZsZzd1ZGdudCkpOwoKICAgIC8vIFBZVlZ3VHh4IDdudGRUcmQgc1R0WXggQm53IHhuc1QgN250ZHdubHgKICAgIENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCd4N3VsVFBUbFQ3ZCcpLm50N250ZFRyZHNUdFkgPSB0bjNudGRUcmRxVHRZMnV0Q2xUdzsKCiAgICBqdXcgc3VndDNudGR1Z3RUdyA9IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdzdWd0M250ZHVndFR3Jyk7CiAgICBqdXcgbllkVHczbnRkdWd0VHcgPSBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnbllkVHczbnRkdWd0VHcnKTsKICAgIHN1Z3QzbnRkdWd0VHcudUNDTWpUdGRJZ3hkVHRUdygnZHd1dHhnZGdudFR0QycsIEJZdDdkZ250IChUKSB7CiAgICAgICAgZ0IgKFQuZHV3RVRkID09PSBzdWd0M250ZHVndFR3KSB7CiAgICAgICAgICAgIGp1dyBUalR0ZCA9IENuN1lzVHRkLjd3VHVkVE1qVHRkKCdXZk1qVHRkeCcpOwogICAgICAgICAgICBUalR0ZC5ndGdkV2ZNalR0ZCgnd1R4Z0dUJywgQnVseFQsIEJ1bHhULCBvZ3RDbm8sIHYpOwogICAgICAgICAgICBvZ3RDbm8uQ2d4VnVkN2JNalR0ZChUalR0ZCk7CiAgICAgICAgICAgIG5ZZFR3M250ZHVndFR3LjdsdXh4SWd4ZC53VHNualQoJ3hnQ1QwdXdxbmpndEUnKTsKICAgICAgICB9CiAgICB9LCBkd1lUKTsKCiAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygneGdDVDB1d0huRUVsVCcpLnVDQ01qVHRkSWd4ZFR0VHcoJzdsZzdPJywKICAgICAgICAgICAgQll0N2RnbnQgKCkgewogICAgICAgICAgICAgICAgZGJneC43bHV4eElneGQuZG5FRWxUKCdkbkVFbFRDJyk7CiAgICAgICAgICAgICAgICBuWWRUdzNudGR1Z3RUdy43bHV4eElneGQudUNDKCd4Z0NUMHV3cW5qZ3RFJyk7CiAgICAgICAgICAgICAgICBuWWRUdzNudGR1Z3RUdy43bHV4eElneGQuZG5FRWxUKCd4Z0NUMHV3OVZUdCcpOwogICAgICAgICAgICAgICAgS1M1TmdUb1R3QVZWbGc3dWRnbnQueGdDVDB1dzlWVHQgPQogICAgICAgICAgICAgICAgICAgICAgICBuWWRUdzNudGR1Z3RUdy43bHV4eElneGQuN250ZHVndHgoJ3hnQ1QwdXc5VlR0Jyk7CiAgICAgICAgICAgICAgICBnQiAoS1M1TmdUb1R3QVZWbGc3dWRnbnQueGdDVDB1dzlWVHQpIHsKICAgICAgICAgICAgICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC53VEJ3VHhiSGJZczB0dWdsTmdUb1R3KCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5Cbnc3VGVUdENUd2d0RSgpOwogICAgICAgICAgICB9KTsKCiAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnamdUb0hiWXMwdHVnbCcpLnVDQ01qVHRkSWd4ZFR0VHcoJzdsZzdPJywgQll0N2RnbnQgKCkgewogICAgICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250LnhvZ2Q3YlBnQ1QwdXdOZ1RvKCdkYllzMHgnKTsKICAgIH0pOwoKICAgIENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdqZ1RvOVlkbGd0VCcpLnVDQ01qVHRkSWd4ZFR0VHcoJzdsZzdPJywgQll0N2RnbnQgKCkgewogICAgICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250LnhvZ2Q3YlBnQ1QwdXdOZ1RvKCduWWRsZ3RUJyk7CiAgICB9KTsKCiAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnamdUbzlZZGxndFQnKS51Q0NNalR0ZElneGRUdFR3KCdDMGw3bGc3TycsIEJZdDdkZ250ICgpIHsKICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5uWWRsZ3RULmRuRUVsVDlZZGxndFRId1RUKCk7CiAgICB9KTsKCiAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnamdUb0FkZHU3YnNUdGR4JykudUNDTWpUdGRJZ3hkVHRUdygnN2xnN08nLCBCWXQ3ZGdudCAoKSB7CiAgICAgICAgS1M1TmdUb1R3QVZWbGc3dWRnbnQueG9nZDdiUGdDVDB1d05nVG8oJ3VkZHU3YnNUdGR4Jyk7CiAgICB9KTsKCiAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnVndUamduWXgnKS51Q0NNalR0ZElneGRUdFR3KCc3bGc3TycsIEJZdDdkZ250ICgpIHsKICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5WdUVULS07CiAgICB9KTsKCiAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygndFRyZCcpLnVDQ01qVHRkSWd4ZFR0VHcoJzdsZzdPJywgQll0N2RnbnQgKCkgewogICAgICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250LlZ1RVQrKzsKICAgIH0pOwoKICAgIENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdHbm5zZnQnKS51Q0NNalR0ZElneGRUdFR3KCc3bGc3TycsIEJZdDdkZ250ICgpIHsKICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5Hbm5zZnQoKTsKICAgIH0pOwoKICAgIENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdHbm5zOVlkJykudUNDTWpUdGRJZ3hkVHRUdygnN2xnN08nLCBCWXQ3ZGdudCAoKSB7CiAgICAgICAgS1M1TmdUb1R3QVZWbGc3dWRnbnQuR25uczlZZCgpOwogICAgfSk7CgogICAgQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ1Z1RVQ2WXMwVHcnKS51Q0NNalR0ZElneGRUdFR3KCc3bGc3TycsIEJZdDdkZ250ICgpIHsKICAgICAgICBkYmd4LnhUbFQ3ZCgpOwogICAgfSk7CgogICAgQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ1Z1RVQ2WXMwVHcnKS51Q0NNalR0ZElneGRUdFR3KCc3YnV0RVQnLCBCWXQ3ZGdudCAoKSB7CiAgICAgICAgLy8gMnV0Q2xUIGRiVCBZeFR3IGd0VllkZGd0RSB1IEJsbnVkZ3RFIFZuZ3RkIHRZczBUdy4KICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5WdUVUID0gKGRiZ3guanVsWVQgfCB2KTsKCiAgICAgICAgZ0IgKGRiZ3guanVsWVQgIT09IChkYmd4Lmp1bFlUIHwgdikuZG5QZHdndEUoKSkgewogICAgICAgICAgICBkYmd4Lmp1bFlUID0gS1M1TmdUb1R3QVZWbGc3dWRnbnQuVnVFVDsKICAgICAgICB9CiAgICB9KTsKCiAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygneDd1bFRQVGxUN2QnKS51Q0NNalR0ZElneGRUdFR3KCc3YnV0RVQnLCBCWXQ3ZGdudCAoKSB7CiAgICAgICAgZ0IgKGRiZ3guanVsWVQgPT09ICc3WXhkbnMnKSB7CiAgICAgICAgICAgIHdUZFl3dDsKICAgICAgICB9CiAgICAgICAgS1M1TmdUb1R3QVZWbGc3dWRnbnQuVkNCTmdUb1R3LjdZd3dUdGRQN3VsVE51bFlUID0gZGJneC5qdWxZVDsKICAgIH0pOwoKICAgIENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdWd1R4VHRkdWRnbnRxbkNUJykudUNDTWpUdGRJZ3hkVHRUdygnN2xnN08nLCBQVDdudEN1d2tIbm5sMHV3LlZ3VHhUdGR1ZGdudHFuQ1QzbGc3Ty4wZ3RDKFBUN250Q3V3a0hubmwwdXcpKTsKCiAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnblZUdDVnbFQnKS51Q0NNalR0ZElneGRUdFR3KCc3bGc3TycsIFBUN250Q3V3a0hubmwwdXcublZUdDVnbFQzbGc3Ty4wZ3RDKFBUN250Q3V3a0hubmwwdXcpKTsKICA8P1ZiVgogICAgZ0IgKGd0X3V3d3VrKCdtJywgJFZUd19DVGR1Z2x4KSB8fCBndF91d3d1aygnRCcsICRWVHdfQ1RkdWdseCkgfHwgJENuN3hUZF9Wd2d0ZF9CbHVFKSB7CiAgICAgICAgPz4KICAgIENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdWd2d0ZCcpLnVDQ01qVHRkSWd4ZFR0VHcoJzdsZzdPJywgUFQ3bnRDdXdrSG5ubDB1dy5Wd2d0ZDNsZzdPLjBndEMoUFQ3bnRDdXdrSG5ubDB1dykpOwogIDw/VmJWCiAgICB9CiAgICA/PgogICAgIDw/VmJWCiAgICBnQiAoZ3RfdXd3dWsoJ1onLCAkVlR3X0NUZHVnbHgpIHx8IGd0X3V3d3VrKCdEJywgJFZUd19DVGR1Z2x4KSB8fCAkQ243eFRkX0Nub3RsbnVDX0JsdUUpIHsKICAgICAgICA/PiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKCiAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnQ25vdGxudUMnKS51Q0NNalR0ZElneGRUdFR3KCc3bGc3TycsIFBUN250Q3V3a0hubmwwdXcuQ25vdGxudUMzbGc3Ty4wZ3RDKFBUN250Q3V3a0hubmwwdXcpKTsKICAgPD9WYlYgfQogICAgPz4KCiAgICAvLwlBQ0NUQyAwayBQd2cgUndneGJ0dXQKICAgIENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdqZ1RvNm5kVHgnKS51Q0NNalR0ZElneGRUdFR3KCc3bGc3TycsIEJZdDdkZ250ICgpIHsKICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC54b2dkN2JQZ0NUMHV3TmdUbygndG5kVHgnKTsKICAgIH0pOwogICAgQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ2pnVG9BdHRuZHVkZ250eCcpLnVDQ01qVHRkSWd4ZFR0VHcoJzdsZzdPJywgQll0N2RnbnQgKCkgewogICAgICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250LnhvZ2Q3YlBnQ1QwdXdOZ1RvKCd1dHRuZHVkZ250eCcpOwogICAgfSk7CiAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygneHVqVHRuZFQnKS51Q0NNalR0ZElneGRUdFR3KCc3bGc3TycsIEJZdDdkZ250IChUKSB7CiAgICAgICAgVC5Wd1RqVHRkU1RCdVlsZCgpOwogICAgICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250Lnh1alRBdENJbnVDU243WXNUdGQ2bmRUeCgpOwogICAgfSk7CiAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygneHVqVEF0dG5kdWRnbnR4JykudUNDTWpUdGRJZ3hkVHRUdygnN2xnN08nLCBCWXQ3ZGdudCAoKSB7CiAgICAgICAgS1M1TmdUb1R3QVZWbGc3dWRnbnQueHVqVEF0Q0ludUNTbjdZc1R0ZEF0dG5kdWRnbnR4KCk7CiAgICAgICAgS1M1TmdUb1R3QVZWbGc3dWRnbnQud25kdWRUS3VFVHgodik7CiAgICB9KTsKICAgIENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdDVGxUZFRBdHRuZHVkZ250JykudUNDTWpUdGRJZ3hkVHRUdygnN2xnN08nLCBCWXQ3ZGdudCAoKSB7CiAgICAgICAgS1M1TmdUb1R3QVZWbGc3dWRnbnQuQ1RsVGRUU243WXNUdGRBdHRuZHVkZ250KCk7CiAgICB9KTsKICAgIENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdiZ0VibGdFYmQnKS51Q0NNalR0ZElneGRUdFR3KCc3bGc3TycsIEJZdDdkZ250ICgpIHsKICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC43d1R1ZFRTbjdZc1R0ZEF0dG5kdWRnbnQoQTY2OUhBSGY5Nl8yZnAySWZwMkgpOwogICAgfSk7CiAgICAgPD9WYlYgZ0IoJHdUQ3U3ZF94ZHVzVl94Z0V0X3dnRWJkeF9DVGR1Z2x4W3ZdWyd3VEN1N2QnXSl7ID8+CiAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnMGx1N09uWWQnKS51Q0NNalR0ZElneGRUdFR3KCc3bGc3TycsIEJZdDdkZ250ICgpIHsKICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC43d1R1ZFRTbjdZc1R0ZEF0dG5kdWRnbnQoQTY2OUhBSGY5Nl9GSUEzUjlXSCk7CiAgICB9KTsKICAgICA8P1ZiViB9Pz4KICAgIENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdUbGxnVnhUJykudUNDTWpUdGRJZ3hkVHRUdygnN2xnN08nLCBCWXQ3ZGdudCAoKSB7CiAgICAgICAgS1M1TmdUb1R3QVZWbGc3dWRnbnQuN3dUdWRUU243WXNUdGRBdHRuZHVkZ250KEE2NjlIQUhmOTZfTUlJZktQTSk7CiAgICB9KTsKCiAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygneGRnN09rdG5kVCcpLnVDQ01qVHRkSWd4ZFR0VHcoJzdsZzdPJywgQll0N2RnbnQgKCkgewogICAgICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250Ljd3VHVkVFNuN1lzVHRkQXR0bmR1ZGdudChBNjY5SEFIZjk2X1BIZjNSNDY5SE0pOwogICAgfSk7CiAgICA8P1ZiViBnQigkd1RDdTdkX3hkdXNWX3hnRXRfd2dFYmR4X0NUZHVnbHhbdl1bJ3hkdXNWJ10peyA/PgogICAgQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ3dZMDBUd3hkdXNWJykudUNDTWpUdGRJZ3hkVHRUdygnN2xnN08nLCBCWXQ3ZGdudCAoKSB7CiAgICAgICAgZ0IgKEtTNU5nVG9Ud0FWVmxnN3VkZ250LlZDQk5nVG9Udy5fVnVFVHhlbmR1ZGdudCA9PSB2KSB7CiAgICAgICAgICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250LndZMDBUd1BkdXNWQXR0bmR1ZGdudC5uVlR0KCk7CiAgICAgICAgfQogICAgfSk7CiAgICAgPD9WYlYgfT8+CiAgICAgPD9WYlYgZ0IoJHdUQ3U3ZF94ZHVzVl94Z0V0X3dnRWJkeF9DVGR1Z2x4W3ZdWydDZ0VnZHVsX3hnRXQnXSAmJiAkQ2dFZ2R1bF94Z0V0dWRZd1Rfc25DWWxUW3ZdWyd4ZHVkWXgnXSA9PSB6KXsgPz4gICAgCiAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnQ2dFZ2R1bHhnRXQnKS51Q0NNalR0ZElneGRUdFR3KCc3bGc3TycsIEJZdDdkZ250ICgpIHsKICAgICAgICBnQiAoS1M1TmdUb1R3QVZWbGc3dWRnbnQuVkNCTmdUb1R3Ll9WdUVUeGVuZHVkZ250ID09IHYpIHsKICAgICAgICAgICAgS1M1TmdUb1R3QVZWbGc3dWRnbnQuQ2dFZ2R1bHhnRXRBdHRuZHVkZ250Lm5WVHQoKTsKICAgICAgICB9CiAgICB9KTsKICAgIDw/VmJWIH0/PgogICAgZ0IgKEJnbFQgJiYgQmdsVC5sdXhkZnRDVHI5QignQmdsVDonLCB2KSA9PT0gdikgewogICAgICAgIC8vIEJnbFQ6LXg3YlRzVC4gSW51QyBkYlQgN250ZFR0ZHggZ3QgZGJUIHN1Z3QgZGJ3VHVDIDBUN3VZeFQgaGQ4VDBSZ2QKICAgICAgICAvLyA3dXR0bmQgbG51QyBCZ2xUOi1XZUl4IGd0IHUgOFQwIDhud09Udy4gQmdsVDotV2VJeCB1d1QgWXhZdWxsayBsbnVDVEMKICAgICAgICAvLyBqVHdrIFFZZzdPbGssIHhuIGRiVHdUIGd4IHRuIHRUVEMgZG4geFRkIFlWIFZ3bkV3VHh4IFRqVHRkIGxneGRUdFR3eC4KICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC54VGRIZ2RsVFd4Z3RFV3dsKEJnbFQpOwogICAgICAgIGp1dyByYncgPSB0VG8gSnFJMmRkVmVUUVlUeGQoKTsKICAgICAgICByYncubnRsbnVDID0gQll0N2RnbnQgKCkgewogICAgICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5uVlR0KHRUbyBXZ3RkVUF3d3VrKHJidy53VHhWbnR4VCksIHYpOwogICAgICAgIH07CiAgICAgICAgZHdrIHsKICAgICAgICAgICAgcmJ3Lm5WVHQoJ3BNSCcsIEJnbFQpOwogICAgICAgICAgICByYncud1R4Vm50eFRIa1ZUID0gJ3V3d3VrMFlCQlR3JzsKICAgICAgICAgICAgcmJ3LnhUdEMoKTsKICAgICAgICB9IDd1ZDdiIChUKSB7CiAgICAgICAgICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250LlR3d253KHNuR0l6dnQuRVRkKCdsbnVDZ3RFX1R3d253JywgdFlsbCwKICAgICAgICAgICAgICAgICAgICAnQXQgVHd3bncgbjc3WXd3VEMgb2JnbFQgbG51Q2d0RSBkYlQgS1M1LicpLCBUKTsKICAgICAgICB9CiAgICAgICAgd1RkWXd0OwogICAgfQoKICAgIGdCIChCZ2xUKSB7CiAgICAgICAgS1M1TmdUb1R3QVZWbGc3dWRnbnQublZUdChCZ2xULCB2KTsKICAgIH0KfQoKQ243WXNUdGQudUNDTWpUdGRJZ3hkVHRUdygnUzlxM250ZFR0ZEludUNUQycsIG9UME5nVG9Ud0ludUMsIGR3WVQpOwoKQ243WXNUdGQudUNDTWpUdGRJZ3hkVHRUdygnVnVFVHdUdENUd1RDJywgQll0N2RnbnQgKFQpIHsKICAgIGp1dyBWdUVUNllzMFR3ID0gVC5DVGR1Z2wuVnVFVDZZczBUdzsKICAgIGp1dyBWdUVUZnRDVHIgPSBWdUVUNllzMFR3IC0gejsKICAgIGp1dyBWdUVUTmdUbyA9IEtTNU5nVG9Ud0FWVmxnN3VkZ250LlZDQk5nVG9Udy5FVGRLdUVUTmdUbyhWdUVUZnRDVHIpOwoKICAgIC8vQUNDVEMgMGsgUHdnIFJ3Z3hidHV0IEJudyBDd3VvZ3RFIDdZeGRucyB1dHRuZHVkZ250eAogICAgQ3d1b0F0dG5kdWRnbnQ4d3VWVlR3KFZ1RVROZ1RvLCBWdUVUNllzMFR3KTsKICAgIC8vQUNDVEMgZGdsbCBiVHdUIFB3ZyBSd2d4YnR1dCBCbncgQ3d1b2d0RSA3WXhkbnMgdXR0bmR1ZGdudHgKCiAgICBnQiAoS1M1TmdUb1R3QVZWbGc3dWRnbnQueGdDVDB1dzlWVHQpIHsKICAgICAgICBqdXcgZGJZczB0dWdsTmdUbyA9IEtTNU5nVG9Ud0FWVmxnN3VkZ250LlZDQkhiWXMwdHVnbE5nVG9Udy5FVGRIYllzMHR1Z2woVnVFVGZ0Q1RyKTsKICAgICAgICBkYllzMHR1Z2xOZ1RvLnhUZGZzdUVUKFZ1RVROZ1RvKTsKICAgIH0KCiAgICBnQiAoS1M1eVAuVkNCRllFICYmIFBkdWR4LlR0dTBsVEMgJiYgVnVFVE5nVG8ueGR1ZHgpIHsKICAgICAgICBQZHVkeC51Q0MoVnVFVDZZczBUdywgVnVFVE5nVG8ueGR1ZHgpOwogICAgfQoKICAgIGdCIChWdUVUTmdUby5Ud3dudykgewogICAgICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250LlR3d253KHNuR0l6dnQuRVRkKCd3VHRDVHdndEVfVHd3bncnLCB0WWxsLCAnQXQgVHd3bncgbjc3WXd3VEMgb2JnbFQgd1R0Q1R3Z3RFIGRiVCBWdUVULicpLCBWdUVUTmdUby5Ud3dudyk7CiAgICB9CgogICAgLy8gZkIgZGJUIFZ1RVQgZ3ggeGRnbGwgamd4ZzBsVCBvYlR0IGdkIGJ1eCBCZ3RneGJUQyB3VHRDVHdndEUsCiAgICAvLyBUdHhZd1QgZGJ1ZCBkYlQgVnVFVCB0WXMwVHcgZ3RWWWQgbG51Q2d0RSBndENnN3VkbncgZ3ggYmdDQ1R0LgogICAgZ0IgKFZ1RVQ2WXMwVHcgPT09IEtTNU5nVG9Ud0FWVmxnN3VkZ250LlZ1RVQpIHsKICAgICAgICBqdXcgVnVFVDZZczBUd2Z0VllkID0gQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ1Z1RVQ2WXMwVHcnKTsKICAgICAgICBWdUVUNllzMFR3ZnRWWWQuN2x1eHhJZ3hkLndUc25qVChLQXBNXzZXcUZNZV9JOUFTZjZwX2Y2U2YzQUg5ZSk7CiAgICB9Cgp9LCBkd1lUKTsKCkNuN1lzVHRkLnVDQ01qVHRkSWd4ZFR0VHcoJ2RUcmRsdWtUd3dUdENUd1RDJywgQll0N2RnbnQgKFQpIHsKICAgIGp1dyBWdUVUZnRDVHIgPSBULkNUZHVnbC5WdUVUNllzMFR3IC0gejsKICAgIGp1dyBWdUVUTmdUbyA9IEtTNU5nVG9Ud0FWVmxnN3VkZ250LlZDQk5nVG9Udy5FVGRLdUVUTmdUbyhWdUVUZnRDVHIpOwoKfSwgZHdZVCk7CgpDbjdZc1R0ZC51Q0NNalR0ZElneGRUdFR3KCdWdUVUc25DVCcsIEJZdDdkZ250IChUamQpIHsKICAgIGdCICghS1M1TmdUb1R3QVZWbGc3dWRnbnQuZ3RnZGd1bGdHVEMpIHsKICAgICAgICB3VGRZd3Q7CiAgICB9CiAgICAvLyAydXRDbFQgZGJUICdWdUVUc25DVCcgYnV4YiBWdXd1c1RkVHcsIHhUVCB1bHhuIGBLUzVJZ3RPUFR3amc3VF94VGQydXhiYC4KICAgIGp1dyBzbkNUID0gVGpkLkNUZHVnbC5zbkNUOwogICAgeG9nZDdiIChzbkNUKSB7CiAgICAgICAgN3V4VCAnMG5uT3N1d094JzoKICAgICAgICAgICAgLy8gNm5kVDogOVl3IDduQ1QgN3VsbHggZGJneCBWd25WVHdkayAnbllkbGd0VCcsIFRqVHQgZGJuWUViIGRiVAogICAgICAgICAgICAvLyAgICAgICA5VlR0IEt1d3VzVGRUdyB4VlQ3Z0JnN3VkZ250IDd1bGx4IGdkICcwbm5Pc3V3T3gnLgogICAgICAgICAgICBzbkNUID0gJ25ZZGxndFQnOwogICAgICAgICAgICAvKiBCdWxseCBkYnduWUViICovCiAgICAgICAgN3V4VCAnZGJZczB4JzoKICAgICAgICA3dXhUICd1ZGR1N2JzVHRkeCc6CiAgICAgICAgICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250LnhvZ2Q3YlBnQ1QwdXdOZ1RvKHNuQ1QsIGR3WVQpOwogICAgICAgICAgICAwd1R1TzsKICAgICAgICA3dXhUICd0bnRUJzoKICAgICAgICAgICAgZ0IgKEtTNU5nVG9Ud0FWVmxnN3VkZ250LnhnQ1QwdXc5VlR0KSB7CiAgICAgICAgICAgICAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygneGdDVDB1d0huRUVsVCcpLjdsZzdPKCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgMHdUdU87CiAgICB9Cn0sIGR3WVQpOwoKQ243WXNUdGQudUNDTWpUdGRJZ3hkVHRUdygndHVzVEN1N2RnbnQnLCBCWXQ3ZGdudCAoVCkgewogICAgZ0IgKCFLUzVOZ1RvVHdBVlZsZzd1ZGdudC5ndGdkZ3VsZ0dUQykgewogICAgICAgIHdUZFl3dDsKICAgIH0KICAgIC8vIEt3bjdUeHhndEUgN25ZVmxUIG5CIHR1c1RDIHU3ZGdudHggZGJ1ZCBzZ0ViZCAwVCBZeFRCWWwuCiAgICAvLyBQVFQgdWx4biBLUzVJZ3RPUFR3amc3VC5UclQ3WWRUNnVzVENBN2RnbnQKICAgIGp1dyB1N2RnbnQgPSBULkNUZHVnbC51N2RnbnQ7CiAgICB4b2dkN2IgKHU3ZGdudCkgewogICAgICAgIDd1eFQgJ3BuSG5LdUVUJzoKICAgICAgICAgICAgQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ1Z1RVQ2WXMwVHcnKS5CbjdZeCgpOwogICAgICAgICAgICAwd1R1TzsKCiAgICAgICAgN3V4VCAnNWd0Qyc6CiAgICAgICAgICAgIGdCICghS1M1TmdUb1R3QVZWbGc3dWRnbnQueFlWVm53ZHhmdGRURXd1ZFRDNWd0QykgewogICAgICAgICAgICAgICAgS1M1TmdUb1R3QVZWbGc3dWRnbnQuQmd0Q0Z1dy5kbkVFbFQoKTsKICAgICAgICAgICAgfQogICAgICAgICAgICAwd1R1TzsKICAgIH0KfSwgZHdZVCk7CgpvZ3RDbm8udUNDTWpUdGRJZ3hkVHRUdygnVndUeFR0ZHVkZ250c25DVDdidXRFVEMnLCBCWXQ3ZGdudCAoVCkgewogICAganV3IHU3ZGdqVCA9IFQuQ1RkdWdsLnU3ZGdqVDsKICAgIGp1dyB4b2dkN2JmdEt3bkV3VHh4ID0gVC5DVGR1Z2wueG9nZDdiZnRLd25Fd1R4eDsKICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250LlZDQk5nVG9Udy5Wd1R4VHRkdWRnbnRxbkNUUGR1ZFQgPQogICAgICAgICAgICB4b2dkN2JmdEt3bkV3VHh4ID8gS3dUeFR0ZHVkZ250cW5DVFBkdWRULjMyQTZwZjZwIDoKICAgICAgICAgICAgdTdkZ2pUID8gS3dUeFR0ZHVkZ250cW5DVFBkdWRULjVXSUlQM2VNTTYgOiBLd1R4VHRkdWRnbnRxbkNUUGR1ZFQuNjllcUFJOwp9KTsKCm9ndENuby51Q0NNalR0ZElneGRUdFR3KCdZVkN1ZFRqZ1RvdXdUdScsIEJZdDdkZ250IChUamQpIHsKICAgIGdCICghS1M1TmdUb1R3QVZWbGc3dWRnbnQuZ3RnZGd1bGdHVEMpIHsKICAgICAgICB3VGRZd3Q7CiAgICB9CiAgICBqdXcgbG43dWRnbnQgPSBUamQubG43dWRnbnQ7CgogICAgS1M1TmdUb1R3QVZWbGc3dWRnbnQueGRud1QuZ3RnZGd1bGdHVENLd25zZ3hULmRiVHQoQll0N2RnbnQgKCkgewogICAgICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250LnhkbndULnhUZHFZbGRnVmxUKHsKICAgICAgICAgICAgJ1RyZ3hkeCc6IGR3WVQsCiAgICAgICAgICAgICdWdUVUJzogbG43dWRnbnQuVnVFVDZZczBUdywKICAgICAgICAgICAgJ0dubnMnOiBsbjd1ZGdudC54N3VsVCwKICAgICAgICAgICAgJ3g3d25sbElUQmQnOiBsbjd1ZGdudC5sVEJkLAogICAgICAgICAgICAneDd3bmxsSG5WJzogbG43dWRnbnQuZG5WCiAgICAgICAgfSkuN3VkN2IoQll0N2RnbnQgKCkgewogICAgICAgICAgICAvLyBZdHUwbFQgZG4gb3dnZFQgZG4geGRud3VFVAogICAgICAgIH0pOwogICAgfSk7CiAgICBqdXcgYndUQiA9CiAgICAgICAgICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250LlZDQklndE9QVHdqZzdULkVUZEF0N2Jud1d3bChsbjd1ZGdudC5WQ0I5VlR0S3V3dXN4KTsKICAgIENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdqZ1RvRm5uT3N1d08nKS5id1RCID0gYndUQjsKICAgIENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCd4VDdudEN1d2tOZ1RvRm5uT3N1d08nKS5id1RCID0gYndUQjsKCiAgICAvLyBXVkN1ZFQgZGJUIDdZd3dUdGQgMG5uT3N1d08gZ3QgZGJUIDB3bm94Z3RFIGJneGRud2suCiAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5WQ0IyZ3hkbndrLllWQ3VkVDNZd3dUdGRGbm5Pc3V3Tyhsbjd1ZGdudC5WQ0I5VlR0S3V3dXN4LAogICAgICAgICAgICBsbjd1ZGdudC5WdUVUNllzMFR3KTsKCiAgICAvLyBQYm5vL2JnQ1QgZGJUIGxudUNndEUgZ3RDZzd1ZG53IGd0IGRiVCBWdUVUIHRZczBUdyBndFZZZCBUbFRzVHRkLgogICAganV3IFZ1RVQ2WXMwVHdmdFZZZCA9IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdWdUVUNllzMFR3Jyk7CiAgICBqdXcgN1l3d1R0ZEt1RVQgPQogICAgICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5WQ0JOZ1RvVHcuRVRkS3VFVE5nVG8oS1M1TmdUb1R3QVZWbGc3dWRnbnQuVnVFVCAtIHopOwoKICAgIGdCICg3WXd3VHRkS3VFVC53VHRDVHdndEVQZHVkVCA9PT0gZVR0Q1R3Z3RFUGR1ZFR4LjVmNmZQMk1TKSB7CiAgICAgICAgVnVFVDZZczBUd2Z0VllkLjdsdXh4SWd4ZC53VHNualQoS0FwTV82V3FGTWVfSTlBU2Y2cF9mNlNmM0FIOWUpOwogICAgfSBUbHhUIHsKICAgICAgICBWdUVUNllzMFR3ZnRWWWQuN2x1eHhJZ3hkLnVDQyhLQXBNXzZXcUZNZV9JOUFTZjZwX2Y2U2YzQUg5ZSk7CiAgICB9Cn0sIGR3WVQpOwoKb2d0Q25vLnVDQ01qVHRkSWd4ZFR0VHcoJ3dUeGdHVCcsIEJZdDdkZ250IG9UME5nVG9Ud2VUeGdHVChUamQpIHsKICAgIGdCIChLUzVOZ1RvVHdBVlZsZzd1ZGdudC5ndGdkZ3VsZ0dUQykgewogICAgICAgIGp1dyA3WXd3VHRkUDd1bFROdWxZVCA9IEtTNU5nVG9Ud0FWVmxnN3VkZ250LlZDQk5nVG9Udy43WXd3VHRkUDd1bFROdWxZVDsKICAgICAgICBnQiAoN1l3d1R0ZFA3dWxUTnVsWVQgPT09ICd1WWRuJyB8fAogICAgICAgICAgICAgICAgN1l3d1R0ZFA3dWxUTnVsWVQgPT09ICdWdUVULUJnZCcgfHwKICAgICAgICAgICAgICAgIDdZd3dUdGRQN3VsVE51bFlUID09PSAnVnVFVC1vZ0NkYicpIHsKICAgICAgICAgICAgLy8gNm5kVDogZGJUIHg3dWxUIGd4IDdudHhkdXRkIEJudyAnVnVFVC11N2RZdWwnLgogICAgICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5WQ0JOZ1RvVHcuN1l3d1R0ZFA3dWxUTnVsWVQgPSA3WXd3VHRkUDd1bFROdWxZVDsKICAgICAgICB9IFRseFQgZ0IgKCE3WXd3VHRkUDd1bFROdWxZVCkgewogICAgICAgICAgICAvLyA2bndzdWxsayBkYmd4IHhibllsQ3QnZCBidVZWVHQsIDBZZCBnQiBkYlQgeDd1bFQgb3V4dCdkIGd0Z2RndWxnR1RDCiAgICAgICAgICAgIC8vIG9UIHhUZCBnZCBkbiBkYlQgQ1RCdVlsZCBqdWxZVCBndCBud0NUdyBkbiBWd1RqVHRkIHV0ayBneHhZVHguCiAgICAgICAgICAgIC8vIChNLkUuIGRiVCBDbjdZc1R0ZCAwVGd0RSB3VHRDVHdUQyBvZ2RiIGRiVCBvd250RSB4N3VsVCBudCBsbnVDLikKICAgICAgICAgICAgS1M1TmdUb1R3QVZWbGc3dWRnbnQuVkNCTmdUb1R3LjdZd3dUdGRQN3VsVE51bFlUID0gU001QVdJSF9QM0FJTV9OQUlXTTsKICAgICAgICB9CiAgICAgICAgS1M1TmdUb1R3QVZWbGc3dWRnbnQuVkNCTmdUb1R3LllWQ3VkVCgpOwogICAgfQoKICAgIC8vIFBUZCBkYlQgJ3N1ci1iVGdFYmQnIDNQUCBWd25WVHdkayBuQiBkYlQgeFQ3bnRDdXdrIGRubmwwdXcuCiAgICBQVDdudEN1d2tIbm5sMHV3LnhUZHF1cjJUZ0ViZChDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnamdUb1R3M250ZHVndFR3JykpOwp9KTsKCm9ndENuby51Q0NNalR0ZElneGRUdFR3KCdidXhiN2J1dEVUJywgQll0N2RnbnQgb1QwTmdUb1R3MnV4YjdidXRFVChUamQpIHsKICAgIGdCIChLUzVOZ1RvVHdBVlZsZzd1ZGdudC5WQ0IyZ3hkbndrLmd4MnV4YjNidXRFVFd0bG43T1RDKSB7CiAgICAgICAganV3IGJ1eGIgPSBDbjdZc1R0ZC5sbjd1ZGdudC5idXhiLnhZMHhkd2d0RSh6KTsKICAgICAgICBnQiAoIWJ1eGIpIHsKICAgICAgICAgICAgd1RkWXd0OwogICAgICAgIH0KICAgICAgICBnQiAoIUtTNU5nVG9Ud0FWVmxnN3VkZ250Lmd4ZnRnZGd1bE5nVG9QVGQpIHsKICAgICAgICAgICAgS1M1TmdUb1R3QVZWbGc3dWRnbnQuZ3RnZGd1bEZubk9zdXdPID0gYnV4YjsKICAgICAgICB9IFRseFQgewogICAgICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5WQ0JJZ3RPUFR3amc3VC54VGQydXhiKGJ1eGIpOwogICAgICAgIH0KICAgIH0KfSk7CgpvZ3RDbm8udUNDTWpUdGRJZ3hkVHRUdygnN2J1dEVUJywgQll0N2RnbnQgb1QwTmdUb1R3M2J1dEVUKFRqZCkgewogICAganV3IEJnbFR4ID0gVGpkLmR1d0VUZC5CZ2xUeDsKICAgIGdCICghQmdsVHggfHwgQmdsVHgubFR0RWRiID09PSB2KSB7CiAgICAgICAgd1RkWXd0OwogICAgfQogICAganV3IEJnbFQgPSBCZ2xUeFt2XTsKCiAgICBnQiAoIUtTNXlQLkNneHUwbFQzd1R1ZFQ5MDFUN2RXZUkgJiYKICAgICAgICAgICAgZGtWVG5CIFdlSSAhPT0gJ1l0Q1RCZ3RUQycgJiYgV2VJLjd3VHVkVDkwMVQ3ZFdlSSkgewogICAgICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250Lm5WVHQoV2VJLjd3VHVkVDkwMVQ3ZFdlSShCZ2xUKSwgdik7CiAgICB9IFRseFQgewogICAgICAgIC8vIGVUdUMgZGJUIGxuN3VsIEJnbFQgZ3RkbiB1IFdndGRVQXd3dWsuCiAgICAgICAganV3IEJnbFRlVHVDVHcgPSB0VG8gNWdsVGVUdUNUdygpOwogICAgICAgIEJnbFRlVHVDVHcubnRsbnVDID0gQll0N2RnbnQgb1QwTmdUb1R3M2J1dEVUNWdsVGVUdUNUdzl0bG51QyhUamQpIHsKICAgICAgICAgICAganV3IDBZQkJUdyA9IFRqZC5kdXdFVGQud1R4WWxkOwoKICAgICAgICAgICAganV3IFlndGRVQXd3dWsgPSB0VG8gV2d0ZFVBd3d1aygwWUJCVHcpOwogICAgICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5uVlR0KFlndGRVQXd3dWssIHYpOwogICAgICAgIH07CiAgICAgICAgQmdsVGVUdUNUdy53VHVDQXhBd3d1a0ZZQkJUdyhCZ2xUKTsgICAgICAgCiAgICAgICAgCgogICAgfQoKICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250LnhUZEhnZGxUV3hndEVXd2woQmdsVC50dXNUKTsKCiAgICAvLyBXZUkgQ25UeCB0bmQgd1RCbFQ3ZCBWd25WVHcgQ243WXNUdGQgbG43dWRnbnQgLSBiZ0NndEUgeG5zVCBnN250eC4KICAgIENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdqZ1RvRm5uT3N1d08nKS54VGRBZGR3ZzBZZFQoJ2JnQ0NUdCcsICdkd1lUJyk7CiAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygneFQ3bnRDdXdrTmdUb0Zubk9zdXdPJykuCiAgICAgICAgICAgIHhUZEFkZHdnMFlkVCgnYmdDQ1R0JywgJ2R3WVQnKTsKICAgIENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdDbm90bG51QycpLnhUZEFkZHdnMFlkVCgnYmdDQ1R0JywgJ2R3WVQnKTsKICAgIENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCd4VDdudEN1d2tTbm90bG51QycpLnhUZEFkZHdnMFlkVCgnYmdDQ1R0JywgJ2R3WVQnKTsKfSwgZHdZVCk7CgpCWXQ3ZGdudCB4VGxUN2RQN3VsVDlWZGdudChqdWxZVCkgewogICAganV3IG5WZGdudHggPSBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygneDd1bFRQVGxUN2QnKS5uVmRnbnR4OwogICAganV3IFZ3VENUQmd0VENOdWxZVDVuWXRDID0gQnVseFQ7CiAgICBCbncgKGp1dyBnID0gdiwgZ2cgPSBuVmRnbnR4LmxUdEVkYjsgZyA8IGdnOyBnKyspIHsKICAgICAgICBqdXcgblZkZ250ID0gblZkZ250eFtnXTsKICAgICAgICBnQiAoblZkZ250Lmp1bFlUICE9PSBqdWxZVCkgewogICAgICAgICAgICBuVmRnbnQueFRsVDdkVEMgPSBCdWx4VDsKICAgICAgICAgICAgN250ZGd0WVQ7CiAgICAgICAgfQogICAgICAgIG5WZGdudC54VGxUN2RUQyA9IGR3WVQ7CiAgICAgICAgVndUQ1RCZ3RUQ051bFlUNW5ZdEMgPSBkd1lUOwogICAgfQogICAgd1RkWXd0IFZ3VENUQmd0VENOdWxZVDVuWXRDOwp9CgpvZ3RDbm8udUNDTWpUdGRJZ3hkVHRUdygnbG43dWxnR1RDJywgQll0N2RnbnQgbG43dWxnR1RDKFRqZCkgewogICAgQ243WXNUdGQuRVRkTWxUc1R0ZHhGa0h1RTZ1c1QoJ2Jkc2wnKVt2XS5DZ3cgPSBzbkdJenZ0LkVUZFNnd1Q3ZGdudCgpOwoKICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250LnV0Z3N1ZGdudFBkdXdkVENLd25zZ3hULmRiVHQoQll0N2RnbnQgKCkgewogICAgICAgIC8vIEFDMVl4ZCBkYlQgb2dDZGIgbkIgZGJUIEdubnMgMG5yIGRuIEJnZCBkYlQgN250ZFR0ZC4KICAgICAgICAvLyA2bmRUOiBmQiBkYlQgb2d0Q25vIGd4IHR1d3dubyBUdG5ZRWIgZGJ1ZCBkYlQgR25ucyAwbnIgZ3ggdG5kIGpneGcwbFQsCiAgICAgICAgLy8gICAgICAgb1QgZFRzVm53dXdnbGsgeGJubyBnZCBkbiAwVCB1MGxUIGRuIHVDMVl4ZCBnZHggb2dDZGIuCiAgICAgICAganV3IDdudGR1Z3RUdyA9IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCd4N3VsVFBUbFQ3ZDNudGR1Z3RUdycpOwogICAgICAgIGdCICg3bnRkdWd0VHcuN2xnVHRkOGdDZGIgPT09IHYpIHsKICAgICAgICAgICAgN250ZHVndFR3LnhUZEFkZHdnMFlkVCgneGRrbFQnLCAnQ2d4Vmx1azogZ3RiVHdnZDsnKTsKICAgICAgICB9CiAgICAgICAgZ0IgKDdudGR1Z3RUdy43bGdUdGQ4Z0NkYiA+IHYpIHsKICAgICAgICAgICAganV3IHhUbFQ3ZCA9IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCd4N3VsVFBUbFQ3ZCcpOwogICAgICAgICAgICB4VGxUN2QueFRkQWRkd2cwWWRUKCd4ZGtsVCcsICdzZ3Qtb2dDZGI6IGd0YlR3Z2Q7Jyk7CiAgICAgICAgICAgIGp1dyBvZ0NkYiA9IHhUbFQ3ZC43bGdUdGQ4Z0NkYiArIFAzQUlNX1BNSU0zSF8zOTZIQWY2TWVfS0FTU2Y2cDsKICAgICAgICAgICAgeFRsVDdkLnhUZEFkZHdnMFlkVCgneGRrbFQnLCAnc2d0LW9nQ2RiOiAnICsKICAgICAgICAgICAgICAgICAgICAob2dDZGIgKyBQM0FJTV9QTUlNM0hfS0FTU2Y2cCkgKyAnVnI7Jyk7CiAgICAgICAgICAgIDdudGR1Z3RUdy54VGRBZGR3ZzBZZFQoJ3hka2xUJywgJ3NndC1vZ0NkYjogJyArIG9nQ2RiICsgJ1ZyOyAnICsKICAgICAgICAgICAgICAgICAgICAnc3VyLW9nQ2RiOiAnICsgb2dDZGIgKyAnVnI7Jyk7CiAgICAgICAgfQoKICAgICAgICAvLyBQVGQgZGJUICdzdXItYlRnRWJkJyAzUFAgVnduVlR3ZGsgbkIgZGJUIHhUN250Q3V3ayBkbm5sMHV3LgogICAgICAgIFBUN250Q3V3a0hubmwwdXcueFRkcXVyMlRnRWJkKENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdqZ1RvVHczbnRkdWd0VHcnKSk7CiAgICB9KTsKfSwgZHdZVCk7CgpvZ3RDbm8udUNDTWpUdGRJZ3hkVHRUdygneDd1bFQ3YnV0RVQnLCBCWXQ3ZGdudCB4N3VsVDdidXRFVChUamQpIHsKICAgIENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdHbm5zOVlkJykuQ2d4dTBsVEMgPSAoVGpkLng3dWxUID09PSBxZjZfUDNBSU0pOwogICAgQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ0dubnNmdCcpLkNneHUwbFRDID0gKFRqZC54N3VsVCA9PT0gcUFKX1AzQUlNKTsKCiAgICAvLyBXVkN1ZFQgZGJUICd4N3VsVFBUbFQ3ZCcgUzlxIFRsVHNUdGQuCiAgICBqdXcgVndUQ1RCZ3RUQ051bFlUNW5ZdEMgPSB4VGxUN2RQN3VsVDlWZGdudChUamQuVndUeFRkTnVsWVQgfHwKICAgICAgICAgICAgJycgKyBUamQueDd1bFQpOwogICAgZ0IgKCFWd1RDVEJndFRDTnVsWVQ1bll0QykgewogICAgICAgIGp1dyA3WXhkbnNQN3VsVDlWZGdudCA9IENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCc3WXhkbnNQN3VsVDlWZGdudCcpOwogICAgICAgIGp1dyA3WXhkbnNQN3VsVCA9IHF1ZGIud25ZdEMoVGpkLng3dWxUICogenZ2dnYpIC8genZ2OwogICAgICAgIDdZeGRuc1A3dWxUOVZkZ250LmRUcmQzbnRkVHRkID0KICAgICAgICAgICAgICAgIHNuR0l6dnQuRVRkKCdWdUVUX3g3dWxUX1ZUdzdUdGQnLCB7eDd1bFQ6IDdZeGRuc1A3dWxUfSwgJ3t7eDd1bFR9fSUnKTsKICAgICAgICA3WXhkbnNQN3VsVDlWZGdudC54VGxUN2RUQyA9IGR3WVQ7CiAgICB9CiAgICBnQiAoIUtTNU5nVG9Ud0FWVmxnN3VkZ250Lmd0Z2RndWxnR1RDKSB7CiAgICAgICAgd1RkWXd0OwogICAgfQogICAgS1M1TmdUb1R3QVZWbGc3dWRnbnQuVkNCTmdUb1R3LllWQ3VkVCgpOwp9LCBkd1lUKTsKCm9ndENuby51Q0NNalR0ZElneGRUdFR3KCdWdUVUN2J1dEVUJywgQll0N2RnbnQgVnVFVDdidXRFVChUamQpIHsKICAgIGp1dyBWdUVUID0gVGpkLlZ1RVQ2WXMwVHc7CiAgICBnQiAoVGpkLlZ3VGpnbll4S3VFVDZZczBUdyAhPT0gVnVFVCkgewogICAgICAgIENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdWdUVUNllzMFR3JykuanVsWVQgPSBWdUVUOwogICAgICAgIGdCIChLUzVOZ1RvVHdBVlZsZzd1ZGdudC54Z0NUMHV3OVZUdCkgewogICAgICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5WQ0JIYllzMHR1Z2xOZ1RvVHcueDd3bmxsSGJZczB0dWdsZnRkbk5nVG8oVnVFVCk7CiAgICAgICAgfQogICAgfQogICAganV3IHRZc0t1RVR4ID0gS1M1TmdUb1R3QVZWbGc3dWRnbnQuVnVFVHgzbll0ZDsKCiAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnVndUamduWXgnKS5DZ3h1MGxUQyA9IChWdUVUIDw9IHopOwogICAgQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ3RUcmQnKS5DZ3h1MGxUQyA9IChWdUVUID49IHRZc0t1RVR4KTsKCiAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnQmd3eGRLdUVUJykuQ2d4dTBsVEMgPSAoVnVFVCA8PSB6KTsKICAgIENuN1lzVHRkLkVUZE1sVHNUdGRGa2ZDKCdsdXhkS3VFVCcpLkNneHUwbFRDID0gKFZ1RVQgPj0gdFlzS3VFVHgpOwoKICAgIC8vIG9UIHRUVEMgZG4gWVZDdWRUIHhkdWR4CiAgICBnQiAoS1M1eVAuVkNCRllFICYmIFBkdWR4LlR0dTBsVEMpIHsKICAgICAgICBqdXcgVnVFVE5nVG8gPSBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5WQ0JOZ1RvVHcuRVRkS3VFVE5nVG8oVnVFVCAtIHopOwogICAgICAgIGdCIChWdUVUTmdUby54ZHVkeCkgewogICAgICAgICAgICBQZHVkeC51Q0MoVnVFVCwgVnVFVE5nVG8ueGR1ZHgpOwogICAgICAgIH0KICAgIH0KfSwgZHdZVCk7CgpCWXQ3ZGdudCBidXRDbFRxbll4VDhiVFRsKFRqZCkgewogICAganV3IHE5V1BNXzgyTU1JX1NNSUhBXzVBM0g5ZSA9IGl2OwogICAganV3IGRnN094ID0gKFRqZC5ka1ZUID09PSAnUzlxcW5ZeFRQN3dubGwnKSA/IC1UamQuQ1RkdWdsIDoKICAgICAgICAgICAgVGpkLm9iVFRsU1RsZHUgLyBxOVdQTV84Mk1NSV9TTUlIQV81QTNIOWU7CiAgICBqdXcgQ2d3VDdkZ250ID0gKGRnN094IDwgdikgPyAnR25uczlZZCcgOiAnR25uc2Z0JzsKCiAgICBqdXcgVkNCTmdUb1R3ID0gS1M1TmdUb1R3QVZWbGc3dWRnbnQuVkNCTmdUb1R3OwogICAgZ0IgKFZDQk5nVG9Udy5neGZ0S3dUeFR0ZHVkZ250cW5DVCkgewogICAgICAgIFRqZC5Wd1RqVHRkU1RCdVlsZCgpOwogICAgICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250Lng3d25sbEt3VHhUdGR1ZGdudHFuQ1QoZGc3T3ggKgogICAgICAgICAgICAgICAgcTlXUE1fODJNTUlfU01JSEFfNUEzSDllKTsKICAgIH0gVGx4VCBnQiAoVGpkLjdkd2xSVGsgfHwgVGpkLnNUZHVSVGspIHsKICAgICAgICAvLyA5dGxrIEdubnMgZGJUIFZ1RVR4LCB0bmQgZGJUIFR0ZGd3VCBqZ1RvVHcuCiAgICAgICAgVGpkLlZ3VGpUdGRTVEJ1WWxkKCk7CgogICAgICAgIGp1dyBWd1RqZ25ZeFA3dWxUID0gVkNCTmdUb1R3LjdZd3dUdGRQN3VsVDsKCiAgICAgICAgS1M1TmdUb1R3QVZWbGc3dWRnbnRbQ2d3VDdkZ250XShxdWRiLnUweChkZzdPeCkpOwoKICAgICAgICBqdXcgN1l3d1R0ZFA3dWxUID0gVkNCTmdUb1R3LjdZd3dUdGRQN3VsVDsKICAgICAgICBnQiAoVndUamduWXhQN3VsVCAhPT0gN1l3d1R0ZFA3dWxUKSB7CiAgICAgICAgICAgIC8vIEFCZFR3IHg3dWxndEUgZGJUIFZ1RVQgamd1IEdubnNmdC9Hbm5zOVlkLCBkYlQgVm54Z2RnbnQgbkIgZGJUIFlWVlR3LQogICAgICAgICAgICAvLyBsVEJkIDdud3RUdyBneCB3VHhkbndUQy4gOGJUdCBkYlQgc25ZeFQgb2JUVGwgZ3ggWXhUQywgZGJUIFZueGdkZ250CiAgICAgICAgICAgIC8vIFl0Q1R3IGRiVCA3WXd4bncgeGJuWWxDIDBUIHdUeGRud1RDIGd0eGRUdUMuCiAgICAgICAgICAgIGp1dyB4N3VsVDNud3dUN2RnbnQ1dTdkbncgPSA3WXd3VHRkUDd1bFQgLyBWd1RqZ25ZeFA3dWxUIC0gejsKICAgICAgICAgICAganV3IHdUN2QgPSBWQ0JOZ1RvVHcuN250ZHVndFR3LkVUZEZuWXRDZ3RFM2xnVHRkZVQ3ZCgpOwogICAgICAgICAgICBqdXcgQ3IgPSBUamQuN2xnVHRkSiAtIHdUN2QubFRCZDsKICAgICAgICAgICAganV3IENrID0gVGpkLjdsZ1R0ZDQgLSB3VDdkLmRuVjsKICAgICAgICAgICAgVkNCTmdUb1R3LjdudGR1Z3RUdy54N3dubGxJVEJkICs9IENyICogeDd1bFQzbnd3VDdkZ250NXU3ZG53OwogICAgICAgICAgICBWQ0JOZ1RvVHcuN250ZHVndFR3Lng3d25sbEhuViArPSBDayAqIHg3dWxUM253d1Q3ZGdudDV1N2RudzsKICAgICAgICB9CiAgICB9Cn0KCm9ndENuby51Q0NNalR0ZElneGRUdFR3KCdTOXFxbll4VFA3d25sbCcsIGJ1dENsVHFuWXhUOGJUVGwpOwpvZ3RDbm8udUNDTWpUdGRJZ3hkVHRUdygnc25ZeFRvYlRUbCcsIGJ1dENsVHFuWXhUOGJUVGwpOwoKb2d0Q25vLnVDQ01qVHRkSWd4ZFR0VHcoJzdsZzdPJywgQll0N2RnbnQgN2xnN08oVGpkKSB7CiAgICBnQiAoUFQ3bnRDdXdrSG5ubDB1dy5uVlR0VEMgJiYKICAgICAgICAgICAgS1M1TmdUb1R3QVZWbGc3dWRnbnQuVkNCTmdUb1R3LjdudGR1Z3R4TWxUc1R0ZChUamQuZHV3RVRkKSkgewogICAgICAgIFBUN250Q3V3a0hubmwwdXcuN2xueFQoKTsKICAgIH0KfSwgQnVseFQpOwoKb2d0Q25vLnVDQ01qVHRkSWd4ZFR0VHcoJ09Ua0Nub3QnLCBCWXQ3ZGdudCBPVGtDbm90KFRqZCkgewogICAgZ0IgKDlqVHdsdWtxdXR1RVR3LnU3ZGdqVCkgewogICAgICAgIHdUZFl3dDsKICAgIH0KCiAgICBqdXcgYnV0Q2xUQyA9IEJ1bHhUOwogICAganV3IDdzQyA9IChUamQuN2R3bFJUayA/IHogOiB2KSB8CiAgICAgICAgICAgIChUamQudWxkUlRrID8gWiA6IHYpIHwKICAgICAgICAgICAgKFRqZC54YmdCZFJUayA/IGkgOiB2KSB8CiAgICAgICAgICAgIChUamQuc1RkdVJUayA/IFUgOiB2KTsKCiAgICBqdXcgVkNCTmdUb1R3ID0gS1M1TmdUb1R3QVZWbGc3dWRnbnQuVkNCTmdUb1R3OwogICAganV3IGd4TmdUb1R3ZnRLd1R4VHRkdWRnbnRxbkNUID0gVkNCTmdUb1R3ICYmIFZDQk5nVG9Udy5neGZ0S3dUeFR0ZHVkZ250cW5DVDsKCiAgICAvLyA1Z3d4ZCwgYnV0Q2xUIGRiVCBPVGsgMGd0Q2d0RXggZGJ1ZCB1d1QgZ3RDVFZUdENUdGQgb2JUZGJUdyB1dCBndFZZZAogICAgLy8gN250ZHdubCBneCB4VGxUN2RUQyBudyB0bmQuCiAgICBnQiAoN3NDID09PSB6IHx8IDdzQyA9PT0gVSB8fCA3c0MgPT09IGMgfHwgN3NDID09PSB6WikgewogICAgICAgIC8vIFRnZGJUdyAzSGVJIG53IHFNSEEgT1RrIG9nZGIgblZkZ250dWwgUDJmNUguCiAgICAgICAgeG9nZDdiIChUamQuT1RrM25DVCkgewogICAgICAgICAgICA3dXhUIGF2OiAvLyBCCiAgICAgICAgICAgICAgICBnQiAoIUtTNU5nVG9Ud0FWVmxnN3VkZ250LnhZVlZud2R4ZnRkVEV3dWRUQzVndEMpIHsKICAgICAgICAgICAgICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5CZ3RDRnV3Lm5WVHQoKTsKICAgICAgICAgICAgICAgICAgICBidXRDbFRDID0gZHdZVDsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIDB3VHVPOwogICAgICAgICAgICA3dXhUIGF6OiAvLyBFCiAgICAgICAgICAgICAgICBnQiAoIUtTNU5nVG9Ud0FWVmxnN3VkZ250LnhZVlZud2R4ZnRkVEV3dWRUQzVndEMpIHsKICAgICAgICAgICAgICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5CZ3RDRnV3LkNneFZ1ZDdiTWpUdGQoJ3VFdWd0JywKICAgICAgICAgICAgICAgICAgICAgICAgICAgIDdzQyA9PT0gYyB8fCA3c0MgPT09IHpaKTsKICAgICAgICAgICAgICAgICAgICBidXRDbFRDID0gZHdZVDsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIDB3VHVPOwogICAgICAgICAgICA3dXhUIER6OiAvLyA1NS9xdTcgJz0nCiAgICAgICAgICAgIDd1eFQgenZhOiAvLyA1NSAnKycgdXRDICc9JwogICAgICAgICAgICA3dXhUIHpVYTogLy8gM2J3bnNUICcrJwogICAgICAgICAgICA3dXhUIHphejogLy8gNTUgb2dkYiBwVHdzdXQgT1RrMG51d0MKICAgICAgICAgICAgICAgIGdCICghZ3hOZ1RvVHdmdEt3VHhUdGR1ZGdudHFuQ1QpIHsKICAgICAgICAgICAgICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5Hbm5zZnQoKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGJ1dENsVEMgPSBkd1lUOwogICAgICAgICAgICAgICAgMHdUdU87CiAgICAgICAgICAgIDd1eFQgemFtOiAvLyA1NS9xdTcgJy0nCiAgICAgICAgICAgIDd1eFQgenZMOiAvLyA1NSAnLScKICAgICAgICAgICAgN3V4VCB6VUw6IC8vIDNid25zVCAnLScKICAgICAgICAgICAgICAgIGdCICghZ3hOZ1RvVHdmdEt3VHhUdGR1ZGdudHFuQ1QpIHsKICAgICAgICAgICAgICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5Hbm5zOVlkKCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBidXRDbFRDID0gZHdZVDsKICAgICAgICAgICAgICAgIDB3VHVPOwogICAgICAgICAgICA3dXhUIGlVOiAvLyAndicKICAgICAgICAgICAgN3V4VCBMRDogLy8gJ3YnIG50IDZZc1Z1QyBuQiBQb1RDZ3hiIE9UazBudXdDCiAgICAgICAgICAgICAgICBnQiAoIWd4TmdUb1R3ZnRLd1R4VHRkdWRnbnRxbkNUKSB7CiAgICAgICAgICAgICAgICAgICAgLy8gT1RUVmd0RSBnZCBZdGJ1dENsVEMgKGRuIHdUeGRud1QgVnVFVCBHbm5zIGRuIHp2diUpCiAgICAgICAgICAgICAgICAgICAgeFRkSGdzVG5ZZChCWXQ3ZGdudCAoKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIC8vIC4uLiB1dEMgd1R4VGRkZ3RFIGRiVCB4N3VsVCB1QmRUdyAwd25veFR3IHVDMVl4ZHggZ2R4IHg3dWxUCiAgICAgICAgICAgICAgICAgICAgICAgIFZDQk5nVG9Udy43WXd3VHRkUDd1bFROdWxZVCA9IFNNNUFXSUhfUDNBSU1fTkFJV007CiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICAgICAgYnV0Q2xUQyA9IEJ1bHhUOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgMHdUdU87CiAgICAgICAgfQogICAgfQoKICAgIC8vIDNIZUkgbncgcU1IQSBvZ2RibllkIHhiZ0JkCiAgICBnQiAoN3NDID09PSB6IHx8IDdzQyA9PT0gVSkgewogICAgICAgIHhvZ2Q3YiAoVGpkLk9UazNuQ1QpIHsKICAgICAgICAgICAgN3V4VCBVbTogLy8geAogICAgICAgICAgICAgICAgLy9LUzVOZ1RvVHdBVlZsZzd1ZGdudC5Dbm90bG51QygpOwogICAgICAgICAgICAgICAgYnV0Q2xUQyA9IGR3WVQ7CiAgICAgICAgICAgICAgICAwd1R1TzsKICAgICAgICB9CiAgICB9CgogICAgLy8gM0hlSStBSUggbncgOVZkZ250KzNuc3N1dEMKICAgIGdCICg3c0MgPT09IG0gfHwgN3NDID09PSB6dikgewogICAgICAgIHhvZ2Q3YiAoVGpkLk9UazNuQ1QpIHsKICAgICAgICAgICAgN3V4VCBVdjogLy8gVgogICAgICAgICAgICAgICAgS1M1TmdUb1R3QVZWbGc3dWRnbnQud1RRWVR4ZEt3VHhUdGR1ZGdudHFuQ1QoKTsKICAgICAgICAgICAgICAgIGJ1dENsVEMgPSBkd1lUOwogICAgICAgICAgICAgICAgMHdUdU87CiAgICAgICAgICAgIDd1eFQgYXo6IC8vIEUKICAgICAgICAgICAgICAgIC8vIEJuN1l4VHggZ3RWWWQjVnVFVDZZczBUdyBCZ1RsQwogICAgICAgICAgICAgICAgQ243WXNUdGQuRVRkTWxUc1R0ZEZrZkMoJ1Z1RVQ2WXMwVHcnKS54VGxUN2QoKTsKICAgICAgICAgICAgICAgIGJ1dENsVEMgPSBkd1lUOwogICAgICAgICAgICAgICAgMHdUdU87CiAgICAgICAgfQogICAgfQoKICAgIGdCIChidXRDbFRDKSB7CiAgICAgICAgVGpkLlZ3VGpUdGRTVEJ1WWxkKCk7CiAgICAgICAgd1RkWXd0OwogICAgfQoKICAgIC8vIFBuc1QgeGJud2Q3WWR4IHhibllsQyB0bmQgRVRkIGJ1dENsVEMgZ0IgdSA3bnRkd25sL2d0VllkIFRsVHNUdGQKICAgIC8vIGd4IHhUbFQ3ZFRDLgogICAganV3IDdZd01sVHNUdGQgPSBDbjdZc1R0ZC51N2RnalRNbFRzVHRkIHx8IENuN1lzVHRkLlFZVHdrUFRsVDdkbncoJzpCbjdZeCcpOwogICAganV3IDdZd01sVHNUdGRIdUU2dXNUID0gN1l3TWxUc1R0ZCAmJiA3WXdNbFRzVHRkLmR1RTZ1c1QuZG5XVlZUdzN1eFQoKTsKICAgIGdCICg3WXdNbFRzVHRkSHVFNnVzVCA9PT0gJ2Y2S1dIJyB8fAogICAgICAgICAgICA3WXdNbFRzVHRkSHVFNnVzVCA9PT0gJ0hNSkhBZU1BJyB8fAogICAgICAgICAgICA3WXdNbFRzVHRkSHVFNnVzVCA9PT0gJ1BNSU0zSCcpIHsKICAgICAgICAvLyBxdU9UIHhZd1QgZGJ1ZCBkYlQgeFQ3bnRDdXdrIGRubmwwdXcgZ3ggN2xueFRDIG9iVHQgTXg3dVZUIGd4IFZ3VHh4VEMuCiAgICAgICAgZ0IgKFRqZC5PVGszbkNUICE9PSBaYSkgeyAvLyAnTXg3JwogICAgICAgICAgICB3VGRZd3Q7CiAgICAgICAgfQogICAgfQogICAganV3IFR0eFl3VE5nVG9UdzVuN1l4VEMgPSBCdWx4VDsKCiAgICBnQiAoN3NDID09PSB2KSB7IC8vIHRuIDdudGR3bmwgT1RrIFZ3VHh4VEMgdWQgdWxsLgogICAgICAgIHhvZ2Q3YiAoVGpkLk9UazNuQ1QpIHsKICAgICAgICAgICAgN3V4VCBtVTogLy8gWVYgdXd3bm8KICAgICAgICAgICAgN3V4VCBtbTogLy8gVkUgWVYKICAgICAgICAgICAgN3V4VCBVOiAvLyAwdTdPeFZ1N1QKICAgICAgICAgICAgICAgIGdCICghZ3hOZ1RvVHdmdEt3VHhUdGR1ZGdudHFuQ1QgJiYKICAgICAgICAgICAgICAgICAgICAgICAgVkNCTmdUb1R3LjdZd3dUdGRQN3VsVE51bFlUICE9PSAnVnVFVC1CZ2QnKSB7CiAgICAgICAgICAgICAgICAgICAgMHdUdU87CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAvKiBndCBWd1R4VHRkdWRnbnQgc25DVCAqLwogICAgICAgICAgICAgICAgLyogQnVsbHggZGJ3bllFYiAqLwogICAgICAgICAgICA3dXhUIG1hOiAvLyBsVEJkIHV3d25vCiAgICAgICAgICAgICAgICAvLyBibndnR250ZHVsIHg3d25sbGd0RSBZeGd0RSB1d3dubyBPVGt4CiAgICAgICAgICAgICAgICBnQiAoVkNCTmdUb1R3Lmd4Mm53Z0dudGR1bFA3d25sbDB1d010dTBsVEMpIHsKICAgICAgICAgICAgICAgICAgICAwd1R1TzsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIC8qIEJ1bGx4IGRid25ZRWIgKi8KICAgICAgICAgICAgN3V4VCBhYzogLy8gJ08nCiAgICAgICAgICAgIDd1eFQgVXY6IC8vICdWJwogICAgICAgICAgICAgICAgS1M1TmdUb1R3QVZWbGc3dWRnbnQuVnVFVC0tOwogICAgICAgICAgICAgICAgYnV0Q2xUQyA9IGR3WVQ7CiAgICAgICAgICAgICAgICAwd1R1TzsKICAgICAgICAgICAgN3V4VCBaYTogLy8gVHg3IE9UawogICAgICAgICAgICAgICAgZ0IgKFBUN250Q3V3a0hubmwwdXcublZUdFRDKSB7CiAgICAgICAgICAgICAgICAgICAgUFQ3bnRDdXdrSG5ubDB1dy43bG54VCgpOwogICAgICAgICAgICAgICAgICAgIGJ1dENsVEMgPSBkd1lUOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgZ0IgKCFLUzVOZ1RvVHdBVlZsZzd1ZGdudC54WVZWbndkeGZ0ZFRFd3VkVEM1Z3RDICYmCiAgICAgICAgICAgICAgICAgICAgICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250LkJndENGdXcublZUdFRDKSB7CiAgICAgICAgICAgICAgICAgICAgS1M1TmdUb1R3QVZWbGc3dWRnbnQuQmd0Q0Z1dy43bG54VCgpOwogICAgICAgICAgICAgICAgICAgIGJ1dENsVEMgPSBkd1lUOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgMHdUdU87CiAgICAgICAgICAgIDd1eFQgaXY6IC8vIENub3QgdXd3bm8KICAgICAgICAgICAgN3V4VCBtaTogLy8gVkUgQ25vdAogICAgICAgICAgICA3dXhUIG1aOiAvLyB4VnU3VDB1dwogICAgICAgICAgICAgICAgZ0IgKCFneE5nVG9Ud2Z0S3dUeFR0ZHVkZ250cW5DVCAmJgogICAgICAgICAgICAgICAgICAgICAgICBWQ0JOZ1RvVHcuN1l3d1R0ZFA3dWxUTnVsWVQgIT09ICdWdUVULUJnZCcpIHsKICAgICAgICAgICAgICAgICAgICAwd1R1TzsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIC8qIEJ1bGx4IGRid25ZRWIgKi8KICAgICAgICAgICAgN3V4VCBtTDogLy8gd2dFYmQgdXd3bm8KICAgICAgICAgICAgICAgIC8vIGJud2dHbnRkdWwgeDd3bmxsZ3RFIFl4Z3RFIHV3d25vIE9Ua3gKICAgICAgICAgICAgICAgIGdCIChWQ0JOZ1RvVHcuZ3gybndnR250ZHVsUDd3bmxsMHV3TXR1MGxUQykgewogICAgICAgICAgICAgICAgICAgIDB3VHVPOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgLyogQnVsbHggZGJ3bllFYiAqLwogICAgICAgICAgICA3dXhUIGFpOiAvLyAnMScKICAgICAgICAgICAgN3V4VCBhVTogLy8gJ3QnCiAgICAgICAgICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5WdUVUKys7CiAgICAgICAgICAgICAgICBidXRDbFRDID0gZHdZVDsKICAgICAgICAgICAgICAgIDB3VHVPOwoKICAgICAgICAgICAgN3V4VCBtRDogLy8gYm5zVAogICAgICAgICAgICAgICAgZ0IgKGd4TmdUb1R3ZnRLd1R4VHRkdWRnbnRxbkNUIHx8IEtTNU5nVG9Ud0FWVmxnN3VkZ250LlZ1RVQgPiB6KSB7CiAgICAgICAgICAgICAgICAgICAgS1M1TmdUb1R3QVZWbGc3dWRnbnQuVnVFVCA9IHo7CiAgICAgICAgICAgICAgICAgICAgYnV0Q2xUQyA9IGR3WVQ7CiAgICAgICAgICAgICAgICAgICAgVHR4WXdUTmdUb1R3NW43WXhUQyA9IGR3WVQ7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAwd1R1TzsKICAgICAgICAgICAgN3V4VCBtYzogLy8gVHRDCiAgICAgICAgICAgICAgICBnQiAoZ3hOZ1RvVHdmdEt3VHhUdGR1ZGdudHFuQ1QgfHwgKEtTNU5nVG9Ud0FWVmxnN3VkZ250LlZDQlNuN1lzVHRkICYmCiAgICAgICAgICAgICAgICAgICAgICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250LlZ1RVQgPCBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5WdUVUeDNuWXRkKSkgewogICAgICAgICAgICAgICAgICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250LlZ1RVQgPSBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5WdUVUeDNuWXRkOwogICAgICAgICAgICAgICAgICAgIGJ1dENsVEMgPSBkd1lUOwogICAgICAgICAgICAgICAgICAgIFR0eFl3VE5nVG9UdzVuN1l4VEMgPSBkd1lUOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgMHdUdU87CgogICAgICAgICAgICA3dXhUIGFaOiAvLyAnYicKICAgICAgICAgICAgICAgIGdCICghZ3hOZ1RvVHdmdEt3VHhUdGR1ZGdudHFuQ1QpIHsKICAgICAgICAgICAgICAgICAgICAydXRDSG5ubC5kbkVFbFQoKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIDB3VHVPOwogICAgICAgICAgICA3dXhUIFVaOiAvLyAndycKICAgICAgICAgICAgICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250LnduZHVkVEt1RVR4KEx2KTsKICAgICAgICAgICAgICAgIDB3VHVPOwogICAgICAgICAgICA3dXhUIGlEIDoKICAgICAgICAgICAgICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250LkNUbFRkVFNuN1lzVHRkQXR0bmR1ZGdudCgpOwogICAgICAgICAgICAgICAgMHdUdU87CiAgICAgICAgfQoKICAgIH0KCiAgICBnQiAoN3NDID09PSBpKSB7IC8vIHhiZ0JkLU9UawogICAgICAgIHhvZ2Q3YiAoVGpkLk9UazNuQ1QpIHsKICAgICAgICAgICAgN3V4VCBtWjogLy8geFZ1N1QwdXcKICAgICAgICAgICAgICAgIGdCICghZ3hOZ1RvVHdmdEt3VHhUdGR1ZGdudHFuQ1QgJiYKICAgICAgICAgICAgICAgICAgICAgICAgVkNCTmdUb1R3LjdZd3dUdGRQN3VsVE51bFlUICE9PSAnVnVFVC1CZ2QnKSB7CiAgICAgICAgICAgICAgICAgICAgMHdUdU87CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5WdUVULS07CiAgICAgICAgICAgICAgICBidXRDbFRDID0gZHdZVDsKICAgICAgICAgICAgICAgIDB3VHVPOwoKICAgICAgICAgICAgN3V4VCBVWjogLy8gJ3cnCiAgICAgICAgICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC53bmR1ZFRLdUVUeCgtTHYpOwogICAgICAgICAgICAgICAgMHdUdU87CiAgICAgICAgfQogICAgfQoKICAgIGdCICghYnV0Q2xUQyAmJiAhZ3hOZ1RvVHdmdEt3VHhUdGR1ZGdudHFuQ1QpIHsKICAgICAgICAvLyBtbT1LdUVUIFdWICBtaT1LdUVUIFNub3QgIG1jPU10QyAgICBtRD0ybnNUCiAgICAgICAgLy8gbWE9SVRCZCAgICAgbVU9V1YgICAgICAgICBtTD1lZ0ViZCAgaXY9U25vdAogICAgICAgIC8vIG1aPVBWdTdUMHV3CiAgICAgICAgZ0IgKChUamQuT1RrM25DVCA+PSBtbSAmJiBUamQuT1RrM25DVCA8PSBpdikgfHwKICAgICAgICAgICAgICAgIChUamQuT1RrM25DVCA9PT0gbVogJiYgN1l3TWxUc1R0ZEh1RTZ1c1QgIT09ICdGV0hIOTYnKSkgewogICAgICAgICAgICBUdHhZd1ROZ1RvVHc1bjdZeFRDID0gZHdZVDsKICAgICAgICB9CiAgICB9CgogICAgZ0IgKDdzQyA9PT0gWikgeyAvLyB1bGQtT1RrCiAgICAgICAgeG9nZDdiIChUamQuT1RrM25DVCkgewogICAgICAgICAgICA3dXhUIG1hOiAvLyBsVEJkIHV3d25vCiAgICAgICAgICAgICAgICBnQiAoZ3hOZ1RvVHdmdEt3VHhUdGR1ZGdudHFuQ1QpIHsKICAgICAgICAgICAgICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5WQ0IyZ3hkbndrLjB1N08oKTsKICAgICAgICAgICAgICAgICAgICBidXRDbFRDID0gZHdZVDsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIDB3VHVPOwogICAgICAgICAgICA3dXhUIG1MOiAvLyB3Z0ViZCB1d3dubwogICAgICAgICAgICAgICAgZ0IgKGd4TmdUb1R3ZnRLd1R4VHRkdWRnbnRxbkNUKSB7CiAgICAgICAgICAgICAgICAgICAgS1M1TmdUb1R3QVZWbGc3dWRnbnQuVkNCMmd4ZG53ay5CbndvdXdDKCk7CiAgICAgICAgICAgICAgICAgICAgYnV0Q2xUQyA9IGR3WVQ7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAwd1R1TzsKICAgICAgICB9CiAgICB9CgogICAgZ0IgKFR0eFl3VE5nVG9UdzVuN1l4VEMgJiYgIVZDQk5nVG9Udy43bnRkdWd0eE1sVHNUdGQoN1l3TWxUc1R0ZCkpIHsKICAgICAgICAvLyBIYlQgVnVFVCA3bnRkdWd0VHcgZ3ggdG5kIEJuN1l4VEMsIDBZZCB1IFZ1RVQgdHVqZ0V1ZGdudCBPVGsgYnV4IDBUVHQKICAgICAgICAvLyBWd1R4eFRDLiAzYnV0RVQgZGJUIEJuN1l4IGRuIGRiVCBqZ1RvVHcgN250ZHVndFR3IGRuIHN1T1QgeFl3VCBkYnVkCiAgICAgICAgLy8gdHVqZ0V1ZGdudCAwayBPVGswbnV3QyBvbndPeCB1eCBUclZUN2RUQy4KICAgICAgICBWQ0JOZ1RvVHcuQm43WXgoKTsKICAgIH0KCiAgICBnQiAoYnV0Q2xUQykgewogICAgICAgIFRqZC5Wd1RqVHRkU1RCdVlsZCgpOwogICAgfQp9KTsKCm9ndENuby51Q0NNalR0ZElneGRUdFR3KCcwVEJud1RWd2d0ZCcsIEJZdDdkZ250IDBUQm53VEt3Z3RkKFRqZCkgewogICAgCiAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC4wVEJud1RLd2d0ZCgpOwogICAgICQudTF1cih7CiAgICAgICAgICAgIHV4a3Q3OiBCdWx4VCwKICAgICAgICAgICAgZGtWVDogIks5UEgiLAogICAgICAgICAgICBZd2w6ICJDc3gvVndndGRJbkUuVmJWP0NuN1lzVHRkZ0M9PD9WYlYgVDdibiAkd1Q3bndDX0NUZHVnbHhbdl1bJ2dDJ107ID8+JlZnQz08P1ZiViBUN2JuICRWZ0M7ID8+Jjd1ZF9nQz08P1ZiViBUN2JuICR3VDdud0NfQ1RkdWdseFt2XVsnN3VkVEVud2tfZ0MnXTsgPz4mQ243dHVzVD08P1ZiViBUN2JuICR3VDdud0NfQ1RkdWdseFt2XVsnZGdkbFQnXTsgPz4iLAogICAgICAgICAgICB4WTc3VHh4OiBCWXQ3ZGdudCAod1R4Vm50eFQpIHsKICAgICAgICAgICAgICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250LmxudUNTbjdZc1R0ZDZuZFR4KCk7Ci8vICAgICAgICAgICAgICAgICA3bnR4bmxULmxuRSh3VHhWbnR4VCk7CiAgICAgICAgICAgICAgICAvL3VsVHdkKHdUeFZudHhUKTsKICAgICAgICAgICAgfSwKICAgICAgICAgICAgVHd3bnc6IEJZdDdkZ250ICgxUUoyZSwgVHI3VFZkZ250KSB7CiAgICAgICAgICAgICAgICAgN250eG5sVC5sbkUoIjZuIFZ3Z3RkIik7CiAgICAgICAgICAgICAgICAvLyQoIiN3VHhZbGQ2bmRUeCIpLmJkc2woIld0dTBsVCBkbiBsbnVDIHRuZFR4Iik7CiAgICAgICAgICAgIH0KICAgICAgICB9KTsKfSk7CgpvZ3RDbm8udUNDTWpUdGRJZ3hkVHRUdygndUJkVHdWd2d0ZCcsIEJZdDdkZ250IHVCZFR3S3dndGQoVGpkKSB7CiAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC51QmRUd0t3Z3RkKCk7Cn0pOwoKKEJZdDdkZ250IHV0Z3N1ZGdudFBkdXdkVEMzbG54WXdUKCkgewogICAgLy8gSGJUIG5CQnhUZEt1d1R0ZCBneCB0bmQgeFRkIFl0ZGdsIGRiVCBWQ0IuMXggZ0J3dXNUIG53IG4wMVQ3ZCBneCBqZ3hnMGxULgogICAgLy8gOHVnZGd0RSBCbncgQmd3eGQgdXRnc3VkZ250LgogICAgS1M1TmdUb1R3QVZWbGc3dWRnbnQudXRnc3VkZ250UGR1d2RUQ0t3bnNneFQgPSB0VG8gS3duc2d4VCgKICAgICAgICAgICAgQll0N2RnbnQgKHdUeG5salQpIHsKICAgICAgICAgICAgICAgIG9ndENuby53VFFZVHhkQXRnc3VkZ250NXd1c1Qod1R4bmxqVCk7CiAgICAgICAgICAgIH0pOwp9KSgpOwoKCiQoQ243WXNUdGQpLm50KCI3bGc3TyIsICcuQ1RsVGRUdG5kVCcsIEJZdDdkZ250IChUalR0ZCkgewogICAganV3IHRuZFRmQyA9ICQoZGJneCkudWRkdygndG5kVGdDJyk7CiAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5DVGxUZFQzbnRCZ3dzdWRnbnRLd25zVmQublZUdCh0bmRUZkMpOwp9KTsKCiQoQ243WXNUdGQpLm50KCI3bGc3TyIsICcudXR0eFRsVDdkbncnLCBCWXQ3ZGdudCAoVGpUdGQpIHsKICAgIC8vWXR4VGxUN2QgdWxsIHV0dG5kdWRnbnR4IEJnd3hkCiAgICBCbncgKGp1dyBnID0gdjsgZyA8IEtTNU5nVG9Ud0FWVmxnN3VkZ250LkNuN1lzVHRkQXR0bmR1ZGdudHgubFR0RWRiOyBnKyspIHsKICAgICAgICBqdXcgdXR0ID0gS1M1TmdUb1R3QVZWbGc3dWRnbnQuQ243WXNUdGRBdHRuZHVkZ250eFtnXTsKICAgICAgICB1dHQueFRsVDdkVEMgPSBCdWx4VDsKICAgIH0KICAgIGp1dyBkVHNWQXR0bmR1ZGdudGZDID0gJChkYmd4KS51ZGR3KCdkVHNWdXR0bmR1ZGdudGdDJyk7CiAgICBCbncgKGp1dyBnID0gdjsgZyA8IEtTNU5nVG9Ud0FWVmxnN3VkZ250LkNuN1lzVHRkQXR0bmR1ZGdudHgubFR0RWRiOyBnKyspIHsKICAgICAgICBqdXcgdXR0ID0gS1M1TmdUb1R3QVZWbGc3dWRnbnQuQ243WXNUdGRBdHRuZHVkZ250eFtnXTsKICAgICAgICBnQiAoZFRzVkF0dG5kdWRnbnRmQyA9PSB1dHQuZFRzVmZDKSB7CiAgICAgICAgICAgIHV0dC54VGxUN2RUQyA9IGR3WVQ7CiAgICAgICAgICAgIEtTNU5nVG9Ud0FWVmxnN3VkZ250LlZDQk5nVG9Udy54N3dubGxLdUVUZnRkbk5nVG8odXR0LlZ1RVRmQyk7CiAgICAgICAgICAgIDB3VHVPOwogICAgICAgIH0KICAgIH0KICAgIEJudyAoanV3IFZ1RVQ2WXMwVHcgPSB2OyBWdUVUNllzMFR3IDwgS1M1TmdUb1R3QVZWbGc3dWRnbnQuVkNCTmdUb1R3LlZ1RVR4M25ZdGQ7IFZ1RVQ2WXMwVHcrKykgewogICAgICAgIGp1dyBWdUVUTmdUbyA9IEtTNU5nVG9Ud0FWVmxnN3VkZ250LlZDQk5nVG9Udy5FVGRLdUVUTmdUbyhWdUVUNllzMFR3KTsKICAgICAgICBLUzVOZ1RvVHdBVlZsZzd1ZGdudC5Dd3VvU243WXNUdGRBdHRuZHVkZ250eChWdUVUTmdUbywgVnVFVE5nVG8uN250ZFRyZCwgVnVFVDZZczBUdyArIHopOwogICAgfQoKfSk7CkJZdDdkZ250IEVUZDNZd3dUdGRTdWRUKCkgewogICAganV3IHNfdHVzVHggPSB0VG8gQXd3dWsoInl1dCIsICI1VDAiLCAicXV3IiwgIkFWdyIsICJxdWsiLCAieVl0IiwgInlZbCIsICJBWUUiLCAiUFRWIiwgIjk3ZCIsICI2bmoiLCAiU1Q3Iik7CiAgICBqdXcgQyA9IHRUbyBTdWRUKCk7CiAgICBqdXcgN1l3d19DdWRUID0gQy5FVGRTdWRUKCk7CiAgICBqdXcgN1l3d19zbnRkYiA9IEMuRVRkcW50ZGIoKTsKICAgIGp1dyA3WXd3X2tUdXcgPSBDLkVUZDVZbGw0VHV3KCk7CiAgICBqdXcgN1l3d19ibll3ID0gQy5FVGQybll3eCgpOwogICAganV3IDdZd3dfc2d0WWRUeCA9IEMuRVRkcWd0WWRUeCgpOwogICAganV3IDdZd3dUdGRTdWRUID0gN1l3d19DdWRUICsgIi0iICsgc190dXNUeFs3WXd3X3NudGRiXSArICItIiArIDdZd3dfa1R1dyArICIgIiArIDdZd3dfYm5ZdyArICI6IiArIDdZd3dfc2d0WWRUeDsKICAgIHdUZFl3dCA3WXd3VHRkU3VkVDsKfQoKQll0N2RnbnQgRVRkM1l3d1R0ZFN1ZFQ5dGxrKCkgewogICAganV3IHNfdHVzVHggPSB0VG8gQXd3dWsoInl1dCIsICI1VDAiLCAicXV3IiwgIkFWdyIsICJxdWsiLCAieVl0IiwgInlZbCIsICJBWUUiLCAiUFRWIiwgIjk3ZCIsICI2bmoiLCAiU1Q3Iik7CiAgICBqdXcgQyA9IHRUbyBTdWRUKCk7CiAgICBqdXcgN1l3d19DdWRUID0gQy5FVGRTdWRUKCk7CiAgICBqdXcgN1l3d19zbnRkYiA9IEMuRVRkcW50ZGIoKTsKICAgIGp1dyA3WXd3X2tUdXcgPSBDLkVUZDVZbGw0VHV3KCk7CiAgICBqdXcgN1l3d19ibll3ID0gQy5FVGQybll3eCgpOwogICAganV3IDdZd3dfc2d0WWRUeCA9IEMuRVRkcWd0WWRUeCgpOwogICAganV3IDdZd3dUdGRTdWRUID0gN1l3d19DdWRUICsgIi0iICsgc190dXNUeFs3WXd3X3NudGRiXSArICItIiArIDdZd3dfa1R1dzsKICAgIHdUZFl3dCA3WXd3VHRkU3VkVDsKfQoKQll0N2RnbnQgRVRkM1l3d1R0ZEhnc1QoKSB7CiAgICBqdXcgc190dXNUeCA9IHRUbyBBd3d1aygieXV0IiwgIjVUMCIsICJxdXciLCAiQVZ3IiwgInF1ayIsICJ5WXQiLCAieVlsIiwgIkFZRSIsICJQVFYiLCAiOTdkIiwgIjZuaiIsICJTVDciKTsKICAgIGp1dyBDID0gdFRvIFN1ZFQoKTsKICAgIGp1dyA3WXd3X0N1ZFQgPSBDLkVUZFN1ZFQoKTsKICAgIGp1dyA3WXd3X3NudGRiID0gQy5FVGRxbnRkYigpOwogICAganV3IDdZd3dfa1R1dyA9IEMuRVRkNVlsbDRUdXcoKTsKICAgIGp1dyA3WXd3X2JuWXcgPSBDLkVUZDJuWXd4KCk7CiAgICBqdXcgN1l3d19zZ3RZZFR4ID0gQy5FVGRxZ3RZZFR4KCk7CiAgICBqdXcgN1l3d1R0ZEhnc1QgPSA3WXd3X2JuWXcgKyAiOiIgKyA3WXd3X3NndFlkVHg7CiAgICB3VGRZd3QgN1l3d1R0ZEhnc1Q7Cn0KCkJZdDdkZ250IGxuRSh1dHQpIHsKICAgIDdudHhubFQubG5FKCJKeiA6ICIgKyB1dHQucnogKyAiIDR6IDogIiArIHV0dC5reiArICIgSlogOiAiICsgdXR0LnJaICsgIiA0WiA6ICIgKyB1dHQua1opOwp9CiQoQ243WXNUdGQpLndUdUNrKEJZdDdkZ250ICgpIHsKICAgIC8vU2d4dTBsVCA3WWQgN25WayBWdXhkVAogICAgLyokKCcwbkNrJykuMGd0QygnN1lkIDduVmsgVnV4ZFQnLCBCWXQ3ZGdudCAoVCkgewogICAgICAgIFQuVndUalR0ZFNUQnVZbGQoKTsKICAgIH0pOyovCiAgICAvL1NneHUwbFQgc25ZeFQgd2dFYmQgN2xnN08KICAgICQoIjBuQ2siKS5udCgiN250ZFRyZHNUdFkiLCBCWXQ3ZGdudCAoVCkgewogICAgICAgIHdUZFl3dCBCdWx4VDsKICAgIH0pOwp9KTsKJChDbjdZc1R0ZCkud1R1Q2soQll0N2RnbnQgKCkgewogICAgJCgiMG5DayIpLjd4eCgiLW9UME9nZC1ZeFR3LXhUbFQ3ZCIsICJ0bnRUIik7CiAgICAkKCIwbkNrIikuN3h4KCItc25HLVl4VHcteFRsVDdkIiwgInRudFQiKTsKICAgICQoIjBuQ2siKS43eHgoIi1zeC1ZeFR3LXhUbFQ3ZCIsICJ0bnRUIik7CiAgICAkKCIwbkNrIikuN3h4KCItbi1ZeFR3LXhUbFQ3ZCIsICJ0bnRUIik7CiAgICAkKCIwbkNrIikuN3h4KCJZeFR3LXhUbFQ3ZCIsICJ0bnRUIik7CiAgICAKICAgICBDbjdZc1R0ZC51Q0NNalR0ZElneGRUdFR3KCdTOXEzbnRkVHRkSW51Q1RDJywgQll0N2RnbnQoKSB7CiAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICBDbjdZc1R0ZC5FVGRNbFRzVHRkRmtmQygnQmd0QzZUcmRGWWRkbnQnKS43bGc3TygpOwogICAgICAgICAgICAgICAgICAgICAgICB9LCBCdWx4VCk7Cn0pOwoKICAgIAogICAgPC94N3dnVmQ+CiAgICAKICAgICAgICAgICAgPC9iVHVDPgogICAgICAgICAgICAKICAgICAgICAgICAgPDBuQ2sgZHUwZ3RDVHI9InoiIDdsdXh4PSJsbnVDZ3RFZnRLd25Fd1R4eCI+CiAKICAgICAgICAgICAgICAgIDxDZ2ogZ0M9Im5ZZFR3M250ZHVndFR3IiA+CiAgICAgICAgICAgICAgICAgICAgPENnaiBnQz0ieGdDVDB1dzNudGR1Z3RUdyI+CiAgICAgICAgICAgICAgICAgICAgICAgIDxDZ2ogZ0M9ImRubmwwdXdQZ0NUMHV3Ij4KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxDZ2ogN2x1eHg9InhWbGdkSG5ubDB1d0ZZZGRudCBkbkVFbFRDIj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8MFlkZG50IGdDPSJqZ1RvSGJZczB0dWdsIiA3bHV4eD0iZG5ubDB1d0ZZZGRudCBFd25ZViBkbkVFbFRDIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGdkbFQ9IlBibm8gSGJZczB0dWdseCIgZHUwZ3RDVHI9IloiIEN1ZHUtbHp2dC1nQz0iZGJZczB4Ij4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHhWdXQgQ3VkdS1senZ0LWdDPSJkYllzMHhfbHUwVGwiPkhiWXMwdHVnbHg8L3hWdXQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC8wWWRkbnQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPDBZZGRudCBnQz0iamdUbzZuZFR4IiA3bHV4eD0iZG5ubDB1d0ZZZGRudCBFd25ZViIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRnZGxUPSJQYm5vIFNuN1lzVHRkIDZuZFR4IiBkdTBndENUcj0ibSIgPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8eFZ1dD5TbjdZc1R0ZCA2bmRUeDwveFZ1dD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8LzBZZGRudD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8MFlkZG50IGdDPSJqZ1RvQXR0bmR1ZGdudHgiIDdsdXh4PSJkbm5sMHV3RllkZG50IEV3bllWIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGdkbFQ9IlNuN1lzVHRkIEF0dG5kdWRnbnR4IiBkdTBndENUcj0iaSIgPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8eFZ1dD5TbjdZc1R0ZCBBdHRuZHVkZ250eDwveFZ1dD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8LzBZZGRudD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8MFlkZG50IGdDPSJqZ1RvOVlkbGd0VCIgN2x1eHg9ImRubmwwdXdGWWRkbnQgRXduWVYiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZ2RsVD0iUGJubyBTbjdZc1R0ZCA5WWRsZ3RUIiBkdTBndENUcj0iYyIgQ3VkdS1senZ0LWdDPSJuWWRsZ3RUIj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHhWdXQgQ3VkdS1senZ0LWdDPSJuWWRsZ3RUX2x1MFRsIj5TbjdZc1R0ZCA5WWRsZ3RUPC94VnV0PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvMFlkZG50PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwwWWRkbnQgZ0M9ImpnVG9BZGR1N2JzVHRkeCIgN2x1eHg9ImRubmwwdXdGWWRkbnQgRXduWVYiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZ2RsVD0iUGJubyBBZGR1N2JzVHRkeCIgZHUwZ3RDVHI9IkQiIEN1ZHUtbHp2dC1nQz0idWRkdTdic1R0ZHgiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8eFZ1dCBDdWR1LWx6dnQtZ0M9InVkZHU3YnNUdGR4X2x1MFRsIj5BZGR1N2JzVHRkeDwveFZ1dD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8LzBZZGRudD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvQ2dqPgogICAgICAgICAgICAgICAgICAgICAgICA8L0Nnaj4KICAgICAgICAgICAgICAgICAgICAgICAgPENnaiBnQz0ieGdDVDB1dzNudGRUdGQiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgPENnaiBnQz0iZGJZczB0dWdsTmdUbyI+PC9DZ2o+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Q2dqIGdDPSJ0bmRUeE5nVG8iIDdsdXh4PSJiZ0NDVHQiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxDZ2ogZ0M9InRuZFR4NW53cyI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxCbndzIHU3ZGdudD0iQ3N4L0NuN1lzVHRkdG5kVHguVmJWIiBnQz0iQndzNm5kVHgiIHNUZGJuQz0iVm54ZCI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Z3RWWWQgZGtWVD0id3VDZ24iIHR1c1Q9Ind1QzZuZFRIa1ZUIiBqdWxZVD0iSyIgN2JUN09UQy8+PHhWdXQgN2x1eHg9ImRubmwwdXdJdTBUbCIgPktZMGxnNyAmdDB4Vjs8L3hWdXQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Z3RWWWQgZGtWVD0id3VDZ24iIHR1c1Q9Ind1QzZuZFRIa1ZUIiBqdWxZVD0iVyIvPjx4VnV0IDdsdXh4PSJkbm5sMHV3SXUwVGwiPkt3Z2p1ZFQ8L3hWdXQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZFRyZHV3VHUgd25veD0iYyIgdHVzVD0iZHJkNm5kVCIgZ0M9ImRyZDZuZFQiIDdsdXh4PSJkbm5sMHV3NWdUbEMiIFZsdTdUYm5sQ1R3PSJNdGRUdyB0bmRUIC8gN25zc1R0ZCI+PC9kVHJkdXdUdT48MHcvPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGd0VllkIGRrVlQ9ImJnQ0NUdCIgdHVzVD0iQ243WXNUdGRnQyIgZ0M9IkNuN1lzVHRkZ0MiIGp1bFlUPSI8P1ZiViBUN2JuICRnQzsgPz4iLz4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxndFZZZCBka1ZUPSJiZ0NDVHQiIHR1c1Q9IndUamd4Z250Z0MiIGdDPSJ3VGpneGdudGdDIiBqdWxZVD0iIi8+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Z3RWWWQgZGtWVD0iYmdDQ1R0IiB0dXNUPSJZeFR3X2dDIiBnQz0iWXhUd19nQyIganVsWVQ9Ijw/VmJWIFQ3Ym4gJF9QTVBQZjk2W1BNUFBmOTZfTkFlXzZBcU1dWydZeFR3X2dDJ107ID8+Ii8+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Z3RWWWQgZGtWVD0iYmdDQ1R0IiB0dXNUPSJZeFR3dHVzVCIgZ0M9Ill4VHd0dXNUIiBqdWxZVD0iPD9WYlYgVDdibiAkX1BNUFBmOTZbUE1QUGY5Nl9OQWVfNkFxTV1bJ0J0dXNUJ10gLiAnICcgLiAkX1BNUFBmOTZbUE1QUGY5Nl9OQWVfNkFxTV1bJ3N0dXNUJ10gLiAnICcgLiAkX1BNUFBmOTZbUE1QUGY5Nl9OQWVfNkFxTV1bJ2x0dXNUJ107ID8+Ii8+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Z3RWWWQgZGtWVD0ieFkwc2dkIiA3bHV4eD0ibmpUd2x1a0ZZZGRudCIgZ0M9Inh1alR0bmRUIiBqdWxZVD0iUHVqVCA2bmRUIj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9CbndzPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvQ2dqPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxDZ2ogZ0M9IndUeFlsZDZuZFR4Ij48L0Nnaj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvQ2dqPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgPENnaiBnQz0idXR0bmR1ZGdudHhOZ1RvIiAgN2x1eHg9ImJnQ0NUdCI+PC9DZ2o+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Q2dqIGdDPSJuWWRsZ3RUTmdUbyIgN2x1eHg9ImJnQ0NUdCI+PC9DZ2o+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Q2dqIGdDPSJ1ZGR1N2JzVHRkeE5nVG8iIDdsdXh4PSJiZ0NDVHQiPjwvQ2dqPgogICAgICAgICAgICAgICAgICAgICAgICA8L0Nnaj4KICAgICAgICAgICAgICAgICAgICA8L0Nnaj4KICAgICAgICAgICAgICAgICAgICA8IS0tIHhnQ1QwdXczbnRkdWd0VHcgLS0+CgogICAgICAgICAgICAgICAgICAgIDxDZ2ogZ0M9InN1Z3QzbnRkdWd0VHciPgogICAgICAgICAgICAgICAgICAgICAgICA8Q2dqIDdsdXh4PSJCZ3RDMHV3IGJnQ0NUdCBDbm53MnV0RVR3IGJnQ0NUdFBzdWxsTmdUbyIgZ0M9IkJndEMwdXciPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgPGx1MFRsIEJudz0iQmd0Q2Z0VllkIiA3bHV4eD0iZG5ubDB1d0l1MFRsIiBDdWR1LWx6dnQtZ0M9IkJndENfbHUwVGwiPjVndEM6PC9sdTBUbD4gCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Z3RWWWQgZ0M9IkJndENmdFZZZCIgN2x1eHg9ImRubmwwdXc1Z1RsQyIgZHUwZ3RDVHI9Ikx6IiBqdWxZVD0iQkJCQiI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Q2dqIDdsdXh4PSJ4VmxnZEhubmwwdXdGWWRkbnQiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwwWWRkbnQgN2x1eHg9ImRubmwwdXdGWWRkbnQgQmd0Q0t3VGpnbll4IiBkZ2RsVD0iIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ0M9IkJndENLd1RqZ25ZeCIgZHUwZ3RDVHI9IkxaIiBDdWR1LWx6dnQtZ0M9IkJndENfVndUamduWXgiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8eFZ1dCBDdWR1LWx6dnQtZ0M9IkJndENfVndUamduWXhfbHUwVGwiPkt3VGpnbll4PC94VnV0PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvMFlkZG50PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxDZ2ogN2x1eHg9InhWbGdkSG5ubDB1d0ZZZGRudFBUVnV3dWRudyI+PC9DZ2o+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPDBZZGRudCA3bHV4eD0iZG5ubDB1d0ZZZGRudCBCZ3RDNlRyZCIgZGdkbFQ9IiIgZ0M9IkJndEM2VHJkIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHUwZ3RDVHI9IkxtIiBDdWR1LWx6dnQtZ0M9IkJndENfdFRyZCI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx4VnV0IEN1ZHUtbHp2dC1nQz0iQmd0Q190VHJkX2x1MFRsIj42VHJkPC94VnV0PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvMFlkZG50PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9DZ2o+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Z3RWWWQgZGtWVD0iN2JUN08wbnIiIGdDPSJCZ3RDMmdFYmxnRWJkQWxsIiA3bHV4eD0iZG5ubDB1dzVnVGxDIiA3YlQ3T1RDCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHUwZ3RDVHI9IkxpIj4gPGx1MFRsIEJudz0iQmd0QzJnRWJsZ0ViZEFsbCIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA3bHV4eD0iZG5ubDB1d0l1MFRsIiBDdWR1LWx6dnQtZ0M9IkJndENfYmdFYmxnRWJkIj4yZ0VibGdFYmQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bGw8L2x1MFRsPiA8Z3RWWWQgZGtWVD0iN2JUN08wbnIiIGdDPSJCZ3RDcXVkN2IzdXhUIiA3bHV4eD0iZG5ubDB1dzVnVGxDIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR1MGd0Q1RyPSJMYyI+IDxsdTBUbCBCbnc9IkJndENxdWQ3YjN1eFQiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgN2x1eHg9ImRubmwwdXdJdTBUbCIgQ3VkdS1senZ0LWdDPSJCZ3RDX3N1ZDdiXzd1eFRfbHUwVGwiPnF1ZDdiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgN3V4VDwvbHUwVGw+IDx4VnV0IGdDPSJCZ3RDcXhFIiA3bHV4eD0iZG5ubDB1d0l1MFRsIj48L3hWdXQ+CiAgICAgICAgICAgICAgICAgICAgICAgIDwvQ2dqPgogICAgICAgICAgICAgICAgICAgICAgICA8IS0tIEJndEMwdXcgLS0+CgogICAgICAgICAgICAgICAgICAgICAgICA8Q2dqIGdDPSJ4VDdudEN1d2tIbm5sMHV3IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgIDdsdXh4PSJ4VDdudEN1d2tIbm5sMHV3IGJnQ0NUdCBDbm53MnV0RVR3ZWdFYmQiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgPENnaiBnQz0ieFQ3bnRDdXdrSG5ubDB1d0ZZZGRudDNudGR1Z3RUdyI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPDBZZGRudCBnQz0ieFQ3bnRDdXdrS3dUeFR0ZHVkZ250cW5DVCIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDdsdXh4PSJ4VDdudEN1d2tIbm5sMHV3RllkZG50IFZ3VHhUdGR1ZGdudHFuQ1Qgamd4ZzBsVEl1d0VUTmdUbyIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRnZGxUPSJQb2dkN2IgZG4gS3dUeFR0ZHVkZ250IHFuQ1QiIGR1MGd0Q1RyPSJjeiIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEN1ZHUtbHp2dC1nQz0iVndUeFR0ZHVkZ250X3NuQ1QiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8eFZ1dCBDdWR1LWx6dnQtZ0M9IlZ3VHhUdGR1ZGdudF9zbkNUX2x1MFRsIj5Ld1R4VHRkdWRnbnQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHFuQ1Q8L3hWdXQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC8wWWRkbnQ+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwwWWRkbnQgZ0M9InhUN250Q3V3azlWVHQ1Z2xUIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgN2x1eHg9InhUN250Q3V3a0hubmwwdXdGWWRkbnQgblZUdDVnbFQgamd4ZzBsVEl1d0VUTmdUbyAiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZ2RsVD0iOVZUdCA1Z2xUIiBkdTBndENUcj0iY1oiIEN1ZHUtbHp2dC1nQz0iblZUdF9CZ2xUIj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHhWdXQgQ3VkdS1senZ0LWdDPSJuVlR0X0JnbFRfbHUwVGwiPjlWVHQ8L3hWdXQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC8wWWRkbnQ+CiA8P1ZiVgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnQiAoZ3RfdXd3dWsoJ20nLCAkVlR3X0NUZHVnbHgpIHx8IGd0X3V3d3VrKCdEJywgJFZUd19DVGR1Z2x4KSB8fCAkQ243eFRkX1Z3Z3RkX0JsdUUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID8+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPDBZZGRudCBnQz0ieFQ3bnRDdXdrS3dndGQiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA3bHV4eD0ieFQ3bnRDdXdrSG5ubDB1d0ZZZGRudCBWd2d0ZCBqZ3hnMGxUcVRDZ1lzTmdUbyAgIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGdkbFQ9Ikt3Z3RkIiBkdTBndENUcj0iY20iIEN1ZHUtbHp2dC1nQz0iVndndGQiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8eFZ1dCBDdWR1LWx6dnQtZ0M9IlZ3Z3RkX2x1MFRsIj5Ld2d0ZDwveFZ1dD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8LzBZZGRudD4KICAgICA8P1ZiVgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID8+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDw/VmJWCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdCIChndF91d3d1aygnWicsICRWVHdfQ1RkdWdseCkgfHwgZ3RfdXd3dWsoJ0QnLCAkVlR3X0NUZHVnbHgpIHx8ICRDbjd4VGRfQ25vdGxudUNfQmx1RSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPz4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8MFlkZG50IGdDPSJ4VDdudEN1d2tTbm90bG51QyIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDdsdXh4PSJ4VDdudEN1d2tIbm5sMHV3RllkZG50IENub3RsbnVDIGpneGcwbFRxVENnWXNOZ1RvIENub3RsbnVDX3NrIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGdkbFQ9IlNub3RsbnVDIiBkdTBndENUcj0iY2kiIEN1ZHUtbHp2dC1nQz0iQ25vdGxudUMiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8eFZ1dCBDdWR1LWx6dnQtZ0M9IkNub3RsbnVDX2x1MFRsIj5Tbm90bG51QzwveFZ1dD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8LzBZZGRudD4KIDw/VmJWCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPz4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHUgYndUQj0iIyIgZ0M9InhUN250Q3V3a05nVG9Gbm5Pc3V3TyIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA3bHV4eD0ieFQ3bnRDdXdrSG5ubDB1d0ZZZGRudCAwbm5Pc3V3TyBqZ3hnMGxUUHN1bGxOZ1RvICAiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGdkbFQ9IjNZd3dUdGQgamdUbyAoN25WayBudyBuVlR0IGd0IHRUbyBvZ3RDbm8pIiBkdTBndENUcj0iY2MiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ3VkdS1senZ0LWdDPSIwbm5Pc3V3TyI+IDx4VnV0IEN1ZHUtbHp2dC1nQz0iMG5uT3N1d09fbHUwVGwiPjNZd3dUdGQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5nVG88L3hWdXQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC91PgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Q2dqIDdsdXh4PSJibndnR250ZHVsSG5ubDB1d1BUVnV3dWRudyBqZ3hnMGxUSXV3RVROZ1RvIj48L0Nnaj4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPDBZZGRudCBnQz0iQmd3eGRLdUVUIiA3bHV4eD0ieFQ3bnRDdXdrSG5ubDB1d0ZZZGRudCBCZ3d4ZEt1RVQiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZ2RsVD0icG4gZG4gNWd3eGQgS3VFVCIgZHUwZ3RDVHI9ImNEIiBDdWR1LWx6dnQtZ0M9IkJnd3hkX1Z1RVQiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8eFZ1dCBDdWR1LWx6dnQtZ0M9IkJnd3hkX1Z1RVRfbHUwVGwiPnBuIGRuIDVnd3hkIEt1RVQ8L3hWdXQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC8wWWRkbnQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPDBZZGRudCBnQz0ibHV4ZEt1RVQiIDdsdXh4PSJ4VDdudEN1d2tIbm5sMHV3RllkZG50IGx1eGRLdUVUIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGdkbFQ9InBuIGRuIEl1eGQgS3VFVCIgZHUwZ3RDVHI9ImNhIiBDdWR1LWx6dnQtZ0M9Imx1eGRfVnVFVCI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx4VnV0IEN1ZHUtbHp2dC1nQz0ibHV4ZF9WdUVUX2x1MFRsIj5wbiBkbiBJdXhkIEt1RVQ8L3hWdXQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC8wWWRkbnQ+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxDZ2ogN2x1eHg9ImJud2dHbnRkdWxIbm5sMHV3UFRWdXd1ZG53Ij48L0Nnaj4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPDBZZGRudCBnQz0iVnVFVGVuZHVkVDNvIiA3bHV4eD0ieFQ3bnRDdXdrSG5ubDB1d0ZZZGRudCB3bmR1ZFQzbyIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRnZGxUPSJlbmR1ZFQgM2xuN09vZ3hUIiBkdTBndENUcj0iY1UiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDdWR1LWx6dnQtZ0M9IlZ1RVRfd25kdWRUXzdvIj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHhWdXQgQ3VkdS1senZ0LWdDPSJWdUVUX3duZHVkVF83b19sdTBUbCI+ZW5kdWRUIDNsbjdPb2d4VDwveFZ1dD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8LzBZZGRudD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8MFlkZG50IGdDPSJWdUVUZW5kdWRUMzdvIiA3bHV4eD0ieFQ3bnRDdXdrSG5ubDB1d0ZZZGRudCB3bmR1ZFQzN28iCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZ2RsVD0iZW5kdWRUIDNuWXRkVHc3bG43T29neFQiIGR1MGd0Q1RyPSJjTCIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEN1ZHUtbHp2dC1nQz0iVnVFVF93bmR1ZFRfNzdvIj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHhWdXQgQ3VkdS1senZ0LWdDPSJWdUVUX3duZHVkVF83N29fbHUwVGwiPmVuZHVkVAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgM25ZdGRUdzdsbjdPb2d4VDwveFZ1dD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8LzBZZGRudD4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPENnaiA3bHV4eD0iYm53Z0dudGR1bEhubmwwdXdQVFZ1d3VkbnciPjwvQ2dqPgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8MFlkZG50IGdDPSJkbkVFbFQydXRDSG5ubCIgN2x1eHg9InhUN250Q3V3a0hubmwwdXdGWWRkbnQgYnV0Q0hubmwiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZ2RsVD0iTXR1MGxUIGJ1dEMgZG5ubCIgZHUwZ3RDVHI9IkR2IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ3VkdS1senZ0LWdDPSJidXRDX2RubmxfVHR1MGxUIj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHhWdXQgQ3VkdS1senZ0LWdDPSJidXRDX2RubmxfVHR1MGxUX2x1MFRsIj5NdHUwbFQgYnV0QwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZG5ubDwveFZ1dD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8LzBZZGRudD4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPENnaiA3bHV4eD0iYm53Z0dudGR1bEhubmwwdXdQVFZ1d3VkbnciPjwvQ2dqPgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8MFlkZG50IGdDPSJDbjdZc1R0ZEt3blZUd2RnVHgiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA3bHV4eD0ieFQ3bnRDdXdrSG5ubDB1d0ZZZGRudCBDbjdZc1R0ZEt3blZUd2RnVHgiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZ2RsVD0iU243WXNUdGQgS3duVlR3ZGdUeOKApiIgZHUwZ3RDVHI9IkR6IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ3VkdS1senZ0LWdDPSJDbjdZc1R0ZF9Wd25WVHdkZ1R4Ij4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHhWdXQgQ3VkdS1senZ0LWdDPSJDbjdZc1R0ZF9Wd25WVHdkZ1R4X2x1MFRsIj5TbjdZc1R0ZAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgS3duVlR3ZGdUeOKApjwveFZ1dD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8LzBZZGRudD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8P1ZiViBnQiAoQmdsVF9Ucmd4ZHgoJDd3ZF9CZ2xUKSkgez8+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPDBZZGRudCBnQz0iQ243WXNUdGRTUEt3blZUd2RnVHgiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA3bHV4eD0ieFQ3bnRDdXdrSG5ubDB1d0ZZZGRudCBCdSBCdS1vVkJud3N4IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGdkbFQ9IlNnRWdkdWwgUGdFdFRDIEt3blZUd2RnVHjigKYiIGR1MGd0Q1RyPSJEWiIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHhWdXQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNnRWdkdWwgUGdFdFRDIEt3blZUd2RnVHjigKY8L3hWdXQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC8wWWRkbnQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPD9WYlYgfSA/PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9DZ2o+CiAgICAgICAgICAgICAgICAgICAgICAgIDwvQ2dqPgogICAgICAgICAgICAgICAgICAgICAgICA8IS0tIHhUN250Q3V3a0hubmwwdXcgLS0+CiAgICAgICAgICAgICAgICAgICAgICAgIDxDZ2ogN2x1eHg9ImRubmwwdXciPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgPENnaiBnQz0iZG5ubDB1dzNudGR1Z3RUdyI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPENnaiBnQz0iZG5ubDB1d05nVG9UdyI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxDZ2ogZ0M9ImRubmwwdXdOZ1RvVHdJVEJkIj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwwWWRkbnQgZ0M9InhnQ1QwdXdIbkVFbFQiIDdsdXh4PSJkbm5sMHV3RllkZG50IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZ2RsVD0iSG5FRWxUIFBnQ1QwdXciIGR1MGd0Q1RyPSJ6eiIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ3VkdS1senZ0LWdDPSJkbkVFbFRfeGdDVDB1dyI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHhWdXQgQ3VkdS1senZ0LWdDPSJkbkVFbFRfeGdDVDB1d19sdTBUbCI+SG5FRWxUIFBnQ1QwdXc8L3hWdXQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8LzBZZGRudD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxDZ2ogN2x1eHg9ImRubmwwdXdGWWRkbnRQVnU3VHciPjwvQ2dqPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPDBZZGRudCBnQz0iamdUbzVndEMiIDdsdXh4PSJkbm5sMHV3RllkZG50IEV3bllWIGJnQ0NUdFBzdWxsTmdUbyIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGdkbFQ9IjVndEMgZ3QgU243WXNUdGQiIGR1MGd0Q1RyPSJ6WiIgQ3VkdS1senZ0LWdDPSJCZ3RDMHV3Ij4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8eFZ1dCBDdWR1LWx6dnQtZ0M9IkJndEMwdXdfbHUwVGwiPjVndEM8L3hWdXQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8LzBZZGRudD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxDZ2ogN2x1eHg9InhWbGdkSG5ubDB1d0ZZZGRudCI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPDBZZGRudCA3bHV4eD0iZG5ubDB1d0ZZZGRudCBWdUVUV1YiIGRnZGxUPSJLd1RqZ25ZeCBLdUVUIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ0M9IlZ3VGpnbll4IiBkdTBndENUcj0iem0iIEN1ZHUtbHp2dC1nQz0iVndUamduWXgiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8eFZ1dCBDdWR1LWx6dnQtZ0M9IlZ3VGpnbll4X2x1MFRsIj5Ld1RqZ25ZeDwveFZ1dD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8LzBZZGRudD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Q2dqIDdsdXh4PSJ4VmxnZEhubmwwdXdGWWRkbnRQVFZ1d3VkbnciPjwvQ2dqPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwwWWRkbnQgN2x1eHg9ImRubmwwdXdGWWRkbnQgVnVFVFNub3QiIGRnZGxUPSI2VHJkIEt1RVQiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnQz0idFRyZCIgZHUwZ3RDVHI9InppIiBDdWR1LWx6dnQtZ0M9InRUcmQiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8eFZ1dCBDdWR1LWx6dnQtZ0M9InRUcmRfbHUwVGwiPjZUcmQ8L3hWdXQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC8wWWRkbnQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L0Nnaj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxsdTBUbCBnQz0iVnVFVDZZczBUd0l1MFRsIiA3bHV4eD0iZG5ubDB1d0l1MFRsIiBCbnc9IlZ1RVQ2WXMwVHciCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ3VkdS1senZ0LWdDPSJWdUVUX2x1MFRsIj5LdUVUOiA8L2x1MFRsPiA8Z3RWWWQgZGtWVD0idFlzMFR3IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdDPSJWdUVUNllzMFR3IiA3bHV4eD0iZG5ubDB1dzVnVGxDIFZ1RVQ2WXMwVHciIGp1bFlUPSJ6IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHhnR1Q9ImkiIHNndD0ieiIgZHUwZ3RDVHI9InpjIj4gPHhWdXQgZ0M9InRZc0t1RVR4IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDdsdXh4PSJkbm5sMHV3SXUwVGwiPjwveFZ1dD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9DZ2o+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxDZ2ogZ0M9ImRubmwwdXdOZ1RvVHdlZ0ViZCIgPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPDBZZGRudCBnQz0iVndUeFR0ZHVkZ250cW5DVCIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgN2x1eHg9ImRubmwwdXdGWWRkbnQgVndUeFR0ZHVkZ250cW5DVCBiZ0NDVHRJdXdFVE5nVG8iCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRnZGxUPSJQb2dkN2IgZG4gS3dUeFR0ZHVkZ250IHFuQ1QiIGR1MGd0Q1RyPSJteiIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ3VkdS1senZ0LWdDPSJWd1R4VHRkdWRnbnRfc25DVCI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHhWdXQgQ3VkdS1senZ0LWdDPSJWd1R4VHRkdWRnbnRfc25DVF9sdTBUbCI+S3dUeFR0ZHVkZ250CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHFuQ1Q8L3hWdXQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8LzBZZGRudD4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8MFlkZG50IGdDPSJuVlR0NWdsVCIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgN2x1eHg9ImRubmwwdXdGWWRkbnQgblZUdDVnbFQgYmdDQ1R0SXV3RVROZ1RvICBiZ0NDVHQiIGRnZGxUPSI5VlR0IDVnbFQiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR1MGd0Q1RyPSJtWiIgQ3VkdS1senZ0LWdDPSJuVlR0X0JnbFQiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx4VnV0IEN1ZHUtbHp2dC1nQz0iblZUdF9CZ2xUX2x1MFRsIj45VlR0PC94VnV0PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC8wWWRkbnQ+Cjw/VmJWCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdCIChndF91d3d1aygnbScsICRWVHdfQ1RkdWdseCkgfHwgZ3RfdXd3dWsoJ0QnLCAkVlR3X0NUZHVnbHgpIHx8ICRDbjd4VGRfVndndGRfQmx1RSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPz4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwwWWRkbnQgZ0M9IlZ3Z3RkIiA3bHV4eD0iZG5ubDB1d0ZZZGRudCBWd2d0ZCBiZ0NDVHRxVENnWXNOZ1RvICIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGdkbFQ9Ikt3Z3RkIiBkdTBndENUcj0ibW0iIEN1ZHUtbHp2dC1nQz0iVndndGQiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx4VnV0IEN1ZHUtbHp2dC1nQz0iVndndGRfbHUwVGwiPkt3Z3RkPC94VnV0PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC8wWWRkbnQ+CiA8P1ZiVgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID8+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8P1ZiVgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnQiAoZ3RfdXd3dWsoJ1onLCAkVlR3X0NUZHVnbHgpIHx8IGd0X3V3d3VrKCdEJywgJFZUd19DVGR1Z2x4KSB8fCAkQ243eFRkX0Nub3RsbnVDX0JsdUUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID8+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8MFlkZG50IGdDPSJDbm90bG51QyIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgN2x1eHg9ImRubmwwdXdGWWRkbnQgQ25vdGxudUMgYmdDQ1R0cVRDZ1lzTmdUbyBDbm90bG51Q19zayIgZGdkbFQ9IlNub3RsbnVDIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkdTBndENUcj0ibWkiIEN1ZHUtbHp2dC1nQz0iQ25vdGxudUMiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx4VnV0IEN1ZHUtbHp2dC1nQz0iQ25vdGxudUNfbHUwVGwiPlNub3RsbnVDPC94VnV0PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC8wWWRkbnQ+CiA8P1ZiVgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID8+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dSBid1RCPSIjIiBnQz0iamdUb0Zubk9zdXdPIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgN2x1eHg9ImRubmwwdXdGWWRkbnQgMG5uT3N1d08gYmdDQ1R0UHN1bGxOZ1RvICIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRnZGxUPSIzWXd3VHRkIGpnVG8gKDduVmsgbncgblZUdCBndCB0VG8gb2d0Q25vKSIgZHUwZ3RDVHI9Im1jIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ3VkdS1senZ0LWdDPSIwbm5Pc3V3TyI+IDx4VnV0IEN1ZHUtbHp2dC1nQz0iMG5uT3N1d09fbHUwVGwiPjNZd3dUdGQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTmdUbzwveFZ1dD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdT4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Q2dqIDdsdXh4PSJqVHdkZzd1bEhubmwwdXdQVFZ1d3VkbncgYmdDQ1R0UHN1bGxOZ1RvIj48L0Nnaj4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8MFlkZG50IGdDPSJ4VDdudEN1d2tIbm5sMHV3SG5FRWxUIiA3bHV4eD0iZG5ubDB1d0ZZZGRudCIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGdkbFQ9Ikhubmx4IiBkdTBndENUcj0ibUQiIEN1ZHUtbHp2dC1nQz0iZG5ubHgiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx4VnV0IEN1ZHUtbHp2dC1nQz0iZG5ubHhfbHUwVGwiPkhubmx4PC94VnV0PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC8wWWRkbnQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvQ2dqPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Q2dqIDdsdXh4PSJuWWRUdzNUdGRUdyI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Q2dqIDdsdXh4PSJndHRUdzNUdGRUdyIgZ0M9ImRubmwwdXdOZ1RvVHdxZ0NDbFQiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxDZ2ogN2x1eHg9InhWbGdkSG5ubDB1d0ZZZGRudCI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwwWWRkbnQgZ0M9IkdubnM5WWQiIDdsdXh4PSJkbm5sMHV3RllkZG50IEdubnM5WWQiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGdkbFQ9IlhubnMgOVlkIiBkdTBndENUcj0iWnoiIEN1ZHUtbHp2dC1nQz0iR25uc19uWWQiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHhWdXQgQ3VkdS1senZ0LWdDPSJHbm5zX25ZZF9sdTBUbCI+WG5ucyA5WWQ8L3hWdXQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvMFlkZG50PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Q2dqIDdsdXh4PSJ4VmxnZEhubmwwdXdGWWRkbnRQVFZ1d3VkbnciPjwvQ2dqPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8MFlkZG50IGdDPSJHbm5zZnQiIDdsdXh4PSJkbm5sMHV3RllkZG50IEdubnNmdCIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZ2RsVD0iWG5ucyBmdCIgZHUwZ3RDVHI9IlpaIiBDdWR1LWx6dnQtZ0M9IkdubnNfZ3QiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHhWdXQgQ3VkdS1senZ0LWdDPSJHbm5zX2d0X2x1MFRsIj5Ybm5zIGZ0PC94VnV0PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8LzBZZGRudD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L0Nnaj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8eFZ1dCBnQz0ieDd1bFRQVGxUN2QzbnRkdWd0VHciIDdsdXh4PSJDd25WQ25vdEhubmwwdXdGWWRkbnQiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8eFRsVDdkIGdDPSJ4N3VsVFBUbFQ3ZCIgZGdkbFQ9IlhubnMiIGR1MGd0Q1RyPSJabSIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDdWR1LWx6dnQtZ0M9IkdubnMiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPG5WZGdudCBnQz0iVnVFVEFZZG45VmRnbnQiIGRnZGxUPSIiIGp1bFlUPSJ1WWRuIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4VGxUN2RUQz0ieFRsVDdkVEMiIEN1ZHUtbHp2dC1nQz0iVnVFVF94N3VsVF91WWRuIj5BWWRuc3VkZzcKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBYbm5zPC9uVmRnbnQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8blZkZ250IGdDPSJWdUVUQTdkWXVsOVZkZ250IiBkZ2RsVD0iIiBqdWxZVD0iVnVFVC11N2RZdWwiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEN1ZHUtbHp2dC1nQz0iVnVFVF94N3VsVF91N2RZdWwiPkE3ZFl1bCBQZ0dUPC9uVmRnbnQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8blZkZ250IGdDPSJWdUVUNWdkOVZkZ250IiBkZ2RsVD0iIiBqdWxZVD0iVnVFVC1CZ2QiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEN1ZHUtbHp2dC1nQz0iVnVFVF94N3VsVF9CZ2QiPjVnZCBLdUVUPC9uVmRnbnQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8blZkZ250IGdDPSJWdUVUOGdDZGI5VmRnbnQiIGRnZGxUPSIiIGp1bFlUPSJWdUVULW9nQ2RiIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDdWR1LWx6dnQtZ0M9IlZ1RVRfeDd1bFRfb2dDZGIiPjVZbGwgOGdDZGI8L25WZGdudD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxuVmRnbnQgZ0M9IjdZeGRuc1A3dWxUOVZkZ250IiBkZ2RsVD0iIiBqdWxZVD0iN1l4ZG5zIj48L25WZGdudD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxuVmRnbnQgZGdkbFQ9IiIganVsWVQ9InYuYyIgQ3VkdS1senZ0LWdDPSJWdUVUX3g3dWxUX1ZUdzdUdGQiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEN1ZHUtbHp2dC11d0V4PSd7ICJ4N3VsVCI6IGN2IH0nPmN2JTwvblZkZ250PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPG5WZGdudCBkZ2RsVD0iIiBqdWxZVD0idi5hYyIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ3VkdS1senZ0LWdDPSJWdUVUX3g3dWxUX1ZUdzdUdGQiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEN1ZHUtbHp2dC11d0V4PSd7ICJ4N3VsVCI6IGFjIH0nPmFjJTwvblZkZ250PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPG5WZGdudCBkZ2RsVD0iIiBqdWxZVD0ieiIgQ3VkdS1senZ0LWdDPSJWdUVUX3g3dWxUX1ZUdzdUdGQiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEN1ZHUtbHp2dC11d0V4PSd7ICJ4N3VsVCI6IHp2diB9Jz56dnYlPC9uVmRnbnQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8blZkZ250IGRnZGxUPSIiIGp1bFlUPSJ6LlpjIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDdWR1LWx6dnQtZ0M9IlZ1RVRfeDd1bFRfVlR3N1R0ZCIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ3VkdS1senZ0LXV3RXg9J3sgIng3dWxUIjogelpjIH0nPnpaYyU8L25WZGdudD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxuVmRnbnQgZGdkbFQ9IiIganVsWVQ9InouYyIgQ3VkdS1senZ0LWdDPSJWdUVUX3g3dWxUX1ZUdzdUdGQiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEN1ZHUtbHp2dC11d0V4PSd7ICJ4N3VsVCI6IHpjdiB9Jz56Y3YlPC9uVmRnbnQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8blZkZ250IGRnZGxUPSIiIGp1bFlUPSJaIiBDdWR1LWx6dnQtZ0M9IlZ1RVRfeDd1bFRfVlR3N1R0ZCIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ3VkdS1senZ0LXV3RXg9J3sgIng3dWxUIjogWnZ2IH0nPlp2diU8L25WZGdudD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxuVmRnbnQgZGdkbFQ9IiIganVsWVQ9Im0iIEN1ZHUtbHp2dC1nQz0iVnVFVF94N3VsVF9WVHc3VHRkIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDdWR1LWx6dnQtdXdFeD0neyAieDd1bFQiOiBtdnYgfSc+bXZ2JTwvblZkZ250PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPG5WZGdudCBkZ2RsVD0iIiBqdWxZVD0iaSIgQ3VkdS1senZ0LWdDPSJWdUVUX3g3dWxUX1ZUdzdUdGQiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEN1ZHUtbHp2dC11d0V4PSd7ICJ4N3VsVCI6IGl2diB9Jz5pdnYlPC9uVmRnbnQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwveFRsVDdkPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwveFZ1dD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvQ2dqPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L0Nnaj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L0Nnaj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvQ2dqPgogICAgICAgICAgICAgICAgICAgICAgICA8L0Nnaj4KCiAgICAgICAgICAgICAgICAgICAgICAgIDxDZ2ogN2x1eHg9ImRubmwwdXciPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgPENnaiBnQz0idXR0bmR1ZGdudEhubmwwdXczbnRkdWd0VHciPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxDZ2ogZ0M9ImRubmwwdXdBdHRuZHVkZ250Ij4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPENnaiBnQz0iZG5ubDB1d0F0dG5kdWRnbnRJVEJkIj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8MFlkZG50IGdDPSJ4dWpUQXR0bmR1ZGdudHgiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDdsdXh4PSJkbm5sMHV3RllkZG50IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZ2RsVD0iUHVqVCBBdHRuZHVkZ250eCIgZHUwZ3RDVHI9Im1aIiA+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHhWdXQ+UHVqVCBBdHRuZHVkZ250eDwveFZ1dD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvMFlkZG50PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPENnaiA3bHV4eD0ialR3ZGc3dWxIbm5sMHV3UFRWdXd1ZG53Ij48L0Nnaj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwwWWRkbnQgZ0M9IkNUbFRkVEF0dG5kdWRnbnQiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDdsdXh4PSJkbm5sMHV3RllkZG50IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZ2RsVD0iU1RsVGRUIEF0dG5kdWRnbnQiIGR1MGd0Q1RyPSJtWiIgID4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8eFZ1dD5TVGxUZFQgQXR0bmR1ZGdudHg8L3hWdXQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8LzBZZGRudD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxDZ2ogN2x1eHg9ImpUd2RnN3VsSG5ubDB1d1BUVnV3dWRudyI+PC9DZ2o+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8MFlkZG50IGdDPSIwdTdPRXduWXRDIiAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgN2x1eHg9ImRubmwwdXdGWWRkbnQgMXg3bmxudyB7anVsWVRNbFRzVHRkOnRZbGwsIHhka2xUTWxUc1R0ZDp0WWxsLCBudDVndFQzYnV0RVQ6J1lWQ3VkVChkYmd4KSd9IiAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGdkbFQ9IjNibm54VCBGdTdPRXduWXRDIDNubG53IiBkdTBndENUcj0ienoiID4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8eFZ1dD4zYm5ueFQgRnU3T0V3bll0QyAzbmxudzwveFZ1dD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvMFlkZG50PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPENnaiA3bHV4eD0ialR3ZGc3dWxIbm5sMHV3UFRWdXd1ZG53Ij48L0Nnaj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwwWWRkbnQgZ0M9ImJnRWJsZ0ViZCIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgN2x1eHg9ImRubmwwdXdGWWRkbnQiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRnZGxUPSIyZ0VibGdFYmQgQXR0bmR1ZGdudCIgZHUwZ3RDVHI9Im1aIiA+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHhWdXQ+MmdFYmxnRWJkPC94VnV0PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC8wWWRkbnQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8P1ZiViBnQigkd1RDdTdkX3hkdXNWX3hnRXRfd2dFYmR4X0NUZHVnbHhbdl1bJ3dUQ3U3ZCddKXs/PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPDBZZGRudCBnQz0iMGx1N09uWWQiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDdsdXh4PSJkbm5sMHV3RllkZG50IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZ2RsVD0iZVR1Q3U3ZCAvIEZsdTdPbllkIiBkdTBndENUcj0ibW0iID4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8eFZ1dCA+ZVR1Q3U3ZCAvIEZsdTdPbllkPC94VnV0PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC8wWWRkbnQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8P1ZiViB9Pz4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxDZ2ogN2x1eHg9ImpUd2RnN3VsSG5ubDB1d1BUVnV3dWRudyI+PC9DZ2o+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8MFlkZG50IGdDPSJUbGxnVnhUIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA3bHV4eD0iZG5ubDB1d0ZZZGRudCIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGdkbFQ9Ik1sbGdWeFQiIGR1MGd0Q1RyPSJtaSI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHhWdXQ+TWxsZ1Z4VDwveFZ1dD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvMFlkZG50PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPENnaiA3bHV4eD0ialR3ZGc3dWxIbm5sMHV3UFRWdXd1ZG53Ij48L0Nnaj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwwWWRkbnQgZ0M9InhkZzdPa3RuZFQiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDdsdXh4PSJkbm5sMHV3RllkZG50IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZ2RsVD0iUGRnN09rIDZuZFQiIGR1MGd0Q1RyPSJtYyIgPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx4VnV0PlBkZzdPayA2bmRUPC94VnV0PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC8wWWRkbnQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Q2dqIDdsdXh4PSJqVHdkZzd1bEhubmwwdXdQVFZ1d3VkbnciPjwvQ2dqPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPD9WYlYgZ0IoJHdUQ3U3ZF94ZHVzVl94Z0V0X3dnRWJkeF9DVGR1Z2x4W3ZdWyd4ZHVzViddKXs/PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPDBZZGRudCBnQz0id1kwMFR3eGR1c1YiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDdsdXh4PSJkbm5sMHV3RllkZG50IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZ2RsVD0iZVkwMFR3IFBkdXNWIEF0dG5kdWRnbnQiIGR1MGd0Q1RyPSJtRCIgeGRrbFQ9IjB1N09Fd25ZdEMtZ3N1RVQ6WXdsKCd3VHhuWXc3VHgvVmxZRWd0eC9WQ0JfamdUb1R3X3VDanV0N1RDL2dzdUVUeC9kbm5sMHV3RllkZG50LXhkdXNWQFpyei5WdEUnKTsiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx4VnV0PmVZMDBUdyBQZHVzVjwveFZ1dD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvMFlkZG50PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPD9WYlYgfT8+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Q2dqIDdsdXh4PSJqVHdkZzd1bEhubmwwdXdQVFZ1d3VkbnciPjwvQ2dqPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPD9WYlYgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnQigkd1RDdTdkX3hkdXNWX3hnRXRfd2dFYmR4X0NUZHVnbHhbdl1bJ0NnRWdkdWxfeGdFdCddICYmICRDZ0VnZHVsX3hnRXR1ZFl3VF9zbkNZbFRbdl1bJ3hkdWRZeCddID09IHopewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID8+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwwWWRkbnQgZ0M9IkNnRWdkdWx4Z0V0IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA3bHV4eD0iZG5ubDB1d0ZZZGRudCIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGdkbFQ9IlNnRWdkdWwgUGdFdHVkWXdUICIgZHUwZ3RDVHI9Im1EIiA+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHhWdXQ+U2dFZ2R1bCBQZ0V0PC94VnV0PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC8wWWRkbnQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8P1ZiViB9Pz4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwhLS0gOVl3IEF0dG5kdWRnbnQgRllkZG50eCBNdEMgIC0gUHdnIFJ3Z3hidHV0IC0tPiAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9DZ2o+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9DZ2o+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPENnaiBnQz0ibG51Q2d0RUZ1dyI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxDZ2ogN2x1eHg9IlZ3bkV3VHh4Ij4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxDZ2ogN2x1eHg9IkVsZ3NzVHciPjwvQ2dqPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L0Nnaj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L0Nnaj4JCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L0Nnaj4KICAgICAgICAgICAgICAgICAgICAgICAgPC9DZ2o+CQogICAgICAgICAgICAgICAgICAgICAgICA8c1R0WSBka1ZUPSI3bnRkVHJkIiBnQz0iamdUb1R3M250ZFRyZHFUdFkiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNUdFlnZFRzIGdDPSI3bnRkVHJkNWd3eGRLdUVUIiBsdTBUbD0iNWd3eGQgS3VFVCIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDdWR1LWx6dnQtZ0M9IkJnd3hkX1Z1RVQiPjwvc1R0WWdkVHM+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c1R0WWdkVHMgZ0M9IjdudGRUcmRJdXhkS3VFVCIgbHUwVGw9Ikl1eGQgS3VFVCIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDdWR1LWx6dnQtZ0M9Imx1eGRfVnVFVCI+PC9zVHRZZ2RUcz4KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzVHRZZ2RUcyBnQz0iN250ZFRyZEt1RVRlbmR1ZFQzbyIgbHUwVGw9ImVuZHVkVCAzbG43T29neFQiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ3VkdS1senZ0LWdDPSJWdUVUX3duZHVkVF83byI+PC9zVHRZZ2RUcz4KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzVHRZZ2RUcyBnQz0iN250ZFRyZEt1RVRlbmR1ZFQzN28iIGx1MFRsPSJlbmR1ZFQgM25ZdGRUdy0zbG43T29neFQiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ3VkdS1senZ0LWdDPSJWdUVUX3duZHVkVF83N28iPjwvc1R0WWdkVHM+CiAgICAgICAgICAgICAgICAgICAgICAgIDwvc1R0WT4KCiAgICAgICAgICAgICAgICAgICAgICAgIDxDZ2ogZ0M9ImpnVG9UdzNudGR1Z3RUdyIgZHUwZ3RDVHI9InYiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgPENnaiBnQz0iamdUb1R3IiA3bHV4eD0iVkNCTmdUb1R3Ij48L0Nnaj4KICAgICAgICAgICAgICAgICAgICAgICAgPC9DZ2o+CgogICAgICAgICAgICAgICAgICAgICAgICA8Q2dqIGdDPSJUd3dudzh3dVZWVHciIGJnQ0NUdD0nZHdZVCc+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Q2dqIGdDPSJUd3dud3FUeHh1RVRJVEJkIj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8eFZ1dCBnQz0iVHd3bndxVHh4dUVUIj48L3hWdXQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPDBZZGRudCBnQz0iVHd3bndQYm5vcW53VCIgQ3VkdS1senZ0LWdDPSJUd3dud19zbndUX2d0Qm4iPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBxbndUIGZ0Qm53c3VkZ250PC8wWWRkbnQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPDBZZGRudCBnQz0iVHd3bndQYm5vSVR4eCIgQ3VkdS1senZ0LWdDPSJUd3dud19sVHh4X2d0Qm4iCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiZ0NDVHQ9J2R3WVQnPklUeHggZnRCbndzdWRnbnQ8LzBZZGRudD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvQ2dqPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgPENnaiBnQz0iVHd3bndxVHh4dUVUZWdFYmQiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwwWWRkbnQgZ0M9IlR3d253M2xueFQiIEN1ZHUtbHp2dC1nQz0iVHd3bndfN2xueFQiPjNsbnhUPC8wWWRkbnQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L0Nnaj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxDZ2ogN2x1eHg9IjdsVHV3Rm5kYiI+PC9DZ2o+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZFRyZHV3VHUgZ0M9IlR3d253cW53VGZ0Qm4iIGJnQ0NUdD0nZHdZVCcgd1R1Q250bGs9IndUdUNudGxrIj48L2RUcmR1d1R1PgogICAgICAgICAgICAgICAgICAgICAgICA8L0Nnaj4KICAgICAgICAgICAgICAgICAgICA8L0Nnaj4KICAgICAgICAgICAgICAgICAgICA8IS0tIHN1Z3QzbnRkdWd0VHcgLS0+CgogICAgICAgICAgICAgICAgICAgIDxDZ2ogZ0M9Im5qVHdsdWszbnRkdWd0VHciIDdsdXh4PSJiZ0NDVHQiPgogICAgICAgICAgICAgICAgICAgICAgICA8Q2dqIGdDPSJWdXh4b253QzlqVHdsdWsiIDdsdXh4PSI3bnRkdWd0VHcgYmdDQ1R0Ij4KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxDZ2ogN2x1eHg9IkNndWxuRSI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPENnaiA3bHV4eD0id25vIj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPFYgZ0M9IlZ1eHhvbndDSFRyZCIgQ3VkdS1senZ0LWdDPSJWdXh4b253Q19sdTBUbCI+TXRkVHcgZGJUCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBWdXh4b253QyBkbiBuVlR0IGRiZ3ggS1M1IEJnbFQ6PC9WPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvQ2dqPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxDZ2ogN2x1eHg9IndubyI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxndFZZZCBka1ZUPSJWdXh4b253QyIgZ0M9IlZ1eHhvbndDIiA3bHV4eD0iZG5ubDB1dzVnVGxDIiAvPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvQ2dqPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxDZ2ogN2x1eHg9IjBZZGRudGVubyI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwwWWRkbnQgZ0M9IlZ1eHhvbndDM3V0N1RsIiA3bHV4eD0ibmpUd2x1a0ZZZGRudCI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8eFZ1dCBDdWR1LWx6dnQtZ0M9IlZ1eHhvbndDXzd1dDdUbCI+M3V0N1RsPC94VnV0PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8LzBZZGRudD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPDBZZGRudCBnQz0iVnV4eG9ud0NQWTBzZ2QiIDdsdXh4PSJualR3bHVrRllkZG50Ij4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx4VnV0IEN1ZHUtbHp2dC1nQz0iVnV4eG9ud0Nfbk8iPjlSPC94VnV0PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8LzBZZGRudD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L0Nnaj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvQ2dqPgogICAgICAgICAgICAgICAgICAgICAgICA8L0Nnaj4KICAgICAgICAgICAgICAgICAgICAgICAgPENnaiBnQz0iN250Qmd3c1NUbFRkVDlqVHdsdWsiIDdsdXh4PSI3bnRkdWd0VHcgYmdDQ1R0Ij4KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxDZ2ogN2x1eHg9IkNndWxuRSI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPENnaiA3bHV4eD0id25vIj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPFYgZ0M9IjdudEJnd3NTVGxUZFRIVHJkIj5Bd1Qga25ZIHhZd1Qga25ZIG91dGQgZG4gQ1RsVGRUIGRiVCB0bmRUPzwvVj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L0Nnaj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Q2dqIDdsdXh4PSIwWWRkbnRlbm8iPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8MFlkZG50IGdDPSJDVGxUZFQzdXQ3VGwiIDdsdXh4PSJualR3bHVrRllkZG50Ij4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx4VnV0IEN1ZHUtbHp2dC1nQz0iVnV4eG9ud0NfN3V0N1RsIj4zdXQ3VGw8L3hWdXQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvMFlkZG50PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8MFlkZG50IGdDPSJDVGxUZFRQWTBzZ2QiIDdsdXh4PSJualR3bHVrRllkZG50Ij4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx4VnV0IEN1ZHUtbHp2dC1nQz0iVnV4eG9ud0Nfbk8iPjlSPC94VnV0PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8LzBZZGRudD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L0Nnaj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvQ2dqPgogICAgICAgICAgICAgICAgICAgICAgICA8L0Nnaj4KICAgICAgICAgICAgICAgICAgICAgICAgPENnaiBnQz0iN250Qmd3c1NUbFRkVEF0dG5kdWRnbnQ5alR3bHVrIiA3bHV4eD0iN250ZHVndFR3IGJnQ0NUdCI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Q2dqIDdsdXh4PSJDZ3VsbkUiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxDZ2ogN2x1eHg9IndubyI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxWIGdDPSI3bnRCZ3dzU1RsVGRUSFRyZCI+QXdUIGtuWSB4WXdUIGtuWSBvdXRkIGRuIENUbFRkVCBkYlQgeFRsVDdkVEMgdXR0bmR1ZGdudD88L1Y+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9DZ2o+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPENnaiA3bHV4eD0iMFlkZG50ZW5vIj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPDBZZGRudCBnQz0iQ1RsVGRUNFR4IiA3bHV4eD0ibmpUd2x1a0ZZZGRudCI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8eFZ1dCBDdWR1LWx6dnQtZ0M9IkNUbFRkVDRUeCI+NFR4PC94VnV0PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8LzBZZGRudD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPDBZZGRudCBnQz0iQ1RsVGRUNm4iIDdsdXh4PSJualR3bHVrRllkZG50Ij4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx4VnV0IEN1ZHUtbHp2dC1nQz0iQ1RsVGRUNm4iPjZuPC94VnV0PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8LzBZZGRudD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L0Nnaj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvQ2dqPgogICAgICAgICAgICAgICAgICAgICAgICA8L0Nnaj4KICAgICAgICAgICAgICAgICAgICAgICAgPENnaiBnQz0ieGRnN09rNm5kVDlqVHdsdWsiIDdsdXh4PSI3bnRkdWd0VHcgYmdDQ1R0Ij4KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxDZ2ogN2x1eHg9IkNndWxuRSI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPENnaiA3bHV4eD0id25vIj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPFYgZ0M9IlZ1eHhvbndDSFRyZCI+TXRkVHcgdG5kVDo8L1Y+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9DZ2o+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPENnaiA3bHV4eD0id25vIj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRUcmR1d1R1IDdsdXh4PSJkbm5sMHV3NWdUbEMiIHdub3g9ImkiIDdubHg9Im12IiBnQz0iZHJkUGRnN09rNm5kVCIgdHVzVD0iZHJkUGRnN09rNm5kVCIvPjwvZFRyZHV3VHU+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9DZ2o+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPENnaiA3bHV4eD0iMFlkZG50ZW5vIj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPDBZZGRudCBnQz0ieGRnN09rNm5kVDN1dDdUbCIgN2x1eHg9Im5qVHdsdWtGWWRkbnQiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHhWdXQ+M3V0N1RsPC94VnV0PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8LzBZZGRudD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPDBZZGRudCBnQz0ieGRnN09rNm5kVFBZMHNnZCIgN2x1eHg9Im5qVHdsdWtGWWRkbnQiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHhWdXQ+OVI8L3hWdXQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvMFlkZG50PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvQ2dqPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9DZ2o+CiAgICAgICAgICAgICAgICAgICAgICAgIDwvQ2dqPgogICAgICAgICAgICAgICAgICAgICAgICA8Q2dqIGdDPSJ3WTAwVHdQZHVzVjlqVHdsdWsiIDdsdXh4PSI3bnRkdWd0VHcgYmdDQ1R0Ij4KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxDZ2ogN2x1eHg9IkNndWxuRSI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPENnaiA3bHV4eD0id25vIj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHhWdXQgZ0M9InhUbFQ3ZFBkdXNWSFRyZCI+UFRsVDdkIGRiVCB4ZHVzVjo8L3hWdXQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxWPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHhWdXQgZ0M9IndZMDBUd1BkdXNWUFRsVDdkM250ZHVndFR3IiA3bHV4eD0iQ3duVkNub3RIbm5sMHV3RllkZG50Ij4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8eFRsVDdkIDdsdXh4PSJDd25WQ25vdEhubmwwdXdGWWRkbnQiIGdDPSJ4ZHVzVmRrVlQiIHR1c1Q9InhkdXNWZGtWVCI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxuVmRnbnQganVsWVQ9IkFLS2U5Tk1TIj5BS0tlOU5NUzwvblZkZ250PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8blZkZ250IGp1bFlUPSIzOXFLSU1ITVMiPjM5cUtJTUhNUzwvblZkZ250PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8blZkZ250IGp1bFlUPSIzOTY1ZlNNNkhmQUkiPjM5NjVmU002SGZBSTwvblZkZ250PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8blZkZ250IGp1bFlUPSIzOTZIZTlJSU1TIDM5SzQiPjM5NkhlOUlJTVMgMzlLNDwvblZkZ250PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8blZkZ250IGp1bFlUPSJTTUlmTk1lTVMiPlNNSWZOTWVNUzwvblZkZ250PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8blZkZ250IGp1bFlUPSJTTU5NSTlLcU02SCI+U01OTUk5S3FNNkg8L25WZGdudD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPG5WZGdudCBqdWxZVD0iU2VBNUgiPlNlQTVIPC9uVmRnbnQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxuVmRnbnQganVsWVQ9IlNXS0lmM0FITSI+U1dLSWYzQUhNPC9uVmRnbnQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxuVmRnbnQganVsWVQ9IjllZnBmNkFJIj45ZWZwZjZBSTwvblZkZ250PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8blZkZ250IGp1bFlUPSJLQWZTIj5LQWZTPC9uVmRnbnQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxuVmRnbnQganVsWVQ9IktNNlNmNnAiPktNNlNmNnA8L25WZGdudD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPG5WZGdudCBqdWxZVD0iS2VmOWVmSDQiPktlZjllZkg0PC9uVmRnbnQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxuVmRnbnQganVsWVQ9ImVNeU0zSE1TIj5lTXlNM0hNUzwvblZkZ250PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8blZkZ250IGp1bFlUPSJXZXBNNkgiPldlcE02SDwvblZkZ250PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwveFRsVDdkPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC94VnV0PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L1Y+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9DZ2o+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPENnaiA3bHV4eD0ieFRWdXd1ZG53Ij48L0Nnaj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Q2dqIDdsdXh4PSIwWWRkbnRlbm8iPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8MFlkZG50IGdDPSJ3WTAwVHdQZHVzVjlqVHdsdWszdXQ3VGwiIDdsdXh4PSJualR3bHVrRllkZG50Ij4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx4VnV0IEN1ZHUtbHp2dC1nQz0iVnV4eG9ud0NfN3V0N1RsIj4zdXQ3VGw8L3hWdXQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvMFlkZG50PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8MFlkZG50IGdDPSJ3WTAwVHdQZHVzVjlqVHdsdWs5UiIgN2x1eHg9Im5qVHdsdWtGWWRkbnQiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHhWdXQgQ3VkdS1senZ0LWdDPSJWdXh4b253Q19uTyI+OVI8L3hWdXQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvMFlkZG50PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvQ2dqPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9DZ2o+CiAgICAgICAgICAgICAgICAgICAgICAgIDwvQ2dqPgogICAgICAgICAgICAgICAgICAgICAgICA8Q2dqIGdDPSJDZ0VnZHVseGdFdDlqVHdsdWsiIDdsdXh4PSI3bnRkdWd0VHcgYmdDQ1R0Ij4KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxDZ2ogN2x1eHg9IkNndWxuRSI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPENnaiA3bHV4eD0id25vIj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHhWdXQgZ0M9InhUbFQ3ZFBnRXRIVHJkIj5Bd1Qga25ZIHhZd1Q/PC94VnV0PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Vj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxndFZZZCBka1ZUPSJiZ0NDVHQiIGdDPSJ4Z0V0ZGtWVCIgdHVzVD0ieGdFdGRrVlQiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L1Y+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9DZ2o+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPENnaiA3bHV4eD0ieFRWdXd1ZG53Ij48L0Nnaj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Q2dqIDdsdXh4PSIwWWRkbnRlbm8iPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8MFlkZG50IGdDPSJDZ0VnZHVseGdFdDlqVHdsdWszdXQ3VGwiIDdsdXh4PSJualR3bHVrRllkZG50Ij4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx4VnV0IEN1ZHUtbHp2dC1nQz0iVnV4eG9ud0NfN3V0N1RsIj42bjwveFZ1dD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC8wWWRkbnQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwwWWRkbnQgZ0M9IkNnRWdkdWx4Z0V0OWpUd2x1azlSIiA3bHV4eD0ibmpUd2x1a0ZZZGRudCI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8eFZ1dCBDdWR1LWx6dnQtZ0M9IlZ1eHhvbndDX25PIj40VHg8L3hWdXQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvMFlkZG50PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvQ2dqPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9DZ2o+CiAgICAgICAgICAgICAgICAgICAgICAgIDwvQ2dqPgogICAgICAgICAgICAgICAgICAgICAgICA8Q2dqIGdDPSJDbjdZc1R0ZEt3blZUd2RnVHg5alR3bHVrIiA3bHV4eD0iN250ZHVndFR3IGJnQ0NUdCI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Q2dqIDdsdXh4PSJDZ3VsbkUiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxDZ2ogN2x1eHg9IndubyI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx4VnV0IEN1ZHUtbHp2dC1nQz0iQ243WXNUdGRfVnduVlR3ZGdUeF9CZ2xUX3R1c1QiPjVnbFQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR1c1Q6PC94VnV0PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ViBnQz0iQmdsVDZ1c1Q1Z1RsQyI+LTwvVj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L0Nnaj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Q2dqIDdsdXh4PSJ3bm8iPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8eFZ1dCBDdWR1LWx6dnQtZ0M9IkNuN1lzVHRkX1Z3blZUd2RnVHhfQmdsVF94Z0dUIj41Z2xUCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4Z0dUOjwveFZ1dD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPFYgZ0M9IkJnbFRQZ0dUNWdUbEMiPi08L1Y+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9DZ2o+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPENnaiA3bHV4eD0ieFRWdXd1ZG53Ij48L0Nnaj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Q2dqIDdsdXh4PSJ3bm8iPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8eFZ1dCBDdWR1LWx6dnQtZ0M9IkNuN1lzVHRkX1Z3blZUd2RnVHhfZGdkbFQiPkhnZGxUOjwveFZ1dD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPFYgZ0M9ImRnZGxUNWdUbEMiPi08L1Y+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9DZ2o+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPENnaiA3bHV4eD0id25vIj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHhWdXQgQ3VkdS1senZ0LWdDPSJDbjdZc1R0ZF9Wd25WVHdkZ1R4X3VZZGJudyI+QVlkYm53OjwveFZ1dD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPFYgZ0M9InVZZGJudzVnVGxDIj4tPC9WPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvQ2dqPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxDZ2ogN2x1eHg9IndubyI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx4VnV0IEN1ZHUtbHp2dC1nQz0iQ243WXNUdGRfVnduVlR3ZGdUeF94WTAxVDdkIj5QWTAxVDdkOjwveFZ1dD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPFYgZ0M9InhZMDFUN2Q1Z1RsQyI+LTwvVj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L0Nnaj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Q2dqIDdsdXh4PSJ3bm8iPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8eFZ1dCBDdWR1LWx6dnQtZ0M9IkNuN1lzVHRkX1Z3blZUd2RnVHhfT1Rrb253Q3giPlJUa29ud0N4OjwveFZ1dD4K