About

Questions

  • Which outcome makes the most sense: looking at RTPUSH and RTPULL, or at the bias scores? (more of a question for MFO and BA)
  • Which statistical test(s) would be most appropriate for each aim?
  • If needed: How to set up planned contrasts correctly
  • Which covariates to include (e.g., controlling for order effects - this is more of a question for MFO and BA but there is the issue of sample size vs. overfitting)

At a glance

  • 39 bereaved participants
  • Randomized double-blind placebo-controlled crossover design
      • Two treatments (thus two timepoints): oxytocin or placebo
  • Primary outcome is task performance (reaction time)
  • Primary independent variables are grief severity (continuous self-report score, and/or categorical high-low), treatment (oxytocin/placebo), and stimulus (5 different categories)

Study description

This project uses behavioral and self-report data from the study “The effect of intranasal oxytocin on neural functioning in widow(er)s” (#1503744420, PI: Mary-Frances O’Connor, Co-PI: Brian Arizmendi). It was a double-blind randomized crossover study using an intranasal oxytocin manipulation and approach-avoidance task variant (grief AAT; gAAT) to investigate conflicting accounts of motivated behavior in people with complicated grief. Enrolled participants were older adults who had experienced the death of a spouse or long-term romantic partner between 6-36 months prior to their participation. Stratified sampling was used to ensure a range of grief symptom severity scores was represented in the sample.

Participants attended two identical experimental sessions, at which they received one of two intranasal sprays (oxytocin or placebo) and then took part in an fMRI scan, during which time they completed the task.

Task (gAAT)

In the gAAT, five stimulus categories were presented:

  1. Personal photos of the deceased spouse,
  2. Personal photos of a living loved one,
  3. Photos of a female or male stranger,
  4. Grief-related scenes, and
  5. Neutral scenes.

Photos provided by the participant were scanned,resized, and framed with blue/yellow frames to match the other stimuli used in the task. Photos of the stranger were sex-matched to the participant’s partner.

Participants completed the task using a joystick. The stimuli were animated so that a joystick push would make the image smaller (as if they were pushing it away) and a joystick pull would make the image larger (as if they were bringing it closer).

Participants were instructed to respond during the task to the color of a photo’s frame, e.g., push the joystick when the frame is BLUE, pull when the frame is YELLOW”). Once participants had completed the first run of the task (144 trials), they completed a second run that was identical to the first except for the instructions, which were reversed (e.g. “now push the joystick for YELLOW and pull for BLUE”). Order of instructions was counterbalanced across participants. Stimuli were presented via Inquisit 4 (2014), in a pseudorandomized order determined by genetic algorithm to optimize statistical power and psychological validity (Wager & Nichols, 2003). Each trial last 3000ms, with 2500 ms allowed for response. Intertrial interval was 500ms.

Aims

These are the primary aims for the project:

  1. To identify whether grief severity moderates behavioral response to specific types of stimuli, comparing high-severity (CG group) and low-severity (Non-CG group) participants.
      1a. Alternatively: To identify whether the continuous measure of grief severity moderates behavioral response to specific types of stimuli.
  2. To identify whether bereaved individuals show different behavioral responses when grief-related stimuli are idiographic (personal photos of spouse) versus nomothetic (generic grief-related scenes).
  3. To identify whether effects of intranasal oxytocin differ in high-severity [CG group] versus low-severity [Non-CG group] participants.
      3a. Alternatively: To identify whether the continuous measure of grief severity moderates effects of oxytocin on task performance.

We also wanted to test whether any observed moderation of oxytocin effects grief severity would be specific to certain types of stimuli. However, we likely lack power to detect a three-way interaction in the existing sample.

Analyses

Previous studies’ approaches

Note that the experimental design for the present study is not identical to the studies below.

  • Maccallum et al, 2015:
    • ANOVAs with direction (push or pull) and stimulus as predictors, and median reaction time as outcome.
    • Bias scores were not used as an outcome, but group means are presented (Table 2).

  • Eisma et al, 2015:
    • Multiple regression analyses (a separate model for each stimulus category) with bias score as outcome and self-reported rumination as predictor.

In both papers, bias scores were computed as (median RTpush - median RTpull) in each stimulus category.

Variables

  • ID - participant ID
Predictors:
  • treatment - treatment received (oxytocin or placebo)
  • direction - direction of their response (push or pull)
  • stimulus - the type of image they saw (spouse, living loved one, stranger, generic grief-related, neutral)
  • grief_severity - continuous measure of self-reported complicated grief symptoms
  • group - complicated grief (CG) or non-complicated grief (NCG), based on grief_severity >25
Outcomes:
  • gAAT_RT - reaction time in ms
  • gAAT_bias - difference between push and pull reaction times (positive values indicate approach bias, negative values indicate avoidance bias)

Aim 1 options

Aim 1: To identify whether grief severity moderates behavioral response to specific types of stimuli, comparing high-severity (CG group) and low-severity (Non-CG group) participants.

Option A: RM-ANOVA

library(tidyverse)
library(afex)
library(emmeans)
filter <- dplyr::filter
select <- dplyr::select

# read in behavioral data (long dataset containing trial-level reaction times)
data_long <-  readRDS("~/Dropbox/GLASS Lab/OT gAAT for meeting 5-10-19/bx_long_noOut.rds")
# read in master dataset and subset variables to add to behavioral dataset
# varstoadd <- readRDS("~/Dropbox/GLASS Lab/OT Study/data/master-dataset/ot-fmri_master-dataset_020719.rds")
# varstoadd <- subset(varstoadd, select=c(ID, # participant ID
#                                        sex_m, # sex (female as reference category)
#                                        age_yrs, # age in years
#                                        ethnicity_hisp,  # ethnicity (non-Hispanic as reference category)
#                                        race, # race
#                                        timesincedeath, # time since partner's death and baseline survey completion
#                                        yrs_together, # relationship length in years
#                                        group, # CG or NCG, based on tot_icg >25 as threshold for CG
#                                        tx_v1, # whether they received oxytocin or placebo at first session
#                                        tot_icg # grief severity (Inventory of Complicated Grief)
# ))
# saveRDS(varstoadd, "~/Dropbox/GLASS Lab/OT gAAT for meeting 5-10-19/varstoadd.rds")
# already saved the subset, so just read in the subset:

varstoadd <- readRDS("~/Dropbox/GLASS Lab/OT gAAT for meeting 5-10-19/varstoadd.rds")


########## MODEL 1 ##########
# Model 1 requires a stacked/long dataset containing the following, at minimum:
## one variable `ID` with participant IDs
## one numeric variable `gAAT_RT` with TRIAL-LEVEL reaction times
## one factor `stimulus` with 5 levels (spouse, stranger, loved one, grief scenes, neutral scenes)
## one factor `treatment` with 2 levels (oxytocin, placebo)
## one factor `direction` with 2 levels (push, pull)
## one factor `group` with 2 factors (CG, NCG) *OR* one numeric variable `grief_score` with individual grief severity scores (time-invariant)

data_long <- left_join(data_long, varstoadd, ID="ID") # varstoadd = subset of master dataset
data_placebo <- data_long %>% rename(treatment = cond,
                                     stimulus = stim,
                                     direction = push_pull,
                                     grief_severity = tot_icg) %>%
  mutate(treatment = recode(treatment, 
                            A = "placebo",
                            B = "oxytocin")) %>%
  filter(treatment == "placebo") 
head(data_placebo)


# Model 1: RM-ANOVA with two within-subjects factors (stimulus, push or pull) and one between-subjects factor (group)
m1 <- aov_ez(id = "ID", dv = "gAAT_RT", data_placebo, between = "group", within = c("stimulus", "direction"), fun_aggregate = median) # or use between = "grief_severity" for grief severity as continuous vs. categorical
summary(m1) 

# use the `emmeans` package to conduct pairwise comparisons 
# (emmeans is the same thing as lsmeans and pmmeans, just different terms)
# need to double-check that I'm doing this correctly...
emmeans(m1, ~c(direction, stimulus), contr = "pairwise", adjust="holm")

########## MODEL 2 ##########
# Model 2 requires a stacked/long dataset containing the following, at minimum:
## one variable `ID` with participant IDs
## one numeric variable `gAAT_bias` with participants' push-pull difference scores for each stimulus x treatment level
## e.g., median push RT to death stimuli under placebo MINUS median pull RT to death stimuli under placebo
## one factor `stimulus` with 5 levels (spouse, stranger, loved one, grief scenes, neutral scenes)
## one factor `treatment` with 2 levels (oxytocin, placebo)
## one factor `direction` with 2 levels (push, pull)
## one factor `group` with 2 factors (CG, NCG) *OR* one numeric variable `grief_score` with individual grief severity scores (time-invariant)

data_bias <-  readRDS("~/Dropbox/GLASS Lab/OT gAAT for meeting 5-10-19/bias_long.rds")
data_bias <- left_join(data_bias, varstoadd, by="ID")
  # NOTE that this is the dataset that calculates bias by subtracting the median pull reaction time in each category from the median push reaction time in that category (NOT the trial-by-trial bias subtracting run1 from run2)
  
data_bias_placebo <- data_bias %>% 
  rename(treatment = cond,
         gAAT_bias = bias) %>% 
  mutate(treatment = recode(treatment, 
                            A = "placebo",
                            B = "oxytocin")) %>%
  filter(treatment == "placebo") 


# Model 2: RM-ANOVA with one within-subjects factor (stimulus) and one between-subjects factor (group)
m2 <- aov_ez(id = "ID", dv = "gAAT_bias", data_bias_placebo, between = "group", within = c("stimulus")) # or use between = "grief_severity" for grief severity as continuous vs. categorical
summary(m2)

# use the `emmeans` package to conduct pairwise comparisons 
# (emmeans is the same thing as lsmeans and pmmeans, just different terms)
# need to double-check that I'm doing this correctly...
emmeans(m2, ~stimulus, contr = "pairwise", adjust="holm")
emmeans(m2, ~group, contr = "pairwise", adjust="holm")


# additional covariates such as participant age, task run (first or second), etc. may be included in final model

Option B: Multiple regression

library(tidyverse)
filter <- dplyr::filter
select <- dplyr::select

########## MODEL 1 ##########
# Model 1 requires a stacked/long dataset containing the following, at minimum:
## one variable `ID` with participant IDs
## one numeric variable `gAAT_RT` with TRIAL-LEVEL reaction times
## one factor `stimulus` with 5 levels (spouse, stranger, loved one, grief scenes, neutral scenes)
## one factor `treatment` with 2 levels (oxytocin, placebo)
## one factor `direction` with 2 levels (push, pull)
## one factor `run` with 2 levels (first, second)
## one factor `group` with 2 factors (CG, NCG) *OR* one numeric variable `grief_score` with individual grief severity scores (time-invariant)

# Model 1:
# Multiple linear regression model specifying three-way interaction effect on median push and pull reaction times
m1 <- lm(gAAT_RT ~ stimulus*direction, data=data_placebo) # or use `grief_severity` instead of `group`
summary(m1)

########## MODEL 2 ##########
# Model 2 requires a stacked/long dataset containing the following, at minimum:
## one variable `ID` with participant IDs
## one numeric variable `gAAT_bias` with participants' push-pull difference scores for each stimulus x treatment level
## e.g., median push RT to death stimuli under placebo MINUS median pull RT to death stimuli under placebo
## one factor `stimulus` with 5 levels (spouse, stranger, loved one, grief scenes, neutral scenes)
## one factor `treatment` with 2 levels (oxytocin, placebo)
## one factor `direction` with 2 levels (push, pull)
## one factor `group` with 2 factors (CG, NCG) *OR* one numeric variable `grief_score` with individual grief severity scores (time-invariant)

# Model 2:
# Multiple linear regression model specifying two-way interaction effect on bias scores
m2 <- lm(gAAT_bias ~ stimulus*group, data=data_bias_placebo) # or use `grief_severity` instead of `group`
summary(m2)

# additional covariates such as participant age, task run (first or second), etc. may be included in final model

Option C: Mixed effects model

library(tidyverse)
library(nlme)
filter <- dplyr::filter
select <- dplyr::select

########## MODEL 1 ##########
# Model 1 requires a stacked/long dataset containing the following, at minimum:
## one variable `ID` with participant IDs
## one numeric variable `gAAT_RT` with TRIAL-LEVEL reaction times
## one factor `stimulus` with 5 levels (spouse, stranger, loved one, grief scenes, neutral scenes)
## one factor `treatment` with 2 levels (oxytocin, placebo)
## one factor `direction` with 2 levels (push, pull)
## one factor `run` with 2 levels (first, second)
## one factor `group` with 2 factors (CG, NCG) *OR* one numeric variable `grief_score` with individual grief severity scores (time-invariant)

# Model 1:
# Mixed model specifying three-way interaction effect on median push and pull reaction times
m1 <- lme(gAAT_RT ~ stimulus*direction*group, data = data_placebo, random = ~ 1|ID, method="REML") # or use `grief_severity` instead of `group`
summary(m1)


########## MODEL 2 ##########
# Model 2 requires a stacked/long dataset containing the following, at minimum:
## one variable `ID` with participant IDs
## one numeric variable `gAAT_bias` with participants' push-pull difference scores for each stimulus x treatment level
## e.g., median push RT to death stimuli under placebo MINUS median pull RT to death stimuli under placebo
## one factor `stimulus` with 5 levels (spouse, stranger, loved one, grief scenes, neutral scenes)
## one factor `treatment` with 2 levels (oxytocin, placebo)
## one factor `direction` with 2 levels (push, pull)
## one factor `group` with 2 factors (CG, NCG) *OR* one numeric variable `grief_score` with individual grief severity scores (time-invariant)

# Model 2:
# Mixed model specifying two-way interaction effect on bias scores
m2 <- lme(gAAT_bias ~ stimulus*group, data = data_bias_placebo, random = ~ 1|ID, method="REML") # or use `grief_severity` instead of `group`
summary(m2)

# additional covariates such as participant age, task run (first or second), etc. may be included in final model

Option D: Multilevel growth model (RULED OUT)

