Historic events have profound impacts on today’s world politics, including US politics. World War I decimated Europe and contributed to the rise of the United States. The Great Depression cripled Germany’s economy and thus led Nazi to come to its power which in turn led to World War II. WWII shaped today’s world vastly and the Great Recession gave rise to a new setup of the world which is still ongoing.
This project aims at discorvering how these historic events can affect presidents’ inaugural speeches made during those events. In this project, I focus on three types of historic events in modern history – wars, major economic recessions and economic expansions. Specifically, those events include World War I, World War II, the Great Depression, the Great Recession, the longest and the second longest economic expansions in US history.
Step 0 - Install and load libraries
packages.used=c("rvest", "tibble", "qdap", "ggplot2",
"sentimentr", "gplots", "dplyr",
"tm", "syuzhet", "factoextra",
"scales", "RColorBrewer",
"RANN", "tm", "topicmodels", "lubridate")
# check packages that need to be installed.
packages.needed=setdiff(packages.used,
intersect(installed.packages()[,1],
packages.used))
# install additional packages
if(length(packages.needed)>0){
install.packages(packages.needed, dependencies = TRUE)
}
# load packages
library("rvest")
library("tibble")
library("qdap")
library("ggplot2")
library("sentimentr")
library("gplots")
library("dplyr")
library("tm")
library("syuzhet")
library("factoextra")
library("scales")
library("RColorBrewer")
library("RANN")
library("tm")
library("topicmodels")
library("lubridate")
# Set working directiry
setwd("/Users/zailchen/Documents/RWorkplace/ADS_Project_1_Ziyu_Chen")
path <- getwd()
# Source functions
source(paste0(path,"/lib/plotstacked.R"))
source(paste0(path,"/lib/speechFuncs.R"))
This notebook was prepared with the following environmental settings.
print(R.version)
_
platform x86_64-apple-darwin15.6.0
arch x86_64
os darwin15.6.0
system x86_64, darwin15.6.0
status
major 3
minor 4.3
year 2017
month 11
day 30
svn rev 73796
language R
version.string R version 3.4.3 (2017-11-30)
nickname Kite-Eating Tree
Step 1: Data harvest and read in the speeches
### Inauguaral speeches
main.page <- read_html(x = "http://www.presidency.ucsb.edu/inaugurals.php")
# Get link URLs
inaug=f.speechlinks(main.page)
inaug[,1] <- as.Date(inaug[,1], format="%B %e, %Y")
inaug=inaug[-nrow(inaug),] # remove the last line, irrelevant due to error.
inaug.list=read.csv(paste0(path,"/data/inauglist.csv"), stringsAsFactors = FALSE)
inaug.list$type=c(rep("inaug", nrow(inaug.list)))
inaug.url=inaug
speech.list=cbind(inaug.list, inaug.url)
speech.list = speech.list[ ,- which(colnames(speech.list) == "Date")]
colnames(speech.list)[8] <- "Date"
# Loop over each row in speech.list
speech.list$fulltext=NA
for(i in seq(nrow(speech.list))) {
text <- read_html(speech.list$urls[i]) %>% # load the page
html_nodes(".displaytext") %>% # isloate the text
html_text() # get the text
speech.list$fulltext[i]=text
# Create the file name
filename <- paste0(path,"/data/fulltext/",
speech.list$type[i],
speech.list$File[i], "-",
speech.list$Term[i], ".txt")
sink(file = filename) %>% # open file to write
cat(text) # write the file
sink() # close the file
}
Step 2: Data Processing — generate list of sentences
sentence.list=NULL
for(i in 1:nrow(speech.list)){
sentences=sent_detect(speech.list$fulltext[i],
endmarks = c("?", ".", "!", "|",";"))
if(length(sentences)>0){
emotions=get_nrc_sentiment(sentences)
word.count=word_count(sentences)
# colnames(emotions)=paste0("emo.", colnames(emotions))
# in case the word counts are zeros?
emotions=diag(1/(word.count+0.01))%*%as.matrix(emotions)
sentence.list=rbind(sentence.list,
cbind(speech.list[i,-ncol(speech.list)],
sentences=as.character(sentences),
word.count,
emotions,
sent.id=1:length(sentences)))
}
}
sentence.list = sentence.list %>% filter(!is.na(word.count))
Step 3: Identify inaugural speeches that are made during those historic events
There are altogether 10 of those speeches.
# President(s) who assumed the office during the longest period of economic expansion in US history.
presi.expan1 <- speech.list %>%
filter(Date %within% interval("1991-03-01", "2001-03-30")) %>%
select(President, File, Term) %>%
mutate(Event = "Expansion")
# President(s) who assumed the office during the second longest period of economic expansion.
presi.expan2 <- speech.list %>%
filter(Date %within% interval("1982-12-01", "1990-07-30")) %>%
select(President, File, Term) %>%
mutate(Event = "Expansion")
# President(s) who assumed the office during the Great Depression 1929 - 1933.
presi.rece1 <- speech.list %>%
filter(Date %within% interval("1929-08-01", "1933-03-30")) %>%
select(President, File, Term) %>%
mutate(Event = "Recession")
# President(s) who assumed the office during the Great Recession 2007 - 2009.
presi.rece2 <- speech.list %>%
filter(Date %within% interval("2007-12-01", "2009-06-30")) %>%
select(President, File, Term) %>%
mutate(Event = "Recession")
# President(s) who assumed the office during WWI.
presi.war1 <- speech.list %>%
filter(Date %within% interval("1914-07-28", "1918-11-11")) %>%
select(President, File, Term) %>%
mutate(Event = "War")
# President(s) who assumed the office during WWII.
presi.war2 <- speech.list %>%
filter(Date %within% interval("1939-09-01", "1945-09-02")) %>%
select(President, File, Term) %>%
mutate(Event = "War")
Step 4: Sentiment analysis: Clustering of emotions
For each sentence we will apply sentiment analysis using NRC sentiment lexion. Eight emotions will be displayed: trust, surprise, sadneess, joy feat, disgust, anticipation and anger. Those emotions are mapped with specific words which can be found in NRC sentiment lexion. The goal of this section is to determin whether the emotions expressed from speeches made during those distinct historic events differ from each other.
col.use=c("red2", "darkgoldenrod1",
"chartreuse3", "blueviolet",
"darkgoldenrod2", "dodgerblue3",
"darkgoldenrod1", "darkgoldenrod1")
par(mfrow=c(1,2),mar=c(4, 6, 2, 1))
# Emotion clustering of inaugural speeches made during the longest economic expansion in history.
emo.means=colMeans((sentence.list %>%
filter(President %in% presi.expan1[ ,"President"]) %>%
select(anger:trust))>0.01)
barplot(emo.means[order(emo.means)], las=2, col=col.use[order(emo.means)], horiz=T, main="The longest economic expansion")
# During the second longest economic expansion.
emo.means=colMeans((sentence.list %>%
filter(President %in% presi.expan2[ ,"President"]) %>%
select(anger:trust))>0.01)
barplot(emo.means[order(emo.means)], las=2, col=col.use[order(emo.means)], horiz=T, main="The 2rd longest economic expansion")

# During the Great Depression 1929 - 1933.
emo.means=colMeans((sentence.list %>%
filter(President %in% presi.rece1[ ,"President"]) %>%
select(anger:trust))>0.01)
barplot(emo.means[order(emo.means)], las=2, col=col.use[order(emo.means)], horiz=T, main="The Great Depression")
# During the Great Recession 2007 - 2009.
emo.means=colMeans((sentence.list %>%
filter(President %in% presi.rece2[ ,"President"]) %>%
select(anger:trust))>0.01)
barplot(emo.means[order(emo.means)], las=2, col=col.use[order(emo.means)], horiz=T, main="The Great Recession")

# During the World War I
emo.means=colMeans((sentence.list %>%
filter(President %in% presi.war1[ ,"President"]) %>%
select(anger:trust))>0.01)
barplot(emo.means[order(emo.means)], las=2, col=col.use[order(emo.means)], horiz=T, main="WWI")
# During the World War II
emo.means=colMeans((sentence.list %>%
filter(President %in% presi.war2[ ,"President"]) %>%
select(anger:trust))>0.01)
barplot(emo.means[order(emo.means)], las=2, col=col.use[order(emo.means)], horiz=T, main="WWII")

From the barplots above, we can easily tell that the relative importance of different emotions across all 10 speeches is quite consistent. “Trust” was significantly expressed more than any other emotions. During those major economic expansion periods, we see a lot more “joy” and “surprise” and less “fear” and “anger” overal compared to recession and war periods, which is quite reasonable.
Step 5: Cluster speeches based on the emotion scores
Here we use K-means method to cluster speeches based on their emotion scores. The object of this step is to see whether speeches made during the same type of event can be clustered together, which may indicate a homogeneity in terms of the emotions they express. In order to obtain better results, the clustering was performed under two circumstances: across all three types of historic events and only across economic expansion and recession.
presidents <- rbind(presi.expan1, presi.expan2,
presi.rece1, presi.rece2,
presi.war1, presi.war2) %>%
mutate(President.term = paste0(President, " term " ,Term),
President.event = paste0(President, " term",Term, " ",Event))
presid.summary=tbl_df(sentence.list) %>%
mutate(President.term = paste0(President, " term " ,Term)) %>%
filter(President.term %in% presidents$President.term) %>%
group_by(President.term)%>%
summarise(
anger=mean(anger),
anticipation=mean(anticipation),
disgust=mean(disgust),
fear=mean(fear),
joy=mean(joy),
sadness=mean(sadness),
surprise=mean(surprise),
trust=mean(trust)) %>%
left_join(presidents, by = "President.term") %>%
select(anger:trust, President.event)
presid.summary=as.data.frame(presid.summary)
rownames(presid.summary)=as.character((presid.summary$President.event))
r = which(colnames(presid.summary)=="President.event")
# Cluster under all three types of events: Expansion, recession, and war
km.res=kmeans(presid.summary[,-r], iter.max=200, 3)
fviz_cluster(km.res, stand=F, repel= TRUE,
data = presid.summary[,-r], xlab="", xaxt="n",
show.clust.cent=FALSE)

# Cluster only under economic expansion and recession
km.res=kmeans(presid.summary[-c(3, 4, 10), -r], iter.max=200, 2)
fviz_cluster(km.res, stand=F, repel= TRUE,
data = presid.summary[-c(3, 4, 10), -r], xlab="", xaxt="n",
show.clust.cent=FALSE)

