• Getting started
    • clean up
    • general custom functions
    • necessary packages
    • load data
  • Correlation matrix
  • Describing networks
    • Relational characteristics
    • Role overlap
    • Tie maintenance
    • Tie maintenance vs similarity
    • Homogeneity

Getting started

To copy the code, click the button in the upper right corner of the code-chunks.

clean up

rm(list = ls())
gc()


general custom functions

  • fpackage.check: Check if packages are installed (and install if not) in R
  • fsave: Function to save data with time stamp in correct directory
  • fload: Load R-objects under new names
  • fshowdf: Print objects (tibble / data.frame) nicely on screen in .Rmd.
  • ftheme: pretty ggplot2 theme
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/", ...) {
    if (!dir.exists(location))
        dir.create(location)
    datename <- substr(gsub("[:-]", "", Sys.time()), 1, 8)
    totalname <- paste(location, datename, file, sep = "")
    print(paste("SAVED: ", totalname, sep = ""))
    save(x, file = totalname)
}


fload <- function(fileName) {
    load(fileName)
    get(ls()[ls() != "fileName"])
}

fshowdf <- function(x, digits = 2, ...) {
    knitr::kable(x, digits = digits, "html", ...) %>%
        kableExtra::kable_styling(bootstrap_options = c("striped", "hover")) %>%
        kableExtra::scroll_box(width = "100%", height = "300px")
}

# extrafont::font_import(paths = c('C:/Users/u244147/Downloads/Jost/', prompt = FALSE))
ftheme <- function() {

    # download font at https://fonts.google.com/specimen/Jost/
    theme_minimal(base_family = "Jost") + theme(panel.grid.minor = element_blank(), plot.title = element_text(family = "Jost",
        face = "bold"), axis.title = element_text(family = "Jost Medium"), axis.title.x = element_text(hjust = 0),
        axis.title.y = element_text(hjust = 1), strip.text = element_text(family = "Jost", face = "bold",
            size = rel(0.75), hjust = 0), strip.background = element_rect(fill = "grey90", color = NA),
        legend.position = "bottom")
}


necessary packages

  • tidyverse
  • knitr: generating tables
  • kableExtra: manipulating tables
  • xtable: displaying HTML format
  • ggpubr
  • GenBinomApps: compute Clopper-Pearson confidence interval
  • reshape2
  • ggVennDiagram
packages = c("knitr", "kableExtra", "xtable", "tidyverse", "GenBinomApps", "reshape2", "ggcorrplot",
    "ggVennDiagram")
fpackage.check(packages)


load data

Load the replicated data-sets (constructed here). To load these file, adjust the filenames in the following code so that it matches the most recent version of the .RDa file you have in your ./data/processed/ folder.

You may also obtain them by downloading: Download data_nested.RDa

# list.files('./data/processed/')

# get todays date:
today <- gsub("-", "", Sys.Date())

data <- fload(paste0("./data/processed/", today, "data_nested.RDa"))


some last wrangling:

  • make Y indicate tie loss instead of tie maintenance
  • make X reflect dissimilarity instead of similarity
  • standardize embeddedness in other network layers
  • proximity levels
data$Yloss <- ifelse(data$Y == 1, 0, 1)

data$different_gender <- ifelse(data$same_gender == 1, 0, 1)
data$different_educ <- ifelse(data$sim_educ == 1, 0, 1)

data$embed.ext/3 -> data$embed.ext

data$proximity <- factor(data$proximity, levels = c("far", "close", "roommate"))


Correlation matrix

#get variables of interest, for which we want to calculate correlations
cordf <- data[, rev(c("dif_age","different_gender","different_educ","closeness.t","multiplex", "embed", "embed.ext", "Yloss", "tie"))]

#relabel
names(cordf) <- c("Tie", "Tie loss", "Str. embed. other layers",  "Str. embed. focal layer", "Relational multiplexity", "Emotional closeness", "Different education", "Different gender", "Age difference")

#reorder
desired_order <- rev(c("Tie", "Tie loss", "Different gender", "Different education", "Age difference", "Emotional closeness",  "Relational multiplexity", "Str. embed. focal layer", "Str. embed. other layers"))
cordf <- cordf[, desired_order]

#1. correlations of all observations (regardless of tie type)
all <- cordf[,sapply(cordf, is.numeric)]
#correlation
cormat <- cor(all)
#p value
pmat <- cor_pmat(all)
#below diagonal
cormat[lower.tri(cormat)] <- NA
pmat[lower.tri(pmat)] <- NA
#melt
allc <- melt(cormat)
allp <- melt(pmat)
all <- cbind(allc, pval = allp$value)
#diagonal NA
all$value <- ifelse(all$Var1 == all$Var2, NA, all$value)
all$pval <- ifelse(all$Var1 == all$Var2, NA, all$pval)
#add label
all$label <- ifelse(!is.na(all$value), paste0(format(round(all$value,2), nsmall=2), ifelse(all$pval>0.05, "", "*")),NA)

plot_all <- all %>% 
  ggplot(aes(Var1, Var2, fill = value)) +
  geom_tile (color = 'lightgrey') +
  geom_text(aes(label = label), size = 4) +
  scale_fill_gradient2(low = "blue", mid = "white", high="red", midpoint=0, limit=c(-1,1), na.value = "lightgrey") +
  scale_x_discrete(limits = rev(levels(all$Var1))) +  #reverse x-axis
  theme(axis.text.x = element_text(angle = 45, hjust = 1), legend.position = "right", legend.direction="horizontal") + labs(x=NULL, y=NULL, title="(A) All alter-tie observations", fill = "Correlation") 

#2 now, disaggregated by tie type
# function to compute correlations for a tie type and add the necessary columns
fcompcorr <- function(tie_type) { 
  df <- cordf[cordf$Tie == tie_type, sapply(cordf, is.numeric)]
  cormat <- cor(df)
  pmat <- cor_pmat(df)
  cormat[lower.tri(cormat)] <- NA
  pmat[lower.tri(pmat)] <- NA
  cormat_melted <- melt(cormat)
  pmat_melted <- melt(pmat)
  df <- cbind(cormat_melted, pval = pmat_melted$value)
  df$value <- ifelse(df$Var1 == df$Var2, NA, df$value)
  df$pval <- ifelse(df$Var1 == df$Var2, NA, df$pval)
  df$label <- ifelse(!is.na(df$value), paste0(format(round(df$value, 2), nsmall = 2), ifelse(df$pval > 0.05, "", "*")), NA)
  df$group <- tie_type
  return(df)
}

tie_types <- c("Confidant", "Friend", "Sport", "Study")

#empty df
mycors <- data.frame()

#iterate through tie types and compute correlations
for (i in tie_types) {
  mycors <- rbind(mycors, fcompcorr(i))
}

#relabel...
mycors$group[mycors$group == "Friend"] <- "Best friend"

plot_dis <- mycors %>% 
  ggplot(aes(Var1, Var2, fill = value)) +
  geom_tile (color = 'lightgrey') +
  geom_text(aes(label = label), size = 2.5) +
  scale_fill_gradient2(low = "blue", mid = "white", high="red", midpoint=0, limit=c(-1,1), na.value = "lightgrey") +
  scale_x_discrete(limits = rev(levels(all$Var1))) +
  theme(axis.text.x = element_text(angle = 90, hjust = 1), legend.position = "none") + labs(x=NULL, y=NULL,
                                                                                            title="(B) Disaggregated by social role", fill = "Correlation") +
  facet_grid(~group)

#now, disaggregated by combination tie type * uni vs multiplex
#keep for appendix...
fcompcorr2 <- function(tie_type) {
  df <- cordf[cordf$Tie == tie_type, sapply(cordf, is.numeric)]
  
  #uniplex below diagonal
  dfuni <- df[df$`Relational multiplexity`==0,]
  cormat1 <- cor(dfuni)
  pmat1 <- cor_pmat(dfuni)

  #multiplex above diagonal
  dfmulti <- df[df$`Relational multiplexity`>0,]
  cormat2 <- cor(dfmulti)
  pmat2 <- cor_pmat(dfmulti)
  cormat <- cormat1
  pmat <- pmat1
  
  cormat[upper.tri(cormat)] <- cormat2[upper.tri(cormat2)]
  pmat[upper.tri(pmat)] <- pmat2[upper.tri(pmat2)]
  cormat_melted <- melt(cormat)
  pmat_melted <- melt(pmat)
  df <- cbind(cormat_melted, pval = pmat_melted$value)
  df$value <- ifelse(df$Var1 == df$Var2, NA, df$value)
  df$pval <- ifelse(df$Var1 == df$Var2, NA, df$pval)
  df$label <- ifelse(!is.na(df$value), paste0(format(round(df$value, 2), nsmall = 2), ifelse(df$pval > 0.05, "", "*")), NA)
  df$group <- tie_type

  return(df)
}
  
#empty df
mycors <- data.frame()

#iterate through tie types and compute correlations
for (i in tie_types) {
  mycors <- rbind(mycors, fcompcorr2(i))
}

mycors$group[mycors$group == "Friend"] <- "Best friend"


plot_dis2 <- mycors %>% 
  ggplot(aes(Var1, Var2, fill = value)) +
  geom_tile (color = 'lightgrey') +
  geom_text(aes(label = label), size = 2.5) +
  scale_fill_gradient2(low = "blue", mid = "white", high="red", midpoint=0, limit=c(-1,1), na.value = "lightgrey") +
  scale_x_discrete(limits = rev(levels(all$Var1))) +
  theme(axis.text.x = element_text(angle = 90, hjust = 1), legend.position = "none") + labs(x=NULL, y=NULL,
                                                                                            title="(C) Multiplex alters (above diagonal) vs. uniplex alters (below diagonal)", fill = "Correlation") +
  facet_grid(~group)

#figure <- ggpubr::ggarrange(plot_all, plot_dis, ncol=1, nrow=2)

#ggsave(figure, 
#       file = "./figures/corplot.png",
#       dpi = 320, 
#       width = 11,
#       height = 8)

plot_all

plot_dis

plot_dis2



Describing networks

Relational characteristics

at wave 1

cdn <- data[data$tie == "Confidant" & data$period == "w1 -> w2", ]
bff <- data[data$tie == "Friend" & data$period == "w1 -> w2", ]
study <- data[data$tie == "Study" & data$period == "w1 -> w2", ]
csn <- data[data$tie == "Sport" & data$period == "w1 -> w2", ]

tab <- matrix(nrow = 5, ncol = 4)
rownames(tab) <- c("(Unique) alters", "Confidants", "Study partners", "Best friends", "Sports partners")

colnames(tab) <- c("n", "communication freq.", "closeness", "multiplexity $^{b}$")

tab[1, 1] <- length(unique(data$alterid[data$period == "w1 -> w2"]))
tab[2, 1] <- nrow(cdn)
tab[3, 1] <- nrow(study)
tab[4, 1] <- nrow(bff)
tab[5, 1] <- nrow(csn)

tab[1, 2] <- paste0(round(mean(data$frequency.t[which(!duplicated(data$alterid[data$period == "w1 -> w2"]))],
    na.rm = TRUE), 2), " (", round(sd(data$frequency.t[which(!duplicated(data$alterid[data$period ==
    "w1 -> w2"]))], na.rm = TRUE), 2), ")")
tab[2, 2] <- paste0(round(mean(cdn$frequency.t, na.rm = TRUE), 2), " (", round(sd(cdn$frequency.t, na.rm = TRUE),
    2), ")")
tab[3, 2] <- paste0(round(mean(study$frequency.t, na.rm = TRUE), 2), " (", round(sd(study$frequency.t,
    na.rm = TRUE), 2), ")")
tab[4, 2] <- paste0(round(mean(bff$frequency.t, na.rm = TRUE), 2), " (", round(sd(bff$frequency.t, na.rm = TRUE),
    2), ")")
tab[5, 2] <- paste0(round(mean(csn$frequency.t, na.rm = TRUE), 2), " (", round(sd(csn$frequency.t, na.rm = TRUE),
    2), ")")

tab[1, 3] <- paste0(round(mean(data$closeness.t[which(!duplicated(data$alterid[data$period == "w1 -> w2"]))],
    na.rm = TRUE), 2), " (", round(sd(data$closeness.t[which(!duplicated(data$alterid[data$period ==
    "w1 -> w2"]))], na.rm = TRUE), 2), ")")
tab[2, 3] <- paste0(round(mean(cdn$closeness.t, na.rm = TRUE), 2), " (", round(sd(cdn$closeness.t, na.rm = TRUE),
    2), ")")
tab[3, 3] <- paste0(round(mean(study$closeness.t, na.rm = TRUE), 2), " (", round(sd(study$closeness.t,
    na.rm = TRUE), 2), ")")
tab[4, 3] <- paste0(round(mean(bff$closeness.t, na.rm = TRUE), 2), " (", round(sd(bff$closeness.t, na.rm = TRUE),
    2), ")")
tab[5, 3] <- paste0(round(mean(csn$closeness.t, na.rm = TRUE), 2), " (", round(sd(csn$closeness.t, na.rm = TRUE),
    2), ")")

tab[1, 4] <- paste0(round(mean(data$multiplex[which(!duplicated(data$alterid[data$period == "w1 -> w2"]))],
    na.rm = TRUE), 2), " (", round(sd(data$multiplex[which(!duplicated(data$alterid[data$period == "w1 -> w2"]))],
    na.rm = TRUE), 2), ")")
tab[2, 4] <- paste0(round(mean(cdn$multiplex, na.rm = TRUE), 2), " (", round(sd(cdn$multiplex, na.rm = TRUE),
    2), ")")
tab[3, 4] <- paste0(round(mean(study$multiplex, na.rm = TRUE), 2), " (", round(sd(study$multiplex, na.rm = TRUE),
    2), ")")
tab[4, 4] <- paste0(round(mean(bff$multiplex, na.rm = TRUE), 2), " (", round(sd(bff$multiplex, na.rm = TRUE),
    2), ")")
tab[5, 4] <- paste0(round(mean(csn$multiplex, na.rm = TRUE), 2), " (", round(sd(csn$multiplex, na.rm = TRUE),
    2), ")")

knitr::kable(tab, digits = 2, "html", caption = "Relational characteristics across relational dimensions at t1 $^{a}$") %>%
    kableExtra::kable_styling(bootstrap_options = c("striped", "hover")) %>%
    kableExtra::add_footnote(c("Means and standard deviations in parentheses.", "To achieve a meaningful intercept for our multivariate analyses, we subtracted multiplexity by one. In this context, multiplexity represents the average number of extra relational dimensions for each type of relationship."),
        notation = "alphabet")
Relational characteristics across relational dimensions at t1 a
n communication freq. closeness multiplexity b
(Unique) alters 3104 5.83 (1.17) 3.1 (0.89) 0.59 (0.8)
Confidants 1120 6.32 (0.97) 3.64 (0.64) 1.3 (0.79)
Study partners 961 5.84 (1.27) 2.83 (0.95) 0.83 (0.98)
Best friends 1925 5.97 (1.03) 3.44 (0.65) 0.89 (0.85)
Sports partners 933 6.05 (1.06) 3.07 (0.92) 0.98 (1.02)
a Means and standard deviations in parentheses.
b To achieve a meaningful intercept for our multivariate analyses, we subtracted multiplexity by one. In this context, multiplexity represents the average number of extra relational dimensions for each type of relationship.


cdn <- data[data$tie == "Confidant" & data$period == "w1 -> w2" & data$multiplex == 0, ]
bff <- data[data$tie == "Friend" & data$period == "w1 -> w2" & data$multiplex == 0, ]
study <- data[data$tie == "Study" & data$period == "w1 -> w2" & data$multiplex == 0, ]
csn <- data[data$tie == "Sport" & data$period == "w1 -> w2" & data$multiplex == 0, ]
dataa <- data[data$multiplex == 0, ]

tab <- matrix(nrow = 5, ncol = 4)
rownames(tab) <- c("(Unique) alters", "Confidants", "Study partners", "Best friends", "Sports partners")

colnames(tab) <- c("n", "communication freq.", "closeness", "multiplexity $^{b}$")

tab[1, 1] <- length(unique(dataa$alterid[dataa$period == "w1 -> w2"]))
tab[2, 1] <- nrow(cdn)
tab[3, 1] <- nrow(study)
tab[4, 1] <- nrow(bff)
tab[5, 1] <- nrow(csn)

tab[1, 2] <- paste0(round(mean(dataa$frequency.t[which(!duplicated(dataa$alterid[dataa$period == "w1 -> w2"]))],
    na.rm = TRUE), 2), " (", round(sd(dataa$frequency.t[which(!duplicated(dataa$alterid[dataa$period ==
    "w1 -> w2"]))], na.rm = TRUE), 2), ")")
tab[2, 2] <- paste0(round(mean(cdn$frequency.t, na.rm = TRUE), 2), " (", round(sd(cdn$frequency.t, na.rm = TRUE),
    2), ")")
tab[3, 2] <- paste0(round(mean(study$frequency.t, na.rm = TRUE), 2), " (", round(sd(study$frequency.t,
    na.rm = TRUE), 2), ")")
tab[4, 2] <- paste0(round(mean(bff$frequency.t, na.rm = TRUE), 2), " (", round(sd(bff$frequency.t, na.rm = TRUE),
    2), ")")
tab[5, 2] <- paste0(round(mean(csn$frequency.t, na.rm = TRUE), 2), " (", round(sd(csn$frequency.t, na.rm = TRUE),
    2), ")")

tab[1, 3] <- paste0(round(mean(dataa$closeness.t[which(!duplicated(dataa$alterid[data$period == "w1 -> w2"]))],
    na.rm = TRUE), 2), " (", round(sd(dataa$closeness.t[which(!duplicated(dataa$alterid[data$period ==
    "w1 -> w2"]))], na.rm = TRUE), 2), ")")
tab[2, 3] <- paste0(round(mean(cdn$closeness.t, na.rm = TRUE), 2), " (", round(sd(cdn$closeness.t, na.rm = TRUE),
    2), ")")
tab[3, 3] <- paste0(round(mean(study$closeness.t, na.rm = TRUE), 2), " (", round(sd(study$closeness.t,
    na.rm = TRUE), 2), ")")
tab[4, 3] <- paste0(round(mean(bff$closeness.t, na.rm = TRUE), 2), " (", round(sd(bff$closeness.t, na.rm = TRUE),
    2), ")")
tab[5, 3] <- paste0(round(mean(csn$closeness.t, na.rm = TRUE), 2), " (", round(sd(csn$closeness.t, na.rm = TRUE),
    2), ")")

tab[1, 4] <- paste0(round(mean(dataa$multiplex[which(!duplicated(dataa$alterid[data$period == "w1 -> w2"]))],
    na.rm = TRUE), 2), " (", round(sd(dataa$multiplex[which(!duplicated(dataa$alterid[data$period ==
    "w1 -> w2"]))], na.rm = TRUE), 2), ")")
tab[2, 4] <- paste0(round(mean(cdn$multiplex, na.rm = TRUE), 2), " (", round(sd(cdn$multiplex, na.rm = TRUE),
    2), ")")
tab[3, 4] <- paste0(round(mean(study$multiplex, na.rm = TRUE), 2), " (", round(sd(study$multiplex, na.rm = TRUE),
    2), ")")
tab[4, 4] <- paste0(round(mean(bff$multiplex, na.rm = TRUE), 2), " (", round(sd(bff$multiplex, na.rm = TRUE),
    2), ")")
tab[5, 4] <- paste0(round(mean(csn$multiplex, na.rm = TRUE), 2), " (", round(sd(csn$multiplex, na.rm = TRUE),
    2), ")")

knitr::kable(tab, digits = 2, "html", caption = "Relational characteristics of uniplex ties, across relational dimensions at t1 $^{a}$") %>%
    kableExtra::kable_styling(bootstrap_options = c("striped", "hover")) %>%
    kableExtra::add_footnote(c("Means and standard deviations in parentheses.", "To achieve a meaningful intercept for our multivariate analyses, we subtracted multiplexity by one. In this context, multiplexity represents the average number of extra relational dimensions for each type of relationship."),
        notation = "alphabet")
Relational characteristics of uniplex ties, across relational dimensions at t1 a
n communication freq. closeness multiplexity b
(Unique) alters 1809 5.49 (1.23) 2.72 (0.89) 0 (0)
Confidants 165 5.94 (1.44) 3.22 (1.02) 0 (0)
Study partners 489 5.36 (1.41) 2.25 (0.82) 0 (0)
Best friends 731 5.45 (1.07) 3.19 (0.68) 0 (0)
Sports partners 424 5.52 (1.17) 2.39 (0.81) 0 (0)
a Means and standard deviations in parentheses.
b To achieve a meaningful intercept for our multivariate analyses, we subtracted multiplexity by one. In this context, multiplexity represents the average number of extra relational dimensions for each type of relationship.



Role overlap

x1 <- list(
  'Best friend' = data$alterid[data$bff == 1 & data$period == "w1 -> w2"],
  'Confidant' = data$alterid[data$cdn == 1 & data$period == "w1 -> w2"],
  
  'Sports partner' = data$alterid[data$csn == 1 & data$period == "w1 -> w2"],
  'Study partner' = data$alterid[data$study == 1 & data$period == "w1 -> w2"]
)


(venn <- ggVennDiagram(x1, label = "percent", label_size = 3, label_percent_digit = 1, set_size = 3, show_intersect = FALSE) + 
    scale_fill_distiller(palette = "OrRd", direction = 1) +
    theme(legend.position = "right", plot.title = element_text(hjust = 0.5)) +
    scale_x_continuous(expand = expansion(mult = .2)) +
    labs(fill = "Alter count"))

#ggsave(venn, filename = "./figures/venn1.png")

#?ggVennDiagram
x2 <- list(`Best Friend` = data$alterid[data$bff == 1 & data$period == "w2 -> w3"], Confidant = data$alterid[data$cdn ==
    1 & data$period == "w2 -> w3"], `Sports partner` = data$alterid[data$csn == 1 & data$period == "w2 -> w3"],
    `Study partner` = data$alterid[data$study == 1 & data$period == "w2 -> w3"])


(venn <- ggVennDiagram(x2, label = "percent", label_size = 3, label_percent_digit = 1, set_size = 3,
    show_intersect = FALSE) + scale_fill_distiller(palette = "OrRd", direction = 1) + theme(legend.position = "right",
    plot.title = element_text(hjust = 0.5)) + scale_x_continuous(expand = expansion(mult = 0.2)) + labs(fill = "Alter count"))



Tie maintenance

# make table
tab <- matrix(nrow = 5, ncol = 2)
rownames(tab) <- c("All (unique) ties", "Confidants", "Best friends", "Study partners", "Sports partners")
colnames(tab) <- c("n", "Relisted")


bff <- data[data$tie == "Friend", ]
cdn <- data[data$tie == "Confidant", ]
study <- data[data$tie == "Study", ]
csn <- data[data$tie == "Sport", ]

tab[1, 1] <- nrow(data)
tab[2, 1] <- nrow(cdn)
tab[3, 1] <- nrow(bff)
tab[4, 1] <- nrow(study)
tab[5, 1] <- nrow(csn)

tab[1, 2] <- round(prop.table(table(data$Y))[[2]], 2)
tab[2, 2] <- round(prop.table(table(cdn$Y))[[2]], 2)
tab[3, 2] <- round(prop.table(table(bff$Y))[[2]], 2)
tab[4, 2] <- round(prop.table(table(study$Y))[[2]], 2)
tab[5, 2] <- round(prop.table(table(csn$Y))[[2]], 2)

options(knitr.kable.NA = "")

knitr::kable(tab, digits = 2, "html", caption = "Maintenance of multiple social ties over time among 513 students") %>%
    kableExtra::kable_styling(bootstrap_options = c("striped", "hover"))
Maintenance of multiple social ties over time among 513 students
n Relisted
All (unique) ties 7924 0.58
Confidants 1843 0.68
Best friends 2981 0.69
Study partners 1616 0.38
Sports partners 1484 0.43


Tie maintenance vs similarity

# 1. similarities vs tie loss, per dimension
plotdata1 <- data[, c("duration", "same_gender", "Y", "tie")]
plotdata1$same <- ifelse(plotdata1$same_gender == 1, 1, 0)
plotdata1$dimension <- "Gender"

plotdata2 <- data[, c("duration", "sim_educ", "Y", "tie")]
plotdata2$same <- ifelse(plotdata2$sim_educ == 1, 1, 0)
plotdata2$dimension <- "Education"

plotdata3 <- data[, c("duration", "dif_age", "Y", "tie")]
plotdata3$same <- ifelse(plotdata3$dif_age < 4, 1, 0)
plotdata3$dimension <- "Age"

plotdata1 <- plotdata1[, -2]
plotdata2 <- plotdata2[, -2]
plotdata3 <- plotdata3[, -2]
plotdata <- rbind(plotdata1, plotdata2, plotdata3)
plotdata$same <- factor(plotdata$same)

# calculate tie loss rate for similarity dimensions
means <- aggregate(Y ~ same + dimension, data = plotdata, FUN = "mean")
sd <- aggregate(Y ~ same + dimension, data = plotdata, FUN = "sd")
n <- aggregate(Y ~ same + dimension, data = plotdata, FUN = "sum")
means <- cbind(means, sd = sd$Y, n = n$Y)

# calculate a confidence interval around this proportion, usingthe Clopper-Pearson Confidence
# Interval
means$LL <- NA
means$UL <- NA

for (i in 1:nrow(means)) {
    cp.ci <- GenBinomApps::clopper.pearson.ci(k = round(means$Y[i] * means$n[i]), n = means$n[i], alpha = 0.05,
        CI = "two.sided")
    means$LL[i] <- cp.ci$Lower.limit
    means$UL[i] <- cp.ci$Upper.limit
}


