Preamble

The goal of this notebook is to bring together resources on the rstanarm R package, which provides an interface between the R programming environment and the Stan probabilistic programming language.

The creators of rstanarm say the goal of the package is to,

make Bayesian estimation routine for the most common regression models that applied researchers use. This will enable researchers to avoid the counter-intuitiveness of the frequentist approach to probability and statistics with only minimal changes to their existing R scripts.

If you are already fitting models using lm() or glm() form the stats package or using the mixed effects versions lmer() and glmer() from lme4, then it will be easy to translate those models to a Bayesian framework to get the Bayesian benefits. To do so, you:

A great place to get started is the CRAN rstanarm page, which has a ton of helpful vignettes. This document is my attempt to pull together pieces of information that I found helpful. In it, we will:

Set up

Clear the workspace and set some global options for the notebook.

Load packages and set plotting aesthetics.

Loading required package: Rcpp
rstanarm (Version 2.15.3, packaged: 2017-04-29 06:18:44 UTC)
- Do not expect the default priors to remain the same in future rstanarm versions.
Thus, R scripts should specify priors explicitly, even if they are just the defaults.
- For execution on a local, multicore CPU with excess RAM we recommend calling
options(mc.cores = parallel::detectCores())
Loading required package: Matrix
Loading tidyverse: ggplot2
Loading tidyverse: tibble
Loading tidyverse: tidyr
Loading tidyverse: readr
Loading tidyverse: purrr
Loading tidyverse: dplyr
Conflicts with tidy packages --------------------------------------------------------------------------
expand(): tidyr, Matrix
filter(): dplyr, stats
lag():    dplyr, stats

Attaching package: ‘magrittr’

The following object is masked from ‘package:purrr’:

    set_names

The following object is masked from ‘package:tidyr’:

    extract

A lot of the code in this tutorial is inspired by a blogpost from Tristan Mahr where he models the effect of sleep deprivation on Reaction Time using the sleepstudy dataset. The post is great! And it’s a really nice example of how to use visualization to understand what’s going on in a data analysis model.

Here is some backgound information on the dataset:

The average reaction time per day for subjects in a sleep deprivation study. On day 0 the subjects had their normal amount of sleep. Starting that night they were restricted to 3 hours of sleep per night. The observations represent the average reaction time on a series of tests given each day to each subject.

Load the data and look at the structure.

Observations: 180
Variables: 3
$ Reaction <dbl> 249.5600, 258.7047, 250.8006, 321.4398, 356.8519, 414.6901, 382.2038, 290.1486, 4...
$ Days     <dbl> 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, ...
$ Subject  <fctr> 308, 308, 308, 308, 308, 308, 308, 308, 308, 308, 309, 309, 309, 309, 309, 309, ...

Let’s get a sense of the variability due to random effects by plotting the relationship between days of sleep deprivation and Reaction Time for each participant.

We can also summarize these data in table by computing the mean and standard deviation for each day. These summary statistics will also be used as parameters in our simulated dataset.

Days m stdev
0 256.65 32.13
1 264.50 33.43
2 265.36 29.47
3 282.99 38.86
4 288.65 42.54
5 308.52 51.77
6 312.18 63.17
7 318.75 50.10
8 336.63 60.20
9 350.85 66.99

Simulation

To help us understand the models in the RStanArm package, let’s write a few functions to simulate these data. Note the repeated measures structure: that we have multiple measures for each participant that come from different days. Participants could vary in their baseline RTs and they could also vary in how they respond to sleep deprivation, so we want to build this into our simulation.

Next, let’s write a function to generate model parameters for each participant. Note that the user can control:

Test our simulate_participant() function with no added noise and the same age effect as in the original dataset.

Now that we can simulate the data for a single participant, let’s simulate the entire experiment.

Plot the simulated data by participant with regression lines fit to each participants’ data.

Fit a complete pooling that doesn’t know that our measurements come from different participants.


Call:
lm(formula = RT ~ day, data = d)

Residuals:
    Min      1Q  Median      3Q     Max 
-155.24  -56.75  -14.16   16.20  591.62 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  246.441     13.464  18.304  < 2e-16 ***
day           12.088      2.522   4.793 3.22e-06 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 102.4 on 198 degrees of freedom
Multiple R-squared:  0.104, Adjusted R-squared:  0.09944 
F-statistic: 22.97 on 1 and 198 DF,  p-value: 3.218e-06

Visualize variability by participant

Fit mixed effect model allowing for each participant to have a different intercept and slope.

Linear mixed model fit by REML ['lmerMod']
Formula: RT ~ 1 + day + (1 + day | id)
   Data: d

REML criterion at convergence: 2407.8

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-1.5153 -0.5539 -0.1383  0.1581  5.7750 

Random effects:
 Groups   Name        Variance  Std.Dev.  Corr
 id       (Intercept) 0.000e+00 0.000e+00     
          day         2.610e-15 5.109e-08  NaN
 Residual             1.049e+04 1.024e+02     
Number of obs: 200, groups:  id, 20

Fixed effects:
            Estimate Std. Error t value
(Intercept)  246.441     13.464  18.304
day           12.088      2.522   4.793

Correlation of Fixed Effects:
    (Intr)
day -0.843

We can plot the model outpout for each participant alongside their data.

It looks like when we increase the level of noise for each participant, or between-participants variability, we get different inferences from lm vs. lmer(). In the complete pooling model the slope parameter is sig, but in the mixed-effects model it is not.

Fit Bayesian Mixed Effects model using RStanArm

Set the number of cores to the number of cores on your computer.

Fit the varying intercepts and slopes model.

starting worker pid=608 on localhost:11919 at 12:08:07.334
starting worker pid=616 on localhost:11919 at 12:08:07.613

SAMPLING FOR MODEL 'continuous' NOW (CHAIN 1).

Gradient evaluation took 0.000734 seconds
1000 transitions using 10 leapfrog steps per transition would take 7.34 seconds.
Adjust your expectations accordingly!


Iteration:    1 / 2000 [  0%]  (Warmup)

SAMPLING FOR MODEL 'continuous' NOW (CHAIN 2).

Gradient evaluation took 0.000307 seconds
1000 transitions using 10 leapfrog steps per transition would take 3.07 seconds.
Adjust your expectations accordingly!


Iteration:    1 / 2000 [  0%]  (Warmup)
Iteration:  200 / 2000 [ 10%]  (Warmup)
Iteration:  400 / 2000 [ 20%]  (Warmup)
Iteration:  600 / 2000 [ 30%]  (Warmup)
Iteration:  800 / 2000 [ 40%]  (Warmup)
Iteration:  200 / 2000 [ 10%]  (Warmup)
Iteration: 1000 / 2000 [ 50%]  (Warmup)
Iteration: 1001 / 2000 [ 50%]  (Sampling)
Iteration: 1200 / 2000 [ 60%]  (Sampling)
Iteration:  400 / 2000 [ 20%]  (Warmup)
Iteration: 1400 / 2000 [ 70%]  (Sampling)
Iteration:  600 / 2000 [ 30%]  (Warmup)
Iteration: 1600 / 2000 [ 80%]  (Sampling)
Iteration: 1800 / 2000 [ 90%]  (Sampling)
Iteration:  800 / 2000 [ 40%]  (Warmup)
Iteration: 2000 / 2000 [100%]  (Sampling)

 Elapsed Time: 10.8088 seconds (Warm-up)
               3.52982 seconds (Sampling)
               14.3386 seconds (Total)

Iteration: 1000 / 2000 [ 50%]  (Warmup)
Iteration: 1001 / 2000 [ 50%]  (Sampling)
Iteration: 1200 / 2000 [ 60%]  (Sampling)
Iteration: 1400 / 2000 [ 70%]  (Sampling)
Iteration: 1600 / 2000 [ 80%]  (Sampling)
Iteration: 1800 / 2000 [ 90%]  (Sampling)
Iteration: 2000 / 2000 [100%]  (Sampling)

 Elapsed Time: 15.1694 seconds (Warm-up)
               5.29238 seconds (Sampling)
               20.4618 seconds (Total)

We can use the default plot function in R directly on our fitted model to visualize the posterior interval over various parameters in the model.

Under the hood, the plot method is using functions from the bayesplot library. There are a lot of other visualizations of the posterior distributions that you can make using this library, and the nice thing is that all of the functions return ggplot objects!

For more information on what you can do with the bayesplot library, see the manual and this nice vignette.

This is bayesplot version 1.2.0

We can also create the same interval plot from before.

Scale for 'x' is already present. Adding another scale for 'x', which will replace the existing
scale.

Or if you want to make a density plot.

The bayesplot and default plots are nice, but if you want more flexibility, you can sample from samples from the posterior distributions over the slope and intercept parameters. This first visualization is a countour plot using code from Tristan Mahr’s lovely blogpost.

Let’s first extract the samples from the model obect.

Now make the contour plot, showing a set of plausible values for the intercept and slope parameters.

