It has been said that an image is worth a thousand words. It has also been said that good graphics “force one to see that which otherwise would have been missed” (John Tukey). The reason for these advantages is tied to our evolutionary history; visually identifying complex patterns that might indicate a threat to our survival were quite adaptive. Failing to understand a table of numbers, on the other hand, likely never threatened the survival of our ancestors.

The landscape has changed, and with it, so have the threats to our “survival.” The dangers we face now do not come in the form of sabertoothed tigers, bears, sharks, and the like. Rather, the dangers we face are misinformation. The replication crisis has shed light on the fact that this new landscape is dangerous in other ways, as misinformation spreads throughout science and the public.

Unfortunately, statistical analysis is enormously complex, with more nuances and complexities growing daily. With the added complexity, the potential for misinformation grows even larger. It is curious, then, that with the added potential for misunderstanding, there hasn’t been a proportional push for greater simplification of interpretation. Given that our visual pattern recognition system is highly developed, graphics seem to be the most intuitive place to start simplifying the message.

I suspect the primary reason researchers fail to use graphics is two-fold. First, people do not understand how to produce good visualizations. Unfortunately, it is just as easy to deceive with visuals as it is for numbers. Although visualization resources are readily available, a cursory review of the literature demonstrates the message isn’t getting across; researchers rarely use figures, and when they do, they do so poorly. However, the bigger reason researchers fail to use graphics, I suspect, is due to software limitations. Most standard graphics produced by statistical software aremisleading, poor representations of the analyses, or plain ugly. Even if users are somehow able to overcome the software obstacle, deciding what graphic best represents the statistical analysis is another problem.

This paper attempts to address all these limitations by introducing Flexplot: an easy-to-use software package with a point-and-click interface that simplifies the visualization process. Flexplot produces publication-ready graphics that follow best-practices in visualization. Flexplot automates much of the decision-making in the backend. It is intelligent enough to determine which variables are categorical versus numeric, whether to do a scatterplot, histogram, bar chart, etc. By providing access to all these sorts of graphics in a single interface, Flexplot thus frees the resources of the user to spend their intellectual resources interpreting the graphics.

In this paper, I will proceed as follows. I first introduce the framework and general rules Flexplot uses to generate graphics. Subsequently, I illustrate the use of flexplot by showing how various sorts of modeling strategies (e.g., t-tests, ANOVAs, regressions) can be visualized using flexplot. I conclude with an example that shows how modeling and visualization can be integrated.

The General Linear Model Approach

Flexplot adapts a “General Linear Model” approach to visualization. Although most introductory statistics classes teach ANOVA’s, t-tests, regressions, etc. as separate and distinct procedures, most researchers eventually come to learn they are all part and parcel of the general linear model (GLM), which is simply an expanded form of regression. One can, for example, perform a t-test using regression (GLM) by relabeling one group as zero (e.g., Males=0) and the other as one (e.g., Females=1). The slope of said model is equivalent to the mean difference between the two groups (and the intercept is equal to the mean of the group recoded as zero), and the test of significance for that slope is equivalent to a t-test. In mathematical notation:

\(Y = b_0 + b_1\times X\)

where X is a dummy-coded variable indicating group membership. (For a more thorough treatment of general linear models, see Cohen, 1968)

If a grouping variable is a conversion from a label (e.g., Male versus Female) to a number (e.g., 0 versus 1), then one can plot the grouping variables on an X axis exactly as one would in a scatterplot (see, for example, the left-most panel in the figure below). This scatterplot can be improved further by labeling the axes (second panel).

However, this introduces a problem: because all males share the same X score (in other words, since all males share the score “Male”), there is too much overlap to see what is going on. This problem was solved years ago (reference) by the practice of “jittering.” Jittering means that we simply take the dummy-coded scores (1 and 0 in this case) and add a trivial amount of noise to that score. For example, one males’s score, formerly zero, might become .0987, while another male’s score might become -.972. Likewise, a female’s score (formerly one) might become 0.993 and another’s might become 1.045. Jittering minimizes overlap between datapoints and makes it easier to see where each individual score falls (see left panel in the figure below).

This image can be improved still by adding two elements: first, we can overlay means and standard errors. Additionally, we can alter the amount of noise applied during the jittering such that areas with greater concentration of scores are jittered more, while those areas with low concentration are jittered very little. (Technically, these images are jittered proportional to the density function of Outcome for that particular group). With enough datapoints, the “jittered density”, or JD plots begin looking like a reflected histogram. As an aside, this is very similar to how violin plots are created). These two improvements (overlaying means/standard errors and density-based jittering) are show in the right panel of the figure below. With these improvements, it is very easy to see how the two groups compare.

This conversion from t-test to GLM may require a slight modification in conceptualization. The traditional t-test aims to test differences between means. The GLM approach, on the other hand, treats group membership as a predictor and asks whether group membership is associated with the outcome variable. Although the conceptual difference seems nontrivial (i.e., mean difference versus association), the mathematics of both approaches are identical.

Once one is able to shift their conceptualization of grouping variables (or, in GLM terms, categorical predictor variables), the distinctions between groups and predictors becomes less important. This shift in thinking is necessary to understand the rationale of flexplot.

Much as the GLM conceptualizes statistical modeling in the form of an equation, flexplot also conceptualizes visualization in the form of an equation. The user need only specify the outcome and the predictor variable(s). Sometimes the user may also decide to specify how predictor variables are displayed (on the x-axis, as separate colors, as separate panels, etc.).

Flexplot’s Rules

This section will briefly explain the rules flexplot follows to generate graphics. Those looking for more specific information are welcome to study the code within Flexplot itself.

Flexplot was built using R, then adapted for use in the point-and-click software Jamovi: an open-source statistical computing software that allows developers (such as myself) to create “modules” for the general public. Flexplot is one such module.

The figure below shows the interface for Flexplot. Notice there are three panels of interest: Outcome variable, Predictor variable, and Paneled Variable. Aside from the outcome variable, Flexplot allows a total of four variables to be displayed: two variables in the “Predictor variables” box, and two in the “Paneled variables” box. For simplicity, I will name the first variable entered into Predictor variable as Predictor 1 and the second as Predictor 2. The first variable entered into Paneled variable I will call Panel 1 and the second Panel 2.

Predictor 1 will always be displayed on the X axis. If this variable is numeric, flexplot will produce a scatterplot. If this first variable is categorical, flexplot will produce a JD plot. Predictor 2 will be shown as different lines/colors/symbols. If Predictor 2 is numeric, it will first be “binned,” and each line/color/symbol will represent the relationship between Predictor 1 and the outcome for that particular level of Ppredictor 2. Likewise, if the variable is categorical, each line/color/symbol will represent the Predictor 1/outcome relationship for that level of (categorical) Predictor 2.

Panel 1 will show up in column panels, while Panel 2 will show up in row panels. As before, whichever of these variables are numeric will be binned first.

The user may wish to view the distribution of a particular variable (e.g., the outcome variable). To do so, the user simply specifies no predictor and no panel variables. Flexplot will then produce histograms (for numeric variables) or barplots (for categorical variables).

Now that I have epxlained the rules behind Flexplot, I will not demonstrate how to visualize various common analyses in research. In the process, I will highlight several features of Flexplot that enhance visual interpretation.

Regression in Flexplot

Much like the GLM is the basis of the majority of statistical analyses, likewise a scatterplot is the basis of most visualizations in flexplot. All other analyses are simply extensions of this outcome/predictor visual.

As expected, to visualize simple regression (i.e., one predictor variable), the user only needs to input the predictor variable and the outcome of interest. Flexplot will default to showing a “loess” or “lowess” line. In short, a loess line is a nonparametric curve that is allowed to “bend” with the data. The reason flexplot defaults to a loess curve is because often nonlinearities in data are masked if the researcher overlays a straight line. For example, in the figure below, the left plot appears to have a very weak linear relationship. It isn’t until we overlay a loess line that we realize the data are actually curvilinear.

Flexplot allows the user to specify a regression (straight) line, a loess line, a “robust” line, etc.:

Which results in this image:

Analysis of Variance (ANOVA)/T-Test

As mentioned previously, a categorical variable may be treated as numeric and subsequently plotted as a scatterplot. The examples shown in the first and second graphics are visual representation of a t-test. As the only difference between an ANOVA and a t-test is the number of groups; a visual for an ANOVA simply has three levels on the x axis, rather than two. The figure below shows a JD plots representing a t-test on the left, and an ANOVA on the right.

The user has the option of include means+standard errors, means + standard deviations, or medians with interquartile ranges. These may technically not be necessary, because the raw data provide all the information one would need. However, it is helpful to see a visual display of central tendency and variability The choice of which depends on what statistics the user choose to emphasize. If one is performing significance tests, means + standard errors should probably be reported (since p-values are a function of standard errors). If one is instead emphasizing effect sizes, such as Cohen’s d, means + standard deviations would be more appropriate (since cohen’s d is a function of standard deviations). The default is to report medians with interquartile ranges. The rationale for this is that it will highlight potential deviations from standard assumptions (normality, homoskedasticity).

To produce the graphics in Flexplot, one would simply put rewards (or therapy.type) in the predictor variable box, and weight.loss in the outcome variable box, like below

Factorial ANOVA

Recall that a Factorial ANOVA has two categorical variables, rather than one. For example, we might analyze the relationship between weight loss and gender/therapy.type. A graphic to match ought to incorporate both variables in the graphic. This can be done in one of two ways. The first way is to show the second variable as separate symbols/colors (left-most image in the figure below). Another way is to separate into panels, as in the middle plot in the figure below. The advantage of the left plot (where the second factor is presented as separate symbols/colors) is that it makes it easier to compare because the summary statistics are situated close to gether. Unfortunately, there is often a lot of overlap, which may mask important relationships. The graphic in the middle, however, reduces overlap, but makes it harder to make comparisons across panels. The far right panels uses a “ghost” line. The red line, or the ghost line, simply repeats the pattern from the “male” panel into the “female” panel, making it much easier to see that, across experimental conditions, females have more weight loss than males.

Error in round(breaks[i], digits = 1) : 
  non-numeric argument to mathematical function

One difficulty with multivariate data such as this is that one then has to choose which variable goes on the X axis. Each will give a different “view” of the data and, as such, both ought to be displayed (if not for publication, at least during data analysis). The figure, for example, shows therapy.type on the x axis in the left panel, and gender in the right panel. Each gives different insights into the data. In this case, the left panel emphasizes the main effect of therapy.type, while the right panel emphasizes the main effect of gender.

require(ggplot2)
require(cowplot)
require(flexplot)
data(exercise_data)
d =exercise_data
a = flexplot(weight.loss~gender | therapy.type, data=d, ghost.line="red")
Note: You didn't specify a reference for the ghost line. I'm going to choose it at random.
c = flexplot(weight.loss~therapy.type | gender, data=d, ghost.line="red")
Note: You didn't specify a reference for the ghost line. I'm going to choose it at random.
plot_grid(a,c,ncol=2)

ANCOVA

An ANCOVA generally involves a categorical grouping variable (e.g., an experimental effect) and a numeric “covariate.” When one performs an ANCOVA, they are typically not interested in the covariate. Rather, they seek the remove the influence of that predictor on the outcome. One way to visualize removing the effect of a predictor on an outcome is with Added Variable Plots (AVPs). In the background, the AVP models the relationship between the covariate and the outcome, residualizes the effect of the covariate (i.e., subtracting the fitted score from the actual score), then plots the categorical variable against the residuals. Residualizing a predictore removes any signal associated with the linear effect of that predictor.

Residualizing does not, however, remove any nonlinear relationships, such as interaction effects and polynomials. Because of this, I recommend plotting two graphics. One graphic will display the grouping variable as separated lines/colors/symbols. This first graphic will make it clear whether nonlinear and/or interaction effects are present. This is then supplemented with an AVP.

For example, the left panel of the figure below shows the relationship between motivation and weight.loss for each therapy.type (with a ghost line, for better interpretation). There may be some nonlinearity present, and the lines may deviate from parallel (indicating an interaction effect). However, these are relatively small sample sizes, so these minor deviations are probably nothing to worry about. The right panel shows the mean differences on the residualized outcome variable (as indicated by weight.loss|motivation), showing that there’s a slight advantage for beh over both cog and control conditions.

Normally when one residualizes a predictor variable from an outcome, the residuals are centered around zero. This can be confusing for those unfamiliar with AVPs. As such, Flexplot adds the mean of the depedent variable back into the residuals to make the visuals less intimidating.

Note: You didn't specify a reference for the ghost line. I'm going to choose it at random.

To create the left graphic in Jamovi, one would simply put weight.loss in the outcome variable box, motivation in predictor variable box, and therapy.type in the panel box. Notice the ghost.line box is checked. To create the right graphic, one would do all the same, except check the “Residualize predictor variable” box is checked.

Multiple Regression

Finally, we come to multiple regression (MR). Researchers tend to call an analysis a MR if they include multiple numeric variables. In actuality, MR is synonymous with the GLM; the mathematics (and flexplot, for that matter) don’t care whether the researcher considers the variables numeric or categorical. As such, we will illustrate multiple variable types in this section.

When plotting multivariate relationships, is it essential that we use paneling, AVPs, and ghost lines, otherwise things become overly complicated. The human brain is only capable of retaining so much information at once. To further simplify the analysis, I generally remove the standard error bars from the plots since they tend to add overlap between different plotted relationships. I also tend to plot regression lines, unless the loess lines indicate serious deviations from normality. Also, flexplot is only capable of plotting four predictor variables at once. More than that is exceptionally difficult for the human mind to interpret, so I have elected not to allow more than that. (One could plot separate paneled graphs for each of the levels of another variable to accomplish this, but again, that becomes quite difficult to interpret).

There is one other important feature of flexplot that needs noting before I demonstrate in Jamovi; categorical variables in the second, axis, row panels, or column panels will be “binned.” Bin simply means we convert them to categorical variables (e.g., each score on the categorical is categorized as high, medium, or low). Without this step, there would be as many panels as there are unique values of the numeric variable.

