For the review, We will use “EuroStore” data set (same data set in Lab 10)- THIS IS NOT THE DATA SET WE WILL USE IN THE EXAM. THE DATA WE WILL USE FOR EXAM 3 IS UPLOADED TO SAKAI IN FOLDER “EXAM_3”>> “DATA_FOR_EXAM_3.ZIP”. This review will be used as examples for questions that could be asked in the exam. THE EXAM WILL INCLUDE ADDITIONAL QUESTIONS THAT ARE NOT DISCUSSED HERE AS WELL. PLEASE READ EVERYTHING IN SLIDES, ASSIGNMENTS, AND CLASS NOTES.

IMPORTANT: In the exam, you will have the questions on paper. It will not be in R studio. Therefore, you will have to create a new R Notebook to do your calculations. In order to do that, you click on file>>new file>> R Notebook >> then save the R notebook in the folder where you have the data for exam_3 >> then set your working directory to source file

1- Calculate signal to noise ratio for “Sales” column; does this data have high / low potential for noise? Explain your answer. (USE TRAINING DATA SET “EuroStore_Train.csv”)

# first you set working direcotry to source file
# then we should read the data 
store_data = read.csv(file = "EuroStore_Train.csv")
head(store_data) # you did this to see that data looks good in R studio
#then we need to read the "Sales" column 
sales_train = store_data$Sales
# snr = mean / sd 
mean_sales_train = mean(sales_train)
sd_sales_train = sd(sales_train)
snr_sales_train = mean_sales_train/sd_sales_train
snr_sales_train

the signal to noise ration is 9.145139. In the exam you have to show your calculations (i.e. the snr formula, the mean, the sd, and the snr value. don’t just write a number) It seems that it has low potential for noise because Snr is much higher than 1.

2- Do we have outliers in “Fuel Volume”? If yes, list those outliers; show your calculations (USE TRAINING DATA SET “EuroStore_Train.csv”)

#first you need to decide on the method. As you know we have two methods. I will pick mean+-3*sd

# we ened to read the column 
fuel_vol_train = store_data$Fuel.Volume
mean_fuel_vol_train = mean(fuel_vol_train)
sd_fuel_vol_train = sd(fuel_vol_train)

upper_threshold = mean_fuel_vol_train+3*sd_fuel_vol_train
upper_threshold
lower_threshold = mean_fuel_vol_train - 3*sd_fuel_vol_train
lower_threshold

Upper threshold = 69660.98, lower threshold = 56443.82. open the EuroStore_Train.csv, and see if any of the fuel volume values is outside the range 56443.82 to 69660.98. You will not find any; therefore, you can say that we don’t have outliers (remember, show your calcualtions i.e. upper limit, lower limit, formulas, and reasoning)

3- This week TV GRP = 182, Radio GRP = 190. Calculate the corresponding z-value or z-score. If we want to compare this week’s GRP with GRP values in the data set for both TV and Radio commercials (i.e. comparing this week’s TV GRP with TV GRP values in the data set, and comparing this week’s Radio GRP with Radio GRP values in the data set ), which of the commercials did better, TV or Radio? (USE TRAINING DATA SET “EuroStore_Train.csv”)

# we need to read the data
tv_train = store_data$TV
radio_train = store_data$Radio

# the z score formula is z = (X-mean)/sd, where X is the value we are calculating the z score for.
mean_tv_train = mean(tv_train)
sd_tv_train = sd(tv_train)
z_tv = (182-mean_tv_train) / sd_tv_train
z_tv

mean_radio_train = mean(radio_train)
sd_radio_train = sd(radio_train)
z_radio = (190-mean_radio_train)/sd_radio_train
z_radio

z score for TV GRP = 182 is 1.949604, and z score for Radio GRP = 190 is 1.310603.

How do I know which of the commercials did better this week? The question asks you to compare this week’s TV GRP with TV GRP values in the data set, and compare this week’s Radio GRP with Radio GRP values in the data set, and then decide which of the commercials did better. Actually the z scores will help a lot. Z score is the number of standard deviations the value is away from the mean. We know that 180 is 1.949604 away from the mean of TV GRP’s in the data set, and that 190 is 1.310603 standard deviations away from the mean of Radio GRP’s in the data set. As a result, this week the TV commercials did better this week comparing to hestorical values.

4- You need to create a predictive model that predicts sales. You will create the model using the training data set, and then test it using the testing data set.

4.A Calculate different correlation factors and list by order the most potential pedictive variables, execlude week and holiday.(USE TRAINING DATA SET “EuroStore_Train.csv”)

# here we will claculate the correlation coefficient between sales and all other varaibles in the data set 

cor(store_data)

you need to look at the correlation values in the table and rank the predictive varaibles accordingly. Based on the results we can see that the order is as the following (the first is the most potential predicitve variable, and the last is the least potential)

1- Temprature 2- Fuel Volume 3- Fuel Price 4- Radio 5- TV

(side note: remember that this is not enough to say that temprature, or fuel volume are good predcitors. You need to create models and test them; we can’t rely on correaltion coefficient only)

4.B The manager of the marekting department requested that you evaluate two models that predcits sales. Model_1 uses temprature and fuel price as predcitors, and Model_2 uses fuel volume and radio as predciotrs.

You need to evaluate the two models and show which one is the best.

First part of questions (models creation) :you need to create the two models using the training data set, and test them using the testing data set. After you create them using the training data set, you need to write the equations for the two models, explain the coefficients of the equation, and write the Rsquare and adjusted R square values. You need to compare the two models based on the training data set results using the R squared and adjusted R squared values.

Second part of question (models testing, evaluation, and selection): For the testing you need to compare the RMSE values for each model; also you can plot the predcited values vs actual values and compare (you don’t need to draw any plot on the exam paper; this is for you to have better insights on the best model).You also need to compare the two models based on the testing data set results i.e. based on RMSE (for this question You need to use both the training data set “EuroStore_Train.csv” and the testing data set “EuroStore_Test.csv”)

# let us start by creating the two models
# we already extracted the sales, fuel volume, Tv, and radio from training data set. we need to extract the temprature and fuel price 

temp_train = store_data$Temp
fuel_p_train = store_data$Fuel.Price
# now we can create the first model 
model_1 = lm (sales_train~temp_train+fuel_p_train)
summary(model_1)
# we can also create the second model
model_2 = lm (sales_train~fuel_vol_train+radio_train)
summary(model_2)

From the summary results you can asnwer the first part of the question

Model_1 Equation: Sales = -6761.09 + 204.36 * temprature + 234.78 * fuel price Coefficients: if temprature and price are both equal to zero the sales will be -6761.09 i.e. we will lose money. If temprature is increased by 1, the sales will increase by 204.36, and if fuel price is increased by 1, the sales will increase by 234.78. R squared = 0.6339, Adjusted R-squared = 0.6198

