Introduction
Discriminating between truth and fiction is becoming increasingly difficult in the age of ubiquitous digital information. From national politics to the current COVID-19 pandemic, understanding who or what to believe impacts our lives daily. While I can still remember the days of hard copy periodicals, books, and the library’s card catalog, today’s students and young professionals have grown up in an almost exclusively digital world. The digital generation is quite comfortable engaging online as much if not more than in the real world, but their ability to recognize the quality of information on their screens leaves much to be desired.
In the 18 months leading up to the 2016 presidential election, Stanford University commissioned a study to evaluate U.S. students’ ability to distinguish between factual media articles and politically biased or manufactured stories. The results were not flattering. Stanford followed up that study with a national survey that culminated in 2019 with equally dismal results. Most students struggled, with close to 90% failing four of the six survey tasks. The study concluded, unsurprisingly, that technology is evolving faster than our educational institutions can adapt.
Post-election, studies on how to identify and mitigate the threat of inaccurate media gained steam as the term “fake news” began trending. In December 2016, an entrepreneur/ professor (Dean Pomerleau) and an artificial intelligence researchers (Delip Rao) organized a competition to develop software tools to aid fact checkers in identifying online hoaxes and misinformation (fakenewschallenge.org). The event eventually brought together more than 100 volunteers and 71 teams globally vying for a nominal cash prize. Their contest highlighted the difficulty with applying broad labels of true and false to nuanced news media, so they instead settled on a “stance detection” methodology, that aimed to identify how various media sources reported on specific topics or news stories. These “stances” assisted fact checkers (and the public) in understanding which media sources were more reliable, a key first step in mitigating the spread of misinformation.
Prepare
An inability to recognize fake news is only getting more difficult as gigs of data are created by the hour that are never reviewed by an editor, proofreader, or certified publisher. It’s easy to see how one can get overwhelmed by the sheer volume of information we wade through in a day online. A key recommendation out of the Stanford study is for there to be a fundamental shift to increase digital literacy instruction at all levels of education. This problem is the driving force behind the key question this case study is attempting to address: Can technology automate the process of recognizing misinformation in online media?
This case study will examine how text mining with automated software tools can help uncover patterns that are easy to miss as we manually peruse online articles. The two categories of text mining most closely aligned to my research question are information extraction and document classification. Extraction seeks to identify key pieces of information, such as locations, dates, and addresses that can by analyzed as structured data. Alternatively, classification seeks to categorize a document or piece of unstructured text based on word choice and can be used to analyze sentiment or discussion topics. Sentiment analysis attempts to understand the attitude of a given text towards a specific topic. This method works well to determine bias in phrasing. Topic detection attempts to identify subjects or themes in a body of text. Since my challenge is to identify truth versus fiction, I decided to explore both sentiment and topic analysis in this project. Understanding how software applications can do this could be extremely relevant for educators as well as anyone working in the field of digital media production. In addition to the technical implications, this field of research has the potential to shed light on how news media is categorized, titled, and promoted to either highlight or hide its true character.
In this project, we will use data from this study by William Y. Wang designed to assist fact checkers and serve as a benchmark for fake news detection. The study authors developed the LIAR dataset as part of a 10-yr project where fact checkers manually labeled news stories collected in various contexts from Politifact.com. The specific data (publicly available here) was originally labeled as the training data and is comprised of over 10,000 instances with 14 variables. From the author’s ReadMe file (part of the data download), the variables are defined as follows:

Prior to importing the data, we should install and load the packages we’ll need for our data transformation and initial visualizations:
# Install and load packages
library(rmarkdown)
library(knitr)
library(tidyverse)
library(here)
library(tidytext)
library(wordcloud2)
library(vader)
library(colorspace)
library(scales)
Wrangle
We begin the case study by importing and reviewing the training dataset that’s been downloaded from Professor Wang’s portal:
# Import LIAR dataset and view header rows
liar_data <- read.csv(here("Liar_train.csv"))
paged_table(head(liar_data))
As you can see from the data frame this creates, the original file is imported without any column labels. We will fix that, so that our columns have titles that will act as variables for exploratory analysis. We also have this annoying feature in the “ID” column where every entry contains “.json” after the number. Let’s remove that so our ID #s are simpler:
# Modify column labels and ID entries
colnames(liar_data) <- c("ID", "Label", "Statement", "Subject",
"Speaker", "Position", "State", "Party",
"Barely True", "False", "Half True",
"Mostly True", "Pants on Fire", "Venue")
liar_data$ID <- gsub(".json", "", as.character(liar_data$ID))
paged_table(head(liar_data))
The last item of pre-processing includes two steps that will prepare our data for sentiment analysis: tokenization and stop word removal.
# Tokenize Statement text
statement_tokens <- liar_data %>%
unnest_tokens(output = word,
input = Statement) %>%
relocate(word)
# Remove stop words
tidy_liar <- anti_join(statement_tokens,
stop_words,
by = "word")
Explore
This section will use basic data visualization techniques to explore relationships within the data to provide insights into which variables indicate the potential for misinformation. In reviewing the tidied data frame, candidate variables ripe for visual analysis include party affiliation, number of articles by label, state affiliation, and historic averages. We’ll begin with some basic graphs depicting the breadth and scope of the data:
- “Truthiness” Ratings. Our main goal in this case study is to identify benchmarks for misinformation. A good starting point is to understand where our data falls on the rating scale between TRUE and FALSE. Politifact.com’s Truth-O-Meter ratings are as follows:
TRUE – The statement is accurate and there’s nothing significant missing.
MOSTLY TRUE – The statement is accurate but needs clarification or additional information.
HALF TRUE – The statement is partially accurate but leaves out important details or takes things out of context.
BARELY TRUE – The statement contains an element of truth but ignores critical facts that would give a different impression (originally listed as ‘mostly false’ but modified by the creator of the dataset).
FALSE – The statement is not accurate.
PANTS ON FIRE – The statement is not accurate and makes a ridiculous claim.
liar_data %>%
ggplot(aes(x = Label)) +
geom_bar() +
scale_x_discrete(limits = c("TRUE",
"mostly-true",
"half-true",
"barely-true",
"FALSE",
"pants-fire")) +
labs(x = "Truth-O-Meter", y = "Statement Count")

This bar chart indicates the data is relatively balanced across the 6 labels except for the most egregious category of pants on fire (POF). While most have from 1600 - 2000 statements, POF has ~ 800 statements.
- Most Discussed Issues. Will be interesting to see if tone changes depending on the topic of discussion. First we’ll tokenize the Subject column and then identify the most common discussion topics.
# Review top 50 tokens for subjects
subject_tokens <- liar_data %>%
unnest_tokens(output = word,
input = Subject) %>%
relocate(word)
subject_top_tokens <- subject_tokens %>%
count(word, sort = TRUE) %>%
top_n(50)
paged_table(subject_top_tokens)
# Create word cloud for top subjects
wordcloud2(subject_top_tokens, size = .5, shape = 'rectangle',
color = 'random-dark', backgroundColor = "black")
Now let’s see how these topics align with the levels of truth:
top_subjects <- c("health", "economy", "taxes", "education", "jobs")
subject_tokens %>%
rename(Issue = word) %>%
filter(Issue %in% top_subjects) %>%
ggplot(aes(y = Label, fill = Label)) +
geom_bar(show.legend = FALSE) +
facet_wrap(~ Issue) +
scale_y_discrete(limits = c("pants-fire",
"FALSE",
"barely-true",
"half-true",
"mostly-true",
"TRUE")) +
labs(y = "Truth-O-Meter", x = "Statement Count", subtitle = "Truth by Issue (Raw Count)") +
scale_fill_manual(values = c("pants-fire" = "red", "FALSE" = "orange", "barely-true" = "yellow", "half-true" = "yellowgreen", "mostly-true" = "green", "TRUE" = "blue"))

# Same query/plot, but by % of posts on that topic
top5_subjects <- subject_tokens %>%
rename(Issue = word) %>%
filter(Issue %in% top_subjects) %>%
group_by(Issue, Label) %>%
summarize(cnt = n()) %>%
mutate(freq = round(cnt / sum(cnt), 2)) %>%
arrange(desc(freq))
top5_subjects %>%
ggplot(aes(x= Label, y = freq, fill = Label,)) +
geom_col() +
facet_grid(~ Issue) +
scale_y_continuous(labels = scales::percent) +
scale_x_discrete(limits = c("TRUE",
"mostly-true",
"half-true",
"barely-true",
"FALSE",
"pants-fire")) +
labs(y = "% Statement Count", x = "", subtitle = "Truth by Issue (Relative %)") +
scale_fill_manual(name = "Truth-O-Meter", values = c("pants-fire" = "red",
"FALSE" = "orange",
"barely-true" = "yellow",
"half-true" = "yellowgreen",
"mostly-true" = "green",
"TRUE" = "blue")) +
theme_minimal() +
theme(axis.text.x = element_blank())

The two topics that generate the most disparity between truth and fiction are health and taxes. This is my shocked face:

- Party Affiliation.
top4_parties <- c("democrat", "republican", "independent", "libertarian")
top_parties <- liar_data %>%
filter(Party %in% top4_parties) %>%
group_by(Party, Label) %>%
summarize(cnt = n()) %>%
mutate(freq = round(cnt / sum(cnt), 2)) %>%
arrange(desc(freq))
top_parties %>%
ggplot(aes(x= Label, y = freq, fill = Label,)) +
geom_col() +
facet_grid(~ Party) +
scale_y_continuous(labels = scales::percent) +
scale_x_discrete(limits = c("TRUE",
"mostly-true",
"half-true",
"barely-true",
"FALSE",
"pants-fire")) +
labs(y = "% Statement Count", x = "", subtitle = "Truth by Party (Relative %)") +
scale_fill_manual(name = "Truth-O-Meter", values = c("pants-fire" = "red",
"FALSE" = "orange",
"barely-true" = "yellow",
"half-true" = "yellowgreen",
"mostly-true" = "green",
"TRUE" = "blue")) +
theme_minimal() +
theme(axis.text.x = element_blank())

