This script analyzes the association between NPi and Spikes in ICP (ICP > 22 mmHg) at different time points starting from the initiation of ICP monitoring (up to 96 hours) in patients with TBI, IPH, and aSAH.

library(tidyverse)
library(ggplot2)
library(kableExtra)
library(lme4)
library(lmerTest)
library(formattable)
library(knitr)
library(forcats)
library(viridis)
library(RColorBrewer)
library(cowplot)
library(broom)
library(broom.mixed)
library(DT)

Set working directory & Load Data

# NPi closest to ICP
load("processed_data/icp_pupils_closest.rda")
closest <- icp_pupils

# NPi Before AND After ICP
load("processed_Data/icp_pupils_before_after.rda")
before_after <- icp_pupils

rm(icp_pupils)

# diagnoses & demographics
load("processed_data/final_dx.rda")
load("processed_data/Demographics.rda")
load("processed_data/Demographics_Table1.rda")

# evd
load("processed_data/evd.rda")

# burdens in the first 24 hours of icp monitoring
load("processed_data/burdens.rda")

source("R/time_sensitivity_funcs.r")

Data & Time Interval Setup

Select TBI, IPH, and aSAH patients

closest <- merge(closest, final_dx, by = "Study_ID")
before_after <- merge(before_after, final_dx, by = "Study_ID")

Add Covariates

EVD Drainage

Identify whether EVD drainage occurred within 1 hour before NPi or ICP measurement. EVD_Either will indicate that the drainage occurred either before NPi OR ICP. A contingency plot below will show that when EVD drainage occurred, it was most prevelenly before both the ICP & NPi.

closest <- evd_drainage(closest)

Hemi-craniectomy before NPi/ICP measurement

The hemi_crani() function will identify whether or not hemi-craniectomy occurred anytime before the measurement. It is unlikley that in a one hour time-interval, one measurement could have occurred before the ICP but not NPI, or vice versa. This is true in the 69 patient analysis, but wouldn’t hurt to do a sanity check if more data is added.

closest <- hemi_crani(closest)

Add demographics

Demographics <- demo %>%
  select(Study_ID, deceased)

closest <- merge(closest, Demographics, by = "Study_ID")

NPi/ICP Burden

Add NPi and ICP burden - this was calculated using all pupil and ICP measurements within the first 24 hours upon starting ICP monitoring.

  • npi_burden1 = proportion of NPi measurements < 1
  • npi_burden3 = proportion of NPi measurements < 3
  • icp_burden = proportion of ICP measurements < 22
closest <- closest %>% 
  left_join(., burdens, by = "Study_ID")

Bin NPi

The following function bins NPi into 3 categories based on reactivity: npi_bins3 or 2 categories npi_bins2

closest <- bin_npi(closest)

Calculate time difference from the start of ICP monitoring

For each paired measurement, we calculate the time difference from the start of NPi monitoring.

Additionally, for NPi measurements that occurred \(\leq\) 1 hour before start of ICP monitoring, we will round the time difference to 0 in order to keep these in the analysis with the function below.

Lastly, we will only analyze the first 96 hours worth of measurements

closest <- monitoring_timediff(closest)

Patient Cohort

Our patient cohort of interest contains patients who have IPH, aSAH, or TBI and who had an NPi measurement within 1 hour before or after an ICP measurement, and whose pupil measurements started within the first 96 hours of ICP monitoring.

datatable(table1)

Sample Size Table

The sample_size function calculates the number of paired NPi & ICP observations, numbers of patients, and numbers of spikes within different NPi Buckets and time intervals from the start of ICP monitoring.

The below for-loop will generate a sample size table by running our sample_size function on paired measurements that fall within the following time intervals: 0-24 hours, 24-48 hours, 48-72 etc, all the way to 96 hours. We also run our function on all paired measurements

# run for-loop
sample_size_list = list()
  
  for (i in seq(from = 24, to = 96, by = 24)) {
    result <- sample_size(closest, i)
    sample_size_list[[i]] <- result # add it to your list
  }
  
  sample_size_list = do.call(rbind, sample_size_list)
  
  # Also run function on all data
  all_sample <- sample_size(closest, 0)
  
  # bind to the previous results
  sample_size_list <- rbind(all_sample, sample_size_list)
  
  row.names(sample_size_list) <- c("All Measurements", "First 24 Hours", "First 24-48 Hours",
                                   "First 48-72 Hours", "First 72-96 Hours")
  
  sample_size_table <- tibble::rownames_to_column(sample_size_list, "Analysis")

sample_size_table %>%
  kable("html") %>%
  add_header_above(c("Total Observations" = 4, 
                     "NPi < 1" = 3,
                     "NPi 1-3" = 3, 
                     "NPi > 3"  = 3)) %>%
  kable_styling(bootstrap_options = "striped")
Total Observations
NPi < 1
NPi 1-3
NPi > 3
Analysis m n m_spike Pts_Bin1 m_Bin1 m_Spikes_Bin1 Pts_Bin2 m_Bin2 m_Spikes_Bin2 Pts_Bin3 m_Bin3 m_Spikes_Bin3
All Measurements 1830 69 189 20 342 89 17 106 18 62 1382 129
First 24 Hours 571 66 80 18 130 45 13 40 6 56 401 42
First 24-48 Hours 480 58 39 11 82 18 9 22 3 52 376 40
First 48-72 Hours 396 48 36 10 63 14 7 25 6 45 308 22
First 72-96 Hours 372 44 31 8 61 9 7 18 3 38 293 24

Primary Hypothesis

Our primary hypothesis is that poor NPi is a biomarker of elevated ICP.

Linear Association of NPi and ICP

Note: Perhaps we should include in supplementary - but may be good to show as not finding a linear association could still be an important finding

closest <- closest %>% 
  mutate(NPi_bins3 = fct_relevel(NPi_bins3,
                                "< 1", 
                                "1-3",
                                "3-5"))

ggplot(closest %>% filter(timediff <= 96), 
       aes(x = ICP, y = minNPi, color = Study_ID)) + 
  geom_point() +
  theme_bw() +
  theme(legend.position = "none")

Association of NPi binned by reactivity and ICP

ggplot(closest, aes(x = NPi_bins3, y = ICP, fill = NPi_bins3)) + 
  geom_boxplot() +
  scale_fill_viridis(discrete = TRUE, alpha=0.8) +
  geom_jitter(color = "black", size=0.4, alpha=0.2) +
  theme_bw() +
  theme(legend.position = "none")

Random Mixed-effects Models

When conducting a random mixed-effects logistic regression model controlling for patient as a random effect, we observe that poor NPi (NPi < 1), is significantly associated with an increased odds of having a ICP spike.

closest$NPi_bins3 <- relevel(closest$NPi_bins3,"3-5")

m1 <- tidy(glmer(spike ~ NPi_bins3 + (1|Study_ID), 
              family = "binomial", 
              data = closest), 
              effects = "fixed")

tidy_results(m1)

Adjusting for Covariates

EVD-Drainage

EVD drainage is confounding variable -> can influence the exposure (NPi) and the outcome (ICP), however, having two variables that indicate EVD drainage before NPi and ICP would likely be correlated.

When looking at the contingency tables, we can see that for patients with EVD drainage, there were only 35 instances where the drainage did not occur within 1 hour before both the NPi and ICP measurement. Thus, we can create a variable EVD_Either to indicate whether there was EVD drainage either before NPi, ICP, or both measurements.

table(closest$EVD_NPi, closest$EVD_ICP)
##    
##       0   1
##   0 763 224
##   1  35 808
ggplot(closest %>%
         mutate(NPi_bins3 = fct_relevel(NPi_bins3,
                                "< 1", 
                                "1-3",
                                "3-5")),
       aes(x = NPi_bins3, y = ICP, fill = as.factor(EVD_Either))) +
  geom_boxplot() +
  scale_fill_viridis(discrete = TRUE, alpha=0.8) +
  geom_jitter(color = "black", size=0.4, alpha=0.2) +
  theme_bw() 

Random Mixed-effects Models

closest$NPi_bins3 <- relevel(closest$NPi_bins3,"3-5")

m1.2 <- tidy(glmer(spike ~ NPi_bins3 + EVD_Either + (1|Study_ID), 
              family = "binomial", 
              data = closest), 
              effects = "fixed")

tidy_results(m1.2)

We will also assess interaction terms. For example, NPi_bins3< 1:EVD_Either examines whether poor pupil reactivity has an interaction with EVD drainage occurring within 1 hour before. No significance was found, suggesting that we can remove the iteraction term from our model.

m1.3 <- tidy(glmer(spike ~ NPi_bins3 * EVD_Either + (1|Study_ID), 
              family = "binomial", 
              data = closest), 
              effects = "fixed")

tidy_results(m1.3)

Hemi-craniectomy

Unique patients with hemi-crani

crani_pts <- closest %>% 
       filter(hemi_crani_before == 1) %>%
       distinct(Study_ID)
nrow(crani_pts)
## [1] 11

Number of observations post hemi-craniectomy

table(closest$hemi_crani_before)
## 
##    0    1 
## 1512  318

Only 4 patients with hemi-crani and ICP > 22 after hemi-craniectomy

closest %>%
       filter(Study_ID %in% crani_pts$Study_ID,
              ICP > 22,
              hemi_crani_before == 1) %>% 
       distinct(Study_ID, Diagnosis)
##   Study_ID Diagnosis
## 1      102       TBI
## 2      118       TBI
## 3      219      aSAH
## 4      230       IPH

Distributions of NPi and ICP in observations of patients who had hemi-craniectomy at some point within the first 96 hours

In patients with hemi-craniectomy, we have very little data for observations prior to surgery. The following plots show the distribution of NPi and ICP for only the 11 patients with hemi-craniectomy at some point

Note: Patient 118 has all NPi = and always elevated ICP, 102 has 2 measurements with NPi <= 3, but the other two patients have normal NPi

ggplot(closest %>% 
         filter(Study_ID %in% crani_pts$Study_ID),
       aes(x = minNPi, fill = as.factor(hemi_crani_before))) + 
         geom_histogram() + 
  scale_fill_viridis(discrete = TRUE, alpha=0.8) +
  theme_bw() + 
  facet_wrap(~as.factor(hemi_crani_before))
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

ggplot(closest %>% 
         filter(Study_ID %in% crani_pts$Study_ID),
       aes(x = ICP, fill = as.factor(hemi_crani_before))) + 
         geom_histogram() + 
  scale_fill_viridis(discrete = TRUE, alpha=0.8) +
  theme_bw() + 
  facet_wrap(~as.factor(hemi_crani_before))
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

ggplot(closest %>%
         mutate(NPi_bins3 = fct_relevel(NPi_bins3,
                                "< 1", 
                                "1-3",
                                "3-5")),
       aes(x = NPi_bins3, y = ICP, fill = as.factor(hemi_crani_before))) +
  geom_boxplot() +
  geom_point(alpha = 0.1, position=position_jitterdodge()) + 
  scale_fill_viridis(discrete = TRUE, alpha=0.8) +
  theme_bw() 

Random Mixed-effects Models

Hemi-craniectomy does not seem to be a predictor of spikes in ICP

closest$NPi_bins3 <- relevel(closest$NPi_bins3,"3-5")

m1.4 <- tidy(glmer(spike ~ NPi_bins3 + as.factor(hemi_crani_before) + (1|Study_ID), 
              family = "binomial", 
              data = closest), 
              effects = "fixed")

tidy_results(m1.4)

Stratify observations into hemi vs non-hemicraniectomy observations

Without hemi-craniectomy observations, NPi < 1 is still significantly associated with spikes in ICP.

m1.5 <- tidy(glmer(spike ~ NPi_bins3 + EVD_Either + (1|Study_ID), 
              family = "binomial", 
              data = closest %>% filter(hemi_crani_before == 0)), 
              effects = "fixed")

tidy_results(m1.5)

To evaluate NPi in patients with hemi-craniectomy, we need to use 2 bins as we don’t have enough observations for the 3 bin approach. We see that NPi < 3 is not significantly associated with spikes in ICP in patients observations post-hemicraniectomy

m1.6 <- tidy(glmer(spike ~ NPi_bins2 + (1|Study_ID), 
              family = "binomial", 
              data = closest %>% filter(hemi_crani_before == 1)), 
              effects = "fixed")

tidy_results(m1.6)

Secondary Hypotheses

Does the strength of the association of NPi and ICP change overtime?

NPi and ICP Association Overtime

Patient & Observation counts with ICP > 22 and NPi < 3

Overall, there are few patients and observations, especially overtime, that have our outcome of interest.

  • Is this implicit survival bias in this type of analysis? Patients who are really sick would die earlier, while healthier patients, who we continue to follow, would survive. Also, patients should ideally be getting better (having less spikes, better pupil reactivity), because they are being treated
  • Can we increase sample size with extra MGH/BMC data?
closest <- obs_overtime(closest)
closest <- closest %>% 
  mutate(NPi_bins3 = fct_relevel(NPi_bins3,
                                "< 1", 
                                "1-3",
                                "3-5"))

