Most popular words in economics papers?
paper_words <- nber %>%
unnest_tokens(word, abstract) %>%
filter(!word %in% stop_words$word)%>%
count(word, sort = TRUE)%>%
slice_max(n, n = 10)
tot<-nrow(nber)
paper_words%>%mutate(tot=tot)%>%
mutate(`fraction of papers`=round(n/tot,2))%>%select(1,4)%>%knitr::kable("markdown")
| model |
0.54 |
| paper |
0.53 |
| data |
0.49 |
| market |
0.39 |
| effects |
0.38 |
| policy |
0.34 |
| rate |
0.31 |
| income |
0.31 |
| firms |
0.30 |
| tax |
0.29 |
Data vs models?
I use the same word searches as Currie, Kleven, and Zwiers (2020).
nber<-nber%>%
mutate(ex=(str_detect(abstract, "exploit")),
dd=str_detect(abstract, "Difference in Diff|Difference in diff|difference in diff|Difference-in-Diff|Difference-in-diff|difference-in-diff|Differences in Diff|Differences in diff|differences in diff|Differences-in-Diff|Differences-in-diff|differences-in-diff|diff-in-diff|d-in-d|DiD"),
event=str_detect(abstract, "event study|event-study"),
iv=str_detect(abstract, "Instrumental Variable|Instrumental variable|instrumental variable|Instrumental-Variable|Instrumental-variable|instrumental-variable|Two Stage Least Squares|Two stage least squares|two
stage least squares|2SLS|TSLS|valid instrument|exogenous instrument|IV Estimat|IV estimat|IV-estimat|IV Specification|IV specification|IV-specification|IV Regression|IV regression|IV-regression|IV Strateg|IV strateg|IV-strateg|we instrument|I instrument|paper instruments|exclusion restriction|weak first stage|simulated instrument"),
rd=str_detect(abstract, "Regression Discontinuit|Regression discontinuit|regression discontinuit|Regression-discontinuity|regression-discontinuity|Regression Kink|Regression kink|regression kink|RD Design|RD design|RD-design|RD Estimat|RD estimat|RD-estimat|RD Model|RD model|RD-model|RD Regression|RD regression|RD-regression|RD Coefficient|RD coefficient|RD-coefficient|RK Design|RK design|RK-Design|RK-design|RKD"),
covid=str_detect(abstract, "covid|coronavirus|COVID|Covid|CORONAVIRUS"),
data=str_detect(abstract, "data"),
model=str_detect(abstract, "model"))
Note: I use the {ggtext} package to color words in the title and subtitle.
library(ggtext)
nber%>%mutate(year=year(ymd(public_date)))%>%
group_by(year)%>%filter(year>=1980)%>%
summarise(data=mean(data==T),
model=mean(model==T))%>%
pivot_longer(2:3)%>%
ggplot(aes(x=year, y=value, color=name, linetype=name, shape=name))+
geom_line()+geom_point()+
scale_color_manual(values=c("#009E73", "gray40"), name="")+
labs(x="", y="", caption="Data: NBER working paper metadata. Plot: Alex Albright.",
title="<span style = 'font-size:22pt'><span style = 'color:#009E73;'>Data</span> has overtaken <span style = 'color:gray40;'>Models</span></span><br> % of abstracts including the words <span style = 'color:#009E73;'>'data'</span> or <span style = 'color:gray40;'>'model'</span>")+
scale_y_continuous(labels=scales::percent_format(accuracy = 1), breaks=seq(0.2,.6,.1), limits=c(0.18,0.5))+
theme_minimal(base_family = "Palatino", base_size = 14)+theme(plot.title.position = "plot", legend.position = "none",
plot.title = element_markdown())
21 failed to parse.
ggsave('graphs/modelvdata1.png', dpi=250, width=7, height=5)

Most popular quasi experimental methods?
library(wesanderson)
nber%>%mutate(year=year(ymd(public_date)))%>%
group_by(year)%>%filter(year>=1980)%>%
summarise(IV=mean(iv==T),
DD=mean(dd==T),
RD=mean(rd==T))%>%
pivot_longer(2:4)%>%
ggplot(aes(x=year, y=value, color=name, linetype=name, shape=name))+
labs(y="", x="", caption="Data: NBER working paper metadata. Plot: Alex Albright.")+
geom_point()+
scale_y_continuous(labels=scales::percent_format(accuracy = 1))+
geom_line()+ggtitle("DD overtakes IV as quasi-experimental queen",
subtitle="% of abstracts using quasi-experimental method words")+
scale_color_manual(values=wes_palette("Darjeeling1", 4, type="discrete"))+
theme_minimal(base_family = "Palatino", base_size=15)+
theme(plot.title.position = "plot", legend.title = element_blank(),
legend.position = "right")
21 failed to parse.
ggsave('graphs/quasi-exp-methods1.png', dpi=250, width=7.5, height=5)

Using the word ‘exploit’
For more n-gram examples see Text Mining with R
time<-nber%>%mutate(year=year(ymd(public_date)))%>%
group_by(year)%>%filter(year>=1980)%>%
summarise(exp=mean(ex==T))%>%
ggplot(aes(x=year, y=exp))+
geom_line()+geom_point()+
geom_line()+ggtitle("% abstracts that use the word 'exploit'")+labs(x="", y="")+
scale_y_continuous(labels=scales::percent_format(accuracy = 1), breaks=seq(0,.08,.02), limits=c(0,0.08))+
theme_minimal(base_family = "Palatino", base_size = 14)+theme(plot.title.position = "plot")
21 failed to parse.
abs_bi <- nber %>%
unnest_tokens(bigram, abstract, token = "ngrams", n = 3)
abs_bi%>%
count(bigram, sort = TRUE)
bigrams_separated <- abs_bi %>%
separate(bigram, c("word1", "word2", "word3"), sep = " ")
bigrams_filtered <- bigrams_separated %>%
filter(str_detect(word1, "exploit"))
# new bigram counts:
bigram_counts <- bigrams_filtered %>%
mutate(word1="exploit")%>%
mutate(word2=if_else(word2=="the"|word2=="an"|word2=="a"|word2=="this"|word2=="of"|word2=="these"|word2=="their", word3, word2))%>%
select(word1, word2)%>%
count(word1, word2, sort = TRUE)
bigram_graph <- bigram_counts %>%
filter(n >= 15) %>%
graph_from_data_frame()
set.seed(2009)
a <- grid::arrow(type = "closed", length = unit(.15, "inches"))
net<-ggraph(bigram_graph, layout = "fr") +
geom_edge_link(aes(edge_alpha = n), show.legend = FALSE,
arrow = a, end_cap = circle(.07, 'inches')) +
geom_node_point(color = "lightblue", size = 5) +
geom_node_text(aes(label = name, family="Palatino"), vjust = 0, hjust = 1) +
theme_void(base_family = "Palatino", base_size = 12)+
ggtitle("Most common words following 'exploit'")+
theme(plot.title.position = "plot")
time/net+
plot_annotation(title = "Economists love 'exploiting' variation",
theme = theme(plot.title = element_text(size = 22, family="Palatino"))) +
plot_annotation(caption = 'Ignoring generic words: a, an, this, these, the, of, their\nData: NBER working paper metadata. Plot: Alex Albright.',
theme = theme(plot.caption = element_text(size = 13, family="Palatino")))
ggsave('graphs/econ-exploit2.png', dpi=250, width=9.5, height=9)

Covid plot
nber%>%mutate(my=floor_date(ymd(public_date), "month"))%>%
group_by(my)%>%filter(my>="2018-01-01")%>%
summarise(covid=mean(covid==T))%>%
ggplot(aes(x=my, y=covid))+
geom_line()+geom_point()+labs(x="", y="", caption = "Data: NBER working paper metadata. Plot: Alex Albright.")+
ggtitle("% of abstracts that include 'covid/coronavirus'")+
scale_x_date()+
scale_y_continuous(labels=scales::percent_format(accuracy = 1), breaks=seq(0,.3,.05), limits=c(0,0.3))+
theme_minimal(base_family = "Palatino", base_size = 14)+theme(plot.title.position = "plot")
21 failed to parse.
ggsave('graphs/covid1.png', dpi=250, width=7, height=4)

Econ paper title conventions
nber$q=if_else(grepl("\\?", nber$title), 1, 0)
input string 109 is invalid in this localeinput string 173 is invalid in this localeinput string 177 is invalid in this localeinput string 183 is invalid in this localeinput string 245 is invalid in this locale
nber$colon=if_else(grepl("\\:", nber$title), 1, 0)
input string 109 is invalid in this localeinput string 173 is invalid in this localeinput string 177 is invalid in this localeinput string 183 is invalid in this localeinput string 245 is invalid in this locale
nber%>%summarise(`title w/ question`=mean(q==1),
`title w/ colon`=mean(colon==1),
`title w/ question or colon`=mean(q==1 | colon==1),
`title w/ question and colon`=mean(q==1 & colon==1))%>%
pivot_longer(1:4)%>%mutate(value=round(value,2))%>%
rename(convention=name, `fraction of papers`=value)%>%knitr::kable("markdown")
| title w/ question |
0.13 |
| title w/ colon |
0.34 |
| title w/ question or colon |
0.45 |
| title w/ question and colon |
0.03 |
34% use :s and 13% use question marks! 45% do one of the two.
Common bigrams
abs_bi <- nber %>%
unnest_tokens(bigram, abstract, token = "ngrams", n = 2)
bigrams_separated <- abs_bi %>%
separate(bigram, c("word1", "word2"), sep = " ")
bigrams_filtered <- bigrams_separated %>%
filter(!word1 %in% stop_words$word) %>%
filter(!word2 %in% stop_words$word)
# new bigram counts:
bigram_counts <- bigrams_filtered %>%
count(word1, word2, sort = TRUE)
#make graph
bigram_graph <- bigram_counts %>%
filter(!is.na(word1))%>%
filter(n >= 500) %>%
graph_from_data_frame()
set.seed(2010)
a <- grid::arrow(type = "closed", length = unit(.15, "inches"))
ggraph(bigram_graph, layout = "fr") +
geom_edge_link(aes(edge_alpha = n), show.legend = FALSE,
arrow = a, end_cap = circle(.07, 'inches')) +
geom_node_point(color = "lightblue", size = 5) +
geom_node_text(aes(label = name, family="Palatino"), vjust = 0, hjust = 1) +
theme_void()+
ggtitle("Common bigrams in NBER WP abstracts", subtitle="Limit to bigrams with 500+ observations")+
labs(caption="Excluding stop words.\nData: NBER working paper metadata. Plot: Alex Albright.")+
theme(text=element_text(family="Palatino", size = 20))
ggsave('graphs/bigrams1.png', dpi=250, width=10.5, height=7)

Who are the authors?
Use this {predict race} package from Jacob Kaplan to get race and gender from the author names.
Let’s use the cleaner author .txt data but only keep those that link to the large .tab file, so we are pulling from the same universe of papers.
papers<-nber%>%select(paper, public_date)%>%distinct()
authors<-inner_join(auths, papers)
Joining, by = "paper"
#separate out name into first and last
authors<-authors%>%
mutate(lastname=word(name, -1), firstname=word(name, -2))
argument is not an atomic vector; coercingargument is not an atomic vector; coercing
df<-authors%>%
mutate(firstname_race=predict_race(firstname, probability = F, surname = F)$likely_race,
lastname_race=predict_race(lastname, probability = F, surname = T)$likely_race,
gender=predict_gender(firstname, probability = F)$likely_gender)
Not weighting by paper: unique count of authors per year
df<-df%>%
mutate(year=year(ymd(public_date)))%>%
select(-c(paper, public_date))%>%distinct()
38 failed to parse.
In 2020,
what % nonwhite authors? 30%
nrow(subset(df, year==2020 & !is.na(lastname_race) & (lastname_race!="white")))/nrow(subset(df, year==2020 &!is.na(lastname_race)))
[1] 0.3017241
what % black/hispanic/native american authors? 6%
nrow(subset(df, year==2020 & !is.na(lastname_race) & (lastname_race=="black" | lastname_race=="hispanic" | lastname_race=="american indian")))/nrow(subset(df, year==2020 &!is.na(lastname_race)))
[1] 0.05997001
what % women? 28%
nrow(subset(df, year==2020 & gender=="female" &!is.na(gender)))/nrow(subset(df, year==2020 &!is.na(gender)))
[1] 0.2783964
library(lubridate)
# RACE
dfr<-df%>%filter(year>=1980)%>%
group_by(year)%>%filter(!is.na(gender) & !is.na(lastname_race))%>%
summarise(`White`=mean(lastname_race=="white"),
`Black`=mean(lastname_race=="black"),
`Asian`=mean(lastname_race=="asian"),
`Hispanic`=mean(lastname_race=="hispanic"),
`Native`=mean(lastname_race=="american indian"))%>%pivot_longer(2:6)
race<-dfr%>%ggplot(aes(x=year, y=value, fill=name))+
geom_area()+scale_fill_manual(values=c("#A6CEE3", "#B2DF8A", "#F89A99", "#FABF6F", "#CAB2D6"), name="")+
scale_y_continuous(labels=scales::percent)+theme_minimal(base_family = "Palatino")+
theme(plot.title.position = "plot")+
ggtitle("Race* of NBER Paper Authors")+
labs(x="", y="", caption="*Predicted from last name using Census data.\nOmitting authors without predictions.")
#GENDER
dfg<-df%>%filter(year>=1980)%>%
group_by(year)%>%filter(!is.na(gender) & !is.na(lastname_race))%>%
summarise(`Men`=mean(gender=="male"),
`Women`=mean(gender=="female"))%>%pivot_longer(2:3)
gender<-dfg%>%ggplot(aes(x=year, y=value, fill=name))+
geom_area()+scale_fill_manual(values=c("gray80", "gray30"), name="")+
scale_y_continuous(labels=scales::percent)+theme_minimal(base_family = "Palatino")+
theme(plot.title.position = "plot")+
ggtitle("Gender* of NBER Paper Authors")+
labs(x="", y="", caption="*Predicted from first name using\n US Social Security Admin Data.\nOmitting authors without predictions.")
#GENDER AND RACE
dfgr<-df%>%filter(year>=1980)%>%
group_by(year)%>%filter(!is.na(gender) & !is.na(lastname_race))%>%
summarise(`White Men`=mean(gender=="male" & lastname_race=="white"),
`White Women`=mean(gender=="female" & lastname_race=="white"),
`Black Women`=mean(gender=="female" & lastname_race=="black"),
`Black Men`=mean(gender=="male" & lastname_race=="black"),
`Asian Women`=mean(gender=="female" & lastname_race=="asian"),
`Asian Men`=mean(gender=="male" & lastname_race=="asian"),
`Hispanic Women`=mean(gender=="female" & lastname_race=="hispanic"),
`Hispanic Men`=mean(gender=="male" & lastname_race=="hispanic"),
`Native Women`=mean(gender=="female" & lastname_race=="american indian"),
`Native Men`=mean(gender=="male" & lastname_race=="american indian"))%>%pivot_longer(2:11)
rg<-dfgr%>%ggplot(aes(x=year, y=value, fill=name))+
geom_area()+scale_fill_brewer(palette="Paired", name = "")+
scale_y_continuous(labels=scales::percent)+theme_minimal(base_family = "Palatino")+theme(plot.title.position = "plot")+
ggtitle("Gender and Race* of NBER Paper Authors")+
labs(x="", y="", caption="*Again, using census and SSA to predict race and gender, respectively.\nOmitting observations without predictions")
#Put them all together
(race+gender)/rg+plot_annotation(title = 'Demographics of NBER Paper Authors, 1980-2021',
theme = theme(plot.title = element_text(size = 22, family="Palatino"))) +
plot_annotation(caption = 'Data: NBER working paper metadata. Plot: Alex Albright.',
theme = theme(plot.caption = element_text(size = 13, family="Palatino")))
ggsave('graphs/authors-nber2.png', dpi=250, width=8, height=8)

Where do econs write about?
Not a lot of counties mentioned. Focus on US states.
paper_words <- nber %>%
unnest_tokens(word, abstract) %>%
count(word, sort = TRUE)
states<-election%>%select(state)%>%
mutate(state=tolower(state))%>%distinct()%>%
filter(state!="district of columbia")
df<-paper_words%>%
filter(word %in% states$state)%>%mutate(state=word)
paper_2words <- nber %>%
unnest_tokens(bigram, abstract, token = "ngrams", n = 2)%>%
count(bigram, sort = TRUE)
df2<-paper_2words%>%
filter(bigram %in% states$state)%>%mutate(state=bigram)
dff<-bind_rows(df, df2)
plot count and count per million in population
statepop$state<-tolower(statepop$full)
dff<-full_join(dff, statepop)
Joining, by = "state"
dff<-dff%>%
mutate(n=replace_na(n, 0))%>%
mutate(popm=pop_2015/1000000)%>%
mutate(nperm=n/popm)
library(statebins)
#the united states of nber papers
a<-statebins(state_data = dff, state_col = "full", value_col = "n",
ggplot2_scale_function = viridis::scale_fill_viridis)+
theme_void(base_family = "Palatino", base_size = 14)+ theme(legend.title = element_blank())+
ggtitle("# of NBER abstract mentions")
b<-statebins(state_data = dff, state_col = "full", value_col = "nperm",
ggplot2_scale_function = viridis::scale_fill_viridis)+
theme_void(base_family = "Palatino", base_size = 14)+ theme(legend.title = element_blank())+ #plot.title = element_text(hjust = 0.5))+
ggtitle("# of NBER abstract mentions per million residents*")+
labs(caption="*population #s from 2015")
library(patchwork)
a/b+
plot_annotation(title = 'The United States of NBER Papers',
theme = theme(plot.title = element_text(size = 25, family="Palatino"))) +
plot_annotation(caption = 'Data: NBER working paper metadata. Plot: Alex Albright.',
theme = theme(plot.caption = element_text(size = 16, family="Palatino")))
ggsave('graphs/states-nber1.png', dpi=250, width=7, height=10)

LS0tCnRpdGxlOiAiTWV0YXBsb3RzIHVzaW5nIG1ldGFkYXRhIgphdXRob3I6IEFsZXggQWxicmlnaHQKZGF0ZTogSnVuZSAyOCAyMDIxCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMgR2V0dGluZyBOQkVSIG1ldGFkYXRhCgpOQkVSIGZvbGtzIHJlY29tbWVuZCBkb3dubG9hZGluZyBbdGhpcyAudGFiIGZpbGVdKGh0dHBzOi8vZGF0YS5uYmVyLm9yZy9uYmVyLXdwLWxvZ3Mvd29ya2luZ19wYXBlcnMudGFiKS4KCllvdSBjYW4gYWxzbyBkb3dubG9hZCBOQkVSIG1ldGFkYXRhIGFzIC50eHQgZmlsZXMgZnJvbSBbaGVyZV0oaHR0cHM6Ly93d3cyLm5iZXIub3JnL3dwX21ldGFkYXRhKS4KKFRoZSBpc3N1ZSB3aXRoIHRoZSAudHh0IGZpbGVzIGlzIHRoYXQgdGhleSBvZnRlbiBhcmUgbWlzc2luZyBkYXRlcywgd2hpY2ggSSB3YW50IGZvciBhIGxvdCBvZiBwbG90cy4pIAoKSSdsbCB1c2UgdGhlIHRhYiBmaWxlIGFuZCB0aGVuIHVzZSB0aGUgYXV0aG9ycyB0ZXh0IGZpbGUgZm9yIHdoZW4gSSBnZXQgaW50byBhdXRob3IgZGVtb2dyYXBoaWNzLiAKCkkgYGZyZWFkYCBkaXJlY3RseSBmcm9tIHRoZSBOQkVSIFVSTHMuIEknbSBkb2luZyB0aGlzIG9uIDYvMjgvMjEsIGJ1dCBpZiB5b3UncmUgcnVubmluZyB0aGlzIGxhdGVyLCB0aGUgb3V0cHV0IHdpbGwgYmUgc2xpZ2h0bHkgZGlmZmVyZW50IHNpbmNlIG1vcmUgcGFwZXJzIHdpbGwgYmUgaW5jbHVkZWQgaW4gdGhlIHJhdyBkYXRhLiAKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkoZGF0YS50YWJsZSk7bGlicmFyeShwcmVkaWN0cmFjZSk7bGlicmFyeSh0aWR5dmVyc2UpO2xpYnJhcnkodGlkeXIpCmxpYnJhcnkodGlkeXRleHQpO2xpYnJhcnkocXVpY2twYWxldHRlKTtsaWJyYXJ5KHZpcmlkaXMpCmxpYnJhcnkodXNtYXApO2xpYnJhcnkoc29jdml6KQpsaWJyYXJ5KGdncmFwaCk7bGlicmFyeShpZ3JhcGgpCmxpYnJhcnkobHVicmlkYXRlKTtsaWJyYXJ5KHBhdGNod29yaykKCm5iZXI8LSNmcmVhZCgibmJlci1kYXRhL3dvcmtpbmdfcGFwZXJzLnRhYiIsICBxdW90ZSA9ICIiKSU+JQogIGZyZWFkKCJodHRwczovL2RhdGEubmJlci5vcmcvbmJlci13cC1sb2dzL3dvcmtpbmdfcGFwZXJzLnRhYiIsICBxdW90ZSA9ICIiKSU+JQogIGZpbHRlcihhYnN0cmFjdCE9Ik5VTEwiKQpgYGAKCmBgYHtyfQpuYmVyJT4lc2VsZWN0KHBhcGVyKSU+JWRpc3RpbmN0KCklPiVucm93KCkKYGBgCgpUaGVyZSBhcmUgMzAsNDg4IHBhcGVycyBpbiB0aGUgTkJFUiBkYXRhLgoKIyBNb3N0IHBvcHVsYXIgd29yZHMgaW4gZWNvbm9taWNzIHBhcGVycz8KCmBgYHtyfQpwYXBlcl93b3JkcyA8LSBuYmVyICU+JQogIHVubmVzdF90b2tlbnMod29yZCwgYWJzdHJhY3QpICU+JQogIGZpbHRlcighd29yZCAlaW4lIHN0b3Bfd29yZHMkd29yZCklPiUKICBjb3VudCh3b3JkLCBzb3J0ID0gVFJVRSklPiUKICBzbGljZV9tYXgobiwgbiA9IDEwKSAKCnRvdDwtbnJvdyhuYmVyKQoKcGFwZXJfd29yZHMlPiVtdXRhdGUodG90PXRvdCklPiUKICBtdXRhdGUoYGZyYWN0aW9uIG9mIHBhcGVyc2A9cm91bmQobi90b3QsMikpJT4lc2VsZWN0KDEsNCklPiVrbml0cjo6a2FibGUoIm1hcmtkb3duIikKYGBgCgojIERhdGEgdnMgbW9kZWxzPwoKSSB1c2UgdGhlIHNhbWUgd29yZCBzZWFyY2hlcyBhcyBbQ3VycmllLCBLbGV2ZW4sIGFuZCBad2llcnMgKDIwMjApIF0oaHR0cHM6Ly93d3cuYWVhd2ViLm9yZy9hcnRpY2xlcz9pZD0xMC4xMjU3L3BhbmRwLjIwMjAxMDU4KS5eW1NlZSBUYWJsZSBBLkkuIGluIHRoZWlyIG9ubGluZSBhcHBlbmRpeC5dCgpgYGB7cn0KbmJlcjwtbmJlciU+JQogIG11dGF0ZShleD0oc3RyX2RldGVjdChhYnN0cmFjdCwgImV4cGxvaXQiKSksCiAgICAgICAgIGRkPXN0cl9kZXRlY3QoYWJzdHJhY3QsICJEaWZmZXJlbmNlIGluIERpZmZ8RGlmZmVyZW5jZSBpbiBkaWZmfGRpZmZlcmVuY2UgaW4gZGlmZnxEaWZmZXJlbmNlLWluLURpZmZ8RGlmZmVyZW5jZS1pbi1kaWZmfGRpZmZlcmVuY2UtaW4tZGlmZnxEaWZmZXJlbmNlcyBpbiBEaWZmfERpZmZlcmVuY2VzIGluIGRpZmZ8ZGlmZmVyZW5jZXMgaW4gZGlmZnxEaWZmZXJlbmNlcy1pbi1EaWZmfERpZmZlcmVuY2VzLWluLWRpZmZ8ZGlmZmVyZW5jZXMtaW4tZGlmZnxkaWZmLWluLWRpZmZ8ZC1pbi1kfERpRCIpLAogICAgICAgICBldmVudD1zdHJfZGV0ZWN0KGFic3RyYWN0LCAiZXZlbnQgc3R1ZHl8ZXZlbnQtc3R1ZHkiKSwKICAgICAgICAgaXY9c3RyX2RldGVjdChhYnN0cmFjdCwgIkluc3RydW1lbnRhbCBWYXJpYWJsZXxJbnN0cnVtZW50YWwgdmFyaWFibGV8aW5zdHJ1bWVudGFsIHZhcmlhYmxlfEluc3RydW1lbnRhbC1WYXJpYWJsZXxJbnN0cnVtZW50YWwtdmFyaWFibGV8aW5zdHJ1bWVudGFsLXZhcmlhYmxlfFR3byBTdGFnZSBMZWFzdCBTcXVhcmVzfFR3byBzdGFnZSBsZWFzdCBzcXVhcmVzfHR3bwpzdGFnZSBsZWFzdCBzcXVhcmVzfDJTTFN8VFNMU3x2YWxpZCBpbnN0cnVtZW50fGV4b2dlbm91cyBpbnN0cnVtZW50fElWIEVzdGltYXR8SVYgZXN0aW1hdHxJVi1lc3RpbWF0fElWIFNwZWNpZmljYXRpb258SVYgc3BlY2lmaWNhdGlvbnxJVi1zcGVjaWZpY2F0aW9ufElWIFJlZ3Jlc3Npb258SVYgcmVncmVzc2lvbnxJVi1yZWdyZXNzaW9ufElWIFN0cmF0ZWd8SVYgc3RyYXRlZ3xJVi1zdHJhdGVnfHdlIGluc3RydW1lbnR8SSBpbnN0cnVtZW50fHBhcGVyIGluc3RydW1lbnRzfGV4Y2x1c2lvbiByZXN0cmljdGlvbnx3ZWFrIGZpcnN0IHN0YWdlfHNpbXVsYXRlZCBpbnN0cnVtZW50IiksCiAgICAgICAgcmQ9c3RyX2RldGVjdChhYnN0cmFjdCwgIlJlZ3Jlc3Npb24gRGlzY29udGludWl0fFJlZ3Jlc3Npb24gZGlzY29udGludWl0fHJlZ3Jlc3Npb24gZGlzY29udGludWl0fFJlZ3Jlc3Npb24tZGlzY29udGludWl0eXxyZWdyZXNzaW9uLWRpc2NvbnRpbnVpdHl8UmVncmVzc2lvbiBLaW5rfFJlZ3Jlc3Npb24ga2lua3xyZWdyZXNzaW9uIGtpbmt8UkQgRGVzaWdufFJEIGRlc2lnbnxSRC1kZXNpZ258UkQgRXN0aW1hdHxSRCBlc3RpbWF0fFJELWVzdGltYXR8UkQgTW9kZWx8UkQgbW9kZWx8UkQtbW9kZWx8UkQgUmVncmVzc2lvbnxSRCByZWdyZXNzaW9ufFJELXJlZ3Jlc3Npb258UkQgQ29lZmZpY2llbnR8UkQgY29lZmZpY2llbnR8UkQtY29lZmZpY2llbnR8UksgRGVzaWdufFJLIGRlc2lnbnxSSy1EZXNpZ258UkstZGVzaWdufFJLRCIpLAogICAgICAgICBjb3ZpZD1zdHJfZGV0ZWN0KGFic3RyYWN0LCAiY292aWR8Y29yb25hdmlydXN8Q09WSUR8Q292aWR8Q09ST05BVklSVVMiKSwKICAgICAgICAgZGF0YT1zdHJfZGV0ZWN0KGFic3RyYWN0LCAiZGF0YSIpLAogICAgICAgICBtb2RlbD1zdHJfZGV0ZWN0KGFic3RyYWN0LCAibW9kZWwiKSkKYGBgCgpOb3RlOiBJIHVzZSB0aGUge2dndGV4dH0gcGFja2FnZSB0byBjb2xvciB3b3JkcyBpbiB0aGUgdGl0bGUgYW5kIHN1YnRpdGxlLgoKYGBge3J9CmxpYnJhcnkoZ2d0ZXh0KQoKbmJlciU+JW11dGF0ZSh5ZWFyPXllYXIoeW1kKHB1YmxpY19kYXRlKSkpJT4lCiAgZ3JvdXBfYnkoeWVhciklPiVmaWx0ZXIoeWVhcj49MTk4MCklPiUKICBzdW1tYXJpc2UoZGF0YT1tZWFuKGRhdGE9PVQpLAogICAgICAgICAgICBtb2RlbD1tZWFuKG1vZGVsPT1UKSklPiUKICBwaXZvdF9sb25nZXIoMjozKSU+JQogIGdncGxvdChhZXMoeD15ZWFyLCB5PXZhbHVlLCBjb2xvcj1uYW1lLCBsaW5ldHlwZT1uYW1lLCBzaGFwZT1uYW1lKSkrCiAgZ2VvbV9saW5lKCkrZ2VvbV9wb2ludCgpKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiIzAwOUU3MyIsICJncmF5NDAiKSwgbmFtZT0iIikrCiAgbGFicyh4PSIiLCB5PSIiLCBjYXB0aW9uPSJEYXRhOiBOQkVSIHdvcmtpbmcgcGFwZXIgbWV0YWRhdGEuIFBsb3Q6IEFsZXggQWxicmlnaHQuIiwKICAgICAgIHRpdGxlPSI8c3BhbiBzdHlsZSA9ICdmb250LXNpemU6MjJwdCc+PHNwYW4gc3R5bGUgPSAnY29sb3I6IzAwOUU3MzsnPkRhdGE8L3NwYW4+IGhhcyBvdmVydGFrZW4gPHNwYW4gc3R5bGUgPSAnY29sb3I6Z3JheTQwOyc+TW9kZWxzPC9zcGFuPjwvc3Bhbj48YnI+ICUgb2YgYWJzdHJhY3RzIGluY2x1ZGluZyB0aGUgd29yZHMgPHNwYW4gc3R5bGUgPSAnY29sb3I6IzAwOUU3MzsnPidkYXRhJzwvc3Bhbj4gb3IgPHNwYW4gc3R5bGUgPSAnY29sb3I6Z3JheTQwOyc+J21vZGVsJzwvc3Bhbj4iKSsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPXNjYWxlczo6cGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSAxKSwgYnJlYWtzPXNlcSgwLjIsLjYsLjEpLCBsaW1pdHM9YygwLjE4LDAuNSkpKwogIHRoZW1lX21pbmltYWwoYmFzZV9mYW1pbHkgPSAiUGFsYXRpbm8iLCBiYXNlX3NpemUgPSAxNCkrdGhlbWUocGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwbG90IiwgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfbWFya2Rvd24oKSkKZ2dzYXZlKCdncmFwaHMvbW9kZWx2ZGF0YTEucG5nJywgZHBpPTI1MCwgd2lkdGg9NywgaGVpZ2h0PTUpCmBgYAoKIyBNb3N0IHBvcHVsYXIgcXVhc2kgZXhwZXJpbWVudGFsIG1ldGhvZHM/CgpgYGB7cn0KbGlicmFyeSh3ZXNhbmRlcnNvbikKCm5iZXIlPiVtdXRhdGUoeWVhcj15ZWFyKHltZChwdWJsaWNfZGF0ZSkpKSU+JQogIGdyb3VwX2J5KHllYXIpJT4lZmlsdGVyKHllYXI+PTE5ODApJT4lCiAgc3VtbWFyaXNlKElWPW1lYW4oaXY9PVQpLAogICAgICAgICAgICBERD1tZWFuKGRkPT1UKSwKICAgICAgICAgICAgUkQ9bWVhbihyZD09VCkpJT4lCiAgcGl2b3RfbG9uZ2VyKDI6NCklPiUKICBnZ3Bsb3QoYWVzKHg9eWVhciwgeT12YWx1ZSwgY29sb3I9bmFtZSwgbGluZXR5cGU9bmFtZSwgc2hhcGU9bmFtZSkpKwogIGxhYnMoeT0iIiwgeD0iIiwgY2FwdGlvbj0iRGF0YTogTkJFUiB3b3JraW5nIHBhcGVyIG1ldGFkYXRhLiBQbG90OiBBbGV4IEFsYnJpZ2h0LiIpKwogIGdlb21fcG9pbnQoKSsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPXNjYWxlczo6cGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSAxKSkrCiAgZ2VvbV9saW5lKCkrZ2d0aXRsZSgiREQgb3ZlcnRha2VzIElWIGFzIHF1YXNpLWV4cGVyaW1lbnRhbCBxdWVlbiIsCiAgICAgICAgICAgICAgICAgICAgICBzdWJ0aXRsZT0iJSBvZiBhYnN0cmFjdHMgdXNpbmcgcXVhc2ktZXhwZXJpbWVudGFsIG1ldGhvZCB3b3JkcyIpKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9d2VzX3BhbGV0dGUoIkRhcmplZWxpbmcxIiwgNCwgdHlwZT0iZGlzY3JldGUiKSkrCiAgdGhlbWVfbWluaW1hbChiYXNlX2ZhbWlseSA9ICJQYWxhdGlubyIsIGJhc2Vfc2l6ZT0xNSkrCiAgdGhlbWUocGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwbG90IiwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpCgpnZ3NhdmUoJ2dyYXBocy9xdWFzaS1leHAtbWV0aG9kczEucG5nJywgZHBpPTI1MCwgd2lkdGg9Ny41LCBoZWlnaHQ9NSkKYGBgCgojIFVzaW5nIHRoZSB3b3JkICdleHBsb2l0JwoKRm9yIG1vcmUgbi1ncmFtIGV4YW1wbGVzIHNlZSBbVGV4dCBNaW5pbmcgd2l0aCBSXShodHRwczovL3d3dy50aWR5dGV4dG1pbmluZy5jb20vbmdyYW1zLmh0bWwpCgpgYGB7cn0KdGltZTwtbmJlciU+JW11dGF0ZSh5ZWFyPXllYXIoeW1kKHB1YmxpY19kYXRlKSkpJT4lCiAgZ3JvdXBfYnkoeWVhciklPiVmaWx0ZXIoeWVhcj49MTk4MCklPiUKICBzdW1tYXJpc2UoZXhwPW1lYW4oZXg9PVQpKSU+JQogIGdncGxvdChhZXMoeD15ZWFyLCB5PWV4cCkpKwogIGdlb21fbGluZSgpK2dlb21fcG9pbnQoKSsKICBnZW9tX2xpbmUoKStnZ3RpdGxlKCIlIGFic3RyYWN0cyB0aGF0IHVzZSB0aGUgd29yZCAnZXhwbG9pdCciKStsYWJzKHg9IiIsIHk9IiIpKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9c2NhbGVzOjpwZXJjZW50X2Zvcm1hdChhY2N1cmFjeSA9IDEpLCBicmVha3M9c2VxKDAsLjA4LC4wMiksIGxpbWl0cz1jKDAsMC4wOCkpKwogIHRoZW1lX21pbmltYWwoYmFzZV9mYW1pbHkgPSAiUGFsYXRpbm8iLCBiYXNlX3NpemUgPSAxNCkrdGhlbWUocGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwbG90IikKCmFic19iaSA8LSBuYmVyICU+JQogIHVubmVzdF90b2tlbnMoYmlncmFtLCBhYnN0cmFjdCwgdG9rZW4gPSAibmdyYW1zIiwgbiA9IDMpCgphYnNfYmklPiUKICBjb3VudChiaWdyYW0sIHNvcnQgPSBUUlVFKQoKYmlncmFtc19zZXBhcmF0ZWQgPC0gYWJzX2JpICU+JQogIHNlcGFyYXRlKGJpZ3JhbSwgYygid29yZDEiLCAid29yZDIiLCAid29yZDMiKSwgc2VwID0gIiAiKQoKYmlncmFtc19maWx0ZXJlZCA8LSBiaWdyYW1zX3NlcGFyYXRlZCAlPiUKICBmaWx0ZXIoc3RyX2RldGVjdCh3b3JkMSwgImV4cGxvaXQiKSkKCiMgbmV3IGJpZ3JhbSBjb3VudHM6CmJpZ3JhbV9jb3VudHMgPC0gYmlncmFtc19maWx0ZXJlZCAlPiUgCiAgbXV0YXRlKHdvcmQxPSJleHBsb2l0IiklPiUKICBtdXRhdGUod29yZDI9aWZfZWxzZSh3b3JkMj09InRoZSJ8d29yZDI9PSJhbiJ8d29yZDI9PSJhInx3b3JkMj09InRoaXMifHdvcmQyPT0ib2YifHdvcmQyPT0idGhlc2UifHdvcmQyPT0idGhlaXIiLCB3b3JkMywgd29yZDIpKSU+JQogIHNlbGVjdCh3b3JkMSwgd29yZDIpJT4lCiAgY291bnQod29yZDEsIHdvcmQyLCBzb3J0ID0gVFJVRSkKICAKYmlncmFtX2dyYXBoIDwtIGJpZ3JhbV9jb3VudHMgJT4lCiAgZmlsdGVyKG4gPj0gMTUpICU+JQogIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSgpCgpzZXQuc2VlZCgyMDA5KQphIDwtIGdyaWQ6OmFycm93KHR5cGUgPSAiY2xvc2VkIiwgbGVuZ3RoID0gdW5pdCguMTUsICJpbmNoZXMiKSkKCm5ldDwtZ2dyYXBoKGJpZ3JhbV9ncmFwaCwgbGF5b3V0ID0gImZyIikgKwogIGdlb21fZWRnZV9saW5rKGFlcyhlZGdlX2FscGhhID0gbiksIHNob3cubGVnZW5kID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgYXJyb3cgPSBhLCBlbmRfY2FwID0gY2lyY2xlKC4wNywgJ2luY2hlcycpKSArCiAgZ2VvbV9ub2RlX3BvaW50KGNvbG9yID0gImxpZ2h0Ymx1ZSIsIHNpemUgPSA1KSArCiAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gbmFtZSwgZmFtaWx5PSJQYWxhdGlubyIpLCB2anVzdCA9IDAsIGhqdXN0ID0gMSkgKwogIHRoZW1lX3ZvaWQoYmFzZV9mYW1pbHkgPSAiUGFsYXRpbm8iLCBiYXNlX3NpemUgPSAxMikrCiAgZ2d0aXRsZSgiTW9zdCBjb21tb24gd29yZHMgZm9sbG93aW5nICdleHBsb2l0JyIpKwogIHRoZW1lKHBsb3QudGl0bGUucG9zaXRpb24gPSAicGxvdCIpCgp0aW1lL25ldCsKICBwbG90X2Fubm90YXRpb24odGl0bGUgPSAiRWNvbm9taXN0cyBsb3ZlICdleHBsb2l0aW5nJyB2YXJpYXRpb24iLAogICAgICAgICAgICAgICAgICAgIHRoZW1lID0gdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjIsIGZhbWlseT0iUGFsYXRpbm8iKSkpICsKICBwbG90X2Fubm90YXRpb24oY2FwdGlvbiA9ICdJZ25vcmluZyBnZW5lcmljIHdvcmRzOiBhLCBhbiwgdGhpcywgdGhlc2UsIHRoZSwgb2YsIHRoZWlyXG5EYXRhOiBOQkVSIHdvcmtpbmcgcGFwZXIgbWV0YWRhdGEuIFBsb3Q6IEFsZXggQWxicmlnaHQuJywKICAgICAgICAgICAgICAgICAgICB0aGVtZSA9IHRoZW1lKHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dChzaXplID0gMTMsIGZhbWlseT0iUGFsYXRpbm8iKSkpIAogIAoKZ2dzYXZlKCdncmFwaHMvZWNvbi1leHBsb2l0Mi5wbmcnLCBkcGk9MjUwLCB3aWR0aD05LjUsIGhlaWdodD05KQpgYGAKCiMgQ292aWQgcGxvdAoKYGBge3J9Cm5iZXIlPiVtdXRhdGUobXk9Zmxvb3JfZGF0ZSh5bWQocHVibGljX2RhdGUpLCAibW9udGgiKSklPiUKICBncm91cF9ieShteSklPiVmaWx0ZXIobXk+PSIyMDE4LTAxLTAxIiklPiUKICBzdW1tYXJpc2UoY292aWQ9bWVhbihjb3ZpZD09VCkpJT4lCiAgZ2dwbG90KGFlcyh4PW15LCB5PWNvdmlkKSkrCiAgZ2VvbV9saW5lKCkrZ2VvbV9wb2ludCgpK2xhYnMoeD0iIiwgeT0iIiwgY2FwdGlvbiA9ICJEYXRhOiBOQkVSIHdvcmtpbmcgcGFwZXIgbWV0YWRhdGEuIFBsb3Q6IEFsZXggQWxicmlnaHQuIikrCiAgZ2d0aXRsZSgiJSBvZiBhYnN0cmFjdHMgdGhhdCBpbmNsdWRlICdjb3ZpZC9jb3JvbmF2aXJ1cyciKSsKICBzY2FsZV94X2RhdGUoKSsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPXNjYWxlczo6cGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSAxKSwgYnJlYWtzPXNlcSgwLC4zLC4wNSksIGxpbWl0cz1jKDAsMC4zKSkrCiAgdGhlbWVfbWluaW1hbChiYXNlX2ZhbWlseSA9ICJQYWxhdGlubyIsIGJhc2Vfc2l6ZSA9IDE0KSt0aGVtZShwbG90LnRpdGxlLnBvc2l0aW9uID0gInBsb3QiKQoKZ2dzYXZlKCdncmFwaHMvY292aWQxLnBuZycsIGRwaT0yNTAsIHdpZHRoPTcsIGhlaWdodD00KQpgYGAKCiMgRWNvbiBwYXBlciB0aXRsZSBjb252ZW50aW9ucwoKYGBge3J9Cm5iZXIkcT1pZl9lbHNlKGdyZXBsKCJcXD8iLCBuYmVyJHRpdGxlKSwgMSwgMCkKbmJlciRjb2xvbj1pZl9lbHNlKGdyZXBsKCJcXDoiLCBuYmVyJHRpdGxlKSwgMSwgMCkKCm5iZXIlPiVzdW1tYXJpc2UoYHRpdGxlIHcvIHF1ZXN0aW9uYD1tZWFuKHE9PTEpLCAKICAgICAgICAgICAgICAgICAgYHRpdGxlIHcvIGNvbG9uYD1tZWFuKGNvbG9uPT0xKSwgCiAgICAgICAgICAgICAgICAgYHRpdGxlIHcvIHF1ZXN0aW9uIG9yIGNvbG9uYD1tZWFuKHE9PTEgfCBjb2xvbj09MSksCiAgICAgICAgICAgICAgICAgIGB0aXRsZSB3LyBxdWVzdGlvbiBhbmQgY29sb25gPW1lYW4ocT09MSAmIGNvbG9uPT0xKSklPiUKICBwaXZvdF9sb25nZXIoMTo0KSU+JW11dGF0ZSh2YWx1ZT1yb3VuZCh2YWx1ZSwyKSklPiUKICByZW5hbWUoY29udmVudGlvbj1uYW1lLCBgZnJhY3Rpb24gb2YgcGFwZXJzYD12YWx1ZSklPiVrbml0cjo6a2FibGUoIm1hcmtkb3duIikKYGBgCgozNCUgdXNlIDpzIGFuZCAxMyUgdXNlIHF1ZXN0aW9uIG1hcmtzISA0NSUgZG8gb25lIG9mIHRoZSB0d28uCgojIENvbW1vbiBiaWdyYW1zCgpgYGB7cn0KYWJzX2JpIDwtIG5iZXIgJT4lCiAgdW5uZXN0X3Rva2VucyhiaWdyYW0sIGFic3RyYWN0LCB0b2tlbiA9ICJuZ3JhbXMiLCBuID0gMikKCmJpZ3JhbXNfc2VwYXJhdGVkIDwtIGFic19iaSAlPiUKICBzZXBhcmF0ZShiaWdyYW0sIGMoIndvcmQxIiwgIndvcmQyIiksIHNlcCA9ICIgIikKCmJpZ3JhbXNfZmlsdGVyZWQgPC0gYmlncmFtc19zZXBhcmF0ZWQgJT4lCiAgZmlsdGVyKCF3b3JkMSAlaW4lIHN0b3Bfd29yZHMkd29yZCkgJT4lCiAgZmlsdGVyKCF3b3JkMiAlaW4lIHN0b3Bfd29yZHMkd29yZCkKCiMgbmV3IGJpZ3JhbSBjb3VudHM6CmJpZ3JhbV9jb3VudHMgPC0gYmlncmFtc19maWx0ZXJlZCAlPiUgCiAgY291bnQod29yZDEsIHdvcmQyLCBzb3J0ID0gVFJVRSkKCiNtYWtlIGdyYXBoCmJpZ3JhbV9ncmFwaCA8LSBiaWdyYW1fY291bnRzICU+JQogIGZpbHRlcighaXMubmEod29yZDEpKSU+JQogIGZpbHRlcihuID49IDUwMCkgJT4lCiAgZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKCkKCnNldC5zZWVkKDIwMTApCmEgPC0gZ3JpZDo6YXJyb3codHlwZSA9ICJjbG9zZWQiLCBsZW5ndGggPSB1bml0KC4xNSwgImluY2hlcyIpKQoKZ2dyYXBoKGJpZ3JhbV9ncmFwaCwgbGF5b3V0ID0gImZyIikgKwogIGdlb21fZWRnZV9saW5rKGFlcyhlZGdlX2FscGhhID0gbiksIHNob3cubGVnZW5kID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgYXJyb3cgPSBhLCBlbmRfY2FwID0gY2lyY2xlKC4wNywgJ2luY2hlcycpKSArCiAgZ2VvbV9ub2RlX3BvaW50KGNvbG9yID0gImxpZ2h0Ymx1ZSIsIHNpemUgPSA1KSArCiAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gbmFtZSwgZmFtaWx5PSJQYWxhdGlubyIpLCB2anVzdCA9IDAsIGhqdXN0ID0gMSkgKwogIHRoZW1lX3ZvaWQoKSsKICBnZ3RpdGxlKCJDb21tb24gYmlncmFtcyBpbiBOQkVSIFdQIGFic3RyYWN0cyIsIHN1YnRpdGxlPSJMaW1pdCB0byBiaWdyYW1zIHdpdGggNTAwKyBvYnNlcnZhdGlvbnMiKSsKICBsYWJzKGNhcHRpb249IkV4Y2x1ZGluZyBzdG9wIHdvcmRzLlxuRGF0YTogTkJFUiB3b3JraW5nIHBhcGVyIG1ldGFkYXRhLiBQbG90OiBBbGV4IEFsYnJpZ2h0LiIpKwogIHRoZW1lKHRleHQ9ZWxlbWVudF90ZXh0KGZhbWlseT0iUGFsYXRpbm8iLCBzaXplID0gMjApKQogIApnZ3NhdmUoJ2dyYXBocy9iaWdyYW1zMi5wbmcnLCBkcGk9MjUwLCB3aWR0aD0xMC41LCBoZWlnaHQ9NykKYGBgCgojIFdobyBhcmUgdGhlIGF1dGhvcnM/CgpVc2UgW3RoaXMge3ByZWRpY3QgcmFjZX1dKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9wcmVkaWN0cmFjZS92aWduZXR0ZXMvUHJlZGljdC1yYWNlLW9mLXN1cm5hbWUuaHRtbCkgcGFja2FnZSBmcm9tIEphY29iIEthcGxhbiB0byBnZXQgcmFjZSBhbmQgZ2VuZGVyIGZyb20gdGhlIGF1dGhvciBuYW1lcy4KCkxldCdzIHVzZSB0aGUgY2xlYW5lciBhdXRob3IgLnR4dCBkYXRhIGJ1dCBvbmx5IGtlZXAgdGhvc2UgdGhhdCBsaW5rIHRvIHRoZSBsYXJnZSAudGFiIGZpbGUsIHNvIHdlIGFyZSBwdWxsaW5nIGZyb20gdGhlIHNhbWUgdW5pdmVyc2Ugb2YgcGFwZXJzLgoKYGBge3J9CmF1dGhzPC0jZnJlYWQoIm5iZXItZGF0YS9hdXRocy50eHQiLCBxdW90ZT0iIikKICBmcmVhZCgiaHR0cDovL3d3dzIubmJlci5vcmcvd3BfbWV0YWRhdGEvdHh0L2F1dGhzLnR4dCIsIHF1b3RlID0gIiIpCgpwYXBlcnM8LW5iZXIlPiVzZWxlY3QocGFwZXIsIHB1YmxpY19kYXRlKSU+JWRpc3RpbmN0KCkKYXV0aG9yczwtaW5uZXJfam9pbihhdXRocywgcGFwZXJzKQoKI3NlcGFyYXRlIG91dCBuYW1lIGludG8gZmlyc3QgYW5kIGxhc3QKYXV0aG9yczwtYXV0aG9ycyU+JQogIG11dGF0ZShsYXN0bmFtZT13b3JkKG5hbWUsIC0xKSwgZmlyc3RuYW1lPXdvcmQobmFtZSwgLTIpKQoKZGY8LWF1dGhvcnMlPiUKICBtdXRhdGUoZmlyc3RuYW1lX3JhY2U9cHJlZGljdF9yYWNlKGZpcnN0bmFtZSwgcHJvYmFiaWxpdHkgPSBGLCBzdXJuYW1lID0gRikkbGlrZWx5X3JhY2UsCiAgICAgICAgIGxhc3RuYW1lX3JhY2U9cHJlZGljdF9yYWNlKGxhc3RuYW1lLCBwcm9iYWJpbGl0eSA9IEYsIHN1cm5hbWUgPSBUKSRsaWtlbHlfcmFjZSwKICAgICAgICAgZ2VuZGVyPXByZWRpY3RfZ2VuZGVyKGZpcnN0bmFtZSwgcHJvYmFiaWxpdHkgPSBGKSRsaWtlbHlfZ2VuZGVyKQpgYGAKCk5vdCB3ZWlnaHRpbmcgYnkgcGFwZXI6IHVuaXF1ZSBjb3VudCBvZiBhdXRob3JzIHBlciB5ZWFyCgpgYGB7cn0KZGY8LWRmJT4lCiAgbXV0YXRlKHllYXI9eWVhcih5bWQocHVibGljX2RhdGUpKSklPiUKICBzZWxlY3QoLWMocGFwZXIsIHB1YmxpY19kYXRlKSklPiVkaXN0aW5jdCgpCmBgYAoKSW4gMjAyMCwgCgp3aGF0ICUgbm9ud2hpdGUgYXV0aG9ycz8gMzAlCgpgYGB7cn0KbnJvdyhzdWJzZXQoZGYsIHllYXI9PTIwMjAgJiAhaXMubmEobGFzdG5hbWVfcmFjZSkgJiAobGFzdG5hbWVfcmFjZSE9IndoaXRlIikpKS9ucm93KHN1YnNldChkZiwgeWVhcj09MjAyMCAmIWlzLm5hKGxhc3RuYW1lX3JhY2UpKSkKYGBgCgp3aGF0ICUgYmxhY2svaGlzcGFuaWMvbmF0aXZlIGFtZXJpY2FuIGF1dGhvcnM/IDYlIAoKYGBge3J9Cm5yb3coc3Vic2V0KGRmLCB5ZWFyPT0yMDIwICYgIWlzLm5hKGxhc3RuYW1lX3JhY2UpICYgKGxhc3RuYW1lX3JhY2U9PSJibGFjayIgfCBsYXN0bmFtZV9yYWNlPT0iaGlzcGFuaWMiIHwgbGFzdG5hbWVfcmFjZT09ImFtZXJpY2FuIGluZGlhbiIpKSkvbnJvdyhzdWJzZXQoZGYsIHllYXI9PTIwMjAgJiFpcy5uYShsYXN0bmFtZV9yYWNlKSkpCmBgYAoKd2hhdCAlIHdvbWVuPyAyOCUKCmBgYHtyfQpucm93KHN1YnNldChkZiwgeWVhcj09MjAyMCAmIGdlbmRlcj09ImZlbWFsZSIgJiFpcy5uYShnZW5kZXIpKSkvbnJvdyhzdWJzZXQoZGYsIHllYXI9PTIwMjAgJiFpcy5uYShnZW5kZXIpKSkKYGBgCgpgYGB7cn0KbGlicmFyeShsdWJyaWRhdGUpCgojIFJBQ0UKCmRmcjwtZGYlPiVmaWx0ZXIoeWVhcj49MTk4MCklPiUKICBncm91cF9ieSh5ZWFyKSU+JWZpbHRlcighaXMubmEoZ2VuZGVyKSAmICFpcy5uYShsYXN0bmFtZV9yYWNlKSklPiUKICBzdW1tYXJpc2UoYFdoaXRlYD1tZWFuKGxhc3RuYW1lX3JhY2U9PSJ3aGl0ZSIpLAogICAgICAgICAgICBgQmxhY2tgPW1lYW4obGFzdG5hbWVfcmFjZT09ImJsYWNrIiksCiAgICAgICAgICAgIGBBc2lhbmA9bWVhbihsYXN0bmFtZV9yYWNlPT0iYXNpYW4iKSwKICAgICAgICAgICAgYEhpc3BhbmljYD1tZWFuKGxhc3RuYW1lX3JhY2U9PSJoaXNwYW5pYyIpLAogICAgICAgICAgICBgTmF0aXZlYD1tZWFuKGxhc3RuYW1lX3JhY2U9PSJhbWVyaWNhbiBpbmRpYW4iKSklPiVwaXZvdF9sb25nZXIoMjo2KQoKcmFjZTwtZGZyJT4lZ2dwbG90KGFlcyh4PXllYXIsIHk9dmFsdWUsIGZpbGw9bmFtZSkpKwogIGdlb21fYXJlYSgpK3NjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCIjQTZDRUUzIiwgIiNCMkRGOEEiLCAiI0Y4OUE5OSIsICIjRkFCRjZGIiwgIiNDQUIyRDYiKSwgbmFtZT0iIikrCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1zY2FsZXM6OnBlcmNlbnQpK3RoZW1lX21pbmltYWwoYmFzZV9mYW1pbHkgPSAiUGFsYXRpbm8iKSsKICB0aGVtZShwbG90LnRpdGxlLnBvc2l0aW9uID0gInBsb3QiKSsKICBnZ3RpdGxlKCJSYWNlKiBvZiBOQkVSIFBhcGVyIEF1dGhvcnMiKSsKICBsYWJzKHg9IiIsIHk9IiIsIGNhcHRpb249IipQcmVkaWN0ZWQgZnJvbSBsYXN0IG5hbWUgdXNpbmcgQ2Vuc3VzIGRhdGEuXG5PbWl0dGluZyBhdXRob3JzIHdpdGhvdXQgcHJlZGljdGlvbnMuIikKCiNHRU5ERVIKCmRmZzwtZGYlPiVmaWx0ZXIoeWVhcj49MTk4MCklPiUKICBncm91cF9ieSh5ZWFyKSU+JWZpbHRlcighaXMubmEoZ2VuZGVyKSAmICFpcy5uYShsYXN0bmFtZV9yYWNlKSklPiUKICBzdW1tYXJpc2UoYE1lbmA9bWVhbihnZW5kZXI9PSJtYWxlIiksCiAgICAgICAgICAgIGBXb21lbmA9bWVhbihnZW5kZXI9PSJmZW1hbGUiKSklPiVwaXZvdF9sb25nZXIoMjozKQoKZ2VuZGVyPC1kZmclPiVnZ3Bsb3QoYWVzKHg9eWVhciwgeT12YWx1ZSwgZmlsbD1uYW1lKSkrCiAgZ2VvbV9hcmVhKCkrc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoImdyYXk4MCIsICJncmF5MzAiKSwgbmFtZT0iIikrCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1zY2FsZXM6OnBlcmNlbnQpK3RoZW1lX21pbmltYWwoYmFzZV9mYW1pbHkgPSAiUGFsYXRpbm8iKSsKICB0aGVtZShwbG90LnRpdGxlLnBvc2l0aW9uID0gInBsb3QiKSsKICBnZ3RpdGxlKCJHZW5kZXIqIG9mIE5CRVIgUGFwZXIgQXV0aG9ycyIpKwogIGxhYnMoeD0iIiwgeT0iIiwgY2FwdGlvbj0iKlByZWRpY3RlZCBmcm9tIGZpcnN0IG5hbWUgdXNpbmdcbiBVUyBTb2NpYWwgU2VjdXJpdHkgQWRtaW4gRGF0YS5cbk9taXR0aW5nIGF1dGhvcnMgd2l0aG91dCBwcmVkaWN0aW9ucy4iKQoKI0dFTkRFUiBBTkQgUkFDRQoKZGZncjwtZGYlPiVmaWx0ZXIoeWVhcj49MTk4MCklPiUKICBncm91cF9ieSh5ZWFyKSU+JWZpbHRlcighaXMubmEoZ2VuZGVyKSAmICFpcy5uYShsYXN0bmFtZV9yYWNlKSklPiUKICBzdW1tYXJpc2UoYFdoaXRlIE1lbmA9bWVhbihnZW5kZXI9PSJtYWxlIiAmIGxhc3RuYW1lX3JhY2U9PSJ3aGl0ZSIpLAogICAgICAgICAgICBgV2hpdGUgV29tZW5gPW1lYW4oZ2VuZGVyPT0iZmVtYWxlIiAmIGxhc3RuYW1lX3JhY2U9PSJ3aGl0ZSIpLAogICAgICAgICAgICBgQmxhY2sgV29tZW5gPW1lYW4oZ2VuZGVyPT0iZmVtYWxlIiAmIGxhc3RuYW1lX3JhY2U9PSJibGFjayIpLAogICAgICAgICAgICBgQmxhY2sgTWVuYD1tZWFuKGdlbmRlcj09Im1hbGUiICYgbGFzdG5hbWVfcmFjZT09ImJsYWNrIiksCiAgICAgICAgICAgIGBBc2lhbiBXb21lbmA9bWVhbihnZW5kZXI9PSJmZW1hbGUiICYgbGFzdG5hbWVfcmFjZT09ImFzaWFuIiksCiAgICAgICAgICAgIGBBc2lhbiBNZW5gPW1lYW4oZ2VuZGVyPT0ibWFsZSIgJiBsYXN0bmFtZV9yYWNlPT0iYXNpYW4iKSwKICAgICAgICAgICAgYEhpc3BhbmljIFdvbWVuYD1tZWFuKGdlbmRlcj09ImZlbWFsZSIgJiBsYXN0bmFtZV9yYWNlPT0iaGlzcGFuaWMiKSwKICAgICAgICAgICAgYEhpc3BhbmljIE1lbmA9bWVhbihnZW5kZXI9PSJtYWxlIiAmIGxhc3RuYW1lX3JhY2U9PSJoaXNwYW5pYyIpLAogICAgICAgICAgICBgTmF0aXZlIFdvbWVuYD1tZWFuKGdlbmRlcj09ImZlbWFsZSIgJiBsYXN0bmFtZV9yYWNlPT0iYW1lcmljYW4gaW5kaWFuIiksCiAgICAgICAgICAgIGBOYXRpdmUgTWVuYD1tZWFuKGdlbmRlcj09Im1hbGUiICYgbGFzdG5hbWVfcmFjZT09ImFtZXJpY2FuIGluZGlhbiIpKSU+JXBpdm90X2xvbmdlcigyOjExKQoKcmc8LWRmZ3IlPiVnZ3Bsb3QoYWVzKHg9eWVhciwgeT12YWx1ZSwgZmlsbD1uYW1lKSkrCiAgZ2VvbV9hcmVhKCkrc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZT0iUGFpcmVkIiwgbmFtZSA9ICIiKSsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPXNjYWxlczo6cGVyY2VudCkrdGhlbWVfbWluaW1hbChiYXNlX2ZhbWlseSA9ICJQYWxhdGlubyIpK3RoZW1lKHBsb3QudGl0bGUucG9zaXRpb24gPSAicGxvdCIpKwogIGdndGl0bGUoIkdlbmRlciBhbmQgUmFjZSogb2YgTkJFUiBQYXBlciBBdXRob3JzIikrCiAgbGFicyh4PSIiLCB5PSIiLCBjYXB0aW9uPSIqQWdhaW4sIHVzaW5nIGNlbnN1cyBhbmQgU1NBIHRvIHByZWRpY3QgcmFjZSBhbmQgZ2VuZGVyLCByZXNwZWN0aXZlbHkuXG5PbWl0dGluZyBvYnNlcnZhdGlvbnMgd2l0aG91dCBwcmVkaWN0aW9ucyIpCgojUHV0IHRoZW0gYWxsIHRvZ2V0aGVyCgoocmFjZStnZW5kZXIpL3JnK3Bsb3RfYW5ub3RhdGlvbih0aXRsZSA9ICdEZW1vZ3JhcGhpY3Mgb2YgTkJFUiBQYXBlciBBdXRob3JzLCAxOTgwLTIwMjEnLAogICAgICAgICAgICAgICAgICAgIHRoZW1lID0gdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjIsIGZhbWlseT0iUGFsYXRpbm8iKSkpICsKICBwbG90X2Fubm90YXRpb24oY2FwdGlvbiA9ICdEYXRhOiBOQkVSIHdvcmtpbmcgcGFwZXIgbWV0YWRhdGEuIFBsb3Q6IEFsZXggQWxicmlnaHQuJywKICAgICAgICAgICAgICAgICAgICB0aGVtZSA9IHRoZW1lKHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dChzaXplID0gMTMsIGZhbWlseT0iUGFsYXRpbm8iKSkpIAogIAoKZ2dzYXZlKCdncmFwaHMvYXV0aG9ycy1uYmVyMi5wbmcnLCBkcGk9MjUwLCB3aWR0aD04LCBoZWlnaHQ9OCkKYGBgCgojIFdoZXJlIGRvIGVjb25zIHdyaXRlIGFib3V0PwoKTm90IGEgbG90IG9mIGNvdW50aWVzIG1lbnRpb25lZC4gRm9jdXMgb24gVVMgc3RhdGVzLgoKYGBge3J9CnBhcGVyX3dvcmRzIDwtIG5iZXIgJT4lCiAgdW5uZXN0X3Rva2Vucyh3b3JkLCBhYnN0cmFjdCkgJT4lCiAgY291bnQod29yZCwgc29ydCA9IFRSVUUpCgpzdGF0ZXM8LWVsZWN0aW9uJT4lc2VsZWN0KHN0YXRlKSU+JQogIG11dGF0ZShzdGF0ZT10b2xvd2VyKHN0YXRlKSklPiVkaXN0aW5jdCgpJT4lCiAgZmlsdGVyKHN0YXRlIT0iZGlzdHJpY3Qgb2YgY29sdW1iaWEiKQoKZGY8LXBhcGVyX3dvcmRzJT4lCiAgZmlsdGVyKHdvcmQgJWluJSBzdGF0ZXMkc3RhdGUpJT4lbXV0YXRlKHN0YXRlPXdvcmQpCgpwYXBlcl8yd29yZHMgPC0gbmJlciAlPiUKICB1bm5lc3RfdG9rZW5zKGJpZ3JhbSwgYWJzdHJhY3QsIHRva2VuID0gIm5ncmFtcyIsIG4gPSAyKSU+JQogIGNvdW50KGJpZ3JhbSwgc29ydCA9IFRSVUUpCgpkZjI8LXBhcGVyXzJ3b3JkcyU+JQogIGZpbHRlcihiaWdyYW0gJWluJSBzdGF0ZXMkc3RhdGUpJT4lbXV0YXRlKHN0YXRlPWJpZ3JhbSkKCmRmZjwtYmluZF9yb3dzKGRmLCBkZjIpCmBgYAoKcGxvdCBjb3VudCBhbmQgY291bnQgcGVyIG1pbGxpb24gaW4gcG9wdWxhdGlvbgoKYGBge3J9CnN0YXRlcG9wJHN0YXRlPC10b2xvd2VyKHN0YXRlcG9wJGZ1bGwpCmRmZjwtZnVsbF9qb2luKGRmZiwgc3RhdGVwb3ApCgpkZmY8LWRmZiU+JQogIG11dGF0ZShuPXJlcGxhY2VfbmEobiwgMCkpJT4lCiAgbXV0YXRlKHBvcG09cG9wXzIwMTUvMTAwMDAwMCklPiUKICBtdXRhdGUobnBlcm09bi9wb3BtKQoKbGlicmFyeShzdGF0ZWJpbnMpCiN0aGUgdW5pdGVkIHN0YXRlcyBvZiBuYmVyIHBhcGVycwoKYTwtc3RhdGViaW5zKHN0YXRlX2RhdGEgPSBkZmYsIHN0YXRlX2NvbCA9ICJmdWxsIiwgdmFsdWVfY29sID0gIm4iLCAKICAgICAgICAgIGdncGxvdDJfc2NhbGVfZnVuY3Rpb24gPSB2aXJpZGlzOjpzY2FsZV9maWxsX3ZpcmlkaXMpKwogIHRoZW1lX3ZvaWQoYmFzZV9mYW1pbHkgPSAiUGFsYXRpbm8iLCBiYXNlX3NpemUgPSAxNCkrIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkrCiAgZ2d0aXRsZSgiIyBvZiBOQkVSIGFic3RyYWN0IG1lbnRpb25zIikKCmI8LXN0YXRlYmlucyhzdGF0ZV9kYXRhID0gZGZmLCBzdGF0ZV9jb2wgPSAiZnVsbCIsIHZhbHVlX2NvbCA9ICJucGVybSIsIAogICAgICAgICAgZ2dwbG90Ml9zY2FsZV9mdW5jdGlvbiA9IHZpcmlkaXM6OnNjYWxlX2ZpbGxfdmlyaWRpcykrCiAgdGhlbWVfdm9pZChiYXNlX2ZhbWlseSA9ICJQYWxhdGlubyIsIGJhc2Vfc2l6ZSA9IDE0KSsgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSsgI3Bsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSsKICBnZ3RpdGxlKCIjIG9mIE5CRVIgYWJzdHJhY3QgbWVudGlvbnMgcGVyIG1pbGxpb24gcmVzaWRlbnRzKiIpKwogIGxhYnMoY2FwdGlvbj0iKnBvcHVsYXRpb24gI3MgZnJvbSAyMDE1IikKCmxpYnJhcnkocGF0Y2h3b3JrKQphL2IrCiAgcGxvdF9hbm5vdGF0aW9uKHRpdGxlID0gJ1RoZSBVbml0ZWQgU3RhdGVzIG9mIE5CRVIgUGFwZXJzJywKICAgICAgICAgICAgICAgICAgICB0aGVtZSA9IHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDI1LCBmYW1pbHk9IlBhbGF0aW5vIikpKSArCiAgcGxvdF9hbm5vdGF0aW9uKGNhcHRpb24gPSAnRGF0YTogTkJFUiB3b3JraW5nIHBhcGVyIG1ldGFkYXRhLiBQbG90OiBBbGV4IEFsYnJpZ2h0LicsCiAgICAgICAgICAgICAgICAgICAgdGhlbWUgPSB0aGVtZShwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LCBmYW1pbHk9IlBhbGF0aW5vIikpKSAKICAKCmdnc2F2ZSgnZ3JhcGhzL3N0YXRlcy1uYmVyMS5wbmcnLCBkcGk9MjUwLCB3aWR0aD03LCBoZWlnaHQ9MTApCmBgYA==