Milkias Z. SEMEREAB

GEOL0097-Geostatistics, University of Liège

October 21, 2022


Meuse river data set

For this project, you will use the Meuse dataset that is available in CSV format (comma separated values). This data set gives locations and top soil heavy metal concentrations (ppm), along with a number of soil and landscape variables, collected in a flood plain of the river Meuse, near the village Stein. Heavy metal concentrations are bulk sampled from an area of approximately 15 m x 15 m.

Format: The data frame contains the following columns:

References

P.A. Burrough, R.A. McDonnell, 1998. Principles of Geographical Information Systems. Oxford University Press.

Task 1: Loading the dataset

• Create your working directory: The working directory/working folder is the default location where R will look for files that you want to load and where it will put any files you save. You can Create your working directory in 2 ways:

To create a new project in Rstudio: File > New Project > New Directory > New Project > Type in the name of the directory to store your project, e.g. “meuse_project”

The first method is highly recommended. Once you create the project, use the getwd() function to make sure your default working directory is created.

 # Show where your working directory was created:
getwd()
[1] "D:/GEO-STATISTICS COURSE/2022-23/GST_Practical/R-Markdown and Notebooks"

• Load the “meuse dataset” into the workspace using the read.csv() function and store the dataframe as variable called “data”.

data = read.csv("meuse_data.csv")

Note: the meuse.csv dataset should be inside the working directory, otherwise R won’t be able to find the file and will therefore throw an error.

Task 2: Quick Exploratory Data Analysis (EDA)

To have a look at your dataset, you can use the following methods:

head(data)
tail(data)
str(data)
'data.frame':   155 obs. of  13 variables:
 $ x      : num  181072 181025 181165 181298 181307 ...
 $ y      : num  333611 333558 333537 333484 333330 ...
 $ cadmium: num  11.7 8.6 6.5 2.6 2.8 3 3.2 2.8 2.4 1.6 ...
 $ copper : num  85 81 68 81 48 61 31 29 37 24 ...
 $ lead   : num  299 277 199 116 117 137 132 150 133 80 ...
 $ zinc   : num  1022 1141 640 257 269 ...
 $ elev   : num  7.91 6.98 7.8 7.66 7.48 7.79 8.22 8.49 8.67 9.05 ...
 $ om     : num  13.6 14 13 8 8.7 7.8 9.2 9.5 10.6 6.3 ...
 $ ffreq  : int  1 1 1 1 1 1 1 1 1 1 ...
 $ soil   : int  1 1 1 2 2 2 2 1 1 2 ...
 $ lime   : int  1 1 1 0 0 0 0 0 0 0 ...
 $ landuse: chr  "Ah" "Ah" "Ah" "Ga" ...
 $ dist   : num  50 30 150 270 380 470 240 120 240 420 ...

Questions:


Task 3: Spatial Data Visualization

• Visualization of samples location

plot(data[,1],data[,2],pch=16,cex=0.5, xlab = "Easting(m)", ylab = "Northing(m)",main="Sample Locations",asp=1)

The plot() function took the following arguments:

Questions:

• Visualization of data distribution

Visualization of heavy metal concentrations in relation to spatial locations.

# cadmium
plot(data[,1],data[,2],pch=16,cex=2*(data[ ,3] - min(data[ ,3]))/(max
(data[ ,3]) - min(data[ ,3])),xlab = "Easting(m)", ylab = "Northing(m)", main="cadmium concentrations (ppm)",asp=1)

# copper
plot(data[,1],data[,2],pch=16,cex=2*(data[ ,4] - min(data[ ,4]))/(max
(data[ ,4]) - min(data[ ,4])),xlab = "Easting(m)",ylab = "Northing(m)", main="copper concentrations (ppm)",asp=1)

# lead
plot(data[,1],data[,2],pch=16,cex=2*(data[ ,5] - min(data[ ,5]))/(max
(data[ ,5]) - min(data[ ,5])),xlab = "Easting(m)", ylab = "Northing(m)", main="lead concentrations (ppm)",asp=1)

# zinc
plot(data[,1],data[,2],pch=16,cex=2*(data[ ,6] - min(data[ ,6]))/(max
(data[ ,6]) - min(data[ ,6])),xlab = "Easting(m)", ylab = "Northing(m)", main="zinc concentrations (ppm)",asp=1)

Questions:
- Can you see concentration anomalies?
- Can you observe any spatial regions with outliers (high heavy metal concentrations)?

Hint: The process governing heavy metal distribution seems that polluted sediment is carried by the river, and mostly deposited close to the river bank

Note: Although works well, the above block of code is not efficient. Whenever you write such code, try to use for loop to repeat a section of code a known number of times.

for(j in 1:4){
  plot(data[,1],data[,2],pch=16,cex=2*(data[,j+2]-min(data[,j+2]))/(max
  (data[,j+2])-min(data[,j+2])),xlab = "Easting(m)", ylab = "Northing(m)",
  main=paste(colnames(data)[j+2],"concentrations (ppm)",sep=" "),asp=1)
}

• Other way to visualize the Data using the library plot3D

Plot3D is an R package/library containing many functions for 2D and 3D plotting. To install any package in Rstudio:

install.packages("plot3D")

Once the package is installed, you have to import/load it to the workspace. You can do this either by:

library(plot3D)

scatter2D() is a function with in Plot3D library that is used to polt a Colored scatter plots with a color variable as points.

scatter2D(data[,1], data[,2],colvar=data[,6],pch = 16, xlab = "Easting(m)", ylab = "Northing(m)",clab="zinc",main="zinc concentrations(ppm)", asp=1)

• Visualization of categorical Variables (e.g., Soil Type)
scatter2D(data[,1],data[,2],colvar=data[,10],col=c("blue", "green", "brown"),pch=16, xlab="Easting(m)", ylab="Northing(m)", clab=colnames(data)[10],main="Soil Type", asp=1, cex=0.8)

# Add legend to the plot using the legend() function
legend("bottomright",legend=c("Soil - 1","Soil - 2", "Soil - 3"), fill=c("blue", "green", "brown"), cex=1)

Task 4: Univariate EDA

• Compute the main descriptive univariate statistics for the 4 heavy metals

summary(data[ ,3:6])
    cadmium           copper            lead            zinc       
 Min.   : 0.200   Min.   : 14.00   Min.   : 37.0   Min.   : 113.0  
 1st Qu.: 0.800   1st Qu.: 23.00   1st Qu.: 72.5   1st Qu.: 198.0  
 Median : 2.100   Median : 31.00   Median :123.0   Median : 326.0  
 Mean   : 3.246   Mean   : 40.32   Mean   :153.4   Mean   : 469.7  
 3rd Qu.: 3.850   3rd Qu.: 49.50   3rd Qu.:207.0   3rd Qu.: 674.5  
 Max.   :18.100   Max.   :128.00   Max.   :654.0   Max.   :1839.0  

Questions:

• Display histograms and boxplots of all four heavy metals concentrations

hist(data$cadmium, col="blue", xlab="Values",main="cadmium concentrations")