This is what I did for Emily’s class - I think we all agreed that this is unneccessarily complicated given that we are not interested in trial-level changes in reaction time over the course of the task. In these analyses, I ultimately ended up removing time (trial #) as a predictor anyway since there was no fixed or random effect of time.

In this approach, we also end up dropping more participants because four people failed to reverse the instructions on their second run of the task so I could not subtract, say, RT on run 2 trial #30 (“PULL”) from RT on run 1 trial #30 (“PUSH”) because they pushed (or pulled) on that trial on both runs.

Aim 2 options

Aim 2: To identify whether bereaved individuals show different behavioral responses when grief-related stimuli are idiographic (personal photos of spouse) versus nomothetic (generic grief-related scenes).

This should be a planned contrast within one of the Aim 1 analyses, I think. There is a way to specify contrasts in nlme using the contrasts = argument but I need some guidance as to how to correctly set up the list it’s expecting.

This is how you do it for the ANOVA using emmeans:

?aov_ez

The S3 object returned per default can be directly passed to emmeans::emmeans for further analysis. This allows to test any type of contrasts that might be of interest independent of whether or not this contrast involves between-subject variables, within-subject variables, or a combination thereof. The general procedure to run those contrasts is the following (see Examples for a full example):

(1) Estimate an afex_aov object with the function returned here. For example: x <- aov_car(dv ~ a*b + (id/c), d)

(2) Obtain a emmGrid-class object by running emmeans on the afex_aov object from step 1 using the factors involved in the contrast. For example: r <- emmeans(x, ~a:c)

(3) Create a list containing the desired contrasts on the reference grid object from step 2. For example: 
con1 <- list(a_x = c(-1, 1, 0, 0, 0, 0), b_x = c(0, 0, -0.5, -0.5, 0, 1))

(4) Test the contrast on the reference grid using contrast. For example: contrast(r, con1)

To control for multiple testing p-value adjustments can be specified. For example the Bonferroni-Holm correction: contrast(r, con1, adjust = "holm")

Or… is the test for Aim 2 a separate test? I may be thinking too much of fMRI but was thinking of two additional factors, one in which spouse trials = 1 and generic grief trials = -1, and a second one in which spouse trials = -1 and generic grief trials = 1, which could be used as predictors to test the effect of spouse > generic grief (or versa).

Aim 3 options

Aim 3: To identify whether effects of intranasal oxytocin differ in high-severity [CG group] versus low-severity [Non-CG group] participants.

As in Aim 1, this could involve any of the three potential tests (RM-ANOVA, linear regression, linear mixed effects), except that the data for this analysis includes data from both placebo and oxytocin sessions and the two-level factor treatment is included as an additional predictor.

If using push and pull RTs rather than bias scores, this would potentially yield a 4-way interaction (stimulus*direction*treatment*group) which is not so desirable from a statistical power and interpretability standpoint. There isn’t likely to be one, so I think I would first run the most complex model, then drop predictors that don’t significantly improve the model fit to the data (as judged by AIC, BIC, log likelihood stats). The other option would be to test push and pull in separate models and correct your alpha for the number of tests, but this means that the models aren’t conditioned on both directions being included - not clear what impact this has and how important it is.

Data visualization

library(tidyverse)
library(jtools)
# load in data
varstoadd <- readRDS("~/Dropbox/GLASS Lab/OT Study/data/master-dataset/ot-fmri_master-dataset_020719.rds")
varstoadd <- subset(varstoadd, select=c(ID, # participant ID
                                        sex_m, # sex (female as reference category)
                                        age_yrs, # age in years
                                        ethnicity_hisp,  # ethnicity (non-Hispanic as reference category)
                                        race, # race
                                        timesincedeath, # time since partner's death and baseline survey completion
                                        yrs_together, # relationship length in years
                                        group, # CG or NCG, based on tot_icg >25 as threshold for CG
                                        tx_v1, # whether they received oxytocin or placebo at first session
                                        tot_icg # grief severity (Inventory of Complicated Grief)
))
data_bias <-  readRDS("~/Dropbox/GLASS Lab/OT gAAT for meeting 5-10-19/bias_long.rds")
data_bias <- left_join(data_bias, varstoadd, by="ID")
data_long <-  readRDS("~/Dropbox/GLASS Lab/OT gAAT for meeting 5-10-19/bx_long_noOut.rds")
data_long <- left_join(data_long, varstoadd, by="ID")
# panel by stimulus
panelbystim <- ggplot(data_bias, aes(fill=cond, y=bias, x=group)) + 
  geom_boxplot(aes(fill=cond), outlier.alpha = 0.3)
p1 <- panelbystim + facet_grid(. ~ stimulus) +  theme(strip.text.x = element_text(size=12, color="red",
                                      face="bold.italic"),
          strip.text.y = element_text(size=12, color="red",
                                      face="bold.italic")) + geom_hline(yintercept=0, linetype="solid", color="black", size=.5) + xlab("Group") + ylab("Avoid bias                Approach bias")
p1

# ggsave("~/Desktop/p1.png", units="in", width=6.5, height=4)
# while (!is.null(dev.list()))  dev.off()
# panel by group
panelbystim <- ggplot(data_bias, aes(fill=cond, y=bias, x=stimulus)) + 
  geom_boxplot(aes(fill=cond), outlier.alpha = 0.3)
p2 <- panelbystim + facet_grid(. ~ group) +  theme(strip.text.x = element_text(size=12, color="red",
                                      face="bold.italic"),
          strip.text.y = element_text(size=12, color="red",
                                      face="bold.italic")) + geom_hline(yintercept=0, linetype="solid", color="black", size=.5) + xlab("Group") + ylab("Avoid bias                Approach bias")
p2

# ggsave("~/Desktop/p2.png", units="in", width=6.5, height=4)
# while (!is.null(dev.list()))  dev.off()
# three-way interaction
m <- lm(bias ~ stimulus*cond*tot_icg, data=data_bias)
summary(m)

Call:
lm(formula = bias ~ stimulus * cond * tot_icg, data = data_bias)

Residuals:
     Min       1Q   Median       3Q      Max 
-248.321  -43.880   -0.662   39.729  266.863 

Coefficients:
                               Estimate Std. Error t value Pr(>|t|)  
(Intercept)                     31.5257    22.9905   1.371   0.1711  
stimulusliving                  23.2035    32.5135   0.714   0.4759  
stimulusneutral                 -0.9685    32.5135  -0.030   0.9763  
stimulusspouse                  28.9937    32.5135   0.892   0.3731  
stimulusstranger                 8.2273    32.5135   0.253   0.8004  
condB                          -42.0367    32.5135  -1.293   0.1969  
tot_icg                         -1.8163     0.8676  -2.094   0.0370 *
stimulusliving:condB           -19.8412    45.9811  -0.432   0.6663  
stimulusneutral:condB           15.9719    45.9811   0.347   0.7285  
stimulusspouse:condB            16.8846    45.9811   0.367   0.7137  
stimulusstranger:condB          27.6590    45.9811   0.602   0.5479  
stimulusliving:tot_icg           0.8932     1.2269   0.728   0.4671  
stimulusneutral:tot_icg          0.6291     1.2269   0.513   0.6084  
stimulusspouse:tot_icg           0.9065     1.2269   0.739   0.4605  
stimulusstranger:tot_icg         0.2014     1.2269   0.164   0.8697  
condB:tot_icg                    2.1973     1.2269   1.791   0.0741 .
stimulusliving:condB:tot_icg    -0.0194     1.7351  -0.011   0.9911  
stimulusneutral:condB:tot_icg   -1.2411     1.7351  -0.715   0.4749  
stimulusspouse:condB:tot_icg    -0.6886     1.7351  -0.397   0.6917  
stimulusstranger:condB:tot_icg  -1.4459     1.7351  -0.833   0.4052  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 67.54 on 370 degrees of freedom
Multiple R-squared:  0.1146,    Adjusted R-squared:  0.06916 
F-statistic: 2.521 on 19 and 370 DF,  p-value: 0.0004856
interact_plot(m, pred="tot_icg", modx = "cond", plot.points=T, jitter=0.1, point.shape=T)

Appendix: Data cleaning

The scripts below generate the data files used in the analyses above.

Pre-R steps:

  1. Removed all .iqdat files under 25KB or so in order to filter out pilot data and false starts.
  2. Removed non-study data (i.e., tests and OT undergrad files).
  3. Organized raw .iqdat files for each visit by run 1/run 2 (two separate folders) based on date/time stamp.

    In Terminal, within each of the folders in turn…

  4. Changed file extensions to .tsv (tab-separated) from .iqdat: find . -iname "*.iqdat" -exec bash -c 'mv "$0" "${0%\.iqdat}.tsv"' {} \;
  5. Merged the files: cat *.tsv > OT_gAAT_run-1.tsv (or OT_gAAT_run-2.tsv)
Notes:
  • D117: Had 3 visits due to scanner technical issues. Use “_b" and “_c" as visit 1 and visit 2 respectively.
  • D114: Has multiple files from visit 2. Use the last two.
  • D135: Use files from 6/06/16 and 6/17/18 (scanner issues on 06/13/16). Use “_b" and “_c" as visit 1 and visit 2 respectively.
  • D147: Visit 1 run 2 is partial data for some reason (I do have notes that she switched back to PUSH-YELLOW during run 2, but did not re-run because running way over time.)

Long dataset (trial-level RTs)

Import data

library(tidyverse)
filter <- dplyr::filter
select <- dplyr::select

# read in the data (only importing a subset of columns)
raw_r1 <- as_data_frame(read_tsv("~/Dropbox/GLASS Lab/OT Study/data/raw-data/OT-gAAT-behavioral-data/Run1_tsv/OT_gAAT_run-1.tsv", col_types=cols_only(
  date = col_integer(),
  time = col_character(),
  subject = col_character(),
  blockcode = col_character(),
  blocknum = col_character(),
  trialcode = col_character(),
  values.trialcode = col_character(),
  values.stimulus = col_character(),
  values.initialresponse = col_character(),
  values.RT = col_number()
)))

raw_r2 <- as_tibble(read_tsv("~/Dropbox/GLASS Lab/OT Study/data/raw-data/OT-gAAT-behavioral-data/Run2_tsv/OT_gAAT_run-2.tsv", col_types=cols_only(
  date = col_integer(),
  time = col_character(),
  subject = col_character(),
  blockcode = col_character(),
  blocknum = col_character(),
  trialcode = col_character(),
  values.trialcode = col_character(),
  values.stimulus = col_character(),
  values.initialresponse = col_character(),
  values.RT = col_number()
)))

# header line repeats when I used `cat` to merge, so get those out of there
raw_r1 <- raw_r1 %>% filter(!is.na(date))
raw_r2 <- raw_r2 %>% filter(!is.na(date))

unique(raw_r1$subject)
# D118 is showing up as "test" for some reason (checked against the .iqdat file), and D130_b is missing
# both of D130's and D142's visits were entered as "D130"/"D142", so change the subject ID for the visit on 052416 to D130_b and on 
raw_r1$subject[raw_r1$date == 020916] <- "D118"
raw_r1$subject[raw_r1$date == 052416] <- "D130_b"
raw_r1$subject[raw_r1$date == 111516] <- "D142_b"

# fixing some other stuff in a similar vein
raw_r1$subject[raw_r1$subject == "D101_2"] <- "D101_b"
raw_r1$subject[raw_r1$subject == "D102_B"] <- "D102_b"
raw_r1$subject[raw_r1$subject == "D117_b"] <- "D117"
raw_r1$subject[raw_r1$subject == "D117_c"] <- "D117_b"
raw_r1$subject[raw_r1$subject == "D135_c"] <- "D135_b"

length(unique(raw_r1$subject)) # 78 unique - that is correct

unique(raw_r2$subject)
# some similar issues to fix
raw_r2$subject[raw_r2$subject == "D101_2Y"] <- "D101_b"
raw_r2$subject[raw_r2$subject == "D102_B"] <- "D102_b"
raw_r2$subject[raw_r2$subject == "D107_B_2"] <- "D107_b"
raw_r2$subject[raw_r2$subject == "D117_b"] <- "D117"
raw_r2$subject[raw_r2$subject == "D117_c"] <- "D117_b"
raw_r2$subject[raw_r2$subject == "D126_B"] <- "D126_b"
raw_r2$subject[raw_r2$subject == "D135_c"] <- "D135_b"
raw_r2$subject[raw_r2$date == 111516] <- "D142_b"

length(unique(raw_r2$subject)) # 78 unique - that is correct

str(raw_r1)
str(raw_r2)
# take out ITIs
unique(raw_r1$trialcode)
mlm_r1 <- filter(raw_r1, grepl("^A",trialcode))
unique(mlm_r1$trialcode)

unique(raw_r2$trialcode)
mlm_r2 <- filter(raw_r2, grepl("^A",trialcode))
unique(mlm_r2$trialcode)

# add a "trialnum" variable, grouped by ID
mlm_r1 <- mlm_r1 %>% group_by(subject) %>% mutate(trialnum = row_number())
View(mlm_r1)
mlm_r2 <- mlm_r2 %>% group_by(subject) %>% mutate(trialnum = row_number())
View(mlm_r2)

mlm_r1 %>% group_by(subject) %>% count() # everyone has 144 trials
mlm_r2 %>% group_by(subject) %>% count() # everyone has 144 trials, except D122_b has 177
# no clue why that happened, although I do vaguely remember we had one session where the task seemed to go on and on and we force quit it?

# remove trials 145-177 for D122_b:
mlm_r2 <- filter(mlm_r2, trialnum <=144)
mlm_r2 %>% group_by(subject) %>% count()
# now everyone has 144 trials

# add a column for "run"
mlm_r1$run <- "1"
mlm_r2$run <- "2"

# add a column for "visit"
mlm_r1$visit <- as.factor(ifelse(grepl("*_b", mlm_r1$subject), "2", "1"))
mlm_r2$visit <- as.factor(ifelse(grepl("*_b", mlm_r2$subject), "2", "1"))

mlm_r1 %>% group_by(subject, visit, run) %>% count() # all looks good: everyone has 144 trials for each run at each visit
mlm_r2 %>% group_by(subject, visit, run) %>% count() # all looks good: everyone has 144 trials for each run at each visit

# now remove the "_b" from visit 2 IDs
mlm_r1 <- mlm_r1 %>% ungroup() %>%
  mutate(subject = str_replace(subject, "_b", ""))
unique(mlm_r1$subject)

mlm_r2 <- mlm_r2 %>% ungroup() %>%
  mutate(subject = str_replace(subject, "_b", ""))
unique(mlm_r2$subject)

# merge data from the 2 runs 
bx <- bind_rows(mlm_r1, mlm_r2)

# split up by visit
bx_v1 <- bx %>% filter(visit == "1")
bx_v2 <- bx %>% filter(visit == "2")

bx_v1 %>% group_by(subject, run) %>% count() # everyone has 144 trials for each run at visit 1
bx_v2 %>% group_by(subject, run) %>% count() # everyone has 144 trials for each run at visit 2
# add columns for "cond" at visit 1 and visit 2 [condition: A/placebo or B/oxytocin]
# load in the randomization data
randomize <- readRDS("~/Dropbox/GLASS Lab/OT Study/data/cleaned-data/randomization.rds")
str(randomize)

bx_v1 <- bx_v1 %>%
  rename("ID" = subject)

bx_v2 <- bx_v2 %>%
  rename("ID" = subject)

# get the IDs for everyone who got treatment A at visit 1 
IDs_v1_txA <- randomize %>% filter(tx_v1 == "A") 
txA_list <- IDs_v1_txA$ID
txA_list

# ifelse statement: if ID = any of those listed in txA_list, make cond_v1 = "A", else make it "B"
bx_v1 <- bx_v1 %>%
  mutate(cond_v1 = as.factor(ifelse(ID == "D101" | ID == "D105" | ID == "D109" | ID == "D110" | ID == "D114" | ID == "D115" | ID == "D116" | ID == "D118" | ID == "D119" | ID == "D120" | ID == "D123" | ID == "D124" | ID == "D126" | ID == "D128" | ID == "D132" | ID == "D135" | ID == "D136" | ID == "D137" | ID == "D138" | ID == "D140" | ID == "D141" | ID == "D145" | ID == "D148" | ID == "D149" | ID == "D117", "A", "B")), cond_v2 = as.factor(ifelse(ID == "D101" | ID == "D105" | ID == "D109" | ID == "D110" | ID == "D114" | ID == "D115" | ID == "D116" | ID == "D118" | ID == "D119" | ID == "D120" | ID == "D123" | ID == "D124" | ID == "D126" | ID == "D128" | ID == "D132" | ID == "D135" | ID == "D136" | ID == "D137" | ID == "D138" | ID == "D140" | ID == "D141" | ID == "D145" | ID == "D148" | ID == "D149" | ID == "D117", "B", "A")))

# ifelse statement: if ID = any of those listed in txA_list, make cond_v2 = "B", else make it "A" (people who were A at visit 1 should be B for visit 2, and vice versa)
bx_v2 <- bx_v2 %>%
  mutate(cond_v2 = as.factor(ifelse(ID == "D101" | ID == "D105" | ID == "D109" | ID == "D110" | ID == "D114" | ID == "D115" | ID == "D116" | ID == "D118" | ID == "D119" | ID == "D120" | ID == "D123" | ID == "D124" | ID == "D126" | ID == "D128" | ID == "D132" | ID == "D135" | ID == "D136" | ID == "D137" | ID == "D138" | ID == "D140" | ID == "D141" | ID == "D145" | ID == "D148" | ID == "D149" | ID == "D117", "B", "A")), cond_v1 = as.factor(ifelse(ID == "D101" | ID == "D105" | ID == "D109" | ID == "D110" | ID == "D114" | ID == "D115" | ID == "D116" | ID == "D118" | ID == "D119" | ID == "D120" | ID == "D123" | ID == "D124" | ID == "D126" | ID == "D128" | ID == "D132" | ID == "D135" | ID == "D136" | ID == "D137" | ID == "D138" | ID == "D140" | ID == "D141" | ID == "D145" | ID == "D148" | ID == "D149" | ID == "D117", "A", "B")))

levels(bx_v1$cond_v1)
levels(bx_v2$cond_v2)

head(bx_v1)

txA_list
bx_v1 %>% group_by(cond_v1) %>% count(ID) # IDs and cond match txA_list *note that some IDs from the randomization dataset are listed in txA but not in the behavioral data. This is because some participants were dropped or never ended up completing their experimental session: D109 (dropped after 1st session), D116 and D136 (never enrolled), D124 (incidental finding, excluded after T1MPRAGE).
bx_v2 %>% group_by(cond_v2) %>% count(ID) # IDs and cond match txA_list

bx_long <- bind_rows(bx_v1,bx_v2)
View(bx_long)
# rename some variables
colnames(bx_long)
bx_long <- bx_long %>% rename("push_pull" = values.initialresponse,
                              "gAAT_RT" = values.RT)
head(bx_long)

# add a new variable for condition
bx_long <- bx_long %>% mutate(cond = as.factor(ifelse(cond_v1 == "A" & visit == "1", "A",
                                                      ifelse(cond_v2 == "A" & visit == "2", "A",
                                                             ifelse(cond_v1 == "B" & visit == "1", "B",
                                                                    ifelse(cond_v2 == "B" & visit == "2", "B", NA))))))

View(bx_long) # check that it coded the "cond" column correctly      

# add a new variable for stimulus category
# in values.stimulus:
# 1 = spouse, 2 = living loved one/WHOTO, 3 = stranger, 4 = nomothetic death-related, 5 = neutral images

sort(unique(bx_long$values.stimulus))

bx_long <- bx_long %>%
  mutate(stim = as.factor(ifelse(values.stimulus == "1B_1.jpg"|values.stimulus == "1B_2.jpg"|values.stimulus == "1B_3.jpg"|values.stimulus == "1Y_1.jpg"|values.stimulus == "1Y_2.jpg"|values.stimulus == "1Y_3.jpg", "spouse", 
                                 ifelse(values.stimulus == "2B_1.jpg"|values.stimulus == "2B_2.jpg"|values.stimulus == "2B_3.jpg"|values.stimulus == "2Y_1.jpg"|values.stimulus == "2Y_2.jpg"|values.stimulus == "2Y_3.jpg", "living",
                                        ifelse(values.stimulus == "3B_1.jpg"|values.stimulus == "3B_2.jpg"|values.stimulus == "3B_3.jpg"|values.stimulus == "3Y_1.jpg"|values.stimulus == "3Y_2.jpg"|values.stimulus == "3Y_3.jpg", "stranger",
                                               ifelse(values.stimulus == "4B_1.jpg"|values.stimulus == "4B_2.jpg"|values.stimulus == "4B_3.jpg"|values.stimulus == "4Y_1.jpg"|values.stimulus == "4Y_2.jpg"|values.stimulus == "4Y_3.jpg", "death",
                                                      ifelse(values.stimulus == "5B_1.jpg"|values.stimulus == "5B_2.jpg"|values.stimulus == "5B_3.jpg"|values.stimulus == "5Y_1.jpg"|values.stimulus == "5Y_2.jpg"|values.stimulus == "5Y_3.jpg", "neutral", NA)))))))

levels(bx_long$stim)
bx_long$stim <- relevel(bx_long$stim, ref = "neutral") # make neutral the reference level

# save it
saveRDS(bx_long, "~/Dropbox/GLASS Lab/OT gAAT for meeting 5-10-19/bx_long.rds")

Remove outliers

Outlier removal follows conventions from other gAAT papers, which exclude trials with RTs that are equal to or above the 99th percentile (calculated from the sample as a whole) or equal to or below 1st percentile.

# calculate percentiles separately for placebo/oxytocin conditions
bx_pl <- bx_long %>% filter(cond == "A")
bx_ot <- bx_long %>% filter(cond == "B")
p99pl <- quantile(bx_pl$gAAT_RT, 0.99) # 1716.76 ms
p01pl <- quantile(bx_pl$gAAT_RT, 0.01) # 463 ms
p99ot <- quantile(bx_ot$gAAT_RT, 0.99) # 1711.07 ms
p01ot <- quantile(bx_ot$gAAT_RT, 0.01) # 473 ms

# identify placebo condition outliers
bx_pl <- bx_pl %>%
  mutate(outlier_RT = ifelse(gAAT_RT <= p01pl | gAAT_RT >= p99pl, 1, 0))
table(bx_pl$outlier_RT) 
227/11005 # about 2% of trials are outliers

# identify oxytocin condition outliers
bx_ot <- bx_ot %>%
  mutate(outlier_RT = ifelse(gAAT_RT <= p01ot | gAAT_RT >= p99ot, 1, 0))
table(bx_ot$outlier_RT) 
229/11003 # about 2% of trials are outliers

bx_long_noOut <- bind_rows(bx_pl, bx_ot) %>% filter(outlier_RT == 0)

dim(bx_long)
dim(bx_long_noOut)  # after outliers removed, there are 22008 trials total of the original 22464: 22464 - (227+229) = 22008

saveRDS(bx_long_noOut, "~/Dropbox/GLASS Lab/OT gAAT for meeting 5-10-19/bx_long_noOut.rds")

Check data and distribution

library(psych)

# how much missing data is there?
ntrials <- bx_long_noOut %>% group_by(ID, cond) %>% count() # don't group by push_pull because peopled pulled/pushed on different numbers of trials, for ex. responses in the wrong direction
describe(ntrials$n/288) # everyone has at least 90% of the 288 trials expected at each visit (no more than 10% trials dropped because of outliers or missed responses)

describe(bx_long_noOut$gAAT_RT) # skewness is 1.17, kurtosis is 1.7
hist(bx_long_noOut$gAAT_RT) # distribution is skewed, as usual for RT data...
qqnorm(bx_long_noOut$gAAT_RT) # and skewness is reflected in QQ plot

Bias scores (based on median RTs)

# creating a wide dataset with the bias variables, which will then be converted back to a long dataset
# The arguments to spread():
# - data: Data object
# - key: Name of column containing the new column names
# - value: Name of column containing values
data_wide <- spread(bx_long_noOut, key=stim, value=gAAT_RT)
colnames(data_wide)
View(data_wide)

# subset by condition and direction
data_pushA <- data_wide %>% select(ID, cond, push_pull, visit, neutral, death, living, spouse, stranger) %>% filter(cond == "A" & push_pull == "PUSH") %>% group_by(ID) %>% mutate(neutralApush = median(neutral, na.rm = TRUE), deathApush = median(death, na.rm = TRUE), spouseApush = median(spouse, na.rm=TRUE), livingApush = median(living, na.rm=TRUE), strangerApush = median(stranger, na.rm=TRUE))

data_pullA <- data_wide %>% select(ID, cond, push_pull, visit, neutral, death, living, spouse, stranger) %>% filter(cond == "A" & push_pull == "PULL") %>% group_by(ID) %>% mutate(neutralApull = median(neutral, na.rm = TRUE), deathApull = median(death, na.rm = TRUE), spouseApull = median(spouse, na.rm=TRUE), livingApull = median(living, na.rm=TRUE), strangerApull = median(stranger, na.rm=TRUE))

data_pushB <- data_wide %>% select(ID, cond, push_pull, visit, neutral, death, living, spouse, stranger) %>% filter(cond == "B" & push_pull == "PUSH") %>% group_by(ID) %>% mutate(neutralBpush = median(neutral, na.rm = TRUE), deathBpush = median(death, na.rm = TRUE), spouseBpush = median(spouse, na.rm=TRUE), livingBpush = median(living, na.rm=TRUE), strangerBpush = median(stranger, na.rm=TRUE))

data_pullB <- data_wide %>% select(ID, cond, push_pull, visit, neutral, death, living, spouse, stranger) %>% filter(cond == "B" & push_pull == "PULL") %>% group_by(ID) %>% mutate(neutralBpull = median(neutral, na.rm = TRUE), deathBpull = median(death, na.rm = TRUE), spouseBpull = median(spouse, na.rm=TRUE), livingBpull = median(living, na.rm=TRUE), strangerBpull = median(stranger, na.rm=TRUE))

# summarize by ID
data_pushA1 <- data_pushA[!duplicated(data_pushA$ID), ] %>% select(-c(neutral, death, living, spouse, stranger, visit, cond, push_pull))
data_pushB1 <- data_pushB[!duplicated(data_pushB$ID), ] %>% select(-c(neutral, death, living, spouse, stranger, visit, cond, push_pull))
data_pullA1 <- data_pullA[!duplicated(data_pullA$ID), ] %>% select(-c(neutral, death, living, spouse, stranger, visit, cond, push_pull))
data_pullB1 <- data_pullB[!duplicated(data_pullB$ID), ] %>% select(-c(neutral, death, living, spouse, stranger, visit, cond, push_pull))

# merge the 4 subsets together
join1 <- left_join(data_pushA1, data_pushB1, by="ID")
join2 <- left_join(join1, data_pullA1, by = "ID")
bias <- left_join(join2, data_pullB1, by = "ID")
head(bias)

bias <- bias %>% mutate(bias_neu_A = neutralApush - neutralApull,
                        bias_dea_A = deathApush - deathApull,
                        bias_spo_A = spouseApush - spouseApull,
                        bias_str_A = strangerApush - strangerApull,
                        bias_liv_A = livingApush - livingApull,
                        bias_neu_B = neutralBpush - neutralBpull,
                        bias_dea_B = deathBpush - deathBpull,
                        bias_spo_B = spouseBpush - spouseBpull,
                        bias_str_B = strangerBpush - strangerBpull,
                        bias_liv_B = livingBpush - livingBpull
)

# drop the condition/stim specific variables
bias <- bias %>% select(-c(neutralApush, deathApush,  spouseApush,  livingApush, strangerApush, neutralBpush, deathBpush,   spouseBpush,  livingBpush,  strangerBpush, neutralApull, deathApull, spouseApull, livingApull, strangerApull, neutralBpull, deathBpull, spouseBpull, livingBpull, strangerBpull))
colnames(bias)

# turn it into a long dataset
bias_long <- gather(bias,
                    key = "stim",
                    value = "bias", -c(ID)) 
head(bias_long)



# create new columns for stimulus category and condition
bias_long$cond <- as.factor(ifelse(grepl("*_A", bias_long$stim), "A", "B"))
bias_long$stimulus <- as.factor(ifelse(grepl("*neu*", bias_long$stim), "neutral", 
                                       ifelse(grepl("*dea*", bias_long$stim), "death",
                                              ifelse(grepl("*spo*", bias_long$stim), "spouse", 
                                                     ifelse(grepl("*str*", bias_long$stim), "stranger", 
                                                            ifelse(grepl("*liv*", bias_long$stim), "living", NA))))))

bias_long <- bias_long %>% select(-stim) # no longer need the "stim" variable

Check data and distribution

describe(bias_long$bias) # skewness is -.01, kurtosis is 1.34, M = 14.04, SD = 70.01
hist(bias_long$bias) # normal distribution
qqnorm(bias_long$bias) # definitely some outliers

# check out the outliers
## function from https://stackoverflow.com/questions/12866189/calculating-the-outliers-in-r
outfun <- function(x) {
  abs(x-mean(x,na.rm=TRUE)) > 3*sd(x,na.rm=TRUE)
}

# add a variable for outlier = T/F
bias_long$outlier <- outfun(bias_long$bias)
table(bias_long$outlier) # 4 observations where outlier = TRUE (>3SD)
# which are these?
bias_long %>% filter(outlier==TRUE)

### this is another way to do it using boxplot.stats
# outlier_values <- boxplot.stats(medians_long$bias)$out
# boxplot(data_long$bias, main="Outliers", boxwex=0.3)
# mtext(paste("Outlying values: ", paste(round(outlier_values, digits=2), collapse=", ")), cex=0.9, side=1)

saveRDS(bias_long, "~/Dropbox/GLASS Lab/OT gAAT for meeting 5-10-19/bias_long.rds")
The four extreme outliers (>3 SD) are:
    D137 death A (-284.0) D145 death A (-247.5) D147 death A (233.0) D139 spouse B (275.5)

Trial-level bias scores (for MLM only)

To calculate trial-level bias (aka “compatibility”) scores: separate push minus pull trials, then subtract RT on that trial at run1 from RT on that trial at run2.

bx_long <- readRDS("~/Dropbox/GLASS Lab/OT gAAT for meeting 5-10-19/bx_long.rds")
bx_r1.1 <- bx_long %>% filter(run == "1")
bx_r2.1 <- bx_long %>% filter(run == "2")
tail(bx_r1.1)
tail(bx_r2.1) 
# run1 should line up with run2: "stim" should match (i.e, spouse trials with spouse trials) but push_pull should say PUSH at one run and PULL at the other

# calculate percentiles for outlier removal (run1 and run2)
p99r1 <- quantile(bx_r1.1$gAAT_RT, 0.99) 
p01r1 <- quantile(bx_r1.1$gAAT_RT, 0.01) 
p99r1 # 99th percentile RTs = 1713.38ms 
p01r1 # 1st percentile RTs = 472ms

p99r2 <- quantile(bx_r2.1$gAAT_RT, 0.99) 
p01r2 <- quantile(bx_r2.1$gAAT_RT, 0.01) 
p99r2 # 99th percentile RTs = 1712.45ms 
p01r2 # 1st percentile RTs = 463ms

bx_r1.2 <- bx_r1.1 %>%
  mutate(outlier_RT = ifelse(gAAT_RT <= p01r1 | gAAT_RT >= p99r1, 1, 0))
table(bx_r1.2$outlier_RT) 
227/11005 # 227 trials will be dropped, 11005 will be retained...about 2% of trials.

bx_r2.2 <- bx_r2.1 %>%
  mutate(outlier_RT = ifelse(gAAT_RT <= p01r2 | gAAT_RT >= p99r2, 1, 0))
table(bx_r2.2$outlier_RT) 
230/11002 # 230 trials will be dropped, 11002 will be retained...about 2% of trials.

bx_r1r2 <- bind_cols(bx_r1.2, bx_r2.2)
dim(bx_r1r2)  # after outliers removed, there are 11232 trials total

# make sure that trials in the two runs line up post-merge
head(bx_r1r2) 
tail(bx_r1r2)

# get rid of any trials with outliers in either run1 or run2 
# (need run1/run2 to be the same length so that the trials match up)
bx_r1r2.1 <- bx_r1r2 %>% filter(outlier_RT == "0" & outlier_RT1 == "0") 
count(bx_r1r2.1) # 10790 obs.
10790/11232 # ~96% of trials retained = 4% data excluded

push_pull <- bx_r1r2.1 %>% filter(push_pull == "PUSH" & push_pull1 == "PULL") %>% mutate(bias = (gAAT_RT-gAAT_RT1))
pull_push <- bx_r1r2.1 %>% filter(push_pull == "PULL" & push_pull1 == "PUSH") %>% mutate(bias = (gAAT_RT1-gAAT_RT))
bx_pp <- bind_rows(push_pull,pull_push)

head(bx_pp) # can see from this that D101 (and possibly others) has only a few trials, because they failed to reverse the instructions (i.e., push_pull and push_pull1 columns have the same values instead of PUSH at one and PULL at the other)
# in essence, this removes their "error" trials

bx_pp %>% group_by(ID, cond) %>% count() # yep, this is visible in their *very low* trialcounts:
# D101 A n = 3
# D141 A n = 18
# D147 B n = 1
# D148 A n = 19

As we see from the last part of the script above, 4 participants have extremely low trial counts at one visit or another, due to failure to reverse the instructions. This will be addressed next.

# create a "drop" variable for these 4
bx_pp <- bx_pp %>% mutate(low_n_trials = ifelse(ID == "D101" & cond == "A" | ID == "D141" & cond == "A"| ID == "D148" & cond == "A" | ID == "D147" & cond == "B", 1, 0))

# check whether the rows line up
notlinedup <- bx_pp %>% filter(stim != stim1)
notlinedup
notlinedup <- bx_pp %>% filter(trialcode != trialcode1)
notlinedup
notlinedup <- bx_pp %>% filter(trialnum != trialnum1)
notlinedup
notlinedup <- bx_pp %>% filter(push_pull == push_pull1)
notlinedup
# 0 rows returned; all the rows match. Thus we conclude the rows from the two runs line up.

saveRDS(bx_pp, "~/Dropbox/GLASS Lab/OT gAAT for meeting 5-10-19/bx_long_trialbytrialBias.rds")
LS0tCnRpdGxlOiAiT1QgZ0FBVCBiZWhhdmlvcmFsIGRhdGEgKGZvciBjb25zdWx0KSIKYXV0aG9yOiAiU2FyZW4gU2VlbGV5IgpkYXRlOiAiMDUtMDEtMjAxOSIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBudW1iZXJfc2VjdGlvbnM6IG5vCiAgICB0aGVtZTogcGFwZXIKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogIGh0bWxfZG9jdW1lbnQ6CiAgICBkZl9wcmludDogcGFnZWQKICAgIHRvYzogeWVzCi0tLQojIEFib3V0CgojIyBRdWVzdGlvbnMKKiBXaGljaCBvdXRjb21lIG1ha2VzIHRoZSBtb3N0IHNlbnNlOiBsb29raW5nIGF0IFJUPHN1Yj5QVVNIPC9zdWI+IGFuZCBSVDxzdWI+UFVMTDwvc3ViPiwgb3IgYXQgdGhlIGJpYXMgc2NvcmVzPyAobW9yZSBvZiBhIHF1ZXN0aW9uIGZvciBNRk8gYW5kIEJBKQoqIFdoaWNoIHN0YXRpc3RpY2FsIHRlc3Qocykgd291bGQgYmUgbW9zdCBhcHByb3ByaWF0ZSBmb3IgZWFjaCBhaW0/CiogSWYgbmVlZGVkOiBIb3cgdG8gc2V0IHVwIHBsYW5uZWQgY29udHJhc3RzIGNvcnJlY3RseQoqIFdoaWNoIGNvdmFyaWF0ZXMgdG8gaW5jbHVkZSAoZS5nLiwgY29udHJvbGxpbmcgZm9yIG9yZGVyIGVmZmVjdHMgLSB0aGlzIGlzIG1vcmUgb2YgYSBxdWVzdGlvbiBmb3IgTUZPIGFuZCBCQSBidXQgdGhlcmUgaXMgdGhlIGlzc3VlIG9mIHNhbXBsZSBzaXplIHZzLiBvdmVyZml0dGluZykKCiMjIEF0IGEgZ2xhbmNlCgoqIDM5IGJlcmVhdmVkIHBhcnRpY2lwYW50cwoqIFJhbmRvbWl6ZWQgZG91YmxlLWJsaW5kIHBsYWNlYm8tY29udHJvbGxlZCBjcm9zc292ZXIgZGVzaWduCjx1bD4qIFR3byB0cmVhdG1lbnRzICh0aHVzIHR3byB0aW1lcG9pbnRzKTogb3h5dG9jaW4gb3IgcGxhY2VibzwvdWw+CiogUHJpbWFyeSBvdXRjb21lIGlzIHRhc2sgcGVyZm9ybWFuY2UgKHJlYWN0aW9uIHRpbWUpCiogUHJpbWFyeSBpbmRlcGVuZGVudCB2YXJpYWJsZXMgYXJlIGdyaWVmIHNldmVyaXR5IChjb250aW51b3VzIHNlbGYtcmVwb3J0IHNjb3JlLCBfYW5kL29yXyBjYXRlZ29yaWNhbCBoaWdoLWxvdyksIHRyZWF0bWVudCAob3h5dG9jaW4vcGxhY2VibyksIGFuZCBzdGltdWx1cyAoNSBkaWZmZXJlbnQgY2F0ZWdvcmllcykKCgojIyBTdHVkeSBkZXNjcmlwdGlvbgpUaGlzIHByb2plY3QgdXNlcyBiZWhhdmlvcmFsIGFuZCBzZWxmLXJlcG9ydCBkYXRhIGZyb20gdGhlIHN0dWR5IOKAnFRoZSBlZmZlY3Qgb2YgaW50cmFuYXNhbCBveHl0b2NpbiBvbiBuZXVyYWwgZnVuY3Rpb25pbmcgaW4gd2lkb3coZXIpc+KAnSAoIzE1MDM3NDQ0MjAsIFBJOiBNYXJ5LUZyYW5jZXMgTydDb25ub3IsIENvLVBJOiBCcmlhbiBBcml6bWVuZGkpLiBJdCB3YXMgYSBkb3VibGUtYmxpbmQgcmFuZG9taXplZCBjcm9zc292ZXIgc3R1ZHkgdXNpbmcgYW4gaW50cmFuYXNhbCBveHl0b2NpbiBtYW5pcHVsYXRpb24gYW5kIGFwcHJvYWNoLWF2b2lkYW5jZSB0YXNrIHZhcmlhbnQgKGdyaWVmIEFBVDsgZ0FBVCkgdG8gaW52ZXN0aWdhdGUgY29uZmxpY3RpbmcgYWNjb3VudHMgb2YgbW90aXZhdGVkIGJlaGF2aW9yIGluIHBlb3BsZSB3aXRoIGNvbXBsaWNhdGVkIGdyaWVmLiBFbnJvbGxlZCBwYXJ0aWNpcGFudHMgd2VyZSBvbGRlciBhZHVsdHMgd2hvIGhhZCBleHBlcmllbmNlZCB0aGUgZGVhdGggb2YgYSBzcG91c2Ugb3IgbG9uZy10ZXJtIHJvbWFudGljIHBhcnRuZXIgYmV0d2VlbiA2LTM2IG1vbnRocyBwcmlvciB0byB0aGVpciBwYXJ0aWNpcGF0aW9uLiBTdHJhdGlmaWVkIHNhbXBsaW5nIHdhcyB1c2VkIHRvIGVuc3VyZSBhIHJhbmdlIG9mIGdyaWVmIHN5bXB0b20gc2V2ZXJpdHkgc2NvcmVzIHdhcyByZXByZXNlbnRlZCBpbiB0aGUgc2FtcGxlLgoKUGFydGljaXBhbnRzIGF0dGVuZGVkIHR3byBpZGVudGljYWwgZXhwZXJpbWVudGFsIHNlc3Npb25zLCBhdCB3aGljaCB0aGV5IHJlY2VpdmVkIG9uZSBvZiB0d28gaW50cmFuYXNhbCBzcHJheXMgKG94eXRvY2luIG9yIHBsYWNlYm8pIGFuZCB0aGVuIHRvb2sgcGFydCBpbiBhbiBmTVJJIHNjYW4sIGR1cmluZyB3aGljaCB0aW1lIHRoZXkgY29tcGxldGVkIHRoZSB0YXNrLgoKIyMgVGFzayAoZ0FBVCkKSW4gdGhlIGdBQVQsIGZpdmUgc3RpbXVsdXMgY2F0ZWdvcmllcyB3ZXJlIHByZXNlbnRlZDogCgoxLiBQZXJzb25hbCBwaG90b3Mgb2YgdGhlIGRlY2Vhc2VkIHNwb3VzZSwKMi4gUGVyc29uYWwgcGhvdG9zIG9mIGEgbGl2aW5nIGxvdmVkIG9uZSwgCjMuIFBob3RvcyBvZiBhIGZlbWFsZSBvciBtYWxlIHN0cmFuZ2VyLAo0LiBHcmllZi1yZWxhdGVkIHNjZW5lcywgYW5kIAo1LiBOZXV0cmFsIHNjZW5lcy4gCgpQaG90b3MgcHJvdmlkZWQgYnkgdGhlIHBhcnRpY2lwYW50IHdlcmUgc2Nhbm5lZCxyZXNpemVkLCBhbmQgZnJhbWVkIHdpdGggYmx1ZS95ZWxsb3cgZnJhbWVzIHRvIG1hdGNoIHRoZSBvdGhlciBzdGltdWxpIHVzZWQgaW4gdGhlIHRhc2suIFBob3RvcyBvZiB0aGUgc3RyYW5nZXIgd2VyZSBzZXgtbWF0Y2hlZCB0byB0aGUgcGFydGljaXBhbnQncyBwYXJ0bmVyLiAKClBhcnRpY2lwYW50cyBjb21wbGV0ZWQgdGhlIHRhc2sgdXNpbmcgYSBqb3lzdGljay4gVGhlIHN0aW11bGkgd2VyZSBhbmltYXRlZCBzbyB0aGF0IGEgam95c3RpY2sgcHVzaCB3b3VsZCBtYWtlIHRoZSBpbWFnZSBzbWFsbGVyIChhcyBpZiB0aGV5IHdlcmUgcHVzaGluZyBpdCBhd2F5KSBhbmQgYSBqb3lzdGljayBwdWxsIHdvdWxkIG1ha2UgdGhlIGltYWdlIGxhcmdlciAoYXMgaWYgdGhleSB3ZXJlIGJyaW5naW5nIGl0IGNsb3NlcikuCgpQYXJ0aWNpcGFudHMgd2VyZSBpbnN0cnVjdGVkIHRvIHJlc3BvbmQgZHVyaW5nIHRoZSB0YXNrIHRvIHRoZSBjb2xvciBvZiBhIHBob3RvJ3MgZnJhbWUsIGUuZy4sIF8iKipwdXNoKiogdGhlIGpveXN0aWNrIHdoZW4gdGhlIGZyYW1lIGlzIEJMVUUsICoqcHVsbCoqIHdoZW4gdGhlIGZyYW1lIGlzIFlFTExPVyJfKS4gT25jZSBwYXJ0aWNpcGFudHMgaGFkIGNvbXBsZXRlZCB0aGUgZmlyc3QgcnVuIG9mIHRoZSB0YXNrICgxNDQgdHJpYWxzKSwgdGhleSBjb21wbGV0ZWQgYSBzZWNvbmQgcnVuIHRoYXQgd2FzIGlkZW50aWNhbCB0byB0aGUgZmlyc3QgZXhjZXB0IGZvciB0aGUgaW5zdHJ1Y3Rpb25zLCB3aGljaCB3ZXJlIHJldmVyc2VkIChlLmcuIF8ibm93ICoqcHVzaCoqIHRoZSBqb3lzdGljayBmb3IgWUVMTE9XIGFuZCAqKnB1bGwqKiBmb3IgQkxVRSJfKS4gT3JkZXIgb2YgaW5zdHJ1Y3Rpb25zIHdhcyBjb3VudGVyYmFsYW5jZWQgYWNyb3NzIHBhcnRpY2lwYW50cy4gU3RpbXVsaSB3ZXJlIHByZXNlbnRlZCB2aWEgSW5xdWlzaXQgNCAoMjAxNCksIGluIGEgcHNldWRvcmFuZG9taXplZCBvcmRlciBkZXRlcm1pbmVkIGJ5IGdlbmV0aWMgYWxnb3JpdGhtIHRvIG9wdGltaXplIHN0YXRpc3RpY2FsIHBvd2VyIGFuZCBwc3ljaG9sb2dpY2FsIHZhbGlkaXR5IChXYWdlciAmIE5pY2hvbHMsIDIwMDMpLiBFYWNoIHRyaWFsIGxhc3QgMzAwMG1zLCB3aXRoIDI1MDAgbXMgYWxsb3dlZCBmb3IgcmVzcG9uc2UuIEludGVydHJpYWwgaW50ZXJ2YWwgd2FzIDUwMG1zLgoKIyBBaW1zClRoZXNlIGFyZSB0aGUgcHJpbWFyeSBhaW1zIGZvciB0aGUgcHJvamVjdDoKCjEuIFRvIGlkZW50aWZ5IHdoZXRoZXIgZ3JpZWYgc2V2ZXJpdHkgbW9kZXJhdGVzIGJlaGF2aW9yYWwgcmVzcG9uc2UgdG8gc3BlY2lmaWMgdHlwZXMgb2Ygc3RpbXVsaSwgY29tcGFyaW5nIGhpZ2gtc2V2ZXJpdHkgKENHIGdyb3VwKSBhbmQgbG93LXNldmVyaXR5IChOb24tQ0cgZ3JvdXApIHBhcnRpY2lwYW50cy4KPHVsPjxpPjFhLiBBbHRlcm5hdGl2ZWx5OiBUbyBpZGVudGlmeSB3aGV0aGVyIHRoZSBjb250aW51b3VzIG1lYXN1cmUgb2YgZ3JpZWYgc2V2ZXJpdHkgbW9kZXJhdGVzIGJlaGF2aW9yYWwgcmVzcG9uc2UgdG8gc3BlY2lmaWMgdHlwZXMgb2Ygc3RpbXVsaS48L2k+PC91bD4KMi4gVG8gaWRlbnRpZnkgd2hldGhlciBiZXJlYXZlZCBpbmRpdmlkdWFscyBzaG93IGRpZmZlcmVudCBiZWhhdmlvcmFsIHJlc3BvbnNlcyB3aGVuIGdyaWVmLXJlbGF0ZWQgc3RpbXVsaSBhcmUgaWRpb2dyYXBoaWMgKHBlcnNvbmFsIHBob3RvcyBvZiBzcG91c2UpIHZlcnN1cyBub21vdGhldGljIChnZW5lcmljIGdyaWVmLXJlbGF0ZWQgc2NlbmVzKS4KMy4gVG8gaWRlbnRpZnkgd2hldGhlciBlZmZlY3RzIG9mIGludHJhbmFzYWwgb3h5dG9jaW4gZGlmZmVyIGluIGhpZ2gtc2V2ZXJpdHkgW0NHIGdyb3VwXSB2ZXJzdXMgbG93LXNldmVyaXR5IFtOb24tQ0cgZ3JvdXBdIHBhcnRpY2lwYW50cy4KPHVsPjxpPjNhLiBBbHRlcm5hdGl2ZWx5OiBUbyBpZGVudGlmeSB3aGV0aGVyIHRoZSBjb250aW51b3VzIG1lYXN1cmUgb2YgZ3JpZWYgc2V2ZXJpdHkgbW9kZXJhdGVzIGVmZmVjdHMgb2Ygb3h5dG9jaW4gb24gdGFzayBwZXJmb3JtYW5jZS48L2k+PC91bD4KCldlIGFsc28gd2FudGVkIHRvIHRlc3Qgd2hldGhlciBhbnkgb2JzZXJ2ZWQgbW9kZXJhdGlvbiBvZiBveHl0b2NpbiBlZmZlY3RzIGdyaWVmIHNldmVyaXR5IHdvdWxkIGJlIHNwZWNpZmljIHRvIGNlcnRhaW4gdHlwZXMgb2Ygc3RpbXVsaS4gSG93ZXZlciwgd2UgbGlrZWx5IGxhY2sgcG93ZXIgdG8gZGV0ZWN0IGEgdGhyZWUtd2F5IGludGVyYWN0aW9uIGluIHRoZSBleGlzdGluZyBzYW1wbGUuCgojIEFuYWx5c2VzCiMjIFByZXZpb3VzIHN0dWRpZXMnIGFwcHJvYWNoZXMKCl9Ob3RlIHRoYXQgdGhlIGV4cGVyaW1lbnRhbCBkZXNpZ24gZm9yIHRoZSBwcmVzZW50IHN0dWR5IGlzIG5vdCBpZGVudGljYWwgdG8gdGhlIHN0dWRpZXMgYmVsb3cuXwoKKiBNYWNjYWxsdW0gZXQgYWwsIDIwMTU6Cjx1bD48bGk+QU5PVkFzIHdpdGggZGlyZWN0aW9uIChwdXNoIG9yIHB1bGwpIGFuZCBzdGltdWx1cyBhcyBwcmVkaWN0b3JzLCBhbmQgbWVkaWFuIHJlYWN0aW9uIHRpbWUgYXMgb3V0Y29tZS48L2xpPgo8bGk+QmlhcyBzY29yZXMgd2VyZSBub3QgdXNlZCBhcyBhbiBvdXRjb21lLCBidXQgZ3JvdXAgbWVhbnMgYXJlIHByZXNlbnRlZCAoVGFibGUgMikuPC9saT48L3VsPgo8cD4KKiBFaXNtYSBldCBhbCwgMjAxNToKPHVsPjxsaT5NdWx0aXBsZSByZWdyZXNzaW9uIGFuYWx5c2VzIChhIHNlcGFyYXRlIG1vZGVsIGZvciBlYWNoIHN0aW11bHVzIGNhdGVnb3J5KSB3aXRoIGJpYXMgc2NvcmUgYXMgb3V0Y29tZSBhbmQgc2VsZi1yZXBvcnRlZCBydW1pbmF0aW9uIGFzIHByZWRpY3Rvci48L2xpPjwvdWw+CgpJbiBib3RoIHBhcGVycywgYmlhcyBzY29yZXMgd2VyZSBjb21wdXRlZCBhcyAobWVkaWFuIFJUPHN1Yj5wdXNoPC9zdWI+IC0gbWVkaWFuIFJUPHN1Yj5wdWxsPC9zdWI+KSBpbiBlYWNoIHN0aW11bHVzIGNhdGVnb3J5LgoKIyMgVmFyaWFibGVzCgoKKiBgSURgIC0gcGFydGljaXBhbnQgSUQKCiMjIyMjUHJlZGljdG9yczoKCiogYHRyZWF0bWVudGAgLSB0cmVhdG1lbnQgcmVjZWl2ZWQgKG94eXRvY2luIG9yIHBsYWNlYm8pPGJyPgoqIGBkaXJlY3Rpb25gIC0gZGlyZWN0aW9uIG9mIHRoZWlyIHJlc3BvbnNlIChfcHVzaF8gb3IgX3B1bGxfKTxicj4KKiBgc3RpbXVsdXNgIC0gdGhlIHR5cGUgb2YgaW1hZ2UgdGhleSBzYXcgKHNwb3VzZSwgbGl2aW5nIGxvdmVkIG9uZSwgc3RyYW5nZXIsIGdlbmVyaWMgZ3JpZWYtcmVsYXRlZCwgbmV1dHJhbCk8YnI+CiogYGdyaWVmX3NldmVyaXR5YCAtIGNvbnRpbnVvdXMgbWVhc3VyZSBvZiBzZWxmLXJlcG9ydGVkIGNvbXBsaWNhdGVkIGdyaWVmIHN5bXB0b21zPGJyPgoqIGBncm91cGAgLSBjb21wbGljYXRlZCBncmllZiAoQ0cpIG9yIG5vbi1jb21wbGljYXRlZCBncmllZiAoTkNHKSwgYmFzZWQgb24gYGdyaWVmX3NldmVyaXR5YCA+MjUKCiMjIyMjT3V0Y29tZXM6CgoqIGBnQUFUX1JUYCAtIHJlYWN0aW9uIHRpbWUgaW4gbXM8YnI+CiogYGdBQVRfYmlhc2AgLSBkaWZmZXJlbmNlIGJldHdlZW4gcHVzaCBhbmQgcHVsbCByZWFjdGlvbiB0aW1lcyAocG9zaXRpdmUgdmFsdWVzIGluZGljYXRlIGFwcHJvYWNoIGJpYXMsIG5lZ2F0aXZlIHZhbHVlcyBpbmRpY2F0ZSBhdm9pZGFuY2UgYmlhcykKCgojIyBBaW0gMSBvcHRpb25zCj5BaW0gMTogVG8gaWRlbnRpZnkgd2hldGhlciBncmllZiBzZXZlcml0eSBtb2RlcmF0ZXMgYmVoYXZpb3JhbCByZXNwb25zZSB0byBzcGVjaWZpYyB0eXBlcyBvZiBzdGltdWxpLCBjb21wYXJpbmcgaGlnaC1zZXZlcml0eSAoQ0cgZ3JvdXApIGFuZCBsb3ctc2V2ZXJpdHkgKE5vbi1DRyBncm91cCkgcGFydGljaXBhbnRzLgoKIyMjIE9wdGlvbiBBOiBSTS1BTk9WQQoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGFmZXgpCmxpYnJhcnkoZW1tZWFucykKZmlsdGVyIDwtIGRwbHlyOjpmaWx0ZXIKc2VsZWN0IDwtIGRwbHlyOjpzZWxlY3QKCiMgcmVhZCBpbiBiZWhhdmlvcmFsIGRhdGEgKGxvbmcgZGF0YXNldCBjb250YWluaW5nIHRyaWFsLWxldmVsIHJlYWN0aW9uIHRpbWVzKQpkYXRhX2xvbmcgPC0gIHJlYWRSRFMoIn4vRHJvcGJveC9HTEFTUyBMYWIvT1QgZ0FBVCBmb3IgbWVldGluZyA1LTEwLTE5L2J4X2xvbmdfbm9PdXQucmRzIikKIyByZWFkIGluIG1hc3RlciBkYXRhc2V0IGFuZCBzdWJzZXQgdmFyaWFibGVzIHRvIGFkZCB0byBiZWhhdmlvcmFsIGRhdGFzZXQKIyB2YXJzdG9hZGQgPC0gcmVhZFJEUygifi9Ecm9wYm94L0dMQVNTIExhYi9PVCBTdHVkeS9kYXRhL21hc3Rlci1kYXRhc2V0L290LWZtcmlfbWFzdGVyLWRhdGFzZXRfMDIwNzE5LnJkcyIpCiMgdmFyc3RvYWRkIDwtIHN1YnNldCh2YXJzdG9hZGQsIHNlbGVjdD1jKElELCAjIHBhcnRpY2lwYW50IElECiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2V4X20sICMgc2V4IChmZW1hbGUgYXMgcmVmZXJlbmNlIGNhdGVnb3J5KQojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFnZV95cnMsICMgYWdlIGluIHllYXJzCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXRobmljaXR5X2hpc3AsICAjIGV0aG5pY2l0eSAobm9uLUhpc3BhbmljIGFzIHJlZmVyZW5jZSBjYXRlZ29yeSkKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYWNlLCAjIHJhY2UKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aW1lc2luY2VkZWF0aCwgIyB0aW1lIHNpbmNlIHBhcnRuZXIncyBkZWF0aCBhbmQgYmFzZWxpbmUgc3VydmV5IGNvbXBsZXRpb24KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5cnNfdG9nZXRoZXIsICMgcmVsYXRpb25zaGlwIGxlbmd0aCBpbiB5ZWFycwojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwLCAjIENHIG9yIE5DRywgYmFzZWQgb24gdG90X2ljZyA+MjUgYXMgdGhyZXNob2xkIGZvciBDRwojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR4X3YxLCAjIHdoZXRoZXIgdGhleSByZWNlaXZlZCBveHl0b2NpbiBvciBwbGFjZWJvIGF0IGZpcnN0IHNlc3Npb24KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b3RfaWNnICMgZ3JpZWYgc2V2ZXJpdHkgKEludmVudG9yeSBvZiBDb21wbGljYXRlZCBHcmllZikKIyApKQojIHNhdmVSRFModmFyc3RvYWRkLCAifi9Ecm9wYm94L0dMQVNTIExhYi9PVCBnQUFUIGZvciBtZWV0aW5nIDUtMTAtMTkvdmFyc3RvYWRkLnJkcyIpCiMgYWxyZWFkeSBzYXZlZCB0aGUgc3Vic2V0LCBzbyBqdXN0IHJlYWQgaW4gdGhlIHN1YnNldDoKCnZhcnN0b2FkZCA8LSByZWFkUkRTKCJ+L0Ryb3Bib3gvR0xBU1MgTGFiL09UIGdBQVQgZm9yIG1lZXRpbmcgNS0xMC0xOS92YXJzdG9hZGQucmRzIikKCgojIyMjIyMjIyMjIE1PREVMIDEgIyMjIyMjIyMjIwojIE1vZGVsIDEgcmVxdWlyZXMgYSBzdGFja2VkL2xvbmcgZGF0YXNldCBjb250YWluaW5nIHRoZSBmb2xsb3dpbmcsIGF0IG1pbmltdW06CiMjIG9uZSB2YXJpYWJsZSBgSURgIHdpdGggcGFydGljaXBhbnQgSURzCiMjIG9uZSBudW1lcmljIHZhcmlhYmxlIGBnQUFUX1JUYCB3aXRoIFRSSUFMLUxFVkVMIHJlYWN0aW9uIHRpbWVzCiMjIG9uZSBmYWN0b3IgYHN0aW11bHVzYCB3aXRoIDUgbGV2ZWxzIChzcG91c2UsIHN0cmFuZ2VyLCBsb3ZlZCBvbmUsIGdyaWVmIHNjZW5lcywgbmV1dHJhbCBzY2VuZXMpCiMjIG9uZSBmYWN0b3IgYHRyZWF0bWVudGAgd2l0aCAyIGxldmVscyAob3h5dG9jaW4sIHBsYWNlYm8pCiMjIG9uZSBmYWN0b3IgYGRpcmVjdGlvbmAgd2l0aCAyIGxldmVscyAocHVzaCwgcHVsbCkKIyMgb25lIGZhY3RvciBgZ3JvdXBgIHdpdGggMiBmYWN0b3JzIChDRywgTkNHKSAqT1IqIG9uZSBudW1lcmljIHZhcmlhYmxlIGBncmllZl9zY29yZWAgd2l0aCBpbmRpdmlkdWFsIGdyaWVmIHNldmVyaXR5IHNjb3JlcyAodGltZS1pbnZhcmlhbnQpCgpkYXRhX2xvbmcgPC0gbGVmdF9qb2luKGRhdGFfbG9uZywgdmFyc3RvYWRkLCBJRD0iSUQiKSAjIHZhcnN0b2FkZCA9IHN1YnNldCBvZiBtYXN0ZXIgZGF0YXNldApkYXRhX3BsYWNlYm8gPC0gZGF0YV9sb25nICU+JSByZW5hbWUodHJlYXRtZW50ID0gY29uZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0aW11bHVzID0gc3RpbSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9IHB1c2hfcHVsbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyaWVmX3NldmVyaXR5ID0gdG90X2ljZykgJT4lCiAgbXV0YXRlKHRyZWF0bWVudCA9IHJlY29kZSh0cmVhdG1lbnQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgQSA9ICJwbGFjZWJvIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIEIgPSAib3h5dG9jaW4iKSkgJT4lCiAgZmlsdGVyKHRyZWF0bWVudCA9PSAicGxhY2VibyIpIApoZWFkKGRhdGFfcGxhY2VibykKCgojIE1vZGVsIDE6IFJNLUFOT1ZBIHdpdGggdHdvIHdpdGhpbi1zdWJqZWN0cyBmYWN0b3JzIChzdGltdWx1cywgcHVzaCBvciBwdWxsKSBhbmQgb25lIGJldHdlZW4tc3ViamVjdHMgZmFjdG9yIChncm91cCkKbTEgPC0gYW92X2V6KGlkID0gIklEIiwgZHYgPSAiZ0FBVF9SVCIsIGRhdGFfcGxhY2VibywgYmV0d2VlbiA9ICJncm91cCIsIHdpdGhpbiA9IGMoInN0aW11bHVzIiwgImRpcmVjdGlvbiIpLCBmdW5fYWdncmVnYXRlID0gbWVkaWFuKSAjIG9yIHVzZSBiZXR3ZWVuID0gImdyaWVmX3NldmVyaXR5IiBmb3IgZ3JpZWYgc2V2ZXJpdHkgYXMgY29udGludW91cyB2cy4gY2F0ZWdvcmljYWwKc3VtbWFyeShtMSkgCgojIHVzZSB0aGUgYGVtbWVhbnNgIHBhY2thZ2UgdG8gY29uZHVjdCBwYWlyd2lzZSBjb21wYXJpc29ucyAKIyAoZW1tZWFucyBpcyB0aGUgc2FtZSB0aGluZyBhcyBsc21lYW5zIGFuZCBwbW1lYW5zLCBqdXN0IGRpZmZlcmVudCB0ZXJtcykKIyBuZWVkIHRvIGRvdWJsZS1jaGVjayB0aGF0IEknbSBkb2luZyB0aGlzIGNvcnJlY3RseS4uLgplbW1lYW5zKG0xLCB+YyhkaXJlY3Rpb24sIHN0aW11bHVzKSwgY29udHIgPSAicGFpcndpc2UiLCBhZGp1c3Q9ImhvbG0iKQoKIyMjIyMjIyMjIyBNT0RFTCAyICMjIyMjIyMjIyMKIyBNb2RlbCAyIHJlcXVpcmVzIGEgc3RhY2tlZC9sb25nIGRhdGFzZXQgY29udGFpbmluZyB0aGUgZm9sbG93aW5nLCBhdCBtaW5pbXVtOgojIyBvbmUgdmFyaWFibGUgYElEYCB3aXRoIHBhcnRpY2lwYW50IElEcwojIyBvbmUgbnVtZXJpYyB2YXJpYWJsZSBgZ0FBVF9iaWFzYCB3aXRoIHBhcnRpY2lwYW50cycgcHVzaC1wdWxsIGRpZmZlcmVuY2Ugc2NvcmVzIGZvciBlYWNoIHN0aW11bHVzIHggdHJlYXRtZW50IGxldmVsCiMjIGUuZy4sIG1lZGlhbiBwdXNoIFJUIHRvIGRlYXRoIHN0aW11bGkgdW5kZXIgcGxhY2VibyBNSU5VUyBtZWRpYW4gcHVsbCBSVCB0byBkZWF0aCBzdGltdWxpIHVuZGVyIHBsYWNlYm8KIyMgb25lIGZhY3RvciBgc3RpbXVsdXNgIHdpdGggNSBsZXZlbHMgKHNwb3VzZSwgc3RyYW5nZXIsIGxvdmVkIG9uZSwgZ3JpZWYgc2NlbmVzLCBuZXV0cmFsIHNjZW5lcykKIyMgb25lIGZhY3RvciBgdHJlYXRtZW50YCB3aXRoIDIgbGV2ZWxzIChveHl0b2NpbiwgcGxhY2VibykKIyMgb25lIGZhY3RvciBgZGlyZWN0aW9uYCB3aXRoIDIgbGV2ZWxzIChwdXNoLCBwdWxsKQojIyBvbmUgZmFjdG9yIGBncm91cGAgd2l0aCAyIGZhY3RvcnMgKENHLCBOQ0cpICpPUiogb25lIG51bWVyaWMgdmFyaWFibGUgYGdyaWVmX3Njb3JlYCB3aXRoIGluZGl2aWR1YWwgZ3JpZWYgc2V2ZXJpdHkgc2NvcmVzICh0aW1lLWludmFyaWFudCkKCmRhdGFfYmlhcyA8LSAgcmVhZFJEUygifi9Ecm9wYm94L0dMQVNTIExhYi9PVCBnQUFUIGZvciBtZWV0aW5nIDUtMTAtMTkvYmlhc19sb25nLnJkcyIpCmRhdGFfYmlhcyA8LSBsZWZ0X2pvaW4oZGF0YV9iaWFzLCB2YXJzdG9hZGQsIGJ5PSJJRCIpCiAgIyBOT1RFIHRoYXQgdGhpcyBpcyB0aGUgZGF0YXNldCB0aGF0IGNhbGN1bGF0ZXMgYmlhcyBieSBzdWJ0cmFjdGluZyB0aGUgbWVkaWFuIHB1bGwgcmVhY3Rpb24gdGltZSBpbiBlYWNoIGNhdGVnb3J5IGZyb20gdGhlIG1lZGlhbiBwdXNoIHJlYWN0aW9uIHRpbWUgaW4gdGhhdCBjYXRlZ29yeSAoTk9UIHRoZSB0cmlhbC1ieS10cmlhbCBiaWFzIHN1YnRyYWN0aW5nIHJ1bjEgZnJvbSBydW4yKQogIApkYXRhX2JpYXNfcGxhY2VibyA8LSBkYXRhX2JpYXMgJT4lIAogIHJlbmFtZSh0cmVhdG1lbnQgPSBjb25kLAogICAgICAgICBnQUFUX2JpYXMgPSBiaWFzKSAlPiUgCiAgbXV0YXRlKHRyZWF0bWVudCA9IHJlY29kZSh0cmVhdG1lbnQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgQSA9ICJwbGFjZWJvIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIEIgPSAib3h5dG9jaW4iKSkgJT4lCiAgZmlsdGVyKHRyZWF0bWVudCA9PSAicGxhY2VibyIpIAoKCiMgTW9kZWwgMjogUk0tQU5PVkEgd2l0aCBvbmUgd2l0aGluLXN1YmplY3RzIGZhY3RvciAoc3RpbXVsdXMpIGFuZCBvbmUgYmV0d2Vlbi1zdWJqZWN0cyBmYWN0b3IgKGdyb3VwKQptMiA8LSBhb3ZfZXooaWQgPSAiSUQiLCBkdiA9ICJnQUFUX2JpYXMiLCBkYXRhX2JpYXNfcGxhY2VibywgYmV0d2VlbiA9ICJncm91cCIsIHdpdGhpbiA9IGMoInN0aW11bHVzIikpICMgb3IgdXNlIGJldHdlZW4gPSAiZ3JpZWZfc2V2ZXJpdHkiIGZvciBncmllZiBzZXZlcml0eSBhcyBjb250aW51b3VzIHZzLiBjYXRlZ29yaWNhbApzdW1tYXJ5KG0yKQoKIyB1c2UgdGhlIGBlbW1lYW5zYCBwYWNrYWdlIHRvIGNvbmR1Y3QgcGFpcndpc2UgY29tcGFyaXNvbnMgCiMgKGVtbWVhbnMgaXMgdGhlIHNhbWUgdGhpbmcgYXMgbHNtZWFucyBhbmQgcG1tZWFucywganVzdCBkaWZmZXJlbnQgdGVybXMpCiMgbmVlZCB0byBkb3VibGUtY2hlY2sgdGhhdCBJJ20gZG9pbmcgdGhpcyBjb3JyZWN0bHkuLi4KZW1tZWFucyhtMiwgfnN0aW11bHVzLCBjb250ciA9ICJwYWlyd2lzZSIsIGFkanVzdD0iaG9sbSIpCmVtbWVhbnMobTIsIH5ncm91cCwgY29udHIgPSAicGFpcndpc2UiLCBhZGp1c3Q9ImhvbG0iKQoKCiMgYWRkaXRpb25hbCBjb3ZhcmlhdGVzIHN1Y2ggYXMgcGFydGljaXBhbnQgYWdlLCB0YXNrIHJ1biAoZmlyc3Qgb3Igc2Vjb25kKSwgZXRjLiBtYXkgYmUgaW5jbHVkZWQgaW4gZmluYWwgbW9kZWwKYGBgCgojIyMgT3B0aW9uIEI6IE11bHRpcGxlIHJlZ3Jlc3Npb24KYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpmaWx0ZXIgPC0gZHBseXI6OmZpbHRlcgpzZWxlY3QgPC0gZHBseXI6OnNlbGVjdAoKIyMjIyMjIyMjIyBNT0RFTCAxICMjIyMjIyMjIyMKIyBNb2RlbCAxIHJlcXVpcmVzIGEgc3RhY2tlZC9sb25nIGRhdGFzZXQgY29udGFpbmluZyB0aGUgZm9sbG93aW5nLCBhdCBtaW5pbXVtOgojIyBvbmUgdmFyaWFibGUgYElEYCB3aXRoIHBhcnRpY2lwYW50IElEcwojIyBvbmUgbnVtZXJpYyB2YXJpYWJsZSBgZ0FBVF9SVGAgd2l0aCBUUklBTC1MRVZFTCByZWFjdGlvbiB0aW1lcwojIyBvbmUgZmFjdG9yIGBzdGltdWx1c2Agd2l0aCA1IGxldmVscyAoc3BvdXNlLCBzdHJhbmdlciwgbG92ZWQgb25lLCBncmllZiBzY2VuZXMsIG5ldXRyYWwgc2NlbmVzKQojIyBvbmUgZmFjdG9yIGB0cmVhdG1lbnRgIHdpdGggMiBsZXZlbHMgKG94eXRvY2luLCBwbGFjZWJvKQojIyBvbmUgZmFjdG9yIGBkaXJlY3Rpb25gIHdpdGggMiBsZXZlbHMgKHB1c2gsIHB1bGwpCiMjIG9uZSBmYWN0b3IgYHJ1bmAgd2l0aCAyIGxldmVscyAoZmlyc3QsIHNlY29uZCkKIyMgb25lIGZhY3RvciBgZ3JvdXBgIHdpdGggMiBmYWN0b3JzIChDRywgTkNHKSAqT1IqIG9uZSBudW1lcmljIHZhcmlhYmxlIGBncmllZl9zY29yZWAgd2l0aCBpbmRpdmlkdWFsIGdyaWVmIHNldmVyaXR5IHNjb3JlcyAodGltZS1pbnZhcmlhbnQpCgojIE1vZGVsIDE6CiMgTXVsdGlwbGUgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgc3BlY2lmeWluZyB0aHJlZS13YXkgaW50ZXJhY3Rpb24gZWZmZWN0IG9uIG1lZGlhbiBwdXNoIGFuZCBwdWxsIHJlYWN0aW9uIHRpbWVzCm0xIDwtIGxtKGdBQVRfUlQgfiBzdGltdWx1cypkaXJlY3Rpb24sIGRhdGE9ZGF0YV9wbGFjZWJvKSAjIG9yIHVzZSBgZ3JpZWZfc2V2ZXJpdHlgIGluc3RlYWQgb2YgYGdyb3VwYApzdW1tYXJ5KG0xKQoKIyMjIyMjIyMjIyBNT0RFTCAyICMjIyMjIyMjIyMKIyBNb2RlbCAyIHJlcXVpcmVzIGEgc3RhY2tlZC9sb25nIGRhdGFzZXQgY29udGFpbmluZyB0aGUgZm9sbG93aW5nLCBhdCBtaW5pbXVtOgojIyBvbmUgdmFyaWFibGUgYElEYCB3aXRoIHBhcnRpY2lwYW50IElEcwojIyBvbmUgbnVtZXJpYyB2YXJpYWJsZSBgZ0FBVF9iaWFzYCB3aXRoIHBhcnRpY2lwYW50cycgcHVzaC1wdWxsIGRpZmZlcmVuY2Ugc2NvcmVzIGZvciBlYWNoIHN0aW11bHVzIHggdHJlYXRtZW50IGxldmVsCiMjIGUuZy4sIG1lZGlhbiBwdXNoIFJUIHRvIGRlYXRoIHN0aW11bGkgdW5kZXIgcGxhY2VibyBNSU5VUyBtZWRpYW4gcHVsbCBSVCB0byBkZWF0aCBzdGltdWxpIHVuZGVyIHBsYWNlYm8KIyMgb25lIGZhY3RvciBgc3RpbXVsdXNgIHdpdGggNSBsZXZlbHMgKHNwb3VzZSwgc3RyYW5nZXIsIGxvdmVkIG9uZSwgZ3JpZWYgc2NlbmVzLCBuZXV0cmFsIHNjZW5lcykKIyMgb25lIGZhY3RvciBgdHJlYXRtZW50YCB3aXRoIDIgbGV2ZWxzIChveHl0b2NpbiwgcGxhY2VibykKIyMgb25lIGZhY3RvciBgZGlyZWN0aW9uYCB3aXRoIDIgbGV2ZWxzIChwdXNoLCBwdWxsKQojIyBvbmUgZmFjdG9yIGBncm91cGAgd2l0aCAyIGZhY3RvcnMgKENHLCBOQ0cpICpPUiogb25lIG51bWVyaWMgdmFyaWFibGUgYGdyaWVmX3Njb3JlYCB3aXRoIGluZGl2aWR1YWwgZ3JpZWYgc2V2ZXJpdHkgc2NvcmVzICh0aW1lLWludmFyaWFudCkKCiMgTW9kZWwgMjoKIyBNdWx0aXBsZSBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbCBzcGVjaWZ5aW5nIHR3by13YXkgaW50ZXJhY3Rpb24gZWZmZWN0IG9uIGJpYXMgc2NvcmVzCm0yIDwtIGxtKGdBQVRfYmlhcyB+IHN0aW11bHVzKmdyb3VwLCBkYXRhPWRhdGFfYmlhc19wbGFjZWJvKSAjIG9yIHVzZSBgZ3JpZWZfc2V2ZXJpdHlgIGluc3RlYWQgb2YgYGdyb3VwYApzdW1tYXJ5KG0yKQoKIyBhZGRpdGlvbmFsIGNvdmFyaWF0ZXMgc3VjaCBhcyBwYXJ0aWNpcGFudCBhZ2UsIHRhc2sgcnVuIChmaXJzdCBvciBzZWNvbmQpLCBldGMuIG1heSBiZSBpbmNsdWRlZCBpbiBmaW5hbCBtb2RlbApgYGAKCgojIyMgT3B0aW9uIEM6IE1peGVkIGVmZmVjdHMgbW9kZWwKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KG5sbWUpCmZpbHRlciA8LSBkcGx5cjo6ZmlsdGVyCnNlbGVjdCA8LSBkcGx5cjo6c2VsZWN0CgojIyMjIyMjIyMjIE1PREVMIDEgIyMjIyMjIyMjIwojIE1vZGVsIDEgcmVxdWlyZXMgYSBzdGFja2VkL2xvbmcgZGF0YXNldCBjb250YWluaW5nIHRoZSBmb2xsb3dpbmcsIGF0IG1pbmltdW06CiMjIG9uZSB2YXJpYWJsZSBgSURgIHdpdGggcGFydGljaXBhbnQgSURzCiMjIG9uZSBudW1lcmljIHZhcmlhYmxlIGBnQUFUX1JUYCB3aXRoIFRSSUFMLUxFVkVMIHJlYWN0aW9uIHRpbWVzCiMjIG9uZSBmYWN0b3IgYHN0aW11bHVzYCB3aXRoIDUgbGV2ZWxzIChzcG91c2UsIHN0cmFuZ2VyLCBsb3ZlZCBvbmUsIGdyaWVmIHNjZW5lcywgbmV1dHJhbCBzY2VuZXMpCiMjIG9uZSBmYWN0b3IgYHRyZWF0bWVudGAgd2l0aCAyIGxldmVscyAob3h5dG9jaW4sIHBsYWNlYm8pCiMjIG9uZSBmYWN0b3IgYGRpcmVjdGlvbmAgd2l0aCAyIGxldmVscyAocHVzaCwgcHVsbCkKIyMgb25lIGZhY3RvciBgcnVuYCB3aXRoIDIgbGV2ZWxzIChmaXJzdCwgc2Vjb25kKQojIyBvbmUgZmFjdG9yIGBncm91cGAgd2l0aCAyIGZhY3RvcnMgKENHLCBOQ0cpICpPUiogb25lIG51bWVyaWMgdmFyaWFibGUgYGdyaWVmX3Njb3JlYCB3aXRoIGluZGl2aWR1YWwgZ3JpZWYgc2V2ZXJpdHkgc2NvcmVzICh0aW1lLWludmFyaWFudCkKCiMgTW9kZWwgMToKIyBNaXhlZCBtb2RlbCBzcGVjaWZ5aW5nIHRocmVlLXdheSBpbnRlcmFjdGlvbiBlZmZlY3Qgb24gbWVkaWFuIHB1c2ggYW5kIHB1bGwgcmVhY3Rpb24gdGltZXMKbTEgPC0gbG1lKGdBQVRfUlQgfiBzdGltdWx1cypkaXJlY3Rpb24qZ3JvdXAsIGRhdGEgPSBkYXRhX3BsYWNlYm8sIHJhbmRvbSA9IH4gMXxJRCwgbWV0aG9kPSJSRU1MIikgIyBvciB1c2UgYGdyaWVmX3NldmVyaXR5YCBpbnN0ZWFkIG9mIGBncm91cGAKc3VtbWFyeShtMSkKCgojIyMjIyMjIyMjIE1PREVMIDIgIyMjIyMjIyMjIwojIE1vZGVsIDIgcmVxdWlyZXMgYSBzdGFja2VkL2xvbmcgZGF0YXNldCBjb250YWluaW5nIHRoZSBmb2xsb3dpbmcsIGF0IG1pbmltdW06CiMjIG9uZSB2YXJpYWJsZSBgSURgIHdpdGggcGFydGljaXBhbnQgSURzCiMjIG9uZSBudW1lcmljIHZhcmlhYmxlIGBnQUFUX2JpYXNgIHdpdGggcGFydGljaXBhbnRzJyBwdXNoLXB1bGwgZGlmZmVyZW5jZSBzY29yZXMgZm9yIGVhY2ggc3RpbXVsdXMgeCB0cmVhdG1lbnQgbGV2ZWwKIyMgZS5nLiwgbWVkaWFuIHB1c2ggUlQgdG8gZGVhdGggc3RpbXVsaSB1bmRlciBwbGFjZWJvIE1JTlVTIG1lZGlhbiBwdWxsIFJUIHRvIGRlYXRoIHN0aW11bGkgdW5kZXIgcGxhY2VibwojIyBvbmUgZmFjdG9yIGBzdGltdWx1c2Agd2l0aCA1IGxldmVscyAoc3BvdXNlLCBzdHJhbmdlciwgbG92ZWQgb25lLCBncmllZiBzY2VuZXMsIG5ldXRyYWwgc2NlbmVzKQojIyBvbmUgZmFjdG9yIGB0cmVhdG1lbnRgIHdpdGggMiBsZXZlbHMgKG94eXRvY2luLCBwbGFjZWJvKQojIyBvbmUgZmFjdG9yIGBkaXJlY3Rpb25gIHdpdGggMiBsZXZlbHMgKHB1c2gsIHB1bGwpCiMjIG9uZSBmYWN0b3IgYGdyb3VwYCB3aXRoIDIgZmFjdG9ycyAoQ0csIE5DRykgKk9SKiBvbmUgbnVtZXJpYyB2YXJpYWJsZSBgZ3JpZWZfc2NvcmVgIHdpdGggaW5kaXZpZHVhbCBncmllZiBzZXZlcml0eSBzY29yZXMgKHRpbWUtaW52YXJpYW50KQoKIyBNb2RlbCAyOgojIE1peGVkIG1vZGVsIHNwZWNpZnlpbmcgdHdvLXdheSBpbnRlcmFjdGlvbiBlZmZlY3Qgb24gYmlhcyBzY29yZXMKbTIgPC0gbG1lKGdBQVRfYmlhcyB+IHN0aW11bHVzKmdyb3VwLCBkYXRhID0gZGF0YV9iaWFzX3BsYWNlYm8sIHJhbmRvbSA9IH4gMXxJRCwgbWV0aG9kPSJSRU1MIikgIyBvciB1c2UgYGdyaWVmX3NldmVyaXR5YCBpbnN0ZWFkIG9mIGBncm91cGAKc3VtbWFyeShtMikKCiMgYWRkaXRpb25hbCBjb3ZhcmlhdGVzIHN1Y2ggYXMgcGFydGljaXBhbnQgYWdlLCB0YXNrIHJ1biAoZmlyc3Qgb3Igc2Vjb25kKSwgZXRjLiBtYXkgYmUgaW5jbHVkZWQgaW4gZmluYWwgbW9kZWwKYGBgCgoKIyMjIE9wdGlvbiBEOiBNdWx0aWxldmVsIGdyb3d0aCBtb2RlbCAoUlVMRUQgT1VUKQpUaGlzIGlzIHdoYXQgSSBkaWQgZm9yIEVtaWx5J3MgY2xhc3MgLSAqKkkgdGhpbmsgd2UgYWxsIGFncmVlZCB0aGF0IHRoaXMgaXMgdW5uZWNjZXNzYXJpbHkgY29tcGxpY2F0ZWQgZ2l2ZW4gdGhhdCB3ZSBhcmUgbm90IGludGVyZXN0ZWQgaW4gdHJpYWwtbGV2ZWwgY2hhbmdlcyBpbiByZWFjdGlvbiB0aW1lIG92ZXIgdGhlIGNvdXJzZSBvZiB0aGUgdGFzay4qKiBJbiB0aGVzZSBhbmFseXNlcywgSSB1bHRpbWF0ZWx5IGVuZGVkIHVwIHJlbW92aW5nIHRpbWUgKHRyaWFsICMpIGFzIGEgcHJlZGljdG9yIGFueXdheSBzaW5jZSB0aGVyZSB3YXMgbm8gZml4ZWQgb3IgcmFuZG9tIGVmZmVjdCBvZiB0aW1lLiAKCkluIHRoaXMgYXBwcm9hY2gsIHdlIGFsc28gZW5kIHVwIGRyb3BwaW5nIG1vcmUgcGFydGljaXBhbnRzIGJlY2F1c2UgZm91ciBwZW9wbGUgZmFpbGVkIHRvIHJldmVyc2UgdGhlIGluc3RydWN0aW9ucyBvbiB0aGVpciBzZWNvbmQgcnVuIG9mIHRoZSB0YXNrIHNvIEkgY291bGQgbm90IHN1YnRyYWN0LCBzYXksIFJUIG9uIHJ1biAyIHRyaWFsICMzMCAoIlBVTEwiKSBmcm9tIFJUIG9uIHJ1biAxIHRyaWFsICMzMCAoIlBVU0giKSBiZWNhdXNlIHRoZXkgcHVzaGVkIChvciBwdWxsZWQpIG9uIHRoYXQgdHJpYWwgb24gYm90aCBydW5zLgoKIyMgQWltIDIgb3B0aW9ucwo+QWltIDI6IFRvIGlkZW50aWZ5IHdoZXRoZXIgYmVyZWF2ZWQgaW5kaXZpZHVhbHMgc2hvdyBkaWZmZXJlbnQgYmVoYXZpb3JhbCByZXNwb25zZXMgd2hlbiBncmllZi1yZWxhdGVkIHN0aW11bGkgYXJlIGlkaW9ncmFwaGljIChwZXJzb25hbCBwaG90b3Mgb2Ygc3BvdXNlKSB2ZXJzdXMgbm9tb3RoZXRpYyAoZ2VuZXJpYyBncmllZi1yZWxhdGVkIHNjZW5lcykuCgpUaGlzIHNob3VsZCBiZSBhIHBsYW5uZWQgY29udHJhc3Qgd2l0aGluIG9uZSBvZiB0aGUgQWltIDEgYW5hbHlzZXMsIEkgdGhpbmsuIFRoZXJlIGlzIGEgd2F5IHRvIHNwZWNpZnkgY29udHJhc3RzIGluIGBubG1lYCB1c2luZyB0aGUgYGNvbnRyYXN0cyA9IGAgYXJndW1lbnQgYnV0IEkgbmVlZCBzb21lIGd1aWRhbmNlIGFzIHRvIGhvdyB0byBjb3JyZWN0bHkgc2V0IHVwIHRoZSBsaXN0IGl0J3MgZXhwZWN0aW5nLgoKVGhpcyBpcyBob3cgeW91IGRvIGl0IGZvciB0aGUgQU5PVkEgdXNpbmcgYGVtbWVhbnNgOgoKYGBgCj9hb3ZfZXoKClRoZSBTMyBvYmplY3QgcmV0dXJuZWQgcGVyIGRlZmF1bHQgY2FuIGJlIGRpcmVjdGx5IHBhc3NlZCB0byBlbW1lYW5zOjplbW1lYW5zIGZvciBmdXJ0aGVyIGFuYWx5c2lzLiBUaGlzIGFsbG93cyB0byB0ZXN0IGFueSB0eXBlIG9mIGNvbnRyYXN0cyB0aGF0IG1pZ2h0IGJlIG9mIGludGVyZXN0IGluZGVwZW5kZW50IG9mIHdoZXRoZXIgb3Igbm90IHRoaXMgY29udHJhc3QgaW52b2x2ZXMgYmV0d2Vlbi1zdWJqZWN0IHZhcmlhYmxlcywgd2l0aGluLXN1YmplY3QgdmFyaWFibGVzLCBvciBhIGNvbWJpbmF0aW9uIHRoZXJlb2YuIFRoZSBnZW5lcmFsIHByb2NlZHVyZSB0byBydW4gdGhvc2UgY29udHJhc3RzIGlzIHRoZSBmb2xsb3dpbmcgKHNlZSBFeGFtcGxlcyBmb3IgYSBmdWxsIGV4YW1wbGUpOgoKKDEpIEVzdGltYXRlIGFuIGFmZXhfYW92IG9iamVjdCB3aXRoIHRoZSBmdW5jdGlvbiByZXR1cm5lZCBoZXJlLiBGb3IgZXhhbXBsZTogeCA8LSBhb3ZfY2FyKGR2IH4gYSpiICsgKGlkL2MpLCBkKQoKKDIpIE9idGFpbiBhIGVtbUdyaWQtY2xhc3Mgb2JqZWN0IGJ5IHJ1bm5pbmcgZW1tZWFucyBvbiB0aGUgYWZleF9hb3Ygb2JqZWN0IGZyb20gc3RlcCAxIHVzaW5nIHRoZSBmYWN0b3JzIGludm9sdmVkIGluIHRoZSBjb250cmFzdC4gRm9yIGV4YW1wbGU6IHIgPC0gZW1tZWFucyh4LCB+YTpjKQoKKDMpIENyZWF0ZSBhIGxpc3QgY29udGFpbmluZyB0aGUgZGVzaXJlZCBjb250cmFzdHMgb24gdGhlIHJlZmVyZW5jZSBncmlkIG9iamVjdCBmcm9tIHN0ZXAgMi4gRm9yIGV4YW1wbGU6IApjb24xIDwtIGxpc3QoYV94ID0gYygtMSwgMSwgMCwgMCwgMCwgMCksIGJfeCA9IGMoMCwgMCwgLTAuNSwgLTAuNSwgMCwgMSkpCgooNCkgVGVzdCB0aGUgY29udHJhc3Qgb24gdGhlIHJlZmVyZW5jZSBncmlkIHVzaW5nIGNvbnRyYXN0LiBGb3IgZXhhbXBsZTogY29udHJhc3QociwgY29uMSkKClRvIGNvbnRyb2wgZm9yIG11bHRpcGxlIHRlc3RpbmcgcC12YWx1ZSBhZGp1c3RtZW50cyBjYW4gYmUgc3BlY2lmaWVkLiBGb3IgZXhhbXBsZSB0aGUgQm9uZmVycm9uaS1Ib2xtIGNvcnJlY3Rpb246IGNvbnRyYXN0KHIsIGNvbjEsIGFkanVzdCA9ICJob2xtIikKYGBgCgpPci4uLiBpcyB0aGUgdGVzdCBmb3IgQWltIDIgYSBzZXBhcmF0ZSB0ZXN0PyBJIG1heSBiZSB0aGlua2luZyB0b28gbXVjaCBvZiBmTVJJIGJ1dCB3YXMgdGhpbmtpbmcgb2YgdHdvIGFkZGl0aW9uYWwgZmFjdG9ycywgb25lIGluIHdoaWNoIHNwb3VzZSB0cmlhbHMgPSAxIGFuZCBnZW5lcmljIGdyaWVmIHRyaWFscyA9IC0xLCBhbmQgYSBzZWNvbmQgb25lIGluIHdoaWNoIHNwb3VzZSB0cmlhbHMgPSAtMSBhbmQgZ2VuZXJpYyBncmllZiB0cmlhbHMgPSAxLCB3aGljaCBjb3VsZCBiZSB1c2VkIGFzIHByZWRpY3RvcnMgdG8gdGVzdCB0aGUgZWZmZWN0IG9mIHNwb3VzZSA+IGdlbmVyaWMgZ3JpZWYgKG9yIHZlcnNhKS4gCgoKIyMgQWltIDMgb3B0aW9ucwo+QWltIDM6IFRvIGlkZW50aWZ5IHdoZXRoZXIgZWZmZWN0cyBvZiBpbnRyYW5hc2FsIG94eXRvY2luIGRpZmZlciBpbiBoaWdoLXNldmVyaXR5IFtDRyBncm91cF0gdmVyc3VzIGxvdy1zZXZlcml0eSBbTm9uLUNHIGdyb3VwXSBwYXJ0aWNpcGFudHMuCgpBcyBpbiBBaW0gMSwgdGhpcyBjb3VsZCBpbnZvbHZlIGFueSBvZiB0aGUgdGhyZWUgcG90ZW50aWFsIHRlc3RzIChSTS1BTk9WQSwgbGluZWFyIHJlZ3Jlc3Npb24sIGxpbmVhciBtaXhlZCBlZmZlY3RzKSwgZXhjZXB0IHRoYXQgdGhlIGRhdGEgZm9yIHRoaXMgYW5hbHlzaXMgaW5jbHVkZXMgZGF0YSBmcm9tIGJvdGggcGxhY2VibyBhbmQgb3h5dG9jaW4gc2Vzc2lvbnMgYW5kIHRoZSB0d28tbGV2ZWwgZmFjdG9yIGB0cmVhdG1lbnRgIGlzIGluY2x1ZGVkIGFzIGFuIGFkZGl0aW9uYWwgcHJlZGljdG9yLiAKCklmIHVzaW5nIHB1c2ggYW5kIHB1bGwgUlRzIHJhdGhlciB0aGFuIGJpYXMgc2NvcmVzLCB0aGlzIHdvdWxkIHBvdGVudGlhbGx5IHlpZWxkIGEgNC13YXkgaW50ZXJhY3Rpb24gKGBzdGltdWx1cypkaXJlY3Rpb24qdHJlYXRtZW50Kmdyb3VwYCkgd2hpY2ggaXMgbm90IHNvIGRlc2lyYWJsZSBmcm9tIGEgc3RhdGlzdGljYWwgcG93ZXIgYW5kIGludGVycHJldGFiaWxpdHkgc3RhbmRwb2ludC4gVGhlcmUgaXNuJ3QgbGlrZWx5IHRvIGJlIG9uZSwgc28gSSB0aGluayBJIHdvdWxkIGZpcnN0IHJ1biB0aGUgbW9zdCBjb21wbGV4IG1vZGVsLCB0aGVuIGRyb3AgcHJlZGljdG9ycyB0aGF0IGRvbid0IHNpZ25pZmljYW50bHkgaW1wcm92ZSB0aGUgbW9kZWwgZml0IHRvIHRoZSBkYXRhIChhcyBqdWRnZWQgYnkgQUlDLCBCSUMsIGxvZyBsaWtlbGlob29kIHN0YXRzKS4gVGhlIG90aGVyIG9wdGlvbiB3b3VsZCBiZSB0byB0ZXN0IHB1c2ggYW5kIHB1bGwgaW4gc2VwYXJhdGUgbW9kZWxzIGFuZCBjb3JyZWN0IHlvdXIgYWxwaGEgZm9yIHRoZSBudW1iZXIgb2YgdGVzdHMsIGJ1dCB0aGlzIG1lYW5zIHRoYXQgdGhlIG1vZGVscyBhcmVuJ3QgY29uZGl0aW9uZWQgb24gYm90aCBkaXJlY3Rpb25zIGJlaW5nIGluY2x1ZGVkIC0gbm90IGNsZWFyIHdoYXQgaW1wYWN0IHRoaXMgaGFzIGFuZCBob3cgaW1wb3J0YW50IGl0IGlzLgoKCiMgRGF0YSB2aXN1YWxpemF0aW9uCgpgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoanRvb2xzKQoKIyBsb2FkIGluIGRhdGEKdmFyc3RvYWRkIDwtIHJlYWRSRFMoIn4vRHJvcGJveC9HTEFTUyBMYWIvT1QgU3R1ZHkvZGF0YS9tYXN0ZXItZGF0YXNldC9vdC1mbXJpX21hc3Rlci1kYXRhc2V0XzAyMDcxOS5yZHMiKQp2YXJzdG9hZGQgPC0gc3Vic2V0KHZhcnN0b2FkZCwgc2VsZWN0PWMoSUQsICMgcGFydGljaXBhbnQgSUQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNleF9tLCAjIHNleCAoZmVtYWxlIGFzIHJlZmVyZW5jZSBjYXRlZ29yeSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFnZV95cnMsICMgYWdlIGluIHllYXJzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBldGhuaWNpdHlfaGlzcCwgICMgZXRobmljaXR5IChub24tSGlzcGFuaWMgYXMgcmVmZXJlbmNlIGNhdGVnb3J5KQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmFjZSwgIyByYWNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aW1lc2luY2VkZWF0aCwgIyB0aW1lIHNpbmNlIHBhcnRuZXIncyBkZWF0aCBhbmQgYmFzZWxpbmUgc3VydmV5IGNvbXBsZXRpb24KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlyc190b2dldGhlciwgIyByZWxhdGlvbnNoaXAgbGVuZ3RoIGluIHllYXJzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cCwgIyBDRyBvciBOQ0csIGJhc2VkIG9uIHRvdF9pY2cgPjI1IGFzIHRocmVzaG9sZCBmb3IgQ0cKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR4X3YxLCAjIHdoZXRoZXIgdGhleSByZWNlaXZlZCBveHl0b2NpbiBvciBwbGFjZWJvIGF0IGZpcnN0IHNlc3Npb24KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvdF9pY2cgIyBncmllZiBzZXZlcml0eSAoSW52ZW50b3J5IG9mIENvbXBsaWNhdGVkIEdyaWVmKQopKQoKZGF0YV9iaWFzIDwtICByZWFkUkRTKCJ+L0Ryb3Bib3gvR0xBU1MgTGFiL09UIGdBQVQgZm9yIG1lZXRpbmcgNS0xMC0xOS9iaWFzX2xvbmcucmRzIikKZGF0YV9iaWFzIDwtIGxlZnRfam9pbihkYXRhX2JpYXMsIHZhcnN0b2FkZCwgYnk9IklEIikKZGF0YV9sb25nIDwtICByZWFkUkRTKCJ+L0Ryb3Bib3gvR0xBU1MgTGFiL09UIGdBQVQgZm9yIG1lZXRpbmcgNS0xMC0xOS9ieF9sb25nX25vT3V0LnJkcyIpCmRhdGFfbG9uZyA8LSBsZWZ0X2pvaW4oZGF0YV9sb25nLCB2YXJzdG9hZGQsIGJ5PSJJRCIpCgojIHBhbmVsIGJ5IHN0aW11bHVzCnBhbmVsYnlzdGltIDwtIGdncGxvdChkYXRhX2JpYXMsIGFlcyhmaWxsPWNvbmQsIHk9YmlhcywgeD1ncm91cCkpICsgCiAgZ2VvbV9ib3hwbG90KGFlcyhmaWxsPWNvbmQpLCBvdXRsaWVyLmFscGhhID0gMC4zKQpwMSA8LSBwYW5lbGJ5c3RpbSArIGZhY2V0X2dyaWQoLiB+IHN0aW11bHVzKSArICB0aGVtZShzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT0xMiwgY29sb3I9InJlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjZT0iYm9sZC5pdGFsaWMiKSwKICAgICAgICAgIHN0cmlwLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplPTEyLCBjb2xvcj0icmVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWNlPSJib2xkLml0YWxpYyIpKSArIGdlb21faGxpbmUoeWludGVyY2VwdD0wLCBsaW5ldHlwZT0ic29saWQiLCBjb2xvcj0iYmxhY2siLCBzaXplPS41KSArIHhsYWIoIkdyb3VwIikgKyB5bGFiKCJBdm9pZCBiaWFzICAgICAgICAgICAgICAgIEFwcHJvYWNoIGJpYXMiKQpwMQojIGdnc2F2ZSgifi9EZXNrdG9wL3AxLnBuZyIsIHVuaXRzPSJpbiIsIHdpZHRoPTYuNSwgaGVpZ2h0PTQpCiMgd2hpbGUgKCFpcy5udWxsKGRldi5saXN0KCkpKSAgZGV2Lm9mZigpCgojIHBhbmVsIGJ5IGdyb3VwCnBhbmVsYnlzdGltIDwtIGdncGxvdChkYXRhX2JpYXMsIGFlcyhmaWxsPWNvbmQsIHk9YmlhcywgeD1zdGltdWx1cykpICsgCiAgZ2VvbV9ib3hwbG90KGFlcyhmaWxsPWNvbmQpLCBvdXRsaWVyLmFscGhhID0gMC4zKQpwMiA8LSBwYW5lbGJ5c3RpbSArIGZhY2V0X2dyaWQoLiB+IGdyb3VwKSArICB0aGVtZShzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT0xMiwgY29sb3I9InJlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjZT0iYm9sZC5pdGFsaWMiKSwKICAgICAgICAgIHN0cmlwLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplPTEyLCBjb2xvcj0icmVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWNlPSJib2xkLml0YWxpYyIpKSArIGdlb21faGxpbmUoeWludGVyY2VwdD0wLCBsaW5ldHlwZT0ic29saWQiLCBjb2xvcj0iYmxhY2siLCBzaXplPS41KSArIHhsYWIoIkdyb3VwIikgKyB5bGFiKCJBdm9pZCBiaWFzICAgICAgICAgICAgICAgIEFwcHJvYWNoIGJpYXMiKQpwMgojIGdnc2F2ZSgifi9EZXNrdG9wL3AyLnBuZyIsIHVuaXRzPSJpbiIsIHdpZHRoPTYuNSwgaGVpZ2h0PTQpCiMgd2hpbGUgKCFpcy5udWxsKGRldi5saXN0KCkpKSAgZGV2Lm9mZigpCgojIHRocmVlLXdheSBpbnRlcmFjdGlvbgptIDwtIGxtKGJpYXMgfiBzdGltdWx1cypjb25kKnRvdF9pY2csIGRhdGE9ZGF0YV9iaWFzKQpzdW1tYXJ5KG0pCmludGVyYWN0X3Bsb3QobSwgcHJlZD0idG90X2ljZyIsIG1vZHggPSAiY29uZCIsIHBsb3QucG9pbnRzPVQsIGppdHRlcj0wLjEsIHBvaW50LnNoYXBlPVQpCmBgYAoKCgoKCgoKCgoKCgoKIyBBcHBlbmRpeDogRGF0YSBjbGVhbmluZwpUaGUgc2NyaXB0cyBiZWxvdyBnZW5lcmF0ZSB0aGUgZGF0YSBmaWxlcyB1c2VkIGluIHRoZSBhbmFseXNlcyBhYm92ZS4KCjxiPlByZS1SIHN0ZXBzPC9iPjoKCjEuIFJlbW92ZWQgYWxsIC5pcWRhdCBmaWxlcyB1bmRlciAyNUtCIG9yIHNvIGluIG9yZGVyIHRvIGZpbHRlciBvdXQgcGlsb3QgZGF0YSBhbmQgZmFsc2Ugc3RhcnRzLjxicj4KMi4gUmVtb3ZlZCBub24tc3R1ZHkgZGF0YSAoaS5lLiwgdGVzdHMgYW5kIE9UIHVuZGVyZ3JhZCBmaWxlcykuIDxicj4KMy4gT3JnYW5pemVkIHJhdyAuaXFkYXQgZmlsZXMgZm9yIGVhY2ggdmlzaXQgYnkgcnVuIDEvcnVuIDIgKHR3byBzZXBhcmF0ZSBmb2xkZXJzKSBiYXNlZCBvbiBkYXRlL3RpbWUgc3RhbXAuIDxwPgo8aT5JbiBUZXJtaW5hbCwgd2l0aGluIGVhY2ggb2YgdGhlIGZvbGRlcnMgaW4gdHVybi4uLjwvaT48cD4KNC4gQ2hhbmdlZCBmaWxlIGV4dGVuc2lvbnMgdG8gLnRzdiAodGFiLXNlcGFyYXRlZCkgZnJvbSAuaXFkYXQ6IGBmaW5kIC4gLWluYW1lICIqLmlxZGF0IiAtZXhlYyBiYXNoIC1jICdtdiAiJDAiICIkezAlXC5pcWRhdH0udHN2Iicge30gXDtgPGJyPgo1LiBNZXJnZWQgdGhlIGZpbGVzOiBgY2F0ICoudHN2ID4gT1RfZ0FBVF9ydW4tMS50c3ZgIChvciBgT1RfZ0FBVF9ydW4tMi50c3ZgKQoKPGk+Tm90ZXM6PGJyPgo8dWw+PGxpPkQxMTc6IEhhZCAzIHZpc2l0cyBkdWUgdG8gc2Nhbm5lciB0ZWNobmljYWwgaXNzdWVzLiBVc2UgIl9iIiBhbmQgIl9jIiBhcyB2aXNpdCAxIGFuZCB2aXNpdCAyIHJlc3BlY3RpdmVseS48L2xpPgo8bGk+RDExNDogSGFzIG11bHRpcGxlIGZpbGVzIGZyb20gdmlzaXQgMi4gVXNlIHRoZSBsYXN0IHR3by48L2xpPgo8bGk+RDEzNTogVXNlIGZpbGVzIGZyb20gNi8wNi8xNiBhbmQgNi8xNy8xOCAoc2Nhbm5lciBpc3N1ZXMgb24gMDYvMTMvMTYpLiBVc2UgIl9iIiBhbmQgIl9jIiBhcyB2aXNpdCAxIGFuZCB2aXNpdCAyIHJlc3BlY3RpdmVseS48L2xpPgo8bGk+RDE0NzogVmlzaXQgMSBydW4gMiBpcyBwYXJ0aWFsIGRhdGEgZm9yIHNvbWUgcmVhc29uIChJIGRvIGhhdmUgbm90ZXMgdGhhdCBzaGUgc3dpdGNoZWQgYmFjayB0byA8aT5QVVNILVlFTExPVzwvaT4gZHVyaW5nIHJ1biAyLCBidXQgZGlkIG5vdCByZS1ydW4gYmVjYXVzZSBydW5uaW5nIHdheSBvdmVyIHRpbWUuKTwvbGk+PC91bD48L2k+CgojIyBMb25nIGRhdGFzZXQgKHRyaWFsLWxldmVsIFJUcykKIyMjIEltcG9ydCBkYXRhCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKZmlsdGVyIDwtIGRwbHlyOjpmaWx0ZXIKc2VsZWN0IDwtIGRwbHlyOjpzZWxlY3QKCiMgcmVhZCBpbiB0aGUgZGF0YSAob25seSBpbXBvcnRpbmcgYSBzdWJzZXQgb2YgY29sdW1ucykKcmF3X3IxIDwtIGFzX2RhdGFfZnJhbWUocmVhZF90c3YoIn4vRHJvcGJveC9HTEFTUyBMYWIvT1QgU3R1ZHkvZGF0YS9yYXctZGF0YS9PVC1nQUFULWJlaGF2aW9yYWwtZGF0YS9SdW4xX3Rzdi9PVF9nQUFUX3J1bi0xLnRzdiIsIGNvbF90eXBlcz1jb2xzX29ubHkoCiAgZGF0ZSA9IGNvbF9pbnRlZ2VyKCksCiAgdGltZSA9IGNvbF9jaGFyYWN0ZXIoKSwKICBzdWJqZWN0ID0gY29sX2NoYXJhY3RlcigpLAogIGJsb2NrY29kZSA9IGNvbF9jaGFyYWN0ZXIoKSwKICBibG9ja251bSA9IGNvbF9jaGFyYWN0ZXIoKSwKICB0cmlhbGNvZGUgPSBjb2xfY2hhcmFjdGVyKCksCiAgdmFsdWVzLnRyaWFsY29kZSA9IGNvbF9jaGFyYWN0ZXIoKSwKICB2YWx1ZXMuc3RpbXVsdXMgPSBjb2xfY2hhcmFjdGVyKCksCiAgdmFsdWVzLmluaXRpYWxyZXNwb25zZSA9IGNvbF9jaGFyYWN0ZXIoKSwKICB2YWx1ZXMuUlQgPSBjb2xfbnVtYmVyKCkKKSkpCgpyYXdfcjIgPC0gYXNfdGliYmxlKHJlYWRfdHN2KCJ+L0Ryb3Bib3gvR0xBU1MgTGFiL09UIFN0dWR5L2RhdGEvcmF3LWRhdGEvT1QtZ0FBVC1iZWhhdmlvcmFsLWRhdGEvUnVuMl90c3YvT1RfZ0FBVF9ydW4tMi50c3YiLCBjb2xfdHlwZXM9Y29sc19vbmx5KAogIGRhdGUgPSBjb2xfaW50ZWdlcigpLAogIHRpbWUgPSBjb2xfY2hhcmFjdGVyKCksCiAgc3ViamVjdCA9IGNvbF9jaGFyYWN0ZXIoKSwKICBibG9ja2NvZGUgPSBjb2xfY2hhcmFjdGVyKCksCiAgYmxvY2tudW0gPSBjb2xfY2hhcmFjdGVyKCksCiAgdHJpYWxjb2RlID0gY29sX2NoYXJhY3RlcigpLAogIHZhbHVlcy50cmlhbGNvZGUgPSBjb2xfY2hhcmFjdGVyKCksCiAgdmFsdWVzLnN0aW11bHVzID0gY29sX2NoYXJhY3RlcigpLAogIHZhbHVlcy5pbml0aWFscmVzcG9uc2UgPSBjb2xfY2hhcmFjdGVyKCksCiAgdmFsdWVzLlJUID0gY29sX251bWJlcigpCikpKQoKIyBoZWFkZXIgbGluZSByZXBlYXRzIHdoZW4gSSB1c2VkIGBjYXRgIHRvIG1lcmdlLCBzbyBnZXQgdGhvc2Ugb3V0IG9mIHRoZXJlCnJhd19yMSA8LSByYXdfcjEgJT4lIGZpbHRlcighaXMubmEoZGF0ZSkpCnJhd19yMiA8LSByYXdfcjIgJT4lIGZpbHRlcighaXMubmEoZGF0ZSkpCgp1bmlxdWUocmF3X3IxJHN1YmplY3QpCiMgRDExOCBpcyBzaG93aW5nIHVwIGFzICJ0ZXN0IiBmb3Igc29tZSByZWFzb24gKGNoZWNrZWQgYWdhaW5zdCB0aGUgLmlxZGF0IGZpbGUpLCBhbmQgRDEzMF9iIGlzIG1pc3NpbmcKIyBib3RoIG9mIEQxMzAncyBhbmQgRDE0MidzIHZpc2l0cyB3ZXJlIGVudGVyZWQgYXMgIkQxMzAiLyJEMTQyIiwgc28gY2hhbmdlIHRoZSBzdWJqZWN0IElEIGZvciB0aGUgdmlzaXQgb24gMDUyNDE2IHRvIEQxMzBfYiBhbmQgb24gCnJhd19yMSRzdWJqZWN0W3Jhd19yMSRkYXRlID09IDAyMDkxNl0gPC0gIkQxMTgiCnJhd19yMSRzdWJqZWN0W3Jhd19yMSRkYXRlID09IDA1MjQxNl0gPC0gIkQxMzBfYiIKcmF3X3IxJHN1YmplY3RbcmF3X3IxJGRhdGUgPT0gMTExNTE2XSA8LSAiRDE0Ml9iIgoKIyBmaXhpbmcgc29tZSBvdGhlciBzdHVmZiBpbiBhIHNpbWlsYXIgdmVpbgpyYXdfcjEkc3ViamVjdFtyYXdfcjEkc3ViamVjdCA9PSAiRDEwMV8yIl0gPC0gIkQxMDFfYiIKcmF3X3IxJHN1YmplY3RbcmF3X3IxJHN1YmplY3QgPT0gIkQxMDJfQiJdIDwtICJEMTAyX2IiCnJhd19yMSRzdWJqZWN0W3Jhd19yMSRzdWJqZWN0ID09ICJEMTE3X2IiXSA8LSAiRDExNyIKcmF3X3IxJHN1YmplY3RbcmF3X3IxJHN1YmplY3QgPT0gIkQxMTdfYyJdIDwtICJEMTE3X2IiCnJhd19yMSRzdWJqZWN0W3Jhd19yMSRzdWJqZWN0ID09ICJEMTM1X2MiXSA8LSAiRDEzNV9iIgoKbGVuZ3RoKHVuaXF1ZShyYXdfcjEkc3ViamVjdCkpICMgNzggdW5pcXVlIC0gdGhhdCBpcyBjb3JyZWN0Cgp1bmlxdWUocmF3X3IyJHN1YmplY3QpCiMgc29tZSBzaW1pbGFyIGlzc3VlcyB0byBmaXgKcmF3X3IyJHN1YmplY3RbcmF3X3IyJHN1YmplY3QgPT0gIkQxMDFfMlkiXSA8LSAiRDEwMV9iIgpyYXdfcjIkc3ViamVjdFtyYXdfcjIkc3ViamVjdCA9PSAiRDEwMl9CIl0gPC0gIkQxMDJfYiIKcmF3X3IyJHN1YmplY3RbcmF3X3IyJHN1YmplY3QgPT0gIkQxMDdfQl8yIl0gPC0gIkQxMDdfYiIKcmF3X3IyJHN1YmplY3RbcmF3X3IyJHN1YmplY3QgPT0gIkQxMTdfYiJdIDwtICJEMTE3IgpyYXdfcjIkc3ViamVjdFtyYXdfcjIkc3ViamVjdCA9PSAiRDExN19jIl0gPC0gIkQxMTdfYiIKcmF3X3IyJHN1YmplY3RbcmF3X3IyJHN1YmplY3QgPT0gIkQxMjZfQiJdIDwtICJEMTI2X2IiCnJhd19yMiRzdWJqZWN0W3Jhd19yMiRzdWJqZWN0ID09ICJEMTM1X2MiXSA8LSAiRDEzNV9iIgpyYXdfcjIkc3ViamVjdFtyYXdfcjIkZGF0ZSA9PSAxMTE1MTZdIDwtICJEMTQyX2IiCgpsZW5ndGgodW5pcXVlKHJhd19yMiRzdWJqZWN0KSkgIyA3OCB1bmlxdWUgLSB0aGF0IGlzIGNvcnJlY3QKCnN0cihyYXdfcjEpCnN0cihyYXdfcjIpCmBgYAoKYGBge3J9CiMgdGFrZSBvdXQgSVRJcwp1bmlxdWUocmF3X3IxJHRyaWFsY29kZSkKbWxtX3IxIDwtIGZpbHRlcihyYXdfcjEsIGdyZXBsKCJeQSIsdHJpYWxjb2RlKSkKdW5pcXVlKG1sbV9yMSR0cmlhbGNvZGUpCgp1bmlxdWUocmF3X3IyJHRyaWFsY29kZSkKbWxtX3IyIDwtIGZpbHRlcihyYXdfcjIsIGdyZXBsKCJeQSIsdHJpYWxjb2RlKSkKdW5pcXVlKG1sbV9yMiR0cmlhbGNvZGUpCgojIGFkZCBhICJ0cmlhbG51bSIgdmFyaWFibGUsIGdyb3VwZWQgYnkgSUQKbWxtX3IxIDwtIG1sbV9yMSAlPiUgZ3JvdXBfYnkoc3ViamVjdCkgJT4lIG11dGF0ZSh0cmlhbG51bSA9IHJvd19udW1iZXIoKSkKVmlldyhtbG1fcjEpCm1sbV9yMiA8LSBtbG1fcjIgJT4lIGdyb3VwX2J5KHN1YmplY3QpICU+JSBtdXRhdGUodHJpYWxudW0gPSByb3dfbnVtYmVyKCkpClZpZXcobWxtX3IyKQoKbWxtX3IxICU+JSBncm91cF9ieShzdWJqZWN0KSAlPiUgY291bnQoKSAjIGV2ZXJ5b25lIGhhcyAxNDQgdHJpYWxzCm1sbV9yMiAlPiUgZ3JvdXBfYnkoc3ViamVjdCkgJT4lIGNvdW50KCkgIyBldmVyeW9uZSBoYXMgMTQ0IHRyaWFscywgZXhjZXB0IEQxMjJfYiBoYXMgMTc3CiMgbm8gY2x1ZSB3aHkgdGhhdCBoYXBwZW5lZCwgYWx0aG91Z2ggSSBkbyB2YWd1ZWx5IHJlbWVtYmVyIHdlIGhhZCBvbmUgc2Vzc2lvbiB3aGVyZSB0aGUgdGFzayBzZWVtZWQgdG8gZ28gb24gYW5kIG9uIGFuZCB3ZSBmb3JjZSBxdWl0IGl0PwoKIyByZW1vdmUgdHJpYWxzIDE0NS0xNzcgZm9yIEQxMjJfYjoKbWxtX3IyIDwtIGZpbHRlcihtbG1fcjIsIHRyaWFsbnVtIDw9MTQ0KQptbG1fcjIgJT4lIGdyb3VwX2J5KHN1YmplY3QpICU+JSBjb3VudCgpCiMgbm93IGV2ZXJ5b25lIGhhcyAxNDQgdHJpYWxzCgojIGFkZCBhIGNvbHVtbiBmb3IgInJ1biIKbWxtX3IxJHJ1biA8LSAiMSIKbWxtX3IyJHJ1biA8LSAiMiIKCiMgYWRkIGEgY29sdW1uIGZvciAidmlzaXQiCm1sbV9yMSR2aXNpdCA8LSBhcy5mYWN0b3IoaWZlbHNlKGdyZXBsKCIqX2IiLCBtbG1fcjEkc3ViamVjdCksICIyIiwgIjEiKSkKbWxtX3IyJHZpc2l0IDwtIGFzLmZhY3RvcihpZmVsc2UoZ3JlcGwoIipfYiIsIG1sbV9yMiRzdWJqZWN0KSwgIjIiLCAiMSIpKQoKbWxtX3IxICU+JSBncm91cF9ieShzdWJqZWN0LCB2aXNpdCwgcnVuKSAlPiUgY291bnQoKSAjIGFsbCBsb29rcyBnb29kOiBldmVyeW9uZSBoYXMgMTQ0IHRyaWFscyBmb3IgZWFjaCBydW4gYXQgZWFjaCB2aXNpdAptbG1fcjIgJT4lIGdyb3VwX2J5KHN1YmplY3QsIHZpc2l0LCBydW4pICU+JSBjb3VudCgpICMgYWxsIGxvb2tzIGdvb2Q6IGV2ZXJ5b25lIGhhcyAxNDQgdHJpYWxzIGZvciBlYWNoIHJ1biBhdCBlYWNoIHZpc2l0CgojIG5vdyByZW1vdmUgdGhlICJfYiIgZnJvbSB2aXNpdCAyIElEcwptbG1fcjEgPC0gbWxtX3IxICU+JSB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKHN1YmplY3QgPSBzdHJfcmVwbGFjZShzdWJqZWN0LCAiX2IiLCAiIikpCnVuaXF1ZShtbG1fcjEkc3ViamVjdCkKCm1sbV9yMiA8LSBtbG1fcjIgJT4lIHVuZ3JvdXAoKSAlPiUKICBtdXRhdGUoc3ViamVjdCA9IHN0cl9yZXBsYWNlKHN1YmplY3QsICJfYiIsICIiKSkKdW5pcXVlKG1sbV9yMiRzdWJqZWN0KQoKIyBtZXJnZSBkYXRhIGZyb20gdGhlIDIgcnVucyAKYnggPC0gYmluZF9yb3dzKG1sbV9yMSwgbWxtX3IyKQoKIyBzcGxpdCB1cCBieSB2aXNpdApieF92MSA8LSBieCAlPiUgZmlsdGVyKHZpc2l0ID09ICIxIikKYnhfdjIgPC0gYnggJT4lIGZpbHRlcih2aXNpdCA9PSAiMiIpCgpieF92MSAlPiUgZ3JvdXBfYnkoc3ViamVjdCwgcnVuKSAlPiUgY291bnQoKSAjIGV2ZXJ5b25lIGhhcyAxNDQgdHJpYWxzIGZvciBlYWNoIHJ1biBhdCB2aXNpdCAxCmJ4X3YyICU+JSBncm91cF9ieShzdWJqZWN0LCBydW4pICU+JSBjb3VudCgpICMgZXZlcnlvbmUgaGFzIDE0NCB0cmlhbHMgZm9yIGVhY2ggcnVuIGF0IHZpc2l0IDIKYGBgCgpgYGB7cn0KIyBhZGQgY29sdW1ucyBmb3IgImNvbmQiIGF0IHZpc2l0IDEgYW5kIHZpc2l0IDIgW2NvbmRpdGlvbjogQS9wbGFjZWJvIG9yIEIvb3h5dG9jaW5dCiMgbG9hZCBpbiB0aGUgcmFuZG9taXphdGlvbiBkYXRhCnJhbmRvbWl6ZSA8LSByZWFkUkRTKCJ+L0Ryb3Bib3gvR0xBU1MgTGFiL09UIFN0dWR5L2RhdGEvY2xlYW5lZC1kYXRhL3JhbmRvbWl6YXRpb24ucmRzIikKc3RyKHJhbmRvbWl6ZSkKCmJ4X3YxIDwtIGJ4X3YxICU+JQogIHJlbmFtZSgiSUQiID0gc3ViamVjdCkKCmJ4X3YyIDwtIGJ4X3YyICU+JQogIHJlbmFtZSgiSUQiID0gc3ViamVjdCkKCiMgZ2V0IHRoZSBJRHMgZm9yIGV2ZXJ5b25lIHdobyBnb3QgdHJlYXRtZW50IEEgYXQgdmlzaXQgMSAKSURzX3YxX3R4QSA8LSByYW5kb21pemUgJT4lIGZpbHRlcih0eF92MSA9PSAiQSIpIAp0eEFfbGlzdCA8LSBJRHNfdjFfdHhBJElECnR4QV9saXN0CgojIGlmZWxzZSBzdGF0ZW1lbnQ6IGlmIElEID0gYW55IG9mIHRob3NlIGxpc3RlZCBpbiB0eEFfbGlzdCwgbWFrZSBjb25kX3YxID0gIkEiLCBlbHNlIG1ha2UgaXQgIkIiCmJ4X3YxIDwtIGJ4X3YxICU+JQogIG11dGF0ZShjb25kX3YxID0gYXMuZmFjdG9yKGlmZWxzZShJRCA9PSAiRDEwMSIgfCBJRCA9PSAiRDEwNSIgfCBJRCA9PSAiRDEwOSIgfCBJRCA9PSAiRDExMCIgfCBJRCA9PSAiRDExNCIgfCBJRCA9PSAiRDExNSIgfCBJRCA9PSAiRDExNiIgfCBJRCA9PSAiRDExOCIgfCBJRCA9PSAiRDExOSIgfCBJRCA9PSAiRDEyMCIgfCBJRCA9PSAiRDEyMyIgfCBJRCA9PSAiRDEyNCIgfCBJRCA9PSAiRDEyNiIgfCBJRCA9PSAiRDEyOCIgfCBJRCA9PSAiRDEzMiIgfCBJRCA9PSAiRDEzNSIgfCBJRCA9PSAiRDEzNiIgfCBJRCA9PSAiRDEzNyIgfCBJRCA9PSAiRDEzOCIgfCBJRCA9PSAiRDE0MCIgfCBJRCA9PSAiRDE0MSIgfCBJRCA9PSAiRDE0NSIgfCBJRCA9PSAiRDE0OCIgfCBJRCA9PSAiRDE0OSIgfCBJRCA9PSAiRDExNyIsICJBIiwgIkIiKSksIGNvbmRfdjIgPSBhcy5mYWN0b3IoaWZlbHNlKElEID09ICJEMTAxIiB8IElEID09ICJEMTA1IiB8IElEID09ICJEMTA5IiB8IElEID09ICJEMTEwIiB8IElEID09ICJEMTE0IiB8IElEID09ICJEMTE1IiB8IElEID09ICJEMTE2IiB8IElEID09ICJEMTE4IiB8IElEID09ICJEMTE5IiB8IElEID09ICJEMTIwIiB8IElEID09ICJEMTIzIiB8IElEID09ICJEMTI0IiB8IElEID09ICJEMTI2IiB8IElEID09ICJEMTI4IiB8IElEID09ICJEMTMyIiB8IElEID09ICJEMTM1IiB8IElEID09ICJEMTM2IiB8IElEID09ICJEMTM3IiB8IElEID09ICJEMTM4IiB8IElEID09ICJEMTQwIiB8IElEID09ICJEMTQxIiB8IElEID09ICJEMTQ1IiB8IElEID09ICJEMTQ4IiB8IElEID09ICJEMTQ5IiB8IElEID09ICJEMTE3IiwgIkIiLCAiQSIpKSkKCiMgaWZlbHNlIHN0YXRlbWVudDogaWYgSUQgPSBhbnkgb2YgdGhvc2UgbGlzdGVkIGluIHR4QV9saXN0LCBtYWtlIGNvbmRfdjIgPSAiQiIsIGVsc2UgbWFrZSBpdCAiQSIgKHBlb3BsZSB3aG8gd2VyZSBBIGF0IHZpc2l0IDEgc2hvdWxkIGJlIEIgZm9yIHZpc2l0IDIsIGFuZCB2aWNlIHZlcnNhKQpieF92MiA8LSBieF92MiAlPiUKICBtdXRhdGUoY29uZF92MiA9IGFzLmZhY3RvcihpZmVsc2UoSUQgPT0gIkQxMDEiIHwgSUQgPT0gIkQxMDUiIHwgSUQgPT0gIkQxMDkiIHwgSUQgPT0gIkQxMTAiIHwgSUQgPT0gIkQxMTQiIHwgSUQgPT0gIkQxMTUiIHwgSUQgPT0gIkQxMTYiIHwgSUQgPT0gIkQxMTgiIHwgSUQgPT0gIkQxMTkiIHwgSUQgPT0gIkQxMjAiIHwgSUQgPT0gIkQxMjMiIHwgSUQgPT0gIkQxMjQiIHwgSUQgPT0gIkQxMjYiIHwgSUQgPT0gIkQxMjgiIHwgSUQgPT0gIkQxMzIiIHwgSUQgPT0gIkQxMzUiIHwgSUQgPT0gIkQxMzYiIHwgSUQgPT0gIkQxMzciIHwgSUQgPT0gIkQxMzgiIHwgSUQgPT0gIkQxNDAiIHwgSUQgPT0gIkQxNDEiIHwgSUQgPT0gIkQxNDUiIHwgSUQgPT0gIkQxNDgiIHwgSUQgPT0gIkQxNDkiIHwgSUQgPT0gIkQxMTciLCAiQiIsICJBIikpLCBjb25kX3YxID0gYXMuZmFjdG9yKGlmZWxzZShJRCA9PSAiRDEwMSIgfCBJRCA9PSAiRDEwNSIgfCBJRCA9PSAiRDEwOSIgfCBJRCA9PSAiRDExMCIgfCBJRCA9PSAiRDExNCIgfCBJRCA9PSAiRDExNSIgfCBJRCA9PSAiRDExNiIgfCBJRCA9PSAiRDExOCIgfCBJRCA9PSAiRDExOSIgfCBJRCA9PSAiRDEyMCIgfCBJRCA9PSAiRDEyMyIgfCBJRCA9PSAiRDEyNCIgfCBJRCA9PSAiRDEyNiIgfCBJRCA9PSAiRDEyOCIgfCBJRCA9PSAiRDEzMiIgfCBJRCA9PSAiRDEzNSIgfCBJRCA9PSAiRDEzNiIgfCBJRCA9PSAiRDEzNyIgfCBJRCA9PSAiRDEzOCIgfCBJRCA9PSAiRDE0MCIgfCBJRCA9PSAiRDE0MSIgfCBJRCA9PSAiRDE0NSIgfCBJRCA9PSAiRDE0OCIgfCBJRCA9PSAiRDE0OSIgfCBJRCA9PSAiRDExNyIsICJBIiwgIkIiKSkpCgpsZXZlbHMoYnhfdjEkY29uZF92MSkKbGV2ZWxzKGJ4X3YyJGNvbmRfdjIpCgpoZWFkKGJ4X3YxKQoKdHhBX2xpc3QKYnhfdjEgJT4lIGdyb3VwX2J5KGNvbmRfdjEpICU+JSBjb3VudChJRCkgIyBJRHMgYW5kIGNvbmQgbWF0Y2ggdHhBX2xpc3QgKm5vdGUgdGhhdCBzb21lIElEcyBmcm9tIHRoZSByYW5kb21pemF0aW9uIGRhdGFzZXQgYXJlIGxpc3RlZCBpbiB0eEEgYnV0IG5vdCBpbiB0aGUgYmVoYXZpb3JhbCBkYXRhLiBUaGlzIGlzIGJlY2F1c2Ugc29tZSBwYXJ0aWNpcGFudHMgd2VyZSBkcm9wcGVkIG9yIG5ldmVyIGVuZGVkIHVwIGNvbXBsZXRpbmcgdGhlaXIgZXhwZXJpbWVudGFsIHNlc3Npb246IEQxMDkgKGRyb3BwZWQgYWZ0ZXIgMXN0IHNlc3Npb24pLCBEMTE2IGFuZCBEMTM2IChuZXZlciBlbnJvbGxlZCksIEQxMjQgKGluY2lkZW50YWwgZmluZGluZywgZXhjbHVkZWQgYWZ0ZXIgVDFNUFJBR0UpLgpieF92MiAlPiUgZ3JvdXBfYnkoY29uZF92MikgJT4lIGNvdW50KElEKSAjIElEcyBhbmQgY29uZCBtYXRjaCB0eEFfbGlzdAoKYnhfbG9uZyA8LSBiaW5kX3Jvd3MoYnhfdjEsYnhfdjIpClZpZXcoYnhfbG9uZykKYGBgCgpgYGB7cn0KIyByZW5hbWUgc29tZSB2YXJpYWJsZXMKY29sbmFtZXMoYnhfbG9uZykKYnhfbG9uZyA8LSBieF9sb25nICU+JSByZW5hbWUoInB1c2hfcHVsbCIgPSB2YWx1ZXMuaW5pdGlhbHJlc3BvbnNlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZ0FBVF9SVCIgPSB2YWx1ZXMuUlQpCmhlYWQoYnhfbG9uZykKCiMgYWRkIGEgbmV3IHZhcmlhYmxlIGZvciBjb25kaXRpb24KYnhfbG9uZyA8LSBieF9sb25nICU+JSBtdXRhdGUoY29uZCA9IGFzLmZhY3RvcihpZmVsc2UoY29uZF92MSA9PSAiQSIgJiB2aXNpdCA9PSAiMSIsICJBIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGNvbmRfdjIgPT0gIkEiICYgdmlzaXQgPT0gIjIiLCAiQSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoY29uZF92MSA9PSAiQiIgJiB2aXNpdCA9PSAiMSIsICJCIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoY29uZF92MiA9PSAiQiIgJiB2aXNpdCA9PSAiMiIsICJCIiwgTkEpKSkpKSkKClZpZXcoYnhfbG9uZykgIyBjaGVjayB0aGF0IGl0IGNvZGVkIHRoZSAiY29uZCIgY29sdW1uIGNvcnJlY3RseSAgICAgIAoKIyBhZGQgYSBuZXcgdmFyaWFibGUgZm9yIHN0aW11bHVzIGNhdGVnb3J5CiMgaW4gdmFsdWVzLnN0aW11bHVzOgojIDEgPSBzcG91c2UsIDIgPSBsaXZpbmcgbG92ZWQgb25lL1dIT1RPLCAzID0gc3RyYW5nZXIsIDQgPSBub21vdGhldGljIGRlYXRoLXJlbGF0ZWQsIDUgPSBuZXV0cmFsIGltYWdlcwoKc29ydCh1bmlxdWUoYnhfbG9uZyR2YWx1ZXMuc3RpbXVsdXMpKQoKYnhfbG9uZyA8LSBieF9sb25nICU+JQogIG11dGF0ZShzdGltID0gYXMuZmFjdG9yKGlmZWxzZSh2YWx1ZXMuc3RpbXVsdXMgPT0gIjFCXzEuanBnInx2YWx1ZXMuc3RpbXVsdXMgPT0gIjFCXzIuanBnInx2YWx1ZXMuc3RpbXVsdXMgPT0gIjFCXzMuanBnInx2YWx1ZXMuc3RpbXVsdXMgPT0gIjFZXzEuanBnInx2YWx1ZXMuc3RpbXVsdXMgPT0gIjFZXzIuanBnInx2YWx1ZXMuc3RpbXVsdXMgPT0gIjFZXzMuanBnIiwgInNwb3VzZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UodmFsdWVzLnN0aW11bHVzID09ICIyQl8xLmpwZyJ8dmFsdWVzLnN0aW11bHVzID09ICIyQl8yLmpwZyJ8dmFsdWVzLnN0aW11bHVzID09ICIyQl8zLmpwZyJ8dmFsdWVzLnN0aW11bHVzID09ICIyWV8xLmpwZyJ8dmFsdWVzLnN0aW11bHVzID09ICIyWV8yLmpwZyJ8dmFsdWVzLnN0aW11bHVzID09ICIyWV8zLmpwZyIsICJsaXZpbmciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHZhbHVlcy5zdGltdWx1cyA9PSAiM0JfMS5qcGcifHZhbHVlcy5zdGltdWx1cyA9PSAiM0JfMi5qcGcifHZhbHVlcy5zdGltdWx1cyA9PSAiM0JfMy5qcGcifHZhbHVlcy5zdGltdWx1cyA9PSAiM1lfMS5qcGcifHZhbHVlcy5zdGltdWx1cyA9PSAiM1lfMi5qcGcifHZhbHVlcy5zdGltdWx1cyA9PSAiM1lfMy5qcGciLCAic3RyYW5nZXIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZSh2YWx1ZXMuc3RpbXVsdXMgPT0gIjRCXzEuanBnInx2YWx1ZXMuc3RpbXVsdXMgPT0gIjRCXzIuanBnInx2YWx1ZXMuc3RpbXVsdXMgPT0gIjRCXzMuanBnInx2YWx1ZXMuc3RpbXVsdXMgPT0gIjRZXzEuanBnInx2YWx1ZXMuc3RpbXVsdXMgPT0gIjRZXzIuanBnInx2YWx1ZXMuc3RpbXVsdXMgPT0gIjRZXzMuanBnIiwgImRlYXRoIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHZhbHVlcy5zdGltdWx1cyA9PSAiNUJfMS5qcGcifHZhbHVlcy5zdGltdWx1cyA9PSAiNUJfMi5qcGcifHZhbHVlcy5zdGltdWx1cyA9PSAiNUJfMy5qcGcifHZhbHVlcy5zdGltdWx1cyA9PSAiNVlfMS5qcGcifHZhbHVlcy5zdGltdWx1cyA9PSAiNVlfMi5qcGcifHZhbHVlcy5zdGltdWx1cyA9PSAiNVlfMy5qcGciLCAibmV1dHJhbCIsIE5BKSkpKSkpKQoKbGV2ZWxzKGJ4X2xvbmckc3RpbSkKYnhfbG9uZyRzdGltIDwtIHJlbGV2ZWwoYnhfbG9uZyRzdGltLCByZWYgPSAibmV1dHJhbCIpICMgbWFrZSBuZXV0cmFsIHRoZSByZWZlcmVuY2UgbGV2ZWwKCiMgc2F2ZSBpdApzYXZlUkRTKGJ4X2xvbmcsICJ+L0Ryb3Bib3gvR0xBU1MgTGFiL09UIGdBQVQgZm9yIG1lZXRpbmcgNS0xMC0xOS9ieF9sb25nLnJkcyIpCmBgYAoKIyMjIFJlbW92ZSBvdXRsaWVycwpPdXRsaWVyIHJlbW92YWwgZm9sbG93cyBjb252ZW50aW9ucyBmcm9tIG90aGVyIGdBQVQgcGFwZXJzLCB3aGljaCBleGNsdWRlIHRyaWFscyB3aXRoIFJUcyB0aGF0IGFyZSBlcXVhbCB0byBvciBhYm92ZSB0aGUgOTl0aCBwZXJjZW50aWxlIChjYWxjdWxhdGVkIGZyb20gdGhlIHNhbXBsZSBhcyBhIHdob2xlKSBvciBlcXVhbCB0byBvciBiZWxvdyAxc3QgcGVyY2VudGlsZS4gCmBgYHtyfQojIGNhbGN1bGF0ZSBwZXJjZW50aWxlcyBzZXBhcmF0ZWx5IGZvciBwbGFjZWJvL294eXRvY2luIGNvbmRpdGlvbnMKYnhfcGwgPC0gYnhfbG9uZyAlPiUgZmlsdGVyKGNvbmQgPT0gIkEiKQpieF9vdCA8LSBieF9sb25nICU+JSBmaWx0ZXIoY29uZCA9PSAiQiIpCnA5OXBsIDwtIHF1YW50aWxlKGJ4X3BsJGdBQVRfUlQsIDAuOTkpICMgMTcxNi43NiBtcwpwMDFwbCA8LSBxdWFudGlsZShieF9wbCRnQUFUX1JULCAwLjAxKSAjIDQ2MyBtcwpwOTlvdCA8LSBxdWFudGlsZShieF9vdCRnQUFUX1JULCAwLjk5KSAjIDE3MTEuMDcgbXMKcDAxb3QgPC0gcXVhbnRpbGUoYnhfb3QkZ0FBVF9SVCwgMC4wMSkgIyA0NzMgbXMKCiMgaWRlbnRpZnkgcGxhY2VibyBjb25kaXRpb24gb3V0bGllcnMKYnhfcGwgPC0gYnhfcGwgJT4lCiAgbXV0YXRlKG91dGxpZXJfUlQgPSBpZmVsc2UoZ0FBVF9SVCA8PSBwMDFwbCB8IGdBQVRfUlQgPj0gcDk5cGwsIDEsIDApKQp0YWJsZShieF9wbCRvdXRsaWVyX1JUKSAKMjI3LzExMDA1ICMgYWJvdXQgMiUgb2YgdHJpYWxzIGFyZSBvdXRsaWVycwoKIyBpZGVudGlmeSBveHl0b2NpbiBjb25kaXRpb24gb3V0bGllcnMKYnhfb3QgPC0gYnhfb3QgJT4lCiAgbXV0YXRlKG91dGxpZXJfUlQgPSBpZmVsc2UoZ0FBVF9SVCA8PSBwMDFvdCB8IGdBQVRfUlQgPj0gcDk5b3QsIDEsIDApKQp0YWJsZShieF9vdCRvdXRsaWVyX1JUKSAKMjI5LzExMDAzICMgYWJvdXQgMiUgb2YgdHJpYWxzIGFyZSBvdXRsaWVycwoKYnhfbG9uZ19ub091dCA8LSBiaW5kX3Jvd3MoYnhfcGwsIGJ4X290KSAlPiUgZmlsdGVyKG91dGxpZXJfUlQgPT0gMCkKCmRpbShieF9sb25nKQpkaW0oYnhfbG9uZ19ub091dCkgICMgYWZ0ZXIgb3V0bGllcnMgcmVtb3ZlZCwgdGhlcmUgYXJlIDIyMDA4IHRyaWFscyB0b3RhbCBvZiB0aGUgb3JpZ2luYWwgMjI0NjQ6IDIyNDY0IC0gKDIyNysyMjkpID0gMjIwMDgKCnNhdmVSRFMoYnhfbG9uZ19ub091dCwgIn4vRHJvcGJveC9HTEFTUyBMYWIvT1QgZ0FBVCBmb3IgbWVldGluZyA1LTEwLTE5L2J4X2xvbmdfbm9PdXQucmRzIikKYGBgCgoKIyMjIENoZWNrIGRhdGEgYW5kIGRpc3RyaWJ1dGlvbgpgYGB7cn0KbGlicmFyeShwc3ljaCkKCiMgaG93IG11Y2ggbWlzc2luZyBkYXRhIGlzIHRoZXJlPwpudHJpYWxzIDwtIGJ4X2xvbmdfbm9PdXQgJT4lIGdyb3VwX2J5KElELCBjb25kKSAlPiUgY291bnQoKSAjIGRvbid0IGdyb3VwIGJ5IHB1c2hfcHVsbCBiZWNhdXNlIHBlb3BsZWQgcHVsbGVkL3B1c2hlZCBvbiBkaWZmZXJlbnQgbnVtYmVycyBvZiB0cmlhbHMsIGZvciBleC4gcmVzcG9uc2VzIGluIHRoZSB3cm9uZyBkaXJlY3Rpb24KZGVzY3JpYmUobnRyaWFscyRuLzI4OCkgIyBldmVyeW9uZSBoYXMgYXQgbGVhc3QgOTAlIG9mIHRoZSAyODggdHJpYWxzIGV4cGVjdGVkIGF0IGVhY2ggdmlzaXQgKG5vIG1vcmUgdGhhbiAxMCUgdHJpYWxzIGRyb3BwZWQgYmVjYXVzZSBvZiBvdXRsaWVycyBvciBtaXNzZWQgcmVzcG9uc2VzKQoKZGVzY3JpYmUoYnhfbG9uZ19ub091dCRnQUFUX1JUKSAjIHNrZXduZXNzIGlzIDEuMTcsIGt1cnRvc2lzIGlzIDEuNwpoaXN0KGJ4X2xvbmdfbm9PdXQkZ0FBVF9SVCkgIyBkaXN0cmlidXRpb24gaXMgc2tld2VkLCBhcyB1c3VhbCBmb3IgUlQgZGF0YS4uLgpxcW5vcm0oYnhfbG9uZ19ub091dCRnQUFUX1JUKSAjIGFuZCBza2V3bmVzcyBpcyByZWZsZWN0ZWQgaW4gUVEgcGxvdApgYGAKCiMjIyBCaWFzIHNjb3JlcyAoYmFzZWQgb24gbWVkaWFuIFJUcykKYGBge3J9CiMgY3JlYXRpbmcgYSB3aWRlIGRhdGFzZXQgd2l0aCB0aGUgYmlhcyB2YXJpYWJsZXMsIHdoaWNoIHdpbGwgdGhlbiBiZSBjb252ZXJ0ZWQgYmFjayB0byBhIGxvbmcgZGF0YXNldAojIFRoZSBhcmd1bWVudHMgdG8gc3ByZWFkKCk6CiMgLSBkYXRhOiBEYXRhIG9iamVjdAojIC0ga2V5OiBOYW1lIG9mIGNvbHVtbiBjb250YWluaW5nIHRoZSBuZXcgY29sdW1uIG5hbWVzCiMgLSB2YWx1ZTogTmFtZSBvZiBjb2x1bW4gY29udGFpbmluZyB2YWx1ZXMKZGF0YV93aWRlIDwtIHNwcmVhZChieF9sb25nX25vT3V0LCBrZXk9c3RpbSwgdmFsdWU9Z0FBVF9SVCkKY29sbmFtZXMoZGF0YV93aWRlKQpWaWV3KGRhdGFfd2lkZSkKCiMgc3Vic2V0IGJ5IGNvbmRpdGlvbiBhbmQgZGlyZWN0aW9uCmRhdGFfcHVzaEEgPC0gZGF0YV93aWRlICU+JSBzZWxlY3QoSUQsIGNvbmQsIHB1c2hfcHVsbCwgdmlzaXQsIG5ldXRyYWwsIGRlYXRoLCBsaXZpbmcsIHNwb3VzZSwgc3RyYW5nZXIpICU+JSBmaWx0ZXIoY29uZCA9PSAiQSIgJiBwdXNoX3B1bGwgPT0gIlBVU0giKSAlPiUgZ3JvdXBfYnkoSUQpICU+JSBtdXRhdGUobmV1dHJhbEFwdXNoID0gbWVkaWFuKG5ldXRyYWwsIG5hLnJtID0gVFJVRSksIGRlYXRoQXB1c2ggPSBtZWRpYW4oZGVhdGgsIG5hLnJtID0gVFJVRSksIHNwb3VzZUFwdXNoID0gbWVkaWFuKHNwb3VzZSwgbmEucm09VFJVRSksIGxpdmluZ0FwdXNoID0gbWVkaWFuKGxpdmluZywgbmEucm09VFJVRSksIHN0cmFuZ2VyQXB1c2ggPSBtZWRpYW4oc3RyYW5nZXIsIG5hLnJtPVRSVUUpKQoKZGF0YV9wdWxsQSA8LSBkYXRhX3dpZGUgJT4lIHNlbGVjdChJRCwgY29uZCwgcHVzaF9wdWxsLCB2aXNpdCwgbmV1dHJhbCwgZGVhdGgsIGxpdmluZywgc3BvdXNlLCBzdHJhbmdlcikgJT4lIGZpbHRlcihjb25kID09ICJBIiAmIHB1c2hfcHVsbCA9PSAiUFVMTCIpICU+JSBncm91cF9ieShJRCkgJT4lIG11dGF0ZShuZXV0cmFsQXB1bGwgPSBtZWRpYW4obmV1dHJhbCwgbmEucm0gPSBUUlVFKSwgZGVhdGhBcHVsbCA9IG1lZGlhbihkZWF0aCwgbmEucm0gPSBUUlVFKSwgc3BvdXNlQXB1bGwgPSBtZWRpYW4oc3BvdXNlLCBuYS5ybT1UUlVFKSwgbGl2aW5nQXB1bGwgPSBtZWRpYW4obGl2aW5nLCBuYS5ybT1UUlVFKSwgc3RyYW5nZXJBcHVsbCA9IG1lZGlhbihzdHJhbmdlciwgbmEucm09VFJVRSkpCgpkYXRhX3B1c2hCIDwtIGRhdGFfd2lkZSAlPiUgc2VsZWN0KElELCBjb25kLCBwdXNoX3B1bGwsIHZpc2l0LCBuZXV0cmFsLCBkZWF0aCwgbGl2aW5nLCBzcG91c2UsIHN0cmFuZ2VyKSAlPiUgZmlsdGVyKGNvbmQgPT0gIkIiICYgcHVzaF9wdWxsID09ICJQVVNIIikgJT4lIGdyb3VwX2J5KElEKSAlPiUgbXV0YXRlKG5ldXRyYWxCcHVzaCA9IG1lZGlhbihuZXV0cmFsLCBuYS5ybSA9IFRSVUUpLCBkZWF0aEJwdXNoID0gbWVkaWFuKGRlYXRoLCBuYS5ybSA9IFRSVUUpLCBzcG91c2VCcHVzaCA9IG1lZGlhbihzcG91c2UsIG5hLnJtPVRSVUUpLCBsaXZpbmdCcHVzaCA9IG1lZGlhbihsaXZpbmcsIG5hLnJtPVRSVUUpLCBzdHJhbmdlckJwdXNoID0gbWVkaWFuKHN0cmFuZ2VyLCBuYS5ybT1UUlVFKSkKCmRhdGFfcHVsbEIgPC0gZGF0YV93aWRlICU+JSBzZWxlY3QoSUQsIGNvbmQsIHB1c2hfcHVsbCwgdmlzaXQsIG5ldXRyYWwsIGRlYXRoLCBsaXZpbmcsIHNwb3VzZSwgc3RyYW5nZXIpICU+JSBmaWx0ZXIoY29uZCA9PSAiQiIgJiBwdXNoX3B1bGwgPT0gIlBVTEwiKSAlPiUgZ3JvdXBfYnkoSUQpICU+JSBtdXRhdGUobmV1dHJhbEJwdWxsID0gbWVkaWFuKG5ldXRyYWwsIG5hLnJtID0gVFJVRSksIGRlYXRoQnB1bGwgPSBtZWRpYW4oZGVhdGgsIG5hLnJtID0gVFJVRSksIHNwb3VzZUJwdWxsID0gbWVkaWFuKHNwb3VzZSwgbmEucm09VFJVRSksIGxpdmluZ0JwdWxsID0gbWVkaWFuKGxpdmluZywgbmEucm09VFJVRSksIHN0cmFuZ2VyQnB1bGwgPSBtZWRpYW4oc3RyYW5nZXIsIG5hLnJtPVRSVUUpKQoKIyBzdW1tYXJpemUgYnkgSUQKZGF0YV9wdXNoQTEgPC0gZGF0YV9wdXNoQVshZHVwbGljYXRlZChkYXRhX3B1c2hBJElEKSwgXSAlPiUgc2VsZWN0KC1jKG5ldXRyYWwsIGRlYXRoLCBsaXZpbmcsIHNwb3VzZSwgc3RyYW5nZXIsIHZpc2l0LCBjb25kLCBwdXNoX3B1bGwpKQpkYXRhX3B1c2hCMSA8LSBkYXRhX3B1c2hCWyFkdXBsaWNhdGVkKGRhdGFfcHVzaEIkSUQpLCBdICU+JSBzZWxlY3QoLWMobmV1dHJhbCwgZGVhdGgsIGxpdmluZywgc3BvdXNlLCBzdHJhbmdlciwgdmlzaXQsIGNvbmQsIHB1c2hfcHVsbCkpCmRhdGFfcHVsbEExIDwtIGRhdGFfcHVsbEFbIWR1cGxpY2F0ZWQoZGF0YV9wdWxsQSRJRCksIF0gJT4lIHNlbGVjdCgtYyhuZXV0cmFsLCBkZWF0aCwgbGl2aW5nLCBzcG91c2UsIHN0cmFuZ2VyLCB2aXNpdCwgY29uZCwgcHVzaF9wdWxsKSkKZGF0YV9wdWxsQjEgPC0gZGF0YV9wdWxsQlshZHVwbGljYXRlZChkYXRhX3B1bGxCJElEKSwgXSAlPiUgc2VsZWN0KC1jKG5ldXRyYWwsIGRlYXRoLCBsaXZpbmcsIHNwb3VzZSwgc3RyYW5nZXIsIHZpc2l0LCBjb25kLCBwdXNoX3B1bGwpKQoKIyBtZXJnZSB0aGUgNCBzdWJzZXRzIHRvZ2V0aGVyCmpvaW4xIDwtIGxlZnRfam9pbihkYXRhX3B1c2hBMSwgZGF0YV9wdXNoQjEsIGJ5PSJJRCIpCmpvaW4yIDwtIGxlZnRfam9pbihqb2luMSwgZGF0YV9wdWxsQTEsIGJ5ID0gIklEIikKYmlhcyA8LSBsZWZ0X2pvaW4oam9pbjIsIGRhdGFfcHVsbEIxLCBieSA9ICJJRCIpCmhlYWQoYmlhcykKCmJpYXMgPC0gYmlhcyAlPiUgbXV0YXRlKGJpYXNfbmV1X0EgPSBuZXV0cmFsQXB1c2ggLSBuZXV0cmFsQXB1bGwsCiAgICAgICAgICAgICAgICAgICAgICAgIGJpYXNfZGVhX0EgPSBkZWF0aEFwdXNoIC0gZGVhdGhBcHVsbCwKICAgICAgICAgICAgICAgICAgICAgICAgYmlhc19zcG9fQSA9IHNwb3VzZUFwdXNoIC0gc3BvdXNlQXB1bGwsCiAgICAgICAgICAgICAgICAgICAgICAgIGJpYXNfc3RyX0EgPSBzdHJhbmdlckFwdXNoIC0gc3RyYW5nZXJBcHVsbCwKICAgICAgICAgICAgICAgICAgICAgICAgYmlhc19saXZfQSA9IGxpdmluZ0FwdXNoIC0gbGl2aW5nQXB1bGwsCiAgICAgICAgICAgICAgICAgICAgICAgIGJpYXNfbmV1X0IgPSBuZXV0cmFsQnB1c2ggLSBuZXV0cmFsQnB1bGwsCiAgICAgICAgICAgICAgICAgICAgICAgIGJpYXNfZGVhX0IgPSBkZWF0aEJwdXNoIC0gZGVhdGhCcHVsbCwKICAgICAgICAgICAgICAgICAgICAgICAgYmlhc19zcG9fQiA9IHNwb3VzZUJwdXNoIC0gc3BvdXNlQnB1bGwsCiAgICAgICAgICAgICAgICAgICAgICAgIGJpYXNfc3RyX0IgPSBzdHJhbmdlckJwdXNoIC0gc3RyYW5nZXJCcHVsbCwKICAgICAgICAgICAgICAgICAgICAgICAgYmlhc19saXZfQiA9IGxpdmluZ0JwdXNoIC0gbGl2aW5nQnB1bGwKKQoKIyBkcm9wIHRoZSBjb25kaXRpb24vc3RpbSBzcGVjaWZpYyB2YXJpYWJsZXMKYmlhcyA8LSBiaWFzICU+JSBzZWxlY3QoLWMobmV1dHJhbEFwdXNoLCBkZWF0aEFwdXNoLCAgc3BvdXNlQXB1c2gsICBsaXZpbmdBcHVzaCwgc3RyYW5nZXJBcHVzaCwgbmV1dHJhbEJwdXNoLCBkZWF0aEJwdXNoLCAgIHNwb3VzZUJwdXNoLCAgbGl2aW5nQnB1c2gsICBzdHJhbmdlckJwdXNoLCBuZXV0cmFsQXB1bGwsIGRlYXRoQXB1bGwsIHNwb3VzZUFwdWxsLCBsaXZpbmdBcHVsbCwgc3RyYW5nZXJBcHVsbCwgbmV1dHJhbEJwdWxsLCBkZWF0aEJwdWxsLCBzcG91c2VCcHVsbCwgbGl2aW5nQnB1bGwsIHN0cmFuZ2VyQnB1bGwpKQpjb2xuYW1lcyhiaWFzKQoKIyB0dXJuIGl0IGludG8gYSBsb25nIGRhdGFzZXQKYmlhc19sb25nIDwtIGdhdGhlcihiaWFzLAogICAgICAgICAgICAgICAgICAgIGtleSA9ICJzdGltIiwKICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9ICJiaWFzIiwgLWMoSUQpKSAKaGVhZChiaWFzX2xvbmcpCgoKCiMgY3JlYXRlIG5ldyBjb2x1bW5zIGZvciBzdGltdWx1cyBjYXRlZ29yeSBhbmQgY29uZGl0aW9uCmJpYXNfbG9uZyRjb25kIDwtIGFzLmZhY3RvcihpZmVsc2UoZ3JlcGwoIipfQSIsIGJpYXNfbG9uZyRzdGltKSwgIkEiLCAiQiIpKQpiaWFzX2xvbmckc3RpbXVsdXMgPC0gYXMuZmFjdG9yKGlmZWxzZShncmVwbCgiKm5ldSoiLCBiaWFzX2xvbmckc3RpbSksICJuZXV0cmFsIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShncmVwbCgiKmRlYSoiLCBiaWFzX2xvbmckc3RpbSksICJkZWF0aCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ3JlcGwoIipzcG8qIiwgYmlhc19sb25nJHN0aW0pLCAic3BvdXNlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdyZXBsKCIqc3RyKiIsIGJpYXNfbG9uZyRzdGltKSwgInN0cmFuZ2VyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShncmVwbCgiKmxpdioiLCBiaWFzX2xvbmckc3RpbSksICJsaXZpbmciLCBOQSkpKSkpKQoKYmlhc19sb25nIDwtIGJpYXNfbG9uZyAlPiUgc2VsZWN0KC1zdGltKSAjIG5vIGxvbmdlciBuZWVkIHRoZSAic3RpbSIgdmFyaWFibGUKYGBgCgojIyMgQ2hlY2sgZGF0YSBhbmQgZGlzdHJpYnV0aW9uCmBgYHtyfQpkZXNjcmliZShiaWFzX2xvbmckYmlhcykgIyBza2V3bmVzcyBpcyAtLjAxLCBrdXJ0b3NpcyBpcyAxLjM0LCBNID0gMTQuMDQsIFNEID0gNzAuMDEKaGlzdChiaWFzX2xvbmckYmlhcykgIyBub3JtYWwgZGlzdHJpYnV0aW9uCnFxbm9ybShiaWFzX2xvbmckYmlhcykgIyBkZWZpbml0ZWx5IHNvbWUgb3V0bGllcnMKCiMgY2hlY2sgb3V0IHRoZSBvdXRsaWVycwojIyBmdW5jdGlvbiBmcm9tIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzEyODY2MTg5L2NhbGN1bGF0aW5nLXRoZS1vdXRsaWVycy1pbi1yCm91dGZ1biA8LSBmdW5jdGlvbih4KSB7CiAgYWJzKHgtbWVhbih4LG5hLnJtPVRSVUUpKSA+IDMqc2QoeCxuYS5ybT1UUlVFKQp9CgojIGFkZCBhIHZhcmlhYmxlIGZvciBvdXRsaWVyID0gVC9GCmJpYXNfbG9uZyRvdXRsaWVyIDwtIG91dGZ1bihiaWFzX2xvbmckYmlhcykKdGFibGUoYmlhc19sb25nJG91dGxpZXIpICMgNCBvYnNlcnZhdGlvbnMgd2hlcmUgb3V0bGllciA9IFRSVUUgKD4zU0QpCiMgd2hpY2ggYXJlIHRoZXNlPwpiaWFzX2xvbmcgJT4lIGZpbHRlcihvdXRsaWVyPT1UUlVFKQoKIyMjIHRoaXMgaXMgYW5vdGhlciB3YXkgdG8gZG8gaXQgdXNpbmcgYm94cGxvdC5zdGF0cwojIG91dGxpZXJfdmFsdWVzIDwtIGJveHBsb3Quc3RhdHMobWVkaWFuc19sb25nJGJpYXMpJG91dAojIGJveHBsb3QoZGF0YV9sb25nJGJpYXMsIG1haW49Ik91dGxpZXJzIiwgYm94d2V4PTAuMykKIyBtdGV4dChwYXN0ZSgiT3V0bHlpbmcgdmFsdWVzOiAiLCBwYXN0ZShyb3VuZChvdXRsaWVyX3ZhbHVlcywgZGlnaXRzPTIpLCBjb2xsYXBzZT0iLCAiKSksIGNleD0wLjksIHNpZGU9MSkKCnNhdmVSRFMoYmlhc19sb25nLCAifi9Ecm9wYm94L0dMQVNTIExhYi9PVCBnQUFUIGZvciBtZWV0aW5nIDUtMTAtMTkvYmlhc19sb25nLnJkcyIpCmBgYApUaGUgZm91ciBleHRyZW1lIG91dGxpZXJzICg+MyBTRCkgYXJlOgo8dWw+RDEzNyBkZWF0aCBBICgtMjg0LjApCkQxNDUgZGVhdGggQSAoLTI0Ny41KQpEMTQ3IGRlYXRoIEEgKDIzMy4wKQpEMTM5IHNwb3VzZSBCICgyNzUuNSk8L3VsPgoKIyMjIFRyaWFsLWxldmVsIGJpYXMgc2NvcmVzIChmb3IgTUxNIG9ubHkpClRvIGNhbGN1bGF0ZSB0cmlhbC1sZXZlbCBiaWFzIChha2EgImNvbXBhdGliaWxpdHkiKSBzY29yZXM6IHNlcGFyYXRlIHB1c2ggbWludXMgcHVsbCB0cmlhbHMsIHRoZW4gc3VidHJhY3QgUlQgb24gdGhhdCB0cmlhbCBhdCBydW4xIGZyb20gUlQgb24gdGhhdCB0cmlhbCBhdCBydW4yLgoKYGBge3J9CmJ4X2xvbmcgPC0gcmVhZFJEUygifi9Ecm9wYm94L0dMQVNTIExhYi9PVCBnQUFUIGZvciBtZWV0aW5nIDUtMTAtMTkvYnhfbG9uZy5yZHMiKQpieF9yMS4xIDwtIGJ4X2xvbmcgJT4lIGZpbHRlcihydW4gPT0gIjEiKQpieF9yMi4xIDwtIGJ4X2xvbmcgJT4lIGZpbHRlcihydW4gPT0gIjIiKQp0YWlsKGJ4X3IxLjEpCnRhaWwoYnhfcjIuMSkgCiMgcnVuMSBzaG91bGQgbGluZSB1cCB3aXRoIHJ1bjI6ICJzdGltIiBzaG91bGQgbWF0Y2ggKGkuZSwgc3BvdXNlIHRyaWFscyB3aXRoIHNwb3VzZSB0cmlhbHMpIGJ1dCBwdXNoX3B1bGwgc2hvdWxkIHNheSBQVVNIIGF0IG9uZSBydW4gYW5kIFBVTEwgYXQgdGhlIG90aGVyCgojIGNhbGN1bGF0ZSBwZXJjZW50aWxlcyBmb3Igb3V0bGllciByZW1vdmFsIChydW4xIGFuZCBydW4yKQpwOTlyMSA8LSBxdWFudGlsZShieF9yMS4xJGdBQVRfUlQsIDAuOTkpIApwMDFyMSA8LSBxdWFudGlsZShieF9yMS4xJGdBQVRfUlQsIDAuMDEpIApwOTlyMSAjIDk5dGggcGVyY2VudGlsZSBSVHMgPSAxNzEzLjM4bXMgCnAwMXIxICMgMXN0IHBlcmNlbnRpbGUgUlRzID0gNDcybXMKCnA5OXIyIDwtIHF1YW50aWxlKGJ4X3IyLjEkZ0FBVF9SVCwgMC45OSkgCnAwMXIyIDwtIHF1YW50aWxlKGJ4X3IyLjEkZ0FBVF9SVCwgMC4wMSkgCnA5OXIyICMgOTl0aCBwZXJjZW50aWxlIFJUcyA9IDE3MTIuNDVtcyAKcDAxcjIgIyAxc3QgcGVyY2VudGlsZSBSVHMgPSA0NjNtcwoKYnhfcjEuMiA8LSBieF9yMS4xICU+JQogIG11dGF0ZShvdXRsaWVyX1JUID0gaWZlbHNlKGdBQVRfUlQgPD0gcDAxcjEgfCBnQUFUX1JUID49IHA5OXIxLCAxLCAwKSkKdGFibGUoYnhfcjEuMiRvdXRsaWVyX1JUKSAKMjI3LzExMDA1ICMgMjI3IHRyaWFscyB3aWxsIGJlIGRyb3BwZWQsIDExMDA1IHdpbGwgYmUgcmV0YWluZWQuLi5hYm91dCAyJSBvZiB0cmlhbHMuCgpieF9yMi4yIDwtIGJ4X3IyLjEgJT4lCiAgbXV0YXRlKG91dGxpZXJfUlQgPSBpZmVsc2UoZ0FBVF9SVCA8PSBwMDFyMiB8IGdBQVRfUlQgPj0gcDk5cjIsIDEsIDApKQp0YWJsZShieF9yMi4yJG91dGxpZXJfUlQpIAoyMzAvMTEwMDIgIyAyMzAgdHJpYWxzIHdpbGwgYmUgZHJvcHBlZCwgMTEwMDIgd2lsbCBiZSByZXRhaW5lZC4uLmFib3V0IDIlIG9mIHRyaWFscy4KCmJ4X3IxcjIgPC0gYmluZF9jb2xzKGJ4X3IxLjIsIGJ4X3IyLjIpCmRpbShieF9yMXIyKSAgIyBhZnRlciBvdXRsaWVycyByZW1vdmVkLCB0aGVyZSBhcmUgMTEyMzIgdHJpYWxzIHRvdGFsCgojIG1ha2Ugc3VyZSB0aGF0IHRyaWFscyBpbiB0aGUgdHdvIHJ1bnMgbGluZSB1cCBwb3N0LW1lcmdlCmhlYWQoYnhfcjFyMikgCnRhaWwoYnhfcjFyMikKCiMgZ2V0IHJpZCBvZiBhbnkgdHJpYWxzIHdpdGggb3V0bGllcnMgaW4gZWl0aGVyIHJ1bjEgb3IgcnVuMiAKIyAobmVlZCBydW4xL3J1bjIgdG8gYmUgdGhlIHNhbWUgbGVuZ3RoIHNvIHRoYXQgdGhlIHRyaWFscyBtYXRjaCB1cCkKYnhfcjFyMi4xIDwtIGJ4X3IxcjIgJT4lIGZpbHRlcihvdXRsaWVyX1JUID09ICIwIiAmIG91dGxpZXJfUlQxID09ICIwIikgCmNvdW50KGJ4X3IxcjIuMSkgIyAxMDc5MCBvYnMuCjEwNzkwLzExMjMyICMgfjk2JSBvZiB0cmlhbHMgcmV0YWluZWQgPSA0JSBkYXRhIGV4Y2x1ZGVkCgpwdXNoX3B1bGwgPC0gYnhfcjFyMi4xICU+JSBmaWx0ZXIocHVzaF9wdWxsID09ICJQVVNIIiAmIHB1c2hfcHVsbDEgPT0gIlBVTEwiKSAlPiUgbXV0YXRlKGJpYXMgPSAoZ0FBVF9SVC1nQUFUX1JUMSkpCnB1bGxfcHVzaCA8LSBieF9yMXIyLjEgJT4lIGZpbHRlcihwdXNoX3B1bGwgPT0gIlBVTEwiICYgcHVzaF9wdWxsMSA9PSAiUFVTSCIpICU+JSBtdXRhdGUoYmlhcyA9IChnQUFUX1JUMS1nQUFUX1JUKSkKYnhfcHAgPC0gYmluZF9yb3dzKHB1c2hfcHVsbCxwdWxsX3B1c2gpCgpoZWFkKGJ4X3BwKSAjIGNhbiBzZWUgZnJvbSB0aGlzIHRoYXQgRDEwMSAoYW5kIHBvc3NpYmx5IG90aGVycykgaGFzIG9ubHkgYSBmZXcgdHJpYWxzLCBiZWNhdXNlIHRoZXkgZmFpbGVkIHRvIHJldmVyc2UgdGhlIGluc3RydWN0aW9ucyAoaS5lLiwgcHVzaF9wdWxsIGFuZCBwdXNoX3B1bGwxIGNvbHVtbnMgaGF2ZSB0aGUgc2FtZSB2YWx1ZXMgaW5zdGVhZCBvZiBQVVNIIGF0IG9uZSBhbmQgUFVMTCBhdCB0aGUgb3RoZXIpCiMgaW4gZXNzZW5jZSwgdGhpcyByZW1vdmVzIHRoZWlyICJlcnJvciIgdHJpYWxzCgpieF9wcCAlPiUgZ3JvdXBfYnkoSUQsIGNvbmQpICU+JSBjb3VudCgpICMgeWVwLCB0aGlzIGlzIHZpc2libGUgaW4gdGhlaXIgKnZlcnkgbG93KiB0cmlhbGNvdW50czoKIyBEMTAxIEEgbiA9IDMKIyBEMTQxIEEgbiA9IDE4CiMgRDE0NyBCIG4gPSAxCiMgRDE0OCBBIG4gPSAxOQpgYGAKQXMgd2Ugc2VlIGZyb20gdGhlIGxhc3QgcGFydCBvZiB0aGUgc2NyaXB0IGFib3ZlLCA0IHBhcnRpY2lwYW50cyBoYXZlIGV4dHJlbWVseSBsb3cgdHJpYWwgY291bnRzIGF0IG9uZSB2aXNpdCBvciBhbm90aGVyLCBkdWUgdG8gZmFpbHVyZSB0byByZXZlcnNlIHRoZSBpbnN0cnVjdGlvbnMuIFRoaXMgd2lsbCBiZSBhZGRyZXNzZWQgbmV4dC4KCmBgYHtyfQojIGNyZWF0ZSBhICJkcm9wIiB2YXJpYWJsZSBmb3IgdGhlc2UgNApieF9wcCA8LSBieF9wcCAlPiUgbXV0YXRlKGxvd19uX3RyaWFscyA9IGlmZWxzZShJRCA9PSAiRDEwMSIgJiBjb25kID09ICJBIiB8IElEID09ICJEMTQxIiAmIGNvbmQgPT0gIkEifCBJRCA9PSAiRDE0OCIgJiBjb25kID09ICJBIiB8IElEID09ICJEMTQ3IiAmIGNvbmQgPT0gIkIiLCAxLCAwKSkKCiMgY2hlY2sgd2hldGhlciB0aGUgcm93cyBsaW5lIHVwCm5vdGxpbmVkdXAgPC0gYnhfcHAgJT4lIGZpbHRlcihzdGltICE9IHN0aW0xKQpub3RsaW5lZHVwCm5vdGxpbmVkdXAgPC0gYnhfcHAgJT4lIGZpbHRlcih0cmlhbGNvZGUgIT0gdHJpYWxjb2RlMSkKbm90bGluZWR1cApub3RsaW5lZHVwIDwtIGJ4X3BwICU+JSBmaWx0ZXIodHJpYWxudW0gIT0gdHJpYWxudW0xKQpub3RsaW5lZHVwCm5vdGxpbmVkdXAgPC0gYnhfcHAgJT4lIGZpbHRlcihwdXNoX3B1bGwgPT0gcHVzaF9wdWxsMSkKbm90bGluZWR1cAojIDAgcm93cyByZXR1cm5lZDsgYWxsIHRoZSByb3dzIG1hdGNoLiBUaHVzIHdlIGNvbmNsdWRlIHRoZSByb3dzIGZyb20gdGhlIHR3byBydW5zIGxpbmUgdXAuCgpzYXZlUkRTKGJ4X3BwLCAifi9Ecm9wYm94L0dMQVNTIExhYi9PVCBnQUFUIGZvciBtZWV0aW5nIDUtMTAtMTkvYnhfbG9uZ190cmlhbGJ5dHJpYWxCaWFzLnJkcyIpCmBgYAo=