Agenda

Homework

  • (late) Generic R Notebook
  • (late) GitHub Startup
  • (friday) Programming Notebooks: MDSR Chapter 04
  • (sunday) Programming Notebooks: MDSR Chapter 03
  • (next week) MDSR Chap 3 Exercises
  • (next week) Programming Notebooks: MDSR Chapter 05

STAT 380 workflow

Git / GitHub

Dr. Beckman’s Directory to Organize GitHub Repositories

Dr. Beckman’s Directory to Organize GitHub Repositories

Git / GitHub

Git / GitHub

Markdown / R Markdown

Why RMarkdown?

RMarkdown lets us separate content from formatting

  • Alternative to WYSIWYG’s like MS Word & Google Docs
  • Easy to configure headings, lists, TOC, figures, captions, links, images, etc
  • Change formatting globally with a css (cascading style sheet)
  • Good-looking tables are easy
  • Typeset nice-looking mathematics using LaTeX (and some preview)

STAT 501 excerpt (inline math)…

Here’s the model:

\(log(\frac{\hat{p}_i}{1-\hat{p}_i}) = 3.309 - 0.288(dist_i)\)

where \(\hat{p}_i\) is the proportion that voted “Yes” for community i.

Since the relationship on a logarithmic scale is hard to interpret, we back transform before interpreting coefficients.

Note: If \(e^{\beta_1} = 1\), then it means the odds are 1:1 which translates to a 50-50 chance and means there would be no relationship between the explanatory variable and the odds of “success” (however that’s defined in the context of the study).

STAT 501 excerpt (aligned to = sign)…

\[\begin{align*} \mathit{SSE} &= \Sigma_{i} \left( y_{i} - b_{0} - b_{1}x_{i} \right)^2 \\ \\ \frac{\partial \left( SSE \right)}{\partial b_{0}} &= \Sigma_{i} \left( y_{i} - b_{0} - b_{1}x_{i} \right)^2 \\ &= \left( -2 \right) \Sigma_{i} \left( y_{i} - b_{0} - b_{1}x_{i} \right) \\ &= \left( -2 \right) \left( \Sigma y_{i} - \Sigma b_{0} - \Sigma b_{1}x_{i} \right) \\ \\ \frac{\partial \left( SSE \right)}{\partial b_{1}} &= \Sigma_{i} \left( y_{i} - b_{0} - b_{1}x_{i} \right)^2 \\ &= \Sigma_{i} \left( -2x_{i} \right) \left( y_{i} - b_{0} - b_{1}x_{i} \right) \\ &= \left( -2\right) \Sigma_{i} \left( x_{i} y_{i} - x_{i} b_{0} - b_{1}x_{i}^2 \right) \\ &= \left( -2\right) \left( \Sigma x_{i} y_{i} - \Sigma x_{i} b_{0} - \Sigma b_{1}x_{i}^2 \right) \\ \end{align*}\]

(my) STAT 184 Philosophy

Individual lego bricks are simple.1 A complex model made of lego bricks 2
Bricks Trafalgar Legoland

Tidy Data

A page from Francis Galton’s notebook.

A page from Francis Galton’s notebook.

# package
require(mosaicData)  

# intake data from `mosaicData` package
data("Galton")

head(Galton, 10)

tidyverse command chains

# package
require(DataComputing)
# intake data
data("BabyNames")
# a command chain
Hazels <- 
  BabyNames %>%
  filter(grepl("Hazel", name)) %>%
  group_by(year) %>%
  summarise(total = sum(count))

Parts of speech

Discussion question

Hazels <- 
  BabyNames %>%
  filter(grepl("Hazel", name)) %>%
  group_by(year) %>%
  summarise(total = sum(count))

Just from the syntax, you should be able to tell which of the five different kinds of object each of these things is:

  • Hazels
  • BabyNames
  • filter
  • grepl
  • "Hazel"
  • name
  • group_by
  • year
  • summarise
  • total
  • sum
  • count

Small group discussion:

Kinds of join

Different joins have different answers to these questions.

Popular join types:


IF no right cases match the left case…

  • left_join(): Keep the left case and fill in the new variables (from the right table) with NA
  • inner_join(): Discard the left case.


IF multiple right cases match the left case…

left_join() and inner_join() do the same thing:

  • left_join(): Keep all combinations.
  • inner_join(): Keep all combinations.


Other useful joins:

  • full_join() Keep left case as well as unmatched right cases.
  • semi_join() Discard left case corresponding to unmatched right case.
  • anti_join() Keep the left case but discard any left case with a match in the right table

Reshaping data

require(dplyr)
# From http://stackoverflow.com/questions/1181060
Stocks <- tibble(
  time = as.Date('2009-01-01') + 0:9,
  X = rnorm(10, 0, 1),
  Y = rnorm(10, 0, 2),
  Z = rnorm(10, 0, 4)
)
# inspect data
Stocks
# gather/stack/melt--wide to narrow
StocksNarrow <- 
  Stocks %>% 
  gather(key = stock, value = price, X, Y, Z)  
StocksNarrow 
# spread/unstack/cast--narrow to wide
StocksWide <- 
  StocksNarrow %>% 
  spread(key = stock, value = price)
StocksWide

Three Important Concepts

  1. Data can be usefully organized into tables with “cases” and “variables.”
    • In “tidy data” every case is the same sort of thing (e.g. a person, a car, a year, a country in a year)
    • We sometimes even modify data in order to change what the cases represent in order to better represent a point.
  2. Data graphics and “glyph-ready” data
    • each case corresponds to a “glyph” (mark) on the graph
    • each variable to a graphical attribute of that glyph such as x- or y-position, color, size, length, shape, etc.
    • same is true for more technical tools (e.g., models)
  3. When data are not yet in glyph-ready form, you can transform (i.e. wrangle) them into glyph-ready form.
    • Such transformations are accomplished by performing one or more of a small set of basic operations on data tables
    • This is the work of data “verbs”

Grammar of graphics

Anatomy of a data visualization

  • Frame
  • Glyph
  • Aesthetic
  • Scale
  • Guide (legend)
  • Facet

SAT Scores & Student Spending by State in the US

require(mdsr)
data("SAT_2010")
# 2010 SAT Scores grouped by participation rate
SAT_2010 <- 
  SAT_2010 %>%
  mutate(SAT_rate = cut(sat_pct, breaks = c(0, 30, 60, 100), 
                        labels = c("low", "medium", "high")))
# initialize scatter plot
g <- 
  SAT_2010 %>%
  ggplot(aes(x = expenditure, y = math)) + 
  geom_point() + 
  geom_smooth(method = "lm", se = 0) + 
  xlab("Average expenditure per student ($1000)") + 
  ylab("Average score on math SAT")
# base plot showing SAT Math vs Student expenditure
g

# color scatter plot by SAT_rate
g + 
  aes(color = SAT_rate)

Some Graphics Components

glyph

The basic graphical unit that represents one case. Other terms used include mark and symbol.

aesthetic

  • a visual property of a glyph such as position, size, shape, color, etc.
  • may be mapped based on data values: sex -> color
  • may be set to particular non-data related values: color is black

scale

  • A mapping that translates data values into aesthetics.
  • example: male -> blue; female -> pink

frame

  • The position scale describing how data are mapped to x and y

guide

  • An indication for the human viewer of the scale. This allows the viewer to translate aesthetics back into data values.
  • Examples: x- and y-axes, various sorts of legends

Facets

# facet by SAT participation rate
g + 
  facet_wrap( ~ SAT_rate)

Layers

Medicare costs in Pennsylvania among other states

require(mdsr)
data("MedicareCharges", package = "mdsr")   # from mdsr, not DataComputing
# Pennsylvania medicare charges
ChargesPA <- 
  MedicareCharges %>%
  filter(stateProvider == "PA")
# Plot Pennsylvania data
p <- 
  ChargesPA %>%
  ggplot(aes(x = reorder(drg, mean_charge), y = mean_charge)) + 
  geom_bar(fill = "gray", stat = "identity") +   # stat = "identity" ==> value dictates bar height
  ylab("Statewide Average Charges ($)") + 
  xlab("Medical Procedure (DRG)") + 
  theme(axis.text.x = element_text(angle = 90, hjust = 1))