datatable(closest %>%
       group_by(Study_ID, hour24) %>% 
       filter(minNPi < 3) %>%
       mutate(sum_spike = sum(spike)) %>%
       distinct(Study_ID, hour24, sum_spike) %>%
  tidyr::pivot_wider(names_from = hour24, 
              values_from = sum_spike,
              values_fill = 0) %>%
    select(Study_ID, `24`, `48`, `72`, `96`) %>%
    arrange(desc(`24`)))

Unique Patients with ICP > 22

ggplot(closest %>% 
         group_by(hour24, NPi_bins3) %>% 
         filter(spike == 1) %>%
         distinct(Study_ID, NPi_bins3, hour24) %>% 
         mutate(count_n = n_distinct(Study_ID)) %>% 
       distinct(NPi_bins3, hour24, count_n),
       aes(x = as.factor(hour24), y = count_n, fill = NPi_bins3)) + 
  geom_bar(stat = "identity", position = "dodge") + 
  scale_fill_viridis(discrete = TRUE, alpha=0.8) +
  xlab("Time") + 
  ylab("Unique Patients") + 
  theme_bw() 

Random Mixed-effects Models

We will use timediff to adjust for the time in hours that the NPi/ICP measurement were taking since the start of ICP monitoring.

closest$NPi_bins3 <- relevel(closest$NPi_bins3,"3-5")


m2 <- tidy(glmer(spike ~ NPi_bins3 + timediff + (1|Study_ID), 
              family = "binomial", 
              data = closest), 
              effects = "fixed")

tidy_results(m2)

There does not appear to be an interaction between NPi_bins3< 1:timediff, thus we can drop these from the model.

m3 <- tidy(glmer(spike ~ NPi_bins3 * timediff + (1|Study_ID), 
              family = "binomial", 
              data = closest), 
              effects = "fixed")

tidy_results(m3)

Adjusting for Covariates

m2.2 <- tidy(glmer(spike ~ NPi_bins3 + timediff + EVD_Either + (1|Study_ID), 
              family = "binomial", 
              data = closest), 
              effects = "fixed")

tidy_results(m2.2)
m3.2 <- tidy(glmer(spike ~ NPi_bins3 * timediff + EVD_Either + (1|Study_ID), 
              family = "binomial", 
              data = closest), 
              effects = "fixed")

tidy_results(m3.2)

Sensitivity of NPi as a Biomarker of ICP

Here we examine metrics to determine how sensitive/specific NPi < 3 is for predicting patients with ICP > 22.

Though, sensitivity is overall low, it is highest within the first 24 hours (Not sure this is really helpful with our small sample size - of note, here sensitivity was higher with NPi < 3 compared to NPi < 1)

sens24 <- sensitivity_time_function(closest, time = 24)
sens48 <- sensitivity_time_function(closest, time = 48)
sens72 <- sensitivity_time_function(closest, time = 72)
sens96 <- sensitivity_time_function(closest, time = 96)

sens_all <- rbind(sens24, sens48, sens72, sens96)

ggplot(sens_all %>% 
         pivot_longer(cols = sensitivity:npv,
                      names_to = "metric", 
                      values_to = "value"),
       aes(x = as.factor(hour24), y = value, color = metric)) + 
  scale_color_brewer(palette = "Dark2") + 
  geom_point(aes(colour = metric, group = metric)) + 
  geom_line(aes(colour = metric, group = metric)) + 
  theme_bw()

Alternative Outcomes

Timing of pupil measurements

Interestingly, the majority of the paired pupil measurements occurred after the spike in ICP - any bias here with nurses being more likely to measure after?

closest <- closest %>%
  mutate(npi_after_icp = if_else(Date_NPi >= Date_ICP, 1, 0))

ggplot(closest %>%
  mutate(NPi_bins3 = fct_relevel(NPi_bins3,
                                "< 1", 
                                "1-3",
                                "3-5")), 
       aes(x = NPi_bins3, fill = as.factor(npi_after_icp))) + 
  geom_bar(position = "dodge") + 
  scale_fill_viridis(discrete = TRUE, alpha=0.8) +
  theme_bw()

Association of NPi and ICP with Death

Note: More complex Regression models with interaction terms won’t converge

m4 <- tidy(glmer(deceased ~ NPi_bins3 + spike + (1|Study_ID), 
              family = "binomial", 
              data = closest), 
              effects = "fixed")

tidy_results(m4)
m4.1 <- tidy(glmer(deceased ~ NPi_bins3 + spike + log(timediff+1) + (1|Study_ID), 
              family = "binomial", 
              data = closest), 
              effects = "fixed")

tidy_results(m4.1)

NPi and ICP Burden to predict death

Sample size is very low for patients with increased NPi burden (10% of measurements NPi < 3) and those who were deceased

deceased_poor_npi <- closest %>% 
  distinct(Study_ID, deceased, npi_burden3) %>%
  mutate(burden10 = if_else(npi_burden3 > 0.10, 1, 0))

table(deceased_poor_npi$deceased, deceased_poor_npi$burden10)
##    
##      0  1
##   0 27 14
##   1 14 11
ggplot(closest %>% distinct(Study_ID, deceased, npi_burden1),
       aes(x = npi_burden1, fill = as.factor(deceased))) + 
  geom_histogram() + 
  theme_bw()
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## Warning: Removed 3 rows containing non-finite values (stat_bin).

ggplot(closest %>% distinct(Study_ID, deceased, npi_burden3), 
       aes(x = as.factor(deceased), y = npi_burden3, fill = as.factor(deceased))) + 
  scale_fill_viridis(discrete = TRUE, alpha=0.8) +
  geom_jitter(color = "black", size=0.4, alpha=0.2) +
  geom_boxplot() + 
  theme_bw()
## Warning: Removed 3 rows containing non-finite values (stat_boxplot).
## Warning: Removed 3 rows containing missing values (geom_point).

m4.2 <- glm(deceased ~ npi_burden1 * icp_burden,
            family = "binomial", 
            closest)

summary(m4.2)
## 
## Call:
## glm(formula = deceased ~ npi_burden1 * icp_burden, family = "binomial", 
##     data = closest)
## 
## Deviance Residuals: 
##     Min       1Q   Median       3Q      Max  
## -1.5254  -0.9418  -0.6090   1.2717   1.7673  
## 
## Coefficients:
##                         Estimate Std. Error z value Pr(>|z|)    
## (Intercept)             -0.21899    0.07176  -3.052  0.00228 ** 
## npi_burden1             -0.78932    0.17944  -4.399 1.09e-05 ***
## icp_burden             -10.51859    0.99843 -10.535  < 2e-16 ***
## npi_burden1:icp_burden  13.27434    1.09816  12.088  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 2282.1  on 1805  degrees of freedom
## Residual deviance: 2005.1  on 1802  degrees of freedom
##   (24 observations deleted due to missingness)
## AIC: 2013.1
## 
## Number of Fisher Scoring iterations: 5

NPi and ICP Burden

There is not correlation between NPi and ICP Burden. The Linear regression results are significant but we can see the data is very non-linear + many outliers

ggplot(closest, 
       aes(x = npi_burden3, y = icp_burden, color = Study_ID)) + 
  geom_point() + 
  theme_bw() + 
  theme(legend.position = "none") 
## Warning: Removed 24 rows containing missing values (geom_point).

ggplot(closest %>% distinct(Study_ID, deceased, npi_burden3, Diagnosis), 
       aes(x = Diagnosis, y = npi_burden3, fill = as.factor(Diagnosis), color = Study_ID)) + 
  scale_fill_viridis(discrete = TRUE, alpha=0.8) +
  geom_point() + 
  theme_bw() + 
  theme(legend.position = "none")
## Warning: Removed 3 rows containing missing values (geom_point).

ggplot(closest %>% distinct(Study_ID, deceased, icp_burden, Diagnosis), 
       aes(x = Diagnosis, y = icp_burden, fill = as.factor(Diagnosis), color = Study_ID)) + 
  scale_fill_viridis(discrete = TRUE, alpha=0.8) +
  geom_point() + 
  theme_bw() + 
  theme(legend.position = "none")
## Warning: Removed 3 rows containing missing values (geom_point).

burdens <- closest %>% 
  distinct(Study_ID, icp_burden, npi_burden1, npi_burden3, Diagnosis)

cor.test(burdens$icp_burden, burdens$npi_burden1, method = "spearman")
## Warning in cor.test.default(burdens$icp_burden, burdens$npi_burden1, method =
## "spearman"): Cannot compute exact p-value with ties
## 
##  Spearman's rank correlation rho
## 
## data:  burdens$icp_burden and burdens$npi_burden1
## S = 40774, p-value = 0.2329
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##      rho 
## 0.148848
cor.test(burdens$icp_burden, burdens$npi_burden3, method = "spearman")
## Warning in cor.test.default(burdens$icp_burden, burdens$npi_burden3, method =
## "spearman"): Cannot compute exact p-value with ties
## 
##  Spearman's rank correlation rho
## 
## data:  burdens$icp_burden and burdens$npi_burden3
## S = 39912, p-value = 0.1806
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##       rho 
## 0.1668543
summary(lm(icp_burden ~ npi_burden3, data = burdens))
## 
## Call:
## lm(formula = icp_burden ~ npi_burden3, data = burdens)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -0.28204 -0.06444 -0.04507  0.03330  0.71796 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  0.04507    0.02823   1.596 0.115311    
## npi_burden3  0.23697    0.06019   3.937 0.000206 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.1902 on 64 degrees of freedom
##   (3 observations deleted due to missingness)
## Multiple R-squared:  0.195,  Adjusted R-squared:  0.1824 
## F-statistic:  15.5 on 1 and 64 DF,  p-value: 0.0002061

Diagnosis

Unique number of patients by diagnosis

closest <- closest %>% 
  mutate(NPi_bins3 = fct_relevel(NPi_bins3,
                                "< 1", 
                                "1-3",
                                "3-5"))

ggplot(closest %>% 
         group_by(hour24, NPi_bins3, Diagnosis) %>% 
         filter(spike == 1) %>%
         distinct(Study_ID, NPi_bins3, hour24, Diagnosis) %>% 
         mutate(count_n = n_distinct(Study_ID)) %>% 
       distinct(NPi_bins3, hour24, count_n),
       aes(x = as.factor(hour24), y = count_n, group = NPi_bins3, fill = NPi_bins3)) + 
  geom_bar(stat = "identity", position = "dodge") + 
  scale_fill_viridis(discrete = TRUE, alpha=0.8) +
  xlab("Time") + 
  ylab("Unique Patients") + 
  theme_bw() +
  facet_wrap(~Diagnosis, nrow = 1)

NPi and ICP overtime by diagnosis

ggplot(closest,
       aes(x = as.factor(hour24), y = ICP, 
           fill = NPi_bins3)) + 
  facet_grid(rows = vars(Diagnosis),
             scales = 'free', space = 'free') +
  scale_fill_viridis(discrete = TRUE, alpha=0.8) +
  geom_jitter(color = "black", size=0.4, alpha=0.5) +
  geom_hline(yintercept= 20, size = 1, linetype="dashed", color = "slateblue") + 
  scale_y_continuous(breaks=seq(-20, 80, 10)) + 
  xlab("Hours Since Initiation of ICP Monitoring") + 
  geom_boxplot() + 
  theme_bw() + 
  labs(fill = "NPi Bin")

TBI

tbi <- closest %>% 
  filter(Diagnosis == "TBI") %>% 
  mutate(NPi_bins3 = fct_relevel(NPi_bins3,
                                "< 1", 
                                "1-3",
                                "3-5"))

table(tbi$NPi_bins3, tbi$spike)
##      
##         0   1
##   < 1  89  65
##   1-3  40   5
##   3-5 395  51
tbi$NPi_bins3 <- relevel(tbi$NPi_bins3,"3-5")

m4 <- tidy(glmer(spike ~ NPi_bins3 + (1|Study_ID), 
              family = "binomial", 
              data = tbi), 
              effects = "fixed")

tidy_results(m4)
m5 <- tidy(glmer(spike ~ NPi_bins3 + timediff + (1|Study_ID), 
              family = "binomial", 
              data = tbi), 
              effects = "fixed")

tidy_results(m5)
m6 <- tidy(glmer(spike ~ NPi_bins3 * timediff + (1|Study_ID), 
              family = "binomial", 
              data = tbi), 
              effects = "fixed")

tidy_results(m6)

aSAH

asah <- closest %>% filter(Diagnosis == "aSAH")
table(asah$NPi_bins3, asah$spike)
##      
##         0   1
##   < 1  35  14
##   1-3  28  11
##   3-5 476  36
asah$NPi_bins3 <- relevel(asah$NPi_bins3,"3-5")

m7 <- tidy(glmer(spike ~ NPi_bins3 + (1|Study_ID), 
              family = "binomial", 
              data = asah), 
              effects = "fixed")

tidy_results(m7)
m8 <- tidy(glmer(spike ~ NPi_bins3 + timediff + (1|Study_ID), 
              family = "binomial", 
              data = asah), 
              effects = "fixed")
