Study Area

The study area is marked in red, and is know as “The Elbow.” It is about 145 km west-northwest of Tampa Bay, Florida. The area is a popular offshore fishing area that contains contains hard bottom ridges and is hypothesized to be a paleoshoreline shaped by wave action approximately 12,000 years ago.

The three lines shown represent day-time video transects completed using a towed video camera system that flies about 2-4 meters above the seafloor. Along these transects, fish were annotated at the frame-level, and habitat was annotated every 15 seconds.

Figure S2.1

Read in and reformat data

Habitat data

Habitat was annotated every 15 seconds of video

hab<- read_csv("Data/derived/CBASS/hab.csv")
hab<- hab %>% select(-c(CBASSLat, CBASSLon, Frame_num, Substrate))
hab<- hab %>% filter(Transect!="T1")
hab<- hab %>% mutate(habitat=ifelse(test = Relief=="None", yes = "Sand", no = Relief))
hab<- hab %>% select(-Relief)
print(hab)

Fish Counts

Fish were annotated on using C-Vision’s video annotation software at the frame level. Each row is an individual fish, and we can see exactly what frame that fish was seen.

fish_annotations<- read_csv("Data/derived/CBASS/fish_annotations.csv")
print(fish_annotations)

To turn these annotations into counts, each individual fish was matched to the closest habitat observation in time, and the number of annotations for each taxa were then summed.

fish_counts<- bind_rows(mutate(match_cvision_fish2hab(merged_cvision_csv = select(filter(fish_annotations, Transect=="T3"), -Transect), video_num = filter(hab, Transect=="T3")$Vid, video_sec = filter(hab, Transect=="T3")$Sec, fps = 12, vid_length = 1, include_vid_sec = TRUE, include_framenum = FALSE), Transect="T3"),
          mutate(match_cvision_fish2hab(merged_cvision_csv = select(filter(fish_annotations, Transect=="T5"), -Transect), video_num = filter(hab, Transect=="T5")$Vid, video_sec = filter(hab, Transect=="T5")$Sec, fps = 12, vid_length = 1, include_vid_sec = TRUE, include_framenum = FALSE), Transect="T5"),
          mutate(match_cvision_fish2hab(merged_cvision_csv = select(filter(fish_annotations, Transect=="T6"), -Transect), video_num = filter(hab, Transect=="T6")$Vid, video_sec = filter(hab, Transect=="T6")$Sec, fps = 12, vid_length = 1, include_vid_sec = TRUE, include_framenum = FALSE), Transect="T6")) %>% select(Transect, everything())
fish_counts[is.na(fish_counts)]<- 0 
fish_counts<- fish_counts %>% select(Transect, Video, Seconds, everything())
names(fish_counts)[2:3]<- c("Vid", "Sec")

#Merge taxa that are difficult to differentiate consistently
fish_counts<- fish_counts %>% mutate(AMBERJACK_SPP= rowSums(across(starts_with("amberjack_", ignore.case = FALSE)))) %>% select(-starts_with("amberjack_", ignore.case = FALSE))

fish_counts<- fish_counts %>% mutate(BUTTERFLYFISH_SPP= rowSums(across(starts_with("butterflyfish_", ignore.case = FALSE))))  %>% select(-starts_with("butterflyfish_",ignore.case = FALSE))

fish_counts<- fish_counts %>% mutate(PORGY_SPP= rowSums(across(starts_with("porgy_", ignore.case = FALSE))))  %>% select(-starts_with("porgy_",ignore.case = FALSE))

fish_counts<- fish_counts %>% mutate(TRIGGERFISH_SPP= rowSums(across(starts_with("triggerfish_",ignore.case = FALSE))))  %>% select(-starts_with("triggerfish_",ignore.case = FALSE))

fish_counts<- fish_counts %>% select(-seaturtle_spp) #NOt a fish

names(fish_counts)[4:ncol(fish_counts)]<- tolower(names(fish_counts)[4:ncol(fish_counts)])
fish_counts<- fish_counts %>% select(Transect, Vid, Sec, sort_species(names(fish_counts)[4:ncol(fish_counts)]))
fish_counts<- fish_counts %>% left_join(select(hab, timestamp, Transect, Vid, Sec), by=c("Transect", "Vid", "Sec"))
fish_counts<- fish_counts %>% select(Transect, Vid, Sec, timestamp, everything())
print(fish_counts)

Raw Auxillary Data

altitude<- bind_rows<- bind_rows(mutate(read_tsv("Data/raw/CBASS/sensors/T3_D1/altimeter_readings.tsv"), Transect="T3"),
                                 mutate(read_tsv("Data/raw/CBASS/sensors/T5_D14/altimeter_readings.tsv"), Transect="T5"),
                                 mutate(read_tsv("Data/raw/CBASS/sensors/T6_D13/altimeter_readings.tsv"), Transect="T6"))
altitude<- altitude %>% mutate(timestamp_exact= timestamp+dmicroseconds(u_second))
compass<- bind_rows<- bind_rows(mutate(read_tsv("Data/raw/CBASS/sensors/T3_D1/compass_readings.tsv"), Transect="T3"),
                                 mutate(read_tsv("Data/raw/CBASS/sensors/T5_D14/compass_readings.tsv"), Transect="T5"),
                                 mutate(read_tsv("Data/raw/CBASS/sensors/T6_D13/compass_readings.tsv"), Transect="T6"))
compass<- compass %>% mutate(timestamp_exact= timestamp+dmicroseconds(u_second))

Speed<- get_HypackSpeed(read_hypack(filename = list.files("Data/raw/Hypack/", pattern = "\\.RAW$", full.names = TRUE)))
Speed<- Speed %>% mutate(Speed_mps=Speed_kph*(1000/(60*60)))
names(Speed)[1]<- "timestamp_exact"

Community Analysis

Calculate the area viewed for each 15 second bin

Equations from McCollough (1893) and Grasty (2014)

Horizontal Angular Field of View

Calculate the angular field of view for the camera

H_AFOV_air = 2 * atan(sensor_width/(2 * focal_length))

Use Snell’s Law to adjust for refraction between air and seawater

H_AFOV_sea = 2 * asin(sin((H_AFOV_air/2)) * (n_air/n_sea))

*n is the index of refraction for the specified medium (n_air~1; n_sea ~1.33)

Distance to Center of Frame

Calculate the camera angle relative to the seafloor

cam_angle_to_ground = mounted_camera_angle - pitch

Adjust the raw altitude measurements to the true altitude by accounting for the pitch of the system

adjusted_altitude = cos(pitch) * altitude

Calculate the distance in meters between the camera lens and the seafloor at the center of an image

centerline_distance = adjusted_altitude/sin(cam_angle_to_ground)

Width of frame

Calculate the width of the image in meters at the center of an image

Width = 2 * centerline_distance * tan(H_AFOV_water/2)

Area Covered

Calculate distance covered in the 15 second observation window

Distance = Speed * 15s

*The median rather than the mean of speed over the 15s observation window is used so that faulty or poor readings do not adversely affect the calculation

Calculate the area viewed by the camera system

Area = Width * Distance

hab<- hab %>% mutate(Area=NA_real_)
H_AFOV_air<- calc_AFOV(d = 13.3, f = 5, medium = "air", type = "horiz", pix=c(1920, 1200))
for (i in 1:nrow(hab)) {
  curr_transect<- hab$Transect[i]
  mid_time<- hab$timestamp[i]
  st_time<- mid_time-dseconds(7.5)
  end_time<-  mid_time+dseconds(7.5)
  
  curr_alt<- median(altitude$altitude[altitude$timestamp_exact>=st_time & altitude$timestamp_exact<=end_time])
  curr_pitch<- median(compass$pitch[compass$timestamp_exact>=st_time & compass$timestamp_exact<=end_time])
  curr_speed<- median(Speed$Speed_mps[Speed$timestamp_exact>=st_time & Speed$timestamp_exact<=end_time])
  
  curr_width<- calc_width(alt = curr_alt, pitch = curr_pitch, cam_angle = 32.8, H_AFOV_air = H_AFOV_air)
  curr_dist<- curr_speed * 15
  
  hab$Area[i]<- curr_width*curr_dist
  }

Merge sequential observations of the same habitat class

Consecutive observations of habitat are collapsed into a single sample for community analysis and counts are summed among the merged observations. This is done to reduce the amount of rows with all zero counts which cannot be handled using semi-metric distances such as Bray-Curtis, and allows us to keep most information from sandy habitats while having more balance in sample sizes across habitat groups.

hab<- hab %>% mutate(samp_num=NA_real_)
hab$samp_num[1]<-1
samp_num<-1
for (i in 2:nrow(hab)) {
  curr_hab_obs<- hab$habitat[i]
  prev_hab_obs<- hab$habitat[i-1]
  curr_obs_transect<- hab$Transect[i]
  prev_obs_transect<- hab$Transect[i-1]
  if((curr_hab_obs!=prev_hab_obs)|(curr_obs_transect!=prev_obs_transect)|is.na(hab$Area[i])){
    samp_num<- samp_num+1
  }
  hab$samp_num[i]<-samp_num
}

fish_hab<- fish_counts %>% left_join(hab, by=c("Vid", "Sec", "timestamp", "Transect"))
fish_hab<- fish_hab %>% select(Transect,Vid, Sec, timestamp, samp_num, habitat, Area, everything())

fish_hab_collapsed<- fish_hab %>% group_by(samp_num) %>% 
  summarize(habitat=unique(habitat), Vid_min = first(Vid)+first(Sec)/60, Vid_max= last(Vid)+last(Sec)/60, across(Area:smnoid_smnoid, .fns = sum), .groups="drop")

print(fish_hab_collapsed)

Transform Data

To account for unequal lengths of the samples, counts are divided by the area duration. Additionally to down-weight over abundant taxa, densities are square root transformed.

dens_hab_collaped<- fish_hab_collapsed %>% mutate(across(amberjack_spp:smnoid_smnoid)/Area)
sq_dens_hab_collaped<- dens_hab_collaped %>% mutate(across(amberjack_spp:smnoid_smnoid, .fns=sqrt))
sq_dens_hab_collaped<- sq_dens_hab_collaped %>% filter(!is.na(Area) & habitat!="No_Vis")
sq_dens_hab_collaped<- sq_dens_hab_collaped %>% select(-c(smnoid_smnoid, lgnoid_lgnoid))
sq_dens<- sq_dens_hab_collaped %>% select(-c(samp_num, habitat, Vid_min, Vid_max, Area)) 
comm_hab<- sq_dens_hab_collaped %>% select(habitat)
idx<- rowSums(sq_dens)>0 #Bray Curtis distance cannot calculate distance in rows with all zeros
sq_dens<- sq_dens[idx,]
comm_hab<- comm_hab[idx,]
comm_hab$habitat<- factor(comm_hab$habitat, levels= c("Sand", "Low_Relief", "Moderate_Relief", "High_Relief"))

PERMANOVA

Check meet assumption of homogenous dispersion

set.seed(5)
permdisp_res<- permutest(betadisper(vegdist(sq_dens, methd="bray"), group= comm_hab$habitat, type = "median"), permutations = 9999)

p = 0.1862

p > .05 so we meet the assumtion of homogeneity of multivariate dispersion among groups and can therefore procedure with the PERMANOVA

Conduct global test

set.seed(6)
PERMANOVA_res<- adonis(sq_dens~habitat, data=comm_hab, permutations=999, method = "bray")
print(PERMANOVA_res)

Call:
adonis(formula = sq_dens ~ habitat, data = comm_hab, permutations = 999,      method = "bray") 

Permutation: free
Number of permutations: 999

Terms added sequentially (first to last)

           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)    
habitat     3     4.762 1.58737  4.4454 0.09052  0.001 ***
Residuals 134    47.849 0.35708         0.90948           
Total     137    52.611                 1.00000           
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Since p < .05 in the PERMANOVA, we conclude that there are sigificant differences in the fish communities among the different habitats

Conduct Pair-wise Test

To see which habitats have fish communities that differ from another, we follow up the global test with pairwise PERMANOVA tests

set.seed(7)
PW_comp<- adonis_PW(formula = sq_dens~habitat, data=comm_hab, permutations = 9999, method = "bray")

Table of pairwise comparisons

p_holm represents a p-value adjusted forf multiple comparisons using a Holm’s sequential Bonferroni correction. The adjusted p value is less than .05 for all comparisons except for between moderate and high relief rock, indicating that moderate and high relief rock did not have significantly different fish communities from one another, but all other habitats did.

Canonical Analysis of Principal Coordinates

Figure S2.2

CAP_result<- CAPdiscrim(as.data.frame(sq_dens)~habitat, data=as.data.frame(comm_hab), dist="bray", m=0, add=FALSE)
Overall classification success (m=10) : 73.9130434782609 percent
Sand (n=41) correct: 63.4146341463415 percent
Low_Relief (n=80) correct: 88.75 percent
Moderate_Relief (n=10) correct: 40 percent
High_Relief (n=7) correct: 14.2857142857143 percent
CAP_Plot<- plot_CAP(CAP_result = CAP_result, Y = sq_dens, Group = comm_hab$habitat, n_spec = 15, color = c("black", "blue", "orange", "red"), legend_title = "Habitat")
plot(CAP_Plot)

Fish Abundance Estimates

Habitat Specific Densities

