Project Signal-Android

#Importing functions:
source("~/R/software-history/scripts/utils.R")
project <- "Signal-Android"
#Csv's:
results_frame <- 
  read.csv(
    paste0("/home/r4ph/R/analysis/results/",project,"_resultsRqsBugsIns.csv"), 
    stringsAsFactors = FALSE
  )
methods_insertions <-
  read.csv(
    paste0("~/R/analysis/results_insertions/",project,"_insertionTs.csv"),
    stringsAsFactors = FALSE
  )
methods_total<-
  read.csv(
    paste0("~/R/analysis/results/",project,"_changesTsWithBugsIns.csv"),
    stringsAsFactors = FALSE
  )
results_frame$Project <- project

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"))

(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") 

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyMjIFByb2plY3QgU2lnbmFsLUFuZHJvaWQKCmBgYHtyfQojSW1wb3J0aW5nIGZ1bmN0aW9uczoKc291cmNlKCJ+L1Ivc29mdHdhcmUtaGlzdG9yeS9zY3JpcHRzL3V0aWxzLlIiKQoKcHJvamVjdCA8LSAiU2lnbmFsLUFuZHJvaWQiCgojQ3N2J3M6CnJlc3VsdHNfZnJhbWUgPC0gCiAgcmVhZC5jc3YoCiAgICBwYXN0ZTAoIi9ob21lL3I0cGgvUi9hbmFseXNpcy9yZXN1bHRzLyIscHJvamVjdCwiX3Jlc3VsdHNScXNCdWdzSW5zLmNzdiIpLCAKICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRQogICkKCm1ldGhvZHNfaW5zZXJ0aW9ucyA8LQogIHJlYWQuY3N2KAogICAgcGFzdGUwKCJ+L1IvYW5hbHlzaXMvcmVzdWx0c19pbnNlcnRpb25zLyIscHJvamVjdCwiX2luc2VydGlvblRzLmNzdiIpLAogICAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFCiAgKQoKbWV0aG9kc190b3RhbDwtCiAgcmVhZC5jc3YoCiAgICBwYXN0ZTAoIn4vUi9hbmFseXNpcy9yZXN1bHRzLyIscHJvamVjdCwiX2NoYW5nZXNUc1dpdGhCdWdzSW5zLmNzdiIpLAogICAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFCiAgKQoKcmVzdWx0c19mcmFtZSRQcm9qZWN0IDwtIHByb2plY3QKCmBgYAoKCiMjI1JhdyBEYXRhc2V0OgpBcXVpIMOpIGFwcmVzZW50YWRvIG8gZGF0YXNldCBxdWUgZm9pIGRpc2N1dGlkbyBuYSB1bHRpbWEgcmV1bmnDo28gY29uZm9ybWUgcGxhbmlsaGEgcXVlIG8gQmllbCBnZXJvdSBubyBHb29nbGUgRHJpdmUuIFRhbCBkYXRhc2V0IGNvbnNpc3RlIG5hIHJlbGHDp8OjbyBlbnRyZSBvcyB2YWxvcmVzIGRlIG11ZGFuw6dhcyBlIGluc2Vyw6fDo28gZGUgYnVncyBjb21taXQuIFNlZ3VlIHVtYSBkZXNjcmnDp8OjbyBkYXMgcmVzcGVjdGl2YXMgY29sdW5hczoKCioqTm9Db21taXRzKiogOiBBIFF1YW50aWRhZGUgZGUgY29tbWl0cyAoaykgcXVlIGEgdGltZSBzZXJpZSBwb3NzdWk7CgoqKmNvbW1pdCoqIDogTyByZXNwZWN0aXZvIGNvbW1pdCBkZW50cm8gZGEgdGltZSBzZXJpZXMgY29tIGsgY29tbWl0czsKCioqTm9UaW1lU2VyaWVzKiogOiBRdWFudGlkYWRlIGRlIHRpbWUgc2VyaWVzIG5vIGNvbW1pdDsKCioqTm9CdWdzSW5zKiogOiBRdWFudGlkYWRlIGRlIGJ1Z3MgaW5zZXJpZG9zIG5vIHJlc3BlY3Rpdm8gY29tbWl0OwoKKipub0NoYW5nZXMqKiA6IFF1YW50aWRhZGUgZGUgbXVkYW7Dp2FzOwoKKipwZXJjQnVncyoqIDogUGVyY2VudHVhbCBkZSBidWdzIGluc2VyaWRvcyBbRm9ybXVsYSBub0J1Z3NJbnMvc3VtKG5vQnVnc0lucyldOwoKKipwZXJjQ2hhbmdlcyoqIDogUGVyY2VudHVhbCBkZSBtdWRhbsOnYXMgW0Zvcm11bGE6IG5vQ2hhbmdlcy9zdW0obm9DaGFuZ2VzKSBdOwoKCk9iczogUmVzc2FsdGFuZG8gcXVlIG9zIGRhZG9zIG5vIGRhdGFzZXQgZW5jb250cmFtLXNlIGRlc25vcm1hbGl6YWRvcywgcG9ydGFudG8gaMOhIHVtYSBwb3NzaWJpbGlkYWRlIGRlIHJlcGV0acOnw6NvICBkZSB2YWxvcmVzIGVtIGFsZ3VtYXMgY29sdW5hcywgZXg6IG5hIGNvbHVuYSBOb1RpbWVTZXJpZXMsIG5hIGxpbmhhIDIgZSAzIGV4aXN0ZSBvIHZhbG9yIDE2ODEgZGUgbWFuZWlyYSByZXBldGlkYSwgbWFzIG5vIGPDoWxjdWxvIGRhcyByZXNwZWN0aXZhcyBtZXRyaWNhcyDDqSB1dGlsaXphZG8gc29tZW50ZSB1bSB2YWxvciwgdmlzdG8gcXVlIGV4aXN0ZW0gc29tZW50ZSAxNjgxIHRpbWUgc2VyaWVzIGNvbSAyIGNvbW1pdHMgZSBuw6NvIG8gZG9icm8gKHNvbWEgZGFzIGxpbmhhcyAyIGUgMykuCgpgYGB7cn0KcmVzdWx0c19mcmFtZQoKYGBgCgojIyNGaW5hbCBEYXRhc2V0OgpBcXVpIMOpIGFwcmVzZW50YWRvIG8gZGF0YXNldCBjb20gYXMgbWV0cmljYXMgY2FsY3VsYWRhcyBjb20gbyBvYmpldGl2byBkZSBnZXJhciBvcyByZXNwZWN0aXZvcyBncsOhZmljb3MgcHJlc2VudGVzIG5hIEdvYWwgMSBlIDIuIFNlZ3VlIHVtYSBkZXNjcmnDp8OjbyBkYXMgY29sdW5hcyBlIHN1YXMgcmVzcGVjdGl2YXMgZm9ybXVsYXM6CgoqKk5vQ29tbWl0cyoqIDogQSBRdWFudGlkYWRlIGRlIGNvbW1pdHMgKGspIHF1ZSBhIHRpbWUgc2VyaWUgcG9zc3VpOwoKKipOb1RpbWVTZXJpZXMqKiA6IFF1YW50aWRhZGUgZGUgdGltZSBzZXJpZXMgbm8gY29tbWl0OwoKKipub0NoYW5nZXMqKiA6IFF1YW50aWRhZGUgZGUgbXVkYW7Dp2FzOwoKKipOb0J1Z3NJbnMqKiA6IFF1YW50aWRhZGUgZGUgYnVncyBpbnNlcmlkb3Mgbm8gcmVzcGVjdGl2byBjb21taXQ7CgoqKkJ1Z3NCeVRzKiogOiBRdWFudGlkYWRlIGRlIGJ1Z3MgcG9yIHRpbWUgc2VyaWVzIFtGb3JtdWxhIDogc3VtKG5vQnVnc0lucykvbWF4KG5vVGltZVNlcmllcykgXTsKCioqQnVnc0J5Q2hhbmdlcyoqIDpRdWFudGlkYWRlIGRlIG11ZGFuw6dhcyBwb3IgYnVncyBbRm9ybXVsYTogc3VtKG5vQnVnc0lucykvIHN1bShub0NoYW5nZXMpXTsKCioqQ2hhbmdlc0J5VHMqKjogUXVhbnRpZGFkZSBkZSBtdWRhbsOnYXMgcHJvIHRpbWUgc2VyaWVzIFtGb3JtdWxhOiBzdW0obm9DaGFuZ2VzKS8gbWF4KG5vVGltZVNlcmllcyldOwoKKipQZXJjQnVnc0J5VHMqKjogUGVyY2VudHVhbCBkZSBidWdzIHBvciB0aW1lIHNlcmllcyBbRm9ybXVsYTogKEJ1Z3NCeVRzL3N1bShCdWdzQnlUcykpICogMTAwXTsKCioqUGVyY0J1Z3NCeUNvbW1pdCoqOiBQZXJjZW50dWFsIGRlIEJ1Z3MgcG9yIGNvbW1pdHMgW0Zvcm11bGE6IChub0J1Z3NJbnMvc3VtKG5vQnVnc0lucykpICogMTAwXTsKCioqUGVyY0J1Z3NCeUNoYW5nZXMqKjogUGVyY2VudHVhbCBkZSBCdWdzIHBvciBtdWRhbsOnYXMgW0Zvcm11bGE6IChCdWdzQnlDaGFuZ2VzL3N1bShCdWdzQnlDaGFuZ2VzKSkgKiAxMDBdOwoKKipQZXJjVHMqKjogUGVyY2VudHVhbCBkZSB0aW1lIHNlcmllcyBbRm9ybXVsYTogbm9UaW1lU2VyaWVzIC8gc3VtKG5vVGltZVNlcmllcykpICogMTAwXTsKCioqUGVyY0NoYW5nZXNCeVRzKio6IFBlcmNlbnR1YWwgZGUgbXVkYW7Dp2FzIHBvciB0aW1lIHNlcmllcyBbRm9ybXVsYTogKENoYW5nZXNCeVRzIC8gc3VtKENoYW5nZXNCeVRzKSkgKiAxMDBdOwoKKipQZXJjQ2hhbmdlcyoqOiBQZXJjZW50dWFsIGRlIG11ZGFuw6dhcyBbRm9ybXVsYTogIChub0NoYW5nZXMgLyBzdW0obm9DaGFuZ2VzKSkgKiAxMDBdOwoKT2JzOiBDb25mb3JtZSBleHBsaWNhZG8sIG9zIGRhZG9zIGFudGVyaW9yZXMgKHJhdyBkYXRhc2V0KSB0ZW0gYWxndW1hcyBjb2x1bmFzIGRlc25vcm1hbGl6YWRhcyAoTm9UaW1lU2VyaWVzKSwgcG9ydGFudG8gYWxndW1hcyBmb3JtdWxhcyBjb250w6ltIG8gdmFsb3IgbWF4aW1vIGRhIHJlc3BlY3RpdmEgY29sdW5hIGRlbnRybyBkbyBhZ3J1cGFtZW50byBkZWZpbmlkby4KCmBgYHtyfQojRmluYWwgRGF0YSBGcmFtZQpkYXRhX3Bsb3QgPC0gYXMuZGF0YS5mcmFtZSgKICByZXN1bHRzX2ZyYW1lICU+JQogICAgZHBseXI6Omdyb3VwX2J5KFByb2plY3QsIE5vQ29tbWl0cykgJT4lCiAgICBkcGx5cjo6c3VtbWFyaXNlKAogICAgICBub1RpbWVTZXJpZXMgPSBtYXgobm9UaW1lU2VyaWVzKSwKICAgICAgbm9DaGFuZ2VzID0gc3VtKG5vQ2hhbmdlcyksCiAgICAgIG5vQnVnc0lucyA9IHN1bShub0J1Z3NJbnMpLAogICAgICBCdWdzQnlUcyA9IHN1bShub0J1Z3NJbnMpIC8gbWF4KG5vVGltZVNlcmllcyksCiAgICAgIEJ1Z3NCeUNoYW5nZXMgPSBzdW0obm9CdWdzSW5zKSAvIHN1bShub0NoYW5nZXMpLAogICAgICBDaGFuZ2VzQnlUcyA9IHN1bShub0NoYW5nZXMpIC8gbWF4KG5vVGltZVNlcmllcykKICAgICkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKAogICAgICBQZXJjQnVnc0J5VHMgPSAoQnVnc0J5VHMgLyBzdW0oQnVnc0J5VHMpKSAqIDEwMCwKICAgICAgUGVyY0J1Z3NCeUNvbW1pdCA9IChub0J1Z3NJbnMgLyBzdW0obm9CdWdzSW5zKSkgKiAxMDAsCiAgICAgIFBlcmNCdWdzQnlDaGFuZ2VzID0gKEJ1Z3NCeUNoYW5nZXMgLyBzdW0oQnVnc0J5Q2hhbmdlcykpICogMTAwLAogICAgICBQZXJjVHMgPSAobm9UaW1lU2VyaWVzIC8gc3VtKG5vVGltZVNlcmllcykpICogMTAwLAogICAgICBQZXJjQ2hhbmdlc0J5VHMgPSAoQ2hhbmdlc0J5VHMgLyBzdW0oQ2hhbmdlc0J5VHMpKSAqIDEwMCwKICAgICAgUGVyY0NoYW5nZXMgPSAobm9DaGFuZ2VzIC8gc3VtKG5vQ2hhbmdlcykpICogMTAwCiAgICApICU+JQogICAgZHBseXI6OnVuZ3JvdXAoKQopCgpkYXRhX3Bsb3QKYGBgCgoKIyMjIChHMSlUbyBpbnZlc3RpZ2F0ZSB0aGUgb2NjdXJyZW5jZSBvZiBjb21taXRzIGFsb25nIHRoZSB0aW1lIHNlcmllczsgCiMjIyMoUTEuMSkgSG93IG9mdGVuIGFyZSBjb21taXRzIHBlcmZvcm1lZCBhbG9uZyB0aGUgdGltZSBzZXJpZXM/CmBgYHtyfQoKI0ZyZXF1ZW5jeToKZ2dwbG90KGRhdGFfcGxvdCkgKwogIGdlb21fYmFyKGFlcyh4PU5vQ29tbWl0cyx5PW5vVGltZVNlcmllcyxncm91cD1Qcm9qZWN0KSwgcG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0ID0gImlkZW50aXR5IikgKwogIGZhY2V0X2dyaWQoLn5Qcm9qZWN0LHNjYWxlcz0iZnJlZSIpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSBjKDAuNywgMC45NSksIGxlZ2VuZC5kaXJlY3Rpb249Imhvcml6b250YWwiLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTUpLCBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkEpICkgKwogIHlsYWIoIkZyZXF1ZW5jeSBvZiBUaW1lIFNlcmllcyBieSBDb21taXRzIikgKyBzY2FsZV94X2Rpc2NyZXRlKG5hbWUgPSJOdW1iZXIgb2YgQ29tbWl0cyIsIGxpbWl0cz1zZXEoMSxtYXgoZGF0YV9wbG90JE5vQ29tbWl0cykpKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChjb2xvdXI9ImdyZXkyMCIsc2l6ZT01LGFuZ2xlPTkwLGhqdXN0PS41LHZqdXN0PS41LGZhY2U9InBsYWluIikpCgojUGVyY2VudHVhbApnZ3Bsb3QoZGF0YV9wbG90KSArCiAgZ2VvbV9iYXIoYWVzKHg9Tm9Db21taXRzLHk9UGVyY1RzLGdyb3VwPVByb2plY3QpLCBwb3NpdGlvbiA9ICJkb2RnZSIsIHN0YXQgPSAiaWRlbnRpdHkiKSsKICBmYWNldF9ncmlkKC5+UHJvamVjdCxzY2FsZXM9ImZyZWUiKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0gYygwLjcsIDAuOTUpLCBsZWdlbmQuZGlyZWN0aW9uPSJob3Jpem9udGFsIiwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT01KSwgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSApICsKICB5bGFiKCJQZXJjZW50dWFsIG9mIFRpbWUgU2VyaWVzIGJ5IENvbW1pdHMiKSArIHNjYWxlX3hfZGlzY3JldGUobmFtZSA9Ik51bWJlciBvZiBDb21taXRzIiwgbGltaXRzPXNlcSgxLG1heChkYXRhX3Bsb3QkTm9Db21taXRzKSkpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkEpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGNvbG91cj0iZ3JleTIwIixzaXplPTUsYW5nbGU9OTAsaGp1c3Q9LjUsdmp1c3Q9LjUsZmFjZT0icGxhaW4iKSkKCgpgYGAKCgoKIyMjIyhRMS4yKSBIb3cgb2Z0ZW4gYXJlIGNoYW5nZXMgcGVyZm9ybWVkIGFtb25nIGNvbW1pdHM/CmBgYHtyfQoKI0ZyZXF1ZW5jeToKZ2dwbG90KGRhdGFfcGxvdCkgKwogIGdlb21fYmFyKGFlcyh4PU5vQ29tbWl0cyx5PW5vQ2hhbmdlcyksIHBvc2l0aW9uID0gImRvZGdlIiwgc3RhdCA9ICJpZGVudGl0eSIpKwogIGZhY2V0X2dyaWQoLn5Qcm9qZWN0LHNjYWxlcz0iZnJlZSIpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSBjKDAuNywgMC45NSksIGxlZ2VuZC5kaXJlY3Rpb249Imhvcml6b250YWwiLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTUpLCBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkEpKSArCiAgeWxhYigiRnJlcXVlbmN5IG9mIENoYW5nZXMgYnkgQ29tbWl0cyIpICsgc2NhbGVfeF9kaXNjcmV0ZShuYW1lID0iTnVtYmVyIG9mIENvbW1pdHMiLCBsaW1pdHM9c2VxKDEsbWF4KGRhdGFfcGxvdCROb0NvbW1pdHMpKSkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSBOQSksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoY29sb3VyPSJncmV5MjAiLHNpemU9NSxhbmdsZT05MCxoanVzdD0uNSx2anVzdD0uNSxmYWNlPSJwbGFpbiIpKQoKCiNQZXJjZW50dWFsCmdncGxvdChkYXRhX3Bsb3QpICsKICBnZW9tX2JhcihhZXMoeD1Ob0NvbW1pdHMseT1QZXJjQ2hhbmdlcyksIHBvc2l0aW9uID0gImRvZGdlIiwgc3RhdCA9ICJpZGVudGl0eSIpKwogIGZhY2V0X2dyaWQoLn5Qcm9qZWN0LHNjYWxlcz0iZnJlZSIpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSBjKDAuNywgMC45NSksIGxlZ2VuZC5kaXJlY3Rpb249Imhvcml6b250YWwiLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTUpLCBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkEpKSArCiAgeWxhYigiUGVyY2VudHVhbCBvZiBDaGFuZ2VzIGJ5IENvbW1pdHMiKSArIHNjYWxlX3hfZGlzY3JldGUobmFtZSA9Ik51bWJlciBvZiBDb21taXRzIiwgbGltaXRzPXNlcSgxLG1heChkYXRhX3Bsb3QkTm9Db21taXRzKSkpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkEpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGNvbG91cj0iZ3JleTIwIixzaXplPTUsYW5nbGU9OTAsaGp1c3Q9LjUsdmp1c3Q9LjUsZmFjZT0icGxhaW4iKSkKCmBgYAoKIyMjIyhRMS4zKSBIb3cgb2Z0ZW4gYXJlIGNoYW5nZXMgcGVyZm9ybWVkIGFtb25nIHRpbWUgc2VyaWVzPwpgYGB7cn0KCiNGcmVxdWVuY3k6CmdncGxvdChkYXRhX3Bsb3QpICsKICBnZW9tX2JhcihhZXMoeD1Ob0NvbW1pdHMseT1DaGFuZ2VzQnlUcyksIHBvc2l0aW9uID0gImRvZGdlIiwgc3RhdCA9ICJpZGVudGl0eSIpKwogIGZhY2V0X2dyaWQoLn5Qcm9qZWN0LHNjYWxlcz0iZnJlZSIpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSBjKDAuNywgMC45NSksIGxlZ2VuZC5kaXJlY3Rpb249Imhvcml6b250YWwiLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTUpLCBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkEpKSArCiAgeWxhYigiRnJlcXVlbmN5IG9mIENoYW5nZXMgYnkgVGltZSBTZXJpcyIpICsgc2NhbGVfeF9kaXNjcmV0ZShuYW1lID0iTnVtYmVyIG9mIENvbW1pdHMiLCBsaW1pdHM9c2VxKDEsbWF4KGRhdGFfcGxvdCROb0NvbW1pdHMpKSkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSBOQSksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoY29sb3VyPSJncmV5MjAiLHNpemU9NSxhbmdsZT05MCxoanVzdD0uNSx2anVzdD0uNSxmYWNlPSJwbGFpbiIpKQoKI1BlcmNlbnR1YWw6CmdncGxvdChkYXRhX3Bsb3QpICsKICBnZW9tX2JhcihhZXMoeD1Ob0NvbW1pdHMseT1QZXJjQ2hhbmdlc0J5VHMpLCBwb3NpdGlvbiA9ICJkb2RnZSIsIHN0YXQgPSAiaWRlbnRpdHkiKSsKICBmYWNldF9ncmlkKC5+UHJvamVjdCxzY2FsZXM9ImZyZWUiKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0gYygwLjcsIDAuOTUpLCBsZWdlbmQuZGlyZWN0aW9uPSJob3Jpem9udGFsIiwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT01KSwgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSkgKwogIHlsYWIoIlBlcmNlbnR1YWwgb2YgQ2hhbmdlcyBieSBUaW1lIFNlcmlzIikgKyBzY2FsZV94X2Rpc2NyZXRlKG5hbWUgPSJOdW1iZXIgb2YgQ29tbWl0cyIsIGxpbWl0cz1zZXEoMSxtYXgoZGF0YV9wbG90JE5vQ29tbWl0cykpKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChjb2xvdXI9ImdyZXkyMCIsc2l6ZT01LGFuZ2xlPTkwLGhqdXN0PS41LHZqdXN0PS41LGZhY2U9InBsYWluIikpCgpgYGAKCiMjIyAoRzIpVG8gYXNzZXNzIHRoZSBpbnRyb2R1Y3Rpb24gb2YgYnVncyBhbG9uZyB0aGUgaGlzdG9yeTsgCgojIyMjIChRMi4xKSBIb3cgb2Z0ZW4gYXJlIGJ1Z3MgaW50cm9kdWNlZCBhbW9uZyB0aGUgY29tbWl0cz8KYGBge3J9CgojRnJlcToKZ2dwbG90KGRhdGFfcGxvdCkgKwogIGdlb21fYmFyKGFlcyh4PU5vQ29tbWl0cyx5PW5vQnVnc0lucyksIHBvc2l0aW9uID0gImRvZGdlIiwgc3RhdCA9ICJpZGVudGl0eSIpKwogIGZhY2V0X2dyaWQoLn5Qcm9qZWN0LHNjYWxlcz0iZnJlZSIpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSBjKDAuNywgMC45NSksIGxlZ2VuZC5kaXJlY3Rpb249Imhvcml6b250YWwiLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTUpLCBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkEpKSArCiAgeWxhYigiUGVyY2VudHVhbCBvZiBCdWdzIGJ5IENvbW1pdHMiKSArIHNjYWxlX3hfZGlzY3JldGUobmFtZSA9Ik51bWJlciBvZiBDb21taXRzIiwgbGltaXRzPXNlcSgxLG1heChkYXRhX3Bsb3QkTm9Db21taXRzKSkpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkEpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGNvbG91cj0iZ3JleTIwIixzaXplPTUsYW5nbGU9OTAsaGp1c3Q9LjUsdmp1c3Q9LjUsZmFjZT0icGxhaW4iKSkKCiNQZXJjCmdncGxvdChkYXRhX3Bsb3QpICsKICBnZW9tX2JhcihhZXMoeD1Ob0NvbW1pdHMseT1QZXJjQnVnc0J5Q29tbWl0KSwgcG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0ID0gImlkZW50aXR5IikrCiAgZmFjZXRfZ3JpZCguflByb2plY3Qsc2NhbGVzPSJmcmVlIikgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb249IGMoMC43LCAwLjk1KSwgbGVnZW5kLmRpcmVjdGlvbj0iaG9yaXpvbnRhbCIsIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9NSksIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSBOQSkpICsKICB5bGFiKCJQZXJjZW50dWFsIG9mIEJ1Z3MgYnkgQ29tbWl0cyIpICsgc2NhbGVfeF9kaXNjcmV0ZShuYW1lID0iTnVtYmVyIG9mIENvbW1pdHMiLCBsaW1pdHM9c2VxKDEsbWF4KGRhdGFfcGxvdCROb0NvbW1pdHMpKSkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSBOQSksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoY29sb3VyPSJncmV5MjAiLHNpemU9NSxhbmdsZT05MCxoanVzdD0uNSx2anVzdD0uNSxmYWNlPSJwbGFpbiIpKQpgYGAKCiMjIyMgKFEyLjIpIEhvdyBvZnRlbiBhcmUgYnVncyBpbnRyb2R1Y2VkIGFtb25nIHRoZSB0aW1lIHNlcmllcz8KYGBge3J9CgojRnJlcXVlbmN5OgpnZ3Bsb3QoZGF0YV9wbG90KSArCiAgZ2VvbV9iYXIoYWVzKHg9Tm9Db21taXRzLHk9QnVnc0J5VHMpLCBwb3NpdGlvbiA9ICJkb2RnZSIsIHN0YXQgPSAiaWRlbnRpdHkiKSsKICBmYWNldF9ncmlkKC5+UHJvamVjdCxzY2FsZXM9ImZyZWUiKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0gYygwLjcsIDAuOTUpLCBsZWdlbmQuZGlyZWN0aW9uPSJob3Jpem9udGFsIiwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT01KSwgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSkgKwogIHlsYWIoIlBlcmNlbnR1YWwgb2YgQnVncyBieSBUaW1lIFNlcmllcyIpICsgc2NhbGVfeF9kaXNjcmV0ZShuYW1lID0iTnVtYmVyIG9mIENvbW1pdHMiLCBsaW1pdHM9c2VxKDEsbWF4KGRhdGFfcGxvdCROb0NvbW1pdHMpKSkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSBOQSksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoY29sb3VyPSJncmV5MjAiLHNpemU9NSxhbmdsZT05MCxoanVzdD0uNSx2anVzdD0uNSxmYWNlPSJwbGFpbiIpKQoKI1BlcmNlbnR1YWw6CmdncGxvdChkYXRhX3Bsb3QpICsKICBnZW9tX2JhcihhZXMoeD1Ob0NvbW1pdHMseT1QZXJjQnVnc0J5VHMpLCBwb3NpdGlvbiA9ICJkb2RnZSIsIHN0YXQgPSAiaWRlbnRpdHkiKSsKICBmYWNldF9ncmlkKC5+UHJvamVjdCxzY2FsZXM9ImZyZWUiKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0gYygwLjcsIDAuOTUpLCBsZWdlbmQuZGlyZWN0aW9uPSJob3Jpem9udGFsIiwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT01KSwgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSkgKwogIHlsYWIoIlBlcmNlbnR1YWwgb2YgQnVncyBieSBUaW1lIFNlcmllcyIpICsgc2NhbGVfeF9kaXNjcmV0ZShuYW1lID0iTnVtYmVyIG9mIENvbW1pdHMiLCBsaW1pdHM9c2VxKDEsbWF4KGRhdGFfcGxvdCROb0NvbW1pdHMpKSkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSBOQSksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoY29sb3VyPSJncmV5MjAiLHNpemU9NSxhbmdsZT05MCxoanVzdD0uNSx2anVzdD0uNSxmYWNlPSJwbGFpbiIpKQpgYGAKCiMjIyMgKFEyLjMpIEhvdyBvZnRlbiBhcmUgYnVncyBpbnRyb2R1Y2VkIGFtb25nIHRoZSBjaGFuZ2VzPwpgYGB7cn0KCiNGcmVxOgpnZ3Bsb3QoZGF0YV9wbG90KSArCiAgZ2VvbV9iYXIoYWVzKHg9Tm9Db21taXRzLHk9QnVnc0J5Q2hhbmdlcyksIHBvc2l0aW9uID0gImRvZGdlIiwgc3RhdCA9ICJpZGVudGl0eSIpKwogIGZhY2V0X2dyaWQoLn5Qcm9qZWN0LHNjYWxlcz0iZnJlZSIpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSBjKDAuNywgMC45NSksIGxlZ2VuZC5kaXJlY3Rpb249Imhvcml6b250YWwiLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTUpLCBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkEpKSArCiAgeWxhYigiUGVyY2VudHVhbCBvZiBCdWdzIGJ5IENoYW5nZXMiKSArIHNjYWxlX3hfZGlzY3JldGUobmFtZSA9Ik51bWJlciBvZiBDb21taXRzIiwgbGltaXRzPXNlcSgxLG1heChkYXRhX3Bsb3QkTm9Db21taXRzKSkpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkEpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGNvbG91cj0iZ3JleTIwIixzaXplPTUsYW5nbGU9OTAsaGp1c3Q9LjUsdmp1c3Q9LjUsZmFjZT0icGxhaW4iKSkKCiNQZXJjOgpnZ3Bsb3QoZGF0YV9wbG90KSArCiAgZ2VvbV9iYXIoYWVzKHg9Tm9Db21taXRzLHk9UGVyY0J1Z3NCeUNoYW5nZXMpLCBwb3NpdGlvbiA9ICJkb2RnZSIsIHN0YXQgPSAiaWRlbnRpdHkiKSsKICBmYWNldF9ncmlkKC5+UHJvamVjdCxzY2FsZXM9ImZyZWUiKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0gYygwLjcsIDAuOTUpLCBsZWdlbmQuZGlyZWN0aW9uPSJob3Jpem9udGFsIiwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT01KSwgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSkgKwogIHlsYWIoIlBlcmNlbnR1YWwgb2YgQnVncyBieSBDaGFuZ2VzIikgKyBzY2FsZV94X2Rpc2NyZXRlKG5hbWUgPSJOdW1iZXIgb2YgQ29tbWl0cyIsIGxpbWl0cz1zZXEoMSxtYXgoZGF0YV9wbG90JE5vQ29tbWl0cykpKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChjb2xvdXI9ImdyZXkyMCIsc2l6ZT01LGFuZ2xlPTkwLGhqdXN0PS41LHZqdXN0PS41LGZhY2U9InBsYWluIikpCmBgYAoKIyMjKEczKSBUbyBhbmFseXNlIHRoZSBraW5kIG9mIGNoYW5nZXMgYXJlIG1vc3RseSByZWxhdGVkIHRvIHRoZSBidWdzIGluc2VydGlvbjsKCiMjIyMoUTMuMSkgV2hpY2ggYXJlIHRoZSB0eXBlcyAoQWRkL0RlbCkgb2YgY2hhbmdlcyBtb3JlIGZyZXF1ZW50IGluIHRoZSBidWdzIGluc2VydGlvbj8gCgoKYGBge3J9CgojQ2hhbmdlcyBDaGFydAptZXRob2RzX2NoYW5nZXMgPC0gZmlsdGVyKG1ldGhvZHNfaW5zZXJ0aW9ucywgY2hhbmdlVHlwZSAhPSAnQWxsJywgZ3JvdXBNZXRyaWMgPT0gJ0FsbCcsIE1ldHJpYyA9PSAnQWxsJykKCm1ldGhvZHNfY2hhbmdlc1ttZXRob2RzX2NoYW5nZXMkY2hhbmdlVHlwZSA9PSAiY2hhbmdlTWV0cmljc0FkZGl0aW9uIiwgYygiY2hhbmdlVHlwZSIpXSA8LSAiQWRkaXRpb24iCm1ldGhvZHNfY2hhbmdlc1ttZXRob2RzX2NoYW5nZXMkY2hhbmdlVHlwZSA9PSAiY2hhbmdlTWV0cmljc0RlbGV0aW9uIiwgYygiY2hhbmdlVHlwZSIpXSA8LSAiRGVsZXRpb24iCgpjYlBhbGV0dGUgPC0gYygiIzAwOUU3MyIsICIjRjE1ODU0IikKCm1ldGhvZHNfY2hhbmdlcyA8LSAgYXMuZGF0YS5mcmFtZSgKICBtZXRob2RzX2NoYW5nZXMgJT4lCiAgICBkcGx5cjo6Z3JvdXBfYnkoUHJvamVjdCwgY2hhbmdlVHlwZSkgJT4lCiAgICBkcGx5cjo6c3VtbWFyaXNlKHRvdGFsQ2hhbmdlcyA9IHN1bShDb3VudCkpICU+JQogICAgbXV0YXRlKFBlcmNlbnR1YWwgPSB0b3RhbENoYW5nZXMgLyBzdW0odG90YWxDaGFuZ2VzKSAqIDEwMCkgJT4lCiAgICB1bmdyb3VwKCkKKQoKZ2dwbG90KG1ldGhvZHNfY2hhbmdlcykgKwogIGdlb21fYmFyKGFlcyh4ID0gUHJvamVjdCwgeSA9IFBlcmNlbnR1YWwsIGZpbGwgPSBjaGFuZ2VUeXBlLCBncm91cCA9IGNoYW5nZVR5cGUpLCBwb3NpdGlvbiA9ICJkb2RnZSIsIHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgZ2VvbV90ZXh0KCBhZXMoeCA9IFByb2plY3QsIHkgPSBQZXJjZW50dWFsLCBsYWJlbCA9IHJvdW5kKFBlcmNlbnR1YWwpLCBncm91cCA9IGNoYW5nZVR5cGUpLCAgCiAgICAgICAgICAgICBjaGVja19vdmVybGFwID0gVFJVRSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLCB2anVzdCA9IC0wLjUsIHNpemUgPSAzKSArICNzY2FsZV9maWxsX2dyZXkoKSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249IGMoMC44MiwgMC45NSksIGxlZ2VuZC5kaXJlY3Rpb249Imhvcml6b250YWwiLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIGF4aXMudGl0bGUueD1lbGVtZW50X2JsYW5rKCksIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTcpLCBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkEpICkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSBOQSkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9Y2JQYWxldHRlKQoKYGBgCgojIyMjKFEzLjIpIFdoaWNoIGFyZSB0aGUgbWV0cmljcyBncm91cHMgbW9yZSBmcmVxdWVudCBpbiB0aGUgYnVncyBpbnNlcnRpb24/IAoKYGBge3J9CiNGaWx0ZXI6RAptZXRob2RzX2dyb3VwczwtIGZpbHRlcihtZXRob2RzX2luc2VydGlvbnMsIGdyb3VwTWV0cmljICE9ICJSTSIsIGNoYW5nZVR5cGUgPT0gJ0FsbCcsIGdyb3VwTWV0cmljICE9ICdBbGwnLCBNZXRyaWMgPT0gJ0FsbCcpCgojR3JvdXAgbWVhc3VyZXMKbWV0aG9kc19ncm91cHMgPC0gIGFzLmRhdGEuZnJhbWUoCiAgbWV0aG9kc19ncm91cHMgJT4lCiAgICBkcGx5cjo6Z3JvdXBfYnkoUHJvamVjdCwgZ3JvdXBNZXRyaWMpICU+JQogICAgZHBseXI6OnN1bW1hcmlzZShDaGFuZ2VzID0gc3VtKENvdW50KSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKFBlcmNlbnR1YWwgPSBDaGFuZ2VzIC8gc3VtKENoYW5nZXMpICogMTAwKSAlPiUKICAgIGRwbHlyOjp1bmdyb3VwKCkKKQoKI1Bsb3QKICBnZ3Bsb3QobWV0aG9kc19ncm91cHMpICsKICAgIGdlb21fYmFyKGFlcyh4ID0gcmVvcmRlcihncm91cE1ldHJpYywgLVBlcmNlbnR1YWwpLCB5ID0gUGVyY2VudHVhbCksIHBvc2l0aW9uID0gImRvZGdlIiwgc3RhdCA9ICJpZGVudGl0eSIpICsKICAgIGdlb21fdGV4dCggYWVzKHggPSByZW9yZGVyKGdyb3VwTWV0cmljLCAtUGVyY2VudHVhbCksIHkgPSBQZXJjZW50dWFsLCBsYWJlbCA9IHJvdW5kKFBlcmNlbnR1YWwpKSwgIAogICAgICAgICAgICAgICBjaGVja19vdmVybGFwID0gVFJVRSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLCB2anVzdCA9IC0wLjUsIHNpemUgPSAzKSArICNzY2FsZV9maWxsX2dyZXkoKSArIAogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCBzaXplPSA4KSkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSBjKDAuODIsIDAuOTUpLCBsZWdlbmQuZGlyZWN0aW9uPSJob3Jpem9udGFsIiwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgIGF4aXMudGl0bGUueD1lbGVtZW50X2JsYW5rKCksIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTcpLCBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkEpICkgKwogICAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSBOQSkpCgpgYGAKCgoKIyMjIyhRMy4zKSBXaGljaCBhcmUgdGhlIGNoYW5nZSBtZXRyaWNzIG1vcmUgZnJlcXVlbnQgaW4gdGhlIGJ1Z3MgaW5zZXJ0aW9uPyAKCmBgYHtyfQojRmlsdGVyOkQKbWV0aG9kc19pbmQgPC0gZmlsdGVyKG1ldGhvZHNfaW5zZXJ0aW9ucywgZ3JvdXBNZXRyaWMgIT0gIlJNIiwgY2hhbmdlVHlwZSA9PSAnQWxsJywgZ3JvdXBNZXRyaWMgIT0gJ0FsbCcsIE1ldHJpYyAhPSAnQWxsJykKCiNPUmRlciBtZXRyaWNzIGJ5IGZyZXF1ZW5jeQpmcmVxc19tZXRyaWNzIDwtIHBseXI6OmNvdW50KG1ldGhvZHNfaW5kJE1ldHJpYykKZnJlcXNfbWV0cmljcyA8LSBmcmVxc19tZXRyaWNzW29yZGVyKC1mcmVxc19tZXRyaWNzJGZyZXEpLCBdCgojR3JvdXBpbmcgZGF0YQptZXRob2RzX2luZCA8LSAgYXMuZGF0YS5mcmFtZSgKICBtZXRob2RzX2luZCAlPiUKICAgIGRwbHlyOjpncm91cF9ieShQcm9qZWN0LCBNZXRyaWMpICU+JQogICAgZHBseXI6OnN1bW1hcmlzZShDaGFuZ2VzID0gc3VtKENvdW50KSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKFBlcmNlbnR1YWwgPSBDaGFuZ2VzIC8gc3VtKENoYW5nZXMpICogMTAwKSAlPiUKICAgIGRwbHlyOjp1bmdyb3VwKCkKKQoKI1RvcCBtZXRyaWNzCnRvcF9tZXRyaWNzIDwtIGhlYWQoZnJlcXNfbWV0cmljcywgMTUpCm1ldGhvZHNfaW5kIDwtIG1ldGhvZHNfaW5kW21ldGhvZHNfaW5kJE1ldHJpYyAlaW4lIHRvcF9tZXRyaWNzJHgsIF0KCiNQbG90CmdncGxvdChtZXRob2RzX2luZCkgKwogIGdlb21fYmFyKGFlcyh4ID0gcmVvcmRlcihNZXRyaWMsIC1QZXJjZW50dWFsKSwgeSA9IFBlcmNlbnR1YWwpLCBwb3NpdGlvbiA9ICJkb2RnZSIsIHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgI2dlb21fdGV4dCggYWVzKHggPSByZW9yZGVyKE1ldHJpYywgLVBlcmNlbnR1YWwpLCB5ID0gUGVyY2VudHVhbCwgbGFiZWwgPSByb3VuZChQZXJjZW50dWFsKSksICAKICAjICAgICAgICAgIGNoZWNrX292ZXJsYXAgPSBUUlVFLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksIHZqdXN0ID0gLTAuNSwgc2l6ZSA9IDMpICsgI3NjYWxlX2ZpbGxfZ3JleSgpICsgCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCBzaXplID0gNykpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249IGMoMC44MiwgMC45NSksIGxlZ2VuZC5kaXJlY3Rpb249Imhvcml6b250YWwiLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIGF4aXMudGl0bGUueD1lbGVtZW50X2JsYW5rKCksIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTcpLCBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkEpICkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSBOQSkpCmBgYAoKCgojIyMgKEc0KSBUbyBhbmFseXNlIHRoZSByZWxhdGlvbiBiZXR3ZWVuIHRoZSBoaXN0b3J5IG9mIGNoYW5nZXMgYW5kIGJ1Z3M7CgojIyMjIChRNC4xKSBJcyBhIGhpZ2ggbnVtYmVyIG9mIGNoYW5nZXMgYW4gaW5kaWNhdGl2ZSBvZiBidWdzIGludHJvZHVjdGlvbj8KCgpgYGB7cn0KI0NoYW5nZXMgQ2hhcnQKbWV0aG9kc19jaGFuZ2VzIDwtIGZpbHRlcihtZXRob2RzX3RvdGFsLCBjaGFuZ2VUeXBlID09ICdBbGwnLCBncm91cE1ldHJpYyA9PSAnQWxsJywgTWV0cmljID09ICdBbGwnKQoKI0NhbGN1bGluZyBwZWFrcwptZXRob2RzX2NoYW5nZXNbLCJ0b3RhbG9mQnVnc0lucyJdIDwtICAgbWFwbHkobWV0aG9kc19jaGFuZ2VzJGJ1Z3NJbnNlcnRpb24sIGdldFRvdGFsQnVnc0lucykKCiNGaWx0ZXJpbmcgb25seSB0cyB3aXRoIGJ1Z3MgYW5kIG1vcmUgd2l0aCBvbmUgY29tbWl0Cm1ldGhvZHNfY2hhbmdlcyA8LSBmaWx0ZXIobWV0aG9kc19jaGFuZ2VzLCB0b3RhbG9mQnVnc0lucyA+IDAsIE50aW1lb2ZDb21taXRzID4gMSkKCiNHZW5lcmF0aW5nIGlkIG9mIGRhdGEgZnJhbWUKbWV0aG9kc19jaGFuZ2VzIDwtIGdlbklkKG1ldGhvZHNfY2hhbmdlcykKCiNMaXN0IG9mIGNoYW5nZXMgYW5kIGJ1Z3MgaW5zZXJ0aW9ucwpsaXN0b2ZQZWFrcyA8PC0gbWV0aG9kc19jaGFuZ2VzJGVsZW1lbnRzVmFsdWUKbGlzdG9mQnVnc0lucyA8PC0gbWV0aG9kc19jaGFuZ2VzJGJ1Z3NJbnNlcnRpb24KCiNDcmVhdGluZyBjb2x1bW5zCm1ldGhvZHNfY2hhbmdlc1ssYygicGVha3MiLCAidHAiLCAiZnAiLCAiZm4iLCAidG4iLCAicHJlY2lzaW9uIiwgInJlY2FsbCIsICJmbWVhc3VyZSIpXSA8LSAwIAojY2FsY3VsYXRpbmcgY29uZnVzaW9uIG1hdHJpeAptZXRob2RzX2NoYW5nZXNbLGMoInBlYWtzIiwgInRwIiwgImZwIiwgImZuIiwgInRuIiwgInByZWNpc2lvbiIsICJyZWNhbGwiLCAiZm1lYXN1cmUiKV0gIDwtICBwbHlyOjpsZHBseShtZXRob2RzX2NoYW5nZXMkaWQsIGdldFN0YXRzUHJvY2VzcykKCiNHcm91cGluZyBkYXRhCmNvbmZ1c2lvbl9tYXRyaXggPC0gYXMuZGF0YS5mcmFtZSgKICBtZXRob2RzX2NoYW5nZXMgJT4lCiAgICBkcGx5cjo6Z3JvdXBfYnkoUHJvamVjdCkgJT4lCiAgICBkcGx5cjo6c3VtbWFyaXNlKAogICAgICBwcmVjaXNpb24gPSBtZWRpYW4ocHJlY2lzaW9uLCBuYS5ybSA9IFRSVUUpLAogICAgICByZWNhbGwgPSBtZWRpYW4ocmVjYWxsLCBuYS5ybSA9IFRSVUUpLAogICAgICBmbWVhc3VyZSA9IG1lZGlhbihmbWVhc3VyZSwgbmEucm0gPSBUUlVFKQogICAgKQopCgojUGl2b3QgZGF0YQpjb25mdXNpb25fbWF0cml4IDwtIG1lbHQoZGZQZWFrcywgaWQgPSAoYygiUHJvamVjdCIpKSkKY29sbmFtZXMoY29uZnVzaW9uX21hdHJpeCkgPC0gYygiUHJvamVjdCIsICJNZWFzdXJlIiwgIlZhbHVlcyIpCgojUGxvdGluZyByZXN1bHRzCmdncGxvdChjb25mdXNpb25fbWF0cml4KSArCiAgZ2VvbV9iYXIoYWVzKHggPSBNZWFzdXJlLCB5ID0gVmFsdWVzKSwgcG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0ID0gImlkZW50aXR5IikgKwogIGdlb21fdGV4dChhZXMoeCA9IE1lYXN1cmUsIHkgPSBWYWx1ZXMsIGxhYmVsID0gcm91bmQoVmFsdWVzLDIpKSwgIAogICAgICAgICAgICBjaGVja19vdmVybGFwID0gVFJVRSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLCB2anVzdCA9IC0wLjUsIHNpemUgPSAzKSArICAKICB0aGVtZShsZWdlbmQuZGlyZWN0aW9uPSJ2ZXJ0aWNhbCIsIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9OCksIAogICAgICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSBOQSksIGF4aXMudGlja3MueCA9ICkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSBOQSkpICsgCiAgZ2d0aXRsZShwcm9qZWN0KSArIHlsYWIoIlBlcmNlbnR1YWwiKSAKCmBgYAoKCg==