This lab journal replicates the analyses for ‘starting to publish’.


Custom functions

  • fpackage.check: Check if packages are installed (and install if not) in R (source).
fpackage.check <- function(packages) {
  lapply(packages, FUN = function(x) {
    if (!require(x, character.only = TRUE)) {
      install.packages(x, dependencies = TRUE)
      library(x, character.only = TRUE)
    }
  })
}

fsave <- function(x, file, location="./data/processed/") {
  datename <- substr(gsub("[:-]", "", Sys.time()), 1,8)  
  totalname <- paste(location, datename, file, sep="")
  save(x, file = totalname)  
}

Packages

  • tidyverse: for data manipulation
  • ggplot2: for creating figures 2-4
  • ggpubr: for combining two figures in one (plot 2)
  • splines splines2: for modelling non-linear cohort relations
packages = c("tidyverse", "ggplot2", "ggpubr", "splines", "splines2")

fpackage.check(packages)

Input

We use two processed datasets:

Furthermore, we load in the results from our analyses to create figures 2-7.

load(file = "./data/processed/df_starting.rda")

load(file = "./data/processed/df_stopping.rda")

Defining color parameters up front

tot <- "#414141"
menc <- "#D1C166"
womenc <- "#48a363"
majc <- "#39839D"
minc <- "#B85042"

Figure 1

Number of PhDs entering the sample per cohort, split out by gender and ethnicity

df_starting %>%
  group_by(phd_year) %>%
  count() -> totalentry

df_starting %>%
  group_by(phd_year) %>%
  count(gender) -> genderentry

df_starting %>%
  group_by(phd_year) %>%
  count(ethnicity2) -> ethnientry

genderentry <- genderentry[genderentry$gender!="missing",]

ethnientry <- ethnientry[ethnientry$ethnicity2!="other",]


genderentry$type <- as.character(genderentry$gender)
genderentry <- genderentry[,-2]


ethnientry$type <- as.character(ethnientry$ethnicity2)
ethnientry <- ethnientry[,-2]

totalentry$type <- rep("total", times=nrow(totalentry))

entry_df <- rbind.data.frame(totalentry, genderentry, ethnientry)

entry_df$type <- ifelse(entry_df$type=="minority", "ethnic minority", entry_df$type)
entry_df$type <- ifelse(entry_df$type=="majority", "ethnic majority", entry_df$type)


ggplot(entry_df, aes(y=n, x=phd_year, color=factor(type, levels=c("total", "men", "women", "ethnic majority", "ethnic minority")))) +
  geom_line(lwd = 0.8)+
  theme_bw() +
  scale_x_continuous(breaks=c(1990,1995,2000,2005,2010,2015,2019))+
  labs(x = "Year of doctorate receipt", y = "Frequency") +
  theme(axis.title=element_text(face="bold")) +
  scale_color_manual(values=c(tot, menc, womenc, majc, minc), name="Group")

ggsave("./output/starting/plot1.jpg", height=4, width=8, dpi=1200)

Figure 2

Loading in results for ‘starting to publish’

load(file = "results/starting/20230405M1.rda")
M1 <- x
rm(x)

load(file = "results/starting/20230405M2.rda")
M2 <- x
rm(x)

load(file = "results/starting/20230405M3.rda")
M3 <- x
rm(x)

load(file = "results/starting/20230405M4.rda")
M4 <- x
rm(x)

Figure 2a: gender only

# Calculating predicted probabilities
M1 %>% predict(df_starting, type="link", se.fit = TRUE) -> plot2a


# calculate upper and lower bounds for the confidence intervals
plot2a$upper <- plot2a$fit + (1.96 * plot2a$se.fit)
plot2a$lower <- plot2a$fit - (1.96 * plot2a$se.fit)

plot2a <- as.data.frame(plot2a)

# excluding gender = missing from the plot
plot2a$gender <- df_starting$gender
plot2a <- plot2a[plot2a$gender!="missing",]


plot2a %>%
  group_by(gender) %>%
  summarise(fit = plogis(mean(fit)), 
            upper = plogis(mean(upper)), 
            lower = plogis(mean(lower))) -> plot2a


ggplot(plot2a,aes(gender,fit,  color=(gender)))+
  geom_boxplot(width = .1) +
  geom_errorbar(aes(ymin = lower, ymax = upper), lwd = 0.8, width = .05) + ylim(0, 0.3) +
  labs(x = "Gender", y = "Probability of starting to publish") +
  theme_bw() +
  scale_color_manual(values=c(menc, womenc), name="Gender") +
  geom_text(x=0.5, y=0.28, label="A", size=10, color="black")+
  theme(axis.title=element_text(face="bold"),
        legend.position = "none") -> plot2a


# Exact gender differences in probability of starting to publish
plot2a$data
## # A tibble: 2 x 4
##   gender   fit upper lower
##   <fct>  <dbl> <dbl> <dbl>
## 1 men    0.212 0.216 0.208
## 2 women  0.220 0.225 0.215

Figure 2b: ethnicity only

# Calculating predicted probabilities
M2 %>% predict(df_starting, type = "link", se.fit = TRUE) -> plot2b


# Calculating confidence intervals
plot2b$upper <- plot2b$fit + (1.96 * plot2b$se.fit)
plot2b$lower <- plot2b$fit - (1.96 * plot2b$se.fit)

plot2b <- as.data.frame(plot2b)
plot2b$ethnicity2 <- df_starting$ethnicity2

# Removing ethnicity 'other' from plot
plot2b <- plot2b[plot2b$ethnicity2!="other",]


plot2b %>%
  group_by(ethnicity2) %>%
  summarise(fit = plogis(mean(fit)), 
            upper = plogis(mean(upper)), 
            lower = plogis(mean(lower))) -> plot2b

ggplot(plot2b,aes(as.factor(ethnicity2),fit,  color=(ethnicity2)))+
  geom_boxplot(width = .1) +
  geom_errorbar(aes(ymin = lower, ymax = upper), lwd = 0.8, width = .05) + ylim(0, 0.3) +
  labs(x = "Ethnicity", y = "Probability of starting to publish") +
  theme_bw() +
  scale_color_manual(values=c(majc, minc), name="Ethnicity") +
  geom_text(x=0.5, y=0.28, label="B", size=10, color="black") +
  theme(axis.title=element_text(face="bold"),
        legend.position = "none") -> plot2b


# Exact ethnic differences in probability of starting to publish
plot2b$data
## # A tibble: 2 x 4
##   ethnicity2   fit upper lower
##   <fct>      <dbl> <dbl> <dbl>
## 1 majority   0.197 0.201 0.194
## 2 minority   0.144 0.160 0.129

Figure 2: combining A and B

plot2 <- ggarrange(plot2a, plot2b, ncol = 2, nrow=1)

plot2

Figure 3

Predicted probability to start by gender and cohort

plot4 <- plot3 <- M4 %>% predict(df_starting, type="link", se.fit=TRUE)

plot3 <- as.data.frame(plot3)

plot3$gender <- df_starting$gender
plot3$phd_cohort <- df_starting$phd_cohort

plot3 <- plot3[plot3$gender!="missing",]

plot3$upper <- plot3$fit + (1.96 * plot3$se.fit)
plot3$lower <- plot3$fit - (1.96 * plot3$se.fit)


plot3 %>%
  group_by(gender, phd_cohort) %>%
  summarise(fit = plogis(mean(fit)), 
            upper = plogis(mean(upper)), 
            lower = plogis(mean(lower))) -> plot3


# transform back to years for easier interpretability
plot3$phdyear <- plot3$phd_cohort+1990


ggplot(plot3, aes(x=as.factor(phdyear), y=fit, color=gender)) +
  geom_boxplot(lwd=.6, position="dodge") +
  geom_errorbar(aes(ymin=lower, ymax=upper), lwd=.7, position="dodge") +
  ylim(0, 0.3) +
  labs(x = "PhD year", y = "Probability of starting to publish") +
  theme_bw() +
  scale_x_discrete(labels = c("1990", c(rep(" ", 4)), "1995", c(rep(" ", 4)), "2000", c(rep(" ", 4)), "2005", c(rep(" ", 4)), "2010", c(rep(" ", 4)), "2015", c(rep("", 3)), "2019")) +
  scale_color_manual(values=c(men=menc,women=womenc), name="Gender") +
  theme(axis.title=element_text(face="bold"), legend.title=element_text(face="bold"))