Diagnostics and plots using Shiny Stan

A few things to look at in Shiny Stan:

Inspecting Priors

It’s always a good idea to check the prior distribution over the parameters in your model to see what kinds of values are generated and confirm that our prior information produces sensible model behavior.

We can use the prior_summary() function to get information about the priors and adjustments used in the model.

Priors for model 'm_bglmer' 
------
Intercept (after predictors centered)
 ~ normal(location = 0, scale = 5)
     **adjusted scale = 539.76

Coefficients
 ~ normal(location = 0, scale = 2)
     **adjusted scale = 74.98

Auxiliary (sigma)
 ~ half-cauchy(location = 0, scale = 5)
     **adjusted scale = 539.76

Covariance
 ~ decov(reg. = 2, conc. = 1, shape = 1, scale = 1)
------
See help('prior_summary.stanreg') for more details

rstanarm comes with a built-in function for visualizing “belief change” after seeing the data.


Drawing from prior...
starting worker pid=642 on localhost:11919 at 12:08:42.835
starting worker pid=650 on localhost:11919 at 12:08:43.079

Gradient evaluation took 0.000354 seconds
1000 transitions using 10 leapfrog steps per transition would take 3.54 seconds.
Adjust your expectations accordingly!



Gradient evaluation took 0.000375 seconds
1000 transitions using 10 leapfrog steps per transition would take 3.75 seconds.
Adjust your expectations accordingly!



 Elapsed Time: 5.16904 seconds (Warm-up)
               3.61552 seconds (Sampling)
               8.78456 seconds (Total)


 Elapsed Time: 5.3337 seconds (Warm-up)
               3.65644 seconds (Sampling)
               8.99013 seconds (Total)

But we can also sample from the prior directly using: prior_PD = TRUE.

starting worker pid=665 on localhost:11919 at 12:08:59.739
starting worker pid=673 on localhost:11919 at 12:08:59.955

Model Info:

 function:  stan_glmer
 family:    gaussian [identity]
 formula:   RT ~ day + (day | id)
 algorithm: sampling
 priors:    see help('prior_summary')
 sample:    2000 (posterior sample size)
 num obs:   200
 groups:    id (20)

Estimates:
              mean   sd     10%    50%    90% 
(Intercept)   -4.4  627.9 -796.5   -5.8  811.6
day           -1.5   75.5 -100.8   -3.1   96.9

Diagnostics:
            mcse Rhat n_eff
(Intercept) 14.0  1.0 2000 
day          1.7  1.0 2000 

For each parameter, mcse is Monte Carlo standard error, n_eff is a crude measure of effective sample size, and Rhat is the potential scale reduction factor on split chains (at convergence Rhat=1).

We can see that our initial prior of normal(0, 2) for the effect of sleep deprivation is centered around zero and thinks that an increase of +/- 76.17 milliseconds per day is reasonable. This seems sensible to me, but if you had more information about what you expect the range of effects to be, you could build this into the prior.

Let’s simulate the same model with a “wider” prior.

starting worker pid=688 on localhost:11919 at 12:09:16.065
starting worker pid=696 on localhost:11919 at 12:09:16.327

SAMPLING FOR MODEL 'continuous' NOW (CHAIN 1).

Gradient evaluation took 0.000314 seconds
1000 transitions using 10 leapfrog steps per transition would take 3.14 seconds.
Adjust your expectations accordingly!


Iteration:    1 / 2000 [  0%]  (Warmup)

SAMPLING FOR MODEL 'continuous' NOW (CHAIN 2).

Gradient evaluation took 0.000277 seconds
1000 transitions using 10 leapfrog steps per transition would take 2.77 seconds.
Adjust your expectations accordingly!


Iteration:    1 / 2000 [  0%]  (Warmup)
Iteration:  200 / 2000 [ 10%]  (Warmup)
Iteration:  200 / 2000 [ 10%]  (Warmup)
Iteration:  400 / 2000 [ 20%]  (Warmup)
Iteration:  400 / 2000 [ 20%]  (Warmup)
Iteration:  600 / 2000 [ 30%]  (Warmup)
Iteration:  600 / 2000 [ 30%]  (Warmup)
Iteration:  800 / 2000 [ 40%]  (Warmup)
Iteration:  800 / 2000 [ 40%]  (Warmup)
Iteration: 1000 / 2000 [ 50%]  (Warmup)
Iteration: 1001 / 2000 [ 50%]  (Sampling)
Iteration: 1000 / 2000 [ 50%]  (Warmup)
Iteration: 1001 / 2000 [ 50%]  (Sampling)
Iteration: 1200 / 2000 [ 60%]  (Sampling)
Iteration: 1200 / 2000 [ 60%]  (Sampling)
Iteration: 1400 / 2000 [ 70%]  (Sampling)
Iteration: 1400 / 2000 [ 70%]  (Sampling)
Iteration: 1600 / 2000 [ 80%]  (Sampling)
Iteration: 1600 / 2000 [ 80%]  (Sampling)
Iteration: 1800 / 2000 [ 90%]  (Sampling)
Iteration: 1800 / 2000 [ 90%]  (Sampling)
Iteration: 2000 / 2000 [100%]  (Sampling)

 Elapsed Time: 5.28373 seconds (Warm-up)
               3.50108 seconds (Sampling)
               8.78481 seconds (Total)

Iteration: 2000 / 2000 [100%]  (Sampling)

 Elapsed Time: 5.0033 seconds (Warm-up)
               3.3543 seconds (Sampling)
               8.35759 seconds (Total)


Model Info:

 function:  stan_glmer
 family:    gaussian [identity]
 formula:   RT ~ day + (day | id)
 algorithm: sampling
 priors:    see help('prior_summary')
 sample:    2000 (posterior sample size)
 num obs:   200
 groups:    id (20)

Estimates:
              mean    sd      10%     50%     90%  
(Intercept)   -16.6  1691.4 -2129.1   -12.9  2094.3
day             2.8   361.1  -458.6     2.7   464.6

Diagnostics:
            mcse Rhat n_eff
(Intercept) 37.8  1.0 2000 
day          8.1  1.0 2000 

For each parameter, mcse is Monte Carlo standard error, n_eff is a crude measure of effective sample size, and Rhat is the potential scale reduction factor on split chains (at convergence Rhat=1).

Now we can see that the model considers values +/- 150 ms per day to be reasonable (within 1 sd), which is probably too broad.

A note on priors from the developers of rstanarm (priors vignette):

With very few exceptions, the default priors in rstanarm —the priors used if the arguments in the tables above are untouched— are not flat priors. Rather, the defaults are intended to be weakly informative. That is, they are designed to provide moderate regularization and help stabilize computation. For many (if not most) applications the defaults will perform well, but this is not guaranteed (there are no default priors that make sense for every possible model specification).

Because the scaling is based on the scales of the predictors (and possibly the outcome) these are technically data-dependent priors. However, since these priors are quite wide (and in most cases rather conservative), the amount of information used is weak and mainly takes into account the order of magnitude of the variables. This enables rstanarm to offer defaults that are reasonable for many models.

To disable automatic rescaling simply set the autoscale argument to to FALSE. For example:

starting worker pid=713 on localhost:11919 at 12:09:31.836
starting worker pid=721 on localhost:11919 at 12:09:32.074

SAMPLING FOR MODEL 'continuous' NOW (CHAIN 1).

Gradient evaluation took 0.0003 seconds
1000 transitions using 10 leapfrog steps per transition would take 3 seconds.
Adjust your expectations accordingly!


Iteration:    1 / 2000 [  0%]  (Warmup)

SAMPLING FOR MODEL 'continuous' NOW (CHAIN 2).

Gradient evaluation took 0.000424 seconds
1000 transitions using 10 leapfrog steps per transition would take 4.24 seconds.
Adjust your expectations accordingly!


Iteration:    1 / 2000 [  0%]  (Warmup)
Iteration:  200 / 2000 [ 10%]  (Warmup)
Iteration:  200 / 2000 [ 10%]  (Warmup)
Iteration:  400 / 2000 [ 20%]  (Warmup)
Iteration:  400 / 2000 [ 20%]  (Warmup)
Iteration:  600 / 2000 [ 30%]  (Warmup)
Iteration:  600 / 2000 [ 30%]  (Warmup)
Iteration:  800 / 2000 [ 40%]  (Warmup)
Iteration: 1000 / 2000 [ 50%]  (Warmup)
Iteration: 1001 / 2000 [ 50%]  (Sampling)
Iteration:  800 / 2000 [ 40%]  (Warmup)
Iteration: 1200 / 2000 [ 60%]  (Sampling)
Iteration: 1000 / 2000 [ 50%]  (Warmup)
Iteration: 1001 / 2000 [ 50%]  (Sampling)
Iteration: 1400 / 2000 [ 70%]  (Sampling)
Iteration: 1200 / 2000 [ 60%]  (Sampling)
Iteration: 1600 / 2000 [ 80%]  (Sampling)
Iteration: 1400 / 2000 [ 70%]  (Sampling)
Iteration: 1800 / 2000 [ 90%]  (Sampling)
Iteration: 1600 / 2000 [ 80%]  (Sampling)
Iteration: 2000 / 2000 [100%]  (Sampling)

 Elapsed Time: 3.30799 seconds (Warm-up)
               3.13123 seconds (Sampling)
               6.43922 seconds (Total)

