Lab 2: Statistics in R1

Introduction

You may be asking yourselves: why are we going to talk about statistics when studying social media and political participation? The answer is multifaceted:

  1. Some of the assigned readings contain regression outputs
  2. Most scientific papers contain some form of data analysis
  3. Even newspaper articles often present or rely on data
  4. You’re going to have to produce these sort of outputs for this class

The goal of this lecture is to get us working with how to answer questions from data. In general, we will think that we have some relationship of interest between an independent variable (\(x\)) and a dependent variable (\(y\)) which are thought to be bound up in some causal relationship.

\[ x \rightarrow y\]

  1. We want to move from concrete questions to the appropriate data
  2. The primary workhorse we will work up to is linear regression
    • If we change \(x\), what happens to \(y\)?
    • What is the (partial) correlation between these variables?
  3. Confidence and Hypothesis Testing
    • What can we say (and what can we not say) about any found relationship?
  4. Can we go back to the data to find better answers after learning empirical relationships?
  5. Causality: Does \(x\) cause \(y\) or are they only correlated?

A Concrete Example

What is the relationship between the unemployment rate and the % votes for an incumbent? I.e.

\[ \text{Unemployment Rate} \rightarrow \text{% Vote for Incumbent ?} \] A quotation of interest: “No American president since Franklin Delano Roosevelt has won a second term in office when the unemployment rate on Election Day topped 7.2 percent.” Binyamin Appelbaum (NYT) 2011.

So what is the effect of the unemployment rate on incumbent vote share? Do we even need to ask? How might we go about answering?

FIRST we need to establish what data we need to collect to take a first pass at the relationship.

  • Dependent Variable: Incumbent Vote Share
  • Independent Variable: Unemployment Rate

Lucky for us, this data was made easily available by FiveThirtyEight! Let’s load it into our current R environment:

unemp <- read.csv("https://www.dropbox.com/s/k4wq9idqoxa2ha0/unemployment.csv?dl=1")
head(unemp)
##   year incumbent_party incumbent_president  nominee unemployment_rate_start
## 1 1912               R                Taft     Taft                     5.1
## 2 1916               D              Wilson   Wilson                     4.9
## 3 1920               D              Wilson      Cox                     5.2
## 4 1924               R             Harding Coolidge                     8.7
## 5 1928               R            Coolidge   Hoover                     4.9
## 6 1932               R              Hoover   Hoover                     4.6
##   unemployment_rate_election election_margin
## 1                        5.3           -18.6
## 2                        5.6             3.1
## 3                        5.2           -26.2
## 4                        5.8            25.2
## 5                        5.0            17.4
## 6                       18.8           -17.7

Let’s take a look at a scatterplot of the two variables of interest, the unemployment rate at the start of the election versus the election margin:

library(ggplot2)
ggplot(unemp, aes(x=unemployment_rate_election, y=election_margin)) +
  geom_point() +
  ggtitle("Unemployment Rate and Incumbent Vote Margin") +
  xlab("Unemployment (%) at Time of Election") +
  ylab("Margin of Victory or Defeat (%)")

At least visually, there doesn’t appear to be a particularly clear relationship. What if we looked at the change in unemployment instead?

unemp$unemployment_change <- unemp$unemployment_rate_election - unemp$unemployment_rate_start

ggplot(unemp, aes(x = unemployment_change, y = election_margin)) +
  geom_point() +
  ggtitle("Change in Unemployment Rate and Incumbent Vote Margin") +
  xlab("Change in Unemployment (%) at Time of Election vs Start of Term") +
  ylab("Margin of Victory or Defeat (%)")

Obviously neither relationship is particularly clear visually. What can we do to take a more rigorous look?

Linear Regression

Linear regression is the work-horse statistical model within political science and beyond. It essentially models the relationship between a dependent variable and one (or more) independent variables as being linear, i.e. able to be adequately modeled by a straight line. The goal, in other terms, is to find the “best-fitting” line for the data as described by the equation

\[ y = X \beta + \epsilon \]

where \(y\) is the independent variable, \(X\) is the (matrix of) independent variable(s), and \(\beta\) is the (vector of) slop coefficient(s) describing the impact of \(X\) on \(y\), recognizing that there will be some \(\epsilon\) (random) error in the model.

Before going back to the unemployment example, it is useful to think of this in a simulated setting. First, let’s remind ourselves what a perfect linear relationship might look like:

vote_share <- seq(100,0,length=6)
unemp_rate <- seq(0,100,length=6)

ex1 <- data.frame(vote_share,
                 unemp_rate,
                 ex = "ex1")

ggplot(ex1, aes(x=unemp_rate,y=vote_share)) +
  geom_point() +
  geom_line()

Intuitively, the relationship given here takes the form

\[ y = 100 - 1 x \]

where the slope/coefficient value is -1 and the intercept value is 100. We might also imagine some other relationship as follows…

vote_share <- seq(100,0,length=6)
unemp_rate <- seq(0,50,length=6)

ex2 <- data.frame(vote_share,
                 unemp_rate,
                 ex = "ex2")

ex <- rbind(ex1,ex2)

ggplot(ex, aes(x=unemp_rate,y=vote_share, color = ex)) +
  geom_point() +
  geom_line()

where now the (blue) relationship is

\[ y = 100 - 2 x \]

where the slope/coefficient value is -2 and the intercept value is 100. How might these two relationships be interpreted?

Interpretation

A regression coefficient tells us how changing the independent variable \(x\) by one unit changes the dependent variable \(y\). Technically, it is the slope of the best-fitting line that we can draw through all data points where we minimize the sum of squared errors of that regression line.

Here is a bit more of a “realistic” simulated example.

nobs <- 150
x <- rnorm(nobs)
y <- 70 - 1.3*x + rnorm(nobs)

ex <- data.frame(y,x)

ggplot(ex, aes(x=x,y=y)) +
  geom_point()

Here we have a clear negative relationship but, supposing we did not generate the data ourselves, have no immediate knowledge of the function which generated it. What to do? Minimize the sum of squared residuals! You won’t have to do this by hand in the course, but the solution to this minimization problem is of the form

\[ \hat{\beta} = (X'X)^{-1}X'y \]

which can be solved for directly in R:

X <- cbind(1,ex$x)

beta <- solve(t(X) %*% X) %*% t(X) %*% ex$y
beta
##           [,1]
## [1,] 70.020312
## [2,] -1.383377

Not a bad estimate!

ggplot(ex, aes(x=x, y=y)) +
  geom_point() + 
  geom_abline(slope = beta[2,1], intercept = beta[1,1])

We can even verify that these parameters minimize the sum of squared errors fairly easily!

intercepts <- seq(60,80,length=10)
slopes <- seq(0,-2,length=100)

params <- expand.grid(intercepts = intercepts,
                      slopes = slopes)

out <- list()
for(i in 1:nrow(params)){
  betas <- c(params[i,"intercepts"],params[i,"slopes"])
  errs <- y - X %*% betas
  out[[i]] <- sum(errs^2)
}

params$errs <- unlist(out)
params$grp <- "Not Minimum"

params[which.min(params$errs),"grp"] <- "Minumum"

params[which.min(params$errs),]
##     intercepts    slopes     errs     grp
## 676   71.11111 -1.353535 295.1866 Minumum
install.packages("plotly", repos = "http://cran.us.r-project.org")
## 
## The downloaded binary packages are in
##  /var/folders/4n/jrzd6fkx7mn9rgtyb7vz7c4c0000gn/T//RtmpZHtKAm/downloaded_packages
library(plotly)
## Warning: package 'plotly' was built under R version 4.2.3
## 
## Attaching package: 'plotly'
## The following object is masked from 'package:ggplot2':
## 
##     last_plot
## The following object is masked from 'package:stats':
## 
##     filter
## The following object is masked from 'package:graphics':
## 
##     layout
plot_ly(params, x = ~intercepts, y = ~slopes, z= ~errs, color= ~grp, colors = c('#BF382A', '#0C4B8E')) %>% 
  add_markers()

Pretty cool! But what is the relationship between these (slope) coefficients and correlations?

If we standardize the relationship between two variables, we get the linear correlation coefficient:

  • Measures the direction and magnitude of a linear relationship between two variables.
  • Can range between -1 (perfect negative correlation) to 0 (no correlation) to 1 (perfect positive correlation)
  • The magnitude of this number tells us the strength of the relationship, in other words, how tight or how close the data is to the line.
ex$std_x <- ex$x/sd(ex$x)
ex$std_y <- ex$y/sd(ex$y)

lm(std_y ~ std_x, data = ex)
## 
## Call:
## lm(formula = std_y ~ std_x, data = ex)
## 
## Coefficients:
## (Intercept)        std_x  
##     43.2332      -0.8372
cor(ex$std_x,ex$std_y)
## [1] -0.8371839

This seems nice, but herein lies danger! These sort of summary statistics, like correlation coefficients, can be generated from a number of fundamentally different relationships! Take The Datasaurus Dozen as a prime example:

Each of the above images have the exact same basic summary statistics, and so would have the same regression line, but have fundamentally different visual relationships! Here are some additional examples from Wikipedia:

Back to our Example

Now that we have those basics out of the way, what do we learn from the first relationship?

library(ggplot2)
ggplot(unemp, aes(x=unemployment_rate_election, y=election_margin)) +
  geom_point() +
  ggtitle("Unemployment Rate and Incumbent Vote Margin") +
  xlab("Unemployment (%) at Time of Election") +
  ylab("Margin of Victory or Defeat (%)") +
  geom_smooth(method="lm")

What is the direction of the correlation? The magnitude? How close does the data fit the line?

lm(election_margin ~ unemployment_rate_election, data = unemp)
## 
## Call:
## lm(formula = election_margin ~ unemployment_rate_election, data = unemp)
## 
## Coefficients:
##                (Intercept)  unemployment_rate_election  
##                    4.15243                    -0.07257
cor(unemp$election_margin,unemp$unemployment_rate_election)
## [1] -0.02119523

What about for the change in unemployment rate?

unemp$unemployment_change <- unemp$unemployment_rate_election - unemp$unemployment_rate_start

ggplot(unemp, aes(x = unemployment_change, y = election_margin)) +
  geom_point() +
  ggtitle("Change in Unemployment Rate and Incumbent Vote Margin") +
  xlab("Change in Unemployment (%) at Time of Election vs Start of Term") +
  ylab("Margin of Victory or Defeat (%)") +
  geom_smooth(method="lm")
## `geom_smooth()` using formula = 'y ~ x'

lm(election_margin ~ unemployment_change, data = unemp)
## 
## Call:
## lm(formula = election_margin ~ unemployment_change, data = unemp)
## 
## Coefficients:
##         (Intercept)  unemployment_change  
##               3.704               -1.144
cor(unemp$election_margin, unemp$unemployment_change)
## [1] -0.349543

Multiple Regression (and some pitfalls)

So what else could be going on?

  • We may have omitted a relevant independent variable!
    • Cant (easily) plot the relationship…
    • BUT … we can still calculate slope coefficients, correlations, etc

Mathematically, this leads to multiple regression which takes the form

\[ y = \beta_0 + \beta_1 x_1 + \beta_2 x_2 + ... + \beta_n x_n + \epsilon = X \beta + \epsilon \] Now each coefficient shows the effect of a one unit change in \(x\) on \(y\) “irrespective of” or “controlling for” the other variables. Let’s think about this through simulation for a moment…

library(MASS)
nobs <- 100
corm <- matrix(c(1,0.5,0.5,1),nrow=2,byrow=T)

X <- mvrnorm(nobs,rep(0,2),corm)
betas <- c(-1,3)

y <- rnorm(nobs, X %*% betas)

d <- data.frame(y,X)

X <- cbind(1,X)

solve(t(X) %*% X) %*% t(X) %*% y
##              [,1]
## [1,]  0.003932194
## [2,] -0.892947797
## [3,]  2.987222819
lm(y ~ ., data = d)
## 
## Call:
## lm(formula = y ~ ., data = d)
## 
## Coefficients:
## (Intercept)           X1           X2  
##    0.003932    -0.892948     2.987223

Great, we are able to get the correct coefficients! What happens if we don’t include X2?

lm(y ~ X1, data = d)
## 
## Call:
## lm(formula = y ~ X1, data = d)
## 
## Coefficients:
## (Intercept)           X1  
##      0.3046       0.6605

Oh no! That’s terribly wrong, our first pitfall and a great example of omitted variable bias a topic for a different course.

Our second pitfall has to do with the nature of the data itself – with statistical analysis we believe that there is some random noise in our data generating the error term. This has a direct bearing on how confident we are in our estimates! Consider the following example:

set.seed(12345)
nobs <- 1000
x <- rnorm(nobs)

y1 <- rnorm(nobs, x, sd = 1)
y2 <- rnorm(nobs, x, sd = 100)

d <- data.frame(y1,y2,x)
ggplot(d,aes(y=y1,x=x)) + 
  geom_point() +
  geom_smooth(method="lm")
## `geom_smooth()` using formula = 'y ~ x'

summary(lm(y1~x,data=d))
## 
## Call:
## lm(formula = y1 ~ x, data = d)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -3.2315 -0.6975  0.0011  0.7156  3.3577 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept) -0.03220    0.03191  -1.009    0.313    
## x            1.03915    0.03193  32.540   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 1.008 on 998 degrees of freedom
## Multiple R-squared:  0.5148, Adjusted R-squared:  0.5143 
## F-statistic:  1059 on 1 and 998 DF,  p-value: < 2.2e-16
ggplot(d,aes(y=y2,x=x)) + 
  geom_point() +
  geom_smooth(method="lm")
## `geom_smooth()` using formula = 'y ~ x'

summary(lm(y2~x,data=d))
## 
## Call:
## lm(formula = y2 ~ x, data = d)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -311.384  -64.608    1.067   64.018  278.335 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)
## (Intercept)  -2.4982     3.0301  -0.824    0.410
## x            -0.1649     3.0321  -0.054    0.957
## 
## Residual standard error: 95.72 on 998 degrees of freedom
## Multiple R-squared:  2.963e-06,  Adjusted R-squared:  -0.000999 
## F-statistic: 0.002957 on 1 and 998 DF,  p-value: 0.9566

In both, the “true” relationship between X and y is exactly the same except that y is more or less stochastic. In the first analysis, we are able to accurately estimate the target coefficient. In the second, however, the estimated coefficient isn’t even in the correct direction!

This leads us directly to the question of how confident can we be in our results, and how do we access statistical significance etc.

This question is relevant because…

  • We are inherently inferring from a smaller sample to a larger population; there will be sampling error!
  • Another way to think about it…
    • There is some “true” relationship in the world
    • Our evidence is a draw from this “true” relationship
    • If we had enough draws, we’d eventually find the “true” relationship
    • But we can’t make unlimited draws, how confident can we be?

Standard Errors and Hypothesis Testing

The basic solution to this problem comes in the notion of a standard error. This has the basic form:

\[ SE_{est} = \sqrt{\frac{\text{Sum of Squared Residuals}}{(\text{Sample Size - Number of Parameters}) * \sum_i(x_i - \bar{x})^2 }} \]

For the x variable of interest. Consider the last simulated example:

m <- lm(y1 ~ x, data = d)
summary(m)
## 
## Call:
## lm(formula = y1 ~ x, data = d)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -3.2315 -0.6975  0.0011  0.7156  3.3577 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept) -0.03220    0.03191  -1.009    0.313    
## x            1.03915    0.03193  32.540   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 1.008 on 998 degrees of freedom
## Multiple R-squared:  0.5148, Adjusted R-squared:  0.5143 
## F-statistic:  1059 on 1 and 998 DF,  p-value: < 2.2e-16

Let’s calculate the term by hand…

se1 <- sqrt(sum(m$residuals^2)/((nobs - 2)*sum((d$x - mean(d$x))^2)))
se1
## [1] 0.03193485

Excellent! But what does this really represent???

I think that the best way to understand this quantity is by simulating the process we are trying to account for. In particular, we will take 1000 random samples from the above process and calculate the standard error of those coefficient values. This is the standard error we are targeting! First, let’s write a simple function:

set.seed(12345)

one_sim <- function(nobs,beta,sd_e){
  x <- rnorm(nobs)
  y <- rnorm(nobs, beta*x, sd_e)
  
  X <- cbind(1,x)
  
  b <- solve( t(X) %*% X) %*% t(X) %*% y
  
  b[2,1]
}

Now let’s get 1000 coefficient estimates for each of our cases:

out1 <- sapply(1:1000,function(x)one_sim(1000,1,1))
out2 <- sapply(1:1000,function(x)one_sim(1000,1,100))

sims <- data.frame(process1 = out1, process2 = out2)

Here is the sampling distribution of the coefficient for the first process:

ggplot(sims, aes(x = process1)) +
  geom_density()

sd(sims$process1)
## [1] 0.03132773
mean(sims$process1)
## [1] 0.9996647

We see a few things…

  1. The coefficient values are all positive
  2. The coefficients are closely concentrated around the truth
  3. The standard deviation of our simulations is approximately the calculated standard error

Now the second scenario…

ggplot(sims, aes(x = process2)) +
  geom_density()

sd(sims$process2)
## [1] 3.22746
mean(sims$process2)
## [1] 0.7846619

We see a few things…

  1. The coefficient values are NOT all positive; almost half are negative!
  2. The coefficients are NOT closely concentrated around the truth, although they are CENTERED on the truth
  3. The standard deviation of our simulations is approximately the calculated standard error

This leads us directly to our notions of statistical hypothesis testing. Generally speaking, we suppose that if the true value of the coefficient is 0 in the world, what is the chance that my sample data gave me this coefficient value? This is the null hypothesis against which we will compare our results.

Mechanically, this is how it works. First, we take the estimated coefficient value and divide it by it’s standard error. This gives the t-statistic of the effect.

s <- summary(m)
s
## 
## Call:
## lm(formula = y1 ~ x, data = d)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -3.2315 -0.6975  0.0011  0.7156  3.3577 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept) -0.03220    0.03191  -1.009    0.313    
## x            1.03915    0.03193  32.540   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 1.008 on 998 degrees of freedom
## Multiple R-squared:  0.5148, Adjusted R-squared:  0.5143 
## F-statistic:  1059 on 1 and 998 DF,  p-value: < 2.2e-16
t1 <- s$coefficients[,1]/s$coefficients[,2]
t1
## (Intercept)           x 
##   -1.009025   32.539627

Next, we take this t-statistic and ask ourselves “for a t-distribution of mean zero and degrees of freedom equal to our regression degrees of freedom, with what probability would we observe a coefficient value this extreme or more?” If this probability is sufficiently small, we declare a “significant” result. Otherwise we call it a “null” result. Here is what a t-distribution looks like with 998 degrees of freedom:

curve(dt(x,df=nobs-2),from=-4,to=4)

And so because the t-statistic of our first example is massive, the effect is highly significant. For a more illustrative example, consider calculating the p-value of the intercept coefficient entirely by hand (which you won’t have to do, but it’s good to see that it is simple!):

# Calculate Regression Coefficients
coefs <- solve(t(cbind(1,x)) %*% cbind(1,x)) %*% t(cbind(1,x)) %*% y1

# Calculate Sum of Squared Residuals
ssr <- sum((y1 - cbind(1,x) %*% coefs)^2)

# Calculate Standard Errors
ses <- sqrt(ssr/(nobs-2) * diag(solve(t(cbind(1,x)) %*% cbind(1,x))))

# Calculate the t-statistic
t_stat <- coefs/ses

# Calculate the p-values
(1-pt(abs(t_stat), nobs-2)) * 2
##       [,1]
##   0.313207
## x 0.000000

Essentially what we have done is calculated the shaded area of the below curve and found it to be too large to be “significant”:

ggplot(data.frame(x = c(4,-4)),aes(x)) +
  stat_function(fun = dt, args=list(df=nobs-2)) +
  stat_function(fun = dt, args=list(df=nobs-2),
                xlim = c(abs(t_stat)[1],4),
                geom = "area",
                fill = "red") +
  stat_function(fun = dt, args=list(df=nobs-2),
                xlim = c(-abs(t_stat)[1],-4),
                geom = "area",
                fill = "red") +
  theme_bw()

What about for the null effect we found?

m2 <- lm(y2 ~ x, data = d)
s2 <- summary(m2)
s2
## 
## Call:
## lm(formula = y2 ~ x, data = d)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -311.384  -64.608    1.067   64.018  278.335 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)
## (Intercept)  -2.4982     3.0301  -0.824    0.410
## x            -0.1649     3.0321  -0.054    0.957
## 
## Residual standard error: 95.72 on 998 degrees of freedom
## Multiple R-squared:  2.963e-06,  Adjusted R-squared:  -0.000999 
## F-statistic: 0.002957 on 1 and 998 DF,  p-value: 0.9566

First let’s replicate the results by hand…

# Calculate Regression Coefficients
coefs <- solve(t(cbind(1,x)) %*% cbind(1,x)) %*% t(cbind(1,x)) %*% y2

# Calculate Sum of Squared Residuals
ssr <- sum((y2 - cbind(1,x) %*% coefs)^2)

# Calculate Standard Errors
ses <- sqrt(ssr/(nobs-2) * diag(solve(t(cbind(1,x)) %*% cbind(1,x))))

# Calculate the t-statistic
t_stat <- coefs/ses

# Calculate the p-values
(1-pt(abs(t_stat), nobs-2)) * 2
##        [,1]
##   0.4098616
## x 0.9566473

And visualize…

ggplot(data.frame(x = c(4,-4)),aes(x)) +
  stat_function(fun = dt, args=list(df=nobs-2)) +
  stat_function(fun = dt, args=list(df=nobs-2),
                xlim = c(abs(t_stat)[1],4),
                geom = "area",
                fill = "red") +
  stat_function(fun = dt, args=list(df=nobs-2),
                xlim = c(-abs(t_stat)[1],-4),
                geom = "area",
                fill = "red") +
  theme_bw() +
  ggtitle("Null Effect of Model 2 Intercept")

ggplot(data.frame(x = c(4,-4)),aes(x)) +
  stat_function(fun = dt, args=list(df=nobs-2)) +
  stat_function(fun = dt, args=list(df=nobs-2),
                xlim = c(abs(t_stat)[2],4),
                geom = "area",
                fill = "red") +
  stat_function(fun = dt, args=list(df=nobs-2),
                xlim = c(-abs(t_stat)[2],-4),
                geom = "area",
                fill = "red") +
  theme_bw() +
  ggtitle("Null Effect of Model 2 x-variable")

Excellent. As a final thought, let’s think about what exactly these confidence intervals say seeing as there are many misinterpretations. We have taken as tacit, following convention, that we are looking for a 95% confidence interval which – insofar as zero is not within the interval – is interpreted as finding a significant difference at the 5% level.

So what does this actually mean? Perhaps the most straightforward interpretation is the following: were we to re-sample the data and repeat the analysis infinitely many times, the ‘true’ value of the parameter will be captured by confidence intervals constructed in such a way 95% of the time. This is known as the ‘coverage rate’ and is straightforward to demonstrate:

one_sim <- function(nobs,truth){
  
  x <- rnorm(nobs)
  y <- truth*x + rnorm(nobs)
  
  m <- lm(y ~ x)
  interval <- confint(m)[2,]
  
  interval
}

set.seed(1234)
nsims <- 5000
nobs <- 2000
truth <- 1
sims <- lapply(1:nsims,
               function(x)one_sim(nobs,truth))

out <- do.call("rbind",sims)
out <- as.data.frame(out)
names(out) <- c("lower","upper")
out$truth_in_interval <- ifelse(out$lower < truth & out$upper > truth,TRUE,FALSE)

mean(out$truth_in_interval)
## [1] 0.95

Pretty cool!

Exercises

Before we get ahead of ourselves, we want to make sure that you have fundamentals in order. Do the following:

Write a script which…

  1. Downloads the following data:
  2. Run different commands that help you answer the following questions:
    • How many status updates has NYU Abu Dhabi posted on its page?
    • What is the average number of likes and comments that its post receive?
    • What is the maximum number of likes and comments that its posts receive?
    • What was the content of the last status update of 2014?
  3. Download the following data:
  4. Run different commands that help you answer the following questions:
    • What type of post (photo, status, link, video) is the most common on Donald Trump’s Facebook page?
    • Using linear regression, do posts that contain photos receive more likes on average than links?
    • Using linear regression, are more liked posts also more shared?
    • Create a plot that displays the total number of comments on the page each month. Do you notice any trends? Come up with an explanation (and support it with data).

Save and email your working R script to aae322@nyu.edu by the end of the lab session.

Hint! These data are saved as .csv files so you’ll have to read them in with something like the following:

d <- read.csv("https://www.dropbox.com/s/kyzun4zl7c12j5z/lab2_nyu_data.csv?dl=1")

  1. This lab is partially based off of materials provided by Sean Kates, Pablo Barbera, and Drew Dimmery.↩︎

LS0tCnRpdGxlOiAiIgphdXRob3I6ICJDaHJpc3RvcGhlciBTY2h3YXJ6LCBlZGl0cyBieSBBbGlhIEVsS2F0dGFuIgpwYWdlczoKICBleHRyYTogdHJ1ZQpvdXRwdXQ6IAogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogMwogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKYGBgCgojIExhYiAyOiBTdGF0aXN0aWNzIGluIFJeW1RoaXMgbGFiIGlzIHBhcnRpYWxseSBiYXNlZCBvZmYgb2YgbWF0ZXJpYWxzIHByb3ZpZGVkIGJ5IFNlYW4gS2F0ZXMsIFBhYmxvIEJhcmJlcmEsIGFuZCBEcmV3IERpbW1lcnkuXQoKIyMgSW50cm9kdWN0aW9uCgpZb3UgbWF5IGJlIGFza2luZyB5b3Vyc2VsdmVzOiB3aHkgYXJlIHdlIGdvaW5nIHRvIHRhbGsgYWJvdXQgc3RhdGlzdGljcyB3aGVuIHN0dWR5aW5nIHNvY2lhbCBtZWRpYSBhbmQgcG9saXRpY2FsIHBhcnRpY2lwYXRpb24/ICBUaGUgYW5zd2VyIGlzIG11bHRpZmFjZXRlZDoKCjEuIFNvbWUgb2YgdGhlIGFzc2lnbmVkIHJlYWRpbmdzIGNvbnRhaW4gcmVncmVzc2lvbiBvdXRwdXRzCjIuIE1vc3Qgc2NpZW50aWZpYyBwYXBlcnMgY29udGFpbiBzb21lIGZvcm0gb2YgZGF0YSBhbmFseXNpcwozLiBFdmVuIG5ld3NwYXBlciBhcnRpY2xlcyBvZnRlbiBwcmVzZW50IG9yIHJlbHkgb24gZGF0YQo0LiBZb3UncmUgZ29pbmcgdG8gaGF2ZSB0byBwcm9kdWNlIHRoZXNlIHNvcnQgb2Ygb3V0cHV0cyBmb3IgdGhpcyBjbGFzcwoKVGhlIGdvYWwgb2YgdGhpcyBsZWN0dXJlIGlzIHRvIGdldCB1cyB3b3JraW5nIHdpdGggaG93IHRvIGFuc3dlciBxdWVzdGlvbnMgZnJvbSBkYXRhLiAgIEluIGdlbmVyYWwsIHdlIHdpbGwgdGhpbmsgdGhhdCB3ZSBoYXZlIHNvbWUgcmVsYXRpb25zaGlwIG9mIGludGVyZXN0IGJldHdlZW4gYW4gKippbmRlcGVuZGVudCB2YXJpYWJsZSoqICgkeCQpIGFuZCBhICoqZGVwZW5kZW50IHZhcmlhYmxlKiogKCR5JCkgd2hpY2ggYXJlIHRob3VnaHQgdG8gYmUgYm91bmQgdXAgaW4gc29tZSBjYXVzYWwgcmVsYXRpb25zaGlwLgoKJCQgeCBccmlnaHRhcnJvdyB5JCQKCjEuIFdlIHdhbnQgdG8gbW92ZSBmcm9tIGNvbmNyZXRlIHF1ZXN0aW9ucyB0byB0aGUgYXBwcm9wcmlhdGUgZGF0YQoyLiBUaGUgcHJpbWFyeSB3b3JraG9yc2Ugd2Ugd2lsbCB3b3JrIHVwIHRvIGlzICpsaW5lYXIgcmVncmVzc2lvbioKICAgICogSWYgd2UgY2hhbmdlICR4JCwgd2hhdCBoYXBwZW5zIHRvICR5JD8KICAgICogV2hhdCBpcyB0aGUgKHBhcnRpYWwpIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlc2UgdmFyaWFibGVzPwozLiBDb25maWRlbmNlIGFuZCBIeXBvdGhlc2lzIFRlc3RpbmcKICAgICogV2hhdCBjYW4gd2Ugc2F5IChhbmQgd2hhdCBjYW4gd2Ugbm90IHNheSkgYWJvdXQgYW55IGZvdW5kIHJlbGF0aW9uc2hpcD8KNC4gQ2FuIHdlIGdvIGJhY2sgdG8gdGhlIGRhdGEgdG8gZmluZCBiZXR0ZXIgYW5zd2VycyBhZnRlciBsZWFybmluZyBlbXBpcmljYWwgcmVsYXRpb25zaGlwcz8KNS4gQ2F1c2FsaXR5OiBEb2VzICR4JCBjYXVzZSAkeSQgb3IgYXJlIHRoZXkgb25seSBjb3JyZWxhdGVkPwoKCiMjIEEgQ29uY3JldGUgRXhhbXBsZQoKV2hhdCBpcyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIHVuZW1wbG95bWVudCByYXRlIGFuZCB0aGUgJSB2b3RlcyBmb3IgYW4gaW5jdW1iZW50PyAgSS5lLgoKJCQgXHRleHR7VW5lbXBsb3ltZW50IFJhdGV9IFxyaWdodGFycm93IFx0ZXh0eyUgVm90ZSBmb3IgSW5jdW1iZW50ID99ICQkCkEgcXVvdGF0aW9uIG9mIGludGVyZXN0OiAiTm8gQW1lcmljYW4gcHJlc2lkZW50IHNpbmNlIEZyYW5rbGluIERlbGFubyBSb29zZXZlbHQgaGFzIHdvbiBhIHNlY29uZCB0ZXJtIGluIG9mZmljZSB3aGVuIHRoZSB1bmVtcGxveW1lbnQgcmF0ZSBvbiBFbGVjdGlvbiBEYXkgdG9wcGVkIDcuMiBwZXJjZW50LiIgIFtCaW55YW1pbiBBcHBlbGJhdW0gKE5ZVCkgMjAxMV0oaHR0cHM6Ly93d3cubnl0aW1lcy5jb20vMjAxMS8wNi8wMi9idXNpbmVzcy9lY29ub215LzAyam9icy5odG1sKS4KClNvIHdoYXQgaXMgdGhlIGVmZmVjdCBvZiB0aGUgdW5lbXBsb3ltZW50IHJhdGUgb24gaW5jdW1iZW50IHZvdGUgc2hhcmU/ICBEbyB3ZSBldmVuIG5lZWQgdG8gYXNrPyAgSG93IG1pZ2h0IHdlIGdvIGFib3V0IGFuc3dlcmluZz8KCioqRklSU1QqKiB3ZSBuZWVkIHRvIGVzdGFibGlzaCB3aGF0ICpkYXRhKiB3ZSBuZWVkIHRvIGNvbGxlY3QgdG8gdGFrZSBhIGZpcnN0IHBhc3MgYXQgdGhlIHJlbGF0aW9uc2hpcC4KCiogKipEZXBlbmRlbnQgVmFyaWFibGUqKjogSW5jdW1iZW50IFZvdGUgU2hhcmUKKiAqKkluZGVwZW5kZW50IFZhcmlhYmxlKio6IFVuZW1wbG95bWVudCBSYXRlCgpMdWNreSBmb3IgdXMsIHRoaXMgZGF0YSB3YXMgbWFkZSBlYXNpbHkgYXZhaWxhYmxlIGJ5IFtGaXZlVGhpcnR5RWlnaHRdKGh0dHBzOi8vZml2ZXRoaXJ0eWVpZ2h0LmNvbS9mZWF0dXJlcy9vbi10aGUtbWFkZGVuaW5nbHktaW5leGFjdC1yZWxhdGlvbnNoaXAtYmV0d2Vlbi11bmVtcGxveW1lbnQtYW5kLXJlLWVsZWN0aW9uLykhICBMZXQncyBsb2FkIGl0IGludG8gb3VyIGN1cnJlbnQgUiBlbnZpcm9ubWVudDoKCmBgYHtyfQp1bmVtcCA8LSByZWFkLmNzdigiaHR0cHM6Ly93d3cuZHJvcGJveC5jb20vcy9rNHdxOWlkcW94YTJoYTAvdW5lbXBsb3ltZW50LmNzdj9kbD0xIikKaGVhZCh1bmVtcCkKYGBgCkxldCdzIHRha2UgYSBsb29rIGF0IGEgc2NhdHRlcnBsb3Qgb2YgdGhlIHR3byB2YXJpYWJsZXMgb2YgaW50ZXJlc3QsIHRoZSB1bmVtcGxveW1lbnQgcmF0ZSBhdCB0aGUgc3RhcnQgb2YgdGhlIGVsZWN0aW9uIHZlcnN1cyB0aGUgZWxlY3Rpb24gbWFyZ2luOgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeShnZ3Bsb3QyKQpnZ3Bsb3QodW5lbXAsIGFlcyh4PXVuZW1wbG95bWVudF9yYXRlX2VsZWN0aW9uLCB5PWVsZWN0aW9uX21hcmdpbikpICsKICBnZW9tX3BvaW50KCkgKwogIGdndGl0bGUoIlVuZW1wbG95bWVudCBSYXRlIGFuZCBJbmN1bWJlbnQgVm90ZSBNYXJnaW4iKSArCiAgeGxhYigiVW5lbXBsb3ltZW50ICglKSBhdCBUaW1lIG9mIEVsZWN0aW9uIikgKwogIHlsYWIoIk1hcmdpbiBvZiBWaWN0b3J5IG9yIERlZmVhdCAoJSkiKQpgYGAKCkF0IGxlYXN0IHZpc3VhbGx5LCB0aGVyZSBkb2Vzbid0IGFwcGVhciB0byBiZSBhIHBhcnRpY3VsYXJseSBjbGVhciByZWxhdGlvbnNoaXAuICBXaGF0IGlmIHdlIGxvb2tlZCBhdCB0aGUgY2hhbmdlIGluIHVuZW1wbG95bWVudCBpbnN0ZWFkPwoKYGBge3J9CnVuZW1wJHVuZW1wbG95bWVudF9jaGFuZ2UgPC0gdW5lbXAkdW5lbXBsb3ltZW50X3JhdGVfZWxlY3Rpb24gLSB1bmVtcCR1bmVtcGxveW1lbnRfcmF0ZV9zdGFydAoKZ2dwbG90KHVuZW1wLCBhZXMoeCA9IHVuZW1wbG95bWVudF9jaGFuZ2UsIHkgPSBlbGVjdGlvbl9tYXJnaW4pKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZ3RpdGxlKCJDaGFuZ2UgaW4gVW5lbXBsb3ltZW50IFJhdGUgYW5kIEluY3VtYmVudCBWb3RlIE1hcmdpbiIpICsKICB4bGFiKCJDaGFuZ2UgaW4gVW5lbXBsb3ltZW50ICglKSBhdCBUaW1lIG9mIEVsZWN0aW9uIHZzIFN0YXJ0IG9mIFRlcm0iKSArCiAgeWxhYigiTWFyZ2luIG9mIFZpY3Rvcnkgb3IgRGVmZWF0ICglKSIpCmBgYAoKT2J2aW91c2x5IG5laXRoZXIgcmVsYXRpb25zaGlwIGlzIHBhcnRpY3VsYXJseSBjbGVhciB2aXN1YWxseS4gIFdoYXQgY2FuIHdlIGRvIHRvIHRha2UgYSBtb3JlIHJpZ29yb3VzIGxvb2s/CgojIyBMaW5lYXIgUmVncmVzc2lvbgoKTGluZWFyIHJlZ3Jlc3Npb24gaXMgdGhlIHdvcmstaG9yc2Ugc3RhdGlzdGljYWwgbW9kZWwgd2l0aGluIHBvbGl0aWNhbCBzY2llbmNlIGFuZCBiZXlvbmQuIEl0IGVzc2VudGlhbGx5IG1vZGVscyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gYSBkZXBlbmRlbnQgdmFyaWFibGUgYW5kIG9uZSAob3IgbW9yZSkgaW5kZXBlbmRlbnQgdmFyaWFibGVzIGFzIGJlaW5nIGxpbmVhciwgaS5lLiBhYmxlIHRvIGJlIGFkZXF1YXRlbHkgbW9kZWxlZCBieSBhIHN0cmFpZ2h0IGxpbmUuIFRoZSBnb2FsLCBpbiBvdGhlciB0ZXJtcywgaXMgdG8gZmluZCB0aGUgImJlc3QtZml0dGluZyIgbGluZSBmb3IgdGhlIGRhdGEgYXMgZGVzY3JpYmVkIGJ5IHRoZSBlcXVhdGlvbgoKJCQgeSA9IFggXGJldGEgKyBcZXBzaWxvbiAkJAoKd2hlcmUgJHkkIGlzIHRoZSBpbmRlcGVuZGVudCB2YXJpYWJsZSwgJFgkIGlzIHRoZSAobWF0cml4IG9mKSBpbmRlcGVuZGVudCB2YXJpYWJsZShzKSwgYW5kICRcYmV0YSQgaXMgdGhlICh2ZWN0b3Igb2YpIHNsb3AgY29lZmZpY2llbnQocykgZGVzY3JpYmluZyB0aGUgaW1wYWN0IG9mICRYJCBvbiAkeSQsIHJlY29nbml6aW5nIHRoYXQgdGhlcmUgd2lsbCBiZSBzb21lICRcZXBzaWxvbiQgKHJhbmRvbSkgZXJyb3IgaW4gdGhlIG1vZGVsLgoKQmVmb3JlIGdvaW5nIGJhY2sgdG8gdGhlIHVuZW1wbG95bWVudCBleGFtcGxlLCBpdCBpcyB1c2VmdWwgdG8gdGhpbmsgb2YgdGhpcyBpbiBhIHNpbXVsYXRlZCBzZXR0aW5nLiAgRmlyc3QsIGxldCdzIHJlbWluZCBvdXJzZWx2ZXMgd2hhdCBhIHBlcmZlY3QgbGluZWFyIHJlbGF0aW9uc2hpcCBtaWdodCBsb29rIGxpa2U6CgpgYGB7cn0Kdm90ZV9zaGFyZSA8LSBzZXEoMTAwLDAsbGVuZ3RoPTYpCnVuZW1wX3JhdGUgPC0gc2VxKDAsMTAwLGxlbmd0aD02KQoKZXgxIDwtIGRhdGEuZnJhbWUodm90ZV9zaGFyZSwKICAgICAgICAgICAgICAgICB1bmVtcF9yYXRlLAogICAgICAgICAgICAgICAgIGV4ID0gImV4MSIpCgpnZ3Bsb3QoZXgxLCBhZXMoeD11bmVtcF9yYXRlLHk9dm90ZV9zaGFyZSkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fbGluZSgpCgpgYGAKCkludHVpdGl2ZWx5LCB0aGUgcmVsYXRpb25zaGlwIGdpdmVuIGhlcmUgdGFrZXMgdGhlIGZvcm0KCiQkIHkgPSAxMDAgLSAxIHggJCQKCndoZXJlIHRoZSBzbG9wZS9jb2VmZmljaWVudCB2YWx1ZSBpcyAtMSBhbmQgdGhlIGludGVyY2VwdCB2YWx1ZSBpcyAxMDAuICBXZSBtaWdodCBhbHNvIGltYWdpbmUgc29tZSBvdGhlciByZWxhdGlvbnNoaXAgYXMgZm9sbG93cy4uLgoKYGBge3J9CnZvdGVfc2hhcmUgPC0gc2VxKDEwMCwwLGxlbmd0aD02KQp1bmVtcF9yYXRlIDwtIHNlcSgwLDUwLGxlbmd0aD02KQoKZXgyIDwtIGRhdGEuZnJhbWUodm90ZV9zaGFyZSwKICAgICAgICAgICAgICAgICB1bmVtcF9yYXRlLAogICAgICAgICAgICAgICAgIGV4ID0gImV4MiIpCgpleCA8LSByYmluZChleDEsZXgyKQoKZ2dwbG90KGV4LCBhZXMoeD11bmVtcF9yYXRlLHk9dm90ZV9zaGFyZSwgY29sb3IgPSBleCkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fbGluZSgpCgpgYGAKCndoZXJlIG5vdyB0aGUgKGJsdWUpIHJlbGF0aW9uc2hpcCBpcyAKCiQkIHkgPSAxMDAgLSAyIHggJCQKCndoZXJlIHRoZSBzbG9wZS9jb2VmZmljaWVudCB2YWx1ZSBpcyAtMiBhbmQgdGhlIGludGVyY2VwdCB2YWx1ZSBpcyAxMDAuICBIb3cgbWlnaHQgdGhlc2UgdHdvIHJlbGF0aW9uc2hpcHMgYmUgaW50ZXJwcmV0ZWQ/CgojIyMgSW50ZXJwcmV0YXRpb24KCkEgcmVncmVzc2lvbiBjb2VmZmljaWVudCB0ZWxscyB1cyBob3cgY2hhbmdpbmcgdGhlIGluZGVwZW5kZW50IHZhcmlhYmxlICR4JCAqKmJ5IG9uZSB1bml0KiogY2hhbmdlcyB0aGUgZGVwZW5kZW50IHZhcmlhYmxlICR5JC4gIFRlY2huaWNhbGx5LCBpdCBpcyB0aGUgKipzbG9wZSoqIG9mIHRoZSBiZXN0LWZpdHRpbmcgbGluZSB0aGF0IHdlIGNhbiBkcmF3IHRocm91Z2ggYWxsIGRhdGEgcG9pbnRzIHdoZXJlIHdlIG1pbmltaXplIHRoZSAqKnN1bSBvZiBzcXVhcmVkIGVycm9ycyoqIG9mIHRoYXQgcmVncmVzc2lvbiBsaW5lLgoKSGVyZSBpcyBhIGJpdCBtb3JlIG9mIGEgInJlYWxpc3RpYyIgc2ltdWxhdGVkIGV4YW1wbGUuCgpgYGB7cn0Kbm9icyA8LSAxNTAKeCA8LSBybm9ybShub2JzKQp5IDwtIDcwIC0gMS4zKnggKyBybm9ybShub2JzKQoKZXggPC0gZGF0YS5mcmFtZSh5LHgpCgpnZ3Bsb3QoZXgsIGFlcyh4PXgseT15KSkgKwogIGdlb21fcG9pbnQoKQoKYGBgCgpIZXJlIHdlIGhhdmUgYSBjbGVhciBuZWdhdGl2ZSByZWxhdGlvbnNoaXAgYnV0LCBzdXBwb3Npbmcgd2UgZGlkIG5vdCBnZW5lcmF0ZSB0aGUgZGF0YSBvdXJzZWx2ZXMsIGhhdmUgbm8gaW1tZWRpYXRlIGtub3dsZWRnZSBvZiB0aGUgZnVuY3Rpb24gd2hpY2ggZ2VuZXJhdGVkIGl0LiAgV2hhdCB0byBkbz8gIE1pbmltaXplIHRoZSBzdW0gb2Ygc3F1YXJlZCByZXNpZHVhbHMhICBZb3Ugd29uJ3QgaGF2ZSB0byBkbyB0aGlzIGJ5IGhhbmQgaW4gdGhlIGNvdXJzZSwgYnV0IHRoZSBzb2x1dGlvbiB0byB0aGlzIG1pbmltaXphdGlvbiBwcm9ibGVtIGlzIG9mIHRoZSBmb3JtCgokJCBcaGF0e1xiZXRhfSA9IChYJ1gpXnstMX1YJ3kgJCQKCndoaWNoIGNhbiBiZSBzb2x2ZWQgZm9yIGRpcmVjdGx5IGluIFI6CgpgYGB7cn0KClggPC0gY2JpbmQoMSxleCR4KQoKYmV0YSA8LSBzb2x2ZSh0KFgpICUqJSBYKSAlKiUgdChYKSAlKiUgZXgkeQpiZXRhCgpgYGAKTm90IGEgYmFkIGVzdGltYXRlIQoKCmBgYHtyfQpnZ3Bsb3QoZXgsIGFlcyh4PXgsIHk9eSkpICsKICBnZW9tX3BvaW50KCkgKyAKICBnZW9tX2FibGluZShzbG9wZSA9IGJldGFbMiwxXSwgaW50ZXJjZXB0ID0gYmV0YVsxLDFdKQpgYGAKCldlIGNhbiBldmVuIHZlcmlmeSB0aGF0IHRoZXNlIHBhcmFtZXRlcnMgbWluaW1pemUgdGhlIHN1bSBvZiBzcXVhcmVkIGVycm9ycyBmYWlybHkgZWFzaWx5IQoKYGBge3J9CgppbnRlcmNlcHRzIDwtIHNlcSg2MCw4MCxsZW5ndGg9MTApCnNsb3BlcyA8LSBzZXEoMCwtMixsZW5ndGg9MTAwKQoKcGFyYW1zIDwtIGV4cGFuZC5ncmlkKGludGVyY2VwdHMgPSBpbnRlcmNlcHRzLAogICAgICAgICAgICAgICAgICAgICAgc2xvcGVzID0gc2xvcGVzKQoKb3V0IDwtIGxpc3QoKQpmb3IoaSBpbiAxOm5yb3cocGFyYW1zKSl7CiAgYmV0YXMgPC0gYyhwYXJhbXNbaSwiaW50ZXJjZXB0cyJdLHBhcmFtc1tpLCJzbG9wZXMiXSkKICBlcnJzIDwtIHkgLSBYICUqJSBiZXRhcwogIG91dFtbaV1dIDwtIHN1bShlcnJzXjIpCn0KCnBhcmFtcyRlcnJzIDwtIHVubGlzdChvdXQpCnBhcmFtcyRncnAgPC0gIk5vdCBNaW5pbXVtIgoKcGFyYW1zW3doaWNoLm1pbihwYXJhbXMkZXJycyksImdycCJdIDwtICJNaW51bXVtIgoKcGFyYW1zW3doaWNoLm1pbihwYXJhbXMkZXJycyksXQoKYGBgCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQppbnN0YWxsLnBhY2thZ2VzKCJwbG90bHkiLCByZXBvcyA9ICJodHRwOi8vY3Jhbi51cy5yLXByb2plY3Qub3JnIikKYGBgCmBgYHtyfQpsaWJyYXJ5KHBsb3RseSkKCnBsb3RfbHkocGFyYW1zLCB4ID0gfmludGVyY2VwdHMsIHkgPSB+c2xvcGVzLCB6PSB+ZXJycywgY29sb3I9IH5ncnAsIGNvbG9ycyA9IGMoJyNCRjM4MkEnLCAnIzBDNEI4RScpKSAlPiUgCiAgYWRkX21hcmtlcnMoKQpgYGAKClByZXR0eSBjb29sISAgQnV0IHdoYXQgaXMgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZXNlIChzbG9wZSkgY29lZmZpY2llbnRzIGFuZCBjb3JyZWxhdGlvbnM/CgpJZiB3ZSBzdGFuZGFyZGl6ZSB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdHdvIHZhcmlhYmxlcywgd2UgZ2V0IHRoZSBsaW5lYXIgY29ycmVsYXRpb24gY29lZmZpY2llbnQ6CgorIE1lYXN1cmVzIHRoZSBkaXJlY3Rpb24gYW5kIG1hZ25pdHVkZSBvZiBhIGxpbmVhciByZWxhdGlvbnNoaXAgYmV0d2VlbiB0d28gdmFyaWFibGVzLgorIENhbiByYW5nZSBiZXR3ZWVuIC0xIChwZXJmZWN0IG5lZ2F0aXZlIGNvcnJlbGF0aW9uKSB0byAwIChubyBjb3JyZWxhdGlvbikgdG8gMSAocGVyZmVjdCBwb3NpdGl2ZSBjb3JyZWxhdGlvbikKKyBUaGUgbWFnbml0dWRlIG9mIHRoaXMgbnVtYmVyIHRlbGxzIHVzIHRoZSBzdHJlbmd0aCBvZiB0aGUgcmVsYXRpb25zaGlwLCBpbiBvdGhlciB3b3JkcywgaG93IHRpZ2h0IG9yIGhvdyBjbG9zZSB0aGUgZGF0YSBpcyB0byB0aGUgbGluZS4KCmBgYHtyfQpleCRzdGRfeCA8LSBleCR4L3NkKGV4JHgpCmV4JHN0ZF95IDwtIGV4JHkvc2QoZXgkeSkKCmxtKHN0ZF95IH4gc3RkX3gsIGRhdGEgPSBleCkKY29yKGV4JHN0ZF94LGV4JHN0ZF95KQoKYGBgCgpUaGlzIHNlZW1zIG5pY2UsIGJ1dCAqaGVyZWluIGxpZXMgZGFuZ2VyKiEgIFRoZXNlIHNvcnQgb2Ygc3VtbWFyeSBzdGF0aXN0aWNzLCBsaWtlIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50cywgY2FuIGJlIGdlbmVyYXRlZCBmcm9tIGEgbnVtYmVyIG9mIGZ1bmRhbWVudGFsbHkgZGlmZmVyZW50IHJlbGF0aW9uc2hpcHMhICBUYWtlIFtUaGUgRGF0YXNhdXJ1cyBEb3plbl0oaHR0cHM6Ly93d3cuYXV0b2Rlc2suY29tL3Jlc2VhcmNoL3B1YmxpY2F0aW9ucy9zYW1lLXN0YXRzLWRpZmZlcmVudC1ncmFwaHMpIGFzIGEgcHJpbWUgZXhhbXBsZToKCmBgYHtyLCBlY2hvPUZBTFNFfQp1cmwxIDwtICJodHRwczovL2RhbWFzc2V0cy5hdXRvZGVzay5uZXQvY29udGVudC9kYW0vYXV0b2Rlc2svcmVzZWFyY2gvcHVibGljYXRpb25zLWFzc2V0cy9pbWFnZXMvQWxsRGlub3NHcmV5XzEucG5nIgoKdXJsMiA8LSAiaHR0cHM6Ly91cGxvYWQud2lraW1lZGlhLm9yZy93aWtpcGVkaWEvY29tbW9ucy90aHVtYi9kL2Q0L0NvcnJlbGF0aW9uX2V4YW1wbGVzMi5zdmcvMTkyMHB4LUNvcnJlbGF0aW9uX2V4YW1wbGVzMi5zdmcucG5nIgoKdXJsMyA8LSAiaHR0cHM6Ly93d3cuZHJvcGJveC5jb20vcy81Z2FhbHlteGp6Y3B6NXAvbW9kZWx6ei5QTkc/ZGw9MSIKYGBgCgohW10oYHIgdXJsMWApCgpFYWNoIG9mIHRoZSBhYm92ZSBpbWFnZXMgaGF2ZSB0aGUgKmV4YWN0IHNhbWUqIGJhc2ljIHN1bW1hcnkgc3RhdGlzdGljcywgYW5kIHNvIHdvdWxkIGhhdmUgdGhlIHNhbWUgcmVncmVzc2lvbiBsaW5lLCBidXQgaGF2ZSBmdW5kYW1lbnRhbGx5IGRpZmZlcmVudCB2aXN1YWwgcmVsYXRpb25zaGlwcyEgIEhlcmUgYXJlIHNvbWUgYWRkaXRpb25hbCBleGFtcGxlcyBmcm9tIFtXaWtpcGVkaWFdKGh0dHBzOi8vdXBsb2FkLndpa2ltZWRpYS5vcmcvd2lraXBlZGlhL2NvbW1vbnMvdGh1bWIvZC9kNC9Db3JyZWxhdGlvbl9leGFtcGxlczIuc3ZnLzE5MjBweC1Db3JyZWxhdGlvbl9leGFtcGxlczIuc3ZnLnBuZyk6CgohW10oaHR0cHM6Ly91cGxvYWQud2lraW1lZGlhLm9yZy93aWtpcGVkaWEvY29tbW9ucy90aHVtYi9kL2Q0L0NvcnJlbGF0aW9uX2V4YW1wbGVzMi5zdmcvMTkyMHB4LUNvcnJlbGF0aW9uX2V4YW1wbGVzMi5zdmcucG5nKQoKIyMjIEJhY2sgdG8gb3VyIEV4YW1wbGUKCk5vdyB0aGF0IHdlIGhhdmUgdGhvc2UgYmFzaWNzIG91dCBvZiB0aGUgd2F5LCB3aGF0IGRvIHdlIGxlYXJuIGZyb20gdGhlIGZpcnN0IHJlbGF0aW9uc2hpcD8KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkoZ2dwbG90MikKZ2dwbG90KHVuZW1wLCBhZXMoeD11bmVtcGxveW1lbnRfcmF0ZV9lbGVjdGlvbiwgeT1lbGVjdGlvbl9tYXJnaW4pKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZ3RpdGxlKCJVbmVtcGxveW1lbnQgUmF0ZSBhbmQgSW5jdW1iZW50IFZvdGUgTWFyZ2luIikgKwogIHhsYWIoIlVuZW1wbG95bWVudCAoJSkgYXQgVGltZSBvZiBFbGVjdGlvbiIpICsKICB5bGFiKCJNYXJnaW4gb2YgVmljdG9yeSBvciBEZWZlYXQgKCUpIikgKwogIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKQpgYGAKCldoYXQgaXMgdGhlIGRpcmVjdGlvbiBvZiB0aGUgY29ycmVsYXRpb24/ICBUaGUgbWFnbml0dWRlPyAgSG93IGNsb3NlIGRvZXMgdGhlIGRhdGEgZml0IHRoZSBsaW5lPwoKYGBge3J9CmxtKGVsZWN0aW9uX21hcmdpbiB+IHVuZW1wbG95bWVudF9yYXRlX2VsZWN0aW9uLCBkYXRhID0gdW5lbXApCmNvcih1bmVtcCRlbGVjdGlvbl9tYXJnaW4sdW5lbXAkdW5lbXBsb3ltZW50X3JhdGVfZWxlY3Rpb24pCmBgYAoKV2hhdCBhYm91dCBmb3IgdGhlIGNoYW5nZSBpbiB1bmVtcGxveW1lbnQgcmF0ZT8KCmBgYHtyfQp1bmVtcCR1bmVtcGxveW1lbnRfY2hhbmdlIDwtIHVuZW1wJHVuZW1wbG95bWVudF9yYXRlX2VsZWN0aW9uIC0gdW5lbXAkdW5lbXBsb3ltZW50X3JhdGVfc3RhcnQKCmdncGxvdCh1bmVtcCwgYWVzKHggPSB1bmVtcGxveW1lbnRfY2hhbmdlLCB5ID0gZWxlY3Rpb25fbWFyZ2luKSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2d0aXRsZSgiQ2hhbmdlIGluIFVuZW1wbG95bWVudCBSYXRlIGFuZCBJbmN1bWJlbnQgVm90ZSBNYXJnaW4iKSArCiAgeGxhYigiQ2hhbmdlIGluIFVuZW1wbG95bWVudCAoJSkgYXQgVGltZSBvZiBFbGVjdGlvbiB2cyBTdGFydCBvZiBUZXJtIikgKwogIHlsYWIoIk1hcmdpbiBvZiBWaWN0b3J5IG9yIERlZmVhdCAoJSkiKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIpCmBgYAoKYGBge3J9CmxtKGVsZWN0aW9uX21hcmdpbiB+IHVuZW1wbG95bWVudF9jaGFuZ2UsIGRhdGEgPSB1bmVtcCkKY29yKHVuZW1wJGVsZWN0aW9uX21hcmdpbiwgdW5lbXAkdW5lbXBsb3ltZW50X2NoYW5nZSkKYGBgCgojIyMgTXVsdGlwbGUgUmVncmVzc2lvbiAoYW5kIHNvbWUgcGl0ZmFsbHMpCgpTbyB3aGF0IGVsc2UgY291bGQgYmUgZ29pbmcgb24/CgorIFdlIG1heSBoYXZlIG9taXR0ZWQgYSByZWxldmFudCBpbmRlcGVuZGVudCB2YXJpYWJsZSEKICAgICsgQ2FudCAoZWFzaWx5KSBwbG90IHRoZSByZWxhdGlvbnNoaXAuLi4KICAgICsgQlVUIC4uLiB3ZSBjYW4gc3RpbGwgY2FsY3VsYXRlIHNsb3BlIGNvZWZmaWNpZW50cywgY29ycmVsYXRpb25zLCBldGMKICAgIApNYXRoZW1hdGljYWxseSwgdGhpcyBsZWFkcyB0byAqKm11bHRpcGxlIHJlZ3Jlc3Npb24qKiB3aGljaCB0YWtlcyB0aGUgZm9ybQoKJCQgeSA9IFxiZXRhXzAgKyBcYmV0YV8xIHhfMSArIFxiZXRhXzIgeF8yICsgLi4uICsgXGJldGFfbiB4X24gKyBcZXBzaWxvbiA9IFggXGJldGEgKyBcZXBzaWxvbiAkJApOb3cgZWFjaCBjb2VmZmljaWVudCBzaG93cyB0aGUgZWZmZWN0IG9mIGEgb25lIHVuaXQgY2hhbmdlIGluICR4JCBvbiAkeSQgImlycmVzcGVjdGl2ZSBvZiIgb3IgImNvbnRyb2xsaW5nIGZvciIgdGhlIG90aGVyIHZhcmlhYmxlcy4gIExldCdzIHRoaW5rIGFib3V0IHRoaXMgdGhyb3VnaCBzaW11bGF0aW9uIGZvciBhIG1vbWVudC4uLgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeShNQVNTKQpub2JzIDwtIDEwMApjb3JtIDwtIG1hdHJpeChjKDEsMC41LDAuNSwxKSxucm93PTIsYnlyb3c9VCkKClggPC0gbXZybm9ybShub2JzLHJlcCgwLDIpLGNvcm0pCmJldGFzIDwtIGMoLTEsMykKCnkgPC0gcm5vcm0obm9icywgWCAlKiUgYmV0YXMpCgpkIDwtIGRhdGEuZnJhbWUoeSxYKQoKWCA8LSBjYmluZCgxLFgpCgpzb2x2ZSh0KFgpICUqJSBYKSAlKiUgdChYKSAlKiUgeQoKbG0oeSB+IC4sIGRhdGEgPSBkKQoKYGBgCgpHcmVhdCwgd2UgYXJlIGFibGUgdG8gZ2V0IHRoZSBjb3JyZWN0IGNvZWZmaWNpZW50cyEgIFdoYXQgaGFwcGVucyBpZiB3ZSBkb24ndCBpbmNsdWRlIFgyPwoKYGBge3J9CmxtKHkgfiBYMSwgZGF0YSA9IGQpCmBgYApPaCBubyEgIFRoYXQncyB0ZXJyaWJseSB3cm9uZywgb3VyICoqZmlyc3QgcGl0ZmFsbCoqIGFuZCBhIGdyZWF0IGV4YW1wbGUgb2YgKipvbWl0dGVkIHZhcmlhYmxlIGJpYXMqKiBhIHRvcGljIGZvciBhIGRpZmZlcmVudCBjb3Vyc2UuICAKCgpPdXIgKipzZWNvbmQgcGl0ZmFsbCoqIGhhcyB0byBkbyB3aXRoIHRoZSBuYXR1cmUgb2YgdGhlIGRhdGEgaXRzZWxmIC0tIHdpdGggc3RhdGlzdGljYWwgYW5hbHlzaXMgd2UgYmVsaWV2ZSB0aGF0IHRoZXJlIGlzIHNvbWUgcmFuZG9tIG5vaXNlIGluIG91ciBkYXRhIGdlbmVyYXRpbmcgdGhlIGVycm9yIHRlcm0uICBUaGlzIGhhcyBhIGRpcmVjdCBiZWFyaW5nIG9uIGhvdyBjb25maWRlbnQgd2UgYXJlIGluIG91ciBlc3RpbWF0ZXMhICBDb25zaWRlciB0aGUgZm9sbG93aW5nIGV4YW1wbGU6CgoKYGBge3J9CnNldC5zZWVkKDEyMzQ1KQpub2JzIDwtIDEwMDAKeCA8LSBybm9ybShub2JzKQoKeTEgPC0gcm5vcm0obm9icywgeCwgc2QgPSAxKQp5MiA8LSBybm9ybShub2JzLCB4LCBzZCA9IDEwMCkKCmQgPC0gZGF0YS5mcmFtZSh5MSx5Mix4KQpgYGAKCmBgYHtyfQpnZ3Bsb3QoZCxhZXMoeT15MSx4PXgpKSArIAogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIpCgpzdW1tYXJ5KGxtKHkxfngsZGF0YT1kKSkKYGBgCgpgYGB7cn0KZ2dwbG90KGQsYWVzKHk9eTIseD14KSkgKyAKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKQoKc3VtbWFyeShsbSh5Mn54LGRhdGE9ZCkpCmBgYApJbiBib3RoLCB0aGUgInRydWUiIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIFggYW5kIHkgaXMgZXhhY3RseSB0aGUgc2FtZSBleGNlcHQgdGhhdCB5IGlzIG1vcmUgb3IgbGVzcyBzdG9jaGFzdGljLiAgSW4gdGhlIGZpcnN0IGFuYWx5c2lzLCB3ZSBhcmUgYWJsZSB0byBhY2N1cmF0ZWx5IGVzdGltYXRlIHRoZSB0YXJnZXQgY29lZmZpY2llbnQuICBJbiB0aGUgc2Vjb25kLCBob3dldmVyLCB0aGUgZXN0aW1hdGVkIGNvZWZmaWNpZW50IGlzbid0IGV2ZW4gaW4gdGhlIGNvcnJlY3QgZGlyZWN0aW9uIQoKVGhpcyBsZWFkcyB1cyBkaXJlY3RseSB0byB0aGUgcXVlc3Rpb24gb2YgKipob3cgY29uZmlkZW50IGNhbiB3ZSBiZSoqIGluIG91ciByZXN1bHRzLCBhbmQgaG93IGRvIHdlIGFjY2VzcyBzdGF0aXN0aWNhbCBzaWduaWZpY2FuY2UgZXRjLgoKVGhpcyBxdWVzdGlvbiBpcyByZWxldmFudCBiZWNhdXNlLi4uCgorIFdlIGFyZSBpbmhlcmVudGx5IGluZmVycmluZyBmcm9tIGEgc21hbGxlciBzYW1wbGUgdG8gYSBsYXJnZXIgcG9wdWxhdGlvbjsgdGhlcmUgd2lsbCBiZSBzYW1wbGluZyBlcnJvciEKKyBBbm90aGVyIHdheSB0byB0aGluayBhYm91dCBpdC4uLgogICAgKyBUaGVyZSBpcyBzb21lICJ0cnVlIiByZWxhdGlvbnNoaXAgaW4gdGhlIHdvcmxkCiAgICArIE91ciBldmlkZW5jZSBpcyBhIGRyYXcgZnJvbSB0aGlzICJ0cnVlIiByZWxhdGlvbnNoaXAKICAgICsgSWYgd2UgaGFkIGVub3VnaCBkcmF3cywgd2UnZCBldmVudHVhbGx5IGZpbmQgdGhlICJ0cnVlIiByZWxhdGlvbnNoaXAKICAgICsgQnV0IHdlIGNhbid0IG1ha2UgdW5saW1pdGVkIGRyYXdzLCBob3cgY29uZmlkZW50IGNhbiB3ZSBiZT8KICAgIAojIyMgU3RhbmRhcmQgRXJyb3JzIGFuZCBIeXBvdGhlc2lzIFRlc3RpbmcKClRoZSBiYXNpYyBzb2x1dGlvbiB0byB0aGlzIHByb2JsZW0gY29tZXMgaW4gdGhlIG5vdGlvbiBvZiBhICoqc3RhbmRhcmQgZXJyb3IqKi4gIFRoaXMgaGFzIHRoZSBiYXNpYyBmb3JtOgoKJCQgU0Vfe2VzdH0gPSBcc3FydHtcZnJhY3tcdGV4dHtTdW0gb2YgU3F1YXJlZCBSZXNpZHVhbHN9fXsoXHRleHR7U2FtcGxlIFNpemUgLSBOdW1iZXIgb2YgUGFyYW1ldGVyc30pICogXHN1bV9pKHhfaSAtIFxiYXJ7eH0pXjIgfX0gJCQKCkZvciB0aGUgeCB2YXJpYWJsZSBvZiBpbnRlcmVzdC4gIENvbnNpZGVyIHRoZSBsYXN0IHNpbXVsYXRlZCBleGFtcGxlOgoKYGBge3J9Cm0gPC0gbG0oeTEgfiB4LCBkYXRhID0gZCkKc3VtbWFyeShtKQpgYGAKTGV0J3MgY2FsY3VsYXRlIHRoZSB0ZXJtIGJ5IGhhbmQuLi4KCmBgYHtyfQpzZTEgPC0gc3FydChzdW0obSRyZXNpZHVhbHNeMikvKChub2JzIC0gMikqc3VtKChkJHggLSBtZWFuKGQkeCkpXjIpKSkKc2UxCmBgYAoKRXhjZWxsZW50ISAgKipCdXQgd2hhdCBkb2VzIHRoaXMgcmVhbGx5IHJlcHJlc2VudD8/PyoqCgpJIHRoaW5rIHRoYXQgdGhlIGJlc3Qgd2F5IHRvIHVuZGVyc3RhbmQgdGhpcyBxdWFudGl0eSBpcyBieSBzaW11bGF0aW5nIHRoZSBwcm9jZXNzIHdlIGFyZSB0cnlpbmcgdG8gYWNjb3VudCBmb3IuICBJbiBwYXJ0aWN1bGFyLCB3ZSB3aWxsIHRha2UgMTAwMCByYW5kb20gc2FtcGxlcyBmcm9tIHRoZSBhYm92ZSBwcm9jZXNzIGFuZCBjYWxjdWxhdGUgdGhlIHN0YW5kYXJkIGVycm9yIG9mIHRob3NlIGNvZWZmaWNpZW50IHZhbHVlcy4gIFRoaXMgaXMgdGhlIHN0YW5kYXJkIGVycm9yIHdlIGFyZSB0YXJnZXRpbmchICBGaXJzdCwgbGV0J3Mgd3JpdGUgYSBzaW1wbGUgZnVuY3Rpb246CgpgYGB7cn0Kc2V0LnNlZWQoMTIzNDUpCgpvbmVfc2ltIDwtIGZ1bmN0aW9uKG5vYnMsYmV0YSxzZF9lKXsKICB4IDwtIHJub3JtKG5vYnMpCiAgeSA8LSBybm9ybShub2JzLCBiZXRhKngsIHNkX2UpCiAgCiAgWCA8LSBjYmluZCgxLHgpCiAgCiAgYiA8LSBzb2x2ZSggdChYKSAlKiUgWCkgJSolIHQoWCkgJSolIHkKICAKICBiWzIsMV0KfQoKYGBgCgpOb3cgbGV0J3MgZ2V0IDEwMDAgY29lZmZpY2llbnQgZXN0aW1hdGVzIGZvciBlYWNoIG9mIG91ciBjYXNlczoKCmBgYHtyfQoKb3V0MSA8LSBzYXBwbHkoMToxMDAwLGZ1bmN0aW9uKHgpb25lX3NpbSgxMDAwLDEsMSkpCm91dDIgPC0gc2FwcGx5KDE6MTAwMCxmdW5jdGlvbih4KW9uZV9zaW0oMTAwMCwxLDEwMCkpCgpzaW1zIDwtIGRhdGEuZnJhbWUocHJvY2VzczEgPSBvdXQxLCBwcm9jZXNzMiA9IG91dDIpCgpgYGAKCkhlcmUgaXMgdGhlICoqc2FtcGxpbmcgZGlzdHJpYnV0aW9uIG9mIHRoZSBjb2VmZmljaWVudCoqIGZvciB0aGUgZmlyc3QgcHJvY2VzczoKCmBgYHtyfQoKZ2dwbG90KHNpbXMsIGFlcyh4ID0gcHJvY2VzczEpKSArCiAgZ2VvbV9kZW5zaXR5KCkKCnNkKHNpbXMkcHJvY2VzczEpCm1lYW4oc2ltcyRwcm9jZXNzMSkKCmBgYAoKV2Ugc2VlIGEgZmV3IHRoaW5ncy4uLgoKMS4gVGhlIGNvZWZmaWNpZW50IHZhbHVlcyBhcmUgYWxsIHBvc2l0aXZlCjIuIFRoZSBjb2VmZmljaWVudHMgYXJlIGNsb3NlbHkgY29uY2VudHJhdGVkIGFyb3VuZCB0aGUgdHJ1dGgKMy4gVGhlIHN0YW5kYXJkIGRldmlhdGlvbiBvZiBvdXIgc2ltdWxhdGlvbnMgaXMgYXBwcm94aW1hdGVseSB0aGUgY2FsY3VsYXRlZCBzdGFuZGFyZCBlcnJvcgoKTm93IHRoZSBzZWNvbmQgc2NlbmFyaW8uLi4KCmBgYHtyfQoKZ2dwbG90KHNpbXMsIGFlcyh4ID0gcHJvY2VzczIpKSArCiAgZ2VvbV9kZW5zaXR5KCkKCnNkKHNpbXMkcHJvY2VzczIpCm1lYW4oc2ltcyRwcm9jZXNzMikKCmBgYAoKV2Ugc2VlIGEgZmV3IHRoaW5ncy4uLgoKMS4gVGhlIGNvZWZmaWNpZW50IHZhbHVlcyBhcmUgTk9UIGFsbCBwb3NpdGl2ZTsgYWxtb3N0IGhhbGYgYXJlIG5lZ2F0aXZlIQoyLiBUaGUgY29lZmZpY2llbnRzIGFyZSBOT1QgY2xvc2VseSBjb25jZW50cmF0ZWQgYXJvdW5kIHRoZSB0cnV0aCwgYWx0aG91Z2ggdGhleSBhcmUgQ0VOVEVSRUQgb24gdGhlIHRydXRoCjMuIFRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2Ygb3VyIHNpbXVsYXRpb25zIGlzIGFwcHJveGltYXRlbHkgdGhlIGNhbGN1bGF0ZWQgc3RhbmRhcmQgZXJyb3IKClRoaXMgbGVhZHMgdXMgZGlyZWN0bHkgdG8gb3VyIG5vdGlvbnMgb2YgKipzdGF0aXN0aWNhbCBoeXBvdGhlc2lzIHRlc3RpbmcqKi4gIEdlbmVyYWxseSBzcGVha2luZywgd2Ugc3VwcG9zZSB0aGF0ICppZiB0aGUgdHJ1ZSB2YWx1ZSBvZiB0aGUgY29lZmZpY2llbnQgaXMgMCBpbiB0aGUgd29ybGQsIHdoYXQgaXMgdGhlIGNoYW5jZSB0aGF0IG15IHNhbXBsZSBkYXRhIGdhdmUgbWUgdGhpcyBjb2VmZmljaWVudCB2YWx1ZT8qICBUaGlzIGlzIHRoZSAqKm51bGwgaHlwb3RoZXNpcyoqIGFnYWluc3Qgd2hpY2ggd2Ugd2lsbCBjb21wYXJlIG91ciByZXN1bHRzLgoKTWVjaGFuaWNhbGx5LCB0aGlzIGlzIGhvdyBpdCB3b3Jrcy4gIEZpcnN0LCB3ZSB0YWtlIHRoZSBlc3RpbWF0ZWQgY29lZmZpY2llbnQgdmFsdWUgYW5kIGRpdmlkZSBpdCBieSBpdCdzIHN0YW5kYXJkIGVycm9yLiAgVGhpcyBnaXZlcyB0aGUgKnQtc3RhdGlzdGljKiBvZiB0aGUgZWZmZWN0LgoKYGBge3J9CnMgPC0gc3VtbWFyeShtKQpzCmBgYApgYGB7cn0KdDEgPC0gcyRjb2VmZmljaWVudHNbLDFdL3MkY29lZmZpY2llbnRzWywyXQp0MQpgYGAKCk5leHQsIHdlIHRha2UgdGhpcyB0LXN0YXRpc3RpYyBhbmQgYXNrIG91cnNlbHZlcyAiZm9yIGEgdC1kaXN0cmlidXRpb24gb2YgbWVhbiB6ZXJvIGFuZCBkZWdyZWVzIG9mIGZyZWVkb20gZXF1YWwgdG8gb3VyIHJlZ3Jlc3Npb24gZGVncmVlcyBvZiBmcmVlZG9tLCB3aXRoIHdoYXQgcHJvYmFiaWxpdHkgd291bGQgd2Ugb2JzZXJ2ZSBhIGNvZWZmaWNpZW50IHZhbHVlIHRoaXMgZXh0cmVtZSBvciBtb3JlPyIgIElmIHRoaXMgcHJvYmFiaWxpdHkgaXMgc3VmZmljaWVudGx5IHNtYWxsLCB3ZSBkZWNsYXJlIGEgInNpZ25pZmljYW50IiByZXN1bHQuICBPdGhlcndpc2Ugd2UgY2FsbCBpdCBhICJudWxsIiByZXN1bHQuICBIZXJlIGlzIHdoYXQgYSB0LWRpc3RyaWJ1dGlvbiBsb29rcyBsaWtlIHdpdGggOTk4IGRlZ3JlZXMgb2YgZnJlZWRvbToKCmBgYHtyfQpjdXJ2ZShkdCh4LGRmPW5vYnMtMiksZnJvbT0tNCx0bz00KQpgYGAKCgpBbmQgc28gYmVjYXVzZSB0aGUgdC1zdGF0aXN0aWMgb2Ygb3VyIGZpcnN0IGV4YW1wbGUgaXMgbWFzc2l2ZSwgdGhlIGVmZmVjdCBpcyBoaWdobHkgc2lnbmlmaWNhbnQuICBGb3IgYSBtb3JlIGlsbHVzdHJhdGl2ZSBleGFtcGxlLCBjb25zaWRlciBjYWxjdWxhdGluZyB0aGUgcC12YWx1ZSBvZiB0aGUgaW50ZXJjZXB0IGNvZWZmaWNpZW50IGVudGlyZWx5IGJ5IGhhbmQgKHdoaWNoIHlvdSB3b24ndCBoYXZlIHRvIGRvLCBidXQgaXQncyBnb29kIHRvIHNlZSB0aGF0IGl0IGlzIHNpbXBsZSEpOiAgCgpgYGB7cn0KIyBDYWxjdWxhdGUgUmVncmVzc2lvbiBDb2VmZmljaWVudHMKY29lZnMgPC0gc29sdmUodChjYmluZCgxLHgpKSAlKiUgY2JpbmQoMSx4KSkgJSolIHQoY2JpbmQoMSx4KSkgJSolIHkxCgojIENhbGN1bGF0ZSBTdW0gb2YgU3F1YXJlZCBSZXNpZHVhbHMKc3NyIDwtIHN1bSgoeTEgLSBjYmluZCgxLHgpICUqJSBjb2VmcyleMikKCiMgQ2FsY3VsYXRlIFN0YW5kYXJkIEVycm9ycwpzZXMgPC0gc3FydChzc3IvKG5vYnMtMikgKiBkaWFnKHNvbHZlKHQoY2JpbmQoMSx4KSkgJSolIGNiaW5kKDEseCkpKSkKCiMgQ2FsY3VsYXRlIHRoZSB0LXN0YXRpc3RpYwp0X3N0YXQgPC0gY29lZnMvc2VzCgojIENhbGN1bGF0ZSB0aGUgcC12YWx1ZXMKKDEtcHQoYWJzKHRfc3RhdCksIG5vYnMtMikpICogMgpgYGAKCkVzc2VudGlhbGx5IHdoYXQgd2UgaGF2ZSBkb25lIGlzIGNhbGN1bGF0ZWQgdGhlIHNoYWRlZCBhcmVhIG9mIHRoZSBiZWxvdyBjdXJ2ZSBhbmQgZm91bmQgaXQgdG8gYmUgdG9vIGxhcmdlIHRvIGJlICJzaWduaWZpY2FudCI6CgpgYGB7cn0KCmdncGxvdChkYXRhLmZyYW1lKHggPSBjKDQsLTQpKSxhZXMoeCkpICsKICBzdGF0X2Z1bmN0aW9uKGZ1biA9IGR0LCBhcmdzPWxpc3QoZGY9bm9icy0yKSkgKwogIHN0YXRfZnVuY3Rpb24oZnVuID0gZHQsIGFyZ3M9bGlzdChkZj1ub2JzLTIpLAogICAgICAgICAgICAgICAgeGxpbSA9IGMoYWJzKHRfc3RhdClbMV0sNCksCiAgICAgICAgICAgICAgICBnZW9tID0gImFyZWEiLAogICAgICAgICAgICAgICAgZmlsbCA9ICJyZWQiKSArCiAgc3RhdF9mdW5jdGlvbihmdW4gPSBkdCwgYXJncz1saXN0KGRmPW5vYnMtMiksCiAgICAgICAgICAgICAgICB4bGltID0gYygtYWJzKHRfc3RhdClbMV0sLTQpLAogICAgICAgICAgICAgICAgZ2VvbSA9ICJhcmVhIiwKICAgICAgICAgICAgICAgIGZpbGwgPSAicmVkIikgKwogIHRoZW1lX2J3KCkKCmBgYAoKV2hhdCBhYm91dCBmb3IgdGhlIG51bGwgZWZmZWN0IHdlIGZvdW5kPwoKYGBge3J9Cm0yIDwtIGxtKHkyIH4geCwgZGF0YSA9IGQpCnMyIDwtIHN1bW1hcnkobTIpCnMyCmBgYAoKRmlyc3QgbGV0J3MgcmVwbGljYXRlIHRoZSByZXN1bHRzIGJ5IGhhbmQuLi4KCmBgYHtyfQojIENhbGN1bGF0ZSBSZWdyZXNzaW9uIENvZWZmaWNpZW50cwpjb2VmcyA8LSBzb2x2ZSh0KGNiaW5kKDEseCkpICUqJSBjYmluZCgxLHgpKSAlKiUgdChjYmluZCgxLHgpKSAlKiUgeTIKCiMgQ2FsY3VsYXRlIFN1bSBvZiBTcXVhcmVkIFJlc2lkdWFscwpzc3IgPC0gc3VtKCh5MiAtIGNiaW5kKDEseCkgJSolIGNvZWZzKV4yKQoKIyBDYWxjdWxhdGUgU3RhbmRhcmQgRXJyb3JzCnNlcyA8LSBzcXJ0KHNzci8obm9icy0yKSAqIGRpYWcoc29sdmUodChjYmluZCgxLHgpKSAlKiUgY2JpbmQoMSx4KSkpKQoKIyBDYWxjdWxhdGUgdGhlIHQtc3RhdGlzdGljCnRfc3RhdCA8LSBjb2Vmcy9zZXMKCiMgQ2FsY3VsYXRlIHRoZSBwLXZhbHVlcwooMS1wdChhYnModF9zdGF0KSwgbm9icy0yKSkgKiAyCmBgYApBbmQgdmlzdWFsaXplLi4uCgpgYGB7cn0KCmdncGxvdChkYXRhLmZyYW1lKHggPSBjKDQsLTQpKSxhZXMoeCkpICsKICBzdGF0X2Z1bmN0aW9uKGZ1biA9IGR0LCBhcmdzPWxpc3QoZGY9bm9icy0yKSkgKwogIHN0YXRfZnVuY3Rpb24oZnVuID0gZHQsIGFyZ3M9bGlzdChkZj1ub2JzLTIpLAogICAgICAgICAgICAgICAgeGxpbSA9IGMoYWJzKHRfc3RhdClbMV0sNCksCiAgICAgICAgICAgICAgICBnZW9tID0gImFyZWEiLAogICAgICAgICAgICAgICAgZmlsbCA9ICJyZWQiKSArCiAgc3RhdF9mdW5jdGlvbihmdW4gPSBkdCwgYXJncz1saXN0KGRmPW5vYnMtMiksCiAgICAgICAgICAgICAgICB4bGltID0gYygtYWJzKHRfc3RhdClbMV0sLTQpLAogICAgICAgICAgICAgICAgZ2VvbSA9ICJhcmVhIiwKICAgICAgICAgICAgICAgIGZpbGwgPSAicmVkIikgKwogIHRoZW1lX2J3KCkgKwogIGdndGl0bGUoIk51bGwgRWZmZWN0IG9mIE1vZGVsIDIgSW50ZXJjZXB0IikKCmBgYAoKYGBge3J9CgpnZ3Bsb3QoZGF0YS5mcmFtZSh4ID0gYyg0LC00KSksYWVzKHgpKSArCiAgc3RhdF9mdW5jdGlvbihmdW4gPSBkdCwgYXJncz1saXN0KGRmPW5vYnMtMikpICsKICBzdGF0X2Z1bmN0aW9uKGZ1biA9IGR0LCBhcmdzPWxpc3QoZGY9bm9icy0yKSwKICAgICAgICAgICAgICAgIHhsaW0gPSBjKGFicyh0X3N0YXQpWzJdLDQpLAogICAgICAgICAgICAgICAgZ2VvbSA9ICJhcmVhIiwKICAgICAgICAgICAgICAgIGZpbGwgPSAicmVkIikgKwogIHN0YXRfZnVuY3Rpb24oZnVuID0gZHQsIGFyZ3M9bGlzdChkZj1ub2JzLTIpLAogICAgICAgICAgICAgICAgeGxpbSA9IGMoLWFicyh0X3N0YXQpWzJdLC00KSwKICAgICAgICAgICAgICAgIGdlb20gPSAiYXJlYSIsCiAgICAgICAgICAgICAgICBmaWxsID0gInJlZCIpICsKICB0aGVtZV9idygpICsKICBnZ3RpdGxlKCJOdWxsIEVmZmVjdCBvZiBNb2RlbCAyIHgtdmFyaWFibGUiKQoKYGBgCgpFeGNlbGxlbnQuICBBcyBhIGZpbmFsIHRob3VnaHQsIGxldCdzIHRoaW5rIGFib3V0IHdoYXQgZXhhY3RseSB0aGVzZSBjb25maWRlbmNlIGludGVydmFscyBzYXkgc2VlaW5nIGFzIHRoZXJlIGFyZSBbbWFueSBtaXNpbnRlcnByZXRhdGlvbnNdKGh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3YvcG1jL2FydGljbGVzL1BNQzQ4Nzc0MTQvKS4gIFdlIGhhdmUgdGFrZW4gYXMgdGFjaXQsIGZvbGxvd2luZyBjb252ZW50aW9uLCB0aGF0IHdlIGFyZSBsb29raW5nIGZvciBhIDk1JSBjb25maWRlbmNlIGludGVydmFsIHdoaWNoIC0tIGluc29mYXIgYXMgemVybyBpcyBub3Qgd2l0aGluIHRoZSBpbnRlcnZhbCAtLSBpcyBpbnRlcnByZXRlZCBhcyBmaW5kaW5nIGEgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBhdCB0aGUgNSUgbGV2ZWwuCgpTbyB3aGF0IGRvZXMgdGhpcyBhY3R1YWxseSBtZWFuPyAgUGVyaGFwcyB0aGUgbW9zdCBzdHJhaWdodGZvcndhcmQgaW50ZXJwcmV0YXRpb24gaXMgdGhlIGZvbGxvd2luZzogd2VyZSB3ZSB0byByZS1zYW1wbGUgdGhlIGRhdGEgYW5kIHJlcGVhdCB0aGUgYW5hbHlzaXMgaW5maW5pdGVseSBtYW55IHRpbWVzLCB0aGUgJ3RydWUnIHZhbHVlIG9mIHRoZSBwYXJhbWV0ZXIgd2lsbCBiZSBjYXB0dXJlZCBieSBjb25maWRlbmNlIGludGVydmFscyBjb25zdHJ1Y3RlZCBpbiBzdWNoIGEgd2F5IDk1JSBvZiB0aGUgdGltZS4gIFRoaXMgaXMga25vd24gYXMgdGhlICdjb3ZlcmFnZSByYXRlJyBhbmQgaXMgc3RyYWlnaHRmb3J3YXJkIHRvIGRlbW9uc3RyYXRlOgoKYGBge3J9CgpvbmVfc2ltIDwtIGZ1bmN0aW9uKG5vYnMsdHJ1dGgpewogIAogIHggPC0gcm5vcm0obm9icykKICB5IDwtIHRydXRoKnggKyBybm9ybShub2JzKQogIAogIG0gPC0gbG0oeSB+IHgpCiAgaW50ZXJ2YWwgPC0gY29uZmludChtKVsyLF0KICAKICBpbnRlcnZhbAp9CgpzZXQuc2VlZCgxMjM0KQpuc2ltcyA8LSA1MDAwCm5vYnMgPC0gMjAwMAp0cnV0aCA8LSAxCnNpbXMgPC0gbGFwcGx5KDE6bnNpbXMsCiAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpb25lX3NpbShub2JzLHRydXRoKSkKCm91dCA8LSBkby5jYWxsKCJyYmluZCIsc2ltcykKb3V0IDwtIGFzLmRhdGEuZnJhbWUob3V0KQpuYW1lcyhvdXQpIDwtIGMoImxvd2VyIiwidXBwZXIiKQpvdXQkdHJ1dGhfaW5faW50ZXJ2YWwgPC0gaWZlbHNlKG91dCRsb3dlciA8IHRydXRoICYgb3V0JHVwcGVyID4gdHJ1dGgsVFJVRSxGQUxTRSkKCm1lYW4ob3V0JHRydXRoX2luX2ludGVydmFsKQpgYGAKUHJldHR5IGNvb2whCgojIyBFeGVyY2lzZXMKCkJlZm9yZSB3ZSBnZXQgYWhlYWQgb2Ygb3Vyc2VsdmVzLCB3ZSB3YW50IHRvIG1ha2Ugc3VyZSB0aGF0IHlvdSBoYXZlIGZ1bmRhbWVudGFscyBpbiBvcmRlci4gIERvIHRoZSBmb2xsb3dpbmc6CgpXcml0ZSBhIHNjcmlwdCB3aGljaC4uLgoKMS4gRG93bmxvYWRzIHRoZSBmb2xsb3dpbmcgZGF0YToKICAgICsgaHR0cHM6Ly93d3cuZHJvcGJveC5jb20vcy9reXp1bjR6bDdjMTJqNXovbGFiMl9ueXVfZGF0YS5jc3Y/ZGw9MQoyLiBSdW4gZGlmZmVyZW50IGNvbW1hbmRzIHRoYXQgaGVscCB5b3UgYW5zd2VyIHRoZSBmb2xsb3dpbmcgcXVlc3Rpb25zOgogICAgKyBIb3cgbWFueSBzdGF0dXMgdXBkYXRlcyBoYXMgTllVIEFidSBEaGFiaSBwb3N0ZWQgb24gaXRzIHBhZ2U/CiAgICArIFdoYXQgaXMgdGhlIGF2ZXJhZ2UgbnVtYmVyIG9mIGxpa2VzIGFuZCBjb21tZW50cyB0aGF0IGl0cyBwb3N0IHJlY2VpdmU/CiAgICArIFdoYXQgaXMgdGhlIG1heGltdW0gbnVtYmVyIG9mIGxpa2VzIGFuZCBjb21tZW50cyB0aGF0IGl0cyBwb3N0cyByZWNlaXZlPwogICAgKyBXaGF0IHdhcyB0aGUgY29udGVudCBvZiB0aGUgbGFzdCBzdGF0dXMgdXBkYXRlIG9mIDIwMTQ/CjMuIERvd25sb2FkIHRoZSBmb2xsb3dpbmcgZGF0YToKICAgICsgaHR0cHM6Ly93d3cuZHJvcGJveC5jb20vcy9obnFtYjhmeXFsYTNlZ3gvbGFiMl90cnVtcF9kYXRhLmNzdj9kbD0xCjQuIFJ1biBkaWZmZXJlbnQgY29tbWFuZHMgdGhhdCBoZWxwIHlvdSBhbnN3ZXIgdGhlIGZvbGxvd2luZyBxdWVzdGlvbnM6CiAgICArIFdoYXQgdHlwZSBvZiBwb3N0IChwaG90bywgc3RhdHVzLCBsaW5rLCB2aWRlbykgaXMgdGhlIG1vc3QgY29tbW9uIG9uIERvbmFsZCBUcnVtcCdzIEZhY2Vib29rIHBhZ2U/CiAgICArIFVzaW5nIGxpbmVhciByZWdyZXNzaW9uLCBkbyBwb3N0cyB0aGF0IGNvbnRhaW4gcGhvdG9zIHJlY2VpdmUgbW9yZSBsaWtlcyBvbiBhdmVyYWdlIHRoYW4gbGlua3M/CiAgICArIFVzaW5nIGxpbmVhciByZWdyZXNzaW9uLCBhcmUgbW9yZSBsaWtlZCBwb3N0cyBhbHNvIG1vcmUgc2hhcmVkPyAgCiAgICArIENyZWF0ZSBhIHBsb3QgdGhhdCBkaXNwbGF5cyB0aGUgdG90YWwgbnVtYmVyIG9mIGNvbW1lbnRzIG9uIHRoZSBwYWdlIGVhY2ggbW9udGguICBEbyB5b3Ugbm90aWNlIGFueSB0cmVuZHM/ICBDb21lIHVwIHdpdGggYW4gZXhwbGFuYXRpb24gKGFuZCBzdXBwb3J0IGl0IHdpdGggZGF0YSkuCiAgICAKU2F2ZSBhbmQgZW1haWwgeW91ciB3b3JraW5nIFIgc2NyaXB0IHRvIGFhZTMyMlxAbnl1LmVkdSBieSB0aGUgZW5kIG9mIHRoZSBsYWIgc2Vzc2lvbi4KCgpIaW50ISAgVGhlc2UgZGF0YSBhcmUgc2F2ZWQgYXMgLmNzdiBmaWxlcyBzbyB5b3UnbGwgaGF2ZSB0byByZWFkIHRoZW0gaW4gd2l0aCBzb21ldGhpbmcgbGlrZSB0aGUgZm9sbG93aW5nOgpgYGB7cn0KZCA8LSByZWFkLmNzdigiaHR0cHM6Ly93d3cuZHJvcGJveC5jb20vcy9reXp1bjR6bDdjMTJqNXovbGFiMl9ueXVfZGF0YS5jc3Y/ZGw9MSIpCgoKYGBgCgo=