Figure 4

Predicted probability to start by ethnicity and cohort

plot4 <- as.data.frame(plot4)

plot4$ethnicity2 <- df_starting$ethnicity2
plot4$phd_cohort <- df_starting$phd_cohort

plot4 <- plot4[plot4$ethnicity2!="other",]

plot4$upper <- plot4$fit + (1.96 * plot4$se.fit)
plot4$lower <- plot4$fit - (1.96 * plot4$se.fit)


plot4 %>%
  group_by(ethnicity2, phd_cohort) %>%
  summarise(fit = plogis(mean(fit)), 
            upper = plogis(mean(upper)), 
            lower = plogis(mean(lower))) -> plot4


# transform back to years for easier interpretability
plot4$phdyear <- plot4$phd_cohort+1990


ggplot(plot4, aes(x=as.factor(phdyear), y=fit, color=ethnicity2)) +
  geom_boxplot(lwd=.6, position="dodge") +
  geom_errorbar(aes(ymin=lower, ymax=upper), lwd=.7, position="dodge") +
  ylim(0, 0.5) +
  labs(x = "PhD year", y = "Probability of starting to publish") +
  theme_bw() +
  scale_x_discrete(labels = c("1990", c(rep(" ", 4)), "1995", c(rep(" ", 4)), "2000", c(rep(" ", 4)), "2005", c(rep(" ", 4)), "2010", c(rep(" ", 4)), "2015", c(rep("", 3)), "2019")) + 
  scale_color_manual(values=c(majority=majc, minority=minc), name="Ethnicity") +
  theme(axis.title=element_text(face="bold"), legend.title=element_text(face="bold"))

Figure 5

Loading in results for ‘stopping to publish’

load(file = "results/stopping/20230405M1.rda")
M1 <- x
rm(x)

load(file = "results/stopping/20230405M2.rda")
M2 <- x
rm(x)

load(file = "results/stopping/20230405M3.rda")
M3 <- x
rm(x)

load(file = "results/stopping/20230405M4.rda")
M4 <- x
rm(x)

Survival times by gender and ethnicity. Based on M1: gender only.

# Calculating predicted probabilities
M1 %>% predict(type="response", conf.int=TRUE, conf.level=.95, newdata=df_ppf3) -> plot5a

class(plot5a)  
## [1] "tbl_df"     "tbl"        "data.frame"
plot5a <- as.data.frame(plot5a)

# excluding gender = missing from the plot
plot5a$gender <- df_ppf3$gender
plot5a <- plot5a[plot5a$gender!="missing",]



plot5a %>%
  group_by(gender) %>%
  summarise(fit = mean(.pred_time), 
            upper = mean(.pred_upper), 
            lower = mean(.pred_lower)) -> plot5a


ggplot(plot5a,aes(gender, fit,  color=(gender)))+
  geom_boxplot(width = .1) +
  geom_errorbar(aes(ymin = lower, ymax = upper), lwd = 0.8, width = .05) + 
  ylim(0, 20) +
  labs(x = "Gender", y = "Average predicted survival time") +
  theme_bw() +
  scale_color_manual(values=c(menc, womenc), name="Gender") +
  geom_text(x=0.7, y=19, label="A", size=10, color="black") +
  theme(axis.title=element_text(face="bold"),
        legend.position = "none") -> plot5a

plot5a

Based on M2: ethnicity only.

# Calculating predicted probabilities
M2 %>% predict(type="response", conf.int=TRUE, conf.level=.95, newdata=df_ppf3) -> plot5b
  
plot5b <- as.data.frame(plot5b)

# excluding gender = missing from the plot
plot5b$ethnicity <- df_ppf3$ethnicity2
plot5b <- plot5b[plot5b$ethnicity!="other",]

plot5b %>%
  group_by(ethnicity) %>%
  summarise(fit = mean(.pred_time), 
            upper = mean(.pred_upper), 
            lower = mean(.pred_lower)) -> plot5b


ggplot(plot5b,aes(ethnicity, fit,  color=(ethnicity)))+
  geom_boxplot(width = .1) +
  geom_errorbar(aes(ymin = lower, ymax = upper), lwd = 0.8, width = .05) + 
  ylim(0, 20) +
  labs(x = "Ethnicity", y = "Average predicted survival time") +
  theme_bw() +
  scale_color_manual(values=c(majc, minc), name="Ethnicity") +
  geom_text(x=0.7, y=19, label="B", size=10, color="black") +
  theme(axis.title=element_text(face="bold"),
        legend.position = "none") -> plot5b

Combined: plot 4

plot5 <- ggarrange(plot5a, plot5b, ncol = 2, nrow=1, widths=c(1,1))

plot5

plot5a$data # predicted survival time by gender
## # A tibble: 2 x 4
##   gender   fit upper lower
##   <fct>  <dbl> <dbl> <dbl>
## 1 men     15.8  16.3  15.3
## 2 women   13.0  13.6  12.5
plot5b$data # predicted survival time by ethnicity
## # A tibble: 2 x 4
##   ethnicity   fit upper lower
##   <fct>     <dbl> <dbl> <dbl>
## 1 majority  14.7   15.2 14.3 
## 2 minority   9.35  10.7  8.16

Figure 6: Gender * cohort

Here, I check the predicted values based on model 3. I found that the predicted values based on the full model were extreme in some cases. By adding the variables in model 3 one by one, I check which variables lead to large deviations from normal predicted values. Inclusion of university, field, cohort and veni leads to a small percentage of unrealistic predicted values, while previous publications seems to add quite a few.

M4 %>% predict(type="response", conf.int=TRUE, conf.level=.95, newdata=df_ppf3) -> p6


plot7 <- plot6 <- as.data.frame(p6) # same data for plot 5 and 6

# excluding gender = missing from the plot
plot6$gender <- df_ppf3$gender
plot6$cohort <- df_ppf3$phd_cohort
plot6 <- plot6[plot6$gender!="missing",]

plot6 %>%
  group_by(gender, cohort) %>%
  summarise(fit = mean(.pred_time),
            upper = mean(.pred_upper), 
            lower = mean(.pred_lower)) -> plot6


# transform back to years for easier interpretability
plot6$phdyear <- plot6$cohort + 1990

ggplot(plot6, aes(x=as.factor(phdyear), y=fit, color=gender)) +
  geom_boxplot(lwd=.6, position="dodge") +
  geom_errorbar(aes(ymin=lower, ymax=upper), lwd=.7, position="dodge") +
  labs(x = "PhD year", y = "Average predicted survival time") +
  theme_bw() +
  scale_x_discrete(labels = c("1990", c(rep(" ", 4)), "1995", c(rep(" ", 4)), "2000", c(rep(" ", 4)), "2005", c(rep(" ", 4)), "2010", c(rep(" ", 4)), "2015", c(rep("", 2)), "2018")) +
  scale_color_manual(values=c(men=menc,women=womenc), name="Gender") +
  theme(axis.title=element_text(face="bold"), legend.title=element_text(face="bold"))

Figure 7: Ethnicity * cohort

# excluding ethnicity = other from the plot
plot7$ethnicity <- df_ppf3$ethnicity2
plot7$cohort <- df_ppf3$phd_cohort
plot7 <- plot7[plot7$ethnicity!="other",]

plot7 %>%
  group_by(ethnicity, cohort) %>%
  summarise(fit = mean(.pred_time),
            upper = mean(.pred_upper), 
            lower = mean(.pred_lower)) -> plot7

# transform back to years for better interpretability
plot7$phdyear <- plot7$cohort + 1990