p

# add layer to show other states for reference
p + 
  geom_point(data = MedicareCharges, size = 1, alpha = 0.3)

Fivethirtyeight reproduction (MDSR p. 50)

MDSR Reproduction

require(mdsr)
require(Hmisc)
BabynamesDist <- make_babynames_dist()  # from mdsr
Joseph <- BabynamesDist %>%
  filter(name == "Joseph" & sex == "M")
# constructing the base plot
name_plot <- 
  Joseph %>%
  ggplot(aes(x = year)) + 
  geom_bar(stat = "identity", aes(y = count_thousands * alive_prob), 
           fill = "#b2d7e9", color = "white") + 
  geom_line(aes(y = count_thousands), size = 2) + 
  ylab("Number of People (thousands)") + 
  xlab(NULL)
# base plot
name_plot

median_yob <- wtd.quantile(x = Joseph$year, weights = Joseph$est_alive_today, probs = 0.5)
median_yob
 50% 
1975 
name_plot <- 
  name_plot + 
  geom_bar(stat = "identity", color = "white", fill = "#008fd5", 
           aes(y = ifelse(year == median_yob, est_alive_today / 1000, 0))) 
# Figure 3.22: Josephs
name_plot + 
  ggtitle(label = "Age Distribution of American Boys Named Joseph", subtitle = "By year of birth") + 
  geom_text(x = 1935, y = 40, size = 3.5, family = "mono", label = "Number of Josephs \n born each year") + 
  geom_text(x = 1915, y = 13, size = 3.5, family = "mono", color = "#008fd5", 
            label = "Number of Josephs \n born each year \n estimated to be alive \n on Jan. 1, 2014") + 
  geom_text(x = 2003, y = 40, size = 3.5, family = "sans", color = "darkgray",
            label = "The median\nliving Joseph\nis 37 years old.") + 
  geom_curve(x = 1995, xend = 1974, y = 40, yend = 24, 
             arrow = arrow(length = unit(0.3, "cm")), curvature = 0.5) + 
  ylim(0, 42) + 
  theme_fivethirtyeight()

NA

Three Important Concepts

  1. Data can be usefully organized into tables with “cases” and “variables.”
    • In “tidy data” every case is the same sort of thing (e.g. a person, a car, a year, a country in a year)
    • We sometimes even modify data in order to change what the cases represent in order to better represent a point.
  2. Data graphics and “glyph-ready” data
    • each case corresponds to a “glyph” (mark) on the graph
    • each variable to a graphical attribute of that glyph such as x- or y-position, color, size, length, shape, etc.
    • same is true for more technical tools (e.g., models)
  3. When data are not yet in glyph-ready form, you can transform (i.e. wrangle) them into glyph-ready form.
    • Such transformations are accomplished by performing one or more of a small set of basic operations on data tables
    • This is the work of data “verbs”

  1. Source : “Lego Color Bricks” by Alan Chia - Lego Color Bricks. Licensed under CC BY-SA 2.0 via Wikimedia Commons

  2. Source: Trafalgar Legoland 2003 by Kaihsu Tai - Kaihsu Tai. Licensed under CC BY-SA 3.0 via Wikimedia Commons

