Raw Dataset:
Aqui é apresentado o dataset que foi discutido na ultima reunião conforme planilha que o Biel gerou no Google Drive. Tal dataset consiste na relação entre os valores de mudanças e inserção de bugs commit. Segue uma descrição das respectivas colunas:
NoCommits : A Quantidade de commits (k) que a time serie possui;
commit : O respectivo commit dentro da time series com k commits;
NoTimeSeries : Quantidade de time series no commit;
NoBugsIns : Quantidade de bugs inseridos no respectivo commit;
noChanges : Quantidade de mudanças;
percBugs : Percentual de bugs inseridos [Formula noBugsIns/sum(noBugsIns)];
percChanges : Percentual de mudanças [Formula: noChanges/sum(noChanges) ];
Obs: Ressaltando que os dados no dataset encontram-se desnormalizados, portanto há uma possibilidade de repetição de valores em algumas colunas, ex: na coluna NoTimeSeries, na linha 2 e 3 existe o valor 1681 de maneira repetida, mas no cálculo das respectivas metricas é utilizado somente um valor, visto que existem somente 1681 time series com 2 commits e não o dobro (soma das linhas 2 e 3).
results_frame
Final Dataset:
Aqui é apresentado o dataset com as metricas calculadas com o objetivo de gerar os respectivos gráficos presentes na Goal 1 e 2. Segue uma descrição das colunas e suas respectivas formulas:
NoCommits : A Quantidade de commits (k) que a time serie possui;
NoTimeSeries : Quantidade de time series no commit;
noChanges : Quantidade de mudanças;
NoBugsIns : Quantidade de bugs inseridos no respectivo commit;
BugsByTs : Quantidade de bugs por time series [Formula : sum(noBugsIns)/max(noTimeSeries) ];
BugsByChanges :Quantidade de mudanças por bugs [Formula: sum(noBugsIns)/ sum(noChanges)];
ChangesByTs: Quantidade de mudanças pro time series [Formula: sum(noChanges)/ max(noTimeSeries)];
PercBugsByTs: Percentual de bugs por time series [Formula: (BugsByTs/sum(BugsByTs)) * 100];
PercBugsByCommit: Percentual de Bugs por commits [Formula: (noBugsIns/sum(noBugsIns)) * 100];
PercBugsByChanges: Percentual de Bugs por mudanças [Formula: (BugsByChanges/sum(BugsByChanges)) * 100];
PercTs: Percentual de time series [Formula: noTimeSeries / sum(noTimeSeries)) * 100];
PercChangesByTs: Percentual de mudanças por time series [Formula: (ChangesByTs / sum(ChangesByTs)) * 100];
PercChanges: Percentual de mudanças [Formula: (noChanges / sum(noChanges)) * 100];
Obs: Conforme explicado, os dados anteriores (raw dataset) tem algumas colunas desnormalizadas (NoTimeSeries), portanto algumas formulas contém o valor maximo da respectiva coluna dentro do agrupamento definido.
#Final Data Frame
data_plot <- as.data.frame(
results_frame %>%
dplyr::group_by(Project, NoCommits) %>%
dplyr::summarise(
noTimeSeries = max(noTimeSeries),
noChanges = sum(noChanges),
noBugsIns = sum(noBugsIns),
BugsByTs = sum(noBugsIns) / max(noTimeSeries),
BugsByChanges = sum(noBugsIns) / sum(noChanges),
ChangesByTs = sum(noChanges) / max(noTimeSeries)
) %>%
dplyr::mutate(
PercBugsByTs = (BugsByTs / sum(BugsByTs)) * 100,
PercBugsByCommit = (noBugsIns / sum(noBugsIns)) * 100,
PercBugsByChanges = (BugsByChanges / sum(BugsByChanges)) * 100,
PercTs = (noTimeSeries / sum(noTimeSeries)) * 100,
PercChangesByTs = (ChangesByTs / sum(ChangesByTs)) * 100,
PercChanges = (noChanges / sum(noChanges)) * 100
) %>%
dplyr::ungroup()
)
data_plot
(G1)To investigate the occurrence of commits along the time series;
(Q1.1) How often are commits performed along the time series?
#Frequency:
ggplot(data_plot) +
geom_bar(aes(x=NoCommits,y=noTimeSeries,group=Project), position = "dodge", stat = "identity") +
facet_grid(.~Project,scales="free") +
theme(legend.position= c(0.7, 0.95), legend.direction="horizontal", legend.title = element_blank(),
legend.text=element_text(size=5), legend.background = element_rect(fill = "transparent", colour = NA) ) +
ylab("Frequency of Time Series by Commits") + scale_x_discrete(name ="Number of Commits", limits=seq(1,max(data_plot$NoCommits))) +
theme(panel.grid.minor = element_blank(),
panel.grid.major = element_blank(),
plot.background = element_rect(fill = "transparent", colour = NA),
axis.text.x = element_text(colour="grey20",size=5,angle=90,hjust=.5,vjust=.5,face="plain"))

#Percentual
ggplot(data_plot) +
geom_bar(aes(x=NoCommits,y=PercTs,group=Project), position = "dodge", stat = "identity")+
facet_grid(.~Project,scales="free") +
theme(legend.position= c(0.7, 0.95), legend.direction="horizontal", legend.title = element_blank(),
legend.text=element_text(size=5), legend.background = element_rect(fill = "transparent", colour = NA) ) +
ylab("Percentual of Time Series by Commits") + scale_x_discrete(name ="Number of Commits", limits=seq(1,max(data_plot$NoCommits))) +
theme(panel.grid.minor = element_blank(),
panel.grid.major = element_blank(),
plot.background = element_rect(fill = "transparent", colour = NA),
axis.text.x = element_text(colour="grey20",size=5,angle=90,hjust=.5,vjust=.5,face="plain"))

(Q1.2) How often are changes performed among commits?
#Frequency:
ggplot(data_plot) +
geom_bar(aes(x=NoCommits,y=noChanges), position = "dodge", stat = "identity")+
facet_grid(.~Project,scales="free") +
theme(legend.position= c(0.7, 0.95), legend.direction="horizontal", legend.title = element_blank(),
legend.text=element_text(size=5), legend.background = element_rect(fill = "transparent", colour = NA)) +
ylab("Frequency of Changes by Commits") + scale_x_discrete(name ="Number of Commits", limits=seq(1,max(data_plot$NoCommits))) +
theme(panel.grid.minor = element_blank(),
panel.grid.major = element_blank(),
plot.background = element_rect(fill = "transparent", colour = NA),
axis.text.x = element_text(colour="grey20",size=5,angle=90,hjust=.5,vjust=.5,face="plain"))

#Percentual
ggplot(data_plot) +
geom_bar(aes(x=NoCommits,y=PercChanges), position = "dodge", stat = "identity")+
facet_grid(.~Project,scales="free") +
theme(legend.position= c(0.7, 0.95), legend.direction="horizontal", legend.title = element_blank(),
legend.text=element_text(size=5), legend.background = element_rect(fill = "transparent", colour = NA)) +
ylab("Percentual of Changes by Commits") + scale_x_discrete(name ="Number of Commits", limits=seq(1,max(data_plot$NoCommits))) +
theme(panel.grid.minor = element_blank(),
panel.grid.major = element_blank(),
plot.background = element_rect(fill = "transparent", colour = NA),
axis.text.x = element_text(colour="grey20",size=5,angle=90,hjust=.5,vjust=.5,face="plain"))

(Q1.3) How often are changes performed among time series?
#Frequency:
ggplot(data_plot) +
geom_bar(aes(x=NoCommits,y=ChangesByTs), position = "dodge", stat = "identity")+
facet_grid(.~Project,scales="free") +
theme(legend.position= c(0.7, 0.95), legend.direction="horizontal", legend.title = element_blank(),
legend.text=element_text(size=5), legend.background = element_rect(fill = "transparent", colour = NA)) +
ylab("Frequency of Changes by Time Seris") + scale_x_discrete(name ="Number of Commits", limits=seq(1,max(data_plot$NoCommits))) +
theme(panel.grid.minor = element_blank(),
panel.grid.major = element_blank(),
plot.background = element_rect(fill = "transparent", colour = NA),
axis.text.x = element_text(colour="grey20",size=5,angle=90,hjust=.5,vjust=.5,face="plain"))

