Estimating the number of people whose livelihoods were disrupted or destroyed, attributed to disasters Sub-indicators:
B5a = Hectares of crops affected * average workers per hectare
B5b = Livestock lost * average workers per hectare
Table of Contents
Sub-indicators:
B5a = Hecatares of crops affected * average workers per hectare
B5b = Livestock lost * average workers per hectare
install.packages("raster")
install.packages("rgdal")
library(rgdal)
library(raster)
Select the folder where all the data is stored in subfolders as your working directory
setwd("C:/Users/mduguru/Desktop/SouthAfricaWorkshop/SA/ADP/Data")
create a folder to store your outputs
dir.create("outputs")
step 2 of 4 Data preparation
subset province boundaries to EC
SA_pl<-readOGR("./adm/pl/ZAF_adm1.shp") # select the level of provinces which is adm1
EC<-subset(SA_pl, NAME_1=="Eastern Cape")
plot(SA_pl)

SA_pl
class : SpatialPolygonsDataFrame
features : 9
extent : 16.45189, 32.89125, -34.83514, -22.12503 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
variables : 12
no non-missing arguments, returning NAno non-missing arguments, returning NA
names : ID_0, ISO, NAME_0, ID_1, NAME_1, HASC_1, CCN_1, CCA_1, TYPE_1, ENGTYPE_1, NL_NAME_1, VARNAME_1
min values : 211, ZAF, South Africa, 1, Eastern Cape, ZA.EC, 0, EC, Provinsie, Province, NA, Eastern Transvaal
max values : 211, ZAF, South Africa, 9, Western Cape, ZA.WC, 0, WC, Provinsie, Province, NA, Wes-Kaap
head(SA_pl)
tail(SA_pl)
Eastern Cape
plot(EC)
head(EC)
Write the Eastern Cape subset shapefile product into your output file
# regarding coordinate reference system: the data here is all in
#"+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,"0"
# thus there is no need to reproject the data
writeOGR(lm,"./outputs/lm2016.shp", "lm", driver = "ESRI Shapefile")
clip land cover (LC map) to EC boundaries
# add LC map of the whole SA
SA_LC2014<-raster("./SA_LC2014/sa_lcov_2013-14_gti_geo_wgs84_vs22b.tif")
# crop the raster with the EC shapefile
LC2014c<-crop(SA_LC2014,EC)
LC2014<-mask(LC2014c, EC)
writeRaster(LC2014,"./outputs/LC2014_EC.tif")
plot(LC2014)


Step 2.2 of 5 Resample H2015_250m to 30m
Add the hazard map which is to be resampled
# Add the hazard map which is to be resampled
H2015_250m<-raster("./H2015_250m/2015_2016_droughtThreecl.tif")
# Resample with nearest neighbour method to not loose category values
H2015<-resample(H2015_250m, LC2014,method="ngb")
writeRaster(H2015,"./outputs/2015H_30m.tif")
Agricultural drought Impact map legend Values are discrete

| 0 |
Not affected |
| 1 |
Damaged |
| 2 |
Desroyed |
Step 2.3 of 5 Extract relevant LC from LC2014 (grassland for livestock and cropland for crops)
The values of the classes can be found on the legend and metadata document in the LC map folder
values<-unique(values(LC2014)) # lists the values from LC
values
[1] 0 7 6 5 41 9 3 65 67 66 24 25 40 23 72 32 33 68 12 11 2 1 36 35 52 10
[27] 15 14 13 4 71 70 69 17 16 18 34 63 62 50 49 61 59 48 58 57 51 42 37 38 43 60
[53] 64 46 44 45 47 55 53 54 56 8 22 39
Reclassification of Land cover for only grassland
recl_grassland<-matrix(c(values, c(NA,1,rep(NA,62))), ncol=2)
LC_grassland<-reclassify(LC2014,rcl = recl_grassland)
recl_grassland
[,1] [,2]
[1,] 0 NA
[2,] 7 1
[3,] 6 NA
[4,] 5 NA
[5,] 41 NA
[6,] 9 NA
[7,] 3 NA
[8,] 65 NA
[9,] 67 NA
[10,] 66 NA
[11,] 24 NA
[12,] 25 NA
[13,] 40 NA
[14,] 23 NA
[15,] 72 NA
[16,] 32 NA
[17,] 33 NA
[18,] 68 NA
[19,] 12 NA
[20,] 11 NA
[21,] 2 NA
[22,] 1 NA
[23,] 36 NA
[24,] 35 NA
[25,] 52 NA
[26,] 10 NA
[27,] 15 NA
[28,] 14 NA
[29,] 13 NA
[30,] 4 NA
[31,] 71 NA
[32,] 70 NA
[33,] 69 NA
[34,] 17 NA
[35,] 16 NA
[36,] 18 NA
[37,] 34 NA
[38,] 63 NA
[39,] 62 NA
[40,] 50 NA
[41,] 49 NA
[42,] 61 NA
[43,] 59 NA
[44,] 48 NA
[45,] 58 NA
[46,] 57 NA
[47,] 51 NA
[48,] 42 NA
[49,] 37 NA
[50,] 38 NA
[51,] 43 NA
[52,] 60 NA
[53,] 64 NA
[54,] 46 NA
[55,] 44 NA
[56,] 45 NA
[57,] 47 NA
[58,] 55 NA
[59,] 53 NA
[60,] 54 NA
[61,] 56 NA
[62,] 8 NA
[63,] 22 NA
[64,] 39 NA
Grassland land cover for Livestock

Write the Land cover containing just grassland to the output folder
writeRaster(LC_grassland, "./outputs/LCGrass2014.tif")
All cultivated agricultural land=1, non-agricultural=NA the values 10-31=1
recl_crop<-matrix(c(values, c(rep(NA,10),1,1,NA,1,rep(NA,6),1,1,rep(NA,3),rep(1,4),rep(NA,4),rep(1,3), rep(NA,26),1, NA)), ncol=2)
LC_crop<-reclassify(LC2014, rcl = recl_crop)
Cropland land cover

Write the Land cover containing just crops to the output folder
writeRaster(LC_crop, "./outputs/LCCrop2014.tif")
Step 3 of 5 Processing for Grassland/ Cropland
Step 3a.1 Overlay H2015, LC_grassland and lm to extract statistics
Crop the hazard map to the grassland layer
# crop the hazard map with the grassland layer
HgrassC<- crop(H2015,LC_grassland)
Hgrass<-mask(HgrassC,LC_grassland)
plot(Hgrass)

Write drought impact map file to output folder
writeRaster(Hgrass, "./outputs/H_grass2015.tif", overwrite=TRUE)
Extract raster values to polygons
v<-extract(Hgrass, lm)
Get class counts for each polygon (municipality)
v.counts <- lapply(v,table)
Create a data.frame where missing classes are NA
class.df <- as.data.frame(t(sapply(v.counts,'[',1:length(unique(Hgrass)))))
Add back to polygon data
lm@data <- data.frame(lm@data, class.df)
head(lm@data)
write.csv(lm@data, file = "./outputs/H_grass2015.csv")
Hgrass2015<-lm@data
Local municipality(lm)
plot(lm)