hist(data$copper,col="blue", xlab="Values",main="copper concentrations")

hist(data$lead,col="blue", xlab="Values",main="lead concentrations")

hist(data$zinc,col="blue", xlab="Values",main="zinc concentrations")

boxplot(data$cadmium,col="blue", xlab="Values",main="cadmium concentrations")

boxplot(data$copper,col="blue", xlab="Values",main="copper concentrations")

boxplot(data$lead,col="blue", xlab="Values",main="lead concentrations")

boxplot(data$zinc,col="blue", xlab="Values",main="zinc concentrations")

Questions:


Task 5: Log-Transform the data

The log transformation can be used to make highly skewed distributions less skewed. This can be valuable both for making patterns in the data more interpretable and for helping to meet the assumptions of inferential statistics.

Heavy metal concentration usually is not symmetric. Log-transform the highly-skewed distribution. Using the log10() function add four columns to the dataframe (one for each log transformed heavy metal concentration).

data$logCd = log10(data$cadmium)
data$logCu = log10(data$copper)
data$logPb = log10(data$lead)
data$logZn = log10(data$zinc)

• Display histograms and boxplots of raw and log transformed heavy metals concentrations side by side

# use par() function to convert the graphical window into 2-by-1 sub-screens 
par(mfrow=c(1,2)) 

#  Display histograms of raw and log transformed data
for(j in 1:4){
  hist(data[,j+2],col="blue", xlab="Values",main=colnames(data)[j+2])
  hist(data[,j+13],col="red", xlab="Values",main=colnames(data)[j+13])
}

par(mfrow=c(1,2)) 

#  Display boxplot of raw and log transformed data
for(j in 1:4){
  boxplot(data[,j+2],col="blue", xlab="Values",main=colnames(data)[j+2])
  boxplot(data[,j+13],col="red", xlab="Values",main=colnames(data)[j+13])
}

Questions:
- Difference of distribution between the raw data and log-transformed?
- Is the skewness of original distribution changed remarkably?


Task 6: Statistics vs category

• Compute summary statistics (e.g. mean) of all four heavy metal concentrations by some categorical variables (e.g. soil type)

aggregate(data[ ,3:6], by=list(data$soil), FUN=mean, na.rm=TRUE)

• Display the histogram and boxplot of heavy metals concentrations by some categorical variables

To do this task, you can use histogram() function from the lattice library and the already familar boxplot() function from the R-Base.

# First install and load the lattice library
install.packages("lattice")
library(lattice)
# Histogram of zinc concentrations for each soil type
histogram(~ data$zinc|as.factor(data$soil),col="blue",xlab= "Zinc concerntration")


# boxplot of zinc concentration for flood frequencies 
boxplot(data$zinc ~ data$ffreq, col="blue",xlab="Flood Frequency Class", 
ylab= "Zinc concerntration")

Questions:


Task 7: Bivariate EDA

• Plot scatter plots between two variables (for e.g. zinc and copper)

plot(data$zinc ~ data$copper, xlab="Copper concentration", ylab="zinc concentration")


plot(data$logZn ~ data$logCu, xlab="log10 Copper concentration", ylab="log10 zinc concentration")

Questions:

• Observe the samples that do not fit the general pattern

ix=which((data$logZn < 2.6) & (data$logCu > 1.6))
print(ix)
[1]   4   5   6 135
print(data[ix, ])

• Compute the scatter plot matrix for all pairs of variables using pair() function

pairs(data[ ,3:6], pch = 19, cex=0.5)

pairs(data[ ,14:17], pch = 19, cex=0.5)

• Compute the Pearson correlation matrix

CorMat = cor(data[ ,3:6])
print(CorMat) 
          cadmium    copper      lead      zinc
cadmium 1.0000000 0.9254499 0.7989466 0.9162139
copper  0.9254499 1.0000000 0.8183069 0.9082695
lead    0.7989466 0.8183069 1.0000000 0.9546913
zinc    0.9162139 0.9082695 0.9546913 1.0000000
# Comput Pearson correlation matrix for log-transformed variables
CorMatLog = cor(data[ ,14:17])
print(CorMatLog) 
          logCd     logCu     logPb     logZn
logCd 1.0000000 0.8363329 0.8124522 0.8624475
logCu 0.8363329 1.0000000 0.8428929 0.8971515
logPb 0.8124522 0.8428929 1.0000000 0.9671621
logZn 0.8624475 0.8971515 0.9671621 1.0000000

Questions:
- Discuss the relationship between the pairs of variables ? The nature (sign) and strength of the relationships?
- The possible reason behind this type of correlation between the heavy metals?

• Compute the Pearson correlation matrix using Corrplot library

corrplot is an R package that provides a visual exploratory tool on correlation matrix that supports rich visualization method, graphic layout, color and legend. The corrplot() function takes an existing correlation matrix as argument

# Install and load corrplot package
install.packages("corrplot")
library(corrplot)
# Pearson Correlation Matrix 
corrplot(CorMat)

corrplot(CorMatLog)

