1. PREPARE
To help us better understand the context, questions, and data sources
we’ll be using in Unit 3, this section will focus on the following
topics:
- Context. As context for our analysis this week,
we’ll review several related papers by my colleagues relevant to our
analysis of MOOC-Ed discussion forums.
- Questions. We’ll also examine what insight topic
modeling can provide to a question that we asked participants answer in
their professional learning teams (PLTs).
- Project Setup. This should be very familiar by now,
but we’ll set up a new R project and install and load the required
packages for the topic modeling walkthrough.
1a. Context
Participating in a MOOC and Professional Learning Team: How a
Blended Approach to Professional Development Makes a Difference

Full text: https://www.learntechlib.org/p/195234/
Abstract
Massive Open Online Courses for Educators (MOOC-Eds) provide
opportunities for using research-based learning and teaching practices,
along with new technological tools and facilitation approaches for
delivering quality online professional development. The Teaching
Statistics Through Data Investigations MOOC-Ed was built for preparing
teachers in pedagogy for teaching statistics, and it has been offered to
participants from around the world. During 2016-2017, professional
learning teams (PLTs) were formed from a subset of MOOC-Ed participants.
These teams met several times to share and discuss their learning and
experiences. This study focused on examining the ways that a blended
approach to professional development may result in similar or different
patterns of engagement to those who only participate in a large-scale
online course. Results show the benefits of a blended learning
environment for retention, engagement with course materials, and
connectedness within the online community of learners in an online
professional development on teaching statistics. The findings suggest
the use of self-forming autonomous PLTs for supporting a deeper and more
comprehensive experience with self-directed online professional
developments such as MOOCs. Other online professional development
courses, such as MOOCs, may benefit from purposely suggesting and
advertising, and perhaps facilitating, the formation of small
face-to-face or virtual PLTs who commit to engage in learning
together.
Data Source & Analysis
All peer interaction, including peer discussion, take place within
discussion forums of MOOC-Eds, which are hosted using the Moodle
Learning Management System. To build the dataset you’ll be using for
this walkthrough, the research team wrote a query for Moodle’s MySQL
database, which records participants’ user-logs of activity in the
online forums. This sql query combines separate database tables
containing postings and comments including participant IDs, timestamps,
discussion text and other attributes or “metadattsa.”
For further description of the forums and data retrieval process, see
also the following papers:
Kellogg, S., & Edelmann, A. (2015). Massively
Open Online Course for Educators (MOOC‐Ed) network
dataset. British journal of educational
technology, 46(5), 977-983.
Ezen-Can, A., Boyer, K. E., Kellogg, S., & Booth, S. (2015,
March). Unsupervised
modeling for understanding MOOC discussion forums: a learning analytics
approach. In Proceedings of the fifth international conference
on learning analytics and knowledge (pp. 146-150).
Kellogg, S., Booth, S., & Oliver, K. (2014). A
social network perspective on peer supported learning in MOOCs for
educators. International Review of Research in Open and
Distributed Learning, 15(5), 263-289.
Summary of Key Findings
The following highlight some key findings related to the discussion
forums in the papers cited above:
- MOOCs designed specifically for K-12 teachers can provide positive
self-directed learning experiences and rich engagement in discussion
forums that help form online communities for educators.
- Analysis of discussion forum data in TSDI provided a very clear
picture of how enthusiastic many PLT members and leaders were to talk to
others in the online community. They posed their questions and shared
ideas with others about teaching statistics throughout the units, even
though they were also meeting synchronously several times with their
colleagues in small group PLTs.
- Findings on knowledge construction demonstrated that over half of
the discussions in both courses moved beyond sharing information and
statements of agreement and entered a process of dissonance, negotiation
and co-construction of knowledge, but seldom moved beyond this phase in
which new knowledge was tested or applied. These findings echo similar
research on difficulties in promoting knowledge construction in online
settings.
- Topic modeling provides more interpretable and cohesive models for
discussion forums than other popular unsupervised modeling techniques
such as k-means and k-medoids clustering algorithms.
1b. Guiding Questions
For the paper, Participating in a
MOOC and Professional Learning Team: How a Blended Approach to
Professional Development Makes a Difference, the researchers
were interested in unpacking how participants who enrolled in the
Teaching Statistics through Data Investigations MOOC-Ed might benefit
from also being in a smaller group of professionals committed to
engaging in the same professional development. The specific research
question for this paper was:
What are the similarities and differences between how PLT members and
Non-PLT online participants engage and meet course goals in a MOOC-Ed
designed for educators in secondary and collegiate settings?
Dr. Hollylynne Lee and the TSDI team also developed a facilitation
guide designed specifically for PLT teams to help groups synthesize the
ideas in the course and make plans for how to implement new strategies
in their classroom in order to impact students’ learning of statistics.
One question PLT members were asked to address was:
What ideas or issues emerged in the discussion forums this past
week?
For this walkthrough, we will further examine that question through
the use of topic modeling.
And just to reiterate yet again from Unit 1, one overarching question
we’ll explore throughout this course, and that Silge and Robinson (2018)
identify as a central question to text mining and natural language
processing, is:
How do we to quantify what a document or collection
of documents is about?
1c. Set Up
As highlighted in Chapter 6 of Data
Science in Education Using R (DSIEUR), one of the first steps of
every workflow should be to set up a “Project” within RStudio. This will
be your “home” for any files and code used or created in Unit 2.
You are welcome to continue using the same project created for Unit
1, or create an entirely new project for Unit 2. However, after you’ve
created your project open up a new R script, and load the following
packages that we’ll be needing for this walkthrough:
library(tidyverse)
library(tidytext)
library(SnowballC)
library(topicmodels)
library(stm)
library(ldatuning)
library(knitr)
library(LDAvis)
At the end of this week, I encourage you share with me your R script
as evidence that you have complete the walkthrough. Although I highly
recommend that that you manually type the code shared throughout this
walkthrough, for large blocks of text it may be easier to copy and
paste.
2. WRANGLE
As noted previously, data wrangling involves some combination of
cleaning, reshaping, transforming, and merging data (Wickham &
Grolemund, 2017). This week we’ll revisit tidying and tokenizing text
using the tidytext package, but are also introduced to the
the stm package. This package makes use of tm
text mining package to preprocess text (e.g., removing punctuation, stop
words, etc.) and will also be our first introduction to word
stemming.
- Import Data. We’ll be working with .csv files this
week and the
read_csv() function but will introduce a new
argument for changing column types.
- Cast a DTM. We revisit the
tidytext
package to “tidy” and tokenize our forum data and introduce the
cast_dtm() function to create the document term matrix
(dtm) need for topic modeling.
- To Stem or not to STEM? We conclude our data
wrangling by also introducing the
textProcessor() function
for preprocessing and discuss the pros and cons of word stemming.
2a. Import Forum Data
To get started, we need to import, or “read”, our data into R. The
function used to import your data will depend on the file format of the
data you are trying to import. First, however, you’ll need to do the
following:
- Download the
ts_forum_data.csv file we’ll be using for
this Unit from our NCSU Moodle course site.
- Create a folder in the directory on your computer where you stored
your R Project and name it “data”.
- Add the file to your data folder.
- Check your Files tab in RStudio to verify that your file is indeed
in your data folder.
Now let’s read our data into our Environment using the
read_csv() function and assign it to a variable name so we
can work with it like any other object in R.
ts_forum_data <- read_csv("data/ts_forum_data.csv",
col_types = cols(course_id = col_character(),
forum_id = col_character(),
discussion_id = col_character(),
post_id = col_character()
)
)
By default, many of the columns like course_id and
forum_id are read in as numeric data. For our purposes, we
plan to treat them as unique identifiers or names for out courses,
forums, discussions, and posts. The read_csv() function has
a handy col_types = argument changing the column types from
numeric to characters.
2b. Cast a Document Term Matrix
In this section we’ll revisit some familiar tidytext
functions used in Units 1 & 2 for tidying and tokenizing text and
introduce some new functions from the stm package for
processing text and transforming our data frames into new data
structures required for topic modeling.
Functions Used
tidytext functions
unnest_tokens() splits a column into tokens
anti_join() returns all rows from x without a match in
y and used to remove stop words from out data.
cast_dtm() takes a tidied data frame take and “casts”
it into a document-term matrix (dtm)
dplyr functions
count() lets you quickly count the unique values of one
or more variables
group_by() takes a data frame and one or more variables
to group by
summarise() creates a summary of data using arguments
like sum and mean
stm functions
textProcessor() takes in a vector or column of raw
texts and performs text processing like removing punctuation and word
stemming.
prepDocuments() performs several corpus manipulations
including removing words and renumbering word indices
Tidying Text
Prior to topic modeling, we have a few remaining steps to tidy our
text that hopefully should feel familiar by this point. If you recall
from Chapter 1 of
Text Mining With R, these preprocessing steps include:
- Transforming our text into “tokens”
- Removing unnecessary characters, punctuation, and whitespace
- Converting all text to lowercase
- Removing stop words such as “the”, “of”, and “to”
Let’s tokenize our forum text and by using the familiar
unnest_tokens() and remove stop words per usual:
forums_tidy <- ts_forum_data %>%
unnest_tokens(output = word, input = post_content) %>%
anti_join(stop_words, by = "word")
forums_tidy
## # A tibble: 192,159 × 14
## course_id course_name forum…¹ forum…² discu…³ discu…⁴ discu…⁵ discu…⁶ discu…⁷
## <chr> <chr> <chr> <chr> <chr> <chr> <dbl> <dbl> <chr>
## 1 9 Teaching S… 126 Invest… 6822 Not mu… 4513 5009 4513
## 2 9 Teaching S… 126 Invest… 6822 Not mu… 4513 5009 4513
## 3 9 Teaching S… 126 Invest… 6822 Not mu… 4513 5009 4513
## 4 9 Teaching S… 126 Invest… 6822 Not mu… 4513 5009 4513
## 5 9 Teaching S… 126 Invest… 6822 Not mu… 4513 5009 4513
## 6 9 Teaching S… 126 Invest… 6822 Not mu… 4513 5009 4513
## 7 9 Teaching S… 126 Invest… 6822 Not mu… 4513 5009 4513
## 8 9 Teaching S… 126 Invest… 6822 Not mu… 4513 5009 4513
## 9 9 Teaching S… 126 Invest… 6822 Not mu… 4513 5009 4513
## 10 9 Teaching S… 126 Invest… 6822 Not mu… 4513 5009 4513
## # … with 192,149 more rows, 5 more variables: parent_id <dbl>, post_date <chr>,
## # post_id <chr>, post_title <chr>, word <chr>, and abbreviated variable names
## # ¹forum_id, ²forum_name, ³discussion_id, ⁴discussion_name,
## # ⁵discussion_creator, ⁶discussion_poster, ⁷discussion_reference
Now let’s do a quick word count to see some of the most common words
used throughout the forums. This should get a sense of what we’re
working with and later we’ll need these word counts for creating our
document term matrix for topic modeling:
forums_tidy %>%
count(word, sort = TRUE)
## # A tibble: 13,620 × 2
## word n
## <chr> <int>
## 1 students 6841
## 2 data 4365
## 3 statistics 3103
## 4 school 1488
## 5 questions 1470
## 6 class 1426
## 7 font 1311
## 8 span 1267
## 9 time 1253
## 10 style 1150
## # … with 13,610 more rows
Terms like “students,” “data,” and “class” are about what we would
have expected from a course teaching statistics. The term “agree” and
“time” however, are not so intuitive and worth a quick look as well.
✅ Comprehension Check
Use the filter() and grepl() functions
introduced in Unit
1. Section 3b to filter for rows in our ts_forum_data
data frame that contain the terms “agree” and “time” and another term or
terms of your choosing. Select a random sample of 10 posts using the
sample_n() function for your terms and answer the following
questions:
What, if anything, do these posts have in common?
What topics or themes might be apparent, or do you anticipate
emerging, from our topic modeling?
Your output should look something like this:
## # A tibble: 10 × 1
## post_content
## <chr>
## 1 "Modeling is always a good place to start when you have expectations that ar…
## 2 "I really like the war game activity. It is a game that your student are pro…
## 3 "I agree with you. I think that this helps with the whole ownership part but…
## 4 "Has anyone used CODAP with their students? Does it take long to use? Can …
## 5 "The text I am using now is the first I have seen to use specific criteria f…
## 6 "Good idea. Then you would only need to perform the time-consuming bit once…
## 7 "I very much agree that we need to all be looking vertically across the curr…
## 8 "This is a great discussion! I agree that using more statistically sophisti…
## 9 "I was re-watching the boys interact in the Watching a Dynamic Simulation To…
## 10 "I agree-maybe hours on Youtube or check their iPhones to see which app and…
Creating a Document Term Matrix
As highlighted in Chapter 5 of
Text Mining with R, the topicmodels package and the Latent
Dirichlet allocation (LDA) algorithm and LDA() function
it uses expects document-term matrix as the data input.
Before we create a our document-term matrix, however, we have an
important decision to make:
What do we consider to be a “document” in a MOOC-Ed
discussion forum?
For example, we could consider each individual discussion post, or
post_id in our data frame, as a document. It might also
make sense to combine texts from all posts within each discussion, or
disccussion_id, and consider that as a document since these
posts are often interconnected an build off one another.
For now, however, let treat each individual post as a unique
“document.” noted above, to create our document term matrix, we’ll need
to first count() how many times each word
occurs in each document, or post_id in our case, and create
a matrix that contains one row per post as our original data frame did,
but now contains a column for each word in the entire
corpus and a value of n for how many times that word occurs
in each post.
To create this document term matrix from our post counts, we’ll use
the cast_dtm() function like so and assign it to the
variable forums_dtm:
forums_dtm <- forums_tidy %>%
count(post_id, word) %>%
cast_dtm(post_id, word, n)
✅ Comprehension Check
Take a look at our forums_dtm object in the console and
answer the following question:
- What “class” of object is
forums_dtm?
- How many unique documents and terms are included our matrix?
- Why might there be fewer documents/posts than were in our original
data frame?
- What exactly is meant by “sparsity”?
## [1] "DocumentTermMatrix" "simple_triplet_matrix"
## <<DocumentTermMatrix (documents: 5766, terms: 13620)>>
## Non-/sparse entries: 142641/78390279
## Sparsity : 100%
## Maximal term length: NA
## Weighting : term frequency (tf)
2c. To Stem or not to Stem?
Next we’ll need to prepare our original data set for structural topic
modeling using the textProcessor() function. The
stm package has a number of features that extend the
functionality of the topicmodels package, including an
argument for “stemming” words, which Schofield
and Mimno (2016) describe as follows:
Stemming is a popular way to reduce the size of a vocabulary in
natural language tasks by conflating words with related meanings.
Specifically, stemming aims to convert words with the same “stem” or
root (e.g “creative” and “creator”) to a single word type (“create”).
Though originally developed in the context of information retrieval (IR)
systems, stemmers are now commonly used as a preprocessing step in
unsupervised machine learning tasks.
The rationale behind stemming is that it can dramatically reduce the
number of words or terms to be modeled, which in theory should help
simplify and improve the performance of your model. We’ll explore this
assumption a little later in this section.
Processing and Stemming for STM
Like unnest_tokens(), the textProcessor()
function includes several useful arguments for processing text like
converting text to lowercase and removing punctuation and numbers. I’ve
included several of these in the script below along with their defaults
used if you do not explicitly specify in your function. Most of these
are pretty intuitive and you can learn more by viewing the
?textProcessor documentation.
Let’s go ahead and process our discussion forum
post_content in preparation for structural topic
modeling:
temp <- textProcessor(ts_forum_data$post_content,
metadata = ts_forum_data,
lowercase=TRUE,
removestopwords=TRUE,
removenumbers=TRUE,
removepunctuation=TRUE,
wordLengths=c(3,Inf),
stem=TRUE,
onlycharacter= FALSE,
striphtml=TRUE,
customstopwords=NULL)
## Building corpus...
## Converting to Lower Case...
## Removing punctuation...
## Removing stopwords...
## Removing numbers...
## Stemming...
## Creating Output...
Note that the first argument the textProcessor function
expects is the column in our data frame that contains the text to be
processed, the second argument metadata = expects the data
frame that contains the text of interest and uses the column names to
label the metadata such as course ids and forum names. This meatdata can
be used to to improve the assignment of words to topics in a corpus and
examine the relationship between topics and various covariates of
interest.
Unlike the unnest_tokens() function, the output is not a
nice tidy data frame. Topic modeling using the stm package
requires a very unique set of inputs that are specific to the package.
The following code will pull elements from the temp list
that was created that will be required for the stm()
function we’ll use in Section 4:
meta <- temp$meta
vocab <- temp$vocab
docs <- temp$documents
Stemming Tidy Text
Notice that the textProcessor stem argument we used
above is set to TRUE by default. We haven’t introduced word
stemming at this point because there is some debate about the actual
value of this process. While words like “students” and “student” might
make sense to collapse into their base word and actually make analyses
and visualizations more concise and easier to interpret. Hvitfeldt and Silge (2021)
note, however, that words like the following have dramatic differences
in meaning, semantics, and use and could result in poor models or
misinterpreted results:
- meaning and mean
- likely, like, liking
- university and universe
The first word pair is particularly relevant to discussion posts from
our Teaching Statistics course data. In addition, collapsing words like
“teachers” and “teaching” could dramatically alter the results from a
topic model.
Schofield
and Mimno (2016) specifically,
Despite their frequent use in topic modeling, we find that
stemmers produce no meaningful improvement in likelihood and coherence
and in fact can degrade topic stability.
For now, we will leave as is the forums_dtm we created
earlier with words unstemmed, but what if we wanted to stem words in a
“tidy” way?
Since the unnest_tokens() function does not
(intentionally I believe) include a stemming function, one approach
would be to use the wordStem() function from the
snowballC package to either replace our words
column with a word stems or create a new variable called
stem with our stemmed words. Let’s do the latter and take a
look at the original words and the stem that was produced:
stemmed_forums <- ts_forum_data %>%
unnest_tokens(output = word, input = post_content) %>%
anti_join(stop_words, by = "word") %>%
mutate(stem = wordStem(word))
stemmed_forums
## # A tibble: 192,159 × 15
## course_id course_name forum…¹ forum…² discu…³ discu…⁴ discu…⁵ discu…⁶ discu…⁷
## <chr> <chr> <chr> <chr> <chr> <chr> <dbl> <dbl> <chr>
## 1 9 Teaching S… 126 Invest… 6822 Not mu… 4513 5009 4513
## 2 9 Teaching S… 126 Invest… 6822 Not mu… 4513 5009 4513
## 3 9 Teaching S… 126 Invest… 6822 Not mu… 4513 5009 4513
## 4 9 Teaching S… 126 Invest… 6822 Not mu… 4513 5009 4513
## 5 9 Teaching S… 126 Invest… 6822 Not mu… 4513 5009 4513
## 6 9 Teaching S… 126 Invest… 6822 Not mu… 4513 5009 4513
## 7 9 Teaching S… 126 Invest… 6822 Not mu… 4513 5009 4513
## 8 9 Teaching S… 126 Invest… 6822 Not mu… 4513 5009 4513
## 9 9 Teaching S… 126 Invest… 6822 Not mu… 4513 5009 4513
## 10 9 Teaching S… 126 Invest… 6822 Not mu… 4513 5009 4513
## # … with 192,149 more rows, 6 more variables: parent_id <dbl>, post_date <chr>,
## # post_id <chr>, post_title <chr>, word <chr>, stem <chr>, and abbreviated
## # variable names ¹forum_id, ²forum_name, ³discussion_id, ⁴discussion_name,
## # ⁵discussion_creator, ⁶discussion_poster, ⁷discussion_reference
You can see that words like “activity” and “activities” that occur
frequently in our discussions have been reduced to the word stem
“activ”. If you are interested in learning other approaches for word
stemming in R, as well as reading a more in depth description of the
stemming process, I highly recommend the Chapter 4 Stemming from
Hvitfeldt and Silge (2021) book, Supervised Machine Learning for
Text Analysis in R.
✅ Comprehension Check
Complete the following code using what we learned in the section on
Creating a Document Term
Matrix and answer the following questions:
- How many fewer terms are in our stemmed document term matrix?
- Did stemming words significantly reduce the sparsity of the
network?
Hint: Make sure your code includes stem counts
rather than word counts.
stemmed_dtm <- ts_forum_data %>%
unnest_tokens(output = word, input = post_content) %>%
anti_join(stop_words, by = "word") %>%
mutate(stem = wordStem(word)) %>%
count(post_id, stem, sort = TRUE) %>%
cast_dtm(post_id, stem, n)
stemmed_dtm
## <<DocumentTermMatrix (documents: 5766, terms: 10001)>>
## Non-/sparse entries: 136185/57529581
## Sparsity : 100%
## Maximal term length: NA
## Weighting : term frequency (tf)
## <<DocumentTermMatrix (documents: 5766, terms: 13620)>>
## Non-/sparse entries: 142641/78390279
## Sparsity : 100%
## Maximal term length: NA
## Weighting : term frequency (tf)
## # A tibble: 10,001 × 2
## stem n
## <chr> <int>
## 1 student 7354
## 2 data 4365
## 3 statist 4161
## 4 question 2470
## 5 teach 1858
## 6 class 1738
## 7 school 1606
## 8 time 1457
## 9 learn 1372
## 10 font 1311
## # … with 9,991 more rows
3. MODEL
This unit provides our first opportunity for modeling a text as data.
In very simple terms, modeling involves developing a mathematical
summary of a dataset. These summaries can help us further explore trends
and patterns in our data.
In their book, Learning Analytics Goes to School, Krumm and
Means (2018) describe two general types of modeling approaches used in
the Data-Intensive Research workflow: unsupervised and supervised
machine learning. In distinguishing between the two, they note:
Unsupervised learning algorithms can be used to understand the
structure of one’s dataset. Supervised models, on the other hand, help
to quantify relationships between features and a known outcome. Known
outcomes are also commonly referred to as labels or dependent
variables.
In Section 3 we focus on Topic Modeling, an unsupervised learning
approach to automatically identify topics in a collection of documents.
In fact, we’ll explore two different approaches to topic modeling, as
well as strategies for identifying the “right” number of topics:
- Fitting a Topic Modeling with LDA. In this section
we learn to use the
topicmodels package and associated
LDA() function for unsupervised classification of our forum
discussions to find natural groupings of words, or topics.
- Fitting a Structural Topic Model. We then explore
the use of the
stm package and stm() function
to fit our model and uses metadata about documents to improve the
assignment of words to “topics” in a corpus.
- Choosing K. Finally, we wrap up Section 3 by
learning about diagnostic properties like exclusivity, semantic
coherence, and heldout likelihood for helping to select an appropriate
number of topics.
3a. Fitting a Topic Modeling with LDA
Before running our first topic model using the LDA()
function, let’s quick recap from our readings some basic principles
behind Latent Dirichlet allocation and why LDA is of preferred over
other automatic classification or clustering approaches.
Unlike simple forms of cluster analysis such as k-means clustering,
LDA is a “mixture” model, which in our context means
that:
- Every document contains a mixture of topics.
Unlike algorithms like k-means, LDA treats each document as a mixture of
topics, which allows documents to “overlap” each other in terms of
content, rather than being separated into discrete groups. So in
practice, this means that a discussion forum post could have an
estimated topic proportion of 70% for Topic 1 (e.g. be mostly about a
Topic 1), but also be partly about Topic 2.
- Every topic contains a mixture of words. For
example, if we specified in our LDA model just 2 topics for our
discussion posts, we might find that one topic seems to be about
pedagogy while another is about learning. The most common words in the
pedagogy topic might be “teacher”, “strategies”, and “instruction”,
while the learning topic may be made up of words like “understanding”
and “students”. However, words can be shared between topics and words
like “statistics” or “assessment” might appear in both equally.
Similar to k-means other other simple clustering approaches, however,
LDA does require us to specify a value of k for the number of
topics in our corpus. Selecting k is no trivial matter and can
greatly impact your results.
Since we don’t have a have strong rationale about the number of
topics that might exist in discussion forums, let’s use the
n_distinct() function from the dplyr package
to find the number of unique forum names in our course data and run with
that:
n_distinct(ts_forum_data$forum_name)
## [1] 21
Since it looks like there are 20 distinct discussion forums, we’ll
use that as our value for the k = argument of the
LDA(). Be patient while this runs, since the default
setting of is to perform a large number of iterations. I changed the
number of iterations from 2000 to 500 to make it run faster.
n_distinct(ts_forum_data$forum_name)
## [1] 21
forums_lda <- LDA(forums_dtm,
k = 20,
iter=500,#to make it run faster
control = list(seed = 588)
)
forums_lda
## A LDA_VEM topic model with 20 topics.
Note that we used the control = argument to pass a
random number (588) to seed the assignment of topics to
each word in our corpus. Since LDA is a stochastic
algorithm that could have different results depending on where the
algorithm starts, specified a seed for reproducibility and
so we’re all seeing the same results every time we specify the same
number of topics.
And tying back to our work in Unit 1, Bail (2020) notes that topic
assignments for each word are updated in an iterative fashion and that
LDA employs the Term Frequency-Inverse Document Frequency (TF-IDF)
metric to assign probabilities.
3b. Fitting a Structural Topic Model
Bail notes that LDA, while perhaps the most common approach to topic
modeling, is just one of many different types, including Dynamic Topic
Models, Correlated Topic Models, Hierarchical Topic Models, and more
recently, Structural Topic Modeling (STM). He argues that one reason STM
has rising in popularity and use is that it employs meta data about
documents to improve the assignment of words to topics in a corpus and
that can be used to examine relationships between covariates and
documents.
Also, since Julia Silge has indicated that STM is, “my current
favorite implementation of topic modeling in R” and has built supports
in the tidytext package for building structural topic
models, this package definitely is worth discussing in this walkthrough.
I also highly recommend her own walkthrough of the stm
package: The
game is afoot! Topic modeling of Sherlock Holmes stories as well as
her follow up post, Training, evaluating,
and interpreting topic models.
The stm Package
As we’ve seen above, STM produced an unusual temp
textProcessor output that is unique to the stm package. And
as you’ve probably already guessed, the stm() function for
fitting a structural topic model does not take a fairly standard
document term matrix like the LDA() function.
Before we fit our model, we’ll have to extract the elements from the
temp object created after we processed our text.
Specifically, the stm() function expects the following
arguments:
documents = the document term matrix to be modeled in
the native stm format
data = an optional data frame containing meta data for
the prevalence and/or content covariates to include in the model
vocab = a character vector specifying the words in the
corpus in the order of the vocab indices in documents.
Let’s go ahead and extract these elements:
docs <- temp$documents
meta <- temp$meta
vocab <- temp$vocab
And now use these elements to fit the model using the same number of
topics for K that we specified for our LDA topic model. Let’s
also take advantage of the fact that we can include the
course_id and forum_id covariates in the
prevealence = argument to help improve, in theory, our
model fit:
forums_stm <- stm(documents=docs,
data=meta,
vocab=vocab,
prevalence =~ course_id + forum_id,
K=20,
max.em.its=25,
verbose = FALSE)
forums_stm
## A topic model with 20 topics, 5781 documents and a 7820 word dictionary.
As noted earlier, the stm package has a number of handy
features. One of these is the plot.STM() function for
viewing the most probable words assigned to each topic.
By default, it only shows the first 3 terms so let’s change that to 5
to help with interpretation:
plot.STM(forums_stm, n = 5)

