Overview

In an effort to add additional theoretical and practical clarity to the class, a number of days will include brief simulations demonstrating important concepts or tools. Today we will cover omitted variables and the conditions under which fixed or random effects are useful for addressing the issue. As we will see, modeling structure within the data – whether through fixed or random effects – can sometimes help and sometimes hurt. If this is completely unfamiliar see this article for comments on fixed effects in particular.

Quick Note on Specification

Advice in the literature regarding which covariates to include within regression analysis is contradictory. One recommendation, usually in older work, was to condition on as many variables as possible. Others have recommended to include all covariates related to the “treatment” of interest while others have recommended including all covariates related to the outcome.

As noted by Clarke (2005), scholars are often led towards bloated “garbage can” regressions out of the fear of omitted variables. Such advice can easily, however, lead to what is known as bad control and bias amplification – the inclusion of additional control variables may increase or decrease bias and, in general, we do not know which is the case in any particular situation. See, for example, Thoemmes (2015) and the citations therein.

More recently these arguments have been applied to the inclusion of fixed or random effects as well. After all, random effects are regularized fixed effects and fixed effects are control variables. In short, while textbook treatments of fixed/random effects usually advertise them as a way of accounting for omitted time-invariant variables, in practice we never know whether bias has increased or decreased outside of two situations – (1) when we simulate the data ourselves and so know the truth and (2) when valid alternative identification strategies, such as instruments, are available.

The key message I’d like to press upon you is to be aware of the uncertainty surrounding identification-by-control strategies. One active literature worth reading would be the one centering around the work of Judea Pearl which makes it lucidly clear that the “correct” conditioning set is itself conditioned on the structural model in mind, and that such a model is “true.” In general this is how traditional statistical models work – standard statistical inference is only valid if the only unknowns are the parameters to be estimated. If anything else is unknown – such as the underlying structural model or correct specification – then things become more difficult and tenuous, if not impossible. There is no panacea.

OVB in Pooled Model

Omitted variable bias is best understood as a particular type of regressor-error dependency. Before we jump into multilevel models, let’s look at some examples of good or bad control. We will begin by simulating some correlated data.

set.seed(1234)

library(MASS)
library(texreg)

# Generate X data
n_obs <- 1000
cor_mat <- matrix(c(1,-0.5,0.5,
                    -0.5,1,-0.5,
                    0.5,-0.5,1),nrow=3,ncol=3)

X <- mvrnorm(n_obs,rep(0,3),cor_mat,empirical = T)

# Make X4 into a "bad control"
u1 <- rnorm(n_obs)
u2 <- rnorm(n_obs)
X4 <- u1 + u2 + rnorm(n_obs)
X[,1] <- X[,1] + u1

# Generate Outcome
betas <- c(1,1,1)
y <- 3 + X %*% betas + u2 + rnorm(n_obs)

d <- data.frame(y,X,X4=X4)

# Estimate Pooled Models
m1 <- lm(y ~ X1 + X2 + X3,data=d)
m2 <- lm(y ~ X1 + X3,data=d)
m3 <- lm(y ~ X1 + X2,data=d)
m4 <- lm(y ~ X1,data=d)
m5 <- lm(y ~ X1 + X2 + X3 + X4,data=d)

htmlreg(l=list(m1,m2,m3,m4,m5),
        doctype = FALSE,
        caption="")
Model 1 Model 2 Model 3 Model 4 Model 5
(Intercept) 2.96*** 2.95*** 2.96*** 2.96*** 2.95***
(0.04) (0.05) (0.05) (0.05) (0.04)
X1 1.05*** 0.90*** 1.19*** 1.03*** 0.81***
(0.03) (0.04) (0.04) (0.04) (0.03)
X2 1.03*** 0.61*** 0.94***
(0.05) (0.05) (0.05)
X3 0.98*** 0.54*** 1.06***
(0.05) (0.05) (0.05)
X4 0.37***
(0.03)
R2 0.63 0.48 0.49 0.43 0.70
Adj. R2 0.63 0.48 0.49 0.43 0.69
Num. obs. 1000 1000 1000 1000 1000
RMSE 1.35 1.61 1.59 1.69 1.23
p < 0.001, p < 0.01, p < 0.05

The first model is correctly specified and gives the correct coefficient estimate for X1. Models 2 and 3 each omit one of the control variables, yielding biased estimates of the effect of X1. Model 4 shows how, in this case, the biases from X2 and X3 directly offset with both are excluded, yielding a correct coefficient estimate. Finally, Model 5 demonstrates “bad control” where the inclusion of X4 biases the coefficient estimates.

Additional details are a bit outside the scope of what we want to talk about here. Note that these concerns are relevant for any covariate adjustment technique, including propensity scores. For additional information see Pearl (2009), Elwert and Winship (2014), and Steiner and Kim (2016) for related discussions.

Fixed and Random Effects

So when can the inclusion of fixed/random effects help? Simply put, when the model is correct except for factors which vary only across, but not within, units. We saw a great example of this with Simpson’s Paradox. Let’s take a closer look at that example.

library(ggplot2)

set.seed(1234)

nobs <- 1000
n_groups <- 4

grp <- rep_len(1:n_groups,nobs)
labels <- letters[grp]
grp_means <- -seq(-n_groups,n_groups,length=n_groups)

x <- rnorm(nobs,grp_means[grp])
err <- rnorm(nobs)

y <- x + 8*grp + err

simp <- data.frame(y,x,grp,grp_means[grp],labels)

ggplot(simp,aes(x=x,y=y,color=labels)) + 
  geom_point()

The last time we saw this it was simply to illustrate what fixed and random effects do and how they relate to each other. What we didn’t talk about in detail was how the data was generated and alternative approaches to estimate the model. In particular, I’d like to draw your attention to the dataset and DGP.

y <- x + 8*grp + err
simp <- data.frame(y,x,grp,grp_means[grp],labels)
head(simp)
##           y          x grp grp_means.grp. labels
## 1  9.587601  2.7929343   1       4.000000      a
## 2 17.912229  1.6107626   2       1.333333      b
## 3 22.211963 -0.2488922   3      -1.333333      c
## 4 26.289673 -6.3456977   4      -4.000000      d
## 5 13.132076  4.4291247   1       4.000000      a
## 6 15.933506  1.8393892   2       1.333333      b

Effectively what we have done is create the grouping structure, reflected by our labels, by omitting the covariate grp from the analysis. Look what happens if we instead include it as a variable.

m1 <- lm(y ~ x + grp, data = simp)
m2 <- lm(y ~ x + labels, data = simp)
htmlreg(l=list(m1,m2),
        doctype = FALSE,
        caption = "")
Model 1 Model 2
(Intercept) -0.43 7.76***
(0.22) (0.14)
x 1.06*** 1.06***
(0.03) (0.03)
grp 8.18***
(0.09)
labelsb 8.12***
(0.12)
labelsc 16.41***
(0.19)
labelsd 24.50***
(0.26)
R2 0.97 0.97
Adj. R2 0.97 0.97
Num. obs. 1000 1000
RMSE 0.98 0.98
p < 0.001, p < 0.01, p < 0.05

