Getting NBER metadata

NBER folks recommend downloading this .tab file.

You can also download NBER metadata as .txt files from here. (The issue with the .txt files is that they often are missing dates, which I want for a lot of plots.)

I’ll use the tab file and then use the authors text file for when I get into author demographics.

I fread directly from the NBER URLs. I’m doing this on 6/28/21, but if you’re running this later, the output will be slightly different since more papers will be included in the raw data.

library(data.table);library(predictrace);library(tidyverse);library(tidyr)
library(tidytext);library(quickpalette);library(viridis)
library(usmap);library(socviz)
library(ggraph);library(igraph)
library(lubridate);library(patchwork)

nber<-#fread("nber-data/working_papers.tab",  quote = "")%>%
  fread("https://data.nber.org/nber-wp-logs/working_papers.tab",  quote = "")%>%
  filter(abstract!="NULL")
nber%>%select(paper)%>%distinct()%>%nrow()
[1] 30488

There are 30,488 papers in the NBER data.

Data vs models?

I use the same word searches as Currie, Kleven, and Zwiers (2020).1

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)

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")
convention fraction of papers
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)


  1. See Table A.I. in their online appendix.↩︎

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==