Introduction

This problem is a typical econometric modeling situation. The Phillips Curve says that inflation and unemployment move in opposite directions. It was the basis for the Fed fighting unemployment by allowing a bit of inflation.

Actually in recent years especially since 2008 this theory is somewhat discredited, though the Trump administration seems to believe it. Few economists believe the link is that close anymore.

The Problem

The Phillips curve and modified Phillips curve relating inflation and unemployment are presented in Example 6.6 in the book. I’d read that first. Now we can examine Example 6.7, which presents some data to test for the Phillips curve.

We quote from the book:

As an illustration of the modified Phillips curve, we present in Table 6.5 data on inflation as measured by year-to-year percentage in the Consumer Price Index (CPI) and the unemployment rate for the period 1960–2006. The unemployment rate represents the civilian unemployment rate. From these data we obtained the change in the inflation rate \((\pi_t − \pi_{t−1})\) and plotted it against the civilian unemployment rate; we are using the CPI as a measure of inflation. The resulting graph appears in Figure 6.9.

As expected, the relation between the change in inflation rate and the unemployment rate is negative—– a low unemployment rate leads to an increase in the inflation rate and therefore an acceleration of the price level, hence the name accelerationist Phillips curve. Looking at Figure 6.9, it is not obvious whether a linear (straight line) regression model or a reciprocal model fits the data; there may be a curvilinear relationship between the two variables. We present below regressions based on both the models. However, keep in mind that for the reciprocal model the intercept term is expected to be negative and the slope positive, as noted in footnote 20.

Linear model:

\[(\pi_t − \pi_{t−1}) = 3.7844 − 0.6385 UN_t \qquad\qquad(6.7.5)\]

\[t = (4.1912) (−4.2756) \qquad R^2 = 0.2935\]

Reciprocal model:

\[(\pi_t − pi_{t−1}) = −3.0684 + 17.2077 (1/UN_t) \qquad\qquad(6.7.6)\]

\[t = (−3.1635) (3.2886) \qquad R^2 = 0.1973\]

All the estimated coefficients in both the models are individually statistically significant, all the p values being lower than the 0.005 level.

We are supposed to use the data in Table 6.5 to create these regressions and determine their quality.

Packages

We load the standard packages for the MBAD637 course.

library(tidyverse) # used to manipulate data and plot
library(ggfortify) # some extra ggplot functions
library(GGally) # pairs ggplot and other options
library(skimr) # nice summaries
library(broom) # neat model summary
library(gt) # nice displays of printed data
library(patchwork) # arranging graphs
library(car) # useful tools for regression analysis
library(yardstick) # for model performance metrics
library(ggResidpanel) # residual plots
library(mbadtools) # custom packages for this course; install from github

Data

We use the Import Datasets button to import from Table 6.5, being sure to copy the code generated for the import.

library(readxl)
Table_6_5 <- read_excel("~/stfrancis/MBAD637 Business Forecasting and Econometrics/GP Data Sets/Table 6_5.xls", 
    skip = 2)
New names:
View(Table_6_5)

Looking at the View() tab for the file, we see that the data are actually in two halves, side by side. We have to put the right half below the left half. The column names are a bit funky too.

Examine Data

Let’s do some basic examination of the data.

Table_6_5
glimpse(Table_6_5)
Rows: 24
Columns: 7
$ Year...1     <chr> "1960", "1961", "1962", "1963", "1964", "1965", "1966…
$ INFLRATE...2 <dbl> 1.718213, 1.013514, 1.003344, 1.324503, 1.307190, 1.6…
$ UNRATE...3   <dbl> 5.5, 6.7, 5.5, 5.7, 5.2, 4.5, 3.8, 3.8, 3.6, 3.5, 4.9…
$ ...4         <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ Year...5     <chr> "1984", "1985", "1986", "1987", "1988", "1989", "1990…
$ INFLRATE...6 <dbl> 4.317269, 3.561116, 1.858736, 3.649635, 4.137324, 4.8…
$ UNRATE...7   <dbl> 7.5, 7.2, 7.0, 6.2, 5.5, 5.3, 5.6, 6.8, 7.5, 6.9, 6.1…

By looking at the end of the file we see that in the right half there is a row of NAs at the end. Since there are 24 rows in this data frame, there must be 47 actual years of data. So there is some wrangling to do to make a new data frame just as we like it.

Data Wrangling

We will make a new data frame phillips by moving in parts of the data from Table_6_5.

We will make a temporary data frame phillips_1 with the left half of the data and phillips_2 with the right half. Because of the weird column names, we will also fix those as we go. And we will make Year a numeric variable.

phillips_1 = Table_6_5 %>% 
  select(1:3) 
names(phillips_1) = c("Year", "INFLRATE", "UNRATE")
glimpse(phillips_1)
Rows: 24
Columns: 3
$ Year     <chr> "1960", "1961", "1962", "1963", "1964", "1965", "1966", "…
$ INFLRATE <dbl> 1.718213, 1.013514, 1.003344, 1.324503, 1.307190, 1.61290…
$ UNRATE   <dbl> 5.5, 6.7, 5.5, 5.7, 5.2, 4.5, 3.8, 3.8, 3.6, 3.5, 4.9, 5.…
phillips_2 = Table_6_5 %>%
  select(5:7)
names(phillips_2)=c("Year", "INFLRATE", "UNRATE")
glimpse(phillips_2)
Rows: 24
Columns: 3
$ Year     <chr> "1984", "1985", "1986", "1987", "1988", "1989", "1990", "…
$ INFLRATE <dbl> 4.317269, 3.561116, 1.858736, 3.649635, 4.137324, 4.81825…
$ UNRATE   <dbl> 7.5, 7.2, 7.0, 6.2, 5.5, 5.3, 5.6, 6.8, 7.5, 6.9, 6.1, 5.…

This looks good.

Now we make our desired data frame by putting phillips_1 on top of phillips_2, using tidyverse tools. Then we remove any NAs. And we make Year a numeric column.

phillips = bind_rows(phillips_1, phillips_2) %>% 
  na.omit %>% 
  mutate(Year=as.numeric(Year))
glimpse(phillips)
Rows: 47
Columns: 3
$ Year     <dbl> 1960, 1961, 1962, 1963, 1964, 1965, 1966, 1967, 1968, 196…
$ INFLRATE <dbl> 1.718213, 1.013514, 1.003344, 1.324503, 1.307190, 1.61290…
$ UNRATE   <dbl> 5.5, 6.7, 5.5, 5.7, 5.2, 4.5, 3.8, 3.8, 3.6, 3.5, 4.9, 5.…

I think we’ve got it!!

Now the research problem specifies that the models have as target not INFLRATE, but the change in inflation rate from the previous year. Let’s add a column to phillips that calculates the change in the INFLRATE column over the past year. Observe we need to put an NA at the start of the column, because there isn’t anything to take a difference from.

phillips = phillips %>% 
  mutate(INFLCHANGE=c(NA,diff(phillips$INFLRATE)) )
glimpse(phillips)
Rows: 47
Columns: 4
$ Year       <dbl> 1960, 1961, 1962, 1963, 1964, 1965, 1966, 1967, 1968, 1…
$ INFLRATE   <dbl> 1.718213, 1.013514, 1.003344, 1.324503, 1.307190, 1.612…
$ UNRATE     <dbl> 5.5, 6.7, 5.5, 5.7, 5.2, 4.5, 3.8, 3.8, 3.6, 3.5, 4.9, …
$ INFLCHANGE <dbl> NA, -0.70469954, -0.01016903, 0.32115883, -0.01731377, …