Not calling any names, but somebody’s pants are on fire…at least in this data set. To summarize, this dataset has quite a few variables that when analyzed separately or in conjunction with each other may provide indicators of how truthful a statement is by source or discussion topic. However, to really understand the impact of each of these variables, we should judge them in the context of how they are used. This next section will analyze sentiment to explore any negativity bias in the text statements.
Model
I’ve chosen to conduct sentiment analysis to attempt to identify additional metrics for misinformation. The dictionary I’ll be using is the NRC lexicon from Saif Mohammad and Peter Turney. This is a crowdsourced list of words and their associations with eight emotions (anger, fear, anticipation, trust, surprise, sadness, joy, and disgust) and two sentiments (negative and positive).
# Download the lexicon
nrc <- get_sentiments("nrc")
sentiment_statements <- inner_join(subject_tokens, nrc, by = "word")
summary_sentiment <- sentiment_statements %>%
count(sentiment, sort = TRUE) %>%
spread(sentiment, n) %>%
mutate(sentiment = positive - negative) %>%
mutate(lexicon = "nrc") %>%
relocate(lexicon)
sentiment_counts <- sentiment_statements %>%
count(sentiment, sort = TRUE)
sentiment_counts %>%
mutate(sentiment = reorder(sentiment,n)) %>%
ggplot(aes(n, sentiment)) +
geom_col() +
labs(x = "Counts", y = "Sentiment")

The large amount of trust and fear words are interesting. Though the lack of a huge difference between negative and positive words indicates that the overall tone is much more nuanced than just good vs. bad. Our last dive into the data will apply these sentiment results across our truth labels and political parties.
sentiment_statements$Label <- factor(sentiment_statements$Label,
levels = c("pants-fire",
"FALSE",
"barely-true",
"half-true",
"mostly-true",
"TRUE"))
sentiment_statements %>%
filter(Party %in% top4_parties) %>%
ggplot(aes(y = sentiment, fill = Label)) +
geom_bar() +
facet_wrap(~ Party) +
labs(x = "Counts", y = "Sentiment", , subtitle = "Sentiment by Party (Raw Count)") +
scale_fill_manual(values = c("pants-fire" = "red", "FALSE" = "orange", "barely-true" = "yellow", "half-true" = "yellowgreen", "mostly-true" = "green", "TRUE" = "blue"))

sentiment_statements$Label <- factor(sentiment_statements$Label,
levels = c("pants-fire",
"FALSE",
"barely-true",
"half-true",
"mostly-true",
"TRUE"))
top_sentiments <- sentiment_statements %>%
filter(Party %in% top4_parties) %>%
group_by(Party, sentiment) %>%
summarize(cnt = n()) %>%
mutate(freq = round(cnt / sum(cnt), 2)) %>%
arrange(desc(freq))
top_sentiments %>%
ggplot(aes(y = sentiment, x = freq, fill = sentiment)) +
geom_col(show.legend = FALSE) +
facet_grid(~ Party) +
labs(x = "", y = "Sentiment", subtitle = "Sentiment by Party (Relative %)") +
scale_x_continuous(labels = scales::percent)