Note that you can also just use plot() as well:
plot(forums_stm, n = 5)

✅ Comprehension Check
Fit a model for both LDA and STM using different values for K and
answer the following questions:
- What topics appear to be similar to those using 20 topics for
K?
- Knowing that you don’t have as much context as the researchers of
this study do, how might you interpret one of these latent topics or
themes using the key terms assigned?
- What topic emerged that seem dramatically different and how might
you interpret this topic?
3c. Finding K
As alluded to earlier, selecting the number of topics for your model
is a non-trivial decision and can dramatically impact your results. Bail
(2018) notes that
The results of topic models should not be over-interpreted unless
the researcher has strong theoretical apriori about the number of topics
in a given corpus, or if the researcher has carefully validated the
results of a topic model using both the quantitative and qualitative
techniques described above.
There are several approaches to estimating a value for K and we’ll
take a quick look at one from the ldatuning package and one
from our stm package.
The FindTopicsNumber Function
The ldatuning package has functions for both calculating
and plotting different metrics that can be used to estimate the most
preferable number of topics for LDA model. It also conveniently takes
the standard document term matrix object that we created from out tidy
text and has the added benefit of running fairly quickly, especially
compared to the function for finding K from the stm
package.
Let’s use the defaults specified in the ?FindTopicNumber
documentation and modify slightly get metrics for a sequence of topics
from 10-75 counting by 5 and plot the output we saved using the
FindTopicsNumber_plot() function:
k_metrics <- FindTopicsNumber(
forums_dtm,
topics = seq(10, 75, by = 5),
metrics = "Griffiths2004",
method = "Gibbs",
control = list(),
mc.cores = NA,
return_models = FALSE,
verbose = FALSE,
libpath = NULL
)
FindTopicsNumber_plot(k_metrics)
Note that the FindTopicNumbers() function contains three
additional metrics for calculating metrics that can be used to estimate
the most preferable number of topics for LDA model. We used the
Griffiths2004 metrics included in the default example and I’ve also
found this to produce the most interpretable results as show in the
figure below:

As a general rule of thumb and overly simplistic heuristic, we’re
looking for an inflection point in our plot which indicates an optimal
number of topics to select for a value of K.
The findingK() Function
Finally, Bail (2018) notes that thestm package has a
useful function called searchK which allows us to specify a
range of values for k and outputs multiple goodness-of-fit
measures that are “very useful in identifying a range of values for
k that provide the best fit for the data.”
The syntax of this function is very similar to the stm()
function we used above, except that we specify a range for
k as one of the arguments. In the code below, we search all
values of k between 10 and 30.
#I am not expecting you run this code as it will take too long
#findingk <- searchK(docs,
#vocab,
#K = c(5:15),
#data = meta,
#verbose=FALSE)
#plot(findingk)
Note that Running searchK() function on this corpus took
all night on a pretty powerful MacBook Pro and crashed once as well, so
I do not expect you to run this for the walkthrough. I ran a couple
iterations and landed on between 5 and 15 with an optimal number of
topics somewhere around 14:

Given the somewhat conflicting results, also somewhat selfishly and
for the same of simplicity for this walkthrough, I’m just going to stick
with the rather arbitrary selection of 20 topics for the remainder of
this Unit.
The LDAvis Explorer
One final tool that I want to introduce from the stm
package is the toLDAvis() function which provides a great
visualizations for exploring topic and word distributions using
LDAvis topic browser:
toLDAvis(mod = forums_stm, docs = docs)
## Loading required namespace: servr
As you can see from the browser screen shot below, our current stm
model of 20 topics is resulting in a lot of overlap among topics and
suggest that 20 may not be an optimal number of topics, as other
approaches for finding k also suggests:

4. EXPLORE
Silge and Robinson (2018) note that fitting at topic model is the
“easy part.” The hard part is making sense of the model results and that
the rest of the analysis involves exploring and interpreting the model
using a variety of approaches which we’ll walkthrough in in this
section.
Bail (2018) cautions, however, that:
…post-hoc interpretation of topic models is rather dangerous… and
can quickly come to resemble the process of “reading tea leaves,” or
finding meaning in patterns that are in fact quite arbitrary or even
random.
4a. Exploring Beta Values
Hidden within this forums_lda topic model object we
created are per-topic-per-word probabilities, called β (“beta”). It is
the probability of a term (word) belonging to a topic.
Let’s take a look at the 5 most likely terms assigned to each topic,
i.e. those with the largest β values using the terms()
function from the topicmodels package:
terms(forums_lda, 5)
## Topic 1 Topic 2 Topic 3 Topic 4 Topic 5 Topic 6
## [1,] "dice" "resources" "students" "statistics" "tv" "stats"
## [2,] "trials" "statistics" "kids" "math" "age" "students"
## [3,] "fair" "teaching" "understand" "mathematics" "coasters" "statistics"
## [4,] "sasi" "unit" "standard" "students" "roller" "class"
## [5,] "level" "mooc" "test" "common" "steel" "ap"
## Topic 7 Topic 8 Topic 9 Topic 10 Topic 11 Topic 12
## [1,] "students" "gapminder" "students" "li" "td" "students"
## [2,] "school" "students" "software" "strong" "difference" "time"
## [3,] "statistics" "td" "technology" "href" "class" "technology"
## [4,] "questions" "love" "reading" "https" "1" "school"
## [5,] "middle" "videos" "statistical" "target" "5" "video"
## Topic 13 Topic 14 Topic 15 Topic 16 Topic 17 Topic 18
## [1,] "questions" "students" "data" "font" "task" "students"
## [2,] "students" "data" "students" "normal" "students" "sample"
## [3,] "question" "real" "questions" "text" "data" "results"
## [4,] "answer" "agree" "set" "0px" "tasks" "size"
## [5,] "answers" "activity" "collecting" "51" "mind" "data"
## Topic 19 Topic 20
## [1,] "div" "span"
## [2,] "http" "style"
## [3,] "href" "height"
## [4,] "https" "font"
## [5,] "target" "0"
Even though we’ve somewhat arbitrarily selected the number of topics
for our corpus, some these topics or themes are fairly intuitive to
interpret. For example:
Topic 11 (technology, students, software, program, excel) seems
to be about students use of technology including software programs like
excel;
Topic 9 (questions, kids, love, gapminder, sharing) seems to be
about the gapminder activity from the MOOC-Ed and kids enjoyment of it;
and
Topic 18 (data, students, collect, real, sets) seems to be about
student collection and use of real world data sets.
Not surprisingly, the tidytext package has a handy
function conveniently name tidy() to convert our lda model
to a tidy data frame containing these beta values for each term:
tidy_lda <- tidy(forums_lda)
tidy_lda
## # A tibble: 272,400 × 3
## topic term beta
## <int> <chr> <dbl>
## 1 1 2015 4.61e-227
## 2 2 2015 7.61e- 4
## 3 3 2015 3.00e- 4
## 4 4 2015 3.92e- 4
## 5 5 2015 3.05e- 4
## 6 6 2015 8.31e- 18
## 7 7 2015 2.68e- 59
## 8 8 2015 1.81e- 40
## 9 9 2015 9.99e- 33
## 10 10 2015 7.09e- 5
## # … with 272,390 more rows
Obviously, it’s not very easy to interpret what the topics are about
from a data frame like this so let’s borrow code again from Chapter
8.4.3 Interpreting the topic model in Text Mining with R to examine
the top 5 terms for each topic and then look at this information
visually:
top_terms <- tidy_lda %>%
group_by(topic) %>%
slice_max(beta, n = 5, with_ties = FALSE) %>%
ungroup() %>%
arrange(topic, -beta)
top_terms %>%
mutate(term = reorder_within(term, beta, topic)) %>%
group_by(topic, term) %>%
arrange(desc(beta)) %>%
ungroup() %>%
ggplot(aes(beta, term, fill = as.factor(topic))) +
geom_col(show.legend = FALSE) +
scale_y_reordered() +
labs(title = "Top 5 terms in each LDA topic",
x = expression(beta), y = NULL) +
facet_wrap(~ topic, ncol = 4, scales = "free")

4b. Exploring Gamma Values
Now that we have a sense of the most common words associated with
each topic, let’s take a look at the topic prevalence in our MOOC-Ed
discussion forum corpus, including the words that contribute to each
topic we examined above.
Also, hidden within our forums_lda topic model object we
created are per-document-per-topic probabilities, called γ (“gamma”).
This provides the probabilities that each document is generated from
each topic, that gamma matrix. We can combine our beta and gamma values
to understand the topic prevalence in our corpus, and which words
contribute to each topic.
To do this, we’re going to borrow some code from the Silge (2018)
post, Training,
evaluating, and interpreting topic models.
First, let’s create two tidy data frames for our beta and gamma
values
td_beta <- tidy(forums_lda)
td_gamma <- tidy(forums_lda, matrix = "gamma")
td_beta
## # A tibble: 272,400 × 3
## topic term beta
## <int> <chr> <dbl>
## 1 1 2015 4.61e-227
## 2 2 2015 7.61e- 4
## 3 3 2015 3.00e- 4
## 4 4 2015 3.92e- 4
## 5 5 2015 3.05e- 4
## 6 6 2015 8.31e- 18
## 7 7 2015 2.68e- 59
## 8 8 2015 1.81e- 40
## 9 9 2015 9.99e- 33
## 10 10 2015 7.09e- 5
## # … with 272,390 more rows
td_gamma
## # A tibble: 115,320 × 3
## document topic gamma
## <chr> <int> <dbl>
## 1 11295 1 0.00185
## 2 12711 1 0.000233
## 3 12725 1 0.0254
## 4 12733 1 0.00216
## 5 12743 1 0.00737
## 6 12744 1 0.00369
## 7 12756 1 0.0254
## 8 12757 1 0.00272
## 9 12775 1 0.00272
## 10 12816 1 0.00272
## # … with 115,310 more rows
Next, we’ll adopt Julia’s code wholesale to create a filtered data
frame of our top_terms, join this to a new data frame for
gamma-terms and create a nice clean table using the
kabel() function knitr package:
top_terms <- td_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()
## Warning: `cols` is now required when using `unnest()`.
## ℹ Please use `cols = c(terms)`.
gamma_terms <- td_gamma %>%
group_by(topic) %>%
summarise(gamma = mean(gamma)) %>%
arrange(desc(gamma)) %>%
left_join(top_terms, by = "topic") %>%
mutate(topic = paste0("Topic ", topic),
topic = reorder(topic, gamma))
gamma_terms %>%
select(topic, gamma, terms) %>%
kable(digits = 3,
col.names = c("Topic", "Expected topic proportion", "Top 7 terms"))
| Topic 7 |
0.098 |
students, school, statistics, questions, middle, level,
understanding |
| Topic 6 |
0.086 |
stats, students, statistics, class, ap, teach,
school |
| Topic 2 |
0.086 |
resources, statistics, teaching, unit, mooc, ideas,
learning |
| Topic 14 |
0.083 |
students, data, real, agree, activity, time,
analyze |
| Topic 13 |
0.068 |
questions, students, question, answer, answers,
correct, results |
| Topic 15 |
0.064 |
data, students, questions, set, collecting, collection,
question |
| Topic 8 |
0.063 |
gapminder, students, td, love, videos, tool, top |
| Topic 4 |
0.057 |
statistics, math, mathematics, students, common,
teaching, core |
| Topic 17 |
0.056 |
task, students, data, tasks, mind, activity,
question |
| Topic 18 |
0.050 |
students, sample, results, size, data, simulation,
statistical |
| Topic 9 |
0.048 |
students, software, technology, reading, statistical,
calculator, learn |
| Topic 12 |
0.047 |
students, time, technology, school, video, data,
student |
| Topic 3 |
0.043 |
students, kids, understand, standard, test, box,
deviation |
| Topic 19 |
0.028 |
div, http, href, https, target, _blank, class |
| Topic 11 |
0.027 |
td, difference, class, 1, 5, 2, align |
| Topic 10 |
0.026 |
li, strong, href, https, target, _blank,
statistics |
| Topic 1 |
0.019 |
dice, trials, fair, sasi, level, framework,
sophistication |
| Topic 16 |
0.018 |
font, normal, text, 0px, 51, 255, style |
| Topic 5 |
0.018 |
tv, age, coasters, roller, steel, coaster, hours |
| Topic 20 |
0.013 |
span, style, height, font, 0, line, margin |
And let’s also compare this to the most prevalent topics and terms
from our forums_stm model that we created using the
plot() function:
plot(forums_stm, n = 7)

