updates

2019-07-09

three dates changed, #55, #136 & #183

General reading: Bewick, V., Cheek, L., Ball, J., 2004. Statistics review 12: survival analysis. Crit. Care 8, 389โ€“394. https://www.ncbi.nlm.nih.gov/pmc/articles/PMC1065034/

PACKAGES

SAMPLE SIZE

Pre-study

consider a trial with 2 year maximum follow-up 6 month uniform enrollment Control/HT hazards = 0.1/0.2 per 1 person-year drop out hazard 0.1 per 1 person-year alpha = 0.025 (1-sided) power = 0.80 (default beta=.1)

ss <- nSurvival(
  lambda1 = .1 ,  ## hazard rate control
  lambda2 = .25,  ## hazard rate HT
  eta = .1,  ## equal drop out rate for both groups
  Ts = 9,  ## maximum study duration
  Tr = 3,  ## accrual (recruitment) duration
  sided = 1,
  alpha = .025,
  ratio = 1,
  beta = .2
)
ss  # default values
Fixed design, two-arm trial with time-to-event
outcome (Lachin and Foulkes, 1986).
Study duration (fixed):          Ts=9
Accrual duration (fixed):        Tr=3
Uniform accrual:              entry="unif"
Control median:      log(2)/lambda1=6.9
Experimental median: log(2)/lambda2=2.8
Censoring median:        log(2)/eta=6.9
Control failure rate:       lambda1=0.1
Experimental failure rate:  lambda2=0.25
Censoring rate:                 eta=0.1
Power:                 100*(1-beta)=80%
Type I error (1-sided):   100*alpha=2.5%
Equal randomization:          ratio=1
Sample size based on hazard ratio=2.5 (type="rr")
Sample size (computed):           n=72
Events required (computed): nEvents=37

Do we have enought statistical power with 39?

See 1. Post hoc power analysis: an idea whose time has passed? M. Levine, M. H. Ensom. Pharmacotherapy 2001: 21(4); 405-9. 2. Confidence limit analyses should replace power calculations in the interpretation of epidemiologic studies. A. H. Smith, M. N. Bates. Epidemiology 1992: 3(5); 449-52. โ€

# Example 14.42 in Rosner B. Fundamentals of Biostatistics.
# (6-th edition). (2006) page 809
powerCT.default(nE = 39, # number of participants in the experimental group.
                nC = 39, # number of participants in the control group.
                pE = 0.6, # probability of failure in group E (experimental group) over the maximum time period of the study (t years).
                pC = 0.5, # probability of failure in group C (control group) over the maximum time period of the study (t years).
                RR = 0.1, # postulated hazard ratio.
                alpha = 0.05) #ype I error rate
[1] 0.9996618

Yes, more than enough.

LOAD DATA

df <- df %>% 
  select(-c(Comments, `Marca temporal`)) # remove unwanted columns

Check variables

Verify the completeness of the data

visdat::vis_dat(df)

DATA CLEANING AND WRANGLING

Convert dates

df$`Treatment date` <-  lubridate::dmy(df$`Treatment date`)
df$`Date of the last radiograph BEFORE the treatment` <- lubridate::dmy(df$`Date of the last radiograph BEFORE the treatment`)
df$`Date First Time noted as having exfoliated: (Hall)` <- lubridate::dmy(df$`Date First Time noted as having exfoliated: (Hall)`)
df$`Date First Time noted as having exfoliated: (Contralateral)` <- lubridate::dmy(df$`Date First Time noted as having exfoliated: (Contralateral)`)
df$`Date of the radiograph 2` <- lubridate::dmy(df$`Date of the radiograph 2`)
df$`Birth Date` <- lubridate::dmy(df$`Birth Date`)

Add id sequential number

df <- df %>% mutate(id = row_number())

Change tooth variable

df$`Hall Crown Tooth` <- as.character(df$`Hall Crown Tooth`)
df$`Contralateral Tooth` <- as.character(df$`Contralateral Tooth`)

Create age at the start of the intervention