## Warning in checkConv(attr(opt, "derivs"), opt$par, ctrl = control$checkConv, :
## unable to evaluate scaled gradient
## Warning in checkConv(attr(opt, "derivs"), opt$par, ctrl = control$checkConv, :
## Model failed to converge: degenerate Hessian with 1 negative eigenvalues
## Warning in vcov.merMod(object, use.hessian = use.hessian): variance-covariance matrix computed from finite-difference Hessian is
## not positive definite or contains NA values: falling back to var-cov estimated from RX
## Warning in vcov.merMod(object, correlation = correlation, sigm = sig): variance-covariance matrix computed from finite-difference Hessian is
## not positive definite or contains NA values: falling back to var-cov estimated from RX
tidy_results(m8)
m9 <- tidy(glmer(spike ~ NPi_bins3 * timediff + (1|Study_ID), 
              family = "binomial", 
              data = asah), 
              effects = "fixed")

tidy_results(m9)

IPH

only 7 spikes total in this patient cohort

iph <- closest %>% filter(Diagnosis == "IPH")
table(iph$NPi_bins3, iph$spike)
##      
##         0   1
##   < 1 137   2
##   1-3  22   0
##   3-5 419   5
m10 <- tidy(glmer(spike ~ NPi_bins3 + (1|Study_ID), 
              family = "binomial", 
              data = iph), 
              effects = "fixed")
## boundary (singular) fit: see ?isSingular
## Warning in vcov.merMod(object, use.hessian = use.hessian): variance-covariance matrix computed from finite-difference Hessian is
## not positive definite or contains NA values: falling back to var-cov estimated from RX
## Warning in vcov.merMod(object, correlation = correlation, sigm = sig): variance-covariance matrix computed from finite-difference Hessian is
## not positive definite or contains NA values: falling back to var-cov estimated from RX
tidy_results(m10)
m11 <- tidy(glmer(spike ~ NPi_bins3 + timediff + (1|Study_ID), 
              family = "binomial", 
              data = iph), 
              effects = "fixed")
## boundary (singular) fit: see ?isSingular
## Warning in vcov.merMod(object, use.hessian = use.hessian): variance-covariance matrix computed from finite-difference Hessian is
## not positive definite or contains NA values: falling back to var-cov estimated from RX

## Warning in vcov.merMod(object, use.hessian = use.hessian): variance-covariance matrix computed from finite-difference Hessian is
## not positive definite or contains NA values: falling back to var-cov estimated from RX
tidy_results(m11)
m12 <- tidy(glmer(spike ~ NPi_bins3 * timediff + (1|Study_ID), 
              family = "binomial", 
              data = iph), 
              effects = "fixed")
## boundary (singular) fit: see ?isSingular
## Warning in vcov.merMod(object, use.hessian = use.hessian): variance-covariance matrix computed from finite-difference Hessian is
## not positive definite or contains NA values: falling back to var-cov estimated from RX

## Warning in vcov.merMod(object, use.hessian = use.hessian): variance-covariance matrix computed from finite-difference Hessian is
## not positive definite or contains NA values: falling back to var-cov estimated from RX
tidy_results(m12)

Explore NPi before and after ICP

Note: There may be more optimal ways to set up the before and after measurements. I was trying to ensure that a before minNPi was never also an after minNPi but I feel like the logic causes us to miss some observation - at the same time we probably want to avoid before and after pairs of measurements that are occurring too closely to one another in case of potential overlap. Logic is in the 2_Merge_Pupil_ICP_Data.Rmd

table(before_after$spike)
## 
##   0   1 
## 564 105
aggregate(delta_npi ~ spike, FUN = "summary", 
          data = before_after)
##   spike delta_npi.Min. delta_npi.1st Qu. delta_npi.Median delta_npi.Mean
## 1     0    -4.60000000       -0.10000000       0.00000000     0.01276596
## 2     1    -2.70000000       -0.20000000       0.00000000    -0.08571429
##   delta_npi.3rd Qu. delta_npi.Max.
## 1        0.20000000     4.90000000
## 2        0.10000000     4.60000000
ggplot(before_after %>%
         pivot_longer(cols = before_minNPi:after_minNPi,
                      names_to = "Pupil_Time", 
                      values_to = "minNPi") %>% 
         mutate(Pupil_Time = factor(Pupil_Time,levels = c("before_minNPi", "after_minNPi"))),
       aes(x = Pupil_Time, y = minNPi, fill = as.factor(spike))) + 
  geom_boxplot() + 
  geom_jitter(color = "black", size=0.4, alpha=0.2) +
  theme_bw()

# calculate change
ggplot(before_after,
       aes(x = as.factor(spike), y = delta_npi, fill = as.factor(spike))) + 
  geom_boxplot() + 
  theme_bw()

ggplot(before_after,
       aes(x = delta_npi, fill = as.factor(spike))) + 
  geom_histogram() + 
  theme_bw()
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

ggplot(before_after, 
       aes(y = delta_npi, x = ICP)) + 
  geom_point() + 
  theme_bw()

Next Steps

  • Control for Covariates - Medications, sex, age, race?
  • Secondary Hypotheses: Timing of ICP measurements (?), NPi before AND after ICP (make sure the code is right)