plot1 <- ggplot(means, aes(x = same, y = Y, fill = as.factor(same))) + facet_wrap(~dimension) + geom_bar(stat = "identity",
    position = "dodge", width = 0.75) + geom_errorbar(aes(ymin = LL, ymax = UL), position = position_dodge(width = 0.5),
    width = 0.25) + labs(x = NULL, y = "Prop. maintained", fill = "Similarity", title = "(A) Maintenance of alter-ties of self-similar vs. dissimilar alters",
    font = "Jost") + scale_y_continuous(breaks = seq(0, 1, 0.25), limits = c(0, 1)) + theme_bw() + theme(axis.text.x = element_blank(),
    legend.position = "bottom")

# 2. dissagregate by relationship duration

# calculate tie loss rate for similarity dimensions means <- aggregate(Y ~ same + dimension +
# duration, data = plotdata, FUN = 'mean') sd <- aggregate(Y ~ same + dimension + duration, data =
# plotdata, FUN = 'sd') n <- aggregate(Y ~ same + dimension + duration, data =plotdata, FUN =
# 'sum') means <- cbind(means, sd=sd$Y, n=n$Y)

# calculate a confidence interval around this proportion, usingthe Clopper-Pearson Confidence
# Interval means$LL <- NA means$UL <- NA

# for (i in 1:nrow(means)) { cp.ci <- GenBinomApps::clopper.pearson.ci( k = round(means$Y[i] *
# means$n[i]), n = means$n[i], alpha = 0.05, CI='two.sided' ) means$LL[i] <- cp.ci$Lower.limit
# means$UL[i] <- cp.ci$Upper.limit }

# duration_names <- c( `0` = 'Under 1 year', `2` = '1-3 years', `6` = '4-8 years', `12` = '9-15
# years', `15` = 'Over 15 years' )

# plot2 <- ggplot(means, aes(x = dimension, y = Y, fill = as.factor(same))) + facet_wrap(~
# duration, labeller = as_labeller(duration_names), nrow = 1) + geom_bar(stat = 'identity',
# position = 'dodge', width = 0.7) + geom_errorbar(aes(ymin = LL, ymax = UL), position =
# position_dodge(width = 0.75), #width=0.25) + labs (x = NULL, y = 'Prop. maintained', fill =
# 'Similarity', title = '(B) Disaggregated by: #tie duration', font = 'Jost') +
# scale_y_continuous(breaks = seq(0, 1, .25), limits = c(0,1)) + theme(axis.text.x =
# element_text(angle = 33, hjust = 1))

# this is more informative. to show convergence effects plot2 <- ggplot(means, aes(x =
# as.factor(duration), y = Y, fill = as.factor(same))) + facet_wrap(~ dimension, nrow = 1) +
# geom_bar(stat = 'identity', position = 'dodge', width = .7) + geom_errorbar(aes(ymin = LL, ymax =
# UL), position = position_dodge(width = 0.75), #width=0.25) + labs (x = NULL, y = 'Prop.
# maintained', fill = 'Similarity', title = '(B) Convergence of #tie maintenance rates with similar
# vs. dissimilar alters over time',font = 'Jost') + scale_y_continuous(breaks = seq(0, 1, .25),
# limits = c(0,1)) + scale_x_discrete(labels = c( '<1', '1-3', '4-8', '9-15', '>15')) +
# theme(axis.text.x = element_text(angle = 33, hjust = 1), legend.position = 'none')

# per relationship type

# calculate tie loss rate for similarity dimensions
means <- aggregate(Y ~ same + dimension + tie, data = plotdata, FUN = "mean")
sd <- aggregate(Y ~ same + dimension + tie, data = plotdata, FUN = "sd")
n <- aggregate(Y ~ same + dimension + tie, data = plotdata, FUN = "sum")
means <- cbind(means, sd = sd$Y, n = n$Y)

# calculate a confidence interval around this proportion, usingthe Clopper-Pearson Confidence
# Interval
means$LL <- NA
means$UL <- NA

for (i in 1:nrow(means)) {
    cp.ci <- GenBinomApps::clopper.pearson.ci(k = round(means$Y[i] * means$n[i]), n = means$n[i], alpha = 0.05,
        CI = "two.sided")
    means$LL[i] <- cp.ci$Lower.limit
    means$UL[i] <- cp.ci$Upper.limit
}

means$tie[means$tie == "Friend"] <- "Best friend"

plot3 <- ggplot(means, aes(x = tie, y = Y, fill = as.factor(same))) + facet_wrap(~dimension, nrow = 1) +
    geom_bar(stat = "identity", position = "dodge", width = 0.7) + geom_errorbar(aes(ymin = LL, ymax = UL),
    position = position_dodge(width = 0.75), width = 0.25) + labs(x = NULL, y = "Prop. maintained", fill = "Similarity",
    title = "(B) Differences between social roles", font = "Jost") + scale_y_continuous(breaks = seq(0,
    1, 0.25), limits = c(0, 1)) + theme_bw() + theme(axis.text.x = element_text(angle = 33, hjust = 1),
    legend.position = "none")

(figure <- ggpubr::ggarrange(plot1, plot3, ncol = 1, nrow = 2))

# ggsave(figure, filename = './figures/desfig.png')


Confidants with a different gender than ego are more, rather than less stable!

Our post-hoc hypothesis is that this may be due to women generally providing more social support than men (Wellman and Wortley 1989), making them valuable confidants and thus less likely to be dissolved, resulting in a negative different-gender effect on confidant loss among men.

# prop.table(table(data$different_gender)) #74% of ties are same-gender

# let's see how this differs across the ties, and further disaggregated by the genders:
tab <- matrix(c(mean(data$same_gender[data$tie == "Confidant" & data$ego_female == 1]), mean(data$same_gender[data$tie ==
    "Confidant" & data$ego_female == 0]), mean(data$same_gender[data$tie == "Friend" & data$ego_female ==
    1]), mean(data$same_gender[data$tie == "Friend" & data$ego_female == 0]), mean(data$same_gender[data$tie ==
    "Study" & data$ego_female == 1]), mean(data$same_gender[data$tie == "Study" & data$ego_female ==
    0]), mean(data$same_gender[data$tie == "Sport" & data$ego_female == 1]), mean(data$same_gender[data$tie ==
    "Sport" & data$ego_female == 0])), nrow = 4, byrow = TRUE)

rownames(tab) <- c("Confidant", "Best friends", "Study partner", "Sports partner")
colnames(tab) <- c("Female", "Male")

knitr::kable(tab, digits = 2, "html", caption = "Proportion of same gender ties, across different tie types, disaggregated by gender") %>%
    kableExtra::kable_styling(bootstrap_options = c("striped", "hover"))
Proportion of same gender ties, across different tie types, disaggregated by gender
Female Male
Confidant 0.73 0.55
Best friends 0.79 0.72
Study partner 0.77 0.50
Sports partner 0.73 0.75
  1. We observe that men tend to have more cross-gender confiding ties (73%) than do women (55%).


# subset relevant columns
plotdata <- data[, c("same_gender", "Y", "tie", "ego_female")]

# filter on confidants
plotdata <- plotdata[plotdata$tie == "Confidant", ]

# calculate tie maintenance rate
means <- aggregate(Y ~ same_gender + ego_female, data = plotdata, FUN = "mean")
sd <- aggregate(Y ~ same_gender + ego_female, data = plotdata, FUN = "sd")
n <- aggregate(Y ~ same_gender + ego_female, data = plotdata, FUN = "sum")

# bind
means <- cbind(means, sd = sd$Y, n = n$Y)
means$ego_female <- ifelse(means$ego_female == 1, "Women", "Men")

# calculate a confidence interval around this proportion, usingthe Clopper-Pearson Confidence
# Interval
means$LL <- NA
means$UL <- NA

for (i in 1:nrow(means)) {
    cp.ci <- GenBinomApps::clopper.pearson.ci(k = round(means$Y[i] * means$n[i]), n = means$n[i], alpha = 0.05,
        CI = "two.sided")
    means$LL[i] <- cp.ci$Lower.limit
    means$UL[i] <- cp.ci$Upper.limit
}

ggplot(means, aes(x = same_gender, y = Y, fill = as.factor(same_gender))) + geom_bar(stat = "identity",
    position = "dodge", width = 0.75) + facet_wrap(~ego_female) + geom_errorbar(aes(ymin = LL, ymax = UL),
    position = position_dodge(width = 0.5), width = 0.25) + labs(x = NULL, y = "Prop. maintained", fill = "Similarity",
    title = "Maintenance of same-gender vs. different gender confidants,\namong men vs. women", font = "Jost") +
    scale_y_continuous(breaks = seq(0, 1, 0.25), limits = c(0, 1)) + theme(axis.text.x = element_blank())

  1. But both men (although not significantly) and women maintain same-gender confidants more often than they maintain different-gender confidants…


Homogeneity

  • EI index for dichotomous variables (same gender, same education)
  • Average similarity score for continuous variable (age difference)
tab <- matrix(nrow = 3, ncol = 3)
rownames(tab) <- c("Gender", "Education", "Age")
colnames(tab) <- c("Homogeneity W1", "Homogeneity W2", "Δ W1-W2")

eigender1 <- NA
eieduc1 <- NA
avsimage1 <- NA
eigender2 <- NA
eieduc2 <- NA
avsimage2 <- NA
eigenderd <- NA
eieducd <- NA
avsimaged <- NA
eigenderd <- NA
eieducd <- NA
avsimaged <- NA

for (i in 1:length(unique(data$ego[data$period == "w2 -> w3"]))) {

    # get network observed at wave 1
    netw1 <- data[data$ego == unique(data$ego[data$period == "w2 -> w3"])[i] & data$period == "w1 -> w2",
        ]

    # get unique alters
    netw1u <- netw1[which(!duplicated(netw1$alterid)), ]

    # EI index for gender and education
    simgender <- length(which(netw1u$same_gender == 1))
    difgender <- length(which(netw1u$different_gender == 1))
    simeduc <- length(which(netw1u$sim_educ == 1))
    difeduc <- length(which(netw1u$different_educ == 1))
    n_alter <- nrow(netw1u)

    # calculate EI
    eigender1[i] <- (simgender - difgender)/n_alter
    eieduc1[i] <- (simeduc - difeduc)/n_alter

    # and average similarity for age
    ego_age <- netw1u$ego_age[1]  #ego age
    alters_age <- as.numeric(netw1u$alter_age)  #alters' age
    min <- 16
    max <- 45
    rv <- max - min  #range
    avsimage1[i] <- mean(1 - abs(alters_age - ego_age)/rv)  #average similarity score

    # now repeat for wave 2
    netw2 <- data[data$ego == unique(data$ego[data$period == "w2 -> w3"])[i] & data$period == "w2 -> w3",
        ]

    # get unique alters
    netw2u <- netw2[which(!duplicated(netw2$alterid)), ]

    simgender <- length(which(netw2u$same_gender == 1))
    difgender <- length(which(netw2u$different_gender == 1))
    simeduc <- length(which(netw2u$sim_educ == 1))
    difeduc <- length(which(netw2u$different_educ == 1))
    n_alter <- nrow(netw2u)

    eigender2[i] <- (simgender - difgender)/n_alter
    eieduc2[i] <- (simeduc - difeduc)/n_alter

    alters_age <- as.numeric(netw2u$alter_age)  #alters' age
    avsimage2[i] <- mean(1 - abs(alters_age - ego_age)/rv)  #average similarity score

    # difference
    eigenderd[i] <- eigender1[i] - eigender2[i]
    eieducd[i] <- eieduc1[i] - eieduc2[i]
    avsimaged[i] <- avsimage1[i] - avsimage2[i]

}