4c. Reading the Tea Leaves
Recognizing that topic modeling is best used as a “tool for reading”
and provides only an incomplete answer to our overarching, “How
do we quantify what a corpus is about?”, the results do suggest
some potential topics that have emerges as well as some areas worth
following up on.
Specifically, looking at some of the common clusters of words for the
more prevalent topics suggest that some key topics or “latent themes”
(renamed in bold) might include:
- Teaching Statistics: Unsurprising, given the course
title, the topics most prevalent in both the
forums_stm and
forums_lda models contains the terms “teach”, “students”,
“statistics”. This could be an “overarching theme” but more likely may
simply be just the residue of the course title though being sprinkled
throughout the forums and deserves some follow up. Topics 8 from the LDA
model may overlap with this topic as well.
- Course Utility: The second most prevalent Topics
(13 and 2) in the
lda and stm models
respectively, seem to potentially be about the usefulness of course
“resources” like lessons, tools, videos, and activities. I’m wagering
this might be a forum dedicated to course feedback. Topic 15 from the
STM model also suggest this may be a broader theme.
- Using Real-World Data: Topics 18 & 12 from the
LDA model particularly intrigue me and I’m wagering this is pretty
positive sentiment among participants about the value and benefit of
having students collect and analyze real data sets (e.g. Census data in
Topic 1) and work on projects relevant to their real life. Will
definitely follow up on this one.
- Technology Use: Several topics (6 & 11 from LDA
and 8 & 19 from STM) appear to be about student use of technology
and software like calculators and Excel for teaching statistics and
using simulations. Topic 16 from LDA also suggest the use of the Common
Online Data Analysis Platform (CODAP).
- Student Struggle & Engagement: Topic 15 from
LDA and Topic 16 from STM also intrigue me and appear to be two opposite
sides of perhaps the same coin. The former includes “struggle” and
“reading” which suggests perhaps a barrier to teaching statistics while
Topic 16 contains top stems like “engage”, “activ”, and “think” and may
suggest participants anticipate activities may engage students.
To serve as a check on my tea leaf reading, I’m going to follow
Bail’s recommendation to examine some of these topics qualitatively. The
stm package has another useful function though
exceptionally fussy function called findThoughts which
extracts passages from documents within the corpus associate with topics
that you specify.
The first line of code may not be necessary for your independent
analysis, but because the textProcessor() function removed
several documents during processing, the findthoughts()
function can’t properly index the processed docs. This line
of code found on stackoverflow removes documents from original
ts_forum_data source that were removed during processing so
there is a one-to-one correspondence with forums_stm and so
you can use the function to find posts associated with a given
topic.
Let’s slightly reduce our original data set to match our STM model,
pass both to the findThoughts() function, and set our
arguments to return n =10 posts from
topics = 2 (i.e. Topic 2) that have at least 50% or
thresh = 0.5 as a minimum threshold for the estimated topic
proportion.
ts_forum_data_reduced <-ts_forum_data$post_content[-temp$docs.removed]
findThoughts(forums_stm,
texts = ts_forum_data_reduced,
topics = 2,
n = 10,
thresh = 0.5)
##
## Topic 2:
## Here is a cool video with Hans Rosling using Gapminder. It's pretty cool. https://www.youtube.com/watch?v=jbkSRLYSojo
## Thank you for sharing the link!!! I think that this is the document that Chris mentions co-writing and being ready for NCTM's National Conference in San Francisco this April. :-)
## Yes thank you! The site was an excellent resource especially for someone like myself who is new to this stuff!
## I've never heard of FiveThirtyEight could you tell me more about the resource? Thanks! Carisa
## QELP looks so cool! Thanks for sharing!
## Thanks for letting us know about this TED talk! I watched the one about Ignorance and found Hans Rosling so entertaining that I ended up finding other TED talks he has done and watched them for way too long last night.
## Wow! I totally agree with you. The Gapminder was great. Also I was inspired to complete this unit as well. I did not know there was a TedTalk about this. I will have to check it out.
## Wow! I totally agree with you. The Gapminder was great. Also I was inspired to complete this unit as well. I did not know there was a TedTalk about this. I will have to check it out.
## I love your idea of using this as a STEM night project. Thank you for the thought...I will have to steal it :) Eren
## Hi Regina I really like the gapminder site. There are some great video on the gapminder site that I have used in my courses. Hans Rosling founder of gapminder also has some really great TED talks. Sadly he passed away this year. My interests have been peaked by the Locus site. I think there is a lot of potential there for use in my classroom too. Good luck! Shar
Duplicate posts aside, this Course Utility topic
returns posts there were expected based on my interpretation of the key
terms for Topic 2. It looks like I may have read those tea leaves
correctly.
Now let’s take a look at Topic 16 that we thought might be related to
student engagement:
findThoughts(forums_stm,
texts = ts_forum_data_reduced,
topics = 16,
n = 10,
thresh = 0.5)
##
## Topic 16:
## Hi Folks One of the discussions that needs to occur when studying the travel time of walking vs. driving by car vs riding on a school bus is the number of stops the bus must make in order to pick up students. One of my previous careers was that of a school bus driver. At each stop I was required to stop the bus put on the flashing lights put on the emergency brake look through all of the mirrors to determine all of the cars had stopped open the bus door then pick up the microphone (which could be heard inside and outside of the bus) to tell the students it was now safe to cross the road and enter the bus. After waiting for all students to get on the bus and take a seat and for the bus monitor to check under the bus and get on the bus again; I would then close the bus door and take off the emergency brake. Next I would check all of my mirrors to make sure it was safe pull completely back into the lane of travel and continue on my bus route. All of these actions increased the amount of time it took to get to school. What is the purpose of this investigation? I would want to know if the students with the longer travel time to and from school are impacted by the amount of time spent traveling each day. What are the grades of the students with the longest travel time how do those grades compare to students with the least travel time? What behaviors are exhibited by students in school who spend the most time traveling to and from school? Are they more likely to exhibit behaviors that result in disciplinary referrals? Does travel time negatively impact the academic and behavioral performance of these students in school? On the flip slide does longer travel time provide the opportunity for students to engage in preferred activities of talking to their friends on the bus or engaging in their electronic device to listen to music or play games and does this provide a beginning and end of the day relaxation experience for the students. Do these students have better grades and less disciplinary referrals?
## This is a great activity and can have so many variations. It doesn't have to be Pepsi vs. Coke if you don't have a lot of pop drinkers in class. You can do a name brand vs. generic orange juice or even a taste test with chips or cookies (perhaps blind folds would be necessary for food tasting). I also think one of the best follow-up discussions is about how many students actually prefer what they claim to prefer. Having the preference beforehand definitely enriches the discussions.
## I agree and oftentimes do a blindfolded taste test with name brand Oreo cookies and then a store brand cookie. I follow a similar method as the Coke vs. Pepsi one but tweak it a bit for AP Statistics. It is fun to see the looks on kids faces when they \choose\" the generic Oreo because they are just so sure they knew the Oreo! Every time I've done this experiment there seems to be no clear evidence students prefer Oreos :) "
## We do which is different out of three as well we also have 6 different combinations and randomly assign students to the combinations (ex coke Pepsi pepsi c p c coke coke pepsi etc)
## My colleagues have commented on the Pepsi versus Coke activity. I also commented in there but liked to expand the concept further. When students are involved in an activity they make it there own and really would make it worth their while. Hence when they actually made the data happen being instrumental in not only choosing which brand to anonymously be named and tasted to collating the results the students learn how to make data collection impartial objective and representative. Also they see the process of good data collection by the randomness it was done such that whatever result would really represent a preference for a brand without any prior bias. So the students learn to collect and collate data and results in as objective and unbiased manner such that results are untainted and would truly represent a true preference and not a directed preference through a prior bias. Though it would take a lot of time yet the lessons learned on how data is done and collected and collated was worth its while in the lesson it has rendered.
## I have used a similar task comparing bottled water versus tap water or two brands/types of bottled water and it worked pretty well. Sometimes it was interesting to see where students could not tell the difference between tap water and bottled water.
## I have done this one as well and it went great. Another version I do is name brand and store brand cookies. Fudge stripes or chips a hoy cookies work great.
## I have done this one in class with approximately 20 students. Instead of picking which is which I ask which one is different out of three samples. We design the experiment together and talk about the random assignment of the odd ball drink in which cup consistency in pouring color smell how to blind the experiment ect. We then look at our data and compare it to a simulation to see if we have more \skill\" than randomly guessing. This helps create a smoother transition between simulations and experiments. I have also used different drinks most recently blue Gatorade vs Blue Powerade. Smell and color were factors we had trouble controlling. "
## I've seen bottled water vs. tap water too
## Hi Erik When I was in school we did a similar activity except that we used regular bags of M&Ms to determine which color is the most common for M&M's. Using skittles would be similar. You could also extend this to see if the type of M&M changes the predominant color - plain vs. peanut vs. ? (there are so many varieties now!).
It looks like my tea reading was a partially correct for Topic 16,
though the results seem to be about a specific “Pepsi challenge”
activity to conduct with students.
Finally, let’s look at posts from Topic 3 which we though might be an
overarching theme about teaching statistics:
ts_forum_data_reduced <-ts_forum_data$post_content[-temp$docs.removed]
findThoughts(forums_stm,
texts = ts_forum_data_reduced,
topics = 3,
n = 10,
thresh = 0.5)
##
## Topic 3:
## I really like the \Gummy Bears in Space\" activity and I can think of different ways to incorporate this into my 7th grade classroom. I think this would be a great hands on activity to get a STEM or science teacher involved to integrate different subjects into a lesson. "
## I agree about them working together. I never have students work independently on these sorts of tasks. It is a richer experience when the conversations can occur about the work being done.
## Motivating the students to be interested to learn the material is a big push for me this year. As others stated we as teachers have to be motivated in order for our students to be motivated. I spend a lot of time trying to make my lessons fun and interactive because I know if the students are engaged they will take away more. Some topics are easier than others. Just like it's easier to incorporate real world situations with some topics and not others. I have discovered that once I got the mindset of making them interesting more students was becoming successful on the lesson.
## I agree also that listening is beneficial for both students and teachers. The students can hear samples of mathematical/statistical thinking going on...like a \think aloud.\" We need to continually model the thinking process for them and these videos help to show the progression of thinking. It is also helpful for us as teachers to see the directions that student minds are going so that we can encourage them to make even more progress by taking their thinking to the next level. "
## Oh yeah. Without a doubt the introduction of the SASI framework was the most useful part of the MOOC for me too. I will definitely be administering this framework in my Statistics classes until it becomes second nature for my students that every time they're thinking about anything statistically significant that they consider the framework in mind.
## I agree that the framework is very useful and I would also like to see lessons created that specifically address each aspect of the framework. These lessons would be used to develop a strong expertise with each aspect using a whole-part-whole instructional method. Teach the SASI framework as a whole then break it down into the 4 parts and practice those skills then go back to completing a whole project. The quality of student work may improve with this teaching progression.
## I also really loved the gummy bear activity idea. I think that my third graders would also really enjoy an activity like this although they would probably eat the gummy bears. I think it would be a great way for them to get more involved in the lesson.
## I agree with the point you made Drew. The discussions made it feel like you were connected with other people and it gave us different ways to look at the particular subject. It gave someone like me who isn't as experienced in statistics viewpoints and thinking strategies from people who are \experts\" in the field. "
## I really like the war game activity. It is a game that your student are probably going to know how to play already which should help you when explaining. Also it can really get your students up and going and you will see the competitiveness really kick in with your students. I also like the discussion part you have with it as well because in reality who really knows which deck of cards is going to be the best to pick from so this makes a great topic for discussion and it would be interesting to see what all of your students say. Overall I would have to say you did a great job with your project here. The only way I can see for adjustments though would be after you do your activities the first time because you really don't know how things are going to work out until you actually try them yourself.
## I don't know that it is fair to say that they don't want to think and are just looking for formulas. I think in the past this has been their experience though and so they want to fall back on what they know. Hopefully MOOCs like this as well as the common core curriculum should be driving the \thinking\" end of things a little more than ever before. I know I have already started to see a difference in the thinking skills of my students if not their math skills and this is a exciting for my future as a math educator. The experts in the video talk about how collecting and analyzing real world data is engaging for kids because it isn't a worksheet that is disconnected from their lives. I think this engagement necessarily forces them to think which is way more fun than being a formula robot. Anecdotally my brother woke me up this week with an interesting geometry problem that made me think about circles in a new way and it was really exciting. Granted as a math teacher I'm probably to the point where I can be excited about thinking about weird problems but I know that balancing my budget is significantly less exciting that solving weird problems that make me think. Lon story short- I think if we are engaging students with interesting problems they will be practicing thinking skills if we drive class discussions with metacognition they will be practicing thinking skills if we have students pose their own problems that are relevant to their lives they will be practicing thinking skills. If we can make a nation of critical thinkers and problem solvers there should be no limit to what we can accomplish. "
Looking at just the 10 posts returned, perhaps a better name for this
topic would be Course Reflections on Teaching
Statistics.
Unit Takeaway
In addition to some useful R packages and functions for the actual
process of topic modeling, hopefully there are two main lessons I’m
hoping you take away from this walkthrough:
- Topic modeling requires a lot of decisions. Beyond
deciding on a value for K, there are a number of key decisions that you
have to make that can dramatically affect your results. For example, to
stem or not to stem? What qualifies as a document? What flavor or topic
modeling is best suited to your data and research questions? How many
iterations to run?
- Topic modeling is as much art as (data) science. As
Bail (2018) noted, the term “topic” is somewhat ambitious, and topic
models do not produce highly nuanced classification of texts. Once
you’ve fit your model, interpreting your model requires some mental
gymnastics and ideally some knowledge of the context from which the data
came to help with interpretation of your topics. Moreover, the
quantitative approaches for making the decisions highlighted above are
imperfect and a good deal of human judgment required.
✅ Comprehension Check
Using the STM model you fit from the Section 3 [Comprehension Check]
with a different value for K, use the approaches demonstrated in Section
4 to explore and interpret your topics and terms and revisit the
following question:
- Now that you have a little more context, how might you revise your
initial interpretation of some of the latent topics or latent themes
from your model?
LS0tCnRpdGxlOiAiVW5pdCAzIFdhbGt0aHJvdWdoOiBUb3BpYyBNb2RlbGluZyBpbiBNT09DLUVkcyIKb3V0cHV0OiAKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDMKICAgIHRvY19mbG9hdDogeWVzCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIGNvZGVfZG93bmxvYWQ6IFRSVUUKZWRpdG9yX29wdGlvbnM6IAogIG1hcmtkb3duOiAKICAgIHdyYXA6IDcyCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKYGBgCgojIyAwLiBJTlRST0RVQ1RJT04KClRoZSBVbml0IDMgd2Fsa3Rocm91Z2ggZXh0ZW5kcyBwcmV2aW91cyByZXNlYXJjaCBhbmQgZXZhbHVhdGlvbiB3b3JrIGF0CnRoZSBGcmlkYXkgSW5zdGl0dXRlIGZvciBFZHVjYXRpb25hbCBJbm5vdmF0aW9uIGF0IE5vcnRoIENhcm9saW5hIFN0YXRlClVuaXZlcnNpdHkuIEluIGFkZGl0aW9uIHRvIG1hbnkgb3RoZXIgYXJlYXMgb2YgaW5xdWlyeSwgdGhpcyB3b3JrIHdhcwphaW1lZCBhdCB1bmRlcnN0YW5kaW5nIGFuZCBpbXByb3ZpbmcgcGVlciBpbnRlcmFjdGlvbiBhbmQgZGlzY3Vzc2lvbiBpbgp0aGUgRnJpZGF5IEluc3RpdHV0ZSdzIE1hc3NpdmVseSBPcGVuIE9ubGluZSBDb3Vyc2VzIGZvciBFZHVjYXRvcnMKKE1PT0MtRWQpIGFuZCBPbmxpbmUgUHJvZmVzc2lvbmFsIExlYXJuaW5nIHByb2dyYW1zLiBUbyBsZWFybiBtb3JlIGFib3V0CnRoZXNlIGNvdXJzZXMgYW5kIHByb2dyYW1zLCB2aXNpdDogPGh0dHBzOi8vcGxhY2UuZmkubmNzdS5lZHU+CgojIyMgV2Fsa3Rocm91Z2ggRm9jdXMKCk91ciBmb2N1cyB0aGlzIHdlZWsgd2lsbCBiZSBvbiBpZGVudGlmeWluZyAidG9waWNzIiBieSBleGFtaW5pbmcgaG93CndvcmRzIGNvaGVyZSBpbnRvIGRpZmZlcmVudCBsYXRlbnQsIG9yIGhpZGRlbiwgdGhlbWVzIGJhc2VkIG9uIHBhdHRlcm5zCm9mIGNvLW9jY3VycmVuY2Ugb2Ygd29yZHMgd2l0aGluIGRvY3VtZW50cy4gV2l0aCBhIGJpdCBvZgp0b25ndWUtaW4tY2hlZWsswqBbTWVla3MgYW5kIFdlaW5nYXJ0CigyMDEyKV0oaHR0cDovL2pvdXJuYWxvZmRpZ2l0YWxodW1hbml0aWVzLm9yZy8yLTEvZGgtY29udHJpYnV0aW9uLXRvLXRvcGljLW1vZGVsaW5nLynCoGRlc2NyaWJlCnRvcGljIG1vZGVsaW5nIGFzOsKgCgo+ICouLi5mb2N1c2VkIG9uIGNvcnBvcmEgYW5kIG5vdCBpbmRpdmlkdWFsIHRleHRzLCB0cmVhdGluZyB0aGUgd29ya3MKPiB0aGVtc2VsdmVzIGFzIHVuY2VyZW1vbmlvdXMgJ2J1Y2tldHMgb2Ygd29yZHMsJyBhbmQgcHJvdmlkaW5nCj4gc2VkdWN0aXZlIGJ1dCBvYnNjdXJlIHJlc3VsdHMgaW4gdGhlIGZvcm1zIG9mIGVhc2lseSBpbnRlcnByZXRlZCAoYW5kCj4gbWFuaXB1bGF0ZWQpICd0b3BpY3MnLi4uLiBUbyBhY2hpZXZlIGl0cyByZXN1bHRzLCBpdCBsZXZlcmFnZXMgb2NjdWx0Cj4gc3RhdGlzdGljYWwgbWV0aG9kcyBsaWtlICdkaXJpY2hsZXQgcHJpb3JzJyBhbmQgJ2JheWVzaWFuIG1vZGVscy4nKgoKVGhhdCBiZWluZyBzYWlkLApbV2VpbmdhcnRdKGh0dHA6Ly9qb3VybmFsb2ZkaWdpdGFsaHVtYW5pdGllcy5vcmcvMi0xL2RoLWNvbnRyaWJ1dGlvbi10by10b3BpYy1tb2RlbGluZy8pCmFsc28gbm90ZWQgdGhhdCAiYSB0b3BpYyBtb2RlbCBpcyBhImNsZXZlciBhbmQgZXhjZXB0aW9uYWxseSB2ZXJzYXRpbGUKbGl0dGxlIGFsZ29yaXRobSB0aGF0IGNhbiBiZSBjdXN0b21pemVkIHRvIGFsbCBzb3J0cyBvZiBhcHBsaWNhdGlvbnMiCmFuZCBbQmFpbAooMjAyMCldKGh0dHBzOi8vc2ljc3MuaW8vMjAyMC9tYXRlcmlhbHMvZGF5My10ZXh0LWFuYWx5c2lzL3RvcGljLW1vZGVsaW5nL3JtYXJrZG93bi9Ub3BpY19Nb2RlbGluZy5odG1sI3J1bm5pbmcteW91ci1maXJzdC10b3BpYy1tb2RlbCkKYWRkIHRoYXQgdG9waWMgbW9kZWxpbmcgY2FuIGJlICJhIHBvd2VyZnVsIHRvb2wgZm9yIGlkZW50aWZ5aW5nIGdlbmVyYWwKdHJlbmRzIGluIGEgY29ycHVzIHRoYXQgY2FuIHRoZW4gYmUgYW5hbHl6ZWQgaW4gYSBtb3JlIGdyYW51bGFyIG1hbm5lcgp1c2luZyBvdGhlciB0ZWNobmlxdWVzLiIKCldpdGggcmVzcGVjdCB0byB0aGUgYWN0dWFsIFIgd29ya2Zsb3cgb2YgYXBwbHlpbmcgdG9waWMgbW9kZWxzIHRvCmRvY3VtZW50cyBhbmQgdGV4dCBvZiBpbnRlcmVzdHMsIFNpbGdlICYgUm9iaW5zb24gYW5kIGEgbmV3IGJvdHRvbSByb3cKdGhlaXIgZmxvd2NoYXJ0IGNvbnNpc3RpbmcgbmV3IGRhdGEgc3RydWN0dXJlcyAoaS5lLiwgYSBjb3JwdXMgb2JqZWN0CmFuZCBkb2N1bWVudC10ZXJtIG1hdHJpeCkgYW5kIGFuZCB0aGUgTERBIG1vZGVsOiDCoAoKWyFbRmlndXJlwqBzb3VyY2U6wqBTaWxnZSzCoEouLMKgJsKgUm9iaW5zb24swqBELsKgKDIwMTcpLsKgVGV4dMKgbWluaW5nwqB3aXRowqBSOsKgQcKgdGlkecKgYXBwcm9hY2guwqBPJ1JlaWxsecKgTWVkaWEswqBJbmMuClJldHJpZXZlZCBmcm9tOgpodHRwczovL3d3dy50aWR5dGV4dG1pbmluZy5jb20vdG9waWNtb2RlbGluZy5odG1sXShpbWcvdG1fZmxvdy5wbmcgIkEgZmxvd2NoYXJ0IG9mIGEgdGV4dCBhbmFseXNpcyB0aGF0IGluY29ycG9yYXRlcyB0b3BpYyBtb2RlbGluZy4gVGhlIHRvcGljbW9kZWxzIHBhY2thZ2UgdGFrZXMgYSBEb2N1bWVudC1UZXJtIE1hdHJpeCBhcyBpbnB1dCBhbmQgcHJvZHVjZXMgYSBtb2RlbCB0aGF0IGNhbiBiZSB0aWRlZCBieSB0aWR5dGV4dCwgc3VjaCB0aGF0IGl0IGNhbiBiZSBtYW5pcHVsYXRlZCBhbmQgdmlzdWFsaXplZCB3aXRoIGRwbHlyIGFuZCBnZ3Bsb3QyLiIpe3dpZHRoPSI5MCUifV0oaHR0cHM6Ly93d3cudGlkeXRleHRtaW5pbmcuY29tL3RvcGljbW9kZWxpbmcuaHRtbCkKClRoaXMgd2VlayB3aWxsIGJlIGFsc28gYmUgb3VyIGZpcnN0IGludHJvZHVjdGlvbiB0byB0aGUgIk1vZGVsIiBwcm9jZXNzCm9mIHRoZSBkYXRhLWludGVuc2l2ZSB3b3JrZmxvdyBkZXNjcmliZWQgaW4gb3VyIGNvdXJzZSB0ZXh0LCBbKkxlYXJuaW5nCkFuYWx5dGljcyBHb2VzIHRvClNjaG9vbCpdKGh0dHBzOi8vY2F0YWxvZy5saWIubmNzdS5lZHUvY2F0YWxvZy9OQ1NVNDg2MjEzNCkqLiogQXMgbm90ZWQKYnkgS3J1bW0gYW5kIE1lYW5zICgyMDE4KSwgdGhpcyB3b3JrZmxvdyBpcyBub3QgYWx3YXlzIGEgbGluZWFyIHByb2Nlc3MKYW5kIHRoZXJlIGlzIG9mdGVuIGEgZ3JlYXQgZGVhbCBvZiBpdGVyYXRpb24gdGhhdCBvY2N1cnMgd2l0aGluIGFuZApiZXR3ZWVuIHdyYW5nbGluZywgZXhwbG9yaW5nLCBtb2RlbGluZy4gQXMgaWxsdXN0cmF0ZWQgYnkgb3VyIHdvcmtmbG93CmJlbG93LCB0aGlzIHdlZWsgd2Ugd2lsbCBwcmltYXJpbHkgZXhwbG9yZSBvdXIgZGF0YSBhZnRlciB0aGUgbW9kZWxpbmcKcHJvY2VzcyBpbiBvcmRlciB0byBnYWluIHNvbWUgYWRkaXRpb25hbCBpbnNpZ2h0IGludG8gdGhlIHRvcGljcwpnZW5lcmF0ZWQgYnkgb3VyIG1vZGVsLiBTcGVjaWZpY2FsbHksIHRoaXMgd2VlayBjb3ZlcnMgdGhlIGZvbGxvd2luZwpjb25jZXB0cyBhbmQgc2tpbGxzOgoKMS4gICoqUHJlcGFyZSoqOiBQcmlvciB0byBhbmFseXNpcywgd2UnbGwgdGFrZSBhIHF1aWNrIGxvb2sgYXQgc29tZSBvZgogICAgdGhlIHJlbGF0ZWQgTU9PQy1FZCByZXNlYXJjaCBhbmQgZXZhbHVhdGlvbiB3b3JrIHRvIGdhaW4gc29tZQogICAgY29udGV4dCBmb3Igb3VyIGFuYWx5c2lzLiBUaGlzIHNob3VsZCBhaWQgaW4gdGhlIGludGVycHJldGF0aW9uIG9mCiAgICBvdXIgcmVzdWx0cyBhbmQgaGVscCBndWlkZSBzb21lIGRlY2lzaW9ucyBhcyB3ZSB0aWR5LCBtb2RlbCwgYW5kCiAgICB2aXN1YWxpemUgb3VyIGRhdGEuCjIuICAqKldyYW5nbGUqKjogSW4gc2VjdGlvbiAyIHdlIGFnYWluIHJldmlzaXQgdGlkeWluZyBhbmQgdG9rZW5pemluZwogICAgdGV4dCB1c2luZyB0aGUgYHRpZHl0ZXh0YCBwYWNrYWdlIGJ1dCBhcmUgYWxzbyBpbnRyb2R1Y2VkIHRvIHRoZSB0aGUKICAgIGBzdG1gIHBhY2thZ2UuIFRoaXMgcGFja2FnZSBtYWtlcyB1c2Ugb2YgYHRtYCB0ZXh0IG1pbmluZyBwYWNrYWdlIHRvCiAgICBwcmVwcm9jZXNzIHRleHQgYW5kIHdpbGwgYWxzbyBiZSBvdXIgZmlyc3QgaW50cm9kdWN0aW9uIHRvIHdvcmQKICAgIHN0ZW1taW5nLgozLiAgKipNb2RlbCoqOiBXZSB0YWtlIGEgbG9vayBhdCB0d28gZGlmZmVyZW50IGFwcHJvYWNoZXMgdG8gdG9waWMKICAgIG1vZGVsaW5nOiBMYXRlbnQgRGlyaWNobGV0IEFsbG9jYXRpb24gKExEQSkgYW5kIFN0cnVjdHVyYWwgVG9waWMKICAgIE1vZGVsaW5nIChTVE0pLCB3aGljaCBpcyB2ZXJ5IHNpbWlsYXIgdG8gTERBIGJ1dCBjYW4gdXNlIG1ldGFkYXRhCiAgICBhYm91dCBkb2N1bWVudHMgdG8gaW1wcm92ZSB0aGUgYXNzaWdubWVudCBvZiB3b3JkcyB0byAidG9waWNzIiBpbiBhCiAgICBjb3JwdXMgYW5kIGV4YW1pbmUgcmVsYXRpb25zaGlwcyBiZXR3ZWVuIHRvcGljcyBhbmQgY292YXJpYXRlcy7CoAo0LiAgKipFeHBsb3JlKio6IFRvIGZ1cnRoZXIgZXhwbG9yZSB0aGUgcmVzdWx0cyBvZiBvdXIgdG9waWMgbW9kZWwsIHdlCiAgICB1c2Ugc2V2ZXJhbCBoYW5keSBmdW5jdGlvbnMgZnJvbSB0aGUgYHRvcGljbW9kZWxzYCBhbmQgYHN0bWAKICAgIHBhY2thZ2VzLCBpbmNsdWRpbmcgdGhlIGBmaW5kVGhvdWdodHNgIGZ1bmN0aW9uIGZvciB2aWV3aW5nCiAgICBkb2N1bWVudHMgYXNzaWduZWQgdG8gYSBnaXZlbiB0b3BpYyBhbmQgdGhlIGB0b0xEQXZpc2AgZnVuY3Rpb24gZm9yCiAgICBleHBsb3JpbmcgdG9waWMgYW5kIHdvcmQgZGlzdHJpYnV0aW9ucy4KCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMgMS4gUFJFUEFSRQoKVG8gaGVscCB1cyBiZXR0ZXIgdW5kZXJzdGFuZCB0aGUgY29udGV4dCwgcXVlc3Rpb25zLCBhbmQgZGF0YSBzb3VyY2VzCndlJ2xsIGJlIHVzaW5nIGluIFVuaXQgMywgdGhpcyBzZWN0aW9uIHdpbGwgZm9jdXMgb24gdGhlIGZvbGxvd2luZwp0b3BpY3M6CgphLiAgKipDb250ZXh0KiouIEFzIGNvbnRleHQgZm9yIG91ciBhbmFseXNpcyB0aGlzIHdlZWssIHdlJ2xsIHJldmlldwogICAgc2V2ZXJhbCByZWxhdGVkIHBhcGVycyBieSBteSBjb2xsZWFndWVzIHJlbGV2YW50IHRvIG91ciBhbmFseXNpcyBvZgogICAgTU9PQy1FZCBkaXNjdXNzaW9uIGZvcnVtcy4KYi4gICoqUXVlc3Rpb25zLioqIFdlJ2xsIGFsc28gZXhhbWluZSB3aGF0IGluc2lnaHQgdG9waWMgbW9kZWxpbmcgY2FuCiAgICBwcm92aWRlIHRvIGEgcXVlc3Rpb24gdGhhdCB3ZSBhc2tlZCBwYXJ0aWNpcGFudHMgYW5zd2VyIGluIHRoZWlyCiAgICBwcm9mZXNzaW9uYWwgbGVhcm5pbmcgdGVhbXMgKFBMVHMpLgpjLiAgKipQcm9qZWN0IFNldHVwLioqIFRoaXMgc2hvdWxkIGJlIHZlcnkgZmFtaWxpYXIgYnkgbm93LCBidXQgd2UnbGwKICAgIHNldCB1cCBhIG5ldyBSIHByb2plY3QgYW5kIGluc3RhbGwgYW5kIGxvYWQgdGhlIHJlcXVpcmVkIHBhY2thZ2VzCiAgICBmb3IgdGhlIHRvcGljIG1vZGVsaW5nIHdhbGt0aHJvdWdoLgoKIyMjIDFhLiBDb250ZXh0CgojIyMjIFBhcnRpY2lwYXRpbmcgaW4gYSBNT09DIGFuZCBQcm9mZXNzaW9uYWwgTGVhcm5pbmcgVGVhbTogSG93IGEgQmxlbmRlZCBBcHByb2FjaCB0byBQcm9mZXNzaW9uYWwgRGV2ZWxvcG1lbnQgTWFrZXMgYSBEaWZmZXJlbmNlCgpbIVtUZWFjaGluZyBTdGF0aXN0aWNzIFRocm91Z2ggRGF0YSBJbnZlc3RpZ2F0aW9ucwpNT09DLUVkXShpbWcvdHNkaS5wbmcgIk91ciB3b3JsZCBpcyByaWNoIHdpdGggZGF0YSBzb3VyY2VzLCBhbmQgdGVjaG5vbG9neSBtYWtlcyBkYXRhIG1vcmUgYWNjZXNzaWJsZSB0aGFuIGV2ZXIgYmVmb3JlISBUbyBoZWxwIGVuc3VyZSBzdHVkZW50cyBhcmUgZnV0dXJlIHJlYWR5IHRvIHVzZSBkYXRhIGZvciBtYWtpbmcgaW5mb3JtZWQgZGVjaXNpb25zLCBtYW55IGNvdW50cmllcyBhcm91bmQgdGhlIHdvcmxkIGhhdmUgaW5jcmVhc2VkIHRoZSBlbXBoYXNpcyBvbiBzdGF0aXN0aWNzIGFuZCBkYXRhIGFuYWx5c2lzIGluIHNjaG9vbCBjdXJyaWN1bHVt4oCTZnJvbSBlbGVtZW50YXJ5L3ByaW1hcnkgZ3JhZGVzIHRocm91Z2ggY29sbGVnZS4gVGhpcyBjb3Vyc2UgYWxsb3dzIHlvdSB0byBsZWFybiwgYWxvbmcgd2l0aCBjb2xsZWFndWVzIGZyb20gb3RoZXIgc2Nob29scywgYW4gaW52ZXN0aWdhdGlvbiBjeWNsZSB0byB0ZWFjaCBzdGF0aXN0aWNzIGFuZCB0byBoZWxwIHN0dWRlbnRzIGV4cGxvcmUgZGF0YSB0byBtYWtlIGV2aWRlbmNlLWJhc2VkIGNsYWltcy4gVG8gbGVhcm4gbW9yZSBhYm91dCBlbmdhZ2luZyBsZWFybmVycyBpbiBtYWtpbmcgaW5mZXJlbmNlcyBhbmQgY2xhaW1zIHN1cHBvcnRlZCBieSBkYXRhIGFuZCBob3cgdG8gZW1waGFzaXplIGluZmVyZW50aWFsIHJlYXNvbmluZyBpbiB0ZWFjaGluZyBzdGF0aXN0aWNzIHRocm91Z2ggcG9zaW5nIGRpZmZlcmVudCB0eXBlcyBvZiBpbnZlc3RpZ2F0aXZlIHF1ZXN0aW9ucywgZW5yb2xsIGluIG91ciBUZWFjaGluZyBTdGF0aXN0aWNzIHRocm91Z2ggSW5mZXJlbnRpYWwgUmVhc29uaW5nIE1PT0MtRWQuIil7d2lkdGg9IjUwJSJ9XShodHRwczovL3BsYWNlLmZpLm5jc3UuZWR1L2xvY2FsL2NhdGFsb2cvY291cnNlLnBocD9pZD00JnJlZj0xKQoKRnVsbCB0ZXh0OiA8aHR0cHM6Ly93d3cubGVhcm50ZWNobGliLm9yZy9wLzE5NTIzNC8+CgoqKkFic3RyYWN0KioKCk1hc3NpdmUgT3BlbiBPbmxpbmUgQ291cnNlcyBmb3IgRWR1Y2F0b3JzIChNT09DLUVkcykgcHJvdmlkZQpvcHBvcnR1bml0aWVzIGZvciB1c2luZyByZXNlYXJjaC1iYXNlZCBsZWFybmluZyBhbmQgdGVhY2hpbmcgcHJhY3RpY2VzLAphbG9uZyB3aXRoIG5ldyB0ZWNobm9sb2dpY2FsIHRvb2xzIGFuZCBmYWNpbGl0YXRpb24gYXBwcm9hY2hlcyBmb3IKZGVsaXZlcmluZyBxdWFsaXR5IG9ubGluZSBwcm9mZXNzaW9uYWwgZGV2ZWxvcG1lbnQuIFRoZSBUZWFjaGluZwpTdGF0aXN0aWNzIFRocm91Z2ggRGF0YSBJbnZlc3RpZ2F0aW9ucyBNT09DLUVkIHdhcyBidWlsdCBmb3IgcHJlcGFyaW5nCnRlYWNoZXJzIGluIHBlZGFnb2d5IGZvciB0ZWFjaGluZyBzdGF0aXN0aWNzLCBhbmQgaXQgaGFzIGJlZW4gb2ZmZXJlZCB0bwpwYXJ0aWNpcGFudHMgZnJvbSBhcm91bmQgdGhlIHdvcmxkLiBEdXJpbmcgMjAxNi0yMDE3LCBwcm9mZXNzaW9uYWwKbGVhcm5pbmcgdGVhbXMgKFBMVHMpIHdlcmUgZm9ybWVkIGZyb20gYSBzdWJzZXQgb2YgTU9PQy1FZCBwYXJ0aWNpcGFudHMuClRoZXNlIHRlYW1zIG1ldCBzZXZlcmFsIHRpbWVzIHRvIHNoYXJlIGFuZCBkaXNjdXNzIHRoZWlyIGxlYXJuaW5nIGFuZApleHBlcmllbmNlcy4gVGhpcyBzdHVkeSBmb2N1c2VkIG9uIGV4YW1pbmluZyB0aGUgd2F5cyB0aGF0IGEgYmxlbmRlZAphcHByb2FjaCB0byBwcm9mZXNzaW9uYWwgZGV2ZWxvcG1lbnQgbWF5IHJlc3VsdCBpbiBzaW1pbGFyIG9yIGRpZmZlcmVudApwYXR0ZXJucyBvZiBlbmdhZ2VtZW50IHRvIHRob3NlIHdobyBvbmx5IHBhcnRpY2lwYXRlIGluIGEgbGFyZ2Utc2NhbGUKb25saW5lIGNvdXJzZS4gUmVzdWx0cyBzaG93IHRoZSBiZW5lZml0cyBvZiBhIGJsZW5kZWQgbGVhcm5pbmcKZW52aXJvbm1lbnQgZm9yIHJldGVudGlvbiwgZW5nYWdlbWVudCB3aXRoIGNvdXJzZSBtYXRlcmlhbHMsIGFuZApjb25uZWN0ZWRuZXNzIHdpdGhpbiB0aGUgb25saW5lIGNvbW11bml0eSBvZiBsZWFybmVycyBpbiBhbiBvbmxpbmUKcHJvZmVzc2lvbmFsIGRldmVsb3BtZW50IG9uIHRlYWNoaW5nIHN0YXRpc3RpY3MuIFRoZSBmaW5kaW5ncyBzdWdnZXN0CnRoZSB1c2Ugb2Ygc2VsZi1mb3JtaW5nIGF1dG9ub21vdXMgUExUcyBmb3Igc3VwcG9ydGluZyBhIGRlZXBlciBhbmQgbW9yZQpjb21wcmVoZW5zaXZlIGV4cGVyaWVuY2Ugd2l0aCBzZWxmLWRpcmVjdGVkIG9ubGluZSBwcm9mZXNzaW9uYWwKZGV2ZWxvcG1lbnRzIHN1Y2ggYXMgTU9PQ3MuIE90aGVyIG9ubGluZSBwcm9mZXNzaW9uYWwgZGV2ZWxvcG1lbnQKY291cnNlcywgc3VjaCBhcyBNT09DcywgbWF5IGJlbmVmaXQgZnJvbSBwdXJwb3NlbHkgc3VnZ2VzdGluZyBhbmQKYWR2ZXJ0aXNpbmcsIGFuZCBwZXJoYXBzIGZhY2lsaXRhdGluZywgdGhlIGZvcm1hdGlvbiBvZiBzbWFsbApmYWNlLXRvLWZhY2Ugb3IgdmlydHVhbCBQTFRzIHdobyBjb21taXQgdG8gZW5nYWdlIGluIGxlYXJuaW5nIHRvZ2V0aGVyLgoKKipEYXRhIFNvdXJjZSAmIEFuYWx5c2lzKioKCkFsbCBwZWVyIGludGVyYWN0aW9uLCBpbmNsdWRpbmcgcGVlciBkaXNjdXNzaW9uLCB0YWtlIHBsYWNlIHdpdGhpbgpkaXNjdXNzaW9uIGZvcnVtcyBvZiBNT09DLUVkcywgd2hpY2ggYXJlIGhvc3RlZCB1c2luZyB0aGUgTW9vZGxlCkxlYXJuaW5nIE1hbmFnZW1lbnQgU3lzdGVtLiBUbyBidWlsZCB0aGUgZGF0YXNldCB5b3UnbGwgYmUgdXNpbmcgZm9yCnRoaXMgd2Fsa3Rocm91Z2gsIHRoZSByZXNlYXJjaCB0ZWFtIHdyb3RlIGEgcXVlcnkgZm9yIE1vb2RsZSdzIE15U1FMCmRhdGFiYXNlLCB3aGljaCByZWNvcmRzIHBhcnRpY2lwYW50cycgdXNlci1sb2dzIG9mIGFjdGl2aXR5IGluIHRoZQpvbmxpbmUgZm9ydW1zLiBUaGlzIHNxbCBxdWVyeSBjb21iaW5lcyBzZXBhcmF0ZSBkYXRhYmFzZSB0YWJsZXMKY29udGFpbmluZyBwb3N0aW5ncyBhbmQgY29tbWVudHMgaW5jbHVkaW5nIHBhcnRpY2lwYW50IElEcywgdGltZXN0YW1wcywKZGlzY3Vzc2lvbiB0ZXh0IGFuZCBvdGhlciBhdHRyaWJ1dGVzIG9yICJtZXRhZGF0dHNhLiIKCkZvciBmdXJ0aGVyIGRlc2NyaXB0aW9uIG9mIHRoZSBmb3J1bXMgYW5kIGRhdGEgcmV0cmlldmFsIHByb2Nlc3MsIHNlZQphbHNvIHRoZSBmb2xsb3dpbmcgcGFwZXJzOgoKLSAgIEtlbGxvZ2csIFMuLCAmIEVkZWxtYW5uLCBBLiAoMjAxNSkuIFtNYXNzaXZlbHkgT3BlbiBPbmxpbmUgQ291cnNlCiAgICBmb3IgRWR1Y2F0b3JzIChNT09D4oCQRWQpIG5ldHdvcmsKICAgIGRhdGFzZXRdKGh0dHBzOi8vYmVyYS1qb3VybmFscy5vbmxpbmVsaWJyYXJ5LndpbGV5LmNvbS9kb2kvcGRmZGlyZWN0LzEwLjExMTEvYmpldC4xMjMxMikuwqAqQnJpdGlzaAogICAgam91cm5hbCBvZiBlZHVjYXRpb25hbCB0ZWNobm9sb2d5KizCoCo0NiooNSksIDk3Ny05ODMuCgotICAgRXplbi1DYW4sIEEuLCBCb3llciwgSy4gRS4sIEtlbGxvZ2csIFMuLCAmIEJvb3RoLCBTLiAoMjAxNSwgTWFyY2gpLgogICAgW1Vuc3VwZXJ2aXNlZCBtb2RlbGluZyBmb3IgdW5kZXJzdGFuZGluZyBNT09DIGRpc2N1c3Npb24gZm9ydW1zOiBhCiAgICBsZWFybmluZyBhbmFseXRpY3MKICAgIGFwcHJvYWNoXShodHRwczovL2RsLmFjbS5vcmcvZG9pL3BkZi8xMC4xMTQ1LzI3MjM1NzYuMjcyMzU4OSkuCiAgICBJbsKgKlByb2NlZWRpbmdzIG9mIHRoZSBmaWZ0aCBpbnRlcm5hdGlvbmFsIGNvbmZlcmVuY2Ugb24gbGVhcm5pbmcKICAgIGFuYWx5dGljcyBhbmQga25vd2xlZGdlKsKgKHBwLiAxNDYtMTUwKS4KCi0gICBLZWxsb2dnLCBTLiwgQm9vdGgsIFMuLCAmIE9saXZlciwgSy4gKDIwMTQpLiBbQSBzb2NpYWwgbmV0d29yawogICAgcGVyc3BlY3RpdmUgb24gcGVlciBzdXBwb3J0ZWQgbGVhcm5pbmcgaW4gTU9PQ3MgZm9yCiAgICBlZHVjYXRvcnMuXShodHRwczovL3d3dy5lcnVkaXQub3JnL2VuL2pvdXJuYWxzL2lycm9kbC8xOTAwLXYxLW4xLWlycm9kbDA0OTQ1LzEwNjU1NDVhci5wZGYpwqAqSW50ZXJuYXRpb25hbAogICAgUmV2aWV3IG9mIFJlc2VhcmNoIGluIE9wZW4gYW5kIERpc3RyaWJ1dGVkIExlYXJuaW5nKizCoCoxNSooNSksCiAgICAyNjMtMjg5LgoKKipTdW1tYXJ5IG9mIEtleSBGaW5kaW5ncyoqCgpUaGUgZm9sbG93aW5nIGhpZ2hsaWdodCBzb21lIGtleSBmaW5kaW5ncyByZWxhdGVkIHRvIHRoZSBkaXNjdXNzaW9uCmZvcnVtcyBpbiB0aGUgcGFwZXJzIGNpdGVkIGFib3ZlOgoKMS4gIE1PT0NzIGRlc2lnbmVkIHNwZWNpZmljYWxseSBmb3IgSy0xMiB0ZWFjaGVycyBjYW4gcHJvdmlkZSBwb3NpdGl2ZQogICAgc2VsZi1kaXJlY3RlZCBsZWFybmluZyBleHBlcmllbmNlcyBhbmQgcmljaCBlbmdhZ2VtZW50IGluIGRpc2N1c3Npb24KICAgIGZvcnVtcyB0aGF0IGhlbHAgZm9ybSBvbmxpbmUgY29tbXVuaXRpZXMgZm9yIGVkdWNhdG9ycy4KMi4gIEFuYWx5c2lzIG9mIGRpc2N1c3Npb24gZm9ydW0gZGF0YSBpbiBUU0RJIHByb3ZpZGVkIGEgdmVyeSBjbGVhcgogICAgcGljdHVyZSBvZiBob3cgZW50aHVzaWFzdGljIG1hbnkgUExUIG1lbWJlcnMgYW5kIGxlYWRlcnMgd2VyZSB0bwogICAgdGFsayB0byBvdGhlcnMgaW4gdGhlIG9ubGluZSBjb21tdW5pdHkuIFRoZXkgcG9zZWQgdGhlaXIgcXVlc3Rpb25zCiAgICBhbmQgc2hhcmVkIGlkZWFzIHdpdGggb3RoZXJzIGFib3V0IHRlYWNoaW5nIHN0YXRpc3RpY3MgdGhyb3VnaG91dAogICAgdGhlIHVuaXRzLCBldmVuIHRob3VnaCB0aGV5IHdlcmUgYWxzbyBtZWV0aW5nIHN5bmNocm9ub3VzbHkgc2V2ZXJhbAogICAgdGltZXMgd2l0aCB0aGVpciBjb2xsZWFndWVzIGluIHNtYWxsIGdyb3VwIFBMVHMuCjMuICBGaW5kaW5ncyBvbiBrbm93bGVkZ2UgY29uc3RydWN0aW9uIGRlbW9uc3RyYXRlZCB0aGF0IG92ZXIgaGFsZiBvZgogICAgdGhlIGRpc2N1c3Npb25zIGluIGJvdGggY291cnNlcyBtb3ZlZCBiZXlvbmQgc2hhcmluZyBpbmZvcm1hdGlvbiBhbmQKICAgIHN0YXRlbWVudHMgb2YgYWdyZWVtZW50IGFuZCBlbnRlcmVkIGEgcHJvY2VzcyBvZiBkaXNzb25hbmNlLAogICAgbmVnb3RpYXRpb24gYW5kIGNvLWNvbnN0cnVjdGlvbiBvZiBrbm93bGVkZ2UsIGJ1dCBzZWxkb20gbW92ZWQKICAgIGJleW9uZCB0aGlzIHBoYXNlIGluIHdoaWNoIG5ldyBrbm93bGVkZ2Ugd2FzIHRlc3RlZCBvciBhcHBsaWVkLgogICAgVGhlc2UgZmluZGluZ3MgZWNobyBzaW1pbGFyIHJlc2VhcmNoIG9uIGRpZmZpY3VsdGllcyBpbiBwcm9tb3RpbmcKICAgIGtub3dsZWRnZSBjb25zdHJ1Y3Rpb24gaW4gb25saW5lIHNldHRpbmdzLgo0LiAgVG9waWMgbW9kZWxpbmcgcHJvdmlkZXMgbW9yZSBpbnRlcnByZXRhYmxlIGFuZCBjb2hlc2l2ZSBtb2RlbHMgZm9yCiAgICBkaXNjdXNzaW9uIGZvcnVtcyB0aGFuIG90aGVyIHBvcHVsYXIgdW5zdXBlcnZpc2VkIG1vZGVsaW5nCiAgICB0ZWNobmlxdWVzIHN1Y2ggYXMgay1tZWFucyBhbmQgay1tZWRvaWRzIGNsdXN0ZXJpbmcgYWxnb3JpdGhtcy4KCiMjIyAxYi4gR3VpZGluZyBRdWVzdGlvbnMKCkZvciB0aGUgcGFwZXIsIFsqUGFydGljaXBhdGluZyBpbiBhIE1PT0MgYW5kIFByb2Zlc3Npb25hbCBMZWFybmluZyBUZWFtOgpIb3cgYSBCbGVuZGVkIEFwcHJvYWNoIHRvIFByb2Zlc3Npb25hbCBEZXZlbG9wbWVudCBNYWtlcyBhCkRpZmZlcmVuY2UqXShodHRwczovL3d3dy5sZWFybnRlY2hsaWIub3JnL3AvMTk1MjM0LyksIHRoZSByZXNlYXJjaGVycwp3ZXJlIGludGVyZXN0ZWQgaW4gdW5wYWNraW5nIGhvdyBwYXJ0aWNpcGFudHMgd2hvIGVucm9sbGVkIGluIHRoZQpUZWFjaGluZyBTdGF0aXN0aWNzIHRocm91Z2ggRGF0YSBJbnZlc3RpZ2F0aW9ucyBNT09DLUVkIG1pZ2h0IGJlbmVmaXQKZnJvbSBhbHNvIGJlaW5nIGluIGEgc21hbGxlciBncm91cCBvZiBwcm9mZXNzaW9uYWxzIGNvbW1pdHRlZCB0bwplbmdhZ2luZyBpbiB0aGUgc2FtZSBwcm9mZXNzaW9uYWwgZGV2ZWxvcG1lbnQuIFRoZSBzcGVjaWZpYyByZXNlYXJjaApxdWVzdGlvbiBmb3IgdGhpcyBwYXBlciB3YXM6Cgo+IFdoYXQgYXJlIHRoZSBzaW1pbGFyaXRpZXMgYW5kIGRpZmZlcmVuY2VzIGJldHdlZW4gaG93IFBMVCBtZW1iZXJzIGFuZAo+IE5vbi1QTFQgb25saW5lIHBhcnRpY2lwYW50cyBlbmdhZ2UgYW5kIG1lZXQgY291cnNlIGdvYWxzIGluIGEgTU9PQy1FZAo+IGRlc2lnbmVkIGZvciBlZHVjYXRvcnMgaW4gc2Vjb25kYXJ5IGFuZCBjb2xsZWdpYXRlIHNldHRpbmdzPwoKRHIuIEhvbGx5bHlubmUgTGVlIGFuZCB0aGUgVFNESSB0ZWFtIGFsc28gZGV2ZWxvcGVkIGEgZmFjaWxpdGF0aW9uIGd1aWRlCmRlc2lnbmVkIHNwZWNpZmljYWxseSBmb3IgUExUIHRlYW1zIHRvIGhlbHAgZ3JvdXBzIHN5bnRoZXNpemUgdGhlIGlkZWFzCmluIHRoZSBjb3Vyc2UgYW5kIG1ha2UgcGxhbnMgZm9yIGhvdyB0byBpbXBsZW1lbnQgbmV3IHN0cmF0ZWdpZXMgaW4KdGhlaXIgY2xhc3Nyb29tIGluIG9yZGVyIHRvIGltcGFjdCBzdHVkZW50cycgbGVhcm5pbmcgb2Ygc3RhdGlzdGljcy4gT25lCnF1ZXN0aW9uIFBMVCBtZW1iZXJzIHdlcmUgYXNrZWQgdG8gYWRkcmVzcyB3YXM6Cgo+IFdoYXQgaWRlYXMgb3IgaXNzdWVzIGVtZXJnZWQgaW4gdGhlIGRpc2N1c3Npb24gZm9ydW1zIHRoaXMgcGFzdCB3ZWVrPwoKRm9yIHRoaXMgd2Fsa3Rocm91Z2gsIHdlIHdpbGwgZnVydGhlciBleGFtaW5lIHRoYXQgcXVlc3Rpb24gdGhyb3VnaCB0aGUKdXNlIG9mIHRvcGljIG1vZGVsaW5nLgoKQW5kIGp1c3QgdG8gcmVpdGVyYXRlIHlldCBhZ2FpbiBmcm9tIFVuaXQgMSwgb25lIG92ZXJhcmNoaW5nIHF1ZXN0aW9uCndlJ2xsIGV4cGxvcmUgdGhyb3VnaG91dCB0aGlzIGNvdXJzZSwgYW5kIHRoYXQgU2lsZ2UgYW5kIFJvYmluc29uICgyMDE4KQppZGVudGlmeSBhcyBhIGNlbnRyYWwgcXVlc3Rpb24gdG8gdGV4dCBtaW5pbmcgYW5kIG5hdHVyYWwgbGFuZ3VhZ2UKcHJvY2Vzc2luZywgaXM6Cgo+IEhvdyBkbyB3ZSB0byAqKnF1YW50aWZ5Kiogd2hhdCBhIGRvY3VtZW50IG9yIGNvbGxlY3Rpb24gb2YgZG9jdW1lbnRzCj4gaXMgYWJvdXQ/CgojIyMgMWMuIFNldCBVcAoKQXMgaGlnaGxpZ2h0ZWQgaW4gW0NoYXB0ZXIgNiBvZiBEYXRhIFNjaWVuY2UgaW4gRWR1Y2F0aW9uIFVzaW5nClJdKGh0dHBzOi8vZGF0YXNjaWVuY2VpbmVkdWNhdGlvbi5jb20vYzA2Lmh0bWwpIChEU0lFVVIpLCBvbmUgb2YgdGhlCmZpcnN0IHN0ZXBzIG9mIGV2ZXJ5IHdvcmtmbG93IHNob3VsZCBiZSB0byBzZXQgdXAgYSAiUHJvamVjdCIgd2l0aGluClJTdHVkaW8uIFRoaXMgd2lsbCBiZSB5b3VyICJob21lIiBmb3IgYW55IGZpbGVzIGFuZCBjb2RlIHVzZWQgb3IgY3JlYXRlZAppbiBVbml0IDIuCgpZb3UgYXJlIHdlbGNvbWUgdG8gY29udGludWUgdXNpbmcgdGhlIHNhbWUgcHJvamVjdCBjcmVhdGVkIGZvciBVbml0IDEsCm9yIGNyZWF0ZSBhbiBlbnRpcmVseSBuZXcgcHJvamVjdCBmb3IgVW5pdCAyLiBIb3dldmVyLCBhZnRlciB5b3UndmUKY3JlYXRlZCB5b3VyIHByb2plY3Qgb3BlbiB1cCBhIG5ldyBSIHNjcmlwdCwgYW5kIGxvYWQgdGhlIGZvbGxvd2luZwpwYWNrYWdlcyB0aGF0IHdlJ2xsIGJlIG5lZWRpbmcgZm9yIHRoaXMgd2Fsa3Rocm91Z2g6CgpgYGB7ciBsb2FkLXBhY2thZ2VzLCBtZXNzYWdlPUZBTFNFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeSh0aWR5dGV4dCkKbGlicmFyeShTbm93YmFsbEMpCmxpYnJhcnkodG9waWNtb2RlbHMpCmxpYnJhcnkoc3RtKQpsaWJyYXJ5KGxkYXR1bmluZykKbGlicmFyeShrbml0cikKbGlicmFyeShMREF2aXMpCmBgYAoKQXQgdGhlIGVuZCBvZiB0aGlzIHdlZWssIEkgZW5jb3VyYWdlIHlvdSBzaGFyZSB3aXRoIG1lIHlvdXIgUiBzY3JpcHQgYXMKZXZpZGVuY2UgdGhhdCB5b3UgaGF2ZSBjb21wbGV0ZSB0aGUgd2Fsa3Rocm91Z2guIEFsdGhvdWdoIEkgaGlnaGx5CnJlY29tbWVuZCB0aGF0IHRoYXQgeW91IG1hbnVhbGx5IHR5cGUgdGhlIGNvZGUgc2hhcmVkIHRocm91Z2hvdXQgdGhpcwp3YWxrdGhyb3VnaCwgZm9yIGxhcmdlIGJsb2NrcyBvZiB0ZXh0IGl0IG1heSBiZSBlYXNpZXIgdG8gY29weSBhbmQKcGFzdGUuCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMjIDIuIFdSQU5HTEUKCkFzIG5vdGVkIHByZXZpb3VzbHksIGRhdGEgd3JhbmdsaW5nIGludm9sdmVzIHNvbWUgY29tYmluYXRpb24gb2YKY2xlYW5pbmcsIHJlc2hhcGluZywgdHJhbnNmb3JtaW5nLCBhbmQgbWVyZ2luZyBkYXRhIChXaWNraGFtICYKR3JvbGVtdW5kLCAyMDE3KS4gVGhpcyB3ZWVrIHdlJ2xsIHJldmlzaXQgdGlkeWluZyBhbmQgdG9rZW5pemluZyB0ZXh0CnVzaW5nIHRoZSBgdGlkeXRleHRgIHBhY2thZ2UsIGJ1dCBhcmUgYWxzbyBpbnRyb2R1Y2VkIHRvIHRoZSB0aGUgYHN0bWAKcGFja2FnZS4gVGhpcyBwYWNrYWdlIG1ha2VzIHVzZSBvZiBgdG1gIHRleHQgbWluaW5nIHBhY2thZ2UgdG8KcHJlcHJvY2VzcyB0ZXh0IChlLmcuLCByZW1vdmluZyBwdW5jdHVhdGlvbiwgc3RvcCB3b3JkcywgZXRjLikgYW5kIHdpbGwKYWxzbyBiZSBvdXIgZmlyc3QgaW50cm9kdWN0aW9uIHRvIHdvcmQgc3RlbW1pbmcuCgphLiAgKipJbXBvcnQgRGF0YSoqLiBXZSdsbCBiZSB3b3JraW5nIHdpdGggLmNzdiBmaWxlcyB0aGlzIHdlZWsgYW5kIHRoZQogICAgYHJlYWRfY3N2KClgIGZ1bmN0aW9uIGJ1dCB3aWxsIGludHJvZHVjZSBhIG5ldyBhcmd1bWVudCBmb3IgY2hhbmdpbmcKICAgIGNvbHVtbiB0eXBlcy4KYi4gICoqQ2FzdCBhIERUTSoqLiBXZSByZXZpc2l0IHRoZSBgdGlkeXRleHRgIHBhY2thZ2UgdG8gInRpZHkiIGFuZAogICAgdG9rZW5pemUgb3VyIGZvcnVtIGRhdGEgYW5kIGludHJvZHVjZSB0aGUgYGNhc3RfZHRtKClgIGZ1bmN0aW9uIHRvCiAgICBjcmVhdGUgdGhlIGRvY3VtZW50IHRlcm0gbWF0cml4IChkdG0pIG5lZWQgZm9yIHRvcGljIG1vZGVsaW5nLgpjLiAgKipUbyBTdGVtIG9yIG5vdCB0byBTVEVNPyoqIFdlIGNvbmNsdWRlIG91ciBkYXRhIHdyYW5nbGluZyBieSBhbHNvCiAgICBpbnRyb2R1Y2luZyB0aGUgYHRleHRQcm9jZXNzb3IoKWAgZnVuY3Rpb24gZm9yIHByZXByb2Nlc3NpbmcgYW5kCiAgICBkaXNjdXNzIHRoZSBwcm9zIGFuZCBjb25zIG9mIHdvcmQgc3RlbW1pbmcuCgojIyMgMmEuIEltcG9ydCBGb3J1bSBEYXRhCgpUbyBnZXQgc3RhcnRlZCwgd2UgbmVlZCB0byBpbXBvcnQsIG9yICJyZWFkIiwgb3VyIGRhdGEgaW50byBSLiBUaGUKZnVuY3Rpb24gdXNlZCB0byBpbXBvcnQgeW91ciBkYXRhIHdpbGwgZGVwZW5kIG9uIHRoZSBmaWxlIGZvcm1hdCBvZiB0aGUKZGF0YSB5b3UgYXJlIHRyeWluZyB0byBpbXBvcnQuIEZpcnN0LCBob3dldmVyLCB5b3UnbGwgbmVlZCB0byBkbyB0aGUKZm9sbG93aW5nOgoKMS4gIERvd25sb2FkIHRoZSBgdHNfZm9ydW1fZGF0YS5jc3ZgIGZpbGUgd2UnbGwgYmUgdXNpbmcgZm9yIHRoaXMgVW5pdAogICAgZnJvbSBvdXIgTkNTVSBNb29kbGUgY291cnNlIHNpdGUuCjIuICBDcmVhdGUgYSBmb2xkZXIgaW4gdGhlIGRpcmVjdG9yeSBvbiB5b3VyIGNvbXB1dGVyIHdoZXJlIHlvdSBzdG9yZWQKICAgIHlvdXIgUiBQcm9qZWN0IGFuZCBuYW1lIGl0ICJkYXRhIi4KMy4gIEFkZCB0aGUgZmlsZSB0byB5b3VyIGRhdGEgZm9sZGVyLgo0LiAgQ2hlY2sgeW91ciBGaWxlcyB0YWIgaW4gUlN0dWRpbyB0byB2ZXJpZnkgdGhhdCB5b3VyIGZpbGUgaXMgaW5kZWVkCiAgICBpbiB5b3VyIGRhdGEgZm9sZGVyLgoKTm93IGxldCdzIHJlYWQgb3VyIGRhdGEgaW50byBvdXIgRW52aXJvbm1lbnQgdXNpbmcgdGhlIGByZWFkX2NzdigpYApmdW5jdGlvbiBhbmQgYXNzaWduIGl0IHRvIGEgdmFyaWFibGUgbmFtZSBzbyB3ZSBjYW4gd29yayB3aXRoIGl0IGxpa2UKYW55IG90aGVyIG9iamVjdCBpbiBSLgoKYGBge3IgcmVhZC1jc3Z9CnRzX2ZvcnVtX2RhdGEgPC0gcmVhZF9jc3YoImRhdGEvdHNfZm9ydW1fZGF0YS5jc3YiLCAKICAgICBjb2xfdHlwZXMgPSBjb2xzKGNvdXJzZV9pZCA9IGNvbF9jaGFyYWN0ZXIoKSwKICAgICAgICAgICAgICAgICAgIGZvcnVtX2lkID0gY29sX2NoYXJhY3RlcigpLCAKICAgICAgICAgICAgICAgICAgIGRpc2N1c3Npb25faWQgPSBjb2xfY2hhcmFjdGVyKCksIAogICAgICAgICAgICAgICAgICAgcG9zdF9pZCA9IGNvbF9jaGFyYWN0ZXIoKQogICAgICAgICAgICAgICAgICAgKQogICAgKQpgYGAKCkJ5IGRlZmF1bHQsIG1hbnkgb2YgdGhlIGNvbHVtbnMgbGlrZSBgY291cnNlX2lkYCBhbmQgYGZvcnVtX2lkYCBhcmUgcmVhZAppbiBhcyBudW1lcmljIGRhdGEuIEZvciBvdXIgcHVycG9zZXMsIHdlIHBsYW4gdG8gdHJlYXQgdGhlbSBhcyB1bmlxdWUKaWRlbnRpZmllcnMgb3IgbmFtZXMgZm9yIG91dCBjb3Vyc2VzLCBmb3J1bXMsIGRpc2N1c3Npb25zLCBhbmQgcG9zdHMuClRoZSBgcmVhZF9jc3YoKWAgZnVuY3Rpb24gaGFzIGEgaGFuZHkgYGNvbF90eXBlcyA9YCBhcmd1bWVudCBjaGFuZ2luZwp0aGUgY29sdW1uIHR5cGVzIGZyb20gbnVtZXJpYyB0byBjaGFyYWN0ZXJzLgoKIyMjIDJiLiBDYXN0IGEgRG9jdW1lbnQgVGVybSBNYXRyaXgKCkluIHRoaXMgc2VjdGlvbiB3ZSdsbCByZXZpc2l0IHNvbWUgZmFtaWxpYXIgYHRpZHl0ZXh0YCBmdW5jdGlvbnMgdXNlZCBpbgpVbml0cyAxICYgMiBmb3IgdGlkeWluZyBhbmQgdG9rZW5pemluZyB0ZXh0IGFuZCBpbnRyb2R1Y2Ugc29tZSBuZXcKZnVuY3Rpb25zIGZyb20gdGhlIGBzdG1gIHBhY2thZ2UgZm9yIHByb2Nlc3NpbmcgdGV4dCBhbmQgdHJhbnNmb3JtaW5nCm91ciBkYXRhIGZyYW1lcyBpbnRvIG5ldyBkYXRhIHN0cnVjdHVyZXMgcmVxdWlyZWQgZm9yIHRvcGljIG1vZGVsaW5nLgoKIyMjIyBGdW5jdGlvbnMgVXNlZAoKKipgdGlkeXRleHRgIGZ1bmN0aW9ucyoqCgotICAgYHVubmVzdF90b2tlbnMoKWAgc3BsaXRzIGEgY29sdW1uIGludG8gdG9rZW5zCi0gICBgYW50aV9qb2luKClgIHJldHVybnMgYWxsIHJvd3MgZnJvbSB4IHdpdGhvdXQgYSBtYXRjaCBpbiB5IGFuZCB1c2VkCiAgICB0byByZW1vdmUgYHN0b3Agd29yZHNgIGZyb20gb3V0IGRhdGEuCi0gICBgY2FzdF9kdG0oKWAgdGFrZXMgYSB0aWRpZWQgZGF0YSBmcmFtZSB0YWtlIGFuZCAiY2FzdHMiIGl0IGludG8gYQogICAgZG9jdW1lbnQtdGVybSBtYXRyaXggKGR0bSkKCioqYGRwbHlyYCoqICoqZnVuY3Rpb25zKioKCi0gICBgY291bnQoKWAgbGV0cyB5b3UgcXVpY2tseSBjb3VudCB0aGUgdW5pcXVlIHZhbHVlcyBvZiBvbmUgb3IgbW9yZQogICAgdmFyaWFibGVzCi0gICBgZ3JvdXBfYnkoKWAgdGFrZXMgYSBkYXRhIGZyYW1lIGFuZCBvbmUgb3IgbW9yZSB2YXJpYWJsZXMgdG8gZ3JvdXAKICAgIGJ5Ci0gICBgc3VtbWFyaXNlKClgIGNyZWF0ZXMgYSBzdW1tYXJ5IG9mIGRhdGEgdXNpbmcgYXJndW1lbnRzIGxpa2Ugc3VtIGFuZAogICAgbWVhbgoKKipgc3RtYCBmdW5jdGlvbnMqKgoKLSAgIGB0ZXh0UHJvY2Vzc29yKClgIHRha2VzIGluIGEgdmVjdG9yIG9yIGNvbHVtbiBvZiByYXcgdGV4dHMgYW5kCiAgICBwZXJmb3JtcyB0ZXh0IHByb2Nlc3NpbmcgbGlrZSByZW1vdmluZyBwdW5jdHVhdGlvbiBhbmQgd29yZAogICAgc3RlbW1pbmcuCi0gICBgcHJlcERvY3VtZW50cygpYCBwZXJmb3JtcyBzZXZlcmFsIGNvcnB1cyBtYW5pcHVsYXRpb25zIGluY2x1ZGluZwogICAgcmVtb3Zpbmcgd29yZHMgYW5kIHJlbnVtYmVyaW5nIHdvcmQgaW5kaWNlcwoKIyMjIyBUaWR5aW5nIFRleHQKClByaW9yIHRvIHRvcGljIG1vZGVsaW5nLCB3ZSBoYXZlIGEgZmV3IHJlbWFpbmluZyBzdGVwcyB0byB0aWR5IG91ciB0ZXh0CnRoYXQgaG9wZWZ1bGx5IHNob3VsZCBmZWVsIGZhbWlsaWFyIGJ5IHRoaXMgcG9pbnQuIElmIHlvdSByZWNhbGwgZnJvbQpbQ2hhcHRlciAxIG9mIFRleHQgTWluaW5nIFdpdGgKUl0oaHR0cHM6Ly93d3cudGlkeXRleHRtaW5pbmcuY29tL3RpZHl0ZXh0Lmh0bWwpLCB0aGVzZSBwcmVwcm9jZXNzaW5nCnN0ZXBzIGluY2x1ZGU6CgoxLiAgVHJhbnNmb3JtaW5nIG91ciB0ZXh0IGludG8gInRva2VucyIKMi4gIFJlbW92aW5nIHVubmVjZXNzYXJ5IGNoYXJhY3RlcnMsIHB1bmN0dWF0aW9uLCBhbmQgd2hpdGVzcGFjZQozLiAgQ29udmVydGluZyBhbGwgdGV4dCB0byBsb3dlcmNhc2UKNC4gIFJlbW92aW5nIHN0b3Agd29yZHMgc3VjaCBhcyAidGhlIiwgIm9mIiwgYW5kICJ0byIKCkxldCdzIHRva2VuaXplIG91ciBmb3J1bSB0ZXh0IGFuZCBieSB1c2luZyB0aGUgZmFtaWxpYXIKYHVubmVzdF90b2tlbnMoKWAgYW5kIHJlbW92ZSBzdG9wIHdvcmRzIHBlciB1c3VhbDoKCmBgYHtyIHRva2VuaXplLWZvcnVtc30KZm9ydW1zX3RpZHkgPC0gdHNfZm9ydW1fZGF0YSAlPiUKICB1bm5lc3RfdG9rZW5zKG91dHB1dCA9IHdvcmQsIGlucHV0ID0gcG9zdF9jb250ZW50KSAlPiUKICBhbnRpX2pvaW4oc3RvcF93b3JkcywgYnkgPSAid29yZCIpCgpmb3J1bXNfdGlkeQpgYGAKCk5vdyBsZXQncyBkbyBhIHF1aWNrIHdvcmQgY291bnQgdG8gc2VlIHNvbWUgb2YgdGhlIG1vc3QgY29tbW9uIHdvcmRzCnVzZWQgdGhyb3VnaG91dCB0aGUgZm9ydW1zLiBUaGlzIHNob3VsZCBnZXQgYSBzZW5zZSBvZiB3aGF0IHdlJ3JlCndvcmtpbmcgd2l0aCBhbmQgbGF0ZXIgd2UnbGwgbmVlZCB0aGVzZSB3b3JkIGNvdW50cyBmb3IgY3JlYXRpbmcgb3VyCmRvY3VtZW50IHRlcm0gbWF0cml4IGZvciB0b3BpYyBtb2RlbGluZzoKCmBgYHtyIGNvdW50LXdvcmRzfQpmb3J1bXNfdGlkeSAlPiUKICBjb3VudCh3b3JkLCBzb3J0ID0gVFJVRSkKYGBgCgpUZXJtcyBsaWtlICJzdHVkZW50cywiICJkYXRhLCIgYW5kICJjbGFzcyIgYXJlIGFib3V0IHdoYXQgd2Ugd291bGQgaGF2ZQpleHBlY3RlZCBmcm9tIGEgY291cnNlIHRlYWNoaW5nIHN0YXRpc3RpY3MuIFRoZSB0ZXJtICJhZ3JlZSIgYW5kICJ0aW1lIgpob3dldmVyLCBhcmUgbm90IHNvIGludHVpdGl2ZSBhbmQgd29ydGggYSBxdWljayBsb29rIGFzIHdlbGwuCgojIyMjIyDinIUgQ29tcHJlaGVuc2lvbiBDaGVjawoKVXNlIHRoZSBgZmlsdGVyKClgIGFuZCBgZ3JlcGwoKWAgZnVuY3Rpb25zIGludHJvZHVjZWQgaW4gW1VuaXQgMS4KU2VjdGlvbgozYl0oaHR0cDovL3NoaXlhbjIwMzAuY29tL3VuaXQtMS13YWxrdGhyb3VnaC5odG1sIzNiX1dvcmRfU2VhcmNoKSB0bwpmaWx0ZXIgZm9yIHJvd3MgaW4gb3VyIGB0c19mb3J1bV9kYXRhYCBkYXRhIGZyYW1lIHRoYXQgY29udGFpbiB0aGUgdGVybXMKImFncmVlIiBhbmQgInRpbWUiIGFuZCBhbm90aGVyIHRlcm0gb3IgdGVybXMgb2YgeW91ciBjaG9vc2luZy4gU2VsZWN0IGEKcmFuZG9tIHNhbXBsZSBvZiAxMCBwb3N0cyB1c2luZyB0aGUgYHNhbXBsZV9uKClgIGZ1bmN0aW9uIGZvciB5b3VyIHRlcm1zCmFuZCBhbnN3ZXIgdGhlIGZvbGxvd2luZyBxdWVzdGlvbnM6CgoxLiAgV2hhdCwgaWYgYW55dGhpbmcsIGRvIHRoZXNlIHBvc3RzIGhhdmUgaW4gY29tbW9uPwoKMi4gIFdoYXQgdG9waWNzIG9yIHRoZW1lcyBtaWdodCBiZSBhcHBhcmVudCwgb3IgZG8geW91IGFudGljaXBhdGUKICAgIGVtZXJnaW5nLCBmcm9tIG91ciB0b3BpYyBtb2RlbGluZz8KCllvdXIgb3V0cHV0IHNob3VsZCBsb29rIHNvbWV0aGluZyBsaWtlIHRoaXM6CgpgYGB7ciBmaW5kLXF1b3RlcywgZWNobz1GQUxTRX0KZm9ydW1fcXVvdGVzIDwtIHRzX2ZvcnVtX2RhdGEgJT4lCiAgc2VsZWN0KHBvc3RfY29udGVudCkgJT4lIAogIGZpbHRlcihncmVwbCgndGltZScsIHBvc3RfY29udGVudCkpCgpzYW1wbGVfbihmb3J1bV9xdW90ZXMsMTApCmBgYAoKIyMjIyBDcmVhdGluZyBhIERvY3VtZW50IFRlcm0gTWF0cml4CgpBcyBoaWdobGlnaHRlZCBpbiBbQ2hhcHRlciA1IG9mIFRleHQgTWluaW5nIHdpdGgKUl0oaHR0cHM6Ly93d3cudGlkeXRleHRtaW5pbmcuY29tL2R0bS5odG1sI2Nhc3QtZHRtKSwgdGhlIGB0b3BpY21vZGVsc2AKcGFja2FnZSBhbmQgdGhlIFtMYXRlbnQgRGlyaWNobGV0IGFsbG9jYXRpb24KKExEQSldKGh0dHBzOi8vd3d3LnRpZHl0ZXh0bWluaW5nLmNvbS90b3BpY21vZGVsaW5nLmh0bWwjbGF0ZW50LWRpcmljaGxldC1hbGxvY2F0aW9uKQphbGdvcml0aG0gYW5kIGBMREEoKWAgZnVuY3Rpb24gaXQgdXNlcyBleHBlY3RzIGRvY3VtZW50LXRlcm0gbWF0cml4IGFzCnRoZSBkYXRhIGlucHV0LgoKQmVmb3JlIHdlIGNyZWF0ZSBhIG91ciBkb2N1bWVudC10ZXJtIG1hdHJpeCwgaG93ZXZlciwgd2UgaGF2ZSBhbgppbXBvcnRhbnQgZGVjaXNpb24gdG8gbWFrZToKCj4gKipXaGF0IGRvIHdlIGNvbnNpZGVyIHRvIGJlIGEgImRvY3VtZW50IiBpbiBhIE1PT0MtRWQgZGlzY3Vzc2lvbgo+IGZvcnVtPyoqCgpGb3IgZXhhbXBsZSwgd2UgY291bGQgY29uc2lkZXIgZWFjaCBpbmRpdmlkdWFsIGRpc2N1c3Npb24gcG9zdCwgb3IKYHBvc3RfaWRgIGluIG91ciBkYXRhIGZyYW1lLCBhcyBhIGRvY3VtZW50LiBJdCBtaWdodCBhbHNvIG1ha2Ugc2Vuc2UgdG8KY29tYmluZSB0ZXh0cyBmcm9tIGFsbCBwb3N0cyB3aXRoaW4gZWFjaCBkaXNjdXNzaW9uLCBvcgpgZGlzY2N1c3Npb25faWRgLCBhbmQgY29uc2lkZXIgdGhhdCBhcyBhIGRvY3VtZW50IHNpbmNlIHRoZXNlIHBvc3RzIGFyZQpvZnRlbiBpbnRlcmNvbm5lY3RlZCBhbiBidWlsZCBvZmYgb25lIGFub3RoZXIuCgpGb3Igbm93LCBob3dldmVyLCBsZXQgdHJlYXQgZWFjaCBpbmRpdmlkdWFsIHBvc3QgYXMgYSB1bmlxdWUgImRvY3VtZW50LiIKbm90ZWQgYWJvdmUsIHRvIGNyZWF0ZSBvdXIgZG9jdW1lbnQgdGVybSBtYXRyaXgsIHdlJ2xsIG5lZWQgdG8gZmlyc3QKYGNvdW50KClgIGhvdyBtYW55IHRpbWVzIGVhY2ggYHdvcmRgIG9jY3VycyBpbiBlYWNoIGRvY3VtZW50LCBvcgpgcG9zdF9pZGAgaW4gb3VyIGNhc2UsIGFuZCBjcmVhdGUgYSBtYXRyaXggdGhhdCBjb250YWlucyBvbmUgcm93IHBlcgpwb3N0IGFzIG91ciBvcmlnaW5hbCBkYXRhIGZyYW1lIGRpZCwgYnV0IG5vdyBjb250YWlucyBhIGNvbHVtbiBmb3IgZWFjaApgd29yZGAgaW4gdGhlIGVudGlyZSBjb3JwdXMgYW5kIGEgdmFsdWUgb2YgYG5gIGZvciBob3cgbWFueSB0aW1lcyB0aGF0CndvcmQgb2NjdXJzIGluIGVhY2ggcG9zdC4KClRvIGNyZWF0ZSB0aGlzIGRvY3VtZW50IHRlcm0gbWF0cml4IGZyb20gb3VyIHBvc3QgY291bnRzLCB3ZSdsbCB1c2UgdGhlCmBjYXN0X2R0bSgpYCBmdW5jdGlvbiBsaWtlIHNvIGFuZCBhc3NpZ24gaXQgdG8gdGhlIHZhcmlhYmxlCmBmb3J1bXNfZHRtYDoKCmBgYHtyIGNhc3QtZHRtfQpmb3J1bXNfZHRtIDwtIGZvcnVtc190aWR5ICU+JQogIGNvdW50KHBvc3RfaWQsIHdvcmQpICU+JQogIGNhc3RfZHRtKHBvc3RfaWQsIHdvcmQsIG4pCmBgYAoKIyMjIyMg4pyFIENvbXByZWhlbnNpb24gQ2hlY2sKClRha2UgYSBsb29rIGF0IG91ciBgZm9ydW1zX2R0bWAgb2JqZWN0IGluIHRoZSBjb25zb2xlIGFuZCBhbnN3ZXIgdGhlCmZvbGxvd2luZyBxdWVzdGlvbjoKCjEuICBXaGF0ICJjbGFzcyIgb2Ygb2JqZWN0IGlzIGBmb3J1bXNfZHRtYD8KMi4gIEhvdyBtYW55IHVuaXF1ZSBkb2N1bWVudHMgYW5kIHRlcm1zIGFyZSBpbmNsdWRlZCBvdXIgbWF0cml4PwozLiAgV2h5IG1pZ2h0IHRoZXJlIGJlIGZld2VyIGRvY3VtZW50cy9wb3N0cyB0aGFuIHdlcmUgaW4gb3VyIG9yaWdpbmFsCiAgICBkYXRhIGZyYW1lPwo0LiAgV2hhdCBleGFjdGx5IGlzIG1lYW50IGJ5ICJzcGFyc2l0eSI/CgpgYGB7ciBjbGFzcy1kdG0sIGVjaG89RkFMU0V9CmNsYXNzKGZvcnVtc19kdG0pCgpmb3J1bXNfZHRtCmBgYAoKIyMjIDJjLiBUbyBTdGVtIG9yIG5vdCB0byBTdGVtPwoKTmV4dCB3ZSdsbCBuZWVkIHRvIHByZXBhcmUgb3VyIG9yaWdpbmFsIGRhdGEgc2V0IGZvciBzdHJ1Y3R1cmFsIHRvcGljCm1vZGVsaW5nIHVzaW5nIHRoZSBgdGV4dFByb2Nlc3NvcigpYCBmdW5jdGlvbi4gVGhlIGBzdG1gIHBhY2thZ2UgaGFzIGEKbnVtYmVyIG9mIGZlYXR1cmVzIHRoYXQgZXh0ZW5kIHRoZSBmdW5jdGlvbmFsaXR5IG9mIHRoZSBgdG9waWNtb2RlbHNgCnBhY2thZ2UsIGluY2x1ZGluZyBhbiBhcmd1bWVudCBmb3IgInN0ZW1taW5nIiB3b3Jkcywgd2hpY2ggW1NjaG9maWVsZAphbmQgTWltbm8KKDIwMTYpXShodHRwczovL2RpcmVjdC5taXQuZWR1L3RhY2wvYXJ0aWNsZS9kb2kvMTAuMTE2Mi90YWNsX2FfMDAwOTkvNDMzNzAvQ29tcGFyaW5nLUFwcGxlcy10by1BcHBsZS1UaGUtRWZmZWN0cy1vZi1TdGVtbWVycykKZGVzY3JpYmUgYXMgZm9sbG93czoKCj4gU3RlbW1pbmcgaXMgYSBwb3B1bGFyIHdheSB0byByZWR1Y2UgdGhlIHNpemUgb2YgYSB2b2NhYnVsYXJ5IGluCj4gbmF0dXJhbCBsYW5ndWFnZSB0YXNrcyBieSBjb25mbGF0aW5nIHdvcmRzIHdpdGggcmVsYXRlZCBtZWFuaW5ncy4KPiBTcGVjaWZpY2FsbHksIHN0ZW1taW5nIGFpbXMgdG8gY29udmVydCB3b3JkcyB3aXRoIHRoZSBzYW1lICJzdGVtIiBvcgo+IHJvb3QgKGUuZyAiY3JlYXRpdmUiIGFuZCAiY3JlYXRvciIpIHRvIGEgc2luZ2xlIHdvcmQgdHlwZSAoImNyZWF0ZSIpLgo+IFRob3VnaCBvcmlnaW5hbGx5IGRldmVsb3BlZCBpbiB0aGUgY29udGV4dCBvZiBpbmZvcm1hdGlvbiByZXRyaWV2YWwKPiAoSVIpIHN5c3RlbXMsIHN0ZW1tZXJzIGFyZSBub3cgY29tbW9ubHkgdXNlZCBhcyBhIHByZXByb2Nlc3Npbmcgc3RlcAo+IGluIHVuc3VwZXJ2aXNlZCBtYWNoaW5lIGxlYXJuaW5nIHRhc2tzLgoKVGhlIHJhdGlvbmFsZSBiZWhpbmQgc3RlbW1pbmcgaXMgdGhhdCBpdCBjYW4gZHJhbWF0aWNhbGx5IHJlZHVjZSB0aGUKbnVtYmVyIG9mIHdvcmRzIG9yIHRlcm1zIHRvIGJlIG1vZGVsZWQsIHdoaWNoIGluIHRoZW9yeSBzaG91bGQgaGVscApzaW1wbGlmeSBhbmQgaW1wcm92ZSB0aGUgcGVyZm9ybWFuY2Ugb2YgeW91ciBtb2RlbC4gV2UnbGwgZXhwbG9yZSB0aGlzCmFzc3VtcHRpb24gYSBsaXR0bGUgbGF0ZXIgaW4gdGhpcyBzZWN0aW9uLgoKIyMjIyBQcm9jZXNzaW5nIGFuZCBTdGVtbWluZyBmb3IgU1RNCgpMaWtlIGB1bm5lc3RfdG9rZW5zKClgLCB0aGUgYHRleHRQcm9jZXNzb3IoKWAgZnVuY3Rpb24gaW5jbHVkZXMgc2V2ZXJhbAp1c2VmdWwgYXJndW1lbnRzIGZvciBwcm9jZXNzaW5nIHRleHQgbGlrZSBjb252ZXJ0aW5nIHRleHQgdG8gbG93ZXJjYXNlCmFuZCByZW1vdmluZyBwdW5jdHVhdGlvbiBhbmQgbnVtYmVycy4gSSd2ZSBpbmNsdWRlZCBzZXZlcmFsIG9mIHRoZXNlIGluCnRoZSBzY3JpcHQgYmVsb3cgYWxvbmcgd2l0aCB0aGVpciBkZWZhdWx0cyB1c2VkIGlmIHlvdSBkbyBub3QgZXhwbGljaXRseQpzcGVjaWZ5IGluIHlvdXIgZnVuY3Rpb24uIE1vc3Qgb2YgdGhlc2UgYXJlIHByZXR0eSBpbnR1aXRpdmUgYW5kIHlvdSBjYW4KbGVhcm4gbW9yZSBieSB2aWV3aW5nIHRoZSBgP3RleHRQcm9jZXNzb3JgIGRvY3VtZW50YXRpb24uCgpMZXQncyBnbyBhaGVhZCBhbmQgcHJvY2VzcyBvdXIgZGlzY3Vzc2lvbiBmb3J1bSBgcG9zdF9jb250ZW50YCBpbgpwcmVwYXJhdGlvbiBmb3Igc3RydWN0dXJhbCB0b3BpYyBtb2RlbGluZzoKCmBgYHtyIHRleHRQcm9jZXNzb3J9CnRlbXAgPC0gdGV4dFByb2Nlc3Nvcih0c19mb3J1bV9kYXRhJHBvc3RfY29udGVudCwgCiAgICAgICAgICAgICAgICAgICAgbWV0YWRhdGEgPSB0c19mb3J1bV9kYXRhLCAgCiAgICAgICAgICAgICAgICAgICAgbG93ZXJjYXNlPVRSVUUsIAogICAgICAgICAgICAgICAgICAgIHJlbW92ZXN0b3B3b3Jkcz1UUlVFLCAKICAgICAgICAgICAgICAgICAgICByZW1vdmVudW1iZXJzPVRSVUUsICAKICAgICAgICAgICAgICAgICAgICByZW1vdmVwdW5jdHVhdGlvbj1UUlVFLCAKICAgICAgICAgICAgICAgICAgICB3b3JkTGVuZ3Rocz1jKDMsSW5mKSwKICAgICAgICAgICAgICAgICAgICBzdGVtPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgb25seWNoYXJhY3Rlcj0gRkFMU0UsIAogICAgICAgICAgICAgICAgICAgIHN0cmlwaHRtbD1UUlVFLCAKICAgICAgICAgICAgICAgICAgICBjdXN0b21zdG9wd29yZHM9TlVMTCkKYGBgCgpOb3RlIHRoYXQgdGhlIGZpcnN0IGFyZ3VtZW50IHRoZSBgdGV4dFByb2Nlc3NvcmAgZnVuY3Rpb24gZXhwZWN0cyBpcyB0aGUKY29sdW1uIGluIG91ciBkYXRhIGZyYW1lIHRoYXQgY29udGFpbnMgdGhlIHRleHQgdG8gYmUgcHJvY2Vzc2VkLCB0aGUKc2Vjb25kIGFyZ3VtZW50IGBtZXRhZGF0YSA9YCBleHBlY3RzIHRoZSBkYXRhIGZyYW1lIHRoYXQgY29udGFpbnMgdGhlCnRleHQgb2YgaW50ZXJlc3QgYW5kIHVzZXMgdGhlIGNvbHVtbiBuYW1lcyB0byBsYWJlbCB0aGUgbWV0YWRhdGEgc3VjaCBhcwpjb3Vyc2UgaWRzIGFuZCBmb3J1bSBuYW1lcy4gVGhpcyBtZWF0ZGF0YSBjYW4gYmUgdXNlZCB0byB0byBpbXByb3ZlIHRoZQphc3NpZ25tZW50IG9mIHdvcmRzIHRvIHRvcGljcyBpbiBhIGNvcnB1cyBhbmQgZXhhbWluZSB0aGUgcmVsYXRpb25zaGlwCmJldHdlZW4gdG9waWNzIGFuZCB2YXJpb3VzIGNvdmFyaWF0ZXMgb2YgaW50ZXJlc3QuCgpVbmxpa2UgdGhlIGB1bm5lc3RfdG9rZW5zKClgIGZ1bmN0aW9uLCB0aGUgb3V0cHV0IGlzIG5vdCBhIG5pY2UgdGlkeQpkYXRhIGZyYW1lLiBUb3BpYyBtb2RlbGluZyB1c2luZyB0aGUgYHN0bWAgcGFja2FnZSByZXF1aXJlcyBhIHZlcnkKdW5pcXVlIHNldCBvZiBpbnB1dHMgdGhhdCBhcmUgc3BlY2lmaWMgdG8gdGhlIHBhY2thZ2UuIFRoZSBmb2xsb3dpbmcKY29kZSB3aWxsIHB1bGwgZWxlbWVudHMgZnJvbSB0aGUgYHRlbXBgIGxpc3QgdGhhdCB3YXMgY3JlYXRlZCB0aGF0IHdpbGwKYmUgcmVxdWlyZWQgZm9yIHRoZSBgc3RtKClgIGZ1bmN0aW9uIHdlJ2xsIHVzZSBpbiBTZWN0aW9uIDQ6CgpgYGB7ciBzdG0taW5wdXRzfQptZXRhIDwtIHRlbXAkbWV0YQp2b2NhYiA8LSB0ZW1wJHZvY2FiCmRvY3MgPC0gdGVtcCRkb2N1bWVudHMKYGBgCgojIyMjIFN0ZW1taW5nIFRpZHkgVGV4dAoKTm90aWNlIHRoYXQgdGhlIGB0ZXh0UHJvY2Vzc29yYCBzdGVtIGFyZ3VtZW50IHdlIHVzZWQgYWJvdmUgaXMgc2V0IHRvCmBUUlVFYCBieSBkZWZhdWx0LiBXZSBoYXZlbid0IGludHJvZHVjZWQgd29yZCBzdGVtbWluZyBhdCB0aGlzIHBvaW50CmJlY2F1c2UgdGhlcmUgaXMgc29tZSBkZWJhdGUgYWJvdXQgdGhlIGFjdHVhbCB2YWx1ZSBvZiB0aGlzIHByb2Nlc3MuCldoaWxlIHdvcmRzIGxpa2UgInN0dWRlbnRzIiBhbmQgInN0dWRlbnQiIG1pZ2h0IG1ha2Ugc2Vuc2UgdG8gY29sbGFwc2UKaW50byB0aGVpciBiYXNlIHdvcmQgYW5kIGFjdHVhbGx5IG1ha2UgYW5hbHlzZXMgYW5kIHZpc3VhbGl6YXRpb25zIG1vcmUKY29uY2lzZSBhbmQgZWFzaWVyIHRvIGludGVycHJldC4gW0h2aXRmZWxkdCBhbmQgU2lsZ2UKKDIwMjEpXShodHRwczovL3NtbHRhci5jb20vc3RlbW1pbmcuaHRtbCkgbm90ZSwgaG93ZXZlciwgdGhhdCB3b3JkcyBsaWtlCnRoZSBmb2xsb3dpbmcgaGF2ZSBkcmFtYXRpYyBkaWZmZXJlbmNlcyBpbiBtZWFuaW5nLCBzZW1hbnRpY3MsIGFuZCB1c2UKYW5kIGNvdWxkIHJlc3VsdCBpbiBwb29yIG1vZGVscyBvciBtaXNpbnRlcnByZXRlZCByZXN1bHRzOgoKLSAgIG1lYW5pbmcgYW5kIG1lYW4KLSAgIGxpa2VseSwgbGlrZSwgbGlraW5nCi0gICB1bml2ZXJzaXR5IGFuZCB1bml2ZXJzZQoKVGhlIGZpcnN0IHdvcmQgcGFpciBpcyBwYXJ0aWN1bGFybHkgcmVsZXZhbnQgdG8gZGlzY3Vzc2lvbiBwb3N0cyBmcm9tCm91ciBUZWFjaGluZyBTdGF0aXN0aWNzIGNvdXJzZSBkYXRhLiBJbiBhZGRpdGlvbiwgY29sbGFwc2luZyB3b3JkcyBsaWtlCiJ0ZWFjaGVycyIgYW5kICJ0ZWFjaGluZyIgY291bGQgZHJhbWF0aWNhbGx5IGFsdGVyIHRoZSByZXN1bHRzIGZyb20gYQp0b3BpYyBtb2RlbC4KCltTY2hvZmllbGQgYW5kIE1pbW5vCigyMDE2KV0oaHR0cHM6Ly9kaXJlY3QubWl0LmVkdS90YWNsL2FydGljbGUvZG9pLzEwLjExNjIvdGFjbF9hXzAwMDk5LzQzMzcwL0NvbXBhcmluZy1BcHBsZXMtdG8tQXBwbGUtVGhlLUVmZmVjdHMtb2YtU3RlbW1lcnMpCnNwZWNpZmljYWxseSwKCj4gKkRlc3BpdGUgdGhlaXIgZnJlcXVlbnQgdXNlIGluIHRvcGljIG1vZGVsaW5nLCB3ZSBmaW5kIHRoYXQgc3RlbW1lcnMKPiBwcm9kdWNlIG5vIG1lYW5pbmdmdWwgaW1wcm92ZW1lbnQgaW4gbGlrZWxpaG9vZCBhbmQgY29oZXJlbmNlIGFuZCBpbgo+IGZhY3QgY2FuIGRlZ3JhZGUgdG9waWMgc3RhYmlsaXR5LioKCkZvciBub3csIHdlIHdpbGwgbGVhdmUgYXMgaXMgdGhlIGBmb3J1bXNfZHRtYCB3ZSBjcmVhdGVkIGVhcmxpZXIgd2l0aAp3b3JkcyB1bnN0ZW1tZWQsIGJ1dCB3aGF0IGlmIHdlIHdhbnRlZCB0byBzdGVtIHdvcmRzIGluIGEgInRpZHkiIHdheT8KClNpbmNlIHRoZSBgdW5uZXN0X3Rva2VucygpYCBmdW5jdGlvbiBkb2VzIG5vdCAoaW50ZW50aW9uYWxseSBJIGJlbGlldmUpCmluY2x1ZGUgYSBzdGVtbWluZyBmdW5jdGlvbiwgb25lIGFwcHJvYWNoIHdvdWxkIGJlIHRvIHVzZSB0aGUKYHdvcmRTdGVtKClgIGZ1bmN0aW9uIGZyb20gdGhlIGBzbm93YmFsbENgIHBhY2thZ2UgdG8gZWl0aGVyIHJlcGxhY2Ugb3VyCmB3b3Jkc2AgY29sdW1uIHdpdGggYSB3b3JkIHN0ZW1zIG9yIGNyZWF0ZSBhIG5ldyB2YXJpYWJsZSBjYWxsZWQgYHN0ZW1gCndpdGggb3VyIHN0ZW1tZWQgd29yZHMuIExldCdzIGRvIHRoZSBsYXR0ZXIgYW5kIHRha2UgYSBsb29rIGF0IHRoZQpvcmlnaW5hbCB3b3JkcyBhbmQgdGhlIHN0ZW0gdGhhdCB3YXMgcHJvZHVjZWQ6CgpgYGB7ciB3b3JkU3RlbX0Kc3RlbW1lZF9mb3J1bXMgPC0gdHNfZm9ydW1fZGF0YSAlPiUKICB1bm5lc3RfdG9rZW5zKG91dHB1dCA9IHdvcmQsIGlucHV0ID0gcG9zdF9jb250ZW50KSAlPiUKICBhbnRpX2pvaW4oc3RvcF93b3JkcywgYnkgPSAid29yZCIpICU+JQogIG11dGF0ZShzdGVtID0gd29yZFN0ZW0od29yZCkpCgpzdGVtbWVkX2ZvcnVtcwpgYGAKCllvdSBjYW4gc2VlIHRoYXQgd29yZHMgbGlrZSAiYWN0aXZpdHkiIGFuZCAiYWN0aXZpdGllcyIgdGhhdCBvY2N1cgpmcmVxdWVudGx5IGluIG91ciBkaXNjdXNzaW9ucyBoYXZlIGJlZW4gcmVkdWNlZCB0byB0aGUgd29yZCBzdGVtCiJhY3RpdiIuIElmIHlvdSBhcmUgaW50ZXJlc3RlZCBpbiBsZWFybmluZyBvdGhlciBhcHByb2FjaGVzIGZvciB3b3JkCnN0ZW1taW5nIGluIFIsIGFzIHdlbGwgYXMgcmVhZGluZyBhIG1vcmUgaW4gZGVwdGggZGVzY3JpcHRpb24gb2YgdGhlCnN0ZW1taW5nIHByb2Nlc3MsIEkgaGlnaGx5IHJlY29tbWVuZCB0aGUgW0NoYXB0ZXIgNApTdGVtbWluZ10oaHR0cHM6Ly9zbWx0YXIuY29tL3N0ZW1taW5nLmh0bWwpIGZyb20gSHZpdGZlbGR0IGFuZCBTaWxnZQooMjAyMSkgYm9vaywgKlN1cGVydmlzZWQgTWFjaGluZSBMZWFybmluZyBmb3IgVGV4dCBBbmFseXNpcyBpbiBSKi4KCiMjIyMjIOKchSBDb21wcmVoZW5zaW9uIENoZWNrCgpDb21wbGV0ZSB0aGUgZm9sbG93aW5nIGNvZGUgdXNpbmcgd2hhdCB3ZSBsZWFybmVkIGluIHRoZSBzZWN0aW9uIG9uCltDcmVhdGluZyBhIERvY3VtZW50IFRlcm0gTWF0cml4XSBhbmQgYW5zd2VyIHRoZSBmb2xsb3dpbmcgcXVlc3Rpb25zOgoKMS4gIEhvdyBtYW55IGZld2VyIHRlcm1zIGFyZSBpbiBvdXIgc3RlbW1lZCBkb2N1bWVudCB0ZXJtIG1hdHJpeD8KMi4gIERpZCBzdGVtbWluZyB3b3JkcyBzaWduaWZpY2FudGx5IHJlZHVjZSB0aGUgc3BhcnNpdHkgb2YgdGhlIG5ldHdvcms/CgoqKkhpbnQ6KiogTWFrZSBzdXJlIHlvdXIgY29kZSBpbmNsdWRlcyBzdGVtIGNvdW50cyByYXRoZXIgdGhhbiB3b3JkCmNvdW50cy4KCmBgYHtyIHN0ZW0tcHJhY3RpY2UsIGV2YWw9RkFMU0V9CnN0ZW1tZWRfZHRtIDwtIHRzX2ZvcnVtX2RhdGEgJT4lCiAgdW5uZXN0X3Rva2VucyhvdXRwdXQgPSB3b3JkLCBpbnB1dCA9IHBvc3RfY29udGVudCkgJT4lCiAgYW50aV9qb2luKHN0b3Bfd29yZHMsIGJ5ID0gIndvcmQiKSAlPiUKICBtdXRhdGUoc3RlbSA9IHdvcmRTdGVtKHdvcmQpKSAlPiUKIGNvdW50KHBvc3RfaWQsIHN0ZW0sIHNvcnQgPSBUUlVFKSAlPiUKICBjYXN0X2R0bShwb3N0X2lkLCBzdGVtLCBuKQogIApzdGVtbWVkX2R0bQpgYGAKCmBgYHtyIHN0ZW0tY291bnRzLCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQpzdGVtbWVkX2R0bSA8LSB0c19mb3J1bV9kYXRhICU+JQogIHVubmVzdF90b2tlbnMob3V0cHV0ID0gd29yZCwgaW5wdXQgPSBwb3N0X2NvbnRlbnQpICU+JQogIGFudGlfam9pbihzdG9wX3dvcmRzLCBieSA9ICJ3b3JkIikgJT4lCiAgbXV0YXRlKHN0ZW0gPSB3b3JkU3RlbSh3b3JkKSkgJT4lCiAgY291bnQocG9zdF9pZCwgc3RlbSwgc29ydCA9IFRSVUUpICU+JQogIGNhc3RfZHRtKHBvc3RfaWQsIHN0ZW0sIG4pCgpzdGVtbWVkX2R0bQpmb3J1bXNfZHRtCgpzdGVtX2NvdW50cyA8LSB0c19mb3J1bV9kYXRhICU+JQogIHVubmVzdF90b2tlbnMob3V0cHV0ID0gd29yZCwgaW5wdXQgPSBwb3N0X2NvbnRlbnQpICU+JQogIGFudGlfam9pbihzdG9wX3dvcmRzLCBieSA9ICJ3b3JkIikgJT4lCiAgbXV0YXRlKHN0ZW0gPSB3b3JkU3RlbSh3b3JkKSkgJT4lCiAgY291bnQoc3RlbSwgc29ydCA9IFRSVUUpCgpzdGVtX2NvdW50cwpgYGAKCiMjIDMuIE1PREVMCgpUaGlzIHVuaXQgcHJvdmlkZXMgb3VyIGZpcnN0IG9wcG9ydHVuaXR5IGZvciBtb2RlbGluZyBhIHRleHQgYXMgZGF0YS4gSW4KdmVyeSBzaW1wbGUgdGVybXMsIG1vZGVsaW5nIGludm9sdmVzIGRldmVsb3BpbmcgYSBtYXRoZW1hdGljYWwgc3VtbWFyeQpvZiBhIGRhdGFzZXQuIFRoZXNlIHN1bW1hcmllcyBjYW4gaGVscCB1cyBmdXJ0aGVyIGV4cGxvcmUgdHJlbmRzIGFuZApwYXR0ZXJucyBpbiBvdXIgZGF0YS4KCkluIHRoZWlyIGJvb2ssICpMZWFybmluZyBBbmFseXRpY3MgR29lcyB0byBTY2hvb2wsKiBLcnVtbSBhbmQgTWVhbnMKKDIwMTgpIGRlc2NyaWJlIHR3byBnZW5lcmFsIHR5cGVzIG9mIG1vZGVsaW5nIGFwcHJvYWNoZXMgdXNlZCBpbiB0aGUKRGF0YS1JbnRlbnNpdmUgUmVzZWFyY2ggd29ya2Zsb3c6IHVuc3VwZXJ2aXNlZCBhbmQgc3VwZXJ2aXNlZCBtYWNoaW5lCmxlYXJuaW5nLiBJbiBkaXN0aW5ndWlzaGluZyBiZXR3ZWVuIHRoZSB0d28sIHRoZXkgbm90ZToKCj4gKlVuc3VwZXJ2aXNlZCBsZWFybmluZyBhbGdvcml0aG1zIGNhbiBiZSB1c2VkIHRvIHVuZGVyc3RhbmQgdGhlCj4gc3RydWN0dXJlIG9mIG9uZSdzIGRhdGFzZXQuIFN1cGVydmlzZWQgbW9kZWxzLCBvbiB0aGUgb3RoZXIgaGFuZCwgaGVscAo+IHRvIHF1YW50aWZ5IHJlbGF0aW9uc2hpcHMgYmV0d2VlbiBmZWF0dXJlcyBhbmQgYSBrbm93biBvdXRjb21lLiBLbm93bgo+IG91dGNvbWVzIGFyZSBhbHNvIGNvbW1vbmx5IHJlZmVycmVkIHRvIGFzIGxhYmVscyBvciBkZXBlbmRlbnQKPiB2YXJpYWJsZXMuKgoKSW4gU2VjdGlvbiAzIHdlIGZvY3VzIG9uIFRvcGljIE1vZGVsaW5nLCBhbiB1bnN1cGVydmlzZWQgbGVhcm5pbmcKYXBwcm9hY2ggdG8gYXV0b21hdGljYWxseSBpZGVudGlmeSB0b3BpY3MgaW4gYSBjb2xsZWN0aW9uIG9mIGRvY3VtZW50cy4KSW4gZmFjdCwgd2UnbGwgZXhwbG9yZSB0d28gZGlmZmVyZW50IGFwcHJvYWNoZXMgdG8gdG9waWMgbW9kZWxpbmcsIGFzCndlbGwgYXMgc3RyYXRlZ2llcyBmb3IgaWRlbnRpZnlpbmcgdGhlICJyaWdodCIgbnVtYmVyIG9mIHRvcGljczoKCmEuICAqKkZpdHRpbmcgYSBUb3BpYyBNb2RlbGluZyB3aXRoIExEQSoqLiBJbiB0aGlzIHNlY3Rpb24gd2UgbGVhcm4gdG8KICAgIHVzZSB0aGUgYHRvcGljbW9kZWxzYCBwYWNrYWdlIGFuZCBhc3NvY2lhdGVkIGBMREEoKWAgZnVuY3Rpb24gZm9yCiAgICB1bnN1cGVydmlzZWQgY2xhc3NpZmljYXRpb24gb2Ygb3VyIGZvcnVtIGRpc2N1c3Npb25zIHRvIGZpbmQgbmF0dXJhbAogICAgZ3JvdXBpbmdzIG9mIHdvcmRzLCBvciB0b3BpY3MuCmIuICAqKkZpdHRpbmcgYSBTdHJ1Y3R1cmFsIFRvcGljIE1vZGVsKiouIFdlIHRoZW4gZXhwbG9yZSB0aGUgdXNlIG9mIHRoZQogICAgYHN0bWAgcGFja2FnZSBhbmQgYHN0bSgpYCBmdW5jdGlvbiB0byBmaXQgb3VyIG1vZGVsIGFuZCB1c2VzCiAgICBtZXRhZGF0YSBhYm91dCBkb2N1bWVudHMgdG8gaW1wcm92ZSB0aGUgYXNzaWdubWVudCBvZiB3b3JkcyB0bwogICAgInRvcGljcyIgaW4gYSBjb3JwdXMuCmMuICAqKkNob29zaW5nIEsuKiogRmluYWxseSwgd2Ugd3JhcCB1cCBTZWN0aW9uIDMgYnkgbGVhcm5pbmcgYWJvdXQKICAgIGRpYWdub3N0aWMgcHJvcGVydGllcyBsaWtlIGV4Y2x1c2l2aXR5LCBzZW1hbnRpYyBjb2hlcmVuY2UsIGFuZAogICAgaGVsZG91dCBsaWtlbGlob29kIGZvciBoZWxwaW5nIHRvIHNlbGVjdCBhbiBhcHByb3ByaWF0ZSBudW1iZXIgb2YKICAgIHRvcGljcy4KCiMjIyAzYS4gRml0dGluZyBhIFRvcGljIE1vZGVsaW5nIHdpdGggTERBCgpCZWZvcmUgcnVubmluZyBvdXIgZmlyc3QgdG9waWMgbW9kZWwgdXNpbmcgdGhlIGBMREEoKWAgZnVuY3Rpb24sIGxldCdzCnF1aWNrIHJlY2FwIGZyb20gb3VyIHJlYWRpbmdzIHNvbWUgYmFzaWMgcHJpbmNpcGxlcyBiZWhpbmQgTGF0ZW50CkRpcmljaGxldCBhbGxvY2F0aW9uIGFuZCB3aHkgTERBIGlzIG9mIHByZWZlcnJlZCBvdmVyIG90aGVyIGF1dG9tYXRpYwpjbGFzc2lmaWNhdGlvbiBvciBjbHVzdGVyaW5nIGFwcHJvYWNoZXMuCgpVbmxpa2Ugc2ltcGxlIGZvcm1zIG9mIGNsdXN0ZXIgYW5hbHlzaXMgc3VjaCBhcyBrLW1lYW5zIGNsdXN0ZXJpbmcsIExEQQppcyBhICoqIm1peHR1cmUiIG1vZGVsKiosIHdoaWNoIGluIG91ciBjb250ZXh0IG1lYW5zIHRoYXQ6CgoxLiAgKipFdmVyeSBbZG9jdW1lbnRdey51bmRlcmxpbmV9IGNvbnRhaW5zIGEgbWl4dHVyZSBvZiB0b3BpY3MuKioKICAgIFVubGlrZSBhbGdvcml0aG1zIGxpa2Ugay1tZWFucywgTERBIHRyZWF0cyBlYWNoIGRvY3VtZW50IGFzIGEKICAgIG1peHR1cmUgb2YgdG9waWNzLCB3aGljaCBhbGxvd3MgZG9jdW1lbnRzIHRvICJvdmVybGFwIiBlYWNoIG90aGVyIGluCiAgICB0ZXJtcyBvZiBjb250ZW50LCByYXRoZXIgdGhhbiBiZWluZyBzZXBhcmF0ZWQgaW50byBkaXNjcmV0ZSBncm91cHMuCiAgICBTbyBpbiBwcmFjdGljZSwgdGhpcyBtZWFucyB0aGF0IGEgZGlzY3Vzc2lvbiBmb3J1bSBwb3N0IGNvdWxkIGhhdmUKICAgIGFuIGVzdGltYXRlZCB0b3BpYyBwcm9wb3J0aW9uIG9mIDcwJSBmb3IgVG9waWMgMSAoZS5nLiBiZSBtb3N0bHkKICAgIGFib3V0IGEgVG9waWMgMSksIGJ1dCBhbHNvIGJlIHBhcnRseSBhYm91dCBUb3BpYyAyLgoyLiAgKipFdmVyeSBbdG9waWNdey51bmRlcmxpbmV9IGNvbnRhaW5zIGEgbWl4dHVyZSBvZiB3b3Jkcy4qKsKgRm9yCiAgICBleGFtcGxlLCBpZiB3ZSBzcGVjaWZpZWQgaW4gb3VyIExEQSBtb2RlbCBqdXN0IDIgdG9waWNzIGZvciBvdXIKICAgIGRpc2N1c3Npb24gcG9zdHMsIHdlIG1pZ2h0IGZpbmQgdGhhdCBvbmUgdG9waWMgc2VlbXMgdG8gYmUgYWJvdXQKICAgIHBlZGFnb2d5IHdoaWxlIGFub3RoZXIgaXMgYWJvdXQgbGVhcm5pbmcuIFRoZSBtb3N0IGNvbW1vbiB3b3JkcyBpbgogICAgdGhlIHBlZGFnb2d5IHRvcGljIG1pZ2h0IGJlICJ0ZWFjaGVyIiwgInN0cmF0ZWdpZXMiLCBhbmQKICAgICJpbnN0cnVjdGlvbiIsIHdoaWxlIHRoZSBsZWFybmluZyB0b3BpYyBtYXkgYmUgbWFkZSB1cCBvZiB3b3JkcyBsaWtlCiAgICAidW5kZXJzdGFuZGluZyIgYW5kICJzdHVkZW50cyIuIEhvd2V2ZXIsIHdvcmRzIGNhbiBiZSBzaGFyZWQgYmV0d2VlbgogICAgdG9waWNzIGFuZCB3b3JkcyBsaWtlICJzdGF0aXN0aWNzIiBvciAiYXNzZXNzbWVudCIgbWlnaHQgYXBwZWFyIGluCiAgICBib3RoIGVxdWFsbHkuCgpTaW1pbGFyIHRvIGstbWVhbnMgb3RoZXIgb3RoZXIgc2ltcGxlIGNsdXN0ZXJpbmcgYXBwcm9hY2hlcywgaG93ZXZlciwKTERBIGRvZXMgcmVxdWlyZSB1cyB0byBzcGVjaWZ5IGEgdmFsdWUgb2YgKmsqIGZvciB0aGUgbnVtYmVyIG9mIHRvcGljcwppbiBvdXIgY29ycHVzLiBTZWxlY3RpbmcgKmsqIGlzIG5vIHRyaXZpYWwgbWF0dGVyIGFuZCBjYW4gZ3JlYXRseSBpbXBhY3QKeW91ciByZXN1bHRzLgoKU2luY2Ugd2UgZG9uJ3QgaGF2ZSBhIGhhdmUgc3Ryb25nIHJhdGlvbmFsZSBhYm91dCB0aGUgbnVtYmVyIG9mIHRvcGljcwp0aGF0IG1pZ2h0IGV4aXN0IGluIGRpc2N1c3Npb24gZm9ydW1zLCBsZXQncyB1c2UgdGhlIGBuX2Rpc3RpbmN0KClgCmZ1bmN0aW9uIGZyb20gdGhlIGBkcGx5cmAgcGFja2FnZSB0byBmaW5kIHRoZSBudW1iZXIgb2YgdW5pcXVlIGZvcnVtCm5hbWVzIGluIG91ciBjb3Vyc2UgZGF0YSBhbmQgcnVuIHdpdGggdGhhdDoKCmBgYHtyIG4tZGlzdGluY3R9Cm5fZGlzdGluY3QodHNfZm9ydW1fZGF0YSRmb3J1bV9uYW1lKQpgYGAKClNpbmNlIGl0IGxvb2tzIGxpa2UgdGhlcmUgYXJlIDIwIGRpc3RpbmN0IGRpc2N1c3Npb24gZm9ydW1zLCB3ZSdsbCB1c2UKdGhhdCBhcyBvdXIgdmFsdWUgZm9yIHRoZSBgayA9YCBhcmd1bWVudCBvZiB0aGUgYExEQSgpYC4gQmUgcGF0aWVudAp3aGlsZSB0aGlzIHJ1bnMsIHNpbmNlIHRoZSBkZWZhdWx0IHNldHRpbmcgb2YgaXMgdG8gcGVyZm9ybSBhIGxhcmdlCm51bWJlciBvZiBpdGVyYXRpb25zLgpJIGNoYW5nZWQgdGhlIG51bWJlciBvZiBpdGVyYXRpb25zIGZyb20gMjAwMCB0byA1MDAgdG8gbWFrZSBpdCBydW4gZmFzdGVyLgoKYGBge3IgTERBfQpuX2Rpc3RpbmN0KHRzX2ZvcnVtX2RhdGEkZm9ydW1fbmFtZSkKCmZvcnVtc19sZGEgPC0gTERBKGZvcnVtc19kdG0sIAogICAgICAgICAgICAgICAgICBrID0gMjAsCiAgICAgICAgICAgICAgICAgIGl0ZXI9NTAwLCN0byBtYWtlIGl0IHJ1biBmYXN0ZXIKICAgICAgICAgICAgICAgICAgY29udHJvbCA9IGxpc3Qoc2VlZCA9IDU4OCkKICAgICAgICAgICAgICAgICAgKQoKZm9ydW1zX2xkYQpgYGAKCk5vdGUgdGhhdCB3ZSB1c2VkIHRoZSBgY29udHJvbCA9YCBhcmd1bWVudCB0byBwYXNzIGEgcmFuZG9tIG51bWJlcgooYDU4OGApIHRvIHNlZWQgdGhlIGFzc2lnbm1lbnQgb2YgdG9waWNzIHRvIGVhY2ggd29yZCBpbiBvdXIgY29ycHVzLgpTaW5jZSBMREEgaXMgYSBbc3RvY2hhc3RpYwphbGdvcml0aG1dKGh0dHBzOi8vbWFjaGluZWxlYXJuaW5nbWFzdGVyeS5jb20vc3RvY2hhc3RpYy1pbi1tYWNoaW5lLWxlYXJuaW5nLykKdGhhdCBjb3VsZCBoYXZlIGRpZmZlcmVudCByZXN1bHRzIGRlcGVuZGluZyBvbiB3aGVyZSB0aGUgYWxnb3JpdGhtCnN0YXJ0cywgc3BlY2lmaWVkIGEgYHNlZWRgIGZvciByZXByb2R1Y2liaWxpdHkgYW5kIHNvIHdlJ3JlIGFsbCBzZWVpbmcKdGhlIHNhbWUgcmVzdWx0cyBldmVyeSB0aW1lIHdlIHNwZWNpZnkgdGhlIHNhbWUgbnVtYmVyIG9mIHRvcGljcy4KCkFuZCB0eWluZyBiYWNrIHRvIG91ciB3b3JrIGluIFVuaXQgMSwgQmFpbCAoMjAyMCkgbm90ZXMgdGhhdCB0b3BpYwphc3NpZ25tZW50cyBmb3IgZWFjaCB3b3JkIGFyZSB1cGRhdGVkIGluIGFuIGl0ZXJhdGl2ZSBmYXNoaW9uIGFuZCB0aGF0CkxEQSBlbXBsb3lzIHRoZSBUZXJtIEZyZXF1ZW5jeS1JbnZlcnNlIERvY3VtZW50IEZyZXF1ZW5jeSAoVEYtSURGKQptZXRyaWMgdG8gYXNzaWduIHByb2JhYmlsaXRpZXMuCgojIyMgM2IuIEZpdHRpbmcgYSBTdHJ1Y3R1cmFsIFRvcGljIE1vZGVsCgpCYWlsIG5vdGVzIHRoYXQgTERBLCB3aGlsZSBwZXJoYXBzIHRoZSBtb3N0IGNvbW1vbiBhcHByb2FjaCB0byB0b3BpYwptb2RlbGluZywgaXMganVzdCBvbmUgb2YgbWFueSBkaWZmZXJlbnQgdHlwZXMsIGluY2x1ZGluZyBEeW5hbWljIFRvcGljCk1vZGVscywgQ29ycmVsYXRlZCBUb3BpYyBNb2RlbHMsIEhpZXJhcmNoaWNhbCBUb3BpYyBNb2RlbHMsIGFuZCBtb3JlCnJlY2VudGx5LCBTdHJ1Y3R1cmFsIFRvcGljIE1vZGVsaW5nIChTVE0pLiBIZSBhcmd1ZXMgdGhhdCBvbmUgcmVhc29uIFNUTQpoYXMgcmlzaW5nIGluIHBvcHVsYXJpdHkgYW5kIHVzZSBpcyB0aGF0IGl0IGVtcGxveXMgbWV0YSBkYXRhIGFib3V0CmRvY3VtZW50cyB0byBpbXByb3ZlIHRoZSBhc3NpZ25tZW50IG9mIHdvcmRzIHRvIHRvcGljcyBpbiBhIGNvcnB1cyBhbmQKdGhhdCBjYW4gYmUgdXNlZCB0byBleGFtaW5lIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiBjb3ZhcmlhdGVzIGFuZApkb2N1bWVudHMuwqAKCkFsc28sIHNpbmNlIEp1bGlhIFNpbGdlIGhhcyBpbmRpY2F0ZWQgdGhhdCBTVE0gaXMsICJteSBjdXJyZW50IGZhdm9yaXRlCmltcGxlbWVudGF0aW9uIG9mIHRvcGljIG1vZGVsaW5nIGluIFIiIGFuZCBoYXMgYnVpbHQgc3VwcG9ydHMgaW4gdGhlCmB0aWR5dGV4dGAgcGFja2FnZSBmb3IgYnVpbGRpbmcgc3RydWN0dXJhbCB0b3BpYyBtb2RlbHMsIHRoaXMgcGFja2FnZQpkZWZpbml0ZWx5IGlzIHdvcnRoIGRpc2N1c3NpbmcgaW4gdGhpcyB3YWxrdGhyb3VnaC4gSSBhbHNvIGhpZ2hseQpyZWNvbW1lbmQgaGVyIG93biB3YWxrdGhyb3VnaCBvZiB0aGUgYHN0bWAgcGFja2FnZTogW1RoZSBnYW1lIGlzIGFmb290IQpUb3BpYyBtb2RlbGluZyBvZiBTaGVybG9jayBIb2xtZXMKc3Rvcmllc10oaHR0cHM6Ly9qdWxpYXNpbGdlLmNvbS9ibG9nL3NoZXJsb2NrLWhvbG1lcy1zdG0vKSBhcyB3ZWxsIGFzCmhlciBmb2xsb3cgdXAgcG9zdCwgW1RyYWluaW5nLCBldmFsdWF0aW5nLCBhbmQgaW50ZXJwcmV0aW5nIHRvcGljCm1vZGVsc10oaHR0cHM6Ly9qdWxpYXNpbGdlLmNvbS9ibG9nL2V2YWx1YXRpbmctc3RtLykuCgojIyMjIFRoZSBgc3RtYCBQYWNrYWdlCgpBcyB3ZSd2ZSBzZWVuIGFib3ZlLCBTVE0gcHJvZHVjZWQgYW4gdW51c3VhbCBgdGVtcGAgdGV4dFByb2Nlc3NvciBvdXRwdXQKdGhhdCBpcyB1bmlxdWUgdG8gdGhlIGBzdG1gIHBhY2thZ2UuIEFuZCBhcyB5b3UndmUgcHJvYmFibHkgYWxyZWFkeQpndWVzc2VkLCB0aGUgYHN0bSgpYCBmdW5jdGlvbiBmb3IgZml0dGluZyBhIHN0cnVjdHVyYWwgdG9waWMgbW9kZWwgZG9lcwpub3QgdGFrZSBhIGZhaXJseSBzdGFuZGFyZCBkb2N1bWVudCB0ZXJtIG1hdHJpeCBsaWtlIHRoZSBgTERBKClgCmZ1bmN0aW9uLgoKQmVmb3JlIHdlIGZpdCBvdXIgbW9kZWwsIHdlJ2xsIGhhdmUgdG8gZXh0cmFjdCB0aGUgZWxlbWVudHMgZnJvbSB0aGUKYHRlbXBgIG9iamVjdCBjcmVhdGVkIGFmdGVyIHdlIHByb2Nlc3NlZCBvdXIgdGV4dC4gU3BlY2lmaWNhbGx5LCB0aGUKYHN0bSgpYCBmdW5jdGlvbiBleHBlY3RzIHRoZSBmb2xsb3dpbmcgYXJndW1lbnRzOgoKLSAgIGBkb2N1bWVudHMgPWAgdGhlIGRvY3VtZW50IHRlcm0gbWF0cml4IHRvIGJlIG1vZGVsZWQgaW4gdGhlIG5hdGl2ZQogICAgc3RtIGZvcm1hdAotICAgYGRhdGEgPWAgYW4gb3B0aW9uYWwgZGF0YSBmcmFtZSBjb250YWluaW5nIG1ldGEgZGF0YSBmb3IgdGhlCiAgICBwcmV2YWxlbmNlIGFuZC9vciBjb250ZW50IGNvdmFyaWF0ZXMgdG8gaW5jbHVkZSBpbiB0aGUgbW9kZWwKLSAgIGB2b2NhYiA9YCBhIGNoYXJhY3RlciB2ZWN0b3Igc3BlY2lmeWluZyB0aGUgd29yZHMgaW4gdGhlIGNvcnB1cyBpbgogICAgdGhlIG9yZGVyIG9mIHRoZSB2b2NhYiBpbmRpY2VzIGluIGRvY3VtZW50cy4KCkxldCdzIGdvIGFoZWFkIGFuZCBleHRyYWN0IHRoZXNlIGVsZW1lbnRzOgoKYGBge3Igc3RtLWRvY3N9CmRvY3MgPC0gdGVtcCRkb2N1bWVudHMgCm1ldGEgPC0gdGVtcCRtZXRhIAp2b2NhYiA8LSB0ZW1wJHZvY2FiIApgYGAKCkFuZCBub3cgdXNlIHRoZXNlIGVsZW1lbnRzIHRvIGZpdCB0aGUgbW9kZWwgdXNpbmcgdGhlIHNhbWUgbnVtYmVyIG9mCnRvcGljcyBmb3IgKksqIHRoYXQgd2Ugc3BlY2lmaWVkIGZvciBvdXIgTERBIHRvcGljIG1vZGVsLiBMZXQncyBhbHNvCnRha2UgYWR2YW50YWdlIG9mIHRoZSBmYWN0IHRoYXQgd2UgY2FuIGluY2x1ZGUgdGhlIGBjb3Vyc2VfaWRgIGFuZApgZm9ydW1faWRgIGNvdmFyaWF0ZXMgaW4gdGhlIGBwcmV2ZWFsZW5jZSA9YCBhcmd1bWVudCB0byBoZWxwIGltcHJvdmUsCmluIHRoZW9yeSwgb3VyIG1vZGVsIGZpdDoKCmBgYHtyIHN0bX0KZm9ydW1zX3N0bSA8LSBzdG0oZG9jdW1lbnRzPWRvY3MsIAogICAgICAgICBkYXRhPW1ldGEsCiAgICAgICAgIHZvY2FiPXZvY2FiLCAKICAgICAgICAgcHJldmFsZW5jZSA9fiBjb3Vyc2VfaWQgKyBmb3J1bV9pZCwKICAgICAgICAgSz0yMCwKICAgICAgICAgbWF4LmVtLml0cz0yNSwKICAgICAgICAgdmVyYm9zZSA9IEZBTFNFKQoKZm9ydW1zX3N0bQpgYGAKCkFzIG5vdGVkIGVhcmxpZXIsIHRoZSBgc3RtYCBwYWNrYWdlIGhhcyBhIG51bWJlciBvZiBoYW5keSBmZWF0dXJlcy4gT25lCm9mIHRoZXNlIGlzIHRoZSBgcGxvdC5TVE0oKWAgZnVuY3Rpb24gZm9yIHZpZXdpbmcgdGhlIG1vc3QgcHJvYmFibGUKd29yZHMgYXNzaWduZWQgdG8gZWFjaCB0b3BpYy4KCkJ5IGRlZmF1bHQsIGl0IG9ubHkgc2hvd3MgdGhlIGZpcnN0IDMgdGVybXMgc28gbGV0J3MgY2hhbmdlIHRoYXQgdG8gNSB0bwpoZWxwIHdpdGggaW50ZXJwcmV0YXRpb246CgpgYGB7ciBwbG90LXN0bX0KcGxvdC5TVE0oZm9ydW1zX3N0bSwgbiA9IDUpCmBgYAoKTm90ZSB0aGF0IHlvdSBjYW4gYWxzbyBqdXN0IHVzZSBgcGxvdCgpYCBhcyB3ZWxsOgoKYGBge3IgcGxvdH0KcGxvdChmb3J1bXNfc3RtLCBuID0gNSkKYGBgCgojIyMjIyDinIUgQ29tcHJlaGVuc2lvbiBDaGVjawoKRml0IGEgbW9kZWwgZm9yIGJvdGggTERBIGFuZCBTVE0gdXNpbmcgZGlmZmVyZW50IHZhbHVlcyBmb3IgSyBhbmQgYW5zd2VyCnRoZSBmb2xsb3dpbmcgcXVlc3Rpb25zOgoKMS4gIFdoYXQgdG9waWNzIGFwcGVhciB0byBiZSBzaW1pbGFyIHRvIHRob3NlIHVzaW5nIDIwIHRvcGljcyBmb3IgSz8KMi4gIEtub3dpbmcgdGhhdCB5b3UgZG9uJ3QgaGF2ZSBhcyBtdWNoIGNvbnRleHQgYXMgdGhlIHJlc2VhcmNoZXJzIG9mCiAgICB0aGlzIHN0dWR5IGRvLCBob3cgbWlnaHQgeW91IGludGVycHJldCBvbmUgb2YgdGhlc2UgbGF0ZW50IHRvcGljcyBvcgogICAgdGhlbWVzIHVzaW5nIHRoZSBrZXkgdGVybXMgYXNzaWduZWQ/CjMuICBXaGF0IHRvcGljIGVtZXJnZWQgdGhhdCBzZWVtIGRyYW1hdGljYWxseSBkaWZmZXJlbnQgYW5kIGhvdyBtaWdodAogICAgeW91IGludGVycHJldCB0aGlzIHRvcGljPwoKIyMjIDNjLiBGaW5kaW5nICpLKgoKQXMgYWxsdWRlZCB0byBlYXJsaWVyLCBzZWxlY3RpbmcgdGhlIG51bWJlciBvZiB0b3BpY3MgZm9yIHlvdXIgbW9kZWwgaXMKYSBub24tdHJpdmlhbCBkZWNpc2lvbiBhbmQgY2FuIGRyYW1hdGljYWxseSBpbXBhY3QgeW91ciByZXN1bHRzLiBCYWlsCigyMDE4KSBub3RlcyB0aGF0Cgo+ICpUaGUgcmVzdWx0cyBvZiB0b3BpYyBtb2RlbHMgc2hvdWxkIG5vdCBiZSBvdmVyLWludGVycHJldGVkIHVubGVzcyB0aGUKPiByZXNlYXJjaGVyIGhhcyBzdHJvbmcgdGhlb3JldGljYWwgYXByaW9yaSBhYm91dCB0aGUgbnVtYmVyIG9mIHRvcGljcwo+IGluIGEgZ2l2ZW4gY29ycHVzLCBvciBpZiB0aGUgcmVzZWFyY2hlciBoYXMgY2FyZWZ1bGx5IHZhbGlkYXRlZCB0aGUKPiByZXN1bHRzIG9mIGEgdG9waWMgbW9kZWwgdXNpbmcgYm90aCB0aGUgcXVhbnRpdGF0aXZlIGFuZCBxdWFsaXRhdGl2ZQo+IHRlY2huaXF1ZXMgZGVzY3JpYmVkIGFib3ZlLioKClRoZXJlIGFyZSBzZXZlcmFsIGFwcHJvYWNoZXMgdG8gZXN0aW1hdGluZyBhIHZhbHVlIGZvciBLIGFuZCB3ZSdsbCB0YWtlCmEgcXVpY2sgbG9vayBhdCBvbmUgZnJvbSB0aGUgYGxkYXR1bmluZ2AgcGFja2FnZSBhbmQgb25lIGZyb20gb3VyIGBzdG1gCnBhY2thZ2UuCgojIyMjIFRoZSBGaW5kVG9waWNzTnVtYmVyIEZ1bmN0aW9uCgpUaGUgYGxkYXR1bmluZ2AgcGFja2FnZSBoYXMgZnVuY3Rpb25zIGZvciBib3RoIGNhbGN1bGF0aW5nIGFuZCBwbG90dGluZwpkaWZmZXJlbnQgbWV0cmljcyB0aGF0IGNhbiBiZSB1c2VkIHRvIGVzdGltYXRlIHRoZSBtb3N0IHByZWZlcmFibGUKbnVtYmVyIG9mIHRvcGljcyBmb3IgTERBIG1vZGVsLiBJdCBhbHNvIGNvbnZlbmllbnRseSB0YWtlcyB0aGUgc3RhbmRhcmQKZG9jdW1lbnQgdGVybSBtYXRyaXggb2JqZWN0IHRoYXQgd2UgY3JlYXRlZCBmcm9tIG91dCB0aWR5IHRleHQgYW5kIGhhcwp0aGUgYWRkZWQgYmVuZWZpdCBvZiBydW5uaW5nIGZhaXJseSBxdWlja2x5LCBlc3BlY2lhbGx5IGNvbXBhcmVkIHRvIHRoZQpmdW5jdGlvbiBmb3IgZmluZGluZyBLIGZyb20gdGhlIGBzdG1gIHBhY2thZ2UuCgpMZXQncyB1c2UgdGhlIGRlZmF1bHRzIHNwZWNpZmllZCBpbiB0aGUgYD9GaW5kVG9waWNOdW1iZXJgIGRvY3VtZW50YXRpb24KYW5kIG1vZGlmeSBzbGlnaHRseSBnZXQgbWV0cmljcyBmb3IgYSBzZXF1ZW5jZSBvZiB0b3BpY3MgZnJvbSAxMC03NQpjb3VudGluZyBieSA1IGFuZCBwbG90IHRoZSBvdXRwdXQgd2Ugc2F2ZWQgdXNpbmcgdGhlCmBGaW5kVG9waWNzTnVtYmVyX3Bsb3QoKWAgZnVuY3Rpb246CgpgYGB7ciBmaW5kLXRvcGljLCBldmFsPUZBTFNFfQprX21ldHJpY3MgPC0gRmluZFRvcGljc051bWJlcigKICBmb3J1bXNfZHRtLAogIHRvcGljcyA9IHNlcSgxMCwgNzUsIGJ5ID0gNSksCiAgbWV0cmljcyA9ICJHcmlmZml0aHMyMDA0IiwKICBtZXRob2QgPSAiR2liYnMiLAogIGNvbnRyb2wgPSBsaXN0KCksCiAgbWMuY29yZXMgPSBOQSwKICByZXR1cm5fbW9kZWxzID0gRkFMU0UsCiAgdmVyYm9zZSA9IEZBTFNFLAogIGxpYnBhdGggPSBOVUxMCikKCkZpbmRUb3BpY3NOdW1iZXJfcGxvdChrX21ldHJpY3MpCmBgYAoKTm90ZSB0aGF0IHRoZSBgRmluZFRvcGljTnVtYmVycygpYCBmdW5jdGlvbiBjb250YWlucyB0aHJlZSBhZGRpdGlvbmFsCm1ldHJpY3MgZm9yIGNhbGN1bGF0aW5nIG1ldHJpY3MgdGhhdCBjYW4gYmUgdXNlZCB0byBlc3RpbWF0ZSB0aGUgbW9zdApwcmVmZXJhYmxlIG51bWJlciBvZiB0b3BpY3MgZm9yIExEQSBtb2RlbC4gV2UgdXNlZCB0aGUgR3JpZmZpdGhzMjAwNAptZXRyaWNzIGluY2x1ZGVkIGluIHRoZSBkZWZhdWx0IGV4YW1wbGUgYW5kIEkndmUgYWxzbyBmb3VuZCB0aGlzIHRvCnByb2R1Y2UgdGhlIG1vc3QgaW50ZXJwcmV0YWJsZSByZXN1bHRzIGFzIHNob3cgaW4gdGhlIGZpZ3VyZSBiZWxvdzoKCiFbXShpbWcva19tZXRyaWNzLnBuZyl7d2lkdGg9IjkwJSJ9CgpBcyBhIGdlbmVyYWwgcnVsZSBvZiB0aHVtYiBhbmQgb3Zlcmx5IHNpbXBsaXN0aWMgaGV1cmlzdGljLCB3ZSdyZQpsb29raW5nIGZvciBhbiBpbmZsZWN0aW9uIHBvaW50IGluIG91ciBwbG90IHdoaWNoIGluZGljYXRlcyBhbiBvcHRpbWFsCm51bWJlciBvZiB0b3BpY3MgdG8gc2VsZWN0IGZvciBhIHZhbHVlIG9mIEsuCgojIyMjIFRoZSBmaW5kaW5nSygpIEZ1bmN0aW9uCgpGaW5hbGx5LCBCYWlsICgyMDE4KSBub3RlcyB0aGF0IHRoZWBzdG1gIHBhY2thZ2UgaGFzIGEgdXNlZnVsIGZ1bmN0aW9uCmNhbGxlZCBgc2VhcmNoS2Agd2hpY2ggYWxsb3dzIHVzIHRvIHNwZWNpZnkgYSByYW5nZSBvZiB2YWx1ZXMgZm9yIGBrYAphbmQgb3V0cHV0cyBtdWx0aXBsZSBnb29kbmVzcy1vZi1maXQgbWVhc3VyZXMgdGhhdCBhcmUgInZlcnkgdXNlZnVsIGluCmlkZW50aWZ5aW5nIGEgcmFuZ2Ugb2YgdmFsdWVzIGZvciBga2AgdGhhdCBwcm92aWRlIHRoZSBiZXN0IGZpdCBmb3IgdGhlCmRhdGEuIgoKVGhlIHN5bnRheCBvZiB0aGlzIGZ1bmN0aW9uIGlzIHZlcnkgc2ltaWxhciB0byB0aGUgYHN0bSgpYCBmdW5jdGlvbiB3ZQp1c2VkIGFib3ZlLCBleGNlcHQgdGhhdCB3ZSBzcGVjaWZ5IGEgcmFuZ2UgZm9yIGBrYCBhcyBvbmUgb2YgdGhlCmFyZ3VtZW50cy4gSW4gdGhlIGNvZGUgYmVsb3csIHdlIHNlYXJjaCBhbGwgdmFsdWVzIG9mwqBga2DCoGJldHdlZW4gMTAgYW5kCjMwLgoKYGBge3Igc2VhcmNrLWssIGV2YWw9RkFMU0V9CiNJIGFtIG5vdCBleHBlY3RpbmcgeW91IHJ1biB0aGlzIGNvZGUgYXMgaXQgd2lsbCB0YWtlIHRvbyBsb25nCiNmaW5kaW5nayA8LSBzZWFyY2hLKGRvY3MsIAogICAgICAgICAgICAgICAgICAgICN2b2NhYiwgCiAgICAgICAgICAgICAgICAgICAgI0sgPSBjKDU6MTUpLAogICAgICAgICAgICAgICAgICAgICNkYXRhID0gbWV0YSwgCiAgICAgICAgICAgICAgICAgICAgI3ZlcmJvc2U9RkFMU0UpCgojcGxvdChmaW5kaW5naykKYGBgCgpOb3RlIHRoYXQgUnVubmluZyBgc2VhcmNoSygpYCBmdW5jdGlvbiBvbiB0aGlzIGNvcnB1cyB0b29rIGFsbCBuaWdodCBvbgphIHByZXR0eSBwb3dlcmZ1bCBNYWNCb29rIFBybyBhbmQgY3Jhc2hlZCBvbmNlIGFzIHdlbGwsIHNvIEkgZG8gbm90CmV4cGVjdCB5b3UgdG8gcnVuIHRoaXMgZm9yIHRoZSB3YWxrdGhyb3VnaC4gSSByYW4gYSBjb3VwbGUgaXRlcmF0aW9ucwphbmQgbGFuZGVkIG9uIGJldHdlZW4gNSBhbmQgMTUgd2l0aCBhbiBvcHRpbWFsIG51bWJlciBvZiB0b3BpY3MKc29tZXdoZXJlIGFyb3VuZCAxNDoKCiFbXShpbWcvc2VhcmNoa19yZXN1bHRzLnBuZyl7d2lkdGg9IjkwJSJ9CgpHaXZlbiB0aGUgc29tZXdoYXQgY29uZmxpY3RpbmcgcmVzdWx0cywgYWxzbyBzb21ld2hhdCBzZWxmaXNobHkgYW5kIGZvcgp0aGUgc2FtZSBvZiBzaW1wbGljaXR5IGZvciB0aGlzIHdhbGt0aHJvdWdoLCBJJ20ganVzdCBnb2luZyB0byBzdGljawp3aXRoIHRoZSByYXRoZXIgYXJiaXRyYXJ5IHNlbGVjdGlvbiBvZiAyMCB0b3BpY3MgZm9yIHRoZSByZW1haW5kZXIgb2YKdGhpcyBVbml0LgoKIyMjIyBUaGUgTERBdmlzIEV4cGxvcmVyCgpPbmUgZmluYWwgdG9vbCB0aGF0IEkgd2FudCB0byBpbnRyb2R1Y2UgZnJvbSB0aGUgYHN0bWAgcGFja2FnZSBpcyB0aGUKYHRvTERBdmlzKClgIGZ1bmN0aW9uIHdoaWNoIHByb3ZpZGVzIGEgZ3JlYXQgdmlzdWFsaXphdGlvbnMgZm9yCmV4cGxvcmluZyB0b3BpYyBhbmQgd29yZCBkaXN0cmlidXRpb25zIHVzaW5nIGBMREF2aXNgIHRvcGljIGJyb3dzZXI6CgpgYGB7ciBMREF2aXN9CnRvTERBdmlzKG1vZCA9IGZvcnVtc19zdG0sIGRvY3MgPSBkb2NzKQpgYGAKCkFzIHlvdSBjYW4gc2VlIGZyb20gdGhlIGJyb3dzZXIgc2NyZWVuIHNob3QgYmVsb3csIG91ciBjdXJyZW50IHN0bSBtb2RlbApvZiAyMCB0b3BpY3MgaXMgcmVzdWx0aW5nIGluIGEgbG90IG9mIG92ZXJsYXAgYW1vbmcgdG9waWNzIGFuZCBzdWdnZXN0CnRoYXQgMjAgbWF5IG5vdCBiZSBhbiBvcHRpbWFsIG51bWJlciBvZiB0b3BpY3MsIGFzIG90aGVyIGFwcHJvYWNoZXMgZm9yCmZpbmRpbmcgayBhbHNvIHN1Z2dlc3RzOgoKIVtdKGltZy9sZGF2aXMucG5nKQoKIyMgNC4gRVhQTE9SRQoKU2lsZ2UgYW5kIFJvYmluc29uICgyMDE4KSBub3RlIHRoYXQgZml0dGluZyBhdCB0b3BpYyBtb2RlbCBpcyB0aGUgImVhc3kKcGFydC4iIFRoZSBoYXJkIHBhcnQgaXMgbWFraW5nIHNlbnNlIG9mIHRoZSBtb2RlbCByZXN1bHRzIGFuZCB0aGF0IHRoZQpyZXN0IG9mIHRoZSBhbmFseXNpcyBpbnZvbHZlcyBleHBsb3JpbmcgYW5kIGludGVycHJldGluZyB0aGUgbW9kZWwgdXNpbmcKYSB2YXJpZXR5IG9mIGFwcHJvYWNoZXMgd2hpY2ggd2UnbGwgd2Fsa3Rocm91Z2ggaW4gaW4gdGhpcyBzZWN0aW9uLgoKQmFpbCAoMjAxOCkgY2F1dGlvbnMsIGhvd2V2ZXIsIHRoYXQ6Cgo+ICouLi5wb3N0LWhvYyBpbnRlcnByZXRhdGlvbiBvZiB0b3BpYyBtb2RlbHMgaXMgcmF0aGVyIGRhbmdlcm91cy4uLiBhbmQKPiBjYW4gcXVpY2tseSBjb21lIHRvIHJlc2VtYmxlIHRoZSBwcm9jZXNzIG9mICJyZWFkaW5nIHRlYSBsZWF2ZXMsIiBvcgo+IGZpbmRpbmcgbWVhbmluZyBpbiBwYXR0ZXJucyB0aGF0IGFyZSBpbiBmYWN0IHF1aXRlIGFyYml0cmFyeSBvciBldmVuCj4gcmFuZG9tLioKCiMjIyA0YS4gRXhwbG9yaW5nIEJldGEgVmFsdWVzCgpIaWRkZW4gd2l0aGluIHRoaXMgYGZvcnVtc19sZGFgIHRvcGljIG1vZGVsIG9iamVjdCB3ZSBjcmVhdGVkIGFyZQpwZXItdG9waWMtcGVyLXdvcmQgcHJvYmFiaWxpdGllcywgY2FsbGVkIM6yICgiYmV0YSIpLiBJdCBpcyB0aGUKcHJvYmFiaWxpdHkgb2YgYSB0ZXJtICh3b3JkKSBiZWxvbmdpbmcgdG8gYSB0b3BpYy7CoAoKTGV0J3MgdGFrZSBhIGxvb2sgYXQgdGhlIDUgbW9zdCBsaWtlbHkgdGVybXMgYXNzaWduZWQgdG8gZWFjaCB0b3BpYywKaS5lLiB0aG9zZSB3aXRoIHRoZSBsYXJnZXN0IM6yIHZhbHVlcyB1c2luZyB0aGUgYHRlcm1zKClgIGZ1bmN0aW9uIGZyb20KdGhlIGB0b3BpY21vZGVsc2AgcGFja2FnZToKCmBgYHtyIHRlcm1zfQp0ZXJtcyhmb3J1bXNfbGRhLCA1KQpgYGAKCkV2ZW4gdGhvdWdoIHdlJ3ZlIHNvbWV3aGF0IGFyYml0cmFyaWx5IHNlbGVjdGVkIHRoZSBudW1iZXIgb2YgdG9waWNzIGZvcgpvdXIgY29ycHVzLCBzb21lIHRoZXNlIHRvcGljcyBvciB0aGVtZXMgYXJlIGZhaXJseSBpbnR1aXRpdmUgdG8KaW50ZXJwcmV0LiBGb3IgZXhhbXBsZToKCi0gICBUb3BpYyAxMSAodGVjaG5vbG9neSwgc3R1ZGVudHMsIHNvZnR3YXJlLCBwcm9ncmFtLCBleGNlbCkgc2VlbXMgdG8KICAgIGJlIGFib3V0IHN0dWRlbnRzIHVzZSBvZiB0ZWNobm9sb2d5IGluY2x1ZGluZyBzb2Z0d2FyZSBwcm9ncmFtcyBsaWtlCiAgICBleGNlbDsKCi0gICBUb3BpYyA5IChxdWVzdGlvbnMsIGtpZHMsIGxvdmUsIGdhcG1pbmRlciwgc2hhcmluZykgc2VlbXMgdG8gYmUKICAgIGFib3V0IHRoZSBnYXBtaW5kZXIgYWN0aXZpdHkgZnJvbSB0aGUgTU9PQy1FZCBhbmQga2lkcyBlbmpveW1lbnQgb2YKICAgIGl0OyBhbmQKCi0gICBUb3BpYyAxOCAoZGF0YSwgc3R1ZGVudHMsIGNvbGxlY3QsIHJlYWwsIHNldHMpIHNlZW1zIHRvIGJlIGFib3V0CiAgICBzdHVkZW50IGNvbGxlY3Rpb24gYW5kIHVzZSBvZiByZWFsIHdvcmxkIGRhdGEgc2V0cy4KCk5vdCBzdXJwcmlzaW5nbHksIHRoZSBgdGlkeXRleHRgIHBhY2thZ2UgaGFzIGEgaGFuZHkgZnVuY3Rpb24KY29udmVuaWVudGx5IG5hbWUgYHRpZHkoKWAgdG8gY29udmVydCBvdXIgbGRhIG1vZGVsIHRvIGEgdGlkeSBkYXRhIGZyYW1lCmNvbnRhaW5pbmcgdGhlc2UgYmV0YSB2YWx1ZXMgZm9yIGVhY2ggdGVybToKCmBgYHtyIHRpZHlfbGRhfQoKdGlkeV9sZGEgPC0gdGlkeShmb3J1bXNfbGRhKQoKdGlkeV9sZGEKYGBgCgpPYnZpb3VzbHksIGl0J3Mgbm90IHZlcnkgZWFzeSB0byBpbnRlcnByZXQgd2hhdCB0aGUgdG9waWNzIGFyZSBhYm91dApmcm9tIGEgZGF0YSBmcmFtZSBsaWtlIHRoaXMgc28gbGV0J3MgYm9ycm93IGNvZGUgYWdhaW4gZnJvbSBbQ2hhcHRlcgo4LjQuMyBJbnRlcnByZXRpbmcgdGhlIHRvcGljCm1vZGVsXShodHRwczovL3d3dy50aWR5dGV4dG1pbmluZy5jb20vbmFzYS5odG1sP3E9YmV0YSNpbnRlcnByZXRpbmctdGhlLXRvcGljLW1vZGVsKQppbiBUZXh0IE1pbmluZyB3aXRoIFIgdG8gZXhhbWluZSB0aGUgdG9wIDUgdGVybXMgZm9yIGVhY2ggdG9waWMgYW5kIHRoZW4KbG9vayBhdCB0aGlzIGluZm9ybWF0aW9uIHZpc3VhbGx5OgoKYGBge3IgdG9wX3Rlcm1zfQoKdG9wX3Rlcm1zIDwtIHRpZHlfbGRhICU+JQogIGdyb3VwX2J5KHRvcGljKSAlPiUKICBzbGljZV9tYXgoYmV0YSwgbiA9IDUsIHdpdGhfdGllcyA9IEZBTFNFKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgYXJyYW5nZSh0b3BpYywgLWJldGEpCgp0b3BfdGVybXMgJT4lCiAgbXV0YXRlKHRlcm0gPSByZW9yZGVyX3dpdGhpbih0ZXJtLCBiZXRhLCB0b3BpYykpICU+JQogIGdyb3VwX2J5KHRvcGljLCB0ZXJtKSAlPiUgICAgCiAgYXJyYW5nZShkZXNjKGJldGEpKSAlPiUgIAogIHVuZ3JvdXAoKSAlPiUKICBnZ3Bsb3QoYWVzKGJldGEsIHRlcm0sIGZpbGwgPSBhcy5mYWN0b3IodG9waWMpKSkgKwogIGdlb21fY29sKHNob3cubGVnZW5kID0gRkFMU0UpICsKICBzY2FsZV95X3Jlb3JkZXJlZCgpICsKICBsYWJzKHRpdGxlID0gIlRvcCA1IHRlcm1zIGluIGVhY2ggTERBIHRvcGljIiwKICAgICAgIHggPSBleHByZXNzaW9uKGJldGEpLCB5ID0gTlVMTCkgKwogIGZhY2V0X3dyYXAofiB0b3BpYywgbmNvbCA9IDQsIHNjYWxlcyA9ICJmcmVlIikKYGBgCgojIyMgNGIuIEV4cGxvcmluZyBHYW1tYSBWYWx1ZXMKCk5vdyB0aGF0IHdlIGhhdmUgYSBzZW5zZSBvZiB0aGUgbW9zdCBjb21tb24gd29yZHMgYXNzb2NpYXRlZCB3aXRoIGVhY2gKdG9waWMsIGxldCdzIHRha2UgYSBsb29rIGF0IHRoZSB0b3BpYyBwcmV2YWxlbmNlIGluIG91ciBNT09DLUVkCmRpc2N1c3Npb24gZm9ydW0gY29ycHVzLCBpbmNsdWRpbmcgdGhlIHdvcmRzIHRoYXQgY29udHJpYnV0ZSB0byBlYWNoCnRvcGljIHdlIGV4YW1pbmVkIGFib3ZlLgoKQWxzbywgaGlkZGVuIHdpdGhpbiBvdXIgYGZvcnVtc19sZGFgIHRvcGljIG1vZGVsIG9iamVjdCB3ZSBjcmVhdGVkIGFyZQpwZXItZG9jdW1lbnQtcGVyLXRvcGljIHByb2JhYmlsaXRpZXMsIGNhbGxlZCDOsyAoImdhbW1hIikuIFRoaXMgcHJvdmlkZXMKdGhlIHByb2JhYmlsaXRpZXMgdGhhdCBlYWNoIGRvY3VtZW50IGlzIGdlbmVyYXRlZCBmcm9tIGVhY2ggdG9waWMsIHRoYXQKZ2FtbWEgbWF0cml4LiBXZSBjYW4gY29tYmluZSBvdXIgYmV0YSBhbmQgZ2FtbWEgdmFsdWVzIHRvIHVuZGVyc3RhbmQgdGhlCnRvcGljIHByZXZhbGVuY2UgaW4gb3VyIGNvcnB1cywgYW5kIHdoaWNoIHdvcmRzIGNvbnRyaWJ1dGUgdG8gZWFjaAp0b3BpYy4KClRvIGRvIHRoaXMsIHdlJ3JlIGdvaW5nIHRvIGJvcnJvdyBzb21lIGNvZGUgZnJvbSB0aGUgU2lsZ2UgKDIwMTgpIHBvc3QsCltUcmFpbmluZywgZXZhbHVhdGluZywgYW5kIGludGVycHJldGluZyB0b3BpYwptb2RlbHNdKGh0dHBzOi8vanVsaWFzaWxnZS5jb20vYmxvZy9ldmFsdWF0aW5nLXN0bS8pLgoKRmlyc3QsIGxldCdzIGNyZWF0ZSB0d28gdGlkeSBkYXRhIGZyYW1lcyBmb3Igb3VyIGJldGEgYW5kIGdhbW1hIHZhbHVlcwoKYGBge3IgYmV0YV9nYW1tYX0KdGRfYmV0YSA8LSB0aWR5KGZvcnVtc19sZGEpCgp0ZF9nYW1tYSA8LSB0aWR5KGZvcnVtc19sZGEsIG1hdHJpeCA9ICJnYW1tYSIpCgp0ZF9iZXRhCnRkX2dhbW1hCgpgYGAKCk5leHQsIHdlJ2xsIGFkb3B0IEp1bGlhJ3MgY29kZSB3aG9sZXNhbGUgdG8gY3JlYXRlIGEgZmlsdGVyZWQgZGF0YSBmcmFtZQpvZiBvdXIgYHRvcF90ZXJtc2AsIGpvaW4gdGhpcyB0byBhIG5ldyBkYXRhIGZyYW1lIGZvciBgZ2FtbWEtdGVybXNgIGFuZApjcmVhdGUgYSBuaWNlIGNsZWFuIHRhYmxlIHVzaW5nIHRoZSBga2FiZWwoKWAgZnVuY3Rpb24gYGtuaXRyYCBwYWNrYWdlOgoKYGBge3IgcHJldmFsZW5jZV90YWJsZX0KdG9wX3Rlcm1zIDwtIHRkX2JldGEgJT4lCiAgYXJyYW5nZShiZXRhKSAlPiUKICBncm91cF9ieSh0b3BpYykgJT4lCiAgdG9wX24oNywgYmV0YSkgJT4lCiAgYXJyYW5nZSgtYmV0YSkgJT4lCiAgc2VsZWN0KHRvcGljLCB0ZXJtKSAlPiUKICBzdW1tYXJpc2UodGVybXMgPSBsaXN0KHRlcm0pKSAlPiUKICBtdXRhdGUodGVybXMgPSBtYXAodGVybXMsIHBhc3RlLCBjb2xsYXBzZSA9ICIsICIpKSAlPiUgCiAgdW5uZXN0KCkKCmdhbW1hX3Rlcm1zIDwtIHRkX2dhbW1hICU+JQogIGdyb3VwX2J5KHRvcGljKSAlPiUKICBzdW1tYXJpc2UoZ2FtbWEgPSBtZWFuKGdhbW1hKSkgJT4lCiAgYXJyYW5nZShkZXNjKGdhbW1hKSkgJT4lCiAgbGVmdF9qb2luKHRvcF90ZXJtcywgYnkgPSAidG9waWMiKSAlPiUKICBtdXRhdGUodG9waWMgPSBwYXN0ZTAoIlRvcGljICIsIHRvcGljKSwKICAgICAgICAgdG9waWMgPSByZW9yZGVyKHRvcGljLCBnYW1tYSkpCgpnYW1tYV90ZXJtcyAlPiUKICBzZWxlY3QodG9waWMsIGdhbW1hLCB0ZXJtcykgJT4lCiAga2FibGUoZGlnaXRzID0gMywgCiAgICAgICAgY29sLm5hbWVzID0gYygiVG9waWMiLCAiRXhwZWN0ZWQgdG9waWMgcHJvcG9ydGlvbiIsICJUb3AgNyB0ZXJtcyIpKQpgYGAKCkFuZCBsZXQncyBhbHNvIGNvbXBhcmUgdGhpcyB0byB0aGUgbW9zdCBwcmV2YWxlbnQgdG9waWNzIGFuZCB0ZXJtcyBmcm9tCm91ciBgZm9ydW1zX3N0bWAgbW9kZWwgdGhhdCB3ZSBjcmVhdGVkIHVzaW5nIHRoZSBgcGxvdCgpYCBmdW5jdGlvbjoKCmBgYHtyIHBsb3Rfc3RtfQpwbG90KGZvcnVtc19zdG0sIG4gPSA3KQpgYGAKCiMjIyA0Yy4gUmVhZGluZyB0aGUgVGVhIExlYXZlcwoKUmVjb2duaXppbmcgdGhhdCB0b3BpYyBtb2RlbGluZyBpcyBiZXN0IHVzZWQgYXMgYSAidG9vbCBmb3IgcmVhZGluZyIgYW5kCnByb3ZpZGVzIG9ubHkgYW4gaW5jb21wbGV0ZSBhbnN3ZXIgdG8gb3VyIG92ZXJhcmNoaW5nLCAqKiJIb3cgZG8gd2UKcXVhbnRpZnkgd2hhdCBhIGNvcnB1cyBpcyBhYm91dD8iKiosIHRoZSByZXN1bHRzIGRvIHN1Z2dlc3Qgc29tZQpwb3RlbnRpYWwgdG9waWNzIHRoYXQgaGF2ZSBlbWVyZ2VzIGFzIHdlbGwgYXMgc29tZSBhcmVhcyB3b3J0aCBmb2xsb3dpbmcKdXAgb24uCgpTcGVjaWZpY2FsbHksIGxvb2tpbmcgYXQgc29tZSBvZiB0aGUgY29tbW9uIGNsdXN0ZXJzIG9mIHdvcmRzIGZvciB0aGUKbW9yZSBwcmV2YWxlbnQgdG9waWNzIHN1Z2dlc3QgdGhhdCBzb21lIGtleSB0b3BpY3Mgb3IgImxhdGVudCB0aGVtZXMiCihyZW5hbWVkIGluIGJvbGQpIG1pZ2h0IGluY2x1ZGU6CgotICAgKipUZWFjaGluZyBTdGF0aXN0aWNzOioqIFVuc3VycHJpc2luZywgZ2l2ZW4gdGhlIGNvdXJzZSB0aXRsZSwgdGhlCiAgICB0b3BpY3MgbW9zdCBwcmV2YWxlbnQgaW4gYm90aCB0aGUgYGZvcnVtc19zdG1gIGFuZCBgZm9ydW1zX2xkYWAKICAgIG1vZGVscyBjb250YWlucyB0aGUgdGVybXMgInRlYWNoIiwgInN0dWRlbnRzIiwgInN0YXRpc3RpY3MiLiBUaGlzCiAgICBjb3VsZCBiZSBhbiAib3ZlcmFyY2hpbmcgdGhlbWUiIGJ1dCBtb3JlIGxpa2VseSBtYXkgc2ltcGx5IGJlIGp1c3QKICAgIHRoZSByZXNpZHVlIG9mIHRoZSBjb3Vyc2UgdGl0bGUgdGhvdWdoIGJlaW5nIHNwcmlua2xlZCB0aHJvdWdob3V0CiAgICB0aGUgZm9ydW1zIGFuZCBkZXNlcnZlcyBzb21lIGZvbGxvdyB1cC4gVG9waWNzIDggZnJvbSB0aGUgTERBIG1vZGVsCiAgICBtYXkgb3ZlcmxhcCB3aXRoIHRoaXMgdG9waWMgYXMgd2VsbC4KLSAgICoqQ291cnNlIFV0aWxpdHk6KiogVGhlIHNlY29uZCBtb3N0IHByZXZhbGVudCBUb3BpY3MgKDEzIGFuZCAyKSBpbgogICAgdGhlIGBsZGFgIGFuZCBgc3RtYCBtb2RlbHMgcmVzcGVjdGl2ZWx5LCBzZWVtIHRvIHBvdGVudGlhbGx5IGJlCiAgICBhYm91dCB0aGUgdXNlZnVsbmVzcyBvZiBjb3Vyc2UgInJlc291cmNlcyIgbGlrZSBsZXNzb25zLCB0b29scywKICAgIHZpZGVvcywgYW5kIGFjdGl2aXRpZXMuIEknbSB3YWdlcmluZyB0aGlzIG1pZ2h0IGJlIGEgZm9ydW0gZGVkaWNhdGVkCiAgICB0byBjb3Vyc2UgZmVlZGJhY2suIFRvcGljIDE1IGZyb20gdGhlIFNUTSBtb2RlbCBhbHNvIHN1Z2dlc3QgdGhpcwogICAgbWF5IGJlIGEgYnJvYWRlciB0aGVtZS4KLSAgICoqVXNpbmcgUmVhbC1Xb3JsZCBEYXRhOioqIFRvcGljcyAxOCAmIDEyIGZyb20gdGhlIExEQSBtb2RlbAogICAgcGFydGljdWxhcmx5IGludHJpZ3VlIG1lIGFuZCBJJ20gd2FnZXJpbmcgdGhpcyBpcyBwcmV0dHkgcG9zaXRpdmUKICAgIHNlbnRpbWVudCBhbW9uZyBwYXJ0aWNpcGFudHMgYWJvdXQgdGhlIHZhbHVlIGFuZCBiZW5lZml0IG9mIGhhdmluZwogICAgc3R1ZGVudHMgY29sbGVjdCBhbmQgYW5hbHl6ZSByZWFsIGRhdGEgc2V0cyAoZS5nLiBDZW5zdXMgZGF0YSBpbgogICAgVG9waWMgMSkgYW5kIHdvcmsgb24gcHJvamVjdHMgcmVsZXZhbnQgdG8gdGhlaXIgcmVhbCBsaWZlLiBXaWxsCiAgICBkZWZpbml0ZWx5IGZvbGxvdyB1cCBvbiB0aGlzIG9uZS4KLSAgICoqVGVjaG5vbG9neSBVc2U6KiogU2V2ZXJhbCB0b3BpY3MgKDYgJiAxMSBmcm9tIExEQSBhbmQgOCAmIDE5IGZyb20KICAgIFNUTSkgYXBwZWFyIHRvIGJlIGFib3V0IHN0dWRlbnQgdXNlIG9mIHRlY2hub2xvZ3kgYW5kIHNvZnR3YXJlIGxpa2UKICAgIGNhbGN1bGF0b3JzIGFuZCBFeGNlbCBmb3IgdGVhY2hpbmcgc3RhdGlzdGljcyBhbmQgdXNpbmcgc2ltdWxhdGlvbnMuCiAgICBUb3BpYyAxNiBmcm9tIExEQSBhbHNvIHN1Z2dlc3QgdGhlIHVzZSBvZiB0aGUgQ29tbW9uIE9ubGluZSBEYXRhCiAgICBBbmFseXNpcyBQbGF0Zm9ybQogICAgKFtDT0RBUF0oQ29tbW9uJTIwT25saW5lJTIwRGF0YSUyMEFuYWx5c2lzJTIwUGxhdGZvcm0lMjAoQ09EQVApJTIwT3Blbi1zb3VyY2UlMjBzb2Z0d2FyZSUyMGZvciUyMGR5bmFtaWMlMjBkYXRhJTIwZXhwbG9yYXRpb24pKS4KLSAgICoqU3R1ZGVudCBTdHJ1Z2dsZSAmIEVuZ2FnZW1lbnQ6KiogVG9waWMgMTUgZnJvbSBMREEgYW5kIFRvcGljIDE2CiAgICBmcm9tIFNUTSBhbHNvIGludHJpZ3VlIG1lIGFuZCBhcHBlYXIgdG8gYmUgdHdvIG9wcG9zaXRlIHNpZGVzIG9mCiAgICBwZXJoYXBzIHRoZSBzYW1lIGNvaW4uIFRoZSBmb3JtZXIgaW5jbHVkZXMgInN0cnVnZ2xlIiBhbmQgInJlYWRpbmciCiAgICB3aGljaCBzdWdnZXN0cyBwZXJoYXBzIGEgYmFycmllciB0byB0ZWFjaGluZyBzdGF0aXN0aWNzIHdoaWxlIFRvcGljCiAgICAxNiBjb250YWlucyB0b3Agc3RlbXMgbGlrZSAiZW5nYWdlIiwgImFjdGl2IiwgYW5kICJ0aGluayIgYW5kIG1heQogICAgc3VnZ2VzdCBwYXJ0aWNpcGFudHMgYW50aWNpcGF0ZSBhY3Rpdml0aWVzIG1heSBlbmdhZ2Ugc3R1ZGVudHMuCgpUbyBzZXJ2ZSBhcyBhIGNoZWNrIG9uIG15IHRlYSBsZWFmIHJlYWRpbmcsIEknbSBnb2luZyB0byBmb2xsb3cgQmFpbCdzCnJlY29tbWVuZGF0aW9uIHRvIGV4YW1pbmUgc29tZSBvZiB0aGVzZSB0b3BpY3MgcXVhbGl0YXRpdmVseS4gVGhlIGBzdG1gCnBhY2thZ2UgaGFzIGFub3RoZXIgdXNlZnVsIGZ1bmN0aW9uIHRob3VnaCBleGNlcHRpb25hbGx5IGZ1c3N5IGZ1bmN0aW9uCmNhbGxlZCBgZmluZFRob3VnaHRzYCB3aGljaCBleHRyYWN0cyBwYXNzYWdlcyBmcm9tIGRvY3VtZW50cyB3aXRoaW4gdGhlCmNvcnB1cyBhc3NvY2lhdGUgd2l0aCB0b3BpY3MgdGhhdCB5b3Ugc3BlY2lmeS4KClRoZSBmaXJzdCBsaW5lIG9mIGNvZGUgbWF5IG5vdCBiZSBuZWNlc3NhcnkgZm9yIHlvdXIgaW5kZXBlbmRlbnQKYW5hbHlzaXMsIGJ1dCBiZWNhdXNlIHRoZSBgdGV4dFByb2Nlc3NvcigpYCBmdW5jdGlvbiByZW1vdmVkIHNldmVyYWwKZG9jdW1lbnRzIGR1cmluZyBwcm9jZXNzaW5nLCB0aGUgYGZpbmR0aG91Z2h0cygpYCBmdW5jdGlvbiBjYW4ndApwcm9wZXJseSBpbmRleCB0aGUgcHJvY2Vzc2VkIGRvY3MuIFRoaXMgW2xpbmUgb2YgY29kZSBmb3VuZCBvbgpzdGFja292ZXJmbG93XShodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy80MzQ5MjY2Ny9yLXN0bS1udW1iZXItb2YtcHJvdmlkZWQtdGV4dHMtYW5kLW51bWJlci1vZi1kb2N1bWVudHMtbW9kZWxlZC1kby1ub3QtbWF0Y2gpCnJlbW92ZXMgZG9jdW1lbnRzIGZyb20gb3JpZ2luYWwgYHRzX2ZvcnVtX2RhdGFgIHNvdXJjZSB0aGF0IHdlcmUgcmVtb3ZlZApkdXJpbmcgcHJvY2Vzc2luZyBzbyB0aGVyZSBpcyBhIG9uZS10by1vbmUgY29ycmVzcG9uZGVuY2Ugd2l0aApgZm9ydW1zX3N0bWAgYW5kIHNvIHlvdSBjYW4gdXNlIHRoZSBmdW5jdGlvbiB0byBmaW5kIHBvc3RzIGFzc29jaWF0ZWQKd2l0aCBhIGdpdmVuIHRvcGljLgoKTGV0J3Mgc2xpZ2h0bHkgcmVkdWNlIG91ciBvcmlnaW5hbCBkYXRhIHNldCB0byBtYXRjaCBvdXIgU1RNIG1vZGVsLCBwYXNzCmJvdGggdG8gdGhlIGBmaW5kVGhvdWdodHMoKWAgZnVuY3Rpb24sIGFuZCBzZXQgb3VyIGFyZ3VtZW50cyB0byByZXR1cm4KYG4gPTEwYCBwb3N0cyBmcm9tIGB0b3BpY3MgPSAyYCAoaS5lLiBUb3BpYyAyKSB0aGF0IGhhdmUgYXQgbGVhc3QgNTAlIG9yCmB0aHJlc2ggPSAwLjVgIGFzIGEgbWluaW11bSB0aHJlc2hvbGQgZm9yIHRoZSBlc3RpbWF0ZWQgdG9waWMKcHJvcG9ydGlvbi4KCmBgYHtyIGZpbmRUaG91Z2h0c18yfQoKdHNfZm9ydW1fZGF0YV9yZWR1Y2VkIDwtdHNfZm9ydW1fZGF0YSRwb3N0X2NvbnRlbnRbLXRlbXAkZG9jcy5yZW1vdmVkXQoKZmluZFRob3VnaHRzKGZvcnVtc19zdG0sCiAgICAgICAgICAgICB0ZXh0cyA9IHRzX2ZvcnVtX2RhdGFfcmVkdWNlZCwKICAgICAgICAgICAgIHRvcGljcyA9IDIsIAogICAgICAgICAgICAgbiA9IDEwLAogICAgICAgICAgICAgdGhyZXNoID0gMC41KQpgYGAKCkR1cGxpY2F0ZSBwb3N0cyBhc2lkZSwgdGhpcyAqKkNvdXJzZSBVdGlsaXR5KiogdG9waWMgcmV0dXJucyBwb3N0cyB0aGVyZQp3ZXJlIGV4cGVjdGVkIGJhc2VkIG9uIG15IGludGVycHJldGF0aW9uIG9mIHRoZSBrZXkgdGVybXMgZm9yIFRvcGljIDIuCkl0IGxvb2tzIGxpa2UgSSBtYXkgaGF2ZSByZWFkIHRob3NlIHRlYSBsZWF2ZXMgY29ycmVjdGx5LgoKTm93IGxldCdzIHRha2UgYSBsb29rIGF0IFRvcGljIDE2IHRoYXQgd2UgdGhvdWdodCBtaWdodCBiZSByZWxhdGVkIHRvCnN0dWRlbnQgZW5nYWdlbWVudDoKCmBgYHtyIGZpbmRUaG91Z2h0c18xNn0KCmZpbmRUaG91Z2h0cyhmb3J1bXNfc3RtLAogICAgICAgICAgICAgdGV4dHMgPSB0c19mb3J1bV9kYXRhX3JlZHVjZWQsCiAgICAgICAgICAgICB0b3BpY3MgPSAxNiwgCiAgICAgICAgICAgICBuID0gMTAsCiAgICAgICAgICAgICB0aHJlc2ggPSAwLjUpCmBgYAoKSXQgbG9va3MgbGlrZSBteSB0ZWEgcmVhZGluZyB3YXMgYSBwYXJ0aWFsbHkgY29ycmVjdCBmb3IgVG9waWMgMTYsCnRob3VnaCB0aGUgcmVzdWx0cyBzZWVtIHRvIGJlIGFib3V0IGEgc3BlY2lmaWMgIlBlcHNpIGNoYWxsZW5nZSIKYWN0aXZpdHkgdG8gY29uZHVjdCB3aXRoIHN0dWRlbnRzLgoKRmluYWxseSwgbGV0J3MgbG9vayBhdCBwb3N0cyBmcm9tIFRvcGljIDMgd2hpY2ggd2UgdGhvdWdoIG1pZ2h0IGJlIGFuCm92ZXJhcmNoaW5nIHRoZW1lIGFib3V0IHRlYWNoaW5nIHN0YXRpc3RpY3M6CgpgYGB7ciBmaW5kVGhvdWdodHNfM30KCnRzX2ZvcnVtX2RhdGFfcmVkdWNlZCA8LXRzX2ZvcnVtX2RhdGEkcG9zdF9jb250ZW50Wy10ZW1wJGRvY3MucmVtb3ZlZF0KCmZpbmRUaG91Z2h0cyhmb3J1bXNfc3RtLAogICAgICAgICAgICAgdGV4dHMgPSB0c19mb3J1bV9kYXRhX3JlZHVjZWQsCiAgICAgICAgICAgICB0b3BpY3MgPSAzLCAKICAgICAgICAgICAgIG4gPSAxMCwKICAgICAgICAgICAgIHRocmVzaCA9IDAuNSkKYGBgCgpMb29raW5nIGF0IGp1c3QgdGhlIDEwIHBvc3RzIHJldHVybmVkLCBwZXJoYXBzIGEgYmV0dGVyIG5hbWUgZm9yIHRoaXMKdG9waWMgd291bGQgYmUgKipDb3Vyc2UgUmVmbGVjdGlvbnMgb24gVGVhY2hpbmcgU3RhdGlzdGljcyoqLgoKIyMjIyBVbml0IFRha2Vhd2F5CgpJbiBhZGRpdGlvbiB0byBzb21lIHVzZWZ1bCBSIHBhY2thZ2VzIGFuZCBmdW5jdGlvbnMgZm9yIHRoZSBhY3R1YWwKcHJvY2VzcyBvZiB0b3BpYyBtb2RlbGluZywgaG9wZWZ1bGx5IHRoZXJlIGFyZSB0d28gbWFpbiBsZXNzb25zIEknbQpob3BpbmcgeW91IHRha2UgYXdheSBmcm9tIHRoaXMgd2Fsa3Rocm91Z2g6CgoxLiAgKipUb3BpYyBtb2RlbGluZyByZXF1aXJlcyBhIGxvdCBvZiBkZWNpc2lvbnMuKiogQmV5b25kIGRlY2lkaW5nIG9uIGEKICAgIHZhbHVlIGZvciBLLCB0aGVyZSBhcmUgYSBudW1iZXIgb2Yga2V5IGRlY2lzaW9ucyB0aGF0IHlvdSBoYXZlIHRvCiAgICBtYWtlIHRoYXQgY2FuIGRyYW1hdGljYWxseSBhZmZlY3QgeW91ciByZXN1bHRzLiBGb3IgZXhhbXBsZSwgdG8gc3RlbQogICAgb3Igbm90IHRvIHN0ZW0/IFdoYXQgcXVhbGlmaWVzIGFzIGEgZG9jdW1lbnQ/IFdoYXQgZmxhdm9yIG9yIHRvcGljCiAgICBtb2RlbGluZyBpcyBiZXN0IHN1aXRlZCB0byB5b3VyIGRhdGEgYW5kIHJlc2VhcmNoIHF1ZXN0aW9ucz8gSG93CiAgICBtYW55IGl0ZXJhdGlvbnMgdG8gcnVuPwoyLiAgKipUb3BpYyBtb2RlbGluZyBpcyBhcyBtdWNoIGFydCBhcyAoZGF0YSkgc2NpZW5jZS4qKiBBcyBCYWlsICgyMDE4KQogICAgbm90ZWQsIHRoZSB0ZXJtICJ0b3BpYyIgaXMgc29tZXdoYXQgYW1iaXRpb3VzLCBhbmQgdG9waWMgbW9kZWxzIGRvCiAgICBub3QgcHJvZHVjZSBoaWdobHkgbnVhbmNlZCBjbGFzc2lmaWNhdGlvbiBvZiB0ZXh0cy4gT25jZSB5b3UndmUgZml0CiAgICB5b3VyIG1vZGVsLCBpbnRlcnByZXRpbmcgeW91ciBtb2RlbCByZXF1aXJlcyBzb21lIG1lbnRhbCBneW1uYXN0aWNzCiAgICBhbmQgaWRlYWxseSBzb21lIGtub3dsZWRnZSBvZiB0aGUgY29udGV4dCBmcm9tIHdoaWNoIHRoZSBkYXRhIGNhbWUKICAgIHRvIGhlbHAgd2l0aCBpbnRlcnByZXRhdGlvbiBvZiB5b3VyIHRvcGljcy4gTW9yZW92ZXIsIHRoZQogICAgcXVhbnRpdGF0aXZlIGFwcHJvYWNoZXMgZm9yIG1ha2luZyB0aGUgZGVjaXNpb25zIGhpZ2hsaWdodGVkIGFib3ZlCiAgICBhcmUgaW1wZXJmZWN0IGFuZCBhIGdvb2QgZGVhbCBvZiBodW1hbiBqdWRnbWVudCByZXF1aXJlZC4KCiMjIyMjIOKchSBDb21wcmVoZW5zaW9uIENoZWNrCgpVc2luZyB0aGUgU1RNIG1vZGVsIHlvdSBmaXQgZnJvbSB0aGUgU2VjdGlvbiAzIFtDb21wcmVoZW5zaW9uIENoZWNrXQp3aXRoIGEgZGlmZmVyZW50IHZhbHVlIGZvciBLLCB1c2UgdGhlIGFwcHJvYWNoZXMgZGVtb25zdHJhdGVkIGluIFNlY3Rpb24KNCB0byBleHBsb3JlIGFuZCBpbnRlcnByZXQgeW91ciB0b3BpY3MgYW5kIHRlcm1zIGFuZCByZXZpc2l0IHRoZQpmb2xsb3dpbmcgcXVlc3Rpb246CgoxLiAgTm93IHRoYXQgeW91IGhhdmUgYSBsaXR0bGUgbW9yZSBjb250ZXh0LCBob3cgbWlnaHQgeW91IHJldmlzZSB5b3VyCiAgICBpbml0aWFsIGludGVycHJldGF0aW9uIG9mIHNvbWUgb2YgdGhlIGxhdGVudCB0b3BpY3Mgb3IgbGF0ZW50IHRoZW1lcwogICAgZnJvbSB5b3VyIG1vZGVsPwo=