These graphs confirms the high use of “trust” words as a potential mask to issues or discussions that aren’t always truthful. The highest rating of false statements (think yellow, orange, red), are in the sentiment categories of trust, negative, positive, and fear.
Communicate
Conclusions
For humans to classify text manually, specific domain expertise is required. Expecting a person to maintain this type of knowledge across multiple domains in the digital age is nearly impossible. For the challenge of monitoring online news media for misinformation, the tasks include collecting the articles, ingesting their content, recognizing patterns in the data, and finally classifying the articles into categories. This case study demonstrates that all of these can be accomplished with current software and just a little bit of creativity.
This exercise specifically looked at the ability to automate these tasks to assist in identifying metrics or key indicators whether text-based media is misinforming the public. Through just a few basic coding samples, numerous examples were discovered that could be pieced together to determine a posting’s veracity.
Additional Areas of Research
This case study examined a single type of online media, text. Similar exercises can be done with images or video, though translating them into a medium that could be analyzed like text would take a bit more computing power than most of have available to us.
Beyond understanding these key metrics is applying them to machine learning models that could learn to predict an article’s truthfulness, sentiment, or bias. Those efforts would enable applications and internet browser extensions that could notify people about the quality of material they consume online.
Limitations
The data is always going to limit how generalizable these results are. Larger data sets will enable broader applications of the insights. For this data set, the text did not contain full, long-form articles. As a result, this study is probably better for social media analysis where the conversations are shorter. Computing power and coding skills are my personal limitation. Large text datasets can return very large tokenized data frames that take a while to run.
Legal/Ethical Considerations
No personal information was collected or used for this case study. The data was generated and made available on a public facing website with this disclaimer:
“The original sources retain the copyright of the data. Note that there are absolutely no guarantees with this data, and we provide this dataset”as is”, but you are welcome to report the issues of the preliminary version of this data. You are allowed to use this dataset for research purposes only.”
Acknowledgements/References
- Breakstone, J., Smith, M., Wineburg, S., Rapaport, A., Carle, J., Garland, M., & Saavedra, A. (2019). Students’ civic online reasoning: A national portrait. Stanford History Education Group & Gibson Consulting. https://purl.stanford.edu/gf151tb4868
- Holan, A. (2020, October 27). Politifact - the principles of the truth-O-meter: PolitiFact’s methodology for independent fact-checking. Politifact. Retrieved December 1, 2021, from https://www.politifact.com/article/2018/feb/12/principles-truth-o-meter-politifacts-methodology-i/.
- Mohammad, S. (2011, July 10). NRC Word-Emotion Association Lexicon. Saif M. Mohammad Homepage. Retrieved December 1, 2021, from http://saifmohammad.com/WebDocs/README-NRC-Lex.txt.
- Wang, W. Y. (2017). Liar, Liar Pants On fire: A new benchmark dataset for fake news detection. Proceedings of the 55th Annual Meeting of the Association for Computational Linguistics (Volume 2: Short Papers). https://doi.org/10.18653/v1/p17-2067
- Wineburg, Sam and McGrew, Sarah and Breakstone, Joel and Ortega, Teresa. (2016). Evaluating Information: The Cornerstone of Civic Online Reasoning. Stanford Digital Repository. http://purl.stanford.edu/fv751yt5934
LS0tCnRpdGxlOiAiQmVuY2htYXJraW5nIEZha2UgTmV3cyIKYXV0aG9yOiAiSmFtZXMgSGFyZGF3YXkiCmRhdGU6ICJgciBmb3JtYXQoU3lzLkRhdGUoKSwnJUIgJWUsICVZJylgIgpvdXRwdXQ6IAogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogNQogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgY29kZV9kb3dubG9hZDogVFJVRQotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIG1lc3NhZ2U9RkFMU0UpCmBgYAoKIyMgSW50cm9kdWN0aW9uCgpEaXNjcmltaW5hdGluZyBiZXR3ZWVuIHRydXRoIGFuZCBmaWN0aW9uIGlzIGJlY29taW5nIGluY3JlYXNpbmdseSBkaWZmaWN1bHQgaW4gdGhlIGFnZSBvZiB1YmlxdWl0b3VzIGRpZ2l0YWwgaW5mb3JtYXRpb24uIEZyb20gbmF0aW9uYWwgcG9saXRpY3MgdG8gdGhlIGN1cnJlbnQgQ09WSUQtMTkgcGFuZGVtaWMsIHVuZGVyc3RhbmRpbmcgd2hvIG9yIHdoYXQgdG8gYmVsaWV2ZSBpbXBhY3RzIG91ciBsaXZlcyBkYWlseS4gV2hpbGUgSSBjYW4gc3RpbGwgcmVtZW1iZXIgdGhlIGRheXMgb2YgaGFyZCBjb3B5IHBlcmlvZGljYWxzLCBib29rcywgYW5kIHRoZSBsaWJyYXJ5J3MgY2FyZCBjYXRhbG9nLCB0b2RheSdzIHN0dWRlbnRzIGFuZCB5b3VuZyBwcm9mZXNzaW9uYWxzIGhhdmUgZ3Jvd24gdXAgaW4gYW4gYWxtb3N0IGV4Y2x1c2l2ZWx5IGRpZ2l0YWwgd29ybGQuIFRoZSBkaWdpdGFsIGdlbmVyYXRpb24gaXMgcXVpdGUgY29tZm9ydGFibGUgZW5nYWdpbmcgb25saW5lIGFzIG11Y2ggaWYgbm90IG1vcmUgdGhhbiBpbiB0aGUgcmVhbCB3b3JsZCwgYnV0IHRoZWlyIGFiaWxpdHkgdG8gcmVjb2duaXplIHRoZSBxdWFsaXR5IG9mIGluZm9ybWF0aW9uIG9uIHRoZWlyIHNjcmVlbnMgbGVhdmVzIG11Y2ggdG8gYmUgZGVzaXJlZC4KCkluIHRoZSAxOCBtb250aHMgbGVhZGluZyB1cCB0byB0aGUgMjAxNiBwcmVzaWRlbnRpYWwgZWxlY3Rpb24sIFN0YW5mb3JkIFVuaXZlcnNpdHkgY29tbWlzc2lvbmVkIGEgW3N0dWR5XShodHRwczovL3N0YWNrcy5zdGFuZm9yZC5lZHUvZmlsZS9kcnVpZDpmdjc1MXl0NTkzNC9TSEVHJTIwRXZhbHVhdGluZyUyMEluZm9ybWF0aW9uJTIwT25saW5lLnBkZikgdG8gZXZhbHVhdGUgVS5TLiBzdHVkZW50cycgYWJpbGl0eSB0byBkaXN0aW5ndWlzaCBiZXR3ZWVuIGZhY3R1YWwgbWVkaWEgYXJ0aWNsZXMgYW5kIHBvbGl0aWNhbGx5IGJpYXNlZCBvciBtYW51ZmFjdHVyZWQgc3Rvcmllcy4gVGhlIHJlc3VsdHMgd2VyZSBub3QgZmxhdHRlcmluZy4gU3RhbmZvcmQgZm9sbG93ZWQgdXAgdGhhdCBzdHVkeSB3aXRoIGEgbmF0aW9uYWwgW3N1cnZleV0oaHR0cHM6Ly9zdGFja3Muc3RhbmZvcmQuZWR1L2ZpbGUvZHJ1aWQ6Z2YxNTF0YjQ4NjgvQ2l2aWMlMjBPbmxpbmUlMjBSZWFzb25pbmclMjBOYXRpb25hbCUyMFBvcnRyYWl0LnBkZikgdGhhdCBjdWxtaW5hdGVkIGluIDIwMTkgd2l0aCBlcXVhbGx5IGRpc21hbCByZXN1bHRzLiBNb3N0IHN0dWRlbnRzIHN0cnVnZ2xlZCwgd2l0aCBjbG9zZSB0byA5MCUgZmFpbGluZyBmb3VyIG9mIHRoZSBzaXggc3VydmV5IHRhc2tzLiBUaGUgc3R1ZHkgY29uY2x1ZGVkLCB1bnN1cnByaXNpbmdseSwgdGhhdCB0ZWNobm9sb2d5IGlzIGV2b2x2aW5nIGZhc3RlciB0aGFuIG91ciBlZHVjYXRpb25hbCBpbnN0aXR1dGlvbnMgY2FuIGFkYXB0LgoKUG9zdC1lbGVjdGlvbiwgc3R1ZGllcyBvbiBob3cgdG8gaWRlbnRpZnkgYW5kIG1pdGlnYXRlIHRoZSB0aHJlYXQgb2YgaW5hY2N1cmF0ZSBtZWRpYSBnYWluZWQgc3RlYW0gYXMgdGhlIHRlcm0gImZha2UgbmV3cyIgYmVnYW4gdHJlbmRpbmcuIEluIERlY2VtYmVyIDIwMTYsIGFuIGVudHJlcHJlbmV1ci8gcHJvZmVzc29yIChEZWFuIFBvbWVybGVhdSkgYW5kIGFuIGFydGlmaWNpYWwgaW50ZWxsaWdlbmNlIHJlc2VhcmNoZXJzIChEZWxpcCBSYW8pIG9yZ2FuaXplZCBhIGNvbXBldGl0aW9uIHRvIGRldmVsb3Agc29mdHdhcmUgdG9vbHMgdG8gYWlkIGZhY3QgY2hlY2tlcnMgaW4gaWRlbnRpZnlpbmcgb25saW5lIGhvYXhlcyBhbmQgbWlzaW5mb3JtYXRpb24gKFtmYWtlbmV3c2NoYWxsZW5nZS5vcmddKGh0dHBzOi8vZmFrZW5ld3NjaGFsbGVuZ2Uub3JnLykpLiBUaGUgZXZlbnQgZXZlbnR1YWxseSBicm91Z2h0IHRvZ2V0aGVyIG1vcmUgdGhhbiAxMDAgdm9sdW50ZWVycyBhbmQgNzEgdGVhbXMgZ2xvYmFsbHkgdnlpbmcgZm9yIGEgbm9taW5hbCBjYXNoIHByaXplLiBUaGVpciBjb250ZXN0IGhpZ2hsaWdodGVkIHRoZSBkaWZmaWN1bHR5IHdpdGggYXBwbHlpbmcgYnJvYWQgbGFiZWxzIG9mIHRydWUgYW5kIGZhbHNlIHRvIG51YW5jZWQgbmV3cyBtZWRpYSwgc28gdGhleSBpbnN0ZWFkIHNldHRsZWQgb24gYSAic3RhbmNlIGRldGVjdGlvbiIgbWV0aG9kb2xvZ3ksIHRoYXQgYWltZWQgdG8gaWRlbnRpZnkgaG93IHZhcmlvdXMgbWVkaWEgc291cmNlcyByZXBvcnRlZCBvbiBzcGVjaWZpYyB0b3BpY3Mgb3IgbmV3cyBzdG9yaWVzLiBUaGVzZSAic3RhbmNlcyIgYXNzaXN0ZWQgZmFjdCBjaGVja2VycyAoYW5kIHRoZSBwdWJsaWMpIGluIHVuZGVyc3RhbmRpbmcgd2hpY2ggbWVkaWEgc291cmNlcyB3ZXJlIG1vcmUgcmVsaWFibGUsIGEga2V5IGZpcnN0IHN0ZXAgaW4gbWl0aWdhdGluZyB0aGUgc3ByZWFkIG9mIG1pc2luZm9ybWF0aW9uLgoKIyMgUHJlcGFyZQoKQW4gaW5hYmlsaXR5IHRvIHJlY29nbml6ZSBmYWtlIG5ld3MgaXMgb25seSBnZXR0aW5nIG1vcmUgZGlmZmljdWx0IGFzIGdpZ3Mgb2YgZGF0YSBhcmUgY3JlYXRlZCBieSB0aGUgaG91ciB0aGF0IGFyZSBuZXZlciByZXZpZXdlZCBieSBhbiBlZGl0b3IsIHByb29mcmVhZGVyLCBvciBjZXJ0aWZpZWQgcHVibGlzaGVyLiBJdCdzIGVhc3kgdG8gc2VlIGhvdyBvbmUgY2FuIGdldCBvdmVyd2hlbG1lZCBieSB0aGUgc2hlZXIgdm9sdW1lIG9mIGluZm9ybWF0aW9uIHdlIHdhZGUgdGhyb3VnaCBpbiBhIGRheSBvbmxpbmUuIEEga2V5IHJlY29tbWVuZGF0aW9uIG91dCBvZiB0aGUgU3RhbmZvcmQgc3R1ZHkgaXMgZm9yIHRoZXJlIHRvIGJlIGEgZnVuZGFtZW50YWwgc2hpZnQgdG8gaW5jcmVhc2UgZGlnaXRhbCBsaXRlcmFjeSBpbnN0cnVjdGlvbiBhdCBhbGwgbGV2ZWxzIG9mIGVkdWNhdGlvbi4gVGhpcyBwcm9ibGVtIGlzIHRoZSBkcml2aW5nIGZvcmNlIGJlaGluZCB0aGUga2V5IHF1ZXN0aW9uIHRoaXMgY2FzZSBzdHVkeSBpcyBhdHRlbXB0aW5nIHRvIGFkZHJlc3M6ICoqKkNhbiB0ZWNobm9sb2d5IGF1dG9tYXRlIHRoZSBwcm9jZXNzIG9mIHJlY29nbml6aW5nIG1pc2luZm9ybWF0aW9uIGluIG9ubGluZSBtZWRpYT8qKioKClRoaXMgY2FzZSBzdHVkeSB3aWxsIGV4YW1pbmUgaG93IHRleHQgbWluaW5nIHdpdGggYXV0b21hdGVkIHNvZnR3YXJlIHRvb2xzIGNhbiBoZWxwIHVuY292ZXIgcGF0dGVybnMgdGhhdCBhcmUgZWFzeSB0byBtaXNzIGFzIHdlIG1hbnVhbGx5IHBlcnVzZSBvbmxpbmUgYXJ0aWNsZXMuIFRoZSB0d28gY2F0ZWdvcmllcyBvZiB0ZXh0IG1pbmluZyBtb3N0IGNsb3NlbHkgYWxpZ25lZCB0byBteSByZXNlYXJjaCBxdWVzdGlvbiBhcmUgaW5mb3JtYXRpb24gZXh0cmFjdGlvbiBhbmQgZG9jdW1lbnQgY2xhc3NpZmljYXRpb24uIEV4dHJhY3Rpb24gc2Vla3MgdG8gaWRlbnRpZnkga2V5IHBpZWNlcyBvZiBpbmZvcm1hdGlvbiwgc3VjaCBhcyBsb2NhdGlvbnMsIGRhdGVzLCBhbmQgYWRkcmVzc2VzIHRoYXQgY2FuIGJ5IGFuYWx5emVkIGFzIHN0cnVjdHVyZWQgZGF0YS4gQWx0ZXJuYXRpdmVseSwgY2xhc3NpZmljYXRpb24gc2Vla3MgdG8gY2F0ZWdvcml6ZSBhIGRvY3VtZW50IG9yIHBpZWNlIG9mIHVuc3RydWN0dXJlZCB0ZXh0IGJhc2VkIG9uIHdvcmQgY2hvaWNlIGFuZCBjYW4gYmUgdXNlZCB0byBhbmFseXplIHNlbnRpbWVudCBvciBkaXNjdXNzaW9uIHRvcGljcy4gU2VudGltZW50IGFuYWx5c2lzIGF0dGVtcHRzIHRvIHVuZGVyc3RhbmQgdGhlIGF0dGl0dWRlIG9mIGEgZ2l2ZW4gdGV4dCB0b3dhcmRzIGEgc3BlY2lmaWMgdG9waWMuIFRoaXMgbWV0aG9kIHdvcmtzIHdlbGwgdG8gZGV0ZXJtaW5lIGJpYXMgaW4gcGhyYXNpbmcuIFRvcGljIGRldGVjdGlvbiBhdHRlbXB0cyB0byBpZGVudGlmeSBzdWJqZWN0cyBvciB0aGVtZXMgaW4gYSBib2R5IG9mIHRleHQuIFNpbmNlIG15IGNoYWxsZW5nZSBpcyB0byBpZGVudGlmeSB0cnV0aCB2ZXJzdXMgZmljdGlvbiwgSSBkZWNpZGVkIHRvIGV4cGxvcmUgYm90aCBzZW50aW1lbnQgYW5kIHRvcGljIGFuYWx5c2lzIGluIHRoaXMgcHJvamVjdC4gVW5kZXJzdGFuZGluZyBob3cgc29mdHdhcmUgYXBwbGljYXRpb25zIGNhbiBkbyB0aGlzIGNvdWxkIGJlIGV4dHJlbWVseSByZWxldmFudCBmb3IgZWR1Y2F0b3JzIGFzIHdlbGwgYXMgYW55b25lIHdvcmtpbmcgaW4gdGhlIGZpZWxkIG9mIGRpZ2l0YWwgbWVkaWEgcHJvZHVjdGlvbi4gSW4gYWRkaXRpb24gdG8gdGhlIHRlY2huaWNhbCBpbXBsaWNhdGlvbnMsIHRoaXMgZmllbGQgb2YgcmVzZWFyY2ggaGFzIHRoZSBwb3RlbnRpYWwgdG8gc2hlZCBsaWdodCBvbiBob3cgbmV3cyBtZWRpYSBpcyBjYXRlZ29yaXplZCwgdGl0bGVkLCBhbmQgcHJvbW90ZWQgdG8gZWl0aGVyIGhpZ2hsaWdodCBvciBoaWRlIGl0cyB0cnVlIGNoYXJhY3Rlci4KCkluIHRoaXMgcHJvamVjdCwgd2Ugd2lsbCB1c2UgZGF0YSBmcm9tIFt0aGlzIHN0dWR5XShjaHJvbWUtZXh0ZW5zaW9uOi8vZWZhaWRuYm1ubm5pYnBjYWpwY2dsY2xlZmluZG1rYWovdmlld2VyLmh0bWw/cGRmdXJsPWh0dHBzJTNBJTJGJTJGc2l0ZXMuY3MudWNzYi5lZHUlMkZ+d2lsbGlhbSUyRnBhcGVycyUyRmFjbDIwMTcucGRmJmNsZW49MjIwMzI3JmNodW5rPXRydWUpIGJ5IFtXaWxsaWFtIFkuIFdhbmddKGh0dHBzOi8vc2l0ZXMuY3MudWNzYi5lZHUvfndpbGxpYW0vKSBkZXNpZ25lZCB0byBhc3Npc3QgZmFjdCBjaGVja2VycyBhbmQgc2VydmUgYXMgYSBiZW5jaG1hcmsgZm9yIGZha2UgbmV3cyBkZXRlY3Rpb24uIFRoZSBzdHVkeSBhdXRob3JzIGRldmVsb3BlZCB0aGUgKkxJQVIqIGRhdGFzZXQgYXMgcGFydCBvZiBhIDEwLXlyIHByb2plY3Qgd2hlcmUgZmFjdCBjaGVja2VycyBtYW51YWxseSBsYWJlbGVkIG5ld3Mgc3RvcmllcyBjb2xsZWN0ZWQgaW4gdmFyaW91cyBjb250ZXh0cyBmcm9tIFtQb2xpdGlmYWN0LmNvbV0oaHR0cHM6Ly9wb2xpdGlmYWN0LmNvbSkuIFRoZSBzcGVjaWZpYyBkYXRhIChwdWJsaWNseSBhdmFpbGFibGUgW2hlcmVdKGh0dHBzOi8vd3d3LmNzLnVjc2IuZWR1L353aWxsaWFtL2RhdGEvbGlhcl9kYXRhc2V0LnppcCkpIHdhcyBvcmlnaW5hbGx5IGxhYmVsZWQgYXMgdGhlIHRyYWluaW5nIGRhdGEgYW5kIGlzIGNvbXByaXNlZCBvZiBvdmVyIDEwLDAwMCBpbnN0YW5jZXMgd2l0aCAxNCB2YXJpYWJsZXMuIEZyb20gdGhlIGF1dGhvcidzICpSZWFkTWUqIGZpbGUgKHBhcnQgb2YgdGhlIGRhdGEgZG93bmxvYWQpLCB0aGUgdmFyaWFibGVzIGFyZSBkZWZpbmVkIGFzIGZvbGxvd3M6CgohW10oaW1hZ2VzL2xpYXJfdmFyaWFibGVzLnBuZyAiTElBUiBEYXRhc2V0IFZhcmlhYmxlcyIpCgpQcmlvciB0byBpbXBvcnRpbmcgdGhlIGRhdGEsIHdlIHNob3VsZCBpbnN0YWxsIGFuZCBsb2FkIHRoZSBwYWNrYWdlcyB3ZSdsbCBuZWVkIGZvciBvdXIgZGF0YSB0cmFuc2Zvcm1hdGlvbiBhbmQgaW5pdGlhbCB2aXN1YWxpemF0aW9uczoKCmBgYHtyLCBlY2hvID0gVFJVRSwgbWVzc2FnZT1GQUxTRX0KIyBJbnN0YWxsIGFuZCBsb2FkIHBhY2thZ2VzCmxpYnJhcnkocm1hcmtkb3duKQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShoZXJlKQpsaWJyYXJ5KHRpZHl0ZXh0KQpsaWJyYXJ5KHdvcmRjbG91ZDIpCmxpYnJhcnkodmFkZXIpCmxpYnJhcnkoY29sb3JzcGFjZSkKbGlicmFyeShzY2FsZXMpCmBgYAoKIyMgV3JhbmdsZQoKV2UgYmVnaW4gdGhlIGNhc2Ugc3R1ZHkgYnkgaW1wb3J0aW5nIGFuZCByZXZpZXdpbmcgdGhlIHRyYWluaW5nIGRhdGFzZXQgdGhhdCdzIGJlZW4gZG93bmxvYWRlZCBmcm9tIFByb2Zlc3NvciBXYW5nJ3MgcG9ydGFsOgoKYGBge3IsIGVjaG8gPSBUUlVFLCBtZXNzYWdlPUZBTFNFfQojIEltcG9ydCBMSUFSIGRhdGFzZXQgYW5kIHZpZXcgaGVhZGVyIHJvd3MKbGlhcl9kYXRhIDwtIHJlYWQuY3N2KGhlcmUoIkxpYXJfdHJhaW4uY3N2IikpCnBhZ2VkX3RhYmxlKGhlYWQobGlhcl9kYXRhKSkKYGBgCgpBcyB5b3UgY2FuIHNlZSBmcm9tIHRoZSBkYXRhIGZyYW1lIHRoaXMgY3JlYXRlcywgdGhlIG9yaWdpbmFsIGZpbGUgaXMgaW1wb3J0ZWQgd2l0aG91dCBhbnkgY29sdW1uIGxhYmVscy4gV2Ugd2lsbCBmaXggdGhhdCwgc28gdGhhdCBvdXIgY29sdW1ucyBoYXZlIHRpdGxlcyB0aGF0IHdpbGwgYWN0IGFzIHZhcmlhYmxlcyBmb3IgZXhwbG9yYXRvcnkgYW5hbHlzaXMuIFdlIGFsc28gaGF2ZSB0aGlzIGFubm95aW5nIGZlYXR1cmUgaW4gdGhlICJJRCIgY29sdW1uIHdoZXJlIGV2ZXJ5IGVudHJ5IGNvbnRhaW5zICIuanNvbiIgYWZ0ZXIgdGhlIG51bWJlci4gTGV0J3MgcmVtb3ZlIHRoYXQgc28gb3VyIElEICNzIGFyZSBzaW1wbGVyOgoKYGBge3J9CiMgTW9kaWZ5IGNvbHVtbiBsYWJlbHMgYW5kIElEIGVudHJpZXMKY29sbmFtZXMobGlhcl9kYXRhKSA8LSBjKCJJRCIsICJMYWJlbCIsICJTdGF0ZW1lbnQiLCAiU3ViamVjdCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAiU3BlYWtlciIsICJQb3NpdGlvbiIsICJTdGF0ZSIsICJQYXJ0eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAiQmFyZWx5IFRydWUiLCAiRmFsc2UiLCAiSGFsZiBUcnVlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICJNb3N0bHkgVHJ1ZSIsICJQYW50cyBvbiBGaXJlIiwgIlZlbnVlIikKbGlhcl9kYXRhJElEIDwtIGdzdWIoIi5qc29uIiwgIiIsIGFzLmNoYXJhY3RlcihsaWFyX2RhdGEkSUQpKQpwYWdlZF90YWJsZShoZWFkKGxpYXJfZGF0YSkpCmBgYAoKVGhlIGxhc3QgaXRlbSBvZiBwcmUtcHJvY2Vzc2luZyBpbmNsdWRlcyB0d28gc3RlcHMgdGhhdCB3aWxsIHByZXBhcmUgb3VyIGRhdGEgZm9yIHNlbnRpbWVudCBhbmFseXNpczogdG9rZW5pemF0aW9uIGFuZCBzdG9wIHdvcmQgcmVtb3ZhbC4KCmBgYHtyfQojIFRva2VuaXplIFN0YXRlbWVudCB0ZXh0CnN0YXRlbWVudF90b2tlbnMgPC0gbGlhcl9kYXRhICU+JSAKICB1bm5lc3RfdG9rZW5zKG91dHB1dCA9IHdvcmQsCiAgICAgICAgICAgICAgICBpbnB1dCA9IFN0YXRlbWVudCkgJT4lIAogIHJlbG9jYXRlKHdvcmQpCgojIFJlbW92ZSBzdG9wIHdvcmRzCnRpZHlfbGlhciA8LSBhbnRpX2pvaW4oc3RhdGVtZW50X3Rva2VucywKICAgICAgICAgICAgICAgICAgICAgICBzdG9wX3dvcmRzLAogICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gIndvcmQiKQpgYGAKCiMjIEV4cGxvcmUKClRoaXMgc2VjdGlvbiB3aWxsIHVzZSBiYXNpYyBkYXRhIHZpc3VhbGl6YXRpb24gdGVjaG5pcXVlcyB0byBleHBsb3JlIHJlbGF0aW9uc2hpcHMgd2l0aGluIHRoZSBkYXRhIHRvIHByb3ZpZGUgaW5zaWdodHMgaW50byB3aGljaCB2YXJpYWJsZXMgaW5kaWNhdGUgdGhlIHBvdGVudGlhbCBmb3IgbWlzaW5mb3JtYXRpb24uIEluIHJldmlld2luZyB0aGUgdGlkaWVkIGRhdGEgZnJhbWUsIGNhbmRpZGF0ZSB2YXJpYWJsZXMgcmlwZSBmb3IgdmlzdWFsIGFuYWx5c2lzIGluY2x1ZGUgcGFydHkgYWZmaWxpYXRpb24sIG51bWJlciBvZiBhcnRpY2xlcyBieSBsYWJlbCwgc3RhdGUgYWZmaWxpYXRpb24sIGFuZCBoaXN0b3JpYyBhdmVyYWdlcy4gV2UnbGwgYmVnaW4gd2l0aCBzb21lIGJhc2ljIGdyYXBocyBkZXBpY3RpbmcgdGhlIGJyZWFkdGggYW5kIHNjb3BlIG9mIHRoZSBkYXRhOgoKMS4gICoqIlRydXRoaW5lc3MiIFJhdGluZ3MuKiogT3VyIG1haW4gZ29hbCBpbiB0aGlzIGNhc2Ugc3R1ZHkgaXMgdG8gaWRlbnRpZnkgYmVuY2htYXJrcyBmb3IgbWlzaW5mb3JtYXRpb24uIEEgZ29vZCBzdGFydGluZyBwb2ludCBpcyB0byB1bmRlcnN0YW5kIHdoZXJlIG91ciBkYXRhIGZhbGxzIG9uIHRoZSByYXRpbmcgc2NhbGUgYmV0d2VlbiBUUlVFIGFuZCBGQUxTRS4gUG9saXRpZmFjdC5jb20ncyBUcnV0aC1PLU1ldGVyIFtyYXRpbmdzXShodHRwczovL3d3dy5wb2xpdGlmYWN0LmNvbS9hcnRpY2xlLzIwMTgvZmViLzEyL3ByaW5jaXBsZXMtdHJ1dGgtby1tZXRlci1wb2xpdGlmYWN0cy1tZXRob2RvbG9neS1pLyNUcnV0aC1PLU1ldGVyJTIwcmF0aW5ncykgYXJlIGFzIGZvbGxvd3M6CgoqKlRSVUUqKiAtLSBUaGUgc3RhdGVtZW50IGlzIGFjY3VyYXRlIGFuZCB0aGVyZSdzIG5vdGhpbmcgc2lnbmlmaWNhbnQgbWlzc2luZy4KCioqTU9TVExZIFRSVUUqKiAtLSBUaGUgc3RhdGVtZW50IGlzIGFjY3VyYXRlIGJ1dCBuZWVkcyBjbGFyaWZpY2F0aW9uIG9yIGFkZGl0aW9uYWwgaW5mb3JtYXRpb24uCgoqKkhBTEYgVFJVRSoqIC0tIFRoZSBzdGF0ZW1lbnQgaXMgcGFydGlhbGx5IGFjY3VyYXRlIGJ1dCBsZWF2ZXMgb3V0IGltcG9ydGFudCBkZXRhaWxzIG9yIHRha2VzIHRoaW5ncyBvdXQgb2YgY29udGV4dC4KCioqQkFSRUxZIFRSVUUqKiAtLSBUaGUgc3RhdGVtZW50IGNvbnRhaW5zIGFuIGVsZW1lbnQgb2YgdHJ1dGggYnV0IGlnbm9yZXMgY3JpdGljYWwgZmFjdHMgdGhhdCB3b3VsZCBnaXZlIGEgZGlmZmVyZW50IGltcHJlc3Npb24gKG9yaWdpbmFsbHkgbGlzdGVkIGFzICdtb3N0bHkgZmFsc2UnIGJ1dCBtb2RpZmllZCBieSB0aGUgY3JlYXRvciBvZiB0aGUgZGF0YXNldCkuCgoqKkZBTFNFKiogLS0gVGhlIHN0YXRlbWVudCBpcyBub3QgYWNjdXJhdGUuCgoqKlBBTlRTIE9OIEZJUkUqKiAtLSBUaGUgc3RhdGVtZW50IGlzIG5vdCBhY2N1cmF0ZSBhbmQgbWFrZXMgYSByaWRpY3Vsb3VzIGNsYWltLgoKYGBge3J9CmxpYXJfZGF0YSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gTGFiZWwpKSArCiAgZ2VvbV9iYXIoKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHMgPSBjKCJUUlVFIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAibW9zdGx5LXRydWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgImhhbGYtdHJ1ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmFyZWx5LXRydWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIkZBTFNFIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwYW50cy1maXJlIikpICsKICBsYWJzKHggPSAiVHJ1dGgtTy1NZXRlciIsIHkgPSAiU3RhdGVtZW50IENvdW50IikKYGBgCgpUaGlzIGJhciBjaGFydCBpbmRpY2F0ZXMgdGhlIGRhdGEgaXMgcmVsYXRpdmVseSBiYWxhbmNlZCBhY3Jvc3MgdGhlIDYgbGFiZWxzIGV4Y2VwdCBmb3IgdGhlIG1vc3QgZWdyZWdpb3VzIGNhdGVnb3J5IG9mICpwYW50cyBvbiBmaXJlKiAoUE9GKS4gV2hpbGUgbW9zdCBoYXZlIGZyb20gMTYwMCAtIDIwMDAgc3RhdGVtZW50cywgUE9GIGhhcyBcfiA4MDAgc3RhdGVtZW50cy4KCjIuICAqKk1vc3QgRGlzY3Vzc2VkIElzc3Vlcy4qKiBXaWxsIGJlIGludGVyZXN0aW5nIHRvIHNlZSBpZiB0b25lIGNoYW5nZXMgZGVwZW5kaW5nIG9uIHRoZSB0b3BpYyBvZiBkaXNjdXNzaW9uLiBGaXJzdCB3ZSdsbCB0b2tlbml6ZSB0aGUgU3ViamVjdCBjb2x1bW4gYW5kIHRoZW4gaWRlbnRpZnkgdGhlIG1vc3QgY29tbW9uIGRpc2N1c3Npb24gdG9waWNzLgoKYGBge3J9CiMgUmV2aWV3IHRvcCA1MCB0b2tlbnMgZm9yIHN1YmplY3RzCnN1YmplY3RfdG9rZW5zIDwtIGxpYXJfZGF0YSAlPiUgCiAgdW5uZXN0X3Rva2VucyhvdXRwdXQgPSB3b3JkLAogICAgICAgICAgICAgICAgaW5wdXQgPSBTdWJqZWN0KSAlPiUgCiAgcmVsb2NhdGUod29yZCkKCnN1YmplY3RfdG9wX3Rva2VucyA8LSBzdWJqZWN0X3Rva2VucyAlPiUgCiAgY291bnQod29yZCwgc29ydCA9IFRSVUUpICU+JSAKICB0b3Bfbig1MCkKCnBhZ2VkX3RhYmxlKHN1YmplY3RfdG9wX3Rva2VucykKCiMgQ3JlYXRlIHdvcmQgY2xvdWQgZm9yIHRvcCBzdWJqZWN0cwp3b3JkY2xvdWQyKHN1YmplY3RfdG9wX3Rva2Vucywgc2l6ZSA9IC41LCBzaGFwZSA9ICdyZWN0YW5nbGUnLAogICAgICAgICAgIGNvbG9yID0gJ3JhbmRvbS1kYXJrJywgYmFja2dyb3VuZENvbG9yID0gImJsYWNrIikKYGBgCgpOb3cgbGV0J3Mgc2VlIGhvdyB0aGVzZSB0b3BpY3MgYWxpZ24gd2l0aCB0aGUgbGV2ZWxzIG9mIHRydXRoOgoKYGBge3J9CnRvcF9zdWJqZWN0cyA8LSBjKCJoZWFsdGgiLCAiZWNvbm9teSIsICJ0YXhlcyIsICJlZHVjYXRpb24iLCAiam9icyIpCgpzdWJqZWN0X3Rva2VucyAlPiUKICByZW5hbWUoSXNzdWUgPSB3b3JkKSAlPiUKICBmaWx0ZXIoSXNzdWUgJWluJSB0b3Bfc3ViamVjdHMpICU+JSAKICBnZ3Bsb3QoYWVzKHkgPSBMYWJlbCwgZmlsbCA9IExhYmVsKSkgKwogIGdlb21fYmFyKHNob3cubGVnZW5kID0gRkFMU0UpICsKICBmYWNldF93cmFwKH4gSXNzdWUpICsKICBzY2FsZV95X2Rpc2NyZXRlKGxpbWl0cyA9IGMoInBhbnRzLWZpcmUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJGQUxTRSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmFyZWx5LXRydWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgImhhbGYtdHJ1ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAibW9zdGx5LXRydWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRSVUUiKSkgKwogIGxhYnMoeSA9ICJUcnV0aC1PLU1ldGVyIiwgeCA9ICJTdGF0ZW1lbnQgQ291bnQiLCBzdWJ0aXRsZSA9ICJUcnV0aCBieSBJc3N1ZSAoUmF3IENvdW50KSIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJwYW50cy1maXJlIiA9ICJyZWQiLCAiRkFMU0UiID0gIm9yYW5nZSIsICJiYXJlbHktdHJ1ZSIgPSAieWVsbG93IiwgImhhbGYtdHJ1ZSIgPSAieWVsbG93Z3JlZW4iLCAibW9zdGx5LXRydWUiID0gImdyZWVuIiwgIlRSVUUiID0gImJsdWUiKSkKYGBgCgpgYGB7cn0KIyBTYW1lIHF1ZXJ5L3Bsb3QsIGJ1dCBieSAlIG9mIHBvc3RzIG9uIHRoYXQgdG9waWMKdG9wNV9zdWJqZWN0cyA8LSBzdWJqZWN0X3Rva2VucyAlPiUKICByZW5hbWUoSXNzdWUgPSB3b3JkKSAlPiUKICBmaWx0ZXIoSXNzdWUgJWluJSB0b3Bfc3ViamVjdHMpICU+JSAKICBncm91cF9ieShJc3N1ZSwgTGFiZWwpICU+JSAKICBzdW1tYXJpemUoY250ID0gbigpKSAlPiUgCiAgbXV0YXRlKGZyZXEgPSByb3VuZChjbnQgLyBzdW0oY250KSwgMikpICU+JSAKICBhcnJhbmdlKGRlc2MoZnJlcSkpIAogIAp0b3A1X3N1YmplY3RzICU+JQogIGdncGxvdChhZXMoeD0gTGFiZWwsIHkgPSBmcmVxLCBmaWxsID0gTGFiZWwsKSkgKwogIGdlb21fY29sKCkgKwogIGZhY2V0X2dyaWQofiBJc3N1ZSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpICsKICBzY2FsZV94X2Rpc2NyZXRlKGxpbWl0cyA9IGMoIlRSVUUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJtb3N0bHktdHJ1ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiaGFsZi10cnVlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiYXJlbHktdHJ1ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRkFMU0UiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgInBhbnRzLWZpcmUiKSkgKwogIGxhYnMoeSA9ICIlIFN0YXRlbWVudCBDb3VudCIsIHggPSAiIiwgc3VidGl0bGUgPSAiVHJ1dGggYnkgSXNzdWUgKFJlbGF0aXZlICUpIikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWUgPSAiVHJ1dGgtTy1NZXRlciIsIHZhbHVlcyA9IGMoInBhbnRzLWZpcmUiID0gInJlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkZBTFNFIiA9ICJvcmFuZ2UiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImJhcmVseS10cnVlIiA9ICJ5ZWxsb3ciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImhhbGYtdHJ1ZSIgPSAieWVsbG93Z3JlZW4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm1vc3RseS10cnVlIiA9ICJncmVlbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVFJVRSIgPSAiYmx1ZSIpKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCgpUaGUgdHdvIHRvcGljcyB0aGF0IGdlbmVyYXRlIHRoZSBtb3N0IGRpc3Bhcml0eSBiZXR3ZWVuIHRydXRoIGFuZCBmaWN0aW9uIGFyZSAqaGVhbHRoKiBhbmQgKnRheGVzKi4gVGhpcyBpcyBteSBzaG9ja2VkIGZhY2U6CgpgYGB7ciBmaWcuYWxpZ24gPSAnY2VudGVyJywgZWNobyA9IEZBTFNFfQppbmNsdWRlX2dyYXBoaWNzKGhlcmUoImltYWdlcy9hc3RvbmlzaGVkX2ZhY2UucG5nIikpCmBgYAoKMy4gICoqUGFydHkgQWZmaWxpYXRpb24uKioKCmBgYHtyfQp0b3A0X3BhcnRpZXMgPC0gYygiZGVtb2NyYXQiLCAicmVwdWJsaWNhbiIsICJpbmRlcGVuZGVudCIsICJsaWJlcnRhcmlhbiIpCgp0b3BfcGFydGllcyA8LSBsaWFyX2RhdGEgJT4lIAogIGZpbHRlcihQYXJ0eSAlaW4lIHRvcDRfcGFydGllcykgJT4lIAogIGdyb3VwX2J5KFBhcnR5LCBMYWJlbCkgJT4lIAogIHN1bW1hcml6ZShjbnQgPSBuKCkpICU+JSAKICBtdXRhdGUoZnJlcSA9IHJvdW5kKGNudCAvIHN1bShjbnQpLCAyKSkgJT4lIAogIGFycmFuZ2UoZGVzYyhmcmVxKSkgCgp0b3BfcGFydGllcyAlPiUgCiAgZ2dwbG90KGFlcyh4PSBMYWJlbCwgeSA9IGZyZXEsIGZpbGwgPSBMYWJlbCwpKSArCiAgZ2VvbV9jb2woKSArCiAgZmFjZXRfZ3JpZCh+IFBhcnR5KSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCkgKwogIHNjYWxlX3hfZGlzY3JldGUobGltaXRzID0gYygiVFJVRSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIm1vc3RseS10cnVlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJoYWxmLXRydWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgImJhcmVseS10cnVlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJGQUxTRSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAicGFudHMtZmlyZSIpKSArCiAgbGFicyh5ID0gIiUgU3RhdGVtZW50IENvdW50IiwgeCA9ICIiLCBzdWJ0aXRsZSA9ICJUcnV0aCBieSBQYXJ0eSAoUmVsYXRpdmUgJSkiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwobmFtZSA9ICJUcnV0aC1PLU1ldGVyIiwgdmFsdWVzID0gYygicGFudHMtZmlyZSIgPSAicmVkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRkFMU0UiID0gIm9yYW5nZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmFyZWx5LXRydWUiID0gInllbGxvdyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiaGFsZi10cnVlIiA9ICJ5ZWxsb3dncmVlbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibW9zdGx5LXRydWUiID0gImdyZWVuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUUlVFIiA9ICJibHVlIikpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKQoKYGBgCgpOb3QgY2FsbGluZyBhbnkgbmFtZXMsIGJ1dCBzb21lYm9keSdzIHBhbnRzIGFyZSBvbiBmaXJlLi4uYXQgbGVhc3QgaW4gdGhpcyBkYXRhIHNldC4gVG8gc3VtbWFyaXplLCB0aGlzIGRhdGFzZXQgaGFzIHF1aXRlIGEgZmV3IHZhcmlhYmxlcyB0aGF0IHdoZW4gYW5hbHl6ZWQgc2VwYXJhdGVseSBvciBpbiBjb25qdW5jdGlvbiB3aXRoIGVhY2ggb3RoZXIgbWF5IHByb3ZpZGUgaW5kaWNhdG9ycyBvZiBob3cgdHJ1dGhmdWwgYSBzdGF0ZW1lbnQgaXMgYnkgc291cmNlIG9yIGRpc2N1c3Npb24gdG9waWMuIEhvd2V2ZXIsIHRvIHJlYWxseSB1bmRlcnN0YW5kIHRoZSBpbXBhY3Qgb2YgZWFjaCBvZiB0aGVzZSB2YXJpYWJsZXMsIHdlIHNob3VsZCBqdWRnZSB0aGVtIGluIHRoZSBjb250ZXh0IG9mIGhvdyB0aGV5IGFyZSB1c2VkLiBUaGlzIG5leHQgc2VjdGlvbiB3aWxsIGFuYWx5emUgc2VudGltZW50IHRvIGV4cGxvcmUgYW55IG5lZ2F0aXZpdHkgYmlhcyBpbiB0aGUgdGV4dCBzdGF0ZW1lbnRzLgoKIyMgTW9kZWwKCkkndmUgY2hvc2VuIHRvIGNvbmR1Y3Qgc2VudGltZW50IGFuYWx5c2lzIHRvIGF0dGVtcHQgdG8gaWRlbnRpZnkgYWRkaXRpb25hbCBtZXRyaWNzIGZvciBtaXNpbmZvcm1hdGlvbi4gVGhlIGRpY3Rpb25hcnkgSSdsbCBiZSB1c2luZyBpcyB0aGUgTlJDIGxleGljb24gZnJvbSBbU2FpZiBNb2hhbW1hZCBhbmQgUGV0ZXIgVHVybmV5XShodHRwOi8vc2FpZm1vaGFtbWFkLmNvbS9XZWJQYWdlcy9OUkMtRW1vdGlvbi1MZXhpY29uLmh0bSkuIFRoaXMgaXMgYSBjcm93ZHNvdXJjZWQgbGlzdCBvZiB3b3JkcyBhbmQgdGhlaXIgYXNzb2NpYXRpb25zIHdpdGggZWlnaHQgZW1vdGlvbnMgKGFuZ2VyLCBmZWFyLCBhbnRpY2lwYXRpb24sIHRydXN0LCBzdXJwcmlzZSwgc2FkbmVzcywgam95LCBhbmQgZGlzZ3VzdCkgYW5kIHR3byBzZW50aW1lbnRzIChuZWdhdGl2ZSBhbmQgcG9zaXRpdmUpLgoKYGBge3J9CiMgRG93bmxvYWQgdGhlIGxleGljb24KbnJjIDwtIGdldF9zZW50aW1lbnRzKCJucmMiKQoKc2VudGltZW50X3N0YXRlbWVudHMgPC0gaW5uZXJfam9pbihzdWJqZWN0X3Rva2VucywgbnJjLCBieSA9ICJ3b3JkIikKc3VtbWFyeV9zZW50aW1lbnQgPC0gc2VudGltZW50X3N0YXRlbWVudHMgJT4lIAogIGNvdW50KHNlbnRpbWVudCwgc29ydCA9IFRSVUUpICU+JQogIHNwcmVhZChzZW50aW1lbnQsIG4pICU+JQogIG11dGF0ZShzZW50aW1lbnQgPSBwb3NpdGl2ZSAtIG5lZ2F0aXZlKSAlPiUKICBtdXRhdGUobGV4aWNvbiA9ICJucmMiKSAlPiUKICByZWxvY2F0ZShsZXhpY29uKQoKc2VudGltZW50X2NvdW50cyA8LSBzZW50aW1lbnRfc3RhdGVtZW50cyAlPiUgCiAgY291bnQoc2VudGltZW50LCBzb3J0ID0gVFJVRSkgCgpzZW50aW1lbnRfY291bnRzICU+JSAgIAogIG11dGF0ZShzZW50aW1lbnQgPSByZW9yZGVyKHNlbnRpbWVudCxuKSkgJT4lCiAgZ2dwbG90KGFlcyhuLCBzZW50aW1lbnQpKSArCiAgZ2VvbV9jb2woKSArCiAgbGFicyh4ID0gIkNvdW50cyIsIHkgPSAiU2VudGltZW50IikKYGBgCgpUaGUgbGFyZ2UgYW1vdW50IG9mICoqKnRydXN0KioqIGFuZCAqKipmZWFyKioqIHdvcmRzIGFyZSBpbnRlcmVzdGluZy4gVGhvdWdoIHRoZSBsYWNrIG9mIGEgaHVnZSBkaWZmZXJlbmNlIGJldHdlZW4gKioqbmVnYXRpdmUqKiogYW5kICoqKnBvc2l0aXZlKioqIHdvcmRzIGluZGljYXRlcyB0aGF0IHRoZSBvdmVyYWxsIHRvbmUgaXMgbXVjaCBtb3JlIG51YW5jZWQgdGhhbiBqdXN0IGdvb2QgdnMuIGJhZC4gT3VyIGxhc3QgZGl2ZSBpbnRvIHRoZSBkYXRhIHdpbGwgYXBwbHkgdGhlc2Ugc2VudGltZW50IHJlc3VsdHMgYWNyb3NzIG91ciB0cnV0aCBsYWJlbHMgYW5kIHBvbGl0aWNhbCBwYXJ0aWVzLgoKYGBge3J9CnNlbnRpbWVudF9zdGF0ZW1lbnRzJExhYmVsIDwtIGZhY3RvcihzZW50aW1lbnRfc3RhdGVtZW50cyRMYWJlbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJwYW50cy1maXJlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJGQUxTRSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmFyZWx5LXRydWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImhhbGYtdHJ1ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibW9zdGx5LXRydWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRSVUUiKSkKCnNlbnRpbWVudF9zdGF0ZW1lbnRzICU+JSAgIAogIGZpbHRlcihQYXJ0eSAlaW4lIHRvcDRfcGFydGllcykgJT4lIAogIGdncGxvdChhZXMoeSA9IHNlbnRpbWVudCwgZmlsbCA9IExhYmVsKSkgKwogIGdlb21fYmFyKCkgKwogIGZhY2V0X3dyYXAofiBQYXJ0eSkgKwogIGxhYnMoeCA9ICJDb3VudHMiLCB5ID0gIlNlbnRpbWVudCIsICwgc3VidGl0bGUgPSAiU2VudGltZW50IGJ5IFBhcnR5IChSYXcgQ291bnQpIikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoInBhbnRzLWZpcmUiID0gInJlZCIsICJGQUxTRSIgPSAib3JhbmdlIiwgImJhcmVseS10cnVlIiA9ICJ5ZWxsb3ciLCAiaGFsZi10cnVlIiA9ICJ5ZWxsb3dncmVlbiIsICJtb3N0bHktdHJ1ZSIgPSAiZ3JlZW4iLCAiVFJVRSIgPSAiYmx1ZSIpKQpgYGAKCmBgYHtyfQpzZW50aW1lbnRfc3RhdGVtZW50cyRMYWJlbCA8LSBmYWN0b3Ioc2VudGltZW50X3N0YXRlbWVudHMkTGFiZWwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygicGFudHMtZmlyZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRkFMU0UiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImJhcmVseS10cnVlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJoYWxmLXRydWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm1vc3RseS10cnVlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUUlVFIikpCgp0b3Bfc2VudGltZW50cyA8LSBzZW50aW1lbnRfc3RhdGVtZW50cyAlPiUgCiAgZmlsdGVyKFBhcnR5ICVpbiUgdG9wNF9wYXJ0aWVzKSAlPiUKICBncm91cF9ieShQYXJ0eSwgc2VudGltZW50KSAlPiUgCiAgc3VtbWFyaXplKGNudCA9IG4oKSkgJT4lIAogIG11dGF0ZShmcmVxID0gcm91bmQoY250IC8gc3VtKGNudCksIDIpKSAlPiUgCiAgYXJyYW5nZShkZXNjKGZyZXEpKSAKCnRvcF9zZW50aW1lbnRzICU+JQogIGdncGxvdChhZXMoeSA9IHNlbnRpbWVudCwgeCA9IGZyZXEsIGZpbGwgPSBzZW50aW1lbnQpKSArCiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGZhY2V0X2dyaWQofiBQYXJ0eSkgKwogIGxhYnMoeCA9ICIiLCB5ID0gIlNlbnRpbWVudCIsIHN1YnRpdGxlID0gIlNlbnRpbWVudCBieSBQYXJ0eSAoUmVsYXRpdmUgJSkiKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCkKYGBgCgpUaGVzZSBncmFwaHMgY29uZmlybXMgdGhlIGhpZ2ggdXNlIG9mICJ0cnVzdCIgd29yZHMgYXMgYSBwb3RlbnRpYWwgbWFzayB0byBpc3N1ZXMgb3IgZGlzY3Vzc2lvbnMgdGhhdCBhcmVuJ3QgYWx3YXlzIHRydXRoZnVsLiBUaGUgaGlnaGVzdCByYXRpbmcgb2YgZmFsc2Ugc3RhdGVtZW50cyAodGhpbmsgeWVsbG93LCBvcmFuZ2UsIHJlZCksIGFyZSBpbiB0aGUgc2VudGltZW50IGNhdGVnb3JpZXMgb2YgKioqdHJ1c3QqKiosICoqKm5lZ2F0aXZlKioqLCAqKipwb3NpdGl2ZSoqKiwgYW5kICoqKmZlYXIqKiouCgojIyBDb21tdW5pY2F0ZQoKIyMjICpDb25jbHVzaW9ucyoKCkZvciBodW1hbnMgdG8gY2xhc3NpZnkgdGV4dCBtYW51YWxseSwgc3BlY2lmaWMgZG9tYWluIGV4cGVydGlzZSBpcyByZXF1aXJlZC4gRXhwZWN0aW5nIGEgcGVyc29uIHRvIG1haW50YWluIHRoaXMgdHlwZSBvZiBrbm93bGVkZ2UgYWNyb3NzIG11bHRpcGxlIGRvbWFpbnMgaW4gdGhlIGRpZ2l0YWwgYWdlIGlzIG5lYXJseSBpbXBvc3NpYmxlLiBGb3IgdGhlIGNoYWxsZW5nZSBvZiBtb25pdG9yaW5nIG9ubGluZSBuZXdzIG1lZGlhIGZvciBtaXNpbmZvcm1hdGlvbiwgdGhlIHRhc2tzIGluY2x1ZGUgY29sbGVjdGluZyB0aGUgYXJ0aWNsZXMsIGluZ2VzdGluZyB0aGVpciBjb250ZW50LCByZWNvZ25pemluZyBwYXR0ZXJucyBpbiB0aGUgZGF0YSwgYW5kIGZpbmFsbHkgY2xhc3NpZnlpbmcgdGhlIGFydGljbGVzIGludG8gY2F0ZWdvcmllcy4gVGhpcyBjYXNlIHN0dWR5IGRlbW9uc3RyYXRlcyB0aGF0IGFsbCBvZiB0aGVzZSBjYW4gYmUgYWNjb21wbGlzaGVkIHdpdGggY3VycmVudCBzb2Z0d2FyZSBhbmQganVzdCBhIGxpdHRsZSBiaXQgb2YgY3JlYXRpdml0eS4KClRoaXMgZXhlcmNpc2Ugc3BlY2lmaWNhbGx5IGxvb2tlZCBhdCB0aGUgYWJpbGl0eSB0byBhdXRvbWF0ZSB0aGVzZSB0YXNrcyB0byBhc3Npc3QgaW4gaWRlbnRpZnlpbmcgbWV0cmljcyBvciBrZXkgaW5kaWNhdG9ycyB3aGV0aGVyIHRleHQtYmFzZWQgbWVkaWEgaXMgbWlzaW5mb3JtaW5nIHRoZSBwdWJsaWMuIFRocm91Z2gganVzdCBhIGZldyBiYXNpYyBjb2Rpbmcgc2FtcGxlcywgbnVtZXJvdXMgZXhhbXBsZXMgd2VyZSBkaXNjb3ZlcmVkIHRoYXQgY291bGQgYmUgcGllY2VkIHRvZ2V0aGVyIHRvIGRldGVybWluZSBhIHBvc3RpbmcncyB2ZXJhY2l0eS4KCiMjIyAqQWRkaXRpb25hbCBBcmVhcyBvZiBSZXNlYXJjaCoKClRoaXMgY2FzZSBzdHVkeSBleGFtaW5lZCBhIHNpbmdsZSB0eXBlIG9mIG9ubGluZSBtZWRpYSwgdGV4dC4gU2ltaWxhciBleGVyY2lzZXMgY2FuIGJlIGRvbmUgd2l0aCBpbWFnZXMgb3IgdmlkZW8sIHRob3VnaCB0cmFuc2xhdGluZyB0aGVtIGludG8gYSBtZWRpdW0gdGhhdCBjb3VsZCBiZSBhbmFseXplZCBsaWtlIHRleHQgd291bGQgdGFrZSBhIGJpdCBtb3JlIGNvbXB1dGluZyBwb3dlciB0aGFuIG1vc3Qgb2YgaGF2ZSBhdmFpbGFibGUgdG8gdXMuCgpCZXlvbmQgdW5kZXJzdGFuZGluZyB0aGVzZSBrZXkgbWV0cmljcyBpcyBhcHBseWluZyB0aGVtIHRvIG1hY2hpbmUgbGVhcm5pbmcgbW9kZWxzIHRoYXQgY291bGQgbGVhcm4gdG8gcHJlZGljdCBhbiBhcnRpY2xlJ3MgdHJ1dGhmdWxuZXNzLCBzZW50aW1lbnQsIG9yIGJpYXMuIFRob3NlIGVmZm9ydHMgd291bGQgZW5hYmxlIGFwcGxpY2F0aW9ucyBhbmQgaW50ZXJuZXQgYnJvd3NlciBleHRlbnNpb25zIHRoYXQgY291bGQgbm90aWZ5IHBlb3BsZSBhYm91dCB0aGUgcXVhbGl0eSBvZiBtYXRlcmlhbCB0aGV5IGNvbnN1bWUgb25saW5lLgoKIyMjICpMaW1pdGF0aW9ucyoKClRoZSBkYXRhIGlzIGFsd2F5cyBnb2luZyB0byBsaW1pdCBob3cgZ2VuZXJhbGl6YWJsZSB0aGVzZSByZXN1bHRzIGFyZS4gTGFyZ2VyIGRhdGEgc2V0cyB3aWxsIGVuYWJsZSBicm9hZGVyIGFwcGxpY2F0aW9ucyBvZiB0aGUgaW5zaWdodHMuIEZvciB0aGlzIGRhdGEgc2V0LCB0aGUgdGV4dCBkaWQgbm90IGNvbnRhaW4gZnVsbCwgbG9uZy1mb3JtIGFydGljbGVzLiBBcyBhIHJlc3VsdCwgdGhpcyBzdHVkeSBpcyBwcm9iYWJseSBiZXR0ZXIgZm9yIHNvY2lhbCBtZWRpYSBhbmFseXNpcyB3aGVyZSB0aGUgY29udmVyc2F0aW9ucyBhcmUgc2hvcnRlci4gQ29tcHV0aW5nIHBvd2VyIGFuZCBjb2Rpbmcgc2tpbGxzIGFyZSBteSBwZXJzb25hbCBsaW1pdGF0aW9uLiBMYXJnZSB0ZXh0IGRhdGFzZXRzIGNhbiByZXR1cm4gdmVyeSBsYXJnZSB0b2tlbml6ZWQgZGF0YSBmcmFtZXMgdGhhdCB0YWtlIGEgd2hpbGUgdG8gcnVuLgoKIyMjICpMZWdhbC9FdGhpY2FsIENvbnNpZGVyYXRpb25zKgoKTm8gcGVyc29uYWwgaW5mb3JtYXRpb24gd2FzIGNvbGxlY3RlZCBvciB1c2VkIGZvciB0aGlzIGNhc2Ugc3R1ZHkuIFRoZSBkYXRhIHdhcyBnZW5lcmF0ZWQgYW5kIG1hZGUgYXZhaWxhYmxlIG9uIGEgcHVibGljIGZhY2luZyB3ZWJzaXRlIHdpdGggdGhpcyBkaXNjbGFpbWVyOgoKIlRoZSBvcmlnaW5hbCBzb3VyY2VzIHJldGFpbiB0aGUgY29weXJpZ2h0IG9mIHRoZSBkYXRhLiBOb3RlIHRoYXQgdGhlcmUgYXJlIGFic29sdXRlbHkgbm8gZ3VhcmFudGVlcyB3aXRoIHRoaXMgZGF0YSwgYW5kIHdlIHByb3ZpZGUgdGhpcyBkYXRhc2V0ICJhcyBpcyIsIGJ1dCB5b3UgYXJlIHdlbGNvbWUgdG8gcmVwb3J0IHRoZSBpc3N1ZXMgb2YgdGhlIHByZWxpbWluYXJ5IHZlcnNpb24gb2YgdGhpcyBkYXRhLiBZb3UgYXJlIGFsbG93ZWQgdG8gdXNlIHRoaXMgZGF0YXNldCBmb3IgcmVzZWFyY2ggcHVycG9zZXMgb25seS4iCgojIyMgKkFja25vd2xlZGdlbWVudHMvUmVmZXJlbmNlcyoKCjEuICBCcmVha3N0b25lLCBKLiwgU21pdGgsIE0uLCBXaW5lYnVyZywgUy4sIFJhcGFwb3J0LCBBLiwgQ2FybGUsIEouLCBHYXJsYW5kLCBNLiwgJiBTYWF2ZWRyYSwgQS4gKDIwMTkpLiBTdHVkZW50cycgY2l2aWMgb25saW5lIHJlYXNvbmluZzogQSBuYXRpb25hbCBwb3J0cmFpdC4gU3RhbmZvcmQgSGlzdG9yeSBFZHVjYXRpb24gR3JvdXAgJiBHaWJzb24gQ29uc3VsdGluZy7CoDxodHRwczovL3B1cmwuc3RhbmZvcmQuZWR1L2dmMTUxdGI0ODY4PgoyLiAgSG9sYW4sIEEuICgyMDIwLCBPY3RvYmVyIDI3KS4gKlBvbGl0aWZhY3QgLSB0aGUgcHJpbmNpcGxlcyBvZiB0aGUgdHJ1dGgtTy1tZXRlcjogUG9saXRpRmFjdCdzIG1ldGhvZG9sb2d5IGZvciBpbmRlcGVuZGVudCBmYWN0LWNoZWNraW5nKi4gUG9saXRpZmFjdC4gUmV0cmlldmVkIERlY2VtYmVyIDEsIDIwMjEsIGZyb20gPGh0dHBzOi8vd3d3LnBvbGl0aWZhY3QuY29tL2FydGljbGUvMjAxOC9mZWIvMTIvcHJpbmNpcGxlcy10cnV0aC1vLW1ldGVyLXBvbGl0aWZhY3RzLW1ldGhvZG9sb2d5LWkvLj4KMy4gIE1vaGFtbWFkLCBTLiAoMjAxMSwgSnVseSAxMCkuICpOUkMgV29yZC1FbW90aW9uIEFzc29jaWF0aW9uIExleGljb24qLiBTYWlmIE0uIE1vaGFtbWFkIEhvbWVwYWdlLiBSZXRyaWV2ZWQgRGVjZW1iZXIgMSwgMjAyMSwgZnJvbSA8aHR0cDovL3NhaWZtb2hhbW1hZC5jb20vV2ViRG9jcy9SRUFETUUtTlJDLUxleC50eHQuPgo0LiAgV2FuZywgVy4gWS4gKDIwMTcpLiBMaWFyLCBMaWFyIFBhbnRzIE9uIGZpcmU6IEEgbmV3IGJlbmNobWFyayBkYXRhc2V0IGZvciBmYWtlIG5ld3MgZGV0ZWN0aW9uLiAqUHJvY2VlZGluZ3Mgb2YgdGhlIDU1dGggQW5udWFsIE1lZXRpbmcgb2YgdGhlIEFzc29jaWF0aW9uIGZvciBDb21wdXRhdGlvbmFsIExpbmd1aXN0aWNzIChWb2x1bWUgMjogU2hvcnQgUGFwZXJzKSouIDxodHRwczovL2RvaS5vcmcvMTAuMTg2NTMvdjEvcDE3LTIwNjc+CjUuICBXaW5lYnVyZywgU2FtIGFuZCBNY0dyZXcsIFNhcmFoIGFuZCBCcmVha3N0b25lLCBKb2VsIGFuZCBPcnRlZ2EsIFRlcmVzYS4gKDIwMTYpLiBFdmFsdWF0aW5nIEluZm9ybWF0aW9uOiBUaGUgQ29ybmVyc3RvbmUgb2YgQ2l2aWMgT25saW5lIFJlYXNvbmluZy4gU3RhbmZvcmQgRGlnaXRhbCBSZXBvc2l0b3J5LiA8aHR0cDovL3B1cmwuc3RhbmZvcmQuZWR1L2Z2NzUxeXQ1OTM0Pgo=