LS0tDQp0aXRsZTogIioqTlBpX2FuZF9JQ1BfQW5hbHlzaXMqKiINCmF1dGhvcjogIioqQXV0aG9yOiBNZWcgSHV0Y2gqKiINCmRhdGU6ICIqKkxhc3QgY29tcGlsZWQgb24qKiBgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkICVCLCAlWTogJUg6JU0nKWAiDQotLS0NCg0KDQpUaGlzIHNjcmlwdCBhbmFseXplcyB0aGUgYXNzb2NpYXRpb24gYmV0d2VlbiBOUGkgYW5kIFNwaWtlcyBpbiBJQ1AgKElDUCA+IDIyIG1tSGcpIGF0IGRpZmZlcmVudCB0aW1lIHBvaW50cyBzdGFydGluZyBmcm9tIHRoZSBpbml0aWF0aW9uIG9mIElDUCBtb25pdG9yaW5nICh1cCB0byA5NiBob3VycykgaW4gcGF0aWVudHMgd2l0aCBUQkksIElQSCwgYW5kIGFTQUguDQoNCmBgYHtyIHNldHVwLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGthYmxlRXh0cmEpDQpsaWJyYXJ5KGxtZTQpDQpsaWJyYXJ5KGxtZXJUZXN0KQ0KbGlicmFyeShmb3JtYXR0YWJsZSkNCmxpYnJhcnkoa25pdHIpDQpsaWJyYXJ5KGZvcmNhdHMpDQpsaWJyYXJ5KHZpcmlkaXMpDQpsaWJyYXJ5KFJDb2xvckJyZXdlcikNCmxpYnJhcnkoY293cGxvdCkNCmxpYnJhcnkoYnJvb20pDQpsaWJyYXJ5KGJyb29tLm1peGVkKQ0KbGlicmFyeShEVCkNCmBgYA0KDQoqKlNldCB3b3JraW5nIGRpcmVjdG9yeSAmIExvYWQgRGF0YSoqDQoNCmBgYHtyfQ0KIyBOUGkgY2xvc2VzdCB0byBJQ1ANCmxvYWQoInByb2Nlc3NlZF9kYXRhL2ljcF9wdXBpbHNfY2xvc2VzdC5yZGEiKQ0KY2xvc2VzdCA8LSBpY3BfcHVwaWxzDQoNCiMgTlBpIEJlZm9yZSBBTkQgQWZ0ZXIgSUNQDQpsb2FkKCJwcm9jZXNzZWRfRGF0YS9pY3BfcHVwaWxzX2JlZm9yZV9hZnRlci5yZGEiKQ0KYmVmb3JlX2FmdGVyIDwtIGljcF9wdXBpbHMNCg0Kcm0oaWNwX3B1cGlscykNCg0KIyBkaWFnbm9zZXMgJiBkZW1vZ3JhcGhpY3MNCmxvYWQoInByb2Nlc3NlZF9kYXRhL2ZpbmFsX2R4LnJkYSIpDQpsb2FkKCJwcm9jZXNzZWRfZGF0YS9EZW1vZ3JhcGhpY3MucmRhIikNCmxvYWQoInByb2Nlc3NlZF9kYXRhL0RlbW9ncmFwaGljc19UYWJsZTEucmRhIikNCg0KIyBldmQNCmxvYWQoInByb2Nlc3NlZF9kYXRhL2V2ZC5yZGEiKQ0KDQojIGJ1cmRlbnMgaW4gdGhlIGZpcnN0IDI0IGhvdXJzIG9mIGljcCBtb25pdG9yaW5nDQpsb2FkKCJwcm9jZXNzZWRfZGF0YS9idXJkZW5zLnJkYSIpDQoNCnNvdXJjZSgiUi90aW1lX3NlbnNpdGl2aXR5X2Z1bmNzLnIiKQ0KYGBgDQoNCiMgKipEYXRhICYgVGltZSBJbnRlcnZhbCBTZXR1cCoqDQoNCiMjIyAqKlNlbGVjdCBUQkksIElQSCwgYW5kIGFTQUggcGF0aWVudHMqKg0KDQpgYGB7cn0NCmNsb3Nlc3QgPC0gbWVyZ2UoY2xvc2VzdCwgZmluYWxfZHgsIGJ5ID0gIlN0dWR5X0lEIikNCmJlZm9yZV9hZnRlciA8LSBtZXJnZShiZWZvcmVfYWZ0ZXIsIGZpbmFsX2R4LCBieSA9ICJTdHVkeV9JRCIpDQpgYGANCg0KIyMjICoqQWRkIENvdmFyaWF0ZXMqKg0KDQoqKkVWRCBEcmFpbmFnZSoqDQoNCklkZW50aWZ5IHdoZXRoZXIgRVZEIGRyYWluYWdlIG9jY3VycmVkIHdpdGhpbiAxIGhvdXIgYmVmb3JlIE5QaSBvciBJQ1AgbWVhc3VyZW1lbnQuIGBgYEVWRF9FaXRoZXJgYGAgd2lsbCBpbmRpY2F0ZSB0aGF0IHRoZSBkcmFpbmFnZSBvY2N1cnJlZCBlaXRoZXIgYmVmb3JlIE5QaSBPUiBJQ1AuIEEgY29udGluZ2VuY3kgcGxvdCBiZWxvdyB3aWxsIHNob3cgdGhhdCB3aGVuIEVWRCBkcmFpbmFnZSBvY2N1cnJlZCwgaXQgd2FzIG1vc3QgcHJldmVsZW5seSBiZWZvcmUgYm90aCB0aGUgSUNQICYgTlBpLg0KDQpgYGB7cn0NCmNsb3Nlc3QgPC0gZXZkX2RyYWluYWdlKGNsb3Nlc3QpDQpgYGANCg0KKipIZW1pLWNyYW5pZWN0b215IGJlZm9yZSBOUGkvSUNQIG1lYXN1cmVtZW50KioNCg0KVGhlIGBgYGhlbWlfY3JhbmkoKWBgYCBmdW5jdGlvbiB3aWxsIGlkZW50aWZ5IHdoZXRoZXIgb3Igbm90IGhlbWktY3JhbmllY3RvbXkgb2NjdXJyZWQgYW55dGltZSBiZWZvcmUgdGhlIG1lYXN1cmVtZW50LiBJdCBpcyB1bmxpa2xleSB0aGF0IGluIGEgb25lIGhvdXIgdGltZS1pbnRlcnZhbCwgb25lIG1lYXN1cmVtZW50IGNvdWxkIGhhdmUgb2NjdXJyZWQgYmVmb3JlIHRoZSBJQ1AgYnV0IG5vdCBOUEksIG9yIHZpY2UgdmVyc2EuIFRoaXMgaXMgdHJ1ZSBpbiB0aGUgNjkgcGF0aWVudCBhbmFseXNpcywgYnV0IHdvdWxkbid0IGh1cnQgdG8gZG8gYSBzYW5pdHkgY2hlY2sgaWYgbW9yZSBkYXRhIGlzIGFkZGVkLg0KDQpgYGB7cn0NCmNsb3Nlc3QgPC0gaGVtaV9jcmFuaShjbG9zZXN0KQ0KYGBgDQoNCioqQWRkIGRlbW9ncmFwaGljcyoqDQoNCmBgYHtyfQ0KRGVtb2dyYXBoaWNzIDwtIGRlbW8gJT4lDQogIHNlbGVjdChTdHVkeV9JRCwgZGVjZWFzZWQpDQoNCmNsb3Nlc3QgPC0gbWVyZ2UoY2xvc2VzdCwgRGVtb2dyYXBoaWNzLCBieSA9ICJTdHVkeV9JRCIpDQpgYGANCg0KKipOUGkvSUNQIEJ1cmRlbioqDQoNCkFkZCBOUGkgYW5kIElDUCBidXJkZW4gLSB0aGlzIHdhcyBjYWxjdWxhdGVkIHVzaW5nIGFsbCBwdXBpbCBhbmQgSUNQIG1lYXN1cmVtZW50cyB3aXRoaW4gdGhlIGZpcnN0IDI0IGhvdXJzIHVwb24gc3RhcnRpbmcgSUNQIG1vbml0b3JpbmcuIA0KDQoqIGBgYG5waV9idXJkZW4xYGBgID0gcHJvcG9ydGlvbiBvZiBOUGkgbWVhc3VyZW1lbnRzIDwgMQ0KKiBgYGBucGlfYnVyZGVuM2BgYCA9IHByb3BvcnRpb24gb2YgTlBpIG1lYXN1cmVtZW50cyA8IDMNCiogYGBgaWNwX2J1cmRlbmBgYCA9IHByb3BvcnRpb24gb2YgSUNQIG1lYXN1cmVtZW50cyA8IDIyDQoNCmBgYHtyfQ0KY2xvc2VzdCA8LSBjbG9zZXN0ICU+JSANCiAgbGVmdF9qb2luKC4sIGJ1cmRlbnMsIGJ5ID0gIlN0dWR5X0lEIikNCmBgYA0KDQoNCiMjIyAqKkJpbiBOUGkqKg0KDQpUaGUgZm9sbG93aW5nIGZ1bmN0aW9uIGJpbnMgTlBpIGludG8gMyBjYXRlZ29yaWVzIGJhc2VkIG9uIHJlYWN0aXZpdHk6IGBgYG5waV9iaW5zM2BgYCBvciAyIGNhdGVnb3JpZXMgYGBgbnBpX2JpbnMyYGBgDQoNCmBgYHtyfQ0KY2xvc2VzdCA8LSBiaW5fbnBpKGNsb3Nlc3QpDQpgYGANCg0KIyMjICoqQ2FsY3VsYXRlIHRpbWUgZGlmZmVyZW5jZSBmcm9tIHRoZSBzdGFydCBvZiBJQ1AgbW9uaXRvcmluZyoqDQoNCkZvciBlYWNoIHBhaXJlZCBtZWFzdXJlbWVudCwgd2UgY2FsY3VsYXRlIHRoZSB0aW1lIGRpZmZlcmVuY2UgZnJvbSB0aGUgc3RhcnQgb2YgTlBpIG1vbml0b3JpbmcuIA0KDQpBZGRpdGlvbmFsbHksIGZvciBOUGkgbWVhc3VyZW1lbnRzIHRoYXQgb2NjdXJyZWQgJFxsZXEkIDEgaG91ciBiZWZvcmUgc3RhcnQgb2YgSUNQIG1vbml0b3JpbmcsIHdlIHdpbGwgcm91bmQgdGhlIHRpbWUgZGlmZmVyZW5jZSB0byAwIGluIG9yZGVyIHRvIGtlZXAgdGhlc2UgaW4gdGhlIGFuYWx5c2lzIHdpdGggdGhlIGZ1bmN0aW9uIGJlbG93Lg0KDQpMYXN0bHksIHdlIHdpbGwgb25seSBhbmFseXplIHRoZSBmaXJzdCA5NiBob3VycyB3b3J0aCBvZiBtZWFzdXJlbWVudHMNCg0KYGBge3J9DQpjbG9zZXN0IDwtIG1vbml0b3JpbmdfdGltZWRpZmYoY2xvc2VzdCkNCmBgYA0KDQojICoqUGF0aWVudCBDb2hvcnQqKg0KDQpPdXIgcGF0aWVudCBjb2hvcnQgb2YgaW50ZXJlc3QgY29udGFpbnMgcGF0aWVudHMgd2hvIGhhdmUgSVBILCBhU0FILCBvciBUQkkgYW5kIHdobyBoYWQgYW4gTlBpIG1lYXN1cmVtZW50IHdpdGhpbiAxIGhvdXIgYmVmb3JlIG9yIGFmdGVyIGFuIElDUCBtZWFzdXJlbWVudCwgYW5kIHdob3NlIHB1cGlsIG1lYXN1cmVtZW50cyBzdGFydGVkIHdpdGhpbiB0aGUgZmlyc3QgOTYgaG91cnMgb2YgSUNQIG1vbml0b3JpbmcuDQoNCmBgYHtyfQ0KZGF0YXRhYmxlKHRhYmxlMSkNCmBgYA0KDQoNCiMjICoqU2FtcGxlIFNpemUgVGFibGUqKg0KDQpUaGUgYGBgc2FtcGxlX3NpemVgYGAgZnVuY3Rpb24gY2FsY3VsYXRlcyB0aGUgbnVtYmVyIG9mIHBhaXJlZCBOUGkgJiBJQ1Agb2JzZXJ2YXRpb25zLCBudW1iZXJzIG9mIHBhdGllbnRzLCBhbmQgbnVtYmVycyBvZiBzcGlrZXMgd2l0aGluIGRpZmZlcmVudCBOUGkgQnVja2V0cyBhbmQgdGltZSBpbnRlcnZhbHMgZnJvbSB0aGUgc3RhcnQgb2YgSUNQIG1vbml0b3JpbmcuDQoNClRoZSBiZWxvdyBmb3ItbG9vcCB3aWxsIGdlbmVyYXRlIGEgc2FtcGxlIHNpemUgdGFibGUgYnkgcnVubmluZyBvdXIgc2FtcGxlX3NpemUgZnVuY3Rpb24gb24gcGFpcmVkIG1lYXN1cmVtZW50cyB0aGF0IGZhbGwgd2l0aGluIHRoZSBmb2xsb3dpbmcgdGltZSBpbnRlcnZhbHM6IDAtMjQgaG91cnMsIDI0LTQ4IGhvdXJzLCA0OC03MiBldGMsIGFsbCB0aGUgd2F5IHRvIDk2IGhvdXJzLiBXZSBhbHNvIHJ1biBvdXIgZnVuY3Rpb24gb24gYWxsIHBhaXJlZCBtZWFzdXJlbWVudHMNCg0KYGBge3J9DQojIHJ1biBmb3ItbG9vcA0Kc2FtcGxlX3NpemVfbGlzdCA9IGxpc3QoKQ0KICANCiAgZm9yIChpIGluIHNlcShmcm9tID0gMjQsIHRvID0gOTYsIGJ5ID0gMjQpKSB7DQogICAgcmVzdWx0IDwtIHNhbXBsZV9zaXplKGNsb3Nlc3QsIGkpDQogICAgc2FtcGxlX3NpemVfbGlzdFtbaV1dIDwtIHJlc3VsdCAjIGFkZCBpdCB0byB5b3VyIGxpc3QNCiAgfQ0KICANCiAgc2FtcGxlX3NpemVfbGlzdCA9IGRvLmNhbGwocmJpbmQsIHNhbXBsZV9zaXplX2xpc3QpDQogIA0KICAjIEFsc28gcnVuIGZ1bmN0aW9uIG9uIGFsbCBkYXRhDQogIGFsbF9zYW1wbGUgPC0gc2FtcGxlX3NpemUoY2xvc2VzdCwgMCkNCiAgDQogICMgYmluZCB0byB0aGUgcHJldmlvdXMgcmVzdWx0cw0KICBzYW1wbGVfc2l6ZV9saXN0IDwtIHJiaW5kKGFsbF9zYW1wbGUsIHNhbXBsZV9zaXplX2xpc3QpDQogIA0KICByb3cubmFtZXMoc2FtcGxlX3NpemVfbGlzdCkgPC0gYygiQWxsIE1lYXN1cmVtZW50cyIsICJGaXJzdCAyNCBIb3VycyIsICJGaXJzdCAyNC00OCBIb3VycyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJGaXJzdCA0OC03MiBIb3VycyIsICJGaXJzdCA3Mi05NiBIb3VycyIpDQogIA0KICBzYW1wbGVfc2l6ZV90YWJsZSA8LSB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbihzYW1wbGVfc2l6ZV9saXN0LCAiQW5hbHlzaXMiKQ0KDQpzYW1wbGVfc2l6ZV90YWJsZSAlPiUNCiAga2FibGUoImh0bWwiKSAlPiUNCiAgYWRkX2hlYWRlcl9hYm92ZShjKCJUb3RhbCBPYnNlcnZhdGlvbnMiID0gNCwgDQogICAgICAgICAgICAgICAgICAgICAiTlBpIDwgMSIgPSAzLA0KICAgICAgICAgICAgICAgICAgICAgIk5QaSAxLTMiID0gMywgDQogICAgICAgICAgICAgICAgICAgICAiTlBpID4gMyIgID0gMykpICU+JQ0KICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gInN0cmlwZWQiKQ0KYGBgDQoNCiMgKipQcmltYXJ5IEh5cG90aGVzaXMqKg0KDQoqKk91ciBwcmltYXJ5IGh5cG90aGVzaXMgaXMgdGhhdCBwb29yIE5QaSBpcyBhIGJpb21hcmtlciBvZiBlbGV2YXRlZCBJQ1AuKioNCg0KIyMgKipMaW5lYXIgQXNzb2NpYXRpb24gb2YgTlBpIGFuZCBJQ1AqKg0KDQoqTm90ZTogUGVyaGFwcyB3ZSBzaG91bGQgaW5jbHVkZSBpbiBzdXBwbGVtZW50YXJ5IC0gYnV0IG1heSBiZSBnb29kIHRvIHNob3cgYXMgbm90IGZpbmRpbmcgYSBsaW5lYXIgYXNzb2NpYXRpb24gY291bGQgc3RpbGwgYmUgYW4gaW1wb3J0YW50IGZpbmRpbmcqDQoNCmBgYHtyfQ0KY2xvc2VzdCA8LSBjbG9zZXN0ICU+JSANCiAgbXV0YXRlKE5QaV9iaW5zMyA9IGZjdF9yZWxldmVsKE5QaV9iaW5zMywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjwgMSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMS0zIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjMtNSIpKQ0KDQpnZ3Bsb3QoY2xvc2VzdCAlPiUgZmlsdGVyKHRpbWVkaWZmIDw9IDk2KSwgDQogICAgICAgYWVzKHggPSBJQ1AsIHkgPSBtaW5OUGksIGNvbG9yID0gU3R1ZHlfSUQpKSArIA0KICBnZW9tX3BvaW50KCkgKw0KICB0aGVtZV9idygpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KYGBgDQoNCiMjICoqQXNzb2NpYXRpb24gb2YgTlBpIGJpbm5lZCBieSByZWFjdGl2aXR5IGFuZCBJQ1AqKg0KDQpgYGB7cn0NCmdncGxvdChjbG9zZXN0LCBhZXMoeCA9IE5QaV9iaW5zMywgeSA9IElDUCwgZmlsbCA9IE5QaV9iaW5zMykpICsgDQogIGdlb21fYm94cGxvdCgpICsNCiAgc2NhbGVfZmlsbF92aXJpZGlzKGRpc2NyZXRlID0gVFJVRSwgYWxwaGE9MC44KSArDQogIGdlb21faml0dGVyKGNvbG9yID0gImJsYWNrIiwgc2l6ZT0wLjQsIGFscGhhPTAuMikgKw0KICB0aGVtZV9idygpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KYGBgDQoNCiMjIyAqKlJhbmRvbSBNaXhlZC1lZmZlY3RzIE1vZGVscyoqDQoNCldoZW4gY29uZHVjdGluZyBhIHJhbmRvbSBtaXhlZC1lZmZlY3RzIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwgY29udHJvbGxpbmcgZm9yIHBhdGllbnQgYXMgYSByYW5kb20gZWZmZWN0LCB3ZSBvYnNlcnZlIHRoYXQgcG9vciBOUGkgKE5QaSA8IDEpLCBpcyBzaWduaWZpY2FudGx5IGFzc29jaWF0ZWQgd2l0aCBhbiBpbmNyZWFzZWQgb2RkcyBvZiBoYXZpbmcgYSBJQ1Agc3Bpa2UuDQoNCmBgYHtyfQ0KY2xvc2VzdCROUGlfYmluczMgPC0gcmVsZXZlbChjbG9zZXN0JE5QaV9iaW5zMywiMy01IikNCg0KbTEgPC0gdGlkeShnbG1lcihzcGlrZSB+IE5QaV9iaW5zMyArICgxfFN0dWR5X0lEKSwgDQogICAgICAgICAgICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsIA0KICAgICAgICAgICAgICBkYXRhID0gY2xvc2VzdCksIA0KICAgICAgICAgICAgICBlZmZlY3RzID0gImZpeGVkIikNCg0KdGlkeV9yZXN1bHRzKG0xKQ0KYGBgDQoNCiMjICoqQWRqdXN0aW5nIGZvciBDb3ZhcmlhdGVzKioNCg0KIyMjICoqRVZELURyYWluYWdlKioNCg0KRVZEIGRyYWluYWdlIGlzIGNvbmZvdW5kaW5nIHZhcmlhYmxlIC0+IGNhbiBpbmZsdWVuY2UgdGhlIGV4cG9zdXJlIChOUGkpIGFuZCB0aGUgb3V0Y29tZSAoSUNQKSwgaG93ZXZlciwgaGF2aW5nIHR3byB2YXJpYWJsZXMgdGhhdCBpbmRpY2F0ZSBFVkQgZHJhaW5hZ2UgYmVmb3JlIE5QaSBhbmQgSUNQIHdvdWxkIGxpa2VseSBiZSBjb3JyZWxhdGVkLg0KDQpXaGVuIGxvb2tpbmcgYXQgdGhlIGNvbnRpbmdlbmN5IHRhYmxlcywgd2UgY2FuIHNlZSB0aGF0IGZvciBwYXRpZW50cyB3aXRoIEVWRCBkcmFpbmFnZSwgdGhlcmUgd2VyZSBvbmx5IDM1IGluc3RhbmNlcyB3aGVyZSB0aGUgZHJhaW5hZ2UgZGlkIG5vdCBvY2N1ciB3aXRoaW4gMSBob3VyIGJlZm9yZSBib3RoIHRoZSBOUGkgYW5kIElDUCBtZWFzdXJlbWVudC4gVGh1cywgd2UgY2FuIGNyZWF0ZSBhIHZhcmlhYmxlIGBgYEVWRF9FaXRoZXJgYGAgdG8gaW5kaWNhdGUgd2hldGhlciB0aGVyZSB3YXMgRVZEIGRyYWluYWdlIGVpdGhlciBiZWZvcmUgTlBpLCBJQ1AsIG9yIGJvdGggbWVhc3VyZW1lbnRzLg0KDQpgYGB7cn0NCnRhYmxlKGNsb3Nlc3QkRVZEX05QaSwgY2xvc2VzdCRFVkRfSUNQKQ0KDQpnZ3Bsb3QoY2xvc2VzdCAlPiUNCiAgICAgICAgIG11dGF0ZShOUGlfYmluczMgPSBmY3RfcmVsZXZlbChOUGlfYmluczMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI8IDEiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjEtMyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIzLTUiKSksDQogICAgICAgYWVzKHggPSBOUGlfYmluczMsIHkgPSBJQ1AsIGZpbGwgPSBhcy5mYWN0b3IoRVZEX0VpdGhlcikpKSArDQogIGdlb21fYm94cGxvdCgpICsNCiAgc2NhbGVfZmlsbF92aXJpZGlzKGRpc2NyZXRlID0gVFJVRSwgYWxwaGE9MC44KSArDQogIGdlb21faml0dGVyKGNvbG9yID0gImJsYWNrIiwgc2l6ZT0wLjQsIGFscGhhPTAuMikgKw0KICB0aGVtZV9idygpIA0KYGBgDQoNCiMjIyAqKlJhbmRvbSBNaXhlZC1lZmZlY3RzIE1vZGVscyoqDQoNCmBgYHtyfQ0KY2xvc2VzdCROUGlfYmluczMgPC0gcmVsZXZlbChjbG9zZXN0JE5QaV9iaW5zMywiMy01IikNCg0KbTEuMiA8LSB0aWR5KGdsbWVyKHNwaWtlIH4gTlBpX2JpbnMzICsgRVZEX0VpdGhlciArICgxfFN0dWR5X0lEKSwgDQogICAgICAgICAgICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsIA0KICAgICAgICAgICAgICBkYXRhID0gY2xvc2VzdCksIA0KICAgICAgICAgICAgICBlZmZlY3RzID0gImZpeGVkIikNCg0KdGlkeV9yZXN1bHRzKG0xLjIpDQpgYGANCg0KV2Ugd2lsbCBhbHNvIGFzc2VzcyBpbnRlcmFjdGlvbiB0ZXJtcy4gRm9yIGV4YW1wbGUsIGBgYE5QaV9iaW5zMzwgMTpFVkRfRWl0aGVyYGBgIGV4YW1pbmVzIHdoZXRoZXIgcG9vciBwdXBpbCByZWFjdGl2aXR5IGhhcyBhbiBpbnRlcmFjdGlvbiB3aXRoIEVWRCBkcmFpbmFnZSBvY2N1cnJpbmcgd2l0aGluIDEgaG91ciBiZWZvcmUuIE5vIHNpZ25pZmljYW5jZSB3YXMgZm91bmQsIHN1Z2dlc3RpbmcgdGhhdCB3ZSBjYW4gcmVtb3ZlIHRoZSBpdGVyYWN0aW9uIHRlcm0gZnJvbSBvdXIgbW9kZWwuDQoNCmBgYHtyfQ0KbTEuMyA8LSB0aWR5KGdsbWVyKHNwaWtlIH4gTlBpX2JpbnMzICogRVZEX0VpdGhlciArICgxfFN0dWR5X0lEKSwgDQogICAgICAgICAgICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsIA0KICAgICAgICAgICAgICBkYXRhID0gY2xvc2VzdCksIA0KICAgICAgICAgICAgICBlZmZlY3RzID0gImZpeGVkIikNCg0KdGlkeV9yZXN1bHRzKG0xLjMpDQpgYGANCg0KIyMjICoqSGVtaS1jcmFuaWVjdG9teSoqDQoNClVuaXF1ZSBwYXRpZW50cyB3aXRoIGhlbWktY3JhbmkNCg0KYGBge3J9DQpjcmFuaV9wdHMgPC0gY2xvc2VzdCAlPiUgDQogICAgICAgZmlsdGVyKGhlbWlfY3JhbmlfYmVmb3JlID09IDEpICU+JQ0KICAgICAgIGRpc3RpbmN0KFN0dWR5X0lEKQ0KbnJvdyhjcmFuaV9wdHMpDQpgYGANCg0KTnVtYmVyIG9mIG9ic2VydmF0aW9ucyBwb3N0IGhlbWktY3JhbmllY3RvbXkNCg0KYGBge3J9DQp0YWJsZShjbG9zZXN0JGhlbWlfY3JhbmlfYmVmb3JlKQ0KYGBgDQoNCk9ubHkgNCBwYXRpZW50cyB3aXRoIGhlbWktY3JhbmkgYW5kIElDUCA+IDIyIGFmdGVyIGhlbWktY3JhbmllY3RvbXkNCg0KYGBge3J9DQpjbG9zZXN0ICU+JQ0KICAgICAgIGZpbHRlcihTdHVkeV9JRCAlaW4lIGNyYW5pX3B0cyRTdHVkeV9JRCwNCiAgICAgICAgICAgICAgSUNQID4gMjIsDQogICAgICAgICAgICAgIGhlbWlfY3JhbmlfYmVmb3JlID09IDEpICU+JSANCiAgICAgICBkaXN0aW5jdChTdHVkeV9JRCwgRGlhZ25vc2lzKQ0KYGBgDQoNCioqRGlzdHJpYnV0aW9ucyBvZiBOUGkgYW5kIElDUCBpbiBvYnNlcnZhdGlvbnMgb2YgcGF0aWVudHMgd2hvIGhhZCBoZW1pLWNyYW5pZWN0b215IGF0IHNvbWUgcG9pbnQgd2l0aGluIHRoZSBmaXJzdCA5NiBob3VycyoqDQoNCkluIHBhdGllbnRzIHdpdGggaGVtaS1jcmFuaWVjdG9teSwgd2UgaGF2ZSB2ZXJ5IGxpdHRsZSBkYXRhIGZvciBvYnNlcnZhdGlvbnMgcHJpb3IgdG8gc3VyZ2VyeS4gVGhlIGZvbGxvd2luZyBwbG90cyBzaG93IHRoZSBkaXN0cmlidXRpb24gb2YgTlBpIGFuZCBJQ1AgZm9yIG9ubHkgdGhlIDExIHBhdGllbnRzIHdpdGggaGVtaS1jcmFuaWVjdG9teSBhdCBzb21lIHBvaW50DQoNCipOb3RlOiBQYXRpZW50IDExOCBoYXMgYWxsIE5QaSA9ICBhbmQgYWx3YXlzIGVsZXZhdGVkIElDUCwgMTAyIGhhcyAyIG1lYXN1cmVtZW50cyB3aXRoIE5QaSA8PSAzLCBidXQgdGhlIG90aGVyIHR3byBwYXRpZW50cyBoYXZlIG5vcm1hbCBOUGkqDQoNCmBgYHtyfQ0KZ2dwbG90KGNsb3Nlc3QgJT4lIA0KICAgICAgICAgZmlsdGVyKFN0dWR5X0lEICVpbiUgY3JhbmlfcHRzJFN0dWR5X0lEKSwNCiAgICAgICBhZXMoeCA9IG1pbk5QaSwgZmlsbCA9IGFzLmZhY3RvcihoZW1pX2NyYW5pX2JlZm9yZSkpKSArIA0KICAgICAgICAgZ2VvbV9oaXN0b2dyYW0oKSArIA0KICBzY2FsZV9maWxsX3ZpcmlkaXMoZGlzY3JldGUgPSBUUlVFLCBhbHBoYT0wLjgpICsNCiAgdGhlbWVfYncoKSArIA0KICBmYWNldF93cmFwKH5hcy5mYWN0b3IoaGVtaV9jcmFuaV9iZWZvcmUpKQ0KDQpnZ3Bsb3QoY2xvc2VzdCAlPiUgDQogICAgICAgICBmaWx0ZXIoU3R1ZHlfSUQgJWluJSBjcmFuaV9wdHMkU3R1ZHlfSUQpLA0KICAgICAgIGFlcyh4ID0gSUNQLCBmaWxsID0gYXMuZmFjdG9yKGhlbWlfY3JhbmlfYmVmb3JlKSkpICsgDQogICAgICAgICBnZW9tX2hpc3RvZ3JhbSgpICsgDQogIHNjYWxlX2ZpbGxfdmlyaWRpcyhkaXNjcmV0ZSA9IFRSVUUsIGFscGhhPTAuOCkgKw0KICB0aGVtZV9idygpICsgDQogIGZhY2V0X3dyYXAofmFzLmZhY3RvcihoZW1pX2NyYW5pX2JlZm9yZSkpDQogIA0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KGNsb3Nlc3QgJT4lDQogICAgICAgICBtdXRhdGUoTlBpX2JpbnMzID0gZmN0X3JlbGV2ZWwoTlBpX2JpbnMzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiPCAxIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIxLTMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMy01IikpLA0KICAgICAgIGFlcyh4ID0gTlBpX2JpbnMzLCB5ID0gSUNQLCBmaWxsID0gYXMuZmFjdG9yKGhlbWlfY3JhbmlfYmVmb3JlKSkpICsNCiAgZ2VvbV9ib3hwbG90KCkgKw0KICBnZW9tX3BvaW50KGFscGhhID0gMC4xLCBwb3NpdGlvbj1wb3NpdGlvbl9qaXR0ZXJkb2RnZSgpKSArIA0KICBzY2FsZV9maWxsX3ZpcmlkaXMoZGlzY3JldGUgPSBUUlVFLCBhbHBoYT0wLjgpICsNCiAgdGhlbWVfYncoKSANCmBgYA0KDQojIyMgKipSYW5kb20gTWl4ZWQtZWZmZWN0cyBNb2RlbHMqKg0KDQpIZW1pLWNyYW5pZWN0b215IGRvZXMgbm90IHNlZW0gdG8gYmUgYSBwcmVkaWN0b3Igb2Ygc3Bpa2VzIGluIElDUA0KDQpgYGB7cn0NCmNsb3Nlc3QkTlBpX2JpbnMzIDwtIHJlbGV2ZWwoY2xvc2VzdCROUGlfYmluczMsIjMtNSIpDQoNCm0xLjQgPC0gdGlkeShnbG1lcihzcGlrZSB+IE5QaV9iaW5zMyArIGFzLmZhY3RvcihoZW1pX2NyYW5pX2JlZm9yZSkgKyAoMXxTdHVkeV9JRCksIA0KICAgICAgICAgICAgICBmYW1pbHkgPSAiYmlub21pYWwiLCANCiAgICAgICAgICAgICAgZGF0YSA9IGNsb3Nlc3QpLCANCiAgICAgICAgICAgICAgZWZmZWN0cyA9ICJmaXhlZCIpDQoNCnRpZHlfcmVzdWx0cyhtMS40KQ0KYGBgDQoNCioqU3RyYXRpZnkgb2JzZXJ2YXRpb25zIGludG8gaGVtaSB2cyBub24taGVtaWNyYW5pZWN0b215IG9ic2VydmF0aW9ucyoqDQoNCldpdGhvdXQgaGVtaS1jcmFuaWVjdG9teSBvYnNlcnZhdGlvbnMsIE5QaSA8IDEgaXMgc3RpbGwgc2lnbmlmaWNhbnRseSBhc3NvY2lhdGVkIHdpdGggc3Bpa2VzIGluIElDUC4gDQoNCmBgYHtyfQ0KbTEuNSA8LSB0aWR5KGdsbWVyKHNwaWtlIH4gTlBpX2JpbnMzICsgRVZEX0VpdGhlciArICgxfFN0dWR5X0lEKSwgDQogICAgICAgICAgICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsIA0KICAgICAgICAgICAgICBkYXRhID0gY2xvc2VzdCAlPiUgZmlsdGVyKGhlbWlfY3JhbmlfYmVmb3JlID09IDApKSwgDQogICAgICAgICAgICAgIGVmZmVjdHMgPSAiZml4ZWQiKQ0KDQp0aWR5X3Jlc3VsdHMobTEuNSkNCmBgYA0KDQpUbyBldmFsdWF0ZSBOUGkgaW4gcGF0aWVudHMgd2l0aCBoZW1pLWNyYW5pZWN0b215LCB3ZSBuZWVkIHRvIHVzZSAyIGJpbnMgYXMgd2UgZG9uJ3QgaGF2ZSBlbm91Z2ggb2JzZXJ2YXRpb25zIGZvciB0aGUgMyBiaW4gYXBwcm9hY2guIFdlIHNlZSB0aGF0IE5QaSA8IDMgaXMgbm90IHNpZ25pZmljYW50bHkgYXNzb2NpYXRlZCB3aXRoIHNwaWtlcyBpbiBJQ1AgaW4gcGF0aWVudHMgb2JzZXJ2YXRpb25zIHBvc3QtaGVtaWNyYW5pZWN0b215DQoNCmBgYHtyfQ0KbTEuNiA8LSB0aWR5KGdsbWVyKHNwaWtlIH4gTlBpX2JpbnMyICsgKDF8U3R1ZHlfSUQpLCANCiAgICAgICAgICAgICAgZmFtaWx5ID0gImJpbm9taWFsIiwgDQogICAgICAgICAgICAgIGRhdGEgPSBjbG9zZXN0ICU+JSBmaWx0ZXIoaGVtaV9jcmFuaV9iZWZvcmUgPT0gMSkpLCANCiAgICAgICAgICAgICAgZWZmZWN0cyA9ICJmaXhlZCIpDQoNCnRpZHlfcmVzdWx0cyhtMS42KQ0KYGBgDQoNCiMgKipTZWNvbmRhcnkgSHlwb3RoZXNlcyoqDQoNCioqRG9lcyB0aGUgc3RyZW5ndGggb2YgdGhlIGFzc29jaWF0aW9uIG9mIE5QaSBhbmQgSUNQIGNoYW5nZSBvdmVydGltZT8qKg0KDQojIyAqKk5QaSBhbmQgSUNQIEFzc29jaWF0aW9uIE92ZXJ0aW1lKioNCg0KIyMjICoqUGF0aWVudCAmIE9ic2VydmF0aW9uIGNvdW50cyB3aXRoIElDUCA+IDIyIGFuZCBOUGkgPCAzKioNCg0KT3ZlcmFsbCwgdGhlcmUgYXJlIGZldyBwYXRpZW50cyBhbmQgb2JzZXJ2YXRpb25zLCBlc3BlY2lhbGx5IG92ZXJ0aW1lLCB0aGF0IGhhdmUgb3VyIG91dGNvbWUgb2YgaW50ZXJlc3QuDQoNCiogSXMgdGhpcyBpbXBsaWNpdCBzdXJ2aXZhbCBiaWFzIGluIHRoaXMgdHlwZSBvZiBhbmFseXNpcz8gUGF0aWVudHMgd2hvIGFyZSByZWFsbHkgc2ljayB3b3VsZCBkaWUgZWFybGllciwgd2hpbGUgaGVhbHRoaWVyIHBhdGllbnRzLCB3aG8gd2UgY29udGludWUgdG8gZm9sbG93LCB3b3VsZCBzdXJ2aXZlLiBBbHNvLCBwYXRpZW50cyBzaG91bGQgaWRlYWxseSBiZSBnZXR0aW5nIGJldHRlciAoaGF2aW5nIGxlc3Mgc3Bpa2VzLCBiZXR0ZXIgcHVwaWwgcmVhY3Rpdml0eSksIGJlY2F1c2UgdGhleSBhcmUgYmVpbmcgdHJlYXRlZA0KKiBDYW4gd2UgaW5jcmVhc2Ugc2FtcGxlIHNpemUgd2l0aCBleHRyYSBNR0gvQk1DIGRhdGE/DQoNCmBgYHtyfQ0KY2xvc2VzdCA8LSBvYnNfb3ZlcnRpbWUoY2xvc2VzdCkNCmNsb3Nlc3QgPC0gY2xvc2VzdCAlPiUgDQogIG11dGF0ZShOUGlfYmluczMgPSBmY3RfcmVsZXZlbChOUGlfYmluczMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI8IDEiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjEtMyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIzLTUiKSkNCg0KZGF0YXRhYmxlKGNsb3Nlc3QgJT4lDQogICAgICAgZ3JvdXBfYnkoU3R1ZHlfSUQsIGhvdXIyNCkgJT4lIA0KICAgICAgIGZpbHRlcihtaW5OUGkgPCAzKSAlPiUNCiAgICAgICBtdXRhdGUoc3VtX3NwaWtlID0gc3VtKHNwaWtlKSkgJT4lDQogICAgICAgZGlzdGluY3QoU3R1ZHlfSUQsIGhvdXIyNCwgc3VtX3NwaWtlKSAlPiUNCiAgdGlkeXI6OnBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBob3VyMjQsIA0KICAgICAgICAgICAgICB2YWx1ZXNfZnJvbSA9IHN1bV9zcGlrZSwNCiAgICAgICAgICAgICAgdmFsdWVzX2ZpbGwgPSAwKSAlPiUNCiAgICBzZWxlY3QoU3R1ZHlfSUQsIGAyNGAsIGA0OGAsIGA3MmAsIGA5NmApICU+JQ0KICAgIGFycmFuZ2UoZGVzYyhgMjRgKSkpDQpgYGANCg0KIyMjICoqVW5pcXVlIFBhdGllbnRzIHdpdGggSUNQID4gMjIqKg0KDQpgYGB7cn0NCmdncGxvdChjbG9zZXN0ICU+JSANCiAgICAgICAgIGdyb3VwX2J5KGhvdXIyNCwgTlBpX2JpbnMzKSAlPiUgDQogICAgICAgICBmaWx0ZXIoc3Bpa2UgPT0gMSkgJT4lDQogICAgICAgICBkaXN0aW5jdChTdHVkeV9JRCwgTlBpX2JpbnMzLCBob3VyMjQpICU+JSANCiAgICAgICAgIG11dGF0ZShjb3VudF9uID0gbl9kaXN0aW5jdChTdHVkeV9JRCkpICU+JSANCiAgICAgICBkaXN0aW5jdChOUGlfYmluczMsIGhvdXIyNCwgY291bnRfbiksDQogICAgICAgYWVzKHggPSBhcy5mYWN0b3IoaG91cjI0KSwgeSA9IGNvdW50X24sIGZpbGwgPSBOUGlfYmluczMpKSArIA0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZG9kZ2UiKSArIA0KICBzY2FsZV9maWxsX3ZpcmlkaXMoZGlzY3JldGUgPSBUUlVFLCBhbHBoYT0wLjgpICsNCiAgeGxhYigiVGltZSIpICsgDQogIHlsYWIoIlVuaXF1ZSBQYXRpZW50cyIpICsgDQogIHRoZW1lX2J3KCkgDQpgYGANCg0KIyMjICoqUmFuZG9tIE1peGVkLWVmZmVjdHMgTW9kZWxzKioNCg0KV2Ugd2lsbCB1c2UgYGBgdGltZWRpZmZgYGAgdG8gYWRqdXN0IGZvciB0aGUgdGltZSBpbiBob3VycyB0aGF0IHRoZSBOUGkvSUNQIG1lYXN1cmVtZW50IHdlcmUgdGFraW5nIHNpbmNlIHRoZSBzdGFydCBvZiBJQ1AgbW9uaXRvcmluZy4gDQoNCmBgYHtyfQ0KY2xvc2VzdCROUGlfYmluczMgPC0gcmVsZXZlbChjbG9zZXN0JE5QaV9iaW5zMywiMy01IikNCg0KDQptMiA8LSB0aWR5KGdsbWVyKHNwaWtlIH4gTlBpX2JpbnMzICsgdGltZWRpZmYgKyAoMXxTdHVkeV9JRCksIA0KICAgICAgICAgICAgICBmYW1pbHkgPSAiYmlub21pYWwiLCANCiAgICAgICAgICAgICAgZGF0YSA9IGNsb3Nlc3QpLCANCiAgICAgICAgICAgICAgZWZmZWN0cyA9ICJmaXhlZCIpDQoNCnRpZHlfcmVzdWx0cyhtMikNCmBgYA0KDQpUaGVyZSBkb2VzIG5vdCBhcHBlYXIgdG8gYmUgYW4gaW50ZXJhY3Rpb24gYmV0d2VlbiBgYGBOUGlfYmluczM8IDE6dGltZWRpZmZgYGAsIHRodXMgd2UgY2FuIGRyb3AgdGhlc2UgZnJvbSB0aGUgbW9kZWwuDQoNCmBgYHtyfQ0KDQptMyA8LSB0aWR5KGdsbWVyKHNwaWtlIH4gTlBpX2JpbnMzICogdGltZWRpZmYgKyAoMXxTdHVkeV9JRCksIA0KICAgICAgICAgICAgICBmYW1pbHkgPSAiYmlub21pYWwiLCANCiAgICAgICAgICAgICAgZGF0YSA9IGNsb3Nlc3QpLCANCiAgICAgICAgICAgICAgZWZmZWN0cyA9ICJmaXhlZCIpDQoNCnRpZHlfcmVzdWx0cyhtMykNCmBgYA0KDQojIyMgKipBZGp1c3RpbmcgZm9yIENvdmFyaWF0ZXMqKg0KDQpgYGB7cn0NCm0yLjIgPC0gdGlkeShnbG1lcihzcGlrZSB+IE5QaV9iaW5zMyArIHRpbWVkaWZmICsgRVZEX0VpdGhlciArICgxfFN0dWR5X0lEKSwgDQogICAgICAgICAgICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsIA0KICAgICAgICAgICAgICBkYXRhID0gY2xvc2VzdCksIA0KICAgICAgICAgICAgICBlZmZlY3RzID0gImZpeGVkIikNCg0KdGlkeV9yZXN1bHRzKG0yLjIpDQoNCg0KbTMuMiA8LSB0aWR5KGdsbWVyKHNwaWtlIH4gTlBpX2JpbnMzICogdGltZWRpZmYgKyBFVkRfRWl0aGVyICsgKDF8U3R1ZHlfSUQpLCANCiAgICAgICAgICAgICAgZmFtaWx5ID0gImJpbm9taWFsIiwgDQogICAgICAgICAgICAgIGRhdGEgPSBjbG9zZXN0KSwgDQogICAgICAgICAgICAgIGVmZmVjdHMgPSAiZml4ZWQiKQ0KDQp0aWR5X3Jlc3VsdHMobTMuMikNCmBgYA0KDQojIyMgKipTZW5zaXRpdml0eSBvZiBOUGkgYXMgYSBCaW9tYXJrZXIgb2YgSUNQKioNCg0KSGVyZSB3ZSBleGFtaW5lIG1ldHJpY3MgdG8gZGV0ZXJtaW5lIGhvdyBzZW5zaXRpdmUvc3BlY2lmaWMgTlBpIDwgMyBpcyBmb3IgcHJlZGljdGluZyBwYXRpZW50cyB3aXRoIElDUCA+IDIyLiANCg0KVGhvdWdoLCBzZW5zaXRpdml0eSBpcyBvdmVyYWxsIGxvdywgaXQgaXMgaGlnaGVzdCB3aXRoaW4gdGhlIGZpcnN0IDI0IGhvdXJzIChOb3Qgc3VyZSB0aGlzIGlzIHJlYWxseSBoZWxwZnVsIHdpdGggb3VyIHNtYWxsIHNhbXBsZSBzaXplIC0gb2Ygbm90ZSwgaGVyZSBzZW5zaXRpdml0eSB3YXMgaGlnaGVyIHdpdGggTlBpIDwgMyBjb21wYXJlZCB0byBOUGkgPCAxKQ0KDQpgYGB7cn0NCnNlbnMyNCA8LSBzZW5zaXRpdml0eV90aW1lX2Z1bmN0aW9uKGNsb3Nlc3QsIHRpbWUgPSAyNCkNCnNlbnM0OCA8LSBzZW5zaXRpdml0eV90aW1lX2Z1bmN0aW9uKGNsb3Nlc3QsIHRpbWUgPSA0OCkNCnNlbnM3MiA8LSBzZW5zaXRpdml0eV90aW1lX2Z1bmN0aW9uKGNsb3Nlc3QsIHRpbWUgPSA3MikNCnNlbnM5NiA8LSBzZW5zaXRpdml0eV90aW1lX2Z1bmN0aW9uKGNsb3Nlc3QsIHRpbWUgPSA5NikNCg0Kc2Vuc19hbGwgPC0gcmJpbmQoc2VuczI0LCBzZW5zNDgsIHNlbnM3Miwgc2Vuczk2KQ0KDQpnZ3Bsb3Qoc2Vuc19hbGwgJT4lIA0KICAgICAgICAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBzZW5zaXRpdml0eTpucHYsDQogICAgICAgICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAibWV0cmljIiwgDQogICAgICAgICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gInZhbHVlIiksDQogICAgICAgYWVzKHggPSBhcy5mYWN0b3IoaG91cjI0KSwgeSA9IHZhbHVlLCBjb2xvciA9IG1ldHJpYykpICsgDQogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIikgKyANCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gbWV0cmljLCBncm91cCA9IG1ldHJpYykpICsgDQogIGdlb21fbGluZShhZXMoY29sb3VyID0gbWV0cmljLCBncm91cCA9IG1ldHJpYykpICsgDQogIHRoZW1lX2J3KCkNCmBgYA0KDQojIyAqKkFsdGVybmF0aXZlIE91dGNvbWVzKioNCg0KIyMjICoqVGltaW5nIG9mIHB1cGlsIG1lYXN1cmVtZW50cyoqDQoNCkludGVyZXN0aW5nbHksIHRoZSBtYWpvcml0eSBvZiB0aGUgcGFpcmVkIHB1cGlsIG1lYXN1cmVtZW50cyBvY2N1cnJlZCBhZnRlciB0aGUgc3Bpa2UgaW4gSUNQIC0gKmFueSBiaWFzIGhlcmUgd2l0aCBudXJzZXMgYmVpbmcgbW9yZSBsaWtlbHkgdG8gbWVhc3VyZSBhZnRlcj8qDQoNCmBgYHtyfQ0KY2xvc2VzdCA8LSBjbG9zZXN0ICU+JQ0KICBtdXRhdGUobnBpX2FmdGVyX2ljcCA9IGlmX2Vsc2UoRGF0ZV9OUGkgPj0gRGF0ZV9JQ1AsIDEsIDApKQ0KDQpnZ3Bsb3QoY2xvc2VzdCAlPiUNCiAgbXV0YXRlKE5QaV9iaW5zMyA9IGZjdF9yZWxldmVsKE5QaV9iaW5zMywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjwgMSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMS0zIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjMtNSIpKSwgDQogICAgICAgYWVzKHggPSBOUGlfYmluczMsIGZpbGwgPSBhcy5mYWN0b3IobnBpX2FmdGVyX2ljcCkpKSArIA0KICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJkb2RnZSIpICsgDQogIHNjYWxlX2ZpbGxfdmlyaWRpcyhkaXNjcmV0ZSA9IFRSVUUsIGFscGhhPTAuOCkgKw0KICB0aGVtZV9idygpDQpgYGANCg0KDQojIyMgKipBc3NvY2lhdGlvbiBvZiBOUGkgYW5kIElDUCB3aXRoIERlYXRoKioNCg0KKk5vdGU6IE1vcmUgY29tcGxleCBSZWdyZXNzaW9uIG1vZGVscyB3aXRoIGludGVyYWN0aW9uIHRlcm1zIHdvbid0IGNvbnZlcmdlKg0KDQpgYGB7cn0NCm00IDwtIHRpZHkoZ2xtZXIoZGVjZWFzZWQgfiBOUGlfYmluczMgKyBzcGlrZSArICgxfFN0dWR5X0lEKSwgDQogICAgICAgICAgICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsIA0KICAgICAgICAgICAgICBkYXRhID0gY2xvc2VzdCksIA0KICAgICAgICAgICAgICBlZmZlY3RzID0gImZpeGVkIikNCg0KdGlkeV9yZXN1bHRzKG00KQ0KDQptNC4xIDwtIHRpZHkoZ2xtZXIoZGVjZWFzZWQgfiBOUGlfYmluczMgKyBzcGlrZSArIGxvZyh0aW1lZGlmZisxKSArICgxfFN0dWR5X0lEKSwgDQogICAgICAgICAgICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsIA0KICAgICAgICAgICAgICBkYXRhID0gY2xvc2VzdCksIA0KICAgICAgICAgICAgICBlZmZlY3RzID0gImZpeGVkIikNCg0KdGlkeV9yZXN1bHRzKG00LjEpDQpgYGANCg0KKipOUGkgYW5kIElDUCBCdXJkZW4gdG8gcHJlZGljdCBkZWF0aCoqDQoNClNhbXBsZSBzaXplIGlzIHZlcnkgbG93IGZvciBwYXRpZW50cyB3aXRoIGluY3JlYXNlZCBOUGkgYnVyZGVuICgxMCUgb2YgbWVhc3VyZW1lbnRzIE5QaSA8IDMpIGFuZCB0aG9zZSB3aG8gd2VyZSBkZWNlYXNlZA0KDQpgYGB7cn0NCmRlY2Vhc2VkX3Bvb3JfbnBpIDwtIGNsb3Nlc3QgJT4lIA0KICBkaXN0aW5jdChTdHVkeV9JRCwgZGVjZWFzZWQsIG5waV9idXJkZW4zKSAlPiUNCiAgbXV0YXRlKGJ1cmRlbjEwID0gaWZfZWxzZShucGlfYnVyZGVuMyA+IDAuMTAsIDEsIDApKQ0KDQp0YWJsZShkZWNlYXNlZF9wb29yX25waSRkZWNlYXNlZCwgZGVjZWFzZWRfcG9vcl9ucGkkYnVyZGVuMTApDQoNCmdncGxvdChjbG9zZXN0ICU+JSBkaXN0aW5jdChTdHVkeV9JRCwgZGVjZWFzZWQsIG5waV9idXJkZW4xKSwNCiAgICAgICBhZXMoeCA9IG5waV9idXJkZW4xLCBmaWxsID0gYXMuZmFjdG9yKGRlY2Vhc2VkKSkpICsgDQogIGdlb21faGlzdG9ncmFtKCkgKyANCiAgdGhlbWVfYncoKQ0KDQpnZ3Bsb3QoY2xvc2VzdCAlPiUgZGlzdGluY3QoU3R1ZHlfSUQsIGRlY2Vhc2VkLCBucGlfYnVyZGVuMyksIA0KICAgICAgIGFlcyh4ID0gYXMuZmFjdG9yKGRlY2Vhc2VkKSwgeSA9IG5waV9idXJkZW4zLCBmaWxsID0gYXMuZmFjdG9yKGRlY2Vhc2VkKSkpICsgDQogIHNjYWxlX2ZpbGxfdmlyaWRpcyhkaXNjcmV0ZSA9IFRSVUUsIGFscGhhPTAuOCkgKw0KICBnZW9tX2ppdHRlcihjb2xvciA9ICJibGFjayIsIHNpemU9MC40LCBhbHBoYT0wLjIpICsNCiAgZ2VvbV9ib3hwbG90KCkgKyANCiAgdGhlbWVfYncoKQ0KYGBgDQoNCmBgYHtyfQ0KbTQuMiA8LSBnbG0oZGVjZWFzZWQgfiBucGlfYnVyZGVuMSAqIGljcF9idXJkZW4sDQogICAgICAgICAgICBmYW1pbHkgPSAiYmlub21pYWwiLCANCiAgICAgICAgICAgIGNsb3Nlc3QpDQoNCnN1bW1hcnkobTQuMikNCmBgYA0KDQojIyMgKipOUGkgYW5kIElDUCBCdXJkZW4qKg0KDQpUaGVyZSBpcyBub3QgY29ycmVsYXRpb24gYmV0d2VlbiBOUGkgYW5kIElDUCBCdXJkZW4uIFRoZSBMaW5lYXIgcmVncmVzc2lvbiByZXN1bHRzIGFyZSBzaWduaWZpY2FudCBidXQgd2UgY2FuIHNlZSB0aGUgZGF0YSBpcyB2ZXJ5IG5vbi1saW5lYXIgKyBtYW55IG91dGxpZXJzDQoNCmBgYHtyfQ0KZ2dwbG90KGNsb3Nlc3QsIA0KICAgICAgIGFlcyh4ID0gbnBpX2J1cmRlbjMsIHkgPSBpY3BfYnVyZGVuLCBjb2xvciA9IFN0dWR5X0lEKSkgKyANCiAgZ2VvbV9wb2ludCgpICsgDQogIHRoZW1lX2J3KCkgKyANCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSANCg0KZ2dwbG90KGNsb3Nlc3QgJT4lIGRpc3RpbmN0KFN0dWR5X0lELCBkZWNlYXNlZCwgbnBpX2J1cmRlbjMsIERpYWdub3NpcyksIA0KICAgICAgIGFlcyh4ID0gRGlhZ25vc2lzLCB5ID0gbnBpX2J1cmRlbjMsIGZpbGwgPSBhcy5mYWN0b3IoRGlhZ25vc2lzKSwgY29sb3IgPSBTdHVkeV9JRCkpICsgDQogIHNjYWxlX2ZpbGxfdmlyaWRpcyhkaXNjcmV0ZSA9IFRSVUUsIGFscGhhPTAuOCkgKw0KICBnZW9tX3BvaW50KCkgKyANCiAgdGhlbWVfYncoKSArIA0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQoNCmdncGxvdChjbG9zZXN0ICU+JSBkaXN0aW5jdChTdHVkeV9JRCwgZGVjZWFzZWQsIGljcF9idXJkZW4sIERpYWdub3NpcyksIA0KICAgICAgIGFlcyh4ID0gRGlhZ25vc2lzLCB5ID0gaWNwX2J1cmRlbiwgZmlsbCA9IGFzLmZhY3RvcihEaWFnbm9zaXMpLCBjb2xvciA9IFN0dWR5X0lEKSkgKyANCiAgc2NhbGVfZmlsbF92aXJpZGlzKGRpc2NyZXRlID0gVFJVRSwgYWxwaGE9MC44KSArDQogIGdlb21fcG9pbnQoKSArIA0KICB0aGVtZV9idygpICsgDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCg0KYnVyZGVucyA8LSBjbG9zZXN0ICU+JSANCiAgZGlzdGluY3QoU3R1ZHlfSUQsIGljcF9idXJkZW4sIG5waV9idXJkZW4xLCBucGlfYnVyZGVuMywgRGlhZ25vc2lzKQ0KDQpjb3IudGVzdChidXJkZW5zJGljcF9idXJkZW4sIGJ1cmRlbnMkbnBpX2J1cmRlbjEsIG1ldGhvZCA9ICJzcGVhcm1hbiIpDQpjb3IudGVzdChidXJkZW5zJGljcF9idXJkZW4sIGJ1cmRlbnMkbnBpX2J1cmRlbjMsIG1ldGhvZCA9ICJzcGVhcm1hbiIpDQoNCnN1bW1hcnkobG0oaWNwX2J1cmRlbiB+IG5waV9idXJkZW4zLCBkYXRhID0gYnVyZGVucykpDQpgYGANCg0KDQojIyAqKkRpYWdub3NpcyoqDQoNCiMjIyAqKlVuaXF1ZSBudW1iZXIgb2YgcGF0aWVudHMgYnkgZGlhZ25vc2lzKioNCg0KYGBge3J9DQpjbG9zZXN0IDwtIGNsb3Nlc3QgJT4lIA0KICBtdXRhdGUoTlBpX2JpbnMzID0gZmN0X3JlbGV2ZWwoTlBpX2JpbnMzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiPCAxIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIxLTMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMy01IikpDQoNCmdncGxvdChjbG9zZXN0ICU+JSANCiAgICAgICAgIGdyb3VwX2J5KGhvdXIyNCwgTlBpX2JpbnMzLCBEaWFnbm9zaXMpICU+JSANCiAgICAgICAgIGZpbHRlcihzcGlrZSA9PSAxKSAlPiUNCiAgICAgICAgIGRpc3RpbmN0KFN0dWR5X0lELCBOUGlfYmluczMsIGhvdXIyNCwgRGlhZ25vc2lzKSAlPiUgDQogICAgICAgICBtdXRhdGUoY291bnRfbiA9IG5fZGlzdGluY3QoU3R1ZHlfSUQpKSAlPiUgDQogICAgICAgZGlzdGluY3QoTlBpX2JpbnMzLCBob3VyMjQsIGNvdW50X24pLA0KICAgICAgIGFlcyh4ID0gYXMuZmFjdG9yKGhvdXIyNCksIHkgPSBjb3VudF9uLCBncm91cCA9IE5QaV9iaW5zMywgZmlsbCA9IE5QaV9iaW5zMykpICsgDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsgDQogIHNjYWxlX2ZpbGxfdmlyaWRpcyhkaXNjcmV0ZSA9IFRSVUUsIGFscGhhPTAuOCkgKw0KICB4bGFiKCJUaW1lIikgKyANCiAgeWxhYigiVW5pcXVlIFBhdGllbnRzIikgKyANCiAgdGhlbWVfYncoKSArDQogIGZhY2V0X3dyYXAofkRpYWdub3NpcywgbnJvdyA9IDEpDQpgYGANCg0KIyMjICoqTlBpIGFuZCBJQ1Agb3ZlcnRpbWUgYnkgZGlhZ25vc2lzKioNCg0KYGBge3J9DQpnZ3Bsb3QoY2xvc2VzdCwNCiAgICAgICBhZXMoeCA9IGFzLmZhY3Rvcihob3VyMjQpLCB5ID0gSUNQLCANCiAgICAgICAgICAgZmlsbCA9IE5QaV9iaW5zMykpICsgDQogIGZhY2V0X2dyaWQocm93cyA9IHZhcnMoRGlhZ25vc2lzKSwNCiAgICAgICAgICAgICBzY2FsZXMgPSAnZnJlZScsIHNwYWNlID0gJ2ZyZWUnKSArDQogIHNjYWxlX2ZpbGxfdmlyaWRpcyhkaXNjcmV0ZSA9IFRSVUUsIGFscGhhPTAuOCkgKw0KICBnZW9tX2ppdHRlcihjb2xvciA9ICJibGFjayIsIHNpemU9MC40LCBhbHBoYT0wLjUpICsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0PSAyMCwgc2l6ZSA9IDEsIGxpbmV0eXBlPSJkYXNoZWQiLCBjb2xvciA9ICJzbGF0ZWJsdWUiKSArIA0KICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgtMjAsIDgwLCAxMCkpICsgDQogIHhsYWIoIkhvdXJzIFNpbmNlIEluaXRpYXRpb24gb2YgSUNQIE1vbml0b3JpbmciKSArIA0KICBnZW9tX2JveHBsb3QoKSArIA0KICB0aGVtZV9idygpICsgDQogIGxhYnMoZmlsbCA9ICJOUGkgQmluIikNCmBgYA0KDQojIyMgKipUQkkqKg0KDQpgYGB7cn0NCnRiaSA8LSBjbG9zZXN0ICU+JSANCiAgZmlsdGVyKERpYWdub3NpcyA9PSAiVEJJIikgJT4lIA0KICBtdXRhdGUoTlBpX2JpbnMzID0gZmN0X3JlbGV2ZWwoTlBpX2JpbnMzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiPCAxIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIxLTMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMy01IikpDQoNCnRhYmxlKHRiaSROUGlfYmluczMsIHRiaSRzcGlrZSkNCg0KdGJpJE5QaV9iaW5zMyA8LSByZWxldmVsKHRiaSROUGlfYmluczMsIjMtNSIpDQoNCm00IDwtIHRpZHkoZ2xtZXIoc3Bpa2UgfiBOUGlfYmluczMgKyAoMXxTdHVkeV9JRCksIA0KICAgICAgICAgICAgICBmYW1pbHkgPSAiYmlub21pYWwiLCANCiAgICAgICAgICAgICAgZGF0YSA9IHRiaSksIA0KICAgICAgICAgICAgICBlZmZlY3RzID0gImZpeGVkIikNCg0KdGlkeV9yZXN1bHRzKG00KQ0KDQptNSA8LSB0aWR5KGdsbWVyKHNwaWtlIH4gTlBpX2JpbnMzICsgdGltZWRpZmYgKyAoMXxTdHVkeV9JRCksIA0KICAgICAgICAgICAgICBmYW1pbHkgPSAiYmlub21pYWwiLCANCiAgICAgICAgICAgICAgZGF0YSA9IHRiaSksIA0KICAgICAgICAgICAgICBlZmZlY3RzID0gImZpeGVkIikNCg0KdGlkeV9yZXN1bHRzKG01KQ0KDQptNiA8LSB0aWR5KGdsbWVyKHNwaWtlIH4gTlBpX2JpbnMzICogdGltZWRpZmYgKyAoMXxTdHVkeV9JRCksIA0KICAgICAgICAgICAgICBmYW1pbHkgPSAiYmlub21pYWwiLCANCiAgICAgICAgICAgICAgZGF0YSA9IHRiaSksIA0KICAgICAgICAgICAgICBlZmZlY3RzID0gImZpeGVkIikNCg0KdGlkeV9yZXN1bHRzKG02KQ0KYGBgDQoNCg0KIyMjICoqYVNBSCoqDQoNCmBgYHtyfQ0KYXNhaCA8LSBjbG9zZXN0ICU+JSBmaWx0ZXIoRGlhZ25vc2lzID09ICJhU0FIIikNCnRhYmxlKGFzYWgkTlBpX2JpbnMzLCBhc2FoJHNwaWtlKQ0KDQphc2FoJE5QaV9iaW5zMyA8LSByZWxldmVsKGFzYWgkTlBpX2JpbnMzLCIzLTUiKQ0KDQptNyA8LSB0aWR5KGdsbWVyKHNwaWtlIH4gTlBpX2JpbnMzICsgKDF8U3R1ZHlfSUQpLCANCiAgICAgICAgICAgICAgZmFtaWx5ID0gImJpbm9taWFsIiwgDQogICAgICAgICAgICAgIGRhdGEgPSBhc2FoKSwgDQogICAgICAgICAgICAgIGVmZmVjdHMgPSAiZml4ZWQiKQ0KDQp0aWR5X3Jlc3VsdHMobTcpDQoNCm04IDwtIHRpZHkoZ2xtZXIoc3Bpa2UgfiBOUGlfYmluczMgKyB0aW1lZGlmZiArICgxfFN0dWR5X0lEKSwgDQogICAgICAgICAgICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsIA0KICAgICAgICAgICAgICBkYXRhID0gYXNhaCksIA0KICAgICAgICAgICAgICBlZmZlY3RzID0gImZpeGVkIikNCg0KdGlkeV9yZXN1bHRzKG04KQ0KDQptOSA8LSB0aWR5KGdsbWVyKHNwaWtlIH4gTlBpX2JpbnMzICogdGltZWRpZmYgKyAoMXxTdHVkeV9JRCksIA0KICAgICAgICAgICAgICBmYW1pbHkgPSAiYmlub21pYWwiLCANCiAgICAgICAgICAgICAgZGF0YSA9IGFzYWgpLCANCiAgICAgICAgICAgICAgZWZmZWN0cyA9ICJmaXhlZCIpDQoNCnRpZHlfcmVzdWx0cyhtOSkNCmBgYA0KDQoNCiMjIyAqKklQSCoqDQoNCioqb25seSA3IHNwaWtlcyB0b3RhbCBpbiB0aGlzIHBhdGllbnQgY29ob3J0KioNCg0KYGBge3J9DQppcGggPC0gY2xvc2VzdCAlPiUgZmlsdGVyKERpYWdub3NpcyA9PSAiSVBIIikNCnRhYmxlKGlwaCROUGlfYmluczMsIGlwaCRzcGlrZSkNCg0KbTEwIDwtIHRpZHkoZ2xtZXIoc3Bpa2UgfiBOUGlfYmluczMgKyAoMXxTdHVkeV9JRCksIA0KICAgICAgICAgICAgICBmYW1pbHkgPSAiYmlub21pYWwiLCANCiAgICAgICAgICAgICAgZGF0YSA9IGlwaCksIA0KICAgICAgICAgICAgICBlZmZlY3RzID0gImZpeGVkIikNCg0KdGlkeV9yZXN1bHRzKG0xMCkNCg0KbTExIDwtIHRpZHkoZ2xtZXIoc3Bpa2UgfiBOUGlfYmluczMgKyB0aW1lZGlmZiArICgxfFN0dWR5X0lEKSwgDQogICAgICAgICAgICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsIA0KICAgICAgICAgICAgICBkYXRhID0gaXBoKSwgDQogICAgICAgICAgICAgIGVmZmVjdHMgPSAiZml4ZWQiKQ0KDQp0aWR5X3Jlc3VsdHMobTExKQ0KDQptMTIgPC0gdGlkeShnbG1lcihzcGlrZSB+IE5QaV9iaW5zMyAqIHRpbWVkaWZmICsgKDF8U3R1ZHlfSUQpLCANCiAgICAgICAgICAgICAgZmFtaWx5ID0gImJpbm9taWFsIiwgDQogICAgICAgICAgICAgIGRhdGEgPSBpcGgpLCANCiAgICAgICAgICAgICAgZWZmZWN0cyA9ICJmaXhlZCIpDQoNCnRpZHlfcmVzdWx0cyhtMTIpDQpgYGANCg0KIyMgKipFeHBsb3JlIE5QaSBiZWZvcmUgYW5kIGFmdGVyIElDUCAqKg0KDQoqTm90ZTogVGhlcmUgbWF5IGJlIG1vcmUgb3B0aW1hbCB3YXlzIHRvIHNldCB1cCB0aGUgYmVmb3JlIGFuZCBhZnRlciBtZWFzdXJlbWVudHMuIEkgd2FzIHRyeWluZyB0byBlbnN1cmUgdGhhdCBhIGJlZm9yZSBtaW5OUGkgd2FzIG5ldmVyIGFsc28gYW4gYWZ0ZXIgbWluTlBpIGJ1dCBJIGZlZWwgbGlrZSB0aGUgbG9naWMgY2F1c2VzIHVzIHRvIG1pc3Mgc29tZSBvYnNlcnZhdGlvbiAtIGF0IHRoZSBzYW1lIHRpbWUgd2UgcHJvYmFibHkgd2FudCB0byBhdm9pZCBiZWZvcmUgYW5kIGFmdGVyIHBhaXJzIG9mIG1lYXN1cmVtZW50cyB0aGF0IGFyZSBvY2N1cnJpbmcgdG9vIGNsb3NlbHkgdG8gb25lIGFub3RoZXIgaW4gY2FzZSBvZiBwb3RlbnRpYWwgb3ZlcmxhcC4gTG9naWMgaXMgaW4gdGhlIDJfTWVyZ2VfUHVwaWxfSUNQX0RhdGEuUm1kKg0KDQpgYGB7cn0NCnRhYmxlKGJlZm9yZV9hZnRlciRzcGlrZSkNCmFnZ3JlZ2F0ZShkZWx0YV9ucGkgfiBzcGlrZSwgRlVOID0gInN1bW1hcnkiLCANCiAgICAgICAgICBkYXRhID0gYmVmb3JlX2FmdGVyKQ0KDQpnZ3Bsb3QoYmVmb3JlX2FmdGVyICU+JQ0KICAgICAgICAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBiZWZvcmVfbWluTlBpOmFmdGVyX21pbk5QaSwNCiAgICAgICAgICAgICAgICAgICAgICBuYW1lc190byA9ICJQdXBpbF9UaW1lIiwgDQogICAgICAgICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gIm1pbk5QaSIpICU+JSANCiAgICAgICAgIG11dGF0ZShQdXBpbF9UaW1lID0gZmFjdG9yKFB1cGlsX1RpbWUsbGV2ZWxzID0gYygiYmVmb3JlX21pbk5QaSIsICJhZnRlcl9taW5OUGkiKSkpLA0KICAgICAgIGFlcyh4ID0gUHVwaWxfVGltZSwgeSA9IG1pbk5QaSwgZmlsbCA9IGFzLmZhY3RvcihzcGlrZSkpKSArIA0KICBnZW9tX2JveHBsb3QoKSArIA0KICBnZW9tX2ppdHRlcihjb2xvciA9ICJibGFjayIsIHNpemU9MC40LCBhbHBoYT0wLjIpICsNCiAgdGhlbWVfYncoKQ0KDQojIGNhbGN1bGF0ZSBjaGFuZ2UNCmdncGxvdChiZWZvcmVfYWZ0ZXIsDQogICAgICAgYWVzKHggPSBhcy5mYWN0b3Ioc3Bpa2UpLCB5ID0gZGVsdGFfbnBpLCBmaWxsID0gYXMuZmFjdG9yKHNwaWtlKSkpICsgDQogIGdlb21fYm94cGxvdCgpICsgDQogIHRoZW1lX2J3KCkNCg0KZ2dwbG90KGJlZm9yZV9hZnRlciwNCiAgICAgICBhZXMoeCA9IGRlbHRhX25waSwgZmlsbCA9IGFzLmZhY3RvcihzcGlrZSkpKSArIA0KICBnZW9tX2hpc3RvZ3JhbSgpICsgDQogIHRoZW1lX2J3KCkNCg0KZ2dwbG90KGJlZm9yZV9hZnRlciwgDQogICAgICAgYWVzKHkgPSBkZWx0YV9ucGksIHggPSBJQ1ApKSArIA0KICBnZW9tX3BvaW50KCkgKyANCiAgdGhlbWVfYncoKQ0KYGBgDQoNCiMgKipOZXh0IFN0ZXBzKioNCiogQ29udHJvbCBmb3IgQ292YXJpYXRlcyAtIE1lZGljYXRpb25zLCBzZXgsIGFnZSwgcmFjZT8NCiogU2Vjb25kYXJ5IEh5cG90aGVzZXM6IFRpbWluZyBvZiBJQ1AgbWVhc3VyZW1lbnRzICg/KSwgTlBpIGJlZm9yZSBBTkQgYWZ0ZXIgSUNQIChtYWtlIHN1cmUgdGhlIGNvZGUgaXMgcmlnaHQpDQoNCg0KDQo=