The result obtained from using k = 3 and all three types of events is not informative. Obviously speeches are clustered together not according to the type of event during which they were made.
However, when using k = 2 and only expansions and recessions, the result seems quite promising. All speeches made during recessions are clustered together and most of speeches made during expansions are clustered together.
Step 6: Topic modeling
Next we would like to analyze those speeches based on the differences in their topics. Here we use topic modeling. The goal is to determine if the speeches made during the same type of event are similar in their topics.
sentence.list.presi <- tbl_df(sentence.list) %>%
mutate(President.term = paste0(President, " term " ,Term)) %>%
filter(President.term %in% presidents$President.term) %>%
left_join(presidents, by = c("President", "File", "Term",
"President.term"))
Build my own LDA function
To avoid running those extremely long LDA codes repeatedly, I created my own LDA function and write.file function.
LDA_Out <- function(event = NULL, df = sentence.list.presi, burnin = 4000,
iter = 2000, thin = 500, seed =list(2003,5,63,100001,765),
nstart = 5, best = TRUE, k = 10) {
if (!is.null(event)) { df <- df %>% filter(tolower(Event) == tolower(event)) }
corpus.list=df[2:(nrow(df)-1), ]
sentence.pre=df$sentences[1:(nrow(df)-2)]
sentence.post=df$sentences[3:(nrow(df)-1)]
corpus.list$snipets=paste(sentence.pre, corpus.list$sentences, sentence.post, sep=" ")
rm.rows=(1:nrow(corpus.list))[corpus.list$sent.id==1]
rm.rows=c(rm.rows, rm.rows-1)
corpus.list=corpus.list[-rm.rows, ]
## Text mining
docs <- Corpus(VectorSource(corpus.list$snipets))
#writeLines(as.character(docs[[sample(1:nrow(corpus.list), 1)]]))
### Text basic processing
#remove potentially problematic symbols
docs <-tm_map(docs,content_transformer(tolower))
#remove punctuation
docs <- tm_map(docs, removePunctuation)
#Strip digits
docs <- tm_map(docs, removeNumbers)
#remove stopwords
docs <- tm_map(docs, removeWords, stopwords("english"))
#remove whitespace
docs <- tm_map(docs, stripWhitespace)
#Stem document
docs <- tm_map(docs,stemDocument)
## Topic modeling
###Gengerate document-term matrices.
dtm <- DocumentTermMatrix(docs)
#convert rownames to filenames#convert rownames to filenames
rownames(dtm) <- paste(corpus.list$type, corpus.list$File,
corpus.list$Term, corpus.list$sent.id, sep="_")
rowTotals <- apply(dtm , 1, sum) #Find the sum of words in each Document
dtm <- dtm[rowTotals> 0, ]
corpus.list=corpus.list[rowTotals>0, ]
#Run LDA using Gibbs sampling
ldaOut <-LDA(dtm, k, method="Gibbs", control=list(nstart=nstart,
seed = seed, best=best,
burnin = burnin, iter = iter,
thin=thin))
return(ldaOut)
}
Build function to write LDA files
write_lda_files <- function(event = NULL, Path = path) {
ldaOut <- LDA_Out(event = event)
#write out results
#docs to topics
ldaOut.topics <- as.matrix(topics(ldaOut))
# table(c(1:k, ldaOut.topics.expan))
write.csv(ldaOut.topics, file=paste0(Path,"/output/LDAGibbs",k,"DocsToTopics","_",event,".csv"))
#top 6 terms in each topic
ldaOut.terms <- as.matrix(terms(ldaOut,20))
write.csv(ldaOut.terms,file=paste0(Path,"/output/LDAGibbs",k,"TopicsToTerms","_",event,".csv"))
#probabilities associated with each topic assignment
topicProbabilities <- as.data.frame(ldaOut@gamma)
write.csv(topicProbabilities,file=paste0(Path,"/output/LDAGibbs",k,"TopicProbabilities",
"_",event,".csv"))
}
Run LDA and write files
In order to determine the differences in topics, here I run LDA separately on speeches made during different types of historic event (expansion, recession and war).
# Run LDA under 3 different events
ldaOut.expan <- LDA_Out(event = "expansion")
ldaOut.reces <- LDA_Out(event = "recession")
ldaOut.war <- LDA_Out(event = "war")
# Write LDA files
sapply(c("expansion","recession", "war"), write_lda_files)
$expansion
NULL
$recession
NULL
$war
NULL
Step 7: LDA Results Visilization
In order to better visilize and understand the LDA results, I used ggplots. Each barplot represents a specific topic and each topic contains 20 terms. Based on the most popular terms and the most salient terms for each topic, we conclude a topic name to each topic.
# During economic expansion
ldaOut.tidy.expan <- tidy(ldaOut.expan)
ldaOut.terms.expan <- as_tibble(terms(ldaOut.expan,20))
top.terms.expan <- ldaOut.tidy.expan %>%
group_by(topic) %>%
top_n(20, beta) %>%
ungroup() %>%
arrange(topic, -beta)
top.terms.expan %>%
mutate(term = reorder(term, beta)) %>%
ggplot(aes(term, beta, fill = factor(topic))) +
geom_bar(stat = "identity", show.legend = FALSE) +
facet_wrap(~ topic, scales = "free", ncol=5, nrow=2) +
ggtitle("Topics and Terms During Economic Expansions")+
coord_flip()

# During economic recession
ldaOut.tidy.reces <- tidy(ldaOut.reces)
ldaOut.terms.reces <- as_tibble(terms(ldaOut.reces,20))
top.terms.reces <- ldaOut.tidy.reces %>%
group_by(topic) %>%
top_n(20, beta) %>%
ungroup() %>%
arrange(topic, -beta)
top.terms.reces %>%
mutate(term = reorder(term, beta)) %>%
ggplot(aes(term, beta, fill = factor(topic))) +
geom_bar(stat = "identity", show.legend = FALSE) +
facet_wrap(~ topic, scales = "free", ncol=5, nrow=2) +
ggtitle("Topics and Terms During Economic Recessions")+
coord_flip()

# During wars
ldaOut.tidy.war <- tidy(ldaOut.war)
ldaOut.terms.war <- as_tibble(terms(ldaOut.war,20))
top.terms.war <- ldaOut.tidy.war %>%
group_by(topic) %>%
top_n(20, beta) %>%
ungroup() %>%
arrange(topic, -beta)
top.terms.war %>%
mutate(term = reorder(term, beta)) %>%
ggplot(aes(term, beta, fill = factor(topic))) +
geom_bar(stat = "identity", show.legend = FALSE) +
facet_wrap(~ topic, scales = "free", ncol=5, nrow=2) +
ggtitle("Topics and Terms During Wars")+
coord_flip()

Those LDA barplots are very informative and the differences in topics are quite salient between different types of historic events. For instance, during economic expansion, presidents like to talk about “freedom” (topic 1), “family” (topic 2), and “national security” (topic 3). Since those two major economic expansions are all during the Cold War, it does make sense presidents then like to talk about those things.
During recessions, they like to talk about “job” (topic 2), “reform” (topic 5), etc.
During wars, they like to talk about “cohesion”" (topic 2), “responsibility”" (topic 3), etc.
Step 9: Topic clustering
Based on the LDA results, I gave all 15 topics a meaningful tag. Then I cluster the topics of those speeches together to find a pattern.
topics.hash=c("American", "Equality", "Election", "Obligation", "Patriotism", "Freedom", "Economy", "Reform", "Unity", "SocialWelfare", "Government", "Defense", "Faith", "Misc", "Legislation")
corpus.list.presi <- corpus.list %>%
mutate(President.term = paste0(President, " term " ,Term)) %>%
filter(President.term %in% presidents$President.term) %>%
mutate(ldatopic=as.vector(ldaOut.topics)) %>%
mutate(ldahash=topics.hash[ldaOut.topics])
colnames(topicProbabilities)=topics.hash
corpus.list.df=cbind(corpus.list.presi, topicProbabilities)
topic.summary=tbl_df(corpus.list.df)%>%
mutate(President.term = paste0(President, " term " ,Term)) %>%
select(President.term, American:Legislation) %>%
group_by(President.term)%>%
summarise_each(funs(mean)) %>%
ungroup() %>%
left_join(presidents, by = "President.term") %>%
select(President.event, American:Legislation)
topic.summary=as.data.frame(topic.summary)
rownames(topic.summary)=topic.summary[,1]
topic.plot=c(7, 8, 2, 9, 12, 10, 6)
print(topics.hash[topic.plot])
[1] "Economy" "Reform" "Equality" "Unity" "Defense" "SocialWelfare" "Freedom"
heatmap.2(as.matrix(topic.summary[,topic.plot+1]),
scale = "column", key=F,
col = bluered(100),
cexRow = 0.9, cexCol = 0.9, margins = c(6, 15),
trace = "none", density.info = "none")

It shows that presidents who assumed the office during economic expansions like to talk about “social welfare”, “unity” and “economy” more. Presidents who assumed the office during wars preferred talking about “defense”, “equality”, and “freedom”. There is no recognizable favored topics for presidents assumed the office during recessions.
Step 10: Cluster speeches using K-means
Lastly I want to cluster those speeches based on their topics. Here K-means method is used again. The purpose of this step is to see whether speeches made during the same type of event can be clustered together, which may indicate a homogeneity in their topics. In order to obtain better results, the clustering was performed under two circumstances: across all three types of historic events and only across economic expansion and recession.
presid.summary=tbl_df(corpus.list.df)%>%
mutate(President.term = paste0(President, " term " ,Term)) %>%
select(President.term, American:Legislation) %>%
group_by(President.term)%>%
summarise_each(funs(mean)) %>%
ungroup() %>%
left_join(presidents, by = "President.term") %>%
select(President.event, American:Legislation)
# Cluster on all three events: Expansions, recessions, and wars
presid.summary=as.data.frame(presid.summary)
rownames(presid.summary)=as.character((presid.summary[,1]))
km.res=kmeans(scale(presid.summary[,-1]), iter.max=200, 3)
fviz_cluster(km.res,
stand=T, repel= TRUE,
data = presid.summary[,-1],
show.clust.cent=FALSE)

# Cluster on only expansions and recessions
km.res=kmeans(scale(presid.summary[-c(3,4,10),-1]), iter.max=200, 2)
fviz_cluster(km.res,
stand=T, repel= TRUE,
data = presid.summary[-c(3,4,10),-1],
show.clust.cent=FALSE)