fish_hab2<- fish_hab %>% filter(!is.na(Area) & habitat!="No_Vis")
fish_hab2<- fish_hab2 %>% mutate(habitat=ifelse(test = habitat %in% c("Moderate_Relief", "High_Relief"), yes = "Mod/High_Relief", no = habitat))
fish_hab2<- fish_hab2 %>% select(-smnoid_smnoid) %>% mutate(All_Fish= rowSums(across(amberjack_spp:lgnoid_lgnoid))) %>% select(-lgnoid_lgnoid) #Calculate total fish include large no id's then remove large no id's

hab_types<- unique(fish_hab2$habitat)

for (i in 1:length(hab_types)) {
  curr_fish_hab<- fish_hab2 %>% filter(habitat==hab_types[i])
  set.seed(i)
  curr_avg_dens<- avg_density(counts =select(curr_fish_hab, amberjack_spp:All_Fish), area = curr_fish_hab$Area, iter=1000, conf = .95)
  curr_avg_dens<- curr_avg_dens %>% mutate(Type= c("lower_bound", "mean", "upper_bound"))
  curr_avg_dens<- curr_avg_dens %>% pivot_longer(cols = -Type, names_to="Taxa", values_to="Density") #Tidy
  curr_avg_dens<- curr_avg_dens %>% pivot_wider(names_from = Type, values_from= Density)
  curr_avg_dens<- curr_avg_dens %>% mutate(habitat=hab_types[i])
  curr_avg_dens<- curr_avg_dens %>% select(Taxa, habitat, lower_bound, mean, upper_bound)
  if(i==1){
    avg_dens<- curr_avg_dens}else{
      avg_dens<- avg_dens %>% bind_rows(curr_avg_dens)
      }
  }
avg_dens$habitat<- factor(avg_dens$habitat, levels = c("Sand", "Low_Relief", "Mod/High_Relief"))
avg_dens<- avg_dens %>% arrange(Taxa, habitat)

Fish densities were estimated by habitat type for 36 species or species groups, as well as for all fish combined. For most taxa (33 of the 36 species/species groups), average fish density was highest over rocky habitats, and only 3 species had their highest densities over sand. Of the 33 taxa that had highest densities over a rocky habitat, 17 had had their highest densities over moderate-high relief rock and 16 had their highest densities over low relief rock.

Table of mean fish densities per Taxa in numbers of fish per kilometer squared with the lower and upper bounds of the 95% bootstrap confidence intervals

Plot of selected Taxa from table

Figure S2.3

Habitat Map

hab_map<- raster("Products/Mapping/Elbow_Supervised_HabRelief.tif")
hab_map<- reclassify(hab_map, matrix(data=c(21, 1, 11, 2, 12, 3, 13, 3), ncol = 2, byrow = TRUE)) #Merge Moderate and High Relief
hab_map<- as.factor(hab_map)
levels(hab_map)[[1]]$habitat<- c("Sand", "LR", "MR/HR")

Figure S2.4

Scale Densities up to Abundance

Multiply densities of taxa for each habitat by the corresponding area of the habitat to get abundance

abd<- avg_dens %>% left_join(hab_area, by="habitat") %>% 
  mutate(across(c(lower_bound, mean, upper_bound))*Area_m2) %>%
  dplyr::select(Taxa, habitat, lower_bound, mean, upper_bound)
abd<- bind_rows((abd %>% group_by(Taxa) %>% summarize(habitat="Total", across(where(is.numeric), .fns=sum), .groups="drop")), abd)
abd$habitat<- factor(abd$habitat, levels = c("Total", "Sand", "Low_Relief", "Mod/High_Relief"))
abd<- abd %>% arrange(Taxa, habitat)

Table of abundance estimates