The coefficient estimate for x, our variable of interest, it the same in either case and a good estimate of the true effect. This is because the fixed effects were exactly what was needed to model this omitted variable.

The idea extends naturally to multiple omitted variables that have the same structure and more complex grouping. We can illustrate this with a two-way fixed effects model and a more complicated structure.

set.seed(1234)

nobs <- 1000
n_g1 <- 4
n_g2 <- 8

grp1 <- sample(1:n_g1,nobs,replace = T)
grp2 <- sample(1:n_g2,nobs,replace = T)

labels1 <- letters[grp1]
labels2 <- letters[26-grp2]

grp_means1 <- rnorm(n_g1,0,2)
grp_means2 <- rnorm(n_g2,0,2)

x <- rnorm(nobs,grp_means1[grp1] + grp_means2[grp2])
err <- rnorm(nobs)

y <- x + grp1 - grp2 + err

data <- data.frame(y,x,
                   grp1,grp2,
                   grpm1 = grp_means1[grp1],
                   grpm2 = grp_means2[grp2],
                   labels1,labels2)

ggplot(data,aes(x=x,y=y,color=paste(labels1,"-",labels2))) + 
  geom_point()

Here we now have two variables that will be omitted; grp1 and grp2. Both are constant within groups. Group assignments were sampled randomly such that observations have multiple membership. Let’s estimate a number of models to see what happens.

m1 <- lm(y ~ x,data = data)
m2 <- lm(y ~ x + grp1 + grp2, data = data)
m3 <- lm(y ~ x + labels1 + labels2, data = data)
m4 <- lm(y ~ x + labels1, data = data)
m5 <- lm(y ~ x + labels2, data = data)

htmlreg(l=list(m1,m2,m3,m4,m5),caption = "",doctype = F)
Model 1 Model 2 Model 3 Model 4 Model 5
(Intercept) -2.12*** 0.14 -6.89*** -4.21*** -5.77***
(0.08) (0.11) (0.11) (0.16) (0.13)
x 0.79*** 0.99*** 0.97*** 0.54*** 1.15***
(0.03) (0.01) (0.03) (0.03) (0.02)
grp1 0.96***
(0.03)
grp2 -1.00***
(0.02)
labels1b 1.01*** 2.24***
(0.13) (0.23)
labels1c 1.87*** 1.60***
(0.09) (0.20)
labels1d 2.95*** 4.24***
(0.15) (0.24)
labels2s 1.05*** 1.01***
(0.13) (0.18)
labels2t 1.99*** 2.45***
(0.15) (0.18)
labels2u 2.91*** 3.80***
(0.19) (0.20)
labels2v 3.83*** 4.31***
(0.17) (0.19)
labels2w 5.14*** 5.33***
(0.13) (0.17)
labels2x 5.89*** 7.00***
(0.26) (0.23)
labels2y 6.89*** 7.12***
(0.14) (0.18)
R2 0.45 0.92 0.92 0.58 0.84
Adj. R2 0.45 0.92 0.92 0.58 0.84
Num. obs. 1000 1000 1000 1000 1000
RMSE 2.59 1.01 1.01 2.26 1.40
p < 0.001, p < 0.01, p < 0.05

Models 2 and 3 are the correct specifications. In the former we include what we are here considering omitted variables. In the latter, we include the group identifiers as covariates, which are able to “suck up” this form of endogeneity. In all other models we are faced with a specification problem. Of particular note are Models 4 and 5 which include only one set of fixed effects. In the former we have found an example of bias amplification – compared to Model 1 which included no fixed effects, Model 4 is even more biased despite being “closer” to an adequate specification. By contrast, Model 5 reverses the sign of the bias.

It is simple to specify this within a random effects framework as well.

library(lme4)
m6 <- lmer(y ~ x + (1|labels1) + (1|labels2), data= data)
summary(m6)
## Linear mixed model fit by REML ['lmerMod']
## Formula: y ~ x + (1 | labels1) + (1 | labels2)
##    Data: data
## 
## REML criterion at convergence: 2931.7
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -3.06757 -0.68444  0.02147  0.66298  2.94074 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  labels2  (Intercept) 5.837    2.416   
##  labels1  (Intercept) 1.577    1.256   
##  Residual             1.022    1.011   
## Number of obs: 1000, groups:  labels2, 8; labels1, 4
## 
## Fixed effects:
##             Estimate Std. Error t value
## (Intercept) -1.97283    1.06065   -1.86
## x            0.96548    0.03246   29.74
## 
## Correlation of Fixed Effects:
##   (Intr)
## x 0.011

You’ll note that this is pretty close to what had been estimated with the two-way fixed effects model.

As a final example, we will look at the case of omitted variables which do not satisfy the “no variation within group” requirement by adapting the above.

set.seed(1234)

nobs <- 1000
n_g1 <- 4
n_g2 <- 8

grp1 <- sample(1:n_g1,nobs,replace = T)
grp2 <- sample(1:n_g2,nobs,replace = T)

labels1 <- letters[grp1]
labels2 <- letters[26-grp2]

grp_means1 <- rnorm(n_g1,0,2)
grp_means2 <- rnorm(n_g2,0,2)

x1 <- rnorm(nobs,grp_means1[grp1] + grp_means2[grp2])
x2 <- x1 + rnorm(nobs)
err <- rnorm(nobs)

y <- x1 + x2 + grp1 - grp2 + err

data <- data.frame(y,x,grp1,grp2,grp_means1[grp1],grp_means2[grp2],labels1,labels2)

m7 <- lm(y ~ x1 + x2 + labels1 + labels2, data = data)
m8 <- lm(y ~ x1 + labels1 + labels2, data = data)
htmlreg(list(m7,m8),doctype = F,caption = "")
Model 1 Model 2
(Intercept) -6.96*** -6.85***
(0.10) (0.15)
x1 1.00*** 1.96***
(0.04) (0.05)
x2 0.99***
(0.03)
labels1b 1.02*** 1.03***
(0.13) (0.19)
labels1c 2.03*** 1.90***
(0.09) (0.13)
labels1d 3.05*** 3.00***
(0.15) (0.21)
labels2s 0.90*** 0.95***
(0.13) (0.18)
labels2t 1.91*** 1.90***
(0.14) (0.21)
labels2u 2.84*** 2.76***
(0.19) (0.27)
labels2v 3.91*** 3.74***
(0.17) (0.24)
labels2w 5.02*** 5.15***
(0.13) (0.18)
labels2x 5.89*** 5.78***
(0.26) (0.36)
labels2y 6.92*** 6.82***
(0.14) (0.19)
R2 0.97 0.94
Adj. R2 0.97 0.94
Num. obs. 1000 1000
RMSE 1.00 1.42
p < 0.001, p < 0.01, p < 0.05

Here x2 is an omitted variable. When it is included in the specification everything is kosher while when it is removed the fixed effects do nothing to remedy the problem.

