1 Data Exploration & Cleaning

The data contains historical sales data for 45 stores located in different regions. Each store contains a number of departments, and you are tasked with predicting the department-wide sales for each store. The data is stored in 3 different csv files.

stores.csv This file contains anonymized information about the 45 stores, indicating the type and size of store.

sales.csv This is the historical sales data, which covers to 2010-02-05 to 2013-07-26. Within this file you will find the following fields:

  • Store - the store number

  • Dept - the department number

  • Date - the week

  • Weekly_Sales - sales for the given department in the given store

  • IsHoliday - whether the week is a special holiday week

Features.csv This file contains additional data related to the store, department, and regional activity for the given dates. It contains the following fields:

  • Store - the store number

  • Date - the week

  • Temperature - average temperature in the region

  • Fuel_Price - cost of fuel in the region

  • MarkDown1-5 - anonymized data related to promotional markdowns that Walmart is running. MarkDown data is only available after Nov 2011, and is not available for all stores all the time. Any missing value is marked with an NA.

  • CPI - the consumer price index

  • Unemployment - the unemployment rate

  • IsHoliday - whether the week is a special holiday week

1.1 Read the Data Sets

Store Date Temperature Fuel_Price MarkDown1 MarkDown2 MarkDown3 MarkDown4 MarkDown5 CPI Unemployment IsHoliday
1 05/02/2010 42.31 2.572 NA NA NA NA NA 211.0964 8.106 FALSE
1 12/02/2010 38.51 2.548 NA NA NA NA NA 211.2422 8.106 TRUE
1 19/02/2010 39.93 2.514 NA NA NA NA NA 211.2891 8.106 FALSE
1 26/02/2010 46.63 2.561 NA NA NA NA NA 211.3196 8.106 FALSE
1 05/03/2010 46.50 2.625 NA NA NA NA NA 211.3501 8.106 FALSE
1 12/03/2010 57.79 2.667 NA NA NA NA NA 211.3806 8.106 FALSE
Store Dept Date Weekly_Sales IsHoliday
1 1 05/02/2010 24924.50 FALSE
1 1 12/02/2010 46039.49 TRUE
1 1 19/02/2010 41595.55 FALSE
1 1 26/02/2010 19403.54 FALSE
1 1 05/03/2010 21827.90 FALSE
1 1 12/03/2010 21043.39 FALSE
Store Type Size
1 A 151315
2 A 202307
3 B 37392
4 A 205863
5 B 34875
6 A 202505

1.2 Data Exploration & Manipulation

In this section, We are going to do some Data Exploration. First of all, We are going to split the data into Year, Month and Day.

Now, We created a feature Weekly sales from sales data set.

Now, We must merge the two data sets features and sales.

There is the information about Store Size from Stores data set. So, We are now, merge the SalesM with Storesdata sets also. Merging all the data sets into one sales data set which will be split into sales and testing data sets for data modeling.

2 Data Analysis & Visualization

2.1 Data Distribution

Let´s, first of all, look at the Variables distribution.

Temperature and Unemployment are fairly normally distributed. Store Sizes have brackets on both ends indicating large number of large and small stores. The medium sized stores are very few in comparison in this data set. We might need to do some transformation of this data.

2.2 Sales Distribution and Analysis

Weekly Sales is positively skewed indicating few large values. This could be caused by the festive Weeks which are few but Sales value for these weeks would be very high in comparison to other weeks. We can transform it using a log transformation as can be seem from the second plot. This might be required when we build the model too.

Sales Data is missing for January in 2010, November and December in 2012.There are weeks when Sales peaks in the festive months of November and December.Also seems like there is a dip in September - October leading towards the holiday weeks.

Let´s now grouping the Weeks based on Sales. We are going to use from 2011, because the data is available for full year. And let´s summarize the Weekly Sales.

Now, calculating the upper and lower threshold based on 5% bounds.

We have around 52 weeks in the data set which can be used as a Categorical Variable as we can see trends in Sales across weeks. But doing this would complicate the model with too many variables.

Instead, we can try to cluster the weeks based on Sales. There are weeks with lows and peaks in Sales and then there are majority of the weeks with Sales around the median value

We split the data year wise and Type wise to calculate an Upper (5% higher than Mean) and Lower (5% lower than Mean) Threshold Sales Value. We cluster weeks with Sales higher than Upper threshold as High weeks, lower than Lower threshold as Low weeks and everything else as Medium weeks. These Clusters are shown in below plot.

Plotting Store Size against Sales, we can observe Linear relation. We could observer possibility of confounding here as we can see chunks for different Sizes.

## $title
## [1] "Store Size vs Sales"
## 
## attr(,"class")
## [1] "labels"

Based on this, we will try to group the Store Sizes but we already have a Type variable in the data set. Below We see how is the sales level behavior in 2011.

## <ggproto object: Class FacetWrap, Facet, gg>
##     compute_layout: function
##     draw_back: function
##     draw_front: function
##     draw_labels: function
##     draw_panels: function
##     finish_data: function
##     init_scales: function
##     map_data: function
##     params: list
##     setup_data: function
##     setup_params: function
##     shrink: TRUE
##     train_scales: function
##     vars: function
##     super:  <ggproto object: Class FacetWrap, Facet, gg>

Here, We have the Week Type per Year and Week.

## <ggproto object: Class FacetWrap, Facet, gg>
##     compute_layout: function
##     draw_back: function
##     draw_front: function
##     draw_labels: function
##     draw_panels: function
##     finish_data: function
##     init_scales: function
##     map_data: function
##     params: list
##     setup_data: function
##     setup_params: function
##     shrink: TRUE
##     train_scales: function
##     vars: function
##     super:  <ggproto object: Class FacetWrap, Facet, gg>

Handling with Store Size Confounding.

Let´s see the distribution of the Weekly Sales by level of the Stores. We created a Upper and Lower threshold.

Below, We have the distribution of the Store by Size Store and grouping by Type.

## <ggproto object: Class FacetWrap, Facet, gg>
##     compute_layout: function
##     draw_back: function
##     draw_front: function
##     draw_labels: function
##     draw_panels: function
##     finish_data: function
##     init_scales: function
##     map_data: function
##     params: list
##     setup_data: function
##     setup_params: function
##     shrink: TRUE
##     train_scales: function
##     vars: function
##     super:  <ggproto object: Class FacetWrap, Facet, gg>

We see in the graphic below, the distribution of Weekly Sales by Store, Level of the Store by Year.

## <ggproto object: Class FacetWrap, Facet, gg>
##     compute_layout: function
##     draw_back: function
##     draw_front: function
##     draw_labels: function
##     draw_panels: function
##     finish_data: function
##     init_scales: function
##     map_data: function
##     params: list
##     setup_data: function
##     setup_params: function
##     shrink: TRUE
##     train_scales: function
##     vars: function
##     super:  <ggproto object: Class FacetWrap, Facet, gg>

When we plot Sales against Store with Type as color dimension, we can observe clear groups in the stores but this is not exactly captured by the Type field. There are some Stores with really high Sales compared to rest. These Stores are a subset of Type A. Then there are bunch of stores with small sales and is a mixture of Type B and Type C. Rest of the stores makes average sales in a year and falls in a different group. These stores are mix of Type A and Type B

We have grouped the stores into 3 clusters like Week Groups without changing the original Type variable. This avoids using the Store variable as a categorical variable

Unemployment, CPI and Fuel Price does influence Weekly Sales but we cannot observe any major patterns here.

Since we don’t have much information on the Markdowns and major part of them are N/A, we are not imputing missing values with a mean / median. Instead, we are replacing N/As with 0 so that it can be used for Model building and other computations.

Let´s see the behavior of Weekly Sales by Holiday features analysis distribution.

Holiday x Week

## <ggproto object: Class FacetWrap, Facet, gg>
##     compute_layout: function
##     draw_back: function
##     draw_front: function
##     draw_labels: function
##     draw_panels: function
##     finish_data: function
##     init_scales: function
##     map_data: function
##     params: list
##     setup_data: function
##     setup_params: function
##     shrink: TRUE
##     train_scales: function
##     vars: function
##     super:  <ggproto object: Class FacetWrap, Facet, gg>

Holiday x Weekly_Sales

Obviously, from the different variable perspective, weekly sales is higher during holidays.

Now, it’s time to see the Markdown features.

Markdown x month x Holiday

Markdown 1 and Markdown 4 are mainly offered on February, March and August and most of them offered during non-holiday. This discount is possibly related to Super bowl season, Mother’s day and back-to-school season.

Markdown 2 is offered mainly during Dec holiday and Jan, but also has its peaks during November. This discount is possibly related to Christmas and New year.

Markdown 3 is offered only during Nov holiday and Dec. This discount is possibly related to Thanksgiving.

Markdown 5 is mainly offered during non-holiday season.

Let´s Categorized the Weeklysalesand see what We figure it out.

3 Machine Learning

Let´s now start the Machine Learning development.

Original Training data set is split into two random training and testing data sets.

3.1 Models Development

## 
## Call:
## lm(formula = Weekly_Sales ~ Size + StoreGroup + IsHoliday, data = trainM)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -676576 -131333  -12932  105772 2173374 
## 
## Coefficients:
##                    Estimate Std. Error t value Pr(>|t|)    
## (Intercept)       9.728e+05  1.649e+04   58.98  < 2e-16 ***
## Size              4.766e+00  7.632e-02   62.44  < 2e-16 ***
## StoreGroupLow    -8.222e+05  1.693e+04  -48.58  < 2e-16 ***
## StoreGroupMedium -6.647e+05  9.978e+03  -66.62  < 2e-16 ***
## IsHolidayTRUE     6.813e+04  1.349e+04    5.05  4.6e-07 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 235900 on 4499 degrees of freedom
## Multiple R-squared:  0.8288, Adjusted R-squared:  0.8287 
## F-statistic:  5445 on 4 and 4499 DF,  p-value: < 2.2e-16

We can expect Holidays to positively impact Sales in general but as can be seem from above plot, we cannot strongly state that all Holiday Weeks result in higher Sales. Thanksgiving week seems to have jump in sales by Xmas week on the other hand shows a drop

We use Forward selection mechanism to pin point the most significant variables

Repeated with Backward Selection. In both cases, we ended up with similar models. Hence proceeding with this Model.

Using leaps package, we can check for different combinations of the independent variables and select the best combination on the basis or R-sq / Adjusted R-sq. We are using Adjusted R-sq here.

## 
## Call:
## lm(formula = Weekly_Sales ~ Type + Temperature + MarkDown3 + 
##     MarkDown5 + CPI + Unemployment + Size + WeekType + StoreGroup, 
##     data = trainM)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -696154 -123359   -1768  111566 1784907 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   2.578e+05  2.900e+04   8.892  < 2e-16 ***
## Type1         4.242e+04  1.083e+04   3.916 9.14e-05 ***
## Type2         3.658e+04  1.686e+04   2.169 0.030122 *  
## Temperature   7.270e+02  1.870e+02   3.887 0.000103 ***
## MarkDown3     4.027e+00  6.398e-01   6.295 3.38e-10 ***
## MarkDown5     5.878e+00  8.070e-01   7.285 3.79e-13 ***
## CPI          -1.294e+03  8.549e+01 -15.135  < 2e-16 ***
## Unemployment -5.231e+03  1.847e+03  -2.832 0.004645 ** 
## Size          5.072e+00  1.187e-01  42.742  < 2e-16 ***
## WeekType1     6.507e+04  7.266e+03   8.955  < 2e-16 ***
## WeekType2     3.997e+05  1.398e+04  28.597  < 2e-16 ***
## StoreGroup1   1.312e+05  1.338e+04   9.806  < 2e-16 ***
## StoreGroup2   7.924e+05  1.676e+04  47.278  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 207500 on 4491 degrees of freedom
## Multiple R-squared:  0.8678, Adjusted R-squared:  0.8674 
## F-statistic:  2456 on 12 and 4491 DF,  p-value: < 2.2e-16

We had noticed that Size of the Store is high on large & Small sizes and few in between which is probably adding to the positive skewness. Hence we will further enhance the current Model with a log transformation of Size.

