Economic Value of direct maize production losses
Sub-indicator: Direct Crop Loss (C2c)
Economic loss due to crops damaged and destroyed by a disaster (drought)
C2c = Loss in annual crop stocks + Loss in perennial crop stocks + Annual crop production loss + Perennial crop production loss + Crop assets loss (complete and partial)
install.packages("raster")
install.packages("foreign")
install.packages("rgdal")
library(rgdal)
library(raster)
library(foreign)
Select the folder where all the data is stored in subfolders as your working directory
setwd("C:/Users/mduguru/Desktop/Ukraine_workshop/UKR/EconLoss/Data")
create a folder to store your outputs
dir.create("outputs")
Read the land use raster into R 30m
LC2015<-raster("./LC2015/Kyiv_2015.tif")
LC2015
class : RasterLayer
dimensions : 8719, 6690, 58330110 (nrow, ncol, ncell)
resolution : 30.00059, 29.99943 (x, y)
extent : 239770.9, 440474.8, 5452339, 5713904 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=utm +zone=36 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0
data source : C:\Users\mduguru\Desktop\Ukraine_workshop\UKR\EconLoss\Data\LC2015\Kyiv_2015.tif
names : Kyiv_2015
values : 0, 13 (min, max)


Land cover with available classes
plot(LC2015, col=colors[0:length(classes)+1], colNA=colors[1], axes=FALSE, box=FALSE)

| 0 |
No value |
| 1 |
Artificial |
| 2 |
Winter wheat |
| 3 |
Winter rapeseed |
| 4 |
Spring crops (wheat, barley) |
| 5 |
Maize |
| 6 |
Sugar beet |
| 7 |
Sunflower |
| 8 |
Soybeans |
| 9 |
Other cereals |
| 10 |
Forest |
| 11 |
Grassland |
| 12 |
Bare land |
| 13 |
Water |
Read the agricultural drought impact to be resampled from 250m to 30 m resolution of the Land cover map
H2015_250m<-raster("./H2015_250m/2015_droughtThreeCl.tif")
H2015_250m
class : RasterLayer
dimensions : 1175, 1441, 1693175 (nrow, ncol, ncell)
resolution : 0.002083333, 0.002083333 (x, y)
extent : 29.22708, 32.22917, 49.13125, 51.57917 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
data source : C:\Users\mduguru\Desktop\Ukraine_workshop\UKR\EconLoss\Data\H2015_250m\2015_droughtThreeCl.tif
names : X2015_droughtThreeCl
values : 0, 2 (min, max)

