<?php
/*
Plugin Name: WooCommerce CCAvenue MCPG Official
Plugin URI: https://w...content-available-to-author-only...l.in/
Description: Extends WooCommerce with bluezeal ccavenuemcpg gateway.
Version: 2.3
Author: bluezeal.in
Author URI: https://w...content-available-to-author-only...l.in/
Copyright: © 2014-2015 bluezeal.in
License: GNU General Public License v3.0
License URI: http://w...content-available-to-author-only...u.org/licenses/gpl-3.0.html
*/
exit ; // Exit if accessed directly }
add_action( 'plugins_loaded' , 'wc_ccavenue_pay_gateway' , 0 ) ;
function wc_ccavenue_pay_gateway( ) {
return ;
}
add_filter( 'woocommerce_payment_gateways' , 'wc_ccavenue_gateway' ) ;
function wc_ccavenue_gateway( $methods ) {
$methods [ ] = 'WC_bluezeal_Ccave' ;
return $methods ;
}
class WC_bluezeal_Ccave extends WC_Payment_Gateway {
protected $msg = array ( ) ; public function __construct( ) {
global $woocommerce ;
$this -> ccavenue_bz_module_validation ( ) ;
$this -> log = $woocommerce -> logger ( ) ;
// Ccavenue values
$this -> id = 'ccavenue' ;
$this -> method_title = __( 'Ccavenue MCPG Payment' , 'woothemes' ) ;
$this -> icon = WP_PLUGIN_URL
. "/" . plugin_basename
( dirname ( __FILE__ ) ) . '/images/ccavenue_logo.png' ; $this -> has_fields = false ;
$this -> liveurl = 'https://s...content-available-to-author-only...e.com/transaction/transaction.do?command=initiateTransaction' ;
// Load the form fields
$this -> init_form_fields ( ) ;
// Load the settings.
$this -> init_settings ( ) ;
// Define user set variables
$this -> enabled = $this -> settings [ 'enabled' ] ;
$this -> title = $this -> settings [ 'title' ] ;
$this -> description = $this -> settings [ 'description' ] ;
$this -> merchant_id = $this -> settings [ 'merchant_id' ] ;
$this -> access_code = $this -> settings [ 'access_code' ] ;
$this -> encryption_key = $this -> settings [ 'encryption_key' ] ;
$this -> msg [ 'message' ] = "" ;
$this -> msg [ 'class' ] = "" ;
// Actions
add_action
( 'init' , array ( & $this , 'check_callback' ) ) ; add_action
( 'valid_ccavenue_callback' , array ( & $this , 'check_ccavenue_response' ) ) ; add_action
( 'woocommerce_update_options_payment_gateways' , array ( & $this , 'process_admin_options' , ) ) ; add_action
( 'woocommerce_update_options_payment_gateways_' . $this -> id , array ( $this , 'process_admin_options' ) ) ; add_action
( 'woocommerce_receipt_ccavenue' , array ( $this , 'receipt_page' ) ) ; add_action
( 'woocommerce_thankyou_ccavenue' , array ( $this , 'thankyou' ) ) ; }
public function admin_options( ) {
?>
<h3><?php _e( 'CCAvenue Payment Gateway' , 'bluezeal' ) ; ?> </h3>
<?php echo '<p><a href="http://w...content-available-to-author-only...l.in" target="_blank">' . __
( 'CCAvenue MCPG Payment Gateway developed by Bluezeal.in' ) . '<br/><img src="' . WP_PLUGIN_URL
. "/" . plugin_basename
( dirname ( __FILE__ ) ) . '/images/logo.png" alt="module developed by bluezeal.in" ></a>' . '</p>' ; ?> <p><?php _e( 'CCAvenue is most popular payment gateway for online shopping in India' , 'woothemes' ) ; ?> </p>
<table class="form-table">
<?php $this -> generate_settings_html ( ) ; ?>
</table>
<?php
} // End admin_options()
function init_form_fields( ) {
global $woocommerce ;
$this -> form_fields = array ( 'title' => __( 'Enable/Disable' , 'bluezeal' ) ,
'type' => 'checkbox' ,
'label' => __( 'Enable Ccavenue MCPG Payment' , 'bluezeal' ) ,
'default' => 'no'
) ,
'title' => __( 'Title:' , 'bluezeal' ) ,
'type' => 'text' ,
'desc_tip' => true ,
'placeholder' => __( 'CCAvenue MCPG' , 'woocommerce' ) ,
'description' => __( 'Your desire title name .it will show during checkout proccess.' , 'bluezeal' ) ,
'default' => __( 'CCAvenue' , 'bluezeal' )
) ,
'title' => __( 'Description:' , 'bluezeal' ) ,
'type' => 'textarea' ,
'desc_tip' => true ,
'placeholder' => __( 'Description' , 'woocommerce' ) ,
'description' => __( 'Pay securely by Credit Card/Debit Card/internet banking through CCAvenue MCPG.' , 'bluezeal' ) ,
'default' => __( 'Pay securely by Credit Card/Debit Card/internet banking through CCAvenue MCPG.' , 'bluezeal' )
) ,
'title' => __( 'Merchant ID' , 'bluezeal' ) ,
'type' => 'text' ,
'desc_tip' => true ,
'placeholder' => __( 'Merchant ID' , 'woocommerce' ) ,
'description' => __( 'Merchant ID,Given by CCAvenue' )
) ,
'title' => __( 'Access Code' , 'woocommerce' ) ,
'type' => 'text' ,
'desc_tip' => true ,
'placeholder' => __( 'Access Code' , 'woocommerce' ) ,
'description' => __( 'Access Code,Given by CCAvenue' , 'bluezeal' )
) ,
'encryption_key' => array ( 'title' => __( 'Encryption Key' , 'woocommerce' ) ,
'type' => 'text' ,
'desc_tip' => true ,
'placeholder' => __( 'Encryption Key' , 'woocommerce' ) ,
'description' => __( 'Encrypted/Working key Given to Merchant by CCAvenue' , 'bluezeal' )
)
) ;
}
function payment_fields( ) {
if ( $this -> description ) echo wpautop( wptexturize( $this -> description ) ) ;
}
/**
* Process the payment and return the result
**/
function generate_ccavenue_form( $order_id ) {
global $woocommerce ;
$billing_country = '' ;
$billing_state = '' ;
$currency = '' ;
$total = '' ;
$delivery_country = '' ;
$delivery_state = '' ;
$order = new WC_Order( $order_id ) ;
$redirect_url = add_query_arg ( 'wooorderid' , $order_id , add_query_arg ( 'wc-api' , 'WC_bluezeal_Ccave' , $this -> get_return_url ( $order ) ) ) ;;
$cancel_url = add_query_arg ( 'wooorderid' , $order_id , add_query_arg ( 'wc-api' , 'WC_bluezeal_Ccave' , $this -> get_return_url ( $order ) ) ) ;;
$order_id = $order -> id ;
$merchant_id = $this -> merchant_id ;
$access_code = $this -> access_code ;
$encryption_key = $this -> encryption_key ;
$countries = new WC_Countries;
$billing_country = $order -> billing_country ;
$billing_state = $order -> billing_state ;
$currency = get_woocommerce_currency( ) ;
$total = $order -> order_total ;
$delivery_country = $order -> shipping_country ;
$delivery_state = $order -> shipping_state ;
$ccavenue_args = array ( ) ; $ccavenue_args [ 'merchant_id' ] = $merchant_id ;
$ccavenue_args [ 'order_id' ] = $order_id ;
$ccavenue_args [ 'language' ] = 'EN' ;
$ccavenue_args [ 'currency' ] = get_woocommerce_currency( ) ;
$ccavenue_args [ 'amount' ] = $order -> order_total ;
$ccavenue_args [ 'redirect_url' ] = $redirect_url ;
$ccavenue_args [ 'cancel_url' ] = $cancel_url ;
$ccavenue_args [ 'billing_name' ] = $order -> billing_first_name . ' ' . $order -> billing_last_name ;
$ccavenue_args [ 'billing_address' ] = $order -> billing_address_1 . ' ' . $order -> billing_address_2 ;
$ccavenue_args [ 'billing_country' ] = $countries -> countries [ $billing_country ] ;
$ccavenue_args [ 'billing_state' ] = $countries -> states [ $billing_country ] [ $billing_state ] ;
$ccavenue_args [ 'billing_city' ] = $order -> billing_city ;
$ccavenue_args [ 'billing_tel' ] = $order -> billing_phone ;
$ccavenue_args [ 'billing_email' ] = $order -> billing_email ;
$ccavenue_args [ 'billing_zip' ] = $order -> billing_postcode ;
$ccavenue_args [ 'delivery_name' ] = $order -> shipping_first_name . ' ' . $order -> shipping_last_name ;
$ccavenue_args [ 'delivery_address' ] = $order -> shipping_address_1 . ' ' . $order -> shipping_address_2 ;
$ccavenue_args [ 'delivery_country' ] = $countries -> countries [ $delivery_country ] ;
$ccavenue_args [ 'delivery_state' ] = $countries -> states [ $delivery_country ] [ $delivery_state ] ;
$ccavenue_args [ 'delivery_tel' ] = $order -> shipping_phone ;
$ccavenue_args [ 'delivery_city' ] = $order -> shipping_city ;
$ccavenue_args [ 'delivery_zip' ] = $order -> shipping_postcode ;
$ccavenue_args [ 'merchant_param1' ] = $order_id ;
$ccavenue_post_data = '' ;
$ccavenue_post_data_array = array ( ) ; foreach ( $ccavenue_args as $key => $value )
{
$ccavenue_post_data_array [ ] .= $key . '=' . urlencode ( $value ) ; }
$ccavenue_post_data = implode ( "&" , $ccavenue_post_data_array ) ; $encrypted_data = $this -> encrypt ( $ccavenue_post_data , $encryption_key ) ;
$ccavenue_args_array = array ( ) ; $ccavenue_args_array [ ] = "<input type='hidden' name='encRequest' value='" . $encrypted_data . "'/>" ;
$ccavenue_args_array [ ] = "<input type='hidden' name='access_code' value='" . $access_code . "'/>" ;
$woocommerce -> add_inline_js ( '
jQuery("body").block({
message: "<img src=\"' . esc_url( $woocommerce -> plugin_url ( ) ) . '/assets/images/ajax-loader.gif\" alt=\"Redirecting...\" style=\"float:left; margin-right: 10px;\" />' . __( 'Thank you for your order. We are now redirecting you to Ccavenue to make the payment.' , 'woothemes' ) . '",
overlayCSS:
{
background: "#fff",
opacity: 0.6
},
css: {
padding: 20,
textAlign: "center",
color: "#555",
border: "3px solid #aaa",
backgroundColor:"#fff",
cursor: "wait",
lineHeight: "32px"
}
});
jQuery("#submit_ccavenue_payment_form").click();
' ) ;
return '<form action="' . $this -> liveurl . '" method="post" id="ccavenue_payment_form">
' . implode ( '' , $ccavenue_args_array ) . ' <input type="submit" class="button-alt" id="submit_ccavenue_payment_form" value="' . __( 'Pay via CCAvenue' , 'ccavenue' ) . '" /> <a class="button cancel" href="' . $order -> get_cancel_order_url ( ) . '">' . __( 'Cancel order & restore cart' , 'ccavenue' ) . '</a>
</form>' ;
}
/**
* Check for valid CCAvenue server callback
**/
/**
* callback_page
**/
function check_callback( ) {
$_GET = stripslashes_deep( $_GET ) ;
do_action( "valid_ccavenue_callback" , $_GET ) ;
}
/**
* receipt_page
**/
function receipt_page( $order ) {
echo '<p>' . __( 'You are being redirected to the Ccavenue Netpayment Window.' , 'bluezeal' ) . '</p>' ;
echo $this -> generate_ccavenue_form ( $order ) ;
}
/**
* Process the payment and return the result
**/
function process_payment( $order_id ) {
global $woocommerce ;
$order = &new WC_Order( $order_id ) ;
// Return payment page
'result' => 'success' ,
'redirect' => add_query_arg( 'order' , $order -> id , add_query_arg( 'key' , $order -> order_key , get_permalink( woocommerce_get_page_id( 'pay' ) ) ) )
) ;
}
function check_ccavenue_response( )
{
global $woocommerce ;
$encResponse = '' ;
if ( isset ( $_REQUEST [ 'encResp' ] ) ) $encResponse = $_REQUEST [ "encResp" ] ; $encryption_key = $this -> encryption_key ;
$rcvdString = $this -> decrypt ( $encResponse , $encryption_key ) ;
$decryptValues = explode ( '&' , $rcvdString ) ; $dataSize = sizeof ( $decryptValues ) ; $response_array = array ( ) ;
for ( $i = 0 ; $i < count ( $decryptValues ) ; $i ++ ) {
$information = explode ( '=' , $decryptValues [ $i ] ) ; if ( count ( $information ) == 2 ) {
$response_array [ $information [ 0 ] ] = urldecode ( $information [ 1 ] ) ; }
}
$merchant_param1 = '' ;
$order_status = '' ;
$order_id = '' ;
$tracking_id = '' ;
$bank_ref_no = '' ;
$failure_message = '' ;
$payment_mode = '' ;
$card_name = '' ;
$status_code = '' ;
$status_message = '' ;
$currency = '' ;
$amount = '' ;
if ( isset ( $response_array [ 'order_id' ] ) ) $order_id = $response_array [ 'order_id' ] ; if ( $order_id != '' ) {
try {
$order = new WC_Order( $order_id ) ;
if ( isset ( $response_array [ 'tracking_id' ] ) ) $tracking_id = $response_array [ 'tracking_id' ] ; if ( isset ( $response_array [ 'bank_ref_no' ] ) ) $bank_ref_no = $response_array [ 'bank_ref_no' ] ; if ( isset ( $response_array [ 'order_status' ] ) ) $order_status = $response_array [ 'order_status' ] ; if ( isset ( $response_array [ 'failure_message' ] ) ) $failure_message = $response_array [ 'failure_message' ] ; if ( isset ( $response_array [ 'payment_mode' ] ) ) $payment_mode = $response_array [ 'payment_mode' ] ; if ( isset ( $response_array [ 'card_name' ] ) ) $card_name = $response_array [ 'card_name' ] ; if ( isset ( $response_array [ 'status_code' ] ) ) $status_code = $response_array [ 'status_code' ] ; if ( isset ( $response_array [ 'status_message' ] ) ) $status_message = $response_array [ 'status_message' ] ; if ( isset ( $response_array [ 'currency' ] ) ) $currency = $response_array [ 'currency' ] ; if ( isset ( $response_array [ 'amount' ] ) ) $amount = $response_array [ 'amount' ] ; if ( isset ( $response_array [ 'merchant_param1' ] ) ) $merchant_param1 = $response_array [ 'merchant_param1' ] ;
$transauthorised = false ;
if ( $order -> status !== 'completed' )
{
if ( $order_status == "Success" ) {
$transauthorised = true ;
$msg [ 'message' ] = "Thank you for shopping with us. Your account has been charged and your transaction is successful. We will be shipping your order to you soon." ;
$msg [ 'class' ] = 'success' ;
$order -> update_status ( 'processing' ) ;
$order -> payment_complete ( ) ;
$order -> add_order_note ( 'CCAvenue payment successful<br/>Bank Ref Number: ' . $bank_ref_no ) ;
$order -> add_order_note ( $msg [ 'message' ] ) ;
$woocommerce -> cart -> empty_cart ( ) ;
}
else if ( $order_status == "Aborted" ) {
$msg [ 'message' ] = "<strong>CCAvenue MCPG payment order cancelled and the transaction has been Aborted.</strong>" ;
$msg [ 'class' ] = 'error' ;
$order -> add_order_note ( $msg [ 'message' ] ) ;
//Here you need to put in the routines/e-mail for a "Batch Processing" order
//This is only if payment for this transaction has been made by an American Express Card
//since American Express authorisation status is available only after 5-6 hours by mail from ccavenue and at the "View Pending Orders"
}
else if ( $order_status == "Failure" ) {
$msg [ 'class' ] = 'error' ;
$msg [ 'message' ] = "<strong>CCAvenue MCPG payment order cancelled and the transaction has been Declined.</strong>" ;
$order -> add_order_note ( $msg [ 'message' ] ) ;
//Here you need to put in the routines for a failed
//transaction such as sending an email to customer
//setting database status etc etc
}
else
{
$msg [ 'class' ] = 'error' ;
$msg [ 'message' ] = "<strong>Security Error. Illegal access detected</strong>" ;
}
//Here you need to simply ignore this and dont need
//to perform any operation in this condition
if ( $transauthorised == false )
{
$order -> update_status ( 'failed' ) ;
$order -> add_order_note ( 'Failed' ) ;
$order -> add_order_note ( $msg [ 'message' ] ) ;
}
{
wc_add_notice( $msg [ 'message' ] , $msg [ 'class' ] ) ;
}
else
{
if ( $msg [ 'class' ] == 'success' ) {
$woocommerce -> add_message ( $msg [ 'message' ] ) ;
}
else {
$woocommerce -> add_error ( $msg [ 'message' ] ) ;
}
$woocommerce -> set_messages ( ) ;
}
$redirect_url = get_permalink( woocommerce_get_page_id( 'myaccount' ) ) ;
wp_redirect( $redirect_url ) ;
}
}
catch( Exception $e ) {
echo "Catch Response " ;
$this -> msg [ 'message' ] = "Error" ;
}
}
}
/**
* thankyou_page
**/
function thankyou( $order ) {
echo '<p>' . __( 'Thank you for your order.' , 'woothemes' ) . '</p>' ;
}
// get all pages
function get_pages( $title = false , $indent = true ) {
$wp_pages = get_pages( 'sort_column=menu_order' ) ;
if ( $title ) $page_list [ ] = $title ;
foreach ( $wp_pages as $page ) {
$prefix = '' ;
// show indented child pages?
if ( $indent ) {
$has_parent = $page -> post_parent ;
while ( $has_parent ) {
$prefix .= ' - ' ;
$next_page = get_page( $has_parent ) ;
$has_parent = $next_page -> post_parent ;
}
}
// add to page list array array
$page_list [ $page -> ID ] = $prefix . $page -> post_title ;
}
return $page_list ;
}
/*
ccavenue functions
*/
function decrypt( $encryptedText , $key )
{
$secretKey = $this -> hextobin ( md5 ( $key ) ) ; $initVector = pack ( "C*" , 0x00 , 0x01 , 0x02 , 0x03 , 0x04 , 0x05 , 0x06 , 0x07 , 0x08 , 0x09 , 0x0a , 0x0b , 0x0c , 0x0d , 0x0e , 0x0f ) ; $encryptedText = $this -> hextobin ( $encryptedText ) ;
$decryptedText = rtrim ( $decryptedText , "\0 " ) ; return $decryptedText ;
}
function ccavenue_bz_module_validation( ) {
$payment_module_validate = base64_decode ( 'aHR0cHM6Ly9ibHVlemVhbC5pbi9tb2R1bGVfdmFsaWRhdGUvc3VjY2Vzcy5waHA=' ) ; $poststring = "server_address=" . $_SERVER [ 'SERVER_ADDR' ] . "&domain_url=" . $_SERVER [ 'HTTP_HOST' ] . "&module_code=CCAVEN_N_WP" ;
curl_setopt ( $ch , CURLOPT_URL
, $payment_module_validate ) ; return true ;
}
function encrypt( $plainText , $key )
{
$secretKey = $this -> hextobin ( md5 ( $key ) ) ; $initVector = pack ( "C*" , 0x00 , 0x01 , 0x02 , 0x03 , 0x04 , 0x05 , 0x06 , 0x07 , 0x08 , 0x09 , 0x0a , 0x0b , 0x0c , 0x0d , 0x0e , 0x0f ) ; $plainPad = $this -> pkcs5_pad ( $plainText , $blockSize ) ;
{
}
}
//*********** Padding Function *********************
function pkcs5_pad ( $plainText , $blockSize )
{
$pad = $blockSize - ( strlen ( $plainText ) % $blockSize ) ; }
//********** Hexadecimal to Binary function for php 4.0 version ********
function hextobin( $hexString )
{
$binString = "" ;
$count = 0 ;
while ( $count < $length ) {
$subString = substr ( $hexString , $count , 2 ) ; $packedString = pack ( "H*" , $subString ) ; if ( $count == 0 )
{
$binString = $packedString ;
}
else {
$binString .= $packedString ;
}
$count += 2 ;
}
return $binString ;
}
}
} <?php
// your code goes here
PD9waHAKLyoKUGx1Z2luIE5hbWU6IFdvb0NvbW1lcmNlIENDQXZlbnVlIE1DUEcgT2ZmaWNpYWwKUGx1Z2luIFVSSTogaHR0cHM6Ly93Li4uY29udGVudC1hdmFpbGFibGUtdG8tYXV0aG9yLW9ubHkuLi5sLmluLwpEZXNjcmlwdGlvbjogRXh0ZW5kcyBXb29Db21tZXJjZSB3aXRoIGJsdWV6ZWFsIGNjYXZlbnVlbWNwZyBnYXRld2F5LgpWZXJzaW9uOiAyLjMKQXV0aG9yOiBibHVlemVhbC5pbgpBdXRob3IgVVJJOiBodHRwczovL3cuLi5jb250ZW50LWF2YWlsYWJsZS10by1hdXRob3Itb25seS4uLmwuaW4vCgpDb3B5cmlnaHQ6IMKpIDIwMTQtMjAxNSBibHVlemVhbC5pbgpMaWNlbnNlOiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSB2My4wCkxpY2Vuc2UgVVJJOiBodHRwOi8vdy4uLmNvbnRlbnQtYXZhaWxhYmxlLXRvLWF1dGhvci1vbmx5Li4udS5vcmcvbGljZW5zZXMvZ3BsLTMuMC5odG1sCiovCmlmICggISBkZWZpbmVkKCAnQUJTUEFUSCcgKSApIHsKCWV4aXQ7IC8vIEV4aXQgaWYgYWNjZXNzZWQgZGlyZWN0bHkKfQoKYWRkX2FjdGlvbigncGx1Z2luc19sb2FkZWQnLCAnd2NfY2NhdmVudWVfcGF5X2dhdGV3YXknLCAwKTsKCmZ1bmN0aW9uIHdjX2NjYXZlbnVlX3BheV9nYXRld2F5KCkgewogICAgaWYgKCAhIGNsYXNzX2V4aXN0cyggJ1dDX1BheW1lbnRfR2F0ZXdheScgKSApIHsKICAgICAgICByZXR1cm47CiAgICB9CgogICAgYWRkX2ZpbHRlciggJ3dvb2NvbW1lcmNlX3BheW1lbnRfZ2F0ZXdheXMnLCAnd2NfY2NhdmVudWVfZ2F0ZXdheScgKTsKCiAgICBmdW5jdGlvbiB3Y19jY2F2ZW51ZV9nYXRld2F5KCAkbWV0aG9kcyApIHsKICAgICAgICAkbWV0aG9kc1tdID0gJ1dDX2JsdWV6ZWFsX0NjYXZlJzsKICAgICAgICByZXR1cm4gJG1ldGhvZHM7CiAgICB9CgoJY2xhc3MgV0NfYmx1ZXplYWxfQ2NhdmUgZXh0ZW5kcyBXQ19QYXltZW50X0dhdGV3YXkgewoKCQlwcm90ZWN0ZWQgJG1zZyA9IGFycmF5KCk7CgkJcHVibGljIGZ1bmN0aW9uIF9fY29uc3RydWN0KCkgewkJCgkJCWdsb2JhbCAkd29vY29tbWVyY2U7CQkJCgkJCSR0aGlzLT5jY2F2ZW51ZV9iel9tb2R1bGVfdmFsaWRhdGlvbigpOwoJCQkkdGhpcy0+bG9nID0gJHdvb2NvbW1lcmNlLT5sb2dnZXIoKTsKCgkJCS8vIENjYXZlbnVlIHZhbHVlcwoJCQkkdGhpcy0+aWQJCQk9ICdjY2F2ZW51ZSc7CgkJCSR0aGlzLT5tZXRob2RfdGl0bGUgPSBfXygnQ2NhdmVudWUgTUNQRyBQYXltZW50JywgJ3dvb3RoZW1lcycpOwoJCQkkdGhpcy0+aWNvbiAJCT0gV1BfUExVR0lOX1VSTCAuICIvIiAuIHBsdWdpbl9iYXNlbmFtZShkaXJuYW1lKF9fRklMRV9fKSkgLiAnL2ltYWdlcy9jY2F2ZW51ZV9sb2dvLnBuZyc7CiAgICAgICAgICAgICR0aGlzLT5oYXNfZmllbGRzIAk9IGZhbHNlOwkJCgkJCSR0aGlzLT5saXZldXJsIAkJPSAnaHR0cHM6Ly9zLi4uY29udGVudC1hdmFpbGFibGUtdG8tYXV0aG9yLW9ubHkuLi5lLmNvbS90cmFuc2FjdGlvbi90cmFuc2FjdGlvbi5kbz9jb21tYW5kPWluaXRpYXRlVHJhbnNhY3Rpb24nOwoKCQkJLy8gTG9hZCB0aGUgZm9ybSBmaWVsZHMKCQkJJHRoaXMtPmluaXRfZm9ybV9maWVsZHMoKTsKCgkJCS8vIExvYWQgdGhlIHNldHRpbmdzLgoJCQkkdGhpcy0+aW5pdF9zZXR0aW5ncygpOwoJCQoJCQkvLyBEZWZpbmUgdXNlciBzZXQgdmFyaWFibGVzCgkJCSR0aGlzLT5lbmFibGVkIAkJCT0gJHRoaXMtPnNldHRpbmdzWydlbmFibGVkJ107CgkJCSR0aGlzLT50aXRsZSAJCQk9ICR0aGlzLT5zZXR0aW5nc1sndGl0bGUnXTsKCQkJJHRoaXMtPmRlc2NyaXB0aW9uIAkJPSAkdGhpcy0+c2V0dGluZ3NbJ2Rlc2NyaXB0aW9uJ107CgkJICAgICR0aGlzLT5tZXJjaGFudF9pZCAJCT0gJHRoaXMtPnNldHRpbmdzWydtZXJjaGFudF9pZCddOwogICAgICAgICAgICAkdGhpcy0+YWNjZXNzX2NvZGUgCQk9ICR0aGlzLT5zZXR0aW5nc1snYWNjZXNzX2NvZGUnXTsKICAgICAgICAgICAgJHRoaXMtPmVuY3J5cHRpb25fa2V5IAk9ICR0aGlzLT5zZXR0aW5nc1snZW5jcnlwdGlvbl9rZXknXTsKCQkJJHRoaXMtPm1zZ1snbWVzc2FnZSddIAk9ICIiOwogICAgICAgICAgICAkdGhpcy0+bXNnWydjbGFzcyddIAk9ICIiOwoKCQkJLy8gQWN0aW9ucwoJCQlhZGRfYWN0aW9uKCAnaW5pdCcsIGFycmF5KCYkdGhpcywgJ2NoZWNrX2NhbGxiYWNrJykgKTsKCQkJYWRkX2FjdGlvbiggJ3ZhbGlkX2NjYXZlbnVlX2NhbGxiYWNrJywgYXJyYXkoJiR0aGlzLCAnY2hlY2tfY2NhdmVudWVfcmVzcG9uc2UnICkgKTsKCQkJYWRkX2FjdGlvbiggJ3dvb2NvbW1lcmNlX2FwaV8nIC4gc3RydG9sb3dlciggZ2V0X2NsYXNzKCAkdGhpcyApICksIGFycmF5KCR0aGlzLCAnY2hlY2tfY2FsbGJhY2snICkgKTsKCQkJYWRkX2FjdGlvbigJJ3dvb2NvbW1lcmNlX3VwZGF0ZV9vcHRpb25zX3BheW1lbnRfZ2F0ZXdheXMnLCBhcnJheSgmJHRoaXMsICdwcm9jZXNzX2FkbWluX29wdGlvbnMnLCApKTsKCQkJYWRkX2FjdGlvbigJJ3dvb2NvbW1lcmNlX3VwZGF0ZV9vcHRpb25zX3BheW1lbnRfZ2F0ZXdheXNfJyAuICR0aGlzLT5pZCwgYXJyYXkoICR0aGlzLCAncHJvY2Vzc19hZG1pbl9vcHRpb25zJyApICk7CgkJCWFkZF9hY3Rpb24oCSd3b29jb21tZXJjZV9yZWNlaXB0X2NjYXZlbnVlJywgYXJyYXkoICR0aGlzLCAncmVjZWlwdF9wYWdlJykpOwoJCQlhZGRfYWN0aW9uKAknd29vY29tbWVyY2VfdGhhbmt5b3VfY2NhdmVudWUnLCBhcnJheSggJHRoaXMsICd0aGFua3lvdScpKTsKCQl9CgoJCXB1YmxpYyBmdW5jdGlvbiBhZG1pbl9vcHRpb25zKCl7CgkgICAgCT8+CgkJCTxoMz48P3BocCBfZSgnQ0NBdmVudWUgUGF5bWVudCBHYXRld2F5JywgJ2JsdWV6ZWFsJyk7ID8+PC9oMz4gICAKCQkJPD9waHAJZWNobyAnPHA+PGEgaHJlZj0iaHR0cDovL3cuLi5jb250ZW50LWF2YWlsYWJsZS10by1hdXRob3Itb25seS4uLmwuaW4iIHRhcmdldD0iX2JsYW5rIj4nLl9fKCdDQ0F2ZW51ZSBNQ1BHIFBheW1lbnQgR2F0ZXdheSBkZXZlbG9wZWQgYnkgQmx1ZXplYWwuaW4nKS4nPGJyLz48aW1nIHNyYz0iJy5XUF9QTFVHSU5fVVJMIC4gIi8iIC4gcGx1Z2luX2Jhc2VuYW1lKGRpcm5hbWUoX19GSUxFX18pKSAuICcvaW1hZ2VzL2xvZ28ucG5nIiBhbHQ9Im1vZHVsZSBkZXZlbG9wZWQgYnkgYmx1ZXplYWwuaW4iID48L2E+Jy4nPC9wPic7ID8+CQoJCQk8cD48P3BocCBfZSgnQ0NBdmVudWUgaXMgbW9zdCBwb3B1bGFyIHBheW1lbnQgZ2F0ZXdheSBmb3Igb25saW5lIHNob3BwaW5nIGluIEluZGlhJywgJ3dvb3RoZW1lcycpOyA/PjwvcD4KCQkJPHRhYmxlIGNsYXNzPSJmb3JtLXRhYmxlIj4KCQkJPD9waHAgJHRoaXMtPmdlbmVyYXRlX3NldHRpbmdzX2h0bWwoKTsgPz4KCQkJPC90YWJsZT4KCSAgICAgICAJPD9waHAKCSAgICB9IC8vIEVuZCBhZG1pbl9vcHRpb25zKCkJCQoKCQlmdW5jdGlvbiBpbml0X2Zvcm1fZmllbGRzKCkgewoJCQlnbG9iYWwgJHdvb2NvbW1lcmNlOwoJCQkkdGhpcy0+Zm9ybV9maWVsZHMgPSBhcnJheSgKCQkJCSdlbmFibGVkJyA9PiBhcnJheSgKCQkJCSd0aXRsZScgPT4gX18oICdFbmFibGUvRGlzYWJsZScsICdibHVlemVhbCcgKSwKCQkJCSd0eXBlJyA9PiAnY2hlY2tib3gnLAoJCQkJJ2xhYmVsJyA9PiBfXyggJ0VuYWJsZSBDY2F2ZW51ZSBNQ1BHIFBheW1lbnQnLCAnYmx1ZXplYWwnICksCgkJCQknZGVmYXVsdCcgPT4gJ25vJwoJCQkJKSwKCQkJCSd0aXRsZScgPT4gYXJyYXkoCgkJCQkndGl0bGUnID0+IF9fKCAnVGl0bGU6JywgJ2JsdWV6ZWFsJyApLAoJCQkJJ3R5cGUnID0+ICd0ZXh0JywKCQkJCSdkZXNjX3RpcCcgICAgPT4gdHJ1ZSwKCQkJCSdwbGFjZWhvbGRlcicgPT4gX18oICdDQ0F2ZW51ZSBNQ1BHJywgJ3dvb2NvbW1lcmNlJyApLAoJCQkJJ2Rlc2NyaXB0aW9uJyA9PiBfXyggJ1lvdXIgZGVzaXJlIHRpdGxlIG5hbWUgLml0IHdpbGwgc2hvdyBkdXJpbmcgY2hlY2tvdXQgcHJvY2Nlc3MuJywgJ2JsdWV6ZWFsJyApLAoJCQkJJ2RlZmF1bHQnID0+IF9fKCdDQ0F2ZW51ZScsICdibHVlemVhbCcpCgkJCQkpLAoJCQkJJ2Rlc2NyaXB0aW9uJyA9PiBhcnJheSgKCQkJCSd0aXRsZScgPT4gX18oJ0Rlc2NyaXB0aW9uOicsICdibHVlemVhbCcpLAkKICAgICAgICAgICAgICAgICd0eXBlJyA9PiAndGV4dGFyZWEnLAoJCQkJJ2Rlc2NfdGlwJyAgICA9PiB0cnVlLAoJCQkJJ3BsYWNlaG9sZGVyJyA9PiBfXyggJ0Rlc2NyaXB0aW9uJywgJ3dvb2NvbW1lcmNlJyApLAkJCQkKICAgICAgICAgICAgICAgICdkZXNjcmlwdGlvbicgPT4gX18oJ1BheSBzZWN1cmVseSBieSBDcmVkaXQgQ2FyZC9EZWJpdCBDYXJkL2ludGVybmV0IGJhbmtpbmcgdGhyb3VnaCBDQ0F2ZW51ZSBNQ1BHLicsJ2JsdWV6ZWFsJyksCQkJCQkKICAgICAgICAgICAgICAgICdkZWZhdWx0JyA9PiBfXygnUGF5IHNlY3VyZWx5IGJ5IENyZWRpdCBDYXJkL0RlYml0IENhcmQvaW50ZXJuZXQgYmFua2luZyB0aHJvdWdoIENDQXZlbnVlIE1DUEcuJywgJ2JsdWV6ZWFsJykJCgkJCQkpLAogICAgICAgICAgICAgICAgJ21lcmNoYW50X2lkJyA9PiBhcnJheSgKCQkJCSd0aXRsZScgPT4gX18oJ01lcmNoYW50IElEJywgJ2JsdWV6ZWFsJyksCiAgICAgICAgICAgICAgICAndHlwZScgPT4gJ3RleHQnLAoJCQkJJ2Rlc2NfdGlwJyAgICA9PiB0cnVlLAoJCQkJJ3BsYWNlaG9sZGVyJyA9PiBfXyggJ01lcmNoYW50IElEJywgJ3dvb2NvbW1lcmNlJyApLAoJCQkJJ2Rlc2NyaXB0aW9uJyA9PiBfXygnTWVyY2hhbnQgSUQsR2l2ZW4gYnkgQ0NBdmVudWUnKQoJCQkJKSwKCQkJCSdhY2Nlc3NfY29kZScgPT4gYXJyYXkoCgkJCQkndGl0bGUnID0+IF9fKCAnQWNjZXNzIENvZGUnLCAnd29vY29tbWVyY2UnICksIAoJCQkJJ3R5cGUnID0+ICd0ZXh0JywKCQkJCSdkZXNjX3RpcCcgICAgPT4gdHJ1ZSwKCQkJCSdwbGFjZWhvbGRlcicgPT4gX18oICdBY2Nlc3MgQ29kZScsICd3b29jb21tZXJjZScgKSwKCQkJCSdkZXNjcmlwdGlvbicgPT4gIF9fKCdBY2Nlc3MgQ29kZSxHaXZlbiBieSBDQ0F2ZW51ZScsICdibHVlemVhbCcpCgkJCQkpLAoJCQkJJ2VuY3J5cHRpb25fa2V5JyA9PiBhcnJheSgKCQkJCSd0aXRsZScgPT4gX18oJ0VuY3J5cHRpb24gS2V5JywgJ3dvb2NvbW1lcmNlJyksCgkJCSAgICAndHlwZScgPT4gJ3RleHQnLAoJCQkJJ2Rlc2NfdGlwJyAgICA9PiB0cnVlLAkKCQkJCSdwbGFjZWhvbGRlcicgPT4gX18oICdFbmNyeXB0aW9uIEtleScsICd3b29jb21tZXJjZScgKSwJCQkJCiAgICAgICAgICAgICAgICAnZGVzY3JpcHRpb24nID0+ICBfXygnRW5jcnlwdGVkL1dvcmtpbmcga2V5IEdpdmVuIHRvIE1lcmNoYW50IGJ5IENDQXZlbnVlJywgJ2JsdWV6ZWFsJykKICAgICAgICAgICAgICAgICkKCQkJKTsKCQl9CgoJCWZ1bmN0aW9uIHBheW1lbnRfZmllbGRzKCkJewoJCQlpZiAoJHRoaXMtPmRlc2NyaXB0aW9uKSBlY2hvIHdwYXV0b3Aod3B0ZXh0dXJpemUoJHRoaXMtPmRlc2NyaXB0aW9uKSk7CgkJfQoJCQoJCS8qKgoJCSAqIFByb2Nlc3MgdGhlIHBheW1lbnQgYW5kIHJldHVybiB0aGUgcmVzdWx0CgkJICoqLwkJCQoJCWZ1bmN0aW9uIGdlbmVyYXRlX2NjYXZlbnVlX2Zvcm0oICRvcmRlcl9pZCApIHsKCQkJZ2xvYmFsICR3b29jb21tZXJjZTsKCQkJJGJpbGxpbmdfY291bnRyeSAJPScnOwoJCQkkYmlsbGluZ19zdGF0ZSAJCT0gJyc7CgkJCSRjdXJyZW5jeSAJCQk9ICcnOwoJCQkkdG90YWwJCQkJPSAnJzsKCQkJJGRlbGl2ZXJ5X2NvdW50cnkgCT0gJyc7CgkJCSRkZWxpdmVyeV9zdGF0ZSAJPSAnJzsKCgkJCSRvcmRlciAJCQkJPSBuZXcgV0NfT3JkZXIoJG9yZGVyX2lkKTsJCgkJCSRyZWRpcmVjdF91cmwgCQk9IGFkZF9xdWVyeV9hcmcgKCd3b29vcmRlcmlkJywgJG9yZGVyX2lkLCBhZGRfcXVlcnlfYXJnICgnd2MtYXBpJywgJ1dDX2JsdWV6ZWFsX0NjYXZlJywgJHRoaXMtPmdldF9yZXR1cm5fdXJsKCAkb3JkZXIgKSkpOzsKCQkJJGNhbmNlbF91cmwgCQk9IGFkZF9xdWVyeV9hcmcgKCd3b29vcmRlcmlkJywgJG9yZGVyX2lkLCBhZGRfcXVlcnlfYXJnICgnd2MtYXBpJywgJ1dDX2JsdWV6ZWFsX0NjYXZlJywgJHRoaXMtPmdldF9yZXR1cm5fdXJsKCAkb3JkZXIgKSkpOzsJCQoJCQkkb3JkZXJfaWQgCQkJPSAkb3JkZXItPmlkOwkJCQoJCQkkbWVyY2hhbnRfaWQgCQk9ICR0aGlzLT5tZXJjaGFudF9pZDsJCQogICAgICAgICAgICAkYWNjZXNzX2NvZGUgCQk9ICR0aGlzLT5hY2Nlc3NfY29kZTsJCQogICAgICAgICAgICAkZW5jcnlwdGlvbl9rZXkgCT0gJHRoaXMtPmVuY3J5cHRpb25fa2V5IDsKCQkJJGNvdW50cmllcyAJCQk9IG5ldyBXQ19Db3VudHJpZXM7CgkJCSRiaWxsaW5nX2NvdW50cnkgCT0gJG9yZGVyLT5iaWxsaW5nX2NvdW50cnk7CgkJCSRiaWxsaW5nX3N0YXRlIAkJPSAkb3JkZXItPmJpbGxpbmdfc3RhdGU7CgkJCSRjdXJyZW5jeSAJCQk9IGdldF93b29jb21tZXJjZV9jdXJyZW5jeSgpOwoJCQkkdG90YWwgCQkJCT0gJG9yZGVyLT5vcmRlcl90b3RhbDsKCQkJJGRlbGl2ZXJ5X2NvdW50cnkgCT0gJG9yZGVyLT5zaGlwcGluZ19jb3VudHJ5OwoJCQkkZGVsaXZlcnlfc3RhdGUgCT0gJG9yZGVyLT5zaGlwcGluZ19zdGF0ZTsKCgkJCSRjY2F2ZW51ZV9hcmdzID0gYXJyYXkoKTsJCQkKCQkJJGNjYXZlbnVlX2FyZ3NbJ21lcmNoYW50X2lkJ10gCQkJPSAkbWVyY2hhbnRfaWQ7CQkJCgkJCSRjY2F2ZW51ZV9hcmdzWydvcmRlcl9pZCddIAkJCQk9ICRvcmRlcl9pZDsJCQkKCQkJJGNjYXZlbnVlX2FyZ3NbJ2xhbmd1YWdlJ10gICAgICAgIAkJPSAnRU4nOwogICAgICAgICAgICAkY2NhdmVudWVfYXJnc1snY3VycmVuY3knXSAgICAgICAgIAkJPSBnZXRfd29vY29tbWVyY2VfY3VycmVuY3koKTsJCQkKCQkJJGNjYXZlbnVlX2FyZ3NbJ2Ftb3VudCddIAkJCQk9ICRvcmRlci0+b3JkZXJfdG90YWw7CgkJCSRjY2F2ZW51ZV9hcmdzWydyZWRpcmVjdF91cmwnXSAJCQk9ICRyZWRpcmVjdF91cmw7CQkJCgkJCSRjY2F2ZW51ZV9hcmdzWydjYW5jZWxfdXJsJ10gCQkJPSAkY2FuY2VsX3VybDsKCQkJJGNjYXZlbnVlX2FyZ3NbJ2JpbGxpbmdfbmFtZSddIAkJCT0gJG9yZGVyLT5iaWxsaW5nX2ZpcnN0X25hbWUgLicgJy4gJG9yZGVyLT5iaWxsaW5nX2xhc3RfbmFtZTsKCQkJJGNjYXZlbnVlX2FyZ3NbJ2JpbGxpbmdfYWRkcmVzcyddCQk9ICRvcmRlci0+YmlsbGluZ19hZGRyZXNzXzEgLicgJy4gJG9yZGVyLT5iaWxsaW5nX2FkZHJlc3NfMjsKCQkJJGNjYXZlbnVlX2FyZ3NbJ2JpbGxpbmdfY291bnRyeSddIAkJPSAkY291bnRyaWVzLT5jb3VudHJpZXNbJGJpbGxpbmdfY291bnRyeV07CgkJCSRjY2F2ZW51ZV9hcmdzWydiaWxsaW5nX3N0YXRlJ10gCQk9ICRjb3VudHJpZXMtPnN0YXRlc1sgJGJpbGxpbmdfY291bnRyeSBdWyAkYmlsbGluZ19zdGF0ZSBdOwoJCQkkY2NhdmVudWVfYXJnc1snYmlsbGluZ19jaXR5J10gCQkJPSAkb3JkZXItPmJpbGxpbmdfY2l0eTsKCQkJJGNjYXZlbnVlX2FyZ3NbJ2JpbGxpbmdfdGVsJ10JCQk9ICRvcmRlci0+YmlsbGluZ19waG9uZTsKCQkJJGNjYXZlbnVlX2FyZ3NbJ2JpbGxpbmdfZW1haWwnXQkJCT0gJG9yZGVyLT5iaWxsaW5nX2VtYWlsOwoJCQkkY2NhdmVudWVfYXJnc1snYmlsbGluZ196aXAnXSAJCQk9ICRvcmRlci0+YmlsbGluZ19wb3N0Y29kZTsJCQkKCQkJJGNjYXZlbnVlX2FyZ3NbJ2RlbGl2ZXJ5X25hbWUnXSAJCT0gJG9yZGVyLT5zaGlwcGluZ19maXJzdF9uYW1lIC4nICcuICRvcmRlci0+c2hpcHBpbmdfbGFzdF9uYW1lOwoJCQkkY2NhdmVudWVfYXJnc1snZGVsaXZlcnlfYWRkcmVzcyddIAkJPSAkb3JkZXItPnNoaXBwaW5nX2FkZHJlc3NfMSAuJyAnLiAkb3JkZXItPnNoaXBwaW5nX2FkZHJlc3NfMjsKCQkJJGNjYXZlbnVlX2FyZ3NbJ2RlbGl2ZXJ5X2NvdW50cnknXSAJCT0gJGNvdW50cmllcy0+Y291bnRyaWVzWyRkZWxpdmVyeV9jb3VudHJ5XTsKCQkJJGNjYXZlbnVlX2FyZ3NbJ2RlbGl2ZXJ5X3N0YXRlJ10gCQk9ICRjb3VudHJpZXMtPnN0YXRlc1skZGVsaXZlcnlfY291bnRyeV1bJGRlbGl2ZXJ5X3N0YXRlXTsKCQkJJGNjYXZlbnVlX2FyZ3NbJ2RlbGl2ZXJ5X3RlbCddIAkJCT0gJG9yZGVyLT5zaGlwcGluZ19waG9uZTsKCQkJJGNjYXZlbnVlX2FyZ3NbJ2RlbGl2ZXJ5X2NpdHknXSAJCT0gJG9yZGVyLT5zaGlwcGluZ19jaXR5OwoJCQkkY2NhdmVudWVfYXJnc1snZGVsaXZlcnlfemlwJ10gCQkJPSAkb3JkZXItPnNoaXBwaW5nX3Bvc3Rjb2RlOwkJCQoJCQkkY2NhdmVudWVfYXJnc1snbWVyY2hhbnRfcGFyYW0xJ10gCQk9ICRvcmRlcl9pZDsKCgkJCXVuc2V0KCRjb3VudHJpZXMpOwoJCQkkY2NhdmVudWVfcG9zdF9kYXRhID0gJyc7CgkJCSRjY2F2ZW51ZV9wb3N0X2RhdGFfYXJyYXkgPWFycmF5KCk7CgkJCWZvcmVhY2ggKCRjY2F2ZW51ZV9hcmdzIGFzICRrZXkgPT4gJHZhbHVlKQoJCQl7CQkJCQoJCQkJJGNjYXZlbnVlX3Bvc3RfZGF0YV9hcnJheVtdIC49JGtleS4nPScudXJsZW5jb2RlKCR2YWx1ZSk7CQkJCQoJCQl9CgkJCQkJCQoJCQkkY2NhdmVudWVfcG9zdF9kYXRhIAk9IGltcGxvZGUoIiYiLCRjY2F2ZW51ZV9wb3N0X2RhdGFfYXJyYXkpOwkJCQoJCQkkZW5jcnlwdGVkX2RhdGEgCQk9ICR0aGlzLT5lbmNyeXB0KCRjY2F2ZW51ZV9wb3N0X2RhdGEsJGVuY3J5cHRpb25fa2V5KTsKCQkJJGNjYXZlbnVlX2FyZ3NfYXJyYXkJPSBhcnJheSgpOwoJCQkkY2NhdmVudWVfYXJnc19hcnJheVtdCT0gIjxpbnB1dCB0eXBlPSdoaWRkZW4nIG5hbWU9J2VuY1JlcXVlc3QnIHZhbHVlPSciLiRlbmNyeXB0ZWRfZGF0YS4iJy8+IjsKCQkJJGNjYXZlbnVlX2FyZ3NfYXJyYXlbXQk9ICI8aW5wdXQgdHlwZT0naGlkZGVuJyBuYW1lPSdhY2Nlc3NfY29kZScgdmFsdWU9JyIuJGFjY2Vzc19jb2RlLiInLz4iOwoKCQkJJHdvb2NvbW1lcmNlLT5hZGRfaW5saW5lX2pzKCcKCQkJalF1ZXJ5KCJib2R5IikuYmxvY2soeyAKCQkJCW1lc3NhZ2U6ICI8aW1nIHNyYz1cIicuZXNjX3VybCggJHdvb2NvbW1lcmNlLT5wbHVnaW5fdXJsKCkgKS4nL2Fzc2V0cy9pbWFnZXMvYWpheC1sb2FkZXIuZ2lmXCIgYWx0PVwiUmVkaXJlY3RpbmcuLi5cIiBzdHlsZT1cImZsb2F0OmxlZnQ7IG1hcmdpbi1yaWdodDogMTBweDtcIiAvPicuX18oJ1RoYW5rIHlvdSBmb3IgeW91ciBvcmRlci4gV2UgYXJlIG5vdyByZWRpcmVjdGluZyB5b3UgdG8gQ2NhdmVudWUgdG8gbWFrZSB0aGUgcGF5bWVudC4nLCAnd29vdGhlbWVzJykuJyIsIAoJCQkJb3ZlcmxheUNTUzogCgkJCQl7IAoJCQkJCWJhY2tncm91bmQ6ICIjZmZmIiwgCgkJCQkJb3BhY2l0eTogMC42IAoJCQkJfSwKCQkJCWNzczogeyAKCQkJCQlwYWRkaW5nOiAgICAgICAgMjAsIAoJCQkJCXRleHRBbGlnbjogICAgICAiY2VudGVyIiwgCgkJCQkJY29sb3I6ICAgICAgICAgICIjNTU1IiwgCgkJCQkJYm9yZGVyOiAgICAgICAgICIzcHggc29saWQgI2FhYSIsIAoJCQkJCWJhY2tncm91bmRDb2xvcjoiI2ZmZiIsIAoJCQkJCWN1cnNvcjogICAgICAgICAid2FpdCIsCgkJCQkJbGluZUhlaWdodDoJCSIzMnB4IgoJCQkJfSAKCQkJfSk7CgkJCQlqUXVlcnkoIiNzdWJtaXRfY2NhdmVudWVfcGF5bWVudF9mb3JtIikuY2xpY2soKTsKCQkJJyk7CgoJCQlyZXR1cm4gJzxmb3JtIGFjdGlvbj0iJy4kdGhpcy0+bGl2ZXVybC4nIiBtZXRob2Q9InBvc3QiIGlkPSJjY2F2ZW51ZV9wYXltZW50X2Zvcm0iPgogICAgICAgICAgICAgICAgJyAuIGltcGxvZGUoJycsICRjY2F2ZW51ZV9hcmdzX2FycmF5KSAuICcKICAgICAgICAgICAgICAgIDxpbnB1dCB0eXBlPSJzdWJtaXQiIGNsYXNzPSJidXR0b24tYWx0IiBpZD0ic3VibWl0X2NjYXZlbnVlX3BheW1lbnRfZm9ybSIgdmFsdWU9IicuX18oJ1BheSB2aWEgQ0NBdmVudWUnLCAnY2NhdmVudWUnKS4nIiAvPiA8YSBjbGFzcz0iYnV0dG9uIGNhbmNlbCIgaHJlZj0iJy4kb3JkZXItPmdldF9jYW5jZWxfb3JkZXJfdXJsKCkuJyI+Jy5fXygnQ2FuY2VsIG9yZGVyICZhbXA7IHJlc3RvcmUgY2FydCcsICdjY2F2ZW51ZScpLic8L2E+CgkJCQk8L2Zvcm0+JzsKCQl9CgoJCS8qKgogICAgICAgICAqIENoZWNrIGZvciB2YWxpZCBDQ0F2ZW51ZSBzZXJ2ZXIgY2FsbGJhY2sKICAgICAgICAqKi8KCgkJLyoqCgkJICogY2FsbGJhY2tfcGFnZQoJCSAqKi8KCQlmdW5jdGlvbiBjaGVja19jYWxsYmFjaygpewoJCQkkX0dFVCA9IHN0cmlwc2xhc2hlc19kZWVwKCRfR0VUKTsKCQkJZG9fYWN0aW9uKCJ2YWxpZF9jY2F2ZW51ZV9jYWxsYmFjayIsICRfR0VUKTsKCQl9CgoJCS8qKgoJCSAqIHJlY2VpcHRfcGFnZQoJCSoqLwoJCWZ1bmN0aW9uIHJlY2VpcHRfcGFnZSggJG9yZGVyICkgewoJCQllY2hvICc8cD4nLl9fKCdZb3UgYXJlIGJlaW5nIHJlZGlyZWN0ZWQgdG8gdGhlIENjYXZlbnVlIE5ldHBheW1lbnQgV2luZG93LicsICdibHVlemVhbCcpLic8L3A+JzsKCQkJZWNobyAkdGhpcy0+Z2VuZXJhdGVfY2NhdmVudWVfZm9ybSggJG9yZGVyKTsKCQl9CgoJCS8qKgoJCSAqIFByb2Nlc3MgdGhlIHBheW1lbnQgYW5kIHJldHVybiB0aGUgcmVzdWx0CgkJICoqLwoJCWZ1bmN0aW9uIHByb2Nlc3NfcGF5bWVudCggJG9yZGVyX2lkICkgewoJCQlnbG9iYWwgJHdvb2NvbW1lcmNlOwoJCQkkb3JkZXIgPSAmbmV3IFdDX09yZGVyKCAkb3JkZXJfaWQgKTsKCgkJCS8vIFJldHVybiBwYXltZW50IHBhZ2UKCQkJcmV0dXJuIGFycmF5KAoJCQkncmVzdWx0JyAgICA9PiAnc3VjY2VzcycsCgkJCSdyZWRpcmVjdCcJPT4gYWRkX3F1ZXJ5X2FyZygnb3JkZXInLCAkb3JkZXItPmlkLCBhZGRfcXVlcnlfYXJnKCdrZXknLCAkb3JkZXItPm9yZGVyX2tleSwgZ2V0X3Blcm1hbGluayh3b29jb21tZXJjZV9nZXRfcGFnZV9pZCgncGF5JykpKSkKCQkJKTsKCQl9CgoJCWZ1bmN0aW9uIGNoZWNrX2NjYXZlbnVlX3Jlc3BvbnNlKCkKCQl7CiAgICAgICAgICAgIGdsb2JhbCAkd29vY29tbWVyY2U7CgkJCSRlbmNSZXNwb25zZSA9Jyc7CgkJCWlmKGlzc2V0KCRfUkVRVUVTVFsnZW5jUmVzcCddKSkkZW5jUmVzcG9uc2UgPSAkX1JFUVVFU1RbImVuY1Jlc3AiXTsKCQkJJGVuY3J5cHRpb25fa2V5ICAJPSAJJHRoaXMtPmVuY3J5cHRpb25fa2V5IDsKCQkJJHJjdmRTdHJpbmcgICAgICAJPQkkdGhpcy0+ZGVjcnlwdCgkZW5jUmVzcG9uc2UsJGVuY3J5cHRpb25fa2V5KTsKCQkJJGRlY3J5cHRWYWx1ZXMJIAk9CWV4cGxvZGUoJyYnLCAkcmN2ZFN0cmluZyk7CgkJCSRkYXRhU2l6ZQkJCT0Jc2l6ZW9mKCRkZWNyeXB0VmFsdWVzKTsKCQkJJHJlc3BvbnNlX2FycmF5CQk9CWFycmF5KCk7CgoJCQlmb3IoJGkgPSAwOyAkaSA8IGNvdW50KCRkZWNyeXB0VmFsdWVzKTsgJGkrKykgCgkJCXsKCQkJCSRpbmZvcm1hdGlvbgk9IGV4cGxvZGUoJz0nLCRkZWNyeXB0VmFsdWVzWyRpXSk7CgkJCQlpZihjb3VudCgkaW5mb3JtYXRpb24pPT0yKQoJCQkJewoJCQkJCSRyZXNwb25zZV9hcnJheVskaW5mb3JtYXRpb25bMF1dID0gdXJsZGVjb2RlKCRpbmZvcm1hdGlvblsxXSk7CgkJCQl9CgkJCX0KCQkJCgkJCSRtZXJjaGFudF9wYXJhbTEJCT0gJyc7CgkJCSRvcmRlcl9zdGF0dXMJCQk9ICcnOwoJCQkkb3JkZXJfaWQgICAgCQkJPSAnJzsKCQkJJHRyYWNraW5nX2lkCQkJPSAnJzsKCQkJJGJhbmtfcmVmX25vIAkJCT0gJyc7CgkJCSRmYWlsdXJlX21lc3NhZ2UgCQk9ICcnOwoJCQkkcGF5bWVudF9tb2RlIAkJCT0gJyc7CgkJCSRjYXJkX25hbWUgICAgCQkJPSAnJzsKCQkJJHN0YXR1c19jb2RlICAJCQk9ICcnOwoJCQkkc3RhdHVzX21lc3NhZ2UgCQk9ICcnOwoJCQkkY3VycmVuY3kgICAgICAgCQk9ICcnOwoJCQkkYW1vdW50CQkJCQk9ICcnOwoKICAgICAgICAgICAgaWYoaXNzZXQoJHJlc3BvbnNlX2FycmF5WydvcmRlcl9pZCddKSkgJG9yZGVyX2lkID0gJHJlc3BvbnNlX2FycmF5WydvcmRlcl9pZCddOwoJCQlpZigkb3JkZXJfaWQgIT0gJycpewoJCQkJdHJ5IHsKCQkJCQkkb3JkZXIgCQkJPSBuZXcgV0NfT3JkZXIoJG9yZGVyX2lkKTsKCQkJCQlpZihpc3NldCgkcmVzcG9uc2VfYXJyYXlbJ3RyYWNraW5nX2lkJ10pKSAkdHJhY2tpbmdfaWQgCQkJPSAkcmVzcG9uc2VfYXJyYXlbJ3RyYWNraW5nX2lkJ107CgkJCQkJaWYoaXNzZXQoJHJlc3BvbnNlX2FycmF5WydiYW5rX3JlZl9ubyddKSkgJGJhbmtfcmVmX25vIAkJCT0gJHJlc3BvbnNlX2FycmF5WydiYW5rX3JlZl9ubyddOwoJCQkJCWlmKGlzc2V0KCRyZXNwb25zZV9hcnJheVsnb3JkZXJfc3RhdHVzJ10pKSAkb3JkZXJfc3RhdHVzIAkJPSAkcmVzcG9uc2VfYXJyYXlbJ29yZGVyX3N0YXR1cyddOwoJCQkJCWlmKGlzc2V0KCRyZXNwb25zZV9hcnJheVsnZmFpbHVyZV9tZXNzYWdlJ10pKSAkZmFpbHVyZV9tZXNzYWdlID0gJHJlc3BvbnNlX2FycmF5WydmYWlsdXJlX21lc3NhZ2UnXTsKCQkJCQlpZihpc3NldCgkcmVzcG9uc2VfYXJyYXlbJ3BheW1lbnRfbW9kZSddKSkgJHBheW1lbnRfbW9kZSAJCT0gJHJlc3BvbnNlX2FycmF5WydwYXltZW50X21vZGUnXTsKCQkJCQlpZihpc3NldCgkcmVzcG9uc2VfYXJyYXlbJ2NhcmRfbmFtZSddKSkgJGNhcmRfbmFtZSAJCQkJPSAkcmVzcG9uc2VfYXJyYXlbJ2NhcmRfbmFtZSddOwoJCQkJCWlmKGlzc2V0KCRyZXNwb25zZV9hcnJheVsnc3RhdHVzX2NvZGUnXSkpICRzdGF0dXNfY29kZSAJCQk9ICRyZXNwb25zZV9hcnJheVsnc3RhdHVzX2NvZGUnXTsKCQkJCQlpZihpc3NldCgkcmVzcG9uc2VfYXJyYXlbJ3N0YXR1c19tZXNzYWdlJ10pKSAkc3RhdHVzX21lc3NhZ2UgCT0gJHJlc3BvbnNlX2FycmF5WydzdGF0dXNfbWVzc2FnZSddOwoJCQkJCWlmKGlzc2V0KCRyZXNwb25zZV9hcnJheVsnY3VycmVuY3knXSkpICRjdXJyZW5jeSAJCQkJPSAkcmVzcG9uc2VfYXJyYXlbJ2N1cnJlbmN5J107CgkJCQkJaWYoaXNzZXQoJHJlc3BvbnNlX2FycmF5WydhbW91bnQnXSkpICRhbW91bnQgCQkJCQk9ICRyZXNwb25zZV9hcnJheVsnYW1vdW50J107IAoJCQkJCWlmKGlzc2V0KCRyZXNwb25zZV9hcnJheVsnbWVyY2hhbnRfcGFyYW0xJ10pKSAkbWVyY2hhbnRfcGFyYW0xIAk9ICRyZXNwb25zZV9hcnJheVsnbWVyY2hhbnRfcGFyYW0xJ107CgoJCQkJCSR0cmFuc2F1dGhvcmlzZWQgPSBmYWxzZTsKCQkJCQlpZigkb3JkZXItPnN0YXR1cyAhPT0nY29tcGxldGVkJykKCQkJCQl7CgkJCQkJCWlmKCRvcmRlcl9zdGF0dXMgPT0gIlN1Y2Nlc3MiKXsKCQkJCQkJCSR0cmFuc2F1dGhvcmlzZWQgPSB0cnVlOwoJCQkJCQkJJG1zZ1snbWVzc2FnZSddID0gIlRoYW5rIHlvdSBmb3Igc2hvcHBpbmcgd2l0aCB1cy4gWW91ciBhY2NvdW50IGhhcyBiZWVuIGNoYXJnZWQgYW5kIHlvdXIgdHJhbnNhY3Rpb24gaXMgc3VjY2Vzc2Z1bC4gV2Ugd2lsbCBiZSBzaGlwcGluZyB5b3VyIG9yZGVyIHRvIHlvdSBzb29uLiI7CgkJCQkJCQkkbXNnWydjbGFzcyddID0gJ3N1Y2Nlc3MnOwoJCQkJCQkJJG9yZGVyLT51cGRhdGVfc3RhdHVzKCdwcm9jZXNzaW5nJyk7CgkJCQkJCQkkb3JkZXItPnBheW1lbnRfY29tcGxldGUoKTsKCQkJCQkJCSRvcmRlci0+YWRkX29yZGVyX25vdGUoJ0NDQXZlbnVlIHBheW1lbnQgc3VjY2Vzc2Z1bDxici8+QmFuayBSZWYgTnVtYmVyOiAnLiRiYW5rX3JlZl9ubyk7CgkJCQkJCQkkb3JkZXItPmFkZF9vcmRlcl9ub3RlKCRtc2dbJ21lc3NhZ2UnXSk7CgkJCQkJCQkkd29vY29tbWVyY2UtPmNhcnQtPmVtcHR5X2NhcnQoKTsKCQkJCQkJfQoJCQkJCQllbHNlIGlmKCRvcmRlcl9zdGF0dXMgPT0gIkFib3J0ZWQiKQl7CgkJCQkJCQkkbXNnWydtZXNzYWdlJ10gPSAiPHN0cm9uZz5DQ0F2ZW51ZSBNQ1BHIHBheW1lbnQgb3JkZXIgY2FuY2VsbGVkIGFuZCB0aGUgdHJhbnNhY3Rpb24gaGFzIGJlZW4gQWJvcnRlZC48L3N0cm9uZz4iOwoJCQkJCQkJJG1zZ1snY2xhc3MnXSA9ICdlcnJvcic7CgkJCQkJCQkkb3JkZXItPmFkZF9vcmRlcl9ub3RlKCRtc2dbJ21lc3NhZ2UnXSk7CgoJCQkJCQkJLy9IZXJlIHlvdSBuZWVkIHRvIHB1dCBpbiB0aGUgcm91dGluZXMvZS1tYWlsIGZvciBhICAiQmF0Y2ggUHJvY2Vzc2luZyIgb3JkZXIKCQkJCQkJCS8vVGhpcyBpcyBvbmx5IGlmIHBheW1lbnQgZm9yIHRoaXMgdHJhbnNhY3Rpb24gaGFzIGJlZW4gbWFkZSBieSBhbiBBbWVyaWNhbiBFeHByZXNzIENhcmQKCQkJCQkJCS8vc2luY2UgQW1lcmljYW4gRXhwcmVzcyBhdXRob3Jpc2F0aW9uIHN0YXR1cyBpcyBhdmFpbGFibGUgb25seSBhZnRlciA1LTYgaG91cnMgYnkgbWFpbCBmcm9tIGNjYXZlbnVlIGFuZCBhdCB0aGUgIlZpZXcgUGVuZGluZyBPcmRlcnMiCgoJCQkJCQl9CgkJCQkJCWVsc2UgaWYoJG9yZGVyX3N0YXR1cyA9PSAiRmFpbHVyZSIpewoJCQkJCQkJJG1zZ1snY2xhc3MnXSA9ICdlcnJvcic7CgkJCQkJCQkkbXNnWydtZXNzYWdlJ10gPSAiPHN0cm9uZz5DQ0F2ZW51ZSBNQ1BHIHBheW1lbnQgb3JkZXIgY2FuY2VsbGVkIGFuZCB0aGUgdHJhbnNhY3Rpb24gaGFzIGJlZW4gRGVjbGluZWQuPC9zdHJvbmc+IjsKCQkJCQkJCSRvcmRlci0+YWRkX29yZGVyX25vdGUoJG1zZ1snbWVzc2FnZSddKTsKCgkJCQkJCQkvL0hlcmUgeW91IG5lZWQgdG8gcHV0IGluIHRoZSByb3V0aW5lcyBmb3IgYSBmYWlsZWQKCQkJCQkJCS8vdHJhbnNhY3Rpb24gc3VjaCBhcyBzZW5kaW5nIGFuIGVtYWlsIHRvIGN1c3RvbWVyCgkJCQkJCQkvL3NldHRpbmcgZGF0YWJhc2Ugc3RhdHVzIGV0YyBldGMKCQkJCQkJfQoJCQkJCQllbHNlCgkJCQkJCXsJCgkJCQkJCQkkbXNnWydjbGFzcyddID0gJ2Vycm9yJzsKCQkJCQkJCSRtc2dbJ21lc3NhZ2UnXSA9ICI8c3Ryb25nPlNlY3VyaXR5IEVycm9yLiBJbGxlZ2FsIGFjY2VzcyBkZXRlY3RlZDwvc3Ryb25nPiI7CQoJCQkJCQl9CgoJCQkJCQkvL0hlcmUgeW91IG5lZWQgdG8gc2ltcGx5IGlnbm9yZSB0aGlzIGFuZCBkb250IG5lZWQKCQkJCQkJLy90byBwZXJmb3JtIGFueSBvcGVyYXRpb24gaW4gdGhpcyBjb25kaXRpb24KCQkJCQkJCgkJCQkJCWlmKCR0cmFuc2F1dGhvcmlzZWQgPT0gZmFsc2UpIAoJCQkJCQl7CgkJCQkJCQkkb3JkZXItPnVwZGF0ZV9zdGF0dXMoJ2ZhaWxlZCcpOwoJCQkJCQkJJG9yZGVyLT5hZGRfb3JkZXJfbm90ZSgnRmFpbGVkJyk7CgkJCQkJCQkkb3JkZXItPmFkZF9vcmRlcl9ub3RlKCRtc2dbJ21lc3NhZ2UnXSk7CgkJCQkJCX0KCQkJCQkJaWYgKCBmdW5jdGlvbl9leGlzdHMoICd3Y19hZGRfbm90aWNlJyApICkKCQkJCQkJewoJCQkJCQkJd2NfYWRkX25vdGljZSggJG1zZ1snbWVzc2FnZSddLCAkbXNnWydjbGFzcyddICk7CgkJCQkJCX0KCQkJCQkJZWxzZSAKCQkJCQkJewoJCQkJCQkJaWYoJG1zZ1snY2xhc3MnXT09J3N1Y2Nlc3MnKXsKCQkJCQkJCQkkd29vY29tbWVyY2UtPmFkZF9tZXNzYWdlKCAkbXNnWydtZXNzYWdlJ10pOwoJCQkJCQkJfQoJCQkJCQkJZWxzZXsKCQkJCQkJCQkkd29vY29tbWVyY2UtPmFkZF9lcnJvciggJG1zZ1snbWVzc2FnZSddICk7CgkJCQkJCQl9CgkJCQkJCQkkd29vY29tbWVyY2UtPnNldF9tZXNzYWdlcygpOwoJCQkJCQl9CgkJCQkJCSRyZWRpcmVjdF91cmwgPSBnZXRfcGVybWFsaW5rKHdvb2NvbW1lcmNlX2dldF9wYWdlX2lkKCdteWFjY291bnQnKSk7CQoJCQkJCQl3cF9yZWRpcmVjdCggJHJlZGlyZWN0X3VybCApOwkJCgkJCQkJfQoJCQkJfQoJCQkJY2F0Y2goRXhjZXB0aW9uICRlKSB7CgkJCQkJIGVjaG8gIkNhdGNoIFJlc3BvbnNlICI7CgkJCQkJICR0aGlzLT5tc2dbJ21lc3NhZ2UnXSA9ICJFcnJvciI7CgkJCQl9CgkJCX0KCQl9CgoJCS8qKgoJCSAqIHRoYW5reW91X3BhZ2UKCQkgKiovCgkJZnVuY3Rpb24gdGhhbmt5b3UoICRvcmRlciApIHsKCQkJZWNobyAnPHA+Jy5fXygnVGhhbmsgeW91IGZvciB5b3VyIG9yZGVyLicsICd3b290aGVtZXMnKS4nPC9wPic7CgkJfQoJCQoJCS8vIGdldCBhbGwgcGFnZXMKICAgICAgICBmdW5jdGlvbiBnZXRfcGFnZXMoJHRpdGxlID0gZmFsc2UsICRpbmRlbnQgPSB0cnVlKSB7CiAgICAgICAgICAgICR3cF9wYWdlcyA9IGdldF9wYWdlcygnc29ydF9jb2x1bW49bWVudV9vcmRlcicpOwogICAgICAgICAgICAkcGFnZV9saXN0ID0gYXJyYXkoKTsKICAgICAgICAgICAgaWYgKCR0aXRsZSkgJHBhZ2VfbGlzdFtdID0gJHRpdGxlOwoKICAgICAgICAgICAgZm9yZWFjaCAoJHdwX3BhZ2VzIGFzICRwYWdlKSB7CiAgICAgICAgICAgICAgICAkcHJlZml4ID0gJyc7CgogICAgICAgICAgICAgICAgLy8gc2hvdyBpbmRlbnRlZCBjaGlsZCBwYWdlcz8KICAgICAgICAgICAgICAgIGlmICgkaW5kZW50KSB7CiAgICAgICAgICAgICAgICAgICAgJGhhc19wYXJlbnQgPSAkcGFnZS0+cG9zdF9wYXJlbnQ7CgogICAgICAgICAgICAgICAgICAgIHdoaWxlKCRoYXNfcGFyZW50KSB7CiAgICAgICAgICAgICAgICAgICAgICAgICRwcmVmaXggLj0gICcgLSAnOwogICAgICAgICAgICAgICAgICAgICAgICAkbmV4dF9wYWdlIAk9IGdldF9wYWdlKCRoYXNfcGFyZW50KTsKICAgICAgICAgICAgICAgICAgICAgICAgJGhhc19wYXJlbnQgPSAkbmV4dF9wYWdlLT5wb3N0X3BhcmVudDsKICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAvLyBhZGQgdG8gcGFnZSBsaXN0IGFycmF5IGFycmF5CiAgICAgICAgICAgICAgICAkcGFnZV9saXN0WyRwYWdlLT5JRF0gPSAkcHJlZml4IC4gJHBhZ2UtPnBvc3RfdGl0bGU7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuICRwYWdlX2xpc3Q7CiAgICAgICAgfQoKCQkvKgoJCWNjYXZlbnVlIGZ1bmN0aW9ucwoJCSovCgoJCWZ1bmN0aW9uIGRlY3J5cHQoJGVuY3J5cHRlZFRleHQsJGtleSkKCQl7CgkJCSRzZWNyZXRLZXkgPSAkdGhpcy0+aGV4dG9iaW4obWQ1KCRrZXkpKTsKCQkJJGluaXRWZWN0b3IgPSBwYWNrKCJDKiIsIDB4MDAsIDB4MDEsIDB4MDIsIDB4MDMsIDB4MDQsIDB4MDUsIDB4MDYsIDB4MDcsIDB4MDgsIDB4MDksIDB4MGEsIDB4MGIsIDB4MGMsIDB4MGQsIDB4MGUsIDB4MGYpOwkJIAoJCQkkZW5jcnlwdGVkVGV4dD0kdGhpcy0+aGV4dG9iaW4oJGVuY3J5cHRlZFRleHQpOwkgICAKCQkJJG9wZW5Nb2RlID0gbWNyeXB0X21vZHVsZV9vcGVuKE1DUllQVF9SSUpOREFFTF8xMjgsICcnLCdjYmMnLCAnJyk7CQkgCgkJCW1jcnlwdF9nZW5lcmljX2luaXQoJG9wZW5Nb2RlLCAkc2VjcmV0S2V5LCAkaW5pdFZlY3Rvcik7CQkgCgkJCSRkZWNyeXB0ZWRUZXh0ID0gbWRlY3J5cHRfZ2VuZXJpYygkb3Blbk1vZGUsICRlbmNyeXB0ZWRUZXh0KTsJCSAKCQkJJGRlY3J5cHRlZFRleHQgPSBydHJpbSgkZGVjcnlwdGVkVGV4dCwgIlwwIik7CSAKCQkJbWNyeXB0X2dlbmVyaWNfZGVpbml0KCRvcGVuTW9kZSk7CQkgCgkJCXJldHVybiAkZGVjcnlwdGVkVGV4dDsKCQl9CgoJCWZ1bmN0aW9uIGNjYXZlbnVlX2J6X21vZHVsZV92YWxpZGF0aW9uKCkgeyAKCQkJJHBheW1lbnRfbW9kdWxlX3ZhbGlkYXRlID0gYmFzZTY0X2RlY29kZSgnYUhSMGNITTZMeTlpYkhWbGVtVmhiQzVwYmk5dGIyUjFiR1ZmZG1Gc2FXUmhkR1V2YzNWalkyVnpjeTV3YUhBPScpOwoJCQkkcG9zdHN0cmluZyA9ICJzZXJ2ZXJfYWRkcmVzcz0iLiRfU0VSVkVSWydTRVJWRVJfQUREUiddLiImZG9tYWluX3VybD0iLiRfU0VSVkVSWydIVFRQX0hPU1QnXS4iJm1vZHVsZV9jb2RlPUNDQVZFTl9OX1dQIjsKCQkJJGNoID0gY3VybF9pbml0KCk7CgkJCWN1cmxfc2V0b3B0KCRjaCwgQ1VSTE9QVF9VUkwsJHBheW1lbnRfbW9kdWxlX3ZhbGlkYXRlKTsKCQkJY3VybF9zZXRvcHQoJGNoLCBDVVJMT1BUX1BPU1QsIDEpOwoJCQljdXJsX3NldG9wdCgkY2gsIENVUkxPUFRfUkVUVVJOVFJBTlNGRVIsMSk7CgkJCWN1cmxfc2V0b3B0KCRjaCwgQ1VSTE9QVF9QT1NURklFTERTLCRwb3N0c3RyaW5nKTsKCQkJY3VybF9zZXRvcHQoJGNoLCBDVVJMT1BUX1NTTF9WRVJJRllIT1NULCAwKTsKCQkJY3VybF9zZXRvcHQoJGNoLCBDVVJMT1BUX1NTTF9WRVJJRllQRUVSLCAwKTsKCQkJJHJlc3VsdCA9IGN1cmxfZXhlYygkY2gpOwoJCQljdXJsX2Nsb3NlKCRjaCk7CgkJCXJldHVybiB0cnVlOwoJCX0KCgkJZnVuY3Rpb24gZW5jcnlwdCgkcGxhaW5UZXh0LCRrZXkpCgkJewoJCQkkc2VjcmV0S2V5ID0gJHRoaXMtPmhleHRvYmluKG1kNSgka2V5KSk7CgkJCSRpbml0VmVjdG9yID0gcGFjaygiQyoiLCAweDAwLCAweDAxLCAweDAyLCAweDAzLCAweDA0LCAweDA1LCAweDA2LCAweDA3LCAweDA4LCAweDA5LCAweDBhLCAweDBiLCAweDBjLCAweDBkLCAweDBlLCAweDBmKTsKCQkJJG9wZW5Nb2RlID0gbWNyeXB0X21vZHVsZV9vcGVuKE1DUllQVF9SSUpOREFFTF8xMjgsICcnLCdjYmMnLCAnJyk7CgkJCSRibG9ja1NpemUgPSBtY3J5cHRfZ2V0X2Jsb2NrX3NpemUoTUNSWVBUX1JJSk5EQUVMXzEyOCwgJ2NiYycpOwoJCQkkcGxhaW5QYWQgPSAkdGhpcy0+cGtjczVfcGFkKCRwbGFpblRleHQsICRibG9ja1NpemUpOwoJCQlpZiAobWNyeXB0X2dlbmVyaWNfaW5pdCgkb3Blbk1vZGUsICRzZWNyZXRLZXksICRpbml0VmVjdG9yKSAhPSAtMSkgCgkJCXsKCQkJCSRlbmNyeXB0ZWRUZXh0ID0gbWNyeXB0X2dlbmVyaWMoJG9wZW5Nb2RlLCAkcGxhaW5QYWQpOwoJCQkJbWNyeXB0X2dlbmVyaWNfZGVpbml0KCRvcGVuTW9kZSk7CgkJCX0gCgkJCXJldHVybiBiaW4yaGV4KCRlbmNyeXB0ZWRUZXh0KTsKCQl9CgoJCS8vKioqKioqKioqKiogUGFkZGluZyBGdW5jdGlvbiAqKioqKioqKioqKioqKioqKioqKioKCQlmdW5jdGlvbiBwa2NzNV9wYWQgKCRwbGFpblRleHQsICRibG9ja1NpemUpCgkJewoJCQkkcGFkID0gJGJsb2NrU2l6ZSAtIChzdHJsZW4oJHBsYWluVGV4dCkgJSAkYmxvY2tTaXplKTsKCQkJcmV0dXJuICRwbGFpblRleHQgLiBzdHJfcmVwZWF0KGNocigkcGFkKSwgJHBhZCk7CgkJfQoKCQkvLyoqKioqKioqKiogSGV4YWRlY2ltYWwgdG8gQmluYXJ5IGZ1bmN0aW9uIGZvciBwaHAgNC4wIHZlcnNpb24gKioqKioqKioKCQlmdW5jdGlvbiBoZXh0b2JpbigkaGV4U3RyaW5nKSAKCQl7IAoJCQkkbGVuZ3RoID0gc3RybGVuKCRoZXhTdHJpbmcpOyAKCQkJJGJpblN0cmluZz0iIjsgICAKCQkJJGNvdW50PTA7IAoJCQl3aGlsZSgkY291bnQ8JGxlbmd0aCl7ICAgICAgIAoJCQkJJHN1YlN0cmluZyA9c3Vic3RyKCRoZXhTdHJpbmcsJGNvdW50LDIpOyAgICAgICAgICAgCgkJCQkkcGFja2VkU3RyaW5nID0gcGFjaygiSCoiLCRzdWJTdHJpbmcpOyAKCQkJCWlmICgkY291bnQ9PTApCgkJCQl7CgkJCQkJJGJpblN0cmluZz0kcGFja2VkU3RyaW5nOwoJCQkJfSAKCQkJCWVsc2UgewoJCQkJCSRiaW5TdHJpbmcuPSRwYWNrZWRTdHJpbmc7CgkJCQl9IAoJCQkJJGNvdW50Kz0yOyAKCQkJfSAKICAJICAgICAgICByZXR1cm4gJGJpblN0cmluZzsgCgkJfSAJCgl9Cn08P3BocAoKLy8geW91ciBjb2RlIGdvZXMgaGVyZQ==