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:

  1. 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.
  2. 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).
  3. 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

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 “metadata.”

Summary of Key Findings

The following highlight some key findings related to the discussion forums in the papers cited above:

  1. 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.
  2. 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.
  3. 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.
  4. 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:

## Warning: package 'tidyverse' was built under R version 4.0.5
## Warning: package 'ggplot2' was built under R version 4.0.5
## Warning: package 'tibble' was built under R version 4.0.5
## Warning: package 'tidyr' was built under R version 4.0.5
## Warning: package 'readr' was built under R version 4.0.5
## Warning: package 'purrr' was built under R version 4.0.5
## Warning: package 'dplyr' was built under R version 4.0.5
## Warning: package 'stringr' was built under R version 4.0.5
## Warning: package 'forcats' was built under R version 4.0.5
## Warning: package 'tidytext' was built under R version 4.0.5
## Warning: package 'topicmodels' was built under R version 4.0.5
## Warning: package 'ldatuning' was built under R version 4.0.5
## Warning: package 'knitr' was built under R version 4.0.5
## Warning: package 'LDAvis' was built under R version 4.0.5
## Warning: package 'devtools' was built under R version 4.0.5
## Warning: package 'usethis' was built under R version 4.0.5

2. WRANGLE

2a. Import Forum Data

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:

  1. Transforming our text into “tokens”
  2. Removing unnecessary characters, punctuation, and whitespace
  3. Converting all text to lowercase
  4. 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:

## # A tibble: 165,720 x 10
##    course_id course_name       forum_id forum_name discussion_id discussion_name
##    <chr>     <chr>             <chr>    <chr>      <chr>         <chr>          
##  1 9         Teaching Statist~ 126      Investiga~ 6822          Not much compa~
##  2 9         Teaching Statist~ 126      Investiga~ 6822          Not much compa~
##  3 9         Teaching Statist~ 126      Investiga~ 6822          Not much compa~
##  4 9         Teaching Statist~ 126      Investiga~ 6822          Not much compa~
##  5 9         Teaching Statist~ 126      Investiga~ 6822          Not much compa~
##  6 9         Teaching Statist~ 126      Investiga~ 6822          Not much compa~
##  7 9         Teaching Statist~ 126      Investiga~ 6822          Not much compa~
##  8 9         Teaching Statist~ 126      Investiga~ 6822          Not much compa~
##  9 9         Teaching Statist~ 126      Investiga~ 6822          Not much compa~
## 10 9         Teaching Statist~ 126      Investiga~ 6822          Not much compa~
## # ... with 165,710 more rows, and 4 more variables: post_id <chr>,
## #   post_title <chr>, post_date <chr>, word <chr>

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:

## # A tibble: 13,666 x 2
##    word            n
##    <chr>       <int>
##  1 students     6837
##  2 data         4338
##  3 statistics   3095
##  4 school       1488
##  5 questions    1470
##  6 time         1252
##  7 class        1208
##  8 agree         999
##  9 teaching      987
## 10 statistical   957
## # ... with 13,656 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:

## # A tibble: 10 x 1
##    post_content                                                                 
##    <chr>                                                                        
##  1 "-  Airport Data     <What learning goal(s) could this task be used for stud~
##  2 "As a learner of statistics  and then as a teacher  I think that is too much~
##  3 "I agree.  The best form of graphical data display depends on what you are t~
##  4 "I really liked how the students refined their questions by looking at the d~
##  5 "I think it's great that so many of you are teaching non-AP stats courses!! ~
##  6 "Technology ushers in fundamental structural changes that can be integral to~
##  7 "I try to have my students engaged in projects at least 8 times during the y~
##  8 "This unit uses data from Census @School. However  the data evolved from jus~
##  9 "One specific thought sticks out in my mind as I reflect on these questions ~
## 10 "Maybe I am not understanding the task fully without actually working with t~
  1. What, if anything, do these posts have in common?
  • similar forum topics: either “discuss w/ your colleagues or investigate”
  1. What topics or themes might be apparent, or do you anticipate emerging, from our topic modeling?
  • Just guessing here but: technology, application to classroom, including time limitations

Your output should look something like this:

## # A tibble: 10 x 1
##    post_content                                                                 
##    <chr>                                                                        
##  1 "I teach Algebra 2 as well.  I taught a Unit on Statistics in the Algebra 2 ~
##  2 "If we look at the CCSL  starting in 6th grade students begin to ask statist~
##  3 "The short class can also be a challenge.   I have sent students home with t~
##  4 "Hi Margaret      I agree with your comments.  The Coke vs Pepsi activity wa~
##  5 "I found the definitions of math and statistics helpful.  As a math major  I~
##  6 "Unfortunately  my class is small (typically 5 - 15 students) and that makes~
##  7 "Every time I teach statistics  I try to add more that my students can do  s~
##  8 "Lana  you are right!  The louder and brighter - the better for the students~
##  9 "In my first year teaching AP Stats  I found my biggest problem was finding ~
## 10 "Dear Participant         It has been a pleasure to offer the view.php?52 Te~

Creating a Document Term Matrix

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:

✅ Comprehension Check

Take a look at our forums_dtm object in the console and answer the following question:

  1. What “class” of object is forums_dtm? a simple triplet matrix

  2. How many unique documents and terms are included our matrix? documents: 5761, terms: 13666

  3. Why might there be fewer documents/posts than were in our original data frame? maybe some documents (posts) are too sparse to be useful for topic modeling

  4. What exactly is meant by “sparsity”? perhaps not enough meaningful text to enable topic modeling

## [1] "DocumentTermMatrix"    "simple_triplet_matrix"
## <<DocumentTermMatrix (documents: 5761, terms: 13666)>>
## Non-/sparse entries: 135796/78594030
## Sparsity           : 100%
## Maximal term length: 320
## Weighting          : term frequency (tf)

2c. To Stem or not to Stem?

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:

## 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:

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.

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:

## # A tibble: 165,720 x 11
##    course_id course_name       forum_id forum_name discussion_id discussion_name
##    <chr>     <chr>             <chr>    <chr>      <chr>         <chr>          
##  1 9         Teaching Statist~ 126      Investiga~ 6822          Not much compa~
##  2 9         Teaching Statist~ 126      Investiga~ 6822          Not much compa~
##  3 9         Teaching Statist~ 126      Investiga~ 6822          Not much compa~
##  4 9         Teaching Statist~ 126      Investiga~ 6822          Not much compa~
##  5 9         Teaching Statist~ 126      Investiga~ 6822          Not much compa~
##  6 9         Teaching Statist~ 126      Investiga~ 6822          Not much compa~
##  7 9         Teaching Statist~ 126      Investiga~ 6822          Not much compa~
##  8 9         Teaching Statist~ 126      Investiga~ 6822          Not much compa~
##  9 9         Teaching Statist~ 126      Investiga~ 6822          Not much compa~
## 10 9         Teaching Statist~ 126      Investiga~ 6822          Not much compa~
## # ... with 165,710 more rows, and 5 more variables: post_id <chr>,
## #   post_title <chr>, post_date <chr>, word <chr>, stem <chr>

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:

  1. How many fewer terms are in our stemmed document term matrix? documents: 5761, terms: 10060 (reduced by 3,606)

  2. Did stemming words significantly reduce the sparsity of the network? sparsity = 100% - the sparsity stayed the same

Hint: Make sure your code includes stem counts rather than word counts.

## <<DocumentTermMatrix (documents: 5761, terms: 10060)>>
## Non-/sparse entries: 129593/57826067
## Sparsity           : 100%
## Maximal term length: 320
## Weighting          : term frequency (tf)
## <<DocumentTermMatrix (documents: 5761, terms: 13666)>>
## Non-/sparse entries: 135796/78594030
## Sparsity           : 100%
## Maximal term length: 320
## Weighting          : term frequency (tf)
## # A tibble: 10,060 x 2
##    stem         n
##    <chr>    <int>
##  1 student   7346
##  2 data      4338
##  3 statist   4152
##  4 question  2470
##  5 teach     1841
##  6 school    1606
##  7 class     1520
##  8 time      1424
##  9 learn     1355
## 10 task      1214
## # ... with 10,050 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.

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:

  1. 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.
  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:

## [1] 20

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.

## [1] 20
## 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:

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:

## A topic model with 20 topics, 5777 documents and a 9306 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:

Note that you can also just use plot() as well:

✅ Comprehension Check

Fit a model for both LDA and STM using different values for K and answer the following questions:

  1. What topics appear to be similar to those using 20 topics for K?
## A topic model with 14 topics, 5777 documents and a 9306 word dictionary.

## A topic model with 12 topics, 5777 documents and a 9306 word dictionary.

  1. 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?
    • Topic 10 seems to be about experiential learning via a project that required using technology
  2. What topic emerged that seem dramatically different and how might you interpret this topic?
    • Topic 6 seems to be about the speed of a roller coaster (maybe a wooden versus a metal track?). Not knowing more, I think this may refer to a specific project

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:

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.

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:

## Loading required namespace: servr

Our current stm model of 20 topics is resulting in a lot of overlap among topics and suggests 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:

##      Topic 1      Topic 2      Topic 3       Topic 4    Topic 5    Topic 6   
## [1,] "school"     "statistics" "test"        "grade"    "students" "students"
## [2,] "students"   "em"         "students"    "data"     "task"     "level"   
## [3,] "middle"     "unit"       "standard"    "graphs"   "data"     "dice"    
## [4,] "video"      "education"  "deviation"   "students" "tasks"    "size"    
## [5,] "elementary" "teaching"   "statistical" "plots"    "question" "sample"  
##      Topic 7      Topic 8       Topic 9     Topic 10     Topic 11    
## [1,] "students"   "statistics"  "questions" "assessment" "technology"
## [2,] "statistics" "teaching"    "kids"      "resource"   "students"  
## [3,] "feel"       "math"        "love"      "items"      "software"  
## [4,] "teach"      "teachers"    "students"  "locus"      "program"   
## [5,] "questions"  "mathematics" "sharing"   "students"   "excel"     
##      Topic 12   Topic 13     Topic 14    Topic 15    Topic 16     Topic 17    
## [1,] "students" "activity"   "question"  "students"  "fuel"       "students"  
## [2,] "project"  "students"   "data"      "questions" "cost"       "makes"     
## [3,] "real"     "agree"      "students"  "class"     "src"        "regression"
## [4,] "class"    "lesson"     "questions" "learn"     "codap"      "wondering" 
## [5,] "projects" "activities" "census"    "answer"    "pluginfile" "model"     
##      Topic 18   Topic 19     Topic 20
## [1,] "data"     "sample"     "stats" 
## [2,] "students" "difference" "ap"    
## [3,] "real"     "samples"    "class" 
## [4,] "collect"  "random"     "school"
## [5,] "sets"     "population" "stat"

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:

## # A tibble: 273,320 x 3
##    topic term       beta
##    <int> <chr>     <dbl>
##  1     1 2015  1.36e- 67
##  2     2 2015  1.55e-  4
##  3     3 2015  1.73e-  4
##  4     4 2015  3.27e-  4
##  5     5 2015  4.43e- 80
##  6     6 2015  1.17e-114
##  7     7 2015  2.73e- 50
##  8     8 2015  7.10e- 40
##  9     9 2015  2.45e- 29
## 10    10 2015  1.12e-  3
## # ... with 273,310 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:

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

## # A tibble: 273,320 x 3
##    topic term       beta
##    <int> <chr>     <dbl>
##  1     1 2015  1.36e- 67
##  2     2 2015  1.55e-  4
##  3     3 2015  1.73e-  4
##  4     4 2015  3.27e-  4
##  5     5 2015  4.43e- 80
##  6     6 2015  1.17e-114
##  7     7 2015  2.73e- 50
##  8     8 2015  7.10e- 40
##  9     9 2015  2.45e- 29
## 10    10 2015  1.12e-  3
## # ... with 273,310 more rows
## # A tibble: 115,220 x 3
##    document topic    gamma
##    <chr>    <int>    <dbl>
##  1 11295        1 0.00241 
##  2 12711        1 0.000381
##  3 12725        1 0.0289  
##  4 12733        1 0.142   
##  5 12743        1 0.00928 
##  6 12744        1 0.00476 
##  7 12756        1 0.0289  
##  8 12757        1 0.00353 
##  9 12775        1 0.00353 
## 10 12816        1 0.00353 
## # ... with 115,210 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:

## Warning: `cols` is now required when using unnest().
## Please use `cols = c(terms)`
Topic Expected topic proportion Top 7 terms
Topic 7 0.087 students, statistics, feel, teach, questions, level, school
Topic 13 0.077 activity, students, agree, lesson, activities, ideas, resources
Topic 15 0.070 students, questions, class, learn, answer, reading, learning
Topic 18 0.067 data, students, real, collect, sets, set, analyze
Topic 5 0.065 students, task, data, tasks, question, statistical, activity
Topic 8 0.063 statistics, teaching, math, teachers, mathematics, teach, science
Topic 9 0.053 questions, kids, love, students, sharing, lot, gapminder
Topic 11 0.051 technology, students, software, program, excel, time, core
Topic 6 0.050 students, level, dice, size, sample, trials, technology
Topic 14 0.048 question, data, students, questions, census, answer, survey
Topic 12 0.047 students, project, real, class, projects, life, time
Topic 10 0.047 assessment, resource, items, locus, students, resources, website
Topic 1 0.046 school, students, middle, video, elementary, age, census
Topic 3 0.039 test, students, standard, deviation, statistical, results, understand
Topic 20 0.039 stats, ap, class, school, stat, math, students
Topic 4 0.037 grade, data, graphs, students, plots, 1, box
Topic 17 0.036 students, makes, regression, wondering, model, days, linear
Topic 19 0.034 sample, difference, samples, random, population, sampling, minutes
Topic 2 0.030 statistics, em, unit, education, teaching, learning, online
Topic 16 0.013 fuel, cost, src, codap, pluginfile, vehicles, city

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:

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.
  • 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.

## 
##  Topic 2: 
##       WHoops!  forgot the link to the video.  VERY SORRY!     www.ted.com talks hans_rosling_shows_the_best_stats_you_ve_ever_seen www.ted.com talks hans_rosling_shows_the_best_stats_you_ve_ever_seen  "
##      Hello Dina  your excitement perked my interest. I must say I did not really bother about these tools as I was reading them but promised myself to look closer and learn more after I read your comments. Your excitement tells me that there must be something in there that I should take a closer look on. Thanks for the vibes.
##      Thank you for putting that up! I haven't looked at the Extend your Learning section at all  but I have now bookmarked the Against all Odds website!
##      I too bookmarked the LinkedIn video.  I also continued to watch some of the SAS videos.  I plan to show some to my AP students.  I also plan to send it as a link to the guidance counselors.
##      Thank you Bonnie. I visited stattrek to help me refresh my own craftsmanship.
##      Thanks for the link. I have never used that Site before and the nurse Geen example may stimulate some good discussions.
##      When I returned from the preceding link  I accidentally rated this resource.    I would give it zero stars if I could  or one star in a do over  because it takes me to a link to purchase something.
##      Thanks for the video links.  I enjoy TED talks.
##      I've never heard of FiveThirtyEight  could you tell me more about the resource?     Thanks!  Carisa
##      Hi Keren and all      I used the following videos (or parts of them) with Business students but I think many of them would be suitable for other ares as well. I found suitable their size (about 10-15 minutes)  and often used them as a review  www.economicsnetwork.ac.uk statistics videos   And some of the older joy of stats videos  www.open.edu openlearn science-maths-technology mathematics-and-statistics statistics watch-the-joy-stats   Klara Kelecsenyi

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:

## 
##  Topic 16: 
##       Maureen   You have a good point  students want to rush through things and just get to the answer but not really think about things. I intentionally didn't re-read the questions and rushed through it just to see how I did  and I missed some things. Students would as well. I like your idea of demonstrating this for students.   "
##      The framework really makes you think about what level the students are at and what you can do to fit the task to that level. It also gives you an idea of what you can do to maybe challenge your students a little and keep them growing.
##      I agree that the reading would be difficult for many of my students. I work with mostly Tier 2 students. I had to read the questions several times myself and reason out the answers. I can see many of my students having trouble with this task. We would need to practice these types of problems many times and discuss the answers for the students to feel comfortable attempting these types of questions.
##      I have the same issues with initial questions. This is where I try to inject motivating questions to explore where my students' motivation may lie. Eventually I hope to get them asking their own questions and not get overwhelmed by the open-endness of the process.
##      I think that AP students would be up to this task and it is a topic that would interest them. I think that the questions are thought provoking and would facilitate good discussions in the classroom. It would be a good extension to ask the students what other information might improve this task to see if they would come up with age and gender as pertinent information.
##      I agree.  I think that the final question was almost more confusing (and multi-layered) then the initial questions.
##      I agree Eric in that I like this activity the best. It gives guidance and helps students learn how to conduct an experiment. Plus  it gets the entire class involved. And  as you said  it can be expanded a little to hit all 4 phases of the statistical process  and it can be transferred to other activities. I think it has a lot of potential!
##      I agree on the two different approaches  and both (I think) are very valid. I  struggle with how to intertwine the two without losing the students. They seem to want to compartmentalize the two instead of looking at them as two parts of a whole  though that could be more due to my lack of experience.   I also would like to think that many of my students would do well. I could see them not doing well because of the differences in question presentation  though. I don't give tests in the traditional sense  so this question format might be a little foreign.
##      I feel like my ap students are good students who will learn to answer those questions as well. I think they are self motivated and want to do well. After a semester I do think they will feel good about answer those questions
##      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.

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:

## 
##  Topic 3: 
##       I am a non native English speaker as well  taking the test was a little intimedating  I hope to gradually gain a better feel of terminology and content
##      The area that I feel I need the most improvement is asking better questions.  Not only do I need to pose better questions  but I need to help my students develop this skill as well.  I feel more confident that I will be able to do so or at least I am willing to try!
##      My confidence has increased slightly and my ability to find useful resources has increased a lot.  So that should translate into a classroom atmosphere where I am even more comfortable pushing students and when they ask things I cannot immediately answer  being able to say  I will get back to you tomorrow with a better answer or question! "
##      I am sure this applies to every area of math  but I find that my students with disabilities really struggle with mathematical reasoning.  They also struggle with math vocabulary.  Most could match a definition to a term  but they do not have understanding of the term when needing to make a mathematical statement to go with it.
##      Hello Katherine. My students are in the upper level Math courses  however  I found this strategy very helpful for my Math vocabulary. This might help in the Math vocabulary development for ELD students. I ask my students to just focus on one Math word  or one Math concept they learned during the week's lessons. Then I ask them to make a Math Graffiti out of the word or concept  a drawing that would subtly depict what they learned. I emphasize that I do not just want a drawing  not a formula solution  not an essay  rather I want a subtle drawing of what they learned using the word or concept. Then at the back of the Math Graffiti  I'd ask them to describe the word or concept. It really helped in how they learned concepts  at the same time asking them to verbalize  in writing  whatever they have learned. Here several modalities of learning had been used.
##      I agree that teaching students how to decode the language used in questions is one of the most important ways we can help them prepare for tests.  I think that too often we focus on vocabulary as individual mathematics and statistics words  and think that if students understand the individual words they will be able to understand the test questions.  In fact  understanding test questions is often about interpreting the little words like to or if or not  as well as the statistics words. "
##      It is always easier to teach a topic when you have had more training on the area and I believe this has made me feel way more confidant in this area!
##      I learned that I need to improve on my understanding of the basic concepts in order to teach students. I need a clear understanding of variability and other key vocabulary terms that left me guessing on the answer. "
##      My students are not at all prepared to answer the questions in the investigation.  They are all sophomores in high school and haven't had much interaction with statistics.  I would definitely need to understand the concepts in order to teach them the concepts.  I would need to feel completely confident in teaching the material beforehand.
##      I also agree that the wording in statistics questions is often difficult to understand  but like learning the specific language of any subject  the more time we and our students spend studying statistics and working statistics problems  the better prepared we will be to overcome those misconceptions.

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:

  1. 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?
  2. 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:

  1. 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?