Model_2 Equation: Sales = -1.350e+04 + 5.627e-01* Fuel Vol + 9.481e+00 *radio coefficients: if fuel volume and radio are both equal to zero the sales will be -1.350e+04 i.e. we will lose money. If fuel volume is increased by 1, the sales will increase by 5.627e-01, and if radio is increased by 1, the sales will increase by 9.481e+00. R-squared: 0.4987, Adjusted R-squared: 0.4794

Based on these results, you can see that model_1 could be better (it has a higher R square and adjusted R square); however, we need to test the two models first before making the decision on which one is the best; remember that a model could be over-fitted to the training data set and do badly on testing data set. We don’t like such model; we need a model that does well on both training and testing.

# let us test the two models
# first we need to read the testing data set
store_data_2 = read.csv(file = "EuroStore_Test.csv")
head(store_data_2)
# we need to read the columns 
sales_test = store_data_2$Sales
temp_test = store_data_2$Temp
fuel_p_test = store_data_2$Fuel.Price
fuel_vol_test = store_data_2$Fuel.Volume
radio_test = store_data_2$Radio
# we will now run the two models on the testing data set and calculate the predicted values of sales. 
#We have two models, so we will have two vectors of predcited values for sales. We will compare the two vectors of predcited values for sales with the actual values for sales in the testing data set (this is what is called testing)

sales_predict_model_1 = coef(model_1)[1]+coef(model_1)[2]*temp_test+coef(model_1)[3]*fuel_p_test

plot(sales_predict_model_1,sales_test)
mse_model_1 = sum((sales_predict_model_1-sales_test)^2)/length(sales_test)
rmse_model_1 =sqrt(mse_model_1)
rmse_model_1

the rmse of model_1 is 3089.406. The plot shows not much correlation between actual sales and predicted sales. However, we can’t assess until we see results of model_2

sales_predict_model_2 = coef(model_2)[1]+coef(model_2)[2]*fuel_vol_test+coef(model_2)[3]*fuel_p_test

plot(sales_predict_model_2,sales_test)
mse_model_2 = sum((sales_predict_model_2-sales_test)^2)/length(sales_test)
rmse_model_2 =sqrt(mse_model_2)
rmse_model_2

the rmse of model_2 is 1870.863, much better than rmse of model_1. Also, looking at the plot of model_2, we will see better correaltion between predcited values and actual values.

As a result, I can say that model_2 is a better model. Although model_1 had higher R squared and Adjusted R squared in training data set, when we introduced the testing data set, model 2 had more accuracy.

  1. After you select your best predictive model, you have to formulate and solve the linear optimization problem. Your goal is to select the optimal values for the two predictors in order to optimize sales. Assume that maximum capacity of the fuel station is 90000, maximum Radio GRP is 30000,and every increase in Radio GRP by 1 leads to sales of at least 10 liters of fuel.Also,

Formulate the problem, identify decision valriables, solve the problem, identify binidng and none-binidng cosntraints, and calculate slack and surplus.

Based on the analysis, you will find that model_2 is the best, so we will use it to solve this question. The goal is to find the optimal fuel volume, and optimal radio GRP to maximize sales

Formulation: decision variables X1 = Fuel volume, X2 = Radio

Obj Max Sales = 5.627e-01* X1 + 9.481e+00 X2 Sub to X1 <= 90000 X2<= 30000 X1-10X2 >= 0 X1 >= 0 X2 >= 0

In order to solve, we need to download LpSolverAPI package

# we first need to downlaod the package to solve linear optimization problem 

if(!require("lpSolveAPI",quietly = TRUE))
  install.packages("lpSolveAPI",dependencies = TRUE, repos = "https://cloud.r-project.org")

now we can use the package to solve

lpSales <- make.lp(0, 2) 
dump = lp.control(lpSales, sense="max")  
# Set the objective function.

set.objfn(lpSales, c(5.627e-01, 9.481e+00))

# add constraints
add.constraint(lpSales, c(1,0 ), "<=", 90000)
add.constraint(lpSales, c(0,1), "<=", 30000)
add.constraint(lpSales, c(1,-10), ">=", 0)
add.constraint(lpSales, c(1,0 ), ">=", 0)
add.constraint(lpSales, c(0,1), ">=", 0)
# View the problem formulation in tabular/matrix form
lpSales

# Solve 
solve(lpSales) 

# Display the objective function optimum value
get.objective(lpSales)

# Display the decision variables optimum values
get.variables(lpSales) 

Solution: X 1 = 90000, X2 = 9000, Sales = 135972

get.sensitivity.rhs(lpSales)

First constraint is binding becuase marginal value =1.5108 <> 0, an increase in the right hand side of the contraint by 1 (if capacity of fuel station icnreases by 1) will increase optimal sales by 1.5108

Third constraint is binding because marginal value = -0.9481 <> 0, if the right hand side of the constraint is increased by 1, the optimal sales will decreases by -0.9481

All other constraints are non-binding becuase they have marginal value = 0

For surplus and slack, I will do it for second constraint only: Second constraint is non-binding and has <=, so it has slack (if it has >= then it has surplus) Second constraint is X2 <= 30000 Optimal solution for X2 = 9000, the slack = 30000-9000 = 21000

  1. Create a quadratic regression model to predict sales based on temprature (use training data set)

Try to solve this on your own, and send me questions