LS0tCnRpdGxlOiAiU1RBVCAxODQgUmV2aWV3IgphdXRob3I6ICJNYXR0aGV3IEJlY2ttYW4iCm91dHB1dDogCiAgc2xpZHlfcHJlc2VudGF0aW9uOiBkZWZhdWx0CiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdAotLS0KCmBgYHtyIGluY2x1ZGU9RkFMU0V9CiMgRnJvbnRtYXR0ZXIKcm0obGlzdCA9IGxzKCkpICAjIGNsZWFuLXVwCgojIHBhY2thZ2VzCmxpYnJhcnkoYmFieW5hbWVzKQpsaWJyYXJ5KERhdGFDb21wdXRpbmcpCmxpYnJhcnkoZ2d0aGVtZXMpCmxpYnJhcnkoSG1pc2MpCmxpYnJhcnkobWRzcikKbGlicmFyeShtb3NhaWMpCmxpYnJhcnkodGlkeXZlcnNlKQoKIyBpbnB1dHMgJiBvdXRwdXRzCgojIyBgR2FsdG9uYCAgICAgZnJvbSBtb3NhaWNEYXRhIHBhY2thZ2UgCiMjIGBCYWJ5TmFtZXNgICBmcm9tIERhdGFDb21wdXRpbmcgcGFja2FnZQojIyBgU3RvY2tzYCAgICAgc2ltdWxhdGVkIGRhdGEKIyMgYFNBVF8yMDEwYCAgIGZyb20gbWRzciBwYWNrYWdlCiMjIGBiYWJ5bmFtZXNgICBmcm9tIGJhYnluYW1lcyBwYWNrYWdlCiMjIGBNZWRpY2FyZUNoYXJnZXNgIGZyb20gbWRzcgpgYGAKCgojIyBBZ2VuZGEKCi0gcmV2aXNpdCByZXByb2R1Y2libGUgd29ya2Zsb3cKLSBzb21lIHJldmlldyBvZiBTVEFUIDE4NCB0b3BpY3MKCiMjIyMgSG9tZXdvcmsgCgotIChsYXRlKSBHZW5lcmljIFIgTm90ZWJvb2sKLSAobGF0ZSkgR2l0SHViIFN0YXJ0dXAKLSAoZnJpZGF5KSBQcm9ncmFtbWluZyBOb3RlYm9va3M6IE1EU1IgQ2hhcHRlciAwNAotIChzdW5kYXkpIFByb2dyYW1taW5nIE5vdGVib29rczogTURTUiBDaGFwdGVyIDAzCi0gKG5leHQgd2VlaykgTURTUiBDaGFwIDMgRXhlcmNpc2VzCi0gKG5leHQgd2VlaykgUHJvZ3JhbW1pbmcgTm90ZWJvb2tzOiBNRFNSIENoYXB0ZXIgMDUKCiMjIFNUQVQgMzgwIHdvcmtmbG93CgotIFJlcHJvZHVjaWJsZSBSZXNlYXJjaAogICAgLSBHaXQoSHViKSBzb3VyY2UgY29udHJvbCBiYXNpY3MKICAgIC0gUlN0dWRpbyBJREUgKFIsIFJtZCwgR2l0KQoKCiMjIEdpdCAvIEdpdEh1YgoKLSBHaXRIdWIncyBJbnRybzogPGh0dHBzOi8vZ3VpZGVzLmdpdGh1Yi5jb20vYWN0aXZpdGllcy9oZWxsby13b3JsZC8+Ci0gIkdpdEh1YiBpcyBhIGNvZGUgaG9zdGluZyBwbGF0Zm9ybSBmb3IgdmVyc2lvbiBjb250cm9sIGFuZCBjb2xsYWJvcmF0aW9uLiBJdCBsZXRzIHlvdSBhbmQgb3RoZXJzIHdvcmsgdG9nZXRoZXIgb24gcHJvamVjdHMgZnJvbSBhbnl3aGVyZS4iIAotICoqUmVwb3NpdG9yaWVzKiogYXJlIHVzZWQgdG8gb3JnYW5pemUgZWFjaCBwcm9qZWN0CiAgICAtIFRoZXNlIGNhbiBjb250YWluIGRvY3VtZW50cywgaW1hZ2VzLCBmb2xkZXJzLCBjb2RlLCBkYXRhLCAuLi4gYmFzaWNhbGx5IGV2ZXJ5dGhpbmcgeW91IG5lZWQgZm9yIHlvdXIgcHJvamVjdCAKICAgIC0gTGFyZ2VyIGZpbGVzICg+IDEwLTE1IE1CKSBuZWVkIHNvbWUgc3BlY2lhbCBoYW5kbGluZywgYnV0IHVzdWFsbHkgbm90IGEgYmlnIGRlYWwKICAgIC0gWW91J2xsIHNvb24gbGluayBlYWNoICoqR2l0SHViIFJlcG9zaXRvcnkqKiB0byBhbiAqKlJTdHVkaW8gUHJvamVjdCoqIHRvIHN0cmVhbWxpbmUgdGhlIHdvcmtmbG93CiAgICAtIERvbid0IHB1dCByZXBvc2l0b3JpZXMgaW5zaWRlIG90aGVyIHJlcG9zaXRvcmllcwotIE1vc3Qgb2YgeW91ciB3b3JrZmxvdyBpcyB1bmNoYW5nZWQKICAgIC0gQXMgZmFyIGFzIHlvdXIgY29tcHV0ZXIgaXMgY29uY2VybmVkLCB0aGUgcmVwb3NpdG9yeSB3b3JrcyBqdXN0IGxpa2UgYW55IG90aGVyIGRpcmVjdG9yeSAoaS5lLiBmb2xkZXIpCiAgICAtIFlvdSBlZGl0IGZpbGVzLCBzYXZlIGNoYW5nZXMsIGV0YwoKIVtEci4gQmVja21hbidzIERpcmVjdG9yeSB0byBPcmdhbml6ZSBHaXRIdWIgUmVwb3NpdG9yaWVzXShHaXRIdWIgRGlyZWN0b3J5LnBuZykKCgojIyBHaXQgLyBHaXRIdWIKCi0gRmlyc3QgbmV3IHBhcnQ6ICgqKmNvbW1pdCoqKSBjaGFuZ2VzCiAgICAtIGlkZWFsbHksIGVhY2ggY29tbWl0IHNob3VsZCBlbmNvbXBhc3MgKm9uZSBtZWFuaW5nZnVsIG1vZGlmaWNhdGlvbiogCiAgICAtIGNyZWF0ZXMgYSBwZXJtYW5lbnQgc25hcHNob3Qgb2YgdGhlIHJlcG9zaXRvcnkKICAgIC0geW91IGNhbiByZXZpc2l0IHRoZXNlIHNuYXBzaG90cyBhdCBhbnkgdGltZS4uLiAKLSBTZWNvbmQgbmV3IHBhcnQ6ICgqKnB1c2gvcHVsbCoqKSB0byByZW1vdGUKICAgIC0gR2l0SHViIHN0b3JlcyB0aGUgc3RhdGUgb2YgeW91ciByZXBvc2l0b3J5IGluIHRoZSBjbG91ZAogICAgLSBXaGVuIHlvdSAqcHVzaCosIHlvdSB1cGRhdGUgdGhlIHJlbW90ZSB2ZXJzaW9uIAogICAgLSBBbnlvbmUgd2l0aCBhY2Nlc3MgdG8geW91ciBHaXRIdWIgcmVwb3NpdG9yeSBjYW4gKnB1bGwqIHRoZSByZW1vdGUgdmVyc2lvbiBhbmQgd29yayB3aXRoIGl0CiAgICAgICAgLSBUaGlzIG1pZ2h0IGJlIHlvdSwgdXNpbmcgYSBkaWZmZXJlbnQgY29tcHV0ZXIKICAgICAgICAtIEl0IG1pZ2h0IGJlIGEgY29sbGFib3JhdG9yIAogICAgICAgIC0gSXQgbWlnaHQgYmUgYSBwcm9mZXNzb3Igb3IgVEEKICAgICAgICAtIElmIHRoZSByZXBvIGlzIG1hZGUgcHVibGljLCBpdCBtaWdodCBiZSBhIGNvbXBsZXRlIHN0cmFuZ2VyIQogICAgLSBUaGUgY29sbGFib3JhdG9yIGNhbiB0aGVuIGNvbW1pdCBjaGFuZ2VzIGFuZCBwdXNoIHRoZW0gdG8gdGhlIHJlbW90ZSBhcyB3ZWxsIAogICAgICAgIC0gZG9uJ3Qgd29ycnksIHRoZXJlIGFyZSBzYWZlZ3VhcmRzIGluIHBsYWNlIGJhc2VkIG9uIHVzZXIgcGVybWlzc2lvbnMKCgohW0dpdCBTY2hlbWF0aWM6IGh0dHA6Ly93d3cudHNiYWtrZXIubmwvZ2l0Lmh0bWxdKGdpdHN0YWdlcy5qcGcpCgojIyBHaXQgLyBHaXRIdWIKCi0gT25jZSBjb25maWd1cmVkLCBuZWFybHkgYWxsIG9mIHRoZSBhY3Rpb24gY2FuIGhhcHBlbiBpbiBSU3R1ZGlvCi0gQSAiR2l0IiB0YWIgd2lsbCBhcHBlYXIgaW4gUlN0dWRpbwotIERpZmYsIENvbW1pdCwgUHVsbCwgUHVzaCBhcmUgbW9zdCBjb21tb24gYWN0aW9ucwoKCiFbXShHaXRIdWIgRGlyZWN0b3J5IFJTdHVkaW8ucG5nKQoKCgoKIyMgTWFya2Rvd24gLyBSIE1hcmtkb3duCgotIEh1bWFuLXJlYWRhYmxlIHN5bnRheCBieSBkZXNpZ24KLSBDYW4gImtuaXQiIChvciBwcmV2aWV3KSBzYW1lIC5SbWQgdG8gSFRNTCAob3IgUERGIG9yIE1TIFdvcmQgd2l0aCBzb21lIGNvbmZpZ3VyYXRpb24pCi0gQ2FuIHByb2R1Y2UgYm90aCBub3RlYm9vaywgc2xpZGVzLCBkb2N1bWVudCwgd2VicGFnZSwgZXRjIGFzIG91dHB1dC4KLSAqKlJlZ2FyZGxlc3MqKiBvZiBpbnRlbmRlZCBvdXRwdXQsIFJtZCBkb2N1bWVudHMgZ2VuZXJhbGx5IHJlcXVpcmUgdHdvIHBhcnRzCiAgICAtICJ5YW1sIiBoZWFkZXIgYXQgdGhlIHRvcCAoZGVzaWduYXRlZCBieSBgLS0tYCBiZWZvcmUvYWZ0ZXIpIGluY2x1ZGVzIHNvbWUgZG9jdW1lbnQgY29udHJvbHMKICAgICAgICAtIHRpdGxlCiAgICAgICAgLSBhdXRob3IKICAgICAgICAtIGRhdGUKICAgICAgICAtIG91dHB1dAogICAgICAgIC0gKGV0YykKICAgIC0gYm9keSBvZiB0aGUgZG9jdW1lbnQgaW5jbHVkaW5nIGNvbXBvbmVudHMgc3VjaCBhczogIAogICAgICAgIC0gTWFya2Rvd24gc3ludGF4IChsaWtlIGhhc2h0YWcgaGVhZGVycykKICAgICAgICAtIE5hcnJhdGl2ZSB0ZXh0CiAgICAgICAgLSBMaXN0cyAoYnVsbGV0cyBvciBudW1iZXJzKQogICAgICAgIC0gQ29kZSAiY2h1bmtzIiAoUiwgcHl0aG9uLCBTUUwsIFN0YW4sIGV0YyBlbWJlZGRlZCBhbW9uZyB0aGUgbmFycmF0aXZlIG9mIHRoZSBkb2N1bWVudCkKICAgICAgICAtIFVSTHMKICAgICAgICAtIEltYWdlcwogICAgICAgIC0gVGFibGVzCiAgICAgICAgLSBhbmQgbXVjaCBtb3JlLi4uCgoKIyMgV2h5IFJNYXJrZG93bj8KCiMjIyMgUk1hcmtkb3duIGxldHMgdXMgc2VwYXJhdGUgY29udGVudCBmcm9tIGZvcm1hdHRpbmcKCi0gQWx0ZXJuYXRpdmUgdG8gV1lTSVdZRydzIGxpa2UgTVMgV29yZCAmIEdvb2dsZSBEb2NzIAotIEVhc3kgdG8gY29uZmlndXJlIGhlYWRpbmdzLCBsaXN0cywgVE9DLCBmaWd1cmVzLCBjYXB0aW9ucywgbGlua3MsIGltYWdlcywgZXRjCi0gQ2hhbmdlIGZvcm1hdHRpbmcgZ2xvYmFsbHkgd2l0aCBhIGNzcyAoY2FzY2FkaW5nIHN0eWxlIHNoZWV0KQotIEdvb2QtbG9va2luZyB0YWJsZXMgYXJlIGVhc3kKLSBUeXBlc2V0IG5pY2UtbG9va2luZyBtYXRoZW1hdGljcyB1c2luZyBMYVRlWCAoYW5kIHNvbWUgcHJldmlldykKCiMjIyMgU1RBVCA1MDEgZXhjZXJwdCAoaW5saW5lIG1hdGgpLi4uCgpIZXJlJ3MgdGhlIG1vZGVsOiAKCiRsb2coXGZyYWN7XGhhdHtwfV9pfXsxLVxoYXR7cH1faX0pID0gMy4zMDkgLSAwLjI4OChkaXN0X2kpJAoKd2hlcmUgJFxoYXR7cH1faSQgaXMgdGhlIHByb3BvcnRpb24gdGhhdCB2b3RlZCAiWWVzIiBmb3IgY29tbXVuaXR5ICppKi4KCgpTaW5jZSB0aGUgcmVsYXRpb25zaGlwIG9uIGEgbG9nYXJpdGhtaWMgc2NhbGUgaXMgaGFyZCB0byBpbnRlcnByZXQsIHdlIGJhY2sgdHJhbnNmb3JtIGJlZm9yZSBpbnRlcnByZXRpbmcgY29lZmZpY2llbnRzLiAKCk5vdGU6IElmICRlXntcYmV0YV8xfSA9IDEkLCB0aGVuIGl0IG1lYW5zIHRoZSBvZGRzIGFyZSAxOjEgd2hpY2ggdHJhbnNsYXRlcyB0byBhIDUwLTUwIGNoYW5jZSBhbmQgbWVhbnMgdGhlcmUgd291bGQgYmUgbm8gcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIGV4cGxhbmF0b3J5IHZhcmlhYmxlIGFuZCB0aGUgb2RkcyBvZiAic3VjY2VzcyIgKGhvd2V2ZXIgdGhhdCdzIGRlZmluZWQgaW4gdGhlIGNvbnRleHQgb2YgdGhlIHN0dWR5KS4gIAoKIyMjIyBTVEFUIDUwMSBleGNlcnB0IChhbGlnbmVkIHRvIGA9YCBzaWduKS4uLgoKXGJlZ2lue2FsaWduKn0KClxtYXRoaXR7U1NFfSAmPSBcU2lnbWFfe2l9IFxsZWZ0KCB5X3tpfSAtIGJfezB9IC0gYl97MX14X3tpfSBccmlnaHQpXjIgXFwKClxcCgpcZnJhY3tccGFydGlhbCBcbGVmdCggU1NFIFxyaWdodCl9e1xwYXJ0aWFsIGJfezB9fSAmPSBcU2lnbWFfe2l9IFxsZWZ0KCB5X3tpfSAtIGJfezB9IC0gYl97MX14X3tpfSBccmlnaHQpXjIgXFwKICY9IFxsZWZ0KCAtMiBccmlnaHQpIFxTaWdtYV97aX0gXGxlZnQoIHlfe2l9IC0gYl97MH0gLSBiX3sxfXhfe2l9IFxyaWdodCkgXFwKICY9IFxsZWZ0KCAtMiBccmlnaHQpIFxsZWZ0KCBcU2lnbWEgeV97aX0gLSBcU2lnbWEgYl97MH0gLSBcU2lnbWEgYl97MX14X3tpfSBccmlnaHQpIFxcCgpcXAoKXGZyYWN7XHBhcnRpYWwgXGxlZnQoIFNTRSBccmlnaHQpfXtccGFydGlhbCBiX3sxfX0gJj0gXFNpZ21hX3tpfSBcbGVmdCggeV97aX0gLSBiX3swfSAtIGJfezF9eF97aX0gXHJpZ2h0KV4yIFxcCiAmPSBcU2lnbWFfe2l9IFxsZWZ0KCAtMnhfe2l9IFxyaWdodCkgXGxlZnQoIHlfe2l9IC0gYl97MH0gLSBiX3sxfXhfe2l9IFxyaWdodCkgXFwKICY9IFxsZWZ0KCAtMlxyaWdodCkgXFNpZ21hX3tpfSBcbGVmdCggeF97aX0geV97aX0gLSB4X3tpfSBiX3swfSAtIGJfezF9eF97aX1eMiBccmlnaHQpIFxcCiAmPSBcbGVmdCggLTJccmlnaHQpIFxsZWZ0KCBcU2lnbWEgeF97aX0geV97aX0gLSBcU2lnbWEgeF97aX0gYl97MH0gLSBcU2lnbWEgYl97MX14X3tpfV4yIFxyaWdodCkgXFwKClxlbmR7YWxpZ24qfQoKCiMjIChteSkgU1RBVCAxODQgUGhpbG9zb3BoeQoKLSAibGVzcy12b2x1bWUsIG1vcmUgY3JlYXRpdml0eSIgIAotIEEgZmV3IHNpbXBsZSB0b29scyBjYW4gYmUgY29tYmluZWQgaW4gcG93ZXJmdWwgd2F5cwotIEluZGl2aWR1YWxseSB0aGVzZSB0b29scyBhcmUgaW50cm9kdWNlZCBhcyAiZGF0YSBtb3ZlcyIgCi0gVGhlIGNvbXBsZXhpdHkgY29tZXMgZnJvbSBjb21iaW5pbmcgdGhlc2Ugc2ltcGxlIHRvb2xzIGluIG9yZGVyIHRvIGFjaGlldmUgb3VyIHNwZWNpZmljIHB1cnBvc2VzCi0gYHRpZHl2ZXJzZWAgc3ViLWxhbmd1YWdlIGFjY29tcGxpc2hlcyB0aGlzIHB1cnBvc2Ugd2l0aGluIGFuIGVjb3N5c3RlbSBwcmVkaWNhdGVkIHVwb24gc28tY2FsbGVkICJUaWR5IiBkYXRhLgoKSW5kaXZpZHVhbCBsZWdvIGJyaWNrcyBhcmUgc2ltcGxlLl5bU291cmNlIDogIkxlZ28gQ29sb3IgQnJpY2tzIiBieSBBbGFuIENoaWEgLSBMZWdvIENvbG9yIEJyaWNrcy4gTGljZW5zZWQgdW5kZXIgQ0MgQlktU0EgMi4wIHZpYSBbV2lraW1lZGlhIENvbW1vbnNdKGh0dHA6Ly9jb21tb25zLndpa2ltZWRpYS5vcmcvd2lraS9GaWxlOkxlZ29fQ29sb3JfQnJpY2tzLmpwZyNtZWRpYXZpZXdlci9GaWxlOkxlZ29fQ29sb3JfQnJpY2tzLmpwZyldICB8IEEgY29tcGxleCBtb2RlbCBtYWRlIG9mIGxlZ28gYnJpY2tzIF5bU291cmNlOiAqVHJhZmFsZ2FyIExlZ29sYW5kIDIwMDMqIGJ5IEthaWhzdSBUYWkgLSBLYWloc3UgVGFpLiBMaWNlbnNlZCB1bmRlciBDQyBCWS1TQSAzLjAgdmlhIFtXaWtpbWVkaWEgQ29tbW9uc10oaHR0cDovL2NvbW1vbnMud2lraW1lZGlhLm9yZy93aWtpL0ZpbGU6VHJhZmFsZ2FyX0xlZ29sYW5kXzIwMDMuanBnI21lZGlhdmlld2VyL0ZpbGU6VHJhZmFsZ2FyX0xlZ29sYW5kXzIwMDMuanBnKV18Ci0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIHwgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gIHwKIVtCcmlja3NdKExlZ29fQ29sb3JfQnJpY2tzLmpwZyl8ICFbVHJhZmFsZ2FyIExlZ29sYW5kXShUcmFmYWxnYXJfTGVnb2xhbmRfMjAwMy5qcGcpIHwKCgojIyBUaWR5IERhdGEKCi0gIk5lYXQiIGlzIG5vdCB0aGUgc2FtZSBhcyAiVGlkeSIKLSAqVGlkeSBkYXRhKiBhcmUgb3JnYW5pemVkIGFjY29yZGluZyB0byB0d28gc2ltcGxlIHJ1bGVzOiAKICAgIDEuIFRoZSByb3dzLS1jYWxsZWQgKmNhc2VzKiBvciBvYnNlcnZhdGlvbmFsIHVuaXRzLS1lYWNoIHJlZmVyIHRvIGEgc3BlY2lmaWMsIHVuaXF1ZSwgYW5kIHNpbWlsYXIgc29ydCBvZiB0aGluZwogICAgMi4gVGhlIGNvbHVtbnMsIGNhbGxlZCAqdmFyaWFibGVzKiwgZWFjaCBoYXZlIHRoZSBzYW1lIHNvcnQgb2YgdmFsdWUgcmVjb3JkZWQgZm9yIGVhY2ggY2FzZSAoaS5lLiByb3cpCi0gR2FsdG9uJ3MgZmFtaWx5IGRhdGEKICAgIC0gQXJlIHRoZXNlIGRhdGEgdGlkeT8KICAgIC0gV2hhdCBpcyBhIGNhc2U/CiAgICAtIFdoYXQgYXJlIHRoZSB2YXJpYWJsZXM/CgohW0EgcGFnZSBmcm9tIEZyYW5jaXMgR2FsdG9uJ3Mgbm90ZWJvb2suXShnYWx0b24tbm90ZWJvb2suanBnKQoKCmBgYHtyIGV2YWw9RkFMU0UsIGVjaG89VFJVRX0KIyBwYWNrYWdlCnJlcXVpcmUobW9zYWljRGF0YSkgIAoKIyBpbnRha2UgZGF0YSBmcm9tIGBtb3NhaWNEYXRhYCBwYWNrYWdlCmRhdGEoIkdhbHRvbiIpCgpoZWFkKEdhbHRvbiwgMTApCmBgYAoKIyMgYHRpZHl2ZXJzZWAgY29tbWFuZCBjaGFpbnMKCi0gRWFjaCBsaW5rIGluIHRoZSBjaGFpbiBpcyBhICJkYXRhIHZlcmIiIG9yICJkYXRhIG1vdmUiICB3aXRoIGl0cyBhcmd1bWVudHMKICAgIC0gVGhlIHZlcnkgZmlyc3QgbGluayBpcyB0eXBpY2FsbHkgYSBkYXRhIHRhYmxlLgogICAgLSBMaW5rcyBhcmUgY29ubmVjdGVkIGJ5IHRoZSBwaXBlOiBgJT4lYAotIE9mdGVuLCBidXQgbm90IGFsd2F5cywgeW91IHdpbGwgc3RvcmUgdGhlIHJlc3VsdCBvZiB0aGUgY2hhaW4gaW4gYSBuYW1lZCBvYmplY3QKICAgIC0gVGhpcyBpcyBkb25lIHdpdGggdGhlICphc3NpZ25tZW50IG9wZXJhdG9yKiwgYDwtYAotIE5ldyBsaW5lIGZvciBlYWNoIGxpbmsKLSBOb3RlIHRoYXQgYCU+JWAgaXMgYXQgdGhlIGVuZCBvZiBlYWNoIGxpbmUuICAqKkV4Y2VwdCoqCiAgICAtIGBIYXplbHMgPC1gIGlzIGFuIGFzc2lnbm1lbnQKICAgIC0gTGFzdCBsaW5lIGhhcyBubyBgJT4lYCAob3RoZXJ3aXNlIFIgdGhpbmtzIHRoZXJlJ3MgbW9yZSkKCgpgYGB7cn0KIyBwYWNrYWdlCnJlcXVpcmUoRGF0YUNvbXB1dGluZykKCiMgaW50YWtlIGRhdGEKZGF0YSgiQmFieU5hbWVzIikKCiMgYSBjb21tYW5kIGNoYWluCkhhemVscyA8LSAKICBCYWJ5TmFtZXMgJT4lCiAgZmlsdGVyKGdyZXBsKCJIYXplbCIsIG5hbWUpKSAlPiUKICBncm91cF9ieSh5ZWFyKSAlPiUKICBzdW1tYXJpc2UodG90YWwgPSBzdW0oY291bnQpKQpgYGAKCiMjIFBhcnRzIG9mIHNwZWVjaAoKLSBEYXRhIHNldAotIGZ1bmN0aW9uCi0gYXJndW1lbnQKLSB2YXJpYWJsZXMKLSBjb25zdGFudHMKCiMjIyMgRGlzY3Vzc2lvbiBxdWVzdGlvbgoKYGBge3IgZXZhbD1GQUxTRX0KSGF6ZWxzIDwtIAogIEJhYnlOYW1lcyAlPiUKICBmaWx0ZXIoZ3JlcGwoIkhhemVsIiwgbmFtZSkpICU+JQogIGdyb3VwX2J5KHllYXIpICU+JQogIHN1bW1hcmlzZSh0b3RhbCA9IHN1bShjb3VudCkpCmBgYAoKSnVzdCBmcm9tIHRoZSBzeW50YXgsIHlvdSBzaG91bGQgYmUgYWJsZSB0byB0ZWxsIHdoaWNoIG9mIHRoZSBmaXZlIGRpZmZlcmVudCBraW5kcyBvZiBvYmplY3QgZWFjaCBvZiB0aGVzZSB0aGluZ3MgaXM6IAoKLSBgSGF6ZWxzYCAKLSBgQmFieU5hbWVzYCAKLSBgZmlsdGVyYCAKLSBgZ3JlcGxgIAotIGAiSGF6ZWwiYCAKLSBgbmFtZWAgCi0gYGdyb3VwX2J5YCAKLSBgeWVhcmAgCi0gYHN1bW1hcmlzZWAgCi0gYHRvdGFsYCAKLSBgc3VtYCAKLSBgY291bnRgCgoKIyMgU21hbGwgZ3JvdXAgZGlzY3Vzc2lvbjogCgotIEV4cGxhaW4gZWFjaCBvZiB0aGVzZSBjb21tb24gYHRpZHl2ZXJzZWAgZnVuY3Rpb25zOgogICAgLSAqKkxpc3QgMS0tZGF0YSBqb2lucyAmIHJlc2hhcGU6KioKICAgICAgICAtIGBsZWZ0X2pvaW4oKWAKICAgICAgICAtIGBpbm5lcl9qb2luKClgCiAgICAgICAgLSBgc3ByZWFkKClgCiAgICAgICAgLSBgZ2F0aGVyKClgCiAgICAtICoqTGlzdCAyLS1kYXRhIHZlcmJzOioqCiAgICAgICAgLSBgbXV0YXRlKClgCiAgICAgICAgLSBgZmlsdGVyKClgCiAgICAgICAgLSBgc2VsZWN0KClgCiAgICAgICAgLSBgYXJyYW5nZSgpYAogICAgLSAqKkxpc3QgMy0tbW9yZSBkYXRhIHZlcmJzOioqCiAgICAgICAgLSBgaGVhZCgpYCAmIGB0YWlsKClgCiAgICAgICAgLSBgdHJhbnNtdXRlKClgCiAgICAgICAgLSBgcmVuYW1lKClgCiAgICAgICAgLSBgc2FtcGxlX24oKWAKICAgICAgICAtIGBzdW1tYXJpc2UoKWAgJiBgZ3JvdXBfYnkoKWAKICAgIC0gKipMaXN0IDQtLXN1bW1hcnkgZnVuY3Rpb25zOioqCiAgICAgICAgLSBgZ2xpbXBzZSgpYAogICAgICAgIC0gYHN0cigpYAogICAgICAgIC0gYHN1bW1hcnkoKWAKICAgICAgICAtIGBucm93KClgICYgYG5jb2woKWAKICAgICAgICAtIGBuYW1lcygpYAogICAgICAgIC0gYFZpZXcoKWAKLSBBcmUgdGhlcmUgZnVuY3Rpb25zIHRoYXQgbm8gb25lIGluIHRoZSBncm91cCB1bmRlcnN0b29kPwoKCgojIyBLaW5kcyBvZiBqb2luCgoKRGlmZmVyZW50IGpvaW5zIGhhdmUgZGlmZmVyZW50IGFuc3dlcnMgdG8gdGhlc2UgcXVlc3Rpb25zLgoKKiBXaGF0IHRvIGRvIHdoZW4gdGhlcmUgaXMgKipubyBtYXRjaCoqIGJldHdlZW4gYSBsZWZ0IGNhc2UgYW5kIGFueSByaWdodCBjYXNlPwoqIFdoYXQgdG8gZG8gd2hlbiB0aGVyZSBhcmUgKiptdWx0aXBsZSBtYXRjaGluZyBjYXNlcyoqIGluIHRoZSByaWdodCB0YWJsZSBmb3IgYSBjYXNlIGluIHRoZSBsZWZ0IHRhYmxlPwoKClBvcHVsYXIgam9pbiB0eXBlczogCgotIGBsZWZ0X2pvaW4oKWA6IGpvaW5zIG1hdGNoaW5nIHJvd3MgZnJvbSB0aGUgKnJpZ2h0KiB0YWJsZSB0byB0aGUgKmxlZnQqIHRhYmxlCi0gYGlubmVyX2pvaW4oKWA6IG9ubHkgcmV0YWluIHJvd3MgZm9yIHdoaWNoIGEgbWF0Y2ggZXhpc3RzCgo8YnI+CgojIyMjIElGIG5vIHJpZ2h0IGNhc2VzIG1hdGNoIHRoZSBsZWZ0IGNhc2UuLi4KCi0gYGxlZnRfam9pbigpYDogS2VlcCB0aGUgbGVmdCBjYXNlIGFuZCBmaWxsIGluIHRoZSBuZXcgdmFyaWFibGVzIChmcm9tIHRoZSByaWdodCB0YWJsZSkgd2l0aCBgTkFgCi0gYGlubmVyX2pvaW4oKWA6IERpc2NhcmQgdGhlIGxlZnQgY2FzZS4KCjxicj4KCiMjIyMgSUYgbXVsdGlwbGUgcmlnaHQgY2FzZXMgbWF0Y2ggdGhlIGxlZnQgY2FzZS4uLgoKYGxlZnRfam9pbigpYCBhbmQgYGlubmVyX2pvaW4oKWAgZG8gdGhlIHNhbWUgdGhpbmc6CgoqIGBsZWZ0X2pvaW4oKWA6IEtlZXAgKiphbGwgY29tYmluYXRpb25zKiouCiogYGlubmVyX2pvaW4oKWA6IEtlZXAgKiphbGwgY29tYmluYXRpb25zKiouCgo8YnI+CgojIyMjIE90aGVyIHVzZWZ1bCBqb2luczoKCiogYGZ1bGxfam9pbigpYCBLZWVwIGxlZnQgY2FzZSBhcyB3ZWxsIGFzIHVubWF0Y2hlZCByaWdodCBjYXNlcy4KKiBgc2VtaV9qb2luKClgIERpc2NhcmQgbGVmdCBjYXNlIGNvcnJlc3BvbmRpbmcgdG8gdW5tYXRjaGVkIHJpZ2h0IGNhc2UuCiogYGFudGlfam9pbigpYCBLZWVwIHRoZSBsZWZ0IGNhc2UgYnV0IGRpc2NhcmQgYW55IGxlZnQgY2FzZSB3aXRoIGEgbWF0Y2ggaW4gdGhlIHJpZ2h0IHRhYmxlCgoKIyMgUmVzaGFwaW5nIGRhdGEKCi0gYGdhdGhlcigpYCBzdGFja3MgY29sdW1ucyB0byBjb252ZXJ0IGZyb20gd2lkZSB0byBuYXJyb3cKLSBgc3ByZWFkKClgIHVuc3RhY2tzIGNvbHVtbnMgdG8gY29udmVydCBuYXJyb3cgdG8gd2lkZQoKCmBgYHtyfQpyZXF1aXJlKGRwbHlyKQojIEZyb20gaHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy8xMTgxMDYwClN0b2NrcyA8LSB0aWJibGUoCiAgdGltZSA9IGFzLkRhdGUoJzIwMDktMDEtMDEnKSArIDA6OSwKICBYID0gcm5vcm0oMTAsIDAsIDEpLAogIFkgPSBybm9ybSgxMCwgMCwgMiksCiAgWiA9IHJub3JtKDEwLCAwLCA0KQopCgojIGluc3BlY3QgZGF0YQpTdG9ja3MKCiMgZ2F0aGVyL3N0YWNrL21lbHQtLXdpZGUgdG8gbmFycm93ClN0b2Nrc05hcnJvdyA8LSAKICBTdG9ja3MgJT4lIAogIGdhdGhlcihrZXkgPSBzdG9jaywgdmFsdWUgPSBwcmljZSwgWCwgWSwgWikgIAoKU3RvY2tzTmFycm93IAoKIyBzcHJlYWQvdW5zdGFjay9jYXN0LS1uYXJyb3cgdG8gd2lkZQpTdG9ja3NXaWRlIDwtIAogIFN0b2Nrc05hcnJvdyAlPiUgCiAgc3ByZWFkKGtleSA9IHN0b2NrLCB2YWx1ZSA9IHByaWNlKQoKU3RvY2tzV2lkZQpgYGAKCgojIyBUaHJlZSBJbXBvcnRhbnQgQ29uY2VwdHMgCgoxLiBEYXRhIGNhbiBiZSB1c2VmdWxseSBvcmdhbml6ZWQgaW50byB0YWJsZXMgd2l0aCAiY2FzZXMiIGFuZCAidmFyaWFibGVzLiIgIAogICAgLSBJbiAidGlkeSBkYXRhIiBldmVyeSBjYXNlIGlzIHRoZSBzYW1lIHNvcnQgb2YgdGhpbmcgKGUuZy4gYSBwZXJzb24sIGEgY2FyLCBhIHllYXIsIGEgY291bnRyeSBpbiBhIHllYXIpIAogICAgLSBXZSBzb21ldGltZXMgZXZlbiBtb2RpZnkgZGF0YSBpbiBvcmRlciB0byBjaGFuZ2Ugd2hhdCB0aGUgY2FzZXMgcmVwcmVzZW50IGluIG9yZGVyIHRvIGJldHRlciByZXByZXNlbnQgYSBwb2ludC4KCiMuIERhdGEgZ3JhcGhpY3MgYW5kICJnbHlwaC1yZWFkeSIgZGF0YQogICAgLSBlYWNoIGNhc2UgY29ycmVzcG9uZHMgdG8gYSAiZ2x5cGgiIChtYXJrKSBvbiB0aGUgZ3JhcGgKICAgIC0gZWFjaCB2YXJpYWJsZSB0byBhIGdyYXBoaWNhbCBhdHRyaWJ1dGUgb2YgdGhhdCBnbHlwaCBzdWNoIGFzIHgtIG9yIHktcG9zaXRpb24sIGNvbG9yLCBzaXplLCBsZW5ndGgsIHNoYXBlLCBldGMuIAogICAgLSBzYW1lIGlzIHRydWUgZm9yIG1vcmUgdGVjaG5pY2FsIHRvb2xzIChlLmcuLCBtb2RlbHMpIAoKIy4gV2hlbiBkYXRhIGFyZSBub3QgeWV0IGluIGdseXBoLXJlYWR5IGZvcm0sIHlvdSBjYW4gdHJhbnNmb3JtIChpLmUuIHdyYW5nbGUpIHRoZW0gaW50byBnbHlwaC1yZWFkeSBmb3JtLiAgCiAgICAtIFN1Y2ggdHJhbnNmb3JtYXRpb25zIGFyZSBhY2NvbXBsaXNoZWQgYnkgcGVyZm9ybWluZyBvbmUgb3IgbW9yZSBvZiBhIHNtYWxsIHNldCBvZiBiYXNpYyBvcGVyYXRpb25zIG9uIGRhdGEgdGFibGVzCiAgICAtIFRoaXMgaXMgdGhlIHdvcmsgb2YgZGF0YSAidmVyYnMiIAoKCgojIyBHcmFtbWFyIG9mIGdyYXBoaWNzCgotIHRoZSBmcmFtZXdvcmsgdW5kZXJwaW5uaW5nIGBnZ3Bsb3QyYCBpbnRlbmRzIHRvIGltcGxlbWVudCBwcmluaWNpcGxlcyBhbmQgcGhpbG9zb3BoeSBzZXQgaW4gV2lsa29uc29uJ3MgMjAwNSBib29rICpUaGUgR3JhbW1lciBvZiBHcmFwaGljcyAoMm5kIEVkLikqCi0gdXNpbmcgdGlkeSBkYXRhLCBlYWNoICpjYXNlKiBjb3JyZXNwb25kcyB0byBhICpnbHB5aCogb3IgbWFyayBvbiB0aGUgZ3JhcGguCgohW10oZ3JhbW1hckdyYXBoaWNzLnBuZykKCiMjIyMgQW5hdG9teSBvZiBhIGRhdGEgdmlzdWFsaXphdGlvbgoKLSBGcmFtZQotIEdseXBoCi0gQWVzdGhldGljCi0gU2NhbGUKLSBHdWlkZSAobGVnZW5kKQotIEZhY2V0CgoKIyMjIyBTQVQgU2NvcmVzICYgU3R1ZGVudCBTcGVuZGluZyBieSBTdGF0ZSBpbiB0aGUgVVMKCmBgYHtyfQpyZXF1aXJlKG1kc3IpCmRhdGEoIlNBVF8yMDEwIikKCiMgMjAxMCBTQVQgU2NvcmVzIGdyb3VwZWQgYnkgcGFydGljaXBhdGlvbiByYXRlClNBVF8yMDEwIDwtIAogIFNBVF8yMDEwICU+JQogIG11dGF0ZShTQVRfcmF0ZSA9IGN1dChzYXRfcGN0LCBicmVha3MgPSBjKDAsIDMwLCA2MCwgMTAwKSwgCiAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoImxvdyIsICJtZWRpdW0iLCAiaGlnaCIpKSkKCiMgaW5pdGlhbGl6ZSBzY2F0dGVyIHBsb3QKZyA8LSAKICBTQVRfMjAxMCAlPiUKICBnZ3Bsb3QoYWVzKHggPSBleHBlbmRpdHVyZSwgeSA9IG1hdGgpKSArIAogIGdlb21fcG9pbnQoKSArIAogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gMCkgKyAKICB4bGFiKCJBdmVyYWdlIGV4cGVuZGl0dXJlIHBlciBzdHVkZW50ICgkMTAwMCkiKSArIAogIHlsYWIoIkF2ZXJhZ2Ugc2NvcmUgb24gbWF0aCBTQVQiKQoKIyBiYXNlIHBsb3Qgc2hvd2luZyBTQVQgTWF0aCB2cyBTdHVkZW50IGV4cGVuZGl0dXJlCmcKYGBgCgpgYGB7cn0KIyBjb2xvciBzY2F0dGVyIHBsb3QgYnkgU0FUX3JhdGUKZyArIAogIGFlcyhjb2xvciA9IFNBVF9yYXRlKQpgYGAKCiMjIFNvbWUgR3JhcGhpY3MgQ29tcG9uZW50cwoKIyMjIyAqKmdseXBoKioKVGhlIGJhc2ljIGdyYXBoaWNhbCB1bml0IHRoYXQgcmVwcmVzZW50cyBvbmUgY2FzZS4KT3RoZXIgdGVybXMgdXNlZCBpbmNsdWRlICptYXJrKiBhbmQgKnN5bWJvbCouIAoKIyMjIyAqKmFlc3RoZXRpYyoqCgoqIGEgdmlzdWFsIHByb3BlcnR5IG9mIGEgZ2x5cGggc3VjaCBhcyBwb3NpdGlvbiwgc2l6ZSwgc2hhcGUsIGNvbG9yLCBldGMuICAKKiBtYXkgYmUgKiptYXBwZWQqKiBiYXNlZCBvbiBkYXRhIHZhbHVlczogYHNleCAtPiBjb2xvcmAgCiogbWF5IGJlICoqc2V0KiogdG8gcGFydGljdWxhciBub24tZGF0YSByZWxhdGVkIHZhbHVlczogYGNvbG9yIGlzIGJsYWNrYAoKIyMjIyAqKnNjYWxlKioKCiogQSBtYXBwaW5nIHRoYXQgdHJhbnNsYXRlcyBkYXRhIHZhbHVlcyBpbnRvIGFlc3RoZXRpY3MuCiogZXhhbXBsZTogIG1hbGUgLT4gPGZvbnQgY29sb3I9ImJsdWUiPmJsdWU8L2ZvbnQ+OyBmZW1hbGUgLT4gPGZvbnQgY29sb3I9InBpbmsiPnBpbms8L2ZvbnQ+CgojIyMjICoqZnJhbWUqKgoKKiBUaGUgcG9zaXRpb24gc2NhbGUgZGVzY3JpYmluZyBob3cgZGF0YSBhcmUgbWFwcGVkIHRvIHggYW5kIHkKCiMjIyMgKipndWlkZSoqCgoqIEFuIGluZGljYXRpb24gZm9yIHRoZSBodW1hbiB2aWV3ZXIgb2YgdGhlIHNjYWxlLiAgVGhpcyBhbGxvd3MgdGhlIHZpZXdlciB0byB0cmFuc2xhdGUgYWVzdGhldGljcyBiYWNrIGludG8gZGF0YSB2YWx1ZXMuCiogRXhhbXBsZXM6ICB4LSBhbmQgeS1heGVzLCB2YXJpb3VzIHNvcnRzIG9mIGxlZ2VuZHMKCgoKCiMjIEZhY2V0cwoKYGBge3J9CiMgZmFjZXQgYnkgU0FUIHBhcnRpY2lwYXRpb24gcmF0ZQpnICsgCiAgZmFjZXRfd3JhcCggfiBTQVRfcmF0ZSkKYGBgCgoKCiMjIExheWVycyAKCiMjIyMgTWVkaWNhcmUgY29zdHMgaW4gUGVubnN5bHZhbmlhIGFtb25nIG90aGVyIHN0YXRlcwoKYGBge3J9CnJlcXVpcmUobWRzcikKZGF0YSgiTWVkaWNhcmVDaGFyZ2VzIiwgcGFja2FnZSA9ICJtZHNyIikgICAjIGZyb20gbWRzciwgbm90IERhdGFDb21wdXRpbmcKCiMgUGVubnN5bHZhbmlhIG1lZGljYXJlIGNoYXJnZXMKQ2hhcmdlc1BBIDwtIAogIE1lZGljYXJlQ2hhcmdlcyAlPiUKICBmaWx0ZXIoc3RhdGVQcm92aWRlciA9PSAiUEEiKQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9MywgZmlnLndpZHRoPTh9CiMgUGxvdCBQZW5uc3lsdmFuaWEgZGF0YQpwIDwtIAogIENoYXJnZXNQQSAlPiUKICBnZ3Bsb3QoYWVzKHggPSByZW9yZGVyKGRyZywgbWVhbl9jaGFyZ2UpLCB5ID0gbWVhbl9jaGFyZ2UpKSArIAogIGdlb21fYmFyKGZpbGwgPSAiZ3JheSIsIHN0YXQgPSAiaWRlbnRpdHkiKSArICAgIyBzdGF0ID0gImlkZW50aXR5IiA9PT4gdmFsdWUgZGljdGF0ZXMgYmFyIGhlaWdodAogIHlsYWIoIlN0YXRld2lkZSBBdmVyYWdlIENoYXJnZXMgKCQpIikgKyAKICB4bGFiKCJNZWRpY2FsIFByb2NlZHVyZSAoRFJHKSIpICsgCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkKcApgYGAKCgpgYGB7ciBmaWcuaGVpZ2h0PTMsIGZpZy53aWR0aD04fQojIGFkZCBsYXllciB0byBzaG93IG90aGVyIHN0YXRlcyBmb3IgcmVmZXJlbmNlCnAgKyAKICBnZW9tX3BvaW50KGRhdGEgPSBNZWRpY2FyZUNoYXJnZXMsIHNpemUgPSAxLCBhbHBoYSA9IDAuMykKYGBgCgoKIyMgRml2ZXRoaXJ0eWVpZ2h0IHJlcHJvZHVjdGlvbiAoTURTUiBwLiA1MCkKCiFbXShqb3NlcGhzRml2ZXRoaXJ0eWVpZ2h0LnBuZykKCiMjIE1EU1IgUmVwcm9kdWN0aW9uCgpgYGB7cn0KcmVxdWlyZShtZHNyKQpyZXF1aXJlKEhtaXNjKQoKQmFieW5hbWVzRGlzdCA8LSBtYWtlX2JhYnluYW1lc19kaXN0KCkgICMgZnJvbSBtZHNyCgpKb3NlcGggPC0gQmFieW5hbWVzRGlzdCAlPiUKICBmaWx0ZXIobmFtZSA9PSAiSm9zZXBoIiAmIHNleCA9PSAiTSIpCgojIGNvbnN0cnVjdGluZyB0aGUgYmFzZSBwbG90Cm5hbWVfcGxvdCA8LSAKICBKb3NlcGggJT4lCiAgZ2dwbG90KGFlcyh4ID0geWVhcikpICsgCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGFlcyh5ID0gY291bnRfdGhvdXNhbmRzICogYWxpdmVfcHJvYiksIAogICAgICAgICAgIGZpbGwgPSAiI2IyZDdlOSIsIGNvbG9yID0gIndoaXRlIikgKyAKICBnZW9tX2xpbmUoYWVzKHkgPSBjb3VudF90aG91c2FuZHMpLCBzaXplID0gMikgKyAKICB5bGFiKCJOdW1iZXIgb2YgUGVvcGxlICh0aG91c2FuZHMpIikgKyAKICB4bGFiKE5VTEwpCgojIGJhc2UgcGxvdApuYW1lX3Bsb3QKYGBgCgpgYGB7cn0KbWVkaWFuX3lvYiA8LSB3dGQucXVhbnRpbGUoeCA9IEpvc2VwaCR5ZWFyLCB3ZWlnaHRzID0gSm9zZXBoJGVzdF9hbGl2ZV90b2RheSwgcHJvYnMgPSAwLjUpCm1lZGlhbl95b2IKYGBgCgotIG5vdGUgdGhlIGNsZXZlciB1c2Ugb2YgYGlmZWxzZWAgdG8gY3JlYXRlIGEgbmV3IGhpc3RvZ3JhbSB3aXRoIG9uZSBub24temVybyBiYXIgYXQgYG1lZGlhbl95b2JgCi0gYWRkIHRpdGxlcwotIGFkZCB0ZXh0IGxhYmVscyAoaW1wcm92ZSBmb250cykKLSBhZGQgY3VydmVkIGFycm93Ci0gYWRkIGltcHJvdmVtZW50cwogICAgLSBiZXR0ZXIgZm9udHMKICAgIC0gYmV0dGVyIHRpdGxlcwogICAgLSBiZXR0ZXIgZnJhbWUKICAgIC0gZXRjCmBgYHtyfQpuYW1lX3Bsb3QgPC0gCiAgbmFtZV9wbG90ICsgCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGNvbG9yID0gIndoaXRlIiwgZmlsbCA9ICIjMDA4ZmQ1IiwgCiAgICAgICAgICAgYWVzKHkgPSBpZmVsc2UoeWVhciA9PSBtZWRpYW5feW9iLCBlc3RfYWxpdmVfdG9kYXkgLyAxMDAwLCAwKSkpIAoKIyBGaWd1cmUgMy4yMjogSm9zZXBocyAoaW1wcm92ZWQpCm5hbWVfcGxvdCArIAogIGdndGl0bGUobGFiZWwgPSAiQWdlIERpc3RyaWJ1dGlvbiBvZiBBbWVyaWNhbiBCb3lzIE5hbWVkIEpvc2VwaCIsIHN1YnRpdGxlID0gIkJ5IHllYXIgb2YgYmlydGgiKSArIAogIGdlb21fdGV4dCh4ID0gMTkzNSwgeSA9IDQwLCBzaXplID0gMy41LCBmYW1pbHkgPSAibW9ubyIsIGxhYmVsID0gIk51bWJlciBvZiBKb3NlcGhzIFxuIGJvcm4gZWFjaCB5ZWFyIikgKyAKICBnZW9tX3RleHQoeCA9IDE5MTUsIHkgPSAxMywgc2l6ZSA9IDMuNSwgZmFtaWx5ID0gIm1vbm8iLCBjb2xvciA9ICIjMDA4ZmQ1IiwgCiAgICAgICAgICAgIGxhYmVsID0gIk51bWJlciBvZiBKb3NlcGhzIFxuIGJvcm4gZWFjaCB5ZWFyIFxuIGVzdGltYXRlZCB0byBiZSBhbGl2ZSBcbiBvbiBKYW4uIDEsIDIwMTQiKSArIAogIGdlb21fdGV4dCh4ID0gMjAwMywgeSA9IDQwLCBzaXplID0gMy41LCBmYW1pbHkgPSAic2FucyIsIGNvbG9yID0gImRhcmtncmF5IiwKICAgICAgICAgICAgbGFiZWwgPSAiVGhlIG1lZGlhblxubGl2aW5nIEpvc2VwaFxuaXMgMzcgeWVhcnMgb2xkLiIpICsgCiAgZ2VvbV9jdXJ2ZSh4ID0gMTk5NSwgeGVuZCA9IDE5NzQsIHkgPSA0MCwgeWVuZCA9IDI0LCAKICAgICAgICAgICAgIGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgwLjMsICJjbSIpKSwgY3VydmF0dXJlID0gMC41KSArIAogIHlsaW0oMCwgNDIpICsgCiAgdGhlbWVfZml2ZXRoaXJ0eWVpZ2h0KCkKICAKYGBgCgoKCgojIyBUaHJlZSBJbXBvcnRhbnQgQ29uY2VwdHMgCgoxLiBEYXRhIGNhbiBiZSB1c2VmdWxseSBvcmdhbml6ZWQgaW50byB0YWJsZXMgd2l0aCAiY2FzZXMiIGFuZCAidmFyaWFibGVzLiIgIAogICAgLSBJbiAidGlkeSBkYXRhIiBldmVyeSBjYXNlIGlzIHRoZSBzYW1lIHNvcnQgb2YgdGhpbmcgKGUuZy4gYSBwZXJzb24sIGEgY2FyLCBhIHllYXIsIGEgY291bnRyeSBpbiBhIHllYXIpIAogICAgLSBXZSBzb21ldGltZXMgZXZlbiBtb2RpZnkgZGF0YSBpbiBvcmRlciB0byBjaGFuZ2Ugd2hhdCB0aGUgY2FzZXMgcmVwcmVzZW50IGluIG9yZGVyIHRvIGJldHRlciByZXByZXNlbnQgYSBwb2ludC4KCiMuIERhdGEgZ3JhcGhpY3MgYW5kICJnbHlwaC1yZWFkeSIgZGF0YQogICAgLSBlYWNoIGNhc2UgY29ycmVzcG9uZHMgdG8gYSAiZ2x5cGgiIChtYXJrKSBvbiB0aGUgZ3JhcGgKICAgIC0gZWFjaCB2YXJpYWJsZSB0byBhIGdyYXBoaWNhbCBhdHRyaWJ1dGUgb2YgdGhhdCBnbHlwaCBzdWNoIGFzIHgtIG9yIHktcG9zaXRpb24sIGNvbG9yLCBzaXplLCBsZW5ndGgsIHNoYXBlLCBldGMuIAogICAgLSBzYW1lIGlzIHRydWUgZm9yIG1vcmUgdGVjaG5pY2FsIHRvb2xzIChlLmcuLCBtb2RlbHMpIAoKIy4gV2hlbiBkYXRhIGFyZSBub3QgeWV0IGluIGdseXBoLXJlYWR5IGZvcm0sIHlvdSBjYW4gdHJhbnNmb3JtIChpLmUuIHdyYW5nbGUpIHRoZW0gaW50byBnbHlwaC1yZWFkeSBmb3JtLiAgCiAgICAtIFN1Y2ggdHJhbnNmb3JtYXRpb25zIGFyZSBhY2NvbXBsaXNoZWQgYnkgcGVyZm9ybWluZyBvbmUgb3IgbW9yZSBvZiBhIHNtYWxsIHNldCBvZiBiYXNpYyBvcGVyYXRpb25zIG9uIGRhdGEgdGFibGVzCiAgICAtIFRoaXMgaXMgdGhlIHdvcmsgb2YgZGF0YSAidmVyYnMiIAoKCg==