Both cluster plots are informative. When clustering all 3 types of events, all speeches made during expansions are clustered together and most of the speech made during wars are clustered together. When clustering only on expansion and recession, there is only one mistake.
This means that the topics covered in the speeches made during economic expansions, recessions and wars are different from each other.
Conclusion
Regardless of the types of events, the most expressed emotion in all speeches is “trust”. During economic expansion periods, there are a lot more “joy” and “surprise” and less “fear” and “anger”expressed in the inaugural speeches overal, compared to recession and war periods.
From the emotion cluster plots, we may conclude that the national economic status can have an influence on the emotions expressed in the inaugural speeches. Emotions expressed in speeches made during economic expansions and economic recessions are different.
Presidents tend to talk about different topics in different historical backgrounds. For example, during economic expansion, they like to talk about “freedom”, “family”, “national security” and etc. During recessions, they like to talk about “jobs”, “reforms” (topic 5) and etc to show their future plans to revitalize economy. During wars, they like to talk about “cohesion”, “responsibility” and etc. to encourage the nation to stick together.
Topic clustering plots also give the same conclusion. All speeches made during expansions are clustered together and most of the speech made during wars are clustered together. This indicates that types of events during which the speeches are made potentially can determine what topics the presidents are going to talk about in their inaugural speeches.
LS0tCnRpdGxlOiAiRWNvbm9taWMgZXhwYW5zaW9ucywgcmVjZXNzaW9ucyBhbmQgd2FycyAtLSBob3cgdGhlc2UgaGlzdG9yaWMgZXZlbnRzIGNhbiBhZmZlY3QgcHJlc2lkZW50cycgaW5hdWd1cmFsIHNwZWVjaGVzIgphdXRob3I6ICJaaXl1IENoZW4iCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KJm5ic3A7ICAKCkhpc3RvcmljIGV2ZW50cyBoYXZlIHByb2ZvdW5kIGltcGFjdHMgb24gdG9kYXkncyB3b3JsZCBwb2xpdGljcywgaW5jbHVkaW5nIFVTIHBvbGl0aWNzLiBXb3JsZCBXYXIgSSBkZWNpbWF0ZWQgRXVyb3BlIGFuZCBjb250cmlidXRlZCB0byB0aGUgcmlzZSBvZiB0aGUgVW5pdGVkIFN0YXRlcy4gVGhlIEdyZWF0IERlcHJlc3Npb24gY3JpcGxlZCBHZXJtYW55J3MgZWNvbm9teSBhbmQgdGh1cyBsZWQgTmF6aSB0byBjb21lIHRvIGl0cyBwb3dlciB3aGljaCBpbiB0dXJuIGxlZCB0byBXb3JsZCBXYXIgSUkuIFdXSUkgc2hhcGVkIHRvZGF5J3Mgd29ybGQgdmFzdGx5IGFuZCB0aGUgR3JlYXQgUmVjZXNzaW9uIGdhdmUgcmlzZSB0byBhIG5ldyBzZXR1cCBvZiB0aGUgd29ybGQgd2hpY2ggaXMgc3RpbGwgb25nb2luZy4gIAoKVGhpcyBwcm9qZWN0IGFpbXMgYXQgZGlzY29ydmVyaW5nIGhvdyB0aGVzZSBoaXN0b3JpYyBldmVudHMgY2FuIGFmZmVjdCBwcmVzaWRlbnRzJyBpbmF1Z3VyYWwgc3BlZWNoZXMgbWFkZSBkdXJpbmcgdGhvc2UgZXZlbnRzLiBJbiB0aGlzIHByb2plY3QsIEkgZm9jdXMgb24gdGhyZWUgdHlwZXMgb2YgaGlzdG9yaWMgZXZlbnRzIGluIG1vZGVybiBoaXN0b3J5IC0tIHdhcnMsIG1ham9yIGVjb25vbWljIHJlY2Vzc2lvbnMgYW5kIGVjb25vbWljIGV4cGFuc2lvbnMuIFNwZWNpZmljYWxseSwgdGhvc2UgZXZlbnRzIGluY2x1ZGUgV29ybGQgV2FyIEksIFdvcmxkIFdhciBJSSwgdGhlIEdyZWF0IERlcHJlc3Npb24sIHRoZSBHcmVhdCBSZWNlc3Npb24sIHRoZSBsb25nZXN0IGFuZCB0aGUgc2Vjb25kIGxvbmdlc3QgZWNvbm9taWMgZXhwYW5zaW9ucyBpbiBVUyBoaXN0b3J5LiAgCgoKIyMgU3RlcCAwIC0gSW5zdGFsbCBhbmQgbG9hZCBsaWJyYXJpZXMKYGBge3J9CnBhY2thZ2VzLnVzZWQ9YygicnZlc3QiLCAidGliYmxlIiwgInFkYXAiLCAiZ2dwbG90MiIsCiAgICAgICAgICAgICAgICAic2VudGltZW50ciIsICJncGxvdHMiLCAiZHBseXIiLCAidGlkeXRleHQiLAogICAgICAgICAgICAgICAgInRtIiwgInN5dXpoZXQiLCAiZmFjdG9leHRyYSIsIAogICAgICAgICAgICAgICAgInNjYWxlcyIsICJSQ29sb3JCcmV3ZXIiLAogICAgICAgICAgICAgICAgIlJBTk4iLCAidG0iLCAidG9waWNtb2RlbHMiLCAibHVicmlkYXRlIikKCiMgY2hlY2sgcGFja2FnZXMgdGhhdCBuZWVkIHRvIGJlIGluc3RhbGxlZC4KcGFja2FnZXMubmVlZGVkPXNldGRpZmYocGFja2FnZXMudXNlZCwgCiAgICAgICAgICAgICAgICAgICAgICAgIGludGVyc2VjdChpbnN0YWxsZWQucGFja2FnZXMoKVssMV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFja2FnZXMudXNlZCkpCiMgaW5zdGFsbCBhZGRpdGlvbmFsIHBhY2thZ2VzCmlmKGxlbmd0aChwYWNrYWdlcy5uZWVkZWQpPjApewogIGluc3RhbGwucGFja2FnZXMocGFja2FnZXMubmVlZGVkLCBkZXBlbmRlbmNpZXMgPSBUUlVFKQp9CgojIGxvYWQgcGFja2FnZXMKbGlicmFyeSgicnZlc3QiKQpsaWJyYXJ5KCJ0aWJibGUiKQpsaWJyYXJ5KCJxZGFwIikKbGlicmFyeSgiZ2dwbG90MiIpCmxpYnJhcnkoInNlbnRpbWVudHIiKQpsaWJyYXJ5KCJncGxvdHMiKQpsaWJyYXJ5KCJkcGx5ciIpCmxpYnJhcnkoInRpZHl0ZXh0IikKbGlicmFyeSgidG0iKQpsaWJyYXJ5KCJzeXV6aGV0IikKbGlicmFyeSgiZmFjdG9leHRyYSIpCmxpYnJhcnkoInNjYWxlcyIpCmxpYnJhcnkoIlJDb2xvckJyZXdlciIpCmxpYnJhcnkoIlJBTk4iKQpsaWJyYXJ5KCJ0bSIpCmxpYnJhcnkoInRvcGljbW9kZWxzIikKbGlicmFyeSgibHVicmlkYXRlIikKCgojIFNldCB3b3JraW5nIGRpcmVjdGlyeQpzZXR3ZCgiL1VzZXJzL3phaWxjaGVuL0RvY3VtZW50cy9SV29ya3BsYWNlL0FEU19Qcm9qZWN0XzFfWml5dV9DaGVuIikKcGF0aCA8LSBnZXR3ZCgpCgojIFNvdXJjZSBmdW5jdGlvbnMKc291cmNlKHBhc3RlMChwYXRoLCIvbGliL3Bsb3RzdGFja2VkLlIiKSkKc291cmNlKHBhc3RlMChwYXRoLCIvbGliL3NwZWVjaEZ1bmNzLlIiKSkKYGBgCiAgCiAgICAKVGhpcyBub3RlYm9vayB3YXMgcHJlcGFyZWQgd2l0aCB0aGUgZm9sbG93aW5nIGVudmlyb25tZW50YWwgc2V0dGluZ3MuCmBgYHtyfQpwcmludChSLnZlcnNpb24pCmBgYAombmJzcDsgIAombmJzcDsgIAombmJzcDsgICAgCgojIyBTdGVwIDE6IERhdGEgaGFydmVzdCBhbmQgcmVhZCBpbiB0aGUgc3BlZWNoZXMKYGBge3J9CiMjIyBJbmF1Z3VhcmFsIHNwZWVjaGVzCm1haW4ucGFnZSA8LSByZWFkX2h0bWwoeCA9ICJodHRwOi8vd3d3LnByZXNpZGVuY3kudWNzYi5lZHUvaW5hdWd1cmFscy5waHAiKQoKIyBHZXQgbGluayBVUkxzCmluYXVnPWYuc3BlZWNobGlua3MobWFpbi5wYWdlKQppbmF1Z1ssMV0gPC0gYXMuRGF0ZShpbmF1Z1ssMV0sIGZvcm1hdD0iJUIgJWUsICVZIikKaW5hdWc9aW5hdWdbLW5yb3coaW5hdWcpLF0gIyByZW1vdmUgdGhlIGxhc3QgbGluZSwgaXJyZWxldmFudCBkdWUgdG8gZXJyb3IuCgppbmF1Zy5saXN0PXJlYWQuY3N2KHBhc3RlMChwYXRoLCIvZGF0YS9pbmF1Z2xpc3QuY3N2IiksIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKaW5hdWcubGlzdCR0eXBlPWMocmVwKCJpbmF1ZyIsIG5yb3coaW5hdWcubGlzdCkpKQppbmF1Zy51cmw9aW5hdWcKc3BlZWNoLmxpc3Q9Y2JpbmQoaW5hdWcubGlzdCwgaW5hdWcudXJsKQpzcGVlY2gubGlzdCA9IHNwZWVjaC5saXN0WyAsLSB3aGljaChjb2xuYW1lcyhzcGVlY2gubGlzdCkgPT0gIkRhdGUiKV0KY29sbmFtZXMoc3BlZWNoLmxpc3QpWzhdIDwtICJEYXRlIgoKCiMgTG9vcCBvdmVyIGVhY2ggcm93IGluIHNwZWVjaC5saXN0CnNwZWVjaC5saXN0JGZ1bGx0ZXh0PU5BCmZvcihpIGluIHNlcShucm93KHNwZWVjaC5saXN0KSkpIHsKICB0ZXh0IDwtIHJlYWRfaHRtbChzcGVlY2gubGlzdCR1cmxzW2ldKSAlPiUgIyBsb2FkIHRoZSBwYWdlCiAgICBodG1sX25vZGVzKCIuZGlzcGxheXRleHQiKSAlPiUgIyBpc2xvYXRlIHRoZSB0ZXh0CiAgICBodG1sX3RleHQoKSAjIGdldCB0aGUgdGV4dAogIHNwZWVjaC5saXN0JGZ1bGx0ZXh0W2ldPXRleHQKICAjIENyZWF0ZSB0aGUgZmlsZSBuYW1lCiAgZmlsZW5hbWUgPC0gcGFzdGUwKHBhdGgsIi9kYXRhL2Z1bGx0ZXh0LyIsIAogICAgICAgICAgICAgICAgICAgICBzcGVlY2gubGlzdCR0eXBlW2ldLAogICAgICAgICAgICAgICAgICAgICBzcGVlY2gubGlzdCRGaWxlW2ldLCAiLSIsIAogICAgICAgICAgICAgICAgICAgICBzcGVlY2gubGlzdCRUZXJtW2ldLCAiLnR4dCIpCiAgc2luayhmaWxlID0gZmlsZW5hbWUpICU+JSAjIG9wZW4gZmlsZSB0byB3cml0ZSAKICBjYXQodGV4dCkgICMgd3JpdGUgdGhlIGZpbGUKICBzaW5rKCkgIyBjbG9zZSB0aGUgZmlsZQp9CmBgYAogIAombmJzcDsgIAombmJzcDsgIAombmJzcDsgIAoKIyMgU3RlcCAyOiBEYXRhIFByb2Nlc3NpbmcgLS0tIGdlbmVyYXRlIGxpc3Qgb2Ygc2VudGVuY2VzCmBgYHtyLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0Kc2VudGVuY2UubGlzdD1OVUxMCmZvcihpIGluIDE6bnJvdyhzcGVlY2gubGlzdCkpewogIHNlbnRlbmNlcz1zZW50X2RldGVjdChzcGVlY2gubGlzdCRmdWxsdGV4dFtpXSwKICAgICAgICAgICAgICAgICAgICAgICAgZW5kbWFya3MgPSBjKCI/IiwgIi4iLCAiISIsICJ8IiwiOyIpKQogIGlmKGxlbmd0aChzZW50ZW5jZXMpPjApewogICAgZW1vdGlvbnM9Z2V0X25yY19zZW50aW1lbnQoc2VudGVuY2VzKQogICAgd29yZC5jb3VudD13b3JkX2NvdW50KHNlbnRlbmNlcykKICAgICMgY29sbmFtZXMoZW1vdGlvbnMpPXBhc3RlMCgiZW1vLiIsIGNvbG5hbWVzKGVtb3Rpb25zKSkKICAgICMgaW4gY2FzZSB0aGUgd29yZCBjb3VudHMgYXJlIHplcm9zPwogICAgZW1vdGlvbnM9ZGlhZygxLyh3b3JkLmNvdW50KzAuMDEpKSUqJWFzLm1hdHJpeChlbW90aW9ucykKICAgIHNlbnRlbmNlLmxpc3Q9cmJpbmQoc2VudGVuY2UubGlzdCwgCiAgICAgICAgICAgICAgICAgICAgICAgIGNiaW5kKHNwZWVjaC5saXN0W2ksLW5jb2woc3BlZWNoLmxpc3QpXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VudGVuY2VzPWFzLmNoYXJhY3RlcihzZW50ZW5jZXMpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd29yZC5jb3VudCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW1vdGlvbnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbnQuaWQ9MTpsZW5ndGgoc2VudGVuY2VzKSkpCiAgIH0KfQoKc2VudGVuY2UubGlzdCA9IHNlbnRlbmNlLmxpc3QgJT4lIGZpbHRlcighaXMubmEod29yZC5jb3VudCkpIApgYGAKICAKJm5ic3A7ICAKJm5ic3A7ICAKJm5ic3A7ICAgCgojIyBTdGVwIDM6IElkZW50aWZ5IGluYXVndXJhbCBzcGVlY2hlcyB0aGF0IGFyZSBtYWRlIGR1cmluZyB0aG9zZSBoaXN0b3JpYyBldmVudHMKIyMjIFRoZXJlIGFyZSBhbHRvZ2V0aGVyIDEwIG9mIHRob3NlIHNwZWVjaGVzLgpgYGB7cn0KIyBQcmVzaWRlbnQocykgd2hvIGFzc3VtZWQgdGhlIG9mZmljZSBkdXJpbmcgdGhlIGxvbmdlc3QgcGVyaW9kIG9mIGVjb25vbWljIGV4cGFuc2lvbiBpbiBVUyBoaXN0b3J5LgpwcmVzaS5leHBhbjEgPC0gc3BlZWNoLmxpc3QgJT4lCiAgZmlsdGVyKERhdGUgJXdpdGhpbiUgaW50ZXJ2YWwoIjE5OTEtMDMtMDEiLCAiMjAwMS0wMy0zMCIpKSAlPiUKICBzZWxlY3QoUHJlc2lkZW50LCBGaWxlLCBUZXJtKSAlPiUKICBtdXRhdGUoRXZlbnQgPSAiRXhwYW5zaW9uIikKCiMgUHJlc2lkZW50KHMpIHdobyBhc3N1bWVkIHRoZSBvZmZpY2UgZHVyaW5nIHRoZSBzZWNvbmQgbG9uZ2VzdCBwZXJpb2Qgb2YgZWNvbm9taWMgZXhwYW5zaW9uLgpwcmVzaS5leHBhbjIgPC0gc3BlZWNoLmxpc3QgJT4lCiAgZmlsdGVyKERhdGUgJXdpdGhpbiUgaW50ZXJ2YWwoIjE5ODItMTItMDEiLCAiMTk5MC0wNy0zMCIpKSAlPiUKICBzZWxlY3QoUHJlc2lkZW50LCBGaWxlLCBUZXJtKSAlPiUKICBtdXRhdGUoRXZlbnQgPSAiRXhwYW5zaW9uIikKCiMgUHJlc2lkZW50KHMpIHdobyBhc3N1bWVkIHRoZSBvZmZpY2UgZHVyaW5nIHRoZSBHcmVhdCBEZXByZXNzaW9uIDE5MjkgLSAxOTMzLgpwcmVzaS5yZWNlMSA8LSBzcGVlY2gubGlzdCAlPiUKICBmaWx0ZXIoRGF0ZSAld2l0aGluJSBpbnRlcnZhbCgiMTkyOS0wOC0wMSIsICIxOTMzLTAzLTMwIikpICU+JQogIHNlbGVjdChQcmVzaWRlbnQsIEZpbGUsIFRlcm0pICU+JQogIG11dGF0ZShFdmVudCA9ICJSZWNlc3Npb24iKQoKIyBQcmVzaWRlbnQocykgd2hvIGFzc3VtZWQgdGhlIG9mZmljZSBkdXJpbmcgdGhlIEdyZWF0IFJlY2Vzc2lvbiAyMDA3IC0gMjAwOS4KcHJlc2kucmVjZTIgPC0gc3BlZWNoLmxpc3QgJT4lCiAgZmlsdGVyKERhdGUgJXdpdGhpbiUgaW50ZXJ2YWwoIjIwMDctMTItMDEiLCAiMjAwOS0wNi0zMCIpKSAlPiUKICBzZWxlY3QoUHJlc2lkZW50LCBGaWxlLCBUZXJtKSAlPiUKICBtdXRhdGUoRXZlbnQgPSAiUmVjZXNzaW9uIikKCiMgUHJlc2lkZW50KHMpIHdobyBhc3N1bWVkIHRoZSBvZmZpY2UgZHVyaW5nIFdXSS4KcHJlc2kud2FyMSA8LSBzcGVlY2gubGlzdCAlPiUKICBmaWx0ZXIoRGF0ZSAld2l0aGluJSBpbnRlcnZhbCgiMTkxNC0wNy0yOCIsICIxOTE4LTExLTExIikpICU+JQogIHNlbGVjdChQcmVzaWRlbnQsIEZpbGUsIFRlcm0pICU+JQogIG11dGF0ZShFdmVudCA9ICJXYXIiKQoKIyBQcmVzaWRlbnQocykgd2hvIGFzc3VtZWQgdGhlIG9mZmljZSBkdXJpbmcgV1dJSS4KcHJlc2kud2FyMiA8LSBzcGVlY2gubGlzdCAlPiUKICBmaWx0ZXIoRGF0ZSAld2l0aGluJSBpbnRlcnZhbCgiMTkzOS0wOS0wMSIsICIxOTQ1LTA5LTAyIikpICU+JQogIHNlbGVjdChQcmVzaWRlbnQsIEZpbGUsIFRlcm0pICU+JQogIG11dGF0ZShFdmVudCA9ICJXYXIiKQpgYGAKICAKJm5ic3A7ICAKJm5ic3A7ICAKJm5ic3A7ICAKCgojIyBTdGVwIDQ6IFNlbnRpbWVudCBhbmFseXNpczogQ2x1c3RlcmluZyBvZiBlbW90aW9ucyAgCkZvciBlYWNoIHNlbnRlbmNlIHdlIHdpbGwgYXBwbHkgc2VudGltZW50IGFuYWx5c2lzIHVzaW5nIE5SQyBzZW50aW1lbnQgbGV4aW9uLiBFaWdodCBlbW90aW9ucyB3aWxsIGJlIGRpc3BsYXllZDogdHJ1c3QsIHN1cnByaXNlLCBzYWRuZWVzcywgam95IGZlYXQsIGRpc2d1c3QsIGFudGljaXBhdGlvbiBhbmQgYW5nZXIuIFRob3NlIGVtb3Rpb25zIGFyZSBtYXBwZWQgd2l0aCBzcGVjaWZpYyB3b3JkcyB3aGljaCBjYW4gYmUgZm91bmQgaW4gTlJDIHNlbnRpbWVudCBsZXhpb24uIFRoZSBnb2FsIG9mIHRoaXMgc2VjdGlvbiBpcyB0byBkZXRlcm1pbiB3aGV0aGVyIHRoZSBlbW90aW9ucyBleHByZXNzZWQgZnJvbSBzcGVlY2hlcyBtYWRlIGR1cmluZyB0aG9zZSBkaXN0aW5jdCBoaXN0b3JpYyBldmVudHMgZGlmZmVyIGZyb20gZWFjaCBvdGhlci4KYGBge3IsIGZpZy53aWR0aD00LjUsIGZpZy5oZWlnaHQ9Mn0KY29sLnVzZT1jKCJyZWQyIiwgImRhcmtnb2xkZW5yb2QxIiwgCiAgICAgICAgICAgICJjaGFydHJldXNlMyIsICJibHVldmlvbGV0IiwKICAgICAgICAgICAgImRhcmtnb2xkZW5yb2QyIiwgImRvZGdlcmJsdWUzIiwgCiAgICAgICAgICAgICJkYXJrZ29sZGVucm9kMSIsICJkYXJrZ29sZGVucm9kMSIpCgpwYXIobWZyb3c9YygxLDIpLG1hcj1jKDQsIDYsIDIsIDEpKQojIEVtb3Rpb24gY2x1c3RlcmluZyBvZiBpbmF1Z3VyYWwgc3BlZWNoZXMgbWFkZSBkdXJpbmcgdGhlIGxvbmdlc3QgZWNvbm9taWMgZXhwYW5zaW9uIGluIGhpc3RvcnkuCmVtby5tZWFucz1jb2xNZWFucygoc2VudGVuY2UubGlzdCAlPiUgCiAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihQcmVzaWRlbnQgJWluJSBwcmVzaS5leHBhbjFbICwiUHJlc2lkZW50Il0pICU+JQogICAgICAgICAgICAgICAgICAgICBzZWxlY3QoYW5nZXI6dHJ1c3QpKT4wLjAxKQpiYXJwbG90KGVtby5tZWFuc1tvcmRlcihlbW8ubWVhbnMpXSwgbGFzPTIsIGNvbD1jb2wudXNlW29yZGVyKGVtby5tZWFucyldLCBob3Jpej1ULCBtYWluPSJUaGUgbG9uZ2VzdCBlY29ub21pYyBleHBhbnNpb24iKQoKIyBEdXJpbmcgdGhlIHNlY29uZCBsb25nZXN0IGVjb25vbWljIGV4cGFuc2lvbi4KZW1vLm1lYW5zPWNvbE1lYW5zKChzZW50ZW5jZS5saXN0ICU+JSAKICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKFByZXNpZGVudCAlaW4lIHByZXNpLmV4cGFuMlsgLCJQcmVzaWRlbnQiXSkgJT4lCiAgICAgICAgICAgICAgICAgICAgIHNlbGVjdChhbmdlcjp0cnVzdCkpPjAuMDEpCmJhcnBsb3QoZW1vLm1lYW5zW29yZGVyKGVtby5tZWFucyldLCBsYXM9MiwgY29sPWNvbC51c2Vbb3JkZXIoZW1vLm1lYW5zKV0sIGhvcml6PVQsIG1haW49IlRoZSAycmQgbG9uZ2VzdCBlY29ub21pYyBleHBhbnNpb24iKQoKIyBEdXJpbmcgdGhlIEdyZWF0IERlcHJlc3Npb24gMTkyOSAtIDE5MzMuCmVtby5tZWFucz1jb2xNZWFucygoc2VudGVuY2UubGlzdCAlPiUgCiAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihQcmVzaWRlbnQgJWluJSBwcmVzaS5yZWNlMVsgLCJQcmVzaWRlbnQiXSkgJT4lCiAgICAgICAgICAgICAgICAgICAgIHNlbGVjdChhbmdlcjp0cnVzdCkpPjAuMDEpCmJhcnBsb3QoZW1vLm1lYW5zW29yZGVyKGVtby5tZWFucyldLCBsYXM9MiwgY29sPWNvbC51c2Vbb3JkZXIoZW1vLm1lYW5zKV0sIGhvcml6PVQsIG1haW49IlRoZSBHcmVhdCBEZXByZXNzaW9uIikKCiMgRHVyaW5nIHRoZSBHcmVhdCBSZWNlc3Npb24gMjAwNyAtIDIwMDkuCmVtby5tZWFucz1jb2xNZWFucygoc2VudGVuY2UubGlzdCAlPiUgCiAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihQcmVzaWRlbnQgJWluJSBwcmVzaS5yZWNlMlsgLCJQcmVzaWRlbnQiXSkgJT4lCiAgICAgICAgICAgICAgICAgICAgIHNlbGVjdChhbmdlcjp0cnVzdCkpPjAuMDEpCmJhcnBsb3QoZW1vLm1lYW5zW29yZGVyKGVtby5tZWFucyldLCBsYXM9MiwgY29sPWNvbC51c2Vbb3JkZXIoZW1vLm1lYW5zKV0sIGhvcml6PVQsIG1haW49IlRoZSBHcmVhdCBSZWNlc3Npb24iKQoKIyBEdXJpbmcgdGhlIFdvcmxkIFdhciBJCmVtby5tZWFucz1jb2xNZWFucygoc2VudGVuY2UubGlzdCAlPiUgCiAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihQcmVzaWRlbnQgJWluJSBwcmVzaS53YXIxWyAsIlByZXNpZGVudCJdKSAlPiUKICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KGFuZ2VyOnRydXN0KSk+MC4wMSkKYmFycGxvdChlbW8ubWVhbnNbb3JkZXIoZW1vLm1lYW5zKV0sIGxhcz0yLCBjb2w9Y29sLnVzZVtvcmRlcihlbW8ubWVhbnMpXSwgaG9yaXo9VCwgbWFpbj0iV1dJIikKCiMgRHVyaW5nIHRoZSBXb3JsZCBXYXIgSUkKZW1vLm1lYW5zPWNvbE1lYW5zKChzZW50ZW5jZS5saXN0ICU+JSAKICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKFByZXNpZGVudCAlaW4lIHByZXNpLndhcjJbICwiUHJlc2lkZW50Il0pICU+JQogICAgICAgICAgICAgICAgICAgICBzZWxlY3QoYW5nZXI6dHJ1c3QpKT4wLjAxKQpiYXJwbG90KGVtby5tZWFuc1tvcmRlcihlbW8ubWVhbnMpXSwgbGFzPTIsIGNvbD1jb2wudXNlW29yZGVyKGVtby5tZWFucyldLCBob3Jpej1ULCBtYWluPSJXV0lJIikKCmBgYApGcm9tIHRoZSBiYXJwbG90cyBhYm92ZSwgd2UgY2FuIGVhc2lseSB0ZWxsIHRoYXQgdGhlIHJlbGF0aXZlIGltcG9ydGFuY2Ugb2YgZGlmZmVyZW50IGVtb3Rpb25zIGFjcm9zcyBhbGwgMTAgc3BlZWNoZXMgaXMgcXVpdGUgY29uc2lzdGVudC4gIlRydXN0IiB3YXMgc2lnbmlmaWNhbnRseSBleHByZXNzZWQgbW9yZSB0aGFuIGFueSBvdGhlciBlbW90aW9ucy4gRHVyaW5nIHRob3NlIG1ham9yIGVjb25vbWljIGV4cGFuc2lvbiBwZXJpb2RzLCB3ZSBzZWUgYSBsb3QgbW9yZSAiam95IiBhbmQgInN1cnByaXNlIiBhbmQgbGVzcyAiZmVhciIgYW5kICJhbmdlciIgb3ZlcmFsIGNvbXBhcmVkIHRvIHJlY2Vzc2lvbiBhbmQgd2FyIHBlcmlvZHMsIHdoaWNoIGlzIHF1aXRlIHJlYXNvbmFibGUuICAKCiZuYnNwOyAgCiZuYnNwOyAgCiZuYnNwOyAgCgojIyBTdGVwIDU6IENsdXN0ZXIgc3BlZWNoZXMgYmFzZWQgb24gdGhlIGVtb3Rpb24gc2NvcmVzICAKSGVyZSB3ZSB1c2UgSy1tZWFucyBtZXRob2QgdG8gY2x1c3RlciBzcGVlY2hlcyBiYXNlZCBvbiB0aGVpciBlbW90aW9uIHNjb3Jlcy4gVGhlIG9iamVjdCBvZiB0aGlzIHN0ZXAgaXMgdG8gc2VlIHdoZXRoZXIgc3BlZWNoZXMgbWFkZSBkdXJpbmcgdGhlIHNhbWUgdHlwZSBvZiBldmVudCBjYW4gYmUgY2x1c3RlcmVkIHRvZ2V0aGVyLCB3aGljaCBtYXkgaW5kaWNhdGUgYSBob21vZ2VuZWl0eSBpbiB0ZXJtcyBvZiB0aGUgZW1vdGlvbnMgdGhleSBleHByZXNzLiBJbiBvcmRlciB0byBvYnRhaW4gYmV0dGVyIHJlc3VsdHMsIHRoZSBjbHVzdGVyaW5nIHdhcyBwZXJmb3JtZWQgdW5kZXIgdHdvIGNpcmN1bXN0YW5jZXM6IGFjcm9zcyBhbGwgdGhyZWUgdHlwZXMgb2YgaGlzdG9yaWMgZXZlbnRzIGFuZCBvbmx5IGFjcm9zcyBlY29ub21pYyBleHBhbnNpb24gYW5kIHJlY2Vzc2lvbi4gCmBgYHtyfQpwcmVzaWRlbnRzIDwtIHJiaW5kKHByZXNpLmV4cGFuMSwgcHJlc2kuZXhwYW4yLCAKICAgICAgICAgICAgICAgICAgICBwcmVzaS5yZWNlMSwgcHJlc2kucmVjZTIsCiAgICAgICAgICAgICAgICAgICAgcHJlc2kud2FyMSwgcHJlc2kud2FyMikgJT4lCiAgICAgICAgICAgICAgbXV0YXRlKFByZXNpZGVudC50ZXJtID0gcGFzdGUwKFByZXNpZGVudCwgIiB0ZXJtICIgLFRlcm0pLAogICAgICAgICAgICAgICAgICAgICBQcmVzaWRlbnQuZXZlbnQgPSBwYXN0ZTAoUHJlc2lkZW50LCAiIHRlcm0iLFRlcm0sICIgIixFdmVudCkpIAogICAgICAgICAgICAKCnByZXNpZC5zdW1tYXJ5PXRibF9kZihzZW50ZW5jZS5saXN0KSAlPiUKICBtdXRhdGUoUHJlc2lkZW50LnRlcm0gPSBwYXN0ZTAoUHJlc2lkZW50LCAiIHRlcm0gIiAsVGVybSkpICU+JQogIGZpbHRlcihQcmVzaWRlbnQudGVybSAlaW4lIHByZXNpZGVudHMkUHJlc2lkZW50LnRlcm0pICU+JQogIGdyb3VwX2J5KFByZXNpZGVudC50ZXJtKSU+JQogIHN1bW1hcmlzZSgKICAgIGFuZ2VyPW1lYW4oYW5nZXIpLAogICAgYW50aWNpcGF0aW9uPW1lYW4oYW50aWNpcGF0aW9uKSwKICAgIGRpc2d1c3Q9bWVhbihkaXNndXN0KSwKICAgIGZlYXI9bWVhbihmZWFyKSwKICAgIGpveT1tZWFuKGpveSksCiAgICBzYWRuZXNzPW1lYW4oc2FkbmVzcyksCiAgICBzdXJwcmlzZT1tZWFuKHN1cnByaXNlKSwKICAgIHRydXN0PW1lYW4odHJ1c3QpKSAlPiUKICAgIGxlZnRfam9pbihwcmVzaWRlbnRzLCBieSA9ICJQcmVzaWRlbnQudGVybSIpICU+JQogICAgc2VsZWN0KGFuZ2VyOnRydXN0LCBQcmVzaWRlbnQuZXZlbnQpCiAgICAKCnByZXNpZC5zdW1tYXJ5PWFzLmRhdGEuZnJhbWUocHJlc2lkLnN1bW1hcnkpCnJvd25hbWVzKHByZXNpZC5zdW1tYXJ5KT1hcy5jaGFyYWN0ZXIoKHByZXNpZC5zdW1tYXJ5JFByZXNpZGVudC5ldmVudCkpCnIgPSB3aGljaChjb2xuYW1lcyhwcmVzaWQuc3VtbWFyeSk9PSJQcmVzaWRlbnQuZXZlbnQiKQoKIyBDbHVzdGVyIHVuZGVyIGFsbCB0aHJlZSB0eXBlcyBvZiBldmVudHM6IEV4cGFuc2lvbiwgcmVjZXNzaW9uLCBhbmQgd2FyCmttLnJlcz1rbWVhbnMocHJlc2lkLnN1bW1hcnlbLC1yXSwgaXRlci5tYXg9MjAwLCAzKQpmdml6X2NsdXN0ZXIoa20ucmVzLCBzdGFuZD1GLCByZXBlbD0gVFJVRSwKICAgICAgICAgICAgIGRhdGEgPSBwcmVzaWQuc3VtbWFyeVssLXJdLCB4bGFiPSIiLCB4YXh0PSJuIiwKICAgICAgICAgICAgIHNob3cuY2x1c3QuY2VudD1GQUxTRSkKCiMgQ2x1c3RlciBvbmx5IHVuZGVyIGVjb25vbWljIGV4cGFuc2lvbiBhbmQgcmVjZXNzaW9uCmttLnJlcz1rbWVhbnMocHJlc2lkLnN1bW1hcnlbLWMoMywgNCwgMTApLCAtcl0sIGl0ZXIubWF4PTIwMCwgMikKZnZpel9jbHVzdGVyKGttLnJlcywgc3RhbmQ9RiwgcmVwZWw9IFRSVUUsCiAgICAgICAgICAgICBkYXRhID0gcHJlc2lkLnN1bW1hcnlbLWMoMywgNCwgMTApLCAtcl0sIHhsYWI9IiIsIHhheHQ9Im4iLAogICAgICAgICAgICAgc2hvdy5jbHVzdC5jZW50PUZBTFNFKQpgYGAKVGhlIHJlc3VsdCBvYnRhaW5lZCBmcm9tIHVzaW5nIGsgPSAzIGFuZCBhbGwgdGhyZWUgdHlwZXMgb2YgZXZlbnRzIGlzIG5vdCBpbmZvcm1hdGl2ZS4gT2J2aW91c2x5IHNwZWVjaGVzIGFyZSBjbHVzdGVyZWQgdG9nZXRoZXIgbm90IGFjY29yZGluZyB0byB0aGUgdHlwZSBvZiBldmVudCBkdXJpbmcgd2hpY2ggdGhleSB3ZXJlIG1hZGUuICAKSG93ZXZlciwgd2hlbiB1c2luZyBrID0gMiBhbmQgb25seSBleHBhbnNpb25zIGFuZCByZWNlc3Npb25zLCB0aGUgcmVzdWx0IHNlZW1zIHF1aXRlIHByb21pc2luZy4gQWxsIHNwZWVjaGVzIG1hZGUgZHVyaW5nIHJlY2Vzc2lvbnMgYXJlIGNsdXN0ZXJlZCB0b2dldGhlciBhbmQgbW9zdCBvZiBzcGVlY2hlcyBtYWRlIGR1cmluZyBleHBhbnNpb25zIGFyZSBjbHVzdGVyZWQgdG9nZXRoZXIuICAKCiZuYnNwOyAgCiZuYnNwOyAgCiZuYnNwOyAgCgojIyBTdGVwIDY6IFRvcGljIG1vZGVsaW5nCk5leHQgd2Ugd291bGQgbGlrZSB0byBhbmFseXplIHRob3NlIHNwZWVjaGVzIGJhc2VkIG9uIHRoZSBkaWZmZXJlbmNlcyBpbiB0aGVpciB0b3BpY3MuIEhlcmUgd2UgdXNlIHRvcGljIG1vZGVsaW5nLiBUaGUgZ29hbCBpcyB0byBkZXRlcm1pbmUgaWYgdGhlIHNwZWVjaGVzIG1hZGUgZHVyaW5nIHRoZSBzYW1lIHR5cGUgb2YgZXZlbnQgYXJlIHNpbWlsYXIgaW4gdGhlaXIgdG9waWNzLgpgYGB7cn0Kc2VudGVuY2UubGlzdC5wcmVzaSA8LSB0YmxfZGYoc2VudGVuY2UubGlzdCkgJT4lCiAgbXV0YXRlKFByZXNpZGVudC50ZXJtID0gcGFzdGUwKFByZXNpZGVudCwgIiB0ZXJtICIgLFRlcm0pKSAlPiUKICBmaWx0ZXIoUHJlc2lkZW50LnRlcm0gJWluJSBwcmVzaWRlbnRzJFByZXNpZGVudC50ZXJtKSAlPiUgCiAgbGVmdF9qb2luKHByZXNpZGVudHMsIGJ5ID0gYygiUHJlc2lkZW50IiwgIkZpbGUiLCAiVGVybSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUHJlc2lkZW50LnRlcm0iKSkKYGBgCiAgCiZuYnNwOyAgCgojIyMjIEJ1aWxkIG15IG93biBMREEgZnVuY3Rpb24gIApUbyBhdm9pZCBydW5uaW5nIHRob3NlIGV4dHJlbWVseSBsb25nIExEQSBjb2RlcyByZXBlYXRlZGx5LCBJIGNyZWF0ZWQgbXkgb3duIExEQSBmdW5jdGlvbiBhbmQgd3JpdGUuZmlsZSBmdW5jdGlvbi4gIApgYGB7cn0KTERBX091dCA8LSBmdW5jdGlvbihldmVudCA9IE5VTEwsIGRmID0gc2VudGVuY2UubGlzdC5wcmVzaSwgYnVybmluID0gNDAwMCwKICAgICAgICAgICAgICAgICAgICAgaXRlciA9IDIwMDAsIHRoaW4gPSA1MDAsIHNlZWQgPWxpc3QoMjAwMyw1LDYzLDEwMDAwMSw3NjUpLAogICAgICAgICAgICAgICAgICAgICBuc3RhcnQgPSA1LCBiZXN0ID0gVFJVRSwgayA9IDEwKSB7CiAgaWYgKCFpcy5udWxsKGV2ZW50KSkgeyBkZiA8LSBkZiAlPiUgZmlsdGVyKHRvbG93ZXIoRXZlbnQpID09IHRvbG93ZXIoZXZlbnQpKSB9CgogIGNvcnB1cy5saXN0PWRmWzI6KG5yb3coZGYpLTEpLCBdCiAgc2VudGVuY2UucHJlPWRmJHNlbnRlbmNlc1sxOihucm93KGRmKS0yKV0KICBzZW50ZW5jZS5wb3N0PWRmJHNlbnRlbmNlc1szOihucm93KGRmKS0xKV0KICBjb3JwdXMubGlzdCRzbmlwZXRzPXBhc3RlKHNlbnRlbmNlLnByZSwgY29ycHVzLmxpc3Qkc2VudGVuY2VzLCBzZW50ZW5jZS5wb3N0LCBzZXA9IiAiKQogIHJtLnJvd3M9KDE6bnJvdyhjb3JwdXMubGlzdCkpW2NvcnB1cy5saXN0JHNlbnQuaWQ9PTFdCiAgcm0ucm93cz1jKHJtLnJvd3MsIHJtLnJvd3MtMSkKICBjb3JwdXMubGlzdD1jb3JwdXMubGlzdFstcm0ucm93cywgXQoKCiAgIyMgVGV4dCBtaW5pbmcKICBkb2NzIDwtIENvcnB1cyhWZWN0b3JTb3VyY2UoY29ycHVzLmxpc3Qkc25pcGV0cykpCiAgI3dyaXRlTGluZXMoYXMuY2hhcmFjdGVyKGRvY3NbW3NhbXBsZSgxOm5yb3coY29ycHVzLmxpc3QpLCAxKV1dKSkKCiAgIyMjIFRleHQgYmFzaWMgcHJvY2Vzc2luZwogICNyZW1vdmUgcG90ZW50aWFsbHkgcHJvYmxlbWF0aWMgc3ltYm9scwogIGRvY3MgPC10bV9tYXAoZG9jcyxjb250ZW50X3RyYW5zZm9ybWVyKHRvbG93ZXIpKQoKICAjcmVtb3ZlIHB1bmN0dWF0aW9uCiAgZG9jcyA8LSB0bV9tYXAoZG9jcywgcmVtb3ZlUHVuY3R1YXRpb24pCgogICNTdHJpcCBkaWdpdHMKICBkb2NzIDwtIHRtX21hcChkb2NzLCByZW1vdmVOdW1iZXJzKQoKICAjcmVtb3ZlIHN0b3B3b3JkcwogIGRvY3MgPC0gdG1fbWFwKGRvY3MsIHJlbW92ZVdvcmRzLCBzdG9wd29yZHMoImVuZ2xpc2giKSkKCiAgI3JlbW92ZSB3aGl0ZXNwYWNlCiAgZG9jcyA8LSB0bV9tYXAoZG9jcywgc3RyaXBXaGl0ZXNwYWNlKQoKICAjU3RlbSBkb2N1bWVudAogIGRvY3MgPC0gdG1fbWFwKGRvY3Msc3RlbURvY3VtZW50KQoKCiAgIyMgVG9waWMgbW9kZWxpbmcKICAjIyNHZW5nZXJhdGUgZG9jdW1lbnQtdGVybSBtYXRyaWNlcy4gCgoKICBkdG0gPC0gRG9jdW1lbnRUZXJtTWF0cml4KGRvY3MpCiAgI2NvbnZlcnQgcm93bmFtZXMgdG8gZmlsZW5hbWVzI2NvbnZlcnQgcm93bmFtZXMgdG8gZmlsZW5hbWVzCiAgcm93bmFtZXMoZHRtKSA8LSBwYXN0ZShjb3JwdXMubGlzdCR0eXBlLCBjb3JwdXMubGlzdCRGaWxlLAogICAgICAgICAgICAgICAgICAgICAgICAgY29ycHVzLmxpc3QkVGVybSwgY29ycHVzLmxpc3Qkc2VudC5pZCwgc2VwPSJfIikKCiAgcm93VG90YWxzIDwtIGFwcGx5KGR0bSAsIDEsIHN1bSkgI0ZpbmQgdGhlIHN1bSBvZiB3b3JkcyBpbiBlYWNoIERvY3VtZW50CgogIGR0bSAgPC0gZHRtW3Jvd1RvdGFscz4gMCwgXQogIGNvcnB1cy5saXN0PWNvcnB1cy5saXN0W3Jvd1RvdGFscz4wLCBdCgogICNSdW4gTERBIHVzaW5nIEdpYmJzIHNhbXBsaW5nCiAgbGRhT3V0IDwtTERBKGR0bSwgaywgbWV0aG9kPSJHaWJicyIsIGNvbnRyb2w9bGlzdChuc3RhcnQ9bnN0YXJ0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlZWQgPSBzZWVkLCBiZXN0PWJlc3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBidXJuaW4gPSBidXJuaW4sIGl0ZXIgPSBpdGVyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaW49dGhpbikpCiAgcmV0dXJuKGxkYU91dCkKfQpgYGAKICAKJm5ic3A7ICAKJm5ic3A7ICAKJm5ic3A7ICAKICAKIyMjIyBCdWlsZCBmdW5jdGlvbiB0byB3cml0ZSBMREEgZmlsZXMKYGBge3J9CndyaXRlX2xkYV9maWxlcyA8LSBmdW5jdGlvbihldmVudCA9IE5VTEwsIFBhdGggPSBwYXRoKSB7CiAgCiAgbGRhT3V0IDwtIExEQV9PdXQoZXZlbnQgPSBldmVudCkKCiAgI3dyaXRlIG91dCByZXN1bHRzCiAgI2RvY3MgdG8gdG9waWNzCiAgbGRhT3V0LnRvcGljcyA8LSBhcy5tYXRyaXgodG9waWNzKGxkYU91dCkpCiAgIyB0YWJsZShjKDE6aywgbGRhT3V0LnRvcGljcy5leHBhbikpCiAgd3JpdGUuY3N2KGxkYU91dC50b3BpY3MsIGZpbGU9cGFzdGUwKFBhdGgsIi9vdXRwdXQvTERBR2liYnMiLGssIkRvY3NUb1RvcGljcyIsIl8iLGV2ZW50LCIuY3N2IikpCgogICN0b3AgNiB0ZXJtcyBpbiBlYWNoIHRvcGljCiAgbGRhT3V0LnRlcm1zIDwtIGFzLm1hdHJpeCh0ZXJtcyhsZGFPdXQsMjApKQogIHdyaXRlLmNzdihsZGFPdXQudGVybXMsZmlsZT1wYXN0ZTAoUGF0aCwiL291dHB1dC9MREFHaWJicyIsaywiVG9waWNzVG9UZXJtcyIsIl8iLGV2ZW50LCIuY3N2IikpCgogICNwcm9iYWJpbGl0aWVzIGFzc29jaWF0ZWQgd2l0aCBlYWNoIHRvcGljIGFzc2lnbm1lbnQKICB0b3BpY1Byb2JhYmlsaXRpZXMgPC0gYXMuZGF0YS5mcmFtZShsZGFPdXRAZ2FtbWEpCiAgd3JpdGUuY3N2KHRvcGljUHJvYmFiaWxpdGllcyxmaWxlPXBhc3RlMChQYXRoLCIvb3V0cHV0L0xEQUdpYmJzIixrLCJUb3BpY1Byb2JhYmlsaXRpZXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJfIixldmVudCwiLmNzdiIpKQp9CmBgYAogIAombmJzcDsgIAoKIyMjI1J1biBMREEgYW5kIHdyaXRlIGZpbGVzICAKSW4gb3JkZXIgdG8gZGV0ZXJtaW5lIHRoZSBkaWZmZXJlbmNlcyBpbiB0b3BpY3MsIGhlcmUgSSBydW4gTERBIHNlcGFyYXRlbHkgb24gc3BlZWNoZXMgbWFkZSBkdXJpbmcgZGlmZmVyZW50IHR5cGVzIG9mIGhpc3RvcmljIGV2ZW50IChleHBhbnNpb24sIHJlY2Vzc2lvbiBhbmQgd2FyKS4gIApgYGB7cn0KIyBSdW4gTERBIHVuZGVyIDMgZGlmZmVyZW50IGV2ZW50cwpsZGFPdXQuZXhwYW4gPC0gTERBX091dChldmVudCA9ICJleHBhbnNpb24iKQpsZGFPdXQucmVjZXMgPC0gTERBX091dChldmVudCA9ICJyZWNlc3Npb24iKQpsZGFPdXQud2FyIDwtIExEQV9PdXQoZXZlbnQgPSAid2FyIikKCiMgV3JpdGUgTERBIGZpbGVzIApzYXBwbHkoYygiZXhwYW5zaW9uIiwicmVjZXNzaW9uIiwgIndhciIpLCB3cml0ZV9sZGFfZmlsZXMpCmBgYAogIAombmJzcDsgIAombmJzcDsgIAombmJzcDsgIAoKCiMjIFN0ZXAgNzogTERBIFJlc3VsdHMgVmlzaWxpemF0aW9uCkluIG9yZGVyIHRvIGJldHRlciB2aXNpbGl6ZSBhbmQgdW5kZXJzdGFuZCB0aGUgTERBIHJlc3VsdHMsIEkgdXNlZCBnZ3Bsb3RzLiBFYWNoIGJhcnBsb3QgcmVwcmVzZW50cyBhIHNwZWNpZmljIHRvcGljIGFuZCBlYWNoIHRvcGljIGNvbnRhaW5zIDIwIHRlcm1zLiBCYXNlZCBvbiB0aGUgbW9zdCBwb3B1bGFyIHRlcm1zIGFuZCB0aGUgbW9zdCBzYWxpZW50IHRlcm1zIGZvciBlYWNoIHRvcGljLCB3ZSBjb25jbHVkZSBhIHRvcGljIG5hbWUgdG8gZWFjaCB0b3BpYy4gCmBgYHtyLCBmaWcuaGVpZ2h0PTMuMywgZmlnLndpZHRoPTMuNX0KIyBEdXJpbmcgZWNvbm9taWMgZXhwYW5zaW9uCmxkYU91dC50aWR5LmV4cGFuIDwtIHRpZHkobGRhT3V0LmV4cGFuKQpsZGFPdXQudGVybXMuZXhwYW4gPC0gYXNfdGliYmxlKHRlcm1zKGxkYU91dC5leHBhbiwyMCkpCgp0b3AudGVybXMuZXhwYW4gPC0gbGRhT3V0LnRpZHkuZXhwYW4gJT4lCiAgZ3JvdXBfYnkodG9waWMpICU+JQogIHRvcF9uKDIwLCBiZXRhKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgYXJyYW5nZSh0b3BpYywgLWJldGEpCgp0b3AudGVybXMuZXhwYW4gJT4lCiAgbXV0YXRlKHRlcm0gPSByZW9yZGVyKHRlcm0sIGJldGEpKSAlPiUKICBnZ3Bsb3QoYWVzKHRlcm0sIGJldGEsIGZpbGwgPSBmYWN0b3IodG9waWMpKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgZmFjZXRfd3JhcCh+IHRvcGljLCBzY2FsZXMgPSAiZnJlZSIsIG5jb2w9NSwgbnJvdz0yKSArCiAgZ2d0aXRsZSgiVG9waWNzIGFuZCBUZXJtcyBEdXJpbmcgRWNvbm9taWMgRXhwYW5zaW9ucyIpKwogIGNvb3JkX2ZsaXAoKQoKIyBEdXJpbmcgZWNvbm9taWMgcmVjZXNzaW9uCmxkYU91dC50aWR5LnJlY2VzIDwtIHRpZHkobGRhT3V0LnJlY2VzKQpsZGFPdXQudGVybXMucmVjZXMgPC0gYXNfdGliYmxlKHRlcm1zKGxkYU91dC5yZWNlcywyMCkpCgp0b3AudGVybXMucmVjZXMgPC0gbGRhT3V0LnRpZHkucmVjZXMgJT4lCiAgZ3JvdXBfYnkodG9waWMpICU+JQogIHRvcF9uKDIwLCBiZXRhKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgYXJyYW5nZSh0b3BpYywgLWJldGEpCgp0b3AudGVybXMucmVjZXMgJT4lCiAgbXV0YXRlKHRlcm0gPSByZW9yZGVyKHRlcm0sIGJldGEpKSAlPiUKICBnZ3Bsb3QoYWVzKHRlcm0sIGJldGEsIGZpbGwgPSBmYWN0b3IodG9waWMpKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgZmFjZXRfd3JhcCh+IHRvcGljLCBzY2FsZXMgPSAiZnJlZSIsIG5jb2w9NSwgbnJvdz0yKSArCiAgZ2d0aXRsZSgiVG9waWNzIGFuZCBUZXJtcyBEdXJpbmcgRWNvbm9taWMgUmVjZXNzaW9ucyIpKwogIGNvb3JkX2ZsaXAoKQoKIyBEdXJpbmcgd2FycwpsZGFPdXQudGlkeS53YXIgPC0gdGlkeShsZGFPdXQud2FyKQpsZGFPdXQudGVybXMud2FyIDwtIGFzX3RpYmJsZSh0ZXJtcyhsZGFPdXQud2FyLDIwKSkKCnRvcC50ZXJtcy53YXIgPC0gbGRhT3V0LnRpZHkud2FyICU+JQogIGdyb3VwX2J5KHRvcGljKSAlPiUKICB0b3BfbigyMCwgYmV0YSkgJT4lCiAgdW5ncm91cCgpICU+JQogIGFycmFuZ2UodG9waWMsIC1iZXRhKQoKdG9wLnRlcm1zLndhciAlPiUKICBtdXRhdGUodGVybSA9IHJlb3JkZXIodGVybSwgYmV0YSkpICU+JQogIGdncGxvdChhZXModGVybSwgYmV0YSwgZmlsbCA9IGZhY3Rvcih0b3BpYykpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBmYWNldF93cmFwKH4gdG9waWMsIHNjYWxlcyA9ICJmcmVlIiwgbmNvbD01LCBucm93PTIpICsKICBnZ3RpdGxlKCJUb3BpY3MgYW5kIFRlcm1zIER1cmluZyBXYXJzIikrCiAgY29vcmRfZmxpcCgpCmBgYApUaG9zZSBMREEgYmFycGxvdHMgYXJlIHZlcnkgaW5mb3JtYXRpdmUgYW5kIHRoZSBkaWZmZXJlbmNlcyBpbiB0b3BpY3MgYXJlIHF1aXRlIHNhbGllbnQgYmV0d2VlbiBkaWZmZXJlbnQgdHlwZXMgb2YgaGlzdG9yaWMgZXZlbnRzLiBGb3IgaW5zdGFuY2UsIGR1cmluZyBlY29ub21pYyBleHBhbnNpb24sIHByZXNpZGVudHMgbGlrZSB0byB0YWxrIGFib3V0ICJmcmVlZG9tIiAodG9waWMgMSksICJmYW1pbHkiICh0b3BpYyAyKSwgYW5kICJuYXRpb25hbCBzZWN1cml0eSIgKHRvcGljIDMpLiBTaW5jZSB0aG9zZSB0d28gbWFqb3IgZWNvbm9taWMgZXhwYW5zaW9ucyBhcmUgYWxsIGR1cmluZyB0aGUgQ29sZCBXYXIsIGl0IGRvZXMgbWFrZSBzZW5zZSBwcmVzaWRlbnRzIHRoZW4gbGlrZSB0byB0YWxrIGFib3V0IHRob3NlIHRoaW5ncy4gIApEdXJpbmcgcmVjZXNzaW9ucywgdGhleSBsaWtlIHRvIHRhbGsgYWJvdXQgImpvYiIgKHRvcGljIDIpLCAicmVmb3JtIiAodG9waWMgNSksIGV0Yy4gIApEdXJpbmcgd2FycywgdGhleSBsaWtlIHRvIHRhbGsgYWJvdXQgImNvaGVzaW9uIiIgKHRvcGljIDIpLCAicmVzcG9uc2liaWxpdHkiIiAodG9waWMgMyksIGV0Yy4gIAoKJm5ic3A7ICAKJm5ic3A7ICAKJm5ic3A7ICAKCgojIyBTdGVwIDg6IFBlcmZvcm0gTERBIGFjcm9zcyBhbGwgdHlwZXMgb2YgZXZlbnRzClRoaXMgc3RlcCBpcyBwcmVwYXJlZCBmb3IgdG9waWMgY2x1c3RlcmluZwpgYGB7ciwgZmlnLmhlaWdodD00LjUsIGZpZy53aWR0aD0zLCBlY2hvPVRSVUV9CmxkYU91dCA8LSBMREFfT3V0KGV2ZW50ID0gTlVMTCwgayA9IDE1KQprID0gMTUKI3dyaXRlIG91dCByZXN1bHRzCiNkb2NzIHRvIHRvcGljcwpsZGFPdXQudG9waWNzIDwtIGFzLm1hdHJpeCh0b3BpY3MobGRhT3V0KSkKIyB0YWJsZShjKDE6aywgbGRhT3V0LnRvcGljcy5leHBhbikpCndyaXRlLmNzdihsZGFPdXQudG9waWNzLCBmaWxlPXBhc3RlMChwYXRoLCIvb3V0cHV0L0xEQUdpYmJzIixrLCJEb2NzVG9Ub3BpY3MuY3N2IikpCgojdG9wIDYgdGVybXMgaW4gZWFjaCB0b3BpYwpsZGFPdXQudGVybXMgPC0gYXMubWF0cml4KHRlcm1zKGxkYU91dCwyMCkpCndyaXRlLmNzdihsZGFPdXQudGVybXMsZmlsZT1wYXN0ZTAocGF0aCwiL291dHB1dC9MREFHaWJicyIsaywiVG9waWNzVG9UZXJtcy5jc3YiKSkKCiNwcm9iYWJpbGl0aWVzIGFzc29jaWF0ZWQgd2l0aCBlYWNoIHRvcGljIGFzc2lnbm1lbnQKdG9waWNQcm9iYWJpbGl0aWVzIDwtIGFzLmRhdGEuZnJhbWUobGRhT3V0QGdhbW1hKQp3cml0ZS5jc3YodG9waWNQcm9iYWJpbGl0aWVzLGZpbGU9cGFzdGUwKHBhdGgsIi9vdXRwdXQvTERBR2liYnMiLGssIi5jc3YiKSkKCmxkYU91dC50aWR5IDwtIHRpZHkobGRhT3V0KQpsZGFPdXQudGVybXMgPC0gYXNfdGliYmxlKHRlcm1zKGxkYU91dCwyMCkpCgp0b3AudGVybXMgPC0gbGRhT3V0LnRpZHkgJT4lCiAgZ3JvdXBfYnkodG9waWMpICU+JQogIHRvcF9uKDIwLCBiZXRhKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgYXJyYW5nZSh0b3BpYywgLWJldGEpCgp0b3AudGVybXMgJT4lCiAgbXV0YXRlKHRlcm0gPSByZW9yZGVyKHRlcm0sIGJldGEpKSAlPiUKICBnZ3Bsb3QoYWVzKHRlcm0sIGJldGEsIGZpbGwgPSBmYWN0b3IodG9waWMpKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgZmFjZXRfd3JhcCh+IHRvcGljLCBzY2FsZXMgPSAiZnJlZSIsIG5jb2w9NSwgbnJvdz0zKSArCiAgZ2d0aXRsZSgiQWNyb3NzIGFsbCBldmVudHMiKSsKICBjb29yZF9mbGlwKCkKYGBgClRoaXMgcGxvdCBpcyB1c2VkIHRvIGdlbmVyYXRlIHRoZSBoYXNodGFncy4gSXQgZG9lcyBub3QgaGF2ZSBtdWNoIGltcGxpY2F0aW9ucyBpdHNlbGYuCiZuYnNwOyAgCiZuYnNwOyAgCiZuYnNwOyAgCgojIyBTdGVwIDk6IFRvcGljIGNsdXN0ZXJpbmcgIApCYXNlZCBvbiB0aGUgTERBIHJlc3VsdHMsIEkgZ2F2ZSBhbGwgMTUgdG9waWNzIGEgbWVhbmluZ2Z1bCB0YWcuIFRoZW4gSSBjbHVzdGVyIHRoZSB0b3BpY3Mgb2YgdGhvc2Ugc3BlZWNoZXMgdG9nZXRoZXIgdG8gZmluZCBhIHBhdHRlcm4uCmBgYHtyLCBmaWcud2lkdGg9NC41LCBmaWcuaGVpZ2h0PTIsIG1lc3NhZ2U9RkFMU0UsIGVjaG89VFJVRX0KdG9waWNzLmhhc2g9YygiQW1lcmljYW4iLCAiRXF1YWxpdHkiLCAiRWxlY3Rpb24iLCAiT2JsaWdhdGlvbiIsICJQYXRyaW90aXNtIiwgIkZyZWVkb20iLCAiRWNvbm9teSIsICJSZWZvcm0iLCAiVW5pdHkiLCAiU29jaWFsV2VsZmFyZSIsICJHb3Zlcm5tZW50IiwgIkRlZmVuc2UiLCAiRmFpdGgiLCAiTWlzYyIsICJMZWdpc2xhdGlvbiIpCmNvcnB1cy5saXN0LnByZXNpIDwtIGNvcnB1cy5saXN0ICU+JQogIG11dGF0ZShQcmVzaWRlbnQudGVybSA9IHBhc3RlMChQcmVzaWRlbnQsICIgdGVybSAiICxUZXJtKSkgJT4lCiAgZmlsdGVyKFByZXNpZGVudC50ZXJtICVpbiUgcHJlc2lkZW50cyRQcmVzaWRlbnQudGVybSkgJT4lIAogIG11dGF0ZShsZGF0b3BpYz1hcy52ZWN0b3IobGRhT3V0LnRvcGljcykpICU+JQogIG11dGF0ZShsZGFoYXNoPXRvcGljcy5oYXNoW2xkYU91dC50b3BpY3NdKQoKY29sbmFtZXModG9waWNQcm9iYWJpbGl0aWVzKT10b3BpY3MuaGFzaApjb3JwdXMubGlzdC5kZj1jYmluZChjb3JwdXMubGlzdC5wcmVzaSwgdG9waWNQcm9iYWJpbGl0aWVzKQoKCnRvcGljLnN1bW1hcnk9dGJsX2RmKGNvcnB1cy5saXN0LmRmKSU+JQogIG11dGF0ZShQcmVzaWRlbnQudGVybSA9IHBhc3RlMChQcmVzaWRlbnQsICIgdGVybSAiICxUZXJtKSkgJT4lCiAgc2VsZWN0KFByZXNpZGVudC50ZXJtLCBBbWVyaWNhbjpMZWdpc2xhdGlvbikgJT4lCiAgZ3JvdXBfYnkoUHJlc2lkZW50LnRlcm0pJT4lCiAgc3VtbWFyaXNlX2VhY2goZnVucyhtZWFuKSkgICU+JQogIHVuZ3JvdXAoKSAlPiUKICBsZWZ0X2pvaW4ocHJlc2lkZW50cywgYnkgPSAiUHJlc2lkZW50LnRlcm0iKSAlPiUKICBzZWxlY3QoUHJlc2lkZW50LmV2ZW50LCBBbWVyaWNhbjpMZWdpc2xhdGlvbikKCnRvcGljLnN1bW1hcnk9YXMuZGF0YS5mcmFtZSh0b3BpYy5zdW1tYXJ5KQpyb3duYW1lcyh0b3BpYy5zdW1tYXJ5KT10b3BpYy5zdW1tYXJ5WywxXQoKdG9waWMucGxvdD1jKDcsIDgsIDIsIDksIDEyLCAxMCwgNikKcHJpbnQodG9waWNzLmhhc2hbdG9waWMucGxvdF0pCgpoZWF0bWFwLjIoYXMubWF0cml4KHRvcGljLnN1bW1hcnlbLHRvcGljLnBsb3QrMV0pLCAKICAgICAgICAgIHNjYWxlID0gImNvbHVtbiIsIGtleT1GLCAKICAgICAgICAgIGNvbCA9IGJsdWVyZWQoMTAwKSwKICAgICAgICAgIGNleFJvdyA9IDAuOSwgY2V4Q29sID0gMC45LCBtYXJnaW5zID0gYyg2LCAxNSksCiAgICAgICAgICB0cmFjZSA9ICJub25lIiwgZGVuc2l0eS5pbmZvID0gIm5vbmUiKQoKYGBgCkl0IHNob3dzIHRoYXQgcHJlc2lkZW50cyB3aG8gYXNzdW1lZCB0aGUgb2ZmaWNlIGR1cmluZyBlY29ub21pYyBleHBhbnNpb25zIGxpa2UgdG8gdGFsayBhYm91dCAic29jaWFsIHdlbGZhcmUiLCAidW5pdHkiIGFuZCAiZWNvbm9teSIgbW9yZS4gUHJlc2lkZW50cyB3aG8gYXNzdW1lZCB0aGUgb2ZmaWNlIGR1cmluZyB3YXJzIHByZWZlcnJlZCB0YWxraW5nIGFib3V0ICJkZWZlbnNlIiwgImVxdWFsaXR5IiwgYW5kICJmcmVlZG9tIi4gVGhlcmUgaXMgbm8gcmVjb2duaXphYmxlIGZhdm9yZWQgdG9waWNzIGZvciBwcmVzaWRlbnRzIGFzc3VtZWQgdGhlIG9mZmljZSBkdXJpbmcgcmVjZXNzaW9ucy4gIAoKJm5ic3A7ICAKJm5ic3A7ICAKJm5ic3A7ICAKCiMjIFN0ZXAgMTA6IENsdXN0ZXIgc3BlZWNoZXMgdXNpbmcgSy1tZWFucwpMYXN0bHkgSSB3YW50IHRvIGNsdXN0ZXIgdGhvc2Ugc3BlZWNoZXMgYmFzZWQgb24gdGhlaXIgdG9waWNzLiBIZXJlIEstbWVhbnMgbWV0aG9kIGlzIHVzZWQgYWdhaW4uIFRoZSBwdXJwb3NlIG9mIHRoaXMgc3RlcCBpcyB0byBzZWUgd2hldGhlciBzcGVlY2hlcyBtYWRlIGR1cmluZyB0aGUgc2FtZSB0eXBlIG9mIGV2ZW50IGNhbiBiZSBjbHVzdGVyZWQgdG9nZXRoZXIsIHdoaWNoIG1heSBpbmRpY2F0ZSBhIGhvbW9nZW5laXR5IGluIHRoZWlyIHRvcGljcy4gSW4gb3JkZXIgdG8gb2J0YWluIGJldHRlciByZXN1bHRzLCB0aGUgY2x1c3RlcmluZyB3YXMgcGVyZm9ybWVkIHVuZGVyIHR3byBjaXJjdW1zdGFuY2VzOiBhY3Jvc3MgYWxsIHRocmVlIHR5cGVzIG9mIGhpc3RvcmljIGV2ZW50cyBhbmQgb25seSBhY3Jvc3MgZWNvbm9taWMgZXhwYW5zaW9uIGFuZCByZWNlc3Npb24uCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQpwcmVzaWQuc3VtbWFyeT10YmxfZGYoY29ycHVzLmxpc3QuZGYpJT4lCiAgbXV0YXRlKFByZXNpZGVudC50ZXJtID0gcGFzdGUwKFByZXNpZGVudCwgIiB0ZXJtICIgLFRlcm0pKSAlPiUKICBzZWxlY3QoUHJlc2lkZW50LnRlcm0sIEFtZXJpY2FuOkxlZ2lzbGF0aW9uKSAlPiUKICBncm91cF9ieShQcmVzaWRlbnQudGVybSklPiUKICBzdW1tYXJpc2VfZWFjaChmdW5zKG1lYW4pKSAgJT4lCiAgdW5ncm91cCgpICU+JQogIGxlZnRfam9pbihwcmVzaWRlbnRzLCBieSA9ICJQcmVzaWRlbnQudGVybSIpICU+JQogIHNlbGVjdChQcmVzaWRlbnQuZXZlbnQsIEFtZXJpY2FuOkxlZ2lzbGF0aW9uKQoKCiMgQ2x1c3RlciBvbiBhbGwgdGhyZWUgZXZlbnRzOiBFeHBhbnNpb25zLCByZWNlc3Npb25zLCBhbmQgd2FycwpwcmVzaWQuc3VtbWFyeT1hcy5kYXRhLmZyYW1lKHByZXNpZC5zdW1tYXJ5KQpyb3duYW1lcyhwcmVzaWQuc3VtbWFyeSk9YXMuY2hhcmFjdGVyKChwcmVzaWQuc3VtbWFyeVssMV0pKQprbS5yZXM9a21lYW5zKHNjYWxlKHByZXNpZC5zdW1tYXJ5WywtMV0pLCBpdGVyLm1heD0yMDAsIDMpCmZ2aXpfY2x1c3RlcihrbS5yZXMsIAogICAgICAgICAgICAgc3RhbmQ9VCwgcmVwZWw9IFRSVUUsCiAgICAgICAgICAgICBkYXRhID0gcHJlc2lkLnN1bW1hcnlbLC0xXSwKICAgICAgICAgICAgIHNob3cuY2x1c3QuY2VudD1GQUxTRSkKCiMgQ2x1c3RlciBvbiBvbmx5IGV4cGFuc2lvbnMgYW5kIHJlY2Vzc2lvbnMKa20ucmVzPWttZWFucyhzY2FsZShwcmVzaWQuc3VtbWFyeVstYygzLDQsMTApLC0xXSksIGl0ZXIubWF4PTIwMCwgMikKZnZpel9jbHVzdGVyKGttLnJlcywgCiAgICAgICAgICAgICBzdGFuZD1ULCByZXBlbD0gVFJVRSwKICAgICAgICAgICAgIGRhdGEgPSBwcmVzaWQuc3VtbWFyeVstYygzLDQsMTApLC0xXSwKICAgICAgICAgICAgIHNob3cuY2x1c3QuY2VudD1GQUxTRSkKYGBgCkJvdGggY2x1c3RlciBwbG90cyBhcmUgaW5mb3JtYXRpdmUuIFdoZW4gY2x1c3RlcmluZyBhbGwgMyB0eXBlcyBvZiBldmVudHMsIGFsbCBzcGVlY2hlcyBtYWRlIGR1cmluZyBleHBhbnNpb25zIGFyZSBjbHVzdGVyZWQgdG9nZXRoZXIgYW5kIG1vc3Qgb2YgdGhlIHNwZWVjaCBtYWRlIGR1cmluZyB3YXJzIGFyZSBjbHVzdGVyZWQgdG9nZXRoZXIuIFdoZW4gY2x1c3RlcmluZyBvbmx5IG9uIGV4cGFuc2lvbiBhbmQgcmVjZXNzaW9uLCB0aGVyZSBpcyBvbmx5IG9uZSBtaXN0YWtlLiAgClRoaXMgbWVhbnMgdGhhdCB0aGUgdG9waWNzIGNvdmVyZWQgaW4gdGhlIHNwZWVjaGVzIG1hZGUgZHVyaW5nIGVjb25vbWljIGV4cGFuc2lvbnMsIHJlY2Vzc2lvbnMgYW5kIHdhcnMgYXJlIGRpZmZlcmVudCBmcm9tIGVhY2ggb3RoZXIuICAKCiZuYnNwOyAgCiZuYnNwOyAgCiZuYnNwOyAgCgojIyBDb25jbHVzaW9uICAKUmVnYXJkbGVzcyBvZiB0aGUgdHlwZXMgb2YgZXZlbnRzLCB0aGUgbW9zdCBleHByZXNzZWQgZW1vdGlvbiBpbiBhbGwgc3BlZWNoZXMgaXMgInRydXN0Ii4gRHVyaW5nIGVjb25vbWljIGV4cGFuc2lvbiBwZXJpb2RzLCB0aGVyZSBhcmUgYSBsb3QgbW9yZSAiam95IiBhbmQgInN1cnByaXNlIiBhbmQgbGVzcyAiZmVhciIgYW5kICJhbmdlciJleHByZXNzZWQgaW4gdGhlIGluYXVndXJhbCBzcGVlY2hlcyBvdmVyYWwsIGNvbXBhcmVkIHRvIHJlY2Vzc2lvbiBhbmQgd2FyIHBlcmlvZHMuIAombmJzcDsgIApGcm9tIHRoZSBlbW90aW9uIGNsdXN0ZXIgcGxvdHMsIHdlIG1heSBjb25jbHVkZSB0aGF0IHRoZSBuYXRpb25hbCBlY29ub21pYyBzdGF0dXMgY2FuIGhhdmUgYW4gaW5mbHVlbmNlIG9uIHRoZSBlbW90aW9ucyBleHByZXNzZWQgaW4gdGhlIGluYXVndXJhbCBzcGVlY2hlcy4gRW1vdGlvbnMgZXhwcmVzc2VkIGluIHNwZWVjaGVzIG1hZGUgZHVyaW5nIGVjb25vbWljIGV4cGFuc2lvbnMgYW5kIGVjb25vbWljIHJlY2Vzc2lvbnMgYXJlIGRpZmZlcmVudC4gIAombmJzcDsgICAKClByZXNpZGVudHMgdGVuZCB0byB0YWxrIGFib3V0IGRpZmZlcmVudCB0b3BpY3MgaW4gZGlmZmVyZW50IGhpc3RvcmljYWwgYmFja2dyb3VuZHMuIEZvciBleGFtcGxlLCBkdXJpbmcgZWNvbm9taWMgZXhwYW5zaW9uLCB0aGV5IGxpa2UgdG8gdGFsayBhYm91dCAiZnJlZWRvbSIsICJmYW1pbHkiLCAibmF0aW9uYWwgc2VjdXJpdHkiIGFuZCBldGMuIER1cmluZyByZWNlc3Npb25zLCB0aGV5IGxpa2UgdG8gdGFsayBhYm91dCAiam9icyIsICJyZWZvcm1zIiAodG9waWMgNSkgYW5kIGV0YyB0byBzaG93IHRoZWlyIGZ1dHVyZSBwbGFucyB0byByZXZpdGFsaXplIGVjb25vbXkuIER1cmluZyB3YXJzLCB0aGV5IGxpa2UgdG8gdGFsayBhYm91dCAiY29oZXNpb24iLCAicmVzcG9uc2liaWxpdHkiIGFuZCBldGMuIHRvIGVuY291cmFnZSB0aGUgbmF0aW9uIHRvIHN0aWNrIHRvZ2V0aGVyLiAgCiZuYnNwOyAgIAoKVG9waWMgY2x1c3RlcmluZyBwbG90cyBhbHNvIGdpdmUgdGhlIHNhbWUgY29uY2x1c2lvbi4gQWxsIHNwZWVjaGVzIG1hZGUgZHVyaW5nIGV4cGFuc2lvbnMgYXJlIGNsdXN0ZXJlZCB0b2dldGhlciBhbmQgbW9zdCBvZiB0aGUgc3BlZWNoIG1hZGUgZHVyaW5nIHdhcnMgYXJlIGNsdXN0ZXJlZCB0b2dldGhlci4gVGhpcyBpbmRpY2F0ZXMgdGhhdCB0eXBlcyBvZiBldmVudHMgZHVyaW5nIHdoaWNoIHRoZSBzcGVlY2hlcyBhcmUgbWFkZSBwb3RlbnRpYWxseSBjYW4gZGV0ZXJtaW5lIHdoYXQgdG9waWNzIHRoZSBwcmVzaWRlbnRzIGFyZSBnb2luZyB0byB0YWxrIGFib3V0IGluIHRoZWlyIGluYXVndXJhbCBzcGVlY2hlcy4gIA==