Three dates were corrected (treatment and birth changed: 55, 183 and 136.

df <- df %>%
  mutate(age = interval(ymd(`Birth Date`), ymd(`Treatment date`)) / years(1),
         age = if_else(age < 0, age + 100, age))

Change names, etc

df <- df %>%
  janitor::clean_names() %>%
  janitor::remove_empty(c("rows", "cols"))

Check age

df %>%
  ggplot(aes(x = age)) +
  geom_histogram(bins = 10) +
  scale_y_continuous(labels = scales::number_format(accuracy = 1)) +
  scale_x_continuous(labels = scales::number_format(accuracy = 1)) +
  facet_wrap(~ gender) +
  theme_pubclean() +
  labs(
  title = "Age by gender",
  y = "Count",
  x = "Age (years"
  )

Create new var grouping firsts molars and second molars

df <- df %>% 
  mutate(hall_molar = case_when(
    hall_crown_tooth %in% c(55, 65, 75, 85) ~ "1st", 
    TRUE ~ "2nd"
  )) %>% 
  mutate(contralateral_molar = case_when(
    contralateral_tooth %in% c(55, 65, 75, 85) ~ "1st", 
    TRUE ~ "2nd"
  ))

Create new var for maxillar and mandibular molars

df <- df %>% 
  mutate(hall_jaw = case_when(
    hall_crown_tooth %in% c(55, 65) ~ "Maxillary H Molar", 
    TRUE ~ "Mandibular H molar"
  )) %>% 
  mutate((contralateral_jaw = case_when(
    contralateral_tooth %in% c(55, 65) ~ "Maxillary C Molar", 
    TRUE ~ "Mandibular C molar"
  )))

Dataset ready for analysis

EDA

Age

df %>%
  ggplot(aes( x = age)) +
  geom_histogram(bins = 10) +
  scale_y_continuous(labels = scales::number_format(accuracy = 1)) +
  facet_wrap( ~ gender) +
  labs(title = "Age at the time of the treatment by gender",
       y = "Count",
       x = "Age") +
  theme_pubclean()

Any difference of sex by gender?

There is NO SIGNIFICANT difference in the age mean by gender The age means of girls and boys are 7.450262, 8.0041041 respectively, and this difference is NON significant (p-value = 0.0264872 )

More info

t.test(age ~ gender, data = df)

    Welch Two Sample t-test

data:  age by gender
t = -1.0985, df = 35.738, p-value = 0.2793
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -1.5766407  0.4689565
sample estimates:
mean in group Female   mean in group Male 
            7.450262             8.004104 

Gender proportions

table(df$gender)

Female   Male 
    20     19 

The proportion of women is almost half, so obviously the proportion test will deliver a non-significant value for the difference.

prop.test(x = 20,
          n = 39,
          p = 0.5,
          correct = FALSE)

    1-sample proportions test without continuity correction

data:  20 out of 39, null probability 0.5
X-squared = 0.025641, df = 1, p-value = 0.8728
alternative hypothesis: true p is not equal to 0.5
95 percent confidence interval:
 0.3619936 0.6613482
sample estimates:
        p 
0.5128205 
df %>%
  ggplot(aes(x = gender)) +
  geom_bar() +
  labs(title = "Gender distribution",
       y = "Count",
       x = "Gender") +
  theme_pubclean()

Tooth

df %>%
  ggplot(aes(x = hall_crown_tooth, fill = gender)) +
  geom_bar() +
  facet_grid(gender~. ) +
  labs(title = "Tooth distribution by gender",
  y = "Count",
  x = "Tooth") +
  theme_pubclean() +
  guides(fill = FALSE) # remove the legend

df %>% 
  mutate(molar = case_when(
    hall_crown_tooth %in% c(55, 65) ~ "UFPM", 
    hall_crown_tooth %in% c(54, 64) ~ "USPM",
    hall_crown_tooth %in% c(85, 75) ~ "LFPM",
    TRUE ~ "LSPM", 
  )) %>% 
    select(gender, molar, hall_crown_tooth) %>% 
  select(gender, molar, hall_crown_tooth) %>% 
  ggplot(aes(x = molar, fill = gender)) +
  geom_bar() + 
  labs(title = "Molar distribution by gender", 
       y = "Count", x = "Molar type", fill = "Gender") + 
  theme_pubclean() + 
  facet_grid(gender~.) + 
  guides(fill = FALSE) # remove the legend

table by gender

df %>% 
  janitor::tabyl(hall_molar, gender ) %>% 
  janitor::adorn_totals("col") 
 hall_molar Female Male Total
        1st     11   14    25
        2nd      9    5    14

Molar distribution by gender

df %>%
  ggplot(aes(x = hall_molar)) +
  geom_bar() +
  facet_wrap( ~ gender) +
  labs(title = "Molar distribution by gender",
       y = "Count",
       x = "Molar") +
  theme_pubclean()

Distribution of teeth-pairs per gender

plot teeth pairs

df %>%
  ggplot(aes(x = hall_molar,
             y = contralateral_molar,
             color = gender)) +
  geom_jitter(alpha = 0.5, width = .1, height = .1) +
  theme_pubclean() +
  labs(title = "Distribution of molar-pairs by gender", 
       y = "Contralateral molar", 
       x = "HT molar", 
       color = "Gender")

chisq.test(table(df$gender, df$hall_crown_tooth))
Chi-squared approximation may be incorrect

    Pearson's Chi-squared test

data:  table(df$gender, df$hall_crown_tooth)
X-squared = 8.1797, df = 7, p-value = 0.317

Table 1

DONE

COMBINE 55/65, etc
################## DONE #####################

table1::table1( ~ age +
                  hall_molar +
                  contralateral_molar +
                  type_of_radiograph +
                  demirjian_index_perm_tooth_hall_tooth_crown + 
                  demirjian_index_perm_tooth_contralateral
                | gender ,
                data = df)
Female
(n=20)
Male
(n=19)
Overall
(n=39)
age
Mean (SD) 7.45 (1.46) 8.00 (1.67) 7.72 (1.57)
Median [Min, Max] 7.35 [4.15, 10.0] 7.74 [5.15, 11.5] 7.70 [4.15, 11.5]
hall_molar
1st 11 (55.0%) 14 (73.7%) 25 (64.1%)
2nd 9 (45.0%) 5 (26.3%) 14 (35.9%)
contralateral_molar
1st 11 (55.0%) 14 (73.7%) 25 (64.1%)
2nd 9 (45.0%) 5 (26.3%) 14 (35.9%)
type_of_radiograph
Bitewing 8 (40.0%) 7 (36.8%) 15 (38.5%)
OPT 12 (60.0%) 12 (63.2%) 24 (61.5%)
demirjian_index_perm_tooth_hall_tooth_crown
E 5 (25.0%) 4 (21.1%) 9 (23.1%)
F 3 (15.0%) 6 (31.6%) 9 (23.1%)
G 3 (15.0%) 2 (10.5%) 5 (12.8%)
H 1 (5.0%) 0 (0%) 1 (2.6%)
Not possible to determine (bitewing) 8 (40.0%) 7 (36.8%) 15 (38.5%)
demirjian_index_perm_tooth_contralateral
E 4 (20.0%) 5 (26.3%) 9 (23.1%)
F 4 (20.0%) 6 (31.6%) 10 (25.6%)
G 3 (15.0%) 0 (0%) 3 (7.7%)
H 1 (5.0%) 1 (5.3%) 2 (5.1%)
Not possible to determine (bitewing) 8 (40.0%) 7 (36.8%) 15 (38.5%)

Demirjian status

TO DO

COMBINE 55/65, etc AND graph by teeth ################## TO DO #####################

df %>%
  filter(
  demirjian_index_perm_tooth_hall_tooth_crown != "Not possible to determine (bitewing)" |
  demirjian_index_perm_tooth_contralateral != "Not possible to determine (bitewing)"
  ) %>%
  ggplot(
  aes(x = demirjian_index_perm_tooth_hall_tooth_crown,
  y = demirjian_index_perm_tooth_contralateral,
  color = hall_molar)
  ) +
  # geom_point() +
  geom_jitter(alpha = 0.5, width = .15, height = .15) +
  labs(title = "Demirjian status of HT and contralateral baseline",
  y = "HT",
  x = "CT") +
  theme_pubclean()

NA

TO DO

Compare 1st prim molar with 2d prim molar with Demirjian and exof_time ################## TO DO #####################

Check


df %>%
  filter(
  demirjian_index_perm_tooth_hall_tooth_crown != "Not possible to determine (bitewing)" |
  demirjian_index_perm_tooth_contralateral != "Not possible to determine (bitewing)"
  ) %$% # this also do the trick!
  fisher.test(
  table(
  demirjian_index_perm_tooth_hall_tooth_crown,
  .$demirjian_index_perm_tooth_contralateral
  )
  )

    Fisher's Exact Test for Count Data

data:  table(demirjian_index_perm_tooth_hall_tooth_crown, .$demirjian_index_perm_tooth_contralateral)
p-value = 0.0001543
alternative hypothesis: two.sided

Ok, so maybe any difference in the survival by gender could be explained by the demirjian status at the beggining of the follow-up

Status of the contralateral tooth by gender

df %>%
  ggplot(aes(x = status_of_the_contralateral_tooth)) +
  geom_bar() +
  labs(title = "Status of the contralateral tooth",
  y = "Count",
  x = "Status") +
  theme_pubclean() 

DONE

change scale from 4, 3, 2, 1, 0, exf ################# DONE #####################

df$degree_of_primary_tooth_resorption_contralateral <-
  fct_relevel(
  df$degree_of_primary_tooth_resorption_contralateral,
  "4",
  "3",
  "2",
  "1",
  "0",
  "exfoliated"
  )

df$degree_of_primary_tooth_resorption_hall_tooth_crown <-
  fct_relevel(
  df$degree_of_primary_tooth_resorption_hall_tooth_crown,
  "4",
  "3",
  "2",
  "1",
  "0",
  "exfoliated"
  )

Degree of root resorption at the beginning

df %>%
  ggplot(
  aes(x = degree_of_primary_tooth_resorption_hall_tooth_crown,
  y = degree_of_primary_tooth_resorption_contralateral,
  color = gender)
  ) +
  geom_jitter(alpha = 0.8) +
  labs(titl = "Baseline degree of root resorption",
  y = "Contralateral",
  x = "HT") +
  theme_pubclean() +
  labs(title = "Degree of root resorption at the beginning", color = "Gender") 

The same, now for 1st or 2nd molar

df %>%
  ggplot(
  aes(x = degree_of_primary_tooth_resorption_hall_tooth_crown,
  y = degree_of_primary_tooth_resorption_contralateral,
  color = hall_molar)
  ) +
  geom_jitter(alpha = 0.8,
  width = 0.15,
  height = 0.15) +
  labs(titl = "Baseline degree of root resorption",
  y = "Contralateral",
  x = "HT") +
  theme_pubclean() +
  labs(title = "Degree of root resorption at the beginning", color = "Molar") 

TIME-TO-EVENT ANALYSIS

KM analysis

Create new var = days until exfoliation


df$Hall_group <-
  difftime(
    df$date_first_time_noted_as_having_exfoliated_hall,
    df$treatment_date,
    units = c("days")
  ) # for Hall

df$Contralateral_group <-
  difftime(
    df$date_first_time_noted_as_having_exfoliated_contralateral,
    df$treatment_date,
    units = c("days")
  ) # for contralateral

Just to see the correlation between the exfoliation time between groups

CHECK HERE 20190604

DONE

separate by 1st and 2d molars ################## DONE #####################

check the correlation.

I see thereโ€™s a directly proportional correlation. This strongly suggests that as a dte with HT exfoliates, so does its contralateral.

lm(Hall_group ~ Contralateral_group, data = df)

Call:
lm(formula = Hall_group ~ Contralateral_group, data = df)

Coefficients:
        (Intercept)  Contralateral_group  
           191.7337               0.7965  

So, for every extra unit of exfoliation time for a Contralateral tooth, a HT also increase in 0.79 unit of time.

create a new column event full with 1

df$event <- 1

Now gather Hall and contralateral

df <- df %>%
  gather(key = "group",
         value = "exf_time",
         Hall_group:Contralateral_group)

DONE

change 1st and 2d molars ################## DONE #####################

Same for only for molar type

df %>% 
  ggplot(aes(x = exf_time, fill = gender)) + 
  geom_histogram(bins = 10) + 
  facet_grid(group~hall_molar) + 
  theme_pubclean() + 
  labs(title = "Exfoliation time histogram by molar, group and gender", 
       y = "Count", 
       x = "Exfoliation time (days", 
       gender = "Gender")

QUESTION: What could this bimodal distribution be?

Kaplan-Meier analysis

surv_object <- survival::Surv(time = df$exf_time, event = df$event)

Check the survival object

surv_object
  [1] 1636 2380 1077  569 2025  651 1930  823 1813 1877 1027  599 2646 1841  835 1889 1062
 [18]  364 1442 1225 1098  899  595 1157 1552 1188  475  917 1888  865 2618  409 1195 2112
 [35] 1075 2025  532 1312  863 1636 2380 1077  569 2025  651 1930  823 1813 1877 1027  599
 [52] 2646 1841  835 1889 1062  364 1442 1225 1098  899  595 1157 1552 1188  475  917 1888
 [69]  865 2618  409 1195 2112 1075 2025  532 1312  863 1819 2772  961  937 2116  712 2345
 [86]  736 1813 1938 1153 1047 2260 1841 1317 1344 1427 1306 1442  876 1251 1159  291  420
[103] 1769 1335   21 1291 1525 1163 2749  161 1344 1870 2207 2025  660 1251 1345 1819 2772
[120]  961  937 2116  712 2345  736 1813 1938 1153 1047 2260 1841 1317 1344 1427 1306 1442
[137]  876 1251 1159  291  420 1769 1335   21 1291 1525 1163 2749  161 1344 1870 2207 2025
[154]  660 1251 1345

Convert the difftime in number to extract any wrong value, i.e.

df$exf_time_number <- as.numeric(df$exf_time) # convert diff time in a new var
which(df$exf_time_number < 0) # check if is any wrong time
integer(0)
##############################################
########## DELETE THIS STEP ##################
# df <- df %>% 
#  filter(allocation_num != 78)
########## DELETE THIS STEP ##################
##############################################

Master table for survival analysis

fit1 <- survival::survfit(surv_object ~ group, data = df)
summary(fit1)
Call: survfit(formula = surv_object ~ group, data = df)

                group=Contralateral_group 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   21     78       2   0.9744  0.0179      0.93991        1.000
  161     76       2   0.9487  0.0250      0.90101        0.999
  291     74       2   0.9231  0.0302      0.86580        0.984
  420     72       2   0.8974  0.0344      0.83257        0.967
  660     70       2   0.8718  0.0379      0.80067        0.949
  712     68       2   0.8462  0.0409      0.76976        0.930
  736     66       2   0.8205  0.0435      0.73962        0.910
  876     64       2   0.7949  0.0457      0.71013        0.890
  937     62       2   0.7692  0.0477      0.68119        0.869
  961     60       2   0.7436  0.0494      0.65274        0.847
 1047     58       2   0.7179  0.0510      0.62472        0.825
 1153     56       2   0.6923  0.0523      0.59710        0.803
 1159     54       2   0.6667  0.0534      0.56985        0.780
 1163     52       2   0.6410  0.0543      0.54294        0.757
 1251     50       4   0.5897  0.0557      0.49009        0.710
 1291     46       2   0.5641  0.0561      0.46413        0.686
 1306     44       2   0.5385  0.0564      0.43845        0.661
 1317     42       2   0.5128  0.0566      0.41307        0.637
 1335     40       2   0.4872  0.0566      0.38798        0.612
 1344     38       4   0.4359  0.0561      0.33864        0.561
 1345     34       2   0.4103  0.0557      0.31441        0.535
 1427     32       2   0.3846  0.0551      0.29048        0.509
 1442     30       2   0.3590  0.0543      0.26685        0.483
 1525     28       2   0.3333  0.0534      0.24354        0.456
 1769     26       2   0.3077  0.0523      0.22057        0.429
 1813     24       2   0.2821  0.0510      0.19795        0.402
 1819     22       2   0.2564  0.0494      0.17571        0.374
 1841     20       2   0.2308  0.0477      0.15389        0.346
 1870     18       2   0.2051  0.0457      0.13253        0.318
 1938     16       2   0.1795  0.0435      0.11168        0.288
 2025     14       2   0.1538  0.0409      0.09142        0.259
 2116     12       2   0.1282  0.0379      0.07188        0.229
 2207     10       2   0.1026  0.0344      0.05320        0.198
 2260      8       2   0.0769  0.0302      0.03566        0.166
 2345      6       2   0.0513  0.0250      0.01974        0.133
 2749      4       2   0.0256  0.0179      0.00653        0.101
 2772      2       2   0.0000     NaN           NA           NA

                group=Hall_group 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
  364     78       2   0.9744  0.0179      0.93991        1.000
  409     76       2   0.9487  0.0250      0.90101        0.999
  475     74       2   0.9231  0.0302      0.86580        0.984
  532     72       2   0.8974  0.0344      0.83257        0.967
  569     70       2   0.8718  0.0379      0.80067        0.949
  595     68       2   0.8462  0.0409      0.76976        0.930
  599     66       2   0.8205  0.0435      0.73962        0.910
  651     64       2   0.7949  0.0457      0.71013        0.890
  823     62       2   0.7692  0.0477      0.68119        0.869
  835     60       2   0.7436  0.0494      0.65274        0.847
  863     58       2   0.7179  0.0510      0.62472        0.825
  865     56       2   0.6923  0.0523      0.59710        0.803
  899     54       2   0.6667  0.0534      0.56985        0.780
  917     52       2   0.6410  0.0543      0.54294        0.757
 1027     50       2   0.6154  0.0551      0.51636        0.733
 1062     48       2   0.5897  0.0557      0.49009        0.710
 1075     46       2   0.5641  0.0561      0.46413        0.686
 1077     44       2   0.5385  0.0564      0.43845        0.661
 1098     42       2   0.5128  0.0566      0.41307        0.637
 1157     40       2   0.4872  0.0566      0.38798        0.612
 1188     38       2   0.4615  0.0564      0.36317        0.587
 1195     36       2   0.4359  0.0561      0.33864        0.561
 1225     34       2   0.4103  0.0557      0.31441        0.535
 1312     32       2   0.3846  0.0551      0.29048        0.509
 1442     30       2   0.3590  0.0543      0.26685        0.483
 1552     28       2   0.3333  0.0534      0.24354        0.456
 1636     26       2   0.3077  0.0523      0.22057        0.429
 1813     24       2   0.2821  0.0510      0.19795        0.402
 1841     22       2   0.2564  0.0494      0.17571        0.374
 1877     20       2   0.2308  0.0477      0.15389        0.346
 1888     18       2   0.2051  0.0457      0.13253        0.318
 1889     16       2   0.1795  0.0435      0.11168        0.288
 1930     14       2   0.1538  0.0409      0.09142        0.259
 2025     12       4   0.1026  0.0344      0.05320        0.198
 2112      8       2   0.0769  0.0302      0.03566        0.166
 2380      6       2   0.0513  0.0250      0.01974        0.133
 2618      4       2   0.0256  0.0179      0.00653        0.101
 2646      2       2   0.0000     NaN           NA           NA

917### Technical explanation and essential concepts

Follow-up data are censored: one does not know the exact survival time, only that it is greater or less than a certain time. Being X the real time of exfoliation and T the time censored, what we observe is the minimum of X and T together with an indication of which is which. With this, we create an S(t) survival function that measures the probability of exfoliation at a given moment.

The analysis process begins with the creation of a survival object.

Once we have the survival object, we can calculate the survival function for census data on the right.

For all the teeth is

survival::survfit(surv_object ~ group, data = df)
Call: survfit(formula = surv_object ~ group, data = df)

                           n events median 0.95LCL 0.95UCL
group=Contralateral_group 78     78   1335    1251    1442
group=Hall_group          78     78   1157    1062    1442

So, the median of exfoliation time for contralateral is 1335 days (divided by 30 = 44.5 months approx), and for Hall is 1098 days (36.6 months). The lower 95%IC are 1163 days for CL and 917 for HT.

NEW: for Hall is 1157 days (38.5 months). The lower 95%IC are 1251 days for CL and 1062 for HT.

In order to see if there are differences in the groups, it is necessary to observe the complete survival curve and to verify if somewhere the confidence intervals do not overlap. Now letโ€™s graph

Plots grey

# jpeg("survival-grey-months.jpg") 
survminer::ggsurvplot(
  fit1,
  data = df,
  conf.int = TRUE,
  # Add confidence interval
  pval = TRUE,
  pval.coord = c(1400, 0.10), 
  # add p value
  xscale = "d_m",
  # convert days in years
  xlim = c(0, 3350),
  # present narrower X axis, but not affect
  # survival estimates.
  # conf.int.style = "step",  
  # customize style of confidence intervals
  # surv.median.line = "hv",
  # add the median survival pointer.
  legend.labs = c("CL group", "HT group"),
  fun = "event", 
  
   ########## risk table #########
  risk.table = TRUE,
  risk.table.y.text.col = TRUE,
  risk.table.y.text = TRUE,
  risk.table.height = 0.34, 
  risk.table.title = "Exfoliation events",
  palette = c("#333333", "#999999"),# custom color palettes
  # palette = "grey" # for bw publication if required
  
) +
  labs(title = "Exfoliation Time Probability Plot (Months)",
       x = "Time in months", 
       y = "Exfoliation Probability")

# Close the pdf file
# dev.off() 
# jpeg("survival-grey-years.jpg") 
survminer::ggsurvplot(
  fit1,
  data = df,
  conf.int = TRUE,
  # Add confidence interval
  pval = TRUE,
  pval.coord = c(1400, 0.10), 
  # add p value
  xscale = "d_y",
  # convert days in years
  xlim = c(0, 3350),
  # present narrower X axis, but not affect
  # survival estimates.
  # conf.int.style = "step",  
  # customize style of confidence intervals
  # surv.median.line = "hv",
  # add the median survival pointer.
  legend.labs = c("CL group", "HT group"),
  fun = "event", 
  
   ########## risk table #########
  risk.table = TRUE,
  risk.table.y.text.col = TRUE,
  risk.table.y.text = TRUE,
  risk.table.height = 0.34, 
  risk.table.title = "Exfoliation events",
  palette = c("#333333", "#999999"),# custom color palettes
  # palette = "grey" # for bw publication if required
  
) +
  labs(title = "Exfoliation Time Probability Plot (Years)",
       x = "Time in years", 
       y = "Exfoliation Probability")

# Close the pdf file
# dev.off() 

Plots color

# jpeg("survival-color-months.jpg") 
survminer::ggsurvplot(
  fit1,
  data = df,
  conf.int = TRUE,
  # Add confidence interval
  pval = TRUE,
  pval.coord = c(1400, 0.10), 
  # add p value
  xscale = "d_m",
  # convert days in years
  xlim = c(0, 3350),
  # present narrower X axis, but not affect
  # survival estimates.
  # conf.int.style = "step",  
  # customize style of confidence intervals
  # surv.median.line = "hv",
  # add the median survival pointer.
  legend.labs = c("CL group", "HT group"),
  fun = "event", 
  
   ########## risk table #########
  risk.table = TRUE,
  risk.table.y.text.col = TRUE,
  risk.table.y.text = TRUE,
  risk.table.height = 0.34, 
  risk.table.title = "Exfoliation events",
  palette = c("#CA3C42", "#28637B"),# custom color palettes
  # palette = "grey" # for bw publication if required
  
) +
  labs(title = "Exfoliation Time Probability Plot (Months)",
       x = "Time in months", 
       y = "Exfoliation Probability")

# Close the pdf file
# dev.off() 
# jpeg("survival-color-years.jpg") 
survminer::ggsurvplot(
  fit1,
  data = df,
  conf.int = TRUE,
  # Add confidence interval
  pval = TRUE,
  pval.coord = c(1400, 0.10), 
  # add p value
  xscale = "d_y",
  # convert days in years
  xlim = c(0, 3350),
  # present narrower X axis, but not affect
  # survival estimates.
  # conf.int.style = "step",  
  # customize style of confidence intervals
  # surv.median.line = "hv",
  # add the median survival pointer.
  legend.labs = c("CL group", "HT group"),
  fun = "event", 
  
   ########## risk table #########
  risk.table = TRUE,
  risk.table.y.text.col = TRUE,
  risk.table.y.text = TRUE,
  risk.table.height = 0.34, 
  risk.table.title = "Exfoliation events",
  palette = c("#CA3C42", "#28637B"),# custom color palettes
  # palette = "grey" # for bw publication if required
  
) +
  labs(title = "Exfoliation Time Probability Plot (Years)",
       x = "Time in years", 
       y = "Exfoliation Probability")

# Close the pdf file
# dev.off()

fit1 <- survival::survfit(surv_object ~ group, data = df)

ggsurvplot(
  survival::survfit(surv_object ~ df$group),   # survfit object with calculated statistics.
  data = df,                                   # data used to fit survival curves.
  risk.table = FALSE,                          # show risk table.
  pval = TRUE,                                 # show p-value of log-rank test.
  pval.coord = c(1500, 0.30),                  # position of the legend
  conf.int = TRUE,                             # show confidence intervals for
                                               # point estimates of survival curves.
  palette = c("#E7B800", "#2E9FDF"),
  xlim = c(0, 3350),                           # present narrower X axis, but not affect
                                               # survival estimates.
  xlab = "Time in days",                       # customize X axis label.
  break.time.by = 365,                         # break X axis in time intervals by 500.
  ggtheme = theme_classic(),                     # customize plot and risk table with a theme.
  # risk.table.y.text.col = T,# colour risk table text annotations.
  # risk.table.height = 0.35, # the height of the risk table
  # risk.table.y.text = FALSE,# show bars instead of names in text annotations
  # in legend of risk table.
  
  conf.int.style = "step",
  # customize style of confidence intervals
  surv.median.line = "hv",
  # add the median survival pointer.
  fun = "event",
  legend.labs =
    c("CL group", "HT group")    # change legend labels.
)

Subanalysis

autoplot(aareg(Surv(exf_time , event) ~ 
                 gender,
               data = df))

DONE

just four groups, with molars ################## DONE #####################

autoplot(aareg(Surv(exf_time , event) ~ 
                 hall_molar,
               data = df))

autoplot(aareg(Surv(exf_time , event) ~ 
                 contralateral_molar,
               data = df))

additional analyses July 8, 2019

The mean age, (sd and range) for

o all of the children when they had the crown fitted

o The same for boys only

o The same for girls only

df %>%
  mutate(
  birth_date = ymd(birth_date),
  treatment_date = ymd(treatment_date),
  age_when_HT = floor(decimal_date(treatment_date) - decimal_date(birth_date))
  ) %>% 
  summarise("Age at treatment" = mean(age_when_HT), sd = sd(age_when_HT), min = min(age_when_HT), max = max(age_when_HT), range = max - min)
df %>%
  mutate(
  birth_date = ymd(birth_date),
  treatment_date = ymd(treatment_date),
  age_when_HT = floor(decimal_date(treatment_date) - decimal_date(birth_date))
  ) %>%
  ggplot(aes(x = age_when_HT)) +
  geom_histogram(bins = 10) +
  theme_pubr() +
  labs(title = "Age at treatment",
  x = "Age at treatment", y = "Count")

df %>%
  mutate(
  birth_date = ymd(birth_date),
  treatment_date = ymd(treatment_date),
  age_when_HT = floor(decimal_date(treatment_date) - decimal_date(birth_date))
  ) %>% 
  group_by(gender) %>% 
  summarise("Age at treatment" = mean(age_when_HT), sd = sd(age_when_HT), min = min(age_when_HT), max = max(age_when_HT), range = max - min)
df %>%
  mutate(
  birth_date = ymd(birth_date),
  treatment_date = ymd(treatment_date),
  age_when_HT = floor(decimal_date(treatment_date) - decimal_date(birth_date))
  ) %$% 
  t.test(age_when_HT ~gender, data = .)

    Welch Two Sample t-test

data:  age_when_HT by gender
t = -2.6298, df = 149.04, p-value = 0.009441
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -1.0969290 -0.1557026
sample estimates:
mean in group Female   mean in group Male 
            6.900000             7.526316 
df %>%
  mutate(
  birth_date = ymd(birth_date),
  treatment_date = ymd(treatment_date),
  age_when_HT = floor(decimal_date(treatment_date) - decimal_date(birth_date))
  ) %>%
  ggplot(aes(x = gender, y = age_when_HT)) +
  ylim(0, 11) +
  geom_boxplot() +
  geom_jitter(alpha = 0.5) +
  theme_pubclean() + 
  labs(title = "Age at treatment by gender")

df %>%
  mutate(
  birth_date = ymd(birth_date),
  treatment_date = ymd(treatment_date),
  age_when_HT = floor(decimal_date(treatment_date) - decimal_date(birth_date))
  ) %>% 
  ggplot(aes(x = age_when_HT)) + 
  geom_histogram(bins= 10) + 
  theme_pubr() + 
  labs(title = "Age at treatment", 
       x = "Age at treatment", y = "Count") + 
  facet_grid(gender~.)

ยท The mean age (sd and range) of the children when

o the hall crown tooth exfoliated

o the contralateral tooth exfoliated

df %>%
  mutate(
  age_when_HT_exfoliated = floor(
  decimal_date(date_first_time_noted_as_having_exfoliated_hall) - decimal_date(birth_date)
  ) ,
  age_when_CT_exfoliated = floor(
  decimal_date(date_first_time_noted_as_having_exfoliated_contralateral) - decimal_date(birth_date)
  )
  ) %>%
  gather(key = "key", value = value, age_when_HT_exfoliated:age_when_CT_exfoliated) %>% 
  group_by(key) %>% 
  summarise(
  "Mean exfol age" = mean(value),
  sd = sd(value),
  min = min(value),
  max = max(value),
  range = max(value) - min(value)
  )
df %>%
  mutate(
  age_when_HT_exfoliated = floor(
  decimal_date(date_first_time_noted_as_having_exfoliated_hall) - decimal_date(birth_date)
  ) ,
  age_when_CT_exfoliated = floor(
  decimal_date(date_first_time_noted_as_having_exfoliated_contralateral) - decimal_date(birth_date)
  )
  ) %>%
  gather(key = "key", value = value, age_when_HT_exfoliated:age_when_CT_exfoliated) %>% 
  ggplot(aes(x = value)) + 
  geom_histogram(bins = 8) + 
  facet_grid(key~.) + 
  theme_pubr() + 
  labs(title = "Age at exfoliation time by group", y = "Count", x = "Age (years)")

CODEBOOK

# install.packages("dataMaid")
 #devtools::install_github("ekstroem/dataMaid")

INTERACTIVE EDA

# install.packages("ExPanDaR")
#library(ExPanDaR)
#df$cs_id <- row.names(df)
#df$ts_id <- 1
#ExPanDaR::ExPanD(
#  df,
#  cs_id = "cs_id",
#  ts_id = "ts_id",
#  components = c(trend_graph = FALSE, quantile_trend_graph = FALSE)
#)
LS0tCnRpdGxlOiBBc3NvY2lhdGlvbiBiZXR3ZWVuIHRoZSBIYWxsIFRlY2huaXF1ZSBhbmQgZmFjdG9ycyBhc3NvY2lhdGVkIHdpdGggdGltZSBvZgogIGV4Zm9saWF0aW9uIG9mIHByaW1hcnkgdGVldGgKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBmaWdfY2FwdGlvbjogeWVzCiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICB3b3JkX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICBwZGZfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogIGh0bWxfZG9jdW1lbnQ6CiAgICBkZl9wcmludDogcGFnZWQKICAgIHRvYzogeWVzCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkICVCLCAlWScpYCIKLS0tCgojIHVwZGF0ZXMKIyMgMjAxOS0wNy0wOSAKdGhyZWUgZGF0ZXMgY2hhbmdlZCwgIzU1LCAjMTM2ICYgIzE4MwoKCkdlbmVyYWwgcmVhZGluZzogCkJld2ljaywgVi4sIENoZWVrLCBMLiwgQmFsbCwgSi4sIDIwMDQuIFN0YXRpc3RpY3MgcmV2aWV3IDEyOiBzdXJ2aXZhbCBhbmFseXNpcy4gQ3JpdC4gQ2FyZSA4LCAzODnigJMzOTQuCmh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3YvcG1jL2FydGljbGVzL1BNQzEwNjUwMzQvCgojIFN0YXRpc3RpY2FsIGFuYWx5c2lzCgoKU2VlIGh0dHBzOi8vZG9jcy5nb29nbGUuY29tL2RvY3VtZW50L2QvMVhpcURtVGdoenJSSS16Nnl0SmRzemxPZF9nVzZTM0FLVDdfWktTU1A1ck0vZWRpdCAKCgoKCgojIFBBQ0tBR0VTIApgYGB7ciBwYWNrYWdlcywgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRSwgZXJyb3I9RkFMU0UsIHJlc3VsdHM9J2hpZGUnLCBpbmNsdWRlPUZBTFNFfQppZiAoIXJlcXVpcmUoInRpZHl2ZXJzZSIpKSAgIGluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpICMgaW5zdGFsbCBwYWNrYWdlcyBpbiBjYXNlIHRoZXkgYXJlIG5vdCBpbnN0YWxsZWQKaWYgKCFyZXF1aXJlKCJwb3dlclN1cnZFcGkiKSkgICBpbnN0YWxsLnBhY2thZ2VzKCJwb3dlclN1cnZFcGkiKSAjIGZvciBzYW1wbGUgc2l6ZSBjYWxjdWxhdGlvbiBvZiBzdXJ2aXZhbAoKaWYgKCFyZXF1aXJlKCJnc0Rlc2lnbiIpKSAgaW5zdGFsbC5wYWNrYWdlcygiZ3NEZXNpZ24iKSAjIGZvciBzYW1wbGUgc2l6ZSBjYWxjdWxhdGlvbiBvZiBzdXJ2aXZhbCBhbmFseXNpcwoKbGlicmFyeShnc0Rlc2lnbikKCmlmICghcmVxdWlyZSgic3Vydml2YWwiKSkgICBpbnN0YWxsLnBhY2thZ2VzKCJzdXJ2aXZhbCIpICMgZm9yIHN1cnZpdmFsIGFuYWx5c2lzCmlmICghcmVxdWlyZSgic3Vydm1pbmVyIikpICAgaW5zdGFsbC5wYWNrYWdlcygic3Vydm1pbmVyIikgIyBmb3Igc3Vydml2YWwgYW5hbHlzaXMKCmlmICghcmVxdWlyZSgibHVicmlkYXRlIikpICBpbnN0YWxsLnBhY2thZ2VzKCJsdWJyaWRhdGUiKSAjIGluc3RhbGwgcGFja2FnZXMgaW4gY2FzZSB0aGV5IGFyZSBub3QgaW5zdGFsbGVkCmlmICghcmVxdWlyZSgidGFibGUxIikpICBpbnN0YWxsLnBhY2thZ2VzKCJ0YWJsZTEiKSAjIGluc3RhbGwgcGFja2FnZXMgaW4gY2FzZSB0aGV5IGFyZSBub3QgaW5zdGFsbGVkIAoKI2luc3RhbGwucGFja2FnZXMoImdnZm9ydGlmeSIpCmxpYnJhcnkoZ2dmb3J0aWZ5KQpgYGAKCiAKIyBTQU1QTEUgU0laRQoKIyMgUHJlLXN0dWR5CiBjb25zaWRlciBhIHRyaWFsIHdpdGggCiAyIHllYXIgbWF4aW11bSBmb2xsb3ctdXAKIDYgbW9udGggdW5pZm9ybSBlbnJvbGxtZW50CiBDb250cm9sL0hUIGhhemFyZHMgPSAwLjEvMC4yIHBlciAxIHBlcnNvbi15ZWFyCiBkcm9wIG91dCBoYXphcmQgMC4xIHBlciAxIHBlcnNvbi15ZWFyCiBhbHBoYSA9IDAuMDI1ICgxLXNpZGVkKQogcG93ZXIgPSAwLjgwIChkZWZhdWx0IGJldGE9LjEpCgpgYGB7ciBzYW1wbGUgc2l6ZSBjYWxjfQpzcyA8LSBuU3Vydml2YWwoCiAgbGFtYmRhMSA9IC4xICwgICMjIGhhemFyZCByYXRlIGNvbnRyb2wKICBsYW1iZGEyID0gLjI1LCAgIyMgaGF6YXJkIHJhdGUgSFQKICBldGEgPSAuMSwgICMjIGVxdWFsIGRyb3Agb3V0IHJhdGUgZm9yIGJvdGggZ3JvdXBzCiAgVHMgPSA5LCAgIyMgbWF4aW11bSBzdHVkeSBkdXJhdGlvbgogIFRyID0gMywgICMjIGFjY3J1YWwgKHJlY3J1aXRtZW50KSBkdXJhdGlvbgogIHNpZGVkID0gMSwKICBhbHBoYSA9IC4wMjUsCiAgcmF0aW8gPSAxLAogIGJldGEgPSAuMgopCnNzICAjIGRlZmF1bHQgdmFsdWVzCmBgYAoKCgojIyBEbyB3ZSBoYXZlIGVub3VnaHQgc3RhdGlzdGljYWwgcG93ZXIgd2l0aCAzOT8KClNlZSAKMS4gUG9zdCBob2MgcG93ZXIgYW5hbHlzaXM6IGFuIGlkZWEgd2hvc2UgdGltZSBoYXMgcGFzc2VkPyBNLiBMZXZpbmUsIE0uIEguIEVuc29tLiBQaGFybWFjb3RoZXJhcHkgMjAwMTogMjEoNCk7IDQwNS05LgoyLiBDb25maWRlbmNlIGxpbWl0IGFuYWx5c2VzIHNob3VsZCByZXBsYWNlIHBvd2VyIGNhbGN1bGF0aW9ucyBpbiB0aGUgaW50ZXJwcmV0YXRpb24gb2YgZXBpZGVtaW9sb2dpYyBzdHVkaWVzLiBBLiBILiBTbWl0aCwgTS4gTi4gQmF0ZXMuIEVwaWRlbWlvbG9neSAxOTkyOiAzKDUpOyA0NDktNTIuIOKAnQoKCmBgYHtyIHBvd2VyIGNhbGMgd2l0aCBuIDM5fQojIEV4YW1wbGUgMTQuNDIgaW4gUm9zbmVyIEIuIEZ1bmRhbWVudGFscyBvZiBCaW9zdGF0aXN0aWNzLgojICg2LXRoIGVkaXRpb24pLiAoMjAwNikgcGFnZSA4MDkKcG93ZXJDVC5kZWZhdWx0KG5FID0gMzksICMgbnVtYmVyIG9mIHBhcnRpY2lwYW50cyBpbiB0aGUgZXhwZXJpbWVudGFsIGdyb3VwLgogICAgICAgICAgICAgICAgbkMgPSAzOSwgIyBudW1iZXIgb2YgcGFydGljaXBhbnRzIGluIHRoZSBjb250cm9sIGdyb3VwLgogICAgICAgICAgICAgICAgcEUgPSAwLjYsICMgcHJvYmFiaWxpdHkgb2YgZmFpbHVyZSBpbiBncm91cCBFIChleHBlcmltZW50YWwgZ3JvdXApIG92ZXIgdGhlIG1heGltdW0gdGltZSBwZXJpb2Qgb2YgdGhlIHN0dWR5ICh0IHllYXJzKS4KICAgICAgICAgICAgICAgIHBDID0gMC41LCAjIHByb2JhYmlsaXR5IG9mIGZhaWx1cmUgaW4gZ3JvdXAgQyAoY29udHJvbCBncm91cCkgb3ZlciB0aGUgbWF4aW11bSB0aW1lIHBlcmlvZCBvZiB0aGUgc3R1ZHkgKHQgeWVhcnMpLgogICAgICAgICAgICAgICAgUlIgPSAwLjEsICMgcG9zdHVsYXRlZCBoYXphcmQgcmF0aW8uCiAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMDUpICN5cGUgSSBlcnJvciByYXRlCmBgYAoKWWVzLCBtb3JlIHRoYW4gZW5vdWdoLgoKIyBMT0FEIERBVEEKCgpgYGB7ciBkYXRhc2V0LCBpbmNsdWRlPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30KZGYgPC0gcmVhZF9jc3YoImh0dHBzOi8vZG9jcy5nb29nbGUuY29tL3NwcmVhZHNoZWV0cy9kL2UvMlBBQ1gtMXZTZThlbnYzNU9FTERZeEl4M2dwNkl6QUdWeUcxbXFQNEtfTGVBT05PSnE5X25rWDdUOUNrUEctZ3lUSUoyX2xsNzJEZVFmbkEzN0M3OWMvcHViP2dpZD0xMjU4NjY4ODQ3JnNpbmdsZT10cnVlJm91dHB1dD1jc3YiKQp3cml0ZV9jc3YoZGYsICJkZi5jc3YiKSAjIHN0b3JlIGEgbG9jYWwgY29weSAKIyBkZiA8LSByZWFkX2NzdigiZGYuY3N2IikKYGBgCgpgYGB7ciByZW1vdmUgY29scywgcmVzdWx0cz0naGlkZSd9CmRmIDwtIGRmICU+JSAKICBzZWxlY3QoLWMoQ29tbWVudHMsIGBNYXJjYSB0ZW1wb3JhbGApKSAjIHJlbW92ZSB1bndhbnRlZCBjb2x1bW5zCgpgYGAKCkNoZWNrIHZhcmlhYmxlcwpgYGB7ciBjaGVjayB2YXJzLCBlY2hvPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30KaGVhZChkZikKYGBgCgpWZXJpZnkgdGhlIGNvbXBsZXRlbmVzcyBvZiB0aGUgZGF0YQpgYGB7ciBOQXMgdmlzdWFsaXphdGlvbn0KdmlzZGF0Ojp2aXNfZGF0KGRmKQpgYGAKCiMgREFUQSBDTEVBTklORyBBTkQgV1JBTkdMSU5HCkNvbnZlcnQgZGF0ZXMKYGBge3IgQ29udmVydCBkYXRlcyB0byBkYXRlIGZvcm1hdH0KZGYkYFRyZWF0bWVudCBkYXRlYCA8LSAgbHVicmlkYXRlOjpkbXkoZGYkYFRyZWF0bWVudCBkYXRlYCkKZGYkYERhdGUgb2YgdGhlIGxhc3QgcmFkaW9ncmFwaCBCRUZPUkUgdGhlIHRyZWF0bWVudGAgPC0gbHVicmlkYXRlOjpkbXkoZGYkYERhdGUgb2YgdGhlIGxhc3QgcmFkaW9ncmFwaCBCRUZPUkUgdGhlIHRyZWF0bWVudGApCmRmJGBEYXRlIEZpcnN0IFRpbWUgbm90ZWQgYXMgaGF2aW5nIGV4Zm9saWF0ZWQ6IChIYWxsKWAgPC0gbHVicmlkYXRlOjpkbXkoZGYkYERhdGUgRmlyc3QgVGltZSBub3RlZCBhcyBoYXZpbmcgZXhmb2xpYXRlZDogKEhhbGwpYCkKZGYkYERhdGUgRmlyc3QgVGltZSBub3RlZCBhcyBoYXZpbmcgZXhmb2xpYXRlZDogKENvbnRyYWxhdGVyYWwpYCA8LSBsdWJyaWRhdGU6OmRteShkZiRgRGF0ZSBGaXJzdCBUaW1lIG5vdGVkIGFzIGhhdmluZyBleGZvbGlhdGVkOiAoQ29udHJhbGF0ZXJhbClgKQpkZiRgRGF0ZSBvZiB0aGUgcmFkaW9ncmFwaCAyYCA8LSBsdWJyaWRhdGU6OmRteShkZiRgRGF0ZSBvZiB0aGUgcmFkaW9ncmFwaCAyYCkKZGYkYEJpcnRoIERhdGVgIDwtIGx1YnJpZGF0ZTo6ZG15KGRmJGBCaXJ0aCBEYXRlYCkKCmBgYAoKCkFkZCBpZCBzZXF1ZW50aWFsIG51bWJlcgpgYGB7ciBhZGQgaWQgY29sdW1ufQpkZiA8LSBkZiAlPiUgbXV0YXRlKGlkID0gcm93X251bWJlcigpKQpgYGAKCkNoYW5nZSB0b290aCB2YXJpYWJsZQpgYGB7ciBjaGFuZ2UgdG9vdGggdG8gY2hyfQpkZiRgSGFsbCBDcm93biBUb290aGAgPC0gYXMuY2hhcmFjdGVyKGRmJGBIYWxsIENyb3duIFRvb3RoYCkKZGYkYENvbnRyYWxhdGVyYWwgVG9vdGhgIDwtIGFzLmNoYXJhY3RlcihkZiRgQ29udHJhbGF0ZXJhbCBUb290aGApCmBgYAoKIyMgQ3JlYXRlIGFnZSBhdCB0aGUgc3RhcnQgb2YgdGhlIGludGVydmVudGlvbiAKClRocmVlIGRhdGVzIHdlcmUgY29ycmVjdGVkICh0cmVhdG1lbnQgYW5kIGJpcnRoIGNoYW5nZWQ6IDU1LCAxODMgYW5kIDEzNi4KCmBgYHtyIGNyZWF0ZSBhZ2UgdmFyfQpkZiA8LSBkZiAlPiUKICBtdXRhdGUoYWdlID0gaW50ZXJ2YWwoeW1kKGBCaXJ0aCBEYXRlYCksIHltZChgVHJlYXRtZW50IGRhdGVgKSkgLyB5ZWFycygxKSwKICAgICAgICAgYWdlID0gaWZfZWxzZShhZ2UgPCAwLCBhZ2UgKyAxMDAsIGFnZSkpCgpgYGAKCiMjIENoYW5nZSBuYW1lcywgZXRjCmBgYHtyIGphbml0b3IyfQpkZiA8LSBkZiAlPiUKICBqYW5pdG9yOjpjbGVhbl9uYW1lcygpICU+JQogIGphbml0b3I6OnJlbW92ZV9lbXB0eShjKCJyb3dzIiwgImNvbHMiKSkKYGBgCgoKQ2hlY2sgYWdlCmBgYHtyIGNoZWNrIGFnZX0KZGYgJT4lCiAgZ2dwbG90KGFlcyh4ID0gYWdlKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAxMCkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6Om51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAxKSkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6Om51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAxKSkgKwogIGZhY2V0X3dyYXAofiBnZW5kZXIpICsKICB0aGVtZV9wdWJjbGVhbigpICsKICBsYWJzKAogIHRpdGxlID0gIkFnZSBieSBnZW5kZXIiLAogIHkgPSAiQ291bnQiLAogIHggPSAiQWdlICh5ZWFycyIKICApCmBgYAojIyBDcmVhdGUgbmV3IHZhciBncm91cGluZyBmaXJzdHMgbW9sYXJzIGFuZCBzZWNvbmQgbW9sYXJzCgpgYGB7cn0KZGYgPC0gZGYgJT4lIAogIG11dGF0ZShoYWxsX21vbGFyID0gY2FzZV93aGVuKAogICAgaGFsbF9jcm93bl90b290aCAlaW4lIGMoNTUsIDY1LCA3NSwgODUpIH4gIjFzdCIsIAogICAgVFJVRSB+ICIybmQiCiAgKSkgJT4lIAogIG11dGF0ZShjb250cmFsYXRlcmFsX21vbGFyID0gY2FzZV93aGVuKAogICAgY29udHJhbGF0ZXJhbF90b290aCAlaW4lIGMoNTUsIDY1LCA3NSwgODUpIH4gIjFzdCIsIAogICAgVFJVRSB+ICIybmQiCiAgKSkKYGBgCgoKIyMgQ3JlYXRlIG5ldyB2YXIgZm9yIG1heGlsbGFyIGFuZCBtYW5kaWJ1bGFyIG1vbGFycwoKYGBge3J9CmRmIDwtIGRmICU+JSAKICBtdXRhdGUoaGFsbF9qYXcgPSBjYXNlX3doZW4oCiAgICBoYWxsX2Nyb3duX3Rvb3RoICVpbiUgYyg1NSwgNjUpIH4gIk1heGlsbGFyeSBIIE1vbGFyIiwgCiAgICBUUlVFIH4gIk1hbmRpYnVsYXIgSCBtb2xhciIKICApKSAlPiUgCiAgbXV0YXRlKChjb250cmFsYXRlcmFsX2phdyA9IGNhc2Vfd2hlbigKICAgIGNvbnRyYWxhdGVyYWxfdG9vdGggJWluJSBjKDU1LCA2NSkgfiAiTWF4aWxsYXJ5IEMgTW9sYXIiLCAKICAgIFRSVUUgfiAiTWFuZGlidWxhciBDIG1vbGFyIgogICkpKQpgYGAKCgpEYXRhc2V0IHJlYWR5IGZvciBhbmFseXNpcwoKCiMgRURBCiMjIEFnZQpgYGB7ciBoaXN0IGFnZX0KZGYgJT4lCiAgZ2dwbG90KGFlcyggeCA9IGFnZSkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMTApICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMSkpICsKICBmYWNldF93cmFwKCB+IGdlbmRlcikgKwogIGxhYnModGl0bGUgPSAiQWdlIGF0IHRoZSB0aW1lIG9mIHRoZSB0cmVhdG1lbnQgYnkgZ2VuZGVyIiwKICAgICAgIHkgPSAiQ291bnQiLAogICAgICAgeCA9ICJBZ2UiKSArCiAgdGhlbWVfcHViY2xlYW4oKQpgYGAKIyMjIEFueSBkaWZmZXJlbmNlIG9mIHNleCBieSBnZW5kZXI/CgpUaGVyZSBpcyBOTyBTSUdOSUZJQ0FOVCBkaWZmZXJlbmNlIGluIHRoZSBhZ2UgbWVhbiBieSBnZW5kZXIKVGhlIGFnZSBtZWFucyBvZiBnaXJscyBhbmQgYm95cyBhcmUgYHIgKHQudGVzdChhZ2V+Z2VuZGVyLCBkYXRhID0gZGYpJGVzdGltYXRlKSBgIHJlc3BlY3RpdmVseSwgYW5kIHRoaXMgZGlmZmVyZW5jZSBpcyBOT04gc2lnbmlmaWNhbnQgKHAtdmFsdWUgPSBgciAodC50ZXN0KGFnZX5nZW5kZXIsIGRhdGEgPSBkZikkcC52YWx1ZSlgICkKCk1vcmUgaW5mbwpgYGB7ciB0LXRlc3QgYWdlIGJ5IGdlbmRlcn0KdC50ZXN0KGFnZSB+IGdlbmRlciwgZGF0YSA9IGRmKQpgYGAKCgojIyBHZW5kZXIgcHJvcG9ydGlvbnMKYGBge3IgdGFibGUgZ2VuZGVyfQp0YWJsZShkZiRnZW5kZXIpCmBgYApUaGUgcHJvcG9ydGlvbiBvZiB3b21lbiBpcyBhbG1vc3QgaGFsZiwgc28gb2J2aW91c2x5IHRoZSBwcm9wb3J0aW9uIHRlc3Qgd2lsbCBkZWxpdmVyIGEgbm9uLXNpZ25pZmljYW50IHZhbHVlIGZvciB0aGUgZGlmZmVyZW5jZS4gCmBgYHtyIHByb3AudGVzdCBnZW5kZXJ9CnByb3AudGVzdCh4ID0gMjAsCiAgICAgICAgICBuID0gMzksCiAgICAgICAgICBwID0gMC41LAogICAgICAgICAgY29ycmVjdCA9IEZBTFNFKQpgYGAKCmBgYHtyIHBsb3QgZ2VuZGVyfQpkZiAlPiUKICBnZ3Bsb3QoYWVzKHggPSBnZW5kZXIpKSArCiAgZ2VvbV9iYXIoKSArCiAgbGFicyh0aXRsZSA9ICJHZW5kZXIgZGlzdHJpYnV0aW9uIiwKICAgICAgIHkgPSAiQ291bnQiLAogICAgICAgeCA9ICJHZW5kZXIiKSArCiAgdGhlbWVfcHViY2xlYW4oKQpgYGAKCgojIyBUb290aApgYGB7ciBwbG90IHRvb3RofQpkZiAlPiUKICBnZ3Bsb3QoYWVzKHggPSBoYWxsX2Nyb3duX3Rvb3RoLCBmaWxsID0gZ2VuZGVyKSkgKwogIGdlb21fYmFyKCkgKwogIGZhY2V0X2dyaWQoZ2VuZGVyfi4gKSArCiAgbGFicyh0aXRsZSA9ICJUb290aCBkaXN0cmlidXRpb24gYnkgZ2VuZGVyIiwKICB5ID0gIkNvdW50IiwKICB4ID0gIlRvb3RoIikgKwogIHRoZW1lX3B1YmNsZWFuKCkgKwogIGd1aWRlcyhmaWxsID0gRkFMU0UpICMgcmVtb3ZlIHRoZSBsZWdlbmQKYGBgCgpgYGB7ciBncmFwaCBieSBtb2xhciBhbmQgdXBwZXIvbG93ZXJ9CmRmICU+JSAKICBtdXRhdGUobW9sYXIgPSBjYXNlX3doZW4oCiAgICBoYWxsX2Nyb3duX3Rvb3RoICVpbiUgYyg1NSwgNjUpIH4gIlVGUE0iLCAKICAgIGhhbGxfY3Jvd25fdG9vdGggJWluJSBjKDU0LCA2NCkgfiAiVVNQTSIsCiAgICBoYWxsX2Nyb3duX3Rvb3RoICVpbiUgYyg4NSwgNzUpIH4gIkxGUE0iLAogICAgVFJVRSB+ICJMU1BNIiwgCiAgKSkgJT4lIAogICAgc2VsZWN0KGdlbmRlciwgbW9sYXIsIGhhbGxfY3Jvd25fdG9vdGgpICU+JSAKICBzZWxlY3QoZ2VuZGVyLCBtb2xhciwgaGFsbF9jcm93bl90b290aCkgJT4lIAogIGdncGxvdChhZXMoeCA9IG1vbGFyLCBmaWxsID0gZ2VuZGVyKSkgKwogIGdlb21fYmFyKCkgKyAKICBsYWJzKHRpdGxlID0gIk1vbGFyIGRpc3RyaWJ1dGlvbiBieSBnZW5kZXIiLCAKICAgICAgIHkgPSAiQ291bnQiLCB4ID0gIk1vbGFyIHR5cGUiLCBmaWxsID0gIkdlbmRlciIpICsgCiAgdGhlbWVfcHViY2xlYW4oKSArIAogIGZhY2V0X2dyaWQoZ2VuZGVyfi4pICsgCiAgZ3VpZGVzKGZpbGwgPSBGQUxTRSkgIyByZW1vdmUgdGhlIGxlZ2VuZApgYGAKCgp0YWJsZSBieSBnZW5kZXIKYGBge3IgdGVldGggdGFibGUgYnkgZ2VuZGVyfQpkZiAlPiUgCiAgamFuaXRvcjo6dGFieWwoaGFsbF9tb2xhciwgZ2VuZGVyICkgJT4lIAogIGphbml0b3I6OmFkb3JuX3RvdGFscygiY29sIikgCmBgYApNb2xhciBkaXN0cmlidXRpb24gYnkgZ2VuZGVyCmBgYHtyIHBsb3QgTW9sYXIgZGlzdHJpYnV0aW9uIGJ5IGdlbmRlcn0KZGYgJT4lCiAgZ2dwbG90KGFlcyh4ID0gaGFsbF9tb2xhcikpICsKICBnZW9tX2JhcigpICsKICBmYWNldF93cmFwKCB+IGdlbmRlcikgKwogIGxhYnModGl0bGUgPSAiTW9sYXIgZGlzdHJpYnV0aW9uIGJ5IGdlbmRlciIsCiAgICAgICB5ID0gIkNvdW50IiwKICAgICAgIHggPSAiTW9sYXIiKSArCiAgdGhlbWVfcHViY2xlYW4oKQpgYGAKCgojIyBEaXN0cmlidXRpb24gb2YgdGVldGgtcGFpcnMgcGVyIGdlbmRlcgoKCgpwbG90IHRlZXRoIHBhaXJzCmBgYHtyIHBsb3QgdGVldGggcGFpcnN9CmRmICU+JQogIGdncGxvdChhZXMoeCA9IGhhbGxfbW9sYXIsCiAgICAgICAgICAgICB5ID0gY29udHJhbGF0ZXJhbF9tb2xhciwKICAgICAgICAgICAgIGNvbG9yID0gZ2VuZGVyKSkgKwogIGdlb21faml0dGVyKGFscGhhID0gMC41LCB3aWR0aCA9IC4xLCBoZWlnaHQgPSAuMSkgKwogIHRoZW1lX3B1YmNsZWFuKCkgKwogIGxhYnModGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIG1vbGFyLXBhaXJzIGJ5IGdlbmRlciIsIAogICAgICAgeSA9ICJDb250cmFsYXRlcmFsIG1vbGFyIiwgCiAgICAgICB4ID0gIkhUIG1vbGFyIiwgCiAgICAgICBjb2xvciA9ICJHZW5kZXIiKQpgYGAKCmBgYHtyfQpjaGlzcS50ZXN0KHRhYmxlKGRmJGdlbmRlciwgZGYkaGFsbF9jcm93bl90b290aCkpCmBgYAoKCgojIyBUYWJsZSAxCgoKIyMjIyMjIyMjIyMjIyMjIyMjIERPTkUgIyMjIyMjIyMjIyMjIyMjIyMjIyMjCkNPTUJJTkUgNTUvNjUsIGV0YyAgCiMjIyMjIyMjIyMjIyMjIyMjIyBET05FICMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKYGBge3IgdGFibGUxfQp0YWJsZTE6OnRhYmxlMSggfiBhZ2UgKwogICAgICAgICAgICAgICAgICBoYWxsX21vbGFyICsKICAgICAgICAgICAgICAgICAgY29udHJhbGF0ZXJhbF9tb2xhciArCiAgICAgICAgICAgICAgICAgIHR5cGVfb2ZfcmFkaW9ncmFwaCArCiAgICAgICAgICAgICAgICAgIGRlbWlyamlhbl9pbmRleF9wZXJtX3Rvb3RoX2hhbGxfdG9vdGhfY3Jvd24gKyAKICAgICAgICAgICAgICAgICAgZGVtaXJqaWFuX2luZGV4X3Blcm1fdG9vdGhfY29udHJhbGF0ZXJhbAogICAgICAgICAgICAgICAgfCBnZW5kZXIgLAogICAgICAgICAgICAgICAgZGF0YSA9IGRmKQpgYGAKCgoKIyMgRGVtaXJqaWFuIHN0YXR1cwoKCiMjIyMjIyMjIyMjIyMjIyMjIyBUTyBETyAjIyMjIyMjIyMjIyMjIyMjIyMjIyMKQ09NQklORSA1NS82NSwgZXRjICBBTkQgZ3JhcGggYnkgdGVldGgKIyMjIyMjIyMjIyMjIyMjIyMjIFRPIERPICMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKYGBge3IgRGVtaXJqaWFuIHN0YXR1c30KZGYgJT4lCiAgZmlsdGVyKAogIGRlbWlyamlhbl9pbmRleF9wZXJtX3Rvb3RoX2hhbGxfdG9vdGhfY3Jvd24gIT0gIk5vdCBwb3NzaWJsZSB0byBkZXRlcm1pbmUgKGJpdGV3aW5nKSIgfAogIGRlbWlyamlhbl9pbmRleF9wZXJtX3Rvb3RoX2NvbnRyYWxhdGVyYWwgIT0gIk5vdCBwb3NzaWJsZSB0byBkZXRlcm1pbmUgKGJpdGV3aW5nKSIKICApICU+JQogIGdncGxvdCgKICBhZXMoeCA9IGRlbWlyamlhbl9pbmRleF9wZXJtX3Rvb3RoX2hhbGxfdG9vdGhfY3Jvd24sCiAgeSA9IGRlbWlyamlhbl9pbmRleF9wZXJtX3Rvb3RoX2NvbnRyYWxhdGVyYWwsCiAgY29sb3IgPSBoYWxsX21vbGFyKQogICkgKwogICMgZ2VvbV9wb2ludCgpICsKICBnZW9tX2ppdHRlcihhbHBoYSA9IDAuNSwgd2lkdGggPSAuMTUsIGhlaWdodCA9IC4xNSkgKwogIGxhYnModGl0bGUgPSAiRGVtaXJqaWFuIHN0YXR1cyBvZiBIVCBhbmQgY29udHJhbGF0ZXJhbCBiYXNlbGluZSIsCiAgeSA9ICJIVCIsCiAgeCA9ICJDVCIpICsKICB0aGVtZV9wdWJjbGVhbigpCiAgCmBgYAoKCgojIyMjIyMjIyMjIyMjIyMjIyMgVE8gRE8gIyMjIyMjIyMjIyMjIyMjIyMjIyMjCkNvbXBhcmUgMXN0IHByaW0gbW9sYXIgd2l0aCAyZCBwcmltIG1vbGFyICB3aXRoIERlbWlyamlhbiBhbmQgZXhvZl90aW1lCiMjIyMjIyMjIyMjIyMjIyMjIyBUTyBETyAjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCgpDaGVjawpgYGB7ciBjaGVjayB0b290aCBwYWlycyBkZW1pcmppYW4gc3RhdHVzIGJ5IGdlbmRlcn0KCmRmICU+JQogIGZpbHRlcigKICBkZW1pcmppYW5faW5kZXhfcGVybV90b290aF9oYWxsX3Rvb3RoX2Nyb3duICE9ICJOb3QgcG9zc2libGUgdG8gZGV0ZXJtaW5lIChiaXRld2luZykiIHwKICBkZW1pcmppYW5faW5kZXhfcGVybV90b290aF9jb250cmFsYXRlcmFsICE9ICJOb3QgcG9zc2libGUgdG8gZGV0ZXJtaW5lIChiaXRld2luZykiCiAgKSAlJCUgIyB0aGlzIGFsc28gZG8gdGhlIHRyaWNrIQogIGZpc2hlci50ZXN0KAogIHRhYmxlKAogIGRlbWlyamlhbl9pbmRleF9wZXJtX3Rvb3RoX2hhbGxfdG9vdGhfY3Jvd24sCiAgLiRkZW1pcmppYW5faW5kZXhfcGVybV90b290aF9jb250cmFsYXRlcmFsCiAgKQogICkKCmBgYApPaywgc28gbWF5YmUgYW55IGRpZmZlcmVuY2UgaW4gdGhlIHN1cnZpdmFsIGJ5IGdlbmRlciBjb3VsZCBiZSBleHBsYWluZWQgYnkgdGhlIGRlbWlyamlhbiBzdGF0dXMgYXQgdGhlIGJlZ2dpbmluZyBvZiB0aGUgZm9sbG93LXVwCgoKIyMgU3RhdHVzIG9mIHRoZSBjb250cmFsYXRlcmFsIHRvb3RoIGJ5IGdlbmRlcgpgYGB7ciBTdGF0dXMgb2YgdGhlIGNvbnRyYWxhdGVyYWwgdG9vdGh9CmRmICU+JQogIGdncGxvdChhZXMoeCA9IHN0YXR1c19vZl90aGVfY29udHJhbGF0ZXJhbF90b290aCkpICsKICBnZW9tX2JhcigpICsKICBsYWJzKHRpdGxlID0gIlN0YXR1cyBvZiB0aGUgY29udHJhbGF0ZXJhbCB0b290aCIsCiAgeSA9ICJDb3VudCIsCiAgeCA9ICJTdGF0dXMiKSArCiAgdGhlbWVfcHViY2xlYW4oKSAKYGBgCgoKCgoKIyMjIyMjIyMjIyMjIyMjIyMjIERPTkUgIyMjIyMjIyMjIyMjIyMjIyMjIyMjCmNoYW5nZSBzY2FsZSBmcm9tIDQsIDMsIDIsIDEsIDAsIGV4ZgojIyMjIyMjIyMjIyMjIyMjIyBET05FICMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKYGBge3J9CmRmJGRlZ3JlZV9vZl9wcmltYXJ5X3Rvb3RoX3Jlc29ycHRpb25fY29udHJhbGF0ZXJhbCA8LQogIGZjdF9yZWxldmVsKAogIGRmJGRlZ3JlZV9vZl9wcmltYXJ5X3Rvb3RoX3Jlc29ycHRpb25fY29udHJhbGF0ZXJhbCwKICAiNCIsCiAgIjMiLAogICIyIiwKICAiMSIsCiAgIjAiLAogICJleGZvbGlhdGVkIgogICkKCmRmJGRlZ3JlZV9vZl9wcmltYXJ5X3Rvb3RoX3Jlc29ycHRpb25faGFsbF90b290aF9jcm93biA8LQogIGZjdF9yZWxldmVsKAogIGRmJGRlZ3JlZV9vZl9wcmltYXJ5X3Rvb3RoX3Jlc29ycHRpb25faGFsbF90b290aF9jcm93biwKICAiNCIsCiAgIjMiLAogICIyIiwKICAiMSIsCiAgIjAiLAogICJleGZvbGlhdGVkIgogICkKYGBgCgoKCiMjIERlZ3JlZSBvZiByb290IHJlc29ycHRpb24gYXQgdGhlIGJlZ2lubmluZwpgYGB7ciByb290IHJlc29ycHRpb24gYmFzZWxpbmV9CmRmICU+JQogIGdncGxvdCgKICBhZXMoeCA9IGRlZ3JlZV9vZl9wcmltYXJ5X3Rvb3RoX3Jlc29ycHRpb25faGFsbF90b290aF9jcm93biwKICB5ID0gZGVncmVlX29mX3ByaW1hcnlfdG9vdGhfcmVzb3JwdGlvbl9jb250cmFsYXRlcmFsLAogIGNvbG9yID0gZ2VuZGVyKQogICkgKwogIGdlb21faml0dGVyKGFscGhhID0gMC44KSArCiAgbGFicyh0aXRsID0gIkJhc2VsaW5lIGRlZ3JlZSBvZiByb290IHJlc29ycHRpb24iLAogIHkgPSAiQ29udHJhbGF0ZXJhbCIsCiAgeCA9ICJIVCIpICsKICB0aGVtZV9wdWJjbGVhbigpICsKICBsYWJzKHRpdGxlID0gIkRlZ3JlZSBvZiByb290IHJlc29ycHRpb24gYXQgdGhlIGJlZ2lubmluZyIsIGNvbG9yID0gIkdlbmRlciIpIApgYGAKVGhlIHNhbWUsIG5vdyBmb3IgMXN0IG9yIDJuZCBtb2xhcgoKYGBge3J9CmRmICU+JQogIGdncGxvdCgKICBhZXMoeCA9IGRlZ3JlZV9vZl9wcmltYXJ5X3Rvb3RoX3Jlc29ycHRpb25faGFsbF90b290aF9jcm93biwKICB5ID0gZGVncmVlX29mX3ByaW1hcnlfdG9vdGhfcmVzb3JwdGlvbl9jb250cmFsYXRlcmFsLAogIGNvbG9yID0gaGFsbF9tb2xhcikKICApICsKICBnZW9tX2ppdHRlcihhbHBoYSA9IDAuOCwKICB3aWR0aCA9IDAuMTUsCiAgaGVpZ2h0ID0gMC4xNSkgKwogIGxhYnModGl0bCA9ICJCYXNlbGluZSBkZWdyZWUgb2Ygcm9vdCByZXNvcnB0aW9uIiwKICB5ID0gIkNvbnRyYWxhdGVyYWwiLAogIHggPSAiSFQiKSArCiAgdGhlbWVfcHViY2xlYW4oKSArCiAgbGFicyh0aXRsZSA9ICJEZWdyZWUgb2Ygcm9vdCByZXNvcnB0aW9uIGF0IHRoZSBiZWdpbm5pbmciLCBjb2xvciA9ICJNb2xhciIpIApgYGAKCgojIFRJTUUtVE8tRVZFTlQgQU5BTFlTSVMKCiMjIEtNIGFuYWx5c2lzCkNyZWF0ZSBuZXcgdmFyID0gZGF5cyB1bnRpbCBleGZvbGlhdGlvbgoKYGBge3IgIGRheXMgdW50aWwgZXhmb2xpYXRpb259CgpkZiRIYWxsX2dyb3VwIDwtCiAgZGlmZnRpbWUoCiAgICBkZiRkYXRlX2ZpcnN0X3RpbWVfbm90ZWRfYXNfaGF2aW5nX2V4Zm9saWF0ZWRfaGFsbCwKICAgIGRmJHRyZWF0bWVudF9kYXRlLAogICAgdW5pdHMgPSBjKCJkYXlzIikKICApICMgZm9yIEhhbGwKCmRmJENvbnRyYWxhdGVyYWxfZ3JvdXAgPC0KICBkaWZmdGltZSgKICAgIGRmJGRhdGVfZmlyc3RfdGltZV9ub3RlZF9hc19oYXZpbmdfZXhmb2xpYXRlZF9jb250cmFsYXRlcmFsLAogICAgZGYkdHJlYXRtZW50X2RhdGUsCiAgICB1bml0cyA9IGMoImRheXMiKQogICkgIyBmb3IgY29udHJhbGF0ZXJhbApgYGAKCgoKCkp1c3QgdG8gc2VlIHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBleGZvbGlhdGlvbiB0aW1lIGJldHdlZW4gZ3JvdXBzCgojIyMjIyMjIyMjIyMjIyMjIyMjIyBDSEVDSyBIRVJFIDIwMTkwNjA0ICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIyMjIyMjIyMjIyMjIyMjIyBET05FICMjIyMjIyMjIyMjIyMjIyMjIyMjIwpzZXBhcmF0ZSBieSAxc3QgYW5kIDJkIG1vbGFycwojIyMjIyMjIyMjIyMjIyMjIyMgRE9ORSAjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCmBgYHtyIHBsb3Qgc2VwYXJhdGUgYnkgMXN0IGFuZCAyZCBtb2xhcnN9CmRmICU+JQogIGdncGxvdChhZXMoeCA9IEhhbGxfZ3JvdXAsIHkgPSBDb250cmFsYXRlcmFsX2dyb3VwLCBjb2xvciA9IGhhbGxfbW9sYXIpKSArCiAgZ2VvbV9qaXR0ZXIoYWxwaGEgPSAwLjgsCiAgd2lkdGggPSAwLjE1LAogIGhlaWdodCA9IDAuMTUpICsKICB0aGVtZV9wdWJjbGVhbigpICsKICBsYWJzKAogIHRpdGxlID0gIkRheXMgaW4gZXhmb2xpYXRpb24gZm9yIHBhaXJzIG9mIG1vbGFycyIsCiAgeSA9ICJDb250cmFsYXRlcmFsIiwKICB4ID0gIkhUIiwKICBjb2xvciA9ICJNb2xhciIKICApCmBgYAoKY2hlY2sgdGhlIGNvcnJlbGF0aW9uLiAKYGBge3IgY29ycmVsYXRpb24gcGxvdH0KZGYgJT4lCiAgZ2dwbG90KGFlcyh4ID0gSGFsbF9ncm91cCwgeSA9IENvbnRyYWxhdGVyYWxfZ3JvdXAsIGNvbG9yID0gaGFsbF9tb2xhcikpICsKICBnZW9tX2ppdHRlcihhbHBoYSA9IDAuOCwKICAgICAgICAgICAgICB3aWR0aCA9IDAuMTUsCiAgICAgICAgICAgICAgaGVpZ2h0ID0gMC4xNSkgKwogIGdlb21fc21vb3RoKCkgKwogIHRoZW1lX3B1YmNsZWFuKCkgKwogIGxhYnModGl0bGUgPSAiQ29ycmVsYXRpb24gYmV0d2VlbiBleGZvbGlhdGlvbiB0aW1lcyBDVCAmIEhUIChkYXlzKSIsCiAgICAgICB5ID0gIkNMIiwgeCA9ICJIVCIpCmBgYApJIHNlZSB0aGVyZSdzIGEgZGlyZWN0bHkgcHJvcG9ydGlvbmFsIGNvcnJlbGF0aW9uLiBUaGlzIHN0cm9uZ2x5IHN1Z2dlc3RzIHRoYXQgYXMgYSBkdGUgd2l0aCBIVCBleGZvbGlhdGVzLCBzbyBkb2VzIGl0cyBjb250cmFsYXRlcmFsLgoKYGBge3Igc2VlIGNvcnJlbGF0aW9uIGJldHdlZW4gZ3JvdXBzfQpsbShIYWxsX2dyb3VwIH4gQ29udHJhbGF0ZXJhbF9ncm91cCwgZGF0YSA9IGRmKQpgYGAKClNvLCBmb3IgZXZlcnkgZXh0cmEgdW5pdCBvZiBleGZvbGlhdGlvbiB0aW1lIGZvciBhIENvbnRyYWxhdGVyYWwgdG9vdGgsIGEgSFQgYWxzbyBpbmNyZWFzZSBpbiAwLjc5IHVuaXQgb2YgdGltZS4gCgoKY3JlYXRlIGEgbmV3IGNvbHVtbiBldmVudCBmdWxsIHdpdGggMQpgYGB7ciBkdW1teSBjb2x1bW59CmRmJGV2ZW50IDwtIDEKYGBgCgpOb3cgZ2F0aGVyIEhhbGwgYW5kIGNvbnRyYWxhdGVyYWwKCmBgYHtyIGdhdGhlciB0ZWV0aH0KZGYgPC0gZGYgJT4lCiAgZ2F0aGVyKGtleSA9ICJncm91cCIsCiAgICAgICAgIHZhbHVlID0gImV4Zl90aW1lIiwKICAgICAgICAgSGFsbF9ncm91cDpDb250cmFsYXRlcmFsX2dyb3VwKQpgYGAKCgojIyMjIyMjIyMjIyMjIyMjIyMgRE9ORSAjIyMjIyMjIyMjIyMjIyMjIyMjIyMKY2hhbmdlIDFzdCBhbmQgMmQgbW9sYXJzCiMjIyMjIyMjIyMjIyMjIyMjIyBET05FICMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKYGBge3IgaGlzdG8gb2YgZXhmX3RpbWUgZ2VuZXJhbH0KZGYgJT4lIAogIGdncGxvdChhZXMoeCA9IGV4Zl90aW1lKSkgKyAKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gNykgKyAKICBmYWNldF9ncmlkKGdyb3VwfmhhbGxfbW9sYXIpKyAKICB0aGVtZV9wdWJjbGVhbigpICsgCiAgbGFicyh0aXRsZSA9ICJFeGZvbGlhdGlvbiB0aW1lIGhpc3RvZ3JhbSBieSBtb2xhciBhbmQgZ3JvdXAiLCAKICAgICAgIHkgPSAiQ291bnQiLCAKICAgICAgIHggPSAiRXhmb2xpYXRpb24gdGltZSAoZGF5cyIpCmBgYApTYW1lIGZvciBvbmx5IGZvciBtb2xhciB0eXBlCmBgYHtyfQpkZiAlPiUKICBnZ3Bsb3QoYWVzKHggPSBleGZfdGltZSkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gNykgKwogIGZhY2V0X2dyaWQoLiB+IGhhbGxfbW9sYXIpICsKICB0aGVtZV9wdWJjbGVhbigpICsKICBsYWJzKHRpdGxlID0gIkV4Zm9saWF0aW9uIHRpbWUgaGlzdG9ncmFtIGJ5IG1vbGFyIiwKICB5ID0gIkNvdW50IiwKICB4ID0gIkV4Zm9saWF0aW9uIHRpbWUgKGRheXMiKQpgYGAKCgoKYGBge3IgaGlzdG8gb2YgZXhmX3RpbWUgIGJ5IGdlbmRlcn0KZGYgJT4lIAogIGdncGxvdChhZXMoeCA9IGV4Zl90aW1lLCBmaWxsID0gZ2VuZGVyKSkgKyAKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMTApICsgCiAgZmFjZXRfZ3JpZChncm91cH5oYWxsX21vbGFyKSArIAogIHRoZW1lX3B1YmNsZWFuKCkgKyAKICBsYWJzKHRpdGxlID0gIkV4Zm9saWF0aW9uIHRpbWUgaGlzdG9ncmFtIGJ5IG1vbGFyLCBncm91cCBhbmQgZ2VuZGVyIiwgCiAgICAgICB5ID0gIkNvdW50IiwgCiAgICAgICB4ID0gIkV4Zm9saWF0aW9uIHRpbWUgKGRheXMiLCAKICAgICAgIGdlbmRlciA9ICJHZW5kZXIiKQpgYGAKUVVFU1RJT046IFdoYXQgY291bGQgdGhpcyBiaW1vZGFsIGRpc3RyaWJ1dGlvbiBiZT8KCiMjIyBLYXBsYW4tTWVpZXIgYW5hbHlzaXMgCgpgYGB7ciBzdXJ2aXZhbCBvYmplY3QgY3JlYXRlZH0Kc3Vydl9vYmplY3QgPC0gc3Vydml2YWw6OlN1cnYodGltZSA9IGRmJGV4Zl90aW1lLCBldmVudCA9IGRmJGV2ZW50KQpgYGAKQ2hlY2sgdGhlIHN1cnZpdmFsIG9iamVjdApgYGB7ciBzdXJ2aXZhbCBvYmplY3QgZGV0YWlsfQpzdXJ2X29iamVjdAoKYGBgCgpDb252ZXJ0IHRoZSBkaWZmdGltZSBpbiBudW1iZXIgdG8gZXh0cmFjdCBhbnkgd3JvbmcgdmFsdWUsIGkuZS4KCmBgYHtyfQpkZiRleGZfdGltZV9udW1iZXIgPC0gYXMubnVtZXJpYyhkZiRleGZfdGltZSkgIyBjb252ZXJ0IGRpZmYgdGltZSBpbiBhIG5ldyB2YXIKd2hpY2goZGYkZXhmX3RpbWVfbnVtYmVyIDwgMCkgIyBjaGVjayBpZiBpcyBhbnkgd3JvbmcgdGltZQpgYGAKCgpgYGB7ciBkZWxldGUgdGhpc30KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyMjIyMjIyMjIERFTEVURSBUSElTIFNURVAgIyMjIyMjIyMjIyMjIyMjIyMjCiMgZGYgPC0gZGYgJT4lIAojICBmaWx0ZXIoYWxsb2NhdGlvbl9udW0gIT0gNzgpCiMjIyMjIyMjIyMgREVMRVRFIFRISVMgU1RFUCAjIyMjIyMjIyMjIyMjIyMjIyMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpgYGAKCgpNYXN0ZXIgdGFibGUgZm9yIHN1cnZpdmFsIGFuYWx5c2lzCmBgYHtyIGZpdCBzdXJ2aXZhbH0KZml0MSA8LSBzdXJ2aXZhbDo6c3VydmZpdChzdXJ2X29iamVjdCB+IGdyb3VwLCBkYXRhID0gZGYpCnN1bW1hcnkoZml0MSkKYGBgCgo5MTcjIyMgVGVjaG5pY2FsIGV4cGxhbmF0aW9uIGFuZCBlc3NlbnRpYWwgY29uY2VwdHMKCkZvbGxvdy11cCBkYXRhIGFyZSBjZW5zb3JlZDogb25lIGRvZXMgbm90IGtub3cgdGhlIGV4YWN0IHN1cnZpdmFsIHRpbWUsIG9ubHkgdGhhdCBpdCBpcyBncmVhdGVyIG9yIGxlc3MgdGhhbiBhIGNlcnRhaW4gdGltZS4gCkJlaW5nIFggdGhlIHJlYWwgdGltZSBvZiBleGZvbGlhdGlvbiBhbmQgVCB0aGUgdGltZSBjZW5zb3JlZCwgd2hhdCB3ZSBvYnNlcnZlIGlzIHRoZSBtaW5pbXVtIG9mIFggYW5kIFQgdG9nZXRoZXIgd2l0aCBhbiBpbmRpY2F0aW9uIG9mIHdoaWNoIGlzIHdoaWNoLiAKV2l0aCB0aGlzLCB3ZSBjcmVhdGUgYW4gUyh0KSBzdXJ2aXZhbCBmdW5jdGlvbiB0aGF0IG1lYXN1cmVzIHRoZSBwcm9iYWJpbGl0eSBvZiBleGZvbGlhdGlvbiBhdCBhIGdpdmVuIG1vbWVudC4gCgpUaGUgYW5hbHlzaXMgcHJvY2VzcyBiZWdpbnMgd2l0aCB0aGUgY3JlYXRpb24gb2YgYSBzdXJ2aXZhbCBvYmplY3QuCgpPbmNlIHdlIGhhdmUgdGhlIHN1cnZpdmFsIG9iamVjdCwgd2UgY2FuIGNhbGN1bGF0ZSB0aGUgc3Vydml2YWwgZnVuY3Rpb24gZm9yIGNlbnN1cyBkYXRhIG9uIHRoZSByaWdodC4gCgpGb3IgYWxsIHRoZSB0ZWV0aCBpcwoKYGBge3J9CnN1cnZpdmFsOjpzdXJ2Zml0KHN1cnZfb2JqZWN0IH4gZ3JvdXAsIGRhdGEgPSBkZikKYGBgCgpTbywgdGhlIG1lZGlhbiBvZiBleGZvbGlhdGlvbiB0aW1lIGZvciBjb250cmFsYXRlcmFsIGlzIDEzMzUgZGF5cyAoZGl2aWRlZCBieSAzMCA9IDQ0LjUgbW9udGhzIGFwcHJveCksIGFuZCBmb3IgSGFsbCBpcyAxMDk4IGRheXMgKDM2LjYgbW9udGhzKS4gVGhlIGxvd2VyIDk1JUlDIGFyZSAxMTYzIGRheXMgZm9yIENMIGFuZCA5MTcgZm9yIEhULiAKCk5FVzogZm9yIEhhbGwgaXMgMTE1NyBkYXlzICgzOC41IG1vbnRocykuIFRoZSBsb3dlciA5NSVJQyBhcmUgMTI1MSBkYXlzIGZvciBDTCBhbmQgMTA2MiBmb3IgSFQuCgpJbiBvcmRlciB0byBzZWUgaWYgdGhlcmUgYXJlIGRpZmZlcmVuY2VzIGluIHRoZSBncm91cHMsIGl0IGlzIG5lY2Vzc2FyeSB0byBvYnNlcnZlIHRoZSBjb21wbGV0ZSBzdXJ2aXZhbCBjdXJ2ZSBhbmQgdG8gdmVyaWZ5IGlmIHNvbWV3aGVyZSB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbHMgZG8gbm90IG92ZXJsYXAuIE5vdyBsZXQncyBncmFwaAoKIyMjIyBQbG90cyBncmV5CmBgYHtyIG1haW4gcGxvdCBzdXJ2aXZhbCBncmV5IG1vbnRoc30KIyBqcGVnKCJzdXJ2aXZhbC1ncmV5LW1vbnRocy5qcGciKSAKc3Vydm1pbmVyOjpnZ3N1cnZwbG90KAogIGZpdDEsCiAgZGF0YSA9IGRmLAogIGNvbmYuaW50ID0gVFJVRSwKICAjIEFkZCBjb25maWRlbmNlIGludGVydmFsCiAgcHZhbCA9IFRSVUUsCiAgcHZhbC5jb29yZCA9IGMoMTQwMCwgMC4xMCksIAogICMgYWRkIHAgdmFsdWUKICB4c2NhbGUgPSAiZF9tIiwKICAjIGNvbnZlcnQgZGF5cyBpbiB5ZWFycwogIHhsaW0gPSBjKDAsIDMzNTApLAogICMgcHJlc2VudCBuYXJyb3dlciBYIGF4aXMsIGJ1dCBub3QgYWZmZWN0CiAgIyBzdXJ2aXZhbCBlc3RpbWF0ZXMuCiAgIyBjb25mLmludC5zdHlsZSA9ICJzdGVwIiwgIAogICMgY3VzdG9taXplIHN0eWxlIG9mIGNvbmZpZGVuY2UgaW50ZXJ2YWxzCiAgIyBzdXJ2Lm1lZGlhbi5saW5lID0gImh2IiwKICAjIGFkZCB0aGUgbWVkaWFuIHN1cnZpdmFsIHBvaW50ZXIuCiAgbGVnZW5kLmxhYnMgPSBjKCJDTCBncm91cCIsICJIVCBncm91cCIpLAogIGZ1biA9ICJldmVudCIsIAogIAogICAjIyMjIyMjIyMjIHJpc2sgdGFibGUgIyMjIyMjIyMjCiAgcmlzay50YWJsZSA9IFRSVUUsCiAgcmlzay50YWJsZS55LnRleHQuY29sID0gVFJVRSwKICByaXNrLnRhYmxlLnkudGV4dCA9IFRSVUUsCiAgcmlzay50YWJsZS5oZWlnaHQgPSAwLjM0LCAKICByaXNrLnRhYmxlLnRpdGxlID0gIkV4Zm9saWF0aW9uIGV2ZW50cyIsCiAgcGFsZXR0ZSA9IGMoIiMzMzMzMzMiLCAiIzk5OTk5OSIpLCMgY3VzdG9tIGNvbG9yIHBhbGV0dGVzCiAgIyBwYWxldHRlID0gImdyZXkiICMgZm9yIGJ3IHB1YmxpY2F0aW9uIGlmIHJlcXVpcmVkCiAgCikgKwogIGxhYnModGl0bGUgPSAiRXhmb2xpYXRpb24gVGltZSBQcm9iYWJpbGl0eSBQbG90IChNb250aHMpIiwKICAgICAgIHggPSAiVGltZSBpbiBtb250aHMiLCAKICAgICAgIHkgPSAiRXhmb2xpYXRpb24gUHJvYmFiaWxpdHkiKQojIENsb3NlIHRoZSBwZGYgZmlsZQojIGRldi5vZmYoKSAKCmBgYApgYGB7ciBtYWluIHBsb3Qgc3Vydml2YWwgZ3JleSB5ZWFyc30KIyBqcGVnKCJzdXJ2aXZhbC1ncmV5LXllYXJzLmpwZyIpIApzdXJ2bWluZXI6Omdnc3VydnBsb3QoCiAgZml0MSwKICBkYXRhID0gZGYsCiAgY29uZi5pbnQgPSBUUlVFLAogICMgQWRkIGNvbmZpZGVuY2UgaW50ZXJ2YWwKICBwdmFsID0gVFJVRSwKICBwdmFsLmNvb3JkID0gYygxNDAwLCAwLjEwKSwgCiAgIyBhZGQgcCB2YWx1ZQogIHhzY2FsZSA9ICJkX3kiLAogICMgY29udmVydCBkYXlzIGluIHllYXJzCiAgeGxpbSA9IGMoMCwgMzM1MCksCiAgIyBwcmVzZW50IG5hcnJvd2VyIFggYXhpcywgYnV0IG5vdCBhZmZlY3QKICAjIHN1cnZpdmFsIGVzdGltYXRlcy4KICAjIGNvbmYuaW50LnN0eWxlID0gInN0ZXAiLCAgCiAgIyBjdXN0b21pemUgc3R5bGUgb2YgY29uZmlkZW5jZSBpbnRlcnZhbHMKICAjIHN1cnYubWVkaWFuLmxpbmUgPSAiaHYiLAogICMgYWRkIHRoZSBtZWRpYW4gc3Vydml2YWwgcG9pbnRlci4KICBsZWdlbmQubGFicyA9IGMoIkNMIGdyb3VwIiwgIkhUIGdyb3VwIiksCiAgZnVuID0gImV2ZW50IiwgCiAgCiAgICMjIyMjIyMjIyMgcmlzayB0YWJsZSAjIyMjIyMjIyMKICByaXNrLnRhYmxlID0gVFJVRSwKICByaXNrLnRhYmxlLnkudGV4dC5jb2wgPSBUUlVFLAogIHJpc2sudGFibGUueS50ZXh0ID0gVFJVRSwKICByaXNrLnRhYmxlLmhlaWdodCA9IDAuMzQsIAogIHJpc2sudGFibGUudGl0bGUgPSAiRXhmb2xpYXRpb24gZXZlbnRzIiwKICBwYWxldHRlID0gYygiIzMzMzMzMyIsICIjOTk5OTk5IiksIyBjdXN0b20gY29sb3IgcGFsZXR0ZXMKICAjIHBhbGV0dGUgPSAiZ3JleSIgIyBmb3IgYncgcHVibGljYXRpb24gaWYgcmVxdWlyZWQKICAKKSArCiAgbGFicyh0aXRsZSA9ICJFeGZvbGlhdGlvbiBUaW1lIFByb2JhYmlsaXR5IFBsb3QgKFllYXJzKSIsCiAgICAgICB4ID0gIlRpbWUgaW4geWVhcnMiLCAKICAgICAgIHkgPSAiRXhmb2xpYXRpb24gUHJvYmFiaWxpdHkiKQojIENsb3NlIHRoZSBwZGYgZmlsZQojIGRldi5vZmYoKSAKYGBgCgojIyMjIFBsb3RzIGNvbG9yCmBgYHtyIG1haW4gcGxvdCBzdXJ2aXZhbCBjb2xvciBtb250aHN9CiMganBlZygic3Vydml2YWwtY29sb3ItbW9udGhzLmpwZyIpIApzdXJ2bWluZXI6Omdnc3VydnBsb3QoCiAgZml0MSwKICBkYXRhID0gZGYsCiAgY29uZi5pbnQgPSBUUlVFLAogICMgQWRkIGNvbmZpZGVuY2UgaW50ZXJ2YWwKICBwdmFsID0gVFJVRSwKICBwdmFsLmNvb3JkID0gYygxNDAwLCAwLjEwKSwgCiAgIyBhZGQgcCB2YWx1ZQogIHhzY2FsZSA9ICJkX20iLAogICMgY29udmVydCBkYXlzIGluIHllYXJzCiAgeGxpbSA9IGMoMCwgMzM1MCksCiAgIyBwcmVzZW50IG5hcnJvd2VyIFggYXhpcywgYnV0IG5vdCBhZmZlY3QKICAjIHN1cnZpdmFsIGVzdGltYXRlcy4KICAjIGNvbmYuaW50LnN0eWxlID0gInN0ZXAiLCAgCiAgIyBjdXN0b21pemUgc3R5bGUgb2YgY29uZmlkZW5jZSBpbnRlcnZhbHMKICAjIHN1cnYubWVkaWFuLmxpbmUgPSAiaHYiLAogICMgYWRkIHRoZSBtZWRpYW4gc3Vydml2YWwgcG9pbnRlci4KICBsZWdlbmQubGFicyA9IGMoIkNMIGdyb3VwIiwgIkhUIGdyb3VwIiksCiAgZnVuID0gImV2ZW50IiwgCiAgCiAgICMjIyMjIyMjIyMgcmlzayB0YWJsZSAjIyMjIyMjIyMKICByaXNrLnRhYmxlID0gVFJVRSwKICByaXNrLnRhYmxlLnkudGV4dC5jb2wgPSBUUlVFLAogIHJpc2sudGFibGUueS50ZXh0ID0gVFJVRSwKICByaXNrLnRhYmxlLmhlaWdodCA9IDAuMzQsIAogIHJpc2sudGFibGUudGl0bGUgPSAiRXhmb2xpYXRpb24gZXZlbnRzIiwKICBwYWxldHRlID0gYygiI0NBM0M0MiIsICIjMjg2MzdCIiksIyBjdXN0b20gY29sb3IgcGFsZXR0ZXMKICAjIHBhbGV0dGUgPSAiZ3JleSIgIyBmb3IgYncgcHVibGljYXRpb24gaWYgcmVxdWlyZWQKICAKKSArCiAgbGFicyh0aXRsZSA9ICJFeGZvbGlhdGlvbiBUaW1lIFByb2JhYmlsaXR5IFBsb3QgKE1vbnRocykiLAogICAgICAgeCA9ICJUaW1lIGluIG1vbnRocyIsIAogICAgICAgeSA9ICJFeGZvbGlhdGlvbiBQcm9iYWJpbGl0eSIpCiMgQ2xvc2UgdGhlIHBkZiBmaWxlCiMgZGV2Lm9mZigpIAoKYGBgCmBgYHtyIG1haW4gcGxvdCBzdXJ2aXZhbCBjb2xvciB5ZWFyc30KIyBqcGVnKCJzdXJ2aXZhbC1jb2xvci15ZWFycy5qcGciKSAKc3Vydm1pbmVyOjpnZ3N1cnZwbG90KAogIGZpdDEsCiAgZGF0YSA9IGRmLAogIGNvbmYuaW50ID0gVFJVRSwKICAjIEFkZCBjb25maWRlbmNlIGludGVydmFsCiAgcHZhbCA9IFRSVUUsCiAgcHZhbC5jb29yZCA9IGMoMTQwMCwgMC4xMCksIAogICMgYWRkIHAgdmFsdWUKICB4c2NhbGUgPSAiZF95IiwKICAjIGNvbnZlcnQgZGF5cyBpbiB5ZWFycwogIHhsaW0gPSBjKDAsIDMzNTApLAogICMgcHJlc2VudCBuYXJyb3dlciBYIGF4aXMsIGJ1dCBub3QgYWZmZWN0CiAgIyBzdXJ2aXZhbCBlc3RpbWF0ZXMuCiAgIyBjb25mLmludC5zdHlsZSA9ICJzdGVwIiwgIAogICMgY3VzdG9taXplIHN0eWxlIG9mIGNvbmZpZGVuY2UgaW50ZXJ2YWxzCiAgIyBzdXJ2Lm1lZGlhbi5saW5lID0gImh2IiwKICAjIGFkZCB0aGUgbWVkaWFuIHN1cnZpdmFsIHBvaW50ZXIuCiAgbGVnZW5kLmxhYnMgPSBjKCJDTCBncm91cCIsICJIVCBncm91cCIpLAogIGZ1biA9ICJldmVudCIsIAogIAogICAjIyMjIyMjIyMjIHJpc2sgdGFibGUgIyMjIyMjIyMjCiAgcmlzay50YWJsZSA9IFRSVUUsCiAgcmlzay50YWJsZS55LnRleHQuY29sID0gVFJVRSwKICByaXNrLnRhYmxlLnkudGV4dCA9IFRSVUUsCiAgcmlzay50YWJsZS5oZWlnaHQgPSAwLjM0LCAKICByaXNrLnRhYmxlLnRpdGxlID0gIkV4Zm9saWF0aW9uIGV2ZW50cyIsCiAgcGFsZXR0ZSA9IGMoIiNDQTNDNDIiLCAiIzI4NjM3QiIpLCMgY3VzdG9tIGNvbG9yIHBhbGV0dGVzCiAgIyBwYWxldHRlID0gImdyZXkiICMgZm9yIGJ3IHB1YmxpY2F0aW9uIGlmIHJlcXVpcmVkCiAgCikgKwogIGxhYnModGl0bGUgPSAiRXhmb2xpYXRpb24gVGltZSBQcm9iYWJpbGl0eSBQbG90IChZZWFycykiLAogICAgICAgeCA9ICJUaW1lIGluIHllYXJzIiwgCiAgICAgICB5ID0gIkV4Zm9saWF0aW9uIFByb2JhYmlsaXR5IikKIyBDbG9zZSB0aGUgcGRmIGZpbGUKIyBkZXYub2ZmKCkKYGBgCgoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCmZpdDEgPC0gc3Vydml2YWw6OnN1cnZmaXQoc3Vydl9vYmplY3QgfiBncm91cCwgZGF0YSA9IGRmKQoKYGBge3J9Cmdnc3VydnBsb3QoCiAgc3Vydml2YWw6OnN1cnZmaXQoc3Vydl9vYmplY3QgfiBkZiRncm91cCksICAgIyBzdXJ2Zml0IG9iamVjdCB3aXRoIGNhbGN1bGF0ZWQgc3RhdGlzdGljcy4KICBkYXRhID0gZGYsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGRhdGEgdXNlZCB0byBmaXQgc3Vydml2YWwgY3VydmVzLgogIHJpc2sudGFibGUgPSBGQUxTRSwgICAgICAgICAgICAgICAgICAgICAgICAgICMgc2hvdyByaXNrIHRhYmxlLgogIHB2YWwgPSBUUlVFLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgc2hvdyBwLXZhbHVlIG9mIGxvZy1yYW5rIHRlc3QuCiAgcHZhbC5jb29yZCA9IGMoMTUwMCwgMC4zMCksICAgICAgICAgICAgICAgICAgIyBwb3NpdGlvbiBvZiB0aGUgbGVnZW5kCiAgY29uZi5pbnQgPSBUUlVFLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBzaG93IGNvbmZpZGVuY2UgaW50ZXJ2YWxzIGZvcgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgcG9pbnQgZXN0aW1hdGVzIG9mIHN1cnZpdmFsIGN1cnZlcy4KICBwYWxldHRlID0gYygiI0U3QjgwMCIsICIjMkU5RkRGIiksCiAgeGxpbSA9IGMoMCwgMzM1MCksICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBwcmVzZW50IG5hcnJvd2VyIFggYXhpcywgYnV0IG5vdCBhZmZlY3QKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHN1cnZpdmFsIGVzdGltYXRlcy4KICB4bGFiID0gIlRpbWUgaW4gZGF5cyIsICAgICAgICAgICAgICAgICAgICAgICAjIGN1c3RvbWl6ZSBYIGF4aXMgbGFiZWwuCiAgYnJlYWsudGltZS5ieSA9IDM2NSwgICAgICAgICAgICAgICAgICAgICAgICAgIyBicmVhayBYIGF4aXMgaW4gdGltZSBpbnRlcnZhbHMgYnkgNTAwLgogIGdndGhlbWUgPSB0aGVtZV9jbGFzc2ljKCksICAgICAgICAgICAgICAgICAgICAgIyBjdXN0b21pemUgcGxvdCBhbmQgcmlzayB0YWJsZSB3aXRoIGEgdGhlbWUuCiAgIyByaXNrLnRhYmxlLnkudGV4dC5jb2wgPSBULCMgY29sb3VyIHJpc2sgdGFibGUgdGV4dCBhbm5vdGF0aW9ucy4KICAjIHJpc2sudGFibGUuaGVpZ2h0ID0gMC4zNSwgIyB0aGUgaGVpZ2h0IG9mIHRoZSByaXNrIHRhYmxlCiAgIyByaXNrLnRhYmxlLnkudGV4dCA9IEZBTFNFLCMgc2hvdyBiYXJzIGluc3RlYWQgb2YgbmFtZXMgaW4gdGV4dCBhbm5vdGF0aW9ucwogICMgaW4gbGVnZW5kIG9mIHJpc2sgdGFibGUuCiAgCiAgY29uZi5pbnQuc3R5bGUgPSAic3RlcCIsCiAgIyBjdXN0b21pemUgc3R5bGUgb2YgY29uZmlkZW5jZSBpbnRlcnZhbHMKICBzdXJ2Lm1lZGlhbi5saW5lID0gImh2IiwKICAjIGFkZCB0aGUgbWVkaWFuIHN1cnZpdmFsIHBvaW50ZXIuCiAgZnVuID0gImV2ZW50IiwKICBsZWdlbmQubGFicyA9CiAgICBjKCJDTCBncm91cCIsICJIVCBncm91cCIpICAgICMgY2hhbmdlIGxlZ2VuZCBsYWJlbHMuCikKCmBgYAojIyBTdWJhbmFseXNpcwoKYGBge3J9CmF1dG9wbG90KGFhcmVnKFN1cnYoZXhmX3RpbWUgLCBldmVudCkgfiAKICAgICAgICAgICAgICAgICBnZW5kZXIsCiAgICAgICAgICAgICAgIGRhdGEgPSBkZikpCmBgYAoKIyMjIyMjIyMjIyMjIyMjIyMjIERPTkUgIyMjIyMjIyMjIyMjIyMjIyMjIyMjCmp1c3QgZm91ciBncm91cHMsIHdpdGggbW9sYXJzCiMjIyMjIyMjIyMjIyMjIyMjIyBET05FICMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKYGBge3J9CmF1dG9wbG90KGFhcmVnKFN1cnYoZXhmX3RpbWUgLCBldmVudCkgfiAKICAgICAgICAgICAgICAgICBoYWxsX21vbGFyLAogICAgICAgICAgICAgICBkYXRhID0gZGYpKQpgYGAKYGBge3J9CmF1dG9wbG90KGFhcmVnKFN1cnYoZXhmX3RpbWUgLCBldmVudCkgfiAKICAgICAgICAgICAgICAgICBjb250cmFsYXRlcmFsX21vbGFyLAogICAgICAgICAgICAgICBkYXRhID0gZGYpKQpgYGAKCgoKIyBhZGRpdGlvbmFsIGFuYWx5c2VzIEp1bHkgOCwgMjAxOQoKCiBUaGUgbWVhbiBhZ2UsIChzZCBhbmQgcmFuZ2UpIGZvcgoKbyAgIGFsbCBvZiB0aGUgY2hpbGRyZW4gd2hlbiB0aGV5IGhhZCB0aGUgY3Jvd24gZml0dGVkCgpvICAgVGhlIHNhbWUgZm9yIGJveXMgb25seQoKbyAgIFRoZSBzYW1lIGZvciBnaXJscyBvbmx5CgoKYGBge3IgYWdlIGF0IHRyZWF0bWVudCB0YWJsZX0KZGYgJT4lCiAgbXV0YXRlKAogIGJpcnRoX2RhdGUgPSB5bWQoYmlydGhfZGF0ZSksCiAgdHJlYXRtZW50X2RhdGUgPSB5bWQodHJlYXRtZW50X2RhdGUpLAogIGFnZV93aGVuX0hUID0gZmxvb3IoZGVjaW1hbF9kYXRlKHRyZWF0bWVudF9kYXRlKSAtIGRlY2ltYWxfZGF0ZShiaXJ0aF9kYXRlKSkKICApICU+JSAKICBzdW1tYXJpc2UoIkFnZSBhdCB0cmVhdG1lbnQiID0gbWVhbihhZ2Vfd2hlbl9IVCksIHNkID0gc2QoYWdlX3doZW5fSFQpLCBtaW4gPSBtaW4oYWdlX3doZW5fSFQpLCBtYXggPSBtYXgoYWdlX3doZW5fSFQpLCByYW5nZSA9IG1heCAtIG1pbikKYGBgCmBgYHtyIGFnZSBhdCB0cmVhdG1lbnQgaGlzdG9ncmFtfQpkZiAlPiUKICBtdXRhdGUoCiAgYmlydGhfZGF0ZSA9IHltZChiaXJ0aF9kYXRlKSwKICB0cmVhdG1lbnRfZGF0ZSA9IHltZCh0cmVhdG1lbnRfZGF0ZSksCiAgYWdlX3doZW5fSFQgPSBmbG9vcihkZWNpbWFsX2RhdGUodHJlYXRtZW50X2RhdGUpIC0gZGVjaW1hbF9kYXRlKGJpcnRoX2RhdGUpKQogICkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gYWdlX3doZW5fSFQpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDEwKSArCiAgdGhlbWVfcHVicigpICsKICBsYWJzKHRpdGxlID0gIkFnZSBhdCB0cmVhdG1lbnQiLAogIHggPSAiQWdlIGF0IHRyZWF0bWVudCIsIHkgPSAiQ291bnQiKQpgYGAKCgoKYGBge3IgYWdlIGF0IHRyZWF0bWVudCB0YWJsZSBieSBnZW5kZXJ9CmRmICU+JQogIG11dGF0ZSgKICBiaXJ0aF9kYXRlID0geW1kKGJpcnRoX2RhdGUpLAogIHRyZWF0bWVudF9kYXRlID0geW1kKHRyZWF0bWVudF9kYXRlKSwKICBhZ2Vfd2hlbl9IVCA9IGZsb29yKGRlY2ltYWxfZGF0ZSh0cmVhdG1lbnRfZGF0ZSkgLSBkZWNpbWFsX2RhdGUoYmlydGhfZGF0ZSkpCiAgKSAlPiUgCiAgZ3JvdXBfYnkoZ2VuZGVyKSAlPiUgCiAgc3VtbWFyaXNlKCJBZ2UgYXQgdHJlYXRtZW50IiA9IG1lYW4oYWdlX3doZW5fSFQpLCBzZCA9IHNkKGFnZV93aGVuX0hUKSwgbWluID0gbWluKGFnZV93aGVuX0hUKSwgbWF4ID0gbWF4KGFnZV93aGVuX0hUKSwgcmFuZ2UgPSBtYXggLSBtaW4pCmBgYAoKYGBge3IgYWdlIGF0IHRyZWF0bWVudCB0LXRlc3R9CmRmICU+JQogIG11dGF0ZSgKICBiaXJ0aF9kYXRlID0geW1kKGJpcnRoX2RhdGUpLAogIHRyZWF0bWVudF9kYXRlID0geW1kKHRyZWF0bWVudF9kYXRlKSwKICBhZ2Vfd2hlbl9IVCA9IGZsb29yKGRlY2ltYWxfZGF0ZSh0cmVhdG1lbnRfZGF0ZSkgLSBkZWNpbWFsX2RhdGUoYmlydGhfZGF0ZSkpCiAgKSAlJCUgCiAgdC50ZXN0KGFnZV93aGVuX0hUIH5nZW5kZXIsIGRhdGEgPSAuKQpgYGAKCgpgYGB7ciBhZ2UgYXQgdHJlYXRtZW50IGJ5IGdlbmRlciBib3hwbG90fQpkZiAlPiUKICBtdXRhdGUoCiAgYmlydGhfZGF0ZSA9IHltZChiaXJ0aF9kYXRlKSwKICB0cmVhdG1lbnRfZGF0ZSA9IHltZCh0cmVhdG1lbnRfZGF0ZSksCiAgYWdlX3doZW5fSFQgPSBmbG9vcihkZWNpbWFsX2RhdGUodHJlYXRtZW50X2RhdGUpIC0gZGVjaW1hbF9kYXRlKGJpcnRoX2RhdGUpKQogICkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gZ2VuZGVyLCB5ID0gYWdlX3doZW5fSFQpKSArCiAgeWxpbSgwLCAxMSkgKwogIGdlb21fYm94cGxvdCgpICsKICBnZW9tX2ppdHRlcihhbHBoYSA9IDAuNSkgKwogIHRoZW1lX3B1YmNsZWFuKCkgKyAKICBsYWJzKHRpdGxlID0gIkFnZSBhdCB0cmVhdG1lbnQgYnkgZ2VuZGVyIikKYGBgCmBgYHtyIGFnZSBhdCB0cmVhdG1lbnQgYnkgZ2VuZGVyIGhpc3RvZ3JhbX0KZGYgJT4lCiAgbXV0YXRlKAogIGJpcnRoX2RhdGUgPSB5bWQoYmlydGhfZGF0ZSksCiAgdHJlYXRtZW50X2RhdGUgPSB5bWQodHJlYXRtZW50X2RhdGUpLAogIGFnZV93aGVuX0hUID0gZmxvb3IoZGVjaW1hbF9kYXRlKHRyZWF0bWVudF9kYXRlKSAtIGRlY2ltYWxfZGF0ZShiaXJ0aF9kYXRlKSkKICApICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBhZ2Vfd2hlbl9IVCkpICsgCiAgZ2VvbV9oaXN0b2dyYW0oYmlucz0gMTApICsgCiAgdGhlbWVfcHVicigpICsgCiAgbGFicyh0aXRsZSA9ICJBZ2UgYXQgdHJlYXRtZW50IiwgCiAgICAgICB4ID0gIkFnZSBhdCB0cmVhdG1lbnQiLCB5ID0gIkNvdW50IikgKyAKICBmYWNldF9ncmlkKGdlbmRlcn4uKQpgYGAKCgrCtyAgICAgICAgIFRoZSBtZWFuIGFnZSAoc2QgYW5kIHJhbmdlKSBvZiB0aGUgY2hpbGRyZW4gd2hlbgoKbyAgIHRoZSBoYWxsIGNyb3duIHRvb3RoIGV4Zm9saWF0ZWQKCm8gICB0aGUgY29udHJhbGF0ZXJhbCB0b290aCBleGZvbGlhdGVkCgpgYGB7ciBleGZvbGlhdGlvbiB0aW1lIGJ5IEhUIGFuZCBDVCB0YWJsZX0KZGYgJT4lCiAgbXV0YXRlKAogIGFnZV93aGVuX0hUX2V4Zm9saWF0ZWQgPSBmbG9vcigKICBkZWNpbWFsX2RhdGUoZGF0ZV9maXJzdF90aW1lX25vdGVkX2FzX2hhdmluZ19leGZvbGlhdGVkX2hhbGwpIC0gZGVjaW1hbF9kYXRlKGJpcnRoX2RhdGUpCiAgKSAsCiAgYWdlX3doZW5fQ1RfZXhmb2xpYXRlZCA9IGZsb29yKAogIGRlY2ltYWxfZGF0ZShkYXRlX2ZpcnN0X3RpbWVfbm90ZWRfYXNfaGF2aW5nX2V4Zm9saWF0ZWRfY29udHJhbGF0ZXJhbCkgLSBkZWNpbWFsX2RhdGUoYmlydGhfZGF0ZSkKICApCiAgKSAlPiUKICBnYXRoZXIoa2V5ID0gImtleSIsIHZhbHVlID0gdmFsdWUsIGFnZV93aGVuX0hUX2V4Zm9saWF0ZWQ6YWdlX3doZW5fQ1RfZXhmb2xpYXRlZCkgJT4lIAogIGdyb3VwX2J5KGtleSkgJT4lIAogIHN1bW1hcmlzZSgKICAiTWVhbiBleGZvbCBhZ2UiID0gbWVhbih2YWx1ZSksCiAgc2QgPSBzZCh2YWx1ZSksCiAgbWluID0gbWluKHZhbHVlKSwKICBtYXggPSBtYXgodmFsdWUpLAogIHJhbmdlID0gbWF4KHZhbHVlKSAtIG1pbih2YWx1ZSkKICApCmBgYAoKYGBge3IgZXhmb2xpYXRpb24gdGltZSBieSBIVCBhbmQgQ1QgcGxvdH0KZGYgJT4lCiAgbXV0YXRlKAogIGFnZV93aGVuX0hUX2V4Zm9saWF0ZWQgPSBmbG9vcigKICBkZWNpbWFsX2RhdGUoZGF0ZV9maXJzdF90aW1lX25vdGVkX2FzX2hhdmluZ19leGZvbGlhdGVkX2hhbGwpIC0gZGVjaW1hbF9kYXRlKGJpcnRoX2RhdGUpCiAgKSAsCiAgYWdlX3doZW5fQ1RfZXhmb2xpYXRlZCA9IGZsb29yKAogIGRlY2ltYWxfZGF0ZShkYXRlX2ZpcnN0X3RpbWVfbm90ZWRfYXNfaGF2aW5nX2V4Zm9saWF0ZWRfY29udHJhbGF0ZXJhbCkgLSBkZWNpbWFsX2RhdGUoYmlydGhfZGF0ZSkKICApCiAgKSAlPiUKICBnYXRoZXIoa2V5ID0gImtleSIsIHZhbHVlID0gdmFsdWUsIGFnZV93aGVuX0hUX2V4Zm9saWF0ZWQ6YWdlX3doZW5fQ1RfZXhmb2xpYXRlZCkgJT4lIAogIGdncGxvdChhZXMoeCA9IHZhbHVlKSkgKyAKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gOCkgKyAKICBmYWNldF9ncmlkKGtleX4uKSArIAogIHRoZW1lX3B1YnIoKSArIAogIGxhYnModGl0bGUgPSAiQWdlIGF0IGV4Zm9saWF0aW9uIHRpbWUgYnkgZ3JvdXAiLCB5ID0gIkNvdW50IiwgeCA9ICJBZ2UgKHllYXJzKSIpCmBgYAoKIyBDT0RFQk9PSwpgYGB7cn0KIyBpbnN0YWxsLnBhY2thZ2VzKCJkYXRhTWFpZCIpCiAjZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJla3N0cm9lbS9kYXRhTWFpZCIpCmBgYAoKCgoKIyBJTlRFUkFDVElWRSBFREEKYGBge3J9CiMgaW5zdGFsbC5wYWNrYWdlcygiRXhQYW5EYVIiKQojbGlicmFyeShFeFBhbkRhUikKYGBgCmBgYHtyfQojZGYkY3NfaWQgPC0gcm93Lm5hbWVzKGRmKQojZGYkdHNfaWQgPC0gMQojRXhQYW5EYVI6OkV4UGFuRCgKIyAgZGYsCiMgIGNzX2lkID0gImNzX2lkIiwKIyAgdHNfaWQgPSAidHNfaWQiLAojICBjb21wb25lbnRzID0gYyh0cmVuZF9ncmFwaCA9IEZBTFNFLCBxdWFudGlsZV90cmVuZF9ncmFwaCA9IEZBTFNFKQojKQpgYGAKCgo=