Imagine you had to do an experiment with a really hard to get population, for example let’s say the CEOs of Fortune 500 companies. These are people with super tight-schedules and it’s unlikely you’ll ever get to work with them again if this experiment goes wrong. Stakes are high. How do you know your experiment will work? You don’t want to do something too mundane, but at the same time you want to do something safe enough that you’re likely to get significant results with. How do you prepare? One way to approach this problem is to think about all the possible outcomes and ways of analyzing this experiment, and consider the probability of best-case and worst-case outcomes, and work off of that.
DeclareDesign is the tool to do just that (Blair, Coppock, Cooper And Humphreys, 2019). DeclareDesign, winner of the prestigious Rosenthal Prize for Open Social Science & Society for Political Methodology Statistical Software Award, is a tool for creating a fake dataset, looping the dataset a few thousand times with some random noise, and then changing the initial assumptions and comparing the results. The purpose of DeclareDesign is to determine how subtle methodological changes affect the results of an experiment. This is hugely important if you are about to invest a huge amount of time and money into an experiment that may not pan-out.
Of course, learning to simulate data is tricky and there is a learning-curve to doing it. I am going to do my best in this guide to walk new users through difficulties and make this as easy as possible. DeclareDesign closely follows the framework laid out by Gerber & Green’s Field Experiment handbook. I think this is the single best resource to look at if you find any of the notation confusing. For a more hands-on approach for DeclareDesign, I really like this gentle introduction by Dorothy Bishop. Another helpful resource is Kevin Munger’s repository from his workshop, and lastly the DeclareDesign book looks fantastic, but as I write this, it’s still a work in progress.
One thing I found difficult as a new DeclareDesign user is that because the tools are so powerful, the documentation often can’t define every single option available. In this guide, I will do my best to address these ambiguities. I also try to be clear about what order the steps come in, but with that said, it is important to emphasize that I am only teaching one way to use DeclareDesign and most steps can be done in different orders (sometimes with differing results!). Most of the DeclareDesign functions below can have their internals replaced with other “handlers”, and allow more flexibility than I am letting on.
In my perspective, DeclareDesign can be thought of in 2 parts. 1) The data fabrication step (this is the bulk of the code), and 2) the evaluation step, where users can change initial assumptions and see how well their design actually worked (this is the computationally intensive part of the code).
The cool thing about the DeclareDesign data fabrication step is that it allows for (as far as I know) any design imaginable, which is why there are so many steps. However, because most researchers often need to work with simple/common designs, there are some ready-made designs which are available in the DesignLibrary, which users can also contribute to. As far as I can tell, most simple psychology lab-experiments will be able to get the entirety of their needs met by DesignLibrary. Although I do think you will develop more intuition for the process by using the individual parts of DeclareDesign. I will expand on DesignLibrary in a future article.
Brief Overview of Power Analysis / DeclareDesign Terms
Before expanding on DeclareDesign, it makes sense to have a few terms defined. I won’t be using all these terms in the design I share, but it is still useful to have them defined in one place:
attrition_rate - the proportion of cases that will be lost to follow-up.
\(\alpha\) (alpha) - The chance of making a type I error; the chance of claiming there is an effect when there actually is none – a false alarm. Traditionally 0.05 (= p-value significance threshold). Also known as the chance of making a fool of yourself.
\(\beta\) (beta) - The chance of making a type II error where you falsely claim there is not an effect when there actually is – missed detection. Known as power or sensitivity. Traditionally 0.8.
Blocking - Participants put into blocks/strata and then randomly assigned. Helps reduce sampling variability, and assures that subgroups are available for separate analysis. In practice, blocking rarely has any downsides.
Cluster random assignment - Random assignment not done on the individual level, but instead assigned on the group level. Consider cities or classrooms randomly getting a treatment, instead of each person individually being assigned. Generally bad for power although necessary.
Diagnosand - A summary of the distribution of a diagnostic statistic. (i.e., the expected value from looping the design)
ES - Effect size. Measures the strength of the phenomenon of interest; solely magnitude based - does not depend on sample size.
N - The sample size. Larger N can lead to smaller ES being deemed significant, although the smaller ES is not always interesting in practical terms (imagine something that makes 1 million people 0.0001% happier – a large N can cause small effects to be deemed significant, regardless of it’s actual interest).
\(\rho\) (rho) - The correlation between time 1 and time 2. When using a within subjects design, intuitively you would expect some stability in peoples’ preferences overtime.
t1 - Time 1. Can be modified for any time period e.g., tx
Z - Condition. In this example I use one this 1 to represent the treatment group, and 0 to represent the control. Cf. arms
Data and Design Fabrication
DeclareDesign operates using a MIDA framework. The functions for each of the MIDA letters are shown below. Simply put MIDA stands for:
- M - model of the world
declare_population
declare_potentional_outcomes
- I - inquiry
- D - data strategy
declare_sampling
declare_assignment
declare_reveal
declare_step
- A - answer strategy
It is important to note that the order of the functions is for the most part necessary and that they all follow the declare_* pattern.
First Example: The effect of coffee on productivity
Let’s begin with a simple design. Let’s say we have a factory with 100 workers who make widgets. I split my workers into two groups, and give one group coffee. I want to see how coffee impacts the productivity of the second group.
We start by loading the following packages:
rm(list = ls())
set.seed(13)
library(DeclareDesign)
library(DesignLibrary)
library(knitr)
library(DT)
library(tidyverse)
n_sims = 100
M - Model of the World
Terms
To begin, let’s define our terms. Intuitively we know that we’ll need N, the number of people, but we’ll also need to define the effect size we think coffee will have. Notice I am making these assumptions up-front, and defining them as objects. In my opinion this is the most transparent way to use DeclareDesign and is also the most intuitive. Please note that more complex designs will have a lot more terms to define.
(Note: I keep adding to a df1 at the bottom of my chunks, but this is only for visualization purposes – it is not part of the DeclareDesign framework, and you won’t need to do this)
N <- 100 # sample size, 100 factory workers
ate <- 4 # average treatment effect I think coffee will have on productivity
sd_1 <- 5 # SD of worker productivity before intervention
df1 <- ""
Population
I start by defining the population. For me this is literally everyone in the factory, all 100 people, but thinking ahead, imagine I was studying Facebook users, I would theoretically use 360 million to represent everyone on Facebook. In reality my sample wouldn’t involve every user on Facebook, but that would still be my population. Next, notice I manually assert the distributions for widgets because not everyone makes the same number of widgets each day.
The purpose of this step is to define the that groups will be compared before being given the treatment, and for me this is one group. This step is really creating similar to making a regular dataframe with the exception of the special N argument which defines the number of rows, and creates a column to label the participants.
# M: Model
population <-
declare_population(N = N,
widgets_t1 = rnorm(n = N, # 100 draws from a normal distribution
mean = 50, # before intervention, my workers average of 50 widgets a day
sd = sd_1) %>% round(., 2)) # sd of worker productivity
df1 <- population()
datatable(df1)
Here we see the each of the 100 workers makes approximately 50 widgets a day.
The key points from this declare_population are:
The number of rows in your population will be equal to N.
Your final sample will be equal to or less than N
One column for each measure that you expect that affects or will be affected by treatment
Outcomes
The purpose of this step is to define the two outcomes using each of the groups (i.e. treatment/control). The treatment group will have the ATE added to their distribution. Again this step is just adding new columns to our data frames.
potential_outcomes <- declare_potential_outcomes(Y_Z_0 = widgets_t1, # the control group, here we expect business as usual
Y_Z_1 = widgets_t1 + ate) # the treatment group, business as usual + the productivity boost from coffee
df1 <- potential_outcomes(df1)
datatable(df1)
Notice above how everyone has a “potential outcome” for that would happen if they were treated or not. Since we expect to split our design into two groups, in real life we wouldn’t actually get to observe both of these potential outcomes.
The key points from this declare_potential_outcomes are:
I - Inquiry
Estimand
The purpose of this step is to define, how you define, your ATE – this is your TRUE TREATMENT EFFECT). Because we are simulating data, we have somewhat of a “perfect world”, where all participants get the treatment perfectly and no one is missing (yet), we will get exactly the same ATE as we defined originally.
The estimand below is the simplest estimand, but as Jasper points out that there are conditional ATEs, or special ATEs for when you have categorical outcomes which are necessary for more complex designs.
estimand <- declare_estimand(ATE = mean(Y_Z_1 - Y_Z_0))
kable(estimand(df1))
The key points from this declare_estimand are:
D - Data Strategy
Assignment
There are two important arguments in the declare_assignment function which are prob (the chance of getting picked) and assignment_variable (the name of the variable being assigned).
I think it is really important to point out that this function defaults the name to assignment_variable to Z which is essential. What this means is that the default use of declare_assignment is to declare conditions, although this function has other purposes it used for also (e.g., attrition).
We are declaring what % of people get assigned to the treatment group. Here we create the Z and Z_cond_prob columns
assignment <- declare_assignment(prob = .5,
assignment_variable = Z) # by the relevant part of columns to assign from, default assignment_variable = Z
df1 <- assignment(df1)
datatable(df1)
Above Z represents the condition the participant is assigned to, Z_cond_prob the chance that the participant gets assigned to Z. This is of course could be a lot more complicated with more conditions, and unequal assignment levels.
The key points from this declare_assignment are:
Actually put people in groups (Reveal)
Next we actually give people the treatment. Here we create the Y column, which is our observed outcome.
reveal <- declare_reveal(outcome_variables = Y) # here we use the prefix before the Z part begins, in our case this is simply Y
df1 <- reveal(df1)
datatable(df1)
Note that the way the chunk above is written, you can conceptually you can think of declare_reveal like:
df1 %>%
mutate(Y = if_else(Z == 1, Y_Z_1, Y_Z_0))
A - Answer Strategy
This is the actual modelling we’re using
The important points here are that:
- Our estimands argument correspond with the names of the estimands we made before,
- The model can be anything that works with the
broom package, and can be modified to work with any model that outputs a dataframe. Here we use estimatr::lm_robust as our model.
The model being shown here is simply using treatment assignment (Z) to predict productivity outcomes (Y)
estimated_effect <- declare_estimator(
Y ~ Z,
model = lm_robust,
estimand = c("ATE"), # also just `estimand` (the object we defined above) would work
#subset = R == 1, # only keep people not lost to attrition
label = "Treatment Effect"
)
The key points from declare_estimator is:
This is where you define your model. You know, the same one you are going to use in the your paper.
You can also use this step to try out multiple models to see which one works best for your design.
Note: If you are planning on testing multiple models, it makes sense to create a different delcare_estimator function for each of the models you are planning on testing. For example for our current design, I use linear regression, but I could have opted for a correlation or a t-test if I had wanted to.
Put it all together
Putting all the pieces we just wrote together we get a design that looks like this. We defined all these pieces individually, but of course we could have done this all together ggplot style, although I personally prefer to do one step at a time. From now on the combination of all of those parts will be called our our_design
our_design <- population +
potential_outcomes +
estimand +
assignment +
reveal +
estimated_effect
Here I paste all the code from above together just incase you would like to test it as a whole:
our_design <-
declare_population(N = N,
widgets_t1 = rnorm(n = N,
mean = 50,
sd = sd_1) %>% round(., 2)) +
declare_potential_outcomes(Y_Z_0 = widgets_t1,
Y_Z_1 = widgets_t1 + ate) +
declare_estimand(ATE = mean(Y_Z_1 - Y_Z_0)) +
declare_assignment(prob = .5,
assignment_variable = Z) +
declare_reveal(outcome_variables = Y) +
declare_estimator(Y ~ Z,
model = lm_robust,
estimand = c("ATE"),
label = "Treatment Effect"
)
Model Evaluation
The following chunks each showcase one model evaluating function. Note that sometimes I use multiple functions together because that is best way to use that function. I am piping some functions into head and kable for visualization purposes.
To get take a peek at your design
Note: This is only a single simulation of your data with draw_data
our_design %>%
draw_data() %>% # draw single simulation
head(5) %>%
kable()
| 001 |
53.47 |
53.47 |
57.47 |
0 |
0.5 |
53.47 |
| 002 |
50.83 |
50.83 |
54.83 |
0 |
0.5 |
50.83 |
| 003 |
45.60 |
45.60 |
49.60 |
1 |
0.5 |
49.60 |
| 004 |
40.44 |
40.44 |
44.44 |
0 |
0.5 |
40.44 |
| 005 |
49.93 |
49.93 |
53.93 |
1 |
0.5 |
53.93 |
Take a peek at your unbiased estimands
draw_estimands
our_design %>%
draw_estimands() %>%
kable()
See estimates of model
draw_estimates
our_design %>%
draw_estimates() %>% #
kable()
| Treatment Effect |
Z |
5.1136 |
0.9793757 |
5.221285 |
1e-06 |
3.170061 |
7.057139 |
98 |
Y |
ATE |
To see the aggregated summary of your design
diagnose_design will loop the creation of your design, making it the most resource intensive step described. This shows the details of your design. This is the single most important function for the evaluation of models
Here I use sims = 100 only for demonstration purposes, but in real life you would likely want to use 500 or higher.
diagnosis1 <- our_design %>%
diagnose_design(sims = n_sims)
OPTIONAL ASIDE: Another way to to simulate data in DeclareDesign is with the simulate_design function. I don’t showcase it here but it is essentially equivalent to our_design %>% diagnose_design %>% get_simulations()
What are all the stats in the diagnosand anyway?
Descriptions from pg 7, Formulas from here.
| design_label |
. |
|
|
| estimand_label |
ATE |
|
|
| estimator_label |
Treatment Effect |
|
|
| term |
Z |
|
|
| bias |
0.0455959999999999 |
Expected difference between estimate and estimand |
mean(estimate - estimand) |
| se(bias) |
0.115653978121041 |
|
|
| rmse |
1.10361088903653 |
Root mean squared error |
sqrt(mean((estimate - estimand) ^ 2)) |
| se(rmse) |
0.0843282077977243 |
|
|
| power |
0.98 |
Probability of rejecting null hypothesis of no effect |
mean(p.value < alpha) |
| se(power) |
0.0140072131490179 |
|
|
| coverage |
0.92 |
Probability that conf. interval contains estimand |
mean(estimand <= conf.high & estimand >= conf.low) |
| se(coverage) |
0.027762339144018 |
|
|
| mean_estimate |
4.045596 |
Mean of the estimates |
mean(estimate) |
| se(mean_estimate) |
0.115653978121041 |
|
|
| sd_estimate |
1.10822362144802 |
|
|
| se(sd_estimate) |
0.0835280827049709 |
|
|
| mean_se |
0.993976024671408 |
|
|
| se(mean_se) |
0.0078903273521745 |
|
|
| type_s_rate |
0 |
Probability that a significant estimate has incorrect sign |
mean((sign(estimate) != sign(estimand))[p.value < alpha]) |
| se(type_s_rate) |
0 |
|
|
| mean_estimand |
4 |
|
|
| se(mean_estimand) |
0 |
|
|
| n_sims |
100 |
|
|
OPTIONAL ASIDE - What if we don’t want all these stats or want to create a new stat? declare_diagnosands
- We can drop stats with the
subtract argument
- Create stats by specifying out own argument
- Or keep stats with the
select argument
# keep only bias, rmse, & type_s_rate
my_diagnosands <- declare_diagnosands(select = c(bias, rmse, type_s_rate))
# drop type_s_rate
my_diagnosands <- declare_diagnosands(subtract = type_s_rate)
# You can add your own diagnosands in addition to or instead of the defaults e.g.,
my_diagnosands <-
declare_diagnosands(median_bias = median(estimate - estimand))
# Keep only the stat we defined
my_diagnosands <-
declare_diagnosands(median_bias = median(estimate - estimand),
keep_defaults = FALSE)
To apply:
our_design %>%
diagnose_design(sims = n_sims, diagnosands = my_diagnosands) %>%
get_diagnosands() %>%
kable()
| . |
ATE |
Treatment Effect |
Z |
0.0849 |
0.1166837 |
100 |
To see the 100 individual simulations that made the aggregated summary
get_simulations
diagnosis1 %>%
get_simulations() %>%
datatable()
get_simulations also has nice properties for plotting e.g.,
get_simulations(diagnosis1) %>%
ggplot(aes(estimate)) +
geom_density() +
geom_vline(xintercept = ate, col = "red") +
labs(title = "Density of Effect Size Estimates",
subtitle = "Real ATE shown in Red")

