Causal inference using fixed effects panel models
Causal inference includes a variety of approaches that seek to identify causal relationships between variables. The idea is to combine theory, logic, and robust statistical approaches to isolate a causal effect (i.e., how a change in x causes a change in y). There are many statistical approaches that can be used to infer causal relationships (see https://mixtape.scunning.com/ for a broader introduction into causal inference). Here I focus on a linear model that has often been used to estimate causal relationships – the fixed effects (FE) panel model.
FE panel models, often referred to as within-estimator models, leverage panel data to estimate causal relationships. Panel data are also referred to as longitudinal or time series data with time period ≥ 2. FE panel models can enable causal inference if certain conditions are met. FE panel models are increasingly applied to conservation and ecological studies, and various packages to estimate these models are being developed and revised in R; it’s a fast-moving area of development both in the literature and the various statistical software we use.
Broadly, the FE panel model approach divides all possible variables (i.e., both the observed and unobserved variables in a study) into time-varying and time-invariant. Simply put, time-varying means that the observed values change through time and time-invariant means that the observed values don’t change through time.
A simple FE panel model can be written as follows: \[
Y_{it} \sim \alpha + \beta X_{it} + c_i + y_t+ \epsilon_{it}
\] Where Yit is the dependent variable (observed values from observational unit i at time t; for simplicity, from here on I use “plot” as the observational unit and “year” as the time period), α is the intercept, β is the coefficient of the time-varying explanatory variable (the hypothesized causal relationship of interest), ci is the heterogeneity associated with the unobserved, time-invariant variables unique to each plot, γt represents the heterogeneity associated with the unobserved, time-varying variables unique to each year and shared by all plots, and ɛit is the random error term (see https://doi.org/10.1111/2041-210X.13190).
Whether a variable is time-invariant or time-varying largely depends on the study system and spatial distribution of plots. Topography and soil type are typically considered time-invariant (unless of course a volcano erupts or major landslide occurs). The classification of most other variables depends on 1) the observed variable itself (i.e., species abundance can vary more than presence/absence), 2) the study design, and 3) the unique characteristics of the system of interest.
For example, in longitudinal studies with observations from plots located close together in space, there may be very little variation in rainfall across plots but high variation in rainfall across years. In this case, variation in rainfall is largely captured by year fixed effects. In contrast, if there’s high spatial variation across plots (e.g., the plots were established across large topographic gradients), then rainfall would vary by plot and would be estimated as a time-varying explanatory variable. Furthermore, it’s critical to consider whether there are unobserved, time-varying and time-invariant variables. For example, maybe there was an insect outbreak in a subset of plots that wasn’t captured by the observed variables. If and when these time-varying variables exist, additional tests can be done to determine the likelihood of bias due to their presence. These unobserved, time-varying variables are the major limitation of FE panel models and can lead to biased estimates of the causal relationship of interest.
The major advantage of an FE panel model is that unobserved, time-invariant variables are subtracted from the model, which can allow for more causal estimates of underlying relationships (if unobserved, time-varying variables are not biasing the estimates). Because it’s often impossible to control for all unobserved, time-varying variables in observational settings, coefficient estimates should always be carefully interpreted. Still, FE panel models offer an important step towards estimating causal relationships in ecology.
Centering and standardizing vs. demeaning
The FE panel model eliminates unobserved, time-invariant variables through a simple mathematical process of unit-level demeaning, using the within transformation (hence the alternative name to FE panel model – the within-estimator panel data model). Demeaning enables FE panel models to control for time-invariant measured and unmeasured variables, as well as time-varying variables that are collinear with time period (I’ll explain this further below), that may otherwise be confounding the underlying causal relationship a researcher is seeking to estimate. FE panel models essentially reduce the variation in the observed variables to deviations from plot- and year-level means and use this variation (which has now controlled for time-invariant, unobserved variable bias) to estimate the coefficients.
I’ll explain this demeaning process by comparing it to standardization of non-binary variables, often used prior to estimating statistical models in ecology (thereby increasing the interpretability of coefficients and enabling comparison of coefficient magnitude within and across models). The fundamental difference is that standardizing independent variables in ecology demeans (centers the data) across all of the observations, and often across all time periods, whereas demeaning in the FE panel model context subtracts out the mean from each individual- or plot-level observation. To demonstrate this, I create a simulated dataset with annual temperature and precipitation values measured at each plot across 20 years, as well plot-level elevation and year variables.
## creating a panel dataset with plot-level observations (n = 10 plots) across 20 years
##empty dataframe
paneldata = data.frame()
##dataset for loop
for (i in 1:20){
elevation <- seq(1100,2000, by=100)
plot <- seq(1:10)
year <- as.integer(rep(paste(i), 10))
richness <- sample(x = 1:16, replace = T, size = 10)
precip <- sample(x = 200:500, size = 10)
temps <- sample(x=3:15, replace = T, size = 10)
mergedata <- data.frame(plot, year, elevation, richness, precip, temps)
paneldata = rbind(paneldata, mergedata)
}
(Side note: economists often use “cross-sectional data” to describe a dataset with observations from one time period vs. “panel data” to describe a dataset that includes repeated observations from each observed unit over multiple periods of time.)
## A cross-sectional dataset example:
cross_sectional_dataset <- filter(paneldata, year==1)
Standardizing explanatory variables using the z-transformation first centers the data and then divides by the standard deviation.
center <- paneldata %>%
mutate(temps_centered = temps-mean(temps),
temps_standardized = (temps-mean(temps))/sd(temps),
elevation_centered = elevation-mean(elevation),
elevation_standardized = (elevation-mean(elevation))/sd(elevation)) %>%
select(plot, year, elevation, temps_centered, elevation_centered, elevation_standardized)
head(center)
## plot year elevation temps_centered elevation_centered elevation_standardized
## 1 1 1 1100 -0.34 -450 -1.5627772
## 2 2 1 1200 -1.34 -350 -1.2154934
## 3 3 1 1300 -5.34 -250 -0.8682096
## 4 4 1 1400 -4.34 -150 -0.5209257
## 5 5 1 1500 -4.34 -50 -0.1736419
## 6 6 1 1600 -6.34 50 0.1736419
Notice the variation of all explanatory variables is largely maintained. This contrasts to demeaning in the FE panel model context, which seeks to eliminate the variation of time-invariant explanatory variables (elevation is a time-invariant explanatory variable).
To eliminate the variation associated with time-invariant variables, FE panel models can demean the data by centering variables at the plot- and year-level. While demeaning is often implemented using matrix algebra, to demonstrate the underlying idea, I’ll give an overly simplistic example. To demean at the plot-level, we first calculate the average richness, temperature, and precipitation for each plot. Then, we simply subtract out these means from the plot-level observations from each year – resulting in plot-level deviations across 20 years for all variables estimated in the model.
demeaningPlot <- paneldata %>%
##first demeaning by plot
group_by(plot)%>%
mutate(meanp = mean(precip), meant = mean(temps),
meanelev = mean(elevation), meanr = mean(richness)) %>%
mutate(precip_demean = precip-meanp, temps_demean = temps-meant,
richness_demean=richness-meanr, elevation_demean=elevation-meanelev) %>%
select(plot, year, elevation, temps_demean, elevation_demean, richness_demean)
head(demeaningPlot)
## # A tibble: 6 × 6
## # Groups: plot [6]
## plot year elevation temps_demean elevation_demean richness_demean
## <int> <int> <dbl> <dbl> <dbl> <dbl>
## 1 1 1 1100 -0.100 0 4.9
## 2 2 1 1200 -2 0 -5.6
## 3 3 1 1300 -6.05 0 -2.5
## 4 4 1 1400 -3.35 0 -0.85
## 5 5 1 1500 -3.45 0 6.05
## 6 6 1 1600 -6.95 0 -1.55
## Notice that using the within-estimator demeaning, elevation is 0; it's time-invariant.
FE panel models also simultaneously demean variables from each time period. That is, all variables have a mean across all plots in a given year, so the resulting variables in the FE transformation, both the explanatory and outcome variables, are demeaned at the plot and year-levels.
In practice, there are at least three within transformations (for brief descriptions, refer to https://en.wikipedia.org/wiki/Fixed_effects_model). Depending on the package and estimator used, there may not be any demeaning prior to estimating the model, as estimating a plot-level coefficient estimate is mathematically equivalent to demeaning. However, particularly when using large datasets, different packages, like fixest, avoid estimating plot-level coefficients because it’s highly cumbersome for large datasets.
Fixed effects (FE) panel models
Simply speaking, FE panel models are often linear models that can be estimated using a variety of packages and software. I’ll use two estimators here for explanation and comparison: 1) the function feols from fixest package (see https://cran.r-project.org/web/packages/fixest/fixest.pdf), and 2) the function lm from R stats. I like using the fixest package as it’s one of the more developed packages for these models in R and more efficient when using large datasets, though it too is evolving rapidly. Both the lm and feols functions estimate models slightly differently, resulting in the same coefficient estimates with small differences in standard errors. (Side note: these models have very different R^2s, which I’ll ignore for now, since we’re less interested in model prediction and fit and much more interested in the underlying causal relationship of the explanatory variables and the outcome variable).
FE panel models using feols
## The FE panel model using the feols function from the fixest package
fe_mod <- feols(richness ~ temps + precip | plot + year,
data = paneldata)
summary(fe_mod)
## OLS estimation, Dep. Var.: richness
## Observations: 200
## Fixed-effects: plot: 10, year: 20
## Standard-errors: Clustered (plot)
## Estimate Std. Error t value Pr(>|t|)
## temps -0.086097 0.103841 -0.829126 0.428474
## precip -0.008461 0.003995 -2.117601 0.063284 .
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## RMSE: 4.42784 Adj. R2: 0.007905
## Within R2: 0.028072
The FE panel model I am using here estimates richness (the outcome variable), as a function of temperature and precipitation (i.e., the time-varying explanatory variables) and includes plot and year as the fixed effects (i.e., the dummy variables). Observed time-invariant variables (in this case elevation) are not included because time-invariant variables are dropped during demeaning (they are omitted anyway if included in the model (see side note below)).
## Side note: if you add in elevation, the time-invariant variable, you can see a warning
## message that it's dropped from the model due to collinearity
fe_mod_elev <- feols(richness ~ temps + precip + elevation | plot + year,
data = paneldata)
## The variable 'elevation' has been removed because of collinearity (see $collin.var).
The feols estimator is based off of Berge (2018). The core of this algorithm is based on a general ML model that “integrates a fixed-point acceleration method to hasten the convergence of the fixed-effect coefficients.” In addition, while there’s ongoing debate about whether and how to cluster standard errors – often used to control for bias associated with spatial correlation and experimental or observational designs that are clustered – in feols, standard errors are clustered by default using the fixed effects in the order they are entered into R. You can also use the vcov argument or other specifications from the package clubSandwich. In ecological settings, data are often nested within plot and/or spatially correlated, so clustering standard errors, by plot for example, should typically be included.
In this specific example, the FE model is essentially estimating deviation from plot- and year-level means of the explanatory variable (richness) as a function of the deviations of the time-varying explanatory variables (temperature and precipitation). The plot fixed effect is controlling for the time-invariant unobserved variables correlated with any variables in the model (i.e., both the explanatory and dependent variables), and the year fixed effect is controlling for variables that changed through time but only if the change was the same across plots (these could include atmospheric C02 fluctuations, solar radiation, etc). Time-varying variables that affect only certain plots, which might include weather variables, fire occurrence, defoliators, are NOT controlled for in the demeaning process.
FE panel models using lm
Below is an example of fixed effects panel model using lm with plot and year as factors (i.e., factoring the variables transforms them to dummy variables). The intercept is not shown to match the feols summary table; the intercept is difficult to estimate in large datasets and therefore often not reported. The ordering of the factors using lm is not important, since lm does not cluster standard errors by default.
## FE panel model using lm
fe_mod_lm <- lm(richness ~ temps + precip + factor(plot) + factor(year) -1,
data = paneldata)
summary(fe_mod_lm)
##
## Call:
## lm(formula = richness ~ temps + precip + factor(plot) + factor(year) -
## 1, data = paneldata)
##
## Residuals:
## Min 1Q Median 3Q Max
## -11.1847 -3.5914 0.4511 3.2809 8.9024
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## temps -0.086097 0.095325 -0.903 0.3677
## precip -0.008461 0.004360 -1.941 0.0540 .
## factor(plot)1 10.311536 2.518060 4.095 6.53e-05 ***
## factor(plot)2 12.805263 2.517997 5.085 9.66e-07 ***
## factor(plot)3 12.345759 2.415237 5.112 8.57e-07 ***
## factor(plot)4 12.817174 2.443714 5.245 4.63e-07 ***
## factor(plot)5 12.454948 2.312967 5.385 2.40e-07 ***
## factor(plot)6 11.694272 2.499588 4.678 5.89e-06 ***
## factor(plot)7 11.780684 2.496909 4.718 4.97e-06 ***
## factor(plot)8 13.701533 2.367085 5.788 3.38e-08 ***
## factor(plot)9 11.816251 2.494369 4.737 4.57e-06 ***
## factor(plot)10 14.066950 2.443850 5.756 3.96e-08 ***
## factor(year)2 1.422366 2.157508 0.659 0.5106
## factor(year)3 1.544412 2.157009 0.716 0.4750
## factor(year)4 1.654800 2.161139 0.766 0.4449
## factor(year)5 0.945296 2.164300 0.437 0.6628
## factor(year)6 3.293183 2.155092 1.528 0.1284
## factor(year)7 1.630927 2.169216 0.752 0.4532
## factor(year)8 1.807964 2.161372 0.836 0.4041
## factor(year)9 1.129838 2.186885 0.517 0.6061
## factor(year)10 -1.950716 2.155674 -0.905 0.3668
## factor(year)11 -1.821751 2.159952 -0.843 0.4002
## factor(year)12 0.317525 2.162365 0.147 0.8834
## factor(year)13 3.791207 2.160238 1.755 0.0811 .
## factor(year)14 0.486082 2.157050 0.225 0.8220
## factor(year)15 1.441576 2.157104 0.668 0.5049
## factor(year)16 0.648251 2.172606 0.298 0.7658
## factor(year)17 0.096238 2.167887 0.044 0.9646
## factor(year)18 -0.757660 2.164398 -0.350 0.7267
## factor(year)19 1.459348 2.168078 0.673 0.5018
## factor(year)20 -0.104364 2.154683 -0.048 0.9614
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 4.817 on 169 degrees of freedom
## Multiple R-squared: 0.8244, Adjusted R-squared: 0.7922
## F-statistic: 25.59 on 31 and 169 DF, p-value: < 2.2e-16
## combining these model coefficients to compare them
fe_res <- data.frame(coeftable(fe_mod), model="feols summary")
lm_res <- data.frame(summary(fe_mod_lm)$coefficient[c(1:2),c(1:4)], model ="lm summary")
list(fe_res, lm_res)
## [[1]]
## Estimate Std..Error t.value Pr...t.. model
## temps -0.086097314 0.1038410 -0.8291263 0.42847427 feols summary
## precip -0.008460664 0.0039954 -2.1176014 0.06328369 feols summary
##
## [[2]]
## Estimate Std..Error t.value Pr...t.. model
## temps -0.086097314 0.095324662 -0.9032008 0.36770490 lm summary
## precip -0.008460664 0.004359554 -1.9407179 0.05395646 lm summary
You can see that the lm and foels estimators produce the same coefficient estimates, but with slightly different standard errors and corresponding t-values and p-values. The reason that they are producing the same coefficient estimates is that mathematically, the plot and year coefficients are the same as if these models were demeaned first before being estimated. The reason they produce different standard errors is due to the underlying estimator engine and the default clustering of the standard errors in feols. In theory, both lm (and alternatively glm) and feols estimations are correct; therefore it’s incumbent on the researcher to decide which estimator to use both in R and across other statistical software (often comes down to efficiency and familiarity).
Difference between FE panel models and glmms
Now I will compare fixed effects panel models (using feols) to mixed models, specifically generalized linear mixed models (glmms) that are widely used in ecology. Notice I include elevation as an explanatory variable to demonstrate that glmms estimate both time-invariant and time-varying variables when included as covariates, which contrasts to the FE panel model using feols that drops time-invariant variables through demeaning.
Side note and warning: the following explanation may cause further confusion than good. The differences between mixed models in ecology and fixed effects models in econ can seem confusing due in part to the fact that fixed effects are defined very differently. For example, a fixed effect in a glmm is more equivalent to an explanatory variable in an FE panel model than a fixed effect in a FE panel model, whereas a random effect in a glmm would more likely be estimated as a fixed effect in a panel model (for more detail https://en.wikipedia.org/wiki/Fixed_effects_model).
## GLMM: A glmm using random effects for year and plot
glmm_res_A <- lmer(richness~ temps + precip + elevation + (1|plot) + (1|year),
data = paneldata)
## boundary (singular) fit: see ?isSingular
summary(glmm_res_A)
## Linear mixed model fit by REML ['lmerMod']
## Formula: richness ~ temps + precip + elevation + (1 | plot) + (1 | year)
## Data: paneldata
##
## REML criterion at convergence: 1212.8
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -2.1658 -0.7560 0.1085 0.8207 1.7819
##
## Random effects:
## Groups Name Variance Std.Dev.
## year (Intercept) 0.000e+00 0.000e+00
## plot (Intercept) 8.183e-15 9.046e-08
## Residual 2.276e+01 4.771e+00
## Number of obs: 200, groups: year, 20; plot, 10
##
## Fixed effects:
## Estimate Std. Error t value
## (Intercept) 10.347513 2.488097 4.159
## temps -0.096800 0.088742 -1.091
## precip -0.007959 0.003964 -2.008
## elevation 0.001809 0.001176 1.538
##
## Correlation of Fixed Effects:
## (Intr) temps precip
## temps -0.289
## precip -0.570 -0.100
## elevation -0.765 0.018 0.046
## optimizer (nloptwrap) convergence code: 0 (OK)
## boundary (singular) fit: see ?isSingular
I’ll focus on the differences between FE panel models and glmms relevant to causal inference. First, FE panel models control for all unobserved time-invariant variables. Though the random effects in glmms help control for much of the unobserved variable bias (for example, the unobserved variables correlated with plot and year), they cannot control for the possibility that these unobserved variables are also correlated with the explanatory variables (see https://doi.org/10.1111/2041-210X.13190). For instance, unobserved time invariant variables (let’s use soil type) may be correlated both with plot AND the explanatory variables, precip and temperature. Including the random effect of plot only controls for the correlation between soil type and plot, not the correlation between soil type and precip and soil type and temp. Thus, in the random effects glmm model above, correlations between unobserved variables and the explanatory variables are captured in the error term, resulting in biased coefficient estimates of precip and temp.
Second, glmms cannot control for severe multicollinearity among the observed explanatory variables. In contrast, FE panel models can control for severe multicollinearity induced by time-invariant variables. If temperature and precipitation are highly correlated with elevation, for example, elevation would likely have a very high variance inflation factor (VIF) https://www.tandfonline.com/doi/abs/10.1081/QEN-120001878. The higher the VIF, the larger the SEs, resulting in less precise and interpretable coefficient estimates. If there’s a strong correlation between a time-invariant (e.g., elevation) and time-varying variable (e.g., temperature), FE panel models provide a useful solution, as they subtract out the time-invariant variable, thereby estimating a more precise coefficient of the time-varying variable. This is of course much preferable to omitting the problematic variable when the VIF is too high, as it increases the interpretability and precision of the coefficient estimate.
Finally, one of the main advantages of FE panel models, other than they often provide less biased coefficients of explanatory variables than a glmm, is that it can be used to estimate a counterfactual scenario – a world where the treatment didn’t occur. This counterfactual can be equated to a control treatment in an experiment. Because the coefficient estimates in a FE panel model are capturing less biased estimates of the causal relationship of interest, they can be used to estimate a world in which one or more of these explanatory variables didn’t change through time. This counterfactual thus resembles a control in an experimental setting and the difference between control and treatment can be estimated.
FE panel model limitations
There are two major limitations of FE panel models. First, an FE panel model is fairly useless when predicting out-of-sample. If prediction is the main focus of an analysis, using a random effects model like a glmm that estimates the variance associated with plots can facilitate out-of-sample predictions (with the caveat that these predictions are likely biased). Second, FE panel models cannot control for unobserved, time-varying variables, which in some settings, means they are likely less useful than a glm(m).
LS0tCnRpdGxlOiAiRml4ZWQgZWZmZWN0cyBwYW5lbCBtb2RlbHMgaW4gZWNvbG9neSIKYXV0aG9yOiAiSm9hbiBEdWRuZXkiCmRhdGU6ICIxMS80LzIwMjEiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgdG9jOiB0cnVlCiAgd29yZF9kb2N1bWVudDogZGVmYXVsdAotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCmBgYAoKIyMgQ2F1c2FsIGluZmVyZW5jZSB1c2luZyBmaXhlZCBlZmZlY3RzIHBhbmVsIG1vZGVscwpDYXVzYWwgaW5mZXJlbmNlIGluY2x1ZGVzIGEgdmFyaWV0eSBvZiBhcHByb2FjaGVzIHRoYXQgc2VlayB0byBpZGVudGlmeSBjYXVzYWwgcmVsYXRpb25zaGlwcyBiZXR3ZWVuIHZhcmlhYmxlcy4gVGhlIGlkZWEgaXMgdG8gY29tYmluZSB0aGVvcnksIGxvZ2ljLCBhbmQgcm9idXN0IHN0YXRpc3RpY2FsIGFwcHJvYWNoZXMgdG8gaXNvbGF0ZSBhIGNhdXNhbCBlZmZlY3QgKGkuZS4sIGhvdyBhIGNoYW5nZSBpbiB4IGNhdXNlcyBhIGNoYW5nZSBpbiB5KS4gVGhlcmUgYXJlIG1hbnkgc3RhdGlzdGljYWwgYXBwcm9hY2hlcyB0aGF0IGNhbiBiZSB1c2VkIHRvIGluZmVyIGNhdXNhbCByZWxhdGlvbnNoaXBzIChzZWUgaHR0cHM6Ly9taXh0YXBlLnNjdW5uaW5nLmNvbS8gZm9yIGEgYnJvYWRlciBpbnRyb2R1Y3Rpb24gaW50byBjYXVzYWwgaW5mZXJlbmNlKS4gSGVyZSBJIGZvY3VzIG9uIGEgbGluZWFyIG1vZGVsIHRoYXQgaGFzIG9mdGVuIGJlZW4gdXNlZCB0byBlc3RpbWF0ZSBjYXVzYWwgcmVsYXRpb25zaGlwcyAtLSB0aGUgZml4ZWQgZWZmZWN0cyAoRkUpIHBhbmVsIG1vZGVsLgoKRkUgcGFuZWwgbW9kZWxzLCBvZnRlbiByZWZlcnJlZCB0byBhcyB3aXRoaW4tZXN0aW1hdG9yIG1vZGVscywgbGV2ZXJhZ2UgcGFuZWwgZGF0YSB0byBlc3RpbWF0ZSBjYXVzYWwgcmVsYXRpb25zaGlwcy4gUGFuZWwgZGF0YSBhcmUgYWxzbyByZWZlcnJlZCB0byBhcyBsb25naXR1ZGluYWwgb3IgdGltZSBzZXJpZXMgZGF0YSB3aXRoIHRpbWUgcGVyaW9kIOKJpSAyLiBGRSBwYW5lbCBtb2RlbHMgY2FuIGVuYWJsZSBjYXVzYWwgaW5mZXJlbmNlIGlmIGNlcnRhaW4gY29uZGl0aW9ucyBhcmUgbWV0LiBGRSBwYW5lbCBtb2RlbHMgYXJlIGluY3JlYXNpbmdseSBhcHBsaWVkIHRvIGNvbnNlcnZhdGlvbiBhbmQgZWNvbG9naWNhbCBzdHVkaWVzLCBhbmQgdmFyaW91cyBwYWNrYWdlcyB0byBlc3RpbWF0ZSB0aGVzZSBtb2RlbHMgYXJlIGJlaW5nIGRldmVsb3BlZCBhbmQgcmV2aXNlZCBpbiBSOyBpdCdzIGEgZmFzdC1tb3ZpbmcgYXJlYSBvZiBkZXZlbG9wbWVudCBib3RoIGluIHRoZSBsaXRlcmF0dXJlIGFuZCB0aGUgdmFyaW91cyBzdGF0aXN0aWNhbCBzb2Z0d2FyZSB3ZSB1c2UuIAoKQnJvYWRseSwgdGhlIEZFIHBhbmVsIG1vZGVsIGFwcHJvYWNoIGRpdmlkZXMgYWxsIHBvc3NpYmxlIHZhcmlhYmxlcyAoaS5lLiwgYm90aCB0aGUgb2JzZXJ2ZWQgYW5kIHVub2JzZXJ2ZWQgdmFyaWFibGVzIGluIGEgc3R1ZHkpIGludG8gdGltZS12YXJ5aW5nIGFuZCB0aW1lLWludmFyaWFudC4gU2ltcGx5IHB1dCwgdGltZS12YXJ5aW5nIG1lYW5zIHRoYXQgdGhlIG9ic2VydmVkIHZhbHVlcyBjaGFuZ2UgdGhyb3VnaCB0aW1lIGFuZCB0aW1lLWludmFyaWFudCBtZWFucyB0aGF0IHRoZSBvYnNlcnZlZCB2YWx1ZXMgZG9uJ3QgY2hhbmdlIHRocm91Z2ggdGltZS4gCgpBIHNpbXBsZSBGRSBwYW5lbCBtb2RlbCBjYW4gYmUgd3JpdHRlbiBhcyBmb2xsb3dzOgokJApZX3tpdH0gXHNpbSBcYWxwaGEgKyBcYmV0YSBYX3tpdH0gKyBjX2kgKyB5X3QrIFxlcHNpbG9uX3tpdH0KJCQKV2hlcmUgWWl0IGlzIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUgKG9ic2VydmVkIHZhbHVlcyBmcm9tIG9ic2VydmF0aW9uYWwgdW5pdCBpIGF0IHRpbWUgdDsgZm9yIHNpbXBsaWNpdHksIGZyb20gaGVyZSBvbiBJIHVzZSAicGxvdCIgYXMgdGhlIG9ic2VydmF0aW9uYWwgdW5pdCBhbmQgInllYXIiIGFzIHRoZSB0aW1lIHBlcmlvZCksIM6xIGlzIHRoZSBpbnRlcmNlcHQsIM6yIGlzIHRoZSBjb2VmZmljaWVudCBvZiB0aGUgdGltZS12YXJ5aW5nIGV4cGxhbmF0b3J5IHZhcmlhYmxlICh0aGUgaHlwb3RoZXNpemVkIGNhdXNhbCByZWxhdGlvbnNoaXAgb2YgaW50ZXJlc3QpLCBjaSBpcyB0aGUgaGV0ZXJvZ2VuZWl0eSBhc3NvY2lhdGVkIHdpdGggdGhlIHVub2JzZXJ2ZWQsIHRpbWUtaW52YXJpYW50IHZhcmlhYmxlcyB1bmlxdWUgdG8gZWFjaCBwbG90LCDOs3QgcmVwcmVzZW50cyB0aGUgaGV0ZXJvZ2VuZWl0eSBhc3NvY2lhdGVkIHdpdGggdGhlIHVub2JzZXJ2ZWQsIHRpbWUtdmFyeWluZyB2YXJpYWJsZXMgdW5pcXVlIHRvIGVhY2ggeWVhciBhbmQgc2hhcmVkIGJ5IGFsbCBwbG90cywgYW5kIMmbaXQgaXMgdGhlIHJhbmRvbSBlcnJvciB0ZXJtIChzZWUgaHR0cHM6Ly9kb2kub3JnLzEwLjExMTEvMjA0MS0yMTBYLjEzMTkwKS4gCgpXaGV0aGVyIGEgdmFyaWFibGUgaXMgdGltZS1pbnZhcmlhbnQgb3IgdGltZS12YXJ5aW5nIGxhcmdlbHkgZGVwZW5kcyBvbiB0aGUgc3R1ZHkgc3lzdGVtIGFuZCBzcGF0aWFsIGRpc3RyaWJ1dGlvbiBvZiBwbG90cy4gVG9wb2dyYXBoeSBhbmQgc29pbCB0eXBlIGFyZSB0eXBpY2FsbHkgY29uc2lkZXJlZCB0aW1lLWludmFyaWFudCAodW5sZXNzIG9mIGNvdXJzZSBhIHZvbGNhbm8gZXJ1cHRzIG9yIG1ham9yIGxhbmRzbGlkZSBvY2N1cnMpLiBUaGUgY2xhc3NpZmljYXRpb24gb2YgbW9zdCBvdGhlciB2YXJpYWJsZXMgZGVwZW5kcyBvbiAxKSB0aGUgb2JzZXJ2ZWQgdmFyaWFibGUgaXRzZWxmIChpLmUuLCBzcGVjaWVzIGFidW5kYW5jZSBjYW4gdmFyeSBtb3JlIHRoYW4gcHJlc2VuY2UvYWJzZW5jZSksIDIpIHRoZSBzdHVkeSBkZXNpZ24sIGFuZCAzKSB0aGUgdW5pcXVlIGNoYXJhY3RlcmlzdGljcyBvZiB0aGUgc3lzdGVtIG9mIGludGVyZXN0LiAKCkZvciBleGFtcGxlLCBpbiBsb25naXR1ZGluYWwgc3R1ZGllcyB3aXRoIG9ic2VydmF0aW9ucyBmcm9tIHBsb3RzIGxvY2F0ZWQgY2xvc2UgdG9nZXRoZXIgaW4gc3BhY2UsIHRoZXJlIG1heSBiZSB2ZXJ5IGxpdHRsZSB2YXJpYXRpb24gaW4gcmFpbmZhbGwgYWNyb3NzIHBsb3RzIGJ1dCBoaWdoIHZhcmlhdGlvbiBpbiByYWluZmFsbCBhY3Jvc3MgeWVhcnMuIEluIHRoaXMgY2FzZSwgdmFyaWF0aW9uIGluIHJhaW5mYWxsIGlzIGxhcmdlbHkgY2FwdHVyZWQgYnkgeWVhciBmaXhlZCBlZmZlY3RzLiBJbiBjb250cmFzdCwgaWYgdGhlcmUncyBoaWdoIHNwYXRpYWwgdmFyaWF0aW9uIGFjcm9zcyBwbG90cyAoZS5nLiwgdGhlIHBsb3RzIHdlcmUgZXN0YWJsaXNoZWQgYWNyb3NzIGxhcmdlIHRvcG9ncmFwaGljIGdyYWRpZW50cyksIHRoZW4gcmFpbmZhbGwgd291bGQgdmFyeSBieSBwbG90IGFuZCB3b3VsZCBiZSBlc3RpbWF0ZWQgYXMgYSB0aW1lLXZhcnlpbmcgZXhwbGFuYXRvcnkgdmFyaWFibGUuIEZ1cnRoZXJtb3JlLCBpdCdzIGNyaXRpY2FsIHRvIGNvbnNpZGVyIHdoZXRoZXIgdGhlcmUgYXJlIHVub2JzZXJ2ZWQsIHRpbWUtdmFyeWluZyBhbmQgdGltZS1pbnZhcmlhbnQgdmFyaWFibGVzLiBGb3IgZXhhbXBsZSwgbWF5YmUgdGhlcmUgd2FzIGFuIGluc2VjdCBvdXRicmVhayBpbiBhIHN1YnNldCBvZiBwbG90cyB0aGF0IHdhc24ndCBjYXB0dXJlZCBieSB0aGUgb2JzZXJ2ZWQgdmFyaWFibGVzLiBJZiBhbmQgd2hlbiB0aGVzZSB0aW1lLXZhcnlpbmcgdmFyaWFibGVzIGV4aXN0LCBhZGRpdGlvbmFsIHRlc3RzIGNhbiBiZSBkb25lIHRvIGRldGVybWluZSB0aGUgbGlrZWxpaG9vZCBvZiBiaWFzIGR1ZSB0byB0aGVpciBwcmVzZW5jZS4gVGhlc2UgdW5vYnNlcnZlZCwgdGltZS12YXJ5aW5nIHZhcmlhYmxlcyBhcmUgdGhlIG1ham9yIGxpbWl0YXRpb24gb2YgRkUgcGFuZWwgbW9kZWxzIGFuZCBjYW4gbGVhZCB0byBiaWFzZWQgZXN0aW1hdGVzIG9mIHRoZSBjYXVzYWwgcmVsYXRpb25zaGlwIG9mIGludGVyZXN0LgoKVGhlIG1ham9yIGFkdmFudGFnZSBvZiBhbiBGRSBwYW5lbCBtb2RlbCBpcyB0aGF0IHVub2JzZXJ2ZWQsIHRpbWUtaW52YXJpYW50IHZhcmlhYmxlcyBhcmUgc3VidHJhY3RlZCBmcm9tIHRoZSBtb2RlbCwgd2hpY2ggY2FuIGFsbG93IGZvciBtb3JlIGNhdXNhbCBlc3RpbWF0ZXMgb2YgdW5kZXJseWluZyByZWxhdGlvbnNoaXBzIChpZiB1bm9ic2VydmVkLCB0aW1lLXZhcnlpbmcgdmFyaWFibGVzIGFyZSBub3QgYmlhc2luZyB0aGUgZXN0aW1hdGVzKS4gQmVjYXVzZSBpdCdzIG9mdGVuIGltcG9zc2libGUgdG8gY29udHJvbCBmb3IgYWxsIHVub2JzZXJ2ZWQsIHRpbWUtdmFyeWluZyB2YXJpYWJsZXMgaW4gb2JzZXJ2YXRpb25hbCBzZXR0aW5ncywgY29lZmZpY2llbnQgZXN0aW1hdGVzIHNob3VsZCBhbHdheXMgYmUgY2FyZWZ1bGx5IGludGVycHJldGVkLiBTdGlsbCwgRkUgcGFuZWwgbW9kZWxzIG9mZmVyIGFuIGltcG9ydGFudCBzdGVwIHRvd2FyZHMgZXN0aW1hdGluZyBjYXVzYWwgcmVsYXRpb25zaGlwcyBpbiBlY29sb2d5LgoKIyMgQ2VudGVyaW5nIGFuZCBzdGFuZGFyZGl6aW5nIHZzLiBkZW1lYW5pbmcKVGhlIEZFIHBhbmVsIG1vZGVsIGVsaW1pbmF0ZXMgdW5vYnNlcnZlZCwgdGltZS1pbnZhcmlhbnQgdmFyaWFibGVzIHRocm91Z2ggYSBzaW1wbGUgbWF0aGVtYXRpY2FsIHByb2Nlc3Mgb2YgdW5pdC1sZXZlbCBkZW1lYW5pbmcsIHVzaW5nIHRoZSB3aXRoaW4gdHJhbnNmb3JtYXRpb24gKGhlbmNlIHRoZSBhbHRlcm5hdGl2ZSBuYW1lIHRvIEZFIHBhbmVsIG1vZGVsIC0tIHRoZSB3aXRoaW4tZXN0aW1hdG9yIHBhbmVsIGRhdGEgbW9kZWwpLiBEZW1lYW5pbmcgZW5hYmxlcyBGRSBwYW5lbCBtb2RlbHMgdG8gY29udHJvbCBmb3IgdGltZS1pbnZhcmlhbnQgbWVhc3VyZWQgYW5kIHVubWVhc3VyZWQgdmFyaWFibGVzLCBhcyB3ZWxsIGFzIHRpbWUtdmFyeWluZyB2YXJpYWJsZXMgdGhhdCBhcmUgY29sbGluZWFyIHdpdGggdGltZSBwZXJpb2QgKEknbGwgZXhwbGFpbiB0aGlzIGZ1cnRoZXIgYmVsb3cpLCB0aGF0IG1heSBvdGhlcndpc2UgYmUgY29uZm91bmRpbmcgdGhlIHVuZGVybHlpbmcgY2F1c2FsIHJlbGF0aW9uc2hpcCBhIHJlc2VhcmNoZXIgaXMgc2Vla2luZyB0byBlc3RpbWF0ZS4gRkUgcGFuZWwgbW9kZWxzIGVzc2VudGlhbGx5IHJlZHVjZSB0aGUgdmFyaWF0aW9uIGluIHRoZSBvYnNlcnZlZCB2YXJpYWJsZXMgdG8gZGV2aWF0aW9ucyBmcm9tIHBsb3QtIGFuZCB5ZWFyLWxldmVsIG1lYW5zIGFuZCB1c2UgdGhpcyB2YXJpYXRpb24gKHdoaWNoIGhhcyBub3cgY29udHJvbGxlZCBmb3IgdGltZS1pbnZhcmlhbnQsIHVub2JzZXJ2ZWQgdmFyaWFibGUgYmlhcykgdG8gZXN0aW1hdGUgdGhlIGNvZWZmaWNpZW50cy4gCgpJJ2xsIGV4cGxhaW4gdGhpcyBkZW1lYW5pbmcgcHJvY2VzcyBieSBjb21wYXJpbmcgaXQgdG8gc3RhbmRhcmRpemF0aW9uIG9mIG5vbi1iaW5hcnkgdmFyaWFibGVzLCBvZnRlbiB1c2VkIHByaW9yIHRvIGVzdGltYXRpbmcgc3RhdGlzdGljYWwgbW9kZWxzIGluIGVjb2xvZ3kgKHRoZXJlYnkgaW5jcmVhc2luZyB0aGUgaW50ZXJwcmV0YWJpbGl0eSBvZiBjb2VmZmljaWVudHMgYW5kIGVuYWJsaW5nIGNvbXBhcmlzb24gb2YgY29lZmZpY2llbnQgbWFnbml0dWRlIHdpdGhpbiBhbmQgYWNyb3NzIG1vZGVscykuIFRoZSBmdW5kYW1lbnRhbCBkaWZmZXJlbmNlIGlzIHRoYXQgc3RhbmRhcmRpemluZyBpbmRlcGVuZGVudCB2YXJpYWJsZXMgaW4gZWNvbG9neSBkZW1lYW5zIChjZW50ZXJzIHRoZSBkYXRhKSBhY3Jvc3MgYWxsIG9mIHRoZSBvYnNlcnZhdGlvbnMsIGFuZCBvZnRlbiBhY3Jvc3MgYWxsIHRpbWUgcGVyaW9kcywgd2hlcmVhcyBkZW1lYW5pbmcgaW4gdGhlIEZFIHBhbmVsIG1vZGVsIGNvbnRleHQgc3VidHJhY3RzIG91dCB0aGUgbWVhbiBmcm9tIGVhY2ggaW5kaXZpZHVhbC0gb3IgcGxvdC1sZXZlbCBvYnNlcnZhdGlvbi4gVG8gZGVtb25zdHJhdGUgdGhpcywgSSBjcmVhdGUgYSBzaW11bGF0ZWQgZGF0YXNldCB3aXRoIGFubnVhbCB0ZW1wZXJhdHVyZSBhbmQgcHJlY2lwaXRhdGlvbiB2YWx1ZXMgbWVhc3VyZWQgYXQgZWFjaCBwbG90IGFjcm9zcyAyMCB5ZWFycywgYXMgd2VsbCBwbG90LWxldmVsIGVsZXZhdGlvbiBhbmQgeWVhciB2YXJpYWJsZXMuCgpgYGB7ciBpbmNsdWRlPUZBTFNFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShsbWU0KQpsaWJyYXJ5KGdnZWZmZWN0cykKbGlicmFyeShmaXhlc3QpCmxpYnJhcnkocGxvdHJpeCkKYGBgCgoKCmBgYHtyfQojIyBjcmVhdGluZyBhIHBhbmVsIGRhdGFzZXQgd2l0aCBwbG90LWxldmVsIG9ic2VydmF0aW9ucyAobiA9IDEwIHBsb3RzKSBhY3Jvc3MgMjAgeWVhcnMKCiMjZW1wdHkgZGF0YWZyYW1lCnBhbmVsZGF0YSA9IGRhdGEuZnJhbWUoKQoKIyNkYXRhc2V0IGZvciBsb29wCmZvciAoaSBpbiAxOjIwKXsKICAKICBlbGV2YXRpb24gPC0gc2VxKDExMDAsMjAwMCwgYnk9MTAwKQogIHBsb3QgPC0gc2VxKDE6MTApCiAgeWVhciA8LSBhcy5pbnRlZ2VyKHJlcChwYXN0ZShpKSwgMTApKQogIHJpY2huZXNzIDwtIHNhbXBsZSh4ID0gMToxNiwgcmVwbGFjZSA9IFQsIHNpemUgID0gMTApCiAgcHJlY2lwIDwtIHNhbXBsZSh4ID0gMjAwOjUwMCwgc2l6ZSAgPSAxMCkKICB0ZW1wcyA8LSBzYW1wbGUoeD0zOjE1LCByZXBsYWNlID0gVCwgc2l6ZSA9IDEwKQogIAogIG1lcmdlZGF0YSA8LSBkYXRhLmZyYW1lKHBsb3QsIHllYXIsIGVsZXZhdGlvbiwgcmljaG5lc3MsIHByZWNpcCwgdGVtcHMpCiAgcGFuZWxkYXRhID0gcmJpbmQocGFuZWxkYXRhLCBtZXJnZWRhdGEpCn0KCmBgYAoKKFNpZGUgbm90ZTogZWNvbm9taXN0cyBvZnRlbiB1c2Ug4oCcY3Jvc3Mtc2VjdGlvbmFsIGRhdGHigJ0gdG8gZGVzY3JpYmUgYSBkYXRhc2V0IHdpdGggb2JzZXJ2YXRpb25zIGZyb20gb25lIHRpbWUgcGVyaW9kIHZzLiDigJxwYW5lbCBkYXRh4oCdIHRvIGRlc2NyaWJlIGEgZGF0YXNldCB0aGF0IGluY2x1ZGVzIHJlcGVhdGVkIG9ic2VydmF0aW9ucyBmcm9tIGVhY2ggb2JzZXJ2ZWQgdW5pdCBvdmVyIG11bHRpcGxlIHBlcmlvZHMgb2YgdGltZS4pCgpgYGB7cn0KIyMgQSBjcm9zcy1zZWN0aW9uYWwgZGF0YXNldCBleGFtcGxlOgoKY3Jvc3Nfc2VjdGlvbmFsX2RhdGFzZXQgPC0gZmlsdGVyKHBhbmVsZGF0YSwgeWVhcj09MSkKCmBgYAoKU3RhbmRhcmRpemluZyBleHBsYW5hdG9yeSB2YXJpYWJsZXMgdXNpbmcgdGhlIHotdHJhbnNmb3JtYXRpb24gZmlyc3QgY2VudGVycyB0aGUgZGF0YSBhbmQgdGhlbiBkaXZpZGVzIGJ5IHRoZSBzdGFuZGFyZCBkZXZpYXRpb24uIAoKYGBge3J9CmNlbnRlciA8LSBwYW5lbGRhdGEgJT4lCiAgbXV0YXRlKHRlbXBzX2NlbnRlcmVkID0gdGVtcHMtbWVhbih0ZW1wcyksIAogICAgICAgICB0ZW1wc19zdGFuZGFyZGl6ZWQgPSAodGVtcHMtbWVhbih0ZW1wcykpL3NkKHRlbXBzKSwKICAgICAgICAgZWxldmF0aW9uX2NlbnRlcmVkID0gZWxldmF0aW9uLW1lYW4oZWxldmF0aW9uKSwKICAgICAgICAgZWxldmF0aW9uX3N0YW5kYXJkaXplZCA9IChlbGV2YXRpb24tbWVhbihlbGV2YXRpb24pKS9zZChlbGV2YXRpb24pKSAlPiUgCiAgc2VsZWN0KHBsb3QsIHllYXIsIGVsZXZhdGlvbiwgdGVtcHNfY2VudGVyZWQsIGVsZXZhdGlvbl9jZW50ZXJlZCwgZWxldmF0aW9uX3N0YW5kYXJkaXplZCkKCmhlYWQoY2VudGVyKQoKYGBgCk5vdGljZSB0aGUgdmFyaWF0aW9uIG9mIGFsbCBleHBsYW5hdG9yeSB2YXJpYWJsZXMgaXMgbGFyZ2VseSBtYWludGFpbmVkLiBUaGlzIGNvbnRyYXN0cyB0byBkZW1lYW5pbmcgaW4gdGhlIEZFIHBhbmVsIG1vZGVsIGNvbnRleHQsIHdoaWNoIHNlZWtzIHRvIGVsaW1pbmF0ZSB0aGUgdmFyaWF0aW9uIG9mIHRpbWUtaW52YXJpYW50IGV4cGxhbmF0b3J5IHZhcmlhYmxlcyAoZWxldmF0aW9uIGlzIGEgdGltZS1pbnZhcmlhbnQgZXhwbGFuYXRvcnkgdmFyaWFibGUpLgoKVG8gZWxpbWluYXRlIHRoZSB2YXJpYXRpb24gYXNzb2NpYXRlZCB3aXRoIHRpbWUtaW52YXJpYW50IHZhcmlhYmxlcywgRkUgcGFuZWwgbW9kZWxzIGNhbiBkZW1lYW4gdGhlIGRhdGEgYnkgY2VudGVyaW5nIHZhcmlhYmxlcyBhdCB0aGUgcGxvdC0gYW5kIHllYXItbGV2ZWwuIFdoaWxlIGRlbWVhbmluZyBpcyBvZnRlbiBpbXBsZW1lbnRlZCB1c2luZyBtYXRyaXggYWxnZWJyYSwgdG8gZGVtb25zdHJhdGUgdGhlIHVuZGVybHlpbmcgaWRlYSwgSSdsbCBnaXZlIGFuIG92ZXJseSBzaW1wbGlzdGljIGV4YW1wbGUuIFRvIGRlbWVhbiBhdCB0aGUgcGxvdC1sZXZlbCwgd2UgZmlyc3QgY2FsY3VsYXRlIHRoZSBhdmVyYWdlIHJpY2huZXNzLCB0ZW1wZXJhdHVyZSwgYW5kIHByZWNpcGl0YXRpb24gZm9yIGVhY2ggcGxvdC4gVGhlbiwgd2Ugc2ltcGx5IHN1YnRyYWN0IG91dCB0aGVzZSBtZWFucyBmcm9tIHRoZSBwbG90LWxldmVsIG9ic2VydmF0aW9ucyBmcm9tIGVhY2ggeWVhciAtLSByZXN1bHRpbmcgaW4gcGxvdC1sZXZlbCBkZXZpYXRpb25zIGFjcm9zcyAyMCB5ZWFycyBmb3IgYWxsIHZhcmlhYmxlcyBlc3RpbWF0ZWQgaW4gdGhlIG1vZGVsLgoKYGBge3J9CgpkZW1lYW5pbmdQbG90IDwtIHBhbmVsZGF0YSAlPiUKICAjI2ZpcnN0IGRlbWVhbmluZyBieSBwbG90CiAgZ3JvdXBfYnkocGxvdCklPiUKICBtdXRhdGUobWVhbnAgPSBtZWFuKHByZWNpcCksIG1lYW50ID0gbWVhbih0ZW1wcyksIAogICAgICAgICBtZWFuZWxldiA9IG1lYW4oZWxldmF0aW9uKSwgbWVhbnIgPSBtZWFuKHJpY2huZXNzKSkgJT4lCiAgbXV0YXRlKHByZWNpcF9kZW1lYW4gPSBwcmVjaXAtbWVhbnAsIHRlbXBzX2RlbWVhbiA9IHRlbXBzLW1lYW50LCAKICAgICAgICByaWNobmVzc19kZW1lYW49cmljaG5lc3MtbWVhbnIsIGVsZXZhdGlvbl9kZW1lYW49ZWxldmF0aW9uLW1lYW5lbGV2KSAlPiUgCiAgc2VsZWN0KHBsb3QsIHllYXIsIGVsZXZhdGlvbiwgdGVtcHNfZGVtZWFuLCBlbGV2YXRpb25fZGVtZWFuLCByaWNobmVzc19kZW1lYW4pCmhlYWQoZGVtZWFuaW5nUGxvdCkKCiMjIE5vdGljZSB0aGF0IHVzaW5nIHRoZSB3aXRoaW4tZXN0aW1hdG9yIGRlbWVhbmluZywgZWxldmF0aW9uIGlzIDA7IGl0J3MgdGltZS1pbnZhcmlhbnQuCgpgYGAKRkUgcGFuZWwgbW9kZWxzIGFsc28gc2ltdWx0YW5lb3VzbHkgZGVtZWFuIHZhcmlhYmxlcyBmcm9tIGVhY2ggdGltZSBwZXJpb2QuIFRoYXQgaXMsIGFsbCB2YXJpYWJsZXMgaGF2ZSBhIG1lYW4gYWNyb3NzIGFsbCBwbG90cyBpbiBhIGdpdmVuIHllYXIsIHNvIHRoZSByZXN1bHRpbmcgdmFyaWFibGVzIGluIHRoZSBGRSB0cmFuc2Zvcm1hdGlvbiwgYm90aCB0aGUgZXhwbGFuYXRvcnkgYW5kIG91dGNvbWUgdmFyaWFibGVzLCBhcmUgZGVtZWFuZWQgYXQgdGhlIHBsb3QgYW5kIHllYXItbGV2ZWxzLgoKSW4gcHJhY3RpY2UsIHRoZXJlIGFyZSBhdCBsZWFzdCB0aHJlZSB3aXRoaW4gdHJhbnNmb3JtYXRpb25zIChmb3IgYnJpZWYgZGVzY3JpcHRpb25zLCByZWZlciB0byBodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9GaXhlZF9lZmZlY3RzX21vZGVsKS4gRGVwZW5kaW5nIG9uIHRoZSBwYWNrYWdlIGFuZCBlc3RpbWF0b3IgdXNlZCwgdGhlcmUgbWF5IG5vdCBiZSBhbnkgZGVtZWFuaW5nIHByaW9yIHRvIGVzdGltYXRpbmcgdGhlIG1vZGVsLCBhcyBlc3RpbWF0aW5nIGEgcGxvdC1sZXZlbCBjb2VmZmljaWVudCBlc3RpbWF0ZSBpcyBtYXRoZW1hdGljYWxseSBlcXVpdmFsZW50IHRvIGRlbWVhbmluZy4gSG93ZXZlciwgcGFydGljdWxhcmx5IHdoZW4gdXNpbmcgbGFyZ2UgZGF0YXNldHMsIGRpZmZlcmVudCBwYWNrYWdlcywgbGlrZSBmaXhlc3QsIGF2b2lkIGVzdGltYXRpbmcgcGxvdC1sZXZlbCBjb2VmZmljaWVudHMgYmVjYXVzZSBpdCdzIGhpZ2hseSBjdW1iZXJzb21lIGZvciBsYXJnZSBkYXRhc2V0cy4gCgpgYGB7cn0KCmBgYAoKIyMgRml4ZWQgZWZmZWN0cyAoRkUpIHBhbmVsIG1vZGVscwpTaW1wbHkgc3BlYWtpbmcsIEZFIHBhbmVsIG1vZGVscyBhcmUgb2Z0ZW4gbGluZWFyIG1vZGVscyB0aGF0IGNhbiBiZSBlc3RpbWF0ZWQgdXNpbmcgYSB2YXJpZXR5IG9mIHBhY2thZ2VzIGFuZCBzb2Z0d2FyZS4gSeKAmWxsIHVzZSB0d28gZXN0aW1hdG9ycyBoZXJlIGZvciBleHBsYW5hdGlvbiBhbmQgY29tcGFyaXNvbjogMSkgdGhlIGZ1bmN0aW9uIGZlb2xzIGZyb20gZml4ZXN0IHBhY2thZ2UgKHNlZSBodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvZml4ZXN0L2ZpeGVzdC5wZGYpLCBhbmQgMikgdGhlIGZ1bmN0aW9uIGxtIGZyb20gUiBzdGF0cy4gSSBsaWtlIHVzaW5nIHRoZSBmaXhlc3QgcGFja2FnZSBhcyBpdOKAmXMgb25lIG9mIHRoZSBtb3JlIGRldmVsb3BlZCBwYWNrYWdlcyBmb3IgdGhlc2UgbW9kZWxzIGluIFIgYW5kIG1vcmUgZWZmaWNpZW50IHdoZW4gdXNpbmcgbGFyZ2UgZGF0YXNldHMsIHRob3VnaCBpdCB0b28gaXMgZXZvbHZpbmcgcmFwaWRseS4gQm90aCB0aGUgbG0gYW5kIGZlb2xzIGZ1bmN0aW9ucyBlc3RpbWF0ZSBtb2RlbHMgc2xpZ2h0bHkgZGlmZmVyZW50bHksIHJlc3VsdGluZyBpbiB0aGUgc2FtZSBjb2VmZmljaWVudCBlc3RpbWF0ZXMgd2l0aCBzbWFsbCBkaWZmZXJlbmNlcyBpbiBzdGFuZGFyZCBlcnJvcnMuIChTaWRlIG5vdGU6IHRoZXNlIG1vZGVscyBoYXZlIHZlcnkgZGlmZmVyZW50IFJeMnMsIHdoaWNoIEnigJlsbCBpZ25vcmUgZm9yIG5vdywgc2luY2Ugd2XigJlyZSBsZXNzIGludGVyZXN0ZWQgaW4gbW9kZWwgcHJlZGljdGlvbiBhbmQgZml0IGFuZCBtdWNoIG1vcmUgaW50ZXJlc3RlZCBpbiB0aGUgdW5kZXJseWluZyBjYXVzYWwgcmVsYXRpb25zaGlwIG9mIHRoZSBleHBsYW5hdG9yeSB2YXJpYWJsZXMgYW5kIHRoZSBvdXRjb21lIHZhcmlhYmxlKS4KCiMjIEZFIHBhbmVsIG1vZGVscyB1c2luZyBmZW9scwpgYGB7cn0KCiMjIFRoZSBGRSBwYW5lbCBtb2RlbCB1c2luZyB0aGUgZmVvbHMgZnVuY3Rpb24gZnJvbSB0aGUgZml4ZXN0IHBhY2thZ2UKCmZlX21vZCA8LSAgZmVvbHMocmljaG5lc3MgfiB0ZW1wcyArIHByZWNpcCB8IHBsb3QgKyB5ZWFyLAogICAgICAgICAgICAgICBkYXRhID0gcGFuZWxkYXRhKQoKc3VtbWFyeShmZV9tb2QpCgpgYGAKVGhlIEZFIHBhbmVsIG1vZGVsIEkgYW0gdXNpbmcgaGVyZSBlc3RpbWF0ZXMgcmljaG5lc3MgKHRoZSBvdXRjb21lIHZhcmlhYmxlKSwgYXMgYSBmdW5jdGlvbiBvZiB0ZW1wZXJhdHVyZSBhbmQgcHJlY2lwaXRhdGlvbiAoaS5lLiwgdGhlIHRpbWUtdmFyeWluZyBleHBsYW5hdG9yeSB2YXJpYWJsZXMpIGFuZCBpbmNsdWRlcyBwbG90IGFuZCB5ZWFyIGFzIHRoZSBmaXhlZCBlZmZlY3RzIChpLmUuLCB0aGUgZHVtbXkgdmFyaWFibGVzKS4gT2JzZXJ2ZWQgdGltZS1pbnZhcmlhbnQgdmFyaWFibGVzIChpbiB0aGlzIGNhc2UgZWxldmF0aW9uKSBhcmUgbm90IGluY2x1ZGVkIGJlY2F1c2UgdGltZS1pbnZhcmlhbnQgdmFyaWFibGVzIGFyZSBkcm9wcGVkIGR1cmluZyBkZW1lYW5pbmcgKHRoZXkgYXJlIG9taXR0ZWQgYW55d2F5IGlmIGluY2x1ZGVkIGluIHRoZSBtb2RlbCAoc2VlIHNpZGUgbm90ZSBiZWxvdykpLiAKCmBgYHtyfQoKIyMgU2lkZSBub3RlOiBpZiB5b3UgYWRkIGluIGVsZXZhdGlvbiwgdGhlIHRpbWUtaW52YXJpYW50IHZhcmlhYmxlLCB5b3UgY2FuIHNlZSBhIHdhcm5pbmcgCiMjIG1lc3NhZ2UgdGhhdCBpdCdzIGRyb3BwZWQgZnJvbSB0aGUgbW9kZWwgZHVlIHRvIGNvbGxpbmVhcml0eQoKZmVfbW9kX2VsZXYgPC0gIGZlb2xzKHJpY2huZXNzIH4gdGVtcHMgKyBwcmVjaXAgKyBlbGV2YXRpb24gIHwgcGxvdCArIHllYXIsCiAgICAgICAgICAgICAgIGRhdGEgPSBwYW5lbGRhdGEpCgpgYGAKVGhlIGZlb2xzIGVzdGltYXRvciBpcyBiYXNlZCBvZmYgb2YgQmVyZ2UgKDIwMTgpLiBUaGUgY29yZSBvZiB0aGlzIGFsZ29yaXRobSBpcyBiYXNlZCBvbiBhIGdlbmVyYWwgTUwgbW9kZWwgdGhhdCAiaW50ZWdyYXRlcyBhIGZpeGVkLXBvaW50IGFjY2VsZXJhdGlvbiBtZXRob2QgdG8gaGFzdGVuIHRoZSBjb252ZXJnZW5jZSBvZiB0aGUgZml4ZWQtZWZmZWN0IGNvZWZmaWNpZW50cy4iIEluIGFkZGl0aW9uLCB3aGlsZSB0aGVyZSdzIG9uZ29pbmcgZGViYXRlIGFib3V0IHdoZXRoZXIgYW5kIGhvdyB0byBjbHVzdGVyIHN0YW5kYXJkIGVycm9ycyAgLS0gb2Z0ZW4gdXNlZCB0byBjb250cm9sIGZvciBiaWFzIGFzc29jaWF0ZWQgd2l0aCBzcGF0aWFsIGNvcnJlbGF0aW9uIGFuZCBleHBlcmltZW50YWwgb3Igb2JzZXJ2YXRpb25hbCBkZXNpZ25zIHRoYXQgYXJlIGNsdXN0ZXJlZCAtLSBpbiBmZW9scywgc3RhbmRhcmQgZXJyb3JzIGFyZSBjbHVzdGVyZWQgYnkgZGVmYXVsdCB1c2luZyB0aGUgZml4ZWQgZWZmZWN0cyBpbiB0aGUgb3JkZXIgdGhleSBhcmUgZW50ZXJlZCBpbnRvIFIuIFlvdSBjYW4gYWxzbyB1c2UgdGhlIHZjb3YgYXJndW1lbnQgb3Igb3RoZXIgc3BlY2lmaWNhdGlvbnMgZnJvbSB0aGUgcGFja2FnZSBjbHViU2FuZHdpY2guIEluIGVjb2xvZ2ljYWwgc2V0dGluZ3MsIGRhdGEgYXJlIG9mdGVuIG5lc3RlZCB3aXRoaW4gcGxvdCBhbmQvb3Igc3BhdGlhbGx5IGNvcnJlbGF0ZWQsIHNvIGNsdXN0ZXJpbmcgc3RhbmRhcmQgZXJyb3JzLCBieSBwbG90IGZvciBleGFtcGxlLCBzaG91bGQgdHlwaWNhbGx5IGJlIGluY2x1ZGVkLgoKSW4gdGhpcyBzcGVjaWZpYyBleGFtcGxlLCB0aGUgRkUgbW9kZWwgaXMgZXNzZW50aWFsbHkgZXN0aW1hdGluZyBkZXZpYXRpb24gZnJvbSBwbG90LSBhbmQgeWVhci1sZXZlbCBtZWFucyBvZiB0aGUgZXhwbGFuYXRvcnkgdmFyaWFibGUgKHJpY2huZXNzKSBhcyBhIGZ1bmN0aW9uIG9mIHRoZSBkZXZpYXRpb25zIG9mIHRoZSB0aW1lLXZhcnlpbmcgZXhwbGFuYXRvcnkgdmFyaWFibGVzICh0ZW1wZXJhdHVyZSBhbmQgcHJlY2lwaXRhdGlvbikuIFRoZSBwbG90IGZpeGVkICBlZmZlY3QgaXMgY29udHJvbGxpbmcgZm9yIHRoZSB0aW1lLWludmFyaWFudCB1bm9ic2VydmVkIHZhcmlhYmxlcyBjb3JyZWxhdGVkIHdpdGggYW55IHZhcmlhYmxlcyBpbiB0aGUgbW9kZWwgKGkuZS4sIGJvdGggdGhlIGV4cGxhbmF0b3J5IGFuZCBkZXBlbmRlbnQgdmFyaWFibGVzKSwgYW5kIHRoZSB5ZWFyIGZpeGVkIGVmZmVjdCBpcyBjb250cm9sbGluZyBmb3IgdmFyaWFibGVzIHRoYXQgY2hhbmdlZCB0aHJvdWdoIHRpbWUgYnV0IG9ubHkgaWYgdGhlIGNoYW5nZSB3YXMgdGhlIHNhbWUgYWNyb3NzIHBsb3RzICh0aGVzZSBjb3VsZCBpbmNsdWRlIGF0bW9zcGhlcmljIEMwMiBmbHVjdHVhdGlvbnMsIHNvbGFyIHJhZGlhdGlvbiwgZXRjKS4gVGltZS12YXJ5aW5nIHZhcmlhYmxlcyB0aGF0IGFmZmVjdCBvbmx5IGNlcnRhaW4gcGxvdHMsIHdoaWNoIG1pZ2h0IGluY2x1ZGUgd2VhdGhlciB2YXJpYWJsZXMsIGZpcmUgb2NjdXJyZW5jZSwgZGVmb2xpYXRvcnMsIGFyZSBOT1QgY29udHJvbGxlZCBmb3IgaW4gdGhlIGRlbWVhbmluZyBwcm9jZXNzLiAKCgojIyBGRSBwYW5lbCBtb2RlbHMgdXNpbmcgbG0KCkJlbG93IGlzIGFuIGV4YW1wbGUgb2YgZml4ZWQgZWZmZWN0cyBwYW5lbCBtb2RlbCB1c2luZyBsbSB3aXRoIHBsb3QgYW5kIHllYXIgYXMgZmFjdG9ycyAoaS5lLiwgZmFjdG9yaW5nIHRoZSB2YXJpYWJsZXMgdHJhbnNmb3JtcyB0aGVtIHRvIGR1bW15IHZhcmlhYmxlcykuIFRoZSBpbnRlcmNlcHQgaXMgbm90IHNob3duIHRvIG1hdGNoIHRoZSBmZW9scyBzdW1tYXJ5IHRhYmxlOyB0aGUgaW50ZXJjZXB0IGlzIGRpZmZpY3VsdCB0byBlc3RpbWF0ZSBpbiBsYXJnZSBkYXRhc2V0cyBhbmQgdGhlcmVmb3JlIG9mdGVuIG5vdCByZXBvcnRlZC4gVGhlIG9yZGVyaW5nIG9mIHRoZSBmYWN0b3JzIHVzaW5nIGxtIGlzIG5vdCBpbXBvcnRhbnQsIHNpbmNlIGxtIGRvZXMgbm90IGNsdXN0ZXIgc3RhbmRhcmQgZXJyb3JzIGJ5IGRlZmF1bHQuCgpgYGB7cn0KCiMjIEZFIHBhbmVsIG1vZGVsIHVzaW5nIGxtCgpmZV9tb2RfbG0gPC0gbG0ocmljaG5lc3MgfiB0ZW1wcyArIHByZWNpcCArIGZhY3RvcihwbG90KSArIGZhY3Rvcih5ZWFyKSAtMSwKICAgICAgICAgICAgIGRhdGEgPSBwYW5lbGRhdGEpCgpzdW1tYXJ5KGZlX21vZF9sbSkKCgojIyBjb21iaW5pbmcgdGhlc2UgbW9kZWwgY29lZmZpY2llbnRzIHRvIGNvbXBhcmUgIHRoZW0KZmVfcmVzIDwtIGRhdGEuZnJhbWUoY29lZnRhYmxlKGZlX21vZCksIG1vZGVsPSJmZW9scyBzdW1tYXJ5IikKbG1fcmVzIDwtIGRhdGEuZnJhbWUoc3VtbWFyeShmZV9tb2RfbG0pJGNvZWZmaWNpZW50W2MoMToyKSxjKDE6NCldLCBtb2RlbCA9ImxtIHN1bW1hcnkiKQoKbGlzdChmZV9yZXMsIGxtX3JlcykKCmBgYApZb3UgY2FuIHNlZSB0aGF0IHRoZSBsbSBhbmQgZm9lbHMgZXN0aW1hdG9ycyBwcm9kdWNlIHRoZSBzYW1lIGNvZWZmaWNpZW50IGVzdGltYXRlcywgYnV0IHdpdGggc2xpZ2h0bHkgZGlmZmVyZW50IHN0YW5kYXJkIGVycm9ycyBhbmQgY29ycmVzcG9uZGluZyB0LXZhbHVlcyBhbmQgcC12YWx1ZXMuIFRoZSByZWFzb24gdGhhdCB0aGV5IGFyZSBwcm9kdWNpbmcgdGhlIHNhbWUgY29lZmZpY2llbnQgZXN0aW1hdGVzIGlzIHRoYXQgbWF0aGVtYXRpY2FsbHksIHRoZSBwbG90IGFuZCB5ZWFyIGNvZWZmaWNpZW50cyBhcmUgdGhlIHNhbWUgYXMgaWYgdGhlc2UgbW9kZWxzIHdlcmUgZGVtZWFuZWQgZmlyc3QgYmVmb3JlIGJlaW5nIGVzdGltYXRlZC4gVGhlIHJlYXNvbiB0aGV5IHByb2R1Y2UgZGlmZmVyZW50IHN0YW5kYXJkIGVycm9ycyBpcyBkdWUgdG8gdGhlIHVuZGVybHlpbmcgZXN0aW1hdG9yIGVuZ2luZSBhbmQgdGhlIGRlZmF1bHQgY2x1c3RlcmluZyBvZiB0aGUgc3RhbmRhcmQgZXJyb3JzIGluIGZlb2xzLiBJbiB0aGVvcnksIGJvdGggbG0gKGFuZCBhbHRlcm5hdGl2ZWx5IGdsbSkgYW5kIGZlb2xzIGVzdGltYXRpb25zIGFyZSBjb3JyZWN0OyB0aGVyZWZvcmUgaXQncyBpbmN1bWJlbnQgb24gdGhlIHJlc2VhcmNoZXIgdG8gZGVjaWRlIHdoaWNoIGVzdGltYXRvciB0byB1c2UgYm90aCBpbiBSIGFuZCBhY3Jvc3Mgb3RoZXIgc3RhdGlzdGljYWwgc29mdHdhcmUgKG9mdGVuIGNvbWVzIGRvd24gdG8gZWZmaWNpZW5jeSBhbmQgZmFtaWxpYXJpdHkpLgoKIyMgRGlmZmVyZW5jZSBiZXR3ZWVuIEZFIHBhbmVsIG1vZGVscyBhbmQgZ2xtbXMgCk5vdyBJIHdpbGwgY29tcGFyZSBmaXhlZCBlZmZlY3RzIHBhbmVsIG1vZGVscyAodXNpbmcgZmVvbHMpIHRvIG1peGVkIG1vZGVscywgc3BlY2lmaWNhbGx5IGdlbmVyYWxpemVkIGxpbmVhciBtaXhlZCBtb2RlbHMgKGdsbW1zKSB0aGF0IGFyZSB3aWRlbHkgdXNlZCBpbiBlY29sb2d5LiBOb3RpY2UgSSBpbmNsdWRlIGVsZXZhdGlvbiBhcyBhbiBleHBsYW5hdG9yeSB2YXJpYWJsZSB0byBkZW1vbnN0cmF0ZSB0aGF0IGdsbW1zIGVzdGltYXRlIGJvdGggdGltZS1pbnZhcmlhbnQgYW5kIHRpbWUtdmFyeWluZyB2YXJpYWJsZXMgd2hlbiBpbmNsdWRlZCBhcyBjb3ZhcmlhdGVzLCB3aGljaCBjb250cmFzdHMgdG8gdGhlIEZFIHBhbmVsIG1vZGVsIHVzaW5nIGZlb2xzIHRoYXQgZHJvcHMgdGltZS1pbnZhcmlhbnQgdmFyaWFibGVzIHRocm91Z2ggZGVtZWFuaW5nLgoKU2lkZSBub3RlIGFuZCB3YXJuaW5nOiB0aGUgZm9sbG93aW5nIGV4cGxhbmF0aW9uIG1heSBjYXVzZSBmdXJ0aGVyIGNvbmZ1c2lvbiB0aGFuIGdvb2QuIFRoZSBkaWZmZXJlbmNlcyBiZXR3ZWVuIG1peGVkIG1vZGVscyBpbiBlY29sb2d5IGFuZCBmaXhlZCBlZmZlY3RzIG1vZGVscyBpbiBlY29uIGNhbiBzZWVtIGNvbmZ1c2luZyBkdWUgaW4gcGFydCB0byB0aGUgZmFjdCB0aGF0IGZpeGVkIGVmZmVjdHMgYXJlIGRlZmluZWQgdmVyeSBkaWZmZXJlbnRseS4gRm9yIGV4YW1wbGUsIGEgZml4ZWQgZWZmZWN0IGluIGEgZ2xtbSBpcyBtb3JlIGVxdWl2YWxlbnQgdG8gYW4gZXhwbGFuYXRvcnkgdmFyaWFibGUgaW4gYW4gRkUgcGFuZWwgbW9kZWwgdGhhbiBhIGZpeGVkIGVmZmVjdCBpbiBhIEZFIHBhbmVsIG1vZGVsLCB3aGVyZWFzIGEgcmFuZG9tIGVmZmVjdCBpbiBhIGdsbW0gd291bGQgbW9yZSBsaWtlbHkgYmUgZXN0aW1hdGVkIGFzIGEgZml4ZWQgZWZmZWN0IGluIGEgcGFuZWwgbW9kZWwgKGZvciBtb3JlIGRldGFpbCBodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9GaXhlZF9lZmZlY3RzX21vZGVsKS4KCmBgYHtyfQoKIyMgR0xNTTogQSBnbG1tIHVzaW5nIHJhbmRvbSBlZmZlY3RzIGZvciB5ZWFyIGFuZCBwbG90CmdsbW1fcmVzX0EgPC0gbG1lcihyaWNobmVzc34gdGVtcHMgKyBwcmVjaXAgKyBlbGV2YXRpb24gKyAoMXxwbG90KSArICgxfHllYXIpLAogICAgICAgICAgICAgIGRhdGEgPSBwYW5lbGRhdGEpCgpzdW1tYXJ5KGdsbW1fcmVzX0EpCgpgYGAKSSdsbCBmb2N1cyBvbiB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiBGRSBwYW5lbCBtb2RlbHMgYW5kIGdsbW1zIHJlbGV2YW50IHRvIGNhdXNhbCBpbmZlcmVuY2UuIEZpcnN0LCBGRSBwYW5lbCBtb2RlbHMgY29udHJvbCBmb3IgYWxsIHVub2JzZXJ2ZWQgdGltZS1pbnZhcmlhbnQgdmFyaWFibGVzLiBUaG91Z2ggdGhlIHJhbmRvbSBlZmZlY3RzIGluIGdsbW1zIGhlbHAgY29udHJvbCBmb3IgbXVjaCBvZiB0aGUgdW5vYnNlcnZlZCB2YXJpYWJsZSBiaWFzIChmb3IgZXhhbXBsZSwgdGhlIHVub2JzZXJ2ZWQgdmFyaWFibGVzIGNvcnJlbGF0ZWQgd2l0aCBwbG90IGFuZCB5ZWFyKSwgdGhleSBjYW5ub3QgY29udHJvbCBmb3IgdGhlIHBvc3NpYmlsaXR5IHRoYXQgdGhlc2UgdW5vYnNlcnZlZCB2YXJpYWJsZXMgYXJlIGFsc28gY29ycmVsYXRlZCB3aXRoIHRoZSBleHBsYW5hdG9yeSB2YXJpYWJsZXMgKHNlZSBodHRwczovL2RvaS5vcmcvMTAuMTExMS8yMDQxLTIxMFguMTMxOTApLiBGb3IgaW5zdGFuY2UsIHVub2JzZXJ2ZWQgdGltZSBpbnZhcmlhbnQgdmFyaWFibGVzIChsZXQncyB1c2Ugc29pbCB0eXBlKSBtYXkgYmUgY29ycmVsYXRlZCBib3RoIHdpdGggcGxvdCBBTkQgdGhlIGV4cGxhbmF0b3J5IHZhcmlhYmxlcywgcHJlY2lwIGFuZCB0ZW1wZXJhdHVyZS4gSW5jbHVkaW5nIHRoZSByYW5kb20gZWZmZWN0IG9mIHBsb3Qgb25seSBjb250cm9scyBmb3IgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gc29pbCB0eXBlIGFuZCBwbG90LCBub3QgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gc29pbCB0eXBlIGFuZCBwcmVjaXAgYW5kIHNvaWwgdHlwZSBhbmQgdGVtcC4gVGh1cywgaW4gdGhlIHJhbmRvbSBlZmZlY3RzIGdsbW0gbW9kZWwgYWJvdmUsIGNvcnJlbGF0aW9ucyBiZXR3ZWVuIHVub2JzZXJ2ZWQgdmFyaWFibGVzIGFuZCB0aGUgZXhwbGFuYXRvcnkgdmFyaWFibGVzIGFyZSBjYXB0dXJlZCBpbiB0aGUgZXJyb3IgdGVybSwgcmVzdWx0aW5nIGluIGJpYXNlZCBjb2VmZmljaWVudCBlc3RpbWF0ZXMgb2YgcHJlY2lwIGFuZCB0ZW1wLiAKClNlY29uZCwgZ2xtbXMgY2Fubm90IGNvbnRyb2wgZm9yIHNldmVyZSBtdWx0aWNvbGxpbmVhcml0eSBhbW9uZyB0aGUgb2JzZXJ2ZWQgZXhwbGFuYXRvcnkgdmFyaWFibGVzLiBJbiBjb250cmFzdCwgRkUgcGFuZWwgbW9kZWxzIGNhbiBjb250cm9sIGZvciBzZXZlcmUgbXVsdGljb2xsaW5lYXJpdHkgaW5kdWNlZCBieSB0aW1lLWludmFyaWFudCB2YXJpYWJsZXMuIElmIHRlbXBlcmF0dXJlIGFuZCBwcmVjaXBpdGF0aW9uIGFyZSBoaWdobHkgY29ycmVsYXRlZCB3aXRoIGVsZXZhdGlvbiwgZm9yIGV4YW1wbGUsIGVsZXZhdGlvbiB3b3VsZCBsaWtlbHkgaGF2ZSBhIHZlcnkgaGlnaCB2YXJpYW5jZSBpbmZsYXRpb24gZmFjdG9yIChWSUYpIGh0dHBzOi8vd3d3LnRhbmRmb25saW5lLmNvbS9kb2kvYWJzLzEwLjEwODEvUUVOLTEyMDAwMTg3OC4gVGhlIGhpZ2hlciB0aGUgVklGLCB0aGUgbGFyZ2VyIHRoZSBTRXMsIHJlc3VsdGluZyBpbiBsZXNzIHByZWNpc2UgYW5kIGludGVycHJldGFibGUgY29lZmZpY2llbnQgZXN0aW1hdGVzLiBJZiB0aGVyZSdzIGEgc3Ryb25nIGNvcnJlbGF0aW9uIGJldHdlZW4gYSB0aW1lLWludmFyaWFudCAoZS5nLiwgZWxldmF0aW9uKSBhbmQgdGltZS12YXJ5aW5nIHZhcmlhYmxlIChlLmcuLCB0ZW1wZXJhdHVyZSksIEZFIHBhbmVsIG1vZGVscyBwcm92aWRlIGEgdXNlZnVsIHNvbHV0aW9uLCBhcyB0aGV5IHN1YnRyYWN0IG91dCB0aGUgdGltZS1pbnZhcmlhbnQgdmFyaWFibGUsIHRoZXJlYnkgZXN0aW1hdGluZyBhIG1vcmUgcHJlY2lzZSBjb2VmZmljaWVudCBvZiB0aGUgdGltZS12YXJ5aW5nIHZhcmlhYmxlLiBUaGlzIGlzIG9mIGNvdXJzZSBtdWNoIHByZWZlcmFibGUgdG8gb21pdHRpbmcgdGhlIHByb2JsZW1hdGljIHZhcmlhYmxlIHdoZW4gdGhlIFZJRiBpcyB0b28gaGlnaCwgYXMgaXQgaW5jcmVhc2VzIHRoZSBpbnRlcnByZXRhYmlsaXR5IGFuZCBwcmVjaXNpb24gb2YgdGhlIGNvZWZmaWNpZW50IGVzdGltYXRlLgoKRmluYWxseSwgb25lIG9mIHRoZSBtYWluIGFkdmFudGFnZXMgb2YgRkUgcGFuZWwgbW9kZWxzLCBvdGhlciB0aGFuIHRoZXkgb2Z0ZW4gcHJvdmlkZSBsZXNzIGJpYXNlZCBjb2VmZmljaWVudHMgb2YgZXhwbGFuYXRvcnkgdmFyaWFibGVzIHRoYW4gYSBnbG1tLCBpcyB0aGF0IGl0IGNhbiBiZSB1c2VkIHRvIGVzdGltYXRlIGEgY291bnRlcmZhY3R1YWwgc2NlbmFyaW8g4oCTIGEgd29ybGQgd2hlcmUgdGhlIHRyZWF0bWVudCBkaWRu4oCZdCBvY2N1ci4gVGhpcyBjb3VudGVyZmFjdHVhbCBjYW4gYmUgZXF1YXRlZCB0byBhIGNvbnRyb2wgdHJlYXRtZW50IGluIGFuIGV4cGVyaW1lbnQuIEJlY2F1c2UgdGhlIGNvZWZmaWNpZW50IGVzdGltYXRlcyBpbiBhIEZFIHBhbmVsIG1vZGVsIGFyZSBjYXB0dXJpbmcgbGVzcyBiaWFzZWQgZXN0aW1hdGVzIG9mIHRoZSBjYXVzYWwgcmVsYXRpb25zaGlwIG9mIGludGVyZXN0LCB0aGV5IGNhbiBiZSB1c2VkIHRvIGVzdGltYXRlIGEgd29ybGQgaW4gd2hpY2ggb25lIG9yIG1vcmUgb2YgdGhlc2UgZXhwbGFuYXRvcnkgdmFyaWFibGVzIGRpZG7igJl0IGNoYW5nZSB0aHJvdWdoIHRpbWUuIFRoaXMgY291bnRlcmZhY3R1YWwgdGh1cyByZXNlbWJsZXMgYSBjb250cm9sIGluIGFuIGV4cGVyaW1lbnRhbCBzZXR0aW5nIGFuZCB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIGNvbnRyb2wgYW5kIHRyZWF0bWVudCBjYW4gYmUgZXN0aW1hdGVkLgoKIyMgRkUgcGFuZWwgbW9kZWwgbGltaXRhdGlvbnMKClRoZXJlIGFyZSB0d28gbWFqb3IgbGltaXRhdGlvbnMgb2YgRkUgcGFuZWwgbW9kZWxzLiBGaXJzdCwgYW4gRkUgcGFuZWwgbW9kZWwgaXMgZmFpcmx5IHVzZWxlc3Mgd2hlbiBwcmVkaWN0aW5nIG91dC1vZi1zYW1wbGUuIElmIHByZWRpY3Rpb24gaXMgdGhlIG1haW4gZm9jdXMgb2YgYW4gYW5hbHlzaXMsIHVzaW5nIGEgcmFuZG9tIGVmZmVjdHMgbW9kZWwgbGlrZSBhIGdsbW0gdGhhdCBlc3RpbWF0ZXMgdGhlIHZhcmlhbmNlIGFzc29jaWF0ZWQgd2l0aCBwbG90cyBjYW4gZmFjaWxpdGF0ZSBvdXQtb2Ytc2FtcGxlIHByZWRpY3Rpb25zICh3aXRoIHRoZSBjYXZlYXQgdGhhdCB0aGVzZSBwcmVkaWN0aW9ucyBhcmUgbGlrZWx5IGJpYXNlZCkuIFNlY29uZCwgRkUgcGFuZWwgbW9kZWxzIGNhbm5vdCBjb250cm9sIGZvciB1bm9ic2VydmVkLCB0aW1lLXZhcnlpbmcgdmFyaWFibGVzLCB3aGljaCBpbiBzb21lIHNldHRpbmdzLCBtZWFucyB0aGV5IGFyZSBsaWtlbHkgbGVzcyB1c2VmdWwgdGhhbiBhIGdsbShtKS4KCgoKCg==