There are other specific contexts in which fixed/random effects will fail to provide unbiased estimates of treatment effects. See Imai and Kim (2019) for a discussion regarding how this limits applications to longitudinal data in particular.

Quick Aside: What if labels were omitted too?

In the above we saw that, insofar as omitted factors are invariant within groups, that they may be captured using knowledge of group membership. But what if we don’t know that either? While somewhat outside the scope of the class, this touches on a closely related family of latent variable models. In particular, there is a clean bridge to mixture models in which it is suspected or known that subpopulations exist within the sample, but the membership within such models is unknown. There is a cool illustration available here.

Optional Self Study Practice

The best way to learn R is to use R, and the best way to really understand methods is to poke around at them either with the mathematical theory or simulations. I suggest considering the following questions:

  1. Above we saw that when the omitted variables are constant within groups that fixed/random effects are appropriate while when they vary within groups they are not. Run simulations to assess the relationship between variability of an omitted continuous covariate and the extent of bias.
  2. In the above we saw that only specifying part of the grouping structure can amplify bias. Revisit the Frisch-Waugh-Lovell theorem from last time and examine the partial relationship between y and x. Do you notice anything plotting the residuals against each other?
  3. Gibbons et al. (2018) show that when treatment effects are heterogenous (think random slopes) that traditional fixed effects estimates (i.e. only introducing intercepts) is generally not a consistent estimator. Demonstrate this and connect the result back to omitted variables.
  4. The objects m3 and m6 contain fixed and random effect estimates of the multimembership model used above. Use the data augmentation trick to show that the former is an unregularized version of the latter.