Change your assumptions
You can test different assumptions from your your DeclareDesign design using redesign the function. redesign takes the global values you are using within the function and gives them new values The first argument is your design, the second are the new assumptions. Also note that it makes sense in most cases to pipe this function into diagnose_design or get_simulations. Here I experiment with changing the sample size:
change_the_parameters <-
our_design %>%
redesign(N = list(30, 50, 75, 100), # note that I define N as a variable in the first chunk in this document
ate = list(1, 2, 3, 4)) %>% # what if the ATE is lower than I originally expected?
diagnose_design(sims = n_sims) # note this does sims for each of combination of N's and ate's
change_the_parameters %>%
get_diagnosands() %>%
kable()
| design_1 |
30 |
1 |
ATE |
Treatment Effect |
Z |
-0.0034533 |
0.1969732 |
1.8343939 |
0.1190232 |
0.08 |
0.0269972 |
0.96 |
0.0186742 |
0.9965467 |
0.1969732 |
1.843632 |
0.1204478 |
1.840460 |
0.0225472 |
0.0000000 |
0.0000000 |
1 |
0 |
100 |
| design_2 |
50 |
1 |
ATE |
Treatment Effect |
Z |
-0.0907840 |
0.1471181 |
1.4435108 |
0.1057918 |
0.08 |
0.0278414 |
0.95 |
0.0226816 |
0.9092160 |
0.1471181 |
1.447911 |
0.1066926 |
1.411619 |
0.0148110 |
0.1250000 |
0.1458455 |
1 |
0 |
100 |
| design_3 |
75 |
1 |
ATE |
Treatment Effect |
Z |
0.0292023 |
0.1240253 |
1.2038179 |
0.0985437 |
0.13 |
0.0366268 |
0.90 |
0.0292110 |
1.0292023 |
0.1240253 |
1.209526 |
0.0997754 |
1.141634 |
0.0120812 |
0.0769231 |
0.0833045 |
1 |
0 |
100 |
| design_4 |
100 |
1 |
ATE |
Treatment Effect |
Z |
0.0946080 |
0.1112108 |
1.0419003 |
0.0758989 |
0.21 |
0.0409996 |
0.93 |
0.0233158 |
1.0946080 |
0.1112108 |
1.042823 |
0.0778319 |
0.981938 |
0.0061373 |
0.0476190 |
0.0470524 |
1 |
0 |
100 |
| design_5 |
30 |
2 |
ATE |
Treatment Effect |
Z |
-0.0960000 |
0.1855930 |
1.8885777 |
0.1454002 |
0.21 |
0.0394061 |
0.92 |
0.0282004 |
1.9040000 |
0.1855930 |
1.895638 |
0.1464280 |
1.797472 |
0.0241419 |
0.0476190 |
0.0426354 |
2 |
0 |
100 |
| design_6 |
50 |
2 |
ATE |
Treatment Effect |
Z |
-0.1966960 |
0.1504968 |
1.4405168 |
0.0788561 |
0.23 |
0.0455133 |
0.96 |
0.0162692 |
1.8033040 |
0.1504968 |
1.434214 |
0.0827779 |
1.405005 |
0.0147104 |
0.0000000 |
0.0000000 |
2 |
0 |
100 |
| design_7 |
75 |
2 |
ATE |
Treatment Effect |
Z |
0.0700125 |
0.1233924 |
1.2256098 |
0.0857311 |
0.47 |
0.0533049 |
0.93 |
0.0246337 |
2.0700125 |
0.1233924 |
1.229773 |
0.0881893 |
1.152958 |
0.0084375 |
0.0000000 |
0.0000000 |
2 |
0 |
100 |
| design_8 |
100 |
2 |
ATE |
Treatment Effect |
Z |
-0.0518520 |
0.1070171 |
1.0119394 |
0.0632917 |
0.49 |
0.0449847 |
0.97 |
0.0176143 |
1.9481480 |
0.1070171 |
1.015701 |
0.0635915 |
1.003862 |
0.0066878 |
0.0000000 |
0.0000000 |
2 |
0 |
100 |
| design_9 |
30 |
3 |
ATE |
Treatment Effect |
Z |
0.0121733 |
0.1507504 |
1.6300766 |
0.1327646 |
0.30 |
0.0454485 |
0.94 |
0.0230228 |
3.0121733 |
0.1507504 |
1.638243 |
0.1334250 |
1.838747 |
0.0237285 |
0.0000000 |
0.0000000 |
3 |
0 |
100 |
| design_10 |
50 |
3 |
ATE |
Treatment Effect |
Z |
-0.0329440 |
0.1192950 |
1.2328144 |
0.0649279 |
0.53 |
0.0496715 |
1.00 |
0.0000000 |
2.9670560 |
0.1192950 |
1.238583 |
0.0652218 |
1.414221 |
0.0125305 |
0.0000000 |
0.0000000 |
3 |
0 |
100 |
| design_11 |
75 |
3 |
ATE |
Treatment Effect |
Z |
-0.0647430 |
0.1175204 |
1.0791808 |
0.0768960 |
0.73 |
0.0457909 |
0.97 |
0.0174553 |
2.9352570 |
0.1175204 |
1.082664 |
0.0794593 |
1.131993 |
0.0106370 |
0.0000000 |
0.0000000 |
3 |
0 |
100 |
| design_12 |
100 |
3 |
ATE |
Treatment Effect |
Z |
-0.2615480 |
0.0984310 |
0.9822463 |
0.0753796 |
0.78 |
0.0372915 |
0.94 |
0.0225798 |
2.7384520 |
0.0984310 |
0.951554 |
0.0629973 |
1.002502 |
0.0061493 |
0.0000000 |
0.0000000 |
3 |
0 |
100 |
| design_13 |
30 |
4 |
ATE |
Treatment Effect |
Z |
-0.1232600 |
0.2104620 |
1.8947399 |
0.1465375 |
0.57 |
0.0536397 |
0.97 |
0.0167124 |
3.8767400 |
0.2104620 |
1.900251 |
0.1374858 |
1.821036 |
0.0246287 |
0.0000000 |
0.0000000 |
4 |
0 |
100 |
| design_14 |
50 |
4 |
ATE |
Treatment Effect |
Z |
-0.1740480 |
0.1392170 |
1.3003914 |
0.0928401 |
0.76 |
0.0469010 |
0.96 |
0.0218895 |
3.8259520 |
0.1392170 |
1.295183 |
0.0890643 |
1.415701 |
0.0163220 |
0.0000000 |
0.0000000 |
4 |
0 |
100 |
| design_15 |
75 |
4 |
ATE |
Treatment Effect |
Z |
0.0961406 |
0.1155925 |
1.1755980 |
0.0837818 |
0.94 |
0.0218005 |
0.95 |
0.0199990 |
4.0961406 |
0.1155925 |
1.177563 |
0.0856972 |
1.154123 |
0.0092089 |
0.0000000 |
0.0000000 |
4 |
0 |
100 |
| design_16 |
100 |
4 |
ATE |
Treatment Effect |
Z |
0.1921140 |
0.1000403 |
0.9878416 |
0.0610962 |
1.00 |
0.0000000 |
0.97 |
0.0163287 |
4.1921140 |
0.1000403 |
0.973862 |
0.0601903 |
1.000048 |
0.0070673 |
0.0000000 |
0.0000000 |
4 |
0 |
100 |
OPTIONAL ASIDE - Why use list() in redesign instead of c()?
Good practice in DeclareDesign is to use list() in redesign and it’s sister function expand_design instead of c(). The distinction is subtle, but the reason why is there are some cases where we would want a to use a vector within our design [think list(c("A", "B", "C")) vs c(c("A", "B". "C"))] and a normal vector won’t cut it. Using c() won’t cause problems in most cases, but this is an edge case to be aware of.
get_diagnosands(change_the_parameters) %>%
mutate(N = factor(N),
ate = factor(ate)) %>%
ggplot(aes(N, power, fill = ate)) +
geom_bar(position = "dodge", stat = "identity") +
geom_errorbar(aes(ymin = power - 1.96*`se(power)`,
ymax = power + 1.96*`se(power)`,
width = .3),
position = position_dodge(width = .9)) +
geom_hline(yintercept = 0.8) +
labs(title = "Power at each N and ate",
subtitle = "95% Confidence Intervals")

