#########################################################################
# fhem Modul für Victron BMV 600 Batteriemonitor
# Die Beschreibung und Kommentierung dieses Moduls ist in deutsch gehalten,
# um anderen das erstellen eigener Module zu erleichtern.
# Als Basis diente das Modul 00_TAHR.pm und 00_WHR962.pm
#
# # Kommentarbereich
use strict; #
use warnings; #
use Time
:: HiRes qw ( gettimeofday
) ; #
sub BMV600_Read( $) ; #
sub BMV600_Ready( $) ; #
sub BMV600_setbits( $$ ) ; #
sub BMV600_SetReading( $$ $$ ) ; #
my $buf1 = "" ; # Hilfsvariable für auslesen des Buffers
my $Zeit = 0 ; # Hilfsvariable Zeit
my $Umin = 15 ; #Hilfsvariable Minimale Batteriespannung (um ungültige Werte abzufangen) in V
my $Umax = 38 ; #dito, nur uMax
my %BMV600_sets = ( # Hier werden Befehle an den Batterie Monitor geschickt
) ;
#########################################################################
sub BMV600_Initialize( $)
{
my ( $hash ) = @_ ;
require "$attr{global}{modpath}/FHEM/DevIo.pm" ;
$hash -> { ReadFn} = "BMV600_Read" ;
$hash -> { ReadyFn} = "BMV600_Ready" ;
$hash -> { DefFn} = "BMV600_Define" ;
$hash -> { UndefFn} = "BMV600_Undef" ;
$hash -> { SetFn} = "BMV600_Set" ;
$hash -> { AttrList} =
"do_not_notify:1,0 loglevel:0,1,2,3,4,5,6 " . $readingFnAttributes ;
}
######################################################################### #
sub BMV600_Define( $$ )
{
my ( $hash , $def ) = @_ ;
my @a = split ( "[ \t ][ \t ]*" , $def ) ;
return "wrong syntax: define <name> BMV600 [devicename|none]" if ( @a != 3 ) ;
DevIo_CloseDev( $hash ) ;
my $name = $a [ 0 ] ;
my $dev = $a [ 2 ] ;
if ( $dev eq "none" )
{
Log3
undef , 1 , "BMV600 device is none, commands will be echoed only" ; }
$hash -> { DeviceName} = $dev ;
my $ret = DevIo_OpenDev( $hash , 0 , "BMV600_Poll" ) ;
}
#########################################################################
sub #
BMV600_Undef( $$ ) #
{ #
my ( $hash , $arg ) = @_ ; #
DevIo_CloseDev( $hash ) ; #
RemoveInternalTimer( $hash ) ; #
} #
#########################################################################
sub BMV600_Set( $@ )
{
my ( $hash , @a ) = @_ ;
my $name = $hash -> { NAME} ;
return "\" set BMV600\" needs at least an argument" if ( @a < 2 ) ;
my $cmd = $BMV600_sets { $a [ 1 ] } ;
return "Unknown argument $a[1], choose one of "
Log3 $name , 3 , "DevIo_SimpleWrite: $hash $cmd" ;
DevIo_SimpleWrite( $hash , $cmd , 1 ) ;
}
sub BMV600_Read( $)
{
my ( $hash ) = @_ ;
my $name = $hash -> { NAME} ;
my ( $data , $crc ) ;
my $buf = DevIo_SimpleRead( $hash ) ;
my $tn = TimeNow( ) ;
my ( $key , $val ) = ( "key" , "val" ) ;
my $Power = 0 ;
###### Daten der seriellen Schnittstelle holen und an $buf1 anhaengen
$buf1 .= $buf ;
#Log3 $name, 5, "Current buffer content: " $buf1;
my $pos_cs0 = index ( $buf1 , "\n Checksum" ) ; #sucht nach neuer Zeile mit Checksum my $pos_cs1 = - 1 ;
if ( $pos_cs0 >= 0 )
{
$pos_cs1 = index ( $buf1 , "\n Checksum" , $pos_cs0 + 1 ) ; }
if ( ( $pos_cs0 >= 0 ) && ( $pos_cs1 >= 0 ) ) #wenn 2mal Checksum dann beginnt er das lesen
{
readingsBeginUpdate( $hash ) ;
my @e = split ( "\n " , $buf1 ) ; #Splittet die Daten bei einer neuen Zeile auf my $V_first = index ( $e [ 1 ] , "V" ) >= 0 ; #schaut in die Schlaufe und fängt bei V an for my $i ( 0 .. $#e )
{
my @e_ = split ( " " , $e [ $i ] ) ; if ( $e_ [ 0 ] eq "Checksum" )
{
next ;
}
if ( $e_ [ 0 ] eq "V" )
{
if ( ( $e_ [ 1 ] / 1000 ) > $Umin && ( $e_ [ 1 ] / 1000 ) < $Umax ) #nur Werte übernehmen die im gültigen bereich liegen
{
#readingsBulkUpdate($hash,"_V",($e_[1] ));
readingsBulkUpdate
( $hash , "Spannung" , sprintf ( "%.1f" , $e_ [ 1 ] / 1000 ) ) ; $Power = $e_ [ 1 ] / 1000 ; #für Leistungsberechnung als Reading
}
}
if ( $e_ [ 0 ] eq "I" )
{
#readingsBulkUpdate($hash,"_I",($e_[1])); # aktueller Strom in mA
readingsBulkUpdate
( $hash , "Strom" , sprintf ( "%.1f" , $e_ [ 1 ] / 1000 ) ) ; # aktueller Strom in A $Power = ( $Power * $e_ [ 1 ] ) / 1000 ; #für Leistungsberechnung als Reading
}
if ( $e_ [ 0 ] eq "SOC" )
{
if ( ( $e_ [ 1 ] ) > - 1 && ( $e_ [ 1 ] ) < 1001 )
{
#readingsBulkUpdate($hash,"_SOC",$e_[1]); # Ladezustand in %
readingsBulkUpdate
( $hash , "Ladezustand" , sprintf ( "%.2f" , ( $e_ [ 1 ] ) / 10 ) ) ; # Ladezustand in % }
}
if ( $e_ [ 0 ] eq "TTG" )
{
#readingsBulkUpdate($hash,"_TTG",$e_[1]); #Restlaufzeit in Minuten
readingsBulkUpdate
( $hash , "Restlaufzeit_h" , sprintf ( "%.2f" , ( $e_ [ 1 ] ) / 60 ) ) ; #Restlaufzeit in stunden }
if ( $e_ [ 0 ] eq "VS" )
{
#readingsBulkUpdate($hash,"_VS",$e_[1]);
readingsBulkUpdate
( $hash , "Starterbatteriespannung" , sprintf ( "%.2f" , ( $e_ [ 1 ] ) / 1000 ) ) ; #Spannung der Starterbatterie }
if ( $e_ [ 0 ] eq "CE" )
{
#readingsBulkUpdate($hash,"_CE",$e_[1]); #entnommene Kapazität in Ah
readingsBulkUpdate
( $hash , "Amperestunden" , sprintf ( "%.1f" , $e_ [ 1 ] / 1000 ) ) ; }
if ( $e_ [ 0 ] eq "H1" ) # mAh Wert der bisher tiefsten Entladung
{
#readingsBulkUpdate($hash,"_H1",$e_[1]);
readingsBulkUpdate
( $hash , "Entladung_tiefste_Ah" , sprintf ( "%.2f" , $e_ [ 1 ] / 1000 ) ) ; }
if ( $e_ [ 0 ] eq "H2" ) # mAh Wert der letzten Entladung
{
#readingsBulkUpdate($hash,"_H2",$e_[1]);
readingsBulkUpdate
( $hash , "Entladung_letzte_Ah" , sprintf ( "%.2f" , $e_ [ 1 ] / 1000 ) ) ; }
if ( $e_ [ 0 ] eq "H3" ) # mAh Wert der durchschnittlichen Entladung
{
#readingsBulkUpdate($hash,"_H3",$e_[1]);
readingsBulkUpdate
( $hash , "Entladung_Durchschnitt_Ah" , sprintf ( "%.2f" , $e_ [ 1 ] / 1000 ) ) ; }
if ( $e_ [ 0 ] eq "H4" ) # Anzahl der Ladezyklen
{
#readingsBulkUpdate($hash,"_H4",$e_[1]);
readingsBulkUpdate( $hash , "Ladezyklen_Anzahl" , $e_ [ 1 ] ) ;
}
if ( $e_ [ 0 ] eq "H5" ) # Anzahl der völligen Entladungen
{
#readingsBulkUpdate($hash,"_H5",$e_[1]);
readingsBulkUpdate( $hash , "Entladung_voellige_Anzahl" , $e_ [ 1 ] ) ;
}
if ( $e_ [ 0 ] eq "H6" ) # mAh Gesamtwert (kumuliert) der bisher entnommenen Ah
{
#readingsBulkUpdate($hash,"_H6",$e_[1]);
readingsBulkUpdate
( $hash , "Entladung_gesamt_Ah" , sprintf ( "%.2f" , $e_ [ 1 ] / 1000 ) ) ; }
if ( $e_ [ 0 ] eq "H7" ) # mV Minimalwert der Batteriespannung
{
#readingsBulkUpdate($hash,"_H7",$e_[1]);
readingsBulkUpdate
( $hash , "Spannung_minmal" , sprintf ( "%.2f" , $e_ [ 1 ] / 1000 ) ) ; }
if ( $e_ [ 0 ] eq "H8" ) # mV Maximalwert der Batteriespannung
{
#readingsBulkUpdate($hash,"_H8",$e_[1]);
readingsBulkUpdate
( $hash , "Spannung_maximal" , sprintf ( "%.2f" , $e_ [ 1 ] / 1000 ) ) ; }
if ( $e_ [ 0 ] eq "H9" ) # Sekunden Anzahl der Tage seit der letzten Volladung
{
#readingsBulkUpdate($hash,"_H9",$e_[1]);
readingsBulkUpdate
( $hash , "Volladung_letzte_vor_Stunden" , sprintf ( "%.2f" , $e_ [ 1 ] / 3600 ) ) ; }
if ( $e_ [ 0 ] eq "H10" ) # Anzahl der automatisch durchgeführten Synchronistionen
{
#readingsBulkUpdate($hash,"_H10",$e_[1]);
readingsBulkUpdate( $hash , "autom_Synchronisationen_Anzahl" , $e_ [ 1 ] ) ;
}
if ( $e_ [ 0 ] eq "H11" ) # Anzahl der Unterspannungs Alarme
{
#readingsBulkUpdate($hash,"_H11",$e_[1]);
readingsBulkUpdate( $hash , "Alarm_Unterspannung_Anzahl" , $e_ [ 1 ] ) ;
}
if ( $e_ [ 0 ] eq "H12" ) # Anzahl der Überspannungs Alarme.
{
#readingsBulkUpdate($hash,"_H12",$e_[1]);
readingsBulkUpdate( $hash , "Alarm_Ueberspannungs_Anzahl" , $e_ [ 1 ] ) ;
}
if ( $e_ [ 0 ] eq "H13" ) # Anzahl der Alarme für leere Starterbatterie. nur beim BMV-602
{
#readingsBulkUpdate($hash,"_H13",$e_[1]);
readingsBulkUpdate( $hash , "Alarm_leere_Starterbatterie_Anzahl" , $e_ [ 1 ] ) ;
}
if ( $e_ [ 0 ] eq "H14" ) # Anzahl der Alarme bezüglich der Zahl der Überspannungsalarme nur beim BMV-602
{
#readingsBulkUpdate($hash,"_H14",$e_[1]);
readingsBulkUpdate( $hash , "Alarm_Ueberspannung_Starterbatterie_Anzahl" , $e_ [ 1 ] ) ;
}
if ( $e_ [ 0 ] eq "H15" ) # Minimale Starter-Batterie-Spannung. nur beim BMV-602
{
#readingsBulkUpdate($hash,"_H15",$e_[1]);
readingsBulkUpdate
( $hash , "Starterbatteriespannung_minimal" , sprintf ( "%.2f" , $e_ [ 1 ] / 1000 ) ) ; }
if ( $e_ [ 0 ] eq "H16" ) # Maximale Starterbatteriespannung nur beim BMV-602
{
#readingsBulkUpdate($hash,"_H16",$e_[1]);
readingsBulkUpdate
( $hash , "Starterbatteriespannung_maximal" , sprintf ( "%.2f" , $e_ [ 1 ] / 1000 ) ) ; }
if ( $e_ [ 0 ] eq "Alarm" )
{
#readingsBulkUpdate($hash,"_Alarm",$e_[1]);
readingsBulkUpdate( $hash , "Alarmzustand" , $e_ [ 1 ] ) ;
}
if ( $e_ [ 0 ] eq "AR" )
{
# Alarm Reason :
#Low Voltage 1
#High Voltage 2
#Low SOC 4
#Low Starter Voltage 8
#High Starter Voltage 16
if ( $e_ [ 1 ] eq "0" ) { readingsBulkUpdate( $hash , "Alarm_Reason" , "-" ) ; }
elsif ( $e_ [ 1 ] eq "1" ) { readingsBulkUpdate( $hash , "Alarm_Reason" , "Low Voltage" ) ; }
elsif ( $e_ [ 1 ] eq "2" ) { readingsBulkUpdate( $hash , "Alarm_Reason" , "High Voltage" ) ; }
elsif ( $e_ [ 1 ] eq "4" ) { readingsBulkUpdate( $hash , "Alarm_Reason" , "Low SOC" ) ; }
elsif ( $e_ [ 1 ] eq "8" ) { readingsBulkUpdate( $hash , "Alarm_Reason" , "Low Starter Voltage" ) ; }
elsif ( $e_ [ 1 ] eq "16" ) { readingsBulkUpdate( $hash , "Alarm_Reason" , "High Starter Voltage" ) ; }
else { readingsBulkUpdate( $hash , "Alarm_Reason" , "Multi-Alarm" ) ; }
#readingsBulkUpdate($hash,"_AR",$e_[1]);
}
if ( $e_ [ 0 ] eq "FW" )
{
#readingsBulkUpdate($hash,"_FW",$e_[1]);
readingsBulkUpdate( $hash , "BMV_Firmware" , $e_ [ 1 ] ) ;
}
if ( $e_ [ 0 ] eq "BMV" )
{
#readingsBulkUpdate($hash,"_BMV",$e_[1]);
readingsBulkUpdate( $hash , "BMV_Modell" , $e_ [ 1 ] ) ;
}
}
readingsBulkUpdate
( $hash , "Power" , sprintf ( "%.2f" , $Power ) ) ; #readingsBulkUpdate($hash,"Umin(System)",$Umin);
#readingsBulkUpdate($hash,"Umax(System)",$Umax);
readingsEndUpdate( $hash , 1 ) ;
$buf1 = "" ;
}
}
#########################################################################
sub BMV600_Ready( $)
{
my ( $hash ) = @_ ;
if ( $hash -> { STATE} eq "disconnected" ) ;
# This is relevant for windows/USB only
my $po = $hash -> { USBDev} ;
my ( $BlockingFlags , $InBytes , $OutBytes , $ErrorFlags ) = $po -> status ;
}
#########################################################################
sub BMV600_Poll( $)
{
my ( $hash ) = @_ ;
my $name = $hash -> { NAME} ;
push @ { $hash -> { SENDBUFFER
} } , $BMV600_sets { "logmode" } ; DevIo_SimpleWrite( $hash , "07F0009B01014A070F" , 1 ) ;
Log3 $name , 5 , "RS232 Modus PC-Master" ;
}
#########################################################################
sub BMV600_SetReading( $$ $$ )
{
my ( $hash , $tn , $key , $val ) = @_ ;
my $name = $hash -> { NAME} ;
Log3 $name , 4 , "$name: $key $val" ;
$hash -> { READINGS} { $key } { TIME} = $tn ;
$hash -> { READINGS} { $key } { VAL} = $val ;
DoTrigger( $name , "$key: $val" ) ;
}
1 ;
IyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIGZoZW0gTW9kdWwgZsO8ciBWaWN0cm9uIEJNViA2MDAgQmF0dGVyaWVtb25pdG9yCiMgRGllIEJlc2NocmVpYnVuZyB1bmQgS29tbWVudGllcnVuZyBkaWVzZXMgTW9kdWxzIGlzdCBpbiBkZXV0c2NoIGdlaGFsdGVuLAojIHVtIGFuZGVyZW4gZGFzIGVyc3RlbGxlbiBlaWdlbmVyIE1vZHVsZSB6dSBlcmxlaWNodGVybi4KIyBBbHMgQmFzaXMgZGllbnRlIGRhcyBNb2R1bCAwMF9UQUhSLnBtIHVuZCAwMF9XSFI5NjIucG0KIwojCQkJCQkJCQkJCSMgS29tbWVudGFyYmVyZWljaApwYWNrYWdlIG1haW47Cgp1c2Ugc3RyaWN0OyAgICAgICAgICAgICAgICAgICAgICAgICAgIwp1c2Ugd2FybmluZ3M7ICAgICAgICAgICAgICAgICAgICAgICAgIwp1c2UgVGltZTo6SGlSZXMgcXcoZ2V0dGltZW9mZGF5KTsgICAgIwoKc3ViIEJNVjYwMF9SZWFkKCQpOyAgICAgICAgICAgICAgICAgICMKc3ViIEJNVjYwMF9SZWFkeSgkKTsgICAgICAgICAgICAgICAgICMKc3ViIEJNVjYwMF9zZXRiaXRzKCQkKTsgICAgICAgICAgICAgICMKc3ViIEJNVjYwMF9TZXRSZWFkaW5nKCQkJCQpOyAgICAgICAgICMKCm15ICRidWYxID0gIiI7ICAgICAgICAgICAgICAgICAgICAgICAjIEhpbGZzdmFyaWFibGUgZsO8ciBhdXNsZXNlbiBkZXMgQnVmZmVycwpteSAkWmVpdCA9IDA7ICAgICAgICAgICAgICAgICAgICAgICAgIyBIaWxmc3ZhcmlhYmxlIFplaXQKbXkgJFVtaW4gPSAxNTsgICAgICAgICAgICAgICAgICAgICAgICNIaWxmc3ZhcmlhYmxlIE1pbmltYWxlIEJhdHRlcmllc3Bhbm51bmcgKHVtIHVuZ8O8bHRpZ2UgV2VydGUgYWJ6dWZhbmdlbikgaW4gVgpteSAkVW1heCA9IDM4OyAgICAgICAgICAgICAgICAgICAgICAjZGl0bywgbnVyIHVNYXgKCm15ICVCTVY2MDBfc2V0cyA9ICggICAgCQkjIEhpZXIgd2VyZGVuIEJlZmVobGUgYW4gZGVuIEJhdHRlcmllIE1vbml0b3IgZ2VzY2hpY2t0CgopOwoKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKc3ViIEJNVjYwMF9Jbml0aWFsaXplKCQpCnsKCW15ICgkaGFzaCkgPSBAXzsKCglyZXF1aXJlICIkYXR0cntnbG9iYWx9e21vZHBhdGh9L0ZIRU0vRGV2SW8ucG0iOwoKCSRoYXNoLT57UmVhZEZufSAgPSAiQk1WNjAwX1JlYWQiOwoJJGhhc2gtPntSZWFkeUZufSA9ICJCTVY2MDBfUmVhZHkiOwoJJGhhc2gtPntEZWZGbn0gICA9ICJCTVY2MDBfRGVmaW5lIjsKCSRoYXNoLT57VW5kZWZGbn0gPSAiQk1WNjAwX1VuZGVmIjsKCSRoYXNoLT57U2V0Rm59ICAgPSAiQk1WNjAwX1NldCI7CgkkaGFzaC0+e0F0dHJMaXN0fSA9CgkgICJkb19ub3Rfbm90aWZ5OjEsMCBsb2dsZXZlbDowLDEsMiwzLDQsNSw2ICIgLiAkcmVhZGluZ0ZuQXR0cmlidXRlczsKfQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwkJCQkJCQkJCSMKc3ViIEJNVjYwMF9EZWZpbmUoJCQpCnsKCW15ICggJGhhc2gsICRkZWYgKSA9IEBfOwoJbXkgQGEgPSBzcGxpdCggIlsgXHRdWyBcdF0qIiwgJGRlZiApOwkKCglyZXR1cm4gIndyb25nIHN5bnRheDogZGVmaW5lIDxuYW1lPiBCTVY2MDAgW2RldmljZW5hbWV8bm9uZV0iCgkgIGlmICggQGEgIT0gMyApOwoKCURldklvX0Nsb3NlRGV2KCRoYXNoKTsKCW15ICRuYW1lID0gJGFbMF07CglteSAkZGV2ICA9ICRhWzJdOwoKCWlmICggJGRldiBlcSAibm9uZSIgKQoJewoJCUxvZzMgdW5kZWYsIDEsICJCTVY2MDAgZGV2aWNlIGlzIG5vbmUsIGNvbW1hbmRzIHdpbGwgYmUgZWNob2VkIG9ubHkiOwoJCXJldHVybiB1bmRlZjsKCX0KCgkkaGFzaC0+e0RldmljZU5hbWV9ID0gJGRldjsKCW15ICRyZXQgPSBEZXZJb19PcGVuRGV2KCAkaGFzaCwgMCwgIkJNVjYwMF9Qb2xsIiApOwoJcmV0dXJuICRyZXQ7Cn0KCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKc3ViICAgICAgICAgICAgICAgICAgICMKICBCTVY2MDBfVW5kZWYoJCQpICAgICMKeyAgICAgICAgICAgICAgICAgICAgICMKCW15ICggJGhhc2gsICRhcmcgKSA9IEBfOyAgICAgICAjCglEZXZJb19DbG9zZURldigkaGFzaCk7ICAgICAgICAgIwoJUmVtb3ZlSW50ZXJuYWxUaW1lcigkaGFzaCk7ICAgICMKCXJldHVybiB1bmRlZjsgICAgICAgICAgICAgICAgICAjCn0gICAgIwoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpzdWIgQk1WNjAwX1NldCgkQCkKewoJbXkgKCAkaGFzaCwgQGEgKSA9IEBfOwoJbXkgJG5hbWUgPSAkaGFzaC0+e05BTUV9OwoJcmV0dXJuICJcInNldCBCTVY2MDBcIiBuZWVkcyBhdCBsZWFzdCBhbiBhcmd1bWVudCIgaWYgKCBAYSA8IDIgKTsKCglteSAkY21kID0gJEJNVjYwMF9zZXRzeyAkYVsxXSB9OwoJcmV0dXJuICJVbmtub3duIGFyZ3VtZW50ICRhWzFdLCBjaG9vc2Ugb25lIG9mICIKCSAgLiBqb2luKCAiICIsIHNvcnQga2V5cyAlQk1WNjAwX3NldHMgKQoJICBpZiAoICFkZWZpbmVkKCRjbWQpICk7CgoJTG9nMyAkbmFtZSwgMywgIkRldklvX1NpbXBsZVdyaXRlOiAkaGFzaCAkY21kIjsKCURldklvX1NpbXBsZVdyaXRlKCAkaGFzaCwgJGNtZCwgMSApOwoJcmV0dXJuIHVuZGVmOwp9CgoKc3ViIEJNVjYwMF9SZWFkKCQpCnsKCW15ICgkaGFzaCkgPSBAXzsKCW15ICRuYW1lID0gJGhhc2gtPntOQU1FfTsKCW15ICggJGRhdGEsICRjcmMgKTsKCW15ICRidWYgPSBEZXZJb19TaW1wbGVSZWFkKCRoYXNoKTsKCW15ICR0biAgPSBUaW1lTm93KCk7CglteSAoICRrZXksICR2YWwgKSA9ICggImtleSIsICJ2YWwiICk7CiAgbXkgJFBvd2VyID0gMDsgIAogIAoJIyMjIyMjIERhdGVuIGRlciBzZXJpZWxsZW4gU2Nobml0dHN0ZWxsZSBob2xlbiB1bmQgYW4gJGJ1ZjEgYW5oYWVuZ2VuCgoJcmV0dXJuICIiIGlmICggIWRlZmluZWQoJGJ1ZikgKTsKCSRidWYxIC49ICRidWY7CgoJI0xvZzMgJG5hbWUsIDUsICJDdXJyZW50IGJ1ZmZlciBjb250ZW50OiAiICAkYnVmMTsKCiAgICAgICAgbXkgJHBvc19jczAgPSBpbmRleCgkYnVmMSwiXG5DaGVja3N1bSIpOwkJCSNzdWNodCBuYWNoIG5ldWVyIFplaWxlIG1pdCBDaGVja3N1bQogICAgICAgIG15ICRwb3NfY3MxID0gLTE7CglpZigkcG9zX2NzMCA+PSAwKQoJewoJICAgICAgICAkcG9zX2NzMSA9IGluZGV4KCRidWYxLCJcbkNoZWNrc3VtIiwkcG9zX2NzMCsxKTsKCX0KCWlmKCgkcG9zX2NzMCA+PSAwKSAmJiAoJHBvc19jczEgPj0gMCkpCQkJCSN3ZW5uIDJtYWwgQ2hlY2tzdW0gZGFubiBiZWdpbm50IGVyIGRhcyBsZXNlbgoJewoJCXJlYWRpbmdzQmVnaW5VcGRhdGUoJGhhc2gpOwogICAgICAJICAgICAgICBteSBAZSA9IHNwbGl0KCJcbiIsJGJ1ZjEpOwkJCQkjU3BsaXR0ZXQgZGllIERhdGVuIGJlaSBlaW5lciBuZXVlbiBaZWlsZSBhdWYKCQlteSAkVl9maXJzdCA9IGluZGV4KCRlWzFdLCJWIikgPj0gMDsJCQkjc2NoYXV0IGluIGRpZSBTY2hsYXVmZSB1bmQgZsOkbmd0IGJlaSBWIGFuCgkJZm9yIG15ICRpICgwIC4uICQjZSkKCQl7CgkJCQogICAgICBteSBAZV8gPSBzcGxpdCgiICIsJGVbJGldKTsKCQkJaWYoJGVfWzBdIGVxICJDaGVja3N1bSIpCgkJCXsKCQkJCW5leHQ7CgkJCX0KICAgICAgaWYoJGVfWzBdIGVxICJWIikKCQkJewoJCQkJaWYoKCRlX1sxXSAvMTAwMCApID4gJFVtaW4gJiYgKCRlX1sxXSAvMTAwMCApIDwgJFVtYXggKSAjbnVyIFdlcnRlIMO8YmVybmVobWVuIGRpZSBpbSBnw7xsdGlnZW4gYmVyZWljaCBsaWVnZW4KICAgICAgICB7CiAgICAgICAgICAjcmVhZGluZ3NCdWxrVXBkYXRlKCRoYXNoLCJfViIsKCRlX1sxXSApKTsgCiAgICAgICAgICByZWFkaW5nc0J1bGtVcGRhdGUoJGhhc2gsIlNwYW5udW5nIixzcHJpbnRmKCIlLjFmIiwkZV9bMV0vMTAwMCkpOwogICAgICAgICAgJFBvd2VyID0gJGVfWzFdIC8gMTAwMDsgIAkJCSNmw7xyIExlaXN0dW5nc2JlcmVjaG51bmcgYWxzIFJlYWRpbmcKICAgICAgICB9CgkJCX0KCQkKCQkgICAKICAgICAgaWYoJGVfWzBdIGVxICJJIikKCQkJewoJI3JlYWRpbmdzQnVsa1VwZGF0ZSgkaGFzaCwiX0kiLCgkZV9bMV0pKTsgICMgYWt0dWVsbGVyIFN0cm9tIGluIG1BCiAgICAgICAgcmVhZGluZ3NCdWxrVXBkYXRlKCRoYXNoLCJTdHJvbSIsc3ByaW50ZigiJS4xZiIsJGVfWzFdIC8gMTAwMCkpOyAjIGFrdHVlbGxlciBTdHJvbSBpbiBBCiAgICAgICAgJFBvd2VyID0gKCRQb3dlciAqICRlX1sxXSkgLyAxMDAwOyAgICAgICAgICAgCSNmw7xyIExlaXN0dW5nc2JlcmVjaG51bmcgYWxzIFJlYWRpbmcKCQkJfQogICAgICAKICAgICAgaWYoJGVfWzBdIGVxICJTT0MiKQoJCQl7CgkJCQlpZigoJGVfWzFdKSA+IC0xICYmICgkZV9bMV0pIDwgMTAwMSApCiAgICAgICAgewogICAgICAgICNyZWFkaW5nc0J1bGtVcGRhdGUoJGhhc2gsIl9TT0MiLCRlX1sxXSk7ICAjIExhZGV6dXN0YW5kIGluICUKICAgICAgICByZWFkaW5nc0J1bGtVcGRhdGUoJGhhc2gsIkxhZGV6dXN0YW5kIixzcHJpbnRmKCIlLjJmIiwoJGVfWzFdKSAvIDEwKSk7ICAjIExhZGV6dXN0YW5kIGluICUKICAgICAgICB9CgkJCX0KICAgICAgaWYoJGVfWzBdIGVxICJUVEciKQoJCQl7CgkjcmVhZGluZ3NCdWxrVXBkYXRlKCRoYXNoLCJfVFRHIiwkZV9bMV0pOyAgICNSZXN0bGF1ZnplaXQgaW4gTWludXRlbgogICAgICAgIHJlYWRpbmdzQnVsa1VwZGF0ZSgkaGFzaCwiUmVzdGxhdWZ6ZWl0X2giLHNwcmludGYoIiUuMmYiLCgkZV9bMV0pIC8gNjApKTsgICAjUmVzdGxhdWZ6ZWl0IGluIHN0dW5kZW4KCQkJfQogICAgICBpZigkZV9bMF0gZXEgIlZTIikKCQkJewoJI3JlYWRpbmdzQnVsa1VwZGF0ZSgkaGFzaCwiX1ZTIiwkZV9bMV0pOwogICAgICAgIHJlYWRpbmdzQnVsa1VwZGF0ZSgkaGFzaCwiU3RhcnRlcmJhdHRlcmllc3Bhbm51bmciLHNwcmludGYoIiUuMmYiLCgkZV9bMV0pIC8gMTAwMCkpOyAjU3Bhbm51bmcgZGVyIFN0YXJ0ZXJiYXR0ZXJpZQoJCQl9CiAgICAgIGlmKCRlX1swXSBlcSAiQ0UiKQoJCQl7CgkjcmVhZGluZ3NCdWxrVXBkYXRlKCRoYXNoLCJfQ0UiLCRlX1sxXSk7ICAjZW50bm9tbWVuZSBLYXBheml0w6R0IGluIEFoCiAgICAgICAgcmVhZGluZ3NCdWxrVXBkYXRlKCRoYXNoLCJBbXBlcmVzdHVuZGVuIixzcHJpbnRmKCIlLjFmIiwkZV9bMV0gLzEwMDAgKSk7CgkJCX0KICAgICAgaWYoJGVfWzBdIGVxICJIMSIpICAgICMgbUFoIFdlcnQgZGVyIGJpc2hlciB0aWVmc3RlbiBFbnRsYWR1bmcgCgkJCXsKCSNyZWFkaW5nc0J1bGtVcGRhdGUoJGhhc2gsIl9IMSIsJGVfWzFdKTsKICAgICAgICByZWFkaW5nc0J1bGtVcGRhdGUoJGhhc2gsIkVudGxhZHVuZ190aWVmc3RlX0FoIixzcHJpbnRmKCIlLjJmIiwkZV9bMV0gLzEwMDAgKSk7CgkJCX0KICAgICAgaWYoJGVfWzBdIGVxICJIMiIpICAgICAjIG1BaCBXZXJ0IGRlciBsZXR6dGVuIEVudGxhZHVuZwoJCQl7CgkjcmVhZGluZ3NCdWxrVXBkYXRlKCRoYXNoLCJfSDIiLCRlX1sxXSk7CiAgICAgICAgcmVhZGluZ3NCdWxrVXBkYXRlKCRoYXNoLCJFbnRsYWR1bmdfbGV0enRlX0FoIixzcHJpbnRmKCIlLjJmIiwkZV9bMV0gLyAxMDAwKSk7CgkJCX0KICAgICAgaWYoJGVfWzBdIGVxICJIMyIpICAgIyBtQWggV2VydCBkZXIgZHVyY2hzY2huaXR0bGljaGVuIEVudGxhZHVuZwoJCQl7CgkjcmVhZGluZ3NCdWxrVXBkYXRlKCRoYXNoLCJfSDMiLCRlX1sxXSk7CiAgICAgICAgcmVhZGluZ3NCdWxrVXBkYXRlKCRoYXNoLCJFbnRsYWR1bmdfRHVyY2hzY2huaXR0X0FoIixzcHJpbnRmKCIlLjJmIiwkZV9bMV0gLyAxMDAwKSk7CgkJCX0KICAgICAgaWYoJGVfWzBdIGVxICJINCIpICAjIEFuemFobCBkZXIgTGFkZXp5a2xlbgoJCQl7CgkjcmVhZGluZ3NCdWxrVXBkYXRlKCRoYXNoLCJfSDQiLCRlX1sxXSk7CiAgICAgICAgcmVhZGluZ3NCdWxrVXBkYXRlKCRoYXNoLCJMYWRlenlrbGVuX0FuemFobCIsJGVfWzFdKTsKCQkJfQogICAgICBpZigkZV9bMF0gZXEgIkg1IikgIyBBbnphaGwgZGVyIHbDtmxsaWdlbiBFbnRsYWR1bmdlbiAKCQkJewoJI3JlYWRpbmdzQnVsa1VwZGF0ZSgkaGFzaCwiX0g1IiwkZV9bMV0pOwogICAgICAgIHJlYWRpbmdzQnVsa1VwZGF0ZSgkaGFzaCwiRW50bGFkdW5nX3ZvZWxsaWdlX0FuemFobCIsJGVfWzFdKTsKCQkJfQogICAgICBpZigkZV9bMF0gZXEgIkg2IikgICMgbUFoIEdlc2FtdHdlcnQgKGt1bXVsaWVydCkgZGVyIGJpc2hlciBlbnRub21tZW5lbiBBaAoJCQl7CgkjcmVhZGluZ3NCdWxrVXBkYXRlKCRoYXNoLCJfSDYiLCRlX1sxXSk7CiAgICAgICAgcmVhZGluZ3NCdWxrVXBkYXRlKCRoYXNoLCJFbnRsYWR1bmdfZ2VzYW10X0FoIixzcHJpbnRmKCIlLjJmIiwkZV9bMV0gLyAxMDAwKSk7CgkJCX0KICAgICAgaWYoJGVfWzBdIGVxICJINyIpICAjIG1WIE1pbmltYWx3ZXJ0IGRlciBCYXR0ZXJpZXNwYW5udW5nIAoJCQl7CgkjcmVhZGluZ3NCdWxrVXBkYXRlKCRoYXNoLCJfSDciLCRlX1sxXSk7CiAgICAgICAgcmVhZGluZ3NCdWxrVXBkYXRlKCRoYXNoLCJTcGFubnVuZ19taW5tYWwiLHNwcmludGYoIiUuMmYiLCRlX1sxXSAvIDEwMDApKTsKCQkJfQogICAgICBpZigkZV9bMF0gZXEgIkg4IikgICMgbVYgTWF4aW1hbHdlcnQgZGVyIEJhdHRlcmllc3Bhbm51bmcgCgkJCXsKCSNyZWFkaW5nc0J1bGtVcGRhdGUoJGhhc2gsIl9IOCIsJGVfWzFdKTsKICAgICAgICByZWFkaW5nc0J1bGtVcGRhdGUoJGhhc2gsIlNwYW5udW5nX21heGltYWwiLHNwcmludGYoIiUuMmYiLCRlX1sxXSAvIDEwMDApKTsKCQkJfQogICAgICBpZigkZV9bMF0gZXEgIkg5IikgICMgU2VrdW5kZW4gIEFuemFobCBkZXIgVGFnZSBzZWl0IGRlciBsZXR6dGVuIFZvbGxhZHVuZwoJCQl7CgkjcmVhZGluZ3NCdWxrVXBkYXRlKCRoYXNoLCJfSDkiLCRlX1sxXSk7CiAgICAgICAgcmVhZGluZ3NCdWxrVXBkYXRlKCRoYXNoLCJWb2xsYWR1bmdfbGV0enRlX3Zvcl9TdHVuZGVuIixzcHJpbnRmKCIlLjJmIiwkZV9bMV0gLyAzNjAwKSk7CgkJCX0gCiAgICAgIGlmKCRlX1swXSBlcSAiSDEwIikgIyBBbnphaGwgZGVyIGF1dG9tYXRpc2NoIGR1cmNoZ2Vmw7xocnRlbiBTeW5jaHJvbmlzdGlvbmVuIAoJCQl7CgkjcmVhZGluZ3NCdWxrVXBkYXRlKCRoYXNoLCJfSDEwIiwkZV9bMV0pOwogICAgICAgIHJlYWRpbmdzQnVsa1VwZGF0ZSgkaGFzaCwiYXV0b21fU3luY2hyb25pc2F0aW9uZW5fQW56YWhsIiwkZV9bMV0pOwoJCQl9CiAgICAgIGlmKCRlX1swXSBlcSAiSDExIikgIyBBbnphaGwgZGVyIFVudGVyc3Bhbm51bmdzIEFsYXJtZQoJCQl7CgkjcmVhZGluZ3NCdWxrVXBkYXRlKCRoYXNoLCJfSDExIiwkZV9bMV0pOwogICAgICAgIHJlYWRpbmdzQnVsa1VwZGF0ZSgkaGFzaCwiQWxhcm1fVW50ZXJzcGFubnVuZ19BbnphaGwiLCRlX1sxXSk7CgkJCX0KICAgICAgaWYoJGVfWzBdIGVxICJIMTIiKSAjIEFuemFobCBkZXIgw5xiZXJzcGFubnVuZ3MgQWxhcm1lLgoJCQl7CgkjcmVhZGluZ3NCdWxrVXBkYXRlKCRoYXNoLCJfSDEyIiwkZV9bMV0pOwogICAgICAgIHJlYWRpbmdzQnVsa1VwZGF0ZSgkaGFzaCwiQWxhcm1fVWViZXJzcGFubnVuZ3NfQW56YWhsIiwkZV9bMV0pOwoJCQl9CiAgICAgIGlmKCRlX1swXSBlcSAiSDEzIikgIyBBbnphaGwgZGVyIEFsYXJtZSBmw7xyIGxlZXJlIFN0YXJ0ZXJiYXR0ZXJpZS4gIG51ciBiZWltIEJNVi02MDIKCQkJewoJI3JlYWRpbmdzQnVsa1VwZGF0ZSgkaGFzaCwiX0gxMyIsJGVfWzFdKTsKICAgICAgICByZWFkaW5nc0J1bGtVcGRhdGUoJGhhc2gsIkFsYXJtX2xlZXJlX1N0YXJ0ZXJiYXR0ZXJpZV9BbnphaGwiLCRlX1sxXSk7CgkJCX0KICAgICAgaWYoJGVfWzBdIGVxICJIMTQiKSAjIEFuemFobCBkZXIgQWxhcm1lIGJlesO8Z2xpY2ggZGVyIFphaGwgZGVyIMOcYmVyc3Bhbm51bmdzYWxhcm1lIG51ciBiZWltIEJNVi02MDIgCgkJCXsKCSNyZWFkaW5nc0J1bGtVcGRhdGUoJGhhc2gsIl9IMTQiLCRlX1sxXSk7CiAgICAgICAgcmVhZGluZ3NCdWxrVXBkYXRlKCRoYXNoLCJBbGFybV9VZWJlcnNwYW5udW5nX1N0YXJ0ZXJiYXR0ZXJpZV9BbnphaGwiLCRlX1sxXSk7CgkJCX0KICAgICAgaWYoJGVfWzBdIGVxICJIMTUiKSAjIE1pbmltYWxlIFN0YXJ0ZXItQmF0dGVyaWUtU3Bhbm51bmcuICBudXIgYmVpbSBCTVYtNjAyIAoJCQl7CgkjcmVhZGluZ3NCdWxrVXBkYXRlKCRoYXNoLCJfSDE1IiwkZV9bMV0pOwogICAgICAgIHJlYWRpbmdzQnVsa1VwZGF0ZSgkaGFzaCwiU3RhcnRlcmJhdHRlcmllc3Bhbm51bmdfbWluaW1hbCIsc3ByaW50ZigiJS4yZiIsJGVfWzFdIC8gMTAwMCkpOwoJCQl9CiAgICAgIGlmKCRlX1swXSBlcSAiSDE2IikgIyBNYXhpbWFsZSBTdGFydGVyYmF0dGVyaWVzcGFubnVuZyAgbnVyIGJlaW0gQk1WLTYwMgoJCQl7CgkjcmVhZGluZ3NCdWxrVXBkYXRlKCRoYXNoLCJfSDE2IiwkZV9bMV0pOwogICAgICAgIHJlYWRpbmdzQnVsa1VwZGF0ZSgkaGFzaCwiU3RhcnRlcmJhdHRlcmllc3Bhbm51bmdfbWF4aW1hbCIsc3ByaW50ZigiJS4yZiIsJGVfWzFdIC8gMTAwMCkpOwoJCQl9IAogICAgICBpZigkZV9bMF0gZXEgIkFsYXJtIikKCQkJewoJI3JlYWRpbmdzQnVsa1VwZGF0ZSgkaGFzaCwiX0FsYXJtIiwkZV9bMV0pOwogICAgICAgIHJlYWRpbmdzQnVsa1VwZGF0ZSgkaGFzaCwiQWxhcm16dXN0YW5kIiwkZV9bMV0pOwoJCQl9CiAgICAgIGlmKCRlX1swXSBlcSAiQVIiKQoJCQl7CgkJCQkgIyBBbGFybSBSZWFzb24gOgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNMb3cgVm9sdGFnZSAgICAgICAgICAgICAgICAgMSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjSGlnaCBWb2x0YWdlICAgICAgICAgICAgICAgIDIgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI0xvdyBTT0MgICAgICAgICAgICAgICAgICAgICA0IAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNMb3cgU3RhcnRlciBWb2x0YWdlICAgICAgICAgOCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjSGlnaCBTdGFydGVyIFZvbHRhZ2UgICAgICAgIDE2CiAgICAgICAgaWYoJGVfWzFdIGVxICIwIil7cmVhZGluZ3NCdWxrVXBkYXRlKCRoYXNoLCJBbGFybV9SZWFzb24iLCItIik7fQogICAgICAgIGVsc2lmKCRlX1sxXSBlcSAiMSIpe3JlYWRpbmdzQnVsa1VwZGF0ZSgkaGFzaCwiQWxhcm1fUmVhc29uIiwiTG93IFZvbHRhZ2UiKTt9CiAgICAgICAgZWxzaWYoJGVfWzFdIGVxICIyIil7cmVhZGluZ3NCdWxrVXBkYXRlKCRoYXNoLCJBbGFybV9SZWFzb24iLCJIaWdoIFZvbHRhZ2UiKTt9CiAgICAgICAgZWxzaWYoJGVfWzFdIGVxICI0Iil7cmVhZGluZ3NCdWxrVXBkYXRlKCRoYXNoLCJBbGFybV9SZWFzb24iLCJMb3cgU09DIik7fQogICAgICAgIGVsc2lmKCRlX1sxXSBlcSAiOCIpe3JlYWRpbmdzQnVsa1VwZGF0ZSgkaGFzaCwiQWxhcm1fUmVhc29uIiwiTG93IFN0YXJ0ZXIgVm9sdGFnZSIpO30KICAgICAgICBlbHNpZigkZV9bMV0gZXEgIjE2Iil7cmVhZGluZ3NCdWxrVXBkYXRlKCRoYXNoLCJBbGFybV9SZWFzb24iLCJIaWdoIFN0YXJ0ZXIgVm9sdGFnZSIpO30KICAgICAgICBlbHNle3JlYWRpbmdzQnVsa1VwZGF0ZSgkaGFzaCwiQWxhcm1fUmVhc29uIiwiTXVsdGktQWxhcm0iKTt9CiAgICAgICAgI3JlYWRpbmdzQnVsa1VwZGF0ZSgkaGFzaCwiX0FSIiwkZV9bMV0pOwoJCQl9CiAgICAgIGlmKCRlX1swXSBlcSAiRlciKQoJCQl7CgkjcmVhZGluZ3NCdWxrVXBkYXRlKCRoYXNoLCJfRlciLCRlX1sxXSk7CiAgICAgICAgcmVhZGluZ3NCdWxrVXBkYXRlKCRoYXNoLCJCTVZfRmlybXdhcmUiLCRlX1sxXSk7CgkJCX0KICAgICAgaWYoJGVfWzBdIGVxICJCTVYiKQoJCQl7CgkjcmVhZGluZ3NCdWxrVXBkYXRlKCRoYXNoLCJfQk1WIiwkZV9bMV0pOyAKICAgICAgICByZWFkaW5nc0J1bGtVcGRhdGUoJGhhc2gsIkJNVl9Nb2RlbGwiLCRlX1sxXSk7CgkJCX0KICAgICAgCiAgICB9IAogICAgcmVhZGluZ3NCdWxrVXBkYXRlKCRoYXNoLCJQb3dlciIsc3ByaW50ZigiJS4yZiIsJFBvd2VyKSk7CiAgICAjcmVhZGluZ3NCdWxrVXBkYXRlKCRoYXNoLCJVbWluKFN5c3RlbSkiLCRVbWluKTsKICAgICNyZWFkaW5nc0J1bGtVcGRhdGUoJGhhc2gsIlVtYXgoU3lzdGVtKSIsJFVtYXgpOwoJCXJlYWRpbmdzRW5kVXBkYXRlKCAkaGFzaCwgMSApOwoJCSRidWYxID0gIiI7Cgl9Cn0KCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKc3ViIEJNVjYwMF9SZWFkeSgkKQp7CglteSAoJGhhc2gpID0gQF87CgoJcmV0dXJuIERldklvX09wZW5EZXYoICRoYXNoLCAxLCB1bmRlZiApCgkgIGlmICggJGhhc2gtPntTVEFURX0gZXEgImRpc2Nvbm5lY3RlZCIgKTsKCgkjIFRoaXMgaXMgcmVsZXZhbnQgZm9yIHdpbmRvd3MvVVNCIG9ubHkKCW15ICRwbyA9ICRoYXNoLT57VVNCRGV2fTsKCW15ICggJEJsb2NraW5nRmxhZ3MsICRJbkJ5dGVzLCAkT3V0Qnl0ZXMsICRFcnJvckZsYWdzICkgPSAkcG8tPnN0YXR1czsKCXJldHVybiAoICRJbkJ5dGVzID4gMCApOwp9CgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCnN1YiBCTVY2MDBfUG9sbCgkKQp7CglteSAoJGhhc2gpID0gQF87CglteSAkbmFtZSA9ICRoYXNoLT57TkFNRX07CglwdXNoIEB7ICRoYXNoLT57U0VOREJVRkZFUn0gfSwgJEJNVjYwMF9zZXRzeyJsb2dtb2RlIn07CglEZXZJb19TaW1wbGVXcml0ZSggJGhhc2gsICIwN0YwMDA5QjAxMDE0QTA3MEYiLCAxICk7CglMb2czICRuYW1lLCA1LCAiUlMyMzIgTW9kdXMgUEMtTWFzdGVyIjsKCXJldHVybiB1bmRlZjsKfQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpzdWIgQk1WNjAwX1NldFJlYWRpbmcoJCQkJCkKewoJbXkgKCAkaGFzaCwgJHRuLCAka2V5LCAkdmFsICkgPSBAXzsKCW15ICRuYW1lID0gJGhhc2gtPntOQU1FfTsKCUxvZzMgJG5hbWUsIDQsICIkbmFtZTogJGtleSAkdmFsIjsKCSRoYXNoLT57UkVBRElOR1N9eyRrZXl9e1RJTUV9ID0gJHRuOwoJJGhhc2gtPntSRUFESU5HU317JGtleX17VkFMfSAgPSAkdmFsOwoJRG9UcmlnZ2VyKCAkbmFtZSwgIiRrZXk6ICR2YWwiICk7Cn0KCgoxOwo=