Now we have the difference each year from the last. We can check that by trying the first few:

d=c()
for (i in 1:6) d[i] = phillips$INFLRATE[i+1] - phillips$INFLRATE[i]
d
[1] -0.70469954 -0.01016903  0.32115883 -0.01731377  0.30571368  1.24423963

The differences match what are in the INFLCHANGE column.

Data Description

Looking at the data we have

phillips %>% glimpse
Rows: 47
Columns: 4
$ Year       <dbl> 1960, 1961, 1962, 1963, 1964, 1965, 1966, 1967, 1968, 1…
$ INFLRATE   <dbl> 1.718213, 1.013514, 1.003344, 1.324503, 1.307190, 1.612…
$ UNRATE     <dbl> 5.5, 6.7, 5.5, 5.7, 5.2, 4.5, 3.8, 3.8, 3.6, 3.5, 4.9, …
$ INFLCHANGE <dbl> NA, -0.70469954, -0.01016903, 0.32115883, -0.01731377, …
phillips %>% skim
── Data Summary ────────────────────────
                           Values    
Name                       Piped data
Number of rows             47        
Number of columns          4         
_______________________              
Column type frequency:               
  numeric                  4         
________________________             
Group variables            None      

The only NA is the first INFLCHANGE observation, since we have nothing to subtract from it.

We could throw in an estimate for the first entry, like the mean or median of the differences, or we could just leave it and see if it messes us up and fix it then. Hint: in R, it won’t matter for linear models.

Visualizing Data

A pairs plot is a quick way to see relations between the columns.

phillips %>% ggpairs(progress = FALSE)

Is there a relation between INFLCHANGE and UNRATE? It’s kind of there, and downward, as anticipated. The correlation is around -0.54.

Because the research question poses the Linear and Reciprocal, let’s graph the linear model INFLCHANGE~UNRATE and the Reciprocal model INFLCHANGE~I(1/UNRATE). The reciprocal formula has an I() function around it because we want R to interpret the formula identically as it is written. That function stands for Identity.

We will put the plots in a patchwork object which shows them side by side in two columns. The left one is Figure 6.9 in the text.

g_linear = ggplot(phillips) +
  geom_point(aes(UNRATE,INFLCHANGE), na.rm = T)
g_recip = ggplot(phillips) +
  geom_point(aes(I(1/UNRATE),INFLCHANGE), na.rm=T)

# basic patchwork
g_linear + g_recip

Advanced patchwork, and advanced GGally::ggmatrix methods:

list(g_linear, g_recip) %>% 
  wrap_plots(nrow = 1) +
    plot_annotation(title = "Figure 6.9",
                    tag_levels=list(c("Linear","Reciprocal")))


list(g_linear, g_recip) %>% 
  ggmatrix(ncol=2, nrow=1,
           title="Figure 6.9",
           ylab="Inflation Change (%)",
           xAxisLabels = c("Linear", "Reciprocal"),
           showXAxisPlotLabels = TRUE
  )

We can see some slight linearity in each model. The relation is positive for 1/UNRATE, and negative for UNRATE itself.

Modeling

We estimate the Linear and Reciprocal models.

Linear Model

First we estimate the Linear Model.

fit.lin = lm(INFLCHANGE~UNRATE, data=phillips)
fit.lin %>% glance() 
fit.lin %>% tidy(conf.int=T) %>% gt_add_significance()
term estimate std.error statistic p.value conf.low conf.high
(Intercept) 3.7844 0.9029 4.1912 0.0001 1.9647 5.6042
UNRATE −0.6385 0.1493 −4.2756 0.0001 −0.9394 −0.3375

The coefficient of UNRATE in the Linear Model is -0.63, and it is significant at better than the .005 level. The R-squared of the Linear model is only 0.29, however, which leads us to wonder if this regression is useful. However the F-statistic test tells us the regression is meaningful (naturally, since there is only one driver in the regression, and the coefficient estimate is probably not zero).

anova(fit.lin) %>% tidy %>% gt_add_significance()
term df sumsq meansq statistic p.value
UNRATE 1.0000 38.1475 38.1475 18.2805 0.0001
Residuals 44.0000 91.8187 2.0868 NA NA

The anova() table tells us the same thing.

We are obliged to look at the residual distribution to assess any regression. I like using ggResidpanel::resid_panel. Messages are turned off due to the smoother spitting out stuff.

resid_panel(fit.lin, plots=c("resid","qq","ls","hist"), smooth=T)

The QQ plot leads to some questions about whether the residuals are normally distributed. For large quantiles of inflation they clearly are off the dotted line. This is a problem for the regression.

The RF plot shows that the mean of residuals may be a bit below zero, but it is pretty uniform across the fitted values. They are pretty well scattered about zero and look random.

The SL plot shows that the standard deviation is declining rather than being constant, but it isn’t too awful.

In short, the residual analysis is not giving us much more confidence than the low R-squared in the statistics did. The Linear regression is not too likely to be a good model for prediction.

Reciprocal Model

Now we estimate the Reciprocal Model using R.

fit.rec = lm(INFLCHANGE~I(1/UNRATE), data=phillips)
fit.rec %>% glance
fit.rec %>% tidy(conf.int=T) %>% gt_add_significance()
term estimate std.error statistic p.value conf.low conf.high
(Intercept) −3.0684 0.9699 −3.1635 0.0028 −5.0231 −1.1136
I(1/UNRATE) 17.2077 5.2325 3.2886 0.0020 6.6623 27.7530

The coefficient of 1/UNRATE in the Reciprocal Model is 17.2, and it is significant at better than the .002 level.

The R-squared of the Linear model is only 0.20, however, which leads us to wonder if this regression is useful. However the F-statistic test tells us the regression is meaningful (naturally, since there is only one driver in the regression, and the coefficient estimate is probably not zero).

anova(fit.rec) %>% tidy %>% gt_add_significance()
term df sumsq meansq statistic p.value
I(1/UNRATE) 1.0000 25.6426 25.6426 10.8151 0.0020
Residuals 44.0000 104.3237 2.3710 NA NA

The anova() table tells us the same thing.

We are obliged to look at the residual distribution to assess any regression.

resid_panel(fit.rec, plots=c("resid","qq","ls","hist"), smooth=T)

The QQ plot leads to some questions about whether the residuals are normally distributed. For large quantiles they clearly are off the dotted line. This is a problem for the regression.

The RF plot shows that the mean of residuals may be a bit below zero, and is not uniform across the fitted values. They are pretty well scattered about zero,but don’t look random; they are wide in the middle and narrow at the ends.

The LS plot shows that the standard deviation is declining rather than being constant, and is way up for small fitted values.

In short, the residual analysis is giving us even less confidence than the low R-squared in the statistics did. The Reciprocal regression is also even less likely to be a good model for prediction.

Visualizing the models

Here we will graph the Linear and Reciprocal models on top of the data, so we can get a picture of how well they estimate the data itself. Of course the real question is can they be used by the Fed for instance to estimate future inflation change from unemployment now. These models probably would not be good choices.

We’ll grab the code for the side-by-side plots above and add layers for the regression lines with the geom_smooth() function. It won’t work for the reciprocal,so we will just plot the regression line.

gr_linear = ggplot(phillips,aes(UNRATE,INFLCHANGE)) +
  geom_point(na.rm=TRUE) +
  geom_text(x=8, y=5, label="Linear") +
  geom_smooth(method="lm", se=T, formula='y~x', na.rm=T)

