1.0 Introduction
This script can be used to create bi-plots and Harker plots of all
tephra major elemental data. It includes: tips for flitering data,
interactive exploration of the data, more complex plots, using kernel
densities to delimit chemical envelopes, and some discussion on
identifying useful elements for discrimination via multivariate
analysis. Guidance for saving plots as .svg or .pdf files is also
provided. All the code used to produce this document is downloadable as
an RMarkdown file to the right of this page and should appear for each
specific plot generated. To run this you will require r and RStudio. We
are happy for you to use, share and improve our code, but would ask that
you cite this as a point of origin for the code.
Load packages
We first load in packages required to generate the plots and
manipulate the data. You may need to install these packages in r or
update them to work correctly.
library(ggplot2)
library(factoextra)
library(readr)
library(psych)
library(compositions)
library(gganimate)
library(cowplot)
library(tidyverse)
library(gt)
library(plotly)
library(svglite)
library(png)
library(here)
library(ggdensity)
library(ggrepel)
library(viridis)
2.0 Loading your data
Data should be placed within a ‘Data’ folder created in your project
directory. As this is a Markdown script the ‘here’ package is used to
ensure that project links do not break when moving scripts around,
however you may not need to do this if you have a preferred data storage
approach. As long as you start a new R project and drop this script into
it then set up ‘Data’ and ‘Script’ folders then it will work. Data files
should be in .csv format and contain the group of the tephra as column 1
under the title “id” (see console output below for format). Loaded here
are some data for core ODP-980 in the North Atlantic and a terrestrial
site from the UK called MT. These data were published by Candy et
al. (2021) and the paper can be found here.
chem <- here::here("Data","ODP_norm.csv") %>% read.csv()
2.1 Check your data has loaded correctly
We can first just inspect the data in the console using the ‘head’
command, and then summarise it using the describe function of the psych
package. These commands produce a couple of basic tables which should
allow you to check whether you have correctly loaded the data you wish
to analyse.
head(chem)
## id SiO2 TiO2 Al2O3 FeO MnO MgO
## 1 50.65-50.69 52.79290 3.62976406 13.17806 13.984674 0.26214963 3.98265779
## 2 50.65-50.69 71.85240 0.30401510 12.67428 4.665059 0.16773247 0.06289968
## 3 50.65-50.69 76.69421 0.08264463 11.67355 1.508264 0.05165289 0.02066116
## 4 50.65-50.69 76.76455 0.15455951 11.89078 2.071097 0.04121587 0.05151983
## 5 50.65-50.69 49.75570 3.87825733 12.85627 15.054967 0.24429967 4.80456026
## 6 50.65-50.69 71.67439 0.31942298 12.84905 4.420402 0.16486347 0.06182380
## CaO Na2O K2O P2O5 Total IRD
## 1 8.2173825 2.520669 0.7864489 0.65537407 100 YES
## 2 1.1741273 5.493238 3.5852815 0.02096656 100 YES
## 3 0.3099174 3.584711 6.0743802 0.00000000 100 YES
## 4 0.5461103 4.399794 4.0803709 0.01030397 100 YES
## 5 9.1307003 3.145358 0.6616450 0.46824104 100 YES
## 6 1.2570840 5.461103 3.7712519 0.02060793 100 YES
describe(chem)
## vars n mean sd median trimmed mad min max range skew
## id* 1 240 8.44 4.44 9.00 8.58 4.45 1.00 15.00 14.00 -0.25
## SiO2 2 240 66.45 9.91 72.00 67.31 2.84 48.10 78.07 29.98 -0.83
## TiO2 3 240 1.10 1.19 0.45 0.90 0.27 0.08 3.88 3.80 1.15
## Al2O3 4 240 11.86 2.08 12.70 12.03 1.11 7.07 15.62 8.55 -0.80
## FeO 5 240 7.69 4.70 7.22 7.37 5.46 1.42 17.13 15.71 0.56
## MnO 6 240 0.21 0.08 0.23 0.21 0.07 0.03 0.60 0.57 -0.06
## MgO 7 240 1.43 2.14 0.12 1.09 0.19 -0.03 7.54 7.58 1.08
## CaO 8 240 3.27 3.79 1.00 2.78 0.93 0.25 12.12 11.87 0.93
## Na2O 9 240 4.80 1.28 5.18 4.86 1.32 2.16 6.94 4.78 -0.39
## K2O 10 240 3.03 1.63 3.75 3.13 0.97 0.20 6.83 6.62 -0.57
## P2O5 11 240 0.16 0.25 0.03 0.11 0.03 -0.01 1.37 1.38 2.11
## Total 12 240 100.00 0.00 100.00 100.00 0.00 100.00 100.00 0.00 NaN
## IRD* 13 240 1.15 0.36 1.00 1.06 0.00 1.00 2.00 1.00 1.95
## kurtosis se
## id* -1.16 0.29
## SiO2 -1.10 0.64
## TiO2 -0.26 0.08
## Al2O3 -0.81 0.13
## FeO -1.11 0.30
## MnO 1.43 0.01
## MgO -0.54 0.14
## CaO -0.95 0.24
## Na2O -1.24 0.08
## K2O -1.14 0.11
## P2O5 5.06 0.02
## Total NaN 0.00
## IRD* 1.80 0.02
2.2 Better tables in r.
The main problem with the console output from r is that produces
tables that are not pretty to view. This can largely be addressed by the
‘gt’ package which produces far nicer output in an html format. The
following script produces a summary table of mean values and number of
analyses in your data.
layer |
n |
SiO2. |
sd1 |
TiO2. |
sd2 |
Al2O3. |
sd3 |
FeOt |
sd4 |
MnO. |
sd5 |
MgO. |
sd6 |
CaO. |
sd7 |
Na2O. |
sd8 |
K2O. |
sd9 |
P2O5. |
sd10 |
Total. |
sd11 |
50.65-50.69 |
22 |
65.98 |
11.52 |
1.29 |
1.49 |
12.24 |
1.51 |
7.40 |
5.36 |
0.17 |
0.09 |
1.77 |
2.46 |
3.82 |
4.12 |
4.20 |
1.20 |
2.94 |
1.99 |
0.19 |
0.24 |
100 |
0 |
50.93-50.97 |
14 |
72.64 |
2.53 |
0.35 |
0.15 |
11.41 |
2.58 |
4.83 |
2.32 |
0.19 |
0.09 |
0.09 |
0.13 |
0.70 |
0.35 |
5.59 |
0.68 |
4.17 |
0.60 |
0.03 |
0.03 |
100 |
0 |
51.09-51.13 |
15 |
58.55 |
11.65 |
2.35 |
1.69 |
12.22 |
1.45 |
11.81 |
6.20 |
0.23 |
0.06 |
2.85 |
2.32 |
5.88 |
4.33 |
3.86 |
1.39 |
1.97 |
1.88 |
0.27 |
0.21 |
100 |
0 |
51.25-51.29 |
7 |
73.67 |
1.78 |
0.29 |
0.11 |
12.83 |
0.53 |
3.05 |
0.80 |
0.12 |
0.05 |
0.15 |
0.11 |
1.18 |
0.47 |
4.77 |
0.73 |
3.91 |
0.78 |
0.03 |
0.02 |
100 |
0 |
52.91-52.95 |
7 |
57.96 |
9.78 |
2.31 |
1.32 |
12.62 |
1.74 |
11.53 |
4.08 |
0.25 |
0.04 |
2.75 |
1.89 |
5.96 |
3.59 |
4.18 |
1.16 |
1.87 |
1.56 |
0.56 |
0.57 |
100 |
0 |
53.13-53.17 |
14 |
71.61 |
3.99 |
0.50 |
0.37 |
11.88 |
2.20 |
5.25 |
2.54 |
0.19 |
0.06 |
0.30 |
0.53 |
1.38 |
1.53 |
5.19 |
0.67 |
3.61 |
0.88 |
0.10 |
0.22 |
100 |
0 |
54.01-54.05 |
16 |
66.29 |
8.41 |
1.04 |
0.97 |
11.83 |
2.89 |
7.88 |
3.42 |
0.23 |
0.06 |
1.26 |
1.93 |
2.94 |
3.31 |
5.18 |
1.19 |
3.18 |
1.46 |
0.16 |
0.18 |
100 |
0 |
54.13-54.21 |
18 |
62.43 |
10.16 |
1.38 |
1.01 |
12.42 |
1.97 |
9.21 |
4.20 |
0.22 |
0.06 |
2.43 |
2.49 |
5.09 |
4.35 |
4.38 |
1.39 |
2.25 |
1.66 |
0.19 |
0.18 |
100 |
0 |
54.37-54.41 |
15 |
61.27 |
10.76 |
1.35 |
0.99 |
12.42 |
1.44 |
10.05 |
5.19 |
0.22 |
0.05 |
2.79 |
2.71 |
5.53 |
4.57 |
4.11 |
1.51 |
2.12 |
1.97 |
0.13 |
0.10 |
100 |
0 |
54.53-54.57 |
19 |
66.01 |
10.21 |
1.10 |
1.12 |
11.35 |
2.64 |
7.90 |
3.78 |
0.23 |
0.06 |
1.63 |
2.42 |
3.36 |
4.18 |
5.15 |
1.38 |
3.12 |
1.59 |
0.16 |
0.21 |
100 |
0 |
54.57-54.61 |
20 |
70.90 |
5.51 |
0.50 |
0.56 |
11.48 |
2.30 |
5.77 |
3.13 |
0.22 |
0.11 |
0.33 |
1.18 |
1.43 |
2.18 |
5.55 |
0.90 |
3.78 |
1.04 |
0.04 |
0.08 |
100 |
0 |
54.79-54.83 |
21 |
68.39 |
10.41 |
0.95 |
1.21 |
11.79 |
1.73 |
6.56 |
4.87 |
0.18 |
0.09 |
1.25 |
2.22 |
2.80 |
3.86 |
4.80 |
1.19 |
3.19 |
1.58 |
0.10 |
0.14 |
100 |
0 |
55.11-55.15 |
14 |
67.78 |
9.43 |
1.02 |
1.33 |
11.86 |
1.83 |
7.05 |
4.81 |
0.21 |
0.07 |
1.02 |
1.89 |
2.57 |
3.43 |
5.08 |
1.19 |
3.32 |
1.53 |
0.11 |
0.18 |
100 |
0 |
55.31-55.35 |
21 |
62.97 |
10.71 |
1.42 |
1.18 |
11.57 |
2.32 |
10.05 |
4.77 |
0.25 |
0.07 |
1.97 |
2.13 |
4.44 |
4.05 |
4.51 |
1.39 |
2.45 |
1.76 |
0.38 |
0.41 |
100 |
0 |
55.79-55.87 |
17 |
70.24 |
7.86 |
0.75 |
1.16 |
11.16 |
2.24 |
6.28 |
4.05 |
0.20 |
0.08 |
0.63 |
1.59 |
1.87 |
2.86 |
5.20 |
1.14 |
3.59 |
1.29 |
0.09 |
0.17 |
100 |
0 |
2.3 Make TAS calculations
To calculate for the TAS plot the data require normalisation of the
data. The data used here has been normalised already so this step is
largely redundant, but this is not the case for all tephra data and you
might prefer to utilise unormalised data for your analyses, especially
if you are interested in the effects of analytical totals on your data.
This code does not modify your orignal data so can be safely run for
both normalised and unormalised data. It is required for the TAS plot so
should be run regardless of the state of your data.
TAS_x <- (100/ chem [["Total"]]) * chem [["SiO2"]]
TAS_y <- (100/ chem [["Total"]]) * (chem [["K2O"]] + chem [["Na2O"]])
chem <- cbind(chem, TAS_x, TAS_y)
3.0 Filtering data
It is possible your datasheet contains multiple types of tephra
chemistry which would benefit from filtering before plotting. I suggest
this is carried out initially by using silica values as a divisor.
Rhyolites >68% silica would be a case for this. However, it might be
worth plotting everything first before then selecting a filter to ensure
vital data is not being excluded. Here we continue with all data being
plotted before filtering later in the script when making
comparisons.
#chem <- filter(chem, SiO2 >68) ## code is commented order to retain all data at this stage.
4.0 Plotting your data
First we generate a series of plots from all possible pairs of
elements.
p1 <- ggplot(chem, aes(x = TAS_x, y = TAS_y, fill = id, shape = id)) # this uses the TAS calculations made earlier in step 2.3.
p2 <- ggplot(chem, aes(x = SiO2, y = TiO2, fill = id, shape = id))
p3 <- ggplot(chem, aes(x = SiO2, y = Al2O3, fill = id, shape = id))
p4 <- ggplot(chem, aes(x = SiO2, y = FeO, fill = id, shape = id))
p5 <- ggplot(chem, aes(x = SiO2, y = MnO, fill = id, shape = id))
p6 <- ggplot(chem, aes(x = SiO2, y = MgO, fill = id, shape = id))
p7 <- ggplot(chem, aes(x = SiO2, y = CaO, fill = id, shape = id))
p8 <- ggplot(chem, aes(x = SiO2, y = Na2O, fill = id, shape = id))
p9 <- ggplot(chem, aes(x = SiO2, y = K2O, fill = id, shape = id))
p47 <- ggplot(chem, aes(x = SiO2, y = K2O, fill = id, shape = id))
p10 <- ggplot(chem, aes(x = SiO2, y = P2O5, fill = id, shape = id))
p11 <- ggplot(chem, aes(x = TiO2, y = Al2O3, fill = id, shape = id))
p12 <- ggplot(chem, aes(x = TiO2, y = FeO, fill = id, shape = id))
p13 <- ggplot(chem, aes(x = TiO2, y = MnO, fill = id, shape = id))
p14 <- ggplot(chem, aes(x = TiO2, y = MgO, fill = id, shape = id))
p15 <- ggplot(chem, aes(x = TiO2, y = CaO, fill = id, shape = id))
p16 <- ggplot(chem, aes(x = TiO2, y = Na2O, fill = id, shape = id))
p17 <- ggplot(chem, aes(x = TiO2, y = K2O, fill = id, shape = id))
p18 <- ggplot(chem, aes(x = TiO2, y = P2O5, fill = id, shape = id))
p19 <- ggplot(chem, aes(x = Al2O3, y = FeO, fill = id, shape = id))
p20 <- ggplot(chem, aes(x = Al2O3, y = MnO, fill = id, shape = id))
p21 <- ggplot(chem, aes(x = Al2O3, y = MgO, fill = id, shape = id))
p22 <- ggplot(chem, aes(x = Al2O3, y = CaO, fill = id, shape = id))
p23 <- ggplot(chem, aes(x = Al2O3, y = Na2O, fill = id, shape = id))
p24 <- ggplot(chem, aes(x = Al2O3, y = K2O, fill = id, shape = id))
p25 <- ggplot(chem, aes(x = Al2O3, y = P2O5, fill = id, shape = id))
p26 <- ggplot(chem, aes(x = FeO, y = MnO, fill = id, shape = id))
p27 <- ggplot(chem, aes(x = FeO, y = MgO, fill = id, shape = id))
p28 <- ggplot(chem, aes(x = FeO, y = CaO, fill = id, shape = id))
p29 <- ggplot(chem, aes(x = FeO, y = Na2O, fill = id, shape = id))
p30 <- ggplot(chem, aes(x = FeO, y = K2O, fill = id, shape = id))
p31 <- ggplot(chem, aes(x = FeO, y = P2O5, fill = id, shape = id))
p32 <- ggplot(chem, aes(x = MnO, y = MgO, fill = id, shape = id))
p33 <- ggplot(chem, aes(x = MnO, y = CaO, fill = id, shape = id))
p34 <- ggplot(chem, aes(x = MnO, y = Na2O, fill = id, shape = id))
p35 <- ggplot(chem, aes(x = MnO, y = K2O, fill = id, shape = id))
p36 <- ggplot(chem, aes(x = MnO, y = P2O5, fill = id, shape = id))
p37 <- ggplot(chem, aes(x = MgO, y = CaO, fill = id, shape = id))
p38 <- ggplot(chem, aes(x = MgO, y = Na2O, fill = id, shape = id))
p39 <- ggplot(chem, aes(x = MgO, y = K2O, fill = id, shape = id))
p40 <- ggplot(chem, aes(x = MgO, y = P2O5, fill = id, shape = id))
p41 <- ggplot(chem, aes(x = CaO, y = Na2O, fill = id, shape = id))
p42 <- ggplot(chem, aes(x = CaO, y = K2O, fill = id, shape = id))
p43 <- ggplot(chem, aes(x = CaO, y = P2O5, fill = id, shape = id))
p44 <- ggplot(chem, aes(x = Na2O, y = K2O, fill = id, shape = id))
p45 <- ggplot(chem, aes(x = Na2O, y = P2O5, fill = id, shape = id))
p46 <- ggplot(chem, aes(x = K2O, y = P2O5, fill = id, shape = id))
4.1 Custom tephra theme
To ensure consistency and to provide a shortcut of coding it
everytime we set up a custom tephra plotting theme. This means all of
our plots will have the same sized fonts etc…
Tephra.theme <-theme_bw()+theme(axis.title.x=element_text(size=16),
axis.title.y=element_text(size=16),
axis.text.x=element_text(size=16),
axis.text.y=element_text(size=16))+
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank())
4.2 Custom colour palette
The hex numbers below specify a custom colour palette for plotting.
These can be altered but were slected in order to help those with colour
vision deficiencies, and this should be considered when making changes.
At present 35 layers can be plotted using this pallete. If you have more
than 35 groups of data you will either have to specify additional
colours or consider splitting your dataset. The latter might be more
appropriate for improving the final clarity in the plots.
chempalette <- c("#209A24","#A769EE","#B4C428","#e30303","#000000","#EF139D","#3A700F","#5288FF","#E64701","#7F9AF5","#F36D20","#0B3075","#C18522","#9634A6","#1D7D46","#80ddb8","#7CBC92","#B10E89","#384B27","#F896FD","#C6A766","#20628E","#9C0323","#C3AFE0","#572D24","#FF79A2","#3E6D6F","#E18C63","#6F2B40","#DF9FB4", "#291700", "#7e005b", "#00597a" , "#7b003a", "#470600")
The palette is known as “chempalette”.
5.0 Biplots
We first generate the simple bi-plots of each element. This initial
explorative approach facilitates data checking for unusual analyses and
permits the identification of elements with significant variability.
TAS plot Le Maitre et al. (2002)

SiO2 VS TiO2

SiO2 VS Al2O3

SiO2 VS FeO

SiO2 VS MnO

SiO2 VS MgO

SiO2 VS CaO

SiO2 VS Na2O

SiO2 VS K2O


SiO2 VS P2O5

TiO2 VS Al2O3

TiO2 vs FeO

TiO2 vs MnO

TiO2 VS MgO

TiO2 VS CaO

TiO2 VS Na2O

TiO2 VS K2O

TiO2 VS P2O5

Al2O3 VS FeO

Al2O3 VS MnO

Al2O3 VS MgO
p21 <- p21 + geom_point(aes(fill = id), size=4, alpha=0.8)+xlab("Al2O3 (wt%)")+ylab("MgO (wt%)")+scale_shape_manual(values=c(21:25, 21:25, 21:25, 21:25, 21:25, 21:25, 21:25, 21:25, 21:25, 21:25))+
scale_fill_manual(values = chempalette) +
Tephra.theme
p21

Al2O3 VS CaO

Al2O3 VS Na2O

Al2O3 VS K2O

Al2O3 VS P2O5

FeO VS MnO

FeO vs MgO

FeO vs CaO

FeO VS Na2O

FeO VS K2O

FeO VS P2O5

MnO VS MgO

MnO VS CaO

MnO VS Na2O

MnO VS K2O

MnO VS P2O5

MgO VS CaO

MgO VS Na2O

MgO VS K2O

MgO VS P2O5

CaO VS Na2O

CaO VS K2O

CaO VS P2O5

Na2O VS K2O

Na2O VS P2O5

K2O VS P2O5