There are estimated to be a total of approximately 109616 fish in total within the study area. Of these, 38893 (35%) are on sand, 25299 (23%) are on low relief rock, and 45424 (41%)` are on moderate to high relief rock.

Plot of estimated abundance for select species

Figure S2.5

LS0tDQp0aXRsZTogIkVsYm93IEZpc2ggQW5hbHlzZXMiDQphdXRob3I6ICJBbGV4YW5kZXIgSWxpY2giDQpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclQiAlZCwgJVknKWAiDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6DQplZGl0b3Jfb3B0aW9uczogDQogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2tuaXQkc2V0KHJvb3QuZGlyID0gbm9ybWFsaXplUGF0aCgiLi4iKSkNCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UpICNEZWZhdWx0IGNodW5rIG9wdGlvbnMNCg0KaW5zdGFsbGVkX3BhY2thZ2VzPC0gaW5zdGFsbGVkLnBhY2thZ2VzKCkNCm5lZWRlZF9wYWNrYWdlczwtIGMoInJnZGFsIiwgInNwIiwgInJhc3RlciIsICJzdGFycyIsICJ0bWFwIiwgImRldnRvb2xzIiwgIlJDb2xvckJyZXdlciIsDQogICAgICAgICAgICAgICAgICAgInZlZ2FuIiwgIkJpb2RpdmVyc2l0eVIiLCAiZ2dwbG90MiIsICJnZ3JlcGVsIiwgImx1YnJpZGF0ZSIsICJ0aWR5dmVyc2UiLCAiUmNtZHIiKQ0KDQpwYWNrYWdlc190b19pbnN0YWxsPC0gbmVlZGVkX3BhY2thZ2VzWyEobmVlZGVkX3BhY2thZ2VzICVpbiUgaW5zdGFsbGVkX3BhY2thZ2VzKV0NCmlmKGxlbmd0aChwYWNrYWdlc190b19pbnN0YWxsKT4wKXsNCiAgaWYoIlJjbWRyIiAlaW4lIHBhY2thZ2VzX3RvX2luc3RhbGwpew0KICAgIGluc3RhbGwucGFja2FnZXMoIlJjbWRyIiwgZGVwZW5kZW5jaWVzID0gVFJVRSkNCiAgICBwYWNrYWdlc190b19pbnN0YWxsPC0gcGFja2FnZXNfdG9faW5zdGFsbFtwYWNrYWdlc190b19pbnN0YWxsIT0iUmNtZHIiXQ0KICAgIH0NCiAgaW5zdGFsbC5wYWNrYWdlcyhwYWNrYWdlc190b19pbnN0YWxsKQ0KICB9DQppZighKCJteXRvb2xzIiAlaW4lIGluc3RhbGxlZF9wYWNrYWdlcykpew0KICBkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoImFpbGljaC9teXRvb2xzQHYwLjMxIikgDQogIH0gDQpsaWJyYXJ5KHJnZGFsKSAjU3BhdGlhbA0KbGlicmFyeShzcCkgI1NwYXRpYWwNCmxpYnJhcnkocmFzdGVyKSAjU3BhdGlhbA0KbGlicmFyeShzdGFycykgI1NwYXRpYWwgDQpsaWJyYXJ5KHRtYXApICNTcGF0aWFsIHBsb3R0aW5nDQpsaWJyYXJ5KFJDb2xvckJyZXdlcikgI0NvbG9yIHBhbGV0dGUNCmxpYnJhcnkodmVnYW4pICNTdGF0cw0KbGlicmFyeShCaW9kaXZlcnNpdHlSKSAjU3RhdHMNCmxpYnJhcnkoZ2dwbG90MikgI1Bsb3R0aW5nDQpsaWJyYXJ5KGdncmVwZWwpICNQbG90dGluZw0KbGlicmFyeShsdWJyaWRhdGUpICNGb3IgdGltZXN0YW1wcw0KbGlicmFyeSh0aWR5dmVyc2UpICNEYXRhIHdyYW5nbGluZy90aWR5aW5nDQpsaWJyYXJ5KG15dG9vbHMpICNNeSBmdW5jdGlvbnMNCm9wdGlvbnMoc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQ0KU3lzLnNldGVudihUWj0nVVRDJykgI1NldCB0aW1lIHRvIGRpc3BsYXkgaW4gVVRDDQpvcHRpb25zKGRpZ2l0cy5zZWNzPSA2KSAjVGltZSBkaWdpdHMgZGlzcGxheWVkIGFuZCB3cml0dGVuIHRvIDYgcGxhY2VzDQpgYGANCg0KYGBge3Igd2FybmluZz1UUlVFLCBpbmNsdWRlPUZBTFNFfQ0KI215dG9vbHMgYW5kIEdMQ01UZXh0dXJlcyBhcmUgcGFja2FnZXMgSSBjcmVhdGVkLiBteXRvb2xzIGlzIGFzc29ydGVkIGZ1bmN0aW9ucyBJIGhhdmUgbWFkZSBvdmVyIHRpbWUgYW5kIEdMQ01UZXh0dXJlcyBjYWxjdWxhdGVzIHRleHR1cmUgbWV0cmljcw0KaWYocGFja2FnZVZlcnNpb24oIm15dG9vbHMiKSE9IjAuMyIpew0KICB3YXJuaW5nKCJteXRvb2xzIGlzIGEgZGlmZmVyZW50IHZlcnNpb24gdGhhbiB0aGUgb25lIEkgdXNlZCB0byBydW4gdGhpcyBzY3JpcHQgYW5kIG1heSBwcm9kdWNlIGRpZmZlcmVudCByZXN1bHRzIikNCn0NCmBgYA0KDQpgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQ0KI05vdGUgdG8gbG9hZCB0aGUgZW52aXJvbm1lbnQgYXMgaXQgd291bGQgYmUgYXQgdGhlIGVuZCBvZiB0aGUgc2NyaXB0IHdpdGhvdXQgcnVubmluZyBpdCwgcnVuIHRoaXMgbGluZSBvZiBjb2RlDQpsb2FkKCJEYXRhL1JfZW52aXJvbm1lbnQvRWxib3dfUl9GaXNoX0Vudmlyb25tZW50LlJEYXRhIikNCmBgYA0KDQpgYGB7ciBEZWZpbmUgRnVuY3Rpb25zLCBpbmNsdWRlPUZBTFNFfQ0KYWRvbmlzX1BXPC0gZnVuY3Rpb24oZm9ybXVsYSwgZGF0YSwgcGVybXV0YXRpb25zLCBtZXRob2Qpew0KICBncnBfY29sbmFtZTwtIGxhYmVscyh0ZXJtcyhmb3JtdWxhKSkNCiAgZ3JwczwtIHVuaXF1ZShkYXRhW1tncnBfY29sbmFtZV1dKQ0KICBwd19jb21wczwtIGFzLmRhdGEuZnJhbWUodChjb21ibihhcy5jaGFyYWN0ZXIoZ3JwcyksIG0gPSAyKSkpDQogIFk8LSBnZXRfYWxsX3ZhcnMoZm9ybXVsYSwgZGF0YSA9IGRhdGEpICU+JSBzZWxlY3QoLWFsbF9vZihncnBfY29sbmFtZSkpIA0KICBvdXRwdXQ8LSBwd19jb21wcw0KICBvdXRwdXQ8LSBvdXRwdXQgJT4lIG11dGF0ZShGX3JhdGlvPU5BX3JlYWxfKQ0KICBvdXRwdXQ8LSBvdXRwdXQgJT4lIG11dGF0ZShwPU5BX3JlYWxfKQ0KICBmb3IgKGkgaW4gMTpucm93KHB3X2NvbXBzKSkgew0KICAgIGlkeDwtIGRhdGFbW2dycF9jb2xuYW1lXV0gJWluJSBjKHB3X2NvbXBzJFYxW2ldLCBwd19jb21wcyRWMltpXSkNCiAgICBkYXRhMjwtIGRhdGFbaWR4LCAsZHJvcD1GQUxTRV0NCiAgICBZMjwtIFlbaWR4LF0NCiAgICByZXM8LSBhZG9uaXMoZm9ybXVsYT1hcy5mb3JtdWxhKHBhc3RlMCgiWTJ+IiwgZ3JwX2NvbG5hbWUpKSwgZGF0YT1kYXRhMiwgcGVybXV0YXRpb25zID0gcGVybXV0YXRpb25zLCBtZXRob2QgPSBtZXRob2QpDQogICAgb3V0cHV0JEZfcmF0aW9baV08LSByZXNbWyJhb3YudGFiIl1dW1siRi5Nb2RlbCJdXVtbMV1dDQogICAgb3V0cHV0JHBbaV08LSAgcmVzW1siYW92LnRhYiJdXVtbIlByKD5GKSJdXVtbMV1dDQogIH0NCiAgb3V0cHV0PC0gb3V0cHV0ICU+JSBtdXRhdGUocF9ob2xtPXAuYWRqdXN0KHAsIG1ldGhvZCA9ICJob2xtIikpDQogIA0KICByZXR1cm4ob3V0cHV0KQ0KfQ0KDQpzY2FsZWRfbGVuZ3RoIDwtIGZ1bmN0aW9uKGF4MSwgYXgyLCB3MSwgdzIpew0KICByZXR1cm4oc3FydCgoYXgxKncxKV4yICsgKGF4Mip3MileMikpDQp9DQoNCmdnX2NvbG9yX2h1ZSA8LSBmdW5jdGlvbihuKSB7DQogIGh1ZXMgPSBzZXEoMTUsIDM3NSwgbGVuZ3RoID0gbiArIDEpDQogIGhjbChoID0gaHVlcywgbCA9IDY1LCBjID0gMTAwKVsxOm5dDQp9ICNodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy84MTk3NTU5L2VtdWxhdGUtZ2dwbG90Mi1kZWZhdWx0LWNvbG9yLXBhbGV0dGUNCg0KDQpwbG90X0NBUDwtIGZ1bmN0aW9uKENBUF9yZXN1bHQsIFksIEdyb3VwLCBjb2xvcj1nZ19jb2xvcl9odWUobGVuZ3RoKHVuaXF1ZShHcm91cCkpKSwgbl9zcGVjPW5jb2woWSksIGxlZ2VuZF90aXRsZT0iR3JvdXAiKXsNCiAgQ0FQX2RmPC0gYXMuZGF0YS5mcmFtZShzY29yZXMoQ0FQX3Jlc3VsdCwgY2hvaWNlcyA9IDE6MiwgZGlzcGxheSA9ICJzaXRlcyIpKQ0KICBDQVBfZGYkR3JvdXA8LSBHcm91cA0KICBDQVBfdmVjdF9kZjwtIGFzLmRhdGEuZnJhbWUoYWRkLnNwZWMuc2NvcmVzKENBUF9yZXN1bHQsIGNvbW0gPSBZLCBtZXRob2QgPSAiY29yLnNjb3JlcyIpJGNwcm9qWywxOjJdKSAjQ29ycmVsYXRpb24gdmVjdG9ycw0KICBDQVBfdmVjdF9kZiRTcGVjaWVzPC0gcm93bmFtZXMoQ0FQX3ZlY3RfZGYpDQogIENhbm9uaWNhbF9laWdlbnZhbHM8LSBDQVBfcmVzdWx0JGxkYS5vdGhlciRzdmReMiAjTnVtZXJpY2FsIEVjb2xvZ3kgd2l0aCBSLCAyMDE4LCBwZyAyNjcNCiAgQ2FuX1ZhcjwtIDEwMCooQ2Fub25pY2FsX2VpZ2VudmFscy9zdW0oQ2Fub25pY2FsX2VpZ2VudmFscykpICNDYW5vbmljYWwgVmFyaWF0aW9uDQogIENBUF92ZWN0X2RmPC0gQ0FQX3ZlY3RfZGYgJT4lIA0KICAgIG11dGF0ZShTTD0gc2NhbGVkX2xlbmd0aChheDEgPSBMRDEsIGF4MiA9IExEMiwgdzEgPSBhbGxfb2YoQ2FuX1ZhclsxXSksIHcyID0gYWxsX29mKENhbl9WYXJbMl0pKSkNCiAgQ0FQX3ZlY3RfZGY8LSBDQVBfdmVjdF9kZiAlPiUgYXJyYW5nZShkZXNjKFNMKSkNCiAgc2NhbGVfZmFjdG9yPC0gbWF4KGFicyhjKENBUF9kZiRMRDEsIENBUF9kZiRMRDIpKSkNCiAgQ0FQX2RmJExEMTwtIENBUF9kZiRMRDEvc2NhbGVfZmFjdG9yDQogIENBUF9kZiRMRDI8LSBDQVBfZGYkTEQyL3NjYWxlX2ZhY3RvciAjU2NhbGUgdmFsdWVzIGZyb20gLTEgdG8gMQ0KICBDQVBfQ2VudHJvaWRzPC0gQ0FQX2RmICU+JSBncm91cF9ieShHcm91cCkgJT4lIHN1bW1hcml6ZShMRDE9bWVhbihMRDEpLCBMRDI9bWVhbihMRDIpLCAuZ3JvdXBzPSJkcm9wIikNCiAgDQogIENBUF9wbG90PC0gZ2dwbG90KCkrDQogICAgZ2VvbV9wb2ludChkYXRhPSBDQVBfZGYsIG1hcHBpbmcgPSBhZXMoeD1MRDEsIHk9TEQyLCBjb2xvcj0gR3JvdXApKSsNCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWNvbG9yKSsNCiAgICBnZW9tX3NlZ21lbnQoZGF0YT1DQVBfdmVjdF9kZlsxOm5fc3BlYyxdLCBtYXBwaW5nID0gYWVzKHg9MCwgeGVuZD1MRDEsIHk9MCwgeWVuZD1MRDIpLA0KICAgICAgICAgICAgICAgYXJyb3c9YXJyb3cobGVuZ3RoPXVuaXQoMC4yNSwiY20iKSksIGNvbG9yPSJkYXJrZ3JleSIpKw0KICAgIGdlb21fdGV4dF9yZXBlbChkYXRhID0gQ0FQX3ZlY3RfZGZbMTpuX3NwZWMsXSwgbWFwcGluZz1hZXMoeD1MRDEsIHk9TEQyLCBsYWJlbD1TcGVjaWVzKSwgc2l6ZT0zLCBzZWdtZW50LmNvbG9yID0gTkEpKw0KICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jb2xvcikrDQogICAgZ2VvbV9sYWJlbChkYXRhPUNBUF9DZW50cm9pZHMsIG1hcHBpbmcgPSBhZXMoeD1MRDEsIHk9TEQyLCBsYWJlbD0gR3JvdXAsIGZpbGw9IEdyb3VwKSwgc2hvdy5sZWdlbmQgPSBGQUxTRSwgY29sb3I9IndoaXRlIiwgZm9udGZhY2U9ImJvbGQiKSsNCiAgICB4bGFiKGxhYmVsID0gcGFzdGUwKCJDYW5vbmljYWwgQXhpcyAxICgiLCByb3VuZChDYW5fVmFyWzFdLDIpLCAiJSkiKSkrDQogICAgeWxhYihsYWJlbCA9IHBhc3RlMCgiQ2Fub25pY2FsIEF4aXMgMiAoIiwgcm91bmQoQ2FuX1ZhclsyXSwyKSwgIiUpIikpKw0KICAgIHRoZW1lX2J3KCkrDQogICAgbGFicyhjb2w9bGVnZW5kX3RpdGxlKQ0KICByZXR1cm4oQ0FQX3Bsb3QpDQp9DQpgYGANCg0KIyBTdHVkeSBBcmVhDQoNClRoZSBzdHVkeSBhcmVhIGlzIG1hcmtlZCBpbiByZWQsIGFuZCBpcyBrbm93IGFzICJUaGUgRWxib3cuIiBJdCBpcyBhYm91dCAxNDUga20gd2VzdC1ub3J0aHdlc3Qgb2YgVGFtcGEgQmF5LCBGbG9yaWRhLiBUaGUgYXJlYSBpcyBhIHBvcHVsYXIgb2Zmc2hvcmUgZmlzaGluZyBhcmVhIHRoYXQgY29udGFpbnMgY29udGFpbnMgaGFyZCBib3R0b20gcmlkZ2VzIGFuZCBpcyBoeXBvdGhlc2l6ZWQgdG8gYmUgYSBwYWxlb3Nob3JlbGluZSBzaGFwZWQgYnkgd2F2ZSBhY3Rpb24gYXBwcm94aW1hdGVseSAxMiwwMDAgeWVhcnMgYWdvLg0KDQpUaGUgdGhyZWUgbGluZXMgc2hvd24gcmVwcmVzZW50IGRheS10aW1lIHZpZGVvIHRyYW5zZWN0cyBjb21wbGV0ZWQgdXNpbmcgYSB0b3dlZCB2aWRlbyBjYW1lcmEgc3lzdGVtIHRoYXQgZmxpZXMgYWJvdXQgMi00IG1ldGVycyBhYm92ZSB0aGUgc2VhZmxvb3IuIEFsb25nIHRoZXNlIHRyYW5zZWN0cywgZmlzaCB3ZXJlIGFubm90YXRlZCBhdCB0aGUgZnJhbWUtbGV2ZWwsIGFuZCBoYWJpdGF0IHdhcyBhbm5vdGF0ZWQgZXZlcnkgMTUgc2Vjb25kcy4NCg0KRmlndXJlIFMyLjENCmBgYHtyIGluY2x1ZGU9RkFMU0UsIHJlc3VsdHM9J2hpZGUnLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD02fQ0KRkxfc2hwPC0gcmVhZE9HUigiRGF0YS9kZXJpdmVkL3NoYXBlZmlsZXMvRmxvcmlkYV9TaG9yZWxpbmVfXzFfdG9fMiUyQzAwMCUyQzAwMF9TY2FsZV8uc2hwIikgI1NvdXJjZTogaHR0cHM6Ly9nZW9kYXRhLm15ZndjLmNvbS9kYXRhc2V0cy9mbG9yaWRhLXNob3JlbGluZS0xLXRvLTIwMDAwMDAtc2NhbGU/Z2VvbWV0cnk9LTEwMi4zNjYlMkMyNC4zNTYlMkMtNjUuMjk4JTJDMzEuMTU2DQpFTF9zaHA8LSByZWFkT0dSKCJEYXRhL2Rlcml2ZWQvc2hhcGVmaWxlcy9FTF9TaHAuc2hwIikNCmJhdGh5PC0gcmFzdGVyKCJEYXRhL2Rlcml2ZWQvTXVsdGliZWFtL2JhdGh5LnRpZiIpDQpUcmFuc2VjdF9zaHA8LSByYmluZChyZWFkT0dSKCJEYXRhL2Rlcml2ZWQvc2hhcGVmaWxlcy9FTFQzX1NoaXB0cmFjay5zaHAiKSwNCnJlYWRPR1IoIkRhdGEvZGVyaXZlZC9zaGFwZWZpbGVzL0VMVDVfU2hpcHRyYWNrLnNocCIpLA0KcmVhZE9HUigiRGF0YS9kZXJpdmVkL3NoYXBlZmlsZXMvRUxUNl9TaGlwdHJhY2suc2hwIikpDQpiYXRoeV9wYWw8LSBjb2xvclJhbXBQYWxldHRlKGJyZXdlci5wYWwobiA9IDksIG5hbWUgPSAiQmx1ZXMiKVszOjldKQ0KU3R1ZHlfQXJlYV9QbG90PC0gdG1fc2hhcGUoRkxfc2hwKSsNCiAgdG1fZmlsbCgpKw0KICB0bV9zaGFwZShFTF9zaHApKw0KICB0bV9maWxsKGNvbD0icmVkIikrDQogIHRtX2dyYXRpY3VsZXMobGluZXM9RkFMU0UpKw0KICB0bV9jcmVkaXRzKCJodHRwczovL2dlb2RhdGEubXlmd2MuY29tL2RhdGFzZXRzIiwgcG9zaXRpb24gPSBjKCJsZWZ0IiwgImJvdHRvbSIpKQ0KDQpUcmFuc2VjdF9QbG90PC0gdG1fc2hhcGUoYmF0aHksIHJhc3Rlci5kb3duc2FtcGxlID0gRkFMU0UpKw0KICB0bV9yYXN0ZXIocGFsZXR0ZSA9IGJhdGh5X3BhbCgxMDApLCBzdHlsZT0iY29udCIsIHRpdGxlID0gIkJhdGh5bWV0cnkgKG0pIikrDQogIHRtX3NoYXBlKFRyYW5zZWN0X3NocCkrDQogIHRtX2xpbmVzKCkrDQogIHRtX2NvbXBhc3ModHlwZSA9ICI4c3RhciIsIHBvc2l0aW9uID0gYygicmlnaHQiLCAidG9wIikpKw0KICB0bV9zY2FsZV9iYXIoYnJlYWtzPSBjKDAsIDIuNSwgNSksIHRleHQuc2l6ZT0xKQ0KYGBgDQpgYGB7ciBlY2hvPUZBTFNFfQ0KdG1hcF9hcnJhbmdlKFN0dWR5X0FyZWFfUGxvdCwgVHJhbnNlY3RfUGxvdCkNCmBgYA0KDQoNCiMgUmVhZCBpbiBhbmQgcmVmb3JtYXQgZGF0YQ0KDQojIyBIYWJpdGF0IGRhdGENCg0KSGFiaXRhdCB3YXMgYW5ub3RhdGVkIGV2ZXJ5IDE1IHNlY29uZHMgb2YgdmlkZW8NCg0KYGBge3J9DQpoYWI8LSByZWFkX2NzdigiRGF0YS9kZXJpdmVkL0NCQVNTL2hhYi5jc3YiKQ0KaGFiPC0gaGFiICU+JSBzZWxlY3QoLWMoQ0JBU1NMYXQsIENCQVNTTG9uLCBGcmFtZV9udW0sIFN1YnN0cmF0ZSkpDQpoYWI8LSBoYWIgJT4lIGZpbHRlcihUcmFuc2VjdCE9IlQxIikNCmhhYjwtIGhhYiAlPiUgbXV0YXRlKGhhYml0YXQ9aWZlbHNlKHRlc3QgPSBSZWxpZWY9PSJOb25lIiwgeWVzID0gIlNhbmQiLCBubyA9IFJlbGllZikpDQpoYWI8LSBoYWIgJT4lIHNlbGVjdCgtUmVsaWVmKQ0KcHJpbnQoaGFiKQ0KYGBgDQoNCiMjIEZpc2ggQ291bnRzDQoNCmBgYHtyIGVjaG89RkFMU0V9DQpUM19hbm5vdGF0aW9uPC0gbWVyZ2VfY3Zpc2lvbl9jc3YoZmlsZV9saXN0ID0gbGlzdC5maWxlcyhwYXRoID0gIkRhdGEvcmF3L0NCQVNTL2Zpc2hfY291bnRzL1QzX0QxIiwgcGF0dGVybiA9ICJcXC5jc3YkIiwgZnVsbC5uYW1lcyA9IFRSVUUpLCBmcmFtZXNfcGVyX3NlYyA9IDEyLCB2aWRfbGVuZ3RoID0gMSkNClQ1X2Fubm90YXRpb248LSBtZXJnZV9jdmlzaW9uX2NzdihmaWxlX2xpc3QgPSBsaXN0LmZpbGVzKHBhdGggPSAiRGF0YS9yYXcvQ0JBU1MvZmlzaF9jb3VudHMvVDVfRDE0IiwgcGF0dGVybiA9ICJcXC5jc3YkIiwgZnVsbC5uYW1lcyA9IFRSVUUpLCBmcmFtZXNfcGVyX3NlYyA9IDEyLCB2aWRfbGVuZ3RoID0gMSkNClQ2X2Fubm90YXRpb248LSBtZXJnZV9jdmlzaW9uX2NzdihmaWxlX2xpc3QgPSBsaXN0LmZpbGVzKHBhdGggPSAiRGF0YS9yYXcvQ0JBU1MvZmlzaF9jb3VudHMvVDZfRDEzIiwgcGF0dGVybiA9ICJcXC5jc3YkIiwgZnVsbC5uYW1lcyA9IFRSVUUpLCBmcmFtZXNfcGVyX3NlYyA9IDEyLCB2aWRfbGVuZ3RoID0gMSkNCiAjVDMgYW5ub3RhdGVkIGJlZm9yZSBjb25zaXN0ZW50IG5hbWluZyBmb3Igc3BlY2llcy4gUmVmb3JtYXQgc3BlY2llcyBuYW1lcyBpbiBUMy4NClQzX2Fubm90YXRpb24kRmlzaF9UeXBlW1QzX2Fubm90YXRpb24kRmlzaF9UeXBlPT0ic2hlZXBzaGVhZCJdPC0gInBvcmd5X3NoZWVwc2hlYWQiDQpUM19hbm5vdGF0aW9uJEZpc2hfVHlwZVtUM19hbm5vdGF0aW9uJEZpc2hfVHlwZT09ImxhcmdlX25vaWQiXTwtICJsZ25vaWRfbGdub2lkIg0KVDNfYW5ub3RhdGlvbiRGaXNoX1R5cGVbVDNfYW5ub3RhdGlvbiRGaXNoX1R5cGU9PSJncmF5IHRyaWdnZXJmaXNoIl08LSAidHJpZ2dlcmZpc2hfZ3JheSINClQzX2Fubm90YXRpb24kRmlzaF9UeXBlW1QzX2Fubm90YXRpb24kRmlzaF9UeXBlPT0ic2FuZCB0aWxlZmlzaCJdPC0gInRpbGVmaXNoX3NhbmQiDQpUM19hbm5vdGF0aW9uJEZpc2hfVHlwZVtUM19hbm5vdGF0aW9uJEZpc2hfVHlwZT09ImJsdWUgYW5nZWxmaXNoIl08LSAiYW5nZWxmaXNoX2JsdWUiDQpUM19hbm5vdGF0aW9uJEZpc2hfVHlwZVtUM19hbm5vdGF0aW9uJEZpc2hfVHlwZT09ImdyYXkgYW5nZWxmaXNoIl08LSAiYW5nZWxmaXNoX2dyYXkiDQpUM19hbm5vdGF0aW9uJEZpc2hfVHlwZVtUM19hbm5vdGF0aW9uJEZpc2hfVHlwZT09InNtYWxsX25vaWQiXTwtICJzbW5vaWRfc21ub2lkIg0KVDNfYW5ub3RhdGlvbiRGaXNoX1R5cGVbVDNfYW5ub3RhdGlvbiRGaXNoX1R5cGU9PSJyYWluYm93IHJ1bm5lciJdPC0gImphY2tfcmFpbmJvd3J1bm5lciINClQzX2Fubm90YXRpb24kRmlzaF9UeXBlW1QzX2Fubm90YXRpb24kRmlzaF9UeXBlPT0iZ3JheSBzbmFwcGVyIl08LSAic25hcHBlcl9ncmF5Ig0KVDNfYW5ub3RhdGlvbiRGaXNoX1R5cGVbVDNfYW5ub3RhdGlvbiRGaXNoX1R5cGU9PSJwZWFybHkgcmF6b3JmaXNoIl08LSAid3Jhc3NlX3BlYXJseXJhem9yZmlzaCINClQzX2Fubm90YXRpb24kRmlzaF9UeXBlW1QzX2Fubm90YXRpb24kRmlzaF9UeXBlPT0icmVlZiBidXR0ZXJmbHlmaXNoIl08LSAiYnV0dGVyZmx5ZmlzaF9yZWVmIg0KVDNfYW5ub3RhdGlvbiRGaXNoX1R5cGVbVDNfYW5ub3RhdGlvbiRGaXNoX1R5cGU9PSJyZWQgZ3JvdXBlciJdPC0gImdyb3VwZXJfcmVkIg0KVDNfYW5ub3RhdGlvbiRGaXNoX1R5cGVbVDNfYW5ub3RhdGlvbiRGaXNoX1R5cGU9PSJzZWEgdHVydGxlIHNwcCJdPC0gInNlYXR1cnRsZV9zcHAiDQpUM19hbm5vdGF0aW9uJEZpc2hfVHlwZTwtIHN0cl9yZXBsYWNlKHN0cmluZyA9IFQzX2Fubm90YXRpb24kRmlzaF9UeXBlLCBwYXR0ZXJuID0gIiAiLCAiXyIpDQoNCmZpc2hfYW5ub3RhdGlvbnM8LSBiaW5kX3Jvd3MobXV0YXRlKFQzX2Fubm90YXRpb24sIFRyYW5zZWN0PSJUMyIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoVDVfYW5ub3RhdGlvbiwgVHJhbnNlY3Q9IlQ1IiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShUNl9hbm5vdGF0aW9uLCBUcmFuc2VjdD0iVDYiKSkNCndyaXRlX2NzdihmaXNoX2Fubm90YXRpb25zLCAiRGF0YS9kZXJpdmVkL0NCQVNTL2Zpc2hfYW5ub3RhdGlvbnMuY3N2IikNCmBgYA0KDQpGaXNoIHdlcmUgYW5ub3RhdGVkIG9uIHVzaW5nIEMtVmlzaW9uJ3MgdmlkZW8gYW5ub3RhdGlvbiBzb2Z0d2FyZSBhdCB0aGUgZnJhbWUgbGV2ZWwuIEVhY2ggcm93IGlzIGFuIGluZGl2aWR1YWwgZmlzaCwgYW5kIHdlIGNhbiBzZWUgZXhhY3RseSB3aGF0IGZyYW1lIHRoYXQgZmlzaCB3YXMgc2Vlbi4NCg0KYGBge3J9DQpmaXNoX2Fubm90YXRpb25zPC0gcmVhZF9jc3YoIkRhdGEvZGVyaXZlZC9DQkFTUy9maXNoX2Fubm90YXRpb25zLmNzdiIpDQpwcmludChmaXNoX2Fubm90YXRpb25zKQ0KYGBgDQoNClRvIHR1cm4gdGhlc2UgYW5ub3RhdGlvbnMgaW50byBjb3VudHMsIGVhY2ggaW5kaXZpZHVhbCBmaXNoIHdhcyBtYXRjaGVkIHRvIHRoZSBjbG9zZXN0IGhhYml0YXQgb2JzZXJ2YXRpb24gaW4gdGltZSwgYW5kIHRoZSBudW1iZXIgb2YgYW5ub3RhdGlvbnMgZm9yIGVhY2ggdGF4YSB3ZXJlIHRoZW4gc3VtbWVkLg0KDQpgYGB7ciB9DQpmaXNoX2NvdW50czwtIGJpbmRfcm93cyhtdXRhdGUobWF0Y2hfY3Zpc2lvbl9maXNoMmhhYihtZXJnZWRfY3Zpc2lvbl9jc3YgPSBzZWxlY3QoZmlsdGVyKGZpc2hfYW5ub3RhdGlvbnMsIFRyYW5zZWN0PT0iVDMiKSwgLVRyYW5zZWN0KSwgdmlkZW9fbnVtID0gZmlsdGVyKGhhYiwgVHJhbnNlY3Q9PSJUMyIpJFZpZCwgdmlkZW9fc2VjID0gZmlsdGVyKGhhYiwgVHJhbnNlY3Q9PSJUMyIpJFNlYywgZnBzID0gMTIsIHZpZF9sZW5ndGggPSAxLCBpbmNsdWRlX3ZpZF9zZWMgPSBUUlVFLCBpbmNsdWRlX2ZyYW1lbnVtID0gRkFMU0UpLCBUcmFuc2VjdD0iVDMiKSwNCiAgICAgICAgICBtdXRhdGUobWF0Y2hfY3Zpc2lvbl9maXNoMmhhYihtZXJnZWRfY3Zpc2lvbl9jc3YgPSBzZWxlY3QoZmlsdGVyKGZpc2hfYW5ub3RhdGlvbnMsIFRyYW5zZWN0PT0iVDUiKSwgLVRyYW5zZWN0KSwgdmlkZW9fbnVtID0gZmlsdGVyKGhhYiwgVHJhbnNlY3Q9PSJUNSIpJFZpZCwgdmlkZW9fc2VjID0gZmlsdGVyKGhhYiwgVHJhbnNlY3Q9PSJUNSIpJFNlYywgZnBzID0gMTIsIHZpZF9sZW5ndGggPSAxLCBpbmNsdWRlX3ZpZF9zZWMgPSBUUlVFLCBpbmNsdWRlX2ZyYW1lbnVtID0gRkFMU0UpLCBUcmFuc2VjdD0iVDUiKSwNCiAgICAgICAgICBtdXRhdGUobWF0Y2hfY3Zpc2lvbl9maXNoMmhhYihtZXJnZWRfY3Zpc2lvbl9jc3YgPSBzZWxlY3QoZmlsdGVyKGZpc2hfYW5ub3RhdGlvbnMsIFRyYW5zZWN0PT0iVDYiKSwgLVRyYW5zZWN0KSwgdmlkZW9fbnVtID0gZmlsdGVyKGhhYiwgVHJhbnNlY3Q9PSJUNiIpJFZpZCwgdmlkZW9fc2VjID0gZmlsdGVyKGhhYiwgVHJhbnNlY3Q9PSJUNiIpJFNlYywgZnBzID0gMTIsIHZpZF9sZW5ndGggPSAxLCBpbmNsdWRlX3ZpZF9zZWMgPSBUUlVFLCBpbmNsdWRlX2ZyYW1lbnVtID0gRkFMU0UpLCBUcmFuc2VjdD0iVDYiKSkgJT4lIHNlbGVjdChUcmFuc2VjdCwgZXZlcnl0aGluZygpKQ0KZmlzaF9jb3VudHNbaXMubmEoZmlzaF9jb3VudHMpXTwtIDAgDQpmaXNoX2NvdW50czwtIGZpc2hfY291bnRzICU+JSBzZWxlY3QoVHJhbnNlY3QsIFZpZGVvLCBTZWNvbmRzLCBldmVyeXRoaW5nKCkpDQpuYW1lcyhmaXNoX2NvdW50cylbMjozXTwtIGMoIlZpZCIsICJTZWMiKQ0KDQojTWVyZ2UgdGF4YSB0aGF0IGFyZSBkaWZmaWN1bHQgdG8gZGlmZmVyZW50aWF0ZSBjb25zaXN0ZW50bHkNCmZpc2hfY291bnRzPC0gZmlzaF9jb3VudHMgJT4lIG11dGF0ZShBTUJFUkpBQ0tfU1BQPSByb3dTdW1zKGFjcm9zcyhzdGFydHNfd2l0aCgiYW1iZXJqYWNrXyIsIGlnbm9yZS5jYXNlID0gRkFMU0UpKSkpICU+JSBzZWxlY3QoLXN0YXJ0c193aXRoKCJhbWJlcmphY2tfIiwgaWdub3JlLmNhc2UgPSBGQUxTRSkpDQoNCmZpc2hfY291bnRzPC0gZmlzaF9jb3VudHMgJT4lIG11dGF0ZShCVVRURVJGTFlGSVNIX1NQUD0gcm93U3VtcyhhY3Jvc3Moc3RhcnRzX3dpdGgoImJ1dHRlcmZseWZpc2hfIiwgaWdub3JlLmNhc2UgPSBGQUxTRSkpKSkgICU+JSBzZWxlY3QoLXN0YXJ0c193aXRoKCJidXR0ZXJmbHlmaXNoXyIsaWdub3JlLmNhc2UgPSBGQUxTRSkpDQoNCmZpc2hfY291bnRzPC0gZmlzaF9jb3VudHMgJT4lIG11dGF0ZShQT1JHWV9TUFA9IHJvd1N1bXMoYWNyb3NzKHN0YXJ0c193aXRoKCJwb3JneV8iLCBpZ25vcmUuY2FzZSA9IEZBTFNFKSkpKSAgJT4lIHNlbGVjdCgtc3RhcnRzX3dpdGgoInBvcmd5XyIsaWdub3JlLmNhc2UgPSBGQUxTRSkpDQoNCmZpc2hfY291bnRzPC0gZmlzaF9jb3VudHMgJT4lIG11dGF0ZShUUklHR0VSRklTSF9TUFA9IHJvd1N1bXMoYWNyb3NzKHN0YXJ0c193aXRoKCJ0cmlnZ2VyZmlzaF8iLGlnbm9yZS5jYXNlID0gRkFMU0UpKSkpICAlPiUgc2VsZWN0KC1zdGFydHNfd2l0aCgidHJpZ2dlcmZpc2hfIixpZ25vcmUuY2FzZSA9IEZBTFNFKSkNCg0KZmlzaF9jb3VudHM8LSBmaXNoX2NvdW50cyAlPiUgc2VsZWN0KC1zZWF0dXJ0bGVfc3BwKSAjTk90IGEgZmlzaA0KDQpuYW1lcyhmaXNoX2NvdW50cylbNDpuY29sKGZpc2hfY291bnRzKV08LSB0b2xvd2VyKG5hbWVzKGZpc2hfY291bnRzKVs0Om5jb2woZmlzaF9jb3VudHMpXSkNCmZpc2hfY291bnRzPC0gZmlzaF9jb3VudHMgJT4lIHNlbGVjdChUcmFuc2VjdCwgVmlkLCBTZWMsIHNvcnRfc3BlY2llcyhuYW1lcyhmaXNoX2NvdW50cylbNDpuY29sKGZpc2hfY291bnRzKV0pKQ0KZmlzaF9jb3VudHM8LSBmaXNoX2NvdW50cyAlPiUgbGVmdF9qb2luKHNlbGVjdChoYWIsIHRpbWVzdGFtcCwgVHJhbnNlY3QsIFZpZCwgU2VjKSwgYnk9YygiVHJhbnNlY3QiLCAiVmlkIiwgIlNlYyIpKQ0KZmlzaF9jb3VudHM8LSBmaXNoX2NvdW50cyAlPiUgc2VsZWN0KFRyYW5zZWN0LCBWaWQsIFNlYywgdGltZXN0YW1wLCBldmVyeXRoaW5nKCkpDQpgYGANCg0KYGBge3IgZWNobz1GQUxTRX0NCndyaXRlX2NzdihmaXNoX2NvdW50cywgIkRhdGEvZGVyaXZlZC9DQkFTUy9maXNoX2NvdW50cy5jc3YiKQ0KYGBgDQoNCmBgYHtyfQ0KcHJpbnQoZmlzaF9jb3VudHMpDQpgYGANCg0KIyMgUmF3IEF1eGlsbGFyeSBEYXRhDQoNCmBgYHtyfQ0KYWx0aXR1ZGU8LSBiaW5kX3Jvd3M8LSBiaW5kX3Jvd3MobXV0YXRlKHJlYWRfdHN2KCJEYXRhL3Jhdy9DQkFTUy9zZW5zb3JzL1QzX0QxL2FsdGltZXRlcl9yZWFkaW5ncy50c3YiKSwgVHJhbnNlY3Q9IlQzIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUocmVhZF90c3YoIkRhdGEvcmF3L0NCQVNTL3NlbnNvcnMvVDVfRDE0L2FsdGltZXRlcl9yZWFkaW5ncy50c3YiKSwgVHJhbnNlY3Q9IlQ1IiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUocmVhZF90c3YoIkRhdGEvcmF3L0NCQVNTL3NlbnNvcnMvVDZfRDEzL2FsdGltZXRlcl9yZWFkaW5ncy50c3YiKSwgVHJhbnNlY3Q9IlQ2IikpDQphbHRpdHVkZTwtIGFsdGl0dWRlICU+JSBtdXRhdGUodGltZXN0YW1wX2V4YWN0PSB0aW1lc3RhbXArZG1pY3Jvc2Vjb25kcyh1X3NlY29uZCkpDQpjb21wYXNzPC0gYmluZF9yb3dzPC0gYmluZF9yb3dzKG11dGF0ZShyZWFkX3RzdigiRGF0YS9yYXcvQ0JBU1Mvc2Vuc29ycy9UM19EMS9jb21wYXNzX3JlYWRpbmdzLnRzdiIpLCBUcmFuc2VjdD0iVDMiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShyZWFkX3RzdigiRGF0YS9yYXcvQ0JBU1Mvc2Vuc29ycy9UNV9EMTQvY29tcGFzc19yZWFkaW5ncy50c3YiKSwgVHJhbnNlY3Q9IlQ1IiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUocmVhZF90c3YoIkRhdGEvcmF3L0NCQVNTL3NlbnNvcnMvVDZfRDEzL2NvbXBhc3NfcmVhZGluZ3MudHN2IiksIFRyYW5zZWN0PSJUNiIpKQ0KY29tcGFzczwtIGNvbXBhc3MgJT4lIG11dGF0ZSh0aW1lc3RhbXBfZXhhY3Q9IHRpbWVzdGFtcCtkbWljcm9zZWNvbmRzKHVfc2Vjb25kKSkNCg0KU3BlZWQ8LSBnZXRfSHlwYWNrU3BlZWQocmVhZF9oeXBhY2soZmlsZW5hbWUgPSBsaXN0LmZpbGVzKCJEYXRhL3Jhdy9IeXBhY2svIiwgcGF0dGVybiA9ICJcXC5SQVckIiwgZnVsbC5uYW1lcyA9IFRSVUUpKSkNClNwZWVkPC0gU3BlZWQgJT4lIG11dGF0ZShTcGVlZF9tcHM9U3BlZWRfa3BoKigxMDAwLyg2MCo2MCkpKQ0KbmFtZXMoU3BlZWQpWzFdPC0gInRpbWVzdGFtcF9leGFjdCINCmBgYA0KDQojIENvbW11bml0eSBBbmFseXNpcw0KDQojIyBDYWxjdWxhdGUgdGhlIGFyZWEgdmlld2VkIGZvciBlYWNoIDE1IHNlY29uZCBiaW4NCg0KRXF1YXRpb25zIGZyb20gTWNDb2xsb3VnaCAoMTg5MykgYW5kIEdyYXN0eSAoMjAxNCkNCg0KIyMjIEhvcml6b250YWwgQW5ndWxhciBGaWVsZCBvZiBWaWV3DQoNCltDYWxjdWxhdGUgdGhlIGFuZ3VsYXIgZmllbGQgb2YgdmlldyBmb3IgdGhlIGNhbWVyYV17LnVsfQ0KDQoqSF9BRk9WX2FpciA9IDIgXCogYXRhbihzZW5zb3Jfd2lkdGgvKDIgXCogZm9jYWxfbGVuZ3RoKSkqDQoNCltVc2UgU25lbGwncyBMYXcgdG8gYWRqdXN0IGZvciByZWZyYWN0aW9uIGJldHdlZW4gYWlyIGFuZCBzZWF3YXRlcl17LnVsfQ0KDQoqSF9BRk9WX3NlYSA9IDIgXCogYXNpbihzaW4oKEhfQUZPVl9haXIvMikpIFwqIChuX2Fpci9uX3NlYSkpKg0KDQpcKm4gaXMgdGhlIGluZGV4IG9mIHJlZnJhY3Rpb24gZm9yIHRoZSBzcGVjaWZpZWQgbWVkaXVtIChuX2Fpclx+MTsgbl9zZWEgXH4xLjMzKQ0KDQojIyMgRGlzdGFuY2UgdG8gQ2VudGVyIG9mIEZyYW1lDQoNCltDYWxjdWxhdGUgdGhlIGNhbWVyYSBhbmdsZSByZWxhdGl2ZSB0byB0aGUgc2VhZmxvb3Jdey51bH0NCg0KKmNhbV9hbmdsZV90b19ncm91bmQgPSBtb3VudGVkX2NhbWVyYV9hbmdsZSAtIHBpdGNoKg0KDQpbQWRqdXN0IHRoZSByYXcgYWx0aXR1ZGUgbWVhc3VyZW1lbnRzIHRvIHRoZSB0cnVlIGFsdGl0dWRlIGJ5IGFjY291bnRpbmcgZm9yIHRoZSBwaXRjaCBvZiB0aGUgc3lzdGVtXXsudWx9DQoNCiphZGp1c3RlZF9hbHRpdHVkZSA9IGNvcyhwaXRjaCkgXCogYWx0aXR1ZGUqDQoNCltDYWxjdWxhdGUgdGhlIGRpc3RhbmNlIGluIG1ldGVycyBiZXR3ZWVuIHRoZSBjYW1lcmEgbGVucyBhbmQgdGhlIHNlYWZsb29yIGF0IHRoZSBjZW50ZXIgb2YgYW4gaW1hZ2Vdey51bH0NCg0KKmNlbnRlcmxpbmVfZGlzdGFuY2UgPSBhZGp1c3RlZF9hbHRpdHVkZS9zaW4oY2FtX2FuZ2xlX3RvX2dyb3VuZCkqDQoNCiMjIyBXaWR0aCBvZiBmcmFtZQ0KDQpbQ2FsY3VsYXRlIHRoZSB3aWR0aCBvZiB0aGUgaW1hZ2UgaW4gbWV0ZXJzIGF0IHRoZSBjZW50ZXIgb2YgYW4gaW1hZ2Vdey51bH0NCg0KKldpZHRoID0gMiBcKiBjZW50ZXJsaW5lX2Rpc3RhbmNlIFwqIHRhbihIX0FGT1Zfd2F0ZXIvMikqDQoNCiMjIyBBcmVhIENvdmVyZWQNCg0KW0NhbGN1bGF0ZSBkaXN0YW5jZSBjb3ZlcmVkIGluIHRoZSAxNSBzZWNvbmQgb2JzZXJ2YXRpb24gd2luZG93XXsudWx9DQoNCipEaXN0YW5jZSA9IFNwZWVkIFwqIDE1cyoNCg0KXCpUaGUgbWVkaWFuIHJhdGhlciB0aGFuIHRoZSBtZWFuIG9mIHNwZWVkIG92ZXIgdGhlIDE1cyBvYnNlcnZhdGlvbiB3aW5kb3cgaXMgdXNlZCBzbyB0aGF0IGZhdWx0eSBvciBwb29yIHJlYWRpbmdzIGRvIG5vdCBhZHZlcnNlbHkgYWZmZWN0IHRoZSBjYWxjdWxhdGlvbg0KDQpbQ2FsY3VsYXRlIHRoZSBhcmVhIHZpZXdlZCBieSB0aGUgY2FtZXJhIHN5c3RlbV17LnVsfQ0KDQoqQXJlYSA9IFdpZHRoIFwqIERpc3RhbmNlKg0KDQpgYGB7cn0NCmhhYjwtIGhhYiAlPiUgbXV0YXRlKEFyZWE9TkFfcmVhbF8pDQpIX0FGT1ZfYWlyPC0gY2FsY19BRk9WKGQgPSAxMy4zLCBmID0gNSwgbWVkaXVtID0gImFpciIsIHR5cGUgPSAiaG9yaXoiLCBwaXg9YygxOTIwLCAxMjAwKSkNCmZvciAoaSBpbiAxOm5yb3coaGFiKSkgew0KICBjdXJyX3RyYW5zZWN0PC0gaGFiJFRyYW5zZWN0W2ldDQogIG1pZF90aW1lPC0gaGFiJHRpbWVzdGFtcFtpXQ0KICBzdF90aW1lPC0gbWlkX3RpbWUtZHNlY29uZHMoNy41KQ0KICBlbmRfdGltZTwtICBtaWRfdGltZStkc2Vjb25kcyg3LjUpDQogIA0KICBjdXJyX2FsdDwtIG1lZGlhbihhbHRpdHVkZSRhbHRpdHVkZVthbHRpdHVkZSR0aW1lc3RhbXBfZXhhY3Q+PXN0X3RpbWUgJiBhbHRpdHVkZSR0aW1lc3RhbXBfZXhhY3Q8PWVuZF90aW1lXSkNCiAgY3Vycl9waXRjaDwtIG1lZGlhbihjb21wYXNzJHBpdGNoW2NvbXBhc3MkdGltZXN0YW1wX2V4YWN0Pj1zdF90aW1lICYgY29tcGFzcyR0aW1lc3RhbXBfZXhhY3Q8PWVuZF90aW1lXSkNCiAgY3Vycl9zcGVlZDwtIG1lZGlhbihTcGVlZCRTcGVlZF9tcHNbU3BlZWQkdGltZXN0YW1wX2V4YWN0Pj1zdF90aW1lICYgU3BlZWQkdGltZXN0YW1wX2V4YWN0PD1lbmRfdGltZV0pDQogIA0KICBjdXJyX3dpZHRoPC0gY2FsY193aWR0aChhbHQgPSBjdXJyX2FsdCwgcGl0Y2ggPSBjdXJyX3BpdGNoLCBjYW1fYW5nbGUgPSAzMi44LCBIX0FGT1ZfYWlyID0gSF9BRk9WX2FpcikNCiAgY3Vycl9kaXN0PC0gY3Vycl9zcGVlZCAqIDE1DQogIA0KICBoYWIkQXJlYVtpXTwtIGN1cnJfd2lkdGgqY3Vycl9kaXN0DQogIH0NCmBgYA0KDQojIyBNZXJnZSBzZXF1ZW50aWFsIG9ic2VydmF0aW9ucyBvZiB0aGUgc2FtZSBoYWJpdGF0IGNsYXNzDQoNCkNvbnNlY3V0aXZlIG9ic2VydmF0aW9ucyBvZiBoYWJpdGF0IGFyZSBjb2xsYXBzZWQgaW50byBhIHNpbmdsZSBzYW1wbGUgZm9yIGNvbW11bml0eSBhbmFseXNpcyBhbmQgY291bnRzIGFyZSBzdW1tZWQgYW1vbmcgdGhlIG1lcmdlZCBvYnNlcnZhdGlvbnMuIFRoaXMgaXMgZG9uZSB0byByZWR1Y2UgdGhlIGFtb3VudCBvZiByb3dzIHdpdGggYWxsIHplcm8gY291bnRzIHdoaWNoIGNhbm5vdCBiZSBoYW5kbGVkIHVzaW5nIHNlbWktbWV0cmljIGRpc3RhbmNlcyBzdWNoIGFzIEJyYXktQ3VydGlzLCBhbmQgYWxsb3dzIHVzIHRvIGtlZXAgbW9zdCBpbmZvcm1hdGlvbiBmcm9tIHNhbmR5IGhhYml0YXRzIHdoaWxlIGhhdmluZyBtb3JlIGJhbGFuY2UgaW4gc2FtcGxlIHNpemVzIGFjcm9zcyBoYWJpdGF0IGdyb3Vwcy4NCg0KYGBge3J9DQpoYWI8LSBoYWIgJT4lIG11dGF0ZShzYW1wX251bT1OQV9yZWFsXykNCmhhYiRzYW1wX251bVsxXTwtMQ0Kc2FtcF9udW08LTENCmZvciAoaSBpbiAyOm5yb3coaGFiKSkgew0KICBjdXJyX2hhYl9vYnM8LSBoYWIkaGFiaXRhdFtpXQ0KICBwcmV2X2hhYl9vYnM8LSBoYWIkaGFiaXRhdFtpLTFdDQogIGN1cnJfb2JzX3RyYW5zZWN0PC0gaGFiJFRyYW5zZWN0W2ldDQogIHByZXZfb2JzX3RyYW5zZWN0PC0gaGFiJFRyYW5zZWN0W2ktMV0NCiAgaWYoKGN1cnJfaGFiX29icyE9cHJldl9oYWJfb2JzKXwoY3Vycl9vYnNfdHJhbnNlY3QhPXByZXZfb2JzX3RyYW5zZWN0KXxpcy5uYShoYWIkQXJlYVtpXSkpew0KICAgIHNhbXBfbnVtPC0gc2FtcF9udW0rMQ0KICB9DQogIGhhYiRzYW1wX251bVtpXTwtc2FtcF9udW0NCn0NCg0KZmlzaF9oYWI8LSBmaXNoX2NvdW50cyAlPiUgbGVmdF9qb2luKGhhYiwgYnk9YygiVmlkIiwgIlNlYyIsICJ0aW1lc3RhbXAiLCAiVHJhbnNlY3QiKSkNCmZpc2hfaGFiPC0gZmlzaF9oYWIgJT4lIHNlbGVjdChUcmFuc2VjdCxWaWQsIFNlYywgdGltZXN0YW1wLCBzYW1wX251bSwgaGFiaXRhdCwgQXJlYSwgZXZlcnl0aGluZygpKQ0KDQpmaXNoX2hhYl9jb2xsYXBzZWQ8LSBmaXNoX2hhYiAlPiUgZ3JvdXBfYnkoc2FtcF9udW0pICU+JSANCiAgc3VtbWFyaXplKGhhYml0YXQ9dW5pcXVlKGhhYml0YXQpLCBWaWRfbWluID0gZmlyc3QoVmlkKStmaXJzdChTZWMpLzYwLCBWaWRfbWF4PSBsYXN0KFZpZCkrbGFzdChTZWMpLzYwLCBhY3Jvc3MoQXJlYTpzbW5vaWRfc21ub2lkLCAuZm5zID0gc3VtKSwgLmdyb3Vwcz0iZHJvcCIpDQoNCnByaW50KGZpc2hfaGFiX2NvbGxhcHNlZCkNCmBgYA0KDQojIyBUcmFuc2Zvcm0gRGF0YQ0KDQpUbyBhY2NvdW50IGZvciB1bmVxdWFsIGxlbmd0aHMgb2YgdGhlIHNhbXBsZXMsIGNvdW50cyBhcmUgZGl2aWRlZCBieSB0aGUgYXJlYSBkdXJhdGlvbi4gQWRkaXRpb25hbGx5IHRvIGRvd24td2VpZ2h0IG92ZXIgYWJ1bmRhbnQgdGF4YSwgZGVuc2l0aWVzIGFyZSBzcXVhcmUgcm9vdCB0cmFuc2Zvcm1lZC4NCg0KYGBge3J9DQpkZW5zX2hhYl9jb2xsYXBlZDwtIGZpc2hfaGFiX2NvbGxhcHNlZCAlPiUgbXV0YXRlKGFjcm9zcyhhbWJlcmphY2tfc3BwOnNtbm9pZF9zbW5vaWQpL0FyZWEpDQpzcV9kZW5zX2hhYl9jb2xsYXBlZDwtIGRlbnNfaGFiX2NvbGxhcGVkICU+JSBtdXRhdGUoYWNyb3NzKGFtYmVyamFja19zcHA6c21ub2lkX3Ntbm9pZCwgLmZucz1zcXJ0KSkNCnNxX2RlbnNfaGFiX2NvbGxhcGVkPC0gc3FfZGVuc19oYWJfY29sbGFwZWQgJT4lIGZpbHRlcighaXMubmEoQXJlYSkgJiBoYWJpdGF0IT0iTm9fVmlzIikNCnNxX2RlbnNfaGFiX2NvbGxhcGVkPC0gc3FfZGVuc19oYWJfY29sbGFwZWQgJT4lIHNlbGVjdCgtYyhzbW5vaWRfc21ub2lkLCBsZ25vaWRfbGdub2lkKSkNCnNxX2RlbnM8LSBzcV9kZW5zX2hhYl9jb2xsYXBlZCAlPiUgc2VsZWN0KC1jKHNhbXBfbnVtLCBoYWJpdGF0LCBWaWRfbWluLCBWaWRfbWF4LCBBcmVhKSkgDQpjb21tX2hhYjwtIHNxX2RlbnNfaGFiX2NvbGxhcGVkICU+JSBzZWxlY3QoaGFiaXRhdCkNCmlkeDwtIHJvd1N1bXMoc3FfZGVucyk+MCAjQnJheSBDdXJ0aXMgZGlzdGFuY2UgY2Fubm90IGNhbGN1bGF0ZSBkaXN0YW5jZSBpbiByb3dzIHdpdGggYWxsIHplcm9zDQpzcV9kZW5zPC0gc3FfZGVuc1tpZHgsXQ0KY29tbV9oYWI8LSBjb21tX2hhYltpZHgsXQ0KY29tbV9oYWIkaGFiaXRhdDwtIGZhY3Rvcihjb21tX2hhYiRoYWJpdGF0LCBsZXZlbHM9IGMoIlNhbmQiLCAiTG93X1JlbGllZiIsICJNb2RlcmF0ZV9SZWxpZWYiLCAiSGlnaF9SZWxpZWYiKSkNCmBgYA0KDQojIyBQRVJNQU5PVkENCg0KIyMjIENoZWNrIG1lZXQgYXNzdW1wdGlvbiBvZiBob21vZ2Vub3VzIGRpc3BlcnNpb24NCg0KYGBge3J9DQpzZXQuc2VlZCg1KQ0KcGVybWRpc3BfcmVzPC0gcGVybXV0ZXN0KGJldGFkaXNwZXIodmVnZGlzdChzcV9kZW5zLCBtZXRoZD0iYnJheSIpLCBncm91cD0gY29tbV9oYWIkaGFiaXRhdCwgdHlwZSA9ICJtZWRpYW4iKSwgcGVybXV0YXRpb25zID0gOTk5OSkNCmBgYA0KDQpwID0gYHIgcGVybWRpc3BfcmVzJHRhYltbIlByKD5GKSJdXVsxXWANCg0KcCBcPiAuMDUgc28gd2UgbWVldCB0aGUgYXNzdW10aW9uIG9mIGhvbW9nZW5laXR5IG9mIG11bHRpdmFyaWF0ZSBkaXNwZXJzaW9uIGFtb25nIGdyb3VwcyBhbmQgY2FuIHRoZXJlZm9yZSBwcm9jZWR1cmUgd2l0aCB0aGUgUEVSTUFOT1ZBDQoNCiMjIyBDb25kdWN0IGdsb2JhbCB0ZXN0DQoNCmBgYHtyfQ0Kc2V0LnNlZWQoNikNClBFUk1BTk9WQV9yZXM8LSBhZG9uaXMoc3FfZGVuc35oYWJpdGF0LCBkYXRhPWNvbW1faGFiLCBwZXJtdXRhdGlvbnM9OTk5LCBtZXRob2QgPSAiYnJheSIpDQpwcmludChQRVJNQU5PVkFfcmVzKQ0KYGBgDQoNClNpbmNlIHAgXDwgLjA1IGluIHRoZSBQRVJNQU5PVkEsIHdlIGNvbmNsdWRlIHRoYXQgdGhlcmUgYXJlIHNpZ2lmaWNhbnQgZGlmZmVyZW5jZXMgaW4gdGhlIGZpc2ggY29tbXVuaXRpZXMgYW1vbmcgdGhlIGRpZmZlcmVudCBoYWJpdGF0cw0KDQojIyMgQ29uZHVjdCBQYWlyLXdpc2UgVGVzdA0KDQpUbyBzZWUgd2hpY2ggaGFiaXRhdHMgaGF2ZSBmaXNoIGNvbW11bml0aWVzIHRoYXQgZGlmZmVyIGZyb20gYW5vdGhlciwgd2UgZm9sbG93IHVwIHRoZSBnbG9iYWwgdGVzdCB3aXRoIHBhaXJ3aXNlIFBFUk1BTk9WQSB0ZXN0cw0KDQpgYGB7cn0NCnNldC5zZWVkKDcpDQpQV19jb21wPC0gYWRvbmlzX1BXKGZvcm11bGEgPSBzcV9kZW5zfmhhYml0YXQsIGRhdGE9Y29tbV9oYWIsIHBlcm11dGF0aW9ucyA9IDk5OTksIG1ldGhvZCA9ICJicmF5IikNCmBgYA0KDQpUYWJsZSBvZiBwYWlyd2lzZSBjb21wYXJpc29ucw0KDQpgYGB7ciBlY2hvPUZBTFNFfQ0KcHJpbnQobXV0YXRlKGRwbHlyOjpzZWxlY3QoUFdfY29tcCwgLXApLCBGX3JhdGlvPXJvdW5kKEZfcmF0aW8sMikpKQ0KYGBgDQoNCnBfaG9sbSByZXByZXNlbnRzIGEgcC12YWx1ZSBhZGp1c3RlZCBmb3JmIG11bHRpcGxlIGNvbXBhcmlzb25zIHVzaW5nIGEgSG9sbSdzIHNlcXVlbnRpYWwgQm9uZmVycm9uaSBjb3JyZWN0aW9uLiBUaGUgYWRqdXN0ZWQgcCB2YWx1ZSBpcyBsZXNzIHRoYW4gLjA1IGZvciBhbGwgY29tcGFyaXNvbnMgZXhjZXB0IGZvciBiZXR3ZWVuIG1vZGVyYXRlIGFuZCBoaWdoIHJlbGllZiByb2NrLCBpbmRpY2F0aW5nIHRoYXQgbW9kZXJhdGUgYW5kIGhpZ2ggcmVsaWVmIHJvY2sgZGlkIG5vdCBoYXZlIHNpZ25pZmljYW50bHkgZGlmZmVyZW50IGZpc2ggY29tbXVuaXRpZXMgZnJvbSBvbmUgYW5vdGhlciwgYnV0IGFsbCBvdGhlciBoYWJpdGF0cyBkaWQuDQoNCiMjIENhbm9uaWNhbCBBbmFseXNpcyBvZiBQcmluY2lwYWwgQ29vcmRpbmF0ZXMNCg0KRmlndXJlIFMyLjINCmBgYHtyIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQ0KQ0FQX3Jlc3VsdDwtIENBUGRpc2NyaW0oYXMuZGF0YS5mcmFtZShzcV9kZW5zKX5oYWJpdGF0LCBkYXRhPWFzLmRhdGEuZnJhbWUoY29tbV9oYWIpLCBkaXN0PSJicmF5IiwgbT0wLCBhZGQ9RkFMU0UpDQpDQVBfUGxvdDwtIHBsb3RfQ0FQKENBUF9yZXN1bHQgPSBDQVBfcmVzdWx0LCBZID0gc3FfZGVucywgR3JvdXAgPSBjb21tX2hhYiRoYWJpdGF0LCBuX3NwZWMgPSAxNSwgY29sb3IgPSBjKCJibGFjayIsICJibHVlIiwgIm9yYW5nZSIsICJyZWQiKSwgbGVnZW5kX3RpdGxlID0gIkhhYml0YXQiKQ0KcGxvdChDQVBfUGxvdCkNCmBgYA0KDQojIEZpc2ggQWJ1bmRhbmNlIEVzdGltYXRlcw0KDQojIyBIYWJpdGF0IFNwZWNpZmljIERlbnNpdGllcw0KDQpgYGB7cn0NCmZpc2hfaGFiMjwtIGZpc2hfaGFiICU+JSBmaWx0ZXIoIWlzLm5hKEFyZWEpICYgaGFiaXRhdCE9Ik5vX1ZpcyIpDQpmaXNoX2hhYjI8LSBmaXNoX2hhYjIgJT4lIG11dGF0ZShoYWJpdGF0PWlmZWxzZSh0ZXN0ID0gaGFiaXRhdCAlaW4lIGMoIk1vZGVyYXRlX1JlbGllZiIsICJIaWdoX1JlbGllZiIpLCB5ZXMgPSAiTW9kL0hpZ2hfUmVsaWVmIiwgbm8gPSBoYWJpdGF0KSkNCmZpc2hfaGFiMjwtIGZpc2hfaGFiMiAlPiUgc2VsZWN0KC1zbW5vaWRfc21ub2lkKSAlPiUgbXV0YXRlKEFsbF9GaXNoPSByb3dTdW1zKGFjcm9zcyhhbWJlcmphY2tfc3BwOmxnbm9pZF9sZ25vaWQpKSkgJT4lIHNlbGVjdCgtbGdub2lkX2xnbm9pZCkgI0NhbGN1bGF0ZSB0b3RhbCBmaXNoIGluY2x1ZGUgbGFyZ2Ugbm8gaWQncyB0aGVuIHJlbW92ZSBsYXJnZSBubyBpZCdzDQoNCmhhYl90eXBlczwtIHVuaXF1ZShmaXNoX2hhYjIkaGFiaXRhdCkNCg0KZm9yIChpIGluIDE6bGVuZ3RoKGhhYl90eXBlcykpIHsNCiAgY3Vycl9maXNoX2hhYjwtIGZpc2hfaGFiMiAlPiUgZmlsdGVyKGhhYml0YXQ9PWhhYl90eXBlc1tpXSkNCiAgc2V0LnNlZWQoaSkNCiAgY3Vycl9hdmdfZGVuczwtIGF2Z19kZW5zaXR5KGNvdW50cyA9c2VsZWN0KGN1cnJfZmlzaF9oYWIsIGFtYmVyamFja19zcHA6QWxsX0Zpc2gpLCBhcmVhID0gY3Vycl9maXNoX2hhYiRBcmVhLCBpdGVyPTEwMDAsIGNvbmYgPSAuOTUpDQogIGN1cnJfYXZnX2RlbnM8LSBjdXJyX2F2Z19kZW5zICU+JSBtdXRhdGUoVHlwZT0gYygibG93ZXJfYm91bmQiLCAibWVhbiIsICJ1cHBlcl9ib3VuZCIpKQ0KICBjdXJyX2F2Z19kZW5zPC0gY3Vycl9hdmdfZGVucyAlPiUgcGl2b3RfbG9uZ2VyKGNvbHMgPSAtVHlwZSwgbmFtZXNfdG89IlRheGEiLCB2YWx1ZXNfdG89IkRlbnNpdHkiKSAjVGlkeQ0KICBjdXJyX2F2Z19kZW5zPC0gY3Vycl9hdmdfZGVucyAlPiUgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IFR5cGUsIHZhbHVlc19mcm9tPSBEZW5zaXR5KQ0KICBjdXJyX2F2Z19kZW5zPC0gY3Vycl9hdmdfZGVucyAlPiUgbXV0YXRlKGhhYml0YXQ9aGFiX3R5cGVzW2ldKQ0KICBjdXJyX2F2Z19kZW5zPC0gY3Vycl9hdmdfZGVucyAlPiUgc2VsZWN0KFRheGEsIGhhYml0YXQsIGxvd2VyX2JvdW5kLCBtZWFuLCB1cHBlcl9ib3VuZCkNCiAgaWYoaT09MSl7DQogICAgYXZnX2RlbnM8LSBjdXJyX2F2Z19kZW5zfWVsc2V7DQogICAgICBhdmdfZGVuczwtIGF2Z19kZW5zICU+JSBiaW5kX3Jvd3MoY3Vycl9hdmdfZGVucykNCiAgICAgIH0NCiAgfQ0KYXZnX2RlbnMkaGFiaXRhdDwtIGZhY3RvcihhdmdfZGVucyRoYWJpdGF0LCBsZXZlbHMgPSBjKCJTYW5kIiwgIkxvd19SZWxpZWYiLCAiTW9kL0hpZ2hfUmVsaWVmIikpDQphdmdfZGVuczwtIGF2Z19kZW5zICU+JSBhcnJhbmdlKFRheGEsIGhhYml0YXQpDQpgYGANCg0KYGBge3IgaW5jbHVkZT1GQUxTRX0NCm1heF9kZW5zX2hhYl90YWJsZTwtIGF2Z19kZW5zICU+JSBmaWx0ZXIoVGF4YSE9IkFsbF9GaXNoIikgJT4lIGdyb3VwX2J5KFRheGEpICU+JSBmaWx0ZXIobWVhbj09bWF4KG1lYW4pKSAlPiUgdW5ncm91cCgpICU+JSBncm91cF9ieShoYWJpdGF0KSAlPiUgc3VtbWFyaXplKG49bigpLCAuZ3JvdXBzPSJkcm9wIikNCmBgYA0KRmlzaCBkZW5zaXRpZXMgd2VyZSBlc3RpbWF0ZWQgYnkgaGFiaXRhdCB0eXBlIGZvciBgciBsZW5ndGgodW5pcXVlKGF2Z19kZW5zJFRheGEpKS0xYCBzcGVjaWVzIG9yIHNwZWNpZXMgZ3JvdXBzLCBhcyB3ZWxsIGFzIGZvciBhbGwgZmlzaCBjb21iaW5lZC4gRm9yIG1vc3QgdGF4YSAoYHIgbWF4X2RlbnNfaGFiX3RhYmxlICU+JSBmaWx0ZXIoaGFiaXRhdCE9IlNhbmQiKSAlPiUgcHVsbChuKSAlPiUgc3VtKClgIG9mIHRoZSBgciBsZW5ndGgodW5pcXVlKGF2Z19kZW5zJFRheGEpKS0xYCBzcGVjaWVzL3NwZWNpZXMgZ3JvdXBzKSwgYXZlcmFnZSBmaXNoIGRlbnNpdHkgd2FzIGhpZ2hlc3Qgb3ZlciByb2NreSBoYWJpdGF0cywgYW5kIG9ubHkgYHIgbWF4X2RlbnNfaGFiX3RhYmxlICU+JSBmaWx0ZXIoaGFiaXRhdD09IlNhbmQiKSAlPiUgcHVsbChuKSAlPiUgc3VtKClgIHNwZWNpZXMgaGFkIHRoZWlyIGhpZ2hlc3QgZGVuc2l0aWVzIG92ZXIgc2FuZC4gT2YgdGhlIGByIG1heF9kZW5zX2hhYl90YWJsZSAlPiUgZmlsdGVyKGhhYml0YXQhPSJTYW5kIikgJT4lIHB1bGwobikgJT4lIHN1bSgpYCB0YXhhIHRoYXQgaGFkIGhpZ2hlc3QgZGVuc2l0aWVzIG92ZXIgYSByb2NreSBoYWJpdGF0LCBgciBtYXhfZGVuc19oYWJfdGFibGUgJT4lIGZpbHRlcihoYWJpdGF0PT0iTW9kL0hpZ2hfUmVsaWVmIikgJT4lIHB1bGwobikgJT4lIHN1bSgpYCBoYWQgaGFkIHRoZWlyIGhpZ2hlc3QgZGVuc2l0aWVzIG92ZXIgbW9kZXJhdGUtaGlnaCByZWxpZWYgcm9jayBhbmQgYHIgbWF4X2RlbnNfaGFiX3RhYmxlICU+JSBmaWx0ZXIoaGFiaXRhdD09Ikxvd19SZWxpZWYiKSAlPiUgcHVsbChuKSAlPiUgc3VtKClgIGhhZCB0aGVpciBoaWdoZXN0IGRlbnNpdGllcyBvdmVyIGxvdyByZWxpZWYgcm9jay4gDQoNClRhYmxlIG9mIG1lYW4gZmlzaCBkZW5zaXRpZXMgcGVyIFRheGEgaW4gbnVtYmVycyBvZiBmaXNoIHBlciBraWxvbWV0ZXIgc3F1YXJlZCB3aXRoIHRoZSBsb3dlciBhbmQgdXBwZXIgYm91bmRzIG9mIHRoZSA5NSUgYm9vdHN0cmFwIGNvbmZpZGVuY2UgaW50ZXJ2YWxzDQoNCmBgYHtyIGVjaG89RkFMU0V9DQptdXRhdGUoYXZnX2RlbnMsIHJvdW5kKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSkqMWU2KSwyKQ0KYGBgDQoNClBsb3Qgb2Ygc2VsZWN0ZWQgVGF4YSBmcm9tIHRhYmxlDQoNCkZpZ3VyZSBTMi4zDQpgYGB7ciBlY2hvPUZBTFNFLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04fQ0KI1Bsb3QNCnNlbF90YXhhPC0gYygiQWxsX0Zpc2giLCAiamFja19hbWJlcmphY2siLCAiYmlnZXllX3NwcCIsICJhbmdlbGZpc2hfYmx1ZSIsICJncm91cGVyX2NyZW9sZWZpc2giLCAic25hcHBlcl9ncmF5IiwgImxpb25maXNoX3NwcCIsICJwb3JneV9zcHAiLCAidGlsZWZpc2hfc2FuZCIsICAic3F1aXJyZWxmaXNoX3NwcCIpICNUYXhhIHRvIHBsb3QNCmF2Z19kZW5zX3NlbDwtIGF2Z19kZW5zICU+JSBmaWx0ZXIoVGF4YSAlaW4lIHNlbF90YXhhKQ0KDQphdmdfZGVuc19zZWwkVGF4YVthdmdfZGVuc19zZWwkVGF4YT09IkFsbF9GaXNoIl08LSAiQWxsIEZpc2hlcyINCmF2Z19kZW5zX3NlbCRUYXhhW2F2Z19kZW5zX3NlbCRUYXhhPT0iYW5nZWxmaXNoX2JsdWUiXTwtICJCbHVlIEFuZ2VsZmlzaCINCmF2Z19kZW5zX3NlbCRUYXhhW2F2Z19kZW5zX3NlbCRUYXhhPT0iYmlnZXllX3NwcCJdPC0gIkJpZ2V5ZXMiDQphdmdfZGVuc19zZWwkVGF4YVthdmdfZGVuc19zZWwkVGF4YT09Imxpb25maXNoX3NwcCJdPC0gIkxpb25maXNoZXMiDQphdmdfZGVuc19zZWwkVGF4YVthdmdfZGVuc19zZWwkVGF4YT09InBvcmd5X3NwcCJdPC0gIlBvcmdpZXMiDQphdmdfZGVuc19zZWwkVGF4YVthdmdfZGVuc19zZWwkVGF4YT09InNuYXBwZXJfZ3JheSJdPC0gIkdyYXkgU25hcHBlciINCmF2Z19kZW5zX3NlbCRUYXhhW2F2Z19kZW5zX3NlbCRUYXhhPT0ic3F1aXJyZWxmaXNoX3NwcCJdPC0gIlNxdWlycmVsZmlzaGVzIg0KYXZnX2RlbnNfc2VsJFRheGFbYXZnX2RlbnNfc2VsJFRheGE9PSJ0aWxlZmlzaF9zYW5kIl08LSAiU2FuZCBUaWxlZmlzaCINCmF2Z19kZW5zX3NlbCRUYXhhW2F2Z19kZW5zX3NlbCRUYXhhPT0iamFja19hbWJlcmphY2siXTwtICJBbWJlcmphY2tzIg0KYXZnX2RlbnNfc2VsJFRheGFbYXZnX2RlbnNfc2VsJFRheGE9PSJncm91cGVyX2NyZW9sZWZpc2giXTwtICJDcmVvbGVmaXNoIiAjQ2xlYW4gbmFtZXMgZm9yIHBsb3R0aW5nDQoNCmRlbnNfcGxvdDwtIGdncGxvdChkYXRhPSBhdmdfZGVuc19zZWwsIG1hcHBpbmc9YWVzKHg9aGFiaXRhdCkpKw0KICBnZW9tX2NvbChtYXBwaW5nPWFlcyhmaWxsPWhhYml0YXQsIHkgPSBtZWFuKSwgY29sb3I9ImJsYWNrIikrDQogIGZhY2V0X3dyYXAoflRheGEsIHNjYWxlcz0iZnJlZV95IiwgbmNvbCA9IDMpKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiI0ZGRUJCRSIsICJkb2RnZXJibHVlIiwgInJlZCIpKSsNCiAgZ2VvbV9lcnJvcmJhcihtYXBwaW5nPSBhZXMoeW1pbj0gbG93ZXJfYm91bmQsIHltYXg9dXBwZXJfYm91bmQpLCB3aWR0aD0uMykrDQogIHhsYWIoIiIpKw0KICB5bGFiKGJxdW90ZSgnRGVuc2l0eSAoIyBvZiBJbmRpdmlkdWFscyAvIG0gJyBeMiB+JyknKSkrDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKSsNCiAgdGhlbWUoc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikpDQpkZW5zX3Bsb3QNCmBgYA0KDQojIyBIYWJpdGF0IE1hcA0KDQpgYGB7cn0NCmhhYl9tYXA8LSByYXN0ZXIoIlByb2R1Y3RzL01hcHBpbmcvRWxib3dfU3VwZXJ2aXNlZF9IYWJSZWxpZWYudGlmIikNCmhhYl9tYXA8LSByZWNsYXNzaWZ5KGhhYl9tYXAsIG1hdHJpeChkYXRhPWMoMjEsIDEsIDExLCAyLCAxMiwgMywgMTMsIDMpLCBuY29sID0gMiwgYnlyb3cgPSBUUlVFKSkgI01lcmdlIE1vZGVyYXRlIGFuZCBIaWdoIFJlbGllZg0KaGFiX21hcDwtIGFzLmZhY3RvcihoYWJfbWFwKQ0KbGV2ZWxzKGhhYl9tYXApW1sxXV0kaGFiaXRhdDwtIGMoIlNhbmQiLCAiTFIiLCAiTVIvSFIiKQ0KYGBgDQoNCkZpZ3VyZSBTMi40DQpgYGB7ciBlY2hvPUZBTFNFLCBmaWcuaGVpZ2h0PTksIGZpZy53aWR0aD02fQ0KdG1fc2hhcGUoaGFiX21hcCwgcmFzdGVyLmRvd25zYW1wbGUgPSBGQUxTRSkrDQogIHRtX3Jhc3Rlcih0aXRsZSA9ICJIYWJpdGF0IiwgcGFsZXR0ZT0gYygiI0ZGRUJCRSIsICJkb2RnZXJibHVlIiwgInJlZCIpKQ0KYGBgDQoNCmBgYHtyIGVjaG89RkFMU0V9DQpoYWJfYXJlYTwtIGFzLmRhdGEuZnJhbWUoZnJlcShoYWJfbWFwLCB1c2VOQT0ibm8iKSkNCmhhYl9hcmVhJGhhYml0YXQ8LSBjKCJTYW5kIiwgIkxvd19SZWxpZWYiLCAiTW9kL0hpZ2hfUmVsaWVmIikNCmhhYl9hcmVhPC0gaGFiX2FyZWEgJT4lIG11dGF0ZShBcmVhX20yPSBwcm9kKHJlcyhhbGxfb2YoaGFiX21hcCkpKSpjb3VudCkNCmhhYl9hcmVhPC0gaGFiX2FyZWEgJT4lIG11dGF0ZShBcmVhX2ttMj0gQXJlYV9tMi8xZTYpDQpwcmludChoYWJfYXJlYSAlPiUgZHBseXI6OnNlbGVjdChoYWJpdGF0LCBBcmVhX2ttMikpDQpgYGANCg0KIyMgU2NhbGUgRGVuc2l0aWVzIHVwIHRvIEFidW5kYW5jZQ0KDQpNdWx0aXBseSBkZW5zaXRpZXMgb2YgdGF4YSBmb3IgZWFjaCBoYWJpdGF0IGJ5IHRoZSBjb3JyZXNwb25kaW5nIGFyZWEgb2YgdGhlIGhhYml0YXQgdG8gZ2V0IGFidW5kYW5jZQ0KDQpgYGB7cn0NCmFiZDwtIGF2Z19kZW5zICU+JSBsZWZ0X2pvaW4oaGFiX2FyZWEsIGJ5PSJoYWJpdGF0IikgJT4lIA0KICBtdXRhdGUoYWNyb3NzKGMobG93ZXJfYm91bmQsIG1lYW4sIHVwcGVyX2JvdW5kKSkqQXJlYV9tMikgJT4lDQogIGRwbHlyOjpzZWxlY3QoVGF4YSwgaGFiaXRhdCwgbG93ZXJfYm91bmQsIG1lYW4sIHVwcGVyX2JvdW5kKQ0KYWJkPC0gYmluZF9yb3dzKChhYmQgJT4lIGdyb3VwX2J5KFRheGEpICU+JSBzdW1tYXJpemUoaGFiaXRhdD0iVG90YWwiLCBhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYyksIC5mbnM9c3VtKSwgLmdyb3Vwcz0iZHJvcCIpKSwgYWJkKQ0KYWJkJGhhYml0YXQ8LSBmYWN0b3IoYWJkJGhhYml0YXQsIGxldmVscyA9IGMoIlRvdGFsIiwgIlNhbmQiLCAiTG93X1JlbGllZiIsICJNb2QvSGlnaF9SZWxpZWYiKSkNCmFiZDwtIGFiZCAlPiUgYXJyYW5nZShUYXhhLCBoYWJpdGF0KQ0KYGBgDQoNClRhYmxlIG9mIGFidW5kYW5jZSBlc3RpbWF0ZXMNCg0KYGBge3IgZWNobz1GQUxTRX0NCm11dGF0ZShhYmQsIGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSwgLmZucyA9IHJvdW5kKSkNCmBgYA0KDQpgYGB7ciBlY2hvPUZBTFNFfQ0KdG90X251bTwtIGFiZCAlPiUgZmlsdGVyKFRheGE9PSJBbGxfRmlzaCIgJiBoYWJpdGF0PT0iVG90YWwiKSAlPiUgcHVsbChtZWFuKQ0Kc2FuZF9udW08LSBhYmQgJT4lIGZpbHRlcihUYXhhPT0iQWxsX0Zpc2giICYgaGFiaXRhdD09IlNhbmQiKSAlPiUgcHVsbChtZWFuKQ0KbG93X251bTwtIGFiZCAlPiUgZmlsdGVyKFRheGE9PSJBbGxfRmlzaCIgJiBoYWJpdGF0PT0iTG93X1JlbGllZiIpICU+JSBwdWxsKG1lYW4pDQptaF9udW08LSBhYmQgJT4lIGZpbHRlcihUYXhhPT0iQWxsX0Zpc2giICYgaGFiaXRhdD09Ik1vZC9IaWdoX1JlbGllZiIpICU+JSBwdWxsKG1lYW4pDQpgYGANCg0KVGhlcmUgYXJlIGVzdGltYXRlZCB0byBiZSBhIHRvdGFsIG9mIGFwcHJveGltYXRlbHkgYHIgYXMuaW50ZWdlcihyb3VuZCh0b3RfbnVtKSlgIGZpc2ggaW4gdG90YWwgd2l0aGluIHRoZSBzdHVkeSBhcmVhLiBPZiB0aGVzZSwgYHIgYXMuaW50ZWdlcihyb3VuZChzYW5kX251bSkpYCAoYHIgcm91bmQoMTAwKnNhbmRfbnVtL3RvdF9udW0pYCUpIGFyZSBvbiBzYW5kLCBgciBhcy5pbnRlZ2VyKHJvdW5kKGxvd19udW0pKWAgKGByIHJvdW5kKDEwMCpsb3dfbnVtL3RvdF9udW0pYCUpIGFyZSBvbiBsb3cgcmVsaWVmIHJvY2ssIGFuZCBgciBhcy5pbnRlZ2VyKHJvdW5kKG1oX251bSkpYCAoYHIgcm91bmQoMTAwKm1oX251bS90b3RfbnVtKWAlKWAgYXJlIG9uIG1vZGVyYXRlIHRvIGhpZ2ggcmVsaWVmIHJvY2suDQoNClBsb3Qgb2YgZXN0aW1hdGVkIGFidW5kYW5jZSBmb3Igc2VsZWN0IHNwZWNpZXMNCg0KRmlndXJlIFMyLjUNCmBgYHtyIGVjaG89RkFMU0UsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTh9DQphYmRfc2VsPC0gYWJkICU+JSBmaWx0ZXIoVGF4YSAlaW4lIHNlbF90YXhhKQ0KDQphYmRfc2VsJFRheGFbYWJkX3NlbCRUYXhhPT0iQWxsX0Zpc2giXTwtICJBbGwgRmlzaGVzIg0KYWJkX3NlbCRUYXhhW2FiZF9zZWwkVGF4YT09ImFuZ2VsZmlzaF9ibHVlIl08LSAiQmx1ZSBBbmdlbGZpc2giDQphYmRfc2VsJFRheGFbYWJkX3NlbCRUYXhhPT0iYmlnZXllX3NwcCJdPC0gIkJpZ2V5ZXMiDQphYmRfc2VsJFRheGFbYWJkX3NlbCRUYXhhPT0ibGlvbmZpc2hfc3BwIl08LSAiTGlvbmZpc2hlcyINCmFiZF9zZWwkVGF4YVthYmRfc2VsJFRheGE9PSJwb3JneV9zcHAiXTwtICJQb3JnaWVzIg0KYWJkX3NlbCRUYXhhW2FiZF9zZWwkVGF4YT09InNuYXBwZXJfZ3JheSJdPC0gIkdyYXkgU25hcHBlciINCmFiZF9zZWwkVGF4YVthYmRfc2VsJFRheGE9PSJzcXVpcnJlbGZpc2hfc3BwIl08LSAiU3F1aXJyZWxmaXNoZXMiDQphYmRfc2VsJFRheGFbYWJkX3NlbCRUYXhhPT0idGlsZWZpc2hfc2FuZCJdPC0gIlNhbmQgVGlsZWZpc2giDQphYmRfc2VsJFRheGFbYWJkX3NlbCRUYXhhPT0iamFja19hbWJlcmphY2siXTwtICJBbWJlcmphY2tzIg0KYWJkX3NlbCRUYXhhW2FiZF9zZWwkVGF4YT09Imdyb3VwZXJfY3Jlb2xlZmlzaCJdPC0gIkNyZW9sZWZpc2giICNDbGVhbiBuYW1lcyBmb3IgcGxvdHRpbmcNCg0KYWJkX3Bsb3Q8LSBnZ3Bsb3QoZGF0YT0gYWJkX3NlbCwgbWFwcGluZz1hZXMoeD1oYWJpdGF0KSkrDQogIGdlb21fY29sKG1hcHBpbmc9YWVzKGZpbGw9aGFiaXRhdCwgeSA9IG1lYW4pLCBjb2xvcj0iYmxhY2siKSsNCiAgZmFjZXRfd3JhcCh+VGF4YSwgc2NhbGVzPSJmcmVlX3kiLCBuY29sID0gMykrDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJwdXJwbGUiLCAiI0ZGRUJCRSIsICJkb2RnZXJibHVlIiwgInJlZCIpKSsNCiAgZ2VvbV9lcnJvcmJhcihtYXBwaW5nPSBhZXMoeW1pbj0gbG93ZXJfYm91bmQsIHltYXg9dXBwZXJfYm91bmQpLCB3aWR0aD0uMykrDQogIHhsYWIoIiIpKw0KICB5bGFiKCJBYnVuZGFuY2UiKSsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCkpKw0KICB0aGVtZShzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSkNCmFiZF9wbG90DQpgYGANCg0KYGBge3IgZWNobz1GQUxTRX0NCmdnc2F2ZShDQVBfUGxvdCwgZmlsZW5hbWUgPSAiQ0FQX1Bsb3QudGlmZiIsIGRldmljZSA9ICJ0aWZmIiwgd2lkdGggPSA4LCBoZWlnaHQgPSA2LCBwYXRoID0gIlByb2R1Y3RzL2ZpZ3VyZXMiLCB1bml0cyA9ICJpbiIsIGRwaSA9IDMwMCkNCmdnc2F2ZShkZW5zX3Bsb3QsIGZpbGVuYW1lID0gImRlbnNfcGxvdC50aWZmIiwgZGV2aWNlID0gInRpZmYiLCB3aWR0aCA9IDcsIGhlaWdodCA9IDksIHBhdGggPSAiUHJvZHVjdHMvZmlndXJlcyIsIHVuaXRzID0gImluIiwgZHBpID0gMzAwKQ0KZ2dzYXZlKGFiZF9wbG90LCBmaWxlbmFtZSA9ICJhYmRfcGxvdC50aWZmIiwgZGV2aWNlID0gInRpZmYiLCB3aWR0aCA9IDcsIGhlaWdodCA9IDksIHBhdGggPSAiUHJvZHVjdHMvZmlndXJlcyIsIHVuaXRzID0gImluIiwgZHBpID0gMzAwKQ0Kd3JpdGVfY3N2KGF2Z19kZW5zICU+JSBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLCAuZm5zID0gZm9ybWF0LCBzY2llbnRpZmljPUZBTFNFKSksIHBhdGggPSAiUHJvZHVjdHMvdGFibGVzL2Zpc2hfZGVucy5jc3YiKQ0Kd3JpdGVfY3N2KGFiZCAlPiUgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSwgLmZucz1yb3VuZCkpLCBwYXRoID0gIlByb2R1Y3RzL3RhYmxlcy9maXNoX2FiZC5jc3YiKQ0KYGBgDQoNCmBgYHtyIGVjaG89RkFMU0V9DQpzYXZlLmltYWdlKGZpbGUgPSAnRGF0YS9SX2Vudmlyb25tZW50L0VsYm93X1JfRmlzaF9FbnZpcm9ubWVudC5SRGF0YScpDQpgYGANCg==