gr_recip = ggplot(phillips,aes(I(1/UNRATE),INFLCHANGE)) +
  geom_point(na.rm=TRUE) +
  geom_text(x=0.25, y=5, label="Reciprocal") +
  geom_abline(aes(intercept=coef(fit.rec)[1],
                  slope=coef(fit.rec)[2]), color="red") 

(gr_linear + gr_recip) + 
  plot_annotation(title="Linear and Reciprocal Estimates")

Many of the data points are outside the confidence bands for mean estimates, signifying pretty poor forecasting ability.

Another way to look at the fit is to use yvp plots: we present them side by side with patchwork.

P = list(
  resid_panel(fit.rec, plots=c("yvp"), smooth=T),
  resid_panel(fit.lin, plots=c("yvp"), smooth=T)
        ) 
P %>% wrap_plots(ncol=2) + 
  plot_annotation(subtitle = "Linear and Reciprocal responses")

P %>% ggmatrix(nrow=2, ncol=1,
               xAxisLabels = c("Linear","Reciprocal"))

These both show a lot of noise in the predictions; high accuracy would place the dots close to the blue line.

Conclusion

We looked at a Linear and a Reciprocal model of possible Phillips Curves. Neither was found to be very good for forecasting future inflation rate change for present unemployment.

This is in line with current critiques of the Phillips Curve as a policy tool for the Fed.