## 
##  Topic 10: 
##       In the past I have used tinkerplots to allow students to  explore various outcomes associated with rolling two dice. They start by playing the Two-Dice Elimination game  and then simulate rolling two dice many times using TinkerPlots to determine whether a step model or a triangle model of the distribution of sums is correct. Finally  they use the triangle model to calculate the probability of rolling each sum. Students really liked this activity and really grasped the concept.
##      Is there an underlying assumption here that the two teams are equally likely to win the game? We are assuming that the octopus is equally likely to swim to either flag. But if one team is heavily favored (for example  if one of the teams has a 90% chance of winning)  and the octopus has picked the long shot team  then wouldn't his likelihood of picking the correct team be less? Or is this accounted for with the fact that the octopus is equally likely to swim to either flag  and that he was equally likely to choose the heavily favored team?
##      I also agree with the fact that the students were able to see more clearly by doing the different trials with the different amount of trials in each.  It really did help the students to see how things can be fair or unfair by doing all the trials.
##      I agree with you that I liked how the students could run a simulation of 3000 trials.  On the graphing calculator that we use (TI-84) there is a simulation program also that involves dice and coins  but we are not able to go up to 3000 trials!  We have done something similar to this using the calculator  but it would be nice to try something new with software like what was used in the video.
##      I  personally  enjoy the video simulations.  I find them more engaging and even my children are watching the video at home  )  Adding the technology aspect to the dice roll eased  created prediction  and helped to solve a pattern formation.  The student were talking to help the metacognition of thinking through their thoughts  but the computer quickly revealed dice rolls at various numbers including 3 000.  Trying to roll the dice that many times would take forever.  With the bar graph and pie graph showing the outcome  it helped students determine if the dice were bias or not.
##      Howard   There are many different software options for creating animations.  Most will allow you to use real recorded voices or a computer generated voice  but not all.  We have tried a few  the ones that you see in the course were created using goanimate.com  GoAnimate and "www.powtoon.com  Powtoon. "
##      Once students are able to manipulate the simulation software  they start to make their own inferences about the data.  Students can visually see what happens to the data when they roll the dice more than one time  or more than 50  or even more than 100.  I thought that it was interested to see the pie graph as well.  The percentages looked like they were so far apart when using the bar graph  and then in the pie graph they looked closer.  I think this was great for the students to see as well.
##      From the videos  I saw that the students we trying to level out the dice rolls. Both partners were discussing how it was it was a fair dice. The computer helped them by having the students critically think about their next move. The first pair of boys kept rolling until they got to 3 000.Then the girls rolled until they got to 36. They used and algorithm to find a good stopping point. Even with the AP Stats students  they were able to show their work to prove if the dice was fair or unfair. Eventually  at some point the students thought that the outcomes would even out.
##      It was great to see the activity being used at much different levels  but expecting similar outcomes.  The use of the various technologies really makes it accessible for all learners.
##      I liked that they had the  tool to try the simulations with increasing number of trials.  (It would be nice if my students had similar  tools.)  I wonder why one group did not  explore using larger number of trials.   The first group was able to see the difference and the second buy became  convinced after seeing enough trails.

This topic has to do with different platforms and tools used to conduct experiments (seemingly to better understand statistics). Many teachers seemed to be sharing individual tools and commenting on how they liked the learning experiences that the technology seemed to evoke from students (i.e. “metacognition”)

