Introduction
In this project, we look at the coverage of Coronavirus on mainstream
news articles and Twitter in the USA. The main goal is to inspect the
difference in the focus of each media outlet (topic modelling) and their
expressed attitudes (sentiment analysis) on COVID-19.
The project is conducted with the following steps: Data collection,
Data cleaning and Pre-processing, Topic modeling, and Sentiment
analysis. The data was gathered using web-scraping technique with R and
Python programming. After data cleaning, the Quanteda package
in R was used to prepare for text analysis. Then, we applied topic
modelling to identify distinct topics. In sentiment analysis, we chose a
lexicon, calculated sentiments scores and looked at the shift in
sentiments.
The result has revealed some disparities between the media sources.
Social media, namely Twitter, are reflecting more on people´s sentiments
and quick updates of the situation while news articles are more about
macro problems. The two media’s sentiment remained negative throughout
the observed period.
Data Collection and Cleaning
News Articles
Using the keyword coronavirus for querying, we collected
news articles published on news websites in the United States from the
beginning of 2020, where the first cases of coronavirus were reported,
until April 19, 2020. For sources, we looked at the top 15 U.S news
websites measured by unique monthly visitors (Statista, 2020), excluding
the news aggregators (Yahoo News, Google News) and topic-specific
newspapers (The Wall Street Journal). We used a third-party API called
Currents API in R to get all the available URLs, then put them
into the newspaper3k module in Python, which enabled scraping the entire
articles. Furthermore, after checking the data quality from each source,
we narrowed them down from 15 to 6 news outlets: CNN, The New York
Times, Fox News, The Guardian, USA Today and The LA Times.
# Load the scraped data
news_data <- read_csv("news_coronavirus.csv")
# Add week and remove unnecessary column
news_data <- news_data %>%
mutate(week = isoweek(publish_date)) %>%
select(-title)
# Preview the data
glimpse(news_data)
Rows: 14,149
Columns: 4
$ publish_date <date> 2020-04-19, 2020-04-19, 2020-04-19, 2020-04-19, 202…
$ source <chr> "CNN", "CNN", "CNN", "CNN", "CNN", "CNN", "CNN", "CN…
$ text <chr> "(CNN) Nothing can bring back the months of wedding …
$ week <dbl> 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, …
Data Overview
For further data cleaning, we removed duplicated data, texts that
were too short and kept only texts written in English. We kept the time
variable in week format and the full text of the document for analysis.
Consequently, 14,149 news articles and 109,329 tweets were ready for
analysis.
The data distribution can be seen below. The number of news reported
on COVID-19 in the U.S were relatively low in the first 6 weeks (week 3
- week 8). However, there was a dramatic increase starting from week 9
and peaked in week 11 and 13 for Twitter and News respectively. This was
the end of March when the number of infected cases in the country
surged.

Pre-processing
For text data preparation, firstly, we created a corpus for the data
set of each source. A corpus consists of a collection of documents (each
document is an article or a tweet), and the document variables which
describe the characteristics of the document, for instance published
date and source. Subsequently, we tokenized each corpus, which separates
the text into its single words (also called terms or tokens). A summary
of the corpus for news articles can be seen below.
corpus_News_data <- corpus(news_data, text_field = c("text"), unique_docnames = F) %>%
`docnames<-`(news_data$week) # update the name of document in the corpus
summary(corpus_News_data, 5)
Corpus consisting of 14149 documents, showing 5 documents:
Text Types Tokens Sentences publish_date source week
16.1 134 190 6 2020-04-19 CNN 16
16.2 92 155 7 2020-04-19 CNN 16
16.3 127 230 8 2020-04-19 CNN 16
16.4 113 192 5 2020-04-19 CNN 16
16.5 581 1509 54 2020-04-19 CNN 16
head(corpus_News_data, 5) # take a look at the corpus
Corpus consisting of 5 documents and 3 docvars.
16.1 :
"(CNN) Nothing can bring back the months of wedding planning ..."
16.2 :
"(CNN) Broadway actor Nick Cordero is recovering after having..."
16.3 :
"(CNN) A Louisiana pastor who defied state orders and repeate..."
16.4 :
"(CNN) More than 100,000 people defied Bangladesh lockdown or..."
16.5 :
"Hong Kong (CNN) Less than a month ago, Singapore was being h..."
corpus_Twitter_data <- corpus(tweets_data, text_field = c("text"), unique_docnames = F) %>%
`docnames<-`(tweets_data$week)
stopwords_extended <- readLines("stopwords_en.txt", encoding = "UTF-8")
lemma_data <- read.csv("baseform_en.tsv", encoding = "UTF-8")
We pre-processed the data sets by lowering upper case letters and
removing the numbers, punctuations, symbols, URLs and separators. The
main idea is to reduce the final amount of terms extracted, which is
important in order to improve the accuracy of both topic modeling and
sentiment analysis. If two words are similar it is convenient to combine
them as one unique word. Moreover, if a word is not relevant for the
analysis, it can be removed. Hence, we implemented stop-words removal
and lemmatization technique. Stopwords are words that appear in texts
but do not give the text a substantial meaning (e.g., “the”, “a”, or
“for”) and lemmatization deals with the inflected forms of words by
replacing them with their base forms. The total number tokens and unique
tokens in each source decreased by 40 – 70% after the above steps:
Token_news_data <- corpus_News_data %>%
tokens(remove_punct = TRUE, remove_numbers = TRUE, remove_symbols = TRUE,
remove_url = TRUE, remove_separators = TRUE) %>%
tokens_tolower(keep_acronyms = FALSE) %>%
tokens_remove(pattern = c("amid", "updates", "live", "video",
"didn", "briefing")) %>%
tokens_replace(lemma_data$inflected_form, lemma_data$lemma,
valuetype = "glob") %>%
tokens_replace(pattern = c("covid-19", "ncov", "cov"),
c("coronavirus", "coronavirus", "coronavirus"),
valuetype = "fixed") %>%
tokens_remove(pattern = stopwords_extended, padding = F)
Token_Twitter_data <- corpus_Twitter_data %>%
tokens(remove_punct = TRUE, remove_numbers = TRUE, remove_symbols = TRUE,
remove_url = TRUE, remove_separators = TRUE) %>%
tokens_tolower(keep_acronyms = FALSE) %>%
tokens_remove(pattern = c("people", "covid19", "covid", "rt", "dont")) %>%
tokens_replace(lemma_data$inflected_form, lemma_data$lemma,
valuetype = "glob") %>%
tokens_remove(pattern = stopwords_extended, padding = T)
In the next step, we generated a document-feature matrix (also known
as document-term matrix) for each source. It represents how frequently
terms (tokens) occur in the corpus (document) by counting single terms.
We kept only the top 5% of the most frequent features (minimum term
frequency set at 0.95) that present in less than 10% of all documents
(maximum document frequency set at 0.1) to focus on common but
distinctive features. We also dismissed the documents that had no tokens
left after trimming. The dimensions of the two document-feature matrices
are as follow:
News_DFM <- Token_news_data %>%
tokens_remove("") %>%
dfm() %>%
dfm_trim(min_termfreq = 0.95, termfreq_type = "quantile",
max_docfreq = 0.1, docfreq_type = "prop")
# We remove the token = 0
News_DFM <- News_DFM[ntoken(News_DFM) > 0, ]
#head(News_DFM, n = 5, nf = 8)
Twitter_DFM <- Token_Twitter_data %>%
tokens_remove("") %>%
dfm() %>%
dfm_trim(min_termfreq = 0.95, termfreq_type = "quantile",
max_docfreq = 0.1, docfreq_type = "prop")
# We remove the token = 0
Twitter_DFM <- Twitter_DFM[ntoken(Twitter_DFM) > 0,]
For better interpretation, the first 3 documents and 10 features of
the document-feature matrix of news articles can be seen below.
News_DFM[1:3, 1:10]
Document-feature matrix of: 3 documents, 10 features (66.67% sparse) and 3 docvars.
features
docs wed waste alleviate engage couple stress beer chance hall postpone
16.1 3 1 1 1 4 1 2 1 1 1
16.2 0 0 0 0 0 0 0 0 0 0
16.3 0 0 0 0 0 0 0 0 0 0
Topic Modelling
We discovered topics distributed in news articles and tweets on a
weekly basis over the three-month period and compared the topics between
the two media outlets. For topic modelling we used Structural Topic
Modeling (STM), since it incorporates metadata (information about each
document) into the topic modelling framework, so that we can discover
topics and estimate their relationship to the documents’ metadata.
STM is an unsupervised machine learning model where we have to define
the number of topic K in advance, similarly to k-means clustering we do
not know ahead how many topics we should use for any given corpus.
Therefore, we trained a group of topic models with different numbers of
K (topics) and then evaluated how many topics are appropriate. Here we
proceeded with K = 25 for each of the media forms. The
evaluation method can be referred to in this post by
Julia Silge.
News_stm <- convert(News_DFM, to = "stm")
Twitter_stm <- convert(Twitter_DFM, to = "stm")
News_topic_model <- stm(
documents = News_stm$documents,
vocab = News_stm$vocab,
K = 25,
prevalence =~ s(week),
data = News_stm$meta,
init.type = "Spectral",
seed = 123456)
Twitter_topic_model <- stm(
documents = Twitter_stm$documents,
vocab = Twitter_stm$vocab,
K = 25,
prevalence =~ s(week),
data = Twitter_stm$meta,
init.type = "Spectral",
seed = 123456)
The plots below show the top 10 topics in each corpus (News,
Twitter), and top 7 words that have the highest probability to belong to
that topic. A closer look into each source showed us some interesting
patterns.
News_beta <- tidy(News_topic_model)
News_gamma <- tidy(News_topic_model, matrix = "gamma")
News_top_terms <- News_beta %>%
arrange(beta) %>%
group_by(topic) %>%
top_n(7, beta) %>%
arrange(-beta) %>%
select(topic, term) %>%
summarise(terms = list(term)) %>%
mutate(terms = map(terms, paste, collapse = ", ")) %>%
unnest()
News_gamma_terms <- News_gamma %>%
group_by(topic) %>%
summarise(gamma = mean(gamma)) %>%
arrange(desc(gamma)) %>%
left_join(News_top_terms, by = "topic") %>%
mutate(topic = paste0("Topic ", topic),
topic = reorder(topic, gamma))
News_gamma_terms %>%
top_n(10, gamma) %>%
ggplot(aes(topic, gamma, label = terms, fill = topic)) +
geom_col(show.legend = FALSE) +
geom_text(hjust = 0.8, nudge_y = 0.0005, size = 3,
family = "IBMPlexSans") +
coord_flip() +
scale_y_continuous(expand = c(0,0),
limits = c(0, 0.09),
labels = percent_format()) +
theme_tufte(base_family = "IBMPlexSans", ticks = FALSE) +
theme(plot.title = element_text(size = 16,
family="IBMPlexSans-Bold"),
plot.subtitle = element_text(size = 13)) +
labs(x = NULL, y = expression(gamma),
title = "Top 10 topics by popularity on News Articles",
subtitle = "With the top words that contribute to each topic")

Twitter_beta <- tidy(Twitter_topic_model)
Twitter_gamma <- tidy(Twitter_topic_model, matrix = "gamma")
Twitter_top_terms <- Twitter_beta %>%
arrange(beta) %>%
group_by(topic) %>%
top_n(7, beta) %>%
arrange(-beta) %>%
select(topic, term) %>%
summarise(terms = list(term)) %>%
mutate(terms = map(terms, paste, collapse = ", ")) %>%
unnest()
Twitter_gamma_terms <- Twitter_gamma %>%
group_by(topic) %>%
summarise(gamma = mean(gamma)) %>%
arrange(desc(gamma)) %>%
left_join(Twitter_top_terms, by = "topic") %>%
mutate(topic = paste0("Topic ", topic),
topic = reorder(topic, gamma))
Twitter_gamma_terms %>%
top_n(10, gamma) %>%
ggplot(aes(topic, gamma, label = terms, fill = topic)) +
geom_col(show.legend = FALSE) +
geom_text(hjust = 0.85, nudge_y = 0.0005, size = 3,
family = "IBMPlexSans") +
coord_flip() +
scale_y_continuous(expand = c(0,0),
limits = c(0, 0.09),
labels = percent_format()) +
theme_tufte(base_family = "IBMPlexSans", ticks = FALSE) +
theme(plot.title = element_text(size = 16,
family="IBMPlexSans-Bold"),
plot.subtitle = element_text(size = 13)) +
labs(x = NULL, y = expression(gamma),
title = "Top 10 topics by popularity on Twitter",
subtitle = "With the top words that contribute to each topic")