Hgrass2015
Calculating the area for each class in hectares
# multiply to get ha
Hgrass2015$GrassH0area<-Hgrass2015$X0*0.09
Hgrass2015$GrassH1area<-Hgrass2015$X1*0.09
Hgrass2015$GrassH2area<-Hgrass2015$X2*0.09
Hgrass2015
Sum of all grass hectare area H0+H1+H2 = Total grass area
Hgrass2015$GrassTotalArea<-Hgrass2015$GrassH0area+Hgrass2015$GrassH1area+Hgrass2015$GrassH2area
Hgrass2015
Step 3a.2 : Merge extracted statistics with census survey data to calculate population density
Add agriculture dependent population
AgrDepPop<-read.csv("./StatSA/AgrDepPop.csv") # add agr dependent population (which has been created in Excel before!)
AgrDepPop<-subset(AgrDepPop, select=c(ID, MUNICNAME, LSDepPop, CropDepPop))
AgrDepPop
** Merge the two sets by MUNICNAME**
GrassDepPop = merge(Hgrass2015,AgrDepPop, by ="MUNICNAME")
GrassDepPop<-subset(GrassDepPop, select= c(MUNICNAME, GrassH0area, GrassH1area,GrassH2area, ID, GrassTotalArea, LSDepPop ))
LS dependent population density
GrassDepPop$LSPopDens<-GrassDepPop$LSDepPop/GrassDepPop$GrassTotalArea
GrassDepPop
Step 4a of 5 drought impact classes for grassland
Step 4a.1 of 5 Calculate affected population per drought impact class
# LS Dependent population in H0
GrassDepPop$LSPopH0<-GrassDepPop$LSPopDens*GrassDepPop$GrassH0area
# LS Dependent population in H1
GrassDepPop$LSPopH1<-GrassDepPop$LSPopDens*GrassDepPop$GrassH1area
# LS Dependent population in H2
GrassDepPop$LSPopH2<-GrassDepPop$LSPopDens*GrassDepPop$GrassH2area
Calculate the shares of pop in drought impact class/ total population for grassland
GrassDepPop$ShareLSPopH0<-GrassDepPop$LSPopH0/GrassDepPop$LSDepPop
GrassDepPop$ShareLSPopH1<-GrassDepPop$LSPopH1/GrassDepPop$LSDepPop
GrassDepPop$ShareLSPopH2<-GrassDepPop$LSPopH2/GrassDepPop$LSDepPop
GrassDepPop
Step 4a.2 of 5 Calculate total affected population for grassland damaged (H1) and destroyed (H2)
Affected population (H1+H2)
GrassDepPop$LSPopAff<-GrassDepPop$LSPopH1+GrassDepPop$LSPopH2
Calculate share of total affected pop (h1+h2)
GrassDepPop$ShareLSPopAff<-GrassDepPop$LSPopAff/GrassDepPop$LSDepPop
####### or ######
GrassDepPop$ShareLSPopAff<-GrassDepPop$ShareLSPopH1+GrassDepPop$ShareLSPopH2
GrassDepPop
Write the csv for the affected livestock dependent population (affLSPop2015.csv) to output file
write.csv(GrassDepPop,"./outputs/affLSPop2015.csv")
Step 3b.1. Overlay drought impact map with crop land cover(H2015LC_cropland) with local municipality (lm) to extract statistics
Add local municipality boundaries again, so that results from grassland analysis are removed
lm<-shapefile("./outputs/lm2016.shp")
Eastern Cape local municipalities