LS0tDQp0aXRsZTogIlRvcGljIE1vZGVsaW5nIg0KYXV0aG9yOiAiQ2F0aGVyaW5lIE5vb25hbiINCmRhdGU6ICIyLzE4LzIwMjIiDQpvdXRwdXQ6IA0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19kZXB0aDogMw0KICAgIHRvY19mbG9hdDogeWVzDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgY29kZV9kb3dubG9hZDogVFJVRQ0KZWRpdG9yX29wdGlvbnM6IA0KICBtYXJrZG93bjogDQogICAgd3JhcDogNzINCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gRkFMU0UpDQpgYGANCg0KDQojIyAxLiBQUkVQQVJFDQoNClRvIGhlbHAgdXMgYmV0dGVyIHVuZGVyc3RhbmQgdGhlIGNvbnRleHQsIHF1ZXN0aW9ucywgYW5kIGRhdGEgc291cmNlcw0Kd2UnbGwgYmUgdXNpbmcgaW4gVW5pdCAzLCB0aGlzIHNlY3Rpb24gd2lsbCBmb2N1cyBvbiB0aGUgZm9sbG93aW5nDQp0b3BpY3M6DQoNCmEuICAqKkNvbnRleHQqKi4gQXMgY29udGV4dCBmb3Igb3VyIGFuYWx5c2lzIHRoaXMgd2Vlaywgd2UnbGwgcmV2aWV3DQogICAgc2V2ZXJhbCByZWxhdGVkIHBhcGVycyBieSBteSBjb2xsZWFndWVzIHJlbGV2YW50IHRvIG91ciBhbmFseXNpcyBvZg0KICAgIE1PT0MtRWQgZGlzY3Vzc2lvbiBmb3J1bXMuDQpiLiAgKipRdWVzdGlvbnMuKiogV2UnbGwgYWxzbyBleGFtaW5lIHdoYXQgaW5zaWdodCB0b3BpYyBtb2RlbGluZyBjYW4NCiAgICBwcm92aWRlIHRvIGEgcXVlc3Rpb24gdGhhdCB3ZSBhc2tlZCBwYXJ0aWNpcGFudHMgYW5zd2VyIGluIHRoZWlyDQogICAgcHJvZmVzc2lvbmFsIGxlYXJuaW5nIHRlYW1zIChQTFRzKS4NCmMuICAqKlByb2plY3QgU2V0dXAuKiogVGhpcyBzaG91bGQgYmUgdmVyeSBmYW1pbGlhciBieSBub3csIGJ1dCB3ZSdsbA0KICAgIHNldCB1cCBhIG5ldyBSIHByb2plY3QgYW5kIGluc3RhbGwgYW5kIGxvYWQgdGhlIHJlcXVpcmVkIHBhY2thZ2VzDQogICAgZm9yIHRoZSB0b3BpYyBtb2RlbGluZyB3YWxrdGhyb3VnaC4NCg0KIyMjIDFhLiBDb250ZXh0DQoNCiMjIyMgUGFydGljaXBhdGluZyBpbiBhIE1PT0MgYW5kIFByb2Zlc3Npb25hbCBMZWFybmluZyBUZWFtOiBIb3cgYSBCbGVuZGVkIEFwcHJvYWNoIHRvIFByb2Zlc3Npb25hbCBEZXZlbG9wbWVudCBNYWtlcyBhIERpZmZlcmVuY2UNCg0KDQoNCioqQWJzdHJhY3QqKg0KDQpNYXNzaXZlIE9wZW4gT25saW5lIENvdXJzZXMgZm9yIEVkdWNhdG9ycyAoTU9PQy1FZHMpIHByb3ZpZGUNCm9wcG9ydHVuaXRpZXMgZm9yIHVzaW5nIHJlc2VhcmNoLWJhc2VkIGxlYXJuaW5nIGFuZCB0ZWFjaGluZyBwcmFjdGljZXMsDQphbG9uZyB3aXRoIG5ldyB0ZWNobm9sb2dpY2FsIHRvb2xzIGFuZCBmYWNpbGl0YXRpb24gYXBwcm9hY2hlcyBmb3INCmRlbGl2ZXJpbmcgcXVhbGl0eSBvbmxpbmUgcHJvZmVzc2lvbmFsIGRldmVsb3BtZW50LiBUaGUgVGVhY2hpbmcNClN0YXRpc3RpY3MgVGhyb3VnaCBEYXRhIEludmVzdGlnYXRpb25zIE1PT0MtRWQgd2FzIGJ1aWx0IGZvciBwcmVwYXJpbmcNCnRlYWNoZXJzIGluIHBlZGFnb2d5IGZvciB0ZWFjaGluZyBzdGF0aXN0aWNzLCBhbmQgaXQgaGFzIGJlZW4gb2ZmZXJlZCB0bw0KcGFydGljaXBhbnRzIGZyb20gYXJvdW5kIHRoZSB3b3JsZC4gRHVyaW5nIDIwMTYtMjAxNywgcHJvZmVzc2lvbmFsDQpsZWFybmluZyB0ZWFtcyAoUExUcykgd2VyZSBmb3JtZWQgZnJvbSBhIHN1YnNldCBvZiBNT09DLUVkIHBhcnRpY2lwYW50cy4NClRoZXNlIHRlYW1zIG1ldCBzZXZlcmFsIHRpbWVzIHRvIHNoYXJlIGFuZCBkaXNjdXNzIHRoZWlyIGxlYXJuaW5nIGFuZA0KZXhwZXJpZW5jZXMuIFRoaXMgc3R1ZHkgZm9jdXNlZCBvbiBleGFtaW5pbmcgdGhlIHdheXMgdGhhdCBhIGJsZW5kZWQNCmFwcHJvYWNoIHRvIHByb2Zlc3Npb25hbCBkZXZlbG9wbWVudCBtYXkgcmVzdWx0IGluIHNpbWlsYXIgb3IgZGlmZmVyZW50DQpwYXR0ZXJucyBvZiBlbmdhZ2VtZW50IHRvIHRob3NlIHdobyBvbmx5IHBhcnRpY2lwYXRlIGluIGEgbGFyZ2Utc2NhbGUNCm9ubGluZSBjb3Vyc2UuIFJlc3VsdHMgc2hvdyB0aGUgYmVuZWZpdHMgb2YgYSBibGVuZGVkIGxlYXJuaW5nDQplbnZpcm9ubWVudCBmb3IgcmV0ZW50aW9uLCBlbmdhZ2VtZW50IHdpdGggY291cnNlIG1hdGVyaWFscywgYW5kDQpjb25uZWN0ZWRuZXNzIHdpdGhpbiB0aGUgb25saW5lIGNvbW11bml0eSBvZiBsZWFybmVycyBpbiBhbiBvbmxpbmUNCnByb2Zlc3Npb25hbCBkZXZlbG9wbWVudCBvbiB0ZWFjaGluZyBzdGF0aXN0aWNzLiBUaGUgZmluZGluZ3Mgc3VnZ2VzdA0KdGhlIHVzZSBvZiBzZWxmLWZvcm1pbmcgYXV0b25vbW91cyBQTFRzIGZvciBzdXBwb3J0aW5nIGEgZGVlcGVyIGFuZCBtb3JlDQpjb21wcmVoZW5zaXZlIGV4cGVyaWVuY2Ugd2l0aCBzZWxmLWRpcmVjdGVkIG9ubGluZSBwcm9mZXNzaW9uYWwNCmRldmVsb3BtZW50cyBzdWNoIGFzIE1PT0NzLiBPdGhlciBvbmxpbmUgcHJvZmVzc2lvbmFsIGRldmVsb3BtZW50DQpjb3Vyc2VzLCBzdWNoIGFzIE1PT0NzLCBtYXkgYmVuZWZpdCBmcm9tIHB1cnBvc2VseSBzdWdnZXN0aW5nIGFuZA0KYWR2ZXJ0aXNpbmcsIGFuZCBwZXJoYXBzIGZhY2lsaXRhdGluZywgdGhlIGZvcm1hdGlvbiBvZiBzbWFsbA0KZmFjZS10by1mYWNlIG9yIHZpcnR1YWwgUExUcyB3aG8gY29tbWl0IHRvIGVuZ2FnZSBpbiBsZWFybmluZyB0b2dldGhlci4NCg0KKipEYXRhIFNvdXJjZSAmIEFuYWx5c2lzKioNCg0KQWxsIHBlZXIgaW50ZXJhY3Rpb24sIGluY2x1ZGluZyBwZWVyIGRpc2N1c3Npb24sIHRha2UgcGxhY2Ugd2l0aGluDQpkaXNjdXNzaW9uIGZvcnVtcyBvZiBNT09DLUVkcywgd2hpY2ggYXJlIGhvc3RlZCB1c2luZyB0aGUgTW9vZGxlDQpMZWFybmluZyBNYW5hZ2VtZW50IFN5c3RlbS4gVG8gYnVpbGQgdGhlIGRhdGFzZXQgeW91J2xsIGJlIHVzaW5nIGZvcg0KdGhpcyB3YWxrdGhyb3VnaCwgdGhlIHJlc2VhcmNoIHRlYW0gd3JvdGUgYSBxdWVyeSBmb3IgTW9vZGxlJ3MgTXlTUUwNCmRhdGFiYXNlLCB3aGljaCByZWNvcmRzIHBhcnRpY2lwYW50cycgdXNlci1sb2dzIG9mIGFjdGl2aXR5IGluIHRoZQ0Kb25saW5lIGZvcnVtcy4gVGhpcyBzcWwgcXVlcnkgY29tYmluZXMgc2VwYXJhdGUgZGF0YWJhc2UgdGFibGVzDQpjb250YWluaW5nIHBvc3RpbmdzIGFuZCBjb21tZW50cyBpbmNsdWRpbmcgcGFydGljaXBhbnQgSURzLCB0aW1lc3RhbXBzLA0KZGlzY3Vzc2lvbiB0ZXh0IGFuZCBvdGhlciBhdHRyaWJ1dGVzIG9yICJtZXRhZGF0YS4iDQoNCg0KDQoqKlN1bW1hcnkgb2YgS2V5IEZpbmRpbmdzKioNCg0KVGhlIGZvbGxvd2luZyBoaWdobGlnaHQgc29tZSBrZXkgZmluZGluZ3MgcmVsYXRlZCB0byB0aGUgZGlzY3Vzc2lvbg0KZm9ydW1zIGluIHRoZSBwYXBlcnMgY2l0ZWQgYWJvdmU6DQoNCjEuICBNT09DcyBkZXNpZ25lZCBzcGVjaWZpY2FsbHkgZm9yIEstMTIgdGVhY2hlcnMgY2FuIHByb3ZpZGUgcG9zaXRpdmUNCiAgICBzZWxmLWRpcmVjdGVkIGxlYXJuaW5nIGV4cGVyaWVuY2VzIGFuZCByaWNoIGVuZ2FnZW1lbnQgaW4gZGlzY3Vzc2lvbg0KICAgIGZvcnVtcyB0aGF0IGhlbHAgZm9ybSBvbmxpbmUgY29tbXVuaXRpZXMgZm9yIGVkdWNhdG9ycy4NCjIuICBBbmFseXNpcyBvZiBkaXNjdXNzaW9uIGZvcnVtIGRhdGEgaW4gVFNESSBwcm92aWRlZCBhIHZlcnkgY2xlYXINCiAgICBwaWN0dXJlIG9mIGhvdyBlbnRodXNpYXN0aWMgbWFueSBQTFQgbWVtYmVycyBhbmQgbGVhZGVycyB3ZXJlIHRvDQogICAgdGFsayB0byBvdGhlcnMgaW4gdGhlIG9ubGluZSBjb21tdW5pdHkuIFRoZXkgcG9zZWQgdGhlaXIgcXVlc3Rpb25zDQogICAgYW5kIHNoYXJlZCBpZGVhcyB3aXRoIG90aGVycyBhYm91dCB0ZWFjaGluZyBzdGF0aXN0aWNzIHRocm91Z2hvdXQNCiAgICB0aGUgdW5pdHMsIGV2ZW4gdGhvdWdoIHRoZXkgd2VyZSBhbHNvIG1lZXRpbmcgc3luY2hyb25vdXNseSBzZXZlcmFsDQogICAgdGltZXMgd2l0aCB0aGVpciBjb2xsZWFndWVzIGluIHNtYWxsIGdyb3VwIFBMVHMuDQozLiAgRmluZGluZ3Mgb24ga25vd2xlZGdlIGNvbnN0cnVjdGlvbiBkZW1vbnN0cmF0ZWQgdGhhdCBvdmVyIGhhbGYgb2YNCiAgICB0aGUgZGlzY3Vzc2lvbnMgaW4gYm90aCBjb3Vyc2VzIG1vdmVkIGJleW9uZCBzaGFyaW5nIGluZm9ybWF0aW9uIGFuZA0KICAgIHN0YXRlbWVudHMgb2YgYWdyZWVtZW50IGFuZCBlbnRlcmVkIGEgcHJvY2VzcyBvZiBkaXNzb25hbmNlLA0KICAgIG5lZ290aWF0aW9uIGFuZCBjby1jb25zdHJ1Y3Rpb24gb2Yga25vd2xlZGdlLCBidXQgc2VsZG9tIG1vdmVkDQogICAgYmV5b25kIHRoaXMgcGhhc2UgaW4gd2hpY2ggbmV3IGtub3dsZWRnZSB3YXMgdGVzdGVkIG9yIGFwcGxpZWQuDQogICAgVGhlc2UgZmluZGluZ3MgZWNobyBzaW1pbGFyIHJlc2VhcmNoIG9uIGRpZmZpY3VsdGllcyBpbiBwcm9tb3RpbmcNCiAgICBrbm93bGVkZ2UgY29uc3RydWN0aW9uIGluIG9ubGluZSBzZXR0aW5ncy4NCjQuICBUb3BpYyBtb2RlbGluZyBwcm92aWRlcyBtb3JlIGludGVycHJldGFibGUgYW5kIGNvaGVzaXZlIG1vZGVscyBmb3INCiAgICBkaXNjdXNzaW9uIGZvcnVtcyB0aGFuIG90aGVyIHBvcHVsYXIgdW5zdXBlcnZpc2VkIG1vZGVsaW5nDQogICAgdGVjaG5pcXVlcyBzdWNoIGFzIGstbWVhbnMgYW5kIGstbWVkb2lkcyBjbHVzdGVyaW5nIGFsZ29yaXRobXMuDQoNCiMjIyAxYi4gR3VpZGluZyBRdWVzdGlvbnMNCg0KRm9yIHRoZSBwYXBlciwgWypQYXJ0aWNpcGF0aW5nIGluIGEgTU9PQyBhbmQgUHJvZmVzc2lvbmFsIExlYXJuaW5nIFRlYW06DQpIb3cgYSBCbGVuZGVkIEFwcHJvYWNoIHRvIFByb2Zlc3Npb25hbCBEZXZlbG9wbWVudCBNYWtlcyBhDQpEaWZmZXJlbmNlKl0oaHR0cHM6Ly93d3cubGVhcm50ZWNobGliLm9yZy9wLzE5NTIzNC8pLCB0aGUgcmVzZWFyY2hlcnMNCndlcmUgaW50ZXJlc3RlZCBpbiB1bnBhY2tpbmcgaG93IHBhcnRpY2lwYW50cyB3aG8gZW5yb2xsZWQgaW4gdGhlDQpUZWFjaGluZyBTdGF0aXN0aWNzIHRocm91Z2ggRGF0YSBJbnZlc3RpZ2F0aW9ucyBNT09DLUVkIG1pZ2h0IGJlbmVmaXQNCmZyb20gYWxzbyBiZWluZyBpbiBhIHNtYWxsZXIgZ3JvdXAgb2YgcHJvZmVzc2lvbmFscyBjb21taXR0ZWQgdG8NCmVuZ2FnaW5nIGluIHRoZSBzYW1lIHByb2Zlc3Npb25hbCBkZXZlbG9wbWVudC4gVGhlIHNwZWNpZmljIHJlc2VhcmNoDQpxdWVzdGlvbiBmb3IgdGhpcyBwYXBlciB3YXM6DQoNCj4gV2hhdCBhcmUgdGhlIHNpbWlsYXJpdGllcyBhbmQgZGlmZmVyZW5jZXMgYmV0d2VlbiBob3cgUExUIG1lbWJlcnMgYW5kDQo+IE5vbi1QTFQgb25saW5lIHBhcnRpY2lwYW50cyBlbmdhZ2UgYW5kIG1lZXQgY291cnNlIGdvYWxzIGluIGEgTU9PQy1FZA0KPiBkZXNpZ25lZCBmb3IgZWR1Y2F0b3JzIGluIHNlY29uZGFyeSBhbmQgY29sbGVnaWF0ZSBzZXR0aW5ncz8NCg0KRHIuIEhvbGx5bHlubmUgTGVlIGFuZCB0aGUgVFNESSB0ZWFtIGFsc28gZGV2ZWxvcGVkIGEgZmFjaWxpdGF0aW9uIGd1aWRlDQpkZXNpZ25lZCBzcGVjaWZpY2FsbHkgZm9yIFBMVCB0ZWFtcyB0byBoZWxwIGdyb3VwcyBzeW50aGVzaXplIHRoZSBpZGVhcw0KaW4gdGhlIGNvdXJzZSBhbmQgbWFrZSBwbGFucyBmb3IgaG93IHRvIGltcGxlbWVudCBuZXcgc3RyYXRlZ2llcyBpbg0KdGhlaXIgY2xhc3Nyb29tIGluIG9yZGVyIHRvIGltcGFjdCBzdHVkZW50cycgbGVhcm5pbmcgb2Ygc3RhdGlzdGljcy4gT25lDQpxdWVzdGlvbiBQTFQgbWVtYmVycyB3ZXJlIGFza2VkIHRvIGFkZHJlc3Mgd2FzOg0KDQo+IFdoYXQgaWRlYXMgb3IgaXNzdWVzIGVtZXJnZWQgaW4gdGhlIGRpc2N1c3Npb24gZm9ydW1zIHRoaXMgcGFzdCB3ZWVrPw0KDQpGb3IgdGhpcyB3YWxrdGhyb3VnaCwgd2Ugd2lsbCBmdXJ0aGVyIGV4YW1pbmUgdGhhdCBxdWVzdGlvbiB0aHJvdWdoIHRoZQ0KdXNlIG9mIHRvcGljIG1vZGVsaW5nLg0KDQpBbmQganVzdCB0byByZWl0ZXJhdGUgeWV0IGFnYWluIGZyb20gVW5pdCAxLCBvbmUgb3ZlcmFyY2hpbmcgcXVlc3Rpb24NCndlJ2xsIGV4cGxvcmUgdGhyb3VnaG91dCB0aGlzIGNvdXJzZSwgYW5kIHRoYXQgU2lsZ2UgYW5kIFJvYmluc29uICgyMDE4KQ0KaWRlbnRpZnkgYXMgYSBjZW50cmFsIHF1ZXN0aW9uIHRvIHRleHQgbWluaW5nIGFuZCBuYXR1cmFsIGxhbmd1YWdlDQpwcm9jZXNzaW5nLCBpczoNCg0KPiBIb3cgZG8gd2UgdG8gKipxdWFudGlmeSoqIHdoYXQgYSBkb2N1bWVudCBvciBjb2xsZWN0aW9uIG9mIGRvY3VtZW50cw0KPiBpcyBhYm91dD8NCg0KIyMjIDFjLiBTZXQgVXANCg0KQXMgaGlnaGxpZ2h0ZWQgaW4gW0NoYXB0ZXIgNiBvZiBEYXRhIFNjaWVuY2UgaW4gRWR1Y2F0aW9uIFVzaW5nDQpSXShodHRwczovL2RhdGFzY2llbmNlaW5lZHVjYXRpb24uY29tL2MwNi5odG1sKSAoRFNJRVVSKSwgb25lIG9mIHRoZQ0KZmlyc3Qgc3RlcHMgb2YgZXZlcnkgd29ya2Zsb3cgc2hvdWxkIGJlIHRvIHNldCB1cCBhICJQcm9qZWN0IiB3aXRoaW4NClJTdHVkaW8uIFRoaXMgd2lsbCBiZSB5b3VyICJob21lIiBmb3IgYW55IGZpbGVzIGFuZCBjb2RlIHVzZWQgb3IgY3JlYXRlZA0KaW4gVW5pdCAyLg0KDQpZb3UgYXJlIHdlbGNvbWUgdG8gY29udGludWUgdXNpbmcgdGhlIHNhbWUgcHJvamVjdCBjcmVhdGVkIGZvciBVbml0IDEsDQpvciBjcmVhdGUgYW4gZW50aXJlbHkgbmV3IHByb2plY3QgZm9yIFVuaXQgMi4gSG93ZXZlciwgYWZ0ZXIgeW91J3ZlDQpjcmVhdGVkIHlvdXIgcHJvamVjdCBvcGVuIHVwIGEgbmV3IFIgc2NyaXB0LCBhbmQgbG9hZCB0aGUgZm9sbG93aW5nDQpwYWNrYWdlcyB0aGF0IHdlJ2xsIGJlIG5lZWRpbmcgZm9yIHRoaXMgd2Fsa3Rocm91Z2g6DQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KI2hhdmluZyB0cm91YmxlIGluc3RhbGxpbmcgdGhlIHN0bSBwYWNrYWdlIHNvIHRyeWluZyB0aGlzDQppZighcmVxdWlyZShkZXZ0b29scykpIGluc3RhbGwucGFja2FnZXMoImRldnRvb2xzIikNCg0KbGlicmFyeShkZXZ0b29scykNCmluc3RhbGxfZ2l0aHViKCJic3Rld2FydC9zdG0iLGRlcGVuZGVuY2llcz1UUlVFKQ0KDQojV2hlbiBJIHRyaWVkIHRvIGtuaXQgdGhpcywgaG93ZXZlciwgSSBoYWQgYWxsIGtpbmRzIG9mIGlzc3VlcyBzbyA/Pz8/DQojIEknbSBjb21tZW50aW5nIGl0IG91dA0KYGBgDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KI2luc3RhbGxpbmcgYW5kIGxvYWRpbmcgcmVxdWlyZWQgcGFja2FnZXMNCmluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpDQppbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dGV4dCIpDQppbnN0YWxsLnBhY2thZ2VzKCJTbm93YmFsbEMiKQ0KaW5zdGFsbC5wYWNrYWdlcygidG9waWNtb2RlbHMiKQ0KaW5zdGFsbC5wYWNrYWdlcygibGRhdHVuaW5nIikNCmluc3RhbGwucGFja2FnZXMoImtuaXRyIikNCmluc3RhbGwucGFja2FnZXMoIkxEQXZpcyIpDQppbnN0YWxsLnBhY2thZ2VzKCJzdG0iKQ0KYGBgDQoNCg0KYGBge3IgbG9hZC1wYWNrYWdlcywgbWVzc2FnZT1GQUxTRX0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeSh0aWR5dGV4dCkNCmxpYnJhcnkoU25vd2JhbGxDKQ0KbGlicmFyeSh0b3BpY21vZGVscykNCmxpYnJhcnkoc3RtKQ0KbGlicmFyeShsZGF0dW5pbmcpDQpsaWJyYXJ5KGtuaXRyKQ0KbGlicmFyeShMREF2aXMpDQpsaWJyYXJ5KGRldnRvb2xzKQ0KYGBgDQoNCg0KIyMgMi4gV1JBTkdMRQ0KDQojIyMgMmEuIEltcG9ydCBGb3J1bSBEYXRhDQoNCg0KYGBge3IgcmVhZC1jc3Z9DQp0c19mb3J1bV9kYXRhIDwtIHJlYWRfY3N2KCJkYXRhL3RzX2ZvcnVtX2RhdGEuY3N2IiwgDQogICAgIGNvbF90eXBlcyA9IGNvbHMoY291cnNlX2lkID0gY29sX2NoYXJhY3RlcigpLA0KICAgICAgICAgICAgICAgICAgIGZvcnVtX2lkID0gY29sX2NoYXJhY3RlcigpLCANCiAgICAgICAgICAgICAgICAgICBkaXNjdXNzaW9uX2lkID0gY29sX2NoYXJhY3RlcigpLCANCiAgICAgICAgICAgICAgICAgICBwb3N0X2lkID0gY29sX2NoYXJhY3RlcigpDQogICAgICAgICAgICAgICAgICAgKQ0KICAgICkNCmBgYA0KDQpCeSBkZWZhdWx0LCBtYW55IG9mIHRoZSBjb2x1bW5zIGxpa2UgYGNvdXJzZV9pZGAgYW5kIGBmb3J1bV9pZGAgYXJlIHJlYWQNCmluIGFzIG51bWVyaWMgZGF0YS4gRm9yIG91ciBwdXJwb3Nlcywgd2UgcGxhbiB0byB0cmVhdCB0aGVtIGFzIHVuaXF1ZQ0KaWRlbnRpZmllcnMgb3IgbmFtZXMgZm9yIG91dCBjb3Vyc2VzLCBmb3J1bXMsIGRpc2N1c3Npb25zLCBhbmQgcG9zdHMuDQpUaGUgYHJlYWRfY3N2KClgIGZ1bmN0aW9uIGhhcyBhIGhhbmR5IGBjb2xfdHlwZXMgPWAgYXJndW1lbnQgY2hhbmdpbmcNCnRoZSBjb2x1bW4gdHlwZXMgZnJvbSBudW1lcmljIHRvIGNoYXJhY3RlcnMuDQoNCiMjIyAyYi4gQ2FzdCBhIERvY3VtZW50IFRlcm0gTWF0cml4DQoNCkluIHRoaXMgc2VjdGlvbiB3ZSdsbCByZXZpc2l0IHNvbWUgZmFtaWxpYXIgYHRpZHl0ZXh0YCBmdW5jdGlvbnMgdXNlZCBpbg0KVW5pdHMgMSAmIDIgZm9yIHRpZHlpbmcgYW5kIHRva2VuaXppbmcgdGV4dCBhbmQgaW50cm9kdWNlIHNvbWUgbmV3DQpmdW5jdGlvbnMgZnJvbSB0aGUgYHN0bWAgcGFja2FnZSBmb3IgcHJvY2Vzc2luZyB0ZXh0IGFuZCB0cmFuc2Zvcm1pbmcNCm91ciBkYXRhIGZyYW1lcyBpbnRvIG5ldyBkYXRhIHN0cnVjdHVyZXMgcmVxdWlyZWQgZm9yIHRvcGljIG1vZGVsaW5nLg0KDQojIyMjIEZ1bmN0aW9ucyBVc2VkDQoNCioqYHRpZHl0ZXh0YCBmdW5jdGlvbnMqKg0KDQotICAgYHVubmVzdF90b2tlbnMoKWAgc3BsaXRzIGEgY29sdW1uIGludG8gdG9rZW5zDQotICAgYGFudGlfam9pbigpYCByZXR1cm5zIGFsbCByb3dzIGZyb20geCB3aXRob3V0IGEgbWF0Y2ggaW4geSBhbmQgdXNlZA0KICAgIHRvIHJlbW92ZSBgc3RvcCB3b3Jkc2AgZnJvbSBvdXQgZGF0YS4NCi0gICBgY2FzdF9kdG0oKWAgdGFrZXMgYSB0aWRpZWQgZGF0YSBmcmFtZSB0YWtlIGFuZCAiY2FzdHMiIGl0IGludG8gYQ0KICAgIGRvY3VtZW50LXRlcm0gbWF0cml4IChkdG0pDQoNCioqYGRwbHlyYCoqICoqZnVuY3Rpb25zKioNCg0KLSAgIGBjb3VudCgpYCBsZXRzIHlvdSBxdWlja2x5IGNvdW50IHRoZSB1bmlxdWUgdmFsdWVzIG9mIG9uZSBvciBtb3JlDQogICAgdmFyaWFibGVzDQotICAgYGdyb3VwX2J5KClgIHRha2VzIGEgZGF0YSBmcmFtZSBhbmQgb25lIG9yIG1vcmUgdmFyaWFibGVzIHRvIGdyb3VwDQogICAgYnkNCi0gICBgc3VtbWFyaXNlKClgIGNyZWF0ZXMgYSBzdW1tYXJ5IG9mIGRhdGEgdXNpbmcgYXJndW1lbnRzIGxpa2Ugc3VtIGFuZA0KICAgIG1lYW4NCg0KKipgc3RtYCBmdW5jdGlvbnMqKg0KDQotICAgYHRleHRQcm9jZXNzb3IoKWAgdGFrZXMgaW4gYSB2ZWN0b3Igb3IgY29sdW1uIG9mIHJhdyB0ZXh0cyBhbmQNCiAgICBwZXJmb3JtcyB0ZXh0IHByb2Nlc3NpbmcgbGlrZSByZW1vdmluZyBwdW5jdHVhdGlvbiBhbmQgd29yZA0KICAgIHN0ZW1taW5nLg0KLSAgIGBwcmVwRG9jdW1lbnRzKClgIHBlcmZvcm1zIHNldmVyYWwgY29ycHVzIG1hbmlwdWxhdGlvbnMgaW5jbHVkaW5nDQogICAgcmVtb3Zpbmcgd29yZHMgYW5kIHJlbnVtYmVyaW5nIHdvcmQgaW5kaWNlcw0KDQojIyMjIFRpZHlpbmcgVGV4dA0KDQpQcmlvciB0byB0b3BpYyBtb2RlbGluZywgd2UgaGF2ZSBhIGZldyByZW1haW5pbmcgc3RlcHMgdG8gdGlkeSBvdXIgdGV4dA0KdGhhdCBob3BlZnVsbHkgc2hvdWxkIGZlZWwgZmFtaWxpYXIgYnkgdGhpcyBwb2ludC4gSWYgeW91IHJlY2FsbCBmcm9tDQpbQ2hhcHRlciAxIG9mIFRleHQgTWluaW5nIFdpdGgNClJdKGh0dHBzOi8vd3d3LnRpZHl0ZXh0bWluaW5nLmNvbS90aWR5dGV4dC5odG1sKSwgdGhlc2UgcHJlcHJvY2Vzc2luZw0Kc3RlcHMgaW5jbHVkZToNCg0KMS4gIFRyYW5zZm9ybWluZyBvdXIgdGV4dCBpbnRvICJ0b2tlbnMiDQoyLiAgUmVtb3ZpbmcgdW5uZWNlc3NhcnkgY2hhcmFjdGVycywgcHVuY3R1YXRpb24sIGFuZCB3aGl0ZXNwYWNlDQozLiAgQ29udmVydGluZyBhbGwgdGV4dCB0byBsb3dlcmNhc2UNCjQuICBSZW1vdmluZyBzdG9wIHdvcmRzIHN1Y2ggYXMgInRoZSIsICJvZiIsIGFuZCAidG8iDQoNCkxldCdzIHRva2VuaXplIG91ciBmb3J1bSB0ZXh0IGFuZCBieSB1c2luZyB0aGUgZmFtaWxpYXINCmB1bm5lc3RfdG9rZW5zKClgIGFuZCByZW1vdmUgc3RvcCB3b3JkcyBwZXIgdXN1YWw6DQoNCmBgYHtyIHRva2VuaXplLWZvcnVtc30NCmZvcnVtc190aWR5IDwtIHRzX2ZvcnVtX2RhdGEgJT4lDQogIHVubmVzdF90b2tlbnMob3V0cHV0ID0gd29yZCwgaW5wdXQgPSBwb3N0X2NvbnRlbnQpICU+JQ0KICBhbnRpX2pvaW4oc3RvcF93b3JkcywgYnkgPSAid29yZCIpDQoNCmZvcnVtc190aWR5DQpgYGANCg0KTm93IGxldCdzIGRvIGEgcXVpY2sgd29yZCBjb3VudCB0byBzZWUgc29tZSBvZiB0aGUgbW9zdCBjb21tb24gd29yZHMNCnVzZWQgdGhyb3VnaG91dCB0aGUgZm9ydW1zLiBUaGlzIHNob3VsZCBnZXQgYSBzZW5zZSBvZiB3aGF0IHdlJ3JlDQp3b3JraW5nIHdpdGggYW5kIGxhdGVyIHdlJ2xsIG5lZWQgdGhlc2Ugd29yZCBjb3VudHMgZm9yIGNyZWF0aW5nIG91cg0KZG9jdW1lbnQgdGVybSBtYXRyaXggZm9yIHRvcGljIG1vZGVsaW5nOg0KDQpgYGB7ciBjb3VudC13b3Jkc30NCmZvcnVtc190aWR5ICU+JQ0KICBjb3VudCh3b3JkLCBzb3J0ID0gVFJVRSkNCmBgYA0KDQpUZXJtcyBsaWtlICJzdHVkZW50cywiICJkYXRhLCIgYW5kICJjbGFzcyIgYXJlIGFib3V0IHdoYXQgd2Ugd291bGQgaGF2ZQ0KZXhwZWN0ZWQgZnJvbSBhIGNvdXJzZSB0ZWFjaGluZyBzdGF0aXN0aWNzLiBUaGUgdGVybSAiYWdyZWUiIGFuZCAidGltZSINCmhvd2V2ZXIsIGFyZSBub3Qgc28gaW50dWl0aXZlIGFuZCB3b3J0aCBhIHF1aWNrIGxvb2sgYXMgd2VsbC4NCg0KIyMjIyMg4pyFIENvbXByZWhlbnNpb24gQ2hlY2sNCg0KVXNlIHRoZSBgZmlsdGVyKClgIGFuZCBgZ3JlcGwoKWAgZnVuY3Rpb25zIGludHJvZHVjZWQgaW4gW1VuaXQgMS4NClNlY3Rpb24NCjNiXShodHRwOi8vc2hpeWFuMjAzMC5jb20vdW5pdC0xLXdhbGt0aHJvdWdoLmh0bWwjM2JfV29yZF9TZWFyY2gpIHRvDQpmaWx0ZXIgZm9yIHJvd3MgaW4gb3VyIGB0c19mb3J1bV9kYXRhYCBkYXRhIGZyYW1lIHRoYXQgY29udGFpbiB0aGUgdGVybXMNCiJhZ3JlZSIgYW5kICJ0aW1lIiBhbmQgYW5vdGhlciB0ZXJtIG9yIHRlcm1zIG9mIHlvdXIgY2hvb3NpbmcuIFNlbGVjdCBhDQpyYW5kb20gc2FtcGxlIG9mIDEwIHBvc3RzIHVzaW5nIHRoZSBgc2FtcGxlX24oKWAgZnVuY3Rpb24gZm9yIHlvdXIgdGVybXMNCmFuZCBhbnN3ZXIgdGhlIGZvbGxvd2luZyBxdWVzdGlvbnM6DQoNCmBgYHtyfQ0KI0NvbXByZWhlbnNpb24gY2hlY2s6IGZpbHRlciBmb3Igcm93cyBpbiBvdXIgYHRzX2ZvcnVtX2RhdGFgIGRhdGEgZnJhbWUgdGhhdCANCiNjb250YWluIHRoZSB0ZXJtcyAiYWdyZWUiIGFuZCAidGltZSIgYW5kIGFub3RoZXIgdGVybSBvciB0ZXJtcyBvZiB5b3VyIA0KI2Nob29zaW5nLiANCg0KdHNfZm9ydW1fYWdyZWUgPC0gZm9ydW1zX3RpZHkgJT4lDQogIGZpbHRlcih3b3JkID09ICJhZ3JlZSIpDQoNCnRzX2ZvcnVtX3RpbWUgPC0gZm9ydW1zX3RpZHkgJT4lDQogIGZpbHRlcih3b3JkID09ICJ0aW1lIikNCg0KdHNfZm9ydW1fdGltZWFncmVlIDwtIGZvcnVtc190aWR5ICU+JQ0KICBmaWx0ZXIod29yZCAlaW4lIGMoJ3RpbWUnLCAnYWdyZWUnKSkNCg0KI1NlbGVjdCBhIHJhbmRvbSBzYW1wbGUgb2YgMTAgcG9zdHMgdXNpbmcgdGhlIGBzYW1wbGVfbigpYCANCiNmdW5jdGlvbiBmb3IgeW91ciB0ZXJtcw0KDQp0c19mb3J1bV9yYW5kc2FtcCA8LSBzYW1wbGVfbih0c19mb3J1bV9kYXRhLCAxMCkNCg0KI2FsbCB0aG9zZSB0aGluZ3MgdG9nZXRoZXINCmZvcnVtX3F1b3RlcyA8LSB0c19mb3J1bV9kYXRhICU+JQ0KICBzZWxlY3QocG9zdF9jb250ZW50KSAlPiUgDQogIGZpbHRlcihncmVwbCgndGltZScsIHBvc3RfY29udGVudCkpDQoNCnNhbXBsZV9uKGZvcnVtX3F1b3RlcywxMCkNCmBgYA0KDQoxLiAgV2hhdCwgaWYgYW55dGhpbmcsIGRvIHRoZXNlIHBvc3RzIGhhdmUgaW4gY29tbW9uPw0KICAgIA0KICAtIHNpbWlsYXIgZm9ydW0gdG9waWNzOiBlaXRoZXIgImRpc2N1c3Mgdy8geW91ciBjb2xsZWFndWVzIG9yIGludmVzdGlnYXRlIg0KDQoyLiAgV2hhdCB0b3BpY3Mgb3IgdGhlbWVzIG1pZ2h0IGJlIGFwcGFyZW50LCBvciBkbyB5b3UgYW50aWNpcGF0ZQ0KICAgIGVtZXJnaW5nLCBmcm9tIG91ciB0b3BpYyBtb2RlbGluZz8NCiAgICANCiAgLSBKdXN0IGd1ZXNzaW5nIGhlcmUgYnV0OiB0ZWNobm9sb2d5LCBhcHBsaWNhdGlvbiB0byBjbGFzc3Jvb20sIGluY2x1ZGluZw0KICAgIHRpbWUgbGltaXRhdGlvbnMgDQoNCllvdXIgb3V0cHV0IHNob3VsZCBsb29rIHNvbWV0aGluZyBsaWtlIHRoaXM6DQoNCmBgYHtyIGZpbmQtcXVvdGVzLCBlY2hvPUZBTFNFfQ0KZm9ydW1fcXVvdGVzIDwtIHRzX2ZvcnVtX2RhdGEgJT4lDQogIHNlbGVjdChwb3N0X2NvbnRlbnQpICU+JSANCiAgZmlsdGVyKGdyZXBsKCd0aW1lJywgcG9zdF9jb250ZW50KSkNCg0Kc2FtcGxlX24oZm9ydW1fcXVvdGVzLDEwKQ0KYGBgDQoNCiMjIyMgQ3JlYXRpbmcgYSBEb2N1bWVudCBUZXJtIE1hdHJpeA0KDQoNCkZvciBub3csIGhvd2V2ZXIsIGxldCB0cmVhdCBlYWNoIGluZGl2aWR1YWwgcG9zdCBhcyBhIHVuaXF1ZSAiZG9jdW1lbnQuIg0Kbm90ZWQgYWJvdmUsIHRvIGNyZWF0ZSBvdXIgZG9jdW1lbnQgdGVybSBtYXRyaXgsIHdlJ2xsIG5lZWQgdG8gZmlyc3QNCmBjb3VudCgpYCBob3cgbWFueSB0aW1lcyBlYWNoIGB3b3JkYCBvY2N1cnMgaW4gZWFjaCBkb2N1bWVudCwgb3INCmBwb3N0X2lkYCBpbiBvdXIgY2FzZSwgYW5kIGNyZWF0ZSBhIG1hdHJpeCB0aGF0IGNvbnRhaW5zIG9uZSByb3cgcGVyDQpwb3N0IGFzIG91ciBvcmlnaW5hbCBkYXRhIGZyYW1lIGRpZCwgYnV0IG5vdyBjb250YWlucyBhIGNvbHVtbiBmb3IgZWFjaA0KYHdvcmRgIGluIHRoZSBlbnRpcmUgY29ycHVzIGFuZCBhIHZhbHVlIG9mIGBuYCBmb3IgaG93IG1hbnkgdGltZXMgdGhhdA0Kd29yZCBvY2N1cnMgaW4gZWFjaCBwb3N0Lg0KDQpUbyBjcmVhdGUgdGhpcyBkb2N1bWVudCB0ZXJtIG1hdHJpeCBmcm9tIG91ciBwb3N0IGNvdW50cywgd2UnbGwgdXNlIHRoZQ0KYGNhc3RfZHRtKClgIGZ1bmN0aW9uIGxpa2Ugc28gYW5kIGFzc2lnbiBpdCB0byB0aGUgdmFyaWFibGUNCmBmb3J1bXNfZHRtYDoNCg0KYGBge3IgY2FzdC1kdG19DQpmb3J1bXNfZHRtIDwtIGZvcnVtc190aWR5ICU+JQ0KICBjb3VudChwb3N0X2lkLCB3b3JkKSAlPiUNCiAgY2FzdF9kdG0ocG9zdF9pZCwgd29yZCwgbikNCmBgYA0KDQojIyMjIyDinIUgQ29tcHJlaGVuc2lvbiBDaGVjaw0KDQpUYWtlIGEgbG9vayBhdCBvdXIgYGZvcnVtc19kdG1gIG9iamVjdCBpbiB0aGUgY29uc29sZSBhbmQgYW5zd2VyIHRoZQ0KZm9sbG93aW5nIHF1ZXN0aW9uOg0KDQoxLiAgV2hhdCAiY2xhc3MiIG9mIG9iamVjdCBpcyBgZm9ydW1zX2R0bWA/DQogICAgYSBzaW1wbGUgdHJpcGxldCBtYXRyaXgNCiAgDQoyLiAgSG93IG1hbnkgdW5pcXVlIGRvY3VtZW50cyBhbmQgdGVybXMgYXJlIGluY2x1ZGVkIG91ciBtYXRyaXg/DQogICAgZG9jdW1lbnRzOiA1NzYxLCB0ZXJtczogMTM2NjYNCg0KMy4gIFdoeSBtaWdodCB0aGVyZSBiZSBmZXdlciBkb2N1bWVudHMvcG9zdHMgdGhhbiB3ZXJlIGluIG91ciBvcmlnaW5hbA0KICAgIGRhdGEgZnJhbWU/DQogICAgbWF5YmUgc29tZSBkb2N1bWVudHMgKHBvc3RzKSBhcmUgdG9vIHNwYXJzZSB0byBiZSB1c2VmdWwgZm9yIHRvcGljIG1vZGVsaW5nDQogICAgDQo0LiAgV2hhdCBleGFjdGx5IGlzIG1lYW50IGJ5ICJzcGFyc2l0eSI/DQogICAgcGVyaGFwcyBub3QgZW5vdWdoIG1lYW5pbmdmdWwgdGV4dCB0byBlbmFibGUgdG9waWMgbW9kZWxpbmcNCg0KYGBge3IgY2xhc3MtZHRtLCBlY2hvPUZBTFNFfQ0KY2xhc3MoZm9ydW1zX2R0bSkNCg0KZm9ydW1zX2R0bQ0KYGBgDQoNCiMjIyAyYy4gVG8gU3RlbSBvciBub3QgdG8gU3RlbT8NCiMjIyMgUHJvY2Vzc2luZyBhbmQgU3RlbW1pbmcgZm9yIFNUTQ0KDQpMaWtlIGB1bm5lc3RfdG9rZW5zKClgLCB0aGUgYHRleHRQcm9jZXNzb3IoKWAgZnVuY3Rpb24gaW5jbHVkZXMgc2V2ZXJhbA0KdXNlZnVsIGFyZ3VtZW50cyBmb3IgcHJvY2Vzc2luZyB0ZXh0IGxpa2UgY29udmVydGluZyB0ZXh0IHRvIGxvd2VyY2FzZQ0KYW5kIHJlbW92aW5nIHB1bmN0dWF0aW9uIGFuZCBudW1iZXJzLiBJJ3ZlIGluY2x1ZGVkIHNldmVyYWwgb2YgdGhlc2UgaW4NCnRoZSBzY3JpcHQgYmVsb3cgYWxvbmcgd2l0aCB0aGVpciBkZWZhdWx0cyB1c2VkIGlmIHlvdSBkbyBub3QgZXhwbGljaXRseQ0Kc3BlY2lmeSBpbiB5b3VyIGZ1bmN0aW9uLiBNb3N0IG9mIHRoZXNlIGFyZSBwcmV0dHkgaW50dWl0aXZlIGFuZCB5b3UgY2FuDQpsZWFybiBtb3JlIGJ5IHZpZXdpbmcgdGhlIGA/dGV4dFByb2Nlc3NvcmAgZG9jdW1lbnRhdGlvbi4NCg0KTGV0J3MgZ28gYWhlYWQgYW5kIHByb2Nlc3Mgb3VyIGRpc2N1c3Npb24gZm9ydW0gYHBvc3RfY29udGVudGAgaW4NCnByZXBhcmF0aW9uIGZvciBzdHJ1Y3R1cmFsIHRvcGljIG1vZGVsaW5nOg0KDQpgYGB7ciB0ZXh0UHJvY2Vzc29yfQ0KdGVtcCA8LSB0ZXh0UHJvY2Vzc29yKHRzX2ZvcnVtX2RhdGEkcG9zdF9jb250ZW50LCANCiAgICAgICAgICAgICAgICAgICAgbWV0YWRhdGEgPSB0c19mb3J1bV9kYXRhLCAgDQogICAgICAgICAgICAgICAgICAgIGxvd2VyY2FzZT1UUlVFLCANCiAgICAgICAgICAgICAgICAgICAgcmVtb3Zlc3RvcHdvcmRzPVRSVUUsIA0KICAgICAgICAgICAgICAgICAgICByZW1vdmVudW1iZXJzPVRSVUUsICANCiAgICAgICAgICAgICAgICAgICAgcmVtb3ZlcHVuY3R1YXRpb249VFJVRSwgDQogICAgICAgICAgICAgICAgICAgIHdvcmRMZW5ndGhzPWMoMyxJbmYpLA0KICAgICAgICAgICAgICAgICAgICBzdGVtPVRSVUUsDQogICAgICAgICAgICAgICAgICAgIG9ubHljaGFyYWN0ZXI9IEZBTFNFLCANCiAgICAgICAgICAgICAgICAgICAgc3RyaXBodG1sPVRSVUUsIA0KICAgICAgICAgICAgICAgICAgICBjdXN0b21zdG9wd29yZHM9TlVMTCkNCmBgYA0KDQpOb3RlIHRoYXQgdGhlIGZpcnN0IGFyZ3VtZW50IHRoZSBgdGV4dFByb2Nlc3NvcmAgZnVuY3Rpb24gZXhwZWN0cyBpcyB0aGUNCmNvbHVtbiBpbiBvdXIgZGF0YSBmcmFtZSB0aGF0IGNvbnRhaW5zIHRoZSB0ZXh0IHRvIGJlIHByb2Nlc3NlZCwgdGhlDQpzZWNvbmQgYXJndW1lbnQgYG1ldGFkYXRhID1gIGV4cGVjdHMgdGhlIGRhdGEgZnJhbWUgdGhhdCBjb250YWlucyB0aGUNCnRleHQgb2YgaW50ZXJlc3QgYW5kIHVzZXMgdGhlIGNvbHVtbiBuYW1lcyB0byBsYWJlbCB0aGUgbWV0YWRhdGEgc3VjaCBhcw0KY291cnNlIGlkcyBhbmQgZm9ydW0gbmFtZXMuIFRoaXMgbWVhdGRhdGEgY2FuIGJlIHVzZWQgdG8gdG8gaW1wcm92ZSB0aGUNCmFzc2lnbm1lbnQgb2Ygd29yZHMgdG8gdG9waWNzIGluIGEgY29ycHVzIGFuZCBleGFtaW5lIHRoZSByZWxhdGlvbnNoaXANCmJldHdlZW4gdG9waWNzIGFuZCB2YXJpb3VzIGNvdmFyaWF0ZXMgb2YgaW50ZXJlc3QuDQoNClVubGlrZSB0aGUgYHVubmVzdF90b2tlbnMoKWAgZnVuY3Rpb24sIHRoZSBvdXRwdXQgaXMgbm90IGEgbmljZSB0aWR5DQpkYXRhIGZyYW1lLiBUb3BpYyBtb2RlbGluZyB1c2luZyB0aGUgYHN0bWAgcGFja2FnZSByZXF1aXJlcyBhIHZlcnkNCnVuaXF1ZSBzZXQgb2YgaW5wdXRzIHRoYXQgYXJlIHNwZWNpZmljIHRvIHRoZSBwYWNrYWdlLiBUaGUgZm9sbG93aW5nDQpjb2RlIHdpbGwgcHVsbCBlbGVtZW50cyBmcm9tIHRoZSBgdGVtcGAgbGlzdCB0aGF0IHdhcyBjcmVhdGVkIHRoYXQgd2lsbA0KYmUgcmVxdWlyZWQgZm9yIHRoZSBgc3RtKClgIGZ1bmN0aW9uIHdlJ2xsIHVzZSBpbiBTZWN0aW9uIDQ6DQoNCmBgYHtyIHN0bS1pbnB1dHN9DQptZXRhIDwtIHRlbXAkbWV0YQ0Kdm9jYWIgPC0gdGVtcCR2b2NhYg0KZG9jcyA8LSB0ZW1wJGRvY3VtZW50cw0KYGBgDQoNCiMjIyMgU3RlbW1pbmcgVGlkeSBUZXh0DQoNCk5vdGljZSB0aGF0IHRoZSBgdGV4dFByb2Nlc3NvcmAgc3RlbSBhcmd1bWVudCB3ZSB1c2VkIGFib3ZlIGlzIHNldCB0bw0KYFRSVUVgIGJ5IGRlZmF1bHQuIFdlIGhhdmVuJ3QgaW50cm9kdWNlZCB3b3JkIHN0ZW1taW5nIGF0IHRoaXMgcG9pbnQNCmJlY2F1c2UgdGhlcmUgaXMgc29tZSBkZWJhdGUgYWJvdXQgdGhlIGFjdHVhbCB2YWx1ZSBvZiB0aGlzIHByb2Nlc3MuDQpXaGlsZSB3b3JkcyBsaWtlICJzdHVkZW50cyIgYW5kICJzdHVkZW50IiBtaWdodCBtYWtlIHNlbnNlIHRvIGNvbGxhcHNlDQppbnRvIHRoZWlyIGJhc2Ugd29yZCBhbmQgYWN0dWFsbHkgbWFrZSBhbmFseXNlcyBhbmQgdmlzdWFsaXphdGlvbnMgbW9yZQ0KY29uY2lzZSBhbmQgZWFzaWVyIHRvIGludGVycHJldC4gW0h2aXRmZWxkdCBhbmQgU2lsZ2UNCigyMDIxKV0oaHR0cHM6Ly9zbWx0YXIuY29tL3N0ZW1taW5nLmh0bWwpIG5vdGUsIGhvd2V2ZXIsIHRoYXQgd29yZHMgbGlrZQ0KdGhlIGZvbGxvd2luZyBoYXZlIGRyYW1hdGljIGRpZmZlcmVuY2VzIGluIG1lYW5pbmcsIHNlbWFudGljcywgYW5kIHVzZQ0KYW5kIGNvdWxkIHJlc3VsdCBpbiBwb29yIG1vZGVscyBvciBtaXNpbnRlcnByZXRlZCByZXN1bHRzOg0KDQotICAgbWVhbmluZyBhbmQgbWVhbg0KLSAgIGxpa2VseSwgbGlrZSwgbGlraW5nDQotICAgdW5pdmVyc2l0eSBhbmQgdW5pdmVyc2UNCg0KVGhlIGZpcnN0IHdvcmQgcGFpciBpcyBwYXJ0aWN1bGFybHkgcmVsZXZhbnQgdG8gZGlzY3Vzc2lvbiBwb3N0cyBmcm9tDQpvdXIgVGVhY2hpbmcgU3RhdGlzdGljcyBjb3Vyc2UgZGF0YS4gSW4gYWRkaXRpb24sIGNvbGxhcHNpbmcgd29yZHMgbGlrZQ0KInRlYWNoZXJzIiBhbmQgInRlYWNoaW5nIiBjb3VsZCBkcmFtYXRpY2FsbHkgYWx0ZXIgdGhlIHJlc3VsdHMgZnJvbSBhDQp0b3BpYyBtb2RlbC4NCg0KRm9yIG5vdywgd2Ugd2lsbCBsZWF2ZSBhcyBpcyB0aGUgYGZvcnVtc19kdG1gIHdlIGNyZWF0ZWQgZWFybGllciB3aXRoDQp3b3JkcyB1bnN0ZW1tZWQsIGJ1dCB3aGF0IGlmIHdlIHdhbnRlZCB0byBzdGVtIHdvcmRzIGluIGEgInRpZHkiIHdheT8NCg0KU2luY2UgdGhlIGB1bm5lc3RfdG9rZW5zKClgIGZ1bmN0aW9uIGRvZXMgbm90IChpbnRlbnRpb25hbGx5IEkgYmVsaWV2ZSkNCmluY2x1ZGUgYSBzdGVtbWluZyBmdW5jdGlvbiwgb25lIGFwcHJvYWNoIHdvdWxkIGJlIHRvIHVzZSB0aGUNCmB3b3JkU3RlbSgpYCBmdW5jdGlvbiBmcm9tIHRoZSBgc25vd2JhbGxDYCBwYWNrYWdlIHRvIGVpdGhlciByZXBsYWNlIG91cg0KYHdvcmRzYCBjb2x1bW4gd2l0aCBhIHdvcmQgc3RlbXMgb3IgY3JlYXRlIGEgbmV3IHZhcmlhYmxlIGNhbGxlZCBgc3RlbWANCndpdGggb3VyIHN0ZW1tZWQgd29yZHMuIExldCdzIGRvIHRoZSBsYXR0ZXIgYW5kIHRha2UgYSBsb29rIGF0IHRoZQ0Kb3JpZ2luYWwgd29yZHMgYW5kIHRoZSBzdGVtIHRoYXQgd2FzIHByb2R1Y2VkOg0KDQpgYGB7ciB3b3JkU3RlbX0NCnN0ZW1tZWRfZm9ydW1zIDwtIHRzX2ZvcnVtX2RhdGEgJT4lDQogIHVubmVzdF90b2tlbnMob3V0cHV0ID0gd29yZCwgaW5wdXQgPSBwb3N0X2NvbnRlbnQpICU+JQ0KICBhbnRpX2pvaW4oc3RvcF93b3JkcywgYnkgPSAid29yZCIpICU+JQ0KICBtdXRhdGUoc3RlbSA9IHdvcmRTdGVtKHdvcmQpKQ0KDQpzdGVtbWVkX2ZvcnVtcw0KYGBgDQoNCllvdSBjYW4gc2VlIHRoYXQgd29yZHMgbGlrZSAiYWN0aXZpdHkiIGFuZCAiYWN0aXZpdGllcyIgdGhhdCBvY2N1cg0KZnJlcXVlbnRseSBpbiBvdXIgZGlzY3Vzc2lvbnMgaGF2ZSBiZWVuIHJlZHVjZWQgdG8gdGhlIHdvcmQgc3RlbQ0KImFjdGl2Ii4gSWYgeW91IGFyZSBpbnRlcmVzdGVkIGluIGxlYXJuaW5nIG90aGVyIGFwcHJvYWNoZXMgZm9yIHdvcmQNCnN0ZW1taW5nIGluIFIsIGFzIHdlbGwgYXMgcmVhZGluZyBhIG1vcmUgaW4gZGVwdGggZGVzY3JpcHRpb24gb2YgdGhlDQpzdGVtbWluZyBwcm9jZXNzLCBJIGhpZ2hseSByZWNvbW1lbmQgdGhlIFtDaGFwdGVyIDQNClN0ZW1taW5nXShodHRwczovL3NtbHRhci5jb20vc3RlbW1pbmcuaHRtbCkgZnJvbSBIdml0ZmVsZHQgYW5kIFNpbGdlDQooMjAyMSkgYm9vaywgKlN1cGVydmlzZWQgTWFjaGluZSBMZWFybmluZyBmb3IgVGV4dCBBbmFseXNpcyBpbiBSKi4NCg0KIyMjIyMg4pyFIENvbXByZWhlbnNpb24gQ2hlY2sNCg0KQ29tcGxldGUgdGhlIGZvbGxvd2luZyBjb2RlIHVzaW5nIHdoYXQgd2UgbGVhcm5lZCBpbiB0aGUgc2VjdGlvbiBvbg0KW0NyZWF0aW5nIGEgRG9jdW1lbnQgVGVybSBNYXRyaXhdIGFuZCBhbnN3ZXIgdGhlIGZvbGxvd2luZyBxdWVzdGlvbnM6DQoNCjEuICBIb3cgbWFueSBmZXdlciB0ZXJtcyBhcmUgaW4gb3VyIHN0ZW1tZWQgZG9jdW1lbnQgdGVybSBtYXRyaXg/DQogICAgZG9jdW1lbnRzOiA1NzYxLCB0ZXJtczogMTAwNjAgKHJlZHVjZWQgYnkgMyw2MDYpDQogICAgDQoyLiAgRGlkIHN0ZW1taW5nIHdvcmRzIHNpZ25pZmljYW50bHkgcmVkdWNlIHRoZSBzcGFyc2l0eSBvZiB0aGUgbmV0d29yaz8NCiAgICBzcGFyc2l0eSA9IDEwMCUgLSB0aGUgc3BhcnNpdHkgc3RheWVkIHRoZSBzYW1lDQoNCioqSGludDoqKiBNYWtlIHN1cmUgeW91ciBjb2RlIGluY2x1ZGVzIHN0ZW0gY291bnRzIHJhdGhlciB0aGFuIHdvcmQNCmNvdW50cy4NCg0KYGBge3Igc3RlbS1wcmFjdGljZSwgZXZhbD1GQUxTRX0NCnN0ZW1tZWRfZHRtIDwtIHRzX2ZvcnVtX2RhdGEgJT4lDQogIHVubmVzdF90b2tlbnMob3V0cHV0ID0gd29yZCwgaW5wdXQgPSBwb3N0X2NvbnRlbnQpICU+JQ0KICBhbnRpX2pvaW4oc3RvcF93b3JkcywgYnkgPSAid29yZCIpICU+JQ0KICBtdXRhdGUoc3RlbSA9IHdvcmRTdGVtKHdvcmQpKSAlPiUNCiAgY291bnQocG9zdF9pZCwgc3RlbSkgJT4lDQogIGNhc3RfZHRtKHBvc3RfaWQsIHN0ZW0sIG4pDQogIA0Kc3RlbW1lZF9kdG0NCmBgYA0KDQpgYGB7ciBzdGVtLWNvdW50cywgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCnN0ZW1tZWRfZHRtIDwtIHRzX2ZvcnVtX2RhdGEgJT4lDQogIHVubmVzdF90b2tlbnMob3V0cHV0ID0gd29yZCwgaW5wdXQgPSBwb3N0X2NvbnRlbnQpICU+JQ0KICBhbnRpX2pvaW4oc3RvcF93b3JkcywgYnkgPSAid29yZCIpICU+JQ0KICBtdXRhdGUoc3RlbSA9IHdvcmRTdGVtKHdvcmQpKSAlPiUNCiAgY291bnQocG9zdF9pZCwgc3RlbSwgc29ydCA9IFRSVUUpICU+JQ0KICBjYXN0X2R0bShwb3N0X2lkLCBzdGVtLCBuKQ0KDQpzdGVtbWVkX2R0bQ0KZm9ydW1zX2R0bQ0KDQpzdGVtX2NvdW50cyA8LSB0c19mb3J1bV9kYXRhICU+JQ0KICB1bm5lc3RfdG9rZW5zKG91dHB1dCA9IHdvcmQsIGlucHV0ID0gcG9zdF9jb250ZW50KSAlPiUNCiAgYW50aV9qb2luKHN0b3Bfd29yZHMsIGJ5ID0gIndvcmQiKSAlPiUNCiAgbXV0YXRlKHN0ZW0gPSB3b3JkU3RlbSh3b3JkKSkgJT4lDQogIGNvdW50KHN0ZW0sIHNvcnQgPSBUUlVFKQ0KDQpzdGVtX2NvdW50cw0KYGBgDQoNCiMjIDMuIE1PREVMDQoNClRoaXMgdW5pdCBwcm92aWRlcyBvdXIgZmlyc3Qgb3Bwb3J0dW5pdHkgZm9yIG1vZGVsaW5nIGEgdGV4dCBhcyBkYXRhLiBJbg0KdmVyeSBzaW1wbGUgdGVybXMsIG1vZGVsaW5nIGludm9sdmVzIGRldmVsb3BpbmcgYSBtYXRoZW1hdGljYWwgc3VtbWFyeQ0Kb2YgYSBkYXRhc2V0LiBUaGVzZSBzdW1tYXJpZXMgY2FuIGhlbHAgdXMgZnVydGhlciBleHBsb3JlIHRyZW5kcyBhbmQNCnBhdHRlcm5zIGluIG91ciBkYXRhLg0KDQoNCiMjIyAzYS4gRml0dGluZyBhIFRvcGljIE1vZGVsaW5nIHdpdGggTERBDQoNCkJlZm9yZSBydW5uaW5nIG91ciBmaXJzdCB0b3BpYyBtb2RlbCB1c2luZyB0aGUgYExEQSgpYCBmdW5jdGlvbiwgbGV0J3MNCnF1aWNrIHJlY2FwIGZyb20gb3VyIHJlYWRpbmdzIHNvbWUgYmFzaWMgcHJpbmNpcGxlcyBiZWhpbmQgTGF0ZW50DQpEaXJpY2hsZXQgYWxsb2NhdGlvbiBhbmQgd2h5IExEQSBpcyBvZiBwcmVmZXJyZWQgb3ZlciBvdGhlciBhdXRvbWF0aWMNCmNsYXNzaWZpY2F0aW9uIG9yIGNsdXN0ZXJpbmcgYXBwcm9hY2hlcy4NCg0KVW5saWtlIHNpbXBsZSBmb3JtcyBvZiBjbHVzdGVyIGFuYWx5c2lzIHN1Y2ggYXMgay1tZWFucyBjbHVzdGVyaW5nLCBMREENCmlzIGEgKioibWl4dHVyZSIgbW9kZWwqKiwgd2hpY2ggaW4gb3VyIGNvbnRleHQgbWVhbnMgdGhhdDoNCg0KMS4gICoqRXZlcnkgW2RvY3VtZW50XXsudWx9IGNvbnRhaW5zIGEgbWl4dHVyZSBvZiB0b3BpY3MuKiogVW5saWtlDQogICAgYWxnb3JpdGhtcyBsaWtlIGstbWVhbnMsIExEQSB0cmVhdHMgZWFjaCBkb2N1bWVudCBhcyBhIG1peHR1cmUgb2YNCiAgICB0b3BpY3MsIHdoaWNoIGFsbG93cyBkb2N1bWVudHMgdG8gIm92ZXJsYXAiIGVhY2ggb3RoZXIgaW4gdGVybXMgb2YNCiAgICBjb250ZW50LCByYXRoZXIgdGhhbiBiZWluZyBzZXBhcmF0ZWQgaW50byBkaXNjcmV0ZSBncm91cHMuIFNvIGluDQogICAgcHJhY3RpY2UsIHRoaXMgbWVhbnMgdGhhdCBhIGRpc2N1c3Npb24gZm9ydW0gcG9zdCBjb3VsZCBoYXZlIGFuDQogICAgZXN0aW1hdGVkIHRvcGljIHByb3BvcnRpb24gb2YgNzAlIGZvciBUb3BpYyAxIChlLmcuIGJlIG1vc3RseSBhYm91dA0KICAgIGEgVG9waWMgMSksIGJ1dCBhbHNvIGJlIHBhcnRseSBhYm91dCBUb3BpYyAyLg0KMi4gICoqRXZlcnkgW3RvcGljXXsudWx9IGNvbnRhaW5zIGEgbWl4dHVyZSBvZiB3b3Jkcy4qKsKgRm9yIGV4YW1wbGUsIGlmDQogICAgd2Ugc3BlY2lmaWVkIGluIG91ciBMREEgbW9kZWwganVzdCAyIHRvcGljcyBmb3Igb3VyIGRpc2N1c3Npb24NCiAgICBwb3N0cywgd2UgbWlnaHQgZmluZCB0aGF0IG9uZSB0b3BpYyBzZWVtcyB0byBiZSBhYm91dCBwZWRhZ29neSB3aGlsZQ0KICAgIGFub3RoZXIgaXMgYWJvdXQgbGVhcm5pbmcuIFRoZSBtb3N0IGNvbW1vbiB3b3JkcyBpbiB0aGUgcGVkYWdvZ3kNCiAgICB0b3BpYyBtaWdodCBiZSAidGVhY2hlciIsICJzdHJhdGVnaWVzIiwgYW5kICJpbnN0cnVjdGlvbiIsIHdoaWxlIHRoZQ0KICAgIGxlYXJuaW5nIHRvcGljIG1heSBiZSBtYWRlIHVwIG9mIHdvcmRzIGxpa2UgInVuZGVyc3RhbmRpbmciIGFuZA0KICAgICJzdHVkZW50cyIuIEhvd2V2ZXIsIHdvcmRzIGNhbiBiZSBzaGFyZWQgYmV0d2VlbiB0b3BpY3MgYW5kIHdvcmRzDQogICAgbGlrZSAic3RhdGlzdGljcyIgb3IgImFzc2Vzc21lbnQiIG1pZ2h0IGFwcGVhciBpbiBib3RoIGVxdWFsbHkuDQoNClNpbWlsYXIgdG8gay1tZWFucyBvdGhlciBvdGhlciBzaW1wbGUgY2x1c3RlcmluZyBhcHByb2FjaGVzLCBob3dldmVyLA0KTERBIGRvZXMgcmVxdWlyZSB1cyB0byBzcGVjaWZ5IGEgdmFsdWUgb2YgKmsqIGZvciB0aGUgbnVtYmVyIG9mIHRvcGljcw0KaW4gb3VyIGNvcnB1cy4gU2VsZWN0aW5nICprKiBpcyBubyB0cml2aWFsIG1hdHRlciBhbmQgY2FuIGdyZWF0bHkgaW1wYWN0DQp5b3VyIHJlc3VsdHMuDQoNClNpbmNlIHdlIGRvbid0IGhhdmUgYSBoYXZlIHN0cm9uZyByYXRpb25hbGUgYWJvdXQgdGhlIG51bWJlciBvZiB0b3BpY3MNCnRoYXQgbWlnaHQgZXhpc3QgaW4gZGlzY3Vzc2lvbiBmb3J1bXMsIGxldCdzIHVzZSB0aGUgYG5fZGlzdGluY3QoKWANCmZ1bmN0aW9uIGZyb20gdGhlIGBkcGx5cmAgcGFja2FnZSB0byBmaW5kIHRoZSBudW1iZXIgb2YgdW5pcXVlIGZvcnVtDQpuYW1lcyBpbiBvdXIgY291cnNlIGRhdGEgYW5kIHJ1biB3aXRoIHRoYXQ6DQoNCmBgYHtyIG4tZGlzdGluY3R9DQpuX2Rpc3RpbmN0KHRzX2ZvcnVtX2RhdGEkZm9ydW1fbmFtZSkNCmBgYA0KDQpTaW5jZSBpdCBsb29rcyBsaWtlIHRoZXJlIGFyZSAyMCBkaXN0aW5jdCBkaXNjdXNzaW9uIGZvcnVtcywgd2UnbGwgdXNlDQp0aGF0IGFzIG91ciB2YWx1ZSBmb3IgdGhlIGBrID1gIGFyZ3VtZW50IG9mIHRoZSBgTERBKClgLiBCZSBwYXRpZW50DQp3aGlsZSB0aGlzIHJ1bnMsIHNpbmNlIHRoZSBkZWZhdWx0IHNldHRpbmcgb2YgaXMgdG8gcGVyZm9ybSBhIGxhcmdlDQpudW1iZXIgb2YgaXRlcmF0aW9ucy4NCg0KYGBge3IgTERBfQ0Kbl9kaXN0aW5jdCh0c19mb3J1bV9kYXRhJGZvcnVtX25hbWUpDQoNCmZvcnVtc19sZGEgPC0gTERBKGZvcnVtc19kdG0sIA0KICAgICAgICAgICAgICAgICAgayA9IDIwLCANCiAgICAgICAgICAgICAgICAgIGNvbnRyb2wgPSBsaXN0KHNlZWQgPSA1ODgpDQogICAgICAgICAgICAgICAgICApDQoNCmZvcnVtc19sZGENCmBgYA0KDQpOb3RlIHRoYXQgd2UgdXNlZCB0aGUgYGNvbnRyb2wgPWAgYXJndW1lbnQgdG8gcGFzcyBhIHJhbmRvbSBudW1iZXINCihgNTg4YCkgdG8gc2VlZCB0aGUgYXNzaWdubWVudCBvZiB0b3BpY3MgdG8gZWFjaCB3b3JkIGluIG91ciBjb3JwdXMuDQpTaW5jZSBMREEgaXMgYSBbc3RvY2hhc3RpYw0KYWxnb3JpdGhtXShodHRwczovL21hY2hpbmVsZWFybmluZ21hc3RlcnkuY29tL3N0b2NoYXN0aWMtaW4tbWFjaGluZS1sZWFybmluZy8pDQp0aGF0IGNvdWxkIGhhdmUgZGlmZmVyZW50IHJlc3VsdHMgZGVwZW5kaW5nIG9uIHdoZXJlIHRoZSBhbGdvcml0aG0NCnN0YXJ0cywgc3BlY2lmaWVkIGEgYHNlZWRgIGZvciByZXByb2R1Y2liaWxpdHkgYW5kIHNvIHdlJ3JlIGFsbCBzZWVpbmcNCnRoZSBzYW1lIHJlc3VsdHMgZXZlcnkgdGltZSB3ZSBzcGVjaWZ5IHRoZSBzYW1lIG51bWJlciBvZiB0b3BpY3MuDQoNCkFuZCB0eWluZyBiYWNrIHRvIG91ciB3b3JrIGluIFVuaXQgMSwgQmFpbCAoMjAyMCkgbm90ZXMgdGhhdCB0b3BpYw0KYXNzaWdubWVudHMgZm9yIGVhY2ggd29yZCBhcmUgdXBkYXRlZCBpbiBhbiBpdGVyYXRpdmUgZmFzaGlvbiBhbmQgdGhhdA0KTERBIGVtcGxveXMgdGhlIFRlcm0gRnJlcXVlbmN5LUludmVyc2UgRG9jdW1lbnQgRnJlcXVlbmN5IChURi1JREYpDQptZXRyaWMgdG8gYXNzaWduIHByb2JhYmlsaXRpZXMuDQoNCiMjIyAzYi4gRml0dGluZyBhIFN0cnVjdHVyYWwgVG9waWMgTW9kZWwNCg0KQmFpbCBub3RlcyB0aGF0IExEQSwgd2hpbGUgcGVyaGFwcyB0aGUgbW9zdCBjb21tb24gYXBwcm9hY2ggdG8gdG9waWMNCm1vZGVsaW5nLCBpcyBqdXN0IG9uZSBvZiBtYW55IGRpZmZlcmVudCB0eXBlcywgaW5jbHVkaW5nIER5bmFtaWMgVG9waWMNCk1vZGVscywgQ29ycmVsYXRlZCBUb3BpYyBNb2RlbHMsIEhpZXJhcmNoaWNhbCBUb3BpYyBNb2RlbHMsIGFuZCBtb3JlDQpyZWNlbnRseSwgU3RydWN0dXJhbCBUb3BpYyBNb2RlbGluZyAoU1RNKS4gSGUgYXJndWVzIHRoYXQgb25lIHJlYXNvbiBTVE0NCmhhcyByaXNpbmcgaW4gcG9wdWxhcml0eSBhbmQgdXNlIGlzIHRoYXQgaXQgZW1wbG95cyBtZXRhIGRhdGEgYWJvdXQNCmRvY3VtZW50cyB0byBpbXByb3ZlIHRoZSBhc3NpZ25tZW50IG9mIHdvcmRzIHRvIHRvcGljcyBpbiBhIGNvcnB1cyBhbmQNCnRoYXQgY2FuIGJlIHVzZWQgdG8gZXhhbWluZSByZWxhdGlvbnNoaXBzIGJldHdlZW4gY292YXJpYXRlcyBhbmQNCmRvY3VtZW50cy7CoA0KDQpBbHNvLCBzaW5jZSBKdWxpYSBTaWxnZSBoYXMgaW5kaWNhdGVkIHRoYXQgU1RNIGlzLCAibXkgY3VycmVudCBmYXZvcml0ZQ0KaW1wbGVtZW50YXRpb24gb2YgdG9waWMgbW9kZWxpbmcgaW4gUiIgYW5kIGhhcyBidWlsdCBzdXBwb3J0cyBpbiB0aGUNCmB0aWR5dGV4dGAgcGFja2FnZSBmb3IgYnVpbGRpbmcgc3RydWN0dXJhbCB0b3BpYyBtb2RlbHMsIHRoaXMgcGFja2FnZQ0KZGVmaW5pdGVseSBpcyB3b3J0aCBkaXNjdXNzaW5nIGluIHRoaXMgd2Fsa3Rocm91Z2guIEkgYWxzbyBoaWdobHkNCnJlY29tbWVuZCBoZXIgb3duIHdhbGt0aHJvdWdoIG9mIHRoZSBgc3RtYCBwYWNrYWdlOiBbVGhlIGdhbWUgaXMgYWZvb3QhDQpUb3BpYyBtb2RlbGluZyBvZiBTaGVybG9jayBIb2xtZXMNCnN0b3JpZXNdKGh0dHBzOi8vanVsaWFzaWxnZS5jb20vYmxvZy9zaGVybG9jay1ob2xtZXMtc3RtLykgYXMgd2VsbCBhcw0KaGVyIGZvbGxvdyB1cCBwb3N0LCBbVHJhaW5pbmcsIGV2YWx1YXRpbmcsIGFuZCBpbnRlcnByZXRpbmcgdG9waWMNCm1vZGVsc10oaHR0cHM6Ly9qdWxpYXNpbGdlLmNvbS9ibG9nL2V2YWx1YXRpbmctc3RtLykuDQoNCiMjIyMgVGhlIGBzdG1gIFBhY2thZ2UNCg0KQXMgd2UndmUgc2VlbiBhYm92ZSwgU1RNIHByb2R1Y2VkIGFuIHVudXN1YWwgYHRlbXBgIHRleHRQcm9jZXNzb3Igb3V0cHV0DQp0aGF0IGlzIHVuaXF1ZSB0byB0aGUgYHN0bWAgcGFja2FnZS4gQW5kIGFzIHlvdSd2ZSBwcm9iYWJseSBhbHJlYWR5DQpndWVzc2VkLCB0aGUgYHN0bSgpYCBmdW5jdGlvbiBmb3IgZml0dGluZyBhIHN0cnVjdHVyYWwgdG9waWMgbW9kZWwgZG9lcw0Kbm90IHRha2UgYSBmYWlybHkgc3RhbmRhcmQgZG9jdW1lbnQgdGVybSBtYXRyaXggbGlrZSB0aGUgYExEQSgpYA0KZnVuY3Rpb24uDQoNCkJlZm9yZSB3ZSBmaXQgb3VyIG1vZGVsLCB3ZSdsbCBoYXZlIHRvIGV4dHJhY3QgdGhlIGVsZW1lbnRzIGZyb20gdGhlDQpgdGVtcGAgb2JqZWN0IGNyZWF0ZWQgYWZ0ZXIgd2UgcHJvY2Vzc2VkIG91ciB0ZXh0LiBTcGVjaWZpY2FsbHksIHRoZQ0KYHN0bSgpYCBmdW5jdGlvbiBleHBlY3RzIHRoZSBmb2xsb3dpbmcgYXJndW1lbnRzOg0KDQotICAgYGRvY3VtZW50cyA9YCB0aGUgZG9jdW1lbnQgdGVybSBtYXRyaXggdG8gYmUgbW9kZWxlZCBpbiB0aGUgbmF0aXZlDQogICAgc3RtIGZvcm1hdA0KLSAgIGBkYXRhID1gIGFuIG9wdGlvbmFsIGRhdGEgZnJhbWUgY29udGFpbmluZyBtZXRhIGRhdGEgZm9yIHRoZQ0KICAgIHByZXZhbGVuY2UgYW5kL29yIGNvbnRlbnQgY292YXJpYXRlcyB0byBpbmNsdWRlIGluIHRoZSBtb2RlbA0KLSAgIGB2b2NhYiA9YCBhIGNoYXJhY3RlciB2ZWN0b3Igc3BlY2lmeWluZyB0aGUgd29yZHMgaW4gdGhlIGNvcnB1cyBpbg0KICAgIHRoZSBvcmRlciBvZiB0aGUgdm9jYWIgaW5kaWNlcyBpbiBkb2N1bWVudHMuDQoNCkxldCdzIGdvIGFoZWFkIGFuZCBleHRyYWN0IHRoZXNlIGVsZW1lbnRzOg0KDQpgYGB7ciBzdG0tZG9jc30NCmRvY3MgPC0gdGVtcCRkb2N1bWVudHMgDQptZXRhIDwtIHRlbXAkbWV0YSANCnZvY2FiIDwtIHRlbXAkdm9jYWIgDQpgYGANCg0KQW5kIG5vdyB1c2UgdGhlc2UgZWxlbWVudHMgdG8gZml0IHRoZSBtb2RlbCB1c2luZyB0aGUgc2FtZSBudW1iZXIgb2YNCnRvcGljcyBmb3IgKksqIHRoYXQgd2Ugc3BlY2lmaWVkIGZvciBvdXIgTERBIHRvcGljIG1vZGVsLiBMZXQncyBhbHNvDQp0YWtlIGFkdmFudGFnZSBvZiB0aGUgZmFjdCB0aGF0IHdlIGNhbiBpbmNsdWRlIHRoZSBgY291cnNlX2lkYCBhbmQNCmBmb3J1bV9pZGAgY292YXJpYXRlcyBpbiB0aGUgYHByZXZlYWxlbmNlID1gIGFyZ3VtZW50IHRvIGhlbHAgaW1wcm92ZSwNCmluIHRoZW9yeSwgb3VyIG1vZGVsIGZpdDoNCg0KYGBge3Igc3RtfQ0KZm9ydW1zX3N0bSA8LSBzdG0oZG9jdW1lbnRzPWRvY3MsIA0KICAgICAgICAgZGF0YT1tZXRhLA0KICAgICAgICAgdm9jYWI9dm9jYWIsIA0KICAgICAgICAgcHJldmFsZW5jZSA9fiBjb3Vyc2VfaWQgKyBmb3J1bV9pZCwNCiAgICAgICAgIEs9MjAsDQogICAgICAgICBtYXguZW0uaXRzPTI1LA0KICAgICAgICAgdmVyYm9zZSA9IEZBTFNFKQ0KDQpmb3J1bXNfc3RtDQpgYGANCg0KQXMgbm90ZWQgZWFybGllciwgdGhlIGBzdG1gIHBhY2thZ2UgaGFzIGEgbnVtYmVyIG9mIGhhbmR5IGZlYXR1cmVzLiBPbmUNCm9mIHRoZXNlIGlzIHRoZSBgcGxvdC5TVE0oKWAgZnVuY3Rpb24gZm9yIHZpZXdpbmcgdGhlIG1vc3QgcHJvYmFibGUNCndvcmRzIGFzc2lnbmVkIHRvIGVhY2ggdG9waWMuDQoNCkJ5IGRlZmF1bHQsIGl0IG9ubHkgc2hvd3MgdGhlIGZpcnN0IDMgdGVybXMgc28gbGV0J3MgY2hhbmdlIHRoYXQgdG8gNSB0bw0KaGVscCB3aXRoIGludGVycHJldGF0aW9uOg0KDQpgYGB7ciBwbG90LXN0bX0NCnBsb3QuU1RNKGZvcnVtc19zdG0sIG4gPSA1KQ0KYGBgDQoNCk5vdGUgdGhhdCB5b3UgY2FuIGFsc28ganVzdCB1c2UgYHBsb3QoKWAgYXMgd2VsbDoNCg0KYGBge3IgcGxvdH0NCnBsb3QoZm9ydW1zX3N0bSwgbiA9IDUpDQpgYGANCg0KIyMjIyMg4pyFIENvbXByZWhlbnNpb24gQ2hlY2sNCg0KRml0IGEgbW9kZWwgZm9yIGJvdGggTERBIGFuZCBTVE0gdXNpbmcgZGlmZmVyZW50IHZhbHVlcyBmb3IgSyBhbmQgYW5zd2VyDQp0aGUgZm9sbG93aW5nIHF1ZXN0aW9uczoNCg0KMS4gIFdoYXQgdG9waWNzIGFwcGVhciB0byBiZSBzaW1pbGFyIHRvIHRob3NlIHVzaW5nIDIwIHRvcGljcyBmb3IgSz8NCmBgYHtyfQ0KZm9ydW1zX3N0bV9mb3VydGVlbiA8LSBzdG0oZG9jdW1lbnRzPWRvY3MsIA0KICAgICAgICAgICAgICAgICAgZGF0YT1tZXRhLA0KICAgICAgICAgICAgICAgICAgdm9jYWI9dm9jYWIsIA0KICAgICAgICAgICAgICAgICAgcHJldmFsZW5jZSA9fiBjb3Vyc2VfaWQgKyBmb3J1bV9pZCwNCiAgICAgICAgICAgICAgICAgIEs9MTQsDQogICAgICAgICAgICAgICAgICBtYXguZW0uaXRzPTI1LA0KICAgICAgICAgICAgICAgICAgdmVyYm9zZSA9IEZBTFNFKQ0KDQpmb3J1bXNfc3RtX2ZvdXJ0ZWVuDQpwbG90KGZvcnVtc19zdG1fZm91cnRlZW4sIG49NSkNCg0KIyBJbnRlcmVzdGluZ2x5LCB0aGVzZSB0b3BpY3Mgc29ydCBvdXQgZGlmZmVyZW50bHkuIFRoZXJlIGFyZSBzdGlsbCByZWZlcmVuY2VzDQojIHRvIHN0YXRpc3RpY3MsIGxlYXJuaW5nIGFuZCB0ZWNobm9sb2d5IHVzZSwgcXVlc3Rpb25zLCBhbmQgcmVzb3VyY2VzLiBIb3dldmVyLA0KIyB0aGVyZSBzZWVtIHRvIGJlIG11bHRpcGxlIHNlcGFyYXRlIHRvcGljcyAoMywgMTMsIDExKSB3aGljaCBhbGwgY2VudGVyIGFyb3VuZA0KIyBzdGF0aXN0aWNzLiBJdCBtaWdodCBiZSBpbnRlcmVzdGluZyB0byByZWR1Y2UgdGhlIHRvcGljcyB0byAxMi4NCg0KZm9ydW1zX3N0bV90d2VsdmUgPC0gc3RtKGRvY3VtZW50cz1kb2NzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE9bWV0YSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHZvY2FiPXZvY2FiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHByZXZhbGVuY2UgPX4gY291cnNlX2lkICsgZm9ydW1faWQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBLPTEyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4LmVtLml0cz0yNSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlcmJvc2UgPSBGQUxTRSkNCg0KZm9ydW1zX3N0bV90d2VsdmUNCnBsb3QoZm9ydW1zX3N0bV90d2VsdmUsIG49NSkNCg0KIyBTdGlsbCBtdWx0aXBsZSB0b3BpY3MgdGhhdCBpbmNsdWRlIHRlcm1zIHJlbGF0ZWQgdG8gc3RhdGlzdGljcy4gSSBndWVzcyB0aGlzDQojIGlzIGFuIGltcG9ydGFudCB0aGVtZSBpbiB0aGUgcmVzcG9uc2VzLg0KYGBgDQoNCg0KMi4gIEtub3dpbmcgdGhhdCB5b3UgZG9uJ3QgaGF2ZSBhcyBtdWNoIGNvbnRleHQgYXMgdGhlIHJlc2VhcmNoZXJzIG9mIHRoaXMgc3R1ZHkgZG8sIGhvdyBtaWdodCB5b3UgaW50ZXJwcmV0IG9uZSBvZiB0aGVzZSBsYXRlbnQgdG9waWNzIG9yIHRoZW1lcyB1c2luZyB0aGUga2V5IHRlcm1zDQogICAgYXNzaWduZWQ/DQogICAgLSBUb3BpYyAxMCBzZWVtcyB0byBiZSBhYm91dCBleHBlcmllbnRpYWwgbGVhcm5pbmcgdmlhIGEgcHJvamVjdCB0aGF0DQogcmVxdWlyZWQgdXNpbmcgdGVjaG5vbG9neQ0KICAgIA0KMy4gIFdoYXQgdG9waWMgZW1lcmdlZCB0aGF0IHNlZW0gZHJhbWF0aWNhbGx5IGRpZmZlcmVudCBhbmQgaG93IG1pZ2h0DQogICAgeW91IGludGVycHJldCB0aGlzIHRvcGljPw0KICAgIC0gVG9waWMgNiBzZWVtcyB0byBiZSBhYm91dCB0aGUgc3BlZWQgb2YgYSByb2xsZXIgY29hc3RlciAobWF5YmUgYSB3b29kZW4NCnZlcnN1cyBhIG1ldGFsIHRyYWNrPykuIE5vdCBrbm93aW5nIG1vcmUsIEkgdGhpbmsgdGhpcyBtYXkgcmVmZXIgdG8gYSBzcGVjaWZpYw0KcHJvamVjdA0KDQojIyMgM2MuIEZpbmRpbmcgKksqDQoNCkFzIGFsbHVkZWQgdG8gZWFybGllciwgc2VsZWN0aW5nIHRoZSBudW1iZXIgb2YgdG9waWNzIGZvciB5b3VyIG1vZGVsIGlzDQphIG5vbi10cml2aWFsIGRlY2lzaW9uIGFuZCBjYW4gZHJhbWF0aWNhbGx5IGltcGFjdCB5b3VyIHJlc3VsdHMuIEJhaWwNCigyMDE4KSBub3RlcyB0aGF0DQoNCj4gKlRoZSByZXN1bHRzIG9mIHRvcGljIG1vZGVscyBzaG91bGQgbm90IGJlIG92ZXItaW50ZXJwcmV0ZWQgdW5sZXNzIHRoZQ0KPiByZXNlYXJjaGVyIGhhcyBzdHJvbmcgdGhlb3JldGljYWwgYXByaW9yaSBhYm91dCB0aGUgbnVtYmVyIG9mIHRvcGljcw0KPiBpbiBhIGdpdmVuIGNvcnB1cywgb3IgaWYgdGhlIHJlc2VhcmNoZXIgaGFzIGNhcmVmdWxseSB2YWxpZGF0ZWQgdGhlDQo+IHJlc3VsdHMgb2YgYSB0b3BpYyBtb2RlbCB1c2luZyBib3RoIHRoZSBxdWFudGl0YXRpdmUgYW5kIHF1YWxpdGF0aXZlDQo+IHRlY2huaXF1ZXMgZGVzY3JpYmVkIGFib3ZlLioNCg0KVGhlcmUgYXJlIHNldmVyYWwgYXBwcm9hY2hlcyB0byBlc3RpbWF0aW5nIGEgdmFsdWUgZm9yIEsgYW5kIHdlJ2xsIHRha2UNCmEgcXVpY2sgbG9vayBhdCBvbmUgZnJvbSB0aGUgYGxkYXR1bmluZ2AgcGFja2FnZSBhbmQgb25lIGZyb20gb3VyIGBzdG1gDQpwYWNrYWdlLg0KDQojIyMjIFRoZSBGaW5kVG9waWNzTnVtYmVyIEZ1bmN0aW9uDQoNClRoZSBgbGRhdHVuaW5nYCBwYWNrYWdlIGhhcyBmdW5jdGlvbnMgZm9yIGJvdGggY2FsY3VsYXRpbmcgYW5kIHBsb3R0aW5nDQpkaWZmZXJlbnQgbWV0cmljcyB0aGF0IGNhbiBiZSB1c2VkIHRvIGVzdGltYXRlIHRoZSBtb3N0IHByZWZlcmFibGUNCm51bWJlciBvZiB0b3BpY3MgZm9yIExEQSBtb2RlbC4gSXQgYWxzbyBjb252ZW5pZW50bHkgdGFrZXMgdGhlIHN0YW5kYXJkDQpkb2N1bWVudCB0ZXJtIG1hdHJpeCBvYmplY3QgdGhhdCB3ZSBjcmVhdGVkIGZyb20gb3V0IHRpZHkgdGV4dCBhbmQgaGFzDQp0aGUgYWRkZWQgYmVuZWZpdCBvZiBydW5uaW5nIGZhaXJseSBxdWlja2x5LCBlc3BlY2lhbGx5IGNvbXBhcmVkIHRvIHRoZQ0KZnVuY3Rpb24gZm9yIGZpbmRpbmcgSyBmcm9tIHRoZSBgc3RtYCBwYWNrYWdlLg0KDQpMZXQncyB1c2UgdGhlIGRlZmF1bHRzIHNwZWNpZmllZCBpbiB0aGUgYD9GaW5kVG9waWNOdW1iZXJgIGRvY3VtZW50YXRpb24NCmFuZCBtb2RpZnkgc2xpZ2h0bHkgZ2V0IG1ldHJpY3MgZm9yIGEgc2VxdWVuY2Ugb2YgdG9waWNzIGZyb20gMTAtNzUNCmNvdW50aW5nIGJ5IDUgYW5kIHBsb3QgdGhlIG91dHB1dCB3ZSBzYXZlZCB1c2luZyB0aGUNCmBGaW5kVG9waWNzTnVtYmVyX3Bsb3QoKWAgZnVuY3Rpb246DQoNCmBgYHtyIGZpbmQtdG9waWMsIGV2YWw9RkFMU0V9DQojIFRISVMgSVMgTk9UIFdPUktJTkcgRk9SIE1FIFNPIEknTSBHT0lORyBUTyBDT01NRU5UIElUIE9VVA0KI2tfbWV0cmljcyA8LSBGaW5kVG9waWNzTnVtYmVyKA0KIyAgZm9ydW1zX2R0bSwNCiMgIHRvcGljcyA9IHNlcSgxMCwgNzUsIGJ5ID0gNSksDQojICBtZXRyaWNzID0gIkdyaWZmaXRoczIwMDQiLA0KIyAgbWV0aG9kID0gIkdpYmJzIiwNCiMgIGNvbnRyb2wgPSBsaXN0KCksDQojICBtYy5jb3JlcyA9IE5BLA0KIyAgcmV0dXJuX21vZGVscyA9IEZBTFNFLA0KIyAgdmVyYm9zZSA9IEZBTFNFLA0KIyAgbGlicGF0aCA9IE5VTEwNCiMpDQoNCiNGaW5kVG9waWNzTnVtYmVyX3Bsb3Qoa19tZXRyaWNzKQ0KYGBgDQoNCg0KDQojIyMjIFRoZSBmaW5kaW5nSygpIEZ1bmN0aW9uDQoNCkZpbmFsbHksIEJhaWwgKDIwMTgpIG5vdGVzIHRoYXQgdGhlYHN0bWAgcGFja2FnZSBoYXMgYSB1c2VmdWwgZnVuY3Rpb24NCmNhbGxlZCBgc2VhcmNoS2Agd2hpY2ggYWxsb3dzIHVzIHRvIHNwZWNpZnkgYSByYW5nZSBvZiB2YWx1ZXMgZm9yIGBrYA0KYW5kIG91dHB1dHMgbXVsdGlwbGUgZ29vZG5lc3Mtb2YtZml0IG1lYXN1cmVzIHRoYXQgYXJlICJ2ZXJ5IHVzZWZ1bCBpbg0KaWRlbnRpZnlpbmcgYSByYW5nZSBvZiB2YWx1ZXMgZm9yIGBrYCB0aGF0IHByb3ZpZGUgdGhlIGJlc3QgZml0IGZvciB0aGUNCmRhdGEuIg0KDQpUaGUgc3ludGF4IG9mIHRoaXMgZnVuY3Rpb24gaXMgdmVyeSBzaW1pbGFyIHRvIHRoZSBgc3RtKClgIGZ1bmN0aW9uIHdlDQp1c2VkIGFib3ZlLCBleGNlcHQgdGhhdCB3ZSBzcGVjaWZ5IGEgcmFuZ2UgZm9yIGBrYCBhcyBvbmUgb2YgdGhlDQphcmd1bWVudHMuIEluIHRoZSBjb2RlIGJlbG93LCB3ZSBzZWFyY2ggYWxsIHZhbHVlcyBvZsKgYGtgwqBiZXR3ZWVuIDEwIGFuZA0KMzAuDQoNCmBgYHtyIHNlYXJjay1rLCBldmFsPUZBTFNFfQ0KI0kgYW0gbm90IGV4cGVjdGluZyB5b3UgcnVuIHRoaXMgY29kZSBhcyBpdCB3aWxsIHRha2UgdG9vIGxvbmcNCiNmaW5kaW5nayA8LSBzZWFyY2hLKGRvY3MsIA0KICAgICAgICAgICAgICAgICAgICAjdm9jYWIsIA0KICAgICAgICAgICAgICAgICAgICAjSyA9IGMoNToxNSksDQogICAgICAgICAgICAgICAgICAgICNkYXRhID0gbWV0YSwgDQogICAgICAgICAgICAgICAgICAgICN2ZXJib3NlPUZBTFNFKQ0KDQojcGxvdChmaW5kaW5naykNCmBgYA0KDQpOb3RlIHRoYXQgUnVubmluZyBgc2VhcmNoSygpYCBmdW5jdGlvbiBvbiB0aGlzIGNvcnB1cyB0b29rIGFsbCBuaWdodCBvbg0KYSBwcmV0dHkgcG93ZXJmdWwgTWFjQm9vayBQcm8gYW5kIGNyYXNoZWQgb25jZSBhcyB3ZWxsLCBzbyBJIGRvIG5vdA0KZXhwZWN0IHlvdSB0byBydW4gdGhpcyBmb3IgdGhlIHdhbGt0aHJvdWdoLiBJIHJhbiBhIGNvdXBsZSBpdGVyYXRpb25zDQphbmQgbGFuZGVkIG9uIGJldHdlZW4gNSBhbmQgMTUgd2l0aCBhbiBvcHRpbWFsIG51bWJlciBvZiB0b3BpY3MNCnNvbWV3aGVyZSBhcm91bmQgMTQ6DQoNCkdpdmVuIHRoZSBzb21ld2hhdCBjb25mbGljdGluZyByZXN1bHRzLCBhbHNvIHNvbWV3aGF0IHNlbGZpc2hseSBhbmQgZm9yDQp0aGUgc2FtZSBvZiBzaW1wbGljaXR5IGZvciB0aGlzIHdhbGt0aHJvdWdoLCBJJ20ganVzdCBnb2luZyB0byBzdGljaw0Kd2l0aCB0aGUgcmF0aGVyIGFyYml0cmFyeSBzZWxlY3Rpb24gb2YgMjAgdG9waWNzIGZvciB0aGUgcmVtYWluZGVyIG9mDQp0aGlzIFVuaXQuDQoNCiMjIyMgVGhlIExEQXZpcyBFeHBsb3Jlcg0KDQpPbmUgZmluYWwgdG9vbCB0aGF0IEkgd2FudCB0byBpbnRyb2R1Y2UgZnJvbSB0aGUgYHN0bWAgcGFja2FnZSBpcyB0aGUNCmB0b0xEQXZpcygpYCBmdW5jdGlvbiB3aGljaCBwcm92aWRlcyBhIGdyZWF0IHZpc3VhbGl6YXRpb25zIGZvcg0KZXhwbG9yaW5nIHRvcGljIGFuZCB3b3JkIGRpc3RyaWJ1dGlvbnMgdXNpbmcgYExEQXZpc2AgdG9waWMgYnJvd3NlcjoNCg0KYGBge3IgTERBdmlzfQ0KdG9MREF2aXMobW9kID0gZm9ydW1zX3N0bSwgZG9jcyA9IGRvY3MpDQpgYGANCg0KT3VyIGN1cnJlbnQgc3RtIG1vZGVsIG9mIDIwIHRvcGljcyBpcyByZXN1bHRpbmcgaW4gYSBsb3Qgb2Ygb3ZlcmxhcCBhbW9uZyB0b3BpY3MgYW5kIHN1Z2dlc3RzIHRoYXQgMjAgbWF5IG5vdCBiZSBhbiBvcHRpbWFsIG51bWJlciBvZiB0b3BpY3MsIGFzIG90aGVyIGFwcHJvYWNoZXMgZm9yDQpmaW5kaW5nIGsgYWxzbyBzdWdnZXN0czoNCg0KIyMgNC4gRVhQTE9SRQ0KDQpTaWxnZSBhbmQgUm9iaW5zb24gKDIwMTgpIG5vdGUgdGhhdCBmaXR0aW5nIGF0IHRvcGljIG1vZGVsIGlzIHRoZSAiZWFzeQ0KcGFydC4iIFRoZSBoYXJkIHBhcnQgaXMgbWFraW5nIHNlbnNlIG9mIHRoZSBtb2RlbCByZXN1bHRzIGFuZCB0aGF0IHRoZQ0KcmVzdCBvZiB0aGUgYW5hbHlzaXMgaW52b2x2ZXMgZXhwbG9yaW5nIGFuZCBpbnRlcnByZXRpbmcgdGhlIG1vZGVsIHVzaW5nDQphIHZhcmlldHkgb2YgYXBwcm9hY2hlcyB3aGljaCB3ZSdsbCB3YWxrdGhyb3VnaCBpbiBpbiB0aGlzIHNlY3Rpb24uDQoNCkJhaWwgKDIwMTgpIGNhdXRpb25zLCBob3dldmVyLCB0aGF0Og0KDQo+ICouLi5wb3N0LWhvYyBpbnRlcnByZXRhdGlvbiBvZiB0b3BpYyBtb2RlbHMgaXMgcmF0aGVyIGRhbmdlcm91cy4uLiBhbmQNCj4gY2FuIHF1aWNrbHkgY29tZSB0byByZXNlbWJsZSB0aGUgcHJvY2VzcyBvZiAicmVhZGluZyB0ZWEgbGVhdmVzLCIgb3INCj4gZmluZGluZyBtZWFuaW5nIGluIHBhdHRlcm5zIHRoYXQgYXJlIGluIGZhY3QgcXVpdGUgYXJiaXRyYXJ5IG9yIGV2ZW4NCj4gcmFuZG9tLioNCg0KIyMjIDRhLiBFeHBsb3JpbmcgQmV0YSBWYWx1ZXMNCg0KSGlkZGVuIHdpdGhpbiB0aGlzIGBmb3J1bXNfbGRhYCB0b3BpYyBtb2RlbCBvYmplY3Qgd2UgY3JlYXRlZCBhcmUNCnBlci10b3BpYy1wZXItd29yZCBwcm9iYWJpbGl0aWVzLCBjYWxsZWQgzrIgKCJiZXRhIikuIEl0IGlzIHRoZQ0KcHJvYmFiaWxpdHkgb2YgYSB0ZXJtICh3b3JkKSBiZWxvbmdpbmcgdG8gYSB0b3BpYy7CoA0KDQpMZXQncyB0YWtlIGEgbG9vayBhdCB0aGUgNSBtb3N0IGxpa2VseSB0ZXJtcyBhc3NpZ25lZCB0byBlYWNoIHRvcGljLA0KaS5lLiB0aG9zZSB3aXRoIHRoZSBsYXJnZXN0IM6yIHZhbHVlcyB1c2luZyB0aGUgYHRlcm1zKClgIGZ1bmN0aW9uIGZyb20NCnRoZSBgdG9waWNtb2RlbHNgIHBhY2thZ2U6DQoNCmBgYHtyIHRlcm1zfQ0KdGVybXMoZm9ydW1zX2xkYSwgNSkNCmBgYA0KDQpFdmVuIHRob3VnaCB3ZSd2ZSBzb21ld2hhdCBhcmJpdHJhcmlseSBzZWxlY3RlZCB0aGUgbnVtYmVyIG9mIHRvcGljcyBmb3INCm91ciBjb3JwdXMsIHNvbWUgdGhlc2UgdG9waWNzIG9yIHRoZW1lcyBhcmUgZmFpcmx5IGludHVpdGl2ZSB0bw0KaW50ZXJwcmV0LiBGb3IgZXhhbXBsZToNCg0KLSAgIFRvcGljIDExICh0ZWNobm9sb2d5LCBzdHVkZW50cywgc29mdHdhcmUsIHByb2dyYW0sIGV4Y2VsKSBzZWVtcyB0bw0KICAgIGJlIGFib3V0IHN0dWRlbnRzIHVzZSBvZiB0ZWNobm9sb2d5IGluY2x1ZGluZyBzb2Z0d2FyZSBwcm9ncmFtcyBsaWtlDQogICAgZXhjZWw7DQoNCi0gICBUb3BpYyA5IChxdWVzdGlvbnMsIGtpZHMsIGxvdmUsIGdhcG1pbmRlciwgc2hhcmluZykgc2VlbXMgdG8gYmUNCiAgICBhYm91dCB0aGUgZ2FwbWluZGVyIGFjdGl2aXR5IGZyb20gdGhlIE1PT0MtRWQgYW5kIGtpZHMgZW5qb3ltZW50IG9mDQogICAgaXQ7IGFuZA0KDQotICAgVG9waWMgMTggKGRhdGEsIHN0dWRlbnRzLCBjb2xsZWN0LCByZWFsLCBzZXRzKSBzZWVtcyB0byBiZSBhYm91dA0KICAgIHN0dWRlbnQgY29sbGVjdGlvbiBhbmQgdXNlIG9mIHJlYWwgd29ybGQgZGF0YSBzZXRzLg0KDQpOb3Qgc3VycHJpc2luZ2x5LCB0aGUgYHRpZHl0ZXh0YCBwYWNrYWdlIGhhcyBhIGhhbmR5IGZ1bmN0aW9uDQpjb252ZW5pZW50bHkgbmFtZSBgdGlkeSgpYCB0byBjb252ZXJ0IG91ciBsZGEgbW9kZWwgdG8gYSB0aWR5IGRhdGEgZnJhbWUNCmNvbnRhaW5pbmcgdGhlc2UgYmV0YSB2YWx1ZXMgZm9yIGVhY2ggdGVybToNCg0KYGBge3IgdGlkeV9sZGF9DQoNCnRpZHlfbGRhIDwtIHRpZHkoZm9ydW1zX2xkYSkNCg0KdGlkeV9sZGENCmBgYA0KDQpPYnZpb3VzbHksIGl0J3Mgbm90IHZlcnkgZWFzeSB0byBpbnRlcnByZXQgd2hhdCB0aGUgdG9waWNzIGFyZSBhYm91dA0KZnJvbSBhIGRhdGEgZnJhbWUgbGlrZSB0aGlzIHNvIGxldCdzIGJvcnJvdyBjb2RlIGFnYWluIGZyb20gW0NoYXB0ZXINCjguNC4zIEludGVycHJldGluZyB0aGUgdG9waWMNCm1vZGVsXShodHRwczovL3d3dy50aWR5dGV4dG1pbmluZy5jb20vbmFzYS5odG1sP3E9YmV0YSNpbnRlcnByZXRpbmctdGhlLXRvcGljLW1vZGVsKQ0KaW4gVGV4dCBNaW5pbmcgd2l0aCBSIHRvIGV4YW1pbmUgdGhlIHRvcCA1IHRlcm1zIGZvciBlYWNoIHRvcGljIGFuZCB0aGVuDQpsb29rIGF0IHRoaXMgaW5mb3JtYXRpb24gdmlzdWFsbHk6DQoNCmBgYHtyIHRvcF90ZXJtc30NCg0KdG9wX3Rlcm1zIDwtIHRpZHlfbGRhICU+JQ0KICBncm91cF9ieSh0b3BpYykgJT4lDQogIHNsaWNlX21heChiZXRhLCBuID0gNSwgd2l0aF90aWVzID0gRkFMU0UpICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogIGFycmFuZ2UodG9waWMsIC1iZXRhKQ0KDQp0b3BfdGVybXMgJT4lDQogIG11dGF0ZSh0ZXJtID0gcmVvcmRlcl93aXRoaW4odGVybSwgYmV0YSwgdG9waWMpKSAlPiUNCiAgZ3JvdXBfYnkodG9waWMsIHRlcm0pICU+JSAgICANCiAgYXJyYW5nZShkZXNjKGJldGEpKSAlPiUgIA0KICB1bmdyb3VwKCkgJT4lDQogIGdncGxvdChhZXMoYmV0YSwgdGVybSwgZmlsbCA9IGFzLmZhY3Rvcih0b3BpYykpKSArDQogIGdlb21fY29sKHNob3cubGVnZW5kID0gRkFMU0UpICsNCiAgc2NhbGVfeV9yZW9yZGVyZWQoKSArDQogIGxhYnModGl0bGUgPSAiVG9wIDUgdGVybXMgaW4gZWFjaCBMREEgdG9waWMiLA0KICAgICAgIHggPSBleHByZXNzaW9uKGJldGEpLCB5ID0gTlVMTCkgKw0KICBmYWNldF93cmFwKH4gdG9waWMsIG5jb2wgPSA0LCBzY2FsZXMgPSAiZnJlZSIpDQpgYGANCg0KIyMjIDRiLiBFeHBsb3JpbmcgR2FtbWEgVmFsdWVzDQoNCk5vdyB0aGF0IHdlIGhhdmUgYSBzZW5zZSBvZiB0aGUgbW9zdCBjb21tb24gd29yZHMgYXNzb2NpYXRlZCB3aXRoIGVhY2gNCnRvcGljLCBsZXQncyB0YWtlIGEgbG9vayBhdCB0aGUgdG9waWMgcHJldmFsZW5jZSBpbiBvdXIgTU9PQy1FZA0KZGlzY3Vzc2lvbiBmb3J1bSBjb3JwdXMsIGluY2x1ZGluZyB0aGUgd29yZHMgdGhhdCBjb250cmlidXRlIHRvIGVhY2gNCnRvcGljIHdlIGV4YW1pbmVkIGFib3ZlLg0KDQpBbHNvLCBoaWRkZW4gd2l0aGluIG91ciBgZm9ydW1zX2xkYWAgdG9waWMgbW9kZWwgb2JqZWN0IHdlIGNyZWF0ZWQgYXJlDQpwZXItZG9jdW1lbnQtcGVyLXRvcGljIHByb2JhYmlsaXRpZXMsIGNhbGxlZCDOsyAoImdhbW1hIikuIFRoaXMgcHJvdmlkZXMNCnRoZSBwcm9iYWJpbGl0aWVzIHRoYXQgZWFjaCBkb2N1bWVudCBpcyBnZW5lcmF0ZWQgZnJvbSBlYWNoIHRvcGljLCB0aGF0DQpnYW1tYSBtYXRyaXguIFdlIGNhbiBjb21iaW5lIG91ciBiZXRhIGFuZCBnYW1tYSB2YWx1ZXMgdG8gdW5kZXJzdGFuZCB0aGUNCnRvcGljIHByZXZhbGVuY2UgaW4gb3VyIGNvcnB1cywgYW5kIHdoaWNoIHdvcmRzIGNvbnRyaWJ1dGUgdG8gZWFjaA0KdG9waWMuDQoNClRvIGRvIHRoaXMsIHdlJ3JlIGdvaW5nIHRvIGJvcnJvdyBzb21lIGNvZGUgZnJvbSB0aGUgU2lsZ2UgKDIwMTgpIHBvc3QsDQpbVHJhaW5pbmcsIGV2YWx1YXRpbmcsIGFuZCBpbnRlcnByZXRpbmcgdG9waWMNCm1vZGVsc10oaHR0cHM6Ly9qdWxpYXNpbGdlLmNvbS9ibG9nL2V2YWx1YXRpbmctc3RtLykuDQoNCkZpcnN0LCBsZXQncyBjcmVhdGUgdHdvIHRpZHkgZGF0YSBmcmFtZXMgZm9yIG91ciBiZXRhIGFuZCBnYW1tYSB2YWx1ZXMNCg0KYGBge3IgYmV0YV9nYW1tYX0NCnRkX2JldGEgPC0gdGlkeShmb3J1bXNfbGRhKQ0KDQp0ZF9nYW1tYSA8LSB0aWR5KGZvcnVtc19sZGEsIG1hdHJpeCA9ICJnYW1tYSIpDQoNCnRkX2JldGENCnRkX2dhbW1hDQoNCmBgYA0KDQpOZXh0LCB3ZSdsbCBhZG9wdCBKdWxpYSdzIGNvZGUgd2hvbGVzYWxlIHRvIGNyZWF0ZSBhIGZpbHRlcmVkIGRhdGEgZnJhbWUNCm9mIG91ciBgdG9wX3Rlcm1zYCwgam9pbiB0aGlzIHRvIGEgbmV3IGRhdGEgZnJhbWUgZm9yIGBnYW1tYS10ZXJtc2AgYW5kDQpjcmVhdGUgYSBuaWNlIGNsZWFuIHRhYmxlIHVzaW5nIHRoZSBga2FiZWwoKWAgZnVuY3Rpb24gYGtuaXRyYCBwYWNrYWdlOg0KDQpgYGB7ciBwcmV2YWxlbmNlX3RhYmxlfQ0KdG9wX3Rlcm1zIDwtIHRkX2JldGEgJT4lDQogIGFycmFuZ2UoYmV0YSkgJT4lDQogIGdyb3VwX2J5KHRvcGljKSAlPiUNCiAgdG9wX24oNywgYmV0YSkgJT4lDQogIGFycmFuZ2UoLWJldGEpICU+JQ0KICBzZWxlY3QodG9waWMsIHRlcm0pICU+JQ0KICBzdW1tYXJpc2UodGVybXMgPSBsaXN0KHRlcm0pKSAlPiUNCiAgbXV0YXRlKHRlcm1zID0gbWFwKHRlcm1zLCBwYXN0ZSwgY29sbGFwc2UgPSAiLCAiKSkgJT4lIA0KICB1bm5lc3QoKQ0KDQpnYW1tYV90ZXJtcyA8LSB0ZF9nYW1tYSAlPiUNCiAgZ3JvdXBfYnkodG9waWMpICU+JQ0KICBzdW1tYXJpc2UoZ2FtbWEgPSBtZWFuKGdhbW1hKSkgJT4lDQogIGFycmFuZ2UoZGVzYyhnYW1tYSkpICU+JQ0KICBsZWZ0X2pvaW4odG9wX3Rlcm1zLCBieSA9ICJ0b3BpYyIpICU+JQ0KICBtdXRhdGUodG9waWMgPSBwYXN0ZTAoIlRvcGljICIsIHRvcGljKSwNCiAgICAgICAgIHRvcGljID0gcmVvcmRlcih0b3BpYywgZ2FtbWEpKQ0KDQpnYW1tYV90ZXJtcyAlPiUNCiAgc2VsZWN0KHRvcGljLCBnYW1tYSwgdGVybXMpICU+JQ0KICBrYWJsZShkaWdpdHMgPSAzLCANCiAgICAgICAgY29sLm5hbWVzID0gYygiVG9waWMiLCAiRXhwZWN0ZWQgdG9waWMgcHJvcG9ydGlvbiIsICJUb3AgNyB0ZXJtcyIpKQ0KYGBgDQoNCkFuZCBsZXQncyBhbHNvIGNvbXBhcmUgdGhpcyB0byB0aGUgbW9zdCBwcmV2YWxlbnQgdG9waWNzIGFuZCB0ZXJtcyBmcm9tDQpvdXIgYGZvcnVtc19zdG1gIG1vZGVsIHRoYXQgd2UgY3JlYXRlZCB1c2luZyB0aGUgYHBsb3QoKWAgZnVuY3Rpb246DQoNCmBgYHtyIHBsb3Rfc3RtfQ0KcGxvdChmb3J1bXNfc3RtLCBuID0gNykNCmBgYA0KDQojIyMgNGMuIFJlYWRpbmcgdGhlIFRlYSBMZWF2ZXMNCg0KUmVjb2duaXppbmcgdGhhdCB0b3BpYyBtb2RlbGluZyBpcyBiZXN0IHVzZWQgYXMgYSAidG9vbCBmb3IgcmVhZGluZyIgYW5kDQpwcm92aWRlcyBvbmx5IGFuIGluY29tcGxldGUgYW5zd2VyIHRvIG91ciBvdmVyYXJjaGluZywgKioiSG93IGRvIHdlDQpxdWFudGlmeSB3aGF0IGEgY29ycHVzIGlzIGFib3V0PyIqKiwgdGhlIHJlc3VsdHMgZG8gc3VnZ2VzdCBzb21lDQpwb3RlbnRpYWwgdG9waWNzIHRoYXQgaGF2ZSBlbWVyZ2VzIGFzIHdlbGwgYXMgc29tZSBhcmVhcyB3b3J0aCBmb2xsb3dpbmcNCnVwIG9uLg0KDQpTcGVjaWZpY2FsbHksIGxvb2tpbmcgYXQgc29tZSBvZiB0aGUgY29tbW9uIGNsdXN0ZXJzIG9mIHdvcmRzIGZvciB0aGUNCm1vcmUgcHJldmFsZW50IHRvcGljcyBzdWdnZXN0IHRoYXQgc29tZSBrZXkgdG9waWNzIG9yICJsYXRlbnQgdGhlbWVzIg0KKHJlbmFtZWQgaW4gYm9sZCkgbWlnaHQgaW5jbHVkZToNCg0KLSAgICoqVGVhY2hpbmcgU3RhdGlzdGljczoqKiBVbnN1cnByaXNpbmcsIGdpdmVuIHRoZSBjb3Vyc2UgdGl0bGUsIHRoZQ0KICAgIHRvcGljcyBtb3N0IHByZXZhbGVudCBpbiBib3RoIHRoZSBgZm9ydW1zX3N0bWAgYW5kIGBmb3J1bXNfbGRhYA0KICAgIG1vZGVscyBjb250YWlucyB0aGUgdGVybXMgInRlYWNoIiwgInN0dWRlbnRzIiwgInN0YXRpc3RpY3MiLiBUaGlzDQogICAgY291bGQgYmUgYW4gIm92ZXJhcmNoaW5nIHRoZW1lIiBidXQgbW9yZSBsaWtlbHkgbWF5IHNpbXBseSBiZSBqdXN0DQogICAgdGhlIHJlc2lkdWUgb2YgdGhlIGNvdXJzZSB0aXRsZSB0aG91Z2ggYmVpbmcgc3ByaW5rbGVkIHRocm91Z2hvdXQNCiAgICB0aGUgZm9ydW1zIGFuZCBkZXNlcnZlcyBzb21lIGZvbGxvdyB1cC4gVG9waWNzIDggZnJvbSB0aGUgTERBIG1vZGVsDQogICAgbWF5IG92ZXJsYXAgd2l0aCB0aGlzIHRvcGljIGFzIHdlbGwuDQotICAgKipDb3Vyc2UgVXRpbGl0eToqKiBUaGUgc2Vjb25kIG1vc3QgcHJldmFsZW50IFRvcGljcyAoMTMgYW5kIDIpIGluDQogICAgdGhlIGBsZGFgIGFuZCBgc3RtYCBtb2RlbHMgcmVzcGVjdGl2ZWx5LCBzZWVtIHRvIHBvdGVudGlhbGx5IGJlDQogICAgYWJvdXQgdGhlIHVzZWZ1bG5lc3Mgb2YgY291cnNlICJyZXNvdXJjZXMiIGxpa2UgbGVzc29ucywgdG9vbHMsDQogICAgdmlkZW9zLCBhbmQgYWN0aXZpdGllcy4gSSdtIHdhZ2VyaW5nIHRoaXMgbWlnaHQgYmUgYSBmb3J1bSBkZWRpY2F0ZWQNCiAgICB0byBjb3Vyc2UgZmVlZGJhY2suIFRvcGljIDE1IGZyb20gdGhlIFNUTSBtb2RlbCBhbHNvIHN1Z2dlc3QgdGhpcw0KICAgIG1heSBiZSBhIGJyb2FkZXIgdGhlbWUuDQotICAgKipVc2luZyBSZWFsLVdvcmxkIERhdGE6KiogVG9waWNzIDE4ICYgMTIgZnJvbSB0aGUgTERBIG1vZGVsDQogICAgcGFydGljdWxhcmx5IGludHJpZ3VlIG1lIGFuZCBJJ20gd2FnZXJpbmcgdGhpcyBpcyBwcmV0dHkgcG9zaXRpdmUNCiAgICBzZW50aW1lbnQgYW1vbmcgcGFydGljaXBhbnRzIGFib3V0IHRoZSB2YWx1ZSBhbmQgYmVuZWZpdCBvZiBoYXZpbmcNCiAgICBzdHVkZW50cyBjb2xsZWN0IGFuZCBhbmFseXplIHJlYWwgZGF0YSBzZXRzIChlLmcuIENlbnN1cyBkYXRhIGluDQogICAgVG9waWMgMSkgYW5kIHdvcmsgb24gcHJvamVjdHMgcmVsZXZhbnQgdG8gdGhlaXIgcmVhbCBsaWZlLiBXaWxsDQogICAgZGVmaW5pdGVseSBmb2xsb3cgdXAgb24gdGhpcyBvbmUuDQotICAgKipUZWNobm9sb2d5IFVzZToqKiBTZXZlcmFsIHRvcGljcyAoNiAmIDExIGZyb20gTERBIGFuZCA4ICYgMTkgZnJvbQ0KICAgIFNUTSkgYXBwZWFyIHRvIGJlIGFib3V0IHN0dWRlbnQgdXNlIG9mIHRlY2hub2xvZ3kgYW5kIHNvZnR3YXJlIGxpa2UNCiAgICBjYWxjdWxhdG9ycyBhbmQgRXhjZWwgZm9yIHRlYWNoaW5nIHN0YXRpc3RpY3MgYW5kIHVzaW5nIHNpbXVsYXRpb25zLg0KICAgIFRvcGljIDE2IGZyb20gTERBIGFsc28gc3VnZ2VzdCB0aGUgdXNlIG9mIHRoZSBDb21tb24gT25saW5lIERhdGENCiAgICBBbmFseXNpcyBQbGF0Zm9ybS4NCi0gICAqKlN0dWRlbnQgU3RydWdnbGUgJiBFbmdhZ2VtZW50OioqIFRvcGljIDE1IGZyb20gTERBIGFuZCBUb3BpYyAxNg0KICAgIGZyb20gU1RNIGFsc28gaW50cmlndWUgbWUgYW5kIGFwcGVhciB0byBiZSB0d28gb3Bwb3NpdGUgc2lkZXMgb2YNCiAgICBwZXJoYXBzIHRoZSBzYW1lIGNvaW4uIFRoZSBmb3JtZXIgaW5jbHVkZXMgInN0cnVnZ2xlIiBhbmQgInJlYWRpbmciDQogICAgd2hpY2ggc3VnZ2VzdHMgcGVyaGFwcyBhIGJhcnJpZXIgdG8gdGVhY2hpbmcgc3RhdGlzdGljcyB3aGlsZSBUb3BpYw0KICAgIDE2IGNvbnRhaW5zIHRvcCBzdGVtcyBsaWtlICJlbmdhZ2UiLCAiYWN0aXYiLCBhbmQgInRoaW5rIiBhbmQgbWF5DQogICAgc3VnZ2VzdCBwYXJ0aWNpcGFudHMgYW50aWNpcGF0ZSBhY3Rpdml0aWVzIG1heSBlbmdhZ2Ugc3R1ZGVudHMuDQoNClRvIHNlcnZlIGFzIGEgY2hlY2sgb24gbXkgdGVhIGxlYWYgcmVhZGluZywgSSdtIGdvaW5nIHRvIGZvbGxvdyBCYWlsJ3MNCnJlY29tbWVuZGF0aW9uIHRvIGV4YW1pbmUgc29tZSBvZiB0aGVzZSB0b3BpY3MgcXVhbGl0YXRpdmVseS4gVGhlIGBzdG1gDQpwYWNrYWdlIGhhcyBhbm90aGVyIHVzZWZ1bCBmdW5jdGlvbiB0aG91Z2ggZXhjZXB0aW9uYWxseSBmdXNzeSBmdW5jdGlvbg0KY2FsbGVkIGBmaW5kVGhvdWdodHNgIHdoaWNoIGV4dHJhY3RzIHBhc3NhZ2VzIGZyb20gZG9jdW1lbnRzIHdpdGhpbiB0aGUNCmNvcnB1cyBhc3NvY2lhdGUgd2l0aCB0b3BpY3MgdGhhdCB5b3Ugc3BlY2lmeS4NCg0KVGhlIGZpcnN0IGxpbmUgb2YgY29kZSBtYXkgbm90IGJlIG5lY2Vzc2FyeSBmb3IgeW91ciBpbmRlcGVuZGVudA0KYW5hbHlzaXMsIGJ1dCBiZWNhdXNlIHRoZSBgdGV4dFByb2Nlc3NvcigpYCBmdW5jdGlvbiByZW1vdmVkIHNldmVyYWwNCmRvY3VtZW50cyBkdXJpbmcgcHJvY2Vzc2luZywgdGhlIGBmaW5kdGhvdWdodHMoKWAgZnVuY3Rpb24gY2FuJ3QNCnByb3Blcmx5IGluZGV4IHRoZSBwcm9jZXNzZWQgZG9jcy4gVGhpcyBbbGluZSBvZiBjb2RlIGZvdW5kIG9uDQpzdGFja292ZXJmbG93XShodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy80MzQ5MjY2Ny9yLXN0bS1udW1iZXItb2YtcHJvdmlkZWQtdGV4dHMtYW5kLW51bWJlci1vZi1kb2N1bWVudHMtbW9kZWxlZC1kby1ub3QtbWF0Y2gpDQpyZW1vdmVzIGRvY3VtZW50cyBmcm9tIG9yaWdpbmFsIGB0c19mb3J1bV9kYXRhYCBzb3VyY2UgdGhhdCB3ZXJlIHJlbW92ZWQNCmR1cmluZyBwcm9jZXNzaW5nIHNvIHRoZXJlIGlzIGEgb25lLXRvLW9uZSBjb3JyZXNwb25kZW5jZSB3aXRoDQpgZm9ydW1zX3N0bWAgYW5kIHNvIHlvdSBjYW4gdXNlIHRoZSBmdW5jdGlvbiB0byBmaW5kIHBvc3RzIGFzc29jaWF0ZWQNCndpdGggYSBnaXZlbiB0b3BpYy4NCg0KTGV0J3Mgc2xpZ2h0bHkgcmVkdWNlIG91ciBvcmlnaW5hbCBkYXRhIHNldCB0byBtYXRjaCBvdXIgU1RNIG1vZGVsLCBwYXNzDQpib3RoIHRvIHRoZSBgZmluZFRob3VnaHRzKClgIGZ1bmN0aW9uLCBhbmQgc2V0IG91ciBhcmd1bWVudHMgdG8gcmV0dXJuDQpgbiA9MTBgIHBvc3RzIGZyb20gYHRvcGljcyA9IDJgIChpLmUuIFRvcGljIDIpIHRoYXQgaGF2ZSBhdCBsZWFzdCA1MCUgb3INCmB0aHJlc2ggPSAwLjVgIGFzIGEgbWluaW11bSB0aHJlc2hvbGQgZm9yIHRoZSBlc3RpbWF0ZWQgdG9waWMNCnByb3BvcnRpb24uDQoNCmBgYHtyIGZpbmRUaG91Z2h0c18yfQ0KDQp0c19mb3J1bV9kYXRhX3JlZHVjZWQgPC10c19mb3J1bV9kYXRhJHBvc3RfY29udGVudFstdGVtcCRkb2NzLnJlbW92ZWRdDQoNCmZpbmRUaG91Z2h0cyhmb3J1bXNfc3RtLA0KICAgICAgICAgICAgIHRleHRzID0gdHNfZm9ydW1fZGF0YV9yZWR1Y2VkLA0KICAgICAgICAgICAgIHRvcGljcyA9IDIsIA0KICAgICAgICAgICAgIG4gPSAxMCwNCiAgICAgICAgICAgICB0aHJlc2ggPSAwLjUpDQpgYGANCg0KRHVwbGljYXRlIHBvc3RzIGFzaWRlLCB0aGlzICoqQ291cnNlIFV0aWxpdHkqKiB0b3BpYyByZXR1cm5zIHBvc3RzIHRoZXJlDQp3ZXJlIGV4cGVjdGVkIGJhc2VkIG9uIG15IGludGVycHJldGF0aW9uIG9mIHRoZSBrZXkgdGVybXMgZm9yIFRvcGljIDIuDQpJdCBsb29rcyBsaWtlIEkgbWF5IGhhdmUgcmVhZCB0aG9zZSB0ZWEgbGVhdmVzIGNvcnJlY3RseS4NCg0KTm93IGxldCdzIHRha2UgYSBsb29rIGF0IFRvcGljIDE2IHRoYXQgd2UgdGhvdWdodCBtaWdodCBiZSByZWxhdGVkIHRvDQpzdHVkZW50IGVuZ2FnZW1lbnQ6DQoNCmBgYHtyIGZpbmRUaG91Z2h0c18xNn0NCg0KZmluZFRob3VnaHRzKGZvcnVtc19zdG0sDQogICAgICAgICAgICAgdGV4dHMgPSB0c19mb3J1bV9kYXRhX3JlZHVjZWQsDQogICAgICAgICAgICAgdG9waWNzID0gMTYsIA0KICAgICAgICAgICAgIG4gPSAxMCwNCiAgICAgICAgICAgICB0aHJlc2ggPSAwLjUpDQpgYGANCg0KSXQgbG9va3MgbGlrZSBteSB0ZWEgcmVhZGluZyB3YXMgYSBwYXJ0aWFsbHkgY29ycmVjdCBmb3IgVG9waWMgMTYsDQp0aG91Z2ggdGhlIHJlc3VsdHMgc2VlbSB0byBiZSBhYm91dCBhIHNwZWNpZmljICJQZXBzaSBjaGFsbGVuZ2UiDQphY3Rpdml0eSB0byBjb25kdWN0IHdpdGggc3R1ZGVudHMuDQoNCkZpbmFsbHksIGxldCdzIGxvb2sgYXQgcG9zdHMgZnJvbSBUb3BpYyAzIHdoaWNoIHdlIHRob3VnaCBtaWdodCBiZSBhbg0Kb3ZlcmFyY2hpbmcgdGhlbWUgYWJvdXQgdGVhY2hpbmcgc3RhdGlzdGljczoNCg0KYGBge3IgZmluZFRob3VnaHRzXzN9DQoNCnRzX2ZvcnVtX2RhdGFfcmVkdWNlZCA8LXRzX2ZvcnVtX2RhdGEkcG9zdF9jb250ZW50Wy10ZW1wJGRvY3MucmVtb3ZlZF0NCg0KZmluZFRob3VnaHRzKGZvcnVtc19zdG0sDQogICAgICAgICAgICAgdGV4dHMgPSB0c19mb3J1bV9kYXRhX3JlZHVjZWQsDQogICAgICAgICAgICAgdG9waWNzID0gMywgDQogICAgICAgICAgICAgbiA9IDEwLA0KICAgICAgICAgICAgIHRocmVzaCA9IDAuNSkNCmBgYA0KDQpMb29raW5nIGF0IGp1c3QgdGhlIDEwIHBvc3RzIHJldHVybmVkLCBwZXJoYXBzIGEgYmV0dGVyIG5hbWUgZm9yIHRoaXMNCnRvcGljIHdvdWxkIGJlICoqQ291cnNlIFJlZmxlY3Rpb25zIG9uIFRlYWNoaW5nIFN0YXRpc3RpY3MqKi4NCg0KIyMjIyBVbml0IFRha2Vhd2F5DQoNCkluIGFkZGl0aW9uIHRvIHNvbWUgdXNlZnVsIFIgcGFja2FnZXMgYW5kIGZ1bmN0aW9ucyBmb3IgdGhlIGFjdHVhbA0KcHJvY2VzcyBvZiB0b3BpYyBtb2RlbGluZywgaG9wZWZ1bGx5IHRoZXJlIGFyZSB0d28gbWFpbiBsZXNzb25zIEknbQ0KaG9waW5nIHlvdSB0YWtlIGF3YXkgZnJvbSB0aGlzIHdhbGt0aHJvdWdoOg0KDQoxLiAgKipUb3BpYyBtb2RlbGluZyByZXF1aXJlcyBhIGxvdCBvZiBkZWNpc2lvbnMuKiogQmV5b25kIGRlY2lkaW5nIG9uIGENCiAgICB2YWx1ZSBmb3IgSywgdGhlcmUgYXJlIGEgbnVtYmVyIG9mIGtleSBkZWNpc2lvbnMgdGhhdCB5b3UgaGF2ZSB0bw0KICAgIG1ha2UgdGhhdCBjYW4gZHJhbWF0aWNhbGx5IGFmZmVjdCB5b3VyIHJlc3VsdHMuIEZvciBleGFtcGxlLCB0byBzdGVtDQogICAgb3Igbm90IHRvIHN0ZW0/IFdoYXQgcXVhbGlmaWVzIGFzIGEgZG9jdW1lbnQ/IFdoYXQgZmxhdm9yIG9yIHRvcGljDQogICAgbW9kZWxpbmcgaXMgYmVzdCBzdWl0ZWQgdG8geW91ciBkYXRhIGFuZCByZXNlYXJjaCBxdWVzdGlvbnM/IEhvdw0KICAgIG1hbnkgaXRlcmF0aW9ucyB0byBydW4/DQoyLiAgKipUb3BpYyBtb2RlbGluZyBpcyBhcyBtdWNoIGFydCBhcyAoZGF0YSkgc2NpZW5jZS4qKiBBcyBCYWlsICgyMDE4KQ0KICAgIG5vdGVkLCB0aGUgdGVybSAidG9waWMiIGlzIHNvbWV3aGF0IGFtYml0aW91cywgYW5kIHRvcGljIG1vZGVscyBkbw0KICAgIG5vdCBwcm9kdWNlIGhpZ2hseSBudWFuY2VkIGNsYXNzaWZpY2F0aW9uIG9mIHRleHRzLiBPbmNlIHlvdSd2ZSBmaXQNCiAgICB5b3VyIG1vZGVsLCBpbnRlcnByZXRpbmcgeW91ciBtb2RlbCByZXF1aXJlcyBzb21lIG1lbnRhbCBneW1uYXN0aWNzDQogICAgYW5kIGlkZWFsbHkgc29tZSBrbm93bGVkZ2Ugb2YgdGhlIGNvbnRleHQgZnJvbSB3aGljaCB0aGUgZGF0YSBjYW1lDQogICAgdG8gaGVscCB3aXRoIGludGVycHJldGF0aW9uIG9mIHlvdXIgdG9waWNzLiBNb3Jlb3ZlciwgdGhlDQogICAgcXVhbnRpdGF0aXZlIGFwcHJvYWNoZXMgZm9yIG1ha2luZyB0aGUgZGVjaXNpb25zIGhpZ2hsaWdodGVkIGFib3ZlDQogICAgYXJlIGltcGVyZmVjdCBhbmQgYSBnb29kIGRlYWwgb2YgaHVtYW4ganVkZ21lbnQgcmVxdWlyZWQuDQoNCiMjIyMjIOKchSBDb21wcmVoZW5zaW9uIENoZWNrDQoNClVzaW5nIHRoZSBTVE0gbW9kZWwgeW91IGZpdCBmcm9tIHRoZSBTZWN0aW9uIDMgW0NvbXByZWhlbnNpb24gQ2hlY2tdDQp3aXRoIGEgZGlmZmVyZW50IHZhbHVlIGZvciBLLCB1c2UgdGhlIGFwcHJvYWNoZXMgZGVtb25zdHJhdGVkIGluIFNlY3Rpb24NCjQgdG8gZXhwbG9yZSBhbmQgaW50ZXJwcmV0IHlvdXIgdG9waWNzIGFuZCB0ZXJtcyBhbmQgcmV2aXNpdCB0aGUNCmZvbGxvd2luZyBxdWVzdGlvbjoNCg0KMS4gIE5vdyB0aGF0IHlvdSBoYXZlIGEgbGl0dGxlIG1vcmUgY29udGV4dCwgaG93IG1pZ2h0IHlvdSByZXZpc2UgeW91cg0KICAgIGluaXRpYWwgaW50ZXJwcmV0YXRpb24gb2Ygc29tZSBvZiB0aGUgbGF0ZW50IHRvcGljcyBvciBsYXRlbnQgdGhlbWVzDQogICAgZnJvbSB5b3VyIG1vZGVsPw0KICAgIA0KYGBge3J9DQojIEknbSBnb2luZyB0byBsb29rIGF0IHRvcGljIDEwIChrPTE0KSB3aGljaCBzZWVtcyB0byBiZSByZWxhdGVkIHRvDQojIHN0dWRlbnRzIHVzaW5nIHRlY2hub2xvZ3kNCiAgDQp0c19mb3J1bV9kYXRhX3JlZHVjZWQgPC10c19mb3J1bV9kYXRhJHBvc3RfY29udGVudFstdGVtcCRkb2NzLnJlbW92ZWRdDQoNCmZpbmRUaG91Z2h0cyhmb3J1bXNfc3RtX2ZvdXJ0ZWVuLA0KICAgICAgICAgICAgIHRleHRzID0gdHNfZm9ydW1fZGF0YV9yZWR1Y2VkLA0KICAgICAgICAgICAgIHRvcGljcyA9IDEwLCANCiAgICAgICAgICAgICBuID0gMTAsDQogICAgICAgICAgICAgdGhyZXNoID0gMC41KQ0KYGBgDQogICAgDQpUaGlzIHRvcGljIGhhcyB0byBkbyB3aXRoIGRpZmZlcmVudCBwbGF0Zm9ybXMgYW5kIHRvb2xzIHVzZWQgdG8gY29uZHVjdA0KZXhwZXJpbWVudHMgKHNlZW1pbmdseSB0byBiZXR0ZXIgdW5kZXJzdGFuZCBzdGF0aXN0aWNzKS4gTWFueSB0ZWFjaGVycw0Kc2VlbWVkIHRvIGJlIHNoYXJpbmcgaW5kaXZpZHVhbCB0b29scyBhbmQgY29tbWVudGluZyBvbiBob3cgdGhleSBsaWtlZA0KdGhlIGxlYXJuaW5nIGV4cGVyaWVuY2VzIHRoYXQgdGhlIHRlY2hub2xvZ3kgc2VlbWVkIHRvIGV2b2tlIGZyb20gc3R1ZGVudHMNCihpLmUuICJtZXRhY29nbml0aW9uIik=