The key focuses on Twitter are about something like “the spread of
virus (Topic 11)”, “negative reaction (Topic 7, 23)”, “update on the
pandemic information (Topic 13, 4)”. On the contrary, when looking into
News topics, we can see a relatively difference pattern, which is more
related to “political matters – topic 22”, “situation in other country -
topic 19”, “economy situation – topic 4”, “healthcare system situation
(Topic 20, 21)”. The message about family is popular in both sources
(News Topic 13, Twitter Topic 18). Furthermore, politicians are
well-covered, with Trump on Twitter and Pence/ Cuomo on mainstream
papers.
Sentiment Analysis
Corpus sentiment analysis
To investigate sentiments in news articles and tweets, tokens
extracted from the documents are used to calculate sentiment scores with
the AFINN lexicon developed by Finn Årup Nielsen, which is included in
the tidytext package. The AFINN lexicon is a list of English terms
manually rated for valence with an integer between -5 (negative) and +5
(positive). It comprises 878 positive terms and 1,598 negative terms.
The sentiment score is the percentage of the difference between the
absolute sum of positive terms and negative terms divided by the total
sum of them.
# Make a dataframe with the AFINN dictionary
afinn <- get_sentiments("afinn")
News_ext <- convert(News_DFM, to = "tripletlist")
News_df <- data.frame(doc = News_ext$document,
word = News_ext$feature,
freq = News_ext$frequency)
News_df$word <- as.character(News_df$word)
News_afinn <- News_df %>%
inner_join(afinn, by = "word") %>%
mutate(score = freq * value) %>%
separate(doc, into = c("week", "no"), sep = "\\.") %>%
mutate(sentiment = ifelse(score > 0, "positive", "negative")) %>%
group_by(week, sentiment) %>%
summarise(sentiment_score = sum(score)) %>%
ungroup() %>%
mutate(source = "News")
Twitter_ext <- convert(Twitter_DFM, to = "tripletlist")
Twitter_df <- data.frame(doc = Twitter_ext$document,
word = Twitter_ext$feature,
freq = Twitter_ext$frequency)
Twitter_df$word <- as.character(Twitter_df$word)
Twitter_afinn <- Twitter_df %>%
inner_join(afinn, by = "word") %>%
mutate(score = freq * value) %>%
separate(doc, into = c("week", "no"), sep = "\\.") %>%
mutate(sentiment = ifelse(score > 0, "positive", "negative")) %>%
group_by(week, sentiment) %>%
summarise(sentiment_score = sum(score)) %>%
ungroup() %>%
mutate(source = "Twitter")
# Create a dataframe to plot sentiment
News_afinn_plot <- News_afinn %>%
pivot_wider(names_from = sentiment, values_from = sentiment_score) %>%
mutate(sum = positive + (-1)*negative,
pos_percent = positive/sum*100,
neg_percent = (-1)*negative/sum*100,
polarity = round((pos_percent - neg_percent),3)) %>%
select(week, polarity, source)
Twitter_afinn_plot <- Twitter_afinn %>%
pivot_wider(names_from = sentiment, values_from = sentiment_score) %>%
mutate(sum = positive + (-1)*negative,
pos_percent = positive/sum*100,
neg_percent = (-1)*negative/sum*100,
polarity = round((pos_percent - neg_percent),3)) %>%
select(week, polarity, source)
# Extract beta matrix to data frame format. Using AFINN lexicon, make a data frame with the sentiment for each word
News_beta <- tidy(News_topic_model, matrix = "beta")
News_topic_sc <- inner_join(News_beta, afinn, by = c("term" = "word")) %>%
mutate(score = beta * value) %>%
group_by(topic) %>%
summarise(sentiment_score = sum(score))
News_topic_sc$topic <- factor(News_topic_sc$topic, levels = c(1:25))
Twitter_beta <- tidy(Twitter_topic_model, matrix = "beta")
Twitter_topic_sc <- inner_join(Twitter_beta, afinn, by = c("term" = "word")) %>%
mutate(score = beta * value) %>%
group_by(topic) %>%
summarise(sentiment_score = sum(score))
Twitter_topic_sc$topic <- factor(Twitter_topic_sc$topic, levels = c(1:25))
afinn_chart_all <- rbind(News_afinn_plot, Twitter_afinn_plot)
afinn_chart_all$week <- as.numeric(as.character(afinn_chart_all$week))
afinn_chart_all %>%
arrange(week) %>%
ggplot(aes(x = week, y = polarity, color = source)) +
geom_point() +
geom_path() +
geom_hline(yintercept = 0, color = "gold3") +
geom_vline(xintercept = 12, color = "coral2") +
labs(x = "Week", y = "Sentiment Score") +
scale_x_continuous( # This handles replacement of row
breaks = afinn_chart_all$week, # notice need to reuse data frame
labels = afinn_chart_all$week) +
scale_y_continuous(n.breaks = 10) +
scale_colour_manual(values = c("#E3211C", "#1F78B4")) +
theme(panel.grid = element_blank(),
panel.background = NULL,
axis.title = element_text(size = 16),
axis.text = element_text(size = 16),
legend.title = element_text(size = 16),
legend.text = element_text(size = 16),
legend.position = "bottom")

Overall, the opinion towards COVID-19 remained negative throughout
the period. While news was a bit more positive than Twitter, there was a
similar pattern as the sentiment scores were highly negative in week 3
but showed a positive trend in the subsequent weeks. At week 12 when the
situation got worse in the US, the sentiment score of news articles went
down then picked up again at week 15, whereas Twitter showed a
consistent sentiment.
With the purpose of examining from several perspectives, we also made
use of the NRC lexicon from Saif Mohammad and Peter Turney. The NRC
lexicon categorizes words in a binary fashion (“yes”/ “no”) into
categories of positive, negative, anger, anticipation, disgust, fear,
joy, sadness, surprise, and trust. We filtered out the positive and
negative categories which left us with 4,463 distinct words in the
lexicon (Note: one word can be in multiple sentiment categories). We
counted the number of words in each category and computed their
percentage distribution in each of our sources. Applying NRC lexicon to
inspect the data in different categorical sentiments, we presented the
result in a radar chart:
nrc <- get_sentiments("nrc") %>%
filter(!sentiment %in% c("positive", "negative"))
# News join and calculate score
News_nrc <- News_df %>%
inner_join(nrc) %>%
separate(doc, into = c("week", "no"), sep = "\\.") %>%
group_by(week, sentiment) %>%
summarise(count = sum(freq))
News_nrc_sum <- News_nrc %>%
group_by(sentiment) %>%
summarise(total_count = sum(count)) %>%
ungroup()
News_nrc_sum <- News_nrc_sum %>%
mutate(percent = total_count/ sum(News_nrc_sum$total_count),
source = "News")
# Twitter join and calculate score
Twitter_nrc <- Twitter_df %>%
inner_join(nrc) %>%
separate(doc, into = c("week", "no"), sep = "\\.") %>%
group_by(week, sentiment) %>%
summarise(count = sum(freq))
Twitter_nrc_sum <- Twitter_nrc %>%
group_by(sentiment) %>%
summarise(total_count = sum(count)) %>%
ungroup()
Twitter_nrc_sum <- Twitter_nrc_sum %>%
mutate(percent = total_count/ sum(Twitter_nrc_sum$total_count),
source = "Twitter")
# Combine data and plot radar chart
nrc_chart_all <- rbind(News_nrc_sum, Twitter_nrc_sum)
nrc_chart_all %>%
select(-total_count) %>%
pivot_wider(names_from = source, values_from = percent) %>%
chartJSRadar(width = 8,
height = 5,
showToolTipLabel = FALSE,
colMatrix = grDevices::col2rgb(c("red", "blue", "green")),
labelSize = 18)
Overall, news articles showed the most positivity by coming on top of
“joy” and “trust”, but it also had more “anger” words. Reddit were
dominant in most negative categories, such as “sadness”, “fear” and
“anticipation”. Twitter’s posts were more negative, as they expressed
“disgust”, “sadness”, and somehow “surprise”. This turned out to be a
relevant interpretation of the outcome of the AFINN lexicon analysis
above.
Topic-based sentiment analysis
On the topic-based level, we assigned the sentiment value for each
topic word based on the lexicon and the probability of a word in a topic
given by the STM topic model as the term weight of the word. As a
result, topic sentiment score is calculated as
\[Sentiment\ Score\ of\ Topic\ A =
\sum_{i=1}^{n} (prob(word_i|Topic_A)*sentiment\
value(word_i))\]
An overall topic sentiment score is computed by multiplying the
sentiment value by the probability of words and summing the products in
a chosen topic. Multiple topics could have the same words with different
probability values. Therefore, the sentiment score of a topic would be
distinguished from others even if the same set of words appear in
different topics.
# News
News_topic_sc_plot <- News_topic_sc %>%
ggplot(aes(x = topic, y = sentiment_score)) +
geom_col(fill = "#E3211C") +
geom_hline(yintercept = 0, color = "gold3") +
labs(x = NULL, y = NULL, subtitle = "News") +
scale_y_continuous(limits = c(-1, 0.2), n.breaks = 8) +
theme(panel.grid = element_blank(),
panel.background = NULL,
axis.title = element_text(size = 16),
axis.text = element_text(size = 14),
plot.subtitle = element_text(size = rel(1.5)))
# Twitter
Twitter_topic_sc_plot <- Twitter_topic_sc %>%
ggplot(aes(x = topic, y = sentiment_score)) +
geom_col(fill = "#1F78B4") +
geom_hline(yintercept = 0, color = "gold3") +
labs(x = "Topic", y = NULL, subtitle = "Twitter") +
scale_y_continuous(limits = c(-1, 0.2), n.breaks = 8) +
theme(panel.grid = element_blank(),
panel.background = NULL,
axis.title = element_text(size = 16),
axis.text = element_text(size = 14),
plot.subtitle = element_text(size = rel(1.5)))
grid.arrange(News_topic_sc_plot, Twitter_topic_sc_plot)