#Percentual:
ggplot(data_plot) +
geom_bar(aes(x=NoCommits,y=PercChangesByTs), position = "dodge", stat = "identity")+
facet_grid(.~Project,scales="free") +
theme(legend.position= c(0.7, 0.95), legend.direction="horizontal", legend.title = element_blank(),
legend.text=element_text(size=5), legend.background = element_rect(fill = "transparent", colour = NA)) +
ylab("Percentual of Changes by Time Seris") + scale_x_discrete(name ="Number of Commits", limits=seq(1,max(data_plot$NoCommits))) +
theme(panel.grid.minor = element_blank(),
panel.grid.major = element_blank(),
plot.background = element_rect(fill = "transparent", colour = NA),
axis.text.x = element_text(colour="grey20",size=5,angle=90,hjust=.5,vjust=.5,face="plain"))

(G2)To assess the introduction of bugs along the history;
(Q2.1) How often are bugs introduced among the commits?
#Freq:
ggplot(data_plot) +
geom_bar(aes(x=NoCommits,y=noBugsIns), position = "dodge", stat = "identity")+
facet_grid(.~Project,scales="free") +
theme(legend.position= c(0.7, 0.95), legend.direction="horizontal", legend.title = element_blank(),
legend.text=element_text(size=5), legend.background = element_rect(fill = "transparent", colour = NA)) +
ylab("Percentual of Bugs by Commits") + scale_x_discrete(name ="Number of Commits", limits=seq(1,max(data_plot$NoCommits))) +
theme(panel.grid.minor = element_blank(),
panel.grid.major = element_blank(),
plot.background = element_rect(fill = "transparent", colour = NA),
axis.text.x = element_text(colour="grey20",size=5,angle=90,hjust=.5,vjust=.5,face="plain"))

#Perc
ggplot(data_plot) +
geom_bar(aes(x=NoCommits,y=PercBugsByCommit), position = "dodge", stat = "identity")+
facet_grid(.~Project,scales="free") +
theme(legend.position= c(0.7, 0.95), legend.direction="horizontal", legend.title = element_blank(),
legend.text=element_text(size=5), legend.background = element_rect(fill = "transparent", colour = NA)) +
ylab("Percentual of Bugs by Commits") + scale_x_discrete(name ="Number of Commits", limits=seq(1,max(data_plot$NoCommits))) +
theme(panel.grid.minor = element_blank(),
panel.grid.major = element_blank(),
plot.background = element_rect(fill = "transparent", colour = NA),
axis.text.x = element_text(colour="grey20",size=5,angle=90,hjust=.5,vjust=.5,face="plain"))

(Q2.2) How often are bugs introduced among the time series?
#Frequency:
ggplot(data_plot) +
geom_bar(aes(x=NoCommits,y=BugsByTs), position = "dodge", stat = "identity")+
facet_grid(.~Project,scales="free") +
theme(legend.position= c(0.7, 0.95), legend.direction="horizontal", legend.title = element_blank(),
legend.text=element_text(size=5), legend.background = element_rect(fill = "transparent", colour = NA)) +
ylab("Percentual of Bugs by Time Series") + scale_x_discrete(name ="Number of Commits", limits=seq(1,max(data_plot$NoCommits))) +
theme(panel.grid.minor = element_blank(),
panel.grid.major = element_blank(),
plot.background = element_rect(fill = "transparent", colour = NA),
axis.text.x = element_text(colour="grey20",size=5,angle=90,hjust=.5,vjust=.5,face="plain"))

#Percentual:
ggplot(data_plot) +
geom_bar(aes(x=NoCommits,y=PercBugsByTs), position = "dodge", stat = "identity")+
facet_grid(.~Project,scales="free") +
theme(legend.position= c(0.7, 0.95), legend.direction="horizontal", legend.title = element_blank(),
legend.text=element_text(size=5), legend.background = element_rect(fill = "transparent", colour = NA)) +
ylab("Percentual of Bugs by Time Series") + scale_x_discrete(name ="Number of Commits", limits=seq(1,max(data_plot$NoCommits))) +
theme(panel.grid.minor = element_blank(),
panel.grid.major = element_blank(),
plot.background = element_rect(fill = "transparent", colour = NA),
axis.text.x = element_text(colour="grey20",size=5,angle=90,hjust=.5,vjust=.5,face="plain"))

(Q2.3) How often are bugs introduced among the changes?
#Freq:
ggplot(data_plot) +
geom_bar(aes(x=NoCommits,y=BugsByChanges), position = "dodge", stat = "identity")+
facet_grid(.~Project,scales="free") +
theme(legend.position= c(0.7, 0.95), legend.direction="horizontal", legend.title = element_blank(),
legend.text=element_text(size=5), legend.background = element_rect(fill = "transparent", colour = NA)) +
ylab("Percentual of Bugs by Changes") + scale_x_discrete(name ="Number of Commits", limits=seq(1,max(data_plot$NoCommits))) +
theme(panel.grid.minor = element_blank(),
panel.grid.major = element_blank(),
plot.background = element_rect(fill = "transparent", colour = NA),
axis.text.x = element_text(colour="grey20",size=5,angle=90,hjust=.5,vjust=.5,face="plain"))

#Perc:
ggplot(data_plot) +
geom_bar(aes(x=NoCommits,y=PercBugsByChanges), position = "dodge", stat = "identity")+
facet_grid(.~Project,scales="free") +
theme(legend.position= c(0.7, 0.95), legend.direction="horizontal", legend.title = element_blank(),
legend.text=element_text(size=5), legend.background = element_rect(fill = "transparent", colour = NA)) +
ylab("Percentual of Bugs by Changes") + scale_x_discrete(name ="Number of Commits", limits=seq(1,max(data_plot$NoCommits))) +
theme(panel.grid.minor = element_blank(),
panel.grid.major = element_blank(),
plot.background = element_rect(fill = "transparent", colour = NA),
axis.text.x = element_text(colour="grey20",size=5,angle=90,hjust=.5,vjust=.5,face="plain"))

(G3) To analyse the kind of changes are mostly related to the bugs insertion;
(Q3.1) Which are the types (Add/Del) of changes more frequent in the bugs insertion?
#Changes Chart
methods_changes <- filter(methods_insertions, changeType != 'All', groupMetric == 'All', Metric == 'All')
methods_changes[methods_changes$changeType == "changeMetricsAddition", c("changeType")] <- "Addition"
methods_changes[methods_changes$changeType == "changeMetricsDeletion", c("changeType")] <- "Deletion"
cbPalette <- c("#009E73", "#F15854")
methods_changes <- as.data.frame(
methods_changes %>%
dplyr::group_by(Project, changeType) %>%
dplyr::summarise(totalChanges = sum(Count)) %>%
mutate(Percentual = totalChanges / sum(totalChanges) * 100) %>%
ungroup()
)
ggplot(methods_changes) +
geom_bar(aes(x = Project, y = Percentual, fill = changeType, group = changeType), position = "dodge", stat = "identity") +
geom_text( aes(x = Project, y = Percentual, label = round(Percentual), group = changeType),
check_overlap = TRUE, position = position_dodge(width = 1), vjust = -0.5, size = 3) + #scale_fill_grey() +
theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
theme(legend.position= c(0.82, 0.95), legend.direction="horizontal", legend.title = element_blank(),
axis.title.x=element_blank(), legend.text=element_text(size=7), legend.background = element_rect(fill = "transparent", colour = NA) ) +
theme(panel.grid.minor = element_blank(),
panel.grid.major = element_blank(),
plot.background = element_rect(fill = "transparent", colour = NA)) +
scale_fill_manual(values=cbPalette)

(Q3.2) Which are the metrics groups more frequent in the bugs insertion?
#Filter:D
methods_groups<- filter(methods_insertions, groupMetric != "RM", changeType == 'All', groupMetric != 'All', Metric == 'All')
#Group measures
methods_groups <- as.data.frame(
methods_groups %>%
dplyr::group_by(Project, groupMetric) %>%
dplyr::summarise(Changes = sum(Count)) %>%
dplyr::mutate(Percentual = Changes / sum(Changes) * 100) %>%
dplyr::ungroup()
)
#Plot
ggplot(methods_groups) +
geom_bar(aes(x = reorder(groupMetric, -Percentual), y = Percentual), position = "dodge", stat = "identity") +
geom_text( aes(x = reorder(groupMetric, -Percentual), y = Percentual, label = round(Percentual)),
check_overlap = TRUE, position = position_dodge(width = 1), vjust = -0.5, size = 3) + #scale_fill_grey() +
theme(axis.text.x = element_text(angle = 45, hjust = 1, size= 8)) +
theme(legend.position= c(0.82, 0.95), legend.direction="horizontal", legend.title = element_blank(),
axis.title.x=element_blank(), legend.text=element_text(size=7), legend.background = element_rect(fill = "transparent", colour = NA) ) +
theme(panel.grid.minor = element_blank(),
panel.grid.major = element_blank(),
plot.background = element_rect(fill = "transparent", colour = NA))