LS0tCnRpdGxlOiAiUmV2aWV3X0ZpbmFsIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgojIyMgRm9yIHRoZSByZXZpZXcsIFdlIHdpbGwgdXNlICJFdXJvU3RvcmUiIGRhdGEgc2V0IChzYW1lIGRhdGEgc2V0IGluIExhYiAxMCktIFRISVMgSVMgTk9UIFRIRSBEQVRBIFNFVCBXRSBXSUxMIFVTRSBJTiBUSEUgRVhBTS4gVEhFIERBVEEgV0UgV0lMTCBVU0UgRk9SIEVYQU0gMyBJUyBVUExPQURFRCBUTyBTQUtBSSBJTiBGT0xERVIgIkVYQU1fMyI+PiAiREFUQV9GT1JfRVhBTV8zLlpJUCIuIFRoaXMgcmV2aWV3IHdpbGwgYmUgdXNlZCBhcyBleGFtcGxlcyBmb3IgcXVlc3Rpb25zIHRoYXQgY291bGQgYmUgYXNrZWQgaW4gdGhlIGV4YW0uIFRIRSBFWEFNIFdJTEwgSU5DTFVERSBBRERJVElPTkFMIFFVRVNUSU9OUyBUSEFUIEFSRSBOT1QgRElTQ1VTU0VEIEhFUkUgQVMgV0VMTC4gUExFQVNFIFJFQUQgRVZFUllUSElORyBJTiBTTElERVMsIEFTU0lHTk1FTlRTLCBBTkQgQ0xBU1MgTk9URVMuIAoKIyMjIElNUE9SVEFOVDogSW4gdGhlIGV4YW0sIHlvdSB3aWxsIGhhdmUgdGhlIHF1ZXN0aW9ucyBvbiBwYXBlci4gSXQgd2lsbCBub3QgYmUgaW4gUiBzdHVkaW8uIFRoZXJlZm9yZSwgeW91IHdpbGwgaGF2ZSB0byBjcmVhdGUgYSBuZXcgUiBOb3RlYm9vayB0byBkbyB5b3VyIGNhbGN1bGF0aW9ucy4gSW4gb3JkZXIgdG8gZG8gdGhhdCwgeW91IGNsaWNrIG9uIGZpbGU+Pm5ldyBmaWxlPj4gUiBOb3RlYm9vayA+PiB0aGVuIHNhdmUgdGhlIFIgbm90ZWJvb2sgaW4gdGhlIGZvbGRlciB3aGVyZSB5b3UgaGF2ZSB0aGUgZGF0YSBmb3IgZXhhbV8zID4+IHRoZW4gc2V0IHlvdXIgd29ya2luZyBkaXJlY3RvcnkgdG8gc291cmNlIGZpbGUKCiMxLSBDYWxjdWxhdGUgc2lnbmFsIHRvIG5vaXNlIHJhdGlvIGZvciAiU2FsZXMiIGNvbHVtbjsgZG9lcyB0aGlzIGRhdGEgaGF2ZSBoaWdoIC8gbG93IHBvdGVudGlhbCBmb3Igbm9pc2U/IEV4cGxhaW4geW91ciBhbnN3ZXIuIChVU0UgVFJBSU5JTkcgREFUQSBTRVQgIkV1cm9TdG9yZV9UcmFpbi5jc3YiKQoKYGBge3J9CiMgZmlyc3QgeW91IHNldCB3b3JraW5nIGRpcmVjb3RyeSB0byBzb3VyY2UgZmlsZQojIHRoZW4gd2Ugc2hvdWxkIHJlYWQgdGhlIGRhdGEgCnN0b3JlX2RhdGEgPSByZWFkLmNzdihmaWxlID0gIkV1cm9TdG9yZV9UcmFpbi5jc3YiKQpoZWFkKHN0b3JlX2RhdGEpICMgeW91IGRpZCB0aGlzIHRvIHNlZSB0aGF0IGRhdGEgbG9va3MgZ29vZCBpbiBSIHN0dWRpbwoKYGBgCgpgYGB7cn0KI3RoZW4gd2UgbmVlZCB0byByZWFkIHRoZSAiU2FsZXMiIGNvbHVtbiAKc2FsZXNfdHJhaW4gPSBzdG9yZV9kYXRhJFNhbGVzCiMgc25yID0gbWVhbiAvIHNkIAptZWFuX3NhbGVzX3RyYWluID0gbWVhbihzYWxlc190cmFpbikKc2Rfc2FsZXNfdHJhaW4gPSBzZChzYWxlc190cmFpbikKc25yX3NhbGVzX3RyYWluID0gbWVhbl9zYWxlc190cmFpbi9zZF9zYWxlc190cmFpbgpzbnJfc2FsZXNfdHJhaW4KCmBgYAoKdGhlIHNpZ25hbCB0byBub2lzZSByYXRpb24gaXMgOS4xNDUxMzkuIEluIHRoZSBleGFtIHlvdSBoYXZlIHRvIHNob3cgeW91ciBjYWxjdWxhdGlvbnMgKGkuZS4gdGhlIHNuciBmb3JtdWxhLCB0aGUgbWVhbiwgdGhlIHNkLCBhbmQgdGhlIHNuciB2YWx1ZS4gZG9uJ3QganVzdCB3cml0ZSBhIG51bWJlcikKSXQgc2VlbXMgdGhhdCBpdCBoYXMgbG93IHBvdGVudGlhbCBmb3Igbm9pc2UgYmVjYXVzZSBTbnIgaXMgbXVjaCBoaWdoZXIgdGhhbiAxLgoKIzItIERvIHdlIGhhdmUgb3V0bGllcnMgaW4gIkZ1ZWwgVm9sdW1lIj8gSWYgeWVzLCBsaXN0IHRob3NlIG91dGxpZXJzOyBzaG93IHlvdXIgY2FsY3VsYXRpb25zIChVU0UgVFJBSU5JTkcgREFUQSBTRVQgIkV1cm9TdG9yZV9UcmFpbi5jc3YiKQoKYGBge3J9CiNmaXJzdCB5b3UgbmVlZCB0byBkZWNpZGUgb24gdGhlIG1ldGhvZC4gQXMgeW91IGtub3cgd2UgaGF2ZSB0d28gbWV0aG9kcy4gSSB3aWxsIHBpY2sgbWVhbistMypzZAoKIyB3ZSBlbmVkIHRvIHJlYWQgdGhlIGNvbHVtbiAKZnVlbF92b2xfdHJhaW4gPSBzdG9yZV9kYXRhJEZ1ZWwuVm9sdW1lCm1lYW5fZnVlbF92b2xfdHJhaW4gPSBtZWFuKGZ1ZWxfdm9sX3RyYWluKQpzZF9mdWVsX3ZvbF90cmFpbiA9IHNkKGZ1ZWxfdm9sX3RyYWluKQoKdXBwZXJfdGhyZXNob2xkID0gbWVhbl9mdWVsX3ZvbF90cmFpbiszKnNkX2Z1ZWxfdm9sX3RyYWluCnVwcGVyX3RocmVzaG9sZApsb3dlcl90aHJlc2hvbGQgPSBtZWFuX2Z1ZWxfdm9sX3RyYWluIC0gMypzZF9mdWVsX3ZvbF90cmFpbgpsb3dlcl90aHJlc2hvbGQKYGBgCgpVcHBlciB0aHJlc2hvbGQgPSA2OTY2MC45OCwgbG93ZXIgdGhyZXNob2xkID0gNTY0NDMuODIuIG9wZW4gdGhlIEV1cm9TdG9yZV9UcmFpbi5jc3YsIGFuZCBzZWUgaWYgYW55IG9mIHRoZSBmdWVsIHZvbHVtZSB2YWx1ZXMgaXMgb3V0c2lkZSB0aGUgcmFuZ2UgNTY0NDMuODIgdG8gNjk2NjAuOTguIFlvdSB3aWxsIG5vdCBmaW5kIGFueTsgdGhlcmVmb3JlLCB5b3UgY2FuIHNheSB0aGF0IHdlIGRvbid0IGhhdmUgb3V0bGllcnMgKHJlbWVtYmVyLCBzaG93IHlvdXIgY2FsY3VhbHRpb25zIGkuZS4gdXBwZXIgbGltaXQsIGxvd2VyIGxpbWl0LCBmb3JtdWxhcywgYW5kIHJlYXNvbmluZykKCiMzLSBUaGlzIHdlZWsgVFYgR1JQID0gMTgyLCBSYWRpbyBHUlAgPSAxOTAuIENhbGN1bGF0ZSB0aGUgY29ycmVzcG9uZGluZyB6LXZhbHVlIG9yIHotc2NvcmUuIElmIHdlIHdhbnQgdG8gY29tcGFyZSB0aGlzIHdlZWsncyBHUlAgd2l0aCBHUlAgdmFsdWVzIGluIHRoZSBkYXRhIHNldCBmb3IgYm90aCBUViBhbmQgUmFkaW8gY29tbWVyY2lhbHMgKGkuZS4gY29tcGFyaW5nIHRoaXMgd2VlaydzIFRWIEdSUCB3aXRoIFRWIEdSUCB2YWx1ZXMgaW4gdGhlIGRhdGEgc2V0LCBhbmQgY29tcGFyaW5nIHRoaXMgd2VlaydzIFJhZGlvIEdSUCB3aXRoIFJhZGlvIEdSUCB2YWx1ZXMgaW4gdGhlIGRhdGEgc2V0ICksIHdoaWNoIG9mIHRoZSBjb21tZXJjaWFscyBkaWQgYmV0dGVyLCBUViBvciBSYWRpbz8gKFVTRSBUUkFJTklORyBEQVRBIFNFVCAiRXVyb1N0b3JlX1RyYWluLmNzdiIpCgpgYGB7cn0KIyB3ZSBuZWVkIHRvIHJlYWQgdGhlIGRhdGEKdHZfdHJhaW4gPSBzdG9yZV9kYXRhJFRWCnJhZGlvX3RyYWluID0gc3RvcmVfZGF0YSRSYWRpbwoKIyB0aGUgeiBzY29yZSBmb3JtdWxhIGlzIHogPSAoWC1tZWFuKS9zZCwgd2hlcmUgWCBpcyB0aGUgdmFsdWUgd2UgYXJlIGNhbGN1bGF0aW5nIHRoZSB6IHNjb3JlIGZvci4KbWVhbl90dl90cmFpbiA9IG1lYW4odHZfdHJhaW4pCnNkX3R2X3RyYWluID0gc2QodHZfdHJhaW4pCnpfdHYgPSAoMTgyLW1lYW5fdHZfdHJhaW4pIC8gc2RfdHZfdHJhaW4Kel90dgoKbWVhbl9yYWRpb190cmFpbiA9IG1lYW4ocmFkaW9fdHJhaW4pCnNkX3JhZGlvX3RyYWluID0gc2QocmFkaW9fdHJhaW4pCnpfcmFkaW8gPSAoMTkwLW1lYW5fcmFkaW9fdHJhaW4pL3NkX3JhZGlvX3RyYWluCnpfcmFkaW8KYGBgCnogc2NvcmUgZm9yIFRWIEdSUCA9IDE4MiBpcyAxLjk0OTYwNCwgYW5kIHogc2NvcmUgZm9yIFJhZGlvIEdSUCA9IDE5MCBpcyAxLjMxMDYwMy4gCgpIb3cgZG8gSSBrbm93IHdoaWNoIG9mIHRoZSBjb21tZXJjaWFscyBkaWQgYmV0dGVyIHRoaXMgd2Vlaz8gVGhlIHF1ZXN0aW9uIGFza3MgeW91IHRvIGNvbXBhcmUgdGhpcyB3ZWVrJ3MgVFYgR1JQIHdpdGggVFYgR1JQIHZhbHVlcyBpbiB0aGUgZGF0YSBzZXQsIGFuZCBjb21wYXJlIHRoaXMgd2VlaydzIFJhZGlvIEdSUCB3aXRoIFJhZGlvIEdSUCB2YWx1ZXMgaW4gdGhlIGRhdGEgc2V0LCBhbmQgdGhlbiBkZWNpZGUgd2hpY2ggb2YgdGhlIGNvbW1lcmNpYWxzIGRpZCBiZXR0ZXIuIEFjdHVhbGx5IHRoZSB6IHNjb3JlcyB3aWxsIGhlbHAgYSBsb3QuIFogc2NvcmUgaXMgdGhlIG51bWJlciBvZiBzdGFuZGFyZCBkZXZpYXRpb25zIHRoZSB2YWx1ZSBpcyBhd2F5IGZyb20gdGhlIG1lYW4uIFdlIGtub3cgdGhhdCAxODAgaXMgMS45NDk2MDQgYXdheSBmcm9tIHRoZSBtZWFuIG9mIFRWIEdSUCdzIGluIHRoZSBkYXRhIHNldCwgYW5kIHRoYXQgMTkwIGlzIDEuMzEwNjAzIHN0YW5kYXJkIGRldmlhdGlvbnMgYXdheSBmcm9tIHRoZSBtZWFuIG9mIFJhZGlvIEdSUCdzIGluIHRoZSBkYXRhIHNldC4gQXMgYSByZXN1bHQsIHRoaXMgd2VlayB0aGUgVFYgY29tbWVyY2lhbHMgZGlkIGJldHRlciB0aGlzIHdlZWsgY29tcGFyaW5nIHRvIGhlc3RvcmljYWwgdmFsdWVzLiAKCgojNC0gWW91IG5lZWQgdG8gY3JlYXRlIGEgcHJlZGljdGl2ZSBtb2RlbCB0aGF0IHByZWRpY3RzIHNhbGVzLiBZb3Ugd2lsbCBjcmVhdGUgdGhlIG1vZGVsIHVzaW5nIHRoZSB0cmFpbmluZyBkYXRhIHNldCwgYW5kIHRoZW4gdGVzdCBpdCB1c2luZyB0aGUgdGVzdGluZyBkYXRhIHNldC4KCiM0LkEgQ2FsY3VsYXRlIGRpZmZlcmVudCBjb3JyZWxhdGlvbiBmYWN0b3JzIGFuZCBsaXN0IGJ5IG9yZGVyIHRoZSBtb3N0IHBvdGVudGlhbCBwZWRpY3RpdmUgdmFyaWFibGVzLCBleGVjbHVkZSB3ZWVrIGFuZCBob2xpZGF5LihVU0UgVFJBSU5JTkcgREFUQSBTRVQgIkV1cm9TdG9yZV9UcmFpbi5jc3YiKQoKYGBge3J9CiMgaGVyZSB3ZSB3aWxsIGNsYWN1bGF0ZSB0aGUgY29ycmVsYXRpb24gY29lZmZpY2llbnQgYmV0d2VlbiBzYWxlcyBhbmQgYWxsIG90aGVyIHZhcmFpYmxlcyBpbiB0aGUgZGF0YSBzZXQgCgpjb3Ioc3RvcmVfZGF0YSkKYGBgCgp5b3UgbmVlZCB0byBsb29rIGF0IHRoZSBjb3JyZWxhdGlvbiB2YWx1ZXMgaW4gdGhlIHRhYmxlIGFuZCByYW5rIHRoZSBwcmVkaWN0aXZlIHZhcmFpYmxlcyBhY2NvcmRpbmdseS4gQmFzZWQgb24gdGhlIHJlc3VsdHMgd2UgY2FuIHNlZSB0aGF0IHRoZSBvcmRlciBpcyBhcyB0aGUgZm9sbG93aW5nICh0aGUgZmlyc3QgaXMgdGhlIG1vc3QgcG90ZW50aWFsIHByZWRpY2l0dmUgdmFyaWFibGUsIGFuZCB0aGUgbGFzdCBpcyB0aGUgbGVhc3QgcG90ZW50aWFsKQoKMS0gVGVtcHJhdHVyZSAyLSBGdWVsIFZvbHVtZSAzLSBGdWVsIFByaWNlIDQtIFJhZGlvIDUtIFRWCgooc2lkZSBub3RlOiByZW1lbWJlciB0aGF0IHRoaXMgaXMgbm90IGVub3VnaCB0byBzYXkgdGhhdCB0ZW1wcmF0dXJlLCBvciBmdWVsIHZvbHVtZSBhcmUgZ29vZCBwcmVkY2l0b3JzLiBZb3UgbmVlZCB0byBjcmVhdGUgbW9kZWxzIGFuZCB0ZXN0IHRoZW07IHdlIGNhbid0IHJlbHkgb24gY29ycmVhbHRpb24gY29lZmZpY2llbnQgb25seSkKCjQuQiBUaGUgbWFuYWdlciBvZiB0aGUgbWFyZWt0aW5nIGRlcGFydG1lbnQgcmVxdWVzdGVkIHRoYXQgeW91IGV2YWx1YXRlIHR3byBtb2RlbHMgdGhhdCBwcmVkY2l0cyBzYWxlcy4gTW9kZWxfMSB1c2VzIHRlbXByYXR1cmUgYW5kIGZ1ZWwgcHJpY2UgYXMgcHJlZGNpdG9ycywgYW5kIE1vZGVsXzIgdXNlcyBmdWVsIHZvbHVtZSBhbmQgcmFkaW8gYXMgcHJlZGNpb3Rycy4KCllvdSBuZWVkIHRvIGV2YWx1YXRlIHRoZSB0d28gbW9kZWxzIGFuZCBzaG93IHdoaWNoIG9uZSBpcyB0aGUgYmVzdC4KCkZpcnN0IHBhcnQgb2YgcXVlc3Rpb25zIChtb2RlbHMgY3JlYXRpb24pIDp5b3UgbmVlZCB0byBjcmVhdGUgdGhlIHR3byBtb2RlbHMgdXNpbmcgdGhlIHRyYWluaW5nIGRhdGEgc2V0LCBhbmQgdGVzdCB0aGVtIHVzaW5nIHRoZSB0ZXN0aW5nIGRhdGEgc2V0LiBBZnRlciB5b3UgY3JlYXRlIHRoZW0gdXNpbmcgdGhlIHRyYWluaW5nIGRhdGEgc2V0LCB5b3UgbmVlZCB0byB3cml0ZSB0aGUgZXF1YXRpb25zIGZvciB0aGUgdHdvIG1vZGVscywgZXhwbGFpbiB0aGUgY29lZmZpY2llbnRzIG9mIHRoZSBlcXVhdGlvbiwgYW5kIHdyaXRlIHRoZSBSc3F1YXJlIGFuZCBhZGp1c3RlZCBSIHNxdWFyZSB2YWx1ZXMuIFlvdSBuZWVkIHRvIGNvbXBhcmUgdGhlIHR3byBtb2RlbHMgYmFzZWQgb24gdGhlIHRyYWluaW5nIGRhdGEgc2V0IHJlc3VsdHMgdXNpbmcgdGhlIFIgc3F1YXJlZCBhbmQgYWRqdXN0ZWQgUiBzcXVhcmVkIHZhbHVlcy4KClNlY29uZCBwYXJ0IG9mIHF1ZXN0aW9uIChtb2RlbHMgdGVzdGluZywgZXZhbHVhdGlvbiwgYW5kIHNlbGVjdGlvbik6IEZvciB0aGUgdGVzdGluZyB5b3UgbmVlZCB0byBjb21wYXJlIHRoZSBSTVNFIHZhbHVlcyBmb3IgZWFjaCBtb2RlbDsgYWxzbyB5b3UgY2FuIHBsb3QgdGhlIHByZWRjaXRlZCB2YWx1ZXMgdnMgYWN0dWFsIHZhbHVlcyBhbmQgY29tcGFyZSAoeW91IGRvbid0IG5lZWQgdG8gZHJhdyBhbnkgcGxvdCBvbiB0aGUgZXhhbSBwYXBlcjsgdGhpcyBpcyBmb3IgeW91IHRvIGhhdmUgIGJldHRlciBpbnNpZ2h0cyBvbiB0aGUgYmVzdCBtb2RlbCkuWW91IGFsc28gbmVlZCB0byBjb21wYXJlIHRoZSB0d28gbW9kZWxzIGJhc2VkIG9uIHRoZSB0ZXN0aW5nIGRhdGEgc2V0IHJlc3VsdHMgaS5lLiBiYXNlZCBvbiBSTVNFIAooZm9yIHRoaXMgcXVlc3Rpb24gWW91IG5lZWQgdG8gdXNlIGJvdGggdGhlIHRyYWluaW5nIGRhdGEgc2V0ICJFdXJvU3RvcmVfVHJhaW4uY3N2IiBhbmQgdGhlIHRlc3RpbmcgZGF0YSBzZXQgIkV1cm9TdG9yZV9UZXN0LmNzdiIpCgpgYGB7cn0KIyBsZXQgdXMgc3RhcnQgYnkgY3JlYXRpbmcgdGhlIHR3byBtb2RlbHMKIyB3ZSBhbHJlYWR5IGV4dHJhY3RlZCB0aGUgc2FsZXMsIGZ1ZWwgdm9sdW1lLCBUdiwgYW5kIHJhZGlvIGZyb20gdHJhaW5pbmcgZGF0YSBzZXQuIHdlIG5lZWQgdG8gZXh0cmFjdCB0aGUgdGVtcHJhdHVyZSBhbmQgZnVlbCBwcmljZSAKCnRlbXBfdHJhaW4gPSBzdG9yZV9kYXRhJFRlbXAKZnVlbF9wX3RyYWluID0gc3RvcmVfZGF0YSRGdWVsLlByaWNlCgpgYGAKCgpgYGB7cn0KIyBub3cgd2UgY2FuIGNyZWF0ZSB0aGUgZmlyc3QgbW9kZWwgCm1vZGVsXzEgPSBsbSAoc2FsZXNfdHJhaW5+dGVtcF90cmFpbitmdWVsX3BfdHJhaW4pCnN1bW1hcnkobW9kZWxfMSkKYGBgCgpgYGB7cn0KIyB3ZSBjYW4gYWxzbyBjcmVhdGUgdGhlIHNlY29uZCBtb2RlbAptb2RlbF8yID0gbG0gKHNhbGVzX3RyYWlufmZ1ZWxfdm9sX3RyYWluK3JhZGlvX3RyYWluKQpzdW1tYXJ5KG1vZGVsXzIpCmBgYAoKRnJvbSB0aGUgc3VtbWFyeSByZXN1bHRzIHlvdSBjYW4gYXNud2VyIHRoZSBmaXJzdCBwYXJ0IG9mIHRoZSBxdWVzdGlvbiAKCk1vZGVsXzEgCkVxdWF0aW9uOiBTYWxlcyA9IC02NzYxLjA5ICsgMjA0LjM2ICogdGVtcHJhdHVyZSArIDIzNC43OCAqIGZ1ZWwgcHJpY2UgCkNvZWZmaWNpZW50czogaWYgdGVtcHJhdHVyZSBhbmQgcHJpY2UgYXJlIGJvdGggZXF1YWwgdG8gemVybyB0aGUgc2FsZXMgd2lsbCBiZSAtNjc2MS4wOSBpLmUuIHdlIHdpbGwgbG9zZSBtb25leS4gSWYgdGVtcHJhdHVyZSBpcyBpbmNyZWFzZWQgYnkgMSwgdGhlIHNhbGVzIHdpbGwgaW5jcmVhc2UgYnkgMjA0LjM2LCBhbmQgaWYgZnVlbCBwcmljZSBpcyBpbmNyZWFzZWQgYnkgMSwgdGhlIHNhbGVzIHdpbGwgaW5jcmVhc2UgYnkgMjM0Ljc4LiAKUiBzcXVhcmVkID0gMC42MzM5LAlBZGp1c3RlZCBSLXNxdWFyZWQgPSAwLjYxOTggCgpNb2RlbF8yIApFcXVhdGlvbjogU2FsZXMgPSAtMS4zNTBlKzA0ICsgNS42MjdlLTAxKiBGdWVsIFZvbCArIDkuNDgxZSswMCAqcmFkaW8KY29lZmZpY2llbnRzOiBpZiBmdWVsIHZvbHVtZSBhbmQgcmFkaW8gYXJlIGJvdGggZXF1YWwgdG8gemVybyB0aGUgc2FsZXMgd2lsbCBiZSAtMS4zNTBlKzA0IGkuZS4gd2Ugd2lsbCBsb3NlIG1vbmV5LiBJZiBmdWVsIHZvbHVtZSBpcyBpbmNyZWFzZWQgYnkgMSwgdGhlIHNhbGVzIHdpbGwgaW5jcmVhc2UgYnkgNS42MjdlLTAxLCBhbmQgaWYgcmFkaW8gaXMgaW5jcmVhc2VkIGJ5IDEsIHRoZSBzYWxlcyB3aWxsIGluY3JlYXNlIGJ5IDkuNDgxZSswMC4KUi1zcXVhcmVkOiAgMC40OTg3LAlBZGp1c3RlZCBSLXNxdWFyZWQ6ICAwLjQ3OTQgCgpCYXNlZCBvbiB0aGVzZSByZXN1bHRzLCB5b3UgY2FuIHNlZSB0aGF0IG1vZGVsXzEgY291bGQgYmUgYmV0dGVyIChpdCBoYXMgYSBoaWdoZXIgUiBzcXVhcmUgYW5kIGFkanVzdGVkIFIgc3F1YXJlKTsgaG93ZXZlciwgd2UgbmVlZCB0byB0ZXN0IHRoZSB0d28gbW9kZWxzIGZpcnN0IGJlZm9yZSBtYWtpbmcgdGhlIGRlY2lzaW9uIG9uIHdoaWNoIG9uZSBpcyB0aGUgYmVzdDsgcmVtZW1iZXIgdGhhdCBhIG1vZGVsIGNvdWxkIGJlIG92ZXItZml0dGVkIHRvIHRoZSB0cmFpbmluZyBkYXRhIHNldCBhbmQgZG8gYmFkbHkgb24gdGVzdGluZyBkYXRhIHNldC4gV2UgZG9uJ3QgbGlrZSBzdWNoIG1vZGVsOyB3ZSBuZWVkIGEgbW9kZWwgdGhhdCBkb2VzIHdlbGwgb24gYm90aCB0cmFpbmluZyBhbmQgdGVzdGluZy4gCgpgYGB7cn0KIyBsZXQgdXMgdGVzdCB0aGUgdHdvIG1vZGVscwojIGZpcnN0IHdlIG5lZWQgdG8gcmVhZCB0aGUgdGVzdGluZyBkYXRhIHNldApzdG9yZV9kYXRhXzIgPSByZWFkLmNzdihmaWxlID0gIkV1cm9TdG9yZV9UZXN0LmNzdiIpCmhlYWQoc3RvcmVfZGF0YV8yKQpgYGAKCmBgYHtyfQojIHdlIG5lZWQgdG8gcmVhZCB0aGUgY29sdW1ucyAKc2FsZXNfdGVzdCA9IHN0b3JlX2RhdGFfMiRTYWxlcwp0ZW1wX3Rlc3QgPSBzdG9yZV9kYXRhXzIkVGVtcApmdWVsX3BfdGVzdCA9IHN0b3JlX2RhdGFfMiRGdWVsLlByaWNlCmZ1ZWxfdm9sX3Rlc3QgPSBzdG9yZV9kYXRhXzIkRnVlbC5Wb2x1bWUKcmFkaW9fdGVzdCA9IHN0b3JlX2RhdGFfMiRSYWRpbwpgYGAKCmBgYHtyfQojIHdlIHdpbGwgbm93IHJ1biB0aGUgdHdvIG1vZGVscyBvbiB0aGUgdGVzdGluZyBkYXRhIHNldCBhbmQgY2FsY3VsYXRlIHRoZSBwcmVkaWN0ZWQgdmFsdWVzIG9mIHNhbGVzLiAKI1dlIGhhdmUgdHdvIG1vZGVscywgc28gd2Ugd2lsbCBoYXZlIHR3byB2ZWN0b3JzIG9mIHByZWRjaXRlZCB2YWx1ZXMgZm9yIHNhbGVzLiBXZSB3aWxsIGNvbXBhcmUgdGhlIHR3byB2ZWN0b3JzIG9mIHByZWRjaXRlZCB2YWx1ZXMgZm9yIHNhbGVzIHdpdGggdGhlIGFjdHVhbCB2YWx1ZXMgZm9yIHNhbGVzIGluIHRoZSB0ZXN0aW5nIGRhdGEgc2V0ICh0aGlzIGlzIHdoYXQgaXMgY2FsbGVkIHRlc3RpbmcpCgpzYWxlc19wcmVkaWN0X21vZGVsXzEgPSBjb2VmKG1vZGVsXzEpWzFdK2NvZWYobW9kZWxfMSlbMl0qdGVtcF90ZXN0K2NvZWYobW9kZWxfMSlbM10qZnVlbF9wX3Rlc3QKCnBsb3Qoc2FsZXNfcHJlZGljdF9tb2RlbF8xLHNhbGVzX3Rlc3QpCmBgYAoKYGBge3J9Cm1zZV9tb2RlbF8xID0gc3VtKChzYWxlc19wcmVkaWN0X21vZGVsXzEtc2FsZXNfdGVzdCleMikvbGVuZ3RoKHNhbGVzX3Rlc3QpCnJtc2VfbW9kZWxfMSA9c3FydChtc2VfbW9kZWxfMSkKcm1zZV9tb2RlbF8xCgpgYGAKCnRoZSBybXNlIG9mIG1vZGVsXzEgaXMgMzA4OS40MDYuIFRoZSBwbG90IHNob3dzIG5vdCBtdWNoIGNvcnJlbGF0aW9uIGJldHdlZW4gYWN0dWFsIHNhbGVzIGFuZCBwcmVkaWN0ZWQgc2FsZXMuIEhvd2V2ZXIsIHdlIGNhbid0IGFzc2VzcyB1bnRpbCB3ZSBzZWUgcmVzdWx0cyBvZiBtb2RlbF8yIAoKYGBge3J9CnNhbGVzX3ByZWRpY3RfbW9kZWxfMiA9IGNvZWYobW9kZWxfMilbMV0rY29lZihtb2RlbF8yKVsyXSpmdWVsX3ZvbF90ZXN0K2NvZWYobW9kZWxfMilbM10qZnVlbF9wX3Rlc3QKCnBsb3Qoc2FsZXNfcHJlZGljdF9tb2RlbF8yLHNhbGVzX3Rlc3QpCmBgYAoKYGBge3J9Cm1zZV9tb2RlbF8yID0gc3VtKChzYWxlc19wcmVkaWN0X21vZGVsXzItc2FsZXNfdGVzdCleMikvbGVuZ3RoKHNhbGVzX3Rlc3QpCnJtc2VfbW9kZWxfMiA9c3FydChtc2VfbW9kZWxfMikKcm1zZV9tb2RlbF8yCgpgYGAKdGhlIHJtc2Ugb2YgbW9kZWxfMiBpcyAxODcwLjg2MywgbXVjaCBiZXR0ZXIgdGhhbiBybXNlIG9mIG1vZGVsXzEuIEFsc28sIGxvb2tpbmcgYXQgdGhlIHBsb3Qgb2YgbW9kZWxfMiwgd2Ugd2lsbCBzZWUgYmV0dGVyIGNvcnJlYWx0aW9uIGJldHdlZW4gcHJlZGNpdGVkIHZhbHVlcyBhbmQgYWN0dWFsIHZhbHVlcy4gCgpBcyBhIHJlc3VsdCwgSSBjYW4gc2F5IHRoYXQgbW9kZWxfMiBpcyBhIGJldHRlciBtb2RlbC4gQWx0aG91Z2ggbW9kZWxfMSBoYWQgaGlnaGVyIFIgc3F1YXJlZCBhbmQgQWRqdXN0ZWQgUiBzcXVhcmVkIGluIHRyYWluaW5nIGRhdGEgc2V0LCB3aGVuIHdlIGludHJvZHVjZWQgdGhlIHRlc3RpbmcgZGF0YSBzZXQsIG1vZGVsIDIgaGFkIG1vcmUgYWNjdXJhY3kuCgo1LiBBZnRlciB5b3Ugc2VsZWN0IHlvdXIgYmVzdCBwcmVkaWN0aXZlIG1vZGVsLCB5b3UgaGF2ZSB0byBmb3JtdWxhdGUgYW5kIHNvbHZlIHRoZSBsaW5lYXIgb3B0aW1pemF0aW9uIHByb2JsZW0uIFlvdXIgZ29hbCBpcyB0byBzZWxlY3QgdGhlIG9wdGltYWwgdmFsdWVzIGZvciB0aGUgdHdvIHByZWRpY3RvcnMgaW4gb3JkZXIgdG8gb3B0aW1pemUgc2FsZXMuIEFzc3VtZSB0aGF0IG1heGltdW0gY2FwYWNpdHkgb2YgdGhlIGZ1ZWwgc3RhdGlvbiBpcyA5MDAwMCwgbWF4aW11bSBSYWRpbyBHUlAgaXMgMzAwMDAsYW5kIGV2ZXJ5IGluY3JlYXNlIGluIFJhZGlvIEdSUCBieSAxIGxlYWRzIHRvIHNhbGVzIG9mIGF0IGxlYXN0IDEwIGxpdGVycyBvZiBmdWVsLkFsc28sIAoKRm9ybXVsYXRlIHRoZSBwcm9ibGVtLCBpZGVudGlmeSBkZWNpc2lvbiB2YWxyaWFibGVzLCBzb2x2ZSB0aGUgcHJvYmxlbSwgaWRlbnRpZnkgYmluaWRuZyBhbmQgbm9uZS1iaW5pZG5nIGNvc250cmFpbnRzLCBhbmQgY2FsY3VsYXRlIHNsYWNrIGFuZCBzdXJwbHVzLgoKCgpCYXNlZCBvbiB0aGUgYW5hbHlzaXMsIHlvdSB3aWxsIGZpbmQgdGhhdCBtb2RlbF8yIGlzIHRoZSBiZXN0LCBzbyB3ZSB3aWxsIHVzZSBpdCB0byBzb2x2ZSB0aGlzIHF1ZXN0aW9uLiAKVGhlIGdvYWwgaXMgdG8gZmluZCB0aGUgb3B0aW1hbCBmdWVsIHZvbHVtZSwgYW5kIG9wdGltYWwgcmFkaW8gR1JQIHRvIG1heGltaXplIHNhbGVzCgpGb3JtdWxhdGlvbjoKZGVjaXNpb24gdmFyaWFibGVzIFgxID0gRnVlbCB2b2x1bWUsIFgyID0gUmFkaW8KCk9iaiBNYXggIFNhbGVzID0gNS42MjdlLTAxKiBYMSArIDkuNDgxZSswMCAqWDIKU3ViIHRvIApYMSA8PSA5MDAwMApYMjw9IDMwMDAwClgxLTEwKlgyID49IDAKWDEgPj0gMApYMiA+PSAwCgpJbiBvcmRlciB0byBzb2x2ZSwgd2UgbmVlZCB0byBkb3dubG9hZCBMcFNvbHZlckFQSSBwYWNrYWdlCmBgYHtyfQojIHdlIGZpcnN0IG5lZWQgdG8gZG93bmxhb2QgdGhlIHBhY2thZ2UgdG8gc29sdmUgbGluZWFyIG9wdGltaXphdGlvbiBwcm9ibGVtIAoKaWYoIXJlcXVpcmUoImxwU29sdmVBUEkiLHF1aWV0bHkgPSBUUlVFKSkKICBpbnN0YWxsLnBhY2thZ2VzKCJscFNvbHZlQVBJIixkZXBlbmRlbmNpZXMgPSBUUlVFLCByZXBvcyA9ICJodHRwczovL2Nsb3VkLnItcHJvamVjdC5vcmciKQpgYGAKCm5vdyB3ZSBjYW4gdXNlIHRoZSBwYWNrYWdlIHRvIHNvbHZlIAoKYGBge3J9CmxwU2FsZXMgPC0gbWFrZS5scCgwLCAyKSAKYGBgCgpgYGB7cn0KZHVtcCA9IGxwLmNvbnRyb2wobHBTYWxlcywgc2Vuc2U9Im1heCIpICAKIyBTZXQgdGhlIG9iamVjdGl2ZSBmdW5jdGlvbi4KCnNldC5vYmpmbihscFNhbGVzLCBjKDUuNjI3ZS0wMSwgOS40ODFlKzAwKSkKCiMgYWRkIGNvbnN0cmFpbnRzCmFkZC5jb25zdHJhaW50KGxwU2FsZXMsIGMoMSwwICksICI8PSIsIDkwMDAwKQphZGQuY29uc3RyYWludChscFNhbGVzLCBjKDAsMSksICI8PSIsIDMwMDAwKQphZGQuY29uc3RyYWludChscFNhbGVzLCBjKDEsLTEwKSwgIj49IiwgMCkKYWRkLmNvbnN0cmFpbnQobHBTYWxlcywgYygxLDAgKSwgIj49IiwgMCkKYWRkLmNvbnN0cmFpbnQobHBTYWxlcywgYygwLDEpLCAiPj0iLCAwKQpgYGAKCgpgYGB7cn0KIyBWaWV3IHRoZSBwcm9ibGVtIGZvcm11bGF0aW9uIGluIHRhYnVsYXIvbWF0cml4IGZvcm0KbHBTYWxlcwoKIyBTb2x2ZSAKc29sdmUobHBTYWxlcykgCgojIERpc3BsYXkgdGhlIG9iamVjdGl2ZSBmdW5jdGlvbiBvcHRpbXVtIHZhbHVlCmdldC5vYmplY3RpdmUobHBTYWxlcykKCiMgRGlzcGxheSB0aGUgZGVjaXNpb24gdmFyaWFibGVzIG9wdGltdW0gdmFsdWVzCmdldC52YXJpYWJsZXMobHBTYWxlcykgCmBgYAoKU29sdXRpb246IFggMSA9IDkwMDAwLCBYMiA9IDkwMDAsIFNhbGVzID0gMTM1OTcyCgpgYGB7cn0KZ2V0LnNlbnNpdGl2aXR5LnJocyhscFNhbGVzKQpgYGAKCkZpcnN0IGNvbnN0cmFpbnQgaXMgYmluZGluZyBiZWN1YXNlIG1hcmdpbmFsIHZhbHVlID0xLjUxMDggPD4gMCwgYW4gaW5jcmVhc2UgaW4gdGhlIHJpZ2h0IGhhbmQgc2lkZSBvZiB0aGUgY29udHJhaW50IGJ5IDEgKGlmIGNhcGFjaXR5IG9mIGZ1ZWwgc3RhdGlvbiBpY25yZWFzZXMgYnkgMSkgd2lsbCBpbmNyZWFzZSBvcHRpbWFsIHNhbGVzIGJ5IDEuNTEwOAoKVGhpcmQgY29uc3RyYWludCBpcyBiaW5kaW5nIGJlY2F1c2UgbWFyZ2luYWwgdmFsdWUgPSAtMC45NDgxIDw+IDAsIGlmIHRoZSByaWdodCBoYW5kIHNpZGUgb2YgdGhlIGNvbnN0cmFpbnQgaXMgaW5jcmVhc2VkIGJ5IDEsIHRoZSAgb3B0aW1hbCBzYWxlcyB3aWxsIGRlY3JlYXNlcyBieSAtMC45NDgxCgpBbGwgb3RoZXIgY29uc3RyYWludHMgYXJlIG5vbi1iaW5kaW5nIGJlY3Vhc2UgdGhleSBoYXZlIG1hcmdpbmFsIHZhbHVlID0gMAoKRm9yIHN1cnBsdXMgYW5kIHNsYWNrLCBJIHdpbGwgZG8gaXQgZm9yIHNlY29uZCBjb25zdHJhaW50IG9ubHk6IApTZWNvbmQgY29uc3RyYWludCBpcyBub24tYmluZGluZyBhbmQgaGFzIDw9LCBzbyBpdCBoYXMgc2xhY2sgKGlmIGl0IGhhcyA+PSB0aGVuIGl0IGhhcyBzdXJwbHVzKQpTZWNvbmQgY29uc3RyYWludCBpcyAKWDIgPD0gMzAwMDAKT3B0aW1hbCBzb2x1dGlvbiBmb3IgWDIgPSA5MDAwLCB0aGUgc2xhY2sgPSAzMDAwMC05MDAwID0gMjEwMDAKCgo2LiBDcmVhdGUgYSBxdWFkcmF0aWMgcmVncmVzc2lvbiBtb2RlbCB0byBwcmVkaWN0IHNhbGVzIGJhc2VkIG9uIHRlbXByYXR1cmUgKHVzZSB0cmFpbmluZyBkYXRhIHNldCkKClRyeSB0byBzb2x2ZSB0aGlzIG9uIHlvdXIgb3duLCBhbmQgc2VuZCBtZSBxdWVzdGlvbnMgCgo=