Polynomial Regression

## 
## Call:
## lm(formula = Weekly_Sales ~ Type + Temperature + MarkDown3 + 
##     MarkDown5 + CPI + Unemployment + I(log(Size)) + WeekType + 
##     StoreGroup, data = trainM)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -699985 -148795    3265  131375 1759117 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -4.631e+06  1.512e+05 -30.633  < 2e-16 ***
## Type1        -6.443e+04  1.002e+04  -6.430 1.41e-10 ***
## Type2         1.676e+04  1.861e+04   0.901   0.3677    
## Temperature   7.732e+02  1.952e+02   3.960 7.61e-05 ***
## MarkDown3     4.055e+00  6.679e-01   6.071 1.37e-09 ***
## MarkDown5     6.299e+00  8.422e-01   7.479 8.93e-14 ***
## CPI          -1.049e+03  9.024e+01 -11.629  < 2e-16 ***
## Unemployment -4.608e+03  1.929e+03  -2.389   0.0169 *  
## I(log(Size))  4.811e+05  1.331e+04  36.152  < 2e-16 ***
## WeekType1     6.335e+04  7.585e+03   8.353  < 2e-16 ***
## WeekType2     3.959e+05  1.459e+04  27.142  < 2e-16 ***
## StoreGroup1   7.428e+04  1.608e+04   4.619 3.97e-06 ***
## StoreGroup2   7.689e+05  1.921e+04  40.026  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 216600 on 4491 degrees of freedom
## Multiple R-squared:  0.8559, Adjusted R-squared:  0.8555 
## F-statistic:  2223 on 12 and 4491 DF,  p-value: < 2.2e-16

3.2 Residual Analysis

#################################
# Comparasion of the Two Models #
#################################
plot(trainM$Size,trainM$Weekly_Sales)
points(trainM$Size, Model_full$fitted.values, pch = 20, col= 'blue')
points(trainM$Size, Model_P$fitted.values, pch = 20, col= 'green')

Transformation

We had observed in EDA, that Weekly Sales is positively skewed. There is still skewness to the right and hence we will try transformation on the response variable.

4 Finalizing Model

Initially we tried Square Root transformation but not a major improvement in skewness.

Using Boxcox, we see lambda close to 0 and hence using log transformation.

## 
## Call:
## lm(formula = log(Weekly_Sales) ~ Size + Temperature + MarkDown3 + 
##     MarkDown5 + CPI + WeekType + StoreGroup, data = trainM)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -0.62833 -0.12823 -0.00425  0.12403  0.97004 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  1.261e+01  1.897e-02 664.939  < 2e-16 ***
## Size         5.329e-06  6.638e-08  80.271  < 2e-16 ***
## Temperature  8.137e-04  1.795e-04   4.532 5.98e-06 ***
## MarkDown3    2.313e-06  6.247e-07   3.703 0.000216 ***
## MarkDown5    5.363e-06  7.844e-07   6.837 9.16e-12 ***
## CPI         -1.251e-03  7.840e-05 -15.957  < 2e-16 ***
## WeekType1    4.745e-02  6.953e-03   6.825 9.99e-12 ***
## WeekType2    3.033e-01  1.347e-02  22.514  < 2e-16 ***
## StoreGroup1  4.708e-01  1.099e-02  42.822  < 2e-16 ***
## StoreGroup2  9.111e-01  1.457e-02  62.541  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.2027 on 4494 degrees of freedom
## Multiple R-squared:  0.8834, Adjusted R-squared:  0.8831 
## F-statistic:  3782 on 9 and 4494 DF,  p-value: < 2.2e-16

With this, we have build our final Model: Model with an adjusted R-sq = 88.24 and all variables are highly significant.

5 Prediction Using the Fit Model

6 Evaluation of Model by Test Data

Doing the prediction using the Test Data set, We got very good predictions and pretty closer with the real values.

For whole data set.

7 Forecasting

Other Models

Using now the ts data frame.

8 Conslusion

We were able to build this model with Adjusted R-sq = 88% and Predicted R-Sq = 88%. The variables “Store Group” & “Week Type” constructed from the data set are the most significant variables. With this Model, we can predict a good estimate of the weekly Sales for Stores.

9 Extra: Pivot Table

With this Pivot Table We can manipulate and see the distribution for whatever variables combination. It´s totally interactive Pivot Table. We can drag the variables to the columns or rows, choose the categories, make filters, choose which metrics or graphs.