(Q3.3) Which are the change metrics more frequent in the bugs insertion?
#Filter:D
methods_ind <- filter(methods_insertions, groupMetric != "RM", changeType == 'All', groupMetric != 'All', Metric != 'All')
#ORder metrics by frequency
freqs_metrics <- plyr::count(methods_ind$Metric)
freqs_metrics <- freqs_metrics[order(-freqs_metrics$freq), ]
#Grouping data
methods_ind <- as.data.frame(
methods_ind %>%
dplyr::group_by(Project, Metric) %>%
dplyr::summarise(Changes = sum(Count)) %>%
dplyr::mutate(Percentual = Changes / sum(Changes) * 100) %>%
dplyr::ungroup()
)
#Top metrics
top_metrics <- head(freqs_metrics, 15)
methods_ind <- methods_ind[methods_ind$Metric %in% top_metrics$x, ]
#Plot
ggplot(methods_ind) +
geom_bar(aes(x = reorder(Metric, -Percentual), y = Percentual), position = "dodge", stat = "identity") +
#geom_text( aes(x = reorder(Metric, -Percentual), y = Percentual, label = round(Percentual)),
# check_overlap = TRUE, position = position_dodge(width = 1), vjust = -0.5, size = 3) + #scale_fill_grey() +
theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 7)) +
theme(legend.position= c(0.82, 0.95), legend.direction="horizontal", legend.title = element_blank(),
axis.title.x=element_blank(), legend.text=element_text(size=7), legend.background = element_rect(fill = "transparent", colour = NA) ) +
theme(panel.grid.minor = element_blank(),
panel.grid.major = element_blank(),
plot.background = element_rect(fill = "transparent", colour = NA))

