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.

7.0 Interactive figures

The function ggplotly within the plotly package is extremely useful for interactively examining data. ggplotly plots allow you to zoom into areas of interest and turn layers on and off as well as saving low resolution .png files of zoomed sections of your plots. We refer to these as iPlots (interactive plots) in order to distinguish them from static plots presented above. These are excellent for generating quick plots to support your inferences about your data. The plots can be exported as .png files.

iTAS plot

iFeO-CaO

iK-lines

iTiO2 vs Al2O3

iK2O vs CaO

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=