When you sort of know, use two question marks.
??average ??tail
Install igraph, haven, and tidyverse:
install.packages('tidyverse')
trying URL 'https://cran.rstudio.com/bin/macosx/el-capitan/contrib/3.6/tidyverse_1.2.1.tgz'
Content type 'application/x-gzip' length 89217 bytes (87 KB)
==================================================
downloaded 87 KB
The downloaded binary packages are in
/var/folders/zm/zhc689mj20sf8gz6nfjt09r40000gn/T//Rtmpy32DoF/downloaded_packages
install.packages('igraph')
Error in install.packages : Updating loaded packages
install.packages("haven")
trying URL 'https://cran.rstudio.com/bin/macosx/el-capitan/contrib/3.6/haven_2.2.0.tgz'
Content type 'application/x-gzip' length 1077133 bytes (1.0 MB)
==================================================
downloaded 1.0 MB
The downloaded binary packages are in
/var/folders/zm/zhc689mj20sf8gz6nfjt09r40000gn/T//Rtmpy32DoF/downloaded_packages
Set seed:
rr set.seed(09032019)
Load igraph , haven, and tidyverse OR attach data already loaded in R:
library(igraph)
Attaching package: ‘igraph’
The following objects are masked from ‘package:stats’:
decompose, spectrum
The following object is masked from ‘package:base’:
union
library(tidyverse)
Registered S3 method overwritten by 'dplyr':
method from
print.rowwise_df
[37m── [1mAttaching packages[22m ───────────────────────────────────────────── tidyverse 1.2.1 ──[39m
[37m[32m✔[37m [34mggplot2[37m 3.2.1 [32m✔[37m [34mpurrr [37m 0.3.2
[32m✔[37m [34mtibble [37m 2.1.3 [32m✔[37m [34mdplyr [37m 0.8.3
[32m✔[37m [34mtidyr [37m 1.0.0 [32m✔[37m [34mstringr[37m 1.4.0
[32m✔[37m [34mreadr [37m 1.3.1 [32m✔[37m [34mforcats[37m 0.4.0[39m
[37m── [1mConflicts[22m ──────────────────────────────────────────────── tidyverse_conflicts() ──
[31m✖[37m [34mdplyr[37m::[32mas_data_frame()[37m masks [34mtibble[37m::as_data_frame(), [34migraph[37m::as_data_frame()
[31m✖[37m [34mpurrr[37m::[32mcompose()[37m masks [34migraph[37m::compose()
[31m✖[37m [34mtidyr[37m::[32mcrossing()[37m masks [34migraph[37m::crossing()
[31m✖[37m [34mdplyr[37m::[32mfilter()[37m masks [34mstats[37m::filter()
[31m✖[37m [34mdplyr[37m::[32mgroups()[37m masks [34migraph[37m::groups()
[31m✖[37m [34mdplyr[37m::[32mlag()[37m masks [34mstats[37m::lag()
[31m✖[37m [34mpurrr[37m::[32msimplify()[37m masks [34migraph[37m::simplify()[39m
library(haven)
library(readxl)
attach(mtcars)
The following object is masked from package:ggplot2:
mpg
Read in data from a desktop:
data2 <- read.delim('~/Documents/UCLA/Data/PRIO_UrbanSocialDisorder/events.csv', sep=',')
cannot open file '/Users/Al/Documents/UCLA/Data/PRIO_UrbanSocialDisorder/events.csv': No such file or directoryError in file(file, "rt") : cannot open the connection
Read in data from a website:
# This step only needed to read excel files from the internet:
download.file("https://stats.idre.ucla.edu/stat/data/hsb2.xls", "~/Downloads/myfile.xls", mode="wb")
trying URL 'https://stats.idre.ucla.edu/stat/data/hsb2.xls'
Content type 'application/vnd.ms-excel' length 41984 bytes (41 KB)
==================================================
downloaded 41 KB
Use read_graph to load network data. Create a network from an edgelist. Load data at https://raw.githubusercontent.com/ZacharyST/Data/master/dolphins. Open that link first in your web browser so you know what the data look like. The data are undirected (two options):
data <- graph_from_edgelist(as.matrix(data), directed = FALSE)
Error in as.vector(x, mode) :
cannot coerce type 'closure' to vector of type 'any'
Get the adjacency matrix from the graph above. Tell the function not to return a sparse matrix.
rr amps2 <- as_adjacency_matrix(dataps2, sparse = FALSE)
Load the dolphin data again, this time telling R the network is directed.
rr dataps2d <- read_graph(://raw.githubusercontent.com/ZacharyST/Data/master/dolphins, directed = TRUE)
Load the SCAD data from my Github Data repository. The link is https://raw.githubusercontent.com/ZacharyST/Data/master/scad_latiname rica.
rr data <- read.csv(://raw.githubusercontent.com/ZacharyST/Data/master/scad_latinamerica)
INSPECTING A NETWORK (edges, nodes, components, size, degree)
How many nodes does the network have (two options)?
length(V(dataps2))
[1] 63
How many nodes does the network have (two options) using an adjacency matrix?
ncol(amps2)
[1] 63
How many edges does the network have (three options)?
sum(colSums(amps2))/2
[1] 159
Does the network have any components?
count_components(dataps2)
[1] 2
Save the results from above as a new object. Call the entry of that object that tells you have many components there are.
c$no
[1] 2
What is the size of the component(s)?
c$csize
[1] 1 62
What is the degree of each node? Use the object created when you read in the file.
degree(dataps2)
[1] 0 6 8 4 3 1 4 6 5 6 7 5 1 1 8 12 7 6 9 7 4 9 6 1 3 6 3
[28] 3 5 5 9 5 1 3 10 5 1 7 11 8 2 8 5 6 7 4 11 2 6 1 2 7 10 4
[55] 2 7 2 2 9 1 5 1 3
What is the degree of each node? Use the adjacency matrix?
rowSums(amps2)
[1] 0 6 8 4 3 1 4 6 5 6 7 5 1 1 8 12 7 6 9 7 4 9 6 1 3 6 3
[28] 3 5 5 9 5 1 3 10 5 1 7 11 8 2 8 5 6 7 4 11 2 6 1 2 7 10 4
[55] 2 7 2 2 9 1 5 1 3
What is the degree of the most social dolphin?
max(degree(dataps2))
[1] 12
Which dolphin is the most social?
V(dataps2)[degree(dataps2) == max(degree(dataps2))]
+ 1/63 vertex, from c1bd9b9:
[1] 16
Repeat the last two queries above, but save the result of the most social dolphin as an object.
V(dataps2)[degree(dataps2) == social]
+ 1/63 vertex, from c1bd9b9:
[1] 16
Load and inspect the KARATE data.
Make column names match the row numbers:
Now, let us count how many nodes there are, the number of components, and the degree of each node:
rr library(igraph) # To load igraph functions g <- graph(d) # Fails. Requires edgelist. g <- graph_from_adjacency_matrix(d) # Fails because d is a dataframe. g <- graph_from_adjacency_matrix(as.matrix(d), mode=) # Works. Do not forget to tell it the kind of network you have.
To just get the count of components:
count_components(g)
[1] 1
The most connections and its node or nodes (two options):
V(g)[degree(g) == maximum]
+ 1/34 vertex, named, from b64e902:
[1] 34
Loop, check work, correct:
# Using the apply function:
# MARGIN=2 means columns.
apply(d, MARGIN=2, FUN=sum) # You have to capitalize the argument names.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
16 9 10 6 3 4 4 4 5 2 3 1 2 5 2 2 2 2 2 3 2 2 2 5 3 3 2 4
29 30 31 32 33 34
3 4 4 6 12 17
Find the nodes in the karate network that have the minimum degree.
V(g)[which.min(degree(g))]
+ 1/34 vertex, named, from b64e902:
[1] 12
RANDOM NUMBER GENERATOR (igraph, adjacency matrix)
A binomial distribution is one that produces a series of numbers according to parameters you pass it.We can easily make it produces 1s and 0s and then populate an adjacency matrix with them. The last argument controls the ratio of 1s and 0s. So, half the output will be 1, half will be 0, on average.
rbinom(1,1,.5)
[1] 1
rbinom(1,1,.5)
[1] 1
rbinom(1,1,.5)
[1] 1
rbinom(1,1,.5)
[1] 1
rbinom(1,1,.5)
[1] 0
Let’s speed that up. Why does the below line produce more numbers? 10 replaces 1.
rbinom(10,1,.5)
[1] 0 0 1 0 1 1 0 1 1 1
Let’s understand rbinom a little more. Second number is options.
rbinom(10,3,.5)
[1] 2 1 2 0 1 1 2 1 0 3
We can now make a matrix of arbitrary size, so long as rbinom() creates a square amount of numbers.
temp
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
[1,] 1 0 0 0 0 0 0 1 1
[2,] 0 1 0 1 1 1 1 0 1
[3,] 0 0 1 0 0 0 1 1 1
[4,] 0 0 0 0 0 0 1 1 1
[5,] 1 0 0 1 1 1 1 1 0
[6,] 0 0 1 1 0 0 0 1 0
[7,] 1 1 1 1 0 0 1 0 1
[8,] 1 1 0 0 0 0 1 1 1
[9,] 0 0 0 1 1 0 0 1 0
Maybe this approach is a little more intuitive:
temp
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14]
[1,] 0 0 0 0 0 1 0 0 0 1 1 1 0 1
[2,] 0 0 1 0 1 1 0 1 0 0 0 1 1 1
[3,] 0 1 0 1 0 0 0 1 0 0 0 1 0 0
[4,] 0 1 1 0 1 0 0 0 0 1 1 1 1 0
[5,] 0 0 0 0 0 0 1 0 1 0 0 1 1 1
[6,] 0 0 0 0 1 0 0 0 1 1 0 0 1 1
[7,] 0 0 1 1 1 1 0 1 0 0 0 1 0 1
[8,] 1 1 0 0 1 0 0 0 1 0 0 1 1 0
[9,] 0 0 1 0 0 1 1 1 0 0 0 1 0 0
[10,] 1 0 1 1 1 1 0 0 1 0 1 1 1 0
[11,] 1 0 0 1 1 1 1 0 0 1 0 0 1 1
[12,] 1 0 0 0 0 1 1 1 0 1 0 0 0 1
[13,] 0 1 1 0 1 1 0 1 0 0 1 0 0 0
[14,] 0 1 0 0 0 1 0 0 0 1 0 0 1 0
[15,] 1 1 1 1 0 1 1 1 1 1 0 0 0 0
[,15]
[1,] 1
[2,] 0
[3,] 0
[4,] 0
[5,] 1
[6,] 1
[7,] 0
[8,] 0
[9,] 0
[10,] 1
[11,] 0
[12,] 1
[13,] 0
[14,] 1
[15,] 0
Convert to igraph object.
rr g_temp <- graph_from_adjacency_matrix(temp, mode=)
Note that this approach requires using a directed network.
(colSums(temp) + rowSums(temp)) == degree(g_temp)
[1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
You can also make an undirected graph from the adjacency matrix. igraph will handle the construction of edges by assuming any edge is symmetric.
degree(g_temp2) # Gives the same as the above for graph
[1] 7 9 9 9 12 11 10 9 8 11 8 12 9 10 12
But calculation of other statistics will be tricky. It is better to just make the matrix symmetric right away, which requires some massaging. For the bottom left half of the matrix, make it the same as the top right.
temp2
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14]
[1,] 0 0 0 0 0 1 0 0 0 1 1 1 0 1
[2,] 0 0 1 0 1 1 0 1 0 0 0 1 1 1
[3,] 0 1 0 1 0 0 0 1 0 0 0 1 0 0
[4,] 0 0 1 0 1 0 0 0 0 1 1 1 1 0
[5,] 0 1 0 1 0 0 1 0 1 0 0 1 1 1
[6,] 1 1 0 0 0 0 0 0 1 1 0 0 1 1
[7,] 0 0 0 0 1 0 0 1 0 0 0 1 0 1
[8,] 0 1 1 0 0 0 1 0 1 0 0 1 1 0
[9,] 0 0 0 0 1 1 0 1 0 0 0 1 0 0
[10,] 1 0 0 1 0 1 0 0 0 0 1 1 1 0
[11,] 1 0 0 1 0 0 0 0 0 1 0 0 1 1
[12,] 1 1 1 1 1 0 1 1 1 1 0 0 0 1
[13,] 0 1 0 1 1 1 0 1 0 1 1 0 0 0
[14,] 1 1 0 0 1 1 1 0 0 0 1 1 0 0
[15,] 1 0 0 0 1 1 0 0 0 1 0 1 0 1
[,15]
[1,] 1
[2,] 0
[3,] 0
[4,] 0
[5,] 1
[6,] 1
[7,] 0
[8,] 0
[9,] 0
[10,] 1
[11,] 0
[12,] 1
[13,] 0
[14,] 1
[15,] 0
ADJACENCY MATRIX EXAMPLE
Create an adjacency matrix that has 25 rows and columns, where each cell has a .8 probability of containing a 1. Set the diagonal to zero.
probability <- .8
thisnumber <- 25
thismatrix <- matrix(rbinom(thisnumber^2, 1, probability), nrow=thisnumber)
diag(thismatrix) <- 0
thismatrix
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14]
[1,] 0 1 1 0 0 0 1 1 0 1 1 1 1 0
[2,] 1 0 1 1 1 1 0 1 0 1 1 0 1 1
[3,] 0 1 0 1 1 1 0 1 1 1 1 1 1 1
[4,] 1 1 1 0 1 1 1 1 1 1 1 1 1 0
[5,] 1 1 1 1 0 1 1 1 1 0 1 1 1 0
[6,] 1 1 1 1 1 0 1 0 1 1 1 0 1 1
[7,] 1 1 0 0 1 0 0 1 1 1 1 1 1 1
[8,] 0 0 1 0 1 1 1 0 1 0 1 0 0 1
[9,] 1 1 1 1 1 1 1 0 0 1 1 1 1 1
[10,] 0 1 0 0 1 1 1 1 1 0 1 0 1 1
[11,] 1 1 1 1 1 1 1 1 1 1 0 1 1 1
[12,] 1 1 1 1 1 1 1 0 1 1 1 0 1 1
[13,] 1 1 1 1 1 1 1 1 1 1 1 0 0 1
[14,] 1 1 1 1 1 1 1 1 1 1 0 1 1 0
[15,] 1 1 1 1 1 1 1 1 1 1 1 1 0 1
[16,] 1 1 1 1 1 1 0 1 1 0 1 0 1 1
[17,] 1 1 1 1 0 1 0 1 0 1 0 1 0 0
[18,] 0 1 0 0 1 1 1 1 0 1 0 1 1 0
[19,] 1 1 1 1 1 1 1 1 1 1 0 1 1 1
[20,] 1 0 1 1 1 0 0 0 0 1 1 1 1 1
[21,] 1 1 1 1 1 1 1 1 1 0 1 0 0 1
[22,] 0 1 1 1 1 1 1 0 1 0 1 1 1 1
[23,] 1 1 1 1 1 1 1 1 1 1 1 1 0 1
[24,] 1 1 1 1 1 1 1 1 1 1 1 0 1 1
[25,] 1 0 1 0 0 1 1 1 1 1 1 1 1 1
[,15] [,16] [,17] [,18] [,19] [,20] [,21] [,22] [,23] [,24] [,25]
[1,] 0 1 1 0 1 1 1 1 1 1 0
[2,] 1 1 1 1 1 0 0 1 1 1 1
[3,] 1 0 1 1 1 1 0 0 0 1 0
[4,] 1 1 0 0 1 1 1 1 1 1 0
[5,] 0 1 1 0 1 1 1 1 0 0 1
[6,] 1 0 0 1 1 1 1 1 0 1 0
[7,] 1 1 0 1 0 1 1 1 1 0 1
[8,] 0 1 1 0 1 1 1 1 1 1 1
[9,] 1 0 1 0 1 0 1 1 1 1 1
[10,] 0 0 1 1 1 1 1 0 1 1 1
[11,] 1 1 1 0 1 1 1 0 0 1 0
[12,] 1 1 0 1 1 1 1 1 1 0 1
[13,] 1 1 1 1 1 1 1 1 1 0 1
[14,] 0 1 1 1 1 0 1 1 1 1 1
[15,] 0 1 0 1 1 1 1 1 1 1 1
[16,] 0 0 1 1 1 1 1 1 1 1 1
[17,] 1 1 0 1 0 1 1 0 1 1 1
[18,] 0 0 1 0 1 1 1 1 0 1 1
[19,] 1 0 1 1 0 1 1 0 1 1 0
[20,] 1 1 1 0 1 0 1 1 1 1 0
[21,] 1 0 0 0 1 1 0 1 0 1 1
[22,] 1 1 1 1 1 0 1 0 1 1 1
[23,] 1 0 0 1 1 1 1 1 0 1 1
[24,] 1 0 1 1 1 0 1 1 1 0 1
[25,] 1 1 1 0 1 1 1 0 1 1 0
Convert it to an undirected network.
thismatrix
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14]
[1,] 0 1 1 0 0 0 1 1 0 1 1 1 1 0
[2,] 1 0 1 1 1 1 0 1 0 1 1 0 1 1
[3,] 1 1 0 1 1 1 0 1 1 1 1 1 1 1
[4,] 0 1 1 0 1 1 1 1 1 1 1 1 1 0
[5,] 0 1 1 1 0 1 1 1 1 0 1 1 1 0
[6,] 0 1 1 1 1 0 1 0 1 1 1 0 1 1
[7,] 1 0 0 1 1 1 0 1 1 1 1 1 1 1
[8,] 1 1 1 1 1 0 1 0 1 0 1 0 0 1
[9,] 0 0 1 1 1 1 1 1 0 1 1 1 1 1
[10,] 1 1 1 1 0 1 1 0 1 0 1 0 1 1
[11,] 1 1 1 1 1 1 1 1 1 1 0 1 1 1
[12,] 1 0 1 1 1 0 1 0 1 0 1 0 1 1
[13,] 1 1 1 1 1 1 1 0 1 1 1 1 0 1
[14,] 0 1 1 0 0 1 1 1 1 1 1 1 1 0
[15,] 0 1 1 1 0 1 1 0 1 0 1 1 1 0
[16,] 1 1 0 1 1 0 1 1 0 0 1 1 1 1
[17,] 1 1 1 0 1 0 0 1 1 1 1 0 1 1
[18,] 0 1 1 0 0 1 1 0 0 1 0 1 1 1
[19,] 1 1 1 1 1 1 0 1 1 1 1 1 1 1
[20,] 1 0 1 1 1 1 1 1 0 1 1 1 1 0
[21,] 1 0 0 1 1 1 1 1 1 1 1 1 1 1
[22,] 1 1 0 1 1 1 1 1 1 0 0 1 1 1
[23,] 1 1 0 1 0 0 1 1 1 1 0 1 1 1
[24,] 1 1 1 1 0 1 0 1 1 1 1 0 0 1
[25,] 0 1 0 0 1 0 1 1 1 1 0 1 1 1
[,15] [,16] [,17] [,18] [,19] [,20] [,21] [,22] [,23] [,24] [,25]
[1,] 0 1 1 0 1 1 1 1 1 1 0
[2,] 1 1 1 1 1 0 0 1 1 1 1
[3,] 1 0 1 1 1 1 0 0 0 1 0
[4,] 1 1 0 0 1 1 1 1 1 1 0
[5,] 0 1 1 0 1 1 1 1 0 0 1
[6,] 1 0 0 1 1 1 1 1 0 1 0
[7,] 1 1 0 1 0 1 1 1 1 0 1
[8,] 0 1 1 0 1 1 1 1 1 1 1
[9,] 1 0 1 0 1 0 1 1 1 1 1
[10,] 0 0 1 1 1 1 1 0 1 1 1
[11,] 1 1 1 0 1 1 1 0 0 1 0
[12,] 1 1 0 1 1 1 1 1 1 0 1
[13,] 1 1 1 1 1 1 1 1 1 0 1
[14,] 0 1 1 1 1 0 1 1 1 1 1
[15,] 0 1 0 1 1 1 1 1 1 1 1
[16,] 1 0 1 1 1 1 1 1 1 1 1
[17,] 0 1 0 1 0 1 1 0 1 1 1
[18,] 1 1 1 0 1 1 1 1 0 1 1
[19,] 1 1 0 1 0 1 1 0 1 1 0
[20,] 1 1 1 1 1 0 1 1 1 1 0
[21,] 1 1 1 1 1 1 0 1 0 1 1
[22,] 1 1 0 1 0 1 1 0 1 1 1
[23,] 1 1 1 0 1 1 0 1 0 1 1
[24,] 1 1 1 1 1 1 1 1 1 0 1
[25,] 1 1 1 1 0 0 1 1 1 1 0
Convert the matrix to an igraph graph object.
rr ig2 <- graph_from_adjacency_matrix(thismatrix, mode=‘undirected’)
What is the average degree of the network?
summary(degree(ig2))[4]
Mean
18.64
What is the density of the network?
edge_density(ig2) # same
[1] 0.7766667
What is the global transitivity of the network?
transitivity(ig2, type='globalundirected')
[1] 0.7654172
Use an adjacency matrix to create a fake network that has 30 individuals.
newmatrix
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14]
[1,] 0 1 0 0 1 0 0 0 0 1 1 0 1 0
[2,] 1 1 0 0 0 1 0 0 0 0 1 1 0 0
[3,] 0 0 0 0 1 1 0 0 1 0 0 0 1 1
[4,] 0 0 0 0 1 0 1 0 1 0 0 0 1 0
[5,] 1 1 0 1 1 1 0 1 0 0 0 0 1 0
[6,] 1 1 0 0 0 0 1 0 1 0 0 1 0 0
[7,] 1 1 0 1 0 0 0 1 0 0 0 0 0 1
[8,] 0 0 0 0 0 1 1 0 0 1 0 0 1 1
[9,] 1 0 0 1 0 1 1 1 0 0 1 1 0 1
[10,] 0 0 1 1 0 1 0 1 0 1 0 1 0 1
[11,] 1 0 0 1 1 0 0 1 0 0 0 1 1 1
[12,] 0 1 0 1 1 0 1 0 1 0 1 1 1 0
[13,] 1 0 0 0 0 0 1 0 0 1 1 0 1 1
[14,] 1 0 0 0 0 1 0 1 0 1 1 0 1 0
[15,] 0 1 0 0 0 0 0 1 1 1 1 0 0 0
[16,] 1 0 0 0 0 1 1 0 1 1 0 0 0 1
[17,] 1 0 1 1 1 0 0 0 0 1 0 0 0 1
[18,] 1 0 0 0 1 0 0 1 1 0 0 0 0 0
[19,] 1 1 0 0 1 1 1 1 0 1 1 1 1 0
[20,] 0 1 1 0 1 0 0 0 1 0 0 1 1 1
[21,] 0 0 0 1 1 1 1 0 1 1 0 0 1 0
[22,] 0 1 0 0 1 0 1 1 0 0 0 0 1 1
[23,] 0 1 0 1 0 1 0 1 0 1 0 0 1 0
[24,] 1 0 1 0 0 1 1 0 0 0 0 0 1 1
[25,] 0 1 0 0 1 1 1 1 1 0 1 1 1 1
[26,] 0 1 1 1 1 0 1 0 0 0 1 0 0 1
[27,] 0 1 0 0 0 1 0 1 1 0 1 0 0 0
[28,] 1 0 0 0 1 1 1 0 0 0 1 0 0 1
[29,] 0 1 1 1 0 1 1 1 1 0 1 0 0 0
[30,] 1 1 1 0 1 1 1 0 0 1 0 0 0 0
[,15] [,16] [,17] [,18] [,19] [,20] [,21] [,22] [,23] [,24] [,25] [,26] [,27]
[1,] 1 1 0 0 0 0 1 1 1 1 1 0 1
[2,] 1 1 1 1 0 0 1 0 1 1 1 1 1
[3,] 1 1 1 1 0 1 0 1 0 0 1 0 0
[4,] 0 0 0 0 0 0 0 1 0 0 0 1 1
[5,] 0 1 1 1 0 1 1 0 0 0 1 1 1
[6,] 0 0 1 0 0 0 1 1 0 0 0 1 1
[7,] 1 0 1 1 0 0 0 1 1 1 1 0 1
[8,] 0 0 0 1 0 1 0 0 0 1 1 0 1
[9,] 1 1 1 1 0 0 0 0 1 1 0 1 1
[10,] 1 0 1 0 1 1 1 1 1 1 1 1 0
[11,] 0 0 0 1 0 0 1 1 0 0 1 1 0
[12,] 1 1 0 0 0 1 1 0 1 0 1 0 1
[13,] 1 0 1 1 1 1 0 1 0 1 0 0 0
[14,] 1 0 1 1 0 1 1 1 0 1 0 0 1
[15,] 1 0 1 0 0 1 1 1 0 0 0 0 0
[16,] 1 1 1 0 0 1 1 0 0 0 0 1 0
[17,] 0 0 0 0 0 1 1 0 0 0 0 1 1
[18,] 1 0 1 0 1 1 1 1 1 0 0 0 1
[19,] 0 0 1 1 0 0 0 1 0 1 1 1 1
[20,] 0 1 1 0 1 0 1 1 1 0 1 0 1
[21,] 1 1 1 1 1 1 0 1 1 0 0 0 1
[22,] 1 0 1 1 0 0 0 1 1 1 1 0 1
[23,] 1 0 0 1 0 0 0 0 0 0 1 0 1
[24,] 1 1 1 0 1 1 1 1 1 1 0 1 1
[25,] 1 0 0 0 0 0 0 0 0 1 0 0 1
[26,] 1 0 1 0 0 1 1 0 1 1 1 0 0
[27,] 0 1 0 0 1 0 1 1 1 0 0 0 0
[28,] 0 0 0 1 0 1 0 1 1 1 1 1 1
[29,] 0 1 1 0 1 0 1 0 0 1 0 1 1
[30,] 1 1 0 1 0 0 0 1 0 1 0 0 1
[,28] [,29] [,30]
[1,] 1 0 1
[2,] 1 0 1
[3,] 1 0 0
[4,] 0 1 0
[5,] 1 0 0
[6,] 0 0 0
[7,] 0 0 1
[8,] 1 0 1
[9,] 0 1 0
[10,] 1 0 0
[11,] 1 0 0
[12,] 1 1 0
[13,] 1 1 0
[14,] 1 0 1
[15,] 1 1 0
[16,] 1 1 1
[17,] 1 0 1
[18,] 0 0 0
[19,] 0 0 0
[20,] 1 1 1
[21,] 1 1 1
[22,] 0 1 0
[23,] 0 0 1
[24,] 1 0 1
[25,] 0 0 1
[26,] 1 0 0
[27,] 1 0 1
[28,] 0 0 0
[29,] 1 1 0
[30,] 1 1 1
Calculate the degree of each node using the adjacency matrix:
degree(newmatrix) # fails since not graph object
Error in degree(newmatrix) : Not a graph object
Degree for directed adjacency matrix:
colSums(newmatrix) + rowSums(newmatrix) - 2*diag(newmatrix) # No self loops
[1] 30 31 20 19 30 27 30 26 29 28 26 24 29 31 29 26 31 27 25 33 36 32 25 33 29 28 34
[28] 34 26 28
Degree for undirected
colSums(newmatrix) + rowSums(newmatrix) - diag(newmatrix) # No self loops
[1] 30 32 20 19 31 27 30 26 29 29 26 25 30 31 30 27 31 27 25 33 36 33 25 34 29 28 34
[28] 34 27 29
Convert the adjacency matrix to an asymmetric graph object. Use igraph to calculate the degree of each node.
degree(g3)
[1] 30 33 20 19 32 27 30 26 29 30 26 26 31 31 31 28 31 27 25 33 36 34 25 35 29 28 34
[28] 34 28 30
DENSITY
What is the density of the dolphin network (two options)?
ecount(dataps2)/((vcount(dataps2) * (vcount(dataps2) - 1))/2)
[1] 0.08141321
What is the density of the directed dolphin data?
graph.density(dataps2d)
[1] 0.04070661
Why is the density this value now? How does it compare to what you found in Question 1?
rr #The density of a directed network is half that of an undirected one because there are twice as many possible edges. In the directed network the density is 0.04070661, which is lower than the density in the undirected network (0.08141321). The directed network density is lower, because when we went from an undirected to a directed network, we are adding edges even though we did not add nodes.
Karate club density, automatically and manually:
graph.density(g)
[1] 0.1390374
Let’s make this clearier to understand what’s happening:
totaledges/possibleedges
[1] 0.1390374
Same, counting directly from the adjacency matrix:
sum(colSums(d))/(nrow(d)*ncol(d))
[1] 0.1349481
Our directed graph:
edges/possibleedges
[1] 0.1764706
Our undirected graph:
graph.density(g_temp2b)
[1] 0.4571429
Do you notice anything about the density of the directed graph? It is lower. Why is the density of the undirected graph higher than that of the directed one even though they use the same data? Because when we went from undirected to directed adjacency matrices, we added a 1 to the bottom left or top right triangle if it did not exist before. So, we are adding edges even though we are not adding nodes.
Generate a 10 x 10 matrix.
rr number <- 10 thismatrix <- matrix(rbinom(number^2, 1, .5), nrow=number)
Calculate its directed density.
tm_d <- graph_from_adjacency_matrix(thismatrix, mode='directed')
tm_d <- graph_from_adjacency_matrix(thismatrix, mode='directed')
graph.density(tm_d)
[1] 0.6111111
edges <- sum(thismatrix)
possibleedges <- nrow(thismatrix)*ncol(thismatrix)-nrow(thismatrix)
edges/possibleedges
[1] 0.6111111
Calculate its undirected density. Remember, the calculation is the same once you define the edges correctly. First, make symmetric before passing to igraph and remove self loops.
graph.density(tm_u, loops=FALSE)
[1] 0.4888889
CLUSTERING
What is the global clustering of the undirected dolphin data (two options)?
transitivity(dataps2, type = "global")
[1] 0.3087757
What is the node with the highest local clustering value (two options)?
V(data)[V(data)$clustering == clusteringMax]
+ 0/62 vertices, from 294c26f:
Note that one can specificy undirected but it does not change the calculation; igraph does not appear to calculate directed clustering, globally or locally:

Calculate the global transitivity for our directed graph. transitivity(tm_d, type=‘global’)
Calculate the local transitivity for our directed graph. transitivity(tm_d, type=‘local’)
Calculate the global transitivity for our undirected graph. transitivity(tm_u, type=‘global’) transitivity(tm_u, type=‘globalundirected’)
Calculate the local transitivity for our undirected graph. transitivity(tm_u, type=‘local’) transitivity(tm_u, type=‘localundirected’)
Find the node with the highest clustering coefficient for the directed network. V(tm_d)[transitivity(tm_d, type=‘local’) == max(transitivity(tm_d, type=‘local’))]
mt <- max(transitivity(tm_d, type=‘local’)) V(tm_d)[transitivity(tm_d, type=‘local’) == mt]
Find the node with the lowest clustering coefficient undirected network. V(tm_u)[transitivity(tm_u, type=‘local’) == min(transitivity(tm_u, type=‘local’))]
mint <- min(transitivity(tm_u, type=‘local’)) V(tm_u)[transitivity(tm_u, type=‘local’) == mint]
Plot the relationship between degree and clustering for the 10x10 undirected network. plot(degree(tm_u), transitivity(tm_u, type=‘local’), xlab=‘Node Degree’, ylab=‘Local Clustering’, pch=20)
RANDOM NETWORK
Generate a random network containing 200 nodes with a probability of .2 that any two nodes are connected. Use igraph to convert it to an undirected matrix. Make a histogram of the degree distribution, label the axes, give it a title, and save it to file (two options).

Repeat Problem 1, except vary the probability of ties from .1 to 1 in increments of .1. Save each histogram in a file. What do you notice as p changes?
rr nodes <- 200 prob <- seq(.1,1,by=.1)
for(i in 1:length(prob)){ thenetwork <- matrix(rbinom(nodes^2, 1, p=prob[i]), nrow=nodes) diag(thenetwork) <- 0 thenetwork <- graph_from_adjacency_matrix(thenetwork, mode=‘upper’)
pdf(paste0(‘~/Desktop/UCLA’, prob[i], ‘.pdf’)) hist(degree(thenetwork), xlab=‘Degree’, ylab=‘Count’, main=paste0(‘Distribution of Degree, p=’, prob[i]), breaks=50) dev.off() }
#Making Symmetric Networks From an Adjacency Matrix
Convert an unbalaned adjacency matrix to an undirected adjacency matrix. Start by making the matrix:
rr probability <- .2 thisnumber <- 12 thismatrix <- matrix(rbinom(thisnumber^2, 1, probability), nrow=thisnumber) diag(thismatrix) <- 0
Convert it to an undirected network.
t(thismatrix)
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
[1,] 0 0 0 1 0 1 1 0 0 1 0 0
[2,] 0 0 1 0 0 0 0 0 1 0 0 0
[3,] 0 0 0 1 0 0 0 1 0 0 0 0
[4,] 0 0 0 0 0 0 0 0 0 0 0 0
[5,] 0 0 0 0 0 0 0 0 1 0 0 0
[6,] 0 0 0 0 1 0 0 0 0 0 0 0
[7,] 0 0 0 1 1 0 0 0 0 0 0 0
[8,] 0 0 0 0 0 0 0 0 0 0 0 0
[9,] 0 1 0 0 0 1 0 1 0 0 0 1
[10,] 0 0 0 0 0 0 0 0 0 0 0 1
[11,] 0 0 0 0 0 1 0 0 0 0 0 0
[12,] 0 0 0 0 0 0 0 1 0 0 0 0
RANDOM GRAPH
Build random graphs from matrices. Then, we use igraph to build a random graph. In both cases, we will learn about the network via some statistics. At the end of this section, we will learn how to automatically vary parameters and view the statistics of the resulting networks. Create using matrix.
howmanyrows <- 100
temp <- matrix(rbinom(howmanyrows^2, 1, .5), nrow=howmanyrows)
diag(temp) <- 0 # Make sure there are no self-loops.
# Do not forget to make symmetric
temp[lower.tri(temp)] <- t(temp)[lower.tri(temp)]
bus720 <- graph_from_adjacency_matrix(temp, mode='undirected') # I have chosen a weird object name to emphasize that they are arbitrary. Most documentation for igraph calls graph objects g, but you do not have to.
Explore degree:
summary(degree(bus720))
Min. 1st Qu. Median Mean 3rd Qu. Max.
36.00 46.00 50.00 49.66 53.00 66.00
Explore clustering:
transitivity(bus720, type="local")[1:10]
[1] 0.5206349 0.5132979 0.5063425 0.4804878 0.4964706 0.4956140 0.5130435 0.5045455
[9] 0.5175510 0.4927536
Explore density:
graph.density(bus720)
[1] 0.5016162
Now, let us learn how to have igraph make a random graph for us. I will then show how you can vary the density of the graph using a loop; you could do the same for nodes, but I leave that exercise for the problem set. I will then show how to put the output from each variation into a dataframe; otherwise, you lose the results as each new loop runs. Create using igraph package, explore degree, clustering, density.
graph.density(ibus720)
[1] 0.4923232
SMALL-WORLD NETWORKS
Recreate the small-world chart I showed in class, the one that shows how average path length and clustering change as the probability of rewiring edges increases. Make the network a ring with 1,000 nodes where each node is connected to ten neighbors. As you work on this problem, keep in mind six things: a. You will need a baseline model by which to normalize (divide) the values of each simulation. That is, you will need a model that does not change for each iteration of the loop. b. Make sure you have very small values of p, smaller than the class example. c. Make sure the x-axis is the logarithm of p. 1. If one of your values of p is 0, you should add a small amount, such as .01 or .1, to each value of the rewiring probability when you plot. log(0) is undefined, but you need to see the result for that value. 2. When you do this, you may notice the x-axis values become negative. It is acceptable if you leave the values like that, but I encourage you to explore how to fix them. Subhint: look at xaxt in plot() and axis() after plot(). Subhint2: You could also look at the log argument in plot(). d. To add a second line to a graph, use lines() after plot(). e. Save the chart to your computer. f. How will you distinguish which line corresponds to which statistic? Use the lty argument to lines() and plot(). If you are adventurous, add a legend to the plot as well.

Use igraph: From here on out, we will rely on igraph’s functions to build networks. While we could build them manually from adjacency matrices, creating the proper adjacency matrix or edgelist is a bit more complicated. It is doable but not necessary for the aims of this class. The igraph function sample_smallworld can be confusing. You define the number of dimensions of the lattice; 1 means a line, 2 means a matrix, and so on. The dimension will raise the number of nodes you want to the power of the dimension. It is therefore easiest to just define the number of nodes you want and assume one dimension. nei is how far (many steps) in each direction to make connections between nodes; the higher it is, the greater the average degree.
Create a small-worl network using igraph package, explore degree, clustering, density:
graph.density(bus20)
[1] 0.06060606
Let’s make the printed output a little easier to read.
paste('The density of the graph is', graph.density(bus20))
[1] "The density of the graph is 0.0606060606060606"
Let’s do that again, changing the size of the network fro 100 to 1,000.
rr nodes <- 1000
bus20 <- sample_smallworld(dim=1, size=nodes, nei=3, p=.2)
Let’s make the printed output a little easier to read.
summary(degree(bus20))
Min. 1st Qu. Median Mean 3rd Qu. Max.
1 5 6 6 7 12
paste('The graph\'s transitivity is', round(transitivity(bus20, type='global'), 5))
[1] "The graph's transitivity is 0.16376"
paste('The other way to calculate transitivity suggests the value is', mean(transitivity(bus20, type='local')))
[1] "The other way to calculate transitivity suggests the value is NaN"
paste('The other way to calculate transitivity suggests the value is', mean(transitivity(bus20, type='local'), na.rm=TRUE))
[1] "The other way to calculate transitivity suggests the value is 0.185631518964852"
paste('The density of the graph is', graph.density(bus20))
[1] "The density of the graph is 0.00600600600600601"
paste('There are', ecount(bus20), 'edges in the graph')
[1] "There are 3000 edges in the graph"
Now, we can vary the parameters like we did for random graphs. Since we are familiar with this process, I will vary p and save the results to a dataframe immediately. Notice that I define how many iterations of the loop differently than for random graphs; they both work the same. I am going to introduce a new way to generate sequences of numbers as well.
Vary p using sequence. There are two ways to do this.
Why does the density never change? Because it is the percentage of possible edges that actually exist; density tells you about the network overall (while degree tells you something about individual nodes)
Create a small-world ring network with 100 nodes that each start with connections to 10 neighbors. Randomly rewire with probability of .03.
sw
IGRAPH 77a5caa U--- 100 500 -- Watts-Strogatz random graph
+ attr: name (g/c), dim (g/n), size (g/n), nei (g/n), p (g/n), loops (g/l),
| multiple (g/l)
+ edges from 77a5caa:
[1] 1-- 2 2-- 3 3-- 4 4-- 5 5-- 6 7--74 7-- 8 8-- 9 10--82 10--11 11--12
[12] 12--13 13--14 14--15 15--16 16--17 17--18 18--19 19--20 20--21 21--22 22--23
[23] 23--24 24--25 25--26 26--27 27--28 28--29 29--30 30--31 14--32 32--33 33--34
[34] 34--35 35--36 36--37 24--37 38--39 39--40 40--41 41--42 42--43 43--44 44--45
[45] 45--46 46--47 47--48 48--49 49--50 50--51 51--52 52--53 53--54 54--55 55--56
[56] 56--57 57--58 58--59 59--60 60--61 61--62 62--63 63--64 64--65 65--66 66--67
[67] 67--68 68--69 69--70 70--71 71--72 72--73 73--74 74--75 18--75 77--96 77--78
+ ... omitted several edges
Write a loop that creates a new small-world network each iteration. Vary the rewiring probability from 0 to .2 in increments of .01. Save the results in a dataframe, tracking at least the overall clustering, diameter, and average path length.
SCALE FREE NETWORKS
Create a scale free network with 12,000 nodes where each node adds 20 edges.
a. Make a histogram of the degree distribution. b. What is the ratio of the mean to median degree? c. Is the density less than a small-world network? Why?
graph.density(sf)
[1] 0.003330694
Now, we will explore scale-free networks, using Barabasi’s model of preferential attachment. While there are many mechanisms that can generate scale-free distributions, his is the most commonly used and therefore the one most commonly included out of the box in software. We will focus on varying the number of edges added to a network. A key feature of scale-free networks is that the mean degree is much higher than the median; we will track that ratio.
degree_distribution(sf)
[1] 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
[7] 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 1.615000e-01 1.225833e-01
[13] 9.866667e-02 7.875000e-02 6.375000e-02 5.725000e-02 4.841667e-02 3.783333e-02
[19] 3.300000e-02 2.925000e-02 2.550000e-02 2.066667e-02 1.966667e-02 1.608333e-02
[25] 1.325000e-02 1.308333e-02 9.833333e-03 1.033333e-02 1.000000e-02 8.416667e-03
[31] 8.416667e-03 6.750000e-03 6.083333e-03 5.666667e-03 5.916667e-03 5.916667e-03
[37] 4.750000e-03 3.833333e-03 4.000000e-03 2.666667e-03 2.250000e-03 2.166667e-03
[43] 3.250000e-03 2.416667e-03 2.916667e-03 2.333333e-03 2.166667e-03 2.666667e-03
[49] 2.083333e-03 1.750000e-03 7.500000e-04 1.250000e-03 2.250000e-03 1.916667e-03
[55] 1.750000e-03 1.416667e-03 1.000000e-03 1.250000e-03 8.333333e-04 5.000000e-04
[61] 1.500000e-03 1.083333e-03 9.166667e-04 8.333333e-04 4.166667e-04 8.333333e-04
[67] 5.000000e-04 6.666667e-04 7.500000e-04 5.000000e-04 5.833333e-04 5.000000e-04
[73] 2.500000e-04 9.166667e-04 5.833333e-04 2.500000e-04 5.833333e-04 4.166667e-04
[79] 4.166667e-04 5.000000e-04 8.333333e-04 4.166667e-04 5.000000e-04 2.500000e-04
[85] 5.000000e-04 3.333333e-04 5.000000e-04 4.166667e-04 4.166667e-04 5.000000e-04
[91] 2.500000e-04 2.500000e-04 1.666667e-04 5.000000e-04 3.333333e-04 8.333333e-05
[97] 3.333333e-04 4.166667e-04 2.500000e-04 8.333333e-05 3.333333e-04 3.333333e-04
[103] 1.666667e-04 1.666667e-04 5.833333e-04 2.500000e-04 8.333333e-05 8.333333e-05
[109] 3.333333e-04 0.000000e+00 0.000000e+00 1.666667e-04 4.166667e-04 1.666667e-04
[115] 2.500000e-04 1.666667e-04 8.333333e-05 8.333333e-05 8.333333e-05 0.000000e+00
[121] 0.000000e+00 0.000000e+00 8.333333e-05 0.000000e+00 0.000000e+00 0.000000e+00
[127] 8.333333e-05 1.666667e-04 1.666667e-04 8.333333e-05 1.666667e-04 1.666667e-04
[133] 1.666667e-04 1.666667e-04 8.333333e-05 1.666667e-04 8.333333e-05 8.333333e-05
[139] 0.000000e+00 1.666667e-04 0.000000e+00 2.500000e-04 0.000000e+00 0.000000e+00
[145] 0.000000e+00 0.000000e+00 0.000000e+00 8.333333e-05 0.000000e+00 1.666667e-04
[151] 0.000000e+00 8.333333e-05 0.000000e+00 8.333333e-05 8.333333e-05 0.000000e+00
[157] 2.500000e-04 8.333333e-05 0.000000e+00 0.000000e+00 8.333333e-05 0.000000e+00
[163] 0.000000e+00 0.000000e+00 8.333333e-05 8.333333e-05 8.333333e-05 0.000000e+00
[169] 0.000000e+00 0.000000e+00 8.333333e-05 0.000000e+00 0.000000e+00 0.000000e+00
[175] 0.000000e+00 0.000000e+00 0.000000e+00 8.333333e-05 8.333333e-05 0.000000e+00
[181] 0.000000e+00 8.333333e-05 0.000000e+00 0.000000e+00 0.000000e+00 8.333333e-05
[187] 0.000000e+00 0.000000e+00 0.000000e+00 8.333333e-05 0.000000e+00 0.000000e+00
[193] 8.333333e-05 0.000000e+00 8.333333e-05 0.000000e+00 1.666667e-04 0.000000e+00
[199] 0.000000e+00 0.000000e+00 0.000000e+00 8.333333e-05 1.666667e-04 8.333333e-05
[205] 0.000000e+00 0.000000e+00 0.000000e+00 8.333333e-05 0.000000e+00 0.000000e+00
[211] 0.000000e+00 8.333333e-05 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
[217] 1.666667e-04 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
[223] 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 8.333333e-05
[229] 8.333333e-05 0.000000e+00 0.000000e+00 8.333333e-05 0.000000e+00 0.000000e+00
[235] 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
[241] 0.000000e+00 8.333333e-05 0.000000e+00 8.333333e-05 0.000000e+00 0.000000e+00
[247] 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 8.333333e-05 0.000000e+00
[253] 0.000000e+00 0.000000e+00 0.000000e+00 8.333333e-05 0.000000e+00 0.000000e+00
[259] 0.000000e+00 8.333333e-05 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
[265] 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 8.333333e-05
[271] 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
[277] 8.333333e-05 0.000000e+00 0.000000e+00 0.000000e+00 8.333333e-05 0.000000e+00
[283] 0.000000e+00 0.000000e+00 0.000000e+00 8.333333e-05 0.000000e+00 0.000000e+00
[289] 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
[295] 0.000000e+00 0.000000e+00 1.666667e-04 0.000000e+00 0.000000e+00 0.000000e+00
[301] 0.000000e+00 0.000000e+00 8.333333e-05 0.000000e+00 0.000000e+00 0.000000e+00
[307] 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
[313] 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
[319] 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
[325] 0.000000e+00 0.000000e+00 0.000000e+00 8.333333e-05 0.000000e+00 0.000000e+00
[331] 0.000000e+00 0.000000e+00 8.333333e-05 0.000000e+00 0.000000e+00 0.000000e+00
[337] 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
[343] 0.000000e+00 0.000000e+00 0.000000e+00 1.666667e-04 0.000000e+00 0.000000e+00
[349] 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
[355] 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
[361] 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
[367] 0.000000e+00 0.000000e+00 0.000000e+00 8.333333e-05 0.000000e+00 0.000000e+00
[373] 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
[379] 0.000000e+00 0.000000e+00 8.333333e-05 0.000000e+00 0.000000e+00 8.333333e-05
[385] 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
[391] 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
[397] 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
[403] 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 8.333333e-05
[409] 0.000000e+00 8.333333e-05 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
[415] 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 8.333333e-05 0.000000e+00
[421] 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
[427] 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
[433] 0.000000e+00 0.000000e+00 0.000000e+00 8.333333e-05 0.000000e+00 0.000000e+00
[439] 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
[445] 0.000000e+00 0.000000e+00 0.000000e+00 8.333333e-05 0.000000e+00 0.000000e+00
[451] 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
[457] 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
[463] 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 8.333333e-05 0.000000e+00
[469] 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
[475] 0.000000e+00 0.000000e+00 8.333333e-05
Let’s make the printed output a little easier to read.

Now, let’s use a loop to see how these measures change as we increase the number of nodes in the network. Let us increase it in units of 1,000. Vary network size using a loop:
nodes <- seq(from=1000,to=10000,by=1000)
remember <- data.frame(iteration=NULL, networkSize=NULL, avgDegree=NULL, globalClustering=NULL, glbalClustering2=NULL, density=NULL, ratio=NULL, avgPathLength=NULL)
for(i in 1:length(nodes)){
temp <- sample_pa(n=nodes[i], power=1, m=10, directed=FALSE)
print(paste('This is loop', i, 'of', length(nodes)))
d <- data.frame(iteration=i, size=nodes[i], avgDegree=mean(degree(temp)), globalClustering=transitivity(temp, type='global'), globalClustering2=mean(transitivity(temp, type='local')), density=graph.density(temp), ratio=mean(degree(temp))/median(degree(temp)), avgPathLength=average.path.length(temp))
remember <- rbind(remember, d) # "rowbind", adds a new row, d, to whatever exists in remember.
}
remember # Not bad.
REAL NETWORKS
In this section, we will explore actual network data. The first dataset is e-mails from Enron, an energy firm that imploded when its accounting manipulations were discovered. The second is a sample of individuals from Facebook.
Load Enron:
ecount(enron)
[1] 116865
summary(degree(enron2))
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.000 0.000 1.000 6.375 2.000 1367.000
paste('The graph\'s transitivity is', transitivity(enron2, type='global'))
[1] "The graph's transitivity is 0.0715762061104356"
paste('The other way to calculate transitivity suggests the value is', mean(transitivity(enron2, type='local')))
[1] "The other way to calculate transitivity suggests the value is NaN"
paste('The density of the graph is', graph.density(enron2))
[1] "The density of the graph is 0.000173859823993874"
paste('There are', ecount(enron2), 'edges in the graph')
[1] "There are 116865 edges in the graph"
paste('The diameter is', diameter(enron2)) # Takes awhile to run.
[1] "The diameter is 7"
paste('The average path length is', average.path.length(enron2))
[1] "The average path length is 3.5201731990681"
We can also take subsets of a network based on node features. Below, I will show you how to keep only nodes meeting degree thresholds.
vcount(degree10)/vcount(enron2) # 8.94% of nodes
[1] 0.08940163
ecount(degree10)/ecount(enron2) # 62.45% of edges
[1] 0.6245497
You can keep nodes that match any sort of filter you want. Next, I show based on clustering. Show how to select nodes with high clustering
table(degree(highclustering_g))
0 1 2 3 4 5 6 7 8 9
7462 364 95 54 37 10 13 2 2 2
CALCULATIONS (vectors, objects, phrases)
What is 3819 times 102?
rr 3819 * 102
What is 3819 minus 1892?
rr 3819 - 1892
Repeat the above, but save each number as an object.
rr obj1 <- 3819 obj2 <- 1892 obj1 * obj2 obj1 - obj2
Make a vector of the numbers 10, 20, 30, 40, and 50. Multiply that vector # by another of the numbers 3, 4, 5, 6, and 7.
rr v1 <- c(10, 20, 30, 40, 50) v1_alt <- seq(from = 10, to = 50, by = 10) v2 <- c(3, 4, 5, 6, 7) v2_alt <- 3:7
v1 * v2 v1_alt * v2_alt
Repeat above, except make the second vector the numbers 5 and 10. Show the results and explain, in words, what R is doing with this shorter vector.
rr v2 <- c(5, 10) v1 * v2
#(Warning in v1 * v2: longer object length is not a multiple of shorter object length): R repeats the v2 vector as many times as it takes to match the length of v1. So, it creates a vector that is (5,10,5,10,5)
Does the phrase, “I enjoy learning to program” contain the word “learning”? What about “learn”? What about “towards”?
rr > phrase <- c(‘I enjoy learning to program’) > grepl(‘learning’, phrase) [1] TRUE > grepl(‘learn’, phrase) [1] TRUE > grepl(‘towards’, phrase) [1] FALSE
Why does R return [1]?
rr #Because it is telling the result is a vector of length 1. Vectors and calculation become especially useful when your vector has length greater than 1, such as when it represents a variable with multiple observations. You can then easily manipulate all entries in one vector or perform operations on multiple vectors. To make a vector of length greater than 1, you need c(). The stands for .
Practice with vectors of length greater than 1:
rr first <- c(100,19,20,89,76,102,74,81,65) first * 2
#This multiplies each entry by 2 (great to convert inches to centimeters) first - 20
#This subtracts each entry by 20
second <- c(1,2,4,10,10,1,4,5,10) #Do not need to have the exact same number of entries again, but made it more simple)
first * second
#Multiplies each entry in first by second in order, ie 1*100; multiplying each entry is weighting data first / second
Example using vectors to calculate a more complicated outcome:
rr observed <- first # I have created a new object that has the values of first, i.e., is mapped to first above.
observed == first
# Returns TRUE for as many entries as there are in each vector. (Need two equal marks, one equal will just make a copy like <-, while this compares, good way to check data after doing a transformation)
observed != first #(booleian operation for does not equal)
Chi-square
rr expected <- c(90,18,30,79,80,88,80,83,70) numerator <- (observed-expected)^2 sum(numerator/expected)
Vectors do not have to be numbers. For example, you may have a variable that is a respondent’s favorite sports team, so the entries are likely to be words. If you have a dataframe, the column names are a string vector:
rr char_vec <- c(, , , ) length(char_vec)
‘words’ %in% char_vec ‘words’ == char_vec #for how often ‘word’ %in% char_vec #^good for searching larger texts
sametype <- c(‘this’, 20, ‘converts to’, 5, ‘strings’) #^if R is unsure of a thing it converts it into a string
Create an object that contains five numbers. Multiply those numbers by 2. Add 82 to those numbers.
rr this <- c(1,2,3,4,5) this*2 this+82
Create a second object that contains five numbers. Multiply the two objects together and save the result as a new object. Divide the two objects, saving the result as a new object.
rr arbitrary <- c(18,18,93,103, 45) new <- this*arbitrary new <- this/arbitrary
Does the vector contain the word “tomato”?
rr characters <- c(‘this’, ‘vector’, ‘contains’, ‘words’, ‘that’, ‘have’, ‘words’, ‘with’, ‘letters’, ‘and’, ‘numbers’, 29, ‘30’ )
‘tomato’ %in% characters
How many times does the vector contain the word “words”?
rr grep(‘words’, characters) length(grep(‘words’, characters))
Search the vector for the number 29.
rr grep(‘29’, characters)
Search the vector for the number 100.
rr grep(‘100’, characters)
#integer(0) –> way R says no
It works differently if the words are not separated in a vector:
rr words <- c(‘this vector contains words that have words with letters and numbers 29 30’) ‘this’ %in% words
#FALSE because the word this does not = the first unit in vector words
length(words)
grep(‘this’, words) grepl(‘this’, words)
Notice that grep partial matches by default. To get exact word, use spaces; grep will tell me anywhere vs %in% which is an exact match
grepl(‘contain’, words) grepl(‘contain’, words)
Note: You cannot give a vector a number, e.g., in scores[2,4], R is looking for the second row and fourth column; would need to write:
rr scores <- c(John=25, Marge=34, Dan=24, Emily=29) scores[c(2,4)]
Return individuals with scores greater than 30:
rr scores[scores > 30]
DATA STRUCTURES (create a list, matrix, dataframe, identify variables)
Name each vector in the list:
rr mary_info <- list(classes=c(, , , ), friends=c(, , ), SAT=c(1450,1000,1600))
Return the second vector:
rr mary_info[[2]]
Return the vector named “SAT”
rr mary_info$SAT
Return the second element of friends vector
rr mary_info$friends[2]
Make a list that contains the three departments at Luskin as well as the number of enrolled students in each. Assume the numbers are 60, 80, and 100.
rr list0 <- list(depts = c(, , ), enrolled = c(60 80, 100))
For these next questions, use the list created in the below code.
rr list1 <- list(names=c(‘John’, ‘Kate’, ‘Jessica’, ‘Carl’), grades=c(80,85,60,100), sex=c(‘Male’, ‘Female’, ‘Female’, ‘Male’))
Who has grades greater than 83?
rr list1\(names[list1\)grades > 83]
Which people are female?
rr list1\(names[list1\)sex == ]
Create a 2x3 matrix, filling down columns:
rr a <- matrix(1:6, nrow=2)
Fill across rows:
rr b <- matrix(5:14, nrow=2, byrow=TRUE)
Row 2, column 3:
rr a[2,3]
All rows, column 2:
rr b[,2]
All columns, row 1:
rr a[1,]
Other ways to create matrices:
rr matrix(c(0,1,1,1,0,1,0,0,1), nrow=3)
matrix(0:1, nrow=10, ncol=10)
Create a matrix of 10 rows and 10 columns where each entry is the number 0 or 1 (multiple options).
rr m1 <- matrix(rbinom(100, 1, 0.5), nrow = 10) m <- matrix(0:1, nrow=10, ncol=10)
Show me the first row of the matrix.
rr m1[1, ]
Show the first six rows of the matrix (two options).
rr head(m1) m1[1:6, ]
Show rows 4 through 8.
rr m1[4:8, ]
Show rows 3, 5, 7, and 9.
rr m1[c(3, 5, 7, 9), ]
Show the third column of the matrix.
rr m1[, 3]
Show the third, fifth, and seventh columns of the matrix.
rr m1[, c(3, 5, 7)]
Convert the grades list from above into a data frame (four options).
rr d1 <- data.frame(list1)
as.data.frame(list1)
d1b <- data.frame(names=c(‘John’, ‘Kate’, ‘Jessica’, ‘Carl’), grades=c(80,85,60,100), sex=c(‘Male’, ‘Female’, ‘Female’, ‘Male’))
data.frame(list1)
Who has grades greater than 90?
rr d1[d1$grades > 90, ]
Which people are male?
rr d1[d1$sex == , ]
What are the first six rows and nine columns in the SCAD data?
rr data[1:6, 1:9]
What are the last five rows in the SCAD data (two options)?
rr tail(data, 5) data[(nrow(data)-5):nrow(data),]
Show rows 100 to 107 in the SCAD data.
rr data[100:107, ]
What are the names of the columns in the SCAD data?
rr names(data)
How many times does each country appear in the dataset using ‘table’ in the SCAD data?
table(SCADdata$countryname)
Costa Rica Cuba Dominican Republic El Salvador
35 278 214 135
Guatemala Haiti Honduras Jamaica
348 1322 214 275
Mexico Nicaragua Panama Trinidad and Tobago
1905 165 97 45
How many events started in each year?
rr table(data\(styr) table(data\)eyr)
Write code to save only events that started in 2006 as a new object.
rr new <- data[data$styr == 2006, ]
How many events started in 2006?
rr nrow(new)
Make a table showing the number of events per country that started in 2006.
rr table(new$countryname)
Drop all events where the number of participants is -99.
rr new2 <- data[data$npart != -99, ]
Create a logical vector and numeric vector of equal length:
rr mydata <- data.frame(diabetic = c(TRUE, FALSE, TRUE, FALSE), height = c(65, 69, 71, 73), sex=c(‘Male’, ‘Female’, ‘Female’, ‘Male’), minutesExercise = c(20,30,22,80))
Identify row 3, column 2 height of third male:
rr mydata[3,2]
Using column name, identify the first two rows:
rr mydata[1:2, ]
List all rows of column “diabetic”:
rr mydata[,]
Subsetting creates a numeric vector:
rr mydata$height[2:3]
Numeric vector:
rr mydata[[]]
What are the names of my variables?
rr colnames(mydata)
Assign column names:
rr colnames(mydata) <- c(, , , of Exercise per Week)
#Prof recs alphabetizing
To change the first variable’s name, just use indexing:
rr colnames(mydata)[1] <-
#to verify: colnames(mydata) == ‘Diabetes’
#If you do not now the index but know the name, you can do that too: colnames(mydata)[colnames(mydata) == ‘Diabetes’] <- ‘Diabetic’
#^Where the column name is , change it to .
What are the dimensions of my data frame?
rr dim(mydata)
What are the first five rows?
rr head(mydata)
What are the last five rows?
rr tail(mydata)
Get information about the dataframe, structure:
rr str(mydata)
Get summary statistics:
rr summary(mydata)
summary(mydata$height)
Get number of rows:
rr nrow(mydata)
#Don’t select on col numbers, they won’t stay the same; use colnames(mydata)[colnames(mydata) == ‘Diabetes’] (can also use grep)
Create a dataframe that is five rows tall and three columns wide. The first column is people’s names: Amanda, Brandon, Carl, David, and Eleanor. The second column is their birth year: 1981, 1928, 1997, 2002, 1989. The third column is their height in centimeters: 200, 180, 176, 190, 210.
rr mydata <- data.frame(diabetic = c(TRUE, FALSE, TRUE, FALSE), height = c(65, 69, 71, 73), sex=c(‘Male’, ‘Female’, ‘Female’, ‘Male’), minutesExercise = c(20,30,22,80))
d2 <- data.frame(names=c(‘Amanda’, ‘Brandon’, ‘Carl’, ‘David’, ‘Eleanor’), year=c(1981, 1928, 1997, 2002, 1989), height = c(200,180,176,190,210))
Select rows three through five of the dataframe.
rr d2[3:5,]
Rename the name column to “First_Name”. Rename the birthyear column to “Year”.
rr colnames(d2)[colnames(d2)==‘names’] <- ‘First_Name’ colnames(d2)[colnames(d2)==‘year’] <- ‘Year’
Create a new dataframe of only the individuals who are at least 200 centimeters tall.
rr dtall <- d2[d2$height > 200,]
Create a four row, four column matrix. Multiple that matrix by 3.
rr m <- matrix(1:3, nrow=4, ncol=4) m2 <- matrix(1:16, nrow=4)
m2*3
From that matrix, take the sum of the first column. Take the sum of the third row.
rr sum(m2[,1]) m2[,1] temp <- m2[,1] sum(temp)
sum(m2[3,])
How many columns? ncol(data)
How many rows? nrow(data)
What are the column names? names(data)
What are the row names? rownames(data)
What are the first 6 rows? head(data)
What are the last 6 rows? tail(data)
Note that you can tell head() and tail() how many rows you want to see. 5 is the default. head(data, 10) head(data, 2)
tail(data, 8) tail(data, 2)
If you want to know the set of values a variable takes, use unique() unique(data\(COUNTRY) unique(data\)BYEAR)
If you want to get a sense of how many observations there are for each value of a variable, use table() table(data\(COUNTRY) table(data\)BYEAR)
Explore how to access different data points, based on variable values. We will then modify some of these variables and save the result to a new file.
rr # Select by year.
temp <- data[data$BYEAR == ‘2010’,]
# The events from 2010 are now in this dataframe dim(temp) nrow(temp) - nrow(data)
temp <- data[data$BYEAR == ‘2011’,]
# Now, the dataframe is for 2011.
temp <- data[data$BYEAR < 2010,]
temp2 <- data[data$BYEAR <= 2010,]
nodeaths <- data[data$NDEATH == 0,] january <- data[data$BMONTH == 1,] notjanuary <- data[data$BMONTH != 1,] # != means equal to. notjanuary2 <- data[data$BMONTH > 1,]
Manipulate variables and then save the dataframe. Remember, each column is just a vector, so the vector operations we learned earlier are what we will do here. Note that I do some transformations, like multiple BDAY by BMONTH, just to demonstrate capabilities.
rr data\(newnpart <- data\)NPART*10 data\(newnpart2 <- ifelse(data\)NPART != 99, data\(NPART, NA) data\)npart <- data$NPART/1000
names(data) # Notice that the above line created a new variable.
data\(NPART <- data\)NPART/1000
# Creating a new variable with the same name as an existing one replaces that variable
data\(deathRate <- data\)NDEATH/data\(NPART # What does this do? summary(data\)deathRate) # It did nothing because NDEATH is weirdly constructed.
# We will not discuss here how to fix it.
data\(nonsense <- data\)BDAY*data\(BMONTH data\)COUNTRY[data$COUNTRY == ‘Cote d'Ivoire’] <- ‘Ivory Coast’
# Fails because R treats country name as a factor.
Load the dataframe from earlier. Add the argument `stringsAsFactors=FALSE’.
rr data <- read.csv(‘~/Documents/UCLA/Data/PRIO_UrbanSocialDisorder/events.csv’, stringsAsFactors = FALSE) data\(COUNTRY[data\)COUNTRY == ‘Cote d'Ivoire’] <- ‘Ivory Coast’
How could you verify that the change happened?
rr # Save the file. Make sure to change the file path for your computer. write.csv(data, ‘~/Documents/UCLA/Data/PRIO_UrbanSocialDisorder/events_v3.csv’)
write.table(data, ‘~/Documents/UCLA/Data/PRIO_UrbanSocialDisorder/events_v3.txt’, sep=’)
What are the first five rows?
rr head(mtcars, 5) mtcars[1:5,]
What are the last five rows?
rr tail(mtcars, 5)
What are rows 12 through 21?
rr mtcars[12:21,]
What are the column names?
rr names(mtcars) sort(names(mtcars))
Using mtcars: create a new variable that is horsepower per cylinder.
rr mtcars\(hpc <- mtcars\)hp/mtcars$cyl
Using mtcars: Weight is in thousands of pounds. Create a new variable that is weight in pounds.
rr mtcars\(wt_new <- mtcars\)wt*1000
Using mtcars: Create a new dataframe of cars that get at least 20 miles per gallon. How many cars is that?
rr new_mtcars <- mtcars[mtcars$mpg >= 20,]
Using mtcars: Create a new dataframe of cars that get fewer than 20 miles per gallon.
rr new_mtcars2 <- mtcars[mtcars$mpg < 20,]
PLOTS (histograms, plots, save pdf)
Make a plot of the number of participants at each event using the SCAD data. Label the x and y axis.

Save that plot
rr pdf(~/Desktop/UCLA/Courses/4_Fall 2019/PP 290/Assignments/assn1plot1.pdf) plot(data\(npart[data\)npart != -99], xlab = Index, ylab = of Participants) dev.off()
Make a histogram of the number of participants at each event. Make sure to label the axes.

Make a barplot of the number of participants per event. Hint: you will need to use table as well.

Load data, explore it.
Now plot it:
barplot(table(SCADdata$BYEAR))
no non-missing arguments to min; returning Infno non-missing arguments to max; returning -Infno non-missing arguments to min; returning Infno non-missing arguments to max; returning -InfError in plot.window(xlim, ylim, log = log, ...) :
need finite 'xlim' values

Using mcars: Make a table of the gear variable.
table(mtcars$gear)
3 4 5
15 12 5
Using mcars: Make a proportion table of the gear variable.
prop.table(table(mtcars$gear))
3 4 5
0.46875 0.37500 0.15625
Using mcars: Make a two-way table of the number of cylinders and number of gears.
table(mtcars$gear, mtcars$cyl)
4 6 8
3 1 2 12
4 8 4 0
5 2 1 2
Using mcars: Make a two-way proportion table of the number of cylinders and number of gears. Make one table where the cells add to 1, another where each column adds to 1, and another where each row does.
prop.table(table(mtcars$gear, mtcars$cyl), margin=1)
4 6 8
3 0.06666667 0.13333333 0.80000000
4 0.66666667 0.33333333 0.00000000
5 0.40000000 0.20000000 0.40000000
Using mcars: Plot the miles per gallon against the number of cylinders.

Using mcars: Make a barplot of the cars by the carb variable.

Using mcars: Make a histogram of miles per gallon.

#Non-Network Plots
names(mtcars) # The variables
[1] "mpg" "cyl" "disp" "hp" "drat" "wt" "qsec" "vs" "am" "gear" "carb"
[12] "car"
Base Plotting

Base Plotting, with Multiple Variables: As we learned in lecture, a two-dimensional plot is often too simplistic for the relationships we want to inspect. We will now learn how to change the size, shape, and color of points.

Change the size with the cex argument
legend('topright', legend='Sized by displacement')
Error in strwidth(legend, units = "user", cex = cex, font = text.font) :
plot.new has not been called yet
Change the size with the cex argument

Why would a square root result in dots that are too large? mtcars is very large! Because you do not want the cex numbers to be too large, it is common to take the square root or logarithm. Here, square roots will still create dots that are too large, so I divide by 100 as well as take the logarithm.
What does sizing the dots by displacement reveal about the relationship of displacement with horsepower? What about with miles per gallon? decreased horsepower may be associated with increased miles per gallon.
Now, let us change the shape of points. The key is to use the pch argument, which stands for “point character”. If you look at the help documentation - ?par, then search for pch - you will see the various shapes base R has. The code below first shows you how to change the shape of each entry, and it then shows you how to create a variable enumerating the shape by some other variable.
Change the shape with the pch argument

Why are some dots circles but others triangles? the 1 and 2 in the pch line
Change the shape with the pch argument

This variable is convenient because it is already coded as a number
mtcars$am
[1] 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1
Change shape to be Mazda or not Mazda

Now, let us color the points. The approach is the same as we have seen - pass R a vector of colors and R will make the points those colors. Notice that I have double the size of each point with the cex argument; I do that simply to make the chart more legible.
Change the color with the col argument

What do you notice about the relationship between horsepower, miles per gallon, and the weight of a car?
Plot quarter mile second time against miles per gallon. Change the size based on the car’s weight.

Plot quarter mile second time against miles per gallon. Change the shape based on whether car has an automatic transmission.

Plot quarter mile second time against miles per gallon. Change the color based on whether the car has more than 4 cylinders.

Make one plot that combines the three plots above. That is, change the size, shape, and color of each point based on the car’s weight, transmission, and number of cylinders, respectively.

Modiying the size, shape, and color of nodes is identical. First, let us explore the karate club dataset.

LS0tCnRpdGxlOiBNaWR0ZXJtIFByZXAKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKCgoKCgoKCgojIyMjIyBCQVNJQ1MgCgoKVHlwZSAncSgpJyB0byBxdWl0IFIuCgpBc2tpbmcgZm9yIGhlbHA6CmBgYHtyfQojIFdoZW4geW91IGtub3cgdGhlIGZ1bmN0aW9uIG5hbWUsIHVzZSBvbmUgcXVlc3Rpb24gbWFyay4KP3RhaWwKCiMgV2hlbiB5b3Ugc29ydCBvZiBrbm93LCB1c2UgdHdvIHF1ZXN0aW9uIG1hcmtzLgo/P2F2ZXJhZ2UKPz90YWlsCmBgYAoKSW5zdGFsbCBpZ3JhcGgsIGhhdmVuLCBhbmQgdGlkeXZlcnNlOgpgYGB7cn0KaW5zdGFsbC5wYWNrYWdlcygndGlkeXZlcnNlJykKCmluc3RhbGwucGFja2FnZXMoJ2lncmFwaCcpCgppbnN0YWxsLnBhY2thZ2VzKCJoYXZlbiIpCmBgYAoKU2V0IHNlZWQ6CmBgYHtyfQpzZXQuc2VlZCgwOTAzMjAxOSkKYGBgCgpMb2FkIGlncmFwaCAsIGhhdmVuLCBhbmQgdGlkeXZlcnNlIE9SIGF0dGFjaCBkYXRhIGFscmVhZHkgbG9hZGVkIGluIFI6CmBgYHtyfQpsaWJyYXJ5KGlncmFwaCkKCmxpYnJhcnkodGlkeXZlcnNlKQoKbGlicmFyeShoYXZlbikKCmxpYnJhcnkocmVhZHhsKSAKCmF0dGFjaChtdGNhcnMpCmBgYAoKUmVhZCBpbiBkYXRhIGZyb20gYSBkZXNrdG9wOgpgYGB7cn0KZGF0YTIgPC0gcmVhZC5kZWxpbSgnfi9Eb2N1bWVudHMvVUNMQS9EYXRhL1BSSU9fVXJiYW5Tb2NpYWxEaXNvcmRlci9ldmVudHMuY3N2Jywgc2VwPScsJykKCmRhdGEgPC0gcmVhZC5jc3YoJ34vRG9jdW1lbnRzL1VDTEEvRGF0YS9QUklPX1VyYmFuU29jaWFsRGlzb3JkZXIvZXZlbnRzLmNzdicpCmBgYAoKUmVhZCBpbiBkYXRhIGZyb20gYSB3ZWJzaXRlOgpgYGB7cn0KZGF0X2NzdiA8LSByZWFkLmNzdigiaHR0cHM6Ly9zdGF0cy5pZHJlLnVjbGEuZWR1L3N0YXQvZGF0YS9oc2JkZW1vLmNzdiIpCgpkYXRfdGFiIDwtIHJlYWQuZGVsaW0oImh0dHBzOi8vc3RhdHMuaWRyZS51Y2xhLmVkdS9zdGF0L2RhdGEvaHNiMi50eHQiLCBzZXA9Ilx0IikKCiMgWW91IGNhbiBhbHNvIHJlYWQgcHJvcHJpZXRhcnkgZGF0YSBmb3JtYXRzIChgLnhsc2AsIGAuZHRhYCwgYW5kIHNvIG9uKSB1c2luZyB2YXJpb3VzIFIgcGFja2FnZXMuICBUaGUgbW9zdCBwb3dlcmZ1bCBpcyBgaGF2ZW5gLiAKCiMgU1BTUwpkYXRfc3BzcyA8LSByZWFkX3Nwc3MoImh0dHBzOi8vc3RhdHMuaWRyZS51Y2xhLmVkdS9zdGF0L2RhdGEvaHNiMi5zYXYiKQoKIyBTdGF0YQpkYXRfZHRhIDwtIHJlYWRfc3RhdGEoImh0dHBzOi8vc3RhdHMuaWRyZS51Y2xhLmVkdS9zdGF0L2RhdGEvaHNiZGVtby5kdGEiKQoKIyBUaGlzIHN0ZXAgb25seSBuZWVkZWQgdG8gcmVhZCBleGNlbCBmaWxlcyBmcm9tIHRoZSBpbnRlcm5ldDoKZG93bmxvYWQuZmlsZSgiaHR0cHM6Ly9zdGF0cy5pZHJlLnVjbGEuZWR1L3N0YXQvZGF0YS9oc2IyLnhscyIsICJ+L0Rvd25sb2Fkcy9teWZpbGUueGxzIiwgbW9kZT0id2IiKQoKZGF0X3hscyA8LSByZWFkX2V4Y2VsKCJ+L0Rvd25sb2Fkcy9teWZpbGUueGxzIikKYGBgCgpVc2UgYHJlYWRfZ3JhcGhgIHRvIGxvYWQgbmV0d29yayBkYXRhLiBDcmVhdGUgYSBuZXR3b3JrIGZyb20gYW4gZWRnZWxpc3QuIExvYWQgZGF0YSBhdCBodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vWmFjaGFyeVNUL0RhdGEvbWFzdGVyL2RvbHBoaW5zLiBPcGVuIHRoYXQgbGluayBmaXJzdCBpbiB5b3VyIHdlYiBicm93c2VyIHNvIHlvdSBrbm93IHdoYXQgdGhlIGRhdGEgbG9vayBsaWtlLiBUaGUgZGF0YSBhcmUgdW5kaXJlY3RlZCAodHdvIG9wdGlvbnMpOgpgYGB7cn0KZGF0YXBzMiA8LSByZWFkX2dyYXBoKCdodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vWmFjaGFyeVNUL0RhdGEvbWFzdGVyL2RvbHBoaW5zJywgZGlyZWN0ZWQ9RkFMU0UsIGZvcm1hdCA9IGMoImVkZ2VsaXN0IikpCgpkYXRhIDwtIHJlYWQudGFibGUoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9aYWNoYXJ5U1QvRGF0YS9tYXN0ZXIvZG9scGhpbnMiLApoZWFkZXIgPSBGQUxTRSkKZGF0YSA8LSBncmFwaF9mcm9tX2VkZ2VsaXN0KGFzLm1hdHJpeChkYXRhKSwgZGlyZWN0ZWQgPSBGQUxTRSkKYGBgCgpHZXQgdGhlIGFkamFjZW5jeSBtYXRyaXggZnJvbSB0aGUgZ3JhcGggYWJvdmUuIFRlbGwgdGhlIGZ1bmN0aW9uIG5vdCB0byByZXR1cm4gYSBzcGFyc2UgbWF0cml4LiAKYGBge3J9CmFtcHMyIDwtIGFzX2FkamFjZW5jeV9tYXRyaXgoZGF0YXBzMiwgc3BhcnNlID0gRkFMU0UpCmBgYAoKTG9hZCB0aGUgZG9scGhpbiBkYXRhIGFnYWluLCB0aGlzIHRpbWUgdGVsbGluZyBSIHRoZSBuZXR3b3JrIGlzIGRpcmVjdGVkLgpgYGB7cn0KZGF0YXBzMmQgPC0gcmVhZF9ncmFwaCgiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL1phY2hhcnlTVC9EYXRhL21hc3Rlci9kb2xwaGlucyIsIGRpcmVjdGVkID0gVFJVRSkgCmBgYAoKTG9hZCB0aGUgU0NBRCBkYXRhIGZyb20gbXkgR2l0aHViIERhdGEgcmVwb3NpdG9yeS4gVGhlIGxpbmsgaXMgaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL1phY2hhcnlTVC9EYXRhL21hc3Rlci9zY2FkX2xhdGluYW1lIHJpY2EuCmBgYHtyfQpTQ0FEZGF0YSA8LSByZWFkLmNzdigiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL1phY2hhcnlTVC9EYXRhL21hc3Rlci9zY2FkX2xhdGluYW1lcmljYSIpCmBgYAoKCgoKCgoKCiAgCgoKCiMjIyMjIElOU1BFQ1RJTkcgQSBORVRXT1JLIChlZGdlcywgbm9kZXMsIGNvbXBvbmVudHMsIHNpemUsIGRlZ3JlZSkKCgpIb3cgbWFueSBub2RlcyBkb2VzIHRoZSBuZXR3b3JrIGhhdmUgKHR3byBvcHRpb25zKT8KYGBge3J9CnZjb3VudChkYXRhcHMyKQpsZW5ndGgoVihkYXRhcHMyKSkKYGBgCgpIb3cgbWFueSBub2RlcyBkb2VzIHRoZSBuZXR3b3JrIGhhdmUgKHR3byBvcHRpb25zKSB1c2luZyBhbiBhZGphY2VuY3kgbWF0cml4PwpgYGB7cn0KbnJvdyhhbXBzMikKbmNvbChhbXBzMikKYGBgCgpIb3cgbWFueSBlZGdlcyBkb2VzIHRoZSBuZXR3b3JrIGhhdmUgKHRocmVlIG9wdGlvbnMpPwpgYGB7cn0KZWNvdW50KGRhdGFwczIpCnN1bShyb3dTdW1zKGFtcHMyKSkvMiAKc3VtKGNvbFN1bXMoYW1wczIpKS8yCmBgYAoKRG9lcyB0aGUgbmV0d29yayBoYXZlIGFueSBjb21wb25lbnRzPwpgYGB7cn0KY29tcG9uZW50cyhkYXRhcHMyKQpjb3VudF9jb21wb25lbnRzKGRhdGFwczIpCmBgYAoKU2F2ZSB0aGUgcmVzdWx0cyBmcm9tIGFib3ZlIGFzIGEgbmV3IG9iamVjdC4gQ2FsbCB0aGUgZW50cnkgb2YgdGhhdCBvYmplY3QgdGhhdCB0ZWxscyB5b3UgaGF2ZSBtYW55IGNvbXBvbmVudHMgdGhlcmUgYXJlLgpgYGB7cn0KYyA8LSBjb21wb25lbnRzKGRhdGFwczIpCmMkbm8KYGBgCgpXaGF0IGlzIHRoZSBzaXplIG9mIHRoZSBjb21wb25lbnQocyk/CmBgYHtyfQpjJGNzaXplCmBgYAoKV2hhdCBpcyB0aGUgZGVncmVlIG9mIGVhY2ggbm9kZT8gIFVzZSB0aGUgb2JqZWN0IGNyZWF0ZWQgd2hlbiB5b3UgcmVhZCBpbiB0aGUgZmlsZS4KYGBge3J9CmRlZ3JlZShkYXRhcHMyKQpgYGAKCldoYXQgaXMgdGhlIGRlZ3JlZSBvZiBlYWNoIG5vZGU/ICBVc2UgdGhlIGFkamFjZW5jeSBtYXRyaXg/CmBgYHtyfQpyb3dTdW1zKGFtcHMyKQpgYGAKCldoYXQgaXMgdGhlIGRlZ3JlZSBvZiB0aGUgbW9zdCBzb2NpYWwgZG9scGhpbj8KYGBge3J9Cm1heChkZWdyZWUoZGF0YXBzMikpCmBgYAoKV2hpY2ggZG9scGhpbiBpcyB0aGUgbW9zdCBzb2NpYWw/CmBgYHtyfQpWKGRhdGFwczIpW2RlZ3JlZShkYXRhcHMyKSA9PSBtYXgoZGVncmVlKGRhdGFwczIpKV0KYGBgCgpSZXBlYXQgdGhlIGxhc3QgdHdvIHF1ZXJpZXMgYWJvdmUsIGJ1dCBzYXZlIHRoZSByZXN1bHQgb2YgdGhlIG1vc3Qgc29jaWFsIGRvbHBoaW4gYXMgYW4gb2JqZWN0LgpgYGB7cn0Kc29jaWFsIDwtIG1heChkZWdyZWUoZGF0YXBzMikpIApWKGRhdGFwczIpW2RlZ3JlZShkYXRhcHMyKSA9PSBzb2NpYWxdCmBgYAoKTG9hZCBhbmQgaW5zcGVjdCB0aGUgS0FSQVRFIGRhdGEuIApgYGB7cn0KZCA8LSByZWFkLnRhYmxlKCdodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vWmFjaGFyeVNUL0RhdGEvbWFzdGVyL3phY2hhcnlfa2FyYXRlJywgaGVhZGVyPUZBTFNFKQpkaW0oZCkgIApoZWFkKGQpICAjIEZpcnN0IHNpeCByb3dzIGxvb2sgZmluZSwgdGhvdWdoIEkgZG8gbm90IGxpa2UgdGhlIGNvbHVtbiBuYW1lcy4KYGBgCgpNYWtlIGNvbHVtbiBuYW1lcyBtYXRjaCB0aGUgcm93IG51bWJlcnM6CmBgYHtyfQpuYW1lcyhkKSA8LSBhcy5jaGFyYWN0ZXIoMTpucm93KGQpKSAgCmhlYWQoZCkKIyBGb3IgdGhlIG51bWJlcnMgMSB0byBob3dldmVyIG1hbnkgcm93cyB0aGVyZSBhcmUsIG1ha2UgdGhhdCB0aGUgY29sdW1uIG5hbWUuICBNdXN0IGJlIGEgc3RyaW5nLgpgYGAKCk5vdywgbGV0IHVzIGNvdW50IGhvdyBtYW55IG5vZGVzIHRoZXJlIGFyZSwgdGhlIG51bWJlciBvZiBjb21wb25lbnRzLCBhbmQgdGhlIGRlZ3JlZSBvZiBlYWNoIG5vZGU6CmBgYHtyfQpsaWJyYXJ5KGlncmFwaCkgICMgVG8gbG9hZCBpZ3JhcGggZnVuY3Rpb25zCmcgPC0gZ3JhcGgoZCkgICMgRmFpbHMuICBSZXF1aXJlcyBlZGdlbGlzdC4KZyA8LSBncmFwaF9mcm9tX2FkamFjZW5jeV9tYXRyaXgoZCkgICMgRmFpbHMgYmVjYXVzZSBkIGlzIGEgZGF0YWZyYW1lLgpnIDwtIGdyYXBoX2Zyb21fYWRqYWNlbmN5X21hdHJpeChhcy5tYXRyaXgoZCksIG1vZGU9InVuZGlyZWN0ZWQiKSAgIyBXb3Jrcy4gIERvIG5vdCBmb3JnZXQgdG8gdGVsbCBpdCB0aGUga2luZCBvZiBuZXR3b3JrIHlvdSBoYXZlLgpgYGAKClRvIGp1c3QgZ2V0IHRoZSBjb3VudCBvZiBjb21wb25lbnRzOgpgYGB7cn0KY291bnRfY29tcG9uZW50cyhnKQpgYGAKClRoZSBtb3N0IGNvbm5lY3Rpb25zIGFuZCBpdHMgbm9kZSBvciBub2RlcyAodHdvIG9wdGlvbnMpOgpgYGB7cn0KbWF4KGRlZ3JlZShnKSkKVihnKVtkZWdyZWUoZykgPT0gbWF4KGRlZ3JlZShnKSldCgptYXhpbXVtIDwtIG1heChkZWdyZWUoZykpCm1heGltdW0KVihnKVtkZWdyZWUoZykgPT0gbWF4aW11bV0KYGBgCgpMb29wLCBjaGVjayB3b3JrLCBjb3JyZWN0OgpgYGB7cn0KZGVncmVlcyA8LSBOVUxMCmZvcihpIGluIDE6bmNvbChkKSl7CiAgZGVncmVlc1tpXSA8LSBzdW0oZFssaV0pCn0KCiMgVXNpbmcgdGhlIGFwcGx5IGZ1bmN0aW9uOiAgCiMgTUFSR0lOPTIgbWVhbnMgY29sdW1ucy4KYXBwbHkoZCwgTUFSR0lOPTIsIEZVTj1zdW0pICAjIFlvdSBoYXZlIHRvIGNhcGl0YWxpemUgdGhlIGFyZ3VtZW50IG5hbWVzLgpgYGAKCkZpbmQgdGhlIG5vZGVzIGluIHRoZSBrYXJhdGUgbmV0d29yayB0aGF0IGhhdmUgdGhlIG1pbmltdW0gZGVncmVlLgpgYGB7cn0KdGhlbWluIDwtIG1pbihkZWdyZWUoZykpCnRoZW1pbgpWKGcpW2RlZ3JlZShnKSA9PSB0aGVtaW5dCgpWKGcpW3doaWNoLm1pbihkZWdyZWUoZykpXQpgYGAKCgoKCgoKCgoKCgoKIyMjIyBSQU5ET00gTlVNQkVSIEdFTkVSQVRPUiAoaWdyYXBoLCBhZGphY2VuY3kgbWF0cml4KQoKCmBgYHtyfQpzZXQuc2VlZCgwMTA4MjAxNykKYGBgCgpBIGJpbm9taWFsIGRpc3RyaWJ1dGlvbiBpcyBvbmUgdGhhdCBwcm9kdWNlcyBhIHNlcmllcyBvZiBudW1iZXJzIGFjY29yZGluZyB0byBwYXJhbWV0ZXJzIHlvdSBwYXNzIGl0LldlIGNhbiBlYXNpbHkgbWFrZSBpdCBwcm9kdWNlcyAxcyBhbmQgMHMgYW5kIHRoZW4gcG9wdWxhdGUgYW4gYWRqYWNlbmN5IG1hdHJpeCB3aXRoIHRoZW0uIFRoZSBsYXN0IGFyZ3VtZW50IGNvbnRyb2xzIHRoZSByYXRpbyBvZiAxcyBhbmQgMHMuICBTbywgaGFsZiB0aGUgb3V0cHV0IHdpbGwgYmUgMSwgaGFsZiB3aWxsIGJlIDAsIG9uIGF2ZXJhZ2UuCmBgYHtyfQpyYmlub20oMSwxLC41KQpyYmlub20oMSwxLC41KQpyYmlub20oMSwxLC41KQpyYmlub20oMSwxLC41KQpyYmlub20oMSwxLC41KQpgYGAKCkxldCdzIHNwZWVkIHRoYXQgdXAuICBXaHkgZG9lcyB0aGUgYmVsb3cgbGluZSBwcm9kdWNlIG1vcmUgbnVtYmVycz8gMTAgcmVwbGFjZXMgMS4KYGBge3J9CnJiaW5vbSgxMCwxLC41KQpgYGAKCkxldCdzIHVuZGVyc3RhbmQgcmJpbm9tIGEgbGl0dGxlIG1vcmUuIFNlY29uZCBudW1iZXIgaXMgb3B0aW9ucy4gCmBgYHtyfQpyYmlub20oMTAsMTAsLjUpCnJiaW5vbSgxMCwzLC41KQpgYGAKCldlIGNhbiBub3cgbWFrZSBhIG1hdHJpeCBvZiBhcmJpdHJhcnkgc2l6ZSwgc28gbG9uZyBhcyByYmlub20oKSBjcmVhdGVzIGEgc3F1YXJlIGFtb3VudCBvZiBudW1iZXJzLgpgYGB7cn0KdGVtcCA8LSBtYXRyaXgocmJpbm9tKDgxLCAxLCAuNSksIG5yb3c9OSkKdGVtcApgYGAKCk1heWJlIHRoaXMgYXBwcm9hY2ggaXMgYSBsaXR0bGUgbW9yZSBpbnR1aXRpdmU6CmBgYHtyfQpob3dtYW55cm93cyA8LSAxNQp0ZW1wIDwtIG1hdHJpeChyYmlub20oaG93bWFueXJvd3NeMiwgMSwgLjUpLCBucm93PWhvd21hbnlyb3dzKQpkaWFnKHRlbXApIDwtIDAgICMgTWFrZSBzdXJlIHRoZXJlIGFyZSBubyBzZWxmLWxvb3BzLgp0ZW1wCmBgYAoKQ29udmVydCB0byBpZ3JhcGggb2JqZWN0LgpgYGB7cn0KZ190ZW1wIDwtIGdyYXBoX2Zyb21fYWRqYWNlbmN5X21hdHJpeCh0ZW1wLCBtb2RlPSJkaXJlY3RlZCIpICAKYGBgCgpOb3RlIHRoYXQgdGhpcyBhcHByb2FjaCByZXF1aXJlcyB1c2luZyBhIGRpcmVjdGVkIG5ldHdvcmsuCmBgYHtyfQpjb2xTdW1zKHRlbXApICsgcm93U3Vtcyh0ZW1wKQpkZWdyZWUoZ190ZW1wKQooY29sU3Vtcyh0ZW1wKSArIHJvd1N1bXModGVtcCkpID09IGRlZ3JlZShnX3RlbXApCmBgYAoKWW91IGNhbiBhbHNvIG1ha2UgYW4gdW5kaXJlY3RlZCBncmFwaCBmcm9tIHRoZSBhZGphY2VuY3kgbWF0cml4LiBpZ3JhcGggd2lsbCBoYW5kbGUgdGhlIGNvbnN0cnVjdGlvbiBvZiBlZGdlcyBieSBhc3N1bWluZyBhbnkgZWRnZSBpcyBzeW1tZXRyaWMuCmBgYHtyfQpnX3RlbXAyIDwtIGdyYXBoX2Zyb21fYWRqYWNlbmN5X21hdHJpeCh0ZW1wLCBtb2RlPSJ1bmRpcmVjdGVkIikgIAoKY29sU3Vtcyh0ZW1wKSArIHJvd1N1bXModGVtcCkgLSBjb2xTdW1zKHRlbXAqdCh0ZW1wKSkgICMgVGhlIGxhc3QgcGFydCBnaXZlcyB5b3UgdGhlIG51bWJlciBvZiBiaWRpcmVjdGlvbmFsIGNvbm5lY3Rpb25zLgpkZWdyZWUoZ190ZW1wMikgIyBHaXZlcyB0aGUgc2FtZSBhcyB0aGUgYWJvdmUgZm9yIGdyYXBoCmBgYAoKQnV0IGNhbGN1bGF0aW9uIG9mIG90aGVyIHN0YXRpc3RpY3Mgd2lsbCBiZSB0cmlja3kuICAqKkl0IGlzIGJldHRlciB0byBqdXN0IG1ha2UgdGhlIG1hdHJpeCBzeW1tZXRyaWMgcmlnaHQgYXdheSoqLCB3aGljaCByZXF1aXJlcyBzb21lIG1hc3NhZ2luZy4gRm9yIHRoZSBib3R0b20gbGVmdCBoYWxmIG9mIHRoZSBtYXRyaXgsIG1ha2UgaXQgdGhlIHNhbWUgYXMgdGhlIHRvcCByaWdodC4KYGBge3J9CnRlbXAyIDwtIHRlbXAKdGVtcDJbbG93ZXIudHJpKHRlbXAyKV0gPC0gdCh0ZW1wMilbbG93ZXIudHJpKHRlbXAyKV0KdGVtcDIKYGBgCgoKCgoKCgoKCgoKCgoKIyMjIyBBREpBQ0VOQ1kgTUFUUklYIEVYQU1QTEUKCgpDcmVhdGUgYW4gYWRqYWNlbmN5IG1hdHJpeCB0aGF0IGhhcyAyNSByb3dzIGFuZCBjb2x1bW5zLCB3aGVyZSBlYWNoIGNlbGwgaGFzIGEgLjggcHJvYmFiaWxpdHkgb2YgY29udGFpbmluZyBhIDEuICBTZXQgdGhlIGRpYWdvbmFsIHRvIHplcm8uCmBgYHtyfQpwcm9iYWJpbGl0eSA8LSAuOAp0aGlzbnVtYmVyIDwtIDI1CnRoaXNtYXRyaXggPC0gbWF0cml4KHJiaW5vbSh0aGlzbnVtYmVyXjIsIDEsIHByb2JhYmlsaXR5KSwgbnJvdz10aGlzbnVtYmVyKQpkaWFnKHRoaXNtYXRyaXgpIDwtIDAKdGhpc21hdHJpeApgYGAKCkNvbnZlcnQgaXQgdG8gYW4gdW5kaXJlY3RlZCBuZXR3b3JrLgpgYGB7cn0KdGhpc21hdHJpeFtsb3dlci50cmkodGhpc21hdHJpeCldIDwtIHQodGhpc21hdHJpeClbbG93ZXIudHJpKHRoaXNtYXRyaXgpXQp0aGlzbWF0cml4CmBgYAoKQ29udmVydCB0aGUgbWF0cml4IHRvIGFuIGlncmFwaCBncmFwaCBvYmplY3QuCmBgYHtyfQppZzIgPC0gZ3JhcGhfZnJvbV9hZGphY2VuY3lfbWF0cml4KHRoaXNtYXRyaXgsIG1vZGU9J3VuZGlyZWN0ZWQnKQpgYGAKCldoYXQgaXMgdGhlIGF2ZXJhZ2UgZGVncmVlIG9mIHRoZSBuZXR3b3JrPwpgYGB7cn0KbWVhbihkZWdyZWUoaWcyKSkKc3VtbWFyeShkZWdyZWUoaWcyKSkKc3VtbWFyeShkZWdyZWUoaWcyKSlbNF0KYGBgCgpXaGF0IGlzIHRoZSBkZW5zaXR5IG9mIHRoZSBuZXR3b3JrPwpgYGB7cn0KZGVuc2l0eShpZzIpICMgZmFpbHMKZ3JhcGguZGVuc2l0eShpZzIpICAjIHdvcmtzCmVkZ2VfZGVuc2l0eShpZzIpICAjIHNhbWUKYGBgCgpXaGF0IGlzIHRoZSBnbG9iYWwgdHJhbnNpdGl2aXR5IG9mIHRoZSBuZXR3b3JrPwpgYGB7cn0KdHJhbnNpdGl2aXR5KGlnMiwgdHlwZT0nZ2xvYmFsdW5kaXJlY3RlZCcpCmBgYAoKVXNlIGFuIGFkamFjZW5jeSBtYXRyaXggdG8gY3JlYXRlIGEgZmFrZSBuZXR3b3JrIHRoYXQgaGFzIDMwIGluZGl2aWR1YWxzLiAKYGBge3J9CnBlb3BsZSA8LSAzMApuZXdtYXRyaXggPC0gbWF0cml4KHJiaW5vbShwZW9wbGVeMiwgMSwgLjUpLCBucm93PXBlb3BsZSkKbmV3bWF0cml4CmBgYAoKQ2FsY3VsYXRlIHRoZSBkZWdyZWUgb2YgZWFjaCBub2RlIHVzaW5nIHRoZSBhZGphY2VuY3kgbWF0cml4OgpgYGB7cn0KZGVncmVlKG5ld21hdHJpeCkgICMgZmFpbHMgc2luY2Ugbm90IGdyYXBoIG9iamVjdApgYGAKCkRlZ3JlZSBmb3IgZGlyZWN0ZWQgYWRqYWNlbmN5IG1hdHJpeDoKYGBge3J9CmNvbFN1bXMobmV3bWF0cml4KSArIHJvd1N1bXMobmV3bWF0cml4KQpjb2xTdW1zKG5ld21hdHJpeCkgKyByb3dTdW1zKG5ld21hdHJpeCkgLSAyKmRpYWcobmV3bWF0cml4KSAjIE5vIHNlbGYgbG9vcHMKYGBgCgpEZWdyZWUgZm9yIHVuZGlyZWN0ZWQKYGBge3J9CmNvbFN1bXMobmV3bWF0cml4KSArIHJvd1N1bXMobmV3bWF0cml4KSAtIGRpYWcobmV3bWF0cml4KSAjIE5vIHNlbGYgbG9vcHMKYGBgCgpDb252ZXJ0IHRoZSBhZGphY2VuY3kgbWF0cml4IHRvIGFuIGFzeW1tZXRyaWMgZ3JhcGggb2JqZWN0LiAgVXNlIGlncmFwaCB0byBjYWxjdWxhdGUgdGhlIGRlZ3JlZSBvZiBlYWNoIG5vZGUuCmBgYHtyfQpnMyA8LSBncmFwaF9mcm9tX2FkamFjZW5jeV9tYXRyaXgobmV3bWF0cml4LCBtb2RlPSdkaXJlY3RlZCcpCmRlZ3JlZShnMykKYGBgCgoKCgoKCgoKCgoKCgoKIyMjIyMgREVOU0lUWQoKCldoYXQgaXMgdGhlIGRlbnNpdHkgb2YgdGhlIGRvbHBoaW4gbmV0d29yayAodHdvIG9wdGlvbnMpPwpgYGB7cn0KZ3JhcGguZGVuc2l0eShkYXRhcHMyKQplY291bnQoZGF0YXBzMikvKCh2Y291bnQoZGF0YXBzMikgKiAodmNvdW50KGRhdGFwczIpIC0gMSkpLzIpCmBgYAoKV2hhdCBpcyB0aGUgZGVuc2l0eSBvZiB0aGUgZGlyZWN0ZWQgZG9scGhpbiBkYXRhPwpgYGB7cn0KZ3JhcGguZGVuc2l0eShkYXRhcHMyZCkKYGBgCgpXaHkgaXMgdGhlIGRlbnNpdHkgdGhpcyB2YWx1ZSBub3c/ICBIb3cgZG9lcyBpdCBjb21wYXJlIHRvIHdoYXQgeW91IGZvdW5kIGluIFF1ZXN0aW9uIDE/CmBgYHtyfQojVGhlIGRlbnNpdHkgb2YgYSBkaXJlY3RlZCBuZXR3b3JrIGlzIGhhbGYgdGhhdCBvZiBhbiB1bmRpcmVjdGVkIG9uZSBiZWNhdXNlIHRoZXJlIGFyZSB0d2ljZSBhcyBtYW55IHBvc3NpYmxlIGVkZ2VzLiBJbiB0aGUgZGlyZWN0ZWQgbmV0d29yayB0aGUgZGVuc2l0eSBpcyAwLjA0MDcwNjYxLCB3aGljaCBpcyBsb3dlciB0aGFuIHRoZSBkZW5zaXR5IGluIHRoZSB1bmRpcmVjdGVkIG5ldHdvcmsgKDAuMDgxNDEzMjEpLiBUaGUgZGlyZWN0ZWQgbmV0d29yayBkZW5zaXR5IGlzIGxvd2VyLCBiZWNhdXNlIHdoZW4gd2Ugd2VudCBmcm9tIGFuIHVuZGlyZWN0ZWQgdG8gYSBkaXJlY3RlZCBuZXR3b3JrLCB3ZSBhcmUgYWRkaW5nIGVkZ2VzIGV2ZW4gdGhvdWdoIHdlIGRpZCBub3QgYWRkIG5vZGVzLgpgYGAKCkthcmF0ZSBjbHViIGRlbnNpdHksIGF1dG9tYXRpY2FsbHkgYW5kIG1hbnVhbGx5OgpgYGB7cn0KZ3JhcGguZGVuc2l0eShnKQoKZWNvdW50KGcpLygodmNvdW50KGcpKih2Y291bnQoZyktMSkpLzIpCmBgYAoKTGV0J3MgbWFrZSB0aGlzIGNsZWFyaWVyIHRvIHVuZGVyc3RhbmQgd2hhdCdzIGhhcHBlbmluZzoKYGBge3J9CnRvdGFsZWRnZXMgPC0gZWNvdW50KGcpCnBvc3NpYmxlZWRnZXMgPC0gKHZjb3VudChnKSoodmNvdW50KGcpLTEpKS8yCmVjb3VudChnKS9wb3NzaWJsZWVkZ2VzCgp0b3RhbGVkZ2VzL3Bvc3NpYmxlZWRnZXMKYGBgCgpTYW1lLCBjb3VudGluZyBkaXJlY3RseSBmcm9tIHRoZSBhZGphY2VuY3kgbWF0cml4OgpgYGB7cn0Kc3VtKGNvbFN1bXMoZCkpLyhucm93KGQpKm5jb2woZCkpCgplZGdlcyA8LSBzdW0oY29sU3VtcyhkKSkgICMgbm8gLWRpYWcoZCkgYmVjYXVzZSB0aGUgZGlhZ25vYWwgaXMgYWxyZWFkeSAwCnBvc3NpYmxlZWRnZXMyIDwtIG5yb3coZCkqbmNvbChkKSAKZWRnZXMvcG9zc2libGVlZGdlczIKYGBgCgpPdXIgZGlyZWN0ZWQgZ3JhcGg6CmBgYHtyfQpncmFwaC5kZW5zaXR5KGdfdGVtcCkKCmVkZ2VzIDwtIHN1bSh0ZW1wKQpwb3NzaWJsZWVkZ2VzIDwtIG5yb3codGVtcCkqbmNvbCh0ZW1wKS1ucm93KHRlbXApCmVkZ2VzL3Bvc3NpYmxlZWRnZXMgIApgYGAKCk91ciB1bmRpcmVjdGVkIGdyYXBoOgpgYGB7cn0KIyMgTmVlZCBhIG5ldyBncmFwaCBiZWNhdXNlIHVwZGF0ZWQgdGVtcDIgYWJvdmUgdG8gYmUgdW5kaXJlY3RlZApnX3RlbXAyYiA8LSBncmFwaF9mcm9tX2FkamFjZW5jeV9tYXRyaXgodGVtcDIsIG1vZGU9J3VuZGlyZWN0ZWQnKQoKZ3JhcGguZGVuc2l0eShnX3RlbXAyYikKCmVkZ2VzIDwtIHN1bSh0ZW1wMikvMgpwb3NzaWJsZWVkZ2VzIDwtIChucm93KHRlbXAyKSpucm93KHRlbXAyKS1ucm93KHRlbXAyKSkvMgplZGdlcy9wb3NzaWJsZWVkZ2VzCmBgYAoKRG8geW91IG5vdGljZSBhbnl0aGluZyBhYm91dCB0aGUgZGVuc2l0eSBvZiB0aGUgZGlyZWN0ZWQgZ3JhcGg/IEl0IGlzIGxvd2VyLiAqKldoeSBpcyB0aGUgZGVuc2l0eSBvZiB0aGUgdW5kaXJlY3RlZCBncmFwaCBoaWdoZXIgdGhhbiB0aGF0IG9mIHRoZSBkaXJlY3RlZCBvbmUgZXZlbiB0aG91Z2ggdGhleSB1c2UgdGhlIHNhbWUgZGF0YT8qKiBCZWNhdXNlIHdoZW4gd2Ugd2VudCBmcm9tIHVuZGlyZWN0ZWQgdG8gZGlyZWN0ZWQgYWRqYWNlbmN5IG1hdHJpY2VzLCB3ZSBhZGRlZCBhIDEgdG8gdGhlIGJvdHRvbSBsZWZ0IG9yIHRvcCByaWdodCB0cmlhbmdsZSBpZiBpdCBkaWQgbm90IGV4aXN0IGJlZm9yZS4gIFNvLCB3ZSBhcmUgYWRkaW5nIGVkZ2VzIGV2ZW4gdGhvdWdoIHdlIGFyZSBub3QgYWRkaW5nIG5vZGVzLgoKR2VuZXJhdGUgYSAxMCB4IDEwIG1hdHJpeC4KYGBge3J9Cm51bWJlciA8LSAxMAp0aGlzbWF0cml4IDwtIG1hdHJpeChyYmlub20obnVtYmVyXjIsIDEsIC41KSwgbnJvdz1udW1iZXIpCmBgYAoKQ2FsY3VsYXRlIGl0cyBkaXJlY3RlZCBkZW5zaXR5LgpgYGB7cn0KdG1fZCA8LSBncmFwaF9mcm9tX2FkamFjZW5jeV9tYXRyaXgodGhpc21hdHJpeCwgbW9kZT0nZGlyZWN0ZWQnKQpncmFwaC5kZW5zaXR5KHRtX2QpCgplZGdlcyA8LSBzdW0odGhpc21hdHJpeCkKcG9zc2libGVlZGdlcyA8LSBucm93KHRoaXNtYXRyaXgpKm5jb2wodGhpc21hdHJpeCktbnJvdyh0aGlzbWF0cml4KQplZGdlcy9wb3NzaWJsZWVkZ2VzIApgYGAKCkNhbGN1bGF0ZSBpdHMgdW5kaXJlY3RlZCBkZW5zaXR5LiAgUmVtZW1iZXIsIHRoZSBjYWxjdWxhdGlvbiBpcyB0aGUgc2FtZSBvbmNlIHlvdSBkZWZpbmUgdGhlIGVkZ2VzIGNvcnJlY3RseS4gRmlyc3QsIG1ha2Ugc3ltbWV0cmljIGJlZm9yZSBwYXNzaW5nIHRvIGlncmFwaCBhbmQgcmVtb3ZlIHNlbGYgbG9vcHMuCmBgYHtyfQp0aGlzbWF0cml4MiA8LSB0aGlzbWF0cml4CnRoaXNtYXRyaXgyW2xvd2VyLnRyaSh0aGlzbWF0cml4MildIDwtIHQodGhpc21hdHJpeDIpW2xvd2VyLnRyaSh0aGlzbWF0cml4MildICAKZGlhZyh0aGlzbWF0cml4MikgPC0gMAogIAp0bV91IDwtIGdyYXBoX2Zyb21fYWRqYWNlbmN5X21hdHJpeCh0aGlzbWF0cml4MiwgbW9kZT0ndW5kaXJlY3RlZCcpCmdyYXBoLmRlbnNpdHkodG1fdSwgbG9vcHM9RkFMU0UpCgplZGdlcyA8LSBzdW0odGhpc21hdHJpeDIpLzIKcG9zc2libGVlZGdlcyA8LSAobnJvdyh0aGlzbWF0cml4MikqbnJvdyh0aGlzbWF0cml4MiktbnJvdyh0aGlzbWF0cml4MikpLzIKZWRnZXMvcG9zc2libGVlZGdlcwpgYGAKCgoKCgoKCgoKCgoKCgojIyMjIENMVVNURVJJTkcKCgpXaGF0IGlzIHRoZSBnbG9iYWwgY2x1c3RlcmluZyBvZiB0aGUgdW5kaXJlY3RlZCBkb2xwaGluIGRhdGEgKHR3byBvcHRpb25zKT8KYGBge3J9CnRyYW5zaXRpdml0eShkYXRhcHMyLCB0eXBlPSJnbG9iYWx1bmRpcmVjdGVkIikKdHJhbnNpdGl2aXR5KGRhdGFwczIsIHR5cGUgPSAiZ2xvYmFsIikKYGBgCgpXaGF0IGlzIHRoZSBub2RlIHdpdGggdGhlIGhpZ2hlc3QgbG9jYWwgY2x1c3RlcmluZyB2YWx1ZSAodHdvIG9wdGlvbnMpPwpgYGB7cn0KVCA8LSB0cmFuc2l0aXZpdHkoZGF0YXBzMiwgdHlwZT0nbG9jYWwnKQpUMSA8LSByZXBsYWNlKFQsIGlzLm5hKFQpLCBGQUxTRSkKVihkYXRhcHMyKVtUMSA9PSBtYXgoVDEpXQoKCmNsdXN0ZXJpbmcgPC0gdHJhbnNpdGl2aXR5KGRhdGFwczIsIHR5cGUgPSAibG9jYWwiKSAKY2x1c3RlcmluZ1tpcy5uYShjbHVzdGVyaW5nKV0gPC0gMApkYXRhcHMyIDwtIHNldF92ZXJ0ZXhfYXR0cihkYXRhcHMyLCAiY2x1c3RlcmluZyIsIHZhbHVlID0gY2x1c3RlcmluZykgCmNsdXN0ZXJpbmdNYXggPC0gbWF4KGNsdXN0ZXJpbmcsIG5hLnJtID0gVFJVRSkKdG9rZWVwIDwtIFYoZGF0YXBzMikkY2x1c3RlcmluZyA9PSBjbHVzdGVyaW5nTWF4IAp0b2tlZXBbaXMubmEodG9rZWVwKV0gPC0gRkFMU0UgClYoZGF0YXBzMilbdG9rZWVwXQoKIyB+QmVsb3cgZmFpbHMgYmVjYXVzZSBvZiBOQSBpbiB0aGUgQm9vbGVhbiBzZXF1ZW5jZX4KVihkYXRhKVtWKGRhdGEpJGNsdXN0ZXJpbmcgPT0gY2x1c3RlcmluZ01heF0KYGBgCgpOb3RlIHRoYXQgb25lIGNhbiBzcGVjaWZpY3kgdW5kaXJlY3RlZCBidXQgaXQgZG9lcyBub3QgY2hhbmdlIHRoZSBjYWxjdWxhdGlvbjsgYGlncmFwaGAgZG9lcyBub3QgYXBwZWFyIHRvIGNhbGN1bGF0ZSBkaXJlY3RlZCBjbHVzdGVyaW5nLCBnbG9iYWxseSBvciBsb2NhbGx5OgpgYGB7cn0KdHJhbnNpdGl2aXR5KGcsIHR5cGU9Imdsb2JhbCIpCnRyYW5zaXRpdml0eShnLCB0eXBlPSJsb2NhbCIpCgp0cmFuc2l0aXZpdHkoZywgdHlwZT0iZ2xvYmFsdW5kaXJlY3RlZCIpCnRyYW5zaXRpdml0eShnLCB0eXBlPSJsb2NhbHVuZGlyZWN0ZWQiKQoKcGxvdChkZWdyZWUoZyksIHRyYW5zaXRpdml0eShnLCB0eXBlPSdsb2NhbCcpLCB4bGFiPSdEZWdyZWUgb2YgTm9kZScsIHlsYWI9J0xvY2FsIENsdXN0ZXJpbmcnKQoKdGhpcyA8LSB0cmFuc2l0aXZpdHkoZywgdHlwZT0nbG9jYWwnKQpwbG90KGRlZ3JlZShnKSwgdGhpcywgeGxhYj0nRGVncmVlIG9mIE5vZGUnLCB5bGFiPSdMb2NhbCBDbHVzdGVyaW5nJykKYGBgCgpDYWxjdWxhdGUgdGhlIGdsb2JhbCB0cmFuc2l0aXZpdHkgZm9yIG91ciBkaXJlY3RlZCBncmFwaC4KdHJhbnNpdGl2aXR5KHRtX2QsIHR5cGU9J2dsb2JhbCcpCgpDYWxjdWxhdGUgdGhlIGxvY2FsIHRyYW5zaXRpdml0eSBmb3Igb3VyIGRpcmVjdGVkIGdyYXBoLgp0cmFuc2l0aXZpdHkodG1fZCwgdHlwZT0nbG9jYWwnKQoKQ2FsY3VsYXRlIHRoZSBnbG9iYWwgdHJhbnNpdGl2aXR5IGZvciBvdXIgdW5kaXJlY3RlZCBncmFwaC4KdHJhbnNpdGl2aXR5KHRtX3UsIHR5cGU9J2dsb2JhbCcpCnRyYW5zaXRpdml0eSh0bV91LCB0eXBlPSdnbG9iYWx1bmRpcmVjdGVkJykKCkNhbGN1bGF0ZSB0aGUgbG9jYWwgdHJhbnNpdGl2aXR5IGZvciBvdXIgdW5kaXJlY3RlZCBncmFwaC4KdHJhbnNpdGl2aXR5KHRtX3UsIHR5cGU9J2xvY2FsJykKdHJhbnNpdGl2aXR5KHRtX3UsIHR5cGU9J2xvY2FsdW5kaXJlY3RlZCcpCgpGaW5kIHRoZSBub2RlIHdpdGggdGhlIGhpZ2hlc3QgY2x1c3RlcmluZyBjb2VmZmljaWVudCBmb3IgdGhlIGRpcmVjdGVkIG5ldHdvcmsuClYodG1fZClbdHJhbnNpdGl2aXR5KHRtX2QsIHR5cGU9J2xvY2FsJykgPT0gbWF4KHRyYW5zaXRpdml0eSh0bV9kLCB0eXBlPSdsb2NhbCcpKV0KCm10IDwtIG1heCh0cmFuc2l0aXZpdHkodG1fZCwgdHlwZT0nbG9jYWwnKSkKVih0bV9kKVt0cmFuc2l0aXZpdHkodG1fZCwgdHlwZT0nbG9jYWwnKSA9PSBtdF0KCkZpbmQgdGhlIG5vZGUgd2l0aCB0aGUgbG93ZXN0IGNsdXN0ZXJpbmcgY29lZmZpY2llbnQgdW5kaXJlY3RlZCBuZXR3b3JrLgpWKHRtX3UpW3RyYW5zaXRpdml0eSh0bV91LCB0eXBlPSdsb2NhbCcpID09IG1pbih0cmFuc2l0aXZpdHkodG1fdSwgdHlwZT0nbG9jYWwnKSldCgptaW50IDwtIG1pbih0cmFuc2l0aXZpdHkodG1fdSwgdHlwZT0nbG9jYWwnKSkKVih0bV91KVt0cmFuc2l0aXZpdHkodG1fdSwgdHlwZT0nbG9jYWwnKSA9PSBtaW50XQoKUGxvdCB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gZGVncmVlIGFuZCBjbHVzdGVyaW5nIGZvciB0aGUgMTB4MTAgdW5kaXJlY3RlZCBuZXR3b3JrLgpwbG90KGRlZ3JlZSh0bV91KSwgdHJhbnNpdGl2aXR5KHRtX3UsIHR5cGU9J2xvY2FsJyksIHhsYWI9J05vZGUgRGVncmVlJywgeWxhYj0nTG9jYWwgQ2x1c3RlcmluZycsIHBjaD0yMCkKCgoKCgoKCgoKCgoKCgoKIyMjIyBSQU5ET00gTkVUV09SSwoKCkdlbmVyYXRlIGEgcmFuZG9tIG5ldHdvcmsgY29udGFpbmluZyAyMDAgbm9kZXMgd2l0aCBhIHByb2JhYmlsaXR5IG9mIC4yIHRoYXQgYW55IHR3byBub2RlcyBhcmUgY29ubmVjdGVkLiAgVXNlIGBpZ3JhcGhgIHRvIGNvbnZlcnQgaXQgdG8gYW4gdW5kaXJlY3RlZCBtYXRyaXguIE1ha2UgYSBoaXN0b2dyYW0gb2YgdGhlIGRlZ3JlZSBkaXN0cmlidXRpb24sIGxhYmVsIHRoZSBheGVzLCBnaXZlIGl0IGEgdGl0bGUsIGFuZCBzYXZlIGl0IHRvIGZpbGUgKHR3byBvcHRpb25zKS4KYGBge3J9Cm5vZGVzIDwtIDIwMApyYW5kbmV0IDwtIG1hdHJpeChyYmlub20obm9kZXNeMiwgMSwgLjIpLCBucm93PW5vZGVzKQpyYW5kbmV0W2xvd2VyLnRyaShyYW5kbmV0KV0gPC0gdChyYW5kbmV0KVtsb3dlci50cmkocmFuZG5ldCldCgpyYW5kbmV0X3UgPC0gZ3JhcGhfZnJvbV9hZGphY2VuY3lfbWF0cml4KHJhbmRuZXQsIG1vZGU9J3VwcGVyJykgCgoKbm9kZXMgPC0gMjAwCnByb2IgPC0gMC4yCnRoZW5ldHdvcmsgPC0gbWF0cml4KHJiaW5vbShub2Rlc14yLCAxLCBwID0gcHJvYiksIG5yb3cgPSBub2RlcykKZGlhZyh0aGVuZXR3b3JrKSA8LSAwCgp0aGVuZXR3b3JrIDwtIGdyYXBoX2Zyb21fYWRqYWNlbmN5X21hdHJpeCh0aGVuZXR3b3JrLCBtb2RlID0gInVwcGVyIikKCgpwZGYoJ34vRGVza3RvcC9VQ0xBL0NvdXJzZXMvNF9GYWxsIDIwMTkvUFAgMjkwL0Fzc2lnbm1lbnRzL2Fzc24zcGxvdDEucGRmJykKaGlzdChkZWdyZWUodGhlbmV0d29yayksIHhsYWIgPSAnRGVncmVlJywgeWxhYiA9ICdDb3VudCcsIGJyZWFrcyA9IDUwLCBtYWluID0gJ0Rpc3RyaWJ1dGlvbiBvZiBEZWdyZWUnKSAKZGV2Lm9mZigpCmBgYAoKUmVwZWF0IFByb2JsZW0gMSwgZXhjZXB0IHZhcnkgdGhlIHByb2JhYmlsaXR5IG9mIHRpZXMgZnJvbSAuMSB0byAxIGluIGluY3JlbWVudHMgb2YgLjEuICBTYXZlIGVhY2ggaGlzdG9ncmFtIGluIGEgZmlsZS4gIFdoYXQgZG8geW91IG5vdGljZSBhcyBwIGNoYW5nZXM/CmBgYHtyfQpub2RlcyA8LSAyMDAKcHJvYiA8LSBzZXEoLjEsMSxieT0uMSkKCmZvcihpIGluIDE6bGVuZ3RoKHByb2IpKXsKICB0aGVuZXR3b3JrIDwtIG1hdHJpeChyYmlub20obm9kZXNeMiwgMSwgcD1wcm9iW2ldKSwgbnJvdz1ub2RlcykKICBkaWFnKHRoZW5ldHdvcmspIDwtIDAKICB0aGVuZXR3b3JrIDwtIGdyYXBoX2Zyb21fYWRqYWNlbmN5X21hdHJpeCh0aGVuZXR3b3JrLCBtb2RlPSd1cHBlcicpCiAgCiAgcGRmKHBhc3RlMCgnfi9EZXNrdG9wL1VDTEEnLCBwcm9iW2ldLCAnLnBkZicpKQogIGhpc3QoZGVncmVlKHRoZW5ldHdvcmspLCB4bGFiPSdEZWdyZWUnLCB5bGFiPSdDb3VudCcsIG1haW49cGFzdGUwKCdEaXN0cmlidXRpb24gb2YgRGVncmVlLCBwPScsIHByb2JbaV0pLCBicmVha3M9NTApCiAgZGV2Lm9mZigpCn0KCmBgYAoKI01ha2luZyBTeW1tZXRyaWMgTmV0d29ya3MgRnJvbSBhbiBBZGphY2VuY3kgTWF0cml4CgpDb252ZXJ0IGFuIHVuYmFsYW5lZCBhZGphY2VuY3kgbWF0cml4IHRvIGFuIHVuZGlyZWN0ZWQgYWRqYWNlbmN5IG1hdHJpeC4gU3RhcnQgYnkgbWFraW5nIHRoZSBtYXRyaXg6CmBgYHtyfQpwcm9iYWJpbGl0eSA8LSAuMgp0aGlzbnVtYmVyIDwtIDEyCnRoaXNtYXRyaXggPC0gbWF0cml4KHJiaW5vbSh0aGlzbnVtYmVyXjIsIDEsIHByb2JhYmlsaXR5KSwgbnJvdz10aGlzbnVtYmVyKQpkaWFnKHRoaXNtYXRyaXgpIDwtIDAKYGBgCgpDb252ZXJ0IGl0IHRvIGFuIHVuZGlyZWN0ZWQgbmV0d29yay4KYGBge3J9CnQodGhpc21hdHJpeCkgCiMgdHJhbnNwb3NlcyB0aGlzIG1hdHJpeCwgaS5lLiBjZWxsMiwxIC0+IGNlbGwxLDI7IGNlbGwzLDEtPmNlbGwxLDMsIGFuZCBzbyBvbi4gIAoKIyBJIGRlY2lkZSB0byBtYWtlIHRoZSBsb3dlciB0cmlhbmdsZSBlcXVhbCB0aGUgdXBwZXIgdHJpYW5nbGUuICBTbyB0aGUgdHJhbnNwb3NlIGRvZXMgdGhhdDoKdGhpc21hdHJpeFtsb3dlci50cmkodGhpc21hdHJpeCldIDwtIHQodGhpc21hdHJpeClbbG93ZXIudHJpKHRoaXNtYXRyaXgpXQpgYGAKCgoKCgoKCgoKCgoKCgoKCiMjIyMgUkFORE9NIEdSQVBICgoKQnVpbGQgcmFuZG9tIGdyYXBocyBmcm9tIG1hdHJpY2VzLiBUaGVuLCB3ZSB1c2UgaWdyYXBoIHRvIGJ1aWxkIGEgcmFuZG9tIGdyYXBoLiAgSW4gYm90aCBjYXNlcywgd2Ugd2lsbCBsZWFybiBhYm91dCB0aGUgbmV0d29yayB2aWEgc29tZSBzdGF0aXN0aWNzLiAgQXQgdGhlIGVuZCBvZiB0aGlzIHNlY3Rpb24sIHdlIHdpbGwgbGVhcm4gaG93IHRvIGF1dG9tYXRpY2FsbHkgdmFyeSBwYXJhbWV0ZXJzIGFuZCB2aWV3IHRoZSBzdGF0aXN0aWNzIG9mIHRoZSByZXN1bHRpbmcgbmV0d29ya3MuIENyZWF0ZSB1c2luZyBtYXRyaXguCmBgYHtyfQpob3dtYW55cm93cyA8LSAxMDAKdGVtcCA8LSBtYXRyaXgocmJpbm9tKGhvd21hbnlyb3dzXjIsIDEsIC41KSwgbnJvdz1ob3dtYW55cm93cykKZGlhZyh0ZW1wKSA8LSAwICAjIE1ha2Ugc3VyZSB0aGVyZSBhcmUgbm8gc2VsZi1sb29wcy4KCiMgRG8gbm90IGZvcmdldCB0byBtYWtlIHN5bW1ldHJpYwp0ZW1wW2xvd2VyLnRyaSh0ZW1wKV0gPC0gdCh0ZW1wKVtsb3dlci50cmkodGVtcCldCgpidXM3MjAgPC0gZ3JhcGhfZnJvbV9hZGphY2VuY3lfbWF0cml4KHRlbXAsIG1vZGU9J3VuZGlyZWN0ZWQnKSAgIyBJIGhhdmUgY2hvc2VuIGEgd2VpcmQgb2JqZWN0IG5hbWUgdG8gZW1waGFzaXplIHRoYXQgdGhleSBhcmUgYXJiaXRyYXJ5LiAgTW9zdCBkb2N1bWVudGF0aW9uIGZvciBpZ3JhcGggY2FsbHMgZ3JhcGggb2JqZWN0cyBnLCBidXQgeW91IGRvIG5vdCBoYXZlIHRvLgoKYGBgCgpFeHBsb3JlIGRlZ3JlZToKYGBge3J9CmFkal9kZWdyZWVzIDwtIGNvbFN1bXModGVtcCkKYWRqX2RlZ3JlZXNbMToxMF0KZGVncmVlKGJ1czcyMClbMToxMF0KCnN1bW1hcnkoYWRqX2RlZ3JlZXMpCnN1bW1hcnkoZGVncmVlKGJ1czcyMCkpCgpgYGAKCkV4cGxvcmUgY2x1c3RlcmluZzoKYGBge3J9CnRyYW5zaXRpdml0eShidXM3MjAsIHR5cGU9Imdsb2JhbCIpCnRyYW5zaXRpdml0eShidXM3MjAsIHR5cGU9ImxvY2FsIilbMToxMF0KYGBgCgpFeHBsb3JlIGRlbnNpdHk6CmBgYHtyfQpncmFwaC5kZW5zaXR5KGJ1czcyMCkKYGBgCgoKTm93LCBsZXQgdXMgbGVhcm4gaG93IHRvIGhhdmUgYGlncmFwaGAgbWFrZSBhIHJhbmRvbSBncmFwaCBmb3IgdXMuICBJIHdpbGwgdGhlbiBzaG93IGhvdyB5b3UgY2FuIHZhcnkgdGhlIGRlbnNpdHkgb2YgdGhlIGdyYXBoIHVzaW5nIGEgbG9vcDsgeW91IGNvdWxkIGRvIHRoZSBzYW1lIGZvciBub2RlcywgYnV0IEkgbGVhdmUgdGhhdCBleGVyY2lzZSBmb3IgdGhlIHByb2JsZW0gc2V0LiAgSSB3aWxsIHRoZW4gc2hvdyBob3cgdG8gcHV0IHRoZSBvdXRwdXQgZnJvbSBlYWNoIHZhcmlhdGlvbiBpbnRvIGEgZGF0YWZyYW1lOyBvdGhlcndpc2UsIHlvdSBsb3NlIHRoZSByZXN1bHRzIGFzIGVhY2ggbmV3IGxvb3AgcnVucy4gQ3JlYXRlIHVzaW5nIGlncmFwaCBwYWNrYWdlLCBleHBsb3JlIGRlZ3JlZSwgY2x1c3RlcmluZywgZGVuc2l0eS4KYGBge3J9CmlidXM3MjAgPC0gZXJkb3MucmVueWkuZ2FtZShob3dtYW55cm93cyxwPS41KQoKc3VtbWFyeShkZWdyZWUoaWJ1czcyMCkpCnRyYW5zaXRpdml0eShpYnVzNzIwLCB0eXBlPSdnbG9iYWwnKQp0cmFuc2l0aXZpdHkoaWJ1czcyMCwgdHlwZT0nbG9jYWwnKVsxOjEwXQpncmFwaC5kZW5zaXR5KGlidXM3MjApCmBgYAoKCgoKCgoKCgoKCgoKCgoKIyMjIyBTTUFMTC1XT1JMRCBORVRXT1JLUwoKClJlY3JlYXRlIHRoZSBzbWFsbC13b3JsZCBjaGFydCBJIHNob3dlZCBpbiBjbGFzcywgdGhlIG9uZSB0aGF0IHNob3dzIGhvdyBhdmVyYWdlIHBhdGggbGVuZ3RoIGFuZCBjbHVzdGVyaW5nIGNoYW5nZSBhcyB0aGUgcHJvYmFiaWxpdHkgb2YgcmV3aXJpbmcgZWRnZXMgaW5jcmVhc2VzLiBNYWtlIHRoZSBuZXR3b3JrIGEgcmluZyB3aXRoIDEsMDAwIG5vZGVzIHdoZXJlIGVhY2ggbm9kZSBpcyBjb25uZWN0ZWQgdG8gdGVuIG5laWdoYm9ycy4gQXMgeW91IHdvcmsgb24gdGhpcyBwcm9ibGVtLCBrZWVwIGluIG1pbmQgc2l4IHRoaW5nczogCiAgICBhLiBZb3Ugd2lsbCBuZWVkIGEgYmFzZWxpbmUgbW9kZWwgYnkgd2hpY2ggdG8gbm9ybWFsaXplIChkaXZpZGUpIHRoZQogICAgdmFsdWVzIG9mIGVhY2ggc2ltdWxhdGlvbi4gIFRoYXQgaXMsIHlvdSB3aWxsIG5lZWQgYSBtb2RlbCB0aGF0IGRvZXMKICAgIG5vdCBjaGFuZ2UgZm9yIGVhY2ggaXRlcmF0aW9uIG9mIHRoZSBsb29wLgogICAgYi4gTWFrZSBzdXJlIHlvdSBoYXZlIHZlcnkgc21hbGwgdmFsdWVzIG9mIHAsIHNtYWxsZXIgdGhhbiB0aGUgY2xhc3MKICAgIGV4YW1wbGUuCiAgICBjLiBNYWtlIHN1cmUgdGhlIHgtYXhpcyBpcyB0aGUgbG9nYXJpdGhtIG9mIHAuCiAgICAgIDEuIElmIG9uZSBvZiB5b3VyIHZhbHVlcyBvZiBwIGlzIDAsIHlvdSBzaG91bGQgYWRkIGEgc21hbGwgYW1vdW50LAogICAgICBzdWNoIGFzIC4wMSBvciAuMSwgdG8gZWFjaCB2YWx1ZSBvZiB0aGUgcmV3aXJpbmcgcHJvYmFiaWxpdHkgd2hlbgogICAgICB5b3UgcGxvdC4gIGBsb2coMClgIGlzIHVuZGVmaW5lZCwgYnV0IHlvdSBuZWVkIHRvIHNlZSB0aGUgcmVzdWx0CiAgICAgIGZvciB0aGF0IHZhbHVlLgogICAgICAyLiBXaGVuIHlvdSBkbyB0aGlzLCB5b3UgbWF5IG5vdGljZSB0aGUgeC1heGlzIHZhbHVlcyBiZWNvbWUKICAgICAgbmVnYXRpdmUuICBJdCBpcyBhY2NlcHRhYmxlIGlmIHlvdSBsZWF2ZSB0aGUgdmFsdWVzIGxpa2UgdGhhdCwgYnV0CiAgICAgIEkgZW5jb3VyYWdlIHlvdSB0byBleHBsb3JlIGhvdyB0byBmaXggdGhlbS4gIFN1YmhpbnQ6IGxvb2sgYXQKICAgICAgYHhheHRgIGluIGBwbG90KClgIGFuZCBgYXhpcygpYCBhZnRlciBgcGxvdCgpYC4gIFN1YmhpbnQyOiBZb3UKICAgICAgY291bGQgYWxzbyBsb29rIGF0IHRoZSBgbG9nYCBhcmd1bWVudCBpbiBgcGxvdCgpYC4KICAgIGQuIFRvIGFkZCBhIHNlY29uZCBsaW5lIHRvIGEgZ3JhcGgsIHVzZSBgbGluZXMoKWAgYWZ0ZXIgYHBsb3QoKWAuCiAgICBlLiBTYXZlIHRoZSBjaGFydCB0byB5b3VyIGNvbXB1dGVyLgogICAgZi4gSG93IHdpbGwgeW91IGRpc3Rpbmd1aXNoIHdoaWNoIGxpbmUgY29ycmVzcG9uZHMgdG8gd2hpY2gKICAgIHN0YXRpc3RpYz8gIFVzZSB0aGUgYGx0eWAgYXJndW1lbnQgdG8gbGluZXMoKSBhbmQgcGxvdCgpLiAgSWYgeW91CiAgICBhcmUgYWR2ZW50dXJvdXMsIGFkZCBhIGxlZ2VuZCB0byB0aGUgcGxvdCBhcyB3ZWxsLiAKYGBge3J9CnByb2JzIDwtIHNlcSgwLCAxLCBieT0uMDAxKQpub2RlcyA8LSAxMDAwCm5laWdoYm9ycyA8LSAxMAoKYmFzZWxpbmUgPC0gc2FtcGxlX3NtYWxsd29ybGQoZGltPTEsIHNpemU9bm9kZXMsIG5laT1uZWlnaGJvcnMsIHA9MCkKYl9nQyA8LSBtZWFuKHRyYW5zaXRpdml0eShiYXNlbGluZSwgdHlwZT0nbG9jYWwnKSkKZ19hUEwgPC0gYXZlcmFnZS5wYXRoLmxlbmd0aChiYXNlbGluZSkKICAKcmVtZW1iZXIgPC0gZGF0YS5mcmFtZShpdGVyYXRpb249TlVMTCwgcmV3aXJlUHJvYmFiaWxpdHk9TlVMTCwgZ2xvYmFsQ2x1c3RlcmluZz1OVUxMLCBhdmdQYXRoTGVuZ3RoPU5VTEwpCgpmb3IoaSBpbiAxOmxlbmd0aChwcm9icykpewogIHByaW50KHBhc3RlKCdPbiBpdGVyYXRpb24nLCBpKSkKICAKICB0ZW1wIDwtIHNhbXBsZV9zbWFsbHdvcmxkKGRpbT0xLCBzaXplPW5vZGVzLCBuZWk9bmVpZ2hib3JzLCBwPXByb2JzW2ldKQoKICBnbG9iYWxDbHVzdGVyaW5nIDwtIG1lYW4odHJhbnNpdGl2aXR5KHRlbXAsIHR5cGU9J2xvY2FsJykpL2JfZ0MgIAogIGF2Z1BhdGhMZW5ndGggPC0gYXZlcmFnZS5wYXRoLmxlbmd0aCh0ZW1wKS9nX2FQTAogIAogIGQgPC0gZGF0YS5mcmFtZShpdGVyYXRpb249aSwgcmV3aXJlUHJvYmFiaWxpdHk9cHJvYnNbaV0sIGdsb2JhbENsdXN0ZXJpbmc9Z2xvYmFsQ2x1c3RlcmluZywgYXZnUGF0aExlbmd0aD1hdmdQYXRoTGVuZ3RoKQogIAogIHJlbWVtYmVyIDwtIHJiaW5kKHJlbWVtYmVyLCBkKQp9CgojIFRoZSBiZWxvdyBsaW5lIGFkZHMgYSBsaXR0bGUgYml0IHRvIGVhY2ggdmFsdWUgYmVjYXVzZSB0aGVyZSBpcyBhIDAgdGhhdCBJIHdhbnQgdG8ga2VlcCwgYnV0IGxvZygwKSBpcyB1bmRlZmluZWQuCgpyZW1lbWJlciRyZXdpcmVQcm9iYWJpbGl0eSA8LSByZW1lbWJlciRyZXdpcmVQcm9iYWJpbGl0eSsuMDAwMDEKCnBkZignfi9EZXNrdG9wL1VDTEEucGRmJykKcGxvdCh4PXJlbWVtYmVyJHJld2lyZVByb2JhYmlsaXR5LCB5PXJlbWVtYmVyJGF2Z1BhdGhMZW5ndGgsIHhsYWI9J1Jld2lyZSBQcm9iYWJpbGl0eScsIHlsYWI9J0NoYW5nZSBpbiBQYXRoIExlbmd0aCwgQ2x1c3RlcmluZycsIG1haW49J1NtYWxsLXdvcmxkIE5ldHdvcmtzJywgdHlwZT0nbCcsIGxvZz0neCcpCmxpbmVzKHg9cmVtZW1iZXIkcmV3aXJlUHJvYmFiaWxpdHksIHk9cmVtZW1iZXIkZ2xvYmFsQ2x1c3RlcmluZywgbHR5PTMpCmxlZ2VuZCgndG9wcmlnaHQnLCBsZWdlbmQ9YygnQXZlcmFnZSBQYXRoIExlbmd0aCcsICdDbHVzdGVyaW5nJyksIGx0eT1jKDEsMykpCmRldi5vZmYoKQpgYGAKCgpVc2UgaWdyYXBoOiBGcm9tIGhlcmUgb24gb3V0LCB3ZSB3aWxsIHJlbHkgb24gYGlncmFwaGAncyBmdW5jdGlvbnMgdG8gYnVpbGQgbmV0d29ya3MuICBXaGlsZSB3ZSBjb3VsZCBidWlsZCB0aGVtIG1hbnVhbGx5IGZyb20gYWRqYWNlbmN5IG1hdHJpY2VzLCBjcmVhdGluZyB0aGUgcHJvcGVyIGFkamFjZW5jeSBtYXRyaXggb3IgZWRnZWxpc3QgaXMgYSBiaXQgbW9yZSBjb21wbGljYXRlZC4gIEl0IGlzIGRvYWJsZSBidXQgbm90IG5lY2Vzc2FyeSBmb3IgdGhlIGFpbXMgb2YgdGhpcyBjbGFzcy4gVGhlIGBpZ3JhcGhgIGZ1bmN0aW9uIGBzYW1wbGVfc21hbGx3b3JsZGAgY2FuIGJlIGNvbmZ1c2luZy4gIFlvdSBkZWZpbmUgdGhlIG51bWJlciBvZiBkaW1lbnNpb25zIG9mIHRoZSBsYXR0aWNlOyAxIG1lYW5zIGEgbGluZSwgMiBtZWFucyBhIG1hdHJpeCwgYW5kIHNvIG9uLiAgVGhlIGRpbWVuc2lvbiB3aWxsIHJhaXNlIHRoZSBudW1iZXIgb2Ygbm9kZXMgeW91IHdhbnQgdG8gdGhlIHBvd2VyIG9mIHRoZSBkaW1lbnNpb24uICBJdCBpcyB0aGVyZWZvcmUgZWFzaWVzdCB0byBqdXN0IGRlZmluZSB0aGUgbnVtYmVyIG9mIG5vZGVzIHlvdSB3YW50IGFuZCBhc3N1bWUgb25lIGRpbWVuc2lvbi4gIGBuZWlgIGlzIGhvdyBmYXIgKG1hbnkgc3RlcHMpIGluIGVhY2ggZGlyZWN0aW9uIHRvIG1ha2UgY29ubmVjdGlvbnMgYmV0d2VlbiBub2RlczsgdGhlIGhpZ2hlciBpdCBpcywgdGhlIGdyZWF0ZXIgdGhlIGF2ZXJhZ2UgZGVncmVlLgoKCkNyZWF0ZSBhIHNtYWxsLXdvcmwgbmV0d29yayB1c2luZyBpZ3JhcGggcGFja2FnZSwgZXhwbG9yZSBkZWdyZWUsIGNsdXN0ZXJpbmcsIGRlbnNpdHk6CmBgYHtyfQpub2RlcyA8LSAxMDAKCmJ1czIwIDwtIHNhbXBsZV9zbWFsbHdvcmxkKGRpbT0xLCBzaXplPW5vZGVzLCBuZWk9MywgcD0uMikKc3VtbWFyeShkZWdyZWUoYnVzMjApKQp0cmFuc2l0aXZpdHkoYnVzMjAsIHR5cGU9J2dsb2JhbCcpCm1lYW4odHJhbnNpdGl2aXR5KGJ1czIwLCB0eXBlPSdsb2NhbCcpKQpncmFwaC5kZW5zaXR5KGJ1czIwKQoKYGBgCgpMZXQncyBtYWtlIHRoZSBwcmludGVkIG91dHB1dCBhIGxpdHRsZSBlYXNpZXIgdG8gcmVhZC4KYGBge3J9CnN1bW1hcnkoZGVncmVlKGJ1czIwKSkKcGFzdGUoJ1RoZSBncmFwaFwncyB0cmFuc2l0aXZpdHkgaXMnLCByb3VuZCh0cmFuc2l0aXZpdHkoYnVzMjAsIHR5cGU9J2dsb2JhbCcpLDIpKQpwYXN0ZSgnVGhlIG90aGVyIHdheSB0byBjYWxjdWxhdGUgdHJhbnNpdGl2aXR5IHN1Z2dlc3RzIHRoZSB2YWx1ZSBpcycsIG1lYW4odHJhbnNpdGl2aXR5KGJ1czIwLCB0eXBlPSdsb2NhbCcpKSkKcGFzdGUoJ1RoZSBkZW5zaXR5IG9mIHRoZSBncmFwaCBpcycsIGdyYXBoLmRlbnNpdHkoYnVzMjApKQpwYXN0ZSgnVGhlcmUgYXJlJywgZWNvdW50KGJ1czIwKSwgJ2VkZ2VzIGluIHRoZSBncmFwaCcpCgpgYGAKCkxldCdzIGRvIHRoYXQgYWdhaW4sIGNoYW5naW5nIHRoZSBzaXplIG9mIHRoZSBuZXR3b3JrIGZybyAxMDAgdG8gMSwwMDAuCmBgYHtyfQpub2RlcyA8LSAxMDAwCgpidXMyMCA8LSBzYW1wbGVfc21hbGx3b3JsZChkaW09MSwgc2l6ZT1ub2RlcywgbmVpPTMsIHA9LjIpCmBgYAoKTGV0J3MgbWFrZSB0aGUgcHJpbnRlZCBvdXRwdXQgYSBsaXR0bGUgZWFzaWVyIHRvIHJlYWQuCmBgYHtyfQpzdW1tYXJ5KGRlZ3JlZShidXMyMCkpCnBhc3RlKCdUaGUgZ3JhcGhcJ3MgdHJhbnNpdGl2aXR5IGlzJywgcm91bmQodHJhbnNpdGl2aXR5KGJ1czIwLCB0eXBlPSdnbG9iYWwnKSwgNSkpCnBhc3RlKCdUaGUgb3RoZXIgd2F5IHRvIGNhbGN1bGF0ZSB0cmFuc2l0aXZpdHkgc3VnZ2VzdHMgdGhlIHZhbHVlIGlzJywgbWVhbih0cmFuc2l0aXZpdHkoYnVzMjAsIHR5cGU9J2xvY2FsJykpKQpwYXN0ZSgnVGhlIG90aGVyIHdheSB0byBjYWxjdWxhdGUgdHJhbnNpdGl2aXR5IHN1Z2dlc3RzIHRoZSB2YWx1ZSBpcycsIG1lYW4odHJhbnNpdGl2aXR5KGJ1czIwLCB0eXBlPSdsb2NhbCcpLCBuYS5ybT1UUlVFKSkKcGFzdGUoJ1RoZSBkZW5zaXR5IG9mIHRoZSBncmFwaCBpcycsIGdyYXBoLmRlbnNpdHkoYnVzMjApKQpwYXN0ZSgnVGhlcmUgYXJlJywgZWNvdW50KGJ1czIwKSwgJ2VkZ2VzIGluIHRoZSBncmFwaCcpCmBgYAoKTm93LCB3ZSBjYW4gdmFyeSB0aGUgcGFyYW1ldGVycyBsaWtlIHdlIGRpZCBmb3IgcmFuZG9tIGdyYXBocy4gIFNpbmNlIHdlIGFyZSBmYW1pbGlhciB3aXRoIHRoaXMgcHJvY2VzcywgSSB3aWxsICoqdmFyeSBgcGAgYW5kIHNhdmUgdGhlIHJlc3VsdHMgdG8gYSBkYXRhZnJhbWUqKiBpbW1lZGlhdGVseS4gIE5vdGljZSB0aGF0IEkgZGVmaW5lIGhvdyBtYW55IGl0ZXJhdGlvbnMgb2YgdGhlIGxvb3AgZGlmZmVyZW50bHkgdGhhbiBmb3IgcmFuZG9tIGdyYXBoczsgdGhleSBib3RoIHdvcmsgdGhlIHNhbWUuICBJIGFtIGdvaW5nIHRvIGludHJvZHVjZSBhIG5ldyB3YXkgdG8gZ2VuZXJhdGUgc2VxdWVuY2VzIG9mIG51bWJlcnMgYXMgd2VsbC4KClZhcnkgcCB1c2luZyBzZXF1ZW5jZS4gIFRoZXJlIGFyZSB0d28gd2F5cyB0byBkbyB0aGlzLgpgYGB7cn0KcCA8LSBzZXEoZnJvbT0wLCB0bz0xLCBieT0uMSkKcDIgPC0gc2VxKGZyb209MCwgdG89MSwgbGVuZ3RoLm91dD0xMSkKcCA9PSBwMiAgIyBHcmVhdAoKbm9kZXMgPC0gMjUwCgpyZW1lbWJlciA8LSBkYXRhLmZyYW1lKGl0ZXJhdGlvbj1OVUxMLCByZXdpcmVQcm9iYWJpbGl0eT1OVUxMLCBhdmdEZWdyZWU9TlVMTCwgZ2xvYmFsQ2x1c3RlcmluZz1OVUxMLCBnbGJhbENsdXN0ZXJpbmcyPU5VTEwsIGRlbnNpdHk9TlVMTCwgZGlhbWV0ZXI9TlVMTCwgYXZnUGF0aExlbmd0aD1OVUxMKQoKZm9yKGkgaW4gMTpsZW5ndGgocCkpewogIHRlbXAgPC0gc2FtcGxlX3NtYWxsd29ybGQoZGltPTEsIHNpemU9bm9kZXMsIG5laT0zLCBwPXBbaV0pCiAgCiAgcHJpbnQocGFzdGUoJ1dlIGFyZSBvbiBsb29wJywgaSkpCiAgaXRlcmF0aW9uIDwtIGkKICByZXdpcmVQcm9iYWJpbGl0eSA8LSBwW2ldCiAgYXZnRGVncmVlIDwtIG1lYW4oZGVncmVlKHRlbXApKQogIGdsb2JhbENsdXN0ZXJpbmcgPC0gdHJhbnNpdGl2aXR5KHRlbXAsIHR5cGU9J2dsb2JhbCcpCiAgZ2xvYmFsQ2x1c3RlcmluZzIgPC0gbWVhbih0cmFuc2l0aXZpdHkodGVtcCwgdHlwZT0nbG9jYWwnKSwgbmEucm09VFJVRSkKICBkZW5zaXR5IDwtIGdyYXBoLmRlbnNpdHkodGVtcCkKICBkaWFtZXRlciA8LSBkaWFtZXRlcih0ZW1wKQogIGF2Z1BhdGhMZW5ndGggPC0gYXZlcmFnZS5wYXRoLmxlbmd0aCh0ZW1wKQoKICBwcmludCgnSnVzdCBmaW5pc2hlZCBjYWxjdWxhdGlvbnMuICBNYWtpbmcgZGF0YWZyYW1lLicpCiAgCiAgZCA8LSBkYXRhLmZyYW1lKGl0ZXJhdGlvbj1pdGVyYXRpb24sIHJld2lyZVByb2JhYmlsaXR5PXJld2lyZVByb2JhYmlsaXR5LCBhdmdEZWdyZWU9YXZnRGVncmVlLCBnbG9iYWxDbHVzdGVyaW5nPWdsb2JhbENsdXN0ZXJpbmcsIGdsb2JhbENsdXN0ZXJpbmcyPWdsb2JhbENsdXN0ZXJpbmcyLCBkZW5zaXR5PWRlbnNpdHksIGRpYW1ldGVyPWRpYW1ldGVyLCBhdmdQYXRoTGVuZ3RoPWF2Z1BhdGhMZW5ndGgpCiAgCiAgcmVtZW1iZXIgPC0gcmJpbmQocmVtZW1iZXIsIGQpICAjICJyb3diaW5kIiwgYWRkcyBhIG5ldyByb3csIGQsIHRvIHdoYXRldmVyIGV4aXN0cyBpbiByZW1lbWJlci4KfQoKcmVtZW1iZXIgICMgV29vIQpgYGAKCioqV2h5IGRvZXMgdGhlIGRlbnNpdHkgbmV2ZXIgY2hhbmdlPyoqIEJlY2F1c2UgaXQgaXMgdGhlIHBlcmNlbnRhZ2Ugb2YgcG9zc2libGUgZWRnZXMgdGhhdCBhY3R1YWxseSBleGlzdDsgZGVuc2l0eSB0ZWxscyB5b3UgYWJvdXQgdGhlIG5ldHdvcmsgb3ZlcmFsbCAod2hpbGUgZGVncmVlIHRlbGxzIHlvdSBzb21ldGhpbmcgYWJvdXQgaW5kaXZpZHVhbCBub2RlcykKCkNyZWF0ZSBhIHNtYWxsLXdvcmxkIHJpbmcgbmV0d29yayB3aXRoIDEwMCBub2RlcyB0aGF0IGVhY2ggc3RhcnQgd2l0aCBjb25uZWN0aW9ucyB0byAxMCBuZWlnaGJvcnMuICBSYW5kb21seSByZXdpcmUgd2l0aCBwcm9iYWJpbGl0eSBvZiAuMDMuCmBgYHtyfQpzdyA8LSBzYW1wbGVfc21hbGx3b3JsZChkaW09MSwgc2l6ZT0xMDAsIG5laT01LCBwPS4wMykKc3cKYGBgCgpXcml0ZSBhIGxvb3AgdGhhdCBjcmVhdGVzIGEgbmV3IHNtYWxsLXdvcmxkIG5ldHdvcmsgZWFjaCBpdGVyYXRpb24uICBWYXJ5IHRoZSByZXdpcmluZyBwcm9iYWJpbGl0eSBmcm9tIDAgdG8gLjIgaW4gaW5jcmVtZW50cyBvZiAuMDEuICBTYXZlIHRoZSByZXN1bHRzIGluIGEgZGF0YWZyYW1lLCB0cmFja2luZyBhdCBsZWFzdCB0aGUgb3ZlcmFsbCBjbHVzdGVyaW5nLCBkaWFtZXRlciwgYW5kIGF2ZXJhZ2UgcGF0aCBsZW5ndGguCmBgYHtyfQp0aGVwcyA8LSBzZXEoMCwgLjIsIGJ5PS4wMSkKCnJlbWVtYmVyMyA8LSBkYXRhLmZyYW1lKGl0ZXJhdGlvbj1OVUxMLCByZXdpcmVQcm9iYWJpbGl0eT1OVUxMLCBhdmdEZWdyZWU9TlVMTCwgZ2xvYmFsQ2x1c3RlcmluZz1OVUxMLCBnbGJhbENsdXN0ZXJpbmcyPU5VTEwsIGRlbnNpdHk9TlVMTCwgZGlhbWV0ZXI9TlVMTCwgYXZnUGF0aExlbmd0aD1OVUxMKQoKbm9kZXMgPC0gMTAwCmZvcihpIGluIDE6bGVuZ3RoKHRoZXBzKSl7CiAgdGVtcCA8LSBzYW1wbGVfc21hbGx3b3JsZChkaW09MSwgc2l6ZT1ub2RlcywgbmVpPTMsIHA9dGhlcHNbaV0pCiAgCiAgcHJpbnQocGFzdGUoJ1dlIGFyZSBvbiBsb29wJywgaSkpCiAgaXRlcmF0aW9uIDwtIGkKICByZXdpcmVQcm9iYWJpbGl0eSA8LSB0aGVwc1tpXQogIGF2Z0RlZ3JlZSA8LSBtZWFuKGRlZ3JlZSh0ZW1wKSkKICBnbG9iYWxDbHVzdGVyaW5nIDwtIHRyYW5zaXRpdml0eSh0ZW1wLCB0eXBlPSdnbG9iYWwnKQogIGdsb2JhbENsdXN0ZXJpbmcyIDwtIG1lYW4odHJhbnNpdGl2aXR5KHRlbXAsIHR5cGU9J2xvY2FsJyksIG5hLnJtPVRSVUUpCiAgZGVuc2l0eSA8LSBncmFwaC5kZW5zaXR5KHRlbXApCiAgZGlhbWV0ZXIgPC0gZGlhbWV0ZXIodGVtcCkKICBhdmdQYXRoTGVuZ3RoIDwtIGF2ZXJhZ2UucGF0aC5sZW5ndGgodGVtcCkKCiAgI3ByaW50KCdKdXN0IGZpbmlzaGVkIGNhbGN1bGF0aW9ucy4gIE1ha2luZyBkYXRhZnJhbWUuJykKICAKICBkIDwtIGRhdGEuZnJhbWUoaXRlcmF0aW9uPWl0ZXJhdGlvbiwgcmV3aXJlUHJvYmFiaWxpdHk9cmV3aXJlUHJvYmFiaWxpdHksIGF2Z0RlZ3JlZT1hdmdEZWdyZWUsIGdsb2JhbENsdXN0ZXJpbmc9Z2xvYmFsQ2x1c3RlcmluZywgZ2xvYmFsQ2x1c3RlcmluZzI9Z2xvYmFsQ2x1c3RlcmluZzIsIGRlbnNpdHk9ZGVuc2l0eSwgZGlhbWV0ZXI9ZGlhbWV0ZXIsIGF2Z1BhdGhMZW5ndGg9YXZnUGF0aExlbmd0aCkKICAKICByZW1lbWJlcjMgPC0gcmJpbmQocmVtZW1iZXIzLCBkKSAgIyAicm93YmluZCIsIGFkZHMgYSBuZXcgcm93LCBkLCB0byB3aGF0ZXZlciBleGlzdHMgaW4gcmVtZW1iZXIuCn0KCnJlbWVtYmVyMwpgYGAKCgoKCgoKCgoKCgoKCgojIyMjIFNDQUxFIEZSRUUgTkVUV09SS1MKCgpDcmVhdGUgYSBzY2FsZSBmcmVlIG5ldHdvcmsgd2l0aCAxMiwwMDAgbm9kZXMgd2hlcmUgZWFjaCBub2RlIGFkZHMgMjAgZWRnZXMuICAKICAgIGEuIE1ha2UgYSBoaXN0b2dyYW0gb2YgdGhlIGRlZ3JlZSBkaXN0cmlidXRpb24uCiAgICBiLiBXaGF0IGlzIHRoZSByYXRpbyBvZiB0aGUgbWVhbiB0byBtZWRpYW4gZGVncmVlPwogICAgYy4gSXMgdGhlIGRlbnNpdHkgbGVzcyB0aGFuIGEgc21hbGwtd29ybGQgbmV0d29yaz8gIFdoeT8KYGBge3J9Cm5vZGVzIDwtIDEyMDAwCm5ld2VkZ2VzIDwtIDIwCnNmIDwtIHNhbXBsZV9wYShuPTEyMDAwLCBwb3dlcj0xLCBtPW5ld2VkZ2VzLCBkaXJlY3RlZD1GQUxTRSkKCnBkZignRmlndXJlcy9QUzNfc2NhbGVmcmVlLnBkZicpCmhpc3QoZGVncmVlKHNmKSwgYnJlYWtzPTEwMCwgeGxhYj0nRGVncmVlJywgeWxhYj0nQ291bnQnLCBtYWluPSdTY2FsZS1mcmVlIE5ldHdvcmsnKQpkZXYub2ZmKCkKCm1lYW4oZGVncmVlKHNmKSkvbWVkaWFuKGRlZ3JlZShzZikpCgpncmFwaC5kZW5zaXR5KHNmKQoKIyBEZW5zaXR5IGlzIGxlc3MgaW4gYSBzY2FsZS1mcmVlIG5ldHdvcmsgYmVjYXVzZSBlZGdlcyBhcmUgYWRkZWQgcmFuZG9tbHksIHdoZXJlYXMgc21hbGwtd29ybGQgbmV0d29ya3Mgc3RhcnQgZnJvbSBuZXR3b3JrcyB0aGF0IGhhdmUgY2x1c3RlcmluZyB2YWx1ZXMgb2YgMS4gVGhlIGRlbnNpdHkgaXMgbGVzcyBpbiBhIHNjYWxlLWZyZWUgbmV0d29yayB0aGFuIGluIGEgc21hbGwtd29ybGQgbmV0d29yaywgYmVjYXVzZSBlZGdlcyBhcmUgYWRkZWQgYXQgcmFuZG9tLCBpLmUuLCBzbWFsbC13b3JsZCBuZXR3b3JrcyBzdGFydCBmcm9tIG5ldHdvcmtzIHRoYXQgaGF2ZSBhIGNsdXN0ZXJpbmcgdmFsdWUgb2YgMSBhbmQgd2lsbCB0aGVyZWZvcmUgYWx3YXlzIGhhdmUgYSBncmVhdGVyIGRlbnNpdHkuCgojVGhlIHJ1bGUgYWJvdmUgYXBwbGllcyB0byBnbG9iYWwgY2x1c3RlcmluZyBhcyB3ZWxsLCBpLmUuLCBnbG9iYWwgY2x1c3RlcmluZyBpcyBsZXNzIGluIGEgc2NhbGUtZnJlZSBuZXR3b3JrIHRoYW4gaW4gYSBzbWFsbC13b3JsZCBuZXR3b3JrLgoKYGBgCgpOb3csIHdlIHdpbGwgZXhwbG9yZSBzY2FsZS1mcmVlIG5ldHdvcmtzLCB1c2luZyBCYXJhYmFzaSdzIG1vZGVsIG9mIHByZWZlcmVudGlhbCBhdHRhY2htZW50LiAgV2hpbGUgdGhlcmUgYXJlIG1hbnkgbWVjaGFuaXNtcyB0aGF0IGNhbiBnZW5lcmF0ZSBzY2FsZS1mcmVlIGRpc3RyaWJ1dGlvbnMsIGhpcyBpcyB0aGUgbW9zdCBjb21tb25seSB1c2VkIGFuZCB0aGVyZWZvcmUgdGhlIG9uZSBtb3N0IGNvbW1vbmx5IGluY2x1ZGVkIG91dCBvZiB0aGUgYm94IGluIHNvZnR3YXJlLiBXZSB3aWxsIGZvY3VzIG9uIHZhcnlpbmcgdGhlIG51bWJlciBvZiBlZGdlcyBhZGRlZCB0byBhIG5ldHdvcmsuICBBIGtleSBmZWF0dXJlIG9mIHNjYWxlLWZyZWUgbmV0d29ya3MgaXMgdGhhdCB0aGUgbWVhbiBkZWdyZWUgaXMgbXVjaCBoaWdoZXIgdGhhbiB0aGUgbWVkaWFuOyB3ZSB3aWxsIHRyYWNrIHRoYXQgcmF0aW8uCmBgYHtyfQpOb2RlcyA8LSAxMDAwCnNmIDwtIHNhbXBsZV9wYShuPW5vZGVzLCBwb3dlcj0xLCBtPTEwLCBkaXJlY3RlZD1GQUxTRSkKCmRlZ3JlZV9kaXN0cmlidXRpb24oc2YpICAjIEFzIGxvbmcgYXMgbWF4KGRlZ3JlZShzZikpLiAgR2l2ZXMgcHJvYmFiaWxpdHkgb2Ygbm9kZSBoYXZpbmcgdGhhdCBkZWdyZWUuCmBgYAoKTGV0J3MgbWFrZSB0aGUgcHJpbnRlZCBvdXRwdXQgYSBsaXR0bGUgZWFzaWVyIHRvIHJlYWQuCmBgYHtyfQpzdW1tYXJ5KGRlZ3JlZShzZikpCnBhc3RlKCdUaGUgZ3JhcGhcJ3MgdHJhbnNpdGl2aXR5IGlzJywgdHJhbnNpdGl2aXR5KHNmLCB0eXBlPSdnbG9iYWwnKSkKcGFzdGUoJ1RoZSBvdGhlciB3YXkgdG8gY2FsY3VsYXRlIHRyYW5zaXRpdml0eSBzdWdnZXN0cyB0aGUgdmFsdWUgaXMnLCBtZWFuKHRyYW5zaXRpdml0eShzZiwgdHlwZT0nbG9jYWwnKSkpCnBhc3RlKCdUaGUgZGVuc2l0eSBvZiB0aGUgZ3JhcGggaXMnLCBncmFwaC5kZW5zaXR5KHNmKSkKcGFzdGUoJ1RoZXJlIGFyZScsIGVjb3VudChzZiksICdlZGdlcyBpbiB0aGUgZ3JhcGgnKQpwYXN0ZSgnVGhlIHJhdGlvIG9mIG1lYW4gdG8gbWVkaWFuIGRlZ3JlZSBpcycsIG1lYW4oZGVncmVlKHNmKSkvbWVkaWFuKGRlZ3JlZShzZikpKQoKIyBMZXQncyBjaGFuZ2UgbQpzZiA8LSBzYW1wbGVfcGEobj1ub2RlcywgcG93ZXI9MSwgbT0xLCBkaXJlY3RlZD1GQUxTRSkKCmRlZ3JlZV9kaXN0cmlidXRpb24oc2YpICAjIEFzIGxvbmcgYXMgbWF4KGRlZ3JlZShzZikpLiAgR2l2ZXMgcHJvYmFiaWxpdHkgb2Ygbm9kZSBoYXZpbmcgdGhhdCBkZWdyZWUuCgojIExldCdzIG1ha2UgdGhlIHByaW50ZWQgb3V0cHV0IGEgbGl0dGxlIGVhc2llciB0byByZWFkLgpzdW1tYXJ5KGRlZ3JlZShzZikpCnBhc3RlKCdUaGUgZ3JhcGhcJ3MgdHJhbnNpdGl2aXR5IGlzJywgdHJhbnNpdGl2aXR5KHNmLCB0eXBlPSdnbG9iYWwnKSkKcGFzdGUoJ1RoZSBvdGhlciB3YXkgdG8gY2FsY3VsYXRlIHRyYW5zaXRpdml0eSBzdWdnZXN0cyB0aGUgdmFsdWUgaXMnLCBtZWFuKHRyYW5zaXRpdml0eShzZiwgdHlwZT0nbG9jYWwnKSkpCnBhc3RlKCdUaGUgZGVuc2l0eSBvZiB0aGUgZ3JhcGggaXMnLCBncmFwaC5kZW5zaXR5KHNmKSkKcGFzdGUoJ1RoZXJlIGFyZScsIGVjb3VudChzZiksICdlZGdlcyBpbiB0aGUgZ3JhcGgnKQpwYXN0ZSgnVGhlIHJhdGlvIG9mIG1lYW4gdG8gbWVkaWFuIGRlZ3JlZSBpcycsIG1lYW4oZGVncmVlKHNmKSkvbWVkaWFuKGRlZ3JlZShzZikpKQoKIyBMZXQncyBjaGFuZ2UgbSBBR0FJTgpzZiA8LSBzYW1wbGVfcGEobj1ub2RlcywgcG93ZXI9MSwgbT0yMCwgZGlyZWN0ZWQ9RkFMU0UpCgpkZWdyZWVfZGlzdHJpYnV0aW9uKHNmKSAgIyBBcyBsb25nIGFzIG1heChkZWdyZWUoc2YpKS4gIEdpdmVzIHByb2JhYmlsaXR5IG9mIG5vZGUgaGF2aW5nIHRoYXQgZGVncmVlLgoKIyBMZXQncyBtYWtlIHRoZSBwcmludGVkIG91dHB1dCBhIGxpdHRsZSBlYXNpZXIgdG8gcmVhZC4Kc3VtbWFyeShkZWdyZWUoc2YpKQpwYXN0ZSgnVGhlIGdyYXBoXCdzIHRyYW5zaXRpdml0eSBpcycsIHRyYW5zaXRpdml0eShzZiwgdHlwZT0nZ2xvYmFsJykpCnBhc3RlKCdUaGUgb3RoZXIgd2F5IHRvIGNhbGN1bGF0ZSB0cmFuc2l0aXZpdHkgc3VnZ2VzdHMgdGhlIHZhbHVlIGlzJywgbWVhbih0cmFuc2l0aXZpdHkoc2YsIHR5cGU9J2xvY2FsJykpKQpwYXN0ZSgnVGhlIGRlbnNpdHkgb2YgdGhlIGdyYXBoIGlzJywgZ3JhcGguZGVuc2l0eShzZikpCnBhc3RlKCdUaGVyZSBhcmUnLCBlY291bnQoc2YpLCAnZWRnZXMgaW4gdGhlIGdyYXBoJykKcGFzdGUoJ1RoZSByYXRpbyBvZiBtZWFuIHRvIG1lZGlhbiBkZWdyZWUgaXMnLCBtZWFuKGRlZ3JlZShzZikpL21lZGlhbihkZWdyZWUoc2YpKSkKCiMgTGV0J3MgbWFrZSBhIGhpc3RvZ3JhbSBvZiB0aGUgZGVncmVlIGRpc3RyaWJ1dGlvbgojcGRmKC9jaGFuZ2UvdGhpcy9maWxlbmFtZS90by9zYXZlL291dC5wZGYpCmhpc3QoZGVncmVlKHNmKSwgeGxhYj0nTm9kZSBEZWdyZWUnLCB5bGFiPSdDb3VudCcsIGJyZWFrcz01MCwgbWFpbj0nRGlzdHJpYnV0aW9uIG9mIERlZ3JlZSBpbiBTY2FsZS1GcmVlIEdyYXBoJykKI2Rldi5vZmYoKQpgYGAKCk5vdywgbGV0J3MgdXNlIGEgbG9vcCB0byBzZWUgaG93IHRoZXNlIG1lYXN1cmVzIGNoYW5nZSBhcyB3ZSBpbmNyZWFzZSB0aGUgbnVtYmVyIG9mIG5vZGVzIGluIHRoZSBuZXR3b3JrLiAgTGV0IHVzIGluY3JlYXNlIGl0IGluIHVuaXRzIG9mIDEsMDAwLiBWYXJ5IG5ldHdvcmsgc2l6ZSB1c2luZyBhIGxvb3A6CmBgYHtyfQpub2RlcyA8LSBzZXEoZnJvbT0xMDAwLHRvPTEwMDAwLGJ5PTEwMDApCgpyZW1lbWJlciA8LSBkYXRhLmZyYW1lKGl0ZXJhdGlvbj1OVUxMLCBuZXR3b3JrU2l6ZT1OVUxMLCBhdmdEZWdyZWU9TlVMTCwgZ2xvYmFsQ2x1c3RlcmluZz1OVUxMLCBnbGJhbENsdXN0ZXJpbmcyPU5VTEwsIGRlbnNpdHk9TlVMTCwgcmF0aW89TlVMTCwgYXZnUGF0aExlbmd0aD1OVUxMKQoKZm9yKGkgaW4gMTpsZW5ndGgobm9kZXMpKXsKICB0ZW1wIDwtIHNhbXBsZV9wYShuPW5vZGVzW2ldLCBwb3dlcj0xLCBtPTEwLCBkaXJlY3RlZD1GQUxTRSkKICAKICBwcmludChwYXN0ZSgnVGhpcyBpcyBsb29wJywgaSwgJ29mJywgbGVuZ3RoKG5vZGVzKSkpCiAgCiAgZCA8LSBkYXRhLmZyYW1lKGl0ZXJhdGlvbj1pLCBzaXplPW5vZGVzW2ldLCBhdmdEZWdyZWU9bWVhbihkZWdyZWUodGVtcCkpLCBnbG9iYWxDbHVzdGVyaW5nPXRyYW5zaXRpdml0eSh0ZW1wLCB0eXBlPSdnbG9iYWwnKSwgZ2xvYmFsQ2x1c3RlcmluZzI9bWVhbih0cmFuc2l0aXZpdHkodGVtcCwgdHlwZT0nbG9jYWwnKSksIGRlbnNpdHk9Z3JhcGguZGVuc2l0eSh0ZW1wKSwgcmF0aW89bWVhbihkZWdyZWUodGVtcCkpL21lZGlhbihkZWdyZWUodGVtcCkpLCBhdmdQYXRoTGVuZ3RoPWF2ZXJhZ2UucGF0aC5sZW5ndGgodGVtcCkpCgogIHJlbWVtYmVyIDwtIHJiaW5kKHJlbWVtYmVyLCBkKSAgIyAicm93YmluZCIsIGFkZHMgYSBuZXcgcm93LCBkLCB0byB3aGF0ZXZlciBleGlzdHMgaW4gcmVtZW1iZXIuCn0KCnJlbWVtYmVyICMgTm90IGJhZC4KYGBgCgoKCgoKCgoKCgoKCiMjIyMgUkVBTCBORVRXT1JLUwoKSW4gdGhpcyBzZWN0aW9uLCB3ZSB3aWxsIGV4cGxvcmUgYWN0dWFsIG5ldHdvcmsgZGF0YS4gIFRoZSBmaXJzdCBkYXRhc2V0IGlzIGUtbWFpbHMgZnJvbSBFbnJvbiwgYW4gZW5lcmd5IGZpcm0gdGhhdCBpbXBsb2RlZCB3aGVuIGl0cyBhY2NvdW50aW5nIG1hbmlwdWxhdGlvbnMgd2VyZSBkaXNjb3ZlcmVkLiAgVGhlIHNlY29uZCBpcyBhIHNhbXBsZSBvZiBpbmRpdmlkdWFscyBmcm9tIEZhY2Vib29rLgoKTG9hZCBFbnJvbjoKYGBge3J9CmVucm9uIDwtIHJlYWRfZ3JhcGgoJ2h0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9aYWNoYXJ5U1QvRGF0YS9tYXN0ZXIvZW5yb25fZW1haWwnLCBmb3JtYXQ9YygnZWRnZWxpc3QnKSkKI0Fub3RoZXIgd2F5OiBsb2FkIEVucm9uIGRhdGEgdXNpbmcgcmVhZC50YWJsZSwgY29udmVydCB0byBpZ3JhcGggb2JqZWN0LgoKIyBFeHBsb3JlCmlzLmRpcmVjdGVkKGVucm9uKQplbnJvbiA8LSBhcy51bmRpcmVjdGVkKGVucm9uKSAjbWFrZSBpdCB1bmRpcmVjdGVkCmlzLmRpcmVjdGVkKGVucm9uKQoKbGVuZ3RoKFYoZW5yb24pKSAjbm9kZXMKdmNvdW50KGVucm9uKSAjc2FtZSBhcyBhYm92ZQoKZWNvdW50KGVucm9uKSAjZWRnZXMKYGBgCgpgYGB7cn0KIyBBcmUgdGhlcmUgYWN0dWFsbHkgbmVnYXRpdmUgdmFsdWVzPwpzdW1tYXJ5KGVucm9uKSAgIyBObyBuZWdhdGl2ZSB2YWx1ZXMuCgojIFNvLCBhZGQgb25lIHRvIGVhY2ggdmVydGV4IGlkLiAgVGhpcyBpcyBmaW5lIGJlY2F1c2UgdGhleSBhcmUganVzdCBJRCBudW1iZXJzLgojIE5COiBJIGNyZWF0ZSBhIG5ldyBvYmplY3QsIGVucm9uMiwgdG8gc2hvdyB5b3UgdGhlIGRpZmZlcmVuY2UuICBJZiBJIHdhcyBub3QgdGVhY2hpbmcsIEkgd291bGQganVzdCBoYXZlIHdyaXR0ZW4gZW5yb24gPC0gZW5yb24gKyAxLgplbnJvbjIgPC0gZW5yb24gKyAxCmhlYWQoZW5yb24yKQpoZWFkKGVucm9uKQoKZW5yb24yIDwtIGdyYXBoX2Zyb21fZWRnZWxpc3QoYXMubWF0cml4KGVucm9uMiksIGRpcmVjdGVkPUZBTFNFKQppcy5kaXJlY3RlZChlbnJvbjIpCnZjb3VudChlbnJvbjIpCmVjb3VudChlbnJvbjIpCgojIExldCdzIGxvb2sgYXQgc3VtbWFyeSBzdGF0aXNpY3MuCnN1bW1hcnkoZGVncmVlKGVucm9uMikpCnBhc3RlKCdUaGUgZ3JhcGhcJ3MgdHJhbnNpdGl2aXR5IGlzJywgdHJhbnNpdGl2aXR5KGVucm9uMiwgdHlwZT0nZ2xvYmFsJykpCnBhc3RlKCdUaGUgb3RoZXIgd2F5IHRvIGNhbGN1bGF0ZSB0cmFuc2l0aXZpdHkgc3VnZ2VzdHMgdGhlIHZhbHVlIGlzJywgbWVhbih0cmFuc2l0aXZpdHkoZW5yb24yLCB0eXBlPSdsb2NhbCcpKSkKcGFzdGUoJ1RoZSBkZW5zaXR5IG9mIHRoZSBncmFwaCBpcycsIGdyYXBoLmRlbnNpdHkoZW5yb24yKSkKcGFzdGUoJ1RoZXJlIGFyZScsIGVjb3VudChlbnJvbjIpLCAnZWRnZXMgaW4gdGhlIGdyYXBoJykKcGFzdGUoJ1RoZSBkaWFtZXRlciBpcycsIGRpYW1ldGVyKGVucm9uMikpICAjIFRha2VzIGF3aGlsZSB0byBydW4uCnBhc3RlKCdUaGUgYXZlcmFnZSBwYXRoIGxlbmd0aCBpcycsIGF2ZXJhZ2UucGF0aC5sZW5ndGgoZW5yb24yKSkgICMgVGFrZXMgYXdoaWxlIHRvIHJ1bi4KYGBgCgpXZSBjYW4gYWxzbyB0YWtlIHN1YnNldHMgb2YgYSBuZXR3b3JrIGJhc2VkIG9uIG5vZGUgZmVhdHVyZXMuICBCZWxvdywgSSB3aWxsIHNob3cgeW91IGhvdyB0byBrZWVwIG9ubHkgbm9kZXMgbWVldGluZyBkZWdyZWUgdGhyZXNob2xkcy4KYGBge3J9CiMgU2hvdyBob3cgdG8gc2VsZWN0IG9ubHkgaGlnaC1kZWdyZWUgbm9kZXMKZGVncmVlMTAgPC0gaW5kdWNlZF9zdWJncmFwaChlbnJvbjIsIGRlZ3JlZShlbnJvbjIpPj0xMCkKdmNvdW50KGRlZ3JlZTEwKQplY291bnQoZGVncmVlMTApCgp2Y291bnQoZGVncmVlMTApL3Zjb3VudChlbnJvbjIpICAjIDguOTQlIG9mIG5vZGVzCmVjb3VudChkZWdyZWUxMCkvZWNvdW50KGVucm9uMikgICMgNjIuNDUlIG9mIGVkZ2VzCgpzdW1tYXJ5KGRlZ3JlZShkZWdyZWUxMCkpCnBhc3RlKCdUaGUgZ3JhcGhcJ3MgdHJhbnNpdGl2aXR5IGlzJywgdHJhbnNpdGl2aXR5KGRlZ3JlZTEwLCB0eXBlPSdnbG9iYWwnKSkKcGFzdGUoJ1RoZSBvdGhlciB3YXkgdG8gY2FsY3VsYXRlIHRyYW5zaXRpdml0eSBzdWdnZXN0cyB0aGUgdmFsdWUgaXMnLCBtZWFuKHRyYW5zaXRpdml0eShkZWdyZWUxMCwgdHlwZT0nbG9jYWwnKSwgbmEucm09VFJVRSkpCnBhc3RlKCdUaGUgZGVuc2l0eSBvZiB0aGUgZ3JhcGggaXMnLCBncmFwaC5kZW5zaXR5KGRlZ3JlZTEwKSkKcGFzdGUoJ1RoZXJlIGFyZScsIGVjb3VudChkZWdyZWUxMCksICdlZGdlcyBpbiB0aGUgZ3JhcGgnKQpwYXN0ZSgnVGhlIGRpYW1ldGVyIGlzJywgZGlhbWV0ZXIoZGVncmVlMTApKSAgIyBUYWtlcyBhd2hpbGUgdG8gcnVuLgpwYXN0ZSgnVGhlIGF2ZXJhZ2UgcGF0aCBsZW5ndGggaXMnLCBhdmVyYWdlLnBhdGgubGVuZ3RoKGRlZ3JlZTEwKSkgICMgVGFrZXMgYXdoaWxlIHRvIHJ1bi4KYGBgCgpZb3UgY2FuIGtlZXAgbm9kZXMgdGhhdCBtYXRjaCBhbnkgc29ydCBvZiBmaWx0ZXIgeW91IHdhbnQuICBOZXh0LCBJIHNob3cgYmFzZWQgb24gY2x1c3RlcmluZy4gU2hvdyBob3cgdG8gc2VsZWN0IG5vZGVzIHdpdGggaGlnaCBjbHVzdGVyaW5nCmBgYHtyfQpoaWdoY2x1c3RlcmluZyA8LSBtYXgodHJhbnNpdGl2aXR5KGVucm9uMiwgdHlwZT0nbG9jYWwnKSkKaGlnaGNsdXN0ZXJpbmcgIyBIbT8gIAp0cmFuc2l0aXZpdHkoZW5yb24yLCB0eXBlPSJsb2NhbCIpWzE6MTAwXSAjT2ssIHRoZSBjb2RlIHdvcmtzLiAgU29tZXRpbWVzLCB0aGlzIG1lYW5zIHRoZXJlIGlzIGEgTkEgdmFsdWUsIGFuZCBtYW55IFIgZnVuY3Rpb25zIG5lZWQgaGVscCB3aXRoIHRoYXQuCgpoaWdoY2x1c3RlcmluZyA8LSBtYXgodHJhbnNpdGl2aXR5KGVucm9uMiwgdHlwZT0nbG9jYWwnKSwgbmEucm09VFJVRSkKCiMgVGFrZSBub2RlcyB3aXRoIGhhbGYgdGhlIG1heCBjbHVzdGVyaW5nIHZhbHVlIG9yIG1vcmUuCiMgSSBoYXZlIHRvIGFkZCB0aGUgZXh0cmEgc3RlcHMgYmVjYXVzZSBvZiB0aGUgTkEgdmFsdWVzIHRoZSBmaXJzdCBsaW5lIHJldHVybnMuCmtlZXAgPC0gdHJhbnNpdGl2aXR5KGVucm9uMiwgdHlwZT0nbG9jYWwnKSA+IGhpZ2hjbHVzdGVyaW5nKi41CmtlZXBbaXMubmEoa2VlcCldIDwtIEZBTFNFICAjIFIgd2lsbCBub3Qga25vdyB3aGF0IHRvIGRvIHdpdGggdGhlIE5BIHZhbHVlcy4Ka2VlcFsxOjMwMDBdICMgU28gd2Uga25vdyB3aGF0IGtlZXAgbG9va3MgbGlrZS4KaGlnaGNsdXN0ZXJpbmdfZyA8LSBpbmR1Y2VkX3N1YmdyYXBoKGVucm9uMiwgVihlbnJvbjIpW2tlZXBdKQoKdmNvdW50KGhpZ2hjbHVzdGVyaW5nX2cpCmVjb3VudChoaWdoY2x1c3RlcmluZ19nKSAgIyBWZXJ5IGxvdy4gIFdoeT8KCnRhYmxlKGRlZ3JlZShoaWdoY2x1c3RlcmluZ19nKSkgICMgVGhpcyBpcyB3aHkuCmBgYAoKCgoKCgoKCgoKCiMjIyMgQ0FMQ1VMQVRJT05TICh2ZWN0b3JzLCBvYmplY3RzLCBwaHJhc2VzKQoKCldoYXQgaXMgMzgxOSB0aW1lcyAxMDI/CmBgYHtyfQozODE5ICogMTAyCmBgYAoKV2hhdCBpcyAzODE5IG1pbnVzIDE4OTI/CmBgYHtyfQozODE5IC0gMTg5MgpgYGAKClJlcGVhdCB0aGUgYWJvdmUsIGJ1dCBzYXZlIGVhY2ggbnVtYmVyIGFzIGFuIG9iamVjdC4KYGBge3J9Cm9iajEgPC0gMzgxOSAKb2JqMiA8LSAxODkyIApvYmoxICogb2JqMgpvYmoxIC0gb2JqMgpgYGAKCk1ha2UgYSB2ZWN0b3Igb2YgdGhlIG51bWJlcnMgMTAsIDIwLCAzMCwgNDAsIGFuZCA1MC4gTXVsdGlwbHkgdGhhdCB2ZWN0b3IgIyBieSBhbm90aGVyIG9mIHRoZSBudW1iZXJzIDMsIDQsIDUsIDYsIGFuZCA3LgpgYGB7cn0KdjEgPC0gYygxMCwgMjAsIDMwLCA0MCwgNTApCnYxX2FsdCA8LSBzZXEoZnJvbSA9IDEwLCB0byA9IDUwLCBieSA9IDEwKQp2MiA8LSBjKDMsIDQsIDUsIDYsIDcpIHYyX2FsdCA8LSAzOjcKCnYxICogdjIKdjFfYWx0ICogdjJfYWx0CmBgYAoKUmVwZWF0IGFib3ZlLCBleGNlcHQgbWFrZSB0aGUgc2Vjb25kIHZlY3RvciB0aGUgbnVtYmVycyA1IGFuZCAxMC4gU2hvdyB0aGUgcmVzdWx0cyBhbmQgZXhwbGFpbiwgaW4gd29yZHMsIHdoYXQgUiBpcyBkb2luZyB3aXRoIHRoaXMgc2hvcnRlciB2ZWN0b3IuCmBgYHtyfQp2MiA8LSBjKDUsIDEwKQp2MSAqIHYyCgojKFdhcm5pbmcgaW4gdjEgKiB2MjogbG9uZ2VyIG9iamVjdCBsZW5ndGggaXMgbm90IGEgbXVsdGlwbGUgb2Ygc2hvcnRlciBvYmplY3QgbGVuZ3RoKTogUiByZXBlYXRzIHRoZSB2MiB2ZWN0b3IgYXMgbWFueSB0aW1lcyBhcyBpdCB0YWtlcyB0byBtYXRjaCB0aGUgbGVuZ3RoIG9mIHYxLiBTbywgaXQgY3JlYXRlcyBhIHZlY3RvciB0aGF0IGlzICg1LDEwLDUsMTAsNSkKYGBgCgpEb2VzIHRoZSBwaHJhc2UsICJJIGVuam95IGxlYXJuaW5nIHRvIHByb2dyYW0iIGNvbnRhaW4gdGhlIHdvcmQgImxlYXJuaW5nIj8gIFdoYXQgYWJvdXQgImxlYXJuIj8gIFdoYXQgYWJvdXQgInRvd2FyZHMiPyAKYGBge3J9Cj4gcGhyYXNlIDwtIGMoJ0kgZW5qb3kgbGVhcm5pbmcgdG8gcHJvZ3JhbScpCj4gZ3JlcGwoJ2xlYXJuaW5nJywgcGhyYXNlKQpbMV0gVFJVRSAKPiBncmVwbCgnbGVhcm4nLCBwaHJhc2UpClsxXSBUUlVFCj4gZ3JlcGwoJ3Rvd2FyZHMnLCBwaHJhc2UpClsxXSBGQUxTRQpgYGAKCldoeSBkb2VzIFIgcmV0dXJuIGBbMV1gPwpgYGB7cn0KI0JlY2F1c2UgaXQgaXMgdGVsbGluZyB0aGUgcmVzdWx0IGlzIGEgdmVjdG9yIG9mIGxlbmd0aCAxLiBWZWN0b3JzIGFuZCBjYWxjdWxhdGlvbiBiZWNvbWUgZXNwZWNpYWxseSB1c2VmdWwgd2hlbiB5b3VyIHZlY3RvciBoYXMgbGVuZ3RoIGdyZWF0ZXIgdGhhbiAxLCBzdWNoIGFzIHdoZW4gaXQgcmVwcmVzZW50cyBhIHZhcmlhYmxlIHdpdGggbXVsdGlwbGUgb2JzZXJ2YXRpb25zLiAgWW91IGNhbiB0aGVuIGVhc2lseSBtYW5pcHVsYXRlIGFsbCBlbnRyaWVzIGluIG9uZSB2ZWN0b3Igb3IgcGVyZm9ybSBvcGVyYXRpb25zIG9uIG11bHRpcGxlIHZlY3RvcnMuICBUbyBtYWtlIGEgdmVjdG9yIG9mIGxlbmd0aCBncmVhdGVyIHRoYW4gMSwgeW91IG5lZWQgYGMoKWAuICBUaGUgImMiIHN0YW5kcyBmb3IgImNvbmNhdGVuYXRlIi4KYGBgCgpQcmFjdGljZSB3aXRoIHZlY3RvcnMgb2YgbGVuZ3RoIGdyZWF0ZXIgdGhhbiAxOgpgYGB7cn0KZmlyc3QgPC0gYygxMDAsMTksMjAsODksNzYsMTAyLDc0LDgxLDY1KQpmaXJzdCAqIDIgIAojVGhpcyBtdWx0aXBsaWVzIGVhY2ggZW50cnkgYnkgMiAoZ3JlYXQgdG8gY29udmVydCBpbmNoZXMgdG8gY2VudGltZXRlcnMpCmZpcnN0IC0gMjAgIAojVGhpcyBzdWJ0cmFjdHMgZWFjaCBlbnRyeSBieSAyMAoKc2Vjb25kIDwtIGMoMSwyLDQsMTAsMTAsMSw0LDUsMTApIAojRG8gbm90IG5lZWQgdG8gaGF2ZSB0aGUgZXhhY3Qgc2FtZSBudW1iZXIgb2YgZW50cmllcyBhZ2FpbiwgYnV0IG1hZGUgaXQgbW9yZSBzaW1wbGUpCgpmaXJzdCAqIHNlY29uZCAgCiNNdWx0aXBsaWVzIGVhY2ggZW50cnkgaW4gZmlyc3QgYnkgc2Vjb25kIGluIG9yZGVyLCBpZSAxKjEwMDsgbXVsdGlwbHlpbmcgZWFjaCBlbnRyeSBpcyB3ZWlnaHRpbmcgZGF0YQpmaXJzdCAvIHNlY29uZApgYGAKCkV4YW1wbGUgdXNpbmcgdmVjdG9ycyB0byBjYWxjdWxhdGUgYSBtb3JlIGNvbXBsaWNhdGVkIG91dGNvbWU6CmBgYHtyfQpvYnNlcnZlZCA8LSBmaXJzdCAKIyBJIGhhdmUgY3JlYXRlZCBhIG5ldyBvYmplY3QgdGhhdCBoYXMgdGhlIHZhbHVlcyBvZiBmaXJzdCwgaS5lLiwgaXMgbWFwcGVkIHRvIGZpcnN0IGFib3ZlLgoKb2JzZXJ2ZWQgPT0gZmlyc3QgIAojIFJldHVybnMgVFJVRSBmb3IgYXMgbWFueSBlbnRyaWVzIGFzIHRoZXJlIGFyZSBpbiBlYWNoIHZlY3Rvci4gKE5lZWQgdHdvIGVxdWFsIG1hcmtzLCBvbmUgZXF1YWwgd2lsbCBqdXN0IG1ha2UgYSBjb3B5IGxpa2UgPC0sIHdoaWxlIHRoaXMgY29tcGFyZXMsIGdvb2Qgd2F5IHRvIGNoZWNrIGRhdGEgYWZ0ZXIgZG9pbmcgYSB0cmFuc2Zvcm1hdGlvbikKCm9ic2VydmVkICE9IGZpcnN0IAojKGJvb2xlaWFuIG9wZXJhdGlvbiBmb3IgZG9lcyBub3QgZXF1YWwpCmBgYAoKQ2hpLXNxdWFyZQpgYGB7cn0KZXhwZWN0ZWQgPC0gYyg5MCwxOCwzMCw3OSw4MCw4OCw4MCw4Myw3MCkgCm51bWVyYXRvciA8LSAob2JzZXJ2ZWQtZXhwZWN0ZWQpXjIKc3VtKG51bWVyYXRvci9leHBlY3RlZCkgIApgYGAKClZlY3RvcnMgZG8gbm90IGhhdmUgdG8gYmUgbnVtYmVycy4gRm9yIGV4YW1wbGUsIHlvdSBtYXkgaGF2ZSBhIHZhcmlhYmxlIHRoYXQgaXMgYSByZXNwb25kZW50J3MgZmF2b3JpdGUgc3BvcnRzIHRlYW0sIHNvIHRoZSBlbnRyaWVzIGFyZSBsaWtlbHkgdG8gYmUgd29yZHMuICBJZiB5b3UgaGF2ZSBhIGRhdGFmcmFtZSwgdGhlIGNvbHVtbiBuYW1lcyBhcmUgYSBzdHJpbmcgdmVjdG9yOgpgYGB7cn0KY2hhcl92ZWMgPC0gYygidGhlc2UiLCAiYXJlIiwgInNvbWUiLCAid29yZHMiKQpsZW5ndGgoY2hhcl92ZWMpCgond29yZHMnICVpbiUgY2hhcl92ZWMKJ3dvcmRzJyA9PSBjaGFyX3ZlYwojZm9yIGhvdyBvZnRlbgond29yZCcgJWluJSAgY2hhcl92ZWMKI15nb29kIGZvciBzZWFyY2hpbmcgbGFyZ2VyIHRleHRzCgpzYW1ldHlwZSA8LSBjKCd0aGlzJywgMjAsICdjb252ZXJ0cyB0bycsIDUsICdzdHJpbmdzJykKI15pZiBSIGlzIHVuc3VyZSBvZiBhIHRoaW5nIGl0IGNvbnZlcnRzIGl0IGludG8gYSBzdHJpbmcKYGBgCgpDcmVhdGUgYW4gb2JqZWN0IHRoYXQgY29udGFpbnMgZml2ZSBudW1iZXJzLiBNdWx0aXBseSB0aG9zZSBudW1iZXJzIGJ5IDIuICBBZGQgODIgdG8gdGhvc2UgbnVtYmVycy4KYGBge3J9CnRoaXMgPC0gYygxLDIsMyw0LDUpCnRoaXMqMgp0aGlzKzgyCmBgYAoKQ3JlYXRlIGEgc2Vjb25kIG9iamVjdCB0aGF0IGNvbnRhaW5zIGZpdmUgbnVtYmVycy4gTXVsdGlwbHkgdGhlIHR3byBvYmplY3RzIHRvZ2V0aGVyIGFuZCBzYXZlIHRoZSByZXN1bHQgYXMgYSBuZXcgb2JqZWN0LiBEaXZpZGUgdGhlIHR3byBvYmplY3RzLCBzYXZpbmcgdGhlIHJlc3VsdCBhcyBhIG5ldyBvYmplY3QuCmBgYHtyfQphcmJpdHJhcnkgPC0gYygxOCwxOCw5MywxMDMsIDQ1KQpuZXcgPC0gdGhpcyphcmJpdHJhcnkKbmV3IDwtIHRoaXMvYXJiaXRyYXJ5CmBgYAoKRG9lcyB0aGUgdmVjdG9yIGNvbnRhaW4gdGhlIHdvcmQgInRvbWF0byI/CmBgYHtyfQpjaGFyYWN0ZXJzIDwtIGMoJ3RoaXMnLCAndmVjdG9yJywgJ2NvbnRhaW5zJywgJ3dvcmRzJywgJ3RoYXQnLCAnaGF2ZScsICd3b3JkcycsICd3aXRoJywgJ2xldHRlcnMnLCAnYW5kJywgJ251bWJlcnMnLCAyOSwgJzMwJyApCgondG9tYXRvJyAlaW4lIGNoYXJhY3RlcnMKYGBgCgpIb3cgbWFueSB0aW1lcyBkb2VzIHRoZSB2ZWN0b3IgY29udGFpbiB0aGUgd29yZCAid29yZHMiPwpgYGB7cn0KZ3JlcCgnd29yZHMnLCBjaGFyYWN0ZXJzKQpsZW5ndGgoZ3JlcCgnd29yZHMnLCBjaGFyYWN0ZXJzKSkKYGBgCgpTZWFyY2ggdGhlIHZlY3RvciBmb3IgdGhlIG51bWJlciAyOS4gCmBgYHtyfQpncmVwKCcyOScsIGNoYXJhY3RlcnMpCmBgYAoKU2VhcmNoIHRoZSB2ZWN0b3IgZm9yIHRoZSBudW1iZXIgMTAwLgpgYGB7cn0KZ3JlcCgnMTAwJywgY2hhcmFjdGVycykKCiNpbnRlZ2VyKDApIC0tPiB3YXkgUiBzYXlzIG5vCmBgYAoKSXQgd29ya3MgZGlmZmVyZW50bHkgaWYgdGhlIHdvcmRzIGFyZSBub3Qgc2VwYXJhdGVkIGluIGEgdmVjdG9yOgpgYGB7cn0Kd29yZHMgPC0gYygndGhpcyB2ZWN0b3IgY29udGFpbnMgd29yZHMgdGhhdCBoYXZlIHdvcmRzIHdpdGggbGV0dGVycyBhbmQgbnVtYmVycyAyOSAzMCcpCid0aGlzJyAlaW4lIHdvcmRzCgojRkFMU0UgYmVjYXVzZSB0aGUgd29yZCB0aGlzIGRvZXMgbm90ID0gdGhlIGZpcnN0IHVuaXQgaW4gdmVjdG9yIHdvcmRzIAoKbGVuZ3RoKHdvcmRzKQoKZ3JlcCgndGhpcycsIHdvcmRzKQpncmVwbCgndGhpcycsIHdvcmRzKQoKIyBOb3RpY2UgdGhhdCBncmVwIHBhcnRpYWwgbWF0Y2hlcyBieSBkZWZhdWx0LiBUbyBnZXQgZXhhY3Qgd29yZCwgdXNlIHNwYWNlczsgZ3JlcCB3aWxsIHRlbGwgbWUgYW55d2hlcmUgdnMgJWluJSB3aGljaCBpcyBhbiBleGFjdCBtYXRjaAoKZ3JlcGwoJ2NvbnRhaW4nLCB3b3JkcykKZ3JlcGwoJ2NvbnRhaW4gJywgd29yZHMpCmBgYAoKTm90ZTogWW91IGNhbm5vdCBnaXZlIGEgdmVjdG9yIGEgbnVtYmVyLCBlLmcuLCBpbiBzY29yZXNbMiw0XSwgUiBpcyBsb29raW5nIGZvciB0aGUgc2Vjb25kIHJvdyBhbmQgZm91cnRoIGNvbHVtbjsgd291bGQgbmVlZCB0byB3cml0ZToKYGBge3J9CnNjb3JlcyA8LSBjKEpvaG49MjUsIE1hcmdlPTM0LCBEYW49MjQsIEVtaWx5PTI5KQpzY29yZXNbYygyLDQpXQpgYGAKClJldHVybiBpbmRpdmlkdWFscyB3aXRoIHNjb3JlcyBncmVhdGVyIHRoYW4gMzA6CmBgYHtyfQpzY29yZXNbc2NvcmVzID4gMzBdICAKYGBgCgoKCgoKCgoKCgojIyMjIERBVEEgU1RSVUNUVVJFUyAoY3JlYXRlIGEgbGlzdCwgbWF0cml4LCBkYXRhZnJhbWUsIGlkZW50aWZ5IHZhcmlhYmxlcykKCgpOYW1lIGVhY2ggdmVjdG9yIGluIHRoZSBsaXN0OgpgYGB7cn0KbWFyeV9pbmZvIDwtIGxpc3QoY2xhc3Nlcz1jKCJCaW9sb2d5IiwgIk1hdGgiLCAiTXVzaWMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIlBoeXNpY3MiKSwKICAgICAgICAgICAgICAgICAgZnJpZW5kcz1jKCJKb2huIiwgIkRhbiIsICJFbWlseSIpLAogICAgICAgICAgICAgICAgICBTQVQ9YygxNDUwLDEwMDAsMTYwMCkpCmBgYAoKUmV0dXJuIHRoZSBzZWNvbmQgdmVjdG9yOgpgYGB7cn0KbWFyeV9pbmZvW1syXV0KYGBgCgpSZXR1cm4gdGhlIHZlY3RvciBuYW1lZCAiU0FUIgpgYGB7cn0KbWFyeV9pbmZvJFNBVCAKYGBgCgpSZXR1cm4gdGhlIHNlY29uZCBlbGVtZW50IG9mIGZyaWVuZHMgdmVjdG9yCmBgYHtyfQptYXJ5X2luZm8kZnJpZW5kc1syXQpgYGAKCk1ha2UgYSBsaXN0IHRoYXQgY29udGFpbnMgdGhlIHRocmVlIGRlcGFydG1lbnRzIGF0IEx1c2tpbiBhcyB3ZWxsIGFzIHRoZSBudW1iZXIgb2YgZW5yb2xsZWQgc3R1ZGVudHMgaW4gZWFjaC4gIEFzc3VtZSB0aGUgbnVtYmVycyBhcmUgNjAsIDgwLCBhbmQgMTAwLgpgYGB7cn0KbGlzdDAgPC0gbGlzdChkZXB0cyA9IGMoIlB1YmxpY1BvbGljeSIsICJTb2NpYWxXZWxmYXJlIiwgIlVyYmFuUGxhbm5pbmciKSwgZW5yb2xsZWQgPSBjKDYwIDgwLCAxMDApKQpgYGAKCkZvciB0aGVzZSBuZXh0IHF1ZXN0aW9ucywgdXNlIHRoZSBsaXN0IGNyZWF0ZWQgaW4gdGhlIGJlbG93IGNvZGUuCmBgYHtyfQpsaXN0MSA8LSBsaXN0KG5hbWVzPWMoJ0pvaG4nLCAnS2F0ZScsICdKZXNzaWNhJywgJ0NhcmwnKSwgZ3JhZGVzPWMoODAsODUsNjAsMTAwKSwgc2V4PWMoJ01hbGUnLCAnRmVtYWxlJywgJ0ZlbWFsZScsICdNYWxlJykpCmBgYAoKV2hvIGhhcyBncmFkZXMgZ3JlYXRlciB0aGFuIDgzPwpgYGB7cn0KbGlzdDEkbmFtZXNbbGlzdDEkZ3JhZGVzID4gODNdCmBgYAoKV2hpY2ggcGVvcGxlIGFyZSBmZW1hbGU/CmBgYHtyfQpsaXN0MSRuYW1lc1tsaXN0MSRzZXggPT0gIkZlbWFsZSJdCmBgYAoKQ3JlYXRlIGEgMngzIG1hdHJpeCwgZmlsbGluZyBkb3duIGNvbHVtbnM6CmBgYHtyfQphIDwtIG1hdHJpeCgxOjYsIG5yb3c9MikKYGBgCgpGaWxsIGFjcm9zcyByb3dzOgpgYGB7cn0KYiA8LSBtYXRyaXgoNToxNCwgbnJvdz0yLCBieXJvdz1UUlVFKQpgYGAKClJvdyAyLCBjb2x1bW4gMzoKYGBge3J9CmFbMiwzXQpgYGAKCkFsbCByb3dzLCBjb2x1bW4gMjoKYGBge3J9CmJbLDJdCmBgYAoKQWxsIGNvbHVtbnMsIHJvdyAxOgpgYGB7cn0KYVsxLF0KYGBgCgpPdGhlciB3YXlzIHRvIGNyZWF0ZSBtYXRyaWNlczoKYGBge3J9Cm1hdHJpeChjKDAsMSwxLDEsMCwxLDAsMCwxKSwgbnJvdz0zKQoKbWF0cml4KDA6MSwgbnJvdz0xMCwgbmNvbD0xMCkKYGBgCgpDcmVhdGUgYSBtYXRyaXggb2YgMTAgcm93cyBhbmQgMTAgY29sdW1ucyB3aGVyZSBlYWNoIGVudHJ5IGlzIHRoZSBudW1iZXIgMCBvciAxIChtdWx0aXBsZSBvcHRpb25zKS4KYGBge3J9Cm0xIDwtIG1hdHJpeChyYmlub20oMTAwLCAxLCAwLjUpLCBucm93ID0gMTApCm0gPC0gbWF0cml4KDA6MSwgbnJvdz0xMCwgbmNvbD0xMCkKYGBgCgpTaG93IG1lIHRoZSBmaXJzdCByb3cgb2YgdGhlIG1hdHJpeC4KYGBge3J9Cm0xWzEsIF0KYGBgCgpTaG93IHRoZSBmaXJzdCBzaXggcm93cyBvZiB0aGUgbWF0cml4ICh0d28gb3B0aW9ucykuCmBgYHtyfQpoZWFkKG0xKQptMVsxOjYsIF0KYGBgCgpTaG93IHJvd3MgNCB0aHJvdWdoIDguCmBgYHtyfQptMVs0OjgsIF0KYGBgCgpTaG93IHJvd3MgMywgNSwgNywgYW5kIDkuCmBgYHtyfQptMVtjKDMsIDUsIDcsIDkpLCBdCmBgYAoKU2hvdyB0aGUgdGhpcmQgY29sdW1uIG9mIHRoZSBtYXRyaXguCmBgYHtyfQptMVssIDNdCmBgYAoKU2hvdyB0aGUgdGhpcmQsIGZpZnRoLCBhbmQgc2V2ZW50aCBjb2x1bW5zIG9mIHRoZSBtYXRyaXguCmBgYHtyfQptMVssIGMoMywgNSwgNyldCmBgYAoKQ29udmVydCB0aGUgZ3JhZGVzIGxpc3QgZnJvbSBhYm92ZSBpbnRvIGEgZGF0YSBmcmFtZSAoZm91ciBvcHRpb25zKS4KYGBge3J9CmQxIDwtIGRhdGEuZnJhbWUobGlzdDEpCgphcy5kYXRhLmZyYW1lKGxpc3QxKQoKZDFiIDwtIGRhdGEuZnJhbWUobmFtZXM9YygnSm9obicsICdLYXRlJywgJ0plc3NpY2EnLCAnQ2FybCcpLCBncmFkZXM9Yyg4MCw4NSw2MCwxMDApLCBzZXg9YygnTWFsZScsICdGZW1hbGUnLCAnRmVtYWxlJywgJ01hbGUnKSkKCmRhdGEuZnJhbWUobGlzdDEpCmBgYAoKV2hvIGhhcyBncmFkZXMgZ3JlYXRlciB0aGFuIDkwPwpgYGB7cn0KZDFbZDEkZ3JhZGVzID4gOTAsIF0KYGBgCgpXaGljaCBwZW9wbGUgYXJlIG1hbGU/CmBgYHtyfQpkMVtkMSRzZXggPT0gIk1hbGUiLCBdCmBgYAoKV2hhdCBhcmUgdGhlIGZpcnN0IHNpeCByb3dzIGFuZCBuaW5lIGNvbHVtbnMgaW4gdGhlIFNDQUQgZGF0YT8KYGBge3J9ClNDQURkYXRhWzE6NiwgMTo5XQpgYGAKCldoYXQgYXJlIHRoZSBsYXN0IGZpdmUgcm93cyBpbiB0aGUgU0NBRCBkYXRhICh0d28gb3B0aW9ucyk/CmBgYHtyfQp0YWlsKFNDQURkYXRhLCA1KQpTQ0FEZGF0YVsobnJvdyhTQ0FEZGF0YSktNSk6bnJvdyhTQ0FEZGF0YSksXQpgYGAKClNob3cgcm93cyAxMDAgdG8gMTA3IGluIHRoZSBTQ0FEIGRhdGEuCmBgYHtyfQpTQ0FEZGF0YVsxMDA6MTA3LCBdCmBgYAoKV2hhdCBhcmUgdGhlIG5hbWVzIG9mIHRoZSBjb2x1bW5zIGluIHRoZSBTQ0FEIGRhdGE/CmBgYHtyfQpuYW1lcyhTQ0FEZGF0YSkKYGBgCgpIb3cgbWFueSB0aW1lcyBkb2VzIGVhY2ggY291bnRyeSBhcHBlYXIgaW4gdGhlIGRhdGFzZXQgdXNpbmcgJ3RhYmxlJyBpbiB0aGUgU0NBRCBkYXRhPwpgYGB7cn0KdGFibGUoU0NBRGRhdGEkY291bnRyeW5hbWUpCmBgYAoKSG93IG1hbnkgZXZlbnRzIHN0YXJ0ZWQgaW4gZWFjaCB5ZWFyPwpgYGB7cn0KdGFibGUoU0NBRGRhdGEkc3R5cikKdGFibGUoU0NBRGRhdGEkZXlyKQpgYGAKCldyaXRlIGNvZGUgdG8gc2F2ZSBvbmx5IGV2ZW50cyB0aGF0IHN0YXJ0ZWQgaW4gMjAwNiBhcyBhIG5ldyBvYmplY3QuCmBgYHtyfQpuZXcgPC0gU0NBRGRhdGFbU0NBRGRhdGEkc3R5ciA9PSAyMDA2LCBdCmBgYAoKSG93IG1hbnkgZXZlbnRzIHN0YXJ0ZWQgaW4gMjAwNj8KYGBge3J9Cm5yb3cobmV3KQpgYGAKCk1ha2UgYSB0YWJsZSBzaG93aW5nIHRoZSBudW1iZXIgb2YgZXZlbnRzIHBlciBjb3VudHJ5IHRoYXQgc3RhcnRlZCBpbiAyMDA2LgpgYGB7cn0KdGFibGUobmV3JGNvdW50cnluYW1lKQpgYGAKCkRyb3AgYWxsIGV2ZW50cyB3aGVyZSB0aGUgbnVtYmVyIG9mIHBhcnRpY2lwYW50cyBpcyBgLTk5YC4KYGBge3J9Cm5ldzIgPC0gU0NBRGRhdGFbU0NBRGRhdGEkbnBhcnQgIT0gLTk5LCBdCmBgYAoKQ3JlYXRlIGEgbG9naWNhbCB2ZWN0b3IgYW5kIG51bWVyaWMgdmVjdG9yIG9mIGVxdWFsIGxlbmd0aDoKYGBge3J9Cm15ZGF0YSA8LSBkYXRhLmZyYW1lKGRpYWJldGljID0gYyhUUlVFLCBGQUxTRSwgVFJVRSwgRkFMU0UpLAogICAgICAgICAgICAgICAgICAgICBoZWlnaHQgPSBjKDY1LCA2OSwgNzEsIDczKSwgc2V4PWMoJ01hbGUnLCAnRmVtYWxlJywgJ0ZlbWFsZScsICdNYWxlJyksIG1pbnV0ZXNFeGVyY2lzZSA9IGMoMjAsMzAsMjIsODApKQpgYGAKCklkZW50aWZ5IHJvdyAzLCBjb2x1bW4gMiBoZWlnaHQgb2YgdGhpcmQgbWFsZToKYGBge3J9Cm15ZGF0YVszLDJdCmBgYAoKVXNpbmcgY29sdW1uIG5hbWUsIGlkZW50aWZ5IHRoZSBmaXJzdCB0d28gcm93czoKYGBge3J9Cm15ZGF0YVsxOjIsICJoZWlnaHQiXQpgYGAKCkxpc3QgYWxsIHJvd3Mgb2YgY29sdW1uICJkaWFiZXRpYyI6CmBgYHtyfQpteWRhdGFbLCJkaWFiZXRpYyJdCmBgYAoKU3Vic2V0dGluZyBjcmVhdGVzIGEgbnVtZXJpYyB2ZWN0b3I6CmBgYHtyfQpteWRhdGEkaGVpZ2h0WzI6M10KYGBgCgpOdW1lcmljIHZlY3RvcjoKYGBge3J9Cm15ZGF0YVtbImhlaWdodCJdXQpgYGAKCldoYXQgYXJlIHRoZSBuYW1lcyBvZiBteSB2YXJpYWJsZXM/CmBgYHtyfQpjb2xuYW1lcyhteWRhdGEpCmBgYAoKQXNzaWduIGNvbHVtbiBuYW1lczoKYGBge3J9CmNvbG5hbWVzKG15ZGF0YSkgPC0gYygiRGlhYmV0aWMiLCAiSGVpZ2h0IiwgIlNleCIsICJNaW51dGVzIG9mIEV4ZXJjaXNlIHBlciBXZWVrIikKCiNQcm9mIHJlY3MgYWxwaGFiZXRpemluZwpgYGAKClRvIGNoYW5nZSB0aGUgZmlyc3QgdmFyaWFibGUncyBuYW1lLCBqdXN0IHVzZSBpbmRleGluZzoKYGBge3J9CmNvbG5hbWVzKG15ZGF0YSlbMV0gPC0gIkRpYWJldGVzIgoKI3RvIHZlcmlmeToKY29sbmFtZXMobXlkYXRhKSA9PSAnRGlhYmV0ZXMnCgojSWYgeW91IGRvIG5vdCBub3cgdGhlIGluZGV4IGJ1dCBrbm93IHRoZSBuYW1lLCB5b3UgY2FuIGRvIHRoYXQgdG9vOgpjb2xuYW1lcyhteWRhdGEpW2NvbG5hbWVzKG15ZGF0YSkgPT0gJ0RpYWJldGVzJ10gPC0gJ0RpYWJldGljJyAgCiNeV2hlcmUgdGhlIGNvbHVtbiBuYW1lIGlzICJEaWFiZXRlcyIsIGNoYW5nZSBpdCB0byAiRGlhYmV0aWMiLgpgYGAKCldoYXQgYXJlIHRoZSBkaW1lbnNpb25zIG9mIG15IGRhdGEgZnJhbWU/CmBgYHtyfQpkaW0obXlkYXRhKQpgYGAKCldoYXQgYXJlIHRoZSBmaXJzdCBmaXZlIHJvd3M/CmBgYHtyfQpoZWFkKG15ZGF0YSkKYGBgCgpXaGF0IGFyZSB0aGUgbGFzdCBmaXZlIHJvd3M/CmBgYHtyfQp0YWlsKG15ZGF0YSkKYGBgCgpHZXQgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGRhdGFmcmFtZSwgc3RydWN0dXJlOgpgYGB7cn0Kc3RyKG15ZGF0YSkKYGBgCgpHZXQgc3VtbWFyeSBzdGF0aXN0aWNzOgpgYGB7cn0Kc3VtbWFyeShteWRhdGEpCgpzdW1tYXJ5KG15ZGF0YSRoZWlnaHQpCmBgYAoKR2V0IG51bWJlciBvZiByb3dzOgpgYGB7cn0KbnJvdyhteWRhdGEpCgojRG9uJ3Qgc2VsZWN0IG9uIGNvbCBudW1iZXJzLCB0aGV5IHdvbid0IHN0YXkgdGhlIHNhbWU7IHVzZSBjb2xuYW1lcyhteWRhdGEpW2NvbG5hbWVzKG15ZGF0YSkgPT0gJ0RpYWJldGVzJ10gKGNhbiBhbHNvIHVzZSBncmVwKQpgYGAKCkNyZWF0ZSBhIGRhdGFmcmFtZSB0aGF0IGlzIGZpdmUgcm93cyB0YWxsIGFuZCB0aHJlZSBjb2x1bW5zIHdpZGUuICBUaGUgZmlyc3QgY29sdW1uIGlzIHBlb3BsZSdzIG5hbWVzOiBBbWFuZGEsIEJyYW5kb24sIENhcmwsIERhdmlkLCBhbmQgRWxlYW5vci4gVGhlIHNlY29uZCBjb2x1bW4gaXMgdGhlaXIgYmlydGggeWVhcjogMTk4MSwgMTkyOCwgMTk5NywgMjAwMiwgMTk4OS4gIFRoZSB0aGlyZCBjb2x1bW4gaXMgdGhlaXIgaGVpZ2h0IGluIGNlbnRpbWV0ZXJzOiAyMDAsIDE4MCwgMTc2LCAxOTAsIDIxMC4KCmBgYHtyfQpteWRhdGEgPC0gZGF0YS5mcmFtZShkaWFiZXRpYyA9IGMoVFJVRSwgRkFMU0UsIFRSVUUsIEZBTFNFKSwgCiAgICAgICAgICAgICAgICAgICAgIGhlaWdodCA9IGMoNjUsIDY5LCA3MSwgNzMpLCBzZXg9YygnTWFsZScsICdGZW1hbGUnLCAnRmVtYWxlJywgJ01hbGUnKSwgCiAgICAgICAgICAgICAgICAgICAgIG1pbnV0ZXNFeGVyY2lzZSA9IGMoMjAsMzAsMjIsODApKQoKZDIgPC0gZGF0YS5mcmFtZShuYW1lcz1jKCdBbWFuZGEnLCAnQnJhbmRvbicsICdDYXJsJywgJ0RhdmlkJywgJ0VsZWFub3InKSwgeWVhcj1jKDE5ODEsIDE5MjgsIDE5OTcsIDIwMDIsIDE5ODkpLCBoZWlnaHQgPSBjKDIwMCwxODAsMTc2LDE5MCwyMTApKQpgYGAKClNlbGVjdCByb3dzIHRocmVlIHRocm91Z2ggZml2ZSBvZiB0aGUgZGF0YWZyYW1lLgpgYGB7cn0KZDJbMzo1LF0KYGBgCgpSZW5hbWUgdGhlIG5hbWUgY29sdW1uIHRvICJGaXJzdF9OYW1lIi4gIFJlbmFtZSB0aGUgYmlydGh5ZWFyIGNvbHVtbiB0byAiWWVhciIuCmBgYHtyfQpjb2xuYW1lcyhkMilbY29sbmFtZXMoZDIpPT0nbmFtZXMnXSA8LSAnRmlyc3RfTmFtZScKY29sbmFtZXMoZDIpW2NvbG5hbWVzKGQyKT09J3llYXInXSA8LSAnWWVhcicKYGBgCgpDcmVhdGUgYSBuZXcgZGF0YWZyYW1lIG9mIG9ubHkgdGhlIGluZGl2aWR1YWxzIHdobyBhcmUgYXQgbGVhc3QgMjAwIGNlbnRpbWV0ZXJzIHRhbGwuCmBgYHtyfQpkdGFsbCA8LSBkMltkMiRoZWlnaHQgPiAyMDAsXQpgYGAKCkNyZWF0ZSBhIGZvdXIgcm93LCBmb3VyIGNvbHVtbiBtYXRyaXguICBNdWx0aXBsZSB0aGF0IG1hdHJpeCBieSAzLgpgYGB7cn0KbSA8LSBtYXRyaXgoMTozLCBucm93PTQsIG5jb2w9NCkKbTIgPC0gbWF0cml4KDE6MTYsIG5yb3c9NCkKCm0yKjMKYGBgCgpGcm9tIHRoYXQgbWF0cml4LCB0YWtlIHRoZSBzdW0gb2YgdGhlIGZpcnN0IGNvbHVtbi4gIFRha2UgdGhlIHN1bSBvZiB0aGUgdGhpcmQgcm93LiAKYGBge3J9CnN1bShtMlssMV0pCm0yWywxXQp0ZW1wIDwtIG0yWywxXQpzdW0odGVtcCkKCnN1bShtMlszLF0pCmBgYAoKSG93IG1hbnkgY29sdW1ucz8KbmNvbChkYXRhKQoKSG93IG1hbnkgcm93cz8KbnJvdyhkYXRhKQoKV2hhdCBhcmUgdGhlIGNvbHVtbiBuYW1lcz8KbmFtZXMoZGF0YSkgIAoKV2hhdCBhcmUgdGhlIHJvdyBuYW1lcz8Kcm93bmFtZXMoZGF0YSkKCldoYXQgYXJlIHRoZSBmaXJzdCA2IHJvd3M/CmhlYWQoZGF0YSkKCldoYXQgYXJlIHRoZSBsYXN0IDYgcm93cz8KdGFpbChkYXRhKQoKTm90ZSB0aGF0IHlvdSBjYW4gdGVsbCBoZWFkKCkgYW5kIHRhaWwoKSBob3cgbWFueSByb3dzIHlvdSB3YW50IHRvIHNlZS4gIDUgaXMgdGhlIGRlZmF1bHQuCmhlYWQoZGF0YSwgMTApCmhlYWQoZGF0YSwgMikKCnRhaWwoZGF0YSwgOCkKdGFpbChkYXRhLCAyKQoKSWYgeW91IHdhbnQgdG8ga25vdyB0aGUgc2V0IG9mIHZhbHVlcyBhIHZhcmlhYmxlIHRha2VzLCB1c2UgdW5pcXVlKCkKdW5pcXVlKGRhdGEkQ09VTlRSWSkKdW5pcXVlKGRhdGEkQllFQVIpCgpJZiB5b3Ugd2FudCB0byBnZXQgYSBzZW5zZSBvZiBob3cgbWFueSBvYnNlcnZhdGlvbnMgdGhlcmUgYXJlIGZvciBlYWNoIHZhbHVlIG9mIGEgdmFyaWFibGUsIHVzZSB0YWJsZSgpCnRhYmxlKGRhdGEkQ09VTlRSWSkKdGFibGUoZGF0YSRCWUVBUikKCkV4cGxvcmUgaG93IHRvIGFjY2VzcyBkaWZmZXJlbnQgZGF0YSBwb2ludHMsIGJhc2VkIG9uIHZhcmlhYmxlIHZhbHVlcy4gIFdlIHdpbGwgdGhlbiBtb2RpZnkgc29tZSBvZiB0aGVzZSB2YXJpYWJsZXMgYW5kIHNhdmUgdGhlIHJlc3VsdCB0byBhIG5ldyBmaWxlLgpgYGB7cn0KIyBTZWxlY3QgYnkgeWVhci4gIAp0ZW1wIDwtIGRhdGFbZGF0YSRCWUVBUiA9PSAnMjAxMCcsXSAgCiMgVGhlIGV2ZW50cyBmcm9tIDIwMTAgYXJlIG5vdyBpbiB0aGlzIGRhdGFmcmFtZQpkaW0odGVtcCkKbnJvdyh0ZW1wKSAtIG5yb3coZGF0YSkKCnRlbXAgPC0gZGF0YVtkYXRhJEJZRUFSID09ICcyMDExJyxdICAKIyBOb3csIHRoZSAidGVtcCIgZGF0YWZyYW1lIGlzIGZvciAyMDExLgoKdGVtcCA8LSBkYXRhW2RhdGEkQllFQVIgPCAyMDEwLF0gIAp0ZW1wMiA8LSBkYXRhW2RhdGEkQllFQVIgPD0gMjAxMCxdCgpub2RlYXRocyA8LSBkYXRhW2RhdGEkTkRFQVRIID09IDAsXQpqYW51YXJ5IDwtIGRhdGFbZGF0YSRCTU9OVEggPT0gMSxdCm5vdGphbnVhcnkgPC0gZGF0YVtkYXRhJEJNT05USCAhPSAxLF0gICMgIT0gbWVhbnMgIm5vdCBlcXVhbCB0byIuCm5vdGphbnVhcnkyIDwtIGRhdGFbZGF0YSRCTU9OVEggPiAxLF0KYGBgCgpNYW5pcHVsYXRlIHZhcmlhYmxlcyBhbmQgdGhlbiBzYXZlIHRoZSBkYXRhZnJhbWUuIFJlbWVtYmVyLCBlYWNoIGNvbHVtbiBpcyBqdXN0IGEgdmVjdG9yLCBzbyB0aGUgdmVjdG9yIG9wZXJhdGlvbnMgd2UgbGVhcm5lZCBlYXJsaWVyIGFyZSB3aGF0IHdlIHdpbGwgZG8gaGVyZS4gIE5vdGUgdGhhdCBJIGRvIHNvbWUgdHJhbnNmb3JtYXRpb25zLCBsaWtlIG11bHRpcGxlIGBCREFZYCBieSBgQk1PTlRIYCwganVzdCB0byBkZW1vbnN0cmF0ZSBjYXBhYmlsaXRpZXMuCmBgYHtyfQpkYXRhJG5ld25wYXJ0IDwtIGRhdGEkTlBBUlQqMTAKZGF0YSRuZXducGFydDIgPC0gaWZlbHNlKGRhdGEkTlBBUlQgIT0gOTksIGRhdGEkTlBBUlQsIE5BKQpkYXRhJG5wYXJ0IDwtIGRhdGEkTlBBUlQvMTAwMCAgCm5hbWVzKGRhdGEpICAjIE5vdGljZSB0aGF0IHRoZSBhYm92ZSBsaW5lIGNyZWF0ZWQgYSBuZXcgdmFyaWFibGUuCgpkYXRhJE5QQVJUIDwtIGRhdGEkTlBBUlQvMTAwMCAgCiMgQ3JlYXRpbmcgYSBuZXcgdmFyaWFibGUgd2l0aCB0aGUgc2FtZSBuYW1lIGFzIGFuIGV4aXN0aW5nIG9uZSByZXBsYWNlcyB0aGF0IHZhcmlhYmxlCgpkYXRhJGRlYXRoUmF0ZSA8LSBkYXRhJE5ERUFUSC9kYXRhJE5QQVJUICAjIFdoYXQgZG9lcyB0aGlzIGRvPyAgCnN1bW1hcnkoZGF0YSRkZWF0aFJhdGUpICAjIEl0IGRpZCBub3RoaW5nIGJlY2F1c2UgTkRFQVRIIGlzIHdlaXJkbHkgY29uc3RydWN0ZWQuICAKIyBXZSB3aWxsIG5vdCBkaXNjdXNzIGhlcmUgaG93IHRvIGZpeCBpdC4KCmRhdGEkbm9uc2Vuc2UgPC0gZGF0YSRCREFZKmRhdGEkQk1PTlRICmRhdGEkQ09VTlRSWVtkYXRhJENPVU5UUlkgPT0gJ0NvdGUgZFwnSXZvaXJlJ10gPC0gJ0l2b3J5IENvYXN0JyAgCiMgRmFpbHMgYmVjYXVzZSBSIHRyZWF0cyBjb3VudHJ5IG5hbWUgYXMgYSBmYWN0b3IuICAKCmBgYAoKTG9hZCB0aGUgZGF0YWZyYW1lIGZyb20gZWFybGllci4gIEFkZCB0aGUgYXJndW1lbnQgYHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UnLgpgYGB7cn0KZGF0YSA8LSByZWFkLmNzdignfi9Eb2N1bWVudHMvVUNMQS9EYXRhL1BSSU9fVXJiYW5Tb2NpYWxEaXNvcmRlci9ldmVudHMuY3N2Jywgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQpkYXRhJENPVU5UUllbZGF0YSRDT1VOVFJZID09ICdDb3RlIGRcJ0l2b2lyZSddIDwtICdJdm9yeSBDb2FzdCcgICAKYGBgCgpIb3cgY291bGQgeW91IHZlcmlmeSB0aGF0IHRoZSBjaGFuZ2UgaGFwcGVuZWQ/ICAKYGBge3J9CiMgU2F2ZSB0aGUgZmlsZS4gTWFrZSBzdXJlIHRvIGNoYW5nZSB0aGUgZmlsZSBwYXRoIGZvciB5b3VyIGNvbXB1dGVyLgp3cml0ZS5jc3YoZGF0YSwgJ34vRG9jdW1lbnRzL1VDTEEvRGF0YS9QUklPX1VyYmFuU29jaWFsRGlzb3JkZXIvZXZlbnRzX3YzLmNzdicpCgp3cml0ZS50YWJsZShkYXRhLCAnfi9Eb2N1bWVudHMvVUNMQS9EYXRhL1BSSU9fVXJiYW5Tb2NpYWxEaXNvcmRlci9ldmVudHNfdjMudHh0Jywgc2VwPSdcdCcpIApgYGAKCldoYXQgYXJlIHRoZSBmaXJzdCBmaXZlIHJvd3M/IApgYGB7cn0KaGVhZChtdGNhcnMsIDUpCm10Y2Fyc1sxOjUsXQpgYGAKCldoYXQgYXJlIHRoZSBsYXN0IGZpdmUgcm93cz8KYGBge3J9CnRhaWwobXRjYXJzLCA1KQpgYGAKCldoYXQgYXJlIHJvd3MgMTIgdGhyb3VnaCAyMT8KYGBge3J9Cm10Y2Fyc1sxMjoyMSxdCmBgYAoKV2hhdCBhcmUgdGhlIGNvbHVtbiBuYW1lcz8KYGBge3J9Cm5hbWVzKG10Y2FycykKc29ydChuYW1lcyhtdGNhcnMpKQpgYGAKClVzaW5nIG10Y2FyczogY3JlYXRlIGEgbmV3IHZhcmlhYmxlIHRoYXQgaXMgaG9yc2Vwb3dlciBwZXIgY3lsaW5kZXIuCmBgYHtyfQptdGNhcnMkaHBjIDwtIG10Y2FycyRocC9tdGNhcnMkY3lsCmBgYAoKVXNpbmcgbXRjYXJzOiBXZWlnaHQgaXMgaW4gdGhvdXNhbmRzIG9mIHBvdW5kcy4gQ3JlYXRlIGEgbmV3IHZhcmlhYmxlIHRoYXQgaXMgd2VpZ2h0IGluIHBvdW5kcy4gCmBgYHtyfQptdGNhcnMkd3RfbmV3IDwtIG10Y2FycyR3dCoxMDAwCmBgYAoKVXNpbmcgbXRjYXJzOiBDcmVhdGUgYSBuZXcgZGF0YWZyYW1lIG9mIGNhcnMgdGhhdCBnZXQgYXQgbGVhc3QgMjAgbWlsZXMgcGVyIGdhbGxvbi4gIEhvdyBtYW55IGNhcnMgaXMgdGhhdD8KYGBge3J9Cm5ld19tdGNhcnMgPC0gbXRjYXJzW210Y2FycyRtcGcgPj0gMjAsXQpgYGAKClVzaW5nIG10Y2FyczogQ3JlYXRlIGEgbmV3IGRhdGFmcmFtZSBvZiBjYXJzIHRoYXQgZ2V0IGZld2VyIHRoYW4gMjAgbWlsZXMgcGVyIGdhbGxvbi4KYGBge3J9Cm5ld19tdGNhcnMyIDwtIG10Y2Fyc1ttdGNhcnMkbXBnIDwgMjAsXQpgYGAKCgoKCgoKCgoKCgoKCiMjIyMgUExPVFMgKGhpc3RvZ3JhbXMsIHBsb3RzLCBzYXZlIHBkZikKCk1ha2UgYSBwbG90IG9mIHRoZSBudW1iZXIgb2YgcGFydGljaXBhbnRzIGF0IGVhY2ggZXZlbnQgdXNpbmcgdGhlIFNDQUQgZGF0YS4gTGFiZWwgdGhlIHggYW5kIHkgYXhpcy4KYGBge3J9CnBsb3QoU0NBRGRhdGEkbnBhcnRbU0NBRGRhdGEkbnBhcnQgIT0gLTk5XSwgeGxhYiA9ICJFdmVudCBJbmRleCIsIHlsYWIgPSAiTnVtYmVyIG9mIFBhcnRpY2lwYW50cyIpCmBgYAoKU2F2ZSB0aGF0IHBsb3QKYGBge3J9CnBkZigifi9EZXNrdG9wL1VDTEEvQ291cnNlcy80X0ZhbGwgMjAxOS9QUCAyOTAvQXNzaWdubWVudHMvYXNzbjFwbG90MS5wZGYiKQpwbG90KFNDQURkYXRhJG5wYXJ0W1NDQURkYXRhJG5wYXJ0ICE9IC05OV0sIHhsYWIgPSAiRXZlbnQgSW5kZXgiLCB5bGFiID0gIk51bWJlciBvZiBQYXJ0aWNpcGFudHMiKSBkZXYub2ZmKCkKYGBgCgpNYWtlIGEgaGlzdG9ncmFtIG9mIHRoZSBudW1iZXIgb2YgcGFydGljaXBhbnRzIGF0IGVhY2ggZXZlbnQuIE1ha2Ugc3VyZSB0byBsYWJlbCB0aGUgYXhlcy4KYGBge3J9Cmhpc3QoU0NBRGRhdGEkbnBhcnRbU0NBRGRhdGEkbnBhcnQgIT0gLTk5XSwgeGxhYiA9ICJOdW1iZXIgb2YgUGFydGljaXBhbnRzIiwgbWFpbiA9ICJIaXN0b2dyYW0gb2YgUGFydGljaXBhbnRzIiwgeWxhYiA9ICJQcm9iYWJpbGl0eSIsIGZyZXEgPSBGQUxTRSkKYGBgCgpNYWtlIGEgYmFycGxvdCBvZiB0aGUgbnVtYmVyIG9mIHBhcnRpY2lwYW50cyBwZXIgZXZlbnQuICBIaW50OiB5b3Ugd2lsbCBuZWVkIHRvIHVzZSBgdGFibGVgIGFzIHdlbGwuCmBgYHtyfQpiYXJwbG90KHRhYmxlKFNDQURkYXRhJG5wYXJ0KSwgeGxhYiA9ICJOdW1iZXIgb2YgUGFydGljaXBhbnRzIiwgeWxhYiA9ICJGcmVxdWVuY3kiKQpgYGAKCkxvYWQgZGF0YSwgZXhwbG9yZSBpdC4KYGBge3J9CmQgPC0gcmVhZC5jc3YoImh0dHBzOi8vc3RhdHMuaWRyZS51Y2xhLmVkdS9zdGF0L2RhdGEvaHNicmF3LmNzdiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKZFsxOjEwLF0gIwoKbWVhbihkJHJlYWQpCm1lZGlhbihkJHJlYWQpCnZhcihkJHJlYWQpCnN1bW1hcnkoZCRyZWFkKQoKIyB0YWJsZSgpIHByb2R1Y2VzIGNvdW50cwp0YWJsZShkJGZlbWFsZSkKdGFibGUoZCRzZXMpCgojIEZvciBwcm9wb3J0aW9ucywgdXNlIG91dHB1dCBvZiB0YWJsZSgpIGFzIGlucHV0IHRvIHByb3AudGFibGUoKQpwcm9wLnRhYmxlKHRhYmxlKGQkZmVtYWxlKSkKcHJvcC50YWJsZSh0YWJsZShkJHNlcykpCgojIFlvdSBjb3VsZCBkbyB0aGlzIHVzaW5nIG9iamVjdHMKdDEgPC0gdGFibGUoZCRmZW1hbGUpCnByb3AudGFibGUodDEpCgojIFR3by13YXkgdGFibGVzCnQxIDwtIHRhYmxlKGQkZmVtYWxlLCBkJHNlcykKdDEKcHJvcC50YWJsZSh0MSkgICMgUGVyY2VudGFnZXMgYnkgY2VsbApwcm9wLnRhYmxlKHQxLCBtYXJnaW49MikgICMgUGVyY2VudGFnZXMgYnkgY29sdW1uCnByb3AudGFibGUodDEsIG1hcmdpbj0xKSAgIyBQZXJjZW50YWdlcyBieSByb3cKYGBgCgpOb3cgcGxvdCBpdDoKYGBge3J9CnBsb3QoZCRyZWFkKSAgIyBFdy4gIEJ5IGRlZmF1bHQsIFIgdXNlcyBvcGVuIGNpcmNsZXMuICAKcGxvdChkJHJlYWQsIHR5cGU9J2wnKSAgIyBUaGUgeC1heGlzIGlzIGp1c3QgdGhlIHJvdyBpbmRleC4KcGxvdChkJHJlYWQsIGQkd3JpdGUsIHR5cGU9J2wnKSAgIyBUaGlzIGxvb2tzIHdlaXJkIGJlY2F1c2UgUiBpcyB0cnlpbmcgdG8gZHJhdyBsaW5lcyAKIyBiZXR3ZWVuIHRoZSBwb2ludHMgaW4gZWFjaCByb3cuCnBsb3QoZCRyZWFkLCBkJHdyaXRlKSAgCnBsb3QoZCRyZWFkLCBkJHdyaXRlLCBwY2g9MjApICAjIEkgZmluZCB0aGUgb3BlbiBjaXJjbGVzIHVuYXBwZWFsaW5nLgoKIyBUaGUgYHBjaGAgYXJndW1lbnQgbGV0cyB5b3UgY2hhbmdlIHRoZSBzdHlsZS4KcGxvdChkJHJlYWQsIGQkd3JpdGUsIHBjaD0xNiwgeGxhYj0nUmVhZGluZyBTY29yZScsIHlsYWI9J1dyaXRpbmcgU2NvcmUnLCBtYWluPSdDb3JyZWxhdGlvbiBvZiBSZWFkaW5nIGFuZCBXcml0aW5nJykKcGxvdChhcy5mYWN0b3IoZCRmZW1hbGUpLCBkJHdyaXRlKSAgCgpoaXN0KGQkcmVhZCwgeGxhYj0nUmVhZGluZyBTY29yZScsIG1haW49JycpICAKYmFycGxvdCh0YWJsZShkJGZlbWFsZSkpICAjIEJhciBjaGFydApiYXJwbG90KHRhYmxlKGRhdGEkQllFQVIpKQojIFNhdmluZy4gIERvIG5vdCBmb3JnZXQgdG8gY2hhbmdlIHRoZSBwYXRoIHRvIHJlZmxlY3QgeW91ciBjb21wdXRlci4KYGBgCgpVc2luZyBtY2FyczogTWFrZSBhIHRhYmxlIG9mIHRoZSBnZWFyIHZhcmlhYmxlLgpgYGB7cn0KdGFibGUobXRjYXJzJGdlYXIpCmBgYAoKVXNpbmcgbWNhcnM6IE1ha2UgYSBwcm9wb3J0aW9uIHRhYmxlIG9mIHRoZSBnZWFyIHZhcmlhYmxlLgpgYGB7cn0KcHJvcC50YWJsZSh0YWJsZShtdGNhcnMkZ2VhcikpCmBgYAoKVXNpbmcgbWNhcnM6IE1ha2UgYSB0d28td2F5IHRhYmxlIG9mIHRoZSBudW1iZXIgb2YgY3lsaW5kZXJzIGFuZCBudW1iZXIgb2YgZ2VhcnMuCmBgYHtyfQp0YWJsZShtdGNhcnMkZ2VhciwgbXRjYXJzJGN5bCkKYGBgCgpVc2luZyBtY2FyczogTWFrZSBhIHR3by13YXkgcHJvcG9ydGlvbiB0YWJsZSBvZiB0aGUgbnVtYmVyIG9mIGN5bGluZGVycyBhbmQgbnVtYmVyIG9mIGdlYXJzLiBNYWtlIG9uZSB0YWJsZSB3aGVyZSB0aGUgY2VsbHMgYWRkIHRvIDEsIGFub3RoZXIgd2hlcmUgZWFjaCBjb2x1bW4gYWRkcyB0byAxLCBhbmQgYW5vdGhlciB3aGVyZSBlYWNoIHJvdyBkb2VzLgpgYGB7cn0KcHJvcC50YWJsZSh0YWJsZShtdGNhcnMkZ2VhciwgbXRjYXJzJGN5bCkpCnByb3AudGFibGUodGFibGUobXRjYXJzJGdlYXIsIG10Y2FycyRjeWwpLCBtYXJnaW49MikKcHJvcC50YWJsZSh0YWJsZShtdGNhcnMkZ2VhciwgbXRjYXJzJGN5bCksIG1hcmdpbj0xKQpgYGAKClVzaW5nIG1jYXJzOiBQbG90IHRoZSBtaWxlcyBwZXIgZ2FsbG9uIGFnYWluc3QgdGhlIG51bWJlciBvZiBjeWxpbmRlcnMuIApgYGB7cn0KcGxvdChtdGNhcnMkY3lsLCBtdGNhcnMkbXBnKQpwbG90KGFzLmZhY3RvcihtdGNhcnMkY3lsKSwgbXRjYXJzJG1wZykgI2JveCBhbmQgd2hpc2tlcnMKYGBgCgpVc2luZyBtY2FyczogTWFrZSBhIGJhcnBsb3Qgb2YgdGhlIGNhcnMgYnkgdGhlIGNhcmIgdmFyaWFibGUuCmBgYHtyfQpiYXJwbG90KHRhYmxlKG10Y2FycyRjYXJiKSkKYGBgCgpVc2luZyBtY2FyczogTWFrZSBhIGhpc3RvZ3JhbSBvZiBtaWxlcyBwZXIgZ2FsbG9uLgpgYGB7cn0KaGlzdChtdGNhcnMkbXBnKQpgYGAKCiNOb24tTmV0d29yayBQbG90cwpgYGB7cn0KYXR0YWNoKG10Y2FycykgICMgVXNlIHRoZSBtdGNhcnMgZGF0YXNldAoKbmFtZXMobXRjYXJzKSAgIyBUaGUgdmFyaWFibGVzCmRpbShtdGNhcnMpICMgUm93cyBhbmQgY29sdW1ucwptdGNhcnNbMTo3LF0gIyBUaGUgZmlyc3Qgc2V2ZW4gcm93cwoKc3VtbWFyeShtdGNhcnMpICMgU3VtbWFyeSBzdGF0aXN0aWNzIG9mIHRoZSB2YXJpYWJsZXMKCiMgV2UgbWF5IHdhbnQgdGhlIGZ1bGwgY2FyIG5hbWUgbGF0ZXIKbXRjYXJzJGNhciA8LSByb3duYW1lcyhtdGNhcnMpICAKCiMgV2UgbWF5IHdhbnQgdGhlIGNhciBicmFuZAptdGNhcnMkYnJhbmQgPC0gc2FwcGx5KG10Y2FycyRjYXIsIGZ1bmN0aW9uKHgpIHN0cnNwbGl0KHgsIHNwbGl0PScgJylbWzFdXVsxXSkgCgojV2hhdCBkb2VzIHRoZSBsYXN0IGxpbmUgb2YgdGhlIGFib3ZlIGNvZGUgY2h1bmsgZG8/ICBJdCB0YWtlcyB0aGUgYG10Y2FycyRjYXJgIHZlY3RvciBhbmQgc3BsaXRzIGVhY2ggb2JzZXJ2YXRpb24gdXNpbmcgYHN0cnNwbGl0YC4gYHN0cnNwbGl0YCByZXR1cm5zIGEgbGlzdCBvZiBsaXN0cywgd2hlcmUgZWFjaCBlbnRyeSBpcyB0aGUgbnVtYmVyIG9mIHdvcmRzIGluIHRoZSBjYXIgdmFyaWFibGUuICBgW1sxXV1gIGFjY2Vzc2VzIHRoZSBsaXN0LCBhbmQgYFsxXWAgcmV0dXJucyB0aGUgZmlyc3QgdmFsdWUgaW4gdGhhdCBsaXN0LiAgVGhlIGZpcnN0IHZhbHVlIGlzIGFsd2F5cyB0aGUgY2FyIGJyYW5kLCB3aGljaCBJIG5vdGljZWQganVzdCBmcm9tIHZpc3VhbGx5IGluc3BlY3RpbmcgdGhlIGRhdGEuICBgc2FwcGx5YCB0aGVuIHBlcmZvcm1zIHRoYXQgb3BlcmF0aW9uIG9uIGVhY2ggZWxlbWVudCBvZiBgbXRjYXJzJGNhcmA7IGl0IGhhcyB0aGUgZnVuY3Rpb25hbGl0eSBvZiBhIGxvb3AsIGluIG9uZSBsaW5lLgpgYGAKCkJhc2UgUGxvdHRpbmcKYGBge3J9CnBsb3QobXRjYXJzJGhwLCBtdGNhcnMkbXBnLCBwY2g9MjAsIHhsYWI9J0hvcnNlcG93ZXInLCB5bGFiPSdNaWxlcyBwZXIgR2FsbG9uJykKCnBsb3QobXRjYXJzJGhwLCBtdGNhcnMkcXNlYywgcGNoPTE2LCB4bGFiPSdIb3JzZXBvd2VyJywgeWxhYj0nUXVhcnRlciBNaWxlIFNwZWVkJykKCiMgUmVtZW1iZXIsIHdlIGNhbiBzYXZlIGEgcGxvdCBpbiB0aGUgZm9sbG93aW5nIHdheS4KcGRmKCdXZWVrNV9ob3JzZXBvd2VyTVBHLnBkZicpCnBsb3QobXRjYXJzJGRpc3AsIG10Y2FycyRtcGcsIHBjaD0xMCwgeGxhYj0nRW5naW5lIFNpemUnLCB5bGFiPSdNaWxlcyBwZXIgR2FsbG9uJykKZGV2Lm9mZigpCmBgYAoKQmFzZSBQbG90dGluZywgd2l0aCBNdWx0aXBsZSBWYXJpYWJsZXM6IEFzIHdlIGxlYXJuZWQgaW4gbGVjdHVyZSwgYSB0d28tZGltZW5zaW9uYWwgcGxvdCBpcyBvZnRlbiB0b28gc2ltcGxpc3RpYyBmb3IgdGhlIHJlbGF0aW9uc2hpcHMgd2Ugd2FudCB0byBpbnNwZWN0LiAgV2Ugd2lsbCBub3cgbGVhcm4gaG93IHRvIGNoYW5nZSB0aGUgc2l6ZSwgc2hhcGUsIGFuZCBjb2xvciBvZiBwb2ludHMuCmBgYHtyfQojIENoYW5nZSB0aGUgc2l6ZSB3aXRoIHRoZSBjZXggYXJndW1lbnQKcGxvdChtdGNhcnMkaHAsIG10Y2FycyRtcGcsIHBjaD0yMCwgeGxhYj0nSG9yc2Vwb3dlcicsIHlsYWI9J01pbGVzIHBlciBHYWxsb24nLCBjZXg9bXRjYXJzJGRpc3ApCgojV2h5IGRvZXMgdGhhdCBjb2RlIGNyZWF0ZSBhIGJsYWNrIHBsb3Q/ICBCZWNhdXNlIGBjZXhgIG11bHRpcGxpZXMgdGhlIGRlZmF1bHQgc2l6ZSBvZiB0aGUgcG9pbnQgYnkgdGhlIGFyZ3VtZW50IHBhc3NlZCB0byBpdC4gIChgY2V4YCBzdGFuZHMgZm9yIGBgY2hhcmFjdGVyIGV4cGFuc2lvbicnKSAgU2luY2UgYG10Y2FycyRkaXNwIGhhcyB2ZXJ5IGxhcmdlIHZhbHVlcywgYFJgIGlzIHNob3dpbmcgdXMgdmVyeSBsYXJnZSBkb3RzOyB0aGV5IGFyZSBzbyBsYXJnZSwgaW4gZmFjdCwgdGhhdCBubyB3aGl0ZSBzcGFjZSByZW1haW5zLiAgCgojVGhlIGNvZGUgYmVsb3cgZml4ZXMgdGhhdCBpc3N1ZS4gIEhvdyB0byBzaXplIHBvaW50cyBpcyBtb3JlIGFydCB0aGFuIHNpemUuICBCZWNhdXNlIHlvdSBkbyBub3Qgd2FudCB0aGUgYGNleGAgbnVtYmVycyB0byBiZSB0b28gbGFyZ2UsIGl0IGlzIGNvbW1vbiB0byB0YWtlIHRoZSBzcXVhcmUgcm9vdCBvciBsb2dhcml0aG0uICBIZXJlLCBzcXVhcmUgcm9vdHMgd2lsbCBzdGlsbCBjcmVhdGUgZG90cyB0aGF0IGFyZSB0b28gbGFyZ2UsIHNvIEkgZGl2aWRlIGJ5IDEwMCBhcyB3ZWxsIGFzIHRha2UgdGhlIGxvZ2FyaXRobS4KYGBgCgpDaGFuZ2UgdGhlIHNpemUgd2l0aCB0aGUgY2V4IGFyZ3VtZW50CmBgYHtyfQpwbG90KG10Y2FycyRocCwgbXRjYXJzJG1wZywgcGNoPTIwLCB4bGFiPSdIb3JzZXBvd2VyJywgeWxhYj0nTWlsZXMgcGVyIEdhbGxvbicsIGNleD1tdGNhcnMkZGlzcC8xMDApCmxlZ2VuZCgndG9wcmlnaHQnLCBsZWdlbmQ9J1NpemVkIGJ5IGRpc3BsYWNlbWVudCcpCmBgYAoKQ2hhbmdlIHRoZSBzaXplIHdpdGggdGhlIGNleCBhcmd1bWVudApgYGB7cn0KcGxvdChtdGNhcnMkaHAsIG10Y2FycyRtcGcsIHBjaD0yMCwgeGxhYj0nSG9yc2Vwb3dlcicsIHlsYWI9J01pbGVzIHBlciBHYWxsb24nLCBjZXg9bG9nKG10Y2FycyRkaXNwLCBiYXNlPTEwKSkKbGVnZW5kKCd0b3ByaWdodCcsIGxlZ2VuZD0nU2l6ZWQgYnkgZGlzcGxhY2VtZW50JykKYGBgCgoqKldoeSB3b3VsZCBhIHNxdWFyZSByb290IHJlc3VsdCBpbiBkb3RzIHRoYXQgYXJlIHRvbyBsYXJnZT8qKiBtdGNhcnMgaXMgdmVyeSBsYXJnZSEgQmVjYXVzZSB5b3UgZG8gbm90IHdhbnQgdGhlIGBjZXhgIG51bWJlcnMgdG8gYmUgdG9vIGxhcmdlLCBpdCBpcyBjb21tb24gdG8gdGFrZSB0aGUgc3F1YXJlIHJvb3Qgb3IgbG9nYXJpdGhtLiAgSGVyZSwgc3F1YXJlIHJvb3RzIHdpbGwgc3RpbGwgY3JlYXRlIGRvdHMgdGhhdCBhcmUgdG9vIGxhcmdlLCBzbyBJIGRpdmlkZSBieSAxMDAgYXMgd2VsbCBhcyB0YWtlIHRoZSBsb2dhcml0aG0uCgoqKldoYXQgZG9lcyBzaXppbmcgdGhlIGRvdHMgYnkgZGlzcGxhY2VtZW50IHJldmVhbCBhYm91dCB0aGUgcmVsYXRpb25zaGlwIG9mIGRpc3BsYWNlbWVudCB3aXRoIGhvcnNlcG93ZXI/ICBXaGF0IGFib3V0IHdpdGggbWlsZXMgcGVyIGdhbGxvbj8qKiBkZWNyZWFzZWQgaG9yc2Vwb3dlciBtYXkgYmUgYXNzb2NpYXRlZCB3aXRoIGluY3JlYXNlZCBtaWxlcyBwZXIgZ2FsbG9uLgoKTm93LCBsZXQgdXMgY2hhbmdlIHRoZSBzaGFwZSBvZiBwb2ludHMuICBUaGUga2V5IGlzIHRvIHVzZSB0aGUgYHBjaGAgYXJndW1lbnQsIHdoaWNoIHN0YW5kcyBmb3IgInBvaW50IGNoYXJhY3RlciIuICBJZiB5b3UgbG9vayBhdCB0aGUgaGVscCBkb2N1bWVudGF0aW9uIC0gYD9wYXJgLCB0aGVuIHNlYXJjaCBmb3IgYHBjaGAgLSB5b3Ugd2lsbCBzZWUgdGhlIHZhcmlvdXMgc2hhcGVzIGJhc2UgUiBoYXMuICBUaGUgY29kZSBiZWxvdyBmaXJzdCBzaG93cyB5b3UgaG93IHRvIGNoYW5nZSB0aGUgc2hhcGUgb2YgZWFjaCBlbnRyeSwgYW5kIGl0IHRoZW4gc2hvd3MgeW91IGhvdyB0byBjcmVhdGUgYSB2YXJpYWJsZSBlbnVtZXJhdGluZyB0aGUgc2hhcGUgYnkgc29tZSBvdGhlciB2YXJpYWJsZS4KCkNoYW5nZSB0aGUgc2hhcGUgd2l0aCB0aGUgcGNoIGFyZ3VtZW50CmBgYHtyfQpwbG90KG10Y2FycyRocCwgbXRjYXJzJG1wZywgeGxhYj0nSG9yc2Vwb3dlcicsIHlsYWI9J01pbGVzIHBlciBHYWxsb24nLCBwY2g9YygxLDIpKQpgYGAKCioqV2h5IGFyZSBzb21lIGRvdHMgY2lyY2xlcyBidXQgb3RoZXJzIHRyaWFuZ2xlcz8qKiB0aGUgMSBhbmQgMiBpbiB0aGUgcGNoIGxpbmUKCkNoYW5nZSB0aGUgc2hhcGUgd2l0aCB0aGUgcGNoIGFyZ3VtZW50CmBgYHtyfQpwbG90KG10Y2FycyRocCwgbXRjYXJzJG1wZywgeGxhYj0nSG9yc2Vwb3dlcicsIHlsYWI9J01pbGVzIHBlciBHYWxsb24nLCBwY2g9bXRjYXJzJGFtKQpgYGAKClRoaXMgdmFyaWFibGUgaXMgY29udmVuaWVudCBiZWNhdXNlIGl0IGlzIGFscmVhZHkgY29kZWQgYXMgYSBudW1iZXIKYGBge3J9CnN1bW1hcnkobXRjYXJzJGFtKSAgCm10Y2FycyRhbQpgYGAKCkNoYW5nZSBzaGFwZSB0byBiZSBNYXpkYSBvciBub3QgTWF6ZGEKYGBge3J9Cm10Y2FycyRtYXpkYSA8LSBpZmVsc2UobXRjYXJzJGJyYW5kID09ICdNYXpkYScsIDUsIDE4KQpwbG90KG10Y2FycyRocCwgbXRjYXJzJG1wZywgeGxhYj0nSG9yc2Vwb3dlcicsIHlsYWI9J01pbGVzIHBlciBHYWxsb24nLCBwY2g9bXRjYXJzJG1hemRhKQpgYGAKCk5vdywgbGV0IHVzIGNvbG9yIHRoZSBwb2ludHMuICBUaGUgYXBwcm9hY2ggaXMgdGhlIHNhbWUgYXMgd2UgaGF2ZSBzZWVuIC0gcGFzcyBSIGEgdmVjdG9yIG9mIGNvbG9ycyBhbmQgUiB3aWxsIG1ha2UgdGhlIHBvaW50cyB0aG9zZSBjb2xvcnMuICBOb3RpY2UgdGhhdCBJIGhhdmUgZG91YmxlIHRoZSBzaXplIG9mIGVhY2ggcG9pbnQgd2l0aCB0aGUgYGNleGAgYXJndW1lbnQ7IEkgZG8gdGhhdCBzaW1wbHkgdG8gbWFrZSB0aGUgY2hhcnQgbW9yZSBsZWdpYmxlLgoKQ2hhbmdlIHRoZSBjb2xvciB3aXRoIHRoZSBjb2wgYXJndW1lbnQKYGBge3J9CnBsb3QobXRjYXJzJGhwLCBtdGNhcnMkbXBnLCB4bGFiPSdIb3JzZXBvd2VyJywgeWxhYj0nTWlsZXMgcGVyIEdhbGxvbicsIHBjaD0yMCwgY29sPSdibHVlJywgY2V4PTIpCgojIyBDaGFuZ2UgdGhlIGNvbG9yIHdpdGggdGhlIGNvbCBhcmd1bWVudApwbG90KG10Y2FycyRocCwgbXRjYXJzJG1wZywgeGxhYj0nSG9yc2Vwb3dlcicsIHlsYWI9J01pbGVzIHBlciBHYWxsb24nLCBwY2g9MjAsIGNvbD1jKCdibHVlJywgJ3B1cnBsZScpLCBjZXg9MikKCiMjIE1ha2UgdGhlIGNvbG9yIGFyZ3VtZW50IG1ha2Ugc2Vuc2UKY29sb3JzIDwtIGlmZWxzZShtdGNhcnMkd3Q8MywgJ2dyZWVuJywgJ3JlZCcpCnBsb3QobXRjYXJzJGhwLCBtdGNhcnMkbXBnLCB4bGFiPSdIb3JzZXBvd2VyJywgeWxhYj0nTWlsZXMgcGVyIEdhbGxvbicsIHBjaD0yMCwgY29sPWNvbG9ycywgY2V4PTIpCmxlZ2VuZCgndG9wcmlnaHQnLCBsZWdlbmQ9J0dyZWVuOiBXZWlnaHQgPCAzLDAwMCBsYnMnKQpgYGAKCioqV2hhdCBkbyB5b3Ugbm90aWNlIGFib3V0IHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBob3JzZXBvd2VyLCBtaWxlcyBwZXIgZ2FsbG9uLCBhbmQgdGhlIHdlaWdodCBvZiBhIGNhcj8qKgoKUGxvdCBxdWFydGVyIG1pbGUgc2Vjb25kIHRpbWUgYWdhaW5zdCBtaWxlcyBwZXIgZ2FsbG9uLiAgQ2hhbmdlIHRoZSBzaXplIGJhc2VkIG9uIHRoZSBjYXIncyB3ZWlnaHQuCmBgYHtyfQpwbG90KG10Y2FycyRxc2VjLCBtdGNhcnMkbXBnLCBwY2g9MTUsIGNleD1tdGNhcnMkd3QpCnBsb3QobXRjYXJzJHFzZWMsIG10Y2FycyRtcGcsIHBjaD0xNSwgY2V4PW10Y2FycyR3dC8yKSAgIy8yIHRvIG1ha2Ugc2l6ZSBhIGJpdCBzbWFsbGVyCmBgYAoKUGxvdCBxdWFydGVyIG1pbGUgc2Vjb25kIHRpbWUgYWdhaW5zdCBtaWxlcyBwZXIgZ2FsbG9uLiAgQ2hhbmdlIHRoZSBzaGFwZSBiYXNlZCBvbiB3aGV0aGVyIGNhciBoYXMgYW4gYXV0b21hdGljIHRyYW5zbWlzc2lvbi4KYGBge3J9CnNoYXBlIDwtIGlmZWxzZShtdGNhcnMkYW0gPT0gMSwgMjAsIDUpCnBsb3QobXRjYXJzJHFzZWMsIG10Y2FycyRtcGcsIHBjaD1zaGFwZSkKYGBgCgpQbG90IHF1YXJ0ZXIgbWlsZSBzZWNvbmQgdGltZSBhZ2FpbnN0IG1pbGVzIHBlciBnYWxsb24uICBDaGFuZ2UgdGhlIGNvbG9yIGJhc2VkIG9uIHdoZXRoZXIgdGhlIGNhciBoYXMgbW9yZSB0aGFuIDQgY3lsaW5kZXJzLgpgYGB7cn0KbmV3Y29sIDwtIGlmZWxzZShtdGNhcnMkY3lsID4gNCwgJ2JsdWUnLCAnb3JhbmdlJykKcGxvdChtdGNhcnMkcXNlYywgbXRjYXJzJG1wZywgY29sPW5ld2NvbCkKYGBgCgpNYWtlIG9uZSBwbG90IHRoYXQgY29tYmluZXMgdGhlIHRocmVlIHBsb3RzIGFib3ZlLiAgVGhhdCBpcywgY2hhbmdlIHRoZSBzaXplLCBzaGFwZSwgYW5kIGNvbG9yIG9mIGVhY2ggcG9pbnQgYmFzZWQgb24gdGhlIGNhcidzIHdlaWdodCwgdHJhbnNtaXNzaW9uLCBhbmQgbnVtYmVyIG9mIGN5bGluZGVycywgcmVzcGVjdGl2ZWx5LgpgYGB7cn0KcGxvdChtdGNhcnMkcXNlYywgbXRjYXJzJG1wZywgY29sPW5ld2NvbCwgcGNoPXNoYXBlLCBjZXg9bXRjYXJzJHd0LzIpCmBgYAoKTW9kaXlpbmcgdGhlIHNpemUsIHNoYXBlLCBhbmQgY29sb3Igb2Ygbm9kZXMgaXMgaWRlbnRpY2FsLiAgRmlyc3QsIGxldCB1cyBleHBsb3JlIHRoZSBrYXJhdGUgY2x1YiBkYXRhc2V0LgpgYGB7cn0KaW5zdGFsbC5wYWNrYWdlcygnaWdyYXBoZGF0YScpCmxpYnJhcnkoaWdyYXBoZGF0YSkgIAoKZGF0YShrYXJhdGUpICAjIExldCB1cyB1c2UgdGhlIGthcmF0ZSBjbHViIGRhdGEuCnZjb3VudChrYXJhdGUpCmVjb3VudChrYXJhdGUpCmhlYWQoZGVncmVlKGthcmF0ZSkpCgojTm93LCBsZXQgdXMgbW9kaWZ5IHRoZSBzaXplLiAgV2UgZG8gdGhhdCBieSBtYWtpbmcgbm9kZSBhdHRyaWJ1dGVzIGFuZCBjYWxsaW5nIHRob3NlIGF0dHJpYnV0ZXMgd2hlbiBwbG90dGluZy4gIFNlcGFyYXRlbHksIG5vdGljZSBob3cgdGhlIGxheW91dCBvZiBlYWNoIGdyYXBoIGNoYW5nZXMsIHdoaWNoIGVtcGhhc2l6ZXMgdGhlIGFyYml0cmFyaW5lc3Mgb2YgKHgseSkgY29vcmRpbmF0ZXMgZm9yIG5ldHdvcmsgZ3JhcGhzLgoKc2V0LnNlZWQoMDEwODIwMTcpCgpzaXplIDwtIDE6dmNvdW50KGthcmF0ZSkKVihrYXJhdGUpJHNpemUgPC0gc3FydCgxOnZjb3VudChrYXJhdGUpKQpWKGthcmF0ZSkkc2l6ZQoKcGxvdChrYXJhdGUsIHZlcnRleC5zaXplPVYoa2FyYXRlKSRzaXplKQpwbG90KGthcmF0ZSwgc2l6ZT1zaXplKQojIFRoZSBsYWJlbHMgZ2V0IGluIHRoZSB3YXkgZm9yIG5vdwpwbG90KGthcmF0ZSwgdmVydGV4LnNpemU9VihrYXJhdGUpJHNpemUsIHZlcnRleC5sYWJlbD0iIikgCgojIFRoZSBzaXplIHZlY3RvciBjYW4gYmUgc2VwYXJhdGUgZnJvbSBub2RlIGF0dHJpYnV0ZXJzCnNpemUgPC0gMTp2Y291bnQoa2FyYXRlKQpwbG90KGthcmF0ZSwgdmVydGV4LnNpemU9c2l6ZSwgdmVydGV4LmxhYmVsPSIiKQoKIyBJdCBpcyBjb21tb24gdG8gc2l6ZSBieSBkZWdyZWUKcGxvdChrYXJhdGUsIHZlcnRleC5zaXplPWRlZ3JlZShrYXJhdGUpLCB2ZXJ0ZXgubGFiZWw9IiIpCgojV2Ugd2lsbCBub3cgbW9kaWZ5IHRoZSBzaGFwZSBhbmQgY29sb3Igb2Ygbm9kZXMuICBTZWUgPGh0dHA6Ly9pZ3JhcGgub3JnL3IvZG9jL3Bsb3QuY29tbW9uLmh0bWw+W2xpbmtdKHRoaXMgZG9jdW1lbnRhdGlvbikgZm9yIHZhbGlkIHNoYXBlcy4gIEkgd2lsbCBmaXJzdCBzaG93IGhvdyB0byBhcmJpdHJhcmlseSBjaGFuZ2UgdGhlIHNoYXBlLCB0aGVuIEkgd2lsbCBzaG93IGhvdyB0byBoYXZlIHRoZSBzaGFwZSByZWZsZWN0IGEgdmFyaWFibGUgeW91IG1heSBjYXJlIGFib3V0LiAgSSB3aWxsIHJhbmRvbWx5IGFzc2lnbiBnZW5kZXIgdG8gZWFjaCBub2RlIGFuZCBjaGFuZ2Ugc2hhcGUgYnkgZ2VuZGVyLgoKVihrYXJhdGUpJGdlbmRlciA8LSBjKCdtYWxlJywnZmVtYWxlJykKc2hhcGUgPC0gaWZlbHNlKFYoa2FyYXRlKSRnZW5kZXIgPT0gJ21hbGUnLCAnc3F1YXJlJywgJ3ZyZWN0YW5nbGUnKQpwZGYoJ3Rlc3QucGRmJykKcGxvdC5pZ3JhcGgoa2FyYXRlLCB2ZXJ0ZXguc2hhcGU9c2hhcGUsIHZlcnRleC5sYWJlbD0iIikKCiMgSSBoYXZlIGNoYW5nZWQgc2hhcGUgZm9yIHRoZSBmdW4gb2YgaXQuCnBsb3Qoa2FyYXRlLCB2ZXJ0ZXguc2hhcGU9J3NxdWFyZScsIHZlcnRleC5sYWJlbD0iIiwgdmVydGV4LnNpemU9MjApICAKCgpZb3UgbWF5IGhhdmUgbm90aWNlZCB0aGF0IHRoZSBub2RlcyBhbHJlYWR5IGhhdmUgY29sb3JzLiAgTGV0IHVzIGZpZ3VyZSBvdXQgd2h5IHRoYXQgaXMuCiMgU28sIHRoZXJlIGlzIGFscmVhZHkgYSBjb2xvciBhdHRyaWJ1dGUuIHBsb3Qgd2lsbCB1c2UgdGhhdCBieSBkZWZhdWx0CmdldC52ZXJ0ZXguYXR0cmlidXRlKGthcmF0ZSkgIAoKIyBMZXQgdXMgY2hhbmdlIHRoZSBjb2xvci4KcGxvdChrYXJhdGUsIHZlcnRleC5jb2xvcj0nYmxhY2snLCB2ZXJ0ZXgubGFiZWw9IiIsIHZlcnRleC5zaXplPTEwKSAgCgpnZW5kZXJDb2xvciA8LSBpZmVsc2UoVihrYXJhdGUpJGdlbmRlcj09J21hbGUnLCAncGluaycsICdibHVlJykKcGxvdChrYXJhdGUsIHZlcnRleC5jb2xvcj1nZW5kZXJDb2xvciwgdmVydGV4LmxhYmVsPSIiLCB2ZXJ0ZXguc2l6ZT0xMCkKCiMgVGhlIGV4cGVyaWVuY2Ugd2l0aCBgY29sb3JgIHNob3dzIGEgc2hvcnRjdXQgdGhhdCBjYW4gc29tZXRpbWVzIGJlIGNvbmZ1c2luZy4gIElmIHlvdSBoYXZlIG5vZGUgYXR0cmlidXRlcyB0aGF0IGFyZSBjYWxsZWQgYGxhYmVsYCwgYGNvbG9yYCwgb3IgYHNpemVgLCBgcGxvdGAgd2lsbCB1c2UgdGhvc2UgdW5sZXNzIG92ZXJyaWRkZW4uCgojIFBsb3QgdGhlIGthcmF0ZSBuZXR3b3JrIHdpdGggb3JhbmdlIHJlY3RhbmdsZXMuCnBsb3Qoa2FyYXRlLCB2ZXJ0ZXguY29sb3I9J29yYW5nZScsIHZlcnRleC5zaXplPTIwLCB2ZXJ0ZXguc2hhcGU9J2NyZWN0YW5nbGUnKQpwbG90KGthcmF0ZSwgdmVydGV4LmNvbG9yPSdvcmFuZ2UnLCB2ZXJ0ZXguc2l6ZT0yMCwgdmVydGV4LnNoYXBlPSdjcmVjdGFuZ2xlJywgdmVydGV4LmxhYmVsPSIiKQpwbG90KGthcmF0ZSwgdmVydGV4LmNvbG9yPSdvcmFuZ2UnLCB2ZXJ0ZXguc2l6ZT0yMCwgdmVydGV4LnNoYXBlPSdjcmVjdGFuZ2xlJywgdmVydGV4LmxhYmVsPSJhcmJpdHJhcnkiKQoKIyBQbG90IHRoZSBrYXJhdGUgbmV0d29yay4gIFNpemUgdGhlIG5vZGVzIGJ5IHRoZWlyIGRlZ3JlZS4gIENvbG9yIHRoZSBub2RlcyBieSB0aGVpciBmYWN0aW9uLiAgR2l2ZSAiTXIgSGkiIGFuZCAiSm9obiBBIiBkaWZmZXJlbnQgc2hhcGVzIGZyb20gZXZlcnlvbmUgZWxzZTsgdGhlcmUgd2lsbCBiZSB0aHJlZSBzaGFwZXMuCm5ld3NoYXBlIDwtIGlmZWxzZShrYXJhdGUkbmFtZSA9PSAnTXIgSGknLCAnY2lyY2xlJywgaWZlbHNlKGthcmF0ZSRuYW1lID09ICJKb2huIEEiLCAnY3JlY3RhbmdsZScsICdwaWUnKSkgICMgV2h5IGRpZCB0aGF0IG5vdCB3b3JrPwpuZXdzaGFwZSA8LSBpZmVsc2UoVihrYXJhdGUpJG5hbWUgPT0gJ01yIEhpJywgJ2NpcmNsZScsIGlmZWxzZShWKGthcmF0ZSkkbmFtZSA9PSAiSm9obiBBIiwgJ2NyZWN0YW5nbGUnLCAncGllJykpICAjIENhbGxlZCB2ZXJ0ZXggYXR0cmlidXRlIGluY29ycmVjdGx5CgojIEJlbG93IGlzIGEgc2Vjb25kIHdheQpuZXdzaGFwZTIgPC0gcmVwKCdwaWUnLCB2Y291bnQoa2FyYXRlKSkKbmV3c2hhcGUyW1Yoa2FyYXRlKSRuYW1lID09ICdNciBIaSddIDwtICdjaXJjbGUnCm5ld3NoYXBlMltWKGthcmF0ZSkkbmFtZSA9PSAnSm9obiBBJ10gPC0gJ2NyZWN0YW5nbGUnCgpwbG90KGthcmF0ZSwgdmVydGV4LnNpemU9ZGVncmVlKGthcmF0ZSksIHZlcnRleC5jb2xvcj1rYXJhdGUkZmFjdGlvbiwgdmVydGV4LnNoYXBlPW5ld3NoYXBlKQoKcGRmKCd0ZXN0Mi5wZGYnKQpwbG90KGthcmF0ZSwgdmVydGV4LnNpemU9ZGVncmVlKGthcmF0ZSksIHZlcnRleC5jb2xvcj1rYXJhdGUkZmFjdGlvbiwgdmVydGV4LnNoYXBlPW5ld3NoYXBlLCB2ZXJ0ZXgubGFiZWw9IiIpCmRldi5vZmYoKQpgYGAKCgoKCgoKCgoKCgoKCgojIE5FVFdPUksgTEFZT1VUCgoKRmluYWxseSwgbGV0IHVzIGxvb2sgYXQgaG93IG91ciBuZXR3b3JrcyBsb29rIGRpZmZlcmVudCBkZXBlbmRpbmcgb24gdGhlIGxheW91dCB3ZSB1c2UuICBGcmFua2x5LCBgaWdyYXBoYCBpcyB2ZXJ5IGZydXN0cmF0aW5nIGhlcmUsIGFzIHRoZSBhcmd1bWVudHMgdG8gbGF5b3V0IGRvIG5vdCBwb3NzZXNzIHRoZSBzYW1lIHN0cnVjdHVyZS4gIElmIHlvdSB3YW50IHRvIHRyeSBhIGRpZmZlcmVudCBsYXlvdXQsIEkgc3VnZ2VzdCBnb29nbGluZy4gCmBgYHtyfQpwbG90KGthcmF0ZSwgbGF5b3V0PWxheW91dF9yYW5kb21seSwgdmVydGV4LmxhYmVsPSIiLCBtYWluPSJSYW5kb20iLCB2ZXJ0ZXguY29sb3I9J2JsYWNrJywgdmVydGV4LnNpemU9MTApCgpwbG90KGthcmF0ZSwgbGF5b3V0PWxheW91dF9pbl9jaXJjbGUsIHZlcnRleC5sYWJlbD0iIiwgbWFpbj0iUmluZyIsIHZlcnRleC5jb2xvcj0nYmxhY2snLCB2ZXJ0ZXguc2l6ZT0xMCkKCnBsb3Qoa2FyYXRlLCBsYXlvdXQ9bGF5b3V0X2FzX3RyZWUsIHZlcnRleC5sYWJlbD0iIiwgbWFpbj0iVHJlZSIsIHZlcnRleC5jb2xvcj0nYmxhY2snLCB2ZXJ0ZXguc2l6ZT0xMCkKCnBsb3Qoa2FyYXRlLCBsYXlvdXQ9bGF5b3V0X2FzX3RyZWUoa2FyYXRlLCBjaXJjdWxhcj1UUlVFKSwgdmVydGV4LmxhYmVsPSIiLCBtYWluPSJDaXJjdWxhciBUcmVlIiwgdmVydGV4LmNvbG9yPSdibGFjaycsIHZlcnRleC5zaXplPTEwKQoKcGxvdChrYXJhdGUsIGxheW91dD1sYXlvdXQuZnJ1Y2h0ZXJtYW4ucmVpbmdvbGQoa2FyYXRlKSwgdmVydGV4LmxhYmVsPSIiLCBtYWluPSJGcnVjaHRlcm1hbi1SZWluZ29sZCIsIHZlcnRleC5jb2xvcj0nYmxhY2snLCB2ZXJ0ZXguc2l6ZT0xMCkKYGBgCgoKQmVsb3cgaXMgYW5vdGhlciB3YXkgdG8gZ2VuZXJhdGUgY29vcmRpbmF0ZXMuICBZb3UgZ2VuZXJhdGUgdGhlIGNvb3JkaW5hdGVzIGJlZm9yZSBjYWxsaW5nIHBsb3QsIHNhdmUgdGhhdCBhcyBhbiBvYmplY3QsIHRoZW4gcGFzcyB0aGF0IG9iamVjdCB0byBwbG90LiAgVGhpcyBhcHByb2FjaCBpcyB3aGF0IHlvdSB3b3VsZCBkbyBpZiB5b3Ugd2FudCB0byBtYW51YWxseSBjaGFuZ2UgY29vcmRpbmF0ZXMgdGhhdCBgaWdyYXBoYCBnZW5lcmF0ZXMuICBZb3UgY2FuIGFsc28gdXNlIHRoaXMgYXBwcm9hY2ggdG8gZ2VuZXJhdGUgeW91ciBvd24gbGF5b3V0LgpgYGB7cn0KY29vcmRpbmF0ZXMgPC0gbGF5b3V0LnJhbmRvbShrYXJhdGUpCnBsb3Qoa2FyYXRlLCBsYXlvdXQ9Y29vcmRpbmF0ZXMsIHZlcnRleC5sYWJlbD0iIiwgbWFpbj0iUmFuZG9tIiwgdmVydGV4LmNvbG9yPSdibGFjaycsIHZlcnRleC5zaXplPTEwKQoKY29vcmRpbmF0ZXMgPC0gbGF5b3V0LmNpcmNsZShrYXJhdGUpCnBsb3Qoa2FyYXRlLCBsYXlvdXQ9Y29vcmRpbmF0ZXMsIHZlcnRleC5sYWJlbD0iIiwgbWFpbj0iUmluZyIsIHZlcnRleC5jb2xvcj0nYmxhY2snLCB2ZXJ0ZXguc2l6ZT0xMCkKCiMjIExldCB1cyBmaWd1cmUgb3V0IGhvdyB0byBtYW51YWxseSBjaGFuZ2UgY29vcmRpbmF0ZXMuICAKY29vcmRpbmF0ZXMgICNPaywgZWFjaCByb3cgaXMgKHgseSkgY29vcmRpbmF0ZXMKCiMgQ29tcHJlc3MgdGhlIHRvcHMgYW5kIGJvdHRvbXMKY29vcmRpbmF0ZXNbLDJdW2Nvb3JkaW5hdGVzWywyXSA+IC44XSA8LSAuOApjb29yZGluYXRlc1ssMl1bY29vcmRpbmF0ZXNbLDJdIDwgLS44XSA8LSAtLjgKCnBsb3Qoa2FyYXRlLCBsYXlvdXQ9Y29vcmRpbmF0ZXMsIHZlcnRleC5sYWJlbD0iIiwgbWFpbj0iQWRqdXN0ZWQgUmluZyIsIHZlcnRleC5jb2xvcj0nYmxhY2snLCB2ZXJ0ZXguc2l6ZT0xMCkKCiMgTGV0J3MgcHVsbCBvdXQgdGhlIHR3byBub2RlcyB3aXRoIG5hbWVzCmdldC52ZXJ0ZXguYXR0cmlidXRlKGthcmF0ZSkKY29vcmRpbmF0ZXMgPC0gbGF5b3V0LmNpcmNsZShrYXJhdGUpCgpjb29yZGluYXRlc1tncmVwKCdNciBIaScsIGdldC52ZXJ0ZXguYXR0cmlidXRlKGthcmF0ZSkkbmFtZSksXSA8LSBjKDEsMSkKY29vcmRpbmF0ZXNbZ3JlcCgnSm9obiBBJywgZ2V0LnZlcnRleC5hdHRyaWJ1dGUoa2FyYXRlKSRuYW1lKSxdIDwtIGMoLTEsLTEpCgpwbG90KGthcmF0ZSwgbGF5b3V0PWNvb3JkaW5hdGVzLCB2ZXJ0ZXgubGFiZWw9IiIsIG1haW49IkFkanVzdGVkIFJpbmciLCB2ZXJ0ZXguY29sb3I9J2JsYWNrJywgdmVydGV4LnNpemU9MTApCgojIE1ha2UgeW91ciBvd24gY29vcmRpbmF0ZXMKeCA8LSBzZXEoLTEsIDEsIGxlbmd0aD12Y291bnQoa2FyYXRlKSkKeSA8LSBzZXEoMSwgLTEsIGxlbmd0aD12Y291bnQoa2FyYXRlKSkKCmNvb3JkaW5hdGVzIDwtIG1hdHJpeChjKHgseSksbmNvbD0yKQogICAgICAgICAgICAgICAgICAgICAgCnBsb3Qoa2FyYXRlLCBsYXlvdXQ9Y29vcmRpbmF0ZXMsIG1haW49IlVzZXIgU3VwcGxpZWQgQ29vcmRpbmF0ZXMiKQoKCiNUaGUgZm9sbG93aW5nIHF1ZXN0aW9ucyB1c2UgdGhlIGBVS2ZhY3VsdHlgIGRhdGEuICBHbyBhaGVhZCBhbmQgbWFrZSBpdCBhbiB1bmRpcmVjdGVkIGdyYXBoIGZpcnN0LCB1c2luZyBgYXMudW5kaXJlY3RlZGAgd2l0aCBgbW9kZT1jKCdjb2xsYXBzZScpYC4KCgojIExvYWQgdGhlIFVLZmFjdWx0eSBkYXRhIGFuZCBjb252ZXJ0IGl0IHRvIGFuIHVuZGlyZWN0ZWQgZ3JhcGguCmRhdGEoVUtmYWN1bHR5KQpnIDwtIGFzLnVuZGlyZWN0ZWQoVUtmYWN1bHR5LCBtb2RlPSJjb2xsYXBzZSIpCgojIFdoYXQgYXJlIHRoZSB2ZXJ0ZXggYXR0cmlidXRlcz8KZ2V0LnZlcnRleC5hdHRyaWJ1dGUoZykKCiMgUGxvdCB0aGUgZ3JhcGggdXNpbmcgYSByYW5kb20gbGF5b3V0LgpwbG90KGcsIGxheW91dD1sYXlvdXRfcmFuZG9tbHkpCgojIFBsb3QgdGhlIGdyYXBoIHVzaW5nIGEgY2lyY2xlIGxheW91dC4KcGxvdChnLCBsYXlvdXQ9bGF5b3V0X2luX2NpcmNsZSkKCiMgUGxvdCB0aGUgZ3JhcGggdXNpbmcgYSB0cmVlIGxheW91dC4KcGxvdChnLCBsYXlvdXQ9bGF5b3V0X2FzX3RyZWUpCgojIFBsb3QgdGhlIGdyYXBoIHVzaW5nIGEgRnJ1Y2h0ZXJtYW4tUmVpbmdvbGQgbGF5b3V0LgpwbG90KGcsIGxheW91dD1sYXlvdXRfcmFuZG9tbHkpCgojIENvbG9yIHRoZSBub2RlcyBhY2NvcmRpbmcgdG8gdGhlaXIgZ3JvdXAuICBDaGFuZ2UgdGhlIG5vZGUgc2l6ZSBiYXNlZCBvbiB0aGUgbm9kZSBkZWdyZWUuICBSYW5kb21seSBkZXRlcm1pbmUgaWYgYSBub2RlIGlzIGEgbWFuIG9yIHdvbWFuIGFuZCBjaGFuZ2UgaXRzIHNoYXBlIGFjY29yZGluZ2x5LiAgVXNlIHRoZSBGcnVjaHRlcm1hbi1SZWluZ29sZCBsYXlvdXQuIFNhdmUgdGhlIGZpbGUgYXMgYSAucGRmLgoKVihnKSRnZW5kZXIgPC0gYygnbWFsZScsICdmZW1hbGUnKQpWKGcpJHNoYXBlIDwtIGlmZWxzZShWKGcpJGdlbmRlciA9PSAnbWFsZScsICdwaWUnLCAnY3JlY3RhbmdsZScpCgpwZGYoJ2ZpbmFscGxvdC5wZGYnKQpwbG90KGcsIHZlcnRleC5jb2xvcj1WKGcpJEdyb3VwLCB2ZXJ0ZXguc2l6ZT1kZWdyZWUoZyksIGxheW91dD1sYXlvdXQuZnJ1Y2h0ZXJtYW4ucmVpbmdvbGQoZyksIHZlcnRleC5sYWJlbD0iIikgIAojIHNoYXBlIGlzIHBsb3R0ZWQgYmVjYXVzZSBpZ3JhcGggcmVjb2duaXplcyB0aGUgc2hhcGUgYXR0cmlidXRlCmRldi5vZmYoKQpgYGAKCgoKCgoKCgoKCgoKCgoKCiMjIyMgQ0VOVFJBTElUWQoKRGVncmVlIENlbnRyYWxpdHk6IExldCB1cyB1c2UgYSBkaXJlY3RlZCBkYXRhc2V0LCBgVUtmYWN1bHR5YCB0byBleHBsb3JlIGRpZmZlcmVudCBtZWFzdXJlcyBvZiBkZWdyZWUgY2VudHJhbGl0eS4KYGBge3J9CmxpYnJhcnkoaWdyYXBoZGF0YSkKbGlicmFyeShpZ3JhcGgpCgojIExvYWQgZGF0YQpkYXRhKFVLZmFjdWx0eSkKCiMgRXhwbG9yZSBub2RlIGF0dHJpYnV0ZXMKZ2V0LnZlcnRleC5hdHRyaWJ1dGUoVUtmYWN1bHR5KQoKIyBNYWtlIHZlY3RvcnMgb2YgZGVncmVlcwppbmRlZ3JlZSA8LSBkZWdyZWUoVUtmYWN1bHR5LCBtb2RlPWMoJ2luJykpCm91dGRlZ3JlZSA8LSBkZWdyZWUoVUtmYWN1bHR5LCBtb2RlPWMoJ291dCcpKQpkZWdyZWVDIDwtIGluZGVncmVlK291dGRlZ3JlZQpkZWdyZWVDZW50cmFsaXR5IDwtIGRlZ3JlZShVS2ZhY3VsdHksIG1vZGU9YygndG90YWwnKSkKZEMyIDwtIGRlZ3JlZShVS2ZhY3VsdHksIG1vZGU9YygnYWxsJykpCgojIFRoZSBhcmd1bWVudCB0b3RhbCwgYWxsIGlzIHRoZSBzYW1lCmRlZ3JlZUNlbnRyYWxpdHkgPT0gZEMyCmBgYAoKTm93LCBsZXQgdXMgc2l6ZSBub2RlcyBieSB0aGVpciBjZW50cmFsaXR5OgpgYGB7cn0Kc2V0LnNlZWQoMDEwODIwMTgpCgojIFNhdmluZyB0aGUgbGF5b3V0IGFzIGFuIG9iamVjdCBlbnN1cmVzIHRoYXQgdGhlIGdyYXBocyB3aWxsIGhhdmUgdGhlIG5vZGVzIGluIHRoZSBzYW1lIHBsYWNlLgojIFdpdGggYSBmb3JjZS1kaXJlY3RlZCBsYXlvdXQsIHlvdSBjb3VsZCBnZXQgdmVyeSBkaWZmZXJlbnQgcmVzdWx0cyBpZiB0aGUgbWVhc3VyZXMgb2YgY2VudHJhbGl0eSBkaWZmZXIgbm90aWNhYmx5LiAgCmwgPC0gbGF5b3V0LmZydWNodGVybWFuLnJlaW5nb2xkKFVLZmFjdWx0eSkKcGxvdChVS2ZhY3VsdHksIHZlcnRleC5zaXplPWluZGVncmVlLCBtYWluPSJTaXplIGJ5IEluZGVncmVlIiwgbGF5b3V0PWwpCnBsb3QoVUtmYWN1bHR5LCB2ZXJ0ZXguc2l6ZT1vdXRkZWdyZWUsIG1haW49IlNpemUgYnkgT3V0ZGVncmVlIiwgbGF5b3V0PWwpCnBsb3QoVUtmYWN1bHR5LCB2ZXJ0ZXguc2l6ZT1kZWdyZWVDZW50cmFsaXR5LCBtYWluPSJTaXplIGJ5IERlZ3JlZSIsIGxheW91dD1sKQoKI1lvdSBtYXkgaGF2ZSBub3RpY2VkIHRoYXQgdGhlcmUgYXJlIGFycm93aGVhZHMgb24gdGhlIGVkZ2VzIG5vdy4gIFRoYXQgaXMgYmVjYXVzZSB0aGUgZ3JhcGggaXMgZGlyZWN0ZWQsIHNvIHRoZSBhcnJvdyBwb2ludHMgaW4gdGhlIGRpcmVjdGlvbiBvZiB0aGUgcmVsYXRpb25zaGlwLiAgV2UgY2FuIGNoYW5nZSBhcnJvdyBhdHRyaWJ1dGVzIG9yIG5vdCBwcmludCB0aGUgYXJyb3doZWFkcy4gIEZvciBtb3JlIGRldGFpbCwgdXNlIGA/cGxvdC5pZ3JhcGhgLiAgSSB3aWxsIGFsc28gc2hvdyBob3cgdG8gY2hhbmdlIHRoZSBlZGdlIGNvbG9yIG9yIHR5cGUuICBSZW1lbWJlciwgeW91IGNhbiB2YXJ5IGFsbCBvZiB0aGVzZSBwYXJhbWV0ZXJzIGJ5IG5vZGUgYnkgY3JlYXRpbmcgYSB2ZWN0b3Igd2l0aCBkaWZmZXJlbnQgdmFsdWVzIGZvciBlZGdlIHR5cGUgb3IgY29sb3I7IEkgd2lsbCBzaG93IG9ubHkgaG93IHRvIG1ha2UgdGhlbSBhbGwgdGhlIHNhbWUgdHlwZSBvciBjb2xvci4KCiMgTm8gYXJyb3cKcGxvdChVS2ZhY3VsdHksIHZlcnRleC5zaXplPWluZGVncmVlLCBtYWluPSJObyBBcnJvdyIsIGVkZ2UuYXJyb3cud2lkdGg9MCkKCiMgU21hbGwgYXJyb3cKcGxvdChVS2ZhY3VsdHksIHZlcnRleC5zaXplPWluZGVncmVlLCBtYWluPSJTbWFsbCBBcnJvdyIsIGxheW91dD1sLCBlZGdlLmFycm93LndpZHRoPS4yNSkKCiMgRG90dGVkIGxpbmUKcGxvdChVS2ZhY3VsdHksIHZlcnRleC5zaXplPWluZGVncmVlLCBtYWluPSJEb3R0ZWQgRWRnZXMiLCBsYXlvdXQ9bCwgZWRnZS5hcnJvdy53aWR0aD0wLCBlZGdlLmx0eT0zKQoKIyBDb2xvcmVkIGVkZ2VzCnBsb3QoVUtmYWN1bHR5LCB2ZXJ0ZXguc2l6ZT1pbmRlZ3JlZSwgbWFpbj0iQ29sb3JlZCBFZGdlcyIsIGxheW91dD1sLCBlZGdlLmFycm93LndpZHRoPTAsIGVkZ2UuY29sb3I9J3JlZCcpCmBgYAoKSXQgaXMgb2Z0ZW4gZGlmZmljdWx0IHRvIHNlZSBob3cgZGlmZmVyZW50IGNlbnRyYWxpdHkgbWVhc3VyZXMgY292YXJ5LCBzaW5jZSBpdCBpcyB1bmNsZWFyIHdoYXQgdGhlIGV4YWN0IG51bWJlciBmb3IgZWFjaCBzaXplIGlzLiAgSXQgaXMgdGhlcmVmb3JlIGEgZ29vZCBpZGVhIHRvIHZpc3VhbGl6ZSB0aGUgbmV0d29yayBpbiBvdGhlciB3YXlzLgpgYGB7cn0Kc2V0LnNlZWQoMDEwODIwMTgpCnBsb3QoaW5kZWdyZWUsIG91dGRlZ3JlZSwgeGxhYj0nSW5kZWdyZWUnLCB5bGFiPSdPdXRkZWdyZWUnLCBwY2g9MjApCiMgTGV0IHVzIHJlcGxhY2UgdGhlIGRvdHMgd2l0aCB2ZXJ0ZXggbGFiZWxzLCBtYWtpbmcgaXQgZWFzaWVyIHRvIHNlZSB3aG8gaXMgd2hpY2ggcG9pbnQuCiMgV2UgZG8gbm90IGhhdmUgdHJ1ZSB2ZXJ0ZXggbGFiZWxzLCBzbyBJIGhhdmUganVzdCB1c2VkIHRoZWlyIG5hbWVzLiAgVGhlIGtleSBpcyB0aGUgdmVjdG9yIHBhc3NlZCB0byB0aGUgbGFiZWxzIGFyZ3VtZW50IG9mIHRleHQoKS4KcGxvdChpbmRlZ3JlZSwgb3V0ZGVncmVlLCB4bGFiPSdJbmRlZ3JlZScsIHlsYWI9J091dGRlZ3JlZScsIHBjaD0nJykKdGV4dCh4PWluZGVncmVlLCB5PW91dGRlZ3JlZSwgbGFiZWxzPVYoVUtmYWN1bHR5KSkKYGBgCgpXZSB3aWxsIHVzZSB0aGUgYFVTYWlycG9ydHNgIGRhdGEgZGF0YXNldCwgd2hpY2ggcmVwcmVzZW50cyBmbGlnaHRzIGluIERlY2VtYmVyIDIwMTAuICBFYWNoIGVkZ2UgaXMgYW4gYWlybGluZSByb3V0ZSBiZXR3ZWVuIHR3byBhaXJwb3J0cyB0aGF0IHVzZXMgdGhlIHNhbWUgYWlyY3JhZnQgdHlwZTsgdGhlcmUgY2FuIGJlIG11bHRpcGxlIGVkZ2VzIGJldHdlZW4gZWFjaCBub2RlLiAgWW91IHdpbGwgbm90aWNlIHRoYXQgdGhlIGVkZ2VzIGhhdmUgYXR0cmlidXRlcyBhcyB3ZWxsLgpgYGB7cn0KIyBMb2FkIHRoZSBVU2FpcnBvcnRzIGRhdGEKZGF0YShVU2FpcnBvcnRzKQoKIyBIb3cgbWFueSBhaXJwb3J0cyBhcmUgaW4gdGhpcyBkYXRhPwp2Y291bnQoVVNhaXJwb3J0cykKCiMgSG93IG1hbnkgYWlyY3JhZnQtdHlwZS1yb3V0ZXMgYXJlIGluIHRoaXMgZGF0YT8KZWNvdW50KFVTYWlycG9ydHMpCgojIE1ha2UgYSBuZXR3b3JrIHBsb3QgdXNpbmcgYSByaW5nIGxheW91dC4KciA8LSBsYXlvdXRfaW5fY2lyY2xlKFVTYWlycG9ydHMpCnBsb3QoVVNhaXJwb3J0cywgbGF5b3V0PXIpCgojIE1ha2UgYSBuZXR3b3JrIHBsb3QgdXNpbmcgYSBGcnVjaHRlcm1hbi1SZWluZ29sZCBsYXlvdXQsIHNpemVkIGJ5IHRoZSB0b3RhbCBkZWdyZWUgb2YgZWFjaCBub2RlLiAgRG8gbm90IGxhYmVsIG5vZGVzLgpmIDwtIGxheW91dC5mcnVjaHRlcm1hbi5yZWluZ29sZChVU2FpcnBvcnRzKQpwbG90KFVTYWlycG9ydHMsIGxheW91dD1mKQoKIyBQbG90IHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIGluZGVncmVlIGFuZCBvdXRkZWdyZWUgZm9yIGVhY2ggbmV0d29yay4gIAppbmRlZ3JlZSA8LSBkZWdyZWUoVVNhaXJwb3J0cywgbW9kZT1jKCdpbicpKQpvdXRkZWdyZWUgPC0gZGVncmVlKFVTYWlycG9ydHMsIG1vZGU9Yygnb3V0JykpCgpwbG90KGluZGVncmVlLCBvdXRkZWdyZWUsIHBjaD0yMCwgeGxhYj0nSW5kZWdyZWUnLCB5bGFiPSdPdXRkZWdyZWUnKQoKIyBSZXBlYXQgdGhlIHByZXZpb3VzIHN0ZXAsIGxhYmVsaW5nIGVhY2ggcG9pbnQgd2l0aCBpdHMgdmVydGV4IG5hbWUuICBZb3UgbWF5IG5lZWQgdG8gbWFrZSB0aGUgc2l6ZSBvZiB0aGUgdGV4dCBzbWFsbGVyIHVzaW5nIHRoZSBjZXggYXJndW1lbnQgaW4gdGV4dCgpLgpwbG90KGluZGVncmVlLCBvdXRkZWdyZWUsIHBjaD0nJywgeGxhYj0nSW5kZWdyZWUnLCB5bGFiPSdPdXRkZWdyZWUnKQp0ZXh0KHg9aW5kZWdyZWUsIHk9b3V0ZGVncmVlLCBsYWJlbD1WKFVTYWlycG9ydHMpJG5hbWUsIGNleD0uNSkKCiMgTGV0J3MgYWRkIHNvbWUgaml0dGVyaW5nIHRvIG1ha2UgZWFzaWVyIHRvIHJlYWQKaTIgPC0gaW5kZWdyZWUrcm5vcm0obj1sZW5ndGgoaW5kZWdyZWUpLCBtZWFuPTAsIHNkPTIwKQpvMiA8LSBvdXRkZWdyZWUgKyBybm9ybShuPWxlbmd0aChvdXRkZWdyZWUpLCBtZWFuPTAsIHNkPTIwKQoKcGxvdChpMiwgbzIsIHBjaD0nJywgeGxhYj0nSW5kZWdyZWUnLCB5bGFiPSdPdXRkZWdyZWUnKQp0ZXh0KHg9aTIsIHk9bzIsIGxhYmVsPVYoVVNhaXJwb3J0cykkbmFtZSwgY2V4PS41KQpgYGAKCiMgTmVpZ2hib3IgQ3VtdWxhdGl2ZSBEZWdyZWUgQ2VudHJhbGl0eQpJbiB0aGlzIHNlY3Rpb24sIHdlIHdpbGwgY2FsY3VsYXRlIG5laWdoYm9yIGN1bXVsYXRpdmUgZGVncmVlIGNlbnRyYWxpdHkuICBUaGVyZSBpcyBubyBkZWZhdWx0IGZ1bmN0aW9uIGluIGBpZ3JhcGhgIHRvIGRvIHRoaXMsIHNvIHdlIHdpbGwgaGF2ZSB0byBkbyBpdCBtYW51YWxseS4gIFdlIHdpbGwgbWFrZSBhIGRpcmVjdGVkIG5ldHdvcmsgdW5kaXJlY3RlZCBhbmQgdGhlbiBsb29wIG92ZXIgZXZlcnkgbm9kZS4KYGBge3J9CiMgTWFrZSB0aGUgZ3JhcGggdW5kaXJlY3RlZApnIDwtIGFzLnVuZGlyZWN0ZWQoVUtmYWN1bHR5LCBtb2RlPSJjb2xsYXBzZSIpCgojIEZvciBlYWNoIG5vZGUsIGdldCBpdHMgbmVpZ2hib3JzLgojIEZvciBlYWNoIG5laWdoYm9yLCBnZXQgaXMgZGVncmVlLgojIFN1bSB0aGUgZGVncmVlIG9mIGVhY2ggbmVpZ2hib3IuCiMgU2V0IHRoYXQgYXMgdGhlIHZlcnRleCBhdHRyaWJ1dGUuClYoZykkbmNkYyA8LSBOQQpmb3IoaSBpbiAxOnZjb3VudChnKSl7CiAgdG90YWwgPC0gMAogIG4gPC0gbmVpZ2hib3JzKGcsIFYoZylbaV0pCiAgZm9yKGogaW4gMTpsZW5ndGgobikpewogICAgZCA8LSBkZWdyZWUoZywgdj1uW2pdKQogICAgdG90YWwgPC0gdG90YWwrZAogIH0KICBWKGcpJG5jZGNbaV0gPC0gdG90YWwKfQoKIyMgSW4gZmFjdCwgdGhlcmUgaXMgYW4gZWFzaWVyIHdheS4KIyBHZXQgYWRqYWNlbmN5IG1hdHJpeAphIDwtIG1hdHJpeChnZXQuYWRqYWNlbmN5KGcpLCBucm93PXZjb3VudChnKSkKIyBHZXQgc3VtIG9mIG5laWdoYm9ycycgZGVncmVlLiAlKiUgaXMgbWF0cml4IG11bHRpcGxpY2F0aW9uLgphMiA8LSBhJSolbWF0cml4KGRlZ3JlZShnKSwgbnJvdz12Y291bnQoZykpCiMgTkNEQyBpcyB0aGUgY29sdW1uIHN1bSBvZiB0aGF0IG1hdHJpeApWKGcpJG5jZGMyIDwtIGEyCgojQ29uZmlybQpWKGcpJG5jZGMgPT0gYTIKClYoZykkbmNkYyA9PSBWKGcpJG5jZGMyCmBgYAoKKipXaGVyZSBkbyBJIGNyZWF0ZSB0aGUgdmVydGV4IGF0dHJpYnV0ZSBmb3IgdGhlIE5DREMgbWVhc3VyZT8qKiBGb3IgZWFjaCBub2RlLCB3ZSBoYXZlIHRvIGdldCBpdHMgbmVpZ2hib3JzIGFuZCBmb3IgZWFjaCBuZWlnaGJvciwgZ2V0IGlzIGRlZ3JlZS4gV2UgdGhlbiBzdW0gdGhlIGRlZ3JlZSBvZiBlYWNoIG5laWdoYm9yIGFuZCBtYWtlIHRoYXQgdGhlIHZlcnRleCBhdHRyaWJ1dGUgc28gd2UgY2FuIGVhc2lseSBjYWxsIG9uIGl0IGZvciB0aGUgTkNEQyBtZWFzdXJlLgoKKipXaHkgZG8gSSByZXNldCBgdG90YWwgPC0gMGAgZm9yIGVhY2ggbmV3IGxvb3A/KiogV2UgaGF2ZSB0byBtYWtlIHRoZSBkaXJlY3RlZCBuZXR3b3JrIHVuZGlyZWN0ZWQgYW5kIHRoZW4gbG9vcCBvdmVyIGV2ZXJ5IG5vZGUuCgpOb3csIGxldCB1cyBtYWtlIHBsb3RzLiAKYGBge3J9CmwgPC0gbGF5b3V0LmZydWNodGVybWFuLnJlaW5nb2xkKGcpCgojIEJlbG93IGdyYXBoIHdpbGwgYmUgdWdseS4KcGxvdChnLCB2ZXJ0ZXguc2l6ZT1WKGcpJG5jZGMsIG1haW49IlNpemUgYnkgTkNEQyIsIGxheW91dD1sKQoKIyBCZWxvdyBncmFwaCB3aWxsIGJlIGJldHRlci4KcGxvdChnLCB2ZXJ0ZXguc2l6ZT1WKGcpJG5jZGMvNTAsIG1haW49IlNpemUgYnkgTkNEQy81MCIsIGxheW91dD1sKQoKIyBQbG90IE5DREMgYWdhaW5zdCBEZWdyZWUKIyBOb3RpY2UgaG93IHRvIGxhYmVsIHBvaW50cwpwbG90KGRlZ3JlZUNlbnRyYWxpdHksIFYoZykkbmNkYywgeGxhYj0nRGVncmVlJywgeWxhYj0nTkNEQycsIHBjaD0nJykKdGV4dCh4PWRlZ3JlZUNlbnRyYWxpdHksIHk9VihnKSRuY2RjLCBsYWJlbHM9VihnKSkKCiMgUGxvdCByYW5rIG9yZGVyaW5nLgpyZEMgPC0gcmFuayhkZWdyZWVDZW50cmFsaXR5KQpyTkNEQyA8LSByYW5rKFYoZykkbmNkYykKCnBsb3QocmRDLCByTkNEQywgeGxhYj0nRGVncmVlIFJhbmsnLCB5bGFiPSdOQ0RDIFJhbmsnLCBwY2g9JycpCnRleHQoeD1yZEMsIHk9ck5DREMsIGxhYmVscz1WKGcpKQpgYGAKCkxvYWQgdGhlIGthcmF0ZSBjbHViIGRhdGE6CmBgYHtyfQpkYXRhKGthcmF0ZSkKayA8LSBhcy51bmRpcmVjdGVkKGthcmF0ZSwgbW9kZT0nY29sbGFwc2UnKQogIAojIENhbGN1bGF0ZSBOQ0RDIGZvciBlYWNoIG5vZGUuCmEgPC0gbWF0cml4KGdldC5hZGphY2VuY3koayksIG5yb3c9dmNvdW50KGspKQpkZWdyZWVzIDwtIG1hdHJpeChkZWdyZWUoayksIG5yb3c9dmNvdW50KGspKQoKYTIgPC0gYSUqJWRlZ3JlZXMKClYoaykkbmNkYyA8LSBhMgoKIyBTYW1lIGFzIGFib3ZlLCB3aXRoIGEgbG9vcApWKGthcmF0ZSkkbmNkYzIgPC0gTkEKZm9yKGkgaW4gMTp2Y291bnQoaykpewogIHRvdGFsIDwtIDAKICBuIDwtIG5laWdoYm9ycyhrLCBWKGspW2ldKQogIGZvcihqIGluIDE6bGVuZ3RoKG4pKXsKICAgIGQgPC0gZGVncmVlKGssIHY9bltqXSkKICAgIHRvdGFsIDwtIHRvdGFsK2QKICB9CiAgVihrKSRuY2RjMltpXSA8LSB0b3RhbAp9CgojIENvbmZpcm0KVihrKSRuY2RjMiA9PSBWKGspJG5jZGMKCiMgTWFrZSBhIG5ldHdvcmsgcGxvdCB1c2luZyBhIHJpbmcgbGF5b3V0IHdoZXJlIGVhY2ggbm9kZSBpcyBzaXplZCBieSBOQ0RDLgpyIDwtIGxheW91dF9pbl9jaXJjbGUoaykKcGxvdChrLCBsYXlvdXQ9ciwgdmVydGV4LnNpemU9VihrKSRuY2RjLzUpCgojIFBsb3QgdGhlIGNvcnJlbGF0aW9uIG9mIE5DREMgYW5kIGRlZ3JlZSBjZW50cmFsaXR5LgpwbG90KGRlZ3JlZShrKSwgVihrKSRuY2RjLCBwY2g9JycsIHhsYWI9J0RlZ3JlZScsIHlsYWI9J05DREMnKQp0ZXh0KGRlZ3JlZShrKSwgVihrKSRuY2RjLCBsYWJlbD1WKGspJG5hbWUpCmBgYAoKCiMgQWxsIFN0ZXBzIENlbnRyYWxpdHkKSW4gdGhpcyBzZWN0aW9uLCB3ZSB3aWxsIGV4YW1pbmUgdGhlIGJldHdlZW5uZXNzIGFuZCBlaWdlbnZlY3RvciBjZW50cmFsaXR5IGZvciB0aGUga2FyYXRlIGNsdWIgbmV0d29yay4gIFNlZSBwYWdlIDk1IG9mIEx1a2UgMjAxNSBmb3IgYSBsaXN0IG9mIHRoZSBgaWdyYXBoYCBjZW50cmFsaXR5IGNvbW1hbmRzLgpgYGB7cn0KZGF0YShrYXJhdGUpCgojIEdldCBiZXR3ZWVubmVzcyBjZW50cmFsaXR5ClYoa2FyYXRlKSRiYyA8LSBiZXR3ZWVubmVzcyhrYXJhdGUsIGRpcmVjdGVkPUZBTFNFKQoKIyBHZXQgYmV0d2Vlbm5lc3MgY2VudHJhbGl0eSwgbm9ybWFsaXplZApWKGthcmF0ZSkkYmNfbm9ybSA8LSBiZXR3ZWVubmVzcyhrYXJhdGUsIGRpcmVjdGVkPUZBTFNFLCBub3JtYWxpemVkPVRSVUUpCgojIEdldCBlaWdlbnZlY3RvciBjZW50cmFsaXR5ClYoa2FyYXRlKSRlYyA8LSBldmNlbnQoa2FyYXRlKQoKIyBIbSwgaXQgZmFpbHMuICBXaHk/CmV2Y2VudChrYXJhdGUpCgojIE9rLCBpdCByZXR1cm5zIGEgbGlzdCwgYW5kIG9uZSBvZiB0aGUgbGlzdCBlbnRyaWVzIGlzIHRoZSBlaWdlbnZlY3RvciBjZW50cmFsaXR5LgpWKGthcmF0ZSkkZWMgPC0gZXZjZW50KGthcmF0ZSkkdmVjdG9yCgojIENvcnJlbGF0aW9uCmNvcihWKGthcmF0ZSkkYmMsIFYoa2FyYXRlKSRlYykKCiMjIFdoeSBkb2VzIHRoYXQgZmFpbD8gTGV0J3MgaW5zcGVjdC4KIyBMb29rcyBnb29kClYoa2FyYXRlKSRiYwojIFN0aWxsIHNhdmVkIGFzIGEgbGlzdC4KVihrYXJhdGUpJGVjCgojIEZpeC4gIEhhdmUgdG8gcmVtb3ZlIHRoZSBhdHRyaWJ1dGUgc28gdGhhdCBSIGRvZXMgbm90IHByZXNlcnZlIHRoZSBsaXN0IHN0cnVjdHVyZS4gIFRoYXQgaXMsIGVhcmxpZXIgSSBoYWQgbm90IHJlbW92ZWQgdGhlIGxpc3QsIHNvIFIganVzdCBhZGRlZCBhbiBlbnRyeSB0byB0aGF0IGxpc3QuCmthcmF0ZSA8LSByZW1vdmUudmVydGV4LmF0dHJpYnV0ZShrYXJhdGUsICdlYycpCgojdW5saXN0KCkgd2lsbCBmbGF0dGVuIHRoZSBsaXN0IHlvdSBnaXZlIGl0LgpWKGthcmF0ZSkkZWMgPC0gdW5saXN0KGV2Y2VudChrYXJhdGUpJHZlY3RvcikKCiMgQ29ycmVsYXRpb24KY29yKFYoa2FyYXRlKSRiYywgVihrYXJhdGUpJGVjKQoKIyBDb3JyZWxhdGlvbiBvZiBtdWx0aXBsZSB2YXJpYWJsZXMKY29yKGRhdGEuZnJhbWUoVihrYXJhdGUpJGJjLCBWKGthcmF0ZSkkZWMsIGRlZ3JlZShrYXJhdGUpKSkKYGBgCgpOb3csIHdlIHdpbGwgbWFrZSBwbG90czoKYGBge3J9CmwgPC0gbGF5b3V0LmZydWNodGVybWFuLnJlaW5nb2xkKGthcmF0ZSkKCiMgQmV0d2Vlbm5lc3MuICBOb2RlcyB3aWxsIGJlIHRvbyBiaWcKcGxvdChrYXJhdGUsIHZlcnRleC5zaXplPVYoa2FyYXRlKSRiYywgbWFpbj0iU2l6ZSBieSBCZXR3ZWVubmVzcyIsIGxheW91dD1sKQoKIyBCZXR3ZWVubmVzcy4gIERvd25zaXplIG5vZGVzCnBsb3Qoa2FyYXRlLCB2ZXJ0ZXguc2l6ZT1WKGthcmF0ZSkkYmMvMTAsIG1haW49IlNpemUgYnkgQmV0d2Vlbm5lc3MsIFJlc2NhbGUiLCBsYXlvdXQ9bCkKCiMgQmV0d2Vlbm5lc3MsIG5vcm1hbGl6ZWQuCiMgQWRkIG9uZSBzbyB0aGF0IHRoZXkgYXJlIG5vdCB0b28gc21hbGwuCnBsb3Qoa2FyYXRlLCB2ZXJ0ZXguc2l6ZT1WKGthcmF0ZSkkYmNfbm9ybSArIDEsIG1haW49IlNpemUgYnkgTm9ybWFsaXplZCBCZXR3ZWVubmVzcyIsIGxheW91dD1sKQoKIyBFaWdlbnZlY3RvcgpwbG90KGthcmF0ZSwgdmVydGV4LnNpemU9VihrYXJhdGUpJGVjKjEwLCBtYWluPSJTaXplIGJ5IEVpZ2VudmVjdG9yKjEwIiwgbGF5b3V0PWwpCgojIFBsb3QgQmV0d2Vlbm5lc3MgVmVyc3VzIEVpZ2VudmVjdG9yCiMgSSBjaGFuZ2UgdGhlIHhsaW1pdCBzbyB0aGF0IHRoZSB2ZXJ0ZXggbGFiZWxzIGFyZSBub3QgY3V0IG9mZi4KcGxvdChWKGthcmF0ZSkkYmMsIFYoa2FyYXRlKSRlYywgeGxhYj0nQmV0d2Vlbm5lc3MgQ2VudHJhbGl0eScsIHlsYWI9J0VpZ2VudmVjdG9yIENlbnRyYWxpdHknLCBwY2g9JycsIHhsaW09YygtMjAsIG1heChWKGthcmF0ZSkkYmMpKjEuMSkpCnRleHQoeD1WKGthcmF0ZSkkYmMsIHk9VihrYXJhdGUpJGVjLCBsYWJlbHM9VihrYXJhdGUpJG5hbWUpCgojIFdoYXQgaGFwcGVucyBpZiBJIGRvIG5vdCBjaGFuZ2UgdGhlIHggbGltaXQ/ICBXZSBzZWUgdGhlIGxhYmVscyBnZXQgY3V0IG9mZi4KcGxvdChWKGthcmF0ZSkkYmMsIFYoa2FyYXRlKSRlYywgeGxhYj0nQmV0d2Vlbm5lc3MgQ2VudHJhbGl0eScsIHlsYWI9J0VpZ2VudmVjdG9yIENlbnRyYWxpdHknLCBwY2g9JycpCnRleHQoeD1WKGthcmF0ZSkkYmMsIHk9VihrYXJhdGUpJGVjLCBsYWJlbHM9VihrYXJhdGUpJG5hbWUpCgojIFdlIGNhbiBjb2xvciB0aGUgdGV4dCBsYWJlbHMKY29sb3JzIDwtIGlmZWxzZShWKGthcmF0ZSkkY29sb3I9PTEsICdyZWQnLCAnYmxhY2snKQoKIyBTYW1lIHBsb3QgYXMgYWJvdmUsIGJ1dCBsZXQgdXMgYWxzbyBjb2xvciBieSBncm91cApwbG90KFYoa2FyYXRlKSRiYywgVihrYXJhdGUpJGVjLCB4bGFiPSdCZXR3ZWVubmVzcyBDZW50cmFsaXR5JywgeWxhYj0nRWlnZW52ZWN0b3IgQ2VudHJhbGl0eScsIHBjaD0nJywgeGxpbT1jKC0yMCwgbWF4KFYoa2FyYXRlKSRiYykqMS4xKSkKdGV4dCh4PVYoa2FyYXRlKSRiYywgeT1WKGthcmF0ZSkkZWMsIGxhYmVscz1WKGthcmF0ZSkkbmFtZSwgY29sPWNvbG9ycykKCmBgYAoKCioqV2hpY2ggbm9kZXMgaGF2ZSBoaWdoIGJldHdlZW5uZXNzIGFuZCBlaWdlbnZlY3RvciBjZW50cmFsaXR5PyoqCgoqKldoaWNoIG5vZGVzIGhhdmUgbG93IGJldHdlZW5uZXNzIGJ1dCBoaWdoIGVpZ2VudmVjdG9yIGNlbnRyYWxpdHk/KioKCioqV2hpY2ggbm9kZXMgaGF2ZSBoaWdoIGJldHdlZW5lc3MgYnV0IGxvdyBlaWdlbnZlY3RvciB2ZW50cmFsaXR5PyoqCgoKVGhlIGZvbGxvd2luZyBxdWVzdGlvbnMgdXNlIHRoZSBgVUtmYWN1bHR5YCBkYXRhLiAgUHJldGVuZCBsaWtlIHlvdSBoYXZlIG5vdCBsb2FkZWQgaXQgYWxyZWFkeS4gIE5vdGUgdGhhdCB5b3UgY291bGQgbWFrZSB0aGUgZ3JhcGggdW5kaXJlY3RlZCBvciB5b3UgY2FuIHRlbGwgZWFjaCBmdW5jdGlvbiB0byBhc3N1bWUgdGhlIGdyYXBoIGlzIG5vdCBkaXJlY3RlZDoKYGBge3J9CiMjIExvYWQgdGhlIFVLZmFjdWx0eSBkYXRhCmRhdGEoVUtmYWN1bHR5KQpnIDwtIGFzLnVuZGlyZWN0ZWQoVUtmYWN1bHR5LCBtb2RlPWMoJ2NvbGxhcHNlJykpCgojIyBDYWxjdWxhdGUgdGhlIGJldHdlZW5uZXNzIGNlbnRyYWxpdHkgb2YgZWFjaCBub2RlLgpWKGcpJGJjIDwtIGJldHdlZW5uZXNzKGcsIGRpcmVjdGVkPUZBTFNFKQpWKGcpJGJjX25vcm0gPC0gYmV0d2Vlbm5lc3MoZywgZGlyZWN0ZWQ9RkFMU0UsIG5vcm1hbGl6ZWQ9VFJVRSkKCiMjIENhbGN1bGF0ZSB0aGUgZWlnZW52ZWN0b3IgY2VudHJhbGl0eSBvZiBlYWNoIG5vZGUuClYoZykkZWMgPC0gZXZjZW50KGcpJHZlY3RvcgoKIyMgRHJhdyBhIG5ldHdvcmsgZ3JhcGgsIHNpemluZyBlYWNoIG5vZGUgYnkgYmV0d2Vlbm5lc3MgY2VudHJhbGl0eS4KZiA8LSBsYXlvdXQuZnJ1Y2h0ZXJtYW4ucmVpbmdvbGQoZykKcGxvdChnLCBsYXlvdXQ9ZiwgdmVydGV4LnNpemU9VihnKSRiYy8yNSkKCiMjIERyYXcgYSBuZXR3b3JrIGdyYXBoLCBzaXppbmcgZWFjaCBub2RlIGJ5IGVpZ2VudmVjdG9yIGNlbnRyYWxpdHkuCnBsb3QoZywgbGF5b3V0PWYsIHZlcnRleC5zaXplPVYoZykkZWMqNTApCgojIyBNYWtlIGEgc2NhdHRlcnBsb3Qgb2YgZWlnZW52ZWN0b3IgYW5kIGJldHdlZW5uZXNzIGNlbnRyYWxpdHkuICBMYWJlbCB0aGUgYXhlcy4gIERvIG5vdCBsYWJlbCB0aGUgcG9pbnRzLgpwbG90KFYoZykkYmMsIFYoZykkZWMsIHhsYWI9J0JldHdlZW5uZXNzIENlbnRyYWxpeScsIHlsYWI9J0VpZ2VudmVjdG9yIENlbnRyYWxpdHknKQoKIyMgUmVtYWtlIHRoZSBwcmV2aW91cyBzY2F0dGVycGxvdCwgbGFiZWxpbmcgdGhlIHBvaW50cy4gIFNwbGl0IHRoZW0gaW50byAyIGdyb3VwcyBhbmQgY29sb3IgdGhlbSBieSBncm91cC4KY29sb3JzIDwtIGlmZWxzZShWKGcpJEdyb3VwIDw9IDIsICdibHVlJywgJ29yYW5nZScpCnBsb3QoVihnKSRiYywgVihnKSRlYywgeGxhYj0nQmV0d2Vlbm5lc3MgQ2VudHJhbGl5JywgeWxhYj0nRWlnZW52ZWN0b3IgQ2VudHJhbGl0eScsIHBjaD0nJykKdGV4dChWKGcpJGJjLCBWKGcpJGVjLCBsYWJlbD1WKGcpJEdyb3VwLCBjb2w9Y29sb3JzKQpgYGAKCgoKCgoKCgoKCgoKCgoKIyMjIyBMT09QUwoKV3JpdGUgYSBsb29wIHRoYXQgcHJpbnRzIHRoZSBwaHJhc2UgIkhlbGxvIFdvcmxkIiB0ZW4gdGltZXMuCmBgYHtyfQpmb3IgKGluZGV4IGluIDE6MTApIHsgCiAgcHJpbnQoIkhlbGxvIFdvcmxkIikKfQpgYGAKCldyaXRlIGEgbG9vcCB0aGF0IHByaW50cyB0aGUgbnVtYmVyIG9mIHRoZSBsb29wIG11bHRpcGxpZWQgYnkgMTAuIEZvciBleGFtcGxlLCB0aGUgZmlyc3QgaXRlcmF0aW9uIHByaW50cyBgMTBgLCB0aGUgc2Vjb25kIGAyMGAsIGFuZCBzbyBvbi4gIERvIHRoaXMgcHJvY2VkdXJlIGZvciAyMCBpdGVyYXRpb25zLgpgYGB7cn0KZm9yICh0aGlzaXRlcmF0aW9uIGluIDE6MjApIHsKcHJpbnQodGhpc2l0ZXJhdGlvbiAqIDEwKSAKICB9CmBgYAoKYGBge3J9CmZvcihpIGluIDE6MTApeyAgIyBGb3IgZWFjaCBvZiB0ZW4gaXRlcmF0aW9ucwogIHByaW50KCdIZWxsbyB3b3JsZCcpICAjIHByaW50IHRoZSBwaHJhc2UsICJIZWxsbyB3b3JsZCIKICBwcmludCgyKmkpCn0gCgpmb3IoaSBpbiAxOjEyKXsKICBwcmludCgnaGVsbG8gd29ybGQnKQogIHByaW50KDIqaSkKfQpgYGAKCkhvdyB3b3VsZCB5b3UgY2hhbmdlIHRoZSBhYm92ZSBsb29wIHRvIHByaW50IGEgc3RhdGVtZW50IDIwIHRpbWVzPwpgYGB7cn0KZm9yKGkgaW4gMToyMCl7ICAjIEZvciBlYWNoIG9mIHR3ZW50eSBpdGVyYXRpb25zCiAgcHJpbnQoJ0hlbGxvIHdvcmxkJykgICMgcHJpbnQgdGhlIHBocmFzZSwgIkhlbGxvIHdvcmxkIgogIHByaW50KDIqaSkKfSAKYGBgCgpWZWN0b3JzIGFyZSBmYXN0ZXIgbG9vcHMuIElmIHlvdSBhcmUgZ29pbmcgdG8gY3JlYXRlIGEgdmVjdG9yIGR1cmluZyBhIGxvb3AsIGl0IG5lZWRzIHRvIGJlIGRlZmluZWQgYmVmb3JlIHRoZSBsb29wLgpgYGB7cn0Kb25lIDwtIGMoMTAsMjAsMjAsMTgsIDIwLCAzMCkKdHdvIDwtIGMoMSw1LDMsOSwgNTAsIDEwKQpyZXN1bHQgPC0gTlVMTCAKCmZvcihpIGluIDE6bGVuZ3RoKHR3bykpeyAgIyBOb3RpY2UgaG93IEkgZHluYW1pY2FsbHkgY2hhbmdlZAogIHByaW50KHJlc3VsdFtpXSA8LSBvbmVbaV0qdHdvW2ldKQp9Cgphc3ZlY3RvcnMgPC0gb25lKnR3bwoKcmVzdWx0ID09IGFzdmVjdG9ycwpgYGAKCmkgaXMgdXNlZCB0byBpbmRleCBwbGFjZSBieSBjb252ZW50aW9uLCBidXQgeW91IGNhbiB1c2UgYW55dGhpbmc6CmBgYHtyfQpmb3IoeiBpbiAxOjUpewogIHByaW50KHopCn0KCmZvcih3YXl0b29sb25naW5kZXggaW4gMTo1KXsKICBwcmludCh3YXl0b29sb25naW5kZXgpCn0KYGBgCgpZb3UgY291bGQgZXZlbiB1c2UgaXQgdG8gbWFrZSBhIGxvdCBvZiBncmFwaHMuIERvIG5vdCBmb3JnZXQgdG8gY2hhbmdlIHRoZSBmaWxlcGF0aCB0byBiZSB5b3VyIGNvbXB1dGVyLgpgYGB7cn0KZCA8LSByZWFkLmNzdigiaHR0cHM6Ly9zdGF0cy5pZHJlLnVjbGEuZWR1L3N0YXQvZGF0YS9oc2JyYXcuY3N2Iiwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQoKeWNvbHVtbnMgPC0gYygnd3JpdGUnLCAnbWF0aCcsICdzY2llbmNlJywgJ3NvY3N0JykKCgpmb3IoaSBpbiAxOmxlbmd0aCh5Y29sdW1ucykpewogIGZpbGVuYW1lIDwtIHBhc3RlMCgnfi9EZXNrdG9wL2xvb3BwbG90ZXhhbXBsZV8nLCB5Y29sdW1uc1tpXSwnLnBkZicpCiAgcGRmKGZpbGVuYW1lKQogIHBsb3QoZCRyZWFkLCBkW1t5Y29sdW1uc1tpXV1dLCBwY2g9MjAsIHhsYWI9J1JlYWRpbmcgU2NvcmUnLCB5bGFiPXljb2x1bW5zW2ldKQogIGRldi5vZmYoKQp9CgpxKCkKYGBgCgpJdCBpcyBoYXJkIHRvIGtlZXAgZWFjaCB2YWx1ZSBzdHJhaWdodCwgaG93ZXZlci4gIEFuZCBpZiB3ZSB3YW50IHRvIHJldHVybiB0byB0aGVzZSByZXN1bHRzIGxhdGVyLCB3ZSBuZWVkIHRvIHJlcnVuIHRoZSBsb29wLiAgRG9pbmcgc28gaXMgYW5ub3lpbmcgYW5kIHdpbGwgY3JlYXRlIHNsaWdodGx5IGRpZmZlcmVudCBhbnN3ZXJzIGJlY2F1c2Ugb2YgdGhlIHJhbmRvbSBudW1iZXIgZ2VuZXJhdG9yLiAgTGV0IHVzIGxlYXJuIGhvdyB0byBzYXZlIHRoZSBkYXRhIGFzIHRoZXkgYXJlIGNyZWF0ZWQuCgpJbiB0aGUgbG9vcCwgSSBzaG93IHR3byB3YXlzIHRvIGNyZWF0ZSB0aGUgZGF0YS4gIFRoZSBjb21tZW50ZWQgb25lLCB3aXRoIGAjYCBpbiBmcm9udCBvZiBpdCwgZG9lcyBub3QgcnVuIGJ1dCBtYXkgYmUgZWFzaWVyIHRvIHJlYWQuICBUbyB1c2UgaXQsIHJlbW92ZSB0aGUgYCNgIGZyb20gZWFjaCBsaW5lIGFuZCBwdXQgYCNgIGluIGZyb250IG9mIGxpbmVzIHRoYXQgYXJlIGN1cnJlbnRseSBleGVjdXRlZC4gIFRvIGFkZCBvciByZW1vdmUgY29tbWVudHMgdG8gbXVsdGlwbGUgbGluZXMsIGhpZ2hsaWdodCB0aGUgb25lcyB5b3Ugd2FudCB0byBjaGFuZ2UgYW5kIHR5cGUgYGNtZGArYGNgOyBvbiBhIFdpbmRvd3MgbWFjaGluZSwgeW91IHByb2JhYmx5IHdpbGwgcmVwbGFjZSBgY21kYCB3aXRoIHRoZSBmbGFnIGtleS4KYGBge3J9CnJhbmRvbW5lc3MgPC0gYyguMDEsIC4xLCAuMywgLjUsIC43LCAuOSwgMSkKaXRlcmF0aW9ucyA8LSBsZW5ndGgocmFuZG9tbmVzcykgICMgV2h5IGRpZCBJIGRlZmluZSBpdGVyYXRpb25zIHRoaXMgd2F5Pwpob3dtYW55cm93cyA8LSAxMDAKCnJlbWVtYmVyIDwtIGRhdGEuZnJhbWUoaXRlcmF0aW9uPU5VTEwsIHRpZVByb2JhYmlsaXR5PU5VTEwsIGF2Z0RlZ3JlZT1OVUxMLCBnbG9iYWxDbHVzdGVyaW5nPU5VTEwsIGdsYmFsQ2x1c3RlcmluZzI9TlVMTCwgZGVuc2l0eT1OVUxMKQoKZm9yKGkgaW4gMTppdGVyYXRpb25zKXsKICB0ZW1wIDwtIGVyZG9zLnJlbnlpLmdhbWUoaG93bWFueXJvd3MsIHA9cmFuZG9tbmVzc1tpXSkKICAKICBpdGVyYXRpb24gPC0gaQogIHRpZVByb2JhYmlsaXR5IDwtIHJhbmRvbW5lc3NbaV0KICBhdmdEZWdyZWUgPC0gbWVhbihkZWdyZWUodGVtcCkpCiAgZ2xvYmFsQ2x1c3RlcmluZyA8LSB0cmFuc2l0aXZpdHkodGVtcCwgdHlwZT0nZ2xvYmFsJykKICBnbG9iYWxDbHVzdGVyaW5nMiA8LSBtZWFuKHRyYW5zaXRpdml0eSh0ZW1wLCB0eXBlPSdsb2NhbCcpKQogIGRlbnNpdHkgPC0gZ3JhcGguZGVuc2l0eSh0ZW1wKQogICMgCiAgIyBkIDwtIGRhdGEuZnJhbWUoaXRlcmF0aW9uPWksIHRpZVByb2JhYmlsaXR5PXJhbmRvbW5lc3NbaV0sIGF2Z0RlZ3JlZT1tZWFuKGRlZ3JlZSh0ZW1wKSksIGdsb2JhbENsdXN0ZXJpbmc9dHJhbnNpdGl2aXR5KHRlbXAsIHR5cGU9J2dsb2JhbCcpLCBnbG9iYWxDbHVzdGVyaW5nMj1tZWFuKHRyYW5zaXRpdml0eSh0ZW1wLCB0eXBlPSdsb2NhbCcpKSwgZGVuc2l0eT1ncmFwaC5kZW5zaXR5KHRlbXApKQogIAogIGQgPC0gZGF0YS5mcmFtZShpdGVyYXRpb249aXRlcmF0aW9uLCB0aWVQcm9iYWJpbGl0eT10aWVQcm9iYWJpbGl0eSwgYXZnRGVncmVlPWF2Z0RlZ3JlZSwgZ2xvYmFsQ2x1c3RlcmluZz1nbG9iYWxDbHVzdGVyaW5nLCBnbG9iYWxDbHVzdGVyaW5nMj1nbG9iYWxDbHVzdGVyaW5nMiwgZGVuc2l0eT1kZW5zaXR5KQogIHJlbWVtYmVyIDwtIHJiaW5kKHJlbWVtYmVyLCBkKSAgIyAicm93YmluZCIsIGFkZHMgYSBuZXcgcm93LCBkLCB0byB3aGF0ZXZlciBleGlzdHMgaW4gcmVtZW1iZXIuCiAgI3ByaW50KHJlbWVtYmVyKQp9CgpyZW1lbWJlciAjIENvb2wuCgpgYGAKClVzZSBhIGxvb3AgYW5kIGlncmFwaCB0byBjcmVhdGUgcmFuZG9tIG5ldHdvcmtzLiAgVmFyeSB0aGUgcHJvYmFiaWxpdHkgb2YgZm9ybWluZyBhbiBlZGdlIDEwIHRpbWVzLiAgUHV0IHNvbWUgcmVzdWx0aW5nIHN0YXRpc3RpY3MgaW4gYSBkYXRhZnJhbWUuIApgYGB7cn0KcmVtZW1iZXIyIDwtIGRhdGEuZnJhbWUoaXRlcmF0aW9uPU5VTEwsIHRpZVByb2JhYmlsaXR5PU5VTEwsIGF2Z0RlZ3JlZT1OVUxMLCBnbG9iYWxDbHVzdGVyaW5nPU5VTEwsIGdsYmFsQ2x1c3RlcmluZzI9TlVMTCwgZGVuc2l0eT1OVUxMKQoKdGhlcHMgPC0gYyguMDEsIC4xLCAuMiwgLjMsIC40LCAuNSwgLjYsIC43LCAuOCwgLjkpCml0ZXJhdGlvbnMgPC0gbGVuZ3RoKHRoZXBzKQoKZm9yKGkgaW4gMTppdGVyYXRpb25zKXsKICB0ZW1wIDwtIGVyZG9zLnJlbnlpLmdhbWUoaG93bWFueXJvd3MsIHA9cmFuZG9tbmVzc1tpXSkKICAKICAjIGl0ZXJhdGlvbiA8LSBpCiAgIyB0aWVQcm9iYWJpbGl0eSA8LSByYW5kb21uZXNzW2ldCiAgIyBhdmdEZWdyZWUgPC0gbWVhbihkZWdyZWUodGVtcCkpCiAgIyBnbG9iYWxDbHVzdGVyaW5nIDwtIHRyYW5zaXRpdml0eSh0ZW1wLCB0eXBlPSdnbG9iYWwnKQogICMgZ2xvYmFsQ2x1c3RlcmluZzIgPC0gbWVhbih0cmFuc2l0aXZpdHkodGVtcCwgdHlwZT0nbG9jYWwnKSkKICAjIGRlbnNpdHkgPC0gZ3JhcGguZGVuc2l0eSh0ZW1wKQogICMgCiAgZCA8LSBkYXRhLmZyYW1lKGl0ZXJhdGlvbj1pLCB0aWVQcm9iYWJpbGl0eT1yYW5kb21uZXNzW2ldLCBhdmdEZWdyZWU9bWVhbihkZWdyZWUodGVtcCkpLCBnbG9iYWxDbHVzdGVyaW5nPXRyYW5zaXRpdml0eSh0ZW1wLCB0eXBlPSdnbG9iYWwnKSwgZ2xvYmFsQ2x1c3RlcmluZzI9bWVhbih0cmFuc2l0aXZpdHkodGVtcCwgdHlwZT0nbG9jYWwnKSksIGRlbnNpdHk9Z3JhcGguZGVuc2l0eSh0ZW1wKSkKICAKICAjIGQgPC0gZGF0YS5mcmFtZShpdGVyYXRpb249aXRlcmF0aW9uLCB0aWVQcm9iYWJpbGl0eT10aWVQcm9iYWJpbGl0eSwgYXZnRGVncmVlPWF2Z0RlZ3JlZSwgZ2xvYmFsQ2x1c3RlcmluZz1nbG9iYWxDbHVzdGVyaW5nLCBnbG9iYWxDbHVzdGVyaW5nMj1nbG9iYWxDbHVzdGVyaW5nMiwgZGVuc2l0eT1kZW5zaXR5KQogIHJlbWVtYmVyMiA8LSByYmluZChyZW1lbWJlcjIsIGQpICAjICJyb3diaW5kIiwgYWRkcyBhIG5ldyByb3csIGQsIHRvIHdoYXRldmVyIGV4aXN0cyBpbiByZW1lbWJlci4KICAjcHJpbnQocmVtZW1iZXIpCn0KCnJlbWVtYmVyMgoKbnJvdyhyZW1lbWJlcjIpCm5yb3cocmVtZW1iZXIpCmBgYAoKVmFyeSBwYXJhbWV0ZXJzIHVzaW5nIGEgbG9vcDoKYGBge3J9CnJhbmRvbW5lc3MgPC0gYyguMDEsIC4xLCAuMywgLjUsIC43LCAuOSwgMSkKaXRlcmF0aW9ucyA8LSBsZW5ndGgocmFuZG9tbmVzcykgICMgV2h5IGRpZCBJIGRlZmluZSBpdGVyYXRpb25zIHRoaXMgd2F5Pwpob3dtYW55cm93cyA8LSAxMDAKCiMgV2lsbCBub3Qgc2hvdyBhbnl0aGluZwpmb3IoaSBpbiAxOml0ZXJhdGlvbnMpewogIHRlbXAgPC0gZXJkb3MucmVueWkuZ2FtZShob3dtYW55cm93cywgcD1yYW5kb21uZXNzW2ldKQogIHN1bW1hcnkoZGVncmVlKHRlbXApKQogIHRyYW5zaXRpdml0eSh0ZW1wLCB0eXBlPSdnbG9iYWwnKQogIG1lYW4odHJhbnNpdGl2aXR5KHRlbXAsIHR5cGU9J2xvY2FsJykpCiAgZ3JhcGguZGVuc2l0eSh0ZW1wKQp9CgojIE5lZWQgdG8gcHJpbnQKZm9yKGkgaW4gMTppdGVyYXRpb25zKXsKICB0ZW1wIDwtIGVyZG9zLnJlbnlpLmdhbWUoaG93bWFueXJvd3MsIHA9cmFuZG9tbmVzc1tpXSkKICBwcmludChwYXN0ZTAoJ09uIHRyaWFsICcsIGkpKSAgIyBUaGlzIGxpbmUgbGV0cyBtZSBrbm93IHdoaWNoIGl0ZXJhdGlvbiBJIGFtIG9uCiAgcHJpbnQoJ1N1bW1hcnkgU3RhdGlzdGljczonKQogIHByaW50KHN1bW1hcnkoZGVncmVlKHRlbXApKSkKICBwcmludChwYXN0ZTAoJ0dsb2JhbCBjbHVzdGVyaW5nIGlzOiAnLCB0cmFuc2l0aXZpdHkodGVtcCwgdHlwZT0nZ2xvYmFsJykpKQogIHByaW50KCdBdmVyYWdlIG9mIHRoZSBlYWNoIG5vZGVcJ3MgY2x1c3RlcmluZyBpczogJykgICMgTWF5YmUgeW91IGZpbmQgaXQgZWFzaWVyIHRvIHJlYWQgdGhlIG91dHB1dCB0aGlzIHdheQogIHByaW50KG1lYW4odHJhbnNpdGl2aXR5KHRlbXAsIHR5cGU9J2xvY2FsJyksIG5hLnJtPVRSVUUpKQogIHByaW50KHBhc3RlMCgnVGhlIGdyYXBoXCdzIGRlbnNpdHkgaXM6ICcsIGdyYXBoLmRlbnNpdHkodGVtcCkpKQp9CmBgYAoKCgoKCgoKCgoKCgoKIyMjIyBLRVlXT1JEUwoKCjEuICoqU2NyaXB0KiogLSBUaGUgdGV4dCBkb2N1bWVudCB0aGF0IGNvbnRhaW5zIHRoZSBjb21tYW5kcy4gIEl0IGNhbiBiZSBpbiBhbnkgZm9ybWF0LCB0aG91Z2ggdXN1YWxseSB5b3Ugd2lsbCBzZWUgLnR4dCBvciAuUi4KCjIuICoqQ29uc29sZSoqIC0gV2hlcmUgeW91IHNlZSB0aGUgY29kZSBydW4gd2hlbiBpdCBpcyBleGVjdXRlZC4gIEluIFIgU3R1ZGlvLCB0aGUgY29uc29sZSBpcyB0aGUgdG9wIHJpZ2h0IHdpbmRvdyBieSBkZWZhdWx0LgoKMy4gKipWZWN0b3IqKiAtIFRoZSBiYXNpYyBidWlsZGluZyBibG9jayBvZiBSLCBhIHZlY3RvciBpcyBhIHNlcXVlbmNlIG9mIGl0ZW1zIHRoYXQgeW91IHdpbGwgbWFuaXB1bGF0ZS4gIEEgdmVjdG9yIGNhbiBjb250YWluIGFzIGZldyBhcyBvbmUgaXRlbQoKNC4gKipPYmplY3QqKiAtIFIgaXMgd2hhdCBpcyBrbm93biBhcyBhbiAib2JqZWN0LW9yaWVudGVkIGxhbmd1YWdlIi4gIFRoaXMgbWVhbnMgdGhlcmUgYXJlIGFic3RyYWN0IGVudGl0aXRlcyAtIHRoZSBvYmplY3RzIC0gdGhhdCBjb250YWluIHRoZSBkYXRhIG9uIHdoaWNoIHlvdSB3b3JrLiAgQW4gZW50aXR5IGNvdWxkIGJlIGEgZGF0YXNldCwgYSBsaXN0IG9mIG51bWJlcnMsIGEgZGF0YWJhc2UsIG9yIGFueXRoaW5nIGVsc2UuCgo1LiAqKkRhdGFmcmFtZSoqIC0gVGhlIHByaW1hcnkgdHlwZSBvZiBvYmplY3QgdXNlZCB0byByZXByZXNlbnQgZGF0YSBpbiBSLiAgVGhpbmsgb2YgYSBkYXRhZnJhbWUgYXMgYSBzcHJlYWRzaGVldDogaXQgaGFzIHJvd3MgYW5kIGNvbHVtbnMsIHdoZXJlIGVhY2ggcm93IHJlcHJlc2VudHMgYSB1bml0IG9mIGFuYWx5c2lzIHdpdGggcmVjb3JkcyBmb3IgZWFjaCBvZiB0aGUgY29sdW1ucyAodGhlIG1lYXN1cmVkIHZhcmlhYmxlcykuICBBIGRhdGFmcmFtZSBpcyBhIGNvbGxlY3Rpb24gb2YgdmVjdG9ycy4gQSBkYXRhZnJhbWUgaXMgYSBtYXRyaXggd2hvc2UgdmVjdG9ycyBjYW4gYmUgZGlmZmVyZW50IGRhdGEgdHlwZXMsIHN1Y2ggYXMgc3RyaW5ncyBhbmQgbnVtYmVycy4gCgo2LiAqKlN0cmluZyoqIC0gSWYgc29tZXRoaW5nIGlzIGEgInN0cmluZyIsIHRoYXQgbWVhbnMgaXQgaXMgYSB3b3JkLiAgQSBzdHJpbmcgaXMgaW4gY29udHJhc3QgdG8gbnVtZXJpYyBkYXRhLgoKNy4gKipQYWNrYWdlKiogLSBBIHNldCBvZiBjb2RlIHRoYXQgZXh0ZW5kcyB0aGUgZnVuY3Rpb25hbGl0eSBvZiBiYXNlIFIuICBFYWNoIHBhY2thZ2Ugd2lsbCBoYXZlIGEgZGlmZmVyZW50IHB1cnBvc2UsIGFuZCB0aGUgY2xhcml0eSBvZiB0aGUgZG9jdW1lbnRhdGlvbiwgYXMgd2VsbCBhcyBmdW5jdGlvbmFsaXR5IG9mIHRoZSBjb2RlLCBpcyBhdCB0aGUgd2hpbSBvZiB0aGUgcGFja2FnZSdzIGNyZWF0b3IuICBBbGwgcGFja2FnZXMgYXJlIGZyZWUgdG8gdXNlLgoKOC4gKipEZWJ1ZyoqLCAqKlJlZmFjdG9yKiogLSBUaGVzZSB0d28gd29yZHMgYXJlIGZhbmN5IHdheXMgb2Ygc2F5aW5nIHlvdSBhcmUgZmluZGluZyBhbmQgY29ycmVjdGluZyBlcnJvcnMgaW4geW91ciBjb2RlLgoKOS4gKipMaXN0KiogLSBBIGxpc3QgaXMgYSBjb2xsZWN0aW9uIG9mIHZlY3RvcnMuICBXaGVyZWFzIGEgdmVjdG9yIG11c3QgY29udGFpbiBkYXRhIG9mIHRoZSBzYW1lIHR5cGUsIGEgbGlzdCBjYW4gY29udGFpbiB2ZWN0b3JzIG9mIGRpZmZlcmVudCB0eXBlcyAoZWFjaCB2ZWN0b3Igc3RpbGwgbXVzdCBvbmx5IGNvbnRhaW4gb25lIGRhdGEgdHlwZSkuCgoxMC4gKipNYXRyaXgqKiAtIEEgbWF0cml4IGlzIGEgc2VyaWVzIG9mIHZlY3RvcnMgb2YgbnVtZXJpYyBkYXRhLiAgQSBtYXRyaXggaGFzIHRvIGNvbnRhaW4gbnVtZXJpYyBkYXRhLiAgVGhleSBhcmUgaW1wb3J0YW50IGJlY2F1c2UgdGhleSBjYW4gcmVwcmVzZW50IHJlbGF0aW9uc2hpcHMgaW4gYSBuZXR3b3JrLCBzbyBjb25zdHJ1Y3RpbmcgYW5kIG1hbmlwdWxhdGluZyB0aGVtIGlzIGltcG9ydGFudCBmb3IgbmV0d29yayBhbmFseXNpcy5TaW5jZSB3ZSBub3cgaGF2ZSBhbiBvYmplY3Qgd2l0aCB0d28gZGltZW5zaW9ucyAocm93cyBhbmQgY29sdW1ucyksIHdlIGFjY2VzcyB0aGVtIGRpZmZlcmVudGx5IHRoYW4gd2UgZGlkIHZlY3RvcnMuIEEgd2hvbGUgcm93IGlzIGBvYmplY3Rbcm93bnVtYmVyLF1gLCBhIHdob2xlIGNvbHVtbiBpcyBgb2JqZWN0Wyxjb2x1bW51bWJlcl1gLCBhbmQgYSBzcGVjaWZpYyBjZWxsIGlzIGBvYmplY3Rbcm93LCBjb2x1bW5dYC4KCjExLiAqKnRpZHl2ZXJzZSoqIC0gaXMgYWN0dWFsbHkgYSBzZXJpZXMgb2YgcGFja2FnZXMgY3JlYXRlZCBieSBIYWRsZXkgV2lja2hhbSwgdGhlIHR3byBtb3N0IGNvbW1vbiBvZiB3aGljaCBhcmUgYGRwbHlyYCBmb3IgZGF0YSBtZXJnaW5nIGFuZCBhZ2dyZWdhdGlvbiBhbmQgYGdncGxvdGAgZm9yIGdlbmVyYXRpbmcgZ3JhcGhpY3MuICBUbyBrZWVwIGZyb20gb3ZlcmxvYWRpbmcgeW91IHdpdGggaW5mb3JtYXRpb24sIEkgd2lsbCBub3QgYWN0dWFsbHkgdXNlIHRoZSBgdGlkeXZlcnNlYCBpbiB0aGlzIGNsYXNzLCBidXQgaXQgaXMgcXVpdGUgY29tbW9uIGluIHRoZSBSIHdvcmxkLiAgYGlncmFwaGAgaXMgdGhlIG5ldHdvcmsgcGFja2FnZSB0aGF0IHdlIHdpbGwgdXNlIHRocm91Z2hvdXQgdGhlIHF1YXJ0ZXIuCgpJbiBhZGRpdGlvbiB0byB1c2luZyBjb2RlLCB5b3UgY2FuIGFsc28gdXNlIGEgZ3JhcGhpY2FsIGludGVyZmFjZSB0byBpbnN0YWxsIHBhY2thZ2VzLiAgSW4gYmFzZSBSLCBjbGljayBgUGFja2FnZXMgJiBEYXRhYCwgdGhlbiBgUGFja2FnZSBJbnN0YWxsZXJgLiAgWW91IGNhbiB0aGVuIHNlYXJjaCBmb3IgdGhlIHBhY2thZ2UgYnkgbmFtZS4gIEluIFIgU3R1ZGlvLCBuYXZpZ2F0ZSB0byBgVG9vbHNgLCB0aGVuIGBJbnN0YWxsIFBhY2thZ2VzYCwgYW5kIHNlYXJjaCBmb3IgdGhlIHBhY2thZ2UgYnkgbmFtZS4gIEJlbG93J3MgY29kZSBzaG93cyBob3cgdG8gZG8gdGhpcyBwcm9jZXNzIGluIHlvdXIgc2NyaXB0LlteMV0KClteMV06IElmIHlvdSBsb29rIGF0IHRoZSBSIE1hcmtkb3duIGZpbGUsIHlvdSB3aWxsIG5vdGljZSB0aGUgb3B0aW9uICJldmFsPUZBTFNFIiwgd2hlcmVhcyB0aGUgb3RoZXIgY29kZSBjaHVua3MgdXNlICJldmFsPVRSVUUiLiAgYGV2YWxgIHRlbGxzIFIgTWFya2Rvd24gd2hldGhlciBvciBub3QgdG8gZXhlY3V0ZSB0aGUgY29kZSBpbiB0aGF0IGNodW5rLiAgU2luY2UgSSBkbyBub3Qgd2FudCB0byBpbnN0YWxsIHRoZXNlIHBhY2thZ2VzIGV2ZXJ5IHRpbWUgSSBjb21waWxlIHRoZSBkb2N1bWVudCwgSSBzZXQgaXQgdG8gYEZBTFNFYCBoZXJlLgoKMTIuICoqQ1NWKiogLSBUaGUgbWFpbiBraW5kIG9mIGRhdGEgeW91IHdpbGwgcmVhZCBpcyBgLmNzdmAsIHdoaWNoIHN0YW5kcyBmb3IgY29tbWEtc2VwYXJhdGVkIHZhbHVlcy4gIEl0IGlzIGEgdGV4dCBmaWxlIHdoZXJlIGVhY2ggY29sdW1uIGlzIHNlcGFyYXRlZCBieSBhIGNvbW1hLiAgTWFrZSBzdXJlIHlvdSBjaGFuZ2UgdGhlIGZpbGUgcGF0aCB0byBiZSB0byB3aGVyZSB5b3VyIGRhdGEgYXJlLiAgTm90ZSB0aGF0IHJlYWQgYHJlYWQuYCBsaW5lIHdvcmtzOyB0aGUgcG9pbnQgaXMgdGhhdCBgcmVhZC5jc3ZgIGlzIGEgc3BlY2lhbCBjYXNlIG9mIGByZWFkLmRlbGltYC4gIFRoaXMgZGlzdGluY3Rpb24gbWF0dGVycyBiZWNhdXNlIHlvdSBjb3VsZCBoYXZlIGRhdGEgdGhhdCBhcmUgc2VwYXJhdGVkIGJ5IGEgZmVhdHVyZSB0aGF0IGlzIG5vdCBhIGNvbW1hLCBsaWtlIGEgdGFiIG9yIHwuCgoxMy4gKipMb29wcyoqIC0gWW91IHVzZSBsb29wcyB3aGVuIHlvdSB3YW50IHRvIHJlcGVhdCBhIHBpZWNlIG9mIGNvZGUgbXVsdGlwbGUgdGltZXMuICBGb3IgZXhhbXBsZSwgbGF0ZXIgaW4gdGhlIGNvdXJzZSB3ZSB3aWxsIHJ1biBuZXR3b3JrIHNpbXVsYXRpb25zIHdoZXJlIHdlIHdhbnQgdG8gc2VlIGhvdyBhbiBvdXRjb21lIGRpZmZ1c2VzIG92ZXIgdGltZTsgZWFjaCB1bml0IG9mIHRpbWUgd2lsbCBjb3JyZXNwb25kIHRvIG9uZSBpdGVyYXRpb24gb2YgdGhlIGxvb3AuICBPciB5b3UgbWF5IGhhdmUgYSBsaXN0IG9mIGZpbGVzIHRvIHJlYWQsIHNvIHlvdSB3aWxsIGxvb3Agb3ZlciB0aGF0IGxpc3QgaW4gb3JkZXIgdG8gbG9hZCB0aGVtIG9uZSBhdCBhIHRpbWUuICBXaGlsZSBpdCBpcyBiZXN0IHRvIHVzZSB2ZWN0b3Igb3BlcmF0aW9ucyB3aGVuZXZlciBwb3NzaWJsZSwgbG9vcHMgY2FuIGJlIG1vcmUgaW50dWl0aXZlLiAgCgo=