Notice how if my original estimate of coffee on number of widgets was a little too high, or there were some workers in my factory who didn’t show up my experiment likely wouldn’t work! This could be huge!
LS0tCnRpdGxlOiAiU2ltdWxhdGluZyBSZXNlYXJjaCBEZXNpZ25zIGZvciBTb2NpYWwgU2NpZW5jZSIKc3VidGl0bGU6ICJEZWNsYXJlRGVzaWduIC0gQW4gT3ZlcnZpZXcgJiBCZWdpbm5lciBFeGFtcGxlIgphdXRob3I6ICJKb2huLUhlbnJ5IFBlenp1dG8iCm91dHB1dDogCiAgcm1hcmtkb3duOjpodG1sX25vdGVib29rOgogICAgc21hcnQ6IGZhbHNlCiAgICB0aGVtZTogc3BhY2VsYWIKICAgIG51bWJlcl9zZWN0aW9uczogbm8KICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICB0b2NfZGVwdGg6IDQKLS0tCgoKSW1hZ2luZSB5b3UgaGFkIHRvIGRvIGFuIGV4cGVyaW1lbnQgd2l0aCBhIHJlYWxseSBoYXJkIHRvIGdldCBwb3B1bGF0aW9uLCBmb3IgZXhhbXBsZSBsZXQncyBzYXkgdGhlIENFT3Mgb2YgRm9ydHVuZSA1MDAgY29tcGFuaWVzLiBUaGVzZSBhcmUgcGVvcGxlIHdpdGggc3VwZXIgdGlnaHQtc2NoZWR1bGVzIGFuZCBpdCdzIHVubGlrZWx5IHlvdSdsbCBldmVyIGdldCB0byB3b3JrIHdpdGggdGhlbSBhZ2FpbiBpZiB0aGlzIGV4cGVyaW1lbnQgZ29lcyB3cm9uZy4gU3Rha2VzIGFyZSBoaWdoLiBIb3cgZG8geW91IGtub3cgeW91ciBleHBlcmltZW50IHdpbGwgd29yaz8gWW91IGRvbid0IHdhbnQgdG8gZG8gc29tZXRoaW5nIHRvbyBtdW5kYW5lLCBidXQgYXQgdGhlIHNhbWUgdGltZSB5b3Ugd2FudCB0byBkbyBzb21ldGhpbmcgc2FmZSBlbm91Z2ggdGhhdCB5b3UncmUgbGlrZWx5IHRvIGdldCBzaWduaWZpY2FudCByZXN1bHRzIHdpdGguIEhvdyBkbyB5b3UgcHJlcGFyZT8gT25lIHdheSB0byBhcHByb2FjaCB0aGlzIHByb2JsZW0gaXMgdG8gdGhpbmsgYWJvdXQgYWxsIHRoZSBwb3NzaWJsZSBvdXRjb21lcyBhbmQgd2F5cyBvZiBhbmFseXppbmcgdGhpcyBleHBlcmltZW50LCBhbmQgY29uc2lkZXIgdGhlIHByb2JhYmlsaXR5IG9mIGJlc3QtY2FzZSBhbmQgd29yc3QtY2FzZSBvdXRjb21lcywgYW5kIHdvcmsgb2ZmIG9mIHRoYXQuCgpbRGVjbGFyZURlc2lnbl0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL0RlY2xhcmVEZXNpZ24vRGVjbGFyZURlc2lnbi5wZGYpIGlzIHRoZSB0b29sIHRvIGRvIGp1c3QgdGhhdCBbKEJsYWlyLCBDb3Bwb2NrLCBDb29wZXIgQW5kIEh1bXBocmV5cywgMjAxOSldKGh0dHBzOi8vZGVjbGFyZWRlc2lnbi5vcmcvZGVjbGFyZS5wZGYpLiBEZWNsYXJlRGVzaWduLCB3aW5uZXIgb2YgdGhlIFtwcmVzdGlnaW91cyBSb3NlbnRoYWwgUHJpemUgZm9yIE9wZW4gU29jaWFsIFNjaWVuY2VdKGh0dHA6Ly9uZXdzcm9vbS51Y2xhLmVkdS9kZXB0L2ZhY3VsdHkvcG9saXRpY2FsLXNjaWVudGlzdC13aW5zLTIwMTYtbGVhbWVyLXJvc2VudGhhbC1wcml6ZS1mb3Itb3Blbi1zb2NpYWwtc2NpZW5jZSkgJiBbU29jaWV0eSBmb3IgUG9saXRpY2FsIE1ldGhvZG9sb2d5IFN0YXRpc3RpY2FsIFNvZnR3YXJlIEF3YXJkXShodHRwczovL3d3dy5jYW1icmlkZ2Uub3JnL2NvcmUvbWVtYmVyc2hpcC9zcG0vYWJvdXQtdXMvYXdhcmRzL3N0YXRpc3RpY2FsLXNvZnR3YXJlLWF3YXJkL3N0YXRpc3RpY2FsLXNvZnR3YXJlLWF3YXJkLTIwMTkpLCBpcyBhIHRvb2wgZm9yIGNyZWF0aW5nIGEgZmFrZSBkYXRhc2V0LCBsb29waW5nIHRoZSBkYXRhc2V0IGEgZmV3IHRob3VzYW5kIHRpbWVzIHdpdGggc29tZSByYW5kb20gbm9pc2UsIGFuZCB0aGVuIGNoYW5naW5nIHRoZSBpbml0aWFsIGFzc3VtcHRpb25zIGFuZCBjb21wYXJpbmcgdGhlIHJlc3VsdHMuIFRoZSBwdXJwb3NlIG9mIERlY2xhcmVEZXNpZ24gaXMgdG8gZGV0ZXJtaW5lIGhvdyBzdWJ0bGUgbWV0aG9kb2xvZ2ljYWwgY2hhbmdlcyBhZmZlY3QgdGhlIHJlc3VsdHMgb2YgYW4gZXhwZXJpbWVudC4gVGhpcyBpcyBodWdlbHkgaW1wb3J0YW50IGlmIHlvdSBhcmUgYWJvdXQgdG8gaW52ZXN0IGEgaHVnZSBhbW91bnQgb2YgdGltZSBhbmQgbW9uZXkgaW50byBhbiBleHBlcmltZW50IHRoYXQgbWF5IG5vdCBwYW4tb3V0LgoKT2YgY291cnNlLCBsZWFybmluZyB0byBzaW11bGF0ZSBkYXRhIGlzIHRyaWNreSBhbmQgdGhlcmUgaXMgYSBsZWFybmluZy1jdXJ2ZSB0byBkb2luZyBpdC4gSSBhbSBnb2luZyB0byBkbyBteSBiZXN0IGluIHRoaXMgZ3VpZGUgdG8gd2FsayBuZXcgdXNlcnMgdGhyb3VnaCBkaWZmaWN1bHRpZXMgYW5kIG1ha2UgdGhpcyBhcyBlYXN5IGFzIHBvc3NpYmxlLiBEZWNsYXJlRGVzaWduIGNsb3NlbHkgZm9sbG93cyB0aGUgZnJhbWV3b3JrIGxhaWQgb3V0IGJ5IFtHZXJiZXIgJiBHcmVlbidzIEZpZWxkIEV4cGVyaW1lbnQgaGFuZGJvb2tdKGh0dHBzOi8vd3d3LmFtYXpvbi5jb20vRmllbGQtRXhwZXJpbWVudHMtRGVzaWduLUFuYWx5c2lzLUludGVycHJldGF0aW9uL2RwLzAzOTM5Nzk5NTQpLiBJIHRoaW5rIHRoaXMgaXMgdGhlIHNpbmdsZSBiZXN0IHJlc291cmNlIHRvIGxvb2sgYXQgaWYgeW91IGZpbmQgYW55IG9mIHRoZSBub3RhdGlvbiBjb25mdXNpbmcuIEZvciBhIG1vcmUgaGFuZHMtb24gYXBwcm9hY2ggZm9yIERlY2xhcmVEZXNpZ24sIEkgcmVhbGx5IGxpa2UgW3RoaXMgZ2VudGxlIGludHJvZHVjdGlvbiBieSBEb3JvdGh5IEJpc2hvcF0oaHR0cDovL2Rpc2N1c3MuZGVjbGFyZWRlc2lnbi5vcmcvdC9nZW50bGUtaW50cm9kdWN0aW9uLXRvLWRlY2xhcmVkZXNpZ24tYnktZG9yb3RoeS1iaXNob3AvNTEpLiBBbm90aGVyIGhlbHBmdWwgcmVzb3VyY2UgaXMgW0tldmluIE11bmdlcidzIHJlcG9zaXRvcnkgZnJvbSBoaXMgd29ya3Nob3BdKGh0dHBzOi8vZ2l0aHViLmNvbS9rbXVuZ2VyL1BSRVNTX3Bvd2VyX2FuYWx5c2lzKSwgYW5kIGxhc3RseSB0aGUgW0RlY2xhcmVEZXNpZ24gYm9va10oaHR0cHM6Ly9ib29rLmRlY2xhcmVkZXNpZ24ub3JnLykgbG9va3MgZmFudGFzdGljLCBidXQgYXMgSSB3cml0ZSB0aGlzLCBpdCdzIHN0aWxsIGEgd29yayBpbiBwcm9ncmVzcy4KCk9uZSB0aGluZyBJIGZvdW5kIGRpZmZpY3VsdCBhcyBhIG5ldyBEZWNsYXJlRGVzaWduIHVzZXIgaXMgdGhhdCBiZWNhdXNlIHRoZSB0b29scyBhcmUgc28gcG93ZXJmdWwsIHRoZSBkb2N1bWVudGF0aW9uIG9mdGVuIGNhbid0IGRlZmluZSBldmVyeSBzaW5nbGUgb3B0aW9uIGF2YWlsYWJsZS4gSW4gdGhpcyBndWlkZSwgSSB3aWxsIGRvIG15IGJlc3QgdG8gYWRkcmVzcyB0aGVzZSBhbWJpZ3VpdGllcy4gSSBhbHNvIHRyeSB0byBiZSBjbGVhciBhYm91dCB3aGF0IG9yZGVyIHRoZSBzdGVwcyBjb21lIGluLCBidXQgd2l0aCB0aGF0IHNhaWQsIGl0IGlzIGltcG9ydGFudCB0byBlbXBoYXNpemUgdGhhdCBJIGFtIG9ubHkgdGVhY2hpbmcgb25lIHdheSB0byB1c2UgRGVjbGFyZURlc2lnbiBhbmQgbW9zdCBzdGVwcyBjYW4gYmUgZG9uZSBpbiBkaWZmZXJlbnQgb3JkZXJzIChzb21ldGltZXMgd2l0aCBkaWZmZXJpbmcgcmVzdWx0cyEpLiBNb3N0IG9mIHRoZSBEZWNsYXJlRGVzaWduIGZ1bmN0aW9ucyBiZWxvdyBjYW4gaGF2ZSB0aGVpciBpbnRlcm5hbHMgcmVwbGFjZWQgd2l0aCBvdGhlciAiaGFuZGxlcnMiLCBhbmQgYWxsb3cgbW9yZSBmbGV4aWJpbGl0eSB0aGFuIEkgYW0gbGV0dGluZyBvbi4gCgpJbiBteSBwZXJzcGVjdGl2ZSwgRGVjbGFyZURlc2lnbiBjYW4gYmUgdGhvdWdodCBvZiBpbiAyIHBhcnRzLiBfXzEpIFRoZSBkYXRhIGZhYnJpY2F0aW9uIHN0ZXBfXyAodGhpcyBpcyB0aGUgYnVsayBvZiB0aGUgY29kZSksICBhbmQgX18yKSB0aGUgZXZhbHVhdGlvbiBzdGVwX18sIHdoZXJlIHVzZXJzIGNhbiBjaGFuZ2UgaW5pdGlhbCBhc3N1bXB0aW9ucyBhbmQgc2VlIGhvdyB3ZWxsIHRoZWlyIGRlc2lnbiBhY3R1YWxseSB3b3JrZWQgKHRoaXMgaXMgdGhlIGNvbXB1dGF0aW9uYWxseSBpbnRlbnNpdmUgcGFydCBvZiB0aGUgY29kZSkuCgpUaGUgY29vbCB0aGluZyBhYm91dCB0aGUgRGVjbGFyZURlc2lnbiBkYXRhIGZhYnJpY2F0aW9uIHN0ZXAgaXMgdGhhdCBpdCBhbGxvd3MgZm9yIChhcyBmYXIgYXMgSSBrbm93KSBfYW55IGRlc2lnbiBpbWFnaW5hYmxlXywgd2hpY2ggaXMgd2h5IHRoZXJlIGFyZSBzbyBtYW55IHN0ZXBzLiBIb3dldmVyLCBiZWNhdXNlIG1vc3QgcmVzZWFyY2hlcnMgb2Z0ZW4gbmVlZCB0byB3b3JrIHdpdGggc2ltcGxlL2NvbW1vbiBkZXNpZ25zLCB0aGVyZSBhcmUgc29tZSByZWFkeS1tYWRlIGRlc2lnbnMgd2hpY2ggYXJlIGF2YWlsYWJsZSBpbiB0aGUgW0Rlc2lnbkxpYnJhcnldKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9EZXNpZ25MaWJyYXJ5L0Rlc2lnbkxpYnJhcnkucGRmKSwgd2hpY2ggdXNlcnMgY2FuIGFsc28gY29udHJpYnV0ZSB0by4gX19BcyBmYXIgYXMgSSBjYW4gdGVsbCwgbW9zdCBzaW1wbGUgcHN5Y2hvbG9neSBsYWItZXhwZXJpbWVudHMgd2lsbCBiZSBhYmxlIHRvIGdldCB0aGUgZW50aXJldHkgb2YgdGhlaXIgbmVlZHMgbWV0IGJ5IERlc2lnbkxpYnJhcnkuX18gQWx0aG91Z2ggSSBkbyB0aGluayB5b3Ugd2lsbCBkZXZlbG9wIG1vcmUgaW50dWl0aW9uIGZvciB0aGUgcHJvY2VzcyBieSB1c2luZyB0aGUgaW5kaXZpZHVhbCBwYXJ0cyBvZiBEZWNsYXJlRGVzaWduLiBJIHdpbGwgZXhwYW5kIG9uIERlc2lnbkxpYnJhcnkgaW4gYSBmdXR1cmUgYXJ0aWNsZS4KCgojIyBCcmllZiBPdmVydmlldyBvZiBQb3dlciBBbmFseXNpcyAvIERlY2xhcmVEZXNpZ24gVGVybXMKCkJlZm9yZSBleHBhbmRpbmcgb24gRGVjbGFyZURlc2lnbiwgaXQgbWFrZXMgc2Vuc2UgdG8gaGF2ZSBhIGZldyB0ZXJtcyBkZWZpbmVkLiBJIHdvbid0IGJlIHVzaW5nIGFsbCB0aGVzZSB0ZXJtcyBpbiB0aGUgZGVzaWduIEkgc2hhcmUsIGJ1dCBpdCBpcyBzdGlsbCB1c2VmdWwgdG8gaGF2ZSB0aGVtIGRlZmluZWQgaW4gb25lIHBsYWNlOgoKX19hdHRyaXRpb25fcmF0ZV9fIC0gdGhlIHByb3BvcnRpb24gb2YgY2FzZXMgdGhhdCB3aWxsIGJlIGxvc3QgdG8gZm9sbG93LXVwLgoKX18kXGFscGhhJCAoYWxwaGEpX18gLSBUaGUgY2hhbmNlIG9mIG1ha2luZyBhIHR5cGUgSSBlcnJvcjsgdGhlIGNoYW5jZSBvZiBjbGFpbWluZyB0aGVyZSBpcyBhbiBlZmZlY3Qgd2hlbiB0aGVyZSBhY3R1YWxseSBpcyBub25lIC0tIGEgZmFsc2UgYWxhcm0uIFRyYWRpdGlvbmFsbHkgMC4wNSAoPSBwLXZhbHVlIHNpZ25pZmljYW5jZSB0aHJlc2hvbGQpLiBBbHNvIGtub3duIGFzIHRoZSBbY2hhbmNlIG9mIG1ha2luZyBhIGZvb2wgb2YgeW91cnNlbGZdKGh0dHBzOi8vcm95YWxzb2NpZXR5cHVibGlzaGluZy5vcmcvZG9pL2Z1bGwvMTAuMTA5OC9yc29zLjE0MDIxNikuCgpfXyRcYmV0YSQgKGJldGEpX18gLSBUaGUgY2hhbmNlIG9mIG1ha2luZyBhIHR5cGUgSUkgZXJyb3Igd2hlcmUgeW91IGZhbHNlbHkgY2xhaW0gdGhlcmUgaXMgbm90IGFuIGVmZmVjdCB3aGVuIHRoZXJlIGFjdHVhbGx5IGlzIC0tIG1pc3NlZCBkZXRlY3Rpb24uIEtub3duIGFzIHBvd2VyIG9yIHNlbnNpdGl2aXR5LiBUcmFkaXRpb25hbGx5IDAuOC4gCgpfX0Jsb2NraW5nX18gLSBQYXJ0aWNpcGFudHMgcHV0IGludG8gYmxvY2tzL3N0cmF0YSBhbmQgdGhlbiByYW5kb21seSBhc3NpZ25lZC4gSGVscHMgcmVkdWNlIHNhbXBsaW5nIHZhcmlhYmlsaXR5LCBhbmQgYXNzdXJlcyB0aGF0IHN1Ymdyb3VwcyBhcmUgYXZhaWxhYmxlIGZvciBzZXBhcmF0ZSBhbmFseXNpcy4gSW4gcHJhY3RpY2UsIGJsb2NraW5nIHJhcmVseSBoYXMgYW55IGRvd25zaWRlcy4KCl9fQ2x1c3RlciByYW5kb20gYXNzaWdubWVudF9fIC0gUmFuZG9tIGFzc2lnbm1lbnQgbm90IGRvbmUgb24gdGhlIGluZGl2aWR1YWwgbGV2ZWwsIGJ1dCBpbnN0ZWFkIGFzc2lnbmVkIG9uIHRoZSBncm91cCBsZXZlbC4gQ29uc2lkZXIgY2l0aWVzIG9yIGNsYXNzcm9vbXMgcmFuZG9tbHkgZ2V0dGluZyBhIHRyZWF0bWVudCwgaW5zdGVhZCBvZiBlYWNoIHBlcnNvbiBpbmRpdmlkdWFsbHkgYmVpbmcgYXNzaWduZWQuIEdlbmVyYWxseSBiYWQgZm9yIHBvd2VyIGFsdGhvdWdoIG5lY2Vzc2FyeS4KCl9fRGlhZ25vc2FuZF9fIC0gQSBzdW1tYXJ5IG9mIHRoZSBkaXN0cmlidXRpb24gb2YgYSBkaWFnbm9zdGljIHN0YXRpc3RpYy4gKGkuZS4sIHRoZSBleHBlY3RlZCB2YWx1ZSBmcm9tIGxvb3BpbmcgdGhlIGRlc2lnbikKCl9fRVNfXyAtIEVmZmVjdCBzaXplLiBNZWFzdXJlcyB0aGUgc3RyZW5ndGggb2YgdGhlIHBoZW5vbWVub24gb2YgaW50ZXJlc3Q7IHNvbGVseSBtYWduaXR1ZGUgYmFzZWQgLSAgZG9lcyBub3QgZGVwZW5kIG9uIHNhbXBsZSBzaXplLgoKX19OX18gLSBUaGUgc2FtcGxlIHNpemUuIExhcmdlciBOIGNhbiBsZWFkIHRvIHNtYWxsZXIgRVMgYmVpbmcgZGVlbWVkIHNpZ25pZmljYW50LCBhbHRob3VnaCB0aGUgc21hbGxlciBFUyBpcyBub3QgYWx3YXlzIGludGVyZXN0aW5nIGluIHByYWN0aWNhbCB0ZXJtcyAoaW1hZ2luZSBzb21ldGhpbmcgdGhhdCBtYWtlcyAxIG1pbGxpb24gcGVvcGxlIDAuMDAwMSUgaGFwcGllciAtLSBhIGxhcmdlIE4gY2FuIGNhdXNlIHNtYWxsIGVmZmVjdHMgdG8gYmUgZGVlbWVkIHNpZ25pZmljYW50LCByZWdhcmRsZXNzIG9mIGl0J3MgYWN0dWFsIGludGVyZXN0KS4KCl9fJFxyaG8kIChyaG8pX18gLSBUaGUgY29ycmVsYXRpb24gYmV0d2VlbiB0aW1lIDEgYW5kIHRpbWUgMi4gV2hlbiB1c2luZyBhIHdpdGhpbiBzdWJqZWN0cyBkZXNpZ24sIGludHVpdGl2ZWx5IHlvdSB3b3VsZCBleHBlY3Qgc29tZSBzdGFiaWxpdHkgaW4gcGVvcGxlcycgcHJlZmVyZW5jZXMgb3ZlcnRpbWUuCgpfX3QxX18gLSBUaW1lIDEuIENhbiBiZSBtb2RpZmllZCBmb3IgYW55IHRpbWUgcGVyaW9kIGUuZy4sIHR4IAoKX19aX18gLSBDb25kaXRpb24uIEluIHRoaXMgZXhhbXBsZSBJIHVzZSBvbmUgdGhpcyAxIHRvIHJlcHJlc2VudCB0aGUgdHJlYXRtZW50IGdyb3VwLCBhbmQgMCB0byByZXByZXNlbnQgdGhlIGNvbnRyb2wuIENmLiBhcm1zCgoKIyMgRGF0YSBhbmQgRGVzaWduIEZhYnJpY2F0aW9uCkRlY2xhcmVEZXNpZ24gb3BlcmF0ZXMgdXNpbmcgYSBbTUlEQSBmcmFtZXdvcmtdKGh0dHBzOi8vZGVjbGFyZWRlc2lnbi5vcmcvZGVjbGFyZS5wZGYpLiBUaGUgZnVuY3Rpb25zIGZvciBlYWNoIG9mIHRoZSBNSURBIGxldHRlcnMgYXJlIHNob3duIGJlbG93LiBTaW1wbHkgcHV0IE1JREEgc3RhbmRzIGZvcjoKCiogX19NX18gLSBtb2RlbCBvZiB0aGUgd29ybGQKICArIGBkZWNsYXJlX3BvcHVsYXRpb25gCiAgKyBgZGVjbGFyZV9wb3RlbnRpb25hbF9vdXRjb21lc2AKKiBfX0lfXyAtIGlucXVpcnkKICArIGBkZWNsYXJlX2VzdGltYW5kYAoqIF9fRF9fIC0gZGF0YSBzdHJhdGVneQogICsgYGRlY2xhcmVfc2FtcGxpbmdgCiAgKyBgZGVjbGFyZV9hc3NpZ25tZW50YAogICsgYGRlY2xhcmVfcmV2ZWFsYAogICsgYGRlY2xhcmVfc3RlcGAKKiBfX0FfXyAtIGFuc3dlciBzdHJhdGVneSAKICArIGBkZWNsYXJlX2VzdGltYXRvcmAKCkl0IGlzIGltcG9ydGFudCB0byBub3RlIHRoYXQgdGhlIG9yZGVyIG9mIHRoZSBmdW5jdGlvbnMgaXMgZm9yIHRoZSBtb3N0IHBhcnQgbmVjZXNzYXJ5IGFuZCB0aGF0IHRoZXkgYWxsIGZvbGxvdyB0aGUgYGRlY2xhcmVfKmAgcGF0dGVybi4gCgohW0Egc2ltcGxpZmllZCBleGFtcGxlIG9mIGEgRGVjbGFyZURlc2lnbiBlY29zeXN0ZW0uIEluIGEgcmVhbCBkZXNpZ24sIHlvdSBtYXkgbmVlZCB0byBjaGFuZ2UgdGhlIG9yZGVyIG9mIHRoZSBEZWNsYXJlIHlvdXIgZGVzaWduIHN0ZXBzIChzaG93biBpbiBibHVlKSwgb3IgdXNlIGEgZnVuY3Rpb24gbXVsdGlwbGUgdGltZXMgdG8gcHJvcGVybHkgcmVwcmVzZW50IHlvdXIgZGVzaWduIChkZXNpZ24gZnVuY3Rpb25zIHRoYXQgbWF5IGJlIHVzZWQgbXVsdGlwbGUgdGltZXMgYXJlIHJlcHJlc2VudGVkIHdpdGggYm9sZCBib3JkZXJzKS5dKERlY2xhcmVEZXNpZ24ucG5nKQoKIyBGaXJzdCBFeGFtcGxlOiBUaGUgZWZmZWN0IG9mIGNvZmZlZSBvbiBwcm9kdWN0aXZpdHkKCkxldCdzIGJlZ2luIHdpdGggYSBzaW1wbGUgZGVzaWduLiBMZXQncyBzYXkgd2UgaGF2ZSBhIGZhY3Rvcnkgd2l0aCAxMDAgd29ya2VycyB3aG8gbWFrZSB3aWRnZXRzLiBJIHNwbGl0IG15IHdvcmtlcnMgaW50byB0d28gZ3JvdXBzLCBhbmQgZ2l2ZSBvbmUgZ3JvdXAgY29mZmVlLiBJIHdhbnQgdG8gc2VlIGhvdyBjb2ZmZWUgaW1wYWN0cyB0aGUgcHJvZHVjdGl2aXR5IG9mIHRoZSBzZWNvbmQgZ3JvdXAuIAoKYGBge3IsIGVjaG89RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSkKYGBgCgoKV2Ugc3RhcnQgYnkgbG9hZGluZyB0aGUgZm9sbG93aW5nIHBhY2thZ2VzOgpgYGB7ciAgc2V0dXB9CnJtKGxpc3QgPSBscygpKQpzZXQuc2VlZCgxMykKbGlicmFyeShEZWNsYXJlRGVzaWduKQpsaWJyYXJ5KERlc2lnbkxpYnJhcnkpCmxpYnJhcnkoa25pdHIpCmxpYnJhcnkoRFQpCmxpYnJhcnkodGlkeXZlcnNlKQoKbl9zaW1zID0gMTAwCmBgYAoKIyMjIF9fTV9fIC0gTW9kZWwgb2YgdGhlIFdvcmxkCiMjIyMgVGVybXMKVG8gYmVnaW4sIGxldCdzIGRlZmluZSBvdXIgdGVybXMuIEludHVpdGl2ZWx5IHdlIGtub3cgdGhhdCB3ZSdsbCBuZWVkIGBOYCwgdGhlIG51bWJlciBvZiBwZW9wbGUsIGJ1dCB3ZSdsbCBhbHNvIG5lZWQgdG8gZGVmaW5lIHRoZSBlZmZlY3Qgc2l6ZSB3ZSB0aGluayBjb2ZmZWUgd2lsbCBoYXZlLiBOb3RpY2UgSSBhbSBtYWtpbmcgdGhlc2UgYXNzdW1wdGlvbnMgdXAtZnJvbnQsIGFuZCBkZWZpbmluZyB0aGVtIGFzIG9iamVjdHMuIEluIG15IG9waW5pb24gdGhpcyBpcyB0aGUgbW9zdCB0cmFuc3BhcmVudCB3YXkgdG8gdXNlIERlY2xhcmVEZXNpZ24gYW5kIGlzIGFsc28gdGhlIG1vc3QgaW50dWl0aXZlLiBQbGVhc2Ugbm90ZSB0aGF0IG1vcmUgY29tcGxleCBkZXNpZ25zIHdpbGwgaGF2ZSBhIGxvdCBtb3JlIHRlcm1zIHRvIGRlZmluZS4KCihOb3RlOiBJIGtlZXAgYWRkaW5nIHRvIGEgZGYxIGF0IHRoZSBib3R0b20gb2YgbXkgY2h1bmtzLCBidXQgdGhpcyBpcyBvbmx5IGZvciB2aXN1YWxpemF0aW9uIHB1cnBvc2VzIC0tIGl0IGlzIG5vdCBwYXJ0IG9mIHRoZSBEZWNsYXJlRGVzaWduIGZyYW1ld29yaywgYW5kIHlvdSB3b24ndCBuZWVkIHRvIGRvIHRoaXMpCmBgYHtyIHRlcm1zfQpOIDwtIDEwMCAjIHNhbXBsZSBzaXplLCAxMDAgZmFjdG9yeSB3b3JrZXJzCmF0ZSA8LSA0ICMgYXZlcmFnZSB0cmVhdG1lbnQgZWZmZWN0IEkgdGhpbmsgY29mZmVlIHdpbGwgaGF2ZSBvbiBwcm9kdWN0aXZpdHkKc2RfMSA8LSA1ICMgU0Qgb2Ygd29ya2VyIHByb2R1Y3Rpdml0eSBiZWZvcmUgaW50ZXJ2ZW50aW9uCgpkZjEgPC0gIiIKYGBgCgojIyMjIFBvcHVsYXRpb24KSSBzdGFydCBieSBkZWZpbmluZyB0aGUgcG9wdWxhdGlvbi4gRm9yIG1lIHRoaXMgaXMgbGl0ZXJhbGx5IGV2ZXJ5b25lIGluIHRoZSBmYWN0b3J5LCBhbGwgMTAwIHBlb3BsZSwgYnV0IHRoaW5raW5nIGFoZWFkLCBpbWFnaW5lIEkgd2FzIHN0dWR5aW5nIEZhY2Vib29rIHVzZXJzLCBJIHdvdWxkIHRoZW9yZXRpY2FsbHkgdXNlIDM2MCBtaWxsaW9uIHRvIHJlcHJlc2VudCBldmVyeW9uZSBvbiBGYWNlYm9vay4gSW4gcmVhbGl0eSBteSBzYW1wbGUgd291bGRuJ3QgaW52b2x2ZSBldmVyeSB1c2VyIG9uIEZhY2Vib29rLCBidXQgdGhhdCB3b3VsZCBzdGlsbCBiZSBteSBwb3B1bGF0aW9uLiBOZXh0LCBub3RpY2UgSSBfX21hbnVhbGx5IGFzc2VydCB0aGUgZGlzdHJpYnV0aW9uc19fIGZvciB3aWRnZXRzIGJlY2F1c2Ugbm90IGV2ZXJ5b25lIG1ha2VzIHRoZSBzYW1lIG51bWJlciBvZiB3aWRnZXRzIGVhY2ggZGF5LiAKCl9fVGhlIHB1cnBvc2Ugb2YgdGhpcyBzdGVwIGlzIHRvIGRlZmluZSB0aGUgdGhhdCBncm91cHMgd2lsbCBiZSBjb21wYXJlZCBiZWZvcmUgYmVpbmcgZ2l2ZW4gdGhlIHRyZWF0bWVudCwgYW5kIGZvciBtZSB0aGlzIGlzIG9uZSBncm91cF9fLiBUaGlzIHN0ZXAgaXMgcmVhbGx5IGNyZWF0aW5nIHNpbWlsYXIgdG8gbWFraW5nIGEgcmVndWxhciBkYXRhZnJhbWUgd2l0aCB0aGUgZXhjZXB0aW9uIG9mIHRoZSBzcGVjaWFsIF9fYE5gX18gYXJndW1lbnQgd2hpY2ggZGVmaW5lcyB0aGUgbnVtYmVyIG9mIHJvd3MsIGFuZCBjcmVhdGVzIGEgY29sdW1uIHRvIGxhYmVsIHRoZSBwYXJ0aWNpcGFudHMuCmBgYHtyIHBvcHVsYXRpb259CiMgTTogTW9kZWwKCnBvcHVsYXRpb24gPC0gCiAgZGVjbGFyZV9wb3B1bGF0aW9uKE4gPSBOLAogICAgICAgICAgICAgICAgICAgICB3aWRnZXRzX3QxID0gcm5vcm0obiA9IE4sICMgMTAwIGRyYXdzIGZyb20gYSBub3JtYWwgZGlzdHJpYnV0aW9uCiAgICAgICAgICAgICAgICAgICAgIG1lYW4gPSA1MCwgIyBiZWZvcmUgaW50ZXJ2ZW50aW9uLCBteSB3b3JrZXJzIGF2ZXJhZ2Ugb2YgNTAgd2lkZ2V0cyBhIGRheQogICAgICAgICAgICAgICAgICAgICBzZCA9IHNkXzEpICU+JSByb3VuZCguLCAyKSkgIyBzZCBvZiB3b3JrZXIgcHJvZHVjdGl2aXR5CgoKZGYxIDwtIHBvcHVsYXRpb24oKQoKZGF0YXRhYmxlKGRmMSkKYGBgCgpIZXJlIHdlIHNlZSB0aGUgZWFjaCBvZiB0aGUgMTAwIHdvcmtlcnMgbWFrZXMgYXBwcm94aW1hdGVseSA1MCB3aWRnZXRzIGEgZGF5LgoKVGhlIGtleSBwb2ludHMgZnJvbSB0aGlzIGBkZWNsYXJlX3BvcHVsYXRpb25gIGFyZToKCiogVGhlIG51bWJlciBvZiByb3dzIGluIHlvdXIgcG9wdWxhdGlvbiB3aWxsIGJlIGVxdWFsIHRvIE4uCgoqIFlvdXIgZmluYWwgc2FtcGxlIHdpbGwgYmUgZXF1YWwgdG8gb3IgbGVzcyB0aGFuIE4KCiogT25lIGNvbHVtbiBmb3IgX2VhY2ggbWVhc3VyZSB0aGF0IHlvdSBleHBlY3QgdGhhdCBhZmZlY3RzIG9yIHdpbGwgYmUgYWZmZWN0ZWQgYnkgdHJlYXRtZW50XwoKCgojIyMjIE91dGNvbWVzCl9fVGhlIHB1cnBvc2Ugb2YgdGhpcyBzdGVwIGlzIHRvIGRlZmluZSB0aGUgdHdvIG91dGNvbWVzIHVzaW5nIGVhY2ggb2YgdGhlIGdyb3VwcyAoaS5lLiB0cmVhdG1lbnQvY29udHJvbClfXy4gVGhlIHRyZWF0bWVudCBncm91cCB3aWxsIGhhdmUgdGhlIEFURSBhZGRlZCB0byB0aGVpciBkaXN0cmlidXRpb24uIEFnYWluIHRoaXMgc3RlcCBpcyBqdXN0IGFkZGluZyBuZXcgY29sdW1ucyB0byBvdXIgZGF0YSBmcmFtZXMuCmBgYHtyIG91dGNvbWUsIGluY2x1ZGU9VFJVRX0KcG90ZW50aWFsX291dGNvbWVzIDwtIGRlY2xhcmVfcG90ZW50aWFsX291dGNvbWVzKFlfWl8wID0gd2lkZ2V0c190MSwgIyB0aGUgY29udHJvbCBncm91cCwgaGVyZSB3ZSBleHBlY3QgYnVzaW5lc3MgYXMgdXN1YWwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBZX1pfMSA9IHdpZGdldHNfdDEgKyBhdGUpICMgdGhlIHRyZWF0bWVudCBncm91cCwgYnVzaW5lc3MgYXMgdXN1YWwgKyB0aGUgcHJvZHVjdGl2aXR5IGJvb3N0IGZyb20gY29mZmVlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKCmRmMSA8LSBwb3RlbnRpYWxfb3V0Y29tZXMoZGYxKQoKZGF0YXRhYmxlKGRmMSkKYGBgCk5vdGljZSBhYm92ZSBob3cgZXZlcnlvbmUgaGFzIGEgInBvdGVudGlhbCBvdXRjb21lIiBmb3IgdGhhdCB3b3VsZCBoYXBwZW4gX2lmXyB0aGV5IHdlcmUgdHJlYXRlZCBvciBub3QuIFNpbmNlIHdlIGV4cGVjdCB0byBzcGxpdCBvdXIgZGVzaWduIGludG8gdHdvIGdyb3VwcywgaW4gcmVhbCBsaWZlIHdlIHdvdWxkbid0IGFjdHVhbGx5IGdldCB0byBvYnNlcnZlIGJvdGggb2YgdGhlc2UgcG90ZW50aWFsIG91dGNvbWVzLgoKVGhlIGtleSBwb2ludHMgZnJvbSB0aGlzIGBkZWNsYXJlX3BvdGVudGlhbF9vdXRjb21lc2AgYXJlOiAgCgoqIFRoaXMgaXMgdGhlIHN0ZXAgd2hlcmUgb3VyIHRyZWF0bWVudCBlZmZlY3QgZ2V0cyBpbmNsdWRlZCBpbiB0aGUgbW9kZWwKCiogRXZlcnlvbmUgaGFzIGEgb3V0Y29tZSB0aGF0IF93b3VsZF8gaGFwcGVuIGRlcGVuZGluZyBvbiB3aGljaCBncm91cCB0aGV5IHdlcmUgcGxhY2VkIGluCgoKIyMjIF9fSV9fIC0gSW5xdWlyeQoKIyMjIyBFc3RpbWFuZAoKX19UaGUgcHVycG9zZSBvZiB0aGlzIHN0ZXAgaXMgdG8gZGVmaW5lLCBob3cgeW91IGRlZmluZSwgeW91ciBBVEUgLS0gdGhpcyBpcyB5b3VyIFRSVUUgVFJFQVRNRU5UIEVGRkVDVClfXy4gQmVjYXVzZSB3ZSBhcmUgc2ltdWxhdGluZyBkYXRhLCB3ZSBoYXZlIHNvbWV3aGF0IG9mIGEgInBlcmZlY3Qgd29ybGQiLCB3aGVyZSBhbGwgcGFydGljaXBhbnRzIGdldCB0aGUgdHJlYXRtZW50IHBlcmZlY3RseSBhbmQgbm8gb25lIGlzIG1pc3NpbmcgKHlldCksIHdlIHdpbGwgZ2V0IGV4YWN0bHkgdGhlIHNhbWUgQVRFIGFzIHdlIGRlZmluZWQgb3JpZ2luYWxseS4gCgpUaGUgZXN0aW1hbmQgYmVsb3cgaXMgdGhlIHNpbXBsZXN0IGVzdGltYW5kLCBidXQgYXMgSmFzcGVyIHBvaW50cyBvdXQgdGhhdCB0aGVyZSBhcmUgW2NvbmRpdGlvbmFsIEFURXNdKGh0dHBzOi8vcGRmcy5zZW1hbnRpY3NjaG9sYXIub3JnLzg3MTQvMjYwMTI5ZTUxYWJiMDlmZDg5ZDZmZjc5MDY1YWYxN2JiMTA2LnBkZiksIG9yIHNwZWNpYWwgQVRFcyBmb3Igd2hlbiB5b3UgaGF2ZSBbY2F0ZWdvcmljYWwgb3V0Y29tZXNdKGh0dHBzOi8vYXJ4aXYub3JnL3BkZi8xNTAxLjAxMjM0LnBkZikgd2hpY2ggYXJlIG5lY2Vzc2FyeSBmb3IgbW9yZSBjb21wbGV4IGRlc2lnbnMuCgpgYGB7ciBlc3RpbWFuZCwgaW5jbHVkZT1UUlVFfQplc3RpbWFuZCA8LSBkZWNsYXJlX2VzdGltYW5kKEFURSA9IG1lYW4oWV9aXzEgLSBZX1pfMCkpCgprYWJsZShlc3RpbWFuZChkZjEpKQpgYGAKVGhlIGtleSBwb2ludHMgZnJvbSB0aGlzIGBkZWNsYXJlX2VzdGltYW5kYCBhcmU6CgoqIFRoaXMgaXMgb3VyICJkcmVhbSB3b3JsZCIgdHJlYXRtZW50IGVmZmVjdChzKQoKKiBUaGlzIHdpbGwgYmUgaW1wb3J0YW50IGxhdGVyIG9uIGZvciBldmFsdWF0aW5nIG91ciBtb2RlbAoKCiMjIyBfX0RfXyAtIERhdGEgU3RyYXRlZ3kKCiMjIyMgQXNzaWdubWVudApUaGVyZSBhcmUgdHdvIGltcG9ydGFudCBhcmd1bWVudHMgaW4gdGhlIGBkZWNsYXJlX2Fzc2lnbm1lbnRgIGZ1bmN0aW9uIHdoaWNoIGFyZSBgcHJvYmAgKHRoZSBjaGFuY2Ugb2YgZ2V0dGluZyBwaWNrZWQpIGFuZCBgYXNzaWdubWVudF92YXJpYWJsZWAgKHRoZSBuYW1lIG9mIHRoZSB2YXJpYWJsZSBiZWluZyBhc3NpZ25lZCkuCgpJIHRoaW5rIGl0IGlzIHJlYWxseSBpbXBvcnRhbnQgdG8gcG9pbnQgb3V0IHRoYXQgdGhpcyBmdW5jdGlvbiBkZWZhdWx0cyB0aGUgbmFtZSB0byBgYXNzaWdubWVudF92YXJpYWJsZWAgdG8gWiB3aGljaCBpcyBlc3NlbnRpYWwuIF9fV2hhdCB0aGlzIG1lYW5zIGlzIHRoYXQgdGhlIGRlZmF1bHQgdXNlIG9mIGBkZWNsYXJlX2Fzc2lnbm1lbnRgIGlzIHRvIGRlY2xhcmUgY29uZGl0aW9uc19fLCBhbHRob3VnaCB0aGlzIGZ1bmN0aW9uIGhhcyBvdGhlciBwdXJwb3NlcyBpdCB1c2VkIGZvciBhbHNvIChlLmcuLCBhdHRyaXRpb24pLiAKCgpfX1dlIGFyZSBkZWNsYXJpbmcgd2hhdCAlIG9mIHBlb3BsZSBnZXQgYXNzaWduZWQgdG8gdGhlIHRyZWF0bWVudCBncm91cC4gSGVyZSB3ZSBjcmVhdGUgdGhlIGBaYCBhbmQgYFpfY29uZF9wcm9iYCBjb2x1bW5zX18KYGBge3IgYXNzaWdubWVudCwgaW5jbHVkZT1UUlVFfQphc3NpZ25tZW50IDwtIGRlY2xhcmVfYXNzaWdubWVudChwcm9iID0gLjUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhc3NpZ25tZW50X3ZhcmlhYmxlID0gWikgIyBieSB0aGUgcmVsZXZhbnQgcGFydCBvZiBjb2x1bW5zIHRvIGFzc2lnbiBmcm9tLCBkZWZhdWx0IGFzc2lnbm1lbnRfdmFyaWFibGUgPSBaCmRmMSA8LSBhc3NpZ25tZW50KGRmMSkKZGF0YXRhYmxlKGRmMSkKYGBgCkFib3ZlIGBaYCByZXByZXNlbnRzIHRoZSBjb25kaXRpb24gdGhlIHBhcnRpY2lwYW50IGlzIGFzc2lnbmVkIHRvLCBgWl9jb25kX3Byb2JgIHRoZSBjaGFuY2UgdGhhdCB0aGUgcGFydGljaXBhbnQgZ2V0cyBhc3NpZ25lZCB0byBgWmAuIFRoaXMgaXMgb2YgY291cnNlIGNvdWxkIGJlIGEgbG90IG1vcmUgY29tcGxpY2F0ZWQgd2l0aCBtb3JlIGNvbmRpdGlvbnMsIGFuZCB1bmVxdWFsIGFzc2lnbm1lbnQgbGV2ZWxzLgoKVGhlIGtleSBwb2ludHMgZnJvbSB0aGlzIGBkZWNsYXJlX2Fzc2lnbm1lbnRgIGFyZToKCiogVGhpcyBpcyB3aGVyZSB3ZSBzdGF0ZSB0aGUgcHJvYmFibGl0eSBvZiBiZWluZyBhc3NpZ25lZCB0byBhIGNvbmRpdGlvbgoKKiBTdWJqZWN0cyBhcmUgbm90ICJsaXRlcmFsbHkiIHBsYWNlZCBpbnRvIGdyb3VwcyB5ZXQKCgojIyMjIF9BY3R1YWxseV8gcHV0IHBlb3BsZSBpbiBncm91cHMgKFJldmVhbCkKCk5leHQgd2UgX2FjdHVhbGx5XyBnaXZlIHBlb3BsZSB0aGUgdHJlYXRtZW50LiBIZXJlIHdlIGNyZWF0ZSB0aGUgYFlgIGNvbHVtbiwgd2hpY2ggaXMgb3VyIG9ic2VydmVkIG91dGNvbWUuCgpgYGB7ciBhY3R1YWxfYXNzaWdubWVudCwgaW5jbHVkZT1UUlVFfQpyZXZlYWwgPC0gZGVjbGFyZV9yZXZlYWwob3V0Y29tZV92YXJpYWJsZXMgPSBZKSAjIGhlcmUgd2UgdXNlIHRoZSBwcmVmaXggYmVmb3JlIHRoZSBaIHBhcnQgYmVnaW5zLCBpbiBvdXIgY2FzZSB0aGlzIGlzIHNpbXBseSBZCgoKZGYxIDwtIHJldmVhbChkZjEpCgoKZGF0YXRhYmxlKGRmMSkKYGBgCgpOb3RlIHRoYXQgdGhlIHdheSB0aGUgY2h1bmsgYWJvdmUgaXMgd3JpdHRlbiwgeW91IGNhbiBjb25jZXB0dWFsbHkgeW91IGNhbiB0aGluayBvZiBgZGVjbGFyZV9yZXZlYWxgIGxpa2U6CmBgYApkZjEgJT4lIAogIG11dGF0ZShZID0gaWZfZWxzZShaID09IDEsIFlfWl8xLCBZX1pfMCkpCmBgYAoKIyMjIF9fQV9fIC0gQW5zd2VyIFN0cmF0ZWd5CgpfX1RoaXMgaXMgdGhlIGFjdHVhbCBtb2RlbGxpbmcgd2UncmUgdXNpbmdfXwoKVGhlIGltcG9ydGFudCBwb2ludHMgaGVyZSBhcmUgdGhhdDogIAoKKiBPdXIgZXN0aW1hbmRzIGFyZ3VtZW50IGNvcnJlc3BvbmQgd2l0aCB0aGUgbmFtZXMgb2YgdGhlIGVzdGltYW5kcyB3ZSBtYWRlIGJlZm9yZSwKKiBUaGUgbW9kZWwgY2FuIGJlIGFueXRoaW5nIHRoYXQgd29ya3Mgd2l0aCB0aGUgYGJyb29tYCBwYWNrYWdlLCBhbmQgY2FuIGJlIG1vZGlmaWVkIHRvIHdvcmsgd2l0aCBhbnkgbW9kZWwgdGhhdCBvdXRwdXRzIGEgZGF0YWZyYW1lLiBIZXJlIHdlIHVzZSBgZXN0aW1hdHI6OmxtX3JvYnVzdGAgYXMgb3VyIG1vZGVsLgoKClRoZSBtb2RlbCBiZWluZyBzaG93biBoZXJlIGlzIHNpbXBseSB1c2luZyB0cmVhdG1lbnQgYXNzaWdubWVudCAoWikgdG8gcHJlZGljdCBwcm9kdWN0aXZpdHkgb3V0Y29tZXMgKFkpIApgYGB7ciBlc3RpbWF0ZWRfZWZmZWN0fQplc3RpbWF0ZWRfZWZmZWN0IDwtIGRlY2xhcmVfZXN0aW1hdG9yKAogIFkgfiBaLAogIG1vZGVsID0gbG1fcm9idXN0LAogIGVzdGltYW5kID0gYygiQVRFIiksICMgYWxzbyBqdXN0IGBlc3RpbWFuZGAgKHRoZSBvYmplY3Qgd2UgZGVmaW5lZCBhYm92ZSkgd291bGQgd29yawogICNzdWJzZXQgPSBSID09IDEsICMgb25seSBrZWVwIHBlb3BsZSBub3QgbG9zdCB0byBhdHRyaXRpb24KICBsYWJlbCA9ICJUcmVhdG1lbnQgRWZmZWN0IgopCmBgYAoKVGhlIGtleSBwb2ludHMgZnJvbSBgZGVjbGFyZV9lc3RpbWF0b3JgIGlzOgoKKiBUaGlzIGlzIHdoZXJlIHlvdSBkZWZpbmUgeW91ciBtb2RlbC4gWW91IGtub3csIHRoZSBzYW1lIG9uZSB5b3UgYXJlIGdvaW5nIHRvIHVzZSBpbiB0aGUgeW91ciBwYXBlci4KCiogWW91IGNhbiBhbHNvIHVzZSB0aGlzIHN0ZXAgdG8gdHJ5IG91dCBtdWx0aXBsZSBtb2RlbHMgdG8gc2VlIHdoaWNoIG9uZSB3b3JrcyBiZXN0IGZvciB5b3VyIGRlc2lnbi4KCgpOb3RlOiBfX0lmIHlvdSBhcmUgcGxhbm5pbmcgb24gdGVzdGluZyBtdWx0aXBsZSBtb2RlbHMsIGl0IG1ha2VzIHNlbnNlIHRvIGNyZWF0ZSBhIGRpZmZlcmVudCBgZGVsY2FyZV9lc3RpbWF0b3JgIGZ1bmN0aW9uIGZvciBlYWNoIG9mIHRoZSBtb2RlbHMgeW91IGFyZSBwbGFubmluZyBvbiB0ZXN0aW5nX18uIEZvciBleGFtcGxlIGZvciBvdXIgY3VycmVudCBkZXNpZ24sIEkgdXNlIGxpbmVhciByZWdyZXNzaW9uLCBidXQgSSBjb3VsZCBoYXZlIG9wdGVkIGZvciBhIGNvcnJlbGF0aW9uIG9yIGEgdC10ZXN0IGlmIEkgaGFkIHdhbnRlZCB0by4KCgoKIyMjIyBQdXQgaXQgYWxsIHRvZ2V0aGVyClB1dHRpbmcgYWxsIHRoZSBwaWVjZXMgd2UganVzdCB3cm90ZSB0b2dldGhlciB3ZSBnZXQgYSBkZXNpZ24gdGhhdCBsb29rcyBsaWtlIHRoaXMuIFdlIGRlZmluZWQgYWxsIHRoZXNlIHBpZWNlcyBpbmRpdmlkdWFsbHksIGJ1dCBvZiBjb3Vyc2Ugd2UgY291bGQgaGF2ZSBkb25lIHRoaXMgYWxsIHRvZ2V0aGVyIGdncGxvdCBzdHlsZSwgYWx0aG91Z2ggSSBwZXJzb25hbGx5IHByZWZlciB0byBkbyBvbmUgc3RlcCBhdCBhIHRpbWUuIEZyb20gbm93IG9uIHRoZSBjb21iaW5hdGlvbiBvZiBhbGwgb2YgdGhvc2UgcGFydHMgd2lsbCBiZSBjYWxsZWQgb3VyIF9fX291clxfZGVzaWduX19fCgpgYGB7ciBvdXJfZGVzaWdufQpvdXJfZGVzaWduIDwtIHBvcHVsYXRpb24gKyAKICAgICAgICAgICAgICBwb3RlbnRpYWxfb3V0Y29tZXMgKyAKICAgICAgICAgICAgICBlc3RpbWFuZCArIAogICAgICAgICAgICAgIGFzc2lnbm1lbnQgKyAKICAgICAgICAgICAgICByZXZlYWwgKyAKICAgICAgICAgICAgICBlc3RpbWF0ZWRfZWZmZWN0IApgYGAKCgpIZXJlIEkgcGFzdGUgYWxsIHRoZSBjb2RlIGZyb20gYWJvdmUgdG9nZXRoZXIganVzdCBpbmNhc2UgeW91IHdvdWxkIGxpa2UgdG8gdGVzdCBpdCBhcyBhIHdob2xlOgpgYGB7ciwgb3VyX2Rlc2lnbl8yLCBldmFsPUZBTFNFLCBpbmNsdWRlPVR9Cm91cl9kZXNpZ24gPC0gCiAgZGVjbGFyZV9wb3B1bGF0aW9uKE4gPSBOLCAKICAgICAgICAgICAgICAgICAgICAgd2lkZ2V0c190MSA9IHJub3JtKG4gPSBOLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lYW4gPSA1MCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNkID0gc2RfMSkgJT4lIHJvdW5kKC4sIDIpKSArCiAgZGVjbGFyZV9wb3RlbnRpYWxfb3V0Y29tZXMoWV9aXzAgPSB3aWRnZXRzX3QxLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgWV9aXzEgPSB3aWRnZXRzX3QxICsgYXRlKSArCiAgZGVjbGFyZV9lc3RpbWFuZChBVEUgPSBtZWFuKFlfWl8xIC0gWV9aXzApKSArCiAgZGVjbGFyZV9hc3NpZ25tZW50KHByb2IgPSAuNSwgCiAgICAgICAgICAgICAgICAgICAgIGFzc2lnbm1lbnRfdmFyaWFibGUgPSBaKSArCiAgZGVjbGFyZV9yZXZlYWwob3V0Y29tZV92YXJpYWJsZXMgPSBZKSArIAogIGRlY2xhcmVfZXN0aW1hdG9yKFkgfiBaLAogICAgICAgICAgICAgICAgICAgIG1vZGVsID0gbG1fcm9idXN0LAogICAgICAgICAgICAgICAgICAgIGVzdGltYW5kID0gYygiQVRFIiksIAogICAgICAgICAgICAgICAgICAgIGxhYmVsID0gIlRyZWF0bWVudCBFZmZlY3QiCikKYGBgCgojIyBNb2RlbCBFdmFsdWF0aW9uCgpUaGUgZm9sbG93aW5nIGNodW5rcyBlYWNoIHNob3djYXNlIF9fb25lX18gbW9kZWwgZXZhbHVhdGluZyBmdW5jdGlvbi4gTm90ZSB0aGF0IHNvbWV0aW1lcyBJIHVzZSBtdWx0aXBsZSBmdW5jdGlvbnMgdG9nZXRoZXIgYmVjYXVzZSB0aGF0IGlzIGJlc3Qgd2F5IHRvIHVzZSB0aGF0IGZ1bmN0aW9uLiBJIGFtIHBpcGluZyBzb21lIGZ1bmN0aW9ucyBpbnRvIGBoZWFkYCBhbmQgYGthYmxlYCBmb3IgdmlzdWFsaXphdGlvbiBwdXJwb3Nlcy4KCiMjIyMgVG8gZ2V0IHRha2UgYSBwZWVrIGF0IHlvdXIgZGVzaWduCk5vdGU6IFRoaXMgaXMgb25seSBhIHNpbmdsZSBzaW11bGF0aW9uIG9mIHlvdXIgZGF0YSB3aXRoIGBkcmF3X2RhdGFgCmBgYHtyLCBmaXJzdF92aWV3LCBpbmNsdWRlPVRSVUUsIH0Kb3VyX2Rlc2lnbiAlPiUgCiAgZHJhd19kYXRhKCkgJT4lICMgZHJhdyBzaW5nbGUgc2ltdWxhdGlvbgogIGhlYWQoNSkgJT4lIAogIGthYmxlKCkKYGBgCgojIyMjIFRha2UgYSBwZWVrIGF0IHlvdXIgdW5iaWFzZWQgZXN0aW1hbmRzCmBkcmF3X2VzdGltYW5kc2AKYGBge3IgZHJhd19lc3RpbWFuZHN9Cm91cl9kZXNpZ24gJT4lIAogIGRyYXdfZXN0aW1hbmRzKCkgJT4lCiAga2FibGUoKQpgYGAKCiMjIyMgU2VlIGVzdGltYXRlcyBvZiBtb2RlbApgZHJhd19lc3RpbWF0ZXNgCmBgYHtyLCBkcmF3X2VzdGltYXRlc30Kb3VyX2Rlc2lnbiAlPiUgCiAgZHJhd19lc3RpbWF0ZXMoKSAlPiUgIyAKICBrYWJsZSgpCmBgYAoKIyMjIFRvIHNlZSB0aGUgYWdncmVnYXRlZCBzdW1tYXJ5IG9mIHlvdXIgZGVzaWduCmBkaWFnbm9zZV9kZXNpZ25gIHdpbGwgbG9vcCB0aGUgY3JlYXRpb24gb2YgeW91ciBkZXNpZ24sIG1ha2luZyBpdCB0aGUgbW9zdCByZXNvdXJjZSBpbnRlbnNpdmUgc3RlcCBkZXNjcmliZWQuIFRoaXMgc2hvd3MgdGhlIGRldGFpbHMgb2YgeW91ciBkZXNpZ24uIF9fVGhpcyBpcyB0aGUgc2luZ2xlIG1vc3QgaW1wb3J0YW50IGZ1bmN0aW9uIGZvciB0aGUgZXZhbHVhdGlvbiBvZiBtb2RlbHNfXwoKSGVyZSBJIHVzZSBgc2ltcyA9IGByIG5fc2ltc2BgIG9ubHkgZm9yIGRlbW9uc3RyYXRpb24gcHVycG9zZXMsIGJ1dCBpbiByZWFsIGxpZmUgeW91IHdvdWxkIGxpa2VseSB3YW50IHRvIHVzZSA1MDAgb3IgaGlnaGVyLgpgYGB7ciwgZGlhZ25vc2VfZGVzaWdufQpkaWFnbm9zaXMxIDwtIG91cl9kZXNpZ24gJT4lIAogIGRpYWdub3NlX2Rlc2lnbihzaW1zID0gbl9zaW1zKQpgYGAKCl9fT1BUSU9OQUwgQVNJREU6X18gQW5vdGhlciB3YXkgdG8gdG8gc2ltdWxhdGUgZGF0YSBpbiBEZWNsYXJlRGVzaWduIGlzIHdpdGggdGhlIGBzaW11bGF0ZV9kZXNpZ25gIGZ1bmN0aW9uLiBJIGRvbid0IHNob3djYXNlIGl0IGhlcmUgYnV0IGl0IGlzIGVzc2VudGlhbGx5IGVxdWl2YWxlbnQgdG8gYG91cl9kZXNpZ24gJT4lIGRpYWdub3NlX2Rlc2lnbiAlPiUgZ2V0X3NpbXVsYXRpb25zKClgCgoKIyMjIyMgVG8gc2VlIHRoZSBhZ2dyZWdhdGVkIHN1bW1hcnkgaW4gZGF0YS5mcmFtZSBmb3JtIChkaWFnbm9zYW5kcykKYGdldF9kaWFnbm9zYW5kc2AuIFRoaXMgaXMgcmVhbGx5IHVzZWZ1bCBmb3IgbWFraW5nIHBsb3RzLgpgYGB7ciwgZ2V0X2RpYWdub3NhbmRzfQpkaWFnbm9zaXMxICU+JSAKICBnZXRfZGlhZ25vc2FuZHMoKSAlPiUgIAogIGthYmxlKCkKYGBgCgojIyMjIyBXaGF0IGFyZSBhbGwgdGhlIHN0YXRzIGluIHRoZSBkaWFnbm9zYW5kIGFueXdheT8KRGVzY3JpcHRpb25zIGZyb20gW3BnIDddKGh0dHBzOi8vZGVjbGFyZWRlc2lnbi5vcmcvZGVjbGFyZS5wZGYpLCBGb3JtdWxhcyBmcm9tIFtoZXJlXShodHRwczovL3d3dy5yZG9jdW1lbnRhdGlvbi5vcmcvcGFja2FnZXMvRGVjbGFyZURlc2lnbi92ZXJzaW9ucy8wLjE0LjAvdG9waWNzL2RpYWdub3NhbmRfaGFuZGxlcikuCmBgYHtyIGRpYWdub3NhbmRfdGFibGUsIGVjaG89RkFMU0V9Cm9wdGlvbnMoa25pdHIua2FibGUuTkEgPSAnJykKZ2V0X2RpYWdub3NhbmRzKGRpYWdub3NpczEpICU+JQogIHNsaWNlKDEpICU+JSAKICBnYXRoZXIodmFsdWUgPSAiRXN0aW1hdGUiKSAlPiUgCiAgbXV0YXRlKERlc2NyaXB0aW9uID0gY2FzZV93aGVuKGtleSA9PSAiYmlhcyIgfiAiRXhwZWN0ZWQgZGlmZmVyZW5jZSBiZXR3ZWVuIGVzdGltYXRlIGFuZCBlc3RpbWFuZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2V5ID09ICJybXNlIiB+ICJSb290IG1lYW4gc3F1YXJlZCBlcnJvciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2V5ID09ICJwb3dlciIgfiAiUHJvYmFiaWxpdHkgb2YgcmVqZWN0aW5nIG51bGwgaHlwb3RoZXNpcyBvZiBubyBlZmZlY3QiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtleSA9PSAiY292ZXJhZ2UiIH4gIlByb2JhYmlsaXR5IHRoYXQgY29uZi4gaW50ZXJ2YWwgY29udGFpbnMgZXN0aW1hbmQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtleSA9PSAidHlwZV9zX3JhdGUiIH4gIlByb2JhYmlsaXR5IHRoYXQgYSBzaWduaWZpY2FudCBlc3RpbWF0ZSBoYXMgaW5jb3JyZWN0IHNpZ24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtleSA9PSAibWVhbl9lc3RpbWF0ZSIgfiAiTWVhbiBvZiB0aGUgZXN0aW1hdGVzIiksCiAgICAgICAgIEZvcm11bGEgPSBjYXNlX3doZW4oa2V5ID09ICJiaWFzIiB+ICJtZWFuKGVzdGltYXRlIC0gZXN0aW1hbmQpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrZXkgPT0gInJtc2UiIH4gInNxcnQobWVhbigoZXN0aW1hdGUgLSBlc3RpbWFuZCkgXiAyKSkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtleSA9PSAicG93ZXIiIH4gIm1lYW4ocC52YWx1ZSA8IGFscGhhKSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2V5ID09ICJjb3ZlcmFnZSIgfiAibWVhbihlc3RpbWFuZCA8PSBjb25mLmhpZ2ggJiBlc3RpbWFuZCA+PSBjb25mLmxvdykiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtleSA9PSAidHlwZV9zX3JhdGUiIH4gIm1lYW4oKHNpZ24oZXN0aW1hdGUpICE9IHNpZ24oZXN0aW1hbmQpKVtwLnZhbHVlIDwgYWxwaGFdKSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2V5ID09ICJtZWFuX2VzdGltYXRlIiB+ICJtZWFuKGVzdGltYXRlKSIpKSAlPiUgCiAga2FibGUoKQogIApgYGAKCl9fT1BUSU9OQUwgQVNJREUgLSBXaGF0IGlmIHdlIGRvbid0IHdhbnQgYWxsIHRoZXNlIHN0YXRzIG9yIHdhbnQgdG8gY3JlYXRlIGEgbmV3IHN0YXQ/X18KYGRlY2xhcmVfZGlhZ25vc2FuZHNgICAKCiogV2UgY2FuIGRyb3Agc3RhdHMgd2l0aCB0aGUgYHN1YnRyYWN0YCBhcmd1bWVudAoqIENyZWF0ZSBzdGF0cyBieSBzcGVjaWZ5aW5nIG91dCBvd24gYXJndW1lbnQKKiBPciBrZWVwIHN0YXRzIHdpdGggdGhlIGBzZWxlY3RgIGFyZ3VtZW50CmBgYHtyfQojIGtlZXAgb25seSBiaWFzLCBybXNlLCAmIHR5cGVfc19yYXRlCm15X2RpYWdub3NhbmRzIDwtIGRlY2xhcmVfZGlhZ25vc2FuZHMoc2VsZWN0ID0gYyhiaWFzLCBybXNlLCB0eXBlX3NfcmF0ZSkpCgojIGRyb3AgdHlwZV9zX3JhdGUKbXlfZGlhZ25vc2FuZHMgPC0gZGVjbGFyZV9kaWFnbm9zYW5kcyhzdWJ0cmFjdCA9IHR5cGVfc19yYXRlKQoKIyBZb3UgY2FuIGFkZCB5b3VyIG93biBkaWFnbm9zYW5kcyBpbiBhZGRpdGlvbiB0byBvciBpbnN0ZWFkIG9mIHRoZSBkZWZhdWx0cyBlLmcuLApteV9kaWFnbm9zYW5kcyA8LQogIGRlY2xhcmVfZGlhZ25vc2FuZHMobWVkaWFuX2JpYXMgPSBtZWRpYW4oZXN0aW1hdGUgLSBlc3RpbWFuZCkpCgojIEtlZXAgb25seSB0aGUgc3RhdCB3ZSBkZWZpbmVkCm15X2RpYWdub3NhbmRzIDwtCiAgIGRlY2xhcmVfZGlhZ25vc2FuZHMobWVkaWFuX2JpYXMgPSBtZWRpYW4oZXN0aW1hdGUgLSBlc3RpbWFuZCksCiAgICAgICAgICAgICAgICAgICAgICAga2VlcF9kZWZhdWx0cyA9IEZBTFNFKQpgYGAKClRvIGFwcGx5OgpgYGB7ciBldmFsPVRSVUV9Cm91cl9kZXNpZ24gJT4lIAogIGRpYWdub3NlX2Rlc2lnbihzaW1zID0gbl9zaW1zLCBkaWFnbm9zYW5kcyA9IG15X2RpYWdub3NhbmRzKSAlPiUgCiAgZ2V0X2RpYWdub3NhbmRzKCkgJT4lIAogIGthYmxlKCkKYGBgCgojIyMjIyBUbyBzZWUgdGhlIGByIG5fc2ltc2AgaW5kaXZpZHVhbCBzaW11bGF0aW9ucyB0aGF0IG1hZGUgdGhlIGFnZ3JlZ2F0ZWQgc3VtbWFyeQpgZ2V0X3NpbXVsYXRpb25zYApgYGB7ciBpbmRpdmlkdWFsX3NpbXVsYXRpb25zfQpkaWFnbm9zaXMxICU+JSAKICBnZXRfc2ltdWxhdGlvbnMoKSAlPiUKICBkYXRhdGFibGUoKQpgYGAKCmBnZXRfc2ltdWxhdGlvbnNgIGFsc28gaGFzIG5pY2UgcHJvcGVydGllcyBmb3IgcGxvdHRpbmcgZS5nLiwgCgpgYGB7ciBncmFwaH0KZ2V0X3NpbXVsYXRpb25zKGRpYWdub3NpczEpICU+JSAKICBnZ3Bsb3QoYWVzKGVzdGltYXRlKSkgKyAKICBnZW9tX2RlbnNpdHkoKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYXRlLCBjb2wgPSAicmVkIikgKwogIGxhYnModGl0bGUgPSAiRGVuc2l0eSBvZiBFZmZlY3QgU2l6ZSBFc3RpbWF0ZXMiLAogICAgICAgc3VidGl0bGUgPSAiUmVhbCBBVEUgc2hvd24gaW4gUmVkIikKYGBgCgojIyMgQ2hhbmdlIHlvdXIgYXNzdW1wdGlvbnMKCllvdSBjYW4gdGVzdCBkaWZmZXJlbnQgYXNzdW1wdGlvbnMgZnJvbSB5b3VyIHlvdXIgYERlY2xhcmVEZXNpZ25gIGRlc2lnbiB1c2luZyBgcmVkZXNpZ25gIHRoZSBmdW5jdGlvbi4gX19gcmVkZXNpZ25gIHRha2VzIHRoZSAqZ2xvYmFsIHZhbHVlcyogeW91IGFyZSB1c2luZyB3aXRoaW4gdGhlIGZ1bmN0aW9uIGFuZCBnaXZlcyB0aGVtIG5ldyB2YWx1ZXNfXyBUaGUgZmlyc3QgYXJndW1lbnQgaXMgeW91ciBkZXNpZ24sIHRoZSBzZWNvbmQgYXJlIHRoZSBuZXcgYXNzdW1wdGlvbnMuIEFsc28gbm90ZSB0aGF0IF9faXQgbWFrZXMgc2Vuc2UgaW4gbW9zdCBjYXNlcyB0byBwaXBlIHRoaXMgZnVuY3Rpb24gaW50byBgZGlhZ25vc2VfZGVzaWduYCBvciBgZ2V0X3NpbXVsYXRpb25zYF9fLiBIZXJlIEkgZXhwZXJpbWVudCB3aXRoIGNoYW5naW5nIHRoZSBzYW1wbGUgc2l6ZToKYGBge3J9CmNoYW5nZV90aGVfcGFyYW1ldGVycyA8LSAKICBvdXJfZGVzaWduICU+JSAKICAgcmVkZXNpZ24oTiA9IGxpc3QoMzAsIDUwLCA3NSwgMTAwKSwgIyBub3RlIHRoYXQgSSBkZWZpbmUgTiBhcyBhIHZhcmlhYmxlIGluIHRoZSBmaXJzdCBjaHVuayBpbiB0aGlzIGRvY3VtZW50CiAgICAgICAgICAgIGF0ZSA9IGxpc3QoMSwgMiwgMywgNCkpICU+JSAjIHdoYXQgaWYgdGhlIEFURSBpcyBsb3dlciB0aGFuIEkgb3JpZ2luYWxseSBleHBlY3RlZD8KICAgZGlhZ25vc2VfZGVzaWduKHNpbXMgPSBuX3NpbXMpICMgbm90ZSB0aGlzIGRvZXMgc2ltcyBmb3IgZWFjaCBvZiBjb21iaW5hdGlvbiBvZiBOJ3MgYW5kIGF0ZSdzCgoKY2hhbmdlX3RoZV9wYXJhbWV0ZXJzICU+JSAKICBnZXRfZGlhZ25vc2FuZHMoKSAlPiUgCiAga2FibGUoKQpgYGAKCl9fT1BUSU9OQUwgQVNJREUgLV9fIFdoeSB1c2UgYGxpc3QoKWAgaW4gcmVkZXNpZ24gaW5zdGVhZCBvZiBgYygpYD8KCkdvb2QgcHJhY3RpY2UgaW4gRGVjbGFyZURlc2lnbiBpcyB0byB1c2UgYGxpc3QoKWAgaW4gYHJlZGVzaWduYCBhbmQgaXQncyBzaXN0ZXIgZnVuY3Rpb24gYGV4cGFuZF9kZXNpZ25gIGluc3RlYWQgb2YgYGMoKWAuIFRoZSBkaXN0aW5jdGlvbiBpcyBzdWJ0bGUsIGJ1dCB0aGUgcmVhc29uIHdoeSBpcyB0aGVyZSBhcmUgc29tZSBjYXNlcyB3aGVyZSB3ZSB3b3VsZCB3YW50IGEgdG8gdXNlIGEgdmVjdG9yIHdpdGhpbiBvdXIgZGVzaWduIFt0aGluayBgbGlzdChjKCJBIiwgIkIiLCAiQyIpKWAgdnMgYGMoYygiQSIsICJCIi4gIkMiKSlgXSBhbmQgYSBub3JtYWwgdmVjdG9yIHdvbid0IGN1dCBpdC4gVXNpbmcgYGMoKWAgd29uJ3QgY2F1c2UgcHJvYmxlbXMgaW4gbW9zdCBjYXNlcywgYnV0IHRoaXMgaXMgYW4gZWRnZSBjYXNlIHRvIGJlIGF3YXJlIG9mLiAgCgoKCmBgYHtyfQpnZXRfZGlhZ25vc2FuZHMoY2hhbmdlX3RoZV9wYXJhbWV0ZXJzKSAlPiUKICBtdXRhdGUoTiA9IGZhY3RvcihOKSwKICAgICAgICAgYXRlID0gZmFjdG9yKGF0ZSkpICU+JSAKICBnZ3Bsb3QoYWVzKE4sIHBvd2VyLCBmaWxsID0gYXRlKSkgKwogIGdlb21fYmFyKHBvc2l0aW9uID0gImRvZGdlIiwgc3RhdCA9ICJpZGVudGl0eSIpICsKICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluID0gcG93ZXIgLSAxLjk2KmBzZShwb3dlcilgLCAKICAgICAgICAgICAgICAgICAgICB5bWF4ID0gcG93ZXIgKyAxLjk2KmBzZShwb3dlcilgLAogICAgICAgICAgICAgICAgICAgIHdpZHRoID0gLjMpLAogICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IC45KSkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAuOCkgKwogIGxhYnModGl0bGUgPSAiUG93ZXIgYXQgZWFjaCBOIGFuZCBhdGUiLAogICAgICAgc3VidGl0bGUgPSAiOTUlIENvbmZpZGVuY2UgSW50ZXJ2YWxzIikKYGBgCk5vdGljZSBob3cgaWYgbXkgb3JpZ2luYWwgZXN0aW1hdGUgb2YgY29mZmVlIG9uIG51bWJlciBvZiB3aWRnZXRzIHdhcyBhIGxpdHRsZSB0b28gaGlnaCwgb3IgdGhlcmUgd2VyZSBzb21lIHdvcmtlcnMgaW4gbXkgZmFjdG9yeSB3aG8gZGlkbid0IHNob3cgdXAgbXkgZXhwZXJpbWVudCBsaWtlbHkgd291bGRuJ3Qgd29yayEgVGhpcyBjb3VsZCBiZSBodWdlIQo=