LS0tDQp0aXRsZTogIkdlb3N0YXRpc3RpY3MgLSBVbml2YXJpYXRlIGFuZCBCaXZhcmlhdGUgQW5hbHlzaXMiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQoqTWlsa2lhcyBaLiBTRU1FUkVBQioNCg0KKkdFT0wwMDk3LUdlb3N0YXRpc3RpY3MsIFVuaXZlcnNpdHkgb2YgTGnDqGdlKg0KDQoqT2N0b2JlciAyMSwgMjAyMioNCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCg0KIyMjIyMgKipNZXVzZSByaXZlciBkYXRhIHNldCoqDQoNCkZvciB0aGlzIHByb2plY3QsIHlvdSB3aWxsIHVzZSB0aGUgTWV1c2UgZGF0YXNldCB0aGF0IGlzIGF2YWlsYWJsZSBpbiBDU1YgZm9ybWF0IChjb21tYSBzZXBhcmF0ZWQgdmFsdWVzKS4gVGhpcyBkYXRhIHNldCBnaXZlcyBsb2NhdGlvbnMgYW5kIHRvcCBzb2lsIGhlYXZ5IG1ldGFsIGNvbmNlbnRyYXRpb25zIChwcG0pLCBhbG9uZyB3aXRoIGEgbnVtYmVyIG9mIHNvaWwgYW5kIGxhbmRzY2FwZSB2YXJpYWJsZXMsIGNvbGxlY3RlZCBpbiBhIGZsb29kIHBsYWluIG9mIHRoZSByaXZlciBNZXVzZSwgbmVhciB0aGUgdmlsbGFnZSBTdGVpbi4gSGVhdnkgbWV0YWwgY29uY2VudHJhdGlvbnMgYXJlIGJ1bGsgc2FtcGxlZCBmcm9tIGFuIGFyZWEgb2YgYXBwcm94aW1hdGVseSAxNSBtIHggMTUgbS4NCg0KKipGb3JtYXQ6KioNClRoZSBkYXRhIGZyYW1lIGNvbnRhaW5zIHRoZSBmb2xsb3dpbmcgY29sdW1uczoNCg0KLSB4IGEgbnVtZXJpYyB2ZWN0b3I6IHgtY29vcmRpbmF0ZSAobSkgaW4gUkRNIChEdXRjaCB0b3BvZ3JhcGhpY2FsIG1hcCBjb29yZGluYXRlcykNCi0geSBhIG51bWVyaWMgdmVjdG9yOiB5LWNvb3JkaW5hdGUgKG0pIGluIFJETSAoRHV0Y2ggdG9wb2dyYXBoaWNhbCBtYXAgY29vcmRpbmF0ZXMpDQotIGNhZG1pdW06IHRvcHNvaWwgY2FkbWl1bSBjb25jZW50cmF0aW9uLCBwcG0NCi0gY29wcGVyOiB0b3Bzb2lsIGNvcHBlciBjb25jZW50cmF0aW9uLCBwcG0NCi0gbGVhZDogdG9wc29pbCBsZWFkIGNvbmNlbnRyYXRpb24sIHBwbQ0KLSB6aW5jOiB0b3Bzb2lsIHppbmMgY29uY2VudHJhdGlvbiwgcHBtDQotIGVsZXY6IHJlbGF0aXZlIGVsZXZhdGlvbg0KLSBvbTogb3JnYW5pYyBtYXR0ZXIsIGFzIHBlcmNlbnRhZ2UNCi0gZmZyZXE6IGZsb29kaW5nIGZyZXF1ZW5jeSBjbGFzcw0KLSBzb2lsOiBzb2lsIHR5cGUNCi0gbGltZTogbGltZSBjbGFzcw0KLSBsYW5kdXNlOiBsYW5kdXNlIGNsYXNzDQotIGRpc3Q6IGRpc3RhbmNlIHRvIHJpdmVyIE1ldXNlIChtZXRyZXMpLCANCg0KKipSZWZlcmVuY2VzKiogICAgDQoNClAuQS4gQnVycm91Z2gsIFIuQS4gTWNEb25uZWxsLCAxOTk4LiBQcmluY2lwbGVzIG9mIEdlb2dyYXBoaWNhbCBJbmZvcm1hdGlvbiBTeXN0ZW1zLiBPeGZvcmQgVW5pdmVyc2l0eSBQcmVzcy4NCg0KDQojIyMjICoqVGFzayAxOiBMb2FkaW5nIHRoZSBkYXRhc2V0KioNCg0KKirigKIgQ3JlYXRlIHlvdXIgd29ya2luZyBkaXJlY3Rvcnk6KiogVGhlIHdvcmtpbmcgZGlyZWN0b3J5L3dvcmtpbmcgZm9sZGVyIGlzIHRoZSBkZWZhdWx0IGxvY2F0aW9uIHdoZXJlIFIgd2lsbCBsb29rIGZvciBmaWxlcyB0aGF0IHlvdSB3YW50IHRvIGxvYWQgYW5kIHdoZXJlIGl0IHdpbGwgcHV0IGFueSBmaWxlcyB5b3Ugc2F2ZS4gWW91IGNhbiBDcmVhdGUgeW91ciB3b3JraW5nIGRpcmVjdG9yeSBpbiAyIHdheXM6DQoNCi0gT25lIG9mIHRoZSBncmVhdCB0aGluZ3MgYWJvdXQgdXNpbmcgUlN0dWRpbyBQcm9qZWN0cyBpcyB0aGF0IHdoZW4geW91IGNyZWF0ZSBhIG5ldyBwcm9qZWN0IG9yIG9wZW4gYW4gZXhpc3RpbmcgcHJvamVjdCwgaXQgd2lsbCBhdXRvbWF0aWNhbGx5IHNldCB5b3VyIHdvcmtpbmcgZGlyZWN0b3J5IHRvIHRoZSBhcHByb3ByaWF0ZSBsb2NhdGlvbi4NCg0KVG8gY3JlYXRlIGEgbmV3IHByb2plY3QgaW4gUnN0dWRpbzogKkZpbGUgXD4gTmV3IFByb2plY3QgXD4gTmV3IERpcmVjdG9yeSBcPiBOZXcgUHJvamVjdCBcPiBUeXBlIGluIHRoZSBuYW1lIG9mIHRoZSBkaXJlY3RvcnkgdG8gc3RvcmUgeW91ciBwcm9qZWN0LCBlLmcuICJtZXVzZV9wcm9qZWN0IioNCg0KLSBZb3UgY2FuIGFsc28gc2V0IHRoZSB3b3JraW5nIGRpcmVjdG9yeSBtYW51YWxseSB1c2luZyB0aGUgKipzZXR3ZCgpKiogZnVuY3Rpb24uDQoNClRoZSBmaXJzdCBtZXRob2QgaXMgaGlnaGx5IHJlY29tbWVuZGVkLiBPbmNlIHlvdSBjcmVhdGUgdGhlIHByb2plY3QsIHVzZSB0aGUgKipnZXR3ZCgpKiogZnVuY3Rpb24gdG8gbWFrZSBzdXJlIHlvdXIgZGVmYXVsdCB3b3JraW5nIGRpcmVjdG9yeSBpcyBjcmVhdGVkLg0KDQpgYGB7cn0NCiAjIFNob3cgd2hlcmUgeW91ciB3b3JraW5nIGRpcmVjdG9yeSB3YXMgY3JlYXRlZDoNCmdldHdkKCkNCmBgYA0KDQoqKuKAoiBMb2FkIHRoZSAibWV1c2UgZGF0YXNldCIqKiBpbnRvIHRoZSB3b3Jrc3BhY2UgdXNpbmcgdGhlICoqcmVhZC5jc3YoKSoqIGZ1bmN0aW9uIGFuZCBzdG9yZSB0aGUgZGF0YWZyYW1lIGFzIHZhcmlhYmxlIGNhbGxlZCAiZGF0YSIuDQoNCmBgYHtyfQ0KZGF0YSA9IHJlYWQuY3N2KCJtZXVzZV9kYXRhLmNzdiIpDQpgYGANCg0KKk5vdGU6KiB0aGUgbWV1c2UuY3N2IGRhdGFzZXQgc2hvdWxkIGJlIGluc2lkZSB0aGUgd29ya2luZyBkaXJlY3RvcnksIG90aGVyd2lzZSBSIHdvbid0IGJlIGFibGUgdG8gZmluZCB0aGUgZmlsZSBhbmQgd2lsbCB0aGVyZWZvcmUgdGhyb3cgYW4gZXJyb3IuDQoNCiMjIyMgKipUYXNrIDI6IFF1aWNrIEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMgKEVEQSkqKg0KDQpUbyBoYXZlIGEgbG9vayBhdCB5b3VyIGRhdGFzZXQsIHlvdSBjYW4gdXNlIHRoZSBmb2xsb3dpbmcgbWV0aG9kczoNCg0KLSAiRW52aXJvbm1lbnQiIHRhYiBpbiB0aGUgdG9wIHJpZ2h0IHdpbmRvdyBsaXN0cyB0aGUgdmFyaWFibGVzIGFuZCBmdW5jdGlvbnMgcHJlc2VudCBpbiB0aGUgY3VycmVudCBSIHNlc3Npb24uIFRvIGRpc3BsYXkgdGhlIGZ1bGwgZGF0YWZyYW1lLCBjbGljayBvbiB0aGUgImRhdGEiIHZhcmlhYmxlIG9uIHRoZSBFbnZpcm9ubWVudCB0YWIuDQoNCi0gV2hlbiB5b3Ugd29yayB3aXRoIGxhcmdlIGRhdGFzZXRzIGFuZCBkYXRhIGZyYW1lcywgeW91ciBmaXJzdCB0YXNrIGFzIGEgZ2Vvc3RhdGlzdGljaWFuIGlzIHRvIGRldmVsb3AgYSBjbGVhciB1bmRlcnN0YW5kaW5nIG9mIGl0cyBzdHJ1Y3R1cmUgYW5kIG1haW4gZWxlbWVudHMuIFRoZXJlZm9yZSwgaXQgaXMgb2Z0ZW4gdXNlZnVsIHRvIHNob3cgb25seSBhIHNtYWxsIHBhcnQgb2YgdGhlIGVudGlyZSBkYXRhc2V0LiBUaGUgZnVuY3Rpb24gKipoZWFkKCkqKiBlbmFibGVzIHlvdSB0byBzaG93IHRoZSBmaXJzdCBvYnNlcnZhdGlvbnMgb2YgYSBkYXRhIGZyYW1lLiBTaW1pbGFybHksIHRoZSBmdW5jdGlvbiAqKnRhaWwoKSoqIHByaW50cyBvdXQgdGhlIGxhc3Qgb2JzZXJ2YXRpb25zIGluIHlvdXIgZGF0YXNldC4NCg0KLSBBbm90aGVyIG1ldGhvZCB0aGF0IGlzIG9mdGVuIHVzZWQgdG8gZ2V0IGEgcmFwaWQgb3ZlcnZpZXcgb2YgeW91ciBkYXRhIGlzIHRoZSBmdW5jdGlvbiAqKnN0cigpKiogd2hpY2ggc2hvd3MgeW91IHRoZSBzdHJ1Y3R1cmUgb2YgeW91ciBkYXRhc2V0IGluY2x1ZGluZyB0aGUgdG90YWwgbnVtYmVyIG9mIG9ic2VydmF0aW9ucywgdGhlIHRvdGFsIG51bWJlciBvZiB2YXJpYWJsZXMsIHRoZSBkYXRhIHR5cGUgb2YgZWFjaCB2YXJpYWJsZSBhbmQgdGhlIGZpcnN0IG9ic2VydmF0aW9ucyBldGMuLg0KDQpgYGB7cn0NCmhlYWQoZGF0YSkNCnRhaWwoZGF0YSkNCnN0cihkYXRhKQ0KYGBgDQoNCioqUXVlc3Rpb25zOioqDQoNCi0gSG93IG1hbnkgb2JzZXJ2YXRpb25zIChzYW1wbGVzIG9yIGRhdGEgcG9pbnRzKSBhbmQgdmFyaWFibGVzIChmaWVsZHMgb3IgYXR0cmlidXRlcykgdGhlIG1ldXNlIGRhdHNldCBoYXZlPw0KDQotIFdoaWNoIHZhcmlhYmxlcyBjb250YWluIHRoZSBzcGF0aWFsIGRhdGEgPyAobm90ZTogc3BhdGlhbCA9IGdlb2dyYXBoaWNhbCBsb2NhdGlvbikNCg0KLSBIb3cgbWFueSBjb250aW51b3VzIHZhcmlhYmxlcyBhcmUgdGhlcmU/IEhvdyBtYW55IGNhdGVnb3JpY2FsIHZhcmlhYmxlcyBhcmUgdGhlcmU/ICANCiAgDQo8YnI+DQogICAgDQoNCiMjIyMgKipUYXNrIDM6IFNwYXRpYWwgRGF0YSBWaXN1YWxpemF0aW9uKioNCg0KKirigKIgVmlzdWFsaXphdGlvbiBvZiBzYW1wbGVzIGxvY2F0aW9uKioNCg0KYGBge3J9DQpwbG90KGRhdGFbLDFdLGRhdGFbLDJdLHBjaD0xNixjZXg9MC41LCB4bGFiID0gIkVhc3RpbmcobSkiLCB5bGFiID0gIk5vcnRoaW5nKG0pIixtYWluPSJTYW1wbGUgTG9jYXRpb25zIixhc3A9MSkNCmBgYA0KDQpUaGUgcGxvdCgpIGZ1bmN0aW9uIHRvb2sgdGhlIGZvbGxvd2luZyBhcmd1bWVudHM6DQoNCi0gZGF0YVsgLDFdIGFuZCBkYXRhWyAsMl0gPSB0aGUgbGF0aXR1ZGUvWCBhbmQgbG9uZ2l0dWRlL1kgb2YgYWxsIHRoZSBzYW1wbGUgcG9pbnRzLg0KLSBwY2ggPSBQbG90IGNoYXJhY3Rlci4gVHJ5IHRvIGNoYW5nZSBwY2ggdG8gYW55IG90aGVyIG51bWJlciBiZXR3ZWVuIDEgYW5kIDI1Lg0KLSBjZXggPSBwb2ludCBzaXplDQotIHhsYWIsIHlsYWIgYW5kIG1haW4gPSB0byBwdXQgdGV4dCBsYWJlbCBmb3IgdGhlIHgtYXhpcywgeS1heGlzIGFuZCBoZWFkIHJlc3BlY3RpdmVseS4NCi0gYXNwID0gc2V0IHRoZSBhc3BlY3QgcmF0aW8gb2YgdGhlIHBsb3QNCg0KDQoqKlF1ZXN0aW9uczoqKg0KDQotIFdoYXQgY2FuIHlvdSB0ZWxsIGFib3V0IHRoZSBzYW1wbGluZyBjYW1wYWlnbihzKT8NCi0gRG8geW91IGhhdmUgY2x1c3RlcnM/DQoNCg0KKirigKIgVmlzdWFsaXphdGlvbiBvZiBkYXRhIGRpc3RyaWJ1dGlvbioqDQoNClZpc3VhbGl6YXRpb24gb2YgaGVhdnkgbWV0YWwgY29uY2VudHJhdGlvbnMgaW4gcmVsYXRpb24gdG8gc3BhdGlhbCBsb2NhdGlvbnMuDQoNCmBgYHtyfQ0KIyBjYWRtaXVtDQpwbG90KGRhdGFbLDFdLGRhdGFbLDJdLHBjaD0xNixjZXg9MiooZGF0YVsgLDNdIC0gbWluKGRhdGFbICwzXSkpLyhtYXgNCihkYXRhWyAsM10pIC0gbWluKGRhdGFbICwzXSkpLHhsYWIgPSAiRWFzdGluZyhtKSIsIHlsYWIgPSAiTm9ydGhpbmcobSkiLCBtYWluPSJjYWRtaXVtIGNvbmNlbnRyYXRpb25zIChwcG0pIixhc3A9MSkNCiMgY29wcGVyDQpwbG90KGRhdGFbLDFdLGRhdGFbLDJdLHBjaD0xNixjZXg9MiooZGF0YVsgLDRdIC0gbWluKGRhdGFbICw0XSkpLyhtYXgNCihkYXRhWyAsNF0pIC0gbWluKGRhdGFbICw0XSkpLHhsYWIgPSAiRWFzdGluZyhtKSIseWxhYiA9ICJOb3J0aGluZyhtKSIsIG1haW49ImNvcHBlciBjb25jZW50cmF0aW9ucyAocHBtKSIsYXNwPTEpDQojIGxlYWQNCnBsb3QoZGF0YVssMV0sZGF0YVssMl0scGNoPTE2LGNleD0yKihkYXRhWyAsNV0gLSBtaW4oZGF0YVsgLDVdKSkvKG1heA0KKGRhdGFbICw1XSkgLSBtaW4oZGF0YVsgLDVdKSkseGxhYiA9ICJFYXN0aW5nKG0pIiwgeWxhYiA9ICJOb3J0aGluZyhtKSIsIG1haW49ImxlYWQgY29uY2VudHJhdGlvbnMgKHBwbSkiLGFzcD0xKQ0KIyB6aW5jDQpwbG90KGRhdGFbLDFdLGRhdGFbLDJdLHBjaD0xNixjZXg9MiooZGF0YVsgLDZdIC0gbWluKGRhdGFbICw2XSkpLyhtYXgNCihkYXRhWyAsNl0pIC0gbWluKGRhdGFbICw2XSkpLHhsYWIgPSAiRWFzdGluZyhtKSIsIHlsYWIgPSAiTm9ydGhpbmcobSkiLCBtYWluPSJ6aW5jIGNvbmNlbnRyYXRpb25zIChwcG0pIixhc3A9MSkNCmBgYA0KKipRdWVzdGlvbnM6KiogICANCi0gQ2FuIHlvdSBzZWUgY29uY2VudHJhdGlvbiBhbm9tYWxpZXM/ICAgDQotIENhbiB5b3Ugb2JzZXJ2ZSBhbnkgc3BhdGlhbCByZWdpb25zIHdpdGggb3V0bGllcnMgKGhpZ2ggaGVhdnkgbWV0YWwgY29uY2VudHJhdGlvbnMpPw0KDQoqKipIaW50OiBUaGUgcHJvY2VzcyBnb3Zlcm5pbmcgaGVhdnkgbWV0YWwgZGlzdHJpYnV0aW9uIHNlZW1zIHRoYXQgcG9sbHV0ZWQgc2VkaW1lbnQgaXMgY2FycmllZCBieSB0aGUgcml2ZXIsIGFuZCBtb3N0bHkgZGVwb3NpdGVkIGNsb3NlIHRvIHRoZSByaXZlciBiYW5rKioqDQoNCioqTm90ZToqKiBBbHRob3VnaCB3b3JrcyB3ZWxsLCB0aGUgYWJvdmUgYmxvY2sgb2YgY29kZSBpcyBub3QgZWZmaWNpZW50LiBXaGVuZXZlciB5b3Ugd3JpdGUgc3VjaCBjb2RlLCB0cnkgdG8gdXNlICoqZm9yIGxvb3AqKiB0byByZXBlYXQgYSBzZWN0aW9uIG9mIGNvZGUgYSBrbm93biBudW1iZXIgb2YgdGltZXMuDQoNCmBgYHtyfQ0KZm9yKGogaW4gMTo0KXsNCiAgcGxvdChkYXRhWywxXSxkYXRhWywyXSxwY2g9MTYsY2V4PTIqKGRhdGFbLGorMl0tbWluKGRhdGFbLGorMl0pKS8obWF4DQogIChkYXRhWyxqKzJdKS1taW4oZGF0YVssaisyXSkpLHhsYWIgPSAiRWFzdGluZyhtKSIsIHlsYWIgPSAiTm9ydGhpbmcobSkiLA0KICBtYWluPXBhc3RlKGNvbG5hbWVzKGRhdGEpW2orMl0sImNvbmNlbnRyYXRpb25zIChwcG0pIixzZXA9IiAiKSxhc3A9MSkNCn0NCmBgYA0KDQoqKuKAoiBPdGhlciB3YXkgdG8gdmlzdWFsaXplIHRoZSBEYXRhIHVzaW5nIHRoZSBsaWJyYXJ5ICpwbG90M0QqKioNCg0KUGxvdDNEIGlzIGFuIFIgcGFja2FnZS9saWJyYXJ5IGNvbnRhaW5pbmcgbWFueSBmdW5jdGlvbnMgZm9yIDJEIGFuZCAzRCBwbG90dGluZy4gVG8gaW5zdGFsbCBhbnkgcGFja2FnZSBpbiBSc3R1ZGlvOg0KDQotIEdvIHRvICJwYWNrYWdlcyIgdGFiIFw+IGNsaWNrICJpbnN0YWxsIiBcPiB0eXBlICJwbG90M0QiIGFuZCBjbGljayBpbnN0YWxsDQotIE9yIHVzZSB0aGUgZnVuY3Rpb24gKippbnN0YWxsLnBhY2thZ2VzKCkqKg0KDQpgYGB7cn0NCmluc3RhbGwucGFja2FnZXMoInBsb3QzRCIpDQpgYGANCg0KT25jZSB0aGUgcGFja2FnZSBpcyBpbnN0YWxsZWQsIHlvdSBoYXZlIHRvIGltcG9ydC9sb2FkIGl0IHRvIHRoZSB3b3Jrc3BhY2UuIFlvdSBjYW4gZG8gdGhpcyBlaXRoZXIgYnk6DQoNCi0gU2ltcGx5aW5nIGNoZWNraW5nIHRoZSBjaGVja2JveCBiZXNpZGUgdGhlIHBhY2thZ2UgbmFtZSAiUGxvdDNEIiBpbiB0aGUgUGFja2FnZXMgdGFiDQotIFVzaW5nIHRoZSBsaWJyYXJ5KCkgZnVuY3Rpb24gdG8gbG9hZCBwYWNrYWdlcyB3aGljaCBhcmUgYWxyZWFkeSBpbnN0YWxsZWQuDQoNCmBgYHtyfQ0KbGlicmFyeShwbG90M0QpDQpgYGANCg0KKipzY2F0dGVyMkQoKSoqIGlzIGEgZnVuY3Rpb24gd2l0aCBpbiAqKlBsb3QzRCoqIGxpYnJhcnkgdGhhdCBpcyB1c2VkIHRvIHBvbHQgYSBDb2xvcmVkIHNjYXR0ZXIgcGxvdHMgd2l0aCBhIGNvbG9yIHZhcmlhYmxlIGFzIHBvaW50cy4NCg0KYGBge3J9DQpzY2F0dGVyMkQoZGF0YVssMV0sIGRhdGFbLDJdLGNvbHZhcj1kYXRhWyw2XSxwY2ggPSAxNiwgeGxhYiA9ICJFYXN0aW5nKG0pIiwgeWxhYiA9ICJOb3J0aGluZyhtKSIsY2xhYj0iemluYyIsbWFpbj0iemluYyBjb25jZW50cmF0aW9ucyhwcG0pIiwgYXNwPTEpDQpgYGANCg0KIyMjIyMgKirigKIgVmlzdWFsaXphdGlvbiBvZiBjYXRlZ29yaWNhbCBWYXJpYWJsZXMgKGUuZy4sIFNvaWwgVHlwZSkqKg0KDQpgYGB7cn0NCnNjYXR0ZXIyRChkYXRhWywxXSxkYXRhWywyXSxjb2x2YXI9ZGF0YVssMTBdLGNvbD1jKCJibHVlIiwgImdyZWVuIiwgImJyb3duIikscGNoPTE2LCB4bGFiPSJFYXN0aW5nKG0pIiwgeWxhYj0iTm9ydGhpbmcobSkiLCBjbGFiPWNvbG5hbWVzKGRhdGEpWzEwXSxtYWluPSJTb2lsIFR5cGUiLCBhc3A9MSwgY2V4PTAuOCkNCg0KIyBBZGQgbGVnZW5kIHRvIHRoZSBwbG90IHVzaW5nIHRoZSBsZWdlbmQoKSBmdW5jdGlvbg0KbGVnZW5kKCJib3R0b21yaWdodCIsbGVnZW5kPWMoIlNvaWwgLSAxIiwiU29pbCAtIDIiLCAiU29pbCAtIDMiKSwgZmlsbD1jKCJibHVlIiwgImdyZWVuIiwgImJyb3duIiksIGNleD0xKQ0KYGBgDQoNCiMjIyMgKipUYXNrIDQ6IFVuaXZhcmlhdGUgRURBKioNCg0KKirigKIgQ29tcHV0ZSB0aGUgbWFpbiBkZXNjcmlwdGl2ZSB1bml2YXJpYXRlIHN0YXRpc3RpY3MgZm9yIHRoZSA0IGhlYXZ5IG1ldGFscyoqDQoNCmBgYHtyfQ0Kc3VtbWFyeShkYXRhWyAsMzo2XSkNCmBgYA0KDQoqKlF1ZXN0aW9uczoqKg0KDQotICAgT2JzZXJ2ZSB0aGUgbWluaW11bSwgZmlyc3QgcXVhcnRpbGUsIG1lZGlhbiwgdGhpcmQgcXVhcnRpbGUsIGFuZCBtYXhpbXVtIGhlYXZ5IG1ldGFsIGNvbmNlbnRyYXRpb25zIGluIHRoZSBzYW1wbGUgc2V0Pw0KLSAgIENvbXBhcmUgdGhlIG1lYW4gYW5kIG1lZGlhbi4NCg0KKirigKIgRGlzcGxheSBoaXN0b2dyYW1zIGFuZCBib3hwbG90cyBvZiBhbGwgZm91ciBoZWF2eSBtZXRhbHMgY29uY2VudHJhdGlvbnMqKg0KDQpgYGB7cn0NCmhpc3QoZGF0YSRjYWRtaXVtLCBjb2w9ImJsdWUiLCB4bGFiPSJWYWx1ZXMiLG1haW49ImNhZG1pdW0gY29uY2VudHJhdGlvbnMiKQ0KaGlzdChkYXRhJGNvcHBlcixjb2w9ImJsdWUiLCB4bGFiPSJWYWx1ZXMiLG1haW49ImNvcHBlciBjb25jZW50cmF0aW9ucyIpDQpoaXN0KGRhdGEkbGVhZCxjb2w9ImJsdWUiLCB4bGFiPSJWYWx1ZXMiLG1haW49ImxlYWQgY29uY2VudHJhdGlvbnMiKQ0KaGlzdChkYXRhJHppbmMsY29sPSJibHVlIiwgeGxhYj0iVmFsdWVzIixtYWluPSJ6aW5jIGNvbmNlbnRyYXRpb25zIikNCmBgYA0KDQpgYGB7cn0NCmJveHBsb3QoZGF0YSRjYWRtaXVtLGNvbD0iYmx1ZSIsIHhsYWI9IlZhbHVlcyIsbWFpbj0iY2FkbWl1bSBjb25jZW50cmF0aW9ucyIpDQpib3hwbG90KGRhdGEkY29wcGVyLGNvbD0iYmx1ZSIsIHhsYWI9IlZhbHVlcyIsbWFpbj0iY29wcGVyIGNvbmNlbnRyYXRpb25zIikNCmJveHBsb3QoZGF0YSRsZWFkLGNvbD0iYmx1ZSIsIHhsYWI9IlZhbHVlcyIsbWFpbj0ibGVhZCBjb25jZW50cmF0aW9ucyIpDQpib3hwbG90KGRhdGEkemluYyxjb2w9ImJsdWUiLCB4bGFiPSJWYWx1ZXMiLG1haW49InppbmMgY29uY2VudHJhdGlvbnMiKQ0KYGBgDQoNCioqUXVlc3Rpb25zOioqDQoNCi0gRGVzY3JpYmUgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGVzZSB2YXJpYWJsZXMuIERvIHRoZXkgaGF2ZSBhIHN5bW1ldHJpYyBvciBza2V3ZWQgZGlzdHJpYnV0aW9uPw0KLSAgIEZvciBlYWNoIHZhcmlhYmxlOiBEb2VzIGl0IGFwcGVhciB0byBoYXZlIG1vcmUgdGhhbiBvbmUgcG9wdWxhdGlvbj8gRG9lcyBpdCBhcHBlYXIgdG8gYmUgYW55IGV4dHJlbWUgdmFsdWVzICgib3V0bGllcnMiKT8NCg0KPGJyPg0KDQojIyMjICoqVGFzayA1OiBMb2ctVHJhbnNmb3JtIHRoZSBkYXRhKioNCg0KVGhlIGxvZyB0cmFuc2Zvcm1hdGlvbiBjYW4gYmUgdXNlZCB0byBtYWtlIGhpZ2hseSBza2V3ZWQgZGlzdHJpYnV0aW9ucyBsZXNzIHNrZXdlZC4gVGhpcyBjYW4gYmUgdmFsdWFibGUgYm90aCBmb3IgbWFraW5nIHBhdHRlcm5zIGluIHRoZSBkYXRhIG1vcmUgaW50ZXJwcmV0YWJsZSBhbmQgZm9yIGhlbHBpbmcgdG8gbWVldCB0aGUgYXNzdW1wdGlvbnMgb2YgaW5mZXJlbnRpYWwgc3RhdGlzdGljcy4gICANCg0KDQpIZWF2eSBtZXRhbCBjb25jZW50cmF0aW9uIHVzdWFsbHkgaXMgbm90IHN5bW1ldHJpYy4gTG9nLXRyYW5zZm9ybSB0aGUgaGlnaGx5LXNrZXdlZCBkaXN0cmlidXRpb24uIFVzaW5nIHRoZSAqKmxvZzEwKCkqKiBmdW5jdGlvbiBhZGQgZm91ciBjb2x1bW5zIHRvIHRoZSBkYXRhZnJhbWUgKG9uZSBmb3IgZWFjaCBsb2cgdHJhbnNmb3JtZWQgaGVhdnkgbWV0YWwgY29uY2VudHJhdGlvbikuIA0KDQpgYGB7cn0NCmRhdGEkbG9nQ2QgPSBsb2cxMChkYXRhJGNhZG1pdW0pDQpkYXRhJGxvZ0N1ID0gbG9nMTAoZGF0YSRjb3BwZXIpDQpkYXRhJGxvZ1BiID0gbG9nMTAoZGF0YSRsZWFkKQ0KZGF0YSRsb2dabiA9IGxvZzEwKGRhdGEkemluYykNCmBgYA0KDQoqKuKAoiBEaXNwbGF5IGhpc3RvZ3JhbXMgYW5kIGJveHBsb3RzIG9mIHJhdyBhbmQgbG9nIHRyYW5zZm9ybWVkIGhlYXZ5IG1ldGFscyBjb25jZW50cmF0aW9ucyBzaWRlIGJ5IHNpZGUqKg0KDQoNCmBgYHtyfQ0KIyB1c2UgcGFyKCkgZnVuY3Rpb24gdG8gY29udmVydCB0aGUgZ3JhcGhpY2FsIHdpbmRvdyBpbnRvIDItYnktMSBzdWItc2NyZWVucyANCnBhcihtZnJvdz1jKDEsMikpIA0KDQojICBEaXNwbGF5IGhpc3RvZ3JhbXMgb2YgcmF3IGFuZCBsb2cgdHJhbnNmb3JtZWQgZGF0YQ0KZm9yKGogaW4gMTo0KXsNCiAgaGlzdChkYXRhWyxqKzJdLGNvbD0iYmx1ZSIsIHhsYWI9IlZhbHVlcyIsbWFpbj1jb2xuYW1lcyhkYXRhKVtqKzJdKQ0KICBoaXN0KGRhdGFbLGorMTNdLGNvbD0icmVkIiwgeGxhYj0iVmFsdWVzIixtYWluPWNvbG5hbWVzKGRhdGEpW2orMTNdKQ0KfQ0KYGBgDQoNCmBgYHtyfQ0KcGFyKG1mcm93PWMoMSwyKSkgDQoNCiMgIERpc3BsYXkgYm94cGxvdCBvZiByYXcgYW5kIGxvZyB0cmFuc2Zvcm1lZCBkYXRhDQpmb3IoaiBpbiAxOjQpew0KICBib3hwbG90KGRhdGFbLGorMl0sY29sPSJibHVlIiwgeGxhYj0iVmFsdWVzIixtYWluPWNvbG5hbWVzKGRhdGEpW2orMl0pDQogIGJveHBsb3QoZGF0YVssaisxM10sY29sPSJyZWQiLCB4bGFiPSJWYWx1ZXMiLG1haW49Y29sbmFtZXMoZGF0YSlbaisxM10pDQp9DQpgYGANCioqUXVlc3Rpb25zOioqICAgDQotIERpZmZlcmVuY2Ugb2YgZGlzdHJpYnV0aW9uIGJldHdlZW4gdGhlIHJhdyBkYXRhIGFuZCBsb2ctdHJhbnNmb3JtZWQ/ICAgDQotIElzIHRoZSBza2V3bmVzcyBvZiBvcmlnaW5hbCBkaXN0cmlidXRpb24gY2hhbmdlZCByZW1hcmthYmx5Pw0KDQo8YnI+DQoNCiMjIyMgKipUYXNrIDY6IFN0YXRpc3RpY3MgdnMgY2F0ZWdvcnkqKg0KDQoqKuKAoiBDb21wdXRlIHN1bW1hcnkgc3RhdGlzdGljcyAoZS5nLiBtZWFuKSBvZiBhbGwgZm91ciBoZWF2eSBtZXRhbCBjb25jZW50cmF0aW9ucyBieSBzb21lIGNhdGVnb3JpY2FsIHZhcmlhYmxlcyAoZS5nLiBzb2lsIHR5cGUpKioNCg0KYGBge3J9DQphZ2dyZWdhdGUoZGF0YVsgLDM6Nl0sIGJ5PWxpc3QoZGF0YSRzb2lsKSwgRlVOPW1lYW4sIG5hLnJtPVRSVUUpDQpgYGANCg0KLSAgIGFnZ3JlZ2F0ZSgpIGZ1bmN0aW9uIFNwbGl0cyB0aGUgZGF0YSBpbnRvIHN1YnNldHMsIGNvbXB1dGVzIHN1bW1hcnkgc3RhdGlzdGljcyBmb3IgZWFjaCwgYW5kIHJldHVybnMgdGhlIHJlc3VsdCBpbiBhIGNvbnZlbmllbnQgZm9ybS4NCi0gICBieT1saXN0KCkgaXMgYSBsaXN0IG9mIGdyb3VwaW5nIGVsZW1lbnRzLg0KLSAgIEZVTiA9IGEgZnVuY3Rpb24gdG8gY29tcHV0ZSB0aGUgc3VtbWFyeSBzdGF0aXN0aWNzIHdoaWNoIGNhbiBiZSBhcHBsaWVkIHRvIGFsbCBkYXRhIHN1YnNldHMuDQotICAgbmEucm0gPSBUUlVFIGV4Y2x1ZGVzIG1pc3NpbmcgdmFsdWVzIHdoZW4gY2FsY3VsYXRpbmcgZGVzY3JpcHRpdmUgc3RhdGlzdGljcyBpbiBSLg0KDQoqKuKAoiBEaXNwbGF5IHRoZSBoaXN0b2dyYW0gYW5kIGJveHBsb3Qgb2YgaGVhdnkgbWV0YWxzIGNvbmNlbnRyYXRpb25zIGJ5IHNvbWUgY2F0ZWdvcmljYWwgdmFyaWFibGVzKioNCg0KVG8gZG8gdGhpcyB0YXNrLCB5b3UgY2FuIHVzZSAqKmhpc3RvZ3JhbSgpKiogZnVuY3Rpb24gZnJvbSB0aGUgKipsYXR0aWNlIGxpYnJhcnkqKiBhbmQgdGhlIGFscmVhZHkgZmFtaWxhciAqKmJveHBsb3QoKSoqIGZ1bmN0aW9uIGZyb20gdGhlIFItQmFzZS4NCg0KYGBge3J9DQojIEZpcnN0IGluc3RhbGwgYW5kIGxvYWQgdGhlIGxhdHRpY2UgbGlicmFyeQ0KaW5zdGFsbC5wYWNrYWdlcygibGF0dGljZSIpDQpsaWJyYXJ5KGxhdHRpY2UpDQpgYGANCg0KYGBge3J9DQojIEhpc3RvZ3JhbSBvZiB6aW5jIGNvbmNlbnRyYXRpb25zIGZvciBlYWNoIHNvaWwgdHlwZQ0KaGlzdG9ncmFtKH4gZGF0YSR6aW5jfGFzLmZhY3RvcihkYXRhJHNvaWwpLGNvbD0iYmx1ZSIseGxhYj0gIlppbmMgY29uY2VybnRyYXRpb24iKQ0KDQojIGJveHBsb3Qgb2YgemluYyBjb25jZW50cmF0aW9uIGZvciBmbG9vZCBmcmVxdWVuY2llcyANCmJveHBsb3QoZGF0YSR6aW5jIH4gZGF0YSRmZnJlcSwgY29sPSJibHVlIix4bGFiPSJGbG9vZCBGcmVxdWVuY3kgQ2xhc3MiLCANCnlsYWI9ICJaaW5jIGNvbmNlcm50cmF0aW9uIikNCmBgYA0KDQoqKlF1ZXN0aW9uczoqKg0KDQotICAgd2hpY2ggc29pbCB0eXBlIGlzIG1vcmUgY29udGFtaW5hdGVkIHdpdGggemluYz8NCi0gICBJcyBmbG9vZCBmcmVxdWVuY3kgYXNzb2NpYXRlZCB3aXRoIHppbmMgY29uY2VudHJhdGlvbiA/DQoNCjxicj4NCg0KIyMjIyAqKlRhc2sgNzogQml2YXJpYXRlIEVEQSoqDQoNCg0KKirigKIgUGxvdCBzY2F0dGVyIHBsb3RzIGJldHdlZW4gdHdvIHZhcmlhYmxlcyAoZm9yIGUuZy4gemluYyBhbmQgY29wcGVyKSoqDQoNCmBgYHtyfQ0KcGxvdChkYXRhJHppbmMgfiBkYXRhJGNvcHBlciwgeGxhYj0iQ29wcGVyIGNvbmNlbnRyYXRpb24iLCB5bGFiPSJ6aW5jIGNvbmNlbnRyYXRpb24iKQ0KDQpwbG90KGRhdGEkbG9nWm4gfiBkYXRhJGxvZ0N1LCB4bGFiPSJsb2cxMCBDb3BwZXIgY29uY2VudHJhdGlvbiIsIHlsYWI9ImxvZzEwIHppbmMgY29uY2VudHJhdGlvbiIpDQpgYGANCg0KKipRdWVzdGlvbnM6KioNCg0KLSAgIERlc2NyaWJlIHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIGNvcHBlciBhbmQgemluYyBjb25jZW50cmF0aW9ucy4NCi0gICBBcmUgdGhlcmUgYW55IG9ic2VydmF0aW9ucyB0aGF0IGRvIG5vdCBmaXQgdGhlIGdlbmVyYWwgcGF0dGVybj8gV2hhdCBjb3VsZCBiZSB0aGUgcmVhc29uKHMpPw0KDQoqKuKAoiBPYnNlcnZlIHRoZSBzYW1wbGVzIHRoYXQgZG8gbm90IGZpdCB0aGUgZ2VuZXJhbCBwYXR0ZXJuKioNCg0KYGBge3J9DQppeD13aGljaCgoZGF0YSRsb2dabiA8IDIuNikgJiAoZGF0YSRsb2dDdSA+IDEuNikpDQpwcmludChpeCkNCnByaW50KGRhdGFbaXgsIF0pDQpgYGANCg0KKirigKIgQ29tcHV0ZSB0aGUgc2NhdHRlciBwbG90IG1hdHJpeCBmb3IgYWxsIHBhaXJzIG9mIHZhcmlhYmxlcyB1c2luZyBwYWlyKCkgZnVuY3Rpb24qKg0KYGBge3J9DQpwYWlycyhkYXRhWyAsMzo2XSwgcGNoID0gMTksIGNleD0wLjUpDQpwYWlycyhkYXRhWyAsMTQ6MTddLCBwY2ggPSAxOSwgY2V4PTAuNSkNCmBgYA0KDQoqKuKAoiBDb21wdXRlIHRoZSBQZWFyc29uIGNvcnJlbGF0aW9uIG1hdHJpeCoqDQoNCmBgYHtyfQ0KQ29yTWF0ID0gY29yKGRhdGFbICwzOjZdKQ0KcHJpbnQoQ29yTWF0KSANCg0KIyBDb21wdXQgUGVhcnNvbiBjb3JyZWxhdGlvbiBtYXRyaXggZm9yIGxvZy10cmFuc2Zvcm1lZCB2YXJpYWJsZXMNCkNvck1hdExvZyA9IGNvcihkYXRhWyAsMTQ6MTddKQ0KcHJpbnQoQ29yTWF0TG9nKSANCmBgYA0KDQoqKlF1ZXN0aW9uczoqKiAgICANCi0gRGlzY3VzcyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIHBhaXJzIG9mIHZhcmlhYmxlcyA/IFRoZSBuYXR1cmUgKHNpZ24pIGFuZCBzdHJlbmd0aCBvZiB0aGUgcmVsYXRpb25zaGlwcz8gICAgDQotIFRoZSBwb3NzaWJsZSByZWFzb24gYmVoaW5kIHRoaXMgdHlwZSBvZiBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBoZWF2eSBtZXRhbHM/DQoNCioq4oCiIENvbXB1dGUgdGhlIFBlYXJzb24gY29ycmVsYXRpb24gbWF0cml4IHVzaW5nIENvcnJwbG90IGxpYnJhcnkqKg0KDQpjb3JycGxvdCBpcyBhbiBSIHBhY2thZ2UgdGhhdCBwcm92aWRlcyBhIHZpc3VhbCBleHBsb3JhdG9yeSB0b29sIG9uIGNvcnJlbGF0aW9uIG1hdHJpeCB0aGF0IHN1cHBvcnRzIHJpY2ggdmlzdWFsaXphdGlvbiBtZXRob2QsIGdyYXBoaWMgbGF5b3V0LCBjb2xvciBhbmQgbGVnZW5kLiBUaGUgKipjb3JycGxvdCgpKiogZnVuY3Rpb24gdGFrZXMgYW4gZXhpc3RpbmcgY29ycmVsYXRpb24gbWF0cml4IGFzIGFyZ3VtZW50DQoNCmBgYHtyfQ0KIyBJbnN0YWxsIGFuZCBsb2FkIGNvcnJwbG90IHBhY2thZ2UNCmluc3RhbGwucGFja2FnZXMoImNvcnJwbG90IikNCmxpYnJhcnkoY29ycnBsb3QpDQpgYGANCg0KYGBge3J9DQojIFBlYXJzb24gQ29ycmVsYXRpb24gTWF0cml4IA0KY29ycnBsb3QoQ29yTWF0KQ0KY29ycnBsb3QoQ29yTWF0TG9nKQ0KYGBgDQoNCg0KDQoNCg0KDQo=