Using STM model with the same number of topics of 25, we calculated
the sentiment score of each topic. Again, the general opinions in most
topics were negative. The sentiments were more significant in Twitter,
while in news articles most topics had the scores closer to neutral.
Topic 7 in Twitter was extremely negative, which mostly consist of
sentimental words (hell, yall, shit…). This was one downside of
unsupervised topic modelling, as it grouped these sentimental words
together in one topic, but the interpretation was not useful for topic
discovery. Excluding the topics above, news and Twitter had a few
notable negativities, with topic 22 (political, pence, tweet, blame,
party, attack…) and 23 (police, prison, court, law, jail…) in news and
topic 12 (die, flu, trump…) in Twitter. Twitter users seemed to have the
concerns centered around President Trump’s behaviors, while the news
media gravitated towards the conflict of political parties and worries
about social security.
Among the positive topics, there was a homogeneous them in all
sources. Topic 13 in the news (love, church, moment, wife, mother…) and
Topic 18 (family, friend, pray…) and 15 (protect, god, love, jesus…) in
Twitter had the same theme of faith and belief, though the positive
scores were mild.
Conclusion
This project studies the topic coverage and sentiment dynamics of the
sensitive topic COVID-19 in News media and Twitter. Although the project
has revealed different characteristics of news articles and Twitter, it
only conducts analysis on the text property and the time variable. Many
meta-data were removed from the raw data which might leave out some
important aspects that could be elaborated further. Other choices that
might lead to research bias were the data samples which just cover
subsets of keywords and the dictionaries used for pre-processing and
sentiment analysis. Lastly, the time frame of data collection is only
three months, ending at the middle of April when the pandemic was still
escalating in the US. It would be better If we collect the data and
conduct the analysis after the pandemic is over, which would give a full
overview of the situation.
LS0tDQp0aXRsZTogVGV4dCBtaW5pbmcgb2YgbWFpbnN0cmVhbSBuZXdzIGFuZCBUd2l0dGVyIGFib3V0IENvcm9uYXZpcnVzIG91dGJyZWFrIGluIHRoZSBVU0EuDQphdXRob3I6IFBob25nIFZpZXQgTmd1eWVuDQpkYXRlOiAiMjAyMC0xMi0wNSINCm91dHB1dDogDQogICAgaHRtbF9ub3RlYm9vazoNCiAgICAgIHRvYzogdHJ1ZQ0KLS0tDQoNCiMgSW50cm9kdWN0aW9uDQoNCkluIHRoaXMgcHJvamVjdCwgd2UgbG9vayBhdCB0aGUgY292ZXJhZ2Ugb2YgQ29yb25hdmlydXMgb24gbWFpbnN0cmVhbSBuZXdzIGFydGljbGVzIGFuZCBUd2l0dGVyIGluIHRoZSBVU0EuIFRoZSBtYWluIGdvYWwgaXMgdG8gaW5zcGVjdCB0aGUgZGlmZmVyZW5jZSBpbiB0aGUgZm9jdXMgb2YgZWFjaCBtZWRpYSBvdXRsZXQgKHRvcGljIG1vZGVsbGluZykgYW5kIHRoZWlyIGV4cHJlc3NlZCBhdHRpdHVkZXMgKHNlbnRpbWVudCBhbmFseXNpcykgb24gQ09WSUQtMTkuDQoNClRoZSBwcm9qZWN0IGlzIGNvbmR1Y3RlZCB3aXRoIHRoZSBmb2xsb3dpbmcgc3RlcHM6IERhdGEgY29sbGVjdGlvbiwgRGF0YSBjbGVhbmluZyBhbmQgUHJlLXByb2Nlc3NpbmcsIFRvcGljIG1vZGVsaW5nLCBhbmQgU2VudGltZW50IGFuYWx5c2lzLiBUaGUgZGF0YSB3YXMgZ2F0aGVyZWQgdXNpbmcgd2ViLXNjcmFwaW5nIHRlY2huaXF1ZSB3aXRoIFIgYW5kIFB5dGhvbiBwcm9ncmFtbWluZy4gQWZ0ZXIgZGF0YSBjbGVhbmluZywgdGhlICpRdWFudGVkYSogcGFja2FnZSBpbiBSIHdhcyB1c2VkIHRvIHByZXBhcmUgZm9yIHRleHQgYW5hbHlzaXMuIFRoZW4sIHdlIGFwcGxpZWQgdG9waWMgbW9kZWxsaW5nIHRvIGlkZW50aWZ5IGRpc3RpbmN0IHRvcGljcy4gSW4gc2VudGltZW50IGFuYWx5c2lzLCB3ZSBjaG9zZSBhIGxleGljb24sIGNhbGN1bGF0ZWQgc2VudGltZW50cyBzY29yZXMgYW5kIGxvb2tlZCBhdCB0aGUgc2hpZnQgaW4gc2VudGltZW50cy4NCg0KVGhlIHJlc3VsdCBoYXMgcmV2ZWFsZWQgc29tZSBkaXNwYXJpdGllcyBiZXR3ZWVuIHRoZSBtZWRpYSBzb3VyY2VzLiBTb2NpYWwgbWVkaWEsIG5hbWVseSBUd2l0dGVyLCBhcmUgcmVmbGVjdGluZyBtb3JlIG9uIHBlb3BsZcK0cyBzZW50aW1lbnRzIGFuZCBxdWljayB1cGRhdGVzIG9mIHRoZSBzaXR1YXRpb24gd2hpbGUgbmV3cyBhcnRpY2xlcyBhcmUgbW9yZSBhYm91dCBtYWNybyBwcm9ibGVtcy4gVGhlIHR3byBtZWRpYSdzIHNlbnRpbWVudCByZW1haW5lZCBuZWdhdGl2ZSB0aHJvdWdob3V0IHRoZSBvYnNlcnZlZCBwZXJpb2QuDQoNCmBgYHtyIFBhY2thZ2VzLCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeSh0aWR5dmVyc2UpICMgZGF0YSBtYW5pcHVsYXRpb24NCmxpYnJhcnkocXVhbnRlZGEpICMgdGV4dCBwcmUtcHJvY2Vzc2luZw0KbGlicmFyeShxdWFudGVkYS5kaWN0aW9uYXJpZXMpDQpsaWJyYXJ5KHRpZHl0ZXh0KSAjIHRleHQgYW5hbHlzaXMNCmxpYnJhcnkobHVicmlkYXRlKSAjIGRhdGUgZnVuY3Rpb24NCmxpYnJhcnkoZ3JpZEV4dHJhKSAjIG11bHRpcGxlIGdyYXBocw0KbGlicmFyeShzdG0pICMgdG9waWMgbW9kZWxsaW5nDQpsaWJyYXJ5KHN0bUNvcnJWaXopDQpsaWJyYXJ5KGZ1cnJyKQ0KbGlicmFyeSh0bSkNCmxpYnJhcnkoc2NhbGVzKQ0KbGlicmFyeShnZ3RoZW1lcykNCmxpYnJhcnkocmFkYXJjaGFydCkNCmBgYA0KDQojIERhdGEgQ29sbGVjdGlvbiBhbmQgQ2xlYW5pbmcNCg0KIyMgTmV3cyBBcnRpY2xlcw0KDQpVc2luZyB0aGUga2V5d29yZCAqY29yb25hdmlydXMqIGZvciBxdWVyeWluZywgd2UgY29sbGVjdGVkIG5ld3MgYXJ0aWNsZXMgcHVibGlzaGVkIG9uIG5ld3Mgd2Vic2l0ZXMgaW4gdGhlIFVuaXRlZCBTdGF0ZXMgZnJvbSB0aGUgYmVnaW5uaW5nIG9mIDIwMjAsIHdoZXJlIHRoZSBmaXJzdCBjYXNlcyBvZiBjb3JvbmF2aXJ1cyB3ZXJlIHJlcG9ydGVkLCB1bnRpbCBBcHJpbCAxOSwgMjAyMC4gRm9yIHNvdXJjZXMsIHdlIGxvb2tlZCBhdCB0aGUgdG9wIDE1IFUuUyBuZXdzIHdlYnNpdGVzIG1lYXN1cmVkIGJ5IHVuaXF1ZSBtb250aGx5IHZpc2l0b3JzIChTdGF0aXN0YSwgMjAyMCksIGV4Y2x1ZGluZyB0aGUgbmV3cyBhZ2dyZWdhdG9ycyAoWWFob28gTmV3cywgR29vZ2xlIE5ld3MpIGFuZCB0b3BpYy1zcGVjaWZpYyBuZXdzcGFwZXJzIChUaGUgV2FsbCBTdHJlZXQgSm91cm5hbCkuIFdlIHVzZWQgYSB0aGlyZC1wYXJ0eSBBUEkgY2FsbGVkICpDdXJyZW50cyBBUEkqIGluIFIgdG8gZ2V0IGFsbCB0aGUgYXZhaWxhYmxlIFVSTHMsIHRoZW4gcHV0IHRoZW0gaW50byB0aGUgbmV3c3BhcGVyM2sgbW9kdWxlIGluIFB5dGhvbiwgd2hpY2ggZW5hYmxlZCBzY3JhcGluZyB0aGUgZW50aXJlIGFydGljbGVzLiBGdXJ0aGVybW9yZSwgYWZ0ZXIgY2hlY2tpbmcgdGhlIGRhdGEgcXVhbGl0eSBmcm9tIGVhY2ggc291cmNlLCB3ZSBuYXJyb3dlZCB0aGVtIGRvd24gZnJvbSAxNSB0byA2IG5ld3Mgb3V0bGV0czogQ05OLCBUaGUgTmV3IFlvcmsgVGltZXMsIEZveCBOZXdzLCBUaGUgR3VhcmRpYW4sIFVTQSBUb2RheSBhbmQgVGhlIExBIFRpbWVzLg0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRX0NCiMgTG9hZCB0aGUgc2NyYXBlZCBkYXRhDQpuZXdzX2RhdGEgPC0gcmVhZF9jc3YoIm5ld3NfY29yb25hdmlydXMuY3N2IikNCg0KIyBBZGQgd2VlayBhbmQgcmVtb3ZlIHVubmVjZXNzYXJ5IGNvbHVtbg0KbmV3c19kYXRhIDwtIG5ld3NfZGF0YSAlPiUgDQogIG11dGF0ZSh3ZWVrID0gaXNvd2VlayhwdWJsaXNoX2RhdGUpKSAlPiUgDQogIHNlbGVjdCgtdGl0bGUpDQoNCiMgUHJldmlldyB0aGUgZGF0YQ0KZ2xpbXBzZShuZXdzX2RhdGEpDQpgYGANCg0KIyMgVHdpdHRlcg0KDQpUaGFua3MgdG8gdGhlIHN1cHBvcnQgZnJvbSB0aGUgdGVhbSBhdCA8Y3Jvd2RicmVha3Mub3JnPiwgd2hvIGlzIHRyYWNraW5nIFR3aXR0ZXIgdHJlbmQgb24gQ09WSUQtMTkgaW4gcmVhbCB0aW1lLCB3ZSBtYW5hZ2VkIHRvIGdldCBhbGwgdHdlZXQgSURzIHRoYXQgdGhleSBoYWQgY29sbGVjdGVkIHNpbmNlIEphbnVhcnkgMjAyMCBpbiB0aGUgVVMgd2l0aCB0aGUga2V5d29yZHMgb2Yg4oCcd3VoYW7igJ0sIOKAnG5jb3bigJ0sIOKAnGNvcm9uYXZpcnVz4oCdLCDigJxjb3ZpZOKAnSwg4oCcc2Fycy1jb3YtMuKAnS4gV2UgZGVjaWRlZCB0byB0YWtlIHN0cmF0aWZpZWQgc2FtcGxpbmcgb2YgdGhlIGRhdGEgKDUwJSkgdG8ga2VlcCB0aGUgZGlzdHJpYnV0aW9uIG9mIG51bWJlciBvZiB0d2VldHMgcGVyIHdlZWsgYW5kIHNwZWVkIHVwIGRhdGEgY29sbGVjdGlvbiBhbmQgb2J0YWluIHRoZSBkYXRhIGluIHRpbWUgZm9yIHRoZSByZXBvcnQuIFRoZSBUd2l0dGVyIGRhdGEgd2VyZSBjb2xsZWN0ZWQgdW50aWwgQXByaWwgMTYsIDIwMjAuDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQ0KIyBMb2FkIHRoZSBzY3JhcGVkIGRhdGENCnR3ZWV0c19kYXRhIDwtIHJlYWRfY3N2KCJ0d2l0dGVyX2Nvcm9uYXZpcnVzLmNzdiIpDQoNCiMgVHJhbnNmb3JtIHRoZSBkYXRlIGNvbHVtbg0KdHdlZXRzX2RhdGEgPC0gdHdlZXRzX2RhdGEgJT4lIA0KICBzZXBhcmF0ZShjcmVhdGVkX2F0LCBjKCJ3ZGF5IiwgIm1vbnRoIiwgImRheSIsICJ0aW1lIiwgInBsdXMiLCAieWVhciIpLCANCiAgICAgICAgICAgc2VwID0gIiAiKSAlPiUgDQogIG11dGF0ZShkYXRlID0gcGFzdGUobW9udGgsIGRheSwgeWVhciwgc2VwID0gIiAiKSkgJT4lIA0KICBzZWxlY3QoYygidGV4dCIsICJkYXRlIikpDQoNCnR3ZWV0c19kYXRhJGRhdGUgPC0gYXMuRGF0ZSh0d2VldHNfZGF0YSRkYXRlLCBmb3JtYXQgPSAiJWIgJWQgJVkiKQ0KdHdlZXRzX2RhdGEgPC0gdHdlZXRzX2RhdGEgJT4lIA0KICBtdXRhdGUod2VlayA9IGlzb3dlZWsoZGF0ZSkpICU+JSANCiAgZmlsdGVyKHdlZWsgPiAyKQ0KDQojIENsZWFuIGhhc2h0YWdzLCBsaW5rcyBhbmQgc3BlY2lhbCBjaGFyYWN0ZXJzDQp0d2VldHNfZGF0YSR0ZXh0IDwtIHR3ZWV0c19kYXRhJHRleHQgJT4lIA0KICBzdHJfcmVwbGFjZV9hbGwoIiMiLCAiICIpICU+JQ0KICBzdHJfcmVtb3ZlX2FsbCgiKD88PV58XFxzKWh0dHBbXlxcc10rIikgJT4lIA0KICBzdHJfcmVtb3ZlX2FsbCgiW15hLXpBLVowLTkgXSIpICU+JSANCiAgdHJpbXdzKCkNCg0KIyBSZW1vdmUgYmxhbmsgdGV4dCBhZnRlciBjbGVhbmluZw0KdHdlZXRzX2RhdGEgPC0gdHdlZXRzX2RhdGEgJT4lIA0KICBmaWx0ZXIoc3RyX2NvdW50KHRleHQsIHBhdHRlcm4gPSBib3VuZGFyeSgid29yZCIpKSA+IDEpDQpgYGANCg0KIyMgRGF0YSBPdmVydmlldw0KDQpGb3IgZnVydGhlciBkYXRhIGNsZWFuaW5nLCB3ZSByZW1vdmVkIGR1cGxpY2F0ZWQgZGF0YSwgdGV4dHMgdGhhdCB3ZXJlIHRvbyBzaG9ydCBhbmQga2VwdCBvbmx5IHRleHRzIHdyaXR0ZW4gaW4gRW5nbGlzaC4gV2Uga2VwdCB0aGUgdGltZSB2YXJpYWJsZSBpbiB3ZWVrIGZvcm1hdCBhbmQgdGhlIGZ1bGwgdGV4dCBvZiB0aGUgZG9jdW1lbnQgZm9yIGFuYWx5c2lzLiBDb25zZXF1ZW50bHksIDE0LDE0OSBuZXdzIGFydGljbGVzIGFuZCAxMDksMzI5IHR3ZWV0cyB3ZXJlIHJlYWR5IGZvciBhbmFseXNpcy4NCg0KVGhlIGRhdGEgZGlzdHJpYnV0aW9uIGNhbiBiZSBzZWVuIGJlbG93LiBUaGUgbnVtYmVyIG9mIG5ld3MgcmVwb3J0ZWQgb24gQ09WSUQtMTkgaW4gdGhlIFUuUyB3ZXJlIHJlbGF0aXZlbHkgbG93IGluIHRoZSBmaXJzdCA2IHdlZWtzICh3ZWVrIDMgLSB3ZWVrIDgpLiBIb3dldmVyLCB0aGVyZSB3YXMgYSBkcmFtYXRpYyBpbmNyZWFzZSBzdGFydGluZyBmcm9tIHdlZWsgOSBhbmQgcGVha2VkIGluIHdlZWsgMTEgYW5kIDEzIGZvciBUd2l0dGVyIGFuZCBOZXdzIHJlc3BlY3RpdmVseS4gVGhpcyB3YXMgdGhlIGVuZCBvZiBNYXJjaCB3aGVuIHRoZSBudW1iZXIgb2YgaW5mZWN0ZWQgY2FzZXMgaW4gdGhlIGNvdW50cnkgc3VyZ2VkLiANCg0KYGBge3IgRGF0YSBDb3VudCwgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCnBsb3RfbmV3cyA8LSBuZXdzX2RhdGEgJT4lDQogIGdyb3VwX2J5KHdlZWspICU+JQ0KICBzdW1tYXJpc2UobiA9IG4oKSkgJT4lIA0KICB1bmdyb3VwKCkgJT4lIA0KICBtdXRhdGUoc291cmNlID0gIk5ld3MiKQ0KDQpwbG90X3R3ZWV0cyA8LSB0d2VldHNfZGF0YSAlPiUNCiAgZ3JvdXBfYnkod2VlaykgJT4lDQogIHN1bW1hcmlzZShuID0gbigpKSAlPiUgDQogIHVuZ3JvdXAoKSAlPiUgDQogIG11dGF0ZShzb3VyY2UgPSAiVHdpdHRlciIpDQpgYGANCg0KYGBge3IgRGF0YSBEaXN0cmlidXRpb24sIGVjaG89RkFMU0V9DQoNCm5ld3NfZGlzdHJpYnV0aW9uIDwtIHBsb3RfbmV3cyAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gd2VlaykpICsgDQogIGdlb21fY29sKGFlcyh5ID0gbiwgZmlsbCA9IC1uKSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMobi5icmVha3MgPSAxMCkgKw0KICBsYWJzKHggPSAid2VlayIsIHkgPSAibnVtYmVyIG9mIGRvY3VtZW50cyIsIHN1YnRpdGxlID0gIk5ld3MiKSArDQogIHRoZW1lKA0KICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwNCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGhqdXN0ID0gLjUsIHZqdXN0ID0gLjUpLA0KICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksDQogICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KCJsaWdodGdyYXkiLCBmaWxsID0gTkEpLA0KICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSByZWwoMS44KSkpDQoNCnR3ZWV0c19kaXN0cmlidXRpb24gPC0gcGxvdF90d2VldHMgJT4lDQogIGdncGxvdChhZXMoeCA9IHdlZWspKSArIA0KICBnZW9tX2NvbChhZXMoeSA9IG4sIGZpbGwgPSAtbiksIHNob3cubGVnZW5kID0gRkFMU0UpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKG4uYnJlYWtzID0gMTApICsNCiAgbGFicyh4ID0gIndlZWsiLCB5ID0gTlVMTCwgc3VidGl0bGUgPSAiVHdpdHRlciIpICsNCiAgdGhlbWUoDQogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpLA0KICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgaGp1c3QgPSAuNSwgdmp1c3QgPSAuNSksDQogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwNCiAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoImxpZ2h0Z3JheSIsIGZpbGwgPSBOQSksDQogICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IHJlbCgxLjgpKSkNCg0KZ3JpZC5hcnJhbmdlKG5ld3NfZGlzdHJpYnV0aW9uLCB0d2VldHNfZGlzdHJpYnV0aW9uLCBuY29sID0gMikNCmBgYA0KDQojIFByZS1wcm9jZXNzaW5nDQoNCkZvciB0ZXh0IGRhdGEgcHJlcGFyYXRpb24sIGZpcnN0bHksIHdlIGNyZWF0ZWQgYSBjb3JwdXMgZm9yIHRoZSBkYXRhIHNldCBvZiBlYWNoIHNvdXJjZS4gQSBjb3JwdXMgY29uc2lzdHMgb2YgYSBjb2xsZWN0aW9uIG9mIGRvY3VtZW50cyAoZWFjaCBkb2N1bWVudCBpcyBhbiBhcnRpY2xlIG9yIGEgdHdlZXQpLCBhbmQgdGhlIGRvY3VtZW50IHZhcmlhYmxlcyB3aGljaCBkZXNjcmliZSB0aGUgY2hhcmFjdGVyaXN0aWNzIG9mIHRoZSBkb2N1bWVudCwgZm9yIGluc3RhbmNlIHB1Ymxpc2hlZCBkYXRlIGFuZCBzb3VyY2UuIFN1YnNlcXVlbnRseSwgd2UgdG9rZW5pemVkIGVhY2ggY29ycHVzLCB3aGljaCBzZXBhcmF0ZXMgdGhlIHRleHQgaW50byBpdHMgc2luZ2xlIHdvcmRzIChhbHNvIGNhbGxlZCB0ZXJtcyBvciB0b2tlbnMpLiBBIHN1bW1hcnkgb2YgdGhlIGNvcnB1cyBmb3IgbmV3cyBhcnRpY2xlcyBjYW4gYmUgc2VlbiBiZWxvdy4NCg0KYGBge3IgQ3JlYXRlIGEgY29ycHVzfQ0KY29ycHVzX05ld3NfZGF0YSA8LSBjb3JwdXMobmV3c19kYXRhLCB0ZXh0X2ZpZWxkID0gYygidGV4dCIpLCB1bmlxdWVfZG9jbmFtZXMgPSBGKSAlPiUNCiAgYGRvY25hbWVzPC1gKG5ld3NfZGF0YSR3ZWVrKSAjIHVwZGF0ZSB0aGUgbmFtZSBvZiBkb2N1bWVudCBpbiB0aGUgY29ycHVzDQpzdW1tYXJ5KGNvcnB1c19OZXdzX2RhdGEsIDUpDQpoZWFkKGNvcnB1c19OZXdzX2RhdGEsIDUpICMgdGFrZSBhIGxvb2sgYXQgdGhlIGNvcnB1cw0KDQpjb3JwdXNfVHdpdHRlcl9kYXRhIDwtIGNvcnB1cyh0d2VldHNfZGF0YSwgdGV4dF9maWVsZCA9IGMoInRleHQiKSwgdW5pcXVlX2RvY25hbWVzID0gRikgJT4lDQogIGBkb2NuYW1lczwtYCh0d2VldHNfZGF0YSR3ZWVrKQ0KYGBgDQoNCmBgYHtyIFN0b3Atd29yZHMgYW5kIEJhc2UtZm9ybWVkIHdvcmRzfQ0Kc3RvcHdvcmRzX2V4dGVuZGVkIDwtIHJlYWRMaW5lcygic3RvcHdvcmRzX2VuLnR4dCIsIGVuY29kaW5nID0gIlVURi04IikNCmxlbW1hX2RhdGEgPC0gcmVhZC5jc3YoImJhc2Vmb3JtX2VuLnRzdiIsIGVuY29kaW5nID0gIlVURi04IikNCmBgYA0KDQpXZSBwcmUtcHJvY2Vzc2VkIHRoZSBkYXRhIHNldHMgYnkgbG93ZXJpbmcgdXBwZXIgY2FzZSBsZXR0ZXJzIGFuZCByZW1vdmluZyB0aGUgbnVtYmVycywgcHVuY3R1YXRpb25zLCBzeW1ib2xzLCBVUkxzIGFuZCBzZXBhcmF0b3JzLiBUaGUgbWFpbiBpZGVhIGlzIHRvIHJlZHVjZSB0aGUgZmluYWwgYW1vdW50IG9mIHRlcm1zIGV4dHJhY3RlZCwgd2hpY2ggaXMgaW1wb3J0YW50IGluIG9yZGVyIHRvIGltcHJvdmUgdGhlIGFjY3VyYWN5IG9mIGJvdGggdG9waWMgbW9kZWxpbmcgYW5kIHNlbnRpbWVudCBhbmFseXNpcy4gSWYgdHdvIHdvcmRzIGFyZSBzaW1pbGFyIGl0IGlzIGNvbnZlbmllbnQgdG8gY29tYmluZSB0aGVtIGFzIG9uZSB1bmlxdWUgd29yZC4gTW9yZW92ZXIsIGlmIGEgd29yZCBpcyBub3QgcmVsZXZhbnQgZm9yIHRoZSBhbmFseXNpcywgaXQgY2FuIGJlIHJlbW92ZWQuIEhlbmNlLCB3ZSBpbXBsZW1lbnRlZCBzdG9wLXdvcmRzIHJlbW92YWwgYW5kIGxlbW1hdGl6YXRpb24gdGVjaG5pcXVlLiBTdG9wd29yZHMgYXJlIHdvcmRzIHRoYXQgYXBwZWFyIGluIHRleHRzIGJ1dCBkbyBub3QgZ2l2ZSB0aGUgdGV4dCBhIHN1YnN0YW50aWFsIG1lYW5pbmcgKGUuZy4sICJ0aGUiLCAiYSIsIG9yICJmb3IiKSBhbmQgbGVtbWF0aXphdGlvbiBkZWFscyB3aXRoIHRoZSBpbmZsZWN0ZWQgZm9ybXMgb2Ygd29yZHMgYnkgcmVwbGFjaW5nIHRoZW0gd2l0aCB0aGVpciBiYXNlIGZvcm1zLiBUaGUgdG90YWwgbnVtYmVyIHRva2VucyBhbmQgdW5pcXVlIHRva2VucyBpbiBlYWNoIHNvdXJjZSBkZWNyZWFzZWQgYnkgNDAg4oCTIDcwJSBhZnRlciB0aGUgYWJvdmUgc3RlcHM6DQoNCmBgYHtyIENyZWF0ZSB0b2tlbnN9DQpUb2tlbl9uZXdzX2RhdGEgPC0gY29ycHVzX05ld3NfZGF0YSAlPiUgDQogIHRva2VucyhyZW1vdmVfcHVuY3QgPSBUUlVFLCByZW1vdmVfbnVtYmVycyA9IFRSVUUsIHJlbW92ZV9zeW1ib2xzID0gVFJVRSwgDQogICAgICAgICByZW1vdmVfdXJsID0gVFJVRSwgcmVtb3ZlX3NlcGFyYXRvcnMgPSBUUlVFKSAlPiUgDQogIHRva2Vuc190b2xvd2VyKGtlZXBfYWNyb255bXMgPSBGQUxTRSkgJT4lDQogIHRva2Vuc19yZW1vdmUocGF0dGVybiA9IGMoImFtaWQiLCAidXBkYXRlcyIsICJsaXZlIiwgInZpZGVvIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgImRpZG4iLCAiYnJpZWZpbmciKSkgJT4lDQogIHRva2Vuc19yZXBsYWNlKGxlbW1hX2RhdGEkaW5mbGVjdGVkX2Zvcm0sIGxlbW1hX2RhdGEkbGVtbWEsIA0KICAgICAgICAgICAgICAgICB2YWx1ZXR5cGUgPSAiZ2xvYiIpICU+JQ0KICB0b2tlbnNfcmVwbGFjZShwYXR0ZXJuID0gYygiY292aWQtMTkiLCAibmNvdiIsICJjb3YiKSwgDQogICAgICAgICAgICAgICAgIGMoImNvcm9uYXZpcnVzIiwgImNvcm9uYXZpcnVzIiwgImNvcm9uYXZpcnVzIiksDQogICAgICAgICAgICAgICAgIHZhbHVldHlwZSA9ICJmaXhlZCIpICU+JSANCiAgdG9rZW5zX3JlbW92ZShwYXR0ZXJuID0gc3RvcHdvcmRzX2V4dGVuZGVkLCBwYWRkaW5nID0gRikNCg0KVG9rZW5fVHdpdHRlcl9kYXRhIDwtIGNvcnB1c19Ud2l0dGVyX2RhdGEgJT4lIA0KICB0b2tlbnMocmVtb3ZlX3B1bmN0ID0gVFJVRSwgcmVtb3ZlX251bWJlcnMgPSBUUlVFLCByZW1vdmVfc3ltYm9scyA9IFRSVUUsDQogICAgICAgICByZW1vdmVfdXJsID0gVFJVRSwgcmVtb3ZlX3NlcGFyYXRvcnMgPSBUUlVFKSAlPiUgDQogIHRva2Vuc190b2xvd2VyKGtlZXBfYWNyb255bXMgPSBGQUxTRSkgJT4lDQogIHRva2Vuc19yZW1vdmUocGF0dGVybiA9IGMoInBlb3BsZSIsICJjb3ZpZDE5IiwgImNvdmlkIiwgInJ0IiwgImRvbnQiKSkgJT4lDQogIHRva2Vuc19yZXBsYWNlKGxlbW1hX2RhdGEkaW5mbGVjdGVkX2Zvcm0sIGxlbW1hX2RhdGEkbGVtbWEsIA0KICAgICAgICAgICAgICAgICB2YWx1ZXR5cGUgPSAiZ2xvYiIpICU+JSANCiAgdG9rZW5zX3JlbW92ZShwYXR0ZXJuID0gc3RvcHdvcmRzX2V4dGVuZGVkLCBwYWRkaW5nID0gVCkNCmBgYA0KDQoNCmBgYHtyIE51bWJlciBvZiB0b2tlbnMsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQp0aWJibGUoDQogIFNvdXJjZSA9IGMoIk5ld3MiLCAiVHdpdHRlciIpLCANCiAgQ29ycHVzID0gYygxNDE0OSwgMzUyODQyKSwgDQogIE51bWJlcl9vZl90b2tlbnMgPSBjKCIzOTM4NjM5ICgtNTkuNiUpIiwgIjU3MjkzNjAgKC02OC43JSkiKSwNCiAgVW5pcXVlX3Rva2VucyA9IGMoIjI1MzQ1MTggKC00Mi41JSkiLCAiNTA2NTEzNiAoLTYyLjklKSIpDQopDQpgYGANCg0KSW4gdGhlIG5leHQgc3RlcCwgd2UgZ2VuZXJhdGVkIGEgZG9jdW1lbnQtZmVhdHVyZSBtYXRyaXggKGFsc28ga25vd24gYXMgZG9jdW1lbnQtdGVybSBtYXRyaXgpIGZvciBlYWNoIHNvdXJjZS4gSXQgcmVwcmVzZW50cyBob3cgZnJlcXVlbnRseSB0ZXJtcyAodG9rZW5zKSBvY2N1ciBpbiB0aGUgY29ycHVzIChkb2N1bWVudCkgYnkgY291bnRpbmcgc2luZ2xlIHRlcm1zLiBXZSBrZXB0IG9ubHkgdGhlIHRvcCA1JSBvZiB0aGUgbW9zdCBmcmVxdWVudCBmZWF0dXJlcyAobWluaW11bSB0ZXJtIGZyZXF1ZW5jeSBzZXQgYXQgMC45NSkgdGhhdCBwcmVzZW50IGluIGxlc3MgdGhhbiAxMCUgb2YgYWxsIGRvY3VtZW50cyAobWF4aW11bSBkb2N1bWVudCBmcmVxdWVuY3kgc2V0IGF0IDAuMSkgdG8gZm9jdXMgb24gY29tbW9uIGJ1dCBkaXN0aW5jdGl2ZSBmZWF0dXJlcy4gV2UgYWxzbyBkaXNtaXNzZWQgdGhlIGRvY3VtZW50cyB0aGF0IGhhZCBubyB0b2tlbnMgbGVmdCBhZnRlciB0cmltbWluZy4gVGhlIGRpbWVuc2lvbnMgb2YgdGhlIHR3byBkb2N1bWVudC1mZWF0dXJlIG1hdHJpY2VzIGFyZSBhcyBmb2xsb3c6DQoNCmBgYHtyIEtlZXAgdG9wIGZlYXR1cmVzfQ0KTmV3c19ERk0gPC0gVG9rZW5fbmV3c19kYXRhICU+JSANCiAgdG9rZW5zX3JlbW92ZSgiIikgJT4lDQogIGRmbSgpICU+JSANCiAgZGZtX3RyaW0obWluX3Rlcm1mcmVxID0gMC45NSwgdGVybWZyZXFfdHlwZSA9ICJxdWFudGlsZSIsDQogICAgICAgICAgIG1heF9kb2NmcmVxID0gMC4xLCBkb2NmcmVxX3R5cGUgPSAicHJvcCIpDQojIFdlIHJlbW92ZSB0aGUgdG9rZW4gPSAwDQpOZXdzX0RGTSA8LSBOZXdzX0RGTVtudG9rZW4oTmV3c19ERk0pID4gMCwgXQ0KI2hlYWQoTmV3c19ERk0sIG4gPSA1LCBuZiA9IDgpDQoNClR3aXR0ZXJfREZNIDwtIFRva2VuX1R3aXR0ZXJfZGF0YSAlPiUgDQogIHRva2Vuc19yZW1vdmUoIiIpICU+JQ0KICBkZm0oKSAlPiUNCiAgZGZtX3RyaW0obWluX3Rlcm1mcmVxID0gMC45NSwgdGVybWZyZXFfdHlwZSA9ICJxdWFudGlsZSIsIA0KICAgICAgICAgICBtYXhfZG9jZnJlcSA9IDAuMSwgZG9jZnJlcV90eXBlID0gInByb3AiKQ0KIyBXZSByZW1vdmUgdGhlIHRva2VuID0gMA0KVHdpdHRlcl9ERk0gPC0gVHdpdHRlcl9ERk1bbnRva2VuKFR3aXR0ZXJfREZNKSA+IDAsXQ0KYGBgDQoNCmBgYHtyIERvY3VtZW50LWZlYXR1cmUgbWF0cml4IGRpbWVuc2lvbiwgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCnRpYmJsZSgNCiAgU291cmNlID0gYygiTmV3cyIsICJUd2l0dGVyIiksIA0KICAiTnVtYmVyX29mX2RvY3VtZW50cyAocm93cykiID0gYygxNDE0OSwgMzUxNjAzKSwNCiAgIk51bWJlcl9vZl9mZWF0dXJlcyAoY29sdW1ucykiID0gYygzNDkyLCAyODQ2KQ0KKQ0KYGBgDQoNCkZvciBiZXR0ZXIgaW50ZXJwcmV0YXRpb24sIHRoZSBmaXJzdCAzIGRvY3VtZW50cyBhbmQgMTAgZmVhdHVyZXMgb2YgdGhlIGRvY3VtZW50LWZlYXR1cmUgbWF0cml4IG9mIG5ld3MgYXJ0aWNsZXMgY2FuIGJlIHNlZW4gYmVsb3cuDQoNCmBgYHtyIERGTSBwcmV2aWV3fQ0KTmV3c19ERk1bMTozLCAxOjEwXQ0KYGBgDQoNCiMgVG9waWMgTW9kZWxsaW5nDQoNCldlIGRpc2NvdmVyZWQgdG9waWNzIGRpc3RyaWJ1dGVkIGluIG5ld3MgYXJ0aWNsZXMgYW5kIHR3ZWV0cyBvbiBhIHdlZWtseSBiYXNpcyBvdmVyIHRoZSB0aHJlZS1tb250aCBwZXJpb2QgYW5kIGNvbXBhcmVkIHRoZSB0b3BpY3MgYmV0d2VlbiB0aGUgdHdvIG1lZGlhIG91dGxldHMuIEZvciB0b3BpYyBtb2RlbGxpbmcgd2UgdXNlZCBTdHJ1Y3R1cmFsIFRvcGljIE1vZGVsaW5nIChTVE0pLCBzaW5jZSBpdCBpbmNvcnBvcmF0ZXMgbWV0YWRhdGEgKGluZm9ybWF0aW9uIGFib3V0IGVhY2ggZG9jdW1lbnQpIGludG8gdGhlIHRvcGljIG1vZGVsbGluZyBmcmFtZXdvcmssIHNvIHRoYXQgd2UgY2FuIGRpc2NvdmVyIHRvcGljcyBhbmQgZXN0aW1hdGUgdGhlaXIgcmVsYXRpb25zaGlwIHRvIHRoZSBkb2N1bWVudHMnIG1ldGFkYXRhLg0KDQpTVE0gaXMgYW4gdW5zdXBlcnZpc2VkIG1hY2hpbmUgbGVhcm5pbmcgbW9kZWwgd2hlcmUgd2UgaGF2ZSB0byBkZWZpbmUgdGhlIG51bWJlciBvZiB0b3BpYyBLIGluIGFkdmFuY2UsIHNpbWlsYXJseSB0byBrLW1lYW5zIGNsdXN0ZXJpbmcgd2UgZG8gbm90IGtub3cgYWhlYWQgaG93IG1hbnkgdG9waWNzIHdlIHNob3VsZCB1c2UgZm9yIGFueSBnaXZlbiBjb3JwdXMuIFRoZXJlZm9yZSwgd2UgdHJhaW5lZCBhIGdyb3VwIG9mIHRvcGljIG1vZGVscyB3aXRoIGRpZmZlcmVudCBudW1iZXJzIG9mIEsgKHRvcGljcykgYW5kIHRoZW4gZXZhbHVhdGVkIGhvdyBtYW55IHRvcGljcyBhcmUgYXBwcm9wcmlhdGUuIEhlcmUgd2UgcHJvY2VlZGVkIHdpdGggKipLID0gMjUqKiBmb3IgZWFjaCBvZiB0aGUgbWVkaWEgZm9ybXMuIFRoZSBldmFsdWF0aW9uIG1ldGhvZCBjYW4gYmUgcmVmZXJyZWQgdG8gaW4gW3RoaXMgcG9zdF0oaHR0cHM6Ly9qdWxpYXNpbGdlLmNvbS9ibG9nL2V2YWx1YXRpbmctc3RtLykgYnkgKkp1bGlhIFNpbGdlKi4NCg0KYGBge3IgQ29udmVydCBkZm0gdG8gc3RtIG1vZGVsfQ0KTmV3c19zdG0gPC0gY29udmVydChOZXdzX0RGTSwgdG8gPSAic3RtIikNClR3aXR0ZXJfc3RtIDwtIGNvbnZlcnQoVHdpdHRlcl9ERk0sIHRvID0gInN0bSIpDQpgYGANCg0KYGBge3IgUnVuIHRvcGljIG1vZGVsbGluZywgbWVzc2FnZT1GQUxTRSwgcmVzdWx0cz0naGlkZSd9DQpOZXdzX3RvcGljX21vZGVsIDwtIHN0bSgNCiAgZG9jdW1lbnRzID0gTmV3c19zdG0kZG9jdW1lbnRzLCANCiAgdm9jYWIgPSBOZXdzX3N0bSR2b2NhYiwNCiAgSyA9IDI1LA0KICBwcmV2YWxlbmNlID1+IHMod2VlayksDQogIGRhdGEgPSBOZXdzX3N0bSRtZXRhLA0KICBpbml0LnR5cGUgPSAiU3BlY3RyYWwiLA0KICBzZWVkID0gMTIzNDU2KQ0KDQpUd2l0dGVyX3RvcGljX21vZGVsIDwtIHN0bSgNCiAgZG9jdW1lbnRzID0gVHdpdHRlcl9zdG0kZG9jdW1lbnRzLCANCiAgdm9jYWIgPSBUd2l0dGVyX3N0bSR2b2NhYiwNCiAgSyA9IDI1LA0KICBwcmV2YWxlbmNlID1+IHMod2VlayksDQogIGRhdGEgPSBUd2l0dGVyX3N0bSRtZXRhLA0KICBpbml0LnR5cGUgPSAiU3BlY3RyYWwiLA0KICBzZWVkID0gMTIzNDU2KQ0KYGBgDQoNClRoZSBwbG90cyBiZWxvdyBzaG93IHRoZSB0b3AgMTAgdG9waWNzIGluIGVhY2ggY29ycHVzIChOZXdzLCBUd2l0dGVyKSwgYW5kIHRvcCA3IHdvcmRzIHRoYXQgaGF2ZSB0aGUgaGlnaGVzdCBwcm9iYWJpbGl0eSB0byBiZWxvbmcgdG8gdGhhdCB0b3BpYy4gQSBjbG9zZXIgbG9vayBpbnRvIGVhY2ggc291cmNlIHNob3dlZCB1cyBzb21lIGludGVyZXN0aW5nIHBhdHRlcm5zLiANCg0KYGBge3IgUGxvdCBuZXdzIHRvcGljLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KTmV3c19iZXRhIDwtIHRpZHkoTmV3c190b3BpY19tb2RlbCkNCk5ld3NfZ2FtbWEgPC0gdGlkeShOZXdzX3RvcGljX21vZGVsLCBtYXRyaXggPSAiZ2FtbWEiKQ0KDQpOZXdzX3RvcF90ZXJtcyA8LSBOZXdzX2JldGEgJT4lDQogIGFycmFuZ2UoYmV0YSkgJT4lDQogIGdyb3VwX2J5KHRvcGljKSAlPiUNCiAgdG9wX24oNywgYmV0YSkgJT4lDQogIGFycmFuZ2UoLWJldGEpICU+JQ0KICBzZWxlY3QodG9waWMsIHRlcm0pICU+JQ0KICBzdW1tYXJpc2UodGVybXMgPSBsaXN0KHRlcm0pKSAlPiUNCiAgbXV0YXRlKHRlcm1zID0gbWFwKHRlcm1zLCBwYXN0ZSwgY29sbGFwc2UgPSAiLCAiKSkgJT4lIA0KICB1bm5lc3QoKQ0KDQpOZXdzX2dhbW1hX3Rlcm1zIDwtIE5ld3NfZ2FtbWEgJT4lDQogIGdyb3VwX2J5KHRvcGljKSAlPiUNCiAgc3VtbWFyaXNlKGdhbW1hID0gbWVhbihnYW1tYSkpICU+JQ0KICBhcnJhbmdlKGRlc2MoZ2FtbWEpKSAlPiUNCiAgbGVmdF9qb2luKE5ld3NfdG9wX3Rlcm1zLCBieSA9ICJ0b3BpYyIpICU+JQ0KICBtdXRhdGUodG9waWMgPSBwYXN0ZTAoIlRvcGljICIsIHRvcGljKSwNCiAgICAgICAgIHRvcGljID0gcmVvcmRlcih0b3BpYywgZ2FtbWEpKQ0KDQpOZXdzX2dhbW1hX3Rlcm1zICU+JQ0KICB0b3BfbigxMCwgZ2FtbWEpICU+JQ0KICBnZ3Bsb3QoYWVzKHRvcGljLCBnYW1tYSwgbGFiZWwgPSB0ZXJtcywgZmlsbCA9IHRvcGljKSkgKw0KICBnZW9tX2NvbChzaG93LmxlZ2VuZCA9IEZBTFNFKSArDQogIGdlb21fdGV4dChoanVzdCA9IDAuOCwgbnVkZ2VfeSA9IDAuMDAwNSwgc2l6ZSA9IDMsDQogICAgICAgICAgICBmYW1pbHkgPSAiSUJNUGxleFNhbnMiKSArDQogIGNvb3JkX2ZsaXAoKSArDQogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCksDQogICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDAsIDAuMDkpLA0KICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gcGVyY2VudF9mb3JtYXQoKSkgKw0KICB0aGVtZV90dWZ0ZShiYXNlX2ZhbWlseSA9ICJJQk1QbGV4U2FucyIsIHRpY2tzID0gRkFMU0UpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFtaWx5PSJJQk1QbGV4U2Fucy1Cb2xkIiksDQogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEzKSkgKw0KICBsYWJzKHggPSBOVUxMLCB5ID0gZXhwcmVzc2lvbihnYW1tYSksDQogICAgICAgdGl0bGUgPSAiVG9wIDEwIHRvcGljcyBieSBwb3B1bGFyaXR5IG9uIE5ld3MgQXJ0aWNsZXMiLA0KICAgICAgIHN1YnRpdGxlID0gIldpdGggdGhlIHRvcCB3b3JkcyB0aGF0IGNvbnRyaWJ1dGUgdG8gZWFjaCB0b3BpYyIpDQpgYGANCg0KYGBge3IgUGxvdCB0d2l0dGVyIHRvcGljLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KVHdpdHRlcl9iZXRhIDwtIHRpZHkoVHdpdHRlcl90b3BpY19tb2RlbCkNClR3aXR0ZXJfZ2FtbWEgPC0gdGlkeShUd2l0dGVyX3RvcGljX21vZGVsLCBtYXRyaXggPSAiZ2FtbWEiKQ0KDQpUd2l0dGVyX3RvcF90ZXJtcyA8LSBUd2l0dGVyX2JldGEgJT4lDQogIGFycmFuZ2UoYmV0YSkgJT4lDQogIGdyb3VwX2J5KHRvcGljKSAlPiUNCiAgdG9wX24oNywgYmV0YSkgJT4lDQogIGFycmFuZ2UoLWJldGEpICU+JQ0KICBzZWxlY3QodG9waWMsIHRlcm0pICU+JQ0KICBzdW1tYXJpc2UodGVybXMgPSBsaXN0KHRlcm0pKSAlPiUNCiAgbXV0YXRlKHRlcm1zID0gbWFwKHRlcm1zLCBwYXN0ZSwgY29sbGFwc2UgPSAiLCAiKSkgJT4lIA0KICB1bm5lc3QoKQ0KDQpUd2l0dGVyX2dhbW1hX3Rlcm1zIDwtIFR3aXR0ZXJfZ2FtbWEgJT4lDQogIGdyb3VwX2J5KHRvcGljKSAlPiUNCiAgc3VtbWFyaXNlKGdhbW1hID0gbWVhbihnYW1tYSkpICU+JQ0KICBhcnJhbmdlKGRlc2MoZ2FtbWEpKSAlPiUNCiAgbGVmdF9qb2luKFR3aXR0ZXJfdG9wX3Rlcm1zLCBieSA9ICJ0b3BpYyIpICU+JQ0KICBtdXRhdGUodG9waWMgPSBwYXN0ZTAoIlRvcGljICIsIHRvcGljKSwNCiAgICAgICAgIHRvcGljID0gcmVvcmRlcih0b3BpYywgZ2FtbWEpKQ0KDQpUd2l0dGVyX2dhbW1hX3Rlcm1zICU+JQ0KICB0b3BfbigxMCwgZ2FtbWEpICU+JQ0KICBnZ3Bsb3QoYWVzKHRvcGljLCBnYW1tYSwgbGFiZWwgPSB0ZXJtcywgZmlsbCA9IHRvcGljKSkgKw0KICBnZW9tX2NvbChzaG93LmxlZ2VuZCA9IEZBTFNFKSArDQogIGdlb21fdGV4dChoanVzdCA9IDAuODUsIG51ZGdlX3kgPSAwLjAwMDUsIHNpemUgPSAzLA0KICAgICAgICAgICAgZmFtaWx5ID0gIklCTVBsZXhTYW5zIikgKw0KICBjb29yZF9mbGlwKCkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApLA0KICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygwLCAwLjA5KSwNCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHBlcmNlbnRfZm9ybWF0KCkpICsNCiAgdGhlbWVfdHVmdGUoYmFzZV9mYW1pbHkgPSAiSUJNUGxleFNhbnMiLCB0aWNrcyA9IEZBTFNFKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhbWlseT0iSUJNUGxleFNhbnMtQm9sZCIpLA0KICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMykpICsNCiAgbGFicyh4ID0gTlVMTCwgeSA9IGV4cHJlc3Npb24oZ2FtbWEpLA0KICAgICAgIHRpdGxlID0gIlRvcCAxMCB0b3BpY3MgYnkgcG9wdWxhcml0eSBvbiBUd2l0dGVyIiwNCiAgICAgICBzdWJ0aXRsZSA9ICJXaXRoIHRoZSB0b3Agd29yZHMgdGhhdCBjb250cmlidXRlIHRvIGVhY2ggdG9waWMiKQ0KYGBgDQoNClRoZSBrZXkgZm9jdXNlcyBvbiBUd2l0dGVyIGFyZSBhYm91dCBzb21ldGhpbmcgbGlrZSDigJx0aGUgc3ByZWFkIG9mIHZpcnVzIChUb3BpYyAxMSkiLCAg4oCcbmVnYXRpdmUgcmVhY3Rpb24gKFRvcGljIDcsIDIzKeKAnSwg4oCcdXBkYXRlIG9uIHRoZSBwYW5kZW1pYyBpbmZvcm1hdGlvbiAoVG9waWMgMTMsIDQpIi4gT24gdGhlIGNvbnRyYXJ5LCB3aGVuIGxvb2tpbmcgaW50byBOZXdzIHRvcGljcywgd2UgY2FuIHNlZSBhIHJlbGF0aXZlbHkgZGlmZmVyZW5jZSBwYXR0ZXJuLCB3aGljaCBpcyBtb3JlIHJlbGF0ZWQgdG8g4oCccG9saXRpY2FsIG1hdHRlcnMg4oCTIHRvcGljIDIy4oCdLCDigJxzaXR1YXRpb24gaW4gb3RoZXIgY291bnRyeSAtIHRvcGljIDE54oCdLCDigJxlY29ub215IHNpdHVhdGlvbiDigJMgdG9waWMgNOKAnSwgImhlYWx0aGNhcmUgc3lzdGVtIHNpdHVhdGlvbiAoVG9waWMgMjAsIDIxKSIuIFRoZSBtZXNzYWdlIGFib3V0IGZhbWlseSBpcyBwb3B1bGFyIGluIGJvdGggc291cmNlcyAoTmV3cyBUb3BpYyAxMywgVHdpdHRlciBUb3BpYyAxOCkuIEZ1cnRoZXJtb3JlLCBwb2xpdGljaWFucyBhcmUgd2VsbC1jb3ZlcmVkLCB3aXRoIFRydW1wIG9uIFR3aXR0ZXIgYW5kIFBlbmNlLyBDdW9tbyBvbiBtYWluc3RyZWFtIHBhcGVycy4NCg0KIyBTZW50aW1lbnQgQW5hbHlzaXMNCg0KIyMgQ29ycHVzIHNlbnRpbWVudCBhbmFseXNpcw0KDQpUbyBpbnZlc3RpZ2F0ZSBzZW50aW1lbnRzIGluIG5ld3MgYXJ0aWNsZXMgYW5kIHR3ZWV0cywgdG9rZW5zIGV4dHJhY3RlZCBmcm9tIHRoZSBkb2N1bWVudHMgYXJlIHVzZWQgdG8gY2FsY3VsYXRlIHNlbnRpbWVudCBzY29yZXMgd2l0aCB0aGUgQUZJTk4gbGV4aWNvbiBkZXZlbG9wZWQgYnkgRmlubiDDhXJ1cCBOaWVsc2VuLCB3aGljaCBpcyBpbmNsdWRlZCBpbiB0aGUgdGlkeXRleHQgcGFja2FnZS4gVGhlIEFGSU5OIGxleGljb24gaXMgYSBsaXN0IG9mIEVuZ2xpc2ggdGVybXMgbWFudWFsbHkgcmF0ZWQgZm9yIHZhbGVuY2Ugd2l0aCBhbiBpbnRlZ2VyIGJldHdlZW4gLTUgKG5lZ2F0aXZlKSBhbmQgKzUgKHBvc2l0aXZlKS4gSXQgY29tcHJpc2VzIDg3OCBwb3NpdGl2ZSB0ZXJtcyBhbmQgMSw1OTggbmVnYXRpdmUgdGVybXMuIFRoZSBzZW50aW1lbnQgc2NvcmUgaXMgdGhlIHBlcmNlbnRhZ2Ugb2YgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgYWJzb2x1dGUgc3VtIG9mIHBvc2l0aXZlIHRlcm1zIGFuZCBuZWdhdGl2ZSB0ZXJtcyBkaXZpZGVkIGJ5IHRoZSB0b3RhbCBzdW0gb2YgdGhlbS4NCg0KYGBge3IgUHJlcGFyYXRpb24sIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQojIE1ha2UgYSBkYXRhZnJhbWUgd2l0aCB0aGUgQUZJTk4gZGljdGlvbmFyeQ0KYWZpbm4gPC0gZ2V0X3NlbnRpbWVudHMoImFmaW5uIikNCg0KTmV3c19leHQgPC0gY29udmVydChOZXdzX0RGTSwgdG8gPSAidHJpcGxldGxpc3QiKQ0KTmV3c19kZiA8LSBkYXRhLmZyYW1lKGRvYyA9IE5ld3NfZXh0JGRvY3VtZW50LA0KICAgICAgICAgICAgICAgICAgICAgICAgd29yZCA9IE5ld3NfZXh0JGZlYXR1cmUsDQogICAgICAgICAgICAgICAgICAgICAgICBmcmVxID0gTmV3c19leHQkZnJlcXVlbmN5KQ0KTmV3c19kZiR3b3JkIDwtIGFzLmNoYXJhY3RlcihOZXdzX2RmJHdvcmQpDQoNCk5ld3NfYWZpbm4gPC0gTmV3c19kZiAlPiUgDQogIGlubmVyX2pvaW4oYWZpbm4sIGJ5ID0gIndvcmQiKSAlPiUgDQogIG11dGF0ZShzY29yZSA9IGZyZXEgKiB2YWx1ZSkgJT4lIA0KICBzZXBhcmF0ZShkb2MsIGludG8gPSBjKCJ3ZWVrIiwgIm5vIiksIHNlcCA9ICJcXC4iKSAlPiUgDQogIG11dGF0ZShzZW50aW1lbnQgPSBpZmVsc2Uoc2NvcmUgPiAwLCAicG9zaXRpdmUiLCAibmVnYXRpdmUiKSkgJT4lIA0KICBncm91cF9ieSh3ZWVrLCBzZW50aW1lbnQpICU+JSANCiAgc3VtbWFyaXNlKHNlbnRpbWVudF9zY29yZSA9IHN1bShzY29yZSkpICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgbXV0YXRlKHNvdXJjZSA9ICJOZXdzIikNCg0KVHdpdHRlcl9leHQgPC0gY29udmVydChUd2l0dGVyX0RGTSwgdG8gPSAidHJpcGxldGxpc3QiKQ0KVHdpdHRlcl9kZiA8LSBkYXRhLmZyYW1lKGRvYyA9IFR3aXR0ZXJfZXh0JGRvY3VtZW50LA0KICAgICAgICAgICAgICAgICAgICAgIHdvcmQgPSBUd2l0dGVyX2V4dCRmZWF0dXJlLA0KICAgICAgICAgICAgICAgICAgICAgIGZyZXEgPSBUd2l0dGVyX2V4dCRmcmVxdWVuY3kpDQpUd2l0dGVyX2RmJHdvcmQgPC0gYXMuY2hhcmFjdGVyKFR3aXR0ZXJfZGYkd29yZCkNCg0KVHdpdHRlcl9hZmlubiA8LSBUd2l0dGVyX2RmICU+JSANCiAgaW5uZXJfam9pbihhZmlubiwgYnkgPSAid29yZCIpICU+JSANCiAgbXV0YXRlKHNjb3JlID0gZnJlcSAqIHZhbHVlKSAlPiUgDQogIHNlcGFyYXRlKGRvYywgaW50byA9IGMoIndlZWsiLCAibm8iKSwgc2VwID0gIlxcLiIpICU+JSANCiAgbXV0YXRlKHNlbnRpbWVudCA9IGlmZWxzZShzY29yZSA+IDAsICJwb3NpdGl2ZSIsICJuZWdhdGl2ZSIpKSAlPiUgDQogIGdyb3VwX2J5KHdlZWssIHNlbnRpbWVudCkgJT4lIA0KICBzdW1tYXJpc2Uoc2VudGltZW50X3Njb3JlID0gc3VtKHNjb3JlKSkgJT4lIA0KICB1bmdyb3VwKCkgJT4lIA0KICBtdXRhdGUoc291cmNlID0gIlR3aXR0ZXIiKQ0KDQojIENyZWF0ZSBhIGRhdGFmcmFtZSB0byBwbG90IHNlbnRpbWVudA0KTmV3c19hZmlubl9wbG90IDwtIE5ld3NfYWZpbm4gJT4lIA0KICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gc2VudGltZW50LCB2YWx1ZXNfZnJvbSA9IHNlbnRpbWVudF9zY29yZSkgJT4lIA0KICBtdXRhdGUoc3VtID0gcG9zaXRpdmUgKyAoLTEpKm5lZ2F0aXZlLCANCiAgICAgICAgIHBvc19wZXJjZW50ID0gcG9zaXRpdmUvc3VtKjEwMCwNCiAgICAgICAgIG5lZ19wZXJjZW50ID0gKC0xKSpuZWdhdGl2ZS9zdW0qMTAwLCANCiAgICAgICAgIHBvbGFyaXR5ID0gcm91bmQoKHBvc19wZXJjZW50IC0gbmVnX3BlcmNlbnQpLDMpKSAlPiUNCiAgc2VsZWN0KHdlZWssIHBvbGFyaXR5LCBzb3VyY2UpDQoNClR3aXR0ZXJfYWZpbm5fcGxvdCA8LSBUd2l0dGVyX2FmaW5uICU+JSANCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHNlbnRpbWVudCwgdmFsdWVzX2Zyb20gPSBzZW50aW1lbnRfc2NvcmUpICU+JSANCiAgbXV0YXRlKHN1bSA9IHBvc2l0aXZlICsgKC0xKSpuZWdhdGl2ZSwgDQogICAgICAgICBwb3NfcGVyY2VudCA9IHBvc2l0aXZlL3N1bSoxMDAsDQogICAgICAgICBuZWdfcGVyY2VudCA9ICgtMSkqbmVnYXRpdmUvc3VtKjEwMCwgDQogICAgICAgICBwb2xhcml0eSA9IHJvdW5kKChwb3NfcGVyY2VudCAtIG5lZ19wZXJjZW50KSwzKSkgJT4lDQogIHNlbGVjdCh3ZWVrLCBwb2xhcml0eSwgc291cmNlKQ0KDQojIEV4dHJhY3QgYmV0YSBtYXRyaXggdG8gZGF0YSBmcmFtZSBmb3JtYXQuIFVzaW5nIEFGSU5OIGxleGljb24sIG1ha2UgYSBkYXRhIGZyYW1lIHdpdGggdGhlIHNlbnRpbWVudCBmb3IgZWFjaCB3b3JkDQpOZXdzX2JldGEgPC0gdGlkeShOZXdzX3RvcGljX21vZGVsLCBtYXRyaXggPSAiYmV0YSIpDQpOZXdzX3RvcGljX3NjIDwtIGlubmVyX2pvaW4oTmV3c19iZXRhLCBhZmlubiwgYnkgPSBjKCJ0ZXJtIiA9ICJ3b3JkIikpICU+JSANCiAgbXV0YXRlKHNjb3JlID0gYmV0YSAqIHZhbHVlKSAlPiUgDQogIGdyb3VwX2J5KHRvcGljKSAlPiUgDQogIHN1bW1hcmlzZShzZW50aW1lbnRfc2NvcmUgPSBzdW0oc2NvcmUpKQ0KTmV3c190b3BpY19zYyR0b3BpYyA8LSBmYWN0b3IoTmV3c190b3BpY19zYyR0b3BpYywgbGV2ZWxzID0gYygxOjI1KSkNCg0KVHdpdHRlcl9iZXRhIDwtIHRpZHkoVHdpdHRlcl90b3BpY19tb2RlbCwgbWF0cml4ID0gImJldGEiKQ0KVHdpdHRlcl90b3BpY19zYyA8LSBpbm5lcl9qb2luKFR3aXR0ZXJfYmV0YSwgYWZpbm4sIGJ5ID0gYygidGVybSIgPSAid29yZCIpKSAlPiUgIA0KICBtdXRhdGUoc2NvcmUgPSBiZXRhICogdmFsdWUpICU+JSANCiAgZ3JvdXBfYnkodG9waWMpICU+JSANCiAgc3VtbWFyaXNlKHNlbnRpbWVudF9zY29yZSA9IHN1bShzY29yZSkpDQpUd2l0dGVyX3RvcGljX3NjJHRvcGljIDwtIGZhY3RvcihUd2l0dGVyX3RvcGljX3NjJHRvcGljLCBsZXZlbHMgPSBjKDE6MjUpKQ0KYGBgDQoNCmBgYHtyIFBsb3QgQUZJTk4gc2VudGltZW50IGFuYWx5c2lzLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KYWZpbm5fY2hhcnRfYWxsIDwtIHJiaW5kKE5ld3NfYWZpbm5fcGxvdCwgVHdpdHRlcl9hZmlubl9wbG90KQ0KYWZpbm5fY2hhcnRfYWxsJHdlZWsgPC0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoYWZpbm5fY2hhcnRfYWxsJHdlZWspKQ0KYWZpbm5fY2hhcnRfYWxsICU+JSANCiAgYXJyYW5nZSh3ZWVrKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IHdlZWssIHkgPSBwb2xhcml0eSwgY29sb3IgPSBzb3VyY2UpKSArIA0KICBnZW9tX3BvaW50KCkgKw0KICBnZW9tX3BhdGgoKSArDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGNvbG9yID0gImdvbGQzIikgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAxMiwgY29sb3IgPSAiY29yYWwyIikgKw0KICBsYWJzKHggPSAiV2VlayIsIHkgPSAiU2VudGltZW50IFNjb3JlIikgKyANCiAgc2NhbGVfeF9jb250aW51b3VzKCAgIyBUaGlzIGhhbmRsZXMgcmVwbGFjZW1lbnQgb2Ygcm93IA0KICAgIGJyZWFrcyA9IGFmaW5uX2NoYXJ0X2FsbCR3ZWVrLCAjIG5vdGljZSBuZWVkIHRvIHJldXNlIGRhdGEgZnJhbWUNCiAgICBsYWJlbHMgPSBhZmlubl9jaGFydF9hbGwkd2VlaykgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobi5icmVha3MgPSAxMCkgKw0KICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIiNFMzIxMUMiLCAiIzFGNzhCNCIpKSArDQogIHRoZW1lKHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBOVUxMLA0KICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiksDQogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpLA0KICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSwNCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpDQoNCmBgYA0KDQpPdmVyYWxsLCB0aGUgb3BpbmlvbiB0b3dhcmRzIENPVklELTE5IHJlbWFpbmVkIG5lZ2F0aXZlIHRocm91Z2hvdXQgdGhlIHBlcmlvZC4gV2hpbGUgbmV3cyB3YXMgYSBiaXQgbW9yZSBwb3NpdGl2ZSB0aGFuIFR3aXR0ZXIsIHRoZXJlIHdhcyBhIHNpbWlsYXIgcGF0dGVybiBhcyB0aGUgc2VudGltZW50IHNjb3JlcyB3ZXJlIGhpZ2hseSBuZWdhdGl2ZSBpbiB3ZWVrIDMgYnV0IHNob3dlZCBhIHBvc2l0aXZlIHRyZW5kIGluIHRoZSBzdWJzZXF1ZW50IHdlZWtzLiBBdCB3ZWVrIDEyIHdoZW4gdGhlIHNpdHVhdGlvbiBnb3Qgd29yc2UgaW4gdGhlIFVTLCB0aGUgc2VudGltZW50IHNjb3JlIG9mIG5ld3MgYXJ0aWNsZXMgd2VudCBkb3duIHRoZW4gcGlja2VkIHVwIGFnYWluIGF0IHdlZWsgMTUsIHdoZXJlYXMgVHdpdHRlciBzaG93ZWQgYSBjb25zaXN0ZW50IHNlbnRpbWVudC4NCg0KV2l0aCB0aGUgcHVycG9zZSBvZiBleGFtaW5pbmcgZnJvbSBzZXZlcmFsIHBlcnNwZWN0aXZlcywgd2UgYWxzbyBtYWRlIHVzZSBvZiB0aGUgTlJDIGxleGljb24gZnJvbSBTYWlmIE1vaGFtbWFkIGFuZCBQZXRlciBUdXJuZXkuIFRoZSBOUkMgbGV4aWNvbiBjYXRlZ29yaXplcyB3b3JkcyBpbiBhIGJpbmFyeSBmYXNoaW9uICjigJx5ZXPigJ0vIOKAnG5v4oCdKSBpbnRvIGNhdGVnb3JpZXMgb2YgcG9zaXRpdmUsIG5lZ2F0aXZlLCBhbmdlciwgYW50aWNpcGF0aW9uLCBkaXNndXN0LCBmZWFyLCBqb3ksIHNhZG5lc3MsIHN1cnByaXNlLCBhbmQgdHJ1c3QuIFdlIGZpbHRlcmVkIG91dCB0aGUgcG9zaXRpdmUgYW5kIG5lZ2F0aXZlIGNhdGVnb3JpZXMgd2hpY2ggbGVmdCB1cyB3aXRoIDQsNDYzIGRpc3RpbmN0IHdvcmRzIGluIHRoZSBsZXhpY29uIChOb3RlOiBvbmUgd29yZCBjYW4gYmUgaW4gbXVsdGlwbGUgc2VudGltZW50IGNhdGVnb3JpZXMpLiBXZSBjb3VudGVkIHRoZSBudW1iZXIgb2Ygd29yZHMgaW4gZWFjaCBjYXRlZ29yeSBhbmQgY29tcHV0ZWQgdGhlaXIgcGVyY2VudGFnZSBkaXN0cmlidXRpb24gaW4gZWFjaCBvZiBvdXIgc291cmNlcy4gQXBwbHlpbmcgTlJDIGxleGljb24gdG8gaW5zcGVjdCB0aGUgZGF0YSBpbiBkaWZmZXJlbnQgY2F0ZWdvcmljYWwgc2VudGltZW50cywgd2UgcHJlc2VudGVkIHRoZSByZXN1bHQgaW4gYSByYWRhciBjaGFydDoNCg0KYGBge3IgUGxvdCBOUkMgc2VudGltZW50IGFuYWx5c2lzLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KbnJjIDwtIGdldF9zZW50aW1lbnRzKCJucmMiKSAlPiUgDQogIGZpbHRlcighc2VudGltZW50ICVpbiUgIGMoInBvc2l0aXZlIiwgIm5lZ2F0aXZlIikpDQoNCiMgTmV3cyBqb2luIGFuZCBjYWxjdWxhdGUgc2NvcmUNCk5ld3NfbnJjIDwtIE5ld3NfZGYgJT4lIA0KICBpbm5lcl9qb2luKG5yYykgJT4lIA0KICBzZXBhcmF0ZShkb2MsIGludG8gPSBjKCJ3ZWVrIiwgIm5vIiksIHNlcCA9ICJcXC4iKSAlPiUgDQogIGdyb3VwX2J5KHdlZWssIHNlbnRpbWVudCkgJT4lIA0KICBzdW1tYXJpc2UoY291bnQgPSBzdW0oZnJlcSkpDQpOZXdzX25yY19zdW0gPC0gTmV3c19ucmMgJT4lIA0KICBncm91cF9ieShzZW50aW1lbnQpICU+JSANCiAgc3VtbWFyaXNlKHRvdGFsX2NvdW50ID0gc3VtKGNvdW50KSkgJT4lIA0KICB1bmdyb3VwKCkNCk5ld3NfbnJjX3N1bSA8LSBOZXdzX25yY19zdW0gJT4lIA0KICBtdXRhdGUocGVyY2VudCA9IHRvdGFsX2NvdW50LyBzdW0oTmV3c19ucmNfc3VtJHRvdGFsX2NvdW50KSwNCiAgICAgICAgIHNvdXJjZSA9ICJOZXdzIikNCg0KIyBUd2l0dGVyIGpvaW4gYW5kIGNhbGN1bGF0ZSBzY29yZQ0KVHdpdHRlcl9ucmMgPC0gVHdpdHRlcl9kZiAlPiUgDQogIGlubmVyX2pvaW4obnJjKSAlPiUgDQogIHNlcGFyYXRlKGRvYywgaW50byA9IGMoIndlZWsiLCAibm8iKSwgc2VwID0gIlxcLiIpICU+JSANCiAgZ3JvdXBfYnkod2Vlaywgc2VudGltZW50KSAlPiUgDQogIHN1bW1hcmlzZShjb3VudCA9IHN1bShmcmVxKSkNClR3aXR0ZXJfbnJjX3N1bSA8LSBUd2l0dGVyX25yYyAlPiUgDQogIGdyb3VwX2J5KHNlbnRpbWVudCkgJT4lIA0KICBzdW1tYXJpc2UodG90YWxfY291bnQgPSBzdW0oY291bnQpKSAlPiUgDQogIHVuZ3JvdXAoKQ0KVHdpdHRlcl9ucmNfc3VtIDwtIFR3aXR0ZXJfbnJjX3N1bSAlPiUgDQogIG11dGF0ZShwZXJjZW50ID0gdG90YWxfY291bnQvIHN1bShUd2l0dGVyX25yY19zdW0kdG90YWxfY291bnQpLA0KICAgICAgICAgc291cmNlID0gIlR3aXR0ZXIiKQ0KDQojIENvbWJpbmUgZGF0YSBhbmQgcGxvdCByYWRhciBjaGFydA0KbnJjX2NoYXJ0X2FsbCA8LSByYmluZChOZXdzX25yY19zdW0sIFR3aXR0ZXJfbnJjX3N1bSkNCm5yY19jaGFydF9hbGwgJT4lIA0KICBzZWxlY3QoLXRvdGFsX2NvdW50KSAlPiUgDQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBzb3VyY2UsIHZhbHVlc19mcm9tID0gcGVyY2VudCkgJT4lIA0KICBjaGFydEpTUmFkYXIod2lkdGggPSA4LA0KICAgICAgICAgICAgICAgaGVpZ2h0ID0gNSwNCiAgICAgICAgICAgICAgIHNob3dUb29sVGlwTGFiZWwgPSBGQUxTRSwNCiAgICAgICAgICAgICAgIGNvbE1hdHJpeCA9IGdyRGV2aWNlczo6Y29sMnJnYihjKCJyZWQiLCAiYmx1ZSIsICJncmVlbiIpKSwNCiAgICAgICAgICAgICAgIGxhYmVsU2l6ZSA9IDE4KQ0KYGBgDQoNCk92ZXJhbGwsIG5ld3MgYXJ0aWNsZXMgc2hvd2VkIHRoZSBtb3N0IHBvc2l0aXZpdHkgYnkgY29taW5nIG9uIHRvcCBvZiDigJxqb3nigJ0gYW5kIOKAnHRydXN04oCdLCBidXQgaXQgYWxzbyBoYWQgbW9yZSDigJxhbmdlcuKAnSB3b3Jkcy4gUmVkZGl0IHdlcmUgZG9taW5hbnQgaW4gbW9zdCBuZWdhdGl2ZSBjYXRlZ29yaWVzLCBzdWNoIGFzIOKAnHNhZG5lc3PigJ0sIOKAnGZlYXLigJ0gYW5kIOKAnGFudGljaXBhdGlvbuKAnS4gVHdpdHRlcuKAmXMgcG9zdHMgd2VyZSBtb3JlIG5lZ2F0aXZlLCBhcyB0aGV5IGV4cHJlc3NlZCDigJxkaXNndXN04oCdLCAic2FkbmVzcyIsIGFuZCBzb21laG93ICJzdXJwcmlzZSIuIFRoaXMgdHVybmVkIG91dCB0byBiZSBhIHJlbGV2YW50IGludGVycHJldGF0aW9uIG9mIHRoZSBvdXRjb21lIG9mIHRoZSBBRklOTiBsZXhpY29uIGFuYWx5c2lzIGFib3ZlLiANCg0KIyMgVG9waWMtYmFzZWQgc2VudGltZW50IGFuYWx5c2lzDQoNCk9uIHRoZSB0b3BpYy1iYXNlZCBsZXZlbCwgd2UgYXNzaWduZWQgdGhlIHNlbnRpbWVudCB2YWx1ZSBmb3IgZWFjaCB0b3BpYyB3b3JkIGJhc2VkIG9uIHRoZSBsZXhpY29uIGFuZCB0aGUgcHJvYmFiaWxpdHkgb2YgYSB3b3JkIGluIGEgdG9waWMgZ2l2ZW4gYnkgdGhlIFNUTSB0b3BpYyBtb2RlbCBhcyB0aGUgdGVybSB3ZWlnaHQgb2YgdGhlIHdvcmQuIEFzIGEgcmVzdWx0LCB0b3BpYyBzZW50aW1lbnQgc2NvcmUgaXMgY2FsY3VsYXRlZCBhcw0KDQokJFNlbnRpbWVudFwgU2NvcmVcIG9mXCBUb3BpY1wgQSA9IFxzdW1fe2k9MX1ee259IChwcm9iKHdvcmRfaXxUb3BpY19BKSpzZW50aW1lbnRcIHZhbHVlKHdvcmRfaSkpJCQNCg0KQW4gb3ZlcmFsbCB0b3BpYyBzZW50aW1lbnQgc2NvcmUgaXMgY29tcHV0ZWQgYnkgbXVsdGlwbHlpbmcgdGhlIHNlbnRpbWVudCB2YWx1ZSBieSB0aGUgcHJvYmFiaWxpdHkgb2Ygd29yZHMgYW5kIHN1bW1pbmcgdGhlIHByb2R1Y3RzIGluIGEgY2hvc2VuIHRvcGljLiBNdWx0aXBsZSB0b3BpY3MgY291bGQgaGF2ZSB0aGUgc2FtZSB3b3JkcyB3aXRoIGRpZmZlcmVudCBwcm9iYWJpbGl0eSB2YWx1ZXMuIFRoZXJlZm9yZSwgdGhlIHNlbnRpbWVudCBzY29yZSBvZiBhIHRvcGljIHdvdWxkIGJlIGRpc3Rpbmd1aXNoZWQgZnJvbSBvdGhlcnMgZXZlbiBpZiB0aGUgc2FtZSBzZXQgb2Ygd29yZHMgYXBwZWFyIGluIGRpZmZlcmVudCB0b3BpY3MuDQoNCmBgYHtyIFRvcGljLWJhc2VkIHNlbnRpbWVudCBhbmFseXNpcywgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCg0KIyBOZXdzDQpOZXdzX3RvcGljX3NjX3Bsb3QgPC0gTmV3c190b3BpY19zYyAlPiUgDQogIGdncGxvdChhZXMoeCA9IHRvcGljLCB5ID0gc2VudGltZW50X3Njb3JlKSkgKyANCiAgZ2VvbV9jb2woZmlsbCA9ICIjRTMyMTFDIikgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBjb2xvciA9ICJnb2xkMyIpICsNCiAgbGFicyh4ID0gTlVMTCwgeSA9IE5VTEwsIHN1YnRpdGxlID0gIk5ld3MiKSArIA0KICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygtMSwgMC4yKSwgbi5icmVha3MgPSA4KSArDQogIHRoZW1lKHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBOVUxMLA0KICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiksDQogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpLA0KICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMS41KSkpDQoNCiMgVHdpdHRlcg0KVHdpdHRlcl90b3BpY19zY19wbG90IDwtIFR3aXR0ZXJfdG9waWNfc2MgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSB0b3BpYywgeSA9IHNlbnRpbWVudF9zY29yZSkpICsgDQogIGdlb21fY29sKGZpbGwgPSAiIzFGNzhCNCIpICsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgY29sb3IgPSAiZ29sZDMiKSArDQogIGxhYnMoeCA9ICJUb3BpYyIsIHkgPSBOVUxMLCBzdWJ0aXRsZSA9ICJUd2l0dGVyIikgKyANCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoLTEsIDAuMiksIG4uYnJlYWtzID0gOCkgKw0KICB0aGVtZShwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gTlVMTCwNCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpLA0KICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwNCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDEuNSkpKQ0KDQpncmlkLmFycmFuZ2UoTmV3c190b3BpY19zY19wbG90LCBUd2l0dGVyX3RvcGljX3NjX3Bsb3QpDQpgYGANCg0KVXNpbmcgU1RNIG1vZGVsIHdpdGggdGhlIHNhbWUgbnVtYmVyIG9mIHRvcGljcyBvZiAyNSwgd2UgY2FsY3VsYXRlZCB0aGUgc2VudGltZW50IHNjb3JlIG9mIGVhY2ggdG9waWMuIEFnYWluLCB0aGUgZ2VuZXJhbCBvcGluaW9ucyBpbiBtb3N0IHRvcGljcyB3ZXJlIG5lZ2F0aXZlLiBUaGUgc2VudGltZW50cyB3ZXJlIG1vcmUgc2lnbmlmaWNhbnQgaW4gVHdpdHRlciwgd2hpbGUgaW4gbmV3cyBhcnRpY2xlcyBtb3N0IHRvcGljcyBoYWQgdGhlIHNjb3JlcyBjbG9zZXIgdG8gbmV1dHJhbC4gVG9waWMgNyBpbiBUd2l0dGVyIHdhcyBleHRyZW1lbHkgbmVnYXRpdmUsIHdoaWNoIG1vc3RseSBjb25zaXN0IG9mIHNlbnRpbWVudGFsIHdvcmRzIChoZWxsLCB5YWxsLCBzaGl04oCmKS4gVGhpcyB3YXMgb25lIGRvd25zaWRlIG9mIHVuc3VwZXJ2aXNlZCB0b3BpYyBtb2RlbGxpbmcsIGFzIGl0IGdyb3VwZWQgdGhlc2Ugc2VudGltZW50YWwgd29yZHMgdG9nZXRoZXIgaW4gb25lIHRvcGljLCBidXQgdGhlIGludGVycHJldGF0aW9uIHdhcyBub3QgdXNlZnVsIGZvciB0b3BpYyBkaXNjb3ZlcnkuIEV4Y2x1ZGluZyB0aGUgdG9waWNzIGFib3ZlLCBuZXdzIGFuZCBUd2l0dGVyIGhhZCBhIGZldyBub3RhYmxlIG5lZ2F0aXZpdGllcywgd2l0aCB0b3BpYyAyMiAocG9saXRpY2FsLCBwZW5jZSwgdHdlZXQsIGJsYW1lLCBwYXJ0eSwgYXR0YWNr4oCmKSBhbmQgMjMgKHBvbGljZSwgcHJpc29uLCBjb3VydCwgbGF3LCBqYWls4oCmKSBpbiBuZXdzIGFuZCB0b3BpYyAxMiAoZGllLCBmbHUsIHRydW1w4oCmKSBpbiBUd2l0dGVyLiBUd2l0dGVyIHVzZXJzIHNlZW1lZCB0byBoYXZlIHRoZSBjb25jZXJucyBjZW50ZXJlZCBhcm91bmQgUHJlc2lkZW50IFRydW1w4oCZcyBiZWhhdmlvcnMsIHdoaWxlIHRoZSBuZXdzIG1lZGlhIGdyYXZpdGF0ZWQgdG93YXJkcyB0aGUgY29uZmxpY3Qgb2YgcG9saXRpY2FsIHBhcnRpZXMgYW5kIHdvcnJpZXMgYWJvdXQgc29jaWFsIHNlY3VyaXR5Lg0KDQpBbW9uZyB0aGUgcG9zaXRpdmUgdG9waWNzLCB0aGVyZSB3YXMgYSBob21vZ2VuZW91cyB0aGVtIGluIGFsbCBzb3VyY2VzLiBUb3BpYyAxMyBpbiB0aGUgbmV3cyAobG92ZSwgY2h1cmNoLCBtb21lbnQsIHdpZmUsIG1vdGhlcuKApikgYW5kIFRvcGljIDE4IChmYW1pbHksIGZyaWVuZCwgcHJheeKApikgYW5kIDE1IChwcm90ZWN0LCBnb2QsIGxvdmUsIGplc3VzLi4uKSBpbiBUd2l0dGVyIGhhZCB0aGUgc2FtZSB0aGVtZSBvZiBmYWl0aCBhbmQgYmVsaWVmLCB0aG91Z2ggdGhlIHBvc2l0aXZlIHNjb3JlcyB3ZXJlIG1pbGQuDQoNCiMgQ29uY2x1c2lvbg0KDQpUaGlzIHByb2plY3Qgc3R1ZGllcyB0aGUgdG9waWMgY292ZXJhZ2UgYW5kIHNlbnRpbWVudCBkeW5hbWljcyBvZiB0aGUgc2Vuc2l0aXZlIHRvcGljIENPVklELTE5IGluIE5ld3MgbWVkaWEgYW5kIFR3aXR0ZXIuIEFsdGhvdWdoIHRoZSBwcm9qZWN0IGhhcyByZXZlYWxlZCBkaWZmZXJlbnQgY2hhcmFjdGVyaXN0aWNzIG9mIG5ld3MgYXJ0aWNsZXMgYW5kIFR3aXR0ZXIsIGl0IG9ubHkgY29uZHVjdHMgYW5hbHlzaXMgb24gdGhlIHRleHQgcHJvcGVydHkgYW5kIHRoZSB0aW1lIHZhcmlhYmxlLiBNYW55IG1ldGEtZGF0YSB3ZXJlIHJlbW92ZWQgZnJvbSB0aGUgcmF3IGRhdGEgd2hpY2ggbWlnaHQgbGVhdmUgb3V0IHNvbWUgaW1wb3J0YW50IGFzcGVjdHMgdGhhdCBjb3VsZCBiZSBlbGFib3JhdGVkIGZ1cnRoZXIuIE90aGVyIGNob2ljZXMgdGhhdCBtaWdodCBsZWFkIHRvIHJlc2VhcmNoIGJpYXMgd2VyZSB0aGUgZGF0YSBzYW1wbGVzIHdoaWNoIGp1c3QgY292ZXIgc3Vic2V0cyBvZiBrZXl3b3JkcyBhbmQgdGhlIGRpY3Rpb25hcmllcyB1c2VkIGZvciBwcmUtcHJvY2Vzc2luZyBhbmQgc2VudGltZW50IGFuYWx5c2lzLiBMYXN0bHksIHRoZSB0aW1lIGZyYW1lIG9mIGRhdGEgY29sbGVjdGlvbiBpcyBvbmx5IHRocmVlIG1vbnRocywgZW5kaW5nIGF0IHRoZSBtaWRkbGUgb2YgQXByaWwgd2hlbiB0aGUgcGFuZGVtaWMgd2FzIHN0aWxsIGVzY2FsYXRpbmcgaW4gdGhlIFVTLiBJdCB3b3VsZCBiZSBiZXR0ZXIgSWYgd2UgY29sbGVjdCB0aGUgZGF0YSBhbmQgY29uZHVjdCB0aGUgYW5hbHlzaXMgYWZ0ZXIgdGhlIHBhbmRlbWljIGlzIG92ZXIsIHdoaWNoIHdvdWxkIGdpdmUgYSBmdWxsIG92ZXJ2aWV3IG9mIHRoZSBzaXR1YXRpb24u