tab[1, 1] <- paste0(format(round(mean(eigender1, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(eigender1,
    na.rm = TRUE), 2), nsmall = 2), ")")
tab[1, 2] <- paste0(format(round(mean(eigender2, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(eigender2,
    na.rm = TRUE), 2), nsmall = 2), ")")
tab[1, 3] <- paste0(format(round(mean(eigenderd, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(eigenderd,
    na.rm = TRUE), 2), nsmall = 2), ")")

tab[2, 1] <- paste0(format(round(mean(eieduc1, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(eieduc1,
    na.rm = TRUE), 2), nsmall = 2), ")")
tab[2, 2] <- paste0(format(round(mean(eieduc2, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(eieduc2,
    na.rm = TRUE), 2), nsmall = 2), ")")
tab[2, 3] <- paste0(format(round(mean(eieducd, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(eieducd,
    na.rm = TRUE), 2), nsmall = 2), ")")

tab[3, 1] <- paste0(format(round(mean(avsimage1, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(avsimage1,
    na.rm = TRUE), 2), nsmall = 2), ")")
tab[3, 2] <- paste0(format(round(mean(avsimage2, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(avsimage2,
    na.rm = TRUE), 2), nsmall = 2), ")")
tab[3, 3] <- paste0(format(round(mean(avsimaged, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(avsimaged,
    na.rm = TRUE), 2), nsmall = 2), ")")

fshowdf(tab, caption = "Homogeneity in ego-networks of 281 students who participated in waves 1 and 2")
Homogeneity in ego-networks of 281 students who participated in waves 1 and 2
Homogeneity W1 Homogeneity W2 Δ W1-W2
Gender 0.53 (0.46) 0.44 (0.48) 0.09 (0.33)
Education 0.38 (0.63) 0.02 (0.56) 0.36 (0.46)
Age 0.94 (0.04) 0.94 (0.05) 0.00 (0.04)
tab <- matrix(nrow = 3, ncol = 3)
rownames(tab) <- c("Gender", "Education", "Age")
colnames(tab) <- c("Homogeneity W1", "Homogeneity W2", "Δ W1-W2")

eigender1 <- NA
eieduc1 <- NA
avsimage1 <- NA
eigender2 <- NA
eieduc2 <- NA
avsimage2 <- NA
eigenderd <- NA
eieducd <- NA
avsimaged <- NA

for (i in 1:length(unique(data$ego[data$period == "w2 -> w3"]))) {

    # get network observed at wave 1
    netw1 <- data[data$ego == unique(data$ego[data$period == "w2 -> w3"])[i] & data$period == "w1 -> w2",
        ]

    # get unique alters
    netw1u <- netw1[which(!duplicated(netw1$alterid)), ]

    # filter on tie type
    netw1u <- netw1u[netw1u$tie == "Confidant", ]

    # EI index for gender and education
    simgender <- length(which(netw1u$same_gender == 1))
    difgender <- length(which(netw1u$different_gender == 1))
    simeduc <- length(which(netw1u$sim_educ == 1))
    difeduc <- length(which(netw1u$different_educ == 1))
    n_alter <- nrow(netw1u)

    # calculate EI
    eigender1[i] <- (simgender - difgender)/n_alter
    eieduc1[i] <- (simeduc - difeduc)/n_alter

    # and average similarity for age
    ego_age <- netw1u$ego_age[1]  #ego age
    alters_age <- as.numeric(netw1u$alter_age)  #alters' age
    min <- 16
    max <- 45
    rv <- max - min  #range
    avsimage1[i] <- mean(1 - abs(alters_age - ego_age)/rv)  #average similarity score

    # now repeat for wave 2
    netw2 <- data[data$ego == unique(data$ego[data$period == "w2 -> w3"])[i] & data$period == "w2 -> w3",
        ]

    # get unique alters
    netw2u <- netw2[which(!duplicated(netw2$alterid)), ]

    # filter on tie type
    netw2u <- netw2u[netw2u$tie == "Confidant", ]

    simgender <- length(which(netw2u$same_gender == 1))
    difgender <- length(which(netw2u$different_gender == 1))
    simeduc <- length(which(netw2u$sim_educ == 1))
    difeduc <- length(which(netw2u$different_educ == 1))
    n_alter <- nrow(netw2u)

    eigender2[i] <- (simgender - difgender)/n_alter
    eieduc2[i] <- (simeduc - difeduc)/n_alter

    alters_age <- as.numeric(netw2u$alter_age)  #alters' age
    avsimage2[i] <- mean(1 - abs(alters_age - ego_age)/rv)  #average similarity score

    # difference
    eigenderd[i] <- eigender1[i] - eigender2[i]
    eieducd[i] <- eieduc1[i] - eieduc2[i]
    avsimaged[i] <- avsimage1[i] - avsimage2[i]

}

tab[1, 1] <- paste0(format(round(mean(eigender1, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(eigender1,
    na.rm = TRUE), 2), nsmall = 2), ")")
tab[1, 2] <- paste0(format(round(mean(eigender2, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(eigender2,
    na.rm = TRUE), 2), nsmall = 2), ")")
tab[1, 3] <- paste0(format(round(mean(eigenderd, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(eigenderd,
    na.rm = TRUE), 2), nsmall = 2), ")")

tab[2, 1] <- paste0(format(round(mean(eieduc1, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(eieduc1,
    na.rm = TRUE), 2), nsmall = 2), ")")
tab[2, 2] <- paste0(format(round(mean(eieduc2, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(eieduc2,
    na.rm = TRUE), 2), nsmall = 2), ")")
tab[2, 3] <- paste0(format(round(mean(eieducd, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(eieducd,
    na.rm = TRUE), 2), nsmall = 2), ")")

tab[3, 1] <- paste0(format(round(mean(avsimage1, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(avsimage1,
    na.rm = TRUE), 2), nsmall = 2), ")")
tab[3, 2] <- paste0(format(round(mean(avsimage2, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(avsimage2,
    na.rm = TRUE), 2), nsmall = 2), ")")
tab[3, 3] <- paste0(format(round(mean(avsimaged, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(avsimaged,
    na.rm = TRUE), 2), nsmall = 2), ")")

fshowdf(tab, caption = "Homogeneity in confiding network layer of 281 students who participated in waves 1 and 2")
Homogeneity in confiding network layer of 281 students who participated in waves 1 and 2
Homogeneity W1 Homogeneity W2 Δ W1-W2
Gender 0.32 (0.74) 0.31 (0.72) 0.02 (0.58)
Education 0.36 (0.77) 0.28 (0.74) 0.09 (0.56)
Age 0.94 (0.09) 0.94 (0.08) 0.00 (0.07)
tab <- matrix(nrow = 3, ncol = 3)
rownames(tab) <- c("Gender", "Education", "Age")
colnames(tab) <- c("Homogeneity W1", "Homogeneity W2", "Δ W1-W2")

eigender1 <- NA
eieduc1 <- NA
avsimage1 <- NA
eigender2 <- NA
eieduc2 <- NA
avsimage2 <- NA
eigenderd <- NA
eieducd <- NA
avsimaged <- NA

for (i in 1:length(unique(data$ego[data$period == "w2 -> w3"]))) {

    # get network observed at wave 1
    netw1 <- data[data$ego == unique(data$ego[data$period == "w2 -> w3"])[i] & data$period == "w1 -> w2",
        ]

    # get unique alters
    netw1u <- netw1[which(!duplicated(netw1$alterid)), ]

    # filter on tie type
    netw1u <- netw1u[netw1u$tie == "Friend", ]

    # EI index for gender and education
    simgender <- length(which(netw1u$same_gender == 1))
    difgender <- length(which(netw1u$different_gender == 1))
    simeduc <- length(which(netw1u$sim_educ == 1))
    difeduc <- length(which(netw1u$different_educ == 1))
    n_alter <- nrow(netw1u)

    # calculate EI
    eigender1[i] <- (simgender - difgender)/n_alter
    eieduc1[i] <- (simeduc - difeduc)/n_alter

    # and average similarity for age
    ego_age <- netw1u$ego_age[1]  #ego age
    alters_age <- as.numeric(netw1u$alter_age)  #alters' age
    min <- 16
    max <- 45
    rv <- max - min  #range
    avsimage1[i] <- mean(1 - abs(alters_age - ego_age)/rv)  #average similarity score

    # now repeat for wave 2
    netw2 <- data[data$ego == unique(data$ego[data$period == "w2 -> w3"])[i] & data$period == "w2 -> w3",
        ]

    # get unique alters
    netw2u <- netw2[which(!duplicated(netw2$alterid)), ]

    # filter on tie type
    netw2u <- netw2u[netw2u$tie == "Friend", ]

    simgender <- length(which(netw2u$same_gender == 1))
    difgender <- length(which(netw2u$different_gender == 1))
    simeduc <- length(which(netw2u$sim_educ == 1))
    difeduc <- length(which(netw2u$different_educ == 1))
    n_alter <- nrow(netw2u)

    eigender2[i] <- (simgender - difgender)/n_alter
    eieduc2[i] <- (simeduc - difeduc)/n_alter

    alters_age <- as.numeric(netw2u$alter_age)  #alters' age
    avsimage2[i] <- mean(1 - abs(alters_age - ego_age)/rv)  #average similarity score

    # difference
    eigenderd[i] <- eigender1[i] - eigender2[i]
    eieducd[i] <- eieduc1[i] - eieduc2[i]
    avsimaged[i] <- avsimage1[i] - avsimage2[i]

}

tab[1, 1] <- paste0(format(round(mean(eigender1, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(eigender1,
    na.rm = TRUE), 2), nsmall = 2), ")")
tab[1, 2] <- paste0(format(round(mean(eigender2, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(eigender2,
    na.rm = TRUE), 2), nsmall = 2), ")")
tab[1, 3] <- paste0(format(round(mean(eigenderd, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(eigenderd,
    na.rm = TRUE), 2), nsmall = 2), ")")

tab[2, 1] <- paste0(format(round(mean(eieduc1, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(eieduc1,
    na.rm = TRUE), 2), nsmall = 2), ")")
tab[2, 2] <- paste0(format(round(mean(eieduc2, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(eieduc2,
    na.rm = TRUE), 2), nsmall = 2), ")")
tab[2, 3] <- paste0(format(round(mean(eieducd, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(eieducd,
    na.rm = TRUE), 2), nsmall = 2), ")")

tab[3, 1] <- paste0(format(round(mean(avsimage1, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(avsimage1,
    na.rm = TRUE), 2), nsmall = 2), ")")
tab[3, 2] <- paste0(format(round(mean(avsimage2, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(avsimage2,
    na.rm = TRUE), 2), nsmall = 2), ")")
tab[3, 3] <- paste0(format(round(mean(avsimaged, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(avsimaged,
    na.rm = TRUE), 2), nsmall = 2), ")")

fshowdf(tab, caption = "Homogeneity in friendship network layer of 281 students who participated in waves 1 and 2")
Homogeneity in friendship network layer of 281 students who participated in waves 1 and 2
Homogeneity W1 Homogeneity W2 Δ W1-W2
Gender 0.69 (0.57) 0.60 (0.68) 0.05 (0.57)
Education 0.31 (0.82) 0.07 (0.81) 0.22 (0.82)
Age 0.95 (0.04) 0.95 (0.04) 0.00 (0.04)
tab <- matrix(nrow = 3, ncol = 3)
rownames(tab) <- c("Gender", "Education", "Age")
colnames(tab) <- c("Homogeneity W1", "Homogeneity W2", "Δ W1-W2")

eigender1 <- NA
eieduc1 <- NA
avsimage1 <- NA
eigender2 <- NA
eieduc2 <- NA
avsimage2 <- NA
eigenderd <- NA
eieducd <- NA
avsimaged <- NA

for (i in 1:length(unique(data$ego[data$period == "w2 -> w3"]))) {

    # get network observed at wave 1
    netw1 <- data[data$ego == unique(data$ego[data$period == "w2 -> w3"])[i] & data$period == "w1 -> w2",
        ]

    # get unique alters
    netw1u <- netw1[which(!duplicated(netw1$alterid)), ]

    # filter on tie type
    netw1u <- netw1u[netw1u$tie == "Sport", ]

    # EI index for gender and education
    simgender <- length(which(netw1u$same_gender == 1))
    difgender <- length(which(netw1u$different_gender == 1))
    simeduc <- length(which(netw1u$sim_educ == 1))
    difeduc <- length(which(netw1u$different_educ == 1))
    n_alter <- nrow(netw1u)

    # calculate EI
    eigender1[i] <- (simgender - difgender)/n_alter
    eieduc1[i] <- (simeduc - difeduc)/n_alter

    # and average similarity for age
    ego_age <- netw1u$ego_age[1]  #ego age
    alters_age <- as.numeric(netw1u$alter_age)  #alters' age
    min <- 16
    max <- 45
    rv <- max - min  #range
    avsimage1[i] <- mean(1 - abs(alters_age - ego_age)/rv)  #average similarity score

    # now repeat for wave 2
    netw2 <- data[data$ego == unique(data$ego[data$period == "w2 -> w3"])[i] & data$period == "w2 -> w3",
        ]

    # get unique alters
    netw2u <- netw2[which(!duplicated(netw2$alterid)), ]

    # filter on tie type
    netw2u <- netw2u[netw2u$tie == "Sport", ]

    simgender <- length(which(netw2u$same_gender == 1))
    difgender <- length(which(netw2u$different_gender == 1))
    simeduc <- length(which(netw2u$sim_educ == 1))
    difeduc <- length(which(netw2u$different_educ == 1))
    n_alter <- nrow(netw2u)

    eigender2[i] <- (simgender - difgender)/n_alter
    eieduc2[i] <- (simeduc - difeduc)/n_alter

    alters_age <- as.numeric(netw2u$alter_age)  #alters' age
    avsimage2[i] <- mean(1 - abs(alters_age - ego_age)/rv)  #average similarity score

    # difference
    eigenderd[i] <- eigender1[i] - eigender2[i]
    eieducd[i] <- eieduc1[i] - eieduc2[i]
    avsimaged[i] <- avsimage1[i] - avsimage2[i]

}

tab[1, 1] <- paste0(format(round(mean(eigender1, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(eigender1,
    na.rm = TRUE), 2), nsmall = 2), ")")
tab[1, 2] <- paste0(format(round(mean(eigender2, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(eigender2,
    na.rm = TRUE), 2), nsmall = 2), ")")
tab[1, 3] <- paste0(format(round(mean(eigenderd, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(eigenderd,
    na.rm = TRUE), 2), nsmall = 2), ")")

tab[2, 1] <- paste0(format(round(mean(eieduc1, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(eieduc1,
    na.rm = TRUE), 2), nsmall = 2), ")")
tab[2, 2] <- paste0(format(round(mean(eieduc2, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(eieduc2,
    na.rm = TRUE), 2), nsmall = 2), ")")
tab[2, 3] <- paste0(format(round(mean(eieducd, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(eieducd,
    na.rm = TRUE), 2), nsmall = 2), ")")

tab[3, 1] <- paste0(format(round(mean(avsimage1, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(avsimage1,
    na.rm = TRUE), 2), nsmall = 2), ")")
tab[3, 2] <- paste0(format(round(mean(avsimage2, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(avsimage2,
    na.rm = TRUE), 2), nsmall = 2), ")")
tab[3, 3] <- paste0(format(round(mean(avsimaged, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(avsimaged,
    na.rm = TRUE), 2), nsmall = 2), ")")

fshowdf(tab, caption = "Homogeneity in sporting network layer of 281 students who participated in waves 1 and 2")
Homogeneity in sporting network layer of 281 students who participated in waves 1 and 2
Homogeneity W1 Homogeneity W2 Δ W1-W2
Gender 0.60 (0.73) 0.38 (0.87) 0.16 (0.93)
Education 0.29 (0.85) -0.35 (0.82) 0.41 (1.01)
Age 0.92 (0.09) 0.92 (0.07) -0.01 (0.10)
tab <- matrix(nrow = 3, ncol = 3)
rownames(tab) <- c("Gender", "Education", "Age")
colnames(tab) <- c("Homogeneity W1", "Homogeneity W2", "Δ W1-W2")

eigender1 <- NA
eieduc1 <- NA
avsimage1 <- NA
eigender2 <- NA
eieduc2 <- NA
avsimage2 <- NA
eigenderd <- NA
eieducd <- NA
avsimaged <- NA

for (i in 1:length(unique(data$ego[data$period == "w2 -> w3"]))) {

    # get network observed at wave 1
    netw1 <- data[data$ego == unique(data$ego[data$period == "w2 -> w3"])[i] & data$period == "w1 -> w2",
        ]

    # get unique alters
    netw1u <- netw1[which(!duplicated(netw1$alterid)), ]

    # filter on tie type
    netw1u <- netw1u[netw1u$tie == "Study", ]

    # EI index for gender and education
    simgender <- length(which(netw1u$same_gender == 1))
    difgender <- length(which(netw1u$different_gender == 1))
    simeduc <- length(which(netw1u$sim_educ == 1))
    difeduc <- length(which(netw1u$different_educ == 1))
    n_alter <- nrow(netw1u)

    # calculate EI
    eigender1[i] <- (simgender - difgender)/n_alter
    eieduc1[i] <- (simeduc - difeduc)/n_alter

    # and average similarity for age
    ego_age <- netw1u$ego_age[1]  #ego age
    alters_age <- as.numeric(netw1u$alter_age)  #alters' age
    min <- 16
    max <- 45
    rv <- max - min  #range
    avsimage1[i] <- mean(1 - abs(alters_age - ego_age)/rv)  #average similarity score

    # now repeat for wave 2
    netw2 <- data[data$ego == unique(data$ego[data$period == "w2 -> w3"])[i] & data$period == "w2 -> w3",
        ]

    # get unique alters
    netw2u <- netw2[which(!duplicated(netw2$alterid)), ]

    # filter on tie type
    netw2u <- netw2u[netw2u$tie == "Study", ]

    simgender <- length(which(netw2u$same_gender == 1))
    difgender <- length(which(netw2u$different_gender == 1))
    simeduc <- length(which(netw2u$sim_educ == 1))
    difeduc <- length(which(netw2u$different_educ == 1))
    n_alter <- nrow(netw2u)

    eigender2[i] <- (simgender - difgender)/n_alter
    eieduc2[i] <- (simeduc - difeduc)/n_alter

    alters_age <- as.numeric(netw2u$alter_age)  #alters' age
    avsimage2[i] <- mean(1 - abs(alters_age - ego_age)/rv)  #average similarity score

    # difference
    eigenderd[i] <- eigender1[i] - eigender2[i]
    eieducd[i] <- eieduc1[i] - eieduc2[i]
    avsimaged[i] <- avsimage1[i] - avsimage2[i]

}

tab[1, 1] <- paste0(format(round(mean(eigender1, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(eigender1,
    na.rm = TRUE), 2), nsmall = 2), ")")
tab[1, 2] <- paste0(format(round(mean(eigender2, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(eigender2,
    na.rm = TRUE), 2), nsmall = 2), ")")
tab[1, 3] <- paste0(format(round(mean(eigenderd, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(eigenderd,
    na.rm = TRUE), 2), nsmall = 2), ")")

tab[2, 1] <- paste0(format(round(mean(eieduc1, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(eieduc1,
    na.rm = TRUE), 2), nsmall = 2), ")")
tab[2, 2] <- paste0(format(round(mean(eieduc2, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(eieduc2,
    na.rm = TRUE), 2), nsmall = 2), ")")
tab[2, 3] <- paste0(format(round(mean(eieducd, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(eieducd,
    na.rm = TRUE), 2), nsmall = 2), ")")

tab[3, 1] <- paste0(format(round(mean(avsimage1, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(avsimage1,
    na.rm = TRUE), 2), nsmall = 2), ")")
tab[3, 2] <- paste0(format(round(mean(avsimage2, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(avsimage2,
    na.rm = TRUE), 2), nsmall = 2), ")")
tab[3, 3] <- paste0(format(round(mean(avsimaged, na.rm = TRUE), 2), nsmall = 2), " (", format(round(sd(avsimaged,
    na.rm = TRUE), 2), nsmall = 2), ")")

fshowdf(tab, caption = "Homogeneity in study network layer of 281 students who participated in waves 1 and 2")
Homogeneity in study network layer of 281 students who participated in waves 1 and 2
Homogeneity W1 Homogeneity W2 Δ W1-W2
Gender 0.55 (0.71) 0.44 (0.78) 0.10 (0.81)
Education 0.74 (0.65) -0.33 (0.88) 0.76 (0.93)
Age 0.95 (0.06) 0.95 (0.04) 0.00 (0.06)

Wellman, Barry, and Scot Wortley. 1989. Brothers’ Keepers: Situating Kinship Relations in Broader Networks of Social Support.” Sociological Perspectives 32 (3): 273–306.
LS0tDQp0aXRsZTogIkRlc2NyaXB0aXZlcyINCmJpYmxpb2dyYXBoeTogcmVmZXJlbmNlcy5iaWINCmxpbmstY2l0YXRpb25zOiB0cnVlDQpkYXRlOiAiTGFzdCBjb21waWxlZCBvbiBgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVCLCAlWScpYCINCm91dHB1dDogDQogIGh0bWxfZG9jdW1lbnQ6DQogICAgY3NzOiB0d2Vha3MuY3NzDQogICAgdG9jOiAgdHJ1ZQ0KICAgIHRvY19mbG9hdDogdHJ1ZQ0KICAgIG51bWJlcl9zZWN0aW9uczogZmFsc2UNCiAgICB0b2NfZGVwdGg6IDINCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCi0tLQ0KDQpgYGB7ciwgZ2xvYmFsc2V0dGluZ3MsIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9J2hpZGUnLCBtZXNzYWdlPUZBTFNFfQ0KbGlicmFyeShrbml0cikNCmxpYnJhcnkodGlkeXZlcnNlKQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0Kb3B0c19jaHVuayRzZXQodGlkeS5vcHRzPWxpc3Qod2lkdGguY3V0b2ZmPTEwMCksdGlkeT1UUlVFLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSxjb21tZW50ID0gIiM+IiwgY2FjaGU9VFJVRSwgY2xhc3Muc291cmNlPWMoInRlc3QiKSwgY2xhc3Mub3V0cHV0PWMoInRlc3QzIikpDQpvcHRpb25zKHdpZHRoID0gMTAwKQ0KcmdsOjpzZXR1cEtuaXRyKCkNCm9wdGlvbnMoa25pdHIua2FibGUuTkE9JycpDQoNCmNvbG9yaXplIDwtIGZ1bmN0aW9uKHgsIGNvbG9yKSB7c3ByaW50ZigiPHNwYW4gc3R5bGU9J2NvbG9yOiAlczsnPiVzPC9zcGFuPiIsIGNvbG9yLCB4KSB9DQpgYGANCg0KDQpgYGB7ciBrbGlwcHksIGVjaG89RkFMU0UsIGluY2x1ZGU9VFJVRX0NCmtsaXBweTo6a2xpcHB5KHBvc2l0aW9uID0gYygndG9wJywgJ3JpZ2h0JykpDQoja2xpcHB5OjprbGlwcHkoY29sb3IgPSAnZGFya3JlZCcpDQoja2xpcHB5OjprbGlwcHkodG9vbHRpcF9tZXNzYWdlID0gJ0NsaWNrIHRvIGNvcHknLCB0b29sdGlwX3N1Y2Nlc3MgPSAnRG9uZScpDQpgYGANCg0KDQoNCi0tLSAgDQogIA0KIyBHZXR0aW5nIHN0YXJ0ZWQNCg0KVG8gY29weSB0aGUgY29kZSwgY2xpY2sgdGhlIGJ1dHRvbiBpbiB0aGUgdXBwZXIgcmlnaHQgY29ybmVyIG9mIHRoZSBjb2RlLWNodW5rcy4NCg0KIyMgY2xlYW4gdXANCg0KYGBge3IsIGNsZWFuLCByZXN1bHRzPSdoaWRlJ30NCnJtKGxpc3Q9bHMoKSkNCmdjKCkNCmBgYA0KDQo8YnI+DQoNCiMjIGdlbmVyYWwgY3VzdG9tIGZ1bmN0aW9ucw0KDQotIGBmcGFja2FnZS5jaGVja2A6IENoZWNrIGlmIHBhY2thZ2VzIGFyZSBpbnN0YWxsZWQgKGFuZCBpbnN0YWxsIGlmIG5vdCkgaW4gUg0KLSBgZnNhdmVgOiBGdW5jdGlvbiB0byBzYXZlIGRhdGEgd2l0aCB0aW1lIHN0YW1wIGluIGNvcnJlY3QgZGlyZWN0b3J5DQotIGBmbG9hZGA6IExvYWQgUi1vYmplY3RzIHVuZGVyIG5ldyBuYW1lcw0KLSBgZnNob3dkZmA6IFByaW50IG9iamVjdHMgKGB0aWJibGVgIC8gYGRhdGEuZnJhbWVgKSBuaWNlbHkgb24gc2NyZWVuIGluIGAuUm1kYC4NCi0gYGZ0aGVtZWA6IHByZXR0eSBnZ3Bsb3QyIHRoZW1lDQoNCg0KYGBge3IsIGZ1bmN0aW9uc30NCmZwYWNrYWdlLmNoZWNrIDwtIGZ1bmN0aW9uKHBhY2thZ2VzKSB7DQogICAgbGFwcGx5KHBhY2thZ2VzLCBGVU4gPSBmdW5jdGlvbih4KSB7DQogICAgICAgIGlmICghcmVxdWlyZSh4LCBjaGFyYWN0ZXIub25seSA9IFRSVUUpKSB7DQogICAgICAgICAgICBpbnN0YWxsLnBhY2thZ2VzKHgsIGRlcGVuZGVuY2llcyA9IFRSVUUpDQogICAgICAgICAgICBsaWJyYXJ5KHgsIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkNCiAgICAgICAgfQ0KICAgIH0pDQp9DQoNCmZzYXZlIDwtIGZ1bmN0aW9uKHgsIGZpbGUsIGxvY2F0aW9uID0gIi4vZGF0YS9wcm9jZXNzZWQvIiwgLi4uKSB7DQogICAgaWYgKCFkaXIuZXhpc3RzKGxvY2F0aW9uKSkNCiAgICAgICAgZGlyLmNyZWF0ZShsb2NhdGlvbikNCiAgICBkYXRlbmFtZSA8LSBzdWJzdHIoZ3N1YigiWzotXSIsICIiLCBTeXMudGltZSgpKSwgMSwgOCkNCiAgICB0b3RhbG5hbWUgPC0gcGFzdGUobG9jYXRpb24sIGRhdGVuYW1lLCBmaWxlLCBzZXAgPSAiIikNCiAgICBwcmludChwYXN0ZSgiU0FWRUQ6ICIsIHRvdGFsbmFtZSwgc2VwID0gIiIpKQ0KICAgIHNhdmUoeCwgZmlsZSA9IHRvdGFsbmFtZSkNCn0NCg0KDQpmbG9hZCA8LSBmdW5jdGlvbihmaWxlTmFtZSkgew0KICAgIGxvYWQoZmlsZU5hbWUpDQogICAgZ2V0KGxzKClbbHMoKSAhPSAiZmlsZU5hbWUiXSkNCn0NCg0KZnNob3dkZiA8LSBmdW5jdGlvbih4LCBkaWdpdHMgPSAyLCAuLi4pIHsNCiAgICBrbml0cjo6a2FibGUoeCwgZGlnaXRzID0gZGlnaXRzLCAiaHRtbCIsIC4uLikgJT4lDQogICAgICAgIGthYmxlRXh0cmE6OmthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIikpICU+JQ0KICAgICAgICBrYWJsZUV4dHJhOjpzY3JvbGxfYm94KHdpZHRoID0gIjEwMCUiLCBoZWlnaHQgPSAiMzAwcHgiKQ0KfQ0KDQojZXh0cmFmb250Ojpmb250X2ltcG9ydChwYXRocyA9IGMoIkM6L1VzZXJzL3UyNDQxNDcvRG93bmxvYWRzL0pvc3QvIiwgcHJvbXB0ID0gRkFMU0UpKQ0KZnRoZW1lIDwtIGZ1bmN0aW9uKCkgew0KICANCiAgI2Rvd25sb2FkIGZvbnQgYXQgaHR0cHM6Ly9mb250cy5nb29nbGUuY29tL3NwZWNpbWVuL0pvc3QvDQogIHRoZW1lX21pbmltYWwoYmFzZV9mYW1pbHkgPSAiSm9zdCIpICsNCiAgICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gIkpvc3QiLCBmYWNlID0gImJvbGQiKSwNCiAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJKb3N0IE1lZGl1bSIpLA0KICAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDApLA0KICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDEpLA0KICAgICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gIkpvc3QiLCBmYWNlID0gImJvbGQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IHJlbCgwLjc1KSwgaGp1c3QgPSAwKSwNCiAgICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiZ3JleTkwIiwgY29sb3IgPSBOQSksDQogICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpDQp9DQoNCmBgYA0KDQpgYGB7ciBmb250cywgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRSwgcmVzdWx0cz0naGlkZSd9DQojIGltcG9ydCBmb250IEpPU1QNCiNleHRyYWZvbnQ6OmZvbnRfaW1wb3J0KHBhdHRlcm4gPSAiSm9zdCIpDQpleHRyYWZvbnQ6OmxvYWRmb250cyhkZXZpY2U9IndpbiIpDQoNCiMgU2V0IGRlZmF1bHQgdGhlbWUgYW5kIGZvbnQgc3R1ZmYNCnRoZW1lX3NldChmdGhlbWUoKSkNCnVwZGF0ZV9nZW9tX2RlZmF1bHRzKCJ0ZXh0IiwgbGlzdChmYW1pbHkgPSAiSm9zdCIsIGZvbnRmYWNlID0gInBsYWluIikpDQp1cGRhdGVfZ2VvbV9kZWZhdWx0cygibGFiZWwiLCBsaXN0KGZhbWlseSA9ICJKb3N0IiwgZm9udGZhY2UgPSAicGxhaW4iKSkNCmBgYA0KDQo8YnI+DQoNCiMjIG5lY2Vzc2FyeSBwYWNrYWdlcw0KDQotIGB0aWR5dmVyc2VgDQotIGBrbml0cmA6IGdlbmVyYXRpbmcgdGFibGVzDQotIGBrYWJsZUV4dHJhYDogbWFuaXB1bGF0aW5nIHRhYmxlcw0KLSBgeHRhYmxlYDogZGlzcGxheWluZyBIVE1MIGZvcm1hdA0KLSBgZ2dwdWJyYA0KLSBgR2VuQmlub21BcHBzYDogY29tcHV0ZSBDbG9wcGVyLVBlYXJzb24gY29uZmlkZW5jZSBpbnRlcnZhbA0KLSBgcmVzaGFwZTJgDQotIGBnZ1Zlbm5EaWFncmFtYA0KDQoNCmBgYHtyLCBwYWNrYWdlcywgcmVzdWx0cz0naGlkZScsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpwYWNrYWdlcyA9IGMoImtuaXRyIiwgImthYmxlRXh0cmEiLCAieHRhYmxlIiwgInRpZHl2ZXJzZSIsICJHZW5CaW5vbUFwcHMiLCAicmVzaGFwZTIiLCAiZ2djb3JycGxvdCIsICJnZ1Zlbm5EaWFncmFtIikNCmZwYWNrYWdlLmNoZWNrKHBhY2thZ2VzKQ0KYGBgDQoNCjxicj4NCg0KIyMgbG9hZCBkYXRhDQoNCkxvYWQgdGhlIHJlcGxpY2F0ZWQgZGF0YS1zZXRzIChjb25zdHJ1Y3RlZCBbaGVyZV0oaHR0cHM6Ly9uZXRjaGFuZ2UubmV0bGlmeS5hcHAvcHJlcC5odG1sKSkuIFRvIGxvYWQgdGhlc2UgZmlsZSwgYWRqdXN0IHRoZSBmaWxlbmFtZXMgaW4gdGhlIGZvbGxvd2luZyBjb2RlIHNvIHRoYXQgaXQgbWF0Y2hlcyB0aGUgbW9zdCByZWNlbnQgdmVyc2lvbiBvZiB0aGUgYC5SRGFgIGZpbGUgeW91IGhhdmUgaW4geW91ciBgLi9kYXRhL3Byb2Nlc3NlZC9gIGZvbGRlci4NCg0KWW91IG1heSBhbHNvIG9idGFpbiB0aGVtIGJ5IGRvd25sb2FkaW5nOiBgciB4ZnVuOjplbWJlZF9maWxlKCIuL2RhdGFfc2hhcmVkL2RhdGFfbmVzdGVkLlJEYSIpYA0KDQpgYGB7cixkYXRhfQ0KI2xpc3QuZmlsZXMoIi4vZGF0YS9wcm9jZXNzZWQvIikNCg0KI2dldCB0b2RheXMgZGF0ZToNCnRvZGF5IDwtIGdzdWIoIi0iLCAiIiwgU3lzLkRhdGUoKSkNCg0KZGF0YSA8LSBmbG9hZChwYXN0ZTAoIi4vZGF0YS9wcm9jZXNzZWQvIiwgdG9kYXksICJkYXRhX25lc3RlZC5SRGEiKSkNCmBgYA0KDQoNCjxicj4NCg0Kc29tZSBsYXN0IHdyYW5nbGluZzoNCg0KLSBtYWtlIFkgaW5kaWNhdGUgdGllICoqbG9zcyoqIGluc3RlYWQgb2YgdGllICoqbWFpbnRlbmFuY2UqKg0KLSBtYWtlIFggcmVmbGVjdCAqKmRpc3NpbWlsYXJpdHkqKiBpbnN0ZWFkIG9mICoqc2ltaWxhcml0eSoqDQotIHN0YW5kYXJkaXplIGVtYmVkZGVkbmVzcyBpbiBvdGhlciBuZXR3b3JrIGxheWVycw0KLSBwcm94aW1pdHkgbGV2ZWxzDQoNCmBgYHtyLCB3cmFuZ2xlfQ0KZGF0YSRZbG9zcyA8LSBpZmVsc2UoZGF0YSRZPT0xLCAwLCAxKQ0KDQpkYXRhJGRpZmZlcmVudF9nZW5kZXIgPC0gaWZlbHNlKGRhdGEkc2FtZV9nZW5kZXI9PTEsIDAsIDEpDQpkYXRhJGRpZmZlcmVudF9lZHVjIDwtIGlmZWxzZShkYXRhJHNpbV9lZHVjPT0xLCAwLCAxKQ0KDQpkYXRhJGVtYmVkLmV4dC8zIC0+IGRhdGEkZW1iZWQuZXh0DQoNCmRhdGEkcHJveGltaXR5IDwtIGZhY3RvcihkYXRhJHByb3hpbWl0eSwgbGV2ZWxzID0gYygiZmFyIiwiY2xvc2UiLCJyb29tbWF0ZSIpKQ0KDQpgYGANCg0KDQo8YnI+DQoNCg0KIyBDb3JyZWxhdGlvbiBtYXRyaXgNCg0KYGBge3IsIGNvcnJlbGF0aW9uLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBmaWcud2lkdGg9MTEsIGZpZy5oZWlnaHQ9NCwgY2xhc3Muc291cmNlID0gJ2ZvbGQtaGlkZSd9DQojZ2V0IHZhcmlhYmxlcyBvZiBpbnRlcmVzdCwgZm9yIHdoaWNoIHdlIHdhbnQgdG8gY2FsY3VsYXRlIGNvcnJlbGF0aW9ucw0KY29yZGYgPC0gZGF0YVssIHJldihjKCJkaWZfYWdlIiwiZGlmZmVyZW50X2dlbmRlciIsImRpZmZlcmVudF9lZHVjIiwiY2xvc2VuZXNzLnQiLCJtdWx0aXBsZXgiLCAiZW1iZWQiLCAiZW1iZWQuZXh0IiwgIllsb3NzIiwgInRpZSIpKV0NCg0KI3JlbGFiZWwNCm5hbWVzKGNvcmRmKSA8LSBjKCJUaWUiLCAiVGllIGxvc3MiLCAiU3RyLiBlbWJlZC4gb3RoZXIgbGF5ZXJzIiwgICJTdHIuIGVtYmVkLiBmb2NhbCBsYXllciIsICJSZWxhdGlvbmFsIG11bHRpcGxleGl0eSIsICJFbW90aW9uYWwgY2xvc2VuZXNzIiwgIkRpZmZlcmVudCBlZHVjYXRpb24iLCAiRGlmZmVyZW50IGdlbmRlciIsICJBZ2UgZGlmZmVyZW5jZSIpDQoNCiNyZW9yZGVyDQpkZXNpcmVkX29yZGVyIDwtIHJldihjKCJUaWUiLCAiVGllIGxvc3MiLCAiRGlmZmVyZW50IGdlbmRlciIsICJEaWZmZXJlbnQgZWR1Y2F0aW9uIiwgIkFnZSBkaWZmZXJlbmNlIiwgIkVtb3Rpb25hbCBjbG9zZW5lc3MiLCAgIlJlbGF0aW9uYWwgbXVsdGlwbGV4aXR5IiwgIlN0ci4gZW1iZWQuIGZvY2FsIGxheWVyIiwgIlN0ci4gZW1iZWQuIG90aGVyIGxheWVycyIpKQ0KY29yZGYgPC0gY29yZGZbLCBkZXNpcmVkX29yZGVyXQ0KDQojMS4gY29ycmVsYXRpb25zIG9mIGFsbCBvYnNlcnZhdGlvbnMgKHJlZ2FyZGxlc3Mgb2YgdGllIHR5cGUpDQphbGwgPC0gY29yZGZbLHNhcHBseShjb3JkZiwgaXMubnVtZXJpYyldDQojY29ycmVsYXRpb24NCmNvcm1hdCA8LSBjb3IoYWxsKQ0KI3AgdmFsdWUNCnBtYXQgPC0gY29yX3BtYXQoYWxsKQ0KI2JlbG93IGRpYWdvbmFsDQpjb3JtYXRbbG93ZXIudHJpKGNvcm1hdCldIDwtIE5BDQpwbWF0W2xvd2VyLnRyaShwbWF0KV0gPC0gTkENCiNtZWx0DQphbGxjIDwtIG1lbHQoY29ybWF0KQ0KYWxscCA8LSBtZWx0KHBtYXQpDQphbGwgPC0gY2JpbmQoYWxsYywgcHZhbCA9IGFsbHAkdmFsdWUpDQojZGlhZ29uYWwgTkENCmFsbCR2YWx1ZSA8LSBpZmVsc2UoYWxsJFZhcjEgPT0gYWxsJFZhcjIsIE5BLCBhbGwkdmFsdWUpDQphbGwkcHZhbCA8LSBpZmVsc2UoYWxsJFZhcjEgPT0gYWxsJFZhcjIsIE5BLCBhbGwkcHZhbCkNCiNhZGQgbGFiZWwNCmFsbCRsYWJlbCA8LSBpZmVsc2UoIWlzLm5hKGFsbCR2YWx1ZSksIHBhc3RlMChmb3JtYXQocm91bmQoYWxsJHZhbHVlLDIpLCBuc21hbGw9MiksIGlmZWxzZShhbGwkcHZhbD4wLjA1LCAiIiwgIioiKSksTkEpDQoNCnBsb3RfYWxsIDwtIGFsbCAlPiUgDQogIGdncGxvdChhZXMoVmFyMSwgVmFyMiwgZmlsbCA9IHZhbHVlKSkgKw0KICBnZW9tX3RpbGUgKGNvbG9yID0gJ2xpZ2h0Z3JleScpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGxhYmVsKSwgc2l6ZSA9IDQpICsNCiAgc2NhbGVfZmlsbF9ncmFkaWVudDIobG93ID0gImJsdWUiLCBtaWQgPSAid2hpdGUiLCBoaWdoPSJyZWQiLCBtaWRwb2ludD0wLCBsaW1pdD1jKC0xLDEpLCBuYS52YWx1ZSA9ICJsaWdodGdyZXkiKSArDQogIHNjYWxlX3hfZGlzY3JldGUobGltaXRzID0gcmV2KGxldmVscyhhbGwkVmFyMSkpKSArICAjcmV2ZXJzZSB4LWF4aXMNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwgbGVnZW5kLmRpcmVjdGlvbj0iaG9yaXpvbnRhbCIpICsgbGFicyh4PU5VTEwsIHk9TlVMTCwgdGl0bGU9IihBKSBBbGwgYWx0ZXItdGllIG9ic2VydmF0aW9ucyIsIGZpbGwgPSAiQ29ycmVsYXRpb24iKSANCg0KIzIgbm93LCBkaXNhZ2dyZWdhdGVkIGJ5IHRpZSB0eXBlDQojIGZ1bmN0aW9uIHRvIGNvbXB1dGUgY29ycmVsYXRpb25zIGZvciBhIHRpZSB0eXBlIGFuZCBhZGQgdGhlIG5lY2Vzc2FyeSBjb2x1bW5zDQpmY29tcGNvcnIgPC0gZnVuY3Rpb24odGllX3R5cGUpIHsgDQogIGRmIDwtIGNvcmRmW2NvcmRmJFRpZSA9PSB0aWVfdHlwZSwgc2FwcGx5KGNvcmRmLCBpcy5udW1lcmljKV0NCiAgY29ybWF0IDwtIGNvcihkZikNCiAgcG1hdCA8LSBjb3JfcG1hdChkZikNCiAgY29ybWF0W2xvd2VyLnRyaShjb3JtYXQpXSA8LSBOQQ0KICBwbWF0W2xvd2VyLnRyaShwbWF0KV0gPC0gTkENCiAgY29ybWF0X21lbHRlZCA8LSBtZWx0KGNvcm1hdCkNCiAgcG1hdF9tZWx0ZWQgPC0gbWVsdChwbWF0KQ0KICBkZiA8LSBjYmluZChjb3JtYXRfbWVsdGVkLCBwdmFsID0gcG1hdF9tZWx0ZWQkdmFsdWUpDQogIGRmJHZhbHVlIDwtIGlmZWxzZShkZiRWYXIxID09IGRmJFZhcjIsIE5BLCBkZiR2YWx1ZSkNCiAgZGYkcHZhbCA8LSBpZmVsc2UoZGYkVmFyMSA9PSBkZiRWYXIyLCBOQSwgZGYkcHZhbCkNCiAgZGYkbGFiZWwgPC0gaWZlbHNlKCFpcy5uYShkZiR2YWx1ZSksIHBhc3RlMChmb3JtYXQocm91bmQoZGYkdmFsdWUsIDIpLCBuc21hbGwgPSAyKSwgaWZlbHNlKGRmJHB2YWwgPiAwLjA1LCAiIiwgIioiKSksIE5BKQ0KICBkZiRncm91cCA8LSB0aWVfdHlwZQ0KICByZXR1cm4oZGYpDQp9DQoNCnRpZV90eXBlcyA8LSBjKCJDb25maWRhbnQiLCAiRnJpZW5kIiwgIlNwb3J0IiwgIlN0dWR5IikNCg0KI2VtcHR5IGRmDQpteWNvcnMgPC0gZGF0YS5mcmFtZSgpDQoNCiNpdGVyYXRlIHRocm91Z2ggdGllIHR5cGVzIGFuZCBjb21wdXRlIGNvcnJlbGF0aW9ucw0KZm9yIChpIGluIHRpZV90eXBlcykgew0KICBteWNvcnMgPC0gcmJpbmQobXljb3JzLCBmY29tcGNvcnIoaSkpDQp9DQoNCiNyZWxhYmVsLi4uDQpteWNvcnMkZ3JvdXBbbXljb3JzJGdyb3VwID09ICJGcmllbmQiXSA8LSAiQmVzdCBmcmllbmQiDQoNCnBsb3RfZGlzIDwtIG15Y29ycyAlPiUgDQogIGdncGxvdChhZXMoVmFyMSwgVmFyMiwgZmlsbCA9IHZhbHVlKSkgKw0KICBnZW9tX3RpbGUgKGNvbG9yID0gJ2xpZ2h0Z3JleScpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGxhYmVsKSwgc2l6ZSA9IDIuNSkgKw0KICBzY2FsZV9maWxsX2dyYWRpZW50Mihsb3cgPSAiYmx1ZSIsIG1pZCA9ICJ3aGl0ZSIsIGhpZ2g9InJlZCIsIG1pZHBvaW50PTAsIGxpbWl0PWMoLTEsMSksIG5hLnZhbHVlID0gImxpZ2h0Z3JleSIpICsNCiAgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHMgPSByZXYobGV2ZWxzKGFsbCRWYXIxKSkpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSwgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArIGxhYnMoeD1OVUxMLCB5PU5VTEwsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlPSIoQikgRGlzYWdncmVnYXRlZCBieSBzb2NpYWwgcm9sZSIsIGZpbGwgPSAiQ29ycmVsYXRpb24iKSArDQogIGZhY2V0X2dyaWQofmdyb3VwKQ0KDQojbm93LCBkaXNhZ2dyZWdhdGVkIGJ5IGNvbWJpbmF0aW9uIHRpZSB0eXBlICogdW5pIHZzIG11bHRpcGxleA0KI2tlZXAgZm9yIGFwcGVuZGl4Li4uDQpmY29tcGNvcnIyIDwtIGZ1bmN0aW9uKHRpZV90eXBlKSB7DQogIGRmIDwtIGNvcmRmW2NvcmRmJFRpZSA9PSB0aWVfdHlwZSwgc2FwcGx5KGNvcmRmLCBpcy5udW1lcmljKV0NCiAgDQogICN1bmlwbGV4IGJlbG93IGRpYWdvbmFsDQogIGRmdW5pIDwtIGRmW2RmJGBSZWxhdGlvbmFsIG11bHRpcGxleGl0eWA9PTAsXQ0KICBjb3JtYXQxIDwtIGNvcihkZnVuaSkNCiAgcG1hdDEgPC0gY29yX3BtYXQoZGZ1bmkpDQoNCiAgI211bHRpcGxleCBhYm92ZSBkaWFnb25hbA0KICBkZm11bHRpIDwtIGRmW2RmJGBSZWxhdGlvbmFsIG11bHRpcGxleGl0eWA+MCxdDQogIGNvcm1hdDIgPC0gY29yKGRmbXVsdGkpDQogIHBtYXQyIDwtIGNvcl9wbWF0KGRmbXVsdGkpDQogIGNvcm1hdCA8LSBjb3JtYXQxDQogIHBtYXQgPC0gcG1hdDENCiAgDQogIGNvcm1hdFt1cHBlci50cmkoY29ybWF0KV0gPC0gY29ybWF0Mlt1cHBlci50cmkoY29ybWF0MildDQogIHBtYXRbdXBwZXIudHJpKHBtYXQpXSA8LSBwbWF0Mlt1cHBlci50cmkocG1hdDIpXQ0KICBjb3JtYXRfbWVsdGVkIDwtIG1lbHQoY29ybWF0KQ0KICBwbWF0X21lbHRlZCA8LSBtZWx0KHBtYXQpDQogIGRmIDwtIGNiaW5kKGNvcm1hdF9tZWx0ZWQsIHB2YWwgPSBwbWF0X21lbHRlZCR2YWx1ZSkNCiAgZGYkdmFsdWUgPC0gaWZlbHNlKGRmJFZhcjEgPT0gZGYkVmFyMiwgTkEsIGRmJHZhbHVlKQ0KICBkZiRwdmFsIDwtIGlmZWxzZShkZiRWYXIxID09IGRmJFZhcjIsIE5BLCBkZiRwdmFsKQ0KICBkZiRsYWJlbCA8LSBpZmVsc2UoIWlzLm5hKGRmJHZhbHVlKSwgcGFzdGUwKGZvcm1hdChyb3VuZChkZiR2YWx1ZSwgMiksIG5zbWFsbCA9IDIpLCBpZmVsc2UoZGYkcHZhbCA+IDAuMDUsICIiLCAiKiIpKSwgTkEpDQogIGRmJGdyb3VwIDwtIHRpZV90eXBlDQoNCiAgcmV0dXJuKGRmKQ0KfQ0KICANCiNlbXB0eSBkZg0KbXljb3JzIDwtIGRhdGEuZnJhbWUoKQ0KDQojaXRlcmF0ZSB0aHJvdWdoIHRpZSB0eXBlcyBhbmQgY29tcHV0ZSBjb3JyZWxhdGlvbnMNCmZvciAoaSBpbiB0aWVfdHlwZXMpIHsNCiAgbXljb3JzIDwtIHJiaW5kKG15Y29ycywgZmNvbXBjb3JyMihpKSkNCn0NCg0KbXljb3JzJGdyb3VwW215Y29ycyRncm91cCA9PSAiRnJpZW5kIl0gPC0gIkJlc3QgZnJpZW5kIg0KDQoNCnBsb3RfZGlzMiA8LSBteWNvcnMgJT4lIA0KICBnZ3Bsb3QoYWVzKFZhcjEsIFZhcjIsIGZpbGwgPSB2YWx1ZSkpICsNCiAgZ2VvbV90aWxlIChjb2xvciA9ICdsaWdodGdyZXknKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBsYWJlbCksIHNpemUgPSAyLjUpICsNCiAgc2NhbGVfZmlsbF9ncmFkaWVudDIobG93ID0gImJsdWUiLCBtaWQgPSAid2hpdGUiLCBoaWdoPSJyZWQiLCBtaWRwb2ludD0wLCBsaW1pdD1jKC0xLDEpLCBuYS52YWx1ZSA9ICJsaWdodGdyZXkiKSArDQogIHNjYWxlX3hfZGlzY3JldGUobGltaXRzID0gcmV2KGxldmVscyhhbGwkVmFyMSkpKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSksIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKyBsYWJzKHg9TlVMTCwgeT1OVUxMLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZT0iKEMpIE11bHRpcGxleCBhbHRlcnMgKGFib3ZlIGRpYWdvbmFsKSB2cy4gdW5pcGxleCBhbHRlcnMgKGJlbG93IGRpYWdvbmFsKSIsIGZpbGwgPSAiQ29ycmVsYXRpb24iKSArDQogIGZhY2V0X2dyaWQofmdyb3VwKQ0KDQojZmlndXJlIDwtIGdncHVicjo6Z2dhcnJhbmdlKHBsb3RfYWxsLCBwbG90X2RpcywgbmNvbD0xLCBucm93PTIpDQoNCiNnZ3NhdmUoZmlndXJlLCANCiMgICAgICAgZmlsZSA9ICIuL2ZpZ3VyZXMvY29ycGxvdC5wbmciLA0KIyAgICAgICBkcGkgPSAzMjAsIA0KIyAgICAgICB3aWR0aCA9IDExLA0KIyAgICAgICBoZWlnaHQgPSA4KQ0KDQpwbG90X2FsbA0KcGxvdF9kaXMNCnBsb3RfZGlzMg0KDQpgYGANCg0KDQoNCi0tLS0NCg0KPGJyPg0KDQojIERlc2NyaWJpbmcgbmV0d29ya3MgDQoNCg0KPCEtLS0NCg0KIyMgbmV0d29yayBzaXplDQoNCmF0IHdhdmUgMQ0KDQpgYGB7ciwgY2xhc3Muc291cmNlID0gJ2ZvbGQtaGlkZSd9DQojIHRvdGFsIG5ldHNpemUgKG5vLiBvZiB1bmlxdWUgYWx0ZXJzLCBub24ta2luKQ0KbnMxIDwtIE5BDQojIHNpemUgb2YgZWFjaCBlZ29uZXQNCmNkbjEgPC0gTkENCnN0dTEgPC0gTkENCmJmZjEgPC0gTkENCmNzbjEgPC0gTkENCg0KZm9yIChpIGluIHVuaXF1ZShkYXRhJGVnb1tkYXRhJHBlcmlvZD09IncxIC0+IHcyIl0pKSB7DQogIA0KICBuczFbaV0gPC0gbGVuZ3RoKHVuaXF1ZShkYXRhJGFsdGVyaWRbZGF0YSRlZ289PWkgJiBkYXRhJHBlcmlvZCA9PSAidzEgLT4gdzIiXSkpDQogIGNkbjFbaV0gPC0gbGVuZ3RoKHVuaXF1ZShkYXRhJGFsdGVyaWRbZGF0YSRlZ28gPT0gaSAmIGRhdGEkcGVyaW9kID09ICJ3MSAtPiB3MiIgJiBkYXRhJHRpZSA9PSAiQ29uZmlkYW50Il0pKQ0KICBzdHUxW2ldIDwtIGxlbmd0aCh1bmlxdWUoZGF0YSRhbHRlcmlkW2RhdGEkZWdvID09IGkgJiBkYXRhJHBlcmlvZCA9PSAidzEgLT4gdzIiICYgZGF0YSR0aWUgPT0gIlN0dWR5Il0pKSANCiAgY3NuMVtpXSA8LSBsZW5ndGgodW5pcXVlKGRhdGEkYWx0ZXJpZFtkYXRhJGVnbyA9PSBpICYgZGF0YSRwZXJpb2QgPT0gIncxIC0+IHcyIiAmIGRhdGEkdGllID09ICJTcG9ydCJdKSkgDQogIGJmZjFbaV0gPC0gbGVuZ3RoKHVuaXF1ZShkYXRhJGFsdGVyaWRbZGF0YSRlZ28gPT0gaSAmIGRhdGEkcGVyaW9kID09ICJ3MSAtPiB3MiIgJiBkYXRhJHRpZSA9PSAiRnJpZW5kIl0pKSAgIA0KfQ0KDQpuczEgPC0gcHN5Y2g6OmRlc2NyaWJlKG5zMSkNCnN0dTEgPC0gcHN5Y2g6OmRlc2NyaWJlKHN0dTEpDQpjZG4xIDwtIHBzeWNoOjpkZXNjcmliZShjZG4xKQ0KY3NuMSA8LSBwc3ljaDo6ZGVzY3JpYmUoY3NuMSkNCmJmZjEgPC0gcHN5Y2g6OmRlc2NyaWJlKGJmZjEpDQoNCg0KDQojbWFrZSB0YWJsZQ0KdGFiIDwtIG1hdHJpeChucm93PTUsIG5jb2w9NSkNCnJvd25hbWVzKHRhYikgPC0gYygidG90YWwgbmV0d29yayBzaXplICgjIHVuaXF1ZSBub24ta2luIGFsdGVycykiLCANCiAgICAgICAgICAgICAgICAgICAiIyBjb25maWRhbnRzIiwgDQogICAgICAgICAgICAgICAgICAgIiMgc3R1ZHkgcGFydG5lcnMiLCANCiAgICAgICAgICAgICAgICAgICAiIyBiZXN0IGZyaWVuZHMiIA0KICAgICAgICAgICAgICAgICAgICwiIyBzcG9ydHMgcGFydG5lcnMiKQ0KDQpjb2xuYW1lcyh0YWIpIDwtIGMoIm4iLCAibWVhbiIsICJzZCIsICJtaW4iLCAibWF4IikNCg0KdGFiWzEsXSA8LSB1bmxpc3QobnMxKVtjKDIsMyw0LDgsOSldDQp0YWJbMixdIDwtIHVubGlzdChjZG4xKVtjKDIsMyw0LDgsOSldDQp0YWJbMyxdIDwtIHVubGlzdChzdHUxKVtjKDIsMyw0LDgsOSldDQp0YWJbNCxdIDwtIHVubGlzdChiZmYxKVtjKDIsMyw0LDgsOSldDQp0YWJbNSxdIDwtIHVubGlzdChjc24xKVtjKDIsMyw0LDgsOSldDQoNCmZzaG93ZGYodGFiLGNhcHRpb249IlRhYmxlIDEuIEVnb25ldCBzaXplIChub24ta2luIHJlbGF0aW9ucykgYXQgdDEgYW1vbmcgYSBzYW1wbGUgb2YgNTEzIHN0dWRlbnRzIikNCmBgYA0KDQotLS0gDQoNCjxicj4NCg0KLS0+DQoNCg0KIyMgUmVsYXRpb25hbCBjaGFyYWN0ZXJpc3RpY3Mgey50YWJzZXQgLnRhYnNldC1mYWRlfSANCg0KYXQgd2F2ZSAxDQoNCiMjIyBhbGwgYWx0ZXJzDQoNCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1oaWRlJ30NCmNkbiA8LSBkYXRhW2RhdGEkdGllID09ICJDb25maWRhbnQiICYgZGF0YSRwZXJpb2QgPT0gIncxIC0+IHcyIixdDQpiZmYgPC0gZGF0YVtkYXRhJHRpZSA9PSAiRnJpZW5kIiAmIGRhdGEkcGVyaW9kID09ICJ3MSAtPiB3MiIsXQ0Kc3R1ZHkgPC0gZGF0YVtkYXRhJHRpZSA9PSAiU3R1ZHkiICYgZGF0YSRwZXJpb2QgPT0gIncxIC0+IHcyIixdDQpjc24gPC0gZGF0YVtkYXRhJHRpZSA9PSAiU3BvcnQiICYgZGF0YSRwZXJpb2QgPT0gIncxIC0+IHcyIixdDQoNCnRhYiA8LSBtYXRyaXgobnJvdz01LCBuY29sPTQpDQpyb3duYW1lcyh0YWIpIDwtIGMoIihVbmlxdWUpIGFsdGVycyIsIA0KICAgICAgICAgICAgICAgICAgICJDb25maWRhbnRzIiwgDQogICAgICAgICAgICAgICAgICAgICJTdHVkeSBwYXJ0bmVycyIsDQogICAgICAgICAgICAgICAgICAgIkJlc3QgZnJpZW5kcyIsIA0KICAgICAgICAgICAgICAgICAgICJTcG9ydHMgcGFydG5lcnMiKQ0KDQpjb2xuYW1lcyh0YWIpIDwtIGMoIm4iLCAiY29tbXVuaWNhdGlvbiBmcmVxLiIsICJjbG9zZW5lc3MiLCAibXVsdGlwbGV4aXR5ICRee2J9JCIpDQoNCnRhYlsxLDFdIDwtIGxlbmd0aCh1bmlxdWUoZGF0YSRhbHRlcmlkW2RhdGEkcGVyaW9kPT0idzEgLT4gdzIiXSkpDQp0YWJbMiwxXSA8LSBucm93KGNkbikNCnRhYlszLDFdIDwtIG5yb3coc3R1ZHkpDQp0YWJbNCwxXSA8LSBucm93KGJmZikNCnRhYls1LDFdIDwtIG5yb3coY3NuKQ0KDQp0YWJbMSwyXSA8LSBwYXN0ZTAocm91bmQobWVhbihkYXRhJGZyZXF1ZW5jeS50W3doaWNoKCFkdXBsaWNhdGVkKGRhdGEkYWx0ZXJpZFtkYXRhJHBlcmlvZCA9PSJ3MSAtPiB3MiJdKSldLCBuYS5ybT1UUlVFKSwyKSwgIiAoIiwgcm91bmQoc2QoZGF0YSRmcmVxdWVuY3kudFt3aGljaCghZHVwbGljYXRlZChkYXRhJGFsdGVyaWRbZGF0YSRwZXJpb2QgPT0idzEgLT4gdzIiXSkpXSwgbmEucm09VFJVRSksMiksICIpIikNCnRhYlsyLDJdIDwtIHBhc3RlMChyb3VuZChtZWFuKGNkbiRmcmVxdWVuY3kudCxuYS5ybT1UUlVFKSwyKSwgIiAoIiwgcm91bmQoc2QoY2RuJGZyZXF1ZW5jeS50LG5hLnJtPVRSVUUpLDIpLCAiKSIpDQp0YWJbMywyXSA8LSBwYXN0ZTAocm91bmQobWVhbihzdHVkeSRmcmVxdWVuY3kudCxuYS5ybT1UUlVFKSwyKSwgIiAoIiwgcm91bmQoc2Qoc3R1ZHkkZnJlcXVlbmN5LnQsbmEucm09VFJVRSksMiksICIpIikNCnRhYls0LDJdIDwtIHBhc3RlMChyb3VuZChtZWFuKGJmZiRmcmVxdWVuY3kudCxuYS5ybT1UUlVFKSwyKSwgIiAoIiwgcm91bmQoc2QoYmZmJGZyZXF1ZW5jeS50LG5hLnJtPVRSVUUpLDIpLCAiKSIpDQp0YWJbNSwyXSA8LSBwYXN0ZTAocm91bmQobWVhbihjc24kZnJlcXVlbmN5LnQsbmEucm09VFJVRSksMiksICIgKCIsIHJvdW5kKHNkKGNzbiRmcmVxdWVuY3kudCxuYS5ybT1UUlVFKSwyKSwgIikiKQ0KDQp0YWJbMSwzXSA8LSAgcGFzdGUwKHJvdW5kKG1lYW4oZGF0YSRjbG9zZW5lc3MudFt3aGljaCghZHVwbGljYXRlZChkYXRhJGFsdGVyaWRbZGF0YSRwZXJpb2QgPT0idzEgLT4gdzIiXSkpXSwgbmEucm09VFJVRSksMiksICIgKCIsIHJvdW5kKHNkKGRhdGEkY2xvc2VuZXNzLnRbd2hpY2goIWR1cGxpY2F0ZWQoZGF0YSRhbHRlcmlkW2RhdGEkcGVyaW9kID09IncxIC0+IHcyIl0pKV0sIG5hLnJtPVRSVUUpLDIpLCAiKSIpDQp0YWJbMiwzXSA8LSBwYXN0ZTAocm91bmQobWVhbihjZG4kY2xvc2VuZXNzLnQsbmEucm09VFJVRSksMiksICIgKCIsIHJvdW5kKHNkKGNkbiRjbG9zZW5lc3MudCxuYS5ybT1UUlVFKSwyKSwgIikiKQ0KdGFiWzMsM10gPC0gcGFzdGUwKHJvdW5kKG1lYW4oc3R1ZHkkY2xvc2VuZXNzLnQsbmEucm09VFJVRSksMiksICIgKCIsIHJvdW5kKHNkKHN0dWR5JGNsb3NlbmVzcy50LG5hLnJtPVRSVUUpLDIpLCAiKSIpDQp0YWJbNCwzXSA8LSBwYXN0ZTAocm91bmQobWVhbihiZmYkY2xvc2VuZXNzLnQsbmEucm09VFJVRSksMiksICIgKCIsIHJvdW5kKHNkKGJmZiRjbG9zZW5lc3MudCxuYS5ybT1UUlVFKSwyKSwgIikiKQ0KdGFiWzUsM10gPC0gcGFzdGUwKHJvdW5kKG1lYW4oY3NuJGNsb3NlbmVzcy50LG5hLnJtPVRSVUUpLDIpLCAiICgiLCByb3VuZChzZChjc24kY2xvc2VuZXNzLnQsbmEucm09VFJVRSksMiksICIpIikNCg0KdGFiWzEsNF0gPC0gcGFzdGUwKHJvdW5kKG1lYW4oZGF0YSRtdWx0aXBsZXhbd2hpY2goIWR1cGxpY2F0ZWQoZGF0YSRhbHRlcmlkW2RhdGEkcGVyaW9kID09IncxIC0+IHcyIl0pKV0sIG5hLnJtPVRSVUUpLDIpLCAiICgiLCByb3VuZChzZChkYXRhJG11bHRpcGxleFt3aGljaCghZHVwbGljYXRlZChkYXRhJGFsdGVyaWRbZGF0YSRwZXJpb2QgPT0idzEgLT4gdzIiXSkpXSwgbmEucm09VFJVRSksMiksICIpIikNCnRhYlsyLDRdIDwtIHBhc3RlMChyb3VuZChtZWFuKGNkbiRtdWx0aXBsZXgsbmEucm09VFJVRSksMiksICIgKCIsIHJvdW5kKHNkKGNkbiRtdWx0aXBsZXgsbmEucm09VFJVRSksMiksICIpIikNCnRhYlszLDRdIDwtIHBhc3RlMChyb3VuZChtZWFuKHN0dWR5JG11bHRpcGxleCxuYS5ybT1UUlVFKSwyKSwgIiAoIiwgcm91bmQoc2Qoc3R1ZHkkbXVsdGlwbGV4LG5hLnJtPVRSVUUpLDIpLCAiKSIpDQp0YWJbNCw0XSA8LSBwYXN0ZTAocm91bmQobWVhbihiZmYkbXVsdGlwbGV4LG5hLnJtPVRSVUUpLDIpLCAiICgiLCByb3VuZChzZChiZmYkbXVsdGlwbGV4LG5hLnJtPVRSVUUpLDIpLCAiKSIpDQp0YWJbNSw0XSA8LSBwYXN0ZTAocm91bmQobWVhbihjc24kbXVsdGlwbGV4LG5hLnJtPVRSVUUpLDIpLCAiICgiLCByb3VuZChzZChjc24kbXVsdGlwbGV4LG5hLnJtPVRSVUUpLDIpLCAiKSIpDQoNCmtuaXRyOjprYWJsZSh0YWIsIGRpZ2l0cz0yLCAiaHRtbCIsIGNhcHRpb249IlJlbGF0aW9uYWwgY2hhcmFjdGVyaXN0aWNzIGFjcm9zcyByZWxhdGlvbmFsIGRpbWVuc2lvbnMgYXQgdDEgJF57YX0kIikgJT4lDQogIGthYmxlRXh0cmE6OmthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIikpICU+JQ0KICBrYWJsZUV4dHJhOjphZGRfZm9vdG5vdGUoYygiTWVhbnMgYW5kIHN0YW5kYXJkIGRldmlhdGlvbnMgaW4gcGFyZW50aGVzZXMuIiwgIlRvIGFjaGlldmUgYSBtZWFuaW5nZnVsIGludGVyY2VwdCBmb3Igb3VyIG11bHRpdmFyaWF0ZSBhbmFseXNlcywgd2Ugc3VidHJhY3RlZCBtdWx0aXBsZXhpdHkgYnkgb25lLiBJbiB0aGlzIGNvbnRleHQsIG11bHRpcGxleGl0eSByZXByZXNlbnRzIHRoZSBhdmVyYWdlIG51bWJlciBvZiBleHRyYSByZWxhdGlvbmFsIGRpbWVuc2lvbnMgZm9yIGVhY2ggdHlwZSBvZiByZWxhdGlvbnNoaXAuIiksIG5vdGF0aW9uPSJhbHBoYWJldCIpDQpgYGANCg0KPGJyPiANCg0KIyMjIHVuaXBsZXggdGllcw0KDQpgYGB7ciwgY2xhc3Muc291cmNlID0gJ2ZvbGQtaGlkZSd9DQpjZG4gPC0gZGF0YVtkYXRhJHRpZSA9PSAiQ29uZmlkYW50IiAmIGRhdGEkcGVyaW9kID09ICJ3MSAtPiB3MiIgJiBkYXRhJG11bHRpcGxleCA9PSAwLF0NCmJmZiA8LSBkYXRhW2RhdGEkdGllID09ICJGcmllbmQiICYgZGF0YSRwZXJpb2QgPT0gIncxIC0+IHcyIiAmIGRhdGEkbXVsdGlwbGV4ID09IDAsXQ0Kc3R1ZHkgPC0gZGF0YVtkYXRhJHRpZSA9PSAiU3R1ZHkiICYgZGF0YSRwZXJpb2QgPT0gIncxIC0+IHcyIiAmIGRhdGEkbXVsdGlwbGV4ID09IDAsXQ0KY3NuIDwtIGRhdGFbZGF0YSR0aWUgPT0gIlNwb3J0IiAmIGRhdGEkcGVyaW9kID09ICJ3MSAtPiB3MiIgJiBkYXRhJG11bHRpcGxleCA9PSAwLF0NCmRhdGFhIDwtIGRhdGFbZGF0YSRtdWx0aXBsZXg9PTAsXQ0KDQp0YWIgPC0gbWF0cml4KG5yb3c9NSwgbmNvbD00KQ0Kcm93bmFtZXModGFiKSA8LSBjKCIoVW5pcXVlKSBhbHRlcnMiLCANCiAgICAgICAgICAgICAgICAgICAiQ29uZmlkYW50cyIsIA0KICAgICAgICAgICAgICAgICAgICAiU3R1ZHkgcGFydG5lcnMiLA0KICAgICAgICAgICAgICAgICAgICJCZXN0IGZyaWVuZHMiLCANCiAgICAgICAgICAgICAgICAgICAiU3BvcnRzIHBhcnRuZXJzIikNCg0KY29sbmFtZXModGFiKSA8LSBjKCJuIiwgImNvbW11bmljYXRpb24gZnJlcS4iLCAiY2xvc2VuZXNzIiwgIm11bHRpcGxleGl0eSAkXntifSQiKQ0KDQp0YWJbMSwxXSA8LSBsZW5ndGgodW5pcXVlKGRhdGFhJGFsdGVyaWRbZGF0YWEkcGVyaW9kPT0idzEgLT4gdzIiXSkpDQp0YWJbMiwxXSA8LSBucm93KGNkbikNCnRhYlszLDFdIDwtIG5yb3coc3R1ZHkpDQp0YWJbNCwxXSA8LSBucm93KGJmZikNCnRhYls1LDFdIDwtIG5yb3coY3NuKQ0KDQp0YWJbMSwyXSA8LSBwYXN0ZTAocm91bmQobWVhbihkYXRhYSRmcmVxdWVuY3kudFt3aGljaCghZHVwbGljYXRlZChkYXRhYSRhbHRlcmlkW2RhdGFhJHBlcmlvZCA9PSJ3MSAtPiB3MiJdKSldLCBuYS5ybT1UUlVFKSwyKSwgIiAoIiwgcm91bmQoc2QoZGF0YWEkZnJlcXVlbmN5LnRbd2hpY2goIWR1cGxpY2F0ZWQoZGF0YWEkYWx0ZXJpZFtkYXRhYSRwZXJpb2QgPT0idzEgLT4gdzIiXSkpXSwgbmEucm09VFJVRSksMiksICIpIikNCnRhYlsyLDJdIDwtIHBhc3RlMChyb3VuZChtZWFuKGNkbiRmcmVxdWVuY3kudCxuYS5ybT1UUlVFKSwyKSwgIiAoIiwgcm91bmQoc2QoY2RuJGZyZXF1ZW5jeS50LG5hLnJtPVRSVUUpLDIpLCAiKSIpDQp0YWJbMywyXSA8LSBwYXN0ZTAocm91bmQobWVhbihzdHVkeSRmcmVxdWVuY3kudCxuYS5ybT1UUlVFKSwyKSwgIiAoIiwgcm91bmQoc2Qoc3R1ZHkkZnJlcXVlbmN5LnQsbmEucm09VFJVRSksMiksICIpIikNCnRhYls0LDJdIDwtIHBhc3RlMChyb3VuZChtZWFuKGJmZiRmcmVxdWVuY3kudCxuYS5ybT1UUlVFKSwyKSwgIiAoIiwgcm91bmQoc2QoYmZmJGZyZXF1ZW5jeS50LG5hLnJtPVRSVUUpLDIpLCAiKSIpDQp0YWJbNSwyXSA8LSBwYXN0ZTAocm91bmQobWVhbihjc24kZnJlcXVlbmN5LnQsbmEucm09VFJVRSksMiksICIgKCIsIHJvdW5kKHNkKGNzbiRmcmVxdWVuY3kudCxuYS5ybT1UUlVFKSwyKSwgIikiKQ0KDQp0YWJbMSwzXSA8LSAgcGFzdGUwKHJvdW5kKG1lYW4oZGF0YWEkY2xvc2VuZXNzLnRbd2hpY2goIWR1cGxpY2F0ZWQoZGF0YWEkYWx0ZXJpZFtkYXRhJHBlcmlvZCA9PSJ3MSAtPiB3MiJdKSldLCBuYS5ybT1UUlVFKSwyKSwgIiAoIiwgcm91bmQoc2QoZGF0YWEkY2xvc2VuZXNzLnRbd2hpY2goIWR1cGxpY2F0ZWQoZGF0YWEkYWx0ZXJpZFtkYXRhJHBlcmlvZCA9PSJ3MSAtPiB3MiJdKSldLCBuYS5ybT1UUlVFKSwyKSwgIikiKQ0KdGFiWzIsM10gPC0gcGFzdGUwKHJvdW5kKG1lYW4oY2RuJGNsb3NlbmVzcy50LG5hLnJtPVRSVUUpLDIpLCAiICgiLCByb3VuZChzZChjZG4kY2xvc2VuZXNzLnQsbmEucm09VFJVRSksMiksICIpIikNCnRhYlszLDNdIDwtIHBhc3RlMChyb3VuZChtZWFuKHN0dWR5JGNsb3NlbmVzcy50LG5hLnJtPVRSVUUpLDIpLCAiICgiLCByb3VuZChzZChzdHVkeSRjbG9zZW5lc3MudCxuYS5ybT1UUlVFKSwyKSwgIikiKQ0KdGFiWzQsM10gPC0gcGFzdGUwKHJvdW5kKG1lYW4oYmZmJGNsb3NlbmVzcy50LG5hLnJtPVRSVUUpLDIpLCAiICgiLCByb3VuZChzZChiZmYkY2xvc2VuZXNzLnQsbmEucm09VFJVRSksMiksICIpIikNCnRhYls1LDNdIDwtIHBhc3RlMChyb3VuZChtZWFuKGNzbiRjbG9zZW5lc3MudCxuYS5ybT1UUlVFKSwyKSwgIiAoIiwgcm91bmQoc2QoY3NuJGNsb3NlbmVzcy50LG5hLnJtPVRSVUUpLDIpLCAiKSIpDQoNCnRhYlsxLDRdIDwtIHBhc3RlMChyb3VuZChtZWFuKGRhdGFhJG11bHRpcGxleFt3aGljaCghZHVwbGljYXRlZChkYXRhYSRhbHRlcmlkW2RhdGEkcGVyaW9kID09IncxIC0+IHcyIl0pKV0sIG5hLnJtPVRSVUUpLDIpLCAiICgiLCByb3VuZChzZChkYXRhYSRtdWx0aXBsZXhbd2hpY2goIWR1cGxpY2F0ZWQoZGF0YWEkYWx0ZXJpZFtkYXRhJHBlcmlvZCA9PSJ3MSAtPiB3MiJdKSldLCBuYS5ybT1UUlVFKSwyKSwgIikiKQ0KdGFiWzIsNF0gPC0gcGFzdGUwKHJvdW5kKG1lYW4oY2RuJG11bHRpcGxleCxuYS5ybT1UUlVFKSwyKSwgIiAoIiwgcm91bmQoc2QoY2RuJG11bHRpcGxleCxuYS5ybT1UUlVFKSwyKSwgIikiKQ0KdGFiWzMsNF0gPC0gcGFzdGUwKHJvdW5kKG1lYW4oc3R1ZHkkbXVsdGlwbGV4LG5hLnJtPVRSVUUpLDIpLCAiICgiLCByb3VuZChzZChzdHVkeSRtdWx0aXBsZXgsbmEucm09VFJVRSksMiksICIpIikNCnRhYls0LDRdIDwtIHBhc3RlMChyb3VuZChtZWFuKGJmZiRtdWx0aXBsZXgsbmEucm09VFJVRSksMiksICIgKCIsIHJvdW5kKHNkKGJmZiRtdWx0aXBsZXgsbmEucm09VFJVRSksMiksICIpIikNCnRhYls1LDRdIDwtIHBhc3RlMChyb3VuZChtZWFuKGNzbiRtdWx0aXBsZXgsbmEucm09VFJVRSksMiksICIgKCIsIHJvdW5kKHNkKGNzbiRtdWx0aXBsZXgsbmEucm09VFJVRSksMiksICIpIikNCg0Ka25pdHI6OmthYmxlKHRhYiwgZGlnaXRzPTIsICJodG1sIiwgY2FwdGlvbj0iUmVsYXRpb25hbCBjaGFyYWN0ZXJpc3RpY3Mgb2YgdW5pcGxleCB0aWVzLCBhY3Jvc3MgcmVsYXRpb25hbCBkaW1lbnNpb25zIGF0IHQxICRee2F9JCIpICU+JQ0KICBrYWJsZUV4dHJhOjprYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIpKSAlPiUNCiAga2FibGVFeHRyYTo6YWRkX2Zvb3Rub3RlKGMoIk1lYW5zIGFuZCBzdGFuZGFyZCBkZXZpYXRpb25zIGluIHBhcmVudGhlc2VzLiIsICJUbyBhY2hpZXZlIGEgbWVhbmluZ2Z1bCBpbnRlcmNlcHQgZm9yIG91ciBtdWx0aXZhcmlhdGUgYW5hbHlzZXMsIHdlIHN1YnRyYWN0ZWQgbXVsdGlwbGV4aXR5IGJ5IG9uZS4gSW4gdGhpcyBjb250ZXh0LCBtdWx0aXBsZXhpdHkgcmVwcmVzZW50cyB0aGUgYXZlcmFnZSBudW1iZXIgb2YgZXh0cmEgcmVsYXRpb25hbCBkaW1lbnNpb25zIGZvciBlYWNoIHR5cGUgb2YgcmVsYXRpb25zaGlwLiIpLCBub3RhdGlvbj0iYWxwaGFiZXQiKQ0KYGBgDQoNCg0KIyMgey51bmxpc3RlZCAudW5udW1iZXJlZH0NCg0KLS0tDQoNCjxicj4NCg0KDQojIyBSb2xlIG92ZXJsYXAgey50YWJzZXQgLnRhYnNldC1mYWRlfQ0KDQojIyMgd2F2ZSAxDQoNCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1oaWRlJ30NCngxIDwtIGxpc3QoDQogICdCZXN0IGZyaWVuZCcgPSBkYXRhJGFsdGVyaWRbZGF0YSRiZmYgPT0gMSAmIGRhdGEkcGVyaW9kID09ICJ3MSAtPiB3MiJdLA0KICAnQ29uZmlkYW50JyA9IGRhdGEkYWx0ZXJpZFtkYXRhJGNkbiA9PSAxICYgZGF0YSRwZXJpb2QgPT0gIncxIC0+IHcyIl0sDQogIA0KICAnU3BvcnRzIHBhcnRuZXInID0gZGF0YSRhbHRlcmlkW2RhdGEkY3NuID09IDEgJiBkYXRhJHBlcmlvZCA9PSAidzEgLT4gdzIiXSwNCiAgJ1N0dWR5IHBhcnRuZXInID0gZGF0YSRhbHRlcmlkW2RhdGEkc3R1ZHkgPT0gMSAmIGRhdGEkcGVyaW9kID09ICJ3MSAtPiB3MiJdDQopDQoNCg0KKHZlbm4gPC0gZ2dWZW5uRGlhZ3JhbSh4MSwgbGFiZWwgPSAicGVyY2VudCIsIGxhYmVsX3NpemUgPSAzLCBsYWJlbF9wZXJjZW50X2RpZ2l0ID0gMSwgc2V0X3NpemUgPSAzLCBzaG93X2ludGVyc2VjdCA9IEZBTFNFKSArIA0KICAgIHNjYWxlX2ZpbGxfZGlzdGlsbGVyKHBhbGV0dGUgPSAiT3JSZCIsIGRpcmVjdGlvbiA9IDEpICsNCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLCBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgKw0KICAgIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IC4yKSkgKw0KICAgIGxhYnMoZmlsbCA9ICJBbHRlciBjb3VudCIpKQ0KDQojZ2dzYXZlKHZlbm4sIGZpbGVuYW1lID0gIi4vZmlndXJlcy92ZW5uMS5wbmciKQ0KDQojP2dnVmVubkRpYWdyYW0NCmBgYA0KDQojIyMgd2F2ZSAyDQoNCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1oaWRlJ30NCngyIDwtIGxpc3QoDQogICAnQmVzdCBGcmllbmQnID0gZGF0YSRhbHRlcmlkW2RhdGEkYmZmID09IDEgJiBkYXRhJHBlcmlvZCA9PSAidzIgLT4gdzMiXSwNCiAgICAgJ0NvbmZpZGFudCcgPSBkYXRhJGFsdGVyaWRbZGF0YSRjZG4gPT0gMSAmIGRhdGEkcGVyaW9kID09ICJ3MiAtPiB3MyJdLA0KICAnU3BvcnRzIHBhcnRuZXInID0gZGF0YSRhbHRlcmlkW2RhdGEkY3NuID09IDEgJiBkYXRhJHBlcmlvZCA9PSAidzIgLT4gdzMiXSwNCiAgJ1N0dWR5IHBhcnRuZXInID0gZGF0YSRhbHRlcmlkW2RhdGEkc3R1ZHkgPT0gMSAmIGRhdGEkcGVyaW9kID09ICJ3MiAtPiB3MyJdDQopDQoNCg0KKHZlbm4gPC0gZ2dWZW5uRGlhZ3JhbSh4MiwgbGFiZWwgPSAicGVyY2VudCIsIGxhYmVsX3NpemUgPSAzLCBsYWJlbF9wZXJjZW50X2RpZ2l0ID0gMSwgc2V0X3NpemUgPSAzLCBzaG93X2ludGVyc2VjdCA9IEZBTFNFKSArIA0KICAgIHNjYWxlX2ZpbGxfZGlzdGlsbGVyKHBhbGV0dGUgPSAiT3JSZCIsIGRpcmVjdGlvbiA9IDEpICsNCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLCBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgKw0KICAgIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IC4yKSkgKw0KICAgIGxhYnMoZmlsbCA9ICJBbHRlciBjb3VudCIpKQ0KDQpgYGANCg0KIyMgey51bmxpc3RlZCAudW5udW1iZXJlZH0NCg0KDQotLS0tLQ0KDQo8YnI+IA0KDQoNCiMjIFRpZSBtYWludGVuYW5jZQ0KDQoNCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1oaWRlJ30NCiNtYWtlIHRhYmxlDQp0YWIgPC0gbWF0cml4KG5yb3c9NSwgbmNvbD0yKQ0Kcm93bmFtZXModGFiKSA8LSBjKCJBbGwgKHVuaXF1ZSkgdGllcyIsDQogICAgICAgICAgICAgICAgICAgIkNvbmZpZGFudHMiLA0KICAgICAgICAgICAgICAgICAgICJCZXN0IGZyaWVuZHMiLA0KICAgICAgICAgICAgICAgICAgICJTdHVkeSBwYXJ0bmVycyIsDQogICAgICAgICAgICAgICAgICAgIlNwb3J0cyBwYXJ0bmVycyINCiAgICAgICAgICAgICAgICAgICApDQpjb2xuYW1lcyh0YWIpIDwtIGMoIm4iLCAiUmVsaXN0ZWQiKQ0KDQoNCmJmZiA8LSBkYXRhW2RhdGEkdGllID09ICJGcmllbmQiLF0NCmNkbiA8LSBkYXRhW2RhdGEkdGllID09ICJDb25maWRhbnQiLF0NCnN0dWR5IDwtIGRhdGFbZGF0YSR0aWUgPT0gIlN0dWR5IixdDQpjc24gPC0gZGF0YVtkYXRhJHRpZSA9PSAiU3BvcnQiLF0NCg0KdGFiWzEsMV0gPC0gbnJvdyhkYXRhKQ0KdGFiWzIsMV0gPC0gbnJvdyhjZG4pDQp0YWJbMywxXSA8LSBucm93KGJmZikNCnRhYls0LDFdIDwtIG5yb3coc3R1ZHkpDQp0YWJbNSwxXSA8LSBucm93KGNzbikNCg0KdGFiWzEsMl0gPC0gcm91bmQocHJvcC50YWJsZSh0YWJsZShkYXRhJFkpKVtbMl1dLDIpDQp0YWJbMiwyXSA8LSByb3VuZChwcm9wLnRhYmxlKHRhYmxlKGNkbiRZKSlbWzJdXSwyKQ0KdGFiWzMsMl0gPC0gcm91bmQocHJvcC50YWJsZSh0YWJsZShiZmYkWSkpW1syXV0sMikNCnRhYls0LDJdIDwtIHJvdW5kKHByb3AudGFibGUodGFibGUoc3R1ZHkkWSkpW1syXV0sMikNCnRhYls1LDJdIDwtIHJvdW5kKHByb3AudGFibGUodGFibGUoY3NuJFkpKVtbMl1dLDIpDQoNCm9wdGlvbnMoa25pdHIua2FibGUuTkE9JycpDQoNCmtuaXRyOjprYWJsZSh0YWIsIGRpZ2l0cz0yLCAiaHRtbCIsIGNhcHRpb249Ik1haW50ZW5hbmNlIG9mIG11bHRpcGxlIHNvY2lhbCB0aWVzIG92ZXIgdGltZSBhbW9uZyA1MTMgc3R1ZGVudHMiKSAlPiUNCiAga2FibGVFeHRyYTo6a2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiKSkNCmBgYA0KDQotLS0tDQoNCjxicj4NCg0KIyMgVGllIG1haW50ZW5hbmNlIHZzIHNpbWlsYXJpdHkgDQoNCg0KYGBge3IsIGNsYXNzLnNvdXJjZSA9ICdmb2xkLWhpZGUnLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIzEuIHNpbWlsYXJpdGllcyB2cyB0aWUgbG9zcywgcGVyIGRpbWVuc2lvbg0KcGxvdGRhdGExIDwtIGRhdGFbLGMoImR1cmF0aW9uIiwgInNhbWVfZ2VuZGVyIiwgIlkiLCAidGllIildDQpwbG90ZGF0YTEkc2FtZSA8LSBpZmVsc2UocGxvdGRhdGExJHNhbWVfZ2VuZGVyPT0xLDEsMCkNCnBsb3RkYXRhMSRkaW1lbnNpb24gPC0gIkdlbmRlciINCg0KcGxvdGRhdGEyIDwtIGRhdGFbLGMoImR1cmF0aW9uIiwgInNpbV9lZHVjIiwgIlkiLCAidGllIildDQpwbG90ZGF0YTIkc2FtZSA8LSBpZmVsc2UocGxvdGRhdGEyJHNpbV9lZHVjPT0xLDEsMCkNCnBsb3RkYXRhMiRkaW1lbnNpb24gPC0gIkVkdWNhdGlvbiINCg0KcGxvdGRhdGEzIDwtIGRhdGFbLGMoImR1cmF0aW9uIiwgImRpZl9hZ2UiLCAiWSIsICJ0aWUiKV0NCnBsb3RkYXRhMyRzYW1lIDwtIGlmZWxzZShwbG90ZGF0YTMkZGlmX2FnZSA8IDQsIDEsIDApDQpwbG90ZGF0YTMkZGltZW5zaW9uIDwtICJBZ2UiDQoNCnBsb3RkYXRhMSA8LSBwbG90ZGF0YTFbLC0yXQ0KcGxvdGRhdGEyIDwtIHBsb3RkYXRhMlssLTJdDQpwbG90ZGF0YTMgPC0gcGxvdGRhdGEzWywtMl0NCnBsb3RkYXRhIDwtIHJiaW5kKHBsb3RkYXRhMSxwbG90ZGF0YTIscGxvdGRhdGEzKQ0KcGxvdGRhdGEkc2FtZSA8LSBmYWN0b3IocGxvdGRhdGEkc2FtZSkNCg0KI2NhbGN1bGF0ZSB0aWUgbG9zcyByYXRlIGZvciBzaW1pbGFyaXR5IGRpbWVuc2lvbnMNCm1lYW5zIDwtIGFnZ3JlZ2F0ZShZIH4gc2FtZSArIGRpbWVuc2lvbiwgZGF0YSA9IHBsb3RkYXRhLCBGVU4gPSAibWVhbiIpDQpzZCA8LSBhZ2dyZWdhdGUoWSB+IHNhbWUgKyBkaW1lbnNpb24sIGRhdGEgPSBwbG90ZGF0YSwgRlVOID0gInNkIikNCm4gPC0gYWdncmVnYXRlKFkgfiBzYW1lICsgZGltZW5zaW9uLCBkYXRhID1wbG90ZGF0YSwgRlVOID0gInN1bSIpDQptZWFucyA8LSBjYmluZChtZWFucywgc2Q9c2QkWSwgbj1uJFkpDQoNCiNjYWxjdWxhdGUgYSBjb25maWRlbmNlIGludGVydmFsIGFyb3VuZCB0aGlzIHByb3BvcnRpb24sDQojdXNpbmd0aGUgQ2xvcHBlci1QZWFyc29uIENvbmZpZGVuY2UgSW50ZXJ2YWwgIA0KbWVhbnMkTEwgPC0gTkENCm1lYW5zJFVMIDwtIE5BDQoNCmZvciAoaSBpbiAxOm5yb3cobWVhbnMpKSB7DQogIGNwLmNpIDwtIEdlbkJpbm9tQXBwczo6Y2xvcHBlci5wZWFyc29uLmNpKA0KICAgIGsgPSByb3VuZChtZWFucyRZW2ldICogbWVhbnMkbltpXSksDQogICAgbiA9IG1lYW5zJG5baV0sDQogICAgYWxwaGEgPSAwLjA1LA0KICAgIENJPSJ0d28uc2lkZWQiDQogICkNCiAgbWVhbnMkTExbaV0gPC0gY3AuY2kkTG93ZXIubGltaXQNCiAgbWVhbnMkVUxbaV0gPC0gY3AuY2kkVXBwZXIubGltaXQNCn0NCg0KDQpwbG90MSA8LSBnZ3Bsb3QobWVhbnMsIGFlcyh4ID0gc2FtZSwgeSA9IFksIGZpbGwgPSBhcy5mYWN0b3Ioc2FtZSkpKSArDQogIGZhY2V0X3dyYXAofmRpbWVuc2lvbikgKyANCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIiwgd2lkdGggPSAuNzUpICsNCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbiA9IExMLCB5bWF4ID0gVUwpLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC41KSwgd2lkdGg9MC4yNSkgKyBsYWJzICh4ID0gTlVMTCwgeSA9ICJQcm9wLiBtYWludGFpbmVkIiwgZmlsbCA9ICJTaW1pbGFyaXR5IiwgdGl0bGUgPSAiKEEpIE1haW50ZW5hbmNlIG9mIGFsdGVyLXRpZXMgb2Ygc2VsZi1zaW1pbGFyIHZzLiBkaXNzaW1pbGFyIGFsdGVycyIsZm9udCA9ICJKb3N0IikgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDEsIC4yNSksIGxpbWl0cyA9IGMoMCwxKSkgKw0KICB0aGVtZV9idygpICsNCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpDQoNCiMgMi4gZGlzc2FncmVnYXRlIGJ5IHJlbGF0aW9uc2hpcCBkdXJhdGlvbg0KDQojY2FsY3VsYXRlIHRpZSBsb3NzIHJhdGUgZm9yIHNpbWlsYXJpdHkgZGltZW5zaW9ucw0KI21lYW5zIDwtIGFnZ3JlZ2F0ZShZIH4gc2FtZSArIGRpbWVuc2lvbiArIGR1cmF0aW9uLCBkYXRhID0gcGxvdGRhdGEsIEZVTiA9ICJtZWFuIikNCiNzZCA8LSBhZ2dyZWdhdGUoWSB+IHNhbWUgKyBkaW1lbnNpb24gKyBkdXJhdGlvbiwgZGF0YSA9IHBsb3RkYXRhLCBGVU4gPSAic2QiKQ0KI24gPC0gYWdncmVnYXRlKFkgfiBzYW1lICsgZGltZW5zaW9uICsgZHVyYXRpb24sIGRhdGEgPXBsb3RkYXRhLCBGVU4gPSAic3VtIikNCiNtZWFucyA8LSBjYmluZChtZWFucywgc2Q9c2QkWSwgbj1uJFkpDQoNCiNjYWxjdWxhdGUgYSBjb25maWRlbmNlIGludGVydmFsIGFyb3VuZCB0aGlzIHByb3BvcnRpb24sDQojdXNpbmd0aGUgQ2xvcHBlci1QZWFyc29uIENvbmZpZGVuY2UgSW50ZXJ2YWwgIA0KI21lYW5zJExMIDwtIE5BDQojbWVhbnMkVUwgPC0gTkENCg0KI2ZvciAoaSBpbiAxOm5yb3cobWVhbnMpKSB7DQojICBjcC5jaSA8LSBHZW5CaW5vbUFwcHM6OmNsb3BwZXIucGVhcnNvbi5jaSgNCiMgICAgayA9IHJvdW5kKG1lYW5zJFlbaV0gKiBtZWFucyRuW2ldKSwNCiMgICAgbiA9IG1lYW5zJG5baV0sDQojICAgIGFscGhhID0gMC4wNSwNCiMgICAgQ0k9InR3by5zaWRlZCINCiMgICkNCiMgIG1lYW5zJExMW2ldIDwtIGNwLmNpJExvd2VyLmxpbWl0DQojICBtZWFucyRVTFtpXSA8LSBjcC5jaSRVcHBlci5saW1pdA0KI30NCg0KI2R1cmF0aW9uX25hbWVzIDwtIGMoDQojICAgICAgICAgICAgICAgICAgICBgMGAgPSAiVW5kZXIgMSB5ZWFyIiwNCiMgICAgICAgICAgICAgICAgICAgIGAyYCA9ICIxLTMgeWVhcnMiLA0KIyAgICAgICAgICAgICAgICAgICAgYDZgID0gIjQtOCB5ZWFycyIsDQojICAgICAgICAgICAgICAgICAgICBgMTJgID0gIjktMTUgeWVhcnMiLA0KIyAgICAgICAgICAgICAgICAgICAgYDE1YCA9ICJPdmVyIDE1IHllYXJzIg0KIyAgICAgICAgICAgICAgICAgICAgKQ0KDQojcGxvdDIgPC0gZ2dwbG90KG1lYW5zLCBhZXMoeCA9IGRpbWVuc2lvbiwgeSA9IFksIGZpbGwgPSBhcy5mYWN0b3Ioc2FtZSkpKSArDQojICBmYWNldF93cmFwKH4gZHVyYXRpb24sIGxhYmVsbGVyID0gYXNfbGFiZWxsZXIoZHVyYXRpb25fbmFtZXMpLCBucm93ID0gMSkgKw0KIyAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIiwgd2lkdGggPSAwLjcpICsNCiMgIGdlb21fZXJyb3JiYXIoYWVzKHltaW4gPSBMTCwgeW1heCA9IFVMKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNzUpLCAjd2lkdGg9MC4yNSkgKw0KIyAgbGFicyAoeCA9IE5VTEwsIHkgPSAiUHJvcC4gbWFpbnRhaW5lZCIsIGZpbGwgPSAiU2ltaWxhcml0eSIsIHRpdGxlID0gIihCKSBEaXNhZ2dyZWdhdGVkIGJ5OiAjdGllIGR1cmF0aW9uIiwgZm9udCA9ICJKb3N0IikgKw0KIyAgIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgMSwgLjI1KSwgbGltaXRzID0gYygwLDEpKSArDQojICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDMzLCBoanVzdCA9IDEpKQ0KDQojdGhpcyBpcyBtb3JlIGluZm9ybWF0aXZlLiB0byBzaG93IGNvbnZlcmdlbmNlIGVmZmVjdHMNCiNwbG90MiA8LSBnZ3Bsb3QobWVhbnMsIGFlcyh4ID0gYXMuZmFjdG9yKGR1cmF0aW9uKSwgeSA9IFksIGZpbGwgPSBhcy5mYWN0b3Ioc2FtZSkpKSArDQojICBmYWNldF93cmFwKH4gZGltZW5zaW9uLCBucm93ID0gMSkgKw0KIyAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIiwgd2lkdGggPSAuNykgKw0KIyAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbiA9IExMLCB5bWF4ID0gVUwpLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC43NSksICN3aWR0aD0wLjI1KSArDQojICBsYWJzICh4ID0gTlVMTCwgeSA9ICJQcm9wLiBtYWludGFpbmVkIiwgZmlsbCA9ICJTaW1pbGFyaXR5IiwgdGl0bGUgPSAiKEIpIENvbnZlcmdlbmNlIG9mICN0aWUgbWFpbnRlbmFuY2UgcmF0ZXMgd2l0aCBzaW1pbGFyIHZzLiBkaXNzaW1pbGFyIGFsdGVycyBvdmVyIHRpbWUiLGZvbnQgPSAiSm9zdCIpICsNCiMgICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDEsIC4yNSksIGxpbWl0cyA9IGMoMCwxKSkgKw0KIyAgICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IGMoICI8MSIsICIxLTMiLCAiNC04IiwgIjktMTUiLCAiPjE1IikpICsNCiMgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMzMsIGhqdXN0ID0gMSksIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCg0KIyBwZXIgcmVsYXRpb25zaGlwIHR5cGUNCg0KI2NhbGN1bGF0ZSB0aWUgbG9zcyByYXRlIGZvciBzaW1pbGFyaXR5IGRpbWVuc2lvbnMNCm1lYW5zIDwtIGFnZ3JlZ2F0ZShZIH4gc2FtZSArIGRpbWVuc2lvbiArIHRpZSwgZGF0YSA9IHBsb3RkYXRhLCBGVU4gPSAibWVhbiIpDQpzZCA8LSBhZ2dyZWdhdGUoWSB+IHNhbWUgKyBkaW1lbnNpb24gKyB0aWUsIGRhdGEgPSBwbG90ZGF0YSwgRlVOID0gInNkIikNCm4gPC0gYWdncmVnYXRlKFkgfiBzYW1lICsgZGltZW5zaW9uICsgdGllLCBkYXRhID1wbG90ZGF0YSwgRlVOID0gInN1bSIpDQptZWFucyA8LSBjYmluZChtZWFucywgc2Q9c2QkWSwgbj1uJFkpDQoNCiNjYWxjdWxhdGUgYSBjb25maWRlbmNlIGludGVydmFsIGFyb3VuZCB0aGlzIHByb3BvcnRpb24sDQojdXNpbmd0aGUgQ2xvcHBlci1QZWFyc29uIENvbmZpZGVuY2UgSW50ZXJ2YWwgIA0KbWVhbnMkTEwgPC0gTkENCm1lYW5zJFVMIDwtIE5BDQoNCmZvciAoaSBpbiAxOm5yb3cobWVhbnMpKSB7DQogIGNwLmNpIDwtIEdlbkJpbm9tQXBwczo6Y2xvcHBlci5wZWFyc29uLmNpKA0KICAgIGsgPSByb3VuZChtZWFucyRZW2ldICogbWVhbnMkbltpXSksDQogICAgbiA9IG1lYW5zJG5baV0sDQogICAgYWxwaGEgPSAwLjA1LA0KICAgIENJPSJ0d28uc2lkZWQiDQogICkNCiAgbWVhbnMkTExbaV0gPC0gY3AuY2kkTG93ZXIubGltaXQNCiAgbWVhbnMkVUxbaV0gPC0gY3AuY2kkVXBwZXIubGltaXQNCn0NCg0KbWVhbnMkdGllW21lYW5zJHRpZSA9PSAiRnJpZW5kIl0gPC0gIkJlc3QgZnJpZW5kIg0KDQpwbG90MyA8LSBnZ3Bsb3QobWVhbnMsIGFlcyh4ID0gdGllLCB5ID0gWSwgZmlsbCA9IGFzLmZhY3RvcihzYW1lKSkpICsNCiAgZmFjZXRfd3JhcCh+IGRpbWVuc2lvbiwgbnJvdyA9IDEpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIiwgd2lkdGggPSAwLjcpICsNCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbiA9IExMLCB5bWF4ID0gVUwpLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC43NSksIHdpZHRoPTAuMjUpICsNCiAgbGFicyAoeCA9IE5VTEwsIHkgPSAiUHJvcC4gbWFpbnRhaW5lZCIsIGZpbGwgPSAiU2ltaWxhcml0eSIsIHRpdGxlID0gIihCKSBEaWZmZXJlbmNlcyBiZXR3ZWVuIHNvY2lhbCByb2xlcyIsIGZvbnQgPSAiSm9zdCIpICsNCiAgIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgMSwgLjI1KSwgbGltaXRzID0gYygwLDEpKSArDQogIHRoZW1lX2J3KCkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDMzLCBoanVzdCA9IDEpLCBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQoNCihmaWd1cmUgPC0gZ2dwdWJyOjpnZ2FycmFuZ2UocGxvdDEsIHBsb3QzLCBuY29sPTEsIG5yb3c9MikgKQ0KDQojZ2dzYXZlKGZpZ3VyZSwgZmlsZW5hbWUgPSAiLi9maWd1cmVzL2Rlc2ZpZy5wbmciKQ0KDQpgYGANCg0KPGJyPg0KDQpDb25maWRhbnRzIHdpdGggYSBkaWZmZXJlbnQgZ2VuZGVyIHRoYW4gZWdvIGFyZSAqKm1vcmUqKiwgcmF0aGVyIHRoYW4gbGVzcyBzdGFibGUhDQoNCk91ciBwb3N0LWhvYyBoeXBvdGhlc2lzIGlzIHRoYXQgdGhpcyBtYXkgYmUgZHVlIHRvIHdvbWVuIGdlbmVyYWxseSBwcm92aWRpbmcgbW9yZSBzb2NpYWwgc3VwcG9ydCB0aGFuIG1lbiBbQHdlbGxtYW5dLCBtYWtpbmcgdGhlbSB2YWx1YWJsZSBjb25maWRhbnRzIGFuZCB0aHVzIGxlc3MgbGlrZWx5IHRvIGJlIGRpc3NvbHZlZCwgcmVzdWx0aW5nIGluIGEgbmVnYXRpdmUgZGlmZmVyZW50LWdlbmRlciBlZmZlY3Qgb24gY29uZmlkYW50IGxvc3MgYW1vbmcgbWVuLg0KDQpgYGB7ciwgIGNsYXNzLnNvdXJjZSA9ICdmb2xkLWhpZGUnfQ0KI3Byb3AudGFibGUodGFibGUoZGF0YSRkaWZmZXJlbnRfZ2VuZGVyKSkgIzc0JSBvZiB0aWVzIGFyZSBzYW1lLWdlbmRlcg0KDQojbGV0J3Mgc2VlIGhvdyB0aGlzIGRpZmZlcnMgYWNyb3NzIHRoZSB0aWVzLCBhbmQgZnVydGhlciBkaXNhZ2dyZWdhdGVkIGJ5IHRoZSBnZW5kZXJzOg0KdGFiIDwtIG1hdHJpeChjKA0KICBtZWFuKGRhdGEkc2FtZV9nZW5kZXJbZGF0YSR0aWUgPT0gIkNvbmZpZGFudCIgJiBkYXRhJGVnb19mZW1hbGUgPT0gMV0pLA0KICBtZWFuKGRhdGEkc2FtZV9nZW5kZXJbZGF0YSR0aWUgPT0gIkNvbmZpZGFudCIgJiBkYXRhJGVnb19mZW1hbGUgPT0gMF0pLA0KICBtZWFuKGRhdGEkc2FtZV9nZW5kZXJbZGF0YSR0aWUgPT0gIkZyaWVuZCIgJiAgZGF0YSRlZ29fZmVtYWxlID09IDFdKSwNCiAgbWVhbihkYXRhJHNhbWVfZ2VuZGVyW2RhdGEkdGllID09ICJGcmllbmQiICYgZGF0YSRlZ29fZmVtYWxlID09IDBdKSwNCiAgbWVhbihkYXRhJHNhbWVfZ2VuZGVyW2RhdGEkdGllID09ICJTdHVkeSIgJiBkYXRhJGVnb19mZW1hbGUgPT0gMV0pLA0KICBtZWFuKGRhdGEkc2FtZV9nZW5kZXJbZGF0YSR0aWUgPT0gIlN0dWR5IiAmIGRhdGEkZWdvX2ZlbWFsZSA9PSAwXSksDQogIG1lYW4oZGF0YSRzYW1lX2dlbmRlcltkYXRhJHRpZSA9PSAiU3BvcnQiICYgZGF0YSRlZ29fZmVtYWxlID09IDFdKSwNCiAgbWVhbihkYXRhJHNhbWVfZ2VuZGVyW2RhdGEkdGllID09ICJTcG9ydCIgJiBkYXRhJGVnb19mZW1hbGUgPT0gMF0pKSwgDQogIG5yb3cgPSA0LCBieXJvdyA9IFRSVUUpDQoNCnJvd25hbWVzKHRhYikgPC0gYygiQ29uZmlkYW50IiwgIkJlc3QgZnJpZW5kcyIsICJTdHVkeSBwYXJ0bmVyIiwgIlNwb3J0cyBwYXJ0bmVyIikNCmNvbG5hbWVzKHRhYikgPC0gYygiRmVtYWxlIiwgIk1hbGUiKQ0KDQprbml0cjo6a2FibGUodGFiLCBkaWdpdHM9MiwgImh0bWwiLCBjYXB0aW9uPSJQcm9wb3J0aW9uIG9mIHNhbWUgZ2VuZGVyIHRpZXMsIGFjcm9zcyBkaWZmZXJlbnQgdGllIHR5cGVzLCBkaXNhZ2dyZWdhdGVkIGJ5IGdlbmRlciIpICU+JQ0KICBrYWJsZUV4dHJhOjprYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIpKSANCg0KYGBgIA0KDQoxLiBXZSBvYnNlcnZlIHRoYXQgbWVuIHRlbmQgdG8gaGF2ZSBtb3JlIGNyb3NzLWdlbmRlciBjb25maWRpbmcgdGllcyAoNzMlKSB0aGFuIGRvIHdvbWVuICg1NSUpLg0KDQo8YnI+DQoNCmBgYHtyLCBjbGFzcy5zb3VyY2U9J2ZvbGQtaGlkZScsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQojc3Vic2V0IHJlbGV2YW50IGNvbHVtbnMNCnBsb3RkYXRhIDwtIGRhdGFbLGMoInNhbWVfZ2VuZGVyIiwgIlkiLCAidGllIiwgImVnb19mZW1hbGUiKV0NCg0KI2ZpbHRlciBvbiBjb25maWRhbnRzDQpwbG90ZGF0YSA8LSBwbG90ZGF0YVtwbG90ZGF0YSR0aWUgPT0gIkNvbmZpZGFudCIsXQ0KDQojY2FsY3VsYXRlIHRpZSBtYWludGVuYW5jZSByYXRlDQptZWFucyA8LSBhZ2dyZWdhdGUoWSB+IHNhbWVfZ2VuZGVyICsgZWdvX2ZlbWFsZSwgZGF0YSA9IHBsb3RkYXRhLCBGVU4gPSAibWVhbiIpDQpzZCA8LSBhZ2dyZWdhdGUoWSB+IHNhbWVfZ2VuZGVyICsgZWdvX2ZlbWFsZSwgZGF0YSA9IHBsb3RkYXRhLCBGVU4gPSAic2QiKQ0KbiA8LSBhZ2dyZWdhdGUoWSB+IHNhbWVfZ2VuZGVyICsgZWdvX2ZlbWFsZSwgZGF0YSA9IHBsb3RkYXRhLCBGVU4gPSAic3VtIikNCg0KI2JpbmQNCm1lYW5zIDwtIGNiaW5kKG1lYW5zLCBzZD1zZCRZLCBuPW4kWSkNCm1lYW5zJGVnb19mZW1hbGUgPC0gaWZlbHNlKG1lYW5zJGVnb19mZW1hbGU9PTEsICJXb21lbiIsICJNZW4iKQ0KDQojY2FsY3VsYXRlIGEgY29uZmlkZW5jZSBpbnRlcnZhbCBhcm91bmQgdGhpcyBwcm9wb3J0aW9uLA0KI3VzaW5ndGhlIENsb3BwZXItUGVhcnNvbiBDb25maWRlbmNlIEludGVydmFsICANCm1lYW5zJExMIDwtIE5BDQptZWFucyRVTCA8LSBOQQ0KDQpmb3IgKGkgaW4gMTpucm93KG1lYW5zKSkgew0KICBjcC5jaSA8LSBHZW5CaW5vbUFwcHM6OmNsb3BwZXIucGVhcnNvbi5jaSgNCiAgICBrID0gcm91bmQobWVhbnMkWVtpXSAqIG1lYW5zJG5baV0pLA0KICAgIG4gPSBtZWFucyRuW2ldLA0KICAgIGFscGhhID0gMC4wNSwNCiAgICBDST0idHdvLnNpZGVkIg0KICApDQogIG1lYW5zJExMW2ldIDwtIGNwLmNpJExvd2VyLmxpbWl0DQogIG1lYW5zJFVMW2ldIDwtIGNwLmNpJFVwcGVyLmxpbWl0DQp9DQoNCmdncGxvdChtZWFucywgYWVzKHggPSBzYW1lX2dlbmRlciwgeSA9IFksIGZpbGwgPSBhcy5mYWN0b3Ioc2FtZV9nZW5kZXIpKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZG9kZ2UiLCB3aWR0aCA9IC43NSkgKw0KICBmYWNldF93cmFwKH5lZ29fZmVtYWxlKSArDQogIGdlb21fZXJyb3JiYXIoYWVzKHltaW4gPSBMTCwgeW1heCA9IFVMKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNSksIHdpZHRoPTAuMjUpICsNCiAgbGFicyAoeCA9IE5VTEwsIHkgPSAiUHJvcC4gbWFpbnRhaW5lZCIsIGZpbGwgPSAiU2ltaWxhcml0eSIsIHRpdGxlID0gIk1haW50ZW5hbmNlIG9mIHNhbWUtZ2VuZGVyIHZzLiBkaWZmZXJlbnQgZ2VuZGVyIGNvbmZpZGFudHMsXG5hbW9uZyBtZW4gdnMuIHdvbWVuIiAsZm9udCA9ICJKb3N0IikgKw0KICAgIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgMSwgLjI1KSwgbGltaXRzID0gYygwLDEpKSArDQogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCkpDQpgYGAgDQoNCjIuIEJ1dCBib3RoIG1lbiAoYWx0aG91Z2ggbm90IHNpZ25pZmljYW50bHkpIGFuZCB3b21lbiBtYWludGFpbiBzYW1lLWdlbmRlciBjb25maWRhbnRzIG1vcmUgb2Z0ZW4gdGhhbiB0aGV5IG1haW50YWluIGRpZmZlcmVudC1nZW5kZXIgY29uZmlkYW50cy4uLg0KDQoNCi0tLS0NCg0KPGJyPg0KDQojIyBIb21vZ2VuZWl0eSB7LnRhYnNldCAudGFic2V0LWZhZGV9DQoNCi0gRUkgaW5kZXggZm9yIGRpY2hvdG9tb3VzIHZhcmlhYmxlcyAoc2FtZSBnZW5kZXIsIHNhbWUgZWR1Y2F0aW9uKQ0KLSBBdmVyYWdlIHNpbWlsYXJpdHkgc2NvcmUgZm9yIGNvbnRpbnVvdXMgdmFyaWFibGUgKGFnZSBkaWZmZXJlbmNlKQ0KDQojIyMgYWxsIGFsdGVycw0KDQpgYGB7ciwgY2xhc3Muc291cmNlID0gJ2ZvbGQtaGlkZScgfQ0KdGFiIDwtIG1hdHJpeChucm93PTMsIG5jb2w9MykNCnJvd25hbWVzKHRhYikgPC0gYygiR2VuZGVyIiwgDQogICAgICAgICAgICAgICAgICAgIkVkdWNhdGlvbiIsIA0KICAgICAgICAgICAgICAgICAgICJBZ2UiKQ0KY29sbmFtZXModGFiKSA8LSBjKCJIb21vZ2VuZWl0eSBXMSIsICJIb21vZ2VuZWl0eSBXMiIsICLOlCBXMS1XMiIpDQoNCmVpZ2VuZGVyMSA8LSBOQQ0KZWllZHVjMSA8LSBOQQ0KYXZzaW1hZ2UxIDwtIE5BDQplaWdlbmRlcjIgPC0gTkENCmVpZWR1YzIgPC0gTkENCmF2c2ltYWdlMiA8LSBOQQ0KZWlnZW5kZXJkIDwtIE5BDQplaWVkdWNkIDwtIE5BDQphdnNpbWFnZWQgPC0gTkENCmVpZ2VuZGVyZCA8LSBOQQ0KZWllZHVjZCA8LSBOQQ0KYXZzaW1hZ2VkIDwtIE5BDQoNCmZvciAoaSBpbiAxOmxlbmd0aCh1bmlxdWUoZGF0YSRlZ29bZGF0YSRwZXJpb2Q9PSJ3MiAtPiB3MyJdKSkpIHsNCg0KICAjZ2V0IG5ldHdvcmsgb2JzZXJ2ZWQgYXQgd2F2ZSAxDQogIG5ldHcxIDwtIGRhdGFbZGF0YSRlZ28gPT0gdW5pcXVlKGRhdGEkZWdvW2RhdGEkcGVyaW9kPT0idzIgLT4gdzMiXSlbaV0gJiBkYXRhJHBlcmlvZCA9PSAidzEgLT4gdzIiLF0NCiAgDQogICNnZXQgdW5pcXVlIGFsdGVycw0KICBuZXR3MXUgPC0gbmV0dzFbd2hpY2goIWR1cGxpY2F0ZWQobmV0dzEkYWx0ZXJpZCkpLF0NCiAgDQogICNFSSBpbmRleCBmb3IgZ2VuZGVyIGFuZCBlZHVjYXRpb24NCiAgc2ltZ2VuZGVyIDwtIGxlbmd0aCh3aGljaChuZXR3MXUkc2FtZV9nZW5kZXIgPT0gMSkpDQogIGRpZmdlbmRlciA8LSBsZW5ndGgod2hpY2gobmV0dzF1JGRpZmZlcmVudF9nZW5kZXIgPT0gMSkpDQogIHNpbWVkdWMgPC0gbGVuZ3RoKHdoaWNoKG5ldHcxdSRzaW1fZWR1YyA9PSAxKSkNCiAgZGlmZWR1YyA8LSBsZW5ndGgod2hpY2gobmV0dzF1JGRpZmZlcmVudF9lZHVjID09IDEpKQ0KICBuX2FsdGVyIDwtIG5yb3cobmV0dzF1KQ0KICANCiAgI2NhbGN1bGF0ZSBFSQ0KICBlaWdlbmRlcjFbaV0gPC0gKHNpbWdlbmRlci1kaWZnZW5kZXIpL25fYWx0ZXINCiAgZWllZHVjMVtpXSA8LSAoc2ltZWR1Yy1kaWZlZHVjKS9uX2FsdGVyDQogIA0KICAjYW5kIGF2ZXJhZ2Ugc2ltaWxhcml0eSBmb3IgYWdlDQogIGVnb19hZ2UgPC0gbmV0dzF1JGVnb19hZ2VbMV0gI2VnbyBhZ2UNCiAgYWx0ZXJzX2FnZSA8LSBhcy5udW1lcmljKG5ldHcxdSRhbHRlcl9hZ2UpICNhbHRlcnMnIGFnZQ0KICBtaW4gPC0gMTYNCiAgbWF4IDwtIDQ1DQogIHJ2IDwtIG1heC1taW4gI3JhbmdlDQogIGF2c2ltYWdlMVtpXSA8LSBtZWFuKDEgLSBhYnMoYWx0ZXJzX2FnZSAtIGVnb19hZ2UpL3J2KSAjYXZlcmFnZSBzaW1pbGFyaXR5IHNjb3JlDQogIA0KICAjbm93IHJlcGVhdCBmb3Igd2F2ZSAyDQogICBuZXR3MiA8LSBkYXRhW2RhdGEkZWdvID09IHVuaXF1ZShkYXRhJGVnb1tkYXRhJHBlcmlvZD09IncyIC0+IHczIl0pW2ldICYgZGF0YSRwZXJpb2QgPT0gIncyIC0+IHczIixdDQogICANCiAgI2dldCB1bmlxdWUgYWx0ZXJzDQogIG5ldHcydSA8LSBuZXR3Mlt3aGljaCghZHVwbGljYXRlZChuZXR3MiRhbHRlcmlkKSksXQ0KDQogIHNpbWdlbmRlciA8LSBsZW5ndGgod2hpY2gobmV0dzJ1JHNhbWVfZ2VuZGVyID09IDEpKQ0KICBkaWZnZW5kZXIgPC0gbGVuZ3RoKHdoaWNoKG5ldHcydSRkaWZmZXJlbnRfZ2VuZGVyID09IDEpKQ0KICBzaW1lZHVjIDwtIGxlbmd0aCh3aGljaChuZXR3MnUkc2ltX2VkdWMgPT0gMSkpDQogIGRpZmVkdWMgPC0gbGVuZ3RoKHdoaWNoKG5ldHcydSRkaWZmZXJlbnRfZWR1YyA9PSAxKSkNCiAgbl9hbHRlciA8LSBucm93KG5ldHcydSkNCiAgDQogIGVpZ2VuZGVyMltpXSA8LSAoc2ltZ2VuZGVyLWRpZmdlbmRlcikvbl9hbHRlcg0KICBlaWVkdWMyW2ldIDwtIChzaW1lZHVjLWRpZmVkdWMpL25fYWx0ZXINCiAgDQogIGFsdGVyc19hZ2UgPC0gYXMubnVtZXJpYyhuZXR3MnUkYWx0ZXJfYWdlKSAjYWx0ZXJzJyBhZ2UNCiAgYXZzaW1hZ2UyW2ldIDwtIG1lYW4oMSAtIGFicyhhbHRlcnNfYWdlIC0gZWdvX2FnZSkvcnYpICNhdmVyYWdlIHNpbWlsYXJpdHkgc2NvcmUNCiAgDQogICNkaWZmZXJlbmNlDQogIGVpZ2VuZGVyZFtpXSA8LSBlaWdlbmRlcjFbaV0gLSBlaWdlbmRlcjJbaV0NCiAgZWllZHVjZFtpXSA8LSBlaWVkdWMxW2ldIC0gZWllZHVjMltpXQ0KICBhdnNpbWFnZWRbaV0gPC0gYXZzaW1hZ2UxW2ldIC0gYXZzaW1hZ2UyW2ldDQogIA0KfQ0KDQoNCnRhYlsxLDFdIDwtIHBhc3RlMCggZm9ybWF0KHJvdW5kKG1lYW4oZWlnZW5kZXIxLCBuYS5ybT1UUlVFKSwgMiksIG5zbWFsbCA9MiksICIgKCIsIGZvcm1hdChyb3VuZChzZChlaWdlbmRlcjEsIG5hLnJtPVRSVUUpLCAyKSwgbnNtYWxsPTIpLCAiKSIpDQp0YWJbMSwyXSA8LSBwYXN0ZTAoIGZvcm1hdChyb3VuZChtZWFuKGVpZ2VuZGVyMiwgbmEucm09VFJVRSksIDIpLCBuc21hbGwgPTIpLCAiICgiLCBmb3JtYXQocm91bmQoc2QoZWlnZW5kZXIyLCBuYS5ybT1UUlVFKSwgMiksIG5zbWFsbD0yKSwgIikiKQ0KdGFiWzEsM10gPC0gcGFzdGUwKCBmb3JtYXQocm91bmQobWVhbihlaWdlbmRlcmQsIG5hLnJtPVRSVUUpLCAyKSwgbnNtYWxsID0yKSwgIiAoIiwgZm9ybWF0KHJvdW5kKHNkKGVpZ2VuZGVyZCwgbmEucm09VFJVRSksIDIpLCBuc21hbGw9MiksICIpIikNCg0KdGFiWzIsMV0gPC0gcGFzdGUwKCBmb3JtYXQocm91bmQobWVhbihlaWVkdWMxLCBuYS5ybT1UUlVFKSwgMiksIG5zbWFsbCA9MiksICIgKCIsIGZvcm1hdChyb3VuZChzZChlaWVkdWMxLCBuYS5ybT1UUlVFKSwgMiksIG5zbWFsbD0yKSwgIikiKQ0KdGFiWzIsMl0gPC0gcGFzdGUwKCBmb3JtYXQocm91bmQobWVhbihlaWVkdWMyLCBuYS5ybT1UUlVFKSwgMiksIG5zbWFsbCA9MiksICIgKCIsIGZvcm1hdChyb3VuZChzZChlaWVkdWMyLCBuYS5ybT1UUlVFKSwgMiksIG5zbWFsbD0yKSwgIikiKQ0KdGFiWzIsM10gPC0gcGFzdGUwKCBmb3JtYXQocm91bmQobWVhbihlaWVkdWNkLCBuYS5ybT1UUlVFKSwgMiksIG5zbWFsbCA9MiksICIgKCIsIGZvcm1hdChyb3VuZChzZChlaWVkdWNkLCBuYS5ybT1UUlVFKSwgMiksIG5zbWFsbD0yKSwgIikiKQ0KDQp0YWJbMywxXSA8LSBwYXN0ZTAoIGZvcm1hdChyb3VuZChtZWFuKGF2c2ltYWdlMSwgbmEucm09VFJVRSksIDIpLCBuc21hbGwgPTIpLCAiICgiLCBmb3JtYXQocm91bmQoc2QoYXZzaW1hZ2UxLCBuYS5ybT1UUlVFKSwgMiksIG5zbWFsbD0yKSwgIikiKQ0KdGFiWzMsMl0gPC0gcGFzdGUwKCBmb3JtYXQocm91bmQobWVhbihhdnNpbWFnZTIsIG5hLnJtPVRSVUUpLCAyKSwgbnNtYWxsID0yKSwgIiAoIiwgZm9ybWF0KHJvdW5kKHNkKGF2c2ltYWdlMiwgbmEucm09VFJVRSksIDIpLCBuc21hbGw9MiksICIpIikNCnRhYlszLDNdIDwtIHBhc3RlMCggZm9ybWF0KHJvdW5kKG1lYW4oYXZzaW1hZ2VkLCBuYS5ybT1UUlVFKSwgMiksIG5zbWFsbCA9MiksICIgKCIsIGZvcm1hdChyb3VuZChzZChhdnNpbWFnZWQsIG5hLnJtPVRSVUUpLCAyKSwgbnNtYWxsPTIpLCAiKSIpDQoNCmZzaG93ZGYodGFiLCBjYXB0aW9uPSJIb21vZ2VuZWl0eSBpbiBlZ28tbmV0d29ya3Mgb2YgMjgxIHN0dWRlbnRzIHdobyBwYXJ0aWNpcGF0ZWQgaW4gd2F2ZXMgMSBhbmQgMiIpDQpgYGANCg0KDQojIyMgY29uZmlkYW50cw0KDQpgYGB7ciwgY2xhc3Muc291cmNlID0gJ2ZvbGQtaGlkZScgfQ0KdGFiIDwtIG1hdHJpeChucm93PTMsIG5jb2w9MykNCnJvd25hbWVzKHRhYikgPC0gYygiR2VuZGVyIiwgDQogICAgICAgICAgICAgICAgICAgIkVkdWNhdGlvbiIsIA0KICAgICAgICAgICAgICAgICAgICJBZ2UiKQ0KY29sbmFtZXModGFiKSA8LSBjKCJIb21vZ2VuZWl0eSBXMSIsICJIb21vZ2VuZWl0eSBXMiIsICLOlCBXMS1XMiIpDQoNCmVpZ2VuZGVyMSA8LSBOQQ0KZWllZHVjMSA8LSBOQQ0KYXZzaW1hZ2UxIDwtIE5BDQplaWdlbmRlcjIgPC0gTkENCmVpZWR1YzIgPC0gTkENCmF2c2ltYWdlMiA8LSBOQQ0KZWlnZW5kZXJkIDwtIE5BDQplaWVkdWNkIDwtIE5BDQphdnNpbWFnZWQgPC0gTkENCg0KZm9yIChpIGluIDE6bGVuZ3RoKHVuaXF1ZShkYXRhJGVnb1tkYXRhJHBlcmlvZD09IncyIC0+IHczIl0pKSkgew0KDQogICNnZXQgbmV0d29yayBvYnNlcnZlZCBhdCB3YXZlIDENCiAgbmV0dzEgPC0gZGF0YVtkYXRhJGVnbyA9PSB1bmlxdWUoZGF0YSRlZ29bZGF0YSRwZXJpb2Q9PSJ3MiAtPiB3MyJdKVtpXSAmIGRhdGEkcGVyaW9kID09ICJ3MSAtPiB3MiIsXQ0KICANCiAgI2dldCB1bmlxdWUgYWx0ZXJzDQogIG5ldHcxdSA8LSBuZXR3MVt3aGljaCghZHVwbGljYXRlZChuZXR3MSRhbHRlcmlkKSksXQ0KICANCiAgI2ZpbHRlciBvbiB0aWUgdHlwZQ0KICBuZXR3MXUgPC0gbmV0dzF1W25ldHcxdSR0aWUgPT0gIkNvbmZpZGFudCIsXQ0KICANCiAgI0VJIGluZGV4IGZvciBnZW5kZXIgYW5kIGVkdWNhdGlvbg0KICBzaW1nZW5kZXIgPC0gbGVuZ3RoKHdoaWNoKG5ldHcxdSRzYW1lX2dlbmRlciA9PSAxKSkNCiAgZGlmZ2VuZGVyIDwtIGxlbmd0aCh3aGljaChuZXR3MXUkZGlmZmVyZW50X2dlbmRlciA9PSAxKSkNCiAgc2ltZWR1YyA8LSBsZW5ndGgod2hpY2gobmV0dzF1JHNpbV9lZHVjID09IDEpKQ0KICBkaWZlZHVjIDwtIGxlbmd0aCh3aGljaChuZXR3MXUkZGlmZmVyZW50X2VkdWMgPT0gMSkpDQogIG5fYWx0ZXIgPC0gbnJvdyhuZXR3MXUpDQogIA0KICAjY2FsY3VsYXRlIEVJDQogIGVpZ2VuZGVyMVtpXSA8LSAoc2ltZ2VuZGVyLWRpZmdlbmRlcikvbl9hbHRlcg0KICBlaWVkdWMxW2ldIDwtIChzaW1lZHVjLWRpZmVkdWMpL25fYWx0ZXINCiAgDQogICNhbmQgYXZlcmFnZSBzaW1pbGFyaXR5IGZvciBhZ2UNCiAgZWdvX2FnZSA8LSBuZXR3MXUkZWdvX2FnZVsxXSAjZWdvIGFnZQ0KICBhbHRlcnNfYWdlIDwtIGFzLm51bWVyaWMobmV0dzF1JGFsdGVyX2FnZSkgI2FsdGVycycgYWdlDQogIG1pbiA8LSAxNg0KICBtYXggPC0gNDUNCiAgcnYgPC0gbWF4LW1pbiAjcmFuZ2UNCiAgYXZzaW1hZ2UxW2ldIDwtIG1lYW4oMSAtIGFicyhhbHRlcnNfYWdlIC0gZWdvX2FnZSkvcnYpICNhdmVyYWdlIHNpbWlsYXJpdHkgc2NvcmUNCiAgDQogICNub3cgcmVwZWF0IGZvciB3YXZlIDINCiAgbmV0dzIgPC0gZGF0YVtkYXRhJGVnbyA9PSB1bmlxdWUoZGF0YSRlZ29bZGF0YSRwZXJpb2Q9PSJ3MiAtPiB3MyJdKVtpXSAmIGRhdGEkcGVyaW9kID09ICJ3MiAtPiB3MyIsXQ0KICAgDQogICNnZXQgdW5pcXVlIGFsdGVycw0KICBuZXR3MnUgPC0gbmV0dzJbd2hpY2goIWR1cGxpY2F0ZWQobmV0dzIkYWx0ZXJpZCkpLF0NCiAgDQogICNmaWx0ZXIgb24gdGllIHR5cGUNCiAgbmV0dzJ1IDwtIG5ldHcydVtuZXR3MnUkdGllID09ICJDb25maWRhbnQiLF0NCg0KICBzaW1nZW5kZXIgPC0gbGVuZ3RoKHdoaWNoKG5ldHcydSRzYW1lX2dlbmRlciA9PSAxKSkNCiAgZGlmZ2VuZGVyIDwtIGxlbmd0aCh3aGljaChuZXR3MnUkZGlmZmVyZW50X2dlbmRlciA9PSAxKSkNCiAgc2ltZWR1YyA8LSBsZW5ndGgod2hpY2gobmV0dzJ1JHNpbV9lZHVjID09IDEpKQ0KICBkaWZlZHVjIDwtIGxlbmd0aCh3aGljaChuZXR3MnUkZGlmZmVyZW50X2VkdWMgPT0gMSkpDQogIG5fYWx0ZXIgPC0gbnJvdyhuZXR3MnUpDQogIA0KICBlaWdlbmRlcjJbaV0gPC0gKHNpbWdlbmRlci1kaWZnZW5kZXIpL25fYWx0ZXINCiAgZWllZHVjMltpXSA8LSAoc2ltZWR1Yy1kaWZlZHVjKS9uX2FsdGVyDQogIA0KICBhbHRlcnNfYWdlIDwtIGFzLm51bWVyaWMobmV0dzJ1JGFsdGVyX2FnZSkgI2FsdGVycycgYWdlDQogIGF2c2ltYWdlMltpXSA8LSBtZWFuKDEgLSBhYnMoYWx0ZXJzX2FnZSAtIGVnb19hZ2UpL3J2KSAjYXZlcmFnZSBzaW1pbGFyaXR5IHNjb3JlDQogIA0KICAjZGlmZmVyZW5jZQ0KICBlaWdlbmRlcmRbaV0gPC0gZWlnZW5kZXIxW2ldIC0gZWlnZW5kZXIyW2ldDQogIGVpZWR1Y2RbaV0gPC0gZWllZHVjMVtpXSAtIGVpZWR1YzJbaV0NCiAgYXZzaW1hZ2VkW2ldIDwtIGF2c2ltYWdlMVtpXSAtIGF2c2ltYWdlMltpXQ0KICANCn0NCg0KdGFiWzEsMV0gPC0gcGFzdGUwKCBmb3JtYXQocm91bmQobWVhbihlaWdlbmRlcjEsIG5hLnJtPVRSVUUpLCAyKSwgbnNtYWxsID0yKSwgIiAoIiwgZm9ybWF0KHJvdW5kKHNkKGVpZ2VuZGVyMSwgbmEucm09VFJVRSksIDIpLCBuc21hbGw9MiksICIpIikNCnRhYlsxLDJdIDwtIHBhc3RlMCggZm9ybWF0KHJvdW5kKG1lYW4oZWlnZW5kZXIyLCBuYS5ybT1UUlVFKSwgMiksIG5zbWFsbCA9MiksICIgKCIsIGZvcm1hdChyb3VuZChzZChlaWdlbmRlcjIsIG5hLnJtPVRSVUUpLCAyKSwgbnNtYWxsPTIpLCAiKSIpDQp0YWJbMSwzXSA8LSBwYXN0ZTAoIGZvcm1hdChyb3VuZChtZWFuKGVpZ2VuZGVyZCwgbmEucm09VFJVRSksIDIpLCBuc21hbGwgPTIpLCAiICgiLCBmb3JtYXQocm91bmQoc2QoZWlnZW5kZXJkLCBuYS5ybT1UUlVFKSwgMiksIG5zbWFsbD0yKSwgIikiKQ0KDQp0YWJbMiwxXSA8LSBwYXN0ZTAoIGZvcm1hdChyb3VuZChtZWFuKGVpZWR1YzEsIG5hLnJtPVRSVUUpLCAyKSwgbnNtYWxsID0yKSwgIiAoIiwgZm9ybWF0KHJvdW5kKHNkKGVpZWR1YzEsIG5hLnJtPVRSVUUpLCAyKSwgbnNtYWxsPTIpLCAiKSIpDQp0YWJbMiwyXSA8LSBwYXN0ZTAoIGZvcm1hdChyb3VuZChtZWFuKGVpZWR1YzIsIG5hLnJtPVRSVUUpLCAyKSwgbnNtYWxsID0yKSwgIiAoIiwgZm9ybWF0KHJvdW5kKHNkKGVpZWR1YzIsIG5hLnJtPVRSVUUpLCAyKSwgbnNtYWxsPTIpLCAiKSIpDQp0YWJbMiwzXSA8LSBwYXN0ZTAoIGZvcm1hdChyb3VuZChtZWFuKGVpZWR1Y2QsIG5hLnJtPVRSVUUpLCAyKSwgbnNtYWxsID0yKSwgIiAoIiwgZm9ybWF0KHJvdW5kKHNkKGVpZWR1Y2QsIG5hLnJtPVRSVUUpLCAyKSwgbnNtYWxsPTIpLCAiKSIpDQoNCnRhYlszLDFdIDwtIHBhc3RlMCggZm9ybWF0KHJvdW5kKG1lYW4oYXZzaW1hZ2UxLCBuYS5ybT1UUlVFKSwgMiksIG5zbWFsbCA9MiksICIgKCIsIGZvcm1hdChyb3VuZChzZChhdnNpbWFnZTEsIG5hLnJtPVRSVUUpLCAyKSwgbnNtYWxsPTIpLCAiKSIpDQp0YWJbMywyXSA8LSBwYXN0ZTAoIGZvcm1hdChyb3VuZChtZWFuKGF2c2ltYWdlMiwgbmEucm09VFJVRSksIDIpLCBuc21hbGwgPTIpLCAiICgiLCBmb3JtYXQocm91bmQoc2QoYXZzaW1hZ2UyLCBuYS5ybT1UUlVFKSwgMiksIG5zbWFsbD0yKSwgIikiKQ0KdGFiWzMsM10gPC0gcGFzdGUwKCBmb3JtYXQocm91bmQobWVhbihhdnNpbWFnZWQsIG5hLnJtPVRSVUUpLCAyKSwgbnNtYWxsID0yKSwgIiAoIiwgZm9ybWF0KHJvdW5kKHNkKGF2c2ltYWdlZCwgbmEucm09VFJVRSksIDIpLCBuc21hbGw9MiksICIpIikNCg0KZnNob3dkZih0YWIsIGNhcHRpb249IkhvbW9nZW5laXR5IGluIGNvbmZpZGluZyBuZXR3b3JrIGxheWVyIG9mIDI4MSBzdHVkZW50cyB3aG8gcGFydGljaXBhdGVkIGluIHdhdmVzIDEgYW5kIDIiKQ0KDQpgYGANCg0KDQojIyMgYmVzdCBmcmllbmRzDQoNCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1oaWRlJyB9DQp0YWIgPC0gbWF0cml4KG5yb3c9MywgbmNvbD0zKQ0Kcm93bmFtZXModGFiKSA8LSBjKCJHZW5kZXIiLCANCiAgICAgICAgICAgICAgICAgICAiRWR1Y2F0aW9uIiwgDQogICAgICAgICAgICAgICAgICAgIkFnZSIpDQpjb2xuYW1lcyh0YWIpIDwtIGMoIkhvbW9nZW5laXR5IFcxIiwgIkhvbW9nZW5laXR5IFcyIiwgIs6UIFcxLVcyIikNCg0KZWlnZW5kZXIxIDwtIE5BDQplaWVkdWMxIDwtIE5BDQphdnNpbWFnZTEgPC0gTkENCmVpZ2VuZGVyMiA8LSBOQQ0KZWllZHVjMiA8LSBOQQ0KYXZzaW1hZ2UyIDwtIE5BDQplaWdlbmRlcmQgPC0gTkENCmVpZWR1Y2QgPC0gTkENCmF2c2ltYWdlZCA8LSBOQQ0KDQpmb3IgKGkgaW4gMTpsZW5ndGgodW5pcXVlKGRhdGEkZWdvW2RhdGEkcGVyaW9kPT0idzIgLT4gdzMiXSkpKSB7DQoNCiAgI2dldCBuZXR3b3JrIG9ic2VydmVkIGF0IHdhdmUgMQ0KICBuZXR3MSA8LSBkYXRhW2RhdGEkZWdvID09IHVuaXF1ZShkYXRhJGVnb1tkYXRhJHBlcmlvZD09IncyIC0+IHczIl0pW2ldICYgZGF0YSRwZXJpb2QgPT0gIncxIC0+IHcyIixdDQogIA0KICAjZ2V0IHVuaXF1ZSBhbHRlcnMNCiAgbmV0dzF1IDwtIG5ldHcxW3doaWNoKCFkdXBsaWNhdGVkKG5ldHcxJGFsdGVyaWQpKSxdDQogIA0KICAjZmlsdGVyIG9uIHRpZSB0eXBlDQogIG5ldHcxdSA8LSBuZXR3MXVbbmV0dzF1JHRpZSA9PSAiRnJpZW5kIixdDQogIA0KICAjRUkgaW5kZXggZm9yIGdlbmRlciBhbmQgZWR1Y2F0aW9uDQogIHNpbWdlbmRlciA8LSBsZW5ndGgod2hpY2gobmV0dzF1JHNhbWVfZ2VuZGVyID09IDEpKQ0KICBkaWZnZW5kZXIgPC0gbGVuZ3RoKHdoaWNoKG5ldHcxdSRkaWZmZXJlbnRfZ2VuZGVyID09IDEpKQ0KICBzaW1lZHVjIDwtIGxlbmd0aCh3aGljaChuZXR3MXUkc2ltX2VkdWMgPT0gMSkpDQogIGRpZmVkdWMgPC0gbGVuZ3RoKHdoaWNoKG5ldHcxdSRkaWZmZXJlbnRfZWR1YyA9PSAxKSkNCiAgbl9hbHRlciA8LSBucm93KG5ldHcxdSkNCiAgDQogICNjYWxjdWxhdGUgRUkNCiAgZWlnZW5kZXIxW2ldIDwtIChzaW1nZW5kZXItZGlmZ2VuZGVyKS9uX2FsdGVyDQogIGVpZWR1YzFbaV0gPC0gKHNpbWVkdWMtZGlmZWR1Yykvbl9hbHRlcg0KICANCiAgI2FuZCBhdmVyYWdlIHNpbWlsYXJpdHkgZm9yIGFnZQ0KICBlZ29fYWdlIDwtIG5ldHcxdSRlZ29fYWdlWzFdICNlZ28gYWdlDQogIGFsdGVyc19hZ2UgPC0gYXMubnVtZXJpYyhuZXR3MXUkYWx0ZXJfYWdlKSAjYWx0ZXJzJyBhZ2UNCiAgbWluIDwtIDE2DQogIG1heCA8LSA0NQ0KICBydiA8LSBtYXgtbWluICNyYW5nZQ0KICBhdnNpbWFnZTFbaV0gPC0gbWVhbigxIC0gYWJzKGFsdGVyc19hZ2UgLSBlZ29fYWdlKS9ydikgI2F2ZXJhZ2Ugc2ltaWxhcml0eSBzY29yZQ0KICANCiAgI25vdyByZXBlYXQgZm9yIHdhdmUgMg0KICBuZXR3MiA8LSBkYXRhW2RhdGEkZWdvID09IHVuaXF1ZShkYXRhJGVnb1tkYXRhJHBlcmlvZD09IncyIC0+IHczIl0pW2ldICYgZGF0YSRwZXJpb2QgPT0gIncyIC0+IHczIixdDQogICANCiAgI2dldCB1bmlxdWUgYWx0ZXJzDQogIG5ldHcydSA8LSBuZXR3Mlt3aGljaCghZHVwbGljYXRlZChuZXR3MiRhbHRlcmlkKSksXQ0KICANCiAgI2ZpbHRlciBvbiB0aWUgdHlwZQ0KICBuZXR3MnUgPC0gbmV0dzJ1W25ldHcydSR0aWUgPT0gIkZyaWVuZCIsXQ0KDQogIHNpbWdlbmRlciA8LSBsZW5ndGgod2hpY2gobmV0dzJ1JHNhbWVfZ2VuZGVyID09IDEpKQ0KICBkaWZnZW5kZXIgPC0gbGVuZ3RoKHdoaWNoKG5ldHcydSRkaWZmZXJlbnRfZ2VuZGVyID09IDEpKQ0KICBzaW1lZHVjIDwtIGxlbmd0aCh3aGljaChuZXR3MnUkc2ltX2VkdWMgPT0gMSkpDQogIGRpZmVkdWMgPC0gbGVuZ3RoKHdoaWNoKG5ldHcydSRkaWZmZXJlbnRfZWR1YyA9PSAxKSkNCiAgbl9hbHRlciA8LSBucm93KG5ldHcydSkNCiAgDQogIGVpZ2VuZGVyMltpXSA8LSAoc2ltZ2VuZGVyLWRpZmdlbmRlcikvbl9hbHRlcg0KICBlaWVkdWMyW2ldIDwtIChzaW1lZHVjLWRpZmVkdWMpL25fYWx0ZXINCiAgDQogIGFsdGVyc19hZ2UgPC0gYXMubnVtZXJpYyhuZXR3MnUkYWx0ZXJfYWdlKSAjYWx0ZXJzJyBhZ2UNCiAgYXZzaW1hZ2UyW2ldIDwtIG1lYW4oMSAtIGFicyhhbHRlcnNfYWdlIC0gZWdvX2FnZSkvcnYpICNhdmVyYWdlIHNpbWlsYXJpdHkgc2NvcmUNCiAgDQogICNkaWZmZXJlbmNlDQogIGVpZ2VuZGVyZFtpXSA8LSBlaWdlbmRlcjFbaV0gLSBlaWdlbmRlcjJbaV0NCiAgZWllZHVjZFtpXSA8LSBlaWVkdWMxW2ldIC0gZWllZHVjMltpXQ0KICBhdnNpbWFnZWRbaV0gPC0gYXZzaW1hZ2UxW2ldIC0gYXZzaW1hZ2UyW2ldDQogIA0KfQ0KDQp0YWJbMSwxXSA8LSBwYXN0ZTAoIGZvcm1hdChyb3VuZChtZWFuKGVpZ2VuZGVyMSwgbmEucm09VFJVRSksIDIpLCBuc21hbGwgPTIpLCAiICgiLCBmb3JtYXQocm91bmQoc2QoZWlnZW5kZXIxLCBuYS5ybT1UUlVFKSwgMiksIG5zbWFsbD0yKSwgIikiKQ0KdGFiWzEsMl0gPC0gcGFzdGUwKCBmb3JtYXQocm91bmQobWVhbihlaWdlbmRlcjIsIG5hLnJtPVRSVUUpLCAyKSwgbnNtYWxsID0yKSwgIiAoIiwgZm9ybWF0KHJvdW5kKHNkKGVpZ2VuZGVyMiwgbmEucm09VFJVRSksIDIpLCBuc21hbGw9MiksICIpIikNCnRhYlsxLDNdIDwtIHBhc3RlMCggZm9ybWF0KHJvdW5kKG1lYW4oZWlnZW5kZXJkLCBuYS5ybT1UUlVFKSwgMiksIG5zbWFsbCA9MiksICIgKCIsIGZvcm1hdChyb3VuZChzZChlaWdlbmRlcmQsIG5hLnJtPVRSVUUpLCAyKSwgbnNtYWxsPTIpLCAiKSIpDQoNCnRhYlsyLDFdIDwtIHBhc3RlMCggZm9ybWF0KHJvdW5kKG1lYW4oZWllZHVjMSwgbmEucm09VFJVRSksIDIpLCBuc21hbGwgPTIpLCAiICgiLCBmb3JtYXQocm91bmQoc2QoZWllZHVjMSwgbmEucm09VFJVRSksIDIpLCBuc21hbGw9MiksICIpIikNCnRhYlsyLDJdIDwtIHBhc3RlMCggZm9ybWF0KHJvdW5kKG1lYW4oZWllZHVjMiwgbmEucm09VFJVRSksIDIpLCBuc21hbGwgPTIpLCAiICgiLCBmb3JtYXQocm91bmQoc2QoZWllZHVjMiwgbmEucm09VFJVRSksIDIpLCBuc21hbGw9MiksICIpIikNCnRhYlsyLDNdIDwtIHBhc3RlMCggZm9ybWF0KHJvdW5kKG1lYW4oZWllZHVjZCwgbmEucm09VFJVRSksIDIpLCBuc21hbGwgPTIpLCAiICgiLCBmb3JtYXQocm91bmQoc2QoZWllZHVjZCwgbmEucm09VFJVRSksIDIpLCBuc21hbGw9MiksICIpIikNCg0KdGFiWzMsMV0gPC0gcGFzdGUwKCBmb3JtYXQocm91bmQobWVhbihhdnNpbWFnZTEsIG5hLnJtPVRSVUUpLCAyKSwgbnNtYWxsID0yKSwgIiAoIiwgZm9ybWF0KHJvdW5kKHNkKGF2c2ltYWdlMSwgbmEucm09VFJVRSksIDIpLCBuc21hbGw9MiksICIpIikNCnRhYlszLDJdIDwtIHBhc3RlMCggZm9ybWF0KHJvdW5kKG1lYW4oYXZzaW1hZ2UyLCBuYS5ybT1UUlVFKSwgMiksIG5zbWFsbCA9MiksICIgKCIsIGZvcm1hdChyb3VuZChzZChhdnNpbWFnZTIsIG5hLnJtPVRSVUUpLCAyKSwgbnNtYWxsPTIpLCAiKSIpDQp0YWJbMywzXSA8LSBwYXN0ZTAoIGZvcm1hdChyb3VuZChtZWFuKGF2c2ltYWdlZCwgbmEucm09VFJVRSksIDIpLCBuc21hbGwgPTIpLCAiICgiLCBmb3JtYXQocm91bmQoc2QoYXZzaW1hZ2VkLCBuYS5ybT1UUlVFKSwgMiksIG5zbWFsbD0yKSwgIikiKQ0KDQpmc2hvd2RmKHRhYiwgY2FwdGlvbj0iSG9tb2dlbmVpdHkgaW4gZnJpZW5kc2hpcCBuZXR3b3JrIGxheWVyIG9mIDI4MSBzdHVkZW50cyB3aG8gcGFydGljaXBhdGVkIGluIHdhdmVzIDEgYW5kIDIiKQ0KDQpgYGANCg0KIyMjIHNwb3J0cyBwYXJ0bmVyDQoNCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1oaWRlJyB9DQp0YWIgPC0gbWF0cml4KG5yb3c9MywgbmNvbD0zKQ0Kcm93bmFtZXModGFiKSA8LSBjKCJHZW5kZXIiLCANCiAgICAgICAgICAgICAgICAgICAiRWR1Y2F0aW9uIiwgDQogICAgICAgICAgICAgICAgICAgIkFnZSIpDQpjb2xuYW1lcyh0YWIpIDwtIGMoIkhvbW9nZW5laXR5IFcxIiwgIkhvbW9nZW5laXR5IFcyIiwgIs6UIFcxLVcyIikNCg0KZWlnZW5kZXIxIDwtIE5BDQplaWVkdWMxIDwtIE5BDQphdnNpbWFnZTEgPC0gTkENCmVpZ2VuZGVyMiA8LSBOQQ0KZWllZHVjMiA8LSBOQQ0KYXZzaW1hZ2UyIDwtIE5BDQplaWdlbmRlcmQgPC0gTkENCmVpZWR1Y2QgPC0gTkENCmF2c2ltYWdlZCA8LSBOQQ0KDQpmb3IgKGkgaW4gMTpsZW5ndGgodW5pcXVlKGRhdGEkZWdvW2RhdGEkcGVyaW9kPT0idzIgLT4gdzMiXSkpKSB7DQoNCiAgI2dldCBuZXR3b3JrIG9ic2VydmVkIGF0IHdhdmUgMQ0KICBuZXR3MSA8LSBkYXRhW2RhdGEkZWdvID09IHVuaXF1ZShkYXRhJGVnb1tkYXRhJHBlcmlvZD09IncyIC0+IHczIl0pW2ldICYgZGF0YSRwZXJpb2QgPT0gIncxIC0+IHcyIixdDQogIA0KICAjZ2V0IHVuaXF1ZSBhbHRlcnMNCiAgbmV0dzF1IDwtIG5ldHcxW3doaWNoKCFkdXBsaWNhdGVkKG5ldHcxJGFsdGVyaWQpKSxdDQogIA0KICAjZmlsdGVyIG9uIHRpZSB0eXBlDQogIG5ldHcxdSA8LSBuZXR3MXVbbmV0dzF1JHRpZSA9PSAiU3BvcnQiLF0NCiAgDQogICNFSSBpbmRleCBmb3IgZ2VuZGVyIGFuZCBlZHVjYXRpb24NCiAgc2ltZ2VuZGVyIDwtIGxlbmd0aCh3aGljaChuZXR3MXUkc2FtZV9nZW5kZXIgPT0gMSkpDQogIGRpZmdlbmRlciA8LSBsZW5ndGgod2hpY2gobmV0dzF1JGRpZmZlcmVudF9nZW5kZXIgPT0gMSkpDQogIHNpbWVkdWMgPC0gbGVuZ3RoKHdoaWNoKG5ldHcxdSRzaW1fZWR1YyA9PSAxKSkNCiAgZGlmZWR1YyA8LSBsZW5ndGgod2hpY2gobmV0dzF1JGRpZmZlcmVudF9lZHVjID09IDEpKQ0KICBuX2FsdGVyIDwtIG5yb3cobmV0dzF1KQ0KICANCiAgI2NhbGN1bGF0ZSBFSQ0KICBlaWdlbmRlcjFbaV0gPC0gKHNpbWdlbmRlci1kaWZnZW5kZXIpL25fYWx0ZXINCiAgZWllZHVjMVtpXSA8LSAoc2ltZWR1Yy1kaWZlZHVjKS9uX2FsdGVyDQogIA0KICAjYW5kIGF2ZXJhZ2Ugc2ltaWxhcml0eSBmb3IgYWdlDQogIGVnb19hZ2UgPC0gbmV0dzF1JGVnb19hZ2VbMV0gI2VnbyBhZ2UNCiAgYWx0ZXJzX2FnZSA8LSBhcy5udW1lcmljKG5ldHcxdSRhbHRlcl9hZ2UpICNhbHRlcnMnIGFnZQ0KICBtaW4gPC0gMTYNCiAgbWF4IDwtIDQ1DQogIHJ2IDwtIG1heC1taW4gI3JhbmdlDQogIGF2c2ltYWdlMVtpXSA8LSBtZWFuKDEgLSBhYnMoYWx0ZXJzX2FnZSAtIGVnb19hZ2UpL3J2KSAjYXZlcmFnZSBzaW1pbGFyaXR5IHNjb3JlDQogIA0KICAjbm93IHJlcGVhdCBmb3Igd2F2ZSAyDQogIG5ldHcyIDwtIGRhdGFbZGF0YSRlZ28gPT0gdW5pcXVlKGRhdGEkZWdvW2RhdGEkcGVyaW9kPT0idzIgLT4gdzMiXSlbaV0gJiBkYXRhJHBlcmlvZCA9PSAidzIgLT4gdzMiLF0NCiAgIA0KICAjZ2V0IHVuaXF1ZSBhbHRlcnMNCiAgbmV0dzJ1IDwtIG5ldHcyW3doaWNoKCFkdXBsaWNhdGVkKG5ldHcyJGFsdGVyaWQpKSxdDQogIA0KICAjZmlsdGVyIG9uIHRpZSB0eXBlDQogIG5ldHcydSA8LSBuZXR3MnVbbmV0dzJ1JHRpZSA9PSAiU3BvcnQiLF0NCg0KICBzaW1nZW5kZXIgPC0gbGVuZ3RoKHdoaWNoKG5ldHcydSRzYW1lX2dlbmRlciA9PSAxKSkNCiAgZGlmZ2VuZGVyIDwtIGxlbmd0aCh3aGljaChuZXR3MnUkZGlmZmVyZW50X2dlbmRlciA9PSAxKSkNCiAgc2ltZWR1YyA8LSBsZW5ndGgod2hpY2gobmV0dzJ1JHNpbV9lZHVjID09IDEpKQ0KICBkaWZlZHVjIDwtIGxlbmd0aCh3aGljaChuZXR3MnUkZGlmZmVyZW50X2VkdWMgPT0gMSkpDQogIG5fYWx0ZXIgPC0gbnJvdyhuZXR3MnUpDQogIA0KICBlaWdlbmRlcjJbaV0gPC0gKHNpbWdlbmRlci1kaWZnZW5kZXIpL25fYWx0ZXINCiAgZWllZHVjMltpXSA8LSAoc2ltZWR1Yy1kaWZlZHVjKS9uX2FsdGVyDQogIA0KICBhbHRlcnNfYWdlIDwtIGFzLm51bWVyaWMobmV0dzJ1JGFsdGVyX2FnZSkgI2FsdGVycycgYWdlDQogIGF2c2ltYWdlMltpXSA8LSBtZWFuKDEgLSBhYnMoYWx0ZXJzX2FnZSAtIGVnb19hZ2UpL3J2KSAjYXZlcmFnZSBzaW1pbGFyaXR5IHNjb3JlDQogIA0KICAjZGlmZmVyZW5jZQ0KICBlaWdlbmRlcmRbaV0gPC0gZWlnZW5kZXIxW2ldIC0gZWlnZW5kZXIyW2ldDQogIGVpZWR1Y2RbaV0gPC0gZWllZHVjMVtpXSAtIGVpZWR1YzJbaV0NCiAgYXZzaW1hZ2VkW2ldIDwtIGF2c2ltYWdlMVtpXSAtIGF2c2ltYWdlMltpXQ0KICANCn0NCg0KdGFiWzEsMV0gPC0gcGFzdGUwKCBmb3JtYXQocm91bmQobWVhbihlaWdlbmRlcjEsIG5hLnJtPVRSVUUpLCAyKSwgbnNtYWxsID0yKSwgIiAoIiwgZm9ybWF0KHJvdW5kKHNkKGVpZ2VuZGVyMSwgbmEucm09VFJVRSksIDIpLCBuc21hbGw9MiksICIpIikNCnRhYlsxLDJdIDwtIHBhc3RlMCggZm9ybWF0KHJvdW5kKG1lYW4oZWlnZW5kZXIyLCBuYS5ybT1UUlVFKSwgMiksIG5zbWFsbCA9MiksICIgKCIsIGZvcm1hdChyb3VuZChzZChlaWdlbmRlcjIsIG5hLnJtPVRSVUUpLCAyKSwgbnNtYWxsPTIpLCAiKSIpDQp0YWJbMSwzXSA8LSBwYXN0ZTAoIGZvcm1hdChyb3VuZChtZWFuKGVpZ2VuZGVyZCwgbmEucm09VFJVRSksIDIpLCBuc21hbGwgPTIpLCAiICgiLCBmb3JtYXQocm91bmQoc2QoZWlnZW5kZXJkLCBuYS5ybT1UUlVFKSwgMiksIG5zbWFsbD0yKSwgIikiKQ0KDQp0YWJbMiwxXSA8LSBwYXN0ZTAoIGZvcm1hdChyb3VuZChtZWFuKGVpZWR1YzEsIG5hLnJtPVRSVUUpLCAyKSwgbnNtYWxsID0yKSwgIiAoIiwgZm9ybWF0KHJvdW5kKHNkKGVpZWR1YzEsIG5hLnJtPVRSVUUpLCAyKSwgbnNtYWxsPTIpLCAiKSIpDQp0YWJbMiwyXSA8LSBwYXN0ZTAoIGZvcm1hdChyb3VuZChtZWFuKGVpZWR1YzIsIG5hLnJtPVRSVUUpLCAyKSwgbnNtYWxsID0yKSwgIiAoIiwgZm9ybWF0KHJvdW5kKHNkKGVpZWR1YzIsIG5hLnJtPVRSVUUpLCAyKSwgbnNtYWxsPTIpLCAiKSIpDQp0YWJbMiwzXSA8LSBwYXN0ZTAoIGZvcm1hdChyb3VuZChtZWFuKGVpZWR1Y2QsIG5hLnJtPVRSVUUpLCAyKSwgbnNtYWxsID0yKSwgIiAoIiwgZm9ybWF0KHJvdW5kKHNkKGVpZWR1Y2QsIG5hLnJtPVRSVUUpLCAyKSwgbnNtYWxsPTIpLCAiKSIpDQoNCnRhYlszLDFdIDwtIHBhc3RlMCggZm9ybWF0KHJvdW5kKG1lYW4oYXZzaW1hZ2UxLCBuYS5ybT1UUlVFKSwgMiksIG5zbWFsbCA9MiksICIgKCIsIGZvcm1hdChyb3VuZChzZChhdnNpbWFnZTEsIG5hLnJtPVRSVUUpLCAyKSwgbnNtYWxsPTIpLCAiKSIpDQp0YWJbMywyXSA8LSBwYXN0ZTAoIGZvcm1hdChyb3VuZChtZWFuKGF2c2ltYWdlMiwgbmEucm09VFJVRSksIDIpLCBuc21hbGwgPTIpLCAiICgiLCBmb3JtYXQocm91bmQoc2QoYXZzaW1hZ2UyLCBuYS5ybT1UUlVFKSwgMiksIG5zbWFsbD0yKSwgIikiKQ0KdGFiWzMsM10gPC0gcGFzdGUwKCBmb3JtYXQocm91bmQobWVhbihhdnNpbWFnZWQsIG5hLnJtPVRSVUUpLCAyKSwgbnNtYWxsID0yKSwgIiAoIiwgZm9ybWF0KHJvdW5kKHNkKGF2c2ltYWdlZCwgbmEucm09VFJVRSksIDIpLCBuc21hbGw9MiksICIpIikNCg0KZnNob3dkZih0YWIsIGNhcHRpb249IkhvbW9nZW5laXR5IGluIHNwb3J0aW5nIG5ldHdvcmsgbGF5ZXIgb2YgMjgxIHN0dWRlbnRzIHdobyBwYXJ0aWNpcGF0ZWQgaW4gd2F2ZXMgMSBhbmQgMiIpDQpgYGANCg0KDQojIyMgc3R1ZHkgcGFydG5lcnMNCg0KYGBge3IsIGNsYXNzLnNvdXJjZSA9ICdmb2xkLWhpZGUnIH0NCnRhYiA8LSBtYXRyaXgobnJvdz0zLCBuY29sPTMpDQpyb3duYW1lcyh0YWIpIDwtIGMoIkdlbmRlciIsIA0KICAgICAgICAgICAgICAgICAgICJFZHVjYXRpb24iLCANCiAgICAgICAgICAgICAgICAgICAiQWdlIikNCmNvbG5hbWVzKHRhYikgPC0gYygiSG9tb2dlbmVpdHkgVzEiLCAiSG9tb2dlbmVpdHkgVzIiLCAizpQgVzEtVzIiKQ0KDQplaWdlbmRlcjEgPC0gTkENCmVpZWR1YzEgPC0gTkENCmF2c2ltYWdlMSA8LSBOQQ0KZWlnZW5kZXIyIDwtIE5BDQplaWVkdWMyIDwtIE5BDQphdnNpbWFnZTIgPC0gTkENCmVpZ2VuZGVyZCA8LSBOQQ0KZWllZHVjZCA8LSBOQQ0KYXZzaW1hZ2VkIDwtIE5BDQoNCmZvciAoaSBpbiAxOmxlbmd0aCh1bmlxdWUoZGF0YSRlZ29bZGF0YSRwZXJpb2Q9PSJ3MiAtPiB3MyJdKSkpIHsNCg0KICAjZ2V0IG5ldHdvcmsgb2JzZXJ2ZWQgYXQgd2F2ZSAxDQogIG5ldHcxIDwtIGRhdGFbZGF0YSRlZ28gPT0gdW5pcXVlKGRhdGEkZWdvW2RhdGEkcGVyaW9kPT0idzIgLT4gdzMiXSlbaV0gJiBkYXRhJHBlcmlvZCA9PSAidzEgLT4gdzIiLF0NCiAgDQogICNnZXQgdW5pcXVlIGFsdGVycw0KICBuZXR3MXUgPC0gbmV0dzFbd2hpY2goIWR1cGxpY2F0ZWQobmV0dzEkYWx0ZXJpZCkpLF0NCiAgDQogICNmaWx0ZXIgb24gdGllIHR5cGUNCiAgbmV0dzF1IDwtIG5ldHcxdVtuZXR3MXUkdGllID09ICJTdHVkeSIsXQ0KICANCiAgI0VJIGluZGV4IGZvciBnZW5kZXIgYW5kIGVkdWNhdGlvbg0KICBzaW1nZW5kZXIgPC0gbGVuZ3RoKHdoaWNoKG5ldHcxdSRzYW1lX2dlbmRlciA9PSAxKSkNCiAgZGlmZ2VuZGVyIDwtIGxlbmd0aCh3aGljaChuZXR3MXUkZGlmZmVyZW50X2dlbmRlciA9PSAxKSkNCiAgc2ltZWR1YyA8LSBsZW5ndGgod2hpY2gobmV0dzF1JHNpbV9lZHVjID09IDEpKQ0KICBkaWZlZHVjIDwtIGxlbmd0aCh3aGljaChuZXR3MXUkZGlmZmVyZW50X2VkdWMgPT0gMSkpDQogIG5fYWx0ZXIgPC0gbnJvdyhuZXR3MXUpDQogIA0KICAjY2FsY3VsYXRlIEVJDQogIGVpZ2VuZGVyMVtpXSA8LSAoc2ltZ2VuZGVyLWRpZmdlbmRlcikvbl9hbHRlcg0KICBlaWVkdWMxW2ldIDwtIChzaW1lZHVjLWRpZmVkdWMpL25fYWx0ZXINCiAgDQogICNhbmQgYXZlcmFnZSBzaW1pbGFyaXR5IGZvciBhZ2UNCiAgZWdvX2FnZSA8LSBuZXR3MXUkZWdvX2FnZVsxXSAjZWdvIGFnZQ0KICBhbHRlcnNfYWdlIDwtIGFzLm51bWVyaWMobmV0dzF1JGFsdGVyX2FnZSkgI2FsdGVycycgYWdlDQogIG1pbiA8LSAxNg0KICBtYXggPC0gNDUNCiAgcnYgPC0gbWF4LW1pbiAjcmFuZ2UNCiAgYXZzaW1hZ2UxW2ldIDwtIG1lYW4oMSAtIGFicyhhbHRlcnNfYWdlIC0gZWdvX2FnZSkvcnYpICNhdmVyYWdlIHNpbWlsYXJpdHkgc2NvcmUNCiAgDQogICNub3cgcmVwZWF0IGZvciB3YXZlIDINCiAgbmV0dzIgPC0gZGF0YVtkYXRhJGVnbyA9PSB1bmlxdWUoZGF0YSRlZ29bZGF0YSRwZXJpb2Q9PSJ3MiAtPiB3MyJdKVtpXSAmIGRhdGEkcGVyaW9kID09ICJ3MiAtPiB3MyIsXQ0KICAgDQogICNnZXQgdW5pcXVlIGFsdGVycw0KICBuZXR3MnUgPC0gbmV0dzJbd2hpY2goIWR1cGxpY2F0ZWQobmV0dzIkYWx0ZXJpZCkpLF0NCiAgDQogICNmaWx0ZXIgb24gdGllIHR5cGUNCiAgbmV0dzJ1IDwtIG5ldHcydVtuZXR3MnUkdGllID09ICJTdHVkeSIsXQ0KDQogIHNpbWdlbmRlciA8LSBsZW5ndGgod2hpY2gobmV0dzJ1JHNhbWVfZ2VuZGVyID09IDEpKQ0KICBkaWZnZW5kZXIgPC0gbGVuZ3RoKHdoaWNoKG5ldHcydSRkaWZmZXJlbnRfZ2VuZGVyID09IDEpKQ0KICBzaW1lZHVjIDwtIGxlbmd0aCh3aGljaChuZXR3MnUkc2ltX2VkdWMgPT0gMSkpDQogIGRpZmVkdWMgPC0gbGVuZ3RoKHdoaWNoKG5ldHcydSRkaWZmZXJlbnRfZWR1YyA9PSAxKSkNCiAgbl9hbHRlciA8LSBucm93KG5ldHcydSkNCiAgDQogIGVpZ2VuZGVyMltpXSA8LSAoc2ltZ2VuZGVyLWRpZmdlbmRlcikvbl9hbHRlcg0KICBlaWVkdWMyW2ldIDwtIChzaW1lZHVjLWRpZmVkdWMpL25fYWx0ZXINCiAgDQogIGFsdGVyc19hZ2UgPC0gYXMubnVtZXJpYyhuZXR3MnUkYWx0ZXJfYWdlKSAjYWx0ZXJzJyBhZ2UNCiAgYXZzaW1hZ2UyW2ldIDwtIG1lYW4oMSAtIGFicyhhbHRlcnNfYWdlIC0gZWdvX2FnZSkvcnYpICNhdmVyYWdlIHNpbWlsYXJpdHkgc2NvcmUNCiAgDQogICNkaWZmZXJlbmNlDQogIGVpZ2VuZGVyZFtpXSA8LSBlaWdlbmRlcjFbaV0gLSBlaWdlbmRlcjJbaV0NCiAgZWllZHVjZFtpXSA8LSBlaWVkdWMxW2ldIC0gZWllZHVjMltpXQ0KICBhdnNpbWFnZWRbaV0gPC0gYXZzaW1hZ2UxW2ldIC0gYXZzaW1hZ2UyW2ldDQogIA0KfQ0KDQp0YWJbMSwxXSA8LSBwYXN0ZTAoIGZvcm1hdChyb3VuZChtZWFuKGVpZ2VuZGVyMSwgbmEucm09VFJVRSksIDIpLCBuc21hbGwgPTIpLCAiICgiLCBmb3JtYXQocm91bmQoc2QoZWlnZW5kZXIxLCBuYS5ybT1UUlVFKSwgMiksIG5zbWFsbD0yKSwgIikiKQ0KdGFiWzEsMl0gPC0gcGFzdGUwKCBmb3JtYXQocm91bmQobWVhbihlaWdlbmRlcjIsIG5hLnJtPVRSVUUpLCAyKSwgbnNtYWxsID0yKSwgIiAoIiwgZm9ybWF0KHJvdW5kKHNkKGVpZ2VuZGVyMiwgbmEucm09VFJVRSksIDIpLCBuc21hbGw9MiksICIpIikNCnRhYlsxLDNdIDwtIHBhc3RlMCggZm9ybWF0KHJvdW5kKG1lYW4oZWlnZW5kZXJkLCBuYS5ybT1UUlVFKSwgMiksIG5zbWFsbCA9MiksICIgKCIsIGZvcm1hdChyb3VuZChzZChlaWdlbmRlcmQsIG5hLnJtPVRSVUUpLCAyKSwgbnNtYWxsPTIpLCAiKSIpDQoNCnRhYlsyLDFdIDwtIHBhc3RlMCggZm9ybWF0KHJvdW5kKG1lYW4oZWllZHVjMSwgbmEucm09VFJVRSksIDIpLCBuc21hbGwgPTIpLCAiICgiLCBmb3JtYXQocm91bmQoc2QoZWllZHVjMSwgbmEucm09VFJVRSksIDIpLCBuc21hbGw9MiksICIpIikNCnRhYlsyLDJdIDwtIHBhc3RlMCggZm9ybWF0KHJvdW5kKG1lYW4oZWllZHVjMiwgbmEucm09VFJVRSksIDIpLCBuc21hbGwgPTIpLCAiICgiLCBmb3JtYXQocm91bmQoc2QoZWllZHVjMiwgbmEucm09VFJVRSksIDIpLCBuc21hbGw9MiksICIpIikNCnRhYlsyLDNdIDwtIHBhc3RlMCggZm9ybWF0KHJvdW5kKG1lYW4oZWllZHVjZCwgbmEucm09VFJVRSksIDIpLCBuc21hbGwgPTIpLCAiICgiLCBmb3JtYXQocm91bmQoc2QoZWllZHVjZCwgbmEucm09VFJVRSksIDIpLCBuc21hbGw9MiksICIpIikNCg0KdGFiWzMsMV0gPC0gcGFzdGUwKCBmb3JtYXQocm91bmQobWVhbihhdnNpbWFnZTEsIG5hLnJtPVRSVUUpLCAyKSwgbnNtYWxsID0yKSwgIiAoIiwgZm9ybWF0KHJvdW5kKHNkKGF2c2ltYWdlMSwgbmEucm09VFJVRSksIDIpLCBuc21hbGw9MiksICIpIikNCnRhYlszLDJdIDwtIHBhc3RlMCggZm9ybWF0KHJvdW5kKG1lYW4oYXZzaW1hZ2UyLCBuYS5ybT1UUlVFKSwgMiksIG5zbWFsbCA9MiksICIgKCIsIGZvcm1hdChyb3VuZChzZChhdnNpbWFnZTIsIG5hLnJtPVRSVUUpLCAyKSwgbnNtYWxsPTIpLCAiKSIpDQp0YWJbMywzXSA8LSBwYXN0ZTAoIGZvcm1hdChyb3VuZChtZWFuKGF2c2ltYWdlZCwgbmEucm09VFJVRSksIDIpLCBuc21hbGwgPTIpLCAiICgiLCBmb3JtYXQocm91bmQoc2QoYXZzaW1hZ2VkLCBuYS5ybT1UUlVFKSwgMiksIG5zbWFsbD0yKSwgIikiKQ0KDQpmc2hvd2RmKHRhYiwgY2FwdGlvbj0iSG9tb2dlbmVpdHkgaW4gc3R1ZHkgbmV0d29yayBsYXllciBvZiAyODEgc3R1ZGVudHMgd2hvIHBhcnRpY2lwYXRlZCBpbiB3YXZlcyAxIGFuZCAyIikNCg0KYGBgDQoNCg0KDQotLS0NCg0K


Copyright © 2025 Rob Franken