(G4) To analyse the relation between the history of changes and bugs;
(Q4.1) Is a high number of changes an indicative of bugs introduction?
#Changes Chart
methods_changes <- filter(methods_total, changeType == 'All', groupMetric == 'All', Metric == 'All')
#Calculing peaks
methods_changes[,"totalofBugsIns"] <- maply(methods_changes$bugsInsertion, getTotalBugsIns)
#Filtering only ts with bugs and more with one commit
methods_changes <- filter(methods_changes, totalofBugsIns > 0, NtimeofCommits > 1)
#Generating id of data frame
methods_changes <- genId(methods_changes)
#List of changes and bugs insertions
listofPeaks <<- methods_changes$elementsValue
listofBugsIns <<- methods_changes$bugsInsertion
#Creating columns
methods_changes[,c("peaks", "tp", "fp", "fn", "tn", "precision", "recall", "fmeasure")] <- 0
#calculating confusion matrix
methods_changes[,c("peaks", "tp", "fp", "fn", "tn", "precision", "recall", "fmeasure")] <- plyr::ldply(methods_changes$id, getStatsProcess)
#Grouping data
confusion_matrix <- as.data.frame(
methods_changes %>%
dplyr::group_by(Project) %>%
dplyr::summarise(
precision = median(precision, na.rm = TRUE),
recall = median(recall, na.rm = TRUE),
fmeasure = median(fmeasure, na.rm = TRUE)
)
)
#Pivot data
confusion_matrix <- melt(dfPeaks, id = (c("Project")))
colnames(confusion_matrix) <- c("Project", "Measure", "Values")
#Ploting results
ggplot(confusion_matrix) +
geom_bar(aes(x = Measure, y = Values), position = "dodge", stat = "identity") +
geom_text(aes(x = Measure, y = Values, label = round(Values,2)),
check_overlap = TRUE, position = position_dodge(width = 1), vjust = -0.5, size = 3) +
theme(legend.direction="vertical", legend.title = element_blank(), legend.text=element_text(size=8),
legend.background = element_rect(fill = "transparent", colour = NA), axis.ticks.x = ) +
theme(panel.grid.minor = element_blank(),
panel.grid.major = element_blank(),
plot.background = element_rect(fill = "transparent", colour = NA)) +
ggtitle(project) + ylab("Percentual")

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyMjIFByb2plY3QgT2todHRwCgpgYGB7cn0KI0ltcG9ydGluZyBmdW5jdGlvbnM6CnNvdXJjZSgifi9SL3NvZnR3YXJlLWhpc3Rvcnkvc2NyaXB0cy91dGlscy5SIikKCnByb2plY3QgPC0gIk9raHR0cCIKCiNDc3YnczoKcmVzdWx0c19mcmFtZSA8LSAKICByZWFkLmNzdigKICAgIHBhc3RlMCgiL2hvbWUvcjRwaC9SL2FuYWx5c2lzL3Jlc3VsdHMvIixwcm9qZWN0LCJfcmVzdWx0c1Jxc0J1Z3NJbnMuY3N2IiksIAogICAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFCiAgKQoKbWV0aG9kc19pbnNlcnRpb25zIDwtCiAgcmVhZC5jc3YoCiAgICBwYXN0ZTAoIn4vUi9hbmFseXNpcy9yZXN1bHRzX2luc2VydGlvbnMvIixwcm9qZWN0LCJfaW5zZXJ0aW9uVHMuY3N2IiksCiAgICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UKICApCgptZXRob2RzX3RvdGFsPC0KICByZWFkLmNzdigKICAgIHBhc3RlMCgifi9SL2FuYWx5c2lzL3Jlc3VsdHMvIixwcm9qZWN0LCJfY2hhbmdlc1RzV2l0aEJ1Z3NJbnMuY3N2IiksCiAgICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UKICApCgpyZXN1bHRzX2ZyYW1lJFByb2plY3QgPC0gcHJvamVjdAoKYGBgCgoKIyMjUmF3IERhdGFzZXQ6CkFxdWkgw6kgYXByZXNlbnRhZG8gbyBkYXRhc2V0IHF1ZSBmb2kgZGlzY3V0aWRvIG5hIHVsdGltYSByZXVuacOjbyBjb25mb3JtZSBwbGFuaWxoYSBxdWUgbyBCaWVsIGdlcm91IG5vIEdvb2dsZSBEcml2ZS4gVGFsIGRhdGFzZXQgY29uc2lzdGUgbmEgcmVsYcOnw6NvIGVudHJlIG9zIHZhbG9yZXMgZGUgbXVkYW7Dp2FzIGUgaW5zZXLDp8OjbyBkZSBidWdzIGNvbW1pdC4gU2VndWUgdW1hIGRlc2NyacOnw6NvIGRhcyByZXNwZWN0aXZhcyBjb2x1bmFzOgoKKipOb0NvbW1pdHMqKiA6IEEgUXVhbnRpZGFkZSBkZSBjb21taXRzIChrKSBxdWUgYSB0aW1lIHNlcmllIHBvc3N1aTsKCioqY29tbWl0KiogOiBPIHJlc3BlY3Rpdm8gY29tbWl0IGRlbnRybyBkYSB0aW1lIHNlcmllcyBjb20gayBjb21taXRzOwoKKipOb1RpbWVTZXJpZXMqKiA6IFF1YW50aWRhZGUgZGUgdGltZSBzZXJpZXMgbm8gY29tbWl0OwoKKipOb0J1Z3NJbnMqKiA6IFF1YW50aWRhZGUgZGUgYnVncyBpbnNlcmlkb3Mgbm8gcmVzcGVjdGl2byBjb21taXQ7CgoqKm5vQ2hhbmdlcyoqIDogUXVhbnRpZGFkZSBkZSBtdWRhbsOnYXM7CgoqKnBlcmNCdWdzKiogOiBQZXJjZW50dWFsIGRlIGJ1Z3MgaW5zZXJpZG9zIFtGb3JtdWxhIG5vQnVnc0lucy9zdW0obm9CdWdzSW5zKV07CgoqKnBlcmNDaGFuZ2VzKiogOiBQZXJjZW50dWFsIGRlIG11ZGFuw6dhcyBbRm9ybXVsYTogbm9DaGFuZ2VzL3N1bShub0NoYW5nZXMpIF07CgoKT2JzOiBSZXNzYWx0YW5kbyBxdWUgb3MgZGFkb3Mgbm8gZGF0YXNldCBlbmNvbnRyYW0tc2UgZGVzbm9ybWFsaXphZG9zLCBwb3J0YW50byBow6EgdW1hIHBvc3NpYmlsaWRhZGUgZGUgcmVwZXRpw6fDo28gIGRlIHZhbG9yZXMgZW0gYWxndW1hcyBjb2x1bmFzLCBleDogbmEgY29sdW5hIE5vVGltZVNlcmllcywgbmEgbGluaGEgMiBlIDMgZXhpc3RlIG8gdmFsb3IgMTY4MSBkZSBtYW5laXJhIHJlcGV0aWRhLCBtYXMgbm8gY8OhbGN1bG8gZGFzIHJlc3BlY3RpdmFzIG1ldHJpY2FzIMOpIHV0aWxpemFkbyBzb21lbnRlIHVtIHZhbG9yLCB2aXN0byBxdWUgZXhpc3RlbSBzb21lbnRlIDE2ODEgdGltZSBzZXJpZXMgY29tIDIgY29tbWl0cyBlIG7Do28gbyBkb2JybyAoc29tYSBkYXMgbGluaGFzIDIgZSAzKS4KCmBgYHtyfQpyZXN1bHRzX2ZyYW1lCgpgYGAKCiMjI0ZpbmFsIERhdGFzZXQ6CkFxdWkgw6kgYXByZXNlbnRhZG8gbyBkYXRhc2V0IGNvbSBhcyBtZXRyaWNhcyBjYWxjdWxhZGFzIGNvbSBvIG9iamV0aXZvIGRlIGdlcmFyIG9zIHJlc3BlY3Rpdm9zIGdyw6FmaWNvcyBwcmVzZW50ZXMgbmEgR29hbCAxIGUgMi4gU2VndWUgdW1hIGRlc2NyacOnw6NvIGRhcyBjb2x1bmFzIGUgc3VhcyByZXNwZWN0aXZhcyBmb3JtdWxhczoKCioqTm9Db21taXRzKiogOiBBIFF1YW50aWRhZGUgZGUgY29tbWl0cyAoaykgcXVlIGEgdGltZSBzZXJpZSBwb3NzdWk7CgoqKk5vVGltZVNlcmllcyoqIDogUXVhbnRpZGFkZSBkZSB0aW1lIHNlcmllcyBubyBjb21taXQ7CgoqKm5vQ2hhbmdlcyoqIDogUXVhbnRpZGFkZSBkZSBtdWRhbsOnYXM7CgoqKk5vQnVnc0lucyoqIDogUXVhbnRpZGFkZSBkZSBidWdzIGluc2VyaWRvcyBubyByZXNwZWN0aXZvIGNvbW1pdDsKCioqQnVnc0J5VHMqKiA6IFF1YW50aWRhZGUgZGUgYnVncyBwb3IgdGltZSBzZXJpZXMgW0Zvcm11bGEgOiBzdW0obm9CdWdzSW5zKS9tYXgobm9UaW1lU2VyaWVzKSBdOwoKKipCdWdzQnlDaGFuZ2VzKiogOlF1YW50aWRhZGUgZGUgbXVkYW7Dp2FzIHBvciBidWdzIFtGb3JtdWxhOiBzdW0obm9CdWdzSW5zKS8gc3VtKG5vQ2hhbmdlcyldOwoKKipDaGFuZ2VzQnlUcyoqOiBRdWFudGlkYWRlIGRlIG11ZGFuw6dhcyBwcm8gdGltZSBzZXJpZXMgW0Zvcm11bGE6IHN1bShub0NoYW5nZXMpLyBtYXgobm9UaW1lU2VyaWVzKV07CgoqKlBlcmNCdWdzQnlUcyoqOiBQZXJjZW50dWFsIGRlIGJ1Z3MgcG9yIHRpbWUgc2VyaWVzIFtGb3JtdWxhOiAoQnVnc0J5VHMvc3VtKEJ1Z3NCeVRzKSkgKiAxMDBdOwoKKipQZXJjQnVnc0J5Q29tbWl0Kio6IFBlcmNlbnR1YWwgZGUgQnVncyBwb3IgY29tbWl0cyBbRm9ybXVsYTogKG5vQnVnc0lucy9zdW0obm9CdWdzSW5zKSkgKiAxMDBdOwoKKipQZXJjQnVnc0J5Q2hhbmdlcyoqOiBQZXJjZW50dWFsIGRlIEJ1Z3MgcG9yIG11ZGFuw6dhcyBbRm9ybXVsYTogKEJ1Z3NCeUNoYW5nZXMvc3VtKEJ1Z3NCeUNoYW5nZXMpKSAqIDEwMF07CgoqKlBlcmNUcyoqOiBQZXJjZW50dWFsIGRlIHRpbWUgc2VyaWVzIFtGb3JtdWxhOiBub1RpbWVTZXJpZXMgLyBzdW0obm9UaW1lU2VyaWVzKSkgKiAxMDBdOwoKKipQZXJjQ2hhbmdlc0J5VHMqKjogUGVyY2VudHVhbCBkZSBtdWRhbsOnYXMgcG9yIHRpbWUgc2VyaWVzIFtGb3JtdWxhOiAoQ2hhbmdlc0J5VHMgLyBzdW0oQ2hhbmdlc0J5VHMpKSAqIDEwMF07CgoqKlBlcmNDaGFuZ2VzKio6IFBlcmNlbnR1YWwgZGUgbXVkYW7Dp2FzIFtGb3JtdWxhOiAgKG5vQ2hhbmdlcyAvIHN1bShub0NoYW5nZXMpKSAqIDEwMF07CgpPYnM6IENvbmZvcm1lIGV4cGxpY2Fkbywgb3MgZGFkb3MgYW50ZXJpb3JlcyAocmF3IGRhdGFzZXQpIHRlbSBhbGd1bWFzIGNvbHVuYXMgZGVzbm9ybWFsaXphZGFzIChOb1RpbWVTZXJpZXMpLCBwb3J0YW50byBhbGd1bWFzIGZvcm11bGFzIGNvbnTDqW0gbyB2YWxvciBtYXhpbW8gZGEgcmVzcGVjdGl2YSBjb2x1bmEgZGVudHJvIGRvIGFncnVwYW1lbnRvIGRlZmluaWRvLgoKYGBge3J9CiNGaW5hbCBEYXRhIEZyYW1lCmRhdGFfcGxvdCA8LSBhcy5kYXRhLmZyYW1lKAogIHJlc3VsdHNfZnJhbWUgJT4lCiAgICBkcGx5cjo6Z3JvdXBfYnkoUHJvamVjdCwgTm9Db21taXRzKSAlPiUKICAgIGRwbHlyOjpzdW1tYXJpc2UoCiAgICAgIG5vVGltZVNlcmllcyA9IG1heChub1RpbWVTZXJpZXMpLAogICAgICBub0NoYW5nZXMgPSBzdW0obm9DaGFuZ2VzKSwKICAgICAgbm9CdWdzSW5zID0gc3VtKG5vQnVnc0lucyksCiAgICAgIEJ1Z3NCeVRzID0gc3VtKG5vQnVnc0lucykgLyBtYXgobm9UaW1lU2VyaWVzKSwKICAgICAgQnVnc0J5Q2hhbmdlcyA9IHN1bShub0J1Z3NJbnMpIC8gc3VtKG5vQ2hhbmdlcyksCiAgICAgIENoYW5nZXNCeVRzID0gc3VtKG5vQ2hhbmdlcykgLyBtYXgobm9UaW1lU2VyaWVzKQogICAgKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoCiAgICAgIFBlcmNCdWdzQnlUcyA9IChCdWdzQnlUcyAvIHN1bShCdWdzQnlUcykpICogMTAwLAogICAgICBQZXJjQnVnc0J5Q29tbWl0ID0gKG5vQnVnc0lucyAvIHN1bShub0J1Z3NJbnMpKSAqIDEwMCwKICAgICAgUGVyY0J1Z3NCeUNoYW5nZXMgPSAoQnVnc0J5Q2hhbmdlcyAvIHN1bShCdWdzQnlDaGFuZ2VzKSkgKiAxMDAsCiAgICAgIFBlcmNUcyA9IChub1RpbWVTZXJpZXMgLyBzdW0obm9UaW1lU2VyaWVzKSkgKiAxMDAsCiAgICAgIFBlcmNDaGFuZ2VzQnlUcyA9IChDaGFuZ2VzQnlUcyAvIHN1bShDaGFuZ2VzQnlUcykpICogMTAwLAogICAgICBQZXJjQ2hhbmdlcyA9IChub0NoYW5nZXMgLyBzdW0obm9DaGFuZ2VzKSkgKiAxMDAKICAgICkgJT4lCiAgICBkcGx5cjo6dW5ncm91cCgpCikKCmRhdGFfcGxvdApgYGAKCgojIyMgKEcxKVRvIGludmVzdGlnYXRlIHRoZSBvY2N1cnJlbmNlIG9mIGNvbW1pdHMgYWxvbmcgdGhlIHRpbWUgc2VyaWVzOyAKIyMjIyhRMS4xKSBIb3cgb2Z0ZW4gYXJlIGNvbW1pdHMgcGVyZm9ybWVkIGFsb25nIHRoZSB0aW1lIHNlcmllcz8KYGBge3J9CgojRnJlcXVlbmN5OgpnZ3Bsb3QoZGF0YV9wbG90KSArCiAgZ2VvbV9iYXIoYWVzKHg9Tm9Db21taXRzLHk9bm9UaW1lU2VyaWVzLGdyb3VwPVByb2plY3QpLCBwb3NpdGlvbiA9ICJkb2RnZSIsIHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgZmFjZXRfZ3JpZCguflByb2plY3Qsc2NhbGVzPSJmcmVlIikgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb249IGMoMC43LCAwLjk1KSwgbGVnZW5kLmRpcmVjdGlvbj0iaG9yaXpvbnRhbCIsIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9NSksIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSBOQSkgKSArCiAgeWxhYigiRnJlcXVlbmN5IG9mIFRpbWUgU2VyaWVzIGJ5IENvbW1pdHMiKSArIHNjYWxlX3hfZGlzY3JldGUobmFtZSA9Ik51bWJlciBvZiBDb21taXRzIiwgbGltaXRzPXNlcSgxLG1heChkYXRhX3Bsb3QkTm9Db21taXRzKSkpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkEpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGNvbG91cj0iZ3JleTIwIixzaXplPTUsYW5nbGU9OTAsaGp1c3Q9LjUsdmp1c3Q9LjUsZmFjZT0icGxhaW4iKSkKCiNQZXJjZW50dWFsCmdncGxvdChkYXRhX3Bsb3QpICsKICBnZW9tX2JhcihhZXMoeD1Ob0NvbW1pdHMseT1QZXJjVHMsZ3JvdXA9UHJvamVjdCksIHBvc2l0aW9uID0gImRvZGdlIiwgc3RhdCA9ICJpZGVudGl0eSIpKwogIGZhY2V0X2dyaWQoLn5Qcm9qZWN0LHNjYWxlcz0iZnJlZSIpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSBjKDAuNywgMC45NSksIGxlZ2VuZC5kaXJlY3Rpb249Imhvcml6b250YWwiLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTUpLCBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkEpICkgKwogIHlsYWIoIlBlcmNlbnR1YWwgb2YgVGltZSBTZXJpZXMgYnkgQ29tbWl0cyIpICsgc2NhbGVfeF9kaXNjcmV0ZShuYW1lID0iTnVtYmVyIG9mIENvbW1pdHMiLCBsaW1pdHM9c2VxKDEsbWF4KGRhdGFfcGxvdCROb0NvbW1pdHMpKSkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSBOQSksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoY29sb3VyPSJncmV5MjAiLHNpemU9NSxhbmdsZT05MCxoanVzdD0uNSx2anVzdD0uNSxmYWNlPSJwbGFpbiIpKQoKCmBgYAoKCgojIyMjKFExLjIpIEhvdyBvZnRlbiBhcmUgY2hhbmdlcyBwZXJmb3JtZWQgYW1vbmcgY29tbWl0cz8KYGBge3J9CgojRnJlcXVlbmN5OgpnZ3Bsb3QoZGF0YV9wbG90KSArCiAgZ2VvbV9iYXIoYWVzKHg9Tm9Db21taXRzLHk9bm9DaGFuZ2VzKSwgcG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0ID0gImlkZW50aXR5IikrCiAgZmFjZXRfZ3JpZCguflByb2plY3Qsc2NhbGVzPSJmcmVlIikgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb249IGMoMC43LCAwLjk1KSwgbGVnZW5kLmRpcmVjdGlvbj0iaG9yaXpvbnRhbCIsIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9NSksIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSBOQSkpICsKICB5bGFiKCJGcmVxdWVuY3kgb2YgQ2hhbmdlcyBieSBDb21taXRzIikgKyBzY2FsZV94X2Rpc2NyZXRlKG5hbWUgPSJOdW1iZXIgb2YgQ29tbWl0cyIsIGxpbWl0cz1zZXEoMSxtYXgoZGF0YV9wbG90JE5vQ29tbWl0cykpKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChjb2xvdXI9ImdyZXkyMCIsc2l6ZT01LGFuZ2xlPTkwLGhqdXN0PS41LHZqdXN0PS41LGZhY2U9InBsYWluIikpCgoKI1BlcmNlbnR1YWwKZ2dwbG90KGRhdGFfcGxvdCkgKwogIGdlb21fYmFyKGFlcyh4PU5vQ29tbWl0cyx5PVBlcmNDaGFuZ2VzKSwgcG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0ID0gImlkZW50aXR5IikrCiAgZmFjZXRfZ3JpZCguflByb2plY3Qsc2NhbGVzPSJmcmVlIikgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb249IGMoMC43LCAwLjk1KSwgbGVnZW5kLmRpcmVjdGlvbj0iaG9yaXpvbnRhbCIsIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9NSksIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSBOQSkpICsKICB5bGFiKCJQZXJjZW50dWFsIG9mIENoYW5nZXMgYnkgQ29tbWl0cyIpICsgc2NhbGVfeF9kaXNjcmV0ZShuYW1lID0iTnVtYmVyIG9mIENvbW1pdHMiLCBsaW1pdHM9c2VxKDEsbWF4KGRhdGFfcGxvdCROb0NvbW1pdHMpKSkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSBOQSksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoY29sb3VyPSJncmV5MjAiLHNpemU9NSxhbmdsZT05MCxoanVzdD0uNSx2anVzdD0uNSxmYWNlPSJwbGFpbiIpKQoKYGBgCgojIyMjKFExLjMpIEhvdyBvZnRlbiBhcmUgY2hhbmdlcyBwZXJmb3JtZWQgYW1vbmcgdGltZSBzZXJpZXM/CmBgYHtyfQoKI0ZyZXF1ZW5jeToKZ2dwbG90KGRhdGFfcGxvdCkgKwogIGdlb21fYmFyKGFlcyh4PU5vQ29tbWl0cyx5PUNoYW5nZXNCeVRzKSwgcG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0ID0gImlkZW50aXR5IikrCiAgZmFjZXRfZ3JpZCguflByb2plY3Qsc2NhbGVzPSJmcmVlIikgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb249IGMoMC43LCAwLjk1KSwgbGVnZW5kLmRpcmVjdGlvbj0iaG9yaXpvbnRhbCIsIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9NSksIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSBOQSkpICsKICB5bGFiKCJGcmVxdWVuY3kgb2YgQ2hhbmdlcyBieSBUaW1lIFNlcmlzIikgKyBzY2FsZV94X2Rpc2NyZXRlKG5hbWUgPSJOdW1iZXIgb2YgQ29tbWl0cyIsIGxpbWl0cz1zZXEoMSxtYXgoZGF0YV9wbG90JE5vQ29tbWl0cykpKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChjb2xvdXI9ImdyZXkyMCIsc2l6ZT01LGFuZ2xlPTkwLGhqdXN0PS41LHZqdXN0PS41LGZhY2U9InBsYWluIikpCgojUGVyY2VudHVhbDoKZ2dwbG90KGRhdGFfcGxvdCkgKwogIGdlb21fYmFyKGFlcyh4PU5vQ29tbWl0cyx5PVBlcmNDaGFuZ2VzQnlUcyksIHBvc2l0aW9uID0gImRvZGdlIiwgc3RhdCA9ICJpZGVudGl0eSIpKwogIGZhY2V0X2dyaWQoLn5Qcm9qZWN0LHNjYWxlcz0iZnJlZSIpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSBjKDAuNywgMC45NSksIGxlZ2VuZC5kaXJlY3Rpb249Imhvcml6b250YWwiLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTUpLCBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkEpKSArCiAgeWxhYigiUGVyY2VudHVhbCBvZiBDaGFuZ2VzIGJ5IFRpbWUgU2VyaXMiKSArIHNjYWxlX3hfZGlzY3JldGUobmFtZSA9Ik51bWJlciBvZiBDb21taXRzIiwgbGltaXRzPXNlcSgxLG1heChkYXRhX3Bsb3QkTm9Db21taXRzKSkpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkEpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGNvbG91cj0iZ3JleTIwIixzaXplPTUsYW5nbGU9OTAsaGp1c3Q9LjUsdmp1c3Q9LjUsZmFjZT0icGxhaW4iKSkKCmBgYAoKIyMjIChHMilUbyBhc3Nlc3MgdGhlIGludHJvZHVjdGlvbiBvZiBidWdzIGFsb25nIHRoZSBoaXN0b3J5OyAKCiMjIyMgKFEyLjEpIEhvdyBvZnRlbiBhcmUgYnVncyBpbnRyb2R1Y2VkIGFtb25nIHRoZSBjb21taXRzPwpgYGB7cn0KCiNGcmVxOgpnZ3Bsb3QoZGF0YV9wbG90KSArCiAgZ2VvbV9iYXIoYWVzKHg9Tm9Db21taXRzLHk9bm9CdWdzSW5zKSwgcG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0ID0gImlkZW50aXR5IikrCiAgZmFjZXRfZ3JpZCguflByb2plY3Qsc2NhbGVzPSJmcmVlIikgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb249IGMoMC43LCAwLjk1KSwgbGVnZW5kLmRpcmVjdGlvbj0iaG9yaXpvbnRhbCIsIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9NSksIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSBOQSkpICsKICB5bGFiKCJQZXJjZW50dWFsIG9mIEJ1Z3MgYnkgQ29tbWl0cyIpICsgc2NhbGVfeF9kaXNjcmV0ZShuYW1lID0iTnVtYmVyIG9mIENvbW1pdHMiLCBsaW1pdHM9c2VxKDEsbWF4KGRhdGFfcGxvdCROb0NvbW1pdHMpKSkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSBOQSksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoY29sb3VyPSJncmV5MjAiLHNpemU9NSxhbmdsZT05MCxoanVzdD0uNSx2anVzdD0uNSxmYWNlPSJwbGFpbiIpKQoKI1BlcmMKZ2dwbG90KGRhdGFfcGxvdCkgKwogIGdlb21fYmFyKGFlcyh4PU5vQ29tbWl0cyx5PVBlcmNCdWdzQnlDb21taXQpLCBwb3NpdGlvbiA9ICJkb2RnZSIsIHN0YXQgPSAiaWRlbnRpdHkiKSsKICBmYWNldF9ncmlkKC5+UHJvamVjdCxzY2FsZXM9ImZyZWUiKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0gYygwLjcsIDAuOTUpLCBsZWdlbmQuZGlyZWN0aW9uPSJob3Jpem9udGFsIiwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT01KSwgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSkgKwogIHlsYWIoIlBlcmNlbnR1YWwgb2YgQnVncyBieSBDb21taXRzIikgKyBzY2FsZV94X2Rpc2NyZXRlKG5hbWUgPSJOdW1iZXIgb2YgQ29tbWl0cyIsIGxpbWl0cz1zZXEoMSxtYXgoZGF0YV9wbG90JE5vQ29tbWl0cykpKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChjb2xvdXI9ImdyZXkyMCIsc2l6ZT01LGFuZ2xlPTkwLGhqdXN0PS41LHZqdXN0PS41LGZhY2U9InBsYWluIikpCmBgYAoKIyMjIyAoUTIuMikgSG93IG9mdGVuIGFyZSBidWdzIGludHJvZHVjZWQgYW1vbmcgdGhlIHRpbWUgc2VyaWVzPwpgYGB7cn0KCiNGcmVxdWVuY3k6CmdncGxvdChkYXRhX3Bsb3QpICsKICBnZW9tX2JhcihhZXMoeD1Ob0NvbW1pdHMseT1CdWdzQnlUcyksIHBvc2l0aW9uID0gImRvZGdlIiwgc3RhdCA9ICJpZGVudGl0eSIpKwogIGZhY2V0X2dyaWQoLn5Qcm9qZWN0LHNjYWxlcz0iZnJlZSIpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSBjKDAuNywgMC45NSksIGxlZ2VuZC5kaXJlY3Rpb249Imhvcml6b250YWwiLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTUpLCBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkEpKSArCiAgeWxhYigiUGVyY2VudHVhbCBvZiBCdWdzIGJ5IFRpbWUgU2VyaWVzIikgKyBzY2FsZV94X2Rpc2NyZXRlKG5hbWUgPSJOdW1iZXIgb2YgQ29tbWl0cyIsIGxpbWl0cz1zZXEoMSxtYXgoZGF0YV9wbG90JE5vQ29tbWl0cykpKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChjb2xvdXI9ImdyZXkyMCIsc2l6ZT01LGFuZ2xlPTkwLGhqdXN0PS41LHZqdXN0PS41LGZhY2U9InBsYWluIikpCgojUGVyY2VudHVhbDoKZ2dwbG90KGRhdGFfcGxvdCkgKwogIGdlb21fYmFyKGFlcyh4PU5vQ29tbWl0cyx5PVBlcmNCdWdzQnlUcyksIHBvc2l0aW9uID0gImRvZGdlIiwgc3RhdCA9ICJpZGVudGl0eSIpKwogIGZhY2V0X2dyaWQoLn5Qcm9qZWN0LHNjYWxlcz0iZnJlZSIpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSBjKDAuNywgMC45NSksIGxlZ2VuZC5kaXJlY3Rpb249Imhvcml6b250YWwiLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTUpLCBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkEpKSArCiAgeWxhYigiUGVyY2VudHVhbCBvZiBCdWdzIGJ5IFRpbWUgU2VyaWVzIikgKyBzY2FsZV94X2Rpc2NyZXRlKG5hbWUgPSJOdW1iZXIgb2YgQ29tbWl0cyIsIGxpbWl0cz1zZXEoMSxtYXgoZGF0YV9wbG90JE5vQ29tbWl0cykpKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChjb2xvdXI9ImdyZXkyMCIsc2l6ZT01LGFuZ2xlPTkwLGhqdXN0PS41LHZqdXN0PS41LGZhY2U9InBsYWluIikpCmBgYAoKIyMjIyAoUTIuMykgSG93IG9mdGVuIGFyZSBidWdzIGludHJvZHVjZWQgYW1vbmcgdGhlIGNoYW5nZXM/CmBgYHtyfQoKI0ZyZXE6CmdncGxvdChkYXRhX3Bsb3QpICsKICBnZW9tX2JhcihhZXMoeD1Ob0NvbW1pdHMseT1CdWdzQnlDaGFuZ2VzKSwgcG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0ID0gImlkZW50aXR5IikrCiAgZmFjZXRfZ3JpZCguflByb2plY3Qsc2NhbGVzPSJmcmVlIikgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb249IGMoMC43LCAwLjk1KSwgbGVnZW5kLmRpcmVjdGlvbj0iaG9yaXpvbnRhbCIsIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9NSksIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSBOQSkpICsKICB5bGFiKCJQZXJjZW50dWFsIG9mIEJ1Z3MgYnkgQ2hhbmdlcyIpICsgc2NhbGVfeF9kaXNjcmV0ZShuYW1lID0iTnVtYmVyIG9mIENvbW1pdHMiLCBsaW1pdHM9c2VxKDEsbWF4KGRhdGFfcGxvdCROb0NvbW1pdHMpKSkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSBOQSksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoY29sb3VyPSJncmV5MjAiLHNpemU9NSxhbmdsZT05MCxoanVzdD0uNSx2anVzdD0uNSxmYWNlPSJwbGFpbiIpKQoKI1BlcmM6CmdncGxvdChkYXRhX3Bsb3QpICsKICBnZW9tX2JhcihhZXMoeD1Ob0NvbW1pdHMseT1QZXJjQnVnc0J5Q2hhbmdlcyksIHBvc2l0aW9uID0gImRvZGdlIiwgc3RhdCA9ICJpZGVudGl0eSIpKwogIGZhY2V0X2dyaWQoLn5Qcm9qZWN0LHNjYWxlcz0iZnJlZSIpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSBjKDAuNywgMC45NSksIGxlZ2VuZC5kaXJlY3Rpb249Imhvcml6b250YWwiLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTUpLCBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkEpKSArCiAgeWxhYigiUGVyY2VudHVhbCBvZiBCdWdzIGJ5IENoYW5nZXMiKSArIHNjYWxlX3hfZGlzY3JldGUobmFtZSA9Ik51bWJlciBvZiBDb21taXRzIiwgbGltaXRzPXNlcSgxLG1heChkYXRhX3Bsb3QkTm9Db21taXRzKSkpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkEpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGNvbG91cj0iZ3JleTIwIixzaXplPTUsYW5nbGU9OTAsaGp1c3Q9LjUsdmp1c3Q9LjUsZmFjZT0icGxhaW4iKSkKYGBgCgojIyMoRzMpIFRvIGFuYWx5c2UgdGhlIGtpbmQgb2YgY2hhbmdlcyBhcmUgbW9zdGx5IHJlbGF0ZWQgdG8gdGhlIGJ1Z3MgaW5zZXJ0aW9uOwoKIyMjIyhRMy4xKSBXaGljaCBhcmUgdGhlIHR5cGVzIChBZGQvRGVsKSBvZiBjaGFuZ2VzIG1vcmUgZnJlcXVlbnQgaW4gdGhlIGJ1Z3MgaW5zZXJ0aW9uPyAKCgpgYGB7cn0KCiNDaGFuZ2VzIENoYXJ0Cm1ldGhvZHNfY2hhbmdlcyA8LSBmaWx0ZXIobWV0aG9kc19pbnNlcnRpb25zLCBjaGFuZ2VUeXBlICE9ICdBbGwnLCBncm91cE1ldHJpYyA9PSAnQWxsJywgTWV0cmljID09ICdBbGwnKQoKbWV0aG9kc19jaGFuZ2VzW21ldGhvZHNfY2hhbmdlcyRjaGFuZ2VUeXBlID09ICJjaGFuZ2VNZXRyaWNzQWRkaXRpb24iLCBjKCJjaGFuZ2VUeXBlIildIDwtICJBZGRpdGlvbiIKbWV0aG9kc19jaGFuZ2VzW21ldGhvZHNfY2hhbmdlcyRjaGFuZ2VUeXBlID09ICJjaGFuZ2VNZXRyaWNzRGVsZXRpb24iLCBjKCJjaGFuZ2VUeXBlIildIDwtICJEZWxldGlvbiIKCmNiUGFsZXR0ZSA8LSBjKCIjMDA5RTczIiwgIiNGMTU4NTQiKQoKbWV0aG9kc19jaGFuZ2VzIDwtICBhcy5kYXRhLmZyYW1lKAogIG1ldGhvZHNfY2hhbmdlcyAlPiUKICAgIGRwbHlyOjpncm91cF9ieShQcm9qZWN0LCBjaGFuZ2VUeXBlKSAlPiUKICAgIGRwbHlyOjpzdW1tYXJpc2UodG90YWxDaGFuZ2VzID0gc3VtKENvdW50KSkgJT4lCiAgICBtdXRhdGUoUGVyY2VudHVhbCA9IHRvdGFsQ2hhbmdlcyAvIHN1bSh0b3RhbENoYW5nZXMpICogMTAwKSAlPiUKICAgIHVuZ3JvdXAoKQopCgpnZ3Bsb3QobWV0aG9kc19jaGFuZ2VzKSArCiAgZ2VvbV9iYXIoYWVzKHggPSBQcm9qZWN0LCB5ID0gUGVyY2VudHVhbCwgZmlsbCA9IGNoYW5nZVR5cGUsIGdyb3VwID0gY2hhbmdlVHlwZSksIHBvc2l0aW9uID0gImRvZGdlIiwgc3RhdCA9ICJpZGVudGl0eSIpICsKICBnZW9tX3RleHQoIGFlcyh4ID0gUHJvamVjdCwgeSA9IFBlcmNlbnR1YWwsIGxhYmVsID0gcm91bmQoUGVyY2VudHVhbCksIGdyb3VwID0gY2hhbmdlVHlwZSksICAKICAgICAgICAgICAgIGNoZWNrX292ZXJsYXAgPSBUUlVFLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksIHZqdXN0ID0gLTAuNSwgc2l6ZSA9IDMpICsgI3NjYWxlX2ZpbGxfZ3JleSgpICsgCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0gYygwLjgyLCAwLjk1KSwgbGVnZW5kLmRpcmVjdGlvbj0iaG9yaXpvbnRhbCIsIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgYXhpcy50aXRsZS54PWVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9NyksIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSBOQSkgKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jYlBhbGV0dGUpCgpgYGAKCiMjIyMoUTMuMikgV2hpY2ggYXJlIHRoZSBtZXRyaWNzIGdyb3VwcyBtb3JlIGZyZXF1ZW50IGluIHRoZSBidWdzIGluc2VydGlvbj8gCgpgYGB7cn0KI0ZpbHRlcjpECm1ldGhvZHNfZ3JvdXBzPC0gZmlsdGVyKG1ldGhvZHNfaW5zZXJ0aW9ucywgZ3JvdXBNZXRyaWMgIT0gIlJNIiwgY2hhbmdlVHlwZSA9PSAnQWxsJywgZ3JvdXBNZXRyaWMgIT0gJ0FsbCcsIE1ldHJpYyA9PSAnQWxsJykKCiNHcm91cCBtZWFzdXJlcwptZXRob2RzX2dyb3VwcyA8LSAgYXMuZGF0YS5mcmFtZSgKICBtZXRob2RzX2dyb3VwcyAlPiUKICAgIGRwbHlyOjpncm91cF9ieShQcm9qZWN0LCBncm91cE1ldHJpYykgJT4lCiAgICBkcGx5cjo6c3VtbWFyaXNlKENoYW5nZXMgPSBzdW0oQ291bnQpKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoUGVyY2VudHVhbCA9IENoYW5nZXMgLyBzdW0oQ2hhbmdlcykgKiAxMDApICU+JQogICAgZHBseXI6OnVuZ3JvdXAoKQopCgojUGxvdAogIGdncGxvdChtZXRob2RzX2dyb3VwcykgKwogICAgZ2VvbV9iYXIoYWVzKHggPSByZW9yZGVyKGdyb3VwTWV0cmljLCAtUGVyY2VudHVhbCksIHkgPSBQZXJjZW50dWFsKSwgcG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0ID0gImlkZW50aXR5IikgKwogICAgZ2VvbV90ZXh0KCBhZXMoeCA9IHJlb3JkZXIoZ3JvdXBNZXRyaWMsIC1QZXJjZW50dWFsKSwgeSA9IFBlcmNlbnR1YWwsIGxhYmVsID0gcm91bmQoUGVyY2VudHVhbCkpLCAgCiAgICAgICAgICAgICAgIGNoZWNrX292ZXJsYXAgPSBUUlVFLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksIHZqdXN0ID0gLTAuNSwgc2l6ZSA9IDMpICsgI3NjYWxlX2ZpbGxfZ3JleSgpICsgCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHNpemU9IDgpKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb249IGMoMC44MiwgMC45NSksIGxlZ2VuZC5kaXJlY3Rpb249Imhvcml6b250YWwiLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgICAgYXhpcy50aXRsZS54PWVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9NyksIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSBOQSkgKSArCiAgICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSkKCmBgYAoKCgojIyMjKFEzLjMpIFdoaWNoIGFyZSB0aGUgY2hhbmdlIG1ldHJpY3MgbW9yZSBmcmVxdWVudCBpbiB0aGUgYnVncyBpbnNlcnRpb24/IAoKYGBge3J9CiNGaWx0ZXI6RAptZXRob2RzX2luZCA8LSBmaWx0ZXIobWV0aG9kc19pbnNlcnRpb25zLCBncm91cE1ldHJpYyAhPSAiUk0iLCBjaGFuZ2VUeXBlID09ICdBbGwnLCBncm91cE1ldHJpYyAhPSAnQWxsJywgTWV0cmljICE9ICdBbGwnKQoKI09SZGVyIG1ldHJpY3MgYnkgZnJlcXVlbmN5CmZyZXFzX21ldHJpY3MgPC0gcGx5cjo6Y291bnQobWV0aG9kc19pbmQkTWV0cmljKQpmcmVxc19tZXRyaWNzIDwtIGZyZXFzX21ldHJpY3Nbb3JkZXIoLWZyZXFzX21ldHJpY3MkZnJlcSksIF0KCiNHcm91cGluZyBkYXRhCm1ldGhvZHNfaW5kIDwtICBhcy5kYXRhLmZyYW1lKAogIG1ldGhvZHNfaW5kICU+JQogICAgZHBseXI6Omdyb3VwX2J5KFByb2plY3QsIE1ldHJpYykgJT4lCiAgICBkcGx5cjo6c3VtbWFyaXNlKENoYW5nZXMgPSBzdW0oQ291bnQpKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoUGVyY2VudHVhbCA9IENoYW5nZXMgLyBzdW0oQ2hhbmdlcykgKiAxMDApICU+JQogICAgZHBseXI6OnVuZ3JvdXAoKQopCgojVG9wIG1ldHJpY3MKdG9wX21ldHJpY3MgPC0gaGVhZChmcmVxc19tZXRyaWNzLCAxNSkKbWV0aG9kc19pbmQgPC0gbWV0aG9kc19pbmRbbWV0aG9kc19pbmQkTWV0cmljICVpbiUgdG9wX21ldHJpY3MkeCwgXQoKI1Bsb3QKZ2dwbG90KG1ldGhvZHNfaW5kKSArCiAgZ2VvbV9iYXIoYWVzKHggPSByZW9yZGVyKE1ldHJpYywgLVBlcmNlbnR1YWwpLCB5ID0gUGVyY2VudHVhbCksIHBvc2l0aW9uID0gImRvZGdlIiwgc3RhdCA9ICJpZGVudGl0eSIpICsKICAjZ2VvbV90ZXh0KCBhZXMoeCA9IHJlb3JkZXIoTWV0cmljLCAtUGVyY2VudHVhbCksIHkgPSBQZXJjZW50dWFsLCBsYWJlbCA9IHJvdW5kKFBlcmNlbnR1YWwpKSwgIAogICMgICAgICAgICAgY2hlY2tfb3ZlcmxhcCA9IFRSVUUsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSwgdmp1c3QgPSAtMC41LCBzaXplID0gMykgKyAjc2NhbGVfZmlsbF9ncmV5KCkgKyAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHNpemUgPSA3KSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0gYygwLjgyLCAwLjk1KSwgbGVnZW5kLmRpcmVjdGlvbj0iaG9yaXpvbnRhbCIsIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgYXhpcy50aXRsZS54PWVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9NyksIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSBOQSkgKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSkKYGBgCgoKCiMjIyAoRzQpIFRvIGFuYWx5c2UgdGhlIHJlbGF0aW9uIGJldHdlZW4gdGhlIGhpc3Rvcnkgb2YgY2hhbmdlcyBhbmQgYnVnczsKCiMjIyMgKFE0LjEpIElzIGEgaGlnaCBudW1iZXIgb2YgY2hhbmdlcyBhbiBpbmRpY2F0aXZlIG9mIGJ1Z3MgaW50cm9kdWN0aW9uPwoKCmBgYHtyfQojQ2hhbmdlcyBDaGFydAptZXRob2RzX2NoYW5nZXMgPC0gZmlsdGVyKG1ldGhvZHNfdG90YWwsIGNoYW5nZVR5cGUgPT0gJ0FsbCcsIGdyb3VwTWV0cmljID09ICdBbGwnLCBNZXRyaWMgPT0gJ0FsbCcpCgojQ2FsY3VsaW5nIHBlYWtzCm1ldGhvZHNfY2hhbmdlc1ssInRvdGFsb2ZCdWdzSW5zIl0gPC0gICBtYXBseShtZXRob2RzX2NoYW5nZXMkYnVnc0luc2VydGlvbiwgZ2V0VG90YWxCdWdzSW5zKQoKI0ZpbHRlcmluZyBvbmx5IHRzIHdpdGggYnVncyBhbmQgbW9yZSB3aXRoIG9uZSBjb21taXQKbWV0aG9kc19jaGFuZ2VzIDwtIGZpbHRlcihtZXRob2RzX2NoYW5nZXMsIHRvdGFsb2ZCdWdzSW5zID4gMCwgTnRpbWVvZkNvbW1pdHMgPiAxKQoKI0dlbmVyYXRpbmcgaWQgb2YgZGF0YSBmcmFtZQptZXRob2RzX2NoYW5nZXMgPC0gZ2VuSWQobWV0aG9kc19jaGFuZ2VzKQoKI0xpc3Qgb2YgY2hhbmdlcyBhbmQgYnVncyBpbnNlcnRpb25zCmxpc3RvZlBlYWtzIDw8LSBtZXRob2RzX2NoYW5nZXMkZWxlbWVudHNWYWx1ZQpsaXN0b2ZCdWdzSW5zIDw8LSBtZXRob2RzX2NoYW5nZXMkYnVnc0luc2VydGlvbgoKI0NyZWF0aW5nIGNvbHVtbnMKbWV0aG9kc19jaGFuZ2VzWyxjKCJwZWFrcyIsICJ0cCIsICJmcCIsICJmbiIsICJ0biIsICJwcmVjaXNpb24iLCAicmVjYWxsIiwgImZtZWFzdXJlIildIDwtIDAgCiNjYWxjdWxhdGluZyBjb25mdXNpb24gbWF0cml4Cm1ldGhvZHNfY2hhbmdlc1ssYygicGVha3MiLCAidHAiLCAiZnAiLCAiZm4iLCAidG4iLCAicHJlY2lzaW9uIiwgInJlY2FsbCIsICJmbWVhc3VyZSIpXSAgPC0gIHBseXI6OmxkcGx5KG1ldGhvZHNfY2hhbmdlcyRpZCwgZ2V0U3RhdHNQcm9jZXNzKQoKI0dyb3VwaW5nIGRhdGEKY29uZnVzaW9uX21hdHJpeCA8LSBhcy5kYXRhLmZyYW1lKAogIG1ldGhvZHNfY2hhbmdlcyAlPiUKICAgIGRwbHlyOjpncm91cF9ieShQcm9qZWN0KSAlPiUKICAgIGRwbHlyOjpzdW1tYXJpc2UoCiAgICAgIHByZWNpc2lvbiA9IG1lZGlhbihwcmVjaXNpb24sIG5hLnJtID0gVFJVRSksCiAgICAgIHJlY2FsbCA9IG1lZGlhbihyZWNhbGwsIG5hLnJtID0gVFJVRSksCiAgICAgIGZtZWFzdXJlID0gbWVkaWFuKGZtZWFzdXJlLCBuYS5ybSA9IFRSVUUpCiAgICApCikKCiNQaXZvdCBkYXRhCmNvbmZ1c2lvbl9tYXRyaXggPC0gbWVsdChkZlBlYWtzLCBpZCA9IChjKCJQcm9qZWN0IikpKQpjb2xuYW1lcyhjb25mdXNpb25fbWF0cml4KSA8LSBjKCJQcm9qZWN0IiwgIk1lYXN1cmUiLCAiVmFsdWVzIikKCiNQbG90aW5nIHJlc3VsdHMKZ2dwbG90KGNvbmZ1c2lvbl9tYXRyaXgpICsKICBnZW9tX2JhcihhZXMoeCA9IE1lYXN1cmUsIHkgPSBWYWx1ZXMpLCBwb3NpdGlvbiA9ICJkb2RnZSIsIHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgZ2VvbV90ZXh0KGFlcyh4ID0gTWVhc3VyZSwgeSA9IFZhbHVlcywgbGFiZWwgPSByb3VuZChWYWx1ZXMsMikpLCAgCiAgICAgICAgICAgIGNoZWNrX292ZXJsYXAgPSBUUlVFLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksIHZqdXN0ID0gLTAuNSwgc2l6ZSA9IDMpICsgIAogIHRoZW1lKGxlZ2VuZC5kaXJlY3Rpb249InZlcnRpY2FsIiwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT04KSwgCiAgICAgICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSwgYXhpcy50aWNrcy54ID0gKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSkgKyAKICBnZ3RpdGxlKHByb2plY3QpICsgeWxhYigiUGVyY2VudHVhbCIpIAoKYGBgCgoK