Having said that, let me introduce a strategy I use to visualize multivariate relationships. Let us assume we are interested in studying the relationship between weight.loss and each of the following predictors: motivation, health, muscle gain, and therapy.type. I will first start by plotting the bivariate relationship between weight.loss and each predictor variable. When doing this, I am looking for a couple of things. First, I am looking for bends in the relationships. If there are no bends, I will plot straight lines for the multivariate plot, which are far easier to interpret. I am also looking for the variable with the weakest relationship with weight.loss. I look for the weakest first because I am looking to reduce the number of variables to visualize as quickly as possible. The weakest bivariate relationship will likely be the weakest multivariate relationship. If it’s small enough not to worry about, I will generally remove that variable. In the below figure, gender seems to have the weakest relationship, and some variables have a nonlinear relationship with satisfaction.

Following univariate visuals, I then plot the multivariate visual. In this case, I will place gender on the X axis, and plot conscientiousness as separate lines/colors/symbols. The other two variables will simply be placed in panels (whether rows or columns doesn’t matter). This image is shown below.

At this point, I’m trying to dismiss gender as an important predictor. Eliminating a variable would simplify the analysis immensely. The only place I see a large difference between genders is in the first column/row panel. However, this only shows a large difference because there’s only one Male in that panel. As such, I’m going to dismiss gender as an important predictor and instead look at the other three variables.

Note: You didn't specify a reference for the ghost line. I'm going to choose it at random.

At this point, I am looking for non-parellel lines. Non-parallel lines signal an interaction, but I’m also wary of interpreting any deviation from parallel as important. I’m inclined to say these fitted lines are roughly parallel, but I’m not entirely sure. This is where modeling can be extremely useful. I can fit a model with interactions and a model without interactions and compare the fits. The below table shows various statistics to assess the two models. Fortunately, all metrics agree that the simpler model is a better model.

aic bic bayes.factor p.value r.squared
Main Effects Model 2468.37 2486.88 9106.24 0.35 0.27
Interaction Model 2471.81 2505.11 NA NA 0.28

At this point, the visualizations become extremely easy. The model comparison suggests there are only main effects, which means we are much safer in using AVPs. Granted, there may be some nonlinearity present in the residuals of the AVP plot, but I’m not to worried about that at this point. We can visualize the nonlinearity with the AVPs, as shown in the following figure.

These visuals suggest all variables may have a nonlinear association with satisfaction, once we controll for all the other variables in the model. There’s also some evidence of heteroskedasticity, but addressing that is beyond the scope of this paper.

Summary

In this paper, we have introduced Flexplot, an easy-to-use software package that allows flexible and simple visualizations with a graphical user interface. We have also introduces various graphical tools, including added variable plots, jittered density plots, ghost lines, paneling, etc. We also concluded with a general strategy for complex multivariate visualizations. It is our hope these tools and demonstrations seem both approachable and helpful, and that researchers have no hesitations about utilizing the tools available to flexplot.

References