LS0tDQp0aXRsZTogIklDUFNSIE1MTTI6IE9taXR0ZWQgVmFyaWFibGVzIg0KYXV0aG9yOiAiQ2hyaXN0b3BoZXIgU2Nod2FyeiINCmRhdGU6ICI3LzIxLzIwMjAiDQpwYWdlczoNCiAgZXh0cmE6IHRydWUNCm91dHB1dDogDQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiB0cnVlDQogICAgdG9jX2RlcHRoOiAyDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KLS0tDQoNCiMgT3ZlcnZpZXcNCg0KSW4gYW4gZWZmb3J0IHRvIGFkZCBhZGRpdGlvbmFsIHRoZW9yZXRpY2FsIGFuZCBwcmFjdGljYWwgY2xhcml0eSB0byB0aGUgY2xhc3MsIGEgbnVtYmVyIG9mIGRheXMgd2lsbCBpbmNsdWRlIGJyaWVmIHNpbXVsYXRpb25zIGRlbW9uc3RyYXRpbmcgaW1wb3J0YW50IGNvbmNlcHRzIG9yIHRvb2xzLiAgVG9kYXkgd2Ugd2lsbCBjb3ZlciBvbWl0dGVkIHZhcmlhYmxlcyBhbmQgdGhlIGNvbmRpdGlvbnMgdW5kZXIgd2hpY2ggZml4ZWQgb3IgcmFuZG9tIGVmZmVjdHMgYXJlIHVzZWZ1bCBmb3IgYWRkcmVzc2luZyB0aGUgaXNzdWUuICBBcyB3ZSB3aWxsIHNlZSwgbW9kZWxpbmcgc3RydWN0dXJlIHdpdGhpbiB0aGUgZGF0YSAtLSB3aGV0aGVyIHRocm91Z2ggZml4ZWQgb3IgcmFuZG9tIGVmZmVjdHMgLS0gY2FuIHNvbWV0aW1lcyBoZWxwIGFuZCBzb21ldGltZXMgaHVydC4gIElmIHRoaXMgaXMgY29tcGxldGVseSB1bmZhbWlsaWFyIHNlZSBbdGhpcyBhcnRpY2xlXShodHRwczovL2RvaS5vcmcvMTAuMTA5My9wYW4vbXB3MDE1KSBmb3IgY29tbWVudHMgb24gZml4ZWQgZWZmZWN0cyBpbiBwYXJ0aWN1bGFyLg0KDQojIyBRdWljayBOb3RlIG9uIFNwZWNpZmljYXRpb24NCg0KQWR2aWNlIGluIHRoZSBsaXRlcmF0dXJlIHJlZ2FyZGluZyB3aGljaCBjb3ZhcmlhdGVzIHRvIGluY2x1ZGUgd2l0aGluIHJlZ3Jlc3Npb24gYW5hbHlzaXMgaXMgY29udHJhZGljdG9yeS4gIE9uZSByZWNvbW1lbmRhdGlvbiwgdXN1YWxseSBpbiBvbGRlciB3b3JrLCB3YXMgdG8gY29uZGl0aW9uIG9uIGFzIG1hbnkgdmFyaWFibGVzIGFzIHBvc3NpYmxlLiAgT3RoZXJzIGhhdmUgcmVjb21tZW5kZWQgdG8gaW5jbHVkZSBhbGwgY292YXJpYXRlcyByZWxhdGVkIHRvIHRoZSAidHJlYXRtZW50IiBvZiBpbnRlcmVzdCB3aGlsZSBvdGhlcnMgaGF2ZSByZWNvbW1lbmRlZCBpbmNsdWRpbmcgYWxsIGNvdmFyaWF0ZXMgcmVsYXRlZCB0byB0aGUgb3V0Y29tZS4NCg0KQXMgbm90ZWQgYnkgW0NsYXJrZSAoMjAwNSldKGh0dHBzOi8vZG9pLm9yZy8xMC4xMDgwJTJGMDczODg5NDA1MDAzMzkxODMpLCBzY2hvbGFycyBhcmUgb2Z0ZW4gbGVkIHRvd2FyZHMgYmxvYXRlZCAiZ2FyYmFnZSBjYW4iIHJlZ3Jlc3Npb25zIG91dCBvZiB0aGUgZmVhciBvZiBvbWl0dGVkIHZhcmlhYmxlcy4gIFN1Y2ggYWR2aWNlIGNhbiBlYXNpbHksIGhvd2V2ZXIsIGxlYWQgdG8gd2hhdCBpcyBrbm93biBhcyAqKmJhZCBjb250cm9sKiogYW5kICoqYmlhcyBhbXBsaWZpY2F0aW9uKiogLS0gdGhlIGluY2x1c2lvbiBvZiBhZGRpdGlvbmFsIGNvbnRyb2wgdmFyaWFibGVzIG1heSBpbmNyZWFzZSBvciBkZWNyZWFzZSBiaWFzIGFuZCwgaW4gZ2VuZXJhbCwgd2UgZG8gbm90IGtub3cgd2hpY2ggaXMgdGhlIGNhc2UgaW4gYW55IHBhcnRpY3VsYXIgc2l0dWF0aW9uLiAgU2VlLCBmb3IgZXhhbXBsZSwgW1Rob2VtbWVzICgyMDE1KV0oaHR0cHM6Ly9kb2kub3JnLzEwLjE1MTUvamNpLTIwMTUtMDAxMikgYW5kIHRoZSBjaXRhdGlvbnMgdGhlcmVpbi4NCg0KTW9yZSByZWNlbnRseSB0aGVzZSBhcmd1bWVudHMgaGF2ZSBiZWVuIGFwcGxpZWQgdG8gdGhlIGluY2x1c2lvbiBvZiBmaXhlZCBvciByYW5kb20gZWZmZWN0cyBhcyB3ZWxsLiAgQWZ0ZXIgYWxsLCByYW5kb20gZWZmZWN0cyBhcmUgcmVndWxhcml6ZWQgZml4ZWQgZWZmZWN0cyBhbmQgZml4ZWQgZWZmZWN0cyAqYXJlKiBjb250cm9sIHZhcmlhYmxlcy4gIEluIHNob3J0LCB3aGlsZSB0ZXh0Ym9vayB0cmVhdG1lbnRzIG9mIGZpeGVkL3JhbmRvbSBlZmZlY3RzIHVzdWFsbHkgYWR2ZXJ0aXNlIHRoZW0gYXMgYSB3YXkgb2YgYWNjb3VudGluZyBmb3Igb21pdHRlZCB0aW1lLWludmFyaWFudCB2YXJpYWJsZXMsIGluIHByYWN0aWNlIHdlIG5ldmVyIGtub3cgd2hldGhlciBiaWFzIGhhcyBpbmNyZWFzZWQgb3IgZGVjcmVhc2VkIG91dHNpZGUgb2YgdHdvIHNpdHVhdGlvbnMgLS0gKDEpIHdoZW4gd2Ugc2ltdWxhdGUgdGhlIGRhdGEgb3Vyc2VsdmVzIGFuZCBzbyBrbm93IHRoZSB0cnV0aCBhbmQgKDIpIHdoZW4gdmFsaWQgYWx0ZXJuYXRpdmUgaWRlbnRpZmljYXRpb24gc3RyYXRlZ2llcywgc3VjaCBhcyBpbnN0cnVtZW50cywgYXJlIGF2YWlsYWJsZS4gIA0KDQpUaGUga2V5IG1lc3NhZ2UgSSdkIGxpa2UgdG8gcHJlc3MgdXBvbiB5b3UgaXMgdG8gYmUgYXdhcmUgb2YgdGhlIHVuY2VydGFpbnR5IHN1cnJvdW5kaW5nIGlkZW50aWZpY2F0aW9uLWJ5LWNvbnRyb2wgc3RyYXRlZ2llcy4gIE9uZSBhY3RpdmUgbGl0ZXJhdHVyZSB3b3J0aCByZWFkaW5nIHdvdWxkIGJlIHRoZSBvbmUgY2VudGVyaW5nIGFyb3VuZCB0aGUgd29yayBvZiBbSnVkZWEgUGVhcmxdKGh0dHBzOi8vd3d3LnJlc2VhcmNoZ2F0ZS5uZXQvcHVibGljYXRpb24vMzQwMDgyNzU1X0FfQ3Jhc2hfQ291cnNlX2luX0dvb2RfYW5kX0JhZF9Db250cm9scykgd2hpY2ggbWFrZXMgaXQgbHVjaWRseSBjbGVhciB0aGF0IHRoZSAiY29ycmVjdCIgY29uZGl0aW9uaW5nIHNldCBpcyBpdHNlbGYgY29uZGl0aW9uZWQgb24gdGhlIHN0cnVjdHVyYWwgbW9kZWwgaW4gbWluZCwgYW5kIHRoYXQgc3VjaCBhIG1vZGVsIGlzICJ0cnVlLiIgIEluIGdlbmVyYWwgdGhpcyBpcyBob3cgdHJhZGl0aW9uYWwgc3RhdGlzdGljYWwgbW9kZWxzIHdvcmsgLS0gc3RhbmRhcmQgc3RhdGlzdGljYWwgaW5mZXJlbmNlIGlzIG9ubHkgdmFsaWQgaWYgdGhlICoqb25seSoqIHVua25vd25zIGFyZSB0aGUgcGFyYW1ldGVycyB0byBiZSBlc3RpbWF0ZWQuICBJZiBhbnl0aGluZyBlbHNlIGlzIHVua25vd24gLS0gc3VjaCBhcyB0aGUgdW5kZXJseWluZyBzdHJ1Y3R1cmFsIG1vZGVsIG9yIGNvcnJlY3Qgc3BlY2lmaWNhdGlvbiAtLSB0aGVuIHRoaW5ncyBiZWNvbWUgbW9yZSBkaWZmaWN1bHQgYW5kIHRlbnVvdXMsIGlmIG5vdCBpbXBvc3NpYmxlLiAgVGhlcmUgaXMgbm8gcGFuYWNlYS4NCg0KIyMgT1ZCIGluIFBvb2xlZCBNb2RlbA0KDQpPbWl0dGVkIHZhcmlhYmxlIGJpYXMgaXMgYmVzdCB1bmRlcnN0b29kIGFzIGEgcGFydGljdWxhciB0eXBlIG9mICpyZWdyZXNzb3ItZXJyb3IgZGVwZW5kZW5jeSouICBCZWZvcmUgd2UganVtcCBpbnRvIG11bHRpbGV2ZWwgbW9kZWxzLCBsZXQncyBsb29rIGF0IHNvbWUgZXhhbXBsZXMgb2YgZ29vZCBvciBiYWQgY29udHJvbC4gIFdlIHdpbGwgYmVnaW4gYnkgc2ltdWxhdGluZyBzb21lIGNvcnJlbGF0ZWQgZGF0YS4NCg0KYGBge3IsIHJlc3VsdHM9J2FzaXMnLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRX0NCnNldC5zZWVkKDEyMzQpDQoNCmxpYnJhcnkoTUFTUykNCmxpYnJhcnkodGV4cmVnKQ0KDQojIEdlbmVyYXRlIFggZGF0YQ0Kbl9vYnMgPC0gMTAwMA0KY29yX21hdCA8LSBtYXRyaXgoYygxLC0wLjUsMC41LA0KICAgICAgICAgICAgICAgICAgICAtMC41LDEsLTAuNSwNCiAgICAgICAgICAgICAgICAgICAgMC41LC0wLjUsMSksbnJvdz0zLG5jb2w9MykNCg0KWCA8LSBtdnJub3JtKG5fb2JzLHJlcCgwLDMpLGNvcl9tYXQsZW1waXJpY2FsID0gVCkNCg0KIyBNYWtlIFg0IGludG8gYSAiYmFkIGNvbnRyb2wiDQp1MSA8LSBybm9ybShuX29icykNCnUyIDwtIHJub3JtKG5fb2JzKQ0KWDQgPC0gdTEgKyB1MiArIHJub3JtKG5fb2JzKQ0KWFssMV0gPC0gWFssMV0gKyB1MQ0KDQojIEdlbmVyYXRlIE91dGNvbWUNCmJldGFzIDwtIGMoMSwxLDEpDQp5IDwtIDMgKyBYICUqJSBiZXRhcyArIHUyICsgcm5vcm0obl9vYnMpDQoNCmQgPC0gZGF0YS5mcmFtZSh5LFgsWDQ9WDQpDQoNCiMgRXN0aW1hdGUgUG9vbGVkIE1vZGVscw0KbTEgPC0gbG0oeSB+IFgxICsgWDIgKyBYMyxkYXRhPWQpDQptMiA8LSBsbSh5IH4gWDEgKyBYMyxkYXRhPWQpDQptMyA8LSBsbSh5IH4gWDEgKyBYMixkYXRhPWQpDQptNCA8LSBsbSh5IH4gWDEsZGF0YT1kKQ0KbTUgPC0gbG0oeSB+IFgxICsgWDIgKyBYMyArIFg0LGRhdGE9ZCkNCg0KaHRtbHJlZyhsPWxpc3QobTEsbTIsbTMsbTQsbTUpLA0KICAgICAgICBkb2N0eXBlID0gRkFMU0UsDQogICAgICAgIGNhcHRpb249IiIpDQoNCmBgYA0KDQpUaGUgZmlyc3QgbW9kZWwgaXMgY29ycmVjdGx5IHNwZWNpZmllZCBhbmQgZ2l2ZXMgdGhlIGNvcnJlY3QgY29lZmZpY2llbnQgZXN0aW1hdGUgZm9yIFgxLiAgTW9kZWxzIDIgYW5kIDMgZWFjaCBvbWl0IG9uZSBvZiB0aGUgY29udHJvbCB2YXJpYWJsZXMsIHlpZWxkaW5nIGJpYXNlZCBlc3RpbWF0ZXMgb2YgdGhlIGVmZmVjdCBvZiBYMS4gIE1vZGVsIDQgc2hvd3MgaG93LCBpbiB0aGlzIGNhc2UsIHRoZSBiaWFzZXMgZnJvbSBYMiBhbmQgWDMgZGlyZWN0bHkgb2Zmc2V0IHdpdGggYm90aCBhcmUgZXhjbHVkZWQsIHlpZWxkaW5nIGEgY29ycmVjdCBjb2VmZmljaWVudCBlc3RpbWF0ZS4gIEZpbmFsbHksIE1vZGVsIDUgZGVtb25zdHJhdGVzICJiYWQgY29udHJvbCIgd2hlcmUgdGhlIGluY2x1c2lvbiBvZiBYNCBiaWFzZXMgdGhlIGNvZWZmaWNpZW50IGVzdGltYXRlcy4NCg0KQWRkaXRpb25hbCBkZXRhaWxzIGFyZSBhIGJpdCBvdXRzaWRlIHRoZSBzY29wZSBvZiB3aGF0IHdlIHdhbnQgdG8gdGFsayBhYm91dCBoZXJlLiAgTm90ZSB0aGF0IHRoZXNlIGNvbmNlcm5zIGFyZSByZWxldmFudCBmb3IgYW55IGNvdmFyaWF0ZSBhZGp1c3RtZW50IHRlY2huaXF1ZSwgaW5jbHVkaW5nIHByb3BlbnNpdHkgc2NvcmVzLiAgRm9yIGFkZGl0aW9uYWwgaW5mb3JtYXRpb24gc2VlIFtQZWFybCAoMjAwOSldKGh0dHBzOi8vZnRwLmNzLnVjbGEuZWR1L3B1Yi9zdGF0X3Nlci9yMzQ4LnBkZiksIFtFbHdlcnQgYW5kIFdpbnNoaXAgKDIwMTQpXShodHRwczovL2RvaS5vcmcvMTAuMTE0Ni9hbm51cmV2LXNvYy0wNzE5MTMtMDQzNDU1KSwgYW5kIFtTdGVpbmVyIGFuZCBLaW0gKDIwMTYpXShodHRwczovL2RvaS5vcmcvMTAuMTUxNS9qY2ktMjAxNi0wMDA5KSBmb3IgcmVsYXRlZCBkaXNjdXNzaW9ucy4NCg0KIyMgRml4ZWQgYW5kIFJhbmRvbSBFZmZlY3RzDQoNClNvIHdoZW4gY2FuIHRoZSBpbmNsdXNpb24gb2YgZml4ZWQvcmFuZG9tIGVmZmVjdHMgaGVscD8gIFNpbXBseSBwdXQsIHdoZW4gdGhlIG1vZGVsIGlzIGNvcnJlY3QgZXhjZXB0IGZvciBmYWN0b3JzIHdoaWNoIHZhcnkgb25seSBhY3Jvc3MsIGJ1dCBub3Qgd2l0aGluLCB1bml0cy4gIFdlIHNhdyBhIGdyZWF0IGV4YW1wbGUgb2YgdGhpcyB3aXRoIFNpbXBzb24ncyBQYXJhZG94LiAgTGV0J3MgdGFrZSBhIGNsb3NlciBsb29rIGF0IHRoYXQgZXhhbXBsZS4NCg0KDQpgYGB7ciwgd2FybmluZz1GfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KDQpzZXQuc2VlZCgxMjM0KQ0KDQpub2JzIDwtIDEwMDANCm5fZ3JvdXBzIDwtIDQNCg0KZ3JwIDwtIHJlcF9sZW4oMTpuX2dyb3Vwcyxub2JzKQ0KbGFiZWxzIDwtIGxldHRlcnNbZ3JwXQ0KZ3JwX21lYW5zIDwtIC1zZXEoLW5fZ3JvdXBzLG5fZ3JvdXBzLGxlbmd0aD1uX2dyb3VwcykNCg0KeCA8LSBybm9ybShub2JzLGdycF9tZWFuc1tncnBdKQ0KZXJyIDwtIHJub3JtKG5vYnMpDQoNCnkgPC0geCArIDgqZ3JwICsgZXJyDQoNCnNpbXAgPC0gZGF0YS5mcmFtZSh5LHgsZ3JwLGdycF9tZWFuc1tncnBdLGxhYmVscykNCg0KZ2dwbG90KHNpbXAsYWVzKHg9eCx5PXksY29sb3I9bGFiZWxzKSkgKyANCiAgZ2VvbV9wb2ludCgpDQpgYGANCg0KVGhlIGxhc3QgdGltZSB3ZSBzYXcgdGhpcyBpdCB3YXMgc2ltcGx5IHRvIGlsbHVzdHJhdGUgd2hhdCBmaXhlZCBhbmQgcmFuZG9tIGVmZmVjdHMgZG8gYW5kIGhvdyB0aGV5IHJlbGF0ZSB0byBlYWNoIG90aGVyLiAgV2hhdCB3ZSBkaWRuJ3QgdGFsayBhYm91dCBpbiBkZXRhaWwgd2FzIGhvdyB0aGUgZGF0YSB3YXMgZ2VuZXJhdGVkIGFuZCBhbHRlcm5hdGl2ZSBhcHByb2FjaGVzIHRvIGVzdGltYXRlIHRoZSBtb2RlbC4gIEluIHBhcnRpY3VsYXIsIEknZCBsaWtlIHRvIGRyYXcgeW91ciBhdHRlbnRpb24gdG8gdGhlIGRhdGFzZXQgYW5kIERHUC4NCg0KYGBge3J9DQp5IDwtIHggKyA4KmdycCArIGVycg0Kc2ltcCA8LSBkYXRhLmZyYW1lKHkseCxncnAsZ3JwX21lYW5zW2dycF0sbGFiZWxzKQ0KaGVhZChzaW1wKQ0KYGBgDQoNCkVmZmVjdGl2ZWx5IHdoYXQgd2UgaGF2ZSBkb25lIGlzIGNyZWF0ZSB0aGUgZ3JvdXBpbmcgc3RydWN0dXJlLCByZWZsZWN0ZWQgYnkgb3VyIGxhYmVscywgYnkgb21pdHRpbmcgdGhlIGNvdmFyaWF0ZSAqKmdycCoqIGZyb20gdGhlIGFuYWx5c2lzLiAgTG9vayB3aGF0IGhhcHBlbnMgaWYgd2UgaW5zdGVhZCBpbmNsdWRlIGl0IGFzIGEgdmFyaWFibGUuDQoNCmBgYHtyLCB3YXJuaW5nPUYsIG1lc3NhZ2VzPSBGLCByZXN1bHRzPSJhc2lzIn0NCm0xIDwtIGxtKHkgfiB4ICsgZ3JwLCBkYXRhID0gc2ltcCkNCm0yIDwtIGxtKHkgfiB4ICsgbGFiZWxzLCBkYXRhID0gc2ltcCkNCmh0bWxyZWcobD1saXN0KG0xLG0yKSwNCiAgICAgICAgZG9jdHlwZSA9IEZBTFNFLA0KICAgICAgICBjYXB0aW9uID0gIiIpDQpgYGANCg0KVGhlIGNvZWZmaWNpZW50IGVzdGltYXRlIGZvciB4LCBvdXIgdmFyaWFibGUgb2YgaW50ZXJlc3QsIGl0IHRoZSBzYW1lIGluIGVpdGhlciBjYXNlIGFuZCBhIGdvb2QgZXN0aW1hdGUgb2YgdGhlIHRydWUgZWZmZWN0LiAgVGhpcyBpcyBiZWNhdXNlIHRoZSBmaXhlZCBlZmZlY3RzIHdlcmUgZXhhY3RseSB3aGF0IHdhcyBuZWVkZWQgdG8gbW9kZWwgdGhpcyBvbWl0dGVkIHZhcmlhYmxlLg0KDQpUaGUgaWRlYSBleHRlbmRzIG5hdHVyYWxseSB0byBtdWx0aXBsZSBvbWl0dGVkIHZhcmlhYmxlcyB0aGF0IGhhdmUgdGhlIHNhbWUgc3RydWN0dXJlIGFuZCBtb3JlIGNvbXBsZXggZ3JvdXBpbmcuICBXZSBjYW4gaWxsdXN0cmF0ZSB0aGlzIHdpdGggYSB0d28td2F5IGZpeGVkIGVmZmVjdHMgbW9kZWwgYW5kIGEgbW9yZSBjb21wbGljYXRlZCBzdHJ1Y3R1cmUuDQoNCmBgYHtyfQ0Kc2V0LnNlZWQoMTIzNCkNCg0Kbm9icyA8LSAxMDAwDQpuX2cxIDwtIDQNCm5fZzIgPC0gOA0KDQpncnAxIDwtIHNhbXBsZSgxOm5fZzEsbm9icyxyZXBsYWNlID0gVCkNCmdycDIgPC0gc2FtcGxlKDE6bl9nMixub2JzLHJlcGxhY2UgPSBUKQ0KDQpsYWJlbHMxIDwtIGxldHRlcnNbZ3JwMV0NCmxhYmVsczIgPC0gbGV0dGVyc1syNi1ncnAyXQ0KDQpncnBfbWVhbnMxIDwtIHJub3JtKG5fZzEsMCwyKQ0KZ3JwX21lYW5zMiA8LSBybm9ybShuX2cyLDAsMikNCg0KeCA8LSBybm9ybShub2JzLGdycF9tZWFuczFbZ3JwMV0gKyBncnBfbWVhbnMyW2dycDJdKQ0KZXJyIDwtIHJub3JtKG5vYnMpDQoNCnkgPC0geCArIGdycDEgLSBncnAyICsgZXJyDQoNCmRhdGEgPC0gZGF0YS5mcmFtZSh5LHgsDQogICAgICAgICAgICAgICAgICAgZ3JwMSxncnAyLA0KICAgICAgICAgICAgICAgICAgIGdycG0xID0gZ3JwX21lYW5zMVtncnAxXSwNCiAgICAgICAgICAgICAgICAgICBncnBtMiA9IGdycF9tZWFuczJbZ3JwMl0sDQogICAgICAgICAgICAgICAgICAgbGFiZWxzMSxsYWJlbHMyKQ0KDQpnZ3Bsb3QoZGF0YSxhZXMoeD14LHk9eSxjb2xvcj1wYXN0ZShsYWJlbHMxLCItIixsYWJlbHMyKSkpICsgDQogIGdlb21fcG9pbnQoKQ0KYGBgDQoNCkhlcmUgd2Ugbm93IGhhdmUgdHdvIHZhcmlhYmxlcyB0aGF0IHdpbGwgYmUgb21pdHRlZDsgKipncnAxKiogYW5kICoqZ3JwMioqLiAgQm90aCBhcmUgY29uc3RhbnQgd2l0aGluIGdyb3Vwcy4gIEdyb3VwIGFzc2lnbm1lbnRzIHdlcmUgc2FtcGxlZCByYW5kb21seSBzdWNoIHRoYXQgb2JzZXJ2YXRpb25zIGhhdmUgbXVsdGlwbGUgbWVtYmVyc2hpcC4gIExldCdzIGVzdGltYXRlIGEgbnVtYmVyIG9mIG1vZGVscyB0byBzZWUgd2hhdCBoYXBwZW5zLg0KDQpgYGB7ciwgcmVzdWx0cz0iYXNpcyJ9DQptMSA8LSBsbSh5IH4geCxkYXRhID0gZGF0YSkNCm0yIDwtIGxtKHkgfiB4ICsgZ3JwMSArIGdycDIsIGRhdGEgPSBkYXRhKQ0KbTMgPC0gbG0oeSB+IHggKyBsYWJlbHMxICsgbGFiZWxzMiwgZGF0YSA9IGRhdGEpDQptNCA8LSBsbSh5IH4geCArIGxhYmVsczEsIGRhdGEgPSBkYXRhKQ0KbTUgPC0gbG0oeSB+IHggKyBsYWJlbHMyLCBkYXRhID0gZGF0YSkNCg0KaHRtbHJlZyhsPWxpc3QobTEsbTIsbTMsbTQsbTUpLGNhcHRpb24gPSAiIixkb2N0eXBlID0gRikNCg0KYGBgDQoNCk1vZGVscyAyIGFuZCAzIGFyZSB0aGUgY29ycmVjdCBzcGVjaWZpY2F0aW9ucy4gIEluIHRoZSBmb3JtZXIgd2UgaW5jbHVkZSB3aGF0IHdlIGFyZSBoZXJlIGNvbnNpZGVyaW5nIG9taXR0ZWQgdmFyaWFibGVzLiAgSW4gdGhlIGxhdHRlciwgd2UgaW5jbHVkZSB0aGUgZ3JvdXAgaWRlbnRpZmllcnMgYXMgY292YXJpYXRlcywgd2hpY2ggYXJlIGFibGUgdG8gInN1Y2sgdXAiIHRoaXMgZm9ybSBvZiBlbmRvZ2VuZWl0eS4gIEluIGFsbCBvdGhlciBtb2RlbHMgd2UgYXJlIGZhY2VkIHdpdGggYSBzcGVjaWZpY2F0aW9uIHByb2JsZW0uICBPZiBwYXJ0aWN1bGFyIG5vdGUgYXJlIE1vZGVscyA0IGFuZCA1IHdoaWNoIGluY2x1ZGUgb25seSBvbmUgc2V0IG9mIGZpeGVkIGVmZmVjdHMuICBJbiB0aGUgZm9ybWVyIHdlIGhhdmUgZm91bmQgYW4gZXhhbXBsZSBvZiAqKmJpYXMgYW1wbGlmaWNhdGlvbioqIC0tIGNvbXBhcmVkIHRvIE1vZGVsIDEgd2hpY2ggaW5jbHVkZWQgbm8gZml4ZWQgZWZmZWN0cywgTW9kZWwgNCBpcyBldmVuIG1vcmUgYmlhc2VkIGRlc3BpdGUgYmVpbmcgImNsb3NlciIgdG8gYW4gYWRlcXVhdGUgc3BlY2lmaWNhdGlvbi4gIEJ5IGNvbnRyYXN0LCBNb2RlbCA1IHJldmVyc2VzIHRoZSBzaWduIG9mIHRoZSBiaWFzLg0KDQpJdCBpcyBzaW1wbGUgdG8gc3BlY2lmeSB0aGlzIHdpdGhpbiBhIHJhbmRvbSBlZmZlY3RzIGZyYW1ld29yayBhcyB3ZWxsLg0KDQpgYGB7ciwgbWVzc2FnZT1GLHdhcm5pbmc9Rn0NCmxpYnJhcnkobG1lNCkNCm02IDwtIGxtZXIoeSB+IHggKyAoMXxsYWJlbHMxKSArICgxfGxhYmVsczIpLCBkYXRhPSBkYXRhKQ0Kc3VtbWFyeShtNikNCmBgYA0KDQpZb3UnbGwgbm90ZSB0aGF0IHRoaXMgaXMgcHJldHR5IGNsb3NlIHRvIHdoYXQgaGFkIGJlZW4gZXN0aW1hdGVkIHdpdGggdGhlIHR3by13YXkgZml4ZWQgZWZmZWN0cyBtb2RlbC4NCg0KQXMgYSBmaW5hbCBleGFtcGxlLCB3ZSB3aWxsIGxvb2sgYXQgdGhlIGNhc2Ugb2Ygb21pdHRlZCB2YXJpYWJsZXMgd2hpY2ggZG8gbm90IHNhdGlzZnkgdGhlICJubyB2YXJpYXRpb24gd2l0aGluIGdyb3VwIiByZXF1aXJlbWVudCBieSBhZGFwdGluZyB0aGUgYWJvdmUuDQoNCmBgYHtyLCBtZXNzYWdlPUYsIHdhcm5pbmc9RiwgcmVzdWx0cz0iYXNpcyJ9DQpzZXQuc2VlZCgxMjM0KQ0KDQpub2JzIDwtIDEwMDANCm5fZzEgPC0gNA0Kbl9nMiA8LSA4DQoNCmdycDEgPC0gc2FtcGxlKDE6bl9nMSxub2JzLHJlcGxhY2UgPSBUKQ0KZ3JwMiA8LSBzYW1wbGUoMTpuX2cyLG5vYnMscmVwbGFjZSA9IFQpDQoNCmxhYmVsczEgPC0gbGV0dGVyc1tncnAxXQ0KbGFiZWxzMiA8LSBsZXR0ZXJzWzI2LWdycDJdDQoNCmdycF9tZWFuczEgPC0gcm5vcm0obl9nMSwwLDIpDQpncnBfbWVhbnMyIDwtIHJub3JtKG5fZzIsMCwyKQ0KDQp4MSA8LSBybm9ybShub2JzLGdycF9tZWFuczFbZ3JwMV0gKyBncnBfbWVhbnMyW2dycDJdKQ0KeDIgPC0geDEgKyBybm9ybShub2JzKQ0KZXJyIDwtIHJub3JtKG5vYnMpDQoNCnkgPC0geDEgKyB4MiArIGdycDEgLSBncnAyICsgZXJyDQoNCmRhdGEgPC0gZGF0YS5mcmFtZSh5LHgsZ3JwMSxncnAyLGdycF9tZWFuczFbZ3JwMV0sZ3JwX21lYW5zMltncnAyXSxsYWJlbHMxLGxhYmVsczIpDQoNCm03IDwtIGxtKHkgfiB4MSArIHgyICsgbGFiZWxzMSArIGxhYmVsczIsIGRhdGEgPSBkYXRhKQ0KbTggPC0gbG0oeSB+IHgxICsgbGFiZWxzMSArIGxhYmVsczIsIGRhdGEgPSBkYXRhKQ0KaHRtbHJlZyhsaXN0KG03LG04KSxkb2N0eXBlID0gRixjYXB0aW9uID0gIiIpDQpgYGANCg0KSGVyZSAqKngyKiogaXMgYW4gb21pdHRlZCB2YXJpYWJsZS4gIFdoZW4gaXQgaXMgaW5jbHVkZWQgaW4gdGhlIHNwZWNpZmljYXRpb24gZXZlcnl0aGluZyBpcyBrb3NoZXIgd2hpbGUgd2hlbiBpdCBpcyByZW1vdmVkIHRoZSBmaXhlZCBlZmZlY3RzIGRvIG5vdGhpbmcgdG8gcmVtZWR5IHRoZSBwcm9ibGVtLg0KDQpUaGVyZSBhcmUgb3RoZXIgc3BlY2lmaWMgY29udGV4dHMgaW4gd2hpY2ggZml4ZWQvcmFuZG9tIGVmZmVjdHMgd2lsbCBmYWlsIHRvIHByb3ZpZGUgdW5iaWFzZWQgZXN0aW1hdGVzIG9mIHRyZWF0bWVudCBlZmZlY3RzLiAgU2VlIFtJbWFpIGFuZCBLaW0gKDIwMTkpXShodHRwczovL2ltYWkuZmFzLmhhcnZhcmQuZWR1L3Jlc2VhcmNoL2ZpbGVzL0ZFbWF0Y2gucGRmKSBmb3IgYSBkaXNjdXNzaW9uIHJlZ2FyZGluZyBob3cgdGhpcyBsaW1pdHMgYXBwbGljYXRpb25zIHRvIGxvbmdpdHVkaW5hbCBkYXRhIGluIHBhcnRpY3VsYXIuDQoNCiMjIyBRdWljayBBc2lkZTogV2hhdCBpZiBsYWJlbHMgd2VyZSBvbWl0dGVkIHRvbz8NCg0KSW4gdGhlIGFib3ZlIHdlIHNhdyB0aGF0LCBpbnNvZmFyIGFzIG9taXR0ZWQgZmFjdG9ycyBhcmUgaW52YXJpYW50IHdpdGhpbiBncm91cHMsIHRoYXQgdGhleSBtYXkgYmUgY2FwdHVyZWQgdXNpbmcga25vd2xlZGdlIG9mIGdyb3VwIG1lbWJlcnNoaXAuICBCdXQgd2hhdCBpZiB3ZSBkb24ndCBrbm93IHRoYXQgZWl0aGVyPyAgV2hpbGUgc29tZXdoYXQgb3V0c2lkZSB0aGUgc2NvcGUgb2YgdGhlIGNsYXNzLCB0aGlzIHRvdWNoZXMgb24gYSBjbG9zZWx5IHJlbGF0ZWQgZmFtaWx5IG9mICoqbGF0ZW50IHZhcmlhYmxlIG1vZGVscyoqLiAgSW4gcGFydGljdWxhciwgdGhlcmUgaXMgYSBjbGVhbiBicmlkZ2UgdG8gKiptaXh0dXJlIG1vZGVscyoqIGluIHdoaWNoIGl0IGlzIHN1c3BlY3RlZCBvciBrbm93biB0aGF0IHN1YnBvcHVsYXRpb25zIGV4aXN0IHdpdGhpbiB0aGUgc2FtcGxlLCBidXQgdGhlIG1lbWJlcnNoaXAgd2l0aGluIHN1Y2ggbW9kZWxzIGlzIHVua25vd24uICBUaGVyZSBpcyBhIGNvb2wgaWxsdXN0cmF0aW9uIGF2YWlsYWJsZSBbaGVyZV0oaHR0cHM6Ly90b3dhcmRzZGF0YXNjaWVuY2UuY29tL21peHR1cmUtbW9kZWxsaW5nLWZyb20tc2NyYXRjaC1pbi1yLTVhYjdiZmM4M2VlZikuDQoNCg0KIyMgT3B0aW9uYWwgU2VsZiBTdHVkeSBQcmFjdGljZQ0KDQpUaGUgYmVzdCB3YXkgdG8gbGVhcm4gUiBpcyB0byB1c2UgUiwgYW5kIHRoZSBiZXN0IHdheSB0byByZWFsbHkgdW5kZXJzdGFuZCBtZXRob2RzIGlzIHRvIHBva2UgYXJvdW5kIGF0IHRoZW0gZWl0aGVyIHdpdGggdGhlIG1hdGhlbWF0aWNhbCB0aGVvcnkgb3Igc2ltdWxhdGlvbnMuICBJIHN1Z2dlc3QgY29uc2lkZXJpbmcgdGhlIGZvbGxvd2luZyBxdWVzdGlvbnM6DQoNCjEuIEFib3ZlIHdlIHNhdyB0aGF0IHdoZW4gdGhlIG9taXR0ZWQgdmFyaWFibGVzIGFyZSBjb25zdGFudCB3aXRoaW4gZ3JvdXBzIHRoYXQgZml4ZWQvcmFuZG9tIGVmZmVjdHMgYXJlIGFwcHJvcHJpYXRlIHdoaWxlIHdoZW4gdGhleSB2YXJ5IHdpdGhpbiBncm91cHMgdGhleSBhcmUgbm90LiAgUnVuIHNpbXVsYXRpb25zIHRvIGFzc2VzcyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdmFyaWFiaWxpdHkgb2YgYW4gb21pdHRlZCBjb250aW51b3VzIGNvdmFyaWF0ZSBhbmQgdGhlIGV4dGVudCBvZiBiaWFzLg0KMi4gSW4gdGhlIGFib3ZlIHdlIHNhdyB0aGF0IG9ubHkgc3BlY2lmeWluZyBwYXJ0IG9mIHRoZSBncm91cGluZyBzdHJ1Y3R1cmUgY2FuIGFtcGxpZnkgYmlhcy4gIFJldmlzaXQgdGhlIEZyaXNjaC1XYXVnaC1Mb3ZlbGwgdGhlb3JlbSBmcm9tIGxhc3QgdGltZSBhbmQgZXhhbWluZSB0aGUgcGFydGlhbCByZWxhdGlvbnNoaXAgYmV0d2VlbiB5IGFuZCB4LiAgRG8geW91IG5vdGljZSBhbnl0aGluZyBwbG90dGluZyB0aGUgcmVzaWR1YWxzIGFnYWluc3QgZWFjaCBvdGhlcj8gDQozLiBbR2liYm9ucyBldCBhbC4gKDIwMTgpXShodHRwczovL3d3dy5kZWdydXl0ZXIuY29tL3ZpZXcvam91cm5hbHMvamVtLzgvMS9hcnRpY2xlLTIwMTcwMDAyLnhtbCkgc2hvdyB0aGF0IHdoZW4gdHJlYXRtZW50IGVmZmVjdHMgYXJlIGhldGVyb2dlbm91cyAodGhpbmsgcmFuZG9tIHNsb3BlcykgdGhhdCB0cmFkaXRpb25hbCBmaXhlZCBlZmZlY3RzIGVzdGltYXRlcyAoaS5lLiBvbmx5IGludHJvZHVjaW5nIGludGVyY2VwdHMpIGlzIGdlbmVyYWxseSBub3QgYSBjb25zaXN0ZW50IGVzdGltYXRvci4gIERlbW9uc3RyYXRlIHRoaXMgYW5kIGNvbm5lY3QgdGhlIHJlc3VsdCBiYWNrIHRvIG9taXR0ZWQgdmFyaWFibGVzLg0KNC4gVGhlIG9iamVjdHMgKiptMyoqIGFuZCAqKm02KiogY29udGFpbiBmaXhlZCBhbmQgcmFuZG9tIGVmZmVjdCBlc3RpbWF0ZXMgb2YgdGhlIG11bHRpbWVtYmVyc2hpcCBtb2RlbCB1c2VkIGFib3ZlLiAgVXNlIHRoZSBkYXRhIGF1Z21lbnRhdGlvbiB0cmljayB0byBzaG93IHRoYXQgdGhlIGZvcm1lciBpcyBhbiB1bnJlZ3VsYXJpemVkIHZlcnNpb24gb2YgdGhlIGxhdHRlci4=