<?php
$page_title = 'Run LOME selectivity analysis' ;
require ( '../directoryinfo.php' ) ;
include ( '../connect.php' ) ;
include ( 'functions.php' ) ;
require_once ( '../header.html' ) ;
?>
<!-- Form For Executing Code -->
<form action="index.php" method="post" name="file_select">
<fieldset>
<table align="left" cellspacing=15>
<tr><td colspan="2"><input type="checkbox" checked name="go" value="yes"><STRONG>Run Full Analysis</STRONG></td></tr>
<tr><td colspan=2><input type="submit" name="submit" value="Submit"></td></tr>
</table>
</fieldset>
</form>
<?php
if ( isset ( $_POST [ 'go' ] ) ) {
$carb_colors = array ( 'blue' , 'blue dark' ) ; $clast_colors = array ( 'yellow' , 'orange' , 'tan' , 'gray dark' , 'gray light' , 'gray' ) ;
//////////////
//
// Time scale saved as time_scale.csv
//
//////////////
$q_time_scale = "SELECT interval_name, age_bottom, age_top, intervals.id FROM intervals
WHERE interval_name IN ('Whiterock', 'Chazyan', 'Blackriverian', 'Shermanian', 'Richmondian', 'Hirnantian', 'Rhuddanian', 'Aeronian', 'Telychian', 'Wenlock')
ORDER BY age_bottom" ;
$time_scale = mysqli_query ( $connect_macrostrat , $q_time_scale ) ;
$time_scale_file = "time_scale.csv" ;
$fh = fopen ( $time_scale_file , 'w' ) or
die ( "can't open file" ) ; //chmod($time_scale_file, 0666);
$file_row = "interval_name, age_bottom, age_top, id\n " ;
if ( $row [ 'interval_name' ] == 'Blackriverian' ) {
$file_row = "Blackriveran-Kirkfield," . $row [ 'age_bottom' ] . ",457.0000," . $row [ 'id' ] . "\n " ;
$int_name [ ] = 'Blackriveran-Kirkfield' ;
$int_bottom [ ] = $row [ 'age_bottom' ] ;
$int_top [ ] = 457.0000 ;
} else if ( $row [ 'interval_name' ] == 'Shermanian' ) {
$file_row = "Shermanian-Maysvillian," . $row [ 'age_bottom' ] . ",450.0000," . $row [ 'id' ] . "\n " ;
$int_name [ ] = 'Shermanian-Maysvillian' ;
$int_bottom [ ] = $row [ 'age_bottom' ] ;
$int_top [ ] = 450.0000 ;
} else {
$file_row = $row [ 'interval_name' ] . "," . $row [ 'age_bottom' ] . "," . $row [ 'age_top' ] . "," . $row [ 'id' ] . "\n " ;
$int_name [ ] = $row [ 'interval_name' ] ;
$int_bottom [ ] = $row [ 'age_bottom' ] ;
$int_top [ ] = $row [ 'age_top' ] ;
}
$int_id [ ] = $row [ 'id' ] ;
}
echo 'File <a href="' . $time_scale_file . '">' . $time_scale_file . '</a> saved<BR>' ;
$n_int = count ( $int_name ) ;
$base_ordovician = 488.3 ;
$study_max = max ( $int_bottom ) ; $study_min = min ( $int_top ) ;
//////////////
//
// Column data saved as columns.csv
//
//////////////
$cols_file = "columns.csv" ;
$fh = fopen ( $cols_file , 'w' ) or
die ( "can't open file" ) ; $file_row = "col_id, lat, lng, sheet, col, col_area, project_id\n " ;
$q = "SELECT cols.id, lat, lng, project_id, col_group, col, col_area FROM cols
INNER JOIN col_groups ON col_groups.id=col_group_id
INNER JOIN projects ON projects.id=project_id
WHERE project = 'North America' AND col_group != 'Mexico' AND cols.id NOT IN (34, 111, 139, 218, 586, 587) AND status_code = 'active'" ; //echo $q."<br>";
//(456,443,633,499)
$file_row = $row [ 'id' ] . "," . $row [ 'lat' ] . "," . $row [ 'lng' ] . "," . $row [ 'col_group' ] . "," . $row [ 'col' ] . "," . $row [ 'col_area' ] . "," . $row [ 'project_id' ] . "\n " ;
$my_cols [ ] = $row [ 'id' ] ;
}
echo 'File <a href="' . $cols_file . '">' . $cols_file . '</a> saved<BR>' ;
// get column polygons
$poly_file = "column_polygons.csv" ;
$fh = fopen ( $poly_file , 'w' ) or
die ( "can't open file" ) ; $file_row = "col_id, lat, lng\n " ;
$q = "SELECT col_id, AsText(col_area) coords FROM col_areas
WHERE col_id IN (" . implode ( "," , $my_cols ) . ")" ;
$my_coord = ltrim ( $row [ 'coords' ] , 'POLYGON((' ) ; $my_coord = rtrim ( $my_coord , '))' ) ; $my_coord = explode ( "," , $my_coord ) ;
for ( $i = 0 ; $i < count ( $my_coord ) ; ++ $i ) { $temp_coord = explode ( " " , $my_coord [ $i ] ) ; $file_row = $row [ 'col_id' ] . "," . $temp_coord [ 0 ] . "," . $temp_coord [ 1 ] . "\n " ;
}
}
echo 'File <a href="' . $poly_file . '">' . $poly_file . '</a> saved<BR>' ;
// get obselete columns to exclude
$obsolete_cols = array ( ) ; $q = "SELECT cols.id FROM cols
INNER JOIN col_groups ON col_groups.id=col_group_id
INNER JOIN projects ON projects.id=project_id
WHERE project = 'North America' AND status_code = 'obsolete'" ; //echo $q."<br>";
$obsolete_cols [ ] = $row [ 'id' ] ;
}
//////////////
//
// get packages
//
//////////////
$counter = 0 ;
$temp_pkg = split_packages( 'marine' ) ;
// set package crossers
$pkg_file = "ordovician_packages.csv" ;
$fh = fopen ( $pkg_file , 'w' ) or
die ( "can't open file" ) ; $file_row = "package_id, age_bottom, age_top, col_id\n " ;
for ( $i = 0 ; $i < count ( $temp_pkg ) ; ++ $i ) { $q = "SELECT col_id, max(b.age_bottom) bottom, min(t.age_top) top, count(distinct units.id) n_unit, FO_h FROM units
INNER JOIN intervals b ON b.id=FO
INNER JOIN intervals t ON t.id=LO
WHERE units.id IN ($temp_pkg [$i ])" ;
if ( in_array ( $row [ 'col_id' ] , $my_cols ) === TRUE && $row [ 'bottom' ] > $study_min && $row [ 'top' ] < $study_max ) { $my_pkg [ $counter ] = $temp_pkg [ $i ] ;
$my_pkg_fo [ $counter ] = $row [ 'bottom' ] ;
$my_pkg_lo [ $counter ] = $row [ 'top' ] ;
$my_pkg_n_units [ $counter ] = $row [ 'n_unit' ] ;
$my_pkg_col_id [ $counter ] = $row [ 'col_id' ] ;
$temp_units = explode ( "," , $temp_pkg [ $i ] ) ; for ( $j = 0 ; $j < count ( $temp_units ) ; ++ $j ) $unit_packages [ $temp_units [ $j ] ] = $counter ; // unit_id is key, package number is value
// get fo_h and lo_h for packages
$q = "SELECT units.id, FO_h, (b.age_bottom-b.age_top)/2 half_duration, b.age_bottom FROM units
INNER JOIN intervals b ON b.id=FO
WHERE units.id IN ($temp_pkg [$i ])
ORDER BY b.age_bottom DESC, FO_h
LIMIT 1" ;
$my_temp_fo = $fo_row [ 'FO_h' ] ;
$q = "SELECT units.id, LO_h, (t.age_bottom-t.age_top)/2 half_duration, t.age_top FROM units
INNER JOIN intervals t ON t.id=LO
WHERE units.id IN ($temp_pkg [$i ])
ORDER BY t.age_top, FIELD(LO_h,0,6,5,4,3,2,1)
LIMIT 1" ; //echo $q."<br>";
$my_temp_lo = $lo_row [ 'LO_h' ] ;
if ( $my_temp_fo == 0 ) $my_pkg_fo_h [ $counter ] = $fo_row [ 'age_bottom' ] ;
else $my_pkg_fo_h [ $counter ] = $fo_row [ 'age_bottom' ] - $fo_row [ 'half_duration' ] ;
if ( $my_temp_lo == 0 ) $my_pkg_lo_h [ $counter ] = $lo_row [ 'age_top' ] ;
else $my_pkg_lo_h [ $counter ] = $lo_row [ 'age_top' ] + $lo_row [ 'half_duration' ] ;
$file_row = $counter . "," . $fo_row [ 'age_bottom' ] . "," . $lo_row [ 'age_top' ] . "," . $row [ 'col_id' ] . "\n " ;
// $file_row=$counter.",".$my_pkg_fo_h[$counter].",".$my_pkg_lo_h[$counter]."\n";
++ $counter ;
}
// get packages for testing gaps
if ( in_array ( $row [ 'col_id' ] , $my_cols ) === TRUE ) { // get fo_h and lo_h for packages
$q = "SELECT units.id, FO_h, (b.age_bottom-b.age_top)/2 half_duration, b.age_bottom FROM units
INNER JOIN intervals b ON b.id=FO
INNER JOIN intervals t ON t.id=LO
WHERE units.id IN ($temp_pkg [$i ])
ORDER BY b.age_bottom DESC, FO_h, t.age_top DESC, field(LO_h, 1,2,3,4,5,6,0)
LIMIT 1" ;
if ( $fo_row [ 'FO_h' ] == 0 ) $my_gap_fo_h [ ] = $fo_row [ 'age_bottom' ] ;
else $my_gap_fo_h [ ] = $fo_row [ 'age_bottom' ] - $fo_row [ 'half_duration' ] ;
if ( $fo_row [ 'age_bottom' ] != $row [ 'bottom' ] ) echo "bad base calc<br>" ;
$my_gap_pkg [ ] = $temp_pkg [ $i ] ;
$my_gap_fo [ ] = $row [ 'bottom' ] ;
$my_gap_col_id [ ] = $row [ 'col_id' ] ;
}
}
$all_units_array = explode ( "," , $all_units ) ; $total_units = implode ( "," , $my_gap_pkg ) ; unset ( $temp_units , $temp_pkg , $counter ) ; echo "There are " . ( count ( explode ( "," , $total_units ) ) ) . " units.<br><br>" ; echo 'File <a href="' . $pkg_file . '">' . $pkg_file . '</a> saved<BR>' ;
/*
// calculate package crossers
$crosser_file = 'package_crossers.csv';
$fh = fopen($crosser_file,'w');
chmod($crosser_file, 0666);
fclose($fh);
$file_name_r = 'temp.r';
$fh = fopen($file_name_r, 'w') or die("can't open file");
chmod($file_name_r, 0666);
$r_script = "
source('myFunctions.r')
time.scale <- read.csv(file='$time_scale_file', header=TRUE)
packages <- read.csv(file='$pkg_file', header=TRUE)
cross.temp <- crossers(packages[,2:3], time.scale[,2:3])
write.csv(cbind(time.scale[,c(4,1:3)],cross.temp), file='$crosser_file', quote=FALSE, row.names=FALSE)
";
fwrite($fh, $r_script);
fclose($fh);
$cmd = "echo 'rscript <- \"$file_name_r\"; source(rscript)' | " . "/usr/bin/R --slave 2>&1";
exec($cmd, $r_ran);
if(count($r_ran)>0) {
echo "R (Package Crossers): ";
print_r($r_ran); echo "<br>";
}
echo 'File <a href="'.$crosser_file.'">'.$crosser_file.'</a> saved<BR>';
//////////////
//
// calculate environmental gaps for every unit
//
//////////////
$env_gap = array();
$env_unit_top = array();
$all_unit_array = explode(",",$all_units);
for($i=0; $i<count($all_unit_array); ++$i) {
// get information for focal unit
$q = "SELECT units.id, color, col_id, t.age_bottom top_bottom, t.age_top, LO_h, LO, FO_h, b.age_bottom FROM units
INNER JOIN intervals b ON b.id=FO
INNER JOIN intervals t ON t.id=LO
WHERE units.id=".$all_unit_array[$i];
$result = mysqli_query($connect_macrostrat, $q);
$focal_unit = mysqli_fetch_assoc($result);
mysqli_free_result($result);
if($focal_unit['LO_h'] == 0) {
$gap_bottom = $focal_unit['age_top'];
} else {
$gap_bottom = $focal_unit['age_top'] + ($focal_unit['top_bottom']-$focal_unit['age_top'])/2;
}
// get information on next youngest unit with same color
$q = "SELECT units.id, b.age_bottom, b.age_top bottom_top, FO_h, FO, color, t.age_top, LO_h FROM units
INNER JOIN intervals b ON b.id=FO
INNER JOIN intervals t ON t.id=LO
WHERE col_id=".$focal_unit['col_id']." AND units.id IN (".$total_units.") AND units.id != ".$focal_unit['id']."
AND ((FO_h!=0 AND b.age_bottom-(b.age_bottom-b.age_top)/2 <=".$gap_bottom.") OR (FO_h=0 AND b.age_bottom<=".$gap_bottom."))
AND color='".$focal_unit['color']."'
ORDER BY b.age_bottom DESC, FO_h, t.age_top DESC, field(LO_h, 1,2,3,4,5,6,0)
LIMIT 1"; //echo $q."<br>";
$result = mysqli_query($connect_macrostrat, $q);
if(mysqli_num_rows($result)==1) {
$test_unit = mysqli_fetch_assoc($result);
if($test_unit['FO_h'] == 0) {
$gap_top = $test_unit['age_bottom'];
} else {
$gap_top = $test_unit['age_bottom'] - ($test_unit['age_bottom']-$test_unit['bottom_top'])/2;
}
} else {
$gap_top = 0;
}
mysqli_free_result($result);
if(round($gap_bottom,5)==round($gap_top,5)) {
$env_gap[$all_unit_array[$i]]=0;
} else {
$env_gap[$all_unit_array[$i]] = log($gap_bottom-$gap_top);
}
if($gap_bottom<$gap_top) {
echo $focal_unit['id']." (".$test_unit['id']."): ".$gap_bottom." - ".$gap_top." = ".$env_gap[$all_unit_array[$i]]."<br>";
}
$env_unit_top[$all_unit_array[$i]] = $gap_bottom;
}
// echo "environmental gap:<br>";print_r($env_gap); echo "<br><br>";
//////////////
//
// get duration of gaps above packages
//
//////////////
for($i=0; $i<count($my_pkg); ++$i) {
$temp_max=0;
$temp_fo=0;
for($j=0; $j<count($my_gap_pkg); ++$j) {
if($my_gap_pkg[$j]!=$my_pkg[$i] && $my_pkg_col_id[$i]==$my_gap_col_id[$j] && $my_pkg_lo[$i] >= $my_gap_fo[$j] && $my_gap_fo[$j]>$temp_max) {
$temp_max = $my_gap_fo[$j];
}
if($my_gap_pkg[$j]!=$my_pkg[$i] && $my_pkg_col_id[$i]==$my_gap_col_id[$j] && $my_pkg_lo_h[$i] >= $my_gap_fo_h[$j] && $my_gap_fo_h[$j]>$temp_fo) {
$temp_fo = $my_gap_fo_h[$j];
}
}
if($my_pkg_lo[$i] != $temp_max) {
$my_pkg_gap[$i] = log($my_pkg_lo[$i] - $temp_max);
} else {
$my_pkg_gap[$i] = 0;
}
if(round($my_pkg_lo_h[$i],5) != round($temp_fo,5)) {
$my_pkg_gap2[$i] = log($my_pkg_lo_h[$i] - $temp_fo);
} else {
$my_pkg_gap2[$i] = 0;
}
}
*/
//////////////
//
// get matched ordovician genera and references
//
//////////////
// get all appropriate taxa
$my_occurrences = array ( ) ;
$q = "SELECT occurrences_temp2.taxon_no, genus_name, class, taxon_order, family, min(ta.top_age) pbdb_min,
occurrences_temp2.taxon_environment, occurrences_temp2.locomotion, occurrences_temp2.life_habit, occurrences_temp2.diet1, occurrences_temp2.diet2
FROM occurrences_temp2
INNER JOIN intervals b ON b.id=occurrences_temp2.FO
INNER JOIN intervals t ON t.id=occurrences_temp2.LO
INNER JOIN pbdb.interval_lookup ba ON ba.interval_no=occurrences_temp2.max_interval_no
INNER JOIN pbdb.interval_lookup ta ON ta.interval_no=occurrences_temp2.min_interval_no
LEFT OUTER JOIN pbdb.ecotaph ON ecotaph.taxon_no=occurrences_temp2.taxon_no
LEFT OUTER JOIN pbdb.authorities ON authorities.taxon_no=occurrences_temp2.taxon_no
WHERE occurrences_temp2.unit_id > 0 AND occurrences_temp2.unit_id IN (" . $all_units . ") AND (occurrences_temp2.extant = 'no' OR occurrences_temp2.extant IS NULL)
AND occurrences_temp2.col_id NOT IN (" . implode ( "," , $obsolete_cols ) . ") AND ((b.age_bottom > " . $study_min . " AND t.age_top < " . $study_max . ") OR ((b.age_bottom IS NULL AND t.age_top IS NULL) AND (ba.base_age > " . $study_min . " AND ta.top_age < " . $study_max . ")))
AND (occurrences_temp2.release_date <= now() OR occurrences_temp2.release_date IS NULL)
AND (form_taxon = 'no' OR form_taxon IS NULL) AND (preservation != 'trace' OR preservation IS NULL)
GROUP BY occurrences_temp2.taxon_no" ; //echo $q."<br><br>";
$my_genera [ ] = $row ;
$this_genus [ ] = $row [ 'taxon_no' ] ;
$my_genus_age [ $row [ 'taxon_no' ] ] [ 'pbdb_min' ] = $row [ 'pbdb_min' ] ;
}
// get global and NoAm ranges of taxa - even outside study interval
$q = "SELECT occurrence_no, taxon_no, ba.base_age, ta.top_age, FO_h, LO_h, unit_id,
b.age_bottom-((b.age_bottom-b.age_top)/2*LEAST(1,FO_h)) bottom, t.age_bottom+((t.age_bottom-t.age_top)/2*LEAST(1,LO_h)) top,
unit_id, col_id, occurrences_temp2.collection_no,
original_taxon_no, original_taxon_rank, paleolat, paleolng
FROM occurrences_temp2
INNER JOIN pbdb.interval_lookup ba ON ba.interval_no=occurrences_temp2.max_interval_no
INNER JOIN pbdb.interval_lookup ta ON ta.interval_no=occurrences_temp2.min_interval_no
LEFT OUTER JOIN intervals b ON b.id=FO
LEFT OUTER JOIN intervals t ON t.id=LO
WHERE taxon_no IN (" . implode ( "," , $this_genus ) . ") AND (occurrences_temp2.unit_id=0 OR occurrences_temp2.unit_id IN (" . $all_units . "))
AND (occurrences_temp2.col_id IS NULL OR occurrences_temp2.col_id NOT IN (" . implode ( "," , $obsolete_cols ) . "))" ; //echo $q."<br><br>"; $counter = 0 ;
$int_occurrences = array ( ) ; if ( $row [ 'unit_id' ] == 0 || in_array ( $row [ 'unit_id' ] , $all_units_array ) === FALSE ) { // not matched to north america $occurrence_bottom = $row [ 'base_age' ] ;
$occurrence_top = $row [ 'top_age' ] ;
} else {
if ( $row [ 'base_age' ] > $row [ 'top' ] && $row [ 'top_age' ] < $row [ 'bottom' ] ) { // pbdb and unit ages overlap: use youngest bottom and oldest top
$occurrence_bottom = min ( $row [ 'base_age' ] , $row [ 'bottom' ] ) ; $occurrence_top = max ( $row [ 'top_age' ] , $row [ 'top' ] ) ; } else { // pbdb and unit ages DO NOT overlap: use macrostrat
$occurrence_bottom = $row [ 'bottom' ] ;
$occurrence_top = $row [ 'top' ] ;
}
}
$my_occurrences [ ] = array ( "occurrence_no" => $row [ 'occurrence_no' ] ,
"taxon_no" => $row [ 'taxon_no' ] ,
"bottom" => $occurrence_bottom ,
"top" => $occurrence_top ,
"unit_id" => $row [ 'unit_id' ] ,
"col_id" => $row [ 'col_id' ] ,
"collection_no" => $row [ 'collection_no' ] ,
"original_taxon_no" => $row [ 'original_taxon_no' ] ,
"original_taxon_rank" => $row [ 'original_taxon_rank' ] ,
"paleolat" => $row [ 'paleolat' ] ,
"paleolng" => $row [ 'paleolng' ]
) ;
// get occurrence interval combinations
for ( $i = 0 ; $i < $n_int ; ++ $i ) {
if ( $occurrence_bottom > $int_top [ $i ] && $occurrence_top < $int_bottom [ $i ] ) $int_occurrences [ $i ] [ ] = $counter ;
if ( $occurrence_bottom > $int_top [ $i ] && $occurrence_top < $study_max && is_numeric ( $row [ 'paleolat' ] ) ) $int_paleolat [ $i ] [ $row [ 'taxon_no' ] ] [ ] = $row [ 'paleolat' ] ; }
++ $counter ;
if ( isset ( $my_genus_age [ $row [ 'taxon_no' ] ] [ 'global_max' ] ) === FALSE ) $my_genus_age [ $row [ 'taxon_no' ] ] [ 'global_max' ] = $occurrence_bottom ; else if ( $my_genus_age [ $row [ 'taxon_no' ] ] [ 'global_max' ] < $row [ 'base_age' ] ) $my_genus_age [ $row [ 'taxon_no' ] ] [ 'global_max' ] = $occurrence_bottom ;
if ( isset ( $my_genus_age [ $row [ 'taxon_no' ] ] [ 'global_min' ] ) === FALSE ) $my_genus_age [ $row [ 'taxon_no' ] ] [ 'global_min' ] = $occurrence_top ; else if ( $my_genus_age [ $row [ 'taxon_no' ] ] [ 'global_min' ] > $row [ 'top_age' ] ) $my_genus_age [ $row [ 'taxon_no' ] ] [ 'global_min' ] = $occurrence_top ;
if ( $row [ 'unit_id' ] > 0 && in_array ( $row [ 'unit_id' ] , $all_units_array ) && ( ( $row [ 'top' ] < 443.7 && $my_genus_age [ $row [ 'taxon_no' ] ] [ 'pbdb_min' ] < 443.7 ) || $row [ 'top' ] >= 443.7 ) ) { if ( isset ( $my_genus_age [ $row [ 'taxon_no' ] ] [ 'noam_max' ] ) === FALSE ) $my_genus_age [ $row [ 'taxon_no' ] ] [ 'noam_max' ] = $occurrence_bottom ; else if ( $my_genus_age [ $row [ 'taxon_no' ] ] [ 'noam_max' ] < $row [ 'base_age' ] ) $my_genus_age [ $row [ 'taxon_no' ] ] [ 'noam_max' ] = $occurrence_bottom ;
if ( isset ( $my_genus_age [ $row [ 'taxon_no' ] ] [ 'noam_min' ] ) === FALSE ) $my_genus_age [ $row [ 'taxon_no' ] ] [ 'noam_min' ] = $occurrence_top ; else if ( $my_genus_age [ $row [ 'taxon_no' ] ] [ 'noam_min' ] > $row [ 'top_age' ] ) $my_genus_age [ $row [ 'taxon_no' ] ] [ 'noam_min' ] = $occurrence_top ;
}
}
// $pbdb_file = "ordovician_genera.csv";
$pbdb_file = "ordovician_genera_culled.csv" ;
$fh = fopen ( $pbdb_file , 'w' ) or
die ( "can't open file" ) ; $file_row = "interval_id, interval_name, age_bottom, age_top, taxon_no, genus, class, order, family, life_habit, locomotion, taxon_environment, diet1, diet2, n_species_NoAm, n_species_global, n_collections_NoAm, n_occur_NoAm, global_endemic_to_interval, NoAm_FAD, NoAm_LAD, global_FAD, global_LAD, max_N_paleolat_during_prior, max_S_paleolat_during_prior, n_matched_units_greater_n_45, n_matched_units_greater_s_45, max_great_circle_NoAm, max_great_circle_Global, n_packages_occupied, n_packages_total, n_units_occupied, n_units_total,n_carb_units, n_carb_units_occupied, n_siliciclastic_units, n_siliciclastic_units_occupied, n_truncating_packages_total, n_truncating_packages_occupied, n_env_truncation, n_env_truncation_double, n_units_entirely_within_interval, min_gap, max_gap, mean_gap, median_gap, min_env_gap, max_env_gap, mean_env_gap, median_env_gap, n_env_gap, n_columns_occupied, n_columns_total, n_trunc_columns_occupied\n " ;
$my_collections = array ( ) ; for ( $i = 0 ; $i < 1 ; ++ $i ) {
// for($i=0; $i<$n_int; ++$i) {
// get total units and packages
$q = "SELECT units.id, color, col_id FROM units
INNER JOIN intervals b ON b.id=FO
INNER JOIN intervals t ON t.id=LO
WHERE units.id IN (" . $all_units . ") AND b.age_bottom>$int_top [$i ] AND t.age_top<$int_bottom [$i ]" ;
$my_packages [ ] = $unit_packages [ $row [ 'id' ] ] ;
if ( in_array ( $row [ 'color' ] , $carb_colors ) ) $my_carb [ ] = $row [ 'id' ] ; if ( in_array ( $row [ 'color' ] , $clast_colors ) ) $my_clast [ ] = $row [ 'id' ] ; $my_columns [ ] = $row [ 'col_id' ] ;
}
unset ( $my_packages , $my_columns ) ;
// loop through each package and count truncations
$truncating_packages = array ( ) ; $spanning_packages = array ( ) ; for ( $k = 0 ; $k < count ( $my_pkg ) ; ++ $k ) { // the packages that truncate in this interval
if ( $my_pkg_lo [ $k ] < $int_bottom [ $i ] && $my_pkg_lo [ $k ] >= $int_top [ $i ] ) {
$truncating_packages [ ] = $k ;
// non-truncating packages
} else if ( $my_pkg_lo [ $k ] < $int_bottom [ $i ] && $my_pkg_fo [ $k ] > $int_top [ $i ] ) {
$spanning_packages [ ] = $k ;
}
}
// loop through each occurrence in this interval and get those that occur in this interval
$interval_genus = array ( ) ; for ( $k = 0 ; $k < count ( $int_occurrences [ $i ] ) ; ++ $k ) { $interval_genus [ $my_occurrences [ $k ] [ 'taxon_no' ] ] [ ] = $my_occurrences [ $k ] ;
}
// for($j=0; $j < 100; ++$j) {
for ( $j = 0 ; $j < count ( $interval_genus ) ; ++ $j ) {
$noam_occurrences = array ( ) ; $noam_collections = array ( ) ; $noam_packages = array ( ) ; $noam_paleolat = array ( ) ; $noam_paleolng = array ( ) ; $matched_unit_n_45 = array ( ) ; $matched_unit_s_45 = array ( ) ; $unit_paleolat = array ( ) ; $unit_paleolng = array ( ) ;
$global_occurrences = array ( ) ; $global_collections = array ( ) ; $global_species = array ( ) ; $global_paleolat = array ( ) ; $global_paleolng = array ( ) ;
if ( $my_genus_age [ $this_genus [ $j ] ] [ 'global_max' ] <= $int_bottom [ $i ] && $my_genus_age [ $this_genus [ $j ] ] [ 'global_min' ] > $int_top [ $i ] ) $global_endemic_to_interval = 1 ;
else $global_endemic_to_interval = 0 ;
for ( $k = 0 ; $k < count ( $interval_genus [ $this_genus [ $j ] ] ) ; ++ $k ) { $row = $interval_genus [ $this_genus [ $j ] ] [ $k ] ;
if ( $row [ 'unit_id' ] == 0 || in_array ( $row [ 'unit_id' ] , $all_units_array ) === FALSE || ( $row [ 'unit_id' ] > 0 && ( $my_genus_age [ $row [ 'taxon_no' ] ] [ 'pbdb_min' ] < 443.7 && $row [ 'top' ] < 443.7 ) || $row [ 'top' ] >= 443.7 ) ) { $global_occurrences [ ] = $row [ 'occurrence_no' ] ;
$global_collections [ ] = $row [ 'collection_no' ] ;
$global_paleolat [ ] = $row [ 'paleolat' ] ;
$global_paleolng [ ] = $row [ 'paleolng' ] ;
}
$my_collections [ ] = $row [ 'collection_no' ] ;
if ( $row [ 'original_taxon_rank' ] == 'species' ) $global_species [ ] = $row [ 'original_taxon_no' ] ;
if ( $row [ 'unit_id' ] > 0 && in_array ( $row [ 'unit_id' ] , $all_units_array ) ) { $noam_occurrences [ ] = $row [ 'occurrence_no' ] ;
$noam_collections [ ] = $row [ 'collection_no' ] ;
$noam_units [ ] = $row [ 'unit_id' ] ;
$noam_columns [ ] = $row [ 'col_id' ] ;
if ( $row [ 'original_taxon_rank' ] == 'species' ) $noam_species [ ] = $row [ 'original_taxon_no' ] ;
$noam_paleolat [ ] = $row [ 'paleolat' ] ;
$noam_paleolng [ ] = $row [ 'paleolng' ] ;
if ( $row [ 'paleolat' ] >= 45 ) $matched_unit_n_45 [ ] = $row [ 'unit_id' ] ;
if ( $row [ 'paleolat' ] <= - 45 ) $matched_unit_s_45 [ ] = $row [ 'unit_id' ] ;
$unit_paleolat [ $row [ 'unit_id' ] ] [ ] = $row [ 'paleolat' ] ; //echo $row['paleolat']."<br>";
$unit_paleolng [ $row [ 'unit_id' ] ] [ ] = $row [ 'paleolng' ] ;
}
$noam_packages [ ] = $unit_packages [ $row [ 'unit_id' ] ] ;
}
}
}
$n_units = count ( $noam_units ) ;
if ( $n_units > 0 ) {
// print_r($noam_columns); echo " - $n_cols<br><br>";
else $n_carb_units_occupied = 0 ;
$n_siliciclastic_units_occupied = 0 ;
$max_paleolat_N = 'NA' ;
max_paleolat_S = 'NA' ;
for ( $k = 0 ; $k < count ( $int_paleolat [ $i ] ) ; ++ $k ) { if ( $temp_taxon_no [ $k ] == $row [ 'taxon_no' ] ) {
$max_paleolat_N = max ( $int_paleolat [ $i ] [ $row [ 'taxon_no' ] ] ) ; $max_paleolat_S = min ( $int_paleolat [ $i ] [ $row [ 'taxon_no' ] ] ) ; }
}
// get matched great circle distance
// set up file for sending to R for great circle analysis
$circle_file = "noam_great_circle.csv" ;
$fh2 = fopen ( $circle_file , 'w' ) or
die ( "can't open file" ) ; chmod ( $circle_file , 0666 ) ; $file_row = "plat, plng, unit_id\n " ;
for ( $k = 0 ; $k < count ( $unit_paleolat ) ; ++ $k ) { if ( isset ( $unit_paleolat [ $noam_units [ $k ] ] ) && isset ( $unit_paleolng [ $noam_units [ $k ] ] ) ) { $unit_mean_lat = array_sum ( $unit_paleolat [ $noam_units [ $k ] ] ) / count ( $unit_paleolat [ $noam_units [ $k ] ] ) ; $unit_mean_lng = array_sum ( $unit_paleolng [ $noam_units [ $k ] ] ) / count ( $unit_paleolng [ $noam_units [ $k ] ] ) ; if ( is_null ( $unit_mean_lat ) === FALSE && is_null ( $unit_mean_lng ) === FALSE ) { $file_row = "$unit_mean_lat ,$unit_mean_lng ,$noam_units [$k ]\n " ;
}
} else {
echo "paleo coords not properly set<br>" ;
}
}
if ( $n_units > 1 ) {
$file_name_r = 'temp.r' ;
$fh3 = fopen ( $file_name_r , 'w' ) or
die ( "can't open file" ) ; chmod ( $file_name_r , 0666 ) ; $r_script = "
source('myFunctions.r')
coords <- read.csv(file='$circle_file ', header=TRUE)
if(nrow(unique(coords[,1:2]))>1) {
max.dist <- max(great.circle2(coords[,1:2]), na.rm=TRUE)
} else {
max.dist <- 'NA'
}
write.table(max.dist, file='temp_dist.csv', quote=FALSE, row.names=FALSE, col.names=FALSE, sep=',')
" ;
$cmd = "echo 'rscript <- \" $file_name_r \" ; source(rscript)' | " . "/usr/bin/R --slave 2>&1" ;
echo "R (Matched great circle): " ;
}
$handle = fopen ( "temp_dist.csv" , "r" ) ; while ( $row = fgetcsv ( $handle , 1000 , "," ) ) $max_dist_noam = $row [ 0 ] ; if ( $max_dist_noam == 'NA' ) {
$handle = fopen ( $circle_file , "r" ) ; echo $max_dist_noam . "<br>" ;
while ( $file_row = fgetcsv ( $handle , 1000 , "," ) ) { }
print_r ( $noam_collections ) ; echo "<br><br>" ; }
} else {
$max_dist_noam = 'NA' ;
}
// get global great circle distance
if ( count ( $global_paleolat ) > 1 && count ( $global_paleolng ) == count ( $global_paleolat ) ) { // set up file for sending to R for great circle analysis
$circle_file = "global_great_circle.csv" ;
$fh2 = fopen ( $circle_file , 'w' ) or
die ( "can't open file" ) ; chmod ( $circle_file , 0666 ) ; $file_row = "plat, plng\n " ;
for ( $k = 0 ; $k < count ( $global_paleolat ) ; ++ $k ) { $file_row = $global_paleolat [ $k ] . "," . $global_paleolng [ $k ] . "\n " ;
}
$file_name_r = 'temp.r' ;
$fh3 = fopen ( $file_name_r , 'w' ) or
die ( "can't open file" ) ; chmod ( $file_name_r , 0666 ) ; $r_script = "
source('myFunctions.r')
coords <- read.csv(file='$circle_file ', header=TRUE)
if(nrow(unique(coords))>1) {
max.dist <- max(great.circle2(coords), na.rm=TRUE)
} else {
max.dist <- 'NA'
}
write.table(max.dist, file='temp_dist.csv', quote=FALSE, row.names=FALSE, col.names=FALSE, sep=',')
" ;
$cmd = "echo 'rscript <- \" $file_name_r \" ; source(rscript)' | " . "/usr/bin/R --slave 2>&1" ;
echo "R (Global great circle): " ;
}
$handle = fopen ( "temp_dist.csv" , "r" ) ; while ( $row = fgetcsv ( $handle , 1000 , "," ) ) $max_dist_global = $row [ 0 ] ; } else {
$max_dist_global = 'NA' ;
}
// get stratigraphic gap duration
if ( $n_packages > 0 ) {
$n_trunc_packages_occupied = count ( $trunc_temp ) ; if ( $n_trunc_packages_occupied > 0 ) {
// get n truncating columns
$trunc_temp_columns = array ( ) ; for ( $k = 0 ; $k < $n_trunc_packages_occupied ; ++ $k ) {
$trunc_temp_columns [ ] = $my_pkg_col_id [ $trunc_temp [ $k ] ] ;
}
} else {
$n_trunc_columns_occupied = 0 ;
}
if ( $n_trunc_packages_occupied > 1 ) {
$trunc_packages_occupied = array_combine ( range ( 0 , ( $n_trunc_packages_occupied - 1 ) , 1 ) , $trunc_temp ) ; //print_r($trunc_temp); echo "<br>";
//print_r($trunc_packages_occupied); echo "<br>";
for ( $zz = 0 ; $zz < $n_trunc_packages_occupied ; ++ $zz ) {
$temp_gap [ ] = $my_pkg_gap2 [ $trunc_packages_occupied [ $zz ] ] ;
}
//print_r($temp_gap); echo "<br><br>";
$max_gap = max ( $temp_gap ) ; $min_gap = min ( $temp_gap ) ; $mean_gap = array_sum ( $temp_gap ) / $n_trunc_packages_occupied ;
$h = intval ( $n_trunc_packages_occupied / 2 ) ; if ( $n_trunc_packages_occupied % 2 == 0 ) {
$median_gap = ( $temp_gap [ $h ] + $temp_gap [ $h - 1 ] ) / 2 ;
} else {
$median_gap = $temp_gap [ $h ] ;
}
} else if ( $n_trunc_packages_occupied == 1 ) {
$trunc_packages_occupied = array_combine ( range ( 0 , ( $n_trunc_packages_occupied - 1 ) , 1 ) , $trunc_temp ) ; // returns package keys $max_gap = $my_pkg_gap2 [ $trunc_packages_occupied [ 0 ] ] ;
$min_gap = $max_gap ;
$mean_gap = $max_gap ;
$median_gap = $max_gap ;
} else {
$max_gap = NULL ;
$min_gap = NULL ;
$mean_gap = NULL ;
$median_gap = NULL ;
}
// get environmental truncation
for ( $k = 0 ; $k < $n_packages ; ++ $k ) {
// get unit of oldest occurrence in interval
$q = "SELECT units.id, b.age_bottom, t.age_top, color FROM occurrences_temp2
INNER JOIN units ON units.id=occurrences_temp2.unit_id
INNER JOIN intervals b ON b.id=units.FO
INNER JOIN intervals t ON t.id=units.LO
WHERE taxon_no=" . $this_genus [ $j ] . " AND (occurrences_temp2.release_date <= now() OR occurrences_temp2.release_date IS NULL)
AND units.id IN (" . $my_pkg [ $pkg_occupied [ $k ] ] . ")
AND b.age_bottom > " . $int_top [ $i ] . " AND t.age_top < " . $int_bottom [ $i ] . "
GROUP BY units.id
ORDER BY b.age_bottom DESC, units.FO_h, t.age_top DESC, field(units.LO_h, 1,2,3,4,5,0)
LIMIT 1" ; //echo $q."<br>";
$occupied_unit = $max_unit [ 'id' ] ;
$occupied_bottom = $max_unit [ 'age_bottom' ] ;
$occupied_top = $max_unit [ 'age_top' ] ;
$occupied_color = $max_unit [ 'color' ] ;
$next_unit_temp = NULL ;
// get oldest unit in overlying intervals - may span into focal interval
if ( $i == 0 ) {
$previous_top = 418.7 ;
$previous_bottom = $study_max ;
} else {
$previous_top = $int_top [ $i - 1 ] ;
$previous_bottom = $int_bottom [ $i - 1 ] ;
}
$q = "SELECT units.id, color, LO_h, FO_h, b.age_bottom, t.age_top FROM units
INNER JOIN intervals b ON b.id=FO
INNER JOIN intervals t ON t.id=LO
WHERE units.id IN (" . $my_pkg [ $pkg_occupied [ $k ] ] . ") AND b.age_bottom>" . $previous_top . " AND t.age_top<" . $previous_bottom . "
ORDER BY b.age_bottom DESC, FO_h, t.age_top DESC, field(LO_h, 1,2,3,4,5,0)
LIMIT 1" ;
$next_unit_temp = $next_int_unit [ 'id' ] ;
if ( $next_int_unit [ 'color' ] != $occupied_color ) {
$n_env_temp [ ] = $pkg_occupied [ $k ] ;
// echo $occupied_unit.' '.$occupied_color.' - '.$next_int_unit['id'].' '.$next_int_unit['color']."<br>";
}
}
// loop through the units within the focal interval - may not span into overlying interval
if ( is_null ( $next_unit_temp ) ) $temp_exclude = $occupied_unit ; else $temp_exclude = $occupied_unit . "," . $next_unit_temp ;
$q = "SELECT units.id, color, LO_h, FO_h, b.age_bottom, t.age_top FROM units
INNER JOIN intervals b ON b.id=FO
INNER JOIN intervals t ON t.id=LO
WHERE units.id IN (" . $my_pkg [ $pkg_occupied [ $k ] ] . ") AND b.age_bottom > " . $int_top [ $i ] . " AND t.age_top >= " . $int_top [ $i ] . "
AND b.age_bottom<=" . $occupied_top . " AND units.id NOT IN (" . $temp_exclude . ")
ORDER BY b.age_bottom DESC, FO_h, t.age_top DESC, field(LO_h, 1,2,3,4,5,0)" ; //echo $q."<br>";
$temp_pkg_result = mysqli_query ( $connect_macrostrat , $q ) ; //if(mysqli_num_rows($temp_pkg_result)>2) echo $q."<br>"; if ( $pkg_row [ 'color' ] != $occupied_color && $pkg_row [ 'age_top' ] < $occupied_top ) {
// echo $occupied_unit.' '.$occupied_color.' - '.$pkg_row['id'].' '.$pkg_row['color']."<br>";
if ( $pkg_row [ 'age_top' ] >= $int_top [ $i ] ) { // unit is contained entirely within the interval
$n_env_temp [ ] = $pkg_occupied [ $k ] ; //echo $n_env_truncation."<br>";
} else if ( $pkg_row [ 'age_top' ] < $int_top [ $i ] && $pkg_row [ 'age_bottom' ] > $int_top [ $i ] ) { // units spans interval boundary
$n_env_temp [ ] = $pkg_occupied [ $k ] ; //echo $n_env_truncation."<br>";
}
}
if ( $pkg_row [ 'age_top' ] >= $int_top [ $i ] && $pkg_row [ 'age_bottom' ] <= $int_bottom [ $i ] ) $n_env_temp2 [ ] = $pkg_occupied [ $k ] ;
}
if ( $occupied_top >= $int_top [ $i ] && $occupied_bottom <= $int_bottom [ $i ] ) $n_env_temp2 [ ] = $pkg_occupied [ $k ] ;
}
}
}
$n_env_truncation2 = count ( $n_env_temp ) ; // if($n_env_truncation>0) {print_r($n_env_temp); echo "<br><br>";}
// tabulate environmental gap length
$env_gap_count = array ( ) ; if ( $n_units > 1 ) {
for ( $zzz = 0 ; $zzz < $n_units ; ++ $zzz ) {
if ( $env_unit_top [ $my_occupied_units [ $zzz ] ] >= $int_top [ $i ] && $env_unit_top [ $my_occupied_units [ $zzz ] ] < $int_bottom [ $i ] ) {
$env_gap_count [ ] = $env_gap [ $my_occupied_units [ $zzz ] ] ;
}
}
unset ( $my_occupied_units ) ; } else if ( $n_units == 1 ) {
if ( $env_unit_top [ $my_occupied_units [ 0 ] ] >= $int_top [ $i ] && $env_unit_top [ $my_occupied_units [ 0 ] ] < $int_bottom [ $i ] ) {
$env_gap_count [ ] = $env_gap [ $my_occupied_units [ 0 ] ] ;
}
unset ( $my_occupied_units ) ; }
// tabulate stats
$n_env_gap = count ( $env_gap_count ) ; if ( $n_env_gap > 1 ) {
$min_env_gap = min ( $env_gap_count ) ; $max_env_gap = max ( $env_gap_count ) ; $mean_env_gap = array_sum ( $env_gap_count ) / $n_env_gap ; if ( $n_env_gap % 2 == 0 ) {
$median_env_gap = ( $env_gap_count [ $h ] + $env_gap_count [ $h - 1 ] ) / 2 ;
} else {
$median_env_gap = $env_gap_count [ $h ] ;
}
} else if ( $n_env_gap == 1 ) {
$min_env_gap = $env_gap_count [ 0 ] ;
$max_env_gap = $env_gap_count [ 0 ] ;
$mean_env_gap = $env_gap_count [ 0 ] ;
$median_env_gap = $env_gap_count [ 0 ] ;
} else {
$min_env_gap = NULL ;
$max_env_gap = NULL ;
$mean_env_gap = NULL ;
$median_env_gap = NULL ;
}
$file_row = $int_id [ $i ] . "," . $int_name [ $i ] . "," . $int_bottom [ $i ] . "," . $int_top [ $i ] . "," .
$my_genera [ $j ] [ 'taxon_no' ] . "," . $my_genera [ $j ] [ 'genus_name' ] . "," . $my_genera [ $j ] [ 'class' ] . "," . $my_genera [ $j ] [ 'taxon_order' ] . "," . $my_genera [ $j ] [ 'family' ] . "," .
$my_genera [ $j ] [ 'life_habit' ] . "," . $my_genera [ $j ] [ 'locomotion' ] . "," . $my_genera [ $j ] [ 'taxon_environment' ] . "," . $my_genera [ $j ] [ 'diet1' ] . "," . $my_genera [ $j ] [ 'diet2' ] . "," .
$n_species . "," . $n_species_global . "," . $n_coll . "," . $n_occur . "," . $global_endemic_to_interval . "," .
$my_genus_age [ $this_genus [ $j ] ] [ 'noam_max' ] . "," . $my_genus_age [ $this_genus [ $j ] ] [ 'noam_min' ] . "," .
$my_genus_age [ $this_genus [ $j ] ] [ 'global_max' ] . "," . $my_genus_age [ $this_genus [ $j ] ] [ 'global_min' ] . "," .
$max_paleolat_N . "," . $max_paleolat_S . "," . $n_matched_units_greater_n_45 . "," . $n_matched_units_greater_s_45 . "," .
$max_dist_noam . "," . $max_dist_global . "," .
$n_packages . "," . $n_packages_total . "," . $n_units . "," . $n_units_total . "," .
$n_env_truncation . "," . $n_env_truncation2 . "," . $n_env_truncation3 . "," .
$min_gap . "," . $max_gap . "," . $mean_gap . "," . $median_gap . "," .
$min_env_gap . "," . $max_env_gap . "," . $mean_env_gap . "," . $median_env_gap . "," . $n_env_gap . "," .
$n_cols . "," . $n_columns_total . "," . $n_trunc_columns_occupied . "\n " ;
}
}
}
// get references and authorizers & enterers
$q = "SELECT occurrences_temp2.collection_no, collections.reference_no, collections.authorizer, collections.enterer, collections.modifier,
refs.author1init, refs.author1last, refs.author2init, refs.author2last, refs.otherauthors, refs.pubyr, refs.reftitle, refs.pubtitle,
refs.editors, refs.pubvol, refs.firstpage, refs.lastpage, refs.publication_type
FROM occurrences_temp2
INNER JOIN pbdb.collections ON occurrences_temp2.collection_no=collections.collection_no
INNER JOIN pbdb.refs ON refs.reference_no=collections.reference_no
WHERE collections.collection_no IN (" . $my_collections . ")
GROUP BY occurrences_temp2.collection_no
ORDER BY occurrences_temp2.collection_no" ; //echo $q."<br><br>";
if ( isset ( $data_credits [ $row [ 'authorizer' ] ] ) ) ++ $data_credits [ $row [ 'authorizer' ] ] [ 'auth' ] ; else $data_credits [ $row [ 'authorizer' ] ] = array ( 'auth' => 1 , 'enter' => 0 , 'modify' => 0 ) ;
if ( isset ( $data_credits [ $row [ 'enterer' ] ] ) ) ++ $data_credits [ $row [ 'enterer' ] ] [ 'enter' ] ; else $data_credits [ $row [ 'enterer' ] ] = array ( 'auth' => 0 , 'enter' => 1 , 'modify' => 0 ) ;
if ( isset ( $data_credits [ $row [ 'modifier' ] ] ) ) ++ $data_credits [ $row [ 'modifier' ] ] [ 'modify' ] ; else $data_credits [ $row [ 'modifier' ] ] = array ( 'auth' => 0 , 'enter' => 0 , 'modify' => 1 ) ;
if ( isset ( $ref_credits [ $row [ 'reference_no' ] ] ) ) { ++ $ref_credits [ $row [ 'reference_no' ] ] [ 'count' ] ;
} else {
$author_temp = $row [ 'author1last' ] . ", " . $row [ 'author1init' ] ;
if ( is_null ( $row [ 'otherauthors' ] ) === FALSE ) { $author_temp = $author_temp . ' ,' . $row [ 'author2init' ] . " " . $row [ 'author2last' ] . ", " . $row [ 'otherauthors' ] . "." ;
} else if ( is_null ( $row [ 'author2last' ] ) === FALSE ) { $author_temp = $author_temp . ' and ' . $row [ 'author2init' ] . " " . $row [ 'author2last' ] . "." ;
}
if ( $row [ 'publication_type' ] == 'journal article' || $row [ 'publication_type' ] == 'serial monograph' || $row [ 'publication_type' ] == 'abstract' ) {
$full_ref = $author_temp . " " . $row [ 'pubyr' ] . ". " . $row [ 'reftitle' ] . ". " . $row [ 'pubtitle' ] . " " . $row [ 'pubvol' ] . ":" . $row [ 'firstpage' ] . "-" . $row [ 'lastpage' ] ;
} else if ( $row [ 'publication_type' ] == 'guidebook' || $row [ 'publication_type' ] == 'book/book chapter' || $row [ 'publication_type' ] == 'Ph.D. thesis' || $row [ 'publication_type' ] == 'M.S. thesis' ) {
if ( is_null ( $row [ 'editors' ] ) ) $editor_temp = '' ; else $editor_temp = $row [ 'editors' ] . " (eds.) " ;
$full_ref = $author_temp . " " . $row [ 'pubyr' ] . ". " . $row [ 'reftitle' ] . ". In " . $editor_temp . ". " . $row [ 'pubtitle' ] . " " . $row [ 'firstpage' ] . "-" . $row [ 'lastpage' ] ;
} else {
if ( is_null ( $row [ 'reftitle' ] ) || $row [ 'reftitle' ] == '' ) $temp_pubtitle = '' ; else $temp_pubtitle = $row [ 'reftitle' ] . ". " ;
$full_ref = $author_temp . " " . $row [ 'pubyr' ] . ". " . $temp_pubtitle . " Unpublished data" ;
}
$ref_credits [ $row [ 'reference_no' ] ] = array ( 'count' => 1 , 'full' => $full_ref , 'type' => $row [ 'publication_type' ] ) ; }
}
// write text files
$credit_file = 'collection_credits.txt' ;
$fh = fopen ( $credit_file , 'w' ) ; chmod ( $credit_file , 0777 ) ; $file_row = "name\t authorized\t entered\t modified\n " ;
for ( $i = 0 ; $i < count ( $data_credits ) ; ++ $i ) { if ( is_null ( $my_people [ $i ] ) === FALSE && $my_people [ $i ] != '' ) { $file_row = $my_people [ $i ] . "\t " . $data_credits [ $my_people [ $i ] ] [ 'auth' ] . "\t " . $data_credits [ $my_people [ $i ] ] [ 'enter' ] . "\t " . $data_credits [ $my_people [ $i ] ] [ 'modify' ] . "\n " ;
}
}
echo 'File <a href="' . $credit_file . '">' . $credit_file . '</a> saved<BR>' ;
$ref_file = 'references.txt' ;
$fh = fopen ( $ref_file , 'w' ) ; $file_row = "reference_no\t citation\t n_collections\n " ;
for ( $i = 0 ; $i < count ( $ref_credits ) ; ++ $i ) { $file_row = $my_refs [ $i ] . "\t " . $ref_credits [ $my_refs [ $i ] ] [ 'full' ] . "\t " . $ref_credits [ $my_refs [ $i ] ] [ 'count' ] . "\n " ;
}
echo 'File <a href="' . $ref_file . '">' . $ref_file . '</a> saved<BR>' ;
$coll_file = 'collections.csv' ;
$fh = fopen ( $coll_file , 'w' ) ; echo 'File <a href="' . $coll_file . '">' . $coll_file . '</a> saved<BR>' ;
}
//////////////
//
// stuff at the end
//
//////////////
if ( isset ( $_POST [ 'submit' ] ) ) { $time_diff = $t1 - $t0 ;
if ( $time_diff / 60 < 1 ) {
$diff_seconds = round ( $time_diff , 3 ) ; echo "<br>This process took " . $diff_seconds . " seconds" ;
} else if ( $time_diff >= 1 & $time_diff < 3600 ) {
$diff_min = round ( $time_diff / 60 , 3 ) ; echo "<br>This process took " . $diff_min . " minutes" ;
} else {
$diff_hour = round ( $time_diff / 3600 , 3 ) ; echo "<br>This process took " . $diff_hour . " hours" ;
}
}
?>
<?php
require_once ( '../footer.html' ) ;
?>
PD9waHAKCSRwYWdlX3RpdGxlID0gJ1J1biBMT01FIHNlbGVjdGl2aXR5IGFuYWx5c2lzJzsKCXJlcXVpcmUoJy4uL2RpcmVjdG9yeWluZm8ucGhwJyk7CglpbmNsdWRlKCcuLi9jb25uZWN0LnBocCcpOwoJaW5jbHVkZSgnZnVuY3Rpb25zLnBocCcpOwoJcmVxdWlyZV9vbmNlKCcuLi9oZWFkZXIuaHRtbCcpOwo/PgoKPCEtLSBGb3JtIEZvciBFeGVjdXRpbmcgQ29kZSAtLT4KPGZvcm0gYWN0aW9uPSJpbmRleC5waHAiIG1ldGhvZD0icG9zdCIgbmFtZT0iZmlsZV9zZWxlY3QiPgoJPGZpZWxkc2V0PgoJCgk8dGFibGUgYWxpZ249ImxlZnQiIGNlbGxzcGFjaW5nPTE1PgoJCTx0cj48dGQgY29sc3Bhbj0iMiI+PGlucHV0IHR5cGU9ImNoZWNrYm94IiBjaGVja2VkIG5hbWU9ImdvIiB2YWx1ZT0ieWVzIj48U1RST05HPlJ1biBGdWxsIEFuYWx5c2lzPC9TVFJPTkc+PC90ZD48L3RyPgoJCTx0cj48dGQgY29sc3Bhbj0yPjxpbnB1dCB0eXBlPSJzdWJtaXQiIG5hbWU9InN1Ym1pdCIgdmFsdWU9IlN1Ym1pdCI+PC90ZD48L3RyPgoJPC90YWJsZT4KCTwvZmllbGRzZXQ+CjwvZm9ybT4KCjw/cGhwCgllcnJvcl9yZXBvcnRpbmcoRV9BTEwpOwkKCQoJaWYoaXNzZXQoJF9QT1NUWydnbyddKSkgeyAKCQkkdDAgPSBtaWNyb3RpbWUodHJ1ZSk7CgkKCQkkY2FyYl9jb2xvcnMgPSBhcnJheSgnYmx1ZScsJ2JsdWUgZGFyaycpOwoJCSRjbGFzdF9jb2xvcnMgPSBhcnJheSgneWVsbG93Jywnb3JhbmdlJywndGFuJywnZ3JheSBkYXJrJywnZ3JheSBsaWdodCcsJ2dyYXknKTsKCQkKCQkvLy8vLy8vLy8vLy8vLwoJCS8vCgkJLy8gVGltZSBzY2FsZSBzYXZlZCBhcyB0aW1lX3NjYWxlLmNzdgoJCS8vCgkJLy8vLy8vLy8vLy8vLy8KCQkkcV90aW1lX3NjYWxlID0gIlNFTEVDVCBpbnRlcnZhbF9uYW1lLCBhZ2VfYm90dG9tLCBhZ2VfdG9wLCBpbnRlcnZhbHMuaWQgRlJPTSBpbnRlcnZhbHMgCgkJV0hFUkUgaW50ZXJ2YWxfbmFtZSBJTiAoJ1doaXRlcm9jaycsICdDaGF6eWFuJywgJ0JsYWNrcml2ZXJpYW4nLCAnU2hlcm1hbmlhbicsICdSaWNobW9uZGlhbicsICdIaXJuYW50aWFuJywgJ1JodWRkYW5pYW4nLCAnQWVyb25pYW4nLCAnVGVseWNoaWFuJywgJ1dlbmxvY2snKQoJCU9SREVSIEJZIGFnZV9ib3R0b20iOwoJCSR0aW1lX3NjYWxlID0gbXlzcWxpX3F1ZXJ5KCRjb25uZWN0X21hY3Jvc3RyYXQsICRxX3RpbWVfc2NhbGUpOyAgICAgICAgIAoJCSRuX2JpbiA9IG15c3FsaV9udW1fcm93cygkdGltZV9zY2FsZSk7CgkJCgkJJHRpbWVfc2NhbGVfZmlsZSA9ICJ0aW1lX3NjYWxlLmNzdiI7CgkJJGZoID0gZm9wZW4oJHRpbWVfc2NhbGVfZmlsZSwgJ3cnKSBvciBkaWUoImNhbid0IG9wZW4gZmlsZSIpOwoJCS8vY2htb2QoJHRpbWVfc2NhbGVfZmlsZSwgMDY2Nik7CgkJJGZpbGVfcm93ID0gImludGVydmFsX25hbWUsIGFnZV9ib3R0b20sIGFnZV90b3AsIGlkXG4iOwoJCWZ3cml0ZSgkZmgsICRmaWxlX3Jvdyk7CgkJCgkJd2hpbGUoJHJvdyA9IG15c3FsaV9mZXRjaF9hc3NvYygkdGltZV9zY2FsZSkpIHsJCQkKCQkJaWYoJHJvd1snaW50ZXJ2YWxfbmFtZSddID09ICdCbGFja3JpdmVyaWFuJykgewoJCQkJJGZpbGVfcm93ID0gIkJsYWNrcml2ZXJhbi1LaXJrZmllbGQsIi4kcm93WydhZ2VfYm90dG9tJ10uIiw0NTcuMDAwMCwiLiRyb3dbJ2lkJ10uIlxuIjsKCQkJCSRpbnRfbmFtZVtdID0gJ0JsYWNrcml2ZXJhbi1LaXJrZmllbGQnOwoJCQkJJGludF9ib3R0b21bXSA9ICRyb3dbJ2FnZV9ib3R0b20nXTsKCQkJCSRpbnRfdG9wW10gPSA0NTcuMDAwMDsKCQkJfSBlbHNlIGlmKCRyb3dbJ2ludGVydmFsX25hbWUnXSA9PSAnU2hlcm1hbmlhbicpIHsKCQkJCSRmaWxlX3JvdyA9ICJTaGVybWFuaWFuLU1heXN2aWxsaWFuLCIuJHJvd1snYWdlX2JvdHRvbSddLiIsNDUwLjAwMDAsIi4kcm93WydpZCddLiJcbiI7CgkJCQkkaW50X25hbWVbXSA9ICdTaGVybWFuaWFuLU1heXN2aWxsaWFuJzsKCQkJCSRpbnRfYm90dG9tW10gPSAkcm93WydhZ2VfYm90dG9tJ107CgkJCQkkaW50X3RvcFtdID0gNDUwLjAwMDA7CgkJCX0gZWxzZSB7CgkJCQkkZmlsZV9yb3cgPSAkcm93WydpbnRlcnZhbF9uYW1lJ10uIiwiLiRyb3dbJ2FnZV9ib3R0b20nXS4iLCIuJHJvd1snYWdlX3RvcCddLiIsIi4kcm93WydpZCddLiJcbiI7CgkJCQkkaW50X25hbWVbXSA9ICRyb3dbJ2ludGVydmFsX25hbWUnXTsKCQkJCSRpbnRfYm90dG9tW10gPSAkcm93WydhZ2VfYm90dG9tJ107CgkJCQkkaW50X3RvcFtdID0gJHJvd1snYWdlX3RvcCddOwoJCQl9CgkJCSRpbnRfaWRbXSA9ICRyb3dbJ2lkJ107CgkJCWZ3cml0ZSgkZmgsICRmaWxlX3Jvdyk7CgkJfQoJCWZjbG9zZSgkZmgpOwoJCWVjaG8gJ0ZpbGUgPGEgaHJlZj0iJy4kdGltZV9zY2FsZV9maWxlLiciPicuJHRpbWVfc2NhbGVfZmlsZS4nPC9hPiBzYXZlZDxCUj4nOwoJCW15c3FsaV9mcmVlX3Jlc3VsdCgkdGltZV9zY2FsZSk7CgkJJG5faW50ID0gY291bnQoJGludF9uYW1lKTsKCQkKCQkkYmFzZV9vcmRvdmljaWFuID0gNDg4LjM7CgkJJHN0dWR5X21heCA9IG1heCgkaW50X2JvdHRvbSk7CgkJJHN0dWR5X21pbiA9IG1pbigkaW50X3RvcCk7CgkJCgkJCgkJLy8vLy8vLy8vLy8vLy8KCQkvLwoJCS8vIENvbHVtbiBkYXRhIHNhdmVkIGFzIGNvbHVtbnMuY3N2CgkJLy8KCQkvLy8vLy8vLy8vLy8vLwoJCSRjb2xzX2ZpbGUgPSAiY29sdW1ucy5jc3YiOwoJCSRmaCA9IGZvcGVuKCRjb2xzX2ZpbGUsICd3Jykgb3IgZGllKCJjYW4ndCBvcGVuIGZpbGUiKTsKCQljaG1vZCgkY29sc19maWxlLCAwNzc3KTsKCQkkZmlsZV9yb3cgPSAiY29sX2lkLCBsYXQsIGxuZywgc2hlZXQsIGNvbCwgY29sX2FyZWEsIHByb2plY3RfaWRcbiI7CgkJZndyaXRlKCRmaCwgJGZpbGVfcm93KTsKCQkKCQkkcSA9ICJTRUxFQ1QgY29scy5pZCwgbGF0LCBsbmcsIHByb2plY3RfaWQsIGNvbF9ncm91cCwgY29sLCBjb2xfYXJlYSBGUk9NIGNvbHMgCgkJSU5ORVIgSk9JTiBjb2xfZ3JvdXBzIE9OIGNvbF9ncm91cHMuaWQ9Y29sX2dyb3VwX2lkIAoJCUlOTkVSIEpPSU4gcHJvamVjdHMgT04gcHJvamVjdHMuaWQ9cHJvamVjdF9pZAoJCVdIRVJFIHByb2plY3QgPSAnTm9ydGggQW1lcmljYScgQU5EIGNvbF9ncm91cCAhPSAnTWV4aWNvJyBBTkQgY29scy5pZCBOT1QgSU4gKDM0LCAxMTEsIDEzOSwgMjE4LCA1ODYsIDU4NykgQU5EIHN0YXR1c19jb2RlID0gJ2FjdGl2ZSciOyAvL2VjaG8gJHEuIjxicj4iOwoJCQoJCS8vKDQ1Niw0NDMsNjMzLDQ5OSkKCQkkY29sdW1ucyA9IG15c3FsaV9xdWVyeSgkY29ubmVjdF9tYWNyb3N0cmF0LCAkcSk7ICAgICAgIAoJCXdoaWxlKCRyb3cgPSBteXNxbGlfZmV0Y2hfYXNzb2MoJGNvbHVtbnMpKSB7CgkJCSRmaWxlX3JvdyA9ICRyb3dbJ2lkJ10uIiwiLiRyb3dbJ2xhdCddLiIsIi4kcm93WydsbmcnXS4iLCIuJHJvd1snY29sX2dyb3VwJ10uIiwiLiRyb3dbJ2NvbCddLiIsIi4kcm93Wydjb2xfYXJlYSddLiIsIi4kcm93Wydwcm9qZWN0X2lkJ10uIlxuIjsKCQkJZndyaXRlKCRmaCwgJGZpbGVfcm93KTsKCQkJJG15X2NvbHNbXSA9ICRyb3dbJ2lkJ107CgkJfQoJCWZjbG9zZSgkZmgpOwoJCW15c3FsaV9mcmVlX3Jlc3VsdCgkY29sdW1ucyk7CgkJZWNobyAnRmlsZSA8YSBocmVmPSInLiRjb2xzX2ZpbGUuJyI+Jy4kY29sc19maWxlLic8L2E+IHNhdmVkPEJSPic7CgkJCgkJLy8gIGdldCBjb2x1bW4gcG9seWdvbnMKCQkkcG9seV9maWxlID0gImNvbHVtbl9wb2x5Z29ucy5jc3YiOwoJCSRmaCA9IGZvcGVuKCRwb2x5X2ZpbGUsICd3Jykgb3IgZGllKCJjYW4ndCBvcGVuIGZpbGUiKTsKCQljaG1vZCgkcG9seV9maWxlLCAwNzc3KTsKCQkkZmlsZV9yb3cgPSAiY29sX2lkLCBsYXQsIGxuZ1xuIjsKCQlmd3JpdGUoJGZoLCAkZmlsZV9yb3cpOwoJCQoJCSRxID0gIlNFTEVDVCBjb2xfaWQsIEFzVGV4dChjb2xfYXJlYSkgY29vcmRzIEZST00gY29sX2FyZWFzIAoJCVdIRVJFIGNvbF9pZCBJTiAoIi5pbXBsb2RlKCIsIiwgJG15X2NvbHMpLiIpIjsKCQkkY29sdW1ucyA9IG15c3FsaV9xdWVyeSgkY29ubmVjdF9tYWNyb3N0cmF0LCAkcSk7ICAgICAgIAoJCQoJCXdoaWxlKCRyb3cgPSBteXNxbGlfZmV0Y2hfYXNzb2MoJGNvbHVtbnMpKSB7CgkJCSRteV9jb29yZCA9IGx0cmltKCRyb3dbJ2Nvb3JkcyddLCAnUE9MWUdPTigoJyk7CgkJCSRteV9jb29yZCA9IHJ0cmltKCRteV9jb29yZCwgJykpJyk7CgkJCSRteV9jb29yZCA9IGV4cGxvZGUoIiwiLCAkbXlfY29vcmQpOwoJCQkKCQkJZm9yKCRpPTA7ICRpPGNvdW50KCRteV9jb29yZCk7ICsrJGkpIHsKCQkJCSR0ZW1wX2Nvb3JkID0gZXhwbG9kZSgiICIsICRteV9jb29yZFskaV0pOwoJCQkJJGZpbGVfcm93ID0gJHJvd1snY29sX2lkJ10uIiwiLiR0ZW1wX2Nvb3JkWzBdLiIsIi4kdGVtcF9jb29yZFsxXS4iXG4iOwoJCQkJZndyaXRlKCRmaCwgJGZpbGVfcm93KTsKCQkJfQoJCX0KCQlmY2xvc2UoJGZoKTsKCQlteXNxbGlfZnJlZV9yZXN1bHQoJGNvbHVtbnMpOwoJCWVjaG8gJ0ZpbGUgPGEgaHJlZj0iJy4kcG9seV9maWxlLiciPicuJHBvbHlfZmlsZS4nPC9hPiBzYXZlZDxCUj4nOwoJCQoJCS8vIGdldCBvYnNlbGV0ZSBjb2x1bW5zIHRvIGV4Y2x1ZGUKCQkkb2Jzb2xldGVfY29scyA9IGFycmF5KCk7CgkJJHEgPSAiU0VMRUNUIGNvbHMuaWQgIEZST00gY29scyAKCQlJTk5FUiBKT0lOIGNvbF9ncm91cHMgT04gY29sX2dyb3Vwcy5pZD1jb2xfZ3JvdXBfaWQgCgkJSU5ORVIgSk9JTiBwcm9qZWN0cyBPTiBwcm9qZWN0cy5pZD1wcm9qZWN0X2lkCgkJV0hFUkUgcHJvamVjdCA9ICdOb3J0aCBBbWVyaWNhJyBBTkQgc3RhdHVzX2NvZGUgPSAnb2Jzb2xldGUnIjsgLy9lY2hvICRxLiI8YnI+IjsJCQoJCSRjb2x1bW5zID0gbXlzcWxpX3F1ZXJ5KCRjb25uZWN0X21hY3Jvc3RyYXQsICRxKTsgICAgICAgCgkJd2hpbGUoJHJvdyA9IG15c3FsaV9mZXRjaF9hc3NvYygkY29sdW1ucykpIHsKCQkJJG9ic29sZXRlX2NvbHNbXSA9ICRyb3dbJ2lkJ107CgkJfQoJCW15c3FsaV9mcmVlX3Jlc3VsdCgkY29sdW1ucyk7CgkJCgkJCgoJCS8vLy8vLy8vLy8vLy8vCgkJLy8KCQkvLyBnZXQgcGFja2FnZXMJCgkJLy8KCQkvLy8vLy8vLy8vLy8vLwkJCgkJJGNvdW50ZXIgPSAwOwoJCSR0ZW1wX3BrZyA9IHNwbGl0X3BhY2thZ2VzKCdtYXJpbmUnKTsKCQkKCQkvLyAgc2V0IHBhY2thZ2UgY3Jvc3NlcnMKCQkkcGtnX2ZpbGUgPSAib3Jkb3ZpY2lhbl9wYWNrYWdlcy5jc3YiOwoJCSRmaCA9IGZvcGVuKCRwa2dfZmlsZSwgJ3cnKSBvciBkaWUoImNhbid0IG9wZW4gZmlsZSIpOwoJCWNobW9kKCRwa2dfZmlsZSwgMDc3Nyk7CgkJJGZpbGVfcm93ID0gInBhY2thZ2VfaWQsIGFnZV9ib3R0b20sIGFnZV90b3AsIGNvbF9pZFxuIjsKCQlmd3JpdGUoJGZoLCAkZmlsZV9yb3cpOwoJCQoJCWZvcigkaT0wOyAkaTxjb3VudCgkdGVtcF9wa2cpOyArKyRpKSB7CgkJCSRxID0gIlNFTEVDVCBjb2xfaWQsIG1heChiLmFnZV9ib3R0b20pIGJvdHRvbSwgbWluKHQuYWdlX3RvcCkgdG9wLCBjb3VudChkaXN0aW5jdCB1bml0cy5pZCkgbl91bml0LCBGT19oIEZST00gdW5pdHMKCQkJSU5ORVIgSk9JTiBpbnRlcnZhbHMgYiBPTiBiLmlkPUZPCgkJCUlOTkVSIEpPSU4gaW50ZXJ2YWxzIHQgT04gdC5pZD1MTwoJCQlXSEVSRSB1bml0cy5pZCBJTiAoJHRlbXBfcGtnWyRpXSkiOwoJCQkkcmVzdWx0PW15c3FsaV9xdWVyeSgkY29ubmVjdF9tYWNyb3N0cmF0LCAkcSk7CgkJCSRyb3c9bXlzcWxpX2ZldGNoX2Fzc29jKCRyZXN1bHQpOwoJCQlpZihpbl9hcnJheSgkcm93Wydjb2xfaWQnXSwgJG15X2NvbHMpPT09VFJVRSAmJiAkcm93Wydib3R0b20nXT4kc3R1ZHlfbWluICYmICRyb3dbJ3RvcCddPCRzdHVkeV9tYXgpIHsKCQkJCSRteV9wa2dbJGNvdW50ZXJdID0gJHRlbXBfcGtnWyRpXTsJCgkJCQkkbXlfcGtnX2ZvWyRjb3VudGVyXSA9ICRyb3dbJ2JvdHRvbSddOwkKCQkJCSRteV9wa2dfbG9bJGNvdW50ZXJdID0gJHJvd1sndG9wJ107CQoJCQkJJG15X3BrZ19uX3VuaXRzWyRjb3VudGVyXSA9ICRyb3dbJ25fdW5pdCddOwkKCQkJCSRteV9wa2dfY29sX2lkWyRjb3VudGVyXSA9ICRyb3dbJ2NvbF9pZCddOwoJCQkJCgkJCQkkdGVtcF91bml0cyA9IGV4cGxvZGUoIiwiLCR0ZW1wX3BrZ1skaV0pOwoJCQkJZm9yKCRqPTA7ICRqPGNvdW50KCR0ZW1wX3VuaXRzKTsgKyskaikgJHVuaXRfcGFja2FnZXNbJHRlbXBfdW5pdHNbJGpdXT0kY291bnRlcjsgIC8vIHVuaXRfaWQgaXMga2V5LCBwYWNrYWdlIG51bWJlciBpcyB2YWx1ZQoJCQkJCgkJCQkvLyAgZ2V0IGZvX2ggYW5kIGxvX2ggZm9yIHBhY2thZ2VzCgkJCQkkcSA9ICJTRUxFQ1QgdW5pdHMuaWQsIEZPX2gsIChiLmFnZV9ib3R0b20tYi5hZ2VfdG9wKS8yIGhhbGZfZHVyYXRpb24sIGIuYWdlX2JvdHRvbSBGUk9NIHVuaXRzCgkJCQlJTk5FUiBKT0lOIGludGVydmFscyBiIE9OIGIuaWQ9Rk8KCQkJCVdIRVJFIHVuaXRzLmlkIElOICgkdGVtcF9wa2dbJGldKQoJCQkJT1JERVIgQlkgYi5hZ2VfYm90dG9tIERFU0MsIEZPX2gKCQkJCUxJTUlUIDEiOwoJCQkJJGZvX3Jlc3VsdCA9IG15c3FsaV9xdWVyeSgkY29ubmVjdF9tYWNyb3N0cmF0LCAkcSk7CgkJCQkkZm9fcm93ID0gbXlzcWxpX2ZldGNoX2Fzc29jKCRmb19yZXN1bHQpOwoJCQkJJG15X3RlbXBfZm8gPSAkZm9fcm93WydGT19oJ107CgkJCQlteXNxbGlfZnJlZV9yZXN1bHQoJGZvX3Jlc3VsdCk7CgkJCQkKCQkJCSRxID0gIlNFTEVDVCB1bml0cy5pZCwgTE9faCwgKHQuYWdlX2JvdHRvbS10LmFnZV90b3ApLzIgaGFsZl9kdXJhdGlvbiwgdC5hZ2VfdG9wIEZST00gdW5pdHMKCQkJCUlOTkVSIEpPSU4gaW50ZXJ2YWxzIHQgT04gdC5pZD1MTwoJCQkJV0hFUkUgdW5pdHMuaWQgSU4gKCR0ZW1wX3BrZ1skaV0pCgkJCQlPUkRFUiBCWSB0LmFnZV90b3AsIEZJRUxEKExPX2gsMCw2LDUsNCwzLDIsMSkKCQkJCUxJTUlUIDEiOyAvL2VjaG8gJHEuIjxicj4iOwoJCQkJJGxvX3Jlc3VsdCA9IG15c3FsaV9xdWVyeSgkY29ubmVjdF9tYWNyb3N0cmF0LCAkcSk7CgkJCQkkbG9fcm93ID0gbXlzcWxpX2ZldGNoX2Fzc29jKCRsb19yZXN1bHQpOwoJCQkJJG15X3RlbXBfbG8gPSAkbG9fcm93WydMT19oJ107CgkJCQlteXNxbGlfZnJlZV9yZXN1bHQoJGxvX3Jlc3VsdCk7CgkJCQkJCQoJCQkJaWYoJG15X3RlbXBfZm89PTApICRteV9wa2dfZm9faFskY291bnRlcl0gPSAkZm9fcm93WydhZ2VfYm90dG9tJ107CgkJCQllbHNlICRteV9wa2dfZm9faFskY291bnRlcl0gPSAkZm9fcm93WydhZ2VfYm90dG9tJ10gLSAkZm9fcm93WydoYWxmX2R1cmF0aW9uJ107CgkJCQkKCQkJCWlmKCRteV90ZW1wX2xvPT0wKSAkbXlfcGtnX2xvX2hbJGNvdW50ZXJdID0gJGxvX3Jvd1snYWdlX3RvcCddOwoJCQkJZWxzZSAkbXlfcGtnX2xvX2hbJGNvdW50ZXJdID0gJGxvX3Jvd1snYWdlX3RvcCddICsgJGxvX3Jvd1snaGFsZl9kdXJhdGlvbiddOyAKCQkJCQoJCQkJJGZpbGVfcm93PSRjb3VudGVyLiIsIi4kZm9fcm93WydhZ2VfYm90dG9tJ10uIiwiLiRsb19yb3dbJ2FnZV90b3AnXS4iLCIuJHJvd1snY29sX2lkJ10uIlxuIjsKLy8JCQkJJGZpbGVfcm93PSRjb3VudGVyLiIsIi4kbXlfcGtnX2ZvX2hbJGNvdW50ZXJdLiIsIi4kbXlfcGtnX2xvX2hbJGNvdW50ZXJdLiJcbiI7CgkJCQlmd3JpdGUoJGZoLCAkZmlsZV9yb3cpOwoKCQkJCSsrJGNvdW50ZXI7CgkJCX0KCQkJCgkJCS8vIGdldCBwYWNrYWdlcyBmb3IgdGVzdGluZyBnYXBzCgkJCWlmKGluX2FycmF5KCRyb3dbJ2NvbF9pZCddLCAkbXlfY29scyk9PT1UUlVFKSB7CQkJCgkJCQkvLyAgZ2V0IGZvX2ggYW5kIGxvX2ggZm9yIHBhY2thZ2VzCgkJCQkkcSA9ICJTRUxFQ1QgdW5pdHMuaWQsIEZPX2gsIChiLmFnZV9ib3R0b20tYi5hZ2VfdG9wKS8yIGhhbGZfZHVyYXRpb24sIGIuYWdlX2JvdHRvbSBGUk9NIHVuaXRzCgkJCQlJTk5FUiBKT0lOIGludGVydmFscyBiIE9OIGIuaWQ9Rk8KCQkJCUlOTkVSIEpPSU4gaW50ZXJ2YWxzIHQgT04gdC5pZD1MTwoJCQkJV0hFUkUgdW5pdHMuaWQgSU4gKCR0ZW1wX3BrZ1skaV0pCgkJCQlPUkRFUiBCWSBiLmFnZV9ib3R0b20gREVTQywgRk9faCwgdC5hZ2VfdG9wIERFU0MsIGZpZWxkKExPX2gsIDEsMiwzLDQsNSw2LDApCgkJCQlMSU1JVCAxIjsKCQkJCSRmb19yZXN1bHQgPSBteXNxbGlfcXVlcnkoJGNvbm5lY3RfbWFjcm9zdHJhdCwgJHEpOwoJCQkJJGZvX3JvdyA9IG15c3FsaV9mZXRjaF9hc3NvYygkZm9fcmVzdWx0KTsKCQkJCWlmKCRmb19yb3dbJ0ZPX2gnXT09MCkgJG15X2dhcF9mb19oW10gPSAkZm9fcm93WydhZ2VfYm90dG9tJ107CgkJCQllbHNlICRteV9nYXBfZm9faFtdID0gJGZvX3Jvd1snYWdlX2JvdHRvbSddLSRmb19yb3dbJ2hhbGZfZHVyYXRpb24nXTsKCQkJCWlmKCRmb19yb3dbJ2FnZV9ib3R0b20nXSE9JHJvd1snYm90dG9tJ10pIGVjaG8gImJhZCBiYXNlIGNhbGM8YnI+IjsKCQkJCW15c3FsaV9mcmVlX3Jlc3VsdCgkZm9fcmVzdWx0KTsKCQkJCQoJCQkJJG15X2dhcF9wa2dbXSA9ICR0ZW1wX3BrZ1skaV07CQoJCQkJJG15X2dhcF9mb1tdID0gJHJvd1snYm90dG9tJ107CQoJCQkJJG15X2dhcF9jb2xfaWRbXSA9ICRyb3dbJ2NvbF9pZCddOwoJCQl9CgkJCW15c3FsaV9mcmVlX3Jlc3VsdCgkcmVzdWx0KTsKCQl9CgkJJGFsbF91bml0cyA9IGltcGxvZGUoIiwiLCRteV9wa2cpOwoJCSRhbGxfdW5pdHNfYXJyYXkgPSBleHBsb2RlKCIsIiwgJGFsbF91bml0cyk7CgkJJHRvdGFsX3VuaXRzID0gaW1wbG9kZSgiLCIsJG15X2dhcF9wa2cpOwoJCXVuc2V0KCR0ZW1wX3VuaXRzLCAkdGVtcF9wa2csICRjb3VudGVyKTsKCQllY2hvICJUaGVyZSBhcmUgIi4oY291bnQoZXhwbG9kZSgiLCIsJHRvdGFsX3VuaXRzKSkpLiIgdW5pdHMuPGJyPjxicj4iOwoJCWZjbG9zZSgkZmgpOwoJCWVjaG8gJ0ZpbGUgPGEgaHJlZj0iJy4kcGtnX2ZpbGUuJyI+Jy4kcGtnX2ZpbGUuJzwvYT4gc2F2ZWQ8QlI+JzsKCi8qCQkKCQkvLyBjYWxjdWxhdGUgcGFja2FnZSBjcm9zc2VycwoJCSRjcm9zc2VyX2ZpbGUgPSAncGFja2FnZV9jcm9zc2Vycy5jc3YnOwoJCSRmaCA9IGZvcGVuKCRjcm9zc2VyX2ZpbGUsJ3cnKTsKCQljaG1vZCgkY3Jvc3Nlcl9maWxlLCAwNjY2KTsKCQlmY2xvc2UoJGZoKTsKCQkKCQkkZmlsZV9uYW1lX3IgPSAndGVtcC5yJzsKCQkkZmggPSBmb3BlbigkZmlsZV9uYW1lX3IsICd3Jykgb3IgZGllKCJjYW4ndCBvcGVuIGZpbGUiKTsKCQljaG1vZCgkZmlsZV9uYW1lX3IsIDA2NjYpOwoJCSRyX3NjcmlwdCA9ICIKCQlzb3VyY2UoJ215RnVuY3Rpb25zLnInKQoJCXRpbWUuc2NhbGUgPC0gcmVhZC5jc3YoZmlsZT0nJHRpbWVfc2NhbGVfZmlsZScsIGhlYWRlcj1UUlVFKQoJCXBhY2thZ2VzIDwtIHJlYWQuY3N2KGZpbGU9JyRwa2dfZmlsZScsIGhlYWRlcj1UUlVFKQoJCQoJCWNyb3NzLnRlbXAgPC0gY3Jvc3NlcnMocGFja2FnZXNbLDI6M10sIHRpbWUuc2NhbGVbLDI6M10pCgkJd3JpdGUuY3N2KGNiaW5kKHRpbWUuc2NhbGVbLGMoNCwxOjMpXSxjcm9zcy50ZW1wKSwgZmlsZT0nJGNyb3NzZXJfZmlsZScsIHF1b3RlPUZBTFNFLCByb3cubmFtZXM9RkFMU0UpCgkJIjsKCQlmd3JpdGUoJGZoLCAkcl9zY3JpcHQpOwoJCWZjbG9zZSgkZmgpOwoJCSRjbWQgPSAiZWNobyAncnNjcmlwdCA8LSBcIiRmaWxlX25hbWVfclwiOyBzb3VyY2UocnNjcmlwdCknIHwgIiAuICIvdXNyL2Jpbi9SIC0tc2xhdmUgMj4mMSI7CgkJZXhlYygkY21kLCAkcl9yYW4pOyAKCQlpZihjb3VudCgkcl9yYW4pPjApIHsKCQkJZWNobyAiUiAoUGFja2FnZSBDcm9zc2Vycyk6ICI7CgkJCXByaW50X3IoJHJfcmFuKTsgZWNobyAiPGJyPiI7CgkJfQoJCWVjaG8gJ0ZpbGUgPGEgaHJlZj0iJy4kY3Jvc3Nlcl9maWxlLiciPicuJGNyb3NzZXJfZmlsZS4nPC9hPiBzYXZlZDxCUj4nOwoJCQoKCQkKCQkvLy8vLy8vLy8vLy8vLwoJCS8vCgkJLy8gY2FsY3VsYXRlIGVudmlyb25tZW50YWwgZ2FwcyBmb3IgZXZlcnkgdW5pdAoJCS8vCgkJLy8vLy8vLy8vLy8vLy8KCQkkZW52X2dhcCA9IGFycmF5KCk7CgkJJGVudl91bml0X3RvcCA9IGFycmF5KCk7CgkJJGFsbF91bml0X2FycmF5ID0gZXhwbG9kZSgiLCIsJGFsbF91bml0cyk7CgkJZm9yKCRpPTA7ICRpPGNvdW50KCRhbGxfdW5pdF9hcnJheSk7ICsrJGkpIHsKCQkJLy8gZ2V0IGluZm9ybWF0aW9uIGZvciBmb2NhbCB1bml0CgkJCSRxID0gIlNFTEVDVCB1bml0cy5pZCwgY29sb3IsIGNvbF9pZCwgdC5hZ2VfYm90dG9tIHRvcF9ib3R0b20sIHQuYWdlX3RvcCwgTE9faCwgTE8sIEZPX2gsIGIuYWdlX2JvdHRvbSBGUk9NIHVuaXRzCgkJCUlOTkVSIEpPSU4gaW50ZXJ2YWxzIGIgT04gYi5pZD1GTwoJCQlJTk5FUiBKT0lOIGludGVydmFscyB0IE9OIHQuaWQ9TE8KCQkJV0hFUkUgdW5pdHMuaWQ9Ii4kYWxsX3VuaXRfYXJyYXlbJGldOwoJCQkkcmVzdWx0ID0gbXlzcWxpX3F1ZXJ5KCRjb25uZWN0X21hY3Jvc3RyYXQsICRxKTsKCQkJJGZvY2FsX3VuaXQgPSBteXNxbGlfZmV0Y2hfYXNzb2MoJHJlc3VsdCk7CgkJCW15c3FsaV9mcmVlX3Jlc3VsdCgkcmVzdWx0KTsKCQkJaWYoJGZvY2FsX3VuaXRbJ0xPX2gnXSA9PSAwKSB7CgkJCQkkZ2FwX2JvdHRvbSA9ICRmb2NhbF91bml0WydhZ2VfdG9wJ107CgkJCX0gZWxzZSB7CgkJCQkkZ2FwX2JvdHRvbSA9ICRmb2NhbF91bml0WydhZ2VfdG9wJ10gKyAoJGZvY2FsX3VuaXRbJ3RvcF9ib3R0b20nXS0kZm9jYWxfdW5pdFsnYWdlX3RvcCddKS8yOwoJCQl9CgkJCQoJCQkvLyBnZXQgaW5mb3JtYXRpb24gb24gbmV4dCB5b3VuZ2VzdCB1bml0IHdpdGggc2FtZSBjb2xvcgoJCQkkcSA9ICJTRUxFQ1QgdW5pdHMuaWQsIGIuYWdlX2JvdHRvbSwgYi5hZ2VfdG9wIGJvdHRvbV90b3AsIEZPX2gsIEZPLCBjb2xvciwgdC5hZ2VfdG9wLCBMT19oIEZST00gdW5pdHMgCgkJCUlOTkVSIEpPSU4gaW50ZXJ2YWxzIGIgT04gYi5pZD1GTwoJCQlJTk5FUiBKT0lOIGludGVydmFscyB0IE9OIHQuaWQ9TE8KCQkJV0hFUkUgY29sX2lkPSIuJGZvY2FsX3VuaXRbJ2NvbF9pZCddLiIgQU5EIHVuaXRzLmlkIElOICgiLiR0b3RhbF91bml0cy4iKSBBTkQgdW5pdHMuaWQgIT0gIi4kZm9jYWxfdW5pdFsnaWQnXS4iIAoJCQkJQU5EICgoRk9faCE9MCBBTkQgYi5hZ2VfYm90dG9tLShiLmFnZV9ib3R0b20tYi5hZ2VfdG9wKS8yIDw9Ii4kZ2FwX2JvdHRvbS4iKSBPUiAoRk9faD0wIEFORCBiLmFnZV9ib3R0b208PSIuJGdhcF9ib3R0b20uIikpIAoJCQkJQU5EIGNvbG9yPSciLiRmb2NhbF91bml0Wydjb2xvciddLiInCgkJCU9SREVSIEJZIGIuYWdlX2JvdHRvbSBERVNDLCBGT19oLCB0LmFnZV90b3AgREVTQywgZmllbGQoTE9faCwgMSwyLDMsNCw1LDYsMCkKCQkJTElNSVQgMSI7IC8vZWNobyAkcS4iPGJyPiI7CgkJCSRyZXN1bHQgPSBteXNxbGlfcXVlcnkoJGNvbm5lY3RfbWFjcm9zdHJhdCwgJHEpOwoJCQlpZihteXNxbGlfbnVtX3Jvd3MoJHJlc3VsdCk9PTEpIHsKCQkJCSR0ZXN0X3VuaXQgPSBteXNxbGlfZmV0Y2hfYXNzb2MoJHJlc3VsdCk7CgkJCQlpZigkdGVzdF91bml0WydGT19oJ10gPT0gMCkgewoJCQkJCSRnYXBfdG9wID0gJHRlc3RfdW5pdFsnYWdlX2JvdHRvbSddOwoJCQkJfSBlbHNlIHsKCQkJCQkkZ2FwX3RvcCA9ICR0ZXN0X3VuaXRbJ2FnZV9ib3R0b20nXSAtICgkdGVzdF91bml0WydhZ2VfYm90dG9tJ10tJHRlc3RfdW5pdFsnYm90dG9tX3RvcCddKS8yOwoJCQkJfQoJCQl9IGVsc2UgewoJCQkJJGdhcF90b3AgPSAwOwoJCQl9CgkJCW15c3FsaV9mcmVlX3Jlc3VsdCgkcmVzdWx0KTsKCQkJCgkJCWlmKHJvdW5kKCRnYXBfYm90dG9tLDUpPT1yb3VuZCgkZ2FwX3RvcCw1KSkgewoJCQkJJGVudl9nYXBbJGFsbF91bml0X2FycmF5WyRpXV09MDsKCQkJfSBlbHNlIHsKCQkJCSRlbnZfZ2FwWyRhbGxfdW5pdF9hcnJheVskaV1dID0gbG9nKCRnYXBfYm90dG9tLSRnYXBfdG9wKTsKCQkJfSAKCQkJaWYoJGdhcF9ib3R0b208JGdhcF90b3ApIHsKCQkJCWVjaG8gJGZvY2FsX3VuaXRbJ2lkJ10uIiAoIi4kdGVzdF91bml0WydpZCddLiIpOiAiLiRnYXBfYm90dG9tLiIgLSAiLiRnYXBfdG9wLiIgPSAiLiRlbnZfZ2FwWyRhbGxfdW5pdF9hcnJheVskaV1dLiI8YnI+IjsKCQkJfQoJCQkkZW52X3VuaXRfdG9wWyRhbGxfdW5pdF9hcnJheVskaV1dID0gJGdhcF9ib3R0b207CgkJfQovLwkJZWNobyAiZW52aXJvbm1lbnRhbCBnYXA6PGJyPiI7cHJpbnRfcigkZW52X2dhcCk7IGVjaG8gIjxicj48YnI+IjsKCgkJCgkJLy8vLy8vLy8vLy8vLy8KCQkvLwoJCS8vIGdldCBkdXJhdGlvbiBvZiBnYXBzIGFib3ZlIHBhY2thZ2VzCgkJLy8KCQkvLy8vLy8vLy8vLy8vLwoJCWZvcigkaT0wOyAkaTxjb3VudCgkbXlfcGtnKTsgKyskaSkgewoJCQkkdGVtcF9tYXg9MDsKCQkJJHRlbXBfZm89MDsKCQkJZm9yKCRqPTA7ICRqPGNvdW50KCRteV9nYXBfcGtnKTsgKyskaikgewoJCQkJaWYoJG15X2dhcF9wa2dbJGpdIT0kbXlfcGtnWyRpXSAmJiAkbXlfcGtnX2NvbF9pZFskaV09PSRteV9nYXBfY29sX2lkWyRqXSAmJiAkbXlfcGtnX2xvWyRpXSA+PSAkbXlfZ2FwX2ZvWyRqXSAmJiAkbXlfZ2FwX2ZvWyRqXT4kdGVtcF9tYXgpIHsKCQkJCQkkdGVtcF9tYXggPSAkbXlfZ2FwX2ZvWyRqXTsKCQkJCX0KCQkJCWlmKCRteV9nYXBfcGtnWyRqXSE9JG15X3BrZ1skaV0gJiYgJG15X3BrZ19jb2xfaWRbJGldPT0kbXlfZ2FwX2NvbF9pZFskal0gJiYgJG15X3BrZ19sb19oWyRpXSA+PSAkbXlfZ2FwX2ZvX2hbJGpdICYmICRteV9nYXBfZm9faFskal0+JHRlbXBfZm8pIHsKCQkJCQkkdGVtcF9mbyA9ICRteV9nYXBfZm9faFskal07CQkJCQoJCQkJfQoJCQl9CgkJCWlmKCRteV9wa2dfbG9bJGldICE9ICR0ZW1wX21heCkgewoJCQkJJG15X3BrZ19nYXBbJGldID0gbG9nKCRteV9wa2dfbG9bJGldIC0gJHRlbXBfbWF4KTsKCQkJfSBlbHNlIHsKCQkJCSRteV9wa2dfZ2FwWyRpXSA9IDA7CgkJCX0KCQkJCgkJCWlmKHJvdW5kKCRteV9wa2dfbG9faFskaV0sNSkgIT0gcm91bmQoJHRlbXBfZm8sNSkpIHsKCQkJCSRteV9wa2dfZ2FwMlskaV0gPSBsb2coJG15X3BrZ19sb19oWyRpXSAtICR0ZW1wX2ZvKTsKCQkJfSBlbHNlIHsKCQkJCSRteV9wa2dfZ2FwMlskaV0gPSAwOwoJCQl9CgkJfQoKKi8KCQkvLy8vLy8vLy8vLy8vLwoJCS8vCgkJLy8gZ2V0IG1hdGNoZWQgb3Jkb3ZpY2lhbiBnZW5lcmEgYW5kIHJlZmVyZW5jZXMKCQkvLwoJCS8vLy8vLy8vLy8vLy8vCgkJCgkJLy8gZ2V0IGFsbCBhcHByb3ByaWF0ZSB0YXhhCgkJJG15X2dlbmVyYSA9IGFycmF5KCk7CgkJJHRoaXNfZ2VudXMgPSBhcnJheSgpOwoJCSRteV9nZW51c19hZ2UgPSBhcnJheSgpOwoJCSRteV9vY2N1cnJlbmNlcyA9IGFycmF5KCk7CgkJCgkJJHEgPSAiU0VMRUNUIG9jY3VycmVuY2VzX3RlbXAyLnRheG9uX25vLCBnZW51c19uYW1lLCBjbGFzcywgdGF4b25fb3JkZXIsIGZhbWlseSwgbWluKHRhLnRvcF9hZ2UpIHBiZGJfbWluLAoJCW9jY3VycmVuY2VzX3RlbXAyLnRheG9uX2Vudmlyb25tZW50LCBvY2N1cnJlbmNlc190ZW1wMi5sb2NvbW90aW9uLCBvY2N1cnJlbmNlc190ZW1wMi5saWZlX2hhYml0LCBvY2N1cnJlbmNlc190ZW1wMi5kaWV0MSwgb2NjdXJyZW5jZXNfdGVtcDIuZGlldDIgCgkJRlJPTSBvY2N1cnJlbmNlc190ZW1wMgoJCUlOTkVSIEpPSU4gaW50ZXJ2YWxzIGIgT04gYi5pZD1vY2N1cnJlbmNlc190ZW1wMi5GTwoJCUlOTkVSIEpPSU4gaW50ZXJ2YWxzIHQgT04gdC5pZD1vY2N1cnJlbmNlc190ZW1wMi5MTwoJCUlOTkVSIEpPSU4gcGJkYi5pbnRlcnZhbF9sb29rdXAgYmEgT04gYmEuaW50ZXJ2YWxfbm89b2NjdXJyZW5jZXNfdGVtcDIubWF4X2ludGVydmFsX25vCgkJSU5ORVIgSk9JTiBwYmRiLmludGVydmFsX2xvb2t1cCB0YSBPTiB0YS5pbnRlcnZhbF9ubz1vY2N1cnJlbmNlc190ZW1wMi5taW5faW50ZXJ2YWxfbm8KCQlMRUZUIE9VVEVSIEpPSU4gcGJkYi5lY290YXBoIE9OIGVjb3RhcGgudGF4b25fbm89b2NjdXJyZW5jZXNfdGVtcDIudGF4b25fbm8KCQlMRUZUIE9VVEVSIEpPSU4gcGJkYi5hdXRob3JpdGllcyBPTiBhdXRob3JpdGllcy50YXhvbl9ubz1vY2N1cnJlbmNlc190ZW1wMi50YXhvbl9ubwoJCVdIRVJFIG9jY3VycmVuY2VzX3RlbXAyLnVuaXRfaWQgPiAwIEFORCBvY2N1cnJlbmNlc190ZW1wMi51bml0X2lkIElOICgiLiRhbGxfdW5pdHMuIikgQU5EIChvY2N1cnJlbmNlc190ZW1wMi5leHRhbnQgPSAnbm8nIE9SIG9jY3VycmVuY2VzX3RlbXAyLmV4dGFudCBJUyBOVUxMKQoJCUFORCBvY2N1cnJlbmNlc190ZW1wMi5jb2xfaWQgTk9UIElOICgiLmltcGxvZGUoIiwiLCRvYnNvbGV0ZV9jb2xzKS4iKQoJCUFORCAoKGIuYWdlX2JvdHRvbSA+ICIuJHN0dWR5X21pbi4iIEFORCB0LmFnZV90b3AgPCAiLiRzdHVkeV9tYXguIikgT1IgKChiLmFnZV9ib3R0b20gSVMgTlVMTCBBTkQgdC5hZ2VfdG9wIElTIE5VTEwpIEFORCAoYmEuYmFzZV9hZ2UgPiAiLiRzdHVkeV9taW4uIiBBTkQgdGEudG9wX2FnZSA8ICIuJHN0dWR5X21heC4iKSkpCQkKCQlBTkQgKG9jY3VycmVuY2VzX3RlbXAyLnJlbGVhc2VfZGF0ZSA8PSBub3coKSBPUiBvY2N1cnJlbmNlc190ZW1wMi5yZWxlYXNlX2RhdGUgSVMgTlVMTCkgCgkJQU5EIChmb3JtX3RheG9uID0gJ25vJyBPUiBmb3JtX3RheG9uIElTIE5VTEwpIEFORCAocHJlc2VydmF0aW9uICE9ICd0cmFjZScgT1IgcHJlc2VydmF0aW9uIElTIE5VTEwpCgkJR1JPVVAgQlkgb2NjdXJyZW5jZXNfdGVtcDIudGF4b25fbm8iOyAvL2VjaG8gJHEuIjxicj48YnI+IjsgCgkJJHJlc3VsdCA9IG15c3FsaV9xdWVyeSgkY29ubmVjdF9tYWNyb3N0cmF0LCAkcSk7CgkJZWNobyAiVGhlcmUgYXJlICIubXlzcWxpX251bV9yb3dzKCRyZXN1bHQpLiIgcXVlcmllZCBnZW5lcmE8YnI+IjsgCgkJd2hpbGUoJHJvdz1teXNxbGlfZmV0Y2hfYXNzb2MoJHJlc3VsdCkpIHsKCQkJJG15X2dlbmVyYVtdID0gJHJvdzsKCQkJJHRoaXNfZ2VudXNbXSA9ICRyb3dbJ3RheG9uX25vJ107CgkJCSRteV9nZW51c19hZ2VbJHJvd1sndGF4b25fbm8nXV1bJ3BiZGJfbWluJ10gPSAkcm93WydwYmRiX21pbiddOwoJCX0KCQlteXNxbGlfZnJlZV9yZXN1bHQoJHJlc3VsdCk7CgkJCgkJLy8gZ2V0IGdsb2JhbCBhbmQgTm9BbSByYW5nZXMgb2YgdGF4YSAtIGV2ZW4gb3V0c2lkZSBzdHVkeSBpbnRlcnZhbAoJCQoJCSRxID0gIlNFTEVDVCBvY2N1cnJlbmNlX25vLCB0YXhvbl9ubywgYmEuYmFzZV9hZ2UsIHRhLnRvcF9hZ2UsIEZPX2gsIExPX2gsIHVuaXRfaWQsCgkJYi5hZ2VfYm90dG9tLSgoYi5hZ2VfYm90dG9tLWIuYWdlX3RvcCkvMipMRUFTVCgxLEZPX2gpKSBib3R0b20sIHQuYWdlX2JvdHRvbSsoKHQuYWdlX2JvdHRvbS10LmFnZV90b3ApLzIqTEVBU1QoMSxMT19oKSkgdG9wLAoJCXVuaXRfaWQsIGNvbF9pZCwgb2NjdXJyZW5jZXNfdGVtcDIuY29sbGVjdGlvbl9ubywKCQlvcmlnaW5hbF90YXhvbl9ubywgb3JpZ2luYWxfdGF4b25fcmFuaywgcGFsZW9sYXQsIHBhbGVvbG5nCgkJRlJPTSBvY2N1cnJlbmNlc190ZW1wMgoJCUlOTkVSIEpPSU4gcGJkYi5pbnRlcnZhbF9sb29rdXAgYmEgT04gYmEuaW50ZXJ2YWxfbm89b2NjdXJyZW5jZXNfdGVtcDIubWF4X2ludGVydmFsX25vCgkJSU5ORVIgSk9JTiBwYmRiLmludGVydmFsX2xvb2t1cCB0YSBPTiB0YS5pbnRlcnZhbF9ubz1vY2N1cnJlbmNlc190ZW1wMi5taW5faW50ZXJ2YWxfbm8KCQlMRUZUIE9VVEVSIEpPSU4gaW50ZXJ2YWxzIGIgT04gYi5pZD1GTwoJCUxFRlQgT1VURVIgSk9JTiBpbnRlcnZhbHMgdCBPTiB0LmlkPUxPCgkJV0hFUkUgdGF4b25fbm8gSU4gKCIuaW1wbG9kZSgiLCIsICR0aGlzX2dlbnVzKS4iKQoJCUFORCAob2NjdXJyZW5jZXNfdGVtcDIudW5pdF9pZD0wIE9SIG9jY3VycmVuY2VzX3RlbXAyLnVuaXRfaWQgSU4gKCIuJGFsbF91bml0cy4iKSkgCgkJQU5EIChvY2N1cnJlbmNlc190ZW1wMi5jb2xfaWQgSVMgTlVMTCBPUiBvY2N1cnJlbmNlc190ZW1wMi5jb2xfaWQgTk9UIElOICgiLmltcGxvZGUoIiwiLCRvYnNvbGV0ZV9jb2xzKS4iKSkiOyAvL2VjaG8gJHEuIjxicj48YnI+IjsKCQkkcmVzdWx0ID0gbXlzcWxpX3F1ZXJ5KCRjb25uZWN0X21hY3Jvc3RyYXQsICRxKTsKCQllY2hvICJUaGVyZSBhcmUgIi5teXNxbGlfbnVtX3Jvd3MoJHJlc3VsdCkuIiBxdWVyaWVkIG9jY3VycmVuY2VzPGJyPiI7CgkJJGNvdW50ZXIgPSAwOwoJCSRpbnRfb2NjdXJyZW5jZXMgPSBhcnJheSgpOwoJCSRpbnRfcGFsZW9sYXQgPSBhcnJheSgpOwoJCXdoaWxlKCRyb3c9bXlzcWxpX2ZldGNoX2Fzc29jKCRyZXN1bHQpKSB7CgkJCWlmKCRyb3dbJ3VuaXRfaWQnXT09MCB8fCBpbl9hcnJheSgkcm93Wyd1bml0X2lkJ10sICRhbGxfdW5pdHNfYXJyYXkpPT09RkFMU0UpIHsgLy8gbm90IG1hdGNoZWQgdG8gbm9ydGggYW1lcmljYQoJCQkJCSRvY2N1cnJlbmNlX2JvdHRvbSA9ICRyb3dbJ2Jhc2VfYWdlJ107CgkJCQkJJG9jY3VycmVuY2VfdG9wID0gJHJvd1sndG9wX2FnZSddOwoJCQl9IGVsc2UgewoJCQkJaWYoJHJvd1snYmFzZV9hZ2UnXT4kcm93Wyd0b3AnXSAmJiAkcm93Wyd0b3BfYWdlJ108JHJvd1snYm90dG9tJ10pIHsvLyBwYmRiIGFuZCB1bml0IGFnZXMgb3ZlcmxhcDogdXNlIHlvdW5nZXN0IGJvdHRvbSBhbmQgb2xkZXN0IHRvcAoJCQkJCSRvY2N1cnJlbmNlX2JvdHRvbSA9IG1pbigkcm93WydiYXNlX2FnZSddLCAkcm93Wydib3R0b20nXSk7CgkJCQkJJG9jY3VycmVuY2VfdG9wID0gbWF4KCRyb3dbJ3RvcF9hZ2UnXSwgJHJvd1sndG9wJ10pOyAKCQkJCX0gZWxzZSB7ICAvLyBwYmRiIGFuZCB1bml0IGFnZXMgRE8gTk9UIG92ZXJsYXA6IHVzZSBtYWNyb3N0cmF0CgkJCQkJJG9jY3VycmVuY2VfYm90dG9tID0gJHJvd1snYm90dG9tJ107CgkJCQkJJG9jY3VycmVuY2VfdG9wID0gJHJvd1sndG9wJ107CgkJCQl9CgkJCX0KCQkJCgkJCSRteV9vY2N1cnJlbmNlc1tdID0gYXJyYXkoCgkJCQkib2NjdXJyZW5jZV9ubyIgPT4gJHJvd1snb2NjdXJyZW5jZV9ubyddLCAKCQkJCSJ0YXhvbl9ubyIgPT4gJHJvd1sndGF4b25fbm8nXSwgCgkJCQkiYm90dG9tIiA9PiAkb2NjdXJyZW5jZV9ib3R0b20sIAoJCQkJInRvcCIgPT4gJG9jY3VycmVuY2VfdG9wLAoJCQkJInVuaXRfaWQiID0+ICRyb3dbJ3VuaXRfaWQnXSwKCQkJCSJjb2xfaWQiID0+ICRyb3dbJ2NvbF9pZCddLAoJCQkJImNvbGxlY3Rpb25fbm8iID0+ICRyb3dbJ2NvbGxlY3Rpb25fbm8nXSwKCQkJCSJvcmlnaW5hbF90YXhvbl9ubyIgPT4gJHJvd1snb3JpZ2luYWxfdGF4b25fbm8nXSwKCQkJCSJvcmlnaW5hbF90YXhvbl9yYW5rIiA9PiAkcm93WydvcmlnaW5hbF90YXhvbl9yYW5rJ10sCgkJCQkicGFsZW9sYXQiID0+ICRyb3dbJ3BhbGVvbGF0J10sCgkJCQkicGFsZW9sbmciID0+ICRyb3dbJ3BhbGVvbG5nJ10KCQkJKTsKCQkJLy8gZ2V0IG9jY3VycmVuY2UgaW50ZXJ2YWwgY29tYmluYXRpb25zCgkJCWZvcigkaT0wOyAkaTwkbl9pbnQ7ICsrJGkpIHsKCQkJCWlmKCRvY2N1cnJlbmNlX2JvdHRvbT4kaW50X3RvcFskaV0gJiYgJG9jY3VycmVuY2VfdG9wPCRpbnRfYm90dG9tWyRpXSkgJGludF9vY2N1cnJlbmNlc1skaV1bXSA9ICRjb3VudGVyOwoJCQkJaWYoJG9jY3VycmVuY2VfYm90dG9tPiRpbnRfdG9wWyRpXSAmJiAkb2NjdXJyZW5jZV90b3A8JHN0dWR5X21heCAmJiBpc19udW1lcmljKCRyb3dbJ3BhbGVvbGF0J10pKSAkaW50X3BhbGVvbGF0WyRpXVskcm93Wyd0YXhvbl9ubyddXVtdID0gJHJvd1sncGFsZW9sYXQnXTsKCQkJfQoJCQkrKyRjb3VudGVyOwoJCQkKCQkJaWYoaXNzZXQoJG15X2dlbnVzX2FnZVskcm93Wyd0YXhvbl9ubyddXVsnZ2xvYmFsX21heCddKT09PUZBTFNFKSAkbXlfZ2VudXNfYWdlWyRyb3dbJ3RheG9uX25vJ11dWydnbG9iYWxfbWF4J10gPSAkb2NjdXJyZW5jZV9ib3R0b207CgkJCWVsc2UgaWYoJG15X2dlbnVzX2FnZVskcm93Wyd0YXhvbl9ubyddXVsnZ2xvYmFsX21heCddIDwgJHJvd1snYmFzZV9hZ2UnXSkgJG15X2dlbnVzX2FnZVskcm93Wyd0YXhvbl9ubyddXVsnZ2xvYmFsX21heCddID0gJG9jY3VycmVuY2VfYm90dG9tOwoJCQkKCQkJaWYoaXNzZXQoJG15X2dlbnVzX2FnZVskcm93Wyd0YXhvbl9ubyddXVsnZ2xvYmFsX21pbiddKT09PUZBTFNFKSAkbXlfZ2VudXNfYWdlWyRyb3dbJ3RheG9uX25vJ11dWydnbG9iYWxfbWluJ10gPSAkb2NjdXJyZW5jZV90b3A7CgkJCWVsc2UgaWYoJG15X2dlbnVzX2FnZVskcm93Wyd0YXhvbl9ubyddXVsnZ2xvYmFsX21pbiddID4gJHJvd1sndG9wX2FnZSddKSAkbXlfZ2VudXNfYWdlWyRyb3dbJ3RheG9uX25vJ11dWydnbG9iYWxfbWluJ10gPSAkb2NjdXJyZW5jZV90b3A7CgkJCQoJCQlpZigkcm93Wyd1bml0X2lkJ10+MCAmJiBpbl9hcnJheSgkcm93Wyd1bml0X2lkJ10sICRhbGxfdW5pdHNfYXJyYXkpICYmICgoJHJvd1sndG9wJ10gPCA0NDMuNyAmJiAkbXlfZ2VudXNfYWdlWyRyb3dbJ3RheG9uX25vJ11dWydwYmRiX21pbiddIDwgNDQzLjcpIHx8ICRyb3dbJ3RvcCddID49IDQ0My43KSkgewoJCQkJaWYoaXNzZXQoJG15X2dlbnVzX2FnZVskcm93Wyd0YXhvbl9ubyddXVsnbm9hbV9tYXgnXSk9PT1GQUxTRSkgJG15X2dlbnVzX2FnZVskcm93Wyd0YXhvbl9ubyddXVsnbm9hbV9tYXgnXSA9ICRvY2N1cnJlbmNlX2JvdHRvbTsKCQkJCWVsc2UgaWYoJG15X2dlbnVzX2FnZVskcm93Wyd0YXhvbl9ubyddXVsnbm9hbV9tYXgnXSA8ICRyb3dbJ2Jhc2VfYWdlJ10pICRteV9nZW51c19hZ2VbJHJvd1sndGF4b25fbm8nXV1bJ25vYW1fbWF4J10gPSAkb2NjdXJyZW5jZV9ib3R0b207CgkJCQkKCQkJCWlmKGlzc2V0KCRteV9nZW51c19hZ2VbJHJvd1sndGF4b25fbm8nXV1bJ25vYW1fbWluJ10pPT09RkFMU0UpICRteV9nZW51c19hZ2VbJHJvd1sndGF4b25fbm8nXV1bJ25vYW1fbWluJ10gPSAkb2NjdXJyZW5jZV90b3A7CgkJCQllbHNlIGlmKCRteV9nZW51c19hZ2VbJHJvd1sndGF4b25fbm8nXV1bJ25vYW1fbWluJ10gPiAkcm93Wyd0b3BfYWdlJ10pICRteV9nZW51c19hZ2VbJHJvd1sndGF4b25fbm8nXV1bJ25vYW1fbWluJ10gPSAkb2NjdXJyZW5jZV90b3A7CgkJCX0JCQkKCQl9CgkJbXlzcWxpX2ZyZWVfcmVzdWx0KCRyZXN1bHQpOwoKCi8vCQkkcGJkYl9maWxlID0gIm9yZG92aWNpYW5fZ2VuZXJhLmNzdiI7CgkJJHBiZGJfZmlsZSA9ICJvcmRvdmljaWFuX2dlbmVyYV9jdWxsZWQuY3N2IjsKCQkkZmggPSBmb3BlbigkcGJkYl9maWxlLCAndycpIG9yIGRpZSgiY2FuJ3Qgb3BlbiBmaWxlIik7CgkJY2htb2QoJHBiZGJfZmlsZSwgMDY2Nik7CgkJJGZpbGVfcm93ID0gImludGVydmFsX2lkLCBpbnRlcnZhbF9uYW1lLCBhZ2VfYm90dG9tLCBhZ2VfdG9wLCB0YXhvbl9ubywgZ2VudXMsIGNsYXNzLCBvcmRlciwgZmFtaWx5LCBsaWZlX2hhYml0LCBsb2NvbW90aW9uLCB0YXhvbl9lbnZpcm9ubWVudCwgZGlldDEsIGRpZXQyLCBuX3NwZWNpZXNfTm9BbSwgbl9zcGVjaWVzX2dsb2JhbCwgbl9jb2xsZWN0aW9uc19Ob0FtLCBuX29jY3VyX05vQW0sIGdsb2JhbF9lbmRlbWljX3RvX2ludGVydmFsLCBOb0FtX0ZBRCwgTm9BbV9MQUQsIGdsb2JhbF9GQUQsIGdsb2JhbF9MQUQsIG1heF9OX3BhbGVvbGF0X2R1cmluZ19wcmlvciwgbWF4X1NfcGFsZW9sYXRfZHVyaW5nX3ByaW9yLCBuX21hdGNoZWRfdW5pdHNfZ3JlYXRlcl9uXzQ1LCBuX21hdGNoZWRfdW5pdHNfZ3JlYXRlcl9zXzQ1LCBtYXhfZ3JlYXRfY2lyY2xlX05vQW0sIG1heF9ncmVhdF9jaXJjbGVfR2xvYmFsLCBuX3BhY2thZ2VzX29jY3VwaWVkLCBuX3BhY2thZ2VzX3RvdGFsLCBuX3VuaXRzX29jY3VwaWVkLCBuX3VuaXRzX3RvdGFsLG5fY2FyYl91bml0cywgbl9jYXJiX3VuaXRzX29jY3VwaWVkLCBuX3NpbGljaWNsYXN0aWNfdW5pdHMsIG5fc2lsaWNpY2xhc3RpY191bml0c19vY2N1cGllZCwgbl90cnVuY2F0aW5nX3BhY2thZ2VzX3RvdGFsLCBuX3RydW5jYXRpbmdfcGFja2FnZXNfb2NjdXBpZWQsIG5fZW52X3RydW5jYXRpb24sIG5fZW52X3RydW5jYXRpb25fZG91YmxlLCBuX3VuaXRzX2VudGlyZWx5X3dpdGhpbl9pbnRlcnZhbCwgbWluX2dhcCwgbWF4X2dhcCwgbWVhbl9nYXAsIG1lZGlhbl9nYXAsIG1pbl9lbnZfZ2FwLCBtYXhfZW52X2dhcCwgbWVhbl9lbnZfZ2FwLCBtZWRpYW5fZW52X2dhcCwgbl9lbnZfZ2FwLCBuX2NvbHVtbnNfb2NjdXBpZWQsIG5fY29sdW1uc190b3RhbCwgbl90cnVuY19jb2x1bW5zX29jY3VwaWVkXG4iOwoJCWZ3cml0ZSgkZmgsICRmaWxlX3Jvdyk7CgkJCgkJJG15X2NvbGxlY3Rpb25zID0gYXJyYXkoKTsKCQlmb3IoJGk9MDsgJGkgPCAxOyArKyRpKSB7CQkKLy8JCWZvcigkaT0wOyAkaTwkbl9pbnQ7ICsrJGkpIHsJCQoJCQkvLyBnZXQgdG90YWwgdW5pdHMgYW5kIHBhY2thZ2VzCgkJCSRteV9wYWNrYWdlcyA9IGFycmF5KCk7CgkJCSRteV9jb2x1bW5zID0gYXJyYXkoKTsKCQkJJG15X2NhcmIgPSBhcnJheSgpOwoJCQkkbXlfY2xhc3QgPSBhcnJheSgpOwoJCQkkcSA9ICJTRUxFQ1QgdW5pdHMuaWQsIGNvbG9yLCBjb2xfaWQgRlJPTSB1bml0cwoJCQlJTk5FUiBKT0lOIGludGVydmFscyBiIE9OIGIuaWQ9Rk8KCQkJSU5ORVIgSk9JTiBpbnRlcnZhbHMgdCBPTiB0LmlkPUxPCgkJCVdIRVJFIHVuaXRzLmlkIElOICgiLiRhbGxfdW5pdHMuIikgQU5EIGIuYWdlX2JvdHRvbT4kaW50X3RvcFskaV0gQU5EIHQuYWdlX3RvcDwkaW50X2JvdHRvbVskaV0iOwoJCQkkcmVzdWx0ID0gbXlzcWxpX3F1ZXJ5KCRjb25uZWN0X21hY3Jvc3RyYXQsICRxKTsKCQkJd2hpbGUoJHJvdyA9IG15c3FsaV9mZXRjaF9hc3NvYygkcmVzdWx0KSkgewoJCQkJJG15X3BhY2thZ2VzW10gPSAkdW5pdF9wYWNrYWdlc1skcm93WydpZCddXTsKCQkJCWlmKGluX2FycmF5KCRyb3dbJ2NvbG9yJ10sICRjYXJiX2NvbG9ycykpICRteV9jYXJiW10gPSAkcm93WydpZCddOyAKCQkJCWlmKGluX2FycmF5KCRyb3dbJ2NvbG9yJ10sICRjbGFzdF9jb2xvcnMpKSAkbXlfY2xhc3RbXSA9ICRyb3dbJ2lkJ107IAoJCQkJJG15X2NvbHVtbnNbXSA9ICRyb3dbJ2NvbF9pZCddOwoJCQl9CgkJCSRuX3VuaXRzX3RvdGFsID0gbXlzcWxpX251bV9yb3dzKCRyZXN1bHQpOwoJCQkkbl9wYWNrYWdlc190b3RhbCA9IGNvdW50KGFycmF5X3VuaXF1ZSgkbXlfcGFja2FnZXMpKTsKCQkJJG5fY29sdW1uc190b3RhbCA9IGNvdW50KGFycmF5X3VuaXF1ZSgkbXlfY29sdW1ucykpOwoJCQlteXNxbGlfZnJlZV9yZXN1bHQoJHJlc3VsdCk7CgkJCXVuc2V0KCRteV9wYWNrYWdlcywgJG15X2NvbHVtbnMpOwoJCQkKCQkJLy8gbG9vcCB0aHJvdWdoIGVhY2ggcGFja2FnZSBhbmQgY291bnQgdHJ1bmNhdGlvbnMKCQkJJHRydW5jYXRpbmdfcGFja2FnZXMgPSBhcnJheSgpOwoJCQkkc3Bhbm5pbmdfcGFja2FnZXMgPSBhcnJheSgpOwoJCQlmb3IoJGs9MDsgJGs8Y291bnQoJG15X3BrZyk7ICsrJGspIHsKCQkJCS8vIHRoZSBwYWNrYWdlcyB0aGF0IHRydW5jYXRlIGluIHRoaXMgaW50ZXJ2YWwKCQkJCWlmKCRteV9wa2dfbG9bJGtdPCRpbnRfYm90dG9tWyRpXSAmJiAkbXlfcGtnX2xvWyRrXT49JGludF90b3BbJGldKSB7CgkJCQkJJHRydW5jYXRpbmdfcGFja2FnZXNbXSA9ICRrOwoJCQkJLy8gbm9uLXRydW5jYXRpbmcgcGFja2FnZXMKCQkJCX0gZWxzZSBpZigkbXlfcGtnX2xvWyRrXTwkaW50X2JvdHRvbVskaV0gJiYgJG15X3BrZ19mb1ska10+JGludF90b3BbJGldKSB7CgkJCQkJJHNwYW5uaW5nX3BhY2thZ2VzW10gPSAkazsKCQkJCX0KCQkJfQoJCQkKCQkJLy8gbG9vcCB0aHJvdWdoIGVhY2ggb2NjdXJyZW5jZSBpbiB0aGlzIGludGVydmFsIGFuZCBnZXQgdGhvc2UgdGhhdCBvY2N1ciBpbiB0aGlzIGludGVydmFsCgkJCSRpbnRlcnZhbF9nZW51cyA9IGFycmF5KCk7CgkJCWZvcigkaz0wOyAkazxjb3VudCgkaW50X29jY3VycmVuY2VzWyRpXSk7ICsrJGspIHsKCQkJCSRpbnRlcnZhbF9nZW51c1skbXlfb2NjdXJyZW5jZXNbJGtdWyd0YXhvbl9ubyddXVtdID0gJG15X29jY3VycmVuY2VzWyRrXTsKCQkJfQoJCQkkdGhpc19nZW51cyA9IGFycmF5X2tleXMoJGludGVydmFsX2dlbnVzKTsKCQkJCi8vCQkJZm9yKCRqPTA7ICRqIDwgMTAwOyArKyRqKSB7CgkJCWZvcigkaj0wOyAkajxjb3VudCgkaW50ZXJ2YWxfZ2VudXMpOyArKyRqKSB7CQkKCQkJCQoJCQkJJG5vYW1fb2NjdXJyZW5jZXMgPSBhcnJheSgpOwoJCQkJJG5vYW1fY29sbGVjdGlvbnMgPSBhcnJheSgpOwoJCQkJJG5vYW1fdW5pdHMgPSBhcnJheSgpOwoJCQkJJG5vYW1fY29sdW1ucyA9IGFycmF5KCk7CgkJCQkkbm9hbV9wYWNrYWdlcyA9IGFycmF5KCk7CgkJCQkkbm9hbV9zcGVjaWVzID0gYXJyYXkoKTsKCQkJCSRub2FtX3BhbGVvbGF0ID0gYXJyYXkoKTsKCQkJCSRub2FtX3BhbGVvbG5nID0gYXJyYXkoKTsKCQkJCSRtYXRjaGVkX3VuaXRfbl80NSA9IGFycmF5KCk7CgkJCQkkbWF0Y2hlZF91bml0X3NfNDUgPSBhcnJheSgpOwoJCQkJJHVuaXRfcGFsZW9sYXQgPSBhcnJheSgpOwoJCQkJJHVuaXRfcGFsZW9sbmcgPSBhcnJheSgpOwoKCQkJCSRnbG9iYWxfb2NjdXJyZW5jZXMgPSBhcnJheSgpOwoJCQkJJGdsb2JhbF9jb2xsZWN0aW9ucyA9IGFycmF5KCk7CgkJCQkkZ2xvYmFsX3NwZWNpZXMgPSBhcnJheSgpOwoJCQkJJGdsb2JhbF9wYWxlb2xhdCA9IGFycmF5KCk7CgkJCQkkZ2xvYmFsX3BhbGVvbG5nID0gYXJyYXkoKTsKCQkJCQoJCQkJaWYoJG15X2dlbnVzX2FnZVskdGhpc19nZW51c1skal1dWydnbG9iYWxfbWF4J108PSRpbnRfYm90dG9tWyRpXSAmJiAkbXlfZ2VudXNfYWdlWyR0aGlzX2dlbnVzWyRqXV1bJ2dsb2JhbF9taW4nXT4kaW50X3RvcFskaV0pICRnbG9iYWxfZW5kZW1pY190b19pbnRlcnZhbCA9IDE7CgkJCQllbHNlICRnbG9iYWxfZW5kZW1pY190b19pbnRlcnZhbCA9IDA7CgkJCQkKCQkJCWZvcigkaz0wOyAkazxjb3VudCgkaW50ZXJ2YWxfZ2VudXNbJHRoaXNfZ2VudXNbJGpdXSk7ICsrJGspIHsKCQkJCQkkcm93ID0gJGludGVydmFsX2dlbnVzWyR0aGlzX2dlbnVzWyRqXV1bJGtdOwoJCgkJCQkJaWYoJHJvd1sndW5pdF9pZCddPT0wIHx8IGluX2FycmF5KCRyb3dbJ3VuaXRfaWQnXSwgJGFsbF91bml0c19hcnJheSk9PT1GQUxTRSB8fCAoJHJvd1sndW5pdF9pZCddPjAgJiYgKCRteV9nZW51c19hZ2VbJHJvd1sndGF4b25fbm8nXV1bJ3BiZGJfbWluJ10gPCA0NDMuNyAmJiAkcm93Wyd0b3AnXSA8IDQ0My43KSB8fCAkcm93Wyd0b3AnXSA+PSA0NDMuNykpIHsKCQkJCQkJJGdsb2JhbF9vY2N1cnJlbmNlc1tdID0gJHJvd1snb2NjdXJyZW5jZV9ubyddOwoJCQkJCQkkZ2xvYmFsX2NvbGxlY3Rpb25zW10gPSAkcm93Wydjb2xsZWN0aW9uX25vJ107CgkJCQkJCWlmKGlzX251bWVyaWMoJHJvd1sncGFsZW9sYXQnXSkgJiYgaXNfbnVtZXJpYygkcm93WydwYWxlb2xuZyddKSkgewoJCQkJCQkJJGdsb2JhbF9wYWxlb2xhdFtdID0gJHJvd1sncGFsZW9sYXQnXTsKCQkJCQkJCSRnbG9iYWxfcGFsZW9sbmdbXSA9ICRyb3dbJ3BhbGVvbG5nJ107CgkJCQkJCX0KCQkJCQkJJG15X2NvbGxlY3Rpb25zW10gPSAkcm93Wydjb2xsZWN0aW9uX25vJ107CgkJCQkJCQoJCQkJCQlpZigkcm93WydvcmlnaW5hbF90YXhvbl9yYW5rJ109PSdzcGVjaWVzJykgJGdsb2JhbF9zcGVjaWVzW10gPSAkcm93WydvcmlnaW5hbF90YXhvbl9ubyddOwoJCQkJCQkKCQkJCQkJaWYoJHJvd1sndW5pdF9pZCddPjAgJiYgaW5fYXJyYXkoJHJvd1sndW5pdF9pZCddLCAkYWxsX3VuaXRzX2FycmF5KSkgewoJCQkJCQkJJG5vYW1fb2NjdXJyZW5jZXNbXSA9ICRyb3dbJ29jY3VycmVuY2Vfbm8nXTsKCQkJCQkJCSRub2FtX2NvbGxlY3Rpb25zW10gPSAkcm93Wydjb2xsZWN0aW9uX25vJ107CgkJCQkJCQkkbm9hbV91bml0c1tdID0gJHJvd1sndW5pdF9pZCddOwoJCQkJCQkJJG5vYW1fY29sdW1uc1tdID0gJHJvd1snY29sX2lkJ107CgkJCQkJCQlpZigkcm93WydvcmlnaW5hbF90YXhvbl9yYW5rJ109PSdzcGVjaWVzJykgJG5vYW1fc3BlY2llc1tdID0gJHJvd1snb3JpZ2luYWxfdGF4b25fbm8nXTsKCQkJCQkJCSRub2FtX3BhbGVvbGF0W10gPSAkcm93WydwYWxlb2xhdCddOwoJCQkJCQkJJG5vYW1fcGFsZW9sbmdbXSA9ICRyb3dbJ3BhbGVvbG5nJ107CgkJCQkJCQlpZigkcm93WydwYWxlb2xhdCddPj0gNDUpICRtYXRjaGVkX3VuaXRfbl80NVtdID0gJHJvd1sndW5pdF9pZCddOwoJCQkJCQkJaWYoJHJvd1sncGFsZW9sYXQnXTw9IC00NSkgJG1hdGNoZWRfdW5pdF9zXzQ1W10gPSAkcm93Wyd1bml0X2lkJ107CgkJCQkJCQkKCQkJCQkJCWlmKGlzX251bWVyaWMoJHJvd1sncGFsZW9sYXQnXSkgJiYgaXNfbnVtZXJpYygkcm93WydwYWxlb2xuZyddKSkgewoJCQkJCQkJCSR1bml0X3BhbGVvbGF0WyRyb3dbJ3VuaXRfaWQnXV1bXSA9ICRyb3dbJ3BhbGVvbGF0J107IC8vZWNobyAkcm93WydwYWxlb2xhdCddLiI8YnI+IjsKCQkJCQkJCQkkdW5pdF9wYWxlb2xuZ1skcm93Wyd1bml0X2lkJ11dW10gPSAkcm93WydwYWxlb2xuZyddOwoJCQkJCQkJfQoJCQkJCQkJCgkJCQkJCQkkbm9hbV9wYWNrYWdlc1tdID0gJHVuaXRfcGFja2FnZXNbJHJvd1sndW5pdF9pZCddXTsKCQkJCQkJfQoJCQkJCX0KCQkJCX0KCQkJCSRuX29jY3VyID0gY291bnQoYXJyYXlfdW5pcXVlKCRub2FtX29jY3VycmVuY2VzKSk7CgkJCQkkbl9jb2xsID0gY291bnQoYXJyYXlfdW5pcXVlKCRub2FtX2NvbGxlY3Rpb25zKSk7CgkJCQkkbm9hbV91bml0cyA9IGFycmF5X3VuaXF1ZSgkbm9hbV91bml0cyk7CgkJCQkkbl91bml0cyA9IGNvdW50KCRub2FtX3VuaXRzKTsKCQkJCQoJCQkJaWYoJG5fdW5pdHM+MCkgewoJCQkJCSRub2FtX3VuaXRzID0gYXJyYXlfY29tYmluZShyYW5nZSgwLCRuX3VuaXRzLTEsMSksICRub2FtX3VuaXRzKTsKCQkJCQkkbl9jb2xzID0gY291bnQoYXJyYXlfdW5pcXVlKCRub2FtX2NvbHVtbnMpKTsKCQkJCQkkbl9zcGVjaWVzID0gY291bnQoYXJyYXlfdW5pcXVlKCRub2FtX3NwZWNpZXMpKTsKCQkJCQkkbl9wYWNrYWdlcyA9IGNvdW50KGFycmF5X3VuaXF1ZSgkbm9hbV9wYWNrYWdlcykpOwovLwkJCQkJcHJpbnRfcigkbm9hbV9jb2x1bW5zKTsgZWNobyAiIC0gJG5fY29sczxicj48YnI+IjsKCQkJCQkKCQkJCQlpZihjb3VudCgkbXlfY2FyYik+MCkgJG5fY2FyYl91bml0c19vY2N1cGllZCA9IGNvdW50KGFycmF5X3VuaXF1ZShhcnJheV9pbnRlcnNlY3QoJG15X2NhcmIsICRub2FtX3VuaXRzKSkpOwoJCQkJCWVsc2UgJG5fY2FyYl91bml0c19vY2N1cGllZCA9IDA7CgkJCQkJaWYoY291bnQoJG15X2NsYXN0KT4wKSAkbl9zaWxpY2ljbGFzdGljX3VuaXRzX29jY3VwaWVkID0gY291bnQoYXJyYXlfdW5pcXVlKGFycmF5X2ludGVyc2VjdCgkbXlfY2xhc3QsICRub2FtX3VuaXRzKSkpOwoJCQkJCSRuX3NpbGljaWNsYXN0aWNfdW5pdHNfb2NjdXBpZWQgPSAwOwoJCQkJCQoJCQkJCSRuX29jY3VyX2dsb2JhbCA9IGNvdW50KGFycmF5X3VuaXF1ZSgkZ2xvYmFsX29jY3VycmVuY2VzKSk7CgkJCQkJJG5fY29sbF9nbG9iYWwgPSBjb3VudChhcnJheV91bmlxdWUoJGdsb2JhbF9jb2xsZWN0aW9ucykpOwoJCQkJCSRuX3NwZWNpZXNfZ2xvYmFsID0gY291bnQoYXJyYXlfdW5pcXVlKCRnbG9iYWxfc3BlY2llcykpOwoJCQkJCSRuX21hdGNoZWRfdW5pdHNfZ3JlYXRlcl9uXzQ1ID0gY291bnQoYXJyYXlfdW5pcXVlKCRtYXRjaGVkX3VuaXRfbl80NSkpOwoJCQkJCSRuX21hdGNoZWRfdW5pdHNfZ3JlYXRlcl9zXzQ1ID0gY291bnQoYXJyYXlfdW5pcXVlKCRtYXRjaGVkX3VuaXRfc180NSkpOwoJCQkJCQoJCQkJCSR0ZW1wX3RheG9uX25vID0gYXJyYXlfa2V5cygkaW50X3BhbGVvbGF0WyRpXSk7CgkJCQkJJG1heF9wYWxlb2xhdF9OID0gJ05BJzsKCQkJCQkgbWF4X3BhbGVvbGF0X1MgPSAnTkEnOwoJCQkJCWZvcigkaz0wOyAkazxjb3VudCgkaW50X3BhbGVvbGF0WyRpXSk7ICsrJGspIHsKCQkJCQkJaWYoJHRlbXBfdGF4b25fbm9bJGtdID09ICRyb3dbJ3RheG9uX25vJ10pIHsKCQkJCQkJCSRtYXhfcGFsZW9sYXRfTiA9IG1heCgkaW50X3BhbGVvbGF0WyRpXVskcm93Wyd0YXhvbl9ubyddXSk7CgkJCQkJCQkkbWF4X3BhbGVvbGF0X1MgPSBtaW4oJGludF9wYWxlb2xhdFskaV1bJHJvd1sndGF4b25fbm8nXV0pOwoJCQkJCQl9CgkJCQkJfQoJCQkJCQoJCQkJCS8vIGdldCBtYXRjaGVkIGdyZWF0IGNpcmNsZSBkaXN0YW5jZQoJCQkJCS8vICBzZXQgdXAgZmlsZSBmb3Igc2VuZGluZyB0byBSIGZvciBncmVhdCBjaXJjbGUgYW5hbHlzaXMKCQkJCQkkY2lyY2xlX2ZpbGUgPSAibm9hbV9ncmVhdF9jaXJjbGUuY3N2IjsKCQkJCQkkZmgyID0gZm9wZW4oJGNpcmNsZV9maWxlLCAndycpIG9yIGRpZSgiY2FuJ3Qgb3BlbiBmaWxlIik7CgkJCQkJY2htb2QoJGNpcmNsZV9maWxlLCAwNjY2KTsKCQkJCQkkZmlsZV9yb3cgPSAicGxhdCwgcGxuZywgdW5pdF9pZFxuIjsKCQkJCQlmd3JpdGUoJGZoMiwgJGZpbGVfcm93KTsKCQkJCQlmb3IoJGs9MDsgJGs8Y291bnQoJHVuaXRfcGFsZW9sYXQpOyArKyRrKSB7CgkJCQkJCWlmKGlzc2V0KCR1bml0X3BhbGVvbGF0WyRub2FtX3VuaXRzWyRrXV0pICYmIGlzc2V0KCR1bml0X3BhbGVvbG5nWyRub2FtX3VuaXRzWyRrXV0pKSB7CgkJCQkJCQkkdW5pdF9tZWFuX2xhdCA9IGFycmF5X3N1bSgkdW5pdF9wYWxlb2xhdFskbm9hbV91bml0c1ska11dKS9jb3VudCgkdW5pdF9wYWxlb2xhdFskbm9hbV91bml0c1ska11dKTsKCQkJCQkJCSR1bml0X21lYW5fbG5nID0gYXJyYXlfc3VtKCR1bml0X3BhbGVvbG5nWyRub2FtX3VuaXRzWyRrXV0pL2NvdW50KCR1bml0X3BhbGVvbG5nWyRub2FtX3VuaXRzWyRrXV0pOwoJCQkJCQkJaWYoaXNfbnVsbCgkdW5pdF9tZWFuX2xhdCk9PT1GQUxTRSAmJiBpc19udWxsKCR1bml0X21lYW5fbG5nKT09PUZBTFNFKSB7CgkJCQkJCQkJJGZpbGVfcm93PSIkdW5pdF9tZWFuX2xhdCwkdW5pdF9tZWFuX2xuZywkbm9hbV91bml0c1ska11cbiI7CgkJCQkJCQkJZndyaXRlKCRmaDIsICRmaWxlX3Jvdyk7CgkJCQkJCQl9CgkJCQkJCX0gZWxzZSB7CgkJCQkJCQllY2hvICJwYWxlbyBjb29yZHMgbm90IHByb3Blcmx5IHNldDxicj4iOwoJCQkJCQl9CgkJCQkJfQoJCQkJCWZjbG9zZSgkZmgyKTsgCgkJCQkJCgkJCQkJaWYoJG5fdW5pdHM+MSkgewoJCQkJCQkkZmlsZV9uYW1lX3IgPSAndGVtcC5yJzsKCQkJCQkJJGZoMyA9IGZvcGVuKCRmaWxlX25hbWVfciwgJ3cnKSBvciBkaWUoImNhbid0IG9wZW4gZmlsZSIpOwoJCQkJCQljaG1vZCgkZmlsZV9uYW1lX3IsIDA2NjYpOwoJCQkJCQkkcl9zY3JpcHQgPSAiCgkJCQkJCXNvdXJjZSgnbXlGdW5jdGlvbnMucicpCgkJCQkJCWNvb3JkcyA8LSByZWFkLmNzdihmaWxlPSckY2lyY2xlX2ZpbGUnLCBoZWFkZXI9VFJVRSkKCQkJCQkJaWYobnJvdyh1bmlxdWUoY29vcmRzWywxOjJdKSk+MSkgewoJCQkJCQkJbWF4LmRpc3QgPC0gbWF4KGdyZWF0LmNpcmNsZTIoY29vcmRzWywxOjJdKSwgbmEucm09VFJVRSkKCQkJCQkJfSBlbHNlIHsKCQkJCQkJCW1heC5kaXN0IDwtICdOQScKCQkJCQkJfQoJCQkJCQl3cml0ZS50YWJsZShtYXguZGlzdCwgZmlsZT0ndGVtcF9kaXN0LmNzdicsIHF1b3RlPUZBTFNFLCByb3cubmFtZXM9RkFMU0UsIGNvbC5uYW1lcz1GQUxTRSwgc2VwPScsJykKCQkJCQkJIjsKCQkJCQkJZndyaXRlKCRmaDMsICRyX3NjcmlwdCk7CgkJCQkJCWZjbG9zZSgkZmgzKTsKCQkJCQkJJGNtZCA9ICJlY2hvICdyc2NyaXB0IDwtIFwiJGZpbGVfbmFtZV9yXCI7IHNvdXJjZShyc2NyaXB0KScgfCAiIC4gIi91c3IvYmluL1IgLS1zbGF2ZSAyPiYxIjsKCQkJCQkJZXhlYygkY21kLCAkcl9yYW4pOyAKCQkJCQkJaWYoY291bnQoJHJfcmFuKT4wKSB7CgkJCQkJCQllY2hvICJSIChNYXRjaGVkIGdyZWF0IGNpcmNsZSk6ICI7CgkJCQkJCQlwcmludF9yKCRyX3Jhbik7IGVjaG8gIjxicj4iOwoJCQkJCQl9CgkJCQkJCSRoYW5kbGUgPSBmb3BlbigidGVtcF9kaXN0LmNzdiIsICJyIik7CgkJCQkJCXdoaWxlICgkcm93ID0gZmdldGNzdigkaGFuZGxlLCAxMDAwLCAiLCIpKSAkbWF4X2Rpc3Rfbm9hbSA9ICRyb3dbMF07CgkJCQkJCWZjbG9zZSgkaGFuZGxlKTsKCQkJCQkJaWYoJG1heF9kaXN0X25vYW09PSdOQScpIHsKCQkJCQkJCSRoYW5kbGUgPSBmb3BlbigkY2lyY2xlX2ZpbGUsICJyIik7CgkJCQkJCQllY2hvICRtYXhfZGlzdF9ub2FtLiI8YnI+IjsKCQkJCQkJCXdoaWxlICgkZmlsZV9yb3cgPSBmZ2V0Y3N2KCRoYW5kbGUsIDEwMDAsICIsIikpIHsKCQkJCQkJCQlwcmludF9yKCRmaWxlX3Jvdyk7IGVjaG8gIjxicj4iOwoJCQkJCQkJfQoJCQkJCQkJcHJpbnRfcigkbm9hbV91bml0cyk7ZWNobyAiPGJyPiI7CgkJCQkJCQlwcmludF9yKCRub2FtX2NvbGxlY3Rpb25zKTtlY2hvICI8YnI+PGJyPiI7CgkJCQkJCQlmY2xvc2UoJGhhbmRsZSk7CgkJCQkJCX0KCQkJCQl9IGVsc2UgewoJCQkJCQkkbWF4X2Rpc3Rfbm9hbT0nTkEnOwoJCQkJCX0KCQkJCQkJCQoJCQkJCS8vIGdldCBnbG9iYWwgZ3JlYXQgY2lyY2xlIGRpc3RhbmNlCQkJCQoJCQkJCWlmKGNvdW50KCRnbG9iYWxfcGFsZW9sYXQpPjEgJiYgY291bnQoJGdsb2JhbF9wYWxlb2xuZyk9PWNvdW50KCRnbG9iYWxfcGFsZW9sYXQpKSB7CgkJCQkJCS8vICBzZXQgdXAgZmlsZSBmb3Igc2VuZGluZyB0byBSIGZvciBncmVhdCBjaXJjbGUgYW5hbHlzaXMKCQkJCQkJJGNpcmNsZV9maWxlID0gImdsb2JhbF9ncmVhdF9jaXJjbGUuY3N2IjsKCQkJCQkJJGZoMiA9IGZvcGVuKCRjaXJjbGVfZmlsZSwgJ3cnKSBvciBkaWUoImNhbid0IG9wZW4gZmlsZSIpOwoJCQkJCQljaG1vZCgkY2lyY2xlX2ZpbGUsIDA2NjYpOwoJCQkJCQkkZmlsZV9yb3cgPSAicGxhdCwgcGxuZ1xuIjsKCQkJCQkJZndyaXRlKCRmaDIsICRmaWxlX3Jvdyk7CgkJCQkJCQoJCQkJCQlmb3IoJGs9MDsgJGs8Y291bnQoJGdsb2JhbF9wYWxlb2xhdCk7ICsrJGspIHsKCQkJCQkJCSRmaWxlX3Jvdz0kZ2xvYmFsX3BhbGVvbGF0WyRrXS4iLCIuJGdsb2JhbF9wYWxlb2xuZ1ska10uIlxuIjsKCQkJCQkJCWZ3cml0ZSgkZmgyLCAkZmlsZV9yb3cpOwoJCQkJCQl9CgkJCQkJCWZjbG9zZSgkZmgyKTsKCQkJCQkKCQkJCQkJJGZpbGVfbmFtZV9yID0gJ3RlbXAucic7CgkJCQkJCSRmaDMgPSBmb3BlbigkZmlsZV9uYW1lX3IsICd3Jykgb3IgZGllKCJjYW4ndCBvcGVuIGZpbGUiKTsKCQkJCQkJY2htb2QoJGZpbGVfbmFtZV9yLCAwNjY2KTsKCQkJCQkJJHJfc2NyaXB0ID0gIgoJCQkJCQlzb3VyY2UoJ215RnVuY3Rpb25zLnInKQoJCQkJCQljb29yZHMgPC0gcmVhZC5jc3YoZmlsZT0nJGNpcmNsZV9maWxlJywgaGVhZGVyPVRSVUUpCgkJCQkJCWlmKG5yb3codW5pcXVlKGNvb3JkcykpPjEpIHsKCQkJCQkJCW1heC5kaXN0IDwtIG1heChncmVhdC5jaXJjbGUyKGNvb3JkcyksIG5hLnJtPVRSVUUpCgkJCQkJCX0gZWxzZSB7CgkJCQkJCQltYXguZGlzdCA8LSAnTkEnCgkJCQkJCX0JCgkJCQkJCXdyaXRlLnRhYmxlKG1heC5kaXN0LCBmaWxlPSd0ZW1wX2Rpc3QuY3N2JywgcXVvdGU9RkFMU0UsIHJvdy5uYW1lcz1GQUxTRSwgY29sLm5hbWVzPUZBTFNFLCBzZXA9JywnKQoJCQkJCQkiOwoJCQkJCQlmd3JpdGUoJGZoMywgJHJfc2NyaXB0KTsKCQkJCQkJZmNsb3NlKCRmaDMpOwoJCQkJCQkkY21kID0gImVjaG8gJ3JzY3JpcHQgPC0gXCIkZmlsZV9uYW1lX3JcIjsgc291cmNlKHJzY3JpcHQpJyB8ICIgLiAiL3Vzci9iaW4vUiAtLXNsYXZlIDI+JjEiOwoJCQkJCQlleGVjKCRjbWQsICRyX3Jhbik7IAoJCQkJCQlpZihjb3VudCgkcl9yYW4pPjApIHsKCQkJCQkJCWVjaG8gIlIgKEdsb2JhbCBncmVhdCBjaXJjbGUpOiAiOwoJCQkJCQkJcHJpbnRfcigkcl9yYW4pOyBlY2hvICI8YnI+IjsKCQkJCQkJfQoJCQkJCQkkaGFuZGxlID0gZm9wZW4oInRlbXBfZGlzdC5jc3YiLCAiciIpOwoJCQkJCQl3aGlsZSAoJHJvdyA9IGZnZXRjc3YoJGhhbmRsZSwgMTAwMCwgIiwiKSkgJG1heF9kaXN0X2dsb2JhbCA9ICRyb3dbMF07CgkJCQkJCWZjbG9zZSgkaGFuZGxlKTsKCQkJCQl9IGVsc2UgewoJCQkJCQkkbWF4X2Rpc3RfZ2xvYmFsID0gJ05BJzsKCQkJCQl9CgkJCQkJCgkJCQkJJG5fZW52X3RlbXAgPSBhcnJheSgpOwoJCQkJCSRuX2Vudl90ZW1wMiA9IGFycmF5KCk7CgkJCQkJCgkJCQkJLy8gZ2V0IHN0cmF0aWdyYXBoaWMgZ2FwIGR1cmF0aW9uCgkJCQkJaWYoJG5fcGFja2FnZXM+MCkgewoJCQkJCQkkcGtnX29jY3VwaWVkID0gYXJyYXlfY29tYmluZShyYW5nZSgwLCRuX3BhY2thZ2VzLTEpLCBhcnJheV91bmlxdWUoJG5vYW1fcGFja2FnZXMpKTsKCQkJCQkJJHRydW5jX3RlbXAgPSBhcnJheV9pbnRlcnNlY3QoJHRydW5jYXRpbmdfcGFja2FnZXMsIGFycmF5X3VuaXF1ZSgkbm9hbV9wYWNrYWdlcykpOwoJCQkJCQkkbl90cnVuY19wYWNrYWdlc19vY2N1cGllZCA9IGNvdW50KCR0cnVuY190ZW1wKTsKCQkJCQkJaWYoJG5fdHJ1bmNfcGFja2FnZXNfb2NjdXBpZWQ+MCkgewoJCQkJCQkJJHRydW5jX3RlbXAgPSBhcnJheV9jb21iaW5lKHJhbmdlKDAsJG5fdHJ1bmNfcGFja2FnZXNfb2NjdXBpZWQtMSwxKSwgJHRydW5jX3RlbXApOwoJCQkJCQkJLy8gZ2V0IG4gdHJ1bmNhdGluZyBjb2x1bW5zCgkJCQkJCQkkdHJ1bmNfdGVtcF9jb2x1bW5zID0gYXJyYXkoKTsKCQkJCQkJCWZvcigkaz0wOyAkazwkbl90cnVuY19wYWNrYWdlc19vY2N1cGllZDsgKyskaykgewoJCQkJCQkJCSR0cnVuY190ZW1wX2NvbHVtbnNbXSA9ICRteV9wa2dfY29sX2lkWyR0cnVuY190ZW1wWyRrXV07CgkJCQkJCQl9CgkJCQkJCQkkbl90cnVuY19jb2x1bW5zX29jY3VwaWVkID0gY291bnQoYXJyYXlfdW5pcXVlKCR0cnVuY190ZW1wX2NvbHVtbnMpKTsKCQkJCQkJfSBlbHNlIHsKCQkJCQkJCSRuX3RydW5jX2NvbHVtbnNfb2NjdXBpZWQgPSAwOwoJCQkJCQl9CgkJCQkJCQoJCQkJCQlpZigkbl90cnVuY19wYWNrYWdlc19vY2N1cGllZD4xKSB7CgkJCQkJCQkkdHJ1bmNfcGFja2FnZXNfb2NjdXBpZWQgPSBhcnJheV9jb21iaW5lKHJhbmdlKDAsKCRuX3RydW5jX3BhY2thZ2VzX29jY3VwaWVkLTEpLDEpLCAkdHJ1bmNfdGVtcCk7CgkJCQkJCQkvL3ByaW50X3IoJHRydW5jX3RlbXApOyBlY2hvICI8YnI+IjsKCQkJCQkJCS8vcHJpbnRfcigkdHJ1bmNfcGFja2FnZXNfb2NjdXBpZWQpOyBlY2hvICI8YnI+IjsKCQkJCQkJCQoJCQkJCQkJJHRlbXBfZ2FwID0gYXJyYXkoKTsKCQkJCQkJCWZvcigkeno9MDsgJHp6PCRuX3RydW5jX3BhY2thZ2VzX29jY3VwaWVkOyArKyR6eikgewoJCQkJCQkJCSR0ZW1wX2dhcFtdID0gJG15X3BrZ19nYXAyWyR0cnVuY19wYWNrYWdlc19vY2N1cGllZFskenpdXTsKCQkJCQkJCX0KCQkJCQkJCQoJCQkJCQkJc29ydCgkdGVtcF9nYXApOwoJCQkJCQkJLy9wcmludF9yKCR0ZW1wX2dhcCk7IGVjaG8gIjxicj48YnI+IjsKCQkJCQkJCSRtYXhfZ2FwID0gbWF4KCR0ZW1wX2dhcCk7CgkJCQkJCQkkbWluX2dhcCA9IG1pbigkdGVtcF9nYXApOwoJCQkJCQkJJG1lYW5fZ2FwID0gYXJyYXlfc3VtKCR0ZW1wX2dhcCkvJG5fdHJ1bmNfcGFja2FnZXNfb2NjdXBpZWQ7CgkJCQkJCQkKCQkJCQkJCSRoID0gaW50dmFsKCRuX3RydW5jX3BhY2thZ2VzX29jY3VwaWVkLzIpOwoJCQkJCQkJaWYoJG5fdHJ1bmNfcGFja2FnZXNfb2NjdXBpZWQgJSAyID09IDApIHsgCgkJCQkJCQkJJG1lZGlhbl9nYXAgPSAoJHRlbXBfZ2FwWyRoXSArICR0ZW1wX2dhcFskaC0xXSkvMjsgCgkJCQkJCQl9IGVsc2UgeyAKCQkJCQkJCQkkbWVkaWFuX2dhcCA9ICR0ZW1wX2dhcFskaF07IAoJCQkJCQkJfQoJCQkJCQl9IGVsc2UgaWYoJG5fdHJ1bmNfcGFja2FnZXNfb2NjdXBpZWQ9PTEpIHsKCQkJCQkJCSR0cnVuY19wYWNrYWdlc19vY2N1cGllZCA9IGFycmF5X2NvbWJpbmUocmFuZ2UoMCwoJG5fdHJ1bmNfcGFja2FnZXNfb2NjdXBpZWQtMSksMSksICR0cnVuY190ZW1wKTsgLy8gcmV0dXJucyBwYWNrYWdlIGtleXMKCQkJCQkJCSRtYXhfZ2FwID0gJG15X3BrZ19nYXAyWyR0cnVuY19wYWNrYWdlc19vY2N1cGllZFswXV07CgkJCQkJCQkkbWluX2dhcCA9ICRtYXhfZ2FwOwoJCQkJCQkJJG1lYW5fZ2FwID0gJG1heF9nYXA7CgkJCQkJCQkkbWVkaWFuX2dhcCA9ICRtYXhfZ2FwOwoJCQkJCQl9IGVsc2UgewoJCQkJCQkJJG1heF9nYXAgPSBOVUxMOwoJCQkJCQkJJG1pbl9nYXAgPSBOVUxMOwoJCQkJCQkJJG1lYW5fZ2FwID0gTlVMTDsKCQkJCQkJCSRtZWRpYW5fZ2FwID0gTlVMTDsKCQkJCQkJfQoJCQkJCQkKCQkJCQkJCgkJCQkJCS8vIGdldCBlbnZpcm9ubWVudGFsIHRydW5jYXRpb24KCQkJCQkJZm9yKCRrPTA7ICRrPCRuX3BhY2thZ2VzOyArKyRrKSB7CgkJCQkJCQkvLyBnZXQgdW5pdCBvZiBvbGRlc3Qgb2NjdXJyZW5jZSBpbiBpbnRlcnZhbCAKCQkJCQkJCSRxID0gIlNFTEVDVCB1bml0cy5pZCwgYi5hZ2VfYm90dG9tLCB0LmFnZV90b3AsIGNvbG9yIEZST00gb2NjdXJyZW5jZXNfdGVtcDIKCQkJCQkJCUlOTkVSIEpPSU4gdW5pdHMgT04gdW5pdHMuaWQ9b2NjdXJyZW5jZXNfdGVtcDIudW5pdF9pZAoJCQkJCQkJSU5ORVIgSk9JTiBpbnRlcnZhbHMgYiBPTiBiLmlkPXVuaXRzLkZPCgkJCQkJCQlJTk5FUiBKT0lOIGludGVydmFscyB0IE9OIHQuaWQ9dW5pdHMuTE8KCQkJCQkJCVdIRVJFIHRheG9uX25vPSIuJHRoaXNfZ2VudXNbJGpdLiIgQU5EIChvY2N1cnJlbmNlc190ZW1wMi5yZWxlYXNlX2RhdGUgPD0gbm93KCkgT1Igb2NjdXJyZW5jZXNfdGVtcDIucmVsZWFzZV9kYXRlIElTIE5VTEwpIAoJCQkJCQkJQU5EIHVuaXRzLmlkIElOICgiLiRteV9wa2dbJHBrZ19vY2N1cGllZFska11dLiIpIAoJCQkJCQkJQU5EIGIuYWdlX2JvdHRvbSA+ICIuJGludF90b3BbJGldLiIgQU5EIHQuYWdlX3RvcCA8ICIuJGludF9ib3R0b21bJGldLiIgCgkJCQkJCQlHUk9VUCBCWSB1bml0cy5pZAoJCQkJCQkJT1JERVIgQlkgYi5hZ2VfYm90dG9tIERFU0MsIHVuaXRzLkZPX2gsIHQuYWdlX3RvcCBERVNDLCBmaWVsZCh1bml0cy5MT19oLCAxLDIsMyw0LDUsMCkKCQkJCQkJCUxJTUlUIDEiOyAvL2VjaG8gJHEuIjxicj4iOwoJCQkJCQkJJHJlc3VsdCA9IG15c3FsaV9xdWVyeSgkY29ubmVjdF9tYWNyb3N0cmF0LCAkcSk7CgkJCQkJCQlpZihteXNxbGlfbnVtX3Jvd3MoJHJlc3VsdCk9PTEpIHsKCQkJCQkJCQkkbWF4X3VuaXQgPSBteXNxbGlfZmV0Y2hfYXNzb2MoJHJlc3VsdCk7CgkJCQkJCQkJJG9jY3VwaWVkX3VuaXQgPSAkbWF4X3VuaXRbJ2lkJ107CgkJCQkJCQkJJG9jY3VwaWVkX2JvdHRvbSA9ICRtYXhfdW5pdFsnYWdlX2JvdHRvbSddOwoJCQkJCQkJCSRvY2N1cGllZF90b3AgPSAkbWF4X3VuaXRbJ2FnZV90b3AnXTsKCQkJCQkJCQkkb2NjdXBpZWRfY29sb3IgPSAkbWF4X3VuaXRbJ2NvbG9yJ107CgkJCQkJCQkJJG5leHRfdW5pdF90ZW1wID0gTlVMTDsKCQoJCQkJCQkJCS8vIGdldCBvbGRlc3QgdW5pdCBpbiBvdmVybHlpbmcgaW50ZXJ2YWxzIC0gbWF5IHNwYW4gaW50byBmb2NhbCBpbnRlcnZhbAkJCQkJCQkJCQoJCQkJCQkJCWlmKCRpPT0wKSB7CgkJCQkJCQkJCSRwcmV2aW91c190b3AgPSA0MTguNzsKCQkJCQkJCQkJJHByZXZpb3VzX2JvdHRvbSA9ICRzdHVkeV9tYXg7CgkJCQkJCQkJfSBlbHNlIHsKCQkJCQkJCQkJJHByZXZpb3VzX3RvcCA9ICRpbnRfdG9wWyRpLTFdOwoJCQkJCQkJCQkkcHJldmlvdXNfYm90dG9tID0gJGludF9ib3R0b21bJGktMV07IAoJCQkJCQkJCX0KCQkJCQkJCQkkcSA9ICJTRUxFQ1QgdW5pdHMuaWQsIGNvbG9yLCBMT19oLCBGT19oLCBiLmFnZV9ib3R0b20sIHQuYWdlX3RvcCBGUk9NIHVuaXRzCgkJCQkJCQkJSU5ORVIgSk9JTiBpbnRlcnZhbHMgYiBPTiBiLmlkPUZPCgkJCQkJCQkJSU5ORVIgSk9JTiBpbnRlcnZhbHMgdCBPTiB0LmlkPUxPCgkJCQkJCQkJV0hFUkUgdW5pdHMuaWQgSU4gKCIuJG15X3BrZ1skcGtnX29jY3VwaWVkWyRrXV0uIikgQU5EIGIuYWdlX2JvdHRvbT4iLiRwcmV2aW91c190b3AuIiBBTkQgdC5hZ2VfdG9wPCIuJHByZXZpb3VzX2JvdHRvbS4iIAoJCQkJCQkJCU9SREVSIEJZIGIuYWdlX2JvdHRvbSBERVNDLCBGT19oLCB0LmFnZV90b3AgREVTQywgZmllbGQoTE9faCwgMSwyLDMsNCw1LDApCgkJCQkJCQkJTElNSVQgMSI7CgkJCQkJCQkJJHRlbXBfcGtnX3Jlc3VsdCA9IG15c3FsaV9xdWVyeSgkY29ubmVjdF9tYWNyb3N0cmF0LCAkcSk7CgkJCQkJCQkJaWYobXlzcWxpX251bV9yb3dzKCR0ZW1wX3BrZ19yZXN1bHQpPjApIHsKCQkJCQkJCQkJJG5leHRfaW50X3VuaXQgPSBteXNxbGlfZmV0Y2hfYXNzb2MoJHRlbXBfcGtnX3Jlc3VsdCk7CgkJCQkJCQkJCSRuZXh0X3VuaXRfdGVtcCA9ICRuZXh0X2ludF91bml0WydpZCddOwoJCQkJCQkJCQlpZigkbmV4dF9pbnRfdW5pdFsnY29sb3InXSAhPSAkb2NjdXBpZWRfY29sb3IpIHsKCQkJCQkJCQkJCSRuX2Vudl90ZW1wW10gPSAkcGtnX29jY3VwaWVkWyRrXTsKCS8vCQkJCQkJCQkJCQllY2hvICRvY2N1cGllZF91bml0LicgJy4kb2NjdXBpZWRfY29sb3IuJyAtICcuJG5leHRfaW50X3VuaXRbJ2lkJ10uJyAnLiRuZXh0X2ludF91bml0Wydjb2xvciddLiI8YnI+IjsKCQkJCQkJCQkJfQoJCQkJCQkJCX0KCQkJCQkJCQlteXNxbGlfZnJlZV9yZXN1bHQoJHRlbXBfcGtnX3Jlc3VsdCk7CgkKCQoJCQkJCQkJCS8vIGxvb3AgdGhyb3VnaCB0aGUgdW5pdHMgd2l0aGluIHRoZSBmb2NhbCBpbnRlcnZhbCAtIG1heSBub3Qgc3BhbiBpbnRvIG92ZXJseWluZyBpbnRlcnZhbAkJCQkJCQkJCQoJCQkJCQkJCWlmKGlzX251bGwoJG5leHRfdW5pdF90ZW1wKSkgJHRlbXBfZXhjbHVkZSA9ICRvY2N1cGllZF91bml0OwoJCQkJCQkJCWVsc2UgJHRlbXBfZXhjbHVkZSA9ICRvY2N1cGllZF91bml0LiIsIi4kbmV4dF91bml0X3RlbXA7CgkJCQkJCQkJJHEgPSAiU0VMRUNUIHVuaXRzLmlkLCBjb2xvciwgTE9faCwgRk9faCwgYi5hZ2VfYm90dG9tLCB0LmFnZV90b3AgRlJPTSB1bml0cwoJCQkJCQkJCUlOTkVSIEpPSU4gaW50ZXJ2YWxzIGIgT04gYi5pZD1GTwoJCQkJCQkJCUlOTkVSIEpPSU4gaW50ZXJ2YWxzIHQgT04gdC5pZD1MTwoJCQkJCQkJCVdIRVJFIHVuaXRzLmlkIElOICgiLiRteV9wa2dbJHBrZ19vY2N1cGllZFska11dLiIpIEFORCBiLmFnZV9ib3R0b20gPiAiLiRpbnRfdG9wWyRpXS4iIEFORCB0LmFnZV90b3AgPj0gIi4kaW50X3RvcFskaV0uIgoJCQkJCQkJCUFORCBiLmFnZV9ib3R0b208PSIuJG9jY3VwaWVkX3RvcC4iIEFORCB1bml0cy5pZCBOT1QgSU4gKCIuJHRlbXBfZXhjbHVkZS4iKSAKCQkJCQkJCQlPUkRFUiBCWSBiLmFnZV9ib3R0b20gREVTQywgRk9faCwgdC5hZ2VfdG9wIERFU0MsIGZpZWxkKExPX2gsIDEsMiwzLDQsNSwwKSI7ICAvL2VjaG8gJHEuIjxicj4iOwoJCQkJCQkJCSR0ZW1wX3BrZ19yZXN1bHQgPSBteXNxbGlfcXVlcnkoJGNvbm5lY3RfbWFjcm9zdHJhdCwgJHEpOyAvL2lmKG15c3FsaV9udW1fcm93cygkdGVtcF9wa2dfcmVzdWx0KT4yKSBlY2hvICRxLiI8YnI+IjsKCQkJCQkJCQl3aGlsZSgkcGtnX3Jvdz1teXNxbGlfZmV0Y2hfYXNzb2MoJHRlbXBfcGtnX3Jlc3VsdCkpIHsKCQkJCQkJCQkJaWYoJHBrZ19yb3dbJ2NvbG9yJ10hPSRvY2N1cGllZF9jb2xvciAmJiAkcGtnX3Jvd1snYWdlX3RvcCddPCRvY2N1cGllZF90b3ApIHsKCS8vCQkJCQkJCQkJCQllY2hvICRvY2N1cGllZF91bml0LicgJy4kb2NjdXBpZWRfY29sb3IuJyAtICcuJHBrZ19yb3dbJ2lkJ10uJyAnLiRwa2dfcm93Wydjb2xvciddLiI8YnI+IjsKCQkJCQkJCQkJCWlmKCRwa2dfcm93WydhZ2VfdG9wJ10+PSRpbnRfdG9wWyRpXSkgeyAgLy8gdW5pdCBpcyBjb250YWluZWQgZW50aXJlbHkgd2l0aGluIHRoZSBpbnRlcnZhbAoJCQkJCQkJCQkJCSRuX2Vudl90ZW1wW10gPSAkcGtnX29jY3VwaWVkWyRrXTsgLy9lY2hvICRuX2Vudl90cnVuY2F0aW9uLiI8YnI+IjsKCQkJCQkJCQkJCX0gZWxzZSBpZiAoJHBrZ19yb3dbJ2FnZV90b3AnXTwkaW50X3RvcFskaV0gJiYgJHBrZ19yb3dbJ2FnZV9ib3R0b20nXT4kaW50X3RvcFskaV0pIHsgIC8vIHVuaXRzIHNwYW5zIGludGVydmFsIGJvdW5kYXJ5CgkJCQkJCQkJCQkJJG5fZW52X3RlbXBbXSA9ICRwa2dfb2NjdXBpZWRbJGtdOyAvL2VjaG8gJG5fZW52X3RydW5jYXRpb24uIjxicj4iOwoJCQkJCQkJCQkJfSAKCQkJCQkJCQkJfQoJCQkJCQkJCQlpZigkcGtnX3Jvd1snYWdlX3RvcCddPj0kaW50X3RvcFskaV0gJiYgJHBrZ19yb3dbJ2FnZV9ib3R0b20nXTw9JGludF9ib3R0b21bJGldKSAkbl9lbnZfdGVtcDJbXSA9ICRwa2dfb2NjdXBpZWRbJGtdOwoJCQkJCQkJCX0KCQkJCQkJCQlteXNxbGlfZnJlZV9yZXN1bHQoJHRlbXBfcGtnX3Jlc3VsdCk7CgkJCQkJCQkJaWYoJG9jY3VwaWVkX3RvcD49JGludF90b3BbJGldICYmICRvY2N1cGllZF9ib3R0b208PSRpbnRfYm90dG9tWyRpXSkgJG5fZW52X3RlbXAyW10gPSAkcGtnX29jY3VwaWVkWyRrXTsKCQkJCQkJCX0KCQkJCQkJCW15c3FsaV9mcmVlX3Jlc3VsdCgkcmVzdWx0KTsKCQkJCQkJfSAKCQkJCQl9CgkJCQkJCgkJCQkJJG5fZW52X3RydW5jYXRpb24gPSBjb3VudChhcnJheV91bmlxdWUoJG5fZW52X3RlbXApKTsKCQkJCQkkbl9lbnZfdHJ1bmNhdGlvbjIgPSBjb3VudCgkbl9lbnZfdGVtcCk7CgkJCQkJJG5fZW52X3RydW5jYXRpb24zID0gY291bnQoYXJyYXlfdW5pcXVlKCRuX2Vudl90ZW1wMikpOyAKCS8vCQkJCWlmKCRuX2Vudl90cnVuY2F0aW9uPjApIHtwcmludF9yKCRuX2Vudl90ZW1wKTsgZWNobyAiPGJyPjxicj4iO30KCQoJCQkJCS8vIHRhYnVsYXRlIGVudmlyb25tZW50YWwgZ2FwIGxlbmd0aAoJCQkJCSRlbnZfZ2FwX2NvdW50ID0gYXJyYXkoKTsKCQkJCQlpZigkbl91bml0cz4xKSB7CgkJCQkJCSRteV9vY2N1cGllZF91bml0cyA9IGFycmF5X2NvbWJpbmUocmFuZ2UoMCwkbl91bml0cy0xLDEpLCBhcnJheV91bmlxdWUoJG5vYW1fdW5pdHMpKTsKCQkJCQkJZm9yKCR6eno9MDsgJHp6ejwkbl91bml0czsgKyskenp6KSB7CgkJCQkJCQlpZigkZW52X3VuaXRfdG9wWyRteV9vY2N1cGllZF91bml0c1skenp6XV0gPj0gJGludF90b3BbJGldICYmICRlbnZfdW5pdF90b3BbJG15X29jY3VwaWVkX3VuaXRzWyR6enpdXSA8ICRpbnRfYm90dG9tWyRpXSkgewoJCQkJCQkJCSRlbnZfZ2FwX2NvdW50W10gPSAkZW52X2dhcFskbXlfb2NjdXBpZWRfdW5pdHNbJHp6el1dOwoJCQkJCQkJfQoJCQkJCQl9CgkJCQkJCXVuc2V0KCRteV9vY2N1cGllZF91bml0cyk7CgkJCQkJfSBlbHNlIGlmKCRuX3VuaXRzPT0xKSB7CgkJCQkJCSRteV9vY2N1cGllZF91bml0cyA9IGFycmF5X2NvbWJpbmUoYXJyYXkoMCksIGFycmF5X3VuaXF1ZSgkbm9hbV91bml0cykpOwoJCQkJCQlpZigkZW52X3VuaXRfdG9wWyRteV9vY2N1cGllZF91bml0c1swXV0gPj0gJGludF90b3BbJGldICYmICRlbnZfdW5pdF90b3BbJG15X29jY3VwaWVkX3VuaXRzWzBdXSA8ICRpbnRfYm90dG9tWyRpXSkgewoJCQkJCQkJJGVudl9nYXBfY291bnRbXSA9ICRlbnZfZ2FwWyRteV9vY2N1cGllZF91bml0c1swXV07CgkJCQkJCX0KCQkJCQkJdW5zZXQoJG15X29jY3VwaWVkX3VuaXRzKTsKCQkJCQl9CgkJCQkJCgkJCQkJLy8gdGFidWxhdGUgc3RhdHMKCQkJCQkkbl9lbnZfZ2FwID0gY291bnQoJGVudl9nYXBfY291bnQpOwoJCQkJCWlmKCRuX2Vudl9nYXA+MSkgewoJCQkJCQkkbWluX2Vudl9nYXA9bWluKCRlbnZfZ2FwX2NvdW50KTsKCQkJCQkJJG1heF9lbnZfZ2FwPW1heCgkZW52X2dhcF9jb3VudCk7CgkJCQkJCSRtZWFuX2Vudl9nYXA9YXJyYXlfc3VtKCRlbnZfZ2FwX2NvdW50KS8kbl9lbnZfZ2FwOwoJCQkJCQkkaCA9IGludHZhbCgkbl9lbnZfZ2FwLzIpOwoJCQkJCQlpZigkbl9lbnZfZ2FwICUgMiA9PSAwKSB7IAoJCQkJCQkJJG1lZGlhbl9lbnZfZ2FwID0gKCRlbnZfZ2FwX2NvdW50WyRoXSArICRlbnZfZ2FwX2NvdW50WyRoLTFdKS8yOyAKCQkJCQkJfSBlbHNlIHsgCgkJCQkJCQkkbWVkaWFuX2Vudl9nYXAgPSAkZW52X2dhcF9jb3VudFskaF07IAoJCQkJCQl9CQoJCQkJCX0gZWxzZSBpZigkbl9lbnZfZ2FwPT0xKSB7CgkJCQkJCSRtaW5fZW52X2dhcD0kZW52X2dhcF9jb3VudFswXTsKCQkJCQkJJG1heF9lbnZfZ2FwPSRlbnZfZ2FwX2NvdW50WzBdOwoJCQkJCQkkbWVhbl9lbnZfZ2FwPSRlbnZfZ2FwX2NvdW50WzBdOwoJCQkJCQkkbWVkaWFuX2Vudl9nYXA9JGVudl9nYXBfY291bnRbMF07CgkJCQkJfSBlbHNlIHsKCQkJCQkJJG1pbl9lbnZfZ2FwPU5VTEw7CgkJCQkJCSRtYXhfZW52X2dhcD1OVUxMOwoJCQkJCQkkbWVhbl9lbnZfZ2FwPU5VTEw7CgkJCQkJCSRtZWRpYW5fZW52X2dhcD1OVUxMOwoJCQkJCX0KCQkJCQl1bnNldCgkZW52X2dhcF9jb3VudCk7CgkJCQkJaWYoaXNzZXQoJGZpbGVfcm93KSkgdW5zZXQoJGZpbGVfcm93KTsKCQkJCQkkZmlsZV9yb3cgPSAkaW50X2lkWyRpXS4iLCIuJGludF9uYW1lWyRpXS4iLCIuJGludF9ib3R0b21bJGldLiIsIi4kaW50X3RvcFskaV0uIiwiLgoJCQkJCSRteV9nZW5lcmFbJGpdWyd0YXhvbl9ubyddLiIsIi4kbXlfZ2VuZXJhWyRqXVsnZ2VudXNfbmFtZSddLiIsIi4kbXlfZ2VuZXJhWyRqXVsnY2xhc3MnXS4iLCIuJG15X2dlbmVyYVskal1bJ3RheG9uX29yZGVyJ10uIiwiLiRteV9nZW5lcmFbJGpdWydmYW1pbHknXS4iLCIuCgkJCQkJJG15X2dlbmVyYVskal1bJ2xpZmVfaGFiaXQnXS4iLCIuJG15X2dlbmVyYVskal1bJ2xvY29tb3Rpb24nXS4iLCIuJG15X2dlbmVyYVskal1bJ3RheG9uX2Vudmlyb25tZW50J10uIiwiLiRteV9nZW5lcmFbJGpdWydkaWV0MSddLiIsIi4kbXlfZ2VuZXJhWyRqXVsnZGlldDInXS4iLCIuCgkJCQkJJG5fc3BlY2llcy4iLCIuJG5fc3BlY2llc19nbG9iYWwuIiwiLiRuX2NvbGwuIiwiLiRuX29jY3VyLiIsIi4kZ2xvYmFsX2VuZGVtaWNfdG9faW50ZXJ2YWwuIiwiLgoJCQkJCSRteV9nZW51c19hZ2VbJHRoaXNfZ2VudXNbJGpdXVsnbm9hbV9tYXgnXS4iLCIuJG15X2dlbnVzX2FnZVskdGhpc19nZW51c1skal1dWydub2FtX21pbiddLiIsIi4KCQkJCQkkbXlfZ2VudXNfYWdlWyR0aGlzX2dlbnVzWyRqXV1bJ2dsb2JhbF9tYXgnXS4iLCIuJG15X2dlbnVzX2FnZVskdGhpc19nZW51c1skal1dWydnbG9iYWxfbWluJ10uIiwiLgoJCQkJCSRtYXhfcGFsZW9sYXRfTi4iLCIuJG1heF9wYWxlb2xhdF9TLiIsIi4kbl9tYXRjaGVkX3VuaXRzX2dyZWF0ZXJfbl80NS4iLCIuJG5fbWF0Y2hlZF91bml0c19ncmVhdGVyX3NfNDUuIiwiLgoJCQkJCSRtYXhfZGlzdF9ub2FtLiIsIi4kbWF4X2Rpc3RfZ2xvYmFsLiIsIi4KCQkJCQkkbl9wYWNrYWdlcy4iLCIuJG5fcGFja2FnZXNfdG90YWwuIiwiLiRuX3VuaXRzLiIsIi4kbl91bml0c190b3RhbC4iLCIuCQkJCQkKCQkJCQljb3VudCgkbXlfY2FyYikuIiwiLmNvdW50KGFycmF5X2ludGVyc2VjdCgkbm9hbV91bml0cywgJG15X2NhcmIpKS4iLCIuY291bnQoJG15X2NsYXN0KS4iLCIuY291bnQoYXJyYXlfaW50ZXJzZWN0KCRub2FtX3VuaXRzLCAkbXlfY2xhc3QpKS4iLCIuCQkJCQkKCQkJCQljb3VudCgkdHJ1bmNhdGluZ19wYWNrYWdlcykuIiwiLmNvdW50KGFycmF5X2ludGVyc2VjdCgkbm9hbV9wYWNrYWdlcywgJHRydW5jYXRpbmdfcGFja2FnZXMpKS4iLCIuCQkJCQkKCQkJCQkkbl9lbnZfdHJ1bmNhdGlvbi4iLCIuJG5fZW52X3RydW5jYXRpb24yLiIsIi4kbl9lbnZfdHJ1bmNhdGlvbjMuIiwiLgkJCQkJCgkJCQkJJG1pbl9nYXAuIiwiLiRtYXhfZ2FwLiIsIi4kbWVhbl9nYXAuIiwiLiRtZWRpYW5fZ2FwLiIsIi4JCQkJCQoJCQkJCSRtaW5fZW52X2dhcC4iLCIuJG1heF9lbnZfZ2FwLiIsIi4kbWVhbl9lbnZfZ2FwLiIsIi4kbWVkaWFuX2Vudl9nYXAuIiwiLiRuX2Vudl9nYXAuIiwiLgkJCQkJCgkJCQkJJG5fY29scy4iLCIuJG5fY29sdW1uc190b3RhbC4iLCIuJG5fdHJ1bmNfY29sdW1uc19vY2N1cGllZC4iXG4iOwoJCQkJCWZ3cml0ZSgkZmgsICRmaWxlX3Jvdyk7CgkJCQkJdW5zZXQoJGZpbGVfcm93KTsKCQkJCX0KCQkJfQoJCX0KCQlmY2xvc2UoJGZoKTsKCQkkbXlfY29sbGVjdGlvbnMgPSBpbXBsb2RlKCIsIixhcnJheV91bmlxdWUoJG15X2NvbGxlY3Rpb25zKSk7CgkJCgkJCgkJLy8gZ2V0IHJlZmVyZW5jZXMgYW5kIGF1dGhvcml6ZXJzICYgZW50ZXJlcnMKCQkkcSA9ICJTRUxFQ1Qgb2NjdXJyZW5jZXNfdGVtcDIuY29sbGVjdGlvbl9ubywgY29sbGVjdGlvbnMucmVmZXJlbmNlX25vLCBjb2xsZWN0aW9ucy5hdXRob3JpemVyLCBjb2xsZWN0aW9ucy5lbnRlcmVyLCBjb2xsZWN0aW9ucy5tb2RpZmllciwKCQlyZWZzLmF1dGhvcjFpbml0LCByZWZzLmF1dGhvcjFsYXN0LCByZWZzLmF1dGhvcjJpbml0LCByZWZzLmF1dGhvcjJsYXN0LCByZWZzLm90aGVyYXV0aG9ycywgcmVmcy5wdWJ5ciwgcmVmcy5yZWZ0aXRsZSwgcmVmcy5wdWJ0aXRsZSwgCgkJcmVmcy5lZGl0b3JzLCByZWZzLnB1YnZvbCwgcmVmcy5maXJzdHBhZ2UsIHJlZnMubGFzdHBhZ2UsIHJlZnMucHVibGljYXRpb25fdHlwZSAKCQlGUk9NIG9jY3VycmVuY2VzX3RlbXAyCgkJSU5ORVIgSk9JTiBwYmRiLmNvbGxlY3Rpb25zIE9OIG9jY3VycmVuY2VzX3RlbXAyLmNvbGxlY3Rpb25fbm89Y29sbGVjdGlvbnMuY29sbGVjdGlvbl9ubwoJCUlOTkVSIEpPSU4gcGJkYi5yZWZzIE9OIHJlZnMucmVmZXJlbmNlX25vPWNvbGxlY3Rpb25zLnJlZmVyZW5jZV9ubwoJCVdIRVJFIGNvbGxlY3Rpb25zLmNvbGxlY3Rpb25fbm8gSU4gKCIuJG15X2NvbGxlY3Rpb25zLiIpCgkJR1JPVVAgQlkgb2NjdXJyZW5jZXNfdGVtcDIuY29sbGVjdGlvbl9ubwoJCU9SREVSIEJZIG9jY3VycmVuY2VzX3RlbXAyLmNvbGxlY3Rpb25fbm8iOyAvL2VjaG8gJHEuIjxicj48YnI+IjsKCQkkcmVzdWx0ID0gbXlzcWxpX3F1ZXJ5KCRjb25uZWN0X21hY3Jvc3RyYXQsICRxKTsJCQoJCQkJCgkJJGRhdGFfY3JlZGl0cyA9IGFycmF5KCk7CgkJJHJlZl9jcmVkaXRzID0gYXJyYXkoKTsKCQl3aGlsZSgkcm93PW15c3FsaV9mZXRjaF9hc3NvYygkcmVzdWx0KSkgewkJCgkJCQoJCQlpZihpc3NldCgkZGF0YV9jcmVkaXRzWyRyb3dbJ2F1dGhvcml6ZXInXV0pKSArKyRkYXRhX2NyZWRpdHNbJHJvd1snYXV0aG9yaXplciddXVsnYXV0aCddOwoJCQllbHNlICRkYXRhX2NyZWRpdHNbJHJvd1snYXV0aG9yaXplciddXSA9IGFycmF5KCdhdXRoJz0+IDEsICdlbnRlcicgPT4gMCwgJ21vZGlmeScgPT4gMCk7CgkJCQoJCQlpZihpc3NldCgkZGF0YV9jcmVkaXRzWyRyb3dbJ2VudGVyZXInXV0pKSArKyRkYXRhX2NyZWRpdHNbJHJvd1snZW50ZXJlciddXVsnZW50ZXInXTsKCQkJZWxzZSAkZGF0YV9jcmVkaXRzWyRyb3dbJ2VudGVyZXInXV0gPSBhcnJheSgnYXV0aCc9PiAwLCAnZW50ZXInID0+IDEsICdtb2RpZnknID0+IDApOyAKCQkJCgkJCWlmKGlzc2V0KCRkYXRhX2NyZWRpdHNbJHJvd1snbW9kaWZpZXInXV0pKSArKyRkYXRhX2NyZWRpdHNbJHJvd1snbW9kaWZpZXInXV1bJ21vZGlmeSddOwoJCQllbHNlICRkYXRhX2NyZWRpdHNbJHJvd1snbW9kaWZpZXInXV0gPSBhcnJheSgnYXV0aCc9PiAwLCAnZW50ZXInID0+IDAsICdtb2RpZnknID0+IDEpOwoJCQkKCQkJaWYoaXNzZXQoJHJlZl9jcmVkaXRzWyRyb3dbJ3JlZmVyZW5jZV9ubyddXSkpIHsKCQkJCSsrJHJlZl9jcmVkaXRzWyRyb3dbJ3JlZmVyZW5jZV9ubyddXVsnY291bnQnXTsKCQkJfSBlbHNlIHsKCQkJCSRhdXRob3JfdGVtcCA9ICRyb3dbJ2F1dGhvcjFsYXN0J10uIiwgIi4kcm93WydhdXRob3IxaW5pdCddOwoJCQkJaWYoaXNfbnVsbCgkcm93WydvdGhlcmF1dGhvcnMnXSk9PT1GQUxTRSkgewoJCQkJCSRhdXRob3JfdGVtcCA9ICRhdXRob3JfdGVtcC4nICwnLiRyb3dbJ2F1dGhvcjJpbml0J10uIiAiLiRyb3dbJ2F1dGhvcjJsYXN0J10uIiwgIi4kcm93WydvdGhlcmF1dGhvcnMnXS4iLiI7CgkJCQl9IGVsc2UgaWYoaXNfbnVsbCgkcm93WydhdXRob3IybGFzdCddKT09PUZBTFNFKSB7CgkJCQkJJGF1dGhvcl90ZW1wID0gJGF1dGhvcl90ZW1wLicgYW5kICcuJHJvd1snYXV0aG9yMmluaXQnXS4iICIuJHJvd1snYXV0aG9yMmxhc3QnXS4iLiI7CgkJCQl9CgkJCQkKCQkJCWlmKCRyb3dbJ3B1YmxpY2F0aW9uX3R5cGUnXT09J2pvdXJuYWwgYXJ0aWNsZScgfHwgJHJvd1sncHVibGljYXRpb25fdHlwZSddPT0nc2VyaWFsIG1vbm9ncmFwaCcgfHwgJHJvd1sncHVibGljYXRpb25fdHlwZSddPT0nYWJzdHJhY3QnKSB7CgkJCQkJJGZ1bGxfcmVmID0gJGF1dGhvcl90ZW1wLiIgIi4kcm93WydwdWJ5ciddLiIuICIuJHJvd1sncmVmdGl0bGUnXS4iLiAiLiRyb3dbJ3B1YnRpdGxlJ10uIiAiLiRyb3dbJ3B1YnZvbCddLiI6Ii4kcm93WydmaXJzdHBhZ2UnXS4iLSIuJHJvd1snbGFzdHBhZ2UnXTsKCQkJCX0gZWxzZSBpZiAoJHJvd1sncHVibGljYXRpb25fdHlwZSddPT0nZ3VpZGVib29rJyB8fCAkcm93WydwdWJsaWNhdGlvbl90eXBlJ109PSdib29rL2Jvb2sgY2hhcHRlcicgfHwgJHJvd1sncHVibGljYXRpb25fdHlwZSddPT0nUGguRC4gdGhlc2lzJyB8fCAkcm93WydwdWJsaWNhdGlvbl90eXBlJ109PSdNLlMuIHRoZXNpcycpIHsKCQkJCQlpZihpc19udWxsKCRyb3dbJ2VkaXRvcnMnXSkpICRlZGl0b3JfdGVtcCA9ICcnOwoJCQkJCWVsc2UgJGVkaXRvcl90ZW1wID0gJHJvd1snZWRpdG9ycyddLiIgKGVkcy4pICI7CgkJCQkJCgkJCQkJJGZ1bGxfcmVmID0gJGF1dGhvcl90ZW1wLiIgIi4kcm93WydwdWJ5ciddLiIuICIuJHJvd1sncmVmdGl0bGUnXS4iLiBJbiAiLiRlZGl0b3JfdGVtcC4iLiAiLiRyb3dbJ3B1YnRpdGxlJ10uIiAiLiRyb3dbJ2ZpcnN0cGFnZSddLiItIi4kcm93WydsYXN0cGFnZSddOwoJCQkJfSBlbHNlIHsKCQkJCQlpZihpc19udWxsKCRyb3dbJ3JlZnRpdGxlJ10pIHx8ICRyb3dbJ3JlZnRpdGxlJ109PScnKSAkdGVtcF9wdWJ0aXRsZSA9ICcnOwoJCQkJCWVsc2UgJHRlbXBfcHVidGl0bGUgPSAkcm93WydyZWZ0aXRsZSddLiIuICI7CgkJCQkJJGZ1bGxfcmVmID0gJGF1dGhvcl90ZW1wLiIgIi4kcm93WydwdWJ5ciddLiIuICIuJHRlbXBfcHVidGl0bGUuIiBVbnB1Ymxpc2hlZCBkYXRhIjsKCQkJCX0JCQkJCgkJCQkkcmVmX2NyZWRpdHNbJHJvd1sncmVmZXJlbmNlX25vJ11dID0gYXJyYXkoJ2NvdW50Jz0+IDEsICdmdWxsJyA9PiAkZnVsbF9yZWYsICd0eXBlJyA9PiAkcm93WydwdWJsaWNhdGlvbl90eXBlJ10pOwoJCQl9CgkJfQoJCW15c3FsaV9mcmVlX3Jlc3VsdCgkcmVzdWx0KTsKCQkKCQkvLyB3cml0ZSB0ZXh0IGZpbGVzCgkJJGNyZWRpdF9maWxlID0gJ2NvbGxlY3Rpb25fY3JlZGl0cy50eHQnOwoJCSRmaCA9IGZvcGVuKCRjcmVkaXRfZmlsZSwndycpOwoJCWNobW9kKCRjcmVkaXRfZmlsZSwgMDc3Nyk7CgkJJGZpbGVfcm93ID0gIm5hbWVcdGF1dGhvcml6ZWRcdGVudGVyZWRcdG1vZGlmaWVkXG4iOwoJCWZ3cml0ZSgkZmgsICRmaWxlX3Jvdyk7CgkJCgkJJG15X3Blb3BsZSA9IGFycmF5X2tleXMoJGRhdGFfY3JlZGl0cyk7CgkJZm9yKCRpPTA7ICRpPGNvdW50KCRkYXRhX2NyZWRpdHMpOyArKyRpKSB7CgkJCWlmKGlzX251bGwoJG15X3Blb3BsZVskaV0pPT09RkFMU0UgJiYgJG15X3Blb3BsZVskaV0hPScnKSB7CgkJCQkkZmlsZV9yb3cgPSAkbXlfcGVvcGxlWyRpXS4iXHQiLiRkYXRhX2NyZWRpdHNbJG15X3Blb3BsZVskaV1dWydhdXRoJ10uIlx0Ii4kZGF0YV9jcmVkaXRzWyRteV9wZW9wbGVbJGldXVsnZW50ZXInXS4iXHQiLiRkYXRhX2NyZWRpdHNbJG15X3Blb3BsZVskaV1dWydtb2RpZnknXS4iXG4iOwoJCQkJZndyaXRlKCRmaCwgJGZpbGVfcm93KTsKCQkJfQoJCX0KCQlmY2xvc2UoJGZoKTsKCQllY2hvICdGaWxlIDxhIGhyZWY9IicuJGNyZWRpdF9maWxlLiciPicuJGNyZWRpdF9maWxlLic8L2E+IHNhdmVkPEJSPic7CgkJCgkJJHJlZl9maWxlID0gJ3JlZmVyZW5jZXMudHh0JzsKCQkkZmggPSBmb3BlbigkcmVmX2ZpbGUsJ3cnKTsKCQljaG1vZCgkcmVmX2ZpbGUsIDA3NzcpOwoJCSRmaWxlX3JvdyA9ICJyZWZlcmVuY2Vfbm9cdGNpdGF0aW9uXHRuX2NvbGxlY3Rpb25zXG4iOwoJCWZ3cml0ZSgkZmgsICRmaWxlX3Jvdyk7CgkJCgkJJG15X3JlZnMgPSBhcnJheV9rZXlzKCRyZWZfY3JlZGl0cyk7CgkJZm9yKCRpPTA7ICRpPGNvdW50KCRyZWZfY3JlZGl0cyk7ICsrJGkpIHsKCQkJJGZpbGVfcm93ID0gJG15X3JlZnNbJGldLiJcdCIuJHJlZl9jcmVkaXRzWyRteV9yZWZzWyRpXV1bJ2Z1bGwnXS4iXHQiLiRyZWZfY3JlZGl0c1skbXlfcmVmc1skaV1dWydjb3VudCddLiJcbiI7CgkJCWZ3cml0ZSgkZmgsICRmaWxlX3Jvdyk7CgkJfQoJCWZjbG9zZSgkZmgpOwoJCWVjaG8gJ0ZpbGUgPGEgaHJlZj0iJy4kcmVmX2ZpbGUuJyI+Jy4kcmVmX2ZpbGUuJzwvYT4gc2F2ZWQ8QlI+JzsKCQkKCQkkY29sbF9maWxlID0gJ2NvbGxlY3Rpb25zLmNzdic7CgkJJGZoID0gZm9wZW4oJGNvbGxfZmlsZSwndycpOwoJCWNobW9kKCRjb2xsX2ZpbGUsIDA3NzcpOwoJCWZ3cml0ZSgkZmgsICRteV9jb2xsZWN0aW9ucyk7CgkJZmNsb3NlKCRmaCk7CgkJZWNobyAnRmlsZSA8YSBocmVmPSInLiRjb2xsX2ZpbGUuJyI+Jy4kY29sbF9maWxlLic8L2E+IHNhdmVkPEJSPic7Cgl9CgkKCQoJCgkvLy8vLy8vLy8vLy8vLwoJLy8KCS8vIHN0dWZmIGF0IHRoZSBlbmQKCS8vCgkvLy8vLy8vLy8vLy8vLwoJaWYoaXNzZXQoJF9QT1NUWydzdWJtaXQnXSkpIHsKCQkkdDEgPSBtaWNyb3RpbWUodHJ1ZSk7CgkJJHRpbWVfZGlmZiA9ICR0MSAtICR0MDsKCQlpZiAoJHRpbWVfZGlmZi82MCA8IDEpIHsKCQkJJGRpZmZfc2Vjb25kcyA9IHJvdW5kKCR0aW1lX2RpZmYsIDMpOwoJCQllY2hvICI8YnI+VGhpcyBwcm9jZXNzIHRvb2sgIi4kZGlmZl9zZWNvbmRzLiIgc2Vjb25kcyI7CgkJfSBlbHNlIGlmICgkdGltZV9kaWZmPj0xICYgJHRpbWVfZGlmZjwzNjAwKSB7CgkJCSRkaWZmX21pbiA9IHJvdW5kKCR0aW1lX2RpZmYvNjAsIDMpOwoJCQllY2hvICI8YnI+VGhpcyBwcm9jZXNzIHRvb2sgIi4kZGlmZl9taW4uIiBtaW51dGVzIjsKCQl9IGVsc2UgewoJCQkkZGlmZl9ob3VyID0gcm91bmQoJHRpbWVfZGlmZi8zNjAwLCAzKTsKCQkJZWNobyAiPGJyPlRoaXMgcHJvY2VzcyB0b29rICIuJGRpZmZfaG91ci4iIGhvdXJzIjsKCQl9Cgl9Cj8+CgoKPD9waHAgCglyZXF1aXJlX29uY2UoJy4uL2Zvb3Rlci5odG1sJyk7CglleGl0KCk7Cj8+