5.1 Saving plots
We propose exporting your individual plots in .svg format. This is a
vector file format that preserves your data without size and scaling
issues. It is also readable and editable by software like Adobe
Illustrator, Affinity Designer, or free alternatives like Inkscape.
Using the file structure presented here the all plots can be named
appropriately and will be saved in the Output -> Plots folder. The
width and height and dpi outputs can be altered but override the preview
functions in Rstudio and we recommend that you view the svg file
directly in you preferred image editor to understand how it might
look.
ggsave( filename = file.path("Script", "Output","Plots","fig1.svg"), plot = p1, width = 12, height = 6, dpi = 300)
6.0 Multivariate analysis
Multivariate analysis via ordination is often a helpful way of
exploring your data. It permits the identification of useful elements
for discrimination and facilitates dimension reduction. Unfortunately,
percentage data can have problematic covariation and should be ‘freed’
from their compositional sum where possible. This can be achieved via
undertaking a centred log-ratio transform. This is performed using the
code given below
chem_multi <- chem[ -c(1,6,11,12,13,14,15)] ## check columns to drop. Currently dropping id, MnO, P2O5, Total, and TAS calculations to perform the clr transform.
chem_multi[is.na(chem_multi)] <- 0.005 # replace NAs with half the detection limit
chem_multi_clr <- clr(chem_multi)
cmclr <- as.data.frame(chem_multi_clr)
head(cmclr) # This permits us the opportunity to view the centred log-ratio dataset.
## SiO2 TiO2 Al2O3 FeO MgO CaO Na2O
## 1 2.135807 -0.5414021 0.7479836 0.80739231 -0.4486203 0.2756820 -0.9060452
## 2 3.332329 -2.1329626 1.5972904 0.59781585 -3.7084990 -0.7817596 0.7612333
## 3 3.996737 -2.8362948 2.1142366 0.06787029 -4.2225892 -1.5145389 0.9335885
## 4 3.716439 -2.4914800 1.8514592 0.10377467 -3.5900923 -1.2292383 0.8572538
## 5 2.026855 -0.5248841 0.6735616 0.83143798 -0.3107045 0.3313724 -0.7343422
## 6 3.317036 -2.0963366 1.5981721 0.53113307 -3.7385644 -0.7263028 0.7425532
## K2O
## 1 -2.0707973
## 2 0.3345523
## 3 1.4609906
## 4 0.7818840
## 5 -2.2932962
## 6 0.3723095
We can summarise the importance of the resulting principal components
by summarizing how much of the total variance is captured by each
principal component.
6.1 PCA summary
Information |
PC1 |
PC2 |
PC3 |
PC4 |
PC5 |
PC6 |
PC7 |
PC8 |
Standard deviation |
2.452866 |
1.286943 |
0.5993116 |
0.1933593 |
0.1054135 |
0.07061895 |
0.06210361 |
4.673909e-16 |
Proportion of Variance |
0.743770 |
0.204740 |
0.0444000 |
0.0046200 |
0.0013700 |
0.00062000 |
0.00048000 |
0.000000e+00 |
Cumulative Proportion |
0.743770 |
0.948510 |
0.9929100 |
0.9975300 |
0.9989100 |
0.99952000 |
1.00000000 |
1.000000e+00 |
If this has captured a significant amount of variation it would be
worth plotting the output in order to identify the important variables
in determining the changes observed.
6.3 PCA scores scree plot

This is a visual representation of the summary table showing the
percentage of the total variance explained by each dimension.
6.4 Variables PCA plot

6.5 Loadings dimension 1

6.6 Loadings dimension 2

6.7 PCA - Biplot

6.8 PCA - grouped
## Scale for 'shape' is already present. Adding another scale for 'shape', which
## will replace the existing scale.

8.0 Saving all figures to a .pdf
l <- list(p1, p2, p3, p4, p5, p6, p7, p8, p9, p47, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33, p34, p35, p36, p37, p38, p39, p40, p41, p42, p43, p44, p45, p46)
pdf("allplotsout.pdf", width = 12, height = 6)
invisible(lapply(l, print))
dev.off()
## png
## 2
9.0 Harker plot
It is frequently useful to plot all of the collected elemental data
against SiO[2]. This permits an assessment of groupings within the data
and which elements might be useful discriminators. Additionally, wt% K2O
vs SiO2 can further classify the tephra to low, mid and high Potassium
values. The dividing lines included here are from xxxxxxxx.
g1 <- plot_grid(p1 + theme(legend.position = "none"),
p2 + theme(legend.position = "none"),
p3 + theme(legend.position="none"),
p4 + theme(legend.position="none"),
p5 + theme(legend.position="none"),
p6 + theme(legend.position="none"),
p7 + theme(legend.position="none"),
p8 + theme(legend.position="none"),
p47 + theme(legend.position="none"),
p10 + theme(legend.position="none"),
labels = c("A", "B", "C", "D", "E", "F", "G", "H", "I", "J"), align = "b")
legend <- get_legend(p1)
legplot <- plot_grid(legend)
px <- plot_grid( g1, rel_widths = c(4, 1))
l2 <- list(px,legplot)
pdf("Script/Output/Plots/Harkerplot.pdf", width = 30, height = 20)
invisible(lapply(l2, print))
dev.off()
## png
## 2
ggsave( filename = file.path("Script","Output","Plots","Harker.svg"), plot = px, width = 30, height = 20, dpi = 300)
print(g1)

10.0 Other useful plots
10.1 Creating an inset within a figure
p100 <- ggplot(chem, aes(x = TAS_x, y = TAS_y, fill = id, shape = id))
p100 <- p100 + geom_point(aes(fill = id), size=4, alpha=0.8)+xlab("SiO2 (wt%)")+ylab("Na2O+K2O (wt%)")+
scale_shape_manual(values=c(21:25, 21:25, 21:25, 21:25, 21:25, 21:25, 21:25, 21:25, 21:25, 21:25))+
scale_fill_manual(values = chempalette) +geom_segment(x=77,y=0,xend=69,yend=8)+
geom_segment(x=69, y=8,xend=69,yend=13)+geom_segment(x=41, y=7,xend=52.5,yend=14)+
geom_segment(x=52.5,y=14,xend=57.6,yend=11.7)+geom_segment(x=45,y=0,xend=45,yend=5)+
geom_segment(x=45,y=5,xend=63,yend=14.56)+geom_segment(x=52,y=0,xend=52,yend=5)+
geom_segment(x=52,y=5,xend=63,yend=7)+geom_segment(x=57,y=0,xend=57,yend=5.9)+
geom_segment(x=63,y=0,xend=63,yend=7)+geom_segment(x=45,y=5,xend=52,yend=5)+
geom_segment(x=52,y=5,xend=49.4,yend=7.3)+geom_segment(x=57,y=5.9,xend=53,yend=9.3)+
geom_segment(x=63,y=7,xend=57.6,yend=11.7)+geom_segment(x=49.4,y=7.3,xend=45,yend=9.4)+
geom_segment(x=53,y=9.3,xend=48.4,yend=11.5)+geom_segment(x=41,y=0,xend=41,yend=7)+
geom_segment(x=52.5,y=14,xend=49,yend=15.5)+geom_segment(x=41,y=3,xend=45,yend=3)+
geom_segment(x=63,y=7,xend=69,yend=8)+
scale_x_continuous(limits=c(74, 79), expand = c(0, 0)) + ## set x axis of insert
scale_y_continuous(limits=c(6, 10.5), expand = c(0, 0)) + ## set y axis of insert
theme_bw()+theme(axis.title.x=element_text(size=9), axis.title.y=element_text(size=9),
axis.text.x=element_text(size=9), axis.text.y=element_text(size=9))+ ## change the text size as neccessary
theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(), legend.position = "none")
fig_in <- p1 + annotation_custom(ggplotGrob(p100), xmin = 40, xmax = 56, ymin = 7, ymax = 16) + ## place the insert
annotate("rect", xmin = 74, xmax = 79, ymin = 6, ymax = 10.5,
alpha = .2) ## use this to highlight the area of the insert plot
ggsave( filename = file.path("Script", "Output","Plots","insert_plot.svg"), plot = fig_in, width = 10, height = 6, dpi = 300)
print(fig_in)

10.2 Creating a HDR plot to simplify your data.
Simplifying the data we create to make more visually compelling
figures can be achieved using highest density regions. The following
code permits this as an addition to the previously created plots and as
new plots. It can be added easily to any of the previously created plots
by changing the p code. Visibility of the density regions can be applied
to just reference data or entire datasets. Opacity is varied using the
alpha command and the probability range can be altered in the ‘probs’
argument. You may need to vary the x and y axes in order to fit the full
range in to the plot. These types of plots are best used for giving
better eruptive chemical envelopes (fields) than hand drawing around
existing data.
p28den <- p28 +
geom_hdr(stat= "hdr", method = "kde", na.rm = TRUE, inherit.aes = TRUE, alpha = 0.3, xlim = c(0,100), ylim = c(0,30), smooth = TRUE, n = 1000, probs = c(0.75))
print(p28den)

10.3 Faceted plots to deal with lots of data
The kde plots are interesting but messy and still have lots of
overplotting. This is not ideal for data visualisation. While it may be
helpful to vary the colours or opacity, there is only so much that this
can acheive. If you have particularly messy data like the ODP-980
dataset I’d suggest creating plot ‘facets’ using the following code.
p28den_facet <- p28 +
geom_hdr(method = "kde", alpha = 0.5, xlim = c(0,100), ylim = c(0,30), show.legend = FALSE, smooth = TRUE, n = 1000, probs = c(0.95)) +
facet_wrap(~ id)
print(p28den_facet)

The facet removes some of the complexity and permits the kde to be
visualised more clearly, but arguably you lose some of the key
information about total ranges of chemical data. In the second faceted
plot (below) we remove the kernel density information and use the total
dataset as a background to the facets in order to understand the total
range and our own individual samples. This requires a little bit of data
manipulation in order to create two datasets, one for the total data
spread and another for the facets.
chem2 <- dplyr::select(chem, -Total) # creates the second dataset fpr plotting
chem2 <- rename(chem2, id2=id) # removes confusion over column names
f19 <- ggplot(chem, aes(x = FeO, y = CaO, fill = id, shape = id)) # creates a new plot of FeO and CaO.
f19 <- f19 +
geom_point(data = chem2, inherit.aes = FALSE, aes(x=FeO, y = CaO, shape = id2), colour = "grey70") + ## adds all the data to the plot using a grey colour scheme
geom_point(aes(fill = id), size=4, alpha=0.8)+xlab("FeO (wt%)")+ylab("CaO (wt%)")+scale_shape_manual(values=c(21:25, 21:25, 21:25, 21:25, 21:25, 21:25, 21:25, 21:25, 21:25, 21:25))+ # adds all the data again but retain the groups
scale_fill_manual(values = chempalette) + ## adds standard colours
Tephra.theme + # adds standard theme
coord_cartesian(xlim = c(0,20), ylim = c(0,15)) + # scale the plots to display the data effectively
facet_wrap(~ id) # facets the diagram using id in the main dataset.
print(f19)