LS0tDQp0aXRsZTogPGNlbnRlcj4gU3VwZXJtYXJrZXQgU2FsZXMgUHJlZGljdGlvbiA8Y2VudGVyPg0KYXV0aG9yOiA8Y2VudGVyPiBXZWNzbGV5IE8uIFByYXRlcyA8Y2VudGVyPg0KZGF0ZTogPGNlbnRlcj4gRGVjZW1iZXIsIDExLCAyMDIwIDwvY2VudGVyPg0Kb3V0cHV0OiANCiAgaHRtbF9kb2N1bWVudDogDQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgY29kZV9mb2xkaW5nOiBzaG93DQogICAgZGZfcHJpbnQ6IGthYmxlDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0aGVtZTogZmxhdGx5DQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6IHllcw0Kc3VidGl0bGU6IDxjZW50ZXI+IFN1cGVybWFya2V0IFNhbGVzIFByZWRpY3Rpb24gPC9jZW50ZXI+DQpwYWdldGl0bGU6IDxjZW50ZXI+IFN1cGVybWFya2V0IFNhbGVzIFByZWRpY3Rpb24gPC9jZW50ZXI+DQotLS0NCg0KYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMjIyMjIyMjIyMjIyMjIyMjIyMjDQojIEltcG9ydCBMaWJyYXJpZXMgIw0KIyMjIyMjIyMjIyMjIyMjIyMjIyMNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShsdWJyaWRhdGUpDQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkoRW52U3RhdHMpDQpsaWJyYXJ5KGdyaWRFeHRyYSkNCmxpYnJhcnkoZ3JpZCkNCg0KYGBgDQoNCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMgR3JhcGhpY3MgVGhlbWVzIGZvciBHR3Bsb3QgIw0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQpteV90aGVtZSA8LSBmdW5jdGlvbihiYXNlX3NpemUgPSAxMCwgYmFzZV9mYW1pbHkgPSAic2FucyIpew0KICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IGJhc2Vfc2l6ZSwgYmFzZV9mYW1pbHkgPSBiYXNlX2ZhbWlseSkgKw0KICAgIHRoZW1lKA0KICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksDQogICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDAsIHZqdXN0ID0gMC41LCBoanVzdCA9IDAuNSksDQogICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksDQogICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG9yID0gImdyZXkiKSwNCiAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiI2ZmZmZlZiIpLA0KICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiNmZmJiMDAiLCBjb2xvciA9ICJibGFjayIsIHNpemUgPTAuNSksDQogICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxMCwgY29sb3IgPSAiYmxhY2siKSwNCiAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLA0KICAgICAgbGVnZW5kLmp1c3RpZmljYXRpb24gPSAiY2VudGVyIiwNCiAgICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG9yID0gImdyZXkzMCIsIGZpbGwgPSBOQSwgc2l6ZSA9IDAuNSkNCiAgICApDQp9DQp0aGVtZV9zZXQobXlfdGhlbWUoKSkNCg0KbXljb2xvcnM9YygiI2YzMjQ0MCIsIiNmZmQ3MDAiLCIjZmY4YzAwIiwiI2M5ZTEwMSIsIiNjMTAwZTYiLCIjMzlkM2Q2IiwNCiAgICAgICAgICAgIiNlODQ0MTIiLCAiI0IyMTgyQiIsICIjRDY2MDREIiwgIiNGNEE1ODIiLCAiI0ZEREJDNyIsICIjRDFFNUYwIiwNCiAgICAgICAgICAgIiM5OTk5OTkiLCAiI0U2OUYwMCIsICIjNTZCNEU5IikNCmBgYA0KDQojIERhdGEgRXhwbG9yYXRpb24gJiBDbGVhbmluZyB7LnRhYnNldH0NCg0KVGhlIGRhdGEgY29udGFpbnMgaGlzdG9yaWNhbCBzYWxlcyBkYXRhIGZvciA0NSBgc3RvcmVzYCBsb2NhdGVkIGluIGRpZmZlcmVudCByZWdpb25zLiBFYWNoIHN0b3JlIGNvbnRhaW5zIGEgbnVtYmVyIG9mIGRlcGFydG1lbnRzLCBhbmQgeW91IGFyZSB0YXNrZWQgd2l0aCBwcmVkaWN0aW5nIHRoZSBkZXBhcnRtZW50LXdpZGUgc2FsZXMgZm9yIGVhY2ggc3RvcmUuIFRoZSBkYXRhIGlzIHN0b3JlZCBpbiAzIGRpZmZlcmVudCBgY3N2YCBmaWxlcy4NCg0KKmBzdG9yZXMuY3N2YCogDQpUaGlzIGZpbGUgY29udGFpbnMgYW5vbnltaXplZCBpbmZvcm1hdGlvbiBhYm91dCB0aGUgNDUgc3RvcmVzLCBpbmRpY2F0aW5nIHRoZSB0eXBlIGFuZCBzaXplIG9mIHN0b3JlLg0KDQoqYHNhbGVzLmNzdmAqDQpUaGlzIGlzIHRoZSBoaXN0b3JpY2FsIHNhbGVzIGRhdGEsIHdoaWNoIGNvdmVycyB0byAyMDEwLTAyLTA1IHRvIDIwMTMtMDctMjYuIFdpdGhpbiB0aGlzIGZpbGUgeW91IHdpbGwgZmluZCB0aGUgZm9sbG93aW5nIGZpZWxkczoNCg0KLSBTdG9yZSAtIHRoZSBzdG9yZSBudW1iZXINCg0KLSBEZXB0IC0gdGhlIGRlcGFydG1lbnQgbnVtYmVyDQoNCi0gRGF0ZSAtIHRoZSB3ZWVrDQoNCi0gV2Vla2x5X1NhbGVzIC0gc2FsZXMgZm9yIHRoZSBnaXZlbiBkZXBhcnRtZW50IGluIHRoZSBnaXZlbiBzdG9yZQ0KDQotIElzSG9saWRheSAtIHdoZXRoZXIgdGhlIHdlZWsgaXMgYSBzcGVjaWFsIGhvbGlkYXkgd2Vlaw0KDQoqYEZlYXR1cmVzLmNzdmAqDQpUaGlzIGZpbGUgY29udGFpbnMgYWRkaXRpb25hbCBkYXRhIHJlbGF0ZWQgdG8gdGhlIHN0b3JlLCBkZXBhcnRtZW50LCBhbmQgcmVnaW9uYWwgYWN0aXZpdHkgZm9yIHRoZSBnaXZlbiBkYXRlcy4gSXQgY29udGFpbnMgdGhlIGZvbGxvd2luZyBmaWVsZHM6DQoNCi0gU3RvcmUgLSB0aGUgc3RvcmUgbnVtYmVyDQoNCi0gRGF0ZSAtIHRoZSB3ZWVrDQoNCi0gVGVtcGVyYXR1cmUgLSBhdmVyYWdlIHRlbXBlcmF0dXJlIGluIHRoZSByZWdpb24NCg0KLSBGdWVsX1ByaWNlIC0gY29zdCBvZiBmdWVsIGluIHRoZSByZWdpb24NCg0KLSBNYXJrRG93bjEtNSAtIGFub255bWl6ZWQgZGF0YSByZWxhdGVkIHRvIHByb21vdGlvbmFsIG1hcmtkb3ducyB0aGF0IFdhbG1hcnQgaXMgcnVubmluZy4gTWFya0Rvd24gZGF0YSBpcyBvbmx5IGF2YWlsYWJsZSBhZnRlciBOb3YgMjAxMSwgYW5kIGlzIG5vdCBhdmFpbGFibGUgZm9yIGFsbCBzdG9yZXMgYWxsIHRoZSB0aW1lLiBBbnkgbWlzc2luZyB2YWx1ZSBpcyBtYXJrZWQgd2l0aCBhbiBOQS4NCg0KLSBDUEkgLSB0aGUgY29uc3VtZXIgcHJpY2UgaW5kZXgNCg0KLSBVbmVtcGxveW1lbnQgLSB0aGUgdW5lbXBsb3ltZW50IHJhdGUNCg0KLSBJc0hvbGlkYXkgLSB3aGV0aGVyIHRoZSB3ZWVrIGlzIGEgc3BlY2lhbCBob2xpZGF5IHdlZWsNCg0KIyMgUmVhZCB0aGUgRGF0YSBTZXRzDQoNCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMgUmVhZGluZyB0aGUgRmlsZXMgIw0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQojIyMjIyMjIyMjIyMjIyMjIyMjIw0KIyBGZWF0dXJlcyBEYXRhU2V0ICMNCiMjIyMjIyMjIyMjIyMjIyMjIyMjDQpmZWF0dXJlcyA8LSByZWFkLmNzdigiZmVhdHVyZXMuY3N2IikNCmhlYWQoZmVhdHVyZXMpDQoNCiMjIyMjIyMjIyMjIyMjIyMNCiMgU2FsZSBEYXRhU2V0ICMNCiMjIyMjIyMjIyMjIyMjIyMNCnNhbGVzIDwtIHJlYWQuY3N2KCJzYWxlcy5jc3YiKQ0KaGVhZChzYWxlcykNCg0KIyMjIyMjIyMjIyMjIyMjIyMjDQojIFN0b3JlcyBEYXRhU2V0ICMNCiMjIyMjIyMjIyMjIyMjIyMjIw0Kc3RvcmVzIDwtIHJlYWQuY3N2KCJzdG9yZXMuY3N2IikNCmhlYWQoc3RvcmVzKQ0KDQpgYGANCg0KIyMgRGF0YSBFeHBsb3JhdGlvbiAmIE1hbmlwdWxhdGlvbg0KDQpJbiB0aGlzIHNlY3Rpb24sIFdlIGFyZSBnb2luZyB0byBkbyBzb21lIERhdGEgRXhwbG9yYXRpb24uIEZpcnN0IG9mIGFsbCwgV2UgYXJlIGdvaW5nIHRvIHNwbGl0IHRoZSBkYXRhIGludG8gYFllYXJgLCBgTW9udGhgIGFuZCBgRGF5YC4gIA0KDQpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQojIERhdGUgU3BsaXQgaW50byBZZWFyLCBNb250aCBhbmQgRGF5ICMNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KZmVhdHVyZXMkRGF0ZSA8LSBhcy5EYXRlKGZlYXR1cmVzJERhdGUsIGZvcm1hdCA9ICIlZC8lbS8lWSIpDQpmZWF0dXJlcyRXZWVrIDwtIGZvcm1hdChmZWF0dXJlcyREYXRlLCAiJVYiKQ0KZmVhdHVyZXMgPC0gc2VwYXJhdGUoZmVhdHVyZXMsICJEYXRlIiwgYygiWWVhciIsICJNb250aCIsICJEYXkiKSwgc2VwID0gIi0iKQ0KDQpgYGANCg0KTm93LCBXZSBjcmVhdGVkIGEgZmVhdHVyZSBgV2Vla2x5IHNhbGVzYCBmcm9tIHNhbGVzIGRhdGEgc2V0LiANCg0KYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMgQ3JlYXRpbmcgV2Vla2x5IFNhbGVzICMNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCnNhbGVzIDwtIHNhbGVzICU+JSANCiAgZ3JvdXBfYnkoU3RvcmUsIERhdGUsIElzSG9saWRheSkgJT4lIA0KICBzdW1tYXJpemUoV2Vla2x5X1NhbGVzID0gc3VtKFdlZWtseV9TYWxlcykpDQoNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KIyBEYXRlIFNwbGl0IGludG8gWWVhciwgTW9udGggYW5kIERheSAjDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCnNhbGVzJERhdGUgPC0gYXMuRGF0ZShzYWxlcyREYXRlLCBmb3JtYXQgPSAiJWQvJW0vJVkiKQ0Kc2FsZXMgPC0gc2VwYXJhdGUoc2FsZXMsICJEYXRlIiwgYygiWWVhciIsICJNb250aCIsICJEYXkiKSwgc2VwID0gJy0nKQ0KDQpgYGANCg0KTm93LCBXZSBtdXN0IG1lcmdlIHRoZSB0d28gZGF0YSBzZXRzIGBmZWF0dXJlc2AgYW5kIGBzYWxlc2AuDQoNCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KIyBNZXJnZSB0aGUgRGF0YSBTZXRzICMNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQpzYWxlc00gPC0gbWVyZ2Uoc2FsZXMsZmVhdHVyZXMpDQoNCmBgYA0KDQpUaGVyZSBpcyB0aGUgaW5mb3JtYXRpb24gYWJvdXQgYFN0b3JlIFNpemVgIGZyb20gYFN0b3Jlc2AgZGF0YSBzZXQuIFNvLCBXZSBhcmUgbm93LCBtZXJnZSB0aGUgYFNhbGVzTWAgd2l0aCBgU3RvcmVzYGRhdGEgc2V0cyBhbHNvLiBNZXJnaW5nIGFsbCB0aGUgZGF0YSBzZXRzIGludG8gb25lIHNhbGVzIGRhdGEgc2V0IHdoaWNoIHdpbGwgYmUgc3BsaXQgaW50byBzYWxlcyBhbmQgdGVzdGluZyBkYXRhIHNldHMgZm9yIGRhdGEgbW9kZWxpbmcuIA0KDQpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMgU3RvcmUgU2l6ZSBpbmZvcm1hdGlvbiBpcyBhdmFpbGFibGUgZnJvbSBTdG9yZXMgZGF0YXNldCAjDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0Kc2FsZXNNIDwtIG1lcmdlKHNhbGVzTSwgc3RvcmVzLCBieSA9ICJTdG9yZSIpDQoNCmBgYA0KDQojIERhdGEgQW5hbHlzaXMgJiBWaXN1YWxpemF0aW9uIHsudGFic2V0fQ0KDQojIyBEYXRhIERpc3RyaWJ1dGlvbg0KDQpMZXTCtHMsIGZpcnN0IG9mIGFsbCwgbG9vayBhdCB0aGUgVmFyaWFibGVzIGRpc3RyaWJ1dGlvbi4gDQoNCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQojIERpc3RyaWJ1dGlvbiBvZiBWYXJpYWJsZXMgIw0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KcGFyKG1mcm93PWMoMywyKSkNCmhpc3Qoc2FsZXNNJFN0b3JlLCBjb2wgPSAnbGlnaHQgZ3JlZW4nLCBtYWluID0gIlN0b3JlcyIpDQpoaXN0KHNhbGVzTSRUZW1wZXJhdHVyZSwgY29sID0gJ2xpZ2h0IGdyZWVuJywgbWFpbiA9ICJUZW1wZXJhdHVyZSIpDQpoaXN0KHNhbGVzTSRGdWVsX1ByaWNlLCBjb2wgPSAnbGlnaHQgZ3JlZW4nLCBtYWluID0gIkZ1ZWwgUHJpY2UiKQ0KaGlzdChzYWxlc00kQ1BJLCBjb2wgPSAnbGlnaHQgZ3JlZW4nLCBtYWluID0gIkNQSSIpDQpoaXN0KHNhbGVzTSRVbmVtcGxveW1lbnQsIGNvbCA9ICdsaWdodCBncmVlbicsIG1haW4gPSAiVW5lbXBsb3ltZW50IikNCmhpc3Qoc2FsZXNNJFNpemUsIGNvbCA9ICdsaWdodCBncmVlbicsIG1haW4gPSAiU3RvcmUgU2l6ZSIpDQoNCmBgYA0KDQpgVGVtcGVyYXR1cmVgIGFuZCBgVW5lbXBsb3ltZW50YCBhcmUgZmFpcmx5IG5vcm1hbGx5IGRpc3RyaWJ1dGVkLiBTdG9yZSBTaXplcyBoYXZlIGJyYWNrZXRzIG9uIGJvdGggZW5kcyBpbmRpY2F0aW5nIGxhcmdlIG51bWJlciBvZiBsYXJnZSBhbmQgc21hbGwgc3RvcmVzLiBUaGUgbWVkaXVtIHNpemVkIHN0b3JlcyBhcmUgdmVyeSBmZXcgaW4gY29tcGFyaXNvbiBpbiB0aGlzIGRhdGEgc2V0LiBXZSBtaWdodCBuZWVkIHRvIGRvIHNvbWUgdHJhbnNmb3JtYXRpb24gb2YgdGhpcyBkYXRhLg0KDQojIyBTYWxlcyBEaXN0cmlidXRpb24gYW5kIEFuYWx5c2lzDQoNCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KIyBEaXN0cmlidXRpb24gb2YgV2Vla2x5IFNhbGVzICMNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQpwYXIobWZyb3cgPSBjKDEsMikpDQpoaXN0KHNhbGVzTSRXZWVrbHlfU2FsZXMsIGNvbCA9ICdsaWdodCBncmVlbicsIA0KICAgICBtYWluID0gIldlZWtseSBTYWxlcyBPcmlnaW5hbCIsIHhsYWIgPSAiV2Vla2x5IFNhbGVzIikNCmhpc3QobG9nKHNhbGVzTSRXZWVrbHlfU2FsZXMpLCBjb2wgPSAnbGlnaHQgZ3JlZW4nLCANCiAgICAgbWFpbiA9ICJXZWVrbHkgU2FsZXMgVHJhbnNmb3JtZWQiLCB4bGFiID0nbG9nKFdlZWtseSBTYWxlcyknKQ0KDQpgYGANCg0KYFdlZWtseSBTYWxlc2AgaXMgcG9zaXRpdmVseSBza2V3ZWQgaW5kaWNhdGluZyBmZXcgbGFyZ2UgdmFsdWVzLiBUaGlzIGNvdWxkIGJlIGNhdXNlZCBieSB0aGUgZmVzdGl2ZSBXZWVrcyB3aGljaCBhcmUgZmV3IGJ1dCBTYWxlcyB2YWx1ZSBmb3IgdGhlc2Ugd2Vla3Mgd291bGQgYmUgdmVyeSBoaWdoIGluIGNvbXBhcmlzb24gdG8gb3RoZXIgd2Vla3MuIFdlIGNhbiB0cmFuc2Zvcm0gaXQgdXNpbmcgYSBsb2cgdHJhbnNmb3JtYXRpb24gYXMgY2FuIGJlIHNlZW0gZnJvbSB0aGUgc2Vjb25kIHBsb3QuIFRoaXMgbWlnaHQgYmUgcmVxdWlyZWQgd2hlbiB3ZSBidWlsZCB0aGUgbW9kZWwgdG9vLiANCg0KYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMgRGlzdHJpYnV0aW9uIG9mIFdlZWtseSBTYWxlcyBieSBZZWFyICMNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCmdncGxvdChzYWxlc00sIGFlcyh4ID0gTW9udGgseSA9IFdlZWtseV9TYWxlcyApKSArIA0KICBnZW9tX2NvbCgpICsgbXlfdGhlbWUoKSArDQogIGZhY2V0X3dyYXAoflllYXIpICsgDQogIGdndGl0bGUoIldlZWtseSBTYWxlcyBEaXN0cmlidXRpb24iKQ0KDQpgYGANCg0KU2FsZXMgRGF0YSBpcyBtaXNzaW5nIGZvciBKYW51YXJ5IGluIDIwMTAsIE5vdmVtYmVyIGFuZCBEZWNlbWJlciBpbiAyMDEyLlRoZXJlIGFyZSB3ZWVrcyB3aGVuIFNhbGVzIHBlYWtzIGluIHRoZSBmZXN0aXZlIG1vbnRocyBvZiBOb3ZlbWJlciBhbmQgRGVjZW1iZXIuQWxzbyBzZWVtcyBsaWtlIHRoZXJlIGlzIGEgZGlwIGluIFNlcHRlbWJlciAtIE9jdG9iZXIgbGVhZGluZyB0b3dhcmRzIHRoZSBob2xpZGF5IHdlZWtzLg0KDQpMZXTCtHMgbm93IGdyb3VwaW5nIHRoZSBXZWVrcyBiYXNlZCBvbiBTYWxlcy4gV2UgYXJlIGdvaW5nIHRvIHVzZSBmcm9tIDIwMTEsIGJlY2F1c2UgdGhlIGRhdGEgaXMgYXZhaWxhYmxlIGZvciBmdWxsIHllYXIuIEFuZCBsZXTCtHMgc3VtbWFyaXplIHRoZSBgV2Vla2x5IFNhbGVzYC4gDQoNCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQojIFVzaW5nIDIwMTEgYXMgQmFzZSAjDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQpXZWVrczIwMTFBIDwtIHNhbGVzTSAlPiUgDQogIGZpbHRlcihZZWFyID09IDIwMTEsIFR5cGUgPT0gIkEiKSAlPiUgDQogIGdyb3VwX2J5KFR5cGUsIFdlZWspICU+JSANCiAgc3VtbWFyaXplKFNpemUgPSBtZWFuKFNpemUpLCBXZWVrbHlTYWxlcyA9IHN1bShXZWVrbHlfU2FsZXMpKQ0KDQpXZWVrczIwMTFCIDwtIHNhbGVzTSAlPiUgDQogIGZpbHRlcihZZWFyID09IDIwMTEsIFR5cGUgPT0gIkIiKSAlPiUgDQogIGdyb3VwX2J5KFR5cGUsIFdlZWspICU+JSANCiAgc3VtbWFyaXplKFNpemUgPSBtZWFuKFNpemUpLCBXZWVrbHlTYWxlcyA9IG1lYW4oV2Vla2x5X1NhbGVzKSkNCg0KV2Vla3MyMDExQyA8LSBzYWxlc00gJT4lIA0KICBmaWx0ZXIoWWVhciA9PSAyMDExLCBUeXBlID09ICJDIikgJT4lIA0KICBncm91cF9ieShUeXBlLCBXZWVrKSAlPiUgDQogIHN1bW1hcml6ZShTaXplID0gbWVhbihTaXplKSwgV2Vla2x5U2FsZXMgPSBtZWFuKFdlZWtseV9TYWxlcykpDQoNCmBgYA0KDQpOb3csIGNhbGN1bGF0aW5nIHRoZSB1cHBlciBhbmQgbG93ZXIgdGhyZXNob2xkIGJhc2VkIG9uIDUlIGJvdW5kcy4gDQoNCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KIyBVcHBlciBhbmQgTG93ZXIgVGhyZXNob2xkICMNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQpXZWVrczIwMTFBJE1lYW5XZWVrbHlTYWxlcyA8LSBtZWFuKFdlZWtzMjAxMUEkV2Vla2x5U2FsZXMpDQpXZWVrczIwMTFCJE1lYW5XZWVrbHlTYWxlcyA8LSBtZWFuKFdlZWtzMjAxMUIkV2Vla2x5U2FsZXMpDQpXZWVrczIwMTFDJE1lYW5XZWVrbHlTYWxlcyA8LSBtZWFuKFdlZWtzMjAxMUMkV2Vla2x5U2FsZXMpDQoNCldlZWtzMjAxMUEkU2FsZXNVcHBlclRocmVzaG9sZCA8LSBtZWFuKFdlZWtzMjAxMUEkV2Vla2x5U2FsZXMpICogMS4wNQ0KV2Vla3MyMDExQSRTYWxlc0xvd2VyVGhyZXNob2xkIDwtIG1lYW4oV2Vla3MyMDExQSRXZWVrbHlTYWxlcykgKiAwLjk1DQoNCldlZWtzMjAxMUIkU2FsZXNVcHBlclRocmVzaG9sZCA8LSBtZWFuKFdlZWtzMjAxMUIkV2Vla2x5U2FsZXMpICogMS4wNQ0KV2Vla3MyMDExQiRTYWxlc0xvd2VyVGhyZXNob2xkIDwtIG1lYW4oV2Vla3MyMDExQiRXZWVrbHlTYWxlcykgKiAwLjk1DQoNCldlZWtzMjAxMUMkU2FsZXNVcHBlclRocmVzaG9sZCA8LSBtZWFuKFdlZWtzMjAxMUMkV2Vla2x5U2FsZXMpICogMS4wNQ0KV2Vla3MyMDExQyRTYWxlc0xvd2VyVGhyZXNob2xkIDwtIG1lYW4oV2Vla3MyMDExQyRXZWVrbHlTYWxlcykgKiAwLjk1DQoNCmdncGxvdChXZWVrczIwMTFBLCBhZXMoeCA9IFdlZWsseSA9IFdlZWtseVNhbGVzKSkgKyANCiAgZ2VvbV9jb2woKSArIG15X3RoZW1lKCkNCg0KYGBgDQoNCldlIGhhdmUgYXJvdW5kIDUyIHdlZWtzIGluIHRoZSBkYXRhIHNldCB3aGljaCBjYW4gYmUgdXNlZCBhcyBhIENhdGVnb3JpY2FsIFZhcmlhYmxlIGFzIHdlIGNhbiBzZWUgdHJlbmRzIGluIFNhbGVzIGFjcm9zcyB3ZWVrcy4gQnV0IGRvaW5nIHRoaXMgd291bGQgY29tcGxpY2F0ZSB0aGUgbW9kZWwgd2l0aCB0b28gbWFueSB2YXJpYWJsZXMuDQoNCkluc3RlYWQsIHdlIGNhbiB0cnkgdG8gY2x1c3RlciB0aGUgd2Vla3MgYmFzZWQgb24gU2FsZXMuIFRoZXJlIGFyZSB3ZWVrcyB3aXRoIGxvd3MgYW5kIHBlYWtzIGluIFNhbGVzIGFuZCB0aGVuIHRoZXJlIGFyZSBtYWpvcml0eSBvZiB0aGUgd2Vla3Mgd2l0aCBTYWxlcyBhcm91bmQgdGhlIG1lZGlhbiB2YWx1ZQ0KDQpXZSBzcGxpdCB0aGUgZGF0YSB5ZWFyIHdpc2UgYW5kIFR5cGUgd2lzZSB0byBjYWxjdWxhdGUgYW4gVXBwZXIgKDUlIGhpZ2hlciB0aGFuIE1lYW4pIGFuZCBMb3dlciAoNSUgbG93ZXIgdGhhbiBNZWFuKSBUaHJlc2hvbGQgU2FsZXMgVmFsdWUuIFdlIGNsdXN0ZXIgd2Vla3Mgd2l0aCBTYWxlcyBoaWdoZXIgdGhhbiBVcHBlciB0aHJlc2hvbGQgYXMgSGlnaCB3ZWVrcywgbG93ZXIgdGhhbiBMb3dlciB0aHJlc2hvbGQgYXMgTG93IHdlZWtzIGFuZCBldmVyeXRoaW5nIGVsc2UgYXMgTWVkaXVtIHdlZWtzLiBUaGVzZSBDbHVzdGVycyBhcmUgc2hvd24gaW4gYmVsb3cgcGxvdC4NCg0KYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KIyBDcmVhdGluZyBMZXZlbCBvZiBTYWxlcyAjDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCldlZWtzMjAxMUEkV2Vla1R5cGUgPSAiTWVkaXVtIg0KV2Vla3MyMDExQVt3aGljaChXZWVrczIwMTFBJFdlZWtseVNhbGVzID4gV2Vla3MyMDExQSRTYWxlc1VwcGVyVGhyZXNob2xkKSw4XSA9ICJIaWdoIg0KV2Vla3MyMDExQVt3aGljaChXZWVrczIwMTFBJFdlZWtseVNhbGVzIDwgV2Vla3MyMDExQSRTYWxlc0xvd2VyVGhyZXNob2xkKSw4XSA9ICJMb3ciDQoNCldlZWtzMjAxMUIkV2Vla1R5cGUgPSAiTWVkaXVtIg0KV2Vla3MyMDExQlt3aGljaChXZWVrczIwMTFCJFdlZWtseVNhbGVzID4gV2Vla3MyMDExQiRTYWxlc1VwcGVyVGhyZXNob2xkKSw4XSA9ICJIaWdoIg0KV2Vla3MyMDExQlt3aGljaChXZWVrczIwMTFCJFdlZWtseVNhbGVzIDwgV2Vla3MyMDExQiRTYWxlc0xvd2VyVGhyZXNob2xkKSw4XSA9ICJMb3ciDQoNCldlZWtzMjAxMUMkV2Vla1R5cGUgPSAiTWVkaXVtIg0KV2Vla3MyMDExQ1t3aGljaChXZWVrczIwMTFDJFdlZWtseVNhbGVzID4gV2Vla3MyMDExQyRTYWxlc1VwcGVyVGhyZXNob2xkKSw4XSA9ICJIaWdoIg0KV2Vla3MyMDExQ1t3aGljaChXZWVrczIwMTFDJFdlZWtseVNhbGVzIDwgV2Vla3MyMDExQyRTYWxlc0xvd2VyVGhyZXNob2xkKSw4XSA9ICJMb3ciDQoNCldlZWtzMjAxMSA8LSByYmluZChXZWVrczIwMTFBWyxjKDEsMiw4KV0sIFdlZWtzMjAxMUJbLGMoMSwyLDgpXSwgV2Vla3MyMDExQ1ssYygxLDIsOCldKQ0KDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQojIEFkZCBXZWVrVHlwZSB0byBvdXIgRGF0YSAjDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQpzYWxlc00gPC0gbWVyZ2Uoc2FsZXNNLCBXZWVrczIwMTEsIGJ5ID0gYygiVHlwZSIsICJXZWVrIikpDQoNCmBgYA0KDQpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQojIFBsb3Qgb2YgV2Vla2x5IFNhbGVzICMNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KcGFyKG1mcm93ID0gYygxLDMpKQ0KZ2dwbG90KFdlZWtzMjAxMUEsIGFlcyh4ID0gV2Vlayx5ID0gV2Vla2x5U2FsZXMsIGZpbGwgPSBXZWVrVHlwZSkpICsgDQogIGdlb21fY29sKCkgKyBteV90aGVtZSgpDQpnZ3Bsb3QoV2Vla3MyMDExQiwgYWVzKHggPSBXZWVrLHkgPSBXZWVrbHlTYWxlcywgZmlsbCA9IFdlZWtUeXBlKSkgKyANCiAgZ2VvbV9jb2woKSArIG15X3RoZW1lKCkNCmdncGxvdChXZWVrczIwMTFDLCBhZXMoeCA9IFdlZWsseSA9IFdlZWtseVNhbGVzLCBmaWxsID0gV2Vla1R5cGUpKSArIA0KICBnZW9tX2NvbCgpICsgbXlfdGhlbWUoKQ0KDQpgYGANCg0KUGxvdHRpbmcgU3RvcmUgU2l6ZSBhZ2FpbnN0IFNhbGVzLCB3ZSBjYW4gb2JzZXJ2ZSBMaW5lYXIgcmVsYXRpb24uIFdlIGNvdWxkIG9ic2VydmVyIHBvc3NpYmlsaXR5IG9mIGNvbmZvdW5kaW5nIGhlcmUgYXMgd2UgY2FuIHNlZSBjaHVua3MgZm9yIGRpZmZlcmVudCBTaXplcy4NCg0KYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQojIFBsb3Qgb2YgV2Vla2x5IFNhbGVzIGJ5IFN0b3JlIFNpemUgIw0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCmdncGxvdChzYWxlc00sIGFlcyh4ID0gU2l6ZSwgeSA9IFdlZWtseV9TYWxlcykpKyANCiAgZ2VvbV9wb2ludCgpICsgbXlfdGhlbWUoKQ0KICBnZ3RpdGxlKCJTdG9yZSBTaXplIHZzIFNhbGVzIikNCiAgDQpgYGANCg0KQmFzZWQgb24gdGhpcywgd2Ugd2lsbCB0cnkgdG8gZ3JvdXAgdGhlIFN0b3JlIFNpemVzIGJ1dCB3ZSBhbHJlYWR5IGhhdmUgYSBgVHlwZWAgdmFyaWFibGUgaW4gdGhlIGRhdGEgc2V0LiBCZWxvdyBXZSBzZWUgaG93IGlzIHRoZSBzYWxlcyBsZXZlbCBiZWhhdmlvciBpbiAyMDExLiANCg0KYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KIyBTdW1tYXJ5IG9mIFdlZWtseSBTYWxlcyBieSBXZWVrIFR5cGUgaW4gWWVhciAyMDExICAjDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCnRyYWluX1NfMjAxMSA8LSBzYWxlc00gJT4lIA0KICBmaWx0ZXIoWWVhciA9PSAyMDExKSAlPiUgDQogIGdyb3VwX2J5KFN0b3JlLCBNb250aCwgV2VlaywgV2Vla1R5cGUsIFR5cGUsIElzSG9saWRheSkgJT4lIA0KICBzdW1tYXJpemUoV2Vla2x5U2FsZXMgPSBzdW0oV2Vla2x5X1NhbGVzKSwgU2l6ZSA9IG1lYW4oU2l6ZSksIA0KICAgICAgICAgICAgVGVtcCA9IG1lYW4oVGVtcGVyYXR1cmUpLCBGdWVsUHJpY2UgPSBtZWFuKEZ1ZWxfUHJpY2UpLCANCiAgICAgICAgICAgIFVuZW1wbG95bWVudCA9IG1lYW4oVW5lbXBsb3ltZW50KSkNCmdncGxvdCh0cmFpbl9TXzIwMTEsIGFlcyh4ID0gV2Vlayx5ID0gV2Vla2x5U2FsZXMsIGZpbGwgPSBXZWVrVHlwZSkpICsgDQogIGdlb21fY29sKCkgKyBteV90aGVtZSgpDQogIGZhY2V0X3dyYXAoflR5cGUpDQoNCmBgYA0KDQpIZXJlLCBXZSBoYXZlIHRoZSBgV2VlayBUeXBlYCBwZXIgWWVhciBhbmQgV2Vlay4NCg0KYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMgU3VtbWFyeSBvZiBXZWVrbHkgU2FsZXMgYnkgV2VlayBUeXBlIGJ5IFllYXIgICMNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCmdncGxvdChzYWxlc00sIGFlcyh4ID0gV2Vlayx5ID0gV2Vla2x5X1NhbGVzLCBmaWxsID0gV2Vla1R5cGUpKSArIA0KICBnZW9tX2NvbCgpICsgbXlfdGhlbWUoKQ0KICBmYWNldF93cmFwKH5ZZWFyKQ0KICANCmBgYA0KDQpIYW5kbGluZyB3aXRoIFN0b3JlIFNpemUgQ29uZm91bmRpbmcuDQoNCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMgU2l6ZSBTdG9yZSBJbXBhY3QgIw0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQpnZ3Bsb3Qoc2FsZXNNLCBhZXMoeCA9IFN0b3JlLHkgPSBTaXplLzEwMDAsIGZpbGwgPSBUeXBlKSkgKyANCiAgZ2VvbV9jb2woKSArIG15X3RoZW1lKCkNCg0KYGBgDQoNCkxldMK0cyBzZWUgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgYFdlZWtseSBTYWxlc2AgYnkgbGV2ZWwgb2YgdGhlIFN0b3Jlcy4gV2UgY3JlYXRlZCBhIGBVcHBlcmAgYW5kIGBMb3dlcmAgdGhyZXNob2xkLiANCg0KYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KIyBDcmVhdGluZyB0aGUgTGV2ZWwgb2YgdGhlIFN0b3JlcyAjDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNClN0b3JlU2FsZXMgPC0gc2FsZXNNICU+JSANCiAgZ3JvdXBfYnkoU3RvcmUsIFR5cGUpICU+JSANCiAgc3VtbWFyaXplKFNpemUgPSBtZWFuKFNpemUpLCBXZWVrbHlTYWxlcyA9IHN1bShXZWVrbHlfU2FsZXMpKQ0KDQpTdG9yZVVwcGVyVGhyZXNob2xkIDwtIG1lYW4oU3RvcmVTYWxlcyRXZWVrbHlTYWxlcykgKiAxLjQNClN0b3JlTG93ZXJUaHJlc2hvbGQgPC0gbWVhbihTdG9yZVNhbGVzJFdlZWtseVNhbGVzKSAqIDAuNA0KDQpTdG9yZVNhbGVzJFN0b3JlVXBwZXJUaHJlc2hvbGQgPC0gU3RvcmVVcHBlclRocmVzaG9sZA0KU3RvcmVTYWxlcyRTdG9yZUxvd2VyVGhyZXNob2xkIDwtIFN0b3JlTG93ZXJUaHJlc2hvbGQNCg0KU3RvcmVTYWxlcyRTdG9yZUdyb3VwID0gIk1lZGl1bSINClN0b3JlU2FsZXNbd2hpY2goU3RvcmVTYWxlcyRXZWVrbHlTYWxlcz5TdG9yZVVwcGVyVGhyZXNob2xkKSw3XSA9ICJIaWdoIg0KU3RvcmVTYWxlc1t3aGljaChTdG9yZVNhbGVzJFdlZWtseVNhbGVzPFN0b3JlTG93ZXJUaHJlc2hvbGQpLDddID0gIkxvdyINCg0KZ2dwbG90KFN0b3JlU2FsZXMsIGFlcyh4ID0gU3RvcmUseSA9IFdlZWtseVNhbGVzLCBmaWxsID0gU3RvcmVHcm91cCkpICsgDQogIGdlb21fY29sKCkgKyBteV90aGVtZSgpDQoNCmBgYA0KDQpCZWxvdywgV2UgaGF2ZSB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBgU3RvcmVgIGJ5IGBTaXplIFN0b3JlYCBhbmQgZ3JvdXBpbmcgYnkgYFR5cGVgLiANCg0KYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCnNhbGVzTSA8LSBtZXJnZShzYWxlc00sIFN0b3JlU2FsZXNbLGMoMSw3KV0sIGJ5ID0gIlN0b3JlIikNCmdncGxvdChzYWxlc00sIGFlcyh4ID0gU3RvcmUseSA9IFNpemUvMTAwMCwgZmlsbCA9IFN0b3JlR3JvdXApKSArIA0KICBnZW9tX2NvbCgpICsgbXlfdGhlbWUoKQ0KICBmYWNldF93cmFwKH5UeXBlKQ0KICANCmBgYA0KDQpXZSBzZWUgaW4gdGhlIGdyYXBoaWMgYmVsb3csIHRoZSBkaXN0cmlidXRpb24gb2YgYFdlZWtseSBTYWxlc2AgYnkgYFN0b3JlYCwgYExldmVsIG9mIHRoZSBTdG9yZWAgYnkgYFllYXJgLg0KDQpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KZ2dwbG90KHNhbGVzTSwgYWVzKHggPSBTdG9yZSx5ID0gV2Vla2x5X1NhbGVzLzEwMDAwLCBmaWxsID0gU3RvcmVHcm91cCkpICsgDQogIGdlb21fY29sKCkgKyBteV90aGVtZSgpDQogIGZhY2V0X3dyYXAoflllYXIpDQogIA0KYGBgDQoNCldoZW4gd2UgcGxvdCBgU2FsZXNgIGFnYWluc3QgYFN0b3JlYCB3aXRoIGBUeXBlYCBhcyBjb2xvciBkaW1lbnNpb24sIHdlIGNhbiBvYnNlcnZlIGNsZWFyIGdyb3VwcyBpbiB0aGUgc3RvcmVzIGJ1dCB0aGlzIGlzIG5vdCBleGFjdGx5IGNhcHR1cmVkIGJ5IHRoZSBgVHlwZWAgZmllbGQuIFRoZXJlIGFyZSBzb21lIFN0b3JlcyB3aXRoIHJlYWxseSBoaWdoIFNhbGVzIGNvbXBhcmVkIHRvIHJlc3QuIFRoZXNlIGBTdG9yZXNgIGFyZSBhIHN1YnNldCBvZiBUeXBlIEEuIFRoZW4gdGhlcmUgYXJlIGJ1bmNoIG9mIHN0b3JlcyB3aXRoIHNtYWxsIHNhbGVzIGFuZCBpcyBhIG1peHR1cmUgb2YgVHlwZSBCIGFuZCBUeXBlIEMuIFJlc3Qgb2YgdGhlIHN0b3JlcyBtYWtlcyBhdmVyYWdlIHNhbGVzIGluIGEgeWVhciBhbmQgZmFsbHMgaW4gYSBkaWZmZXJlbnQgZ3JvdXAuIFRoZXNlIHN0b3JlcyBhcmUgbWl4IG9mIFR5cGUgQSBhbmQgVHlwZSBCDQoNCldlIGhhdmUgZ3JvdXBlZCB0aGUgc3RvcmVzIGludG8gMyBjbHVzdGVycyBsaWtlIFdlZWsgR3JvdXBzIHdpdGhvdXQgY2hhbmdpbmcgdGhlIG9yaWdpbmFsIFR5cGUgdmFyaWFibGUuIFRoaXMgYXZvaWRzIHVzaW5nIHRoZSBTdG9yZSB2YXJpYWJsZSBhcyBhIGNhdGVnb3JpY2FsIHZhcmlhYmxlDQoNCmBVbmVtcGxveW1lbnRgLCBgQ1BJYCBhbmQgYEZ1ZWwgUHJpY2VgIGRvZXMgaW5mbHVlbmNlIFdlZWtseSBTYWxlcyBidXQgd2UgY2Fubm90IG9ic2VydmUgYW55IG1ham9yIHBhdHRlcm5zIGhlcmUuDQoNCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMgSGFuZGxpbmcgTWFya2Rvd24gIw0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQpzYWxlc01baXMubmEoc2FsZXNNJE1hcmtEb3duMSksXSRNYXJrRG93bjEgPC0gMA0Kc2FsZXNNW2lzLm5hKHNhbGVzTSRNYXJrRG93bjIpLF0kTWFya0Rvd24yIDwtIDANCnNhbGVzTVtpcy5uYShzYWxlc00kTWFya0Rvd24zKSxdJE1hcmtEb3duMyA8LSAwDQpzYWxlc01baXMubmEoc2FsZXNNJE1hcmtEb3duNCksXSRNYXJrRG93bjQgPC0gMA0Kc2FsZXNNW2lzLm5hKHNhbGVzTSRNYXJrRG93bjUpLF0kTWFya0Rvd241IDwtIDANCg0KYGBgDQoNClNpbmNlIHdlIGRvbuKAmXQgaGF2ZSBtdWNoIGluZm9ybWF0aW9uIG9uIHRoZSBNYXJrZG93bnMgYW5kIG1ham9yIHBhcnQgb2YgdGhlbSBhcmUgTi9BLCB3ZSBhcmUgbm90IGltcHV0aW5nIG1pc3NpbmcgdmFsdWVzIHdpdGggYSBtZWFuIC8gbWVkaWFuLiBJbnN0ZWFkLCB3ZSBhcmUgcmVwbGFjaW5nIE4vQXMgd2l0aCAwIHNvIHRoYXQgaXQgY2FuIGJlIHVzZWQgZm9yIE1vZGVsIGJ1aWxkaW5nIGFuZCBvdGhlciBjb21wdXRhdGlvbnMuDQoNCkxldMK0cyBzZWUgdGhlIGJlaGF2aW9yIG9mIGBXZWVrbHkgU2FsZXNgIGJ5IGBIb2xpZGF5YCBmZWF0dXJlcyBhbmFseXNpcyBkaXN0cmlidXRpb24uDQoNCipIb2xpZGF5IHggV2VlayoNCg0KYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KIyBIb2xpZGF5IERpc3RyaWJ1dGlvbiAjDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCmdncGxvdChzYWxlc00sIGFlcyh4ID0gV2Vlayx5ID0gV2Vla2x5X1NhbGVzLCBmaWxsID0gSXNIb2xpZGF5KSkgKyANCiAgZ2VvbV9jb2woKSArIG15X3RoZW1lKCkNCiAgZmFjZXRfd3JhcCh+WWVhcikNCg0KYGBgDQoNCipIb2xpZGF5IHggV2Vla2x5X1NhbGVzKg0KDQpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KIyBGdWVsIFByaWNlIGJ5IEhvbGlkYXkgIw0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KcDEgPC0gIGdncGxvdChzYWxlc00sIGFlcyhGdWVsX1ByaWNlLFdlZWtseV9TYWxlcykpICsgZ2VvbV9zbW9vdGgoYWVzKGNvbG9yPUlzSG9saWRheSkpDQoNCiMjIyMjIyMjIyMjIyMjIyMjIw0KIyBDUEkgYnkgSG9saWRheSAjDQojIyMjIyMjIyMjIyMjIyMjIyMNCnAyIDwtICBnZ3Bsb3Qoc2FsZXNNLCBhZXMoQ1BJLFdlZWtseV9TYWxlcykpICsgZ2VvbV9zbW9vdGgoYWVzKGNvbG9yPUlzSG9saWRheSkpDQoNCiMjIyMjIyMjIyMjIyMjIyMjIyMjDQojIFN0b3JlIGJ5IEhvbGlkYXkgIw0KIyMjIyMjIyMjIyMjIyMjIyMjIyMNCnAzIDwtICBnZ3Bsb3Qoc2FsZXNNLCBhZXMoU3RvcmUsV2Vla2x5X1NhbGVzKSkgKyBnZW9tX3Ntb290aChhZXMoY29sb3I9SXNIb2xpZGF5KSkNCg0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMgVGVtcGVyYXR1cmUgYnkgSG9saWRheSAjDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KcDQgPC0gIGdncGxvdChzYWxlc00sIGFlcyhUZW1wZXJhdHVyZSxXZWVrbHlfU2FsZXMpKSArIGdlb21fc21vb3RoKGFlcyhjb2xvcj1Jc0hvbGlkYXkpKQ0KDQojIyMjIyMjIyMjIyMjIyMjIyMjDQojIFNpemUgYnkgSG9saWRheSAjDQojIyMjIyMjIyMjIyMjIyMjIyMjDQpwNSA8LSAgZ2dwbG90KHNhbGVzTSwgYWVzKFNpemUsV2Vla2x5X1NhbGVzKSkgKyBnZW9tX3Ntb290aChhZXMoY29sb3I9SXNIb2xpZGF5KSkNCg0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQojIFVuZW1wbG95bWVudCBieSBIb2xpZGF5ICMNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KcDYgPC0gIGdncGxvdChzYWxlc00sIGFlcyhVbmVtcGxveW1lbnQsV2Vla2x5X1NhbGVzKSkgKyBnZW9tX3Ntb290aChhZXMoY29sb3I9SXNIb2xpZGF5KSkNCg0KZ3JpZC5hcnJhbmdlKHAxLCBwMiwgcDMsIHA0LCBwNSwgcDYsIG5jb2wgPSAyKQ0KDQpgYGANCg0KT2J2aW91c2x5LCBmcm9tIHRoZSBkaWZmZXJlbnQgdmFyaWFibGUgcGVyc3BlY3RpdmUsIHdlZWtseSBzYWxlcyBpcyBoaWdoZXIgZHVyaW5nIGhvbGlkYXlzLg0KDQpOb3csIGl0J3MgdGltZSB0byBzZWUgdGhlIGBNYXJrZG93bmAgZmVhdHVyZXMuIA0KDQoqTWFya2Rvd24geCBtb250aCB4IEhvbGlkYXkqDQoNCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMgTWFya2Rvd24gYnkgTW9udGggIw0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQpzYWxlc00kTWFya0Rvd241PWFzLm51bWVyaWMoc2FsZXNNJE1hcmtEb3duNSkNCnNhbGVzTSRNYXJrRG93bjQ9YXMubnVtZXJpYyhzYWxlc00kTWFya0Rvd240KQ0Kc2FsZXNNJE1hcmtEb3duMz1hcy5udW1lcmljKHNhbGVzTSRNYXJrRG93bjMpDQpzYWxlc00kTWFya0Rvd24yPWFzLm51bWVyaWMoc2FsZXNNJE1hcmtEb3duMikNCnNhbGVzTSRNYXJrRG93bjE9YXMubnVtZXJpYyhzYWxlc00kTWFya0Rvd24xKQ0KDQpwMSA8LSBnZ3Bsb3Qoc2FsZXNNLCBhZXMoTW9udGgsIE1hcmtEb3duMSkpICsgDQogIGdlb21fcG9pbnQoKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwLCBmYWNlID0gImJvbGQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2anVzdD0tMTQsIGhqdXN0ID0gMC41KSkNCg0KcDIgPC0gZ2dwbG90KHNhbGVzTSwgYWVzKE1vbnRoLCBNYXJrRG93bjQpKSArIA0KICBnZW9tX3BvaW50KCkgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCwgZmFjZSA9ICJib2xkIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmp1c3Q9LTE0LCBoanVzdCA9IDAuNSkpDQpncmlkLmFycmFuZ2UocDEsIHAyLCBuY29sID0gMSkNCg0KYGBgDQoNCk1hcmtkb3duIDEgYW5kIE1hcmtkb3duIDQgYXJlIG1haW5seSBvZmZlcmVkIG9uIEZlYnJ1YXJ5LCBNYXJjaCBhbmQgQXVndXN0IGFuZCBtb3N0IG9mIHRoZW0gb2ZmZXJlZCBkdXJpbmcgbm9uLWhvbGlkYXkuIFRoaXMgZGlzY291bnQgaXMgcG9zc2libHkgcmVsYXRlZCB0byBTdXBlciBib3dsIHNlYXNvbiwgTW90aGVy4oCZcyBkYXkgYW5kIGJhY2stdG8tc2Nob29sIHNlYXNvbi4NCg0KYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KIyBNYXJrZG93biBieSBNb250aCAjDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMNCmdncGxvdChzYWxlc00sIGFlcyhNb250aCwgTWFya0Rvd24yKSkgKyANCiAgZ2VvbV9wb2ludCgpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjAsIGZhY2UgPSAiYm9sZCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZqdXN0PS0xNCwgaGp1c3QgPSAwLjUpKQ0KDQpgYGANCg0KTWFya2Rvd24gMiBpcyBvZmZlcmVkIG1haW5seSBkdXJpbmcgRGVjIGhvbGlkYXkgYW5kIEphbiwgYnV0IGFsc28gaGFzIGl0cyBwZWFrcyBkdXJpbmcgTm92ZW1iZXIuIFRoaXMgZGlzY291bnQgaXMgcG9zc2libHkgcmVsYXRlZCB0byBDaHJpc3RtYXMgYW5kIE5ldyB5ZWFyLg0KDQpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQojIE1hcmtkb3duIGJ5IE1vbnRoICMNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KZ2dwbG90KHNhbGVzTSwgYWVzKE1vbnRoLCBNYXJrRG93bjMpKSArIA0KICBnZW9tX3BvaW50KCkgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCwgZmFjZSA9ICJib2xkIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmp1c3Q9LTE0LCBoanVzdCA9IDAuNSkpDQoNCmBgYA0KDQpNYXJrZG93biAzIGlzIG9mZmVyZWQgb25seSBkdXJpbmcgTm92IGhvbGlkYXkgYW5kIERlYy4gVGhpcyBkaXNjb3VudCBpcyBwb3NzaWJseSByZWxhdGVkIHRvIFRoYW5rc2dpdmluZy4NCg0KYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KIyBNYXJrZG93biBieSBNb250aCAjDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMNCmdncGxvdChzYWxlc00sIGFlcyhNb250aCwgTWFya0Rvd241KSkgKyANCiAgZ2VvbV9wb2ludCgpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjAsIGZhY2UgPSAiYm9sZCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZqdXN0PS0xNCwgaGp1c3QgPSAwLjUpKQ0KDQpgYGANCg0KTWFya2Rvd24gNSBpcyBtYWlubHkgb2ZmZXJlZCBkdXJpbmcgbm9uLWhvbGlkYXkgc2Vhc29uLg0KDQpMZXTCtHMgQ2F0ZWdvcml6ZWQgdGhlIGBXZWVrbHlzYWxlc2BhbmQgc2VlIHdoYXQgV2UgZmlndXJlIGl0IG91dC4gDQoNCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpzYWxlc00gPC0gc2FsZXNNICU+JQ0KICBtdXRhdGUoc2FsZXNfY2xhc3MgPSBpZmVsc2UoV2Vla2x5X1NhbGVzIDwgMCwgIk5lZ2F0aXZlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShXZWVrbHlfU2FsZXMgPj0wICYgV2Vla2x5X1NhbGVzIDwgMTAwMDAsICJMb3ciLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShXZWVrbHlfU2FsZXMgPj0xMDAwMCAmIFdlZWtseV9TYWxlcyA8IDI1MDAwLCAiTWVkaXVtIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKFdlZWtseV9TYWxlcyA+PTI1MDAwICYgV2Vla2x5X1NhbGVzIDwgMTAwMDAwLCAiSGlnaCIsICJWZXJ5X0hpZ2giKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQ0KICApDQoNCmdncGxvdChzYWxlc00sIGFlcyhzYWxlc19jbGFzcykpICsNCiAgZ2VvbV9iYXIoZmlsbD0yKSArDQogIGdlb21fdGV4dChzdGF0PSJjb3VudCIsYWVzKGxhYmVsID0gLi5jb3VudC4uKSwgdmp1c3QgPSAtMC41ICkNCg0KYGBgDQoNCiMgTWFjaGluZSBMZWFybmluZyB7LnRhYnNldH0NCg0KTGV0wrRzIG5vdyBzdGFydCB0aGUgTWFjaGluZSBMZWFybmluZyBkZXZlbG9wbWVudC4gDQoNCk9yaWdpbmFsIFRyYWluaW5nIGRhdGEgc2V0IGlzIHNwbGl0IGludG8gdHdvIHJhbmRvbSB0cmFpbmluZyBhbmQgdGVzdGluZyBkYXRhIHNldHMuIA0KDQojIyBNb2RlbHMgRGV2ZWxvcG1lbnQgDQoNCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQojIFNwbGl0IHRoZSBEYXRhIFNldCAjDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQpwaXZvdF90YWJsZSA8LSBzYWxlc00NCmluZGV4IDwtIHNhbXBsZShucm93KHNhbGVzTSksbnJvdyhzYWxlc00pKjAuNzApDQp0cmFpbk0gPC0gc2FsZXNNW2luZGV4LF0NCnRlc3RNIDwtIHNhbGVzTVstaW5kZXgsXQ0KDQojIyMjIyMjIyMjIyMjIyMjIyMjDQojIEJ1aWxkIHRoZSBNb2RlbCAjDQojIyMjIyMjIyMjIyMjIyMjIyMjDQpNb2RlbCA8LSBsbShmb3JtdWxhID0gV2Vla2x5X1NhbGVzflNpemUrU3RvcmVHcm91cCtJc0hvbGlkYXksIGRhdGEgPSB0cmFpbk0pDQpzdW1tYXJ5KE1vZGVsKQ0KDQpgYGANCg0KV2UgY2FuIGV4cGVjdCBIb2xpZGF5cyB0byBwb3NpdGl2ZWx5IGltcGFjdCBTYWxlcyBpbiBnZW5lcmFsIGJ1dCBhcyBjYW4gYmUgc2VlbSBmcm9tIGFib3ZlIHBsb3QsIHdlIGNhbm5vdCBzdHJvbmdseSBzdGF0ZSB0aGF0IGFsbCBIb2xpZGF5IFdlZWtzIHJlc3VsdCBpbiBoaWdoZXIgU2FsZXMuIFRoYW5rc2dpdmluZyB3ZWVrIHNlZW1zIHRvIGhhdmUganVtcCBpbiBzYWxlcyBieSBYbWFzIHdlZWsgb24gdGhlIG90aGVyIGhhbmQgc2hvd3MgYSBkcm9wDQoNCipXZSB1c2UgRm9yd2FyZCBzZWxlY3Rpb24gbWVjaGFuaXNtIHRvIHBpbiBwb2ludCB0aGUgbW9zdCBzaWduaWZpY2FudCB2YXJpYWJsZXMqDQoNClJlcGVhdGVkIHdpdGggQmFja3dhcmQgU2VsZWN0aW9uLiBJbiBib3RoIGNhc2VzLCB3ZSBlbmRlZCB1cCB3aXRoIHNpbWlsYXIgbW9kZWxzLiBIZW5jZSBwcm9jZWVkaW5nIHdpdGggdGhpcyBNb2RlbC4NCg0KYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMgQ3JlYXRlZCBjYXRlZ29yaWNhbCBkYXRhICMNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCnRyYWluTSRUeXBlIDwtIGZhY3Rvcih0cmFpbk0kVHlwZSwgbGV2ZWxzID0gYygiQSIsICJCIiwgIkMiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygwLDEsMikpDQoNCnRyYWluTSRXZWVrVHlwZSA8LSBmYWN0b3IodHJhaW5NJFdlZWtUeXBlLCBsZXZlbHMgPSBjKCJMb3ciLCAiTWVkaXVtIiwgIkhpZ2giKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygwLDEsMikpDQoNCnRyYWluTSRTdG9yZUdyb3VwIDwtIGZhY3Rvcih0cmFpbk0kU3RvcmVHcm91cCwgbGV2ZWxzID0gYygiTG93IiwgIk1lZGl1bSIsICJIaWdoIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygwLDEsMikpDQoNCmBgYA0KDQpVc2luZyBsZWFwcyBwYWNrYWdlLCB3ZSBjYW4gY2hlY2sgZm9yIGRpZmZlcmVudCBjb21iaW5hdGlvbnMgb2YgdGhlIGluZGVwZW5kZW50IHZhcmlhYmxlcyBhbmQgc2VsZWN0IHRoZSBiZXN0IGNvbWJpbmF0aW9uIG9uIHRoZSBiYXNpcyBvciBSLXNxIC8gQWRqdXN0ZWQgUi1zcS4gV2UgYXJlIHVzaW5nIEFkanVzdGVkIFItc3EgaGVyZS4NCg0KYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KIyBNb2RlbCBiYXNlZCBvbiBtb3JlIFZhcmlhYmxlcyAjDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCk1vZGVsX2Z1bGwgPC0gbG0oZm9ybXVsYSA9IFdlZWtseV9TYWxlc35UeXBlICsgVGVtcGVyYXR1cmUgKyBNYXJrRG93bjMgKyBNYXJrRG93bjUgKyBDUEkgKyBVbmVtcGxveW1lbnQgKyBTaXplICsgV2Vla1R5cGUgKyBTdG9yZUdyb3VwLCBkYXRhID0gdHJhaW5NKQ0Kc3VtbWFyeShNb2RlbF9mdWxsKQ0KDQpgYGANCg0KV2UgaGFkIG5vdGljZWQgdGhhdCBTaXplIG9mIHRoZSBTdG9yZSBpcyBoaWdoIG9uIGxhcmdlICYgU21hbGwgc2l6ZXMgYW5kIGZldyBpbiBiZXR3ZWVuIHdoaWNoIGlzIHByb2JhYmx5IGFkZGluZyB0byB0aGUgcG9zaXRpdmUgc2tld25lc3MuIEhlbmNlIHdlIHdpbGwgZnVydGhlciBlbmhhbmNlIHRoZSBjdXJyZW50IE1vZGVsIHdpdGggYSBsb2cgdHJhbnNmb3JtYXRpb24gb2YgU2l6ZS4NCg0KKlBvbHlub21pYWwgUmVncmVzc2lvbioNCg0KYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMgUG9seW5vbWlhbCBSZWdyZXNzaW9uIE1vZGVsICMNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCk1vZGVsX1AgPC0gbG0oZm9ybXVsYSA9IFdlZWtseV9TYWxlc35UeXBlICsgVGVtcGVyYXR1cmUgKyBNYXJrRG93bjMgKyBNYXJrRG93bjUgKyBDUEkgKyBVbmVtcGxveW1lbnQgKyBJKGxvZyhTaXplKSkgICsgV2Vla1R5cGUgKyBTdG9yZUdyb3VwLCBkYXRhID0gdHJhaW5NKQ0Kc3VtbWFyeShNb2RlbF9QKQ0KDQpgYGANCg0KIyMgUmVzaWR1YWwgQW5hbHlzaXMgDQoNCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMgUmVzaWR1YWwgQW5hbHlzaXMgIw0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQpwYXIobWZyb3c9YygzLDIpKQ0KcGxvdCh0cmFpbk0kVGVtcGVyYXR1cmUsIE1vZGVsX2Z1bGwkcmVzaWR1YWxzLCBwY2ggPSAyMCkNCnBsb3QodHJhaW5NJE1hcmtEb3duMywgTW9kZWxfZnVsbCRyZXNpZHVhbHMsIHBjaCA9IDIwKQ0KcGxvdCh0cmFpbk0kTWFya0Rvd241LCBNb2RlbF9mdWxsJHJlc2lkdWFscywgcGNoID0gMjApDQpwbG90KHRyYWluTSRDUEksIE1vZGVsX2Z1bGwkcmVzaWR1YWxzLCBwY2ggPSAyMCkNCnBsb3QodHJhaW5NJFNpemUsIE1vZGVsX2Z1bGwkcmVzaWR1YWxzLCBwY2ggPSAyMCkNCg0KYGBgDQoNCmBgYHtyfQ0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQojIENvbXBhcmFzaW9uIG9mIHRoZSBUd28gTW9kZWxzICMNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KcGxvdCh0cmFpbk0kU2l6ZSx0cmFpbk0kV2Vla2x5X1NhbGVzKQ0KcG9pbnRzKHRyYWluTSRTaXplLCBNb2RlbF9mdWxsJGZpdHRlZC52YWx1ZXMsIHBjaCA9IDIwLCBjb2w9ICdibHVlJykNCnBvaW50cyh0cmFpbk0kU2l6ZSwgTW9kZWxfUCRmaXR0ZWQudmFsdWVzLCBwY2ggPSAyMCwgY29sPSAnZ3JlZW4nKQ0KDQpgYGANCg0KYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCnBsb3QodHJhaW5NJFdlZWtseV9TYWxlcywgTW9kZWxfUCRyZXNpZHVhbHMsIHBjaCA9IDIwKQ0KYWJsaW5lKGggPSAwLCBjb2wgPSAiZ3JleSIpDQoNCmBgYA0KDQpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KcGxvdCh0cmFpbk0kV2Vla2x5X1NhbGVzLCBNb2RlbF9mdWxsJHJlc2lkdWFscywgcGNoID0gMjApDQphYmxpbmUoaCA9IDAsIGNvbCA9ICJncmV5IikNCg0KYGBgDQoNCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpxcW5vcm0oTW9kZWxfZnVsbCRyZXNpZHVhbHMpDQpxcWxpbmUoTW9kZWxfZnVsbCRyZXNpZHVhbHMpDQoNCmBgYA0KDQpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KcXFub3JtKE1vZGVsX1AkcmVzaWR1YWxzKQ0KcXFsaW5lKE1vZGVsX1AkcmVzaWR1YWxzKQ0KDQpgYGANCg0KKlRyYW5zZm9ybWF0aW9uKg0KDQpXZSBoYWQgb2JzZXJ2ZWQgaW4gRURBLCB0aGF0IFdlZWtseSBTYWxlcyBpcyBwb3NpdGl2ZWx5IHNrZXdlZC4gVGhlcmUgaXMgc3RpbGwgc2tld25lc3MgdG8gdGhlIHJpZ2h0IGFuZCBoZW5jZSB3ZSB3aWxsIHRyeSB0cmFuc2Zvcm1hdGlvbiBvbiB0aGUgcmVzcG9uc2UgdmFyaWFibGUuDQoNCiMgRmluYWxpemluZyBNb2RlbCB7LnRhYnNldH0NCg0KSW5pdGlhbGx5IHdlIHRyaWVkIFNxdWFyZSBSb290IHRyYW5zZm9ybWF0aW9uIGJ1dCBub3QgYSBtYWpvciBpbXByb3ZlbWVudCBpbiBza2V3bmVzcy4gDQoNCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpiY3ggPC0gYm94Y294KE1vZGVsX2Z1bGwpDQpwbG90KGJjeCkNCg0KYGBgDQoNClVzaW5nIEJveGNveCwgd2Ugc2VlIGxhbWJkYSBjbG9zZSB0byAwIGFuZCBoZW5jZSB1c2luZyBsb2cgdHJhbnNmb3JtYXRpb24uDQoNCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpNb2RlbFQgPC0gbG0oZm9ybXVsYSA9IGxvZyhXZWVrbHlfU2FsZXMpflNpemUrVGVtcGVyYXR1cmUgKyBNYXJrRG93bjMgKyBNYXJrRG93bjUgKyBDUEkgKyBXZWVrVHlwZSArIFN0b3JlR3JvdXAsIGRhdGEgPSB0cmFpbk0pDQpzdW1tYXJ5KE1vZGVsVCkNCg0KYGBgDQoNCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpwbG90KHRyYWluTSRXZWVrbHlfU2FsZXMsIE1vZGVsVCRyZXNpZHVhbHMsIHBjaCA9IDIwKQ0KYWJsaW5lKGggPSAwLCBjb2wgPSAiZ3JleSIpDQoNCmBgYA0KDQpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KcXFub3JtKE1vZGVsVCRyZXNpZHVhbHMpDQpxcWxpbmUoTW9kZWxUJHJlc2lkdWFscykNCg0KYGBgDQoNCldpdGggdGhpcywgd2UgaGF2ZSBidWlsZCBvdXIgZmluYWwgTW9kZWw6IE1vZGVsIHdpdGggYW4gYWRqdXN0ZWQgUi1zcSA9IDg4LjI0IGFuZCBhbGwgdmFyaWFibGVzIGFyZSBoaWdobHkgc2lnbmlmaWNhbnQuDQoNCiMgUHJlZGljdGlvbiBVc2luZyB0aGUgRml0IE1vZGVsIHsudGFic2V0fQ0KDQpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KdHJhaW5NJFByZWRpY3Rpb24gPC0gZXhwKE1vZGVsVCRmaXR0ZWQudmFsdWVzKQ0KdHJhaW5NMjAxMSA8LSB0cmFpbk0gJT4lIGZpbHRlcihZZWFyID09IDIwMTEpICU+JSBncm91cF9ieShXZWVrKSAlPiUgDQogIHN1bW1hcml6ZShXZWVrbHlTYWxlcyA9IHN1bShXZWVrbHlfU2FsZXMpLCBXZWVrbHlQcmVkaWN0aW9uID0gc3VtKFByZWRpY3Rpb24pKQ0KcGxvdCh4ID0gdHJhaW5NMjAxMSRXZWVrLCB5ID0gdHJhaW5NMjAxMSRXZWVrbHlTYWxlcywgY29sID0gJ1JlZCcsIG1haW4gPSJBY3R1YWwgdnMgUHJlZGljaXRvbiIsIHhsYWIgPSAiV2VlayIsIHlsYWIgPSAiV2Vla2x5IFNhbGVzIikNCmxpbmVzKHggPSB0cmFpbk0yMDExJFdlZWssIHkgPSB0cmFpbk0yMDExJFdlZWtseVByZWRpY3Rpb24sIGNvbCA9ICdibHVlJykNCg0KYGBgDQoNCiMgRXZhbHVhdGlvbiBvZiBNb2RlbCBieSBUZXN0IERhdGEgey50YWJzZXR9DQoNCkRvaW5nIHRoZSBwcmVkaWN0aW9uIHVzaW5nIHRoZSBUZXN0IERhdGEgc2V0LCBXZSBnb3QgdmVyeSBnb29kIHByZWRpY3Rpb25zIGFuZCBwcmV0dHkgY2xvc2VyIHdpdGggdGhlIHJlYWwgdmFsdWVzLiANCg0KYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCnRlc3RNJFR5cGUgPC0gZmFjdG9yKHRlc3RNJFR5cGUsIGxldmVscyA9IGMoIkEiLCAiQiIsICJDIiksDQogICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygwLDEsMikpDQp0ZXN0TSRXZWVrVHlwZSA8LSBmYWN0b3IodGVzdE0kV2Vla1R5cGUsIGxldmVscyA9IGMoIkxvdyIsICJNZWRpdW0iLCAiSGlnaCIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKDAsMSwyKSkNCnRlc3RNJFN0b3JlR3JvdXAgPC0gZmFjdG9yKHRlc3RNJFN0b3JlR3JvdXAsIGxldmVscyA9IGMoIkxvdyIsICJNZWRpdW0iLCAiSGlnaCIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoMCwxLDIpKQ0KcHJlZCA8LSBwcmVkaWN0KE1vZGVsVCwgbmV3ZGF0YSA9IHRlc3RNLCBpbnRlcnZhbCA9IGMoJ2NvbmZpZGVuY2UnKSwgbGV2ZWwgPSAwLjk1LCB0eXBlID0gJ3Jlc3BvbnNlJykNCnRlc3RNJFByZWRpY3Rpb24gPC0gZXhwKHByZWRbLCAyXSkNCnRlc3RNU3VtIDwtIHRlc3RNICU+JSAgZ3JvdXBfYnkoV2VlaykgJT4lIA0KICBzdW1tYXJpemUoV2Vla2x5U2FsZXMgPSBzdW0oV2Vla2x5X1NhbGVzKSwgV2Vla2x5UHJlZGljdGlvbiA9IHN1bShQcmVkaWN0aW9uKSkNCnBsb3QoeCA9IHRlc3RNU3VtJFdlZWssIHkgPSB0ZXN0TVN1bSRXZWVrbHlTYWxlcywgY29sID0gJ1JlZCcsIG1haW4gPSAiQWN0dWFsIHZzIFByZWRpY3Rpb24gLSBUZXN0aW5nIERhdGEiLCB4bGFiID0gIldlZWtzIiwgeWxhYiA9ICJXZWVrbHkgU2FsZXMiKQ0KbGluZXMoeCA9IHRlc3RNU3VtJFdlZWssIHkgPSB0ZXN0TVN1bSRXZWVrbHlQcmVkaWN0aW9uLCBjb2wgPSAnYmx1ZScpDQoNCmBgYA0KDQpGb3Igd2hvbGUgZGF0YSBzZXQuIA0KDQpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KcHJlZF9mb3JlY3N0IDwtIHByZWRpY3QoTW9kZWxULCBoPTEwLCBpbnRlcnZhbCA9IGMoJ2NvbmZpZGVuY2UnKSwgbGV2ZWwgPSAwLjk1LCB0eXBlID0gJ3Jlc3BvbnNlJykNCnByZWRfZm9yZWNzdCA8LSBleHAocHJlZF9mb3JlY3N0KQ0KcGFyKG1mcm93ID0gYygxLDEpKQ0KcGxvdCh0cmFpbk0kV2Vla2x5X1NhbGVzLCB0eXBlPSdsJywgDQogICAgIHhsaW09YygyMDExLDIwMTQpLCB4bGFiID0gJ1dlZWtzJywgeWxhYiA9ICdXZWVrbHkgU2FsZXMnKQ0KbGluZXMocHJlZF9mb3JlY3N0WywyXSAsY29sPSdibHVlJykNCmxpbmVzKHByZWRfZm9yZWNzdFssM10sY29sPSdvcmFuZ2UnKQ0KbGluZXMocHJlZF9mb3JlY3N0WywxXSxjb2w9J29yYW5nZScpDQoNCmBgYA0KDQojIEZvcmVjYXN0aW5nIHsudGFic2V0fQ0KDQoqT3RoZXIgTW9kZWxzKg0KDQpVc2luZyBub3cgdGhlIHRzIGRhdGEgZnJhbWUuIA0KDQpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMgSW1wb3J0IExpYnJhcmllcyAjDQojIyMjIyMjIyMjIyMjIyMjIyMjIw0KbGlicmFyeShmb3JlY2FzdCkNCmxpYnJhcnkodGltZURhdGUpDQpsaWJyYXJ5KHJhbmRvbUZvcmVzdCkNCg0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQojIFJlYWRpbmcgdGhlIEZpbGVzICMNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KZmVhdHVyZXMgPC0gcmVhZC5jc3YoImZlYXR1cmVzLmNzdiIpDQpzYWxlcyA8LSByZWFkLmNzdigic2FsZXMuY3N2IikNCnN0b3JlcyA8LSByZWFkLmNzdigic3RvcmVzLmNzdiIpDQoNCiMjIyMjIyMjIyMjIyMjIyMjIyMNCiMgQ29udmVydCB0byBEYXRlICMNCiMjIyMjIyMjIyMjIyMjIyMjIyMNCmZlYXR1cmVzJERhdGUgPC0gYXMuRGF0ZShmZWF0dXJlcyREYXRlLCBmb3JtYXQgPSAiJWQvJW0vJVkiKQ0KDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQojIENyZWF0aW5nIFdlZWtseSBTYWxlcyAjDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQpzYWxlcyA8LSBzYWxlcyAlPiUgDQogIGdyb3VwX2J5KFN0b3JlLCBEYXRlLCBJc0hvbGlkYXkpICU+JSANCiAgc3VtbWFyaXplKFdlZWtseV9TYWxlcyA9IHN1bShXZWVrbHlfU2FsZXMpKQ0Kc2FsZXMkRGF0ZSA8LSBhcy5EYXRlKHNhbGVzJERhdGUsIGZvcm1hdCA9ICIlZC8lbS8lWSIpDQoNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQojIE1lcmdlIHRoZSBEYXRhIFNldHMgIw0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCnNhbGVzTSA8LSBtZXJnZShzYWxlcyxmZWF0dXJlcykNCnNhbGVzTSA8LSBtZXJnZShzYWxlc00sIHN0b3JlcywgYnkgPSAiU3RvcmUiKQ0KDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KIyBTdWJzZXQgd2l0aCBubyBOQSdzIE1hcmtkb3duICMNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQpzdWJzZXRfZGF0YSA8LSBzdWJzZXQoc2FsZXNNLCBzYWxlc00kRGF0ZSA+IGFzLkRhdGUoIjIwMTEtMTEtMSIpICYNCiAgICAgICAgICAgICAgICAgICAgICAgIHNhbGVzTSREYXRlIDwgYXMuRGF0ZSgiMjAxMy0wNy0yNiIpKQ0KDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMgcGxvdHRpbmcgdGltZXMgZXJpZXMgIw0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQpkYXRhc2V0X3RzID0gdHMoc3Vic2V0X2RhdGEkV2Vla2x5X1NhbGVzLCBmcmVxdWVuY3k9NTIsIA0KICAgICAgICAgICAgICAgICAgICAgICBzdGFydCA9IGMoMjAxMSwxMSksIGVuZCA9IGMoMjAxMyw1KSkNCnBsb3QoZGF0YXNldF90cykNCg0KIyBicmVha2luZyBpbnRvIHRyYWluaW5nIGFuZCB2YWxpZGF0aW9uDQp0cmFpbl9zdG9yZTEgPSBoZWFkKHN1YnNldF9kYXRhICwgMjAwMCkNCnRlc3Rfc3RvcmUxICA9IHRhaWwoc3Vic2V0X2RhdGEgLCBucm93KHN1YnNldF9kYXRhKSAtIG5yb3codHJhaW5fc3RvcmUxKSkNCnRyYWluX3N0b3JlMV90cyA9IHRzKHRyYWluX3N0b3JlMSRXZWVrbHlfU2FsZXMsIGZyZXF1ZW5jeT01MiwgDQogICAgICAgICAgICAgICAgICAgICBzdGFydCA9IGMoMjAxMSwxMSksIGVuZCA9IGMoMjAxMyw2KSkNCg0KIyBNb2RlbCAtIFNlYXNvbmFsIE5haXZlIE1vZGVsICMgVGhlIEJlc3QNCnRyYWluX3N0b3JlMV9zbmFpdmUgPSBzbmFpdmUodHJhaW5fc3RvcmUxX3RzLCBoID0gbnJvdyh0cmFpbl9zdG9yZTEpKQ0KdHJhaW5fc3RvcmUxX3NuYWl2ZV9mb3JlY2FzdCA9IGZvcmVjYXN0KHRyYWluX3N0b3JlMV9zbmFpdmUsIGggPSAxNSkNCnBsb3QodHJhaW5fc3RvcmUxX3NuYWl2ZV9mb3JlY2FzdCkNCg0KIyBNb2RlbCA2IDogQVJJTUENCnRyYWluX3N0b3JlMV9hdXRvQXJpbWEgPSBhdXRvLmFyaW1hKHRyYWluX3N0b3JlMV90cykNCnRyYWluXzFfMV90c19hdXRvQXJpbWFfZmMgPSBmb3JlY2FzdCh0cmFpbl9zdG9yZTFfYXV0b0FyaW1hLCBoID0gMTUpDQpwbG90KHRyYWluXzFfMV90c19hdXRvQXJpbWFfZmMpDQoNCmBgYA0KDQojIENvbnNsdXNpb24gey50YWJzZXR9DQoNCldlIHdlcmUgYWJsZSB0byBidWlsZCB0aGlzIG1vZGVsIHdpdGggQWRqdXN0ZWQgUi1zcSA9IDg4JSBhbmQgUHJlZGljdGVkIFItU3EgPSA4OCUuIFRoZSB2YXJpYWJsZXMg4oCcU3RvcmUgR3JvdXDigJ0gJiDigJxXZWVrIFR5cGXigJ0gY29uc3RydWN0ZWQgZnJvbSB0aGUgZGF0YSBzZXQgYXJlIHRoZSBtb3N0IHNpZ25pZmljYW50IHZhcmlhYmxlcy4gV2l0aCB0aGlzIE1vZGVsLCB3ZSBjYW4gcHJlZGljdCBhIGdvb2QgZXN0aW1hdGUgb2YgdGhlIHdlZWtseSBTYWxlcyBmb3IgU3RvcmVzLg0KDQojIEV4dHJhOiBQaXZvdCBUYWJsZQ0KDQpXaXRoIHRoaXMgYFBpdm90IFRhYmxlYCBXZSBjYW4gbWFuaXB1bGF0ZSBhbmQgc2VlIHRoZSBkaXN0cmlidXRpb24gZm9yIHdoYXRldmVyIHZhcmlhYmxlcyBjb21iaW5hdGlvbi4gSXTCtHMgdG90YWxseSBpbnRlcmFjdGl2ZSBQaXZvdCBUYWJsZS4gV2UgY2FuIGRyYWcgdGhlIHZhcmlhYmxlcyB0byB0aGUgY29sdW1ucyBvciByb3dzLCBjaG9vc2UgdGhlIGNhdGVnb3JpZXMsIG1ha2UgZmlsdGVycywgY2hvb3NlIHdoaWNoIG1ldHJpY3Mgb3IgZ3JhcGhzLg0KDQpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQojIEltcG9ydCB0aGUgTGlicmFyaWVzICMNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KbGlicmFyeShycGl2b3RUYWJsZSkNCmxpYnJhcnkoZGF0YS50YWJsZSkNCg0KcnBpdm90VGFibGUoc2V0RFQocGl2b3RfdGFibGUpLA0KICAgICAgICAgICAgY29scz0gIlllYXIiLA0KICAgICAgICAgICAgcm93cyA9ICJXZWVrVHlwZSIsDQogICAgICAgICAgICByZW5kZXJlck5hbWUgPSAiSGVhdG1hcCIpDQpgYGANCg0KDQo=