ggplot(plot7, aes(x=as.factor(phdyear), y=fit, color=ethnicity)) +
  geom_boxplot(lwd=.6, position="dodge") +
  geom_errorbar(aes(ymin=lower, ymax=upper), lwd=.7, position="dodge") +
  labs(x = "PhD year", y = "Average predicted survival time") +
  theme_bw() +
  scale_color_manual(values=c(majority=majc, minority=minc), name="Ethnicity") +
  scale_x_discrete(labels = c("1990", c(rep(" ", 4)), "1995", c(rep(" ", 4)), "2000", c(rep(" ", 4)), "2005", c(rep(" ", 4)), "2010", c(rep(" ", 4)), "2015", c(rep("", 2)), "2018")) +
  theme(axis.title=element_text(face="bold"), legend.title=element_text(face="bold"))

LS0tDQp0aXRsZTogIkZpZ3VyZXMiDQpkYXRlOiAiTGFzdCBjb21waWxlZCBvbiBgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVCLCAlWScpYCINCm91dHB1dDogDQogIGh0bWxfZG9jdW1lbnQ6DQogICAgY3NzOiB0d2Vha3MuY3NzDQogICAgdG9jOiAgdHJ1ZQ0KICAgIHRvY19mbG9hdDogdHJ1ZQ0KICAgIG51bWJlcl9zZWN0aW9uczogZmFsc2UNCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICANCi0tLQ0KDQoNClRoaXMgbGFiIGpvdXJuYWwgcmVwbGljYXRlcyB0aGUgYW5hbHlzZXMgZm9yICdzdGFydGluZyB0byBwdWJsaXNoJy4gDQogIA0KDQotLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFLCByZXN1bHRzPSJoaWRlIn0gDQprbml0cjo6b3B0c19jaHVuayRzZXQod2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UpIA0KYGBgDQoNCg0KYGBge3IsIGVjaG89RkFMU0V9DQoNCnJtKGxpc3QgPSBscygpKQ0KDQpgYGANCg0KDQoNCiMgQ3VzdG9tIGZ1bmN0aW9ucw0KDQotIGBmcGFja2FnZS5jaGVja2A6IENoZWNrIGlmIHBhY2thZ2VzIGFyZSBpbnN0YWxsZWQgKGFuZCBpbnN0YWxsIGlmIG5vdCkgaW4gUiAoW3NvdXJjZV0oaHR0cHM6Ly92YmFsaWdhLmdpdGh1Yi5pby92ZXJpZnktdGhhdC1yLXBhY2thZ2VzLWFyZS1pbnN0YWxsZWQtYW5kLWxvYWRlZC8pKS4gIA0KDQoNCmBgYHtyLCByZXN1bHRzPSdoaWRlJ30NCg0KZnBhY2thZ2UuY2hlY2sgPC0gZnVuY3Rpb24ocGFja2FnZXMpIHsNCiAgbGFwcGx5KHBhY2thZ2VzLCBGVU4gPSBmdW5jdGlvbih4KSB7DQogICAgaWYgKCFyZXF1aXJlKHgsIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkpIHsNCiAgICAgIGluc3RhbGwucGFja2FnZXMoeCwgZGVwZW5kZW5jaWVzID0gVFJVRSkNCiAgICAgIGxpYnJhcnkoeCwgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKQ0KICAgIH0NCiAgfSkNCn0NCg0KZnNhdmUgPC0gZnVuY3Rpb24oeCwgZmlsZSwgbG9jYXRpb249Ii4vZGF0YS9wcm9jZXNzZWQvIikgew0KICBkYXRlbmFtZSA8LSBzdWJzdHIoZ3N1YigiWzotXSIsICIiLCBTeXMudGltZSgpKSwgMSw4KSAgDQogIHRvdGFsbmFtZSA8LSBwYXN0ZShsb2NhdGlvbiwgZGF0ZW5hbWUsIGZpbGUsIHNlcD0iIikNCiAgc2F2ZSh4LCBmaWxlID0gdG90YWxuYW1lKSAgDQp9DQoNCg0KDQpgYGANCg0KDQotLS0gIA0KDQojIFBhY2thZ2VzDQoNCi0gYHRpZHl2ZXJzZWA6IGZvciBkYXRhIG1hbmlwdWxhdGlvbg0KLSBgZ2dwbG90MmA6IGZvciBjcmVhdGluZyBmaWd1cmVzIDItNA0KLSBgZ2dwdWJyYDogZm9yIGNvbWJpbmluZyB0d28gZmlndXJlcyBpbiBvbmUgKHBsb3QgMikNCi0gYHNwbGluZXNgIGBzcGxpbmVzMmA6IGZvciBtb2RlbGxpbmcgbm9uLWxpbmVhciBjb2hvcnQgcmVsYXRpb25zDQoNCg0KYGBge3IsIHJlc3VsdHM9J2hpZGUnfQ0KDQpwYWNrYWdlcyA9IGMoInRpZHl2ZXJzZSIsICJnZ3Bsb3QyIiwgImdncHViciIsICJzcGxpbmVzIiwgInNwbGluZXMyIikNCg0KZnBhY2thZ2UuY2hlY2socGFja2FnZXMpDQoNCmBgYA0KDQoNCg0KDQojIElucHV0DQoNCg0KV2UgdXNlIHR3byBwcm9jZXNzZWQgZGF0YXNldHM6DQoNCiogW2RmX3N0YXJ0aW5nLnJkYV0oImh0dHBzOi8vZ2l0aHViLmNvbS9hbW11bGRlcnMvYW1hdHRlcm9mdGltZS9kYXRhL3Byb2Nlc3NlZC9kZl9zdGFydGluZy5yZGEiKTogZGF0YXNldCBvZiBQaERzIHdpdGggYWxsIHJlbGV2YW50IHZhcmlhYmxlczogZ2VuZGVyICsgZXRobmljaXR5ICsgdW5pdmVyc2l0eSArIFBoRCB5ZWFyICANCiAgICAtIEZvciBjb25zdHJ1Y3Rpb24gb2YgdGhpcyBkYXRhc2V0IHNlZSBbRGVwZW5kZW50IFZhcmlhYmxlcyA6IFN0YXJ0aW5nIGFuZCBTdG9wcGluZyB0byBQdWJsaXNoXShkYXRhcHJlcGFyYXRpb24uaHRtbCkgIA0KICAgIC0gbmFtZSBvZiBkYXRhc2V0OiBgZGZfc3RhcnRpbmdgIA0KICAgIA0KKiBbZGZfc3RvcHBpbmcucmRhXSgiaHR0cHM6Ly9naXRodWIuY29tL2FtbXVsZGVycy9hbWF0dGVyb2Z0aW1lL2RhdGEvcHJvY2Vzc2VkL2RmX3N0b3BwaW5nLnJkYSIpOiBwZXJzb24tcGVyaW9kIGZpbGUgY29udGFpbmluZyBwdWJsaWNhdGlvbnMgYW5kIGFsbCByZWxldmFudCB2YXJpYWJsZXMgZm9yIHRoZSBzdXJ2aXZhbCBtb2RlbHMsIHRpbWUgd2luZG93IGZvciBpbmFjdGl2aXR5IGlzIDMgeWVhcnMNCiAgICAtIEZvciBjb25zdHJ1Y3Rpb24gb2YgdGhpcyBkYXRhc2V0IHNlZSBbRGVwZW5kZW50IFZhcmlhYmxlcyA6IFN0YXJ0aW5nIGFuZCBTdG9wcGluZyB0byBQdWJsaXNoXShkYXRhcHJlcGFyYXRpb24uaHRtbCkNCiAgICAtIG5hbWUgb2YgZGF0YXNldDogYGRmX3BwZjNgIA0KDQoNCkZ1cnRoZXJtb3JlLCB3ZSBsb2FkIGluIHRoZSByZXN1bHRzIGZyb20gb3VyIGFuYWx5c2VzIHRvIGNyZWF0ZSBmaWd1cmVzIDItNy4NCg0KDQpgYGB7ciBkYXRhfQ0KDQpsb2FkKGZpbGUgPSAiLi9kYXRhL3Byb2Nlc3NlZC9kZl9zdGFydGluZy5yZGEiKQ0KDQpsb2FkKGZpbGUgPSAiLi9kYXRhL3Byb2Nlc3NlZC9kZl9zdG9wcGluZy5yZGEiKQ0KDQoNCmBgYA0KDQoNCi0tLQ0KDQoNCkRlZmluaW5nIGNvbG9yIHBhcmFtZXRlcnMgdXAgZnJvbnQNCg0KYGBge3J9DQoNCnRvdCA8LSAiIzQxNDE0MSINCm1lbmMgPC0gIiNEMUMxNjYiDQp3b21lbmMgPC0gIiM0OGEzNjMiDQptYWpjIDwtICIjMzk4MzlEIg0KbWluYyA8LSAiI0I4NTA0MiINCg0KDQpgYGANCg0KDQoNCiMgRmlndXJlIDENCg0KTnVtYmVyIG9mIFBoRHMgZW50ZXJpbmcgdGhlIHNhbXBsZSBwZXIgY29ob3J0LCBzcGxpdCBvdXQgYnkgZ2VuZGVyIGFuZCBldGhuaWNpdHkNCg0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCg0KZGZfc3RhcnRpbmcgJT4lDQogIGdyb3VwX2J5KHBoZF95ZWFyKSAlPiUNCiAgY291bnQoKSAtPiB0b3RhbGVudHJ5DQoNCmRmX3N0YXJ0aW5nICU+JQ0KICBncm91cF9ieShwaGRfeWVhcikgJT4lDQogIGNvdW50KGdlbmRlcikgLT4gZ2VuZGVyZW50cnkNCg0KZGZfc3RhcnRpbmcgJT4lDQogIGdyb3VwX2J5KHBoZF95ZWFyKSAlPiUNCiAgY291bnQoZXRobmljaXR5MikgLT4gZXRobmllbnRyeQ0KDQpnZW5kZXJlbnRyeSA8LSBnZW5kZXJlbnRyeVtnZW5kZXJlbnRyeSRnZW5kZXIhPSJtaXNzaW5nIixdDQoNCmV0aG5pZW50cnkgPC0gZXRobmllbnRyeVtldGhuaWVudHJ5JGV0aG5pY2l0eTIhPSJvdGhlciIsXQ0KDQoNCmdlbmRlcmVudHJ5JHR5cGUgPC0gYXMuY2hhcmFjdGVyKGdlbmRlcmVudHJ5JGdlbmRlcikNCmdlbmRlcmVudHJ5IDwtIGdlbmRlcmVudHJ5WywtMl0NCg0KDQpldGhuaWVudHJ5JHR5cGUgPC0gYXMuY2hhcmFjdGVyKGV0aG5pZW50cnkkZXRobmljaXR5MikNCmV0aG5pZW50cnkgPC0gZXRobmllbnRyeVssLTJdDQoNCnRvdGFsZW50cnkkdHlwZSA8LSByZXAoInRvdGFsIiwgdGltZXM9bnJvdyh0b3RhbGVudHJ5KSkNCg0KZW50cnlfZGYgPC0gcmJpbmQuZGF0YS5mcmFtZSh0b3RhbGVudHJ5LCBnZW5kZXJlbnRyeSwgZXRobmllbnRyeSkNCg0KZW50cnlfZGYkdHlwZSA8LSBpZmVsc2UoZW50cnlfZGYkdHlwZT09Im1pbm9yaXR5IiwgImV0aG5pYyBtaW5vcml0eSIsIGVudHJ5X2RmJHR5cGUpDQplbnRyeV9kZiR0eXBlIDwtIGlmZWxzZShlbnRyeV9kZiR0eXBlPT0ibWFqb3JpdHkiLCAiZXRobmljIG1ham9yaXR5IiwgZW50cnlfZGYkdHlwZSkNCg0KDQpnZ3Bsb3QoZW50cnlfZGYsIGFlcyh5PW4sIHg9cGhkX3llYXIsIGNvbG9yPWZhY3Rvcih0eXBlLCBsZXZlbHM9YygidG90YWwiLCAibWVuIiwgIndvbWVuIiwgImV0aG5pYyBtYWpvcml0eSIsICJldGhuaWMgbWlub3JpdHkiKSkpKSArDQogIGdlb21fbGluZShsd2QgPSAwLjgpKw0KICB0aGVtZV9idygpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKDE5OTAsMTk5NSwyMDAwLDIwMDUsMjAxMCwyMDE1LDIwMTkpKSsNCiAgbGFicyh4ID0gIlllYXIgb2YgZG9jdG9yYXRlIHJlY2VpcHQiLCB5ID0gIkZyZXF1ZW5jeSIpICsNCiAgdGhlbWUoYXhpcy50aXRsZT1lbGVtZW50X3RleHQoZmFjZT0iYm9sZCIpKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9Yyh0b3QsIG1lbmMsIHdvbWVuYywgbWFqYywgbWluYyksIG5hbWU9Ikdyb3VwIikNCg0KDQpgYGANCg0KDQpgYGB7cn0NCg0KZ2dzYXZlKCIuL291dHB1dC9zdGFydGluZy9wbG90MS5qcGciLCBoZWlnaHQ9NCwgd2lkdGg9OCwgZHBpPTEyMDApDQoNCmBgYA0KDQoNCg0KDQojIEZpZ3VyZSAyIA0KDQoNCiMjIExvYWRpbmcgaW4gcmVzdWx0cyBmb3IgJ3N0YXJ0aW5nIHRvIHB1Ymxpc2gnDQoNCmBgYHtyfQ0KDQpsb2FkKGZpbGUgPSAicmVzdWx0cy9zdGFydGluZy8yMDIzMDQwNU0xLnJkYSIpDQpNMSA8LSB4DQpybSh4KQ0KDQpsb2FkKGZpbGUgPSAicmVzdWx0cy9zdGFydGluZy8yMDIzMDQwNU0yLnJkYSIpDQpNMiA8LSB4DQpybSh4KQ0KDQpsb2FkKGZpbGUgPSAicmVzdWx0cy9zdGFydGluZy8yMDIzMDQwNU0zLnJkYSIpDQpNMyA8LSB4DQpybSh4KQ0KDQpsb2FkKGZpbGUgPSAicmVzdWx0cy9zdGFydGluZy8yMDIzMDQwNU00LnJkYSIpDQpNNCA8LSB4DQpybSh4KQ0KDQoNCmBgYA0KDQoNCg0KIyMgRmlndXJlIDJhOiBnZW5kZXIgb25seQ0KDQpgYGB7cn0NCg0KIyBDYWxjdWxhdGluZyBwcmVkaWN0ZWQgcHJvYmFiaWxpdGllcw0KTTEgJT4lIHByZWRpY3QoZGZfc3RhcnRpbmcsIHR5cGU9ImxpbmsiLCBzZS5maXQgPSBUUlVFKSAtPiBwbG90MmENCg0KDQojIGNhbGN1bGF0ZSB1cHBlciBhbmQgbG93ZXIgYm91bmRzIGZvciB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbHMNCnBsb3QyYSR1cHBlciA8LSBwbG90MmEkZml0ICsgKDEuOTYgKiBwbG90MmEkc2UuZml0KQ0KcGxvdDJhJGxvd2VyIDwtIHBsb3QyYSRmaXQgLSAoMS45NiAqIHBsb3QyYSRzZS5maXQpDQoNCnBsb3QyYSA8LSBhcy5kYXRhLmZyYW1lKHBsb3QyYSkNCg0KIyBleGNsdWRpbmcgZ2VuZGVyID0gbWlzc2luZyBmcm9tIHRoZSBwbG90DQpwbG90MmEkZ2VuZGVyIDwtIGRmX3N0YXJ0aW5nJGdlbmRlcg0KcGxvdDJhIDwtIHBsb3QyYVtwbG90MmEkZ2VuZGVyIT0ibWlzc2luZyIsXQ0KDQoNCnBsb3QyYSAlPiUNCiAgZ3JvdXBfYnkoZ2VuZGVyKSAlPiUNCiAgc3VtbWFyaXNlKGZpdCA9IHBsb2dpcyhtZWFuKGZpdCkpLCANCiAgICAgICAgICAgIHVwcGVyID0gcGxvZ2lzKG1lYW4odXBwZXIpKSwgDQogICAgICAgICAgICBsb3dlciA9IHBsb2dpcyhtZWFuKGxvd2VyKSkpIC0+IHBsb3QyYQ0KDQoNCmdncGxvdChwbG90MmEsYWVzKGdlbmRlcixmaXQsICBjb2xvcj0oZ2VuZGVyKSkpKw0KICBnZW9tX2JveHBsb3Qod2lkdGggPSAuMSkgKw0KICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluID0gbG93ZXIsIHltYXggPSB1cHBlciksIGx3ZCA9IDAuOCwgd2lkdGggPSAuMDUpICsgeWxpbSgwLCAwLjMpICsNCiAgbGFicyh4ID0gIkdlbmRlciIsIHkgPSAiUHJvYmFiaWxpdHkgb2Ygc3RhcnRpbmcgdG8gcHVibGlzaCIpICsNCiAgdGhlbWVfYncoKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YyhtZW5jLCB3b21lbmMpLCBuYW1lPSJHZW5kZXIiKSArDQogIGdlb21fdGV4dCh4PTAuNSwgeT0wLjI4LCBsYWJlbD0iQSIsIHNpemU9MTAsIGNvbG9yPSJibGFjayIpKw0KICB0aGVtZShheGlzLnRpdGxlPWVsZW1lbnRfdGV4dChmYWNlPSJib2xkIiksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgLT4gcGxvdDJhDQoNCg0KIyBFeGFjdCBnZW5kZXIgZGlmZmVyZW5jZXMgaW4gcHJvYmFiaWxpdHkgb2Ygc3RhcnRpbmcgdG8gcHVibGlzaA0KcGxvdDJhJGRhdGENCg0KYGBgDQoNCg0KIyMgRmlndXJlIDJiOiBldGhuaWNpdHkgb25seQ0KDQoNCmBgYHtyfQ0KDQojIENhbGN1bGF0aW5nIHByZWRpY3RlZCBwcm9iYWJpbGl0aWVzDQpNMiAlPiUgcHJlZGljdChkZl9zdGFydGluZywgdHlwZSA9ICJsaW5rIiwgc2UuZml0ID0gVFJVRSkgLT4gcGxvdDJiDQoNCg0KIyBDYWxjdWxhdGluZyBjb25maWRlbmNlIGludGVydmFscw0KcGxvdDJiJHVwcGVyIDwtIHBsb3QyYiRmaXQgKyAoMS45NiAqIHBsb3QyYiRzZS5maXQpDQpwbG90MmIkbG93ZXIgPC0gcGxvdDJiJGZpdCAtICgxLjk2ICogcGxvdDJiJHNlLmZpdCkNCg0KcGxvdDJiIDwtIGFzLmRhdGEuZnJhbWUocGxvdDJiKQ0KcGxvdDJiJGV0aG5pY2l0eTIgPC0gZGZfc3RhcnRpbmckZXRobmljaXR5Mg0KDQojIFJlbW92aW5nIGV0aG5pY2l0eSAnb3RoZXInIGZyb20gcGxvdA0KcGxvdDJiIDwtIHBsb3QyYltwbG90MmIkZXRobmljaXR5MiE9Im90aGVyIixdDQoNCg0KcGxvdDJiICU+JQ0KICBncm91cF9ieShldGhuaWNpdHkyKSAlPiUNCiAgc3VtbWFyaXNlKGZpdCA9IHBsb2dpcyhtZWFuKGZpdCkpLCANCiAgICAgICAgICAgIHVwcGVyID0gcGxvZ2lzKG1lYW4odXBwZXIpKSwgDQogICAgICAgICAgICBsb3dlciA9IHBsb2dpcyhtZWFuKGxvd2VyKSkpIC0+IHBsb3QyYg0KDQpnZ3Bsb3QocGxvdDJiLGFlcyhhcy5mYWN0b3IoZXRobmljaXR5MiksZml0LCAgY29sb3I9KGV0aG5pY2l0eTIpKSkrDQogIGdlb21fYm94cGxvdCh3aWR0aCA9IC4xKSArDQogIGdlb21fZXJyb3JiYXIoYWVzKHltaW4gPSBsb3dlciwgeW1heCA9IHVwcGVyKSwgbHdkID0gMC44LCB3aWR0aCA9IC4wNSkgKyB5bGltKDAsIDAuMykgKw0KICBsYWJzKHggPSAiRXRobmljaXR5IiwgeSA9ICJQcm9iYWJpbGl0eSBvZiBzdGFydGluZyB0byBwdWJsaXNoIikgKw0KICB0aGVtZV9idygpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKG1hamMsIG1pbmMpLCBuYW1lPSJFdGhuaWNpdHkiKSArDQogIGdlb21fdGV4dCh4PTAuNSwgeT0wLjI4LCBsYWJlbD0iQiIsIHNpemU9MTAsIGNvbG9yPSJibGFjayIpICsNCiAgdGhlbWUoYXhpcy50aXRsZT1lbGVtZW50X3RleHQoZmFjZT0iYm9sZCIpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpIC0+IHBsb3QyYg0KDQoNCiMgRXhhY3QgZXRobmljIGRpZmZlcmVuY2VzIGluIHByb2JhYmlsaXR5IG9mIHN0YXJ0aW5nIHRvIHB1Ymxpc2gNCnBsb3QyYiRkYXRhDQoNCg0KYGBgDQoNCg0KDQojIyBGaWd1cmUgMjogY29tYmluaW5nIEEgYW5kIEINCg0KDQpgYGB7ciwgZmlnLndpZHRoPTh9DQoNCnBsb3QyIDwtIGdnYXJyYW5nZShwbG90MmEsIHBsb3QyYiwgbmNvbCA9IDIsIG5yb3c9MSkNCg0KcGxvdDINCg0KYGBgDQoNCmBgYHtyLCBldmFsPUZBTFNFLCBlY2hvPUZBTFNFfQ0KDQpnZ3NhdmUoIi4vb3V0cHV0L3N0YXJ0aW5nL3Bsb3QyLmpwZyIsIGhlaWdodD00LCB3aWR0aD04LCBkcGk9MTIwMCkNCg0KYGBgDQoNCg0KDQoNCiMgRmlndXJlIDMNCg0KUHJlZGljdGVkIHByb2JhYmlsaXR5IHRvIHN0YXJ0IGJ5IGdlbmRlciBhbmQgY29ob3J0DQoNCg0KYGBge3J9DQoNCnBsb3Q0IDwtIHBsb3QzIDwtIE00ICU+JSBwcmVkaWN0KGRmX3N0YXJ0aW5nLCB0eXBlPSJsaW5rIiwgc2UuZml0PVRSVUUpDQoNCnBsb3QzIDwtIGFzLmRhdGEuZnJhbWUocGxvdDMpDQoNCnBsb3QzJGdlbmRlciA8LSBkZl9zdGFydGluZyRnZW5kZXINCnBsb3QzJHBoZF9jb2hvcnQgPC0gZGZfc3RhcnRpbmckcGhkX2NvaG9ydA0KDQpwbG90MyA8LSBwbG90M1twbG90MyRnZW5kZXIhPSJtaXNzaW5nIixdDQoNCnBsb3QzJHVwcGVyIDwtIHBsb3QzJGZpdCArICgxLjk2ICogcGxvdDMkc2UuZml0KQ0KcGxvdDMkbG93ZXIgPC0gcGxvdDMkZml0IC0gKDEuOTYgKiBwbG90MyRzZS5maXQpDQoNCg0KcGxvdDMgJT4lDQogIGdyb3VwX2J5KGdlbmRlciwgcGhkX2NvaG9ydCkgJT4lDQogIHN1bW1hcmlzZShmaXQgPSBwbG9naXMobWVhbihmaXQpKSwgDQogICAgICAgICAgICB1cHBlciA9IHBsb2dpcyhtZWFuKHVwcGVyKSksIA0KICAgICAgICAgICAgbG93ZXIgPSBwbG9naXMobWVhbihsb3dlcikpKSAtPiBwbG90Mw0KDQoNCiMgdHJhbnNmb3JtIGJhY2sgdG8geWVhcnMgZm9yIGVhc2llciBpbnRlcnByZXRhYmlsaXR5DQpwbG90MyRwaGR5ZWFyIDwtIHBsb3QzJHBoZF9jb2hvcnQrMTk5MA0KDQoNCmdncGxvdChwbG90MywgYWVzKHg9YXMuZmFjdG9yKHBoZHllYXIpLCB5PWZpdCwgY29sb3I9Z2VuZGVyKSkgKw0KICBnZW9tX2JveHBsb3QobHdkPS42LCBwb3NpdGlvbj0iZG9kZ2UiKSArDQogIGdlb21fZXJyb3JiYXIoYWVzKHltaW49bG93ZXIsIHltYXg9dXBwZXIpLCBsd2Q9LjcsIHBvc2l0aW9uPSJkb2RnZSIpICsNCiAgeWxpbSgwLCAwLjMpICsNCiAgbGFicyh4ID0gIlBoRCB5ZWFyIiwgeSA9ICJQcm9iYWJpbGl0eSBvZiBzdGFydGluZyB0byBwdWJsaXNoIikgKw0KICB0aGVtZV9idygpICsNCiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHMgPSBjKCIxOTkwIiwgYyhyZXAoIiAiLCA0KSksICIxOTk1IiwgYyhyZXAoIiAiLCA0KSksICIyMDAwIiwgYyhyZXAoIiAiLCA0KSksICIyMDA1IiwgYyhyZXAoIiAiLCA0KSksICIyMDEwIiwgYyhyZXAoIiAiLCA0KSksICIyMDE1IiwgYyhyZXAoIiIsIDMpKSwgIjIwMTkiKSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMobWVuPW1lbmMsd29tZW49d29tZW5jKSwgbmFtZT0iR2VuZGVyIikgKw0KICB0aGVtZShheGlzLnRpdGxlPWVsZW1lbnRfdGV4dChmYWNlPSJib2xkIiksIGxlZ2VuZC50aXRsZT1lbGVtZW50X3RleHQoZmFjZT0iYm9sZCIpKQ0KDQpgYGANCg0KDQpgYGB7ciwgZXZhbD1GQUxTRSwgZWNobz1GQUxTRX0NCg0KZ2dzYXZlKCIuL291dHB1dC9zdGFydGluZy9wbG90My5qcGciLCBoZWlnaHQ9NSwgd2lkdGg9OCwgZHBpPTEyMDApDQoNCmBgYA0KDQoNCg0KIyBGaWd1cmUgNA0KDQpQcmVkaWN0ZWQgcHJvYmFiaWxpdHkgdG8gc3RhcnQgYnkgZXRobmljaXR5IGFuZCBjb2hvcnQNCg0KDQpgYGB7cn0NCg0KcGxvdDQgPC0gYXMuZGF0YS5mcmFtZShwbG90NCkNCg0KcGxvdDQkZXRobmljaXR5MiA8LSBkZl9zdGFydGluZyRldGhuaWNpdHkyDQpwbG90NCRwaGRfY29ob3J0IDwtIGRmX3N0YXJ0aW5nJHBoZF9jb2hvcnQNCg0KcGxvdDQgPC0gcGxvdDRbcGxvdDQkZXRobmljaXR5MiE9Im90aGVyIixdDQoNCnBsb3Q0JHVwcGVyIDwtIHBsb3Q0JGZpdCArICgxLjk2ICogcGxvdDQkc2UuZml0KQ0KcGxvdDQkbG93ZXIgPC0gcGxvdDQkZml0IC0gKDEuOTYgKiBwbG90NCRzZS5maXQpDQoNCg0KcGxvdDQgJT4lDQogIGdyb3VwX2J5KGV0aG5pY2l0eTIsIHBoZF9jb2hvcnQpICU+JQ0KICBzdW1tYXJpc2UoZml0ID0gcGxvZ2lzKG1lYW4oZml0KSksIA0KICAgICAgICAgICAgdXBwZXIgPSBwbG9naXMobWVhbih1cHBlcikpLCANCiAgICAgICAgICAgIGxvd2VyID0gcGxvZ2lzKG1lYW4obG93ZXIpKSkgLT4gcGxvdDQNCg0KDQojIHRyYW5zZm9ybSBiYWNrIHRvIHllYXJzIGZvciBlYXNpZXIgaW50ZXJwcmV0YWJpbGl0eQ0KcGxvdDQkcGhkeWVhciA8LSBwbG90NCRwaGRfY29ob3J0KzE5OTANCg0KDQpnZ3Bsb3QocGxvdDQsIGFlcyh4PWFzLmZhY3RvcihwaGR5ZWFyKSwgeT1maXQsIGNvbG9yPWV0aG5pY2l0eTIpKSArDQogIGdlb21fYm94cGxvdChsd2Q9LjYsIHBvc2l0aW9uPSJkb2RnZSIpICsNCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbj1sb3dlciwgeW1heD11cHBlciksIGx3ZD0uNywgcG9zaXRpb249ImRvZGdlIikgKw0KICB5bGltKDAsIDAuNSkgKw0KICBsYWJzKHggPSAiUGhEIHllYXIiLCB5ID0gIlByb2JhYmlsaXR5IG9mIHN0YXJ0aW5nIHRvIHB1Ymxpc2giKSArDQogIHRoZW1lX2J3KCkgKw0KICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IGMoIjE5OTAiLCBjKHJlcCgiICIsIDQpKSwgIjE5OTUiLCBjKHJlcCgiICIsIDQpKSwgIjIwMDAiLCBjKHJlcCgiICIsIDQpKSwgIjIwMDUiLCBjKHJlcCgiICIsIDQpKSwgIjIwMTAiLCBjKHJlcCgiICIsIDQpKSwgIjIwMTUiLCBjKHJlcCgiIiwgMykpLCAiMjAxOSIpKSArIA0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMobWFqb3JpdHk9bWFqYywgbWlub3JpdHk9bWluYyksIG5hbWU9IkV0aG5pY2l0eSIpICsNCiAgdGhlbWUoYXhpcy50aXRsZT1lbGVtZW50X3RleHQoZmFjZT0iYm9sZCIpLCBsZWdlbmQudGl0bGU9ZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiKSkNCg0KYGBgDQoNCmBgYHtyLCBldmFsPUZBTFNFLCBlY2hvPUZBTFNFfQ0KDQpnZ3NhdmUoIi4vb3V0cHV0L3N0YXJ0aW5nL3Bsb3Q0LmpwZyIsIGhlaWdodD01LCB3aWR0aD04LCBkcGk9MTIwMCkNCg0KYGBgDQoNCg0KDQoNCg0KIyBGaWd1cmUgNQ0KDQoNCiMjIExvYWRpbmcgaW4gcmVzdWx0cyBmb3IgJ3N0b3BwaW5nIHRvIHB1Ymxpc2gnDQoNCmBgYHtyfQ0KDQpsb2FkKGZpbGUgPSAicmVzdWx0cy9zdG9wcGluZy8yMDIzMDQwNU0xLnJkYSIpDQpNMSA8LSB4DQpybSh4KQ0KDQpsb2FkKGZpbGUgPSAicmVzdWx0cy9zdG9wcGluZy8yMDIzMDQwNU0yLnJkYSIpDQpNMiA8LSB4DQpybSh4KQ0KDQpsb2FkKGZpbGUgPSAicmVzdWx0cy9zdG9wcGluZy8yMDIzMDQwNU0zLnJkYSIpDQpNMyA8LSB4DQpybSh4KQ0KDQpsb2FkKGZpbGUgPSAicmVzdWx0cy9zdG9wcGluZy8yMDIzMDQwNU00LnJkYSIpDQpNNCA8LSB4DQpybSh4KQ0KDQoNCmBgYA0KDQoNClN1cnZpdmFsIHRpbWVzIGJ5IGdlbmRlciBhbmQgZXRobmljaXR5Lg0KQmFzZWQgb24gTTE6IGdlbmRlciBvbmx5Lg0KDQpgYGB7cn0NCg0KIyBDYWxjdWxhdGluZyBwcmVkaWN0ZWQgcHJvYmFiaWxpdGllcw0KTTEgJT4lIHByZWRpY3QodHlwZT0icmVzcG9uc2UiLCBjb25mLmludD1UUlVFLCBjb25mLmxldmVsPS45NSwgbmV3ZGF0YT1kZl9wcGYzKSAtPiBwbG90NWENCg0KY2xhc3MocGxvdDVhKSAgDQpwbG90NWEgPC0gYXMuZGF0YS5mcmFtZShwbG90NWEpDQoNCiMgZXhjbHVkaW5nIGdlbmRlciA9IG1pc3NpbmcgZnJvbSB0aGUgcGxvdA0KcGxvdDVhJGdlbmRlciA8LSBkZl9wcGYzJGdlbmRlcg0KcGxvdDVhIDwtIHBsb3Q1YVtwbG90NWEkZ2VuZGVyIT0ibWlzc2luZyIsXQ0KDQoNCg0KcGxvdDVhICU+JQ0KICBncm91cF9ieShnZW5kZXIpICU+JQ0KICBzdW1tYXJpc2UoZml0ID0gbWVhbigucHJlZF90aW1lKSwgDQogICAgICAgICAgICB1cHBlciA9IG1lYW4oLnByZWRfdXBwZXIpLCANCiAgICAgICAgICAgIGxvd2VyID0gbWVhbigucHJlZF9sb3dlcikpIC0+IHBsb3Q1YQ0KDQoNCmdncGxvdChwbG90NWEsYWVzKGdlbmRlciwgZml0LCAgY29sb3I9KGdlbmRlcikpKSsNCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gLjEpICsNCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbiA9IGxvd2VyLCB5bWF4ID0gdXBwZXIpLCBsd2QgPSAwLjgsIHdpZHRoID0gLjA1KSArIA0KICB5bGltKDAsIDIwKSArDQogIGxhYnMoeCA9ICJHZW5kZXIiLCB5ID0gIkF2ZXJhZ2UgcHJlZGljdGVkIHN1cnZpdmFsIHRpbWUiKSArDQogIHRoZW1lX2J3KCkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMobWVuYywgd29tZW5jKSwgbmFtZT0iR2VuZGVyIikgKw0KICBnZW9tX3RleHQoeD0wLjcsIHk9MTksIGxhYmVsPSJBIiwgc2l6ZT0xMCwgY29sb3I9ImJsYWNrIikgKw0KICB0aGVtZShheGlzLnRpdGxlPWVsZW1lbnRfdGV4dChmYWNlPSJib2xkIiksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgLT4gcGxvdDVhDQoNCnBsb3Q1YQ0KDQoNCmBgYA0KDQpCYXNlZCBvbiBNMjogZXRobmljaXR5IG9ubHkuDQoNCmBgYHtyfQ0KDQojIENhbGN1bGF0aW5nIHByZWRpY3RlZCBwcm9iYWJpbGl0aWVzDQpNMiAlPiUgcHJlZGljdCh0eXBlPSJyZXNwb25zZSIsIGNvbmYuaW50PVRSVUUsIGNvbmYubGV2ZWw9Ljk1LCBuZXdkYXRhPWRmX3BwZjMpIC0+IHBsb3Q1Yg0KICANCnBsb3Q1YiA8LSBhcy5kYXRhLmZyYW1lKHBsb3Q1YikNCg0KIyBleGNsdWRpbmcgZ2VuZGVyID0gbWlzc2luZyBmcm9tIHRoZSBwbG90DQpwbG90NWIkZXRobmljaXR5IDwtIGRmX3BwZjMkZXRobmljaXR5Mg0KcGxvdDViIDwtIHBsb3Q1YltwbG90NWIkZXRobmljaXR5IT0ib3RoZXIiLF0NCg0KcGxvdDViICU+JQ0KICBncm91cF9ieShldGhuaWNpdHkpICU+JQ0KICBzdW1tYXJpc2UoZml0ID0gbWVhbigucHJlZF90aW1lKSwgDQogICAgICAgICAgICB1cHBlciA9IG1lYW4oLnByZWRfdXBwZXIpLCANCiAgICAgICAgICAgIGxvd2VyID0gbWVhbigucHJlZF9sb3dlcikpIC0+IHBsb3Q1Yg0KDQoNCmdncGxvdChwbG90NWIsYWVzKGV0aG5pY2l0eSwgZml0LCAgY29sb3I9KGV0aG5pY2l0eSkpKSsNCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gLjEpICsNCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbiA9IGxvd2VyLCB5bWF4ID0gdXBwZXIpLCBsd2QgPSAwLjgsIHdpZHRoID0gLjA1KSArIA0KICB5bGltKDAsIDIwKSArDQogIGxhYnMoeCA9ICJFdGhuaWNpdHkiLCB5ID0gIkF2ZXJhZ2UgcHJlZGljdGVkIHN1cnZpdmFsIHRpbWUiKSArDQogIHRoZW1lX2J3KCkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMobWFqYywgbWluYyksIG5hbWU9IkV0aG5pY2l0eSIpICsNCiAgZ2VvbV90ZXh0KHg9MC43LCB5PTE5LCBsYWJlbD0iQiIsIHNpemU9MTAsIGNvbG9yPSJibGFjayIpICsNCiAgdGhlbWUoYXhpcy50aXRsZT1lbGVtZW50X3RleHQoZmFjZT0iYm9sZCIpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpIC0+IHBsb3Q1Yg0KDQoNCmBgYA0KDQpDb21iaW5lZDogcGxvdCA0DQpgYGB7cn0NCg0KcGxvdDUgPC0gZ2dhcnJhbmdlKHBsb3Q1YSwgcGxvdDViLCBuY29sID0gMiwgbnJvdz0xLCB3aWR0aHM9YygxLDEpKQ0KDQpwbG90NQ0KDQoNCnBsb3Q1YSRkYXRhICMgcHJlZGljdGVkIHN1cnZpdmFsIHRpbWUgYnkgZ2VuZGVyDQpwbG90NWIkZGF0YSAjIHByZWRpY3RlZCBzdXJ2aXZhbCB0aW1lIGJ5IGV0aG5pY2l0eQ0KDQpgYGANCg0KYGBge3IsIGV2YWw9RkFMU0UsIGVjaG89RkFMU0V9DQoNCmdnc2F2ZSgiLi9vdXRwdXQvc3RvcHBpbmcvcGxvdDVfbG9nbi5qcGciLCBoZWlnaHQ9NCwgd2lkdGg9OCwgZHBpPTEyMDApDQoNCmBgYA0KDQoNCg0KDQojIEZpZ3VyZSA2OiBHZW5kZXIgKiBjb2hvcnQNCg0KSGVyZSwgSSBjaGVjayB0aGUgcHJlZGljdGVkIHZhbHVlcyBiYXNlZCBvbiBtb2RlbCAzLiBJIGZvdW5kIHRoYXQgdGhlIHByZWRpY3RlZCB2YWx1ZXMgYmFzZWQgb24gdGhlIGZ1bGwgbW9kZWwgd2VyZSBleHRyZW1lIGluIHNvbWUgY2FzZXMuIEJ5IGFkZGluZyB0aGUgdmFyaWFibGVzIGluIG1vZGVsIDMgb25lIGJ5IG9uZSwgSSBjaGVjayB3aGljaCB2YXJpYWJsZXMgbGVhZCB0byBsYXJnZSBkZXZpYXRpb25zIGZyb20gbm9ybWFsIHByZWRpY3RlZCB2YWx1ZXMuIEluY2x1c2lvbiBvZiB1bml2ZXJzaXR5LCBmaWVsZCwgY29ob3J0IGFuZCB2ZW5pIGxlYWRzIHRvIGEgc21hbGwgcGVyY2VudGFnZSBvZiB1bnJlYWxpc3RpYyBwcmVkaWN0ZWQgdmFsdWVzLCB3aGlsZSBwcmV2aW91cyBwdWJsaWNhdGlvbnMgc2VlbXMgdG8gYWRkIHF1aXRlIGEgZmV3LiANCg0KYGBge3J9DQoNCk00ICU+JSBwcmVkaWN0KHR5cGU9InJlc3BvbnNlIiwgY29uZi5pbnQ9VFJVRSwgY29uZi5sZXZlbD0uOTUsIG5ld2RhdGE9ZGZfcHBmMykgLT4gcDYNCg0KDQpwbG90NyA8LSBwbG90NiA8LSBhcy5kYXRhLmZyYW1lKHA2KSAjIHNhbWUgZGF0YSBmb3IgcGxvdCA1IGFuZCA2DQoNCiMgZXhjbHVkaW5nIGdlbmRlciA9IG1pc3NpbmcgZnJvbSB0aGUgcGxvdA0KcGxvdDYkZ2VuZGVyIDwtIGRmX3BwZjMkZ2VuZGVyDQpwbG90NiRjb2hvcnQgPC0gZGZfcHBmMyRwaGRfY29ob3J0DQpwbG90NiA8LSBwbG90NltwbG90NiRnZW5kZXIhPSJtaXNzaW5nIixdDQoNCnBsb3Q2ICU+JQ0KICBncm91cF9ieShnZW5kZXIsIGNvaG9ydCkgJT4lDQogIHN1bW1hcmlzZShmaXQgPSBtZWFuKC5wcmVkX3RpbWUpLA0KICAgICAgICAgICAgdXBwZXIgPSBtZWFuKC5wcmVkX3VwcGVyKSwgDQogICAgICAgICAgICBsb3dlciA9IG1lYW4oLnByZWRfbG93ZXIpKSAtPiBwbG90Ng0KDQoNCiMgdHJhbnNmb3JtIGJhY2sgdG8geWVhcnMgZm9yIGVhc2llciBpbnRlcnByZXRhYmlsaXR5DQpwbG90NiRwaGR5ZWFyIDwtIHBsb3Q2JGNvaG9ydCArIDE5OTANCg0KZ2dwbG90KHBsb3Q2LCBhZXMoeD1hcy5mYWN0b3IocGhkeWVhciksIHk9Zml0LCBjb2xvcj1nZW5kZXIpKSArDQogIGdlb21fYm94cGxvdChsd2Q9LjYsIHBvc2l0aW9uPSJkb2RnZSIpICsNCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbj1sb3dlciwgeW1heD11cHBlciksIGx3ZD0uNywgcG9zaXRpb249ImRvZGdlIikgKw0KICBsYWJzKHggPSAiUGhEIHllYXIiLCB5ID0gIkF2ZXJhZ2UgcHJlZGljdGVkIHN1cnZpdmFsIHRpbWUiKSArDQogIHRoZW1lX2J3KCkgKw0KICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IGMoIjE5OTAiLCBjKHJlcCgiICIsIDQpKSwgIjE5OTUiLCBjKHJlcCgiICIsIDQpKSwgIjIwMDAiLCBjKHJlcCgiICIsIDQpKSwgIjIwMDUiLCBjKHJlcCgiICIsIDQpKSwgIjIwMTAiLCBjKHJlcCgiICIsIDQpKSwgIjIwMTUiLCBjKHJlcCgiIiwgMikpLCAiMjAxOCIpKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YyhtZW49bWVuYyx3b21lbj13b21lbmMpLCBuYW1lPSJHZW5kZXIiKSArDQogIHRoZW1lKGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiKSwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfdGV4dChmYWNlPSJib2xkIikpDQoNCg0KDQpgYGANCg0KDQoNCmBgYHtyLCBldmFsPUZBTFNFLCBlY2hvPUZBTFNFfQ0KDQpnZ3NhdmUoIi4vb3V0cHV0L3N0b3BwaW5nL3Bsb3Q2X2xvZ24uanBnIiwgaGVpZ2h0PTUsIHdpZHRoPTgsIGRwaT0xMjAwKQ0KDQoNCmBgYA0KDQoNCg0KDQoNCg0KIyBGaWd1cmUgNzogRXRobmljaXR5ICogY29ob3J0DQoNCmBgYHtyfQ0KDQojIGV4Y2x1ZGluZyBldGhuaWNpdHkgPSBvdGhlciBmcm9tIHRoZSBwbG90DQpwbG90NyRldGhuaWNpdHkgPC0gZGZfcHBmMyRldGhuaWNpdHkyDQpwbG90NyRjb2hvcnQgPC0gZGZfcHBmMyRwaGRfY29ob3J0DQpwbG90NyA8LSBwbG90N1twbG90NyRldGhuaWNpdHkhPSJvdGhlciIsXQ0KDQpwbG90NyAlPiUNCiAgZ3JvdXBfYnkoZXRobmljaXR5LCBjb2hvcnQpICU+JQ0KICBzdW1tYXJpc2UoZml0ID0gbWVhbigucHJlZF90aW1lKSwNCiAgICAgICAgICAgIHVwcGVyID0gbWVhbigucHJlZF91cHBlciksIA0KICAgICAgICAgICAgbG93ZXIgPSBtZWFuKC5wcmVkX2xvd2VyKSkgLT4gcGxvdDcNCg0KIyB0cmFuc2Zvcm0gYmFjayB0byB5ZWFycyBmb3IgYmV0dGVyIGludGVycHJldGFiaWxpdHkNCnBsb3Q3JHBoZHllYXIgPC0gcGxvdDckY29ob3J0ICsgMTk5MA0KDQpnZ3Bsb3QocGxvdDcsIGFlcyh4PWFzLmZhY3RvcihwaGR5ZWFyKSwgeT1maXQsIGNvbG9yPWV0aG5pY2l0eSkpICsNCiAgZ2VvbV9ib3hwbG90KGx3ZD0uNiwgcG9zaXRpb249ImRvZGdlIikgKw0KICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPWxvd2VyLCB5bWF4PXVwcGVyKSwgbHdkPS43LCBwb3NpdGlvbj0iZG9kZ2UiKSArDQogIGxhYnMoeCA9ICJQaEQgeWVhciIsIHkgPSAiQXZlcmFnZSBwcmVkaWN0ZWQgc3Vydml2YWwgdGltZSIpICsNCiAgdGhlbWVfYncoKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YyhtYWpvcml0eT1tYWpjLCBtaW5vcml0eT1taW5jKSwgbmFtZT0iRXRobmljaXR5IikgKw0KICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IGMoIjE5OTAiLCBjKHJlcCgiICIsIDQpKSwgIjE5OTUiLCBjKHJlcCgiICIsIDQpKSwgIjIwMDAiLCBjKHJlcCgiICIsIDQpKSwgIjIwMDUiLCBjKHJlcCgiICIsIDQpKSwgIjIwMTAiLCBjKHJlcCgiICIsIDQpKSwgIjIwMTUiLCBjKHJlcCgiIiwgMikpLCAiMjAxOCIpKSArDQogIHRoZW1lKGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiKSwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfdGV4dChmYWNlPSJib2xkIikpDQoNCg0KYGBgDQoNCg0KDQpgYGB7ciwgZXZhbD1GQUxTRSwgZWNobz1GQUxTRX0NCg0KZ2dzYXZlKCIuL291dHB1dC9zdG9wcGluZy9wbG90N19sb2duLmpwZyIsIGhlaWdodD01LCB3aWR0aD04LCBkcGk9MTIwMCkNCg0KDQpgYGANCg0KDQoNCg0KDQoNCg0K


Copyright © 2023