Check the projection of the agricultural impact map above in case the raster is not in UTM, the coordinate reference system needs to be changed to UTM just like the Land cover map before resampling
H2015_250m <- projectRaster (H2015_250m, crs="+proj=utm +zone=36 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0", method = "ngb")
H2015_250m
class : RasterLayer
dimensions : 1251, 1579, 1975329 (nrow, ncol, ncell)
resolution : 148, 232 (x, y)
extent : 218873.7, 452565.7, 5436549, 5726781 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=utm +zone=36 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0
data source : in memory
names : X2015_droughtThreeCl
values : 0, 2 (min, max)
Resample now
H2015<-resample(H2015_250m, LC2015,method="ngb")
H2015
class : RasterLayer
dimensions : 8719, 6690, 58330110 (nrow, ncol, ncell)
resolution : 30.00059, 29.99943 (x, y)
extent : 239770.9, 440474.8, 5452339, 5713904 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=utm +zone=36 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0
data source : in memory
names : X2015_droughtThreeCl
values : 0, 2 (min, max)
Write the resampled product into your output file
writeRaster(writeRaster(H2015,"./outputs/2015HUTM36_30m.tif")
lists the values from LC
values<-unique(values(LC2015))
values
[1] 0 11 10 13 12 3 8 2 5 7 1 4 6
recl_m<-matrix(c(values, c(rep(NA,8),1, rep(NA,4))), ncol=2) #reclassify rasterlayer: maize=1, other=NA (see legend in data folder)
recl_m
[,1] [,2]
[1,] 0 NA
[2,] 11 NA
[3,] 10 NA
[4,] 13 NA
[5,] 12 NA
[6,] 3 NA
[7,] 8 NA
[8,] 2 NA
[9,] 5 1
[10,] 7 NA
[11,] 1 NA
[12,] 4 NA
[13,] 6 NA
LC_m<-reclassify(LC2015, rcl = recl_m)
A Land Cover map of Maize
plot(LC_m)

writeRaster(LC_m, "./outputs/Maize2015.tif")
adm2UKR<-shapefile("./adm2UKR/ukr_cod_admbnda_adm2_q2_2017.shp")
plot(adm2UKR)

head(adm2UKR)
adm2UKR
class : SpatialPolygonsDataFrame
features : 680
extent : 22.13691, 40.22079, 44.38641, 52.37929 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
variables : 18
names : a2Pcode, a2NameUa, a2NameRus, a2NameLat, codeNameA2, codeTopoA2, POL_ADM2, PcodeOld2, a1Pcode, a1NameUa, a1NameRus, a1NameLat, codeNameA1, codeTopoA1, a0Pcode, ...
min values : UKR01101, ÐданÑвÑÑка, ÐдановÑкий, Alchevska, мÑÑÑка Ñада, 81300000, мÑÑÑка Ñада, 0110100000, UKR01, ÐиÑомиÑÑÑка, ÐиÑомиÑÑкаÑ, Avtonomna Respublika Krym, мÑÑÑка Ñада, 81200000, UKR, ...
max values : UKR85369, ÐÑÑÑозÑка, ÐÑÑÑожÑкий, Zvenyhorodskyi, Ñайон, 81400000, мÑÑÑка Ñада, 8536900000, UKR85, ÐдеÑÑка, ÐдеÑÑкаÑ, Zhytomyrska, облаÑÑÑ, 81230100, UKR, ...
adm2<-subset(adm2UKR, a1NameLat=="Kyivska")
adm2<-subset(adm2, a2NameLat!="Kyivska")
Kiev Region
plot(adm2)

head(adm2)
Check the projection of the map make sure that adm2 and H2015 have the same projected coordinate system if not reproject the Kiev administrative area adm2
adm2<-spTransform(adm2, CRS("+proj=utm +zone=36 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0 "))
writeOGR(adm2,"./outputs/adm2.shp", "adm2", driver = "ESRI Shapefile")
To Read in the attribute table of the shapefile for Kiev
adm2_attr<-read.dbf("./outputs/adm2.dbf") # read in the attribute table of the shapefile
adm2_attr
at<-adm2_attr[order(adm2_attr$a2NameLat),] # order the names alphabetically of the rayons
at$ID<-c(1:37) # add an ID
at<-at[,c(19,4)] # only select the names and the ID from the attribute table
write.dbf(at,"./outputs/adm2.dbf") # add attribute table back to adm2
Load the updated shapfile again
adm2<-shapefile("./outputs/adm2.shp") # load the updated shapfile again
Hmc<- crop(H2015,LC_m)
Hm<-mask(Hmc,LC_m)

writeRaster(Hm, "./outputs/2015Hmaize.tif", overwrite=TRUE)
Extract raster values to polygons like below
v<-extract(Hm, adm2)
Get class counts for each polygon
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(Hm)))))
class.df
Add back to polygon data
adm2@data <- data.frame(adm2@data, class.df)
write the drought impact for maize to outputs folder
write.csv(adm2@data, file = "./outputs/H_maize.csv")
H_maize<-read.csv("./outputs/H_maize.csv")
H_maize$X0[is.na(H_maize$X0)]<-0 # replaces all NA with 0 --> 0 ha affected
H_maize$X1[is.na(H_maize$X1)]<-0 # replaces all NA with 0 --> 0 ha affected
H_maize$X2[is.na(H_maize$X2)]<-0 # replaces all NA with 0 --> 0 ha affected
To clean data remove all data except for the ones in bracket as below
H_maize<-subset(H_maize, select = c(ID,a2NameLat, X0,X1, X2))
Calculate expected and actual harvested ha to get deltaHa
Adds column with the sum of all maize pixels X0, X1 and X2 which are in column 3-5
H_maize$pixelSum =rowSums(H_maize[, 3:5], na.rm = T)
Area in ha, 1 pixel is 900m², thus the number of pixel needs to be multiplied with 0.09 to get ha
H_maize$H0Area=H_maize$X0*0.09
H_maize$H1Area=H_maize$X1*0.09
H_maize$H2Area=H_maize$X2*0.09
The expected area to be harvested is the total maize crop area(H0, H1, and H2)
| H0 |
Not Affected Maize Land |
| H1 |
Damaged Maize Land |
| H2 |
Destryed Maize Land |
H_maize$expected=H_maize$H0Area+ H_maize$H1Area+ H_maize$H2Area
The actual area is the harvested area (H0 and H1)
H_maize$actual=H_maize$H0Area+ H_maize$H1Area
Compute The difference between the expected havest hectare and the actual harvested hectare
H_maize$deltaHa= H_maize$expected - H_maize$actual
Note: Add the yield data (including the average yield 2010-2014)
maizeYield2015 <-read.csv("./Y2004-2015/YieldStatMaize.csv")
compute for average if the average yield was not yet calculated
maizeYield2015$avg<-((maizeYield2015$X2010 + maizeYield2015$X2011+ maizeYield2015$X2012i+ maizeYeld2015$X2013+ maizeYield2015$X2014)/5)
Remove all yield data from other years than 2015, avg and the ID which is required
maizeYield2015<-subset(maizeYield2015, select = c(ID,X2015,avg))
multiply with 0.1 for conversion from centner to tons
maizeYield2015$deltaY<-(maizeYield2015$avg - maizeYield2015$X2015)*0.1
Set all values <0 ==0 to avoid positive losses
maizeYield2015$deltaY<-replace(maizeYield2015$deltaY, maizeYield2015$deltaY<0, 0)
Add the yield data to maize drought impact
H_maizeYield = merge(maizeYield2015,H_maize, by ="ID")
look up the price from the page *** Agriculturaloutput prices*** from the price excel document UA_WP1_consolidated-database_USD the table for the year 2015 and add it as a column
H_maizeYield$P=127.7
*** Please inspect the tables for clearity on the developed methodology***
H_maizeYield$C2C2= H_maizeYield$P* H_maizeYield$deltaHa* maizeYield2015$avg
H_maizeYield$C2C1= H_maizeYield$P* H_maizeYield$deltaY* H_maizeYield$H1Area
H_maizeYield
Sum of damaged and destroyed maize per Rayon
H_maizeYield$maizeLoss2015= H_maizeYield$C2C1+H_maizeYield$C2C2
Total loss in maize production
overallLossMaize <-sum (H_maizeYield $ maizeLoss2015, na.rm= T)
Overall Economic Value of maize Loss in U.S.D $291493992
overallLossMaize
[1] 291493992
Store the output CSV H_maizeYield as H_LossMaize.csv in the output file
write.csv(H_maizeYield, "./outputs/H_LossMaize.csv")
Optionaly : if you want to have a shapefile with these information, the output can be merged with the adm shapefile
m<-merge(adm2, H_maizeYield, by="ID")
class : SpatialPolygonsDataFrame
features : 37
extent : 239632.3, 440394.5, 5452195, 5713929 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=utm +zone=36 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0
variables : 23
names : ID, a2NameLat.x, X0.x, X1.x, X2.x, X2015, avg, deltaY, a2NameLat.y, X0.y, X1.y, X2.y, pixelSum, H0Area, H1Area, ...
min values : 1, Baryshivskyi, 2, 1, 1, 27, 29.6, 0.00, Baryshivskyi, 0, 0, 0, 0, 0.00, 0.00, ...
max values : 37, Zghurivskyi, 88683, 38765, 55152, 139, 87.6, 2.48, Zghurivskyi, 88683, 38765, 55152, 176752, 7981.47, 3488.85, ...
write Shapefile with all information to outputs folder
writeOGR(m,"./outputs/H_LossMaize2015.shp", "LossMaize2015", driver = "ESRI Shapefile" )
END
LS0tDQp0aXRsZTogIiINCg0Kc3VidGl0bGU6IA0KDQphdXRob3I6DQogDQpvdXRwdXQ6DQogID8gfC0NCiAgOiBkZWZhdWx0DQogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQNCiAgICBodG1sX25vdGVib29rDQogICAgLS0tLS0NCi0tLSAgDQpgYGB7ciAic2V0dXAiLCBpbmNsdWRlPUZBTFNFfQ0KcmVxdWlyZSgia25pdHIiKQ0Kb3B0c19rbml0JHNldChyb290LmRpciA9ICJDOi9Vc2Vycy9tZHVndXJ1L0Rlc2t0b3AvVWtyYWluZV93b3Jrc2hvcC9VS1IvRWNvbkxvc3MvRGF0YSIpDQpgYGANCioqRWNvbm9taWMgVmFsdWUgb2YgZGlyZWN0IG1haXplIHByb2R1Y3Rpb24gbG9zc2VzKioNCjxicj4gDQoqKlN1Yi1pbmRpY2F0b3I6LS0gRGlyZWN0IENyb3AgTG9zcyAoQzJjKSoqDQoNCiMjIyMgKipUYWJsZSBvZiBDb250ZW50cyoqICANCiMjIyMgW1BhcnQuIENdKCNQYXJ0YykNCiMjIyMjIyBbU3RlcCAwIG9mIDQgVGVjaG5pY2FsIEd1aWRhbmNlIFN1Yi1pbmRpY2F0b3JdKCMwKQ0KIyMjIyMjIFtTdGVwIDEgb2YgNCBJbnN0YWxsaW5nIHJlcXVpcmVkIHBhY2thZ2VzIGFuZCBjcmVhdGluZyBkaXJlY3RvcmllcyBdKCMxKQ0KIyMjIyMjIFtTdGVwIDIgb2YgNCBEYXRhIHByZXBhcmF0aW9uICBdKCMyKQ0KIyMjIyMjIFtTdGVwIDIuMSBvZiA0IFJlc2FtcGxlIEgyMDE1XzI1MG0gdG8gMzBtIF0oIzIuMSkNCiMjIyMjIyBbU3RlcCAyLjIgb2YgNCBNYWl6ZTIwMTU6IEV4dHJhY3QgcmVsZXZhbnQgTEMgZnJvbSBMQzIwMTUgKG1haXplIGluIExDIG1hcD01KV0oIzIuMikNCiMjIyMjIyBbU3RlcCAyLjMgb2YgNCBzdWJzZXR0aW5nIEtpZXYgcmVnaW9uIGZyb20gdGhlIFVrcmFpbmUgYWRtaW5pc3RyYXRpdmUgYXJlYV0oIzIuMykNCiMjIyMgICBbUGFydC4gRF0oI1BhcnREKQ0KIyMjIyMjIFtTdGVwIDMgb2YgNCBQcm9jZXNzaW5nXSgjMykNCiMjIyMjIyBbU3RlcCAzLjEgb2YgNCBPdmVybGF5IHRoZSBhZ3JpY3VsdHVyYWwgZHJvdWdodCBpbXBhY3QgbWFwIChIMjAxNSksIG1haXplIGxhbmQgIGNvdmVyIGZvciAyMDE1IChMQzIwMTUpIGFuZCBLaWV2IG1hcCAoYWRtMikgdG8gZXh0cmFjdCBzdGF0aXN0aWNzXSgjMy4xKQ0KIyMjIyMjIFtTdGVwIDMuMiBvZiA0IENhbGN1bGF0ZSBleHBlY3RlZCBhbmQgYWN0dWFsIGhhcnZlc3RlZCBoYSB0byBnZXQgZGVsdGFIYV0oIzMuMikNCiMjIyMjIyBbU3RlcCAzLjMgb2YgNCBDYWxjdWxhdGUgY2hhbmdlIGluIHlpZWxkIChkZWx0YVkpXSgjMy4zKQ0KIyMjIyMjIFtTdGVwIDQgb2YgNCBPdXRwdXRzIGFuZCBmaW5hbCByZXN1bHRzIF0oIzQpDQojIyMjIyMgW1N0ZXAgNCBvZiA0LjEgTG9zcyBvbiBEZXN0cm95ZWQgQXJlYSAoQzJDMikgaW4gVS5TLiBEb2xsYXJzXSgjNC4xKQ0KIyMjIyMjIFtTdGVwIDQgb2YgNC4yIExvc3Mgb24gRGFtYWdlZCBBcmVhIChDMkMxKSBpbiBVLlMuIERvbGxhcnMgIF0oIzQuMikNCiMjIyMjIyBbU3RlcCA0IG9mIDQuMyBNYWl6ZSBwcm9kdWN0aW9uIGxvc3NlcyBmb3IgMjAxNSAgXSgjNC4zKQ0KDQoNCg0KKioqKioqDQoNCiMjIyMgW1BhcnQuIENdKCMpe25hbWU9UGFydGN9DQoqKioqKioNCg0KDQoqKioqKioNCj4gIyMjIyMgW1N0ZXAgMCBvZiA0IFRlY2huaWNhbCBHdWlkYW5jZSBTdWItaW5kaWNhdG9yIF0oIyl7bmFtZT0wfSANCg0KKioqKioqDQoNCkVjb25vbWljIFZhbHVlIG9mIGRpcmVjdCBtYWl6ZSBwcm9kdWN0aW9uIGxvc3NlcyAgDQoNCioqKlN1Yi1pbmRpY2F0b3I6IERpcmVjdCBDcm9wIExvc3MgKEMyYykqKiogDQoNCiBFY29ub21pYyBsb3NzIGR1ZSB0byBjcm9wcyBkYW1hZ2VkIGFuZCBkZXN0cm95ZWQgYnkgYSBkaXNhc3RlciAoZHJvdWdodCkNCiANCiArIEMyYzEgcmVwcmVzZW50cyBkYW1nZWQgbWFpemUgZmllbGRzDQogDQogKyBDMmMyIHJlcHJlc2VudHMgZGVzdHJveWVkIG1haXplIGZpZWxkcw0KDQoNCioqKkMyYyA9IExvc3MgaW4gYW5udWFsIGNyb3Agc3RvY2tzICsgTG9zcyBpbiBwZXJlbm5pYWwgY3JvcCBzdG9ja3MgICsgIEFubnVhbCBjcm9wIHByb2R1Y3Rpb24gbG9zcyArIFBlcmVubmlhbCBjcm9wIHByb2R1Y3Rpb24gbG9zcyArIENyb3AgYXNzZXRzIGxvc3MgKGNvbXBsZXRlIGFuZCBwYXJ0aWFsKSoqKg0KDQoNCg0KKioqKg0KPiAjIyMjIyBbU3RlcCAxIG9mIDQgSW5zdGFsbGluZyByZXF1aXJlZCBwYWNrYWdlcyBhbmQgY3JlYXRpbmcgZGlyZWN0b3JpZXMgXSgjKXtuYW1lPTF9DQoNCioqKioNCmBgYHtyIGV2YWw9RkFMU0V9DQoNCmluc3RhbGwucGFja2FnZXMoInJhc3RlciIpDQppbnN0YWxsLnBhY2thZ2VzKCJmb3JlaWduIikNCmluc3RhbGwucGFja2FnZXMoInJnZGFsIikNCg0KYGBgDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KbGlicmFyeShyZ2RhbCkNCmxpYnJhcnkocmFzdGVyKQ0KbGlicmFyeShmb3JlaWduKQ0KYGBgDQoNClNlbGVjdCB0aGUgZm9sZGVyIHdoZXJlIGFsbCB0aGUgZGF0YSBpcyBzdG9yZWQgaW4gc3ViZm9sZGVycyBhcyB5b3VyIHdvcmtpbmcgZGlyZWN0b3J5DQpgYGB7ciBldmFsPUZBTFNFfQ0Kc2V0d2QoIkM6L1VzZXJzL21kdWd1cnUvRGVza3RvcC9Va3JhaW5lX3dvcmtzaG9wL1VLUi9FY29uTG9zcy9EYXRhIikNCmBgYA0KDQpjcmVhdGUgYSBmb2xkZXIgdG8gc3RvcmUgeW91ciBvdXRwdXRzDQoNCmBgYHtyIGV2YWw9VFJVRX0NCg0KZGlyLmNyZWF0ZSgib3V0cHV0cyIpDQoNCg0KYGBgDQoNCioqKioNCj4gIyMjIyMgW1N0ZXAgMiBvZiA0IERhdGEgcHJlcGFyYXRpb24gXSgjKXtuYW1lPTJ9DQoNCioqKioNCioqKioNCj4gIyMjIyMgW1N0ZXAgMi4xIG9mIDQgUmVzYW1wbGUgSDIwMTVfMjUwbSB0byAzMG0gXSgjKXtuYW1lPTIuMX0NCg0KKioqKg0KDQpSZWFkIHRoZSBsYW5kIHVzZSByYXN0ZXIgaW50byBSIDMwbQ0KYGBge3J9DQpMQzIwMTU8LXJhc3RlcigiLi9MQzIwMTUvS3lpdl8yMDE1LnRpZiIpDQpMQzIwMTUNCg0KYGBgDQoNCmBgYHtyIGVjaG89RkFMU0V9DQpwbG90KExDMjAxNSkgDQpgYGANCg0KTGFuZCBjb3ZlciB3aXRoIGF2YWlsYWJsZSBjbGFzc2VzDQpgYGB7ciBlY2hvPUZBTFNFfQ0KY2xhc3NlcyA8LSB0YWJsZShnZXRWYWx1ZXMoTEMyMDE1KSkgIyBUYWJ1bGF0aW9uIG9mIGNsYXNzIGNvdW50cw0KY29sb3JzIDwtIExDMjAxNUBsZWdlbmRAY29sb3J0YWJsZSAgIyBDbGFzcyBjb2xvcnMNCg0KYGBgDQoNCmBgYHtyfQ0KDQpwbG90KExDMjAxNSwgY29sPWNvbG9yc1swOmxlbmd0aChjbGFzc2VzKSsxXSwgY29sTkE9Y29sb3JzWzFdLCBheGVzPUZBTFNFLCBib3g9RkFMU0UpDQoNCmBgYA0KDQoNCg0KQ09ERSAgICAgICB8IExhbmQgQ292ZXINCi0tLS0tLS0tLS0gfCAtLS0tLS0tLS0tDQogIDAgICAgICAgIHwgTm8gdmFsdWUgICANCiAgMSAgICAgICAgfCBBcnRpZmljaWFsDQogIDIJICAgICAgIHwgV2ludGVyIHdoZWF0DQogIDMgICAgICAgIHwgV2ludGVyIHJhcGVzZWVkDQogIDQJICAgICAgIHwgU3ByaW5nIGNyb3BzICh3aGVhdCwgYmFybGV5KQ0KICAqKio1KioqCSB8ICoqKk1haXplKioqDQogIDYJICAgICAgIHwgU3VnYXIgYmVldA0KICA3CSAgICAgICB8IFN1bmZsb3dlcg0KICA4ICAJICAgICB8IFNveWJlYW5zDQogIDkJICAgICAgIHwgT3RoZXIgY2VyZWFscw0KIDEwCSAgICAgICB8IEZvcmVzdA0KIDExCSAgICAgICB8IEdyYXNzbGFuZA0KIDEyCSAgICAgICB8IEJhcmUgbGFuZA0KIDEzICAgICAgICB8IFdhdGVyDQoNCg0KUmVhZCB0aGUgYWdyaWN1bHR1cmFsIGRyb3VnaHQgaW1wYWN0IHRvIGJlIHJlc2FtcGxlZCBmcm9tIDI1MG0gdG8gMzAgbSByZXNvbHV0aW9uIG9mIHRoZSBMYW5kIGNvdmVyIG1hcA0KYGBge3J9DQpIMjAxNV8yNTBtPC1yYXN0ZXIoIi4vSDIwMTVfMjUwbS8yMDE1X2Ryb3VnaHRUaHJlZUNsLnRpZiIpDQpIMjAxNV8yNTBtDQpgYGANCg0KYGBge3IgZWNobz1GQUxTRX0NCnBsb3QoSDIwMTVfMjUwbSkNCmBgYA0KDQoNCkNoZWNrIHRoZSBwcm9qZWN0aW9uIG9mIHRoZSBhZ3JpY3VsdHVyYWwgaW1wYWN0IG1hcCBhYm92ZSBpbiBjYXNlIHRoZSByYXN0ZXIgaXMgbm90IGluIFVUTSwgdGhlIGNvb3JkaW5hdGUgcmVmZXJlbmNlIHN5c3RlbSBuZWVkcyB0byBiZSBjaGFuZ2VkIHRvIFVUTSBqdXN0IGxpa2UgdGhlIExhbmQgY292ZXIgbWFwIGJlZm9yZSByZXNhbXBsaW5nDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KSDIwMTVfMjUwbSA8LSBwcm9qZWN0UmFzdGVyIChIMjAxNV8yNTBtLCBjcnM9Iitwcm9qPXV0bSArem9uZT0zNiArZGF0dW09V0dTODQgK3VuaXRzPW0gK25vX2RlZnMgK2VsbHBzPVdHUzg0ICt0b3dnczg0PTAsMCwwIiwgbWV0aG9kID0gIm5nYiIpDQogSDIwMTVfMjUwbQ0KYGBgDQoNCg0KUmVzYW1wbGUgbm93IA0KDQpgYGB7cn0NCkgyMDE1PC1yZXNhbXBsZShIMjAxNV8yNTBtLCBMQzIwMTUsbWV0aG9kPSJuZ2IiKQ0KDQpgYGANCg0KYGBge3J9DQpIMjAxNQ0KYGBgDQoNCg0KV3JpdGUgdGhlIHJlc2FtcGxlZCBwcm9kdWN0IGludG8geW91ciBvdXRwdXQgZmlsZQ0KYGBge3IgZXZhbD1GQUxTRX0NCndyaXRlUmFzdGVyKHdyaXRlUmFzdGVyKEgyMDE1LCIuL291dHB1dHMvMjAxNUhVVE0zNl8zMG0udGlmIikNCmBgYA0KDQoqKioqKg0KPiAjIyMjIyBbU3RlcCAyLjIgb2YgNCBNYWl6ZTIwMTU6IEV4dHJhY3QgcmVsZXZhbnQgTEMgZnJvbSBMQzIwMTUgKG1haXplIGluIExDIG1hcD01KV0oIyl7bmFtZT0yLjJ9DQoNCioqKioqDQpsaXN0cyB0aGUgdmFsdWVzIGZyb20gTEMNCmBgYHtyfQ0KdmFsdWVzPC11bmlxdWUodmFsdWVzKExDMjAxNSkpDQp2YWx1ZXMNCmBgYA0KDQpgYGB7cn0NCnJlY2xfbTwtbWF0cml4KGModmFsdWVzLCBjKHJlcChOQSw4KSwxLCByZXAoTkEsNCkpKSwgbmNvbD0yKSAjcmVjbGFzc2lmeSByYXN0ZXJsYXllcjogbWFpemU9MSwgb3RoZXI9TkEgKHNlZSBsZWdlbmQgaW4gZGF0YSBmb2xkZXIpDQoNCnJlY2xfbQ0KYGBgDQoNCmBgYHtyfQ0KTENfbTwtcmVjbGFzc2lmeShMQzIwMTUsIHJjbCA9IHJlY2xfbSkNCmBgYA0KDQpBIExhbmQgQ292ZXIgbWFwIG9mIE1haXplDQpgYGB7cn0NCnBsb3QoTENfbSkNCmBgYA0KDQpgYGB7ciBlY2hvPUZBTFNFfQ0KcGxvdChMQ19tLCBsZWdlbmQ9RikNCnBsb3QoYWRtMiwgYWRkPVQpDQpgYGANCg0KYGBge3IgZXZhbCA9IEZBTFNFfQ0Kd3JpdGVSYXN0ZXIoTENfbSwgIi4vb3V0cHV0cy9NYWl6ZTIwMTUudGlmIikNCmBgYA0KDQoqKioqDQo+ICMjIyMjIFtTdGVwIDIuMyBvZiA0IHN1YnNldHRpbmcgS2lldiByZWdpb24gZnJvbSB0aGUgVWtyYWluZSBhZG1pbmlzdHJhdGl2ZSBhcmVhXSgjKXtuYW1lPTIuM30NCg0KKioqKg0KDQpgYGB7cn0NCmFkbTJVS1I8LXNoYXBlZmlsZSgiLi9hZG0yVUtSL3Vrcl9jb2RfYWRtYm5kYV9hZG0yX3EyXzIwMTcuc2hwIikNCnBsb3QoYWRtMlVLUikNCmBgYA0KDQpgYGB7cn0NCmhlYWQoYWRtMlVLUikNCg0KYGBgDQoNCg0KDQoNCmBgYHtyfQ0KYWRtMlVLUg0KYGBgDQoNCg0KYGBge3J9DQphZG0yPC1zdWJzZXQoYWRtMlVLUiwgYTFOYW1lTGF0PT0iS3lpdnNrYSIpDQphZG0yPC1zdWJzZXQoYWRtMiwgYTJOYW1lTGF0IT0iS3lpdnNrYSIpDQpgYGANCg0KS2lldiBSZWdpb24NCmBgYHtyfQ0KcGxvdChhZG0yKQ0KDQpgYGANCg0KYGBge3J9DQpoZWFkKGFkbTIpDQoNCmBgYA0KDQpDaGVjayB0aGUgcHJvamVjdGlvbiBvZiB0aGUgbWFwIG1ha2Ugc3VyZSB0aGF0IGFkbTIgYW5kIEgyMDE1IGhhdmUgdGhlIHNhbWUgcHJvamVjdGVkIGNvb3JkaW5hdGUgc3lzdGVtIGlmIG5vdCByZXByb2plY3QgdGhlIEtpZXYgYWRtaW5pc3RyYXRpdmUgYXJlYSBhZG0yDQpgYGB7cn0NCmFkbTI8LXNwVHJhbnNmb3JtKGFkbTIsIENSUygiK3Byb2o9dXRtICt6b25lPTM2ICtkYXR1bT1XR1M4NCArdW5pdHM9bSArbm9fZGVmcyArZWxscHM9V0dTODQgK3Rvd2dzODQ9MCwwLDAgIikpDQpgYGANCg0KYGBge3IgZXZhbD1GQUxTRX0NCndyaXRlT0dSKGFkbTIsIi4vb3V0cHV0cy9hZG0yLnNocCIsICJhZG0yIiwgZHJpdmVyID0gIkVTUkkgU2hhcGVmaWxlIikNCmBgYA0KDQpUbyBSZWFkIGluIHRoZSBhdHRyaWJ1dGUgdGFibGUgb2YgdGhlIHNoYXBlZmlsZSBmb3IgS2lldg0KYGBge3J9DQphZG0yX2F0dHI8LXJlYWQuZGJmKCIuL291dHB1dHMvYWRtMi5kYmYiKSAjIHJlYWQgaW4gdGhlIGF0dHJpYnV0ZSB0YWJsZSBvZiB0aGUgc2hhcGVmaWxlDQpgYGANCg0KYGBge3J9DQphZG0yX2F0dHINCmBgYA0KDQpgYGB7cn0NCmF0PC1hZG0yX2F0dHJbb3JkZXIoYWRtMl9hdHRyJGEyTmFtZUxhdCksXSAjIG9yZGVyIHRoZSBuYW1lcyBhbHBoYWJldGljYWxseSBvZiB0aGUgcmF5b25zDQpgYGANCg0KYGBge3J9DQphdCRJRDwtYygxOjM3KSAjIGFkZCBhbiBJRA0KDQpgYGANCg0KYGBge3IgZXZhbD1GQUxTRX0NCmF0PC1hdFssYygxOSw0KV0gIyBvbmx5IHNlbGVjdCB0aGUgbmFtZXMgYW5kIHRoZSBJRCBmcm9tIHRoZSBhdHRyaWJ1dGUgdGFibGUNCmBgYA0KYGBge3J9DQp3cml0ZS5kYmYoYXQsIi4vb3V0cHV0cy9hZG0yLmRiZiIpICMgYWRkIGF0dHJpYnV0ZSB0YWJsZSBiYWNrIHRvIGFkbTINCg0KYGBgDQoNCkxvYWQgdGhlIHVwZGF0ZWQgc2hhcGZpbGUgYWdhaW4NCmBgYHtyfQ0KYWRtMjwtc2hhcGVmaWxlKCIuL291dHB1dHMvYWRtMi5zaHAiKSAjIGxvYWQgdGhlIHVwZGF0ZWQgc2hhcGZpbGUgYWdhaW4NCmBgYA0KDQoqKioqKioNCg0KIyMjIyBbUGFydC4gRF0oIyl7bmFtZT1QYXJ0RH0NCioqKioqKg0KDQoqKioqKg0KPiAjIyMjIyBbU3RlcCAzIG9mIDQgUHJvY2Vzc2luZ10oIyl7bmFtZT0zfQ0KDQoqKioqKg0KDQoNCg0KKioqKioNCj4gIyMjIyMgW1N0ZXAgMy4xIG9mIDQgT3ZlcmxheSB0aGUgYWdyaWN1bHR1cmFsIGRyb3VnaHQgaW1wYWN0IG1hcCAoSDIwMTUpLCBtYWl6ZSBsYW5kICBjb3ZlciBmb3IgMjAxNSAoTEMyMDE1KSBhbmQgS2lldiBtYXAgKGFkbTIpIHRvIGV4dHJhY3Qgc3RhdGlzdGljc10oIyl7bmFtZT0zLjF9DQoNCioqKioqDQoNCmBgYHtyfQ0KSG1jPC0gY3JvcChIMjAxNSxMQ19tKQ0KSG08LW1hc2soSG1jLExDX20pDQpgYGANCg0KYGBge3IgZWNobyA9IEZBTFNFfQ0KcGxvdChIbSkNCmBgYA0KDQoNCmBgYHtyIGV2YWwgPSBGQUxTRX0NCndyaXRlUmFzdGVyKEhtLCAiLi9vdXRwdXRzLzIwMTVIbWFpemUudGlmIiwgb3ZlcndyaXRlPVRSVUUpDQpgYGANCg0KRXh0cmFjdCByYXN0ZXIgdmFsdWVzIHRvIHBvbHlnb25zIGxpa2UgYmVsb3cNCg0KYGBge3J9DQp2PC1leHRyYWN0KEhtLCBhZG0yKQ0KYGBgDQoNCkdldCBjbGFzcyBjb3VudHMgZm9yIGVhY2ggcG9seWdvbg0KDQpgYGB7cn0NCnYuY291bnRzIDwtIGxhcHBseSh2LHRhYmxlKQ0KYGBgDQoNCg0KQ3JlYXRlIGEgZGF0YS5mcmFtZSB3aGVyZSBtaXNzaW5nIGNsYXNzZXMgYXJlIE5BDQoNCmBgYHtyfQ0KY2xhc3MuZGYgPC0gYXMuZGF0YS5mcmFtZSh0KHNhcHBseSh2LmNvdW50cywnWycsMTpsZW5ndGgodW5pcXVlKEhtKSkpKSkNCmBgYA0KDQpgYGB7cn0NCmNsYXNzLmRmDQoNCmBgYA0KDQoNCkFkZCBiYWNrIHRvIHBvbHlnb24gZGF0YQ0KDQpgYGB7cn0NCmFkbTJAZGF0YSA8LSBkYXRhLmZyYW1lKGFkbTJAZGF0YSwgY2xhc3MuZGYpDQpgYGANCndyaXRlIHRoZSBkcm91Z2h0IGltcGFjdCBmb3IgbWFpemUgdG8gb3V0cHV0cyBmb2xkZXINCg0KYGBge3IgZXZhbD1GQUxTRX0NCndyaXRlLmNzdihhZG0yQGRhdGEsIGZpbGUgPSAiLi9vdXRwdXRzL0hfbWFpemUuY3N2IikNCmBgYA0KDQoqKioqKg0KPiAjIyMjIyBbU3RlcCAzLjIgb2YgNCBDYWxjdWxhdGUgZXhwZWN0ZWQgYW5kIGFjdHVhbCBoYXJ2ZXN0ZWQgaGEgdG8gZ2V0IGRlbHRhSGFdKCMpe25hbWU9My4yfQ0KDQoqKioqKg0KDQpgYGB7cn0NCkhfbWFpemU8LXJlYWQuY3N2KCIuL291dHB1dHMvSF9tYWl6ZS5jc3YiKQ0KYGBgDQoNCmBgYHtyfQ0KSF9tYWl6ZSRYMFtpcy5uYShIX21haXplJFgwKV08LTAgIyByZXBsYWNlcyBhbGwgTkEgd2l0aCAwIC0tPiAwIGhhIGFmZmVjdGVkDQpIX21haXplJFgxW2lzLm5hKEhfbWFpemUkWDEpXTwtMCAjIHJlcGxhY2VzIGFsbCBOQSB3aXRoIDAgLS0+IDAgaGEgYWZmZWN0ZWQNCkhfbWFpemUkWDJbaXMubmEoSF9tYWl6ZSRYMildPC0wICMgcmVwbGFjZXMgYWxsIE5BIHdpdGggMCAtLT4gMCBoYSBhZmZlY3RlZA0KYGBgDQoNCmBgYHtyIGVjaG89RkFMU0V9DQpIX21haXplDQpgYGANCg0KVG8gY2xlYW4gZGF0YSByZW1vdmUgYWxsICBkYXRhIGV4Y2VwdCBmb3IgdGhlIG9uZXMgaW4gYnJhY2tldCBhcyBiZWxvdw0KDQpgYGB7cn0NCkhfbWFpemU8LXN1YnNldChIX21haXplLCBzZWxlY3QgPSBjKElELGEyTmFtZUxhdCwgWDAsWDEsIFgyKSkNCmBgYA0KDQpgYGB7ciBlY2hvPUZBTFNFfQ0KSF9tYWl6ZQ0KYGBgDQoNCg0KKioqQ2FsY3VsYXRlIGV4cGVjdGVkIGFuZCBhY3R1YWwgaGFydmVzdGVkIGhhIHRvIGdldCBkZWx0YUhhKioqDQoNCiBBZGRzIGNvbHVtbiB3aXRoIHRoZSBzdW0gb2YgYWxsIG1haXplIHBpeGVscyBYMCwgWDEgYW5kIFgyIHdoaWNoIGFyZSBpbiBjb2x1bW4gMy01DQogDQpgYGB7cn0NCkhfbWFpemUkcGl4ZWxTdW0gPXJvd1N1bXMoSF9tYWl6ZVssIDM6NV0sIG5hLnJtID0gVCkNCmBgYA0KDQpgYGB7ciBlY2hvPUZBTFNFfQ0KSF9tYWl6ZQ0KYGBgDQoNCg0KQXJlYSBpbiBoYSwgMSBwaXhlbCBpcyA5MDBtsiwgdGh1cyB0aGUgbnVtYmVyIG9mIHBpeGVsIG5lZWRzIHRvIGJlIG11bHRpcGxpZWQgd2l0aCAwLjA5IHRvIGdldCBoYQ0KYGBge3J9DQpIX21haXplJEgwQXJlYT1IX21haXplJFgwKjAuMDkgDQpIX21haXplJEgxQXJlYT1IX21haXplJFgxKjAuMDkgDQpIX21haXplJEgyQXJlYT1IX21haXplJFgyKjAuMDkNCmBgYA0KDQpgYGB7ciBlY2hvPUZBTFNFfQ0KSF9tYWl6ZQ0KYGBgDQogDQoNCg0KDQpUaGUgZXhwZWN0ZWQgYXJlYSB0byBiZSBoYXJ2ZXN0ZWQgaXMgdGhlIHRvdGFsIG1haXplIGNyb3AgYXJlYShIMCwgSDEsIGFuZCBIMikNCg0KU2lnbiAgfERyb3VnaHQgSW1wYWN0IGNsYXNzDQotLS0tLS18LS0tLS0tLS0NCkgwICAgIHxOb3QgQWZmZWN0ZWQgTWFpemUgTGFuZA0KSDEgICAgfERhbWFnZWQgTWFpemUgTGFuZA0KSDIgICAgfERlc3RyeWVkIE1haXplIExhbmQNCg0KDQpgYGB7cn0NCkhfbWFpemUkZXhwZWN0ZWQ9SF9tYWl6ZSRIMEFyZWErIEhfbWFpemUkSDFBcmVhKyBIX21haXplJEgyQXJlYSANCmBgYA0KDQpUaGUgYWN0dWFsIGFyZWEgaXMgdGhlIGhhcnZlc3RlZCBhcmVhIChIMCBhbmQgSDEpDQoNCmBgYHtyfQ0KSF9tYWl6ZSRhY3R1YWw9SF9tYWl6ZSRIMEFyZWErIEhfbWFpemUkSDFBcmVhDQpgYGANCg0KQ29tcHV0ZSBUaGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBleHBlY3RlZCBoYXZlc3QgaGVjdGFyZSBhbmQgdGhlIGFjdHVhbCBoYXJ2ZXN0ZWQgaGVjdGFyZQ0KYGBge3J9DQpIX21haXplJGRlbHRhSGE9IEhfbWFpemUkZXhwZWN0ZWQgLSBIX21haXplJGFjdHVhbA0KYGBgDQoNCmBgYHtyIGVjaG89RkFMU0V9DQpIX21haXplDQpgYGANCioqKioqDQo+ICMjIyMjIFtTdGVwIDMuMyBvZiA0IENhbGN1bGF0ZSBjaGFuZ2UgaW4geWllbGQgKGRlbHRhWSldKCMpe25hbWU9My4zfQ0KDQoqKioqKg0KDQoqKk5vdGU6KiogQWRkIHRoZSB5aWVsZCBkYXRhIChpbmNsdWRpbmcgdGhlIGF2ZXJhZ2UgeWllbGQgMjAxMC0yMDE0KQ0KDQpgYGB7cn0NCm1haXplWWllbGQyMDE1IDwtcmVhZC5jc3YoIi4vWTIwMDQtMjAxNS9ZaWVsZFN0YXRNYWl6ZS5jc3YiKQ0KYGBgDQoNCmBgYHtyIGVjaG89RkFMU0V9DQptYWl6ZVlpZWxkMjAxNQ0KYGBgDQoNCg0KY29tcHV0ZSBmb3IgYXZlcmFnZSBpZiB0aGUgYXZlcmFnZSB5aWVsZCB3YXMgbm90IHlldCBjYWxjdWxhdGVkDQoNCmBgYHtyIGV2YWw9RkFMU0V9DQoNCm1haXplWWllbGQyMDE1JGF2ZzwtKChtYWl6ZVlpZWxkMjAxNSRYMjAxMCArIG1haXplWWllbGQyMDE1JFgyMDExKyBtYWl6ZVlpZWxkMjAxNSRYMjAxMmkrIG1haXplWWVsZDIwMTUkWDIwMTMrIG1haXplWWllbGQyMDE1JFgyMDE0KS81KQ0KDQpgYGANCg0KUmVtb3ZlIGFsbCB5aWVsZCBkYXRhIGZyb20gb3RoZXIgeWVhcnMgdGhhbiAyMDE1LCBhdmcgYW5kIHRoZSBJRCB3aGljaCBpcyByZXF1aXJlZA0KDQpgYGB7cn0NCm1haXplWWllbGQyMDE1PC1zdWJzZXQobWFpemVZaWVsZDIwMTUsIHNlbGVjdCA9IGMoSUQsWDIwMTUsYXZnKSkNCmBgYA0KDQoNCg0KYGBge3IgZWNobyA9IEZBTFNFfQ0KbWFpemVZaWVsZDIwMTUNCmBgYA0KDQptdWx0aXBseSB3aXRoIDAuMSBmb3IgY29udmVyc2lvbiBmcm9tIGNlbnRuZXIgdG8gdG9ucyANCmBgYHtyfQ0KbWFpemVZaWVsZDIwMTUkZGVsdGFZPC0obWFpemVZaWVsZDIwMTUkYXZnIC0gbWFpemVZaWVsZDIwMTUkWDIwMTUpKjAuMQ0KYGBgDQoNCmBgYHtyIGVjaG89RkFMU0V9DQptYWl6ZVlpZWxkMjAxNQ0KYGBgDQoNClNldCBhbGwgdmFsdWVzIDwwID09MCB0byBhdm9pZCBwb3NpdGl2ZSBsb3NzZXMNCg0KYGBge3J9DQptYWl6ZVlpZWxkMjAxNSRkZWx0YVk8LXJlcGxhY2UobWFpemVZaWVsZDIwMTUkZGVsdGFZLCBtYWl6ZVlpZWxkMjAxNSRkZWx0YVk8MCwgMCkNCmBgYA0KDQpgYGB7ciBlY2hvPUZBTFNFfQ0KbWFpemVZaWVsZDIwMTUNCmBgYA0KDQoNCkFkZCB0aGUgeWllbGQgZGF0YSB0byBtYWl6ZSBkcm91Z2h0IGltcGFjdA0KYGBge3J9DQpIX21haXplWWllbGQgPSBtZXJnZShtYWl6ZVlpZWxkMjAxNSxIX21haXplLCBieSA9IklEIikNCmBgYA0KDQpsb29rIHVwIHRoZSBwcmljZSBmcm9tIHRoZSBwYWdlICoqKiBBZ3JpY3VsdHVyYWxvdXRwdXQgcHJpY2VzKioqIGZyb20gdGhlIHByaWNlIGV4Y2VsIGRvY3VtZW50IFVBX1dQMV9jb25zb2xpZGF0ZWQtZGF0YWJhc2VfVVNEIHRoZSB0YWJsZSBmb3IgdGhlIHllYXIgMjAxNSBhbmQgYWRkIGl0IGFzIGEgY29sdW1uIA0KYGBge3J9DQpIX21haXplWWllbGQkUD0xMjcuNw0KYGBgDQoNCmBgYHtyIGVjaG89RkFMU0V9DQpIX21haXplWWllbGQNCmBgYA0KKioqKg0KPiAjIyMjIyBbU3RlcCA0IG9mIDQgT3V0cHV0cyBhbmQgZmluYWwgcmVzdWx0cyBdKCMpe25hbWU9NH0NCg0KKioqKg0KDQoqKioqDQo+ICMjIyMjIFtTdGVwIDQgb2YgNC4xIExvc3Mgb24gRGVzdHJveWVkIEFyZWEgKEMyQzIpIGluIFUuUy4gRG9sbGFyc10oIyl7bmFtZT00LjF9DQoNCioqKioNCg0KKioqIFBsZWFzZSBpbnNwZWN0IHRoZSB0YWJsZXMgZm9yIGNsZWFyaXR5IG9uIHRoZSBkZXZlbG9wZWQgbWV0aG9kb2xvZ3kqKioNCmBgYHtyfQ0KSF9tYWl6ZVlpZWxkJEMyQzI9IEhfbWFpemVZaWVsZCRQKiBIX21haXplWWllbGQkZGVsdGFIYSogbWFpemVZaWVsZDIwMTUkYXZnDQpgYGANCg0KYGBge3IgZWNobz1GQUxTRX0NCkhfbWFpemVZaWVsZA0KYGBgDQoNCioqKioNCj4gIyMjIyMgW1N0ZXAgNCBvZiA0LjIgTG9zcyBvbiBEYW1hZ2VkIEFyZWEgKEMyQzEpIGluIFUuUy4gRG9sbGFycyAgXSgjKXtuYW1lPTQuMn0NCg0KKioqKg0KDQpgYGB7cn0NCkhfbWFpemVZaWVsZCRDMkMxPSBIX21haXplWWllbGQkUCogSF9tYWl6ZVlpZWxkJGRlbHRhWSogSF9tYWl6ZVlpZWxkJEgxQXJlYQ0KYGBgDQoNCmBgYHtyfQ0KSF9tYWl6ZVlpZWxkDQpgYGANCg0KKioqKg0KPiAjIyMjIyBbU3RlcCA0IG9mIDQuMyBNYWl6ZSBwcm9kdWN0aW9uIGxvc3NlcyBmb3IgMjAxNSAgXSgjKXtuYW1lPTQuM30NCg0KKioqKg0KU3VtIG9mIGRhbWFnZWQgYW5kIGRlc3Ryb3llZCBtYWl6ZSBwZXIgUmF5b24NCmBgYHtyfQ0KSF9tYWl6ZVlpZWxkJG1haXplTG9zczIwMTU9IEhfbWFpemVZaWVsZCRDMkMxK0hfbWFpemVZaWVsZCRDMkMyDQpgYGANCg0KYGBge3IgZWNobz1GQUxTRX0NCkhfbWFpemVZaWVsZA0KYGBgDQoNClRvdGFsIGxvc3MgaW4gbWFpemUgcHJvZHVjdGlvbg0KYGBge3J9DQpvdmVyYWxsTG9zc01haXplIDwtc3VtIChIX21haXplWWllbGQgJCBtYWl6ZUxvc3MyMDE1LCBuYS5ybT0gVCkNCmBgYA0KDQoqKk92ZXJhbGwgRWNvbm9taWMgVmFsdWUgb2YgbWFpemUgTG9zcyBpbiBVLlMuRCAkMjkxNDkzOTkyICoqDQpgYGB7ciB9DQpvdmVyYWxsTG9zc01haXplDQpgYGANClN0b3JlIHRoZSBvdXRwdXQgQ1NWIEhfbWFpemVZaWVsZCBhcyBIX0xvc3NNYWl6ZS5jc3YgaW4gdGhlIG91dHB1dCBmaWxlDQpgYGB7ciBldmFsPUZBTFNFfQ0Kd3JpdGUuY3N2KEhfbWFpemVZaWVsZCwgIi4vb3V0cHV0cy9IX0xvc3NNYWl6ZS5jc3YiKQ0KYGBgDQpPcHRpb25hbHkgOiBpZiB5b3Ugd2FudCB0byBoYXZlIGEgc2hhcGVmaWxlIHdpdGggdGhlc2UgaW5mb3JtYXRpb24sIHRoZSBvdXRwdXQgY2FuIGJlIG1lcmdlZCB3aXRoIHRoZSBhZG0gc2hhcGVmaWxlIA0KYGBge3J9DQptPC1tZXJnZShhZG0yLCBIX21haXplWWllbGQsIGJ5PSJJRCIpDQpgYGANCg0KYGBge3IgZWNobz1GQUxTRX0NCm0NCmBgYA0KDQp3cml0ZSBTaGFwZWZpbGUgd2l0aCBhbGwgaW5mb3JtYXRpb24gdG8gb3V0cHV0cyBmb2xkZXINCmBgYHtyIGV2YWw9RkFMU0V9DQp3cml0ZU9HUihtLCIuL291dHB1dHMvSF9Mb3NzTWFpemUyMDE1LnNocCIsICJMb3NzTWFpemUyMDE1IiwgZHJpdmVyID0gIkVTUkkgU2hhcGVmaWxlIiApDQpgYGANCioqKioqKioqDQoqKioqKioqKg0KKipFTkQqKg0K