Pre-processing
Firms data
Assign meaningful names and check the modified data:
[1] "CODGEO" "LIBGEO" "REG" "DEP" "E14TST" "E14TS0ND" "E14TS1"
[8] "E14TS6" "E14TS10" "E14TS20" "E14TS50" "E14TS100" "E14TS200" "E14TS500"
names(firms)[2:ncol(firms)] <-
c("town",
"regNum",
"deptNum",
"total",
"null",
"firmsEmpl_1_5",
"firmsEmpl_6_9",
"firmsEmpl_10_19",
"firmsEmpl_20_49",
"firmsEmpl_50_99",
"firmsEmpl_100_199",
"firmsEmpl_200_499",
"firmsEmpl_500plus")
# preliminary checks
names(firms)
[1] "CODGEO" "town" "regNum" "deptNum"
[5] "total" "null" "firmsEmpl_1_5" "firmsEmpl_6_9"
[9] "firmsEmpl_10_19" "firmsEmpl_20_49" "firmsEmpl_50_99" "firmsEmpl_100_199"
[13] "firmsEmpl_200_499" "firmsEmpl_500plus"
'data.frame': 36681 obs. of 14 variables:
$ CODGEO : Factor w/ 36681 levels "01001","01002",..: 1 2 3 4 5 6 7 8 9 10 ...
$ town : Factor w/ 34142 levels "Aast","Abainville",..: 13659 13661 442 444 460 480 484 581 638 802 ...
$ regNum : int 82 82 82 82 82 82 82 82 82 82 ...
$ deptNum : Factor w/ 101 levels "01","02","03",..: 1 1 1 1 1 1 1 1 1 1 ...
$ total : int 25 10 996 99 4 124 48 22 33 14 ...
$ null : int 22 9 577 73 4 87 28 17 23 11 ...
$ firmsEmpl_1_5 : int 1 1 272 20 0 20 15 4 8 2 ...
$ firmsEmpl_6_9 : int 2 0 63 3 0 10 2 1 1 1 ...
$ firmsEmpl_10_19 : int 0 0 46 1 0 5 3 0 0 0 ...
$ firmsEmpl_20_49 : int 0 0 24 2 0 2 0 0 0 0 ...
$ firmsEmpl_50_99 : int 0 0 9 0 0 0 0 0 0 0 ...
$ firmsEmpl_100_199: int 0 0 3 0 0 0 0 0 1 0 ...
$ firmsEmpl_200_499: int 0 0 2 0 0 0 0 0 0 0 ...
$ firmsEmpl_500plus: int 0 0 0 0 0 0 0 0 0 0 ...
CODGEO town regNum deptNum
01001 : 1 Sainte-Colombe: 14 Min. : 1.00 62 : 895
01002 : 1 Saint-Sauveur : 12 1st Qu.:25.00 02 : 816
01004 : 1 Beaulieu : 11 Median :43.00 80 : 782
01005 : 1 Sainte-Marie : 11 Mean :49.42 76 : 745
01006 : 1 Le Pin : 10 3rd Qu.:73.00 57 : 730
01007 : 1 Saint-Aubin : 10 Max. :94.00 14 : 706
(Other):36675 (Other) :36613 (Other):32007
total null firmsEmpl_1_5 firmsEmpl_6_9
Min. : 0.0 Min. : 0.0 Min. : 0.00 Min. : 0.000
1st Qu.: 8.0 1st Qu.: 6.0 1st Qu.: 1.00 1st Qu.: 0.000
Median : 19.0 Median : 14.0 Median : 3.00 Median : 0.000
Mean : 123.5 Mean : 83.6 Mean : 27.29 Mean : 5.221
3rd Qu.: 54.0 3rd Qu.: 39.0 3rd Qu.: 11.00 3rd Qu.: 2.000
Max. :427385.0 Max. :316603.0 Max. :76368.00 Max. :14836.000
firmsEmpl_10_19 firmsEmpl_20_49 firmsEmpl_50_99 firmsEmpl_100_199
Min. : 0.0 Min. : 0.000 Min. : 0.0000 Min. : 0.0000
1st Qu.: 0.0 1st Qu.: 0.000 1st Qu.: 0.0000 1st Qu.: 0.0000
Median : 0.0 Median : 0.000 Median : 0.0000 Median : 0.0000
Mean : 3.8 Mean : 2.296 Mean : 0.7383 Mean : 0.3324
3rd Qu.: 1.0 3rd Qu.: 1.000 3rd Qu.: 0.0000 3rd Qu.: 0.0000
Max. :10829.0 Max. :5643.000 Max. :1658.0000 Max. :812.0000
firmsEmpl_200_499 firmsEmpl_500plus
Min. : 0.0000 Min. : 0.00000
1st Qu.: 0.0000 1st Qu.: 0.00000
Median : 0.0000 Median : 0.00000
Mean : 0.1728 Mean : 0.04842
3rd Qu.: 0.0000 3rd Qu.: 0.00000
Max. :456.0000 Max. :180.00000
# Check for duplicated data: there is no
sum(duplicated.data.frame(firms))
[1] 0
Categorize firms’ size according to EU standard, but in a slightly different form for medium and large firms (i.e., medium firms have <200 instead of <250 employees):
# merge variables
firms$micro <- firms$firmsEmpl_1_5 + firms$firmsEmpl_6_9
firms$small <- firms$firmsEmpl_10_19 + firms$firmsEmpl_20_49
firms$medium <- firms$firmsEmpl_50_99 + firms$firmsEmpl_100_199
firms$large <- firms$firmsEmpl_200_499 + firms$firmsEmpl_500plus
# Drop unnecessary (at the moment) columns
firms <- subset(firms, select = c(CODGEO, town, total, micro, small, medium, large, null))
# check
summary(firms)
CODGEO town total micro
01001 : 1 Sainte-Colombe: 14 Min. : 0.0 Min. : 0.00
01002 : 1 Saint-Sauveur : 12 1st Qu.: 8.0 1st Qu.: 1.00
01004 : 1 Beaulieu : 11 Median : 19.0 Median : 4.00
01005 : 1 Sainte-Marie : 11 Mean : 123.5 Mean : 32.51
01006 : 1 Le Pin : 10 3rd Qu.: 54.0 3rd Qu.: 13.00
01007 : 1 Saint-Aubin : 10 Max. :427385.0 Max. :91204.00
(Other):36675 (Other) :36613
small medium large null
Min. : 0.000 Min. : 0.000 Min. : 0.0000 Min. : 0.0
1st Qu.: 0.000 1st Qu.: 0.000 1st Qu.: 0.0000 1st Qu.: 6.0
Median : 0.000 Median : 0.000 Median : 0.0000 Median : 14.0
Mean : 6.097 Mean : 1.071 Mean : 0.2212 Mean : 83.6
3rd Qu.: 2.000 3rd Qu.: 0.000 3rd Qu.: 0.0000 3rd Qu.: 39.0
Max. :16472.000 Max. :2470.000 Max. :636.0000 Max. :316603.0
# there is an obs with more than 316K null data: we check if it is plausible
# get the highest 20 null values
str_firms <- sort(firms$null, decreasing = T)[1:20]
# get their indexes
str_firms_ind <- match(str_firms, firms$null)
# get the corresponding city
firms$town[str_firms_ind]
[1] Paris Marseille Lyon Nice
[5] Toulouse Bordeaux Montpellier Nantes
[9] Strasbourg Lille Aix-en-Provence Boulogne-Billancourt
[13] Fort-de-France Rennes Grenoble Toulon
[17] Cannes Saint-Denis Neuilly-sur-Seine Nîmes
34142 Levels: Aast Abainville Abancourt Abaucourt Abaucourt-Hautecourt ... Zuytpeene
# they are the largest cities, hence it seems reasonable..
Geographical data
Assign names and remove some variables:
[1] "EU_circo" "code_région" "nom_région"
[4] "chef.lieu_région" "numéro_département" "nom_département"
[7] "préfecture" "numéro_circonscription" "nom_commune"
[10] "codes_postaux" "code_insee" "latitude"
[13] "longitude" "éloignement"
names(geo)[c(2:11, 14)] =
c("code_region",
"region",
"region_capital",
"number_depart",
"department",
"prefecture",
"circons",
"town_name",
"postal_code",
"CODGEO",
"eloignement")
# drop unnecessary columns (code/num and name represents same thing)
geo <- subset(geo, select = -c(EU_circo, code_region, number_depart, prefecture, circons, eloignement, town_name))
# preliminary checks
names(geo)
[1] "region" "region_capital" "department" "postal_code" "CODGEO"
[6] "latitude" "longitude"
'data.frame': 36840 obs. of 7 variables:
$ region : Factor w/ 28 levels "Alsace","Aquitaine",..: 27 27 27 27 27 27 27 27 27 27 ...
$ region_capital: Factor w/ 28 levels "Ajaccio","Amiens",..: 14 14 14 14 14 14 14 14 14 14 ...
$ department : Factor w/ 102 levels "Ain","Aisne",..: 1 1 1 1 1 1 1 1 1 1 ...
$ postal_code : Factor w/ 6106 levels "01000","01090",..: 26 19 29 26 17 1 23 16 17 17 ...
$ CODGEO : int 1024 1029 1038 1040 1245 1053 1065 1069 1072 1095 ...
$ latitude : num 46.3 46.4 46.3 46.4 46.1 ...
$ longitude : Factor w/ 1151 levels "","-","-0,75",..: 874 880 881 864 891 877 872 880 885 892 ...
region region_capital department postal_code
Midi-Pyrénées: 3028 Toulouse: 3028 Pas-de-Calais : 898 51300 : 46
Rhône-Alpes : 2890 Lyon : 2890 Aisne : 816 51800 : 44
Lorraine : 2336 Metz : 2336 Somme : 783 70000 : 42
Aquitaine : 2300 Bordeaux: 2300 Seine-Maritime: 747 88500 : 42
Picardie : 2295 Amiens : 2295 Moselle : 732 80140 : 40
Bourgogne : 2050 Dijon : 2050 Côte-d'Or : 709 02160 : 38
(Other) :21941 (Other) :21941 (Other) :32155 (Other):36588
CODGEO latitude longitude
Min. : 1001 Min. :41.39 : 2841
1st Qu.:24577 1st Qu.:45.22 2.433333: 105
Median :48191 Median :47.43 2.333333: 100
Mean :46298 Mean :47.00 1.833333: 99
3rd Qu.:67043 3rd Qu.:48.85 2.116667: 98
Max. :97617 Max. :51.08 2.25 : 94
NA's :2929 (Other) :33503
Correct typos for longitude data and keep just the unique CODGEO to avoid towns with multiple postal codes:
# spot "," instead of "." in longitude
newLong <- as.character(geo$longitude) # copy the vector
sum(grep(",", newLong)) # total commas
[1] 994302
ind_long_err <- grep(",", newLong) # indexing them
newLong <- gsub(",", ".", newLong) # substituting them with dots
indNA_Long <- is.na(as.numeric((newLong))) # spot NA
NAs introduced by coercion
# geo$longitude[indNA_Long] # verify that they were actually missing
geo$longitude <- as.numeric(newLong) # overwrite the longitude variable with the new one
NAs introduced by coercion
# Check for duplicated data (e.g., cities with different postal codes, that we dropped):
# e.g., to verify it, try on the initial dataset:
# sum(geo$nom_commune == "Paris")
# ind_duplic <- geo$nom_commune == "Paris"
# geo[ind_duplic,]
sum(duplicated.data.frame(geo))
[1] 118
# retaing unique postal cities
geo <- geo[!duplicated(geo$CODGEO),]
# check again
summary(geo)
region region_capital department postal_code
Midi-Pyrénées: 3020 Toulouse: 3020 Pas-de-Calais : 894 51300 : 46
Rhône-Alpes : 2879 Lyon : 2879 Aisne : 816 51800 : 44
Lorraine : 2333 Metz : 2333 Somme : 782 70000 : 42
Aquitaine : 2296 Bordeaux: 2296 Seine-Maritime: 745 88500 : 42
Picardie : 2291 Amiens : 2291 Moselle : 730 80140 : 40
Bourgogne : 2046 Dijon : 2046 Côte-d'Or : 707 02160 : 38
(Other) :21828 (Other) :21828 (Other) :32019 (Other):36441
CODGEO latitude longitude
Min. : 1001 Min. :41.39 Min. :-5.1000
1st Qu.:24561 1st Qu.:45.22 1st Qu.: 0.6833
Median :48172 Median :47.43 Median : 2.6167
Mean :46264 Mean :47.00 Mean : 2.7324
3rd Qu.:67020 3rd Qu.:48.85 3rd Qu.: 4.8500
Max. :97617 Max. :51.08 Max. : 9.5167
NA's :2923 NA's :2902
Assign latitude and longitude values for missing data (almost 3000). The code used to retrieve them using Google API has been commented and its result is loaded.
# index of NAs and their total
indNA_coord = is.na(geo$latitude) | is.na(geo$longitude)
sum(indNA_coord)
[1] 2987
# code used to retrieve the NA using Google API, which have been saved in a csv file
#
# # initialize variables
# city_search = 0
# res = as.data.frame(matrix(c(0, 0, 0), 1, 3))
# names(res) = c("lon", "lat", "address")
#
# # retrieve lat and long (Google API = 2500 request per day)
# # my_iter = floor(sum(indNA_coord)/3)
# for (i in 1:sum(indNA_coord)){
#
# # city searched
# city_search[i] = paste(c(as.character(NA_coord$town_name[i]), as.character(NA_coord$postal_code[i]), as.character(NA_coord$department[i]), "France"), sep=" ", collapse = ", ")
#
# # solution
# res[i,] = geocode(city_search[i], output = "latlona", source = c("google", "dsk"), messaging = FALSE)
#
# # retrieve still missing data, because of existing problems with API (up to 15 trials)
# j = 0
# while (any(is.na(res[i,])) & j < 25){
# res[i,] = geocode(city_search[i], output = "latlona", source = c("google", "dsk"), messaging = FALSE)
# j = j + 1
# }
# }
# # check the solution
# sol = cbind(searched = city_search, res)
# # save it as a csv file to save time
# write.csv(retrieved_geo_NA[,2:3], "geo_NA_Final.csv", quote = FALSE, row.names=FALSE, fileEncoding = "UTF-8")
# read the created csv
setwd("./data")
retrieved_geo_NA = read.csv("geo_NA_Final.csv", header = T, encoding = "UTF-8")
# get only long and lat and assign to original NA
geo$latitude[indNA_coord] = retrieved_geo_NA[,2]
geo$longitude[indNA_coord] = retrieved_geo_NA[,1]
# there are 37 still missing units, which are towns located in old colonies far from Europe
indNA_coord = is.na(geo$latitude) | is.na(geo$longitude)
sum(indNA_coord)
[1] 35
# exclude those towns
geo = geo[!indNA_coord,]
summary(geo)
region region_capital department postal_code
Midi-Pyrénées: 3020 Toulouse: 3020 Pas-de-Calais : 894 51300 : 46
Rhône-Alpes : 2879 Lyon : 2879 Aisne : 816 51800 : 44
Lorraine : 2333 Metz : 2333 Somme : 782 70000 : 42
Aquitaine : 2296 Bordeaux: 2296 Seine-Maritime: 745 88500 : 42
Picardie : 2291 Amiens : 2291 Moselle : 730 80140 : 40
Bourgogne : 2046 Dijon : 2046 Côte-d'Or : 707 02160 : 38
(Other) :21793 (Other) :21793 (Other) :31984 (Other):36406
CODGEO latitude longitude
Min. : 1001 Min. :-21.38 Min. :-63.0885
1st Qu.:24551 1st Qu.: 45.15 1st Qu.: 0.6585
Median :48154 Median : 47.38 Median : 2.6333
Mean :46215 Mean : 46.87 Mean : 2.6611
3rd Qu.:66225 3rd Qu.: 48.83 3rd Qu.: 4.8667
Max. :97613 Max. : 51.08 Max. : 55.8250
Remove DOM-TOM towns (i.e. old colonies far from Europe)
# delete non-European countries
ind_nonEur = geo$latitude < 30 | geo$latitude > 70 |geo$longitude < -20 | geo$longitude > 20
sum(ind_nonEur)
[1] 92
Salary data
Assign meaningful names and check the data:
[1] "CODGEO" "LIBGEO" "SNHM14" "SNHMC14" "SNHMP14" "SNHME14" "SNHMO14"
[8] "SNHMF14" "SNHMFC14" "SNHMFP14" "SNHMFE14" "SNHMFO14" "SNHMH14" "SNHMHC14"
[15] "SNHMHP14" "SNHMHE14" "SNHMHO14" "SNHM1814" "SNHM2614" "SNHM5014" "SNHMF1814"
[22] "SNHMF2614" "SNHMF5014" "SNHMH1814" "SNHMH2614" "SNHMH5014"
names(salary)[2:ncol(salary)] <-
c("town",
"sal_general",
"sal_executive",
"sal_midManager",
"sal_employee",
"sal_worker",
"sal_Females",
"sal_F_executive",
"sal_F_midManager",
"sal_F_employee",
"sal_F_worker",
"sal_Males",
"sal_M_executive",
"sal_M_midManager",
"sal_M_employee",
"sal_M_worker",
"sal_18_25",
"sal_26_50",
"sal_51plus",
"sal_F_18_25",
"sal_F_26_50",
"sal_F_51plus",
"sal_M_18_25",
"sal_M_26_50",
"sal_M_51plus")
# preliminary checks
names(salary)
[1] "CODGEO" "town" "sal_general" "sal_executive"
[5] "sal_midManager" "sal_employee" "sal_worker" "sal_Females"
[9] "sal_F_executive" "sal_F_midManager" "sal_F_employee" "sal_F_worker"
[13] "sal_Males" "sal_M_executive" "sal_M_midManager" "sal_M_employee"
[17] "sal_M_worker" "sal_18_25" "sal_26_50" "sal_51plus"
[21] "sal_F_18_25" "sal_F_26_50" "sal_F_51plus" "sal_M_18_25"
[25] "sal_M_26_50" "sal_M_51plus"
'data.frame': 5136 obs. of 26 variables:
$ CODGEO : Factor w/ 5136 levels "01004","01007",..: 1 2 3 4 5 6 7 8 9 10 ...
$ town : Factor w/ 5085 levels "Abbeville","Ablis",..: 73 79 133 192 275 298 407 395 400 406 ...
$ sal_general : num 13.7 13.5 13.5 12.9 13 13.9 12.4 14 11.5 12.4 ...
$ sal_executive : num 24.2 22.1 27.6 21.8 22.8 22.2 24 23.1 21.2 23.4 ...
$ sal_midManager : num 15.5 14.7 15.6 14.1 14.1 15.1 13.1 15.3 13.5 14.1 ...
$ sal_employee : num 10.3 10.7 11.1 11 10.5 11 10.5 10.9 9.9 10.3 ...
$ sal_worker : num 11.2 11.4 11.1 11.3 11.1 11.4 10.4 11.3 10.5 10.5 ...
$ sal_Females : num 11.6 11.9 10.9 11.4 11.6 12.5 10.9 12.4 10.3 11 ...
$ sal_F_executive : num 19.1 19 19.5 19 19.4 20.3 20.7 20.5 20.8 21.5 ...
$ sal_F_midManager: num 13.2 13.3 11.7 13 13.6 14 11.8 13.9 12.3 13 ...
$ sal_F_employee : num 10.1 10.6 10.8 10.3 10.2 10.9 10.4 10.7 9.8 9.9 ...
$ sal_F_worker : num 9.6 10 9.5 9.9 9.8 10.5 9.3 10.3 9 9.5 ...
$ sal_Males : num 15 14.7 15.3 13.8 13.8 15.2 13.4 15.4 12.3 13.2 ...
$ sal_M_executive : num 26.4 23.3 30.2 23 24.1 23.1 25.2 24.4 21.3 24 ...
$ sal_M_midManager: num 16.7 15.8 17.2 14.7 14.4 15.9 13.8 16.3 14.2 14.9 ...
$ sal_M_employee : num 11 11.3 12.4 13.2 11.7 12.1 10.8 11.8 10.5 11.6 ...
$ sal_M_worker : num 11.6 11.7 11.8 11.6 11.4 11.7 10.8 11.6 11 10.9 ...
$ sal_18_25 : num 10.5 9.8 9.3 9.6 9.4 9.7 9.3 9.7 9.6 9.7 ...
$ sal_26_50 : num 13.7 13.8 13.3 12.9 12.8 14.1 12.5 13.9 11.5 12.3 ...
$ sal_51plus : num 16.1 14.6 16 14.2 15.2 15.4 13.3 16.7 12.7 13.7 ...
$ sal_F_18_25 : num 9.7 9.2 8.9 9.3 9 9.5 8.9 9.7 9.2 9.3 ...
$ sal_F_26_50 : num 11.8 12.2 10.6 11.4 11.8 12.8 11 12.4 10.3 11.2 ...
$ sal_F_51plus : num 12.5 12.5 12.5 12.2 12.3 13 11.5 13.8 11.3 11.4 ...
$ sal_M_18_25 : num 11 10.2 9.6 9.7 9.7 9.9 9.6 9.6 10 9.9 ...
$ sal_M_26_50 : num 14.9 14.9 15.1 13.8 13.4 15.3 13.3 15 12.3 13 ...
$ sal_M_51plus : num 18.6 16.4 18.6 15.9 16.9 17.2 14.9 19.3 13.9 15.4 ...
CODGEO town sal_general sal_executive sal_midManager
01004 : 1 Sainte-Marie: 4 Min. :10.20 Min. :16.0 Min. :11.60
01007 : 1 Saint-Ouen : 3 1st Qu.:12.10 1st Qu.:21.9 1st Qu.:13.80
01014 : 1 Allonnes : 2 Median :13.00 Median :23.2 Median :14.40
01024 : 1 Andilly : 2 Mean :13.71 Mean :23.7 Mean :14.58
01025 : 1 Bassens : 2 3rd Qu.:14.40 3rd Qu.:24.9 3rd Qu.:15.10
01027 : 1 Beaumont : 2 Max. :43.30 Max. :51.5 Max. :54.60
(Other):5130 (Other) :5121
sal_employee sal_worker sal_Females sal_F_executive sal_F_midManager
Min. : 8.70 Min. : 8.30 Min. : 9.30 Min. :12.00 Min. :10.60
1st Qu.:10.00 1st Qu.:10.60 1st Qu.:10.90 1st Qu.:18.80 1st Qu.:12.60
Median :10.40 Median :11.00 Median :11.50 Median :20.00 Median :13.10
Mean :10.56 Mean :11.24 Mean :12.04 Mean :20.22 Mean :13.27
3rd Qu.:10.90 3rd Qu.:11.60 3rd Qu.:12.70 3rd Qu.:21.40 3rd Qu.:13.80
Max. :17.50 Max. :46.30 Max. :26.70 Max. :35.50 Max. :19.00
sal_F_employee sal_F_worker sal_Males sal_M_executive sal_M_midManager
Min. : 8.70 Min. : 6.100 Min. :10.40 Min. :13.8 Min. :11.80
1st Qu.: 9.80 1st Qu.: 9.200 1st Qu.:12.90 1st Qu.:23.1 1st Qu.:14.50
Median :10.10 Median : 9.700 Median :14.10 Median :24.6 Median :15.20
Mean :10.31 Mean : 9.827 Mean :14.85 Mean :25.2 Mean :15.49
3rd Qu.:10.60 3rd Qu.:10.200 3rd Qu.:15.80 3rd Qu.:26.6 3rd Qu.:16.00
Max. :16.10 Max. :28.100 Max. :52.40 Max. :58.0 Max. :93.40
sal_M_employee sal_M_worker sal_18_25 sal_26_50 sal_51plus
Min. : 8.00 Min. : 8.9 Min. : 7.90 Min. : 9.7 Min. :10.50
1st Qu.:10.50 1st Qu.:10.8 1st Qu.: 9.20 1st Qu.:12.0 1st Qu.:13.70
Median :11.10 Median :11.3 Median : 9.50 Median :12.9 Median :15.00
Mean :11.27 Mean :11.5 Mean : 9.55 Mean :13.5 Mean :15.88
3rd Qu.:11.80 3rd Qu.:11.9 3rd Qu.: 9.70 3rd Qu.:14.3 3rd Qu.:16.90
Max. :23.50 Max. :53.2 Max. :60.60 Max. :38.1 Max. :56.90
sal_F_18_25 sal_F_26_50 sal_F_51plus sal_M_18_25 sal_M_26_50
Min. : 7.500 Min. : 9.10 Min. : 9.50 Min. : 7.800 Min. : 9.60
1st Qu.: 8.900 1st Qu.:10.90 1st Qu.:11.70 1st Qu.: 9.400 1st Qu.:12.70
Median : 9.100 Median :11.60 Median :12.60 Median : 9.700 Median :13.80
Mean : 9.162 Mean :12.06 Mean :13.17 Mean : 9.821 Mean :14.49
3rd Qu.: 9.400 3rd Qu.:12.70 3rd Qu.:14.00 3rd Qu.:10.000 3rd Qu.:15.50
Max. :12.000 Max. :26.60 Max. :31.00 Max. :93.300 Max. :45.40
sal_M_51plus
Min. :10.80
1st Qu.:14.90
Median :16.60
Mean :17.68
3rd Qu.:19.00
Max. :68.60
# Check for duplicated data: there are no
sum(duplicated.data.frame(salary))
[1] 0
# drop unnecessary variable
salary <-subset(salary, select = -c(town))
Population data
Rename the variables for population and exclude the unnecessary ones:
#names(population)
names(population)[5:7] <-
c("ageCateg5",
"sex",
"peopleCategNum")
# drop unnecessary columns (NIVGEO is the same for all)
population <- subset(population, select = -c(NIVGEO, LIBGEO))
# Refactor sex and MOCO
population$MOCO <- factor(population$MOCO, levels = c(11,12,21,22,23,31,32),
labels = c("children_living_with_two_parents",
"children_living_with_one_parent",
"adults_living_in_couple_without_child",
"adults_living_in_couple_with_children",
"adults_living_alone_with_children",
"persons_not_from_family_living_in_the_home",
"persons_living_alone"))
population$sex <- factor(population$sex, levels = c(1,2), labels = c("Male", "Female"))
# check again
summary(population)
CODGEO MOCO ageCateg5
01001 : 238 children_living_with_two_parents :1219512 Min. : 0
01002 : 238 children_living_with_one_parent :1219512 1st Qu.:20
01004 : 238 adults_living_in_couple_without_child :1219512 Median :40
01005 : 238 adults_living_in_couple_with_children :1219512 Mean :40
01006 : 238 adults_living_alone_with_children :1219512 3rd Qu.:60
01007 : 238 persons_not_from_family_living_in_the_home:1219512 Max. :80
(Other):8535156 persons_living_alone :1219512
sex peopleCategNum
Male :4268292 Min. : 0.00
Female:4268292 1st Qu.: 0.00
Median : 0.00
Mean : 7.45
3rd Qu.: 3.00
Max. :48873.00
Understand the distribution of population according to different age categories using population pyramide (performed now because later the dataset will be modified):
# need the initial shape of data to construct the pyramide
# Population pyramide
population_data2 <- ddply(population, .(sex, ageCateg5), function(population) {
data.frame(total_population = sum(population$peopleCategNum))
})
pop_pyramid <- ggplot(data = population_data2,
mapping = aes(x = ageCateg5, fill = sex,
y = ifelse(test = sex == "Male",
yes = -total_population, no = total_population))) +
geom_bar(stat = "identity") +
scale_y_continuous(labels = abs, limits = max(population_data2$total_population) * c(-1,1)) +
ggtitle("Pyramid of Population") + theme(plot.title = element_text(hjust = 0.5)) +
labs(x= "Age")+ labs(y = "Population") + coord_flip() # + scale_fill_brewer(palette = "Set1")
pop_pyramid

Re-organize population dataset and set CODGEO as units and create new variables using the available variables.
# Re-organize the data by creating new variables: "total population", "male", "female", "child", "elderly" and "workforce".
population <- ddply(population, .(CODGEO), function(population) {
data.frame(total_population = sum(population$peopleCategNum),
male = sum(population[population$sex == "Male",]$peopleCategNum),
female = sum(population[population$sex == "Female",]$peopleCategNum),
child = sum(population[population$ageCateg5 %in% seq(0, 10, by=5),]$peopleCategNum),
elderly = sum(population[population$ageCateg5 %in% seq(65, 80, by=5),]$peopleCategNum),
workforce = sum(population[population$ageCateg5 %in% seq(15, 60, by=5),]$peopleCategNum)
)})
# Calculate ratios using the existing variables
population$dependent <- population$child + population$elderly
population$sex_ratio <- ifelse(population$female==0, 0, population$male / population$female)
population$dependency_ratio <- ifelse(population$workforce==0, 0, population$dependent / population$workforce)
population$aged_dependency_ratio <- ifelse(population$workforce==0, 0, population$elderly / population$workforce)
population$child_dependency_ratio <- ifelse(population$workforce==0, 0, population$child / population$workforce)
# total population=65mln, which is reasonable
sum(population$total_population)
[1] 63569750
# create dummy variable for urban city
# taking the top 20% in terms of population
population$urbanDummy = population$total_population > quantile(population$total_population, 0.90)
Education data
Assign meaningful names and build some useful indicators:
names(educ)[3:ncol(educ)] <-
c("Age15_NoDip_M","Age15_NoDip_F", "Age15_Sec_M", "Age15_Sec_F", "Age15_Hi_M","Age15_Hi_F", "Age15_Univ_M",
"Age15_Univ_F", "Age20_NoDip_M", "Age20_NoDip_F", "Age20_Sec_M","Age20_Sec_F", "Age20_Hi_M", "Age20_Hi_F",
"Age20_Univ_M", "Age20_Univ_F","Age25_NoDip_M", "Age25_NoDip_F","Age25_Sec_M","Age25_Sec_F", "Age25_Hi_M",
"Age25_Hi_F","Age25_Univ_M","Age25_Univ_F", "Age30_NoDip_M", "Age30_NoDip_F", "Age30_Sec_M", "Age30_Sec_F",
"Age30_Hi_M", "Age30_Hi_F","Age30_Univ_M","Age30_Univ_F", "Age35_NoDip_M", "Age35_NoDip_F", "Age35_Sec_M",
"Age35_Sec_F", "Age35_Hi_M", "Age35_Hi_F", "Age35_Univ_M","Age35_Univ_F", "Age40_NoDip_M", "Age40_NoDip_F",
"Age40_Sec_M","Age40_Sec_F", "Age40_Hi_M", "Age40_Hi_F", "Age40_Univ_M","Age40_Univ_F", "Age45_NoDip_M",
"Age45_NoDip_F","Age45_Sec_M","Age45_Sec_F", "Age45_Hi_M", "Age45_Hi_F", "Age45_Univ_M","Age45_Univ_F",
"Age50_NoDip_M", "Age50_NoDip_F","Age50_Sec_M","Age50_Sec_F", "Age50_Hi_M", "Age50_Hi_F", "Age50_Univ_M",
"Age50_Univ_F", "Age55_NoDip_M", "Age55_NoDip_F","Age55_Sec_M", "Age55_Sec_F", "Age55_Hi_M", "Age55_Hi_F",
"Age55_Univ_M", "Age55_Univ_F", "Age60_NoDip_M", "Age60_NoDip_F","Age60_Sec_M","Age60_Sec_F", "Age60_Hi_M",
"Age60_Hi_F", "Age60_Univ_M", "Age60_Univ_F", "Age65_NoDip_M", "Age65_NoDip_F","Age65_Sec_M","Age65_Sec_F",
"Age65_Hi_M", "Age65_Hi_F", "Age65_Univ_M", "Age65_Univ_F")
# Aggregate variables by grouping all the education level categories by gender
# total number of females with no diploma
educ$female_NoDip <- rowSums(cbind(educ$Age15_NoDip_F, educ$Age20_NoDip_F, educ$Age25_NoDip_F, educ$Age30_NoDip_F,
educ$Age35_NoDip_F,educ$Age40_NoDip_F,educ$Age45_NoDip_F, educ$Age50_NoDip_F,
educ$Age55_NoDip_F, educ$Age60_NoDip_F, educ$Age65_NoDip_F))
# total number of males with no diploma
educ$male_NoDip <- rowSums(cbind(educ$Age15_NoDip_M, educ$Age20_NoDip_M, educ$Age25_NoDip_M, educ$Age30_NoDip_M,
educ$Age35_NoDip_M,educ$Age40_NoDip_M,educ$Age45_NoDip_M, educ$Age50_NoDip_M,
educ$Age55_NoDip_M, educ$Age60_NoDip_M, educ$Age65_NoDip_M))
# total number of females with secondary education level
educ$female_Sec <- rowSums(cbind(educ$Age15_Sec_F, educ$Age20_Sec_F, educ$Age25_Sec_F, educ$Age30_Sec_F,
educ$Age35_Sec_F,educ$Age40_Sec_F,educ$Age45_Sec_F, educ$Age50_Sec_F,
educ$Age55_Sec_F, educ$Age60_Sec_F, educ$Age65_Sec_F))
# total number of males with secondary education level
educ$male_Sec <- rowSums(cbind(educ$Age15_Sec_M, educ$Age20_Sec_M, educ$Age25_Sec_M, educ$Age30_Sec_M,
educ$Age35_Sec_M,educ$Age40_Sec_M,educ$Age45_Sec_M, educ$Age50_Sec_M,
educ$Age55_Sec_M, educ$Age60_Sec_M, educ$Age65_Sec_M))
# total number of females with high-school education level
educ$female_Hi <- rowSums(cbind(educ$Age15_Hi_F, educ$Age20_Hi_F, educ$Age25_Hi_F, educ$Age30_Hi_F,
educ$Age35_Hi_F,educ$Age40_Hi_F,educ$Age45_Hi_F, educ$Age50_Hi_F,
educ$Age55_Hi_F, educ$Age60_Hi_F, educ$Age65_Hi_F))
# total number of males with high-school education level
educ$male_Hi <- rowSums(cbind(educ$Age15_Hi_M, educ$Age20_Hi_M, educ$Age25_Hi_M, educ$Age30_Hi_M,
educ$Age35_Hi_M,educ$Age40_Hi_M,educ$Age45_Hi_M, educ$Age50_Hi_M,
educ$Age55_Hi_M, educ$Age60_Hi_M, educ$Age65_Hi_M))
# total number of females with university degree
educ$female_Univ <- rowSums(cbind(educ$Age15_Univ_F, educ$Age20_Univ_F, educ$Age25_Univ_F, educ$Age30_Univ_F,
educ$Age35_Univ_F,educ$Age40_Univ_F,educ$Age45_Univ_F, educ$Age50_Univ_F,
educ$Age55_Univ_F, educ$Age60_Univ_F, educ$Age65_Univ_F))
# total number of males with university degree
educ$male_Univ <- rowSums(cbind(educ$Age15_Univ_M, educ$Age20_Univ_M, educ$Age25_Univ_M, educ$Age30_Univ_M,
educ$Age35_Univ_M,educ$Age40_Univ_M,educ$Age45_Univ_M, educ$Age50_Univ_M,
educ$Age55_Univ_M, educ$Age60_Univ_M, educ$Age65_Univ_M))
# drop all the unnecessary variables
educ <- subset(educ, select= c(CODGEO,
female_NoDip, male_NoDip,
female_Sec, male_Sec,
female_Hi, male_Hi,
female_Univ, male_Univ))
# total number of population without a diploma
educ$nodip <-rowSums(cbind(educ$female_NoDip, educ$male_NoDip))
# total number of population with secondary level of education
educ$sec <-rowSums(cbind(educ$female_Sec, educ$male_NoDip))
# total number of population with highschool diploma
educ$high <-rowSums(cbind(educ$female_Hi, educ$male_Hi))
# total number of poopulation with university diploma
educ$univ <- rowSums(cbind(educ$female_Univ, educ$male_Univ))
Demographic/social profiles data
Rename the original variables
# rename variables
names(categ_socio)[3:ncol(categ_socio)] <-
c("M_immi_agri",
"F_immi_agri",
"M_NoImmi_agri",
"F_NoImmi_agri",
"M_immi_comm",
"F_immi_comm",
"M_NoImmi_comm",
"F_NoImmi_comm",
"M_immi_exec",
"F_immi_exec",
"M_NoImmi_exec",
"F_NoImmi_exec",
"M_immi_midman",
"F_immi_midman",
"M_NoImmi_midman",
"F_NoImmi_midman",
"M_immi_emp",
"F_immi_emp",
"M_NoImmi_emp",
"F_NoImmi_emp",
"M_immi_worker",
"F_immi_worker",
"M_NoImmi_worker",
"F_NoImmi_worker",
"M_immi_retired",
"F_immi_retired",
"M_NoImmi_retired",
"F_NoImmi_retired",
"M_immi_noAct",
"F_immi_noAct",
"M_NoImmi_noAct",
"F_NoImmi_noAct")
# drop LIBGEO
categ_socio <- subset(categ_socio, select=-c(LIBGEO))
Create the total number of immigrants and natives per town, also separeted by gender.
# total number of male immigrants per town
categ_socio$male_immig <-rowSums(cbind(categ_socio$M_immi_agri, categ_socio$M_immi_comm, categ_socio$M_immi_emp,
categ_socio$M_immi_exec, categ_socio$M_immi_midman,categ_socio$M_immi_noAct,
categ_socio$M_immi_retired, categ_socio$M_immi_worker))
# total number of female immigrants per town
categ_socio$female_immig <- rowSums(cbind(categ_socio$F_immi_agri,categ_socio$F_immi_comm, categ_socio$F_immi_emp,
categ_socio$F_immi_exec, categ_socio$F_immi_midman,
categ_socio$F_immi_noAct, categ_socio$F_immi_retired, categ_socio$F_immi_worker))
# total number immigrants per town
categ_socio$total_immig <- categ_socio$male_immig + categ_socio$female_immig
# working male immigrants per town
categ_socio$male_working_immig <- categ_socio$male_immig - categ_socio$M_immi_retired
# working female immigrants per town
categ_socio$female_working_immig <- categ_socio$female_immig - categ_socio$F_immi_retired
# total number of male natives per town
categ_socio$male_native <- rowSums(cbind(categ_socio$M_NoImmi_agri, categ_socio$M_NoImmi_comm, categ_socio$M_NoImmi_exec, categ_socio$M_NoImmi_emp, categ_socio$M_NoImmi_midman, categ_socio$M_NoImmi_noAct, categ_socio$M_NoImmi_retired, categ_socio$M_NoImmi_worker))
# total number of female natives per town
categ_socio$female_native <- rowSums(cbind(categ_socio$F_NoImmi_agri, categ_socio$F_NoImmi_comm, categ_socio$F_NoImmi_exec, categ_socio$F_NoImmi_emp, categ_socio$F_NoImmi_midman, categ_socio$F_NoImmi_noAct, categ_socio$F_NoImmi_retired, categ_socio$F_NoImmi_worker))
# total number of natives per town
categ_socio$total_native <- categ_socio$male_native + categ_socio$female_native
# drop unnecessary variables
categ_socio <- subset(categ_socio, select = c(CODGEO, male_immig, female_immig, total_immig, male_working_immig,
female_working_immig, male_native, female_native, total_native))
Work status data
Rename the original variables
# rename variables
names(status_work)[3:ncol(status_work)] <-
c("Less20_M_wagearner_Full", "Less20_M_wagearner_Half", "Less20_M_Indp1_Full", "Less20_M_Indp1_Half",
"Less20_M_empl_Full", "Less20_M_empl_Half", "Less20_M_trans_Full", "Less20_M_trans_Half",
"Less20_F_wagearner_Full", "Less20_F_wagearner_Half", "Less20_F_Indp1_Full", "Less20_F_Indp1_Half",
"Less20_F_empl_Full", "Less20_F_empl_Half", "Less20_F_trans_Full", "Less20_F_trans_Half",
"t4_M_wagearner_Full", "t4_M_wagearner_Half", "t4_M_Indp1_Full", "t4_M_Indp1_Half", "t4_M_empl_Full",
"t4_M_empl_Half", "t4_M_trans_Full", "t4_M_trans_Half", "t4_F_wagearner_Full", "t4_F_wagearner_Half",
"t4_F_Indp1_Full", "t4_F_Indp1_Half", "t4_F_empl_Full", "t4_F_empl_Half", "t4_F_trans_Full", "t4_F_trans_Half",
"t9_M_wagearner_Full", "t9_M_wagearner_Half", "t9_M_Indp1_Full", "t9_M_Indp1_Half", "t9_M_empl_Full",
"t9_M_empl_Half", "t9_M_trans_Full", "t9_M_trans_Half", "t9_F_wagearner_Full", "t9_F_wagearner_Half",
"t9_F_Indp1_Full", "t9_F_Indp1_Half", "t9_F_empl_Full", "t9_F_empl_Half", "t9_F_trans_Full", "t9_F_trans_Half",
"T4_M_wagearner_Full", "T4_M_wagearner_Half", "T4_M_Indp1_Full", "T4_M_Indp1_Half", "T4_M_empl_Full",
"T4_M_empl_Half", "T4_M_trans_Full", "T4_M_trans_Half", "T4_F_wagearner_Full", "T4_F_wagearner_Half",
"T4_F_Indp1_Full", "T4_F_Indp1_Half", "T4_F_empl_Full", "T4_F_empl_Half", "T4_F_trans_Full", "T4_F_trans_Half",
"T9_M_wagearner_Full", "T9_M_wagearner_Half", "T9_M_Indp1_Full", "T9_M_Indp1_Half", "T9_M_empl_Full",
"T9_M_empl_Half", "T9_M_trans_Full", "T9_M_trans_Half", "T9_F_wagearner_Full", "T9_F_wagearner_Half",
"T9_F_Indp1_Full", "T9_F_Indp1_Half", "T9_F_empl_Full", "T9_F_empl_Half", "T9_F_trans_Full", "T9_F_trans_Half",
"FF_M_wagearner_Full", "FF_M_wagearner_Half", "FF_M_Indp1_Full", "FF_M_Indp1_Half", "FF_M_empl_Full",
"FF_M_empl_Half", "FF_M_trans_Full", "FF_M_trans_Half", "FF_F_wagearner_Full", "FF_F_wagearner_Half",
"FF_F_Indp1_Full", "FF_F_Indp1_Half", "FF_F_empl_Full", "FF_F_empl_Half", "FF_F_trans_Full", "FF_F_trans_Half",
"F9_M_wagearner_Full", "F9_M_wagearner_Half", "F9_M_Indp1_Full", "F9_M_Indp1_Half", "F9_M_empl_Full",
"F9_M_empl_Half", "F9_M_trans_Full", "F9_M_trans_Half", "F9_F_wagearner_Full", "F9_F_wagearner_Half",
"F9_F_Indp1_Full", "F9_F_Indp1_Half", "F9_F_empl_Full", "F9_F_empl_Half", "F9_F_trans_Full", "F9_F_trans_Half",
"f4_M_wagearner_Full", "f4_M_wagearner_Half", "f4_M_Indp1_Full", "f4_M_Indp1_Half", "f4_M_empl_Full",
"f4_M_empl_Half", "f4_M_trans_Full", "f4_M_trans_Half", "f4_F_wagearner_Full", "f4_F_wagearner_Half",
"f4_F_Indp1_Full", "f4_F_Indp1_Half", "f4_F_empl_Full", "f4_F_empl_Half", "f4_F_trans_Full", "f4_F_trans_Half",
"f9_M_wagearner_Full", "f9_M_wagearner_Half", "f9_M_Indp1_Full", "f9_M_Indp1_Half", "f9_M_empl_Full",
"f9_M_empl_Half", "f9_M_trans_Full", "f9_M_trans_Half", "f9_F_wagearner_Full", "f9_F_wagearner_Half",
"f9_F_Indp1_Full", "f9_F_Indp1_Half", "f9_F_empl_Full", "f9_F_empl_Half", "f9_F_trans_Full", "f9_F_trans_Half",
"s4_M_wagearner_Full", "s4_M_wagearner_Half", "s4_M_Indp1_Full", "s4_M_Indp1_Half", "s4_M_empl_Full",
"s4_M_empl_Half", "s4_M_trans_Full", "s4_M_trans_Half", "s4_F_wagearner_Full", "s4_F_wagearner_Half",
"s4_F_Indp1_Full", "s4_F_Indp1_Half", "s4_F_empl_Full", "s4_F_empl_Half", "s4_F_trans_Full", "s4_F_trans_Half",
"s9_M_wagearner_Full", "s9_M_wagearner_Half", "s9_M_Indp1_Full", "s9_M_Indp1_Half", "s9_M_empl_Full",
"s9_M_empl_Half", "s9_M_trans_Full", "s9_M_trans_Half", "s9_F_wagearner_Full", "s9_F_wagearner_Half",
"s9_F_Indp1_Full", "s9_F_Indp1_Half", "s9_F_empl_Full", "s9_F_empl_Half", "s9_F_trans_Full", "s9_F_trans_Half")
Create aggregate statistics and drop unnecessary variables
# Simplify the variables by summing up by categories
# total number of wage earners for males and females.
nam.M = rep(0, ncol(status_work))
nam.F = rep(0, ncol(status_work))
for (i in 1:ncol(status_work)){
sol = grepl('wagearner', names(status_work)[i])
if (sol==1){
if (grepl('M', names(status_work)[i])){
nam.M[i] = i
}else{nam.F[i]=i}
}else{
nam.F[i]=0
nam.M[i]=0}
}
# names(status_work[nam.M])
# names(status_work[nam.F])
status_work$wagearner_M=rowSums(status_work[,nam.M])
status_work$wagearner_F=rowSums(status_work[,nam.F])
# same but for independent workers by gender
nam.M = rep(0, ncol(status_work))
nam.F = rep(0, ncol(status_work))
for (i in 1:ncol(status_work)){
sol = grepl('Indp1', names(status_work)[i])
if (sol==1){
if (grepl('M', names(status_work)[i])){
nam.M[i] = i
}else{nam.F[i]=i}
}else{
nam.F[i]=0
nam.M[i]=0}
}
# names(status_work[nam.M])
# names(status_work[nam.F])
status_work$independent_M=rowSums(status_work[,nam.M])
status_work$independent_F=rowSums(status_work[,nam.F])
# same but for government transfer receivers
nam.M = rep(0, ncol(status_work))
nam.F = rep(0, ncol(status_work))
for (i in 1:ncol(status_work)){
sol = grepl('trans', names(status_work)[i])
if (sol==1){
if (grepl('M', names(status_work)[i])){
nam.M[i] = i
}else{nam.F[i]=i}
}else{
nam.F[i]=0
nam.M[i]=0}
}
# names(status_work[nam.M])
# names(status_work[nam.F])
status_work$transfer_M=rowSums(status_work[,nam.M])
status_work$transfer_F=rowSums(status_work[,nam.F])
# same but for employers
nam.M = rep(0, ncol(status_work))
nam.F = rep(0, ncol(status_work))
for (i in 1:ncol(status_work)){
sol = grepl('empl', names(status_work)[i])
if (sol==1){
if (grepl('M', names(status_work)[i])){
nam.M[i] = i
}else{nam.F[i]=i}
}else{
nam.F[i]=0
nam.M[i]=0}
}
# names(status_work[nam.M])
# names(status_work[nam.F])
status_work$employer_M=rowSums(status_work[,nam.M])
status_work$employer_F=rowSums(status_work[,nam.F])
# same but for full-time contracts
nam.M = rep(0, ncol(status_work))
nam.F = rep(0, ncol(status_work))
for (i in 1:ncol(status_work)){
sol = grepl('Full', names(status_work)[i])
if (sol==1){
if (grepl('M', names(status_work)[i])){
nam.M[i] = i
}else{nam.F[i]=i}
}else{
nam.F[i]=0
nam.M[i]=0}
}
# names(status_work[nam.M])
# names(status_work[nam.F])
status_work$full_M=rowSums(status_work[,nam.M])
status_work$full_F=rowSums(status_work[,nam.F])
# same but for half-time contracts
nam.M = rep(0, ncol(status_work))
nam.F = rep(0, ncol(status_work))
for (i in 1:ncol(status_work)){
sol = grepl('Half', names(status_work)[i])
if (sol==1){
if (grepl('M', names(status_work)[i])){
nam.M[i] = i
}else{nam.F[i]=i}
}else{
nam.F[i]=0
nam.M[i]=0}
}
#names(status_work[nam.M])
#names(status_work[nam.F])
status_work$half_M=rowSums(status_work[,nam.M])
status_work$half_F=rowSums(status_work[,nam.F])
# total of each variables
status_work$full <- status_work$full_M + status_work$full_F
status_work$half <- status_work$half_M + status_work$half_F
status_work$wagearner <- status_work$wagearner_M + status_work$wagearner_F
status_work$independent <- status_work$independent_M + status_work$independent_F
status_work$transfer <- status_work$transfer_F + status_work$transfer_M
status_work$employer <- status_work$employer_F + status_work$employer_M
# drop unnecessary variables
status_work <- subset(status_work, select = c(CODGEO,
wagearner_M, wagearner_F,
independent_M, independent_F,
transfer_M, transfer_F,
employer_M, employer_F,
full_M, full_F,
half_M, half_F,
full, half,
wagearner, independent, transfer, employer))
# Full variable means individuals with full time contracts. Half means individuals with part time contract.
# "transfer" is individuals receiving transfer payments.
# "independent" is like auto-entrepreneurs.
Inequality data
Drop unnecessary variables and rename the other ones
[1] "CODGEO" "LIBGEO" "REG" "DEP" "P14_POP"
[6] "P09_POP" "SUPERF" "NAIS0914" "DECE0914" "P14_MEN"
[11] "NAISD16" "DECESD16" "P14_LOG" "P14_RP" "P14_RSECOCC"
[16] "P14_LOGVAC" "P14_RP_PROP" "NBMENFISC14" "PIMP14" "MED14"
[21] "TP6014" "P14_EMPLT" "P14_EMPLT_SAL" "P09_EMPLT" "P14_POP1564"
[26] "P14_CHOM1564" "P14_ACT1564" "ETTOT15" "ETAZ15" "ETBE15"
[31] "ETFZ15" "ETGU15" "ETGZ15" "ETOQ15" "ETTEF115"
[36] "ETTEFP1015"
# drop unnecessary variables
ineq <- subset(ineq, select = -c(LIBGEO, P09_POP, NAISD16, DECESD16, P14_RP_PROP, P09_EMPLT,ETTOT15, ETAZ15, ETBE15, ETFZ15, ETGU15, ETGZ15, ETOQ15, ETTEF115, ETTEFP1015))
# rename variables
names(ineq)[4:ncol(ineq)] <-
c("pop_2014",
"Superficie",
"birth09_14",
"death09_14",
"households14",
"housing14",
"princ_resid14",
"sec_resid14",
"vac_resid14",
"tax_house14",
"shared_tax_house14",
"median_living14",
"lev_ineq14",
"empl",
"emp_sal",
"pop15_64",
"unemp15_64",
"act15_64")
# drop more unnecessary variables
ineq <- subset(ineq, select = -c(princ_resid14, sec_resid14, vac_resid14, pop_2014, households14, birth09_14,
death09_14, tax_house14, shared_tax_house14, lev_ineq14))
# unemployment rate
ineq$unemp_rate <- ineq$unemp15_64/ineq$pop15_64
# impute NA using median (only 3)
ineq$median_living14[is.na(ineq$median_living14)] = median(ineq$median_living14, na.rm = T)
Commune data
Drop unnecessary variables and rename the other ones
[1] "codgeo" "orientationeconomique"
[3] "indicefiscalpartiel" "scorefiscal"
[5] "libgeo" "reg"
[7] "dep" "indicedmographique"
[9] "population" "evolutionpop"
[11] "nbmnages" "nbrsidencesprincipales"
[13] "nbpropritaire" "nblogement"
[15] "nboccupantsrsidenceprincipale" "nbfemme"
[17] "nbhomme" "nbmineurs"
[19] "nbmajeurs" "nbetudiants"
[21] "nbentreprisessecteurservices" "nbentreprisessecteurcommerce"
[23] "nbentreprisessecteurconstruction" "nbentreprisessecteurindustrie"
[25] "nbcrationenteprises" "nbcrationindustrielles"
[27] "nbcrationconstruction" "nbcrationcommerces"
[29] "nbcrationservices" "moyennerevenusfiscauxdpartementa"
[31] "moyennerevenusfiscauxrgionaux" "depmoyennesalaireshoraires"
[33] "depmoyennesalairescadrehoraires" "depmoyennesalairesprofintermdiai"
[35] "depmoyennesalairesemployhoraires" "depmoyennesalairesouvrihoraires"
[37] "regmoyennesalaireshoraires" "regmoyennesalairescadrehoraires"
[39] "regmoyennesalairesprofintermdiai" "regmoyennesalairesemployhoraires"
[41] "regmoyennesalairesouvrihoraires" "valeurajoutergionale"
[43] "urbanitruralit" "scoreurbanit"
[45] "nbatifs" "nbactifssalaris"
[47] "nbactifsnonsalaris" "nblogementsecondaireetoccasionne"
[49] "dynamiquedmographiquebv" "tauxtudiants"
[51] "tauxproprit" "dynamiquedmographiqueinsee"
[53] "capacitfisc" "capacitfiscale"
[55] "moyennerevnusfiscaux" "nbindustriesdesbiensintermdiaire"
[57] "nbdecommerce" "nbdeservicesauxparticuliers"
[59] "nbinstitutiondeeducationsantacti" "pibrgionnal"
[61] "segenvironnementdmographiqueobso" "scorecroissancepopulation"
[63] "scorecroissanceentrepreneuriale" "scorevargion"
[65] "scorepib" "environnementdmographique"
[67] "fidlit"
#Drop unnecessary variables
commune <-subset(commune, select=-c(libgeo, scorefiscal, dep, reg, evolutionpop, nbpropritaire,
nblogementsecondaireetoccasionne, scoreurbanit, scorevargion, scorepib,
nbrsidencesprincipales, indicefiscalpartiel, nboccupantsrsidenceprincipale,
depmoyennesalaireshoraires, depmoyennesalairescadrehoraires,
depmoyennesalairesprofintermdiai, depmoyennesalairesemployhoraires,
depmoyennesalairesouvrihoraires, valeurajoutergionale,
nbindustriesdesbiensintermdiaire, nbdecommerce, nbdeservicesauxparticuliers,
nbinstitutiondeeducationsantacti, scorevargion, scorepib,
moyennerevenusfiscauxdpartementa, moyennerevenusfiscauxrgionaux,
regmoyennesalaireshoraires, regmoyennesalairescadrehoraires,
regmoyennesalairesprofintermdiai, regmoyennesalairesemployhoraires,
regmoyennesalairesouvrihoraires, tauxtudiants, dynamiquedmographiqueinsee,
capacitfisc, capacitfiscale, moyennerevnusfiscaux, nblogement, fidlit))
# rename variables
names(commune) <-c("CODGEO", "orient_econ", "demo_index", "population", "nb_household",
"nb_female", "nb_male", "nb_minor", "nb_major", "nb_students",
"nb_firms_service", "nb_firms_commerce", "nb_firms_construction",
"nb_firms_ind", "nb_created_firms", "nb_created_ind",
"nb_created_construction", "nb_created_commerce",
"nb_created_services", "urbanRural", "nb_active", "nb_active_employees",
"nb_active_non_employees", "dymanic_demo_prof", "profitRate",
"regional_GDP", "demo_environment", "evol_pop_score",
"evol_entrepreneurial_score", "demo_envir2")
# drop more variables
commune <-subset(commune, select=-c(demo_index, population, profitRate, demo_envir2, demo_environment))
Produce consistent datasets
The CODGEO variables have to be merged. However, for different reasons already identified by other kaggle users they need some pre-processing. To do so, some already known mistakes are corrected:
firms$CODGEO <- sub("A", "0", firms$CODGEO)
firms$CODGEO <- sub("B", "0", firms$CODGEO)
salary$CODGEO <- sub("A", "0", salary$CODGEO)
salary$CODGEO <- sub("B", "0", salary$CODGEO)
population$CODGEO <- sub("A", "0", population$CODGEO)
population$CODGEO <- sub("B", "0", population$CODGEO)
geo$CODGEO <- sub("A", "0", geo$CODGEO)
geo$CODGEO <- sub("B", "0", geo$CODGEO)
educ$CODGEO <- sub("A", "0", educ$CODGEO)
educ$CODGEO <- sub("B", "0", educ$CODGEO)
categ_socio$CODGEO <- sub("A", "0", categ_socio$CODGEO)
categ_socio$CODGEO <- sub("B", "0", categ_socio$CODGEO)
ineq$CODGEO <- sub("A", "0", ineq$CODGEO)
ineq$CODGEO <- sub("B", "0", ineq$CODGEO)
status_work$CODGEO <- sub("A", "0", status_work$CODGEO)
status_work$CODGEO <- sub("B", "0", status_work$CODGEO)
commune$CODGEO <- sub("A", "0", commune$CODGEO)
commune$CODGEO <- sub("B", "0", commune$CODGEO)
# Then all CODGEO are trasformed to integers and four new datasets are created retaining only the common CODGEO:
# use only integer values
geo$CODGEO <- as.integer(geo$CODGEO)
population$CODGEO <- as.integer(population$CODGEO)
firms$CODGEO <- as.integer(firms$CODGEO)
salary$CODGEO <- as.integer(salary$CODGEO)
status_work$CODGEO <- as.integer(status_work$CODGEO)
ineq$CODGEO <- as.integer(ineq$CODGEO)
educ$CODGEO <- as.integer(educ$CODGEO)
categ_socio$CODGEO <- as.integer(categ_socio$CODGEO)
commune$CODGEO <- as.integer(commune$CODGEO)
# store datasets' names to loop on them
dataset = c("population", "salary", "firms", "geo", "ineq", "commune", "educ", "categ_socio", "status_work")
# obtain sommon IDs for all datasets
for (i in dataset){
# get i-th name and create a new variable concateneting "NEW" at the end
nam <- paste(i, "NEW", sep = "")
# initialize counter to identify the number of iteration in j
iter = 1
for (j in dataset){
if (j != i){
# for each dataset different from the i-th
if (iter == 1){
# 1st iteration: use the original dataset (e.g., geo)
assign(nam, semi_join(get(i), get(j), by = "CODGEO"))
} else{
# successive iteration: use the new dataset (e.g., geoNEW)
assign(nam, semi_join(get(nam), get(j), by = "CODGEO"))
}
iter = iter + 1
}
}
}
# check how many observation have been deleted
for (i in dataset){
del_rows = nrow(get(i)) - nrow(get(paste(i, "NEW", sep = "")))
del_prop = del_rows / nrow(get(i))
del_obs = paste("For", i, del_rows, "units have been deleted.",
"They were the", round(del_prop*100, digits=2), "% of the total.", sep = " ")
print(paste(del_obs))
}
[1] "For population 30843 units have been deleted. They were the 85.99 % of the total."
[1] "For salary 111 units have been deleted. They were the 2.16 % of the total."
[1] "For firms 31656 units have been deleted. They were the 86.3 % of the total."
[1] "For geo 31541 units have been deleted. They were the 86.26 % of the total."
[1] "For ineq 31664 units have been deleted. They were the 86.3 % of the total."
[1] "For commune 31652 units have been deleted. They were the 86.3 % of the total."
[1] "For educ 30843 units have been deleted. They were the 85.99 % of the total."
[1] "For categ_socio 30843 units have been deleted. They were the 85.99 % of the total."
[1] "For status_work 30843 units have been deleted. They were the 85.99 % of the total."
print(paste("The new dataset has", nrow(salaryNEW), "units and",
ncol(salaryNEW)+ncol(populationNEW)+ncol(firmsNEW)+ncol(geoNEW)+
ncol(status_workNEW)+ncol(ineqNEW)+ncol(educNEW)+ncol(categ_socioNEW)+ncol(communeNEW), "features."))
[1] "The new dataset has 5025 units and 131 features."
Overwrite new datesets into the old ones and remove the latter ones from memory
firms <- firmsNEW
geo <- geoNEW
salary <- salaryNEW
population <- populationNEW
educ <- educNEW
categ_socio <- categ_socioNEW
status_work <- status_workNEW
ineq <- ineqNEW
commune <- communeNEW
rm(list=c("firmsNEW", "geoNEW", "salaryNEW", "populationNEW", "educNEW", "categ_socioNEW", "status_workNEW", "ineqNEW", "communeNEW"))
Descriptive statistics
Firms data
Check the distribution of the null firms (i.e., unknown sizes) and analyze firms’ distribution per town:
# check the ratio of null firms for each town
summary(firms$null/firms$total)
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.3000 0.5937 0.6549 0.6549 0.7152 1.0000
# a lot of information is missing, should we remove these data?
ggplot(data=firms, aes(firms$null/firms$total)) +
geom_histogram(aes(y =..density..), col="black", fill="blue", alpha = .3, bins = 50) +
geom_density(col="black") +
labs(x="Null firms/total firms", y="Count") +
ggtitle("Ratio between the number of null firms and total firms per town") +
theme(plot.title = element_text(hjust = 0.5))

# distribution for the firms with unknown size
ggplot(data=firms, aes(log(firms$null))) +
geom_histogram(aes(y =..density..), col="black", fill="blue", alpha = .3, bins = 50) +
geom_density(col="black") +
labs(x="Number of firms of unknown size (log scale)", y="Density") +
ggtitle("Number of firms of unknown size per town") +
theme(plot.title = element_text(hjust = 0.5))

# distribution for the total number of firms
ggplot(data=firms, aes(log(firms$total))) +
geom_histogram(aes(y =..density..), col="black", fill="blue", alpha = .3, bins = 50) +
geom_density(col="black") +
labs(x="Number of firms (log scale)", y="Density") +
ggtitle("Total number of firms per town") +
theme(plot.title = element_text(hjust = 0.5))

# distribution for the number of micro size firms
ggplot(data=firms, aes(log(firms$micro))) +
geom_histogram(aes(y =..density..), col="black", fill="blue", alpha = .3, bins = 50) +
geom_density(col="black") +
labs(x="Number of firms of micro size (log scale)", y="Density") +
ggtitle("Number of firms of micro size per town") +
theme(plot.title = element_text(hjust = 0.5))

# distribution for the number of small size firms
ggplot(data=firms, aes(log(firms$small))) +
geom_histogram(aes(y =..density..), col="black", fill="blue", alpha = .3, bins = 50) +
geom_density(col="black") +
labs(x="Number of firms of small size (log scale)", y="Density") +
ggtitle("Number of firms of small size per town") +
theme(plot.title = element_text(hjust = 0.5))

# distribution for the number of medium size firms
ggplot(data=firms, aes(log(firms$medium))) +
geom_histogram(aes(y =..density..), col="black", fill="blue", alpha = .3, bins = 50) +
geom_density(col="black") +
labs(x="Number of firms of medium size (log scale)", y="Density") +
ggtitle("Number of firms of medium size per town") +
theme(plot.title = element_text(hjust = 0.5))

# distribution for the number of large size firms
ggplot(data=firms, aes(log(firms$large))) +
geom_histogram(aes(y =..density..), col="black", fill="blue", alpha = .3, bins = 50) +
geom_density(col="black") +
labs(x="Number of firms of large size (log scale)", y="Density") +
ggtitle("Number of firms of large size per town") +
theme(plot.title = element_text(hjust = 0.5))

Check correlation among the variables:
corrplot(cor(firms[,3:8]))

What have learned
Solved problems:
- Use the EU firms’ categorization.
Some problematic aspects:
- Some towns have 100% of null firms, should we remove these data?
- These variables are strongly correlated, should we use just the total amount in the following parts?
We could use these data for the following tasks:
- predict the salaries using such information as proxy for the competition in the job market;
- predict the total number of firms, using salary data;
- geo-spatial plot for firms’ size
Geographic data
Plot available towns on a map:
# center of France, obtained using:
# fra_center = as.numeric(geocode("France"))
fra_center = c(2.213749, 46.227638)
# plot all European towns available
geo_pos = as.data.frame(cbind(lon = geo$longitude, lat = geo$latitude))
geo_pos = geo_pos[complete.cases(geo_pos),]
ggmap(get_googlemap(center=fra_center, scale=2, zoom=5), extent="normal") +
geom_point(aes(x=lon, y=lat), data=geo_pos, col="orange", alpha=0.2, size=0.01)
Map from URL : http://maps.googleapis.com/maps/api/staticmap?center=46.227638,2.213749&zoom=5&size=640x640&scale=2&maptype=terrain&sensor=false

# Try to cll google API until there is no error
#
# FraMap = NA
# while (any(is.na(FraMap))){
# FraMap = tryCatch({
# ggmap(get_googlemap(center=fra_center, scale=2, zoom=5), extent="normal")
# }, error = function(e) {
# message("cannot open URL")
# FraMap = NA
# })
# }
What we have learned
Solved problems:
- Missing latitude and longitude;
- Duplications due to multiple postal codes in the same town;
- Exclude non-European towns;
These information are useful to plot any future dataset/analysis. In addition, they could be useful to compare European towns vs. old colonies.
Salary data
Univariate analysis comparing salaries for both genders among various job categories:
# number of units
n_sex <- length(salary$sal_Females)
# vector representing males and females
Label <- c(rep("M", n_sex*5), rep("F", n_sex*5))
# vector representing the variable considered
Variable <- c(rep("General", n_sex),
rep("Executive", n_sex),
rep("MidManager", n_sex),
rep("Employee", n_sex),
rep("Worker",n_sex),
rep("General", n_sex),
rep("Executive", n_sex),
rep("MidManager", n_sex),
rep("Employee", n_sex),
rep("Worker",n_sex))
# merge these data
sal_sex = cbind.data.frame(Label = Label,
value = c(salary$sal_Males, salary$sal_M_executive, salary$sal_M_midManager, salary$sal_M_employee, salary$sal_M_worker,
salary$sal_Females, salary$sal_F_executive, salary$sal_F_midManager, salary$sal_F_employee, salary$sal_F_worker),
Variable = Variable)
# plotting phase
ggplot(data = sal_sex, aes(x=Label, y=value)) +
geom_boxplot(aes(fill = Label)) +
# not color points replacing colour = group instead of colour=Label
geom_point(aes(y=value, colour=Label), position = position_dodge(width=0.75)) +
facet_wrap( ~ Variable, scales="free") +
xlab("Sex") + ylab("Mean net salary per hour") + ggtitle("Gender comparison for different job positions") +
theme(plot.title = element_text(hjust = 0.5)) + stat_boxplot(geom = "errorbar", width = 0.5)

# + guides(fill=guide_legend(title="Legend"))
# the same but excluding outliers
ggplot(data = sal_sex, aes(x=Label, y=value)) +
scale_y_continuous(limits = quantile(sal_sex$value, c(0, 0.9))) +
geom_boxplot(aes(fill = Label)) +
geom_point(aes(y=value, colour=Label), position = position_dodge(width=0.75)) +
facet_wrap( ~ Variable, scales="free") +
xlab("Sex") + ylab("Mean net salary per hour") +
ggtitle("Gender comparison for different job positions excluding the last decile") +
theme(plot.title = element_text(hjust = 0.5)) +
stat_boxplot(geom = "errorbar", width = 0.5)

Univariate analysis comparing salaries for both genders among various ages:
# vector representing males and females
Label <- c(rep("M", n_sex*3), rep("F", n_sex*3))
# vector representing the variable considered
Variable <- c(rep("18-25", n_sex),
rep("26-50", n_sex),
rep("51+", n_sex),
rep("18-25", n_sex),
rep("26-50", n_sex),
rep("51+", n_sex))
# merge these data
sal_sex <- cbind.data.frame(Label = Label,
value = c(salary$sal_M_18_25, salary$sal_M_26_50, salary$sal_M_51plus,
salary$sal_F_18_25, salary$sal_F_26_50, salary$sal_F_51plus),
Variable = Variable)
# plotting phase
ggplot(data = sal_sex, aes(x=Label, y=value)) +
geom_boxplot(aes(fill = Label)) +
geom_point(aes(y=value, colour=Label), position = position_dodge(width=0.75)) +
facet_wrap( ~ Variable, scales="free") +
xlab("Sex") + ylab("Mean net salary per hour") + ggtitle("Gender comparison for different ages") +
theme(plot.title = element_text(hjust = 0.5)) + ylim(c(5, 100)) +
stat_boxplot(geom = "errorbar", width = 0.5)

The income inequality between genders, age groups and working positions is clear. In the following analyses the focus is on the salary ratio between women and men among different job positions:
# Gender salary ratio and general level of income
# Overall mean salary: The higher the net mean income, the more skewed the ratio of salary between female and male is. Only 2 towns have a ratio>1
# create overall F vs M ratio
salary$salary_ratio_FvsM <- salary$sal_Females / salary$sal_Males
# histogram
ggplot(data=salary, aes(salary$salary_ratio_FvsM)) +
geom_histogram(aes(y =..density..), col="black", fill="blue", alpha = .3, bins = 50) +
geom_density(col="black") +
labs(x="Overall salary ratio (females/males)", y="Density") +
labs(title = "Overall salary ratio between females and males") +
theme(plot.title = element_text(hjust = 0.5))

# scatter plot vs overall mean salary
ggplot(salary, aes(x= sal_general, y=salary_ratio_FvsM)) +
geom_point(size = 0.5, colour = "#0091ff")+
labs(x="Overall salary", y="Overall salary ratio(females/males)") +
labs(title = "Overall salary ratio between females and males vs. overall salary") +
theme(plot.title = element_text(hjust = 0.5)) +
geom_smooth(method = "lm")

# Executives mean salary: a bit better the situation for females in this case and less skewed
# create Executives F vs M ratio
salary$salary_ratio_FvsM_Exec <- salary$sal_F_executive / salary$sal_M_executive
# histogram
ggplot(data=salary, aes(salary$salary_ratio_FvsM_Exec)) +
geom_histogram(aes(y =..density..), col="black", fill="blue", alpha = .3, bins = 50) +
geom_density(col="black") +
labs(x="Executives salary ratio (females/males)", y="Density") +
labs(title = "Executives salary ratio between females and males") +
theme(plot.title = element_text(hjust = 0.5))

# scatter plot vs executives mean salary
ggplot(salary, aes(x= sal_general, y= salary_ratio_FvsM_Exec)) +
geom_point(size = 0.5, colour = "#0091ff")+
labs(x="Overall salary", y="Executives salary ratio (females/males)") +
labs(title = "Executives salary ratio between females and males \n vs. overall salary") +
theme(plot.title = element_text(hjust = 0.5)) +
geom_smooth(method = "lm")

# Middle managers mean salary: ....
# create Middle managers F vs M ratio
salary$salary_ratio_FvsM_midManag <- salary$sal_F_midManager / salary$sal_M_midManager
# histogram
ggplot(data=salary, aes(salary$salary_ratio_FvsM_Exec)) +
geom_histogram(aes(y =..density..), col="black", fill="blue", alpha = .3, bins = 50) +
geom_density(col="black") +
labs(x="Middle managers salary ratio (females/males)", y="Density") +
labs(title = "Middle managers salary ratio between females and males") +
theme(plot.title = element_text(hjust = 0.5))

# scatter plot vs executives mean salary
ggplot(salary, aes(x= sal_general, y= salary_ratio_FvsM_midManag)) +
geom_point(size = 0.5, colour = "#0091ff")+
labs(x="Overall salary", y="Middle managers salary ratio (females/males)") +
labs(title = "Middle managers salary ratio between females and males \n vs. overall salary") +
theme(plot.title = element_text(hjust = 0.5)) +
geom_smooth(method = "lm")

# Workers mean salary: ...
# create workers F vs M ratio
salary$salary_ratio_FvsM_worker <- salary$sal_F_worker / salary$sal_M_worker
# histogram
ggplot(data=salary, aes(salary$salary_ratio_FvsM_worker)) +
geom_histogram(aes(y =..density..), col="black", fill="blue", alpha = .3, bins = 50) +
geom_density(col="black") +
labs(x="Workers salary ratio (females/males)", y="Density") +
labs(title = "Workers salary ratio between females and males") +
theme(plot.title = element_text(hjust = 0.5))

# scatter plot vs workers mean salary
ggplot(salary, aes(x= sal_general, y= salary_ratio_FvsM_worker)) +
geom_point(size = 0.5, colour = "#0091ff")+
labs(x="Overall salary", y="Workers salary ratio (females/males)") +
labs(title = "Workers salary ratio between females and males \n vs. overall salary") +
theme(plot.title = element_text(hjust = 0.5)) +
geom_smooth(method = "lm")

# Employee mean salary: ...
# create Employee F vs M ratio
salary$salary_ratio_FvsM_employee <- salary$sal_F_employee / salary$sal_M_employee
# histogram
ggplot(data=salary, aes(salary$salary_ratio_FvsM_employee)) +
geom_histogram(aes(y =..density..), col="black", fill="blue", alpha = .3, bins = 50) +
geom_density(col="black") +
labs(x="Employee salary ratio (females/males)", y="Density") +
labs(title = "Employee salary ratio between females and males") +
theme(plot.title = element_text(hjust = 0.5))

# scatter plot vs Employee mean salary
ggplot(salary, aes(x= sal_general, y= salary_ratio_FvsM_employee)) +
geom_point(size = 0.5, colour = "#0091ff")+
labs(x="Overall salary", y="Employee salary ratio (females/males)") +
labs(title = "Employee salary ratio between females and males \n vs. overall salary") +
theme(plot.title = element_text(hjust = 0.5)) +
geom_smooth(method = "lm")

Now the focus is on the salary ratio between women and men among different age groups:
# 18-25 mean salary: are quite equal apart from some outliers and a quadratic trend
# create 18-25 F vs M ratio
salary$salary_ratio_FvsM_18_25 <- salary$sal_F_18_25 / salary$sal_M_18_25
# histogram
ggplot(data=salary, aes(salary$salary_ratio_FvsM_18_25)) +
geom_histogram(aes(y =..density..), col="black", fill="blue", alpha = .3, bins = 50) +
geom_density(col="black") +
labs(x="18-25 salary ratio (females/males)", y="Density") +
labs(title = "18-25 salary ratio between females and males") +
theme(plot.title = element_text(hjust = 0.5))

# scatter plot vs 18-25 mean salary
ggplot(salary, aes(x= sal_general, y= salary_ratio_FvsM_18_25)) +
geom_point(size = 0.5, colour = "#0091ff")+
labs(x="Overall salary", y="18-25 salary ratio (females/males)") +
labs(title = "18-25 salary ratio between females and males \n vs. overall salary") +
theme(plot.title = element_text(hjust = 0.5)) +
geom_smooth(method = "lm")

# scatter plot vs 18-25 mean salary for them
ggplot(salary, aes(x= sal_18_25, y= salary_ratio_FvsM_18_25)) +
geom_point(size = 0.5, colour = "#0091ff")+
labs(x="18-25 salary", y="18-25 salary ratio (females/males)") +
labs(title = "18-25 salary ratio between females and males \n vs. overall 18-25 salary") +
theme(plot.title = element_text(hjust = 0.5)) +
geom_smooth(method = "loess")

# 26-50 mean salary: ...
# create 26-50 F vs M ratio
salary$salary_ratio_FvsM_26_50 <- salary$sal_F_26_50 / salary$sal_M_26_50
# histogram
ggplot(data=salary, aes(salary$salary_ratio_FvsM_26_50)) +
geom_histogram(aes(y =..density..), col="black", fill="blue", alpha = .3, bins = 50) +
geom_density(col="black") +
labs(x="26-50 salary ratio (females/males)", y="Density") +
labs(title = "26-50 salary ratio between females and males") +
theme(plot.title = element_text(hjust = 0.5))

# scatter plot vs 26-50 mean salary
ggplot(salary, aes(x= sal_general, y= salary_ratio_FvsM_26_50)) +
geom_point(size = 0.5, colour = "#0091ff")+
labs(x="Overall salary", y="26-50 salary ratio (females/males)") +
labs(title = "26-50 salary ratio between females and males \n vs. overall salary") +
theme(plot.title = element_text(hjust = 0.5)) +
geom_smooth(method = "lm")

# 51+ mean salary: ...
# create 51+ F vs M ratio
salary$salary_ratio_FvsM_51plus <- salary$sal_F_51plus / salary$sal_M_51plus
# histogram
ggplot(data=salary, aes(salary$salary_ratio_FvsM_51plus)) +
geom_histogram(aes(y =..density..), col="black", fill="blue", alpha = .3, bins = 50) +
geom_density(col="black") +
labs(x="51+ salary ratio (females/males)", y="Density") +
labs(title = "51+ salary ratio between females and males") +
theme(plot.title = element_text(hjust = 0.5))

# scatter plot vs 26-50 mean salary
ggplot(salary, aes(x= sal_general, y= salary_ratio_FvsM_51plus)) +
geom_point(size = 0.5, colour = "#0091ff")+
labs(x="Overall salary", y="51+ salary ratio (females/males)") +
labs(title = "51+ salary ratio between females and males \n vs. overall salary") +
theme(plot.title = element_text(hjust = 0.5)) +
geom_smooth(method = "lm")

Highlight bivariate relations:
# correlation matrix
corrplot(cor(salary[, 3:ncol(salary)]), method = "circle", title = "Correlation matrix for salary data",
diag = T, tl.cex=0.5, type="lower",
tl.col = "black", mar=c(0,0,1.5,0))

# most general pairs
pairs(salary[c(3:8, 13, 18:20)], gap=0, main = "Scatter matrix of the main variables in salary data", cex = 0.6)

# pairs highlighting genders' differences
pairs(salary[c(9:12, 14:17)], gap=0, main = "Scatter matrix of job categories for both genders", cex = 0.6)

Population data
Plot population data across different towns:
# Histogram of total population per town in log
ggplot(data=population, aes(ifelse(total_population!=0, log10(total_population), 0))) +
geom_histogram(aes(y =..density..), col="black", fill="blue", alpha = .3, bins = 50) +
geom_density(col="black") +
labs(x="Log10 total population", y="Density") +
ggtitle("Histogram of total population per town in log10 scale") +
theme(plot.title = element_text(hjust = 0.5))

# Histogram of dependency ratio per town
ggplot(data=population, aes(ifelse(dependency_ratio!=0, log10(dependency_ratio), 0))) +
geom_histogram(aes(y =..density..), col="black", fill="blue", alpha = .3, bins = 50) +
geom_density(col="black") +
labs(x="Log10 dependency ratio", y="Density") +
ggtitle("Histogram of dependency ratio per town in log10 scale") +
theme(plot.title = element_text(hjust = 0.5))

# Histogram of sex ratio per town
ggplot(data=population, aes(ifelse(sex_ratio!=0, log10(sex_ratio), 0))) +
geom_histogram(aes(y =..density..), col="black", fill="blue", alpha = .3, bins = 50) +
geom_density(col="black") +
labs(x="Log10 sex ratio", y="Density") +
ggtitle("Histogram of sex ratio per town in log10 scale") +
theme(plot.title = element_text(hjust = 0.5))

Understand which towns have the highest concentration of population and ratios.
# Merge geography and population data
# geo_population <- merge(geo, population, by="CODGEO")
geo_population <- cbind.data.frame(geo[unique(geo$CODGEO) %in% unique(population$CODGEO),],
population[unique(population$CODGEO) %in% unique(geo$CODGEO),])
# France map
FraMap = ggmap(get_googlemap(center=fra_center, scale=2, zoom=6), extent="normal")
Map from URL : http://maps.googleapis.com/maps/api/staticmap?center=46.227638,2.213749&zoom=6&size=640x640&scale=2&maptype=terrain&sensor=false
# Plot "Distribution of total population for each town"
sc <- scale_colour_gradientn(colours =palette(rainbow(3)), limits=c(log10(min(geo_population$total_population)),
log10(max(geo_population$total_population))))
population_distribution <-
FraMap +
geom_point(aes(x=geo_population$longitude, y=geo_population$latitude,
colour=log10(geo_population$total_population)),
data=geo_population, alpha=0.2, size=0.01) +
sc + labs(color='') + ggtitle("Distribution of Population for each town")
population_distribution
# Plot "Distribution of aged dependency ratio for each town"
sc <- scale_colour_gradientn(colours =palette(rainbow(4)), limits=c(min(geo_population$aged_dependency_ratio),
max(geo_population$aged_dependency_ratio)))

aged_ratio_distribution <-
FraMap +
geom_point(aes(x=geo_population$longitude, y=geo_population$latitude,
colour=geo_population$aged_dependency_ratio),
data=geo_population, alpha=1, size=1) +
sc + labs(color='') + ggtitle("Aged dependency ratio per town")
aged_ratio_distribution

# which city has the highest/lowest aged dependency ratio
geo_population[which.min(geo_population$aged_dependency_ratio),c('CODGEO')]
[1] 77183
geo_population[which.max(geo_population$aged_dependency_ratio),c('CODGEO')]
[1] 85003
# get list of top 10 highest aged dependency ratio
Rank = sort(population$aged_dependency_ratio, TRUE)
Rank10 = sort(Rank[1:10], TRUE)
sol = rep(0, 10)
for (i in 1:10){
sol[i] = paste(geo_population$CODGEO[geo_population$aged_dependency_ratio %in% Rank10[i]] )
}
# remove the dataset created to save memory
rm(list = c("geo_population", "Rank", "Rank10"))
What we have learned
We can observe that in urban cities, the aged dependcy ratio is lower compared to non-urban cities. The city with the lowest aged dependency ratio is La Fert?-sous-Jouarre and the highest is L’Aiguillon-sur-Mer.
Education data
# Difference between male and female's education level (with University degrees)
summary(educ$male_Univ)
Min. 1st Qu. Median Mean 3rd Qu. Max.
42.0 206.0 329.0 960.3 656.0 440490.0
summary(educ$female_Univ)
Min. 1st Qu. Median Mean 3rd Qu. Max.
57 255 395 1100 776 486406
Min. 1st Qu. Median Mean 3rd Qu. Max.
58.0 260.0 401.0 904.1 754.0 138888.0
summary(educ$female_NoDip)
Min. 1st Qu. Median Mean 3rd Qu. Max.
107 356 567 1242 1081 177240
# Merge geo and educ data to include longitude and latitude in the data.
geo_educ <- cbind.data.frame(geo[unique(geo$CODGEO) %in% unique(educ$CODGEO),],
educ[unique(educ$CODGEO) %in% unique(geo$CODGEO),])
# check the ratio of individuals with high and low education level for each town.
summary(educ$univ/educ$nodip)
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.1149 0.4989 0.7689 0.9438 1.1728 7.7004
# Histogram of the ratio of individuals with high and low education level for each town
ggplot(data=educ, aes(log(educ$univ/educ$nodip))) +
geom_histogram(aes(y=..density..), col="black", fill="blue", alpha=0.3, bins= 50)+
geom_density(col="black") +
labs(x="log. University degree/No diploma", y="Density") +
ggtitle("Ratio between the number of individuals with no diploma and
individuals with University degree per town") +
theme(plot.title =element_text(hjust= 0.5))

# Adjust scales before plotting
sc <- scale_colour_gradientn(colours = c("#56ddc5", "#F8766D", "#00BA38"), limits=c(min(educ$univ/educ$nodip), max(educ$univ/educ$nodip)))
# Map ratio
educ_ratio_NoDipUniv <-
FraMap +
geom_point(aes(x=geo_educ$longitude, y=geo_educ$latitude,
colour=educ$univ/educ$nodip),
data=geo_educ, alpha=1, size=1) +
sc + labs(color='Ratio') + ggtitle("Education level ratio for each town")
educ_ratio_NoDipUniv

# Statistics of shape for the data
# library(psych)
describe(educ$univ/educ$nodip)
vars n mean sd median trimmed mad min max range skew kurtosis se
X1 1 5025 0.94 0.67 0.77 0.84 0.47 0.11 7.7 7.59 2.4 9.98 0.01
# remove the dataset created to save memory
rm(list=c("geo_educ", "educ_ratio_NoDipUniv"))
What we have learned
In average 960 males have university degree and 1100 females have university degree.
In average 904 males have no diploma and 1242 females have no diploma. Highest ratio in Paris=78251=Yvelines
Demographic/social profiles data
Observations: 5,025
Variables: 9
$ CODGEO <int> 1004, 1007, 1014, 1024, 1025, 1027, 1031, 1032, 1033, 1...
$ male_immig <dbl> 702, 55, 456, 55, 60, 63, 397, 72, 1304, 519, 115, 90, ...
$ female_immig <dbl> 660, 45, 427, 65, 35, 38, 397, 92, 1337, 490, 145, 65, ...
$ total_immig <dbl> 1362, 100, 883, 120, 95, 101, 794, 164, 2641, 1009, 260...
$ male_working_immig <dbl> 568, 25, 334, 51, 45, 59, 308, 56, 1006, 400, 90, 70, 2...
$ female_working_immig <dbl> 562, 25, 333, 52, 30, 34, 348, 80, 1069, 387, 100, 45, ...
$ male_native <dbl> 6076, 1174, 1325, 1581, 1548, 1798, 1391, 1524, 4448, 3...
$ female_native <dbl> 6586, 1289, 1195, 1681, 1534, 1063, 1463, 1626, 4645, 4...
$ total_native <dbl> 12662, 2463, 2520, 3262, 3082, 2861, 2854, 3150, 9093, ...
# merge geo and categ_socio
geo_categ_socio <- cbind.data.frame(geo[unique(geo$CODGEO) %in% unique(categ_socio$CODGEO),],
categ_socio[unique(categ_socio$CODGEO) %in% unique(geo$CODGEO),])
# find which cities have the most and least number of immigrants
categ_socio[which.max(categ_socio$total_immig),c('CODGEO')]
[1] 75056
categ_socio[which.min(categ_socio$total_immig),c('CODGEO')]
[1] 33154
# get list of top 10 cities with the most number of immigrants
Rank = sort(categ_socio$total_immig, TRUE)
Rank10 = sort(Rank[1:10], TRUE)
sol = rep(0, 10)
for (i in 1:10){
sol[i] = paste(geo_categ_socio$region[categ_socio$total_immig %in% Rank10[i]] )
}
# Adjust scales before plotting
sc <- scale_colour_gradientn(colours = c("#F8766D", "#00BA38"), limits=c(min(geo_categ_socio$total_immig/population$total_population), max(geo_categ_socio$total_immig/population$total_population)))
# Map ratio
distribution_immig <-
FraMap +
geom_point(aes(x=geo_categ_socio$longitude, y=geo_categ_socio$latitude,
colour=geo_categ_socio$total_immig/population$total_population),
data=geo_categ_socio, alpha=1, size=1) +
sc + labs(color='') + ggtitle("Immigrants for each town")
distribution_immig

What we have learned
City with the least number of immigrants is Rennes and the most is Paris. =“Ãle-de-France” “Provence-Alpes-Côte d’Azur” “Rhône-Alpes” “Midi-Pyrénées”
“Provence-Alpes-Côte d’Azur” “Alsace” “Languedoc-Roussillon” “Ãle-de-France”
“Ãle-de-France” “Ãle-de-France”
Work status data
CODGEO wagearner_M wagearner_F independent_M independent_F
Min. : 1004 Min. : 0 Min. : 0 Min. : 0.0 Min. : 0.00
1st Qu.:31455 1st Qu.: 274 1st Qu.: 299 1st Qu.: 37.0 1st Qu.: 23.00
Median :56017 Median : 589 Median : 594 Median : 62.0 Median : 40.00
Mean :51625 Mean : 1964 Mean : 2011 Mean : 149.8 Mean : 99.83
3rd Qu.:73008 3rd Qu.: 1412 3rd Qu.: 1334 3rd Qu.: 112.0 3rd Qu.: 75.00
Max. :97113 Max. :751026 Max. :828113 Max. :78180.0 Max. :56586.00
transfer_M transfer_F employer_M employer_F
Min. : 0.000 Min. : 0.000 Min. : 0.0 Min. : 0.00
1st Qu.: 0.000 1st Qu.: 0.000 1st Qu.: 34.0 1st Qu.: 10.00
Median : 0.000 Median : 0.000 Median : 59.0 Median : 20.00
Mean : 1.287 Mean : 3.183 Mean : 134.4 Mean : 48.01
3rd Qu.: 0.000 3rd Qu.: 5.000 3rd Qu.: 110.0 3rd Qu.: 40.00
Max. :761.000 Max. :889.000 Max. :54988.0 Max. :20580.00
full_M full_F half_M half_F
Min. : 0 Min. : 0 Min. : 0.0 Min. : 0.0
1st Qu.: 332 1st Qu.: 227 1st Qu.: 26.0 1st Qu.: 105.0
Median : 662 Median : 458 Median : 53.0 Median : 198.0
Mean : 2071 Mean : 1580 Mean : 178.3 Mean : 581.9
3rd Qu.: 1526 3rd Qu.: 1030 3rd Qu.: 118.0 3rd Qu.: 417.0
Max. :790568 Max. :712040 Max. :94387.0 Max. :194128.0
full half wagearner independent
Min. : 0 Min. : 0.0 Min. : 0 Min. : 0.0
1st Qu.: 575 1st Qu.: 135.0 1st Qu.: 588 1st Qu.: 62.0
Median : 1126 Median : 252.0 Median : 1194 Median : 102.0
Mean : 3651 Mean : 760.2 Mean : 3975 Mean : 249.6
3rd Qu.: 2568 3rd Qu.: 536.0 3rd Qu.: 2772 3rd Qu.: 180.0
Max. :1502608 Max. :288515.0 Max. :1579139 Max. :134766.0
transfer employer
Min. : 0.000 Min. : 0.0
1st Qu.: 0.000 1st Qu.: 45.0
Median : 0.000 Median : 79.0
Mean : 4.471 Mean : 182.4
3rd Qu.: 5.000 3rd Qu.: 148.0
Max. :1650.000 Max. :75568.0
[1] "CODGEO" "wagearner_M" "wagearner_F" "independent_M" "independent_F"
[6] "transfer_M" "transfer_F" "employer_M" "employer_F" "full_M"
[11] "full_F" "half_M" "half_F" "full" "half"
[16] "wagearner" "independent" "transfer" "employer"
# merge geo and status_work
# geo_status_work <- cbind.data.frame(geo[unique(geo$CODGEO) %in% unique(status_work$CODGEO),],
# status_work[unique(status_work$CODGEO) %in% unique(geo$CODGEO),])
geo_status_work <- cbind.data.frame(geo[unique(geo$CODGEO) %in% unique(status_work$CODGEO),],
status_work[unique(status_work$CODGEO) %in% unique(geo$CODGEO),])
# which town has the most/least people receiving government transfers
status_work[which.max(status_work$transfer),c('CODGEO')]
[1] 75056
status_work[which.min(status_work$transfer),c('CODGEO')]
[1] 1007
# get list of top 10 cities with the people receiving government transfers
Rank = sort(status_work$transfer, TRUE)
Rank10 = sort(Rank[1:10], TRUE)
sol = rep(0, 10)
for (i in 1:10){
sol[i] = paste(geo_status_work$CODGEO[status_work$transfer %in% Rank10[i]])
}
# which town has the most/least people with part time contract.
status_work[which.max(status_work$half),c('CODGEO')]
[1] 75056
status_work[which.min(status_work$half),c('CODGEO')]
[1] 76095
# get list of top 10 cities with the most part-time contract.
Rank = sort(status_work$half, TRUE)
Rank10 = sort(Rank[1:10], TRUE)
sol = rep(0, 10)
for (i in 1:10){
sol[i] = paste(status_work$CODGEO[status_work$half %in% Rank10[i]] )
}
# Histogram (Females with full time contract)
describe(status_work$full_F) # Skewness
vars n mean sd median trimmed mad min max range skew kurtosis
X1 1 5025 1580.12 11070.87 458 658.08 422.54 0 712040 712040 53.63 3381.11
se
X1 156.18
ggplot(data=status_work, aes(ifelse(full_F!=0, log(full_F), 0))) +
geom_histogram(aes(y =..density..), col="black", fill="blue", alpha = .3, bins = 50) +
geom_density(col="black") +
labs(x="", y="Density") +
ggtitle("Female workers with full time contract") +
theme(plot.title = element_text(hjust = 0.5))

# Histogram (males with full time contract)
describe(status_work$full_M) # Skewness
vars n mean sd median trimmed mad min max range skew kurtosis
X1 1 5025 2070.78 12491.66 662 953.99 616.76 0 790568 790568 51.29 3167.63
se
X1 176.22
ggplot(data=status_work, aes(ifelse(full_M!=0, log(full_M), 0))) +
geom_histogram(aes(y =..density..), col="black", fill="blue", alpha = .3, bins = 50) +
geom_density(col="black") +
labs(x="", y="Density") +
ggtitle("Male workers with full time contract") +
theme(plot.title = element_text(hjust = 0.5))

# Histogram: Contract type ratio
describe(status_work$half/status_work$full) # Skewness
vars n mean sd median trimmed mad min max range skew kurtosis se
X1 1 5024 0.24 0.09 0.23 0.23 0.07 0.04 0.82 0.78 1.24 3.45 0
ggplot(data=status_work, aes(status_work$half/status_work$full)) +
geom_histogram(aes(y =..density..), col="black", fill="blue", alpha = .3, bins = 50) +
geom_density(col="black") +
labs(x="Contract type ratio (temporary/full time)", y="Density") +
ggtitle("Contract type ratio") +
theme(plot.title = element_text(hjust = 0.5))

# number of units
n_sex <- length(status_work$wagearner_F)
# vector representing males and females
Label <- c(rep("M", n_sex*6), rep("F", n_sex*6))
# vector representing the variable considered
Variable <- c(rep("Wagearner", n_sex),
rep("Independent", n_sex),
rep("Transfer", n_sex),
rep("Employer", n_sex),
rep("Full",n_sex),
rep("Half", n_sex))
# merge these data
status_sex = cbind.data.frame(Label = Label,
value = c(status_work$wagearner_M, status_work$wagearner_F, status_work$independent_M,
status_work$independent_F, status_work$transfer_M, status_work$transfer_F,
status_work$employer_M, status_work$employer_F, status_work$full_M, status_work$full_F,
status_work$half_M, status_work$half_F),
Variable = Variable)
# plotting phase
ggplot(data = status_sex, aes(x=Label, y=value)) +
geom_boxplot(aes(fill = Label)) +
geom_point(aes(y=value, colour=Label), position = position_dodge(width=0.75)) +
facet_wrap( ~ Variable, scales="free") +
xlab("Sex") + ylab("# of individuals") + ggtitle("Gender comparison") +
theme(plot.title = element_text(hjust = 0.5)) +
stat_boxplot(geom = "errorbar", width = 0.5)

# the same but excluding outliers
ggplot(data = status_sex, aes(x=Label, y=value)) +
scale_y_continuous(limits = quantile(status_sex$value, c(0, 0.9))) +
geom_boxplot(aes(fill = Label)) +
geom_point(aes(y=value, colour=Label), position = position_dodge(width=0.75)) +
facet_wrap( ~ Variable, scales="free") +
xlab("Sex") + ylab("# of individuals") +
ggtitle("Gender comparison excluding the last decile") +
theme(plot.title = element_text(hjust = 0.5)) +
stat_boxplot(geom = "errorbar", width = 0.5)

What we have learned
Paris is the city where they have the most individuals receiving government transfers. Lyon is the city where they have the least individuals receiving government transfers. =“Ãle-de-France” “Provence-Alpes-Côte d’Azur” “Provence-Alpes-Côte d’Azur” “Rhône-Alpes”
“Midi-Pyrénées” “Aquitaine” “Languedoc-Roussillon” “Pays de la Loire”
“Rhône-Alpes” “Alsace”
Paris has most individuals with half time contract. Rouen has the least. = “Ãle-de-France” “Rhône-Alpes” “Provence-Alpes-Côte d’Azur” “Midi-Pyrénées”
“Pays de la Loire” “Nord-Pas-de-Calais” “Alsace” “Languedoc-Roussillon”
“Aquitaine” “Bretagne”
In average, more females receive transfers than males. In average, more females have part-time contract than males. (In average, 581 females have part-time contract (in each town) and 178 males have part-time contract. (More males have full-time contract.)
More females work as wage-earners than males. =All these facts can be related to vulnerability of females in the labour market. Many studies show that females are mostly working as part-time workers and lower job categories. On top of this, more females receive transfers. We can also observe this in our data that more males are registered as independent workers or employers.
Inequality data
Observations: 5,025
Variables: 12
$ CODGEO <int> 1004, 1007, 1014, 1024, 1025, 1027, 1031, 1032, 1033, 1034, ...
$ REG <int> 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, ...
$ DEP <fctr> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,...
$ Superficie <int> 25, 34, 23, 19, 40, 18, 8, 13, 15, 22, 11, 9, 24, 6, 9, 33, ...
$ housing14 <int> 6838, 1160, 1453, 1362, 1242, 688, 1867, 1253, 5801, 4804, 1...
$ median_living14 <int> 19756, 21679, 19806, 21143, 21781, 22310, 18911, 20612, 1934...
$ empl <int> 7453, 488, 2128, 852, 474, 2117, 2113, 1430, 4328, 5722, 335...
$ emp_sal <int> 6743, 373, 1940, 738, 354, 1903, 1934, 1297, 3824, 5099, 303...
$ pop15_64 <int> 8963, 1614, 2217, 2163, 2043, 2361, 2426, 2059, 7271, 5286, ...
$ unemp15_64 <int> 1060, 108, 204, 121, 120, 69, 263, 165, 976, 647, 193, 111, ...
$ act15_64 <int> 6682, 1267, 1596, 1726, 1634, 2020, 1776, 1627, 5551, 3923, ...
$ unemp_rate <dbl> 0.11826397, 0.06691450, 0.09201624, 0.05594082, 0.05873715, ...
# merge geo and ineq
geo_ineq <- cbind.data.frame(geo[unique(geo$CODGEO) %in% unique(ineq$CODGEO),],
ineq[unique(ineq$CODGEO) %in% unique(geo$CODGEO),])
# which city has the highest/lowest unemployment rate
ineq[which.max(ineq$unemp_rate),c('CODGEO')]
[1] 33402
ineq[which.min(ineq$unemp_rate),c('CODGEO')]
[1] 73257
# get list of top 10 cities with the highest unemployment rate.
Rank = sort(ineq$unemp_rate, TRUE)
Rank10 = sort(Rank[1:10], TRUE)
sol = rep(0, 10)
for (i in 1:10){
sol[i] = paste(ineq$CODGEO[ineq$unemp_rate %in% Rank10[i]] )
}
# which is the smallest/biggest city (area)
ineq[which.max(ineq$Superficie),c('CODGEO')]
[1] 13004
ineq[which.min(ineq$Superficie),c('CODGEO')]
[1] 6011
# which city has the highest/lowest median living level
ineq[which.max(ineq$median_living14),c('CODGEO')]
[1] 74016
ineq[which.min(ineq$median_living14),c('CODGEO')]
[1] 93014
# Adjust scales before plotting
sc <- scale_colour_gradientn(colours = c("#56ddc5", "#ff3db7"), limits=c(min(ineq$unemp_rate), max(ineq$unemp_rate)))
# Map ratio
ineq_unempl_distribution <-
FraMap +
geom_point(aes(x=geo_ineq$longitude, y=geo_ineq$latitude,
colour=geo_ineq$unemp_rate),
data=geo_ineq, alpha=1, size=1) +
sc + labs(color='Unemployment rate') + ggtitle("Unemployment rate for each town")
ineq_unempl_distribution

# remove the dataset created to save memory
rm(list=c("geo_ineq", "ineq_unempl_distribution"))
What we have learned
Bordeaux has the highest unemployment rate. Nantes has the lowest unemployment rate. =“Aquitaine” “Languedoc-Roussillon” “Nord-Pas-de-Calais” “Haute-Normandie” “Guadeloupe”
“Corse” “Nord-Pas-de-Calais” “Corse” “Rhône-Alpes” “Nord-Pas-de-Calais”
Commune data
Observations: 5,025
Variables: 25
$ CODGEO <int> 1004, 1007, 1014, 1024, 1025, 1027, 1031, 1032, 1...
$ orient_econ <fctr> Bassin Résidentiel, Bassin Résidentiel, Bassin...
$ nb_household <int> 4640, 798, 1139, 719, 797, 482, 1484, 855, 4526, ...
$ nb_female <int> 11350, 2078, 3480, 1828, 2220, 1372, 3344, 2442, ...
$ nb_male <int> 10878, 2096, 3560, 1922, 2280, 1590, 3476, 2546, ...
$ nb_minor <int> 13624, 2586, 4537, 2295, 2886, 1871, 4184, 3233, ...
$ nb_major <int> 8604, 1588, 2503, 1455, 1614, 1091, 2636, 1755, 8...
$ nb_students <int> 904, 173, 335, 159, 152, 133, 385, 190, 755, 519,...
$ nb_firms_service <int> 342, 33, 63, 34, 17, 17, 70, 34, 264, 288, 108, 3...
$ nb_firms_commerce <int> 301, 27, 96, 24, 22, 33, 54, 32, 270, 236, 140, 4...
$ nb_firms_construction <int> 58, 17, 22, 20, 14, 9, 15, 22, 83, 36, 49, 21, 17...
$ nb_firms_ind <int> 108, 24, 106, 22, 16, 26, 102, 34, 83, 103, 75, 3...
$ nb_created_firms <int> 83, 14, 19, 7, 8, 5, 12, 14, 42, 54, 37, 9, 226, ...
$ nb_created_ind <int> 4, 1, 1, 1, 0, 0, 2, 2, 3, 3, 0, 0, 17, 1, 1, 1, ...
$ nb_created_construction <int> 14, 2, 3, 0, 1, 0, 2, 1, 15, 10, 6, 1, 31, 1, 3, ...
$ nb_created_commerce <int> 27, 1, 7, 4, 2, 5, 3, 1, 6, 18, 7, 3, 63, 5, 2, 2...
$ nb_created_services <int> 38, 10, 8, 2, 5, 0, 5, 10, 18, 23, 24, 5, 115, 3,...
$ urbanRural <fctr> Com < 50 m habts, Com rurale > 2 000 habts, Com ...
$ nb_active <int> 4556, 921, 1589, 912, 1070, 740, 1727, 1115, 4382...
$ nb_active_employees <int> 4203, 798, 1418, 814, 906, 678, 1594, 1005, 4033,...
$ nb_active_non_employees <int> 353, 123, 171, 98, 164, 62, 133, 110, 349, 320, 2...
$ dymanic_demo_prof <fctr> 1.Accroissement par excédent naturel et migrato...
$ regional_GDP <int> 173681, 173681, 173681, 173681, 173681, 173681, 1...
$ evol_pop_score <fctr> 72,95082, 72,54098, 75, 72,54098, 72,54098, 74,5...
$ evol_entrepreneurial_score <fctr> 0,38471, 0,03314, 0,09539, 0,04784, 0,0317, 0,05...
# change the factor variables to numeric
# aaa = as.numeric(commune$urbanRural)
# Merge geo and commune data to include longitude and latitude in the data.
geo_commune <- cbind.data.frame(geo[unique(geo$CODGEO) %in% unique(commune$CODGEO),],
commune[unique(commune$CODGEO) %in% unique(geo$CODGEO),])
# Adjust scales before plotting
#sc <- scale_colour_gradientn(colours = palette(rainbow(3)), limits=c(min(aaa), max(aaa)))
# Map ratio
# urbanrural<-
# FraMap +
# geom_point(aes(x=geo_commune$longitude, y=geo_commune$latitude,
# colour=aaa),
# data=geo_commune, alpha=1, size=0.5) +
# sc + labs(color='') + ggtitle("Urban and rural cities")
# urbanrural
# boxplot
# number of units
n_firms <- length(commune$nb_firms_commerce)
# vector
Label <- c(rep("Firms", n_firms*4))
# vector representing the variable considered
Variable <- c(rep("Service", n_firms),
rep("Industry", n_firms),
rep("Commerce", n_firms),
rep("Construction", n_firms))
# merge these data
firms_sector = cbind.data.frame(Label = Label,
value = c(commune$nb_firms_commerce, commune$nb_firms_service, commune$nb_firms_ind, commune$nb_firms_construction),
Variable = Variable)
# plotting phase
ggplot(data = firms_sector, aes(x=Label, y=value)) +
geom_boxplot(aes(fill = Label)) +
geom_point(aes(y=value, colour=Label), position = position_dodge(width=0.75)) +
facet_wrap( ~ Variable, scales="free") +
xlab("Firms") + ylab("# of firms") + ggtitle("Sector comparison") +
theme(plot.title = element_text(hjust = 0.5)) +
stat_boxplot(geom = "errorbar", width = 0.5)

# the same but excluding outliers
ggplot(data = firms_sector, aes(x=Label, y=value)) +
scale_y_continuous(limits = quantile(firms_sector$value, c(0, 0.9))) +
geom_boxplot(aes(fill = Label)) +
geom_point(aes(y=value, colour=Label), position = position_dodge(width=0.75)) +
facet_wrap( ~ Variable, scales="free") +
xlab("Firms") + ylab("# of firms") +
ggtitle("Sector comparison excluding the last decile") +
theme(plot.title = element_text(hjust = 0.5)) +
stat_boxplot(geom = "errorbar", width = 0.5)

rm(list = c("geo_commune", "Rank", "Rank10", "aaa"))
object 'aaa' not found
Supervised Learning
ANOVA for salary
First the distribution of salary for both genders is considered, in original and log-scale
# original data
# male
ggplot(data=data.frame(newDat$sal_Males), aes(newDat$sal_Males)) +
geom_histogram(aes(y =..density..), col="black", fill="blue", alpha = .3, bins = 40) +
geom_density(col="black") +
labs(x="Male salaries", y="Density") +
ggtitle("Distribution of salary for males") +
theme(plot.title = element_text(hjust = 0.5))

# females
ggplot(data=data.frame(newDat$sal_Females), aes(newDat$sal_Females)) +
geom_histogram(aes(y =..density..), col="black", fill="blue", alpha = .3, bins = 40) +
geom_density(col="black") +
labs(x="Female salaries", y="Density") +
ggtitle("Distribution of salary for females") +
theme(plot.title = element_text(hjust = 0.5))

# log data
# male
ggplot(data=data.frame(log10(newDat$sal_Males)), aes(log10(newDat$sal_Males))) +
geom_histogram(aes(y =..density..), col="black", fill="blue", alpha = .3, bins = 40) +
geom_density(col="black") +
labs(x="Log10 male salaries", y="Density") +
ggtitle("Distribution of salary for males in log scale") +
theme(plot.title = element_text(hjust = 0.5))

# females
ggplot(data=data.frame(log10(newDat$sal_Females)), aes(log10(newDat$sal_Females))) +
geom_histogram(aes(y =..density..), col="black", fill="blue", alpha = .3, bins = 40) +
geom_density(col="black") +
labs(x="Log10 female salaries", y="Density") +
ggtitle("Distribution of salary for females in log scale") +
theme(plot.title = element_text(hjust = 0.5))

# hist(c(log10(newDat$sal_Males), log10(newDat$sal_Females)), 30)
It is clear that the normality assumption, cannot hold.
At the same time, it is shown how to check if the difference in the mean in salary between males and females using a t-test
t.test(log10(newDat$sal_Males), log10(newDat$sal_Females), alternative = c("two.sided"))
Welch Two Sample t-test
data: log10(newDat$sal_Males) and log10(newDat$sal_Females)
t = 64.095, df = 9332.7, p-value < 2.2e-16
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
0.0857778 0.0911900
sample estimates:
mean of x mean of y
1.165991 1.077507
This solution can also be otbained fitting a linear model with a dummy variable catching the sex effect, which corresponds to a one-way ANOVA model
# create the reponse attaching the salary for each sex
sal_y = c(log10(newDat$sal_Males), log10(newDat$sal_Females))
# create the dummy variable controlling for the corresponding sex
dummy = c(rep(1, length(newDat$sal_Males)), rep(0, length(newDat$sal_Females)))
# the t value is exactly the same as the one obtained in the previous t-test
sal_ANOVA = lm(sal_y ~ dummy)
summary(sal_ANOVA)
Call:
lm(formula = sal_y ~ dummy)
Residuals:
Min 1Q Median 3Q Max
-0.14896 -0.04542 -0.01677 0.02970 0.55334
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.0775073 0.0009762 1103.81 <2e-16 ***
dummy 0.0884839 0.0013805 64.09 <2e-16 ***
---
Signif. codes: 0 *** 0.001 ** 0.01 * 0.05 . 0.1 1
Residual standard error: 0.06918 on 10042 degrees of freedom
Multiple R-squared: 0.2903, Adjusted R-squared: 0.2903
F-statistic: 4108 on 1 and 10042 DF, p-value: < 2.2e-16
# residuals plot
plot(sal_ANOVA$residuals)
abline (0, 0, col = "red")

To improve such analysis some more aspects are now considered. In particualar, the model considered in an ANOVA, where the predictors take in account each gender for different age and job levels, plus their interaction terms.
First of all the dataset is created and a subsample of it is considered, in order to avoid strong correlation among units
set.seed(300)
# create response variable
sal_y = c(newDat$sal_M_18_25, newDat$sal_M_26_50, newDat$sal_M_51plus,
newDat$sal_M_executive, newDat$sal_M_midManager, newDat$sal_M_employee, newDat$sal_M_worker,
newDat$sal_F_18_25, newDat$sal_F_26_50, newDat$sal_F_51plus,
newDat$sal_F_executive, newDat$sal_F_midManager, newDat$sal_F_employee, newDat$sal_F_worker)
n_sal_y = length(sal_y) # length response variable
n_cat = length(newDat$sal_M_18_25) # length of each category (i.e., original vectors)
# create sex dummy variable, 1 for males and 0 for females
sal_sex = rep(0, n_sal_y) # full regressors
sal_sex[1:n_sal_y/2] = 1 # assign males
# create age dummy variables, 18-25 years old is the base case
sal_age = cbind(rep(0, n_sal_y), rep(0, n_sal_y)) # full regressors
# 26-50 y.o.
sal_age[(n_cat+1):(n_cat*2), 1] = 1 # males
sal_age[(n_cat*8+1):(n_cat*9), 1] = 1 # females
# 51+ y.o.
sal_age[(n_cat*2+1):(n_cat*3), 2] = 1 # males
sal_age[(n_cat*9+1):(n_cat*10), 2] = 1 # females
# create job type dummy variables, worker is the base case
sal_job = cbind(rep(0, n_sal_y), rep(0, n_sal_y), rep(0, n_sal_y)) # full regressors
# executives
sal_job[(n_cat*3+1):(n_cat*4), 1] = 1 # males
sal_job[(n_cat*10+1):(n_cat*11), 1] = 1 # females
# middle managers
sal_job[(n_cat*4+1):(n_cat*5), 2] = 1 # males
sal_job[(n_cat*11+1):(n_cat*12), 2] = 1 # females
# employee
sal_job[(n_cat*5+1):(n_cat*6), 3] = 1 # males
sal_job[(n_cat*12+1):(n_cat*13), 3] = 1 # females
# final data set
data_ANOVA = cbind.data.frame(response = sal_y, sex = sal_sex, age = sal_age, job = sal_job)
# names(data_ANOVA)
# show regressors' shape
imagemat(data_ANOVA[,-1], xaxt = "n", main = "Factors for ANOVA")
axis(1, at=1:6, labels=c("Sex", "Age 26-50", "Age 51+", "Execut.", "Mid.Man.", "Empl."))

# sub sample to avoid correlation, (unbalanced dataset)
# set.seed(20)
subs = sample(1:n_sal_y, size = round(n_sal_y*0.1))
data_ANOVA = data_ANOVA[subs,]
# show randomized data
imagemat(data_ANOVA[,-1], xaxt = "n", main = "Factors for ANOVA after sub-sampling")
axis(1, at=1:6, labels=c("Sex", "Age 26-50", "Age 51+", "Execut.", "Mid.Man.", "Empl."))

Run the ANOVA model, tranforming the response variable using Box-Cox transformation
# plot the transformed response variable (suggested by Box-Cox transformation)
sal_y = data_ANOVA[,1]^-1
ggplot(data=data.frame(data_ANOVA[,1]), aes(sal_y)) +
geom_histogram(aes(y =..density..), col="black", fill="blue", alpha = .3, bins = 60) +
geom_density(col="black") +
labs(x="salary^-1", y="Density") +
ggtitle("Transformation of salary found using Box-Cox transformation") +
theme(plot.title = element_text(hjust = 0.5))

# take the identified subsample for dummy variables
sex = sal_sex[subs]
age = sal_age[subs,]
job = sal_job[subs,]
# ANOVA model
sal_ANOVA = lm(sal_y ~ sex + age + job + sex:age + sex:job)
summary(sal_ANOVA)
Call:
lm(formula = sal_y ~ sex + age + job + sex:age + sex:job)
Residuals:
Min 1Q Median 3Q Max
-0.084391 -0.004587 0.000657 0.005446 0.050454
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.1057963 0.0002737 386.559 < 2e-16 ***
sex -0.0106870 0.0003870 -27.618 < 2e-16 ***
age1 -0.0212090 0.0004851 -43.723 < 2e-16 ***
age2 -0.0279090 0.0004717 -59.163 < 2e-16 ***
job1 -0.0555240 0.0004630 -119.912 < 2e-16 ***
job2 -0.0298464 0.0004690 -63.633 < 2e-16 ***
job3 -0.0081649 0.0004693 -17.397 < 2e-16 ***
sex:age1 -0.0023524 0.0006850 -3.434 0.000598 ***
sex:age2 -0.0083323 0.0006713 -12.412 < 2e-16 ***
sex:job1 0.0010803 0.0006723 1.607 0.108151
sex:job2 -0.0002828 0.0006755 -0.419 0.675486
sex:job3 0.0027415 0.0006671 4.109 4.01e-05 ***
---
Signif. codes: 0 *** 0.001 ** 0.01 * 0.05 . 0.1 1
Residual standard error: 0.008719 on 7019 degrees of freedom
Multiple R-squared: 0.8352, Adjusted R-squared: 0.8349
F-statistic: 3233 on 11 and 7019 DF, p-value: < 2.2e-16
Analysis of Variance Table
Response: sal_y
Df Sum Sq Mean Sq F value Pr(>F)
sex 1 0.20446 0.20446 2689.2922 < 2.2e-16 ***
age 2 0.16187 0.08093 1064.5298 < 2.2e-16 ***
job 3 2.31845 0.77282 10164.8476 < 2.2e-16 ***
sex:age 2 0.01775 0.00887 116.7281 < 2.2e-16 ***
sex:job 3 0.00160 0.00053 7.0028 0.0001064 ***
Residuals 7019 0.53364 0.00008
---
Signif. codes: 0 *** 0.001 ** 0.01 * 0.05 . 0.1 1
# aov(sal_y ~ sex + age + job + sex:age + sex:job)
plot(sal_ANOVA, 1)

# box-cox transformation suggested to use y^-1
boxcox(sal_ANOVA)
title("Box-Cox transformation of the response")

# comparison a full model with a reduced one excluding one interaction term
sal_ANOVA2 = lm(sal_y ~ sex + age + job + sex:age)
anova(sal_ANOVA, sal_ANOVA2)
Analysis of Variance Table
Model 1: sal_y ~ sex + age + job + sex:age + sex:job
Model 2: sal_y ~ sex + age + job + sex:age
Res.Df RSS Df Sum of Sq F Pr(>F)
1 7019 0.53364
2 7022 0.53524 -3 -0.0015972 7.0028 0.0001064 ***
---
Signif. codes: 0 *** 0.001 ** 0.01 * 0.05 . 0.1 1
To check if the model can be sparsified, considering groups of variables as a whole, the group-Lasso is applied. It shows that the interaction term sex:job is not so important.
# define the considered model, which includes interaction terms
form <- model.matrix(sal_y ~ (sex + age + job)^2)
# remove interaction age:job
# colnames(form)
form = form[,2:12]
# define groups' labels
grp = c(1,2,2,3,3,3,4,4,5,5,5)
#Group-Lasso with 10-folds Cross Validation and LAD cost function
fit.cv=cv.gglasso(x=form, y=sal_y, group=grp, nfolds=10, pred.loss = "L2")
# plot CV for Lambda
plot(fit.cv)
mtext(expression("10-folds CV for group-Lasso in ANOVA"), outer=TRUE, cex=1, line=-2.2)

# extract coefficients
# coef.mat = fit.cv$gglasso.fit$beta
# plot separately each coefficient
cols = brewer.pal(5,name="Set1")
plot(fit.cv$gglasso.fit, col = cols, lwd = 3, main = "Coefficients vs.Lambda values")
legend('bottomright', legend = paste("Group", 1:5), col=cols[1:5], cex = 0.65, pch = 1, lwd=4, bty ="n")

# plot coefficients' norms (not working), doing it manually
# https://www.rdocumentation.org/packages/gglasso/versions/1.3/topics/plot.gglasso
# https://code.google.com/archive/p/gglasso/issues
# plot(fit.cv$gglasso.fit, group=TRUE, col = cols, lwd = 2)
# legend('bottomright', legend = paste("Group", 1:5), col=cols[1:5], cex = 0.65, pch = 1, lwd=4, bty ="n")
# initialize norms
coeffNorm = matrix(0, nrow = max(fit.cv$gglasso.fit$group), length(fit.cv$gglasso.fit$lambda))
# compute norms group-wise
for (i in 1:max(fit.cv$gglasso.fit$group)){
ind = fit.cv$gglasso.fit$group == i
coeff = fit.cv$gglasso.fit$beta[ind,]
if (sum(ind)>1){
coeffNorm[i,] = apply(coeff, 2, function(x){sqrt(sum(x^2))})
} else coeffNorm[i,] = coeff
}
# coefficients' norm plot
plot(log(fit.cv$gglasso.fit$lambda), coeffNorm[1,], main="Coefficients' norm vs Lambda",
ylab="Coefficients' norm",xlab="Ln Lambda values",
col=cols[1],
# xlim=c(-1,100),
ylim=c(min(coeffNorm), max(coeffNorm)),
type="l",lwd=4)
for (j in 2:nrow(coeffNorm)){
lines(log(fit.cv$gglasso.fit$lambda), coeffNorm[j,], type="l",lwd=4, col=cols[j])
}
abline(0,0, lwd=3)
# plot legend once
# grid()
par(new=T)
legend('topright', legend = paste("group ", 1:5), lty=1, col=cols[1:5], cex = 0.6,lwd=2)

#Pick the best Lambda
lmbda=fit.cv$lambda.1se
(coefs=coef.gglasso(object=fit.cv$gglasso.fit,s=lmbda))
1
(Intercept) 0.103352890
sex -0.009843253
age1 -0.018198974
age2 -0.025734448
job1 -0.051617852
job2 -0.027165667
job3 -0.004583826
sex:age1 -0.002729062
sex:age2 -0.006619003
sex:job1 0.000000000
sex:job2 0.000000000
sex:job3 0.000000000
#At best lambda get coefficients and fitted values
plt=sal_y-predict.gglasso(object=fit.cv$gglasso.fit,newx=form,s=lmbda,type='link')
plot(plt, ylab="residuals", xlab="index", main="Plot of residuals")
abline(0, 0, col= "red")

From this study it is possible to conclude that each factor considered is relevant to determine the salary level.
The least important factor results the interaction between sex and job, which is not statistically significant using group-Lasso. This means that there is no gender discrimination between various jobs, even if gender discrimination exists in general and for different age groups.
In the next section this topic will be investigated further.
Difference in salary: men vs. females
The focus of this section is on the on the difference on salary between males and females in various towns. Some classical approaches will be compared with robust ones, to diagnose the possible negative effect of the presence of noise or outliers. It is motivated by the assumptions that not all the towns come from the same data genereting process.
# These functions are used to create the plots used in the next chunks
# PLOTS FOR interactive regression diagnostic plots
RegressionPlots <- function(fit, textlabels, robust=F, out = NULL){
# number of units
n = length(fit$fitted.values)
# original response
y = fit$y
# Extract fitted values from lm() object
Fitted.Values <- fit$fitted.values
# Extract residuals from lm() object
Residuals <- fit$residuals
if (robust == F){
# Extract standardized residuals from lm() object
Standardized.Residuals <- MASS::stdres(fit)
# Calculate Leverage
Leverage <- lm.influence(fit)$hat
# text for the labels of the plots
tt = "OLS"
} else{
# standardized residuals based on a robust scale estimate
Standardized.Residuals <- fit$residuals/fit$scale
# get the robust distances based on mahalanobis distance from the robust output
# (it has to be specified in the call to lmrob using: control = lmrob.control(compute.rd = T))
Leverage <- fit$MD
# text for the labels of the plots
tt = "Robust"
}
# Extract fitted values for lm() object
Theoretical.Quantiles <- qqnorm(Residuals, plot.it = F)$x
# Create data frame
# Will be used as input to plotly
regMat <- data.frame(Fitted.Values,
Residuals,
Standardized.Residuals,
Theoretical.Quantiles,
Leverage,
textlabels)
# Plot using Plotly
# text info
t <- list(
family = "sans serif",
size = 14,
color = toRGB("grey50"))
# Plot 1: Fitted vs Residuals
# For scatter plot smoother
LOESS <- loess.smooth(Fitted.Values, Residuals)
# plt1 <- regMat %>%
# plot_ly(x = Fitted.Values, y = Residuals,
# type = "scatter", mode = "markers", hoverinfo = "text",
# color = out, name = "Data", marker = list(size = 10, opacity = 0.5),
# text = paste('</br> Unit: ', 1:n,
# '</br> Town: ', as.character(textlabels),
# '</br> x: ', Fitted.Values,
# '</br> y: ', Residuals)) %>%
#
# add_trace(x = LOESS$x, y = LOESS$y, type = "scatter", mode = "lines", name = "Smooth",
# inherit = F, line = list(width = 2)) %>%
#
# layout(title = paste(tt, " Residuals vs Fitted Values"), plot_bgcolor = "#e6e6e6",
# xaxis = list(title = "Fitted Values"),
# yaxis = list(title = "Residuals"))
# Plot 2: Fitted vs Standardized Residuals
# For scatter plot smoother
LOESS <- loess.smooth(Fitted.Values, Standardized.Residuals)
plt2 <- regMat %>%
plot_ly(x = Fitted.Values, y = Standardized.Residuals,
type = "scatter", mode = "markers", hoverinfo = "text",
color = out, name = "Data", marker = list(size = 10, opacity = 0.5),
text = paste('</br> Unit: ', 1:n,
'</br> Town: ', as.character(textlabels),
'</br> x: ', Fitted.Values,
'</br> y: ', Standardized.Residuals)) %>%
add_trace(x = LOESS$x, y = LOESS$y, type = "scatter", mode = "lines", name = "Smooth",
inherit = F, line = list(width = 2)) %>%
layout(title = paste(tt, " Standardized residuals vs Fitted Values"), plot_bgcolor = "#e6e6e6",
xaxis = list(title = "Fitted Values"),
yaxis = list(title = "Standardized residuals"))
# Plot 3: Residuals index
plt3 <- regMat %>%
plot_ly(x = 1:n, y = Standardized.Residuals,
type = "scatter", mode = "markers", hoverinfo = "text",
color = out, name = "Data", marker = list(size = 10, opacity = 0.5),
text = paste('</br> Unit: ', 1:n,
'</br> Town: ', as.character(textlabels),
'</br> x: ', 1:n,
'</br> y: ', Standardized.Residuals)) %>%
add_segments(x = -5, xend = n+5, y = 0, yend = 0, mode = "line", inherit = F,
name = "Null line", line = list(width = 2)) %>%
layout(title = paste(tt, " Standardized Residuals' index"), plot_bgcolor = "#e6e6e6",
xaxis = list(title = "Index"),
yaxis = list(title = "Standardized.Residuals"))
# Plot 4: QQ Pot
plt4 <- regMat %>%
plot_ly(x = Theoretical.Quantiles, y = Standardized.Residuals,
type = "scatter", mode = "markers", hoverinfo = "text",
color = out, name = "Data", marker = list(size = 10, opacity = 0.5),
text = paste('</br> Unit: ', 1:n,
'</br> Town: ', as.character(textlabels),
'</br> x: ', Theoretical.Quantiles,
'</br> y: ', Standardized.Residuals)) %>%
add_trace(x = Theoretical.Quantiles, y = Theoretical.Quantiles, type = "scatter",
mode = "lines", name = "Theoretical", line = list(width = 2),
inherit = F) %>%
layout(title = paste(tt, " Q-Q Plot"), plot_bgcolor = "#e6e6e6",
xaxis = list(title = "Normal theoretical quantiles"),
yaxis = list(title = "Data quantiles"))
# Plot5: Residuals vs Leverage
# For scatter plot smoother
LOESS <- loess.smooth(Leverage, Residuals)
plt5 <- regMat %>%
plot_ly(x = Leverage, y = Residuals,
type = "scatter", mode = "markers", hoverinfo = "text",
color = out, name = "Data", marker = list(size = 10, opacity = 0.5),
text = paste('</br> Unit: ', 1:n,
'</br> Town: ', as.character(textlabels),
'</br> x: ', Leverage,
'</br> y: ', Residuals)) %>%
add_trace(x = LOESS$x, y = LOESS$y, type = "scatter", mode = "lines", name = "Smooth",
line = list(width = 2), inherit = F) %>%
layout(title = paste(tt, " Leverage vs Residuals"), plot_bgcolor = "#e6e6e6",
xaxis = list(title = "Leverage values"),
yaxis = list(title = "Residuals"))
# Plot 6: Fitted vs response
# For scatter plot smoother
LOESS <- loess.smooth(Fitted.Values, y)
plt6 <- regMat %>%
plot_ly(x = Fitted.Values, y =y,
type = "scatter", mode = "markers", hoverinfo = "text",
color = out, name = "Data", marker = list(size = 10, opacity = 0.5),
text = paste('</br> Unit: ', 1:n,
'</br> Town: ', as.character(textlabels),
'</br> x: ', Fitted.Values,
'</br> y: ', y)) %>%
add_trace(x = LOESS$x, y = LOESS$y, type = "scatter", mode = "lines", name = "Smooth",
inherit = F, line = list(width = 2)) %>%
layout(title = paste(tt, " Fitted Values vs response"), plot_bgcolor = "#e6e6e6",
xaxis = list(title = "Fitted Values"),
yaxis = list(title = "Response values"))
# # Plot 7: MISSING: sqrt(abs(Residuals))
# # For scatter plot smoother
# LOESS2 <- loess.smooth(Fitted.Values, Root.Residuals)
#
# plt3 <- regMat %>%
# plot_ly(x = Fitted.Values, y = Root.Residuals,
# type = "scatter", mode = "markers", hoverinfo = "text",
# name = "Data", marker = list(size = 10, opacity = 0.5),
# text = paste('town: ', as.character(textlabels))) %>%
#
# add_trace(x = LOESS2$x, y = LOESS2$y, type = "scatter", mode = "lines", name = "Smooth",
# line = list(width = 2), inherit = F) %>%
#
# layout(title = "Scale Location", plot_bgcolor = "#e6e6e6")
plt = list(plt2, plt3, plt4, plt5, plt6) # plt1,
return(plt)
# not working...to add in all plots
# to avoid error with colorPalette<3
# suppressWarnings(warning("RColorBrewer::brewer.pal"))
}
#
# PLOTS FOR BEST SUBSET REGRESSION
#
plot.regsubsets2 <-
function (x, labels = obj$xnames, main = NULL, scale = c("bic",
"Cp", "adjr2", "r2"), col = gray(seq(0, 0.9, length = 10)), ...)
{
obj <- x
lsum <- summary(obj)
par(mar = c(7, 5, 6, 3) + 0.1)
nmodels <- length(lsum$rsq)
np <- obj$np
propscale <- FALSE
sscale <- pmatch(scale[1], c("bic", "Cp", "adjr2", "r2"),
nomatch = 0)
if (sscale == 0)
stop(paste("Unrecognised scale=", scale))
if (propscale)
stop(paste("Proportional scaling only for probabilities"))
yscale <- switch(sscale, lsum$bic, lsum$cp, lsum$adjr2, lsum$rsq)
up <- switch(sscale, -1, -1, 1, 1)
index <- order(yscale * up)
colorscale <- switch(sscale, yscale, yscale, -log(pmax(yscale,
1e-04)), -log(pmax(yscale, 1e-04)))
image(z = t(ifelse(lsum$which[index, ], colorscale[index],
NA + max(colorscale) * 1.5)), xaxt = "n", yaxt = "n",
x = (1:np), y = 1:nmodels, xlab = "", ylab = scale[1],
col = col)
laspar <- par("las")
on.exit(par(las = laspar))
par(las = 2)
axis(1, at = 1:np, labels = labels, ...) # I modified this line
axis(2, at = 1:nmodels, labels = signif(yscale[index], 2), ...)
# axis(2,cex.axis=0.01)
if (!is.null(main))
title(main = main)
box()
invisible(NULL)
}
The considered model is built using all the variables that could explain the gap in salary. Some of them refers to the difference of some quantity between males and females for each town (e.g., diploma, univeristy, independent workers, etc.). The final model consist of 43 variables and 5025 units.
Additionally, some variables which would have had a huge positive impact on the prediction of the response variable have non been considered, because of their strong relation (e.g., gap in salary between males and females for various ages or occupations)
# response variable
# y = log10(newDat$sal_Males - newDat$sal_Females)
y = newDat$sal_Males - newDat$sal_Females
# original response variable histogram
ggplot(data=as.data.frame(y), aes(y)) +
geom_histogram(aes(y =..density..), col="black", fill="blue", alpha = .3, bins = 35) +
geom_density(col="black") +
labs(x="Male-Female salary", y="Density") +
ggtitle("Original response variable") +
theme(plot.title = element_text(hjust = 0.5))

x = cbind.data.frame(pop = newDat$total_population,
firms = newDat$total,
ratio_pop_firms = newDat$total/newDat$total_population,
# delta_exec = newDat$sal_M_executive - newDat$sal_F_executive,
# delta_midMan = newDat$sal_M_midManager - newDat$sal_F_midManager,
# delta_empl = newDat$sal_M_employee - newDat$sal_F_employee,
# delta_worker = newDat$sal_M_worker - newDat$sal_F_worker,
workforce = newDat$workforce,
dependency_ratio = newDat$dependency_ratio,
delta_wagearner = newDat$wagearner_M - newDat$wagearner_F,
delta_indep = newDat$independent_M - newDat$independent_F,
# delta_transfer = newDat$transfer_M - newDat$transfer_F, # 2000 zeros
delta_employer = newDat$employer_M - newDat$employer_F,
delta_full = newDat$full_M - newDat$full_F,
# delta_half = newDat$half_M - newDat$half_F, # OLS gives NA
superficie = newDat$Superficie,
housing14 = newDat$housing14,
median_living14 = newDat$median_living14,
empl = newDat$empl,
emp_sal = newDat$emp_sal,
pop15_64 = newDat$pop15_64,
unemp15_64 = newDat$unemp15_64,
act15_64 = newDat$act15_64,
unemp_rate = newDat$unemp_rate,
delta_NoDip = newDat$male_NoDip - newDat$female_NoDip,
delta_sec = newDat$male_Sec - newDat$female_Sec,
delta_hi = newDat$male_Hi - newDat$female_Hi,
delta_univ = newDat$male_Univ - newDat$female_Univ,
nodip = newDat$nodip,
delta_immig = newDat$male_immig - newDat$female_immig,
delta_workingImmig = newDat$male_working_immig - newDat$female_working_immig,
delta_native = newDat$male_native - newDat$female_native,
# evol_entrepr = newDat$evol_entrepreneurial_score,
# evol_pop = newDat$evol_pop_score,
regional_GDP = newDat$regional_GDP,
# dymanic_demo_prof = newDat$dymanic_demo_prof,
nb_active_employees = newDat$nb_active_employees,
nb_active_non_employees = newDat$nb_active_non_employees,
# nb_active = newDat$nb_active, # OLS gives NA
nb_created_services = newDat$nb_created_services,
nb_created_commerce = newDat$nb_created_commerce,
nb_created_construction = newDat$nb_created_construction,
nb_created_ind = newDat$nb_created_ind,
# nb_created_firms = newDat$nb_created_firms, # OLS gives
nb_firms_service = newDat$nb_firms_service,
nb_firms_commerce = newDat$nb_firms_commerce,
nb_firms_construction = newDat$nb_firms_construction,
nb_firms_ind = newDat$nb_firms_ind,
nb_major = newDat$nb_major,
nb_minor = newDat$nb_minor,
delta_num_sex = newDat$nb_male - newDat$nb_female,
nb_household = newDat$nb_household)
Error in data.frame(..., check.names = FALSE) :
arguments imply differing number of rows: 5022, 0
These plots shows that:
- the response is long tailed, which also motivates the robust framework
- there is strong evidence of collinearity
The final model is built considering a random sample of observations (70% of them) in order to reduce spatial correlation among units
In the following analyses to towns will be often highlighted and they have been found ex-post. They are considered as 2 typical outliers but for different reasons. One of them is Paris, which is an outlier for obvious reasons. The other (unexpected) one is Chambourcy, which has been spotted by the following analysis and it is a very small town.
All the coefficients’ estimates obtained in the following will be saved in a dataframe to allow an easy ex-post comparison. For fitting methods that provide significance levels, only variables significant at 0.01% will be kept.
Naive approaches
Ordinary least squares
A classical linear model based on OLS is first fitted
It shows that:
- there is etoreskadasticity
- Paris has a levarage equal to 1
Also, high collinearity and robustness are not taken into account. At the same time, running different times OLS didn’t produce any coefficients’ instability, even if VIF values are very high.
Best subset selection
Model selection by exhaustive search (suffering the same drawbacks as OLS) is now applied, which is also a very heavy approach in terms of computing time.
Stepwise selection
Model selection by sequential replacement (suffering the same drawbacks as OLS) is now applied and it is very fast compared to the exhaustive search
This approach results in a sparser model compared to the exhaustive search, and the cost (e.g., in terms of BIC) is higher.
MM estimator
The model is now fitted using the MM estimator, which is a soft trimming methodology. It is based on a starting robust estimator with a high breakdown point (in this case an S estimator), which provides a robust scale estimate used by the MM estimator to recover efficiency
This model shows that:
- residuals and fitted values seem better than the OLS fit
- it is able to identify the most oulying units (considering all the dimensions)
- leverage points (Lyon and Toulouse) have a lower weight compared to OLS estimates
Least trimmed squares
A very similar result is obtained using the LTS estimator (i.e., an hard trimming approach), with trimming proportion equal to 10% of the units.
Using the MM or LTS estimator, as expected, increases the adjusted R squared of around 10%.
Best subset selection with MM weights
The results obtained using a best subset selection procedure are now combined with the weights obtained using the MM estimator (pretty similar to the ones obtaiend using the LTS weights)
This approach results in a significant improvement of the cost function, but the best model is less sparse and it keeps approximately 20 variables.
Elastic net
To face the problem of strong collinearity, which has not been considere yet, an Elastic-net is now fitted using 10-folds cross validation to tune lambda and considering a range of 11 equispaced alpha values. The best model is considered the one with the lowest MSPE.
This estimator proides a fairly sparse model, but it is non robust, it is biased, and it doesn’t easy allow to perform inferential reasoning.
OLS on elastic net solution
To partially solve the latter two problems, an OLS fit could be applied only on the variables previously identified by ENET.
This results in a sparser model and the diagnostic plots shows a better result compared to the raw OLS estimates, but it is still not robust.
Elastic net with MM weights
At this point, it seems reasonable to use the weights obtained by the MM estimator in an ENET model, trying to recover some robustness and keeping a sparse model
Contrarily to what was expected, the model is not so sparse. On the other hand, the mean CV error decreases substiantially (around 0.4) compared to the pure ENET model (around 1.4), and this gain would persist even allowing for a stronger shrinkage of the lambda values and hence reducing the number of coefficients. It is also interesting to note the strong decrease in CV error as some proportion of Lasso is introduced.
Such behavior should be studied further. A motivation could be the fact that ENET is based on CV, and some oulying units with weights different from 0 can affect this result. On the other hand, even providing to ENET only units with MM-weights greater than 0.9 (i.e., almost surely non outlying according to MM based on all variables), mean CV error decrease substantially, but the problem persists.
OLS on Elastic net solution with MM weights
The same is true applying an OLS estimate on the non oulying units (i.e., with MM-weights > 0.05) and the variables identified bu ENET(MM).
Such a model is sparser. It still contains some leverage points, like Toulose and Lyon, but the diagnostic plots don’t show any particularly strange behavior.
At the same two important aspects have to be taken in account:
- the MM weights used were obtained on the base of the full model, hence they could not be really representative
- some units are not being modeled in this framework
Elastic net with MM weights to model outliers
To face the latter problem an approach could be based on the idea of modeling apart the most outlying units. For instance, the following fit is based on ENET where the provided weights correspond to 1 - MMweights.
This model results in:
- in a very sparse model which seems to fit reasonably well all the points
- provides coefficients which are sensibly different than the ones for the previously considered models (e.g., unemployment coefficients changes its sign) supporting the assumption that there is more than one data generating process
- the mean CV error increases substantially
A possible drawback of this approach, again, reside on the fact that the MM weights are based on the full model.
Robust approaches incorporating shrinkage
Sparse-LTS
The estimator sparse-LTS, which is a robustification of Lasso using LTS, is now applied. The parameters used perform a trimming 10% of the units, and 10 replication of 10-folds CV
This model results in:
- a very sparse and robust model
- the unemployment rate is the most important variable
- clearly shows 2 different sub-popilations
- Paris is not a clear outlier
The main drawback resides on the fact that it is not taking into account collinearity.
Elastic net with sparse-LTS weights
In order to try to solve this problem, ENET with weights provided by sparseLTS could be applied
In this case, instead of the actual minimum obtained by ENET which corresponded to a Lasso fit, the best labda kept corresponds to alpha=0.7 (at the cost of a slightly higher CV error). The highest coefficient for this model results the unemployment rate.
To perform a further validation of these results, OLS is applied on the model identified (discarding the units identified by sparse-LTS)
They show that:
- the model seems correctly specified and all regressors are significant
- Paris is not considered as on outlier (its leverage is strongly decreased)
- the unemployment rate has a strong effect on the response
Penalized ENET based on the S estimator
Penalized ENET based on the S estimator (PENSE) is now applied. The PENSE estimate minimizes the robust M-scale of the residuals penalized by the L1 and L2 norm of the regression coefficients (elastic net penalty). The level of penalization is chosen to minimize the k-fold cross-validated prediction error (using a robust measure).
This models show that:
The main drawback it’s the computing time required.
Elastic net with LTS cost function
Robust elastic net, based on LTS, is now fitted to the model trimming 10% of the units. It requires the removal of the dummy variable for urban towns, in order to avoid numerical problems.
This model shows that:
- the algorithm (even if not parallelized for Windows users) is much faster than PENSE
- …
Comparison of the estimates obtained
Print table of results
This function is used to plot a summary of the results obtained in HTML format
LS0tDQp0aXRsZTogIlRTTCBQcm9qZWN0Ig0KYXV0aG9yOiAiTHVjYSBJbnNvbGlhLCBKaXN1IEtpbSBhbmQgR2V2b3JnIFllZ2hpa3lhbiIgICAgDQpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclZC8lbS8lWScpYCINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogJzMnIA0KICAgIGhpZ2hsaWdodDogdGFuZ28NCiAgICBrZWVwX3RleDogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0aGVtZTogdW5pdGVkDQogICAgaGlnaGxpZ2h0OiB0YW5nbyAgICANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogJzMnIA0KIyAgIHBkZl9kb2N1bWVudDogIyBBREQgUERGIQ0KIyAgICAgdG9jOiB5ZXMNCiMgICAgIHRvY19kZXB0aDogJzMnDQojICAgICBrZWVwX3RleDogdHJ1ZQ0KIyAgICAgbGF0ZXhfZW5naW5lOiBwZGZsYXRleA0KIyBlZGl0b3Jfb3B0aW9uczoNCiMgICAjIHRvYzogeWVzDQojICAgIyB0b2NfZGVwdGg6IDMNCiMgICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lDQotLS0NCg0KDQojIEdlbmVyYWwgaW5mb3JtYXRpb24gDQoNCldlIGFuYWx5emUgYSBkYXRhc2V0IHB1Ymxpc2hlZCBvbiBbS2FnZ2xlXShodHRwczovL3d3dy5rYWdnbGUuY29tL2V0aWVubmVscS9mcmVuY2gtZW1wbG95bWVudC1ieS10b3duKS4NCkl0IHJlZmVycyB0byBmcmVuY2ggZW1wbG95bWVudCwgc2FsYXJpZXMsIHBvcHVsYXRpb24gcGVyIHRvd24uIA0KVGhlIGFpbSBpcyB0byBldmFsdWF0ZSBlcXVhbGl0eS9pbmVxdWFsaXRpZXMgaW4gRnJhbmNlLCBhbmQgZ2VvZ3JhcGhpY2FsIGRpc3RyaWJ1dGlvbiBvZiBidXNpbmVzcyBhY2NvcmRpbmcgdG8gdGhlaXIgc2l6ZS4NCg0KU3VjaCBkYXRhIGFyZSBjb2xsZWN0ZWQgYnkgdGhlIElOU0VFLg0KSW5mb3JtYXRpb24gcmVnYXJkaW5nIHRoZSBudW1iZXIgb2YgZmlybXMgaW4gZXZlcnkgZnJlbmNoIHRvd24sIGNhdGVnb3JpemVkIGJ5IHNpemUNCmNhbiBiZSBmb3VuZCBbaGVyZV0oaHR0cHM6Ly93d3cuaW5zZWUuZnIvZnIvbWV0YWRvbm5lZXMvZGVmaW5pdGlvbi9jMTEzNSkuIFRoaXMgZGF0YXNldCBjb250YWlucyBhYm91dCAzNTAwMCB1bml0cy9wZXIgdG93bi4NCg0KSW5mb3JtYXRpb24gYWJvdXQgc2FsYXJpZXMgYXJvdW5kIGZyZW5jaCB0b3duIHBlciBqb2IgY2F0ZWdvcmllcywgYWdlIGFuZCBzZXggKGV4cHJlc3NlZCBpbiBhdmVyYWdlIG5ldCBhbW91bnQgcGVyIGhvdXIgaW4gZXVybykgY2FuIGJlIGZvdW5kIFtoZXJlXShodHRwczovL3d3dy5pbnNlZS5mci9mci9zdGF0aXN0aXF1ZXMvMjUyMjUxNSkuIFRoaXMgZGF0YXNldCBjb250YWlucyBhYm91dCA1MDAwIHVuaXRzL3BlciB0b3duLiANCg0KRGVtb2dyYXBoaWMgaW5mb3JtYXRpb24gaW4gRnJhbmNlIHBlciB0b3duLCBhZ2UsIHNleCBhbmQgbGl2aW5nIG1vZGUNCmNhbiBiZSBmb3VuZCBbaGVyZV0oaHR0cHM6Ly93d3cuaW5zZWUuZnIvZnIvc3RhdGlzdGlxdWVzLzI4NjM2MDcpLiBUaGlzIGRhdGFzZXQgY29udGFpbnMgYWJvdXQgOCBtaWxsaW9uIHVuaXRzL3BlciB0b3duLiBBZGRpdGlvbmFsIGluZm8gYWJvdXQgUG9wdWxhdGlvbiBEYXRhIGNhbiBiZSBmb3VuZCBbaGVyZV0oaHR0cHM6Ly93d3cuaW5zZWUuZnIvZnIvc3RhdGlzdGlxdWVzLzI4NjM2MDcjZGljdGlvbm5haXJlKS4gDQoNClRoZXNlIGRhdGFzZXRzIGhhdmUgYmVlbiBwcmUtcHJvY2Vzc2VkIGFuZCBwdXQgdG9nZXRoZXIuIFRoZSBmaW5hbCBkYXRhc2V0IGNvbnRhaW5zIDU4IHZhcmlhYmxlcyBhbmQgNTAyMiBvYnNlcnZhdGlvbnMuIA0KDQoNCiMjIEFpbSBvZiB0aGUgc3R1ZHkgDQoNClRoaXMgcHJvamVjdCBhaW1zIHRvIGV4cGxvcmUgc3RydWN0dXJlIG9mIEZyZW5jaCBsYWJvdXIgbWFya2V0LiANCkluIHBhcnRpY3VsYXIsIHdlIGFyZSBpbnRlcmVzdGVkIGluOg0KDQoqIGV2YWx1YXRpbmcgcG9zc2libGUgaW5lcXVhbGl0aWVzOiBwZXIgdG93bnMvcmVnaW9uLCBzZXgsIGFnZSwgam9iIGNhdGVnb3JpZXMgZXRjLjsNCiogZGlzY292ZXIgZ2VvZ3JhcGhpY2FsIGRpc3RyaWJ1dGlvbiBvZiBidXNpbmVzcyBhY2NvcmRpbmcgdG8gdGhlaXIgc2l6ZQ0KKiBwcmVkaWN0aW5nIHRoZSAuLi4gdXNpbmcgYSByZWdyZXNzaW9uIG1vZGVsOw0KKiByZWR1Y2UgdGhlIGRpbWVuc2lvbmFsaXR5IG9mIC4uLiBwZXJmb3JtaW5nIGEgUENBOw0KKiBleHBsb3JlIGRpZmZlcmVudCBhbGdvcml0aG1zIHRvIGNsdXN0ZXIgbWFsZS9mZW1hbGVzIHVzaW5nIC4uLg0KDQoNCiMjIFBsYW4gZm9yIHRoZSBzdHVkeSANCg0KMS4gVW5zdXBlcnZpc2VkIGxlYXJuaW5nOiANCiogUENBDQoqIENsdXN0ZXJpbmcgbWV0aG9kcyAoSy1tZWFucy9IaWVyYXJjaGljYWwpDQoyLiBTdXBlcnZpc2VkIGxlYXJuaW5nOg0KKiBHTE0NCiogTGluZWFyL1F1YWRyYXRpYyBEaXNjcmltaW5hbnQgQW5hbHlzaXMNCiogS05ODQoqIENyb3NzLXZhbGlkYXRpb24NCiogQm9vdHN0cmFwDQoqIFN1YnNldCBzZWxlY3Rpb24gDQoqIFNocmlua2FnZSBtZXRob2RzDQoqIERpbWVuc2lvbiByZWR1Y3Rpb24gbWV0aG9kcw0KMy4gRGVzY3JpcHRpb24gb2YgcG9wdWxhdGlvbiBkZW1vZ3JhcGhpY3MgaW4gRnJhbmNlDQo0LiBTdHJ1Y3R1cmUgb2YgdGhlIGZyZW5jaCBsYWJvdXIgbWFya2V0DQo1LiAuLi4NCjYuIEZ1dHVyZSB3b3Jrcw0KDQoNCiMjIExvYWRpbmcgdG9vbHMNCg0KTG9hZGluZyBhbGwgbGlicmFyaWVzIG5lZWRlZCB0aHJvdWdob3V0IHRoZSBub3RlYm9vaw0KYGBge3IgbG9hZGluZyBsaWJyYXJpZXMsIGluY2x1ZGU9RkFMU0UsIGNhY2hlPUZBTFNFfQ0KDQojIGRhdGEgbWFuaXB1bGF0aW9uDQppZighcmVxdWlyZShwc3ljaCkpe2luc3RhbGwucGFja2FnZXMoInBzeWNoIik7IGxpYnJhcnkocHN5Y2gpfSANCmlmKCFyZXF1aXJlKHBseXIpKXtpbnN0YWxsLnBhY2thZ2VzKCJkcGx5ciIpOyBsaWJyYXJ5KHBseXIpfQ0KaWYoIXJlcXVpcmUoZHBseXIpKXtpbnN0YWxsLnBhY2thZ2VzKCJkcGx5ciIpOyBsaWJyYXJ5KGRwbHlyKX0NCiMgcGxvdHRpbmcNCmlmKCFyZXF1aXJlKFJDb2xvckJyZXdlcikpe2luc3RhbGwucGFja2FnZXMoIlJDb2xvckJyZXdlciIpOyBsaWJyYXJ5KFJDb2xvckJyZXdlcil9ICMgY29sb3JzDQppZighcmVxdWlyZSh6b28pKXtpbnN0YWxsLnBhY2thZ2VzKCJ6b28iKTsgbGlicmFyeSh6b28pfSAjIGNvbG9ycw0KaWYoIXJlcXVpcmUoZ2dwbG90Mikpe2luc3RhbGwucGFja2FnZXMoImdncGxvdDIiKTsgbGlicmFyeShnZ3Bsb3QyKX0NCmlmKCFyZXF1aXJlKGdnZm9ydGlmeSkpe2luc3RhbGwucGFja2FnZXMoImdnZm9ydGlmeSIpOyBsaWJyYXJ5KGdnZm9ydGlmeSl9DQppZighcmVxdWlyZShnZ21hcCkpe2luc3RhbGwucGFja2FnZXMoImdnbWFwIik7IGxpYnJhcnkoZ2dtYXApfQ0KaWYoIXJlcXVpcmUoZ2diaXBsb3QpKXsNCiAgaWYoIXJlcXVpcmUoZGV2dG9vbHMpKXsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJkZXZ0b29scyIpfQ0KICBpbnN0YWxsX2dpdGh1YigidnF2L2dnYmlwbG90IikNCiAgbGlicmFyeShnZ2JpcGxvdCl9DQppZighcmVxdWlyZShjb3JycGxvdCkpe2luc3RhbGwucGFja2FnZXMoImNvcnJwbG90Iik7IGxpYnJhcnkoY29ycnBsb3QpfQ0KaWYoIXJlcXVpcmUoem9vKSl7aW5zdGFsbC5wYWNrYWdlcygiem9vIik7IGxpYnJhcnkoem9vKX0NCmlmKCFyZXF1aXJlKHBsb3RseSkpe2luc3RhbGwucGFja2FnZXMoInBsb3RseSIpOyBsaWJyYXJ5KHBsb3RseSl9ICMgaW50ZXJhY3RpdmUgcGxvdHRpbmcNCmlmKCFyZXF1aXJlKGxhdHRpY2UpKXtpbnN0YWxsLnBhY2thZ2VzKCJsYXR0aWNlIik7IGxpYnJhcnkobGF0dGljZSl9DQppZighcmVxdWlyZShNVkEpKXtpbnN0YWxsLnBhY2thZ2VzKCJNVkEiKTsgbGlicmFyeShNVkEpfQ0KaWYoIXJlcXVpcmUoYXBlKSl7aW5zdGFsbC5wYWNrYWdlcygiYXBlIik7IGxpYnJhcnkoYXBlKX0NCmlmKCFyZXF1aXJlKEtlcm5TbW9vdGgpKXtpbnN0YWxsLnBhY2thZ2VzKCJLZXJuU21vb3RoIik7IGxpYnJhcnkoS2VyblNtb290aCl9DQppZighcmVxdWlyZShyZ2wpKXtpbnN0YWxsLnBhY2thZ2VzKCJyZ2wiKTsgbGlicmFyeShyZ2wpfQ0KaWYoIXJlcXVpcmUoY2FyKSl7aW5zdGFsbC5wYWNrYWdlcygiY2FyIik7IGxpYnJhcnkoY2FyKX0NCiMgQ2x1c3RlcmluZw0KaWYoIXJlcXVpcmUobWNsdXN0KSl7aW5zdGFsbC5wYWNrYWdlcygibWNsdXN0Iik7IGxpYnJhcnkobWNsdXN0KX0NCmlmKCFyZXF1aXJlKGRic2Nhbikpe2luc3RhbGwucGFja2FnZXMoImRic2NhbiIpOyBsaWJyYXJ5KGRic2Nhbil9DQojIHBsb3QgZGVzaWduIG1hdHJpeA0KaWYoIXJlcXVpcmUocmFmYWxpYikpe2luc3RhbGwucGFja2FnZXMoInJhZmFsaWIiKTsgbGlicmFyeShyYWZhbGliKX0NCiMgY3Jvc3MgdmFsaWRhdGlvbg0KaWYoIXJlcXVpcmUoYm9vdCkpe2luc3RhbGwucGFja2FnZXMoImJvb3QiKTsgbGlicmFyeShib290KX0NCiMgZWxhc3RpYyBuZXQNCmlmKCFyZXF1aXJlKGdsbW5ldCkpe2luc3RhbGwucGFja2FnZXMoImdsbW5ldCIpOyBsaWJyYXJ5KGdsbW5ldCl9DQojIGdyb3VwIExhc3NvDQppZighcmVxdWlyZShnZ2xhc3NvKSl7aW5zdGFsbC5wYWNrYWdlcygiZ2dsYXNzbyIpOyBsaWJyYXJ5KGdnbGFzc28pfQ0KIyByb2J1c3QgZml0DQppZighcmVxdWlyZShyb2J1c3RiYXNlKSl7aW5zdGFsbC5wYWNrYWdlcygicm9idXN0YmFzZSIpOyBsaWJyYXJ5KHJvYnVzdGJhc2UpfQ0KIyByb2J1c3QgTGFzc28gDQppZighcmVxdWlyZShyb2J1c3RIRCkpe2luc3RhbGwucGFja2FnZXMoInJvYnVzdEhEIik7IGxpYnJhcnkocm9idXN0SEQpfQ0KaWYoIXJlcXVpcmUoZW5ldExUUykpe2luc3RhbGwucGFja2FnZXMoImVuZXRMVFMiKTsgbGlicmFyeShlbmV0TFRTKX0NCiMgYm94LWNveCB0cmFuZm9ybWF0aW9uIChpbiBBTk9WQSkgYW5kIHN0YW5kYXJkaXplZCByZXNpZHVhbHMNCmlmKCFyZXF1aXJlKE1BU1MpKXtpbnN0YWxsLnBhY2thZ2VzKCJNQVNTIik7IGxpYnJhcnkoTUFTUyl9DQojIGJlc3Qgc3Vic2V0IHNlbGVjdGlvbg0KaWYoIXJlcXVpcmUobGVhcHMpKXtpbnN0YWxsLnBhY2thZ2VzKCJsZWFwcyIpOyBsaWJyYXJ5KGxlYXBzKX0NCiMgcGxvdCBmb3IgUENBDQojIGlmKCFyZXF1aXJlKGZhY3RvZXh0cmEpKXtpbnN0YWxsLnBhY2thZ2VzKCJmYWN0b2V4dHJhIik7IGxpYnJhcnkoZmFjdG9leHRyYSl9DQoNCmBgYA0KDQpJbXBvcnQgdGhlIGRhdGFzZXRzDQpgYGB7ciBsb2FkaW5nIGRhdGFzZXRzLCB3YXJuaW5nPUZBTFNFfQ0KDQpzZXR3ZCgiLi9kYXRhIikNCmZpcm1zICAgICAgIDwtIHJlYWQuY3N2KCJiYXNlX2V0YWJsaXNzZW1lbnRfcGFyX3RyYW5jaGVfZWZmZWN0aWYuY3N2IiwgZW5jb2RpbmcgPSAiVVRGLTgiKQ0KZ2VvICAgICAgICAgPC0gcmVhZC5jc3YoIm5hbWVfZ2VvZ3JhcGhpY19pbmZvcm1hdGlvbi5jc3YiLCBlbmNvZGluZyA9ICJVVEYtOCIpDQpzYWxhcnkgICAgICA8LSByZWFkLmNzdigibmV0X3NhbGFyeV9wZXJfdG93bl9jYXRlZ29yaWVzLmNzdiIsIGVuY29kaW5nID0gIlVURi04IikNCnBvcHVsYXRpb24gIDwtIHJlYWQuY3N2KCJwb3B1bGF0aW9uLmNzdiIsIGVuY29kaW5nID0gIlVURi04IikNCmVkdWMgICAgICAgIDwtIHJlYWQuY3N2KCJsZXZlbF9lZHVjYXRpb24uY3N2Iiwgc2VwID0iOyIsIGVuY29kaW5nID0gIlVURi04IikNCmNhdGVnX3NvY2lvIDwtIHJlYWQuY3N2KCJDYXRlZ29yaWVfc29jaW9wcm9mZXNzaW9ubmVsbGUuY3N2Iiwgc2VwID0iOyIsIGVuY29kaW5nID0gIlVURi04IikNCnN0YXR1c193b3JrIDwtIHJlYWQuY3N2KCJFbXBsb2lzX2xpZXVfdHJhdmFpbC5jc3YiLCBzZXAgPSI7IiwgZW5jb2RpbmcgPSAiVVRGLTgiKQ0KaW5lcSAgICAgICAgPC0gcmVhZC5jc3YoIkNvbXBhcmF0ZXVyX3RlcnJpdG9pcmVzLmNzdiIsIHNlcCA9IjsiLCBlbmNvZGluZyA9ICJVVEYtOCIpDQpjb21tdW5lICAgICA8LSByZWFkLmNzdigiaW5zZWVfY29tbXVuZS5jc3YiLCBlbmNvZGluZyA9ICJVVEYtOCIpDQoNCmBgYA0KDQoNCiMgUHJlLXByb2Nlc3NpbmcNCg0KIyMgRmlybXMgZGF0YQ0KIA0KQXNzaWduIG1lYW5pbmdmdWwgbmFtZXMgYW5kIGNoZWNrIHRoZSBtb2RpZmllZCBkYXRhOg0KYGBge3IgcHJlIHByb2Nlc3NpbmcgZmlybXN9DQoNCm5hbWVzKGZpcm1zKSANCm5hbWVzKGZpcm1zKVsyOm5jb2woZmlybXMpXSA8LQ0KICBjKCJ0b3duIiwgDQogICAgInJlZ051bSIsDQogICAgImRlcHROdW0iLA0KICAgICJ0b3RhbCIsDQogICAgIm51bGwiLA0KICAgICJmaXJtc0VtcGxfMV81IiwNCiAgICAiZmlybXNFbXBsXzZfOSIsDQogICAgImZpcm1zRW1wbF8xMF8xOSIsDQogICAgImZpcm1zRW1wbF8yMF80OSIsDQogICAgImZpcm1zRW1wbF81MF85OSIsDQogICAgImZpcm1zRW1wbF8xMDBfMTk5IiwNCiAgICAiZmlybXNFbXBsXzIwMF80OTkiLA0KICAgICJmaXJtc0VtcGxfNTAwcGx1cyIpDQoNCiMgcHJlbGltaW5hcnkgY2hlY2tzDQpuYW1lcyhmaXJtcykNCmhlYWQoZmlybXMpDQpzdHIoZmlybXMpDQpzdW1tYXJ5KGZpcm1zKQ0KDQojIENoZWNrIGZvciBkdXBsaWNhdGVkIGRhdGE6IHRoZXJlIGlzIG5vDQpzdW0oZHVwbGljYXRlZC5kYXRhLmZyYW1lKGZpcm1zKSkNCg0KYGBgDQoNCkNhdGVnb3JpemUgZmlybXMnIHNpemUgYWNjb3JkaW5nIHRvIA0KW0VVIHN0YW5kYXJkXShodHRwOi8vZWMuZXVyb3BhLmV1L2V1cm9zdGF0L3N0YXRpc3RpY3MtZXhwbGFpbmVkL2luZGV4LnBocC9HbG9zc2FyeTpFbnRlcnByaXNlX3NpemUpLCANCmJ1dCBpbiBhIHNsaWdodGx5IGRpZmZlcmVudCBmb3JtIGZvciBtZWRpdW0gYW5kIGxhcmdlIGZpcm1zIA0KKGkuZS4sIG1lZGl1bSBmaXJtcyBoYXZlIDwyMDAgaW5zdGVhZCBvZiA8MjUwIGVtcGxveWVlcyk6DQpgYGB7ciBtb2RpZnkgZmlybXN9DQoNCiMgbWVyZ2UgdmFyaWFibGVzDQpmaXJtcyRtaWNybyAgIDwtIGZpcm1zJGZpcm1zRW1wbF8xXzUgKyBmaXJtcyRmaXJtc0VtcGxfNl85DQpmaXJtcyRzbWFsbCAgIDwtIGZpcm1zJGZpcm1zRW1wbF8xMF8xOSArIGZpcm1zJGZpcm1zRW1wbF8yMF80OQ0KZmlybXMkbWVkaXVtICA8LSBmaXJtcyRmaXJtc0VtcGxfNTBfOTkgKyBmaXJtcyRmaXJtc0VtcGxfMTAwXzE5OQ0KZmlybXMkbGFyZ2UgICA8LSBmaXJtcyRmaXJtc0VtcGxfMjAwXzQ5OSArIGZpcm1zJGZpcm1zRW1wbF81MDBwbHVzDQoNCiMgRHJvcCB1bm5lY2Vzc2FyeSAoYXQgdGhlIG1vbWVudCkgY29sdW1ucyANCmZpcm1zIDwtIHN1YnNldChmaXJtcywgc2VsZWN0ID0gYyhDT0RHRU8sIHRvd24sIHRvdGFsLCBtaWNybywgc21hbGwsIG1lZGl1bSwgbGFyZ2UsIG51bGwpKQ0KDQojIGNoZWNrDQpzdW1tYXJ5KGZpcm1zKQ0KDQojIHRoZXJlIGlzIGFuIG9icyB3aXRoIG1vcmUgdGhhbiAzMTZLIG51bGwgZGF0YTogd2UgY2hlY2sgaWYgaXQgaXMgcGxhdXNpYmxlDQojIGdldCB0aGUgaGlnaGVzdCAyMCBudWxsIHZhbHVlcw0Kc3RyX2Zpcm1zIDwtIHNvcnQoZmlybXMkbnVsbCwgZGVjcmVhc2luZyA9IFQpWzE6MjBdDQojIGdldCB0aGVpciBpbmRleGVzDQpzdHJfZmlybXNfaW5kIDwtIG1hdGNoKHN0cl9maXJtcywgZmlybXMkbnVsbCkNCiMgZ2V0IHRoZSBjb3JyZXNwb25kaW5nIGNpdHkNCmZpcm1zJHRvd25bc3RyX2Zpcm1zX2luZF0NCiMgdGhleSBhcmUgdGhlIGxhcmdlc3QgY2l0aWVzLCBoZW5jZSBpdCBzZWVtcyByZWFzb25hYmxlLi4NCg0KYGBgDQoNCiMjIEdlb2dyYXBoaWNhbCBkYXRhIA0KDQpBc3NpZ24gbmFtZXMgYW5kIHJlbW92ZSBzb21lIHZhcmlhYmxlczoNCmBgYHtyIHByZSBwcm9jZXNzaW5nIGdlb30NCg0KbmFtZXMoZ2VvKQ0KbmFtZXMoZ2VvKVtjKDI6MTEsIDE0KV0gPQ0KICBjKCJjb2RlX3JlZ2lvbiIsDQogICAgInJlZ2lvbiIsIA0KICAgICJyZWdpb25fY2FwaXRhbCIsDQogICAgIm51bWJlcl9kZXBhcnQiLA0KICAgICJkZXBhcnRtZW50IiwgDQogICAgInByZWZlY3R1cmUiLA0KICAgICJjaXJjb25zIiwNCiAgICAidG93bl9uYW1lIiwgDQogICAgInBvc3RhbF9jb2RlIiwgDQogICAgIkNPREdFTyIsDQogICAgImVsb2lnbmVtZW50IikNCg0KIyBkcm9wIHVubmVjZXNzYXJ5IGNvbHVtbnMgKGNvZGUvbnVtIGFuZCBuYW1lIHJlcHJlc2VudHMgc2FtZSB0aGluZykgDQpnZW8gPC0gc3Vic2V0KGdlbywgc2VsZWN0ID0gLWMoRVVfY2lyY28sIGNvZGVfcmVnaW9uLCBudW1iZXJfZGVwYXJ0LCBwcmVmZWN0dXJlLCBjaXJjb25zLCBlbG9pZ25lbWVudCwgdG93bl9uYW1lKSkNCg0KIyBwcmVsaW1pbmFyeSBjaGVja3MNCm5hbWVzKGdlbykNCmhlYWQoZ2VvKQ0Kc3RyKGdlbykNCnN1bW1hcnkoZ2VvKQ0KDQpgYGANCg0KQ29ycmVjdCB0eXBvcyBmb3IgbG9uZ2l0dWRlIGRhdGEgYW5kIGtlZXAganVzdCB0aGUgdW5pcXVlIENPREdFTyB0byBhdm9pZCB0b3ducyB3aXRoIG11bHRpcGxlIHBvc3RhbCBjb2RlczoNCmBgYHtyIGZpeCBnZW99DQoNCiMgc3BvdCAiLCIgaW5zdGVhZCBvZiAiLiIgaW4gbG9uZ2l0dWRlDQpuZXdMb25nICAgICAgIDwtIGFzLmNoYXJhY3RlcihnZW8kbG9uZ2l0dWRlKSAgICAjIGNvcHkgdGhlIHZlY3Rvcg0Kc3VtKGdyZXAoIiwiLCBuZXdMb25nKSkgICAgICAgICAgICAgICAgICAgICAgICAgIyB0b3RhbCBjb21tYXMNCmluZF9sb25nX2VyciAgPC0gZ3JlcCgiLCIsIG5ld0xvbmcpICAgICAgICAgICAgICMgaW5kZXhpbmcgdGhlbQ0KbmV3TG9uZyAgICAgICA8LSBnc3ViKCIsIiwgIi4iLCBuZXdMb25nKSAgICAgICAgIyBzdWJzdGl0dXRpbmcgdGhlbSB3aXRoIGRvdHMNCmluZE5BX0xvbmcgICAgPC0gaXMubmEoYXMubnVtZXJpYygobmV3TG9uZykpKSAgICMgc3BvdCBOQQ0KIyBnZW8kbG9uZ2l0dWRlW2luZE5BX0xvbmddICAgICAgICAgICAgICAgICAgICAgICAjIHZlcmlmeSB0aGF0IHRoZXkgd2VyZSBhY3R1YWxseSBtaXNzaW5nDQpnZW8kbG9uZ2l0dWRlIDwtIGFzLm51bWVyaWMobmV3TG9uZykgICAgICAgICAgICAjIG92ZXJ3cml0ZSB0aGUgbG9uZ2l0dWRlIHZhcmlhYmxlIHdpdGggdGhlIG5ldyBvbmUNCg0KIyBDaGVjayBmb3IgZHVwbGljYXRlZCBkYXRhIChlLmcuLCBjaXRpZXMgd2l0aCBkaWZmZXJlbnQgcG9zdGFsIGNvZGVzLCB0aGF0IHdlIGRyb3BwZWQpOg0KICAjIGUuZy4sIHRvIHZlcmlmeSBpdCwgIHRyeSBvbiB0aGUgaW5pdGlhbCBkYXRhc2V0Og0KICAjIHN1bShnZW8kbm9tX2NvbW11bmUgPT0gIlBhcmlzIikNCiAgIyBpbmRfZHVwbGljIDwtIGdlbyRub21fY29tbXVuZSA9PSAiUGFyaXMiDQogICMgZ2VvW2luZF9kdXBsaWMsXQ0Kc3VtKGR1cGxpY2F0ZWQuZGF0YS5mcmFtZShnZW8pKSANCiMgcmV0YWluZyB1bmlxdWUgcG9zdGFsIGNpdGllcw0KZ2VvIDwtIGdlb1shZHVwbGljYXRlZChnZW8kQ09ER0VPKSxdDQoNCiMgY2hlY2sgYWdhaW4NCnN1bW1hcnkoZ2VvKQ0KDQpgYGANCg0KQXNzaWduIGxhdGl0dWRlIGFuZCBsb25naXR1ZGUgdmFsdWVzIGZvciBtaXNzaW5nIGRhdGEgKGFsbW9zdCAzMDAwKS4NClRoZSBjb2RlIHVzZWQgdG8gcmV0cmlldmUgdGhlbSB1c2luZyBHb29nbGUgQVBJIGhhcyBiZWVuIGNvbW1lbnRlZCBhbmQgaXRzIHJlc3VsdCBpcyBsb2FkZWQuDQpgYGB7ciBhc3NpZ24gTkEgaW4gZ2VvLCB3YXJuaW5nPUZBTFNFfQ0KDQojIGluZGV4IG9mIE5BcyBhbmQgdGhlaXIgdG90YWwNCmluZE5BX2Nvb3JkID0gaXMubmEoZ2VvJGxhdGl0dWRlKSB8IGlzLm5hKGdlbyRsb25naXR1ZGUpDQpzdW0oaW5kTkFfY29vcmQpDQoNCiMgY29kZSB1c2VkIHRvIHJldHJpZXZlIHRoZSBOQSB1c2luZyBHb29nbGUgQVBJLCB3aGljaCBoYXZlIGJlZW4gc2F2ZWQgaW4gYSBjc3YgZmlsZQ0KIyANCiMgIyBpbml0aWFsaXplIHZhcmlhYmxlcw0KIyBjaXR5X3NlYXJjaCA9IDANCiMgcmVzID0gYXMuZGF0YS5mcmFtZShtYXRyaXgoYygwLCAwLCAwKSwgMSwgMykpDQojIG5hbWVzKHJlcykgPSBjKCJsb24iLCAibGF0IiwgImFkZHJlc3MiKQ0KIyANCiMgIyByZXRyaWV2ZSBsYXQgYW5kIGxvbmcgKEdvb2dsZSBBUEkgPSAyNTAwIHJlcXVlc3QgcGVyIGRheSkNCiMgIyBteV9pdGVyID0gZmxvb3Ioc3VtKGluZE5BX2Nvb3JkKS8zKQ0KIyBmb3IgKGkgaW4gMTpzdW0oaW5kTkFfY29vcmQpKXsNCiMgDQojICAgIyBjaXR5IHNlYXJjaGVkDQojICAgY2l0eV9zZWFyY2hbaV0gPSBwYXN0ZShjKGFzLmNoYXJhY3RlcihOQV9jb29yZCR0b3duX25hbWVbaV0pLCBhcy5jaGFyYWN0ZXIoTkFfY29vcmQkcG9zdGFsX2NvZGVbaV0pLCBhcy5jaGFyYWN0ZXIoTkFfY29vcmQkZGVwYXJ0bWVudFtpXSksICJGcmFuY2UiKSwgc2VwPSIgIiwgY29sbGFwc2UgPSAiLCAiKQ0KIyAgIA0KIyAgICMgc29sdXRpb24NCiMgICByZXNbaSxdID0gZ2VvY29kZShjaXR5X3NlYXJjaFtpXSwgb3V0cHV0ID0gImxhdGxvbmEiLCBzb3VyY2UgPSBjKCJnb29nbGUiLCAiZHNrIiksIG1lc3NhZ2luZyA9IEZBTFNFKQ0KIyANCiMgICAjIHJldHJpZXZlIHN0aWxsIG1pc3NpbmcgZGF0YSwgYmVjYXVzZSBvZiBleGlzdGluZyBwcm9ibGVtcyB3aXRoIEFQSSAodXAgdG8gMTUgdHJpYWxzKQ0KIyAgIGogPSAwDQojICAgd2hpbGUgKGFueShpcy5uYShyZXNbaSxdKSkgJiBqIDwgMjUpew0KIyAgICAgcmVzW2ksXSA9IGdlb2NvZGUoY2l0eV9zZWFyY2hbaV0sIG91dHB1dCA9ICJsYXRsb25hIiwgc291cmNlID0gYygiZ29vZ2xlIiwgImRzayIpLCBtZXNzYWdpbmcgPSBGQUxTRSkNCiMgICAgIGogPSBqICsgMQ0KIyAgIH0NCiMgfQ0KDQojICMgY2hlY2sgdGhlIHNvbHV0aW9uDQojIHNvbCA9IGNiaW5kKHNlYXJjaGVkID0gY2l0eV9zZWFyY2gsIHJlcykNCg0KIyAjIHNhdmUgaXQgYXMgYSBjc3YgZmlsZSB0byBzYXZlIHRpbWUNCiMgd3JpdGUuY3N2KHJldHJpZXZlZF9nZW9fTkFbLDI6M10sICJnZW9fTkFfRmluYWwuY3N2IiwgcXVvdGUgPSBGQUxTRSwgcm93Lm5hbWVzPUZBTFNFLCBmaWxlRW5jb2RpbmcgPSAiVVRGLTgiKQ0KICAgIA0KDQojIHJlYWQgdGhlIGNyZWF0ZWQgY3N2DQpzZXR3ZCgiLi9kYXRhIikNCnJldHJpZXZlZF9nZW9fTkEgPSByZWFkLmNzdigiZ2VvX05BX0ZpbmFsLmNzdiIsIGhlYWRlciA9IFQsIGVuY29kaW5nID0gIlVURi04IikNCiMgZ2V0IG9ubHkgbG9uZyBhbmQgbGF0IGFuZCBhc3NpZ24gdG8gb3JpZ2luYWwgTkEgDQpnZW8kbGF0aXR1ZGVbaW5kTkFfY29vcmRdID0gcmV0cmlldmVkX2dlb19OQVssMl0NCmdlbyRsb25naXR1ZGVbaW5kTkFfY29vcmRdID0gcmV0cmlldmVkX2dlb19OQVssMV0NCg0KIyB0aGVyZSBhcmUgMzcgc3RpbGwgbWlzc2luZyB1bml0cywgd2hpY2ggYXJlIHRvd25zIGxvY2F0ZWQgaW4gb2xkIGNvbG9uaWVzIGZhciBmcm9tIEV1cm9wZQ0KaW5kTkFfY29vcmQgPSBpcy5uYShnZW8kbGF0aXR1ZGUpIHwgaXMubmEoZ2VvJGxvbmdpdHVkZSkNCnN1bShpbmROQV9jb29yZCkNCiMgZXhjbHVkZSB0aG9zZSB0b3ducw0KZ2VvID0gZ2VvWyFpbmROQV9jb29yZCxdDQoNCnN1bW1hcnkoZ2VvKQ0KDQpgYGANCg0KUmVtb3ZlIERPTS1UT00gdG93bnMgKGkuZS4gb2xkIGNvbG9uaWVzIGZhciBmcm9tIEV1cm9wZSkNCmBgYHtyfQ0KDQojIGRlbGV0ZSBub24tRXVyb3BlYW4gY291bnRyaWVzDQppbmRfbm9uRXVyID0gZ2VvJGxhdGl0dWRlIDwgMzAgfCBnZW8kbGF0aXR1ZGUgPiA3MCB8Z2VvJGxvbmdpdHVkZSA8IC0yMCB8IGdlbyRsb25naXR1ZGUgPiAyMA0Kc3VtKGluZF9ub25FdXIpDQpnZW8gPSBnZW9bIWluZF9ub25FdXIsXQ0KDQpgYGANCg0KDQojIyBTYWxhcnkgZGF0YSANCg0KQXNzaWduIG1lYW5pbmdmdWwgbmFtZXMgYW5kIGNoZWNrIHRoZSBkYXRhOg0KYGBge3IgcHJlIHByb2Nlc3Npbmcgc2FsYXJ5fQ0KDQpuYW1lcyhzYWxhcnkpDQpuYW1lcyhzYWxhcnkpWzI6bmNvbChzYWxhcnkpXSA8LQ0KICBjKCJ0b3duIiwNCiAgICAic2FsX2dlbmVyYWwiLCAgICANCiAgICAic2FsX2V4ZWN1dGl2ZSIsDQogICAgInNhbF9taWRNYW5hZ2VyIiwNCiAgICAic2FsX2VtcGxveWVlIiwNCiAgICAic2FsX3dvcmtlciIsDQogICAgInNhbF9GZW1hbGVzIiwNCiAgICAic2FsX0ZfZXhlY3V0aXZlIiwNCiAgICAic2FsX0ZfbWlkTWFuYWdlciIsDQogICAgInNhbF9GX2VtcGxveWVlIiwNCiAgICAic2FsX0Zfd29ya2VyIiwNCiAgICAic2FsX01hbGVzIiwNCiAgICAic2FsX01fZXhlY3V0aXZlIiwNCiAgICAic2FsX01fbWlkTWFuYWdlciIsDQogICAgInNhbF9NX2VtcGxveWVlIiwNCiAgICAic2FsX01fd29ya2VyIiwNCiAgICAic2FsXzE4XzI1IiwNCiAgICAic2FsXzI2XzUwIiwNCiAgICAic2FsXzUxcGx1cyIsDQogICAgInNhbF9GXzE4XzI1IiwNCiAgICAic2FsX0ZfMjZfNTAiLA0KICAgICJzYWxfRl81MXBsdXMiLA0KICAgICJzYWxfTV8xOF8yNSIsDQogICAgInNhbF9NXzI2XzUwIiwNCiAgICAic2FsX01fNTFwbHVzIikNCg0KIyBwcmVsaW1pbmFyeSBjaGVja3MNCm5hbWVzKHNhbGFyeSkNCmhlYWQoc2FsYXJ5KQ0Kc3RyKHNhbGFyeSkNCnN1bW1hcnkoc2FsYXJ5KQ0KDQojIENoZWNrIGZvciBkdXBsaWNhdGVkIGRhdGE6IHRoZXJlIGFyZSBubw0Kc3VtKGR1cGxpY2F0ZWQuZGF0YS5mcmFtZShzYWxhcnkpKQ0KDQojIGRyb3AgdW5uZWNlc3NhcnkgdmFyaWFibGUNCnNhbGFyeSA8LXN1YnNldChzYWxhcnksIHNlbGVjdCA9IC1jKHRvd24pKQ0KDQpgYGANCg0KIyMgUG9wdWxhdGlvbiBkYXRhIA0KDQpSZW5hbWUgdGhlIHZhcmlhYmxlcyBmb3IgcG9wdWxhdGlvbiBhbmQgZXhjbHVkZSB0aGUgdW5uZWNlc3Nhcnkgb25lczoNCmBgYHtyIHByZSBwcm9jZXNzaW5nIHBvcHVsYXRpb259DQoNCiNuYW1lcyhwb3B1bGF0aW9uKQ0KbmFtZXMocG9wdWxhdGlvbilbNTo3XSA8LQ0KICBjKCJhZ2VDYXRlZzUiLA0KICAgICJzZXgiLA0KICAgICJwZW9wbGVDYXRlZ051bSIpDQoNCiMgZHJvcCB1bm5lY2Vzc2FyeSBjb2x1bW5zIChOSVZHRU8gaXMgdGhlIHNhbWUgZm9yIGFsbCkNCnBvcHVsYXRpb24gPC0gc3Vic2V0KHBvcHVsYXRpb24sIHNlbGVjdCA9IC1jKE5JVkdFTywgTElCR0VPKSkNCg0KIyBSZWZhY3RvciBzZXggYW5kIE1PQ08NCnBvcHVsYXRpb24kTU9DTyA8LSBmYWN0b3IocG9wdWxhdGlvbiRNT0NPLCBsZXZlbHMgPSBjKDExLDEyLDIxLDIyLDIzLDMxLDMyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiY2hpbGRyZW5fbGl2aW5nX3dpdGhfdHdvX3BhcmVudHMiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY2hpbGRyZW5fbGl2aW5nX3dpdGhfb25lX3BhcmVudCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImFkdWx0c19saXZpbmdfaW5fY291cGxlX3dpdGhvdXRfY2hpbGQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJhZHVsdHNfbGl2aW5nX2luX2NvdXBsZV93aXRoX2NoaWxkcmVuIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYWR1bHRzX2xpdmluZ19hbG9uZV93aXRoX2NoaWxkcmVuIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicGVyc29uc19ub3RfZnJvbV9mYW1pbHlfbGl2aW5nX2luX3RoZV9ob21lIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicGVyc29uc19saXZpbmdfYWxvbmUiKSkNCnBvcHVsYXRpb24kc2V4IDwtIGZhY3Rvcihwb3B1bGF0aW9uJHNleCwgbGV2ZWxzID0gYygxLDIpLCBsYWJlbHMgPSBjKCJNYWxlIiwgIkZlbWFsZSIpKQ0KDQojIGNoZWNrIGFnYWluDQpzdW1tYXJ5KHBvcHVsYXRpb24pDQoNCmBgYA0KDQpVbmRlcnN0YW5kIHRoZSBkaXN0cmlidXRpb24gb2YgcG9wdWxhdGlvbiBhY2NvcmRpbmcgdG8gZGlmZmVyZW50IGFnZSBjYXRlZ29yaWVzIHVzaW5nIHBvcHVsYXRpb24gcHlyYW1pZGUNCihwZXJmb3JtZWQgbm93IGJlY2F1c2UgbGF0ZXIgdGhlIGRhdGFzZXQgd2lsbCBiZSBtb2RpZmllZCk6DQpgYGB7ciBQb3B1bGF0aW9uIHB5cmFtaWRlfQ0KDQojIG5lZWQgdGhlIGluaXRpYWwgc2hhcGUgb2YgZGF0YSB0byBjb25zdHJ1Y3QgdGhlIHB5cmFtaWRlIA0KIyBQb3B1bGF0aW9uIHB5cmFtaWRlDQpwb3B1bGF0aW9uX2RhdGEyIDwtIGRkcGx5KHBvcHVsYXRpb24sIC4oc2V4LCBhZ2VDYXRlZzUpLCBmdW5jdGlvbihwb3B1bGF0aW9uKSB7DQogIGRhdGEuZnJhbWUodG90YWxfcG9wdWxhdGlvbiA9IHN1bShwb3B1bGF0aW9uJHBlb3BsZUNhdGVnTnVtKSkNCiAgfSkNCnBvcF9weXJhbWlkIDwtIGdncGxvdChkYXRhID0gcG9wdWxhdGlvbl9kYXRhMiwNCiAgICAgICBtYXBwaW5nID0gYWVzKHggPSBhZ2VDYXRlZzUsIGZpbGwgPSBzZXgsDQogICAgICAgICAgICAgICAgICAgICB5ID0gaWZlbHNlKHRlc3QgPSBzZXggPT0gIk1hbGUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZXMgPSAtdG90YWxfcG9wdWxhdGlvbiwgbm8gPSB0b3RhbF9wb3B1bGF0aW9uKSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGFicywgbGltaXRzID0gbWF4KHBvcHVsYXRpb25fZGF0YTIkdG90YWxfcG9wdWxhdGlvbikgKiBjKC0xLDEpKSArIA0KICBnZ3RpdGxlKCJQeXJhbWlkIG9mIFBvcHVsYXRpb24iKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSArIA0KICBsYWJzKHg9ICJBZ2UiKSsgbGFicyh5ID0gIlBvcHVsYXRpb24iKSArIGNvb3JkX2ZsaXAoKSAjICsgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIikNCnBvcF9weXJhbWlkDQoNCmBgYA0KDQpSZS1vcmdhbml6ZSBwb3B1bGF0aW9uIGRhdGFzZXQgYW5kIHNldCBDT0RHRU8gYXMgdW5pdHMgYW5kIGNyZWF0ZSBuZXcgdmFyaWFibGVzIHVzaW5nIHRoZSBhdmFpbGFibGUgdmFyaWFibGVzLg0KYGBge3IgUmUtb3JnYW5pemUgcG9wdWxhdGlvbiBkYXRhc2V0IGJ5IENPREdFT30NCg0KIyBSZS1vcmdhbml6ZSB0aGUgZGF0YSBieSBjcmVhdGluZyBuZXcgdmFyaWFibGVzOiAidG90YWwgcG9wdWxhdGlvbiIsICJtYWxlIiwgImZlbWFsZSIsICJjaGlsZCIsICJlbGRlcmx5IiBhbmQgIndvcmtmb3JjZSIuDQpwb3B1bGF0aW9uIDwtIGRkcGx5KHBvcHVsYXRpb24sIC4oQ09ER0VPKSwgZnVuY3Rpb24ocG9wdWxhdGlvbikgew0KICBkYXRhLmZyYW1lKHRvdGFsX3BvcHVsYXRpb24gPSBzdW0ocG9wdWxhdGlvbiRwZW9wbGVDYXRlZ051bSksDQogICAgICAgICAgICAgbWFsZSA9IHN1bShwb3B1bGF0aW9uW3BvcHVsYXRpb24kc2V4ID09ICJNYWxlIixdJHBlb3BsZUNhdGVnTnVtKSwNCiAgICAgICAgICAgICBmZW1hbGUgPSBzdW0ocG9wdWxhdGlvbltwb3B1bGF0aW9uJHNleCA9PSAiRmVtYWxlIixdJHBlb3BsZUNhdGVnTnVtKSwNCiAgICAgICAgICAgICBjaGlsZCA9IHN1bShwb3B1bGF0aW9uW3BvcHVsYXRpb24kYWdlQ2F0ZWc1ICVpbiUgc2VxKDAsIDEwLCBieT01KSxdJHBlb3BsZUNhdGVnTnVtKSwNCiAgICAgICAgICAgICBlbGRlcmx5ID0gc3VtKHBvcHVsYXRpb25bcG9wdWxhdGlvbiRhZ2VDYXRlZzUgJWluJSBzZXEoNjUsIDgwLCBieT01KSxdJHBlb3BsZUNhdGVnTnVtKSwNCiAgICAgICAgICAgICB3b3JrZm9yY2UgPSBzdW0ocG9wdWxhdGlvbltwb3B1bGF0aW9uJGFnZUNhdGVnNSAlaW4lIHNlcSgxNSwgNjAsIGJ5PTUpLF0kcGVvcGxlQ2F0ZWdOdW0pIA0KICApfSkNCg0KIyBDYWxjdWxhdGUgcmF0aW9zIHVzaW5nIHRoZSBleGlzdGluZyB2YXJpYWJsZXMNCnBvcHVsYXRpb24kZGVwZW5kZW50IDwtIHBvcHVsYXRpb24kY2hpbGQgKyBwb3B1bGF0aW9uJGVsZGVybHkNCnBvcHVsYXRpb24kc2V4X3JhdGlvIDwtIGlmZWxzZShwb3B1bGF0aW9uJGZlbWFsZT09MCwgMCwgcG9wdWxhdGlvbiRtYWxlIC8gcG9wdWxhdGlvbiRmZW1hbGUpDQpwb3B1bGF0aW9uJGRlcGVuZGVuY3lfcmF0aW8gPC0gaWZlbHNlKHBvcHVsYXRpb24kd29ya2ZvcmNlPT0wLCAwLCBwb3B1bGF0aW9uJGRlcGVuZGVudCAvIHBvcHVsYXRpb24kd29ya2ZvcmNlKQ0KcG9wdWxhdGlvbiRhZ2VkX2RlcGVuZGVuY3lfcmF0aW8gPC0gaWZlbHNlKHBvcHVsYXRpb24kd29ya2ZvcmNlPT0wLCAwLCBwb3B1bGF0aW9uJGVsZGVybHkgLyBwb3B1bGF0aW9uJHdvcmtmb3JjZSkNCnBvcHVsYXRpb24kY2hpbGRfZGVwZW5kZW5jeV9yYXRpbyA8LSBpZmVsc2UocG9wdWxhdGlvbiR3b3JrZm9yY2U9PTAsIDAsIHBvcHVsYXRpb24kY2hpbGQgLyBwb3B1bGF0aW9uJHdvcmtmb3JjZSkNCg0KIyB0b3RhbCBwb3B1bGF0aW9uPTY1bWxuLCB3aGljaCBpcyByZWFzb25hYmxlDQpzdW0ocG9wdWxhdGlvbiR0b3RhbF9wb3B1bGF0aW9uKQ0KDQojIGNyZWF0ZSBkdW1teSB2YXJpYWJsZSBmb3IgdXJiYW4gY2l0eQ0KIyB0YWtpbmcgdGhlIHRvcCAyMCUgaW4gdGVybXMgb2YgcG9wdWxhdGlvbg0KcG9wdWxhdGlvbiR1cmJhbkR1bW15ID0gcG9wdWxhdGlvbiR0b3RhbF9wb3B1bGF0aW9uID4gcXVhbnRpbGUocG9wdWxhdGlvbiR0b3RhbF9wb3B1bGF0aW9uLCAwLjkwKQ0KDQpgYGANCg0KIyMgRWR1Y2F0aW9uIGRhdGENCg0KQXNzaWduIG1lYW5pbmdmdWwgbmFtZXMgYW5kIGJ1aWxkIHNvbWUgdXNlZnVsIGluZGljYXRvcnM6DQpgYGB7cn0NCg0KbmFtZXMoZWR1YylbMzpuY29sKGVkdWMpXSA8LQ0KICBjKCJBZ2UxNV9Ob0RpcF9NIiwiQWdlMTVfTm9EaXBfRiIsICJBZ2UxNV9TZWNfTSIsICJBZ2UxNV9TZWNfRiIsICJBZ2UxNV9IaV9NIiwiQWdlMTVfSGlfRiIsICJBZ2UxNV9Vbml2X00iLA0KICAgICJBZ2UxNV9Vbml2X0YiLCAiQWdlMjBfTm9EaXBfTSIsICJBZ2UyMF9Ob0RpcF9GIiwgIkFnZTIwX1NlY19NIiwiQWdlMjBfU2VjX0YiLCAiQWdlMjBfSGlfTSIsICJBZ2UyMF9IaV9GIiwNCiAgICAiQWdlMjBfVW5pdl9NIiwgIkFnZTIwX1VuaXZfRiIsIkFnZTI1X05vRGlwX00iLCAiQWdlMjVfTm9EaXBfRiIsIkFnZTI1X1NlY19NIiwiQWdlMjVfU2VjX0YiLCAiQWdlMjVfSGlfTSIsDQogICAgIkFnZTI1X0hpX0YiLCJBZ2UyNV9Vbml2X00iLCJBZ2UyNV9Vbml2X0YiLCAiQWdlMzBfTm9EaXBfTSIsICJBZ2UzMF9Ob0RpcF9GIiwgIkFnZTMwX1NlY19NIiwgIkFnZTMwX1NlY19GIiwNCiAgICAiQWdlMzBfSGlfTSIsICJBZ2UzMF9IaV9GIiwiQWdlMzBfVW5pdl9NIiwiQWdlMzBfVW5pdl9GIiwgIkFnZTM1X05vRGlwX00iLCAiQWdlMzVfTm9EaXBfRiIsICJBZ2UzNV9TZWNfTSIsDQogICAgIkFnZTM1X1NlY19GIiwgIkFnZTM1X0hpX00iLCAiQWdlMzVfSGlfRiIsICJBZ2UzNV9Vbml2X00iLCJBZ2UzNV9Vbml2X0YiLCAiQWdlNDBfTm9EaXBfTSIsICJBZ2U0MF9Ob0RpcF9GIiwNCiAgICAiQWdlNDBfU2VjX00iLCJBZ2U0MF9TZWNfRiIsICJBZ2U0MF9IaV9NIiwgIkFnZTQwX0hpX0YiLCAiQWdlNDBfVW5pdl9NIiwiQWdlNDBfVW5pdl9GIiwgIkFnZTQ1X05vRGlwX00iLA0KICAgICJBZ2U0NV9Ob0RpcF9GIiwiQWdlNDVfU2VjX00iLCJBZ2U0NV9TZWNfRiIsICJBZ2U0NV9IaV9NIiwgIkFnZTQ1X0hpX0YiLCAiQWdlNDVfVW5pdl9NIiwiQWdlNDVfVW5pdl9GIiwNCiAgICAiQWdlNTBfTm9EaXBfTSIsICJBZ2U1MF9Ob0RpcF9GIiwiQWdlNTBfU2VjX00iLCJBZ2U1MF9TZWNfRiIsICJBZ2U1MF9IaV9NIiwgIkFnZTUwX0hpX0YiLCAiQWdlNTBfVW5pdl9NIiwNCiAgICAiQWdlNTBfVW5pdl9GIiwgIkFnZTU1X05vRGlwX00iLCAiQWdlNTVfTm9EaXBfRiIsIkFnZTU1X1NlY19NIiwgIkFnZTU1X1NlY19GIiwgIkFnZTU1X0hpX00iLCAiQWdlNTVfSGlfRiIsDQogICAgIkFnZTU1X1VuaXZfTSIsICJBZ2U1NV9Vbml2X0YiLCAiQWdlNjBfTm9EaXBfTSIsICJBZ2U2MF9Ob0RpcF9GIiwiQWdlNjBfU2VjX00iLCJBZ2U2MF9TZWNfRiIsICJBZ2U2MF9IaV9NIiwNCiAgICAiQWdlNjBfSGlfRiIsICJBZ2U2MF9Vbml2X00iLCAiQWdlNjBfVW5pdl9GIiwgIkFnZTY1X05vRGlwX00iLCAiQWdlNjVfTm9EaXBfRiIsIkFnZTY1X1NlY19NIiwiQWdlNjVfU2VjX0YiLA0KICAgICJBZ2U2NV9IaV9NIiwgIkFnZTY1X0hpX0YiLCAiQWdlNjVfVW5pdl9NIiwgIkFnZTY1X1VuaXZfRiIpDQoNCiMgQWdncmVnYXRlIHZhcmlhYmxlcyBieSBncm91cGluZyBhbGwgdGhlIGVkdWNhdGlvbiBsZXZlbCBjYXRlZ29yaWVzIGJ5IGdlbmRlcg0KIyB0b3RhbCBudW1iZXIgb2YgZmVtYWxlcyB3aXRoIG5vIGRpcGxvbWENCmVkdWMkZmVtYWxlX05vRGlwIDwtIHJvd1N1bXMoY2JpbmQoZWR1YyRBZ2UxNV9Ob0RpcF9GLCBlZHVjJEFnZTIwX05vRGlwX0YsIGVkdWMkQWdlMjVfTm9EaXBfRiwgZWR1YyRBZ2UzMF9Ob0RpcF9GLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlZHVjJEFnZTM1X05vRGlwX0YsZWR1YyRBZ2U0MF9Ob0RpcF9GLGVkdWMkQWdlNDVfTm9EaXBfRiwgZWR1YyRBZ2U1MF9Ob0RpcF9GLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlZHVjJEFnZTU1X05vRGlwX0YsIGVkdWMkQWdlNjBfTm9EaXBfRiwgZWR1YyRBZ2U2NV9Ob0RpcF9GKSkNCg0KIyB0b3RhbCBudW1iZXIgb2YgbWFsZXMgd2l0aCBubyBkaXBsb21hDQplZHVjJG1hbGVfTm9EaXAgPC0gcm93U3VtcyhjYmluZChlZHVjJEFnZTE1X05vRGlwX00sIGVkdWMkQWdlMjBfTm9EaXBfTSwgZWR1YyRBZ2UyNV9Ob0RpcF9NLCBlZHVjJEFnZTMwX05vRGlwX00sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlZHVjJEFnZTM1X05vRGlwX00sZWR1YyRBZ2U0MF9Ob0RpcF9NLGVkdWMkQWdlNDVfTm9EaXBfTSwgZWR1YyRBZ2U1MF9Ob0RpcF9NLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWR1YyRBZ2U1NV9Ob0RpcF9NLCBlZHVjJEFnZTYwX05vRGlwX00sIGVkdWMkQWdlNjVfTm9EaXBfTSkpDQoNCiMgdG90YWwgbnVtYmVyIG9mIGZlbWFsZXMgd2l0aCBzZWNvbmRhcnkgZWR1Y2F0aW9uIGxldmVsDQplZHVjJGZlbWFsZV9TZWMgPC0gcm93U3VtcyhjYmluZChlZHVjJEFnZTE1X1NlY19GLCBlZHVjJEFnZTIwX1NlY19GLCBlZHVjJEFnZTI1X1NlY19GLCBlZHVjJEFnZTMwX1NlY19GLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWR1YyRBZ2UzNV9TZWNfRixlZHVjJEFnZTQwX1NlY19GLGVkdWMkQWdlNDVfU2VjX0YsIGVkdWMkQWdlNTBfU2VjX0YsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWR1YyRBZ2U1NV9TZWNfRiwgZWR1YyRBZ2U2MF9TZWNfRiwgZWR1YyRBZ2U2NV9TZWNfRikpDQoNCiMgdG90YWwgbnVtYmVyIG9mIG1hbGVzIHdpdGggc2Vjb25kYXJ5IGVkdWNhdGlvbiBsZXZlbA0KZWR1YyRtYWxlX1NlYyA8LSByb3dTdW1zKGNiaW5kKGVkdWMkQWdlMTVfU2VjX00sIGVkdWMkQWdlMjBfU2VjX00sIGVkdWMkQWdlMjVfU2VjX00sIGVkdWMkQWdlMzBfU2VjX00sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWR1YyRBZ2UzNV9TZWNfTSxlZHVjJEFnZTQwX1NlY19NLGVkdWMkQWdlNDVfU2VjX00sIGVkdWMkQWdlNTBfU2VjX00sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVkdWMkQWdlNTVfU2VjX00sIGVkdWMkQWdlNjBfU2VjX00sIGVkdWMkQWdlNjVfU2VjX00pKQ0KDQojIHRvdGFsIG51bWJlciBvZiBmZW1hbGVzIHdpdGggaGlnaC1zY2hvb2wgZWR1Y2F0aW9uIGxldmVsDQplZHVjJGZlbWFsZV9IaSA8LSByb3dTdW1zKGNiaW5kKGVkdWMkQWdlMTVfSGlfRiwgZWR1YyRBZ2UyMF9IaV9GLCBlZHVjJEFnZTI1X0hpX0YsIGVkdWMkQWdlMzBfSGlfRiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWR1YyRBZ2UzNV9IaV9GLGVkdWMkQWdlNDBfSGlfRixlZHVjJEFnZTQ1X0hpX0YsIGVkdWMkQWdlNTBfSGlfRiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVkdWMkQWdlNTVfSGlfRiwgZWR1YyRBZ2U2MF9IaV9GLCBlZHVjJEFnZTY1X0hpX0YpKQ0KDQojIHRvdGFsIG51bWJlciBvZiBtYWxlcyB3aXRoIGhpZ2gtc2Nob29sIGVkdWNhdGlvbiBsZXZlbA0KZWR1YyRtYWxlX0hpIDwtIHJvd1N1bXMoY2JpbmQoZWR1YyRBZ2UxNV9IaV9NLCBlZHVjJEFnZTIwX0hpX00sIGVkdWMkQWdlMjVfSGlfTSwgZWR1YyRBZ2UzMF9IaV9NLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWR1YyRBZ2UzNV9IaV9NLGVkdWMkQWdlNDBfSGlfTSxlZHVjJEFnZTQ1X0hpX00sIGVkdWMkQWdlNTBfSGlfTSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlZHVjJEFnZTU1X0hpX00sIGVkdWMkQWdlNjBfSGlfTSwgZWR1YyRBZ2U2NV9IaV9NKSkNCg0KIyB0b3RhbCBudW1iZXIgb2YgZmVtYWxlcyB3aXRoIHVuaXZlcnNpdHkgZGVncmVlDQplZHVjJGZlbWFsZV9Vbml2IDwtIHJvd1N1bXMoY2JpbmQoZWR1YyRBZ2UxNV9Vbml2X0YsIGVkdWMkQWdlMjBfVW5pdl9GLCBlZHVjJEFnZTI1X1VuaXZfRiwgZWR1YyRBZ2UzMF9Vbml2X0YsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWR1YyRBZ2UzNV9Vbml2X0YsZWR1YyRBZ2U0MF9Vbml2X0YsZWR1YyRBZ2U0NV9Vbml2X0YsIGVkdWMkQWdlNTBfVW5pdl9GLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVkdWMkQWdlNTVfVW5pdl9GLCBlZHVjJEFnZTYwX1VuaXZfRiwgZWR1YyRBZ2U2NV9Vbml2X0YpKQ0KDQojIHRvdGFsIG51bWJlciBvZiBtYWxlcyB3aXRoIHVuaXZlcnNpdHkgZGVncmVlDQplZHVjJG1hbGVfVW5pdiA8LSByb3dTdW1zKGNiaW5kKGVkdWMkQWdlMTVfVW5pdl9NLCBlZHVjJEFnZTIwX1VuaXZfTSwgZWR1YyRBZ2UyNV9Vbml2X00sIGVkdWMkQWdlMzBfVW5pdl9NLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlZHVjJEFnZTM1X1VuaXZfTSxlZHVjJEFnZTQwX1VuaXZfTSxlZHVjJEFnZTQ1X1VuaXZfTSwgZWR1YyRBZ2U1MF9Vbml2X00sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVkdWMkQWdlNTVfVW5pdl9NLCBlZHVjJEFnZTYwX1VuaXZfTSwgZWR1YyRBZ2U2NV9Vbml2X00pKQ0KDQojIGRyb3AgYWxsIHRoZSB1bm5lY2Vzc2FyeSB2YXJpYWJsZXMgDQplZHVjIDwtIHN1YnNldChlZHVjLCBzZWxlY3Q9IGMoQ09ER0VPLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZlbWFsZV9Ob0RpcCwgbWFsZV9Ob0RpcCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmVtYWxlX1NlYywgbWFsZV9TZWMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZlbWFsZV9IaSwgbWFsZV9IaSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmVtYWxlX1VuaXYsIG1hbGVfVW5pdikpDQoNCiMgdG90YWwgbnVtYmVyIG9mIHBvcHVsYXRpb24gd2l0aG91dCBhIGRpcGxvbWENCmVkdWMkbm9kaXAgPC1yb3dTdW1zKGNiaW5kKGVkdWMkZmVtYWxlX05vRGlwLCBlZHVjJG1hbGVfTm9EaXApKQ0KDQojIHRvdGFsIG51bWJlciBvZiBwb3B1bGF0aW9uIHdpdGggc2Vjb25kYXJ5IGxldmVsIG9mIGVkdWNhdGlvbg0KZWR1YyRzZWMgPC1yb3dTdW1zKGNiaW5kKGVkdWMkZmVtYWxlX1NlYywgZWR1YyRtYWxlX05vRGlwKSkNCg0KIyB0b3RhbCBudW1iZXIgb2YgcG9wdWxhdGlvbiB3aXRoIGhpZ2hzY2hvb2wgZGlwbG9tYQ0KZWR1YyRoaWdoIDwtcm93U3VtcyhjYmluZChlZHVjJGZlbWFsZV9IaSwgZWR1YyRtYWxlX0hpKSkNCg0KIyB0b3RhbCBudW1iZXIgb2YgcG9vcHVsYXRpb24gd2l0aCB1bml2ZXJzaXR5IGRpcGxvbWENCmVkdWMkdW5pdiA8LSByb3dTdW1zKGNiaW5kKGVkdWMkZmVtYWxlX1VuaXYsIGVkdWMkbWFsZV9Vbml2KSkNCg0KYGBgDQoNCg0KIyMgRGVtb2dyYXBoaWMvc29jaWFsIHByb2ZpbGVzIGRhdGENCg0KUmVuYW1lIHRoZSBvcmlnaW5hbCB2YXJpYWJsZXMgDQpgYGB7ciBwcmUtcHJvY2Vzc2luZyBkZW1vZ3JhcGhpYy9zb2NpYWwgcHJvZmlsZXMgZGF0YX0NCg0KIyByZW5hbWUgdmFyaWFibGVzDQpuYW1lcyhjYXRlZ19zb2NpbylbMzpuY29sKGNhdGVnX3NvY2lvKV0gPC0NCiAgYygiTV9pbW1pX2FncmkiLA0KICAgICJGX2ltbWlfYWdyaSIsDQogICAgIk1fTm9JbW1pX2FncmkiLA0KICAgICJGX05vSW1taV9hZ3JpIiwNCiAgICAiTV9pbW1pX2NvbW0iLA0KICAgICJGX2ltbWlfY29tbSIsDQogICAgIk1fTm9JbW1pX2NvbW0iLA0KICAgICJGX05vSW1taV9jb21tIiwNCiAgICAiTV9pbW1pX2V4ZWMiLA0KICAgICJGX2ltbWlfZXhlYyIsDQogICAgIk1fTm9JbW1pX2V4ZWMiLA0KICAgICJGX05vSW1taV9leGVjIiwNCiAgICAiTV9pbW1pX21pZG1hbiIsDQogICAgIkZfaW1taV9taWRtYW4iLA0KICAgICJNX05vSW1taV9taWRtYW4iLA0KICAgICJGX05vSW1taV9taWRtYW4iLA0KICAgICJNX2ltbWlfZW1wIiwNCiAgICAiRl9pbW1pX2VtcCIsDQogICAgIk1fTm9JbW1pX2VtcCIsDQogICAgIkZfTm9JbW1pX2VtcCIsDQogICAgIk1faW1taV93b3JrZXIiLA0KICAgICJGX2ltbWlfd29ya2VyIiwNCiAgICAiTV9Ob0ltbWlfd29ya2VyIiwNCiAgICAiRl9Ob0ltbWlfd29ya2VyIiwNCiAgICAiTV9pbW1pX3JldGlyZWQiLA0KICAgICJGX2ltbWlfcmV0aXJlZCIsDQogICAgIk1fTm9JbW1pX3JldGlyZWQiLA0KICAgICJGX05vSW1taV9yZXRpcmVkIiwNCiAgICAiTV9pbW1pX25vQWN0IiwNCiAgICAiRl9pbW1pX25vQWN0IiwNCiAgICAiTV9Ob0ltbWlfbm9BY3QiLA0KICAgICJGX05vSW1taV9ub0FjdCIpDQoNCiMgZHJvcCBMSUJHRU8NCmNhdGVnX3NvY2lvIDwtIHN1YnNldChjYXRlZ19zb2Npbywgc2VsZWN0PS1jKExJQkdFTykpDQoNCmBgYA0KDQpDcmVhdGUgdGhlIHRvdGFsIG51bWJlciBvZiBpbW1pZ3JhbnRzIGFuZCBuYXRpdmVzIHBlciB0b3duLCBhbHNvIHNlcGFyZXRlZCBieSBnZW5kZXIuDQpgYGB7ciBDYXRlZ19zb2Npby1yZW5hbWUgdmFyaWFibGVzIH0NCg0KIyB0b3RhbCBudW1iZXIgb2YgbWFsZSBpbW1pZ3JhbnRzIHBlciB0b3duIA0KY2F0ZWdfc29jaW8kbWFsZV9pbW1pZyA8LXJvd1N1bXMoY2JpbmQoY2F0ZWdfc29jaW8kTV9pbW1pX2FncmksIGNhdGVnX3NvY2lvJE1faW1taV9jb21tLCBjYXRlZ19zb2NpbyRNX2ltbWlfZW1wLCAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXRlZ19zb2NpbyRNX2ltbWlfZXhlYywgY2F0ZWdfc29jaW8kTV9pbW1pX21pZG1hbixjYXRlZ19zb2NpbyRNX2ltbWlfbm9BY3QsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2F0ZWdfc29jaW8kTV9pbW1pX3JldGlyZWQsIGNhdGVnX3NvY2lvJE1faW1taV93b3JrZXIpKQ0KIA0KIyB0b3RhbCBudW1iZXIgb2YgZmVtYWxlIGltbWlncmFudHMgcGVyIHRvd24NCmNhdGVnX3NvY2lvJGZlbWFsZV9pbW1pZyA8LSByb3dTdW1zKGNiaW5kKGNhdGVnX3NvY2lvJEZfaW1taV9hZ3JpLGNhdGVnX3NvY2lvJEZfaW1taV9jb21tLCBjYXRlZ19zb2NpbyRGX2ltbWlfZW1wLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhdGVnX3NvY2lvJEZfaW1taV9leGVjLCBjYXRlZ19zb2NpbyRGX2ltbWlfbWlkbWFuLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhdGVnX3NvY2lvJEZfaW1taV9ub0FjdCwgY2F0ZWdfc29jaW8kRl9pbW1pX3JldGlyZWQsIGNhdGVnX3NvY2lvJEZfaW1taV93b3JrZXIpKQ0KDQojIHRvdGFsIG51bWJlciBpbW1pZ3JhbnRzIHBlciB0b3duDQpjYXRlZ19zb2NpbyR0b3RhbF9pbW1pZyA8LSBjYXRlZ19zb2NpbyRtYWxlX2ltbWlnICsgY2F0ZWdfc29jaW8kZmVtYWxlX2ltbWlnDQoNCiMgd29ya2luZyBtYWxlIGltbWlncmFudHMgcGVyIHRvd24gDQpjYXRlZ19zb2NpbyRtYWxlX3dvcmtpbmdfaW1taWcgPC0gY2F0ZWdfc29jaW8kbWFsZV9pbW1pZyAtIGNhdGVnX3NvY2lvJE1faW1taV9yZXRpcmVkIA0KIA0KIyB3b3JraW5nIGZlbWFsZSBpbW1pZ3JhbnRzIHBlciB0b3duICANCmNhdGVnX3NvY2lvJGZlbWFsZV93b3JraW5nX2ltbWlnIDwtIGNhdGVnX3NvY2lvJGZlbWFsZV9pbW1pZyAtIGNhdGVnX3NvY2lvJEZfaW1taV9yZXRpcmVkIA0KIA0KIyB0b3RhbCBudW1iZXIgb2YgbWFsZSBuYXRpdmVzIHBlciB0b3duIA0KY2F0ZWdfc29jaW8kbWFsZV9uYXRpdmUgPC0gcm93U3VtcyhjYmluZChjYXRlZ19zb2NpbyRNX05vSW1taV9hZ3JpLCBjYXRlZ19zb2NpbyRNX05vSW1taV9jb21tLCBjYXRlZ19zb2NpbyRNX05vSW1taV9leGVjLCBjYXRlZ19zb2NpbyRNX05vSW1taV9lbXAsIGNhdGVnX3NvY2lvJE1fTm9JbW1pX21pZG1hbiwgY2F0ZWdfc29jaW8kTV9Ob0ltbWlfbm9BY3QsIGNhdGVnX3NvY2lvJE1fTm9JbW1pX3JldGlyZWQsIGNhdGVnX3NvY2lvJE1fTm9JbW1pX3dvcmtlcikpDQoNCiMgdG90YWwgbnVtYmVyIG9mIGZlbWFsZSBuYXRpdmVzIHBlciB0b3duIA0KY2F0ZWdfc29jaW8kZmVtYWxlX25hdGl2ZSA8LSByb3dTdW1zKGNiaW5kKGNhdGVnX3NvY2lvJEZfTm9JbW1pX2FncmksIGNhdGVnX3NvY2lvJEZfTm9JbW1pX2NvbW0sIGNhdGVnX3NvY2lvJEZfTm9JbW1pX2V4ZWMsIGNhdGVnX3NvY2lvJEZfTm9JbW1pX2VtcCwgY2F0ZWdfc29jaW8kRl9Ob0ltbWlfbWlkbWFuLCBjYXRlZ19zb2NpbyRGX05vSW1taV9ub0FjdCwgY2F0ZWdfc29jaW8kRl9Ob0ltbWlfcmV0aXJlZCwgY2F0ZWdfc29jaW8kRl9Ob0ltbWlfd29ya2VyKSkNCg0KIyB0b3RhbCBudW1iZXIgb2YgbmF0aXZlcyBwZXIgdG93biANCmNhdGVnX3NvY2lvJHRvdGFsX25hdGl2ZSA8LSBjYXRlZ19zb2NpbyRtYWxlX25hdGl2ZSArIGNhdGVnX3NvY2lvJGZlbWFsZV9uYXRpdmUNCg0KIyBkcm9wIHVubmVjZXNzYXJ5IHZhcmlhYmxlcyANCmNhdGVnX3NvY2lvIDwtIHN1YnNldChjYXRlZ19zb2Npbywgc2VsZWN0ID0gYyhDT0RHRU8sIG1hbGVfaW1taWcsIGZlbWFsZV9pbW1pZywgdG90YWxfaW1taWcsIG1hbGVfd29ya2luZ19pbW1pZywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZlbWFsZV93b3JraW5nX2ltbWlnLCBtYWxlX25hdGl2ZSwgZmVtYWxlX25hdGl2ZSwgdG90YWxfbmF0aXZlKSkgDQoNCmBgYA0KDQoNCiMjIFdvcmsgc3RhdHVzIGRhdGENCg0KUmVuYW1lIHRoZSBvcmlnaW5hbCB2YXJpYWJsZXMNCmBgYHtyIHByZS1wcm9jZXNzaW5nIHdvcmsgc3RhdHVzIGRhdGF9DQoNCiMgcmVuYW1lIHZhcmlhYmxlcw0KbmFtZXMoc3RhdHVzX3dvcmspWzM6bmNvbChzdGF0dXNfd29yayldIDwtDQogIGMoIkxlc3MyMF9NX3dhZ2Vhcm5lcl9GdWxsIiwgIkxlc3MyMF9NX3dhZ2Vhcm5lcl9IYWxmIiwgIkxlc3MyMF9NX0luZHAxX0Z1bGwiLCAiTGVzczIwX01fSW5kcDFfSGFsZiIsDQogICAgIkxlc3MyMF9NX2VtcGxfRnVsbCIsICJMZXNzMjBfTV9lbXBsX0hhbGYiLCAiTGVzczIwX01fdHJhbnNfRnVsbCIsICJMZXNzMjBfTV90cmFuc19IYWxmIiwNCiAgICAiTGVzczIwX0Zfd2FnZWFybmVyX0Z1bGwiLCAiTGVzczIwX0Zfd2FnZWFybmVyX0hhbGYiLCAiTGVzczIwX0ZfSW5kcDFfRnVsbCIsICJMZXNzMjBfRl9JbmRwMV9IYWxmIiwNCiAgICAiTGVzczIwX0ZfZW1wbF9GdWxsIiwgIkxlc3MyMF9GX2VtcGxfSGFsZiIsICJMZXNzMjBfRl90cmFuc19GdWxsIiwgIkxlc3MyMF9GX3RyYW5zX0hhbGYiLA0KICAgICJ0NF9NX3dhZ2Vhcm5lcl9GdWxsIiwgInQ0X01fd2FnZWFybmVyX0hhbGYiLCAidDRfTV9JbmRwMV9GdWxsIiwgInQ0X01fSW5kcDFfSGFsZiIsICJ0NF9NX2VtcGxfRnVsbCIsDQogICAgInQ0X01fZW1wbF9IYWxmIiwgInQ0X01fdHJhbnNfRnVsbCIsICJ0NF9NX3RyYW5zX0hhbGYiLCAidDRfRl93YWdlYXJuZXJfRnVsbCIsICJ0NF9GX3dhZ2Vhcm5lcl9IYWxmIiwNCiAgICAidDRfRl9JbmRwMV9GdWxsIiwgInQ0X0ZfSW5kcDFfSGFsZiIsICJ0NF9GX2VtcGxfRnVsbCIsICJ0NF9GX2VtcGxfSGFsZiIsICJ0NF9GX3RyYW5zX0Z1bGwiLCAidDRfRl90cmFuc19IYWxmIiwNCiAgICAidDlfTV93YWdlYXJuZXJfRnVsbCIsICJ0OV9NX3dhZ2Vhcm5lcl9IYWxmIiwgInQ5X01fSW5kcDFfRnVsbCIsICJ0OV9NX0luZHAxX0hhbGYiLCAidDlfTV9lbXBsX0Z1bGwiLA0KICAgICJ0OV9NX2VtcGxfSGFsZiIsICJ0OV9NX3RyYW5zX0Z1bGwiLCAidDlfTV90cmFuc19IYWxmIiwgInQ5X0Zfd2FnZWFybmVyX0Z1bGwiLCAidDlfRl93YWdlYXJuZXJfSGFsZiIsDQogICAgInQ5X0ZfSW5kcDFfRnVsbCIsICJ0OV9GX0luZHAxX0hhbGYiLCAidDlfRl9lbXBsX0Z1bGwiLCAidDlfRl9lbXBsX0hhbGYiLCAidDlfRl90cmFuc19GdWxsIiwgInQ5X0ZfdHJhbnNfSGFsZiIsDQogICAgIlQ0X01fd2FnZWFybmVyX0Z1bGwiLCAiVDRfTV93YWdlYXJuZXJfSGFsZiIsICJUNF9NX0luZHAxX0Z1bGwiLCAiVDRfTV9JbmRwMV9IYWxmIiwgIlQ0X01fZW1wbF9GdWxsIiwNCiAgICAiVDRfTV9lbXBsX0hhbGYiLCAiVDRfTV90cmFuc19GdWxsIiwgIlQ0X01fdHJhbnNfSGFsZiIsICJUNF9GX3dhZ2Vhcm5lcl9GdWxsIiwgIlQ0X0Zfd2FnZWFybmVyX0hhbGYiLA0KICAgICJUNF9GX0luZHAxX0Z1bGwiLCAiVDRfRl9JbmRwMV9IYWxmIiwgIlQ0X0ZfZW1wbF9GdWxsIiwgIlQ0X0ZfZW1wbF9IYWxmIiwgIlQ0X0ZfdHJhbnNfRnVsbCIsICJUNF9GX3RyYW5zX0hhbGYiLA0KICAgICJUOV9NX3dhZ2Vhcm5lcl9GdWxsIiwgIlQ5X01fd2FnZWFybmVyX0hhbGYiLCAiVDlfTV9JbmRwMV9GdWxsIiwgIlQ5X01fSW5kcDFfSGFsZiIsICJUOV9NX2VtcGxfRnVsbCIsDQogICAgIlQ5X01fZW1wbF9IYWxmIiwgIlQ5X01fdHJhbnNfRnVsbCIsICJUOV9NX3RyYW5zX0hhbGYiLCAiVDlfRl93YWdlYXJuZXJfRnVsbCIsICJUOV9GX3dhZ2Vhcm5lcl9IYWxmIiwNCiAgICAiVDlfRl9JbmRwMV9GdWxsIiwgIlQ5X0ZfSW5kcDFfSGFsZiIsICJUOV9GX2VtcGxfRnVsbCIsICJUOV9GX2VtcGxfSGFsZiIsICJUOV9GX3RyYW5zX0Z1bGwiLCAiVDlfRl90cmFuc19IYWxmIiwNCiAgICAiRkZfTV93YWdlYXJuZXJfRnVsbCIsICJGRl9NX3dhZ2Vhcm5lcl9IYWxmIiwgIkZGX01fSW5kcDFfRnVsbCIsICJGRl9NX0luZHAxX0hhbGYiLCAiRkZfTV9lbXBsX0Z1bGwiLA0KICAgICJGRl9NX2VtcGxfSGFsZiIsICJGRl9NX3RyYW5zX0Z1bGwiLCAiRkZfTV90cmFuc19IYWxmIiwgIkZGX0Zfd2FnZWFybmVyX0Z1bGwiLCAiRkZfRl93YWdlYXJuZXJfSGFsZiIsDQogICAgIkZGX0ZfSW5kcDFfRnVsbCIsICJGRl9GX0luZHAxX0hhbGYiLCAiRkZfRl9lbXBsX0Z1bGwiLCAiRkZfRl9lbXBsX0hhbGYiLCAiRkZfRl90cmFuc19GdWxsIiwgIkZGX0ZfdHJhbnNfSGFsZiIsDQogICAgIkY5X01fd2FnZWFybmVyX0Z1bGwiLCAiRjlfTV93YWdlYXJuZXJfSGFsZiIsICJGOV9NX0luZHAxX0Z1bGwiLCAiRjlfTV9JbmRwMV9IYWxmIiwgIkY5X01fZW1wbF9GdWxsIiwNCiAgICAiRjlfTV9lbXBsX0hhbGYiLCAiRjlfTV90cmFuc19GdWxsIiwgIkY5X01fdHJhbnNfSGFsZiIsICJGOV9GX3dhZ2Vhcm5lcl9GdWxsIiwgIkY5X0Zfd2FnZWFybmVyX0hhbGYiLA0KICAgICJGOV9GX0luZHAxX0Z1bGwiLCAiRjlfRl9JbmRwMV9IYWxmIiwgIkY5X0ZfZW1wbF9GdWxsIiwgIkY5X0ZfZW1wbF9IYWxmIiwgIkY5X0ZfdHJhbnNfRnVsbCIsICJGOV9GX3RyYW5zX0hhbGYiLA0KICAgICJmNF9NX3dhZ2Vhcm5lcl9GdWxsIiwgImY0X01fd2FnZWFybmVyX0hhbGYiLCAiZjRfTV9JbmRwMV9GdWxsIiwgImY0X01fSW5kcDFfSGFsZiIsICJmNF9NX2VtcGxfRnVsbCIsDQogICAgImY0X01fZW1wbF9IYWxmIiwgImY0X01fdHJhbnNfRnVsbCIsICJmNF9NX3RyYW5zX0hhbGYiLCAiZjRfRl93YWdlYXJuZXJfRnVsbCIsICJmNF9GX3dhZ2Vhcm5lcl9IYWxmIiwNCiAgICAiZjRfRl9JbmRwMV9GdWxsIiwgImY0X0ZfSW5kcDFfSGFsZiIsICJmNF9GX2VtcGxfRnVsbCIsICJmNF9GX2VtcGxfSGFsZiIsICJmNF9GX3RyYW5zX0Z1bGwiLCAiZjRfRl90cmFuc19IYWxmIiwNCiAgICAiZjlfTV93YWdlYXJuZXJfRnVsbCIsICJmOV9NX3dhZ2Vhcm5lcl9IYWxmIiwgImY5X01fSW5kcDFfRnVsbCIsICJmOV9NX0luZHAxX0hhbGYiLCAiZjlfTV9lbXBsX0Z1bGwiLA0KICAgICJmOV9NX2VtcGxfSGFsZiIsICJmOV9NX3RyYW5zX0Z1bGwiLCAiZjlfTV90cmFuc19IYWxmIiwgImY5X0Zfd2FnZWFybmVyX0Z1bGwiLCAiZjlfRl93YWdlYXJuZXJfSGFsZiIsDQogICAgImY5X0ZfSW5kcDFfRnVsbCIsICJmOV9GX0luZHAxX0hhbGYiLCAiZjlfRl9lbXBsX0Z1bGwiLCAiZjlfRl9lbXBsX0hhbGYiLCAiZjlfRl90cmFuc19GdWxsIiwgImY5X0ZfdHJhbnNfSGFsZiIsDQogICAgInM0X01fd2FnZWFybmVyX0Z1bGwiLCAiczRfTV93YWdlYXJuZXJfSGFsZiIsICJzNF9NX0luZHAxX0Z1bGwiLCAiczRfTV9JbmRwMV9IYWxmIiwgInM0X01fZW1wbF9GdWxsIiwNCiAgICAiczRfTV9lbXBsX0hhbGYiLCAiczRfTV90cmFuc19GdWxsIiwgInM0X01fdHJhbnNfSGFsZiIsICJzNF9GX3dhZ2Vhcm5lcl9GdWxsIiwgInM0X0Zfd2FnZWFybmVyX0hhbGYiLA0KICAgICJzNF9GX0luZHAxX0Z1bGwiLCAiczRfRl9JbmRwMV9IYWxmIiwgInM0X0ZfZW1wbF9GdWxsIiwgInM0X0ZfZW1wbF9IYWxmIiwgInM0X0ZfdHJhbnNfRnVsbCIsICJzNF9GX3RyYW5zX0hhbGYiLA0KICAgICJzOV9NX3dhZ2Vhcm5lcl9GdWxsIiwgInM5X01fd2FnZWFybmVyX0hhbGYiLCAiczlfTV9JbmRwMV9GdWxsIiwgInM5X01fSW5kcDFfSGFsZiIsICJzOV9NX2VtcGxfRnVsbCIsDQogICAgInM5X01fZW1wbF9IYWxmIiwgInM5X01fdHJhbnNfRnVsbCIsICJzOV9NX3RyYW5zX0hhbGYiLCAiczlfRl93YWdlYXJuZXJfRnVsbCIsICJzOV9GX3dhZ2Vhcm5lcl9IYWxmIiwNCiAgICAiczlfRl9JbmRwMV9GdWxsIiwgInM5X0ZfSW5kcDFfSGFsZiIsICJzOV9GX2VtcGxfRnVsbCIsICJzOV9GX2VtcGxfSGFsZiIsICJzOV9GX3RyYW5zX0Z1bGwiLCAiczlfRl90cmFuc19IYWxmIikNCg0KYGBgDQoNCkNyZWF0ZSBhZ2dyZWdhdGUgc3RhdGlzdGljcyBhbmQgZHJvcCB1bm5lY2Vzc2FyeSB2YXJpYWJsZXMNCmBgYHtyIFN0YXR1cyBkcm9wIGFuZCBhZ2dyZWdhdGlvbn0NCg0KIyBTaW1wbGlmeSB0aGUgdmFyaWFibGVzIGJ5IHN1bW1pbmcgdXAgYnkgY2F0ZWdvcmllcw0KIyB0b3RhbCBudW1iZXIgb2Ygd2FnZSBlYXJuZXJzIGZvciBtYWxlcyBhbmQgZmVtYWxlcy4NCm5hbS5NID0gcmVwKDAsIG5jb2woc3RhdHVzX3dvcmspKQ0KbmFtLkYgPSByZXAoMCwgbmNvbChzdGF0dXNfd29yaykpDQpmb3IgKGkgaW4gMTpuY29sKHN0YXR1c193b3JrKSl7DQogIHNvbCA9IGdyZXBsKCd3YWdlYXJuZXInLCBuYW1lcyhzdGF0dXNfd29yaylbaV0pDQogIGlmIChzb2w9PTEpew0KICAgIGlmIChncmVwbCgnTScsIG5hbWVzKHN0YXR1c193b3JrKVtpXSkpew0KICAgICAgbmFtLk1baV0gPSBpICANCiAgICB9ZWxzZXtuYW0uRltpXT1pfQ0KICB9ZWxzZXsNCiAgICBuYW0uRltpXT0wDQogICAgbmFtLk1baV09MH0NCn0NCiMgbmFtZXMoc3RhdHVzX3dvcmtbbmFtLk1dKQ0KIyBuYW1lcyhzdGF0dXNfd29ya1tuYW0uRl0pDQpzdGF0dXNfd29yayR3YWdlYXJuZXJfTT1yb3dTdW1zKHN0YXR1c193b3JrWyxuYW0uTV0pDQpzdGF0dXNfd29yayR3YWdlYXJuZXJfRj1yb3dTdW1zKHN0YXR1c193b3JrWyxuYW0uRl0pIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiMgc2FtZSBidXQgZm9yIGluZGVwZW5kZW50IHdvcmtlcnMgYnkgZ2VuZGVyDQpuYW0uTSA9IHJlcCgwLCBuY29sKHN0YXR1c193b3JrKSkNCm5hbS5GID0gcmVwKDAsIG5jb2woc3RhdHVzX3dvcmspKQ0KZm9yIChpIGluIDE6bmNvbChzdGF0dXNfd29yaykpew0KICBzb2wgPSBncmVwbCgnSW5kcDEnLCBuYW1lcyhzdGF0dXNfd29yaylbaV0pDQogIGlmIChzb2w9PTEpew0KICAgIGlmIChncmVwbCgnTScsIG5hbWVzKHN0YXR1c193b3JrKVtpXSkpew0KICAgICAgbmFtLk1baV0gPSBpICANCiAgICB9ZWxzZXtuYW0uRltpXT1pfQ0KICB9ZWxzZXsNCiAgICBuYW0uRltpXT0wDQogICAgbmFtLk1baV09MH0NCn0NCiMgbmFtZXMoc3RhdHVzX3dvcmtbbmFtLk1dKQ0KIyBuYW1lcyhzdGF0dXNfd29ya1tuYW0uRl0pDQpzdGF0dXNfd29yayRpbmRlcGVuZGVudF9NPXJvd1N1bXMoc3RhdHVzX3dvcmtbLG5hbS5NXSkgDQpzdGF0dXNfd29yayRpbmRlcGVuZGVudF9GPXJvd1N1bXMoc3RhdHVzX3dvcmtbLG5hbS5GXSkNCg0KIyBzYW1lIGJ1dCBmb3IgZ292ZXJubWVudCB0cmFuc2ZlciByZWNlaXZlcnMNCm5hbS5NID0gcmVwKDAsIG5jb2woc3RhdHVzX3dvcmspKQ0KbmFtLkYgPSByZXAoMCwgbmNvbChzdGF0dXNfd29yaykpDQpmb3IgKGkgaW4gMTpuY29sKHN0YXR1c193b3JrKSl7DQogIHNvbCA9IGdyZXBsKCd0cmFucycsIG5hbWVzKHN0YXR1c193b3JrKVtpXSkNCiAgaWYgKHNvbD09MSl7DQogICAgaWYgKGdyZXBsKCdNJywgbmFtZXMoc3RhdHVzX3dvcmspW2ldKSl7DQogICAgICBuYW0uTVtpXSA9IGkgIA0KICAgIH1lbHNle25hbS5GW2ldPWl9DQogIH1lbHNlew0KICAgIG5hbS5GW2ldPTANCiAgICBuYW0uTVtpXT0wfQ0KfQ0KIyBuYW1lcyhzdGF0dXNfd29ya1tuYW0uTV0pDQojIG5hbWVzKHN0YXR1c193b3JrW25hbS5GXSkNCnN0YXR1c193b3JrJHRyYW5zZmVyX009cm93U3VtcyhzdGF0dXNfd29ya1ssbmFtLk1dKSAgDQpzdGF0dXNfd29yayR0cmFuc2Zlcl9GPXJvd1N1bXMoc3RhdHVzX3dvcmtbLG5hbS5GXSkNCg0KIyBzYW1lIGJ1dCBmb3IgZW1wbG95ZXJzDQpuYW0uTSA9IHJlcCgwLCBuY29sKHN0YXR1c193b3JrKSkNCm5hbS5GID0gcmVwKDAsIG5jb2woc3RhdHVzX3dvcmspKQ0KZm9yIChpIGluIDE6bmNvbChzdGF0dXNfd29yaykpew0KICBzb2wgPSBncmVwbCgnZW1wbCcsIG5hbWVzKHN0YXR1c193b3JrKVtpXSkNCiAgaWYgKHNvbD09MSl7DQogICAgaWYgKGdyZXBsKCdNJywgbmFtZXMoc3RhdHVzX3dvcmspW2ldKSl7DQogICAgICBuYW0uTVtpXSA9IGkgIA0KICAgIH1lbHNle25hbS5GW2ldPWl9DQogIH1lbHNlew0KICAgIG5hbS5GW2ldPTANCiAgICBuYW0uTVtpXT0wfQ0KfQ0KIyBuYW1lcyhzdGF0dXNfd29ya1tuYW0uTV0pDQojIG5hbWVzKHN0YXR1c193b3JrW25hbS5GXSkNCnN0YXR1c193b3JrJGVtcGxveWVyX009cm93U3VtcyhzdGF0dXNfd29ya1ssbmFtLk1dKQ0Kc3RhdHVzX3dvcmskZW1wbG95ZXJfRj1yb3dTdW1zKHN0YXR1c193b3JrWyxuYW0uRl0pDQogDQojIHNhbWUgYnV0IGZvciBmdWxsLXRpbWUgY29udHJhY3RzDQpuYW0uTSA9IHJlcCgwLCBuY29sKHN0YXR1c193b3JrKSkNCm5hbS5GID0gcmVwKDAsIG5jb2woc3RhdHVzX3dvcmspKQ0KZm9yIChpIGluIDE6bmNvbChzdGF0dXNfd29yaykpew0KICBzb2wgPSBncmVwbCgnRnVsbCcsIG5hbWVzKHN0YXR1c193b3JrKVtpXSkNCiAgaWYgKHNvbD09MSl7DQogICAgaWYgKGdyZXBsKCdNJywgbmFtZXMoc3RhdHVzX3dvcmspW2ldKSl7DQogICAgICBuYW0uTVtpXSA9IGkgIA0KICAgIH1lbHNle25hbS5GW2ldPWl9DQogIH1lbHNlew0KICAgIG5hbS5GW2ldPTANCiAgICBuYW0uTVtpXT0wfQ0KfQ0KIyBuYW1lcyhzdGF0dXNfd29ya1tuYW0uTV0pDQojIG5hbWVzKHN0YXR1c193b3JrW25hbS5GXSkNCnN0YXR1c193b3JrJGZ1bGxfTT1yb3dTdW1zKHN0YXR1c193b3JrWyxuYW0uTV0pDQpzdGF0dXNfd29yayRmdWxsX0Y9cm93U3VtcyhzdGF0dXNfd29ya1ssbmFtLkZdKQ0KDQojIHNhbWUgYnV0IGZvciBoYWxmLXRpbWUgY29udHJhY3RzDQpuYW0uTSA9IHJlcCgwLCBuY29sKHN0YXR1c193b3JrKSkNCm5hbS5GID0gcmVwKDAsIG5jb2woc3RhdHVzX3dvcmspKQ0KZm9yIChpIGluIDE6bmNvbChzdGF0dXNfd29yaykpew0KICBzb2wgPSBncmVwbCgnSGFsZicsIG5hbWVzKHN0YXR1c193b3JrKVtpXSkNCiAgaWYgKHNvbD09MSl7DQogICAgaWYgKGdyZXBsKCdNJywgbmFtZXMoc3RhdHVzX3dvcmspW2ldKSl7DQogICAgICBuYW0uTVtpXSA9IGkgIA0KICAgIH1lbHNle25hbS5GW2ldPWl9DQogIH1lbHNlew0KICAgIG5hbS5GW2ldPTANCiAgICBuYW0uTVtpXT0wfQ0KfQ0KI25hbWVzKHN0YXR1c193b3JrW25hbS5NXSkNCiNuYW1lcyhzdGF0dXNfd29ya1tuYW0uRl0pDQpzdGF0dXNfd29yayRoYWxmX009cm93U3VtcyhzdGF0dXNfd29ya1ssbmFtLk1dKQ0Kc3RhdHVzX3dvcmskaGFsZl9GPXJvd1N1bXMoc3RhdHVzX3dvcmtbLG5hbS5GXSkNCg0KIyB0b3RhbCBvZiBlYWNoIHZhcmlhYmxlcw0Kc3RhdHVzX3dvcmskZnVsbCA8LSBzdGF0dXNfd29yayRmdWxsX00gKyBzdGF0dXNfd29yayRmdWxsX0YNCnN0YXR1c193b3JrJGhhbGYgPC0gc3RhdHVzX3dvcmskaGFsZl9NICsgc3RhdHVzX3dvcmskaGFsZl9GDQpzdGF0dXNfd29yayR3YWdlYXJuZXIgPC0gc3RhdHVzX3dvcmskd2FnZWFybmVyX00gKyBzdGF0dXNfd29yayR3YWdlYXJuZXJfRg0Kc3RhdHVzX3dvcmskaW5kZXBlbmRlbnQgPC0gc3RhdHVzX3dvcmskaW5kZXBlbmRlbnRfTSArIHN0YXR1c193b3JrJGluZGVwZW5kZW50X0YNCnN0YXR1c193b3JrJHRyYW5zZmVyIDwtIHN0YXR1c193b3JrJHRyYW5zZmVyX0YgKyBzdGF0dXNfd29yayR0cmFuc2Zlcl9NIA0Kc3RhdHVzX3dvcmskZW1wbG95ZXIgPC0gc3RhdHVzX3dvcmskZW1wbG95ZXJfRiArIHN0YXR1c193b3JrJGVtcGxveWVyX00gDQoNCiMgZHJvcCB1bm5lY2Vzc2FyeSB2YXJpYWJsZXMNCnN0YXR1c193b3JrIDwtIHN1YnNldChzdGF0dXNfd29yaywgc2VsZWN0ID0gYyhDT0RHRU8sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2FnZWFybmVyX00sIHdhZ2Vhcm5lcl9GLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmRlcGVuZGVudF9NLCBpbmRlcGVuZGVudF9GLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2Zlcl9NLCB0cmFuc2Zlcl9GLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbXBsb3llcl9NLCBlbXBsb3llcl9GLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdWxsX00sIGZ1bGxfRiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoYWxmX00sIGhhbGZfRiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdWxsLCBoYWxmLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdhZ2Vhcm5lciwgaW5kZXBlbmRlbnQsIHRyYW5zZmVyLCBlbXBsb3llcikpDQojIEZ1bGwgdmFyaWFibGUgbWVhbnMgaW5kaXZpZHVhbHMgd2l0aCBmdWxsIHRpbWUgY29udHJhY3RzLiBIYWxmIG1lYW5zIGluZGl2aWR1YWxzIHdpdGggcGFydCB0aW1lIGNvbnRyYWN0LiANCiMgInRyYW5zZmVyIiBpcyBpbmRpdmlkdWFscyByZWNlaXZpbmcgdHJhbnNmZXIgcGF5bWVudHMuIA0KIyAiaW5kZXBlbmRlbnQiIGlzIGxpa2UgYXV0by1lbnRyZXByZW5ldXJzLiANCg0KYGBgDQoNCg0KIyMgSW5lcXVhbGl0eSBkYXRhDQoNCkRyb3AgdW5uZWNlc3NhcnkgdmFyaWFibGVzIGFuZCByZW5hbWUgdGhlIG90aGVyIG9uZXMNCmBgYHtyIHByZS1wcm9jZXNzaW5nIGluZXF1YWxpdHkgZGF0YX0NCg0KbmFtZXMoaW5lcSkNCg0KIyBkcm9wIHVubmVjZXNzYXJ5IHZhcmlhYmxlcw0KaW5lcSA8LSBzdWJzZXQoaW5lcSwgc2VsZWN0ID0gLWMoTElCR0VPLCBQMDlfUE9QLCBOQUlTRDE2LCBERUNFU0QxNiwgUDE0X1JQX1BST1AsIFAwOV9FTVBMVCxFVFRPVDE1LCBFVEFaMTUsIEVUQkUxNSwgRVRGWjE1LCBFVEdVMTUsIEVUR1oxNSwgRVRPUTE1LCBFVFRFRjExNSwgRVRURUZQMTAxNSkpDQoNCiMgcmVuYW1lIHZhcmlhYmxlcyANCm5hbWVzKGluZXEpWzQ6bmNvbChpbmVxKV0gPC0NCiAgYygicG9wXzIwMTQiLA0KICAgICJTdXBlcmZpY2llIiwNCiAgICAiYmlydGgwOV8xNCIsDQogICAgImRlYXRoMDlfMTQiLA0KICAgICJob3VzZWhvbGRzMTQiLA0KICAgICJob3VzaW5nMTQiLA0KICAgICJwcmluY19yZXNpZDE0IiwNCiAgICAic2VjX3Jlc2lkMTQiLA0KICAgICJ2YWNfcmVzaWQxNCIsDQogICAgInRheF9ob3VzZTE0IiwNCiAgICAic2hhcmVkX3RheF9ob3VzZTE0IiwNCiAgICAibWVkaWFuX2xpdmluZzE0IiwNCiAgICAibGV2X2luZXExNCIsDQogICAgImVtcGwiLA0KICAgICJlbXBfc2FsIiwNCiAgICAicG9wMTVfNjQiLA0KICAgICJ1bmVtcDE1XzY0IiwNCiAgICAiYWN0MTVfNjQiKQ0KDQojIGRyb3AgbW9yZSB1bm5lY2Vzc2FyeSB2YXJpYWJsZXMgDQppbmVxIDwtIHN1YnNldChpbmVxLCBzZWxlY3QgPSAtYyhwcmluY19yZXNpZDE0LCBzZWNfcmVzaWQxNCwgdmFjX3Jlc2lkMTQsIHBvcF8yMDE0LCBob3VzZWhvbGRzMTQsIGJpcnRoMDlfMTQsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWF0aDA5XzE0LCB0YXhfaG91c2UxNCwgc2hhcmVkX3RheF9ob3VzZTE0LCBsZXZfaW5lcTE0KSkgDQogDQojIHVuZW1wbG95bWVudCByYXRlIA0KaW5lcSR1bmVtcF9yYXRlIDwtIGluZXEkdW5lbXAxNV82NC9pbmVxJHBvcDE1XzY0IA0KDQojIGltcHV0ZSBOQSB1c2luZyBtZWRpYW4gKG9ubHkgMykNCmluZXEkbWVkaWFuX2xpdmluZzE0W2lzLm5hKGluZXEkbWVkaWFuX2xpdmluZzE0KV0gPSBtZWRpYW4oaW5lcSRtZWRpYW5fbGl2aW5nMTQsIG5hLnJtID0gVCkNCg0KYGBgDQoNCg0KIyMgQ29tbXVuZSBkYXRhDQoNCkRyb3AgdW5uZWNlc3NhcnkgdmFyaWFibGVzIGFuZCByZW5hbWUgdGhlIG90aGVyIG9uZXMNCmBgYHtyIHByZS1wcm9jZXNzaW5nIGNvbW11bmUgZGF0YX0NCm5hbWVzKGNvbW11bmUpDQoNCiNEcm9wIHVubmVjZXNzYXJ5IHZhcmlhYmxlcw0KY29tbXVuZSA8LXN1YnNldChjb21tdW5lLCBzZWxlY3Q9LWMobGliZ2VvLCBzY29yZWZpc2NhbCwgZGVwLCByZWcsIGV2b2x1dGlvbnBvcCwgbmJwcm9wcml0YWlyZSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYmxvZ2VtZW50c2Vjb25kYWlyZWV0b2NjYXNpb25uZSwgc2NvcmV1cmJhbml0LCBzY29yZXZhcmdpb24sIHNjb3JlcGliLCAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYnJzaWRlbmNlc3ByaW5jaXBhbGVzLCBpbmRpY2VmaXNjYWxwYXJ0aWVsLCBuYm9jY3VwYW50c3JzaWRlbmNlcHJpbmNpcGFsZSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXBtb3llbm5lc2FsYWlyZXNob3JhaXJlcywgZGVwbW95ZW5uZXNhbGFpcmVzY2FkcmVob3JhaXJlcywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXBtb3llbm5lc2FsYWlyZXNwcm9maW50ZXJtZGlhaSwgZGVwbW95ZW5uZXNhbGFpcmVzZW1wbG95aG9yYWlyZXMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVwbW95ZW5uZXNhbGFpcmVzb3V2cmlob3JhaXJlcywgdmFsZXVyYWpvdXRlcmdpb25hbGUsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmJpbmR1c3RyaWVzZGVzYmllbnNpbnRlcm1kaWFpcmUsIG5iZGVjb21tZXJjZSwgbmJkZXNlcnZpY2VzYXV4cGFydGljdWxpZXJzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5iaW5zdGl0dXRpb25kZWVkdWNhdGlvbnNhbnRhY3RpLCBzY29yZXZhcmdpb24sIHNjb3JlcGliLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1veWVubmVyZXZlbnVzZmlzY2F1eGRwYXJ0ZW1lbnRhLCBtb3llbm5lcmV2ZW51c2Zpc2NhdXhyZ2lvbmF1eCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWdtb3llbm5lc2FsYWlyZXNob3JhaXJlcywgcmVnbW95ZW5uZXNhbGFpcmVzY2FkcmVob3JhaXJlcywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWdtb3llbm5lc2FsYWlyZXNwcm9maW50ZXJtZGlhaSwgcmVnbW95ZW5uZXNhbGFpcmVzZW1wbG95aG9yYWlyZXMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVnbW95ZW5uZXNhbGFpcmVzb3V2cmlob3JhaXJlcywgdGF1eHR1ZGlhbnRzLCBkeW5hbWlxdWVkbW9ncmFwaGlxdWVpbnNlZSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXBhY2l0ZmlzYywgY2FwYWNpdGZpc2NhbGUsIG1veWVubmVyZXZudXNmaXNjYXV4LCBuYmxvZ2VtZW50LCBmaWRsaXQpKSANCg0KDQojIHJlbmFtZSB2YXJpYWJsZXMgIA0KbmFtZXMoY29tbXVuZSkgPC1jKCJDT0RHRU8iLCAib3JpZW50X2Vjb24iLCAiZGVtb19pbmRleCIsICJwb3B1bGF0aW9uIiwgIm5iX2hvdXNlaG9sZCIsIA0KICAgICAgICAgICAgICAgICAgICAibmJfZmVtYWxlIiwgIm5iX21hbGUiLCAibmJfbWlub3IiLCAibmJfbWFqb3IiLCAibmJfc3R1ZGVudHMiLCAgDQogICAgICAgICAgICAgICAgICAgICJuYl9maXJtc19zZXJ2aWNlIiwgIm5iX2Zpcm1zX2NvbW1lcmNlIiwgIm5iX2Zpcm1zX2NvbnN0cnVjdGlvbiIsIA0KICAgICAgICAgICAgICAgICAgICAibmJfZmlybXNfaW5kIiwgIm5iX2NyZWF0ZWRfZmlybXMiLCAibmJfY3JlYXRlZF9pbmQiLCANCiAgICAgICAgICAgICAgICAgICAgIm5iX2NyZWF0ZWRfY29uc3RydWN0aW9uIiwgIm5iX2NyZWF0ZWRfY29tbWVyY2UiLA0KICAgICAgICAgICAgICAgICAgICAibmJfY3JlYXRlZF9zZXJ2aWNlcyIsICJ1cmJhblJ1cmFsIiwgIm5iX2FjdGl2ZSIsICJuYl9hY3RpdmVfZW1wbG95ZWVzIiwNCiAgICAgICAgICAgICAgICAgICAgIm5iX2FjdGl2ZV9ub25fZW1wbG95ZWVzIiwgImR5bWFuaWNfZGVtb19wcm9mIiwgInByb2ZpdFJhdGUiLCANCiAgICAgICAgICAgICAgICAgICAgInJlZ2lvbmFsX0dEUCIsICJkZW1vX2Vudmlyb25tZW50IiwgImV2b2xfcG9wX3Njb3JlIiwgDQogICAgICAgICAgICAgICAgICAgICJldm9sX2VudHJlcHJlbmV1cmlhbF9zY29yZSIsICJkZW1vX2VudmlyMiIpIA0KDQojIGRyb3AgbW9yZSB2YXJpYWJsZXMgDQpjb21tdW5lIDwtc3Vic2V0KGNvbW11bmUsIHNlbGVjdD0tYyhkZW1vX2luZGV4LCBwb3B1bGF0aW9uLCBwcm9maXRSYXRlLCBkZW1vX2VudmlyMiwgZGVtb19lbnZpcm9ubWVudCkpIA0KDQpgYGANCg0KDQojIFByb2R1Y2UgY29uc2lzdGVudCBkYXRhc2V0cw0KDQpUaGUgQ09ER0VPIHZhcmlhYmxlcyBoYXZlIHRvIGJlIG1lcmdlZC4NCkhvd2V2ZXIsIGZvciBkaWZmZXJlbnQgcmVhc29ucyBhbHJlYWR5IGlkZW50aWZpZWQgYnkgb3RoZXIga2FnZ2xlIHVzZXJzIHRoZXkgbmVlZCBzb21lIHByZS1wcm9jZXNzaW5nLg0KVG8gZG8gc28sIHNvbWUgYWxyZWFkeSBrbm93biBtaXN0YWtlcyBhcmUgY29ycmVjdGVkOg0KDQpgYGB7ciBmaXggYW5kIG1hdGNoIENPREdFT30NCg0KZmlybXMkQ09ER0VPICAgICAgIDwtIHN1YigiQSIsICIwIiwgZmlybXMkQ09ER0VPKQ0KZmlybXMkQ09ER0VPICAgICAgIDwtIHN1YigiQiIsICIwIiwgZmlybXMkQ09ER0VPKQ0Kc2FsYXJ5JENPREdFTyAgICAgIDwtIHN1YigiQSIsICIwIiwgc2FsYXJ5JENPREdFTykNCnNhbGFyeSRDT0RHRU8gICAgICA8LSBzdWIoIkIiLCAiMCIsIHNhbGFyeSRDT0RHRU8pDQpwb3B1bGF0aW9uJENPREdFTyAgPC0gc3ViKCJBIiwgIjAiLCBwb3B1bGF0aW9uJENPREdFTykNCnBvcHVsYXRpb24kQ09ER0VPICA8LSBzdWIoIkIiLCAiMCIsIHBvcHVsYXRpb24kQ09ER0VPKQ0KZ2VvJENPREdFTyAgICAgICAgIDwtIHN1YigiQSIsICIwIiwgZ2VvJENPREdFTykNCmdlbyRDT0RHRU8gICAgICAgICA8LSBzdWIoIkIiLCAiMCIsIGdlbyRDT0RHRU8pDQplZHVjJENPREdFTyAgICAgICAgPC0gc3ViKCJBIiwgIjAiLCBlZHVjJENPREdFTykNCmVkdWMkQ09ER0VPICAgICAgICA8LSBzdWIoIkIiLCAiMCIsIGVkdWMkQ09ER0VPKQ0KY2F0ZWdfc29jaW8kQ09ER0VPIDwtIHN1YigiQSIsICIwIiwgY2F0ZWdfc29jaW8kQ09ER0VPKQ0KY2F0ZWdfc29jaW8kQ09ER0VPIDwtIHN1YigiQiIsICIwIiwgY2F0ZWdfc29jaW8kQ09ER0VPKQ0KaW5lcSRDT0RHRU8gICAgICAgIDwtIHN1YigiQSIsICIwIiwgaW5lcSRDT0RHRU8pDQppbmVxJENPREdFTyAgICAgICAgPC0gc3ViKCJCIiwgIjAiLCBpbmVxJENPREdFTykNCnN0YXR1c193b3JrJENPREdFTyA8LSBzdWIoIkEiLCAiMCIsIHN0YXR1c193b3JrJENPREdFTykNCnN0YXR1c193b3JrJENPREdFTyA8LSBzdWIoIkIiLCAiMCIsIHN0YXR1c193b3JrJENPREdFTykNCmNvbW11bmUkQ09ER0VPICAgICA8LSBzdWIoIkEiLCAiMCIsIGNvbW11bmUkQ09ER0VPKQ0KY29tbXVuZSRDT0RHRU8gICAgIDwtIHN1YigiQiIsICIwIiwgY29tbXVuZSRDT0RHRU8pDQoNCiMgVGhlbiBhbGwgQ09ER0VPIGFyZSB0cmFzZm9ybWVkIHRvIGludGVnZXJzIGFuZCBmb3VyIG5ldyBkYXRhc2V0cyBhcmUgY3JlYXRlZCByZXRhaW5pbmcgb25seSB0aGUgY29tbW9uIENPREdFTzoNCiMgdXNlIG9ubHkgaW50ZWdlciB2YWx1ZXMNCmdlbyRDT0RHRU8gICAgICAgICA8LSBhcy5pbnRlZ2VyKGdlbyRDT0RHRU8pICANCnBvcHVsYXRpb24kQ09ER0VPICA8LSBhcy5pbnRlZ2VyKHBvcHVsYXRpb24kQ09ER0VPKQ0KZmlybXMkQ09ER0VPICAgICAgIDwtIGFzLmludGVnZXIoZmlybXMkQ09ER0VPKQ0Kc2FsYXJ5JENPREdFTyAgICAgIDwtIGFzLmludGVnZXIoc2FsYXJ5JENPREdFTykNCnN0YXR1c193b3JrJENPREdFTyA8LSBhcy5pbnRlZ2VyKHN0YXR1c193b3JrJENPREdFTykgIA0KaW5lcSRDT0RHRU8gICAgICAgIDwtIGFzLmludGVnZXIoaW5lcSRDT0RHRU8pDQplZHVjJENPREdFTyAgICAgICAgPC0gYXMuaW50ZWdlcihlZHVjJENPREdFTykNCmNhdGVnX3NvY2lvJENPREdFTyA8LSBhcy5pbnRlZ2VyKGNhdGVnX3NvY2lvJENPREdFTykNCmNvbW11bmUkQ09ER0VPICAgICA8LSBhcy5pbnRlZ2VyKGNvbW11bmUkQ09ER0VPKQ0KDQojIHN0b3JlIGRhdGFzZXRzJyBuYW1lcyB0byBsb29wIG9uIHRoZW0NCmRhdGFzZXQgPSBjKCJwb3B1bGF0aW9uIiwgInNhbGFyeSIsICJmaXJtcyIsICJnZW8iLCAiaW5lcSIsICJjb21tdW5lIiwgImVkdWMiLCAiY2F0ZWdfc29jaW8iLCAic3RhdHVzX3dvcmsiKQ0KDQojIG9idGFpbiBzb21tb24gSURzIGZvciBhbGwgZGF0YXNldHMNCmZvciAoaSBpbiBkYXRhc2V0KXsNCiAgIyBnZXQgaS10aCBuYW1lIGFuZCBjcmVhdGUgYSBuZXcgdmFyaWFibGUgY29uY2F0ZW5ldGluZyAiTkVXIiBhdCB0aGUgZW5kDQogIG5hbSA8LSBwYXN0ZShpLCAiTkVXIiwgc2VwID0gIiIpDQogICMgaW5pdGlhbGl6ZSBjb3VudGVyIHRvIGlkZW50aWZ5IHRoZSBudW1iZXIgb2YgaXRlcmF0aW9uIGluIGoNCiAgaXRlciA9IDENCiAgZm9yIChqIGluIGRhdGFzZXQpew0KICAgIGlmIChqICE9IGkpew0KICAgICAgIyBmb3IgZWFjaCBkYXRhc2V0IGRpZmZlcmVudCBmcm9tIHRoZSBpLXRoDQogICAgICBpZiAoaXRlciA9PSAxKXsNCiAgICAgICAgIyAxc3QgaXRlcmF0aW9uOiB1c2UgdGhlIG9yaWdpbmFsIGRhdGFzZXQgKGUuZy4sIGdlbykNCiAgICAgICAgYXNzaWduKG5hbSwgc2VtaV9qb2luKGdldChpKSwgZ2V0KGopLCBieSA9ICJDT0RHRU8iKSkNCiAgICAgIH0gZWxzZXsNCiAgICAgICAgIyBzdWNjZXNzaXZlIGl0ZXJhdGlvbjogdXNlIHRoZSBuZXcgZGF0YXNldCAoZS5nLiwgZ2VvTkVXKQ0KICAgICAgICBhc3NpZ24obmFtLCBzZW1pX2pvaW4oZ2V0KG5hbSksIGdldChqKSwgYnkgPSAiQ09ER0VPIikpDQogICAgICB9DQogICAgICBpdGVyID0gaXRlciArIDENCiAgICB9DQogIH0NCn0NCg0KIyBjaGVjayBob3cgbWFueSBvYnNlcnZhdGlvbiBoYXZlIGJlZW4gZGVsZXRlZA0KZm9yIChpIGluIGRhdGFzZXQpew0KICBkZWxfcm93cyA9IG5yb3coZ2V0KGkpKSAtIG5yb3coZ2V0KHBhc3RlKGksICJORVciLCBzZXAgPSAiIikpKQ0KICBkZWxfcHJvcCA9IGRlbF9yb3dzIC8gbnJvdyhnZXQoaSkpDQogIGRlbF9vYnMgPSBwYXN0ZSgiRm9yIiwgaSwgZGVsX3Jvd3MsICJ1bml0cyBoYXZlIGJlZW4gZGVsZXRlZC4iLA0KICAgICAgICAgICAgICAgICAgIlRoZXkgd2VyZSB0aGUiLCByb3VuZChkZWxfcHJvcCoxMDAsIGRpZ2l0cz0yKSwgIiUgb2YgdGhlIHRvdGFsLiIsIHNlcCA9ICIgIikNCiAgcHJpbnQocGFzdGUoZGVsX29icykpDQp9DQoNCnByaW50KHBhc3RlKCJUaGUgbmV3IGRhdGFzZXQgaGFzIiwgbnJvdyhzYWxhcnlORVcpLCAidW5pdHMgYW5kIiwgDQogICAgICBuY29sKHNhbGFyeU5FVykrbmNvbChwb3B1bGF0aW9uTkVXKStuY29sKGZpcm1zTkVXKStuY29sKGdlb05FVykrDQogICAgICAgIG5jb2woc3RhdHVzX3dvcmtORVcpK25jb2woaW5lcU5FVykrbmNvbChlZHVjTkVXKStuY29sKGNhdGVnX3NvY2lvTkVXKStuY29sKGNvbW11bmVORVcpLCAiZmVhdHVyZXMuIikpDQoNCmBgYA0KDQpPdmVyd3JpdGUgbmV3IGRhdGVzZXRzIGludG8gdGhlIG9sZCBvbmVzIGFuZCByZW1vdmUgdGhlIGxhdHRlciBvbmVzIGZyb20gbWVtb3J5DQpgYGB7ciB0YWtlIHVuaXF1ZSBkYXRhc2V0c30NCg0KZmlybXMgICAgICAgPC0gZmlybXNORVcNCmdlbyAgICAgICAgIDwtIGdlb05FVw0Kc2FsYXJ5ICAgICAgPC0gc2FsYXJ5TkVXDQpwb3B1bGF0aW9uICA8LSBwb3B1bGF0aW9uTkVXDQplZHVjICAgICAgICA8LSBlZHVjTkVXDQpjYXRlZ19zb2NpbyA8LSBjYXRlZ19zb2Npb05FVw0Kc3RhdHVzX3dvcmsgPC0gc3RhdHVzX3dvcmtORVcNCmluZXEgICAgICAgIDwtIGluZXFORVcNCmNvbW11bmUgICAgIDwtIGNvbW11bmVORVcNCg0Kcm0obGlzdD1jKCJmaXJtc05FVyIsICJnZW9ORVciLCAic2FsYXJ5TkVXIiwgInBvcHVsYXRpb25ORVciLCAiZWR1Y05FVyIsICJjYXRlZ19zb2Npb05FVyIsICJzdGF0dXNfd29ya05FVyIsICJpbmVxTkVXIiwgImNvbW11bmVORVciKSkNCg0KYGBgDQoNCg0KIyBEZXNjcmlwdGl2ZSBzdGF0aXN0aWNzIA0KDQojIyBGaXJtcyBkYXRhDQoNCkNoZWNrIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIG51bGwgZmlybXMgKGkuZS4sIHVua25vd24gc2l6ZXMpIGFuZCBhbmFseXplDQpmaXJtcycgZGlzdHJpYnV0aW9uIHBlciB0b3duOg0KYGBge3IgZmlybXMgZGlzdHJpYnV0aW9ufQ0KDQojIGNoZWNrIHRoZSByYXRpbyBvZiBudWxsIGZpcm1zIGZvciBlYWNoIHRvd24NCnN1bW1hcnkoZmlybXMkbnVsbC9maXJtcyR0b3RhbCkNCiMgYSBsb3Qgb2YgaW5mb3JtYXRpb24gaXMgbWlzc2luZywgc2hvdWxkIHdlIHJlbW92ZSB0aGVzZSBkYXRhPw0KZ2dwbG90KGRhdGE9ZmlybXMsIGFlcyhmaXJtcyRudWxsL2Zpcm1zJHRvdGFsKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9Li5kZW5zaXR5Li4pLCBjb2w9ImJsYWNrIiwgZmlsbD0iYmx1ZSIsIGFscGhhID0gLjMsIGJpbnMgPSA1MCkgKw0KICBnZW9tX2RlbnNpdHkoY29sPSJibGFjayIpICsNCiAgbGFicyh4PSJOdWxsIGZpcm1zL3RvdGFsIGZpcm1zIiwgeT0iQ291bnQiKSArDQogIGdndGl0bGUoIlJhdGlvIGJldHdlZW4gdGhlIG51bWJlciBvZiBudWxsIGZpcm1zIGFuZCB0b3RhbCBmaXJtcyBwZXIgdG93biIpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpIA0KDQojIGRpc3RyaWJ1dGlvbiBmb3IgdGhlIGZpcm1zIHdpdGggdW5rbm93biBzaXplIA0KZ2dwbG90KGRhdGE9ZmlybXMsIGFlcyhsb2coZmlybXMkbnVsbCkpKSArDQogIGdlb21faGlzdG9ncmFtKGFlcyh5ID0uLmRlbnNpdHkuLiksIGNvbD0iYmxhY2siLCBmaWxsPSJibHVlIiwgYWxwaGEgPSAuMywgYmlucyA9IDUwKSArDQogIGdlb21fZGVuc2l0eShjb2w9ImJsYWNrIikgKw0KICBsYWJzKHg9Ik51bWJlciBvZiBmaXJtcyBvZiB1bmtub3duIHNpemUgKGxvZyBzY2FsZSkiLCB5PSJEZW5zaXR5IikgKw0KICBnZ3RpdGxlKCJOdW1iZXIgb2YgZmlybXMgb2YgdW5rbm93biBzaXplIHBlciB0b3duIikgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkNCg0KIyBkaXN0cmlidXRpb24gZm9yIHRoZSB0b3RhbCBudW1iZXIgb2YgZmlybXMgDQpnZ3Bsb3QoZGF0YT1maXJtcywgYWVzKGxvZyhmaXJtcyR0b3RhbCkpKSArDQogIGdlb21faGlzdG9ncmFtKGFlcyh5ID0uLmRlbnNpdHkuLiksIGNvbD0iYmxhY2siLCBmaWxsPSJibHVlIiwgYWxwaGEgPSAuMywgYmlucyA9IDUwKSArDQogIGdlb21fZGVuc2l0eShjb2w9ImJsYWNrIikgKw0KICBsYWJzKHg9Ik51bWJlciBvZiBmaXJtcyAobG9nIHNjYWxlKSIsIHk9IkRlbnNpdHkiKSArDQogIGdndGl0bGUoIlRvdGFsIG51bWJlciBvZiBmaXJtcyBwZXIgdG93biIpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpIA0KDQojIGRpc3RyaWJ1dGlvbiBmb3IgdGhlIG51bWJlciBvZiBtaWNybyBzaXplIGZpcm1zIA0KZ2dwbG90KGRhdGE9ZmlybXMsIGFlcyhsb2coZmlybXMkbWljcm8pKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9Li5kZW5zaXR5Li4pLCBjb2w9ImJsYWNrIiwgZmlsbD0iYmx1ZSIsIGFscGhhID0gLjMsIGJpbnMgPSA1MCkgKw0KICBnZW9tX2RlbnNpdHkoY29sPSJibGFjayIpICsNCiAgbGFicyh4PSJOdW1iZXIgb2YgZmlybXMgb2YgbWljcm8gc2l6ZSAobG9nIHNjYWxlKSIsIHk9IkRlbnNpdHkiKSArDQogIGdndGl0bGUoIk51bWJlciBvZiBmaXJtcyBvZiBtaWNybyBzaXplIHBlciB0b3duIikgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkNCg0KIyBkaXN0cmlidXRpb24gZm9yIHRoZSBudW1iZXIgb2Ygc21hbGwgc2l6ZSBmaXJtcyANCmdncGxvdChkYXRhPWZpcm1zLCBhZXMobG9nKGZpcm1zJHNtYWxsKSkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPS4uZGVuc2l0eS4uKSwgY29sPSJibGFjayIsIGZpbGw9ImJsdWUiLCBhbHBoYSA9IC4zLCBiaW5zID0gNTApICsNCiAgZ2VvbV9kZW5zaXR5KGNvbD0iYmxhY2siKSArDQogIGxhYnMoeD0iTnVtYmVyIG9mIGZpcm1zIG9mIHNtYWxsIHNpemUgKGxvZyBzY2FsZSkiLCB5PSJEZW5zaXR5IikgKw0KICBnZ3RpdGxlKCJOdW1iZXIgb2YgZmlybXMgb2Ygc21hbGwgc2l6ZSBwZXIgdG93biIpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpDQoNCiMgZGlzdHJpYnV0aW9uIGZvciB0aGUgbnVtYmVyIG9mIG1lZGl1bSBzaXplIGZpcm1zIA0KZ2dwbG90KGRhdGE9ZmlybXMsIGFlcyhsb2coZmlybXMkbWVkaXVtKSkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPS4uZGVuc2l0eS4uKSwgY29sPSJibGFjayIsIGZpbGw9ImJsdWUiLCBhbHBoYSA9IC4zLCBiaW5zID0gNTApICsNCiAgZ2VvbV9kZW5zaXR5KGNvbD0iYmxhY2siKSArDQogIGxhYnMoeD0iTnVtYmVyIG9mIGZpcm1zIG9mIG1lZGl1bSBzaXplIChsb2cgc2NhbGUpIiwgeT0iRGVuc2l0eSIpICsNCiAgZ2d0aXRsZSgiTnVtYmVyIG9mIGZpcm1zIG9mIG1lZGl1bSBzaXplIHBlciB0b3duIikgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkNCg0KIyBkaXN0cmlidXRpb24gZm9yIHRoZSBudW1iZXIgb2YgbGFyZ2Ugc2l6ZSBmaXJtcyANCmdncGxvdChkYXRhPWZpcm1zLCBhZXMobG9nKGZpcm1zJGxhcmdlKSkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPS4uZGVuc2l0eS4uKSwgY29sPSJibGFjayIsIGZpbGw9ImJsdWUiLCBhbHBoYSA9IC4zLCBiaW5zID0gNTApICsNCiAgZ2VvbV9kZW5zaXR5KGNvbD0iYmxhY2siKSArDQogIGxhYnMoeD0iTnVtYmVyIG9mIGZpcm1zIG9mIGxhcmdlIHNpemUgKGxvZyBzY2FsZSkiLCB5PSJEZW5zaXR5IikgKw0KICBnZ3RpdGxlKCJOdW1iZXIgb2YgZmlybXMgb2YgbGFyZ2Ugc2l6ZSBwZXIgdG93biIpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpDQoNCmBgYA0KDQpDaGVjayBjb3JyZWxhdGlvbiBhbW9uZyB0aGUgdmFyaWFibGVzOg0KYGBge3IgZmlybXMgY29ycmVsYXRpb259DQpjb3JycGxvdChjb3IoZmlybXNbLDM6OF0pKQ0KYGBgDQoNCg0KIyMjIFdoYXQgaGF2ZSBsZWFybmVkDQoNClNvbHZlZCBwcm9ibGVtczogDQoNCiogVXNlIHRoZSBFVSBmaXJtcycgY2F0ZWdvcml6YXRpb24uDQoNClNvbWUgcHJvYmxlbWF0aWMgYXNwZWN0czoNCg0KKiBTb21lIHRvd25zIGhhdmUgMTAwJSBvZiBudWxsIGZpcm1zLCBzaG91bGQgd2UgcmVtb3ZlIHRoZXNlIGRhdGE/DQoqIFRoZXNlIHZhcmlhYmxlcyBhcmUgc3Ryb25nbHkgY29ycmVsYXRlZCwgc2hvdWxkIHdlIHVzZSBqdXN0IHRoZSB0b3RhbCBhbW91bnQgaW4gdGhlIGZvbGxvd2luZyBwYXJ0cz8NCg0KV2UgY291bGQgdXNlIHRoZXNlIGRhdGEgZm9yIHRoZSBmb2xsb3dpbmcgdGFza3M6DQoNCiogcHJlZGljdCB0aGUgc2FsYXJpZXMgdXNpbmcgc3VjaCBpbmZvcm1hdGlvbiBhcyBwcm94eSBmb3IgdGhlIGNvbXBldGl0aW9uIGluIHRoZSBqb2IgbWFya2V0Ow0KKiBwcmVkaWN0IHRoZSB0b3RhbCBudW1iZXIgb2YgZmlybXMsIHVzaW5nIHNhbGFyeSBkYXRhOw0KKiBnZW8tc3BhdGlhbCBwbG90IGZvciBmaXJtcycgc2l6ZSANCg0KDQoNCiMjIEdlb2dyYXBoaWMgZGF0YQ0KDQpQbG90IGF2YWlsYWJsZSB0b3ducyBvbiBhIG1hcDoNCmBgYHtyIGdlbyBtYXB9DQoNCiMgY2VudGVyIG9mIEZyYW5jZSwgb2J0YWluZWQgdXNpbmc6DQojIGZyYV9jZW50ZXIgPSBhcy5udW1lcmljKGdlb2NvZGUoIkZyYW5jZSIpKQ0KZnJhX2NlbnRlciA9IGMoMi4yMTM3NDksIDQ2LjIyNzYzOCkNCiMgcGxvdCBhbGwgRXVyb3BlYW4gdG93bnMgYXZhaWxhYmxlDQpnZW9fcG9zID0gYXMuZGF0YS5mcmFtZShjYmluZChsb24gPSBnZW8kbG9uZ2l0dWRlLCBsYXQgPSBnZW8kbGF0aXR1ZGUpKQ0KZ2VvX3BvcyA9IGdlb19wb3NbY29tcGxldGUuY2FzZXMoZ2VvX3BvcyksXQ0KZ2dtYXAoZ2V0X2dvb2dsZW1hcChjZW50ZXI9ZnJhX2NlbnRlciwgc2NhbGU9Miwgem9vbT01KSwgZXh0ZW50PSJub3JtYWwiKSArDQogIGdlb21fcG9pbnQoYWVzKHg9bG9uLCB5PWxhdCksIGRhdGE9Z2VvX3BvcywgY29sPSJvcmFuZ2UiLCBhbHBoYT0wLjIsIHNpemU9MC4wMSkgDQoNCiMgVHJ5IHRvIGNsbCBnb29nbGUgQVBJIHVudGlsIHRoZXJlIGlzIG5vIGVycm9yDQojIA0KIyBGcmFNYXAgPSBOQQ0KIyB3aGlsZSAoYW55KGlzLm5hKEZyYU1hcCkpKXsNCiMgICBGcmFNYXAgPSB0cnlDYXRjaCh7DQojICAgICAgIGdnbWFwKGdldF9nb29nbGVtYXAoY2VudGVyPWZyYV9jZW50ZXIsIHNjYWxlPTIsIHpvb209NSksIGV4dGVudD0ibm9ybWFsIikNCiMgICB9LCBlcnJvciA9IGZ1bmN0aW9uKGUpIHsNCiMgICAgIG1lc3NhZ2UoImNhbm5vdCBvcGVuIFVSTCIpICANCiMgICAgIEZyYU1hcCA9IE5BDQojICAgfSkNCiMgfQ0KDQpgYGANCg0KIyMjIFdoYXQgd2UgaGF2ZSBsZWFybmVkIA0KDQpTb2x2ZWQgcHJvYmxlbXM6IA0KDQoqIE1pc3NpbmcgbGF0aXR1ZGUgYW5kIGxvbmdpdHVkZTsNCiogRHVwbGljYXRpb25zIGR1ZSB0byBtdWx0aXBsZSBwb3N0YWwgY29kZXMgaW4gdGhlIHNhbWUgdG93bjsNCiogRXhjbHVkZSBub24tRXVyb3BlYW4gdG93bnM7DQoNClRoZXNlIGluZm9ybWF0aW9uIGFyZSB1c2VmdWwgdG8gcGxvdCBhbnkgZnV0dXJlIGRhdGFzZXQvYW5hbHlzaXMuDQpJbiBhZGRpdGlvbiwgdGhleSBjb3VsZCBiZSB1c2VmdWwgdG8gY29tcGFyZSBFdXJvcGVhbiB0b3ducyB2cy4gb2xkIGNvbG9uaWVzLg0KDQoNCiMjIFNhbGFyeSBkYXRhIA0KDQpVbml2YXJpYXRlIGFuYWx5c2lzIGNvbXBhcmluZyBzYWxhcmllcyBmb3IgYm90aCBnZW5kZXJzIGFtb25nIHZhcmlvdXMgam9iIGNhdGVnb3JpZXM6DQoNCmBgYHtyIGJveHBsb3RzIHdvcmtzfQ0KDQojICBudW1iZXIgb2YgdW5pdHMNCm5fc2V4IDwtIGxlbmd0aChzYWxhcnkkc2FsX0ZlbWFsZXMpDQojIHZlY3RvciByZXByZXNlbnRpbmcgbWFsZXMgYW5kIGZlbWFsZXMNCkxhYmVsIDwtIGMocmVwKCJNIiwgbl9zZXgqNSksIHJlcCgiRiIsIG5fc2V4KjUpKQ0KIyB2ZWN0b3IgcmVwcmVzZW50aW5nIHRoZSB2YXJpYWJsZSBjb25zaWRlcmVkDQpWYXJpYWJsZSA8LSBjKHJlcCgiR2VuZXJhbCIsIG5fc2V4KSwgDQogICAgICAgICAgICAgcmVwKCJFeGVjdXRpdmUiLCBuX3NleCksDQogICAgICAgICAgICAgcmVwKCJNaWRNYW5hZ2VyIiwgbl9zZXgpLA0KICAgICAgICAgICAgIHJlcCgiRW1wbG95ZWUiLCBuX3NleCksDQogICAgICAgICAgICAgcmVwKCJXb3JrZXIiLG5fc2V4KSwNCiAgICAgICAgICAgICByZXAoIkdlbmVyYWwiLCBuX3NleCksIA0KICAgICAgICAgICAgIHJlcCgiRXhlY3V0aXZlIiwgbl9zZXgpLA0KICAgICAgICAgICAgIHJlcCgiTWlkTWFuYWdlciIsIG5fc2V4KSwNCiAgICAgICAgICAgICByZXAoIkVtcGxveWVlIiwgbl9zZXgpLA0KICAgICAgICAgICAgIHJlcCgiV29ya2VyIixuX3NleCkpDQojIG1lcmdlIHRoZXNlIGRhdGENCnNhbF9zZXggPSBjYmluZC5kYXRhLmZyYW1lKExhYmVsID0gTGFiZWwsIA0KICAgICAgICAgICAgIHZhbHVlID0gYyhzYWxhcnkkc2FsX01hbGVzLCBzYWxhcnkkc2FsX01fZXhlY3V0aXZlLCBzYWxhcnkkc2FsX01fbWlkTWFuYWdlciwgc2FsYXJ5JHNhbF9NX2VtcGxveWVlLCBzYWxhcnkkc2FsX01fd29ya2VyLA0KICAgICAgICAgICAgICAgICAgICAgICBzYWxhcnkkc2FsX0ZlbWFsZXMsIHNhbGFyeSRzYWxfRl9leGVjdXRpdmUsIHNhbGFyeSRzYWxfRl9taWRNYW5hZ2VyLCBzYWxhcnkkc2FsX0ZfZW1wbG95ZWUsIHNhbGFyeSRzYWxfRl93b3JrZXIpLA0KICAgICAgICAgICAgIFZhcmlhYmxlID0gVmFyaWFibGUpDQojIHBsb3R0aW5nIHBoYXNlDQpnZ3Bsb3QoZGF0YSA9IHNhbF9zZXgsIGFlcyh4PUxhYmVsLCB5PXZhbHVlKSkgKw0KICBnZW9tX2JveHBsb3QoYWVzKGZpbGwgPSBMYWJlbCkpICsNCiAgIyBub3QgY29sb3IgcG9pbnRzIHJlcGxhY2luZyBjb2xvdXIgPSBncm91cCBpbnN0ZWFkIG9mIGNvbG91cj1MYWJlbA0KICBnZW9tX3BvaW50KGFlcyh5PXZhbHVlLCBjb2xvdXI9TGFiZWwpLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoPTAuNzUpKSArDQogIGZhY2V0X3dyYXAoIH4gVmFyaWFibGUsIHNjYWxlcz0iZnJlZSIpICsNCiAgeGxhYigiU2V4IikgKyB5bGFiKCJNZWFuIG5ldCBzYWxhcnkgcGVyIGhvdXIiKSArIGdndGl0bGUoIkdlbmRlciBjb21wYXJpc29uIGZvciBkaWZmZXJlbnQgam9iIHBvc2l0aW9ucyIpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsgICAgICBzdGF0X2JveHBsb3QoZ2VvbSA9ICJlcnJvcmJhciIsIHdpZHRoID0gMC41KQ0KICAjICsgZ3VpZGVzKGZpbGw9Z3VpZGVfbGVnZW5kKHRpdGxlPSJMZWdlbmQiKSkNCg0KIyB0aGUgc2FtZSBidXQgZXhjbHVkaW5nIG91dGxpZXJzDQpnZ3Bsb3QoZGF0YSA9IHNhbF9zZXgsIGFlcyh4PUxhYmVsLCB5PXZhbHVlKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gcXVhbnRpbGUoc2FsX3NleCR2YWx1ZSwgYygwLCAwLjkpKSkgKw0KICBnZW9tX2JveHBsb3QoYWVzKGZpbGwgPSBMYWJlbCkpICsNCiAgZ2VvbV9wb2ludChhZXMoeT12YWx1ZSwgY29sb3VyPUxhYmVsKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aD0wLjc1KSkgKw0KICBmYWNldF93cmFwKCB+IFZhcmlhYmxlLCBzY2FsZXM9ImZyZWUiKSArDQogIHhsYWIoIlNleCIpICsgeWxhYigiTWVhbiBuZXQgc2FsYXJ5IHBlciBob3VyIikgKyANCiAgZ2d0aXRsZSgiR2VuZGVyIGNvbXBhcmlzb24gZm9yIGRpZmZlcmVudCBqb2IgcG9zaXRpb25zIGV4Y2x1ZGluZyB0aGUgbGFzdCBkZWNpbGUiKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSArDQogIHN0YXRfYm94cGxvdChnZW9tID0gImVycm9yYmFyIiwgd2lkdGggPSAwLjUpDQoNCmBgYA0KDQoNClVuaXZhcmlhdGUgYW5hbHlzaXMgY29tcGFyaW5nIHNhbGFyaWVzIGZvciBib3RoIGdlbmRlcnMgYW1vbmcgdmFyaW91cyBhZ2VzOg0KDQpgYGB7ciBib3hwbG90cyBhZ2VzfQ0KDQojIHZlY3RvciByZXByZXNlbnRpbmcgbWFsZXMgYW5kIGZlbWFsZXMNCkxhYmVsIDwtIGMocmVwKCJNIiwgbl9zZXgqMyksIHJlcCgiRiIsIG5fc2V4KjMpKQ0KIyB2ZWN0b3IgcmVwcmVzZW50aW5nIHRoZSB2YXJpYWJsZSBjb25zaWRlcmVkDQpWYXJpYWJsZSA8LSBjKHJlcCgiMTgtMjUiLCBuX3NleCksIA0KICAgICAgICAgICAgICByZXAoIjI2LTUwIiwgbl9zZXgpLA0KICAgICAgICAgICAgICByZXAoIjUxKyIsIG5fc2V4KSwNCiAgICAgICAgICAgICAgcmVwKCIxOC0yNSIsIG5fc2V4KSwgDQogICAgICAgICAgICAgIHJlcCgiMjYtNTAiLCBuX3NleCksDQogICAgICAgICAgICAgIHJlcCgiNTErIiwgbl9zZXgpKQ0KIyBtZXJnZSB0aGVzZSBkYXRhDQpzYWxfc2V4IDwtIGNiaW5kLmRhdGEuZnJhbWUoTGFiZWwgPSBMYWJlbCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9IGMoc2FsYXJ5JHNhbF9NXzE4XzI1LCBzYWxhcnkkc2FsX01fMjZfNTAsIHNhbGFyeSRzYWxfTV81MXBsdXMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhbGFyeSRzYWxfRl8xOF8yNSwgc2FsYXJ5JHNhbF9GXzI2XzUwLCBzYWxhcnkkc2FsX0ZfNTFwbHVzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZhcmlhYmxlID0gVmFyaWFibGUpDQojIHBsb3R0aW5nIHBoYXNlDQpnZ3Bsb3QoZGF0YSA9IHNhbF9zZXgsIGFlcyh4PUxhYmVsLCB5PXZhbHVlKSkgKw0KICBnZW9tX2JveHBsb3QoYWVzKGZpbGwgPSBMYWJlbCkpICsNCiAgZ2VvbV9wb2ludChhZXMoeT12YWx1ZSwgY29sb3VyPUxhYmVsKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aD0wLjc1KSkgKw0KICBmYWNldF93cmFwKCB+IFZhcmlhYmxlLCBzY2FsZXM9ImZyZWUiKSArDQogIHhsYWIoIlNleCIpICsgeWxhYigiTWVhbiBuZXQgc2FsYXJ5IHBlciBob3VyIikgKyBnZ3RpdGxlKCJHZW5kZXIgY29tcGFyaXNvbiBmb3IgZGlmZmVyZW50IGFnZXMiKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSArIHlsaW0oYyg1LCAxMDApKSArDQogIHN0YXRfYm94cGxvdChnZW9tID0gImVycm9yYmFyIiwgd2lkdGggPSAwLjUpDQoNCmBgYA0KDQoNClRoZSBpbmNvbWUgaW5lcXVhbGl0eSBiZXR3ZWVuIGdlbmRlcnMsIGFnZSBncm91cHMgYW5kIHdvcmtpbmcgcG9zaXRpb25zIGlzIGNsZWFyLg0KSW4gdGhlIGZvbGxvd2luZyBhbmFseXNlcyB0aGUgZm9jdXMgaXMgb24gdGhlIHNhbGFyeSByYXRpbyBiZXR3ZWVuIHdvbWVuIGFuZCBtZW4gYW1vbmcgZGlmZmVyZW50DQpqb2IgcG9zaXRpb25zOg0KYGBge3IgcmF0aW8gRiB2cyBNIGFjY3Jvc3Mgam9ic30NCg0KIyBHZW5kZXIgc2FsYXJ5IHJhdGlvIGFuZCBnZW5lcmFsIGxldmVsIG9mIGluY29tZQ0KDQojIE92ZXJhbGwgbWVhbiBzYWxhcnk6IFRoZSBoaWdoZXIgdGhlIG5ldCBtZWFuIGluY29tZSwgdGhlIG1vcmUgc2tld2VkIHRoZSByYXRpbyBvZiBzYWxhcnkgYmV0d2VlbiBmZW1hbGUgYW5kIG1hbGUgaXMuIE9ubHkgMiB0b3ducyBoYXZlIGEgcmF0aW8+MQ0KIyBjcmVhdGUgb3ZlcmFsbCBGIHZzIE0gcmF0aW8NCnNhbGFyeSRzYWxhcnlfcmF0aW9fRnZzTSA8LSBzYWxhcnkkc2FsX0ZlbWFsZXMgLyBzYWxhcnkkc2FsX01hbGVzDQojIGhpc3RvZ3JhbQ0KZ2dwbG90KGRhdGE9c2FsYXJ5LCBhZXMoc2FsYXJ5JHNhbGFyeV9yYXRpb19GdnNNKSkgKyANCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPS4uZGVuc2l0eS4uKSwgY29sPSJibGFjayIsIGZpbGw9ImJsdWUiLCBhbHBoYSA9IC4zLCBiaW5zID0gNTApICsgDQogIGdlb21fZGVuc2l0eShjb2w9ImJsYWNrIikgKyANCiAgbGFicyh4PSJPdmVyYWxsIHNhbGFyeSByYXRpbyAoZmVtYWxlcy9tYWxlcykiLCB5PSJEZW5zaXR5IikgKyANCiAgbGFicyh0aXRsZSA9ICJPdmVyYWxsIHNhbGFyeSByYXRpbyBiZXR3ZWVuIGZlbWFsZXMgYW5kIG1hbGVzIikgKyANCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpIA0KIyBzY2F0dGVyIHBsb3QgdnMgb3ZlcmFsbCBtZWFuIHNhbGFyeQ0KZ2dwbG90KHNhbGFyeSwgYWVzKHg9IHNhbF9nZW5lcmFsLCB5PXNhbGFyeV9yYXRpb19GdnNNKSkgKyAgDQogIGdlb21fcG9pbnQoc2l6ZSA9IDAuNSwgY29sb3VyID0gIiMwMDkxZmYiKSsgDQogIGxhYnMoeD0iT3ZlcmFsbCBzYWxhcnkiLCB5PSJPdmVyYWxsIHNhbGFyeSByYXRpbyhmZW1hbGVzL21hbGVzKSIpICsgDQogIGxhYnModGl0bGUgPSAiT3ZlcmFsbCBzYWxhcnkgcmF0aW8gYmV0d2VlbiBmZW1hbGVzIGFuZCBtYWxlcyB2cy4gb3ZlcmFsbCBzYWxhcnkiKSArIA0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKSANCg0KDQojIEV4ZWN1dGl2ZXMgbWVhbiBzYWxhcnk6IGEgYml0IGJldHRlciB0aGUgc2l0dWF0aW9uIGZvciBmZW1hbGVzIGluIHRoaXMgY2FzZSBhbmQgbGVzcyBza2V3ZWQNCiMgY3JlYXRlIEV4ZWN1dGl2ZXMgRiB2cyBNIHJhdGlvDQpzYWxhcnkkc2FsYXJ5X3JhdGlvX0Z2c01fRXhlYyA8LSBzYWxhcnkkc2FsX0ZfZXhlY3V0aXZlIC8gc2FsYXJ5JHNhbF9NX2V4ZWN1dGl2ZQ0KIyBoaXN0b2dyYW0NCmdncGxvdChkYXRhPXNhbGFyeSwgYWVzKHNhbGFyeSRzYWxhcnlfcmF0aW9fRnZzTV9FeGVjKSkgKyANCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPS4uZGVuc2l0eS4uKSwgY29sPSJibGFjayIsIGZpbGw9ImJsdWUiLCBhbHBoYSA9IC4zLCBiaW5zID0gNTApICsgDQogIGdlb21fZGVuc2l0eShjb2w9ImJsYWNrIikgKyANCiAgbGFicyh4PSJFeGVjdXRpdmVzIHNhbGFyeSByYXRpbyAoZmVtYWxlcy9tYWxlcykiLCB5PSJEZW5zaXR5IikgKyANCiAgbGFicyh0aXRsZSA9ICJFeGVjdXRpdmVzIHNhbGFyeSByYXRpbyBiZXR3ZWVuIGZlbWFsZXMgYW5kIG1hbGVzIikgKyANCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpIA0KIyBzY2F0dGVyIHBsb3QgdnMgZXhlY3V0aXZlcyBtZWFuIHNhbGFyeQ0KZ2dwbG90KHNhbGFyeSwgYWVzKHg9IHNhbF9nZW5lcmFsLCB5PSBzYWxhcnlfcmF0aW9fRnZzTV9FeGVjKSkgKyAgDQogIGdlb21fcG9pbnQoc2l6ZSA9IDAuNSwgY29sb3VyID0gIiMwMDkxZmYiKSsgDQogIGxhYnMoeD0iT3ZlcmFsbCBzYWxhcnkiLCB5PSJFeGVjdXRpdmVzIHNhbGFyeSByYXRpbyAoZmVtYWxlcy9tYWxlcykiKSArIA0KICBsYWJzKHRpdGxlID0gIkV4ZWN1dGl2ZXMgc2FsYXJ5IHJhdGlvIGJldHdlZW4gZmVtYWxlcyBhbmQgbWFsZXMgXG4gdnMuIG92ZXJhbGwgc2FsYXJ5IikgKyANCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIikNCg0KDQojIE1pZGRsZSBtYW5hZ2VycyBtZWFuIHNhbGFyeTogLi4uLg0KIyBjcmVhdGUgTWlkZGxlIG1hbmFnZXJzIEYgdnMgTSByYXRpbw0Kc2FsYXJ5JHNhbGFyeV9yYXRpb19GdnNNX21pZE1hbmFnIDwtIHNhbGFyeSRzYWxfRl9taWRNYW5hZ2VyIC8gc2FsYXJ5JHNhbF9NX21pZE1hbmFnZXINCiMgaGlzdG9ncmFtDQpnZ3Bsb3QoZGF0YT1zYWxhcnksIGFlcyhzYWxhcnkkc2FsYXJ5X3JhdGlvX0Z2c01fRXhlYykpICsgDQogIGdlb21faGlzdG9ncmFtKGFlcyh5ID0uLmRlbnNpdHkuLiksIGNvbD0iYmxhY2siLCBmaWxsPSJibHVlIiwgYWxwaGEgPSAuMywgYmlucyA9IDUwKSArIA0KICBnZW9tX2RlbnNpdHkoY29sPSJibGFjayIpICsgDQogIGxhYnMoeD0iTWlkZGxlIG1hbmFnZXJzIHNhbGFyeSByYXRpbyAoZmVtYWxlcy9tYWxlcykiLCB5PSJEZW5zaXR5IikgKyANCiAgbGFicyh0aXRsZSA9ICJNaWRkbGUgbWFuYWdlcnMgc2FsYXJ5IHJhdGlvIGJldHdlZW4gZmVtYWxlcyBhbmQgbWFsZXMiKSArIA0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgDQojIHNjYXR0ZXIgcGxvdCB2cyBleGVjdXRpdmVzIG1lYW4gc2FsYXJ5DQpnZ3Bsb3Qoc2FsYXJ5LCBhZXMoeD0gc2FsX2dlbmVyYWwsIHk9IHNhbGFyeV9yYXRpb19GdnNNX21pZE1hbmFnKSkgKyAgDQogIGdlb21fcG9pbnQoc2l6ZSA9IDAuNSwgY29sb3VyID0gIiMwMDkxZmYiKSsgDQogIGxhYnMoeD0iT3ZlcmFsbCBzYWxhcnkiLCB5PSJNaWRkbGUgbWFuYWdlcnMgc2FsYXJ5IHJhdGlvIChmZW1hbGVzL21hbGVzKSIpICsgDQogIGxhYnModGl0bGUgPSAiTWlkZGxlIG1hbmFnZXJzIHNhbGFyeSByYXRpbyBiZXR3ZWVuIGZlbWFsZXMgYW5kIG1hbGVzIFxuIHZzLiBvdmVyYWxsIHNhbGFyeSIpICsgDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSArDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIpDQoNCg0KIyBXb3JrZXJzIG1lYW4gc2FsYXJ5OiAuLi4NCiMgY3JlYXRlIHdvcmtlcnMgRiB2cyBNIHJhdGlvDQpzYWxhcnkkc2FsYXJ5X3JhdGlvX0Z2c01fd29ya2VyIDwtIHNhbGFyeSRzYWxfRl93b3JrZXIgLyBzYWxhcnkkc2FsX01fd29ya2VyDQojIGhpc3RvZ3JhbQ0KZ2dwbG90KGRhdGE9c2FsYXJ5LCBhZXMoc2FsYXJ5JHNhbGFyeV9yYXRpb19GdnNNX3dvcmtlcikpICsgDQogIGdlb21faGlzdG9ncmFtKGFlcyh5ID0uLmRlbnNpdHkuLiksIGNvbD0iYmxhY2siLCBmaWxsPSJibHVlIiwgYWxwaGEgPSAuMywgYmlucyA9IDUwKSArIA0KICBnZW9tX2RlbnNpdHkoY29sPSJibGFjayIpICsgDQogIGxhYnMoeD0iV29ya2VycyBzYWxhcnkgcmF0aW8gKGZlbWFsZXMvbWFsZXMpIiwgeT0iRGVuc2l0eSIpICsgDQogIGxhYnModGl0bGUgPSAiV29ya2VycyBzYWxhcnkgcmF0aW8gYmV0d2VlbiBmZW1hbGVzIGFuZCBtYWxlcyIpICsgDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSANCiMgc2NhdHRlciBwbG90IHZzIHdvcmtlcnMgbWVhbiBzYWxhcnkNCmdncGxvdChzYWxhcnksIGFlcyh4PSBzYWxfZ2VuZXJhbCwgeT0gc2FsYXJ5X3JhdGlvX0Z2c01fd29ya2VyKSkgKyAgDQogIGdlb21fcG9pbnQoc2l6ZSA9IDAuNSwgY29sb3VyID0gIiMwMDkxZmYiKSsgDQogIGxhYnMoeD0iT3ZlcmFsbCBzYWxhcnkiLCB5PSJXb3JrZXJzIHNhbGFyeSByYXRpbyAoZmVtYWxlcy9tYWxlcykiKSArIA0KICBsYWJzKHRpdGxlID0gIldvcmtlcnMgc2FsYXJ5IHJhdGlvIGJldHdlZW4gZmVtYWxlcyBhbmQgbWFsZXMgXG4gdnMuIG92ZXJhbGwgc2FsYXJ5IikgKyANCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIikNCg0KDQojIEVtcGxveWVlIG1lYW4gc2FsYXJ5OiAuLi4NCiMgY3JlYXRlIEVtcGxveWVlIEYgdnMgTSByYXRpbw0Kc2FsYXJ5JHNhbGFyeV9yYXRpb19GdnNNX2VtcGxveWVlIDwtIHNhbGFyeSRzYWxfRl9lbXBsb3llZSAvIHNhbGFyeSRzYWxfTV9lbXBsb3llZQ0KIyBoaXN0b2dyYW0NCmdncGxvdChkYXRhPXNhbGFyeSwgYWVzKHNhbGFyeSRzYWxhcnlfcmF0aW9fRnZzTV9lbXBsb3llZSkpICsgDQogIGdlb21faGlzdG9ncmFtKGFlcyh5ID0uLmRlbnNpdHkuLiksIGNvbD0iYmxhY2siLCBmaWxsPSJibHVlIiwgYWxwaGEgPSAuMywgYmlucyA9IDUwKSArIA0KICBnZW9tX2RlbnNpdHkoY29sPSJibGFjayIpICsgDQogIGxhYnMoeD0iRW1wbG95ZWUgc2FsYXJ5IHJhdGlvIChmZW1hbGVzL21hbGVzKSIsIHk9IkRlbnNpdHkiKSArIA0KICBsYWJzKHRpdGxlID0gIkVtcGxveWVlIHNhbGFyeSByYXRpbyBiZXR3ZWVuIGZlbWFsZXMgYW5kIG1hbGVzIikgKyANCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpIA0KIyBzY2F0dGVyIHBsb3QgdnMgRW1wbG95ZWUgbWVhbiBzYWxhcnkNCmdncGxvdChzYWxhcnksIGFlcyh4PSBzYWxfZ2VuZXJhbCwgeT0gc2FsYXJ5X3JhdGlvX0Z2c01fZW1wbG95ZWUpKSArICANCiAgZ2VvbV9wb2ludChzaXplID0gMC41LCBjb2xvdXIgPSAiIzAwOTFmZiIpKyANCiAgbGFicyh4PSJPdmVyYWxsIHNhbGFyeSIsIHk9IkVtcGxveWVlIHNhbGFyeSByYXRpbyAoZmVtYWxlcy9tYWxlcykiKSArIA0KICBsYWJzKHRpdGxlID0gIkVtcGxveWVlIHNhbGFyeSByYXRpbyBiZXR3ZWVuIGZlbWFsZXMgYW5kIG1hbGVzIFxuIHZzLiBvdmVyYWxsIHNhbGFyeSIpICsgDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSArDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIpDQoNCmBgYA0KDQoNCk5vdyB0aGUgZm9jdXMgaXMgb24gdGhlIHNhbGFyeSByYXRpbyBiZXR3ZWVuIHdvbWVuIGFuZCBtZW4gYW1vbmcgZGlmZmVyZW50IGFnZSBncm91cHM6DQpgYGB7ciByYXRpbyBGIHZzIE0gYWNjcm9zcyBhZ2VzfQ0KDQojIDE4LTI1IG1lYW4gc2FsYXJ5OiBhcmUgcXVpdGUgZXF1YWwgYXBhcnQgZnJvbSBzb21lIG91dGxpZXJzIGFuZCBhIHF1YWRyYXRpYyB0cmVuZA0KIyBjcmVhdGUgMTgtMjUgRiB2cyBNIHJhdGlvDQpzYWxhcnkkc2FsYXJ5X3JhdGlvX0Z2c01fMThfMjUgPC0gc2FsYXJ5JHNhbF9GXzE4XzI1IC8gc2FsYXJ5JHNhbF9NXzE4XzI1DQojIGhpc3RvZ3JhbQ0KZ2dwbG90KGRhdGE9c2FsYXJ5LCBhZXMoc2FsYXJ5JHNhbGFyeV9yYXRpb19GdnNNXzE4XzI1KSkgKyANCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPS4uZGVuc2l0eS4uKSwgY29sPSJibGFjayIsIGZpbGw9ImJsdWUiLCBhbHBoYSA9IC4zLCBiaW5zID0gNTApICsgDQogIGdlb21fZGVuc2l0eShjb2w9ImJsYWNrIikgKyANCiAgbGFicyh4PSIxOC0yNSBzYWxhcnkgcmF0aW8gKGZlbWFsZXMvbWFsZXMpIiwgeT0iRGVuc2l0eSIpICsgDQogIGxhYnModGl0bGUgPSAiMTgtMjUgc2FsYXJ5IHJhdGlvIGJldHdlZW4gZmVtYWxlcyBhbmQgbWFsZXMiKSArIA0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgDQojIHNjYXR0ZXIgcGxvdCB2cyAxOC0yNSBtZWFuIHNhbGFyeQ0KZ2dwbG90KHNhbGFyeSwgYWVzKHg9IHNhbF9nZW5lcmFsLCB5PSBzYWxhcnlfcmF0aW9fRnZzTV8xOF8yNSkpICsgIA0KICBnZW9tX3BvaW50KHNpemUgPSAwLjUsIGNvbG91ciA9ICIjMDA5MWZmIikrIA0KICBsYWJzKHg9Ik92ZXJhbGwgc2FsYXJ5IiwgeT0iMTgtMjUgc2FsYXJ5IHJhdGlvIChmZW1hbGVzL21hbGVzKSIpICsgDQogIGxhYnModGl0bGUgPSAiMTgtMjUgc2FsYXJ5IHJhdGlvIGJldHdlZW4gZmVtYWxlcyBhbmQgbWFsZXMgXG4gdnMuIG92ZXJhbGwgc2FsYXJ5IikgKyANCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIikNCiMgc2NhdHRlciBwbG90IHZzIDE4LTI1IG1lYW4gc2FsYXJ5IGZvciB0aGVtDQpnZ3Bsb3Qoc2FsYXJ5LCBhZXMoeD0gc2FsXzE4XzI1LCB5PSBzYWxhcnlfcmF0aW9fRnZzTV8xOF8yNSkpICsgIA0KICBnZW9tX3BvaW50KHNpemUgPSAwLjUsIGNvbG91ciA9ICIjMDA5MWZmIikrIA0KICBsYWJzKHg9IjE4LTI1IHNhbGFyeSIsIHk9IjE4LTI1IHNhbGFyeSByYXRpbyAoZmVtYWxlcy9tYWxlcykiKSArIA0KICBsYWJzKHRpdGxlID0gIjE4LTI1IHNhbGFyeSByYXRpbyBiZXR3ZWVuIGZlbWFsZXMgYW5kIG1hbGVzIFxuIHZzLiBvdmVyYWxsIDE4LTI1IHNhbGFyeSIpICsgDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSArDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsb2VzcyIpDQoNCg0KIyAyNi01MCBtZWFuIHNhbGFyeTogLi4uDQojIGNyZWF0ZSAyNi01MCBGIHZzIE0gcmF0aW8NCnNhbGFyeSRzYWxhcnlfcmF0aW9fRnZzTV8yNl81MCA8LSBzYWxhcnkkc2FsX0ZfMjZfNTAgLyBzYWxhcnkkc2FsX01fMjZfNTANCiMgaGlzdG9ncmFtDQpnZ3Bsb3QoZGF0YT1zYWxhcnksIGFlcyhzYWxhcnkkc2FsYXJ5X3JhdGlvX0Z2c01fMjZfNTApKSArIA0KICBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9Li5kZW5zaXR5Li4pLCBjb2w9ImJsYWNrIiwgZmlsbD0iYmx1ZSIsIGFscGhhID0gLjMsIGJpbnMgPSA1MCkgKyANCiAgZ2VvbV9kZW5zaXR5KGNvbD0iYmxhY2siKSArIA0KICBsYWJzKHg9IjI2LTUwIHNhbGFyeSByYXRpbyAoZmVtYWxlcy9tYWxlcykiLCB5PSJEZW5zaXR5IikgKyANCiAgbGFicyh0aXRsZSA9ICIyNi01MCBzYWxhcnkgcmF0aW8gYmV0d2VlbiBmZW1hbGVzIGFuZCBtYWxlcyIpICsgDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSANCiMgc2NhdHRlciBwbG90IHZzIDI2LTUwIG1lYW4gc2FsYXJ5DQpnZ3Bsb3Qoc2FsYXJ5LCBhZXMoeD0gc2FsX2dlbmVyYWwsIHk9IHNhbGFyeV9yYXRpb19GdnNNXzI2XzUwKSkgKyAgDQogIGdlb21fcG9pbnQoc2l6ZSA9IDAuNSwgY29sb3VyID0gIiMwMDkxZmYiKSsgDQogIGxhYnMoeD0iT3ZlcmFsbCBzYWxhcnkiLCB5PSIyNi01MCBzYWxhcnkgcmF0aW8gKGZlbWFsZXMvbWFsZXMpIikgKyANCiAgbGFicyh0aXRsZSA9ICIyNi01MCBzYWxhcnkgcmF0aW8gYmV0d2VlbiBmZW1hbGVzIGFuZCBtYWxlcyBcbiB2cy4gb3ZlcmFsbCBzYWxhcnkiKSArIA0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKQ0KDQoNCiMgNTErIG1lYW4gc2FsYXJ5OiAuLi4NCiMgY3JlYXRlIDUxKyBGIHZzIE0gcmF0aW8NCnNhbGFyeSRzYWxhcnlfcmF0aW9fRnZzTV81MXBsdXMgPC0gc2FsYXJ5JHNhbF9GXzUxcGx1cyAvIHNhbGFyeSRzYWxfTV81MXBsdXMNCiMgaGlzdG9ncmFtDQpnZ3Bsb3QoZGF0YT1zYWxhcnksIGFlcyhzYWxhcnkkc2FsYXJ5X3JhdGlvX0Z2c01fNTFwbHVzKSkgKyANCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPS4uZGVuc2l0eS4uKSwgY29sPSJibGFjayIsIGZpbGw9ImJsdWUiLCBhbHBoYSA9IC4zLCBiaW5zID0gNTApICsgDQogIGdlb21fZGVuc2l0eShjb2w9ImJsYWNrIikgKyANCiAgbGFicyh4PSI1MSsgc2FsYXJ5IHJhdGlvIChmZW1hbGVzL21hbGVzKSIsIHk9IkRlbnNpdHkiKSArIA0KICBsYWJzKHRpdGxlID0gIjUxKyBzYWxhcnkgcmF0aW8gYmV0d2VlbiBmZW1hbGVzIGFuZCBtYWxlcyIpICsgDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSANCiMgc2NhdHRlciBwbG90IHZzIDI2LTUwIG1lYW4gc2FsYXJ5DQpnZ3Bsb3Qoc2FsYXJ5LCBhZXMoeD0gc2FsX2dlbmVyYWwsIHk9IHNhbGFyeV9yYXRpb19GdnNNXzUxcGx1cykpICsgIA0KICBnZW9tX3BvaW50KHNpemUgPSAwLjUsIGNvbG91ciA9ICIjMDA5MWZmIikrIA0KICBsYWJzKHg9Ik92ZXJhbGwgc2FsYXJ5IiwgeT0iNTErIHNhbGFyeSByYXRpbyAoZmVtYWxlcy9tYWxlcykiKSArIA0KICBsYWJzKHRpdGxlID0gIjUxKyBzYWxhcnkgcmF0aW8gYmV0d2VlbiBmZW1hbGVzIGFuZCBtYWxlcyBcbiB2cy4gb3ZlcmFsbCBzYWxhcnkiKSArIA0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKQ0KDQpgYGANCg0KDQpIaWdobGlnaHQgYml2YXJpYXRlIHJlbGF0aW9uczoNCmBgYHtyIGJpdmFyaWF0ZSBwbG90c30NCg0KIyBjb3JyZWxhdGlvbiBtYXRyaXgNCmNvcnJwbG90KGNvcihzYWxhcnlbLCAzOm5jb2woc2FsYXJ5KV0pLCBtZXRob2QgPSAiY2lyY2xlIiwgdGl0bGUgPSAiQ29ycmVsYXRpb24gbWF0cml4IGZvciBzYWxhcnkgZGF0YSIsIA0KICAgICAgICAgZGlhZyA9IFQsIHRsLmNleD0wLjUsIHR5cGU9Imxvd2VyIiwgDQogICAgICAgICB0bC5jb2wgPSAiYmxhY2siLCBtYXI9YygwLDAsMS41LDApKSANCg0KIyBtb3N0IGdlbmVyYWwgcGFpcnMNCnBhaXJzKHNhbGFyeVtjKDM6OCwgMTMsIDE4OjIwKV0sIGdhcD0wLCBtYWluID0gIlNjYXR0ZXIgbWF0cml4IG9mIHRoZSBtYWluIHZhcmlhYmxlcyBpbiBzYWxhcnkgZGF0YSIsIGNleCA9IDAuNikNCiMgcGFpcnMgaGlnaGxpZ2h0aW5nIGdlbmRlcnMnIGRpZmZlcmVuY2VzDQpwYWlycyhzYWxhcnlbYyg5OjEyLCAxNDoxNyldLCBnYXA9MCwgbWFpbiA9ICJTY2F0dGVyIG1hdHJpeCBvZiBqb2IgY2F0ZWdvcmllcyBmb3IgYm90aCBnZW5kZXJzIiwgY2V4ID0gMC42KQ0KDQpgYGANCg0KIyMjIFdoYXQgd2UgaGF2ZSBsZWFybmVkDQoNCi4uLi4NCg0KDQoNCiMjIFBvcHVsYXRpb24gZGF0YSANCg0KUGxvdCBwb3B1bGF0aW9uIGRhdGEgYWNyb3NzIGRpZmZlcmVudCB0b3duczoNCmBgYHtyIHBsb3R0aW5nIHNvbWUgcG9wdWxhdGlvbiBkYXRhIGluIGxvZzEwfQ0KDQojIEhpc3RvZ3JhbSBvZiB0b3RhbCBwb3B1bGF0aW9uIHBlciB0b3duIGluIGxvZw0KZ2dwbG90KGRhdGE9cG9wdWxhdGlvbiwgYWVzKGlmZWxzZSh0b3RhbF9wb3B1bGF0aW9uIT0wLCBsb2cxMCh0b3RhbF9wb3B1bGF0aW9uKSwgMCkpKSArDQogIGdlb21faGlzdG9ncmFtKGFlcyh5ID0uLmRlbnNpdHkuLiksIGNvbD0iYmxhY2siLCBmaWxsPSJibHVlIiwgYWxwaGEgPSAuMywgYmlucyA9IDUwKSArDQogIGdlb21fZGVuc2l0eShjb2w9ImJsYWNrIikgKw0KICBsYWJzKHg9IkxvZzEwIHRvdGFsIHBvcHVsYXRpb24iLCB5PSJEZW5zaXR5IikgKw0KICBnZ3RpdGxlKCJIaXN0b2dyYW0gb2YgdG90YWwgcG9wdWxhdGlvbiBwZXIgdG93biBpbiBsb2cxMCBzY2FsZSIpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpDQoNCiMgSGlzdG9ncmFtIG9mIGRlcGVuZGVuY3kgcmF0aW8gcGVyIHRvd24NCmdncGxvdChkYXRhPXBvcHVsYXRpb24sIGFlcyhpZmVsc2UoZGVwZW5kZW5jeV9yYXRpbyE9MCwgbG9nMTAoZGVwZW5kZW5jeV9yYXRpbyksIDApKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9Li5kZW5zaXR5Li4pLCBjb2w9ImJsYWNrIiwgZmlsbD0iYmx1ZSIsIGFscGhhID0gLjMsIGJpbnMgPSA1MCkgKw0KICBnZW9tX2RlbnNpdHkoY29sPSJibGFjayIpICsNCiAgbGFicyh4PSJMb2cxMCBkZXBlbmRlbmN5IHJhdGlvIiwgeT0iRGVuc2l0eSIpICsNCiAgZ2d0aXRsZSgiSGlzdG9ncmFtIG9mIGRlcGVuZGVuY3kgcmF0aW8gcGVyIHRvd24gaW4gbG9nMTAgc2NhbGUiKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQ0KDQojIEhpc3RvZ3JhbSBvZiBzZXggcmF0aW8gcGVyIHRvd24NCmdncGxvdChkYXRhPXBvcHVsYXRpb24sIGFlcyhpZmVsc2Uoc2V4X3JhdGlvIT0wLCBsb2cxMChzZXhfcmF0aW8pLCAwKSkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPS4uZGVuc2l0eS4uKSwgY29sPSJibGFjayIsIGZpbGw9ImJsdWUiLCBhbHBoYSA9IC4zLCBiaW5zID0gNTApICsNCiAgZ2VvbV9kZW5zaXR5KGNvbD0iYmxhY2siKSArDQogIGxhYnMoeD0iTG9nMTAgc2V4IHJhdGlvIiwgeT0iRGVuc2l0eSIpICsNCiAgZ2d0aXRsZSgiSGlzdG9ncmFtIG9mIHNleCByYXRpbyBwZXIgdG93biBpbiBsb2cxMCBzY2FsZSIpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpDQoNCmBgYA0KDQpVbmRlcnN0YW5kIHdoaWNoIHRvd25zIGhhdmUgdGhlIGhpZ2hlc3QgY29uY2VudHJhdGlvbiBvZiBwb3B1bGF0aW9uIGFuZCByYXRpb3MuDQpgYGB7ciBnZW8gcGxvdCBmb3IgZWFjaCB0b3dufQ0KDQojIE1lcmdlIGdlb2dyYXBoeSBhbmQgcG9wdWxhdGlvbiBkYXRhDQojIGdlb19wb3B1bGF0aW9uIDwtIG1lcmdlKGdlbywgcG9wdWxhdGlvbiwgYnk9IkNPREdFTyIpDQpnZW9fcG9wdWxhdGlvbiA8LSBjYmluZC5kYXRhLmZyYW1lKGdlb1t1bmlxdWUoZ2VvJENPREdFTykgJWluJSB1bmlxdWUocG9wdWxhdGlvbiRDT0RHRU8pLF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvcHVsYXRpb25bdW5pcXVlKHBvcHVsYXRpb24kQ09ER0VPKSAlaW4lIHVuaXF1ZShnZW8kQ09ER0VPKSxdKQ0KDQojIEZyYW5jZSBtYXANCkZyYU1hcCA9IGdnbWFwKGdldF9nb29nbGVtYXAoY2VudGVyPWZyYV9jZW50ZXIsIHNjYWxlPTIsIHpvb209NiksIGV4dGVudD0ibm9ybWFsIikNCg0KIyBQbG90ICJEaXN0cmlidXRpb24gb2YgdG90YWwgcG9wdWxhdGlvbiBmb3IgZWFjaCB0b3duIiANCnNjIDwtIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oY29sb3VycyA9cGFsZXR0ZShyYWluYm93KDMpKSwgbGltaXRzPWMobG9nMTAobWluKGdlb19wb3B1bGF0aW9uJHRvdGFsX3BvcHVsYXRpb24pKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZzEwKG1heChnZW9fcG9wdWxhdGlvbiR0b3RhbF9wb3B1bGF0aW9uKSkpKSANCnBvcHVsYXRpb25fZGlzdHJpYnV0aW9uIDwtDQogIEZyYU1hcCArDQogIGdlb21fcG9pbnQoYWVzKHg9Z2VvX3BvcHVsYXRpb24kbG9uZ2l0dWRlLCB5PWdlb19wb3B1bGF0aW9uJGxhdGl0dWRlLA0KICAgICAgICAgICAgICAgICBjb2xvdXI9bG9nMTAoZ2VvX3BvcHVsYXRpb24kdG90YWxfcG9wdWxhdGlvbikpLCANCiAgICAgICAgICAgICBkYXRhPWdlb19wb3B1bGF0aW9uLCBhbHBoYT0wLjIsIHNpemU9MC4wMSkgKw0KICAgICAgICAgICAgIHNjICsgbGFicyhjb2xvcj0nJykgKyBnZ3RpdGxlKCJEaXN0cmlidXRpb24gb2YgUG9wdWxhdGlvbiBmb3IgZWFjaCB0b3duIikNCnBvcHVsYXRpb25fZGlzdHJpYnV0aW9uDQoNCiMgUGxvdCAiRGlzdHJpYnV0aW9uIG9mIGFnZWQgZGVwZW5kZW5jeSByYXRpbyBmb3IgZWFjaCB0b3duIg0Kc2MgPC0gc2NhbGVfY29sb3VyX2dyYWRpZW50bihjb2xvdXJzID1wYWxldHRlKHJhaW5ib3coNCkpLCBsaW1pdHM9YyhtaW4oZ2VvX3BvcHVsYXRpb24kYWdlZF9kZXBlbmRlbmN5X3JhdGlvKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heChnZW9fcG9wdWxhdGlvbiRhZ2VkX2RlcGVuZGVuY3lfcmF0aW8pKSkNCmFnZWRfcmF0aW9fZGlzdHJpYnV0aW9uIDwtDQogIEZyYU1hcCArDQogIGdlb21fcG9pbnQoYWVzKHg9Z2VvX3BvcHVsYXRpb24kbG9uZ2l0dWRlLCB5PWdlb19wb3B1bGF0aW9uJGxhdGl0dWRlLA0KICAgICAgICAgICAgICAgICBjb2xvdXI9Z2VvX3BvcHVsYXRpb24kYWdlZF9kZXBlbmRlbmN5X3JhdGlvKSwNCiAgICAgICAgICAgICBkYXRhPWdlb19wb3B1bGF0aW9uLCBhbHBoYT0xLCBzaXplPTEpICsNCiAgICAgICAgICAgICBzYyArIGxhYnMoY29sb3I9JycpICsgZ2d0aXRsZSgiQWdlZCBkZXBlbmRlbmN5IHJhdGlvIHBlciB0b3duIikNCmFnZWRfcmF0aW9fZGlzdHJpYnV0aW9uDQoNCiMgd2hpY2ggY2l0eSBoYXMgdGhlIGhpZ2hlc3QvbG93ZXN0IGFnZWQgZGVwZW5kZW5jeSByYXRpbyANCmdlb19wb3B1bGF0aW9uW3doaWNoLm1pbihnZW9fcG9wdWxhdGlvbiRhZ2VkX2RlcGVuZGVuY3lfcmF0aW8pLGMoJ0NPREdFTycpXSAgDQpnZW9fcG9wdWxhdGlvblt3aGljaC5tYXgoZ2VvX3BvcHVsYXRpb24kYWdlZF9kZXBlbmRlbmN5X3JhdGlvKSxjKCdDT0RHRU8nKV0gIA0KIA0KIyBnZXQgbGlzdCBvZiB0b3AgMTAgaGlnaGVzdCBhZ2VkIGRlcGVuZGVuY3kgcmF0aW8gDQpSYW5rID0gc29ydChwb3B1bGF0aW9uJGFnZWRfZGVwZW5kZW5jeV9yYXRpbywgVFJVRSkgDQpSYW5rMTAgPSBzb3J0KFJhbmtbMToxMF0sIFRSVUUpIA0Kc29sID0gcmVwKDAsIDEwKSANCmZvciAoaSBpbiAxOjEwKXsgDQogICAgc29sW2ldID0gcGFzdGUoZ2VvX3BvcHVsYXRpb24kQ09ER0VPW2dlb19wb3B1bGF0aW9uJGFnZWRfZGVwZW5kZW5jeV9yYXRpbyAlaW4lIFJhbmsxMFtpXV0gKQ0KfSANCg0KIyByZW1vdmUgdGhlIGRhdGFzZXQgY3JlYXRlZCB0byBzYXZlIG1lbW9yeQ0Kcm0obGlzdCA9IGMoImdlb19wb3B1bGF0aW9uIiwgIlJhbmsiLCAiUmFuazEwIikpIA0KDQpgYGANCg0KDQojIyMgV2hhdCB3ZSBoYXZlIGxlYXJuZWQgDQoNCldlIGNhbiBvYnNlcnZlIHRoYXQgaW4gdXJiYW4gY2l0aWVzLCB0aGUgYWdlZCBkZXBlbmRjeSByYXRpbyBpcyBsb3dlciBjb21wYXJlZCB0byBub24tdXJiYW4gY2l0aWVzLiANClRoZSBjaXR5IHdpdGggdGhlIGxvd2VzdCBhZ2VkIGRlcGVuZGVuY3kgcmF0aW8gaXMgTGEgRmVydD8tc291cy1Kb3VhcnJlIGFuZCB0aGUgaGlnaGVzdCBpcyBMJ0FpZ3VpbGxvbi1zdXItTWVyLiANCg0KIyMgRWR1Y2F0aW9uIGRhdGENCg0KYGBge3IgRGVzY3JpcHRpdmUgc3RhdGlzdGljcy1FZHVjYXRpb259IA0KIA0KIyBEaWZmZXJlbmNlIGJldHdlZW4gbWFsZSBhbmQgZmVtYWxlJ3MgZWR1Y2F0aW9uIGxldmVsICh3aXRoIFVuaXZlcnNpdHkgZGVncmVlcykgDQpzdW1tYXJ5KGVkdWMkbWFsZV9Vbml2KSANCnN1bW1hcnkoZWR1YyRmZW1hbGVfVW5pdikgDQpzdW1tYXJ5KGVkdWMkbWFsZV9Ob0RpcCkgDQpzdW1tYXJ5KGVkdWMkZmVtYWxlX05vRGlwKSANCiANCiMgTWVyZ2UgZ2VvIGFuZCBlZHVjIGRhdGEgdG8gaW5jbHVkZSBsb25naXR1ZGUgYW5kIGxhdGl0dWRlIGluIHRoZSBkYXRhLiANCmdlb19lZHVjIDwtIGNiaW5kLmRhdGEuZnJhbWUoZ2VvW3VuaXF1ZShnZW8kQ09ER0VPKSAlaW4lIHVuaXF1ZShlZHVjJENPREdFTyksXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVkdWNbdW5pcXVlKGVkdWMkQ09ER0VPKSAlaW4lIHVuaXF1ZShnZW8kQ09ER0VPKSxdKSANCiANCiMgY2hlY2sgdGhlIHJhdGlvIG9mIGluZGl2aWR1YWxzIHdpdGggaGlnaCBhbmQgbG93IGVkdWNhdGlvbiBsZXZlbCBmb3IgZWFjaCB0b3duLiANCnN1bW1hcnkoZWR1YyR1bml2L2VkdWMkbm9kaXApIA0KIA0KIyBIaXN0b2dyYW0gb2YgdGhlIHJhdGlvIG9mIGluZGl2aWR1YWxzIHdpdGggaGlnaCBhbmQgbG93IGVkdWNhdGlvbiBsZXZlbCBmb3IgZWFjaCB0b3duIA0KZ2dwbG90KGRhdGE9ZWR1YywgYWVzKGxvZyhlZHVjJHVuaXYvZWR1YyRub2RpcCkpKSArIA0KICBnZW9tX2hpc3RvZ3JhbShhZXMoeT0uLmRlbnNpdHkuLiksIGNvbD0iYmxhY2siLCBmaWxsPSJibHVlIiwgYWxwaGE9MC4zLCBiaW5zPSA1MCkrIA0KICAgICAgICAgICAgICAgICAgIGdlb21fZGVuc2l0eShjb2w9ImJsYWNrIikgKyANCiAgICAgICAgICAgICAgICAgICBsYWJzKHg9ImxvZy4gVW5pdmVyc2l0eSBkZWdyZWUvTm8gZGlwbG9tYSIsIHk9IkRlbnNpdHkiKSArIA0KICAgICAgICAgICAgICAgICAgIGdndGl0bGUoIlJhdGlvIGJldHdlZW4gdGhlIG51bWJlciBvZiBpbmRpdmlkdWFscyB3aXRoIG5vIGRpcGxvbWEgYW5kICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGluZGl2aWR1YWxzIHdpdGggVW5pdmVyc2l0eSBkZWdyZWUgcGVyIHRvd24iKSArIA0KICAgICAgICAgICAgICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPWVsZW1lbnRfdGV4dChoanVzdD0gMC41KSkgDQogDQojIEFkanVzdCBzY2FsZXMgYmVmb3JlIHBsb3R0aW5nIA0Kc2MgPC0gc2NhbGVfY29sb3VyX2dyYWRpZW50bihjb2xvdXJzID0gYygiIzU2ZGRjNSIsICIjRjg3NjZEIiwgIiMwMEJBMzgiKSwgbGltaXRzPWMobWluKGVkdWMkdW5pdi9lZHVjJG5vZGlwKSwgbWF4KGVkdWMkdW5pdi9lZHVjJG5vZGlwKSkpIA0KIA0KIyBNYXAgcmF0aW8gIA0KZWR1Y19yYXRpb19Ob0RpcFVuaXYgPC0gDQogIEZyYU1hcCArIA0KICBnZW9tX3BvaW50KGFlcyh4PWdlb19lZHVjJGxvbmdpdHVkZSwgeT1nZW9fZWR1YyRsYXRpdHVkZSwgDQogICAgICAgICAgICAgICAgIGNvbG91cj1lZHVjJHVuaXYvZWR1YyRub2RpcCksIA0KICAgICAgICAgICAgIGRhdGE9Z2VvX2VkdWMsIGFscGhhPTEsIHNpemU9MSkgKyANCiAgICAgICAgICAgICBzYyArIGxhYnMoY29sb3I9J1JhdGlvJykgKyBnZ3RpdGxlKCJFZHVjYXRpb24gbGV2ZWwgcmF0aW8gZm9yIGVhY2ggdG93biIpIA0KZWR1Y19yYXRpb19Ob0RpcFVuaXYgDQogDQojIFN0YXRpc3RpY3Mgb2Ygc2hhcGUgZm9yIHRoZSBkYXRhIA0KIyBsaWJyYXJ5KHBzeWNoKSANCmRlc2NyaWJlKGVkdWMkdW5pdi9lZHVjJG5vZGlwKSANCiANCiMgcmVtb3ZlIHRoZSBkYXRhc2V0IGNyZWF0ZWQgdG8gc2F2ZSBtZW1vcnkgDQpybShsaXN0PWMoImdlb19lZHVjIiwgImVkdWNfcmF0aW9fTm9EaXBVbml2IikpIA0KIA0KYGBgIA0KIA0KIyMjIFdoYXQgd2UgaGF2ZSBsZWFybmVkIA0KIA0KSW4gYXZlcmFnZSA5NjAgbWFsZXMgaGF2ZSB1bml2ZXJzaXR5IGRlZ3JlZSBhbmQgMTEwMCBmZW1hbGVzIGhhdmUgdW5pdmVyc2l0eSBkZWdyZWUuICANCkluIGF2ZXJhZ2UgOTA0IG1hbGVzIGhhdmUgbm8gZGlwbG9tYSBhbmQgMTI0MiBmZW1hbGVzIGhhdmUgbm8gZGlwbG9tYS4gDQpIaWdoZXN0IHJhdGlvIGluIFBhcmlzPTc4MjUxPVl2ZWxpbmVzIA0KIA0KDQojIyBEZW1vZ3JhcGhpYy9zb2NpYWwgcHJvZmlsZXMgZGF0YQ0KDQpgYGB7ciBEZXNjcmlwdGl2ZSBzdGF0aXN0aWNzIERlbW9ncmFwaGljIHByb2ZpbGVzfQ0KZ2xpbXBzZShjYXRlZ19zb2NpbykNCg0KIyBtZXJnZSBnZW8gYW5kIGNhdGVnX3NvY2lvDQpnZW9fY2F0ZWdfc29jaW8gPC0gY2JpbmQuZGF0YS5mcmFtZShnZW9bdW5pcXVlKGdlbyRDT0RHRU8pICVpbiUgdW5pcXVlKGNhdGVnX3NvY2lvJENPREdFTyksXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2F0ZWdfc29jaW9bdW5pcXVlKGNhdGVnX3NvY2lvJENPREdFTykgJWluJSB1bmlxdWUoZ2VvJENPREdFTyksXSkNCg0KIyBmaW5kIHdoaWNoIGNpdGllcyBoYXZlIHRoZSBtb3N0IGFuZCBsZWFzdCBudW1iZXIgb2YgaW1taWdyYW50cw0KY2F0ZWdfc29jaW9bd2hpY2gubWF4KGNhdGVnX3NvY2lvJHRvdGFsX2ltbWlnKSxjKCdDT0RHRU8nKV0gDQpjYXRlZ19zb2Npb1t3aGljaC5taW4oY2F0ZWdfc29jaW8kdG90YWxfaW1taWcpLGMoJ0NPREdFTycpXSANCg0KIyBnZXQgbGlzdCBvZiB0b3AgMTAgY2l0aWVzIHdpdGggdGhlIG1vc3QgbnVtYmVyIG9mIGltbWlncmFudHMNClJhbmsgPSBzb3J0KGNhdGVnX3NvY2lvJHRvdGFsX2ltbWlnLCBUUlVFKQ0KUmFuazEwID0gc29ydChSYW5rWzE6MTBdLCBUUlVFKQ0Kc29sID0gcmVwKDAsIDEwKQ0KZm9yIChpIGluIDE6MTApew0KICAgIHNvbFtpXSA9IHBhc3RlKGdlb19jYXRlZ19zb2NpbyRyZWdpb25bY2F0ZWdfc29jaW8kdG90YWxfaW1taWcgJWluJSBSYW5rMTBbaV1dICkNCn0NCg0KIyBBZGp1c3Qgc2NhbGVzIGJlZm9yZSBwbG90dGluZyANCnNjIDwtIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oY29sb3VycyA9IGMoIiNGODc2NkQiLCAgIiMwMEJBMzgiKSwgbGltaXRzPWMobWluKGdlb19jYXRlZ19zb2NpbyR0b3RhbF9pbW1pZy9wb3B1bGF0aW9uJHRvdGFsX3BvcHVsYXRpb24pLCBtYXgoZ2VvX2NhdGVnX3NvY2lvJHRvdGFsX2ltbWlnL3BvcHVsYXRpb24kdG90YWxfcG9wdWxhdGlvbikpKSANCiANCiMgTWFwIHJhdGlvICANCmRpc3RyaWJ1dGlvbl9pbW1pZyA8LSANCiAgRnJhTWFwICsgDQogIGdlb21fcG9pbnQoYWVzKHg9Z2VvX2NhdGVnX3NvY2lvJGxvbmdpdHVkZSwgeT1nZW9fY2F0ZWdfc29jaW8kbGF0aXR1ZGUsIA0KICAgICAgICAgICAgICAgICBjb2xvdXI9Z2VvX2NhdGVnX3NvY2lvJHRvdGFsX2ltbWlnL3BvcHVsYXRpb24kdG90YWxfcG9wdWxhdGlvbiksIA0KICAgICAgICAgICAgIGRhdGE9Z2VvX2NhdGVnX3NvY2lvLCBhbHBoYT0xLCBzaXplPTEpICsgDQogICAgICAgICAgICAgc2MgKyBsYWJzKGNvbG9yPScnKSArIGdndGl0bGUoIkltbWlncmFudHMgZm9yIGVhY2ggdG93biIpIA0KZGlzdHJpYnV0aW9uX2ltbWlnDQoNCnJtKGdlb19jYXRlZ19zb2NpbykNCmBgYA0KDQojIyMgV2hhdCB3ZSBoYXZlIGxlYXJuZWQNCg0KQ2l0eSB3aXRoIHRoZSBsZWFzdCBudW1iZXIgb2YgaW1taWdyYW50cyBpcyBSZW5uZXMgYW5kIHRoZSBtb3N0IGlzIFBhcmlzLg0KPSLDjmxlLWRlLUZyYW5jZSIgICAgICAgICAgICAgICJQcm92ZW5jZS1BbHBlcy1Dw7R0ZSBkJ0F6dXIiICJSaMO0bmUtQWxwZXMiICAgICAgICAgICAgICAgICJNaWRpLVB5csOpbsOpZXMiICAgICAgICAgICAgIA0KIlByb3ZlbmNlLUFscGVzLUPDtHRlIGQnQXp1ciIgIkFsc2FjZSIgICAgICAgICAgICAgICAgICAgICAiTGFuZ3VlZG9jLVJvdXNzaWxsb24iICAgICAgICLDjmxlLWRlLUZyYW5jZSIgICAgICAgICAgICAgDQoiw45sZS1kZS1GcmFuY2UiICAgICAgICAgICAgICAiw45sZS1kZS1GcmFuY2UiICAgICAgICAgICAgIA0KDQoNCiMjIFdvcmsgc3RhdHVzIGRhdGENCg0KYGBge3IgZGVzY3JpcHRpdmUgc3RhdHMgc3RhdHVzX3dvcmt9DQoNCnN1bW1hcnkoc3RhdHVzX3dvcmspDQpuYW1lcyhzdGF0dXNfd29yaykgDQoNCiMgbWVyZ2UgZ2VvIGFuZCBzdGF0dXNfd29yaw0KIyBnZW9fc3RhdHVzX3dvcmsgPC0gY2JpbmQuZGF0YS5mcmFtZShnZW9bdW5pcXVlKGdlbyRDT0RHRU8pICVpbiUgdW5pcXVlKHN0YXR1c193b3JrJENPREdFTyksXSwNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0dXNfd29ya1t1bmlxdWUoc3RhdHVzX3dvcmskQ09ER0VPKSAlaW4lIHVuaXF1ZShnZW8kQ09ER0VPKSxdKQ0KZ2VvX3N0YXR1c193b3JrIDwtIGNiaW5kLmRhdGEuZnJhbWUoZ2VvW3VuaXF1ZShnZW8kQ09ER0VPKSAlaW4lIHVuaXF1ZShzdGF0dXNfd29yayRDT0RHRU8pLF0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdHVzX3dvcmtbdW5pcXVlKHN0YXR1c193b3JrJENPREdFTykgJWluJSB1bmlxdWUoZ2VvJENPREdFTyksXSkgDQoNCg0KIyB3aGljaCB0b3duIGhhcyB0aGUgbW9zdC9sZWFzdCBwZW9wbGUgcmVjZWl2aW5nIGdvdmVybm1lbnQgdHJhbnNmZXJzDQpzdGF0dXNfd29ya1t3aGljaC5tYXgoc3RhdHVzX3dvcmskdHJhbnNmZXIpLGMoJ0NPREdFTycpXSANCnN0YXR1c193b3JrW3doaWNoLm1pbihzdGF0dXNfd29yayR0cmFuc2ZlciksYygnQ09ER0VPJyldIA0KDQojIGdldCBsaXN0IG9mIHRvcCAxMCBjaXRpZXMgd2l0aCB0aGUgcGVvcGxlIHJlY2VpdmluZyBnb3Zlcm5tZW50IHRyYW5zZmVycw0KUmFuayA9IHNvcnQoc3RhdHVzX3dvcmskdHJhbnNmZXIsIFRSVUUpDQpSYW5rMTAgPSBzb3J0KFJhbmtbMToxMF0sIFRSVUUpDQpzb2wgPSByZXAoMCwgMTApDQpmb3IgKGkgaW4gMToxMCl7DQogICAgc29sW2ldID0gcGFzdGUoZ2VvX3N0YXR1c193b3JrJENPREdFT1tzdGF0dXNfd29yayR0cmFuc2ZlciAlaW4lIFJhbmsxMFtpXV0pDQp9DQoNCiMgd2hpY2ggdG93biBoYXMgdGhlIG1vc3QvbGVhc3QgcGVvcGxlIHdpdGggcGFydCB0aW1lIGNvbnRyYWN0Lg0Kc3RhdHVzX3dvcmtbd2hpY2gubWF4KHN0YXR1c193b3JrJGhhbGYpLGMoJ0NPREdFTycpXSANCnN0YXR1c193b3JrW3doaWNoLm1pbihzdGF0dXNfd29yayRoYWxmKSxjKCdDT0RHRU8nKV0gDQoNCiMgZ2V0IGxpc3Qgb2YgdG9wIDEwIGNpdGllcyB3aXRoIHRoZSBtb3N0IHBhcnQtdGltZSBjb250cmFjdC4NClJhbmsgPSBzb3J0KHN0YXR1c193b3JrJGhhbGYsIFRSVUUpDQpSYW5rMTAgPSBzb3J0KFJhbmtbMToxMF0sIFRSVUUpDQpzb2wgPSByZXAoMCwgMTApDQpmb3IgKGkgaW4gMToxMCl7DQogICAgc29sW2ldID0gcGFzdGUoc3RhdHVzX3dvcmskQ09ER0VPW3N0YXR1c193b3JrJGhhbGYgJWluJSBSYW5rMTBbaV1dICkgDQp9DQoNCg0KIyBIaXN0b2dyYW0gKEZlbWFsZXMgd2l0aCBmdWxsIHRpbWUgY29udHJhY3QpDQpkZXNjcmliZShzdGF0dXNfd29yayRmdWxsX0YpICAgICMgU2tld25lc3MNCg0KZ2dwbG90KGRhdGE9c3RhdHVzX3dvcmssIGFlcyhpZmVsc2UoZnVsbF9GIT0wLCBsb2coZnVsbF9GKSwgMCkpKSArDQogIGdlb21faGlzdG9ncmFtKGFlcyh5ID0uLmRlbnNpdHkuLiksIGNvbD0iYmxhY2siLCBmaWxsPSJibHVlIiwgYWxwaGEgPSAuMywgYmlucyA9IDUwKSArDQogIGdlb21fZGVuc2l0eShjb2w9ImJsYWNrIikgKw0KICBsYWJzKHg9IiIsIHk9IkRlbnNpdHkiKSArDQogIGdndGl0bGUoIkZlbWFsZSB3b3JrZXJzIHdpdGggZnVsbCB0aW1lIGNvbnRyYWN0IikgKyANCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpDQoNCiMgSGlzdG9ncmFtIChtYWxlcyB3aXRoIGZ1bGwgdGltZSBjb250cmFjdCkgDQpkZXNjcmliZShzdGF0dXNfd29yayRmdWxsX00pICAgICMgU2tld25lc3MgDQoNCmdncGxvdChkYXRhPXN0YXR1c193b3JrLCBhZXMoaWZlbHNlKGZ1bGxfTSE9MCwgbG9nKGZ1bGxfTSksIDApKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9Li5kZW5zaXR5Li4pLCBjb2w9ImJsYWNrIiwgZmlsbD0iYmx1ZSIsIGFscGhhID0gLjMsIGJpbnMgPSA1MCkgKw0KICBnZW9tX2RlbnNpdHkoY29sPSJibGFjayIpICsNCiAgbGFicyh4PSIiLCB5PSJEZW5zaXR5IikgKw0KICBnZ3RpdGxlKCJNYWxlIHdvcmtlcnMgd2l0aCBmdWxsIHRpbWUgY29udHJhY3QiKSArIA0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkNCg0KIyBIaXN0b2dyYW06IENvbnRyYWN0IHR5cGUgcmF0aW8NCmRlc2NyaWJlKHN0YXR1c193b3JrJGhhbGYvc3RhdHVzX3dvcmskZnVsbCkgICAgIyBTa2V3bmVzcw0KDQpnZ3Bsb3QoZGF0YT1zdGF0dXNfd29yaywgYWVzKHN0YXR1c193b3JrJGhhbGYvc3RhdHVzX3dvcmskZnVsbCkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPS4uZGVuc2l0eS4uKSwgY29sPSJibGFjayIsIGZpbGw9ImJsdWUiLCBhbHBoYSA9IC4zLCBiaW5zID0gNTApICsNCiAgZ2VvbV9kZW5zaXR5KGNvbD0iYmxhY2siKSArDQogIGxhYnMoeD0iQ29udHJhY3QgdHlwZSByYXRpbyAodGVtcG9yYXJ5L2Z1bGwgdGltZSkiLCB5PSJEZW5zaXR5IikgKw0KICBnZ3RpdGxlKCJDb250cmFjdCB0eXBlIHJhdGlvIikgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkNCg0KYGBgDQoNCmBgYHtyIEJveCBwbG90fQ0KIyAgbnVtYmVyIG9mIHVuaXRzDQpuX3NleCA8LSBsZW5ndGgoc3RhdHVzX3dvcmskd2FnZWFybmVyX0YpDQoNCiMgdmVjdG9yIHJlcHJlc2VudGluZyBtYWxlcyBhbmQgZmVtYWxlcw0KTGFiZWwgPC0gYyhyZXAoIk0iLCBuX3NleCo2KSwgcmVwKCJGIiwgbl9zZXgqNikpDQoNCiMgdmVjdG9yIHJlcHJlc2VudGluZyB0aGUgdmFyaWFibGUgY29uc2lkZXJlZA0KVmFyaWFibGUgPC0gYyhyZXAoIldhZ2Vhcm5lciIsIG5fc2V4KSwgDQogICAgICAgICAgICAgcmVwKCJJbmRlcGVuZGVudCIsIG5fc2V4KSwNCiAgICAgICAgICAgICByZXAoIlRyYW5zZmVyIiwgbl9zZXgpLA0KICAgICAgICAgICAgIHJlcCgiRW1wbG95ZXIiLCBuX3NleCksDQogICAgICAgICAgICAgcmVwKCJGdWxsIixuX3NleCksDQogICAgICAgICAgICAgcmVwKCJIYWxmIiwgbl9zZXgpKQ0KICAgICAgICAgICAgIA0KIyBtZXJnZSB0aGVzZSBkYXRhDQpzdGF0dXNfc2V4ID0gY2JpbmQuZGF0YS5mcmFtZShMYWJlbCA9IExhYmVsLCANCiAgICAgICAgICAgICB2YWx1ZSA9IGMoc3RhdHVzX3dvcmskd2FnZWFybmVyX00sIHN0YXR1c193b3JrJHdhZ2Vhcm5lcl9GLCBzdGF0dXNfd29yayRpbmRlcGVuZGVudF9NLA0KICAgICAgICAgICAgICAgICAgICAgICBzdGF0dXNfd29yayRpbmRlcGVuZGVudF9GLCBzdGF0dXNfd29yayR0cmFuc2Zlcl9NLCBzdGF0dXNfd29yayR0cmFuc2Zlcl9GLA0KICAgICAgICAgICAgICAgICAgICAgICBzdGF0dXNfd29yayRlbXBsb3llcl9NLCBzdGF0dXNfd29yayRlbXBsb3llcl9GLCBzdGF0dXNfd29yayRmdWxsX00sIHN0YXR1c193b3JrJGZ1bGxfRiwNCiAgICAgICAgICAgICAgICAgICAgICAgc3RhdHVzX3dvcmskaGFsZl9NLCBzdGF0dXNfd29yayRoYWxmX0YpLA0KICAgICAgICAgICAgIFZhcmlhYmxlID0gVmFyaWFibGUpDQoNCiMgcGxvdHRpbmcgcGhhc2UNCmdncGxvdChkYXRhID0gc3RhdHVzX3NleCwgYWVzKHg9TGFiZWwsIHk9dmFsdWUpKSArDQogIGdlb21fYm94cGxvdChhZXMoZmlsbCA9IExhYmVsKSkgKw0KICBnZW9tX3BvaW50KGFlcyh5PXZhbHVlLCBjb2xvdXI9TGFiZWwpLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoPTAuNzUpKSArDQogIGZhY2V0X3dyYXAoIH4gVmFyaWFibGUsIHNjYWxlcz0iZnJlZSIpICsNCiAgeGxhYigiU2V4IikgKyB5bGFiKCIjIG9mIGluZGl2aWR1YWxzIikgKyBnZ3RpdGxlKCJHZW5kZXIgY29tcGFyaXNvbiIpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsNCiAgc3RhdF9ib3hwbG90KGdlb20gPSAiZXJyb3JiYXIiLCB3aWR0aCA9IDAuNSkNCg0KDQojIHRoZSBzYW1lIGJ1dCBleGNsdWRpbmcgb3V0bGllcnMNCmdncGxvdChkYXRhID0gc3RhdHVzX3NleCwgYWVzKHg9TGFiZWwsIHk9dmFsdWUpKSArDQogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBxdWFudGlsZShzdGF0dXNfc2V4JHZhbHVlLCBjKDAsIDAuOSkpKSArDQogIGdlb21fYm94cGxvdChhZXMoZmlsbCA9IExhYmVsKSkgKw0KICBnZW9tX3BvaW50KGFlcyh5PXZhbHVlLCBjb2xvdXI9TGFiZWwpLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoPTAuNzUpKSArDQogIGZhY2V0X3dyYXAoIH4gVmFyaWFibGUsIHNjYWxlcz0iZnJlZSIpICsNCiAgeGxhYigiU2V4IikgKyB5bGFiKCIjIG9mIGluZGl2aWR1YWxzIikgKyANCiAgZ2d0aXRsZSgiR2VuZGVyIGNvbXBhcmlzb24gZXhjbHVkaW5nIHRoZSBsYXN0IGRlY2lsZSIpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsNCiAgc3RhdF9ib3hwbG90KGdlb20gPSAiZXJyb3JiYXIiLCB3aWR0aCA9IDAuNSkNCmBgYA0KDQojIyMgV2hhdCB3ZSBoYXZlIGxlYXJuZWQNCg0KUGFyaXMgaXMgdGhlIGNpdHkgd2hlcmUgdGhleSBoYXZlIHRoZSBtb3N0IGluZGl2aWR1YWxzIHJlY2VpdmluZyBnb3Zlcm5tZW50IHRyYW5zZmVycy4NCkx5b24gaXMgdGhlIGNpdHkgd2hlcmUgdGhleSBoYXZlIHRoZSBsZWFzdCBpbmRpdmlkdWFscyByZWNlaXZpbmcgZ292ZXJubWVudCB0cmFuc2ZlcnMuDQo9IsOObGUtZGUtRnJhbmNlIiAgICAgICAgICAgICAgIlByb3ZlbmNlLUFscGVzLUPDtHRlIGQnQXp1ciIgIlByb3ZlbmNlLUFscGVzLUPDtHRlIGQnQXp1ciIgIlJow7RuZS1BbHBlcyIgICAgICAgICAgICAgICANCiJNaWRpLVB5csOpbsOpZXMiICAgICAgICAgICAgICAiQXF1aXRhaW5lIiAgICAgICAgICAgICAgICAgICJMYW5ndWVkb2MtUm91c3NpbGxvbiIgICAgICAgIlBheXMgZGUgbGEgTG9pcmUiICAgICAgICAgIA0KIlJow7RuZS1BbHBlcyIgICAgICAgICAgICAgICAgIkFsc2FjZSIgICAgICAgICAgICAgICAgICAgIA0KDQpQYXJpcyBoYXMgbW9zdCBpbmRpdmlkdWFscyB3aXRoIGhhbGYgdGltZSBjb250cmFjdC4gDQpSb3VlbiBoYXMgdGhlIGxlYXN0LiANCj0gIsOObGUtZGUtRnJhbmNlIiAgICAgICAgICAgICAgIlJow7RuZS1BbHBlcyIgICAgICAgICAgICAgICAgIlByb3ZlbmNlLUFscGVzLUPDtHRlIGQnQXp1ciIgIk1pZGktUHlyw6luw6llcyIgICAgICAgICAgICAgDQoiUGF5cyBkZSBsYSBMb2lyZSIgICAgICAgICAgICJOb3JkLVBhcy1kZS1DYWxhaXMiICAgICAgICAgIkFsc2FjZSIgICAgICAgICAgICAgICAgICAgICAiTGFuZ3VlZG9jLVJvdXNzaWxsb24iICAgICAgDQoiQXF1aXRhaW5lIiAgICAgICAgICAgICAgICAgICJCcmV0YWduZSIgICAgDQoNCkluIGF2ZXJhZ2UsIG1vcmUgZmVtYWxlcyByZWNlaXZlIHRyYW5zZmVycyB0aGFuIG1hbGVzLiANCkluIGF2ZXJhZ2UsIG1vcmUgZmVtYWxlcyBoYXZlIHBhcnQtdGltZSBjb250cmFjdCB0aGFuIG1hbGVzLiAoSW4gYXZlcmFnZSwgNTgxIGZlbWFsZXMgaGF2ZSBwYXJ0LXRpbWUgY29udHJhY3QgKGluIGVhY2ggdG93bikgYW5kIDE3OCBtYWxlcyBoYXZlIHBhcnQtdGltZSBjb250cmFjdC4gKE1vcmUgbWFsZXMgaGF2ZSBmdWxsLXRpbWUgY29udHJhY3QuKQ0KDQpNb3JlIGZlbWFsZXMgd29yayBhcyB3YWdlLWVhcm5lcnMgdGhhbiBtYWxlcy4NCj1BbGwgdGhlc2UgZmFjdHMgY2FuIGJlIHJlbGF0ZWQgdG8gdnVsbmVyYWJpbGl0eSBvZiBmZW1hbGVzIGluIHRoZSBsYWJvdXIgbWFya2V0LiBNYW55IHN0dWRpZXMgc2hvdyB0aGF0IGZlbWFsZXMgYXJlIG1vc3RseSB3b3JraW5nIGFzIHBhcnQtdGltZSB3b3JrZXJzIGFuZCBsb3dlciBqb2IgY2F0ZWdvcmllcy4gT24gdG9wIG9mIHRoaXMsIG1vcmUgZmVtYWxlcyByZWNlaXZlIHRyYW5zZmVycy4NCldlIGNhbiBhbHNvIG9ic2VydmUgdGhpcyBpbiBvdXIgZGF0YSB0aGF0IG1vcmUgbWFsZXMgYXJlIHJlZ2lzdGVyZWQgYXMgaW5kZXBlbmRlbnQgd29ya2VycyBvciBlbXBsb3llcnMuIA0KDQojIyBJbmVxdWFsaXR5IGRhdGENCg0KYGBge3IgZGVzY3JpcHRpdmUgc3RhdGlzdGljcyBJbmVxdWFsaXR5IGRhdGF9DQpnbGltcHNlKGluZXEpDQoNCiMgbWVyZ2UgZ2VvIGFuZCBpbmVxDQpnZW9faW5lcSA8LSBjYmluZC5kYXRhLmZyYW1lKGdlb1t1bmlxdWUoZ2VvJENPREdFTykgJWluJSB1bmlxdWUoaW5lcSRDT0RHRU8pLF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluZXFbdW5pcXVlKGluZXEkQ09ER0VPKSAlaW4lIHVuaXF1ZShnZW8kQ09ER0VPKSxdKQ0KDQojIHdoaWNoIGNpdHkgaGFzIHRoZSBoaWdoZXN0L2xvd2VzdCB1bmVtcGxveW1lbnQgcmF0ZQ0KaW5lcVt3aGljaC5tYXgoaW5lcSR1bmVtcF9yYXRlKSxjKCdDT0RHRU8nKV0gDQppbmVxW3doaWNoLm1pbihpbmVxJHVuZW1wX3JhdGUpLGMoJ0NPREdFTycpXSANCg0KIyBnZXQgbGlzdCBvZiB0b3AgMTAgY2l0aWVzIHdpdGggdGhlIGhpZ2hlc3QgdW5lbXBsb3ltZW50IHJhdGUuDQpSYW5rID0gc29ydChpbmVxJHVuZW1wX3JhdGUsIFRSVUUpDQpSYW5rMTAgPSBzb3J0KFJhbmtbMToxMF0sIFRSVUUpDQpzb2wgPSByZXAoMCwgMTApDQpmb3IgKGkgaW4gMToxMCl7DQogICAgc29sW2ldID0gcGFzdGUoaW5lcSRDT0RHRU9baW5lcSR1bmVtcF9yYXRlICVpbiUgUmFuazEwW2ldXSApIA0KfQ0KDQojIHdoaWNoIGlzIHRoZSBzbWFsbGVzdC9iaWdnZXN0IGNpdHkgKGFyZWEpDQppbmVxW3doaWNoLm1heChpbmVxJFN1cGVyZmljaWUpLGMoJ0NPREdFTycpXSANCmluZXFbd2hpY2gubWluKGluZXEkU3VwZXJmaWNpZSksYygnQ09ER0VPJyldIA0KDQojIHdoaWNoIGNpdHkgaGFzIHRoZSBoaWdoZXN0L2xvd2VzdCBtZWRpYW4gbGl2aW5nIGxldmVsDQppbmVxW3doaWNoLm1heChpbmVxJG1lZGlhbl9saXZpbmcxNCksYygnQ09ER0VPJyldIA0KaW5lcVt3aGljaC5taW4oaW5lcSRtZWRpYW5fbGl2aW5nMTQpLGMoJ0NPREdFTycpXSANCg0KIyBBZGp1c3Qgc2NhbGVzIGJlZm9yZSBwbG90dGluZw0Kc2MgPC0gc2NhbGVfY29sb3VyX2dyYWRpZW50bihjb2xvdXJzID0gYygiIzU2ZGRjNSIsICIjZmYzZGI3IiksIGxpbWl0cz1jKG1pbihpbmVxJHVuZW1wX3JhdGUpLCBtYXgoaW5lcSR1bmVtcF9yYXRlKSkpDQoNCiMgTWFwIHJhdGlvIA0KaW5lcV91bmVtcGxfZGlzdHJpYnV0aW9uIDwtDQogIEZyYU1hcCArDQogIGdlb21fcG9pbnQoYWVzKHg9Z2VvX2luZXEkbG9uZ2l0dWRlLCB5PWdlb19pbmVxJGxhdGl0dWRlLA0KICAgICAgICAgICAgICAgICBjb2xvdXI9Z2VvX2luZXEkdW5lbXBfcmF0ZSksDQogICAgICAgICAgICAgZGF0YT1nZW9faW5lcSwgYWxwaGE9MSwgc2l6ZT0xKSArDQogICAgICAgICAgICAgc2MgKyBsYWJzKGNvbG9yPSdVbmVtcGxveW1lbnQgcmF0ZScpICsgZ2d0aXRsZSgiVW5lbXBsb3ltZW50IHJhdGUgZm9yIGVhY2ggdG93biIpDQppbmVxX3VuZW1wbF9kaXN0cmlidXRpb24NCg0KIyByZW1vdmUgdGhlIGRhdGFzZXQgY3JlYXRlZCB0byBzYXZlIG1lbW9yeQ0Kcm0obGlzdD1jKCJnZW9faW5lcSIsICJpbmVxX3VuZW1wbF9kaXN0cmlidXRpb24iKSkNCg0KYGBgDQoNCiMjIyBXaGF0IHdlIGhhdmUgbGVhcm5lZA0KDQpCb3JkZWF1eCBoYXMgdGhlIGhpZ2hlc3QgdW5lbXBsb3ltZW50IHJhdGUuDQpOYW50ZXMgaGFzIHRoZSBsb3dlc3QgdW5lbXBsb3ltZW50IHJhdGUuIA0KPSJBcXVpdGFpbmUiICAgICAgICAgICAgIkxhbmd1ZWRvYy1Sb3Vzc2lsbG9uIiAiTm9yZC1QYXMtZGUtQ2FsYWlzIiAgICJIYXV0ZS1Ob3JtYW5kaWUiICAgICAgIkd1YWRlbG91cGUiICAgICAgICAgIA0KIkNvcnNlIiAgICAgICAgICAgICAgICAiTm9yZC1QYXMtZGUtQ2FsYWlzIiAgICJDb3JzZSIgICAgICAgICAgICAgICAgIlJow7RuZS1BbHBlcyIgICAgICAgICAgIk5vcmQtUGFzLWRlLUNhbGFpcyIgDQoNCiMjIENvbW11bmUgZGF0YQ0KDQpgYGB7ciBkZXNjcmlwdGl2ZSBzdGF0aXN0aWNzIENvbW11bmUgZGF0YX0NCmdsaW1wc2UoY29tbXVuZSkNCg0KIyBjaGFuZ2UgdGhlIGZhY3RvciB2YXJpYWJsZXMgdG8gbnVtZXJpYw0KIyBhYWEgPSBhcy5udW1lcmljKGNvbW11bmUkdXJiYW5SdXJhbCkNCg0KIyBNZXJnZSBnZW8gYW5kIGNvbW11bmUgZGF0YSB0byBpbmNsdWRlIGxvbmdpdHVkZSBhbmQgbGF0aXR1ZGUgaW4gdGhlIGRhdGEuDQpnZW9fY29tbXVuZSA8LSBjYmluZC5kYXRhLmZyYW1lKGdlb1t1bmlxdWUoZ2VvJENPREdFTykgJWluJSB1bmlxdWUoY29tbXVuZSRDT0RHRU8pLF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbW11bmVbdW5pcXVlKGNvbW11bmUkQ09ER0VPKSAlaW4lIHVuaXF1ZShnZW8kQ09ER0VPKSxdKQ0KDQoNCiMgQWRqdXN0IHNjYWxlcyBiZWZvcmUgcGxvdHRpbmcNCiNzYyA8LSBzY2FsZV9jb2xvdXJfZ3JhZGllbnRuKGNvbG91cnMgPSBwYWxldHRlKHJhaW5ib3coMykpLCBsaW1pdHM9YyhtaW4oYWFhKSwgbWF4KGFhYSkpKQ0KDQojIE1hcCByYXRpbyANCiAjIHVyYmFucnVyYWw8LQ0KICMgIEZyYU1hcCArDQogIyAgZ2VvbV9wb2ludChhZXMoeD1nZW9fY29tbXVuZSRsb25naXR1ZGUsIHk9Z2VvX2NvbW11bmUkbGF0aXR1ZGUsDQogIyAgICAgICAgICAgICAgICAgY29sb3VyPWFhYSksDQogIyAgICAgICAgICAgICBkYXRhPWdlb19jb21tdW5lLCBhbHBoYT0xLCBzaXplPTAuNSkgKw0KICMgICAgICAgICAgICAgc2MgKyBsYWJzKGNvbG9yPScnKSArIGdndGl0bGUoIlVyYmFuIGFuZCBydXJhbCBjaXRpZXMiKQ0KIyB1cmJhbnJ1cmFsDQoNCiMgYm94cGxvdA0KIyAgbnVtYmVyIG9mIHVuaXRzDQpuX2Zpcm1zIDwtIGxlbmd0aChjb21tdW5lJG5iX2Zpcm1zX2NvbW1lcmNlKQ0KDQojIHZlY3RvciANCkxhYmVsIDwtIGMocmVwKCJGaXJtcyIsIG5fZmlybXMqNCkpDQoNCiMgdmVjdG9yIHJlcHJlc2VudGluZyB0aGUgdmFyaWFibGUgY29uc2lkZXJlZA0KVmFyaWFibGUgPC0gYyhyZXAoIlNlcnZpY2UiLCBuX2Zpcm1zKSwgDQogICAgICAgICAgICAgcmVwKCJJbmR1c3RyeSIsIG5fZmlybXMpLA0KICAgICAgICAgICAgIHJlcCgiQ29tbWVyY2UiLCBuX2Zpcm1zKSwNCiAgICAgICAgICAgICByZXAoIkNvbnN0cnVjdGlvbiIsIG5fZmlybXMpKQ0KICAgICAgICAgIA0KICAgICAgICAgICAgIA0KIyBtZXJnZSB0aGVzZSBkYXRhDQpmaXJtc19zZWN0b3IgPSBjYmluZC5kYXRhLmZyYW1lKExhYmVsID0gTGFiZWwsIA0KICAgICAgICAgICAgIHZhbHVlID0gYyhjb21tdW5lJG5iX2Zpcm1zX2NvbW1lcmNlLCBjb21tdW5lJG5iX2Zpcm1zX3NlcnZpY2UsIGNvbW11bmUkbmJfZmlybXNfaW5kLCBjb21tdW5lJG5iX2Zpcm1zX2NvbnN0cnVjdGlvbiksDQogICAgICAgICAgICAgVmFyaWFibGUgPSBWYXJpYWJsZSkNCg0KIyBwbG90dGluZyBwaGFzZQ0KZ2dwbG90KGRhdGEgPSBmaXJtc19zZWN0b3IsIGFlcyh4PUxhYmVsLCB5PXZhbHVlKSkgKw0KICBnZW9tX2JveHBsb3QoYWVzKGZpbGwgPSBMYWJlbCkpICsNCiAgZ2VvbV9wb2ludChhZXMoeT12YWx1ZSwgY29sb3VyPUxhYmVsKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aD0wLjc1KSkgKw0KICBmYWNldF93cmFwKCB+IFZhcmlhYmxlLCBzY2FsZXM9ImZyZWUiKSArDQogIHhsYWIoIkZpcm1zIikgKyB5bGFiKCIjIG9mIGZpcm1zIikgKyBnZ3RpdGxlKCJTZWN0b3IgY29tcGFyaXNvbiIpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsNCiAgc3RhdF9ib3hwbG90KGdlb20gPSAiZXJyb3JiYXIiLCB3aWR0aCA9IDAuNSkNCg0KDQojIHRoZSBzYW1lIGJ1dCBleGNsdWRpbmcgb3V0bGllcnMNCmdncGxvdChkYXRhID0gZmlybXNfc2VjdG9yLCBhZXMoeD1MYWJlbCwgeT12YWx1ZSkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IHF1YW50aWxlKGZpcm1zX3NlY3RvciR2YWx1ZSwgYygwLCAwLjkpKSkgKw0KICBnZW9tX2JveHBsb3QoYWVzKGZpbGwgPSBMYWJlbCkpICsNCiAgZ2VvbV9wb2ludChhZXMoeT12YWx1ZSwgY29sb3VyPUxhYmVsKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aD0wLjc1KSkgKw0KICBmYWNldF93cmFwKCB+IFZhcmlhYmxlLCBzY2FsZXM9ImZyZWUiKSArDQogIHhsYWIoIkZpcm1zIikgKyB5bGFiKCIjIG9mIGZpcm1zIikgKyANCiAgZ2d0aXRsZSgiU2VjdG9yIGNvbXBhcmlzb24gZXhjbHVkaW5nIHRoZSBsYXN0IGRlY2lsZSIpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsNCiAgc3RhdF9ib3hwbG90KGdlb20gPSAiZXJyb3JiYXIiLCB3aWR0aCA9IDAuNSkNCg0KDQpybShsaXN0ID0gYygiZ2VvX2NvbW11bmUiLCAiUmFuayIsICJSYW5rMTAiLCAiYWFhIikpDQpgYGANCg0KDQojIENyZWF0ZSBhbiB1bmlxdWUgZGF0YXNldA0KDQpDcmVhdGUgYW4gdW5pcXVlIGRhdGFzZXQ6DQpgYGB7ciBNZXJnZSB0aGUgZGF0YSBhbmQgY3JlYXRlIGNzdiBmaWxlfQ0KDQojIG1lcmdpbmcNCm5ld0RhdCA9IG1lcmdlKGZpcm1zLCBwb3B1bGF0aW9uLCBieT0iQ09ER0VPIikNCm5ld0RhdCA9IG1lcmdlKG5ld0RhdCwgc2FsYXJ5LCBieT0iQ09ER0VPIikNCm5ld0RhdCA9IG1lcmdlKG5ld0RhdCwgZ2VvLCBieT0iQ09ER0VPIikNCm5ld0RhdCA9IG1lcmdlKG5ld0RhdCwgc3RhdHVzX3dvcmssIGJ5PSJDT0RHRU8iKQ0KbmV3RGF0ID0gbWVyZ2UobmV3RGF0LCBpbmVxLCBieT0iQ09ER0VPIikNCm5ld0RhdCA9IG1lcmdlKG5ld0RhdCwgZWR1YywgYnk9IkNPREdFTyIpDQpuZXdEYXQgPSBtZXJnZShuZXdEYXQsIGNhdGVnX3NvY2lvLCBieT0iQ09ER0VPIikNCm5ld0RhdCA9IG1lcmdlKG5ld0RhdCwgY29tbXVuZSwgYnk9IkNPREdFTyIpDQoNCiMgY2hlY2sNCm5hbWVzKG5ld0RhdCkNCmhlYWQobmV3RGF0KQ0KDQpgYGANCg0KU2F2ZS9sb2FkIGZpbmFsIGRhdGFzZXQgKGp1c3QgdG8gYXZvaWQgcnVubmluZyBhbGwgdGhlIGNvZGUpIA0KYGBge3IgU2F2ZS9sb2FkIGZpbmFsIGRhdGFzZXQsIHdhcm5pbmc9RkFMU0V9IA0KDQojIyBVTkNPTU1FTlQgVEhFU0UgTElORSBBTkQgQ09NTUVOVCBUSEUgTkVYVCBPTkVTIFRPIFNBVkUgVEhFIERBVEFTRVQNCiMjIFRIRU4gTU9WRSBUSElTIEZJTEUgSU4gVEhFIGRhdGEgRk9MREVSDQojICNyZW1vdmUgdW51c2VkIGZhY3RvciBsZXZlbHMgb24gbmV3RGF0DQojIGZvciAoaSBpbiAxOm5jb2wobmV3RGF0KSl7DQojICAgaWYgKGlzLmZhY3RvcihuZXdEYXRbLGldKSl7DQojICAgICBuZXdEYXRbLGldID0gZHJvcGxldmVscy5mYWN0b3IobmV3RGF0WyxpXSkNCiMgICB9DQojIH0NCiMgIyBzYXZlIHRoZSBOZXdEYXQuY3N2IGZpbGUgY3JlYXRlZCAod2hpY2ggaGFzIHRvIGJlIG1vdmVkIGluIHRoZSBkYXRhIGZvbGRlcikNCiMgd3JpdGUudGFibGUobmV3RGF0LCAibmV3RGF0LmNzdiIsIHF1b3RlID0gVFJVRSwgcm93Lm5hbWVzPUZBTFNFLCBjb2wubmFtZXMgPSBUUlVFLA0KIyAgICAgICAgICAgZmlsZUVuY29kaW5nID0gIlVURi04Iiwgc2VwID0gIiwiKQ0KIA0KIyMgTE9BRElORyBEQVRBDQojIGxvYWQgdGhlIGZpbmFsIGRhdGFzZXQNCnNldHdkKCIuL2RhdGEiKQ0KbmV3RGF0IDwtIHJlYWQuY3N2KCJuZXdEYXQuY3N2IiwgZW5jb2RpbmcgPSAiVVRGLTgiLCBoZWFkZXIgPSBUUlVFKQ0KDQojIEpVU1QgQSBDSEVDSywgRE8gTk9UIE5FRUQgVE8gUlVODQojIGNoZWNrIChjaGFuZ2luZyBuZXdEYXQgbG9hZGVkIHdpdGggbmV3RGF0MiksIHRoZSBvbmx5IGRpZmZlcmVuY2VzIGFyZSBpbiB0aGUgb3JkZXIgb2YgMTBlLTE1DQojIGlkZW50aWNhbChuZXdEYXQsIG5ld0RhdDIpDQogDQpgYGANCg0KU3BhdGlhbCBwbG90IG9mIHRoZSBkYXRhIHRvIHNwb3QgcG9zc2libGUgcGF0dGVybnMuIA0KQSBzdWItc2FtcGxlIHdpbGwgYmUgcmV0YWluZWQgd2hlbiBuZWVkZWQgaW4gb3JkZXIgdG8gcmVkdWNlIA0KZ2VvLXNwYXRpYWwgY29ycmVsYXRpb25zLiANCmBgYHtyIG5ld0RhdCBzcGF0aWFsIHBsb3R9IA0KDQojIGNlbnRlciBvZiBGcmFuY2UsIG9idGFpbmVkIHVzaW5nOiANCiMgZnJhX2NlbnRlciA9IGFzLm51bWVyaWMoZ2VvY29kZSgiRnJhbmNlIikpIA0KZnJhX2NlbnRlciA9IGMoMi4yMTM3NDksIDQ2LjIyNzYzOCkgDQogDQpnZ21hcChnZXRfZ29vZ2xlbWFwKGNlbnRlcj1mcmFfY2VudGVyLCBzY2FsZT0yLCB6b29tPTUpLCBleHRlbnQ9Im5vcm1hbCIpICsgDQogIGdlb21fcG9pbnQoYWVzKHg9bG9uZ2l0dWRlLCB5PWxhdGl0dWRlKSwgZGF0YT1uZXdEYXQsIGNvbD0ib3JhbmdlIiwgYWxwaGE9MSwgc2l6ZT0wLjA1KSAgDQogDQpgYGAgDQogDQoNCiMgVW5zdXBlcnZpc2VkIExlYXJuaW5nDQoNCiMjIE11bHRpLURpbWVuc2lvbmFsIFNjYWxpbmcgKE1EUykNCg0KIyMjIFByZWxpbWluYXJ5IG11bHRpdmFyaWF0ZSBkYXRhIHZpc3VhbGlzYXRpb24gdG8gYmV0dGVyIGNvbmR1Y3QgdGhlIHVuc3VwZXJ2aXNlZCBsZWFybmluZyAgDQpgYGB7cn0NCg0KcmVnaW9uIDwtIGdlbyRyZWdpb24NCg0KIyBhZGQgcmVnaW9uIHZhcmlhYmxlIHRvIHRoZSBzYWxhcnkgZGF0YXNldA0Kc2FsYXJ5X3dpdGhfZGVwIDwtIGNiaW5kKHJlZ2lvbiwgc2FsYXJ5KQ0KDQojIGV4dHJhY3QgY29udGludW91cyB2YXJpYWJsZXMNCnNhbGFyeV92YXJpYWJsZXMgPC0gc2FsYXJ5X3dpdGhfZGVwWywgMzozNF0NCg0KI3NjYXR0ZXJwbG90IHRvIHZpc3VhbGx5IHNlZSB0aGUgY29ycmVsYXRpb25zIGJldHdlZW4gdmFyaWFibGVzDQpwYWlycyhzYWxhcnlfdmFyaWFibGVzWzE6OF0sIA0KICAgICAgcGFuZWwgPSBmdW5jdGlvbiAoeCwgeSwgLi4uKSB7DQogICAgICAgICAgcG9pbnRzKHgsIHksIC4uLikNCiAgICAgICAgICBhYmxpbmUobG0oeSB+IHgpLCBjb2wgPSAicmVkIikNCiAgICAgIH0sIHBjaCA9ICIuIiwgY2V4ID0gMC41KQ0KDQojc2NhdHRlcnBsb3QgYmV0d2VlbiB2YXJpYWJsZXMgb2YgbWFqb3IgaW50ZXJlc3QNCnBhaXJzKHNhbGFyeV92YXJpYWJsZXNbLCBjKCJzYWxhcnlfcmF0aW9fRnZzTSIsICJzYWxfZ2VuZXJhbCIsICJzYWxfRmVtYWxlcyIsInNhbF9NYWxlcyIpXSwgDQogICAgICBwYW5lbCA9IGZ1bmN0aW9uICh4LCB5LCAuLi4pIHsNCiAgICAgICAgICBwb2ludHMoeCwgeSwgLi4uKQ0KICAgICAgICAgIGFibGluZShsbSh5IH4geCksIGNvbCA9ICJyZWQiKQ0KICAgICAgfSwgcGNoID0gIi4iLCBjZXggPSAwLjUpDQoNCg0KI3NjYWxlIHRoZSBkYXRhDQpzYWxhcnlfdmFyaWFibGVzX3NjYWxlZCA8LSBhcy5kYXRhLmZyYW1lKHNjYWxlKHNhbGFyeV92YXJpYWJsZXMpKQ0KI2RpdmlkZSBzYWxfZ2VuZXJhbCBpbnRvIDQgcGFydHMNCnNhbGFyeV9sZXZlbHMgPC0gd2l0aChzYWxhcnlfdmFyaWFibGVzX3NjYWxlZCwgDQogICAgICAgICAgICAgICAgICBlcXVhbC5jb3VudChzYWxfZ2VuZXJhbCw0KSkNCg0KI3Bsb3Qgc2FsX3dvcmtlciBhZ2FpbnN0IHNhbF9taWRNYW5hZ2VyIGdpdmVuIDMgcGFydGl0aW9ucyBvZiBzYWxfZ2VuZXJhbA0KcGxvdCh4eXBsb3Qoc2FsX3dvcmtlciB+IHNhbF9taWRNYW5hZ2VyfCBjdXQoc2FsX2dlbmVyYWwsIDMpLCANCiAgICAgICAgICAgIGRhdGEgPSBzYWxhcnlfdmFyaWFibGVzLCANCiAgICAgICAgICAgIGxheW91dCA9IGMoMywgMSksIA0KICAgICAgICAgICAgeGxhYiA9ICJXb3JrZXIgU2FsYXJ5IiwgDQogICAgICAgICAgICB5bGFiID0gIk1pZG1hbmFnZXIgc2FsYXJ5IikpDQoNCiNtdWx0aWRpbWVzbmlvbmFsIHBsb3Qgb2YgbWlkTWFuYWdlciBzYWxhcnkgYWdhaW5zdCB3b3JrZXIgc2FsYXJ5LCBnaXZlbiA0IHBhcnRpdGlvbnMgb2YgRi9NIHNhbGFyeSByYXRpbywgYW5kIGdyYXlzY2FsZSBpbnRlbnNpdGllcyBvZiBnZW5lcmFsIHNhbGFyeQ0KTV9GX3NhbGFyeV9yYXRpbyAgPC0gd2l0aChzYWxhcnlfdmFyaWFibGVzLCBlcXVhbC5jb3VudChzYWxhcnlfcmF0aW9fRnZzTSwgNCkpDQpnZW5lcmFsX3NhbGFyeS5vcmQgPC0gd2l0aChzYWxhcnlfdmFyaWFibGVzLCByZXYob3JkZXIoc2FsX2dlbmVyYWwpKSkNCnNhbGFyeV92YXJpYWJsZXMub3JkZXJlZCA8LSBzYWxhcnlfdmFyaWFibGVzW2dlbmVyYWxfc2FsYXJ5Lm9yZCxdDQpzYWxfZ2VuZXJhbC5icmVha3MgPC0gd2l0aChzYWxhcnlfdmFyaWFibGVzLm9yZGVyZWQsIA0KICAgICAgICAgICAgICAgICAgICAgZG8uYnJlYWtzKHJhbmdlKHNhbF9nZW5lcmFsKSw1MCkpDQpzYWxhcnlfdmFyaWFibGVzLm9yZGVyZWQkY29sb3I8LWxldmVsLmNvbG9ycyhzYWxhcnlfdmFyaWFibGVzLm9yZGVyZWQkc2FsX2dlbmVyYWwsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF0PXNhbF9nZW5lcmFsLmJyZWFrcywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sLnJlZ2lvbnM9Z3JleS5jb2xvcnMpDQpwbG90KHh5cGxvdChzYWxfd29ya2VyIH4gc2FsX21pZE1hbmFnZXIgfCBNX0Zfc2FsYXJ5X3JhdGlvLCANCiAgICAgICAgICAgIGRhdGEgPSBzYWxhcnlfdmFyaWFibGVzLm9yZGVyZWQsDQogICAgICAgICAgICBhc3BlY3QgPSAiaXNvIiwgDQogICAgICAgICAgICBncm91cHMgPSBjb2xvciwgDQogICAgICAgICAgICBjZXggPSAxLCBjb2wgPSAiYmxhY2siLA0KICAgICAgIHBhbmVsID0gZnVuY3Rpb24oeCwgeSwgZ3JvdXBzLCAuLi4sIHN1YnNjcmlwdHMpIHsNCiAgICAgICAgICAgZmlsbCA8LSBncm91cHNbc3Vic2NyaXB0c10NCiAgICAgICAgICAgcGFuZWwuZ3JpZChoID0gLTEsIHYgPSAtMSkNCiAgICAgICAgICAgcGFuZWwueHlwbG90KHgsIHksIHBjaCA9IDIxLCANCiAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBmaWxsLCAuLi4pDQogICAgICAgfSwNCiAgICAgICBsZWdlbmQgPQ0KICAgICAgIGxpc3QocmlnaHQgPQ0KICAgICAgICAgICAgbGlzdChmdW4gPSBkcmF3LmNvbG9ya2V5LA0KICAgICAgICAgICAgICAgICBhcmdzPWxpc3Qoa2V5PWxpc3QoY29sPWdyYXkuY29sb3JzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXQgPSBzYWxfZ2VuZXJhbC5icmVha3MpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgZHJhdyA9IEZBTFNFKSkpLA0KICAgICAgICAgICAgeGxhYiA9ICJXb3JrZXIgU2FsYXJ5IiwgDQogICAgICAgICAgICB5bGFiID0gIk1pZG1hbmFnZXIgc2FsYXJ5IikpDQoNCg0KYGBgDQoNCiMjIyMgUHJlbGltaW5hcnkgbXVsdGl2YXJpYXRlIGZpcm1zIGRhdGEgdmlzdWFsaXNhdGlvbiB0byBiZXR0ZXIgY29uZHVjdCB0aGUgdW5zdXBlcnZpc2VkIGxlYXJuaW5nIA0KYGBge3J9DQojIGFkZCByZWdpb24gdmFyaWFibGUgdG8gdGhlIHNhbGFyeSBkYXRhc2V0DQpmaXJtc193aXRoX2RlcCA8LSBjYmluZChyZWdpb24sIGZpcm1zKQ0KDQojIGV4dHJhY3QgY29udGludW91cyB2YXJpYWJsZXMNCmZpcm1zX3ZhcmlhYmxlcyA8LSBmaXJtc193aXRoX2RlcFssIDQ6OF0NCg0KI3NjYXR0ZXJwbG90IHRvIHZpc3VhbGx5IHNlZSB0aGUgY29ycmVsYXRpb25zIGJldHdlZW4gdmFyaWFibGVzDQpwYWlycyhmaXJtc192YXJpYWJsZXNbLCAyOjVdLCANCiAgICAgIHBhbmVsID0gZnVuY3Rpb24gKHgsIHksIC4uLikgew0KICAgICAgICAgIHBvaW50cyh4LCB5LCAuLi4pDQogICAgICAgICAgYWJsaW5lKGxtKHkgfiB4KSwgY29sID0gInJlZCIpDQogICAgICB9LCBwY2ggPSAiLiIsIGNleCA9IDAuNSkNCg0KDQojc2NhbGUgdGhlIGRhdGENCmZpcm1zX3ZhcmlhYmxlc19zY2FsZWQgPC0gYXMuZGF0YS5mcmFtZShzY2FsZShmaXJtc192YXJpYWJsZXMpKQ0KI2RpdmlkZSBmaXJtcyB0b3RhbCBpbnRvIDQgcGFydHMNCmZpcm1zX2xldmVscyA8LSB3aXRoKGZpcm1zX3ZhcmlhYmxlc19zY2FsZWQsIA0KICAgICAgICAgICAgICAgICAgZXF1YWwuY291bnQodG90YWwsNCkpDQoNCg0KI3Bsb3Qgc2FsX3dvcmtlciBhZ2FpbnN0IHNhbF9taWRNYW5hZ2VyIGdpdmVuIDMgcGFydGl0aW9ucyBvZiBzYWxfZ2VuZXJhbA0KcGxvdCh4eXBsb3QobWVkaXVtIH4gbGFyZ2V8IGN1dCh0b3RhbCwgMyksIA0KICAgICAgICAgICAgZGF0YSA9IGZpcm1zX3ZhcmlhYmxlcywgDQogICAgICAgICAgICBsYXlvdXQgPSBjKDMsIDEpLCANCiAgICAgICAgICAgIHhsYWIgPSAibWVkaXVtIGZpcm1zIiwgDQogICAgICAgICAgICB5bGFiID0gImxhcmdlIGZpcm1zIikpDQoNCg0KYGBgDQoNCg0KIyMjIE11bHRpLWRpbWVuc2lvbmFsIHNjYWxpbmcgKE1EUykgDQojIyMjIE11bHRpLWRpbWVuc2lvbmFsIHNjYWxpbmcgKE1EUykgb24gc2FsYXJ5IGRhdGENCg0KYGBge3J9DQojTXVsdGktZGltZW5zaW9uYWwgc2NhbGluZyAoTURTKSBvbiBzYWxhcnkgZGF0YQ0KIyBwcm9kdWNlcyBhIGxpc3Qgd2l0aCBjb3ZhcmlhbmNlIG1hdHJpeA0KIyBmb3IgZWFjaCByZWdpb24gYXMgY29tcG9uZW50Og0Kc2FsYXJ5X3ZhciA8LSB0YXBwbHkoMTpucm93KHNhbGFyeV93aXRoX2RlcCksIHNhbGFyeV93aXRoX2RlcCRyZWdpb24sIA0KICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oaSkgdmFyKHNhbGFyeV93aXRoX2RlcFtpLDM6N10pKQ0KDQojcmVtb3ZlIHJlZ2lvbnMgd2l0aCBudWxsIHZhbHVlcw0Kc2FsYXJ5X3ZhciA8LSBzYWxhcnlfdmFyWy1jKDExLCAxMiwgMTUsIDE5LCAyMCwgMjgpXQ0KDQoNCiNjcmVhdGUgZGF0YWZyYW1lIHdpdGggdGhlIGNvdW50cyBvZiB0b3ducyBwZXIgcmVnaW9uDQpyZWdpb25zX2NvdW50IDwtIGRhdGEuZnJhbWUodGFibGUoc2FsYXJ5X3dpdGhfZGVwJHJlZ2lvbikpDQpyZWdpb25zX2NvdW50X3N1YjwtcmVnaW9uc19jb3VudFshKHJlZ2lvbnNfY291bnQkRnJlcT09MCB8IHJlZ2lvbnNfY291bnQkRnJlcT09MSksXQ0KI2NoZWNrIHRvdGFsIHN1bQ0KI3Jvdy5uYW1lcyhyZWdpb25zX2NvdW50X3N1YikgPC0gMTpucm93KHJlZ2lvbnNfY291bnRfc3ViKQ0KI3N1bShyZWdpb25zX2NvdW50X3N1YiRGcmVxKQ0KDQoNCg0KIyBpbml0aWFsaXplcyBjb21tb24gY292YXJpYW5jZSBtYXRyaXggdmFyOg0KUyA8LSByZWdpb25zX2NvdW50X3N1YiRGcmVxWzFdICogYXMubWF0cml4KHNhbGFyeV92YXJbWzFdXSkNCiMgY3JlYXRlcyBjb21tb24gY292YXJpYW5jZSBtYXRyaXggUw0KcyA8LSAwDQpmb3IgKHYgaW4gYygxOjIyKSkgUyA8LSBTICsgcmVnaW9uc19jb3VudF9zdWIkRnJlcVt2XSAqIGFzLm1hdHJpeChzYWxhcnlfdmFyW1t2XV0pIA0KUyA8LSBTIC8gNTAwMw0KDQojIGZpbmRzIGNlbnRlciBvZiBlYWNoIHZhcmlhYmxlIChzYWxfZ2VuZXJhbCwgZXRjKQ0KIyBmb3IgZWFjaCByZWdpb24NCnNhbGFyeV9jZW4gPC0gdGFwcGx5KDE6bnJvdyhzYWxhcnlfd2l0aF9kZXApLCBzYWxhcnlfd2l0aF9kZXAkcmVnaW9uLCANCiAgICBmdW5jdGlvbihpKSBhcHBseShzYWxhcnlfd2l0aF9kZXBbaSxjKDM6NyldLCAyLCBtZWFuKSkNCnNhbGFyeV9jZW4gPC0gc2FsYXJ5X2NlblstYygxMSwgMTIsIDE1LCAxOSwgMjAsIDI4KV0NCg0KDQojIGNyZWF0ZSBhIG1hdHJpeCBvdXQgb2YgZWFjaCBjb21wb25lbnRzLCBlYWNoDQojIG1lYW4gbWVhc3VyZW1lbnQgZm9yIGFsbCB2YXJpYWJsZXMgYnkgcmVnaW9uDQpzYWxhcnlfY2VuIDwtIG1hdHJpeCh1bmxpc3Qoc2FsYXJ5X2NlbiksIA0KICAgIG5yb3cgPSBsZW5ndGgoc2FsYXJ5X2NlbiksIGJ5cm93ID0gVFJVRSkNCiNzYWxhcnlfY2VuDQoNCiMgY29tcHV0ZSB0aGUgbWFoYWxhbm9iaXMgZGlzdGFuY2VzOg0Kc2FsYXJ5X21haCA8LSBhcHBseShzYWxhcnlfY2VuLCAxLCANCiAgICBmdW5jdGlvbihjZW4pIG1haGFsYW5vYmlzKHNhbGFyeV9jZW4sIGNlbiwgUykpDQoNCg0KIyBydW4gaXQgb24gdHdvIGRpbWVuc2lvbnMNCnNhbGFyeV9tZHMgPC0gY21kc2NhbGUoc2FsYXJ5X21haCkNCg0KIyBkcmF3IGEgc2NhdHRlcnBsb3Qgb2YgdHdvLWRpbWVuc2lvbmFsIHNvbHV0aW9uDQojIGZyb20gY2xhc3NpY2FsIE1EUyBhcHBsaWVkIHRvIE1haGFsYW5vYmlzDQojIGRpc3RhbmNlczoNCmxpbSA8LSByYW5nZShzYWxhcnlfbWRzKSAqIDEuMg0KcGxvdChzYWxhcnlfbWRzLCB4bGFiID0gIkNvb3JkaW5hdGUgMSIsIA0KICAgICB5bGFiID0gIkNvb3JkaW5hdGUgMiIsDQogICAgIHhsaW0gPSBsaW0sIHlsaW0gPSBsaW0sIHR5cGUgPSAibiIpDQp0ZXh0KHNhbGFyeV9tZHMsIGxhYmVscyA9IGxldmVscyhzYWxhcnlfd2l0aF9kZXAkcmVnaW9uKSwgDQogICAgIGNleCA9IDAuNSkNCg0KYGBgDQpPbmUgY2FuIHNlZSB0aGF0IExhbmd1ZWRvYyBSb3Vzc2lsb24sIHRoZSB3b3JzdCByZWdpb24gaW4gdGVybXMgb2YgR0RQIHBlciBjYXBpdGEsIGlzIGZ1cnRoZXIgYXdheSBmcm9tIHRoZSBjZW50ZXIuDQoNCiMjIyMgTXVsdGktZGltZW5zaW9uYWwgc2NhbGluZyAoTURTKSBvbiBmaXJtcyBkYXRhDQoNCmBgYHtyfQ0KDQpmaXJtc193aXRoX2RlcCA8LSBmaXJtc193aXRoX2RlcFssIC05XQ0KZmlybXNfd2l0aF9kZXBfbm9ybWFsaXplZCA8LSBmaXJtc193aXRoX2RlcFssIDQ6OF0vcG9wdWxhdGlvbiR0b3RhbF9wb3B1bGF0aW9uDQpmaXJtc193aXRoX2RlcF9ub3JtYWxpemVkIDwtIGNiaW5kKGZpcm1zX3dpdGhfZGVwJHJlZ2lvbiwgZmlybXNfd2l0aF9kZXBfbm9ybWFsaXplZCkNCm5hbWVzKGZpcm1zX3dpdGhfZGVwX25vcm1hbGl6ZWQpWzFdIDwtICJyZWdpb24iDQojIHByb2R1Y2VzIGEgbGlzdCB3aXRoIGNvdmFyaWFuY2UgbWF0cml4DQojIGZvciBlYWNoIHJlZ2lvbiBhcyBjb21wb25lbnQ6DQpmaXJtc192YXIgPC0gdGFwcGx5KDE6bnJvdyhmaXJtc193aXRoX2RlcF9ub3JtYWxpemVkKSwgZmlybXNfd2l0aF9kZXBfbm9ybWFsaXplZCRyZWdpb24sIA0KICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oaSkgdmFyKGZpcm1zX3dpdGhfZGVwX25vcm1hbGl6ZWRbaSwyOjZdKSkNCg0KI3JlbW92ZSByZWdpb25zIHdpdGggbnVsbCB2YWx1ZXMNCmZpcm1zX3ZhciA8LSBmaXJtc192YXJbLWMoMTEsIDEyLCAxNSwgMTksIDIwLCAyOCldDQoNCg0KI2NyZWF0ZSBkYXRhZnJhbWUgd2l0aCB0aGUgY291bnRzIG9mIHRvd25zIHBlciByZWdpb24NCnJlZ2lvbnNfY291bnQgPC0gZGF0YS5mcmFtZSh0YWJsZShmaXJtc193aXRoX2RlcF9ub3JtYWxpemVkJHJlZ2lvbikpDQpyZWdpb25zX2NvdW50X3N1YjwtcmVnaW9uc19jb3VudFshKHJlZ2lvbnNfY291bnQkRnJlcT09MCB8IHJlZ2lvbnNfY291bnQkRnJlcT09MSksXQ0KI2NoZWNrIHRvdGFsIHN1bQ0KIyByb3cubmFtZXMocmVnaW9uc19jb3VudF9zdWIpIDwtIDE6bnJvdyhyZWdpb25zX2NvdW50X3N1YikNCiMgc3VtKHJlZ2lvbnNfY291bnRfc3ViJEZyZXEpDQoNCg0KDQojIGluaXRpYWxpemVzIGNvbW1vbiBjb3ZhcmlhbmNlIG1hdHJpeCB2YXI6DQpTIDwtIHJlZ2lvbnNfY291bnRfc3ViJEZyZXFbMV0gKiBhcy5tYXRyaXgoZmlybXNfdmFyW1sxXV0pDQoNCiMgY3JlYXRlcyBjb21tb24gY292YXJpYW5jZSBtYXRyaXggUw0KcyA8LSAwDQpmb3IgKHYgaW4gYygxOjIyKSkgUyA8LSBTICsgKHJlZ2lvbnNfY291bnRfc3ViJEZyZXFbdl0gLSAxKSAqIGFzLm1hdHJpeChmaXJtc192YXJbW3ZdXSkgDQpTIDwtIFMgLyA1MDAzDQoNCiMgZmluZHMgY2VudGVyIG9mIGVhY2ggdmFyaWFibGUgKG1pY3JvLCBldGMpDQojIGZvciBlYWNoIHJlZ2lvbg0KZmlybXNfY2VuIDwtIHRhcHBseSgxOm5yb3coZmlybXNfd2l0aF9kZXBfbm9ybWFsaXplZCksIGZpcm1zX3dpdGhfZGVwX25vcm1hbGl6ZWQkcmVnaW9uLCANCiAgICBmdW5jdGlvbihpKSBhcHBseShmaXJtc193aXRoX2RlcF9ub3JtYWxpemVkW2ksLTFdLCAyLCBtZWFuKSkNCmZpcm1zX2NlbiA8LSBmaXJtc19jZW5bLWMoMTEsIDEyLCAxNSwgMTksIDIwLCAyOCldDQoNCg0KIyBjcmVhdGUgYSBtYXRyaXggb3V0IG9mIGVhY2ggY29tcG9uZW50cywgZWFjaA0KIyBtZWFuIG1lYXN1cmVtZW50IGZvciBhbGwgdmFyaWFibGVzIGJ5IHJlZ2lvbg0KZmlybXNfY2VuIDwtIG1hdHJpeCh1bmxpc3QoZmlybXNfY2VuKSwgDQogICAgbnJvdyA9IGxlbmd0aChmaXJtc19jZW4pLCBieXJvdyA9IFRSVUUpDQoNCiMgY29tcHV0ZSB0aGUgbWFoYWxhbm9iaXMgZGlzdGFuY2VzOg0KZmlybXNfbWFoIDwtIGFwcGx5KGZpcm1zX2NlbiwgMSwgDQogICAgZnVuY3Rpb24oY2VuKSBtYWhhbGFub2JpcyhmaXJtc19jZW4sIGNlbiwgUykpDQoNCg0KDQojIHJ1biBpdCBvbiB0d28gZGltZW5zaW9ucw0KZmlybXNfbWRzIDwtIGNtZHNjYWxlKGZpcm1zX21haCkNCg0KIyBkcmF3IGEgc2NhdHRlcnBsb3Qgb2YgdHdvLWRpbWVuc2lvbmFsIHNvbHV0aW9uDQojIGZyb20gY2xhc3NpY2FsIE1EUyBhcHBsaWVkIHRvIE1haGFsYW5vYmlzDQojIGRpc3RhbmNlczoNCmxpbSA8LSByYW5nZShmaXJtc19tZHMpICogMS4yDQpwbG90KGZpcm1zX21kcywgeGxhYiA9ICJDb29yZGluYXRlIDEiLCANCiAgICAgeWxhYiA9ICJDb29yZGluYXRlIDIiLA0KICAgICB4bGltID0gbGltLCB5bGltID0gbGltLCB0eXBlID0gIm4iKQ0KdGV4dChmaXJtc19tZHMsIGxhYmVscyA9IGxldmVscyhmaXJtc193aXRoX2RlcF9ub3JtYWxpemVkJHJlZ2lvbiksIA0KICAgICBjZXggPSAwLjUpDQoNCmBgYA0KU2luY2UgdGhhIGRhdGEgaXMgbm9ybWFsaXplZCBhY2NvcmRpbmcgdG8gcG9wdWxhdGlvbiBzaXplLCBIYXV0ZSBOb3JtYW5kaWUgYW5kIE1pZGkgUHlyZW5lZXMgYXJlIGZ1cnRoZXIgYXdheS4NCg0KIyMjIyBNdWx0aS1EaW1lbnNpb25hbCBTY2FsaW5nIGZvciBtZXJnZWQgZGF0YXNldA0KDQpgYGB7cn0NCm51bXMgPC0gdW5saXN0KGxhcHBseShjb21tdW5lLCBpcy5udW1lcmljKSkgDQpjb21tdW5lX3NlbGVjdGVkIDwtIGNvbW11bmVbLCBudW1zXQ0KDQpjb21tdW5lX3NlbGVjdGVkIDwtIGNvbW11bmVfc2VsZWN0ZWRbLCAyOjIwXQ0KDQpjb21tdW5lX3NlbGVjdGVkX25vcm1hbGl6ZWQgPC0gY29tbXVuZV9zZWxlY3RlZFtdL3BvcHVsYXRpb24kdG90YWxfcG9wdWxhdGlvbg0KDQp1bmVtcF9wZXJjZW50IDwtIGFzLmRhdGEuZnJhbWUoKGluZXEkdW5lbXAxNV82NC9pbmVxJHBvcDE1XzY0KSoxMDApDQpuYW1lcyh1bmVtcF9wZXJjZW50KVsxXSA8LSAidW5lbXBfcGVyY2VudCINCg0KZmlybXNfdmFyaWFibGVzX25vcm1hbGl6ZWQgPC0gZmlybXNfdmFyaWFibGVzW10vcG9wdWxhdGlvbiR0b3RhbF9wb3B1bGF0aW9uDQoNCnNlbGVjdGVkX3ZhcmlhYmxlcyA8LSBjYmluZChmaXJtc192YXJpYWJsZXNfbm9ybWFsaXplZCwgc2FsYXJ5X3ZhcmlhYmxlcywgY29tbXVuZV9zZWxlY3RlZF9ub3JtYWxpemVkLCB1bmVtcF9wZXJjZW50KQ0KDQpzZWxlY3RlZF92YXJpYWJsZXNfd2l0aF9kZXAgPC0gY2JpbmQoZ2VvJHJlZ2lvbiwgc2VsZWN0ZWRfdmFyaWFibGVzKQ0KbmFtZXMoc2VsZWN0ZWRfdmFyaWFibGVzX3dpdGhfZGVwKVsxXSA8LSAicmVnaW9uIg0KDQpwY2Ffc2VsZWN0ZWRfdmFyaWFibGVzIDwtIHByY29tcChzZWxlY3RlZF92YXJpYWJsZXMpDQpzZWxlY3RlZF9wY2Ffc2NvcmVzPC0gYXMuZGF0YS5mcmFtZShwY2Ffc2VsZWN0ZWRfdmFyaWFibGVzJHhbLDE6M10pDQpzZWxlY3RlZF9wY2Ffd2l0aF9kZXAgPC0gY2JpbmQoZ2VvJHJlZ2lvbiwgc2VsZWN0ZWRfcGNhX3Njb3JlcykNCm5hbWVzKHNlbGVjdGVkX3BjYV93aXRoX2RlcClbMV0gPC0gInJlZ2lvbiINCiMgcHJvZHVjZXMgYSBsaXN0IHdpdGggY292YXJpYW5jZSBtYXRyaXgNCiMgZm9yIGVhY2ggcmVnaW9uIGFzIGNvbXBvbmVudDoNCnNlbGVjdGVkX1BDQV92YXIgPC0gdGFwcGx5KDE6bnJvdyhzZWxlY3RlZF9wY2Ffd2l0aF9kZXApLCBzZWxlY3RlZF9wY2Ffd2l0aF9kZXAkcmVnaW9uLA0KICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oaSkgdmFyKHNlbGVjdGVkX3BjYV93aXRoX2RlcFtpLDI6NF0pKQ0KDQoNCiNyZW1vdmUgcmVnaW9ucyB3aXRoIG51bGwgdmFsdWVzDQpzZWxlY3RlZF9QQ0FfdmFyIDwtIHNlbGVjdGVkX1BDQV92YXJbLWMoMTEsIDEyLCAxNSwgMTksIDIwLCAyOCldDQoNCg0KI2NyZWF0ZSBkYXRhZnJhbWUgd2l0aCB0aGUgY291bnRzIG9mIHRvd25zIHBlciByZWdpb24NCnJlZ2lvbnNfY291bnQgPC0gZGF0YS5mcmFtZSh0YWJsZShzZWxlY3RlZF9wY2Ffd2l0aF9kZXAkcmVnaW9uKSkNCnJlZ2lvbnNfY291bnRfc3ViPC1yZWdpb25zX2NvdW50WyEocmVnaW9uc19jb3VudCRGcmVxPT0wIHwgcmVnaW9uc19jb3VudCRGcmVxPT0xKSxdDQojY2hlY2sgdG90YWwgc3VtDQojIHJvdy5uYW1lcyhyZWdpb25zX2NvdW50X3N1YikgPC0gMTpucm93KHJlZ2lvbnNfY291bnRfc3ViKQ0KIyBzdW0ocmVnaW9uc19jb3VudF9zdWIkRnJlcSkNCg0KDQoNCiMgaW5pdGlhbGl6ZXMgY29tbW9uIGNvdmFyaWFuY2UgbWF0cml4IHZhcjoNClMgPC0gcmVnaW9uc19jb3VudF9zdWIkRnJlcVsxXSAqIGFzLm1hdHJpeChzZWxlY3RlZF9QQ0FfdmFyW1sxXV0pDQoNCiMgY3JlYXRlcyBjb21tb24gY292YXJpYW5jZSBtYXRyaXggUw0KcyA8LSAwDQpmb3IgKHYgaW4gYygxOjIyKSkgUyA8LSBTICsgKHJlZ2lvbnNfY291bnRfc3ViJEZyZXFbdl0gLSAxKSAqIGFzLm1hdHJpeChzZWxlY3RlZF9QQ0FfdmFyW1t2XV0pDQpTIDwtIFMgLyA1MDAzDQoNCiMgZmluZHMgY2VudGVyIG9mIGVhY2ggdmFyaWFibGUgKG1pY3JvLCBldGMpDQojIGZvciBlYWNoIHJlZ2lvbg0Kc2VsZWN0ZWRfY2VuIDwtIHRhcHBseSgxOm5yb3coc2VsZWN0ZWRfcGNhX3dpdGhfZGVwKSwgc2VsZWN0ZWRfcGNhX3dpdGhfZGVwJHJlZ2lvbiwNCiAgICBmdW5jdGlvbihpKSBhcHBseShzZWxlY3RlZF9wY2Ffd2l0aF9kZXBbaSwtMV0sIDIsIG1lYW4pKQ0Kc2VsZWN0ZWRfY2VuIDwtIHNlbGVjdGVkX2NlblstYygxMSwgMTIsIDE1LCAxOSwgMjAsIDI4KV0NCg0KIyBjcmVhdGUgYSBtYXRyaXggb3V0IG9mIGVhY2ggY29tcG9uZW50cywgZWFjaA0KIyBtZWFuIG1lYXN1cmVtZW50IGZvciBhbGwgdmFyaWFibGVzIGJ5IHJlZ2lvbg0Kc2VsZWN0ZWRfY2VuIDwtIG1hdHJpeCh1bmxpc3Qoc2VsZWN0ZWRfY2VuKSwNCiAgICBucm93ID0gbGVuZ3RoKHNlbGVjdGVkX2NlbiksIGJ5cm93ID0gVFJVRSkNCg0KIyBjb21wdXRlIHRoZSBtYWhhbGFub2JpcyBkaXN0YW5jZXM6DQpzZWxlY3RlZF9tYWggPC0gYXBwbHkoc2VsZWN0ZWRfY2VuLCAxLA0KICAgIGZ1bmN0aW9uKGNlbikgbWFoYWxhbm9iaXMoc2VsZWN0ZWRfY2VuLCBjZW4sIFMpKQ0KDQoNCiMgcnVuIGl0IG9uIHR3byBkaW1lbnNpb25zDQpzZWxlY3RlZF9tZHMgPC0gY21kc2NhbGUoc2VsZWN0ZWRfbWFoKQ0KDQojIGRyYXcgYSBzY2F0dGVycGxvdCBvZiB0d28tZGltZW5zaW9uYWwgc29sdXRpb24NCiMgZnJvbSBjbGFzc2ljYWwgTURTIGFwcGxpZWQgdG8gTWFoYWxhbm9iaXMNCiMgZGlzdGFuY2VzOg0KbGltIDwtIHJhbmdlKHNlbGVjdGVkX21kcykgKiAxLjINCnBsb3Qoc2VsZWN0ZWRfbWRzLCB4bGFiID0gIkNvb3JkaW5hdGUgMSIsDQogICAgIHlsYWIgPSAiQ29vcmRpbmF0ZSAyIiwNCiAgICAgeGxpbSA9IGxpbSwgeWxpbSA9IGxpbSwgdHlwZSA9ICJuIikNCnRleHQoc2VsZWN0ZWRfbWRzLCBsYWJlbHMgPSBsZXZlbHMoc2VsZWN0ZWRfcGNhX3dpdGhfZGVwJHJlZ2lvbiksDQogICAgIGNleCA9IDAuNSkNCg0KYGBgDQpPbiB0aGUgbWVyZ2VkIGRhdGFzZXQgb25lIGNhbiBSaG9uZS1BbHBlcyBhbmQgQ290ZSBkJ0F6dXIsIHRoZSB0d28gYmlnZ2VzdCBlY29ub21pZXMgYWZ0ZXIgSWxlIGRlIEZyYW5jZS4NCg0KIyMgUENBDQoNCiMjIyMgUENBIG9uIHNhbGFyeSBkYXRhIGFuZCBkZWx0YSBNLUYNCg0KYGBge3J9DQoNCnBjYV9zYWxhcnkgPC0gcHJjb21wKHNhbGFyeV92YXJpYWJsZXMpDQphdXRvcGxvdChwY2Ffc2FsYXJ5LCBkYXRhID0gc2FsYXJ5X3dpdGhfZGVwLCBjb2xvdXIgPSAncmVnaW9uJywNCiAgICAgICAgIGxvYWRpbmdzID0gVFJVRSwgbG9hZGluZ3MuY29sb3VyID0gJ2JsdWUnLA0KICAgICAgICAgbG9hZGluZ3MubGFiZWwgPSBUUlVFLCBsb2FkaW5ncy5sYWJlbC5zaXplID0gMykNCnBsb3QocGNhX3NhbGFyeSwgdHlwZSA9ICJsIikNCg0KI2NyZWF0ZSBkYXRhc2V0IHdpdGggTS1GIGRpZmZlcmVuY2VzDQpzYWxhcnlfdmFyX2RlbHRhIDwtIGRhdGEuZnJhbWUoIk0tRiIgPSBzYWxhcnlfdmFyaWFibGVzJHNhbF9NYWxlcyAtICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzYWxhcnlfdmFyaWFibGVzJHNhbF9GZW1hbGVzLA0KICAgICAgICAgICAgICAgICAgICAgIkV4ZWN1dGl2ZSBNLUYiID0gc2FsYXJ5X3ZhcmlhYmxlcyRzYWxfTV9leGVjdXRpdmUgLQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzYWxhcnlfdmFyaWFibGVzJHNhbF9GX2V4ZWN1dGl2ZSwNCiAgICAgICAgICAgICAgICAgICAgIm1pZE1hbmFnZXIgTS1GIiA9IHNhbGFyeV92YXJpYWJsZXMkc2FsX01fbWlkTWFuYWdlciAtDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhbGFyeV92YXJpYWJsZXMkc2FsX0ZfbWlkTWFuYWdlciwNCiAgICAgICAgICAgICAgICAgICAgICAiZW1wbG95ZWUgTS1GIiA9IHNhbGFyeV92YXJpYWJsZXMkc2FsX01fZW1wbG95ZWUgLQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzYWxhcnlfdmFyaWFibGVzJHNhbF9GX2VtcGxveWVlLA0KICAgICAgICAgICAgICAgICAgICAgICAgIndvcmtlciBNLUYiID0gc2FsYXJ5X3ZhcmlhYmxlcyRzYWxfTV93b3JrZXIgLQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzYWxhcnlfdmFyaWFibGVzJHNhbF9GX3dvcmtlciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAiMTgtMjUgTS1GIiA9IHNhbGFyeV92YXJpYWJsZXMkc2FsX01fMThfMjUgLQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzYWxhcnlfdmFyaWFibGVzJHNhbF9GXzE4XzI1LA0KICAgICAgICAgICAgICAgICAgICAgICAgICIyNi01MCBNLUYiID0gc2FsYXJ5X3ZhcmlhYmxlcyRzYWxfTV8yNl81MCAtDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhbGFyeV92YXJpYWJsZXMkc2FsX0ZfMjZfNTAsDQogICAgICAgICAgICAgICAgICAgICAgICI1MSBwbHVzIE0tRiIgPSBzYWxhcnlfdmFyaWFibGVzJHNhbF9NXzUxcGx1cyAtDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhbGFyeV92YXJpYWJsZXMkc2FsX0ZfNTFwbHVzKQ0KcGNhX3NhbGFyeV9kZWx0YSA8LSBwcmNvbXAoc2FsYXJ5X3Zhcl9kZWx0YSkNCmF1dG9wbG90KHBjYV9zYWxhcnlfZGVsdGEsIGRhdGEgPSBzYWxhcnlfd2l0aF9kZXAsIGNvbG91ciA9ICdyZWdpb24nLA0KICAgICAgICAgbG9hZGluZ3MgPSBUUlVFLCBsb2FkaW5ncy5jb2xvdXIgPSAnYmx1ZScsDQogICAgICAgICBsb2FkaW5ncy5sYWJlbCA9IFRSVUUsIGxvYWRpbmdzLmxhYmVsLnNpemUgPSAzKQ0KcGxvdChwY2Ffc2FsYXJ5X2RlbHRhLCB0eXBlID0gImwiKQ0KDQpgYGANClRoZXJlIGFyZSB0aHJlZSBtYWluIGRpcmVjdGlvbnMgb2YgZWlnZW52ZWN0b3JzDQpjb250cmlidXRpbmcgdG8gcHJpbmNpcGFsIGNvbXBvbmVudHMnIHNjb3JlczogdmFyaWFibGVzIGRlc2NyaWJpbmcgc2FsYXJpZXMgb2Ygb3JkaW5hcnkgc3RhZmYNCmFjcm9zcyBkaWZmZXJlbnQgYWdlIGNhdGVnb3JpZXMsIHZhcmlhYmxlcyBkZXNjcmliaW5nIG1pZC1tYW5hZ2VyIGFuZCBtYW5hZ2VyIHNhbGFyaWVzLCBhbmQNCnNhbGFyaWVzIG9mIGV4ZWN1dGl2ZXMuDQoNClBDQSBvbiBkZWx0YSBNLUYgcmV2ZWFsZWQgdGhyZWUgbWFpbiBkaXJlY3Rpb25zDQpvZiBlaWdlbnZlY3RvcnMgY29udHJpYnV0aW5nIHRvIHNjb3JlczogbWFsZS1mZW1hbGUgc2FsYXJ5IGRpZmZlcmVuY2VzIG9mIG1pZC1tYW5hZ2VycywNCmV4ZWN1dGl2ZXMsIGFuZCA1MSBhbmQgb2xkZXIgYWdlZCBwZW9wbGUuDQoNCg0KIyMjIyBQQ0Egb24gZmlybXMgZGF0YQ0KDQpgYGB7cn0NCmZpcm1zX3ZhcmlhYmxlc19ub3JtYWxpemVkIDwtIGZpcm1zX3ZhcmlhYmxlc1ssIC0xXS9wb3B1bGF0aW9uJHRvdGFsX3BvcHVsYXRpb24NCg0KcGNhX2Zpcm1zIDwtIHByY29tcChmaXJtc192YXJpYWJsZXNfbm9ybWFsaXplZCkNCmF1dG9wbG90KHBjYV9maXJtcywgZGF0YSA9IGZpcm1zX3dpdGhfZGVwLCBjb2xvdXIgPSAncmVnaW9uJywNCiAgICAgICAgIGxvYWRpbmdzID0gVFJVRSwgbG9hZGluZ3MuY29sb3VyID0gJ2JsdWUnLA0KICAgICAgICAgbG9hZGluZ3MubGFiZWwgPSBUUlVFLCBsb2FkaW5ncy5sYWJlbC5zaXplID0gMykNCnBsb3QocGNhX2Zpcm1zLCB0eXBlID0gImwiKQ0KDQpgYGANClNpbmNlIHRoZXJlIGlzIGEgc3Ryb25nDQptdWx0aWNvbGxpbmVhcml0eSBhbW9uZyB0aGUgdmFyaWFibGVzIG9mIHRoZSBmaXJtcyBkYXRhLCB0aGUgY29uZHVjdGVkIFBDQSByZXN1bHRzDQppbiB0aGUgdmFyaWFibGUgd2l0aCBjb25zaWRlcmFibHkgaGlnaGVyIHZhbHVlcywgaS5lLiB2ZXJ5IHNtYWxsIGZpcm1zLCB0byBmb3JtIGEgbWFpbg0KZWlnZW52ZWN0b3IsIGxlYXZpbmcgZmlybXMgb2Ygb3RoZXIgc2l6ZXMgdG8gZm9ybSBhIHNlcGFyYXRlIGdyb3VwIG9mIGVpZ2VudmVjdG9ycy4NCg0KDQojIyMjIFBDQSBvbiBjb21tdW5lIGRhdGFzZXQNCg0KYGBge3J9DQpjb21tdW5lX3RyaW1tZWQgPC0gY29tbXVuZVssYygibmJfZmlybXNfc2VydmljZSIsIm5iX2Zpcm1zX2NvbW1lcmNlIiwibmJfZmlybXNfY29uc3RydWN0aW9uIildDQpjb21tdW5lX3RyaW1tZWQkYWN0aXZlX2VtcGxfcHJvcCA8LSBjb21tdW5lJG5iX2FjdGl2ZV9lbXBsb3llZXMvcG9wdWxhdGlvbiR0b3RhbF9wb3B1bGF0aW9uDQpjb21tdW5lX3RyaW1tZWQkbmJfZmlybXNfc2VydmljZSA8LSBjb21tdW5lJG5iX2Zpcm1zX3NlcnZpY2UvcG9wdWxhdGlvbiR0b3RhbF9wb3B1bGF0aW9uDQpjb21tdW5lX3RyaW1tZWQkbmJfZmlybXNfY29tbWVyY2UgPC0gY29tbXVuZSRuYl9maXJtc19jb21tZXJjZS9wb3B1bGF0aW9uJHRvdGFsX3BvcHVsYXRpb24NCmNvbW11bmVfdHJpbW1lZCRuYl9maXJtc19jb25zdHJ1Y3Rpb24gPC0gY29tbXVuZSRuYl9maXJtc19jb25zdHJ1Y3Rpb24vcG9wdWxhdGlvbiR0b3RhbF9wb3B1bGF0aW9uDQojY29tbXVuZV90cmltbWVkIDwtIGFzLmRhdGEuZnJhbWUoc2NhbGUoY29tbXVuZV90cmltbWVkKSkNCg0KbmFtZXMod2hpY2goc2FwcGx5KGNvbW11bmVfdHJpbW1lZCwgYW55TkEpKSkNCnN0cihjb21tdW5lX3RyaW1tZWQpDQoNCg0KY29tbXVuZV9wY2EgPC0gcHJjb21wKGNvbW11bmVfdHJpbW1lZCkNCmNvbW11bmVfcGNhDQpjb21tdW5lX3BjYV9zY29yZXM8LSBhcy5kYXRhLmZyYW1lKGNvbW11bmVfcGNhJHhbLDE6M10pDQoNCmF1dG9wbG90KGNvbW11bmVfcGNhLCBkYXRhID0gZ2VvLCBjb2xvdXIgPSAncmVnaW9uJywNCiAgICAgICAgIGxvYWRpbmdzID0gVFJVRSwgbG9hZGluZ3MuY29sb3VyID0gJ2JsdWUnLA0KICAgICAgICAgbG9hZGluZ3MubGFiZWwgPSBUUlVFLCBsb2FkaW5ncy5sYWJlbC5zaXplID0gMykNCnBsb3QoY29tbXVuZV9wY2EsIHR5cGUgPSAibCIpDQoNCiMgcGxvdDNkKGNvbW11bmVfcGNhWywxOjJdLCBjb2w9Y2x1c3RlciRjbHVzdGVyKzEpDQpzY2F0dGVyM2QoeCA9IGNvbW11bmVfcGNhX3Njb3JlcyRQQzEsIHkgPSBjb21tdW5lX3BjYV9zY29yZXMkUEMyLCB6ID0gY29tbXVuZV9wY2Ffc2NvcmVzJFBDMywgZ3JvdXBzID0gYXMuZmFjdG9yKGttZWFucyhjb21tdW5lX3BjYV9zY29yZXMsIA0KICAgICAgICAgICAgICAgICAgY2VudGVycyA9IDYpJGNsdXN0ZXIpLA0KICAgICAgICAgIGdyaWQgPSBGQUxTRSwgc3VyZmFjZSA9IEZBTFNFKQ0KDQpgYGANClBDQSBjb25kdWN0ZWQNCm9uIHRoZSBjb21tdW5lIGRhdGFzZXQgcmV2ZWFsZWQgdHdvIG1haW4gZGlyZWN0aW9ucyBvZiBlaWdlbnZlY3RvcnM6DQpwcm9wb3J0aW9uIG9mIGFjdGl2ZSBlbXBsb3llcnMgaW4gZWFjaCB0b3duLCBhbmQgaW5kdXN0cnkgcmVsYXRlZCB2YXJpYWJsZXMuDQoNCiMjIyMgUENBIG9uIHNlbGVjdGVkIHZhcmlhYmxlcw0KDQpgYGB7cn0NCm51bXMgPC0gdW5saXN0KGxhcHBseShjb21tdW5lLCBpcy5udW1lcmljKSkgDQpjb21tdW5lX3NlbGVjdGVkIDwtIGNvbW11bmVbLCBudW1zXQ0KDQpjb21tdW5lX3NlbGVjdGVkIDwtIGNvbW11bmVfc2VsZWN0ZWRbLCAyOjIwXQ0KDQpjb21tdW5lX3NlbGVjdGVkX25vcm1hbGl6ZWQgPC0gY29tbXVuZV9zZWxlY3RlZFtdL3BvcHVsYXRpb24kdG90YWxfcG9wdWxhdGlvbg0KDQp1bmVtcF9wZXJjZW50IDwtIGFzLmRhdGEuZnJhbWUoKGluZXEkdW5lbXAxNV82NC9pbmVxJHBvcDE1XzY0KSoxMDApDQpuYW1lcyh1bmVtcF9wZXJjZW50KVsxXSA8LSAidW5lbXBfcGVyY2VudCINCg0Kc2VsZWN0ZWRfdmFyaWFibGVzIDwtIGNiaW5kKGZpcm1zX3ZhcmlhYmxlc19ub3JtYWxpemVkLCBzYWxhcnlfdmFyaWFibGVzLCBjb21tdW5lX3NlbGVjdGVkX25vcm1hbGl6ZWQsIHVuZW1wX3BlcmNlbnQpDQoNCnBjYV9zZWxlY3RlZF92YXJpYWJsZXMgPC0gcHJjb21wKHNlbGVjdGVkX3ZhcmlhYmxlcykNCmF1dG9wbG90KHBjYV9zZWxlY3RlZF92YXJpYWJsZXMsIGRhdGEgPSBnZW8sIGNvbG91ciA9ICdyZWdpb24nLA0KICAgICAgICAgbG9hZGluZ3MgPSBUUlVFLCBsb2FkaW5ncy5jb2xvdXIgPSAnYmx1ZScsDQogICAgICAgICBsb2FkaW5ncy5sYWJlbCA9IFRSVUUsIGxvYWRpbmdzLmxhYmVsLnNpemUgPSAzKQ0KcGxvdChwY2Ffc2VsZWN0ZWRfdmFyaWFibGVzLCB0eXBlID0gImwiKQ0KDQpgYGANCnJlZ2lvbmFsIEdEUCBpcyBhIHN0cmlraW5nIGltcG9ydGFudA0KZmFjdG9yLCBjb21wcmlzaW5nIGEgZGlzdGluY3RseSBvcmllbnRlZCBlaWdlbnZlY3Rvci4gQW5vdGhlciBkaXN0aW5jdCBlaWdlbnZlY3RvciwgdGhvdWdoIGxlc3MNCnN1YnN0YW50aWFsLCBpcyB0aGUgdW5lbXBsb3ltZW50IHJhdGUuDQoNCg0KIyMgQ2x1c3RlciBBbmFseXNpcw0KDQojIyMjIENsdXN0ZXIgQW5hbHlzaXMgb24gc2FsYXJ5DQpgYGB7cn0NCg0KI2NyZWF0ZSBkYXRhZnJhbWUgd2l0aCBmaXJzdCB0d28gcHJpbmNpcGFsIGNvbXBvbmVudHMgc2NvcmVzIGFzIHZhcmlhYmxlcw0Kc2FsYXJ5X3BjYV9zY29yZXM8LSBhcy5kYXRhLmZyYW1lKHBjYV9zYWxhcnkkeFssMToyXSkNCnNhbGFyeV9wY2Ffc2NvcmVzIDwtIGFzLmRhdGEuZnJhbWUoc2NhbGUoc2FsYXJ5X3BjYV9zY29yZXMpKQ0Kc2FwcGx5KHNhbGFyeV9wY2Ffc2NvcmVzLCB2YXIpDQoNCiANCiMgSy1tZWFucyBjbHVzdGVyaW5nDQpuIDwtIG5yb3coc2FsYXJ5X3BjYV9zY29yZXMpDQp3c3MgPC0gcmVwKDAsIDIyKQ0Kd3NzWzFdIDwtIChuIC0gMSkgKiBzdW0oc2FwcGx5KHNhbGFyeV9wY2Ffc2NvcmVzLCB2YXIpKQ0KZm9yIChpIGluIDI6MjIpDQogICAgd3NzW2ldIDwtIHN1bShrbWVhbnMoc2FsYXJ5X3BjYV9zY29yZXMsDQogICAgICAgICAgICAgICAgICAgICAgICAgY2VudGVycyA9IGkpJHdpdGhpbnNzKQ0KI3dlIGNhbiBzZWUgZnJvbSB0aGUgcGxvdCB0aGF0IG9wdGltYWwgbnVtYmVyIG9mIGNsdXN0ZXIgaXMgNQ0KcGxvdCgxOjIyLCB3c3MsIHR5cGUgPSAiYiIsIA0KICAgICB4bGFiID0gIk51bWJlciBvZiBncm91cHMiLA0KICAgICB5bGFiID0gIldpdGhpbiBncm91cHMgc3VtIG9mIHNxdWFyZXMiKQ0KDQojcGxvdHRpbmcgaW4gUEMgc3BhY2Ugc2hvd3MgdXMgdGhhdCB0aGVyZSBhcmUgaW5kZWVkIGRpc3Rpbmd1aXNoYWJsZSA1IGdyb3VwcyANCnBsb3Qoc2FsYXJ5X3BjYV9zY29yZXMsIA0KICAgICBwY2ggPSBrbWVhbnMoc2FsYXJ5X3BjYV9zY29yZXMsIA0KICAgICAgICAgICAgICAgICAgY2VudGVycyA9IDUpJGNsdXN0ZXIpDQoNCiNub3cgd2UgaGF2ZSB0byBzZWUgd2hldGhlciB0aGVzZSBncm91cHMgY29ycmVzcG9uZCB0byBnZW9ncmFwaGljYWwgcmVnaW9ucy4uLg0KDQpgYGANCiMjIyMgY2x1c3RlcmluZyBzYWxhcnkgZGVsdGEgTS1GDQpgYGB7cn0NCnNhbGFyeV9kZWx0YV9wY2Ffc2NvcmVzIDwtIGFzLmRhdGEuZnJhbWUocGNhX3NhbGFyeV9kZWx0YSR4WywxOjNdKQ0KDQpuIDwtIG5yb3coc2FsYXJ5X2RlbHRhX3BjYV9zY29yZXMpDQp3c3MgPC0gcmVwKDAsIDE1KQ0Kd3NzWzFdIDwtIChuIC0gMSkgKiBzdW0oc2FwcGx5KHNhbGFyeV9kZWx0YV9wY2Ffc2NvcmVzLCB2YXIpKQ0KZm9yIChpIGluIDI6MTUpDQogICAgd3NzW2ldIDwtIHN1bShrbWVhbnMoc2FsYXJ5X2RlbHRhX3BjYV9zY29yZXMsDQogICAgICAgICAgICAgICAgICAgICAgICAgY2VudGVycyA9IGkpJHdpdGhpbnNzKQ0KI3dlIGNhbiBzZWUgZnJvbSB0aGUgcGxvdCB0aGF0IG9wdGltYWwgbnVtYmVyIG9mIGNsdXN0ZXIgaXMgNQ0KcGxvdCgxOjE1LCB3c3MsIHR5cGUgPSAiYiIsIA0KICAgICB4bGFiID0gIk51bWJlciBvZiBncm91cHMiLA0KICAgICB5bGFiID0gIldpdGhpbiBncm91cHMgc3VtIG9mIHNxdWFyZXMiKQ0KDQoNCiNwbG90cw0Kc2NhdHRlcjNkKHggPSBzYWxhcnlfZGVsdGFfcGNhX3Njb3JlcyRQQzEsIHkgPSBzYWxhcnlfZGVsdGFfcGNhX3Njb3JlcyRQQzIsIHogPSBzYWxhcnlfZGVsdGFfcGNhX3Njb3JlcyRQQzMsIGdyb3VwcyA9IGFzLmZhY3RvcihrbWVhbnMoc2FsYXJ5X2RlbHRhX3BjYV9zY29yZXMsIA0KICAgICAgICAgICAgICAgICAgY2VudGVycyA9IDYpJGNsdXN0ZXIpLA0KICAgICAgICAgIGdyaWQgPSBGQUxTRSwgc3VyZmFjZSA9IEZBTFNFKQ0KDQpjbHVzdGVycyA8LSBrbWVhbnMoc2FsYXJ5X2RlbHRhX3BjYV9zY29yZXMsIA0KICAgICAgICAgICAgICAgICAgY2VudGVycyA9IDYpDQoNCkZyYU1hcCA9IGdnbWFwKGdldF9nb29nbGVtYXAoY2VudGVyPWZyYV9jZW50ZXIsIHNjYWxlPTIsIHpvb209NiksIGV4dGVudD0ibm9ybWFsIikNCiANCiMgUGxvdCAiRGlzdHJpYnV0aW9uIG9mIHRvdGFsIHBvcHVsYXRpb24gZm9yIGVhY2ggdG93biIgDQpzYWxhcnlfZ2VvIDwtDQogIEZyYU1hcCArDQogIGdlb21fcG9pbnQoYWVzKHg9Z2VvJGxvbmdpdHVkZSwgeT1nZW8kbGF0aXR1ZGUsIGNvbG91cj0gZmFjdG9yKGNsdXN0ZXJzJGNsdXN0ZXIpKSwNCiAgICAgICAgICAgICBkYXRhPWdlbywgYWxwaGE9MC41LCBzaXplPTAuNSkgKyBsYWJzKGNvbG9yPScnKSArIGdndGl0bGUoIkNsdXN0ZXJzIG9mIHRvd25zIGJhc2VkIG9uIG1hbGUtZmVtYWxlIHNhbGFyeSBkaWZmZXJlbmNlIikNCnNhbGFyeV9nZW8NCg0KDQpzYWxhcnlfZGVsdGFfY2x1c3RlciA8LSBjYmluZChzYWxhcnlfdmFyX2RlbHRhLCBjbHVzdGVycyRjbHVzdGVyKQ0KbmFtZXMoc2FsYXJ5X2RlbHRhX2NsdXN0ZXIpWzldIDwtICJjbHVzdGVyIg0Kc2FsX2RlbHRhX2J5X2NsdXN0ZXIgPC0gYWdncmVnYXRlKHNhbGFyeV9kZWx0YV9jbHVzdGVyJE0uRiwgYnk9bGlzdChzYWxhcnlfZGVsdGFfY2x1c3RlciRjbHVzdGVyKSwgRlVOPW1lYW4pWzJdDQpuYW1lcyhzYWxfZGVsdGFfYnlfY2x1c3RlcilbMV0gPC0gIlNhbGFyeV9kaWZmZXJlbmNlIg0KDQpGcmFNYXAgPSBnZ21hcChnZXRfZ29vZ2xlbWFwKGNlbnRlcj1mcmFfY2VudGVyLCBzY2FsZT0yLCB6b29tPTYpLCBleHRlbnQ9Im5vcm1hbCIpDQogDQojIFBsb3QgIkRpc3RyaWJ1dGlvbiBvZiB0b3RhbCBwb3B1bGF0aW9uIGZvciBlYWNoIHRvd24iIA0Kc2FsYXJ5X2dlbyA8LQ0KICBGcmFNYXAgKw0KICBnZW9tX3BvaW50KGFlcyh4PWdlbyRsb25naXR1ZGUsIHk9Z2VvJGxhdGl0dWRlLCBjb2xvdXI9IHNhbGFyeV92YXJpYWJsZXMkc2FsYXJ5X3JhdGlvX0Z2c00pLA0KICAgICAgICAgICAgIGRhdGE9Z2VvLCBhbHBoYT0wLjUsIHNpemU9MC41KSArIGxhYnMoY29sb3I9JycpICsgZ2d0aXRsZSgiRmVtYWxlLU1hbGUgc2FsYXJ5IHJhdGlvIikNCnNhbGFyeV9nZW8NCg0KYGBgDQoNCiMjIyMgRmluZGluZyB0b3ducyB3aXRoIGxhcmdlIGRpZmZlcmVuY2UgaW4gbWFsZS1mZW1hbGUgc2FsYXJpZXMNCmBgYHtyfQ0KI2RldGVjdGluZyBleHRyZW1lIGNpdGllcyBpbiBQQ0ENCnF1YW50aWxlczwtdGFwcGx5KHNhbGFyeV9kZWx0YV9wY2Ffc2NvcmVzJFBDMSxmaXJtcyR0b3duLHF1YW50aWxlKQ0KbWlucSA8LSBzYXBwbHkoZmlybXMkdG93biwgZnVuY3Rpb24oeCkgcXVhbnRpbGVzW1t4XV1bIjI1JSJdKQ0KbWF4cSA8LSBzYXBwbHkoZmlybXMkdG93biwgZnVuY3Rpb24oeCkgcXVhbnRpbGVzW1t4XV1bIjc1JSJdKQ0KDQoNCnRvd25zIDwtIGFzLmRhdGEuZnJhbWUoZmlybXMkdG93bikNCmsgPC0gc2FsYXJ5X2RlbHRhX3BjYV9zY29yZXNbd2hpY2goc2FsYXJ5X2RlbHRhX3BjYV9zY29yZXMkUEMxPG1pbnEgfCBzYWxhcnlfZGVsdGFfcGNhX3Njb3JlcyRQQzE+bWF4cSksIF0NCg0KI2ZpbmQgdG93bnMgd2l0aCBsYXJnZWRpZmZlcmVuY2UgDQpleHRyZW1lX3Rvd25fbGlzdCA8LSB0b3duc1t3aGljaChzYWxhcnlfZGVsdGFfcGNhX3Njb3JlcyRQQzE8bWlucSB8IHNhbGFyeV9kZWx0YV9wY2Ffc2NvcmVzJFBDMT5tYXhxKSwgXQ0KDQpleHRyZW1lX3Rvd25zIDwtIGFzLmRhdGEuZnJhbWUoZXh0cmVtZV90b3duX2xpc3QpDQoNCg0KI2RldGVjdGluZyBleHRyZW1lIGNpdGllcyBpbiBzYWxhcnkgZGVsdGENCnF1YW50aWxlczwtdGFwcGx5KHNhbGFyeV92YXJfZGVsdGEkTS5GLGZpcm1zJHRvd24scXVhbnRpbGUpDQptaW5xIDwtIHNhcHBseShmaXJtcyR0b3duLCBmdW5jdGlvbih4KSBxdWFudGlsZXNbW3hdXVsiMjUlIl0pDQptYXhxIDwtIHNhcHBseShmaXJtcyR0b3duLCBmdW5jdGlvbih4KSBxdWFudGlsZXNbW3hdXVsiNzUlIl0pDQoNCnRvd24gPC0gdG93bnNbd2hpY2goc2FsYXJ5X3Zhcl9kZWx0YSRNLkY8bWlucSB8IA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2FsYXJ5X3Zhcl9kZWx0YSRNLkY+bWF4cSksIF0NCg0KZXh0cmVtZV90b3duc19tX2YgPC0gYXMuZGF0YS5mcmFtZSh0b3duKQ0KDQpnZW8gPC0gYXMuZGF0YS5mcmFtZShjYmluZChmaXJtcyR0b3duLCBnZW8pKQ0KY29sbmFtZXMoZ2VvKVtjb2xuYW1lcyhnZW8pPT0iZmlybXMkdG93biJdIDwtICJ0b3duIg0KZ2VvX2V4dHJlbWUgPC0gc3Vic2V0KGdlbywgdG93biAlaW4lIGV4dHJlbWVfdG93bnNfbV9mJHRvd24pDQpnZW9fZXh0cmVtZSA8LSBnZW9fZXh0cmVtZVssIGMoInRvd24iLCAibGF0aXR1ZGUiLCAibG9uZ2l0dWRlIildDQoNCkZyYU1hcCA9IGdnbWFwKGdldF9nb29nbGVtYXAoY2VudGVyPWZyYV9jZW50ZXIsIHNjYWxlPTIsIHpvb209NiksIGV4dGVudD0ibm9ybWFsIikNCiANCiMgUGxvdCAiRGlzdHJpYnV0aW9uIG9mIHRvdGFsIHBvcHVsYXRpb24gZm9yIGVhY2ggdG93biIgDQpzYWxhcnlfZ2VvIDwtDQogIEZyYU1hcCArDQogIGdlb21fcG9pbnQoYWVzKHg9Z2VvX2V4dHJlbWUkbG9uZ2l0dWRlLCB5PWdlb19leHRyZW1lJGxhdGl0dWRlKSwNCiAgICAgICAgICAgICBkYXRhPWdlb19leHRyZW1lLCBjb2w9InJlZCIsIGFscGhhPTAuNSwgc2l6ZT0wLjUpICsgbGFicyhjb2xvcj0nJykgKyBnZ3RpdGxlKCJUb3ducyB3aXRoIGxhcmdlIGRpZmZlcmVuY2UgaW4gbWFsZS1mZW1hbGUgc2FsYXJpZXMiKQ0Kc2FsYXJ5X2dlbw0KDQojQXMgeW91IGNhbiBzZWUsIHRoZSB0b3ducyB3aXRoIGxhcmdlIHNhbHJ5IGRpZmZlcmVuY2VzIGFyZSBjb25jZXRyYXRlZCBhcm91bmQgbGFyZ2UgY2l0aWVzIHN1Y2ggYXMgUGFyaXMgYW5kIEx5b24uDQoNCmBgYA0KIyMjIyBjbHVzdGVyaW5nIHRvd25zIGJhc2VkIG9uIHVuZW1wbG95ZWQgJQ0KYGBge3J9DQp1bmVtcF9wZXJjZW50IDwtIGFzLmRhdGEuZnJhbWUoKGluZXEkdW5lbXAxNV82NC9pbmVxJHBvcDE1XzY0KSoxMDApDQpuYW1lcyh1bmVtcF9wZXJjZW50KVsxXSA8LSAidW5lbXBfcGVyY2VudCINCg0KbiA8LSBucm93KHVuZW1wX3BlcmNlbnQpDQp3c3MgPC0gcmVwKDAsIDE1KQ0Kd3NzWzFdIDwtIChuIC0gMSkgKiBzdW0oc2FwcGx5KHVuZW1wX3BlcmNlbnQsIHZhcikpDQpmb3IgKGkgaW4gMjoxNSkNCiAgICB3c3NbaV0gPC0gc3VtKGttZWFucyh1bmVtcF9wZXJjZW50LA0KICAgICAgICAgICAgICAgICAgICAgICAgIGNlbnRlcnMgPSBpKSR3aXRoaW5zcykNCiN3ZSBjYW4gc2VlIGZyb20gdGhlIHBsb3QgdGhhdCBvcHRpbWFsIG51bWJlciBvZiBjbHVzdGVyIGlzIDYNCnBsb3QoMToxNSwgd3NzLCB0eXBlID0gImIiLCANCiAgICAgeGxhYiA9ICJOdW1iZXIgb2YgZ3JvdXBzIiwNCiAgICAgeWxhYiA9ICJXaXRoaW4gZ3JvdXBzIHN1bSBvZiBzcXVhcmVzIikNCg0KY2x1c3RlcnMgPC0ga21lYW5zKHVuZW1wX3BlcmNlbnQsIDYpDQoNCnVuZW1wX3BlcmNlbnQgPC0gY2JpbmQodW5lbXBfcGVyY2VudCwgY2x1c3RlcnMkY2x1c3RlcikNCm5hbWVzKHVuZW1wX3BlcmNlbnQpWzJdIDwtICJjbHVzdGVyIg0KdW5lbXBfYnlfY2x1c3RlciA8LSBhZ2dyZWdhdGUodW5lbXBfcGVyY2VudCR1bmVtcF9wZXJjZW50LCBieT1saXN0KHVuZW1wX3BlcmNlbnQkY2x1c3RlciksIEZVTj1tZWFuKVsyXQ0KbmFtZXModW5lbXBfYnlfY2x1c3RlcilbMV0gPC0gInVuZW1wX3JhdGUoJSkiIA0KDQpGcmFNYXAgPSBnZ21hcChnZXRfZ29vZ2xlbWFwKGNlbnRlcj1mcmFfY2VudGVyLCBzY2FsZT0yLCB6b29tPTYpLCBleHRlbnQ9Im5vcm1hbCIpDQogDQojIFBsb3QgIkRpc3RyaWJ1dGlvbiBvZiB0b3RhbCBwb3B1bGF0aW9uIGZvciBlYWNoIHRvd24iIA0Kc2FsYXJ5X2dlbyA8LQ0KICBGcmFNYXAgKw0KICBnZW9tX3BvaW50KGFlcyh4PWdlbyRsb25naXR1ZGUsIHk9Z2VvJGxhdGl0dWRlLCBjb2xvdXI9IGZhY3RvcihjbHVzdGVycyRjbHVzdGVyKSwgc2l6ZSA9IHVuZW1wX3BlcmNlbnQkdW5lbXBfcGVyY2VudCksIGRhdGE9Z2VvLCBhbHBoYT0wLjUsIHNpemU9MC41KSArIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWUgPSAiVW5lbXBsb3ltZW50IHJhdGUiLCB2YWx1ZXMgPSB1bmVtcF9ieV9jbHVzdGVyJGB1bmVtcF9yYXRlKCUpYCkgKyBsYWJzKGNvbG9yPScnKSArIGdndGl0bGUoIkNsdXN0ZXJzIG9mIHRvd25zIGJhc2VkIG9uIHVuZW1wbG95bWVudCByYXRlIikNCnNhbGFyeV9nZW8NCg0KDQoNCmBgYA0KDQojIyMjIENsdXN0ZXJpbmcgYmFzZWQgb24gTG9jYXRpb25hbCBHaW5pIENvZWZmaWNpZW50DQpgYGB7cn0NCmluZHVzdHJ5IDwtIGNvbW11bmVbLCBjKCJuYl9maXJtc19zZXJ2aWNlIiwgIm5iX2Zpcm1zX2NvbW1lcmNlIiwgIm5iX2Zpcm1zX2NvbnN0cnVjdGlvbiIpXQ0KDQpscV9zZXJ2aWNlIDwtIChpbmR1c3RyeSRuYl9maXJtc19zZXJ2aWNlLyhpbmR1c3RyeSRuYl9maXJtc19zZXJ2aWNlK2luZHVzdHJ5JG5iX2Zpcm1zX2NvbW1lcmNlK2luZHVzdHJ5JG5iX2Zpcm1zX2NvbnN0cnVjdGlvbikpLyhzdW0oaW5kdXN0cnkkbmJfZmlybXNfc2VydmljZSkvc3VtKGluZHVzdHJ5KSkNCmxxX3NlcnZpY2UgPC0gYXMuZGF0YS5mcmFtZSgobHFfc2VydmljZSkpDQoNCg0KbHFfY29tbWVyY2UgPC0gKGluZHVzdHJ5JG5iX2Zpcm1zX2NvbW1lcmNlLyhpbmR1c3RyeSRuYl9maXJtc19zZXJ2aWNlK2luZHVzdHJ5JG5iX2Zpcm1zX2NvbW1lcmNlK2luZHVzdHJ5JG5iX2Zpcm1zX2NvbnN0cnVjdGlvbikpLyhzdW0oaW5kdXN0cnkkbmJfZmlybXNfY29tbWVyY2UpL3N1bShpbmR1c3RyeSkpDQpscV9jb21tZXJjZSA8LSBhcy5kYXRhLmZyYW1lKChscV9jb21tZXJjZSkpDQoNCmxxX2NvbnN0cnVjdGlvbiA8LSAoaW5kdXN0cnkkbmJfZmlybXNfY29uc3RydWN0aW9uLyhpbmR1c3RyeSRuYl9maXJtc19zZXJ2aWNlK2luZHVzdHJ5JG5iX2Zpcm1zX2NvbW1lcmNlK2luZHVzdHJ5JG5iX2Zpcm1zX2NvbnN0cnVjdGlvbikpLyhzdW0oaW5kdXN0cnkkbmJfZmlybXNfY29uc3RydWN0aW9uKS9zdW0oaW5kdXN0cnkpKQ0KbHFfY29uc3RydWN0aW9uIDwtIGFzLmRhdGEuZnJhbWUoKGxxX2NvbnN0cnVjdGlvbikpDQoNCmluZHVzdHJ5X2xxIDwtIGNiaW5kKGluZHVzdHJ5LCBscV9zZXJ2aWNlLCBscV9jb21tZXJjZSwgbHFfY29uc3RydWN0aW9uKQ0KI2NyZWF0ZSBkYXRhZnJhbWUgd2l0aCB0aGUgY291bnRzIG9mIHRvd25zIHBlciByZWdpb24NCnJlZ2lvbnNfY291bnQgPC0gZGF0YS5mcmFtZSh0YWJsZShzYWxhcnlfd2l0aF9kZXAkcmVnaW9uKSkNCnJlZ2lvbnNfY291bnRfc3ViPC1yZWdpb25zX2NvdW50WyEocmVnaW9uc19jb3VudCRGcmVxPT0wIHwgcmVnaW9uc19jb3VudCRGcmVxPT0xKSxdDQojY2hlY2sgdG90YWwgc3VtDQpyb3cubmFtZXMocmVnaW9uc19jb3VudF9zdWIpIDwtIDE6bnJvdyhyZWdpb25zX2NvdW50X3N1YikNCnN1bShyZWdpb25zX2NvdW50X3N1YiRGcmVxKQ0KDQppbmR1c3RyeV9scSA8LSBjYmluZChmaXJtcyR0b3duLCBpbmR1c3RyeV9scSkNCm5hbWVzKGluZHVzdHJ5X2xxKVsxXSA8LSAidG93biIgDQpuYW1lcyhpbmR1c3RyeV9scSlbNV0gPC0gImxxX3NlcnZpY2UiDQpuYW1lcyhpbmR1c3RyeV9scSlbNl0gPC0gImxxX2NvbW1lcmNlIg0KbmFtZXMoaW5kdXN0cnlfbHEpWzddIDwtICJscV9jb25zdHJ1Y3Rpb24iDQoNCmRtIDwtIGRpc3QoaW5kdXN0cnlfbHFbLCA1OjddKQ0KI3JvdW5kIHRvIHR3byBkZWNpbWFscw0KZG0gPC0gcm91bmQoZG0sIDIpDQogDQojIEstbWVhbnMgY2x1c3RlcmluZw0KbiA8LSBucm93KGluZHVzdHJ5X2xxKQ0Kd3NzIDwtIHJlcCgwLCAyMikNCndzc1sxXSA8LSAobiAtIDEpICogc3VtKHNhcHBseShpbmR1c3RyeV9scVssIDU6N10sIHZhcikpDQpmb3IgKGkgaW4gMjoyMikNCiAgICB3c3NbaV0gPC0gc3VtKGttZWFucyhpbmR1c3RyeV9scVssIDU6N10sDQogICAgICAgICAgICAgICAgICAgICAgICAgY2VudGVycyA9IGkpJHdpdGhpbnNzKQ0KI3dlIGNhbiBzZWUgZnJvbSB0aGUgcGxvdCB0aGF0IG9wdGltYWwgbnVtYmVyIG9mIGNsdXN0ZXIgaXMgNQ0KcGxvdCgxOjIyLCB3c3MsIHR5cGUgPSAiYiIsIA0KICAgICB4bGFiID0gIk51bWJlciBvZiBncm91cHMiLA0KICAgICB5bGFiID0gIldpdGhpbiBncm91cHMgc3VtIG9mIHNxdWFyZXMiKQ0KDQpjbHVzdGVycyA8LSBrbWVhbnMoaW5kdXN0cnlfbHFbLCA1OjddLCA1KQ0KDQojTWFwcGluZyB0aGUgdG93bnMgYmFzZWQgb24gdGhlIGxvY2F0aW9uYWwgR2luaSBjb2VmZmljaWVudA0KRnJhTWFwID0gZ2dtYXAoZ2V0X2dvb2dsZW1hcChjZW50ZXI9ZnJhX2NlbnRlciwgc2NhbGU9Miwgem9vbT02KSwgZXh0ZW50PSJub3JtYWwiKQ0KIA0KIyBQbG90ICJEaXN0cmlidXRpb24gb2YgdG90YWwgcG9wdWxhdGlvbiBmb3IgZWFjaCB0b3duIiANCnNhbGFyeV9nZW8gPC0NCiAgRnJhTWFwICsNCiAgZ2VvbV9wb2ludChhZXMoeD1nZW8kbG9uZ2l0dWRlLCB5PWdlbyRsYXRpdHVkZSwgY29sb3VyPSBmYWN0b3IoY2x1c3RlcnMkY2x1c3RlcikpLA0KICAgICAgICAgICAgIGRhdGE9Z2VvLCBhbHBoYT0wLjUsIHNpemU9MC41KSArIGxhYnMoY29sb3I9JycpICsgZ2d0aXRsZSgiQ2x1c3RlcnMgb2YgdG93bnMgYmFzZWQgb24gbG9jYXRpb25hbCBnaW5pIGNvZWZmaWNpZW50IikNCnNhbGFyeV9nZW8NCg0KDQpgYGANCg0KIyMjIyBhcHBpbmcgdGhlIHRvd25zIGJhc2VkIG9uIHRoZSBpbnRlbnNpdHkgb2YgbG9jYXRpb25hbCBHaW5pIGNvZWZmaWNpZW50DQpgYGB7cn0NCiNNYXBwaW5nIHRoZSB0b3ducyBiYXNlZCBvbiB0aGUgaW50ZW5zaXR5IG9mIGxvY2F0aW9uYWwgR2luaSBjb2VmZmljaWVudCBvZiB0aGUgc2VydmljZSBpbmR1c3RyeQ0KRnJhTWFwID0gZ2dtYXAoZ2V0X2dvb2dsZW1hcChjZW50ZXI9ZnJhX2NlbnRlciwgc2NhbGU9Miwgem9vbT02KSwgZXh0ZW50PSJub3JtYWwiKQ0KIA0KIyBQbG90ICJEaXN0cmlidXRpb24gb2YgdG90YWwgcG9wdWxhdGlvbiBmb3IgZWFjaCB0b3duIiANCnNhbGFyeV9nZW8gPC0NCiAgRnJhTWFwICsNCiAgZ2VvbV9wb2ludChhZXMoeD1nZW8kbG9uZ2l0dWRlLCB5PWdlbyRsYXRpdHVkZSwgY29sb3VyPSBpbmR1c3RyeV9scSRscV9zZXJ2aWNlKSwNCiAgICAgICAgICAgICBkYXRhPWdlbywgYWxwaGE9MC41LCBzaXplPTAuNSkgKyBsYWJzKGNvbG9yPScnKSArIGdndGl0bGUoIlRvd25zIGJhc2VkIG9uIHNlcnZpY2UgbG9jYXRpb25hbCBnaW5pIGNvZWZmaWNpZW50IikNCnNhbGFyeV9nZW8NCg0KI01hcHBpbmcgdGhlIHRvd25zIGJhc2VkIG9uIHRoZSBpbnRlbnNpdHkgb2YgbG9jYXRpb25hbCBHaW5pIGNvZWZmaWNpZW50IG9mIHRoZSBjb21tZXJjZSBpbmR1c3RyeQ0KRnJhTWFwID0gZ2dtYXAoZ2V0X2dvb2dsZW1hcChjZW50ZXI9ZnJhX2NlbnRlciwgc2NhbGU9Miwgem9vbT02KSwgZXh0ZW50PSJub3JtYWwiKQ0KIA0KIyBQbG90ICJEaXN0cmlidXRpb24gb2YgdG90YWwgcG9wdWxhdGlvbiBmb3IgZWFjaCB0b3duIiANCnNhbGFyeV9nZW8gPC0NCiAgRnJhTWFwICsNCiAgZ2VvbV9wb2ludChhZXMoeD1nZW8kbG9uZ2l0dWRlLCB5PWdlbyRsYXRpdHVkZSwgY29sb3VyPSBpbmR1c3RyeV9scSRscV9jb21tZXJjZSksDQogICAgICAgICAgICAgZGF0YT1nZW8sIGFscGhhPTAuNSwgc2l6ZT0wLjUpICsgbGFicyhjb2xvcj0nJykgKyBnZ3RpdGxlKCJUb3ducyBiYXNlZCBvbiBjb21tZXJjZSBsb2NhdGlvbmFsIGdpbmkgY29lZmZpY2llbnQiKQ0Kc2FsYXJ5X2dlbw0KDQojTWFwcGluZyB0aGUgdG93bnMgYmFzZWQgb24gdGhlIGludGVuc2l0eSBvZiBsb2NhdGlvbmFsIEdpbmkgY29lZmZpY2llbnQgb2YgdGhlIGNvbW1lcmNlIGluZHVzdHJ5DQpGcmFNYXAgPSBnZ21hcChnZXRfZ29vZ2xlbWFwKGNlbnRlcj1mcmFfY2VudGVyLCBzY2FsZT0yLCB6b29tPTYpLCBleHRlbnQ9Im5vcm1hbCIpDQogDQojIFBsb3QgIkRpc3RyaWJ1dGlvbiBvZiB0b3RhbCBwb3B1bGF0aW9uIGZvciBlYWNoIHRvd24iIA0Kc2FsYXJ5X2dlbyA8LQ0KICBGcmFNYXAgKw0KICBnZW9tX3BvaW50KGFlcyh4PWdlbyRsb25naXR1ZGUsIHk9Z2VvJGxhdGl0dWRlLCBjb2xvdXI9IGluZHVzdHJ5X2xxJGxxX2NvbnN0cnVjdGlvbiksDQogICAgICAgICAgICAgZGF0YT1nZW8sIGFscGhhPTAuNSwgc2l6ZT0wLjUpICsgbGFicyhjb2xvcj0nJykgKyBnZ3RpdGxlKCJUb3ducyBiYXNlZCBvbiBjb25zdHJ1Y3Rpb24gbG9jYXRpb25hbCBnaW5pIGNvZWZmaWNpZW50IikNCnNhbGFyeV9nZW8NCg0KYGBgDQoNCg0KIyMjIyBTYWxhcnkgY2x1c3RlcnMgDQpgYGB7cn0NCiNjcmVhdGUgZGlzdGFuY2UgbWF0cml4IGZvciBoY2x1c3QNCmRtIDwtIGRpc3Qoc2FsYXJ5X3ZhcmlhYmxlcykNCiNyb3VuZCB0byB0d28gZGVjaW1hbHMNCmRtIDwtIHJvdW5kKGRtLCAyKQ0KIA0KIyBLLW1lYW5zIGNsdXN0ZXJpbmcNCm4gPC0gbnJvdyhzYWxhcnlfdmFyaWFibGVzKQ0Kd3NzIDwtIHJlcCgwLCAyMikNCndzc1sxXSA8LSAobiAtIDEpICogc3VtKHNhcHBseShzYWxhcnlfdmFyaWFibGVzLCB2YXIpKQ0KZm9yIChpIGluIDI6MjIpDQogICAgd3NzW2ldIDwtIHN1bShrbWVhbnMoc2FsYXJ5X3ZhcmlhYmxlcywNCiAgICAgICAgICAgICAgICAgICAgICAgICBjZW50ZXJzID0gaSkkd2l0aGluc3MpDQojd2UgY2FuIHNlZSBmcm9tIHRoZSBwbG90IHRoYXQgb3B0aW1hbCBudW1iZXIgb2YgY2x1c3RlciBpcyA1DQpwbG90KDE6MjIsIHdzcywgdHlwZSA9ICJiIiwgDQogICAgIHhsYWIgPSAiTnVtYmVyIG9mIGdyb3VwcyIsDQogICAgIHlsYWIgPSAiV2l0aGluIGdyb3VwcyBzdW0gb2Ygc3F1YXJlcyIpDQoNCiNub3cgd2UgaGF2ZSB0byBzZWUgd2hldGhlciB0aGVzZSBncm91cHMgY29ycmVzcG9uZCB0byBnZW9ncmFwaGljYWwgcmVnaW9ucy4uLg0KYGBgDQoNCg0KIyMjIyBNYXBwaW5nIHRoZSBzYWxhcnkgY2x1c3RlcnMNCmBgYHtyfQ0KIA0KI25vdyB3ZSBoYXZlIHRvIHNlZSB3aGV0aGVyIHRoZXNlIGdyb3VwcyBjb3JyZXNwb25kIHRvIGdlb2dyYXBoaWNhbCByZWdpb25zLi4uDQpjbHVzdGVycyA8LSBrbWVhbnMoc2FsYXJ5X3ZhcmlhYmxlcywgNikNCnNhbGFyeV93aXRoX2RlcCRjbHVzdGVyIDwtIGNsdXN0ZXJzJGNsdXN0ZXINCmdlbyRjbHVzdGVyIDwtIGNsdXN0ZXJzJGNsdXN0ZXINCiANCkZyYU1hcCA9IGdnbWFwKGdldF9nb29nbGVtYXAoY2VudGVyPWZyYV9jZW50ZXIsIHNjYWxlPTIsIHpvb209NiksIGV4dGVudD0ibm9ybWFsIikNCiANCiMgUGxvdCAiRGlzdHJpYnV0aW9uIG9mIHRvdGFsIHBvcHVsYXRpb24gZm9yIGVhY2ggdG93biIgDQpzYWxhcnlfZ2VvIDwtDQogIEZyYU1hcCArDQogIGdlb21fcG9pbnQoYWVzKHg9Z2VvJGxvbmdpdHVkZSwgeT1nZW8kbGF0aXR1ZGUsIGNvbG91cj0gZmFjdG9yKGdlbyRjbHVzdGVyKSksDQogICAgICAgICAgICAgZGF0YT1nZW8sIGFscGhhPTAuNSwgc2l6ZT0wLjUpICsgbGFicyhjb2xvcj0nJykgKyBnZ3RpdGxlKCJDbHVzdGVycyBvZiB0b3ducyBiYXNlZCBvbiBzYWxhcnkiKQ0Kc2FsYXJ5X2dlbw0KDQpzYWxhcnlfY2wgPC0gY2JpbmQoc2FsYXJ5X3ZhcmlhYmxlcywgY2x1c3RlcnMkY2x1c3RlcikNCm5hbWVzKHNhbGFyeV9jbClbMzNdIDwtICJjbHVzdGVyIg0Kc2FsYXJ5X2NsdXN0ZXIgPC0gYWdncmVnYXRlKHNhbGFyeV9jbCRzYWxfZ2VuZXJhbCwgYnk9bGlzdChzYWxhcnlfY2wkY2x1c3RlciksIEZVTj1tZWFuKVsyXQ0KbmFtZXMoc2FsYXJ5X2NsdXN0ZXIpWzFdIDwtICJzYWxhcnkiIA0KDQogDQpgYGANCg0KDQojIyMjIENsdXN0ZXJpbmcgb24gc2VsZWN0ZWQgdmFyaWFibGVzDQpgYGB7cn0NCnNlbGVjdGVkX3BjYV9zY29yZXM8LSBhcy5kYXRhLmZyYW1lKHBjYV9zZWxlY3RlZF92YXJpYWJsZXMkeFssMTozXSkNCg0KIyBLLW1lYW5zIGNsdXN0ZXJpbmcNCm4gPC0gbnJvdyhzZWxlY3RlZF92YXJpYWJsZXMpDQp3c3MgPC0gcmVwKDAsIDIyKQ0Kd3NzWzFdIDwtIChuIC0gMSkgKiBzdW0oc2FwcGx5KHNlbGVjdGVkX3ZhcmlhYmxlcywgdmFyKSkNCmZvciAoaSBpbiAyOjIyKQ0KICAgIHdzc1tpXSA8LSBzdW0oa21lYW5zKHNlbGVjdGVkX3ZhcmlhYmxlcywNCiAgICAgICAgICAgICAgICAgICAgICAgICBjZW50ZXJzID0gaSkkd2l0aGluc3MpDQojd2UgY2FuIHNlZSBmcm9tIHRoZSBwbG90IHRoYXQgb3B0aW1hbCBudW1iZXIgb2YgY2x1c3RlciBpcyA3DQpwbG90KDE6MjIsIHdzcywgdHlwZSA9ICJiIiwgDQogICAgIHhsYWIgPSAiTnVtYmVyIG9mIGdyb3VwcyIsDQogICAgIHlsYWIgPSAiV2l0aGluIGdyb3VwcyBzdW0gb2Ygc3F1YXJlcyIpDQoNCmNsdXN0ZXJzIDwtIGttZWFucyhzZWxlY3RlZF92YXJpYWJsZXMsIGNlbnRlcnMgPSA3KQ0Kc2NhdHRlcjNkKHggPSBzZWxlY3RlZF9wY2Ffc2NvcmVzJFBDMSwgeSA9IHNlbGVjdGVkX3BjYV9zY29yZXMkUEMyLCB6ID0gc2VsZWN0ZWRfcGNhX3Njb3JlcyRQQzMsIGdyb3VwcyA9IGFzLmZhY3RvcihjbHVzdGVycyRjbHVzdGVyKSwNCiAgICAgICAgICBncmlkID0gRkFMU0UsIHN1cmZhY2UgPSBGQUxTRSkNCg0KRnJhTWFwID0gZ2dtYXAoZ2V0X2dvb2dsZW1hcChjZW50ZXI9ZnJhX2NlbnRlciwgc2NhbGU9Miwgem9vbT02KSwgZXh0ZW50PSJub3JtYWwiKQ0KIA0KIyBQbG90ICJEaXN0cmlidXRpb24gb2YgdG90YWwgcG9wdWxhdGlvbiBmb3IgZWFjaCB0b3duIiANCnNhbGFyeV9nZW8gPC0NCiAgRnJhTWFwICsNCiAgZ2VvbV9wb2ludChhZXMoeD1nZW8kbG9uZ2l0dWRlLCB5PWdlbyRsYXRpdHVkZSwgY29sb3VyPSBmYWN0b3IoY2x1c3RlcnMkY2x1c3RlcikpLA0KICAgICAgICAgICAgIGRhdGE9Z2VvLCBhbHBoYT0wLjUsIHNpemU9MC41KSArIGxhYnMoY29sb3I9JycpICsgZ2d0aXRsZSgiQ2x1c3RlcnMgb2YgdG93bnMgYmFzZWQgb24gc2VsZWN0ZWQgdmFyaWFibGVzIikNCnNhbGFyeV9nZW8NCg0KDQpgYGANCg0KIyMjIyBDbHVzdGVyaW5nIGluIGNvbW11bmUNCmBgYHtyfQ0KI0sgbWVhbnMNCg0KbiA8LSBucm93KGNvbW11bmVfdHJpbW1lZCkNCndzcyA8LSByZXAoMCwgMTUpDQp3c3NbMV0gPC0gKG4gLSAxKSAqIHN1bShzYXBwbHkoY29tbXVuZV90cmltbWVkLCB2YXIpKQ0KZm9yIChpIGluIDI6MTUpDQogICAgd3NzW2ldIDwtIHN1bShrbWVhbnMoY29tbXVuZV90cmltbWVkLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGNlbnRlcnMgPSBpKSR3aXRoaW5zcykNCiN3ZSBjYW4gc2VlIGZyb20gdGhlIHBsb3QgdGhhdCBvcHRpbWFsIG51bWJlciBvZiBjbHVzdGVyIGlzIDExDQpwbG90KDE6MTUsIHdzcywgdHlwZSA9ICJiIiwNCiAgICAgeGxhYiA9ICJOdW1iZXIgb2YgZ3JvdXBzIiwNCiAgICAgeWxhYiA9ICJXaXRoaW4gZ3JvdXBzIHN1bSBvZiBzcXVhcmVzIikNCg0KYGBgDQoNCg0KIyMjIyBNYXBwaW5nIHRoZSBuZXcgY2x1c3RlcnMNCmBgYHtyfQ0KbiA8LSBucm93KGNvbW11bmVfdHJpbW1lZCkNCndzcyA8LSByZXAoMCwgMjIpDQp3c3NbMV0gPC0gKG4gLSAxKSAqIHN1bShzYXBwbHkoY29tbXVuZV90cmltbWVkJGFjdGl2ZV9lbXBsX3Byb3AsIHZhcikpDQpmb3IgKGkgaW4gMjoyMikNCiAgICB3c3NbaV0gPC0gc3VtKGttZWFucyhjb21tdW5lX3RyaW1tZWQkYWN0aXZlX2VtcGxfcHJvcCwNCiAgICAgICAgICAgICAgICAgICAgICAgICBjZW50ZXJzID0gaSkkd2l0aGluc3MpDQojd2UgY2FuIHNlZSBmcm9tIHRoZSBwbG90IHRoYXQgb3B0aW1hbCBudW1iZXIgb2YgY2x1c3RlciBpcyA3DQpwbG90KDE6MjIsIHdzcywgdHlwZSA9ICJiIiwgDQogICAgIHhsYWIgPSAiTnVtYmVyIG9mIGdyb3VwcyIsDQogICAgIHlsYWIgPSAiV2l0aGluIGdyb3VwcyBzdW0gb2Ygc3F1YXJlcyIpDQoNCiNub3cgd2UgaGF2ZSB0byBzZWUgd2hldGhlciB0aGVzZSBncm91cHMgY29ycmVzcG9uZCB0byBnZW9ncmFwaGljYWwgcmVnaW9ucy4uLg0KDQpGcmFNYXAgPSBnZ21hcChnZXRfZ29vZ2xlbWFwKGNlbnRlcj1mcmFfY2VudGVyLCBzY2FsZT0yLCB6b29tPTYpLCBleHRlbnQ9Im5vcm1hbCIpDQoNCiMgUGxvdCAiRGlzdHJpYnV0aW9uIG9mIHRvdGFsIHBvcHVsYXRpb24gZm9yIGVhY2ggdG93biINCm5ld0RhdF9nZW8gPC0NCiAgRnJhTWFwICsNCiAgZ2VvbV9wb2ludChhZXMoeD1nZW8kbG9uZ2l0dWRlLCB5PWdlbyRsYXRpdHVkZSwgY29sb3VyPSBmYWN0b3Ioa21lYW5zKGNvbW11bmVfdHJpbW1lZCRhY3RpdmVfZW1wbF9wcm9wLCANCiAgICAgICAgICAgICAgICAgIGNlbnRlcnMgPSA2KSRjbHVzdGVyKSksDQogICAgICAgICAgICAgZGF0YT1nZW8sIGFscGhhPTAuNSwgc2l6ZT0wLjUpICsgbGFicyhjb2xvcj0nJykgKyBnZ3RpdGxlKCJDbHVzdGVycyBvZiB0b3ducyBiYXNlZCBvbiBhY3RpdmUgZW1wbG95ZWVzIHByb3BvcnRpb24iKQ0KbmV3RGF0X2dlbw0KDQpGcmFNYXAgPSBnZ21hcChnZXRfZ29vZ2xlbWFwKGNlbnRlcj1mcmFfY2VudGVyLCBzY2FsZT0yLCB6b29tPTYpLCBleHRlbnQ9Im5vcm1hbCIpDQoNCiMgUGxvdCAiRGlzdHJpYnV0aW9uIG9mIHRvdGFsIHBvcHVsYXRpb24gZm9yIGVhY2ggdG93biINCm5ld0RhdF9nZW8gPC0NCiAgRnJhTWFwICsNCiAgZ2VvbV9wb2ludChhZXMoeD1nZW8kbG9uZ2l0dWRlLCB5PWdlbyRsYXRpdHVkZSwgY29sb3VyPSBjb21tdW5lX3RyaW1tZWQkYWN0aXZlX2VtcGxfcHJvcCksDQogICAgICAgICAgICAgZGF0YT1nZW8sIGFscGhhPTAuNSwgc2l6ZT0wLjUpICsgbGFicyhjb2xvcj0nJykgKyBnZ3RpdGxlKCJDbHVzdGVycyBvZiB0b3ducyBiYXNlZCBvbiBhY3RpdmUgZW1wbG95ZWVzIikNCm5ld0RhdF9nZW8NCmBgYA0KDQoNCg0KDQoNCiMgU3VwZXJ2aXNlZCBMZWFybmluZw0KDQojIyBBTk9WQSBmb3Igc2FsYXJ5DQoNCkZpcnN0IHRoZSBkaXN0cmlidXRpb24gb2Ygc2FsYXJ5IGZvciBib3RoIGdlbmRlcnMgaXMgY29uc2lkZXJlZCwgaW4gb3JpZ2luYWwgYW5kIGxvZy1zY2FsZQ0KYGBge3IgaGlzdCBzYWxhcnkgZm9yIGdlbmRlcn0NCg0KIyBvcmlnaW5hbCBkYXRhDQojIG1hbGUNCmdncGxvdChkYXRhPWRhdGEuZnJhbWUobmV3RGF0JHNhbF9NYWxlcyksIGFlcyhuZXdEYXQkc2FsX01hbGVzKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9Li5kZW5zaXR5Li4pLCBjb2w9ImJsYWNrIiwgZmlsbD0iYmx1ZSIsIGFscGhhID0gLjMsIGJpbnMgPSA0MCkgKw0KICBnZW9tX2RlbnNpdHkoY29sPSJibGFjayIpICsNCiAgbGFicyh4PSJNYWxlIHNhbGFyaWVzIiwgeT0iRGVuc2l0eSIpICsNCiAgZ2d0aXRsZSgiRGlzdHJpYnV0aW9uIG9mIHNhbGFyeSBmb3IgbWFsZXMiKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQ0KIyBmZW1hbGVzDQpnZ3Bsb3QoZGF0YT1kYXRhLmZyYW1lKG5ld0RhdCRzYWxfRmVtYWxlcyksIGFlcyhuZXdEYXQkc2FsX0ZlbWFsZXMpKSArDQogIGdlb21faGlzdG9ncmFtKGFlcyh5ID0uLmRlbnNpdHkuLiksIGNvbD0iYmxhY2siLCBmaWxsPSJibHVlIiwgYWxwaGEgPSAuMywgYmlucyA9IDQwKSArDQogIGdlb21fZGVuc2l0eShjb2w9ImJsYWNrIikgKw0KICBsYWJzKHg9IkZlbWFsZSBzYWxhcmllcyIsIHk9IkRlbnNpdHkiKSArDQogIGdndGl0bGUoIkRpc3RyaWJ1dGlvbiBvZiBzYWxhcnkgZm9yIGZlbWFsZXMiKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQ0KDQojIGxvZyBkYXRhDQojIG1hbGUNCmdncGxvdChkYXRhPWRhdGEuZnJhbWUobG9nMTAobmV3RGF0JHNhbF9NYWxlcykpLCBhZXMobG9nMTAobmV3RGF0JHNhbF9NYWxlcykpKSArDQogIGdlb21faGlzdG9ncmFtKGFlcyh5ID0uLmRlbnNpdHkuLiksIGNvbD0iYmxhY2siLCBmaWxsPSJibHVlIiwgYWxwaGEgPSAuMywgYmlucyA9IDQwKSArDQogIGdlb21fZGVuc2l0eShjb2w9ImJsYWNrIikgKw0KICBsYWJzKHg9IkxvZzEwIG1hbGUgc2FsYXJpZXMiLCB5PSJEZW5zaXR5IikgKw0KICBnZ3RpdGxlKCJEaXN0cmlidXRpb24gb2Ygc2FsYXJ5IGZvciBtYWxlcyBpbiBsb2cgc2NhbGUiKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQ0KIyBmZW1hbGVzDQpnZ3Bsb3QoZGF0YT1kYXRhLmZyYW1lKGxvZzEwKG5ld0RhdCRzYWxfRmVtYWxlcykpLCBhZXMobG9nMTAobmV3RGF0JHNhbF9GZW1hbGVzKSkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPS4uZGVuc2l0eS4uKSwgY29sPSJibGFjayIsIGZpbGw9ImJsdWUiLCBhbHBoYSA9IC4zLCBiaW5zID0gNDApICsNCiAgZ2VvbV9kZW5zaXR5KGNvbD0iYmxhY2siKSArDQogIGxhYnMoeD0iTG9nMTAgZmVtYWxlIHNhbGFyaWVzIiwgeT0iRGVuc2l0eSIpICsNCiAgZ2d0aXRsZSgiRGlzdHJpYnV0aW9uIG9mIHNhbGFyeSBmb3IgZmVtYWxlcyBpbiBsb2cgc2NhbGUiKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQ0KDQojIGhpc3QoYyhsb2cxMChuZXdEYXQkc2FsX01hbGVzKSwgbG9nMTAobmV3RGF0JHNhbF9GZW1hbGVzKSksIDMwKQ0KDQpgYGANCg0KSXQgaXMgY2xlYXIgdGhhdCB0aGUgbm9ybWFsaXR5IGFzc3VtcHRpb24sIGNhbm5vdCBob2xkLg0KDQpBdCB0aGUgc2FtZSB0aW1lLCBpdCBpcyBzaG93bg0KaG93IHRvIGNoZWNrIGlmIHRoZSBkaWZmZXJlbmNlIGluIHRoZSBtZWFuIGluIHNhbGFyeSANCmJldHdlZW4gbWFsZXMgYW5kIGZlbWFsZXMgdXNpbmcgYSB0LXRlc3QgDQpgYGB7ciBzYWxhcnkgZGlmZmVyZW5jZSB0IHRlc3R9DQoNCnQudGVzdChsb2cxMChuZXdEYXQkc2FsX01hbGVzKSwgbG9nMTAobmV3RGF0JHNhbF9GZW1hbGVzKSwgYWx0ZXJuYXRpdmUgPSBjKCJ0d28uc2lkZWQiKSkNCg0KYGBgDQoNClRoaXMgc29sdXRpb24gY2FuIGFsc28gYmUgb3RiYWluZWQgZml0dGluZyBhIGxpbmVhciBtb2RlbCB3aXRoIGEgZHVtbXkgdmFyaWFibGUgY2F0Y2hpbmcgdGhlIHNleCBlZmZlY3QsDQp3aGljaCBjb3JyZXNwb25kcyB0byBhIG9uZS13YXkgQU5PVkEgbW9kZWwNCmBgYHtyIHNhbGFyeSBkaWZmZXJlbmNlIHQgdGVzdCBhcyBhbiBBTk9WQX0NCg0KIyBjcmVhdGUgdGhlIHJlcG9uc2UgYXR0YWNoaW5nIHRoZSBzYWxhcnkgZm9yIGVhY2ggc2V4DQpzYWxfeSA9IGMobG9nMTAobmV3RGF0JHNhbF9NYWxlcyksIGxvZzEwKG5ld0RhdCRzYWxfRmVtYWxlcykpDQojIGNyZWF0ZSB0aGUgZHVtbXkgdmFyaWFibGUgY29udHJvbGxpbmcgZm9yIHRoZSBjb3JyZXNwb25kaW5nIHNleA0KZHVtbXkgPSBjKHJlcCgxLCBsZW5ndGgobmV3RGF0JHNhbF9NYWxlcykpLCByZXAoMCwgbGVuZ3RoKG5ld0RhdCRzYWxfRmVtYWxlcykpKQ0KDQojIHRoZSB0IHZhbHVlIGlzIGV4YWN0bHkgdGhlIHNhbWUgYXMgdGhlIG9uZSBvYnRhaW5lZCBpbiB0aGUgcHJldmlvdXMgdC10ZXN0DQpzYWxfQU5PVkEgPSBsbShzYWxfeSB+IGR1bW15KQ0Kc3VtbWFyeShzYWxfQU5PVkEpDQoNCiMgcmVzaWR1YWxzIHBsb3QNCnBsb3Qoc2FsX0FOT1ZBJHJlc2lkdWFscykNCmFibGluZSAoMCwgMCwgY29sID0gInJlZCIpDQoNCmBgYA0KDQpUbyBpbXByb3ZlIHN1Y2ggYW5hbHlzaXMgc29tZSBtb3JlIGFzcGVjdHMgYXJlIG5vdyBjb25zaWRlcmVkLg0KSW4gcGFydGljdWFsYXIsIHRoZSBtb2RlbCBjb25zaWRlcmVkIGluIGFuIEFOT1ZBLCB3aGVyZSB0aGUNCnByZWRpY3RvcnMgdGFrZSBpbiBhY2NvdW50IGVhY2ggZ2VuZGVyIGZvciBkaWZmZXJlbnQgYWdlIGFuZCBqb2IgbGV2ZWxzLA0KcGx1cyB0aGVpciBpbnRlcmFjdGlvbiB0ZXJtcy4NCg0KRmlyc3Qgb2YgYWxsIHRoZSBkYXRhc2V0IGlzIGNyZWF0ZWQgYW5kIGEgc3Vic2FtcGxlIG9mIGl0IGlzIGNvbnNpZGVyZWQsIA0KaW4gb3JkZXIgdG8gYXZvaWQgc3Ryb25nIGNvcnJlbGF0aW9uIGFtb25nIHVuaXRzDQpgYGB7ciBzYWxhcnkgY29uc3RydWN0IGZ1bGwgQU5PVkEgbW9kZWx9DQoNCnNldC5zZWVkKDMwMCkNCg0KIyBjcmVhdGUgcmVzcG9uc2UgdmFyaWFibGUNCnNhbF95ID0gYyhuZXdEYXQkc2FsX01fMThfMjUsIG5ld0RhdCRzYWxfTV8yNl81MCwgbmV3RGF0JHNhbF9NXzUxcGx1cywNCiAgICAgICAgICBuZXdEYXQkc2FsX01fZXhlY3V0aXZlLCBuZXdEYXQkc2FsX01fbWlkTWFuYWdlciwgbmV3RGF0JHNhbF9NX2VtcGxveWVlLCBuZXdEYXQkc2FsX01fd29ya2VyLA0KICAgICAgICAgIG5ld0RhdCRzYWxfRl8xOF8yNSwgbmV3RGF0JHNhbF9GXzI2XzUwLCBuZXdEYXQkc2FsX0ZfNTFwbHVzLA0KICAgICAgICAgIG5ld0RhdCRzYWxfRl9leGVjdXRpdmUsIG5ld0RhdCRzYWxfRl9taWRNYW5hZ2VyLCBuZXdEYXQkc2FsX0ZfZW1wbG95ZWUsIG5ld0RhdCRzYWxfRl93b3JrZXIpDQoNCm5fc2FsX3kgPSBsZW5ndGgoc2FsX3kpICAgICAgICAgICAgICMgbGVuZ3RoIHJlc3BvbnNlIHZhcmlhYmxlDQpuX2NhdCA9IGxlbmd0aChuZXdEYXQkc2FsX01fMThfMjUpICAjIGxlbmd0aCBvZiBlYWNoIGNhdGVnb3J5IChpLmUuLCBvcmlnaW5hbCB2ZWN0b3JzKQ0KDQojIGNyZWF0ZSBzZXggZHVtbXkgdmFyaWFibGUsIDEgZm9yIG1hbGVzIGFuZCAwIGZvciBmZW1hbGVzDQpzYWxfc2V4ID0gcmVwKDAsIG5fc2FsX3kpICAgIyBmdWxsIHJlZ3Jlc3NvcnMNCnNhbF9zZXhbMTpuX3NhbF95LzJdID0gMSAgICAjIGFzc2lnbiBtYWxlcw0KDQojIGNyZWF0ZSBhZ2UgZHVtbXkgdmFyaWFibGVzLCAxOC0yNSB5ZWFycyBvbGQgaXMgdGhlIGJhc2UgY2FzZQ0Kc2FsX2FnZSA9IGNiaW5kKHJlcCgwLCBuX3NhbF95KSwgcmVwKDAsIG5fc2FsX3kpKSAjIGZ1bGwgcmVncmVzc29ycw0KIyAyNi01MCB5Lm8uDQpzYWxfYWdlWyhuX2NhdCsxKToobl9jYXQqMiksIDFdID0gMSAgICAgIyBtYWxlcw0Kc2FsX2FnZVsobl9jYXQqOCsxKToobl9jYXQqOSksIDFdID0gMSAgICMgZmVtYWxlcw0KIyA1MSsgeS5vLg0Kc2FsX2FnZVsobl9jYXQqMisxKToobl9jYXQqMyksIDJdID0gMSAgICMgbWFsZXMNCnNhbF9hZ2VbKG5fY2F0KjkrMSk6KG5fY2F0KjEwKSwgMl0gPSAxICAjIGZlbWFsZXMNCg0KIyBjcmVhdGUgam9iIHR5cGUgZHVtbXkgdmFyaWFibGVzLCB3b3JrZXIgaXMgdGhlIGJhc2UgY2FzZQ0Kc2FsX2pvYiA9IGNiaW5kKHJlcCgwLCBuX3NhbF95KSwgcmVwKDAsIG5fc2FsX3kpLCByZXAoMCwgbl9zYWxfeSkpICMgZnVsbCByZWdyZXNzb3JzDQojIGV4ZWN1dGl2ZXMNCnNhbF9qb2JbKG5fY2F0KjMrMSk6KG5fY2F0KjQpLCAxXSA9IDEgICAgICMgbWFsZXMNCnNhbF9qb2JbKG5fY2F0KjEwKzEpOihuX2NhdCoxMSksIDFdID0gMSAgICMgZmVtYWxlcw0KIyBtaWRkbGUgbWFuYWdlcnMNCnNhbF9qb2JbKG5fY2F0KjQrMSk6KG5fY2F0KjUpLCAyXSA9IDEgICAgICMgbWFsZXMNCnNhbF9qb2JbKG5fY2F0KjExKzEpOihuX2NhdCoxMiksIDJdID0gMSAgICMgZmVtYWxlcw0KIyBlbXBsb3llZQ0Kc2FsX2pvYlsobl9jYXQqNSsxKToobl9jYXQqNiksIDNdID0gICAxICAgIyBtYWxlcw0Kc2FsX2pvYlsobl9jYXQqMTIrMSk6KG5fY2F0KjEzKSwgM10gPSAxICAgIyBmZW1hbGVzDQoNCiMgZmluYWwgZGF0YSBzZXQNCmRhdGFfQU5PVkEgPSBjYmluZC5kYXRhLmZyYW1lKHJlc3BvbnNlID0gc2FsX3ksIHNleCA9IHNhbF9zZXgsIGFnZSA9IHNhbF9hZ2UsIGpvYiA9IHNhbF9qb2IpDQojIG5hbWVzKGRhdGFfQU5PVkEpDQojIHNob3cgcmVncmVzc29ycycgc2hhcGUNCmltYWdlbWF0KGRhdGFfQU5PVkFbLC0xXSwgeGF4dCA9ICJuIiwgbWFpbiA9ICJGYWN0b3JzIGZvciBBTk9WQSIpDQpheGlzKDEsIGF0PTE6NiwgbGFiZWxzPWMoIlNleCIsICJBZ2UgMjYtNTAiLCAiQWdlIDUxKyIsICJFeGVjdXQuIiwgIk1pZC5NYW4uIiwgIkVtcGwuIikpDQpib3goKQ0KIyBzdWIgc2FtcGxlIHRvIGF2b2lkIGNvcnJlbGF0aW9uLCAodW5iYWxhbmNlZCBkYXRhc2V0KQ0KIyBzZXQuc2VlZCgyMCkNCnN1YnMgPSBzYW1wbGUoMTpuX3NhbF95LCBzaXplID0gcm91bmQobl9zYWxfeSowLjEpKQ0KZGF0YV9BTk9WQSA9IGRhdGFfQU5PVkFbc3VicyxdDQoNCiMgc2hvdyByYW5kb21pemVkIGRhdGENCmltYWdlbWF0KGRhdGFfQU5PVkFbLC0xXSwgeGF4dCA9ICJuIiwgbWFpbiA9ICJGYWN0b3JzIGZvciBBTk9WQSBhZnRlciBzdWItc2FtcGxpbmciKQ0KYXhpcygxLCBhdD0xOjYsIGxhYmVscz1jKCJTZXgiLCAiQWdlIDI2LTUwIiwgIkFnZSA1MSsiLCAiRXhlY3V0LiIsICJNaWQuTWFuLiIsICJFbXBsLiIpKQ0KYm94KCkNCg0KYGBgDQoNClJ1biB0aGUgQU5PVkEgbW9kZWwsIHRyYW5mb3JtaW5nIHRoZSByZXNwb25zZSB2YXJpYWJsZSB1c2luZyBCb3gtQ294IHRyYW5zZm9ybWF0aW9uDQpgYGB7ciBzYWxhcnkgQU5PVkEgbW9kZWx9DQoNCiMgcGxvdCB0aGUgdHJhbnNmb3JtZWQgcmVzcG9uc2UgdmFyaWFibGUgKHN1Z2dlc3RlZCBieSBCb3gtQ294IHRyYW5zZm9ybWF0aW9uKQ0Kc2FsX3kgPSBkYXRhX0FOT1ZBWywxXV4tMQ0KZ2dwbG90KGRhdGE9ZGF0YS5mcmFtZShkYXRhX0FOT1ZBWywxXSksIGFlcyhzYWxfeSkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPS4uZGVuc2l0eS4uKSwgY29sPSJibGFjayIsIGZpbGw9ImJsdWUiLCBhbHBoYSA9IC4zLCBiaW5zID0gNjApICsNCiAgZ2VvbV9kZW5zaXR5KGNvbD0iYmxhY2siKSArDQogIGxhYnMoeD0ic2FsYXJ5Xi0xIiwgeT0iRGVuc2l0eSIpICsNCiAgZ2d0aXRsZSgiVHJhbnNmb3JtYXRpb24gb2Ygc2FsYXJ5IGZvdW5kIHVzaW5nIEJveC1Db3ggdHJhbnNmb3JtYXRpb24iKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQ0KDQojIHRha2UgdGhlIGlkZW50aWZpZWQgc3Vic2FtcGxlIGZvciBkdW1teSB2YXJpYWJsZXMNCnNleCA9IHNhbF9zZXhbc3Vic10NCmFnZSA9IHNhbF9hZ2Vbc3VicyxdDQpqb2IgPSBzYWxfam9iW3N1YnMsXQ0KIyBBTk9WQSBtb2RlbA0Kc2FsX0FOT1ZBID0gbG0oc2FsX3kgfiBzZXggKyBhZ2UgKyBqb2IgKyBzZXg6YWdlICsgc2V4OmpvYikNCnN1bW1hcnkoc2FsX0FOT1ZBKQ0KYW5vdmEoc2FsX0FOT1ZBKQ0KIyBhb3Yoc2FsX3kgfiBzZXggKyBhZ2UgKyBqb2IgKyBzZXg6YWdlICsgc2V4OmpvYikNCnBsb3Qoc2FsX0FOT1ZBLCAxKQ0KDQojIGJveC1jb3ggdHJhbnNmb3JtYXRpb24gc3VnZ2VzdGVkIHRvIHVzZSB5Xi0xDQpib3hjb3goc2FsX0FOT1ZBKQ0KdGl0bGUoIkJveC1Db3ggdHJhbnNmb3JtYXRpb24gb2YgdGhlIHJlc3BvbnNlIikNCg0KIyBjb21wYXJpc29uIGEgZnVsbCBtb2RlbCB3aXRoIGEgcmVkdWNlZCBvbmUgZXhjbHVkaW5nIG9uZSBpbnRlcmFjdGlvbiB0ZXJtDQpzYWxfQU5PVkEyID0gbG0oc2FsX3kgfiBzZXggKyBhZ2UgKyBqb2IgKyBzZXg6YWdlKQ0KYW5vdmEoc2FsX0FOT1ZBLCBzYWxfQU5PVkEyKQ0KDQpgYGANCg0KDQpUbyBjaGVjayBpZiB0aGUgbW9kZWwgY2FuIGJlIHNwYXJzaWZpZWQsIGNvbnNpZGVyaW5nIGdyb3VwcyBvZiB2YXJpYWJsZXMNCmFzIGEgd2hvbGUsIHRoZSBncm91cC1MYXNzbyBpcyBhcHBsaWVkLg0KSXQgc2hvd3MgdGhhdCB0aGUgaW50ZXJhY3Rpb24gdGVybSBzZXg6am9iIGlzIG5vdCBzbyBpbXBvcnRhbnQuDQpgYGB7ciBzYWxhcnkgZ3JvdXAtTGFzc299DQoNCiMgZGVmaW5lIHRoZSBjb25zaWRlcmVkIG1vZGVsLCB3aGljaCBpbmNsdWRlcyBpbnRlcmFjdGlvbiB0ZXJtcw0KZm9ybSA8LSBtb2RlbC5tYXRyaXgoc2FsX3kgfiAoc2V4ICsgYWdlICsgam9iKV4yKQ0KIyByZW1vdmUgaW50ZXJhY3Rpb24gYWdlOmpvYg0KIyBjb2xuYW1lcyhmb3JtKQ0KZm9ybSA9IGZvcm1bLDI6MTJdDQoNCiMgZGVmaW5lIGdyb3VwcycgbGFiZWxzDQpncnAgPSBjKDEsMiwyLDMsMywzLDQsNCw1LDUsNSkNCg0KI0dyb3VwLUxhc3NvIHdpdGggMTAtZm9sZHMgQ3Jvc3MgVmFsaWRhdGlvbiBhbmQgTEFEIGNvc3QgZnVuY3Rpb24NCmZpdC5jdj1jdi5nZ2xhc3NvKHg9Zm9ybSwgeT1zYWxfeSwgZ3JvdXA9Z3JwLCBuZm9sZHM9MTAsIHByZWQubG9zcyA9ICJMMiIpDQoNCiMgcGxvdCBDViBmb3IgTGFtYmRhDQpwbG90KGZpdC5jdikgDQptdGV4dChleHByZXNzaW9uKCIxMC1mb2xkcyBDViBmb3IgZ3JvdXAtTGFzc28gaW4gQU5PVkEiKSwgb3V0ZXI9VFJVRSwgIGNleD0xLCBsaW5lPS0yLjIpDQoNCiMgZXh0cmFjdCBjb2VmZmljaWVudHMNCiMgY29lZi5tYXQgPSBmaXQuY3YkZ2dsYXNzby5maXQkYmV0YQ0KIyBwbG90IHNlcGFyYXRlbHkgZWFjaCBjb2VmZmljaWVudA0KY29scyA9IGJyZXdlci5wYWwoNSxuYW1lPSJTZXQxIikNCnBsb3QoZml0LmN2JGdnbGFzc28uZml0LCBjb2wgPSBjb2xzLCBsd2QgPSAzLCBtYWluID0gIkNvZWZmaWNpZW50cyB2cy5MYW1iZGEgdmFsdWVzIikNCmxlZ2VuZCgnYm90dG9tcmlnaHQnLCBsZWdlbmQgPSBwYXN0ZSgiR3JvdXAiLCAxOjUpLCBjb2w9Y29sc1sxOjVdLCBjZXggPSAwLjY1LCBwY2ggPSAxLCBsd2Q9NCwgYnR5ID0ibiIpDQoNCiMgcGxvdCBjb2VmZmljaWVudHMnIG5vcm1zIChub3Qgd29ya2luZyksIGRvaW5nIGl0IG1hbnVhbGx5DQojIGh0dHBzOi8vd3d3LnJkb2N1bWVudGF0aW9uLm9yZy9wYWNrYWdlcy9nZ2xhc3NvL3ZlcnNpb25zLzEuMy90b3BpY3MvcGxvdC5nZ2xhc3NvDQojIGh0dHBzOi8vY29kZS5nb29nbGUuY29tL2FyY2hpdmUvcC9nZ2xhc3NvL2lzc3Vlcw0KICAjIHBsb3QoZml0LmN2JGdnbGFzc28uZml0LCBncm91cD1UUlVFLCBjb2wgPSAgY29scywgbHdkID0gMikNCiAgIyBsZWdlbmQoJ2JvdHRvbXJpZ2h0JywgbGVnZW5kID0gcGFzdGUoIkdyb3VwIiwgMTo1KSwgY29sPWNvbHNbMTo1XSwgY2V4ID0gMC42NSwgcGNoID0gMSwgbHdkPTQsIGJ0eSA9Im4iKQ0KIyBpbml0aWFsaXplIG5vcm1zDQpjb2VmZk5vcm0gPSBtYXRyaXgoMCwgbnJvdyA9ICBtYXgoZml0LmN2JGdnbGFzc28uZml0JGdyb3VwKSwgbGVuZ3RoKGZpdC5jdiRnZ2xhc3NvLmZpdCRsYW1iZGEpKQ0KIyBjb21wdXRlIG5vcm1zIGdyb3VwLXdpc2UNCmZvciAoaSBpbiAxOm1heChmaXQuY3YkZ2dsYXNzby5maXQkZ3JvdXApKXsgDQogIGluZCA9IGZpdC5jdiRnZ2xhc3NvLmZpdCRncm91cCA9PSBpDQogIGNvZWZmID0gZml0LmN2JGdnbGFzc28uZml0JGJldGFbaW5kLF0NCiAgaWYgKHN1bShpbmQpPjEpew0KICAgIGNvZWZmTm9ybVtpLF0gPSBhcHBseShjb2VmZiwgMiwgZnVuY3Rpb24oeCl7c3FydChzdW0oeF4yKSl9KQ0KICB9IGVsc2UgY29lZmZOb3JtW2ksXSA9IGNvZWZmDQp9IA0KIyBjb2VmZmljaWVudHMnIG5vcm0gcGxvdA0KcGxvdChsb2coZml0LmN2JGdnbGFzc28uZml0JGxhbWJkYSksIGNvZWZmTm9ybVsxLF0sIG1haW49IkNvZWZmaWNpZW50cycgbm9ybSB2cyBMYW1iZGEiLA0KICAgICB5bGFiPSJDb2VmZmljaWVudHMnIG5vcm0iLHhsYWI9IkxuIExhbWJkYSB2YWx1ZXMiLA0KICAgICBjb2w9Y29sc1sxXSwNCiAgICAgIyB4bGltPWMoLTEsMTAwKSwNCiAgICAgeWxpbT1jKG1pbihjb2VmZk5vcm0pLCBtYXgoY29lZmZOb3JtKSksDQogICAgIHR5cGU9ImwiLGx3ZD00KQ0KZm9yIChqIGluIDI6bnJvdyhjb2VmZk5vcm0pKXsNCiAgbGluZXMobG9nKGZpdC5jdiRnZ2xhc3NvLmZpdCRsYW1iZGEpLCBjb2VmZk5vcm1baixdLCB0eXBlPSJsIixsd2Q9NCwgY29sPWNvbHNbal0pDQp9DQphYmxpbmUoMCwwLCBsd2Q9MykNCiMgcGxvdCBsZWdlbmQgb25jZQ0KIyBncmlkKCkNCnBhcihuZXc9VCkNCmxlZ2VuZCgndG9wcmlnaHQnLCBsZWdlbmQgPSBwYXN0ZSgiZ3JvdXAgIiwgMTo1KSwgbHR5PTEsIGNvbD1jb2xzWzE6NV0sIGNleCA9IDAuNixsd2Q9MikNCg0KI1BpY2sgdGhlIGJlc3QgTGFtYmRhDQpsbWJkYT1maXQuY3YkbGFtYmRhLjFzZQ0KKGNvZWZzPWNvZWYuZ2dsYXNzbyhvYmplY3Q9Zml0LmN2JGdnbGFzc28uZml0LHM9bG1iZGEpKQ0KI0F0IGJlc3QgbGFtYmRhIGdldCBjb2VmZmljaWVudHMgYW5kIGZpdHRlZCB2YWx1ZXMNCnBsdD1zYWxfeS1wcmVkaWN0LmdnbGFzc28ob2JqZWN0PWZpdC5jdiRnZ2xhc3NvLmZpdCxuZXd4PWZvcm0scz1sbWJkYSx0eXBlPSdsaW5rJykNCnBsb3QocGx0LCB5bGFiPSJyZXNpZHVhbHMiLCB4bGFiPSJpbmRleCIsIG1haW49IlBsb3Qgb2YgcmVzaWR1YWxzIikNCmFibGluZSgwLCAwLCBjb2w9ICJyZWQiKQ0KDQpgYGANCg0KRnJvbSB0aGlzIHN0dWR5IGl0IGlzIHBvc3NpYmxlIHRvIGNvbmNsdWRlIHRoYXQgZWFjaCBmYWN0b3IgY29uc2lkZXJlZCANCmlzIHJlbGV2YW50IHRvIGRldGVybWluZSB0aGUgc2FsYXJ5IGxldmVsLiANCg0KVGhlIGxlYXN0IGltcG9ydGFudCBmYWN0b3IgcmVzdWx0cyB0aGUgaW50ZXJhY3Rpb24gYmV0d2VlbiBzZXggYW5kIGpvYiwNCndoaWNoIGlzIG5vdCBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IHVzaW5nIGdyb3VwLUxhc3NvLg0KVGhpcyBtZWFucyB0aGF0IHRoZXJlIGlzIG5vIGdlbmRlciBkaXNjcmltaW5hdGlvbg0KYmV0d2VlbiB2YXJpb3VzIGpvYnMsIGV2ZW4gaWYgZ2VuZGVyIGRpc2NyaW1pbmF0aW9uIGV4aXN0cyANCmluIGdlbmVyYWwgYW5kIGZvciBkaWZmZXJlbnQgYWdlIGdyb3Vwcy4NCg0KSW4gdGhlIG5leHQgc2VjdGlvbiB0aGlzIHRvcGljIHdpbGwgYmUgaW52ZXN0aWdhdGVkIGZ1cnRoZXIuDQoNCg0KIyMgRGlmZmVyZW5jZSBpbiBzYWxhcnk6IG1lbiB2cy4gZmVtYWxlcw0KDQpUaGUgZm9jdXMgb2YgdGhpcyBzZWN0aW9uIGlzIG9uIHRoZSBvbiB0aGUgZGlmZmVyZW5jZSBvbiBzYWxhcnkgDQpiZXR3ZWVuIG1hbGVzIGFuZCBmZW1hbGVzIGluIHZhcmlvdXMgdG93bnMuDQpTb21lIGNsYXNzaWNhbCBhcHByb2FjaGVzIHdpbGwgYmUgY29tcGFyZWQgd2l0aCByb2J1c3Qgb25lcywNCnRvIGRpYWdub3NlIHRoZSBwb3NzaWJsZSBuZWdhdGl2ZSBlZmZlY3Qgb2YgdGhlIHByZXNlbmNlIG9mIG5vaXNlIG9yIG91dGxpZXJzLg0KSXQgaXMgbW90aXZhdGVkIGJ5IHRoZSBhc3N1bXB0aW9ucyB0aGF0IG5vdCBhbGwgdGhlIHRvd25zIGNvbWUgZnJvbSANCnRoZSBzYW1lIGRhdGEgZ2VuZXJldGluZyBwcm9jZXNzLg0KDQpgYGB7ciBmdW5jdGlvbnMgbGluZWFyIG1vZGVsfQ0KDQojIFRoZXNlIGZ1bmN0aW9ucyBhcmUgdXNlZCB0byBjcmVhdGUgdGhlIHBsb3RzIHVzZWQgaW4gdGhlIG5leHQgY2h1bmtzDQoNCiMgUExPVFMgRk9SIGludGVyYWN0aXZlIHJlZ3Jlc3Npb24gZGlhZ25vc3RpYyBwbG90cw0KUmVncmVzc2lvblBsb3RzIDwtIGZ1bmN0aW9uKGZpdCwgdGV4dGxhYmVscywgcm9idXN0PUYsIG91dCA9IE5VTEwpew0KICANCiAgIyBudW1iZXIgb2YgdW5pdHMNCiAgbiA9IGxlbmd0aChmaXQkZml0dGVkLnZhbHVlcykNCiAgDQogICMgb3JpZ2luYWwgcmVzcG9uc2UNCiAgeSA9IGZpdCR5DQogIA0KICAjIEV4dHJhY3QgZml0dGVkIHZhbHVlcyBmcm9tIGxtKCkgb2JqZWN0DQogIEZpdHRlZC5WYWx1ZXMgPC0gIGZpdCRmaXR0ZWQudmFsdWVzDQogIA0KICAjIEV4dHJhY3QgcmVzaWR1YWxzIGZyb20gbG0oKSBvYmplY3QNCiAgUmVzaWR1YWxzIDwtICBmaXQkcmVzaWR1YWxzDQogIA0KICBpZiAocm9idXN0ID09IEYpew0KICAgICMgRXh0cmFjdCBzdGFuZGFyZGl6ZWQgcmVzaWR1YWxzIGZyb20gbG0oKSBvYmplY3QNCiAgICBTdGFuZGFyZGl6ZWQuUmVzaWR1YWxzIDwtIE1BU1M6OnN0ZHJlcyhmaXQpICANCiAgICANCiAgICAjIENhbGN1bGF0ZSBMZXZlcmFnZQ0KICAgIExldmVyYWdlIDwtIGxtLmluZmx1ZW5jZShmaXQpJGhhdA0KICAgIA0KICAgICMgdGV4dCBmb3IgdGhlIGxhYmVscyBvZiB0aGUgcGxvdHMNCiAgICB0dCA9ICJPTFMiDQogIH0gZWxzZXsNCiAgICAjIHN0YW5kYXJkaXplZCByZXNpZHVhbHMgYmFzZWQgb24gYSByb2J1c3Qgc2NhbGUgZXN0aW1hdGUNCiAgICBTdGFuZGFyZGl6ZWQuUmVzaWR1YWxzIDwtIGZpdCRyZXNpZHVhbHMvZml0JHNjYWxlDQogICAgDQogICAgIyBnZXQgdGhlIHJvYnVzdCBkaXN0YW5jZXMgYmFzZWQgb24gbWFoYWxhbm9iaXMgZGlzdGFuY2UgZnJvbSB0aGUgcm9idXN0IG91dHB1dCANCiAgICAjIChpdCBoYXMgdG8gYmUgc3BlY2lmaWVkIGluIHRoZSBjYWxsIHRvIGxtcm9iIHVzaW5nOiBjb250cm9sID0gbG1yb2IuY29udHJvbChjb21wdXRlLnJkID0gVCkpDQogICAgTGV2ZXJhZ2UgPC0gZml0JE1EDQogICAgDQogICAgIyB0ZXh0IGZvciB0aGUgbGFiZWxzIG9mIHRoZSBwbG90cw0KICAgIHR0ID0gIlJvYnVzdCINCiAgfQ0KICANCiAgIyBFeHRyYWN0IGZpdHRlZCB2YWx1ZXMgZm9yIGxtKCkgb2JqZWN0DQogIFRoZW9yZXRpY2FsLlF1YW50aWxlcyA8LSBxcW5vcm0oUmVzaWR1YWxzLCBwbG90Lml0ID0gRikkeA0KICANCiAgIyBDcmVhdGUgZGF0YSBmcmFtZSANCiAgIyBXaWxsIGJlIHVzZWQgYXMgaW5wdXQgdG8gcGxvdGx5DQogIHJlZ01hdCA8LSBkYXRhLmZyYW1lKEZpdHRlZC5WYWx1ZXMsIA0KICAgICAgICAgICAgICAgICAgICAgICBSZXNpZHVhbHMsIA0KICAgICAgICAgICAgICAgICAgICAgICBTdGFuZGFyZGl6ZWQuUmVzaWR1YWxzLCANCiAgICAgICAgICAgICAgICAgICAgICAgVGhlb3JldGljYWwuUXVhbnRpbGVzLA0KICAgICAgICAgICAgICAgICAgICAgICBMZXZlcmFnZSwgDQogICAgICAgICAgICAgICAgICAgICAgIHRleHRsYWJlbHMpDQogIA0KICAjIFBsb3QgdXNpbmcgUGxvdGx5DQogIA0KICAjIHRleHQgaW5mbw0KICB0IDwtIGxpc3QoDQogICAgZmFtaWx5ID0gInNhbnMgc2VyaWYiLA0KICAgIHNpemUgPSAxNCwNCiAgICBjb2xvciA9IHRvUkdCKCJncmV5NTAiKSkNCiAgDQogIA0KICAjIFBsb3QgMTogRml0dGVkIHZzIFJlc2lkdWFscw0KICAjIEZvciBzY2F0dGVyIHBsb3Qgc21vb3RoZXINCiAgTE9FU1MgPC0gbG9lc3Muc21vb3RoKEZpdHRlZC5WYWx1ZXMsIFJlc2lkdWFscykNCiAgDQogICMgcGx0MSA8LSByZWdNYXQgJT4lIA0KICAjICAgcGxvdF9seSh4ID0gRml0dGVkLlZhbHVlcywgeSA9IFJlc2lkdWFscywgDQogICMgICAgICAgICAgIHR5cGUgPSAic2NhdHRlciIsIG1vZGUgPSAibWFya2VycyIsIGhvdmVyaW5mbyA9ICJ0ZXh0IiwNCiAgIyAgICAgICAgICAgY29sb3IgPSBvdXQsIG5hbWUgPSAiRGF0YSIsIG1hcmtlciA9IGxpc3Qoc2l6ZSA9IDEwLCBvcGFjaXR5ID0gMC41KSwNCiAgIyAgICAgICAgICAgdGV4dCA9IHBhc3RlKCc8L2JyPiBVbml0OiAnLCAxOm4sDQogICMgICAgICAgICAgICAgICAgICAgICAgICAnPC9icj4gVG93bjogJywgYXMuY2hhcmFjdGVyKHRleHRsYWJlbHMpLA0KICAjICAgICAgICAgICAgICAgICAgICAgICAgJzwvYnI+IHg6ICcsIEZpdHRlZC5WYWx1ZXMsDQogICMgICAgICAgICAgICAgICAgICAgICAgICAnPC9icj4geTogJywgUmVzaWR1YWxzKSkgJT4lIA0KICAjICAgDQogICMgICBhZGRfdHJhY2UoeCA9IExPRVNTJHgsIHkgPSBMT0VTUyR5LCB0eXBlID0gInNjYXR0ZXIiLCBtb2RlID0gImxpbmVzIiwgbmFtZSA9ICJTbW9vdGgiLA0KICAjICAgICAgICAgICAgIGluaGVyaXQgPSBGLCBsaW5lID0gbGlzdCh3aWR0aCA9IDIpKSAlPiUgDQogICMgDQogICMgICBsYXlvdXQodGl0bGUgPSBwYXN0ZSh0dCwgIiBSZXNpZHVhbHMgdnMgRml0dGVkIFZhbHVlcyIpLCBwbG90X2JnY29sb3IgPSAiI2U2ZTZlNiIsDQogICMgICAgICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIkZpdHRlZCBWYWx1ZXMiKSwNCiAgIyAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiUmVzaWR1YWxzIikpDQogIA0KICAjIFBsb3QgMjogRml0dGVkIHZzIFN0YW5kYXJkaXplZCBSZXNpZHVhbHMNCiAgIyBGb3Igc2NhdHRlciBwbG90IHNtb290aGVyDQogIExPRVNTIDwtIGxvZXNzLnNtb290aChGaXR0ZWQuVmFsdWVzLCBTdGFuZGFyZGl6ZWQuUmVzaWR1YWxzKQ0KICANCiAgcGx0MiA8LSByZWdNYXQgJT4lIA0KICAgIHBsb3RfbHkoeCA9IEZpdHRlZC5WYWx1ZXMsIHkgPSBTdGFuZGFyZGl6ZWQuUmVzaWR1YWxzLCANCiAgICAgICAgICAgIHR5cGUgPSAic2NhdHRlciIsIG1vZGUgPSAibWFya2VycyIsIGhvdmVyaW5mbyA9ICJ0ZXh0IiwNCiAgICAgICAgICAgIGNvbG9yID0gb3V0LCBuYW1lID0gIkRhdGEiLCBtYXJrZXIgPSBsaXN0KHNpemUgPSAxMCwgb3BhY2l0eSA9IDAuNSksDQogICAgICAgICAgICB0ZXh0ID0gcGFzdGUoJzwvYnI+IFVuaXQ6ICcsIDE6biwNCiAgICAgICAgICAgICAgICAgICAgICAgICAnPC9icj4gVG93bjogJywgYXMuY2hhcmFjdGVyKHRleHRsYWJlbHMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICc8L2JyPiB4OiAnLCBGaXR0ZWQuVmFsdWVzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICc8L2JyPiB5OiAnLCBTdGFuZGFyZGl6ZWQuUmVzaWR1YWxzKSkgJT4lIA0KICAgIA0KICAgIGFkZF90cmFjZSh4ID0gTE9FU1MkeCwgeSA9IExPRVNTJHksIHR5cGUgPSAic2NhdHRlciIsIG1vZGUgPSAibGluZXMiLCBuYW1lID0gIlNtb290aCIsDQogICAgICAgICAgICAgIGluaGVyaXQgPSBGLCBsaW5lID0gbGlzdCh3aWR0aCA9IDIpKSAlPiUgDQogICAgDQogICAgbGF5b3V0KHRpdGxlID0gcGFzdGUodHQsICIgU3RhbmRhcmRpemVkIHJlc2lkdWFscyB2cyBGaXR0ZWQgVmFsdWVzIiksIHBsb3RfYmdjb2xvciA9ICIjZTZlNmU2IiwNCiAgICAgICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIkZpdHRlZCBWYWx1ZXMiKSwNCiAgICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIlN0YW5kYXJkaXplZCByZXNpZHVhbHMiKSkgIA0KDQogICMgUGxvdCAzOiBSZXNpZHVhbHMgaW5kZXgNCiAgcGx0MyA8LSByZWdNYXQgJT4lIA0KICAgIHBsb3RfbHkoeCA9IDE6biwgeSA9IFN0YW5kYXJkaXplZC5SZXNpZHVhbHMsIA0KICAgICAgICAgICAgdHlwZSA9ICJzY2F0dGVyIiwgbW9kZSA9ICJtYXJrZXJzIiwgaG92ZXJpbmZvID0gInRleHQiLA0KICAgICAgICAgICAgY29sb3IgPSBvdXQsIG5hbWUgPSAiRGF0YSIsIG1hcmtlciA9IGxpc3Qoc2l6ZSA9IDEwLCBvcGFjaXR5ID0gMC41KSwNCiAgICAgICAgICAgdGV4dCA9IHBhc3RlKCc8L2JyPiBVbml0OiAnLCAxOm4sDQogICAgICAgICAgICAgICAgICAgICAgICAgJzwvYnI+IFRvd246ICcsIGFzLmNoYXJhY3Rlcih0ZXh0bGFiZWxzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAnPC9icj4geDogJywgMTpuLA0KICAgICAgICAgICAgICAgICAgICAgICAgICc8L2JyPiB5OiAnLCBTdGFuZGFyZGl6ZWQuUmVzaWR1YWxzKSkgJT4lIA0KICAgIA0KICAgIGFkZF9zZWdtZW50cyh4ID0gLTUsIHhlbmQgPSBuKzUsIHkgPSAwLCB5ZW5kID0gMCwgbW9kZSA9ICJsaW5lIiwgaW5oZXJpdCA9IEYsIA0KICAgICAgICAgICAgICAgICBuYW1lID0gIk51bGwgbGluZSIsIGxpbmUgPSBsaXN0KHdpZHRoID0gMikpICU+JQ0KICAgIA0KICAgIGxheW91dCh0aXRsZSA9IHBhc3RlKHR0LCAiIFN0YW5kYXJkaXplZCBSZXNpZHVhbHMnIGluZGV4IiksIHBsb3RfYmdjb2xvciA9ICIjZTZlNmU2IiwgDQogICAgICAgICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIkluZGV4IiksDQogICAgICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIlN0YW5kYXJkaXplZC5SZXNpZHVhbHMiKSkNCg0KICAjIFBsb3QgNDogUVEgUG90DQogIHBsdDQgPC0gcmVnTWF0ICU+JSANCiAgICBwbG90X2x5KHggPSBUaGVvcmV0aWNhbC5RdWFudGlsZXMsIHkgPSBTdGFuZGFyZGl6ZWQuUmVzaWR1YWxzLCANCiAgICAgICAgICAgIHR5cGUgPSAic2NhdHRlciIsIG1vZGUgPSAibWFya2VycyIsIGhvdmVyaW5mbyA9ICJ0ZXh0IiwgDQogICAgICAgICAgICBjb2xvciA9IG91dCwgbmFtZSA9ICJEYXRhIiwgbWFya2VyID0gbGlzdChzaXplID0gMTAsIG9wYWNpdHkgPSAwLjUpLA0KICAgICAgICAgICB0ZXh0ID0gcGFzdGUoJzwvYnI+IFVuaXQ6ICcsIDE6biwNCiAgICAgICAgICAgICAgICAgICAgICAgICAnPC9icj4gVG93bjogJywgYXMuY2hhcmFjdGVyKHRleHRsYWJlbHMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICc8L2JyPiB4OiAnLCBUaGVvcmV0aWNhbC5RdWFudGlsZXMsDQogICAgICAgICAgICAgICAgICAgICAgICAgJzwvYnI+IHk6ICcsIFN0YW5kYXJkaXplZC5SZXNpZHVhbHMpKSAlPiUgDQogICAgDQogICAgYWRkX3RyYWNlKHggPSBUaGVvcmV0aWNhbC5RdWFudGlsZXMsIHkgPSBUaGVvcmV0aWNhbC5RdWFudGlsZXMsIHR5cGUgPSAic2NhdHRlciIsIA0KICAgICAgICAgICAgICBtb2RlID0gImxpbmVzIiwgbmFtZSA9ICJUaGVvcmV0aWNhbCIsIGxpbmUgPSBsaXN0KHdpZHRoID0gMiksIA0KICAgICAgICAgICAgICBpbmhlcml0ID0gRikgJT4lDQogICAgDQogICAgbGF5b3V0KHRpdGxlID0gcGFzdGUodHQsICIgUS1RIFBsb3QiKSwgcGxvdF9iZ2NvbG9yID0gIiNlNmU2ZTYiLA0KICAgICAgICAgICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICJOb3JtYWwgdGhlb3JldGljYWwgcXVhbnRpbGVzIiksDQogICAgICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIkRhdGEgcXVhbnRpbGVzIikpDQogIA0KICAjIFBsb3Q1OiBSZXNpZHVhbHMgdnMgTGV2ZXJhZ2UNCiAgIyBGb3Igc2NhdHRlciBwbG90IHNtb290aGVyDQogIExPRVNTIDwtIGxvZXNzLnNtb290aChMZXZlcmFnZSwgUmVzaWR1YWxzKQ0KICANCiAgcGx0NSA8LSByZWdNYXQgJT4lIA0KICAgIHBsb3RfbHkoeCA9IExldmVyYWdlLCB5ID0gUmVzaWR1YWxzLCANCiAgICAgICAgICAgIHR5cGUgPSAic2NhdHRlciIsIG1vZGUgPSAibWFya2VycyIsIGhvdmVyaW5mbyA9ICJ0ZXh0IiwgDQogICAgICAgICAgICBjb2xvciA9IG91dCwgbmFtZSA9ICJEYXRhIiwgbWFya2VyID0gbGlzdChzaXplID0gMTAsIG9wYWNpdHkgPSAwLjUpLCANCiAgICAgICAgICAgdGV4dCA9IHBhc3RlKCc8L2JyPiBVbml0OiAnLCAxOm4sDQogICAgICAgICAgICAgICAgICAgICAgICAgJzwvYnI+IFRvd246ICcsIGFzLmNoYXJhY3Rlcih0ZXh0bGFiZWxzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAnPC9icj4geDogJywgTGV2ZXJhZ2UsDQogICAgICAgICAgICAgICAgICAgICAgICAgJzwvYnI+IHk6ICcsIFJlc2lkdWFscykpICU+JSANCiAgICANCiAgICBhZGRfdHJhY2UoeCA9IExPRVNTJHgsIHkgPSBMT0VTUyR5LCB0eXBlID0gInNjYXR0ZXIiLCBtb2RlID0gImxpbmVzIiwgbmFtZSA9ICJTbW9vdGgiLA0KICAgICAgICAgICAgICBsaW5lID0gbGlzdCh3aWR0aCA9IDIpLCBpbmhlcml0ID0gRikgJT4lDQogICAgDQogICAgbGF5b3V0KHRpdGxlID0gcGFzdGUodHQsICIgTGV2ZXJhZ2UgdnMgUmVzaWR1YWxzIiksIHBsb3RfYmdjb2xvciA9ICIjZTZlNmU2IiwgDQogICAgICAgICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIkxldmVyYWdlIHZhbHVlcyIpLA0KICAgICAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJSZXNpZHVhbHMiKSkgIA0KDQogICMgUGxvdCA2OiBGaXR0ZWQgdnMgcmVzcG9uc2UNCiAgIyBGb3Igc2NhdHRlciBwbG90IHNtb290aGVyDQogIExPRVNTIDwtIGxvZXNzLnNtb290aChGaXR0ZWQuVmFsdWVzLCB5KQ0KICANCiAgcGx0NiA8LSByZWdNYXQgJT4lIA0KICAgIHBsb3RfbHkoeCA9IEZpdHRlZC5WYWx1ZXMsIHkgPXksIA0KICAgICAgICAgICAgdHlwZSA9ICJzY2F0dGVyIiwgbW9kZSA9ICJtYXJrZXJzIiwgaG92ZXJpbmZvID0gInRleHQiLA0KICAgICAgICAgICAgY29sb3IgPSBvdXQsIG5hbWUgPSAiRGF0YSIsIG1hcmtlciA9IGxpc3Qoc2l6ZSA9IDEwLCBvcGFjaXR5ID0gMC41KSwNCiAgICAgICAgICAgdGV4dCA9IHBhc3RlKCc8L2JyPiBVbml0OiAnLCAxOm4sDQogICAgICAgICAgICAgICAgICAgICAgICAgJzwvYnI+IFRvd246ICcsIGFzLmNoYXJhY3Rlcih0ZXh0bGFiZWxzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAnPC9icj4geDogJywgRml0dGVkLlZhbHVlcywNCiAgICAgICAgICAgICAgICAgICAgICAgICAnPC9icj4geTogJywgeSkpICU+JSANCiAgICANCiAgICBhZGRfdHJhY2UoeCA9IExPRVNTJHgsIHkgPSBMT0VTUyR5LCB0eXBlID0gInNjYXR0ZXIiLCBtb2RlID0gImxpbmVzIiwgbmFtZSA9ICJTbW9vdGgiLA0KICAgICAgICAgICAgICBpbmhlcml0ID0gRiwgbGluZSA9IGxpc3Qod2lkdGggPSAyKSkgJT4lIA0KICANCiAgICBsYXlvdXQodGl0bGUgPSBwYXN0ZSh0dCwgIiBGaXR0ZWQgVmFsdWVzIHZzIHJlc3BvbnNlIiksIHBsb3RfYmdjb2xvciA9ICIjZTZlNmU2IiwNCiAgICAgICAgICAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAiRml0dGVkIFZhbHVlcyIpLA0KICAgICAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJSZXNwb25zZSB2YWx1ZXMiKSkNCg0KICAjICMgUGxvdCA3OiBNSVNTSU5HOiBzcXJ0KGFicyhSZXNpZHVhbHMpKQ0KICAjICMgRm9yIHNjYXR0ZXIgcGxvdCBzbW9vdGhlcg0KICAjIExPRVNTMiA8LSBsb2Vzcy5zbW9vdGgoRml0dGVkLlZhbHVlcywgUm9vdC5SZXNpZHVhbHMpDQogICMgDQogICMgcGx0MyA8LSByZWdNYXQgJT4lIA0KICAjICAgcGxvdF9seSh4ID0gRml0dGVkLlZhbHVlcywgeSA9IFJvb3QuUmVzaWR1YWxzLCANCiAgIyAgICAgICAgICAgdHlwZSA9ICJzY2F0dGVyIiwgbW9kZSA9ICJtYXJrZXJzIiwgaG92ZXJpbmZvID0gInRleHQiLCANCiAgIyAgICAgICAgICAgbmFtZSA9ICJEYXRhIiwgbWFya2VyID0gbGlzdChzaXplID0gMTAsIG9wYWNpdHkgPSAwLjUpLA0KICAjICAgICAgICAgICB0ZXh0ID0gcGFzdGUoJ3Rvd246ICcsIGFzLmNoYXJhY3Rlcih0ZXh0bGFiZWxzKSkpICU+JQ0KICAjICAgDQogICMgICBhZGRfdHJhY2UoeCA9IExPRVNTMiR4LCB5ID0gTE9FU1MyJHksIHR5cGUgPSAic2NhdHRlciIsIG1vZGUgPSAibGluZXMiLCBuYW1lID0gIlNtb290aCIsDQogICMgICAgICAgICAgICAgbGluZSA9IGxpc3Qod2lkdGggPSAyKSwgaW5oZXJpdCA9IEYpICU+JSANCiAgIyAgIA0KICAjICAgbGF5b3V0KHRpdGxlID0gIlNjYWxlIExvY2F0aW9uIiwgcGxvdF9iZ2NvbG9yID0gIiNlNmU2ZTYiKQ0KICBwbHQgPSBsaXN0KHBsdDIsIHBsdDMsIHBsdDQsIHBsdDUsIHBsdDYpICMgcGx0MSwgDQogIHJldHVybihwbHQpDQoNCiAgIyBub3Qgd29ya2luZy4uLnRvIGFkZCBpbiBhbGwgcGxvdHMNCiAgIyB0byBhdm9pZCBlcnJvciB3aXRoIGNvbG9yUGFsZXR0ZTwzDQogICMgc3VwcHJlc3NXYXJuaW5ncyh3YXJuaW5nKCJSQ29sb3JCcmV3ZXI6OmJyZXdlci5wYWwiKSkNCn0NCg0KIw0KIyBQTE9UUyBGT1IgQkVTVCBTVUJTRVQgUkVHUkVTU0lPTg0KIw0KcGxvdC5yZWdzdWJzZXRzMiA8LSAgDQogIGZ1bmN0aW9uICh4LCBsYWJlbHMgPSBvYmokeG5hbWVzLCBtYWluID0gTlVMTCwgc2NhbGUgPSBjKCJiaWMiLCAgDQogICAgICJDcCIsICJhZGpyMiIsICJyMiIpLCBjb2wgPSBncmF5KHNlcSgwLCAwLjksIGxlbmd0aCA9IDEwKSksIC4uLikgIA0KICB7IA0KICAgIG9iaiA8LSB4IA0KICAgIGxzdW0gPC0gc3VtbWFyeShvYmopIA0KICAgIHBhcihtYXIgPSBjKDcsIDUsIDYsIDMpICsgMC4xKSANCiAgICBubW9kZWxzIDwtIGxlbmd0aChsc3VtJHJzcSkgDQogICAgbnAgPC0gb2JqJG5wIA0KICAgIHByb3BzY2FsZSA8LSBGQUxTRSANCiAgICBzc2NhbGUgPC0gcG1hdGNoKHNjYWxlWzFdLCBjKCJiaWMiLCAiQ3AiLCAiYWRqcjIiLCAicjIiKSwgIA0KICAgICAgICAgICAgICAgICAgICAgbm9tYXRjaCA9IDApIA0KICAgIGlmIChzc2NhbGUgPT0gMCkgIA0KICAgICAgc3RvcChwYXN0ZSgiVW5yZWNvZ25pc2VkIHNjYWxlPSIsIHNjYWxlKSkgDQogICAgaWYgKHByb3BzY2FsZSkgIA0KICAgICAgc3RvcChwYXN0ZSgiUHJvcG9ydGlvbmFsIHNjYWxpbmcgb25seSBmb3IgcHJvYmFiaWxpdGllcyIpKSANCiAgICB5c2NhbGUgPC0gc3dpdGNoKHNzY2FsZSwgbHN1bSRiaWMsIGxzdW0kY3AsIGxzdW0kYWRqcjIsIGxzdW0kcnNxKSANCiAgICB1cCA8LSBzd2l0Y2goc3NjYWxlLCAtMSwgLTEsIDEsIDEpIA0KICAgIGluZGV4IDwtIG9yZGVyKHlzY2FsZSAqIHVwKSANCiAgICBjb2xvcnNjYWxlIDwtIHN3aXRjaChzc2NhbGUsIHlzY2FsZSwgeXNjYWxlLCAtbG9nKHBtYXgoeXNjYWxlLCAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDFlLTA0KSksIC1sb2cocG1heCh5c2NhbGUsIDFlLTA0KSkpIA0KICAgIGltYWdlKHogPSB0KGlmZWxzZShsc3VtJHdoaWNoW2luZGV4LCBdLCBjb2xvcnNjYWxlW2luZGV4XSwgIA0KICAgICAgICAgICAgICAgICAgICAgICBOQSArIG1heChjb2xvcnNjYWxlKSAqIDEuNSkpLCB4YXh0ID0gIm4iLCB5YXh0ID0gIm4iLCAgDQogICAgICAgICAgeCA9ICgxOm5wKSwgeSA9IDE6bm1vZGVscywgeGxhYiA9ICIiLCB5bGFiID0gc2NhbGVbMV0sICANCiAgICAgICAgICBjb2wgPSBjb2wpIA0KICAgIGxhc3BhciA8LSBwYXIoImxhcyIpIA0KICAgIG9uLmV4aXQocGFyKGxhcyA9IGxhc3BhcikpIA0KICAgIHBhcihsYXMgPSAyKSANCiAgICBheGlzKDEsIGF0ID0gMTpucCwgbGFiZWxzID0gbGFiZWxzLCAuLi4pICMgSSBtb2RpZmllZCB0aGlzIGxpbmUgDQogICAgYXhpcygyLCBhdCA9IDE6bm1vZGVscywgbGFiZWxzID0gc2lnbmlmKHlzY2FsZVtpbmRleF0sIDIpLCAuLi4pIA0KICAgICMgYXhpcygyLGNleC5heGlzPTAuMDEpDQogICAgaWYgKCFpcy5udWxsKG1haW4pKSAgDQogICAgICB0aXRsZShtYWluID0gbWFpbikgDQogICAgYm94KCkgDQogICAgaW52aXNpYmxlKE5VTEwpDQogIH0gDQoNCg0KYGBgDQoNCg0KVGhlIGNvbnNpZGVyZWQgbW9kZWwgaXMgYnVpbHQgdXNpbmcgYWxsIHRoZSB2YXJpYWJsZXMgdGhhdCBjb3VsZCBleHBsYWluIHRoZSBnYXAgaW4gc2FsYXJ5LiANClNvbWUgb2YgdGhlbSByZWZlcnMgdG8gdGhlIGRpZmZlcmVuY2Ugb2Ygc29tZSBxdWFudGl0eSBiZXR3ZWVuIG1hbGVzIGFuZCBmZW1hbGVzIGZvciBlYWNoIHRvd24gDQooZS5nLiwgZGlwbG9tYSwgdW5pdmVyaXN0eSwgaW5kZXBlbmRlbnQgd29ya2VycywgZXRjLikuDQpUaGUgZmluYWwgbW9kZWwgY29uc2lzdCBvZiA0MyB2YXJpYWJsZXMgYW5kIDUwMjUgdW5pdHMuDQoNCkFkZGl0aW9uYWxseSwgc29tZSB2YXJpYWJsZXMgd2hpY2ggd291bGQgaGF2ZSBoYWQgYSBodWdlIHBvc2l0aXZlIGltcGFjdCBvbiB0aGUgcHJlZGljdGlvbg0Kb2YgdGhlIHJlc3BvbnNlIHZhcmlhYmxlIGhhdmUgbm9uIGJlZW4gY29uc2lkZXJlZCwgYmVjYXVzZSBvZiB0aGVpciBzdHJvbmcgcmVsYXRpb24NCihlLmcuLCBnYXAgaW4gc2FsYXJ5IGJldHdlZW4gbWFsZXMgYW5kIGZlbWFsZXMgZm9yIHZhcmlvdXMgYWdlcyBvciBvY2N1cGF0aW9ucykNCmBgYHtyIGxpbmVhciBtb2RlbCBzcGVjaWZpY2F0aW9uIGZvciBkZWx0YSBNLUYgc2FsYXJ5LCBmaWcua2VlcD0nYWxsJ30NCg0KIyByZXNwb25zZSB2YXJpYWJsZQ0KIyB5ID0gbG9nMTAobmV3RGF0JHNhbF9NYWxlcyAtIG5ld0RhdCRzYWxfRmVtYWxlcykNCnkgPSBuZXdEYXQkc2FsX01hbGVzIC0gbmV3RGF0JHNhbF9GZW1hbGVzDQoNCiMgb3JpZ2luYWwgcmVzcG9uc2UgdmFyaWFibGUgaGlzdG9ncmFtDQpnZ3Bsb3QoZGF0YT1hcy5kYXRhLmZyYW1lKHkpLCBhZXMoeSkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPS4uZGVuc2l0eS4uKSwgY29sPSJibGFjayIsIGZpbGw9ImJsdWUiLCBhbHBoYSA9IC4zLCBiaW5zID0gMzUpICsNCiAgZ2VvbV9kZW5zaXR5KGNvbD0iYmxhY2siKSArDQogIGxhYnMoeD0iTWFsZS1GZW1hbGUgc2FsYXJ5IiwgeT0iRGVuc2l0eSIpICsNCiAgZ2d0aXRsZSgiT3JpZ2luYWwgcmVzcG9uc2UgdmFyaWFibGUiKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQ0KDQp4ID0gY2JpbmQuZGF0YS5mcmFtZShwb3AgPSBuZXdEYXQkdG90YWxfcG9wdWxhdGlvbiwgDQogICAgICAgICAgICAgICAgICAgICBmaXJtcyA9IG5ld0RhdCR0b3RhbCwNCiAgICAgICAgICAgICAgICAgICAgIHJhdGlvX3BvcF9maXJtcyA9IG5ld0RhdCR0b3RhbC9uZXdEYXQkdG90YWxfcG9wdWxhdGlvbiwNCiAgICAgICAgICAgICAgICAgICAgICMgZGVsdGFfZXhlYyA9IG5ld0RhdCRzYWxfTV9leGVjdXRpdmUgLSBuZXdEYXQkc2FsX0ZfZXhlY3V0aXZlLA0KICAgICAgICAgICAgICAgICAgICAgIyBkZWx0YV9taWRNYW4gPSBuZXdEYXQkc2FsX01fbWlkTWFuYWdlciAtIG5ld0RhdCRzYWxfRl9taWRNYW5hZ2VyLA0KICAgICAgICAgICAgICAgICAgICAgIyBkZWx0YV9lbXBsID0gbmV3RGF0JHNhbF9NX2VtcGxveWVlIC0gbmV3RGF0JHNhbF9GX2VtcGxveWVlLA0KICAgICAgICAgICAgICAgICAgICAgIyBkZWx0YV93b3JrZXIgPSBuZXdEYXQkc2FsX01fd29ya2VyIC0gbmV3RGF0JHNhbF9GX3dvcmtlciwNCiAgICAgICAgICAgICAgICAgICAgIHdvcmtmb3JjZSA9IG5ld0RhdCR3b3JrZm9yY2UsDQogICAgICAgICAgICAgICAgICAgICBkZXBlbmRlbmN5X3JhdGlvID0gbmV3RGF0JGRlcGVuZGVuY3lfcmF0aW8sDQogICAgICAgICAgICAgICAgICAgICBkZWx0YV93YWdlYXJuZXIgPSBuZXdEYXQkd2FnZWFybmVyX00gLSBuZXdEYXQkd2FnZWFybmVyX0YsDQogICAgICAgICAgICAgICAgICAgICBkZWx0YV9pbmRlcCA9IG5ld0RhdCRpbmRlcGVuZGVudF9NIC0gbmV3RGF0JGluZGVwZW5kZW50X0YsDQogICAgICAgICAgICAgICAgICAgICAjIGRlbHRhX3RyYW5zZmVyID0gbmV3RGF0JHRyYW5zZmVyX00gLSBuZXdEYXQkdHJhbnNmZXJfRiwgIyAyMDAwIHplcm9zDQogICAgICAgICAgICAgICAgICAgICBkZWx0YV9lbXBsb3llciA9IG5ld0RhdCRlbXBsb3llcl9NIC0gbmV3RGF0JGVtcGxveWVyX0YsDQogICAgICAgICAgICAgICAgICAgICBkZWx0YV9mdWxsID0gbmV3RGF0JGZ1bGxfTSAtIG5ld0RhdCRmdWxsX0YsDQogICAgICAgICAgICAgICAgICAgICAjIGRlbHRhX2hhbGYgPSBuZXdEYXQkaGFsZl9NIC0gbmV3RGF0JGhhbGZfRiwgIyBPTFMgZ2l2ZXMgTkENCiAgICAgICAgICAgICAgICAgICAgIHN1cGVyZmljaWUgPSBuZXdEYXQkU3VwZXJmaWNpZSwNCiAgICAgICAgICAgICAgICAgICAgIGhvdXNpbmcxNCA9IG5ld0RhdCRob3VzaW5nMTQsDQogICAgICAgICAgICAgICAgICAgICBtZWRpYW5fbGl2aW5nMTQgPSBuZXdEYXQkbWVkaWFuX2xpdmluZzE0LA0KICAgICAgICAgICAgICAgICAgICAgZW1wbCA9IG5ld0RhdCRlbXBsLA0KICAgICAgICAgICAgICAgICAgICAgZW1wX3NhbCA9IG5ld0RhdCRlbXBfc2FsLA0KICAgICAgICAgICAgICAgICAgICAgcG9wMTVfNjQgPSBuZXdEYXQkcG9wMTVfNjQsDQogICAgICAgICAgICAgICAgICAgICB1bmVtcDE1XzY0ID0gbmV3RGF0JHVuZW1wMTVfNjQsDQogICAgICAgICAgICAgICAgICAgICBhY3QxNV82NCA9IG5ld0RhdCRhY3QxNV82NCwNCiAgICAgICAgICAgICAgICAgICAgIHVuZW1wX3JhdGUgPSBuZXdEYXQkdW5lbXBfcmF0ZSwNCiAgICAgICAgICAgICAgICAgICAgIGRlbHRhX05vRGlwID0gbmV3RGF0JG1hbGVfTm9EaXAgLSBuZXdEYXQkZmVtYWxlX05vRGlwLA0KICAgICAgICAgICAgICAgICAgICAgZGVsdGFfc2VjID0gbmV3RGF0JG1hbGVfU2VjIC0gbmV3RGF0JGZlbWFsZV9TZWMsDQogICAgICAgICAgICAgICAgICAgICBkZWx0YV9oaSA9IG5ld0RhdCRtYWxlX0hpIC0gbmV3RGF0JGZlbWFsZV9IaSwNCiAgICAgICAgICAgICAgICAgICAgIGRlbHRhX3VuaXYgPSBuZXdEYXQkbWFsZV9Vbml2IC0gbmV3RGF0JGZlbWFsZV9Vbml2LA0KICAgICAgICAgICAgICAgICAgICAgbm9kaXAgPSBuZXdEYXQkbm9kaXAsDQogICAgICAgICAgICAgICAgICAgICBkZWx0YV9pbW1pZyA9IG5ld0RhdCRtYWxlX2ltbWlnIC0gbmV3RGF0JGZlbWFsZV9pbW1pZywNCiAgICAgICAgICAgICAgICAgICAgIGRlbHRhX3dvcmtpbmdJbW1pZyA9IG5ld0RhdCRtYWxlX3dvcmtpbmdfaW1taWcgLSBuZXdEYXQkZmVtYWxlX3dvcmtpbmdfaW1taWcsDQogICAgICAgICAgICAgICAgICAgICBkZWx0YV9uYXRpdmUgPSBuZXdEYXQkbWFsZV9uYXRpdmUgLSBuZXdEYXQkZmVtYWxlX25hdGl2ZSwNCiAgICAgICAgICAgICAgICAgICAgICMgZXZvbF9lbnRyZXByID0gbmV3RGF0JGV2b2xfZW50cmVwcmVuZXVyaWFsX3Njb3JlLA0KICAgICAgICAgICAgICAgICAgICAgIyBldm9sX3BvcCA9IG5ld0RhdCRldm9sX3BvcF9zY29yZSwNCiAgICAgICAgICAgICAgICAgICAgIHJlZ2lvbmFsX0dEUCA9IG5ld0RhdCRyZWdpb25hbF9HRFAsDQogICAgICAgICAgICAgICAgICAgICAjIGR5bWFuaWNfZGVtb19wcm9mID0gbmV3RGF0JGR5bWFuaWNfZGVtb19wcm9mLA0KICAgICAgICAgICAgICAgICAgICAgbmJfYWN0aXZlX2VtcGxveWVlcyA9IG5ld0RhdCRuYl9hY3RpdmVfZW1wbG95ZWVzLA0KICAgICAgICAgICAgICAgICAgICAgbmJfYWN0aXZlX25vbl9lbXBsb3llZXMgPSBuZXdEYXQkbmJfYWN0aXZlX25vbl9lbXBsb3llZXMsDQogICAgICAgICAgICAgICAgICAgICAjIG5iX2FjdGl2ZSA9IG5ld0RhdCRuYl9hY3RpdmUsICAgIyBPTFMgZ2l2ZXMgTkENCiAgICAgICAgICAgICAgICAgICAgIG5iX2NyZWF0ZWRfc2VydmljZXMgPSBuZXdEYXQkbmJfY3JlYXRlZF9zZXJ2aWNlcywNCiAgICAgICAgICAgICAgICAgICAgIG5iX2NyZWF0ZWRfY29tbWVyY2UgPSBuZXdEYXQkbmJfY3JlYXRlZF9jb21tZXJjZSwNCiAgICAgICAgICAgICAgICAgICAgIG5iX2NyZWF0ZWRfY29uc3RydWN0aW9uID0gbmV3RGF0JG5iX2NyZWF0ZWRfY29uc3RydWN0aW9uLA0KICAgICAgICAgICAgICAgICAgICAgbmJfY3JlYXRlZF9pbmQgPSBuZXdEYXQkbmJfY3JlYXRlZF9pbmQsDQogICAgICAgICAgICAgICAgICAgICAjIG5iX2NyZWF0ZWRfZmlybXMgPSBuZXdEYXQkbmJfY3JlYXRlZF9maXJtcywgIyBPTFMgZ2l2ZXMgIA0KICAgICAgICAgICAgICAgICAgICAgbmJfZmlybXNfc2VydmljZSA9IG5ld0RhdCRuYl9maXJtc19zZXJ2aWNlLA0KICAgICAgICAgICAgICAgICAgICAgbmJfZmlybXNfY29tbWVyY2UgPSBuZXdEYXQkbmJfZmlybXNfY29tbWVyY2UsDQogICAgICAgICAgICAgICAgICAgICBuYl9maXJtc19jb25zdHJ1Y3Rpb24gPSBuZXdEYXQkbmJfZmlybXNfY29uc3RydWN0aW9uLA0KICAgICAgICAgICAgICAgICAgICAgbmJfZmlybXNfaW5kID0gbmV3RGF0JG5iX2Zpcm1zX2luZCwNCiAgICAgICAgICAgICAgICAgICAgIG5iX21ham9yID0gbmV3RGF0JG5iX21ham9yLA0KICAgICAgICAgICAgICAgICAgICAgbmJfbWlub3IgPSBuZXdEYXQkbmJfbWlub3IsDQogICAgICAgICAgICAgICAgICAgICBkZWx0YV9udW1fc2V4ID0gbmV3RGF0JG5iX21hbGUgLSBuZXdEYXQkbmJfZmVtYWxlLA0KICAgICAgICAgICAgICAgICAgICAgbmJfaG91c2Vob2xkID0gbmV3RGF0JG5iX2hvdXNlaG9sZCkNCiAgICAgICAgICAgICAgICAgICAgICMgdXJiYW5UUlVFID0gbmV3RGF0JHVyYmFuRHVtbXkpDQoNCiMgYWRkIGR1bW15IGZvciB1cmJhbiAhISENCg0KIyBtZXJnZSB2YXJpYWJsZXMNCm1vZCA9IGNiaW5kLmRhdGEuZnJhbWUoeSwgeCkNCiMgZGltKG1vZCkNCg0KIyBTcGVjaWZ5IHRoZSBtb2RlbCB3aXRoIGFkZGl0aW9uYWwgcG9seW5vbWlhbHMgYXMgcHJlZGljdG9ycw0KIyAjIG1lcmdlIHZhcmlhYmxlcw0KIyBtb2R5eCA9IGNiaW5kLmRhdGEuZnJhbWUoeSwgeCkNCiMgIyBtZXJnZSB2YXJpYWJsZXMgZXhjbHVkaW5nIG91bGllcnMNCiMgIyBtb2QgPSBtb2RbIW91dGwsXQ0KIyANCiMgIyBhZGQgdHJhbnNmb3JtYXRpb25zIG9uIHRoZSBwcmVkaWN0b3JzDQojICAgbW9kID0gY2JpbmQuZGF0YS5mcmFtZShtb2QsIG1vZFssMjpuY29sKG1vZCldXjIsIG1vZFssMjpuY29sKG1vZCldXjMpDQojICAgbmFtZXNkYXRhQlMgPSBuYW1lcyhtb2QpDQojICAgbGxsID0gKChkaW0obW9kKVsyXS0xKS8zKQ0KIyAgICMgZm9yIChpIGluIDE6bGxsKzEpew0KIyAgICMgICBzdHIgPSBuYW1lc2RhdGFCU1tpXQ0KIyAgICMgICBuYW1lc2RhdGFCU1tpXSA9IHJlZ21hdGNoZXMoc3RyLCByZWdleHByKCJfIiwgc3RyKSwgaW52ZXJ0ID0gVFJVRSlbWzFdXVstMV0NCiMgICAjIH0NCiMgICBuYW1lc2RhdGFCU1sobGxsKzIpOihsbGwqMisxKV0gPSBwYXN0ZShuYW1lc2RhdGFCU1sxOmxsbCsxXSwgcmVwKCJeMiIsIGxsbCksIHNlcD0iIikNCiMgICBuYW1lc2RhdGFCU1sobGxsKjIrMik6KGxsbCozKzEpXSA9IHBhc3RlKG5hbWVzZGF0YUJTWzE6bGxsKzFdLCByZXAoIl4zIiwgbGxsKSwgc2VwPSIiKQ0KIyAgICMgbmFtZXNkYXRhQlNbKGxsbCozKzIpOihsbGwqNCsxKV0gPSBwYXN0ZShuYW1lc2RhdGFCU1sxOmxsbCsxXSwgcmVwKCJsb2ciLCBsbGwpKQ0KIyAgIG5hbWVzKG1vZCkgPSBuYW1lc2RhdGFCUw0KDQojIHNjYXR0ZXIgcGxvdCBtYXRyaXgNCiMgcGFpcnMobW9kKQ0KIyBjb3JyZWxhdGlvbnMNCmNvcnJwbG90KGNvcihtb2QpLCBtZXRob2QgPSAiY29sb3IiLCAjdGl0bGUgPSAiQ29ycmVsYXRpb24gbWF0cml4IGZvciBYIHZhcmlhYmxlcyIsDQogICAgICAgICBkaWFnID0gVCwgdGwuY2V4PTAuNSwgdHlwZT0ibG93ZXIiLCAjY29sID0gY29sb3JSYW1wUGFsZXR0ZShjKCJyZWQiLCJncmVlbiIsIm5hdnlibHVlIikpKDEwMCkpDQogICAgICAgICB0bC5jb2wgPSAiYmxhY2siKSAgIyAsIG1hcj1jKDAsMCwxLjUsMCkNCg0KYGBgDQoNClRoZXNlIHBsb3RzIHNob3dzIHRoYXQ6IA0KDQoqIHRoZSByZXNwb25zZSBpcyBsb25nIHRhaWxlZCwgd2hpY2ggYWxzbyBtb3RpdmF0ZXMgdGhlIHJvYnVzdCBmcmFtZXdvcmsNCiogdGhlcmUgaXMgc3Ryb25nIGV2aWRlbmNlIG9mIGNvbGxpbmVhcml0eQ0KDQpUaGUgZmluYWwgbW9kZWwgaXMgYnVpbHQgY29uc2lkZXJpbmcgYSByYW5kb20gc2FtcGxlIG9mIG9ic2VydmF0aW9ucyAoNzAlIG9mIHRoZW0pDQppbiBvcmRlciB0byByZWR1Y2Ugc3BhdGlhbCBjb3JyZWxhdGlvbiBhbW9uZyB1bml0cw0KYGBge3Igc3ViLXNhbXBsaW5nfQ0KDQpzZXQuc2VlZCgxKQ0Kc3VicyA9IHNhbXBsZSgxOmxlbmd0aCh5KSwgc2l6ZSA9IHJvdW5kKGxlbmd0aCh5KSowLjcpKQ0KeSA9IHlbc3Vic10NCnggPSB4W3N1YnMsXQ0KbW9kID0gbW9kW3N1YnMsXQ0KdG93bnMgPSBuZXdEYXQkdG93bltzdWJzXQ0KcHJpbnQoIlRoZSBmaW5hbCBkYXRhc2V0IGhhcyBhIGRpbWVuc2lvbiBvZjogIikNCmRpbShtb2QpDQoNCiMgZHVtbXkgdmFyaWFibGUgZm9yIFBhcmlzIGFuZCBDaGFtYm91cmN5LCB1c2VkIGxhdGVyIGZvciBwbG90cyAoZm91bmQgZXgtcG9zdCkNCmRjaXR5ID0gcmVwKDEsIGxlbmd0aCh5KSkNCmRjaXR5W3Rvd25zPT0iUGFyaXMiXSA9IDINCmRjaXR5W3Rvd25zPT0iQ2hhbWJvdXJjeSJdID0gMw0KZGNpdHkgPSBhcy5mYWN0b3IoZGNpdHkpDQoNCiMgIyByZWR1Y2VkIHJlc3BvbnNlIHZhcmlhYmxlIGhpc3RvZ3JhbQ0KIyBnZ3Bsb3QoZGF0YT1hcy5kYXRhLmZyYW1lKHkpLCBhZXMoeSkpICsNCiMgICBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9Li5kZW5zaXR5Li4pLCBjb2w9ImJsYWNrIiwgZmlsbD0iYmx1ZSIsIGFscGhhID0gLjMsIGJpbnMgPSAzNSkgKw0KIyAgIGdlb21fZGVuc2l0eShjb2w9ImJsYWNrIikgKw0KIyAgIGxhYnMoeD0iTWFsZS1GZW1hbGUgc2FsYXJ5IiwgeT0iRGVuc2l0eSIpICsNCiMgICBnZ3RpdGxlKCJPcmlnaW5hbCByZXNwb25zZSB2YXJpYWJsZSIpICsNCiMgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkNCiMgDQojICMgY29ycmVsYXRpb25zDQojIGNvcnJwbG90KGNvcihtb2QpLCBtZXRob2QgPSAiY29sb3IiLCAjIHRpdGxlID0gIkNvcnJlbGF0aW9uIG1hdHJpeCBmb3IgWCB2YXJpYWJsZXMiLA0KIyAgICAgICAgICBkaWFnID0gVCwgdGwuY2V4PTAuNSwgdHlwZT0ibG93ZXIiLCAjY29sID0gY29sb3JSYW1wUGFsZXR0ZShjKCJyZWQiLCJncmVlbiIsIm5hdnlibHVlIikpKDEwMCkpDQojICAgICAgICAgIHRsLmNvbCA9ICJibGFjayIpICAjICwgbWFyPWMoMCwwLDEuNSwwKQ0KDQoNCg0KYGBgDQoNCkluIHRoZSBmb2xsb3dpbmcgYW5hbHlzZXMgdG8gdG93bnMgd2lsbCBiZSBvZnRlbiBoaWdobGlnaHRlZCBhbmQgDQp0aGV5IGhhdmUgYmVlbiBmb3VuZCBleC1wb3N0Lg0KVGhleSBhcmUgY29uc2lkZXJlZCBhcyAyIHR5cGljYWwgb3V0bGllcnMgYnV0IGZvciBkaWZmZXJlbnQgcmVhc29ucy4NCk9uZSBvZiB0aGVtIGlzIFBhcmlzLCB3aGljaCBpcyBhbiBvdXRsaWVyIGZvciBvYnZpb3VzIHJlYXNvbnMuIA0KVGhlIG90aGVyICh1bmV4cGVjdGVkKSBvbmUgaXMgW0NoYW1ib3VyY3ldKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0NoYW1ib3VyY3kpLCANCndoaWNoIGhhcyBiZWVuIHNwb3R0ZWQgYnkgdGhlIGZvbGxvd2luZyBhbmFseXNpcyBhbmQgaXQgaXMgYSB2ZXJ5IHNtYWxsIHRvd24uDQoNCkFsbCB0aGUgY29lZmZpY2llbnRzJyBlc3RpbWF0ZXMgb2J0YWluZWQgaW4gdGhlIGZvbGxvd2luZyB3aWxsIGJlIHNhdmVkDQppbiBhIGRhdGFmcmFtZSB0byBhbGxvdyBhbiBlYXN5IGV4LXBvc3QgY29tcGFyaXNvbi4NCkZvciBmaXR0aW5nIG1ldGhvZHMgdGhhdCBwcm92aWRlIHNpZ25pZmljYW5jZSBsZXZlbHMsIG9ubHkgdmFyaWFibGVzDQpzaWduaWZpY2FudCBhdCAwLjAxJSB3aWxsIGJlIGtlcHQuDQoNCiMjIyBOYWl2ZSBhcHByb2FjaGVzIA0KDQojIyMjIE9yZGluYXJ5IGxlYXN0IHNxdWFyZXMNCg0KQSBjbGFzc2ljYWwgbGluZWFyIG1vZGVsIGJhc2VkIG9uIE9MUyBpcyBmaXJzdCBmaXR0ZWQNCmBgYHtyIE9MU30NCg0KIyBPTFMNCm9scyA9IGxtKHkgfiAuLCBkYXRhID0gbW9kLCB5PVQpDQpzdW1tYXJ5KG9scykNCg0KIyBWSUYNCiMgdmlmKG9scykNCg0KIyBkaWFnbm9zdGljIHBsb3RzDQojIGxheW91dChtYXRyaXgoMTo2LCBuciA9IDIpLCBoZWlnaHQgPSBjKDIsIDEpKQ0KUmVncmVzc2lvblBsb3RzKG9scywgdG93bnMsIHJvYnVzdCA9IEYsIG91dD1kY2l0eSkNCg0KIyBleHRyYWN0IHZhcmlhYmxlcyBzaWduaWZpY2FudCBhdCAwLjAxJSBhbmQgc2F2ZSB0aGVtIGluIGEgZGF0YSBmcmFtZQ0KY29lZmYuZGYgPSBkYXRhLmZyYW1lKGFzLm1hdHJpeChzdW1tYXJ5KG9scylbWyJjb2VmZmljaWVudHMiXV1bLCJQcig+fHR8KSJdPDAuMDEpLCANCiAgICAgICAgICAgICAgICAgICAgICByb3cubmFtZXMgPSBjKCIoSW50ZXJjZXB0KSIsIG5hbWVzKHgpKSkNCm5hbWVzKGNvZWZmLmRmKSA9IGMoIk9MUyIpDQpjb2VmZi5kZltjb2VmZi5kZj09VFJVRV0gPSBzcHJpbnRmKCIlLjJlIiwNCiAgICAgICAgICAgYXMubWF0cml4KG9scyRjb2VmZmljaWVudHNbc3VtbWFyeShvbHMpW1siY29lZmZpY2llbnRzIl1dWywiUHIoPnx0fCkiXTwwLjAxXSksIDQpDQpjb2VmZi5kZltjb2VmZi5kZj09RkFMU0VdID0gIi0tIg0KDQpgYGANCg0KSXQgc2hvd3MgdGhhdDoNCg0KKiB0aGVyZSBpcyBldG9yZXNrYWRhc3RpY2l0eQ0KKiBQYXJpcyBoYXMgYSBsZXZhcmFnZSBlcXVhbCB0byAxDQoNCkFsc28sIGhpZ2ggY29sbGluZWFyaXR5IGFuZCByb2J1c3RuZXNzIGFyZSBub3QgdGFrZW4gaW50byBhY2NvdW50Lg0KQXQgdGhlIHNhbWUgdGltZSwgcnVubmluZyBkaWZmZXJlbnQgdGltZXMgT0xTIGRpZG4ndCBwcm9kdWNlIGFueSBjb2VmZmljaWVudHMnIGluc3RhYmlsaXR5LA0KZXZlbiBpZiBWSUYgdmFsdWVzIGFyZSB2ZXJ5IGhpZ2guDQoNCiMjIyMgQmVzdCBzdWJzZXQgc2VsZWN0aW9uDQoNCk1vZGVsIHNlbGVjdGlvbiBieSBleGhhdXN0aXZlIHNlYXJjaCAoc3VmZmVyaW5nIHRoZSBzYW1lIGRyYXdiYWNrcyBhcyBPTFMpIGlzIG5vdyBhcHBsaWVkLA0Kd2hpY2ggaXMgYWxzbyBhIHZlcnkgaGVhdnkgYXBwcm9hY2ggaW4gdGVybXMgb2YgY29tcHV0aW5nIHRpbWUuDQpgYGB7ciBCU1MgZXhoYXVzdGl2ZX0NCg0Kc2V0LnNlZWQoMSkNCg0KIyBiZXN0IHN1YnNldCBzZWxlY3Rpb24NCmJlc3Quc3ViID0gcmVnc3Vic2V0cyh5IH4gLiwgZGF0YSA9IG1vZCwgbnZtYXggPSBuY29sKG1vZCksIHJlYWxseS5iaWc9VFJVRSwgbWV0aG9kPSJleGhhdXN0aXZlIikgIyBleGhhdXN0aXZlICMgc2VxcmVwDQpiZXN0LnN1Yi5zdW1tYXJ5ID0gc3VtbWFyeShiZXN0LnN1YikNCiMgbWFudWFsIHBsb3R0aW5nDQpwYXIobWZyb3cgPWMoMiwyKSkNCiMgcnNxDQpwbG90KGJlc3Quc3ViLnN1bW1hcnkkcnNxICwgeGxhYj0iTnVtYmVyIG9mIFZhcmlhYmxlcyIsIHlsYWI9IlJzcSIsIHR5cGU9ImwiKQ0KaW5kX1JzcSA9IHdoaWNoLm1heChiZXN0LnN1Yi5zdW1tYXJ5JHJzcSkNCnBvaW50cyhpbmRfUnNxLCBiZXN0LnN1Yi5zdW1tYXJ5JGFkanIyW2luZF9Sc3FdLCBjb2wgPSJyZWQiLCBjZXg9MiwgcGNoPTIwKQ0KIyBhZGpSc3ENCnBsb3QoYmVzdC5zdWIuc3VtbWFyeSRhZGpyMiAseGxhYj0iTnVtYmVyIG9mIFZhcmlhYmxlcyIsIHlsYWI9IkFkanVzdGVkIFJTcSIsIHR5cGU9ImwiKQ0KaW5kX2FkalJzcSA9IHdoaWNoLm1heChiZXN0LnN1Yi5zdW1tYXJ5JGFkanIyKQ0KcG9pbnRzKGluZF9hZGpSc3EsIGJlc3Quc3ViLnN1bW1hcnkkYWRqcjJbaW5kX2FkalJzcV0sIGNvbCA9InJlZCIsIGNleD0yLCBwY2g9MjApDQojIENwDQpwbG90KGJlc3Quc3ViLnN1bW1hcnkkY3AgLHhsYWI9Ik51bWJlciBvZiBWYXJpYWJsZXMiLCB5bGFiPSJDcCIsIHR5cGU9ImwiKQ0KaW5kX0NwID0gd2hpY2gubWluKGJlc3Quc3ViLnN1bW1hcnkkY3ApDQpwb2ludHMoaW5kX0NwLCBiZXN0LnN1Yi5zdW1tYXJ5JGNwW2luZF9hZGpSc3FdLCBjb2wgPSJyZWQiLCBjZXg9MiwgcGNoPTIwKQ0KIyBiaWMNCnBsb3QoYmVzdC5zdWIuc3VtbWFyeSRiaWMgLHhsYWI9Ik51bWJlciBvZiBWYXJpYWJsZXMiLCB5bGFiPSJiaWMiLCB0eXBlPSJsIikNCmluZF9iaWMgPSB3aGljaC5taW4oYmVzdC5zdWIuc3VtbWFyeSRiaWMpDQpwb2ludHMoaW5kX2JpYywgYmVzdC5zdWIuc3VtbWFyeSRiaWNbaW5kX2JpY10sIGNvbCA9InJlZCIsIGNleD0yLCBwY2g9MjApDQptdGV4dCgiQmVzdCBzdWJzZXQgc2VsZWN0aW9uIGZvciBkZWx0YSBnZW5kZXIgc2FsYXJ5Iiwgb3V0ZXI9VFJVRSwgIGNleD0xLjIsIGxpbmU9LTEuNSkNCg0KIyBidWlsdC1pbiBwbG90cw0KcGFyKG1mcm93PWMoMSwxKSkNCnBsb3QucmVnc3Vic2V0czIoYmVzdC5zdWIsIHNjYWxlID0gInIyIiwgY2V4LmF4aXMgPSAwLjYsIG1haW4gPSAiQmVzdCBzdWJzZXQgc2VsZWN0aW9uIHVzaW5nIFIgc3F1YXJlZCIpDQpwbG90LnJlZ3N1YnNldHMyKGJlc3Quc3ViLCBzY2FsZSA9ICJhZGpyMiIsIGNleC5heGlzID0gMC42LCBtYWluID0gIkJlc3Qgc3Vic2V0IHNlbGVjdGlvbiB1c2luZyBhZGp1c3RlZCBSIHNxdWFyZWQiKQ0KcGxvdC5yZWdzdWJzZXRzMihiZXN0LnN1Yiwgc2NhbGUgPSAiQ3AiLCBjZXguYXhpcyA9IDAuNiwgbWFpbiA9ICJCZXN0IHN1YnNldCBzZWxlY3Rpb24gdXNpbmcgTWFsbG93cycgQ3AiKQ0KcGxvdC5yZWdzdWJzZXRzMihiZXN0LnN1Yiwgc2NhbGUgPSAiYmljIiwgY2V4LmF4aXMgPSAwLjYsIG1haW4gPSAiQmVzdCBzdWJzZXQgc2VsZWN0aW9uIHVzaW5nIEJJQyIpDQoNCiMgbXRleHQoIkJlc3Qgc3Vic2V0IHNlbGVjdGlvbiBmb3Igc2FsYXJ5IDE4LTI1IHVzaW5nIEJJQyIsIG91dGVyPVRSVUUsICBjZXg9MS40LCBsaW5lPS0zLjUpDQoNCiMgcmV0cmlldmUgdGhlIG1vZGVsIHdpdGggbWluIEJJQw0KY29lZmZpY2llbnRzKGJlc3Quc3ViLCB3aGljaC5taW4oYmVzdC5zdWIuc3VtbWFyeSRiaWMpKQ0Kbm5uID0gbmFtZXMoY29lZmZpY2llbnRzKGJlc3Quc3ViLCB3aGljaC5taW4oYmVzdC5zdWIuc3VtbWFyeSRiaWMpKSkNCm5ublsobm5uID09ICJ1cmJhblRSVUVUUlVFIildID0gInVyYmFuVFJVRSINCiAgIyBubm4gPC0gZ3N1Yih4ID0gbm5uLA0KICAjICAgICAgICAgICAgIHBhdHRlcm4gPSAiYCIsDQogICMgICAgICAgICAgICAgcmVwbGFjZW1lbnQgPSAiIikNCg0KIyBhcHBseSBPTFMgdG8gb2J0YWluIGRpYWdub3N0aWMgcGxvdHMgKGFwcHJveGltYXRlbHkgdGhlIHNhbWUgY29lZmZpY2llbnRzKQ0KbW9kX2JpYyA9IG1vZFssIGNvbG5hbWVzKG1vZCkgJWluJSBubm5dIA0KbW9kX2JpYyA9IGNiaW5kLmRhdGEuZnJhbWUoeSwgbW9kX2JpYykNCm9sc19iaWMgPSBsbSh5IH4gLiwgZGF0YSA9IG1vZF9iaWMsIHk9VCkNCnN1bW1hcnkob2xzX2JpYykNClJlZ3Jlc3Npb25QbG90cyhvbHNfYmljLCB0ZXh0bGFiZWxzID0gdG93bnMsIG91dCA9IGRjaXR5KQ0KDQojIGV4dHJhY3QgdmFyaWFibGVzIHNpZ25pZmljYW50IGF0IDAuMDElIGFuZCBzYXZlIHRoZW0gaW4gYSBkYXRhIGZyYW1lDQppQlNTID0gcm93Lm5hbWVzKGNvZWZmLmRmKSAlaW4lIG5ubg0KY29lZmYuZGYkQlNTID0gYXMuY2hhcmFjdGVyKHJlcCgiLS0iLCBucm93KGNvZWZmLmRmKSkpDQpjb2VmZi5kZiRCU1NbaUJTU10gPSBzcHJpbnRmKCIlLjJlIiwgYXMubWF0cml4KGNvZWZmaWNpZW50cyhiZXN0LnN1Yiwgd2hpY2gubWluKGJlc3Quc3ViLnN1bW1hcnkkYmljKSkpKQ0KDQpgYGANCg0KDQojIyMjIFN0ZXB3aXNlIHNlbGVjdGlvbg0KDQpNb2RlbCBzZWxlY3Rpb24gYnkgc2VxdWVudGlhbCByZXBsYWNlbWVudCAoc3VmZmVyaW5nIHRoZSBzYW1lIGRyYXdiYWNrcyBhcyBPTFMpIGlzIG5vdyBhcHBsaWVkDQphbmQgaXQgaXMgdmVyeSBmYXN0IGNvbXBhcmVkIHRvIHRoZSBleGhhdXN0aXZlIHNlYXJjaA0KYGBge3IgQlNTIHNlcXJlcH0NCg0Kc2V0LnNlZWQoMSkNCg0KIyBiZXN0IHN1YnNldCBzZWxlY3Rpb24NCmJlc3Quc3ViID0gcmVnc3Vic2V0cyh5IH4gLiwgZGF0YSA9IG1vZCwgbnZtYXggPSBuY29sKG1vZCksIHJlYWxseS5iaWc9VFJVRSwgbWV0aG9kPSJzZXFyZXAiKSAjIGV4aGF1c3RpdmUgIyBzZXFyZXANCmJlc3Quc3ViLnN1bW1hcnkgPSBzdW1tYXJ5KGJlc3Quc3ViKQ0KIyBtYW51YWwgcGxvdHRpbmcNCnBhcihtZnJvdyA9YygyLDIpKQ0KIyByc3ENCnBsb3QoYmVzdC5zdWIuc3VtbWFyeSRyc3EgLCB4bGFiPSJOdW1iZXIgb2YgVmFyaWFibGVzIiwgeWxhYj0iUnNxIiwgdHlwZT0ibCIpDQppbmRfUnNxID0gd2hpY2gubWF4KGJlc3Quc3ViLnN1bW1hcnkkcnNxKQ0KcG9pbnRzKGluZF9Sc3EsIGJlc3Quc3ViLnN1bW1hcnkkYWRqcjJbaW5kX1JzcV0sIGNvbCA9InJlZCIsIGNleD0yLCBwY2g9MjApDQojIGFkalJzcQ0KcGxvdChiZXN0LnN1Yi5zdW1tYXJ5JGFkanIyICx4bGFiPSJOdW1iZXIgb2YgVmFyaWFibGVzIiwgeWxhYj0iQWRqdXN0ZWQgUlNxIiwgdHlwZT0ibCIpDQppbmRfYWRqUnNxID0gd2hpY2gubWF4KGJlc3Quc3ViLnN1bW1hcnkkYWRqcjIpDQpwb2ludHMoaW5kX2FkalJzcSwgYmVzdC5zdWIuc3VtbWFyeSRhZGpyMltpbmRfYWRqUnNxXSwgY29sID0icmVkIiwgY2V4PTIsIHBjaD0yMCkNCiMgQ3ANCnBsb3QoYmVzdC5zdWIuc3VtbWFyeSRjcCAseGxhYj0iTnVtYmVyIG9mIFZhcmlhYmxlcyIsIHlsYWI9IkNwIiwgdHlwZT0ibCIpDQppbmRfQ3AgPSB3aGljaC5taW4oYmVzdC5zdWIuc3VtbWFyeSRjcCkNCnBvaW50cyhpbmRfQ3AsIGJlc3Quc3ViLnN1bW1hcnkkY3BbaW5kX2FkalJzcV0sIGNvbCA9InJlZCIsIGNleD0yLCBwY2g9MjApDQojIGJpYw0KcGxvdChiZXN0LnN1Yi5zdW1tYXJ5JGJpYyAseGxhYj0iTnVtYmVyIG9mIFZhcmlhYmxlcyIsIHlsYWI9ImJpYyIsIHR5cGU9ImwiKQ0KaW5kX2JpYyA9IHdoaWNoLm1pbihiZXN0LnN1Yi5zdW1tYXJ5JGJpYykNCnBvaW50cyhpbmRfYmljLCBiZXN0LnN1Yi5zdW1tYXJ5JGJpY1tpbmRfYmljXSwgY29sID0icmVkIiwgY2V4PTIsIHBjaD0yMCkNCm10ZXh0KCJCZXN0IHN1YnNldCBzZWxlY3Rpb24gZm9yIGRlbHRhIGdlbmRlciBzYWxhcnkiLCBvdXRlcj1UUlVFLCAgY2V4PTEuMiwgbGluZT0tMS41KQ0KDQojIGJ1aWx0LWluIHBsb3RzDQpwYXIobWZyb3c9YygxLDEpKQ0KcGxvdC5yZWdzdWJzZXRzMihiZXN0LnN1Yiwgc2NhbGUgPSAicjIiLCBjZXguYXhpcyA9IDAuNiwgbWFpbiA9ICJCZXN0IHN1YnNldCBzZWxlY3Rpb24gdXNpbmcgUiBzcXVhcmVkIikNCnBsb3QucmVnc3Vic2V0czIoYmVzdC5zdWIsIHNjYWxlID0gImFkanIyIiwgY2V4LmF4aXMgPSAwLjYsIG1haW4gPSAiQmVzdCBzdWJzZXQgc2VsZWN0aW9uIHVzaW5nIGFkanVzdGVkIFIgc3F1YXJlZCIpDQpwbG90LnJlZ3N1YnNldHMyKGJlc3Quc3ViLCBzY2FsZSA9ICJDcCIsIGNleC5heGlzID0gMC42LCBtYWluID0gIkJlc3Qgc3Vic2V0IHNlbGVjdGlvbiB1c2luZyBNYWxsb3dzJyBDcCIpDQpwbG90LnJlZ3N1YnNldHMyKGJlc3Quc3ViLCBzY2FsZSA9ICJiaWMiLCBjZXguYXhpcyA9IDAuNiwgbWFpbiA9ICJCZXN0IHN1YnNldCBzZWxlY3Rpb24gdXNpbmcgQklDIikNCg0KIyBtdGV4dCgiQmVzdCBzdWJzZXQgc2VsZWN0aW9uIGZvciBzYWxhcnkgMTgtMjUgdXNpbmcgQklDIiwgb3V0ZXI9VFJVRSwgIGNleD0xLjQsIGxpbmU9LTMuNSkNCg0KIyByZXRyaWV2ZSB0aGUgbW9kZWwgd2l0aCBtaW4gQklDDQpjb2VmZmljaWVudHMoYmVzdC5zdWIsIHdoaWNoLm1pbihiZXN0LnN1Yi5zdW1tYXJ5JGJpYykpDQpubm4gPSBuYW1lcyhjb2VmZmljaWVudHMoYmVzdC5zdWIsIHdoaWNoLm1pbihiZXN0LnN1Yi5zdW1tYXJ5JGJpYykpKQ0Kbm5uWyhubm4gPT0gInVyYmFuVFJVRVRSVUUiKV0gPSAidXJiYW5UUlVFIg0KICAjIG5ubiA8LSBnc3ViKHggPSBubm4sDQogICMgICAgICAgICAgICAgcGF0dGVybiA9ICJgIiwNCiAgIyAgICAgICAgICAgICByZXBsYWNlbWVudCA9ICIiKQ0KDQojIGFwcGx5IE9MUyB0byBvYnRhaW4gZGlhZ25vc3RpYyBwbG90cyAoYXBwcm94aW1hdGVseSB0aGUgc2FtZSBjb2VmZmljaWVudHMpDQptb2RfYmljID0gbW9kWywgY29sbmFtZXMobW9kKSAlaW4lIG5ubl0gDQptb2RfYmljID0gY2JpbmQuZGF0YS5mcmFtZSh5LCBtb2RfYmljKQ0Kb2xzX2JpYyA9IGxtKHkgfiAuLCBkYXRhID0gbW9kX2JpYywgeT1UKQ0Kc3VtbWFyeShvbHNfYmljKQ0KUmVncmVzc2lvblBsb3RzKG9sc19iaWMsIHRleHRsYWJlbHMgPSB0b3ducywgb3V0ID0gZGNpdHkpDQoNCiMgZXh0cmFjdCB2YXJpYWJsZXMgc2lnbmlmaWNhbnQgYXQgMC4wMSUgYW5kIHNhdmUgdGhlbSBpbiBhIGRhdGEgZnJhbWUNCmlCU1MgPSByb3cubmFtZXMoY29lZmYuZGYpICVpbiUgbm5uDQpjb2VmZi5kZiQiQlNTLVNSIiA9IGFzLmNoYXJhY3RlcihyZXAoIi0tIiwgbnJvdyhjb2VmZi5kZikpKQ0KY29lZmYuZGYkIkJTUy1TUiJbaUJTU10gPSBzcHJpbnRmKCIlLjJlIiwgYXMubWF0cml4KGNvZWZmaWNpZW50cyhiZXN0LnN1Yiwgd2hpY2gubWluKGJlc3Quc3ViLnN1bW1hcnkkYmljKSkpKQ0KDQpgYGANCg0KVGhpcyBhcHByb2FjaCByZXN1bHRzIGluIGEgc3BhcnNlciBtb2RlbCBjb21wYXJlZCB0byB0aGUgZXhoYXVzdGl2ZSBzZWFyY2gsDQphbmQgdGhlIGNvc3QgKGUuZy4sIGluIHRlcm1zIG9mIEJJQykgaXMgaGlnaGVyLg0KDQoNCiMjIyMgTU0gZXN0aW1hdG9yDQoNClRoZSBtb2RlbCBpcyBub3cgZml0dGVkIHVzaW5nIHRoZSBNTSBlc3RpbWF0b3IsDQp3aGljaCBpcyBhIHNvZnQgdHJpbW1pbmcgbWV0aG9kb2xvZ3kuDQpJdCBpcyBiYXNlZCBvbiBhIHN0YXJ0aW5nIHJvYnVzdCBlc3RpbWF0b3Igd2l0aCBhIGhpZ2gNCmJyZWFrZG93biBwb2ludCAoaW4gdGhpcyBjYXNlIGFuIFMgZXN0aW1hdG9yKSwNCndoaWNoIHByb3ZpZGVzIGEgcm9idXN0IHNjYWxlIGVzdGltYXRlIHVzZWQgYnkNCnRoZSBNTSBlc3RpbWF0b3IgdG8gcmVjb3ZlciBlZmZpY2llbmN5DQpgYGB7ciBNTX0NCg0Kc2V0LnNlZWQoMTEpICMgdG8gZW5zdXJlIGNvbnZlcmdlbmNlDQoNCiMgcm9idXN0IGZpdCB1c2luZyBNTSBlc3RpbWF0b3IgDQptbSA9IGxtcm9iKHl+LiwgZGF0YSA9IG1vZCwgeT1ULCBjb250cm9sID0gbG1yb2IuY29udHJvbChjb21wdXRlLnJkID0gVCkpICMgc2V0dGluZyA9ICJLUzIwMTQiLA0Kc3VtbWFyeShtbSkNCg0KIyBvdXRsaWVycyBpZGVudGlmaWVkIGFuZCBpbXBvcnRhbnQgY2l0aWVzDQpvdXRsTU0gPSBhcy5jaGFyYWN0ZXIoZGNpdHkpDQpvdXRsTU1bbW0kcndlaWdodHMgPCAyLjhlLTA1XSA9ICIwIg0Kb3V0bE1NW2RjaXR5IT0xXSA9IGFzLmNoYXJhY3RlcihkY2l0eVtkY2l0eSE9MV0pDQpvdXRsTU0gPSBhcy5mYWN0b3Iob3V0bE1NKQ0KDQojIGRpYWdub3N0aWMgcGxvdHMNCiAgIyBsYXlvdXQobWF0cml4KDE6NiwgbnIgPSAyKSwgaGVpZ2h0ID0gYygyLCAxKSkNCiAgIyBwbG90KG1tLCBjZXggPSAwLjYsIGlkLm4gPSAxMCwgbGFiZWxzLmlkID0gbmV3RGF0JHRvd25fbmFtZSwgc3ViLmNhcHRpb249Ik1NIikNClJlZ3Jlc3Npb25QbG90cyhtbSwgdG93bnMsIHJvYnVzdCA9IFQsb3V0PW91dGxNTSkNCg0KIyBleHRyYWN0IHZhcmlhYmxlcyBzaWduaWZpY2FudCBhdCAwLjAxJSBhbmQgc2F2ZSB0aGVtIGluIGEgZGF0YSBmcmFtZQ0KY29lZmYuZGYkTU0gPSBhcy5tYXRyaXgoc3VtbWFyeShtbSlbWyJjb2VmZmljaWVudHMiXV1bLCJQcig+fHR8KSJdPDAuMDEpDQpjb2VmZi5kZiRNTVtjb2VmZi5kZiRNTT09VFJVRV0gPSBzcHJpbnRmKCIlLjJlIiwNCiAgICAgICAgICAgICAgIGFzLm1hdHJpeChtbSRjb2VmZmljaWVudHNbc3VtbWFyeShtbSlbWyJjb2VmZmljaWVudHMiXV1bLCJQcig+fHR8KSJdPDAuMDFdKSwgNCkgDQpjb2VmZi5kZiRNTVtjb2VmZi5kZiRNTT09RkFMU0VdID0gIi0tIg0KDQpgYGANClRoaXMgbW9kZWwgc2hvd3MgdGhhdDoNCg0KKiByZXNpZHVhbHMgYW5kIGZpdHRlZCB2YWx1ZXMgc2VlbSBiZXR0ZXIgdGhhbiB0aGUgT0xTIGZpdA0KKiBpdCBpcyBhYmxlIHRvIGlkZW50aWZ5IHRoZSBtb3N0IG91bHlpbmcgdW5pdHMgKGNvbnNpZGVyaW5nIGFsbCB0aGUgZGltZW5zaW9ucykNCiogbGV2ZXJhZ2UgcG9pbnRzIChMeW9uIGFuZCBUb3Vsb3VzZSkgaGF2ZSBhIGxvd2VyIHdlaWdodCBjb21wYXJlZCB0byBPTFMgZXN0aW1hdGVzDQoNCg0KIyMjIyBMZWFzdCB0cmltbWVkIHNxdWFyZXMNCg0KQSB2ZXJ5IHNpbWlsYXIgcmVzdWx0IGlzIG9idGFpbmVkIHVzaW5nIHRoZSBMVFMgZXN0aW1hdG9yIA0KKGkuZS4sIGFuIGhhcmQgdHJpbW1pbmcgYXBwcm9hY2gpLCB3aXRoIHRyaW1taW5nIHByb3BvcnRpb24gZXF1YWwgDQp0byAxMCUgb2YgdGhlIHVuaXRzLg0KYGBge3IgTFRTfQ0KDQpzZXQuc2VlZCgxKQ0KDQpsdHNfc29sID0gbHRzUmVnKHl+LiwgZGF0YSA9IG1vZCwgIG1ldGhvZCA9ICJsdHMiLCBhbHBoYSA9IDAuOSwgbWNkID0gRikNCnN1bW1hcnkobHRzX3NvbCkNCiMgYXNzaWduIHZhcmlhYmxlcyB1c2VkIGZvciBwbG90dGluZw0KbHRzX3NvbCR5ID0geQ0KbHRzX3NvbCRNRCA9IG1tJE1EICMgdXNlIE1NIG1haGFsYW5vYmlzIGRpc3RhbmNlIChmb3IgY29tcHV0YXRpb25hbCBwcm9ibGVtcyBvZiBzaW5ndWxhcml0eSkNCiAgIyBsdHNfc29sJE1EID0gY292TWNkKG1vZFssYygxOjEyLCAxNDpuY29sKG1vZCkpXSkkbWFoDQoNCiMgb3V0bGllcnMgaWRlbnRpZmllZCBhbmQgaW1wb3J0YW50IGNpdGllcw0Kb3V0bExUUyA9IGFzLmNoYXJhY3RlcihkY2l0eSkNCm91dGxMVFNbbHRzX3NvbCRsdHMud3QgPCAyZS0wNV0gPSAiMCINCm91dGxMVFNbZGNpdHkhPTFdID0gYXMuY2hhcmFjdGVyKGRjaXR5W2RjaXR5IT0xXSkNCm91dGxMVFMgPSBhcy5mYWN0b3Iob3V0bExUUykNCg0KIyBwbG90KGx0c19zb2wpDQpSZWdyZXNzaW9uUGxvdHMobHRzX3NvbCwgdG93bnMsIHJvYnVzdCA9IFQsIG91dCA9IG91dGxMVFMpDQoNCiMgZXh0cmFjdCB2YXJpYWJsZXMgc2lnbmlmaWNhbnQgYXQgMC4wMSUgYW5kIHNhdmUgdGhlbSBpbiBhIGRhdGEgZnJhbWUNCmNvZWZmLmRmJExUUyA9IHN1bW1hcnkobHRzX3NvbClbWyJjb2VmZmljaWVudHMiXV1bLCJQcig+fHR8KSJdPDAuMDENCmNvZWZmLmRmJExUU1tjb2VmZi5kZiRMVFM9PVRSVUVdID0NCiAgc3ByaW50ZigiJS4yZSIsIGFzLm1hdHJpeChsdHNfc29sJGNvZWZmaWNpZW50c1tzdW1tYXJ5KGx0c19zb2wpW1siY29lZmZpY2llbnRzIl1dWywiUHIoPnx0fCkiXTwwLjAxXSksIDQpDQpjb2VmZi5kZiRMVFNbY29lZmYuZGYkTFRTPT1GQUxTRV0gPSAiLS0iDQoNCmBgYA0KDQpVc2luZyB0aGUgTU0gb3IgTFRTIGVzdGltYXRvciwgYXMgZXhwZWN0ZWQsIGluY3JlYXNlcyB0aGUgYWRqdXN0ZWQgUiBzcXVhcmVkIG9mIGFyb3VuZCAxMCUuDQoNCg0KIyMjIyBCZXN0IHN1YnNldCBzZWxlY3Rpb24gd2l0aCBNTSB3ZWlnaHRzDQoNClRoZSByZXN1bHRzIG9idGFpbmVkIHVzaW5nIGEgYmVzdCBzdWJzZXQgc2VsZWN0aW9uIHByb2NlZHVyZSBhcmUgbm93IGNvbWJpbmVkIHdpdGggdGhlDQp3ZWlnaHRzIG9idGFpbmVkIHVzaW5nIHRoZSBNTSBlc3RpbWF0b3IgKHByZXR0eSBzaW1pbGFyIHRvIHRoZSBvbmVzIG9idGFpZW5kIHVzaW5nIHRoZSBMVFMgd2VpZ2h0cykNCmBgYHtyIEJTUyhNTSkgZXhoYXVzdGl2ZX0NCg0Kc2V0LnNlZWQoMSkNCg0KIyBiZXN0IHN1YnNldCBzZWxlY3Rpb24NCmJlc3Quc3ViID0gcmVnc3Vic2V0cyh5IH4gLiwgZGF0YSA9IG1vZCwgbnZtYXggPSBuY29sKG1vZCksIHJlYWxseS5iaWc9VFJVRSwgbWV0aG9kPSJleGhhdXN0aXZlIiwgd2VpZ2h0cyA9IGx0c19zb2wkbHRzLnd0KSAjIGV4aGF1c3RpdmUgIyBzZXFyZXANCmJlc3Quc3ViLnN1bW1hcnkgPSBzdW1tYXJ5KGJlc3Quc3ViKQ0KIyBtYW51YWwgcGxvdHRpbmcNCnBhcihtZnJvdyA9YygyLDIpKQ0KIyByc3ENCnBsb3QoYmVzdC5zdWIuc3VtbWFyeSRyc3EgLCB4bGFiPSJOdW1iZXIgb2YgVmFyaWFibGVzIiwgeWxhYj0iUnNxIiwgdHlwZT0ibCIpDQppbmRfUnNxID0gd2hpY2gubWF4KGJlc3Quc3ViLnN1bW1hcnkkcnNxKQ0KcG9pbnRzKGluZF9Sc3EsIGJlc3Quc3ViLnN1bW1hcnkkYWRqcjJbaW5kX1JzcV0sIGNvbCA9InJlZCIsIGNleD0yLCBwY2g9MjApDQojIGFkalJzcQ0KcGxvdChiZXN0LnN1Yi5zdW1tYXJ5JGFkanIyICx4bGFiPSJOdW1iZXIgb2YgVmFyaWFibGVzIiwgeWxhYj0iQWRqdXN0ZWQgUlNxIiwgdHlwZT0ibCIpDQppbmRfYWRqUnNxID0gd2hpY2gubWF4KGJlc3Quc3ViLnN1bW1hcnkkYWRqcjIpDQpwb2ludHMoaW5kX2FkalJzcSwgYmVzdC5zdWIuc3VtbWFyeSRhZGpyMltpbmRfYWRqUnNxXSwgY29sID0icmVkIiwgY2V4PTIsIHBjaD0yMCkNCiMgQ3ANCnBsb3QoYmVzdC5zdWIuc3VtbWFyeSRjcCAseGxhYj0iTnVtYmVyIG9mIFZhcmlhYmxlcyIsIHlsYWI9IkNwIiwgdHlwZT0ibCIpDQppbmRfQ3AgPSB3aGljaC5taW4oYmVzdC5zdWIuc3VtbWFyeSRjcCkNCnBvaW50cyhpbmRfQ3AsIGJlc3Quc3ViLnN1bW1hcnkkY3BbaW5kX2FkalJzcV0sIGNvbCA9InJlZCIsIGNleD0yLCBwY2g9MjApDQojIGJpYw0KcGxvdChiZXN0LnN1Yi5zdW1tYXJ5JGJpYyAseGxhYj0iTnVtYmVyIG9mIFZhcmlhYmxlcyIsIHlsYWI9ImJpYyIsIHR5cGU9ImwiKQ0KaW5kX2JpYyA9IHdoaWNoLm1pbihiZXN0LnN1Yi5zdW1tYXJ5JGJpYykNCnBvaW50cyhpbmRfYmljLCBiZXN0LnN1Yi5zdW1tYXJ5JGJpY1tpbmRfYmljXSwgY29sID0icmVkIiwgY2V4PTIsIHBjaD0yMCkNCm10ZXh0KCJCZXN0IHN1YnNldCBzZWxlY3Rpb24gZm9yIGRlbHRhIGdlbmRlciBzYWxhcnkiLCBvdXRlcj1UUlVFLCAgY2V4PTEuMiwgbGluZT0tMS41KQ0KDQojIGJ1aWx0LWluIHBsb3RzDQpwYXIobWZyb3c9YygxLDEpKQ0KcGxvdC5yZWdzdWJzZXRzMihiZXN0LnN1Yiwgc2NhbGUgPSAicjIiLCBjZXguYXhpcyA9IDAuNiwgbWFpbiA9ICJCZXN0IHN1YnNldCBzZWxlY3Rpb24gdXNpbmcgUiBzcXVhcmVkIikNCnBsb3QucmVnc3Vic2V0czIoYmVzdC5zdWIsIHNjYWxlID0gImFkanIyIiwgY2V4LmF4aXMgPSAwLjYsIG1haW4gPSAiQmVzdCBzdWJzZXQgc2VsZWN0aW9uIHVzaW5nIGFkanVzdGVkIFIgc3F1YXJlZCIpDQpwbG90LnJlZ3N1YnNldHMyKGJlc3Quc3ViLCBzY2FsZSA9ICJDcCIsIGNleC5heGlzID0gMC42LCBtYWluID0gIkJlc3Qgc3Vic2V0IHNlbGVjdGlvbiB1c2luZyBNYWxsb3dzJyBDcCIpDQpwbG90LnJlZ3N1YnNldHMyKGJlc3Quc3ViLCBzY2FsZSA9ICJiaWMiLCBjZXguYXhpcyA9IDAuNiwgbWFpbiA9ICJCZXN0IHN1YnNldCBzZWxlY3Rpb24gdXNpbmcgQklDIikNCg0KIyBtdGV4dCgiQmVzdCBzdWJzZXQgc2VsZWN0aW9uIGZvciBzYWxhcnkgMTgtMjUgdXNpbmcgQklDIiwgb3V0ZXI9VFJVRSwgIGNleD0xLjQsIGxpbmU9LTMuNSkNCg0KIyByZXRyaWV2ZSB0aGUgbW9kZWwgd2l0aCBtaW4gQklDDQpjb2VmZmljaWVudHMoYmVzdC5zdWIsIHdoaWNoLm1pbihiZXN0LnN1Yi5zdW1tYXJ5JGJpYykpDQpubm4gPSBuYW1lcyhjb2VmZmljaWVudHMoYmVzdC5zdWIsIHdoaWNoLm1pbihiZXN0LnN1Yi5zdW1tYXJ5JGJpYykpKQ0Kbm5uWyhubm4gPT0gInVyYmFuVFJVRVRSVUUiKV0gPSAidXJiYW5UUlVFIg0KICAjIG5ubiA8LSBnc3ViKHggPSBubm4sDQogICMgICAgICAgICAgICAgcGF0dGVybiA9ICJgIiwNCiAgIyAgICAgICAgICAgICByZXBsYWNlbWVudCA9ICIiKQ0KDQojIGFwcGx5IE9MUyB0byBvYnRhaW4gZGlhZ25vc3RpYyBwbG90cyAoYXBwcm94aW1hdGVseSB0aGUgc2FtZSBjb2VmZmljaWVudHMpDQogICMgbW9kX2JpYyA9IG1vZFssIGNvbG5hbWVzKG1vZCkgJWluJSBubm5dIA0KICAjIG1vZF9iaWMgPSBjYmluZC5kYXRhLmZyYW1lKHksIG1vZF9iaWMpDQogICMgb2xzX2JpYyA9IGxtKHkgfiAuLCBkYXRhID0gbW9kX2JpYywgeT1UKQ0KICAjIHN1bW1hcnkob2xzX2JpYykNCiAgIyBSZWdyZXNzaW9uUGxvdHMob2xzX2JpYywgdGV4dGxhYmVscyA9IHRvd25zLCBvdXQgPSBkY2l0eSkNCg0KIyBleHRyYWN0IHZhcmlhYmxlcyBzaWduaWZpY2FudCBhdCAwLjAxJSBhbmQgc2F2ZSB0aGVtIGluIGEgZGF0YSBmcmFtZQ0KaUJTUyA9IHJvdy5uYW1lcyhjb2VmZi5kZikgJWluJSBubm4NCmNvZWZmLmRmJCJCU1MoTU0pIiA9IGFzLmNoYXJhY3RlcihyZXAoIi0tIiwgbnJvdyhjb2VmZi5kZikpKQ0KY29lZmYuZGYkIkJTUyhNTSkiW2lCU1NdID0gc3ByaW50ZigiJS4yZSIsIGFzLm1hdHJpeChjb2VmZmljaWVudHMoYmVzdC5zdWIsIHdoaWNoLm1pbihiZXN0LnN1Yi5zdW1tYXJ5JGJpYykpKSkNCg0KYGBgDQoNClRoaXMgYXBwcm9hY2ggcmVzdWx0cyBpbiBhIHNpZ25pZmljYW50IGltcHJvdmVtZW50IG9mIHRoZSBjb3N0IGZ1bmN0aW9uLA0KYnV0IHRoZSBiZXN0IG1vZGVsIGlzIGxlc3Mgc3BhcnNlIGFuZCBpdCBrZWVwcyBhcHByb3hpbWF0ZWx5IDIwIHZhcmlhYmxlcy4NCg0KDQojIyMjIEVsYXN0aWMgbmV0DQoNClRvIGZhY2UgdGhlIHByb2JsZW0gb2Ygc3Ryb25nIGNvbGxpbmVhcml0eSwgd2hpY2ggaGFzIG5vdCBiZWVuIGNvbnNpZGVyZSB5ZXQsDQphbiBFbGFzdGljLW5ldCBpcyBub3cgZml0dGVkIHVzaW5nIDEwLWZvbGRzIGNyb3NzIHZhbGlkYXRpb24gDQp0byB0dW5lIGxhbWJkYSBhbmQgY29uc2lkZXJpbmcgYSByYW5nZSBvZiAxMSBlcXVpc3BhY2VkIGFscGhhIHZhbHVlcy4NClRoZSBiZXN0IG1vZGVsIGlzIGNvbnNpZGVyZWQgdGhlIG9uZSB3aXRoIHRoZSBsb3dlc3QgTVNQRS4NCmBgYHtyIEVORVR9DQoNCnNldC5zZWVkKDIpDQoNCiMgRWxhc3RpYyBuZXQNCnggPSBhcy5tYXRyaXgobW9kWywgMjpuY29sKG1vZCldKQ0KeSA9IG1vZFssIDFdDQpwYXIobWZyb3cgPWMoMyw0KSkNCnBhcihvbWE9YygwLDAsMiwwKSkNCmFscCA9IHNlcSgwLCAxLCAwLjEpICMgc2VxKDAsIDEsIGxlbmd0aC5vdXQgPSAyMCkNCg0KIyBpbml0aWFsaXplIGxpc3QgdG8gY29udGFpbiB0aGUgdmFyaWFibGVzIHNlbGVjdGVkLCANCiMgbnVtYmVyIG9mIG5vbiB6ZXJvIGNvZWZmaWNpZW50cywNCiMgY29zdCBmdW5jdGlvbiBhbmQgdGhlIGNvdW50ZXINCm56Y29lZiA9IG1hdHJpeChOQSwgbGVuZ3RoKGFscCksIDIpDQp2YXJfc2VsZWMgPSBsaXN0KCkNCmNvc3RDViA9IHJlcChOQSwgbGVuZ3RoKGFscCkpDQppID0gMQ0KDQpmb3IgKGogaW4gYWxwKXsNCiAgIyBzZXQuc2VlZCAoMykNCiAgY3Yub3V0ID0gY3YuZ2xtbmV0KHgsIHksIGFscGhhID0gaiwgbmZvbGRzPTEwKSAjIHN0YW5kYXJkaXplLnJlc3BvbnNlID0gVCAsIHBhcmFsbGVsID0gVCANCiAgcGxvdChjdi5vdXQpDQogIHRpdGxlKHBhc3RlKCJhbHBoYSA9ICIsIGopLCBsaW5lID0gMC4zKQ0KICAjIHNhdmUgc2VsZWN0ZWQgdmFyaWFibGVzDQogICMga2VlcCBsb3dlciBudW1iZXIgb2YgdmFyaWFibGVzIHNlbGVjdGVkIGJ1IGxhbWJkYSBvciBsYW1iZGEuMXNlDQogIGlmIChzdW0oY29lZihjdi5vdXQsIHMgPSAibGFtYmRhLm1pbiIpICE9IDApID4gc3VtKGNvZWYoY3Yub3V0LCBzID0gImxhbWJkYS4xc2UiKSAhPSAwKSl7ICMgbG93ZXN0IGlzIG1pbiBMYW1iZGENCiAgICB0bXBfY29lZmZzIDwtIGNvZWYoY3Yub3V0LCBzID0gImxhbWJkYS4xc2UiKSANCiAgfSBlbHNlIHsNCiAgICB0bXBfY29lZmZzIDwtIGNvZWYoY3Yub3V0LCBzID0gImxhbWJkYS5taW4iKSAjIGN2Lm91dCRsYW1iZGEuMXNlIA0KICB9DQogIHZhcl9zZWxlY1tbaV1dID0gZGF0YS5mcmFtZShuYW1lID0gdG1wX2NvZWZmc0BEaW1uYW1lc1tbMV1dW3RtcF9jb2VmZnNAaSArIDFdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvZWZmaWNpZW50ID0gdG1wX2NvZWZmc0B4KQ0KICAjIHNhdmUgbnVtYmVyIG9mIG5vbiB6ZXJvIHZhcmlhYmxlcw0KICBuemNvZWZbaSwxXSA9IGN2Lm91dCRuemVyb1tjdi5vdXQkbGFtYmRhID09IGN2Lm91dCRsYW1iZGEubWluXQ0KICBuemNvZWZbaSwyXSA9IGN2Lm91dCRuemVyb1tjdi5vdXQkbGFtYmRhID09IGN2Lm91dCRsYW1iZGEuMXNlXQ0KICAjIHNhdmUgdGhlIHZhbHVlIG9mIHRoZSBjb3N0IGZ1bmN0aW9uDQogIGNvc3RDVltpXSA9IG1pbihjdi5vdXQkY3ZtKQ0KICAjIGluY3JlYXNlIGl0ZXJhdG9yDQogIGkgPSBpICsgMQ0KfQ0KbXRleHQoZXhwcmVzc2lvbigiQmVzdCBsYW1iZGEgZm9yIGRlbHRhIGdlbmRlciBzYWxhcnkgdXNpbmcgZWxhc3RpYy1uZXQgYW5kIDEwLWZvbGRzIENWIiksIG91dGVyPVRSVUUsICBjZXg9MSwgbGluZT0wLjIpDQoNCiMgYmVzdCBtb2RlbCAobWluIG1lYW4gQ3YgZXJyb3IpDQpiZXN0Q1YgPSB3aGljaC5taW4oY29zdENWKQ0KIyAjIHNob3cgdGhlIGNvZWZmaWNpZW50cyBvYnRhaW5lZCBmb3IgdGhlIGJlc3QgbW9kZWwgKGFkZGVkIGluIHRoZSBmaW5hbCB0YWJsZSkNCiMgcHJpbnQodmFyX3NlbGVjW1tiZXN0Q1ZdXSkNCg0KcGFyKG1mcm93ID1jKDEsMSkpDQojIHBsb3RtZWFuIEN2IGVycm9yDQpwbG90KGFscCwgY29zdENWLCBtYWluPSJNZWFuIDEwLWZvbGRzIENWIGVycm9yIGZvciBlYWNoIGFscGhhIGxldmVsIiwNCiAgICAgeGxhYiA9ICJhbHBoYSBwcm9wb3J0aW9uIiwgeWxhYiA9ICJtZWFuIENWIGVycm9yIiwgdHlwZSA9ICJiIiwgY29sID0gImJsdWUiKQ0KYXhpcyhzaWRlID0gMSwgYXQgPSBjKGFscCkpDQoNCiMgcGxvdCBudW1iZXIgb2Ygbm9uIHplcm8gY29lZmZpY2llbnRzDQpwbG90KGFscCwgbnpjb2VmWywxXSwgbWFpbj0iTnVtYmVyIG9mIG5vbi16ZXJvIGNvZWZmaWNpZW50cyBmb3IgZWFjaCBhbHBoYSBsZXZlbCIsDQogICAgIHhsYWIgPSAiYWxwaGEgcHJvcG9ydGlvbiIsIHlsYWIgPSAiTm9uLXplcm8gY29lZmZpY2llbnRzIiwgdHlwZSA9ICJiIiwgY29sID0gImJsdWUiLA0KICAgICB5bGltID0gYyhtaW4obnpjb2VmKSwgbWF4KG56Y29lZikpKQ0KbGluZXMoYWxwLCBuemNvZWZbLDJdLCBjb2wgPSAicmVkIiwgdHlwZSA9ICJiIikNCmxlZ2VuZCgndG9wcmlnaHQnLCBjKCJsYW1iZGEgbWluIiwgImxhbWJkYSAxU0UiKSwgbHR5ID0gMSwgY29sID0gYygiYmx1ZSIsICJyZWQiKSwgY2V4ID0gMC43LGx3ZD0yKSANCmF4aXMoc2lkZSA9IDEsIGF0ID0gYyhhbHApKQ0KDQojIGV4dHJhY3Qgc2lnbmlmaWNhbnQgdmFyaWFibGVzIGFuZCBzYXZlIGluIGEgZGF0YWZyYW1lDQpjb2VmZi5kZiRFTkVUID0gYXMuY2hhcmFjdGVyKHJlcCgiLS0iLCBucm93KGNvZWZmLmRmKSkpDQppRU5FVCA9IHJvdy5uYW1lcyhjb2VmZi5kZikgJWluJSB2YXJfc2VsZWNbW2Jlc3RDVl1dJG5hbWUNCmNvZWZmLmRmJEVORVRbaUVORVRdID0gc3ByaW50ZigiJS4yZSIsIGFzLm1hdHJpeCh2YXJfc2VsZWNbW2Jlc3RDVl1dJGNvZWZmaWNpZW50KSkgDQoNCiMgIyBkaWFnbm9zdGljIHBsb3RzDQojICMgY3JlYXRlIHF1YW50aXRpZXMgb2YgaW50ZXJlc3QNCiMgY3Yub3V0JGZpdHRlZC52YWx1ZXMgPSANCiMgICBhcy5tYXRyaXgoY2JpbmQuZGF0YS5mcmFtZSgiKEludGVyY2VwdCkiID0gcmVwKDEsIG5yb3coeCkpLCB4KSlbLGldICUqJSB2YXJfc2VsZWNbW2Jlc3RDVl1dJGNvZWZmaWNpZW50DQojIGN2Lm91dCRyZXNpZHVhbHMgPSB5IC0gY3Yub3V0JGZpdHRlZC52YWx1ZXMNCiMgY3Yub3V0JHJlc2lkdWFscyR5ID0geQ0KIyBjdi5vdXQkIA0KIyANCiMgIyBvdXRsaWVycyBpZGVudGlmaWVkIGFuZCBpbXBvcnRhbnQgY2l0aWVzDQojIG91dGwgPSBkY2l0eQ0KIyAjIG91dGxbbHRzX3NvbCRsdHMud3QgPCAyZS0wNV0gPSAiMCINCiMgIyBvdXRsW2RjaXR5IT0xXSA9IGFzLmNoYXJhY3RlcihkY2l0eVtkY2l0eSE9MV0pDQojICMgb3V0bCA9IGFzLmZhY3RvcihvdXRsKQ0KIyANCiMgIyBwbG90KGx0c19zb2wpDQojIFJlZ3Jlc3Npb25QbG90cyhjdi5vdXQsIHRvd25zLCByb2J1c3QgPSBGLCBvdXQgPSBvdXRsKQ0KDQpgYGANCg0KVGhpcyBlc3RpbWF0b3IgcHJvaWRlcyBhIGZhaXJseSBzcGFyc2UgbW9kZWwsDQpidXQgaXQgaXMgbm9uIHJvYnVzdCwgaXQgaXMgYmlhc2VkLCBhbmQgaXQgZG9lc24ndCANCmVhc3kgYWxsb3cgdG8gcGVyZm9ybSBpbmZlcmVudGlhbCByZWFzb25pbmcuDQoNCg0KIyMjIyBPTFMgb24gZWxhc3RpYyBuZXQgc29sdXRpb24NCg0KVG8gcGFydGlhbGx5IHNvbHZlIHRoZSBsYXR0ZXIgdHdvIHByb2JsZW1zLA0KYW4gT0xTIGZpdCBjb3VsZCBiZSBhcHBsaWVkIG9ubHkgb24gdGhlIHZhcmlhYmxlcyANCnByZXZpb3VzbHkgaWRlbnRpZmllZCBieSBFTkVULg0KYGBge3IgRU5FVCtPTFN9DQoNCiMgT0xTDQppbmRDb2VmID0gbmFtZXMobW9kKSAlaW4lIHZhcl9zZWxlY1tbYmVzdENWXV0kbmFtZQ0KbW9kRU5FVE9MUyA9IGNiaW5kLmRhdGEuZnJhbWUoeSwgbW9kWyxpbmRDb2VmXSkNCkVORVRfb2xzID0gbG0oeSB+IC4sIHk9VCwgZGF0YSA9IG1vZEVORVRPTFMpDQpzdW1tYXJ5KEVORVRfb2xzKQ0KDQojIGRpYWdub3N0aWMgcGxvdHMNCiMgbGF5b3V0KG1hdHJpeCgxOjYsIG5yID0gMiksIGhlaWdodCA9IGMoMiwgMSkpDQpSZWdyZXNzaW9uUGxvdHMoRU5FVF9vbHMsIHRvd25zLCByb2J1c3QgPSBGLCBvdXQ9ZGNpdHkpDQoNCiMgZXh0cmFjdCB2YXJpYWJsZXMgc2lnbmlmaWNhbnQgYXQgMC4wMSUgYW5kIHNhdmUgdGhlbSBpbiBhIGRhdGEgZnJhbWUNCmNvZWZmLmRmJCJFTkVUK09MUyIgPSBhcy5jaGFyYWN0ZXIocmVwKCItLSIsIG5yb3coY29lZmYuZGYpKSkNCmNvZWZmLmRmJCJFTkVUK09MUyJbaUVORVRdID0gYXMubWF0cml4KHN1bW1hcnkoRU5FVF9vbHMpW1siY29lZmZpY2llbnRzIl1dWywiUHIoPnx0fCkiXTwwLjAxKQ0KY29lZmYuZGZbY29lZmYuZGY9PVRSVUVdID0gc3ByaW50ZigiJS4yZSIsDQogICAgICAgICAgIGFzLm1hdHJpeChFTkVUX29scyRjb2VmZmljaWVudHNbc3VtbWFyeShFTkVUX29scylbWyJjb2VmZmljaWVudHMiXV1bLCJQcig+fHR8KSJdPDAuMDFdKSwgNCkNCmNvZWZmLmRmW2NvZWZmLmRmPT1GQUxTRV0gPSAiLS0iDQoNCmBgYA0KDQpUaGlzIHJlc3VsdHMgaW4gYSBzcGFyc2VyIG1vZGVsIGFuZCB0aGUgZGlhZ25vc3RpYyBwbG90cw0Kc2hvd3MgYSBiZXR0ZXIgcmVzdWx0IGNvbXBhcmVkIHRvIHRoZSByYXcgT0xTIGVzdGltYXRlcywNCmJ1dCBpdCBpcyBzdGlsbCBub3Qgcm9idXN0Lg0KDQoNCiMjIyMgRWxhc3RpYyBuZXQgd2l0aCBNTSB3ZWlnaHRzDQoNCkF0IHRoaXMgcG9pbnQsIGl0IHNlZW1zIHJlYXNvbmFibGUgdG8gdXNlIHRoZSB3ZWlnaHRzDQpvYnRhaW5lZCBieSB0aGUgTU0gZXN0aW1hdG9yIGluIGFuIEVORVQgbW9kZWwsDQp0cnlpbmcgdG8gcmVjb3ZlciBzb21lIHJvYnVzdG5lc3MgYW5kIGtlZXBpbmcgYSBzcGFyc2UgbW9kZWwNCmBgYHtyIEVORVQoTU0pfQ0KDQpzZXQuc2VlZCgxKQ0KDQojIGluaXRpYWxpemUgbGlzdCB0byBjb250YWluIHRoZSB2YXJpYWJsZXMgc2VsZWN0ZWQsIA0KIyBudW1iZXIgb2Ygbm9uIHplcm8gY29lZmZpY2llbnRzLA0KIyBjb3N0IGZ1bmN0aW9uIGFuZCB0aGUgY291bnRlcg0Kbnpjb2VmID0gbWF0cml4KE5BLCBsZW5ndGgoYWxwKSwgMikNCnZhcl9zZWxlYyA9IGxpc3QoKQ0KY29zdENWID0gcmVwKE5BLCBsZW5ndGgoYWxwKSkNCmkgPSAxDQoNCnBhcihtZnJvdyA9YygzLDQpKQ0KcGFyKG9tYT1jKDAsMCwyLDApKQ0KDQojIHh4ID0geFttbSRyd2VpZ2h0cz4wLjksXQ0KIyB5eSA9IHlbbW0kcndlaWdodHM+MC45XQ0KDQoNCmZvciAoaiBpbiBhbHApew0KICAjIHNldC5zZWVkICgzKQ0KICBjdi5vdXQgPSBjdi5nbG1uZXQoeCwgeSwgYWxwaGEgPSBqLCBuZm9sZHM9MTAsIHdlaWdodHMgPSBtbSRyd2VpZ2h0cykgIyBsdHNfc29sJGx0cy53dA0KICBwbG90KGN2Lm91dCkNCiAgdGl0bGUocGFzdGUoImFscGhhID0gIiwgaiksIGxpbmUgPSAwLjMpDQogICMgc2F2ZSBzZWxlY3RlZCB2YXJpYWJsZXMNCiAgIyBrZWVwIGxvd2VyIG51bWJlciBvZiB2YXJpYWJsZXMgc2VsZWN0ZWQgYnUgbGFtYmRhIG9yIGxhbWJkYS4xc2UNCiAgaWYgKHN1bShjb2VmKGN2Lm91dCwgcyA9ICJsYW1iZGEubWluIikgIT0gMCkgPiBzdW0oY29lZihjdi5vdXQsIHMgPSAibGFtYmRhLjFzZSIpICE9IDApKXsgIyBsb3dlc3QgaXMgbWluIExhbWJkYQ0KICAgIHRtcF9jb2VmZnMgPC0gY29lZihjdi5vdXQsIHMgPSAibGFtYmRhLjFzZSIpIA0KICB9IGVsc2Ugew0KICAgIHRtcF9jb2VmZnMgPC0gY29lZihjdi5vdXQsIHMgPSAibGFtYmRhLm1pbiIpICMgY3Yub3V0JGxhbWJkYS4xc2UgDQogIH0NCiAgdmFyX3NlbGVjW1tpXV0gPSBkYXRhLmZyYW1lKG5hbWUgPSB0bXBfY29lZmZzQERpbW5hbWVzW1sxXV1bdG1wX2NvZWZmc0BpICsgMV0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29lZmZpY2llbnQgPSB0bXBfY29lZmZzQHgpDQogICMgc2F2ZSBudW1iZXIgb2Ygbm9uIHplcm8gdmFyaWFibGVzDQogIG56Y29lZltpLDFdID0gY3Yub3V0JG56ZXJvW2N2Lm91dCRsYW1iZGEgPT0gY3Yub3V0JGxhbWJkYS5taW5dDQogIG56Y29lZltpLDJdID0gY3Yub3V0JG56ZXJvW2N2Lm91dCRsYW1iZGEgPT0gY3Yub3V0JGxhbWJkYS4xc2VdDQogICMgc2F2ZSB0aGUgdmFsdWUgb2YgdGhlIGNvc3QgZnVuY3Rpb24NCiAgY29zdENWW2ldID0gbWluKGN2Lm91dCRjdm0pDQogICMgaW5jcmVhc2UgaXRlcmF0b3INCiAgaSA9IGkgKyAxDQp9DQptdGV4dChleHByZXNzaW9uKCJCZXN0IGxhbWJkYSBmb3IgZGVsdGEgZ2VuZGVyIHNhbGFyeSB1c2luZyBlbGFzdGljLW5ldCBhbmQgMTAtZm9sZHMgQ1Ygd2l0aCBNTSB3ZWlnaHRzIiksIA0KICAgICAgb3V0ZXI9VFJVRSwgIGNleD0wLjgsIGxpbmU9MC4yKQ0KDQojIGJlc3QgbW9kZWwgKG1pbiBtZWFuIEN2IGVycm9yKQ0KYmVzdENWID0gd2hpY2gubWluKGNvc3RDVikNCiMgIyBzaG93IHRoZSBjb2VmZmljaWVudHMgb2J0YWluZWQgZm9yIHRoZSBiZXN0IG1vZGVsIChhZGRlZCBpbiB0aGUgZmluYWwgdGFibGUpDQojIHByaW50KHZhcl9zZWxlY1tbYmVzdENWXV0pDQoNCnBhcihtZnJvdyA9YygxLDEpKQ0KIyBwbG90bWVhbiBDdiBlcnJvcg0KcGxvdChhbHAsIGNvc3RDViwgbWFpbj0iTWVhbiAxMC1mb2xkcyBDViBlcnJvciBmb3IgZWFjaCBhbHBoYSBsZXZlbCIsDQogICAgIHhsYWIgPSAiYWxwaGEgcHJvcG9ydGlvbiIsIHlsYWIgPSAibWVhbiBDViBlcnJvciIsIHR5cGUgPSAiYiIsIGNvbCA9ICJibHVlIikNCmF4aXMoc2lkZSA9IDEsIGF0ID0gYyhhbHApKQ0KDQojIHBsb3QgbnVtYmVyIG9mIG5vbiB6ZXJvIGNvZWZmaWNpZW50cw0KcGxvdChhbHAsIG56Y29lZlssMV0sIG1haW49Ik51bWJlciBvZiBub24temVybyBjb2VmZmljaWVudHMgZm9yIGVhY2ggYWxwaGEgbGV2ZWwiLA0KICAgICB4bGFiID0gImFscGhhIHByb3BvcnRpb24iLCB5bGFiID0gIk5vbi16ZXJvIGNvZWZmaWNpZW50cyIsIHR5cGUgPSAiYiIsIGNvbCA9ICJibHVlIiwNCiAgICAgeWxpbSA9IGMobWluKG56Y29lZiksIG1heChuemNvZWYpKSkNCmxpbmVzKGFscCwgbnpjb2VmWywyXSwgY29sID0gInJlZCIsIHR5cGUgPSAiYiIpDQpsZWdlbmQoJ3RvcHJpZ2h0JywgYygibGFtYmRhIG1pbiIsICJsYW1iZGEgMVNFIiksIGx0eSA9IDEsIGNvbCA9IGMoImJsdWUiLCAicmVkIiksIGNleCA9IDAuNyxsd2Q9MikgDQpheGlzKHNpZGUgPSAxLCBhdCA9IGMoYWxwKSkNCg0KIyBleHRyYWN0IHNpZ25pZmljYW50IHZhcmlhYmxlcyBhbmQgc2F2ZSBpbiBhIGRhdGFmcmFtZQ0KY29lZmYuZGYkIkVORVQoTU0pIiA9IGFzLmNoYXJhY3RlcihyZXAoIi0tIiwgbnJvdyhjb2VmZi5kZikpKQ0KaUVORVRNTSA9IHJvdy5uYW1lcyhjb2VmZi5kZikgJWluJSB2YXJfc2VsZWNbW2Jlc3RDVl1dJG5hbWUNCmNvZWZmLmRmJCJFTkVUKE1NKSJbaUVORVRNTV0gPSBzcHJpbnRmKCIlLjJlIiwgYXMubWF0cml4KHZhcl9zZWxlY1tbYmVzdENWXV0kY29lZmZpY2llbnQpKSANCg0KYGBgDQoNCkNvbnRyYXJpbHkgdG8gd2hhdCB3YXMgZXhwZWN0ZWQsIHRoZSBtb2RlbCBpcyBub3Qgc28gc3BhcnNlLg0KT24gdGhlIG90aGVyIGhhbmQsIHRoZSBtZWFuIENWIGVycm9yIGRlY3JlYXNlcyBzdWJzdGlhbnRpYWxseSAoYXJvdW5kIDAuNCkNCmNvbXBhcmVkIHRvIHRoZSBwdXJlIEVORVQgbW9kZWwgKGFyb3VuZCAxLjQpLCBhbmQgdGhpcyBnYWluIHdvdWxkDQpwZXJzaXN0IGV2ZW4gYWxsb3dpbmcgZm9yIGEgc3Ryb25nZXIgc2hyaW5rYWdlIG9mIHRoZSBsYW1iZGEgdmFsdWVzDQphbmQgaGVuY2UgcmVkdWNpbmcgdGhlIG51bWJlciBvZiBjb2VmZmljaWVudHMuDQpJdCBpcyBhbHNvIGludGVyZXN0aW5nIHRvIG5vdGUgdGhlIHN0cm9uZyBkZWNyZWFzZSBpbiBDViBlcnJvcg0KYXMgc29tZSBwcm9wb3J0aW9uIG9mIExhc3NvIGlzIGludHJvZHVjZWQuDQoNClN1Y2ggYmVoYXZpb3Igc2hvdWxkIGJlIHN0dWRpZWQgZnVydGhlci4NCkEgbW90aXZhdGlvbiBjb3VsZCBiZSB0aGUgZmFjdCB0aGF0IEVORVQgaXMgYmFzZWQgb24gQ1YsIGFuZCBzb21lIG91bHlpbmcgdW5pdHMgd2l0aCB3ZWlnaHRzDQpkaWZmZXJlbnQgZnJvbSAwIGNhbiBhZmZlY3QgdGhpcyByZXN1bHQuDQpPbiB0aGUgb3RoZXIgaGFuZCwgZXZlbiBwcm92aWRpbmcgdG8gRU5FVCBvbmx5IHVuaXRzIHdpdGggTU0td2VpZ2h0cw0KZ3JlYXRlciB0aGFuIDAuOSAoaS5lLiwgYWxtb3N0IHN1cmVseSBub24gb3V0bHlpbmcgYWNjb3JkaW5nIHRvIE1NIGJhc2VkIG9uIGFsbCB2YXJpYWJsZXMpLA0KbWVhbiBDViBlcnJvciBkZWNyZWFzZSBzdWJzdGFudGlhbGx5LCBidXQgdGhlIHByb2JsZW0gcGVyc2lzdHMuDQoNCg0KIyMjIyBPTFMgb24gRWxhc3RpYyBuZXQgc29sdXRpb24gd2l0aCBNTSB3ZWlnaHRzDQoNClRoZSBzYW1lIGlzIHRydWUgYXBwbHlpbmcgYW4gT0xTIGVzdGltYXRlIG9uIHRoZSBub24gb3VseWluZyB1bml0cw0KKGkuZS4sIHdpdGggTU0td2VpZ2h0cyA+IDAuMDUpIGFuZCB0aGUgdmFyaWFibGVzIGlkZW50aWZpZWQgYnUgRU5FVChNTSkuDQpgYGB7ciBFTkVUKE1NKStPTFN9DQoNCiMgVG8gdHJ5IHRvIHNvbHZlIHRoaXMgcHJvYmxlbSwgYW5vdGhlciBzdGVwIG9mDQojIE9MUyBlc3RpbWF0ZSBpcyBjb21wdXRlZCBvbiB0aGUgdmFyaWFibGVzIHNlbGVjdGVkIGJ5DQojIEUtTmV0IHdpdGggTU0gd2VpZ2h0cywgZXhjbHVkaW5nIGZyb210IHRoZSBmaXQgdW5pdHMNCiMgd2l0aCBNTS13ZWlnaHRzIDw9IDAuMDUNCg0KIyBBREQgT0xTDQppbmRDb2VmID0gbmFtZXMobW9kKSAlaW4lIHZhcl9zZWxlY1tbYmVzdENWXV0kbmFtZQ0KbW9kRU5FVE1NT0xTID0gY2JpbmQuZGF0YS5mcmFtZSh5LCBtb2RbLGluZENvZWZdKQ0KbW9kRU5FVE1NT0xTID0gbW9kRU5FVE1NT0xTW21tJHJ3ZWlnaHRzPjAuMDUsXQ0KRU5FVE1NX29scyA9IGxtKHkgfiAuLCB5PVQsIGRhdGEgPSBtb2RFTkVUTU1PTFMpDQpzdW1tYXJ5KEVORVRNTV9vbHMpDQoNCiMgZGlhZ25vc3RpYyBwbG90cw0KIyBsYXlvdXQobWF0cml4KDE6NiwgbnIgPSAyKSwgaGVpZ2h0ID0gYygyLCAxKSkNClJlZ3Jlc3Npb25QbG90cyhFTkVUTU1fb2xzLCB0b3duc1ttbSRyd2VpZ2h0cz4wLjA1XSwgcm9idXN0ID0gRiwgb3V0PWRjaXR5W21tJHJ3ZWlnaHRzPjAuMDVdKQ0KDQojIGV4dHJhY3QgdmFyaWFibGVzIHNpZ25pZmljYW50IGF0IDAuMDElIGFuZCBzYXZlIHRoZW0gaW4gYSBkYXRhIGZyYW1lDQpjb2VmZi5kZiQiRU5FVChNTSkrT0xTIiA9IGFzLmNoYXJhY3RlcihyZXAoIi0tIiwgbnJvdyhjb2VmZi5kZikpKQ0KY29lZmYuZGYkIkVORVQoTU0pK09MUyJbaUVORVRNTV0gPSBhcy5tYXRyaXgoc3VtbWFyeShFTkVUTU1fb2xzKVtbImNvZWZmaWNpZW50cyJdXVssIlByKD58dHwpIl08MC4wMSkNCmNvZWZmLmRmJCJFTkVUKE1NKStPTFMiW2NvZWZmLmRmJCJFTkVUKE1NKStPTFMiPT1UUlVFXSA9IHNwcmludGYoIiUuMmUiLA0KICAgICAgICAgICBhcy5tYXRyaXgoRU5FVE1NX29scyRjb2VmZmljaWVudHNbc3VtbWFyeShFTkVUTU1fb2xzKVtbImNvZWZmaWNpZW50cyJdXVssIlByKD58dHwpIl08MC4wMV0pLCA0KQ0KY29lZmYuZGYkIkVORVQoTU0pK09MUyJbY29lZmYuZGYkIkVORVQoTU0pK09MUyI9PUZBTFNFXSA9ICItLSINCg0KYGBgDQoNCg0KU3VjaCBhIG1vZGVsIGlzIHNwYXJzZXIuIEl0IHN0aWxsIGNvbnRhaW5zIHNvbWUgbGV2ZXJhZ2UgcG9pbnRzLA0KbGlrZSBUb3Vsb3NlIGFuZCBMeW9uLCBidXQgdGhlIGRpYWdub3N0aWMgcGxvdHMgZG9uJ3Qgc2hvdyBhbnkNCnBhcnRpY3VsYXJseSBzdHJhbmdlIGJlaGF2aW9yLg0KDQpBdCB0aGUgc2FtZSB0d28gaW1wb3J0YW50IGFzcGVjdHMgaGF2ZSB0byBiZSB0YWtlbiBpbiBhY2NvdW50Og0KDQoqIHRoZSBNTSB3ZWlnaHRzIHVzZWQgd2VyZSBvYnRhaW5lZCBvbiB0aGUgYmFzZSBvZiB0aGUgZnVsbCBtb2RlbCwgDQogIGhlbmNlIHRoZXkgY291bGQgbm90IGJlIHJlYWxseSByZXByZXNlbnRhdGl2ZQ0KKiBzb21lIHVuaXRzIGFyZSBub3QgYmVpbmcgbW9kZWxlZCBpbiB0aGlzIGZyYW1ld29yaw0KDQoNCiMjIyMgRWxhc3RpYyBuZXQgd2l0aCBNTSB3ZWlnaHRzIHRvIG1vZGVsIG91dGxpZXJzDQoNClRvIGZhY2UgdGhlIGxhdHRlciBwcm9ibGVtIGFuIGFwcHJvYWNoIGNvdWxkIGJlIGJhc2VkIG9uIHRoZSBpZGVhIG9mIG1vZGVsaW5nDQphcGFydCB0aGUgbW9zdCBvdXRseWluZyB1bml0cy4NCkZvciBpbnN0YW5jZSwgdGhlIGZvbGxvd2luZyBmaXQgaXMgYmFzZWQgb24gRU5FVCB3aGVyZSB0aGUgcHJvdmlkZWQgd2VpZ2h0cw0KY29ycmVzcG9uZCB0byAxIC0gTU13ZWlnaHRzLg0KYGBge3IgRU5FVChNTW91dCl9DQoNCnNldC5zZWVkKDEpDQoNCiMgaW5pdGlhbGl6ZSBsaXN0IHRvIGNvbnRhaW4gdGhlIHZhcmlhYmxlcyBzZWxlY3RlZCwgDQojIG51bWJlciBvZiBub24gemVybyBjb2VmZmljaWVudHMsDQojIGNvc3QgZnVuY3Rpb24gYW5kIHRoZSBjb3VudGVyDQpuemNvZWYgPSBtYXRyaXgoTkEsIGxlbmd0aChhbHApLCAyKQ0KdmFyX3NlbGVjID0gbGlzdCgpDQpjb3N0Q1YgPSByZXAoTkEsIGxlbmd0aChhbHApKQ0KaSA9IDENCg0KcGFyKG1mcm93ID1jKDMsNCkpDQpwYXIob21hPWMoMCwwLDIsMCkpDQoNCmZvciAoaiBpbiBhbHApew0KICAjIHNldC5zZWVkICgzKQ0KICBjdi5vdXQgPSBjdi5nbG1uZXQoeCwgeSwgYWxwaGEgPSBqLCBuZm9sZHM9MTAsIHdlaWdodHMgPSAxLW1tJHJ3ZWlnaHRzKSAjIHN0YW5kYXJkaXplLnJlc3BvbnNlID0gVCAsIHBhcmFsbGVsID0gVCANCiAgcGxvdChjdi5vdXQpDQogIHRpdGxlKHBhc3RlKCJhbHBoYSA9ICIsIGopLCBsaW5lID0gMC4zKQ0KICAjIHNhdmUgc2VsZWN0ZWQgdmFyaWFibGVzDQogICMga2VlcCBsb3dlciBudW1iZXIgb2YgdmFyaWFibGVzIHNlbGVjdGVkIGJ1IGxhbWJkYSBvciBsYW1iZGEuMXNlDQogIGlmIChzdW0oY29lZihjdi5vdXQsIHMgPSAibGFtYmRhLm1pbiIpICE9IDApID4gc3VtKGNvZWYoY3Yub3V0LCBzID0gImxhbWJkYS4xc2UiKSAhPSAwKSl7ICMgbG93ZXN0IGlzIG1pbiBMYW1iZGENCiAgICB0bXBfY29lZmZzIDwtIGNvZWYoY3Yub3V0LCBzID0gImxhbWJkYS4xc2UiKSANCiAgfSBlbHNlIHsNCiAgICB0bXBfY29lZmZzIDwtIGNvZWYoY3Yub3V0LCBzID0gImxhbWJkYS5taW4iKSAjIGN2Lm91dCRsYW1iZGEuMXNlIA0KICB9DQogIHZhcl9zZWxlY1tbaV1dID0gZGF0YS5mcmFtZShuYW1lID0gdG1wX2NvZWZmc0BEaW1uYW1lc1tbMV1dW3RtcF9jb2VmZnNAaSArIDFdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvZWZmaWNpZW50ID0gdG1wX2NvZWZmc0B4KQ0KICAjIHNhdmUgbnVtYmVyIG9mIG5vbiB6ZXJvIHZhcmlhYmxlcw0KICBuemNvZWZbaSwxXSA9IGN2Lm91dCRuemVyb1tjdi5vdXQkbGFtYmRhID09IGN2Lm91dCRsYW1iZGEubWluXQ0KICBuemNvZWZbaSwyXSA9IGN2Lm91dCRuemVyb1tjdi5vdXQkbGFtYmRhID09IGN2Lm91dCRsYW1iZGEuMXNlXQ0KICAjIHNhdmUgdGhlIHZhbHVlIG9mIHRoZSBjb3N0IGZ1bmN0aW9uDQogIGNvc3RDVltpXSA9IG1pbihjdi5vdXQkY3ZtKQ0KICAjIGluY3JlYXNlIGl0ZXJhdG9yDQogIGkgPSBpICsgMQ0KfQ0KbXRleHQoZXhwcmVzc2lvbigiQmVzdCBsYW1iZGEgZm9yIGRlbHRhIGdlbmRlciBzYWxhcnkgdXNpbmcgZWxhc3RpYy1uZXQgYW5kIDEwLWZvbGRzIENWIHdpdGggTU0gd2VpZ2h0cyIpLCANCiAgICAgIG91dGVyPVRSVUUsICBjZXg9MC44LCBsaW5lPTAuMikNCg0KIyBiZXN0IG1vZGVsIChtaW4gbWVhbiBDdiBlcnJvcikNCmJlc3RDViA9IHdoaWNoLm1pbihjb3N0Q1YpDQojICMgc2hvdyB0aGUgY29lZmZpY2llbnRzIG9idGFpbmVkIGZvciB0aGUgYmVzdCBtb2RlbCAoYWRkZWQgaW4gdGhlIGZpbmFsIHRhYmxlKQ0KIyBwcmludCh2YXJfc2VsZWNbW2Jlc3RDVl1dKQ0KDQpwYXIobWZyb3cgPWMoMSwxKSkNCiMgcGxvdG1lYW4gQ3YgZXJyb3INCnBsb3QoYWxwLCBjb3N0Q1YsIG1haW49Ik1lYW4gMTAtZm9sZHMgQ1YgZXJyb3IgZm9yIGVhY2ggYWxwaGEgbGV2ZWwiLA0KICAgICB4bGFiID0gImFscGhhIHByb3BvcnRpb24iLCB5bGFiID0gIm1lYW4gQ1YgZXJyb3IiLCB0eXBlID0gImIiLCBjb2wgPSAiYmx1ZSIpDQpheGlzKHNpZGUgPSAxLCBhdCA9IGMoYWxwKSkNCg0KIyBwbG90IG51bWJlciBvZiBub24gemVybyBjb2VmZmljaWVudHMNCnBsb3QoYWxwLCBuemNvZWZbLDFdLCBtYWluPSJOdW1iZXIgb2Ygbm9uLXplcm8gY29lZmZpY2llbnRzIGZvciBlYWNoIGFscGhhIGxldmVsIiwNCiAgICAgeGxhYiA9ICJhbHBoYSBwcm9wb3J0aW9uIiwgeWxhYiA9ICJOb24temVybyBjb2VmZmljaWVudHMiLCB0eXBlID0gImIiLCBjb2wgPSAiYmx1ZSIsDQogICAgIHlsaW0gPSBjKG1pbihuemNvZWYpLCBtYXgobnpjb2VmKSkpDQpsaW5lcyhhbHAsIG56Y29lZlssMl0sIGNvbCA9ICJyZWQiLCB0eXBlID0gImIiKQ0KbGVnZW5kKCd0b3ByaWdodCcsIGMoImxhbWJkYSBtaW4iLCAibGFtYmRhIDFTRSIpLCBsdHkgPSAxLCBjb2wgPSBjKCJibHVlIiwgInJlZCIpLCBjZXggPSAwLjcsbHdkPTIpIA0KYXhpcyhzaWRlID0gMSwgYXQgPSBjKGFscCkpDQoNCiMgZXh0cmFjdCBzaWduaWZpY2FudCB2YXJpYWJsZXMgYW5kIHNhdmUgaW4gYSBkYXRhZnJhbWUNCmNvZWZmLmRmJCJFTkVUKE1Nb3V0KSIgPSBhcy5jaGFyYWN0ZXIocmVwKCItLSIsIG5yb3coY29lZmYuZGYpKSkNCmlFTkVUTU0gPSByb3cubmFtZXMoY29lZmYuZGYpICVpbiUgdmFyX3NlbGVjW1tiZXN0Q1ZdXSRuYW1lDQpjb2VmZi5kZiQiRU5FVChNTW91dCkiW2lFTkVUTU1dID0gc3ByaW50ZigiJS4yZSIsIGFzLm1hdHJpeCh2YXJfc2VsZWNbW2Jlc3RDVl1dJGNvZWZmaWNpZW50KSkgDQoNCiMgQUREIE9MUyAob25seSB0byBvYnRhaW4gZGlhZ25vc3RpYyBwbG90cykNCnRyaW0gPSAwLjE1ICMgTU0gd2VpZ2h0cyBjdXRvZmYgdG8gY29uc2lkZXIgb3V0bGllcnMNCmluZENvZWYgPSBuYW1lcyhtb2QpICVpbiUgdmFyX3NlbGVjW1tiZXN0Q1ZdXSRuYW1lDQptb2RFTkVUTU1PTFNvdXQgPSBjYmluZC5kYXRhLmZyYW1lKHkgPSB5W21tJHJ3ZWlnaHRzPHRyaW1dLCBtb2RbbW0kcndlaWdodHM8dHJpbSxpbmRDb2VmXSkgDQptb2RFTkVUTU1PTFNvdXQgPSBsbSh5IH4gLiwgeT1ULCBkYXRhID0gbW9kRU5FVE1NT0xTb3V0KQ0Kc3VtbWFyeShtb2RFTkVUTU1PTFNvdXQpDQoNCiMgZGlhZ25vc3RpYyBwbG90cw0KIyBsYXlvdXQobWF0cml4KDE6NiwgbnIgPSAyKSwgaGVpZ2h0ID0gYygyLCAxKSkNCm91dGxPcHBvc2l0ZSA9IGFzLmNoYXJhY3RlcihvdXRsTU0pIA0Kb3V0bE9wcG9zaXRlW291dGxPcHBvc2l0ZSA9PSAwXSA9IDEwMA0Kb3V0bE9wcG9zaXRlW291dGxPcHBvc2l0ZSA9PSAxXSA9IDANCm91dGxPcHBvc2l0ZVtvdXRsT3Bwb3NpdGUgPT0gMTAwXSA9IDENCm91dGxPcHBvc2l0ZSA9IGFzLmZhY3RvcihvdXRsT3Bwb3NpdGUpDQpSZWdyZXNzaW9uUGxvdHMobW9kRU5FVE1NT0xTb3V0LCB0b3duc1ttbSRyd2VpZ2h0czx0cmltXSwgcm9idXN0ID0gRiwgb3V0PWRjaXR5W21tJHJ3ZWlnaHRzPHRyaW1dKQ0KDQojIGV4dHJhY3QgdmFyaWFibGVzIHNpZ25pZmljYW50IGF0IDAuMDElIGFuZCBzYXZlIHRoZW0gaW4gYSBkYXRhIGZyYW1lDQojIGNvZWZmLmRmJCJFTkVUKE1Nb3V0KSIgPSBhcy5jaGFyYWN0ZXIocmVwKCItLSIsIG5yb3coY29lZmYuZGYpKSkNCiMgY29lZmYuZGYkIkVORVQoTU1vdXQpIltpRU5FVE1NXSA9IGFzLm1hdHJpeChzdW1tYXJ5KG1vZEVORVRNTU9MU291dClbWyJjb2VmZmljaWVudHMiXV1bLCJQcig+fHR8KSJdPDAuMDEpDQojIGNvZWZmLmRmW2NvZWZmLmRmPT1UUlVFXSA9IHNwcmludGYoIiUuMmUiLA0KIyAgICAgICAgICAgIGFzLm1hdHJpeChtb2RFTkVUTU1PTFNvdXQkY29lZmZpY2llbnRzW3N1bW1hcnkobW9kRU5FVE1NT0xTb3V0KVtbImNvZWZmaWNpZW50cyJdXVssIlByKD58dHwpIl08MC4wMV0pLCA0KQ0KIyBjb2VmZi5kZltjb2VmZi5kZj09RkFMU0VdID0gIi0tIiANCg0KYGBgDQoNClRoaXMgbW9kZWwgcmVzdWx0cyBpbjoNCg0KKiBpbiBhIHZlcnkgc3BhcnNlIG1vZGVsIHdoaWNoIHNlZW1zIHRvIGZpdCByZWFzb25hYmx5IHdlbGwgYWxsIHRoZSBwb2ludHMNCiogcHJvdmlkZXMgY29lZmZpY2llbnRzIHdoaWNoIGFyZSBzZW5zaWJseSBkaWZmZXJlbnQgdGhhbiB0aGUgb25lcyBmb3IgdGhlIHByZXZpb3VzbHkgY29uc2lkZXJlZCBtb2RlbHMNCihlLmcuLCB1bmVtcGxveW1lbnQgY29lZmZpY2llbnRzIGNoYW5nZXMgaXRzIHNpZ24pIHN1cHBvcnRpbmcgdGhlIGFzc3VtcHRpb24gdGhhdCB0aGVyZSBpcyBtb3JlIHRoYW4gb25lIGRhdGEgZ2VuZXJhdGluZyBwcm9jZXNzDQoqIHRoZSBtZWFuIENWIGVycm9yIGluY3JlYXNlcyBzdWJzdGFudGlhbGx5IA0KDQpBIHBvc3NpYmxlIGRyYXdiYWNrIG9mIHRoaXMgYXBwcm9hY2gsIGFnYWluLCByZXNpZGUgb24gdGhlIGZhY3QgdGhhdCB0aGUgTU0gd2VpZ2h0cyBhcmUgYmFzZWQgb24gdGhlIGZ1bGwgbW9kZWwuDQoNCg0KIyMjIFJvYnVzdCBhcHByb2FjaGVzIGluY29ycG9yYXRpbmcgc2hyaW5rYWdlDQoNCiMjIyMgU3BhcnNlLUxUUw0KDQpUaGUgZXN0aW1hdG9yIHNwYXJzZS1MVFMsIHdoaWNoIGlzIGEgcm9idXN0aWZpY2F0aW9uIG9mIExhc3NvIHVzaW5nIExUUywgaXMgbm93IGFwcGxpZWQuDQpUaGUgcGFyYW1ldGVycyB1c2VkIHBlcmZvcm0gYSB0cmltbWluZyAxMCUgb2YgdGhlIHVuaXRzLCBhbmQgMTAgcmVwbGljYXRpb24gb2YgMTAtZm9sZHMgQ1YNCmBgYHtyIHNwYXJzZUxUUywgd2FybmluZz1GQUxTRX0NCg0Kc2V0LnNlZWQoMSkNCg0KIyBpbnN0YWxsLnBhY2thZ2VzKCJzbm93IikNCiMgbGlicmFyeSgic25vdyIpDQoNCiMgZml0IHJvYnVzdCBMYXNzbw0KY2wgPSBtYWtlQ2x1c3RlcihkZXRlY3RDb3JlcygpKQ0Kc29sX3NwYXJzZUxUUyA9IHNwYXJzZUxUUyh4LCB5LCBtb2RlID0gImxhbWJkYSIsIGFscGhhID0gMC45LCBjbCA9IGNsLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWw9VFJVRSwgY3JpdCA9ICJQRSIsIHNwbGl0cyA9IGZvbGRDb250cm9sKDEwLCAxMCkpICMgY3JpdCA9ICJCSUMiDQojIHNvbF9zcGFyc2VMVFNfQ1YgPSBwZXJyeShzb2xfc3BhcnNlTFRTLCBzcGxpdHMgPSBmb2xkQ29udHJvbCgxMCwgMTApLCBjb3N0ID0gcnRtc3BlLCBuY29yZXMgPSBjbCkNCnN0b3BDbHVzdGVyKGNsKQ0KDQojIGNoZWNrIHRoZSBzb2x1dGlvbg0KcHJpbnQoc29sX3NwYXJzZUxUUykgDQoNCiMgZml0IGFuZCBldmFsdWF0ZSBzcGFyc2UgTFRTIG1vZGVsDQogICMgcGxvdChzb2xfc3BhcnNlTFRTX0NWLCAiZGVuc2l0eSIpIA0KDQojIGFzc2lnbiBsZXZlcmFnZXMsIGFzc2lnbmVkIG9ubHkgdG8gb2J0YWluIGRpYWdub3N0aWMgcGxvdHMNCnNvbF9zcGFyc2VMVFMkTUQgPSByZXAoMSwgbGVuZ3RoKHkpKSAjIGNvdk1jZCh4KSRtYWggIyBjb21wdXRlIHN0YW5kYXJkIGxldmVyYWdlcw0KIyBvdXRsaWVycyBpZGVudGlmaWVkIGFuZCBpbXBvcnRhbnQgY2l0aWVzDQpvdXRsU0xUUyA9IGFzLmNoYXJhY3Rlcihzb2xfc3BhcnNlTFRTJHd0KQ0Kb3V0bFNMVFNbZGNpdHkhPTFdID0gYXMuY2hhcmFjdGVyKGRjaXR5W2RjaXR5IT0xXSkNCm91dGxTTFRTID0gYXMuZmFjdG9yKG91dGxTTFRTKQ0KIyBkaWFnbm9zdGljIHBsb3RzDQpSZWdyZXNzaW9uUGxvdHMoc29sX3NwYXJzZUxUUywgdGV4dGxhYmVscz10b3ducywgcm9idXN0ID0gVFJVRSwgb3V0ID0gb3V0bFNMVFMpW1sxXV0NClJlZ3Jlc3Npb25QbG90cyhzb2xfc3BhcnNlTFRTLCB0ZXh0bGFiZWxzPXRvd25zLCByb2J1c3QgPSBUUlVFLCBvdXQgPSBvdXRsU0xUUylbWzJdXQ0KUmVncmVzc2lvblBsb3RzKHNvbF9zcGFyc2VMVFMsIHRleHRsYWJlbHM9dG93bnMsIHJvYnVzdCA9IFRSVUUsIG91dCA9IG91dGxTTFRTKVtbM11dDQpkaWFnbm9zdGljUGxvdChzb2xfc3BhcnNlTFRTLCBpZC5uID0gMTAsIGFzayA9IEZBTFNFLCBsYWJlbD10b3ducywgd2hpY2ggPSAicmRpYWciKQ0KDQojIGV4dHJhY3QgdmFyaWFibGVzIHNpZ25pZmljYW50IGFuZCBzYXZlIHRoZW0gaW4gYSBkYXRhIGZyYW1lDQppU0xUUyA9IGNvZWZmaWNpZW50cyhzb2xfc3BhcnNlTFRTKSE9MA0KY29lZmYuZGYkU0xUUyA9IGFzLmNoYXJhY3RlcihyZXAoIi0tIiwgbnJvdyhjb2VmZi5kZikpKQ0KY29lZmYuZGYkU0xUU1tpU0xUU10gPSBzcHJpbnRmKCIlLjJlIiwgYXMubWF0cml4KGNvZWZmaWNpZW50cyhzb2xfc3BhcnNlTFRTKVtpU0xUU10pKQ0KDQpgYGANCg0KVGhpcyBtb2RlbCByZXN1bHRzIGluOiANCg0KKiBhIHZlcnkgc3BhcnNlIGFuZCByb2J1c3QgbW9kZWwNCiogdGhlIHVuZW1wbG95bWVudCByYXRlIGlzIHRoZSBtb3N0IGltcG9ydGFudCB2YXJpYWJsZQ0KKiBjbGVhcmx5IHNob3dzIDIgZGlmZmVyZW50IHN1Yi1wb3BpbGF0aW9ucw0KKiBQYXJpcyBpcyBub3QgYSBjbGVhciBvdXRsaWVyDQoNClRoZSBtYWluIGRyYXdiYWNrIHJlc2lkZXMgb24gdGhlIGZhY3QgdGhhdCBpdCBpcyBub3QgdGFraW5nIGludG8gYWNjb3VudCBjb2xsaW5lYXJpdHkuDQoNCg0KIyMjIyBFbGFzdGljIG5ldCB3aXRoIHNwYXJzZS1MVFMgd2VpZ2h0cw0KDQpJbiBvcmRlciB0byB0cnkgdG8gc29sdmUgdGhpcyBwcm9ibGVtLCBFTkVUIHdpdGggd2VpZ2h0cyBwcm92aWRlZCBieSBzcGFyc2VMVFMgY291bGQgYmUgYXBwbGllZA0KYGBge3IgRU5FVChTTFRTKX0NCg0Kc2V0LnNlZWQoMSkNCg0KIyBpbml0aWFsaXplIGxpc3QgdG8gY29udGFpbiB0aGUgdmFyaWFibGVzIHNlbGVjdGVkLA0KIyBudW1iZXIgb2Ygbm9uIHplcm8gY29lZmZpY2llbnRzLA0KIyBjb3N0IGZ1bmN0aW9uIGFuZCB0aGUgY291bnRlcg0Kbnpjb2VmID0gbWF0cml4KE5BLCBsZW5ndGgoYWxwKSwgMikNCnZhcl9zZWxlYyA9IGxpc3QoKQ0KY29zdENWID0gcmVwKE5BLCBsZW5ndGgoYWxwKSkNCmkgPSAxDQoNCnBhcihtZnJvdyA9YygzLDQpKQ0KcGFyKG9tYT1jKDAsMCwyLDApKQ0KDQpub25PdXRTTFRTID0gYXMubG9naWNhbChzb2xfc3BhcnNlTFRTJHd0KQ0KDQpmb3IgKGogaW4gYWxwKXsNCiAgIyBzZXQuc2VlZCAoMykNCiAgY3Yub3V0ID0gY3YuZ2xtbmV0KHgsIHksIGFscGhhID0gaiwgbmZvbGRzPTEwLCB3ZWlnaHRzID0gbm9uT3V0U0xUUykNCiAgcGxvdChjdi5vdXQpDQogIHRpdGxlKHBhc3RlKCJhbHBoYSA9ICIsIGopLCBsaW5lID0gMC4zKQ0KICAjIHNhdmUgc2VsZWN0ZWQgdmFyaWFibGVzDQogICMga2VlcCBsb3dlciBudW1iZXIgb2YgdmFyaWFibGVzIHNlbGVjdGVkIGJ5IGxhbWJkYSBvciBsYW1iZGEuMXNlDQogIGlmIChzdW0oY29lZihjdi5vdXQsIHMgPSAibGFtYmRhLm1pbiIpICE9IDApID4gc3VtKGNvZWYoY3Yub3V0LCBzID0gImxhbWJkYS4xc2UiKSAhPSAwKSl7ICMgbG93ZXN0IGlzIG1pbiBMYW1iZGENCiAgICB0bXBfY29lZmZzIDwtIGNvZWYoY3Yub3V0LCBzID0gImxhbWJkYS4xc2UiKQ0KICB9IGVsc2Ugew0KICAgIHRtcF9jb2VmZnMgPC0gY29lZihjdi5vdXQsIHMgPSAibGFtYmRhLm1pbiIpICMgY3Yub3V0JGxhbWJkYS4xc2UNCiAgfQ0KICB2YXJfc2VsZWNbW2ldXSA9IGRhdGEuZnJhbWUobmFtZSA9IHRtcF9jb2VmZnNARGltbmFtZXNbWzFdXVt0bXBfY29lZmZzQGkgKyAxXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvZWZmaWNpZW50ID0gdG1wX2NvZWZmc0B4KQ0KICAjIHNhdmUgbnVtYmVyIG9mIG5vbiB6ZXJvIHZhcmlhYmxlcw0KICBuemNvZWZbaSwxXSA9IGN2Lm91dCRuemVyb1tjdi5vdXQkbGFtYmRhID09IGN2Lm91dCRsYW1iZGEubWluXQ0KICBuemNvZWZbaSwyXSA9IGN2Lm91dCRuemVyb1tjdi5vdXQkbGFtYmRhID09IGN2Lm91dCRsYW1iZGEuMXNlXQ0KICAjIHNhdmUgdGhlIHZhbHVlIG9mIHRoZSBjb3N0IGZ1bmN0aW9uDQogIGNvc3RDVltpXSA9IG1pbihjdi5vdXQkY3ZtKQ0KICAjIGluY3JlYXNlIGl0ZXJhdG9yDQogIGkgPSBpICsgMQ0KfQ0KbXRleHQoZXhwcmVzc2lvbigiQmVzdCBsYW1iZGEgZm9yIGRlbHRhIGdlbmRlciBzYWxhcnkgdXNpbmcgZWxhc3RpYy1uZXQgYW5kIDEwLWZvbGRzIENWIHdpdGggc3BhcnNlLUxUUyB3ZWlnaHRzIiksDQogICAgICBvdXRlcj1UUlVFLCAgY2V4PTAuOCwgbGluZT0wLjIpDQoNCiMgYmVzdCBtb2RlbCAobWluIG1lYW4gQ3YgZXJyb3IpDQpiZXN0Q1YgPSB3aGljaC5taW4oY29zdENWKQ0KIyBtYW51YWxseSBzZWxlY3QgdGhlIDh0aCBhcyB0aGUgYmVzdCBtb2RlbA0KYmVzdENWID0gOA0KIyAjIHNob3cgdGhlIGNvZWZmaWNpZW50cyBvYnRhaW5lZCBmb3IgdGhlIGJlc3QgbW9kZWwgKGFkZGVkIGluIHRoZSBmaW5hbCB0YWJsZSkNCiMgcHJpbnQodmFyX3NlbGVjW1tiZXN0Q1ZdXSkNCg0KcGFyKG1mcm93ID1jKDEsMSkpDQojIHBsb3RtZWFuIEN2IGVycm9yDQpwbG90KGFscCwgY29zdENWLCBtYWluPSJNZWFuIDEwLWZvbGRzIENWIGVycm9yIGZvciBlYWNoIGFscGhhIGxldmVsIiwNCiAgICAgeGxhYiA9ICJhbHBoYSBwcm9wb3J0aW9uIiwgeWxhYiA9ICJtZWFuIENWIGVycm9yIiwgdHlwZSA9ICJiIiwgY29sID0gImJsdWUiKQ0KYXhpcyhzaWRlID0gMSwgYXQgPSBjKGFscCkpDQoNCiMgcGxvdCBudW1iZXIgb2Ygbm9uIHplcm8gY29lZmZpY2llbnRzDQpwbG90KGFscCwgbnpjb2VmWywxXSwgbWFpbj0iTnVtYmVyIG9mIG5vbi16ZXJvIGNvZWZmaWNpZW50cyBmb3IgZWFjaCBhbHBoYSBsZXZlbCIsDQogICAgIHhsYWIgPSAiYWxwaGEgcHJvcG9ydGlvbiIsIHlsYWIgPSAiTm9uLXplcm8gY29lZmZpY2llbnRzIiwgdHlwZSA9ICJiIiwgY29sID0gImJsdWUiLA0KICAgICB5bGltID0gYyhtaW4obnpjb2VmKSwgbWF4KG56Y29lZikpKQ0KbGluZXMoYWxwLCBuemNvZWZbLDJdLCBjb2wgPSAicmVkIiwgdHlwZSA9ICJiIikNCmxlZ2VuZCgndG9wcmlnaHQnLCBjKCJsYW1iZGEgbWluIiwgImxhbWJkYSAxU0UiKSwgbHR5ID0gMSwgY29sID0gYygiYmx1ZSIsICJyZWQiKSwgY2V4ID0gMC43LGx3ZD0yKQ0KYXhpcyhzaWRlID0gMSwgYXQgPSBjKGFscCkpDQoNCiMgZXh0cmFjdCBzaWduaWZpY2FudCB2YXJpYWJsZXMgYW5kIHNhdmUgaW4gYSBkYXRhZnJhbWUNCmNvZWZmLmRmJCJFTkVUKFNMVFMpIiA9IGFzLmNoYXJhY3RlcihyZXAoIi0tIiwgbnJvdyhjb2VmZi5kZikpKQ0KaUVORVRTTFRTID0gcm93Lm5hbWVzKGNvZWZmLmRmKSAlaW4lIHZhcl9zZWxlY1tbYmVzdENWXV0kbmFtZQ0KY29lZmYuZGYkIkVORVQoU0xUUykiW2lFTkVUU0xUU10gPSBzcHJpbnRmKCIlLjJlIiwgYXMubWF0cml4KHZhcl9zZWxlY1tbYmVzdENWXV0kY29lZmZpY2llbnQpKQ0KDQpgYGANCg0KSW4gdGhpcyBjYXNlLCBpbnN0ZWFkIG9mIHRoZSBhY3R1YWwgbWluaW11bSBvYnRhaW5lZCBieSBFTkVUIHdoaWNoDQpjb3JyZXNwb25kZWQgdG8gYSBMYXNzbyBmaXQsIHRoZSBiZXN0IGxhYmRhIGtlcHQgY29ycmVzcG9uZHMgdG8gYWxwaGE9MC43DQooYXQgdGhlIGNvc3Qgb2YgYSBzbGlnaHRseSBoaWdoZXIgQ1YgZXJyb3IpLg0KVGhlIGhpZ2hlc3QgY29lZmZpY2llbnQgZm9yIHRoaXMgbW9kZWwgcmVzdWx0cyB0aGUgdW5lbXBsb3ltZW50IHJhdGUuDQoNClRvIHBlcmZvcm0gYSBmdXJ0aGVyIHZhbGlkYXRpb24gb2YgdGhlc2UgcmVzdWx0cywgT0xTIGlzIGFwcGxpZWQgb24gdGhlIG1vZGVsIGlkZW50aWZpZWQgDQooZGlzY2FyZGluZyB0aGUgdW5pdHMgaWRlbnRpZmllZCBieSBzcGFyc2UtTFRTKQ0KYGBge3IgRU5FVChTTFRTKStPTFN9DQoNCiMgQUREIE9MUw0KaW5kQ29lZiA9IG5hbWVzKG1vZCkgJWluJSB2YXJfc2VsZWNbW2Jlc3RDVl1dJG5hbWUNCm1vZEVORVRzbHRzT0xTID0gY2JpbmQuZGF0YS5mcmFtZSh5ID0geVtub25PdXRTTFRTXSwgbW9kW25vbk91dFNMVFMsaW5kQ29lZl0pIA0KRU5FVF9TTFRTX29scyA9IGxtKHkgfiAuLCB5PVQsIGRhdGEgPSBtb2RFTkVUc2x0c09MUykNCnN1bW1hcnkoRU5FVF9TTFRTX29scykNCg0KIyBkaWFnbm9zdGljIHBsb3RzDQojIGxheW91dChtYXRyaXgoMTo2LCBuciA9IDIpLCBoZWlnaHQgPSBjKDIsIDEpKQ0KUmVncmVzc2lvblBsb3RzKEVORVRfU0xUU19vbHMsIHRvd25zW25vbk91dFNMVFNdLCByb2J1c3QgPSBGLCBvdXQ9ZGNpdHlbbm9uT3V0U0xUU10pDQoNCiMgIyBleHRyYWN0IHZhcmlhYmxlcyBzaWduaWZpY2FudCBhdCAwLjAxJSBhbmQgc2F2ZSB0aGVtIGluIGEgZGF0YSBmcmFtZQ0KIyBjb2VmZi5kZiQiRU5FVChTTFRTKStPTFMiID0gYXMuY2hhcmFjdGVyKHJlcCgiLS0iLCBucm93KGNvZWZmLmRmKSkpDQojIGNvZWZmLmRmJCJFTkVUKFNMVFMpK09MUyJbaUVORVRTTFRTXSA9IGFzLm1hdHJpeChzdW1tYXJ5KEVORVRfU0xUU19vbHMpW1siY29lZmZpY2llbnRzIl1dWywiUHIoPnx0fCkiXTwwLjAxKQ0KIyBjb2VmZi5kZiQiRU5FVChTTFRTKStPTFMiW2NvZWZmLmRmJCJFTkVUK1NMVFMrT0xTIj09VFJVRV0gPSBzcHJpbnRmKCIlLjJlIiwNCiMgICAgICAgICAgICBhcy5tYXRyaXgoRU5FVF9TTFRTX29scyRjb2VmZmljaWVudHNbc3VtbWFyeShFTkVUX1NMVFNfb2xzKQ0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbWyJjb2VmZmljaWVudHMiXV1bLCJQcig+fHR8KSJdPDAuMDFdKSwgNCkNCiMgY29lZmYuZGYkIkVORVQoU0xUUykrT0xTIltjb2VmZi5kZiQiRU5FVCtTTFRTK09MUyI9PUZBTFNFXSA9ICItLSINCg0KYGBgDQoNClRoZXkgc2hvdyB0aGF0Og0KDQoqIHRoZSBtb2RlbCBzZWVtcyBjb3JyZWN0bHkgc3BlY2lmaWVkIGFuZCBhbGwgcmVncmVzc29ycyBhcmUgc2lnbmlmaWNhbnQNCiogUGFyaXMgaXMgbm90IGNvbnNpZGVyZWQgYXMgb24gb3V0bGllciAoaXRzIGxldmVyYWdlIGlzIHN0cm9uZ2x5IGRlY3JlYXNlZCkNCiogdGhlIHVuZW1wbG95bWVudCByYXRlIGhhcyBhIHN0cm9uZyBlZmZlY3Qgb24gdGhlIHJlc3BvbnNlDQoNCg0KIyMjIyBQZW5hbGl6ZWQgRU5FVCBiYXNlZCBvbiB0aGUgUyBlc3RpbWF0b3INCg0KUGVuYWxpemVkIEVORVQgYmFzZWQgb24gdGhlIFMgZXN0aW1hdG9yIChQRU5TRSkgaXMgbm93IGFwcGxpZWQuDQpUaGUgUEVOU0UgZXN0aW1hdGUgbWluaW1pemVzIHRoZSByb2J1c3QgTS1zY2FsZSBvZiB0aGUgcmVzaWR1YWxzIHBlbmFsaXplZCBieSB0aGUgTDEgYW5kIEwyDQpub3JtIG9mIHRoZSByZWdyZXNzaW9uIGNvZWZmaWNpZW50cyAoZWxhc3RpYyBuZXQgcGVuYWx0eSkuIFRoZSBsZXZlbCBvZiBwZW5hbGl6YXRpb24gaXMgY2hvc2VuIHRvDQptaW5pbWl6ZSB0aGUgay1mb2xkIGNyb3NzLXZhbGlkYXRlZCBwcmVkaWN0aW9uIGVycm9yICh1c2luZyBhIHJvYnVzdCBtZWFzdXJlKS4NCmBgYHtyIEVORVRTfQ0KDQojIGluc3RhbGwucGFja2FnZXMoInBlbnNlIikNCmxpYnJhcnkoInBlbnNlIikNCg0KYWxwID0gc2VxKDAsIDEsbGVuZ3RoLm91dCA9IDUpDQppID0gMQ0Kc29sX0VORVRTID0gbGlzdCgpDQoNCmZvciAoaiBpbiBhbHApew0KICBjbCA9IG1ha2VDbHVzdGVyKGRldGVjdENvcmVzKCkpDQogIHNvbF9FTkVUU1tbaV1dID0gcGVuc2UoeFssMTpuY29sKHgpLTFdLCB5LCBhbHBoYSA9IGosIG5sYW1iZGEgPSAxMCwgY3ZfayA9IDIsIGNsID0gY2wpDQogIHN0b3BDbHVzdGVyKGNsKQ0KICBpID0gaSArIDENCn0NCg0KIyBwZW5zZW0oeCwgYWxwaGEsIHNjYWxlLCBubGFtYmRhID0gNTAsIGxhbWJkYSwNCiMgbGFtYmRhX21pbl9yYXRpbywgc3RhbmRhcmRpemUsIGN2X2sgPSA1LCBjdl9vYmplY3RpdmUsDQojIG5jb3JlcyA9IGdldE9wdGlvbigibWMuY29yZXMiLCAxTCksIGNsID0gTlVMTCwNCiMgbW1fb3B0aW9ucyA9IG1zdGVwX29wdGlvbnMoKSwgZW5fb3B0aW9ucywgeF90cmFpbiwgeV90cmFpbiwgLi4uKQ0KDQoNCmBgYA0KDQpUaGlzIG1vZGVscyBzaG93IHRoYXQ6DQoqDQoqDQoNClRoZSBtYWluIGRyYXdiYWNrIGl0J3MgdGhlIGNvbXB1dGluZyB0aW1lIHJlcXVpcmVkLg0KDQoNCiMjIyMgRWxhc3RpYyBuZXQgd2l0aCBMVFMgY29zdCBmdW5jdGlvbg0KDQpSb2J1c3QgZWxhc3RpYyBuZXQsIGJhc2VkIG9uIExUUywgaXMgbm93IGZpdHRlZCB0byB0aGUgbW9kZWwgdHJpbW1pbmcgMTAlIG9mIHRoZSB1bml0cy4gDQpJdCByZXF1aXJlcyB0aGUgcmVtb3ZhbCBvZiB0aGUgZHVtbXkgdmFyaWFibGUgZm9yIHVyYmFuIHRvd25zLCANCmluIG9yZGVyIHRvIGF2b2lkIG51bWVyaWNhbCBwcm9ibGVtcy4NCmBgYHtyIGVuZXRMVFN9DQoNCiMgLCBlY2hvPUZBTFNFLCBjYWNoZT1GQUxTRQ0KDQojIHNsb3dlciB2ZXJzaW9uDQpzb2xfZW5ldExUUyA9IGVuZXRMVFMoeFssMTpuY29sKHgpLTFdLCB5LCBmYW1pbHk9ImdhdXNzaWFuIiwgYWxwaGFzPXNlcSgwLCAxLCAwLjIpLCBoc2l6ZT0wLjksDQogICAgICAgICAgICAgICAgICAgICAgbmZvbGQ9MTAsIHBhcmE9RkFMU0UsIHJlcGwgPSAxMCwgZGVsPTAuMDUpICMgcGFyYWxsZWwgZG9lcyBub3Qgd29yayBvbiB3aW5kb3dzDQojIGZhc3RlciB2ZXJzaW9uDQojIHNvbF9lbmV0TFRTID0gZW5ldExUUyh4WywxOm5jb2woeCktMV0sIHksIGZhbWlseT0iZ2F1c3NpYW4iLCBhbHBoYXM9c2VxKDAsIDEsIDAuMiksIGhzaXplPTAuOSwgDQojICAgICAgICAgICAgICAgICAgICAgICBuZm9sZD0xMCwgcGFyYT1UUlVFLCByZXBsID0gNSwgZGVsPTAuMDUpICMgcGFyYWxsZWwgZG9lcyBub3Qgd29yayBvbiB3aW5kb3dzDQoNCnByaW50KHNvbF9lbmV0TFRTKQ0KDQojIHNhdmUgb3JpZ2luYWwgcmVzcG9uc2UgKHVzZWQgZm9yIGRpYWdub3N0aWMgcGxvdHMpDQpzb2xfZW5ldExUUyR5ID0geQ0KIyBjb25zdHJ1Y3QgbWFoYWxhbm9iaXMgZGlzdGFuY2UgKHVzZWQgZm9yIGRpYWdub3N0aWMgcGxvdHMpDQpzb2xfZW5ldExUUyRNRCA9IGhhdHZhbHVlcyhvbHMpICMgY292TWNkKHgpJG1haCAjIGNvbXB1dGUgc3RhbmRhcmQgbGV2ZXJhZ2VzDQojIGNvbnN0cnVjdCByb2J1c3Qgc2NhbGUgKHVzZWQgZm9yIGRpYWdub3N0aWMgcGxvdHMpDQpzb2xfZW5ldExUUyRzY2FsZSA9IHNkKHNvbF9lbmV0TFRTJHJlc2lkdWFsc1thcy5sb2dpY2FsKHNvbF9lbmV0TFRTJHd0KV0pDQojIGludGVyYWN0aXZlIHBsb3RzDQpSZWdyZXNzaW9uUGxvdHMoc29sX2VuZXRMVFMsIHRleHRsYWJlbHM9dG93bnMsIHJvYnVzdCA9IFRSVUUsIG91dCA9IGFzLmZhY3Rvcihzb2xfZW5ldExUUyR3dCkpW1sxXV0NClJlZ3Jlc3Npb25QbG90cyhzb2xfZW5ldExUUywgdGV4dGxhYmVscz10b3ducywgcm9idXN0ID0gVFJVRSwgb3V0ID0gYXMuZmFjdG9yKHNvbF9lbmV0TFRTJHd0KSlbWzJdXQ0KUmVncmVzc2lvblBsb3RzKHNvbF9lbmV0TFRTLCB0ZXh0bGFiZWxzPXRvd25zLCByb2J1c3QgPSBUUlVFLCBvdXQgPSBhcy5mYWN0b3Ioc29sX2VuZXRMVFMkd3QpKVtbM11dDQoNCiMgYnVpbHQtaW4gcGxvdHMNCnBsb3RDb2VmLmVuZXRMVFMoc29sX2VuZXRMVFMsIGNleCA9IDUpDQpwbG90RGlhZ25vc3RpYy5lbmV0TFRTKHNvbF9lbmV0TFRTLCBjZXggPSAzKQ0KcGxvdFJlc2lkLmVuZXRMVFMoc29sX2VuZXRMVFMsIGNleCA9IDMpDQojIHBsb3Qoc29sX2VuZXRMVFMsIG1ldGhvZD1jKCJjb2VmZmljaWVudHMiLCJyZXNpZCIsImRpYWdub3N0aWMiKSwgdmVycz1jKCJyZXdlaWdodGVkIiwicmF3IiksLi4uKQ0KDQojIHNhdmUgb3V0bGllcnMgaW5kZXggDQpvdXRsRU5FVExUUyA9IGFzLmxvZ2ljYWwoc29sX2VuZXRMVFMkd3QpDQoNCiMgc2F2ZSBjb2VmZmljaWVudHMgaW4gYSBkYXRhZnJhbWUNCmlFTkVUTFRTID0gYyhUUlVFLCBzb2xfZW5ldExUUyRjb2VmZmljaWVudHMgIT0gMCwgRkFMU0UpICMgbWFudWFsbHkgaW5jbHVkZSBpbnRlcmNlcHQgYW5kIGR1bW15IGZvciBVcmJhbg0KY29lZmYuZGYkIkVORVRMVFMiID0gYXMuY2hhcmFjdGVyKHJlcCgiLS0iLCBucm93KGNvZWZmLmRmKSkpDQpzb2xfZW5ldExUUyRjb2VmZmljaWVudHNXaXRoSW50ID0gYygiKEludGVyY2VwdCkiID0gc29sX2VuZXRMVFMkYTAsIHNvbF9lbmV0TFRTJGNvZWZmaWNpZW50cykNCmNvZWZmLmRmJCJFTkVUTFRTIltpRU5FVExUU10gPSBzcHJpbnRmKCIlLjJlIixzb2xfZW5ldExUUyRjb2VmZmljaWVudHNXaXRoSW50W2lFTkVUTFRTXSwgNCkNCg0KIyMgcGVyZm9ybSBDViBmb3IgdXNlci12YWx1ZXMNCiMgDQojIENhbGN1bGF0ZSBsYW1iZGEgcGF0aCAoZmlyc3QgZ2V0IGxhbWJkYV9tYXgpOg0KIyBsYW1iZGFfbWF4IDwtIDEwICMgbWF4KGFicyhjb2xTdW1zKHN4KnN5KSkpL24NCiMgZXBzaWxvbiA8LSAuMDAwMQ0KIyBLIDwtIDEwDQojIGxhbWJkYXBhdGggPC0gcm91bmQoZXhwKHNlcShsb2cobGFtYmRhX21heCksIGxvZyhsYW1iZGFfbWF4KmVwc2lsb24pLA0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVuZ3RoLm91dCA9IEspKSwgZGlnaXRzID0gMTApDQojIHNvbF9jdiA9IGN2LmVuZXRMVFMoaW5kZXg9TlVMTCx4LHksZmFtaWx5PSJnYXVzc2lhbiIscm91bmQobGVuZ3RoKHkpKjAuOTApLA0KIyAgICAgICAgICAgIHNlcSgwLCAxLCAwLjIpLGxhbWJkYXMgPSBsYW1iZGFwYXRoICxuY29yZXM9MSxyZXBsPTUsbmZvbGQ9MTAscGxvdD1UUlVFKQ0KIyBzb2xfY3YNCg0KIyBPTFMNCm1vZEVORVRsdHNPTFMgPSBkYXRhLmZyYW1lKG1vZFtvdXRsRU5FVExUUyxpRU5FVExUU10pDQpFTkVUbHRzX29scyA9IGxtKHkgfiAuLCB5PVQsIGRhdGEgPSBtb2RFTkVUbHRzT0xTLCBzdWJzZXQgPSBzb2xfZW5ldExUUyR3dCkNCnN1bW1hcnkoRU5FVGx0c19vbHMpDQoNCiMgZGlhZ25vc3RpYyBwbG90cw0KIyBsYXlvdXQobWF0cml4KDE6NiwgbnIgPSAyKSwgaGVpZ2h0ID0gYygyLCAxKSkNClJlZ3Jlc3Npb25QbG90cyhFTkVUbHRzX29scywgdG93bnNbb3V0bEVORVRMVFNdLCByb2J1c3QgPSBGLCBvdXQ9b3V0bEVORVRMVFNbb3V0bEVORVRMVFM9PTFdKQ0KDQojIGV4dHJhY3QgdmFyaWFibGVzIHNpZ25pZmljYW50IGF0IDAuMDElIGFuZCBzYXZlIHRoZW0gaW4gYSBkYXRhIGZyYW1lDQogICMgY29lZmYuZGYkIkVORVRMVFMrT0xTIiA9IGFzLmNoYXJhY3RlcihyZXAoIi0tIiwgbnJvdyhjb2VmZi5kZikpKQ0KICAjIGNvZWZmLmRmJCJFTkVUTFRTK09MUyJbaUVORVRMVFNdID0gYXMubWF0cml4KHN1bW1hcnkoRU5FVGx0c19vbHMpW1siY29lZmZpY2llbnRzIl1dWywiUHIoPnx0fCkiXTwwLjAxKQ0KICAjIGNvZWZmLmRmW2NvZWZmLmRmPT1UUlVFXSA9IHNwcmludGYoIiUuMmUiLA0KICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXMubWF0cml4KEVORVRsdHNfb2xzJGNvZWZmaWNpZW50c1tzdW1tYXJ5KEVORVRsdHNfb2xzKVtbImNvZWZmaWNpZW50cyJdXVssIlByKD58dHwpIl08MC4wMV0pLCA0KQ0KICAjIGNvZWZmLmRmW2NvZWZmLmRmPT1GQUxTRV0gPSAiLS0iDQoNCmBgYA0KDQpUaGlzIG1vZGVsIHNob3dzIHRoYXQ6DQoNCiogdGhlIGFsZ29yaXRobSAoZXZlbiBpZiBub3QgcGFyYWxsZWxpemVkIGZvciBXaW5kb3dzIHVzZXJzKSBpcyBtdWNoIGZhc3RlciB0aGFuIFBFTlNFDQoqIC4uLg0KDQoNCiMjIyMgDQoNCmBgYHtyIEJTUyB3ZWlnaHRlZH0NCg0KIyBiZXN0IHN1YnNldCBzZWxlY3Rpb24NCmJlc3Quc3ViID0gcmVnc3Vic2V0cyh5IH4gLiwgZGF0YSA9IG1vZEVORVRsdHNPTFMsIG52bWF4ID0gbmNvbChtb2QpLCBtZXRob2Q9ImV4aGF1c3RpdmUiKSAjIGV4aGF1c3RpdmUgIyBzZXFyZXAgIyByZWFsbHkuYmlnPVRSVUUsIA0KYmVzdC5zdWIuc3VtbWFyeSA9IHN1bW1hcnkoYmVzdC5zdWIpDQojIG1hbnVhbCBwbG90dGluZw0KcGFyKG1mcm93ID1jKDIsMikpDQojIHJzcQ0KcGxvdChiZXN0LnN1Yi5zdW1tYXJ5JHJzcSAsIHhsYWI9Ik51bWJlciBvZiBWYXJpYWJsZXMiLCB5bGFiPSJSc3EiLCB0eXBlPSJsIikNCmluZF9Sc3EgPSB3aGljaC5tYXgoYmVzdC5zdWIuc3VtbWFyeSRyc3EpDQpwb2ludHMoaW5kX1JzcSwgYmVzdC5zdWIuc3VtbWFyeSRhZGpyMltpbmRfUnNxXSwgY29sID0icmVkIiwgY2V4PTIsIHBjaD0yMCkNCiMgYWRqUnNxDQpwbG90KGJlc3Quc3ViLnN1bW1hcnkkYWRqcjIgLHhsYWI9Ik51bWJlciBvZiBWYXJpYWJsZXMiLCB5bGFiPSJBZGp1c3RlZCBSU3EiLCB0eXBlPSJsIikNCmluZF9hZGpSc3EgPSB3aGljaC5tYXgoYmVzdC5zdWIuc3VtbWFyeSRhZGpyMikNCnBvaW50cyhpbmRfYWRqUnNxLCBiZXN0LnN1Yi5zdW1tYXJ5JGFkanIyW2luZF9hZGpSc3FdLCBjb2wgPSJyZWQiLCBjZXg9MiwgcGNoPTIwKQ0KIyBDcA0KcGxvdChiZXN0LnN1Yi5zdW1tYXJ5JGNwICx4bGFiPSJOdW1iZXIgb2YgVmFyaWFibGVzIiwgeWxhYj0iQ3AiLCB0eXBlPSJsIikNCmluZF9DcCA9IHdoaWNoLm1pbihiZXN0LnN1Yi5zdW1tYXJ5JGNwKQ0KcG9pbnRzKGluZF9DcCwgYmVzdC5zdWIuc3VtbWFyeSRjcFtpbmRfYWRqUnNxXSwgY29sID0icmVkIiwgY2V4PTIsIHBjaD0yMCkNCiMgYmljDQpwbG90KGJlc3Quc3ViLnN1bW1hcnkkYmljICx4bGFiPSJOdW1iZXIgb2YgVmFyaWFibGVzIiwgeWxhYj0iYmljIiwgdHlwZT0ibCIpDQppbmRfYmljID0gd2hpY2gubWluKGJlc3Quc3ViLnN1bW1hcnkkYmljKQ0KcG9pbnRzKGluZF9iaWMsIGJlc3Quc3ViLnN1bW1hcnkkYmljW2luZF9iaWNdLCBjb2wgPSJyZWQiLCBjZXg9MiwgcGNoPTIwKQ0KbXRleHQoIkJlc3Qgc3Vic2V0IHNlbGVjdGlvbiBmb3IgZGVsdGEgZ2VuZGVyIHNhbGFyeSIsIG91dGVyPVRSVUUsICBjZXg9MS4yLCBsaW5lPS0xLjUpDQoNCiMgYnVpbHQtaW4gcGxvdHMNCnBhcihtZnJvdz1jKDEsMSkpDQpwbG90LnJlZ3N1YnNldHMyKGJlc3Quc3ViLCBzY2FsZSA9ICJyMiIsIGNleC5heGlzID0gMC42LCBtYWluID0gIkJlc3Qgc3Vic2V0IHNlbGVjdGlvbiB1c2luZyBSIHNxdWFyZWQiKQ0KcGxvdC5yZWdzdWJzZXRzMihiZXN0LnN1Yiwgc2NhbGUgPSAiYWRqcjIiLCBjZXguYXhpcyA9IDAuNiwgbWFpbiA9ICJCZXN0IHN1YnNldCBzZWxlY3Rpb24gdXNpbmcgYWRqdXN0ZWQgUiBzcXVhcmVkIikNCnBsb3QucmVnc3Vic2V0czIoYmVzdC5zdWIsIHNjYWxlID0gIkNwIiwgY2V4LmF4aXMgPSAwLjYsIG1haW4gPSAiQmVzdCBzdWJzZXQgc2VsZWN0aW9uIHVzaW5nIE1hbGxvd3MnIENwIikNCnBsb3QucmVnc3Vic2V0czIoYmVzdC5zdWIsIHNjYWxlID0gImJpYyIsIGNleC5heGlzID0gMC42LCBtYWluID0gIkJlc3Qgc3Vic2V0IHNlbGVjdGlvbiB1c2luZyBCSUMiKQ0KDQojIG10ZXh0KCJCZXN0IHN1YnNldCBzZWxlY3Rpb24gZm9yIHNhbGFyeSAxOC0yNSB1c2luZyBCSUMiLCBvdXRlcj1UUlVFLCAgY2V4PTEuNCwgbGluZT0tMy41KQ0KDQojIHJldHJpZXZlIHRoZSBtb2RlbCB3aXRoIG1pbiBCSUMNCmNvZWZmaWNpZW50cyhiZXN0LnN1Yiwgd2hpY2gubWluKGJlc3Quc3ViLnN1bW1hcnkkYmljKSkNCm5ubiA9IG5hbWVzKGNvZWZmaWNpZW50cyhiZXN0LnN1Yiwgd2hpY2gubWluKGJlc3Quc3ViLnN1bW1hcnkkYmljKSkpDQoNCiMgYXBwbHkgT0xTDQptb2RfYmljID0gbW9kW21tJHJ3ZWlnaHRzPnRyaW0sIGNvbG5hbWVzKG1vZCkgJWluJSBubm5dIA0KbW9kX2JpYyA9IGNiaW5kLmRhdGEuZnJhbWUoeSA9IHlbbW0kcndlaWdodHM+dHJpbV0sIG1vZF9iaWMpDQpvbHNfYmljID0gbG0oeSB+IC4sIGRhdGEgPSBtb2RfYmljLCB5PVQpDQpzdW1tYXJ5KG9sc19iaWMpDQpSZWdyZXNzaW9uUGxvdHMob2xzX2JpYywgdGV4dGxhYmVscyA9IHRvd25zW21tJHJ3ZWlnaHRzPnRyaW1dLCBvdXQgPSBkY2l0eVttbSRyd2VpZ2h0cz50cmltXSkNCg0KIyBleHRyYWN0IHZhcmlhYmxlcyBzaWduaWZpY2FudCBhdCAwLjAxJSBhbmQgc2F2ZSB0aGVtIGluIGEgZGF0YSBmcmFtZQ0KaUJTUyA9IHJvdy5uYW1lcyhjb2VmZi5kZikgJWluJSBubm4NCmNvZWZmLmRmJCJCU1MoU0VORVQpIiA9IGFzLmNoYXJhY3RlcihyZXAoIi0tIiwgbnJvdyhjb2VmZi5kZikpKQ0KY29lZmYuZGYkIkJTUyhTRU5FVCkiW2lCU1NdID0gc3ByaW50ZigiJS4yZSIsIGFzLm1hdHJpeChjb2VmZmljaWVudHMoYmVzdC5zdWIsIHdoaWNoLm1pbihiZXN0LnN1Yi5zdW1tYXJ5JGJpYykpKSkNCg0KYGBgDQoNCg0KIyMjIENvbXBhcmlzb24gb2YgdGhlIGVzdGltYXRlcyBvYnRhaW5lZA0KDQpQcmludCB0YWJsZSBvZiByZXN1bHRzDQpgYGB7cn0NCiMgIHByaW50IHJlc3VsdHMgaW4gcGRmLCByZXN1bHRzPSdhc2lzJywgcmVuZGVyPW5vcm1hbF9wcmludA0KDQoNCmxpYnJhcnkoZ3JpZEV4dHJhKQ0KcGRmKCJyZXN1bHRzIHNwYXJzZSBtb2RlbHMucGRmIiwgaGVpZ2h0PTExLCB3aWR0aD0xMikNCmdyaWQudGFibGUoY29lZmYuZGZbMToyMyxdKQ0KZ3JpZC5uZXdwYWdlKCkNCmdyaWQudGFibGUoY29lZmYuZGZbMjQ6bnJvdyhjb2VmZi5kZiksXSkNCmRldi5vZmYoKQ0KDQpgYGANCg0KVGhpcyBmdW5jdGlvbiBpcyB1c2VkIHRvIHBsb3QgYSBzdW1tYXJ5IG9mIHRoZSByZXN1bHRzIG9idGFpbmVkIGluIEhUTUwgZm9ybWF0DQpgYGB7ciBpbnRlcmFjdGl2ZSByZXN1bHRzIGZvciBMTSwgZWNobyA9IEZBTFNFfQ0KDQojIyBQUk9DRURVUkUgRk9SIFdJTkRPV1MNCiMjIEluc3RhbGwgNjRiaXQgamF2YSBhbmQgc2V0IGl0cyBQYXRoIGluIGVudmlyb25tZW50YWwgdmFyaWFibGVzLCB0aGVuDQojIGluc3RhbGwucGFja2FnZXMoJ3JKYXZhJywgLmxpYlBhdGhzKClbMV0sICdodHRwOi8vd3d3LnJmb3JnZS5uZXQvJykNCiMgb3B0aW9ucyhqYXZhLmhvbWU9IkM6L1Byb2dyYW0gRmlsZXMvSmF2YS9qcmUxLjguMF8xNzEiKSANCiMgU3lzLnNldGVudihKQVZBX0hPTUU9J0M6L1Byb2dyYW0gRmlsZXMvSmF2YS9qcmUxLjguMF8xNzEnKSAjIGZvciA2NC1iaXQgdmVyc2lvbiANCiMjIEluc3RhbGwgbW9yZSBwYWNrYWdlcw0KIyBpbnN0YWxsLnBhY2thZ2VzKCJSZXBvcnRlUnMiKQ0KIyBpbnN0YWxsLnBhY2thZ2VzKCJzaGlueSIpDQojIGluc3RhbGwucGFja2FnZXMoInJzY29ubmVjdCIpDQoNCiMgV0FSTklORzogaW4gYSBub3RlYm9vayB0aGUgaW50ZXJhY3Rpb24gaXMgZGlzcGF5ZWQganVzdCBhdCB0aGUgZW5kDQojIEJFVFRFUiBUTyBSVU4gSVQgSU4gQSBOT1JNQUwgU0NSSVBUDQoNCiMgTG9hZCBwYWNrYWdlcw0KbGlicmFyeSgickphdmEiKQ0KbGlicmFyeSgic2hpbnkiKQ0KbGlicmFyeSgiUmVwb3J0ZVJzIikNCmxpYnJhcnkoInJzY29ubmVjdCIpDQoNCiMgc3RvcmUgYSBkYXRhZnJhbWUgd2l0aCBYIGluIHBsYWNlIG9mIHNpZ25pZmljYW50IGNvZWZmaWNpZW50cw0KbXljb2VmZi5kZiA9IGNvZWZmLmRmDQpteWNvZWZmLmRmW215Y29lZmYuZGYhPSItLSJdID0gIlgiDQoNCiMgdWkNCnVpIDwtIGZsdWlkUGFnZSgNCiAgdGFncyRoMSgiTGluZWFyIG1vZGVscycgcmVzdWx0cyBmb3IgZ2VuZGVyJ3MgZ2FwIGluIHNhbGFyeSIpLA0KICB0YWJsZU91dHB1dChvdXRwdXRJZCA9ICJ0YWJsZSIpLA0KICBicigpLA0KICB2ZXJiYXRpbVRleHRPdXRwdXQob3V0cHV0SWQgPSAib3V0IikNCikNCg0KIyBzZXJ2ZXINCnNlcnZlciA8LSBmdW5jdGlvbihpbnB1dCwgb3V0cHV0KSB7DQogIG91dHB1dCR0YWJsZSA8LSByZW5kZXJGbGV4VGFibGUoew0KICAgICMgQ3JlYXRlIGNoZWNrYm94ZXMgICANCiAgICBteWNvZWZmLmRmJFZhcmlhYmxlIDwtIHBhc3RlMCgnPGxhYmVsPjxpbnB1dCB0eXBlPSJjaGVja2JveCIgaWQ9ImNhcicsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcV9hbG9uZyhyb3duYW1lcyhjb2VmZi5kZikpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnIj4gPHNwYW4+Jywgcm93bmFtZXMoY29lZmYuZGYpLCAnPC9zcGFuPjwvbGFiZWw+JykNCiAgICBteWNvZWZmLmRmIDwtIG15Y29lZmYuZGZbYygiVmFyaWFibGUiLCBuYW1lcyhjb2VmZi5kZikpXSAjIFB1dCBjb2wgJ05hbWUnIGluIHRoZSBmaXJzdCBwbGFjZQ0KICAgICMgbXljb2VmZi5kZiA9IGNvZWZmLmRmWywxOm5jb2woY29lZmYuZGYpLTFdDQogICAgZnQgPC0gdmFuaWxsYS50YWJsZShteWNvZWZmLmRmKSAjIGNvbnZlcnQgdG8gRmxleFRhYmxlIG9iamVjdA0KICAgIGZ0WywgIlZhcmlhYmxlIiwgdG8gPSAiaGVhZGVyIl0gPC0gcGFyTGVmdCgpICMgbGVmdCBhbGlnbiBjaGVja2JveGVzDQogICAgZnRbLCAiVmFyaWFibGUiXSA8LSBwYXJMZWZ0KCkgIyBsZWZ0IGFsaWduIGhlYWRlcg0KICAgIHJldHVybihmdCkNCiAgfSkNCiAgIyB0aGUgaW5wdXRzIGNyZWF0ZWQgYXJlIGluIGlucHV0JGNhcjEsIGlucHV0JGNhcjIsIC4uLg0KICBvdXRwdXQkb3V0IDwtIHJlbmRlclByaW50KHsNCiAgICAjIHJlc3VsdHMNCiAgICByZXMgPC0gdW5saXN0KGxhcHBseSgxOm5yb3cobXljb2VmZi5kZiksIGZ1bmN0aW9uKGkpIGlucHV0W1twYXN0ZTAoImNhciIsIGkpXV0pKQ0KICAgICMgcHJpbnQocmVzKQ0KICAgIGlmIChhbnkocmVzKSkgew0KICAgICAgbXljb2VmZi5kZltteWNvZWZmLmRmIT0iLS0iXSA9ICJYIg0KICAgICAgcmVzMiA9IGFzLmRhdGEuZnJhbWUoY29lZmYuZGZbcmVzLF0pICMgcm93bmFtZXMobXljb2VmZi5kZilbcmVzXSkNCiAgICAgIHByaW50KHJlczIpDQogICAgfQ0KICB9KQ0KfQ0KDQojIGxhdW5jaCBhcHANCnNoaW55QXBwKHVpID0gdWksIHNlcnZlciA9IHNlcnZlcikNCg0KYGBgDQo=