Project Material-Dialogs

#Importing functions:
source("~/R/software-history/scripts/utils.R")
project <- "Material-Dialogs"
#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") 

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyMjIFByb2plY3QgTWF0ZXJpYWwtRGlhbG9ncwoKYGBge3J9CiNJbXBvcnRpbmcgZnVuY3Rpb25zOgpzb3VyY2UoIn4vUi9zb2Z0d2FyZS1oaXN0b3J5L3NjcmlwdHMvdXRpbHMuUiIpCgpwcm9qZWN0IDwtICJNYXRlcmlhbC1EaWFsb2dzIgoKI0NzdidzOgpyZXN1bHRzX2ZyYW1lIDwtIAogIHJlYWQuY3N2KAogICAgcGFzdGUwKCIvaG9tZS9yNHBoL1IvYW5hbHlzaXMvcmVzdWx0cy8iLHByb2plY3QsIl9yZXN1bHRzUnFzQnVnc0lucy5jc3YiKSwgCiAgICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UKICApCgptZXRob2RzX2luc2VydGlvbnMgPC0KICByZWFkLmNzdigKICAgIHBhc3RlMCgifi9SL2FuYWx5c2lzL3Jlc3VsdHNfaW5zZXJ0aW9ucy8iLHByb2plY3QsIl9pbnNlcnRpb25Ucy5jc3YiKSwKICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRQogICkKCm1ldGhvZHNfdG90YWw8LQogIHJlYWQuY3N2KAogICAgcGFzdGUwKCJ+L1IvYW5hbHlzaXMvcmVzdWx0cy8iLHByb2plY3QsIl9jaGFuZ2VzVHNXaXRoQnVnc0lucy5jc3YiKSwKICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRQogICkKCnJlc3VsdHNfZnJhbWUkUHJvamVjdCA8LSBwcm9qZWN0CgpgYGAKCgojIyNSYXcgRGF0YXNldDoKQXF1aSDDqSBhcHJlc2VudGFkbyBvIGRhdGFzZXQgcXVlIGZvaSBkaXNjdXRpZG8gbmEgdWx0aW1hIHJldW5pw6NvIGNvbmZvcm1lIHBsYW5pbGhhIHF1ZSBvIEJpZWwgZ2Vyb3Ugbm8gR29vZ2xlIERyaXZlLiBUYWwgZGF0YXNldCBjb25zaXN0ZSBuYSByZWxhw6fDo28gZW50cmUgb3MgdmFsb3JlcyBkZSBtdWRhbsOnYXMgZSBpbnNlcsOnw6NvIGRlIGJ1Z3MgY29tbWl0LiBTZWd1ZSB1bWEgZGVzY3Jpw6fDo28gZGFzIHJlc3BlY3RpdmFzIGNvbHVuYXM6CgoqKk5vQ29tbWl0cyoqIDogQSBRdWFudGlkYWRlIGRlIGNvbW1pdHMgKGspIHF1ZSBhIHRpbWUgc2VyaWUgcG9zc3VpOwoKKipjb21taXQqKiA6IE8gcmVzcGVjdGl2byBjb21taXQgZGVudHJvIGRhIHRpbWUgc2VyaWVzIGNvbSBrIGNvbW1pdHM7CgoqKk5vVGltZVNlcmllcyoqIDogUXVhbnRpZGFkZSBkZSB0aW1lIHNlcmllcyBubyBjb21taXQ7CgoqKk5vQnVnc0lucyoqIDogUXVhbnRpZGFkZSBkZSBidWdzIGluc2VyaWRvcyBubyByZXNwZWN0aXZvIGNvbW1pdDsKCioqbm9DaGFuZ2VzKiogOiBRdWFudGlkYWRlIGRlIG11ZGFuw6dhczsKCioqcGVyY0J1Z3MqKiA6IFBlcmNlbnR1YWwgZGUgYnVncyBpbnNlcmlkb3MgW0Zvcm11bGEgbm9CdWdzSW5zL3N1bShub0J1Z3NJbnMpXTsKCioqcGVyY0NoYW5nZXMqKiA6IFBlcmNlbnR1YWwgZGUgbXVkYW7Dp2FzIFtGb3JtdWxhOiBub0NoYW5nZXMvc3VtKG5vQ2hhbmdlcykgXTsKCgpPYnM6IFJlc3NhbHRhbmRvIHF1ZSBvcyBkYWRvcyBubyBkYXRhc2V0IGVuY29udHJhbS1zZSBkZXNub3JtYWxpemFkb3MsIHBvcnRhbnRvIGjDoSB1bWEgcG9zc2liaWxpZGFkZSBkZSByZXBldGnDp8OjbyAgZGUgdmFsb3JlcyBlbSBhbGd1bWFzIGNvbHVuYXMsIGV4OiBuYSBjb2x1bmEgTm9UaW1lU2VyaWVzLCBuYSBsaW5oYSAyIGUgMyBleGlzdGUgbyB2YWxvciAxNjgxIGRlIG1hbmVpcmEgcmVwZXRpZGEsIG1hcyBubyBjw6FsY3VsbyBkYXMgcmVzcGVjdGl2YXMgbWV0cmljYXMgw6kgdXRpbGl6YWRvIHNvbWVudGUgdW0gdmFsb3IsIHZpc3RvIHF1ZSBleGlzdGVtIHNvbWVudGUgMTY4MSB0aW1lIHNlcmllcyBjb20gMiBjb21taXRzIGUgbsOjbyBvIGRvYnJvIChzb21hIGRhcyBsaW5oYXMgMiBlIDMpLgoKYGBge3J9CnJlc3VsdHNfZnJhbWUKCmBgYAoKIyMjRmluYWwgRGF0YXNldDoKQXF1aSDDqSBhcHJlc2VudGFkbyBvIGRhdGFzZXQgY29tIGFzIG1ldHJpY2FzIGNhbGN1bGFkYXMgY29tIG8gb2JqZXRpdm8gZGUgZ2VyYXIgb3MgcmVzcGVjdGl2b3MgZ3LDoWZpY29zIHByZXNlbnRlcyBuYSBHb2FsIDEgZSAyLiBTZWd1ZSB1bWEgZGVzY3Jpw6fDo28gZGFzIGNvbHVuYXMgZSBzdWFzIHJlc3BlY3RpdmFzIGZvcm11bGFzOgoKKipOb0NvbW1pdHMqKiA6IEEgUXVhbnRpZGFkZSBkZSBjb21taXRzIChrKSBxdWUgYSB0aW1lIHNlcmllIHBvc3N1aTsKCioqTm9UaW1lU2VyaWVzKiogOiBRdWFudGlkYWRlIGRlIHRpbWUgc2VyaWVzIG5vIGNvbW1pdDsKCioqbm9DaGFuZ2VzKiogOiBRdWFudGlkYWRlIGRlIG11ZGFuw6dhczsKCioqTm9CdWdzSW5zKiogOiBRdWFudGlkYWRlIGRlIGJ1Z3MgaW5zZXJpZG9zIG5vIHJlc3BlY3Rpdm8gY29tbWl0OwoKKipCdWdzQnlUcyoqIDogUXVhbnRpZGFkZSBkZSBidWdzIHBvciB0aW1lIHNlcmllcyBbRm9ybXVsYSA6IHN1bShub0J1Z3NJbnMpL21heChub1RpbWVTZXJpZXMpIF07CgoqKkJ1Z3NCeUNoYW5nZXMqKiA6UXVhbnRpZGFkZSBkZSBtdWRhbsOnYXMgcG9yIGJ1Z3MgW0Zvcm11bGE6IHN1bShub0J1Z3NJbnMpLyBzdW0obm9DaGFuZ2VzKV07CgoqKkNoYW5nZXNCeVRzKio6IFF1YW50aWRhZGUgZGUgbXVkYW7Dp2FzIHBybyB0aW1lIHNlcmllcyBbRm9ybXVsYTogc3VtKG5vQ2hhbmdlcykvIG1heChub1RpbWVTZXJpZXMpXTsKCioqUGVyY0J1Z3NCeVRzKio6IFBlcmNlbnR1YWwgZGUgYnVncyBwb3IgdGltZSBzZXJpZXMgW0Zvcm11bGE6IChCdWdzQnlUcy9zdW0oQnVnc0J5VHMpKSAqIDEwMF07CgoqKlBlcmNCdWdzQnlDb21taXQqKjogUGVyY2VudHVhbCBkZSBCdWdzIHBvciBjb21taXRzIFtGb3JtdWxhOiAobm9CdWdzSW5zL3N1bShub0J1Z3NJbnMpKSAqIDEwMF07CgoqKlBlcmNCdWdzQnlDaGFuZ2VzKio6IFBlcmNlbnR1YWwgZGUgQnVncyBwb3IgbXVkYW7Dp2FzIFtGb3JtdWxhOiAoQnVnc0J5Q2hhbmdlcy9zdW0oQnVnc0J5Q2hhbmdlcykpICogMTAwXTsKCioqUGVyY1RzKio6IFBlcmNlbnR1YWwgZGUgdGltZSBzZXJpZXMgW0Zvcm11bGE6IG5vVGltZVNlcmllcyAvIHN1bShub1RpbWVTZXJpZXMpKSAqIDEwMF07CgoqKlBlcmNDaGFuZ2VzQnlUcyoqOiBQZXJjZW50dWFsIGRlIG11ZGFuw6dhcyBwb3IgdGltZSBzZXJpZXMgW0Zvcm11bGE6IChDaGFuZ2VzQnlUcyAvIHN1bShDaGFuZ2VzQnlUcykpICogMTAwXTsKCioqUGVyY0NoYW5nZXMqKjogUGVyY2VudHVhbCBkZSBtdWRhbsOnYXMgW0Zvcm11bGE6ICAobm9DaGFuZ2VzIC8gc3VtKG5vQ2hhbmdlcykpICogMTAwXTsKCk9iczogQ29uZm9ybWUgZXhwbGljYWRvLCBvcyBkYWRvcyBhbnRlcmlvcmVzIChyYXcgZGF0YXNldCkgdGVtIGFsZ3VtYXMgY29sdW5hcyBkZXNub3JtYWxpemFkYXMgKE5vVGltZVNlcmllcyksIHBvcnRhbnRvIGFsZ3VtYXMgZm9ybXVsYXMgY29udMOpbSBvIHZhbG9yIG1heGltbyBkYSByZXNwZWN0aXZhIGNvbHVuYSBkZW50cm8gZG8gYWdydXBhbWVudG8gZGVmaW5pZG8uCgpgYGB7cn0KI0ZpbmFsIERhdGEgRnJhbWUKZGF0YV9wbG90IDwtIGFzLmRhdGEuZnJhbWUoCiAgcmVzdWx0c19mcmFtZSAlPiUKICAgIGRwbHlyOjpncm91cF9ieShQcm9qZWN0LCBOb0NvbW1pdHMpICU+JQogICAgZHBseXI6OnN1bW1hcmlzZSgKICAgICAgbm9UaW1lU2VyaWVzID0gbWF4KG5vVGltZVNlcmllcyksCiAgICAgIG5vQ2hhbmdlcyA9IHN1bShub0NoYW5nZXMpLAogICAgICBub0J1Z3NJbnMgPSBzdW0obm9CdWdzSW5zKSwKICAgICAgQnVnc0J5VHMgPSBzdW0obm9CdWdzSW5zKSAvIG1heChub1RpbWVTZXJpZXMpLAogICAgICBCdWdzQnlDaGFuZ2VzID0gc3VtKG5vQnVnc0lucykgLyBzdW0obm9DaGFuZ2VzKSwKICAgICAgQ2hhbmdlc0J5VHMgPSBzdW0obm9DaGFuZ2VzKSAvIG1heChub1RpbWVTZXJpZXMpCiAgICApICU+JQogICAgZHBseXI6Om11dGF0ZSgKICAgICAgUGVyY0J1Z3NCeVRzID0gKEJ1Z3NCeVRzIC8gc3VtKEJ1Z3NCeVRzKSkgKiAxMDAsCiAgICAgIFBlcmNCdWdzQnlDb21taXQgPSAobm9CdWdzSW5zIC8gc3VtKG5vQnVnc0lucykpICogMTAwLAogICAgICBQZXJjQnVnc0J5Q2hhbmdlcyA9IChCdWdzQnlDaGFuZ2VzIC8gc3VtKEJ1Z3NCeUNoYW5nZXMpKSAqIDEwMCwKICAgICAgUGVyY1RzID0gKG5vVGltZVNlcmllcyAvIHN1bShub1RpbWVTZXJpZXMpKSAqIDEwMCwKICAgICAgUGVyY0NoYW5nZXNCeVRzID0gKENoYW5nZXNCeVRzIC8gc3VtKENoYW5nZXNCeVRzKSkgKiAxMDAsCiAgICAgIFBlcmNDaGFuZ2VzID0gKG5vQ2hhbmdlcyAvIHN1bShub0NoYW5nZXMpKSAqIDEwMAogICAgKSAlPiUKICAgIGRwbHlyOjp1bmdyb3VwKCkKKQoKZGF0YV9wbG90CmBgYAoKCiMjIyAoRzEpVG8gaW52ZXN0aWdhdGUgdGhlIG9jY3VycmVuY2Ugb2YgY29tbWl0cyBhbG9uZyB0aGUgdGltZSBzZXJpZXM7IAojIyMjKFExLjEpIEhvdyBvZnRlbiBhcmUgY29tbWl0cyBwZXJmb3JtZWQgYWxvbmcgdGhlIHRpbWUgc2VyaWVzPwpgYGB7cn0KCiNGcmVxdWVuY3k6CmdncGxvdChkYXRhX3Bsb3QpICsKICBnZW9tX2JhcihhZXMoeD1Ob0NvbW1pdHMseT1ub1RpbWVTZXJpZXMsZ3JvdXA9UHJvamVjdCksIHBvc2l0aW9uID0gImRvZGdlIiwgc3RhdCA9ICJpZGVudGl0eSIpICsKICBmYWNldF9ncmlkKC5+UHJvamVjdCxzY2FsZXM9ImZyZWUiKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0gYygwLjcsIDAuOTUpLCBsZWdlbmQuZGlyZWN0aW9uPSJob3Jpem9udGFsIiwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT01KSwgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSApICsKICB5bGFiKCJGcmVxdWVuY3kgb2YgVGltZSBTZXJpZXMgYnkgQ29tbWl0cyIpICsgc2NhbGVfeF9kaXNjcmV0ZShuYW1lID0iTnVtYmVyIG9mIENvbW1pdHMiLCBsaW1pdHM9c2VxKDEsbWF4KGRhdGFfcGxvdCROb0NvbW1pdHMpKSkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSBOQSksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoY29sb3VyPSJncmV5MjAiLHNpemU9NSxhbmdsZT05MCxoanVzdD0uNSx2anVzdD0uNSxmYWNlPSJwbGFpbiIpKQoKI1BlcmNlbnR1YWwKZ2dwbG90KGRhdGFfcGxvdCkgKwogIGdlb21fYmFyKGFlcyh4PU5vQ29tbWl0cyx5PVBlcmNUcyxncm91cD1Qcm9qZWN0KSwgcG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0ID0gImlkZW50aXR5IikrCiAgZmFjZXRfZ3JpZCguflByb2plY3Qsc2NhbGVzPSJmcmVlIikgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb249IGMoMC43LCAwLjk1KSwgbGVnZW5kLmRpcmVjdGlvbj0iaG9yaXpvbnRhbCIsIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9NSksIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSBOQSkgKSArCiAgeWxhYigiUGVyY2VudHVhbCBvZiBUaW1lIFNlcmllcyBieSBDb21taXRzIikgKyBzY2FsZV94X2Rpc2NyZXRlKG5hbWUgPSJOdW1iZXIgb2YgQ29tbWl0cyIsIGxpbWl0cz1zZXEoMSxtYXgoZGF0YV9wbG90JE5vQ29tbWl0cykpKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChjb2xvdXI9ImdyZXkyMCIsc2l6ZT01LGFuZ2xlPTkwLGhqdXN0PS41LHZqdXN0PS41LGZhY2U9InBsYWluIikpCgoKYGBgCgoKCiMjIyMoUTEuMikgSG93IG9mdGVuIGFyZSBjaGFuZ2VzIHBlcmZvcm1lZCBhbW9uZyBjb21taXRzPwpgYGB7cn0KCiNGcmVxdWVuY3k6CmdncGxvdChkYXRhX3Bsb3QpICsKICBnZW9tX2JhcihhZXMoeD1Ob0NvbW1pdHMseT1ub0NoYW5nZXMpLCBwb3NpdGlvbiA9ICJkb2RnZSIsIHN0YXQgPSAiaWRlbnRpdHkiKSsKICBmYWNldF9ncmlkKC5+UHJvamVjdCxzY2FsZXM9ImZyZWUiKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0gYygwLjcsIDAuOTUpLCBsZWdlbmQuZGlyZWN0aW9uPSJob3Jpem9udGFsIiwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT01KSwgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSkgKwogIHlsYWIoIkZyZXF1ZW5jeSBvZiBDaGFuZ2VzIGJ5IENvbW1pdHMiKSArIHNjYWxlX3hfZGlzY3JldGUobmFtZSA9Ik51bWJlciBvZiBDb21taXRzIiwgbGltaXRzPXNlcSgxLG1heChkYXRhX3Bsb3QkTm9Db21taXRzKSkpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkEpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGNvbG91cj0iZ3JleTIwIixzaXplPTUsYW5nbGU9OTAsaGp1c3Q9LjUsdmp1c3Q9LjUsZmFjZT0icGxhaW4iKSkKCgojUGVyY2VudHVhbApnZ3Bsb3QoZGF0YV9wbG90KSArCiAgZ2VvbV9iYXIoYWVzKHg9Tm9Db21taXRzLHk9UGVyY0NoYW5nZXMpLCBwb3NpdGlvbiA9ICJkb2RnZSIsIHN0YXQgPSAiaWRlbnRpdHkiKSsKICBmYWNldF9ncmlkKC5+UHJvamVjdCxzY2FsZXM9ImZyZWUiKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0gYygwLjcsIDAuOTUpLCBsZWdlbmQuZGlyZWN0aW9uPSJob3Jpem9udGFsIiwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT01KSwgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSkgKwogIHlsYWIoIlBlcmNlbnR1YWwgb2YgQ2hhbmdlcyBieSBDb21taXRzIikgKyBzY2FsZV94X2Rpc2NyZXRlKG5hbWUgPSJOdW1iZXIgb2YgQ29tbWl0cyIsIGxpbWl0cz1zZXEoMSxtYXgoZGF0YV9wbG90JE5vQ29tbWl0cykpKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChjb2xvdXI9ImdyZXkyMCIsc2l6ZT01LGFuZ2xlPTkwLGhqdXN0PS41LHZqdXN0PS41LGZhY2U9InBsYWluIikpCgpgYGAKCiMjIyMoUTEuMykgSG93IG9mdGVuIGFyZSBjaGFuZ2VzIHBlcmZvcm1lZCBhbW9uZyB0aW1lIHNlcmllcz8KYGBge3J9CgojRnJlcXVlbmN5OgpnZ3Bsb3QoZGF0YV9wbG90KSArCiAgZ2VvbV9iYXIoYWVzKHg9Tm9Db21taXRzLHk9Q2hhbmdlc0J5VHMpLCBwb3NpdGlvbiA9ICJkb2RnZSIsIHN0YXQgPSAiaWRlbnRpdHkiKSsKICBmYWNldF9ncmlkKC5+UHJvamVjdCxzY2FsZXM9ImZyZWUiKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0gYygwLjcsIDAuOTUpLCBsZWdlbmQuZGlyZWN0aW9uPSJob3Jpem9udGFsIiwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT01KSwgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSkgKwogIHlsYWIoIkZyZXF1ZW5jeSBvZiBDaGFuZ2VzIGJ5IFRpbWUgU2VyaXMiKSArIHNjYWxlX3hfZGlzY3JldGUobmFtZSA9Ik51bWJlciBvZiBDb21taXRzIiwgbGltaXRzPXNlcSgxLG1heChkYXRhX3Bsb3QkTm9Db21taXRzKSkpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkEpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGNvbG91cj0iZ3JleTIwIixzaXplPTUsYW5nbGU9OTAsaGp1c3Q9LjUsdmp1c3Q9LjUsZmFjZT0icGxhaW4iKSkKCiNQZXJjZW50dWFsOgpnZ3Bsb3QoZGF0YV9wbG90KSArCiAgZ2VvbV9iYXIoYWVzKHg9Tm9Db21taXRzLHk9UGVyY0NoYW5nZXNCeVRzKSwgcG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0ID0gImlkZW50aXR5IikrCiAgZmFjZXRfZ3JpZCguflByb2plY3Qsc2NhbGVzPSJmcmVlIikgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb249IGMoMC43LCAwLjk1KSwgbGVnZW5kLmRpcmVjdGlvbj0iaG9yaXpvbnRhbCIsIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9NSksIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSBOQSkpICsKICB5bGFiKCJQZXJjZW50dWFsIG9mIENoYW5nZXMgYnkgVGltZSBTZXJpcyIpICsgc2NhbGVfeF9kaXNjcmV0ZShuYW1lID0iTnVtYmVyIG9mIENvbW1pdHMiLCBsaW1pdHM9c2VxKDEsbWF4KGRhdGFfcGxvdCROb0NvbW1pdHMpKSkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSBOQSksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoY29sb3VyPSJncmV5MjAiLHNpemU9NSxhbmdsZT05MCxoanVzdD0uNSx2anVzdD0uNSxmYWNlPSJwbGFpbiIpKQoKYGBgCgojIyMgKEcyKVRvIGFzc2VzcyB0aGUgaW50cm9kdWN0aW9uIG9mIGJ1Z3MgYWxvbmcgdGhlIGhpc3Rvcnk7IAoKIyMjIyAoUTIuMSkgSG93IG9mdGVuIGFyZSBidWdzIGludHJvZHVjZWQgYW1vbmcgdGhlIGNvbW1pdHM/CmBgYHtyfQoKI0ZyZXE6CmdncGxvdChkYXRhX3Bsb3QpICsKICBnZW9tX2JhcihhZXMoeD1Ob0NvbW1pdHMseT1ub0J1Z3NJbnMpLCBwb3NpdGlvbiA9ICJkb2RnZSIsIHN0YXQgPSAiaWRlbnRpdHkiKSsKICBmYWNldF9ncmlkKC5+UHJvamVjdCxzY2FsZXM9ImZyZWUiKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0gYygwLjcsIDAuOTUpLCBsZWdlbmQuZGlyZWN0aW9uPSJob3Jpem9udGFsIiwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT01KSwgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSkgKwogIHlsYWIoIlBlcmNlbnR1YWwgb2YgQnVncyBieSBDb21taXRzIikgKyBzY2FsZV94X2Rpc2NyZXRlKG5hbWUgPSJOdW1iZXIgb2YgQ29tbWl0cyIsIGxpbWl0cz1zZXEoMSxtYXgoZGF0YV9wbG90JE5vQ29tbWl0cykpKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChjb2xvdXI9ImdyZXkyMCIsc2l6ZT01LGFuZ2xlPTkwLGhqdXN0PS41LHZqdXN0PS41LGZhY2U9InBsYWluIikpCgojUGVyYwpnZ3Bsb3QoZGF0YV9wbG90KSArCiAgZ2VvbV9iYXIoYWVzKHg9Tm9Db21taXRzLHk9UGVyY0J1Z3NCeUNvbW1pdCksIHBvc2l0aW9uID0gImRvZGdlIiwgc3RhdCA9ICJpZGVudGl0eSIpKwogIGZhY2V0X2dyaWQoLn5Qcm9qZWN0LHNjYWxlcz0iZnJlZSIpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSBjKDAuNywgMC45NSksIGxlZ2VuZC5kaXJlY3Rpb249Imhvcml6b250YWwiLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTUpLCBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkEpKSArCiAgeWxhYigiUGVyY2VudHVhbCBvZiBCdWdzIGJ5IENvbW1pdHMiKSArIHNjYWxlX3hfZGlzY3JldGUobmFtZSA9Ik51bWJlciBvZiBDb21taXRzIiwgbGltaXRzPXNlcSgxLG1heChkYXRhX3Bsb3QkTm9Db21taXRzKSkpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkEpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGNvbG91cj0iZ3JleTIwIixzaXplPTUsYW5nbGU9OTAsaGp1c3Q9LjUsdmp1c3Q9LjUsZmFjZT0icGxhaW4iKSkKYGBgCgojIyMjIChRMi4yKSBIb3cgb2Z0ZW4gYXJlIGJ1Z3MgaW50cm9kdWNlZCBhbW9uZyB0aGUgdGltZSBzZXJpZXM/CmBgYHtyfQoKI0ZyZXF1ZW5jeToKZ2dwbG90KGRhdGFfcGxvdCkgKwogIGdlb21fYmFyKGFlcyh4PU5vQ29tbWl0cyx5PUJ1Z3NCeVRzKSwgcG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0ID0gImlkZW50aXR5IikrCiAgZmFjZXRfZ3JpZCguflByb2plY3Qsc2NhbGVzPSJmcmVlIikgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb249IGMoMC43LCAwLjk1KSwgbGVnZW5kLmRpcmVjdGlvbj0iaG9yaXpvbnRhbCIsIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9NSksIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSBOQSkpICsKICB5bGFiKCJQZXJjZW50dWFsIG9mIEJ1Z3MgYnkgVGltZSBTZXJpZXMiKSArIHNjYWxlX3hfZGlzY3JldGUobmFtZSA9Ik51bWJlciBvZiBDb21taXRzIiwgbGltaXRzPXNlcSgxLG1heChkYXRhX3Bsb3QkTm9Db21taXRzKSkpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkEpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGNvbG91cj0iZ3JleTIwIixzaXplPTUsYW5nbGU9OTAsaGp1c3Q9LjUsdmp1c3Q9LjUsZmFjZT0icGxhaW4iKSkKCiNQZXJjZW50dWFsOgpnZ3Bsb3QoZGF0YV9wbG90KSArCiAgZ2VvbV9iYXIoYWVzKHg9Tm9Db21taXRzLHk9UGVyY0J1Z3NCeVRzKSwgcG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0ID0gImlkZW50aXR5IikrCiAgZmFjZXRfZ3JpZCguflByb2plY3Qsc2NhbGVzPSJmcmVlIikgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb249IGMoMC43LCAwLjk1KSwgbGVnZW5kLmRpcmVjdGlvbj0iaG9yaXpvbnRhbCIsIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9NSksIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSBOQSkpICsKICB5bGFiKCJQZXJjZW50dWFsIG9mIEJ1Z3MgYnkgVGltZSBTZXJpZXMiKSArIHNjYWxlX3hfZGlzY3JldGUobmFtZSA9Ik51bWJlciBvZiBDb21taXRzIiwgbGltaXRzPXNlcSgxLG1heChkYXRhX3Bsb3QkTm9Db21taXRzKSkpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkEpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGNvbG91cj0iZ3JleTIwIixzaXplPTUsYW5nbGU9OTAsaGp1c3Q9LjUsdmp1c3Q9LjUsZmFjZT0icGxhaW4iKSkKYGBgCgojIyMjIChRMi4zKSBIb3cgb2Z0ZW4gYXJlIGJ1Z3MgaW50cm9kdWNlZCBhbW9uZyB0aGUgY2hhbmdlcz8KYGBge3J9CgojRnJlcToKZ2dwbG90KGRhdGFfcGxvdCkgKwogIGdlb21fYmFyKGFlcyh4PU5vQ29tbWl0cyx5PUJ1Z3NCeUNoYW5nZXMpLCBwb3NpdGlvbiA9ICJkb2RnZSIsIHN0YXQgPSAiaWRlbnRpdHkiKSsKICBmYWNldF9ncmlkKC5+UHJvamVjdCxzY2FsZXM9ImZyZWUiKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0gYygwLjcsIDAuOTUpLCBsZWdlbmQuZGlyZWN0aW9uPSJob3Jpem9udGFsIiwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT01KSwgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSkgKwogIHlsYWIoIlBlcmNlbnR1YWwgb2YgQnVncyBieSBDaGFuZ2VzIikgKyBzY2FsZV94X2Rpc2NyZXRlKG5hbWUgPSJOdW1iZXIgb2YgQ29tbWl0cyIsIGxpbWl0cz1zZXEoMSxtYXgoZGF0YV9wbG90JE5vQ29tbWl0cykpKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChjb2xvdXI9ImdyZXkyMCIsc2l6ZT01LGFuZ2xlPTkwLGhqdXN0PS41LHZqdXN0PS41LGZhY2U9InBsYWluIikpCgojUGVyYzoKZ2dwbG90KGRhdGFfcGxvdCkgKwogIGdlb21fYmFyKGFlcyh4PU5vQ29tbWl0cyx5PVBlcmNCdWdzQnlDaGFuZ2VzKSwgcG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0ID0gImlkZW50aXR5IikrCiAgZmFjZXRfZ3JpZCguflByb2plY3Qsc2NhbGVzPSJmcmVlIikgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb249IGMoMC43LCAwLjk1KSwgbGVnZW5kLmRpcmVjdGlvbj0iaG9yaXpvbnRhbCIsIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9NSksIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSBOQSkpICsKICB5bGFiKCJQZXJjZW50dWFsIG9mIEJ1Z3MgYnkgQ2hhbmdlcyIpICsgc2NhbGVfeF9kaXNjcmV0ZShuYW1lID0iTnVtYmVyIG9mIENvbW1pdHMiLCBsaW1pdHM9c2VxKDEsbWF4KGRhdGFfcGxvdCROb0NvbW1pdHMpKSkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSBOQSksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoY29sb3VyPSJncmV5MjAiLHNpemU9NSxhbmdsZT05MCxoanVzdD0uNSx2anVzdD0uNSxmYWNlPSJwbGFpbiIpKQpgYGAKCiMjIyhHMykgVG8gYW5hbHlzZSB0aGUga2luZCBvZiBjaGFuZ2VzIGFyZSBtb3N0bHkgcmVsYXRlZCB0byB0aGUgYnVncyBpbnNlcnRpb247CgojIyMjKFEzLjEpIFdoaWNoIGFyZSB0aGUgdHlwZXMgKEFkZC9EZWwpIG9mIGNoYW5nZXMgbW9yZSBmcmVxdWVudCBpbiB0aGUgYnVncyBpbnNlcnRpb24/IAoKCmBgYHtyfQoKI0NoYW5nZXMgQ2hhcnQKbWV0aG9kc19jaGFuZ2VzIDwtIGZpbHRlcihtZXRob2RzX2luc2VydGlvbnMsIGNoYW5nZVR5cGUgIT0gJ0FsbCcsIGdyb3VwTWV0cmljID09ICdBbGwnLCBNZXRyaWMgPT0gJ0FsbCcpCgptZXRob2RzX2NoYW5nZXNbbWV0aG9kc19jaGFuZ2VzJGNoYW5nZVR5cGUgPT0gImNoYW5nZU1ldHJpY3NBZGRpdGlvbiIsIGMoImNoYW5nZVR5cGUiKV0gPC0gIkFkZGl0aW9uIgptZXRob2RzX2NoYW5nZXNbbWV0aG9kc19jaGFuZ2VzJGNoYW5nZVR5cGUgPT0gImNoYW5nZU1ldHJpY3NEZWxldGlvbiIsIGMoImNoYW5nZVR5cGUiKV0gPC0gIkRlbGV0aW9uIgoKY2JQYWxldHRlIDwtIGMoIiMwMDlFNzMiLCAiI0YxNTg1NCIpCgptZXRob2RzX2NoYW5nZXMgPC0gIGFzLmRhdGEuZnJhbWUoCiAgbWV0aG9kc19jaGFuZ2VzICU+JQogICAgZHBseXI6Omdyb3VwX2J5KFByb2plY3QsIGNoYW5nZVR5cGUpICU+JQogICAgZHBseXI6OnN1bW1hcmlzZSh0b3RhbENoYW5nZXMgPSBzdW0oQ291bnQpKSAlPiUKICAgIG11dGF0ZShQZXJjZW50dWFsID0gdG90YWxDaGFuZ2VzIC8gc3VtKHRvdGFsQ2hhbmdlcykgKiAxMDApICU+JQogICAgdW5ncm91cCgpCikKCmdncGxvdChtZXRob2RzX2NoYW5nZXMpICsKICBnZW9tX2JhcihhZXMoeCA9IFByb2plY3QsIHkgPSBQZXJjZW50dWFsLCBmaWxsID0gY2hhbmdlVHlwZSwgZ3JvdXAgPSBjaGFuZ2VUeXBlKSwgcG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0ID0gImlkZW50aXR5IikgKwogIGdlb21fdGV4dCggYWVzKHggPSBQcm9qZWN0LCB5ID0gUGVyY2VudHVhbCwgbGFiZWwgPSByb3VuZChQZXJjZW50dWFsKSwgZ3JvdXAgPSBjaGFuZ2VUeXBlKSwgIAogICAgICAgICAgICAgY2hlY2tfb3ZlcmxhcCA9IFRSVUUsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSwgdmp1c3QgPSAtMC41LCBzaXplID0gMykgKyAjc2NhbGVfZmlsbF9ncmV5KCkgKyAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSBjKDAuODIsIDAuOTUpLCBsZWdlbmQuZGlyZWN0aW9uPSJob3Jpem9udGFsIiwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLCBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT03KSwgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSApICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkEpKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWNiUGFsZXR0ZSkKCmBgYAoKIyMjIyhRMy4yKSBXaGljaCBhcmUgdGhlIG1ldHJpY3MgZ3JvdXBzIG1vcmUgZnJlcXVlbnQgaW4gdGhlIGJ1Z3MgaW5zZXJ0aW9uPyAKCmBgYHtyfQojRmlsdGVyOkQKbWV0aG9kc19ncm91cHM8LSBmaWx0ZXIobWV0aG9kc19pbnNlcnRpb25zLCBncm91cE1ldHJpYyAhPSAiUk0iLCBjaGFuZ2VUeXBlID09ICdBbGwnLCBncm91cE1ldHJpYyAhPSAnQWxsJywgTWV0cmljID09ICdBbGwnKQoKI0dyb3VwIG1lYXN1cmVzCm1ldGhvZHNfZ3JvdXBzIDwtICBhcy5kYXRhLmZyYW1lKAogIG1ldGhvZHNfZ3JvdXBzICU+JQogICAgZHBseXI6Omdyb3VwX2J5KFByb2plY3QsIGdyb3VwTWV0cmljKSAlPiUKICAgIGRwbHlyOjpzdW1tYXJpc2UoQ2hhbmdlcyA9IHN1bShDb3VudCkpICU+JQogICAgZHBseXI6Om11dGF0ZShQZXJjZW50dWFsID0gQ2hhbmdlcyAvIHN1bShDaGFuZ2VzKSAqIDEwMCkgJT4lCiAgICBkcGx5cjo6dW5ncm91cCgpCikKCiNQbG90CiAgZ2dwbG90KG1ldGhvZHNfZ3JvdXBzKSArCiAgICBnZW9tX2JhcihhZXMoeCA9IHJlb3JkZXIoZ3JvdXBNZXRyaWMsIC1QZXJjZW50dWFsKSwgeSA9IFBlcmNlbnR1YWwpLCBwb3NpdGlvbiA9ICJkb2RnZSIsIHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgICBnZW9tX3RleHQoIGFlcyh4ID0gcmVvcmRlcihncm91cE1ldHJpYywgLVBlcmNlbnR1YWwpLCB5ID0gUGVyY2VudHVhbCwgbGFiZWwgPSByb3VuZChQZXJjZW50dWFsKSksICAKICAgICAgICAgICAgICAgY2hlY2tfb3ZlcmxhcCA9IFRSVUUsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSwgdmp1c3QgPSAtMC41LCBzaXplID0gMykgKyAjc2NhbGVfZmlsbF9ncmV5KCkgKyAKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgc2l6ZT0gOCkpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0gYygwLjgyLCAwLjk1KSwgbGVnZW5kLmRpcmVjdGlvbj0iaG9yaXpvbnRhbCIsIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICBheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLCBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT03KSwgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSApICsKICAgIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkEpKQoKYGBgCgoKCiMjIyMoUTMuMykgV2hpY2ggYXJlIHRoZSBjaGFuZ2UgbWV0cmljcyBtb3JlIGZyZXF1ZW50IGluIHRoZSBidWdzIGluc2VydGlvbj8gCgpgYGB7cn0KI0ZpbHRlcjpECm1ldGhvZHNfaW5kIDwtIGZpbHRlcihtZXRob2RzX2luc2VydGlvbnMsIGdyb3VwTWV0cmljICE9ICJSTSIsIGNoYW5nZVR5cGUgPT0gJ0FsbCcsIGdyb3VwTWV0cmljICE9ICdBbGwnLCBNZXRyaWMgIT0gJ0FsbCcpCgojT1JkZXIgbWV0cmljcyBieSBmcmVxdWVuY3kKZnJlcXNfbWV0cmljcyA8LSBwbHlyOjpjb3VudChtZXRob2RzX2luZCRNZXRyaWMpCmZyZXFzX21ldHJpY3MgPC0gZnJlcXNfbWV0cmljc1tvcmRlcigtZnJlcXNfbWV0cmljcyRmcmVxKSwgXQoKI0dyb3VwaW5nIGRhdGEKbWV0aG9kc19pbmQgPC0gIGFzLmRhdGEuZnJhbWUoCiAgbWV0aG9kc19pbmQgJT4lCiAgICBkcGx5cjo6Z3JvdXBfYnkoUHJvamVjdCwgTWV0cmljKSAlPiUKICAgIGRwbHlyOjpzdW1tYXJpc2UoQ2hhbmdlcyA9IHN1bShDb3VudCkpICU+JQogICAgZHBseXI6Om11dGF0ZShQZXJjZW50dWFsID0gQ2hhbmdlcyAvIHN1bShDaGFuZ2VzKSAqIDEwMCkgJT4lCiAgICBkcGx5cjo6dW5ncm91cCgpCikKCiNUb3AgbWV0cmljcwp0b3BfbWV0cmljcyA8LSBoZWFkKGZyZXFzX21ldHJpY3MsIDE1KQptZXRob2RzX2luZCA8LSBtZXRob2RzX2luZFttZXRob2RzX2luZCRNZXRyaWMgJWluJSB0b3BfbWV0cmljcyR4LCBdCgojUGxvdApnZ3Bsb3QobWV0aG9kc19pbmQpICsKICBnZW9tX2JhcihhZXMoeCA9IHJlb3JkZXIoTWV0cmljLCAtUGVyY2VudHVhbCksIHkgPSBQZXJjZW50dWFsKSwgcG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0ID0gImlkZW50aXR5IikgKwogICNnZW9tX3RleHQoIGFlcyh4ID0gcmVvcmRlcihNZXRyaWMsIC1QZXJjZW50dWFsKSwgeSA9IFBlcmNlbnR1YWwsIGxhYmVsID0gcm91bmQoUGVyY2VudHVhbCkpLCAgCiAgIyAgICAgICAgICBjaGVja19vdmVybGFwID0gVFJVRSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLCB2anVzdCA9IC0wLjUsIHNpemUgPSAzKSArICNzY2FsZV9maWxsX2dyZXkoKSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgc2l6ZSA9IDcpKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSBjKDAuODIsIDAuOTUpLCBsZWdlbmQuZGlyZWN0aW9uPSJob3Jpem9udGFsIiwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLCBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT03KSwgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BKSApICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkEpKQpgYGAKCgoKIyMjIChHNCkgVG8gYW5hbHlzZSB0aGUgcmVsYXRpb24gYmV0d2VlbiB0aGUgaGlzdG9yeSBvZiBjaGFuZ2VzIGFuZCBidWdzOwoKIyMjIyAoUTQuMSkgSXMgYSBoaWdoIG51bWJlciBvZiBjaGFuZ2VzIGFuIGluZGljYXRpdmUgb2YgYnVncyBpbnRyb2R1Y3Rpb24/CgoKYGBge3J9CiNDaGFuZ2VzIENoYXJ0Cm1ldGhvZHNfY2hhbmdlcyA8LSBmaWx0ZXIobWV0aG9kc190b3RhbCwgY2hhbmdlVHlwZSA9PSAnQWxsJywgZ3JvdXBNZXRyaWMgPT0gJ0FsbCcsIE1ldHJpYyA9PSAnQWxsJykKCiNDYWxjdWxpbmcgcGVha3MKbWV0aG9kc19jaGFuZ2VzWywidG90YWxvZkJ1Z3NJbnMiXSA8LSAgIG1hcGx5KG1ldGhvZHNfY2hhbmdlcyRidWdzSW5zZXJ0aW9uLCBnZXRUb3RhbEJ1Z3NJbnMpCgojRmlsdGVyaW5nIG9ubHkgdHMgd2l0aCBidWdzIGFuZCBtb3JlIHdpdGggb25lIGNvbW1pdAptZXRob2RzX2NoYW5nZXMgPC0gZmlsdGVyKG1ldGhvZHNfY2hhbmdlcywgdG90YWxvZkJ1Z3NJbnMgPiAwLCBOdGltZW9mQ29tbWl0cyA+IDEpCgojR2VuZXJhdGluZyBpZCBvZiBkYXRhIGZyYW1lCm1ldGhvZHNfY2hhbmdlcyA8LSBnZW5JZChtZXRob2RzX2NoYW5nZXMpCgojTGlzdCBvZiBjaGFuZ2VzIGFuZCBidWdzIGluc2VydGlvbnMKbGlzdG9mUGVha3MgPDwtIG1ldGhvZHNfY2hhbmdlcyRlbGVtZW50c1ZhbHVlCmxpc3RvZkJ1Z3NJbnMgPDwtIG1ldGhvZHNfY2hhbmdlcyRidWdzSW5zZXJ0aW9uCgojQ3JlYXRpbmcgY29sdW1ucwptZXRob2RzX2NoYW5nZXNbLGMoInBlYWtzIiwgInRwIiwgImZwIiwgImZuIiwgInRuIiwgInByZWNpc2lvbiIsICJyZWNhbGwiLCAiZm1lYXN1cmUiKV0gPC0gMCAKI2NhbGN1bGF0aW5nIGNvbmZ1c2lvbiBtYXRyaXgKbWV0aG9kc19jaGFuZ2VzWyxjKCJwZWFrcyIsICJ0cCIsICJmcCIsICJmbiIsICJ0biIsICJwcmVjaXNpb24iLCAicmVjYWxsIiwgImZtZWFzdXJlIildICA8LSAgcGx5cjo6bGRwbHkobWV0aG9kc19jaGFuZ2VzJGlkLCBnZXRTdGF0c1Byb2Nlc3MpCgojR3JvdXBpbmcgZGF0YQpjb25mdXNpb25fbWF0cml4IDwtIGFzLmRhdGEuZnJhbWUoCiAgbWV0aG9kc19jaGFuZ2VzICU+JQogICAgZHBseXI6Omdyb3VwX2J5KFByb2plY3QpICU+JQogICAgZHBseXI6OnN1bW1hcmlzZSgKICAgICAgcHJlY2lzaW9uID0gbWVkaWFuKHByZWNpc2lvbiwgbmEucm0gPSBUUlVFKSwKICAgICAgcmVjYWxsID0gbWVkaWFuKHJlY2FsbCwgbmEucm0gPSBUUlVFKSwKICAgICAgZm1lYXN1cmUgPSBtZWRpYW4oZm1lYXN1cmUsIG5hLnJtID0gVFJVRSkKICAgICkKKQoKI1Bpdm90IGRhdGEKY29uZnVzaW9uX21hdHJpeCA8LSBtZWx0KGRmUGVha3MsIGlkID0gKGMoIlByb2plY3QiKSkpCmNvbG5hbWVzKGNvbmZ1c2lvbl9tYXRyaXgpIDwtIGMoIlByb2plY3QiLCAiTWVhc3VyZSIsICJWYWx1ZXMiKQoKI1Bsb3RpbmcgcmVzdWx0cwpnZ3Bsb3QoY29uZnVzaW9uX21hdHJpeCkgKwogIGdlb21fYmFyKGFlcyh4ID0gTWVhc3VyZSwgeSA9IFZhbHVlcyksIHBvc2l0aW9uID0gImRvZGdlIiwgc3RhdCA9ICJpZGVudGl0eSIpICsKICBnZW9tX3RleHQoYWVzKHggPSBNZWFzdXJlLCB5ID0gVmFsdWVzLCBsYWJlbCA9IHJvdW5kKFZhbHVlcywyKSksICAKICAgICAgICAgICAgY2hlY2tfb3ZlcmxhcCA9IFRSVUUsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSwgdmp1c3QgPSAtMC41LCBzaXplID0gMykgKyAgCiAgdGhlbWUobGVnZW5kLmRpcmVjdGlvbj0idmVydGljYWwiLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTgpLCAKICAgICAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkEpLCBheGlzLnRpY2tzLnggPSApICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkEpKSArIAogIGdndGl0bGUocHJvamVjdCkgKyB5bGFiKCJQZXJjZW50dWFsIikgCgpgYGAKCgo=