Iteration: 1800 / 2000 [ 90%]  (Sampling)
Iteration: 2000 / 2000 [100%]  (Sampling)

 Elapsed Time: 3.61395 seconds (Warm-up)
               3.20448 seconds (Sampling)
               6.81843 seconds (Total)
Priors for model 'test_no_autoscale' 
------
Intercept (after predictors centered)
 ~ student_t(df = 4, location = 0, scale = 10)

Coefficients
 ~ normal(location = 0, scale = 5)

Auxiliary (sigma)
 ~ exponential(rate = 0.1)

Covariance
 ~ decov(reg. = 2, conc. = 1, shape = 1, scale = 1)
------
See help('prior_summary.stanreg') for more details

But the rstanarm developers point out that:

Disabling prior scale adjustments is usually unnecessary but is useful for when more informative prior information is available. There is an example of specifying an informative prior later in this vignette.

LS0tCnRpdGxlOiAiTGFuZ0NvZyBSU3RhbkFybSBUdXRvcmlhbCIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6IGRlZmF1bHQKICBodG1sX25vdGVib29rOiBkZWZhdWx0CmVkaXRvcl9vcHRpb25zOgogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUKLS0tCgojIyBQcmVhbWJsZQoKVGhlIGdvYWwgb2YgdGhpcyBub3RlYm9vayBpcyB0byBicmluZyB0b2dldGhlciByZXNvdXJjZXMgb24gdGhlICpyc3RhbmFybSogUiBwYWNrYWdlLCB3aGljaCBwcm92aWRlcyBhbiBpbnRlcmZhY2UgYmV0d2VlbiB0aGUgUiBwcm9ncmFtbWluZyBlbnZpcm9ubWVudCBhbmQgdGhlIFN0YW4gcHJvYmFiaWxpc3RpYyBwcm9ncmFtbWluZyBsYW5ndWFnZS4gCgpUaGUgY3JlYXRvcnMgb2YgKnJzdGFuYXJtKiBzYXkgdGhlIGdvYWwgb2YgdGhlIHBhY2thZ2UgaXMgdG8sCgo+IG1ha2UgQmF5ZXNpYW4gZXN0aW1hdGlvbiByb3V0aW5lIGZvciB0aGUgbW9zdCBjb21tb24gcmVncmVzc2lvbiBtb2RlbHMgdGhhdCBhcHBsaWVkIHJlc2VhcmNoZXJzIHVzZS4gVGhpcyB3aWxsIGVuYWJsZSByZXNlYXJjaGVycyB0byBhdm9pZCB0aGUgY291bnRlci1pbnR1aXRpdmVuZXNzIG9mIHRoZSBmcmVxdWVudGlzdCBhcHByb2FjaCB0byBwcm9iYWJpbGl0eSBhbmQgc3RhdGlzdGljcyB3aXRoIG9ubHkgbWluaW1hbCBjaGFuZ2VzIHRvIHRoZWlyIGV4aXN0aW5nIFIgc2NyaXB0cy4KCklmIHlvdSBhcmUgYWxyZWFkeSBmaXR0aW5nIG1vZGVscyB1c2luZyBsbSgpIG9yIGdsbSgpIGZvcm0gdGhlICpzdGF0cyogcGFja2FnZSBvciB1c2luZyB0aGUgbWl4ZWQgZWZmZWN0cyB2ZXJzaW9ucyBsbWVyKCkgYW5kIGdsbWVyKCkgZnJvbSAqbG1lNCosIHRoZW4gaXQgd2lsbCBiZSBlYXN5IHRvIHRyYW5zbGF0ZSB0aG9zZSBtb2RlbHMgdG8gYSBCYXllc2lhbiBmcmFtZXdvcmsgdG8gZ2V0IHRoZSBCYXllc2lhbiBiZW5lZml0cy4gVG8gZG8gc28sIHlvdToKCiogYWRkIGBzdGFuX2AgdG8geW91ciBtb2RlbHMKKiBzcGVjaWZ5IGEgcHJpb3IgZGlzdHJpYnV0aW9uIChvciB1c2UgdGhlIGRlZmF1bHQsIHdlYWtseSBpbmZvcm1hdGl2ZSBwcmlvcnMpCiogbGVhcm4gaG93IHRvICJpbnNwZWN0IiB0aGUgcG9zdGVyaW9yIGRpc3RyaWJ1dGlvbiBhbmQgcmVwb3J0IHRoZSByZXN1bHRzCgpBIGdyZWF0IHBsYWNlIHRvIGdldCBzdGFydGVkIGlzIHRoZSBDUkFOICpyc3RhbmFybSogW3BhZ2VdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9yc3RhbmFybS9pbmRleC5odG1sKSwgd2hpY2ggaGFzIGEgdG9uIG9mIGhlbHBmdWwgdmlnbmV0dGVzLiBUaGlzIGRvY3VtZW50IGlzIG15IGF0dGVtcHQgdG8gcHVsbCB0b2dldGhlciBwaWVjZXMgb2YgaW5mb3JtYXRpb24gdGhhdCBJIGZvdW5kIGhlbHBmdWwuIEluIGl0LCB3ZSB3aWxsOgoKICAqIEZpdCBkaWZmZXJlbnQga2luZHMgb2YgbGluZWFyIG1vZGVscyB0byBhIHNpbXVsYXRlZCBkYXRhc2V0OiBNTEUsIExNTSwgYW5kIEJheWVzaWFuIExNTQogICogTGVhcm4gaG93IHRvIGV4dHJhY3QgcG9zdGVyaW9yIHNhbXBsZXMgZnJvbSBhIGZpdHRlZCBtb2RlbCBvYmplY3QgCiAgKiBTZWUgYSBzZXQgb2YgdG9vbHMgZm9yIHZpc3VhbGl6aW5nIGRpc3RyaWJ1dGlvbnMgKGJvdGggcHJpb3JzIGFuZCBwb3N0ZXJpb3JzKSBpbiBhIEJheWVzaWFuIGFuYWx5c2lzCgojIyBTZXQgdXAgCgpDbGVhciB0aGUgd29ya3NwYWNlIGFuZCBzZXQgc29tZSBnbG9iYWwgb3B0aW9ucyBmb3IgdGhlIG5vdGVib29rLgoKYGBge3J9CnJtKGxpc3Q9bHMoKSkKa25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG89VCwgd2FybmluZz1GLCBjYWNoZT1ULCBtZXNzYWdlPUYpCmBgYAoKTG9hZCBwYWNrYWdlcyBhbmQgc2V0IHBsb3R0aW5nIGFlc3RoZXRpY3MuIAoKYGBge3J9CmxpYnJhcnkocnN0YW5hcm0pCmxpYnJhcnkobG1lNCkKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoYnJvb20pCmxpYnJhcnkobWFncml0dHIpCnRoZW1lX3NldChnZ3RoZW1lczo6dGhlbWVfZmV3KCkpCmBgYAoKQSBsb3Qgb2YgdGhlIGNvZGUgaW4gdGhpcyB0dXRvcmlhbCBpcyBpbnNwaXJlZCBieSBhIFtibG9ncG9zdF0oaHR0cHM6Ly90am1haHIuZ2l0aHViLmlvL3Bsb3R0aW5nLXBhcnRpYWwtcG9vbGluZy1pbi1taXhlZC1lZmZlY3RzLW1vZGVscy8pIGZyb20gVHJpc3RhbiBNYWhyIHdoZXJlIGhlIG1vZGVscyB0aGUgZWZmZWN0IG9mIHNsZWVwIGRlcHJpdmF0aW9uIG9uIFJlYWN0aW9uIFRpbWUgdXNpbmcgdGhlIGBzbGVlcHN0dWR5YCBkYXRhc2V0LiBUaGUgcG9zdCBpcyBncmVhdCEgQW5kIGl0J3MgYSByZWFsbHkgbmljZSBleGFtcGxlIG9mIGhvdyB0byB1c2UgdmlzdWFsaXphdGlvbiB0byB1bmRlcnN0YW5kIHdoYXQncyBnb2luZyBvbiBpbiBhIGRhdGEgYW5hbHlzaXMgbW9kZWwuIAoKSGVyZSBpcyBzb21lIGJhY2tnb3VuZCBpbmZvcm1hdGlvbiBvbiB0aGUgZGF0YXNldDoKCj4gVGhlIGF2ZXJhZ2UgcmVhY3Rpb24gdGltZSBwZXIgZGF5IGZvciBzdWJqZWN0cyBpbiBhIHNsZWVwIGRlcHJpdmF0aW9uIHN0dWR5LiBPbiBkYXkgMCB0aGUgc3ViamVjdHMgaGFkIHRoZWlyIG5vcm1hbCBhbW91bnQgb2Ygc2xlZXAuIFN0YXJ0aW5nIHRoYXQgbmlnaHQgdGhleSB3ZXJlIHJlc3RyaWN0ZWQgdG8gMyBob3VycyBvZiBzbGVlcCBwZXIgbmlnaHQuIFRoZSBvYnNlcnZhdGlvbnMgcmVwcmVzZW50IHRoZSBhdmVyYWdlIHJlYWN0aW9uIHRpbWUgb24gYSBzZXJpZXMgb2YgdGVzdHMgZ2l2ZW4gZWFjaCBkYXkgdG8gZWFjaCBzdWJqZWN0LgoKTG9hZCB0aGUgZGF0YSBhbmQgbG9vayBhdCB0aGUgc3RydWN0dXJlLgoKYGBge3J9CmQub3JpZyA8LSBzbGVlcHN0dWR5CmdsaW1wc2UoZC5vcmlnKQpgYGAKCkxldCdzIGdldCBhIHNlbnNlIG9mIHRoZSB2YXJpYWJpbGl0eSBkdWUgdG8gcmFuZG9tIGVmZmVjdHMgYnkgcGxvdHRpbmcgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGRheXMgb2Ygc2xlZXAgZGVwcml2YXRpb24gYW5kIFJlYWN0aW9uIFRpbWUgZm9yIGVhY2ggcGFydGljaXBhbnQuIAoKYGBge3J9CnhsYWIgPC0gIkRheXMgb2Ygc2xlZXAgZGVwcml2YXRpb24iCnlsYWIgPC0gIkF2ZXJhZ2UgcmVhY3Rpb24gdGltZSAobXMpIgoKZ2dwbG90KGQub3JpZykgKyAKICBhZXMoeCA9IERheXMsIHkgPSBSZWFjdGlvbikgKyAKICBzdGF0X3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFKSArCiAgZ2VvbV9wb2ludCgpICsKICBmYWNldF93cmFwKCJTdWJqZWN0IikgKwogIGxhYnMoeCA9IHhsYWIsIHkgPSB5bGFiKSArIAogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSAwOjQgKiAyKQpgYGAKCldlIGNhbiBhbHNvIHN1bW1hcml6ZSB0aGVzZSBkYXRhIGluIHRhYmxlIGJ5IGNvbXB1dGluZyB0aGUgbWVhbiBhbmQgc3RhbmRhcmQgZGV2aWF0aW9uIGZvciBlYWNoIGRheS4gVGhlc2Ugc3VtbWFyeSBzdGF0aXN0aWNzIHdpbGwgYWxzbyBiZSB1c2VkIGFzIHBhcmFtZXRlcnMgaW4gb3VyIHNpbXVsYXRlZCBkYXRhc2V0LiAKCmBgYHtyfQptcyA8LSBkLm9yaWcgJT4lIAogIGdyb3VwX2J5KERheXMpICU+JSAKICBzdW1tYXJpc2UobSA9IG1lYW4oUmVhY3Rpb24pLAogICAgICAgICAgICBzdGRldiA9IHNkKFJlYWN0aW9uKSkgJT4lIAogIG11dGF0ZV9hbGwocm91bmQsIGRpZ2l0cyA9IDIpICU+JSAKICBtdXRhdGUoRGF5cyA9IGFzLmNoYXJhY3RlcihEYXlzKSkKCm1zICU+JSBrbml0cjo6a2FibGUoKQpgYGAKCiMjIFNpbXVsYXRpb24KClRvIGhlbHAgdXMgdW5kZXJzdGFuZCB0aGUgbW9kZWxzIGluIHRoZSBSU3RhbkFybSBwYWNrYWdlLCBsZXQncyB3cml0ZSBhIGZldyBmdW5jdGlvbnMgdG8gc2ltdWxhdGUgdGhlc2UgZGF0YS4gTm90ZSB0aGUgcmVwZWF0ZWQgbWVhc3VyZXMgc3RydWN0dXJlOiB0aGF0IHdlIGhhdmUgbXVsdGlwbGUgbWVhc3VyZXMgZm9yIGVhY2ggcGFydGljaXBhbnQgdGhhdCBjb21lIGZyb20gZGlmZmVyZW50IGRheXMuIFBhcnRpY2lwYW50cyBjb3VsZCB2YXJ5IGluIHRoZWlyIGJhc2VsaW5lIFJUcyBhbmQgdGhleSBjb3VsZCBhbHNvIHZhcnkgaW4gaG93IHRoZXkgcmVzcG9uZCB0byBzbGVlcCBkZXByaXZhdGlvbiwgc28gd2Ugd2FudCB0byBidWlsZCB0aGlzIGludG8gb3VyIHNpbXVsYXRpb24uCgoKYGBge3J9CnNpbXVsYXRlX3BhcnRpY2lwYW50IDwtIGZ1bmN0aW9uKGRheXNfZGVwcml2YXRpb24sIHNzX25vaXNlID0gMCwgaWQsIGxvY2F0aW9uX3NoaWZ0ID0gMCkgewogIGRheV90aWJibGUgPC0gdGliYmxlKCkKICBzc190aWJibGUgPC0gdGliYmxlKCkKICAjIHNpbXVsYXRlIHRha2luZyBtZWFzdXJlbWVudHMgZm9yIGEgcmFuZ2Ugb2YgZGF5cwogIGZvciAoZGF5IGluIGRheXNfZGVwcml2YXRpb24pIHsKICAgIGRheV9ub2lzZSA8LSBybm9ybSgxLCBtZWFuID0gMCwgc2QgPSBhYnMoc3Nfbm9pc2UpKSAjIHJhbmRvbWx5IHNhbXBsZSB0aGUgbm9pc2UKICAgIFJUIDwtIHNpbXVsYXRlX21lYXN1cmVtZW50KHBhcmFtc19kZiA9IG1zLCBkYXkgPSBxdW8oZGF5KSwgc3Nfbm9pc2UgPSBkYXlfbm9pc2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2NhdGlvbl9zaGlmdCA9IGxvY2F0aW9uX3NoaWZ0KQogICAgZGF5X3RpYmJsZSA8LSB0aWJibGUoaWQsIGRheSwgUlQsIGRheV9ub2lzZSwgc3Nfbm9pc2UpCiAgICBzc190aWJibGUgPC0gYmluZF9yb3dzKHNzX3RpYmJsZSwgZGF5X3RpYmJsZSkKICB9CiAgc3NfdGliYmxlCn0KYGBgCgpOZXh0LCBsZXQncyB3cml0ZSBhIGZ1bmN0aW9uIHRvIGdlbmVyYXRlIG1vZGVsIHBhcmFtZXRlcnMgZm9yIGVhY2ggcGFydGljaXBhbnQuIE5vdGUgdGhhdCB0aGUgdXNlciBjYW4gY29udHJvbDogCgogICogdGhlIGFtb3VudCBvZiBwYXJ0aWNpcGFudC1sZXZlbCB2YXJpYWJpbGl0eSB1c2luZyB0aGUgYHNzX25vaXNlYCBhcmd1bWVudCwgd2hpY2ggY29udHJvbHMgdGhlIHdpZHRoIG9mIHRoZSBub2lzZSBkaXN0cmlidXRpb24uIGhpZ2hlciBudW1iZXJzIHJlc3VsdCBpbiBtb3JlIG5vaXNlIGZvciBlYWNoIHBhcnRpY2lwYW50J3MgbWVhc3VyZW1lbnQuCiAgKiB0aGUgc2l6ZSBvZiB0aGUgZWZmZWN0IG9mIHNsZWVwIGRlcHJpdmF0aW9uIHVzaW5nIHRoZSBgbG9jYXRpb25fc2hpZnRgIGFyZ3VtZW50LiBoaWdoZXIgbnVtYmVycyByZXN1bHQgaW4gYSBzbWFsbGVyIGVmZmVjdCBvZiBkYXkKCmBgYHtyfQpzaW11bGF0ZV9tZWFzdXJlbWVudCA8LSBmdW5jdGlvbiAocGFyYW1zX2RmLCBkYXksIHNzX25vaXNlID0gMCwgbG9jYXRpb25fc2hpZnQgPSAwKSB7CiAgIyBleHRyYWN0IHRoZSB1bmRlcmx5aW5nIHBhcmFtdGVycyBmb3IgdGhhdCBkYXkgCiAgIyBub3RlIHRoZSB1c2Ugb2YgISEgZnJvbSB0aGUgdGlkeWV2YWwgZnJhbWV3b3JrLCBhbGxvd3MgdXMgdG8gcGFzcyB2YXJpYWJsZXMgdG8gZHBseXIgdmVyYnMKICBwYXJhbXMgPC0gcGFyYW1zX2RmICU+JSBmaWx0ZXIoRGF5cyA9PSAhIWRheSkgCiAgbSA8LSBwYXJhbXMgJT4lIG11dGF0ZShtX3NoaWZ0ID0gbSAtIChhcy5udW1lcmljKERheXMpICogbG9jYXRpb25fc2hpZnQpKSAlPiUgcHVsbChtX3NoaWZ0KQogIHMgPC0gcGFyYW1zICU+JSBwdWxsKHN0ZGV2KSArIHNzX25vaXNlCiAgIyBjb252ZXJ0IHRvIGxvZyBzcGFjZSBmb3IgdGhlIGxvZy1ub3JtYWwgZGlzdHJpYnV0aW9uCiAgbG9jYXRpb24gPC0gbG9nKG1eMiAvIHNxcnQoc14yICsgbV4yKSkKICBzaGFwZSA8LSBzcXJ0KGxvZygxICsgKHNeMiAvIG1eMikpKQogICMgc2FtcGxlIGFuIFJUIGZyb20gdGhlIGxvZy1ub3JtYWwgZGlzdHJpYnV0aW9uCiAgc3NfcnQgPC0gcmxub3JtKG4gPSAxLCBtZWFuID0gbG9jYXRpb24sIHNkID0gc2hhcGUpCiAgIyBtYWtlIHN1cmUgUlQgaXMgcG9zaXRpdmUgYW5kIGFib3ZlIDEwMCBtcwogIGlmIChzc19ydCA8IDIwMCkge3NzX3J0IDwtIDIwMH0KICBzc19ydAp9CgpgYGAKClRlc3Qgb3VyIHNpbXVsYXRlX3BhcnRpY2lwYW50KCkgZnVuY3Rpb24gd2l0aCBubyBhZGRlZCBub2lzZSBhbmQgdGhlIHNhbWUgYWdlIGVmZmVjdCBhcyBpbiB0aGUgb3JpZ2luYWwgZGF0YXNldC4gCgpgYGB7cn0KZGF5c19kZXByaXZhdGlvbiA8LSBtaW4oZC5vcmlnJERheXMpOm1heChkLm9yaWckRGF5cykKc2ltdWxhdGVfcGFydGljaXBhbnQoZGF5c19kZXByaXZhdGlvbiA9IGRheXNfZGVwcml2YXRpb24sIHNzX25vaXNlID0gMCwgaWQgPSAxLCAKICAgICAgICAgICAgICAgICAgICAgbG9jYXRpb25fc2hpZnQgPSAwKSAlPiUgCiAgbXV0YXRlKG9yaWdfUlQgPSBtcyRtKQpgYGAKCk5vdyB0aGF0IHdlIGNhbiBzaW11bGF0ZSB0aGUgZGF0YSBmb3IgYSBzaW5nbGUgcGFydGljaXBhbnQsIGxldCdzIHNpbXVsYXRlIHRoZSBlbnRpcmUgZXhwZXJpbWVudC4KCmBgYHtyfQojIGdsb2JhbCB2YXJzCm5fcGFydGljaXBhbnRzIDwtIDIwICMgY29udHJvbHMgdGhlIG51bWJlciBvZiBwYXJ0aWNpcGFudHMgaW4gdGhlIHN0dWR5CnNzX25vaXNlX2V4cGVyaW1lbnQgPC0gMTAwICMgY29udHJvbHMgdGhlIGFtb3VudCBvZiBub2lzZSBmb3IgZWFjaCBwYXJ0aWNpcGFudCwgaGlnaGVyIG51bWJlcnMgbWVhbiBub2lzaWVyIHBhcnRpY2lwYW50cwpsb2NhdGlvbl9zaGlmdCA8LSAwICMgY29udHJvbHMgd2hldGhlciB0aGVyZSBpcyBhbiBlZmZlY3Qgb2YgZGF5LCBoaWdoZXIgbnVtYmVycyBkZWNyZWFzZSB0aGUgZWZmZWN0IG9mIHNsZWVwIGRlcHJpdmF0aW9uIG9uIFJUCgojIHJ1biBzaW11bGF0aW9uCmQgPC0gdGliYmxlKCkKCmZvciAoaWQgaW4gMTpuX3BhcnRpY2lwYW50cykgewogIHNzX25vaXNlIDwtIHJub3JtKG4gPSAxLCBtZWFuID0gMCwgc2QgPSBzc19ub2lzZV9leHBlcmltZW50KQogIHNzIDwtIHNpbXVsYXRlX3BhcnRpY2lwYW50KGRheXNfZGVwcml2YXRpb24sIHNzX25vaXNlID0gc3Nfbm9pc2VfZXhwZXJpbWVudCwgaWQgPSBpZCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9jYXRpb25fc2hpZnQgPSBsb2NhdGlvbl9zaGlmdCkKICBkIDwtIGJpbmRfcm93cyhkLCBzcykKfQpgYGAKClBsb3QgdGhlIHNpbXVsYXRlZCBkYXRhIGJ5IHBhcnRpY2lwYW50IHdpdGggcmVncmVzc2lvbiBsaW5lcyBmaXQgdG8gZWFjaCBwYXJ0aWNpcGFudHMnIGRhdGEuCgpgYGB7cn0Kc2xlZXBfcGxvdCA8LSBnZ3Bsb3QoZCkgKyAKICBhZXMoeCA9IGRheSwgeSA9IFJUKSArIAogIHN0YXRfc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UpICsKICBnZW9tX3BvaW50KCkgKwogIGZhY2V0X3dyYXAoImlkIiwgc2NhbGVzID0iZnJlZSIpICsKICBsYWJzKHggPSB4bGFiLCB5ID0geWxhYikgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gMDo0ICogMikgCgpzbGVlcF9wbG90CmBgYAoKRml0IGEgY29tcGxldGUgcG9vbGluZyB0aGF0IGRvZXNuJ3Qga25vdyB0aGF0IG91ciBtZWFzdXJlbWVudHMgY29tZSBmcm9tIGRpZmZlcmVudCBwYXJ0aWNpcGFudHMuIAoKYGBge3J9Cm1fcG9vbGVkIDwtIGxtKFJUIH4gZGF5LCBkKSAKc3VtbWFyeShtX3Bvb2xlZCkKCmRmX3Bvb2xlZCA8LSBkYXRhX2ZyYW1lKAogIE1vZGVsID0gIkNvbXBsZXRlIHBvb2xpbmciLAogIGlkID0gYXMuY2hhcmFjdGVyKHVuaXF1ZShkJGlkKSksCiAgaW50ZXJjZXB0ID0gY29lZihtX3Bvb2xlZClbMV0sIAogIHNsb3BlX2RheXMgPSBjb2VmKG1fcG9vbGVkKVsyXSkKYGBgCgojIyBWaXN1YWxpemUgdmFyaWFiaWxpdHkgYnkgcGFydGljaXBhbnQKCmBgYHtyfQpkICU+JSAKICBncm91cF9ieShpZCkgJT4lIAogIHN1bW1hcmlzZShtX3J0ID0gbWVhbihSVCkpICU+JSAKICBtdXRhdGUoaWQgPSByZW9yZGVyKGlkLCBtX3J0KSkgJT4lIAogIGdncGxvdChhZXMoeCA9IGlkLCB5ID0gbV9ydCkpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBtZWFuKGQkUlQpLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9wb2ludChjb2xvciA9ICJkYXJrb3JhbmdlIiwgc2l6ZSA9IDIpICsKICBjb29yZF9mbGlwKCkgKwogIGxpbXMoeSA9IGMoMCwgNzUwKSkKYGBgCgoKRml0IG1peGVkIGVmZmVjdCBtb2RlbCBhbGxvd2luZyBmb3IgZWFjaCBwYXJ0aWNpcGFudCB0byBoYXZlIGEgZGlmZmVyZW50IGludGVyY2VwdCBhbmQgc2xvcGUuCgpgYGB7cn0KbV9taXhlZCA8LSBsbWVyKFJUIH4gMSArIGRheSArICgxICsgZGF5IHwgaWQpLCBkYXRhID0gZCkKc3VtbWFyeShtX21peGVkKQpgYGAKCldlIGNhbiBwbG90IHRoZSBtb2RlbCBvdXRwb3V0IGZvciBlYWNoIHBhcnRpY2lwYW50IGFsb25nc2lkZSB0aGVpciBkYXRhLgoKYGBge3J9CiMgZXh0cmFjdCByYW5kb20gZWZmZWN0IGNvZWZzIGZvciBlYWNoIHBhcnRpY2lwYW50CmRmX3BhcnRpYWxfcG9vbGluZyA8LSBjb2VmKG1fbWl4ZWQpW1siaWQiXV0gJT4lIAogIGFzX3RpYmJsZSgpICU+JSAKICByb3duYW1lc190b19jb2x1bW4oImlkIikgJT4lIAogIHJlbmFtZShpbnRlcmNlcHQgPSBgKEludGVyY2VwdClgLCBzbG9wZV9kYXlzID0gZGF5KSAlPiUgCiAgbXV0YXRlKE1vZGVsID0gIlBhcnRpYWwgcG9vbGluZyIpCgoKIyBBZGQgdGhpcyBpbmZvcm1hdGlvbiB0byB0aGUgZGF0YSBwbG90CmQgJTw+JSBtdXRhdGUoaWQgPSBhcy5jaGFyYWN0ZXIoaWQpKSAKZGZfbW9kZWxzIDwtIGxlZnRfam9pbihkLCBkZl9wYXJ0aWFsX3Bvb2xpbmcsIGJ5ID0gImlkIikgCmRmX21vZGVscyAlPD4lIGJpbmRfcm93cyguLCBkZl9wb29sZWQpCgojIE1ha2UgcGxvdApwX21vZGVsX2NvbXBhcmlzb24gPC0gZ2dwbG90KGRmX21vZGVscykgKyAKICBhZXMoeCA9IGRheSwgeSA9IFJUKSArIAogIGdlb21fYWJsaW5lKGFlcyhpbnRlcmNlcHQgPSBpbnRlcmNlcHQsIHNsb3BlID0gc2xvcGVfZGF5cywgY29sb3IgPSBNb2RlbCksCiAgICAgICAgICAgICAgc2l6ZSA9IC43NSkgKyAKICBnZW9tX3BvaW50KCkgKwogIGZhY2V0X3dyYXAoImlkIiwgc2NhbGVzID0gImZyZWUiKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IDA6NCAqIDIpICsgCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiRGFyazIiKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQoKcF9tb2RlbF9jb21wYXJpc29uCmBgYAoKSXQgbG9va3MgbGlrZSB3aGVuIHdlIGluY3JlYXNlIHRoZSBsZXZlbCBvZiBub2lzZSBmb3IgZWFjaCBwYXJ0aWNpcGFudCwgb3IgYmV0d2Vlbi1wYXJ0aWNpcGFudHMgdmFyaWFiaWxpdHksIHdlIGdldCBkaWZmZXJlbnQgaW5mZXJlbmNlcyBmcm9tIGxtIHZzLiBsbWVyKCkuIEluIHRoZSBjb21wbGV0ZSBwb29saW5nIG1vZGVsIHRoZSBzbG9wZSBwYXJhbWV0ZXIgaXMgc2lnLCBidXQgaW4gdGhlIG1peGVkLWVmZmVjdHMgbW9kZWwgaXQgaXMgbm90LiAKCiMjIEZpdCBCYXllc2lhbiBNaXhlZCBFZmZlY3RzIG1vZGVsIHVzaW5nIFJTdGFuQXJtCgpTZXQgdGhlIG51bWJlciBvZiBjb3JlcyB0byB0aGUgbnVtYmVyIG9mIGNvcmVzIG9uIHlvdXIgY29tcHV0ZXIuCgpgYGB7cn0Kb3B0aW9ucyhtYy5jb3JlcyA9IHBhcmFsbGVsOjpkZXRlY3RDb3JlcygpKQpgYGAKCkZpdCB0aGUgdmFyeWluZyBpbnRlcmNlcHRzIGFuZCBzbG9wZXMgbW9kZWwuCgpgYGB7cn0KbV9iZ2xtZXIgPC0gc3Rhbl9nbG1lcigKICBSVCB+IGRheSArIChkYXkgfCBpZCksICMgc3BlY2lmeSBtb2RlbCBmb3JtdWxhIHRoZSBzYW1lIHdheSBhcyBpbiBnbG1lciAKICBmYW1pbHkgPSBnYXVzc2lhbigpLCAjIHNwZWNpZnkgdHlwZSBvZiBtb2RlbAogIGRhdGEgPSBkLAogIHByaW9yID0gbm9ybWFsKDAsIDIpLCAjIHByaW9yIG9uIG1vZGVsIGNvZWZzIChEb2VzIG5vdCBpbmNsdWRlIGNvZWZmaWNpZW50cyB0aGF0IHZhcnkgYnkgZ3JvdXAgaW4gYSBtdWx0aWxldmVsIG1vZGVsKQogIHByaW9yX2ludGVyY2VwdCA9IG5vcm1hbCgwLCA1KSwgIyBwcmlvciBvbiBpbnRlcmNlcHQgYWZ0ZXIgY2VudGVyaW5nIHByZWRpY3RvcnMKICBwcmlvcl9jb3ZhcmlhbmNlID0gZGVjb3YocmVndWxhcml6YXRpb24gPSAyKSwgIyBwcmlvciBvbiBDb3ZhcmlhbmNlIG1hdHJpY2VzIGZvciBtaXhlZCBlZmZlY3RzIG1vZGVsCiAgY2hhaW5zID0gMgopCmBgYAoKV2UgY2FuIHVzZSB0aGUgZGVmYXVsdCBwbG90IGZ1bmN0aW9uIGluIFIgZGlyZWN0bHkgb24gb3VyIGZpdHRlZCBtb2RlbCB0byB2aXN1YWxpemUgdGhlIHBvc3RlcmlvciBpbnRlcnZhbCBvdmVyIHZhcmlvdXMgcGFyYW1ldGVycyBpbiB0aGUgbW9kZWwuIAoKYGBge3J9CiMgYWxsIHBhcmFtZXRlcnMgaW5jbHVkaW5nIHJhbmRvbSBzbG9wZXMgYW5kIGludGVyY2VwdHMKcGxvdChtX2JnbG1lcikKCiMgem9vbSBpbiBvbiBqdXN0IHRoZSBzbG9wZSBwYXJhbWV0ZXIKcGxvdChtX2JnbG1lciwgcGFycyA9IGMoImRheSIpKQpgYGAKClVuZGVyIHRoZSBob29kLCB0aGUgcGxvdCBtZXRob2QgaXMgdXNpbmcgZnVuY3Rpb25zIGZyb20gdGhlIGBiYXllc3Bsb3RgIGxpYnJhcnkuIFRoZXJlIGFyZSBhIGxvdCBvZiBvdGhlciB2aXN1YWxpemF0aW9ucyBvZiB0aGUgcG9zdGVyaW9yIGRpc3RyaWJ1dGlvbnMgdGhhdCB5b3UgY2FuIG1ha2UgdXNpbmcgdGhpcyBsaWJyYXJ5LCBhbmQgdGhlIG5pY2UgdGhpbmcgaXMgdGhhdCBhbGwgb2YgdGhlIGZ1bmN0aW9ucyByZXR1cm4gZ2dwbG90IG9iamVjdHMhIAoKRm9yIG1vcmUgaW5mb3JtYXRpb24gb24gd2hhdCB5b3UgY2FuIGRvIHdpdGggdGhlIGBiYXllc3Bsb3RgIGxpYnJhcnksIHNlZSB0aGUgW21hbnVhbF0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2JheWVzcGxvdC9iYXllc3Bsb3QucGRmKSBhbmQgdGhpcyBuaWNlIFt2aWduZXR0ZV0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2JheWVzcGxvdC92aWduZXR0ZXMvTUNNQy5odG1sKS4KCmBgYHtyfQpsaWJyYXJ5KGJheWVzcGxvdCkKcG9zdGVyaW9yIDwtIG1fYmdsbWVyICU+JSBhcy5kYXRhLmZyYW1lKCkgIyBleHRyYWN0IHRoZSBwb3N0ZXJpb3Igc2FtcGxlcyBhcyBkYXRhIGZyYW1lCmNvbG9yX3NjaGVtZV9zZXQoImdyYXkiKSAjIHNldCBjb2xvciBhZXN0aGV0aWNzIG9mIHBsb3QKCiMgbWFrZSBhIGJpdmFyaWF0ZSBzY2F0dGVyIG9mIHRoZSBpbnRlcmNlcHQgYW5kIHNsb3BlIHBhcmFtZXRlcnMKbWNtY19zY2F0dGVyKHBvc3RlcmlvciwgcGFycyA9IGMoIihJbnRlcmNlcHQpIiwgImRheSIpLCBzaXplID0gMS41LCBhbHBoYSA9IDAuNSkgCmBgYAoKV2UgY2FuIGFsc28gY3JlYXRlIHRoZSBzYW1lIGludGVydmFsIHBsb3QgZnJvbSBiZWZvcmUuIAoKYGBge3J9CmNvbG9yX3NjaGVtZV9zZXQoInJlZCIpCgpwIDwtIHBvc3RlcmlvciAlPiUgCiAgIyBqdXN0IHBsb3QgdGhlIHNsb3BlIHBhcmFtZXRlcgogIHNlbGVjdChzdGFydHNfd2l0aCgiZGF5IikpICU+JQogIG1jbWNfaW50ZXJ2YWxzKC4sCiAgICAgICAgICAgICAgICAgcHJvYiA9IDAuOCwgIyA4MCUgaW50ZXJ2YWxzCiAgICAgICAgICAgICAgICAgcHJvYl9vdXRlciA9IDAuOTksICMgOTklCiAgICAgICAgICAgICAgICAgcG9pbnRfZXN0ID0gIm1lYW4iCiAgICAgICAgICAgICAgICAgKSAKcAoKIyBhZGQgYSB2bGluZSBhdCB6ZXJvCnAgKyB4bGltKC01LDI1KSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAnZGFzaGVkJykKYGBgCgpPciBpZiB5b3Ugd2FudCB0byBtYWtlIGEgZGVuc2l0eSBwbG90LiAKCmBgYHtyfQpwb3N0ZXJpb3IgJT4lIAogIHNlbGVjdChjb250YWlucygiZGF5IikpICU+JSAKICBtY21jX2FyZWFzKC4sIAogICAgICAgICAgICAgcGFycyA9IGMoImRheSIpLAogICAgICAgICAgICAgcHJvYiA9IDAuOCwgIyA4MCUgaW50ZXJ2YWwKICAgICAgICAgICAgIHByb2Jfb3V0ZXIgPSAwLjk5LCAjIDk5JSBpbnRlcnZhbAogICAgICAgICAgICAgcG9pbnRfZXN0ID0gIm1lYW4iCikKYGBgCgpUaGUgYmF5ZXNwbG90IGFuZCBkZWZhdWx0IHBsb3RzIGFyZSBuaWNlLCBidXQgaWYgeW91IHdhbnQgbW9yZSBmbGV4aWJpbGl0eSwgeW91IGNhbiBzYW1wbGUgZnJvbSBzYW1wbGVzIGZyb20gdGhlIHBvc3RlcmlvciBkaXN0cmlidXRpb25zIG92ZXIgdGhlIHNsb3BlIGFuZCBpbnRlcmNlcHQgcGFyYW1ldGVycy4gVGhpcyBmaXJzdCB2aXN1YWxpemF0aW9uIGlzIGEgY291bnRvdXIgcGxvdCB1c2luZyBjb2RlIGZyb20gVHJpc3RhbiBNYWhyJ3MgbG92ZWx5IFtibG9ncG9zdF0oaHR0cHM6Ly90am1haHIuZ2l0aHViLmlvL3Bsb3R0aW5nLXBhcnRpYWwtcG9vbGluZy1pbi1taXhlZC1lZmZlY3RzLW1vZGVscy8pLiAKCkxldCdzIGZpcnN0IGV4dHJhY3QgdGhlIHNhbXBsZXMgZnJvbSB0aGUgbW9kZWwgb2JlY3QuCgpgYGB7cn0KIyBHZXQgYSBkYXRhZnJhbWU6IE9uZSByb3cgcGVyIHBvc3RlcmlvciBzYW1wbGUKZGZfcG9zdGVyaW9yIDwtIG1fYmdsbWVyICU+JSAKICBhcy5kYXRhLmZyYW1lKCkgJT4lIAogIGFzX3RpYmJsZSgpICU+JSAKICByZW5hbWUoaW50ZXJjZXB0ID0gYChJbnRlcmNlcHQpYCkKYGBgCgpOb3cgbWFrZSB0aGUgY29udG91ciBwbG90LCBzaG93aW5nIGEgc2V0IG9mIHBsYXVzaWJsZSB2YWx1ZXMgZm9yIHRoZSBpbnRlcmNlcHQgYW5kIHNsb3BlIHBhcmFtZXRlcnMuCgpgYGB7cn0KZ2dwbG90KGRmX3Bvc3RlcmlvcikgKyAKICBhZXMoeCA9IGludGVyY2VwdCwgeSA9IGBkYXlgKSArIAogICMgQ2FsY3VsYXRlIHRoZSBkZW5zaXR5CiAgc3RhdF9kZW5zaXR5XzJkKGFlcyhmaWxsID0gLi5sZXZlbC4uKSwgZ2VvbSA9ICJwb2x5Z29uIikgKwogIGdndGl0bGUoIldoZXJlJ3MgdGhlIGF2ZXJhZ2UgaW50ZXJjZXB0IGFuZCBzbG9wZT8iKSArIAogIHhsYWIoIkVzdGltYXRlIGZvciBhdmVyYWdlIGludGVyY2VwdCIpICsgCiAgeWxhYigiRXN0aW1hdGUgZm9yIGF2ZXJhZ2Ugc2xvcGUiKSArCiAgIyBVc2UgdGhlIHNhbWUgY29vcmRpbmF0ZSBsaW1pdHMgYXMgbGFzdCBwbG90CiAgY29vcmRfY2FydGVzaWFuKAogICAgeGxpbSA9IHJhbmdlKGRmX3Bvc3RlcmlvciRpbnRlcmNlcHQpLCAKICAgIHlsaW0gPSByYW5nZShkZl9wb3N0ZXJpb3IkZGF5KSwKICAgIGV4cGFuZCA9IFRSVUUpICsgCiAgZ3VpZGVzKGZpbGwgPSAibm9uZSIpCmBgYAoKIyMgRGlhZ25vc3RpY3MgYW5kIHBsb3RzIHVzaW5nIFNoaW55IFN0YW4KCmBgYHtyLCBldmFsID0gRn0KbGF1bmNoX3NoaW55c3RhbihtX2JnbG1lcikKYGBgCgpBIGZldyB0aGluZ3MgdG8gbG9vayBhdCBpbiBTaGlueSBTdGFuOgoKKiB0cmFjZXBsb3RzIG9mIE1DTUMgY2hhaW5zCiogUG9zdGVyaW9yIHByZWRpY3RpdmUgKFBQKSBjaGVja3MKICAtIGRpc3RyaWJ1dGlvbiBvZiBvYnNlcnZlZCBkYXRhIHZzIG1vZGVsLWdlbmVyYXRlZCBkYXRhCiAgLSBkaXN0cmlidXRpb25zIG9mIHRlc3Qgc3RhdGlzdGljcwoqIGdlbmVyYXRpbmcgdGFibGVzCgojIyBJbnNwZWN0aW5nIFByaW9ycwoKSXQncyBhbHdheXMgYSBnb29kIGlkZWEgdG8gY2hlY2sgdGhlIHByaW9yIGRpc3RyaWJ1dGlvbiBvdmVyIHRoZSBwYXJhbWV0ZXJzIGluIHlvdXIgbW9kZWwgdG8gc2VlIHdoYXQga2luZHMgb2YgdmFsdWVzIGFyZSBnZW5lcmF0ZWQgYW5kIGNvbmZpcm0gdGhhdCBvdXIgcHJpb3IgaW5mb3JtYXRpb24gcHJvZHVjZXMgc2Vuc2libGUgbW9kZWwgYmVoYXZpb3IuCgpXZSBjYW4gdXNlIHRoZSBwcmlvcl9zdW1tYXJ5KCkgZnVuY3Rpb24gdG8gZ2V0IGluZm9ybWF0aW9uIGFib3V0IHRoZSBwcmlvcnMgYW5kIGFkanVzdG1lbnRzIHVzZWQgaW4gdGhlIG1vZGVsLgoKYGBge3J9CnByaW9yX3N1bW1hcnkobV9iZ2xtZXIpCmBgYAoKKnJzdGFuYXJtKiBjb21lcyB3aXRoIGEgYnVpbHQtaW4gZnVuY3Rpb24gZm9yIHZpc3VhbGl6aW5nICJiZWxpZWYgY2hhbmdlIiBhZnRlciBzZWVpbmcgdGhlIGRhdGEuCgpgYGB7cn0KcG9zdGVyaW9yX3ZzX3ByaW9yKG1fYmdsbWVyLCBwYXJzID0gImRheSIpCmBgYAoKQnV0IHdlIGNhbiBhbHNvIHNhbXBsZSBmcm9tIHRoZSBwcmlvciBkaXJlY3RseSB1c2luZzogYHByaW9yX1BEID0gVFJVRWAuIAoKYGBge3J9Cm1fYmdsbWVyX3ByaW9yIDwtIHN0YW5fZ2xtZXIoCiAgUlQgfiBkYXkgKyAoZGF5IHwgaWQpLAogIGZhbWlseSA9IGdhdXNzaWFuKCksCiAgZGF0YSA9IGQsCiAgcHJpb3IgPSBub3JtYWwoMCwgMiksCiAgcHJpb3JfaW50ZXJjZXB0ID0gbm9ybWFsKDAsIDUpLAogIHByaW9yX2NvdmFyaWFuY2UgPSBkZWNvdihyZWd1bGFyaXphdGlvbiA9IDIpLAogIHByaW9yX2F1eCA9IGNhdWNoeSgwLCAxKSwKICBjaGFpbnMgPSAyLAogIHByaW9yX1BEID0gVFJVRSAjIHNldCB0aGlzIHRvIFRSVUUgdG8gc2FtcGxlIGRpcmVjdGx5IGZyb20gcHJpb3IKKQpgYGAKCmBgYHtyfQpzdW1tYXJ5KG1fYmdsbWVyX3ByaW9yLCBwYXJzID0gYygiKEludGVyY2VwdCkiLCAiZGF5IiksIHByb2JzID0gYyguMSwgLjUsIC45KSkKCnNkIDwtIGJyb29tOjp0aWR5KG1fYmdsbWVyX3ByaW9yKSAlPiUgcHVsbChzdGQuZXJyb3IpCnNkIDwtIHNkWzJdIApgYGAKCldlIGNhbiBzZWUgdGhhdCBvdXIgaW5pdGlhbCBwcmlvciBvZiBgbm9ybWFsKDAsIDIpYCBmb3IgdGhlIGVmZmVjdCBvZiBzbGVlcCBkZXByaXZhdGlvbiBpcyBjZW50ZXJlZCBhcm91bmQgemVybyBhbmQgdGhpbmtzIHRoYXQgYW4gaW5jcmVhc2Ugb2YgKy8tIGByIHJvdW5kKHNkLCAyKWAgbWlsbGlzZWNvbmRzIHBlciBkYXkgaXMgcmVhc29uYWJsZS4gVGhpcyBzZWVtcyBzZW5zaWJsZSB0byBtZSwgYnV0IGlmIHlvdSBoYWQgbW9yZSBpbmZvcm1hdGlvbiBhYm91dCB3aGF0IHlvdSBleHBlY3QgdGhlIHJhbmdlIG9mIGVmZmVjdHMgdG8gYmUsIHlvdSBjb3VsZCBidWlsZCB0aGlzIGludG8gdGhlIHByaW9yLiAKCkxldCdzIHNpbXVsYXRlIHRoZSBzYW1lIG1vZGVsIHdpdGggYSAid2lkZXIiIHByaW9yLgoKYGBge3J9Cm1fYmdsbWVyX3ByaW9yX3dpZGUgPC0gc3Rhbl9nbG1lcigKICBSVCB+IGRheSArIChkYXkgfCBpZCksCiAgZmFtaWx5ID0gZ2F1c3NpYW4oKSwKICBkYXRhID0gZCwKICBwcmlvciA9IG5vcm1hbCgwLCAxMCksICMgY2hhbmdlIHRoZSBwcmlvciBvbiB0aGUgc2xvcGUgcGFyYW1ldGVyCiAgcHJpb3JfaW50ZXJjZXB0ID0gbm9ybWFsKDAsIDUpLAogIHByaW9yX2NvdmFyaWFuY2UgPSBkZWNvdihyZWd1bGFyaXphdGlvbiA9IDIpLAogIHByaW9yX2F1eCA9IGNhdWNoeSgwLCAxKSwKICBjaGFpbnMgPSAyLAogIHByaW9yX1BEID0gVFJVRQopCgpzdW1tYXJ5KG1fYmdsbWVyX3ByaW9yX3dpZGUsIHBhcnMgPSBjKCIoSW50ZXJjZXB0KSIsICJkYXkiKSwgcHJvYnMgPSBjKC4xLCAuNSwgLjkpKQpgYGAKCk5vdyB3ZSBjYW4gc2VlIHRoYXQgdGhlIG1vZGVsIGNvbnNpZGVycyB2YWx1ZXMgKy8tIDE1MCBtcyBwZXIgZGF5IHRvIGJlIHJlYXNvbmFibGUgKHdpdGhpbiAxIHNkKSwgd2hpY2ggaXMgcHJvYmFibHkgdG9vIGJyb2FkLiAKCkEgbm90ZSBvbiBwcmlvcnMgZnJvbSB0aGUgZGV2ZWxvcGVycyBvZiAqcnN0YW5hcm0qIChwcmlvcnMgW3ZpZ25ldHRlXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvcnN0YW5hcm0vdmlnbmV0dGVzL3ByaW9ycy5odG1sKSk6Cgo+IFdpdGggdmVyeSBmZXcgZXhjZXB0aW9ucywgdGhlIGRlZmF1bHQgcHJpb3JzIGluIHJzdGFuYXJtIOKAlHRoZSBwcmlvcnMgdXNlZCBpZiB0aGUgYXJndW1lbnRzIGluIHRoZSB0YWJsZXMgYWJvdmUgYXJlIHVudG91Y2hlZOKAlCBhcmUgbm90IGZsYXQgcHJpb3JzLiBSYXRoZXIsIHRoZSBkZWZhdWx0cyBhcmUgaW50ZW5kZWQgdG8gYmUgd2Vha2x5IGluZm9ybWF0aXZlLiBUaGF0IGlzLCB0aGV5IGFyZSBkZXNpZ25lZCB0byBwcm92aWRlIG1vZGVyYXRlIHJlZ3VsYXJpemF0aW9uIGFuZCBoZWxwIHN0YWJpbGl6ZSBjb21wdXRhdGlvbi4gRm9yIG1hbnkgKGlmIG5vdCBtb3N0KSBhcHBsaWNhdGlvbnMgdGhlIGRlZmF1bHRzIHdpbGwgcGVyZm9ybSB3ZWxsLCBidXQgdGhpcyBpcyBub3QgZ3VhcmFudGVlZCAodGhlcmUgYXJlIG5vIGRlZmF1bHQgcHJpb3JzIHRoYXQgbWFrZSBzZW5zZSBmb3IgZXZlcnkgcG9zc2libGUgbW9kZWwgc3BlY2lmaWNhdGlvbikuCgo+IEJlY2F1c2UgdGhlIHNjYWxpbmcgaXMgYmFzZWQgb24gdGhlIHNjYWxlcyBvZiB0aGUgcHJlZGljdG9ycyAoYW5kIHBvc3NpYmx5IHRoZSBvdXRjb21lKSB0aGVzZSBhcmUgdGVjaG5pY2FsbHkgZGF0YS1kZXBlbmRlbnQgcHJpb3JzLiBIb3dldmVyLCBzaW5jZSB0aGVzZSBwcmlvcnMgYXJlIHF1aXRlIHdpZGUgKGFuZCBpbiBtb3N0IGNhc2VzIHJhdGhlciBjb25zZXJ2YXRpdmUpLCB0aGUgYW1vdW50IG9mIGluZm9ybWF0aW9uIHVzZWQgaXMgd2VhayBhbmQgbWFpbmx5IHRha2VzIGludG8gYWNjb3VudCB0aGUgb3JkZXIgb2YgbWFnbml0dWRlIG9mIHRoZSB2YXJpYWJsZXMuIFRoaXMgZW5hYmxlcyByc3RhbmFybSB0byBvZmZlciBkZWZhdWx0cyB0aGF0IGFyZSByZWFzb25hYmxlIGZvciBtYW55IG1vZGVscy4KClRvIGRpc2FibGUgYXV0b21hdGljIHJlc2NhbGluZyBzaW1wbHkgc2V0IHRoZSBhdXRvc2NhbGUgYXJndW1lbnQgdG8gdG8gRkFMU0UuIEZvciBleGFtcGxlOgoKYGBge3J9CnRlc3Rfbm9fYXV0b3NjYWxlIDwtCiAgdXBkYXRlKAogICAgbV9iZ2xtZXJfcHJpb3IsCiAgICBwcmlvciA9IG5vcm1hbCgwLCA1LCBhdXRvc2NhbGUgPSBGQUxTRSksCiAgICBwcmlvcl9pbnRlcmNlcHQgPSBzdHVkZW50X3QoNCwgMCwgMTAsIGF1dG9zY2FsZSA9IEZBTFNFKSwKICAgIHByaW9yX2F1eCA9IGV4cG9uZW50aWFsKDEvMTAsIGF1dG9zY2FsZT1GQUxTRSkKICApCmBgYAoKYGBge3J9CnByaW9yX3N1bW1hcnkodGVzdF9ub19hdXRvc2NhbGUpCmBgYAoKQnV0IHRoZSByc3RhbmFybSBkZXZlbG9wZXJzIHBvaW50IG91dCB0aGF0OgoKPiBEaXNhYmxpbmcgcHJpb3Igc2NhbGUgYWRqdXN0bWVudHMgaXMgdXN1YWxseSB1bm5lY2Vzc2FyeSBidXQgaXMgdXNlZnVsIGZvciB3aGVuIG1vcmUgaW5mb3JtYXRpdmUgcHJpb3IgaW5mb3JtYXRpb24gaXMgYXZhaWxhYmxlLiBUaGVyZSBpcyBhbiBleGFtcGxlIG9mIHNwZWNpZnlpbmcgYW4gaW5mb3JtYXRpdmUgcHJpb3IgbGF0ZXIgaW4gdGhpcyB2aWduZXR0ZS4K