References

  1. Gujarati, D.N. and Porter, D.C. (2009) Basic Econometrics. 5th Edition, 2009. New York, McGraw-Hill Irwin. Chapter 6, Example 6.7, page 170. (https://learn.stfrancis.edu/courses/1189436/modules/items/13332634)
  1. Wikipedia (2024) Phillips Curve. (https://en.wikipedia.org/wiki/Phillips_curve)
LS0tDQp0aXRsZTogIkV4YW1wbGUgNl83IFBoaWxsaXBzIEN1cnZlIg0KYXV0aG9yOiAiQnJ1Y2UgSGFydG1hbiINCmRhdGU6ICJGZWJydWFyeSAyMSwgMjAyNCINCm91dHB1dDogICANCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0b2M6IFRSVUUNCiAgICB0b2NfZmxvYXQ6IFRSVUUNCiAgICB0aGVtZTogdW5pdGVkDQphYnN0cmFjdDogfA0KICBXZSBkaXNjdXNzIHNldmVyYWwgZm9ybXMgb2YgdGhlIFBoaWxsaXBzIGN1cnZlIHdoaWNoIHJlbGF0ZXMgaW5mbGF0aW9uIHRvIHVuZW1wbG95bWVudC4gDQotLS0NCg0KIyBJbnRyb2R1Y3Rpb24NClRoaXMgcHJvYmxlbSBpcyBhIHR5cGljYWwgZWNvbm9tZXRyaWMgbW9kZWxpbmcgc2l0dWF0aW9uLiBUaGUgW1BoaWxsaXBzIEN1cnZlXSgjcjIpIHNheXMgdGhhdCBpbmZsYXRpb24gYW5kIHVuZW1wbG95bWVudCBtb3ZlIGluIG9wcG9zaXRlIGRpcmVjdGlvbnMuIEl0IHdhcyB0aGUgYmFzaXMgZm9yIHRoZSBGZWQgZmlnaHRpbmcgdW5lbXBsb3ltZW50IGJ5IGFsbG93aW5nIGEgYml0IG9mIGluZmxhdGlvbi4NCg0KQWN0dWFsbHkgaW4gcmVjZW50IHllYXJzIGVzcGVjaWFsbHkgc2luY2UgMjAwOCB0aGlzIHRoZW9yeSBpcyBzb21ld2hhdA0KZGlzY3JlZGl0ZWQsIHRob3VnaCB0aGUgVHJ1bXAgYWRtaW5pc3RyYXRpb24gc2VlbXMgdG8gYmVsaWV2ZSBpdC4gRmV3DQplY29ub21pc3RzIGJlbGlldmUgdGhlIGxpbmsgaXMgdGhhdCBjbG9zZSBhbnltb3JlLiANCg0KIyBUaGUgUHJvYmxlbQ0KVGhlIFBoaWxsaXBzIGN1cnZlIGFuZCBtb2RpZmllZCBQaGlsbGlwcyBjdXJ2ZSByZWxhdGluZyBpbmZsYXRpb24gYW5kIHVuZW1wbG95bWVudCBhcmUgcHJlc2VudGVkIGluIEV4YW1wbGUgNi42IGluIFt0aGUgYm9va10oI3IxKS4gSSdkIHJlYWQgdGhhdCBmaXJzdC4gIE5vdyB3ZSBjYW4gZXhhbWluZSBFeGFtcGxlIDYuNywgd2hpY2ggcHJlc2VudHMgc29tZSBkYXRhIHRvIHRlc3QgZm9yIHRoZSBQaGlsbGlwcyBjdXJ2ZS4gDQoNCldlIHF1b3RlIGZyb20gdGhlIGJvb2s6DQoNCj5BcyBhbiBpbGx1c3RyYXRpb24gb2YgdGhlIG1vZGlmaWVkIFBoaWxsaXBzIGN1cnZlLCB3ZSBwcmVzZW50IGluIFRhYmxlIDYuNSBkYXRhIG9uIGluZmxhdGlvbg0KYXMgbWVhc3VyZWQgYnkgeWVhci10by15ZWFyIHBlcmNlbnRhZ2UgaW4gdGhlIENvbnN1bWVyIFByaWNlIEluZGV4IChDUEkpIGFuZA0KdGhlIHVuZW1wbG95bWVudCByYXRlIGZvciB0aGUgcGVyaW9kIDE5NjDigJMyMDA2LiBUaGUgdW5lbXBsb3ltZW50IHJhdGUgcmVwcmVzZW50cw0KdGhlIGNpdmlsaWFuIHVuZW1wbG95bWVudCByYXRlLiBGcm9tIHRoZXNlIGRhdGEgd2Ugb2J0YWluZWQgdGhlIGNoYW5nZSBpbiB0aGUgaW5mbGF0aW9uDQpyYXRlICQoXHBpX3Qg4oiSIFxwaV97dOKIkjF9KSQgYW5kIHBsb3R0ZWQgaXQgYWdhaW5zdCB0aGUgY2l2aWxpYW4gdW5lbXBsb3ltZW50IHJhdGU7IHdlIGFyZSB1c2luZyB0aGUgQ1BJDQphcyBhIG1lYXN1cmUgb2YgaW5mbGF0aW9uLiBUaGUgcmVzdWx0aW5nIGdyYXBoIGFwcGVhcnMgaW4gRmlndXJlIDYuOS4NCg0KPkFzIGV4cGVjdGVkLCB0aGUgcmVsYXRpb24gYmV0d2VlbiB0aGUgY2hhbmdlIGluIGluZmxhdGlvbiByYXRlIGFuZCB0aGUgdW5lbXBsb3ltZW50DQpyYXRlIGlzIG5lZ2F0aXZl4oCULS0gYSBsb3cgdW5lbXBsb3ltZW50IHJhdGUgbGVhZHMgdG8gYW4gaW5jcmVhc2UgaW4gdGhlIGluZmxhdGlvbiByYXRlIGFuZA0KdGhlcmVmb3JlIGFuIGFjY2VsZXJhdGlvbiBvZiB0aGUgcHJpY2UgbGV2ZWwsIGhlbmNlIHRoZSBuYW1lIGFjY2VsZXJhdGlvbmlzdCBQaGlsbGlwcyBjdXJ2ZS4NCkxvb2tpbmcgYXQgRmlndXJlIDYuOSwgaXQgaXMgbm90IG9idmlvdXMgd2hldGhlciBhIGxpbmVhciAoc3RyYWlnaHQgbGluZSkgcmVncmVzc2lvbiBtb2RlbA0Kb3IgYSByZWNpcHJvY2FsIG1vZGVsIGZpdHMgdGhlIGRhdGE7IHRoZXJlIG1heSBiZSBhIGN1cnZpbGluZWFyIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZQ0KdHdvIHZhcmlhYmxlcy4gV2UgcHJlc2VudCBiZWxvdyByZWdyZXNzaW9ucyBiYXNlZCBvbiBib3RoIHRoZSBtb2RlbHMuIEhvd2V2ZXIsIGtlZXAgaW4NCm1pbmQgdGhhdCBmb3IgdGhlIHJlY2lwcm9jYWwgbW9kZWwgdGhlIGludGVyY2VwdCB0ZXJtIGlzIGV4cGVjdGVkIHRvIGJlIG5lZ2F0aXZlIGFuZCB0aGUNCnNsb3BlIHBvc2l0aXZlLCBhcyBub3RlZCBpbiBmb290bm90ZSAyMC4NCg0KPkxpbmVhciBtb2RlbDogDQoNCiQkKFxwaV90IOKIkiBccGlfe3TiiJIxfSkgPSAzLjc4NDQg4oiSIDAuNjM4NSBVTl90ICBccXF1YWRccXF1YWQoNi43LjUpJCQNCg0KJCR0ID0gKDQuMTkxMikgKOKIkjQuMjc1NikgXHFxdWFkIFJeMiA9IDAuMjkzNSQkDQoNCj5SZWNpcHJvY2FsIG1vZGVsOg0KDQogICQkKFxwaV90IOKIkiBwaV97dOKIkjF9KSA9IOKIkjMuMDY4NCArIDE3LjIwNzcgKDEvVU5fdCkgIFxxcXVhZFxxcXVhZCg2LjcuNikkJA0KDQogJCR0ID0gKOKIkjMuMTYzNSkgKDMuMjg4NikgXHFxdWFkIFJeMiA9IDAuMTk3MyQkDQoNCj5BbGwgdGhlIGVzdGltYXRlZCBjb2VmZmljaWVudHMgaW4gYm90aCB0aGUgbW9kZWxzIGFyZSBpbmRpdmlkdWFsbHkgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCwgYWxsIHRoZSBwIHZhbHVlcyBiZWluZyBsb3dlciB0aGFuIHRoZSAwLjAwNSBsZXZlbC4NCg0KV2UgYXJlIHN1cHBvc2VkIHRvIHVzZSB0aGUgZGF0YSBpbiBUYWJsZSA2LjUgdG8gY3JlYXRlIHRoZXNlIHJlZ3Jlc3Npb25zIGFuZCBkZXRlcm1pbmUgdGhlaXIgcXVhbGl0eS4NCg0KIyBQYWNrYWdlcw0KV2UgbG9hZCB0aGUgc3RhbmRhcmQgcGFja2FnZXMgZm9yIHRoZSBNQkFENjM3IGNvdXJzZS4NCmBgYHtyfQ0KbGlicmFyeSh0aWR5dmVyc2UpICMgdXNlZCB0byBtYW5pcHVsYXRlIGRhdGEgYW5kIHBsb3QNCmxpYnJhcnkoZ2dmb3J0aWZ5KSAjIHNvbWUgZXh0cmEgZ2dwbG90IGZ1bmN0aW9ucw0KbGlicmFyeShHR2FsbHkpICMgcGFpcnMgZ2dwbG90IGFuZCBvdGhlciBvcHRpb25zDQpsaWJyYXJ5KHNraW1yKSAjIG5pY2Ugc3VtbWFyaWVzDQpsaWJyYXJ5KGJyb29tKSAjIG5lYXQgbW9kZWwgc3VtbWFyeQ0KbGlicmFyeShndCkgIyBuaWNlIGRpc3BsYXlzIG9mIHByaW50ZWQgZGF0YQ0KbGlicmFyeShwYXRjaHdvcmspICMgYXJyYW5naW5nIGdyYXBocw0KbGlicmFyeShjYXIpICMgdXNlZnVsIHRvb2xzIGZvciByZWdyZXNzaW9uIGFuYWx5c2lzDQpsaWJyYXJ5KHlhcmRzdGljaykgIyBmb3IgbW9kZWwgcGVyZm9ybWFuY2UgbWV0cmljcw0KbGlicmFyeShnZ1Jlc2lkcGFuZWwpICMgcmVzaWR1YWwgcGxvdHMNCmxpYnJhcnkobWJhZHRvb2xzKSAjIGN1c3RvbSBwYWNrYWdlcyBmb3IgdGhpcyBjb3Vyc2U7IGluc3RhbGwgZnJvbSBnaXRodWINCmBgYA0KDQojIERhdGENCg0KV2UgdXNlIHRoZSAqSW1wb3J0IERhdGFzZXRzKiBidXR0b24gdG8gaW1wb3J0IGZyb20gVGFibGUgNi41LCBiZWluZyBzdXJlIHRvIGNvcHkgdGhlIGNvZGUgZ2VuZXJhdGVkIGZvciB0aGUgaW1wb3J0Lg0KDQpgYGB7cn0NCmxpYnJhcnkocmVhZHhsKQ0KVGFibGVfNl81IDwtIHJlYWRfZXhjZWwoIn4vc3RmcmFuY2lzL01CQUQ2MzcgQnVzaW5lc3MgRm9yZWNhc3RpbmcgYW5kIEVjb25vbWV0cmljcy9HUCBEYXRhIFNldHMvVGFibGUgNl81LnhscyIsIA0KICAgIHNraXAgPSAyKQ0KVmlldyhUYWJsZV82XzUpDQpgYGANCg0KTG9va2luZyBhdCB0aGUgYFZpZXcoKWAgdGFiIGZvciB0aGUgZmlsZSwgd2Ugc2VlIHRoYXQgdGhlIGRhdGEgYXJlIGFjdHVhbGx5IGluIHR3byBoYWx2ZXMsIHNpZGUgYnkgc2lkZS4gV2UgaGF2ZSB0byBwdXQgdGhlIHJpZ2h0IGhhbGYgYmVsb3cgdGhlIGxlZnQgaGFsZi4gVGhlIGNvbHVtbiBuYW1lcyBhcmUgYSBiaXQgZnVua3kgdG9vLiAgDQoNCiMgRXhhbWluZSBEYXRhDQpMZXQncyBkbyBzb21lIGJhc2ljIGV4YW1pbmF0aW9uIG9mIHRoZSBkYXRhLg0KDQpgYGB7cn0NClRhYmxlXzZfNQ0KZ2xpbXBzZShUYWJsZV82XzUpDQpgYGANCg0KQnkgbG9va2luZyBhdCB0aGUgZW5kIG9mIHRoZSBmaWxlIHdlIHNlZSB0aGF0IGluIHRoZSByaWdodCBoYWxmIHRoZXJlIGlzIGEgcm93IG9mIE5BcyBhdCB0aGUgZW5kLiBTaW5jZSB0aGVyZSBhcmUgMjQgcm93cyBpbiB0aGlzIGRhdGEgZnJhbWUsIHRoZXJlIG11c3QgYmUgNDcgYWN0dWFsIHllYXJzIG9mIGRhdGEuIFNvIHRoZXJlIGlzIHNvbWUgd3JhbmdsaW5nIHRvIGRvIHRvIG1ha2UgYSBuZXcgZGF0YSBmcmFtZSBqdXN0IGFzIHdlIGxpa2UgaXQuIA0KDQojIERhdGEgV3JhbmdsaW5nDQoNCldlIHdpbGwgbWFrZSBhIG5ldyBkYXRhIGZyYW1lIGBwaGlsbGlwc2AgYnkgbW92aW5nIGluIHBhcnRzIG9mIHRoZSBkYXRhIGZyb20gYFRhYmxlXzZfNWAuDQoNCldlIHdpbGwgbWFrZSBhIHRlbXBvcmFyeSBkYXRhIGZyYW1lIGBwaGlsbGlwc18xYCB3aXRoIHRoZSBsZWZ0IGhhbGYgb2YgdGhlIGRhdGEgYW5kIGBwaGlsbGlwc18yYCB3aXRoIHRoZSByaWdodCBoYWxmLiBCZWNhdXNlIG9mIHRoZSB3ZWlyZCBjb2x1bW4gbmFtZXMsIHdlIHdpbGwgYWxzbyBmaXggdGhvc2UgYXMgd2UgZ28uIEFuZCB3ZSB3aWxsIG1ha2UgWWVhciBhIG51bWVyaWMgdmFyaWFibGUuDQoNCmBgYHtyfQ0KcGhpbGxpcHNfMSA9IFRhYmxlXzZfNSAlPiUgDQogIHNlbGVjdCgxOjMpIA0KbmFtZXMocGhpbGxpcHNfMSkgPSBjKCJZZWFyIiwgIklORkxSQVRFIiwgIlVOUkFURSIpDQpnbGltcHNlKHBoaWxsaXBzXzEpDQoNCnBoaWxsaXBzXzIgPSBUYWJsZV82XzUgJT4lDQogIHNlbGVjdCg1OjcpDQpuYW1lcyhwaGlsbGlwc18yKT1jKCJZZWFyIiwgIklORkxSQVRFIiwgIlVOUkFURSIpDQpnbGltcHNlKHBoaWxsaXBzXzIpDQpgYGANCg0KVGhpcyBsb29rcyBnb29kLg0KDQpOb3cgd2UgbWFrZSBvdXIgZGVzaXJlZCBkYXRhIGZyYW1lIGJ5IHB1dHRpbmcgYHBoaWxsaXBzXzFgIG9uIHRvcCBvZiBgcGhpbGxpcHNfMmAsIHVzaW5nIGB0aWR5dmVyc2VgIHRvb2xzLiBUaGVuIHdlIHJlbW92ZSBhbnkgTkFzLiBBbmQgd2UgbWFrZSBZZWFyIGEgbnVtZXJpYyBjb2x1bW4uDQoNCmBgYHtyfQ0KcGhpbGxpcHMgPSBiaW5kX3Jvd3MocGhpbGxpcHNfMSwgcGhpbGxpcHNfMikgJT4lIA0KICBuYS5vbWl0ICU+JSANCiAgbXV0YXRlKFllYXI9YXMubnVtZXJpYyhZZWFyKSkNCmdsaW1wc2UocGhpbGxpcHMpDQpgYGANCg0KSSB0aGluayB3ZSd2ZSBnb3QgaXQhIQ0KDQpOb3cgdGhlIHJlc2VhcmNoIHByb2JsZW0gc3BlY2lmaWVzIHRoYXQgdGhlIG1vZGVscyBoYXZlIGFzIHRhcmdldCBub3QgSU5GTFJBVEUsIGJ1dCB0aGUgY2hhbmdlIGluIGluZmxhdGlvbiByYXRlIGZyb20gdGhlIHByZXZpb3VzIHllYXIuIExldCdzIGFkZCBhIGNvbHVtbiB0byBgcGhpbGxpcHNgIHRoYXQgY2FsY3VsYXRlcyB0aGUgY2hhbmdlIGluIHRoZSBgSU5GTFJBVEVgIGNvbHVtbiBvdmVyIHRoZSBwYXN0IHllYXIuIE9ic2VydmUgd2UgbmVlZCB0byBwdXQgYW4gTkEgYXQgdGhlIHN0YXJ0IG9mIHRoZSBjb2x1bW4sIGJlY2F1c2UgdGhlcmUgaXNuJ3QgYW55dGhpbmcgdG8gdGFrZSBhIGRpZmZlcmVuY2UgZnJvbS4NCg0KYGBge3J9DQpwaGlsbGlwcyA9IHBoaWxsaXBzICU+JSANCiAgbXV0YXRlKElORkxDSEFOR0U9YyhOQSxkaWZmKHBoaWxsaXBzJElORkxSQVRFKSkgKQ0KZ2xpbXBzZShwaGlsbGlwcykNCmBgYA0KDQpOb3cgd2UgaGF2ZSB0aGUgZGlmZmVyZW5jZSBlYWNoIHllYXIgZnJvbSB0aGUgbGFzdC4gV2UgY2FuIGNoZWNrIHRoYXQgYnkgdHJ5aW5nIHRoZSBmaXJzdCBmZXc6DQpgYGB7cn0NCmQ9YygpDQpmb3IgKGkgaW4gMTo2KSBkW2ldID0gcGhpbGxpcHMkSU5GTFJBVEVbaSsxXSAtIHBoaWxsaXBzJElORkxSQVRFW2ldDQpkDQpgYGANClRoZSBkaWZmZXJlbmNlcyBtYXRjaCB3aGF0IGFyZSBpbiB0aGUgSU5GTENIQU5HRSBjb2x1bW4uDQoNCiMgRGF0YSBEZXNjcmlwdGlvbg0KDQpMb29raW5nIGF0IHRoZSBkYXRhIHdlIGhhdmUNCg0KYGBge3J9DQpwaGlsbGlwcyAlPiUgZ2xpbXBzZQ0KcGhpbGxpcHMgJT4lIHNraW0NCmBgYA0KDQpUaGUgb25seSBOQSBpcyB0aGUgZmlyc3QgSU5GTENIQU5HRSBvYnNlcnZhdGlvbiwgc2luY2Ugd2UgaGF2ZSBub3RoaW5nIHRvIHN1YnRyYWN0IGZyb20gaXQuIA0KDQpXZSBjb3VsZCB0aHJvdyBpbiBhbiBlc3RpbWF0ZSBmb3IgdGhlIGZpcnN0IGVudHJ5LCBsaWtlIHRoZSBtZWFuIG9yIG1lZGlhbiBvZiB0aGUgZGlmZmVyZW5jZXMsIG9yIHdlIGNvdWxkIGp1c3QgbGVhdmUgaXQgYW5kIHNlZSBpZiBpdCBtZXNzZXMgdXMgdXAgYW5kIGZpeCBpdCB0aGVuLiBIaW50OiBpbiBSLCBpdCB3b24ndCBtYXR0ZXIgZm9yIGxpbmVhciBtb2RlbHMuDQoNCiMgVmlzdWFsaXppbmcgRGF0YQ0KDQpBIHBhaXJzIHBsb3QgaXMgYSBxdWljayB3YXkgdG8gc2VlIHJlbGF0aW9ucyBiZXR3ZWVuIHRoZSBjb2x1bW5zLg0KDQpgYGB7cn0NCnBoaWxsaXBzICU+JSBnZ3BhaXJzKHByb2dyZXNzID0gRkFMU0UpDQpgYGANCg0KSXMgdGhlcmUgYSByZWxhdGlvbiBiZXR3ZWVuIGBJTkZMQ0hBTkdFYCBhbmQgYFVOUkFURWA/IEl0J3Mga2luZCBvZiB0aGVyZSwgYW5kIGRvd253YXJkLCBhcyBhbnRpY2lwYXRlZC4gVGhlIGNvcnJlbGF0aW9uIGlzIGFyb3VuZCAtMC41NC4NCg0KQmVjYXVzZSB0aGUgcmVzZWFyY2ggcXVlc3Rpb24gcG9zZXMgdGhlIExpbmVhciBhbmQgUmVjaXByb2NhbCwgbGV0J3MgZ3JhcGggdGhlIGxpbmVhciBtb2RlbCBgSU5GTENIQU5HRX5VTlJBVEVgIGFuZCB0aGUgUmVjaXByb2NhbCBtb2RlbCBgSU5GTENIQU5HRX5JKDEvVU5SQVRFKWAuIFRoZSByZWNpcHJvY2FsIGZvcm11bGEgaGFzIGFuIGBJKClgIGZ1bmN0aW9uIGFyb3VuZCBpdCBiZWNhdXNlIHdlIHdhbnQgUiB0byBpbnRlcnByZXQgdGhlIGZvcm11bGEgaWRlbnRpY2FsbHkgYXMgaXQgaXMgd3JpdHRlbi4gVGhhdCBmdW5jdGlvbiBzdGFuZHMgZm9yIElkZW50aXR5Lg0KDQpXZSB3aWxsIHB1dCB0aGUgcGxvdHMgaW4gYSBgcGF0Y2h3b3JrYCBvYmplY3Qgd2hpY2ggc2hvd3MgdGhlbSBzaWRlIGJ5IHNpZGUgaW4gdHdvIGNvbHVtbnMuIFRoZSBsZWZ0IG9uZSBpcyBGaWd1cmUgNi45IGluIHRoZSB0ZXh0Lg0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFfQ0KZ19saW5lYXIgPSBnZ3Bsb3QocGhpbGxpcHMpICsNCiAgZ2VvbV9wb2ludChhZXMoVU5SQVRFLElORkxDSEFOR0UpLCBuYS5ybSA9IFQpDQpnX3JlY2lwID0gZ2dwbG90KHBoaWxsaXBzKSArDQogIGdlb21fcG9pbnQoYWVzKEkoMS9VTlJBVEUpLElORkxDSEFOR0UpLCBuYS5ybT1UKQ0KDQojIGJhc2ljIHBhdGNod29yaw0KZ19saW5lYXIgKyBnX3JlY2lwDQpgYGANCg0KQWR2YW5jZWQgYHBhdGNod29ya2AsIGFuZCBhZHZhbmNlZCBgR0dhbGx5OjpnZ21hdHJpeGAgbWV0aG9kczoNCmBgYHtyfQ0KbGlzdChnX2xpbmVhciwgZ19yZWNpcCkgJT4lIA0KICB3cmFwX3Bsb3RzKG5yb3cgPSAxKSArDQogICAgcGxvdF9hbm5vdGF0aW9uKHRpdGxlID0gIkZpZ3VyZSA2LjkiLA0KICAgICAgICAgICAgICAgICAgICB0YWdfbGV2ZWxzPWxpc3QoYygiTGluZWFyIiwiUmVjaXByb2NhbCIpKSkNCg0KbGlzdChnX2xpbmVhciwgZ19yZWNpcCkgJT4lIA0KICBnZ21hdHJpeChuY29sPTIsIG5yb3c9MSwNCiAgICAgICAgICAgdGl0bGU9IkZpZ3VyZSA2LjkiLA0KICAgICAgICAgICB5bGFiPSJJbmZsYXRpb24gQ2hhbmdlICglKSIsDQogICAgICAgICAgIHhBeGlzTGFiZWxzID0gYygiTGluZWFyIiwgIlJlY2lwcm9jYWwiKSwNCiAgICAgICAgICAgc2hvd1hBeGlzUGxvdExhYmVscyA9IFRSVUUNCiAgKQ0KYGBgDQpXZSBjYW4gc2VlIHNvbWUgc2xpZ2h0IGxpbmVhcml0eSBpbiBlYWNoIG1vZGVsLiBUaGUgcmVsYXRpb24gaXMgcG9zaXRpdmUgZm9yIDEvVU5SQVRFLCBhbmQgbmVnYXRpdmUgZm9yIFVOUkFURSBpdHNlbGYuDQoNCiMgTW9kZWxpbmcNCldlIGVzdGltYXRlIHRoZSBMaW5lYXIgYW5kIFJlY2lwcm9jYWwgbW9kZWxzLg0KDQojIyBMaW5lYXIgTW9kZWwNCg0KRmlyc3Qgd2UgZXN0aW1hdGUgdGhlIExpbmVhciBNb2RlbC4NCg0KYGBge3J9DQpmaXQubGluID0gbG0oSU5GTENIQU5HRX5VTlJBVEUsIGRhdGE9cGhpbGxpcHMpDQpmaXQubGluICU+JSBnbGFuY2UoKSANCmZpdC5saW4gJT4lIHRpZHkoY29uZi5pbnQ9VCkgJT4lIGd0X2FkZF9zaWduaWZpY2FuY2UoKQ0KYGBgDQoNClRoZSBjb2VmZmljaWVudCBvZiBgVU5SQVRFYCBpbiB0aGUgTGluZWFyIE1vZGVsIGlzIC0wLjYzLCBhbmQgaXQgaXMgc2lnbmlmaWNhbnQgYXQgYmV0dGVyIHRoYW4gdGhlIC4wMDUgbGV2ZWwuIFRoZSBSLXNxdWFyZWQgb2YgdGhlIExpbmVhciBtb2RlbCBpcyBvbmx5IDAuMjksIGhvd2V2ZXIsIHdoaWNoIGxlYWRzIHVzIHRvIHdvbmRlciBpZiB0aGlzIHJlZ3Jlc3Npb24gaXMgdXNlZnVsLiBIb3dldmVyIHRoZSBGLXN0YXRpc3RpYyB0ZXN0IHRlbGxzIHVzIHRoZSByZWdyZXNzaW9uIGlzIG1lYW5pbmdmdWwgKG5hdHVyYWxseSwgc2luY2UgdGhlcmUgaXMgb25seSBvbmUgZHJpdmVyIGluIHRoZSByZWdyZXNzaW9uLCBhbmQgdGhlIGNvZWZmaWNpZW50IGVzdGltYXRlIGlzIHByb2JhYmx5IG5vdCB6ZXJvKS4NCg0KYGBge3J9DQphbm92YShmaXQubGluKSAlPiUgdGlkeSAlPiUgZ3RfYWRkX3NpZ25pZmljYW5jZSgpDQpgYGANClRoZSBgYW5vdmEoKWAgdGFibGUgdGVsbHMgdXMgdGhlIHNhbWUgdGhpbmcuDQoNCldlIGFyZSBvYmxpZ2VkIHRvIGxvb2sgYXQgdGhlIHJlc2lkdWFsIGRpc3RyaWJ1dGlvbiB0byBhc3Nlc3MgYW55IHJlZ3Jlc3Npb24uIEkgbGlrZSB1c2luZyBgZ2dSZXNpZHBhbmVsOjpyZXNpZF9wYW5lbGAuIE1lc3NhZ2VzIGFyZSB0dXJuZWQgb2ZmIGR1ZSB0byB0aGUgc21vb3RoZXIgc3BpdHRpbmcgb3V0IHN0dWZmLg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFfQ0KcmVzaWRfcGFuZWwoZml0LmxpbiwgcGxvdHM9YygicmVzaWQiLCJxcSIsImxzIiwiaGlzdCIpLCBzbW9vdGg9VCkNCmBgYA0KDQpUaGUgUVEgcGxvdCBsZWFkcyB0byBzb21lIHF1ZXN0aW9ucyBhYm91dCB3aGV0aGVyIHRoZSByZXNpZHVhbHMgYXJlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLiBGb3IgbGFyZ2UgcXVhbnRpbGVzIG9mIGluZmxhdGlvbiB0aGV5IGNsZWFybHkgYXJlIG9mZiB0aGUgZG90dGVkIGxpbmUuICBUaGlzIGlzIGEgcHJvYmxlbSBmb3IgdGhlIHJlZ3Jlc3Npb24uDQoNClRoZSBSRiBwbG90IHNob3dzIHRoYXQgdGhlIG1lYW4gb2YgcmVzaWR1YWxzIG1heSBiZSBhIGJpdCBiZWxvdyB6ZXJvLCBidXQgaXQgaXMgcHJldHR5IHVuaWZvcm0gYWNyb3NzIHRoZSBmaXR0ZWQgdmFsdWVzLiBUaGV5IGFyZSBwcmV0dHkgd2VsbCBzY2F0dGVyZWQgYWJvdXQgemVybyBhbmQgbG9vayByYW5kb20uICANCg0KVGhlIFNMIHBsb3Qgc2hvd3MgdGhhdCB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uIGlzIGRlY2xpbmluZyByYXRoZXIgdGhhbiBiZWluZyBjb25zdGFudCwgYnV0IGl0IGlzbid0IHRvbyBhd2Z1bC4NCg0KSW4gc2hvcnQsIHRoZSByZXNpZHVhbCBhbmFseXNpcyBpcyBub3QgZ2l2aW5nIHVzIG11Y2ggbW9yZSBjb25maWRlbmNlIHRoYW4gdGhlIGxvdyBSLXNxdWFyZWQgaW4gdGhlIHN0YXRpc3RpY3MgZGlkLiBUaGUgTGluZWFyIHJlZ3Jlc3Npb24gaXMgbm90IHRvbyBsaWtlbHkgdG8gYmUgYSBnb29kIG1vZGVsIGZvciBwcmVkaWN0aW9uLg0KDQojIyBSZWNpcHJvY2FsIE1vZGVsDQoNCk5vdyB3ZSBlc3RpbWF0ZSB0aGUgUmVjaXByb2NhbCBNb2RlbCB1c2luZyBSLg0KDQpgYGB7cn0NCmZpdC5yZWMgPSBsbShJTkZMQ0hBTkdFfkkoMS9VTlJBVEUpLCBkYXRhPXBoaWxsaXBzKQ0KZml0LnJlYyAlPiUgZ2xhbmNlDQpmaXQucmVjICU+JSB0aWR5KGNvbmYuaW50PVQpICU+JSBndF9hZGRfc2lnbmlmaWNhbmNlKCkNCmBgYA0KDQpUaGUgY29lZmZpY2llbnQgb2YgYDEvVU5SQVRFYCBpbiB0aGUgUmVjaXByb2NhbCBNb2RlbCBpcyAxNy4yLCBhbmQgaXQgaXMgc2lnbmlmaWNhbnQgYXQgYmV0dGVyIHRoYW4gdGhlIC4wMDIgbGV2ZWwuIA0KDQpUaGUgUi1zcXVhcmVkIG9mIHRoZSBMaW5lYXIgbW9kZWwgaXMgb25seSAwLjIwLCBob3dldmVyLCB3aGljaCBsZWFkcyB1cyB0byB3b25kZXIgaWYgdGhpcyByZWdyZXNzaW9uIGlzIHVzZWZ1bC4gSG93ZXZlciB0aGUgRi1zdGF0aXN0aWMgdGVzdCB0ZWxscyB1cyB0aGUgcmVncmVzc2lvbiBpcyBtZWFuaW5nZnVsIChuYXR1cmFsbHksIHNpbmNlIHRoZXJlIGlzIG9ubHkgb25lIGRyaXZlciBpbiB0aGUgcmVncmVzc2lvbiwgYW5kIHRoZSBjb2VmZmljaWVudCBlc3RpbWF0ZSBpcyBwcm9iYWJseSBub3QgemVybykuDQoNCmBgYHtyfQ0KYW5vdmEoZml0LnJlYykgJT4lIHRpZHkgJT4lIGd0X2FkZF9zaWduaWZpY2FuY2UoKQ0KYGBgDQpUaGUgYGFub3ZhKClgIHRhYmxlIHRlbGxzIHVzIHRoZSBzYW1lIHRoaW5nLg0KDQpXZSBhcmUgb2JsaWdlZCB0byBsb29rIGF0IHRoZSByZXNpZHVhbCBkaXN0cmlidXRpb24gdG8gYXNzZXNzIGFueSByZWdyZXNzaW9uLg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFfQ0KcmVzaWRfcGFuZWwoZml0LnJlYywgcGxvdHM9YygicmVzaWQiLCJxcSIsImxzIiwiaGlzdCIpLCBzbW9vdGg9VCkNCmBgYA0KDQpUaGUgUVEgcGxvdCBsZWFkcyB0byBzb21lIHF1ZXN0aW9ucyBhYm91dCB3aGV0aGVyIHRoZSByZXNpZHVhbHMgYXJlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLiBGb3IgbGFyZ2UgcXVhbnRpbGVzIHRoZXkgY2xlYXJseSBhcmUgb2ZmIHRoZSBkb3R0ZWQgbGluZS4gIFRoaXMgaXMgYSBwcm9ibGVtIGZvciB0aGUgcmVncmVzc2lvbi4gIA0KDQpUaGUgUkYgcGxvdCBzaG93cyB0aGF0IHRoZSBtZWFuIG9mIHJlc2lkdWFscyBtYXkgYmUgYSBiaXQgYmVsb3cgemVybywgYW5kIGlzIG5vdCB1bmlmb3JtIGFjcm9zcyB0aGUgZml0dGVkIHZhbHVlcy4gVGhleSBhcmUgcHJldHR5IHdlbGwgc2NhdHRlcmVkIGFib3V0IHplcm8sYnV0IGRvbid0IGxvb2sgcmFuZG9tOyB0aGV5IGFyZSB3aWRlIGluIHRoZSBtaWRkbGUgYW5kIG5hcnJvdyBhdCB0aGUgZW5kcy4gIA0KDQpUaGUgTFMgcGxvdCBzaG93cyB0aGF0IHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gaXMgZGVjbGluaW5nIHJhdGhlciB0aGFuIGJlaW5nIGNvbnN0YW50LCBhbmQgaXMgd2F5IHVwIGZvciBzbWFsbCBmaXR0ZWQgdmFsdWVzLg0KDQpJbiBzaG9ydCwgdGhlIHJlc2lkdWFsIGFuYWx5c2lzIGlzIGdpdmluZyB1cyBldmVuIGxlc3MgY29uZmlkZW5jZSB0aGFuIHRoZSBsb3cgUi1zcXVhcmVkIGluIHRoZSBzdGF0aXN0aWNzIGRpZC4gVGhlIFJlY2lwcm9jYWwgcmVncmVzc2lvbiBpcyBhbHNvIGV2ZW4gbGVzcyBsaWtlbHkgdG8gYmUgYSBnb29kIG1vZGVsIGZvciBwcmVkaWN0aW9uLg0KDQojIFZpc3VhbGl6aW5nIHRoZSBtb2RlbHMNCg0KSGVyZSB3ZSB3aWxsIGdyYXBoIHRoZSBMaW5lYXIgYW5kIFJlY2lwcm9jYWwgbW9kZWxzIG9uIHRvcCBvZiB0aGUgZGF0YSwgc28gd2UgY2FuIGdldCBhIHBpY3R1cmUgb2YgaG93IHdlbGwgdGhleSBlc3RpbWF0ZSB0aGUgZGF0YSBpdHNlbGYuIE9mIGNvdXJzZSB0aGUgcmVhbCBxdWVzdGlvbiBpcyBjYW4gdGhleSBiZSB1c2VkIGJ5IHRoZSBGZWQgZm9yIGluc3RhbmNlIHRvIGVzdGltYXRlIGZ1dHVyZSBpbmZsYXRpb24gY2hhbmdlIGZyb20gdW5lbXBsb3ltZW50IG5vdy4gVGhlc2UgbW9kZWxzIHByb2JhYmx5IHdvdWxkIG5vdCBiZSBnb29kIGNob2ljZXMuDQoNCldlJ2xsIGdyYWIgdGhlIGNvZGUgZm9yIHRoZSBzaWRlLWJ5LXNpZGUgcGxvdHMgYWJvdmUgYW5kIGFkZCBsYXllcnMgZm9yIHRoZSByZWdyZXNzaW9uIGxpbmVzIHdpdGggdGhlIGBnZW9tX3Ntb290aCgpYCBmdW5jdGlvbi4gSXQgd29uJ3Qgd29yayBmb3IgdGhlIHJlY2lwcm9jYWwsc28gd2Ugd2lsbCBqdXN0IHBsb3QgdGhlIHJlZ3Jlc3Npb24gbGluZS4NCg0KYGBge3Igd2FybmluZz1GQUxTRX0NCmdyX2xpbmVhciA9IGdncGxvdChwaGlsbGlwcyxhZXMoVU5SQVRFLElORkxDSEFOR0UpKSArDQogIGdlb21fcG9pbnQobmEucm09VFJVRSkgKw0KICBnZW9tX3RleHQoeD04LCB5PTUsIGxhYmVsPSJMaW5lYXIiKSArDQogIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iLCBzZT1ULCBmb3JtdWxhPSd5fngnLCBuYS5ybT1UKQ0KDQpncl9yZWNpcCA9IGdncGxvdChwaGlsbGlwcyxhZXMoSSgxL1VOUkFURSksSU5GTENIQU5HRSkpICsNCiAgZ2VvbV9wb2ludChuYS5ybT1UUlVFKSArDQogIGdlb21fdGV4dCh4PTAuMjUsIHk9NSwgbGFiZWw9IlJlY2lwcm9jYWwiKSArDQogIGdlb21fYWJsaW5lKGFlcyhpbnRlcmNlcHQ9Y29lZihmaXQucmVjKVsxXSwNCiAgICAgICAgICAgICAgICAgIHNsb3BlPWNvZWYoZml0LnJlYylbMl0pLCBjb2xvcj0icmVkIikgDQoNCihncl9saW5lYXIgKyBncl9yZWNpcCkgKyANCiAgcGxvdF9hbm5vdGF0aW9uKHRpdGxlPSJMaW5lYXIgYW5kIFJlY2lwcm9jYWwgRXN0aW1hdGVzIikNCmBgYA0KDQpNYW55IG9mIHRoZSBkYXRhIHBvaW50cyBhcmUgb3V0c2lkZSB0aGUgY29uZmlkZW5jZSBiYW5kcyBmb3IgbWVhbiBlc3RpbWF0ZXMsIHNpZ25pZnlpbmcgcHJldHR5IHBvb3IgZm9yZWNhc3RpbmcgYWJpbGl0eS4NCg0KQW5vdGhlciB3YXkgdG8gbG9vayBhdCB0aGUgZml0IGlzIHRvIHVzZSB5dnAgcGxvdHM6IHdlIHByZXNlbnQgdGhlbSBzaWRlIGJ5IHNpZGUgd2l0aCBgcGF0Y2h3b3JrYC4NCmBgYHtyIG1lc3NhZ2U9RkFMU0V9DQpQID0gbGlzdCgNCiAgcmVzaWRfcGFuZWwoZml0LnJlYywgcGxvdHM9YygieXZwIiksIHNtb290aD1UKSwNCiAgcmVzaWRfcGFuZWwoZml0LmxpbiwgcGxvdHM9YygieXZwIiksIHNtb290aD1UKQ0KICAgICAgICApIA0KUCAlPiUgd3JhcF9wbG90cyhuY29sPTIpICsgDQogIHBsb3RfYW5ub3RhdGlvbihzdWJ0aXRsZSA9ICJMaW5lYXIgYW5kIFJlY2lwcm9jYWwgcmVzcG9uc2VzIikNClAgJT4lIGdnbWF0cml4KG5yb3c9MiwgbmNvbD0xLA0KICAgICAgICAgICAgICAgeEF4aXNMYWJlbHMgPSBjKCJMaW5lYXIiLCJSZWNpcHJvY2FsIikpDQpgYGANCg0KVGhlc2UgYm90aCBzaG93IGEgbG90IG9mIG5vaXNlIGluIHRoZSBwcmVkaWN0aW9uczsgaGlnaCBhY2N1cmFjeSB3b3VsZCBwbGFjZSB0aGUgZG90cyBjbG9zZSB0byB0aGUgYmx1ZSBsaW5lLg0KDQojIENvbmNsdXNpb24NCg0KV2UgbG9va2VkIGF0IGEgTGluZWFyIGFuZCBhIFJlY2lwcm9jYWwgbW9kZWwgb2YgcG9zc2libGUgUGhpbGxpcHMgQ3VydmVzLiAgTmVpdGhlciB3YXMgZm91bmQgdG8gYmUgdmVyeSBnb29kIGZvciBmb3JlY2FzdGluZyBmdXR1cmUgaW5mbGF0aW9uIHJhdGUgY2hhbmdlIGZvciBwcmVzZW50IHVuZW1wbG95bWVudC4NCg0KVGhpcyBpcyBpbiBsaW5lIHdpdGggY3VycmVudCBjcml0aXF1ZXMgb2YgdGhlIFBoaWxsaXBzIEN1cnZlIGFzIGEgcG9saWN5IHRvb2wgZm9yIHRoZSBGZWQuDQoNCiMgUmVmZXJlbmNlcw0KOjo6eyNyMX0NCjEuIEd1amFyYXRpLCBELk4uIGFuZCBQb3J0ZXIsIEQuQy4gKDIwMDkpIEJhc2ljIEVjb25vbWV0cmljcy4gNXRoIEVkaXRpb24sIDIwMDkuIE5ldyBZb3JrLCBNY0dyYXctSGlsbCBJcndpbi4gQ2hhcHRlciA2LCBFeGFtcGxlIDYuNywgcGFnZSAxNzAuIChodHRwczovL2xlYXJuLnN0ZnJhbmNpcy5lZHUvY291cnNlcy8xMTg5NDM2L21vZHVsZXMvaXRlbXMvMTMzMzI2MzQpDQo6OjoNCg0KOjo6eyNyMn0NCjIuIFdpa2lwZWRpYSAoMjAyNCkgUGhpbGxpcHMgQ3VydmUuIChodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9QaGlsbGlwc19jdXJ2ZSkNCjo6Og0KDQo=