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

Part. C

Part. D

Part. C



Step 0 of 4 Technical Guidance Sub-indicator

Sub-indicators:

B5a = Hecatares of crops affected * average workers per hectare

B5b = Livestock lost * average workers per hectare


Sep 1 of 5 Installing required packages and creating directories

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



Step 2.1 of 5 Subset of administrative boundaries and land cover map (LC map)


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


Map Value Class
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")

Part. D


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