class : SpatialPolygonsDataFrame
features : 33
extent : 22.73574, 30.19472, -34.21386, -30.0018 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
variables : 13
names : OBJECTID, PROVINCE, CATEGORY, CAT2, CAT_B, MUNICNAME, NAMECODE, MAP_TITLE, DISTRICT, DISTRICT_N, Shape_STAr, Shape_STLe, F2
min values : 1, EC, A, Local Municipality, BUF, Amahlathi, Amahlathi (EC124), Amahlathi Local Municipality, BUF, Alfred Nzo, 0.1226250, 2.393968, Amahlathi Local Municipality (EC124)
max values : 9, EC, B, Metropolitan Municipality, NMA, Walter Sisulu, Walter Sisulu (EC145), Walter Sisulu Local Municipality, NMA, O.R.Tambo, 2.7599461, 11.466761, Walter Sisulu Local Municipality (EC145)
HcropC<- crop(H2015,LC_crop)
Hcrop<-mask(HcropC,LC_crop)
writeRaster(Hcrop, "./outputs/H_crop2015.tif", overwrite=TRUE)
Extract pixels by class per municipality
v<-extract(Hcrop, lm) #Extract raster values to polygons
v.counts <- lapply(v,table) # Get class counts for each polygon
Create a data.frame where missing classes are NA
class.df <- as.data.frame(t(sapply(v.counts,'[',1:length(unique(Hcrop)))))
Add pixel count back to polygon data per municipality
lm@data <- data.frame(lm@data, class.df)# Add back to polygon data
head(lm@data)
write.csv(lm@data, file = "./outputs/H_crop2015.csv")
Hcrop2015<-lm@data
Hcrop2015<-read.csv("./outputs/H_crop2015.csv")
Subset pixel counts for classes and compute the hectares in each class by multiplying by 0.09
Hcrop2015<-subset(Hcrop2015, select = c(OBJECTID,MUNICNAME,X0, X1, X2))
Hcrop2015
multiply to get ha
Hcrop2015$CropH0area<-Hcrop2015$X0*0.09
Hcrop2015$CropH1area<-Hcrop2015$X1*0.09
Hcrop2015$CropH2area<-Hcrop2015$X2*0.09
Hcrop2015
Total crop area estimation
Hcrop2015$CropTotalArea<-Hcrop2015$CropH0area+Hcrop2015$CropH1area+Hcrop2015$CropH2area
Step 3b.3: Merge extracted statistics with census survey data to calculate population density
Merge the two sets by MUNICNAME
CropDepPop = merge(Hcrop2015,AgrDepPop, by ="MUNICNAME")
CropDepPop
Subset crop required columns
CropDepPop<-subset(CropDepPop, select= c(MUNICNAME, CropH0area, CropH1area,CropH2area, ID, CropTotalArea, CropDepPop ))
CropDepPop
Crop dependent population density
CropDepPop$CropPopDens<-CropDepPop$CropDepPop/CropDepPop$CropTotalArea
CropDepPop
Step 4b of 5 drought impact classes for cropland
Step 4b.1 of 5 Calculate affected population per drought impact class
# crop Dependent population in H0
CropDepPop$CropPopH0<-CropDepPop$CropPopDens*CropDepPop$CropH0area
# crop Dependent population in H1
CropDepPop$CropPopH1<-CropDepPop$CropPopDens*CropDepPop$CropH1area
# crop Dependent population in H2
CropDepPop$CropPopH2<-CropDepPop$CropPopDens*CropDepPop$CropH2area
Calculate the shares of pop in drought impact class/ total population for cropland
CropDepPop$ShareCropPopH0<-CropDepPop$CropPopH0/CropDepPop$CropDepPop
CropDepPop$ShareCropPopH1<-CropDepPop$CropPopH1/CropDepPop$CropDepPop
CropDepPop$ShareCropPopH2<-CropDepPop$CropPopH2/CropDepPop$CropDepPop
CropDepPop
Step 4b.2 of 5 Calculate total affected population for cropland damaged (H1) and destroyed (H2)
Affected population (H1+H2)
CropDepPop$CropPopAff<-CropDepPop$CropPopH1+CropDepPop$CropPopH2
Calculate share of total affected pop (h1+h2)
CropDepPop$ShareCropPopAff<-CropDepPop$CropPopAff/CropDepPop$CropDepPop
####### or ######
CropDepPop$ShareCropPopAff<-CropDepPop$ShareCropPopH1+CropDepPop$ShareCropPopH2
CropDepPop
Write the csv for the affected crop dependent population (affCropPop2015.csv) to output file
write.csv(CropDepPop,"./outputs/affCropPop2015.csv")
Step 5 of 5 calculate total affected population
Merge the two datasets
affPop2015<-merge(CropDepPop,GrassDepPop, by="MUNICNAME")
affPop2015$affPop<-affPop2015$CropPopAff+affPop2015$LSPopAff
affPop2015$ShareaffPop<-affPop2015$affPop/(affPop2015$CropDepPop+affPop2015$LSDepPop)
affPop2015
write.csv(affPop2015,"./outputs/affPop2015.csv")
*** Additionaly: If you want to have a shapefile with these information, the output can be merged with the local municipality (lm) shapefile ***
lm<-shapefile("./outputs/lm2016.shp")
m<-merge(lm, affPop2015, by="MUNICNAME")
writeOGR(m,"./outputs/affPop2015.shp", "affPop2015", driver = "ESRI Shapefile" )
LS0tDQp0aXRsZTogIiINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCmBgYHtyICJzZXR1cCIsIGluY2x1ZGU9RkFMU0V9DQpyZXF1aXJlKCJrbml0ciIpDQpvcHRzX2tuaXQkc2V0KHJvb3QuZGlyID0gIkM6L1VzZXJzL21kdWd1cnUvRGVza3RvcC9Tb3V0aEFmcmljYVdvcmtzaG9wL1NBL0FEUC9EYXRhIikNCmBgYA0KDQoqKkVzdGltYXRpbmcgdGhlIG51bWJlciBvZiBwZW9wbGUgd2hvc2UgbGl2ZWxpaG9vZHMgd2VyZSBkaXNydXB0ZWQgb3IgZGVzdHJveWVkLCBhdHRyaWJ1dGVkIHRvIGRpc2FzdGVycyoqDQoqKipTdWItaW5kaWNhdG9yczogKioqDQoNCioqKkI1YSA9IEhlY3RhcmVzIG9mIGNyb3BzIGFmZmVjdGVkKioqICogKioqYXZlcmFnZSB3b3JrZXJzIHBlciBoZWN0YXJlICoqKg0KDQoqKipCNWIgPSBMaXZlc3RvY2sgbG9zdCoqKiAgKiAqKiphdmVyYWdlIHdvcmtlcnMgcGVyIGhlY3RhcmUqKioNCg0KDQoNCiMjIyMgKipUYWJsZSBvZiBDb250ZW50cyoqDQojIyMjIFtQYXJ0LiBDXSgjUGFydGMpDQojIyMjIyMgW1N0ZXAgMCBvZiA1IFRlY2huaWNhbCBHdWlkYW5jZSBTdWItaW5kaWNhdG9yXSgjMCkNCiMjIyMjIyBbU3RlcCAxIG9mIDUgSW5zdGFsbGluZyByZXF1aXJlZCBwYWNrYWdlcyBhbmQgY3JlYXRpbmcgZGlyZWN0b3JpZXNdKCMxKQ0KIyMjIyMjIFtzdGVwIDIgb2YgNSBEYXRhIHByZXBhcmF0aW9uXSgjMikNCiMjIyMjIyBbc3RlcCAyLjEgb2YgNSBTdWJzZXQgb2YgYWRtaW5pc3RyYXRpdmUgYm91bmRhcmllcyBhbmQgbGFuZCBjb3ZlciBtYXAgKExDIG1hcCldKCMyLjEpDQojIyMjIyMgW1N0ZXAgMi4yIG9mIDUgUmVzYW1wbGUgSDIwMTVfMjUwbSB0byAzMG0gXSgjMi4yKQ0KIyMjIyMjIFtTdGVwIDIuMyBvZiA1IEV4dHJhY3QgcmVsZXZhbnQgTEMgZnJvbSBMQzIwMTQgKGdyYXNzbGFuZCBmb3IgbGl2ZXN0b2NrIGFuZCBjcm9wbGFuZCBmb3IgY3JvcHMpXSgjMi4zKQ0KIyMjIyBbUGFydC4gRF0oI1BhcnRkKQ0KIyMjIyMjIFtTdGVwIDNhIG9mIDUgIFByb2Nlc3NpbmcgZm9yIEdyYXNzbGFuZF0oIzNhKQ0KIyMjIyMjIFtTdGVwIDNhLjEgT3ZlcmxheSBIMjAxNSwgTENfZ3Jhc3NsYW5kIGFuZCBsbSB0byBleHRyYWN0IHN0YXRpc3RpY3NdKCMzYS4xKQ0KIyMjIyMjIFtTdGVwIDNhLjIgOiBNZXJnZSBleHRyYWN0ZWQgc3RhdGlzdGljcyB3aXRoIGNlbnN1cyBzdXJ2ZXkgZGF0YSB0byBjYWxjdWxhdGUgcG9wdWxhdGlvbiBkZW5zaXR5XSgjM2EuMikNCiMjIyMjIyBbU3RlcCA0YSBvZiA1IGhhemFyZCBjbGFzc2VzIGZvciBncmFzc2xhbmRdKCM0YSkNCiMjIyMjIyBbU3RlcCA0YS4xIG9mIDUgaGF6YXJkIGNsYXNzZXMgZm9yIGdyYXNzbGFuZF0oIzRhLjEpDQojIyMjIyMgW1N0ZXAgNGEuMiBvZiA1IENhbGN1bGF0ZSB0b3RhbCBhZmZlY3RlZCBwb3B1bGF0aW9uIGZvciBncmFzc2xhbmQgZGFtYWdlZCAoSDEpIG9yIGRlc3Ryb3llZCAoSDIpXSgjNGEuMikNCiMjIyMjIyBbU3RlcCAzYi4xIG9mIDUgT3ZlcmxheSBkcm91Z2h0IGltcGFjdCBtYXAgd2l0aCBjcm9wIGxhbmQgY292ZXIoSDIwMTVMQ19jcm9wbGFuZCkgd2l0aCBsb2NhbCBtdW5pY2lwYWxpdHkgKGxtKSB0byBleHRyYWN0IHN0YXRpc3RpY3NdKCMzYi4xKQ0KIyMjIyMjIFtTdGVwIDNiLjI6IE1lcmdlIGV4dHJhY3RlZCBzdGF0aXN0aWNzIHdpdGggY2Vuc3VzIHN1cnZleSBkYXRhIHRvIGNhbGN1bGF0ZSBwb3B1bGF0aW9uIGRlbnNpdHldKCMzYi4yKQ0KDQojIyMjIyMNCiMjIyMjIyBbU3RlcCA0YiBvZiA1IGRyb3VnaHQgaW1wYWN0IGNsYXNzZXMgZm9yIGNyb3BsYW5kXSgjNGIpDQojIyMjIyMgW1N0ZXAgNGIuMSBvZiA1IENhbGN1bGF0ZSBhZmZlY3RlZCBwb3B1bGF0aW9uIHBlciBkcm91Z2h0IGltcGFjdCBjbGFzc10oIzRiLjEpDQojIyMjIyMgW1N0ZXAgNGIuMiBvZiA1IENhbGN1bGF0ZSB0b3RhbCBhZmZlY3RlZCBwb3B1bGF0aW9uIGZvciBjcm9wbGFuZCBkYW1hZ2VkIChIMSkgYW5kIGRlc3Ryb3llZCAoSDIpXSgjNGIuMikNCiMjIyMjIyBbIFN0ZXAgNSBvZiA1IGNhbGN1bGF0ZSB0b3RhbCBhZmZlY3RlZCBwb3B1bGF0aW9uXSgjNSkNCioqKioqKg0KDQojIyMjIFtQYXJ0LiBDXSgjKXtuYW1lPVBhcnRjfQ0KKioqKioqDQoNCg0KKioqKioqDQo+ICMjIyMjIFtTdGVwIDAgb2YgNCBUZWNobmljYWwgR3VpZGFuY2UgU3ViLWluZGljYXRvciBdKCMpe25hbWU9MH0gDQoNCioqKioqKg0KKioqU3ViLWluZGljYXRvcnM6ICoqKg0KDQpCNWEgPSBIZWNhdGFyZXMgb2YgY3JvcHMgYWZmZWN0ZWQgKiBhdmVyYWdlIHdvcmtlcnMgcGVyIGhlY3RhcmUNCg0KQjViID0gTGl2ZXN0b2NrIGxvc3QgICogYXZlcmFnZSB3b3JrZXJzIHBlciBoZWN0YXJlDQoNCioqKioNCj4jIyMjIyBbU2VwIDEgb2YgNSBJbnN0YWxsaW5nIHJlcXVpcmVkIHBhY2thZ2VzIGFuZCBjcmVhdGluZyBkaXJlY3Rvcmllc10oIyl7bmFtZT0xfQ0KDQoqKioqDQoNCmBgYHtyIGV2YWw9RkFMU0V9DQoNCmluc3RhbGwucGFja2FnZXMoInJhc3RlciIpDQppbnN0YWxsLnBhY2thZ2VzKCJyZ2RhbCIpDQoNCmBgYA0KDQpgYGB7ciwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCg0KbGlicmFyeShyZ2RhbCkNCmxpYnJhcnkocmFzdGVyKQ0KDQpgYGANCg0KU2VsZWN0IHRoZSBmb2xkZXIgd2hlcmUgYWxsIHRoZSBkYXRhIGlzIHN0b3JlZCBpbiBzdWJmb2xkZXJzIGFzIHlvdXIgd29ya2luZyBkaXJlY3RvcnkNCg0KYGBge3IgZXZhbD1GQUxTRX0NCnNldHdkKCJDOi9Vc2Vycy9tZHVndXJ1L0Rlc2t0b3AvU291dGhBZnJpY2FXb3Jrc2hvcC9TQS9BRFAvRGF0YSIpDQpgYGANCmNyZWF0ZSBhIGZvbGRlciB0byBzdG9yZSB5b3VyIG91dHB1dHMNCg0KYGBge3IgZXZhbD1UUlVFfQ0KDQpkaXIuY3JlYXRlKCJvdXRwdXRzIikNCg0KDQpgYGANCg0KKioqKg0KPltzdGVwIDIgb2YgNCBEYXRhIHByZXBhcmF0aW9uXSgjKXtuYW1lPTJ9DQoNCioqKioNCioqKioNCj4gIyMjIyMgW1N0ZXAgMi4xIG9mIDUgU3Vic2V0IG9mIGFkbWluaXN0cmF0aXZlIGJvdW5kYXJpZXMgYW5kIGxhbmQgY292ZXIgbWFwIChMQyBtYXApXSgjKXtuYW1lPTIuMX0NCg0KKioqKg0KPGJyPg0Kc3Vic2V0IHByb3ZpbmNlIGJvdW5kYXJpZXMgdG8gRUMNCmBgYHtyIGV2YWw9RkFMU0V9DQpTQV9wbDwtcmVhZE9HUigiLi9hZG0vcGwvWkFGX2FkbTEuc2hwIikgIyBzZWxlY3QgdGhlIGxldmVsIG9mIHByb3ZpbmNlcyB3aGljaCBpcyBhZG0xDQpFQzwtc3Vic2V0KFNBX3BsLCBOQU1FXzE9PSJFYXN0ZXJuIENhcGUiKQ0KDQpgYGANCmBgYHtyfQ0KcGxvdChTQV9wbCkNCg0KYGBgDQoNCg0KYGBge3J9DQpTQV9wbA0KYGBgDQoNCmBgYHtyfQ0KaGVhZChTQV9wbCkNCnRhaWwoU0FfcGwpDQpgYGANCjxicj4NCioqRWFzdGVybiBDYXBlKioNCmBgYHtyfQ0KcGxvdChFQykNCg0KYGBgDQpgYGB7cn0NCmhlYWQoRUMpDQoNCmBgYA0KPGJyPg0KV3JpdGUgdGhlIEVhc3Rlcm4gQ2FwZSBzdWJzZXQgc2hhcGVmaWxlIHByb2R1Y3QgaW50byB5b3VyIG91dHB1dCBmaWxlDQpgYGB7ciBldmFsPUZBTFNFfQ0KIyByZWdhcmRpbmcgY29vcmRpbmF0ZSByZWZlcmVuY2Ugc3lzdGVtOiB0aGUgZGF0YSBoZXJlIGlzIGFsbCBpbg0KIyIrcHJvaj1sb25nbGF0ICtkYXR1bT1XR1M4NCArbm9fZGVmcyArZWxscHM9V0dTODQgK3Rvd2dzODQ9MCwwLCIwIiANCiMgdGh1cyB0aGVyZSBpcyBubyBuZWVkIHRvIHJlcHJvamVjdCB0aGUgZGF0YQ0KDQp3cml0ZU9HUihsbSwiLi9vdXRwdXRzL2xtMjAxNi5zaHAiLCAibG0iLCBkcml2ZXIgPSAiRVNSSSBTaGFwZWZpbGUiKQ0KYGBgDQoNCjxicj4NCg0KY2xpcCBsYW5kIGNvdmVyIChMQyBtYXApIHRvIEVDIGJvdW5kYXJpZXMgDQpgYGB7ciBldmFsPUZBTFNFfQ0KIyBhZGQgTEMgbWFwIG9mIHRoZSB3aG9sZSBTQQ0KU0FfTEMyMDE0PC1yYXN0ZXIoIi4vU0FfTEMyMDE0L3NhX2xjb3ZfMjAxMy0xNF9ndGlfZ2VvX3dnczg0X3ZzMjJiLnRpZiIpIA0KYGBgDQoNCmBgYHtyIGV2YWw9RkFMU0V9DQojIGNyb3AgdGhlIHJhc3RlciB3aXRoIHRoZSBFQyBzaGFwZWZpbGUNCkxDMjAxNGM8LWNyb3AoU0FfTEMyMDE0LEVDKSANCkxDMjAxNDwtbWFzayhMQzIwMTRjLCBFQykNCndyaXRlUmFzdGVyKExDMjAxNCwiLi9vdXRwdXRzL0xDMjAxNF9FQy50aWYiKQ0KYGBgDQoNCmBgYHtyfQ0KcGxvdChMQzIwMTQpIA0KYGBgDQoNCiFbXShDOi9Vc2Vycy9tZHVndXJ1L0Rlc2t0b3AvU291dGhBZnJpY2FXb3Jrc2hvcC9TQS9BRFAvRGF0YS9TQV9MQzIwMTQvUmVwb3J0X01ldGFkYXRhL0xDLnBuZykNCg0KKioqKg0KPiBbU3RlcCAyLjIgb2YgNSBSZXNhbXBsZSBIMjAxNV8yNTBtIHRvIDMwbSBdKCMpe25hbWU9Mi4yfQ0KDQoqKioqDQoNCioqQWRkIHRoZSBoYXphcmQgbWFwIHdoaWNoIGlzIHRvIGJlIHJlc2FtcGxlZCoqDQpgYGB7ciBldmFsPUZBTFNFfQ0KIyBBZGQgdGhlIGhhemFyZCBtYXAgd2hpY2ggaXMgdG8gYmUgcmVzYW1wbGVkDQpIMjAxNV8yNTBtPC1yYXN0ZXIoIi4vSDIwMTVfMjUwbS8yMDE1XzIwMTZfZHJvdWdodFRocmVlY2wudGlmIikgDQojIFJlc2FtcGxlIHdpdGggbmVhcmVzdCBuZWlnaGJvdXIgbWV0aG9kIHRvIG5vdCBsb29zZSBjYXRlZ29yeSB2YWx1ZXMNCkgyMDE1PC1yZXNhbXBsZShIMjAxNV8yNTBtLCBMQzIwMTQsbWV0aG9kPSJuZ2IiKSANCndyaXRlUmFzdGVyKEgyMDE1LCIuL291dHB1dHMvMjAxNUhfMzBtLnRpZiIpDQoNCmBgYA0KDQoqKipBZ3JpY3VsdHVyYWwgZHJvdWdodCAgSW1wYWN0IG1hcCBsZWdlbmQgVmFsdWVzIGFyZSBkaXNjcmV0ZSoqKg0KYGBge3IgZWNobz1GQUxTRX0NCnBsb3QoSDIwMTUpDQpgYGANCg0KPGJyPg0KDQoNCk1hcCBWYWx1ZSB8Q2xhc3MNCi0tLS0tLS0tLS18LS0tLS0tDQowICAgICAgICAgfE5vdCBhZmZlY3RlZCANCjEgICAgICAgICB8RGFtYWdlZCANCjIgICAgICAgICB8RGVzcm95ZWQNCg0KKioqKg0KPiBbU3RlcCAyLjMgb2YgNSBFeHRyYWN0IHJlbGV2YW50IExDIGZyb20gTEMyMDE0IChncmFzc2xhbmQgZm9yIGxpdmVzdG9jayBhbmQgY3JvcGxhbmQgZm9yIGNyb3BzKV0oMyl7bmFtZT0yLjN9DQoNCioqKioNCg0KKioqVGhlIHZhbHVlcyBvZiB0aGUgY2xhc3NlcyBjYW4gYmUgZm91bmQgb24gdGhlIGxlZ2VuZCBhbmQgbWV0YWRhdGEgZG9jdW1lbnQgaW4gdGhlIExDIG1hcCBmb2xkZXIqKioNCg0KYGBge3IgZXZhbD1GQUxTRX0NCnZhbHVlczwtdW5pcXVlKHZhbHVlcyhMQzIwMTQpKSAjIGxpc3RzIHRoZSB2YWx1ZXMgZnJvbSBMQw0KYGBgDQoNCmBgYHtyfQ0KdmFsdWVzDQpgYGANCg0KPGJyPg0KKioqUmVjbGFzc2lmaWNhdGlvbiBvZiBMYW5kIGNvdmVyIGZvciBvbmx5IGdyYXNzbGFuZCoqKg0KYGBge3IgZXZhbD1GQUxTRX0NCnJlY2xfZ3Jhc3NsYW5kPC1tYXRyaXgoYyh2YWx1ZXMsIGMoTkEsMSxyZXAoTkEsNjIpKSksIG5jb2w9MikNCkxDX2dyYXNzbGFuZDwtcmVjbGFzc2lmeShMQzIwMTQscmNsID0gcmVjbF9ncmFzc2xhbmQpDQpgYGANCmBgYHtyfQ0KcmVjbF9ncmFzc2xhbmQNCg0KYGBgDQoNCjxicj4NCg0KKioqR3Jhc3NsYW5kIGxhbmQgY292ZXIgZm9yIExpdmVzdG9jayoqKg0KYGBge3IgZWNobz1GQUxTRX0NCnBsb3QoTENfZ3Jhc3NsYW5kLCBsZWdlbmQ9RikNCmBgYA0KDQo8YnI+DQoNCipXcml0ZSB0aGUgTGFuZCBjb3ZlciBjb250YWluaW5nIGp1c3QgZ3Jhc3NsYW5kIHRvIHRoZSBvdXRwdXQgZm9sZGVyKg0KYGBge3IgZXZhbD1GQUxTRX0NCndyaXRlUmFzdGVyKExDX2dyYXNzbGFuZCwgIi4vb3V0cHV0cy9MQ0dyYXNzMjAxNC50aWYiKQ0KYGBgDQoNCioqKkFsbCBjdWx0aXZhdGVkIGFncmljdWx0dXJhbCBsYW5kPTEsIG5vbi1hZ3JpY3VsdHVyYWw9TkEgdGhlIHZhbHVlcyAxMC0zMT0xKioqDQpgYGB7ciBldmFsPUZBTFNFfQ0KcmVjbF9jcm9wPC1tYXRyaXgoYyh2YWx1ZXMsIGMocmVwKE5BLDEwKSwxLDEsTkEsMSxyZXAoTkEsNiksMSwxLHJlcChOQSwzKSxyZXAoMSw0KSxyZXAoTkEsNCkscmVwKDEsMyksIHJlcChOQSwyNiksMSwgTkEpKSwgbmNvbD0yKQ0KTENfY3JvcDwtcmVjbGFzc2lmeShMQzIwMTQsIHJjbCA9IHJlY2xfY3JvcCkNCmBgYCANCg0KPGJyPg0KDQoqKipDcm9wbGFuZCBsYW5kIGNvdmVyICoqKg0KYGBge3IgZWNobz1GQUxTRX0NCnBsb3QoTENfY3JvcCxsZWdlbmQ9RikNCmBgYA0KKldyaXRlIHRoZSBMYW5kIGNvdmVyIGNvbnRhaW5pbmcganVzdCBjcm9wcyB0byB0aGUgb3V0cHV0IGZvbGRlcioNCmBgYHtyIGV2YWw9RkFMU0V9DQp3cml0ZVJhc3RlcihMQ19jcm9wLCAiLi9vdXRwdXRzL0xDQ3JvcDIwMTQudGlmIikNCmBgYA0KDQojIyMjIFtQYXJ0LiBEXSgjKXtuYW1lPVBhcnRkfQ0KDQoqKioNCj4gW1N0ZXAgMyBvZiA1ICBQcm9jZXNzaW5nIGZvciBHcmFzc2xhbmQvIENyb3BsYW5kXSgjKXtuYW1lPTNhfQ0KDQoqKioNCioqKg0KPiBbU3RlcCAzYS4xIE92ZXJsYXkgSDIwMTUsIExDX2dyYXNzbGFuZCBhbmQgbG0gdG8gZXh0cmFjdCBzdGF0aXN0aWNzXSgjKXtuYW1lPTNhLjF9DQoNCioqKg0KKipDcm9wIHRoZSBoYXphcmQgbWFwIHRvIHRoZSBncmFzc2xhbmQgbGF5ZXIqKg0KYGBge3IgZXZhbD1GQUxTRX0NCiMgY3JvcCB0aGUgaGF6YXJkIG1hcCB3aXRoIHRoZSBncmFzc2xhbmQgbGF5ZXINCkhncmFzc0M8LSBjcm9wKEgyMDE1LExDX2dyYXNzbGFuZCkgIA0KSGdyYXNzPC1tYXNrKEhncmFzc0MsTENfZ3Jhc3NsYW5kKQ0KYGBgDQpgYGB7cn0NCnBsb3QoSGdyYXNzKQ0KYGBgDQoNCjxicj4NCipXcml0ZSBkcm91Z2h0IGltcGFjdCBtYXAgZmlsZSB0byBvdXRwdXQgZm9sZGVyKg0KDQpgYGB7ciBldmFsPUZBTFNFfQ0Kd3JpdGVSYXN0ZXIoSGdyYXNzLCAiLi9vdXRwdXRzL0hfZ3Jhc3MyMDE1LnRpZiIsIG92ZXJ3cml0ZT1UUlVFKQ0KYGBgDQoNCioqRXh0cmFjdCByYXN0ZXIgdmFsdWVzIHRvIHBvbHlnb25zKioNCg0KYGBge3IgZXZhbD1GQUxTRX0NCnY8LWV4dHJhY3QoSGdyYXNzLCBsbSkNCmBgYA0KDQoqKkdldCBjbGFzcyBjb3VudHMgZm9yIGVhY2ggcG9seWdvbiAobXVuaWNpcGFsaXR5KSoqDQpgYGB7ciBldmFsPUZBTFNFfQ0Kdi5jb3VudHMgPC0gbGFwcGx5KHYsdGFibGUpDQpgYGANCioqQ3JlYXRlIGEgZGF0YS5mcmFtZSB3aGVyZSBtaXNzaW5nIGNsYXNzZXMgYXJlIE5BKioNCg0KYGBge3J9DQpjbGFzcy5kZiA8LSBhcy5kYXRhLmZyYW1lKHQoc2FwcGx5KHYuY291bnRzLCdbJywxOmxlbmd0aCh1bmlxdWUoSGdyYXNzKSkpKSkNCmBgYA0KPGJyPg0KKipBZGQgYmFjayB0byBwb2x5Z29uIGRhdGEqKg0KDQpgYGB7ciBldmFsPUZBTFNFfQ0KbG1AZGF0YSA8LSBkYXRhLmZyYW1lKGxtQGRhdGEsIGNsYXNzLmRmKQ0KaGVhZChsbUBkYXRhKQ0Kd3JpdGUuY3N2KGxtQGRhdGEsIGZpbGUgPSAiLi9vdXRwdXRzL0hfZ3Jhc3MyMDE1LmNzdiIpDQpIZ3Jhc3MyMDE1PC1sbUBkYXRhDQoNCmBgYA0KKipMb2NhbCBtdW5pY2lwYWxpdHkobG0pKioNCmBgYHtyfQ0KcGxvdChsbSkNCmBgYA0KDQpgYGB7cn0NCkhncmFzczIwMTU8LXN1YnNldChIZ3Jhc3MyMDE1LCBzZWxlY3QgPSBjKE9CSkVDVElELE1VTklDTkFNRSxYMCwgWDEsIFgyKSkNCg0KSGdyYXNzMjAxNQ0KYGBgDQoNCjxicj4NCg0KKioqQ2FsY3VsYXRpbmcgdGhlIGFyZWEgZm9yIGVhY2ggY2xhc3MgaW4gaGVjdGFyZXMgKioqDQpgYGB7cn0NCiMgbXVsdGlwbHkgdG8gZ2V0IGhhDQpIZ3Jhc3MyMDE1JEdyYXNzSDBhcmVhPC1IZ3Jhc3MyMDE1JFgwKjAuMDkgDQpIZ3Jhc3MyMDE1JEdyYXNzSDFhcmVhPC1IZ3Jhc3MyMDE1JFgxKjAuMDkNCkhncmFzczIwMTUkR3Jhc3NIMmFyZWE8LUhncmFzczIwMTUkWDIqMC4wOQ0KSGdyYXNzMjAxNQ0KYGBgDQo8YnI+DQoNCioqU3VtIG9mIGFsbCBncmFzcyBoZWN0YXJlIGFyZWEgSDArSDErSDIgPSBUb3RhbCBncmFzcyBhcmVhICoqDQpgYGB7cn0NCkhncmFzczIwMTUkR3Jhc3NUb3RhbEFyZWE8LUhncmFzczIwMTUkR3Jhc3NIMGFyZWErSGdyYXNzMjAxNSRHcmFzc0gxYXJlYStIZ3Jhc3MyMDE1JEdyYXNzSDJhcmVhDQpIZ3Jhc3MyMDE1DQpgYGANCg0KKioqDQo+IFtTdGVwIDNhLjIgOiBNZXJnZSBleHRyYWN0ZWQgc3RhdGlzdGljcyB3aXRoIGNlbnN1cyBzdXJ2ZXkgZGF0YSB0byBjYWxjdWxhdGUgcG9wdWxhdGlvbiBkZW5zaXR5XSgjKXtuYW1lPTNhLjJ9DQoNCioqKioNCioqQWRkIGFncmljdWx0dXJlIGRlcGVuZGVudCBwb3B1bGF0aW9uKioNCmBgYHtyIGV2YWw9RkFMU0V9DQpBZ3JEZXBQb3A8LXJlYWQuY3N2KCIuL1N0YXRTQS9BZ3JEZXBQb3AuY3N2IikgIyBhZGQgYWdyIGRlcGVuZGVudCBwb3B1bGF0aW9uICh3aGljaCBoYXMgYmVlbiBjcmVhdGVkIGluIEV4Y2VsIGJlZm9yZSEpDQpBZ3JEZXBQb3A8LXN1YnNldChBZ3JEZXBQb3AsIHNlbGVjdD1jKElELCBNVU5JQ05BTUUsIExTRGVwUG9wLCBDcm9wRGVwUG9wKSkNCg0KYGBgDQoNCmBgYHtyfQ0KQWdyRGVwUG9wDQpgYGANCioqIE1lcmdlIHRoZSB0d28gc2V0cyBieSBNVU5JQ05BTUUqKg0KYGBge3J9DQpHcmFzc0RlcFBvcCA9IG1lcmdlKEhncmFzczIwMTUsQWdyRGVwUG9wLCBieSA9Ik1VTklDTkFNRSIpICANCkdyYXNzRGVwUG9wPC1zdWJzZXQoR3Jhc3NEZXBQb3AsIHNlbGVjdD0gYyhNVU5JQ05BTUUsIEdyYXNzSDBhcmVhLCBHcmFzc0gxYXJlYSxHcmFzc0gyYXJlYSwgSUQsIEdyYXNzVG90YWxBcmVhLCBMU0RlcFBvcCApKQ0KDQpgYGANCg0KKipMUyBkZXBlbmRlbnQgcG9wdWxhdGlvbiBkZW5zaXR5ICoqDQpgYGB7cn0NCkdyYXNzRGVwUG9wJExTUG9wRGVuczwtR3Jhc3NEZXBQb3AkTFNEZXBQb3AvR3Jhc3NEZXBQb3AkR3Jhc3NUb3RhbEFyZWENCkdyYXNzRGVwUG9wDQpgYGANCjxicj4NCg0KKioqKg0KPiBbU3RlcCA0YSBvZiA1IGRyb3VnaHQgaW1wYWN0IGNsYXNzZXMgZm9yIGdyYXNzbGFuZF0oIyl7bmFtZT00YX0NCg0KKioqDQoNCioqKg0KPiBbU3RlcCA0YS4xIG9mIDUgQ2FsY3VsYXRlIGFmZmVjdGVkIHBvcHVsYXRpb24gcGVyIGRyb3VnaHQgaW1wYWN0IGNsYXNzXSgjKXtuYW1lPTRhLjF9DQoNCioqKg0KYGBge3J9DQojIExTIERlcGVuZGVudCBwb3B1bGF0aW9uIGluIEgwIA0KR3Jhc3NEZXBQb3AkTFNQb3BIMDwtR3Jhc3NEZXBQb3AkTFNQb3BEZW5zKkdyYXNzRGVwUG9wJEdyYXNzSDBhcmVhIA0KIyBMUyBEZXBlbmRlbnQgcG9wdWxhdGlvbiBpbiBIMQ0KR3Jhc3NEZXBQb3AkTFNQb3BIMTwtR3Jhc3NEZXBQb3AkTFNQb3BEZW5zKkdyYXNzRGVwUG9wJEdyYXNzSDFhcmVhIA0KIyBMUyBEZXBlbmRlbnQgcG9wdWxhdGlvbiBpbiBIMg0KR3Jhc3NEZXBQb3AkTFNQb3BIMjwtR3Jhc3NEZXBQb3AkTFNQb3BEZW5zKkdyYXNzRGVwUG9wJEdyYXNzSDJhcmVhIA0KDQpgYGANCg0KKipDYWxjdWxhdGUgdGhlIHNoYXJlcyBvZiBwb3AgaW4gZHJvdWdodCBpbXBhY3QgY2xhc3MvIHRvdGFsIHBvcHVsYXRpb24gZm9yIGdyYXNzbGFuZCoqDQoNCmBgYHtyfQ0KR3Jhc3NEZXBQb3AkU2hhcmVMU1BvcEgwPC1HcmFzc0RlcFBvcCRMU1BvcEgwL0dyYXNzRGVwUG9wJExTRGVwUG9wDQpHcmFzc0RlcFBvcCRTaGFyZUxTUG9wSDE8LUdyYXNzRGVwUG9wJExTUG9wSDEvR3Jhc3NEZXBQb3AkTFNEZXBQb3ANCkdyYXNzRGVwUG9wJFNoYXJlTFNQb3BIMjwtR3Jhc3NEZXBQb3AkTFNQb3BIMi9HcmFzc0RlcFBvcCRMU0RlcFBvcA0KR3Jhc3NEZXBQb3ANCmBgYA0KKioqKg0KPiBbU3RlcCA0YS4yIG9mIDUgQ2FsY3VsYXRlIHRvdGFsIGFmZmVjdGVkIHBvcHVsYXRpb24gZm9yIGdyYXNzbGFuZCBkYW1hZ2VkIChIMSkgYW5kIGRlc3Ryb3llZCAoSDIpXSgjKXtuYW1lPTRhLjJ9DQoNCioqKioNCg0KKipBZmZlY3RlZCBwb3B1bGF0aW9uIChIMStIMikqKg0KYGBge3J9DQpHcmFzc0RlcFBvcCRMU1BvcEFmZjwtR3Jhc3NEZXBQb3AkTFNQb3BIMStHcmFzc0RlcFBvcCRMU1BvcEgyDQoNCmBgYA0KDQoqKkNhbGN1bGF0ZSBzaGFyZSBvZiB0b3RhbCBhZmZlY3RlZCBwb3AgKGgxK2gyKSoqDQpgYGB7cn0NCkdyYXNzRGVwUG9wJFNoYXJlTFNQb3BBZmY8LUdyYXNzRGVwUG9wJExTUG9wQWZmL0dyYXNzRGVwUG9wJExTRGVwUG9wDQojIyMjIyMjIG9yICMjIyMjIw0KR3Jhc3NEZXBQb3AkU2hhcmVMU1BvcEFmZjwtR3Jhc3NEZXBQb3AkU2hhcmVMU1BvcEgxK0dyYXNzRGVwUG9wJFNoYXJlTFNQb3BIMg0KR3Jhc3NEZXBQb3ANCmBgYA0KDQo8YnI+DQoNCipXcml0ZSB0aGUgY3N2IGZvciB0aGUgYWZmZWN0ZWQgbGl2ZXN0b2NrIGRlcGVuZGVudCBwb3B1bGF0aW9uIChhZmZMU1BvcDIwMTUuY3N2KSB0byBvdXRwdXQgZmlsZSogDQpgYGB7ciBldmFsPUZBTFNFfQ0Kd3JpdGUuY3N2KEdyYXNzRGVwUG9wLCIuL291dHB1dHMvYWZmTFNQb3AyMDE1LmNzdiIpDQpgYGANCg0KDQoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg0KKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioNCg0KKioqKg0KPltTdGVwIDNiLjEuIE92ZXJsYXkgZHJvdWdodCBpbXBhY3QgbWFwIHdpdGggY3JvcCBsYW5kIGNvdmVyKEgyMDE1TENfY3JvcGxhbmQpIHdpdGggbG9jYWwgbXVuaWNpcGFsaXR5IChsbSkgdG8gZXh0cmFjdCBzdGF0aXN0aWNzXSgjKXtuYW1lPTNiLjF9DQoNCioqKg0KDQoqKkFkZCBsb2NhbCBtdW5pY2lwYWxpdHkgYm91bmRhcmllcyBhZ2Fpbiwgc28gdGhhdCByZXN1bHRzIGZyb20gZ3Jhc3NsYW5kIGFuYWx5c2lzIGFyZSByZW1vdmVkKioNCmBgYHtyIGV2YWw9RkFMU0V9DQpsbTwtc2hhcGVmaWxlKCIuL291dHB1dHMvbG0yMDE2LnNocCIpDQpgYGANCioqRWFzdGVybiBDYXBlIGxvY2FsIG11bmljaXBhbGl0aWVzKioNCmBgYHtyIGVjaG89RkFMU0V9DQpwbG90KGxtKQ0KbG0NCmhlYWQobG0pDQpgYGANCg0KYGBge3IgZXZhbD1GQUxTRX0NCkhjcm9wQzwtIGNyb3AoSDIwMTUsTENfY3JvcCkNCkhjcm9wPC1tYXNrKEhjcm9wQyxMQ19jcm9wKQ0Kd3JpdGVSYXN0ZXIoSGNyb3AsICIuL291dHB1dHMvSF9jcm9wMjAxNS50aWYiLCBvdmVyd3JpdGU9VFJVRSkNCmBgYA0KDQoqKkV4dHJhY3QgcGl4ZWxzIGJ5IGNsYXNzIHBlciBtdW5pY2lwYWxpdHkqKg0KDQpgYGB7ciBldmFsPUZBTFNFfQ0KdjwtZXh0cmFjdChIY3JvcCwgbG0pICNFeHRyYWN0IHJhc3RlciB2YWx1ZXMgdG8gcG9seWdvbnMgDQp2LmNvdW50cyA8LSBsYXBwbHkodix0YWJsZSkgIyBHZXQgY2xhc3MgY291bnRzIGZvciBlYWNoIHBvbHlnb24NCmBgYA0KDQoqKkNyZWF0ZSBhIGRhdGEuZnJhbWUgd2hlcmUgbWlzc2luZyBjbGFzc2VzIGFyZSBOQSoqDQpgYGB7ciBldmFsPUZBTFNFfQ0KY2xhc3MuZGYgPC0gYXMuZGF0YS5mcmFtZSh0KHNhcHBseSh2LmNvdW50cywnWycsMTpsZW5ndGgodW5pcXVlKEhjcm9wKSkpKSkgDQoNCmBgYA0KDQpgYGB7ciBlY2hvPUZBTFNFfQ0KY2xhc3MuZGYNCmBgYA0KDQoqKkFkZCBwaXhlbCBjb3VudCBiYWNrIHRvIHBvbHlnb24gZGF0YSBwZXIgbXVuaWNpcGFsaXR5KioNCmBgYHtyIGV2YWw9RkFMU0V9DQpsbUBkYXRhIDwtIGRhdGEuZnJhbWUobG1AZGF0YSwgY2xhc3MuZGYpIyBBZGQgYmFjayB0byBwb2x5Z29uIGRhdGENCmhlYWQobG1AZGF0YSkNCndyaXRlLmNzdihsbUBkYXRhLCBmaWxlID0gIi4vb3V0cHV0cy9IX2Nyb3AyMDE1LmNzdiIpDQpIY3JvcDIwMTU8LWxtQGRhdGENCkhjcm9wMjAxNTwtcmVhZC5jc3YoIi4vb3V0cHV0cy9IX2Nyb3AyMDE1LmNzdiIpIA0KYGBgDQoNCg0KKipTdWJzZXQgcGl4ZWwgY291bnRzIGZvciBjbGFzc2VzIGFuZCBjb21wdXRlIHRoZSBoZWN0YXJlcyBpbiBlYWNoIGNsYXNzIGJ5IG11bHRpcGx5aW5nIGJ5IDAuMDkgKioNCg0KYGBge3IgZXZhbD1GQUxTRX0NCkhjcm9wMjAxNTwtc3Vic2V0KEhjcm9wMjAxNSwgc2VsZWN0ID0gYyhPQkpFQ1RJRCxNVU5JQ05BTUUsWDAsIFgxLCBYMikpDQpIY3JvcDIwMTUNCmBgYA0KDQo8YnI+DQoNCioqbXVsdGlwbHkgdG8gZ2V0IGhhKioNCmBgYHtyfQ0KSGNyb3AyMDE1JENyb3BIMGFyZWE8LUhjcm9wMjAxNSRYMCowLjA5DQpIY3JvcDIwMTUkQ3JvcEgxYXJlYTwtSGNyb3AyMDE1JFgxKjAuMDkNCkhjcm9wMjAxNSRDcm9wSDJhcmVhPC1IY3JvcDIwMTUkWDIqMC4wOQ0KSGNyb3AyMDE1DQpgYGANCg0KKipUb3RhbCBjcm9wIGFyZWEgZXN0aW1hdGlvbioqDQpgYGB7cn0NCkhjcm9wMjAxNSRDcm9wVG90YWxBcmVhPC1IY3JvcDIwMTUkQ3JvcEgwYXJlYStIY3JvcDIwMTUkQ3JvcEgxYXJlYStIY3JvcDIwMTUkQ3JvcEgyYXJlYQ0KDQpgYGANCioqKioNCj4gW1N0ZXAgM2IuMzogTWVyZ2UgZXh0cmFjdGVkIHN0YXRpc3RpY3Mgd2l0aCBjZW5zdXMgc3VydmV5IGRhdGEgdG8gY2FsY3VsYXRlIHBvcHVsYXRpb24gZGVuc2l0eV0oIyl7bmFtZT0zYi4yfQ0KDQoqKioqDQoqKk1lcmdlIHRoZSB0d28gc2V0cyBieSBNVU5JQ05BTUUqKg0KDQpgYGB7cn0NCkNyb3BEZXBQb3AgPSBtZXJnZShIY3JvcDIwMTUsQWdyRGVwUG9wLCBieSA9Ik1VTklDTkFNRSIpDQpDcm9wRGVwUG9wDQpgYGANCioqU3Vic2V0IGNyb3AgcmVxdWlyZWQgY29sdW1ucyoqDQpgYGB7cn0NCkNyb3BEZXBQb3A8LXN1YnNldChDcm9wRGVwUG9wLCBzZWxlY3Q9IGMoTVVOSUNOQU1FLCBDcm9wSDBhcmVhLCBDcm9wSDFhcmVhLENyb3BIMmFyZWEsIElELCBDcm9wVG90YWxBcmVhLCBDcm9wRGVwUG9wICkpDQpDcm9wRGVwUG9wDQpgYGANCg0KKipDcm9wIGRlcGVuZGVudCBwb3B1bGF0aW9uIGRlbnNpdHkqKg0KYGBge3J9DQpDcm9wRGVwUG9wJENyb3BQb3BEZW5zPC1Dcm9wRGVwUG9wJENyb3BEZXBQb3AvQ3JvcERlcFBvcCRDcm9wVG90YWxBcmVhDQpDcm9wRGVwUG9wDQpgYGANCioqKioNCj4gW1N0ZXAgNGIgb2YgNSBkcm91Z2h0IGltcGFjdCBjbGFzc2VzIGZvciBjcm9wbGFuZF0oIyl7bmFtZT00Yn0NCg0KKioqDQoNCioqKg0KPiBbU3RlcCA0Yi4xIG9mIDUgQ2FsY3VsYXRlIGFmZmVjdGVkIHBvcHVsYXRpb24gcGVyIGRyb3VnaHQgaW1wYWN0IGNsYXNzXSgjKXtuYW1lPTRiLjF9DQoNCioqKg0KYGBge3J9DQojIGNyb3AgIERlcGVuZGVudCBwb3B1bGF0aW9uIGluIEgwDQpDcm9wRGVwUG9wJENyb3BQb3BIMDwtQ3JvcERlcFBvcCRDcm9wUG9wRGVucypDcm9wRGVwUG9wJENyb3BIMGFyZWENCiMgY3JvcCAgRGVwZW5kZW50IHBvcHVsYXRpb24gaW4gSDENCkNyb3BEZXBQb3AkQ3JvcFBvcEgxPC1Dcm9wRGVwUG9wJENyb3BQb3BEZW5zKkNyb3BEZXBQb3AkQ3JvcEgxYXJlYQ0KIyBjcm9wICBEZXBlbmRlbnQgcG9wdWxhdGlvbiBpbiBIMg0KQ3JvcERlcFBvcCRDcm9wUG9wSDI8LUNyb3BEZXBQb3AkQ3JvcFBvcERlbnMqQ3JvcERlcFBvcCRDcm9wSDJhcmVhIA0KDQpgYGANCioqQ2FsY3VsYXRlIHRoZSBzaGFyZXMgb2YgcG9wIGluIGRyb3VnaHQgaW1wYWN0IGNsYXNzLyB0b3RhbCBwb3B1bGF0aW9uIGZvciBjcm9wbGFuZCoqDQpgYGB7cn0NCkNyb3BEZXBQb3AkU2hhcmVDcm9wUG9wSDA8LUNyb3BEZXBQb3AkQ3JvcFBvcEgwL0Nyb3BEZXBQb3AkQ3JvcERlcFBvcCANCkNyb3BEZXBQb3AkU2hhcmVDcm9wUG9wSDE8LUNyb3BEZXBQb3AkQ3JvcFBvcEgxL0Nyb3BEZXBQb3AkQ3JvcERlcFBvcA0KQ3JvcERlcFBvcCRTaGFyZUNyb3BQb3BIMjwtQ3JvcERlcFBvcCRDcm9wUG9wSDIvQ3JvcERlcFBvcCRDcm9wRGVwUG9wDQpDcm9wRGVwUG9wDQpgYGANCioqKioNCj4gW1N0ZXAgNGIuMiBvZiA1IENhbGN1bGF0ZSB0b3RhbCBhZmZlY3RlZCBwb3B1bGF0aW9uIGZvciBjcm9wbGFuZCBkYW1hZ2VkIChIMSkgYW5kIGRlc3Ryb3llZCAoSDIpXSgjKXtuYW1lPTRiLjJ9DQoNCioqKioNCg0KKipBZmZlY3RlZCBwb3B1bGF0aW9uIChIMStIMikqKg0KYGBge3J9DQpDcm9wRGVwUG9wJENyb3BQb3BBZmY8LUNyb3BEZXBQb3AkQ3JvcFBvcEgxK0Nyb3BEZXBQb3AkQ3JvcFBvcEgyDQoNCmBgYA0KDQoqKkNhbGN1bGF0ZSBzaGFyZSBvZiB0b3RhbCBhZmZlY3RlZCBwb3AgKGgxK2gyKSoqDQpgYGB7cn0NCkNyb3BEZXBQb3AkU2hhcmVDcm9wUG9wQWZmPC1Dcm9wRGVwUG9wJENyb3BQb3BBZmYvQ3JvcERlcFBvcCRDcm9wRGVwUG9wDQoNCiMjIyMjIyMgb3IgIyMjIyMjDQoNCkNyb3BEZXBQb3AkU2hhcmVDcm9wUG9wQWZmPC1Dcm9wRGVwUG9wJFNoYXJlQ3JvcFBvcEgxK0Nyb3BEZXBQb3AkU2hhcmVDcm9wUG9wSDINCkNyb3BEZXBQb3ANCmBgYA0KDQo8YnI+DQoNCipXcml0ZSB0aGUgY3N2IGZvciB0aGUgYWZmZWN0ZWQgY3JvcCBkZXBlbmRlbnQgcG9wdWxhdGlvbiAoYWZmQ3JvcFBvcDIwMTUuY3N2KSB0byBvdXRwdXQgZmlsZSogDQpgYGB7cn0NCndyaXRlLmNzdihDcm9wRGVwUG9wLCIuL291dHB1dHMvYWZmQ3JvcFBvcDIwMTUuY3N2IikNCmBgYA0KDQoqKioqKg0KPiBbIFN0ZXAgNSBvZiA1IGNhbGN1bGF0ZSB0b3RhbCBhZmZlY3RlZCBwb3B1bGF0aW9uXSgjKXtuYW1lPTV9DQoNCioqKioqDQoNCioqTWVyZ2UgdGhlIHR3byBkYXRhc2V0cyoqDQpgYGB7cn0NCmFmZlBvcDIwMTU8LW1lcmdlKENyb3BEZXBQb3AsR3Jhc3NEZXBQb3AsIGJ5PSJNVU5JQ05BTUUiKQ0KYWZmUG9wMjAxNSRhZmZQb3A8LWFmZlBvcDIwMTUkQ3JvcFBvcEFmZithZmZQb3AyMDE1JExTUG9wQWZmDQoNCmBgYA0KDQpgYGB7cn0NCmFmZlBvcDIwMTUkU2hhcmVhZmZQb3A8LWFmZlBvcDIwMTUkYWZmUG9wLyhhZmZQb3AyMDE1JENyb3BEZXBQb3ArYWZmUG9wMjAxNSRMU0RlcFBvcCkNCg0KYWZmUG9wMjAxNQ0Kd3JpdGUuY3N2KGFmZlBvcDIwMTUsIi4vb3V0cHV0cy9hZmZQb3AyMDE1LmNzdiIpDQpgYGANCg0KKioqIEFkZGl0aW9uYWx5OiBJZiB5b3Ugd2FudCB0byBoYXZlIGEgc2hhcGVmaWxlIHdpdGggdGhlc2UgaW5mb3JtYXRpb24sIHRoZSBvdXRwdXQgY2FuIGJlIG1lcmdlZCB3aXRoIHRoZSBsb2NhbCBtdW5pY2lwYWxpdHkgKGxtKSBzaGFwZWZpbGUgKioqDQpgYGB7cn0NCmxtPC1zaGFwZWZpbGUoIi4vb3V0cHV0cy9sbTIwMTYuc2hwIikNCm08LW1lcmdlKGxtLCBhZmZQb3AyMDE1LCBieT0iTVVOSUNOQU1FIikNCg0Kd3JpdGVPR1IobSwiLi9vdXRwdXRzL2FmZlBvcDIwMTUuc2hwIiwgImFmZlBvcDIwMTUiLCBkcml2ZXIgPSAiRVNSSSBTaGFwZWZpbGUiICkNCg0KDQpgYGANCg0K