ggsave( filename = file.path("Script", "Output","Plots","faceted plot.pdf"), plot = f19, width = 30, height = 20, units = "cm", dpi = 300)
11.0 Comparing unknown samples
All of the above code can be used on unknown samples and for your own
data exploration. It can also be used to explore a reference dataset in
order to understand what chemical plots can be used to best
differentiate tephra from different volcanoes and even different
eruptions. However, some times it is better to keep the exploration and
analysis phases separate. This section looks at importing a specific
unknown tephra and making direct comparisons to a reference dataset. It
uses the ODP-980 data presented above as a record of volcanism in the
North Atlantic during MIS-11c and then compares this with our unknown
tephra from a site in England called Marks Tey. First we load and
summarise the data as before but then we look at filtering and
presenting the data more clearly.
This code loads our unknown data from a normalised dataset called
MT_norm.csv. We then present all of the data in a table.
unknowns <- here::here("Data","MT_norm.csv") %>% read.csv()
gt(unknowns)
id2 |
SiO2 |
TiO2 |
Al2O3 |
FeO |
MnO |
MgO |
CaO |
Na2O |
K2O |
P2O5 |
Total |
MT-15.47 |
77.46191 |
0.12271193 |
11.66786 |
2.147459 |
0.07158196 |
0.00000000 |
0.7874016 |
4.591472 |
3.149606 |
0.00000000 |
100 |
MT-15.47 |
77.52786 |
0.12158055 |
11.24620 |
2.249240 |
0.05065856 |
0.02026343 |
0.7294833 |
4.528875 |
3.515704 |
0.01013171 |
100 |
MT-15.47 |
77.59528 |
0.13955985 |
11.70156 |
2.190016 |
0.07514761 |
0.03220612 |
0.7407407 |
4.551798 |
2.973698 |
0.01073537 |
100 |
MT-15.47 |
77.23816 |
0.11152793 |
11.84224 |
2.220420 |
0.06083342 |
0.00000000 |
0.6894454 |
4.430701 |
3.406671 |
0.01013890 |
100 |
MT-15.47 |
77.40131 |
0.12433945 |
11.94695 |
2.124132 |
0.06216972 |
0.07253134 |
0.6320589 |
4.403689 |
3.212102 |
0.01036162 |
100 |
MT-15.47 |
77.05858 |
0.12507817 |
11.79904 |
1.928289 |
0.09380863 |
0.01042318 |
0.7504690 |
4.732124 |
3.481343 |
0.01042318 |
100 |
MT-15.47 |
76.96308 |
0.12480499 |
11.93968 |
2.132085 |
0.08320333 |
0.00000000 |
0.7696308 |
4.492980 |
3.473739 |
0.02080083 |
100 |
MT-15.47 |
77.23074 |
0.12597103 |
11.11694 |
2.466933 |
0.05248793 |
0.05248793 |
0.8188117 |
4.797397 |
3.327735 |
0.00000000 |
100 |
MT-15.47 |
77.54255 |
0.14893617 |
11.34043 |
2.297872 |
0.08510638 |
0.05319149 |
0.6702128 |
4.808511 |
3.063830 |
0.00000000 |
100 |
MT-15.47 |
75.02112 |
0.08449514 |
13.45585 |
1.373046 |
0.06337136 |
-0.02112378 |
0.7498944 |
4.002957 |
5.259823 |
0.01056189 |
100 |
MT-15.47 |
77.76506 |
0.12485694 |
11.50765 |
1.966497 |
0.07283321 |
0.04161898 |
0.6867131 |
4.557278 |
3.267090 |
0.01040474 |
100 |
MT-15.47 |
77.22352 |
0.12736149 |
11.83401 |
2.133305 |
0.06368075 |
0.02122692 |
0.7004882 |
4.733602 |
3.173424 |
0.00000000 |
100 |
MT-15.47 |
78.07481 |
0.12433945 |
11.36670 |
2.041239 |
0.08289296 |
0.00000000 |
0.6527821 |
4.403689 |
3.253549 |
0.01036162 |
100 |
MT-15.47 |
77.86376 |
0.13236941 |
11.55687 |
2.026270 |
0.05091131 |
0.01018226 |
0.6720293 |
4.470013 |
3.197230 |
0.01018226 |
100 |
MT-15.47 |
77.59115 |
0.13314216 |
11.68578 |
1.915199 |
0.06145022 |
0.00000000 |
0.6964359 |
4.475625 |
3.430971 |
0.01024170 |
100 |
MT-15.47 |
77.21947 |
0.13723213 |
11.89697 |
2.216827 |
0.07389423 |
-0.02111264 |
0.8022802 |
4.496991 |
3.156339 |
0.01055632 |
100 |
MT-15.47 |
77.39612 |
0.12528712 |
11.67258 |
2.213406 |
0.09396534 |
0.01044059 |
0.6264356 |
4.740029 |
3.111297 |
0.01044059 |
100 |
MT-15.47 |
76.98995 |
0.12568077 |
11.86636 |
2.199413 |
0.08378718 |
0.01047340 |
0.6912442 |
4.639715 |
3.382907 |
0.02094680 |
100 |
MT-15.47 |
77.37722 |
0.13584117 |
11.58830 |
2.361546 |
0.06269592 |
0.03134796 |
0.8045977 |
4.420063 |
3.218391 |
0.01044932 |
100 |
Like before this is useful to use to understand that our data has
loaded correctly, but a summary table might be more useful. This is
performed using the code from section 2.2.
unknown_sum <- unknowns %>% group_by(id2) %>% dplyr::summarise(
count=n(),
SiO2.= mean(SiO2),
sd1 = sd(SiO2),
TiO2. = mean(TiO2),
sd2 = sd(TiO2),
Al2O3. = mean(Al2O3),
sd3 = sd(Al2O3),
FeOt = mean(FeO),
sd4 = sd(FeO),
MnO.= mean(MnO),
sd5 = sd(MnO),
MgO.= mean(MgO),
sd6 = sd(MgO),
CaO.= mean(CaO),
sd7 = sd(CaO),
Na2O. = mean(Na2O),
sd8 = sd(Na2O),
K2O. = mean(K2O),
sd9 = sd(K2O),
P2O5. = mean(P2O5),
sd10 = sd(P2O5),
Total.=mean(Total),
sd11 = sd(Total))
unknown_sum <- unknown_sum %>% mutate(across(where(is.numeric), ~ round(., digits = 2)))
unknown_sum %>% rename(layer = id2, n = count , SiO2 = SiO2., TiO2 = TiO2.)
## # A tibble: 1 x 24
## layer n SiO2 sd1 TiO2 sd2 Al2O3. sd3 FeOt sd4 MnO. sd5 MgO.
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 MT-1~ 19 77.3 0.62 0.13 0.01 11.7 0.48 2.12 0.23 0.07 0.01 0.02
## # ... with 11 more variables: sd6 <dbl>, CaO. <dbl>, sd7 <dbl>, Na2O. <dbl>,
## # sd8 <dbl>, K2O. <dbl>, sd9 <dbl>, P2O5. <dbl>, sd10 <dbl>, Total. <dbl>,
## # sd11 <dbl>
gt(unknown_sum)
id2 |
count |
SiO2. |
sd1 |
TiO2. |
sd2 |
Al2O3. |
sd3 |
FeOt |
sd4 |
MnO. |
sd5 |
MgO. |
sd6 |
CaO. |
sd7 |
Na2O. |
sd8 |
K2O. |
sd9 |
P2O5. |
sd10 |
Total. |
sd11 |
MT-15.47 |
19 |
77.29 |
0.62 |
0.13 |
0.01 |
11.74 |
0.48 |
2.12 |
0.23 |
0.07 |
0.01 |
0.02 |
0.03 |
0.72 |
0.06 |
4.54 |
0.19 |
3.37 |
0.48 |
0.01 |
0.01 |
100 |
0 |
We evidently have a relatively homogenous highly silicic tephra with
average silica values of 77.29 %wt and FeOt values below 3%wt. We could
undertake further plots to check this out, but it might also be an
examination of the tabular data is sufficient for this purpose. This
helps us to filter our possible correlatives. We can also restrict our
possible correlatives using other stratigraphic and chronological data.
This might be plausible time windows that the tephra could occur or
other factors. The ODP-980 data have some additional information that
might aid some discrimination. The publication lists sections of Ice
rafted debris (IRD) which reflect mixtures of ash layers and therefore
not primary tephra deposits. We will exclude these here in order to only
deal with potential primary ash layers.
chem_red <- filter(chem, IRD == "NO") #We might want to filter our data by age or other stratigraphic information. here we are excluding layers identified as ice rafted debris. This can be achieved using additional columns in the input data sheet. All of the plotting code will ignore these unless told otherwise.
chem_red <- filter(chem_red, SiO2 >68 & FeO <4) # Our unknown sample is a rhyolite so we can now employ our filtering by value, we can also exclude some of the high iron examples in the ODP-980 dataset.
c28 <- ggplot(chem_red, aes(x = SiO2, y = CaO, fill = id, shape = id)) # create a new plot using the reduced chemical comparison data
c28 <- c28 +
geom_hdr(method = "kde", alpha = 0.4, xlim = c(0,100), ylim = c(0,30), show.legend = TRUE, smooth = TRUE, n = 500, probs = c(0.95), color = "black") + # Add the ODP-980 data as a kde field for comparison this uses 95% probability ranges for comparison.
scale_fill_viridis(discrete = TRUE) + # We will use the Viridis scale for now as this gives relatively good differentiation.
geom_point(data = unknowns, inherit.aes = FALSE, aes(x=SiO2, y = CaO, shape = id2, fill = id2), size=4, alpha=0.7, show.legend = FALSE) + # we take our unknown data and plot it as points
xlab("SiO2 (wt%)") + # Label our axes
ylab("CaO (wt%)") +
scale_shape_manual(values=c(1:5,7,11, 21:25, 21:25, 21:25, 21:25, 21:25, 21:25, 21:25, 21:25, 21:25)) +
Tephra.theme # add the tephra theme.
print(c28)
We can see that only samples 54.79-54.83 and 51.09-51.13 have any
overlap with our unknown at 95% probability. It is worth noting here
that this is in part down to our filtering of the data in the previous
step. We need to be sure that we are not excluding important data when
undertaking this step otehrwise our resulting kdes can be strongly
altered. Therefore it is also sensible to plot the raw point data for
comparison also. The interactive plot below uses the same elements but
permits exploration of the data. From this we can see that 54.79-54.83
is the best match for our sample on these elements.
u28 <- ggplot(chem_red, aes(x = SiO2, y = CaO, fill = id, shape = id))
u28 <- u28 + geom_point(aes(fill = id), size=4, alpha=0.8)+xlab("SiO2 (wt%)")+ylab("CaO (wt%)")+scale_shape_manual(values=c(21:25, 21:25, 21:25, 21:25, 21:25, 21:25, 21:25, 21:25, 21:25, 21:25))+
geom_point(data = unknowns, inherit.aes = FALSE, aes(x=SiO2, y = CaO, shape = id2, fill = id2), size=4, alpha=0.8) +
scale_fill_manual(values = chempalette) +
Tephra.theme
ggplotly(u28, width = 1000, height = 800)
References
R. W. Le Maitre (editor), A. Streckeisen, B. Zanettin, M. J. Le Bas,
B. Bonin, P. Bateman, G. Bellieni, A. Dudek, S. Efremova, J. Keller, J.
Lamere, P. A. Sabine, R. Schmid, H. Sorensen, and A. R. Woolley, Igneous
Rocks: A Classification and Glossary of Terms, Recommendations of the
International Union of Geological Sciences, Subcommission of the
Systematics of Igneous Rocks. Cambridge University Press, 2002.
Papers using versions of this code.
Walsh, A.A., Blockley, S.P., Milner, A.M. and Martin-Puertas, C.,
2023. Updated age constraints on key tephra markers for NW Europe based
on a high-precision varve lake chronology. Quaternary Science Reviews,
300, p.107897. read
it here
Carter‐Champion, A., Abrook, A.M., Pike, J.H., Matthews, I.P.,
Palmer, A.P. and Lowe, J.J., 2022. Ice‐sheet deglaciation and Loch
Lomond Readvance in the eastern Cairngorms: implications of a
Lateglacial sediment record from Glen Builg. Journal of Quaternary
Science, 37(8), pp.1332-1347. read it
here
Walsh, A.A., Blockley, S.P., Milner, A.M., Matthews, I.P. and
Martin-Puertas, C., 2021. Complexities in European Holocene cryptotephra
dispersal revealed in the annually laminated lake record of Diss Mere,
East Anglia. Quaternary Geochronology, 66, p.101213. read
it here
Palmer, A.P., Matthews, I.P., Lowe, J.J., MacLeod, A. and Grant, R.,
2020. A revised chronology for the growth and demise of Loch Lomond
Readvance (‘Younger Dryas’) ice lobes in the Lochaber area, Scotland.
Quaternary Science Reviews, 248, p.106548.read
it here
Lowe, J., Matthews, I., Mayfield, R., Lincoln, P., Palmer, A., Staff,
R. and Timms, R., 2019. On the timing of retreat of the Loch Lomond
(‘Younger Dryas’) Readvance icefield in the SW Scottish Highlands and
its wider significance. Quaternary Science Reviews, 219, pp.171-186.read
it here
LS0tDQp0aXRsZTogIkFzaHBsb3RSIg0KYXV0aG9yOiAiSWFuIE1hdHRoZXdzICYgSm9zaHVhIFBpa2UiDQpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgdGhlbWU6IGNlcnVsZWFuDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KLS0tDQoNCiMgMS4wIEludHJvZHVjdGlvbg0KDQpUaGlzIHNjcmlwdCBjYW4gYmUgdXNlZCB0byBjcmVhdGUgYmktcGxvdHMgYW5kIEhhcmtlciBwbG90cyBvZiBhbGwgdGVwaHJhIG1ham9yIGVsZW1lbnRhbCBkYXRhLiBJdCBpbmNsdWRlczogdGlwcyBmb3IgZmxpdGVyaW5nIGRhdGEsIGludGVyYWN0aXZlIGV4cGxvcmF0aW9uIG9mIHRoZSBkYXRhLCBtb3JlIGNvbXBsZXggcGxvdHMsIHVzaW5nIGtlcm5lbCBkZW5zaXRpZXMgdG8gZGVsaW1pdCBjaGVtaWNhbCBlbnZlbG9wZXMsIGFuZCBzb21lIGRpc2N1c3Npb24gb24gaWRlbnRpZnlpbmcgdXNlZnVsIGVsZW1lbnRzIGZvciBkaXNjcmltaW5hdGlvbiB2aWEgbXVsdGl2YXJpYXRlIGFuYWx5c2lzLiBHdWlkYW5jZSBmb3Igc2F2aW5nIHBsb3RzIGFzIC5zdmcgb3IgLnBkZiBmaWxlcyBpcyBhbHNvIHByb3ZpZGVkLiBBbGwgdGhlIGNvZGUgdXNlZCB0byBwcm9kdWNlIHRoaXMgZG9jdW1lbnQgaXMgZG93bmxvYWRhYmxlIGFzIGFuIFJNYXJrZG93biBmaWxlIHRvIHRoZSByaWdodCBvZiB0aGlzIHBhZ2UgYW5kIHNob3VsZCBhcHBlYXIgZm9yIGVhY2ggc3BlY2lmaWMgcGxvdCBnZW5lcmF0ZWQuIFRvIHJ1biB0aGlzIHlvdSB3aWxsIHJlcXVpcmUgciBhbmQgUlN0dWRpby4gV2UgYXJlIGhhcHB5IGZvciB5b3UgdG8gdXNlLCBzaGFyZSBhbmQgaW1wcm92ZSBvdXIgY29kZSwgYnV0IHdvdWxkIGFzayB0aGF0IHlvdSBjaXRlIHRoaXMgYXMgYSBwb2ludCBvZiBvcmlnaW4gZm9yIHRoZSBjb2RlLg0KDQojIyBMb2FkIHBhY2thZ2VzDQoNCldlIGZpcnN0IGxvYWQgaW4gcGFja2FnZXMgcmVxdWlyZWQgdG8gZ2VuZXJhdGUgdGhlIHBsb3RzIGFuZCBtYW5pcHVsYXRlIHRoZSBkYXRhLiBZb3UgbWF5IG5lZWQgdG8gaW5zdGFsbCB0aGVzZSBwYWNrYWdlcyBpbiByIG9yIHVwZGF0ZSB0aGVtIHRvIHdvcmsgY29ycmVjdGx5Lg0KDQpgYGB7ciBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgZWNobz1UUlVFfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShmYWN0b2V4dHJhKQ0KbGlicmFyeShyZWFkcikNCmxpYnJhcnkocHN5Y2gpDQpsaWJyYXJ5KGNvbXBvc2l0aW9ucykNCmxpYnJhcnkoZ2dhbmltYXRlKQ0KbGlicmFyeShjb3dwbG90KQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGd0KQ0KbGlicmFyeShwbG90bHkpDQpsaWJyYXJ5KHN2Z2xpdGUpDQpsaWJyYXJ5KHBuZykNCmxpYnJhcnkoaGVyZSkNCmxpYnJhcnkoZ2dkZW5zaXR5KQ0KbGlicmFyeShnZ3JlcGVsKQ0KbGlicmFyeSh2aXJpZGlzKQ0KYGBgDQoNCg0KIyAyLjAgTG9hZGluZyB5b3VyIGRhdGENCg0KRGF0YSBzaG91bGQgYmUgcGxhY2VkIHdpdGhpbiBhICdEYXRhJyBmb2xkZXIgY3JlYXRlZCBpbiB5b3VyIHByb2plY3QgZGlyZWN0b3J5LiBBcyB0aGlzIGlzIGEgTWFya2Rvd24gc2NyaXB0IHRoZSAnaGVyZScgcGFja2FnZSBpcyB1c2VkIHRvIGVuc3VyZSB0aGF0IHByb2plY3QgbGlua3MgZG8gbm90IGJyZWFrIHdoZW4gbW92aW5nIHNjcmlwdHMgYXJvdW5kLCBob3dldmVyIHlvdSBtYXkgbm90IG5lZWQgdG8gZG8gdGhpcyBpZiB5b3UgaGF2ZSBhIHByZWZlcnJlZCBkYXRhIHN0b3JhZ2UgYXBwcm9hY2guIEFzIGxvbmcgYXMgeW91IHN0YXJ0IGEgbmV3IFIgcHJvamVjdCBhbmQgZHJvcCB0aGlzIHNjcmlwdCBpbnRvIGl0IHRoZW4gc2V0IHVwICdEYXRhJyBhbmQgJ1NjcmlwdCcgZm9sZGVycyB0aGVuIGl0IHdpbGwgd29yay4gRGF0YSBmaWxlcyBzaG91bGQgYmUgaW4gLmNzdiBmb3JtYXQgYW5kIGNvbnRhaW4gdGhlIGdyb3VwIG9mIHRoZSB0ZXBocmEgYXMgY29sdW1uIDEgdW5kZXIgdGhlIHRpdGxlICJpZCIgKHNlZSBjb25zb2xlIG91dHB1dCBiZWxvdyBmb3IgZm9ybWF0KS4gTG9hZGVkIGhlcmUgYXJlIHNvbWUgZGF0YSBmb3IgY29yZSBPRFAtOTgwIGluIHRoZSBOb3J0aCBBdGxhbnRpYyBhbmQgYSB0ZXJyZXN0cmlhbCBzaXRlIGZyb20gdGhlIFVLIGNhbGxlZCBNVC4gVGhlc2UgZGF0YSB3ZXJlIHB1Ymxpc2hlZCBieSBDYW5keSBldCBhbC4gKDIwMjEpIGFuZCB0aGUgcGFwZXIgY2FuIGJlIGZvdW5kIFtoZXJlXShodHRwczovL2RvaS5vcmcvMTAuMTAwMi9qcXMuMzM2NykuDQoNCmBgYHtyfQ0KY2hlbSA8LSBoZXJlOjpoZXJlKCJEYXRhIiwiT0RQX25vcm0uY3N2IikgJT4lIHJlYWQuY3N2KCkNCmBgYA0KDQojIyAyLjEgQ2hlY2sgeW91ciBkYXRhIGhhcyBsb2FkZWQgY29ycmVjdGx5DQpXZSBjYW4gZmlyc3QganVzdCBpbnNwZWN0IHRoZSBkYXRhIGluIHRoZSBjb25zb2xlIHVzaW5nIHRoZSAnaGVhZCcgY29tbWFuZCwgYW5kIHRoZW4gc3VtbWFyaXNlIGl0IHVzaW5nIHRoZSBkZXNjcmliZSBmdW5jdGlvbiBvZiB0aGUgcHN5Y2ggcGFja2FnZS4gVGhlc2UgY29tbWFuZHMgcHJvZHVjZSBhIGNvdXBsZSBvZiBiYXNpYyB0YWJsZXMgd2hpY2ggc2hvdWxkIGFsbG93IHlvdSB0byBjaGVjayB3aGV0aGVyIHlvdSBoYXZlIGNvcnJlY3RseSBsb2FkZWQgdGhlIGRhdGEgeW91IHdpc2ggdG8gYW5hbHlzZS4NCmBgYHtyfQ0KaGVhZChjaGVtKQ0KZGVzY3JpYmUoY2hlbSkNCmBgYA0KDQojIyAyLjIgQmV0dGVyIHRhYmxlcyBpbiByLg0KVGhlIG1haW4gcHJvYmxlbSB3aXRoIHRoZSBjb25zb2xlIG91dHB1dCBmcm9tIHIgaXMgdGhhdCBwcm9kdWNlcyB0YWJsZXMgdGhhdCBhcmUgbm90IHByZXR0eSB0byB2aWV3LiBUaGlzIGNhbiBsYXJnZWx5IGJlIGFkZHJlc3NlZCBieSB0aGUgJ2d0JyBwYWNrYWdlIHdoaWNoIHByb2R1Y2VzIGZhciBuaWNlciBvdXRwdXQgaW4gYW4gaHRtbCBmb3JtYXQuIA0KVGhlIGZvbGxvd2luZyBzY3JpcHQgcHJvZHVjZXMgYSBzdW1tYXJ5IHRhYmxlIG9mIG1lYW4gdmFsdWVzIGFuZCBudW1iZXIgb2YgYW5hbHlzZXMgaW4geW91ciBkYXRhLg0KDQpgYGB7ciBlY2hvPUZBTFNFfQ0KY2hlbV9zdW0gPC0gY2hlbSAlPiUgZ3JvdXBfYnkoaWQpICU+JSBkcGx5cjo6c3VtbWFyaXNlKCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY291bnQ9bigpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNpTzIuPSBtZWFuKFNpTzIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNkMSA9IHNkKFNpTzIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRpTzIuID0gbWVhbihUaU8yKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZDIgPSBzZChUaU8yKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBBbDJPMy4gPSBtZWFuKEFsMk8zKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZDMgPSBzZChBbDJPMyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRmVPdCA9IG1lYW4oRmVPKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZDQgPSBzZChGZU8pLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1uTy49IG1lYW4oTW5PKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZDUgPSBzZChNbk8pLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1nTy49IG1lYW4oTWdPKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZDYgPSBzZChNZ08pLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIENhTy49IG1lYW4oQ2FPKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZDcgPSBzZChDYU8pLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5hMk8uID0gbWVhbihOYTJPKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZDggPSBzZChOYTJPKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBLMk8uID0gbWVhbihLMk8pLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNkOSA9IHNkKEsyTyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUDJPNS4gPSBtZWFuKFAyTzUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNkMTAgPSBzZChQMk81KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUb3RhbC49bWVhbihUb3RhbCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2QxMSA9IHNkKFRvdGFsKSkNCmNoZW1fc3VtIDwtIGNoZW1fc3VtICU+JSBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLCB+IHJvdW5kKC4sIGRpZ2l0cyA9IDIpKSkNCmNoZW1fc3VtIDwtIGNoZW1fc3VtICU+JSByZW5hbWUobGF5ZXIgPSBpZCwgbiA9IGNvdW50KQ0KDQoNCmd0KGNoZW1fc3VtKQ0KYGBgDQojIyAyLjMgTWFrZSBUQVMgY2FsY3VsYXRpb25zDQoNClRvIGNhbGN1bGF0ZSBmb3IgdGhlIFRBUyBwbG90IHRoZSBkYXRhIHJlcXVpcmUgbm9ybWFsaXNhdGlvbiBvZiB0aGUgZGF0YS4gVGhlIGRhdGEgdXNlZCBoZXJlIGhhcyBiZWVuIG5vcm1hbGlzZWQgYWxyZWFkeSBzbyB0aGlzIHN0ZXAgaXMgbGFyZ2VseSByZWR1bmRhbnQsIGJ1dCB0aGlzIGlzIG5vdCB0aGUgY2FzZSBmb3IgYWxsIHRlcGhyYSBkYXRhIGFuZCB5b3UgbWlnaHQgcHJlZmVyIHRvIHV0aWxpc2UgdW5vcm1hbGlzZWQgZGF0YSBmb3IgeW91ciBhbmFseXNlcywgZXNwZWNpYWxseSBpZiB5b3UgYXJlIGludGVyZXN0ZWQgaW4gdGhlIGVmZmVjdHMgb2YgYW5hbHl0aWNhbCB0b3RhbHMgb24geW91ciBkYXRhLiBUaGlzIGNvZGUgZG9lcyBub3QgbW9kaWZ5IHlvdXIgb3JpZ25hbCBkYXRhIHNvIGNhbiBiZSBzYWZlbHkgcnVuIGZvciBib3RoIG5vcm1hbGlzZWQgYW5kIHVub3JtYWxpc2VkIGRhdGEuIEl0IGlzIHJlcXVpcmVkIGZvciB0aGUgVEFTIHBsb3Qgc28gc2hvdWxkIGJlIHJ1biByZWdhcmRsZXNzIG9mIHRoZSBzdGF0ZSBvZiB5b3VyIGRhdGEuDQoNCmBgYHtyfQ0KVEFTX3ggPC0gKDEwMC8gY2hlbSBbWyJUb3RhbCJdXSkgKiBjaGVtIFtbIlNpTzIiXV0NClRBU195IDwtICgxMDAvIGNoZW0gW1siVG90YWwiXV0pICogKGNoZW0gW1siSzJPIl1dICsgY2hlbSBbWyJOYTJPIl1dKQ0KDQpjaGVtIDwtIGNiaW5kKGNoZW0sIFRBU194LCBUQVNfeSkNCmBgYA0KDQojIDMuMCBGaWx0ZXJpbmcgZGF0YQ0KSXQgaXMgcG9zc2libGUgeW91ciBkYXRhc2hlZXQgY29udGFpbnMgbXVsdGlwbGUgdHlwZXMgb2YgdGVwaHJhIGNoZW1pc3RyeSB3aGljaCB3b3VsZCBiZW5lZml0IGZyb20gZmlsdGVyaW5nIGJlZm9yZSBwbG90dGluZy4gSSBzdWdnZXN0IHRoaXMgaXMgY2FycmllZCBvdXQgaW5pdGlhbGx5IGJ5IHVzaW5nIHNpbGljYSB2YWx1ZXMgYXMgYSBkaXZpc29yLiBSaHlvbGl0ZXMgPjY4JSBzaWxpY2Egd291bGQgYmUgYSBjYXNlIGZvciB0aGlzLiBIb3dldmVyLCBpdCBtaWdodCBiZSB3b3J0aCBwbG90dGluZyBldmVyeXRoaW5nIGZpcnN0IGJlZm9yZSB0aGVuIHNlbGVjdGluZyBhIGZpbHRlciB0byBlbnN1cmUgdml0YWwgZGF0YSBpcyBub3QgYmVpbmcgZXhjbHVkZWQuIEhlcmUgd2UgY29udGludWUgd2l0aCBhbGwgZGF0YSBiZWluZyBwbG90dGVkIGJlZm9yZSBmaWx0ZXJpbmcgbGF0ZXIgaW4gdGhlIHNjcmlwdCB3aGVuIG1ha2luZyBjb21wYXJpc29ucy4NCmBgYHtyfQ0KI2NoZW0gPC0gZmlsdGVyKGNoZW0sIFNpTzIgPjY4KSAjIyBjb2RlIGlzIGNvbW1lbnRlZCBvcmRlciB0byByZXRhaW4gYWxsIGRhdGEgYXQgdGhpcyBzdGFnZS4NCmBgYA0KDQoNCg0KIyA0LjAgUGxvdHRpbmcgeW91ciBkYXRhDQoNCkZpcnN0IHdlIGdlbmVyYXRlIGEgc2VyaWVzIG9mIHBsb3RzIGZyb20gYWxsIHBvc3NpYmxlIHBhaXJzIG9mIGVsZW1lbnRzLg0KDQpgYGB7cn0NCnAxIDwtIGdncGxvdChjaGVtLCBhZXMoeCA9IFRBU194LCB5ID0gVEFTX3ksIGZpbGwgPSBpZCwgc2hhcGUgPSBpZCkpICMgdGhpcyB1c2VzIHRoZSBUQVMgY2FsY3VsYXRpb25zIG1hZGUgZWFybGllciBpbiBzdGVwIDIuMy4NCnAyIDwtIGdncGxvdChjaGVtLCBhZXMoeCA9IFNpTzIsIHkgPSBUaU8yLCBmaWxsID0gaWQsIHNoYXBlID0gaWQpKQ0KcDMgPC0gZ2dwbG90KGNoZW0sIGFlcyh4ID0gU2lPMiwgeSA9IEFsMk8zLCBmaWxsID0gaWQsIHNoYXBlID0gaWQpKQ0KcDQgPC0gZ2dwbG90KGNoZW0sIGFlcyh4ID0gU2lPMiwgeSA9IEZlTywgIGZpbGwgPSBpZCwgc2hhcGUgPSBpZCkpDQpwNSA8LSBnZ3Bsb3QoY2hlbSwgYWVzKHggPSBTaU8yLCB5ID0gTW5PLCAgZmlsbCA9IGlkLCBzaGFwZSA9IGlkKSkNCnA2IDwtIGdncGxvdChjaGVtLCBhZXMoeCA9IFNpTzIsIHkgPSBNZ08sICBmaWxsID0gaWQsIHNoYXBlID0gaWQpKQ0KcDcgPC0gZ2dwbG90KGNoZW0sIGFlcyh4ID0gU2lPMiwgeSA9IENhTywgIGZpbGwgPSBpZCwgc2hhcGUgPSBpZCkpDQpwOCA8LSBnZ3Bsb3QoY2hlbSwgYWVzKHggPSBTaU8yLCB5ID0gTmEyTywgIGZpbGwgPSBpZCwgc2hhcGUgPSBpZCkpDQpwOSA8LSBnZ3Bsb3QoY2hlbSwgYWVzKHggPSBTaU8yLCB5ID0gSzJPLCAgZmlsbCA9IGlkLCBzaGFwZSA9IGlkKSkNCnA0NyA8LSBnZ3Bsb3QoY2hlbSwgYWVzKHggPSBTaU8yLCB5ID0gSzJPLCBmaWxsID0gaWQsIHNoYXBlID0gaWQpKQ0KcDEwIDwtIGdncGxvdChjaGVtLCBhZXMoeCA9IFNpTzIsIHkgPSBQMk81LCAgZmlsbCA9IGlkLCBzaGFwZSA9IGlkKSkNCnAxMSA8LSBnZ3Bsb3QoY2hlbSwgYWVzKHggPSBUaU8yLCB5ID0gQWwyTzMsICBmaWxsID0gaWQsIHNoYXBlID0gaWQpKQ0KcDEyIDwtIGdncGxvdChjaGVtLCBhZXMoeCA9IFRpTzIsIHkgPSBGZU8sICBmaWxsID0gaWQsIHNoYXBlID0gaWQpKQ0KcDEzIDwtIGdncGxvdChjaGVtLCBhZXMoeCA9IFRpTzIsIHkgPSBNbk8sICBmaWxsID0gaWQsIHNoYXBlID0gaWQpKQ0KcDE0IDwtIGdncGxvdChjaGVtLCBhZXMoeCA9IFRpTzIsIHkgPSBNZ08sICBmaWxsID0gaWQsIHNoYXBlID0gaWQpKQ0KcDE1IDwtIGdncGxvdChjaGVtLCBhZXMoeCA9IFRpTzIsIHkgPSBDYU8sICBmaWxsID0gaWQsIHNoYXBlID0gaWQpKQ0KcDE2IDwtIGdncGxvdChjaGVtLCBhZXMoeCA9IFRpTzIsIHkgPSBOYTJPLCAgZmlsbCA9IGlkLCBzaGFwZSA9IGlkKSkNCnAxNyA8LSBnZ3Bsb3QoY2hlbSwgYWVzKHggPSBUaU8yLCB5ID0gSzJPLCAgZmlsbCA9IGlkLCBzaGFwZSA9IGlkKSkNCnAxOCA8LSBnZ3Bsb3QoY2hlbSwgYWVzKHggPSBUaU8yLCB5ID0gUDJPNSwgIGZpbGwgPSBpZCwgc2hhcGUgPSBpZCkpDQpwMTkgPC0gZ2dwbG90KGNoZW0sIGFlcyh4ID0gQWwyTzMsIHkgPSBGZU8sICBmaWxsID0gaWQsIHNoYXBlID0gaWQpKQ0KcDIwIDwtIGdncGxvdChjaGVtLCBhZXMoeCA9IEFsMk8zLCB5ID0gTW5PLCAgZmlsbCA9IGlkLCBzaGFwZSA9IGlkKSkNCnAyMSA8LSBnZ3Bsb3QoY2hlbSwgYWVzKHggPSBBbDJPMywgeSA9IE1nTywgIGZpbGwgPSBpZCwgc2hhcGUgPSBpZCkpDQpwMjIgPC0gZ2dwbG90KGNoZW0sIGFlcyh4ID0gQWwyTzMsIHkgPSBDYU8sICBmaWxsID0gaWQsIHNoYXBlID0gaWQpKQ0KcDIzIDwtIGdncGxvdChjaGVtLCBhZXMoeCA9IEFsMk8zLCB5ID0gTmEyTywgIGZpbGwgPSBpZCwgc2hhcGUgPSBpZCkpDQpwMjQgPC0gZ2dwbG90KGNoZW0sIGFlcyh4ID0gQWwyTzMsIHkgPSBLMk8sICBmaWxsID0gaWQsIHNoYXBlID0gaWQpKQ0KcDI1IDwtIGdncGxvdChjaGVtLCBhZXMoeCA9IEFsMk8zLCB5ID0gUDJPNSwgIGZpbGwgPSBpZCwgc2hhcGUgPSBpZCkpDQpwMjYgPC0gZ2dwbG90KGNoZW0sIGFlcyh4ID0gRmVPLCB5ID0gTW5PLCAgZmlsbCA9IGlkLCBzaGFwZSA9IGlkKSkNCnAyNyA8LSBnZ3Bsb3QoY2hlbSwgYWVzKHggPSBGZU8sIHkgPSBNZ08sICBmaWxsID0gaWQsIHNoYXBlID0gaWQpKQ0KcDI4IDwtIGdncGxvdChjaGVtLCBhZXMoeCA9IEZlTywgeSA9IENhTywgIGZpbGwgPSBpZCwgc2hhcGUgPSBpZCkpDQpwMjkgPC0gZ2dwbG90KGNoZW0sIGFlcyh4ID0gRmVPLCB5ID0gTmEyTywgIGZpbGwgPSBpZCwgc2hhcGUgPSBpZCkpDQpwMzAgPC0gZ2dwbG90KGNoZW0sIGFlcyh4ID0gRmVPLCB5ID0gSzJPLCAgZmlsbCA9IGlkLCBzaGFwZSA9IGlkKSkNCnAzMSA8LSBnZ3Bsb3QoY2hlbSwgYWVzKHggPSBGZU8sIHkgPSBQMk81LCAgZmlsbCA9IGlkLCBzaGFwZSA9IGlkKSkNCnAzMiA8LSBnZ3Bsb3QoY2hlbSwgYWVzKHggPSBNbk8sIHkgPSBNZ08sICBmaWxsID0gaWQsIHNoYXBlID0gaWQpKQ0KcDMzIDwtIGdncGxvdChjaGVtLCBhZXMoeCA9IE1uTywgeSA9IENhTywgIGZpbGwgPSBpZCwgc2hhcGUgPSBpZCkpDQpwMzQgPC0gZ2dwbG90KGNoZW0sIGFlcyh4ID0gTW5PLCB5ID0gTmEyTywgIGZpbGwgPSBpZCwgc2hhcGUgPSBpZCkpDQpwMzUgPC0gZ2dwbG90KGNoZW0sIGFlcyh4ID0gTW5PLCB5ID0gSzJPLCAgZmlsbCA9IGlkLCBzaGFwZSA9IGlkKSkNCnAzNiA8LSBnZ3Bsb3QoY2hlbSwgYWVzKHggPSBNbk8sIHkgPSBQMk81LCAgZmlsbCA9IGlkLCBzaGFwZSA9IGlkKSkNCnAzNyA8LSBnZ3Bsb3QoY2hlbSwgYWVzKHggPSBNZ08sIHkgPSBDYU8sICBmaWxsID0gaWQsIHNoYXBlID0gaWQpKQ0KcDM4IDwtIGdncGxvdChjaGVtLCBhZXMoeCA9IE1nTywgeSA9IE5hMk8sICBmaWxsID0gaWQsIHNoYXBlID0gaWQpKQ0KcDM5IDwtIGdncGxvdChjaGVtLCBhZXMoeCA9IE1nTywgeSA9IEsyTywgIGZpbGwgPSBpZCwgc2hhcGUgPSBpZCkpDQpwNDAgPC0gZ2dwbG90KGNoZW0sIGFlcyh4ID0gTWdPLCB5ID0gUDJPNSwgIGZpbGwgPSBpZCwgc2hhcGUgPSBpZCkpDQpwNDEgPC0gZ2dwbG90KGNoZW0sIGFlcyh4ID0gQ2FPLCB5ID0gTmEyTywgIGZpbGwgPSBpZCwgc2hhcGUgPSBpZCkpDQpwNDIgPC0gZ2dwbG90KGNoZW0sIGFlcyh4ID0gQ2FPLCB5ID0gSzJPLCAgZmlsbCA9IGlkLCBzaGFwZSA9IGlkKSkNCnA0MyA8LSBnZ3Bsb3QoY2hlbSwgYWVzKHggPSBDYU8sIHkgPSBQMk81LCAgZmlsbCA9IGlkLCBzaGFwZSA9IGlkKSkNCnA0NCA8LSBnZ3Bsb3QoY2hlbSwgYWVzKHggPSBOYTJPLCB5ID0gSzJPLCAgZmlsbCA9IGlkLCBzaGFwZSA9IGlkKSkNCnA0NSA8LSBnZ3Bsb3QoY2hlbSwgYWVzKHggPSBOYTJPLCB5ID0gUDJPNSwgIGZpbGwgPSBpZCwgc2hhcGUgPSBpZCkpDQpwNDYgPC0gZ2dwbG90KGNoZW0sIGFlcyh4ID0gSzJPLCB5ID0gUDJPNSwgIGZpbGwgPSBpZCwgc2hhcGUgPSBpZCkpDQpgYGANCg0KDQojIyA0LjEgQ3VzdG9tIHRlcGhyYSB0aGVtZQ0KVG8gZW5zdXJlIGNvbnNpc3RlbmN5IGFuZCB0byBwcm92aWRlIGEgc2hvcnRjdXQgb2YgY29kaW5nIGl0IGV2ZXJ5dGltZSB3ZSBzZXQgdXAgYSBjdXN0b20gdGVwaHJhIHBsb3R0aW5nIHRoZW1lLiBUaGlzIG1lYW5zIGFsbCBvZiBvdXIgcGxvdHMgd2lsbCBoYXZlIHRoZSBzYW1lIHNpemVkIGZvbnRzIGV0Yy4uLg0KDQoNCmBgYHtyfQ0KVGVwaHJhLnRoZW1lIDwtdGhlbWVfYncoKSt0aGVtZShheGlzLnRpdGxlLng9ZWxlbWVudF90ZXh0KHNpemU9MTYpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnk9ZWxlbWVudF90ZXh0KHNpemU9MTYpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemU9MTYpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X3RleHQoc2l6ZT0xNikpKw0KICB0aGVtZShwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLCANCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkNCmBgYA0KDQojIyA0LjIgQ3VzdG9tIGNvbG91ciBwYWxldHRlDQoNClRoZSBoZXggbnVtYmVycyBiZWxvdyBzcGVjaWZ5IGEgY3VzdG9tIGNvbG91ciBwYWxldHRlIGZvciBwbG90dGluZy4gVGhlc2UgY2FuIGJlIGFsdGVyZWQgYnV0IHdlcmUgc2xlY3RlZCBpbiBvcmRlciB0byBoZWxwIHRob3NlIHdpdGggY29sb3VyIHZpc2lvbiBkZWZpY2llbmNpZXMsIGFuZCB0aGlzIHNob3VsZCBiZSBjb25zaWRlcmVkIHdoZW4gbWFraW5nIGNoYW5nZXMuIEF0IHByZXNlbnQgMzUgbGF5ZXJzIGNhbiBiZSBwbG90dGVkIHVzaW5nIHRoaXMgcGFsbGV0ZS4gSWYgeW91IGhhdmUgbW9yZSB0aGFuIDM1IGdyb3VwcyBvZiBkYXRhIHlvdSB3aWxsIGVpdGhlciBoYXZlIHRvIHNwZWNpZnkgYWRkaXRpb25hbCBjb2xvdXJzIG9yIGNvbnNpZGVyIHNwbGl0dGluZyB5b3VyIGRhdGFzZXQuIFRoZSBsYXR0ZXIgbWlnaHQgYmUgbW9yZSBhcHByb3ByaWF0ZSBmb3IgaW1wcm92aW5nIHRoZSBmaW5hbCBjbGFyaXR5IGluIHRoZSBwbG90cy4gDQoNCmBgYHtyfQ0KY2hlbXBhbGV0dGUgPC0gYygiIzIwOUEyNCIsIiNBNzY5RUUiLCIjQjRDNDI4IiwiI2UzMDMwMyIsIiMwMDAwMDAiLCIjRUYxMzlEIiwiIzNBNzAwRiIsIiM1Mjg4RkYiLCIjRTY0NzAxIiwiIzdGOUFGNSIsIiNGMzZEMjAiLCIjMEIzMDc1IiwiI0MxODUyMiIsIiM5NjM0QTYiLCIjMUQ3RDQ2IiwiIzgwZGRiOCIsIiM3Q0JDOTIiLCIjQjEwRTg5IiwiIzM4NEIyNyIsIiNGODk2RkQiLCIjQzZBNzY2IiwiIzIwNjI4RSIsIiM5QzAzMjMiLCIjQzNBRkUwIiwiIzU3MkQyNCIsIiNGRjc5QTIiLCIjM0U2RDZGIiwiI0UxOEM2MyIsIiM2RjJCNDAiLCIjREY5RkI0IiwgIiMyOTE3MDAiLCAiIzdlMDA1YiIsICIjMDA1OTdhIiAsICIjN2IwMDNhIiwJIiM0NzA2MDAiKQ0KYGBgDQoNClRoZSBwYWxldHRlIGlzIGtub3duIGFzICJjaGVtcGFsZXR0ZSIuDQoNCiMgNS4wIEJpcGxvdHMgey50YWJzZXQgLnRhYnNldC1waWxsc30NCg0KV2UgZmlyc3QgZ2VuZXJhdGUgdGhlIHNpbXBsZSBiaS1wbG90cyBvZiBlYWNoIGVsZW1lbnQuIFRoaXMgaW5pdGlhbCBleHBsb3JhdGl2ZSBhcHByb2FjaCBmYWNpbGl0YXRlcyBkYXRhIGNoZWNraW5nIGZvciB1bnVzdWFsIGFuYWx5c2VzIGFuZCBwZXJtaXRzIHRoZSBpZGVudGlmaWNhdGlvbiBvZiBlbGVtZW50cyB3aXRoIHNpZ25pZmljYW50IHZhcmlhYmlsaXR5Lg0KDQojIyBUQVMgcGxvdCBMZSBNYWl0cmUgZXQgYWwuICgyMDAyKQ0KYGBge3IgVEFTIHBsb3QsIGVjaG89RkFMU0V9DQpwMSA8LSBwMSArIGdlb21fcG9pbnQoYWVzKGZpbGwgPSBpZCksIHNpemU9NCwgYWxwaGE9MC44KSArDQogICN4bGFiKGV4cHJlc3Npb24gKFNpT1syXX4iKHd0JSkiKSkgKyB1c2UgdGhlc2UgZm9yIG91dHB1dHRpbmcgc3Vic2NyaXB0IGNoYXJhY3RlcnMgZm9yIHNhdmVkIHN2ZyBvciBwZGYgcGxvdHMuDQogIHhsYWIoIlNpTzIgKHd0JSkiKSArDQogICN5bGFiKGV4cHJlc3Npb24gKE5hWzJdKk9+IisifktbMl0qT34iKHd0JSkiKSkgKw0KICB5bGFiKCJOYTJPICsgSzJPICh3dCUpIikgKw0KICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzPWMoMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1KSkrDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNoZW1wYWxldHRlKSArIA0KICBnZW9tX3NlZ21lbnQoeD03Nyx5PTAseGVuZD02OSx5ZW5kPTgpKyANCiAgZ2VvbV9zZWdtZW50KHg9NjksIHk9OCx4ZW5kPTY5LHllbmQ9MTMpK2dlb21fc2VnbWVudCh4PTQxLCB5PTcseGVuZD01Mi41LHllbmQ9MTQpKw0KICBnZW9tX3NlZ21lbnQoeD01Mi41LHk9MTQseGVuZD01Ny42LHllbmQ9MTEuNykrDQogIGdlb21fc2VnbWVudCh4PTQ1LHk9MCx4ZW5kPTQ1LHllbmQ9NSkrDQogIGdlb21fc2VnbWVudCh4PTQ1LHk9NSx4ZW5kPTYzLHllbmQ9MTQuNTYpKw0KICBnZW9tX3NlZ21lbnQoeD01Mix5PTAseGVuZD01Mix5ZW5kPTUpKw0KICBnZW9tX3NlZ21lbnQoeD01Mix5PTUseGVuZD02Myx5ZW5kPTcpKw0KICBnZW9tX3NlZ21lbnQoeD01Nyx5PTAseGVuZD01Nyx5ZW5kPTUuOSkrDQogIGdlb21fc2VnbWVudCh4PTYzLHk9MCx4ZW5kPTYzLHllbmQ9NykrDQogIGdlb21fc2VnbWVudCh4PTQ1LHk9NSx4ZW5kPTUyLHllbmQ9NSkrDQogIGdlb21fc2VnbWVudCh4PTUyLHk9NSx4ZW5kPTQ5LjQseWVuZD03LjMpKw0KICBnZW9tX3NlZ21lbnQoeD01Nyx5PTUuOSx4ZW5kPTUzLHllbmQ9OS4zKSsNCiAgZ2VvbV9zZWdtZW50KHg9NjMseT03LHhlbmQ9NTcuNix5ZW5kPTExLjcpKw0KICBnZW9tX3NlZ21lbnQoeD00OS40LHk9Ny4zLHhlbmQ9NDUseWVuZD05LjQpKw0KICBnZW9tX3NlZ21lbnQoeD01Myx5PTkuMyx4ZW5kPTQ4LjQseWVuZD0xMS41KSsNCiAgZ2VvbV9zZWdtZW50KHg9NDEseT0wLHhlbmQ9NDEseWVuZD03KSsNCiAgZ2VvbV9zZWdtZW50KHg9NTIuNSx5PTE0LHhlbmQ9NDkseWVuZD0xNS41KSsNCiAgZ2VvbV9zZWdtZW50KHg9NDEseT0zLHhlbmQ9NDUseWVuZD0zKSsNCiAgZ2VvbV9zZWdtZW50KHg9NjMseT03LHhlbmQ9NjkseWVuZD04KSsNCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cz1jKDQwLCA4MCksIGV4cGFuZCA9IGMoMCwgMCkpICsgDQogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHM9YygwLCAxNiksIGV4cGFuZCA9IGMoMCwgMCkpICsNCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gYyg3Niw2Ny41LDU5LDU0LDQ4LDQyLjUsNDguNSw1Myw1Nyw2Myw0Myw0OCw1Myw1Nyw0MiksIHkgPSBjKDYsNS4yLDQsMywyLjUsMS41LDYsNy41LDguOCwxMSw3LDEwLDEyLDE0LjUsMTMpLCBsYWJlbCA9IGMoIlIiLCJPMyIsIk8yIiwiTzEiLCJCIiwiUGMiLCJTMSIsIlMyIiwiUzMiLCJUIiwiVTEiLCJVMiIsIlUzIiwiUGgiLCJGIikpICsNCiAgVGVwaHJhLnRoZW1lDQpwMQ0KYGBgDQoNCiMjIFNpTzIgVlMgVGlPMg0KYGBge3IgZWNobz1GQUxTRX0NCnAyIDwtIHAyICsgZ2VvbV9wb2ludChhZXMoZmlsbCA9IGlkKSwgc2l6ZT00LCBhbHBoYT0wLjgpK3hsYWIoIlNpTzIgKHd0JSkiKSt5bGFiKCJUaU8yICh3dCUpIikrc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcz1jKDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1KSkrDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNoZW1wYWxldHRlKSArDQogIFRlcGhyYS50aGVtZQ0KcDINCmBgYA0KDQojIyBTaU8yIFZTIEFsMk8zDQpgYGB7ciBlY2hvPUZBTFNFfQ0KcDMgPC0gcDMgKyBnZW9tX3BvaW50KGFlcyhmaWxsID0gaWQpLCBzaXplPTQsIGFscGhhPTAuOCkreGxhYigiU2lPMiAod3QlKSIpK3lsYWIoIkFsMk8zICh3dCUpIikrc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcz1jKDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1KSkrDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNoZW1wYWxldHRlKSArDQogIFRlcGhyYS50aGVtZQ0KcDMNCmBgYA0KDQojIyBTaU8yIFZTIEZlTw0KYGBge3IgZWNobz1GQUxTRX0NCnA0IDwtIHA0ICsgZ2VvbV9wb2ludChhZXMoZmlsbCA9IGlkKSwgc2l6ZT00LCBhbHBoYT0wLjgpK3hsYWIoIlNpTzIgKHd0JSkiKSt5bGFiKCJGZU8gKHd0JSkiKStzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzPWMoMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUpKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY2hlbXBhbGV0dGUpICsNCiAgVGVwaHJhLnRoZW1lDQpwNA0KYGBgDQoNCiMjIFNpTzIgVlMgTW5PDQpgYGB7ciBlY2hvPUZBTFNFfQ0KcDUgPC0gcDUgKyBnZW9tX3BvaW50KGFlcyhmaWxsID0gaWQpLCBzaXplPTQsIGFscGhhPTAuOCkreGxhYigiU2lPMiAod3QlKSIpK3lsYWIoIk1uTyAod3QlKSIpK3NjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXM9YygyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSkpKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjaGVtcGFsZXR0ZSkgKw0KICBUZXBocmEudGhlbWUNCnA1DQpgYGANCg0KIyMgU2lPMiBWUyBNZ08NCmBgYHtyIGVjaG89RkFMU0V9DQpwNiA8LSBwNiArIGdlb21fcG9pbnQoYWVzKGZpbGwgPSBpZCksIHNpemU9NCwgYWxwaGE9MC44KSt4bGFiKCJTaU8yICh3dCUpIikreWxhYigiTWdPICh3dCUpIikrc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcz1jKDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1KSkrDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNoZW1wYWxldHRlKSArDQogIFRlcGhyYS50aGVtZQ0KcDYNCmBgYA0KDQojIyBTaU8yIFZTIENhTw0KYGBge3IgZWNobz1GQUxTRX0NCnA3IDwtIHA3ICsgZ2VvbV9wb2ludChhZXMoZmlsbCA9IGlkKSwgc2l6ZT00LCBhbHBoYT0wLjgpK3hsYWIoIlNpTzIgKHd0JSkiKSt5bGFiKCJDYU8gKHd0JSkiKStzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzPWMoMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUpKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY2hlbXBhbGV0dGUpICsNCiAgVGVwaHJhLnRoZW1lDQpwNw0KYGBgDQoNCiMjIFNpTzIgVlMgTmEyTw0KYGBge3IgZWNobz1GQUxTRX0NCnA4IDwtIHA4ICsgZ2VvbV9wb2ludChhZXMoZmlsbCA9IGlkKSwgc2l6ZT00LCBhbHBoYT0wLjgpK3hsYWIoIlNpTzIgKHd0JSkiKSt5bGFiKCJOYTJPICh3dCUpIikrc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcz1jKDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1KSkrDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNoZW1wYWxldHRlKSArDQogIFRlcGhyYS50aGVtZQ0KcDgNCmBgYA0KDQojIyBTaU8yIFZTIEsyTw0KYGBge3IgZWNobz1GQUxTRX0NCnA5IDwtIHA5ICsgZ2VvbV9wb2ludChhZXMoZmlsbCA9IGlkKSwgc2l6ZT00LCBhbHBoYT0wLjgpK3hsYWIoIlNpTzIgKHd0JSkiKSt5bGFiKCJLMk8gKHd0JSkiKStzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzPWMoMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUpKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY2hlbXBhbGV0dGUpICsNCiAgVGVwaHJhLnRoZW1lDQpwOQ0KYGBgDQoNCmBgYHtyIGVjaG89RkFMU0V9DQpwNDcgPC0gcDQ3ICsgZ2VvbV9wb2ludChhZXMoZmlsbCA9IGlkKSwgc2l6ZT00LCBhbHBoYT0wLjgpKw0KICB4bGFiKCJTaU8yICh3dCUpIikreWxhYigiSzJPICh3dCUpIikrDQogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXM9YygyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSkpKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjaGVtcGFsZXR0ZSkgKw0KICBnZW9tX3NlZ21lbnQoeD00OCx5PTEuNix4ZW5kPTUyLHllbmQ9Mi40KSsgDQogIGdlb21fc2VnbWVudCh4PTUyLCB5PTIuNCx4ZW5kPTU2LHllbmQ9My4yKSsNCiAgZ2VvbV9zZWdtZW50KHg9NTYsIHk9My4yLHhlbmQ9NjMseWVuZD00LjApKw0KICBnZW9tX3NlZ21lbnQoeD00OCx5PTEuMix4ZW5kPTUyLHllbmQ9MS41KSsNCiAgZ2VvbV9zZWdtZW50KHg9NTIseT0xLjUseGVuZD01Nix5ZW5kPTEuOCkrDQogIGdlb21fc2VnbWVudCh4PTU2LHk9MS44LHhlbmQ9NjMseWVuZD0yLjQpKw0KICBnZW9tX3NlZ21lbnQoeD02Myx5PTIuNCx4ZW5kPTcwLHllbmQ9My4wKSsNCiAgZ2VvbV9zZWdtZW50KHg9NDgseT0wLjMseGVuZD01Mix5ZW5kPTAuNSkrDQogIGdlb21fc2VnbWVudCh4PTUyLHk9MC41LHhlbmQ9NTYseWVuZD0wLjcpKw0KICBnZW9tX3NlZ21lbnQoeD01Nix5PTAuNyx4ZW5kPTYzLHllbmQ9MS4wKSsNCiAgZ2VvbV9zZWdtZW50KHg9NjMseT0xLjAseGVuZD03MCx5ZW5kPTEuMykrDQogIGdlb21fc2VnbWVudCh4PTcwLHk9MS4zLHhlbmQ9ODAseWVuZD0xLjYpKw0KICBUZXBocmEudGhlbWUNCnA0Nw0KYGBgDQoNCiMjIFNpTzIgVlMgUDJPNQ0KYGBge3IgZWNobz1GQUxTRX0NCnAxMCA8LSBwMTAgKyBnZW9tX3BvaW50KGFlcyhmaWxsID0gaWQpLCBzaXplPTQsIGFscGhhPTAuOCkreGxhYigiU2lPMiAod3QlKSIpK3lsYWIoIlAyTzUgKHd0JSkiKStzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzPWMoMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUpKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY2hlbXBhbGV0dGUpICsNCiAgVGVwaHJhLnRoZW1lDQpwMTANCmBgYA0KDQojIyBUaU8yIFZTIEFsMk8zDQpgYGB7ciBlY2hvPUZBTFNFfQ0KcDExIDwtIHAxMSArIGdlb21fcG9pbnQoYWVzKGZpbGwgPSBpZCksIHNpemU9NCwgYWxwaGE9MC44KSt4bGFiKCJUaU8yICh3dCUpIikreWxhYigiQWwyTzMgKHd0JSkiKStzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzPWMoMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUpKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY2hlbXBhbGV0dGUpICsNCiAgVGVwaHJhLnRoZW1lDQpwMTENCmBgYA0KDQojIyBUaU8yIHZzIEZlTw0KYGBge3IgZWNobz1GQUxTRX0NCnAxMiA8LSBwMTIgKyBnZW9tX3BvaW50KGFlcyhmaWxsID0gaWQpLCBzaXplPTQsIGFscGhhPTAuOCkreGxhYigiVGlPMiAod3QlKSIpK3lsYWIoIkZlTyAod3QlKSIpK3NjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXM9YygyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSkpKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjaGVtcGFsZXR0ZSkgKw0KICBUZXBocmEudGhlbWUNCnAxMg0KYGBgDQoNCiMjIFRpTzIgdnMgTW5PDQpgYGB7ciBlY2hvPUZBTFNFfQ0KcDEzIDwtIHAxMyArIGdlb21fcG9pbnQoYWVzKGZpbGwgPSBpZCksIHNpemU9NCwgYWxwaGE9MC44KSt4bGFiKCJUaU8yICh3dCUpIikreWxhYigiTW5PICh3dCUpIikrc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcz1jKDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1KSkrDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNoZW1wYWxldHRlKSArDQogIFRlcGhyYS50aGVtZQ0KcDEzDQpgYGANCg0KIyMgVGlPMiBWUyBNZ08NCmBgYHtyIGVjaG89RkFMU0V9DQpwMTQgPC0gcDE0ICsgZ2VvbV9wb2ludChhZXMoZmlsbCA9IGlkKSwgc2l6ZT00LCBhbHBoYT0wLjgpK3hsYWIoIlRpTzIgKHd0JSkiKSt5bGFiKCJNZ08gKHd0JSkiKStzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzPWMoMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUpKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY2hlbXBhbGV0dGUpICsNCiAgVGVwaHJhLnRoZW1lDQpwMTQNCmBgYA0KDQojIyBUaU8yIFZTIENhTw0KYGBge3IgZWNobz1GQUxTRX0NCnAxNSA8LSBwMTUgKyBnZW9tX3BvaW50KGFlcyhmaWxsID0gaWQpLCBzaXplPTQsIGFscGhhPTAuOCkreGxhYigiVGlPMiAod3QlKSIpK3lsYWIoIkNhTyAod3QlKSIpK3NjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXM9YygyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSkpKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjaGVtcGFsZXR0ZSkgKw0KICBUZXBocmEudGhlbWUNCnAxNQ0KYGBgDQoNCiMjIFRpTzIgVlMgTmEyTw0KYGBge3IgZWNobz1GQUxTRX0NCnAxNiA8LSBwMTYgKyBnZW9tX3BvaW50KGFlcyhmaWxsID0gaWQpLCBzaXplPTQsIGFscGhhPTAuOCkreGxhYigiVGlPMiAod3QlKSIpK3lsYWIoIk5hMk8gKHd0JSkiKStzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzPWMoMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUpKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY2hlbXBhbGV0dGUpICsNCiAgVGVwaHJhLnRoZW1lDQpwMTYNCmBgYA0KDQojIyBUaU8yIFZTIEsyTw0KYGBge3IgZWNobz1GQUxTRX0NCnAxNyA8LSBwMTcgKyBnZW9tX3BvaW50KGFlcyhmaWxsID0gaWQpLCBzaXplPTQsIGFscGhhPTAuOCkreGxhYigiVGlPMiAod3QlKSIpK3lsYWIoIksyTyAod3QlKSIpK3NjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXM9YygyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSkpKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjaGVtcGFsZXR0ZSkgKw0KICBUZXBocmEudGhlbWUNCnAxNw0KYGBgDQoNCiMjIFRpTzIgVlMgUDJPNQ0KYGBge3IgZWNobz1GQUxTRX0NCnAxOCA8LSBwMTggKyBnZW9tX3BvaW50KGFlcyhmaWxsID0gaWQpLCBzaXplPTQsIGFscGhhPTAuOCkreGxhYigiVGlPMiAod3QlKSIpK3lsYWIoIlAyTzUgKHd0JSkiKStzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzPWMoMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUpKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY2hlbXBhbGV0dGUpICsNCiAgVGVwaHJhLnRoZW1lDQpwMTgNCmBgYA0KDQojIyBBbDJPMyBWUyBGZU8NCmBgYHtyIGVjaG89RkFMU0V9DQpwMTkgPC0gcDE5ICsgZ2VvbV9wb2ludChhZXMoZmlsbCA9IGlkKSwgc2l6ZT00LCBhbHBoYT0wLjgpK3hsYWIoIkFsMk8zICh3dCUpIikreWxhYigiRmVPICh3dCUpIikrc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcz1jKDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1KSkrDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNoZW1wYWxldHRlKSArDQogIFRlcGhyYS50aGVtZQ0KcDE5DQpgYGANCg0KIyMgQWwyTzMgVlMgTW5PDQpgYGB7ciBlY2hvPUZBTFNFfQ0KcDIwIDwtIHAyMCArIGdlb21fcG9pbnQoYWVzKGZpbGwgPSBpZCksIHNpemU9NCwgYWxwaGE9MC44KSt4bGFiKCJBbDJPMyAod3QlKSIpK3lsYWIoIk1uTyAod3QlKSIpK3NjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXM9YygyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSkpKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjaGVtcGFsZXR0ZSkgKw0KICBUZXBocmEudGhlbWUNCnAyMA0KYGBgDQoNCiMjIEFsMk8zIFZTIE1nTw0KYGBge3J9DQpwMjEgPC0gcDIxICsgZ2VvbV9wb2ludChhZXMoZmlsbCA9IGlkKSwgc2l6ZT00LCBhbHBoYT0wLjgpK3hsYWIoIkFsMk8zICh3dCUpIikreWxhYigiTWdPICh3dCUpIikrc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcz1jKDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1KSkrDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNoZW1wYWxldHRlKSArDQogIFRlcGhyYS50aGVtZQ0KcDIxDQpgYGANCg0KIyMgQWwyTzMgVlMgQ2FPDQpgYGB7ciBlY2hvPUZBTFNFfQ0KcDIyIDwtIHAyMiArIGdlb21fcG9pbnQoYWVzKGZpbGwgPSBpZCksIHNpemU9NCwgYWxwaGE9MC44KSt4bGFiKCJBbDJPMyAod3QlKSIpK3lsYWIoIkNhTyAod3QlKSIpK3NjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXM9YygyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSkpKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjaGVtcGFsZXR0ZSkgKw0KICBUZXBocmEudGhlbWUNCnAyMg0KYGBgDQoNCiMjIEFsMk8zIFZTIE5hMk8NCmBgYHtyIGVjaG89RkFMU0V9DQpwMjMgPC0gcDIzICsgZ2VvbV9wb2ludChhZXMoZmlsbCA9IGlkKSwgc2l6ZT00LCBhbHBoYT0wLjgpK3hsYWIoIkFsMk8zICh3dCUpIikreWxhYigiTmEyTyAod3QlKSIpK3NjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXM9YygyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSkpKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjaGVtcGFsZXR0ZSkgKw0KICBUZXBocmEudGhlbWUNCnAyMw0KYGBgDQoNCiMjIEFsMk8zIFZTIEsyTw0KYGBge3IgZWNobz1GQUxTRX0NCnAyNCA8LSBwMjQgKyBnZW9tX3BvaW50KGFlcyhmaWxsID0gaWQpLCBzaXplPTQsIGFscGhhPTAuOCkreGxhYigiQWwyTzMgKHd0JSkiKSt5bGFiKCJLMk8gKHd0JSkiKStzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzPWMoMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUpKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY2hlbXBhbGV0dGUpICsNCiAgVGVwaHJhLnRoZW1lDQpwMjQNCmBgYA0KDQojIyBBbDJPMyBWUyBQMk81DQpgYGB7ciBlY2hvPUZBTFNFfQ0KcDI1IDwtIHAyNSArIGdlb21fcG9pbnQoYWVzKGZpbGwgPSBpZCksIHNpemU9NCwgYWxwaGE9MC44KSt4bGFiKCJBbDJPMyAod3QlKSIpK3lsYWIoIlAyTzUgKHd0JSkiKStzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzPWMoMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUpKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY2hlbXBhbGV0dGUpICsNCiAgVGVwaHJhLnRoZW1lDQpwMjUNCmBgYA0KDQojIyBGZU8gVlMgTW5PDQpgYGB7ciBlY2hvPUZBTFNFfQ0KcDI2IDwtIHAyNiArIGdlb21fcG9pbnQoYWVzKGZpbGwgPSBpZCksIHNpemU9NCwgYWxwaGE9MC44KSt4bGFiKCJGZU8gKHd0JSkiKSt5bGFiKCJNbk8gKHd0JSkiKStzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzPWMoMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUpKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY2hlbXBhbGV0dGUpICsNCiAgVGVwaHJhLnRoZW1lDQpwMjYNCmBgYA0KDQojIyBGZU8gdnMgTWdPDQpgYGB7ciBlY2hvPUZBTFNFfQ0KcDI3IDwtIHAyNyArIGdlb21fcG9pbnQoYWVzKGZpbGwgPSBpZCksIHNpemU9NCwgYWxwaGE9MC44KSt4bGFiKCJGZU8gKHd0JSkiKSt5bGFiKCJNZ08gKHd0JSkiKStzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzPWMoMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUpKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY2hlbXBhbGV0dGUpICsNCiAgVGVwaHJhLnRoZW1lDQpwMjcNCmBgYA0KDQojIyBGZU8gdnMgQ2FPDQpgYGB7ciBlY2hvPUZBTFNFfQ0KcDI4IDwtIHAyOCArIGdlb21fcG9pbnQoYWVzKGZpbGwgPSBpZCksIHNpemU9NCwgYWxwaGE9MC44KSt4bGFiKCJGZU8gKHd0JSkiKSt5bGFiKCJDYU8gKHd0JSkiKStzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzPWMoMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUpKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY2hlbXBhbGV0dGUpICsNCiAgVGVwaHJhLnRoZW1lDQpwMjgNCmBgYA0KDQojIyBGZU8gVlMgTmEyTw0KYGBge3IgZWNobz1GQUxTRX0NCnAyOSA8LSBwMjkgKyBnZW9tX3BvaW50KGFlcyhmaWxsID0gaWQpLCBzaXplPTQsIGFscGhhPTAuOCkreGxhYigiRmVPICh3dCUpIikreWxhYigiTmEyTyAod3QlKSIpK3NjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXM9YygyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSkpKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjaGVtcGFsZXR0ZSkgKw0KICBUZXBocmEudGhlbWUNCnAyOQ0KYGBgDQoNCiMjIEZlTyBWUyBLMk8NCmBgYHtyIGVjaG89RkFMU0V9DQpwMzAgPC0gcDMwICsgZ2VvbV9wb2ludChhZXMoZmlsbCA9IGlkKSwgc2l6ZT00LCBhbHBoYT0wLjgpK3hsYWIoIkZlTyAod3QlKSIpK3lsYWIoIksyTyAod3QlKSIpK3NjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXM9YygyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSkpKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjaGVtcGFsZXR0ZSkgKw0KICBUZXBocmEudGhlbWUNCnAzMA0KYGBgDQoNCiMjIEZlTyBWUyBQMk81DQpgYGB7ciBlY2hvPUZBTFNFfQ0KcDMxIDwtIHAzMSArIGdlb21fcG9pbnQoYWVzKGZpbGwgPSBpZCksIHNpemU9NCwgYWxwaGE9MC44KSt4bGFiKCJGZU8gKHd0JSkiKSt5bGFiKCJQMk81ICh3dCUpIikrc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcz1jKDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1KSkrDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNoZW1wYWxldHRlKSArDQogIFRlcGhyYS50aGVtZQ0KcDMxDQpgYGANCg0KIyMgTW5PIFZTIE1nTw0KYGBge3IgZWNobz1GQUxTRX0NCnAzMiA8LSBwMzIgKyBnZW9tX3BvaW50KGFlcyhmaWxsID0gaWQpLCBzaXplPTQsIGFscGhhPTAuOCkreGxhYigiTW5PICh3dCUpIikreWxhYigiTWdPICh3dCUpIikrc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcz1jKDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1KSkrDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNoZW1wYWxldHRlKSArDQogIFRlcGhyYS50aGVtZQ0KcDMyDQpgYGANCg0KIyMgTW5PIFZTIENhTw0KYGBge3IgZWNobz1GQUxTRX0NCnAzMyA8LSBwMzMgKyBnZW9tX3BvaW50KGFlcyhmaWxsID0gaWQpLCBzaXplPTQsIGFscGhhPTAuOCkreGxhYigiTW5PICh3dCUpIikreWxhYigiQ2FPICh3dCUpIikrc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcz1jKDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1KSkrDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNoZW1wYWxldHRlKSArDQogIFRlcGhyYS50aGVtZQ0KcDMzDQpgYGANCg0KIyMgTW5PIFZTIE5hMk8NCmBgYHtyIGVjaG89RkFMU0V9DQpwMzQgPC0gcDM0ICsgZ2VvbV9wb2ludChhZXMoZmlsbCA9IGlkKSwgc2l6ZT00LCBhbHBoYT0wLjgpK3hsYWIoIk1uTyAod3QlKSIpK3lsYWIoIk5hMk8gKHd0JSkiKStzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzPWMoMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUpKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY2hlbXBhbGV0dGUpICsNCiAgVGVwaHJhLnRoZW1lDQpwMzQNCmBgYA0KDQojIyBNbk8gVlMgSzJPDQpgYGB7ciBlY2hvPUZBTFNFfQ0KcDM1IDwtIHAzNSArIGdlb21fcG9pbnQoYWVzKGZpbGwgPSBpZCksIHNpemU9NCwgYWxwaGE9MC44KSt4bGFiKCJNbk8gKHd0JSkiKSt5bGFiKCJLMk8gKHd0JSkiKStzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzPWMoMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUpKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY2hlbXBhbGV0dGUpICsNCiAgVGVwaHJhLnRoZW1lDQpwMzUNCmBgYA0KDQojIyBNbk8gVlMgUDJPNQ0KYGBge3IgZWNobz1GQUxTRX0NCnAzNiA8LSBwMzYgKyBnZW9tX3BvaW50KGFlcyhmaWxsID0gaWQpLCBzaXplPTQsIGFscGhhPTAuOCkreGxhYigiTW5PICh3dCUpIikreWxhYigiUDJPNSAod3QlKSIpK3NjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXM9YygyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSkpKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjaGVtcGFsZXR0ZSkgKw0KICBUZXBocmEudGhlbWUNCnAzNg0KYGBgDQoNCiMjIE1nTyBWUyBDYU8NCmBgYHtyIGVjaG89RkFMU0V9DQpwMzcgPC0gcDM3ICsgZ2VvbV9wb2ludChhZXMoZmlsbCA9IGlkKSwgc2l6ZT00LCBhbHBoYT0wLjgpK3hsYWIoIk1nTyAod3QlKSIpK3lsYWIoIkNhTyAod3QlKSIpK3NjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXM9YygyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSkpKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjaGVtcGFsZXR0ZSkgKw0KICBUZXBocmEudGhlbWUNCnAzNw0KYGBgDQoNCiMjIE1nTyBWUyBOYTJPDQpgYGB7ciBlY2hvPUZBTFNFfQ0KcDM4IDwtIHAzOCArIGdlb21fcG9pbnQoYWVzKGZpbGwgPSBpZCksIHNpemU9NCwgYWxwaGE9MC44KSt4bGFiKCJNZ08gKHd0JSkiKSt5bGFiKCJOYTJPICh3dCUpIikrc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcz1jKDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1KSkrDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNoZW1wYWxldHRlKSArDQogIFRlcGhyYS50aGVtZQ0KcDM4DQpgYGANCg0KIyMgTWdPIFZTIEsyTw0KYGBge3IgZWNobz1GQUxTRX0NCnAzOSA8LSBwMzkgKyBnZW9tX3BvaW50KGFlcyhmaWxsID0gaWQpLCBzaXplPTQsIGFscGhhPTAuOCkreGxhYigiTWdPICh3dCUpIikreWxhYigiSzJPICh3dCUpIikrc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcz1jKDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1KSkrDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNoZW1wYWxldHRlKSArDQogIFRlcGhyYS50aGVtZQ0KcDM5DQpgYGANCg0KIyMgTWdPIFZTIFAyTzUNCmBgYHtyIGVjaG89RkFMU0V9DQpwNDAgPC0gcDQwICsgZ2VvbV9wb2ludChhZXMoZmlsbCA9IGlkKSwgc2l6ZT00LCBhbHBoYT0wLjgpK3hsYWIoIk1nTyAod3QlKSIpK3lsYWIoIlAyTzUgKHd0JSkiKStzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzPWMoMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUpKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY2hlbXBhbGV0dGUpICsNCiAgVGVwaHJhLnRoZW1lDQpwNDANCmBgYA0KDQojIyBDYU8gVlMgTmEyTw0KYGBge3IgZWNobz1GQUxTRX0NCnA0MSA8LSBwNDEgKyBnZW9tX3BvaW50KGFlcyhmaWxsID0gaWQpLCBzaXplPTQsIGFscGhhPTAuOCkreGxhYigiQ2FPICh3dCUpIikreWxhYigiTmEyTyAod3QlKSIpK3NjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXM9YygyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSkpKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjaGVtcGFsZXR0ZSkgKw0KICBUZXBocmEudGhlbWUNCnA0MQ0KYGBgDQoNCiMjIENhTyBWUyBLMk8NCmBgYHtyIGVjaG89RkFMU0V9DQpwNDIgPC0gcDQyICsgZ2VvbV9wb2ludChhZXMoZmlsbCA9IGlkKSwgc2l6ZT00LCBhbHBoYT0wLjgpK3hsYWIoIkNhTyAod3QlKSIpK3lsYWIoIksyTyAod3QlKSIpK3NjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXM9YygyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSkpKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjaGVtcGFsZXR0ZSkgKw0KICBUZXBocmEudGhlbWUNCnA0Mg0KYGBgDQoNCiMjIENhTyBWUyBQMk81DQpgYGB7ciBlY2hvPUZBTFNFfQ0KcDQzIDwtIHA0MyArIGdlb21fcG9pbnQoYWVzKGZpbGwgPSBpZCksIHNpemU9NCwgYWxwaGE9MC44KSt4bGFiKCJDYU8gKHd0JSkiKSt5bGFiKCJQMk81ICh3dCUpIikrc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcz1jKDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1KSkrDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNoZW1wYWxldHRlKSArDQogIFRlcGhyYS50aGVtZQ0KcDQzDQpgYGANCg0KIyMgTmEyTyBWUyBLMk8NCmBgYHtyIGVjaG89RkFMU0V9DQpwNDQgPC0gcDQ0ICsgZ2VvbV9wb2ludChhZXMoZmlsbCA9IGlkKSwgc2l6ZT00LCBhbHBoYT0wLjgpK3hsYWIoIk5hMk8gKHd0JSkiKSt5bGFiKCJLMk8gKHd0JSkiKStzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzPWMoMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUpKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY2hlbXBhbGV0dGUpICsNCiAgVGVwaHJhLnRoZW1lDQpwNDQNCmBgYA0KDQojIyBOYTJPIFZTIFAyTzUNCmBgYHtyIGVjaG89RkFMU0V9DQpwNDUgPC0gcDQ1ICsgZ2VvbV9wb2ludChhZXMoZmlsbCA9IGlkKSwgc2l6ZT00LCBhbHBoYT0wLjgpK3hsYWIoIk5hMk8gKHd0JSkiKSt5bGFiKCJQMk81ICh3dCUpIikrc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcz1jKDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1KSkrDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNoZW1wYWxldHRlKSArDQogIFRlcGhyYS50aGVtZQ0KcDQ1DQpgYGANCg0KIyMgSzJPIFZTIFAyTzUNCmBgYHtyIGVjaG89RkFMU0V9DQpwNDYgPC0gcDQ2ICsgZ2VvbV9wb2ludChhZXMoZmlsbCA9IGlkKSwgc2l6ZT00LCBhbHBoYT0wLjgpK3hsYWIoIksyTyAod3QlKSIpK3lsYWIoIlAyTzUgKHd0JSkiKStzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzPWMoMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUpKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY2hlbXBhbGV0dGUpICsNCiAgVGVwaHJhLnRoZW1lDQpwNDYNCmBgYA0KDQojIyA1LjEgIFNhdmluZyBwbG90cw0KDQpXZSBwcm9wb3NlIGV4cG9ydGluZyB5b3VyIGluZGl2aWR1YWwgcGxvdHMgaW4gLnN2ZyBmb3JtYXQuIFRoaXMgaXMgYSB2ZWN0b3IgZmlsZSBmb3JtYXQgdGhhdCBwcmVzZXJ2ZXMgeW91ciBkYXRhIHdpdGhvdXQgc2l6ZSBhbmQgc2NhbGluZyBpc3N1ZXMuIEl0IGlzIGFsc28gcmVhZGFibGUgYW5kIGVkaXRhYmxlIGJ5IHNvZnR3YXJlIGxpa2UgQWRvYmUgSWxsdXN0cmF0b3IsIEFmZmluaXR5IERlc2lnbmVyLCBvciBmcmVlIGFsdGVybmF0aXZlcyBsaWtlIElua3NjYXBlLiBVc2luZyB0aGUgZmlsZSBzdHJ1Y3R1cmUgcHJlc2VudGVkIGhlcmUgdGhlIGFsbCBwbG90cyBjYW4gYmUgbmFtZWQgYXBwcm9wcmlhdGVseSBhbmQgd2lsbCBiZSBzYXZlZCBpbiB0aGUgT3V0cHV0IC0+IFBsb3RzIGZvbGRlci4gVGhlIHdpZHRoIGFuZCBoZWlnaHQgYW5kIGRwaSBvdXRwdXRzIGNhbiBiZSBhbHRlcmVkIGJ1dCBvdmVycmlkZSB0aGUgcHJldmlldyBmdW5jdGlvbnMgaW4gUnN0dWRpbyBhbmQgd2UgcmVjb21tZW5kIHRoYXQgeW91IHZpZXcgdGhlIHN2ZyBmaWxlIGRpcmVjdGx5IGluIHlvdSBwcmVmZXJyZWQgaW1hZ2UgZWRpdG9yIHRvIHVuZGVyc3RhbmQgaG93IGl0IG1pZ2h0IGxvb2suDQoNCmBgYHtyfQ0KZ2dzYXZlKCBmaWxlbmFtZSA9IGZpbGUucGF0aCgiU2NyaXB0IiwgIk91dHB1dCIsIlBsb3RzIiwiZmlnMS5zdmciKSwgcGxvdCA9IHAxLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSA2LCBkcGkgPSAzMDApDQpgYGANCg0KIyB7LX0NCg0KIyA2LjAgTXVsdGl2YXJpYXRlIGFuYWx5c2lzIHsudGFic2V0IC50YWJzZXQtcGlsbHN9DQpNdWx0aXZhcmlhdGUgYW5hbHlzaXMgdmlhIG9yZGluYXRpb24gaXMgb2Z0ZW4gYSBoZWxwZnVsIHdheSBvZiBleHBsb3JpbmcgeW91ciBkYXRhLiBJdCBwZXJtaXRzIHRoZSBpZGVudGlmaWNhdGlvbiBvZiB1c2VmdWwgZWxlbWVudHMgZm9yIGRpc2NyaW1pbmF0aW9uIGFuZCBmYWNpbGl0YXRlcyBkaW1lbnNpb24gcmVkdWN0aW9uLiBVbmZvcnR1bmF0ZWx5LCBwZXJjZW50YWdlIGRhdGEgY2FuIGhhdmUgcHJvYmxlbWF0aWMgY292YXJpYXRpb24gYW5kIHNob3VsZCBiZSAnZnJlZWQnIGZyb20gdGhlaXIgY29tcG9zaXRpb25hbCBzdW0gd2hlcmUgcG9zc2libGUuIFRoaXMgY2FuIGJlIGFjaGlldmVkIHZpYSB1bmRlcnRha2luZyBhIGNlbnRyZWQgbG9nLXJhdGlvIHRyYW5zZm9ybS4gVGhpcyBpcyBwZXJmb3JtZWQgdXNpbmcgdGhlIGNvZGUgZ2l2ZW4gYmVsb3cNCg0KYGBge3J9DQpjaGVtX211bHRpIDwtIGNoZW1bIC1jKDEsNiwxMSwxMiwxMywxNCwxNSldICMjIGNoZWNrIGNvbHVtbnMgdG8gZHJvcC4gQ3VycmVudGx5IGRyb3BwaW5nIGlkLCBNbk8sIFAyTzUsIFRvdGFsLCBhbmQgVEFTIGNhbGN1bGF0aW9ucyB0byBwZXJmb3JtIHRoZSBjbHIgdHJhbnNmb3JtLg0KY2hlbV9tdWx0aVtpcy5uYShjaGVtX211bHRpKV0gPC0gMC4wMDUgIyByZXBsYWNlIE5BcyB3aXRoIGhhbGYgdGhlIGRldGVjdGlvbiBsaW1pdA0KY2hlbV9tdWx0aV9jbHIgPC0gY2xyKGNoZW1fbXVsdGkpDQpjbWNsciA8LSBhcy5kYXRhLmZyYW1lKGNoZW1fbXVsdGlfY2xyKQ0KaGVhZChjbWNscikgIyBUaGlzIHBlcm1pdHMgdXMgdGhlIG9wcG9ydHVuaXR5IHRvIHZpZXcgdGhlIGNlbnRyZWQgbG9nLXJhdGlvIGRhdGFzZXQuDQpgYGANCg0KV2UgY2FuIHN1bW1hcmlzZSB0aGUgaW1wb3J0YW5jZSBvZiB0aGUgcmVzdWx0aW5nIHByaW5jaXBhbCBjb21wb25lbnRzIGJ5IHN1bW1hcml6aW5nIGhvdyBtdWNoIG9mIHRoZSB0b3RhbCB2YXJpYW5jZSBpcyBjYXB0dXJlZCBieSBlYWNoIHByaW5jaXBhbCBjb21wb25lbnQuDQoNCiMjIDYuMSBQQ0Egc3VtbWFyeQ0KYGBge3IgZWNobz1GQUxTRX0NCnBjYXNjb3JlcyA8LSBwcmNvbXAoY21jbHIpDQpzdW1tIDwtIGFzLmRhdGEuZnJhbWUoc3VtbWFyeShwY2FzY29yZXMpJGltcG9ydGFuY2UpDQpzdW1tIDwtIHRpYmJsZTo6cm93bmFtZXNfdG9fY29sdW1uKHN1bW0sICJJbmZvcm1hdGlvbiIpDQpzdW1tICU+JSBndCgpDQpgYGANCklmIHRoaXMgaGFzIGNhcHR1cmVkIGEgc2lnbmlmaWNhbnQgYW1vdW50IG9mIHZhcmlhdGlvbiBpdCB3b3VsZCBiZSB3b3J0aCBwbG90dGluZyB0aGUgb3V0cHV0IGluIG9yZGVyIHRvIGlkZW50aWZ5IHRoZSBpbXBvcnRhbnQgdmFyaWFibGVzIGluIGRldGVybWluaW5nIHRoZSBjaGFuZ2VzIG9ic2VydmVkLg0KDQojIyA2LjMgUENBIHNjb3JlcyBzY3JlZSBwbG90DQpgYGB7ciB3YXJuaW5nID0gRkFMU0UsIGVjaG89RkFMU0V9DQpmdml6X2VpZyhwY2FzY29yZXMpDQoNCmBgYA0KDQpUaGlzIGlzIGEgdmlzdWFsIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBzdW1tYXJ5IHRhYmxlIHNob3dpbmcgdGhlIHBlcmNlbnRhZ2Ugb2YgdGhlIHRvdGFsIHZhcmlhbmNlIGV4cGxhaW5lZCBieSBlYWNoIGRpbWVuc2lvbi4NCg0KIyMgNi40IFZhcmlhYmxlcyBQQ0EgcGxvdA0KYGBge3Igd2FybmluZyA9IEZBTFNFLCBlY2hvPUZBTFNFfQ0KZnZpel9wY2FfdmFyKHBjYXNjb3JlcywgY29sLnZhciA9ICJjb250cmliIiwgIyBDb2xvciBieSBjb250cmlidXRpb25zIHRvIHRoZSBQQw0KICAgICAgICAgICAgIGdyYWRpZW50LmNvbHMgPSBjKCIjMDBBRkJCIiwgIiNFN0I4MDAiLCAiI0ZDNEUwNyIpLA0KICAgICAgICAgICAgIHJlcGVsID0gVFJVRSAgICAgIyBBdm9pZCB0ZXh0IG92ZXJsYXBwaW5nDQopDQpgYGANCg0KDQojIyA2LjUgTG9hZGluZ3MgZGltZW5zaW9uIDENCmBgYHtyIGVjaG89RkFMU0V9DQpmdml6X2NvbnRyaWIocGNhc2NvcmVzLCBjaG9pY2U9InZhciIsIGF4ZXMgPSAxLGZpbGwgPSAiIzAwQUZCQiIsIGNvbG9yID0gImJsYWNrIikgK3RoZW1lX21pbmltYWwoKSArdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9NDUpKQ0KYGBgDQoNCiMjIDYuNiBMb2FkaW5ncyBkaW1lbnNpb24gMg0KDQpgYGB7ciBlY2hvPUZBTFNFfQ0KZnZpel9jb250cmliKHBjYXNjb3JlcywgY2hvaWNlPSJ2YXIiLCBheGVzID0gMixmaWxsID0gIiMwMEFGQkIiLCBjb2xvciA9ICJibGFjayIpICt0aGVtZV9taW5pbWFsKCkgK3RoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTQ1KSkNCmBgYA0KDQojIyA2LjcgUENBIC0gQmlwbG90DQpgYGB7ciB3YXJuaW5nID0gRkFMU0UsIGVjaG89RkFMU0V9DQpmdml6X3BjYV9iaXBsb3QocGNhc2NvcmVzLCByZXBlbCA9IEZBTFNFLA0KICAgICAgICAgICAgICAgIGNvbC52YXIgPSAiIzJFOUZERiIsICMgVmFyaWFibGVzIGNvbG9yDQogICAgICAgICAgICAgICAgY29sLmluZCA9ICIjNjk2OTY5IiAgIyBJbmRpdmlkdWFscyBjb2xvcg0KKQ0KYGBgDQoNCiMjIDYuOCBQQ0EgLSBncm91cGVkDQpgYGB7ciB3YXJuaW5nID0gRkFMU0UsIGVjaG89RkFMU0V9DQpwY291dCA8LSBwY2FzY29yZXMkeA0KaWQgPC0gYXMuZGF0YS5mcmFtZShjaGVtJGlkKQ0KaWQgPC0gdW5saXN0KGlkKQ0KaWQgPC0gYXNfZGF0YV9mcmFtZShpZCkNCnBjb3V0IDwtIGNiaW5kKGlkLCBwY291dCkNCmNvbG5hbWVzKHBjb3V0KVtjb2xuYW1lcyhwY291dCk9PSJ2YWx1ZSJdIDwtICJpZCINCnBjMXBsb3QgPC0gZ2dwbG90KHBjb3V0LCBhZXMoeCA9IFBDMSwgeSA9IFBDMiwgZmlsbCA9IGlkLCBzaGFwZSA9IGlkKSkNCnBjMXBsb3QgPC0gcGMxcGxvdCArIGdlb21fcG9pbnQoYWVzKGZpbGwgPSBpZCksIHNpemU9NCwgYWxwaGE9MC44KSt4bGFiKCJQQzEiKSt5bGFiKCJQQzIiKSt0aGVtZV9idygpK3RoZW1lKGF4aXMudGl0bGUueD1lbGVtZW50X3RleHQoc2l6ZT0xNiksIGF4aXMudGl0bGUueT1lbGVtZW50X3RleHQoc2l6ZT0xNiksIGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChzaXplPTE2KSwgYXhpcy50ZXh0Lnk9ZWxlbWVudF90ZXh0KHNpemU9MTYpKStzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzPWMoMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUpKStzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGNoZW1wYWxldHRlKSArDQogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY2hlbXBhbGV0dGUpICsNCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcz1jKDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1KSkNCg0KICBwYzFwbG90DQpgYGANCg0KIyB7LX0NCg0KIyA3LjAgSW50ZXJhY3RpdmUgZmlndXJlcyB7LnRhYnNldCAudGFic2V0LXBpbGxzfQ0KDQpUaGUgZnVuY3Rpb24gZ2dwbG90bHkgd2l0aGluIHRoZSBwbG90bHkgcGFja2FnZSBpcyBleHRyZW1lbHkgdXNlZnVsIGZvciBpbnRlcmFjdGl2ZWx5IGV4YW1pbmluZyBkYXRhLiBnZ3Bsb3RseSBwbG90cyBhbGxvdyB5b3UgdG8gem9vbSBpbnRvIGFyZWFzIG9mIGludGVyZXN0IGFuZCB0dXJuIGxheWVycyBvbiBhbmQgb2ZmIGFzIHdlbGwgYXMgc2F2aW5nIGxvdyByZXNvbHV0aW9uIC5wbmcgZmlsZXMgb2Ygem9vbWVkIHNlY3Rpb25zIG9mIHlvdXIgcGxvdHMuIFdlIHJlZmVyIHRvIHRoZXNlIGFzIGlQbG90cyAoaW50ZXJhY3RpdmUgcGxvdHMpIGluIG9yZGVyIHRvIGRpc3Rpbmd1aXNoIHRoZW0gZnJvbSBzdGF0aWMgcGxvdHMgcHJlc2VudGVkIGFib3ZlLiBUaGVzZSBhcmUgZXhjZWxsZW50IGZvciBnZW5lcmF0aW5nIHF1aWNrIHBsb3RzIHRvIHN1cHBvcnQgeW91ciBpbmZlcmVuY2VzIGFib3V0IHlvdXIgZGF0YS4gVGhlIHBsb3RzIGNhbiBiZSBleHBvcnRlZCBhcyAucG5nIGZpbGVzLg0KDQojIyBpVEFTIHBsb3QNCmBgYHtyIHdhcm5pbmcgPSBGQUxTRSwgZWNobz1GQUxTRX0NCmdncGxvdGx5KHAxLCB3aWR0aCA9IDEwMDAsIGhlaWdodCA9IDgwMCkNCmBgYA0KDQojIyBpRmVPLUNhTw0KYGBge3Igd2FybmluZyA9IEZBTFNFLCBlY2hvPUZBTFNFfQ0KZ2dwbG90bHkocDI4LCB3aWR0aCA9IDEwMDAsIGhlaWdodCA9IDgwMCkNCmBgYA0KIyMgaUstbGluZXMNCmBgYHtyIHdhcm5pbmcgPSBGQUxTRSwgZWNobz1GQUxTRX0NCmdncGxvdGx5KHA0Nywgd2lkdGggPSAxMDAwLCBoZWlnaHQgPSA4MDAsIGR5bmFtaWNUaWNrcyA9IFRSVUUpDQpgYGANCiMjIGlUaU8yIHZzIEFsMk8zDQpgYGB7ciB3YXJuaW5nID0gRkFMU0UsIGVjaG89RkFMU0V9DQpnZ3Bsb3RseShwMTEsIHdpZHRoID0gMTAwMCwgaGVpZ2h0ID0gODAwLCBkeW5hbWljVGlja3MgPSBUUlVFKQ0KYGBgDQoNCg0KIyMgaUsyTyB2cyBDYU8NCmBgYHtyIHdhcm5pbmcgPSBGQUxTRSwgZWNobz1GQUxTRX0NCmdncGxvdGx5KHA0Miwgd2lkdGggPSAxMDAwLCBoZWlnaHQgPSA4MDAsIGR5bmFtaWNUaWNrcyA9IFRSVUUpDQpgYGANCg0KDQoNCiMjIHstfQ0KDQojIDguMCBTYXZpbmcgYWxsIGZpZ3VyZXMgdG8gYSAucGRmDQoNCg0KYGBge3J9DQpsIDwtIGxpc3QocDEsIHAyLCBwMywgcDQsIHA1LCBwNiwgcDcsIHA4LCBwOSwgcDQ3LCBwMTAsIHAxMSwgcDEyLCBwMTMsIHAxNCwgcDE1LCBwMTYsIHAxNywgcDE4LCBwMTksIHAyMCwgcDIxLCBwMjIsIHAyMywgcDI0LCBwMjUsIHAyNiwgcDI3LCBwMjgsIHAyOSwgcDMwLCBwMzEsIHAzMiwgcDMzLCBwMzQsIHAzNSwgcDM2LCBwMzcsIHAzOCwgcDM5LCBwNDAsIHA0MSwgcDQyLCBwNDMsIHA0NCwgcDQ1LCBwNDYpDQpwZGYoImFsbHBsb3Rzb3V0LnBkZiIsIHdpZHRoID0gMTIsIGhlaWdodCA9IDYpDQppbnZpc2libGUobGFwcGx5KGwsIHByaW50KSkNCmRldi5vZmYoKQ0KYGBgDQoNCiMgOS4wIEhhcmtlciBwbG90DQpJdCBpcyBmcmVxdWVudGx5IHVzZWZ1bCB0byBwbG90IGFsbCBvZiB0aGUgY29sbGVjdGVkIGVsZW1lbnRhbCBkYXRhIGFnYWluc3QgU2lPWzJdLiBUaGlzIHBlcm1pdHMgYW4gYXNzZXNzbWVudCBvZiBncm91cGluZ3Mgd2l0aGluIHRoZSBkYXRhIGFuZCB3aGljaCBlbGVtZW50cyBtaWdodCBiZSB1c2VmdWwgZGlzY3JpbWluYXRvcnMuIEFkZGl0aW9uYWxseSwgd3QlIEsyTyB2cyBTaU8yIGNhbiBmdXJ0aGVyIGNsYXNzaWZ5IHRoZSB0ZXBocmEgdG8gbG93LCBtaWQgYW5kIGhpZ2ggUG90YXNzaXVtIHZhbHVlcy4gVGhlIGRpdmlkaW5nIGxpbmVzIGluY2x1ZGVkIGhlcmUgYXJlIGZyb20geHh4eHh4eHguDQpgYGB7ciBmaWcuaGVpZ2h0ID0gMTAsIGZpZy53aWR0aCA9IDE4fQ0KZzEgPC0gcGxvdF9ncmlkKHAxICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSwgDQogICAgICAgICAgICAgICAgcDIgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpLA0KICAgICAgICAgICAgICAgIHAzICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIiksDQogICAgICAgICAgICAgICAgcDQgKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSwNCiAgICAgICAgICAgICAgICBwNSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpLA0KICAgICAgICAgICAgICAgIHA2ICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIiksDQogICAgICAgICAgICAgICAgcDcgKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSwNCiAgICAgICAgICAgICAgICBwOCArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpLCANCiAgICAgICAgICAgICAgICBwNDcgKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSwgDQogICAgICAgICAgICAgICAgcDEwICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIiksDQogICAgICAgICAgICAgICAgbGFiZWxzID0gYygiQSIsICJCIiwgIkMiLCAiRCIsICJFIiwgIkYiLCAiRyIsICJIIiwgIkkiLCAiSiIpLCBhbGlnbiA9ICJiIikNCmxlZ2VuZCA8LSBnZXRfbGVnZW5kKHAxKQ0KbGVncGxvdCA8LSBwbG90X2dyaWQobGVnZW5kKQ0KcHggPC0gcGxvdF9ncmlkKCBnMSwgcmVsX3dpZHRocyA9IGMoNCwgMSkpDQpsMiA8LSBsaXN0KHB4LGxlZ3Bsb3QpDQpwZGYoIlNjcmlwdC9PdXRwdXQvUGxvdHMvSGFya2VycGxvdC5wZGYiLCB3aWR0aCA9IDMwLCBoZWlnaHQgPSAyMCkNCmludmlzaWJsZShsYXBwbHkobDIsIHByaW50KSkNCmRldi5vZmYoKQ0KDQpnZ3NhdmUoIGZpbGVuYW1lID0gZmlsZS5wYXRoKCJTY3JpcHQiLCJPdXRwdXQiLCJQbG90cyIsIkhhcmtlci5zdmciKSwgcGxvdCA9IHB4LCB3aWR0aCA9IDMwLCBoZWlnaHQgPSAyMCwgZHBpID0gMzAwKQ0KDQpwcmludChnMSkNCg0KYGBgDQoNCiMgMTAuMCBPdGhlciB1c2VmdWwgcGxvdHMNCg0KIyMgMTAuMSBDcmVhdGluZyBhbiBpbnNldCB3aXRoaW4gYSBmaWd1cmUNCmBgYHtyIHdhcm5pbmc9RkFMU0UgfQ0KcDEwMCA8LSBnZ3Bsb3QoY2hlbSwgYWVzKHggPSBUQVNfeCwgeSA9IFRBU195LCBmaWxsID0gaWQsIHNoYXBlID0gaWQpKQ0KcDEwMCA8LSBwMTAwICsgZ2VvbV9wb2ludChhZXMoZmlsbCA9IGlkKSwgc2l6ZT00LCBhbHBoYT0wLjgpK3hsYWIoIlNpTzIgKHd0JSkiKSt5bGFiKCJOYTJPK0syTyAod3QlKSIpKw0KICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzPWMoMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUpKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY2hlbXBhbGV0dGUpICtnZW9tX3NlZ21lbnQoeD03Nyx5PTAseGVuZD02OSx5ZW5kPTgpKyANCiAgZ2VvbV9zZWdtZW50KHg9NjksIHk9OCx4ZW5kPTY5LHllbmQ9MTMpK2dlb21fc2VnbWVudCh4PTQxLCB5PTcseGVuZD01Mi41LHllbmQ9MTQpKw0KICBnZW9tX3NlZ21lbnQoeD01Mi41LHk9MTQseGVuZD01Ny42LHllbmQ9MTEuNykrZ2VvbV9zZWdtZW50KHg9NDUseT0wLHhlbmQ9NDUseWVuZD01KSsNCiAgZ2VvbV9zZWdtZW50KHg9NDUseT01LHhlbmQ9NjMseWVuZD0xNC41NikrZ2VvbV9zZWdtZW50KHg9NTIseT0wLHhlbmQ9NTIseWVuZD01KSsNCiAgZ2VvbV9zZWdtZW50KHg9NTIseT01LHhlbmQ9NjMseWVuZD03KStnZW9tX3NlZ21lbnQoeD01Nyx5PTAseGVuZD01Nyx5ZW5kPTUuOSkrDQogIGdlb21fc2VnbWVudCh4PTYzLHk9MCx4ZW5kPTYzLHllbmQ9NykrZ2VvbV9zZWdtZW50KHg9NDUseT01LHhlbmQ9NTIseWVuZD01KSsNCiAgZ2VvbV9zZWdtZW50KHg9NTIseT01LHhlbmQ9NDkuNCx5ZW5kPTcuMykrZ2VvbV9zZWdtZW50KHg9NTcseT01LjkseGVuZD01Myx5ZW5kPTkuMykrDQogIGdlb21fc2VnbWVudCh4PTYzLHk9Nyx4ZW5kPTU3LjYseWVuZD0xMS43KStnZW9tX3NlZ21lbnQoeD00OS40LHk9Ny4zLHhlbmQ9NDUseWVuZD05LjQpKw0KICBnZW9tX3NlZ21lbnQoeD01Myx5PTkuMyx4ZW5kPTQ4LjQseWVuZD0xMS41KStnZW9tX3NlZ21lbnQoeD00MSx5PTAseGVuZD00MSx5ZW5kPTcpKw0KICBnZW9tX3NlZ21lbnQoeD01Mi41LHk9MTQseGVuZD00OSx5ZW5kPTE1LjUpK2dlb21fc2VnbWVudCh4PTQxLHk9Myx4ZW5kPTQ1LHllbmQ9MykrDQogIGdlb21fc2VnbWVudCh4PTYzLHk9Nyx4ZW5kPTY5LHllbmQ9OCkrDQogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHM9Yyg3NCwgNzkpLCBleHBhbmQgPSBjKDAsIDApKSArICMjIHNldCB4IGF4aXMgb2YgaW5zZXJ0DQogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHM9Yyg2LCAxMC41KSwgZXhwYW5kID0gYygwLCAwKSkgKyAjIyBzZXQgeSBheGlzIG9mIGluc2VydA0KICB0aGVtZV9idygpK3RoZW1lKGF4aXMudGl0bGUueD1lbGVtZW50X3RleHQoc2l6ZT05KSwgYXhpcy50aXRsZS55PWVsZW1lbnRfdGV4dChzaXplPTkpLCANCiAgICAgICAgICAgICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X3RleHQoc2l6ZT05KSwgYXhpcy50ZXh0Lnk9ZWxlbWVudF90ZXh0KHNpemU9OSkpKyAjIyBjaGFuZ2UgdGhlIHRleHQgc2l6ZSBhcyBuZWNjZXNzYXJ5DQogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCmZpZ19pbiA8LSBwMSArIGFubm90YXRpb25fY3VzdG9tKGdncGxvdEdyb2IocDEwMCksIHhtaW4gPSA0MCwgeG1heCA9IDU2LCB5bWluID0gNywgeW1heCA9IDE2KSArICMjIHBsYWNlIHRoZSBpbnNlcnQNCiAgIGFubm90YXRlKCJyZWN0IiwgeG1pbiA9IDc0LCB4bWF4ID0gNzksIHltaW4gPSA2LCB5bWF4ID0gMTAuNSwNCiAgYWxwaGEgPSAuMikgIyMgdXNlIHRoaXMgdG8gaGlnaGxpZ2h0IHRoZSBhcmVhIG9mIHRoZSBpbnNlcnQgcGxvdA0KYGBgDQoNCmBgYHtyIGZpZy5oZWlnaHQgPSAxMCwgZmlnLndpZHRoID0gMTh9DQpnZ3NhdmUoIGZpbGVuYW1lID0gZmlsZS5wYXRoKCJTY3JpcHQiLCAiT3V0cHV0IiwiUGxvdHMiLCJpbnNlcnRfcGxvdC5zdmciKSwgcGxvdCA9IGZpZ19pbiwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNiwgZHBpID0gMzAwKQ0KDQpwcmludChmaWdfaW4pDQpgYGANCg0KIyMgMTAuMiBDcmVhdGluZyBhIEhEUiBwbG90IHRvIHNpbXBsaWZ5IHlvdXIgZGF0YS4NClNpbXBsaWZ5aW5nIHRoZSBkYXRhIHdlIGNyZWF0ZSB0byBtYWtlIG1vcmUgdmlzdWFsbHkgY29tcGVsbGluZyBmaWd1cmVzIGNhbiBiZSBhY2hpZXZlZCB1c2luZyBoaWdoZXN0IGRlbnNpdHkgcmVnaW9ucy4gVGhlIGZvbGxvd2luZyBjb2RlIHBlcm1pdHMgdGhpcyBhcyBhbiBhZGRpdGlvbiB0byB0aGUgcHJldmlvdXNseSBjcmVhdGVkIHBsb3RzIGFuZCBhcyBuZXcgcGxvdHMuIEl0IGNhbiBiZSBhZGRlZCBlYXNpbHkgdG8gYW55IG9mIHRoZSBwcmV2aW91c2x5IGNyZWF0ZWQgcGxvdHMgYnkgY2hhbmdpbmcgdGhlIHAgY29kZS4gVmlzaWJpbGl0eSBvZiB0aGUgZGVuc2l0eSByZWdpb25zIGNhbiBiZSBhcHBsaWVkIHRvIGp1c3QgcmVmZXJlbmNlIGRhdGEgb3IgZW50aXJlIGRhdGFzZXRzLiBPcGFjaXR5IGlzIHZhcmllZCB1c2luZyB0aGUgYWxwaGEgY29tbWFuZCBhbmQgdGhlIHByb2JhYmlsaXR5IHJhbmdlIGNhbiBiZSBhbHRlcmVkIGluIHRoZSAncHJvYnMnIGFyZ3VtZW50LiBZb3UgbWF5IG5lZWQgdG8gdmFyeSB0aGUgeCBhbmQgeSBheGVzIGluIG9yZGVyIHRvIGZpdCB0aGUgZnVsbCByYW5nZSBpbiB0byB0aGUgcGxvdC4gVGhlc2UgdHlwZXMgb2YgcGxvdHMgYXJlIGJlc3QgdXNlZCBmb3IgZ2l2aW5nIGJldHRlciBlcnVwdGl2ZSBjaGVtaWNhbCBlbnZlbG9wZXMgKGZpZWxkcykgdGhhbiBoYW5kIGRyYXdpbmcgYXJvdW5kIGV4aXN0aW5nIGRhdGEuIA0KDQpgYGB7cn0NCnAyOGRlbiA8LSBwMjggKw0KZ2VvbV9oZHIoc3RhdD0gImhkciIsIG1ldGhvZCA9ICJrZGUiLCBuYS5ybSA9IFRSVUUsIGluaGVyaXQuYWVzID0gVFJVRSwgYWxwaGEgID0gMC4zLCB4bGltID0gYygwLDEwMCksIHlsaW0gPSBjKDAsMzApLCBzbW9vdGggPSBUUlVFLCBuID0gMTAwMCwgcHJvYnMgPSBjKDAuNzUpKQ0KcHJpbnQocDI4ZGVuKQ0KDQoNCmBgYA0KDQojIyAxMC4zIEZhY2V0ZWQgcGxvdHMgdG8gZGVhbCB3aXRoIGxvdHMgb2YgZGF0YQ0KVGhlIGtkZSBwbG90cyBhcmUgaW50ZXJlc3RpbmcgYnV0IG1lc3N5IGFuZCBzdGlsbCBoYXZlIGxvdHMgb2Ygb3ZlcnBsb3R0aW5nLiBUaGlzIGlzIG5vdCBpZGVhbCBmb3IgZGF0YSB2aXN1YWxpc2F0aW9uLiBXaGlsZSBpdCBtYXkgYmUgaGVscGZ1bCB0byB2YXJ5IHRoZSBjb2xvdXJzIG9yIG9wYWNpdHksIHRoZXJlIGlzIG9ubHkgc28gbXVjaCB0aGF0IHRoaXMgY2FuIGFjaGVpdmUuIElmIHlvdSBoYXZlIHBhcnRpY3VsYXJseSBtZXNzeSBkYXRhIGxpa2UgdGhlIE9EUC05ODAgZGF0YXNldCBJJ2Qgc3VnZ2VzdCBjcmVhdGluZyBwbG90ICdmYWNldHMnIHVzaW5nIHRoZSBmb2xsb3dpbmcgY29kZS4NCg0KYGBge3J9DQpwMjhkZW5fZmFjZXQgPC0gcDI4ICsNCmdlb21faGRyKG1ldGhvZCA9ICJrZGUiLCBhbHBoYSAgPSAwLjUsIHhsaW0gPSBjKDAsMTAwKSwgeWxpbSA9IGMoMCwzMCksIHNob3cubGVnZW5kID0gRkFMU0UsIHNtb290aCA9IFRSVUUsIG4gPSAxMDAwLCBwcm9icyA9IGMoMC45NSkpICsNCiAgZmFjZXRfd3JhcCh+IGlkKQ0KDQoNCnByaW50KHAyOGRlbl9mYWNldCkNCmBgYA0KDQpUaGUgZmFjZXQgcmVtb3ZlcyBzb21lIG9mIHRoZSBjb21wbGV4aXR5IGFuZCBwZXJtaXRzIHRoZSBrZGUgdG8gYmUgdmlzdWFsaXNlZCBtb3JlIGNsZWFybHksIGJ1dCBhcmd1YWJseSB5b3UgbG9zZSBzb21lIG9mIHRoZSBrZXkgaW5mb3JtYXRpb24gYWJvdXQgdG90YWwgcmFuZ2VzIG9mIGNoZW1pY2FsIGRhdGEuIEluIHRoZSBzZWNvbmQgZmFjZXRlZCBwbG90IChiZWxvdykgd2UgcmVtb3ZlIHRoZSBrZXJuZWwgZGVuc2l0eSBpbmZvcm1hdGlvbiBhbmQgdXNlIHRoZSB0b3RhbCBkYXRhc2V0IGFzIGEgYmFja2dyb3VuZCB0byB0aGUgZmFjZXRzIGluIG9yZGVyIHRvIHVuZGVyc3RhbmQgdGhlIHRvdGFsIHJhbmdlIGFuZCBvdXIgb3duIGluZGl2aWR1YWwgc2FtcGxlcy4gVGhpcyByZXF1aXJlcyBhIGxpdHRsZSBiaXQgb2YgZGF0YSBtYW5pcHVsYXRpb24gaW4gb3JkZXIgdG8gY3JlYXRlIHR3byBkYXRhc2V0cywgb25lIGZvciB0aGUgdG90YWwgZGF0YSBzcHJlYWQgYW5kIGFub3RoZXIgZm9yIHRoZSBmYWNldHMuDQoNCmBgYHtyfQ0KY2hlbTIgPC0gZHBseXI6OnNlbGVjdChjaGVtLCAtVG90YWwpICMgY3JlYXRlcyB0aGUgc2Vjb25kIGRhdGFzZXQgZnByIHBsb3R0aW5nDQpjaGVtMiA8LSByZW5hbWUoY2hlbTIsIGlkMj1pZCkgIyByZW1vdmVzIGNvbmZ1c2lvbiBvdmVyIGNvbHVtbiBuYW1lcw0KZjE5IDwtIGdncGxvdChjaGVtLCBhZXMoeCA9IEZlTywgeSA9IENhTywgIGZpbGwgPSBpZCwgc2hhcGUgPSBpZCkpICMgY3JlYXRlcyBhIG5ldyBwbG90IG9mIEZlTyBhbmQgQ2FPLg0KDQpmMTkgPC0gZjE5ICsgDQogICAgZ2VvbV9wb2ludChkYXRhID0gY2hlbTIsIGluaGVyaXQuYWVzID0gRkFMU0UsIGFlcyh4PUZlTywgeSA9IENhTywgc2hhcGUgPSBpZDIpLCBjb2xvdXIgPSAiZ3JleTcwIikgKyAjIyBhZGRzIGFsbCB0aGUgZGF0YSB0byB0aGUgcGxvdCB1c2luZyBhIGdyZXkgY29sb3VyIHNjaGVtZQ0KICBnZW9tX3BvaW50KGFlcyhmaWxsID0gaWQpLCBzaXplPTQsIGFscGhhPTAuOCkreGxhYigiRmVPICh3dCUpIikreWxhYigiQ2FPICh3dCUpIikrc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcz1jKDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1KSkrICMgYWRkcyBhbGwgdGhlIGRhdGEgYWdhaW4gYnV0IHJldGFpbiB0aGUgZ3JvdXBzDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNoZW1wYWxldHRlKSArICMjIGFkZHMgc3RhbmRhcmQgY29sb3Vycw0KICBUZXBocmEudGhlbWUgKyAjIGFkZHMgc3RhbmRhcmQgdGhlbWUNCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsMjApLCB5bGltID0gYygwLDE1KSkgKyAjIHNjYWxlIHRoZSBwbG90cyB0byBkaXNwbGF5IHRoZSBkYXRhIGVmZmVjdGl2ZWx5DQogIGZhY2V0X3dyYXAofiBpZCkgIyBmYWNldHMgdGhlIGRpYWdyYW0gdXNpbmcgaWQgaW4gdGhlIG1haW4gZGF0YXNldC4NCg0KcHJpbnQoZjE5KQ0KDQpnZ3NhdmUoIGZpbGVuYW1lID0gZmlsZS5wYXRoKCJTY3JpcHQiLCAiT3V0cHV0IiwiUGxvdHMiLCJmYWNldGVkIHBsb3QucGRmIiksIHBsb3QgPSBmMTksIHdpZHRoID0gMzAsIGhlaWdodCA9IDIwLCB1bml0cyA9ICJjbSIsIGRwaSA9IDMwMCkNCg0KDQoNCmBgYA0KDQojIDExLjAgQ29tcGFyaW5nIHVua25vd24gc2FtcGxlcw0KQWxsIG9mIHRoZSBhYm92ZSBjb2RlIGNhbiBiZSB1c2VkIG9uIHVua25vd24gc2FtcGxlcyBhbmQgZm9yIHlvdXIgb3duIGRhdGEgZXhwbG9yYXRpb24uIEl0IGNhbiBhbHNvIGJlIHVzZWQgdG8gZXhwbG9yZSBhIHJlZmVyZW5jZSBkYXRhc2V0IGluIG9yZGVyIHRvIHVuZGVyc3RhbmQgd2hhdCBjaGVtaWNhbCBwbG90cyBjYW4gYmUgdXNlZCB0byBiZXN0IGRpZmZlcmVudGlhdGUgdGVwaHJhIGZyb20gZGlmZmVyZW50IHZvbGNhbm9lcyBhbmQgZXZlbiBkaWZmZXJlbnQgZXJ1cHRpb25zLiBIb3dldmVyLCBzb21lIHRpbWVzIGl0IGlzIGJldHRlciB0byBrZWVwIHRoZSBleHBsb3JhdGlvbiBhbmQgYW5hbHlzaXMgcGhhc2VzIHNlcGFyYXRlLiBUaGlzIHNlY3Rpb24gbG9va3MgYXQgaW1wb3J0aW5nIGEgc3BlY2lmaWMgdW5rbm93biB0ZXBocmEgYW5kIG1ha2luZyBkaXJlY3QgY29tcGFyaXNvbnMgdG8gYSByZWZlcmVuY2UgZGF0YXNldC4gSXQgdXNlcyB0aGUgT0RQLTk4MCBkYXRhIHByZXNlbnRlZCBhYm92ZSBhcyBhIHJlY29yZCBvZiB2b2xjYW5pc20gaW4gdGhlIE5vcnRoIEF0bGFudGljIGR1cmluZyBNSVMtMTFjIGFuZCB0aGVuIGNvbXBhcmVzIHRoaXMgd2l0aCBvdXIgdW5rbm93biB0ZXBocmEgZnJvbSBhIHNpdGUgaW4gRW5nbGFuZCBjYWxsZWQgTWFya3MgVGV5LiBGaXJzdCB3ZSBsb2FkIGFuZCBzdW1tYXJpc2UgdGhlIGRhdGEgYXMgYmVmb3JlIGJ1dCB0aGVuIHdlIGxvb2sgYXQgZmlsdGVyaW5nIGFuZCBwcmVzZW50aW5nIHRoZSBkYXRhIG1vcmUgY2xlYXJseS4NCg0KVGhpcyBjb2RlIGxvYWRzIG91ciB1bmtub3duIGRhdGEgZnJvbSBhIG5vcm1hbGlzZWQgZGF0YXNldCBjYWxsZWQgTVRfbm9ybS5jc3YuIFdlIHRoZW4gcHJlc2VudCBhbGwgb2YgdGhlIGRhdGEgaW4gYSB0YWJsZS4NCmBgYHtyfQ0KdW5rbm93bnMgPC0gaGVyZTo6aGVyZSgiRGF0YSIsIk1UX25vcm0uY3N2IikgJT4lIHJlYWQuY3N2KCkNCmd0KHVua25vd25zKQ0KYGBgDQoNCkxpa2UgYmVmb3JlIHRoaXMgaXMgdXNlZnVsIHRvIHVzZSB0byB1bmRlcnN0YW5kIHRoYXQgb3VyIGRhdGEgaGFzIGxvYWRlZCBjb3JyZWN0bHksIGJ1dCBhIHN1bW1hcnkgdGFibGUgbWlnaHQgYmUgbW9yZSB1c2VmdWwuIFRoaXMgaXMgcGVyZm9ybWVkIHVzaW5nIHRoZSBjb2RlIGZyb20gc2VjdGlvbiAyLjIuDQpgYGB7cn0NCnVua25vd25fc3VtIDwtIHVua25vd25zICU+JSBncm91cF9ieShpZDIpICU+JSBkcGx5cjo6c3VtbWFyaXNlKCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY291bnQ9bigpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNpTzIuPSBtZWFuKFNpTzIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNkMSA9IHNkKFNpTzIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRpTzIuID0gbWVhbihUaU8yKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZDIgPSBzZChUaU8yKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBBbDJPMy4gPSBtZWFuKEFsMk8zKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZDMgPSBzZChBbDJPMyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRmVPdCA9IG1lYW4oRmVPKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZDQgPSBzZChGZU8pLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1uTy49IG1lYW4oTW5PKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZDUgPSBzZChNbk8pLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1nTy49IG1lYW4oTWdPKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZDYgPSBzZChNZ08pLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIENhTy49IG1lYW4oQ2FPKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZDcgPSBzZChDYU8pLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5hMk8uID0gbWVhbihOYTJPKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZDggPSBzZChOYTJPKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBLMk8uID0gbWVhbihLMk8pLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNkOSA9IHNkKEsyTyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUDJPNS4gPSBtZWFuKFAyTzUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNkMTAgPSBzZChQMk81KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUb3RhbC49bWVhbihUb3RhbCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2QxMSA9IHNkKFRvdGFsKSkNCnVua25vd25fc3VtIDwtIHVua25vd25fc3VtICU+JSBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLCB+IHJvdW5kKC4sIGRpZ2l0cyA9IDIpKSkNCnVua25vd25fc3VtICU+JSByZW5hbWUobGF5ZXIgPSBpZDIsIG4gPSBjb3VudCAsIFNpTzIgPSBTaU8yLiwgVGlPMiA9IFRpTzIuKQ0KDQpndCh1bmtub3duX3N1bSkNCmBgYA0KV2UgZXZpZGVudGx5IGhhdmUgYSByZWxhdGl2ZWx5IGhvbW9nZW5vdXMgaGlnaGx5IHNpbGljaWMgdGVwaHJhIHdpdGggYXZlcmFnZSBzaWxpY2EgdmFsdWVzIG9mIDc3LjI5ICV3dCBhbmQgRmVPdCB2YWx1ZXMgYmVsb3cgMyV3dC4gV2UgY291bGQgdW5kZXJ0YWtlIGZ1cnRoZXIgcGxvdHMgdG8gY2hlY2sgdGhpcyBvdXQsIGJ1dCBpdCBtaWdodCBhbHNvIGJlIGFuIGV4YW1pbmF0aW9uIG9mIHRoZSB0YWJ1bGFyIGRhdGEgaXMgc3VmZmljaWVudCBmb3IgdGhpcyBwdXJwb3NlLiBUaGlzIGhlbHBzIHVzIHRvIGZpbHRlciBvdXIgcG9zc2libGUgY29ycmVsYXRpdmVzLiBXZSBjYW4gYWxzbyByZXN0cmljdCBvdXIgcG9zc2libGUgY29ycmVsYXRpdmVzIHVzaW5nIG90aGVyIHN0cmF0aWdyYXBoaWMgYW5kIGNocm9ub2xvZ2ljYWwgZGF0YS4gVGhpcyBtaWdodCBiZSBwbGF1c2libGUgdGltZSB3aW5kb3dzIHRoYXQgdGhlIHRlcGhyYSBjb3VsZCBvY2N1ciBvciBvdGhlciBmYWN0b3JzLiBUaGUgT0RQLTk4MCBkYXRhIGhhdmUgc29tZSBhZGRpdGlvbmFsIGluZm9ybWF0aW9uIHRoYXQgbWlnaHQgYWlkIHNvbWUgZGlzY3JpbWluYXRpb24uIFRoZSBwdWJsaWNhdGlvbiBsaXN0cyBzZWN0aW9ucyBvZiBJY2UgcmFmdGVkIGRlYnJpcyAoSVJEKSB3aGljaCByZWZsZWN0IG1peHR1cmVzIG9mIGFzaCBsYXllcnMgYW5kIHRoZXJlZm9yZSBub3QgcHJpbWFyeSB0ZXBocmEgZGVwb3NpdHMuIFdlIHdpbGwgZXhjbHVkZSB0aGVzZSBoZXJlIGluIG9yZGVyIHRvIG9ubHkgZGVhbCB3aXRoIHBvdGVudGlhbCBwcmltYXJ5IGFzaCBsYXllcnMuDQoNCmBgYHtyfQ0KY2hlbV9yZWQgPC0gZmlsdGVyKGNoZW0sIElSRCA9PSAiTk8iKSAjV2UgbWlnaHQgd2FudCB0byBmaWx0ZXIgb3VyIGRhdGEgYnkgYWdlIG9yIG90aGVyIHN0cmF0aWdyYXBoaWMgaW5mb3JtYXRpb24uIGhlcmUgd2UgYXJlIGV4Y2x1ZGluZyBsYXllcnMgaWRlbnRpZmllZCBhcyBpY2UgcmFmdGVkIGRlYnJpcy4gVGhpcyBjYW4gYmUgYWNoaWV2ZWQgdXNpbmcgYWRkaXRpb25hbCBjb2x1bW5zIGluIHRoZSBpbnB1dCBkYXRhIHNoZWV0LiBBbGwgb2YgdGhlIHBsb3R0aW5nIGNvZGUgd2lsbCBpZ25vcmUgdGhlc2UgdW5sZXNzIHRvbGQgb3RoZXJ3aXNlLg0KDQpjaGVtX3JlZCA8LSBmaWx0ZXIoY2hlbV9yZWQsIFNpTzIgPjY4ICYgRmVPIDw0KSAjIE91ciB1bmtub3duIHNhbXBsZSBpcyBhIHJoeW9saXRlIHNvIHdlIGNhbiBub3cgZW1wbG95IG91ciBmaWx0ZXJpbmcgYnkgdmFsdWUsIHdlIGNhbiBhbHNvIGV4Y2x1ZGUgc29tZSBvZiB0aGUgaGlnaCBpcm9uIGV4YW1wbGVzIGluIHRoZSBPRFAtOTgwIGRhdGFzZXQuDQoNCmMyOCA8LSBnZ3Bsb3QoY2hlbV9yZWQsIGFlcyh4ID0gU2lPMiwgeSA9IENhTywgZmlsbCA9IGlkLCBzaGFwZSA9IGlkKSkgIyBjcmVhdGUgYSBuZXcgcGxvdCB1c2luZyB0aGUgcmVkdWNlZCBjaGVtaWNhbCBjb21wYXJpc29uIGRhdGENCmMyOCA8LSBjMjggKyANCiAgZ2VvbV9oZHIobWV0aG9kID0gImtkZSIsIGFscGhhICA9IDAuNCwgeGxpbSA9IGMoMCwxMDApLCB5bGltID0gYygwLDMwKSwgc2hvdy5sZWdlbmQgPSBUUlVFLCBzbW9vdGggPSBUUlVFLCBuID0gNTAwLCBwcm9icyA9IGMoMC45NSksIGNvbG9yID0gImJsYWNrIikgKyAjIEFkZCB0aGUgT0RQLTk4MCBkYXRhIGFzIGEga2RlIGZpZWxkIGZvciBjb21wYXJpc29uIHRoaXMgdXNlcyA5NSUgcHJvYmFiaWxpdHkgcmFuZ2VzIGZvciBjb21wYXJpc29uLg0KICAgc2NhbGVfZmlsbF92aXJpZGlzKGRpc2NyZXRlID0gVFJVRSkgKyAjIFdlIHdpbGwgdXNlIHRoZSBWaXJpZGlzIHNjYWxlIGZvciBub3cgYXMgdGhpcyBnaXZlcyByZWxhdGl2ZWx5IGdvb2QgZGlmZmVyZW50aWF0aW9uLg0KICAgIGdlb21fcG9pbnQoZGF0YSA9IHVua25vd25zLCBpbmhlcml0LmFlcyA9IEZBTFNFLCBhZXMoeD1TaU8yLCB5ID0gQ2FPLCBzaGFwZSA9IGlkMiwgZmlsbCA9IGlkMiksIHNpemU9NCwgYWxwaGE9MC43LCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArICMgd2UgdGFrZSBvdXIgdW5rbm93biBkYXRhIGFuZCBwbG90IGl0IGFzIHBvaW50cw0KICB4bGFiKCJTaU8yICh3dCUpIikgKyAjIExhYmVsIG91ciBheGVzDQogIHlsYWIoIkNhTyAod3QlKSIpICsgDQogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXM9YygxOjUsNywxMSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSkpICsNCiAgVGVwaHJhLnRoZW1lICMgYWRkIHRoZSB0ZXBocmEgdGhlbWUuDQpwcmludChjMjgpDQpgYGANCldlIGNhbiBzZWUgdGhhdCBvbmx5IHNhbXBsZXMgNTQuNzktNTQuODMgYW5kIDUxLjA5LTUxLjEzIGhhdmUgYW55IG92ZXJsYXAgd2l0aCBvdXIgdW5rbm93biBhdCA5NSUgcHJvYmFiaWxpdHkuIEl0IGlzIHdvcnRoIG5vdGluZyBoZXJlIHRoYXQgdGhpcyBpcyBpbiBwYXJ0IGRvd24gdG8gb3VyIGZpbHRlcmluZyBvZiB0aGUgZGF0YSBpbiB0aGUgcHJldmlvdXMgc3RlcC4gV2UgbmVlZCB0byBiZSBzdXJlIHRoYXQgd2UgYXJlIG5vdCBleGNsdWRpbmcgaW1wb3J0YW50IGRhdGEgd2hlbiB1bmRlcnRha2luZyB0aGlzIHN0ZXAgb3RlaHJ3aXNlIG91ciByZXN1bHRpbmcga2RlcyBjYW4gYmUgc3Ryb25nbHkgYWx0ZXJlZC4gVGhlcmVmb3JlIGl0IGlzIGFsc28gc2Vuc2libGUgdG8gcGxvdCB0aGUgcmF3IHBvaW50IGRhdGEgZm9yIGNvbXBhcmlzb24gYWxzby4gVGhlIGludGVyYWN0aXZlIHBsb3QgYmVsb3cgdXNlcyB0aGUgc2FtZSBlbGVtZW50cyBidXQgcGVybWl0cyBleHBsb3JhdGlvbiBvZiB0aGUgZGF0YS4gRnJvbSB0aGlzIHdlIGNhbiBzZWUgdGhhdCA1NC43OS01NC44MyBpcyB0aGUgYmVzdCBtYXRjaCBmb3Igb3VyIHNhbXBsZSBvbiB0aGVzZSBlbGVtZW50cy4NCg0KYGBge3J9DQp1MjggPC0gZ2dwbG90KGNoZW1fcmVkLCBhZXMoeCA9IFNpTzIsIHkgPSBDYU8sICBmaWxsID0gaWQsIHNoYXBlID0gaWQpKQ0KdTI4IDwtIHUyOCArIGdlb21fcG9pbnQoYWVzKGZpbGwgPSBpZCksIHNpemU9NCwgYWxwaGE9MC44KSt4bGFiKCJTaU8yICh3dCUpIikreWxhYigiQ2FPICh3dCUpIikrc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcz1jKDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1LCAyMToyNSwgMjE6MjUsIDIxOjI1KSkrDQogICAgICBnZW9tX3BvaW50KGRhdGEgPSB1bmtub3ducywgaW5oZXJpdC5hZXMgPSBGQUxTRSwgYWVzKHg9U2lPMiwgeSA9IENhTywgc2hhcGUgPSBpZDIsIGZpbGwgPSBpZDIpLCBzaXplPTQsIGFscGhhPTAuOCkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjaGVtcGFsZXR0ZSkgKw0KICBUZXBocmEudGhlbWUNCg0KZ2dwbG90bHkodTI4LCB3aWR0aCA9IDEwMDAsIGhlaWdodCA9IDgwMCkNCmBgYA0KDQoNCg0KIyBSZWZlcmVuY2VzDQpSLiBXLiBMZSBNYWl0cmUgKGVkaXRvciksIEEuIFN0cmVja2Vpc2VuLCBCLiBaYW5ldHRpbiwgTS4gSi4gTGUgQmFzLCBCLiBCb25pbiwgUC4gQmF0ZW1hbiwgRy4gQmVsbGllbmksIEEuIER1ZGVrLCBTLiBFZnJlbW92YSwgSi4gS2VsbGVyLCBKLiBMYW1lcmUsIFAuIEEuIFNhYmluZSwgUi4gU2NobWlkLCBILiBTb3JlbnNlbiwgYW5kIEEuIFIuIFdvb2xsZXksIElnbmVvdXMgUm9ja3M6IEEgQ2xhc3NpZmljYXRpb24gYW5kIEdsb3NzYXJ5IG9mIFRlcm1zLCBSZWNvbW1lbmRhdGlvbnMgb2YgdGhlIEludGVybmF0aW9uYWwgVW5pb24gb2YgR2VvbG9naWNhbCBTY2llbmNlcywgU3ViY29tbWlzc2lvbiBvZiB0aGUgU3lzdGVtYXRpY3Mgb2YgSWduZW91cyBSb2Nrcy4gQ2FtYnJpZGdlIFVuaXZlcnNpdHkgUHJlc3MsIDIwMDIuDQoNCiMgUGFwZXJzIHVzaW5nIHZlcnNpb25zIG9mIHRoaXMgY29kZS4NCg0KV2Fsc2gsIEEuQS4sIEJsb2NrbGV5LCBTLlAuLCBNaWxuZXIsIEEuTS4gYW5kIE1hcnRpbi1QdWVydGFzLCBDLiwgMjAyMy4gVXBkYXRlZCBhZ2UgY29uc3RyYWludHMgb24ga2V5IHRlcGhyYSBtYXJrZXJzIGZvciBOVyBFdXJvcGUgYmFzZWQgb24gYSBoaWdoLXByZWNpc2lvbiB2YXJ2ZSBsYWtlIGNocm9ub2xvZ3kuIFF1YXRlcm5hcnkgU2NpZW5jZSBSZXZpZXdzLCAzMDAsIHAuMTA3ODk3LiBbcmVhZCBpdCBoZXJlXShodHRwczovL3d3dy5zY2llbmNlZGlyZWN0LmNvbS9zY2llbmNlL2FydGljbGUvcGlpL1MwMjc3Mzc5MTIyMDA1Mjg1I2ZpZzIpDQoNCkNhcnRlcuKAkENoYW1waW9uLCBBLiwgQWJyb29rLCBBLk0uLCBQaWtlLCBKLkguLCBNYXR0aGV3cywgSS5QLiwgUGFsbWVyLCBBLlAuIGFuZCBMb3dlLCBKLkouLCAyMDIyLiBJY2XigJBzaGVldCBkZWdsYWNpYXRpb24gYW5kIExvY2ggTG9tb25kIFJlYWR2YW5jZSBpbiB0aGUgZWFzdGVybiBDYWlybmdvcm1zOiBpbXBsaWNhdGlvbnMgb2YgYSBMYXRlZ2xhY2lhbCBzZWRpbWVudCByZWNvcmQgZnJvbSBHbGVuIEJ1aWxnLiBKb3VybmFsIG9mIFF1YXRlcm5hcnkgU2NpZW5jZSwgMzcoOCksIHBwLjEzMzItMTM0Ny4gW3JlYWQgaXQgaGVyZV0oaHR0cHM6Ly9vbmxpbmVsaWJyYXJ5LndpbGV5LmNvbS9kb2kvMTAuMTAwMi9qcXMuMzQ0OCkNCg0KV2Fsc2gsIEEuQS4sIEJsb2NrbGV5LCBTLlAuLCBNaWxuZXIsIEEuTS4sIE1hdHRoZXdzLCBJLlAuIGFuZCBNYXJ0aW4tUHVlcnRhcywgQy4sIDIwMjEuIENvbXBsZXhpdGllcyBpbiBFdXJvcGVhbiBIb2xvY2VuZSBjcnlwdG90ZXBocmEgZGlzcGVyc2FsIHJldmVhbGVkIGluIHRoZSBhbm51YWxseSBsYW1pbmF0ZWQgbGFrZSByZWNvcmQgb2YgRGlzcyBNZXJlLCBFYXN0IEFuZ2xpYS4gUXVhdGVybmFyeSBHZW9jaHJvbm9sb2d5LCA2NiwgcC4xMDEyMTMuICBbcmVhZCBpdCBoZXJlXShodHRwczovL3d3dy5zY2llbmNlZGlyZWN0LmNvbS9zY2llbmNlL2FydGljbGUvcGlpL1MxODcxMTAxNDIxMDAwNjM3KQ0KIA0KUGFsbWVyLCBBLlAuLCBNYXR0aGV3cywgSS5QLiwgTG93ZSwgSi5KLiwgTWFjTGVvZCwgQS4gYW5kIEdyYW50LCBSLiwgMjAyMC4gQSByZXZpc2VkIGNocm9ub2xvZ3kgZm9yIHRoZSBncm93dGggYW5kIGRlbWlzZSBvZiBMb2NoIExvbW9uZCBSZWFkdmFuY2UgKOKAmFlvdW5nZXIgRHJ5YXPigJkpIGljZSBsb2JlcyBpbiB0aGUgTG9jaGFiZXIgYXJlYSwgU2NvdGxhbmQuIFF1YXRlcm5hcnkgU2NpZW5jZSBSZXZpZXdzLCAyNDgsIHAuMTA2NTQ4LltyZWFkIGl0IGhlcmVdKGh0dHBzOi8vd3d3LnNjaWVuY2VkaXJlY3QuY29tL3NjaWVuY2UvYXJ0aWNsZS9waWkvUzAyNzczNzkxMjAzMDUxMDIpDQogDQpMb3dlLCBKLiwgTWF0dGhld3MsIEkuLCBNYXlmaWVsZCwgUi4sIExpbmNvbG4sIFAuLCBQYWxtZXIsIEEuLCBTdGFmZiwgUi4gYW5kIFRpbW1zLCBSLiwgMjAxOS4gT24gdGhlIHRpbWluZyBvZiByZXRyZWF0IG9mIHRoZSBMb2NoIExvbW9uZCAo4oCYWW91bmdlciBEcnlhc+KAmSkgUmVhZHZhbmNlIGljZWZpZWxkIGluIHRoZSBTVyBTY290dGlzaCBIaWdobGFuZHMgYW5kIGl0cyB3aWRlciBzaWduaWZpY2FuY2UuIFF1YXRlcm5hcnkgU2NpZW5jZSBSZXZpZXdzLCAyMTksIHBwLjE3MS0xODYuW3JlYWQgaXQgaGVyZV0oaHR0cHM6Ly93d3cuc2NpZW5jZWRpcmVjdC5jb20vc2NpZW5jZS9hcnRpY2xlL3BpaS9TMDI3NzM3OTExOTMwMTk1NykNCg0KDQo=