Economic Value of direct maize production losses
Sub-indicator:– Direct Crop Loss (C2c)

Table of Contents

Part. C

Part. D

Part. C



Step 0 of 4 Technical Guidance Sub-indicator

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)


Step 1 of 4 Installing required packages and creating directories

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")

Step 2 of 4 Data preparation


Step 2.1 of 4 Resample H2015_250m to 30m

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)

CODE Land Cover
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")

Step 2.2 of 4 Maize2015: Extract relevant LC from LC2015 (maize in LC map=5)

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")

Step 2.3 of 4 subsetting Kiev region from the Ukraine administrative area

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

Part. D



Step 3 of 4 Processing


Step 3.1 of 4 Overlay the agricultural drought impact map (H2015), maize land cover for 2015 (LC2015) and Kiev map (adm2) to extract statistics

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")

Step 3.2 of 4 Calculate expected and actual harvested ha to get deltaHa

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)

Sign Drought Impact class
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

Step 3.3 of 4 Calculate change in yield (deltaY)

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

Step 4 of 4 Outputs and final results


Step 4 of 4.1 Loss on Destroyed Area (C2C2) in U.S. Dollars

*** Please inspect the tables for clearity on the developed methodology***

H_maizeYield$C2C2= H_maizeYield$P* H_maizeYield$deltaHa* maizeYield2015$avg

Step 4 of 4.2 Loss on Damaged Area (C2C1) in U.S. Dollars

H_maizeYield$C2C1= H_maizeYield$P* H_maizeYield$deltaY* H_maizeYield$H1Area
H_maizeYield

Step 4 of 4.3 Maize production losses for 2015

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