LS0tCnRpdGxlICAgICAgICAgICAgIDogIkEgR3JhcGhpYyBpcyBXb3J0aCBhIFRob3VzYW5kIFRlc3QgU3RhdGlzdGljczogTWFwcGluZyBWaXN1YWxzIG9udG8gQ29tbW9uIEFuYWx5c2VzIgpzaG9ydHRpdGxlICAgICAgICA6ICJHcmFwaGljIGlzIFdvcnRoIGEgVGhvdXNhbmQgU3RhdGlzdGljcyIKCmF1dGhvcjogCiAgLSBuYW1lICAgICAgICAgIDogIkR1c3RpbiBGaWZlIgogICAgYWZmaWxpYXRpb24gICA6ICIxIgogICAgY29ycmVzcG9uZGluZyA6IHllcyAgICAjIERlZmluZSBvbmx5IG9uZSBjb3JyZXNwb25kaW5nIGF1dGhvcgogICAgYWRkcmVzcyAgICAgICA6ICIyMDEgTXVsbGljYSBIaWxsIFJvYWQKICAgICAgICAgICAgICAgICAgICBHbGFzc2Jvcm8sIE5KIDA4MDI4IgogICAgZW1haWwgICAgICAgICA6ICJmaWZlLmR1c3RpbkBnbWFpbC5jb20iCgphZmZpbGlhdGlvbjoKICAtIGlkICAgICAgICAgICAgOiAiMSIKICAgIGluc3RpdHV0aW9uICAgOiAiUm93YW4gVW5pdmVyc2l0eSIKICAKYXV0aG9yX25vdGU6ID4KIyBJIHdpc2ggdG8gdGhhbmsgdGhvc2Ugd2hvIGFzc2lzdGVkIGluIHJldmlld2luZyB0aGlzIG1hbnVzY3JpcHQsIGluY2x1ZGluZyBUb20gRGluemVvLCBQb2xseSBUcmVtb3VsZXQsIEplZmZyZXkgR3JlZXNvbiwgQ2hyaXN0aW5lIFNpbW1vbnMsIGFuZCBKb3NlcGggUm9kZ2VycywgYXMgd2VsbCBhcyB0aGUgYW5vbnltb3VzIHJldmlld2VycyBhbmQgZWRpdG9yLiAgCgphYnN0cmFjdDogPgogIEdyYXBoaWNhbCBkaXNwbGF5cyBvZiBkYXRhIG9mZmVyIHNldmVyYWwgYWR2YW50YWdlcywgaW5jbHVkaW5nIGltcHJvdmluZyBlbmNvZGluZywgaGlnaGxpZ2h0aW5nIHVuY2VydGFpbnR5LCBhbmQgaGlnaGxpZ2h0aW5nIHByb2JsZW1zIHdpdGggb3VyIGRhdGEuIERlc3BpdGUgdGhpcyBmYWN0LCB0aGVyZSBpcyBhIG1ham9yIGxhY2sgb2YgZ3JhcGhpY2FsIHByZXNlbnRhdGlvbiBpbiB0b2RheSdzIGFjYWRlbWljIGpvdXJuYWxzLiBUaG9zZSBhcnRpY2xlcyB0aGF0IGRvIGRpc3BsYXkgZ3JhcGhpY3Mgb2Z0ZW4gZG8gc28gcG9vcmx5LCBpbiBzdWNoIGEgd2F5IHRoYXQgbWF5IG1pc2xlYWQgcmVhZGVycy4gVGhpcyBpcyBsaWtlbHkgZHVlIHRvIGEgbGFjayBvZiBzb2Z0d2FyZSBhbmQvb3IgZ3VpZGFuY2Ugb24gd2hhdCBncmFwaGljcyBhcmUgbW9zdCBhcHByb3ByaWF0ZSBmb3Igd2hpY2ggYW5hbHlzZXMuIEluIHRoaXMgYXJ0aWNsZSwgd2UgYXR0ZW1wdCB0byBhZGRyZXNzIHRoZXNlIGlzc3VlcyBieSBpZGVudGlmeWluZyBhcHByb3ByaWF0ZSBncmFwaGljcyBmb3IgdGhlIG1vc3QgY29tbW9uIGFuYWx5c2VzLCBpbmNsdWRpbmcgcmVncmVzc2lvbiwgdC10ZXN0cywgQU5PVkFzLCBBTkNPVkFzLCBhbmQgbXVsdGlwbGUgcmVncmVzc2lvbi4gV2UgYWxzbyBkZW1vbnN0cmF0ZSBob3cgdG8gZ3JhcGggdGhlc2UgdXNpbmcgdGhlIEZsZXhwbG90IG1vZHVsZSBpbiBKYW1vdmksIGEgZnJlZSBhbmQgZWFzeSB0byB1c2UgcG9pbnQgYW5kIGNsaWNrIHNvZnR3YXJlLiAKICAKICBcCgogIAprZXl3b3JkcyAgICAgICAgICA6ICJ2aXN1YWxpemF0aW9uLCBncmFwaGljcywgZmxleHBsb3QsIGphbW92aSwgZGF0YSBhbmFseXNpcyIKd29yZGNvdW50ICAgICAgICAgOiAiWCIKCmJpYmxpb2dyYXBoeSAgICAgIDogWyIuLi8uLi8uLi9tYXN0ZXJiaWIvbWVuZGVsZXlfMjAxOF8xMF8zMC5iaWIiXQpmaWdzaW50ZXh0ICAgICAgICA6IG5vCmZpZ3VyZWxpc3QgICAgICAgIDogbm8KdGFibGVsaXN0ICAgICAgICAgOiBubwpmb290bm90ZWxpc3QgICAgICA6IG5vCmxpbmVubyAgICAgICAgICAgIDogbm8KCmxhbmcgICAgICAgICAgICAgIDogImVuZ2xpc2giCmNsYXNzICAgICAgICAgICAgIDogImRvYyIKb3V0cHV0ICAgICAgICAgICAgOiBodG1sX25vdGVib29rCiNwYXBhamE6OmFwYTZfcGRmCgpoZWFkZXItaW5jbHVkZXM6CiAgIC0gXHVzZXBhY2thZ2V7Y29sb3J0Ymx9CiAgIC0gXHVzZXBhY2thZ2VbZXhwb3J0XXthZGp1c3Rib3h9ICAgIyMgdG8gdmVydGljYWwgYWxpZ24gaW1hZ2VzIGluIHRleHRib3gKICAgLSBcdXNlcGFja2FnZXtwZGZsc2NhcGV9ICAjIyMgdG8gZG8gYSBzaWRld2F5cyB0YWJsZQogICAtIFx1c2VwYWNrYWdle2xvbmd0YWJsZX0gIyMjIyB0byBsZXQgdGhlIHRhYmxlIHNwYW4gbXVsdGlwbGUgcGFnZXMKLS0tCgpJdCBoYXMgYmVlbiBzYWlkIHRoYXQgYW4gaW1hZ2UgaXMgd29ydGggYSB0aG91c2FuZCB3b3Jkcy4gSXQgaGFzIGFsc28gYmVlbiBzYWlkIHRoYXQgZ29vZCBncmFwaGljcyAiZm9yY2Ugb25lIHRvIHNlZSB0aGF0IHdoaWNoIG90aGVyd2lzZSB3b3VsZCBoYXZlIGJlZW4gbWlzc2VkIiAoSm9obiBUdWtleSkuIFRoZSByZWFzb24gZm9yIHRoZXNlIGFkdmFudGFnZXMgaXMgdGllZCB0byBvdXIgZXZvbHV0aW9uYXJ5IGhpc3Rvcnk7IHZpc3VhbGx5IGlkZW50aWZ5aW5nIGNvbXBsZXggcGF0dGVybnMgdGhhdCBtaWdodCBpbmRpY2F0ZSBhIHRocmVhdCB0byBvdXIgc3Vydml2YWwgd2VyZSBxdWl0ZSBhZGFwdGl2ZS4gRmFpbGluZyB0byB1bmRlcnN0YW5kIGEgdGFibGUgb2YgbnVtYmVycywgb24gdGhlIG90aGVyIGhhbmQsIGxpa2VseSBuZXZlciB0aHJlYXRlbmVkIHRoZSBzdXJ2aXZhbCBvZiBvdXIgYW5jZXN0b3JzLiAKClRoZSBsYW5kc2NhcGUgaGFzIGNoYW5nZWQsIGFuZCB3aXRoIGl0LCBzbyBoYXZlIHRoZSB0aHJlYXRzIHRvIG91ciAic3Vydml2YWwuIiBUaGUgZGFuZ2VycyB3ZSBmYWNlIG5vdyBkbyBub3QgY29tZSBpbiB0aGUgZm9ybSBvZiBzYWJlcnRvb3RoZWQgdGlnZXJzLCBiZWFycywgc2hhcmtzLCBhbmQgdGhlIGxpa2UuIFJhdGhlciwgdGhlIGRhbmdlcnMgd2UgZmFjZSBhcmUgbWlzaW5mb3JtYXRpb24uIFRoZSByZXBsaWNhdGlvbiBjcmlzaXMgaGFzIHNoZWQgbGlnaHQgb24gdGhlIGZhY3QgdGhhdCB0aGlzIG5ldyBsYW5kc2NhcGUgaXMgZGFuZ2Vyb3VzIGluIG90aGVyIHdheXMsIGFzIG1pc2luZm9ybWF0aW9uIHNwcmVhZHMgdGhyb3VnaG91dCBzY2llbmNlIGFuZCB0aGUgcHVibGljLiAgCgpVbmZvcnR1bmF0ZWx5LCBzdGF0aXN0aWNhbCBhbmFseXNpcyBpcyBlbm9ybW91c2x5IGNvbXBsZXgsIHdpdGggbW9yZSBudWFuY2VzIGFuZCBjb21wbGV4aXRpZXMgZ3Jvd2luZyBkYWlseS4gV2l0aCB0aGUgYWRkZWQgY29tcGxleGl0eSwgdGhlIHBvdGVudGlhbCBmb3IgbWlzaW5mb3JtYXRpb24gZ3Jvd3MgZXZlbiBsYXJnZXIuIEl0IGlzIGN1cmlvdXMsIHRoZW4sIHRoYXQgd2l0aCB0aGUgYWRkZWQgcG90ZW50aWFsIGZvciBtaXN1bmRlcnN0YW5kaW5nLCB0aGVyZSBoYXNuJ3QgYmVlbiBhIHByb3BvcnRpb25hbCBwdXNoIGZvciBncmVhdGVyIHNpbXBsaWZpY2F0aW9uIG9mIGludGVycHJldGF0aW9uLiBHaXZlbiB0aGF0IG91ciB2aXN1YWwgcGF0dGVybiByZWNvZ25pdGlvbiBzeXN0ZW0gaXMgaGlnaGx5IGRldmVsb3BlZCwgZ3JhcGhpY3Mgc2VlbSB0byBiZSB0aGUgbW9zdCBpbnR1aXRpdmUgcGxhY2UgdG8gc3RhcnQgc2ltcGxpZnlpbmcgdGhlIG1lc3NhZ2UuIAoKSSBzdXNwZWN0IHRoZSBwcmltYXJ5IHJlYXNvbiByZXNlYXJjaGVycyBmYWlsIHRvIHVzZSBncmFwaGljcyBpcyB0d28tZm9sZC4gRmlyc3QsIHBlb3BsZSBkbyBub3QgdW5kZXJzdGFuZCBob3cgdG8gcHJvZHVjZSBnb29kIHZpc3VhbGl6YXRpb25zLiBVbmZvcnR1bmF0ZWx5LCBpdCBpcyBqdXN0IGFzIGVhc3kgdG8gZGVjZWl2ZSB3aXRoIHZpc3VhbHMgYXMgaXQgaXMgZm9yIG51bWJlcnMuIEFsdGhvdWdoIHZpc3VhbGl6YXRpb24gcmVzb3VyY2VzIGFyZSByZWFkaWx5IGF2YWlsYWJsZSwgYSBjdXJzb3J5IHJldmlldyBvZiB0aGUgbGl0ZXJhdHVyZSBkZW1vbnN0cmF0ZXMgdGhlIG1lc3NhZ2UgaXNuJ3QgZ2V0dGluZyBhY3Jvc3M7IHJlc2VhcmNoZXJzIHJhcmVseSB1c2UgZmlndXJlcywgYW5kIHdoZW4gdGhleSBkbywgdGhleSBkbyBzbyBwb29ybHkuIEhvd2V2ZXIsIHRoZSBiaWdnZXIgcmVhc29uIHJlc2VhcmNoZXJzIGZhaWwgdG8gdXNlIGdyYXBoaWNzLCBJIHN1c3BlY3QsIGlzIGR1ZSB0byBzb2Z0d2FyZSBsaW1pdGF0aW9ucy4gTW9zdCBzdGFuZGFyZCBncmFwaGljcyBwcm9kdWNlZCBieSBzdGF0aXN0aWNhbCBzb2Z0d2FyZSBhcmVtaXNsZWFkaW5nLCBwb29yIHJlcHJlc2VudGF0aW9ucyBvZiB0aGUgYW5hbHlzZXMsIG9yIHBsYWluIHVnbHkuIEV2ZW4gaWYgdXNlcnMgYXJlIHNvbWVob3cgYWJsZSB0byBvdmVyY29tZSB0aGUgc29mdHdhcmUgb2JzdGFjbGUsICpkZWNpZGluZyogd2hhdCBncmFwaGljIGJlc3QgcmVwcmVzZW50cyB0aGUgc3RhdGlzdGljYWwgYW5hbHlzaXMgaXMgYW5vdGhlciBwcm9ibGVtLgoKVGhpcyBwYXBlciBhdHRlbXB0cyB0byBhZGRyZXNzIGFsbCB0aGVzZSBsaW1pdGF0aW9ucyBieSBpbnRyb2R1Y2luZyBGbGV4cGxvdDogYW4gZWFzeS10by11c2Ugc29mdHdhcmUgcGFja2FnZSB3aXRoIGEgcG9pbnQtYW5kLWNsaWNrIGludGVyZmFjZSB0aGF0IHNpbXBsaWZpZXMgdGhlIHZpc3VhbGl6YXRpb24gcHJvY2Vzcy4gRmxleHBsb3QgcHJvZHVjZXMgcHVibGljYXRpb24tcmVhZHkgZ3JhcGhpY3MgdGhhdCBmb2xsb3cgYmVzdC1wcmFjdGljZXMgaW4gdmlzdWFsaXphdGlvbi4gRmxleHBsb3QgYXV0b21hdGVzIG11Y2ggb2YgdGhlIGRlY2lzaW9uLW1ha2luZyBpbiB0aGUgYmFja2VuZC4gSXQgaXMgaW50ZWxsaWdlbnQgZW5vdWdoIHRvIGRldGVybWluZSB3aGljaCB2YXJpYWJsZXMgYXJlIGNhdGVnb3JpY2FsIHZlcnN1cyBudW1lcmljLCB3aGV0aGVyIHRvIGRvIGEgc2NhdHRlcnBsb3QsIGhpc3RvZ3JhbSwgYmFyIGNoYXJ0LCBldGMuIEJ5IHByb3ZpZGluZyBhY2Nlc3MgdG8gYWxsIHRoZXNlIHNvcnRzIG9mIGdyYXBoaWNzIGluIGEgc2luZ2xlIGludGVyZmFjZSwgRmxleHBsb3QgdGh1cyBmcmVlcyB0aGUgcmVzb3VyY2VzIG9mIHRoZSB1c2VyIHRvIHNwZW5kIHRoZWlyIGludGVsbGVjdHVhbCByZXNvdXJjZXMgaW50ZXJwcmV0aW5nIHRoZSBncmFwaGljcy4KCkluIHRoaXMgcGFwZXIsIEkgd2lsbCBwcm9jZWVkIGFzIGZvbGxvd3MuIEkgZmlyc3QgaW50cm9kdWNlIHRoZSBmcmFtZXdvcmsgYW5kIGdlbmVyYWwgcnVsZXMgRmxleHBsb3QgdXNlcyB0byBnZW5lcmF0ZSBncmFwaGljcy4gU3Vic2VxdWVudGx5LCBJIGlsbHVzdHJhdGUgdGhlIHVzZSBvZiBmbGV4cGxvdCBieSBzaG93aW5nIGhvdyB2YXJpb3VzIHNvcnRzIG9mIG1vZGVsaW5nIHN0cmF0ZWdpZXMgKGUuZy4sIHQtdGVzdHMsIEFOT1ZBcywgcmVncmVzc2lvbnMpIGNhbiBiZSB2aXN1YWxpemVkIHVzaW5nIGZsZXhwbG90LiBJIGNvbmNsdWRlIHdpdGggYW4gZXhhbXBsZSB0aGF0IHNob3dzIGhvdyBtb2RlbGluZyBhbmQgdmlzdWFsaXphdGlvbiBjYW4gYmUgaW50ZWdyYXRlZC4gCgojIFRoZSBHZW5lcmFsIExpbmVhciBNb2RlbCBBcHByb2FjaApGbGV4cGxvdCBhZGFwdHMgYSAiR2VuZXJhbCBMaW5lYXIgTW9kZWwiIGFwcHJvYWNoIHRvIHZpc3VhbGl6YXRpb24uIEFsdGhvdWdoIG1vc3QgaW50cm9kdWN0b3J5IHN0YXRpc3RpY3MgY2xhc3NlcyB0ZWFjaCBBTk9WQSdzLCB0LXRlc3RzLCByZWdyZXNzaW9ucywgZXRjLiBhcyBzZXBhcmF0ZSBhbmQgZGlzdGluY3QgcHJvY2VkdXJlcywgbW9zdCByZXNlYXJjaGVycyBldmVudHVhbGx5IGNvbWUgdG8gbGVhcm4gdGhleSBhcmUgYWxsIHBhcnQgYW5kIHBhcmNlbCBvZiB0aGUgZ2VuZXJhbCBsaW5lYXIgbW9kZWwgKEdMTSksIHdoaWNoIGlzIHNpbXBseSBhbiBleHBhbmRlZCBmb3JtIG9mIHJlZ3Jlc3Npb24uIE9uZSBjYW4sIGZvciBleGFtcGxlLCBwZXJmb3JtIGEgdC10ZXN0IHVzaW5nIHJlZ3Jlc3Npb24gKEdMTSkgYnkgcmVsYWJlbGluZyBvbmUgZ3JvdXAgYXMgemVybyAoZS5nLiwgTWFsZXM9MCkgYW5kIHRoZSBvdGhlciBhcyBvbmUgKGUuZy4sIEZlbWFsZXM9MSkuIFRoZSBzbG9wZSBvZiBzYWlkIG1vZGVsIGlzIGVxdWl2YWxlbnQgdG8gdGhlIG1lYW4gZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSB0d28gZ3JvdXBzIChhbmQgdGhlIGludGVyY2VwdCBpcyBlcXVhbCB0byB0aGUgbWVhbiBvZiB0aGUgZ3JvdXAgcmVjb2RlZCBhcyB6ZXJvKSwgYW5kIHRoZSB0ZXN0IG9mIHNpZ25pZmljYW5jZSBmb3IgdGhhdCBzbG9wZSBpcyBlcXVpdmFsZW50IHRvIGEgdC10ZXN0LiBJbiBtYXRoZW1hdGljYWwgbm90YXRpb246CgokWSA9IGJfMCArIGJfMVx0aW1lcyBYJAoKd2hlcmUgWCBpcyBhIGR1bW15LWNvZGVkIHZhcmlhYmxlIGluZGljYXRpbmcgZ3JvdXAgbWVtYmVyc2hpcC4gKEZvciBhIG1vcmUgdGhvcm91Z2ggdHJlYXRtZW50IG9mIGdlbmVyYWwgbGluZWFyIG1vZGVscywgc2VlIENvaGVuLCAxOTY4KQoKSWYgYSBncm91cGluZyB2YXJpYWJsZSBpcyBhIGNvbnZlcnNpb24gZnJvbSBhIGxhYmVsIChlLmcuLCBNYWxlIHZlcnN1cyBGZW1hbGUpIHRvIGEgbnVtYmVyIChlLmcuLCAwIHZlcnN1cyAxKSwgdGhlbiBvbmUgY2FuIHBsb3QgdGhlIGdyb3VwaW5nIHZhcmlhYmxlcyBvbiBhbiBYIGF4aXMgZXhhY3RseSBhcyBvbmUgd291bGQgaW4gYSBzY2F0dGVycGxvdCAoc2VlLCBmb3IgZXhhbXBsZSwgdGhlIGxlZnQtbW9zdCBwYW5lbCBpbiB0aGUgZmlndXJlIGJlbG93KS4gVGhpcyBzY2F0dGVycGxvdCBjYW4gYmUgaW1wcm92ZWQgZnVydGhlciBieSBsYWJlbGluZyB0aGUgYXhlcyAoc2Vjb25kIHBhbmVsKS4KCgoKYGBge3IsIGZpZy5jYXAgPSAiQSAnU2NhdHRlcnBsb3QnIHNob3dpbmcgdGhlIGdyb3VwaW5nIHZhcmlhYmxlIChnZW5kZXIgaW4gdGhpcyBjYXNlKSBvbiB0aGUgWCBheGlzIGFuZCB0aGUgb3V0Y29tZSBvbiB0aGUgWSBheGlzIFxcbGFiZWx7ZmlnOmNhdGVnb3JpY2FscmVnfSIsIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGVjaG89RkFMU0V9CnJlcXVpcmUodGlkeXZlcnNlKQpyZXF1aXJlKGNvd3Bsb3QpCnJlcXVpcmUoZmxleHBsb3QpCgpncm91cHMgPSBzYW1wbGUoYygxLDApLCBzaXplPTQwMCwgcmVwbGFjZT1UKQpvdXRjb21lID0gZ3JvdXBzICsgcm5vcm0oNDAwLCAxMCwyKQpkID0gZGF0YS5mcmFtZShHcm91cD1ncm91cHMsIE91dGNvbWU9b3V0Y29tZSkKYSA9IGZsZXhwbG90KE91dGNvbWV+R3JvdXAsIGRhdGE9ZCwgaml0dGVyPUYsIHN1cHByZXNzX3Ntb290aCA9IFQsIGFscGhhPS4yKQoKYiA9IGZsZXhwbG90KE91dGNvbWV+R3JvdXBfQ2F0LCBkYXRhPWQlPiVtdXRhdGUoR3JvdXBfQ2F0ID0gY3V0KEdyb3VwLCBicmVha3M9YygtSW5mLCAuNSwgSW5mKSwgbGFiZWxzPWMoIk1hbGUiLCAiRmVtYWxlIiksIG9yZGVyZWQ9VCkpLCBqaXR0ZXI9RiwgYWxwaGEgPSAuMiwgc3VwcHJlc3Nfc21vb3RoID0gVCkgKyBsYWJzKHg9IiIpCmMgPSBmbGV4cGxvdChPdXRjb21lfkdyb3VwX0NhdCwgZGF0YT1kJT4lbXV0YXRlKEdyb3VwX0NhdCA9IGN1dChHcm91cCwgYnJlYWtzPWMoLUluZiwgLjUsIEluZiksIGxhYmVscz1jKCJNYWxlIiwgIkZlbWFsZSIpLCBvcmRlcmVkPVQpKSwgcmF3LmRhdGE9Riwgc3VwcHJlc3Nfc21vb3RoID0gVCkgKyBsYWJzKHg9IiIpICsgZ2VvbV9qaXR0ZXIod2lkdGg9LjIsIGFscGhhPS4yKQplID0gZmxleHBsb3QoT3V0Y29tZX5Hcm91cF9DYXQsIGRhdGE9ZCU+JW11dGF0ZShHcm91cF9DYXQgPSBjdXQoR3JvdXAsIGJyZWFrcz1jKC1JbmYsIC41LCBJbmYpLCBsYWJlbHM9YygiTWFsZSIsICJGZW1hbGUiKSwgb3JkZXJlZD1UKSksIHNwcmVhZD0ic3RlcnIiKSArIGxhYnMoeD0iIikgCgoKcGxvdF9ncmlkKGEsYikKCgpgYGAKCgoKSG93ZXZlciwgdGhpcyBpbnRyb2R1Y2VzIGEgcHJvYmxlbTogYmVjYXVzZSBhbGwgbWFsZXMgc2hhcmUgdGhlIHNhbWUgWCBzY29yZSAoaW4gb3RoZXIgd29yZHMsIHNpbmNlIGFsbCBtYWxlcyBzaGFyZSB0aGUgc2NvcmUgIk1hbGUiKSwgdGhlcmUgaXMgdG9vIG11Y2ggb3ZlcmxhcCB0byBzZWUgd2hhdCBpcyBnb2luZyBvbi4gVGhpcyBwcm9ibGVtIHdhcyBzb2x2ZWQgeWVhcnMgYWdvIChyZWZlcmVuY2UpIGJ5IHRoZSBwcmFjdGljZSBvZiAiaml0dGVyaW5nLiIgSml0dGVyaW5nIG1lYW5zIHRoYXQgd2Ugc2ltcGx5IHRha2UgdGhlIGR1bW15LWNvZGVkIHNjb3JlcyAoMSBhbmQgMCBpbiB0aGlzIGNhc2UpIGFuZCBhZGQgYSB0cml2aWFsIGFtb3VudCBvZiBub2lzZSB0byB0aGF0IHNjb3JlLiBGb3IgZXhhbXBsZSwgb25lIG1hbGVzJ3Mgc2NvcmUsIGZvcm1lcmx5IHplcm8sIG1pZ2h0IGJlY29tZSAuMDk4Nywgd2hpbGUgYW5vdGhlciBtYWxlJ3Mgc2NvcmUgbWlnaHQgYmVjb21lIC0uOTcyLiBMaWtld2lzZSwgYSBmZW1hbGUncyBzY29yZSAoZm9ybWVybHkgb25lKSBtaWdodCBiZWNvbWUgMC45OTMgYW5kIGFub3RoZXIncyBtaWdodCBiZWNvbWUgMS4wNDUuIEppdHRlcmluZyBtaW5pbWl6ZXMgb3ZlcmxhcCBiZXR3ZWVuIGRhdGFwb2ludHMgYW5kIG1ha2VzIGl0IGVhc2llciB0byBzZWUgd2hlcmUgZWFjaCBpbmRpdmlkdWFsIHNjb3JlIGZhbGxzIChzZWUgbGVmdCBwYW5lbCBpbiB0aGUgZmlndXJlIGJlbG93KS4gCgoKVGhpcyBpbWFnZSBjYW4gYmUgaW1wcm92ZWQgc3RpbGwgYnkgYWRkaW5nIHR3byBlbGVtZW50czogZmlyc3QsIHdlIGNhbiBvdmVybGF5IG1lYW5zIGFuZCBzdGFuZGFyZCBlcnJvcnMuIEFkZGl0aW9uYWxseSwgd2UgY2FuIGFsdGVyIHRoZSBhbW91bnQgb2Ygbm9pc2UgYXBwbGllZCBkdXJpbmcgdGhlIGppdHRlcmluZyBzdWNoIHRoYXQgYXJlYXMgd2l0aCBncmVhdGVyIGNvbmNlbnRyYXRpb24gb2Ygc2NvcmVzIGFyZSBqaXR0ZXJlZCBtb3JlLCB3aGlsZSB0aG9zZSBhcmVhcyB3aXRoIGxvdyBjb25jZW50cmF0aW9uIGFyZSBqaXR0ZXJlZCB2ZXJ5IGxpdHRsZS4gKFRlY2huaWNhbGx5LCB0aGVzZSBpbWFnZXMgYXJlIGppdHRlcmVkIHByb3BvcnRpb25hbCB0byB0aGUgZGVuc2l0eSBmdW5jdGlvbiBvZiBPdXRjb21lIGZvciB0aGF0IHBhcnRpY3VsYXIgZ3JvdXApLiBXaXRoIGVub3VnaCBkYXRhcG9pbnRzLCB0aGUgImppdHRlcmVkIGRlbnNpdHkiLCBvciBKRCBwbG90cyBiZWdpbiBsb29raW5nIGxpa2UgYSByZWZsZWN0ZWQgaGlzdG9ncmFtLiBBcyBhbiBhc2lkZSwgdGhpcyBpcyB2ZXJ5IHNpbWlsYXIgdG8gaG93IHZpb2xpbiBwbG90cyBhcmUgY3JlYXRlZCkuIFRoZXNlIHR3byBpbXByb3ZlbWVudHMgKG92ZXJsYXlpbmcgbWVhbnMvc3RhbmRhcmQgZXJyb3JzIGFuZCBkZW5zaXR5LWJhc2VkIGppdHRlcmluZykgYXJlIHNob3cgaW4gdGhlIHJpZ2h0IHBhbmVsIG9mIHRoZSBmaWd1cmUgYmVsb3cuIFdpdGggdGhlc2UgaW1wcm92ZW1lbnRzLCBpdCBpcyB2ZXJ5IGVhc3kgdG8gc2VlIGhvdyB0aGUgdHdvIGdyb3VwcyBjb21wYXJlLiAKCmBgYHtyLCBmaWcuY2FwID0gIkEgJ1NjYXR0ZXJwbG90JyBzaG93aW5nIHRoZSBncm91cGluZyB2YXJpYWJsZSAoZ2VuZGVyIGluIHRoaXMgY2FzZSkgb24gdGhlIFggYXhpcyBhbmQgdGhlIG91dGNvbWUgb24gdGhlIFkgYXhpcy4gVGhlIGxlZnQgcGFuZWwgaXMgaml0dGVyZWQsIHdoaWxlIHRoZSByaWdodCBwYW5lbCBpcyBkZW5zaXR5IGppdHRlcmVkIGFuZCB0aGUgbWVhbi9zdGFuZGFyZCBlcnJvcnMgaGF2ZSBiZWVuIG92ZXJsYWlkLiBcXGxhYmVse2ZpZzpqaXR9IiwgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9NSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1GQUxTRX0KcGxvdF9ncmlkKGMsZSkKYGBgCgpUaGlzIGNvbnZlcnNpb24gZnJvbSB0LXRlc3QgdG8gR0xNIG1heSByZXF1aXJlIGEgc2xpZ2h0IG1vZGlmaWNhdGlvbiBpbiBjb25jZXB0dWFsaXphdGlvbi4gVGhlIHRyYWRpdGlvbmFsIHQtdGVzdCBhaW1zIHRvIHRlc3QgZGlmZmVyZW5jZXMgYmV0d2VlbiBtZWFucy4gVGhlIEdMTSBhcHByb2FjaCwgb24gdGhlIG90aGVyIGhhbmQsIHRyZWF0cyBncm91cCBtZW1iZXJzaGlwIGFzIGEgKnByZWRpY3RvciogYW5kIGFza3Mgd2hldGhlciBncm91cCBtZW1iZXJzaGlwIGlzIGFzc29jaWF0ZWQgd2l0aCB0aGUgb3V0Y29tZSB2YXJpYWJsZS4gQWx0aG91Z2ggdGhlIGNvbmNlcHR1YWwgZGlmZmVyZW5jZSBzZWVtcyBub250cml2aWFsIChpLmUuLCBtZWFuIGRpZmZlcmVuY2UgdmVyc3VzIGFzc29jaWF0aW9uKSwgdGhlIG1hdGhlbWF0aWNzIG9mIGJvdGggYXBwcm9hY2hlcyBhcmUgaWRlbnRpY2FsLiAKCk9uY2Ugb25lIGlzIGFibGUgdG8gc2hpZnQgdGhlaXIgY29uY2VwdHVhbGl6YXRpb24gb2YgZ3JvdXBpbmcgdmFyaWFibGVzIChvciwgaW4gR0xNIHRlcm1zLCBjYXRlZ29yaWNhbCBwcmVkaWN0b3IgdmFyaWFibGVzKSwgdGhlIGRpc3RpbmN0aW9ucyBiZXR3ZWVuIGdyb3VwcyBhbmQgcHJlZGljdG9ycyBiZWNvbWVzIGxlc3MgaW1wb3J0YW50LiBUaGlzIHNoaWZ0IGluIHRoaW5raW5nIGlzIG5lY2Vzc2FyeSB0byB1bmRlcnN0YW5kIHRoZSByYXRpb25hbGUgb2YgZmxleHBsb3QuIAoKTXVjaCBhcyB0aGUgR0xNIGNvbmNlcHR1YWxpemVzIHN0YXRpc3RpY2FsIG1vZGVsaW5nIGluIHRoZSBmb3JtIG9mIGFuIGVxdWF0aW9uLCBmbGV4cGxvdCBhbHNvIGNvbmNlcHR1YWxpemVzIHZpc3VhbGl6YXRpb24gaW4gdGhlIGZvcm0gb2YgYW4gZXF1YXRpb24uIFRoZSB1c2VyIG5lZWQgb25seSBzcGVjaWZ5IHRoZSBvdXRjb21lIGFuZCB0aGUgcHJlZGljdG9yIHZhcmlhYmxlKHMpLiBTb21ldGltZXMgdGhlIHVzZXIgbWF5IGFsc28gZGVjaWRlIHRvIHNwZWNpZnkgaG93IHByZWRpY3RvciB2YXJpYWJsZXMgYXJlIGRpc3BsYXllZCAob24gdGhlIHgtYXhpcywgYXMgc2VwYXJhdGUgY29sb3JzLCBhcyBzZXBhcmF0ZSBwYW5lbHMsIGV0Yy4pLiAKCiMgRmxleHBsb3QncyBSdWxlcwoKVGhpcyBzZWN0aW9uIHdpbGwgYnJpZWZseSBleHBsYWluIHRoZSBydWxlcyBmbGV4cGxvdCBmb2xsb3dzIHRvIGdlbmVyYXRlIGdyYXBoaWNzLiBUaG9zZSBsb29raW5nIGZvciBtb3JlIHNwZWNpZmljIGluZm9ybWF0aW9uIGFyZSB3ZWxjb21lIHRvIHN0dWR5IHRoZSBjb2RlIHdpdGhpbiBGbGV4cGxvdCBpdHNlbGYuIAoKRmxleHBsb3Qgd2FzIGJ1aWx0IHVzaW5nIFIsIHRoZW4gYWRhcHRlZCBmb3IgdXNlIGluIHRoZSBwb2ludC1hbmQtY2xpY2sgc29mdHdhcmUgSmFtb3ZpOiBhbiBvcGVuLXNvdXJjZSBzdGF0aXN0aWNhbCBjb21wdXRpbmcgc29mdHdhcmUgdGhhdCBhbGxvd3MgZGV2ZWxvcGVycyAoc3VjaCBhcyBteXNlbGYpIHRvIGNyZWF0ZSAibW9kdWxlcyIgZm9yIHRoZSBnZW5lcmFsIHB1YmxpYy4gRmxleHBsb3QgaXMgb25lIHN1Y2ggbW9kdWxlLgoKVGhlIGZpZ3VyZSBiZWxvdyBzaG93cyB0aGUgaW50ZXJmYWNlIGZvciBGbGV4cGxvdC4gTm90aWNlIHRoZXJlIGFyZSB0aHJlZSBwYW5lbHMgb2YgaW50ZXJlc3Q6IE91dGNvbWUgdmFyaWFibGUsIFByZWRpY3RvciB2YXJpYWJsZSwgYW5kIFBhbmVsZWQgVmFyaWFibGUuIEFzaWRlIGZyb20gdGhlIG91dGNvbWUgdmFyaWFibGUsIEZsZXhwbG90IGFsbG93cyBhIHRvdGFsIG9mIGZvdXIgdmFyaWFibGVzIHRvIGJlIGRpc3BsYXllZDogdHdvIHZhcmlhYmxlcyBpbiB0aGUgIlByZWRpY3RvciB2YXJpYWJsZXMiIGJveCwgYW5kIHR3byBpbiB0aGUgIlBhbmVsZWQgdmFyaWFibGVzIiBib3guIEZvciBzaW1wbGljaXR5LCBJIHdpbGwgbmFtZSB0aGUgZmlyc3QgdmFyaWFibGUgZW50ZXJlZCBpbnRvIFByZWRpY3RvciB2YXJpYWJsZSBhcyBQcmVkaWN0b3IgMSBhbmQgdGhlIHNlY29uZCBhcyBQcmVkaWN0b3IgMi4gVGhlIGZpcnN0IHZhcmlhYmxlIGVudGVyZWQgaW50byBQYW5lbGVkIHZhcmlhYmxlIEkgd2lsbCBjYWxsIFBhbmVsIDEgYW5kIHRoZSBzZWNvbmQgUGFuZWwgMi4KCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCByZXN1bHRzPUZBTFNFLCBlY2hvPUZBTFNFfQpubXMuZmlsZXMgPSBsaXN0LmZpbGVzKCJpbWFnZXMvc2NyZWVucyIsIGZ1bGwubmFtZXMgPSBUKQpgYGAKPGNlbnRlcj4KCmByIHNwcmludGYoIjxpbWcgc3JjID0gJyVzJyB3aWR0aD0nNDAwJz4iLCBubXMuZmlsZXNbMV0pYAoKPC9jZW50ZXI+CgoKUHJlZGljdG9yIDEgd2lsbCBhbHdheXMgYmUgZGlzcGxheWVkIG9uIHRoZSBYIGF4aXMuIElmIHRoaXMgdmFyaWFibGUgaXMgbnVtZXJpYywgZmxleHBsb3Qgd2lsbCBwcm9kdWNlIGEgc2NhdHRlcnBsb3QuIElmIHRoaXMgZmlyc3QgdmFyaWFibGUgaXMgY2F0ZWdvcmljYWwsIGZsZXhwbG90IHdpbGwgcHJvZHVjZSBhIEpEIHBsb3QuIApQcmVkaWN0b3IgMiB3aWxsIGJlIHNob3duIGFzIGRpZmZlcmVudCBsaW5lcy9jb2xvcnMvc3ltYm9scy4gSWYgUHJlZGljdG9yIDIgaXMgbnVtZXJpYywgaXQgd2lsbCBmaXJzdCBiZSAiYmlubmVkLCIgYW5kIGVhY2ggbGluZS9jb2xvci9zeW1ib2wgd2lsbCByZXByZXNlbnQgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIFByZWRpY3RvciAxIGFuZCB0aGUgb3V0Y29tZSBmb3IgdGhhdCBwYXJ0aWN1bGFyIGxldmVsIG9mIFBwcmVkaWN0b3IgMi4gTGlrZXdpc2UsIGlmIHRoZSB2YXJpYWJsZSBpcyBjYXRlZ29yaWNhbCwgZWFjaCBsaW5lL2NvbG9yL3N5bWJvbCB3aWxsIHJlcHJlc2VudCB0aGUgUHJlZGljdG9yIDEvb3V0Y29tZSByZWxhdGlvbnNoaXAgZm9yIHRoYXQgbGV2ZWwgb2YgKGNhdGVnb3JpY2FsKSBQcmVkaWN0b3IgMi4gCgpQYW5lbCAxIHdpbGwgc2hvdyB1cCBpbiBjb2x1bW4gcGFuZWxzLCB3aGlsZSBQYW5lbCAyIHdpbGwgc2hvdyB1cCBpbiByb3cgcGFuZWxzLiBBcyBiZWZvcmUsIHdoaWNoZXZlciBvZiB0aGVzZSB2YXJpYWJsZXMgYXJlIG51bWVyaWMgd2lsbCBiZSBiaW5uZWQgZmlyc3QuCgpUaGUgdXNlciBtYXkgd2lzaCB0byB2aWV3IHRoZSBkaXN0cmlidXRpb24gb2YgYSBwYXJ0aWN1bGFyIHZhcmlhYmxlIChlLmcuLCB0aGUgb3V0Y29tZSB2YXJpYWJsZSkuIFRvIGRvIHNvLCB0aGUgdXNlciBzaW1wbHkgc3BlY2lmaWVzIG5vIHByZWRpY3RvciBhbmQgbm8gcGFuZWwgdmFyaWFibGVzLiBGbGV4cGxvdCB3aWxsIHRoZW4gcHJvZHVjZSBoaXN0b2dyYW1zIChmb3IgbnVtZXJpYyB2YXJpYWJsZXMpIG9yIGJhcnBsb3RzIChmb3IgY2F0ZWdvcmljYWwgdmFyaWFibGVzKS4gCgpOb3cgdGhhdCBJIGhhdmUgZXB4bGFpbmVkIHRoZSBydWxlcyBiZWhpbmQgRmxleHBsb3QsIEkgd2lsbCBub3QgZGVtb25zdHJhdGUgaG93IHRvIHZpc3VhbGl6ZSB2YXJpb3VzIGNvbW1vbiBhbmFseXNlcyBpbiByZXNlYXJjaC4gSW4gdGhlIHByb2Nlc3MsIEkgd2lsbCBoaWdobGlnaHQgc2V2ZXJhbCBmZWF0dXJlcyBvZiBGbGV4cGxvdCB0aGF0IGVuaGFuY2UgdmlzdWFsIGludGVycHJldGF0aW9uLiAKCiMjIFJlZ3Jlc3Npb24gaW4gRmxleHBsb3QKCk11Y2ggbGlrZSB0aGUgR0xNIGlzIHRoZSBiYXNpcyBvZiB0aGUgbWFqb3JpdHkgb2Ygc3RhdGlzdGljYWwgYW5hbHlzZXMsIGxpa2V3aXNlIGEgc2NhdHRlcnBsb3QgaXMgdGhlIGJhc2lzIG9mIG1vc3QgdmlzdWFsaXphdGlvbnMgaW4gZmxleHBsb3QuIEFsbCBvdGhlciBhbmFseXNlcyBhcmUgc2ltcGx5IGV4dGVuc2lvbnMgb2YgdGhpcyBvdXRjb21lL3ByZWRpY3RvciB2aXN1YWwuIAoKQXMgZXhwZWN0ZWQsIHRvIHZpc3VhbGl6ZSBzaW1wbGUgcmVncmVzc2lvbiAoaS5lLiwgb25lIHByZWRpY3RvciB2YXJpYWJsZSksIHRoZSB1c2VyIG9ubHkgbmVlZHMgdG8gaW5wdXQgdGhlIHByZWRpY3RvciB2YXJpYWJsZSBhbmQgdGhlIG91dGNvbWUgb2YgaW50ZXJlc3QuIEZsZXhwbG90IHdpbGwgZGVmYXVsdCB0byBzaG93aW5nIGEgImxvZXNzIiBvciAibG93ZXNzIiBsaW5lLiBJbiBzaG9ydCwgYSBsb2VzcyBsaW5lIGlzIGEgbm9ucGFyYW1ldHJpYyBjdXJ2ZSB0aGF0IGlzIGFsbG93ZWQgdG8gImJlbmQiIHdpdGggdGhlIGRhdGEuIFRoZSByZWFzb24gZmxleHBsb3QgZGVmYXVsdHMgdG8gYSBsb2VzcyBjdXJ2ZSBpcyBiZWNhdXNlIG9mdGVuIG5vbmxpbmVhcml0aWVzIGluIGRhdGEgYXJlIG1hc2tlZCBpZiB0aGUgcmVzZWFyY2hlciBvdmVybGF5cyBhIHN0cmFpZ2h0IGxpbmUuIEZvciBleGFtcGxlLCBpbiB0aGUgZmlndXJlIGJlbG93LCB0aGUgbGVmdCBwbG90IGFwcGVhcnMgdG8gaGF2ZSBhIHZlcnkgd2VhayBsaW5lYXIgcmVsYXRpb25zaGlwLiBJdCBpc24ndCB1bnRpbCB3ZSBvdmVybGF5IGEgbG9lc3MgbGluZSB0aGF0IHdlIHJlYWxpemUgdGhlIGRhdGEgYXJlIGFjdHVhbGx5IGN1cnZpbGluZWFyLiAKCmBgYHtyLCBmaWcuY2FwID0gIlNjYXR0ZXJwbG90cyBvZiB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdHdvIHZhcmlhYmxlcy4gVGhlIGxlZnQgcGFuZWwgc2hvd3MgYSBzdHJhaWdodCBmaXR0ZWQgbGluZSwgd2hpbGUgdGhlIHJpZ2h0IHBhbmVsIHNob3dzIGEgbG9lc3MgbGluZS4gXFxsYWJlbHtmaWc6cmVncmVzc2lvbn0iLCBmaWcuaGVpZ2h0PTMsIGZpZy53aWR0aD01LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBlY2hvPUZBTFNFfQpzZXQuc2VlZCgxMTExMSkKaGVpZ2h0ID0gcm5vcm0oMjAwLCAwLDEpCndlaWdodCA9IDMwICsgLS40NSpoZWlnaHReMiArIHJub3JtKDIwMCwwLC44KQpkID0gZGF0YS5mcmFtZShYPWhlaWdodCwgWT13ZWlnaHQpCQpkID0gZFstd2hpY2goZCRZPDI3KSxdCQojZCR3ZWlnaHQgPSBkJHdlaWdodCAKZCRZID0gZmlmZXIyOjpyZXNjYWxlKGQkWSwgMzAsIDEwKQphID0gZmxleHBsb3QoWX5YLCBkYXRhPWQsIHJhdy5kYXRhPVQsIG1ldGhvZD0ibG0iLCBzZT1GKSAKYiA9IGZsZXhwbG90KFl+WCwgZGF0YT1kLCByYXcuZGF0YT1ULCBtZXRob2Q9ImxvZXNzIiwgc2U9RikKYyA9IGZsZXhwbG90KFl+WCwgZGF0YT1kLCByYXcuZGF0YT1ULCBtZXRob2Q9IiIsIHNlPUYpCnBsb3RfZ3JpZChhLGIpCmBgYAoKCkZsZXhwbG90IGFsbG93cyB0aGUgdXNlciB0byBzcGVjaWZ5IGEgcmVncmVzc2lvbiAoc3RyYWlnaHQpIGxpbmUsIGEgbG9lc3MgbGluZSwgYSAicm9idXN0IiBsaW5lLCBldGMuOgoKPGNlbnRlcj4KCmByIHNwcmludGYoIjxpbWcgc3JjID0gJyVzJyB3aWR0aD0nNDAwJz4iLCBubXMuZmlsZXNbMl0pYAoKPC9jZW50ZXI+CgpXaGljaCByZXN1bHRzIGluIHRoaXMgaW1hZ2U6CgpgYGB7ciwgZmlnLmNhcCA9ICJTY2F0dGVycGxvdHMgb2YgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIG1vdGl2YXRpb24gYW5kIHdlaWdodCBsb3NzLiBUaGlzIGdyYXBoaWMgaXMgYSB2aXN1YWwgcmVwcmVzZW50YXRpb24gb2YgYSByZWdyZXNzaW9uIGFuYWx5c2lzLiBCb3RoIHBsb3RzIHNob3cgdGhlIHNhbWUgcmF3IGRhdGEsIGJ1dCB0aGUgbGVmdCBwbG90IHNob3dzIGEgbG9lc3MgbGluZSwgd2hpbGUgdGhlIHJpZ2h0IHBsb3Qgc2hvd3MgYSByZWdyZXNzaW9uIGxpbmUuIFxcbGFiZWx7ZmlnOnJlZ3Jlc3Npb24yfSIsIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGVjaG89RkFMU0V9CnJlcXVpcmUoZ2dwbG90MikKcmVxdWlyZShjb3dwbG90KQpyZXF1aXJlKGZsZXhwbG90KQoKZGF0YShleGVyY2lzZV9kYXRhKQpkID1leGVyY2lzZV9kYXRhCmEgPSBmbGV4cGxvdCh3ZWlnaHQubG9zc35tb3RpdmF0aW9uLCBkYXRhPWQpCmIgPSBmbGV4cGxvdCh3ZWlnaHQubG9zc35tb3RpdmF0aW9uLCBkYXRhPWQsIG1ldGhvZD0ibG0iKQpwbG90X2dyaWQoYSxiKQpgYGAKPCEtLSBUaGUgZmxleHBsb3QgbW9kdWxlIGFsc28gaW5jbHVkZXMgdG9vbHMgZm9yIG1vZGVsaW5nLiBXaXRoaW4gdGhlIGZsZXhwbG90IG1lbnUsIG9uZSBjYW4gc2VsZWN0ICJHZW5lcmFsIExpbmVhciBNb2RlbC4iIFRoaXMgbWVudSBhbGxvd3MgdGhlIHVzZXIgdG8gdmlzdWFsaXplIGFuZCBtb2RlbCBpbiB0YW5kZW0uIEluIHRoZSBiYWNrZ3JvdW5kLCBmbGV4cGxvdCBpcyBkZWNpZGluZyBvbiB0aGUgbW9zdCBhcHByb3ByaWF0ZSBncmFwaGljIHRvIGRpc3BsYXksIGdpdmVuIHRoZSBtb2RlbCBzcGVjaWZpZWQgYnkgdGhlIHVzZXIuIEl0IHdpbGwgbm90IG9ubHkgb3V0cHV0IGEgZ3JhcGggb2YgdGhlIGFuYWx5c2lzLCBidXQgaXQgY2FuIGFsc28gZGlzcGxheSBkaWFnbm9zdGljIHBsb3RzIGFuZCBlc3RpbWF0ZXMuIEZpZ3VyZSBccmVme2ZpZzpyZWdtb2R9IHNob3dzIGFuIGV4YW1wbGUgb2YgdGhpcy4gIC0tPgoKIyBBbmFseXNpcyBvZiBWYXJpYW5jZSAoQU5PVkEpL1QtVGVzdAoKQXMgbWVudGlvbmVkIHByZXZpb3VzbHksIGEgY2F0ZWdvcmljYWwgdmFyaWFibGUgbWF5IGJlIHRyZWF0ZWQgYXMgbnVtZXJpYyBhbmQgc3Vic2VxdWVudGx5IHBsb3R0ZWQgYXMgYSBzY2F0dGVycGxvdC4gVGhlIGV4YW1wbGVzIHNob3duIGluIHRoZSBmaXJzdCBhbmQgc2Vjb25kIGdyYXBoaWNzIGFyZSB2aXN1YWwgcmVwcmVzZW50YXRpb24gb2YgYSB0LXRlc3QuIEFzIHRoZSBvbmx5IGRpZmZlcmVuY2UgYmV0d2VlbiBhbiBBTk9WQSBhbmQgYSB0LXRlc3QgaXMgdGhlIG51bWJlciBvZiBncm91cHM7IGEgdmlzdWFsIGZvciBhbiBBTk9WQSBzaW1wbHkgaGFzIHRocmVlIGxldmVscyBvbiB0aGUgeCBheGlzLCByYXRoZXIgdGhhbiB0d28uIFRoZSBmaWd1cmUgYmVsb3cgc2hvd3MgYSBKRCBwbG90cyByZXByZXNlbnRpbmcgYSB0LXRlc3Qgb24gdGhlIGxlZnQsIGFuZCBhbiBBTk9WQSBvbiB0aGUgcmlnaHQuIAoKVGhlIHVzZXIgaGFzIHRoZSBvcHRpb24gb2YgaW5jbHVkZSBtZWFucytzdGFuZGFyZCBlcnJvcnMsIG1lYW5zICsgc3RhbmRhcmQgZGV2aWF0aW9ucywgb3IgbWVkaWFucyB3aXRoIGludGVycXVhcnRpbGUgcmFuZ2VzLiBUaGVzZSBtYXkgdGVjaG5pY2FsbHkgbm90IGJlIG5lY2Vzc2FyeSwgYmVjYXVzZSB0aGUgcmF3IGRhdGEgcHJvdmlkZSBhbGwgdGhlIGluZm9ybWF0aW9uIG9uZSB3b3VsZCBuZWVkLiBIb3dldmVyLCBpdCBpcyBoZWxwZnVsIHRvIHNlZSBhIHZpc3VhbCBkaXNwbGF5IG9mIGNlbnRyYWwgdGVuZGVuY3kgYW5kIHZhcmlhYmlsaXR5IFRoZSBjaG9pY2Ugb2Ygd2hpY2ggZGVwZW5kcyBvbiB3aGF0IHN0YXRpc3RpY3MgdGhlIHVzZXIgY2hvb3NlIHRvIGVtcGhhc2l6ZS4gSWYgb25lIGlzIHBlcmZvcm1pbmcgc2lnbmlmaWNhbmNlIHRlc3RzLCBtZWFucyArIHN0YW5kYXJkIGVycm9ycyBzaG91bGQgcHJvYmFibHkgYmUgcmVwb3J0ZWQgKHNpbmNlIHAtdmFsdWVzIGFyZSBhIGZ1bmN0aW9uIG9mIHN0YW5kYXJkIGVycm9ycykuIElmIG9uZSBpcyBpbnN0ZWFkIGVtcGhhc2l6aW5nIGVmZmVjdCBzaXplcywgc3VjaCBhcyBDb2hlbidzIGQsIG1lYW5zICsgc3RhbmRhcmQgZGV2aWF0aW9ucyB3b3VsZCBiZSBtb3JlIGFwcHJvcHJpYXRlIChzaW5jZSBjb2hlbidzIGQgaXMgYSBmdW5jdGlvbiBvZiBzdGFuZGFyZCBkZXZpYXRpb25zKS4gVGhlIGRlZmF1bHQgaXMgdG8gcmVwb3J0IG1lZGlhbnMgd2l0aCBpbnRlcnF1YXJ0aWxlIHJhbmdlcy4gVGhlIHJhdGlvbmFsZSBmb3IgdGhpcyBpcyB0aGF0IGl0IHdpbGwgaGlnaGxpZ2h0IHBvdGVudGlhbCBkZXZpYXRpb25zIGZyb20gc3RhbmRhcmQgYXNzdW1wdGlvbnMgKG5vcm1hbGl0eSwgaG9tb3NrZWRhc3RpY2l0eSkuICAKCmBgYHtyLCBmaWcuY2FwID0gIlxcbGFiZWx7ZmlnOmFub3ZhfSIsIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGVjaG89RkFMU0V9CnJlcXVpcmUoZ2dwbG90MikKcmVxdWlyZShjb3dwbG90KQpyZXF1aXJlKGZsZXhwbG90KQoKZGF0YShleGVyY2lzZV9kYXRhKQpkID1leGVyY2lzZV9kYXRhCmEgPSBmbGV4cGxvdCh3ZWlnaHQubG9zc35yZXdhcmRzLCBkYXRhPWQsIHNwcmVhZD0ic3RlcnIiKQpiID0gZmxleHBsb3Qod2VpZ2h0Lmxvc3N+dGhlcmFweS50eXBlLCBkYXRhPWQsIHNwcmVhZD0ic3RlcnIiKQpwbG90X2dyaWQoYSxiKQpgYGAKClRvIHByb2R1Y2UgdGhlIGdyYXBoaWNzIGluIEZsZXhwbG90LCBvbmUgd291bGQgc2ltcGx5IHB1dCByZXdhcmRzIChvciB0aGVyYXB5LnR5cGUpIGluIHRoZSBwcmVkaWN0b3IgdmFyaWFibGUgYm94LCBhbmQgd2VpZ2h0Lmxvc3MgaW4gdGhlIG91dGNvbWUgdmFyaWFibGUgYm94LCBsaWtlIGJlbG93Cgo8Y2VudGVyPgoKYHIgc3ByaW50ZigiPGltZyBzcmMgPSAnJXMnIHdpZHRoPSc0MDAnPiIsIG5tcy5maWxlc1szXSlgCgo8L2NlbnRlcj4KCiMgRmFjdG9yaWFsIEFOT1ZBCgpSZWNhbGwgdGhhdCBhIEZhY3RvcmlhbCBBTk9WQSBoYXMgdHdvIGNhdGVnb3JpY2FsIHZhcmlhYmxlcywgcmF0aGVyIHRoYW4gb25lLiBGb3IgZXhhbXBsZSwgd2UgbWlnaHQgYW5hbHl6ZSB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gd2VpZ2h0IGxvc3MgYW5kIGdlbmRlci90aGVyYXB5LnR5cGUuIEEgZ3JhcGhpYyB0byBtYXRjaCBvdWdodCB0byBpbmNvcnBvcmF0ZSAqYm90aCogdmFyaWFibGVzIGluIHRoZSBncmFwaGljLiBUaGlzIGNhbiBiZSBkb25lIGluIG9uZSBvZiB0d28gd2F5cy4gVGhlIGZpcnN0IHdheSBpcyB0byBzaG93IHRoZSBzZWNvbmQgdmFyaWFibGUgYXMgc2VwYXJhdGUgc3ltYm9scy9jb2xvcnMgKGxlZnQtbW9zdCBpbWFnZSBpbiB0aGUgZmlndXJlIGJlbG93KS4gQW5vdGhlciB3YXkgaXMgdG8gc2VwYXJhdGUgaW50byBwYW5lbHMsIGFzIGluIHRoZSBtaWRkbGUgcGxvdCBpbiB0aGUgZmlndXJlIGJlbG93LiBUaGUgYWR2YW50YWdlIG9mIHRoZSBsZWZ0IHBsb3QgKHdoZXJlIHRoZSBzZWNvbmQgZmFjdG9yIGlzIHByZXNlbnRlZCBhcyBzZXBhcmF0ZSBzeW1ib2xzL2NvbG9ycykgaXMgdGhhdCBpdCBtYWtlcyBpdCBlYXNpZXIgdG8gY29tcGFyZSBiZWNhdXNlIHRoZSBzdW1tYXJ5IHN0YXRpc3RpY3MgYXJlIHNpdHVhdGVkIGNsb3NlIHRvIGdldGhlci4gVW5mb3J0dW5hdGVseSwgdGhlcmUgaXMgb2Z0ZW4gYSBsb3Qgb2Ygb3ZlcmxhcCwgd2hpY2ggbWF5IG1hc2sgaW1wb3J0YW50IHJlbGF0aW9uc2hpcHMuIFRoZSBncmFwaGljIGluIHRoZSBtaWRkbGUsIGhvd2V2ZXIsIHJlZHVjZXMgb3ZlcmxhcCwgYnV0IG1ha2VzIGl0IGhhcmRlciB0byBtYWtlIGNvbXBhcmlzb25zIGFjcm9zcyBwYW5lbHMuIFRoZSBmYXIgcmlnaHQgcGFuZWxzIHVzZXMgYSAiZ2hvc3QiIGxpbmUuIFRoZSByZWQgbGluZSwgb3IgdGhlIGdob3N0IGxpbmUsIHNpbXBseSByZXBlYXRzIHRoZSBwYXR0ZXJuIGZyb20gdGhlICJtYWxlIiBwYW5lbCBpbnRvIHRoZSAiZmVtYWxlIiBwYW5lbCwgbWFraW5nIGl0IG11Y2ggZWFzaWVyIHRvIHNlZSB0aGF0LCBhY3Jvc3MgZXhwZXJpbWVudGFsIGNvbmRpdGlvbnMsIGZlbWFsZXMgaGF2ZSBtb3JlIHdlaWdodCBsb3NzIHRoYW4gbWFsZXMuIAoKCmBgYHtyLCBmaWcuY2FwID0gIkRvdCBwbG90cyBvZiB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gZXhwZXJpbWVudGFsIGNvbmRpdGlvbi9nZW5kZXIgYW5kIHdlaWdodCBsb3NzLiBUaGlzIGdyYXBoaWMgaXMgYSB2aXN1YWwgcmVwcmVzZW50YXRpb24gb2YgYSBmYWN0b3JpYWwgQU5PVkEuIEFsbCBncmFwaGljcyBwbG90IHRoZSBzYW1lIGRhdGEsIGJ1dCB0aGUgbGVmdCBwbG90IHNob3dzIHRoZSBtZWFuL3N0YW5kYXJkIGVycm9yLCB3aGlsZSB0aGUgcmlnaHQgc2hvd3MgdGhlIG1lZGlhbi9pbnRlcnF1YXJ0aWxlIHJhbmdlLiBcXGxhYmVse2ZpZzpmYWN0b3JpYWx9IiwgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9NSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgbm90ZT1GQUxTRSwgZWNobz1GQUxTRX0KcmVxdWlyZShnZ3Bsb3QyKQpyZXF1aXJlKGNvd3Bsb3QpCnJlcXVpcmUoZmxleHBsb3QpCgpkYXRhKGV4ZXJjaXNlX2RhdGEpCmQgPWV4ZXJjaXNlX2RhdGEKYSA9IGZsZXhwbG90KHdlaWdodC5sb3NzfnRoZXJhcHkudHlwZSArIGdlbmRlciwgZGF0YT1kKQpiID0gZmxleHBsb3Qod2VpZ2h0Lmxvc3N+dGhlcmFweS50eXBlIHwgZ2VuZGVyLCBkYXRhPWQpCmMgPSBmbGV4cGxvdCh3ZWlnaHQubG9zc350aGVyYXB5LnR5cGUgfCBnZW5kZXIsIGRhdGE9ZCwgZ2hvc3QubGluZT0icmVkIiwgZ2hvc3QucmVmZXJlbmNlPWxpc3QoZ2VuZGVyPSJNYWxlIikpCnBsb3RfZ3JpZChhLGIsYyxuY29sPTMpCgpudyA9IHBhc3RlMCgiIVtdKCIsIG5tcy5maWxlc1s0OjZdLCAiIDMwMHgzMDApICIsIGNvbGxhcHNlPSIgIikKYGBgCgoKT25lIGRpZmZpY3VsdHkgd2l0aCBtdWx0aXZhcmlhdGUgZGF0YSBzdWNoIGFzIHRoaXMgaXMgdGhhdCBvbmUgdGhlbiBoYXMgdG8gY2hvb3NlIHdoaWNoIHZhcmlhYmxlIGdvZXMgb24gdGhlIFggYXhpcy4gRWFjaCB3aWxsIGdpdmUgYSBkaWZmZXJlbnQgInZpZXciIG9mIHRoZSBkYXRhIGFuZCwgYXMgc3VjaCwgYm90aCBvdWdodCB0byBiZSBkaXNwbGF5ZWQgKGlmIG5vdCBmb3IgcHVibGljYXRpb24sIGF0IGxlYXN0IGR1cmluZyBkYXRhIGFuYWx5c2lzKS4gVGhlIGZpZ3VyZSwgZm9yIGV4YW1wbGUsIHNob3dzIHRoZXJhcHkudHlwZSBvbiB0aGUgeCBheGlzIGluIHRoZSBsZWZ0IHBhbmVsLCBhbmQgZ2VuZGVyIGluIHRoZSByaWdodCBwYW5lbC4gRWFjaCBnaXZlcyBkaWZmZXJlbnQgaW5zaWdodHMgaW50byB0aGUgZGF0YS4gSW4gdGhpcyBjYXNlLCB0aGUgbGVmdCBwYW5lbCBlbXBoYXNpemVzIHRoZSBtYWluIGVmZmVjdCBvZiB0aGVyYXB5LnR5cGUsIHdoaWxlIHRoZSByaWdodCBwYW5lbCBlbXBoYXNpemVzIHRoZSBtYWluIGVmZmVjdCBvZiBnZW5kZXIuICAKCmBgYHtyLCBmaWcuY2FwID0gIkRvdCBwbG90cyBvZiB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gZXhwZXJpbWVudGFsIGNvbmRpdGlvbi9nZW5kZXIgYW5kIHdlaWdodCBsb3NzLiBUaGVzZSBncmFwaGljcyBzaG93IHRoZSByZXN1bHRzIHdpdGggZGlmZmVyZW50IHZhcmlhYmxlcyByZXByZXNlbnRlZCBvbiB0aGUgeC1heGlzL2FzIHNlcGFyYXRlZCBsaW5lcy4gIFxcbGFiZWx7ZmlnOmZhY3RvcmlhbDJ9IiwgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9NSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1UUlVFfQpyZXF1aXJlKGdncGxvdDIpCnJlcXVpcmUoY293cGxvdCkKcmVxdWlyZShmbGV4cGxvdCkKCmRhdGEoZXhlcmNpc2VfZGF0YSkKZCA9ZXhlcmNpc2VfZGF0YQphID0gZmxleHBsb3Qod2VpZ2h0Lmxvc3N+Z2VuZGVyIHwgdGhlcmFweS50eXBlLCBkYXRhPWQsIGdob3N0LmxpbmU9InJlZCIpCmMgPSBmbGV4cGxvdCh3ZWlnaHQubG9zc350aGVyYXB5LnR5cGUgfCBnZW5kZXIsIGRhdGE9ZCwgZ2hvc3QubGluZT0icmVkIikKcGxvdF9ncmlkKGEsYyxuY29sPTIpCmBgYAoKIyBBTkNPVkEKQW4gQU5DT1ZBIGdlbmVyYWxseSBpbnZvbHZlcyBhIGNhdGVnb3JpY2FsIGdyb3VwaW5nIHZhcmlhYmxlIChlLmcuLCBhbiBleHBlcmltZW50YWwgZWZmZWN0KSBhbmQgYSBudW1lcmljICJjb3ZhcmlhdGUuIiBXaGVuIG9uZSBwZXJmb3JtcyBhbiBBTkNPVkEsIHRoZXkgYXJlIHR5cGljYWxseSBub3QgaW50ZXJlc3RlZCBpbiB0aGUgY292YXJpYXRlLiBSYXRoZXIsIHRoZXkgc2VlayB0aGUgcmVtb3ZlIHRoZSBpbmZsdWVuY2Ugb2YgdGhhdCBwcmVkaWN0b3Igb24gdGhlIG91dGNvbWUuIE9uZSB3YXkgdG8gdmlzdWFsaXplIHJlbW92aW5nIHRoZSBlZmZlY3Qgb2YgYSBwcmVkaWN0b3Igb24gYW4gb3V0Y29tZSBpcyB3aXRoIEFkZGVkIFZhcmlhYmxlIFBsb3RzIChBVlBzKS4gSW4gdGhlIGJhY2tncm91bmQsIHRoZSBBVlAgbW9kZWxzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgY292YXJpYXRlIGFuZCB0aGUgb3V0Y29tZSwgcmVzaWR1YWxpemVzIHRoZSBlZmZlY3Qgb2YgdGhlIGNvdmFyaWF0ZSAoaS5lLiwgc3VidHJhY3RpbmcgdGhlIGZpdHRlZCBzY29yZSBmcm9tIHRoZSBhY3R1YWwgc2NvcmUpLCB0aGVuIHBsb3RzIHRoZSBjYXRlZ29yaWNhbCB2YXJpYWJsZSBhZ2FpbnN0IHRoZSByZXNpZHVhbHMuIFJlc2lkdWFsaXppbmcgYSBwcmVkaWN0b3JlIHJlbW92ZXMgYW55IHNpZ25hbCBhc3NvY2lhdGVkIHdpdGggdGhlICpsaW5lYXIgZWZmZWN0KiBvZiB0aGF0IHByZWRpY3Rvci4gCgpSZXNpZHVhbGl6aW5nIGRvZXMgbm90LCBob3dldmVyLCByZW1vdmUgYW55IG5vbmxpbmVhciByZWxhdGlvbnNoaXBzLCBzdWNoIGFzIGludGVyYWN0aW9uIGVmZmVjdHMgYW5kIHBvbHlub21pYWxzLiBCZWNhdXNlIG9mIHRoaXMsIEkgcmVjb21tZW5kIHBsb3R0aW5nIHR3byBncmFwaGljcy4gT25lIGdyYXBoaWMgd2lsbCBkaXNwbGF5IHRoZSBncm91cGluZyB2YXJpYWJsZSBhcyBzZXBhcmF0ZWQgbGluZXMvY29sb3JzL3N5bWJvbHMuIFRoaXMgZmlyc3QgZ3JhcGhpYyB3aWxsIG1ha2UgaXQgY2xlYXIgd2hldGhlciBub25saW5lYXIgYW5kL29yIGludGVyYWN0aW9uIGVmZmVjdHMgYXJlIHByZXNlbnQuIFRoaXMgaXMgdGhlbiBzdXBwbGVtZW50ZWQgd2l0aCBhbiBBVlAuCgpGb3IgZXhhbXBsZSwgdGhlIGxlZnQgcGFuZWwgb2YgdGhlIGZpZ3VyZSBiZWxvdyBzaG93cyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gbW90aXZhdGlvbiBhbmQgd2VpZ2h0Lmxvc3MgZm9yIGVhY2ggdGhlcmFweS50eXBlICh3aXRoIGEgZ2hvc3QgbGluZSwgZm9yIGJldHRlciBpbnRlcnByZXRhdGlvbikuIFRoZXJlIG1heSBiZSAqc29tZSogbm9ubGluZWFyaXR5IHByZXNlbnQsIGFuZCB0aGUgbGluZXMgbWF5IGRldmlhdGUgZnJvbSBwYXJhbGxlbCAoaW5kaWNhdGluZyBhbiBpbnRlcmFjdGlvbiBlZmZlY3QpLiBIb3dldmVyLCB0aGVzZSBhcmUgcmVsYXRpdmVseSBzbWFsbCBzYW1wbGUgc2l6ZXMsIHNvIHRoZXNlIG1pbm9yIGRldmlhdGlvbnMgYXJlIHByb2JhYmx5IG5vdGhpbmcgdG8gd29ycnkgYWJvdXQuIFRoZSByaWdodCBwYW5lbCBzaG93cyB0aGUgbWVhbiBkaWZmZXJlbmNlcyBvbiB0aGUgcmVzaWR1YWxpemVkIG91dGNvbWUgdmFyaWFibGUgKGFzIGluZGljYXRlZCBieSB3ZWlnaHQubG9zc3xtb3RpdmF0aW9uKSwgc2hvd2luZyB0aGF0IHRoZXJlJ3MgYSBzbGlnaHQgYWR2YW50YWdlIGZvciBiZWggb3ZlciBib3RoIGNvZyBhbmQgY29udHJvbCBjb25kaXRpb25zLiAKCk5vcm1hbGx5IHdoZW4gb25lIHJlc2lkdWFsaXplcyBhIHByZWRpY3RvciB2YXJpYWJsZSBmcm9tIGFuIG91dGNvbWUsIHRoZSByZXNpZHVhbHMgYXJlIGNlbnRlcmVkIGFyb3VuZCB6ZXJvLiBUaGlzIGNhbiBiZSBjb25mdXNpbmcgZm9yIHRob3NlIHVuZmFtaWxpYXIgd2l0aCBBVlBzLiBBcyBzdWNoLCBGbGV4cGxvdCBhZGRzIHRoZSBtZWFuIG9mIHRoZSBkZXBlZGVudCB2YXJpYWJsZSBiYWNrIGludG8gdGhlIHJlc2lkdWFscyB0byBtYWtlIHRoZSB2aXN1YWxzIGxlc3MgaW50aW1pZGF0aW5nLiAKCgpgYGB7ciwgZmlnLmNhcCA9ICJEb3QgcGxvdHMgb2YgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHdlaWdodCBsb3NzIGFuZCBleHBlcmltZW50YWwgY29uZGl0aW9uL21vdGl2YXRpb24uIC4uLiBcXGxhYmVse2ZpZzphbmNvdmF9IiwgZWNobyA9IEZBTFNFLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD01LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBlY2hvPUZBTFNFfQpyZXF1aXJlKGdncGxvdDIpCnJlcXVpcmUoY293cGxvdCkKcmVxdWlyZShmbGV4cGxvdCkKCmRhdGEoZXhlcmNpc2VfZGF0YSkKZCA9ZXhlcmNpc2VfZGF0YQphID0gZmxleHBsb3Qod2VpZ2h0Lmxvc3N+bW90aXZhdGlvbiB8IHRoZXJhcHkudHlwZSwgZGF0YT1kLCBnaG9zdC5saW5lPSJyZWQiKQpiID0gYWRkZWQucGxvdCh3ZWlnaHQubG9zc35tb3RpdmF0aW9uICsgdGhlcmFweS50eXBlLCBkYXRhPWQpCnBsb3RfZ3JpZChhLGIsbmNvbD0yKQpgYGAKClRvIGNyZWF0ZSB0aGUgbGVmdCBncmFwaGljIGluIEphbW92aSwgb25lIHdvdWxkIHNpbXBseSBwdXQgd2VpZ2h0Lmxvc3MgaW4gdGhlIG91dGNvbWUgdmFyaWFibGUgYm94LCBtb3RpdmF0aW9uIGluIHByZWRpY3RvciB2YXJpYWJsZSBib3gsIGFuZCB0aGVyYXB5LnR5cGUgaW4gdGhlIHBhbmVsIGJveC4gTm90aWNlIHRoZSBnaG9zdC5saW5lIGJveCBpcyBjaGVja2VkLiBUbyBjcmVhdGUgdGhlIHJpZ2h0IGdyYXBoaWMsIG9uZSB3b3VsZCBkbyBhbGwgdGhlIHNhbWUsIGV4Y2VwdCBjaGVjayB0aGUgIlJlc2lkdWFsaXplIHByZWRpY3RvciB2YXJpYWJsZSIgYm94IGlzIGNoZWNrZWQuIAoKPGNlbnRlcj4KCmByIHNwcmludGYoIjxpbWcgc3JjID0gJyVzJyB3aWR0aD0nNDAwJz4iLCBubXMuZmlsZXNbOF0pYAoKYHIgc3ByaW50ZigiPGltZyBzcmMgPSAnJXMnIHdpZHRoPSc0MDAnPiIsIG5tcy5maWxlc1s5XSlgCgo8L2NlbnRlcj4KCiMgTXVsdGlwbGUgUmVncmVzc2lvbgoKRmluYWxseSwgd2UgY29tZSB0byBtdWx0aXBsZSByZWdyZXNzaW9uIChNUikuIFJlc2VhcmNoZXJzIHRlbmQgdG8gY2FsbCBhbiBhbmFseXNpcyBhIE1SIGlmIHRoZXkgaW5jbHVkZSBtdWx0aXBsZSBudW1lcmljIHZhcmlhYmxlcy4gSW4gYWN0dWFsaXR5LCBNUiBpcyBzeW5vbnltb3VzIHdpdGggdGhlIEdMTTsgdGhlIG1hdGhlbWF0aWNzIChhbmQgZmxleHBsb3QsIGZvciB0aGF0IG1hdHRlcikgZG9uJ3QgY2FyZSB3aGV0aGVyIHRoZSByZXNlYXJjaGVyIGNvbnNpZGVycyB0aGUgdmFyaWFibGVzIG51bWVyaWMgb3IgY2F0ZWdvcmljYWwuIEFzIHN1Y2gsIHdlIHdpbGwgaWxsdXN0cmF0ZSBtdWx0aXBsZSB2YXJpYWJsZSB0eXBlcyBpbiB0aGlzIHNlY3Rpb24uIAoKV2hlbiBwbG90dGluZyBtdWx0aXZhcmlhdGUgcmVsYXRpb25zaGlwcywgaXMgaXQgZXNzZW50aWFsIHRoYXQgd2UgdXNlIHBhbmVsaW5nLCBBVlBzLCBhbmQgZ2hvc3QgbGluZXMsIG90aGVyd2lzZSB0aGluZ3MgYmVjb21lIG92ZXJseSBjb21wbGljYXRlZC4gVGhlIGh1bWFuIGJyYWluIGlzIG9ubHkgY2FwYWJsZSBvZiByZXRhaW5pbmcgc28gbXVjaCBpbmZvcm1hdGlvbiBhdCBvbmNlLiBUbyBmdXJ0aGVyIHNpbXBsaWZ5IHRoZSBhbmFseXNpcywgSSBnZW5lcmFsbHkgcmVtb3ZlIHRoZSBzdGFuZGFyZCBlcnJvciBiYXJzIGZyb20gdGhlIHBsb3RzIHNpbmNlIHRoZXkgdGVuZCB0byBhZGQgb3ZlcmxhcCBiZXR3ZWVuIGRpZmZlcmVudCBwbG90dGVkIHJlbGF0aW9uc2hpcHMuIEkgYWxzbyB0ZW5kIHRvIHBsb3QgcmVncmVzc2lvbiBsaW5lcywgdW5sZXNzIHRoZSBsb2VzcyBsaW5lcyBpbmRpY2F0ZSBzZXJpb3VzIGRldmlhdGlvbnMgZnJvbSBub3JtYWxpdHkuIEFsc28sIGZsZXhwbG90IGlzIG9ubHkgY2FwYWJsZSBvZiBwbG90dGluZyBmb3VyIHByZWRpY3RvciB2YXJpYWJsZXMgYXQgb25jZS4gTW9yZSB0aGFuIHRoYXQgaXMgKmV4Y2VwdGlvbmFsbHkqIGRpZmZpY3VsdCBmb3IgdGhlIGh1bWFuIG1pbmQgdG8gaW50ZXJwcmV0LCBzbyBJIGhhdmUgZWxlY3RlZCBub3QgdG8gYWxsb3cgbW9yZSB0aGFuIHRoYXQuIChPbmUgY291bGQgcGxvdCBzZXBhcmF0ZSBwYW5lbGVkIGdyYXBocyBmb3IgZWFjaCBvZiB0aGUgbGV2ZWxzIG9mICphbm90aGVyKiB2YXJpYWJsZSB0byBhY2NvbXBsaXNoIHRoaXMsIGJ1dCBhZ2FpbiwgdGhhdCBiZWNvbWVzIHF1aXRlIGRpZmZpY3VsdCB0byBpbnRlcnByZXQpLiAKClRoZXJlIGlzIG9uZSBvdGhlciBpbXBvcnRhbnQgZmVhdHVyZSBvZiBmbGV4cGxvdCB0aGF0IG5lZWRzIG5vdGluZyBiZWZvcmUgSSBkZW1vbnN0cmF0ZSBpbiBKYW1vdmk7IGNhdGVnb3JpY2FsIHZhcmlhYmxlcyBpbiB0aGUgc2Vjb25kLCBheGlzLCByb3cgcGFuZWxzLCBvciBjb2x1bW4gcGFuZWxzIHdpbGwgYmUgImJpbm5lZC4iIEJpbiBzaW1wbHkgbWVhbnMgd2UgY29udmVydCB0aGVtIHRvIGNhdGVnb3JpY2FsIHZhcmlhYmxlcyAoZS5nLiwgZWFjaCBzY29yZSBvbiB0aGUgY2F0ZWdvcmljYWwgaXMgY2F0ZWdvcml6ZWQgYXMgaGlnaCwgbWVkaXVtLCBvciBsb3cpLiBXaXRob3V0IHRoaXMgc3RlcCwgdGhlcmUgd291bGQgYmUgYXMgbWFueSBwYW5lbHMgYXMgdGhlcmUgYXJlIHVuaXF1ZSB2YWx1ZXMgb2YgdGhlIG51bWVyaWMgdmFyaWFibGUuIAoKSGF2aW5nIHNhaWQgdGhhdCwgbGV0IG1lIGludHJvZHVjZSBhIHN0cmF0ZWd5IEkgdXNlIHRvIHZpc3VhbGl6ZSBtdWx0aXZhcmlhdGUgcmVsYXRpb25zaGlwcy4gTGV0IHVzIGFzc3VtZSB3ZSBhcmUgaW50ZXJlc3RlZCBpbiBzdHVkeWluZyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gd2VpZ2h0Lmxvc3MgYW5kIGVhY2ggb2YgdGhlIGZvbGxvd2luZyBwcmVkaWN0b3JzOiBtb3RpdmF0aW9uLCBoZWFsdGgsIG11c2NsZSBnYWluLCBhbmQgdGhlcmFweS50eXBlLiBJIHdpbGwgZmlyc3Qgc3RhcnQgYnkgcGxvdHRpbmcgdGhlIGJpdmFyaWF0ZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB3ZWlnaHQubG9zcyBhbmQgZWFjaCBwcmVkaWN0b3IgdmFyaWFibGUuIFdoZW4gZG9pbmcgdGhpcywgSSBhbSBsb29raW5nIGZvciBhIGNvdXBsZSBvZiB0aGluZ3MuIEZpcnN0LCBJIGFtIGxvb2tpbmcgZm9yIGJlbmRzIGluIHRoZSByZWxhdGlvbnNoaXBzLiBJZiB0aGVyZSBhcmUgbm8gYmVuZHMsIEkgd2lsbCBwbG90IHN0cmFpZ2h0IGxpbmVzIGZvciB0aGUgbXVsdGl2YXJpYXRlIHBsb3QsIHdoaWNoIGFyZSBmYXIgZWFzaWVyIHRvIGludGVycHJldC4gSSBhbSBhbHNvIGxvb2tpbmcgZm9yIHRoZSB2YXJpYWJsZSB3aXRoIHRoZSB3ZWFrZXN0IHJlbGF0aW9uc2hpcCB3aXRoIHdlaWdodC5sb3NzLiBJIGxvb2sgZm9yIHRoZSB3ZWFrZXN0IGZpcnN0IGJlY2F1c2UgSSBhbSBsb29raW5nIHRvIHJlZHVjZSB0aGUgbnVtYmVyIG9mIHZhcmlhYmxlcyB0byB2aXN1YWxpemUgYXMgcXVpY2tseSBhcyBwb3NzaWJsZS4gVGhlIHdlYWtlc3QgYml2YXJpYXRlIHJlbGF0aW9uc2hpcCB3aWxsIGxpa2VseSBiZSB0aGUgd2Vha2VzdCBtdWx0aXZhcmlhdGUgcmVsYXRpb25zaGlwLiBJZiBpdCdzIHNtYWxsIGVub3VnaCBub3QgdG8gd29ycnkgYWJvdXQsIEkgd2lsbCBnZW5lcmFsbHkgcmVtb3ZlIHRoYXQgdmFyaWFibGUuIEluIHRoZSBiZWxvdyBmaWd1cmUsIGdlbmRlciBzZWVtcyB0byBoYXZlIHRoZSB3ZWFrZXN0IHJlbGF0aW9uc2hpcCwgYW5kIHNvbWUgdmFyaWFibGVzIGhhdmUgYSBub25saW5lYXIgcmVsYXRpb25zaGlwIHdpdGggc2F0aXNmYWN0aW9uLiAKCgpgYGB7ciwgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9NSwgZWNobyA9IEZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpyZXF1aXJlKHRpZHl2ZXJzZSkKcmVxdWlyZShjb3dwbG90KQpyZXF1aXJlKGZsZXhwbG90KQoKZGF0YSgicmVsYXRpb25zaGlwX3NhdGlzZmFjdGlvbiIpCmQgPXJlbGF0aW9uc2hpcF9zYXRpc2ZhY3Rpb24gJT4lIGZpbHRlcihnZW5kZXIgPT0gIkZlbWFsZSIgfCBnZW5kZXI9PSJNYWxlIikKYSA9IGZsZXhwbG90KHNhdGlzZmFjdGlvbn5jb25zY2llbnRpb3VzbmVzcywgZGF0YT1kKQpiID0gZmxleHBsb3Qoc2F0aXNmYWN0aW9ufmhvbmVzdHksIGRhdGE9ZCkKYyA9IGZsZXhwbG90KHNhdGlzZmFjdGlvbn5jb21tdW5pY2F0aW9uLCBkYXRhPWQpCmUgPSBmbGV4cGxvdChzYXRpc2ZhY3Rpb25+Z2VuZGVyLCBkYXRhPWQpCnBsb3RfZ3JpZChhLGIsYyxlLG5jb2w9MikKYGBgCgoKRm9sbG93aW5nIHVuaXZhcmlhdGUgdmlzdWFscywgSSB0aGVuIHBsb3QgdGhlIG11bHRpdmFyaWF0ZSB2aXN1YWwuIEluIHRoaXMgY2FzZSwgSSB3aWxsIHBsYWNlIGdlbmRlciBvbiB0aGUgWCBheGlzLCBhbmQgcGxvdCBjb25zY2llbnRpb3VzbmVzcyBhcyBzZXBhcmF0ZSBsaW5lcy9jb2xvcnMvc3ltYm9scy4gVGhlIG90aGVyIHR3byB2YXJpYWJsZXMgd2lsbCBzaW1wbHkgYmUgcGxhY2VkIGluIHBhbmVscyAod2hldGhlciByb3dzIG9yIGNvbHVtbnMgZG9lc24ndCBtYXR0ZXIpLiBUaGlzIGltYWdlIGlzIHNob3duIGJlbG93LgoKCgpgYGB7ciwgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9NSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1GQUxTRX0KcmVxdWlyZShnZ3Bsb3QyKQpyZXF1aXJlKGNvd3Bsb3QpCnJlcXVpcmUoZmxleHBsb3QpCgphID0gZmxleHBsb3Qoc2F0aXNmYWN0aW9ufmdlbmRlciArIGNvbnNjaWVudGlvdXNuZXNzfCBjb21tdW5pY2F0aW9uICsgaG9uZXN0eSwgZGF0YT1kLCBtZXRob2Q9ImxtIiwgc2U9RikKYQpgYGAKCkF0IHRoaXMgcG9pbnQsIEknbSB0cnlpbmcgdG8gZGlzbWlzcyBnZW5kZXIgYXMgYW4gaW1wb3J0YW50IHByZWRpY3Rvci4gRWxpbWluYXRpbmcgYSB2YXJpYWJsZSB3b3VsZCBzaW1wbGlmeSB0aGUgYW5hbHlzaXMgaW1tZW5zZWx5LiBUaGUgb25seSBwbGFjZSBJIHNlZSBhIGxhcmdlIGRpZmZlcmVuY2UgYmV0d2VlbiBnZW5kZXJzIGlzIGluIHRoZSBmaXJzdCBjb2x1bW4vcm93IHBhbmVsLiBIb3dldmVyLCB0aGlzIG9ubHkgc2hvd3MgYSBsYXJnZSBkaWZmZXJlbmNlIGJlY2F1c2UgdGhlcmUncyBvbmx5IG9uZSBNYWxlIGluIHRoYXQgcGFuZWwuIEFzIHN1Y2gsIEknbSBnb2luZyB0byBkaXNtaXNzIGdlbmRlciBhcyBhbiBpbXBvcnRhbnQgcHJlZGljdG9yIGFuZCBpbnN0ZWFkIGxvb2sgYXQgdGhlIG90aGVyIHRocmVlIHZhcmlhYmxlcy4gCgpgYGB7ciwgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9NSwgbWVzc2FnZT1GQUxTRSxlY2hvID0gRkFMU0UsICB3YXJuaW5nPUZBTFNFfQpyZXF1aXJlKGdncGxvdDIpCnJlcXVpcmUoY293cGxvdCkKcmVxdWlyZShmbGV4cGxvdCkKCmEgPSBmbGV4cGxvdChzYXRpc2ZhY3Rpb25+IGNvbnNjaWVudGlvdXNuZXNzfCBjb21tdW5pY2F0aW9uICsgaG9uZXN0eSwgZGF0YT1kLCBtZXRob2Q9ImxtIiwgc2U9RiwgZ2hvc3QubGluZT0icmVkIikKYQpgYGAKCgpBdCB0aGlzIHBvaW50LCBJIGFtIGxvb2tpbmcgZm9yIG5vbi1wYXJlbGxlbCBsaW5lcy4gTm9uLXBhcmFsbGVsIGxpbmVzIHNpZ25hbCBhbiBpbnRlcmFjdGlvbiwgYnV0IEknbSBhbHNvIHdhcnkgb2YgaW50ZXJwcmV0aW5nIGFueSBkZXZpYXRpb24gZnJvbSBwYXJhbGxlbCBhcyBpbXBvcnRhbnQuIEknbSBpbmNsaW5lZCB0byBzYXkgdGhlc2UgZml0dGVkIGxpbmVzIGFyZSByb3VnaGx5IHBhcmFsbGVsLCBidXQgSSdtIG5vdCBlbnRpcmVseSBzdXJlLiBUaGlzIGlzIHdoZXJlIG1vZGVsaW5nIGNhbiBiZSBleHRyZW1lbHkgdXNlZnVsLiBJIGNhbiBmaXQgYSBtb2RlbCB3aXRoIGludGVyYWN0aW9ucyBhbmQgYSBtb2RlbCB3aXRob3V0IGludGVyYWN0aW9ucyBhbmQgY29tcGFyZSB0aGUgZml0cy4gVGhlIGJlbG93IHRhYmxlIHNob3dzIHZhcmlvdXMgc3RhdGlzdGljcyB0byBhc3Nlc3MgdGhlIHR3byBtb2RlbHMuIEZvcnR1bmF0ZWx5LCBhbGwgbWV0cmljcyBhZ3JlZSB0aGF0IHRoZSBzaW1wbGVyIG1vZGVsIGlzIGEgYmV0dGVyIG1vZGVsLiAKCmBgYHtyLCByZXN1bHRzPSdhc2lzJywgbWVzc2FnZT1GQUxTRSwgZWNobyA9IEZBTFNFLCB3YXJuaW5nPUZBTFNFfQpyZXF1aXJlKGtuaXRyKQoKYSA9IGxtKHNhdGlzZmFjdGlvbn4gY29uc2NpZW50aW91c25lc3MrY29tbXVuaWNhdGlvbitob25lc3R5LCBkYXRhPWQpCmIgPSBsbShzYXRpc2ZhY3Rpb25+IGNvbnNjaWVudGlvdXNuZXNzKmNvbW11bmljYXRpb24qaG9uZXN0eSwgZGF0YT1kKQptYyA9IG1vZGVsLmNvbXBhcmlzb24oYSxiKSRzdGF0aXN0aWNzCnJvdy5uYW1lcyhtYykgPSBjKCJNYWluIEVmZmVjdHMgTW9kZWwiLCAiSW50ZXJhY3Rpb24gTW9kZWwiKQprYWJsZShtYywgZm9ybWF0ID0gImh0bWwiLCBkaWdpdHM9MikKCmBgYAoKQXQgdGhpcyBwb2ludCwgdGhlIHZpc3VhbGl6YXRpb25zIGJlY29tZSBleHRyZW1lbHkgZWFzeS4gVGhlIG1vZGVsIGNvbXBhcmlzb24gc3VnZ2VzdHMgdGhlcmUgYXJlIG9ubHkgbWFpbiBlZmZlY3RzLCB3aGljaCBtZWFucyB3ZSBhcmUgbXVjaCBzYWZlciBpbiB1c2luZyBBVlBzLiBHcmFudGVkLCB0aGVyZSBtYXkgYmUgc29tZSBub25saW5lYXJpdHkgcHJlc2VudCBpbiB0aGUgcmVzaWR1YWxzIG9mIHRoZSBBVlAgcGxvdCwgYnV0IEknbSBub3QgdG8gd29ycmllZCBhYm91dCB0aGF0IGF0IHRoaXMgcG9pbnQuIFdlIGNhbiB2aXN1YWxpemUgdGhlIG5vbmxpbmVhcml0eSB3aXRoIHRoZSBBVlBzLCBhcyBzaG93biBpbiB0aGUgZm9sbG93aW5nIGZpZ3VyZS4gCgpgYGB7ciwgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9NSwgbWVzc2FnZT1GQUxTRSxlY2hvID0gRkFMU0UsICB3YXJuaW5nPUZBTFNFfQpyZXF1aXJlKGdncGxvdDIpCnJlcXVpcmUoY293cGxvdCkKcmVxdWlyZShmbGV4cGxvdCkKCmhlYWQoZCkKYSA9IGFkZGVkLnBsb3Qoc2F0aXNmYWN0aW9ufiBjb25zY2llbnRpb3VzbmVzc3wgY29tbXVuaWNhdGlvbiArIGhvbmVzdHksIGRhdGE9ZCwgbWV0aG9kPSJwb2x5bm9taWFsIiwgc2U9RikKYiA9IGFkZGVkLnBsb3Qoc2F0aXNmYWN0aW9ufiBjb25zY2llbnRpb3VzbmVzc3wgaG9uZXN0eSArIGNvbW11bmljYXRpb24gLCBkYXRhPWQsIG1ldGhvZD0icG9seW5vbWlhbCIsIHNlPUYpCmMgPSBhZGRlZC5wbG90KHNhdGlzZmFjdGlvbn4gIGNvbW11bmljYXRpb24gKyBob25lc3R5ICsgY29uc2NpZW50aW91c25lc3MsIGRhdGE9ZCwgbWV0aG9kPSJwb2x5bm9taWFsIiwgc2U9RikKcGxvdF9ncmlkKGEsYixjLCBucm93PTEpCgpgYGAKClRoZXNlIHZpc3VhbHMgc3VnZ2VzdCBhbGwgdmFyaWFibGVzIG1heSBoYXZlIGEgbm9ubGluZWFyIGFzc29jaWF0aW9uIHdpdGggc2F0aXNmYWN0aW9uLCBvbmNlIHdlIGNvbnRyb2xsIGZvciBhbGwgdGhlIG90aGVyIHZhcmlhYmxlcyBpbiB0aGUgbW9kZWwuIFRoZXJlJ3MgYWxzbyBzb21lIGV2aWRlbmNlIG9mIGhldGVyb3NrZWRhc3RpY2l0eSwgYnV0IGFkZHJlc3NpbmcgdGhhdCBpcyBiZXlvbmQgdGhlIHNjb3BlIG9mIHRoaXMgcGFwZXIuIAoKIyBTdW1tYXJ5CkluIHRoaXMgcGFwZXIsIHdlIGhhdmUgaW50cm9kdWNlZCBGbGV4cGxvdCwgYW4gZWFzeS10by11c2Ugc29mdHdhcmUgcGFja2FnZSB0aGF0IGFsbG93cyBmbGV4aWJsZSBhbmQgc2ltcGxlIHZpc3VhbGl6YXRpb25zIHdpdGggYSBncmFwaGljYWwgdXNlciBpbnRlcmZhY2UuIFdlIGhhdmUgYWxzbyBpbnRyb2R1Y2VzIHZhcmlvdXMgZ3JhcGhpY2FsIHRvb2xzLCBpbmNsdWRpbmcgYWRkZWQgdmFyaWFibGUgcGxvdHMsIGppdHRlcmVkIGRlbnNpdHkgcGxvdHMsIGdob3N0IGxpbmVzLCBwYW5lbGluZywgZXRjLiBXZSBhbHNvIGNvbmNsdWRlZCB3aXRoIGEgZ2VuZXJhbCBzdHJhdGVneSBmb3IgY29tcGxleCBtdWx0aXZhcmlhdGUgdmlzdWFsaXphdGlvbnMuIEl0IGlzIG91ciBob3BlIHRoZXNlIHRvb2xzIGFuZCBkZW1vbnN0cmF0aW9ucyBzZWVtIGJvdGggYXBwcm9hY2hhYmxlIGFuZCBoZWxwZnVsLCBhbmQgdGhhdCByZXNlYXJjaGVycyBoYXZlIG5vIGhlc2l0YXRpb25zIGFib3V0IHV0aWxpemluZyB0aGUgdG9vbHMgYXZhaWxhYmxlIHRvIGZsZXhwbG90LiAKClxuZXdwYWdlCgojIFJlZmVyZW5jZXMKCgpcc2V0bGVuZ3Roe1xwYXJpbmRlbnR9ey0wLjVpbn0KXHNldGxlbmd0aHtcbGVmdHNraXB9ezAuNWlufQoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgojCg==