<?php
// +----------------------------------------------------------------------+
// | BoletoPhp - Versão Beta |
// +----------------------------------------------------------------------+
// | Este arquivo está disponível sob a Licença GPL disponível pela Web |
// | em http://p...content-available-to-author-only...a.org/wiki/GNU_General_Public_License |
// | Você deve ter recebido uma cópia da GNU Public License junto com |
// | esse pacote; se não, escreva para: |
// | |
// | Free Software Foundation, Inc. |
// | 59 Temple Place - Suite 330 |
// | Boston, MA 02111-1307, USA. |
// +----------------------------------------------------------------------+
// +----------------------------------------------------------------------+
// | Originado do Projeto BBBoletoFree que tiveram colaborações de Daniel |
// | William Schultz e Leandro Maniezo que por sua vez foi derivado do |
// | PHPBoleto de João Prado Maia e Pablo Martins F. Costa |
// | |
// | Se vc quer colaborar, nos ajude a desenvolver p/ os demais bancos :-)|
// | Acesse o site do Projeto BoletoPhp: www.boletophp.com.br |
// +----------------------------------------------------------------------+
// +----------------------------------------------------------------------+
// | Equipe Coordenação Projeto BoletoPhp: <boletophp@boletophp.com.br> |
// | Desenvolvimento Boleto CEF: Elizeu Alcantara |
// +----------------------------------------------------------------------+
$codigobanco = "104" ;
$codigo_banco_com_dv = geraCodigoBanco( $codigobanco ) ;
$nummoeda = "9" ;
$fator_vencimento = fator_vencimento( $dadosboleto [ "data_vencimento" ] ) ;
//valor tem 10 digitos, sem virgula
$valor = formata_numero( $dadosboleto [ "valor_boleto" ] , 10 , 0 , "valor" ) ;
//agencia é 4 digitos
$agencia = formata_numero( $dadosboleto [ "agencia" ] , 4 , 0 ) ;
//conta é 5 digitos
$conta = formata_numero( $dadosboleto [ "conta" ] , 5 , 0 ) ;
//dv da conta
$conta_dv = formata_numero( $dadosboleto [ "conta_dv" ] , 1 , 0 ) ;
//carteira é 2 caracteres
$carteira = $dadosboleto [ "carteira" ] ;
//nosso número (sem dv) é 10 digitos
$nnum = $dadosboleto [ "inicio_nosso_numero" ] . formata_numero( $dadosboleto [ "nosso_numero" ] , 8 , 0 ) ;
//dv do nosso número
$dv_nosso_numero = digitoVerificador_nossonumero( $nnum ) ;
$nossonumero_dv = "$nnum $dv_nosso_numero " ;
//conta cedente (sem dv) é 11 digitos
$conta_cedente = formata_numero( $dadosboleto [ "conta_cedente" ] , 11 , 0 ) ;
//dv da conta cedente
$conta_cedente_dv = formata_numero( $dadosboleto [ "conta_cedente_dv" ] , 1 , 0 ) ;
$ag_contacedente = $agencia . $conta_cedente ;
// 43 numeros para o calculo do digito verificador do codigo de barras
$dv = digitoVerificador_barra( "$codigobanco $nummoeda $fator_vencimento $valor $nnum $ag_contacedente " , 9 , 0 ) ;
// Numero para o codigo de barras com 44 digitos
$linha = "$codigobanco $nummoeda $dv $fator_vencimento $valor $nnum $ag_contacedente " ;
$nossonumero = substr ( $nossonumero_dv , 0 , 10 ) . '-' . substr ( $nossonumero_dv , 10 , 1 ) ; $agencia_codigo = $agencia . " / " . $conta_cedente . "-" . $conta_cedente_dv ;
$dadosboleto [ "codigo_barras" ] = $linha ;
$dadosboleto [ "linha_digitavel" ] = monta_linha_digitavel( $linha ) ;
$dadosboleto [ "agencia_codigo" ] = $agencia_codigo ;
$dadosboleto [ "nosso_numero" ] = $nossonumero ;
$dadosboleto [ "codigo_banco_com_dv" ] = $codigo_banco_com_dv ;
function digitoVerificador_nossonumero( $numero ) {
$resto2 = modulo_11( $numero , 9 , 1 ) ;
$digito = 11 - $resto2 ;
if ( $digito == 10 || $digito == 11 ) {
$dv = 0 ;
} else {
$dv = $digito ;
}
return $dv ;
}
function digitoVerificador_barra( $numero ) {
$resto2 = modulo_11( $numero , 9 , 1 ) ;
if ( $resto2 == 0 || $resto2 == 1 || $resto2 == 10 ) {
$dv = 1 ;
} else {
$dv = 11 - $resto2 ;
}
return $dv ;
}
// FUNÇÕES
// Algumas foram retiradas do Projeto PhpBoleto e modificadas para atender as particularidades de cada banco
function formata_numero( $numero , $loop , $insert , $tipo = "geral" ) {
if ( $tipo == "geral" ) {
$numero = $insert . $numero ;
}
}
if ( $tipo == "valor" ) {
/*
retira as virgulas
formata o numero
preenche com zeros
*/
$numero = $insert . $numero ;
}
}
if ( $tipo == "convenio" ) {
$numero = $numero . $insert ;
}
}
return $numero ;
}
function fbarcode( $valor ) {
$fino = 1 ;
$largo = 3 ;
$altura = 50 ;
$barcodes [ 0 ] = "00110" ;
$barcodes [ 1 ] = "10001" ;
$barcodes [ 2 ] = "01001" ;
$barcodes [ 3 ] = "11000" ;
$barcodes [ 4 ] = "00101" ;
$barcodes [ 5 ] = "10100" ;
$barcodes [ 6 ] = "01100" ;
$barcodes [ 7 ] = "00011" ;
$barcodes [ 8 ] = "10010" ;
$barcodes [ 9 ] = "01010" ;
for ( $f1 = 9 ; $f1 >= 0 ; $f1 -- ) {
for ( $f2 = 9 ; $f2 >= 0 ; $f2 -- ) {
$f = ( $f1 * 10 ) + $f2 ;
$texto = "" ;
for ( $i = 1 ; $i < 6 ; $i ++ ) {
$texto .= substr ( $barcodes [ $f1 ] , ( $i - 1 ) , 1 ) . substr ( $barcodes [ $f2 ] , ( $i - 1 ) , 1 ) ; }
$barcodes [ $f ] = $texto ;
}
}
//Desenho da barra
//Guarda inicial
?> <img src=imagens/p.png width=<?php echo $fino ?> height=<?php echo $altura ?> border=0><img
src=imagens/b.png width=<?php echo $fino ?> height=<?php echo $altura ?> border=0><img
src=imagens/p.png width=<?php echo $fino ?> height=<?php echo $altura ?> border=0><img
src=imagens/b.png width=<?php echo $fino ?> height=<?php echo $altura ?> border=0><img
<?php
$texto = $valor ;
if ( ( strlen ( $texto ) % 2 ) <> 0 ) { $texto = "0" . $texto ;
}
// Draw dos dados
$i = round ( esquerda
( $texto , 2 ) ) ; $texto = direita
( $texto , strlen ( $texto ) - 2 ) ; $f = $barcodes [ $i ] ;
for ( $i = 1 ; $i < 11 ; $i += 2 ) {
if ( substr ( $f , ( $i - 1 ) , 1 ) == "0" ) { $f1 = $fino ;
} else {
$f1 = $largo ;
}
?>
src=imagens/p.png width=<?php echo $f1 ?> height=<?php echo $altura ?> border=0><img
<?php
$f2 = $fino ;
} else {
$f2 = $largo ;
}
?>
src=imagens/b.png width=<?php echo $f2 ?> height=<?php echo $altura ?> border=0><img
<?php
}
}
// Draw guarda final
?>
src=imagens/p.png width=<?php echo $largo ?> height=<?php echo $altura ?> border=0><img
src=imagens/b.png width=<?php echo $fino ?> height=<?php echo $altura ?> border=0><img
src=imagens/p.png width=<?php echo 1 ?> height=<?php echo $altura ?> border=0>
<?php
} //Fim da função
function esquerda( $entra , $comp ) {
return substr ( $entra , 0 , $comp ) ; }
function direita( $entra , $comp ) {
}
function fator_vencimento( $data ) {
$ano = $data [ 2 ] ;
$mes = $data [ 1 ] ;
$dia = $data [ 0 ] ;
return ( abs ( ( _dateToDays
( "1997" , "10" , "07" ) ) - ( _dateToDays
( $ano , $mes , $dia ) ) ) ) ; }
function _dateToDays( $year , $month , $day ) {
$century = substr ( $year , 0 , 2 ) ; if ( $month > 2 ) {
$month -= 3 ;
} else {
$month += 9 ;
if ( $year ) {
$year --;
} else {
$year = 99 ;
$century --;
}
}
return ( floor ( ( 146097 * $century ) / 4 ) + floor ( ( 1461 * $year ) / 4 ) + floor ( ( 153 * $month + 2 ) / 5 ) + $day + 1721119 ) ;
}
function modulo_10( $num ) {
$numtotal10 = 0 ;
$fator = 2 ;
// Separacao dos numeros
for ( $i = strlen ( $num ) ; $i > 0 ; $i -- ) { // pega cada numero isoladamente
$numeros [ $i ] = substr ( $num , $i - 1 , 1 ) ; // Efetua multiplicacao do numero pelo (falor 10)
$temp = $numeros [ $i ] * $fator ;
$temp0 = 0 ;
foreach ( preg_split ( '//' , $temp ,- 1 , PREG_SPLIT_NO_EMPTY
) as $k => $v ) { $temp0 += $v ; } $parcial10 [ $i ] = $temp0 ; //$numeros[$i] * $fator;
// monta sequencia para soma dos digitos no (modulo 10)
$numtotal10 += $parcial10 [ $i ] ;
if ( $fator == 2 ) {
$fator = 1 ;
} else {
$fator = 2 ; // intercala fator de multiplicacao (modulo 10)
}
}
// várias linhas removidas, vide função original
// Calculo do modulo 10
$resto = $numtotal10 % 10 ;
$digito = 10 - $resto ;
if ( $resto == 0 ) {
$digito = 0 ;
}
return $digito ;
}
function modulo_11( $num , $base = 9 , $r = 0 ) {
/**
* Autor:
* Pablo Costa <pablo@users.sourceforge.net>
*
* Função:
* Calculo do Modulo 11 para geracao do digito verificador
* de boletos bancarios conforme documentos obtidos
* da Febraban - www.febraban.org.br
*
* Entrada:
* $num: string numérica para a qual se deseja calcularo digito verificador;
* $base: valor maximo de multiplicacao [2-$base]
* $r: quando especificado um devolve somente o resto
*
* Saída:
* Retorna o Digito verificador.
*
* Observações:
* - Script desenvolvido sem nenhum reaproveitamento de código pré existente.
* - Assume-se que a verificação do formato das variáveis de entrada é feita antes da execução deste script.
*/
$soma = 0 ;
$fator = 2 ;
/* Separacao dos numeros */
for ( $i = strlen ( $num ) ; $i > 0 ; $i -- ) { // pega cada numero isoladamente
$numeros [ $i ] = substr ( $num , $i - 1 , 1 ) ; // Efetua multiplicacao do numero pelo falor
$parcial [ $i ] = $numeros [ $i ] * $fator ;
// Soma dos digitos
$soma += $parcial [ $i ] ;
if ( $fator == $base ) {
// restaura fator de multiplicacao para 2
$fator = 1 ;
}
$fator ++;
}
/* Calculo do modulo 11 */
if ( $r == 0 ) {
$soma *= 10 ;
$digito = $soma % 11 ;
if ( $digito == 10 ) {
$digito = 0 ;
}
return $digito ;
} elseif ( $r == 1 ) {
$resto = $soma % 11 ;
return $resto ;
}
}
function monta_linha_digitavel( $codigo ) {
// Posição Conteúdo
// 1 a 3 Número do banco
// 4 Código da Moeda - 9 para Real
// 5 Digito verificador do Código de Barras
// 6 a 9 Fator de Vencimento
// 10 a 19 Valor (8 inteiros e 2 decimais)
// 20 a 44 Campo Livre definido por cada banco (25 caracteres)
// 1. Campo - composto pelo código do banco, código da moéda, as cinco primeiras posições
// do campo livre e DV (modulo10) deste campo
$p3 = modulo_10( "$p1 $p2 " ) ;
$p4 = "$p1 $p2 $p3 " ;
$campo1 = "$p5 .$p6 " ;
// 2. Campo - composto pelas posiçoes 6 a 15 do campo livre
// e livre e DV (modulo10) deste campo
$p1 = substr ( $codigo , 24 , 10 ) ; $p2 = modulo_10( $p1 ) ;
$p3 = "$p1 $p2 " ;
$campo2 = "$p4 .$p5 " ;
// 3. Campo composto pelas posicoes 16 a 25 do campo livre
// e livre e DV (modulo10) deste campo
$p1 = substr ( $codigo , 34 , 10 ) ; $p2 = modulo_10( $p1 ) ;
$p3 = "$p1 $p2 " ;
$campo3 = "$p4 .$p5 " ;
// 4. Campo - digito verificador do codigo de barras
$campo4 = substr ( $codigo , 4 , 1 ) ;
// 5. Campo composto pelo fator vencimento e valor nominal do documento, sem
// indicacao de zeros a esquerda e sem edicao (sem ponto e virgula). Quando se
// tratar de valor zerado, a representacao deve ser 000 (tres zeros).
$campo5 = "$p1 $p2 " ;
return "$campo1 $campo2 $campo3 $campo4 $campo5 " ;
}
function geraCodigoBanco( $numero ) {
$parte1 = substr ( $numero , 0 , 3 ) ; $parte2 = modulo_11( $parte1 ) ;
return $parte1 . "-" . $parte2 ;
}
?>
PD9waHAKLy8gKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rCi8vIHwgQm9sZXRvUGhwIC0gVmVyc8OjbyBCZXRhICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKLy8gKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rCi8vIHwgRXN0ZSBhcnF1aXZvIGVzdMOhIGRpc3BvbsOtdmVsIHNvYiBhIExpY2Vuw6dhIEdQTCBkaXNwb27DrXZlbCBwZWxhIFdlYiAgIHwKLy8gfCBlbSBodHRwOi8vcC4uLmNvbnRlbnQtYXZhaWxhYmxlLXRvLWF1dGhvci1vbmx5Li4uYS5vcmcvd2lraS9HTlVfR2VuZXJhbF9QdWJsaWNfTGljZW5zZSAgICAgICAgICAgfAovLyB8IFZvY8OqIGRldmUgdGVyIHJlY2ViaWRvIHVtYSBjw7NwaWEgZGEgR05VIFB1YmxpYyBMaWNlbnNlIGp1bnRvIGNvbSAgICAgfAovLyB8IGVzc2UgcGFjb3RlOyBzZSBuw6NvLCBlc2NyZXZhIHBhcmE6ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8Ci8vIHwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAovLyB8IEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgSW5jLiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKLy8gfCA1OSBUZW1wbGUgUGxhY2UgLSBTdWl0ZSAzMzAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8Ci8vIHwgQm9zdG9uLCBNQSAwMjExMS0xMzA3LCBVU0EuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAovLyArLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSsKCi8vICstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKwovLyB8IE9yaWdpbmFkbyBkbyBQcm9qZXRvIEJCQm9sZXRvRnJlZSBxdWUgdGl2ZXJhbSBjb2xhYm9yYcOnw7VlcyBkZSBEYW5pZWwgfAovLyB8IFdpbGxpYW0gU2NodWx0eiBlIExlYW5kcm8gTWFuaWV6byBxdWUgcG9yIHN1YSB2ZXogZm9pIGRlcml2YWRvIGRvCSAgfAovLyB8IFBIUEJvbGV0byBkZSBKb8OjbyBQcmFkbyBNYWlhIGUgUGFibG8gTWFydGlucyBGLiBDb3N0YQkJCQkgICAgICAgIHwKLy8gfCAJCQkJCQkJCQkJCQkJCSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCQkJICB8Ci8vIHwgU2UgdmMgcXVlciBjb2xhYm9yYXIsIG5vcyBhanVkZSBhIGRlc2Vudm9sdmVyIHAvIG9zIGRlbWFpcyBiYW5jb3MgOi0pfAovLyB8IEFjZXNzZSBvIHNpdGUgZG8gUHJvamV0byBCb2xldG9QaHA6IHd3dy5ib2xldG9waHAuY29tLmJyICAgICAgICAgICAgIHwKLy8gKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rCgovLyArLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSsKLy8gfCBFcXVpcGUgQ29vcmRlbmHDp8OjbyBQcm9qZXRvIEJvbGV0b1BocDogPGJvbGV0b3BocEBib2xldG9waHAuY29tLmJyPiAgIHwKLy8gfCBEZXNlbnZvbHZpbWVudG8gQm9sZXRvIENFRjogRWxpemV1IEFsY2FudGFyYSAgICAgICAgICAgICAgICAgICAgICAgICB8Ci8vICstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKwoKCiRjb2RpZ29iYW5jbyA9ICIxMDQiOwokY29kaWdvX2JhbmNvX2NvbV9kdiA9IGdlcmFDb2RpZ29CYW5jbygkY29kaWdvYmFuY28pOwokbnVtbW9lZGEgPSAiOSI7CiRmYXRvcl92ZW5jaW1lbnRvID0gZmF0b3JfdmVuY2ltZW50bygkZGFkb3Nib2xldG9bImRhdGFfdmVuY2ltZW50byJdKTsKCi8vdmFsb3IgdGVtIDEwIGRpZ2l0b3MsIHNlbSB2aXJndWxhCiR2YWxvciA9IGZvcm1hdGFfbnVtZXJvKCRkYWRvc2JvbGV0b1sidmFsb3JfYm9sZXRvIl0sMTAsMCwidmFsb3IiKTsKLy9hZ2VuY2lhIMOpIDQgZGlnaXRvcwokYWdlbmNpYSA9IGZvcm1hdGFfbnVtZXJvKCRkYWRvc2JvbGV0b1siYWdlbmNpYSJdLDQsMCk7Ci8vY29udGEgw6kgNSBkaWdpdG9zCiRjb250YSA9IGZvcm1hdGFfbnVtZXJvKCRkYWRvc2JvbGV0b1siY29udGEiXSw1LDApOwovL2R2IGRhIGNvbnRhCiRjb250YV9kdiA9IGZvcm1hdGFfbnVtZXJvKCRkYWRvc2JvbGV0b1siY29udGFfZHYiXSwxLDApOwovL2NhcnRlaXJhIMOpIDIgY2FyYWN0ZXJlcwokY2FydGVpcmEgPSAkZGFkb3Nib2xldG9bImNhcnRlaXJhIl07CgovL25vc3NvIG7Dum1lcm8gKHNlbSBkdikgw6kgMTAgZGlnaXRvcwokbm51bSA9ICRkYWRvc2JvbGV0b1siaW5pY2lvX25vc3NvX251bWVybyJdIC4gZm9ybWF0YV9udW1lcm8oJGRhZG9zYm9sZXRvWyJub3Nzb19udW1lcm8iXSw4LDApOwovL2R2IGRvIG5vc3NvIG7Dum1lcm8KJGR2X25vc3NvX251bWVybyA9IGRpZ2l0b1ZlcmlmaWNhZG9yX25vc3NvbnVtZXJvKCRubnVtKTsKJG5vc3NvbnVtZXJvX2R2ID0iJG5udW0kZHZfbm9zc29fbnVtZXJvIjsKCi8vY29udGEgY2VkZW50ZSAoc2VtIGR2KSDDqSAxMSBkaWdpdG9zCiRjb250YV9jZWRlbnRlID0gZm9ybWF0YV9udW1lcm8oJGRhZG9zYm9sZXRvWyJjb250YV9jZWRlbnRlIl0sMTEsMCk7Ci8vZHYgZGEgY29udGEgY2VkZW50ZQokY29udGFfY2VkZW50ZV9kdiA9IGZvcm1hdGFfbnVtZXJvKCRkYWRvc2JvbGV0b1siY29udGFfY2VkZW50ZV9kdiJdLDEsMCk7CgokYWdfY29udGFjZWRlbnRlID0gJGFnZW5jaWEgLiAkY29udGFfY2VkZW50ZTsKCi8vIDQzIG51bWVyb3MgcGFyYSBvIGNhbGN1bG8gZG8gZGlnaXRvIHZlcmlmaWNhZG9yIGRvIGNvZGlnbyBkZSBiYXJyYXMKJGR2ID0gZGlnaXRvVmVyaWZpY2Fkb3JfYmFycmEoIiRjb2RpZ29iYW5jbyRudW1tb2VkYSRmYXRvcl92ZW5jaW1lbnRvJHZhbG9yJG5udW0kYWdfY29udGFjZWRlbnRlIiwgOSwgMCk7Ci8vIE51bWVybyBwYXJhIG8gY29kaWdvIGRlIGJhcnJhcyBjb20gNDQgZGlnaXRvcwokbGluaGEgPSAiJGNvZGlnb2JhbmNvJG51bW1vZWRhJGR2JGZhdG9yX3ZlbmNpbWVudG8kdmFsb3Ikbm51bSRhZ19jb250YWNlZGVudGUiOwoKJG5vc3NvbnVtZXJvID0gc3Vic3RyKCRub3Nzb251bWVyb19kdiwwLDEwKS4nLScuc3Vic3RyKCRub3Nzb251bWVyb19kdiwxMCwxKTsKJGFnZW5jaWFfY29kaWdvID0gJGFnZW5jaWEuIiAvICIuICRjb250YV9jZWRlbnRlIC4iLSIuICRjb250YV9jZWRlbnRlX2R2OwoKCiRkYWRvc2JvbGV0b1siY29kaWdvX2JhcnJhcyJdID0gJGxpbmhhOwokZGFkb3Nib2xldG9bImxpbmhhX2RpZ2l0YXZlbCJdID0gbW9udGFfbGluaGFfZGlnaXRhdmVsKCRsaW5oYSk7CiRkYWRvc2JvbGV0b1siYWdlbmNpYV9jb2RpZ28iXSA9ICRhZ2VuY2lhX2NvZGlnbzsKJGRhZG9zYm9sZXRvWyJub3Nzb19udW1lcm8iXSA9ICRub3Nzb251bWVybzsKJGRhZG9zYm9sZXRvWyJjb2RpZ29fYmFuY29fY29tX2R2Il0gPSAkY29kaWdvX2JhbmNvX2NvbV9kdjsKCmZ1bmN0aW9uIGRpZ2l0b1ZlcmlmaWNhZG9yX25vc3NvbnVtZXJvKCRudW1lcm8pIHsKCSRyZXN0bzIgPSBtb2R1bG9fMTEoJG51bWVybywgOSwgMSk7CiAgICAgJGRpZ2l0byA9IDExIC0gJHJlc3RvMjsKICAgICBpZiAoJGRpZ2l0byA9PSAxMCB8fCAkZGlnaXRvID09IDExKSB7CiAgICAgICAgJGR2ID0gMDsKICAgICB9IGVsc2UgewogICAgICAgICRkdiA9ICRkaWdpdG87CiAgICAgfQoJIHJldHVybiAkZHY7Cn0KCgpmdW5jdGlvbiBkaWdpdG9WZXJpZmljYWRvcl9iYXJyYSgkbnVtZXJvKSB7CgkkcmVzdG8yID0gbW9kdWxvXzExKCRudW1lcm8sIDksIDEpOwogICAgIGlmICgkcmVzdG8yID09IDAgfHwgJHJlc3RvMiA9PSAxIHx8ICRyZXN0bzIgPT0gMTApIHsKICAgICAgICAkZHYgPSAxOwogICAgIH0gZWxzZSB7CgkgCSRkdiA9IDExIC0gJHJlc3RvMjsKICAgICB9CgkgcmV0dXJuICRkdjsKfQoKCi8vIEZVTsOHw5VFUwovLyBBbGd1bWFzIGZvcmFtIHJldGlyYWRhcyBkbyBQcm9qZXRvIFBocEJvbGV0byBlIG1vZGlmaWNhZGFzIHBhcmEgYXRlbmRlciBhcyBwYXJ0aWN1bGFyaWRhZGVzIGRlIGNhZGEgYmFuY28KCmZ1bmN0aW9uIGZvcm1hdGFfbnVtZXJvKCRudW1lcm8sJGxvb3AsJGluc2VydCwkdGlwbyA9ICJnZXJhbCIpIHsKCWlmICgkdGlwbyA9PSAiZ2VyYWwiKSB7CgkJJG51bWVybyA9IHN0cl9yZXBsYWNlKCIsIiwiIiwkbnVtZXJvKTsKCQl3aGlsZShzdHJsZW4oJG51bWVybyk8JGxvb3ApewoJCQkkbnVtZXJvID0gJGluc2VydCAuICRudW1lcm87CgkJfQoJfQoJaWYgKCR0aXBvID09ICJ2YWxvciIpIHsKCQkvKgoJCXJldGlyYSBhcyB2aXJndWxhcwoJCWZvcm1hdGEgbyBudW1lcm8KCQlwcmVlbmNoZSBjb20gemVyb3MKCQkqLwoJCSRudW1lcm8gPSBzdHJfcmVwbGFjZSgiLCIsIiIsJG51bWVybyk7CgkJd2hpbGUoc3RybGVuKCRudW1lcm8pPCRsb29wKXsKCQkJJG51bWVybyA9ICRpbnNlcnQgLiAkbnVtZXJvOwoJCX0KCX0KCWlmICgkdGlwbyA9PSAiY29udmVuaW8iKSB7CgkJd2hpbGUoc3RybGVuKCRudW1lcm8pPCRsb29wKXsKCQkJJG51bWVybyA9ICRudW1lcm8gLiAkaW5zZXJ0OwoJCX0KCX0KCXJldHVybiAkbnVtZXJvOwp9CgoKZnVuY3Rpb24gZmJhcmNvZGUoJHZhbG9yKXsKCiRmaW5vID0gMSA7CiRsYXJnbyA9IDMgOwokYWx0dXJhID0gNTAgOwoKICAkYmFyY29kZXNbMF0gPSAiMDAxMTAiIDsKICAkYmFyY29kZXNbMV0gPSAiMTAwMDEiIDsKICAkYmFyY29kZXNbMl0gPSAiMDEwMDEiIDsKICAkYmFyY29kZXNbM10gPSAiMTEwMDAiIDsKICAkYmFyY29kZXNbNF0gPSAiMDAxMDEiIDsKICAkYmFyY29kZXNbNV0gPSAiMTAxMDAiIDsKICAkYmFyY29kZXNbNl0gPSAiMDExMDAiIDsKICAkYmFyY29kZXNbN10gPSAiMDAwMTEiIDsKICAkYmFyY29kZXNbOF0gPSAiMTAwMTAiIDsKICAkYmFyY29kZXNbOV0gPSAiMDEwMTAiIDsKICBmb3IoJGYxPTk7JGYxPj0wOyRmMS0tKXsgCiAgICBmb3IoJGYyPTk7JGYyPj0wOyRmMi0tKXsgIAogICAgICAkZiA9ICgkZjEgKiAxMCkgKyAkZjIgOwogICAgICAkdGV4dG8gPSAiIiA7CiAgICAgIGZvcigkaT0xOyRpPDY7JGkrKyl7IAogICAgICAgICR0ZXh0byAuPSAgc3Vic3RyKCRiYXJjb2Rlc1skZjFdLCgkaS0xKSwxKSAuIHN1YnN0cigkYmFyY29kZXNbJGYyXSwoJGktMSksMSk7CiAgICAgIH0KICAgICAgJGJhcmNvZGVzWyRmXSA9ICR0ZXh0bzsKICAgIH0KICB9CgoKLy9EZXNlbmhvIGRhIGJhcnJhCgoKLy9HdWFyZGEgaW5pY2lhbAo/PjxpbWcgc3JjPWltYWdlbnMvcC5wbmcgd2lkdGg9PD9waHAgZWNobyAkZmlubz8+IGhlaWdodD08P3BocCBlY2hvICRhbHR1cmE/PiBib3JkZXI9MD48aW1nIApzcmM9aW1hZ2Vucy9iLnBuZyB3aWR0aD08P3BocCBlY2hvICRmaW5vPz4gaGVpZ2h0PTw/cGhwIGVjaG8gJGFsdHVyYT8+IGJvcmRlcj0wPjxpbWcgCnNyYz1pbWFnZW5zL3AucG5nIHdpZHRoPTw/cGhwIGVjaG8gJGZpbm8/PiBoZWlnaHQ9PD9waHAgZWNobyAkYWx0dXJhPz4gYm9yZGVyPTA+PGltZyAKc3JjPWltYWdlbnMvYi5wbmcgd2lkdGg9PD9waHAgZWNobyAkZmlubz8+IGhlaWdodD08P3BocCBlY2hvICRhbHR1cmE/PiBib3JkZXI9MD48aW1nIAo8P3BocAokdGV4dG8gPSAkdmFsb3IgOwppZigoc3RybGVuKCR0ZXh0bykgJSAyKSA8PiAwKXsKCSR0ZXh0byA9ICIwIiAuICR0ZXh0bzsKfQoKLy8gRHJhdyBkb3MgZGFkb3MKd2hpbGUgKHN0cmxlbigkdGV4dG8pID4gMCkgewogICRpID0gcm91bmQoZXNxdWVyZGEoJHRleHRvLDIpKTsKICAkdGV4dG8gPSBkaXJlaXRhKCR0ZXh0byxzdHJsZW4oJHRleHRvKS0yKTsKICAkZiA9ICRiYXJjb2Rlc1skaV07CiAgZm9yKCRpPTE7JGk8MTE7JGkrPTIpewogICAgaWYgKHN1YnN0cigkZiwoJGktMSksMSkgPT0gIjAiKSB7CiAgICAgICRmMSA9ICRmaW5vIDsKICAgIH1lbHNlewogICAgICAkZjEgPSAkbGFyZ28gOwogICAgfQo/PgogICAgc3JjPWltYWdlbnMvcC5wbmcgd2lkdGg9PD9waHAgZWNobyAkZjE/PiBoZWlnaHQ9PD9waHAgZWNobyAkYWx0dXJhPz4gYm9yZGVyPTA+PGltZyAKPD9waHAKICAgIGlmIChzdWJzdHIoJGYsJGksMSkgPT0gIjAiKSB7CiAgICAgICRmMiA9ICRmaW5vIDsKICAgIH1lbHNlewogICAgICAkZjIgPSAkbGFyZ28gOwogICAgfQo/PgogICAgc3JjPWltYWdlbnMvYi5wbmcgd2lkdGg9PD9waHAgZWNobyAkZjI/PiBoZWlnaHQ9PD9waHAgZWNobyAkYWx0dXJhPz4gYm9yZGVyPTA+PGltZyAKPD9waHAKICB9Cn0KCi8vIERyYXcgZ3VhcmRhIGZpbmFsCj8+CnNyYz1pbWFnZW5zL3AucG5nIHdpZHRoPTw/cGhwIGVjaG8gJGxhcmdvPz4gaGVpZ2h0PTw/cGhwIGVjaG8gJGFsdHVyYT8+IGJvcmRlcj0wPjxpbWcgCnNyYz1pbWFnZW5zL2IucG5nIHdpZHRoPTw/cGhwIGVjaG8gJGZpbm8/PiBoZWlnaHQ9PD9waHAgZWNobyAkYWx0dXJhPz4gYm9yZGVyPTA+PGltZyAKc3JjPWltYWdlbnMvcC5wbmcgd2lkdGg9PD9waHAgZWNobyAxPz4gaGVpZ2h0PTw/cGhwIGVjaG8gJGFsdHVyYT8+IGJvcmRlcj0wPiAKICA8P3BocAp9IC8vRmltIGRhIGZ1bsOnw6NvCgpmdW5jdGlvbiBlc3F1ZXJkYSgkZW50cmEsJGNvbXApewoJcmV0dXJuIHN1YnN0cigkZW50cmEsMCwkY29tcCk7Cn0KCmZ1bmN0aW9uIGRpcmVpdGEoJGVudHJhLCRjb21wKXsKCXJldHVybiBzdWJzdHIoJGVudHJhLHN0cmxlbigkZW50cmEpLSRjb21wLCRjb21wKTsKfQoKZnVuY3Rpb24gZmF0b3JfdmVuY2ltZW50bygkZGF0YSkgewoJJGRhdGEgPSBleHBsb2RlKCIvIiwkZGF0YSk7CgkkYW5vID0gJGRhdGFbMl07CgkkbWVzID0gJGRhdGFbMV07CgkkZGlhID0gJGRhdGFbMF07CiAgICByZXR1cm4oYWJzKChfZGF0ZVRvRGF5cygiMTk5NyIsIjEwIiwiMDciKSkgLSAoX2RhdGVUb0RheXMoJGFubywgJG1lcywgJGRpYSkpKSk7Cn0KCmZ1bmN0aW9uIF9kYXRlVG9EYXlzKCR5ZWFyLCRtb250aCwkZGF5KSB7CiAgICAkY2VudHVyeSA9IHN1YnN0cigkeWVhciwgMCwgMik7CiAgICAkeWVhciA9IHN1YnN0cigkeWVhciwgMiwgMik7CiAgICBpZiAoJG1vbnRoID4gMikgewogICAgICAgICRtb250aCAtPSAzOwogICAgfSBlbHNlIHsKICAgICAgICAkbW9udGggKz0gOTsKICAgICAgICBpZiAoJHllYXIpIHsKICAgICAgICAgICAgJHllYXItLTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAkeWVhciA9IDk5OwogICAgICAgICAgICAkY2VudHVyeSAtLTsKICAgICAgICB9CiAgICB9CiAgICByZXR1cm4gKCBmbG9vcigoICAxNDYwOTcgKiAkY2VudHVyeSkgICAgLyAgNCApICsKICAgICAgICAgICAgZmxvb3IoKCAxNDYxICogJHllYXIpICAgICAgICAvICA0ICkgKwogICAgICAgICAgICBmbG9vcigoIDE1MyAqICRtb250aCArICAyKSAvICA1ICkgKwogICAgICAgICAgICAgICAgJGRheSArICAxNzIxMTE5KTsKfQoKZnVuY3Rpb24gbW9kdWxvXzEwKCRudW0pIHsgCgkJJG51bXRvdGFsMTAgPSAwOwogICAgICAgICRmYXRvciA9IDI7CgogICAgICAgIC8vIFNlcGFyYWNhbyBkb3MgbnVtZXJvcwogICAgICAgIGZvciAoJGkgPSBzdHJsZW4oJG51bSk7ICRpID4gMDsgJGktLSkgewogICAgICAgICAgICAvLyBwZWdhIGNhZGEgbnVtZXJvIGlzb2xhZGFtZW50ZQogICAgICAgICAgICAkbnVtZXJvc1skaV0gPSBzdWJzdHIoJG51bSwkaS0xLDEpOwogICAgICAgICAgICAvLyBFZmV0dWEgbXVsdGlwbGljYWNhbyBkbyBudW1lcm8gcGVsbyAoZmFsb3IgMTApCiAgICAgICAgICAgICR0ZW1wID0gJG51bWVyb3NbJGldICogJGZhdG9yOyAKICAgICAgICAgICAgJHRlbXAwPTA7CiAgICAgICAgICAgIGZvcmVhY2ggKHByZWdfc3BsaXQoJy8vJywkdGVtcCwtMSxQUkVHX1NQTElUX05PX0VNUFRZKSBhcyAkaz0+JHYpeyAkdGVtcDArPSR2OyB9CiAgICAgICAgICAgICRwYXJjaWFsMTBbJGldID0gJHRlbXAwOyAvLyRudW1lcm9zWyRpXSAqICRmYXRvcjsKICAgICAgICAgICAgLy8gbW9udGEgc2VxdWVuY2lhIHBhcmEgc29tYSBkb3MgZGlnaXRvcyBubyAobW9kdWxvIDEwKQogICAgICAgICAgICAkbnVtdG90YWwxMCArPSAkcGFyY2lhbDEwWyRpXTsKICAgICAgICAgICAgaWYgKCRmYXRvciA9PSAyKSB7CiAgICAgICAgICAgICAgICAkZmF0b3IgPSAxOwogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgJGZhdG9yID0gMjsgLy8gaW50ZXJjYWxhIGZhdG9yIGRlIG11bHRpcGxpY2FjYW8gKG1vZHVsbyAxMCkKICAgICAgICAgICAgfQogICAgICAgIH0KCQkKICAgICAgICAvLyB2w6FyaWFzIGxpbmhhcyByZW1vdmlkYXMsIHZpZGUgZnVuw6fDo28gb3JpZ2luYWwKICAgICAgICAvLyBDYWxjdWxvIGRvIG1vZHVsbyAxMAogICAgICAgICRyZXN0byA9ICRudW10b3RhbDEwICUgMTA7CiAgICAgICAgJGRpZ2l0byA9IDEwIC0gJHJlc3RvOwogICAgICAgIGlmICgkcmVzdG8gPT0gMCkgewogICAgICAgICAgICAkZGlnaXRvID0gMDsKICAgICAgICB9CgkJCiAgICAgICAgcmV0dXJuICRkaWdpdG87CgkJCn0KCmZ1bmN0aW9uIG1vZHVsb18xMSgkbnVtLCAkYmFzZT05LCAkcj0wKSAgewogICAgLyoqCiAgICAgKiAgIEF1dG9yOgogICAgICogICAgICAgICAgIFBhYmxvIENvc3RhIDxwYWJsb0B1c2Vycy5zb3VyY2Vmb3JnZS5uZXQ+CiAgICAgKgogICAgICogICBGdW7Dp8OjbzoKICAgICAqICAgIENhbGN1bG8gZG8gTW9kdWxvIDExIHBhcmEgZ2VyYWNhbyBkbyBkaWdpdG8gdmVyaWZpY2Fkb3IgCiAgICAgKiAgICBkZSBib2xldG9zIGJhbmNhcmlvcyBjb25mb3JtZSBkb2N1bWVudG9zIG9idGlkb3MgCiAgICAgKiAgICBkYSBGZWJyYWJhbiAtIHd3dy5mZWJyYWJhbi5vcmcuYnIgCiAgICAgKgogICAgICogICBFbnRyYWRhOgogICAgICogICAgICRudW06IHN0cmluZyBudW3DqXJpY2EgcGFyYSBhIHF1YWwgc2UgZGVzZWphIGNhbGN1bGFybyBkaWdpdG8gdmVyaWZpY2Fkb3I7CiAgICAgKiAgICAgJGJhc2U6IHZhbG9yIG1heGltbyBkZSBtdWx0aXBsaWNhY2FvIFsyLSRiYXNlXQogICAgICogICAgICRyOiBxdWFuZG8gZXNwZWNpZmljYWRvIHVtIGRldm9sdmUgc29tZW50ZSBvIHJlc3RvCiAgICAgKgogICAgICogICBTYcOtZGE6CiAgICAgKiAgICAgUmV0b3JuYSBvIERpZ2l0byB2ZXJpZmljYWRvci4KICAgICAqCiAgICAgKiAgIE9ic2VydmHDp8O1ZXM6CiAgICAgKiAgICAgLSBTY3JpcHQgZGVzZW52b2x2aWRvIHNlbSBuZW5odW0gcmVhcHJvdmVpdGFtZW50byBkZSBjw7NkaWdvIHByw6kgZXhpc3RlbnRlLgogICAgICogICAgIC0gQXNzdW1lLXNlIHF1ZSBhIHZlcmlmaWNhw6fDo28gZG8gZm9ybWF0byBkYXMgdmFyacOhdmVpcyBkZSBlbnRyYWRhIMOpIGZlaXRhIGFudGVzIGRhIGV4ZWN1w6fDo28gZGVzdGUgc2NyaXB0LgogICAgICovICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAoKICAgICRzb21hID0gMDsKICAgICRmYXRvciA9IDI7CgogICAgLyogU2VwYXJhY2FvIGRvcyBudW1lcm9zICovCiAgICBmb3IgKCRpID0gc3RybGVuKCRudW0pOyAkaSA+IDA7ICRpLS0pIHsKICAgICAgICAvLyBwZWdhIGNhZGEgbnVtZXJvIGlzb2xhZGFtZW50ZQogICAgICAgICRudW1lcm9zWyRpXSA9IHN1YnN0cigkbnVtLCRpLTEsMSk7CiAgICAgICAgLy8gRWZldHVhIG11bHRpcGxpY2FjYW8gZG8gbnVtZXJvIHBlbG8gZmFsb3IKICAgICAgICAkcGFyY2lhbFskaV0gPSAkbnVtZXJvc1skaV0gKiAkZmF0b3I7CiAgICAgICAgLy8gU29tYSBkb3MgZGlnaXRvcwogICAgICAgICRzb21hICs9ICRwYXJjaWFsWyRpXTsKICAgICAgICBpZiAoJGZhdG9yID09ICRiYXNlKSB7CiAgICAgICAgICAgIC8vIHJlc3RhdXJhIGZhdG9yIGRlIG11bHRpcGxpY2FjYW8gcGFyYSAyIAogICAgICAgICAgICAkZmF0b3IgPSAxOwogICAgICAgIH0KICAgICAgICAkZmF0b3IrKzsKICAgIH0KCiAgICAvKiBDYWxjdWxvIGRvIG1vZHVsbyAxMSAqLwogICAgaWYgKCRyID09IDApIHsKICAgICAgICAkc29tYSAqPSAxMDsKICAgICAgICAkZGlnaXRvID0gJHNvbWEgJSAxMTsKICAgICAgICBpZiAoJGRpZ2l0byA9PSAxMCkgewogICAgICAgICAgICAkZGlnaXRvID0gMDsKICAgICAgICB9CiAgICAgICAgcmV0dXJuICRkaWdpdG87CiAgICB9IGVsc2VpZiAoJHIgPT0gMSl7CiAgICAgICAgJHJlc3RvID0gJHNvbWEgJSAxMTsKICAgICAgICByZXR1cm4gJHJlc3RvOwogICAgfQp9CgpmdW5jdGlvbiBtb250YV9saW5oYV9kaWdpdGF2ZWwoJGNvZGlnbykgewoJCQoJCS8vIFBvc2nDp8OjbyAJQ29udGXDumRvCiAgICAgICAgLy8gMSBhIDMgICAgTsO6bWVybyBkbyBiYW5jbwogICAgICAgIC8vIDQgICAgICAgIEPDs2RpZ28gZGEgTW9lZGEgLSA5IHBhcmEgUmVhbAogICAgICAgIC8vIDUgICAgICAgIERpZ2l0byB2ZXJpZmljYWRvciBkbyBDw7NkaWdvIGRlIEJhcnJhcwogICAgICAgIC8vIDYgYSA5ICAgRmF0b3IgZGUgVmVuY2ltZW50bwoJCS8vIDEwIGEgMTkgVmFsb3IgKDggaW50ZWlyb3MgZSAyIGRlY2ltYWlzKQogICAgICAgIC8vIDIwIGEgNDQgQ2FtcG8gTGl2cmUgZGVmaW5pZG8gcG9yIGNhZGEgYmFuY28gKDI1IGNhcmFjdGVyZXMpCgogICAgICAgIC8vIDEuIENhbXBvIC0gY29tcG9zdG8gcGVsbyBjw7NkaWdvIGRvIGJhbmNvLCBjw7NkaWdvIGRhIG1vw6lkYSwgYXMgY2luY28gcHJpbWVpcmFzIHBvc2nDp8O1ZXMKICAgICAgICAvLyBkbyBjYW1wbyBsaXZyZSBlIERWIChtb2R1bG8xMCkgZGVzdGUgY2FtcG8KICAgICAgICAkcDEgPSBzdWJzdHIoJGNvZGlnbywgMCwgNCk7CiAgICAgICAgJHAyID0gc3Vic3RyKCRjb2RpZ28sIDE5LCA1KTsKICAgICAgICAkcDMgPSBtb2R1bG9fMTAoIiRwMSRwMiIpOwogICAgICAgICRwNCA9ICIkcDEkcDIkcDMiOwogICAgICAgICRwNSA9IHN1YnN0cigkcDQsIDAsIDUpOwogICAgICAgICRwNiA9IHN1YnN0cigkcDQsIDUpOwogICAgICAgICRjYW1wbzEgPSAiJHA1LiRwNiI7CgogICAgICAgIC8vIDIuIENhbXBvIC0gY29tcG9zdG8gcGVsYXMgcG9zacOnb2VzIDYgYSAxNSBkbyBjYW1wbyBsaXZyZQogICAgICAgIC8vIGUgbGl2cmUgZSBEViAobW9kdWxvMTApIGRlc3RlIGNhbXBvCiAgICAgICAgJHAxID0gc3Vic3RyKCRjb2RpZ28sIDI0LCAxMCk7CiAgICAgICAgJHAyID0gbW9kdWxvXzEwKCRwMSk7CiAgICAgICAgJHAzID0gIiRwMSRwMiI7CiAgICAgICAgJHA0ID0gc3Vic3RyKCRwMywgMCwgNSk7CiAgICAgICAgJHA1ID0gc3Vic3RyKCRwMywgNSk7CiAgICAgICAgJGNhbXBvMiA9ICIkcDQuJHA1IjsKCiAgICAgICAgLy8gMy4gQ2FtcG8gY29tcG9zdG8gcGVsYXMgcG9zaWNvZXMgMTYgYSAyNSBkbyBjYW1wbyBsaXZyZQogICAgICAgIC8vIGUgbGl2cmUgZSBEViAobW9kdWxvMTApIGRlc3RlIGNhbXBvCiAgICAgICAgJHAxID0gc3Vic3RyKCRjb2RpZ28sIDM0LCAxMCk7CiAgICAgICAgJHAyID0gbW9kdWxvXzEwKCRwMSk7CiAgICAgICAgJHAzID0gIiRwMSRwMiI7CiAgICAgICAgJHA0ID0gc3Vic3RyKCRwMywgMCwgNSk7CiAgICAgICAgJHA1ID0gc3Vic3RyKCRwMywgNSk7CiAgICAgICAgJGNhbXBvMyA9ICIkcDQuJHA1IjsKCiAgICAgICAgLy8gNC4gQ2FtcG8gLSBkaWdpdG8gdmVyaWZpY2Fkb3IgZG8gY29kaWdvIGRlIGJhcnJhcwogICAgICAgICRjYW1wbzQgPSBzdWJzdHIoJGNvZGlnbywgNCwgMSk7CgogICAgICAgIC8vIDUuIENhbXBvIGNvbXBvc3RvIHBlbG8gZmF0b3IgdmVuY2ltZW50byBlIHZhbG9yIG5vbWluYWwgZG8gZG9jdW1lbnRvLCBzZW0KICAgICAgICAvLyBpbmRpY2FjYW8gZGUgemVyb3MgYSBlc3F1ZXJkYSBlIHNlbSBlZGljYW8gKHNlbSBwb250byBlIHZpcmd1bGEpLiBRdWFuZG8gc2UKICAgICAgICAvLyB0cmF0YXIgZGUgdmFsb3IgemVyYWRvLCBhIHJlcHJlc2VudGFjYW8gZGV2ZSBzZXIgMDAwICh0cmVzIHplcm9zKS4KCQkkcDEgPSBzdWJzdHIoJGNvZGlnbywgNSwgNCk7CgkJJHAyID0gc3Vic3RyKCRjb2RpZ28sIDksIDEwKTsKCQkkY2FtcG81ID0gIiRwMSRwMiI7CgogICAgICAgIHJldHVybiAiJGNhbXBvMSAkY2FtcG8yICRjYW1wbzMgJGNhbXBvNCAkY2FtcG81IjsgCn0KCmZ1bmN0aW9uIGdlcmFDb2RpZ29CYW5jbygkbnVtZXJvKSB7CiAgICAkcGFydGUxID0gc3Vic3RyKCRudW1lcm8sIDAsIDMpOwogICAgJHBhcnRlMiA9IG1vZHVsb18xMSgkcGFydGUxKTsKICAgIHJldHVybiAkcGFydGUxIC4gIi0iIC4gJHBhcnRlMjsKfQoKPz4K